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 
5 #include "base/profiler/module_cache.h"
6 
7 #include <objbase.h>
8 #include <psapi.h>
9 
10 #include "base/process/process_handle.h"
11 #include "base/stl_util.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "base/strings/string_util.h"
14 #include "base/strings/stringprintf.h"
15 #include "base/strings/utf_string_conversions.h"
16 #include "base/win/pe_image.h"
17 #include "base/win/scoped_handle.h"
18 #include "base/win/win_util.h"
19 
20 namespace base {
21 
22 namespace {
23 
24 // Gets the unique build ID and the corresponding debug path for a module.
25 // Windows build IDs are created by a concatenation of a GUID and AGE fields
26 // found in the headers of a module. The GUID is stored in the first 16 bytes
27 // and the AGE is stored in the last 4 bytes. Returns the empty string if the
28 // function fails to get the build ID. The debug path (pdb file) can be found
29 // in the PE file and is the build time path where the debug file was produced.
30 //
31 // Example:
32 // dumpbin chrome.exe /headers | find "Format:"
33 //   ... Format: RSDS, {16B2A428-1DED-442E-9A36-FCE8CBD29726}, 10, ...
34 //
35 // The resulting buildID string of this instance of chrome.exe is
36 // "16B2A4281DED442E9A36FCE8CBD2972610".
37 //
38 // Note that the AGE field is encoded in decimal, not hex.
GetDebugInfoForModule(HMODULE module_handle,std::string * build_id,FilePath * pdb_name)39 void GetDebugInfoForModule(HMODULE module_handle,
40                            std::string* build_id,
41                            FilePath* pdb_name) {
42   GUID guid;
43   DWORD age;
44   LPCSTR pdb_file = nullptr;
45   size_t pdb_file_length = 0;
46   if (!win::PEImage(module_handle)
47            .GetDebugId(&guid, &age, &pdb_file, &pdb_file_length)) {
48     return;
49   }
50 
51   FilePath::StringType pdb_filename;
52   if (!UTF8ToWide(pdb_file, pdb_file_length, &pdb_filename))
53     return;
54   *pdb_name = FilePath(std::move(pdb_filename)).BaseName();
55 
56   auto buffer = win::String16FromGUID(guid);
57   RemoveChars(buffer, STRING16_LITERAL("{}-"), &buffer);
58   buffer.append(NumberToString16(age));
59   *build_id = UTF16ToUTF8(buffer);
60 }
61 
62 // Traits class to adapt GenericScopedHandle for HMODULES.
63 class ModuleHandleTraits : public win::HandleTraits {
64  public:
65   using Handle = HMODULE;
66 
CloseHandle(HMODULE handle)67   static bool CloseHandle(HMODULE handle) { return ::FreeLibrary(handle) != 0; }
IsHandleValid(HMODULE handle)68   static bool IsHandleValid(HMODULE handle) { return handle != nullptr; }
NullHandle()69   static HMODULE NullHandle() { return nullptr; }
70 
71  private:
72   DISALLOW_IMPLICIT_CONSTRUCTORS(ModuleHandleTraits);
73 };
74 
75 // HMODULE is not really a handle, and has reference count semantics, so the
76 // standard VerifierTraits does not apply.
77 using ScopedModuleHandle =
78     win::GenericScopedHandle<ModuleHandleTraits, win::DummyVerifierTraits>;
79 
80 class WindowsModule : public ModuleCache::Module {
81  public:
WindowsModule(ScopedModuleHandle module_handle,const MODULEINFO module_info,const std::string & id,const FilePath & debug_basename)82   WindowsModule(ScopedModuleHandle module_handle,
83                 const MODULEINFO module_info,
84                 const std::string& id,
85                 const FilePath& debug_basename)
86       : module_handle_(std::move(module_handle)),
87         module_info_(module_info),
88         id_(id),
89         debug_basename_(debug_basename) {}
90 
91   WindowsModule(const WindowsModule&) = delete;
92   WindowsModule& operator=(const WindowsModule&) = delete;
93 
94   // ModuleCache::Module
GetBaseAddress() const95   uintptr_t GetBaseAddress() const override {
96     return reinterpret_cast<uintptr_t>(module_info_.lpBaseOfDll);
97   }
98 
GetId() const99   std::string GetId() const override { return id_; }
GetDebugBasename() const100   FilePath GetDebugBasename() const override { return debug_basename_; }
GetSize() const101   size_t GetSize() const override { return module_info_.SizeOfImage; }
IsNative() const102   bool IsNative() const override { return true; }
103 
104  private:
105   ScopedModuleHandle module_handle_;
106   const MODULEINFO module_info_;
107   std::string id_;
108   FilePath debug_basename_;
109 };
110 
GetModuleHandleForAddress(DWORD64 address)111 ScopedModuleHandle GetModuleHandleForAddress(DWORD64 address) {
112   HMODULE module_handle = nullptr;
113   // GetModuleHandleEx() increments the module reference count, which is then
114   // managed and ultimately decremented by ScopedModuleHandle.
115   if (!::GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
116                            reinterpret_cast<LPCTSTR>(address),
117                            &module_handle)) {
118     const DWORD error = ::GetLastError();
119     DCHECK_EQ(ERROR_MOD_NOT_FOUND, static_cast<int>(error));
120   }
121   return ScopedModuleHandle(module_handle);
122 }
123 
CreateModuleForHandle(ScopedModuleHandle module_handle)124 std::unique_ptr<ModuleCache::Module> CreateModuleForHandle(
125     ScopedModuleHandle module_handle) {
126   FilePath pdb_name;
127   std::string build_id;
128   GetDebugInfoForModule(module_handle.Get(), &build_id, &pdb_name);
129 
130   MODULEINFO module_info;
131   if (!::GetModuleInformation(GetCurrentProcessHandle(), module_handle.Get(),
132                               &module_info, sizeof(module_info))) {
133     return nullptr;
134   }
135 
136   return std::make_unique<WindowsModule>(std::move(module_handle), module_info,
137                                          build_id, pdb_name);
138 }
139 
140 }  // namespace
141 
142 // static
CreateModuleForAddress(uintptr_t address)143 std::unique_ptr<const ModuleCache::Module> ModuleCache::CreateModuleForAddress(
144     uintptr_t address) {
145   ScopedModuleHandle module_handle = GetModuleHandleForAddress(address);
146   if (!module_handle.IsValid())
147     return nullptr;
148   return CreateModuleForHandle(std::move(module_handle));
149 }
150 
151 }  // namespace base
152