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 <elf.h>
9*6777b538SAndroid Build Coastguard Worker
10*6777b538SAndroid Build Coastguard Worker #include <optional>
11*6777b538SAndroid Build Coastguard Worker #include <string_view>
12*6777b538SAndroid Build Coastguard Worker
13*6777b538SAndroid Build Coastguard Worker #include "base/debug/elf_reader.h"
14*6777b538SAndroid Build Coastguard Worker #include "build/build_config.h"
15*6777b538SAndroid Build Coastguard Worker
16*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_ANDROID)
17*6777b538SAndroid Build Coastguard Worker extern "C" {
18*6777b538SAndroid Build Coastguard Worker // &__executable_start is the start address of the current module.
19*6777b538SAndroid Build Coastguard Worker extern const char __executable_start;
20*6777b538SAndroid Build Coastguard Worker // &__etext is the end addesss of the code segment in the current module.
21*6777b538SAndroid Build Coastguard Worker extern const char _etext;
22*6777b538SAndroid Build Coastguard Worker }
23*6777b538SAndroid Build Coastguard Worker #endif
24*6777b538SAndroid Build Coastguard Worker
25*6777b538SAndroid Build Coastguard Worker namespace base {
26*6777b538SAndroid Build Coastguard Worker
27*6777b538SAndroid Build Coastguard Worker namespace {
28*6777b538SAndroid Build Coastguard Worker
29*6777b538SAndroid Build Coastguard Worker // Returns the unique build ID for a module loaded at |module_addr|. Returns the
30*6777b538SAndroid Build Coastguard Worker // empty string if the function fails to get the build ID.
31*6777b538SAndroid Build Coastguard Worker //
32*6777b538SAndroid Build Coastguard Worker // Build IDs follow a cross-platform format consisting of several fields
33*6777b538SAndroid Build Coastguard Worker // concatenated together:
34*6777b538SAndroid Build Coastguard Worker // - the module's unique ID, and
35*6777b538SAndroid Build Coastguard Worker // - the age suffix for incremental builds.
36*6777b538SAndroid Build Coastguard Worker //
37*6777b538SAndroid Build Coastguard Worker // On POSIX, the unique ID is read from the ELF binary located at |module_addr|.
38*6777b538SAndroid Build Coastguard Worker // The age field is always 0.
GetUniqueBuildId(const void * module_addr)39*6777b538SAndroid Build Coastguard Worker std::string GetUniqueBuildId(const void* module_addr) {
40*6777b538SAndroid Build Coastguard Worker debug::ElfBuildIdBuffer build_id;
41*6777b538SAndroid Build Coastguard Worker size_t build_id_length = debug::ReadElfBuildId(module_addr, true, build_id);
42*6777b538SAndroid Build Coastguard Worker if (!build_id_length)
43*6777b538SAndroid Build Coastguard Worker return std::string();
44*6777b538SAndroid Build Coastguard Worker
45*6777b538SAndroid Build Coastguard Worker // Append 0 for the age value.
46*6777b538SAndroid Build Coastguard Worker return std::string(build_id, build_id_length) + "0";
47*6777b538SAndroid Build Coastguard Worker }
48*6777b538SAndroid Build Coastguard Worker
49*6777b538SAndroid Build Coastguard Worker // Returns the offset from |module_addr| to the first byte following the last
50*6777b538SAndroid Build Coastguard Worker // executable segment from the ELF file mapped at |module_addr|.
51*6777b538SAndroid Build Coastguard Worker // It's defined this way so that any executable address from this module is in
52*6777b538SAndroid Build Coastguard Worker // range [addr, addr + GetLastExecutableOffset(addr)).
53*6777b538SAndroid Build Coastguard Worker // If no executable segment is found, returns 0.
GetLastExecutableOffset(const void * module_addr)54*6777b538SAndroid Build Coastguard Worker size_t GetLastExecutableOffset(const void* module_addr) {
55*6777b538SAndroid Build Coastguard Worker const size_t relocation_offset = debug::GetRelocationOffset(module_addr);
56*6777b538SAndroid Build Coastguard Worker size_t max_offset = 0;
57*6777b538SAndroid Build Coastguard Worker for (const Phdr& header : debug::GetElfProgramHeaders(module_addr)) {
58*6777b538SAndroid Build Coastguard Worker if (header.p_type != PT_LOAD || !(header.p_flags & PF_X))
59*6777b538SAndroid Build Coastguard Worker continue;
60*6777b538SAndroid Build Coastguard Worker
61*6777b538SAndroid Build Coastguard Worker max_offset = std::max(
62*6777b538SAndroid Build Coastguard Worker max_offset, static_cast<size_t>(
63*6777b538SAndroid Build Coastguard Worker header.p_vaddr + relocation_offset + header.p_memsz -
64*6777b538SAndroid Build Coastguard Worker reinterpret_cast<uintptr_t>(module_addr)));
65*6777b538SAndroid Build Coastguard Worker }
66*6777b538SAndroid Build Coastguard Worker
67*6777b538SAndroid Build Coastguard Worker return max_offset;
68*6777b538SAndroid Build Coastguard Worker }
69*6777b538SAndroid Build Coastguard Worker
GetDebugBasenameForModule(const void * base_address,std::string_view file)70*6777b538SAndroid Build Coastguard Worker FilePath GetDebugBasenameForModule(const void* base_address,
71*6777b538SAndroid Build Coastguard Worker std::string_view file) {
72*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_ANDROID)
73*6777b538SAndroid Build Coastguard Worker // Preferentially identify the library using its soname on Android. Libraries
74*6777b538SAndroid Build Coastguard Worker // mapped directly from apks have the apk filename in |dl_info.dli_fname|, and
75*6777b538SAndroid Build Coastguard Worker // this doesn't distinguish the particular library.
76*6777b538SAndroid Build Coastguard Worker std::optional<std::string_view> library_name =
77*6777b538SAndroid Build Coastguard Worker debug::ReadElfLibraryName(base_address);
78*6777b538SAndroid Build Coastguard Worker if (library_name)
79*6777b538SAndroid Build Coastguard Worker return FilePath(*library_name);
80*6777b538SAndroid Build Coastguard Worker #endif // BUILDFLAG(IS_ANDROID)
81*6777b538SAndroid Build Coastguard Worker
82*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_CHROMEOS)
83*6777b538SAndroid Build Coastguard Worker // SetProcessTitleFromCommandLine() does not play well with dladdr(). In
84*6777b538SAndroid Build Coastguard Worker // particular, after calling our setproctitle(), calling dladdr() with an
85*6777b538SAndroid Build Coastguard Worker // address in the main binary will return the complete command line of the
86*6777b538SAndroid Build Coastguard Worker // program, including all arguments, in dli_fname. If we get a complete
87*6777b538SAndroid Build Coastguard Worker // command-line like "/opt/google/chrome/chrome --type=gpu-process
88*6777b538SAndroid Build Coastguard Worker // --gpu-sandbox-failures-fatal=yes --enable-logging ...", strip off
89*6777b538SAndroid Build Coastguard Worker // everything that looks like an argument. This is safe on ChromeOS, where we
90*6777b538SAndroid Build Coastguard Worker // control the directory and file names and know that no chrome binary or
91*6777b538SAndroid Build Coastguard Worker // system library will have a " --" in the path.
92*6777b538SAndroid Build Coastguard Worker base::StringPiece::size_type pos = file.find(" --");
93*6777b538SAndroid Build Coastguard Worker if (pos != base::StringPiece::npos) {
94*6777b538SAndroid Build Coastguard Worker file = file.substr(0, pos);
95*6777b538SAndroid Build Coastguard Worker }
96*6777b538SAndroid Build Coastguard Worker #endif // BUILDFLAG(IS_CHROMEOS)
97*6777b538SAndroid Build Coastguard Worker
98*6777b538SAndroid Build Coastguard Worker return FilePath(file).BaseName();
99*6777b538SAndroid Build Coastguard Worker }
100*6777b538SAndroid Build Coastguard Worker
101*6777b538SAndroid Build Coastguard Worker class PosixModule : public ModuleCache::Module {
102*6777b538SAndroid Build Coastguard Worker public:
103*6777b538SAndroid Build Coastguard Worker PosixModule(uintptr_t base_address,
104*6777b538SAndroid Build Coastguard Worker const std::string& build_id,
105*6777b538SAndroid Build Coastguard Worker const FilePath& debug_basename,
106*6777b538SAndroid Build Coastguard Worker size_t size);
107*6777b538SAndroid Build Coastguard Worker
108*6777b538SAndroid Build Coastguard Worker PosixModule(const PosixModule&) = delete;
109*6777b538SAndroid Build Coastguard Worker PosixModule& operator=(const PosixModule&) = delete;
110*6777b538SAndroid Build Coastguard Worker
111*6777b538SAndroid Build Coastguard Worker // ModuleCache::Module
GetBaseAddress() const112*6777b538SAndroid Build Coastguard Worker uintptr_t GetBaseAddress() const override { return base_address_; }
GetId() const113*6777b538SAndroid Build Coastguard Worker std::string GetId() const override { return id_; }
GetDebugBasename() const114*6777b538SAndroid Build Coastguard Worker FilePath GetDebugBasename() const override { return debug_basename_; }
GetSize() const115*6777b538SAndroid Build Coastguard Worker size_t GetSize() const override { return size_; }
IsNative() const116*6777b538SAndroid Build Coastguard Worker bool IsNative() const override { return true; }
117*6777b538SAndroid Build Coastguard Worker
118*6777b538SAndroid Build Coastguard Worker private:
119*6777b538SAndroid Build Coastguard Worker uintptr_t base_address_;
120*6777b538SAndroid Build Coastguard Worker std::string id_;
121*6777b538SAndroid Build Coastguard Worker FilePath debug_basename_;
122*6777b538SAndroid Build Coastguard Worker size_t size_;
123*6777b538SAndroid Build Coastguard Worker };
124*6777b538SAndroid Build Coastguard Worker
PosixModule(uintptr_t base_address,const std::string & build_id,const FilePath & debug_basename,size_t size)125*6777b538SAndroid Build Coastguard Worker PosixModule::PosixModule(uintptr_t base_address,
126*6777b538SAndroid Build Coastguard Worker const std::string& build_id,
127*6777b538SAndroid Build Coastguard Worker const FilePath& debug_basename,
128*6777b538SAndroid Build Coastguard Worker size_t size)
129*6777b538SAndroid Build Coastguard Worker : base_address_(base_address),
130*6777b538SAndroid Build Coastguard Worker id_(build_id),
131*6777b538SAndroid Build Coastguard Worker debug_basename_(debug_basename),
132*6777b538SAndroid Build Coastguard Worker size_(size) {}
133*6777b538SAndroid Build Coastguard Worker
134*6777b538SAndroid Build Coastguard Worker } // namespace
135*6777b538SAndroid Build Coastguard Worker
136*6777b538SAndroid Build Coastguard Worker // static
CreateModuleForAddress(uintptr_t address)137*6777b538SAndroid Build Coastguard Worker std::unique_ptr<const ModuleCache::Module> ModuleCache::CreateModuleForAddress(
138*6777b538SAndroid Build Coastguard Worker uintptr_t address) {
139*6777b538SAndroid Build Coastguard Worker Dl_info info;
140*6777b538SAndroid Build Coastguard Worker if (!dladdr(reinterpret_cast<const void*>(address), &info)) {
141*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_ANDROID)
142*6777b538SAndroid Build Coastguard Worker // dladdr doesn't know about the Chrome module in Android targets using the
143*6777b538SAndroid Build Coastguard Worker // crazy linker. Explicitly check against the module's extents in that case.
144*6777b538SAndroid Build Coastguard Worker // This is checked after dladdr because if dladdr CAN find the Chrome
145*6777b538SAndroid Build Coastguard Worker // module, it will return a better fallback basename in `info.dli_fname`.
146*6777b538SAndroid Build Coastguard Worker if (address >= reinterpret_cast<uintptr_t>(&__executable_start) &&
147*6777b538SAndroid Build Coastguard Worker address < reinterpret_cast<uintptr_t>(&_etext)) {
148*6777b538SAndroid Build Coastguard Worker const void* const base_address =
149*6777b538SAndroid Build Coastguard Worker reinterpret_cast<const void*>(&__executable_start);
150*6777b538SAndroid Build Coastguard Worker return std::make_unique<PosixModule>(
151*6777b538SAndroid Build Coastguard Worker reinterpret_cast<uintptr_t>(&__executable_start),
152*6777b538SAndroid Build Coastguard Worker GetUniqueBuildId(base_address),
153*6777b538SAndroid Build Coastguard Worker // Extract the soname from the module. It is expected to exist, but if
154*6777b538SAndroid Build Coastguard Worker // it doesn't use an empty string.
155*6777b538SAndroid Build Coastguard Worker GetDebugBasenameForModule(base_address, /* file = */ ""),
156*6777b538SAndroid Build Coastguard Worker GetLastExecutableOffset(base_address));
157*6777b538SAndroid Build Coastguard Worker }
158*6777b538SAndroid Build Coastguard Worker #endif
159*6777b538SAndroid Build Coastguard Worker return nullptr;
160*6777b538SAndroid Build Coastguard Worker }
161*6777b538SAndroid Build Coastguard Worker
162*6777b538SAndroid Build Coastguard Worker return std::make_unique<PosixModule>(
163*6777b538SAndroid Build Coastguard Worker reinterpret_cast<uintptr_t>(info.dli_fbase),
164*6777b538SAndroid Build Coastguard Worker GetUniqueBuildId(info.dli_fbase),
165*6777b538SAndroid Build Coastguard Worker GetDebugBasenameForModule(info.dli_fbase, info.dli_fname),
166*6777b538SAndroid Build Coastguard Worker GetLastExecutableOffset(info.dli_fbase));
167*6777b538SAndroid Build Coastguard Worker }
168*6777b538SAndroid Build Coastguard Worker
169*6777b538SAndroid Build Coastguard Worker } // namespace base
170