| Index: base/debug/activity_tracker.cc
|
| diff --git a/base/debug/activity_tracker.cc b/base/debug/activity_tracker.cc
|
| index 562e662c98972f0588ba3ee9266b73c813b8e620..c17239746c8f405b843cb0f626e64466c4838f79 100644
|
| --- a/base/debug/activity_tracker.cc
|
| +++ b/base/debug/activity_tracker.cc
|
| @@ -16,6 +16,7 @@
|
| #include "base/metrics/field_trial.h"
|
| #include "base/metrics/histogram_macros.h"
|
| #include "base/pending_task.h"
|
| +#include "base/pickle.h"
|
| #include "base/process/process.h"
|
| #include "base/process/process_handle.h"
|
| #include "base/stl_util.h"
|
| @@ -893,6 +894,80 @@ size_t ThreadActivityTracker::SizeForStackDepth(int stack_depth) {
|
|
|
| GlobalActivityTracker* GlobalActivityTracker::g_tracker_ = nullptr;
|
|
|
| +GlobalActivityTracker::ModuleInfo::ModuleInfo() {}
|
| +GlobalActivityTracker::ModuleInfo::ModuleInfo(ModuleInfo&& rhs) = default;
|
| +GlobalActivityTracker::ModuleInfo::ModuleInfo(const ModuleInfo& rhs) = default;
|
| +GlobalActivityTracker::ModuleInfo::~ModuleInfo() {}
|
| +
|
| +GlobalActivityTracker::ModuleInfo& GlobalActivityTracker::ModuleInfo::operator=(
|
| + ModuleInfo&& rhs) = default;
|
| +GlobalActivityTracker::ModuleInfo& GlobalActivityTracker::ModuleInfo::operator=(
|
| + const ModuleInfo& rhs) = default;
|
| +
|
| +bool GlobalActivityTracker::ModuleInfoRecord::DecodeTo(
|
| + GlobalActivityTracker::ModuleInfo* info,
|
| + size_t record_size) const {
|
| + std::atomic_thread_fence(std::memory_order_acquire);
|
| + if (offsetof(ModuleInfoRecord, pickle) + pickle_size > record_size)
|
| + return false;
|
| +
|
| + info->is_loaded = loaded != 0;
|
| + info->address = static_cast<uintptr_t>(address);
|
| + info->size = static_cast<size_t>(size);
|
| +
|
| + Pickle pickler(pickle, pickle_size);
|
| + PickleIterator iter(pickler);
|
| + return iter.ReadString(&info->file) && iter.ReadString(&info->version) &&
|
| + iter.ReadString(&info->identifier) &&
|
| + iter.ReadString(&info->debug_file) &&
|
| + iter.ReadString(&info->debug_identifier);
|
| +}
|
| +
|
| +bool GlobalActivityTracker::ModuleInfoRecord::EncodeFrom(
|
| + const GlobalActivityTracker::ModuleInfo& info,
|
| + size_t record_size) {
|
| + Pickle pickler;
|
| + bool okay = pickler.WriteString(info.file) &&
|
| + pickler.WriteString(info.version) &&
|
| + pickler.WriteString(info.identifier) &&
|
| + pickler.WriteString(info.debug_file) &&
|
| + pickler.WriteString(info.debug_identifier);
|
| + if (!okay) {
|
| + NOTREACHED();
|
| + return false;
|
| + }
|
| + if (offsetof(ModuleInfoRecord, pickle) + pickler.size() > record_size) {
|
| + NOTREACHED();
|
| + return false;
|
| + }
|
| +
|
| + memcpy(pickle, pickler.data(), pickler.size());
|
| + pickle_size = pickler.size();
|
| + return UpdateFrom(info);
|
| +}
|
| +
|
| +bool GlobalActivityTracker::ModuleInfoRecord::UpdateFrom(
|
| + const GlobalActivityTracker::ModuleInfo& info) {
|
| + address = info.address;
|
| + size = info.size;
|
| + loaded = info.is_loaded ? 1 : 0;
|
| + std::atomic_thread_fence(std::memory_order_release);
|
| + return true;
|
| +}
|
| +
|
| +// static
|
| +size_t GlobalActivityTracker::ModuleInfoRecord::EncodedSize(
|
| + const GlobalActivityTracker::ModuleInfo& info) {
|
| + PickleSizer sizer;
|
| + sizer.AddString(info.file);
|
| + sizer.AddString(info.version);
|
| + sizer.AddString(info.identifier);
|
| + sizer.AddString(info.debug_file);
|
| + sizer.AddString(info.debug_identifier);
|
| +
|
| + return offsetof(ModuleInfoRecord, pickle) + sizer.payload_size();
|
| +}
|
| +
|
| GlobalActivityTracker::ScopedThreadActivity::ScopedThreadActivity(
|
| const void* program_counter,
|
| const void* origin,
|
| @@ -1065,6 +1140,39 @@ void GlobalActivityTracker::RecordLogMessage(StringPiece message) {
|
| }
|
| }
|
|
|
| +void GlobalActivityTracker::RecordModuleInfo(const ModuleInfo& info) {
|
| + AutoLock lock(modules_lock_);
|
| + auto found = modules_.find(info.file);
|
| + if (found != modules_.end()) {
|
| + ModuleInfoRecord* record = allocator_->GetAsObject<ModuleInfoRecord>(
|
| + found->second, kTypeIdModuleInfoRecord);
|
| + DCHECK(record);
|
| +
|
| + // Get should never fail but need to be tolerant in production.
|
| + if (record) {
|
| + // Update the basic state of module information that has been already
|
| + // recorded. It is assumed that the string information (identifier,
|
| + // version, etc.) remain unchanged which means that there's no need
|
| + // to create a new record to accommodate a possibly longer length.
|
| + record->UpdateFrom(info);
|
| + return;
|
| + }
|
| + }
|
| +
|
| + size_t required_size = ModuleInfoRecord::EncodedSize(info);
|
| + PersistentMemoryAllocator::Reference ref =
|
| + allocator_->Allocate(required_size, kTypeIdModuleInfoRecord);
|
| + ModuleInfoRecord* record =
|
| + allocator_->GetAsObject<ModuleInfoRecord>(ref, kTypeIdModuleInfoRecord);
|
| + if (!record)
|
| + return;
|
| +
|
| + bool success = record->EncodeFrom(info, allocator_->GetAllocSize(ref));
|
| + DCHECK(success);
|
| + allocator_->MakeIterable(ref);
|
| + modules_.insert(std::make_pair(info.file, ref));
|
| +}
|
| +
|
| GlobalActivityTracker::GlobalActivityTracker(
|
| std::unique_ptr<PersistentMemoryAllocator> allocator,
|
| int stack_depth)
|
| @@ -1098,8 +1206,7 @@ GlobalActivityTracker::GlobalActivityTracker(
|
| DCHECK(!g_tracker_);
|
| g_tracker_ = this;
|
|
|
| - // The global user-data record must be iterable in order to be found by an
|
| - // analyzer.
|
| + // The global records must be iterable in order to be found by an analyzer.
|
| allocator_->MakeIterable(allocator_->GetAsReference(
|
| user_data_.GetBaseAddress(), kTypeIdGlobalDataRecord));
|
| }
|
|
|