module_cache.h 6.9 KB

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