1*6dbdd20aSAndroid Build Coastguard Worker /*
2*6dbdd20aSAndroid Build Coastguard Worker * Copyright (C) 2019 The Android Open Source Project
3*6dbdd20aSAndroid Build Coastguard Worker *
4*6dbdd20aSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*6dbdd20aSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*6dbdd20aSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*6dbdd20aSAndroid Build Coastguard Worker *
8*6dbdd20aSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*6dbdd20aSAndroid Build Coastguard Worker *
10*6dbdd20aSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*6dbdd20aSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*6dbdd20aSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*6dbdd20aSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*6dbdd20aSAndroid Build Coastguard Worker * limitations under the License.
15*6dbdd20aSAndroid Build Coastguard Worker */
16*6dbdd20aSAndroid Build Coastguard Worker
17*6dbdd20aSAndroid Build Coastguard Worker #include "src/profiling/symbolizer/local_symbolizer.h"
18*6dbdd20aSAndroid Build Coastguard Worker
19*6dbdd20aSAndroid Build Coastguard Worker #include <fcntl.h>
20*6dbdd20aSAndroid Build Coastguard Worker
21*6dbdd20aSAndroid Build Coastguard Worker #include <charconv>
22*6dbdd20aSAndroid Build Coastguard Worker #include <cinttypes>
23*6dbdd20aSAndroid Build Coastguard Worker #include <limits>
24*6dbdd20aSAndroid Build Coastguard Worker #include <memory>
25*6dbdd20aSAndroid Build Coastguard Worker #include <optional>
26*6dbdd20aSAndroid Build Coastguard Worker #include <sstream>
27*6dbdd20aSAndroid Build Coastguard Worker #include <string>
28*6dbdd20aSAndroid Build Coastguard Worker #include <vector>
29*6dbdd20aSAndroid Build Coastguard Worker
30*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/base/build_config.h"
31*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/base/compiler.h"
32*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/base/logging.h"
33*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/file_utils.h"
34*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/scoped_file.h"
35*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/scoped_mmap.h"
36*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/string_utils.h"
37*6dbdd20aSAndroid Build Coastguard Worker #include "src/profiling/symbolizer/elf.h"
38*6dbdd20aSAndroid Build Coastguard Worker #include "src/profiling/symbolizer/filesystem.h"
39*6dbdd20aSAndroid Build Coastguard Worker
40*6dbdd20aSAndroid Build Coastguard Worker namespace perfetto {
41*6dbdd20aSAndroid Build Coastguard Worker namespace profiling {
42*6dbdd20aSAndroid Build Coastguard Worker
43*6dbdd20aSAndroid Build Coastguard Worker // TODO(fmayer): Fix up name. This suggests it always returns a symbolizer or
44*6dbdd20aSAndroid Build Coastguard Worker // dies, which isn't the case.
LocalSymbolizerOrDie(std::vector<std::string> binary_path,const char * mode)45*6dbdd20aSAndroid Build Coastguard Worker std::unique_ptr<Symbolizer> LocalSymbolizerOrDie(
46*6dbdd20aSAndroid Build Coastguard Worker std::vector<std::string> binary_path,
47*6dbdd20aSAndroid Build Coastguard Worker const char* mode) {
48*6dbdd20aSAndroid Build Coastguard Worker std::unique_ptr<Symbolizer> symbolizer;
49*6dbdd20aSAndroid Build Coastguard Worker
50*6dbdd20aSAndroid Build Coastguard Worker if (!binary_path.empty()) {
51*6dbdd20aSAndroid Build Coastguard Worker #if PERFETTO_BUILDFLAG(PERFETTO_LOCAL_SYMBOLIZER)
52*6dbdd20aSAndroid Build Coastguard Worker std::unique_ptr<BinaryFinder> finder;
53*6dbdd20aSAndroid Build Coastguard Worker if (!mode || strncmp(mode, "find", 4) == 0)
54*6dbdd20aSAndroid Build Coastguard Worker finder.reset(new LocalBinaryFinder(std::move(binary_path)));
55*6dbdd20aSAndroid Build Coastguard Worker else if (strncmp(mode, "index", 5) == 0)
56*6dbdd20aSAndroid Build Coastguard Worker finder.reset(new LocalBinaryIndexer(std::move(binary_path)));
57*6dbdd20aSAndroid Build Coastguard Worker else
58*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_FATAL("Invalid symbolizer mode [find | index]: %s", mode);
59*6dbdd20aSAndroid Build Coastguard Worker symbolizer.reset(new LocalSymbolizer(std::move(finder)));
60*6dbdd20aSAndroid Build Coastguard Worker #else
61*6dbdd20aSAndroid Build Coastguard Worker base::ignore_result(mode);
62*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_FATAL("This build does not support local symbolization.");
63*6dbdd20aSAndroid Build Coastguard Worker #endif
64*6dbdd20aSAndroid Build Coastguard Worker }
65*6dbdd20aSAndroid Build Coastguard Worker return symbolizer;
66*6dbdd20aSAndroid Build Coastguard Worker }
67*6dbdd20aSAndroid Build Coastguard Worker
68*6dbdd20aSAndroid Build Coastguard Worker } // namespace profiling
69*6dbdd20aSAndroid Build Coastguard Worker } // namespace perfetto
70*6dbdd20aSAndroid Build Coastguard Worker
71*6dbdd20aSAndroid Build Coastguard Worker #if PERFETTO_BUILDFLAG(PERFETTO_LOCAL_SYMBOLIZER)
72*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/string_splitter.h"
73*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/string_utils.h"
74*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/utils.h"
75*6dbdd20aSAndroid Build Coastguard Worker
76*6dbdd20aSAndroid Build Coastguard Worker #include <signal.h>
77*6dbdd20aSAndroid Build Coastguard Worker #include <sys/stat.h>
78*6dbdd20aSAndroid Build Coastguard Worker #include <sys/types.h>
79*6dbdd20aSAndroid Build Coastguard Worker
80*6dbdd20aSAndroid Build Coastguard Worker #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
81*6dbdd20aSAndroid Build Coastguard Worker constexpr const char* kDefaultSymbolizer = "llvm-symbolizer.exe";
82*6dbdd20aSAndroid Build Coastguard Worker #else
83*6dbdd20aSAndroid Build Coastguard Worker constexpr const char* kDefaultSymbolizer = "llvm-symbolizer";
84*6dbdd20aSAndroid Build Coastguard Worker #endif
85*6dbdd20aSAndroid Build Coastguard Worker
86*6dbdd20aSAndroid Build Coastguard Worker namespace perfetto {
87*6dbdd20aSAndroid Build Coastguard Worker namespace profiling {
88*6dbdd20aSAndroid Build Coastguard Worker
89*6dbdd20aSAndroid Build Coastguard Worker namespace {
90*6dbdd20aSAndroid Build Coastguard Worker
GetLine(std::function<int64_t (char *,size_t)> fn_read)91*6dbdd20aSAndroid Build Coastguard Worker std::string GetLine(std::function<int64_t(char*, size_t)> fn_read) {
92*6dbdd20aSAndroid Build Coastguard Worker std::string line;
93*6dbdd20aSAndroid Build Coastguard Worker char buffer[512];
94*6dbdd20aSAndroid Build Coastguard Worker int64_t rd = 0;
95*6dbdd20aSAndroid Build Coastguard Worker while ((rd = fn_read(buffer, sizeof(buffer))) > 0) {
96*6dbdd20aSAndroid Build Coastguard Worker std::string data(buffer, static_cast<size_t>(rd));
97*6dbdd20aSAndroid Build Coastguard Worker line += data;
98*6dbdd20aSAndroid Build Coastguard Worker if (line.back() == '\n') {
99*6dbdd20aSAndroid Build Coastguard Worker break;
100*6dbdd20aSAndroid Build Coastguard Worker }
101*6dbdd20aSAndroid Build Coastguard Worker // There should be no intermediate new lines in the read data.
102*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_DCHECK(line.find('\n') == std::string::npos);
103*6dbdd20aSAndroid Build Coastguard Worker }
104*6dbdd20aSAndroid Build Coastguard Worker if (rd == -1) {
105*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_ELOG("Failed to read data from subprocess.");
106*6dbdd20aSAndroid Build Coastguard Worker }
107*6dbdd20aSAndroid Build Coastguard Worker return line;
108*6dbdd20aSAndroid Build Coastguard Worker }
109*6dbdd20aSAndroid Build Coastguard Worker
InRange(const void * base,size_t total_size,const void * ptr,size_t size)110*6dbdd20aSAndroid Build Coastguard Worker bool InRange(const void* base,
111*6dbdd20aSAndroid Build Coastguard Worker size_t total_size,
112*6dbdd20aSAndroid Build Coastguard Worker const void* ptr,
113*6dbdd20aSAndroid Build Coastguard Worker size_t size) {
114*6dbdd20aSAndroid Build Coastguard Worker return ptr >= base && static_cast<const char*>(ptr) + size <=
115*6dbdd20aSAndroid Build Coastguard Worker static_cast<const char*>(base) + total_size;
116*6dbdd20aSAndroid Build Coastguard Worker }
117*6dbdd20aSAndroid Build Coastguard Worker
118*6dbdd20aSAndroid Build Coastguard Worker template <typename E>
GetElfLoadBias(void * mem,size_t size)119*6dbdd20aSAndroid Build Coastguard Worker std::optional<uint64_t> GetElfLoadBias(void* mem, size_t size) {
120*6dbdd20aSAndroid Build Coastguard Worker const typename E::Ehdr* ehdr = static_cast<typename E::Ehdr*>(mem);
121*6dbdd20aSAndroid Build Coastguard Worker if (!InRange(mem, size, ehdr, sizeof(typename E::Ehdr))) {
122*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_ELOG("Corrupted ELF.");
123*6dbdd20aSAndroid Build Coastguard Worker return std::nullopt;
124*6dbdd20aSAndroid Build Coastguard Worker }
125*6dbdd20aSAndroid Build Coastguard Worker for (size_t i = 0; i < ehdr->e_phnum; ++i) {
126*6dbdd20aSAndroid Build Coastguard Worker typename E::Phdr* phdr = GetPhdr<E>(mem, ehdr, i);
127*6dbdd20aSAndroid Build Coastguard Worker if (!InRange(mem, size, phdr, sizeof(typename E::Phdr))) {
128*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_ELOG("Corrupted ELF.");
129*6dbdd20aSAndroid Build Coastguard Worker return std::nullopt;
130*6dbdd20aSAndroid Build Coastguard Worker }
131*6dbdd20aSAndroid Build Coastguard Worker if (phdr->p_type == PT_LOAD && phdr->p_flags & PF_X) {
132*6dbdd20aSAndroid Build Coastguard Worker return phdr->p_vaddr - phdr->p_offset;
133*6dbdd20aSAndroid Build Coastguard Worker }
134*6dbdd20aSAndroid Build Coastguard Worker }
135*6dbdd20aSAndroid Build Coastguard Worker return 0u;
136*6dbdd20aSAndroid Build Coastguard Worker }
137*6dbdd20aSAndroid Build Coastguard Worker
138*6dbdd20aSAndroid Build Coastguard Worker template <typename E>
GetElfBuildId(void * mem,size_t size)139*6dbdd20aSAndroid Build Coastguard Worker std::optional<std::string> GetElfBuildId(void* mem, size_t size) {
140*6dbdd20aSAndroid Build Coastguard Worker const typename E::Ehdr* ehdr = static_cast<typename E::Ehdr*>(mem);
141*6dbdd20aSAndroid Build Coastguard Worker if (!InRange(mem, size, ehdr, sizeof(typename E::Ehdr))) {
142*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_ELOG("Corrupted ELF.");
143*6dbdd20aSAndroid Build Coastguard Worker return std::nullopt;
144*6dbdd20aSAndroid Build Coastguard Worker }
145*6dbdd20aSAndroid Build Coastguard Worker for (size_t i = 0; i < ehdr->e_shnum; ++i) {
146*6dbdd20aSAndroid Build Coastguard Worker typename E::Shdr* shdr = GetShdr<E>(mem, ehdr, i);
147*6dbdd20aSAndroid Build Coastguard Worker if (!InRange(mem, size, shdr, sizeof(typename E::Shdr))) {
148*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_ELOG("Corrupted ELF.");
149*6dbdd20aSAndroid Build Coastguard Worker return std::nullopt;
150*6dbdd20aSAndroid Build Coastguard Worker }
151*6dbdd20aSAndroid Build Coastguard Worker
152*6dbdd20aSAndroid Build Coastguard Worker if (shdr->sh_type != SHT_NOTE)
153*6dbdd20aSAndroid Build Coastguard Worker continue;
154*6dbdd20aSAndroid Build Coastguard Worker
155*6dbdd20aSAndroid Build Coastguard Worker auto offset = shdr->sh_offset;
156*6dbdd20aSAndroid Build Coastguard Worker while (offset < shdr->sh_offset + shdr->sh_size) {
157*6dbdd20aSAndroid Build Coastguard Worker typename E::Nhdr* nhdr =
158*6dbdd20aSAndroid Build Coastguard Worker reinterpret_cast<typename E::Nhdr*>(static_cast<char*>(mem) + offset);
159*6dbdd20aSAndroid Build Coastguard Worker
160*6dbdd20aSAndroid Build Coastguard Worker if (!InRange(mem, size, nhdr, sizeof(typename E::Nhdr))) {
161*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_ELOG("Corrupted ELF.");
162*6dbdd20aSAndroid Build Coastguard Worker return std::nullopt;
163*6dbdd20aSAndroid Build Coastguard Worker }
164*6dbdd20aSAndroid Build Coastguard Worker if (nhdr->n_type == NT_GNU_BUILD_ID && nhdr->n_namesz == 4) {
165*6dbdd20aSAndroid Build Coastguard Worker char* name = reinterpret_cast<char*>(nhdr) + sizeof(*nhdr);
166*6dbdd20aSAndroid Build Coastguard Worker if (!InRange(mem, size, name, 4)) {
167*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_ELOG("Corrupted ELF.");
168*6dbdd20aSAndroid Build Coastguard Worker return std::nullopt;
169*6dbdd20aSAndroid Build Coastguard Worker }
170*6dbdd20aSAndroid Build Coastguard Worker if (memcmp(name, "GNU", 3) == 0) {
171*6dbdd20aSAndroid Build Coastguard Worker const char* value = reinterpret_cast<char*>(nhdr) + sizeof(*nhdr) +
172*6dbdd20aSAndroid Build Coastguard Worker base::AlignUp<4>(nhdr->n_namesz);
173*6dbdd20aSAndroid Build Coastguard Worker
174*6dbdd20aSAndroid Build Coastguard Worker if (!InRange(mem, size, value, nhdr->n_descsz)) {
175*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_ELOG("Corrupted ELF.");
176*6dbdd20aSAndroid Build Coastguard Worker return std::nullopt;
177*6dbdd20aSAndroid Build Coastguard Worker }
178*6dbdd20aSAndroid Build Coastguard Worker return std::string(value, nhdr->n_descsz);
179*6dbdd20aSAndroid Build Coastguard Worker }
180*6dbdd20aSAndroid Build Coastguard Worker }
181*6dbdd20aSAndroid Build Coastguard Worker offset += sizeof(*nhdr) + base::AlignUp<4>(nhdr->n_namesz) +
182*6dbdd20aSAndroid Build Coastguard Worker base::AlignUp<4>(nhdr->n_descsz);
183*6dbdd20aSAndroid Build Coastguard Worker }
184*6dbdd20aSAndroid Build Coastguard Worker }
185*6dbdd20aSAndroid Build Coastguard Worker return std::nullopt;
186*6dbdd20aSAndroid Build Coastguard Worker }
187*6dbdd20aSAndroid Build Coastguard Worker
SplitBuildID(const std::string & hex_build_id)188*6dbdd20aSAndroid Build Coastguard Worker std::string SplitBuildID(const std::string& hex_build_id) {
189*6dbdd20aSAndroid Build Coastguard Worker if (hex_build_id.size() < 3) {
190*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_DFATAL_OR_ELOG("Invalid build-id (< 3 char) %s",
191*6dbdd20aSAndroid Build Coastguard Worker hex_build_id.c_str());
192*6dbdd20aSAndroid Build Coastguard Worker return {};
193*6dbdd20aSAndroid Build Coastguard Worker }
194*6dbdd20aSAndroid Build Coastguard Worker
195*6dbdd20aSAndroid Build Coastguard Worker return hex_build_id.substr(0, 2) + "/" + hex_build_id.substr(2);
196*6dbdd20aSAndroid Build Coastguard Worker }
197*6dbdd20aSAndroid Build Coastguard Worker
IsElf(const char * mem,size_t size)198*6dbdd20aSAndroid Build Coastguard Worker bool IsElf(const char* mem, size_t size) {
199*6dbdd20aSAndroid Build Coastguard Worker if (size <= EI_MAG3)
200*6dbdd20aSAndroid Build Coastguard Worker return false;
201*6dbdd20aSAndroid Build Coastguard Worker return (mem[EI_MAG0] == ELFMAG0 && mem[EI_MAG1] == ELFMAG1 &&
202*6dbdd20aSAndroid Build Coastguard Worker mem[EI_MAG2] == ELFMAG2 && mem[EI_MAG3] == ELFMAG3);
203*6dbdd20aSAndroid Build Coastguard Worker }
204*6dbdd20aSAndroid Build Coastguard Worker
205*6dbdd20aSAndroid Build Coastguard Worker constexpr uint32_t kMachO64Magic = 0xfeedfacf;
206*6dbdd20aSAndroid Build Coastguard Worker
IsMachO64(const char * mem,size_t size)207*6dbdd20aSAndroid Build Coastguard Worker bool IsMachO64(const char* mem, size_t size) {
208*6dbdd20aSAndroid Build Coastguard Worker if (size < sizeof(kMachO64Magic))
209*6dbdd20aSAndroid Build Coastguard Worker return false;
210*6dbdd20aSAndroid Build Coastguard Worker return memcmp(mem, &kMachO64Magic, sizeof(kMachO64Magic)) == 0;
211*6dbdd20aSAndroid Build Coastguard Worker }
212*6dbdd20aSAndroid Build Coastguard Worker
213*6dbdd20aSAndroid Build Coastguard Worker struct mach_header_64 {
214*6dbdd20aSAndroid Build Coastguard Worker uint32_t magic; /* mach magic number identifier */
215*6dbdd20aSAndroid Build Coastguard Worker int32_t cputype; /* cpu specifier */
216*6dbdd20aSAndroid Build Coastguard Worker int32_t cpusubtype; /* machine specifier */
217*6dbdd20aSAndroid Build Coastguard Worker uint32_t filetype; /* type of file */
218*6dbdd20aSAndroid Build Coastguard Worker uint32_t ncmds; /* number of load commands */
219*6dbdd20aSAndroid Build Coastguard Worker uint32_t sizeofcmds; /* the size of all the load commands */
220*6dbdd20aSAndroid Build Coastguard Worker uint32_t flags; /* flags */
221*6dbdd20aSAndroid Build Coastguard Worker uint32_t reserved; /* reserved */
222*6dbdd20aSAndroid Build Coastguard Worker };
223*6dbdd20aSAndroid Build Coastguard Worker
224*6dbdd20aSAndroid Build Coastguard Worker struct load_command {
225*6dbdd20aSAndroid Build Coastguard Worker uint32_t cmd; /* type of load command */
226*6dbdd20aSAndroid Build Coastguard Worker uint32_t cmdsize; /* total size of command in bytes */
227*6dbdd20aSAndroid Build Coastguard Worker };
228*6dbdd20aSAndroid Build Coastguard Worker
229*6dbdd20aSAndroid Build Coastguard Worker struct segment_64_command {
230*6dbdd20aSAndroid Build Coastguard Worker uint32_t cmd; /* LC_SEGMENT_64 */
231*6dbdd20aSAndroid Build Coastguard Worker uint32_t cmdsize; /* includes sizeof section_64 structs */
232*6dbdd20aSAndroid Build Coastguard Worker char segname[16]; /* segment name */
233*6dbdd20aSAndroid Build Coastguard Worker uint64_t vmaddr; /* memory address of this segment */
234*6dbdd20aSAndroid Build Coastguard Worker uint64_t vmsize; /* memory size of this segment */
235*6dbdd20aSAndroid Build Coastguard Worker uint64_t fileoff; /* file offset of this segment */
236*6dbdd20aSAndroid Build Coastguard Worker uint64_t filesize; /* amount to map from the file */
237*6dbdd20aSAndroid Build Coastguard Worker uint32_t maxprot; /* maximum VM protection */
238*6dbdd20aSAndroid Build Coastguard Worker uint32_t initprot; /* initial VM protection */
239*6dbdd20aSAndroid Build Coastguard Worker uint32_t nsects; /* number of sections in segment */
240*6dbdd20aSAndroid Build Coastguard Worker uint32_t flags; /* flags */
241*6dbdd20aSAndroid Build Coastguard Worker };
242*6dbdd20aSAndroid Build Coastguard Worker
243*6dbdd20aSAndroid Build Coastguard Worker struct BinaryInfo {
244*6dbdd20aSAndroid Build Coastguard Worker std::string build_id;
245*6dbdd20aSAndroid Build Coastguard Worker uint64_t load_bias;
246*6dbdd20aSAndroid Build Coastguard Worker BinaryType type;
247*6dbdd20aSAndroid Build Coastguard Worker };
248*6dbdd20aSAndroid Build Coastguard Worker
GetMachOBinaryInfo(char * mem,size_t size)249*6dbdd20aSAndroid Build Coastguard Worker std::optional<BinaryInfo> GetMachOBinaryInfo(char* mem, size_t size) {
250*6dbdd20aSAndroid Build Coastguard Worker if (size < sizeof(mach_header_64))
251*6dbdd20aSAndroid Build Coastguard Worker return {};
252*6dbdd20aSAndroid Build Coastguard Worker
253*6dbdd20aSAndroid Build Coastguard Worker mach_header_64 header;
254*6dbdd20aSAndroid Build Coastguard Worker memcpy(&header, mem, sizeof(mach_header_64));
255*6dbdd20aSAndroid Build Coastguard Worker
256*6dbdd20aSAndroid Build Coastguard Worker if (size < sizeof(mach_header_64) + header.sizeofcmds)
257*6dbdd20aSAndroid Build Coastguard Worker return {};
258*6dbdd20aSAndroid Build Coastguard Worker
259*6dbdd20aSAndroid Build Coastguard Worker std::optional<std::string> build_id;
260*6dbdd20aSAndroid Build Coastguard Worker uint64_t load_bias = 0;
261*6dbdd20aSAndroid Build Coastguard Worker
262*6dbdd20aSAndroid Build Coastguard Worker char* pcmd = mem + sizeof(mach_header_64);
263*6dbdd20aSAndroid Build Coastguard Worker char* pcmds_end = pcmd + header.sizeofcmds;
264*6dbdd20aSAndroid Build Coastguard Worker while (pcmd < pcmds_end) {
265*6dbdd20aSAndroid Build Coastguard Worker load_command cmd_header;
266*6dbdd20aSAndroid Build Coastguard Worker memcpy(&cmd_header, pcmd, sizeof(load_command));
267*6dbdd20aSAndroid Build Coastguard Worker
268*6dbdd20aSAndroid Build Coastguard Worker constexpr uint32_t LC_SEGMENT_64 = 0x19;
269*6dbdd20aSAndroid Build Coastguard Worker constexpr uint32_t LC_UUID = 0x1b;
270*6dbdd20aSAndroid Build Coastguard Worker
271*6dbdd20aSAndroid Build Coastguard Worker switch (cmd_header.cmd) {
272*6dbdd20aSAndroid Build Coastguard Worker case LC_UUID: {
273*6dbdd20aSAndroid Build Coastguard Worker build_id = std::string(pcmd + sizeof(load_command),
274*6dbdd20aSAndroid Build Coastguard Worker cmd_header.cmdsize - sizeof(load_command));
275*6dbdd20aSAndroid Build Coastguard Worker break;
276*6dbdd20aSAndroid Build Coastguard Worker }
277*6dbdd20aSAndroid Build Coastguard Worker case LC_SEGMENT_64: {
278*6dbdd20aSAndroid Build Coastguard Worker segment_64_command seg_cmd;
279*6dbdd20aSAndroid Build Coastguard Worker memcpy(&seg_cmd, pcmd, sizeof(segment_64_command));
280*6dbdd20aSAndroid Build Coastguard Worker if (strcmp(seg_cmd.segname, "__TEXT") == 0) {
281*6dbdd20aSAndroid Build Coastguard Worker load_bias = seg_cmd.vmaddr;
282*6dbdd20aSAndroid Build Coastguard Worker }
283*6dbdd20aSAndroid Build Coastguard Worker break;
284*6dbdd20aSAndroid Build Coastguard Worker }
285*6dbdd20aSAndroid Build Coastguard Worker default:
286*6dbdd20aSAndroid Build Coastguard Worker break;
287*6dbdd20aSAndroid Build Coastguard Worker }
288*6dbdd20aSAndroid Build Coastguard Worker
289*6dbdd20aSAndroid Build Coastguard Worker pcmd += cmd_header.cmdsize;
290*6dbdd20aSAndroid Build Coastguard Worker }
291*6dbdd20aSAndroid Build Coastguard Worker
292*6dbdd20aSAndroid Build Coastguard Worker if (build_id) {
293*6dbdd20aSAndroid Build Coastguard Worker constexpr uint32_t MH_DSYM = 0xa;
294*6dbdd20aSAndroid Build Coastguard Worker BinaryType type = header.filetype == MH_DSYM ? BinaryType::kMachODsym
295*6dbdd20aSAndroid Build Coastguard Worker : BinaryType::kMachO;
296*6dbdd20aSAndroid Build Coastguard Worker return BinaryInfo{*build_id, load_bias, type};
297*6dbdd20aSAndroid Build Coastguard Worker }
298*6dbdd20aSAndroid Build Coastguard Worker return {};
299*6dbdd20aSAndroid Build Coastguard Worker }
300*6dbdd20aSAndroid Build Coastguard Worker
GetBinaryInfo(const char * fname,size_t size)301*6dbdd20aSAndroid Build Coastguard Worker std::optional<BinaryInfo> GetBinaryInfo(const char* fname, size_t size) {
302*6dbdd20aSAndroid Build Coastguard Worker static_assert(EI_CLASS > EI_MAG3, "mem[EI_MAG?] accesses are in range.");
303*6dbdd20aSAndroid Build Coastguard Worker if (size <= EI_CLASS)
304*6dbdd20aSAndroid Build Coastguard Worker return std::nullopt;
305*6dbdd20aSAndroid Build Coastguard Worker base::ScopedMmap map = base::ReadMmapFilePart(fname, size);
306*6dbdd20aSAndroid Build Coastguard Worker if (!map.IsValid()) {
307*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_PLOG("Failed to mmap %s", fname);
308*6dbdd20aSAndroid Build Coastguard Worker return std::nullopt;
309*6dbdd20aSAndroid Build Coastguard Worker }
310*6dbdd20aSAndroid Build Coastguard Worker char* mem = static_cast<char*>(map.data());
311*6dbdd20aSAndroid Build Coastguard Worker
312*6dbdd20aSAndroid Build Coastguard Worker std::optional<std::string> build_id;
313*6dbdd20aSAndroid Build Coastguard Worker std::optional<uint64_t> load_bias;
314*6dbdd20aSAndroid Build Coastguard Worker if (IsElf(mem, size)) {
315*6dbdd20aSAndroid Build Coastguard Worker switch (mem[EI_CLASS]) {
316*6dbdd20aSAndroid Build Coastguard Worker case ELFCLASS32:
317*6dbdd20aSAndroid Build Coastguard Worker build_id = GetElfBuildId<Elf32>(mem, size);
318*6dbdd20aSAndroid Build Coastguard Worker load_bias = GetElfLoadBias<Elf32>(mem, size);
319*6dbdd20aSAndroid Build Coastguard Worker break;
320*6dbdd20aSAndroid Build Coastguard Worker case ELFCLASS64:
321*6dbdd20aSAndroid Build Coastguard Worker build_id = GetElfBuildId<Elf64>(mem, size);
322*6dbdd20aSAndroid Build Coastguard Worker load_bias = GetElfLoadBias<Elf64>(mem, size);
323*6dbdd20aSAndroid Build Coastguard Worker break;
324*6dbdd20aSAndroid Build Coastguard Worker default:
325*6dbdd20aSAndroid Build Coastguard Worker return std::nullopt;
326*6dbdd20aSAndroid Build Coastguard Worker }
327*6dbdd20aSAndroid Build Coastguard Worker if (build_id && load_bias) {
328*6dbdd20aSAndroid Build Coastguard Worker return BinaryInfo{*build_id, *load_bias, BinaryType::kElf};
329*6dbdd20aSAndroid Build Coastguard Worker }
330*6dbdd20aSAndroid Build Coastguard Worker } else if (IsMachO64(mem, size)) {
331*6dbdd20aSAndroid Build Coastguard Worker return GetMachOBinaryInfo(mem, size);
332*6dbdd20aSAndroid Build Coastguard Worker }
333*6dbdd20aSAndroid Build Coastguard Worker return std::nullopt;
334*6dbdd20aSAndroid Build Coastguard Worker }
335*6dbdd20aSAndroid Build Coastguard Worker
BuildIdIndex(std::vector<std::string> dirs)336*6dbdd20aSAndroid Build Coastguard Worker std::map<std::string, FoundBinary> BuildIdIndex(std::vector<std::string> dirs) {
337*6dbdd20aSAndroid Build Coastguard Worker std::map<std::string, FoundBinary> result;
338*6dbdd20aSAndroid Build Coastguard Worker WalkDirectories(std::move(dirs), [&result](const char* fname, size_t size) {
339*6dbdd20aSAndroid Build Coastguard Worker static_assert(EI_MAG3 + 1 == sizeof(kMachO64Magic));
340*6dbdd20aSAndroid Build Coastguard Worker char magic[EI_MAG3 + 1];
341*6dbdd20aSAndroid Build Coastguard Worker // Scope file access. On windows OpenFile opens an exclusive lock.
342*6dbdd20aSAndroid Build Coastguard Worker // This lock needs to be released before mapping the file.
343*6dbdd20aSAndroid Build Coastguard Worker {
344*6dbdd20aSAndroid Build Coastguard Worker base::ScopedFile fd(base::OpenFile(fname, O_RDONLY));
345*6dbdd20aSAndroid Build Coastguard Worker if (!fd) {
346*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_PLOG("Failed to open %s", fname);
347*6dbdd20aSAndroid Build Coastguard Worker return;
348*6dbdd20aSAndroid Build Coastguard Worker }
349*6dbdd20aSAndroid Build Coastguard Worker ssize_t rd = base::Read(*fd, &magic, sizeof(magic));
350*6dbdd20aSAndroid Build Coastguard Worker if (rd != sizeof(magic)) {
351*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_PLOG("Failed to read %s", fname);
352*6dbdd20aSAndroid Build Coastguard Worker return;
353*6dbdd20aSAndroid Build Coastguard Worker }
354*6dbdd20aSAndroid Build Coastguard Worker if (!IsElf(magic, static_cast<size_t>(rd)) &&
355*6dbdd20aSAndroid Build Coastguard Worker !IsMachO64(magic, static_cast<size_t>(rd))) {
356*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_DLOG("%s not an ELF or Mach-O 64.", fname);
357*6dbdd20aSAndroid Build Coastguard Worker return;
358*6dbdd20aSAndroid Build Coastguard Worker }
359*6dbdd20aSAndroid Build Coastguard Worker }
360*6dbdd20aSAndroid Build Coastguard Worker std::optional<BinaryInfo> binary_info = GetBinaryInfo(fname, size);
361*6dbdd20aSAndroid Build Coastguard Worker if (!binary_info) {
362*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_DLOG("Failed to extract build id from %s.", fname);
363*6dbdd20aSAndroid Build Coastguard Worker return;
364*6dbdd20aSAndroid Build Coastguard Worker }
365*6dbdd20aSAndroid Build Coastguard Worker auto it = result.emplace(
366*6dbdd20aSAndroid Build Coastguard Worker binary_info->build_id,
367*6dbdd20aSAndroid Build Coastguard Worker FoundBinary{fname, binary_info->load_bias, binary_info->type});
368*6dbdd20aSAndroid Build Coastguard Worker
369*6dbdd20aSAndroid Build Coastguard Worker // If there was already an existing FoundBinary, the emplace wouldn't insert
370*6dbdd20aSAndroid Build Coastguard Worker // anything. But, for Mac binaries, we prefer dSYM files over the original
371*6dbdd20aSAndroid Build Coastguard Worker // binary, so make sure these overwrite the FoundBinary entry.
372*6dbdd20aSAndroid Build Coastguard Worker bool has_existing = it.second == false;
373*6dbdd20aSAndroid Build Coastguard Worker if (has_existing) {
374*6dbdd20aSAndroid Build Coastguard Worker if (it.first->second.type == BinaryType::kMachO &&
375*6dbdd20aSAndroid Build Coastguard Worker binary_info->type == BinaryType::kMachODsym) {
376*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_LOG("Overwriting index entry for %s to %s.",
377*6dbdd20aSAndroid Build Coastguard Worker base::ToHex(binary_info->build_id).c_str(), fname);
378*6dbdd20aSAndroid Build Coastguard Worker it.first->second =
379*6dbdd20aSAndroid Build Coastguard Worker FoundBinary{fname, binary_info->load_bias, binary_info->type};
380*6dbdd20aSAndroid Build Coastguard Worker } else {
381*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_DLOG("Ignoring %s, index entry for %s already exists.", fname,
382*6dbdd20aSAndroid Build Coastguard Worker base::ToHex(binary_info->build_id).c_str());
383*6dbdd20aSAndroid Build Coastguard Worker }
384*6dbdd20aSAndroid Build Coastguard Worker } else {
385*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_LOG("Indexed: %s (%s)", fname,
386*6dbdd20aSAndroid Build Coastguard Worker base::ToHex(binary_info->build_id).c_str());
387*6dbdd20aSAndroid Build Coastguard Worker }
388*6dbdd20aSAndroid Build Coastguard Worker });
389*6dbdd20aSAndroid Build Coastguard Worker return result;
390*6dbdd20aSAndroid Build Coastguard Worker }
391*6dbdd20aSAndroid Build Coastguard Worker
ParseJsonString(const char * & it,const char * end,std::string * out)392*6dbdd20aSAndroid Build Coastguard Worker bool ParseJsonString(const char*& it, const char* end, std::string* out) {
393*6dbdd20aSAndroid Build Coastguard Worker *out = "";
394*6dbdd20aSAndroid Build Coastguard Worker if (it == end) {
395*6dbdd20aSAndroid Build Coastguard Worker return false;
396*6dbdd20aSAndroid Build Coastguard Worker }
397*6dbdd20aSAndroid Build Coastguard Worker if (*it++ != '"') {
398*6dbdd20aSAndroid Build Coastguard Worker return false;
399*6dbdd20aSAndroid Build Coastguard Worker }
400*6dbdd20aSAndroid Build Coastguard Worker while (true) {
401*6dbdd20aSAndroid Build Coastguard Worker if (it == end) {
402*6dbdd20aSAndroid Build Coastguard Worker return false;
403*6dbdd20aSAndroid Build Coastguard Worker }
404*6dbdd20aSAndroid Build Coastguard Worker char c = *it++;
405*6dbdd20aSAndroid Build Coastguard Worker if (c == '"') {
406*6dbdd20aSAndroid Build Coastguard Worker return true;
407*6dbdd20aSAndroid Build Coastguard Worker }
408*6dbdd20aSAndroid Build Coastguard Worker if (c == '\\') {
409*6dbdd20aSAndroid Build Coastguard Worker if (it == end) {
410*6dbdd20aSAndroid Build Coastguard Worker return false;
411*6dbdd20aSAndroid Build Coastguard Worker }
412*6dbdd20aSAndroid Build Coastguard Worker c = *it++;
413*6dbdd20aSAndroid Build Coastguard Worker switch (c) {
414*6dbdd20aSAndroid Build Coastguard Worker case '"':
415*6dbdd20aSAndroid Build Coastguard Worker case '\\':
416*6dbdd20aSAndroid Build Coastguard Worker case '/':
417*6dbdd20aSAndroid Build Coastguard Worker out->push_back(c);
418*6dbdd20aSAndroid Build Coastguard Worker break;
419*6dbdd20aSAndroid Build Coastguard Worker case 'b':
420*6dbdd20aSAndroid Build Coastguard Worker out->push_back('\b');
421*6dbdd20aSAndroid Build Coastguard Worker break;
422*6dbdd20aSAndroid Build Coastguard Worker case 'f':
423*6dbdd20aSAndroid Build Coastguard Worker out->push_back('\f');
424*6dbdd20aSAndroid Build Coastguard Worker break;
425*6dbdd20aSAndroid Build Coastguard Worker case 'n':
426*6dbdd20aSAndroid Build Coastguard Worker out->push_back('\n');
427*6dbdd20aSAndroid Build Coastguard Worker break;
428*6dbdd20aSAndroid Build Coastguard Worker case 'r':
429*6dbdd20aSAndroid Build Coastguard Worker out->push_back('\r');
430*6dbdd20aSAndroid Build Coastguard Worker break;
431*6dbdd20aSAndroid Build Coastguard Worker case 't':
432*6dbdd20aSAndroid Build Coastguard Worker out->push_back('\t');
433*6dbdd20aSAndroid Build Coastguard Worker break;
434*6dbdd20aSAndroid Build Coastguard Worker // Pass-through \u escape codes without re-encoding to utf-8, for
435*6dbdd20aSAndroid Build Coastguard Worker // simplicity.
436*6dbdd20aSAndroid Build Coastguard Worker case 'u':
437*6dbdd20aSAndroid Build Coastguard Worker out->push_back('\\');
438*6dbdd20aSAndroid Build Coastguard Worker out->push_back('u');
439*6dbdd20aSAndroid Build Coastguard Worker break;
440*6dbdd20aSAndroid Build Coastguard Worker default:
441*6dbdd20aSAndroid Build Coastguard Worker return false;
442*6dbdd20aSAndroid Build Coastguard Worker }
443*6dbdd20aSAndroid Build Coastguard Worker } else {
444*6dbdd20aSAndroid Build Coastguard Worker out->push_back(c);
445*6dbdd20aSAndroid Build Coastguard Worker }
446*6dbdd20aSAndroid Build Coastguard Worker }
447*6dbdd20aSAndroid Build Coastguard Worker }
448*6dbdd20aSAndroid Build Coastguard Worker
ParseJsonNumber(const char * & it,const char * end,double * out)449*6dbdd20aSAndroid Build Coastguard Worker bool ParseJsonNumber(const char*& it, const char* end, double* out) {
450*6dbdd20aSAndroid Build Coastguard Worker bool is_minus = false;
451*6dbdd20aSAndroid Build Coastguard Worker double ret = 0;
452*6dbdd20aSAndroid Build Coastguard Worker if (it == end) {
453*6dbdd20aSAndroid Build Coastguard Worker return false;
454*6dbdd20aSAndroid Build Coastguard Worker }
455*6dbdd20aSAndroid Build Coastguard Worker if (*it == '-') {
456*6dbdd20aSAndroid Build Coastguard Worker ++it;
457*6dbdd20aSAndroid Build Coastguard Worker is_minus = true;
458*6dbdd20aSAndroid Build Coastguard Worker }
459*6dbdd20aSAndroid Build Coastguard Worker while (true) {
460*6dbdd20aSAndroid Build Coastguard Worker if (it == end) {
461*6dbdd20aSAndroid Build Coastguard Worker return false;
462*6dbdd20aSAndroid Build Coastguard Worker }
463*6dbdd20aSAndroid Build Coastguard Worker char c = *it++;
464*6dbdd20aSAndroid Build Coastguard Worker if (isdigit(c)) {
465*6dbdd20aSAndroid Build Coastguard Worker ret = ret * 10 + (c - '0');
466*6dbdd20aSAndroid Build Coastguard Worker } else if (c == 'e') {
467*6dbdd20aSAndroid Build Coastguard Worker // Scientific syntax is not supported.
468*6dbdd20aSAndroid Build Coastguard Worker return false;
469*6dbdd20aSAndroid Build Coastguard Worker } else {
470*6dbdd20aSAndroid Build Coastguard Worker // Unwind the iterator to point at the end of the number.
471*6dbdd20aSAndroid Build Coastguard Worker it--;
472*6dbdd20aSAndroid Build Coastguard Worker break;
473*6dbdd20aSAndroid Build Coastguard Worker }
474*6dbdd20aSAndroid Build Coastguard Worker }
475*6dbdd20aSAndroid Build Coastguard Worker *out = is_minus ? -ret : ret;
476*6dbdd20aSAndroid Build Coastguard Worker return true;
477*6dbdd20aSAndroid Build Coastguard Worker }
478*6dbdd20aSAndroid Build Coastguard Worker
ParseJsonArray(const char * & it,const char * end,std::function<bool (const char * &,const char *)> process_value)479*6dbdd20aSAndroid Build Coastguard Worker bool ParseJsonArray(
480*6dbdd20aSAndroid Build Coastguard Worker const char*& it,
481*6dbdd20aSAndroid Build Coastguard Worker const char* end,
482*6dbdd20aSAndroid Build Coastguard Worker std::function<bool(const char*&, const char*)> process_value) {
483*6dbdd20aSAndroid Build Coastguard Worker if (it == end) {
484*6dbdd20aSAndroid Build Coastguard Worker return false;
485*6dbdd20aSAndroid Build Coastguard Worker }
486*6dbdd20aSAndroid Build Coastguard Worker char c = *it++;
487*6dbdd20aSAndroid Build Coastguard Worker if (c != '[') {
488*6dbdd20aSAndroid Build Coastguard Worker return false;
489*6dbdd20aSAndroid Build Coastguard Worker }
490*6dbdd20aSAndroid Build Coastguard Worker while (true) {
491*6dbdd20aSAndroid Build Coastguard Worker if (!process_value(it, end)) {
492*6dbdd20aSAndroid Build Coastguard Worker return false;
493*6dbdd20aSAndroid Build Coastguard Worker }
494*6dbdd20aSAndroid Build Coastguard Worker if (it == end) {
495*6dbdd20aSAndroid Build Coastguard Worker return false;
496*6dbdd20aSAndroid Build Coastguard Worker }
497*6dbdd20aSAndroid Build Coastguard Worker c = *it++;
498*6dbdd20aSAndroid Build Coastguard Worker if (c == ']') {
499*6dbdd20aSAndroid Build Coastguard Worker return true;
500*6dbdd20aSAndroid Build Coastguard Worker }
501*6dbdd20aSAndroid Build Coastguard Worker if (c != ',') {
502*6dbdd20aSAndroid Build Coastguard Worker return false;
503*6dbdd20aSAndroid Build Coastguard Worker }
504*6dbdd20aSAndroid Build Coastguard Worker }
505*6dbdd20aSAndroid Build Coastguard Worker }
506*6dbdd20aSAndroid Build Coastguard Worker
ParseJsonObject(const char * & it,const char * end,std::function<bool (const char * &,const char *,const std::string &)> process_value)507*6dbdd20aSAndroid Build Coastguard Worker bool ParseJsonObject(
508*6dbdd20aSAndroid Build Coastguard Worker const char*& it,
509*6dbdd20aSAndroid Build Coastguard Worker const char* end,
510*6dbdd20aSAndroid Build Coastguard Worker std::function<bool(const char*&, const char*, const std::string&)>
511*6dbdd20aSAndroid Build Coastguard Worker process_value) {
512*6dbdd20aSAndroid Build Coastguard Worker if (it == end) {
513*6dbdd20aSAndroid Build Coastguard Worker return false;
514*6dbdd20aSAndroid Build Coastguard Worker }
515*6dbdd20aSAndroid Build Coastguard Worker char c = *it++;
516*6dbdd20aSAndroid Build Coastguard Worker if (c != '{') {
517*6dbdd20aSAndroid Build Coastguard Worker return false;
518*6dbdd20aSAndroid Build Coastguard Worker }
519*6dbdd20aSAndroid Build Coastguard Worker while (true) {
520*6dbdd20aSAndroid Build Coastguard Worker std::string key;
521*6dbdd20aSAndroid Build Coastguard Worker if (!ParseJsonString(it, end, &key)) {
522*6dbdd20aSAndroid Build Coastguard Worker return false;
523*6dbdd20aSAndroid Build Coastguard Worker }
524*6dbdd20aSAndroid Build Coastguard Worker if (*it++ != ':') {
525*6dbdd20aSAndroid Build Coastguard Worker return false;
526*6dbdd20aSAndroid Build Coastguard Worker }
527*6dbdd20aSAndroid Build Coastguard Worker if (!process_value(it, end, key)) {
528*6dbdd20aSAndroid Build Coastguard Worker return false;
529*6dbdd20aSAndroid Build Coastguard Worker }
530*6dbdd20aSAndroid Build Coastguard Worker if (it == end) {
531*6dbdd20aSAndroid Build Coastguard Worker return false;
532*6dbdd20aSAndroid Build Coastguard Worker }
533*6dbdd20aSAndroid Build Coastguard Worker c = *it++;
534*6dbdd20aSAndroid Build Coastguard Worker if (c == '}') {
535*6dbdd20aSAndroid Build Coastguard Worker return true;
536*6dbdd20aSAndroid Build Coastguard Worker }
537*6dbdd20aSAndroid Build Coastguard Worker if (c != ',') {
538*6dbdd20aSAndroid Build Coastguard Worker return false;
539*6dbdd20aSAndroid Build Coastguard Worker }
540*6dbdd20aSAndroid Build Coastguard Worker }
541*6dbdd20aSAndroid Build Coastguard Worker }
542*6dbdd20aSAndroid Build Coastguard Worker
SkipJsonValue(const char * & it,const char * end)543*6dbdd20aSAndroid Build Coastguard Worker bool SkipJsonValue(const char*& it, const char* end) {
544*6dbdd20aSAndroid Build Coastguard Worker if (it == end) {
545*6dbdd20aSAndroid Build Coastguard Worker return false;
546*6dbdd20aSAndroid Build Coastguard Worker }
547*6dbdd20aSAndroid Build Coastguard Worker char c = *it;
548*6dbdd20aSAndroid Build Coastguard Worker if (c == '"') {
549*6dbdd20aSAndroid Build Coastguard Worker std::string ignored;
550*6dbdd20aSAndroid Build Coastguard Worker return ParseJsonString(it, end, &ignored);
551*6dbdd20aSAndroid Build Coastguard Worker }
552*6dbdd20aSAndroid Build Coastguard Worker if (isdigit(c) || c == '-') {
553*6dbdd20aSAndroid Build Coastguard Worker double ignored;
554*6dbdd20aSAndroid Build Coastguard Worker return ParseJsonNumber(it, end, &ignored);
555*6dbdd20aSAndroid Build Coastguard Worker }
556*6dbdd20aSAndroid Build Coastguard Worker if (c == '[') {
557*6dbdd20aSAndroid Build Coastguard Worker return ParseJsonArray(it, end, [](const char*& it, const char* end) {
558*6dbdd20aSAndroid Build Coastguard Worker return SkipJsonValue(it, end);
559*6dbdd20aSAndroid Build Coastguard Worker });
560*6dbdd20aSAndroid Build Coastguard Worker }
561*6dbdd20aSAndroid Build Coastguard Worker if (c == '{') {
562*6dbdd20aSAndroid Build Coastguard Worker return ParseJsonObject(
563*6dbdd20aSAndroid Build Coastguard Worker it, end, [](const char*& it, const char* end, const std::string&) {
564*6dbdd20aSAndroid Build Coastguard Worker return SkipJsonValue(it, end);
565*6dbdd20aSAndroid Build Coastguard Worker });
566*6dbdd20aSAndroid Build Coastguard Worker }
567*6dbdd20aSAndroid Build Coastguard Worker return false;
568*6dbdd20aSAndroid Build Coastguard Worker }
569*6dbdd20aSAndroid Build Coastguard Worker
570*6dbdd20aSAndroid Build Coastguard Worker } // namespace
571*6dbdd20aSAndroid Build Coastguard Worker
ParseLlvmSymbolizerJsonLine(const std::string & line,std::vector<SymbolizedFrame> * result)572*6dbdd20aSAndroid Build Coastguard Worker bool ParseLlvmSymbolizerJsonLine(const std::string& line,
573*6dbdd20aSAndroid Build Coastguard Worker std::vector<SymbolizedFrame>* result) {
574*6dbdd20aSAndroid Build Coastguard Worker // Parse Json of the format:
575*6dbdd20aSAndroid Build Coastguard Worker // ```
576*6dbdd20aSAndroid Build Coastguard Worker // {"Address":"0x1b72f","ModuleName":"...","Symbol":[{"Column":0,
577*6dbdd20aSAndroid Build Coastguard Worker // "Discriminator":0,"FileName":"...","FunctionName":"...","Line":0,
578*6dbdd20aSAndroid Build Coastguard Worker // "StartAddress":"","StartFileName":"...","StartLine":0},...]}
579*6dbdd20aSAndroid Build Coastguard Worker // ```
580*6dbdd20aSAndroid Build Coastguard Worker const char* it = line.data();
581*6dbdd20aSAndroid Build Coastguard Worker const char* end = it + line.size();
582*6dbdd20aSAndroid Build Coastguard Worker return ParseJsonObject(
583*6dbdd20aSAndroid Build Coastguard Worker it, end, [&](const char*& it, const char* end, const std::string& key) {
584*6dbdd20aSAndroid Build Coastguard Worker if (key == "Symbol") {
585*6dbdd20aSAndroid Build Coastguard Worker return ParseJsonArray(it, end, [&](const char*& it, const char* end) {
586*6dbdd20aSAndroid Build Coastguard Worker SymbolizedFrame frame;
587*6dbdd20aSAndroid Build Coastguard Worker if (!ParseJsonObject(
588*6dbdd20aSAndroid Build Coastguard Worker it, end,
589*6dbdd20aSAndroid Build Coastguard Worker [&](const char*& it, const char* end,
590*6dbdd20aSAndroid Build Coastguard Worker const std::string& key) {
591*6dbdd20aSAndroid Build Coastguard Worker if (key == "FileName") {
592*6dbdd20aSAndroid Build Coastguard Worker return ParseJsonString(it, end, &frame.file_name);
593*6dbdd20aSAndroid Build Coastguard Worker }
594*6dbdd20aSAndroid Build Coastguard Worker if (key == "FunctionName") {
595*6dbdd20aSAndroid Build Coastguard Worker return ParseJsonString(it, end, &frame.function_name);
596*6dbdd20aSAndroid Build Coastguard Worker }
597*6dbdd20aSAndroid Build Coastguard Worker if (key == "Line") {
598*6dbdd20aSAndroid Build Coastguard Worker double number;
599*6dbdd20aSAndroid Build Coastguard Worker if (!ParseJsonNumber(it, end, &number)) {
600*6dbdd20aSAndroid Build Coastguard Worker return false;
601*6dbdd20aSAndroid Build Coastguard Worker }
602*6dbdd20aSAndroid Build Coastguard Worker frame.line = static_cast<unsigned int>(number);
603*6dbdd20aSAndroid Build Coastguard Worker return true;
604*6dbdd20aSAndroid Build Coastguard Worker }
605*6dbdd20aSAndroid Build Coastguard Worker return SkipJsonValue(it, end);
606*6dbdd20aSAndroid Build Coastguard Worker })) {
607*6dbdd20aSAndroid Build Coastguard Worker return false;
608*6dbdd20aSAndroid Build Coastguard Worker }
609*6dbdd20aSAndroid Build Coastguard Worker // Use "??" for empty filenames, to match non-JSON output.
610*6dbdd20aSAndroid Build Coastguard Worker if (frame.file_name.empty()) {
611*6dbdd20aSAndroid Build Coastguard Worker frame.file_name = "??";
612*6dbdd20aSAndroid Build Coastguard Worker }
613*6dbdd20aSAndroid Build Coastguard Worker result->push_back(frame);
614*6dbdd20aSAndroid Build Coastguard Worker return true;
615*6dbdd20aSAndroid Build Coastguard Worker });
616*6dbdd20aSAndroid Build Coastguard Worker }
617*6dbdd20aSAndroid Build Coastguard Worker if (key == "Error") {
618*6dbdd20aSAndroid Build Coastguard Worker std::string message;
619*6dbdd20aSAndroid Build Coastguard Worker if (!ParseJsonObject(it, end,
620*6dbdd20aSAndroid Build Coastguard Worker [&](const char*& it, const char* end,
621*6dbdd20aSAndroid Build Coastguard Worker const std::string& key) {
622*6dbdd20aSAndroid Build Coastguard Worker if (key == "Message") {
623*6dbdd20aSAndroid Build Coastguard Worker return ParseJsonString(it, end, &message);
624*6dbdd20aSAndroid Build Coastguard Worker }
625*6dbdd20aSAndroid Build Coastguard Worker return SkipJsonValue(it, end);
626*6dbdd20aSAndroid Build Coastguard Worker })) {
627*6dbdd20aSAndroid Build Coastguard Worker return false;
628*6dbdd20aSAndroid Build Coastguard Worker }
629*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_ELOG("Failed to symbolize: %s.", message.c_str());
630*6dbdd20aSAndroid Build Coastguard Worker return true;
631*6dbdd20aSAndroid Build Coastguard Worker }
632*6dbdd20aSAndroid Build Coastguard Worker return SkipJsonValue(it, end);
633*6dbdd20aSAndroid Build Coastguard Worker });
634*6dbdd20aSAndroid Build Coastguard Worker }
635*6dbdd20aSAndroid Build Coastguard Worker
636*6dbdd20aSAndroid Build Coastguard Worker BinaryFinder::~BinaryFinder() = default;
637*6dbdd20aSAndroid Build Coastguard Worker
LocalBinaryIndexer(std::vector<std::string> roots)638*6dbdd20aSAndroid Build Coastguard Worker LocalBinaryIndexer::LocalBinaryIndexer(std::vector<std::string> roots)
639*6dbdd20aSAndroid Build Coastguard Worker : buildid_to_file_(BuildIdIndex(std::move(roots))) {}
640*6dbdd20aSAndroid Build Coastguard Worker
FindBinary(const std::string & abspath,const std::string & build_id)641*6dbdd20aSAndroid Build Coastguard Worker std::optional<FoundBinary> LocalBinaryIndexer::FindBinary(
642*6dbdd20aSAndroid Build Coastguard Worker const std::string& abspath,
643*6dbdd20aSAndroid Build Coastguard Worker const std::string& build_id) {
644*6dbdd20aSAndroid Build Coastguard Worker auto it = buildid_to_file_.find(build_id);
645*6dbdd20aSAndroid Build Coastguard Worker if (it != buildid_to_file_.end())
646*6dbdd20aSAndroid Build Coastguard Worker return it->second;
647*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_ELOG("Could not find Build ID: %s (file %s).",
648*6dbdd20aSAndroid Build Coastguard Worker base::ToHex(build_id).c_str(), abspath.c_str());
649*6dbdd20aSAndroid Build Coastguard Worker return std::nullopt;
650*6dbdd20aSAndroid Build Coastguard Worker }
651*6dbdd20aSAndroid Build Coastguard Worker
652*6dbdd20aSAndroid Build Coastguard Worker LocalBinaryIndexer::~LocalBinaryIndexer() = default;
653*6dbdd20aSAndroid Build Coastguard Worker
LocalBinaryFinder(std::vector<std::string> roots)654*6dbdd20aSAndroid Build Coastguard Worker LocalBinaryFinder::LocalBinaryFinder(std::vector<std::string> roots)
655*6dbdd20aSAndroid Build Coastguard Worker : roots_(std::move(roots)) {}
656*6dbdd20aSAndroid Build Coastguard Worker
FindBinary(const std::string & abspath,const std::string & build_id)657*6dbdd20aSAndroid Build Coastguard Worker std::optional<FoundBinary> LocalBinaryFinder::FindBinary(
658*6dbdd20aSAndroid Build Coastguard Worker const std::string& abspath,
659*6dbdd20aSAndroid Build Coastguard Worker const std::string& build_id) {
660*6dbdd20aSAndroid Build Coastguard Worker auto p = cache_.emplace(abspath, std::nullopt);
661*6dbdd20aSAndroid Build Coastguard Worker if (!p.second)
662*6dbdd20aSAndroid Build Coastguard Worker return p.first->second;
663*6dbdd20aSAndroid Build Coastguard Worker
664*6dbdd20aSAndroid Build Coastguard Worker std::optional<FoundBinary>& cache_entry = p.first->second;
665*6dbdd20aSAndroid Build Coastguard Worker
666*6dbdd20aSAndroid Build Coastguard Worker // Try the absolute path first.
667*6dbdd20aSAndroid Build Coastguard Worker if (base::StartsWith(abspath, "/")) {
668*6dbdd20aSAndroid Build Coastguard Worker cache_entry = IsCorrectFile(abspath, build_id);
669*6dbdd20aSAndroid Build Coastguard Worker if (cache_entry)
670*6dbdd20aSAndroid Build Coastguard Worker return cache_entry;
671*6dbdd20aSAndroid Build Coastguard Worker }
672*6dbdd20aSAndroid Build Coastguard Worker
673*6dbdd20aSAndroid Build Coastguard Worker for (const std::string& root_str : roots_) {
674*6dbdd20aSAndroid Build Coastguard Worker cache_entry = FindBinaryInRoot(root_str, abspath, build_id);
675*6dbdd20aSAndroid Build Coastguard Worker if (cache_entry)
676*6dbdd20aSAndroid Build Coastguard Worker return cache_entry;
677*6dbdd20aSAndroid Build Coastguard Worker }
678*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_ELOG("Could not find %s (Build ID: %s).", abspath.c_str(),
679*6dbdd20aSAndroid Build Coastguard Worker base::ToHex(build_id).c_str());
680*6dbdd20aSAndroid Build Coastguard Worker return cache_entry;
681*6dbdd20aSAndroid Build Coastguard Worker }
682*6dbdd20aSAndroid Build Coastguard Worker
IsCorrectFile(const std::string & symbol_file,const std::string & build_id)683*6dbdd20aSAndroid Build Coastguard Worker std::optional<FoundBinary> LocalBinaryFinder::IsCorrectFile(
684*6dbdd20aSAndroid Build Coastguard Worker const std::string& symbol_file,
685*6dbdd20aSAndroid Build Coastguard Worker const std::string& build_id) {
686*6dbdd20aSAndroid Build Coastguard Worker if (!base::FileExists(symbol_file)) {
687*6dbdd20aSAndroid Build Coastguard Worker return std::nullopt;
688*6dbdd20aSAndroid Build Coastguard Worker }
689*6dbdd20aSAndroid Build Coastguard Worker // Openfile opens the file with an exclusive lock on windows.
690*6dbdd20aSAndroid Build Coastguard Worker std::optional<uint64_t> file_size = base::GetFileSize(symbol_file);
691*6dbdd20aSAndroid Build Coastguard Worker if (!file_size.has_value()) {
692*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_PLOG("Failed to get file size %s", symbol_file.c_str());
693*6dbdd20aSAndroid Build Coastguard Worker return std::nullopt;
694*6dbdd20aSAndroid Build Coastguard Worker }
695*6dbdd20aSAndroid Build Coastguard Worker
696*6dbdd20aSAndroid Build Coastguard Worker static_assert(sizeof(size_t) <= sizeof(uint64_t));
697*6dbdd20aSAndroid Build Coastguard Worker size_t size = static_cast<size_t>(
698*6dbdd20aSAndroid Build Coastguard Worker std::min<uint64_t>(std::numeric_limits<size_t>::max(), *file_size));
699*6dbdd20aSAndroid Build Coastguard Worker
700*6dbdd20aSAndroid Build Coastguard Worker if (size == 0) {
701*6dbdd20aSAndroid Build Coastguard Worker return std::nullopt;
702*6dbdd20aSAndroid Build Coastguard Worker }
703*6dbdd20aSAndroid Build Coastguard Worker
704*6dbdd20aSAndroid Build Coastguard Worker std::optional<BinaryInfo> binary_info =
705*6dbdd20aSAndroid Build Coastguard Worker GetBinaryInfo(symbol_file.c_str(), size);
706*6dbdd20aSAndroid Build Coastguard Worker if (!binary_info)
707*6dbdd20aSAndroid Build Coastguard Worker return std::nullopt;
708*6dbdd20aSAndroid Build Coastguard Worker if (binary_info->build_id != build_id) {
709*6dbdd20aSAndroid Build Coastguard Worker return std::nullopt;
710*6dbdd20aSAndroid Build Coastguard Worker }
711*6dbdd20aSAndroid Build Coastguard Worker return FoundBinary{symbol_file, binary_info->load_bias, binary_info->type};
712*6dbdd20aSAndroid Build Coastguard Worker }
713*6dbdd20aSAndroid Build Coastguard Worker
FindBinaryInRoot(const std::string & root_str,const std::string & abspath,const std::string & build_id)714*6dbdd20aSAndroid Build Coastguard Worker std::optional<FoundBinary> LocalBinaryFinder::FindBinaryInRoot(
715*6dbdd20aSAndroid Build Coastguard Worker const std::string& root_str,
716*6dbdd20aSAndroid Build Coastguard Worker const std::string& abspath,
717*6dbdd20aSAndroid Build Coastguard Worker const std::string& build_id) {
718*6dbdd20aSAndroid Build Coastguard Worker constexpr char kApkPrefix[] = "base.apk!";
719*6dbdd20aSAndroid Build Coastguard Worker
720*6dbdd20aSAndroid Build Coastguard Worker std::string filename;
721*6dbdd20aSAndroid Build Coastguard Worker std::string dirname;
722*6dbdd20aSAndroid Build Coastguard Worker
723*6dbdd20aSAndroid Build Coastguard Worker for (base::StringSplitter sp(abspath, '/'); sp.Next();) {
724*6dbdd20aSAndroid Build Coastguard Worker if (!dirname.empty())
725*6dbdd20aSAndroid Build Coastguard Worker dirname += "/";
726*6dbdd20aSAndroid Build Coastguard Worker dirname += filename;
727*6dbdd20aSAndroid Build Coastguard Worker filename = sp.cur_token();
728*6dbdd20aSAndroid Build Coastguard Worker }
729*6dbdd20aSAndroid Build Coastguard Worker
730*6dbdd20aSAndroid Build Coastguard Worker // Return the first match for the following options:
731*6dbdd20aSAndroid Build Coastguard Worker // * absolute path of library file relative to root.
732*6dbdd20aSAndroid Build Coastguard Worker // * absolute path of library file relative to root, but with base.apk!
733*6dbdd20aSAndroid Build Coastguard Worker // removed from filename.
734*6dbdd20aSAndroid Build Coastguard Worker // * only filename of library file relative to root.
735*6dbdd20aSAndroid Build Coastguard Worker // * only filename of library file relative to root, but with base.apk!
736*6dbdd20aSAndroid Build Coastguard Worker // removed from filename.
737*6dbdd20aSAndroid Build Coastguard Worker // * in the subdirectory .build-id: the first two hex digits of the build-id
738*6dbdd20aSAndroid Build Coastguard Worker // as subdirectory, then the rest of the hex digits, with ".debug"appended.
739*6dbdd20aSAndroid Build Coastguard Worker // See
740*6dbdd20aSAndroid Build Coastguard Worker // https://fedoraproject.org/wiki/RolandMcGrath/BuildID#Find_files_by_build_ID
741*6dbdd20aSAndroid Build Coastguard Worker //
742*6dbdd20aSAndroid Build Coastguard Worker // For example, "/system/lib/base.apk!foo.so" with build id abcd1234,
743*6dbdd20aSAndroid Build Coastguard Worker // is looked for at
744*6dbdd20aSAndroid Build Coastguard Worker // * $ROOT/system/lib/base.apk!foo.so
745*6dbdd20aSAndroid Build Coastguard Worker // * $ROOT/system/lib/foo.so
746*6dbdd20aSAndroid Build Coastguard Worker // * $ROOT/base.apk!foo.so
747*6dbdd20aSAndroid Build Coastguard Worker // * $ROOT/foo.so
748*6dbdd20aSAndroid Build Coastguard Worker // * $ROOT/.build-id/ab/cd1234.debug
749*6dbdd20aSAndroid Build Coastguard Worker
750*6dbdd20aSAndroid Build Coastguard Worker std::optional<FoundBinary> result;
751*6dbdd20aSAndroid Build Coastguard Worker
752*6dbdd20aSAndroid Build Coastguard Worker std::string symbol_file = root_str + "/" + dirname + "/" + filename;
753*6dbdd20aSAndroid Build Coastguard Worker result = IsCorrectFile(symbol_file, build_id);
754*6dbdd20aSAndroid Build Coastguard Worker if (result) {
755*6dbdd20aSAndroid Build Coastguard Worker return result;
756*6dbdd20aSAndroid Build Coastguard Worker }
757*6dbdd20aSAndroid Build Coastguard Worker
758*6dbdd20aSAndroid Build Coastguard Worker if (base::StartsWith(filename, kApkPrefix)) {
759*6dbdd20aSAndroid Build Coastguard Worker symbol_file = root_str + "/" + dirname + "/" +
760*6dbdd20aSAndroid Build Coastguard Worker filename.substr(sizeof(kApkPrefix) - 1);
761*6dbdd20aSAndroid Build Coastguard Worker result = IsCorrectFile(symbol_file, build_id);
762*6dbdd20aSAndroid Build Coastguard Worker if (result) {
763*6dbdd20aSAndroid Build Coastguard Worker return result;
764*6dbdd20aSAndroid Build Coastguard Worker }
765*6dbdd20aSAndroid Build Coastguard Worker }
766*6dbdd20aSAndroid Build Coastguard Worker
767*6dbdd20aSAndroid Build Coastguard Worker symbol_file = root_str + "/" + filename;
768*6dbdd20aSAndroid Build Coastguard Worker result = IsCorrectFile(symbol_file, build_id);
769*6dbdd20aSAndroid Build Coastguard Worker if (result) {
770*6dbdd20aSAndroid Build Coastguard Worker return result;
771*6dbdd20aSAndroid Build Coastguard Worker }
772*6dbdd20aSAndroid Build Coastguard Worker
773*6dbdd20aSAndroid Build Coastguard Worker if (base::StartsWith(filename, kApkPrefix)) {
774*6dbdd20aSAndroid Build Coastguard Worker symbol_file = root_str + "/" + filename.substr(sizeof(kApkPrefix) - 1);
775*6dbdd20aSAndroid Build Coastguard Worker result = IsCorrectFile(symbol_file, build_id);
776*6dbdd20aSAndroid Build Coastguard Worker if (result) {
777*6dbdd20aSAndroid Build Coastguard Worker return result;
778*6dbdd20aSAndroid Build Coastguard Worker }
779*6dbdd20aSAndroid Build Coastguard Worker }
780*6dbdd20aSAndroid Build Coastguard Worker
781*6dbdd20aSAndroid Build Coastguard Worker std::string hex_build_id = base::ToHex(build_id.c_str(), build_id.size());
782*6dbdd20aSAndroid Build Coastguard Worker std::string split_hex_build_id = SplitBuildID(hex_build_id);
783*6dbdd20aSAndroid Build Coastguard Worker if (!split_hex_build_id.empty()) {
784*6dbdd20aSAndroid Build Coastguard Worker symbol_file =
785*6dbdd20aSAndroid Build Coastguard Worker root_str + "/" + ".build-id" + "/" + split_hex_build_id + ".debug";
786*6dbdd20aSAndroid Build Coastguard Worker result = IsCorrectFile(symbol_file, build_id);
787*6dbdd20aSAndroid Build Coastguard Worker if (result) {
788*6dbdd20aSAndroid Build Coastguard Worker return result;
789*6dbdd20aSAndroid Build Coastguard Worker }
790*6dbdd20aSAndroid Build Coastguard Worker }
791*6dbdd20aSAndroid Build Coastguard Worker
792*6dbdd20aSAndroid Build Coastguard Worker return std::nullopt;
793*6dbdd20aSAndroid Build Coastguard Worker }
794*6dbdd20aSAndroid Build Coastguard Worker
795*6dbdd20aSAndroid Build Coastguard Worker LocalBinaryFinder::~LocalBinaryFinder() = default;
796*6dbdd20aSAndroid Build Coastguard Worker
LLVMSymbolizerProcess(const std::string & symbolizer_path)797*6dbdd20aSAndroid Build Coastguard Worker LLVMSymbolizerProcess::LLVMSymbolizerProcess(const std::string& symbolizer_path)
798*6dbdd20aSAndroid Build Coastguard Worker :
799*6dbdd20aSAndroid Build Coastguard Worker #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
800*6dbdd20aSAndroid Build Coastguard Worker subprocess_(symbolizer_path, {"--output-style=JSON"}) {
801*6dbdd20aSAndroid Build Coastguard Worker }
802*6dbdd20aSAndroid Build Coastguard Worker #else
803*6dbdd20aSAndroid Build Coastguard Worker subprocess_(symbolizer_path, {"llvm-symbolizer", "--output-style=JSON"}) {
804*6dbdd20aSAndroid Build Coastguard Worker }
805*6dbdd20aSAndroid Build Coastguard Worker #endif
806*6dbdd20aSAndroid Build Coastguard Worker
Symbolize(const std::string & binary,uint64_t address)807*6dbdd20aSAndroid Build Coastguard Worker std::vector<SymbolizedFrame> LLVMSymbolizerProcess::Symbolize(
808*6dbdd20aSAndroid Build Coastguard Worker const std::string& binary,
809*6dbdd20aSAndroid Build Coastguard Worker uint64_t address) {
810*6dbdd20aSAndroid Build Coastguard Worker std::vector<SymbolizedFrame> result;
811*6dbdd20aSAndroid Build Coastguard Worker base::StackString<1024> buffer("\"%s\" 0x%" PRIx64 "\n", binary.c_str(),
812*6dbdd20aSAndroid Build Coastguard Worker address);
813*6dbdd20aSAndroid Build Coastguard Worker if (subprocess_.Write(buffer.c_str(), buffer.len()) < 0) {
814*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_ELOG("Failed to write to llvm-symbolizer.");
815*6dbdd20aSAndroid Build Coastguard Worker return result;
816*6dbdd20aSAndroid Build Coastguard Worker }
817*6dbdd20aSAndroid Build Coastguard Worker auto line = GetLine([&](char* read_buffer, size_t buffer_size) {
818*6dbdd20aSAndroid Build Coastguard Worker return subprocess_.Read(read_buffer, buffer_size);
819*6dbdd20aSAndroid Build Coastguard Worker });
820*6dbdd20aSAndroid Build Coastguard Worker // llvm-symbolizer writes out records as one JSON per line.
821*6dbdd20aSAndroid Build Coastguard Worker if (!ParseLlvmSymbolizerJsonLine(line, &result)) {
822*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_ELOG("Failed to parse llvm-symbolizer JSON: %s", line.c_str());
823*6dbdd20aSAndroid Build Coastguard Worker return {};
824*6dbdd20aSAndroid Build Coastguard Worker }
825*6dbdd20aSAndroid Build Coastguard Worker return result;
826*6dbdd20aSAndroid Build Coastguard Worker }
Symbolize(const std::string & mapping_name,const std::string & build_id,uint64_t load_bias,const std::vector<uint64_t> & addresses)827*6dbdd20aSAndroid Build Coastguard Worker std::vector<std::vector<SymbolizedFrame>> LocalSymbolizer::Symbolize(
828*6dbdd20aSAndroid Build Coastguard Worker const std::string& mapping_name,
829*6dbdd20aSAndroid Build Coastguard Worker const std::string& build_id,
830*6dbdd20aSAndroid Build Coastguard Worker uint64_t load_bias,
831*6dbdd20aSAndroid Build Coastguard Worker const std::vector<uint64_t>& addresses) {
832*6dbdd20aSAndroid Build Coastguard Worker std::optional<FoundBinary> binary =
833*6dbdd20aSAndroid Build Coastguard Worker finder_->FindBinary(mapping_name, build_id);
834*6dbdd20aSAndroid Build Coastguard Worker if (!binary)
835*6dbdd20aSAndroid Build Coastguard Worker return {};
836*6dbdd20aSAndroid Build Coastguard Worker uint64_t load_bias_correction = 0;
837*6dbdd20aSAndroid Build Coastguard Worker if (binary->load_bias > load_bias) {
838*6dbdd20aSAndroid Build Coastguard Worker // On Android 10, there was a bug in libunwindstack that would incorrectly
839*6dbdd20aSAndroid Build Coastguard Worker // calculate the load_bias, and thus the relative PC. This would end up in
840*6dbdd20aSAndroid Build Coastguard Worker // frames that made no sense. We can fix this up after the fact if we
841*6dbdd20aSAndroid Build Coastguard Worker // detect this situation.
842*6dbdd20aSAndroid Build Coastguard Worker load_bias_correction = binary->load_bias - load_bias;
843*6dbdd20aSAndroid Build Coastguard Worker PERFETTO_LOG("Correcting load bias by %" PRIu64 " for %s",
844*6dbdd20aSAndroid Build Coastguard Worker load_bias_correction, mapping_name.c_str());
845*6dbdd20aSAndroid Build Coastguard Worker }
846*6dbdd20aSAndroid Build Coastguard Worker std::vector<std::vector<SymbolizedFrame>> result;
847*6dbdd20aSAndroid Build Coastguard Worker result.reserve(addresses.size());
848*6dbdd20aSAndroid Build Coastguard Worker for (uint64_t address : addresses)
849*6dbdd20aSAndroid Build Coastguard Worker result.emplace_back(llvm_symbolizer_.Symbolize(
850*6dbdd20aSAndroid Build Coastguard Worker binary->file_name, address + load_bias_correction));
851*6dbdd20aSAndroid Build Coastguard Worker return result;
852*6dbdd20aSAndroid Build Coastguard Worker }
853*6dbdd20aSAndroid Build Coastguard Worker
LocalSymbolizer(const std::string & symbolizer_path,std::unique_ptr<BinaryFinder> finder)854*6dbdd20aSAndroid Build Coastguard Worker LocalSymbolizer::LocalSymbolizer(const std::string& symbolizer_path,
855*6dbdd20aSAndroid Build Coastguard Worker std::unique_ptr<BinaryFinder> finder)
856*6dbdd20aSAndroid Build Coastguard Worker : llvm_symbolizer_(symbolizer_path), finder_(std::move(finder)) {}
857*6dbdd20aSAndroid Build Coastguard Worker
LocalSymbolizer(std::unique_ptr<BinaryFinder> finder)858*6dbdd20aSAndroid Build Coastguard Worker LocalSymbolizer::LocalSymbolizer(std::unique_ptr<BinaryFinder> finder)
859*6dbdd20aSAndroid Build Coastguard Worker : LocalSymbolizer(kDefaultSymbolizer, std::move(finder)) {}
860*6dbdd20aSAndroid Build Coastguard Worker
861*6dbdd20aSAndroid Build Coastguard Worker LocalSymbolizer::~LocalSymbolizer() = default;
862*6dbdd20aSAndroid Build Coastguard Worker
863*6dbdd20aSAndroid Build Coastguard Worker } // namespace profiling
864*6dbdd20aSAndroid Build Coastguard Worker } // namespace perfetto
865*6dbdd20aSAndroid Build Coastguard Worker
866*6dbdd20aSAndroid Build Coastguard Worker #endif // PERFETTO_BUILDFLAG(PERFETTO_LOCAL_SYMBOLIZER)
867