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