module_cache.h 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. // Copyright 2018 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. #ifndef BASE_PROFILER_MODULE_CACHE_H_
  5. #define BASE_PROFILER_MODULE_CACHE_H_
  6. #include <memory>
  7. #include <set>
  8. #include <string>
  9. #include <vector>
  10. #include "base/base_export.h"
  11. #include "base/containers/flat_set.h"
  12. #include "base/files/file_path.h"
  13. #include "base/memory/raw_ptr.h"
  14. #include "base/strings/string_piece.h"
  15. #include "build/build_config.h"
  16. #if BUILDFLAG(IS_WIN)
  17. #include "base/win/windows_types.h"
  18. #endif
  19. namespace base {
  20. // Converts module id to match the id that Breakpad outputs.
  21. BASE_EXPORT std::string TransformModuleIDToBreakpadFormat(
  22. StringPiece module_id);
  23. // Supports cached lookup of modules by address, with caching based on module
  24. // address ranges.
  25. //
  26. // Cached lookup is necessary on Mac for performance, due to an inefficient
  27. // dladdr implementation. See https://crrev.com/487092.
  28. //
  29. // Cached lookup is beneficial on Windows to minimize use of the loader
  30. // lock. Note however that the cache retains a handle to looked-up modules for
  31. // its lifetime, which may result in pinning modules in memory that were
  32. // transiently loaded by the OS.
  33. class BASE_EXPORT ModuleCache {
  34. public:
  35. // Module represents a binary module (executable or library) and its
  36. // associated state.
  37. class BASE_EXPORT Module {
  38. public:
  39. Module() = default;
  40. virtual ~Module() = default;
  41. Module(const Module&) = delete;
  42. Module& operator=(const Module&) = delete;
  43. // Gets the base address of the module.
  44. virtual uintptr_t GetBaseAddress() const = 0;
  45. // Gets the opaque binary string that uniquely identifies a particular
  46. // program version with high probability. This is parsed from headers of the
  47. // loaded module.
  48. // For binaries generated by GNU tools:
  49. // Contents of the .note.gnu.build-id field.
  50. // On Windows:
  51. // GUID + AGE in the debug image headers of a module.
  52. virtual std::string GetId() const = 0;
  53. // Gets the debug basename of the module. This is the basename of the PDB
  54. // file on Windows and the basename of the binary on other platforms.
  55. virtual FilePath GetDebugBasename() const = 0;
  56. // Gets the size of the module.
  57. virtual size_t GetSize() const = 0;
  58. // True if this is a native module.
  59. virtual bool IsNative() const = 0;
  60. };
  61. // Interface for lazily creating a native module for a given |address|. The
  62. // provider is registered with RegisterAuxiliaryModuleProvider().
  63. class AuxiliaryModuleProvider {
  64. public:
  65. AuxiliaryModuleProvider() = default;
  66. AuxiliaryModuleProvider(const AuxiliaryModuleProvider&) = delete;
  67. AuxiliaryModuleProvider& operator=(const AuxiliaryModuleProvider&) = delete;
  68. virtual std::unique_ptr<const Module> TryCreateModuleForAddress(
  69. uintptr_t address) = 0;
  70. protected:
  71. ~AuxiliaryModuleProvider() = default;
  72. };
  73. ModuleCache();
  74. ~ModuleCache();
  75. // Gets the module containing |address| or nullptr if |address| is not within
  76. // a module. The returned module remains owned by and has the same lifetime as
  77. // the ModuleCache object.
  78. const Module* GetModuleForAddress(uintptr_t address);
  79. std::vector<const Module*> GetModules() const;
  80. // Updates the set of non-native modules maintained by the
  81. // ModuleCache. Non-native modules represent regions of non-native executable
  82. // code such as V8 generated code.
  83. //
  84. // Note that non-native modules may be embedded within native modules, as in
  85. // the case of V8 builtin code compiled within Chrome. In that case
  86. // GetModuleForAddress() will return the non-native module rather than the
  87. // native module for the memory region it occupies.
  88. //
  89. // Modules in |defunct_modules| are removed from the set of active modules;
  90. // specifically they no longer participate in the GetModuleForAddress()
  91. // lookup. They continue to exist for the lifetime of the ModuleCache,
  92. // however, so that existing references to them remain valid. Modules in
  93. // |new_modules| are added to the set of active non-native modules. Modules in
  94. // |new_modules| may not overlap with any non-native Modules already present
  95. // in ModuleCache, unless those modules are provided in |defunct_modules| in
  96. // the same call.
  97. void UpdateNonNativeModules(
  98. const std::vector<const Module*>& defunct_modules,
  99. std::vector<std::unique_ptr<const Module>> new_modules);
  100. // Adds a custom native module to the cache. This is intended to support
  101. // native modules that require custom handling. In general, native modules
  102. // will be found and added automatically when invoking GetModuleForAddress().
  103. // |module| may not overlap with any native Modules already present in
  104. // ModuleCache.
  105. void AddCustomNativeModule(std::unique_ptr<const Module> module);
  106. // Registers a custom module provider for lazily creating native modules. At
  107. // most one provider can be registered at any time, and the provider must be
  108. // unregistered before being destroyed. This is intended to support native
  109. // modules that require custom handling. In general, native modules will be
  110. // found and added automatically when invoking GetModuleForAddress(). If no
  111. // module is found, this provider will be used as fallback.
  112. void RegisterAuxiliaryModuleProvider(
  113. AuxiliaryModuleProvider* auxiliary_module_provider);
  114. // Unregisters the custom module provider.
  115. void UnregisterAuxiliaryModuleProvider(
  116. AuxiliaryModuleProvider* auxiliary_module_provider);
  117. // Gets the module containing |address| if one already exists, or nullptr
  118. // otherwise. The returned module remains owned by and has the same lifetime
  119. // as the ModuleCache object.
  120. // NOTE: Only users that create their own modules and need control over native
  121. // module creation should use this function. Everyone else should use
  122. // GetModuleForAddress().
  123. const Module* GetExistingModuleForAddress(uintptr_t address) const;
  124. private:
  125. // Heterogenously compares modules by base address, and modules and
  126. // addresses. The module/address comparison considers the address equivalent
  127. // to the module if the address is within the extent of the module. Combined
  128. // with is_transparent this allows modules to be looked up by address in the
  129. // using containers.
  130. struct ModuleAndAddressCompare {
  131. using is_transparent = void;
  132. bool operator()(const std::unique_ptr<const Module>& m1,
  133. const std::unique_ptr<const Module>& m2) const;
  134. bool operator()(const std::unique_ptr<const Module>& m1,
  135. uintptr_t address) const;
  136. bool operator()(uintptr_t address,
  137. const std::unique_ptr<const Module>& m2) const;
  138. };
  139. // Creates a Module object for the specified memory address. Returns null if
  140. // the address does not belong to a module.
  141. static std::unique_ptr<const Module> CreateModuleForAddress(
  142. uintptr_t address);
  143. // Set of native modules sorted by base address. We use set rather than
  144. // flat_set because the latter type has O(n^2) runtime for adding modules
  145. // one-at-a-time, which is how modules are added on Windows and Mac.
  146. std::set<std::unique_ptr<const Module>, ModuleAndAddressCompare>
  147. native_modules_;
  148. // Set of non-native modules currently mapped into the address space, sorted
  149. // by base address. Represented as flat_set because std::set does not support
  150. // extracting move-only element types prior to C++17's
  151. // std::set<>::extract(). The non-native module insertion/removal patterns --
  152. // initial bulk insertion, then infrequent inserts/removals -- should work
  153. // reasonably well with the flat_set complexity guarantees. Separate from
  154. // native_modules_ to support preferential lookup of non-native modules
  155. // embedded in native modules; see comment on UpdateNonNativeModules().
  156. base::flat_set<std::unique_ptr<const Module>, ModuleAndAddressCompare>
  157. non_native_modules_;
  158. // Unsorted vector of inactive non-native modules. Inactive modules are no
  159. // longer mapped in the address space and don't participate in address lookup,
  160. // but are retained by the cache so that existing references to the them
  161. // remain valid. Note that this cannot be represented as a set/flat_set
  162. // because it can contain multiple modules that were loaded (then subsequently
  163. // unloaded) at the same base address.
  164. std::vector<std::unique_ptr<const Module>> inactive_non_native_modules_;
  165. // Auxiliary module provider, for lazily creating native modules.
  166. raw_ptr<AuxiliaryModuleProvider> auxiliary_module_provider_ = nullptr;
  167. };
  168. } // namespace base
  169. #endif // BASE_PROFILER_MODULE_CACHE_H_