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