xref: /aosp_15_r20/external/cronet/base/profiler/module_cache_apple.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 <dlfcn.h>
8*6777b538SAndroid Build Coastguard Worker #include <mach-o/getsect.h>
9*6777b538SAndroid Build Coastguard Worker #include <string.h>
10*6777b538SAndroid Build Coastguard Worker #include <uuid/uuid.h>
11*6777b538SAndroid Build Coastguard Worker 
12*6777b538SAndroid Build Coastguard Worker #include "base/strings/string_number_conversions.h"
13*6777b538SAndroid Build Coastguard Worker #include "build/build_config.h"
14*6777b538SAndroid Build Coastguard Worker 
15*6777b538SAndroid Build Coastguard Worker namespace base {
16*6777b538SAndroid Build Coastguard Worker 
17*6777b538SAndroid Build Coastguard Worker namespace {
18*6777b538SAndroid Build Coastguard Worker 
19*6777b538SAndroid Build Coastguard Worker #if defined(ARCH_CPU_64_BITS)
20*6777b538SAndroid Build Coastguard Worker using MachHeaderType = mach_header_64;
21*6777b538SAndroid Build Coastguard Worker using SegmentCommandType = segment_command_64;
22*6777b538SAndroid Build Coastguard Worker constexpr uint32_t kMachHeaderMagic = MH_MAGIC_64;
23*6777b538SAndroid Build Coastguard Worker constexpr uint32_t kSegmentCommand = LC_SEGMENT_64;
24*6777b538SAndroid Build Coastguard Worker #else
25*6777b538SAndroid Build Coastguard Worker using MachHeaderType = mach_header;
26*6777b538SAndroid Build Coastguard Worker using SegmentCommandType = segment_command;
27*6777b538SAndroid Build Coastguard Worker constexpr uint32_t kMachHeaderMagic = MH_MAGIC;
28*6777b538SAndroid Build Coastguard Worker constexpr uint32_t kSegmentCommand = LC_SEGMENT;
29*6777b538SAndroid Build Coastguard Worker #endif
30*6777b538SAndroid Build Coastguard Worker 
31*6777b538SAndroid Build Coastguard Worker // Returns the unique build ID and text segment size for a module loaded at
32*6777b538SAndroid Build Coastguard Worker // |module_addr|. Returns the empty string and 0 if the function fails to get
33*6777b538SAndroid Build Coastguard Worker // the build ID or size.
34*6777b538SAndroid Build Coastguard Worker //
35*6777b538SAndroid Build Coastguard Worker // Build IDs are created by the concatenation of the module's GUID (Windows) /
36*6777b538SAndroid Build Coastguard Worker // UUID (Mac) and an "age" field that indicates how many times that GUID/UUID
37*6777b538SAndroid Build Coastguard Worker // has been reused. In Windows binaries, the "age" field is present in the
38*6777b538SAndroid Build Coastguard Worker // module header, but on the Mac, UUIDs are never reused and so the "age" value
39*6777b538SAndroid Build Coastguard Worker // appended to the UUID is always 0.
GetUniqueIdAndTextSize(const void * module_addr,std::string * unique_id,size_t * text_size)40*6777b538SAndroid Build Coastguard Worker void GetUniqueIdAndTextSize(const void* module_addr,
41*6777b538SAndroid Build Coastguard Worker                             std::string* unique_id,
42*6777b538SAndroid Build Coastguard Worker                             size_t* text_size) {
43*6777b538SAndroid Build Coastguard Worker   const MachHeaderType* mach_header =
44*6777b538SAndroid Build Coastguard Worker       reinterpret_cast<const MachHeaderType*>(module_addr);
45*6777b538SAndroid Build Coastguard Worker   DCHECK_EQ(mach_header->magic, kMachHeaderMagic);
46*6777b538SAndroid Build Coastguard Worker 
47*6777b538SAndroid Build Coastguard Worker   size_t offset = sizeof(MachHeaderType);
48*6777b538SAndroid Build Coastguard Worker   size_t offset_limit = sizeof(MachHeaderType) + mach_header->sizeofcmds;
49*6777b538SAndroid Build Coastguard Worker   bool found_uuid = false;
50*6777b538SAndroid Build Coastguard Worker   bool found_text_size = false;
51*6777b538SAndroid Build Coastguard Worker 
52*6777b538SAndroid Build Coastguard Worker   for (uint32_t i = 0; i < mach_header->ncmds; ++i) {
53*6777b538SAndroid Build Coastguard Worker     if (offset + sizeof(load_command) >= offset_limit) {
54*6777b538SAndroid Build Coastguard Worker       unique_id->clear();
55*6777b538SAndroid Build Coastguard Worker       *text_size = 0;
56*6777b538SAndroid Build Coastguard Worker       return;
57*6777b538SAndroid Build Coastguard Worker     }
58*6777b538SAndroid Build Coastguard Worker 
59*6777b538SAndroid Build Coastguard Worker     const load_command* load_cmd = reinterpret_cast<const load_command*>(
60*6777b538SAndroid Build Coastguard Worker         reinterpret_cast<const uint8_t*>(mach_header) + offset);
61*6777b538SAndroid Build Coastguard Worker 
62*6777b538SAndroid Build Coastguard Worker     if (offset + load_cmd->cmdsize > offset_limit) {
63*6777b538SAndroid Build Coastguard Worker       // This command runs off the end of the command list. This is malformed.
64*6777b538SAndroid Build Coastguard Worker       unique_id->clear();
65*6777b538SAndroid Build Coastguard Worker       *text_size = 0;
66*6777b538SAndroid Build Coastguard Worker       return;
67*6777b538SAndroid Build Coastguard Worker     }
68*6777b538SAndroid Build Coastguard Worker 
69*6777b538SAndroid Build Coastguard Worker     if (load_cmd->cmd == LC_UUID) {
70*6777b538SAndroid Build Coastguard Worker       if (load_cmd->cmdsize < sizeof(uuid_command)) {
71*6777b538SAndroid Build Coastguard Worker         // This "UUID command" is too small. This is malformed.
72*6777b538SAndroid Build Coastguard Worker         unique_id->clear();
73*6777b538SAndroid Build Coastguard Worker       } else {
74*6777b538SAndroid Build Coastguard Worker         const uuid_command* uuid_cmd =
75*6777b538SAndroid Build Coastguard Worker             reinterpret_cast<const uuid_command*>(load_cmd);
76*6777b538SAndroid Build Coastguard Worker         static_assert(sizeof(uuid_cmd->uuid) == sizeof(uuid_t),
77*6777b538SAndroid Build Coastguard Worker                       "UUID field of UUID command should be 16 bytes.");
78*6777b538SAndroid Build Coastguard Worker         // The ID comprises the UUID concatenated with the Mac's "age" value
79*6777b538SAndroid Build Coastguard Worker         // which is always 0.
80*6777b538SAndroid Build Coastguard Worker         unique_id->assign(HexEncode(&uuid_cmd->uuid, sizeof(uuid_cmd->uuid)) +
81*6777b538SAndroid Build Coastguard Worker                           "0");
82*6777b538SAndroid Build Coastguard Worker       }
83*6777b538SAndroid Build Coastguard Worker       if (found_text_size) {
84*6777b538SAndroid Build Coastguard Worker         return;
85*6777b538SAndroid Build Coastguard Worker       }
86*6777b538SAndroid Build Coastguard Worker       found_uuid = true;
87*6777b538SAndroid Build Coastguard Worker     } else if (load_cmd->cmd == kSegmentCommand) {
88*6777b538SAndroid Build Coastguard Worker       const SegmentCommandType* segment_cmd =
89*6777b538SAndroid Build Coastguard Worker           reinterpret_cast<const SegmentCommandType*>(load_cmd);
90*6777b538SAndroid Build Coastguard Worker       if (strncmp(segment_cmd->segname, SEG_TEXT,
91*6777b538SAndroid Build Coastguard Worker                   sizeof(segment_cmd->segname)) == 0) {
92*6777b538SAndroid Build Coastguard Worker         *text_size = segment_cmd->vmsize;
93*6777b538SAndroid Build Coastguard Worker         // Compare result with library function call, which is slower than this
94*6777b538SAndroid Build Coastguard Worker         // code.
95*6777b538SAndroid Build Coastguard Worker         unsigned long text_size_from_libmacho;
96*6777b538SAndroid Build Coastguard Worker         DCHECK(getsegmentdata(mach_header, SEG_TEXT, &text_size_from_libmacho));
97*6777b538SAndroid Build Coastguard Worker         DCHECK_EQ(*text_size, text_size_from_libmacho);
98*6777b538SAndroid Build Coastguard Worker       }
99*6777b538SAndroid Build Coastguard Worker       if (found_uuid) {
100*6777b538SAndroid Build Coastguard Worker         return;
101*6777b538SAndroid Build Coastguard Worker       }
102*6777b538SAndroid Build Coastguard Worker       found_text_size = true;
103*6777b538SAndroid Build Coastguard Worker     }
104*6777b538SAndroid Build Coastguard Worker     offset += load_cmd->cmdsize;
105*6777b538SAndroid Build Coastguard Worker   }
106*6777b538SAndroid Build Coastguard Worker 
107*6777b538SAndroid Build Coastguard Worker   if (!found_uuid) {
108*6777b538SAndroid Build Coastguard Worker     unique_id->clear();
109*6777b538SAndroid Build Coastguard Worker   }
110*6777b538SAndroid Build Coastguard Worker   if (!found_text_size) {
111*6777b538SAndroid Build Coastguard Worker     *text_size = 0;
112*6777b538SAndroid Build Coastguard Worker   }
113*6777b538SAndroid Build Coastguard Worker }
114*6777b538SAndroid Build Coastguard Worker 
115*6777b538SAndroid Build Coastguard Worker }  // namespace
116*6777b538SAndroid Build Coastguard Worker 
117*6777b538SAndroid Build Coastguard Worker class MacModule : public ModuleCache::Module {
118*6777b538SAndroid Build Coastguard Worker  public:
MacModule(const Dl_info & dl_info)119*6777b538SAndroid Build Coastguard Worker   explicit MacModule(const Dl_info& dl_info)
120*6777b538SAndroid Build Coastguard Worker       : base_address_(reinterpret_cast<uintptr_t>(dl_info.dli_fbase)),
121*6777b538SAndroid Build Coastguard Worker         debug_basename_(FilePath(dl_info.dli_fname).BaseName()) {
122*6777b538SAndroid Build Coastguard Worker     GetUniqueIdAndTextSize(dl_info.dli_fbase, &id_, &size_);
123*6777b538SAndroid Build Coastguard Worker   }
124*6777b538SAndroid Build Coastguard Worker 
125*6777b538SAndroid Build Coastguard Worker   MacModule(const MacModule&) = delete;
126*6777b538SAndroid Build Coastguard Worker   MacModule& operator=(const MacModule&) = delete;
127*6777b538SAndroid Build Coastguard Worker 
128*6777b538SAndroid Build Coastguard Worker   // ModuleCache::Module
GetBaseAddress() const129*6777b538SAndroid Build Coastguard Worker   uintptr_t GetBaseAddress() const override { return base_address_; }
GetId() const130*6777b538SAndroid Build Coastguard Worker   std::string GetId() const override { return id_; }
GetDebugBasename() const131*6777b538SAndroid Build Coastguard Worker   FilePath GetDebugBasename() const override { return debug_basename_; }
GetSize() const132*6777b538SAndroid Build Coastguard Worker   size_t GetSize() const override { return size_; }
IsNative() const133*6777b538SAndroid Build Coastguard Worker   bool IsNative() const override { return true; }
134*6777b538SAndroid Build Coastguard Worker 
135*6777b538SAndroid Build Coastguard Worker  private:
136*6777b538SAndroid Build Coastguard Worker   uintptr_t base_address_;
137*6777b538SAndroid Build Coastguard Worker   std::string id_;
138*6777b538SAndroid Build Coastguard Worker   FilePath debug_basename_;
139*6777b538SAndroid Build Coastguard Worker   size_t size_;
140*6777b538SAndroid Build Coastguard Worker };
141*6777b538SAndroid Build Coastguard Worker 
142*6777b538SAndroid Build Coastguard Worker // static
CreateModuleForAddress(uintptr_t address)143*6777b538SAndroid Build Coastguard Worker std::unique_ptr<const ModuleCache::Module> ModuleCache::CreateModuleForAddress(
144*6777b538SAndroid Build Coastguard Worker     uintptr_t address) {
145*6777b538SAndroid Build Coastguard Worker   Dl_info info;
146*6777b538SAndroid Build Coastguard Worker   if (!dladdr(reinterpret_cast<const void*>(address), &info)) {
147*6777b538SAndroid Build Coastguard Worker     return nullptr;
148*6777b538SAndroid Build Coastguard Worker   }
149*6777b538SAndroid Build Coastguard Worker   return std::make_unique<MacModule>(info);
150*6777b538SAndroid Build Coastguard Worker }
151*6777b538SAndroid Build Coastguard Worker 
152*6777b538SAndroid Build Coastguard Worker }  // namespace base
153