| // Copyright 2016 The Chromium Authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | #ifndef BASE_DEBUG_ACTIVITY_ANALYZER_H_ | 
 | #define BASE_DEBUG_ACTIVITY_ANALYZER_H_ | 
 |  | 
 | #include <map> | 
 | #include <memory> | 
 | #include <set> | 
 | #include <string> | 
 | #include <vector> | 
 |  | 
 | #include "base/base_export.h" | 
 | #include "base/debug/activity_tracker.h" | 
 |  | 
 | namespace base { | 
 | namespace debug { | 
 |  | 
 | class GlobalActivityAnalyzer; | 
 |  | 
 | // This class provides analysis of data captured from a ThreadActivityTracker. | 
 | // When created, it takes a snapshot of the data held by the tracker and | 
 | // makes that information available to other code. | 
 | class BASE_EXPORT ThreadActivityAnalyzer { | 
 |  public: | 
 |   struct BASE_EXPORT Snapshot : ThreadActivityTracker::Snapshot { | 
 |     Snapshot(); | 
 |     ~Snapshot(); | 
 |  | 
 |     // The user-data snapshot for an activity, matching the |activity_stack| | 
 |     // of ThreadActivityTracker::Snapshot, if any. | 
 |     std::vector<ActivityUserData::Snapshot> user_data_stack; | 
 |   }; | 
 |  | 
 |   // This class provides keys that uniquely identify a thread, even across | 
 |   // multiple processes. | 
 |   class ThreadKey { | 
 |    public: | 
 |     ThreadKey(int64_t pid, int64_t tid) : pid_(pid), tid_(tid) {} | 
 |  | 
 |     bool operator<(const ThreadKey& rhs) const { | 
 |       if (pid_ != rhs.pid_) | 
 |         return pid_ < rhs.pid_; | 
 |       return tid_ < rhs.tid_; | 
 |     } | 
 |  | 
 |     bool operator==(const ThreadKey& rhs) const { | 
 |       return (pid_ == rhs.pid_ && tid_ == rhs.tid_); | 
 |     } | 
 |  | 
 |    private: | 
 |     int64_t pid_; | 
 |     int64_t tid_; | 
 |   }; | 
 |  | 
 |   // Creates an analyzer for an existing activity |tracker|. A snapshot is taken | 
 |   // immediately and the tracker is not referenced again. | 
 |   explicit ThreadActivityAnalyzer(const ThreadActivityTracker& tracker); | 
 |  | 
 |   // Creates an analyzer for a block of memory currently or previously in-use | 
 |   // by an activity-tracker. A snapshot is taken immediately and the memory | 
 |   // is not referenced again. | 
 |   ThreadActivityAnalyzer(void* base, size_t size); | 
 |  | 
 |   // Creates an analyzer for a block of memory held within a persistent-memory | 
 |   // |allocator| at the given |reference|. A snapshot is taken immediately and | 
 |   // the memory is not referenced again. | 
 |   ThreadActivityAnalyzer(PersistentMemoryAllocator* allocator, | 
 |                          PersistentMemoryAllocator::Reference reference); | 
 |  | 
 |   ~ThreadActivityAnalyzer(); | 
 |  | 
 |   // Adds information from the global analyzer. | 
 |   void AddGlobalInformation(GlobalActivityAnalyzer* global); | 
 |  | 
 |   // Returns true iff the contained data is valid. Results from all other | 
 |   // methods are undefined if this returns false. | 
 |   bool IsValid() { return activity_snapshot_valid_; } | 
 |  | 
 |   // Gets the process id and its creation stamp. | 
 |   int64_t GetProcessId(int64_t* out_stamp = nullptr) { | 
 |     if (out_stamp) | 
 |       *out_stamp = activity_snapshot_.create_stamp; | 
 |     return activity_snapshot_.process_id; | 
 |   } | 
 |  | 
 |   // Gets the name of the thread. | 
 |   const std::string& GetThreadName() { | 
 |     return activity_snapshot_.thread_name; | 
 |   } | 
 |  | 
 |   // Gets the TheadKey for this thread. | 
 |   ThreadKey GetThreadKey() { | 
 |     return ThreadKey(activity_snapshot_.process_id, | 
 |                      activity_snapshot_.thread_id); | 
 |   } | 
 |  | 
 |   const Snapshot& activity_snapshot() { return activity_snapshot_; } | 
 |  | 
 |  private: | 
 |   friend class GlobalActivityAnalyzer; | 
 |  | 
 |   // The snapshot of the activity tracker taken at the moment of construction. | 
 |   Snapshot activity_snapshot_; | 
 |  | 
 |   // Flag indicating if the snapshot data is valid. | 
 |   bool activity_snapshot_valid_; | 
 |  | 
 |   // A reference into a persistent memory allocator, used by the global | 
 |   // analyzer to know where this tracker came from. | 
 |   PersistentMemoryAllocator::Reference allocator_reference_ = 0; | 
 |  | 
 |   DISALLOW_COPY_AND_ASSIGN(ThreadActivityAnalyzer); | 
 | }; | 
 |  | 
 |  | 
 | // This class manages analyzers for all known processes and threads as stored | 
 | // in a persistent memory allocator. It supports retrieval of them through | 
 | // iteration and directly using a ThreadKey, which allows for cross-references | 
 | // to be resolved. | 
 | // Note that though atomic snapshots are used and everything has its snapshot | 
 | // taken at the same time, the multi-snapshot itself is not atomic and thus may | 
 | // show small inconsistencies between threads if attempted on a live system. | 
 | class BASE_EXPORT GlobalActivityAnalyzer { | 
 |  public: | 
 |   struct ProgramLocation { | 
 |     int module; | 
 |     uintptr_t offset; | 
 |   }; | 
 |  | 
 |   using ThreadKey = ThreadActivityAnalyzer::ThreadKey; | 
 |  | 
 |   // Creates a global analyzer from a persistent memory allocator. | 
 |   explicit GlobalActivityAnalyzer( | 
 |       std::unique_ptr<PersistentMemoryAllocator> allocator); | 
 |  | 
 |   ~GlobalActivityAnalyzer(); | 
 |  | 
 |   // Creates a global analyzer using a given persistent-memory |allocator|. | 
 |   static std::unique_ptr<GlobalActivityAnalyzer> CreateWithAllocator( | 
 |       std::unique_ptr<PersistentMemoryAllocator> allocator); | 
 |  | 
 | #if !defined(OS_NACL) | 
 |   // Creates a global analyzer using the contents of a file given in | 
 |   // |file_path|. | 
 |   static std::unique_ptr<GlobalActivityAnalyzer> CreateWithFile( | 
 |       const FilePath& file_path); | 
 | #endif  // !defined(OS_NACL) | 
 |  | 
 |   // Like above but accesses an allocator in a mapped shared-memory segment. | 
 |   static std::unique_ptr<GlobalActivityAnalyzer> CreateWithSharedMemory( | 
 |       std::unique_ptr<SharedMemory> shm); | 
 |  | 
 |   // Like above but takes a handle to an existing shared memory segment and | 
 |   // maps it before creating the tracker. | 
 |   static std::unique_ptr<GlobalActivityAnalyzer> CreateWithSharedMemoryHandle( | 
 |       const SharedMemoryHandle& handle, | 
 |       size_t size); | 
 |  | 
 |   // Iterates over all known valid processes and returns their PIDs or zero | 
 |   // if there are no more. Calls to GetFirstProcess() will perform a global | 
 |   // snapshot in order to provide a relatively consistent state across the | 
 |   // future calls to GetNextProcess() and GetFirst/NextAnalyzer(). PIDs are | 
 |   // returned in the order they're found meaning that a first-launched | 
 |   // controlling process will be found first. Note, however, that space | 
 |   // freed by an exiting process may be re-used by a later process. | 
 |   int64_t GetFirstProcess(); | 
 |   int64_t GetNextProcess(); | 
 |  | 
 |   // Iterates over all known valid analyzers for the a given process or returns | 
 |   // null if there are no more. | 
 |   // | 
 |   // GetFirstProcess() must be called first in order to capture a global | 
 |   // snapshot! Ownership stays with the global analyzer object and all existing | 
 |   // analyzer pointers are invalidated when GetFirstProcess() is called. | 
 |   ThreadActivityAnalyzer* GetFirstAnalyzer(int64_t pid); | 
 |   ThreadActivityAnalyzer* GetNextAnalyzer(); | 
 |  | 
 |   // Gets the analyzer for a specific thread or null if there is none. | 
 |   // Ownership stays with the global analyzer object. | 
 |   ThreadActivityAnalyzer* GetAnalyzerForThread(const ThreadKey& key); | 
 |  | 
 |   // Extract user data based on a reference and its identifier. | 
 |   ActivityUserData::Snapshot GetUserDataSnapshot(int64_t pid, | 
 |                                                  uint32_t ref, | 
 |                                                  uint32_t id); | 
 |  | 
 |   // Extract the data for a specific process. An empty snapshot will be | 
 |   // returned if the process is not known. | 
 |   const ActivityUserData::Snapshot& GetProcessDataSnapshot(int64_t pid); | 
 |  | 
 |   // Gets all log messages stored within. | 
 |   std::vector<std::string> GetLogMessages(); | 
 |  | 
 |   // Gets modules corresponding to a pid. This pid must come from a call to | 
 |   // GetFirst/NextProcess. Only modules that were first registered prior to | 
 |   // GetFirstProcess's snapshot are returned. | 
 |   std::vector<GlobalActivityTracker::ModuleInfo> GetModules(int64_t pid); | 
 |  | 
 |   // Gets the corresponding "program location" for a given "program counter". | 
 |   // This will return {0,0} if no mapping could be found. | 
 |   ProgramLocation GetProgramLocationFromAddress(uint64_t address); | 
 |  | 
 |   // Returns whether the data is complete. Data can be incomplete if the | 
 |   // recording size quota is hit. | 
 |   bool IsDataComplete() const; | 
 |  | 
 |  private: | 
 |   using AnalyzerMap = | 
 |       std::map<ThreadKey, std::unique_ptr<ThreadActivityAnalyzer>>; | 
 |  | 
 |   struct UserDataSnapshot { | 
 |     // Complex class needs out-of-line ctor/dtor. | 
 |     UserDataSnapshot(); | 
 |     UserDataSnapshot(const UserDataSnapshot& rhs); | 
 |     UserDataSnapshot(UserDataSnapshot&& rhs); | 
 |     ~UserDataSnapshot(); | 
 |  | 
 |     int64_t process_id; | 
 |     int64_t create_stamp; | 
 |     ActivityUserData::Snapshot data; | 
 |   }; | 
 |  | 
 |   // Finds, creates, and indexes analyzers for all known processes and threads. | 
 |   void PrepareAllAnalyzers(); | 
 |  | 
 |   // The persistent memory allocator holding all tracking data. | 
 |   std::unique_ptr<PersistentMemoryAllocator> allocator_; | 
 |  | 
 |   // The time stamp when analysis began. This is used to prevent looking into | 
 |   // process IDs that get reused when analyzing a live system. | 
 |   int64_t analysis_stamp_; | 
 |  | 
 |   // The iterator for finding tracking information in the allocator. | 
 |   PersistentMemoryAllocator::Iterator allocator_iterator_; | 
 |  | 
 |   // A set of all interesting memory references found within the allocator. | 
 |   std::set<PersistentMemoryAllocator::Reference> memory_references_; | 
 |  | 
 |   // A set of all process-data memory references found within the allocator. | 
 |   std::map<int64_t, UserDataSnapshot> process_data_; | 
 |  | 
 |   // A set of all process IDs collected during PrepareAllAnalyzers. These are | 
 |   // popped and returned one-by-one with calls to GetFirst/NextProcess(). | 
 |   std::vector<int64_t> process_ids_; | 
 |  | 
 |   // A map, keyed by ThreadKey, of all valid activity analyzers. | 
 |   AnalyzerMap analyzers_; | 
 |  | 
 |   // The iterator within the analyzers_ map for returning analyzers through | 
 |   // first/next iteration. | 
 |   AnalyzerMap::iterator analyzers_iterator_; | 
 |   int64_t analyzers_iterator_pid_; | 
 |  | 
 |   DISALLOW_COPY_AND_ASSIGN(GlobalActivityAnalyzer); | 
 | }; | 
 |  | 
 | }  // namespace debug | 
 | }  // namespace base | 
 |  | 
 | #endif  // BASE_DEBUG_ACTIVITY_ANALYZER_H_ |