1 // Copyright 2016 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef BASE_DEBUG_ACTIVITY_ANALYZER_H_ 6 #define BASE_DEBUG_ACTIVITY_ANALYZER_H_ 7 8 #include <map> 9 #include <memory> 10 #include <set> 11 #include <string> 12 #include <vector> 13 14 #include "base/base_export.h" 15 #include "base/debug/activity_tracker.h" 16 17 namespace base { 18 namespace debug { 19 20 class GlobalActivityAnalyzer; 21 22 // This class provides analysis of data captured from a ThreadActivityTracker. 23 // When created, it takes a snapshot of the data held by the tracker and 24 // makes that information available to other code. 25 class BASE_EXPORT ThreadActivityAnalyzer { 26 public: 27 struct BASE_EXPORT Snapshot : ThreadActivityTracker::Snapshot { 28 Snapshot(); 29 ~Snapshot(); 30 31 // The user-data snapshot for an activity, matching the |activity_stack| 32 // of ThreadActivityTracker::Snapshot, if any. 33 std::vector<ActivityUserData::Snapshot> user_data_stack; 34 }; 35 36 // This class provides keys that uniquely identify a thread, even across 37 // multiple processes. 38 class ThreadKey { 39 public: ThreadKey(int64_t pid,int64_t tid)40 ThreadKey(int64_t pid, int64_t tid) : pid_(pid), tid_(tid) {} 41 42 bool operator<(const ThreadKey& rhs) const { 43 if (pid_ != rhs.pid_) 44 return pid_ < rhs.pid_; 45 return tid_ < rhs.tid_; 46 } 47 48 bool operator==(const ThreadKey& rhs) const { 49 return (pid_ == rhs.pid_ && tid_ == rhs.tid_); 50 } 51 52 private: 53 int64_t pid_; 54 int64_t tid_; 55 }; 56 57 // Creates an analyzer for an existing activity |tracker|. A snapshot is taken 58 // immediately and the tracker is not referenced again. 59 explicit ThreadActivityAnalyzer(const ThreadActivityTracker& tracker); 60 61 // Creates an analyzer for a block of memory currently or previously in-use 62 // by an activity-tracker. A snapshot is taken immediately and the memory 63 // is not referenced again. 64 ThreadActivityAnalyzer(void* base, size_t size); 65 66 // Creates an analyzer for a block of memory held within a persistent-memory 67 // |allocator| at the given |reference|. A snapshot is taken immediately and 68 // the memory is not referenced again. 69 ThreadActivityAnalyzer(PersistentMemoryAllocator* allocator, 70 PersistentMemoryAllocator::Reference reference); 71 72 ~ThreadActivityAnalyzer(); 73 74 // Adds information from the global analyzer. 75 void AddGlobalInformation(GlobalActivityAnalyzer* global); 76 77 // Returns true iff the contained data is valid. Results from all other 78 // methods are undefined if this returns false. IsValid()79 bool IsValid() { return activity_snapshot_valid_; } 80 81 // Gets the process id and its creation stamp. 82 int64_t GetProcessId(int64_t* out_stamp = nullptr) { 83 if (out_stamp) 84 *out_stamp = activity_snapshot_.create_stamp; 85 return activity_snapshot_.process_id; 86 } 87 88 // Gets the name of the thread. GetThreadName()89 const std::string& GetThreadName() { 90 return activity_snapshot_.thread_name; 91 } 92 93 // Gets the TheadKey for this thread. GetThreadKey()94 ThreadKey GetThreadKey() { 95 return ThreadKey(activity_snapshot_.process_id, 96 activity_snapshot_.thread_id); 97 } 98 activity_snapshot()99 const Snapshot& activity_snapshot() { return activity_snapshot_; } 100 101 private: 102 friend class GlobalActivityAnalyzer; 103 104 // The snapshot of the activity tracker taken at the moment of construction. 105 Snapshot activity_snapshot_; 106 107 // Flag indicating if the snapshot data is valid. 108 bool activity_snapshot_valid_; 109 110 // A reference into a persistent memory allocator, used by the global 111 // analyzer to know where this tracker came from. 112 PersistentMemoryAllocator::Reference allocator_reference_ = 0; 113 114 DISALLOW_COPY_AND_ASSIGN(ThreadActivityAnalyzer); 115 }; 116 117 118 // This class manages analyzers for all known processes and threads as stored 119 // in a persistent memory allocator. It supports retrieval of them through 120 // iteration and directly using a ThreadKey, which allows for cross-references 121 // to be resolved. 122 // Note that though atomic snapshots are used and everything has its snapshot 123 // taken at the same time, the multi-snapshot itself is not atomic and thus may 124 // show small inconsistencies between threads if attempted on a live system. 125 class BASE_EXPORT GlobalActivityAnalyzer { 126 public: 127 struct ProgramLocation { 128 int module; 129 uintptr_t offset; 130 }; 131 132 using ThreadKey = ThreadActivityAnalyzer::ThreadKey; 133 134 // Creates a global analyzer from a persistent memory allocator. 135 explicit GlobalActivityAnalyzer( 136 std::unique_ptr<PersistentMemoryAllocator> allocator); 137 138 ~GlobalActivityAnalyzer(); 139 140 // Creates a global analyzer using a given persistent-memory |allocator|. 141 static std::unique_ptr<GlobalActivityAnalyzer> CreateWithAllocator( 142 std::unique_ptr<PersistentMemoryAllocator> allocator); 143 144 #if !defined(OS_NACL) 145 // Creates a global analyzer using the contents of a file given in 146 // |file_path|. 147 static std::unique_ptr<GlobalActivityAnalyzer> CreateWithFile( 148 const FilePath& file_path); 149 #endif // !defined(OS_NACL) 150 151 // Like above but accesses an allocator in a mapped shared-memory segment. 152 static std::unique_ptr<GlobalActivityAnalyzer> CreateWithSharedMemory( 153 std::unique_ptr<SharedMemory> shm); 154 155 // Like above but takes a handle to an existing shared memory segment and 156 // maps it before creating the tracker. 157 static std::unique_ptr<GlobalActivityAnalyzer> CreateWithSharedMemoryHandle( 158 const SharedMemoryHandle& handle, 159 size_t size); 160 161 // Iterates over all known valid processes and returns their PIDs or zero 162 // if there are no more. Calls to GetFirstProcess() will perform a global 163 // snapshot in order to provide a relatively consistent state across the 164 // future calls to GetNextProcess() and GetFirst/NextAnalyzer(). PIDs are 165 // returned in the order they're found meaning that a first-launched 166 // controlling process will be found first. Note, however, that space 167 // freed by an exiting process may be re-used by a later process. 168 int64_t GetFirstProcess(); 169 int64_t GetNextProcess(); 170 171 // Iterates over all known valid analyzers for the a given process or returns 172 // null if there are no more. 173 // 174 // GetFirstProcess() must be called first in order to capture a global 175 // snapshot! Ownership stays with the global analyzer object and all existing 176 // analyzer pointers are invalidated when GetFirstProcess() is called. 177 ThreadActivityAnalyzer* GetFirstAnalyzer(int64_t pid); 178 ThreadActivityAnalyzer* GetNextAnalyzer(); 179 180 // Gets the analyzer for a specific thread or null if there is none. 181 // Ownership stays with the global analyzer object. 182 ThreadActivityAnalyzer* GetAnalyzerForThread(const ThreadKey& key); 183 184 // Extract user data based on a reference and its identifier. 185 ActivityUserData::Snapshot GetUserDataSnapshot(int64_t pid, 186 uint32_t ref, 187 uint32_t id); 188 189 // Extract the data for a specific process. An empty snapshot will be 190 // returned if the process is not known. 191 const ActivityUserData::Snapshot& GetProcessDataSnapshot(int64_t pid); 192 193 // Gets all log messages stored within. 194 std::vector<std::string> GetLogMessages(); 195 196 // Gets modules corresponding to a pid. This pid must come from a call to 197 // GetFirst/NextProcess. Only modules that were first registered prior to 198 // GetFirstProcess's snapshot are returned. 199 std::vector<GlobalActivityTracker::ModuleInfo> GetModules(int64_t pid); 200 201 // Gets the corresponding "program location" for a given "program counter". 202 // This will return {0,0} if no mapping could be found. 203 ProgramLocation GetProgramLocationFromAddress(uint64_t address); 204 205 // Returns whether the data is complete. Data can be incomplete if the 206 // recording size quota is hit. 207 bool IsDataComplete() const; 208 209 private: 210 using AnalyzerMap = 211 std::map<ThreadKey, std::unique_ptr<ThreadActivityAnalyzer>>; 212 213 struct UserDataSnapshot { 214 // Complex class needs out-of-line ctor/dtor. 215 UserDataSnapshot(); 216 UserDataSnapshot(const UserDataSnapshot& rhs); 217 UserDataSnapshot(UserDataSnapshot&& rhs); 218 ~UserDataSnapshot(); 219 220 int64_t process_id; 221 int64_t create_stamp; 222 ActivityUserData::Snapshot data; 223 }; 224 225 // Finds, creates, and indexes analyzers for all known processes and threads. 226 void PrepareAllAnalyzers(); 227 228 // The persistent memory allocator holding all tracking data. 229 std::unique_ptr<PersistentMemoryAllocator> allocator_; 230 231 // The time stamp when analysis began. This is used to prevent looking into 232 // process IDs that get reused when analyzing a live system. 233 int64_t analysis_stamp_; 234 235 // The iterator for finding tracking information in the allocator. 236 PersistentMemoryAllocator::Iterator allocator_iterator_; 237 238 // A set of all interesting memory references found within the allocator. 239 std::set<PersistentMemoryAllocator::Reference> memory_references_; 240 241 // A set of all process-data memory references found within the allocator. 242 std::map<int64_t, UserDataSnapshot> process_data_; 243 244 // A set of all process IDs collected during PrepareAllAnalyzers. These are 245 // popped and returned one-by-one with calls to GetFirst/NextProcess(). 246 std::vector<int64_t> process_ids_; 247 248 // A map, keyed by ThreadKey, of all valid activity analyzers. 249 AnalyzerMap analyzers_; 250 251 // The iterator within the analyzers_ map for returning analyzers through 252 // first/next iteration. 253 AnalyzerMap::iterator analyzers_iterator_; 254 int64_t analyzers_iterator_pid_; 255 256 DISALLOW_COPY_AND_ASSIGN(GlobalActivityAnalyzer); 257 }; 258 259 } // namespace debug 260 } // namespace base 261 262 #endif // BASE_DEBUG_ACTIVITY_ANALYZER_H_ 263