xref: /aosp_15_r20/external/cronet/base/profiler/module_cache_win.cc (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 #include "base/profiler/module_cache.h"
6*6777b538SAndroid Build Coastguard Worker 
7*6777b538SAndroid Build Coastguard Worker #include <objbase.h>
8*6777b538SAndroid Build Coastguard Worker 
9*6777b538SAndroid Build Coastguard Worker #include <psapi.h>
10*6777b538SAndroid Build Coastguard Worker 
11*6777b538SAndroid Build Coastguard Worker #include <string>
12*6777b538SAndroid Build Coastguard Worker 
13*6777b538SAndroid Build Coastguard Worker #include "base/debug/alias.h"
14*6777b538SAndroid Build Coastguard Worker #include "base/process/process_handle.h"
15*6777b538SAndroid Build Coastguard Worker #include "base/strings/string_number_conversions.h"
16*6777b538SAndroid Build Coastguard Worker #include "base/strings/string_util.h"
17*6777b538SAndroid Build Coastguard Worker #include "base/strings/utf_string_conversions.h"
18*6777b538SAndroid Build Coastguard Worker #include "base/win/pe_image.h"
19*6777b538SAndroid Build Coastguard Worker #include "base/win/scoped_handle.h"
20*6777b538SAndroid Build Coastguard Worker #include "base/win/win_util.h"
21*6777b538SAndroid Build Coastguard Worker 
22*6777b538SAndroid Build Coastguard Worker namespace base {
23*6777b538SAndroid Build Coastguard Worker 
24*6777b538SAndroid Build Coastguard Worker namespace {
25*6777b538SAndroid Build Coastguard Worker 
26*6777b538SAndroid Build Coastguard Worker // Gets the unique build ID and the corresponding debug path for a module.
27*6777b538SAndroid Build Coastguard Worker // Windows build IDs are created by a concatenation of a GUID and AGE fields
28*6777b538SAndroid Build Coastguard Worker // found in the headers of a module. The GUID is stored in the first 16 bytes
29*6777b538SAndroid Build Coastguard Worker // and the AGE is stored in the last 4 bytes. Returns the empty string if the
30*6777b538SAndroid Build Coastguard Worker // function fails to get the build ID. The debug path (pdb file) can be found
31*6777b538SAndroid Build Coastguard Worker // in the PE file and is the build time path where the debug file was produced.
32*6777b538SAndroid Build Coastguard Worker //
33*6777b538SAndroid Build Coastguard Worker // Example:
34*6777b538SAndroid Build Coastguard Worker // dumpbin chrome.exe /headers | find "Format:"
35*6777b538SAndroid Build Coastguard Worker //   ... Format: RSDS, {16B2A428-1DED-442E-9A36-FCE8CBD29726}, 10, ...
36*6777b538SAndroid Build Coastguard Worker //
37*6777b538SAndroid Build Coastguard Worker // The resulting buildID string of this instance of chrome.exe is
38*6777b538SAndroid Build Coastguard Worker // "16B2A4281DED442E9A36FCE8CBD2972610".
39*6777b538SAndroid Build Coastguard Worker //
40*6777b538SAndroid Build Coastguard Worker // Note that the AGE field is encoded in decimal, not hex.
GetDebugInfoForModule(HMODULE module_handle,std::string * build_id,FilePath * pdb_name)41*6777b538SAndroid Build Coastguard Worker void GetDebugInfoForModule(HMODULE module_handle,
42*6777b538SAndroid Build Coastguard Worker                            std::string* build_id,
43*6777b538SAndroid Build Coastguard Worker                            FilePath* pdb_name) {
44*6777b538SAndroid Build Coastguard Worker   GUID guid;
45*6777b538SAndroid Build Coastguard Worker   DWORD age;
46*6777b538SAndroid Build Coastguard Worker   LPCSTR pdb_file = nullptr;
47*6777b538SAndroid Build Coastguard Worker   size_t pdb_file_length = 0;
48*6777b538SAndroid Build Coastguard Worker   if (!win::PEImage(module_handle)
49*6777b538SAndroid Build Coastguard Worker            .GetDebugId(&guid, &age, &pdb_file, &pdb_file_length)) {
50*6777b538SAndroid Build Coastguard Worker     return;
51*6777b538SAndroid Build Coastguard Worker   }
52*6777b538SAndroid Build Coastguard Worker 
53*6777b538SAndroid Build Coastguard Worker   FilePath::StringType pdb_filename;
54*6777b538SAndroid Build Coastguard Worker   if (!UTF8ToWide(pdb_file, pdb_file_length, &pdb_filename))
55*6777b538SAndroid Build Coastguard Worker     return;
56*6777b538SAndroid Build Coastguard Worker   *pdb_name = FilePath(std::move(pdb_filename)).BaseName();
57*6777b538SAndroid Build Coastguard Worker 
58*6777b538SAndroid Build Coastguard Worker   auto buffer = win::WStringFromGUID(guid);
59*6777b538SAndroid Build Coastguard Worker   RemoveChars(buffer, L"{}-", &buffer);
60*6777b538SAndroid Build Coastguard Worker   buffer.append(NumberToWString(age));
61*6777b538SAndroid Build Coastguard Worker   *build_id = WideToUTF8(buffer);
62*6777b538SAndroid Build Coastguard Worker }
63*6777b538SAndroid Build Coastguard Worker 
64*6777b538SAndroid Build Coastguard Worker // Returns true if the address is in the address space accessible to
65*6777b538SAndroid Build Coastguard Worker // applications and DLLs, as reported by ::GetSystemInfo.
IsValidUserSpaceAddress(uintptr_t address)66*6777b538SAndroid Build Coastguard Worker bool IsValidUserSpaceAddress(uintptr_t address) {
67*6777b538SAndroid Build Coastguard Worker   static LPVOID max_app_addr = 0;
68*6777b538SAndroid Build Coastguard Worker   static LPVOID min_app_addr = 0;
69*6777b538SAndroid Build Coastguard Worker   if (!max_app_addr) {
70*6777b538SAndroid Build Coastguard Worker     SYSTEM_INFO sys_info;
71*6777b538SAndroid Build Coastguard Worker     ::GetSystemInfo(&sys_info);
72*6777b538SAndroid Build Coastguard Worker     max_app_addr = sys_info.lpMaximumApplicationAddress;
73*6777b538SAndroid Build Coastguard Worker     min_app_addr = sys_info.lpMinimumApplicationAddress;
74*6777b538SAndroid Build Coastguard Worker   }
75*6777b538SAndroid Build Coastguard Worker   return reinterpret_cast<LPVOID>(address) >= min_app_addr &&
76*6777b538SAndroid Build Coastguard Worker          reinterpret_cast<LPVOID>(address) <= max_app_addr;
77*6777b538SAndroid Build Coastguard Worker }
78*6777b538SAndroid Build Coastguard Worker 
79*6777b538SAndroid Build Coastguard Worker // Traits class to adapt GenericScopedHandle for HMODULES.
80*6777b538SAndroid Build Coastguard Worker class ModuleHandleTraits : public win::HandleTraits {
81*6777b538SAndroid Build Coastguard Worker  public:
82*6777b538SAndroid Build Coastguard Worker   using Handle = HMODULE;
83*6777b538SAndroid Build Coastguard Worker 
84*6777b538SAndroid Build Coastguard Worker   ModuleHandleTraits() = delete;
85*6777b538SAndroid Build Coastguard Worker   ModuleHandleTraits(const ModuleHandleTraits&) = delete;
86*6777b538SAndroid Build Coastguard Worker   ModuleHandleTraits& operator=(const ModuleHandleTraits&) = delete;
87*6777b538SAndroid Build Coastguard Worker 
CloseHandle(HMODULE handle)88*6777b538SAndroid Build Coastguard Worker   static bool CloseHandle(HMODULE handle) { return ::FreeLibrary(handle) != 0; }
IsHandleValid(HMODULE handle)89*6777b538SAndroid Build Coastguard Worker   static bool IsHandleValid(HMODULE handle) { return handle != nullptr; }
NullHandle()90*6777b538SAndroid Build Coastguard Worker   static HMODULE NullHandle() { return nullptr; }
91*6777b538SAndroid Build Coastguard Worker };
92*6777b538SAndroid Build Coastguard Worker 
93*6777b538SAndroid Build Coastguard Worker // HMODULE is not really a handle, and has reference count semantics, so the
94*6777b538SAndroid Build Coastguard Worker // standard VerifierTraits does not apply.
95*6777b538SAndroid Build Coastguard Worker using ScopedModuleHandle =
96*6777b538SAndroid Build Coastguard Worker     win::GenericScopedHandle<ModuleHandleTraits, win::DummyVerifierTraits>;
97*6777b538SAndroid Build Coastguard Worker 
98*6777b538SAndroid Build Coastguard Worker class WindowsModule : public ModuleCache::Module {
99*6777b538SAndroid Build Coastguard Worker  public:
WindowsModule(ScopedModuleHandle module_handle,const MODULEINFO module_info,const std::string & id,const FilePath & debug_basename)100*6777b538SAndroid Build Coastguard Worker   WindowsModule(ScopedModuleHandle module_handle,
101*6777b538SAndroid Build Coastguard Worker                 const MODULEINFO module_info,
102*6777b538SAndroid Build Coastguard Worker                 const std::string& id,
103*6777b538SAndroid Build Coastguard Worker                 const FilePath& debug_basename)
104*6777b538SAndroid Build Coastguard Worker       : module_handle_(std::move(module_handle)),
105*6777b538SAndroid Build Coastguard Worker         module_info_(module_info),
106*6777b538SAndroid Build Coastguard Worker         id_(id),
107*6777b538SAndroid Build Coastguard Worker         debug_basename_(debug_basename) {}
108*6777b538SAndroid Build Coastguard Worker 
109*6777b538SAndroid Build Coastguard Worker   WindowsModule(const WindowsModule&) = delete;
110*6777b538SAndroid Build Coastguard Worker   WindowsModule& operator=(const WindowsModule&) = delete;
111*6777b538SAndroid Build Coastguard Worker 
112*6777b538SAndroid Build Coastguard Worker   // ModuleCache::Module
GetBaseAddress() const113*6777b538SAndroid Build Coastguard Worker   uintptr_t GetBaseAddress() const override {
114*6777b538SAndroid Build Coastguard Worker     return reinterpret_cast<uintptr_t>(module_info_.lpBaseOfDll);
115*6777b538SAndroid Build Coastguard Worker   }
116*6777b538SAndroid Build Coastguard Worker 
GetId() const117*6777b538SAndroid Build Coastguard Worker   std::string GetId() const override { return id_; }
GetDebugBasename() const118*6777b538SAndroid Build Coastguard Worker   FilePath GetDebugBasename() const override { return debug_basename_; }
GetSize() const119*6777b538SAndroid Build Coastguard Worker   size_t GetSize() const override { return module_info_.SizeOfImage; }
IsNative() const120*6777b538SAndroid Build Coastguard Worker   bool IsNative() const override { return true; }
121*6777b538SAndroid Build Coastguard Worker 
122*6777b538SAndroid Build Coastguard Worker  private:
123*6777b538SAndroid Build Coastguard Worker   ScopedModuleHandle module_handle_;
124*6777b538SAndroid Build Coastguard Worker   const MODULEINFO module_info_;
125*6777b538SAndroid Build Coastguard Worker   std::string id_;
126*6777b538SAndroid Build Coastguard Worker   FilePath debug_basename_;
127*6777b538SAndroid Build Coastguard Worker };
128*6777b538SAndroid Build Coastguard Worker 
GetModuleHandleForAddress(uintptr_t address)129*6777b538SAndroid Build Coastguard Worker ScopedModuleHandle GetModuleHandleForAddress(uintptr_t address) {
130*6777b538SAndroid Build Coastguard Worker   // Record the address in crash dumps to help understand the source of
131*6777b538SAndroid Build Coastguard Worker   // GetModuleHandleEx crashes on Windows 11 observed in
132*6777b538SAndroid Build Coastguard Worker   // https://crbug.com/1297776.
133*6777b538SAndroid Build Coastguard Worker   debug::Alias(&address);
134*6777b538SAndroid Build Coastguard Worker   if (!IsValidUserSpaceAddress(address))
135*6777b538SAndroid Build Coastguard Worker     return ScopedModuleHandle(nullptr);
136*6777b538SAndroid Build Coastguard Worker 
137*6777b538SAndroid Build Coastguard Worker   HMODULE module_handle = nullptr;
138*6777b538SAndroid Build Coastguard Worker 
139*6777b538SAndroid Build Coastguard Worker   // GetModuleHandleEx() increments the module reference count, which is then
140*6777b538SAndroid Build Coastguard Worker   // managed and ultimately decremented by ScopedModuleHandle.
141*6777b538SAndroid Build Coastguard Worker   if (!::GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
142*6777b538SAndroid Build Coastguard Worker                            reinterpret_cast<LPCTSTR>(address),
143*6777b538SAndroid Build Coastguard Worker                            &module_handle)) {
144*6777b538SAndroid Build Coastguard Worker     const DWORD error = ::GetLastError();
145*6777b538SAndroid Build Coastguard Worker     DCHECK_EQ(ERROR_MOD_NOT_FOUND, static_cast<int>(error));
146*6777b538SAndroid Build Coastguard Worker   }
147*6777b538SAndroid Build Coastguard Worker   return ScopedModuleHandle(module_handle);
148*6777b538SAndroid Build Coastguard Worker }
149*6777b538SAndroid Build Coastguard Worker 
CreateModuleForHandle(ScopedModuleHandle module_handle)150*6777b538SAndroid Build Coastguard Worker std::unique_ptr<ModuleCache::Module> CreateModuleForHandle(
151*6777b538SAndroid Build Coastguard Worker     ScopedModuleHandle module_handle) {
152*6777b538SAndroid Build Coastguard Worker   FilePath pdb_name;
153*6777b538SAndroid Build Coastguard Worker   std::string build_id;
154*6777b538SAndroid Build Coastguard Worker   GetDebugInfoForModule(module_handle.get(), &build_id, &pdb_name);
155*6777b538SAndroid Build Coastguard Worker 
156*6777b538SAndroid Build Coastguard Worker   MODULEINFO module_info;
157*6777b538SAndroid Build Coastguard Worker   if (!::GetModuleInformation(GetCurrentProcessHandle(), module_handle.get(),
158*6777b538SAndroid Build Coastguard Worker                               &module_info, sizeof(module_info))) {
159*6777b538SAndroid Build Coastguard Worker     return nullptr;
160*6777b538SAndroid Build Coastguard Worker   }
161*6777b538SAndroid Build Coastguard Worker 
162*6777b538SAndroid Build Coastguard Worker   return std::make_unique<WindowsModule>(std::move(module_handle), module_info,
163*6777b538SAndroid Build Coastguard Worker                                          build_id, pdb_name);
164*6777b538SAndroid Build Coastguard Worker }
165*6777b538SAndroid Build Coastguard Worker 
166*6777b538SAndroid Build Coastguard Worker }  // namespace
167*6777b538SAndroid Build Coastguard Worker 
168*6777b538SAndroid Build Coastguard Worker // static
CreateModuleForAddress(uintptr_t address)169*6777b538SAndroid Build Coastguard Worker std::unique_ptr<const ModuleCache::Module> ModuleCache::CreateModuleForAddress(
170*6777b538SAndroid Build Coastguard Worker     uintptr_t address) {
171*6777b538SAndroid Build Coastguard Worker   ScopedModuleHandle module_handle = GetModuleHandleForAddress(address);
172*6777b538SAndroid Build Coastguard Worker   if (!module_handle.is_valid())
173*6777b538SAndroid Build Coastguard Worker     return nullptr;
174*6777b538SAndroid Build Coastguard Worker   return CreateModuleForHandle(std::move(module_handle));
175*6777b538SAndroid Build Coastguard Worker }
176*6777b538SAndroid Build Coastguard Worker 
177*6777b538SAndroid Build Coastguard Worker }  // namespace base
178