// 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 #include #include #include "base/strings/string_number_conversions.h" namespace base { namespace { // Returns the unique build ID for a module loaded at |module_addr|. Returns the // empty string if the function fails to get the build ID. // // Build IDs are created by the concatenation of the module's GUID (Windows) / // UUID (Mac) and an "age" field that indicates how many times that GUID/UUID // has been reused. In Windows binaries, the "age" field is present in the // module header, but on the Mac, UUIDs are never reused and so the "age" value // appended to the UUID is always 0. std::string GetUniqueId(const void* module_addr) { const mach_header_64* mach_header = reinterpret_cast(module_addr); DCHECK_EQ(MH_MAGIC_64, mach_header->magic); size_t offset = sizeof(mach_header_64); size_t offset_limit = sizeof(mach_header_64) + mach_header->sizeofcmds; for (uint32_t i = 0; i < mach_header->ncmds; ++i) { if (offset + sizeof(load_command) >= offset_limit) return std::string(); const load_command* current_cmd = reinterpret_cast( reinterpret_cast(mach_header) + offset); if (offset + current_cmd->cmdsize > offset_limit) { // This command runs off the end of the command list. This is malformed. return std::string(); } if (current_cmd->cmd == LC_UUID) { if (current_cmd->cmdsize < sizeof(uuid_command)) { // This "UUID command" is too small. This is malformed. return std::string(); } const uuid_command* uuid_cmd = reinterpret_cast(current_cmd); static_assert(sizeof(uuid_cmd->uuid) == sizeof(uuid_t), "UUID field of UUID command should be 16 bytes."); // The ID is comprised of the UUID concatenated with the Mac's "age" value // which is always 0. return HexEncode(&uuid_cmd->uuid, sizeof(uuid_cmd->uuid)) + "0"; } offset += current_cmd->cmdsize; } return std::string(); } } // namespace // static ModuleCache::Module ModuleCache::CreateModuleForAddress(uintptr_t address) { Dl_info inf; if (!dladdr(reinterpret_cast(address), &inf)) return Module(); auto base_module_address = reinterpret_cast(inf.dli_fbase); return Module(base_module_address, GetUniqueId(inf.dli_fbase), FilePath(inf.dli_fname), GetModuleTextSize(inf.dli_fbase)); } size_t ModuleCache::GetModuleTextSize(const void* module_addr) { const mach_header_64* mach_header = reinterpret_cast(module_addr); DCHECK_EQ(MH_MAGIC_64, mach_header->magic); unsigned long module_size; getsegmentdata(mach_header, SEG_TEXT, &module_size); return module_size; } } // namespace base