Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2623)

Unified Diff: base/debug/activity_tracker.cc

Issue 2566983009: Support storing information about what modules are loaded in the process. (Closed)
Patch Set: Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« base/debug/activity_tracker.h ('K') | « base/debug/activity_tracker.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: base/debug/activity_tracker.cc
diff --git a/base/debug/activity_tracker.cc b/base/debug/activity_tracker.cc
index 562e662c98972f0588ba3ee9266b73c813b8e620..1b278c5f7303387f3d8aafc72df4cd53a9adc0d8 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"
@@ -38,8 +39,9 @@ const int kMinStackDepth = 2;
// The amount of memory set aside for holding arbitrary user data (key/value
// pairs) globally or associated with ActivityData entries.
-const size_t kUserDataSize = 1024; // bytes
-const size_t kGlobalDataSize = 4096; // bytes
+const size_t kUserDataSize = 1024; // bytes
+const size_t kGlobalDataSize = 4096; // bytes
+const size_t kGlobalModulesSize = 4096; // bytes
const size_t kMaxUserDataNameLength =
static_cast<size_t>(std::numeric_limits<uint8_t>::max());
@@ -58,6 +60,89 @@ union ThreadRef {
#endif
};
+// State of a module as stared in persistent memory.
manzagop (departed) 2016/12/14 20:08:53 typo: stared -> stored
bcwhite 2016/12/14 21:59:05 Done.
+struct ModuleInfoStore {
+ // Expected size for 32/64-bit check.
+ static constexpr size_t kExpectedInstanceSize = 24;
manzagop (departed) 2016/12/14 20:08:53 nit: I like having units in variable names (kExpec
manzagop (departed) 2016/12/14 20:08:53 Unused?
bcwhite 2016/12/14 21:59:05 The constant is required (and used) by the Persist
+
+ uint64_t address; // The base address of the module.
+ uint64_t size; // The size of the module in bytes.
+ uint16_t pickle_size; // The size of the following pickle.
+ uint8_t loaded; // Flag indicating if module is loaded or not.
+ char pickle[5]; // Other strings; may allocate larger.
+
+ // Decodes/encodes storage structure from more generic info structure.
+ bool DecodeTo(GlobalActivityTracker::ModuleInfo* info);
+ bool EncodeFrom(const GlobalActivityTracker::ModuleInfo& info, size_t size);
manzagop (departed) 2016/12/14 20:08:53 Why do you need the size? Ah it's the size budget.
bcwhite 2016/12/14 21:59:05 Done.
+
+ // Updates the core information without changing the encoded strings. This is
+ // useful when a known module changes state (i.e. new load or unload).
+ bool UpdateFrom(const GlobalActivityTracker::ModuleInfo& info);
+
+ // Deterimes the required memory size for the encoded storage.
manzagop (departed) 2016/12/14 20:08:53 typo: Deterimes
bcwhite 2016/12/14 21:59:05 Done.
+ static size_t EncodedSize(const GlobalActivityTracker::ModuleInfo& info);
+};
+
+static constexpr size_t kModuleInfoStoreHeaderSize =
+ sizeof(ModuleInfoStore) - sizeof(((ModuleInfoStore*)0)->pickle);
manzagop (departed) 2016/12/14 20:08:53 Size of on the null pointer smells funny to me. Wo
bcwhite 2016/12/14 21:59:05 Done.
+
+bool ModuleInfoStore::DecodeTo(GlobalActivityTracker::ModuleInfo* info) {
+ std::atomic_thread_fence(std::memory_order_acquire);
+ 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 ModuleInfoStore::EncodeFrom(const GlobalActivityTracker::ModuleInfo& info,
+ size_t 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 (pickler.size() + kModuleInfoStoreHeaderSize > size) {
+ NOTREACHED();
+ return false;
+ }
+
+ memcpy(pickle, pickler.data(), pickler.size());
+ return UpdateFrom(info);
+}
+
+bool ModuleInfoStore::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 ModuleInfoStore::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 kModuleInfoStoreHeaderSize + sizer.payload_size();
+}
+
// Determines the previous aligned index.
size_t RoundDownToAlignment(size_t index, size_t alignment) {
return index & (0 - alignment);
@@ -1065,6 +1150,38 @@ 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()) {
+ ModuleInfoStore* store = allocator_->GetAsObject<ModuleInfoStore>(
+ found->second, kTypeIdModulesRecord);
+ DCHECK(store);
+
+ // Get should never fail but need to be tolerant in production.
+ if (store) {
+ // 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 accomodate a possibly longer length.
manzagop (departed) 2016/12/14 20:08:53 typo: accommodate
bcwhite 2016/12/14 21:59:05 Done.
+ store->UpdateFrom(info);
+ return;
manzagop (departed) 2016/12/14 20:08:53 return outside the if(store)?
bcwhite 2016/12/14 21:59:05 If it fails to load it, a new record will be creat
manzagop (departed) 2016/12/16 16:09:31 But then the map insertion will fail as the key al
bcwhite 2016/12/16 18:35:15 Good point. Always return.
+ }
+ }
+
+ size_t required_size = ModuleInfoStore::EncodedSize(info);
+ PersistentMemoryAllocator::Reference ref =
+ allocator_->Allocate(required_size, kTypeIdModulesRecord);
+ ModuleInfoStore* store =
+ allocator_->GetAsObject<ModuleInfoStore>(ref, kTypeIdModulesRecord);
+ if (!store)
+ return;
+
+ bool success = store->EncodeFrom(info, allocator_->GetAllocSize(ref));
+ DCHECK(success);
+ modules_.insert(std::make_pair(info.file, ref));
+}
+
GlobalActivityTracker::GlobalActivityTracker(
std::unique_ptr<PersistentMemoryAllocator> allocator,
int stack_depth)
@@ -1098,8 +1215,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));
}
« base/debug/activity_tracker.h ('K') | « base/debug/activity_tracker.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698