| // Copyright 2018 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "base/sampling_heap_profiler/module_cache.h" |
| |
| #include <objbase.h> |
| #include <psapi.h> |
| |
| #include "base/process/process_handle.h" |
| #include "base/stl_util.h" |
| #include "base/strings/string_util.h" |
| #include "base/strings/stringprintf.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "base/win/pe_image.h" |
| #include "base/win/scoped_handle.h" |
| |
| namespace base { |
| |
| namespace { |
| |
| // Gets the unique build ID for a module. Windows build IDs are created by a |
| // concatenation of a GUID and AGE fields found in the headers of a module. The |
| // GUID is stored in the first 16 bytes and the AGE is stored in the last 4 |
| // bytes. Returns the empty string if the function fails to get the build ID. |
| // |
| // Example: |
| // dumpbin chrome.exe /headers | find "Format:" |
| // ... Format: RSDS, {16B2A428-1DED-442E-9A36-FCE8CBD29726}, 10, ... |
| // |
| // The resulting buildID string of this instance of chrome.exe is |
| // "16B2A4281DED442E9A36FCE8CBD2972610". |
| // |
| // Note that the AGE field is encoded in decimal, not hex. |
| std::string GetBuildIDForModule(HMODULE module_handle) { |
| GUID guid; |
| DWORD age; |
| if (!win::PEImage(module_handle) |
| .GetDebugId(&guid, &age, /* pdb_filename= */ nullptr, |
| /* pdb_filename_length= */ nullptr)) { |
| return std::string(); |
| } |
| const int kGUIDSize = 39; |
| string16 build_id; |
| int result = |
| ::StringFromGUID2(guid, WriteInto(&build_id, kGUIDSize), kGUIDSize); |
| if (result != kGUIDSize) |
| return std::string(); |
| RemoveChars(build_id, L"{}-", &build_id); |
| build_id += StringPrintf(L"%d", age); |
| return UTF16ToUTF8(build_id); |
| } |
| |
| } // namespace |
| |
| // static |
| ModuleCache::Module ModuleCache::CreateModuleForAddress(uintptr_t address) { |
| HMODULE module_handle = nullptr; |
| if (!::GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, |
| reinterpret_cast<LPCTSTR>(address), |
| &module_handle)) { |
| DCHECK_EQ(ERROR_MOD_NOT_FOUND, static_cast<int>(::GetLastError())); |
| return Module(); |
| } |
| Module module = CreateModuleForHandle(module_handle); |
| ::CloseHandle(module_handle); |
| return module; |
| } |
| |
| // static |
| ModuleCache::Module ModuleCache::CreateModuleForHandle(HMODULE module_handle) { |
| wchar_t module_name[MAX_PATH]; |
| DWORD result_length = |
| ::GetModuleFileName(module_handle, module_name, size(module_name)); |
| if (result_length == 0) |
| return Module(); |
| const std::string& module_id = GetBuildIDForModule(module_handle); |
| if (module_id.empty()) |
| return Module(); |
| |
| MODULEINFO module_info; |
| if (!::GetModuleInformation(GetCurrentProcessHandle(), module_handle, |
| &module_info, sizeof(module_info))) { |
| return Module(); |
| } |
| |
| return Module(reinterpret_cast<uintptr_t>(module_info.lpBaseOfDll), module_id, |
| FilePath(module_name), module_info.SizeOfImage); |
| } |
| |
| } // namespace base |