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