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)); |
} |