1*387f9dfdSAndroid Build Coastguard Worker /*
2*387f9dfdSAndroid Build Coastguard Worker * Copyright (c) 2016 GitHub, Inc.
3*387f9dfdSAndroid Build Coastguard Worker *
4*387f9dfdSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*387f9dfdSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*387f9dfdSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*387f9dfdSAndroid Build Coastguard Worker *
8*387f9dfdSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*387f9dfdSAndroid Build Coastguard Worker *
10*387f9dfdSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*387f9dfdSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*387f9dfdSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*387f9dfdSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*387f9dfdSAndroid Build Coastguard Worker * limitations under the License.
15*387f9dfdSAndroid Build Coastguard Worker */
16*387f9dfdSAndroid Build Coastguard Worker #include <sys/types.h>
17*387f9dfdSAndroid Build Coastguard Worker #include <sys/stat.h>
18*387f9dfdSAndroid Build Coastguard Worker #include <sys/mman.h>
19*387f9dfdSAndroid Build Coastguard Worker #include <errno.h>
20*387f9dfdSAndroid Build Coastguard Worker #include <fcntl.h>
21*387f9dfdSAndroid Build Coastguard Worker #include <unistd.h>
22*387f9dfdSAndroid Build Coastguard Worker #include <string.h>
23*387f9dfdSAndroid Build Coastguard Worker #include <libgen.h>
24*387f9dfdSAndroid Build Coastguard Worker #include <stdio.h>
25*387f9dfdSAndroid Build Coastguard Worker #include <stdlib.h>
26*387f9dfdSAndroid Build Coastguard Worker #include <limits.h>
27*387f9dfdSAndroid Build Coastguard Worker #ifdef HAVE_LIBLZMA
28*387f9dfdSAndroid Build Coastguard Worker #include <lzma.h>
29*387f9dfdSAndroid Build Coastguard Worker #endif
30*387f9dfdSAndroid Build Coastguard Worker #ifdef HAVE_LIBDEBUGINFOD
31*387f9dfdSAndroid Build Coastguard Worker #include <elfutils/debuginfod.h>
32*387f9dfdSAndroid Build Coastguard Worker #endif
33*387f9dfdSAndroid Build Coastguard Worker
34*387f9dfdSAndroid Build Coastguard Worker #include <gelf.h>
35*387f9dfdSAndroid Build Coastguard Worker #include "bcc_elf.h"
36*387f9dfdSAndroid Build Coastguard Worker #include "bcc_proc.h"
37*387f9dfdSAndroid Build Coastguard Worker #include "bcc_syms.h"
38*387f9dfdSAndroid Build Coastguard Worker #include "bcc_zip.h"
39*387f9dfdSAndroid Build Coastguard Worker
40*387f9dfdSAndroid Build Coastguard Worker #define NT_STAPSDT 3
41*387f9dfdSAndroid Build Coastguard Worker #define ELF_ST_TYPE(x) (((uint32_t) x) & 0xf)
42*387f9dfdSAndroid Build Coastguard Worker
openelf_fd(int fd,Elf ** elf_out)43*387f9dfdSAndroid Build Coastguard Worker static int openelf_fd(int fd, Elf **elf_out) {
44*387f9dfdSAndroid Build Coastguard Worker if (elf_version(EV_CURRENT) == EV_NONE)
45*387f9dfdSAndroid Build Coastguard Worker return -1;
46*387f9dfdSAndroid Build Coastguard Worker
47*387f9dfdSAndroid Build Coastguard Worker *elf_out = elf_begin(fd, ELF_C_READ, 0);
48*387f9dfdSAndroid Build Coastguard Worker if (*elf_out == NULL)
49*387f9dfdSAndroid Build Coastguard Worker return -1;
50*387f9dfdSAndroid Build Coastguard Worker
51*387f9dfdSAndroid Build Coastguard Worker return 0;
52*387f9dfdSAndroid Build Coastguard Worker }
53*387f9dfdSAndroid Build Coastguard Worker
openelf_mem(void * buf,size_t buf_len,Elf ** elf_out)54*387f9dfdSAndroid Build Coastguard Worker static int openelf_mem(void *buf, size_t buf_len, Elf **elf_out) {
55*387f9dfdSAndroid Build Coastguard Worker if (elf_version(EV_CURRENT) == EV_NONE)
56*387f9dfdSAndroid Build Coastguard Worker return -1;
57*387f9dfdSAndroid Build Coastguard Worker
58*387f9dfdSAndroid Build Coastguard Worker *elf_out = elf_memory(buf, buf_len);
59*387f9dfdSAndroid Build Coastguard Worker if (*elf_out == NULL)
60*387f9dfdSAndroid Build Coastguard Worker return -1;
61*387f9dfdSAndroid Build Coastguard Worker
62*387f9dfdSAndroid Build Coastguard Worker return 0;
63*387f9dfdSAndroid Build Coastguard Worker }
64*387f9dfdSAndroid Build Coastguard Worker
65*387f9dfdSAndroid Build Coastguard Worker // Type of bcc_elf_file.
66*387f9dfdSAndroid Build Coastguard Worker enum bcc_elf_file_type {
67*387f9dfdSAndroid Build Coastguard Worker // Empty bcc_elf_file, not associated with any Elf or resources.
68*387f9dfdSAndroid Build Coastguard Worker // None of the union fields should be read and elf pointer is NULL.
69*387f9dfdSAndroid Build Coastguard Worker BCC_ELF_FILE_TYPE_NONE = 0,
70*387f9dfdSAndroid Build Coastguard Worker
71*387f9dfdSAndroid Build Coastguard Worker // bcc_elf_file owning a file descriptor and providing access to
72*387f9dfdSAndroid Build Coastguard Worker // an Elf file backed by data from that file.
73*387f9dfdSAndroid Build Coastguard Worker // fd field of the impl union stores the file descriptor and elf
74*387f9dfdSAndroid Build Coastguard Worker // pointer is not NULL.
75*387f9dfdSAndroid Build Coastguard Worker BCC_ELF_FILE_TYPE_FD,
76*387f9dfdSAndroid Build Coastguard Worker
77*387f9dfdSAndroid Build Coastguard Worker // bcc_elf_file owning a memory buffer and providing access to an
78*387f9dfdSAndroid Build Coastguard Worker // Elf file backed by data in that buffer.
79*387f9dfdSAndroid Build Coastguard Worker // buf field of the impl union stores the address of the buffer
80*387f9dfdSAndroid Build Coastguard Worker // and elf pointer is not NULL.
81*387f9dfdSAndroid Build Coastguard Worker BCC_ELF_FILE_TYPE_BUF,
82*387f9dfdSAndroid Build Coastguard Worker
83*387f9dfdSAndroid Build Coastguard Worker // bcc_elf_file owning a bcc_zip_archive and providing access to
84*387f9dfdSAndroid Build Coastguard Worker // an Elf file backed by data from one of the zip entries.
85*387f9dfdSAndroid Build Coastguard Worker // archive field of the impl union stores the address of the
86*387f9dfdSAndroid Build Coastguard Worker // zip archive and elf pointer is not NULL.
87*387f9dfdSAndroid Build Coastguard Worker BCC_ELF_FILE_TYPE_ARCHIVE
88*387f9dfdSAndroid Build Coastguard Worker };
89*387f9dfdSAndroid Build Coastguard Worker
90*387f9dfdSAndroid Build Coastguard Worker // Provides access to an Elf structure in an uniform way,
91*387f9dfdSAndroid Build Coastguard Worker // independently from its source (file, memory buffer, zip archive).
92*387f9dfdSAndroid Build Coastguard Worker struct bcc_elf_file {
93*387f9dfdSAndroid Build Coastguard Worker Elf *elf;
94*387f9dfdSAndroid Build Coastguard Worker enum bcc_elf_file_type type;
95*387f9dfdSAndroid Build Coastguard Worker
96*387f9dfdSAndroid Build Coastguard Worker union {
97*387f9dfdSAndroid Build Coastguard Worker int fd;
98*387f9dfdSAndroid Build Coastguard Worker void *buf;
99*387f9dfdSAndroid Build Coastguard Worker struct bcc_zip_archive *archive;
100*387f9dfdSAndroid Build Coastguard Worker };
101*387f9dfdSAndroid Build Coastguard Worker };
102*387f9dfdSAndroid Build Coastguard Worker
103*387f9dfdSAndroid Build Coastguard Worker // Initializes bcc_elf_file as not pointing to any elf file and not
104*387f9dfdSAndroid Build Coastguard Worker // owning any resources. After returning the provided elf_file can be
105*387f9dfdSAndroid Build Coastguard Worker // safely passed to bcc_elf_file_close.
bcc_elf_file_init(struct bcc_elf_file * elf_file)106*387f9dfdSAndroid Build Coastguard Worker static void bcc_elf_file_init(struct bcc_elf_file *elf_file) {
107*387f9dfdSAndroid Build Coastguard Worker memset(elf_file, 0, sizeof(struct bcc_elf_file));
108*387f9dfdSAndroid Build Coastguard Worker }
109*387f9dfdSAndroid Build Coastguard Worker
110*387f9dfdSAndroid Build Coastguard Worker #ifdef HAVE_LIBLZMA
bcc_elf_file_open_buf(void * buf,size_t buf_len,struct bcc_elf_file * out)111*387f9dfdSAndroid Build Coastguard Worker static int bcc_elf_file_open_buf(void *buf, size_t buf_len,
112*387f9dfdSAndroid Build Coastguard Worker struct bcc_elf_file *out) {
113*387f9dfdSAndroid Build Coastguard Worker Elf *elf = NULL;
114*387f9dfdSAndroid Build Coastguard Worker
115*387f9dfdSAndroid Build Coastguard Worker if (openelf_mem(buf, buf_len, &elf)) {
116*387f9dfdSAndroid Build Coastguard Worker return -1;
117*387f9dfdSAndroid Build Coastguard Worker }
118*387f9dfdSAndroid Build Coastguard Worker
119*387f9dfdSAndroid Build Coastguard Worker out->elf = elf;
120*387f9dfdSAndroid Build Coastguard Worker out->type = BCC_ELF_FILE_TYPE_BUF;
121*387f9dfdSAndroid Build Coastguard Worker out->buf = buf;
122*387f9dfdSAndroid Build Coastguard Worker return 0;
123*387f9dfdSAndroid Build Coastguard Worker }
124*387f9dfdSAndroid Build Coastguard Worker #endif
125*387f9dfdSAndroid Build Coastguard Worker
bcc_elf_file_open_fd(int fd,struct bcc_elf_file * out)126*387f9dfdSAndroid Build Coastguard Worker static int bcc_elf_file_open_fd(int fd, struct bcc_elf_file *out) {
127*387f9dfdSAndroid Build Coastguard Worker Elf *elf = NULL;
128*387f9dfdSAndroid Build Coastguard Worker
129*387f9dfdSAndroid Build Coastguard Worker if (openelf_fd(fd, &elf)) {
130*387f9dfdSAndroid Build Coastguard Worker return -1;
131*387f9dfdSAndroid Build Coastguard Worker }
132*387f9dfdSAndroid Build Coastguard Worker
133*387f9dfdSAndroid Build Coastguard Worker out->elf = elf;
134*387f9dfdSAndroid Build Coastguard Worker out->type = BCC_ELF_FILE_TYPE_FD;
135*387f9dfdSAndroid Build Coastguard Worker out->fd = fd;
136*387f9dfdSAndroid Build Coastguard Worker return 0;
137*387f9dfdSAndroid Build Coastguard Worker }
138*387f9dfdSAndroid Build Coastguard Worker
bcc_elf_file_open(const char * path,struct bcc_elf_file * out)139*387f9dfdSAndroid Build Coastguard Worker static int bcc_elf_file_open(const char *path, struct bcc_elf_file *out) {
140*387f9dfdSAndroid Build Coastguard Worker struct bcc_zip_archive *archive = NULL;
141*387f9dfdSAndroid Build Coastguard Worker struct bcc_zip_entry entry;
142*387f9dfdSAndroid Build Coastguard Worker int fd = -1;
143*387f9dfdSAndroid Build Coastguard Worker
144*387f9dfdSAndroid Build Coastguard Worker fd = open(path, O_RDONLY);
145*387f9dfdSAndroid Build Coastguard Worker if (fd >= 0) {
146*387f9dfdSAndroid Build Coastguard Worker if (bcc_elf_file_open_fd(fd, out)) {
147*387f9dfdSAndroid Build Coastguard Worker close(fd);
148*387f9dfdSAndroid Build Coastguard Worker return -1;
149*387f9dfdSAndroid Build Coastguard Worker }
150*387f9dfdSAndroid Build Coastguard Worker
151*387f9dfdSAndroid Build Coastguard Worker return 0;
152*387f9dfdSAndroid Build Coastguard Worker }
153*387f9dfdSAndroid Build Coastguard Worker
154*387f9dfdSAndroid Build Coastguard Worker archive = bcc_zip_archive_open_and_find(path, &entry);
155*387f9dfdSAndroid Build Coastguard Worker if (archive) {
156*387f9dfdSAndroid Build Coastguard Worker if (entry.compression ||
157*387f9dfdSAndroid Build Coastguard Worker openelf_mem((void *)entry.data, entry.data_length, &out->elf)) {
158*387f9dfdSAndroid Build Coastguard Worker bcc_zip_archive_close(archive);
159*387f9dfdSAndroid Build Coastguard Worker return -1;
160*387f9dfdSAndroid Build Coastguard Worker }
161*387f9dfdSAndroid Build Coastguard Worker
162*387f9dfdSAndroid Build Coastguard Worker out->type = BCC_ELF_FILE_TYPE_ARCHIVE;
163*387f9dfdSAndroid Build Coastguard Worker out->archive = archive;
164*387f9dfdSAndroid Build Coastguard Worker return 0;
165*387f9dfdSAndroid Build Coastguard Worker }
166*387f9dfdSAndroid Build Coastguard Worker
167*387f9dfdSAndroid Build Coastguard Worker return -1;
168*387f9dfdSAndroid Build Coastguard Worker }
169*387f9dfdSAndroid Build Coastguard Worker
bcc_elf_file_close(struct bcc_elf_file * elf_file)170*387f9dfdSAndroid Build Coastguard Worker static void bcc_elf_file_close(struct bcc_elf_file *elf_file) {
171*387f9dfdSAndroid Build Coastguard Worker if (elf_file->elf) {
172*387f9dfdSAndroid Build Coastguard Worker elf_end(elf_file->elf);
173*387f9dfdSAndroid Build Coastguard Worker }
174*387f9dfdSAndroid Build Coastguard Worker
175*387f9dfdSAndroid Build Coastguard Worker switch (elf_file->type) {
176*387f9dfdSAndroid Build Coastguard Worker case BCC_ELF_FILE_TYPE_FD:
177*387f9dfdSAndroid Build Coastguard Worker close(elf_file->fd);
178*387f9dfdSAndroid Build Coastguard Worker break;
179*387f9dfdSAndroid Build Coastguard Worker
180*387f9dfdSAndroid Build Coastguard Worker case BCC_ELF_FILE_TYPE_BUF:
181*387f9dfdSAndroid Build Coastguard Worker free(elf_file->buf);
182*387f9dfdSAndroid Build Coastguard Worker break;
183*387f9dfdSAndroid Build Coastguard Worker
184*387f9dfdSAndroid Build Coastguard Worker case BCC_ELF_FILE_TYPE_ARCHIVE:
185*387f9dfdSAndroid Build Coastguard Worker bcc_zip_archive_close(elf_file->archive);
186*387f9dfdSAndroid Build Coastguard Worker break;
187*387f9dfdSAndroid Build Coastguard Worker
188*387f9dfdSAndroid Build Coastguard Worker default:
189*387f9dfdSAndroid Build Coastguard Worker break;
190*387f9dfdSAndroid Build Coastguard Worker }
191*387f9dfdSAndroid Build Coastguard Worker
192*387f9dfdSAndroid Build Coastguard Worker bcc_elf_file_init(elf_file);
193*387f9dfdSAndroid Build Coastguard Worker }
194*387f9dfdSAndroid Build Coastguard Worker
parse_stapsdt_note(struct bcc_elf_usdt * probe,GElf_Shdr * probes_shdr,const char * desc,int elf_class)195*387f9dfdSAndroid Build Coastguard Worker static const char *parse_stapsdt_note(struct bcc_elf_usdt *probe,
196*387f9dfdSAndroid Build Coastguard Worker GElf_Shdr *probes_shdr,
197*387f9dfdSAndroid Build Coastguard Worker const char *desc, int elf_class) {
198*387f9dfdSAndroid Build Coastguard Worker if (elf_class == ELFCLASS32) {
199*387f9dfdSAndroid Build Coastguard Worker probe->pc = *((uint32_t *)(desc));
200*387f9dfdSAndroid Build Coastguard Worker probe->base_addr = *((uint32_t *)(desc + 4));
201*387f9dfdSAndroid Build Coastguard Worker probe->semaphore = *((uint32_t *)(desc + 8));
202*387f9dfdSAndroid Build Coastguard Worker desc = desc + 12;
203*387f9dfdSAndroid Build Coastguard Worker } else {
204*387f9dfdSAndroid Build Coastguard Worker probe->pc = *((uint64_t *)(desc));
205*387f9dfdSAndroid Build Coastguard Worker probe->base_addr = *((uint64_t *)(desc + 8));
206*387f9dfdSAndroid Build Coastguard Worker probe->semaphore = *((uint64_t *)(desc + 16));
207*387f9dfdSAndroid Build Coastguard Worker desc = desc + 24;
208*387f9dfdSAndroid Build Coastguard Worker }
209*387f9dfdSAndroid Build Coastguard Worker
210*387f9dfdSAndroid Build Coastguard Worker // Offset from start of file
211*387f9dfdSAndroid Build Coastguard Worker if (probe->semaphore && probes_shdr)
212*387f9dfdSAndroid Build Coastguard Worker probe->semaphore_offset =
213*387f9dfdSAndroid Build Coastguard Worker probe->semaphore - probes_shdr->sh_addr + probes_shdr->sh_offset;
214*387f9dfdSAndroid Build Coastguard Worker else
215*387f9dfdSAndroid Build Coastguard Worker probe->semaphore_offset = 0;
216*387f9dfdSAndroid Build Coastguard Worker
217*387f9dfdSAndroid Build Coastguard Worker probe->provider = desc;
218*387f9dfdSAndroid Build Coastguard Worker desc += strlen(desc) + 1;
219*387f9dfdSAndroid Build Coastguard Worker
220*387f9dfdSAndroid Build Coastguard Worker probe->name = desc;
221*387f9dfdSAndroid Build Coastguard Worker desc += strlen(desc) + 1;
222*387f9dfdSAndroid Build Coastguard Worker
223*387f9dfdSAndroid Build Coastguard Worker probe->arg_fmt = desc;
224*387f9dfdSAndroid Build Coastguard Worker desc += strlen(desc) + 1;
225*387f9dfdSAndroid Build Coastguard Worker
226*387f9dfdSAndroid Build Coastguard Worker return desc;
227*387f9dfdSAndroid Build Coastguard Worker }
228*387f9dfdSAndroid Build Coastguard Worker
do_note_segment(Elf_Scn * section,GElf_Shdr * probes_shdr,int elf_class,bcc_elf_probecb callback,const char * binpath,uint64_t first_inst_offset,void * payload)229*387f9dfdSAndroid Build Coastguard Worker static int do_note_segment(Elf_Scn *section, GElf_Shdr *probes_shdr, int elf_class,
230*387f9dfdSAndroid Build Coastguard Worker bcc_elf_probecb callback, const char *binpath,
231*387f9dfdSAndroid Build Coastguard Worker uint64_t first_inst_offset, void *payload) {
232*387f9dfdSAndroid Build Coastguard Worker Elf_Data *data = NULL;
233*387f9dfdSAndroid Build Coastguard Worker
234*387f9dfdSAndroid Build Coastguard Worker while ((data = elf_getdata(section, data)) != 0) {
235*387f9dfdSAndroid Build Coastguard Worker size_t offset = 0;
236*387f9dfdSAndroid Build Coastguard Worker GElf_Nhdr hdr;
237*387f9dfdSAndroid Build Coastguard Worker size_t name_off, desc_off;
238*387f9dfdSAndroid Build Coastguard Worker
239*387f9dfdSAndroid Build Coastguard Worker while ((offset = gelf_getnote(data, offset, &hdr, &name_off, &desc_off)) !=
240*387f9dfdSAndroid Build Coastguard Worker 0) {
241*387f9dfdSAndroid Build Coastguard Worker const char *desc, *desc_end;
242*387f9dfdSAndroid Build Coastguard Worker struct bcc_elf_usdt probe;
243*387f9dfdSAndroid Build Coastguard Worker
244*387f9dfdSAndroid Build Coastguard Worker if (hdr.n_type != NT_STAPSDT)
245*387f9dfdSAndroid Build Coastguard Worker continue;
246*387f9dfdSAndroid Build Coastguard Worker
247*387f9dfdSAndroid Build Coastguard Worker if (hdr.n_namesz != 8)
248*387f9dfdSAndroid Build Coastguard Worker continue;
249*387f9dfdSAndroid Build Coastguard Worker
250*387f9dfdSAndroid Build Coastguard Worker if (memcmp((const char *)data->d_buf + name_off, "stapsdt", 8) != 0)
251*387f9dfdSAndroid Build Coastguard Worker continue;
252*387f9dfdSAndroid Build Coastguard Worker
253*387f9dfdSAndroid Build Coastguard Worker desc = (const char *)data->d_buf + desc_off;
254*387f9dfdSAndroid Build Coastguard Worker desc_end = desc + hdr.n_descsz;
255*387f9dfdSAndroid Build Coastguard Worker
256*387f9dfdSAndroid Build Coastguard Worker if (parse_stapsdt_note(&probe, probes_shdr, desc, elf_class) == desc_end) {
257*387f9dfdSAndroid Build Coastguard Worker if (probe.pc < first_inst_offset)
258*387f9dfdSAndroid Build Coastguard Worker fprintf(stderr,
259*387f9dfdSAndroid Build Coastguard Worker "WARNING: invalid address 0x%lx for probe (%s,%s) in binary %s\n",
260*387f9dfdSAndroid Build Coastguard Worker probe.pc, probe.provider, probe.name, binpath);
261*387f9dfdSAndroid Build Coastguard Worker else
262*387f9dfdSAndroid Build Coastguard Worker callback(binpath, &probe, payload);
263*387f9dfdSAndroid Build Coastguard Worker }
264*387f9dfdSAndroid Build Coastguard Worker }
265*387f9dfdSAndroid Build Coastguard Worker }
266*387f9dfdSAndroid Build Coastguard Worker return 0;
267*387f9dfdSAndroid Build Coastguard Worker }
268*387f9dfdSAndroid Build Coastguard Worker
listprobes(Elf * e,bcc_elf_probecb callback,const char * binpath,void * payload)269*387f9dfdSAndroid Build Coastguard Worker static int listprobes(Elf *e, bcc_elf_probecb callback, const char *binpath,
270*387f9dfdSAndroid Build Coastguard Worker void *payload) {
271*387f9dfdSAndroid Build Coastguard Worker Elf_Scn *section = NULL;
272*387f9dfdSAndroid Build Coastguard Worker bool found_probes_shdr;
273*387f9dfdSAndroid Build Coastguard Worker size_t stridx;
274*387f9dfdSAndroid Build Coastguard Worker int elf_class = gelf_getclass(e);
275*387f9dfdSAndroid Build Coastguard Worker uint64_t first_inst_offset = 0;
276*387f9dfdSAndroid Build Coastguard Worker GElf_Shdr probes_shdr = {};
277*387f9dfdSAndroid Build Coastguard Worker
278*387f9dfdSAndroid Build Coastguard Worker if (elf_getshdrstrndx(e, &stridx) != 0)
279*387f9dfdSAndroid Build Coastguard Worker return -1;
280*387f9dfdSAndroid Build Coastguard Worker
281*387f9dfdSAndroid Build Coastguard Worker // Get the offset to the first instruction
282*387f9dfdSAndroid Build Coastguard Worker while ((section = elf_nextscn(e, section)) != 0) {
283*387f9dfdSAndroid Build Coastguard Worker GElf_Shdr header;
284*387f9dfdSAndroid Build Coastguard Worker
285*387f9dfdSAndroid Build Coastguard Worker if (!gelf_getshdr(section, &header))
286*387f9dfdSAndroid Build Coastguard Worker continue;
287*387f9dfdSAndroid Build Coastguard Worker
288*387f9dfdSAndroid Build Coastguard Worker // The elf file section layout is based on increasing virtual address,
289*387f9dfdSAndroid Build Coastguard Worker // getting the first section with SHF_EXECINSTR is enough.
290*387f9dfdSAndroid Build Coastguard Worker if (header.sh_flags & SHF_EXECINSTR) {
291*387f9dfdSAndroid Build Coastguard Worker first_inst_offset = header.sh_addr;
292*387f9dfdSAndroid Build Coastguard Worker break;
293*387f9dfdSAndroid Build Coastguard Worker }
294*387f9dfdSAndroid Build Coastguard Worker }
295*387f9dfdSAndroid Build Coastguard Worker
296*387f9dfdSAndroid Build Coastguard Worker found_probes_shdr = false;
297*387f9dfdSAndroid Build Coastguard Worker while ((section = elf_nextscn(e, section)) != 0) {
298*387f9dfdSAndroid Build Coastguard Worker if (!gelf_getshdr(section, &probes_shdr))
299*387f9dfdSAndroid Build Coastguard Worker continue;
300*387f9dfdSAndroid Build Coastguard Worker
301*387f9dfdSAndroid Build Coastguard Worker char *name = elf_strptr(e, stridx, probes_shdr.sh_name);
302*387f9dfdSAndroid Build Coastguard Worker if (name && !strcmp(name, ".probes")) {
303*387f9dfdSAndroid Build Coastguard Worker found_probes_shdr = true;
304*387f9dfdSAndroid Build Coastguard Worker break;
305*387f9dfdSAndroid Build Coastguard Worker }
306*387f9dfdSAndroid Build Coastguard Worker }
307*387f9dfdSAndroid Build Coastguard Worker
308*387f9dfdSAndroid Build Coastguard Worker while ((section = elf_nextscn(e, section)) != 0) {
309*387f9dfdSAndroid Build Coastguard Worker GElf_Shdr header;
310*387f9dfdSAndroid Build Coastguard Worker char *name;
311*387f9dfdSAndroid Build Coastguard Worker
312*387f9dfdSAndroid Build Coastguard Worker if (!gelf_getshdr(section, &header))
313*387f9dfdSAndroid Build Coastguard Worker continue;
314*387f9dfdSAndroid Build Coastguard Worker
315*387f9dfdSAndroid Build Coastguard Worker if (header.sh_type != SHT_NOTE)
316*387f9dfdSAndroid Build Coastguard Worker continue;
317*387f9dfdSAndroid Build Coastguard Worker
318*387f9dfdSAndroid Build Coastguard Worker name = elf_strptr(e, stridx, header.sh_name);
319*387f9dfdSAndroid Build Coastguard Worker if (name && !strcmp(name, ".note.stapsdt")) {
320*387f9dfdSAndroid Build Coastguard Worker GElf_Shdr *shdr_ptr = found_probes_shdr ? &probes_shdr : NULL;
321*387f9dfdSAndroid Build Coastguard Worker if (do_note_segment(section, shdr_ptr, elf_class, callback, binpath,
322*387f9dfdSAndroid Build Coastguard Worker first_inst_offset, payload) < 0)
323*387f9dfdSAndroid Build Coastguard Worker return -1;
324*387f9dfdSAndroid Build Coastguard Worker }
325*387f9dfdSAndroid Build Coastguard Worker }
326*387f9dfdSAndroid Build Coastguard Worker
327*387f9dfdSAndroid Build Coastguard Worker return 0;
328*387f9dfdSAndroid Build Coastguard Worker }
329*387f9dfdSAndroid Build Coastguard Worker
bcc_elf_foreach_usdt(const char * path,bcc_elf_probecb callback,void * payload)330*387f9dfdSAndroid Build Coastguard Worker int bcc_elf_foreach_usdt(const char *path, bcc_elf_probecb callback,
331*387f9dfdSAndroid Build Coastguard Worker void *payload) {
332*387f9dfdSAndroid Build Coastguard Worker int res;
333*387f9dfdSAndroid Build Coastguard Worker struct bcc_elf_file elf_file;
334*387f9dfdSAndroid Build Coastguard Worker bcc_elf_file_init(&elf_file);
335*387f9dfdSAndroid Build Coastguard Worker
336*387f9dfdSAndroid Build Coastguard Worker if (bcc_elf_file_open(path, &elf_file) < 0)
337*387f9dfdSAndroid Build Coastguard Worker return -1;
338*387f9dfdSAndroid Build Coastguard Worker
339*387f9dfdSAndroid Build Coastguard Worker res = listprobes(elf_file.elf, callback, path, payload);
340*387f9dfdSAndroid Build Coastguard Worker
341*387f9dfdSAndroid Build Coastguard Worker bcc_elf_file_close(&elf_file);
342*387f9dfdSAndroid Build Coastguard Worker return res;
343*387f9dfdSAndroid Build Coastguard Worker }
344*387f9dfdSAndroid Build Coastguard Worker
get_section(Elf * e,const char * section_name,GElf_Shdr * section_hdr,size_t * section_idx)345*387f9dfdSAndroid Build Coastguard Worker static Elf_Scn * get_section(Elf *e, const char *section_name,
346*387f9dfdSAndroid Build Coastguard Worker GElf_Shdr *section_hdr, size_t *section_idx) {
347*387f9dfdSAndroid Build Coastguard Worker Elf_Scn *section = NULL;
348*387f9dfdSAndroid Build Coastguard Worker GElf_Shdr header;
349*387f9dfdSAndroid Build Coastguard Worker char *name;
350*387f9dfdSAndroid Build Coastguard Worker
351*387f9dfdSAndroid Build Coastguard Worker size_t stridx;
352*387f9dfdSAndroid Build Coastguard Worker if (elf_getshdrstrndx(e, &stridx) != 0)
353*387f9dfdSAndroid Build Coastguard Worker return NULL;
354*387f9dfdSAndroid Build Coastguard Worker
355*387f9dfdSAndroid Build Coastguard Worker size_t index;
356*387f9dfdSAndroid Build Coastguard Worker for (index = 1; (section = elf_nextscn(e, section)) != 0; index++) {
357*387f9dfdSAndroid Build Coastguard Worker if (!gelf_getshdr(section, &header))
358*387f9dfdSAndroid Build Coastguard Worker continue;
359*387f9dfdSAndroid Build Coastguard Worker
360*387f9dfdSAndroid Build Coastguard Worker name = elf_strptr(e, stridx, header.sh_name);
361*387f9dfdSAndroid Build Coastguard Worker if (name && !strcmp(name, section_name)) {
362*387f9dfdSAndroid Build Coastguard Worker if (section_hdr)
363*387f9dfdSAndroid Build Coastguard Worker *section_hdr = header;
364*387f9dfdSAndroid Build Coastguard Worker if (section_idx)
365*387f9dfdSAndroid Build Coastguard Worker *section_idx = index;
366*387f9dfdSAndroid Build Coastguard Worker return section;
367*387f9dfdSAndroid Build Coastguard Worker }
368*387f9dfdSAndroid Build Coastguard Worker }
369*387f9dfdSAndroid Build Coastguard Worker
370*387f9dfdSAndroid Build Coastguard Worker return NULL;
371*387f9dfdSAndroid Build Coastguard Worker }
372*387f9dfdSAndroid Build Coastguard Worker
list_in_scn(Elf * e,Elf_Scn * section,size_t stridx,size_t symsize,struct bcc_symbol_option * option,bcc_elf_symcb callback,bcc_elf_symcb_lazy callback_lazy,void * payload,bool debugfile)373*387f9dfdSAndroid Build Coastguard Worker static int list_in_scn(Elf *e, Elf_Scn *section, size_t stridx, size_t symsize,
374*387f9dfdSAndroid Build Coastguard Worker struct bcc_symbol_option *option,
375*387f9dfdSAndroid Build Coastguard Worker bcc_elf_symcb callback, bcc_elf_symcb_lazy callback_lazy,
376*387f9dfdSAndroid Build Coastguard Worker void *payload, bool debugfile) {
377*387f9dfdSAndroid Build Coastguard Worker Elf_Data *data = NULL;
378*387f9dfdSAndroid Build Coastguard Worker
379*387f9dfdSAndroid Build Coastguard Worker #if defined(__powerpc64__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
380*387f9dfdSAndroid Build Coastguard Worker size_t opdidx = 0;
381*387f9dfdSAndroid Build Coastguard Worker Elf_Scn *opdsec = NULL;
382*387f9dfdSAndroid Build Coastguard Worker GElf_Shdr opdshdr = {};
383*387f9dfdSAndroid Build Coastguard Worker Elf_Data *opddata = NULL;
384*387f9dfdSAndroid Build Coastguard Worker
385*387f9dfdSAndroid Build Coastguard Worker opdsec = get_section(e, ".opd", &opdshdr, &opdidx);
386*387f9dfdSAndroid Build Coastguard Worker if (opdsec && opdshdr.sh_type == SHT_PROGBITS)
387*387f9dfdSAndroid Build Coastguard Worker opddata = elf_getdata(opdsec, NULL);
388*387f9dfdSAndroid Build Coastguard Worker #endif
389*387f9dfdSAndroid Build Coastguard Worker
390*387f9dfdSAndroid Build Coastguard Worker while ((data = elf_getdata(section, data)) != 0) {
391*387f9dfdSAndroid Build Coastguard Worker size_t i, symcount = data->d_size / symsize;
392*387f9dfdSAndroid Build Coastguard Worker
393*387f9dfdSAndroid Build Coastguard Worker if (data->d_size % symsize)
394*387f9dfdSAndroid Build Coastguard Worker return -1;
395*387f9dfdSAndroid Build Coastguard Worker
396*387f9dfdSAndroid Build Coastguard Worker for (i = 0; i < symcount; ++i) {
397*387f9dfdSAndroid Build Coastguard Worker GElf_Sym sym;
398*387f9dfdSAndroid Build Coastguard Worker const char *name;
399*387f9dfdSAndroid Build Coastguard Worker size_t name_len;
400*387f9dfdSAndroid Build Coastguard Worker
401*387f9dfdSAndroid Build Coastguard Worker if (!gelf_getsym(data, (int)i, &sym))
402*387f9dfdSAndroid Build Coastguard Worker continue;
403*387f9dfdSAndroid Build Coastguard Worker
404*387f9dfdSAndroid Build Coastguard Worker if ((name = elf_strptr(e, stridx, sym.st_name)) == NULL)
405*387f9dfdSAndroid Build Coastguard Worker continue;
406*387f9dfdSAndroid Build Coastguard Worker if (name[0] == 0)
407*387f9dfdSAndroid Build Coastguard Worker continue;
408*387f9dfdSAndroid Build Coastguard Worker name_len = strlen(name);
409*387f9dfdSAndroid Build Coastguard Worker
410*387f9dfdSAndroid Build Coastguard Worker if (sym.st_value == 0)
411*387f9dfdSAndroid Build Coastguard Worker continue;
412*387f9dfdSAndroid Build Coastguard Worker
413*387f9dfdSAndroid Build Coastguard Worker uint32_t st_type = ELF_ST_TYPE(sym.st_info);
414*387f9dfdSAndroid Build Coastguard Worker if (!(option->use_symbol_type & (1 << st_type)))
415*387f9dfdSAndroid Build Coastguard Worker continue;
416*387f9dfdSAndroid Build Coastguard Worker
417*387f9dfdSAndroid Build Coastguard Worker #ifdef __powerpc64__
418*387f9dfdSAndroid Build Coastguard Worker #if defined(_CALL_ELF) && _CALL_ELF == 2
419*387f9dfdSAndroid Build Coastguard Worker if (option->use_symbol_type & (1 << STT_PPC64_ELFV2_SYM_LEP)) {
420*387f9dfdSAndroid Build Coastguard Worker /*
421*387f9dfdSAndroid Build Coastguard Worker * The PowerPC 64-bit ELF v2 ABI says that the 3 most significant bits
422*387f9dfdSAndroid Build Coastguard Worker * in the st_other field of the symbol table specifies the number of
423*387f9dfdSAndroid Build Coastguard Worker * instructions between a function's Global Entry Point (GEP) and Local
424*387f9dfdSAndroid Build Coastguard Worker * Entry Point (LEP).
425*387f9dfdSAndroid Build Coastguard Worker */
426*387f9dfdSAndroid Build Coastguard Worker switch (sym.st_other >> 5) {
427*387f9dfdSAndroid Build Coastguard Worker /* GEP and LEP are the same for 0 or 1, usage is reserved for 7 */
428*387f9dfdSAndroid Build Coastguard Worker /* If 2, LEP is 1 instruction past the GEP */
429*387f9dfdSAndroid Build Coastguard Worker case 2: sym.st_value += 4; break;
430*387f9dfdSAndroid Build Coastguard Worker /* If 3, LEP is 2 instructions past the GEP */
431*387f9dfdSAndroid Build Coastguard Worker case 3: sym.st_value += 8; break;
432*387f9dfdSAndroid Build Coastguard Worker /* If 4, LEP is 4 instructions past the GEP */
433*387f9dfdSAndroid Build Coastguard Worker case 4: sym.st_value += 16; break;
434*387f9dfdSAndroid Build Coastguard Worker /* If 5, LEP is 8 instructions past the GEP */
435*387f9dfdSAndroid Build Coastguard Worker case 5: sym.st_value += 32; break;
436*387f9dfdSAndroid Build Coastguard Worker /* If 6, LEP is 16 instructions past the GEP */
437*387f9dfdSAndroid Build Coastguard Worker case 6: sym.st_value += 64; break;
438*387f9dfdSAndroid Build Coastguard Worker }
439*387f9dfdSAndroid Build Coastguard Worker }
440*387f9dfdSAndroid Build Coastguard Worker #else
441*387f9dfdSAndroid Build Coastguard Worker if (opddata && sym.st_shndx == opdidx) {
442*387f9dfdSAndroid Build Coastguard Worker size_t offset = sym.st_value - opdshdr.sh_addr;
443*387f9dfdSAndroid Build Coastguard Worker /* Find the function descriptor */
444*387f9dfdSAndroid Build Coastguard Worker uint64_t *descr = opddata->d_buf + offset;
445*387f9dfdSAndroid Build Coastguard Worker /* Read the actual entry point address from the descriptor */
446*387f9dfdSAndroid Build Coastguard Worker sym.st_value = *descr;
447*387f9dfdSAndroid Build Coastguard Worker }
448*387f9dfdSAndroid Build Coastguard Worker #endif
449*387f9dfdSAndroid Build Coastguard Worker #endif
450*387f9dfdSAndroid Build Coastguard Worker
451*387f9dfdSAndroid Build Coastguard Worker int ret;
452*387f9dfdSAndroid Build Coastguard Worker if (option->lazy_symbolize)
453*387f9dfdSAndroid Build Coastguard Worker ret = callback_lazy(stridx, sym.st_name, name_len, sym.st_value,
454*387f9dfdSAndroid Build Coastguard Worker sym.st_size, debugfile, payload);
455*387f9dfdSAndroid Build Coastguard Worker else
456*387f9dfdSAndroid Build Coastguard Worker ret = callback(name, sym.st_value, sym.st_size, payload);
457*387f9dfdSAndroid Build Coastguard Worker if (ret < 0)
458*387f9dfdSAndroid Build Coastguard Worker return 1; // signal termination to caller
459*387f9dfdSAndroid Build Coastguard Worker }
460*387f9dfdSAndroid Build Coastguard Worker }
461*387f9dfdSAndroid Build Coastguard Worker
462*387f9dfdSAndroid Build Coastguard Worker return 0;
463*387f9dfdSAndroid Build Coastguard Worker }
464*387f9dfdSAndroid Build Coastguard Worker
listsymbols(Elf * e,bcc_elf_symcb callback,bcc_elf_symcb_lazy callback_lazy,void * payload,struct bcc_symbol_option * option,bool debugfile)465*387f9dfdSAndroid Build Coastguard Worker static int listsymbols(Elf *e, bcc_elf_symcb callback,
466*387f9dfdSAndroid Build Coastguard Worker bcc_elf_symcb_lazy callback_lazy, void *payload,
467*387f9dfdSAndroid Build Coastguard Worker struct bcc_symbol_option *option, bool debugfile) {
468*387f9dfdSAndroid Build Coastguard Worker Elf_Scn *section = NULL;
469*387f9dfdSAndroid Build Coastguard Worker
470*387f9dfdSAndroid Build Coastguard Worker while ((section = elf_nextscn(e, section)) != 0) {
471*387f9dfdSAndroid Build Coastguard Worker GElf_Shdr header;
472*387f9dfdSAndroid Build Coastguard Worker
473*387f9dfdSAndroid Build Coastguard Worker if (!gelf_getshdr(section, &header))
474*387f9dfdSAndroid Build Coastguard Worker continue;
475*387f9dfdSAndroid Build Coastguard Worker
476*387f9dfdSAndroid Build Coastguard Worker if (header.sh_type != SHT_SYMTAB && header.sh_type != SHT_DYNSYM)
477*387f9dfdSAndroid Build Coastguard Worker continue;
478*387f9dfdSAndroid Build Coastguard Worker
479*387f9dfdSAndroid Build Coastguard Worker int rc = list_in_scn(e, section, header.sh_link, header.sh_entsize,
480*387f9dfdSAndroid Build Coastguard Worker option, callback, callback_lazy, payload, debugfile);
481*387f9dfdSAndroid Build Coastguard Worker if (rc == 1)
482*387f9dfdSAndroid Build Coastguard Worker break; // callback signaled termination
483*387f9dfdSAndroid Build Coastguard Worker
484*387f9dfdSAndroid Build Coastguard Worker if (rc < 0)
485*387f9dfdSAndroid Build Coastguard Worker return rc;
486*387f9dfdSAndroid Build Coastguard Worker }
487*387f9dfdSAndroid Build Coastguard Worker
488*387f9dfdSAndroid Build Coastguard Worker return 0;
489*387f9dfdSAndroid Build Coastguard Worker }
490*387f9dfdSAndroid Build Coastguard Worker
get_section_elf_data(Elf * e,const char * section_name)491*387f9dfdSAndroid Build Coastguard Worker static Elf_Data * get_section_elf_data(Elf *e, const char *section_name) {
492*387f9dfdSAndroid Build Coastguard Worker Elf_Scn *section = get_section(e, section_name, NULL, NULL);
493*387f9dfdSAndroid Build Coastguard Worker if (section)
494*387f9dfdSAndroid Build Coastguard Worker return elf_getdata(section, NULL);
495*387f9dfdSAndroid Build Coastguard Worker return NULL;
496*387f9dfdSAndroid Build Coastguard Worker }
497*387f9dfdSAndroid Build Coastguard Worker
find_debuglink(Elf * e,char ** debug_file,unsigned int * crc)498*387f9dfdSAndroid Build Coastguard Worker static int find_debuglink(Elf *e, char **debug_file, unsigned int *crc) {
499*387f9dfdSAndroid Build Coastguard Worker Elf_Data *data = NULL;
500*387f9dfdSAndroid Build Coastguard Worker
501*387f9dfdSAndroid Build Coastguard Worker *debug_file = NULL;
502*387f9dfdSAndroid Build Coastguard Worker *crc = 0;
503*387f9dfdSAndroid Build Coastguard Worker
504*387f9dfdSAndroid Build Coastguard Worker data = get_section_elf_data(e, ".gnu_debuglink");
505*387f9dfdSAndroid Build Coastguard Worker if (!data || data->d_size <= 5)
506*387f9dfdSAndroid Build Coastguard Worker return 0;
507*387f9dfdSAndroid Build Coastguard Worker
508*387f9dfdSAndroid Build Coastguard Worker *debug_file = (char *)data->d_buf;
509*387f9dfdSAndroid Build Coastguard Worker *crc = *(unsigned int*)((char *)data->d_buf + data->d_size - 4);
510*387f9dfdSAndroid Build Coastguard Worker
511*387f9dfdSAndroid Build Coastguard Worker return *debug_file ? 1 : 0;
512*387f9dfdSAndroid Build Coastguard Worker }
513*387f9dfdSAndroid Build Coastguard Worker
find_buildid(Elf * e,char * buildid)514*387f9dfdSAndroid Build Coastguard Worker static int find_buildid(Elf *e, char *buildid) {
515*387f9dfdSAndroid Build Coastguard Worker Elf_Data *data = get_section_elf_data(e, ".note.gnu.build-id");
516*387f9dfdSAndroid Build Coastguard Worker if (!data || data->d_size <= 16 || strcmp((char *)data->d_buf + 12, "GNU"))
517*387f9dfdSAndroid Build Coastguard Worker return 0;
518*387f9dfdSAndroid Build Coastguard Worker
519*387f9dfdSAndroid Build Coastguard Worker char *buf = (char *)data->d_buf + 16;
520*387f9dfdSAndroid Build Coastguard Worker size_t length = data->d_size - 16;
521*387f9dfdSAndroid Build Coastguard Worker size_t i = 0;
522*387f9dfdSAndroid Build Coastguard Worker for (i = 0; i < length; ++i) {
523*387f9dfdSAndroid Build Coastguard Worker sprintf(buildid + (i * 2), "%02hhx", buf[i]);
524*387f9dfdSAndroid Build Coastguard Worker }
525*387f9dfdSAndroid Build Coastguard Worker
526*387f9dfdSAndroid Build Coastguard Worker return 1;
527*387f9dfdSAndroid Build Coastguard Worker }
528*387f9dfdSAndroid Build Coastguard Worker
529*387f9dfdSAndroid Build Coastguard Worker // The CRC algorithm used by GNU debuglink. Taken from:
530*387f9dfdSAndroid Build Coastguard Worker // https://sourceware.org/gdb/onlinedocs/gdb/Separate-Debug-Files.html
gnu_debuglink_crc32(unsigned int crc,char * buf,size_t len)531*387f9dfdSAndroid Build Coastguard Worker static unsigned int gnu_debuglink_crc32(unsigned int crc,
532*387f9dfdSAndroid Build Coastguard Worker char *buf, size_t len) {
533*387f9dfdSAndroid Build Coastguard Worker static const unsigned int crc32_table[256] =
534*387f9dfdSAndroid Build Coastguard Worker {
535*387f9dfdSAndroid Build Coastguard Worker 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419,
536*387f9dfdSAndroid Build Coastguard Worker 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4,
537*387f9dfdSAndroid Build Coastguard Worker 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07,
538*387f9dfdSAndroid Build Coastguard Worker 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
539*387f9dfdSAndroid Build Coastguard Worker 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856,
540*387f9dfdSAndroid Build Coastguard Worker 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
541*387f9dfdSAndroid Build Coastguard Worker 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,
542*387f9dfdSAndroid Build Coastguard Worker 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
543*387f9dfdSAndroid Build Coastguard Worker 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,
544*387f9dfdSAndroid Build Coastguard Worker 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a,
545*387f9dfdSAndroid Build Coastguard Worker 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599,
546*387f9dfdSAndroid Build Coastguard Worker 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
547*387f9dfdSAndroid Build Coastguard Worker 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190,
548*387f9dfdSAndroid Build Coastguard Worker 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,
549*387f9dfdSAndroid Build Coastguard Worker 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e,
550*387f9dfdSAndroid Build Coastguard Worker 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
551*387f9dfdSAndroid Build Coastguard Worker 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed,
552*387f9dfdSAndroid Build Coastguard Worker 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
553*387f9dfdSAndroid Build Coastguard Worker 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3,
554*387f9dfdSAndroid Build Coastguard Worker 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
555*387f9dfdSAndroid Build Coastguard Worker 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,
556*387f9dfdSAndroid Build Coastguard Worker 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5,
557*387f9dfdSAndroid Build Coastguard Worker 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010,
558*387f9dfdSAndroid Build Coastguard Worker 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
559*387f9dfdSAndroid Build Coastguard Worker 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17,
560*387f9dfdSAndroid Build Coastguard Worker 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6,
561*387f9dfdSAndroid Build Coastguard Worker 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,
562*387f9dfdSAndroid Build Coastguard Worker 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
563*387f9dfdSAndroid Build Coastguard Worker 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344,
564*387f9dfdSAndroid Build Coastguard Worker 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
565*387f9dfdSAndroid Build Coastguard Worker 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a,
566*387f9dfdSAndroid Build Coastguard Worker 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
567*387f9dfdSAndroid Build Coastguard Worker 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1,
568*387f9dfdSAndroid Build Coastguard Worker 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c,
569*387f9dfdSAndroid Build Coastguard Worker 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,
570*387f9dfdSAndroid Build Coastguard Worker 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
571*387f9dfdSAndroid Build Coastguard Worker 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe,
572*387f9dfdSAndroid Build Coastguard Worker 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31,
573*387f9dfdSAndroid Build Coastguard Worker 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c,
574*387f9dfdSAndroid Build Coastguard Worker 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
575*387f9dfdSAndroid Build Coastguard Worker 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b,
576*387f9dfdSAndroid Build Coastguard Worker 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
577*387f9dfdSAndroid Build Coastguard Worker 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1,
578*387f9dfdSAndroid Build Coastguard Worker 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
579*387f9dfdSAndroid Build Coastguard Worker 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,
580*387f9dfdSAndroid Build Coastguard Worker 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7,
581*387f9dfdSAndroid Build Coastguard Worker 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66,
582*387f9dfdSAndroid Build Coastguard Worker 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
583*387f9dfdSAndroid Build Coastguard Worker 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,
584*387f9dfdSAndroid Build Coastguard Worker 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8,
585*387f9dfdSAndroid Build Coastguard Worker 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b,
586*387f9dfdSAndroid Build Coastguard Worker 0x2d02ef8d
587*387f9dfdSAndroid Build Coastguard Worker };
588*387f9dfdSAndroid Build Coastguard Worker char *end;
589*387f9dfdSAndroid Build Coastguard Worker
590*387f9dfdSAndroid Build Coastguard Worker crc = ~crc & 0xffffffff;
591*387f9dfdSAndroid Build Coastguard Worker for (end = buf + len; buf < end; ++buf)
592*387f9dfdSAndroid Build Coastguard Worker crc = crc32_table[(crc ^ *buf) & 0xff] ^ (crc >> 8);
593*387f9dfdSAndroid Build Coastguard Worker return ~crc & 0xffffffff;
594*387f9dfdSAndroid Build Coastguard Worker }
595*387f9dfdSAndroid Build Coastguard Worker
verify_checksum(const char * file,unsigned int crc)596*387f9dfdSAndroid Build Coastguard Worker static int verify_checksum(const char *file, unsigned int crc) {
597*387f9dfdSAndroid Build Coastguard Worker struct stat st;
598*387f9dfdSAndroid Build Coastguard Worker int fd;
599*387f9dfdSAndroid Build Coastguard Worker void *buf;
600*387f9dfdSAndroid Build Coastguard Worker unsigned int actual;
601*387f9dfdSAndroid Build Coastguard Worker
602*387f9dfdSAndroid Build Coastguard Worker fd = open(file, O_RDONLY);
603*387f9dfdSAndroid Build Coastguard Worker if (fd < 0)
604*387f9dfdSAndroid Build Coastguard Worker return 0;
605*387f9dfdSAndroid Build Coastguard Worker
606*387f9dfdSAndroid Build Coastguard Worker if (fstat(fd, &st) < 0) {
607*387f9dfdSAndroid Build Coastguard Worker close(fd);
608*387f9dfdSAndroid Build Coastguard Worker return 0;
609*387f9dfdSAndroid Build Coastguard Worker }
610*387f9dfdSAndroid Build Coastguard Worker
611*387f9dfdSAndroid Build Coastguard Worker buf = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
612*387f9dfdSAndroid Build Coastguard Worker if (!buf) {
613*387f9dfdSAndroid Build Coastguard Worker close(fd);
614*387f9dfdSAndroid Build Coastguard Worker return 0;
615*387f9dfdSAndroid Build Coastguard Worker }
616*387f9dfdSAndroid Build Coastguard Worker
617*387f9dfdSAndroid Build Coastguard Worker actual = gnu_debuglink_crc32(0, buf, st.st_size);
618*387f9dfdSAndroid Build Coastguard Worker
619*387f9dfdSAndroid Build Coastguard Worker munmap(buf, st.st_size);
620*387f9dfdSAndroid Build Coastguard Worker close(fd);
621*387f9dfdSAndroid Build Coastguard Worker return actual == crc;
622*387f9dfdSAndroid Build Coastguard Worker }
623*387f9dfdSAndroid Build Coastguard Worker
624*387f9dfdSAndroid Build Coastguard Worker // Check if two filenames point to the same file, including hard or soft links.
same_file(char * a,const char * b)625*387f9dfdSAndroid Build Coastguard Worker static bool same_file(char *a, const char *b)
626*387f9dfdSAndroid Build Coastguard Worker {
627*387f9dfdSAndroid Build Coastguard Worker struct stat stat_a, stat_b;
628*387f9dfdSAndroid Build Coastguard Worker
629*387f9dfdSAndroid Build Coastguard Worker if (stat(a, &stat_a) || stat(b, &stat_b))
630*387f9dfdSAndroid Build Coastguard Worker return false;
631*387f9dfdSAndroid Build Coastguard Worker
632*387f9dfdSAndroid Build Coastguard Worker if ((stat_a.st_dev == stat_b.st_dev) &&
633*387f9dfdSAndroid Build Coastguard Worker (stat_a.st_ino == stat_b.st_ino))
634*387f9dfdSAndroid Build Coastguard Worker return true;
635*387f9dfdSAndroid Build Coastguard Worker else
636*387f9dfdSAndroid Build Coastguard Worker return false;
637*387f9dfdSAndroid Build Coastguard Worker }
638*387f9dfdSAndroid Build Coastguard Worker
try_open_debuglink_candidate(const char * path,int check_crc,int crc,struct bcc_elf_file * out)639*387f9dfdSAndroid Build Coastguard Worker static int try_open_debuglink_candidate(const char *path, int check_crc,
640*387f9dfdSAndroid Build Coastguard Worker int crc, struct bcc_elf_file *out) {
641*387f9dfdSAndroid Build Coastguard Worker if (access(path, F_OK)) {
642*387f9dfdSAndroid Build Coastguard Worker return -1;
643*387f9dfdSAndroid Build Coastguard Worker }
644*387f9dfdSAndroid Build Coastguard Worker
645*387f9dfdSAndroid Build Coastguard Worker if (check_crc && !verify_checksum(path, crc)) {
646*387f9dfdSAndroid Build Coastguard Worker return -1;
647*387f9dfdSAndroid Build Coastguard Worker }
648*387f9dfdSAndroid Build Coastguard Worker
649*387f9dfdSAndroid Build Coastguard Worker return bcc_elf_file_open(path, out);
650*387f9dfdSAndroid Build Coastguard Worker }
651*387f9dfdSAndroid Build Coastguard Worker
652*387f9dfdSAndroid Build Coastguard Worker // Returns 0 on success, otherwise nonzero.
653*387f9dfdSAndroid Build Coastguard Worker // If successfull, 'out' param is a valid bcc_elf_file.
654*387f9dfdSAndroid Build Coastguard Worker // Caller is responsible for calling bcc_elf_file_close when done using it.
655*387f9dfdSAndroid Build Coastguard Worker // See https://sourceware.org/gdb/onlinedocs/gdb/Separate-Debug-Files.html
find_debug_via_debuglink(Elf * e,const char * binpath,int check_crc,struct bcc_elf_file * out)656*387f9dfdSAndroid Build Coastguard Worker static int find_debug_via_debuglink(Elf *e, const char *binpath, int check_crc,
657*387f9dfdSAndroid Build Coastguard Worker struct bcc_elf_file *out) {
658*387f9dfdSAndroid Build Coastguard Worker char fullpath[PATH_MAX];
659*387f9dfdSAndroid Build Coastguard Worker char tmppath[PATH_MAX];
660*387f9dfdSAndroid Build Coastguard Worker char *bindir = NULL;
661*387f9dfdSAndroid Build Coastguard Worker unsigned int crc;
662*387f9dfdSAndroid Build Coastguard Worker char *name; // the name of the debuginfo file
663*387f9dfdSAndroid Build Coastguard Worker
664*387f9dfdSAndroid Build Coastguard Worker if (!find_debuglink(e, &name, &crc))
665*387f9dfdSAndroid Build Coastguard Worker return -1;
666*387f9dfdSAndroid Build Coastguard Worker
667*387f9dfdSAndroid Build Coastguard Worker strncpy(tmppath, binpath, PATH_MAX);
668*387f9dfdSAndroid Build Coastguard Worker tmppath[PATH_MAX - 1] = 0;
669*387f9dfdSAndroid Build Coastguard Worker bindir = dirname(tmppath);
670*387f9dfdSAndroid Build Coastguard Worker
671*387f9dfdSAndroid Build Coastguard Worker // Search for the file in 'binpath', but ignore the file we find if it
672*387f9dfdSAndroid Build Coastguard Worker // matches the binary itself: the binary will always be probed later on,
673*387f9dfdSAndroid Build Coastguard Worker // and it might contain poorer symbols (e.g. stripped or partial symbols)
674*387f9dfdSAndroid Build Coastguard Worker // than the external debuginfo that might be available elsewhere.
675*387f9dfdSAndroid Build Coastguard Worker snprintf(fullpath, sizeof(fullpath),"%s/%s", bindir, name);
676*387f9dfdSAndroid Build Coastguard Worker if (same_file(fullpath, binpath) != true &&
677*387f9dfdSAndroid Build Coastguard Worker try_open_debuglink_candidate(fullpath, check_crc, crc, out) == 0)
678*387f9dfdSAndroid Build Coastguard Worker return 0;
679*387f9dfdSAndroid Build Coastguard Worker
680*387f9dfdSAndroid Build Coastguard Worker // Search for the file in 'binpath'/.debug
681*387f9dfdSAndroid Build Coastguard Worker snprintf(fullpath, sizeof(fullpath), "%s/.debug/%s", bindir, name);
682*387f9dfdSAndroid Build Coastguard Worker if (try_open_debuglink_candidate(fullpath, check_crc, crc, out) == 0)
683*387f9dfdSAndroid Build Coastguard Worker return 0;
684*387f9dfdSAndroid Build Coastguard Worker
685*387f9dfdSAndroid Build Coastguard Worker // Search for the file in the global debug directory /usr/lib/debug/'binpath'
686*387f9dfdSAndroid Build Coastguard Worker snprintf(fullpath, sizeof(fullpath), "/usr/lib/debug%s/%s", bindir, name);
687*387f9dfdSAndroid Build Coastguard Worker if (try_open_debuglink_candidate(fullpath, check_crc, crc, out) == 0)
688*387f9dfdSAndroid Build Coastguard Worker return 0;
689*387f9dfdSAndroid Build Coastguard Worker
690*387f9dfdSAndroid Build Coastguard Worker return -1;
691*387f9dfdSAndroid Build Coastguard Worker }
692*387f9dfdSAndroid Build Coastguard Worker
693*387f9dfdSAndroid Build Coastguard Worker // Returns 0 on success, otherwise nonzero.
694*387f9dfdSAndroid Build Coastguard Worker // If successfull, 'out' param is a valid bcc_elf_file.
695*387f9dfdSAndroid Build Coastguard Worker // Caller is responsible for calling bcc_elf_file_close when done using it.
696*387f9dfdSAndroid Build Coastguard Worker // See https://sourceware.org/gdb/onlinedocs/gdb/Separate-Debug-Files.html
find_debug_via_buildid(Elf * e,struct bcc_elf_file * out)697*387f9dfdSAndroid Build Coastguard Worker static int find_debug_via_buildid(Elf *e, struct bcc_elf_file *out) {
698*387f9dfdSAndroid Build Coastguard Worker char fullpath[PATH_MAX];
699*387f9dfdSAndroid Build Coastguard Worker char buildid[128]; // currently 40 seems to be default, let's be safe
700*387f9dfdSAndroid Build Coastguard Worker
701*387f9dfdSAndroid Build Coastguard Worker if (!find_buildid(e, buildid))
702*387f9dfdSAndroid Build Coastguard Worker return -1;
703*387f9dfdSAndroid Build Coastguard Worker
704*387f9dfdSAndroid Build Coastguard Worker // Search for the file in the global debug directory with a sub-path:
705*387f9dfdSAndroid Build Coastguard Worker // mm/nnnnnn...nnnn.debug
706*387f9dfdSAndroid Build Coastguard Worker // Where mm are the first two characters of the buildid, and nnnn are the
707*387f9dfdSAndroid Build Coastguard Worker // rest of the build id, followed by .debug.
708*387f9dfdSAndroid Build Coastguard Worker const char *bcc_debuginfo_root = getenv("BCC_DEBUGINFO_ROOT");
709*387f9dfdSAndroid Build Coastguard Worker if (bcc_debuginfo_root == NULL)
710*387f9dfdSAndroid Build Coastguard Worker bcc_debuginfo_root = "/usr/lib/debug";
711*387f9dfdSAndroid Build Coastguard Worker snprintf(fullpath, sizeof(fullpath), "%s/.build-id/%c%c/%s.debug",
712*387f9dfdSAndroid Build Coastguard Worker bcc_debuginfo_root, buildid[0], buildid[1], buildid + 2);
713*387f9dfdSAndroid Build Coastguard Worker return bcc_elf_file_open(fullpath, out);
714*387f9dfdSAndroid Build Coastguard Worker }
715*387f9dfdSAndroid Build Coastguard Worker
716*387f9dfdSAndroid Build Coastguard Worker // Returns 0 on success, otherwise nonzero.
717*387f9dfdSAndroid Build Coastguard Worker // If successfull, 'out' param is a valid bcc_elf_file.
718*387f9dfdSAndroid Build Coastguard Worker // Caller is responsible for calling bcc_elf_file_close when done using it.
719*387f9dfdSAndroid Build Coastguard Worker // See
720*387f9dfdSAndroid Build Coastguard Worker // https://github.com/torvalds/linux/blob/v5.2/tools/perf/Documentation/perf-report.txt#L325
find_debug_via_symfs(Elf * e,const char * path,struct bcc_elf_file * out)721*387f9dfdSAndroid Build Coastguard Worker static int find_debug_via_symfs(Elf *e, const char *path,
722*387f9dfdSAndroid Build Coastguard Worker struct bcc_elf_file *out) {
723*387f9dfdSAndroid Build Coastguard Worker char fullpath[PATH_MAX];
724*387f9dfdSAndroid Build Coastguard Worker char buildid[128];
725*387f9dfdSAndroid Build Coastguard Worker char symfs_buildid[128];
726*387f9dfdSAndroid Build Coastguard Worker int check_build_id;
727*387f9dfdSAndroid Build Coastguard Worker char *symfs;
728*387f9dfdSAndroid Build Coastguard Worker struct bcc_elf_file symfs_elf_file;
729*387f9dfdSAndroid Build Coastguard Worker bcc_elf_file_init(&symfs_elf_file);
730*387f9dfdSAndroid Build Coastguard Worker
731*387f9dfdSAndroid Build Coastguard Worker symfs = getenv("BCC_SYMFS");
732*387f9dfdSAndroid Build Coastguard Worker if (!symfs || !*symfs)
733*387f9dfdSAndroid Build Coastguard Worker goto fail;
734*387f9dfdSAndroid Build Coastguard Worker
735*387f9dfdSAndroid Build Coastguard Worker check_build_id = find_buildid(e, buildid);
736*387f9dfdSAndroid Build Coastguard Worker
737*387f9dfdSAndroid Build Coastguard Worker int ns_prefix_length = 0;
738*387f9dfdSAndroid Build Coastguard Worker sscanf(path, "/proc/%*u/root/%n", &ns_prefix_length);
739*387f9dfdSAndroid Build Coastguard Worker path += ns_prefix_length;
740*387f9dfdSAndroid Build Coastguard Worker
741*387f9dfdSAndroid Build Coastguard Worker snprintf(fullpath, sizeof(fullpath), "%s/%s", symfs, path);
742*387f9dfdSAndroid Build Coastguard Worker if (access(fullpath, F_OK) == -1)
743*387f9dfdSAndroid Build Coastguard Worker goto fail;
744*387f9dfdSAndroid Build Coastguard Worker
745*387f9dfdSAndroid Build Coastguard Worker if (bcc_elf_file_open(fullpath, &symfs_elf_file) < 0) {
746*387f9dfdSAndroid Build Coastguard Worker goto fail;
747*387f9dfdSAndroid Build Coastguard Worker }
748*387f9dfdSAndroid Build Coastguard Worker
749*387f9dfdSAndroid Build Coastguard Worker if (check_build_id) {
750*387f9dfdSAndroid Build Coastguard Worker if (!find_buildid(symfs_elf_file.elf, symfs_buildid))
751*387f9dfdSAndroid Build Coastguard Worker goto fail;
752*387f9dfdSAndroid Build Coastguard Worker
753*387f9dfdSAndroid Build Coastguard Worker if (strncmp(buildid, symfs_buildid, sizeof(buildid)))
754*387f9dfdSAndroid Build Coastguard Worker goto fail;
755*387f9dfdSAndroid Build Coastguard Worker }
756*387f9dfdSAndroid Build Coastguard Worker
757*387f9dfdSAndroid Build Coastguard Worker *out = symfs_elf_file;
758*387f9dfdSAndroid Build Coastguard Worker return 0;
759*387f9dfdSAndroid Build Coastguard Worker
760*387f9dfdSAndroid Build Coastguard Worker fail:
761*387f9dfdSAndroid Build Coastguard Worker bcc_elf_file_close(&symfs_elf_file);
762*387f9dfdSAndroid Build Coastguard Worker return -1;
763*387f9dfdSAndroid Build Coastguard Worker }
764*387f9dfdSAndroid Build Coastguard Worker
765*387f9dfdSAndroid Build Coastguard Worker #ifdef HAVE_LIBLZMA
766*387f9dfdSAndroid Build Coastguard Worker
767*387f9dfdSAndroid Build Coastguard Worker #define LZMA_MIN_BUFFER_SIZE 4096
768*387f9dfdSAndroid Build Coastguard Worker #define LZMA_MEMLIMIT (128 * 1024 * 1024)
open_mini_debug_info_file(void * gnu_debugdata,size_t gnu_debugdata_size,struct bcc_elf_file * out)769*387f9dfdSAndroid Build Coastguard Worker static int open_mini_debug_info_file(void *gnu_debugdata,
770*387f9dfdSAndroid Build Coastguard Worker size_t gnu_debugdata_size,
771*387f9dfdSAndroid Build Coastguard Worker struct bcc_elf_file *out) {
772*387f9dfdSAndroid Build Coastguard Worker void *decompressed = NULL;
773*387f9dfdSAndroid Build Coastguard Worker void *new_decompressed = NULL;
774*387f9dfdSAndroid Build Coastguard Worker size_t decompressed_data_size = 0;
775*387f9dfdSAndroid Build Coastguard Worker size_t decompressed_buffer_size = 0;
776*387f9dfdSAndroid Build Coastguard Worker lzma_stream stream = LZMA_STREAM_INIT;
777*387f9dfdSAndroid Build Coastguard Worker lzma_ret ret;
778*387f9dfdSAndroid Build Coastguard Worker
779*387f9dfdSAndroid Build Coastguard Worker ret = lzma_stream_decoder(&stream, LZMA_MEMLIMIT, 0);
780*387f9dfdSAndroid Build Coastguard Worker if (ret != LZMA_OK)
781*387f9dfdSAndroid Build Coastguard Worker return -1;
782*387f9dfdSAndroid Build Coastguard Worker
783*387f9dfdSAndroid Build Coastguard Worker stream.next_in = gnu_debugdata;
784*387f9dfdSAndroid Build Coastguard Worker stream.avail_in = gnu_debugdata_size;
785*387f9dfdSAndroid Build Coastguard Worker stream.avail_out = 0;
786*387f9dfdSAndroid Build Coastguard Worker
787*387f9dfdSAndroid Build Coastguard Worker while (ret == LZMA_OK && stream.avail_in > 0) {
788*387f9dfdSAndroid Build Coastguard Worker if (stream.avail_out < LZMA_MIN_BUFFER_SIZE) {
789*387f9dfdSAndroid Build Coastguard Worker decompressed_buffer_size += LZMA_MIN_BUFFER_SIZE;
790*387f9dfdSAndroid Build Coastguard Worker new_decompressed = realloc(decompressed, decompressed_buffer_size);
791*387f9dfdSAndroid Build Coastguard Worker if (new_decompressed == NULL) {
792*387f9dfdSAndroid Build Coastguard Worker ret = LZMA_MEM_ERROR;
793*387f9dfdSAndroid Build Coastguard Worker break;
794*387f9dfdSAndroid Build Coastguard Worker }
795*387f9dfdSAndroid Build Coastguard Worker
796*387f9dfdSAndroid Build Coastguard Worker decompressed = new_decompressed;
797*387f9dfdSAndroid Build Coastguard Worker stream.avail_out += LZMA_MIN_BUFFER_SIZE;
798*387f9dfdSAndroid Build Coastguard Worker stream.next_out = decompressed + decompressed_data_size;
799*387f9dfdSAndroid Build Coastguard Worker }
800*387f9dfdSAndroid Build Coastguard Worker ret = lzma_code(&stream, LZMA_FINISH);
801*387f9dfdSAndroid Build Coastguard Worker decompressed_data_size = decompressed_buffer_size - stream.avail_out;
802*387f9dfdSAndroid Build Coastguard Worker }
803*387f9dfdSAndroid Build Coastguard Worker lzma_end(&stream);
804*387f9dfdSAndroid Build Coastguard Worker
805*387f9dfdSAndroid Build Coastguard Worker if (ret != LZMA_STREAM_END ||
806*387f9dfdSAndroid Build Coastguard Worker bcc_elf_file_open_buf(decompressed, decompressed_data_size, out)) {
807*387f9dfdSAndroid Build Coastguard Worker free(decompressed);
808*387f9dfdSAndroid Build Coastguard Worker return -1;
809*387f9dfdSAndroid Build Coastguard Worker }
810*387f9dfdSAndroid Build Coastguard Worker
811*387f9dfdSAndroid Build Coastguard Worker return 0;
812*387f9dfdSAndroid Build Coastguard Worker }
813*387f9dfdSAndroid Build Coastguard Worker
814*387f9dfdSAndroid Build Coastguard Worker // Returns 0 on success, otherwise nonzero.
815*387f9dfdSAndroid Build Coastguard Worker // If successfull, 'out' param is a valid bcc_elf_file.
816*387f9dfdSAndroid Build Coastguard Worker // Caller is responsible for calling bcc_elf_file_close when done using it.
817*387f9dfdSAndroid Build Coastguard Worker // See https://sourceware.org/gdb/onlinedocs/gdb/MiniDebugInfo.html
find_debug_via_mini_debug_info(Elf * elf,struct bcc_elf_file * out)818*387f9dfdSAndroid Build Coastguard Worker static int find_debug_via_mini_debug_info(Elf *elf, struct bcc_elf_file *out) {
819*387f9dfdSAndroid Build Coastguard Worker Elf_Data *gnu_debugdata;
820*387f9dfdSAndroid Build Coastguard Worker
821*387f9dfdSAndroid Build Coastguard Worker gnu_debugdata = get_section_elf_data(elf, ".gnu_debugdata");
822*387f9dfdSAndroid Build Coastguard Worker if (gnu_debugdata == NULL)
823*387f9dfdSAndroid Build Coastguard Worker return -1;
824*387f9dfdSAndroid Build Coastguard Worker
825*387f9dfdSAndroid Build Coastguard Worker return open_mini_debug_info_file(gnu_debugdata->d_buf, gnu_debugdata->d_size,
826*387f9dfdSAndroid Build Coastguard Worker out);
827*387f9dfdSAndroid Build Coastguard Worker }
828*387f9dfdSAndroid Build Coastguard Worker #endif
829*387f9dfdSAndroid Build Coastguard Worker
830*387f9dfdSAndroid Build Coastguard Worker #ifdef HAVE_LIBDEBUGINFOD
831*387f9dfdSAndroid Build Coastguard Worker
832*387f9dfdSAndroid Build Coastguard Worker // Returns 0 on success, otherwise nonzero.
833*387f9dfdSAndroid Build Coastguard Worker // If successfull, 'out' param is a valid bcc_elf_file.
834*387f9dfdSAndroid Build Coastguard Worker // Caller is responsible for calling bcc_elf_file_close when done using it.
835*387f9dfdSAndroid Build Coastguard Worker // See https://sourceware.org/elfutils/Debuginfod.html
find_debug_via_debuginfod(Elf * e,struct bcc_elf_file * out)836*387f9dfdSAndroid Build Coastguard Worker static int find_debug_via_debuginfod(Elf *e, struct bcc_elf_file *out) {
837*387f9dfdSAndroid Build Coastguard Worker char buildid[128];
838*387f9dfdSAndroid Build Coastguard Worker int fd = -1;
839*387f9dfdSAndroid Build Coastguard Worker
840*387f9dfdSAndroid Build Coastguard Worker if (!find_buildid(e, buildid))
841*387f9dfdSAndroid Build Coastguard Worker return -1;
842*387f9dfdSAndroid Build Coastguard Worker
843*387f9dfdSAndroid Build Coastguard Worker debuginfod_client *client = debuginfod_begin();
844*387f9dfdSAndroid Build Coastguard Worker if (!client)
845*387f9dfdSAndroid Build Coastguard Worker return -1;
846*387f9dfdSAndroid Build Coastguard Worker
847*387f9dfdSAndroid Build Coastguard Worker // In case of an error, the function returns a negative error code.
848*387f9dfdSAndroid Build Coastguard Worker fd = debuginfod_find_debuginfo(client, (const unsigned char *)buildid, 0,
849*387f9dfdSAndroid Build Coastguard Worker NULL);
850*387f9dfdSAndroid Build Coastguard Worker if (fd >= 0) {
851*387f9dfdSAndroid Build Coastguard Worker if (bcc_elf_file_open_fd(fd, out)) {
852*387f9dfdSAndroid Build Coastguard Worker close(fd);
853*387f9dfdSAndroid Build Coastguard Worker fd = -1;
854*387f9dfdSAndroid Build Coastguard Worker }
855*387f9dfdSAndroid Build Coastguard Worker }
856*387f9dfdSAndroid Build Coastguard Worker
857*387f9dfdSAndroid Build Coastguard Worker debuginfod_end(client);
858*387f9dfdSAndroid Build Coastguard Worker return fd >= 0 ? 0 : -1;
859*387f9dfdSAndroid Build Coastguard Worker }
860*387f9dfdSAndroid Build Coastguard Worker #endif
861*387f9dfdSAndroid Build Coastguard Worker
862*387f9dfdSAndroid Build Coastguard Worker // Returns 0 on success, otherwise nonzero.
863*387f9dfdSAndroid Build Coastguard Worker // If successfull, 'out' param is a valid bcc_elf_file.
864*387f9dfdSAndroid Build Coastguard Worker // Caller is responsible for calling bcc_elf_file_close when done using it.
find_debug_file(Elf * e,const char * path,int check_crc,struct bcc_elf_file * out)865*387f9dfdSAndroid Build Coastguard Worker static int find_debug_file(Elf *e, const char *path, int check_crc,
866*387f9dfdSAndroid Build Coastguard Worker struct bcc_elf_file *out) {
867*387f9dfdSAndroid Build Coastguard Worker if (find_debug_via_symfs(e, path, out) == 0)
868*387f9dfdSAndroid Build Coastguard Worker return 0;
869*387f9dfdSAndroid Build Coastguard Worker
870*387f9dfdSAndroid Build Coastguard Worker if (find_debug_via_buildid(e, out) == 0)
871*387f9dfdSAndroid Build Coastguard Worker return 0;
872*387f9dfdSAndroid Build Coastguard Worker
873*387f9dfdSAndroid Build Coastguard Worker if (find_debug_via_debuglink(e, path, check_crc, out) == 0)
874*387f9dfdSAndroid Build Coastguard Worker return 0;
875*387f9dfdSAndroid Build Coastguard Worker
876*387f9dfdSAndroid Build Coastguard Worker #ifdef HAVE_LIBLZMA
877*387f9dfdSAndroid Build Coastguard Worker if (find_debug_via_mini_debug_info(e, out) == 0)
878*387f9dfdSAndroid Build Coastguard Worker return 0;
879*387f9dfdSAndroid Build Coastguard Worker #endif
880*387f9dfdSAndroid Build Coastguard Worker
881*387f9dfdSAndroid Build Coastguard Worker #ifdef HAVE_LIBDEBUGINFOD
882*387f9dfdSAndroid Build Coastguard Worker if (find_debug_via_debuginfod(e, out) == 0)
883*387f9dfdSAndroid Build Coastguard Worker return 0;
884*387f9dfdSAndroid Build Coastguard Worker #endif
885*387f9dfdSAndroid Build Coastguard Worker
886*387f9dfdSAndroid Build Coastguard Worker return -1;
887*387f9dfdSAndroid Build Coastguard Worker }
888*387f9dfdSAndroid Build Coastguard Worker
foreach_sym_core(const char * path,bcc_elf_symcb callback,bcc_elf_symcb_lazy callback_lazy,struct bcc_symbol_option * option,void * payload)889*387f9dfdSAndroid Build Coastguard Worker static int foreach_sym_core(const char *path, bcc_elf_symcb callback,
890*387f9dfdSAndroid Build Coastguard Worker bcc_elf_symcb_lazy callback_lazy,
891*387f9dfdSAndroid Build Coastguard Worker struct bcc_symbol_option *option, void *payload) {
892*387f9dfdSAndroid Build Coastguard Worker struct bcc_elf_file elf_file;
893*387f9dfdSAndroid Build Coastguard Worker bcc_elf_file_init(&elf_file);
894*387f9dfdSAndroid Build Coastguard Worker struct bcc_elf_file debug_elf_file;
895*387f9dfdSAndroid Build Coastguard Worker bcc_elf_file_init(&debug_elf_file);
896*387f9dfdSAndroid Build Coastguard Worker int res;
897*387f9dfdSAndroid Build Coastguard Worker
898*387f9dfdSAndroid Build Coastguard Worker if (!option)
899*387f9dfdSAndroid Build Coastguard Worker return -1;
900*387f9dfdSAndroid Build Coastguard Worker
901*387f9dfdSAndroid Build Coastguard Worker if (bcc_elf_file_open(path, &elf_file) < 0)
902*387f9dfdSAndroid Build Coastguard Worker return -1;
903*387f9dfdSAndroid Build Coastguard Worker
904*387f9dfdSAndroid Build Coastguard Worker if (option->use_debug_file) {
905*387f9dfdSAndroid Build Coastguard Worker if (find_debug_file(elf_file.elf, path, option->check_debug_file_crc,
906*387f9dfdSAndroid Build Coastguard Worker &debug_elf_file) == 0) {
907*387f9dfdSAndroid Build Coastguard Worker listsymbols(debug_elf_file.elf, callback, callback_lazy, payload, option,
908*387f9dfdSAndroid Build Coastguard Worker 1);
909*387f9dfdSAndroid Build Coastguard Worker bcc_elf_file_close(&debug_elf_file);
910*387f9dfdSAndroid Build Coastguard Worker }
911*387f9dfdSAndroid Build Coastguard Worker }
912*387f9dfdSAndroid Build Coastguard Worker
913*387f9dfdSAndroid Build Coastguard Worker res = listsymbols(elf_file.elf, callback, callback_lazy, payload, option, 0);
914*387f9dfdSAndroid Build Coastguard Worker bcc_elf_file_close(&elf_file);
915*387f9dfdSAndroid Build Coastguard Worker return res;
916*387f9dfdSAndroid Build Coastguard Worker }
917*387f9dfdSAndroid Build Coastguard Worker
bcc_elf_foreach_sym(const char * path,bcc_elf_symcb callback,void * option,void * payload)918*387f9dfdSAndroid Build Coastguard Worker int bcc_elf_foreach_sym(const char *path, bcc_elf_symcb callback,
919*387f9dfdSAndroid Build Coastguard Worker void *option, void *payload) {
920*387f9dfdSAndroid Build Coastguard Worker struct bcc_symbol_option *o = option;
921*387f9dfdSAndroid Build Coastguard Worker o->lazy_symbolize = 0;
922*387f9dfdSAndroid Build Coastguard Worker return foreach_sym_core(path, callback, NULL, o, payload);
923*387f9dfdSAndroid Build Coastguard Worker }
924*387f9dfdSAndroid Build Coastguard Worker
bcc_elf_foreach_sym_lazy(const char * path,bcc_elf_symcb_lazy callback,void * option,void * payload)925*387f9dfdSAndroid Build Coastguard Worker int bcc_elf_foreach_sym_lazy(const char *path, bcc_elf_symcb_lazy callback,
926*387f9dfdSAndroid Build Coastguard Worker void *option, void *payload) {
927*387f9dfdSAndroid Build Coastguard Worker struct bcc_symbol_option *o = option;
928*387f9dfdSAndroid Build Coastguard Worker o->lazy_symbolize = 1;
929*387f9dfdSAndroid Build Coastguard Worker return foreach_sym_core(path, NULL, callback, o, payload);
930*387f9dfdSAndroid Build Coastguard Worker }
931*387f9dfdSAndroid Build Coastguard Worker
bcc_elf_get_text_scn_info(const char * path,uint64_t * addr,uint64_t * offset)932*387f9dfdSAndroid Build Coastguard Worker int bcc_elf_get_text_scn_info(const char *path, uint64_t *addr,
933*387f9dfdSAndroid Build Coastguard Worker uint64_t *offset) {
934*387f9dfdSAndroid Build Coastguard Worker int err;
935*387f9dfdSAndroid Build Coastguard Worker Elf_Scn *section = NULL;
936*387f9dfdSAndroid Build Coastguard Worker GElf_Shdr header;
937*387f9dfdSAndroid Build Coastguard Worker size_t stridx;
938*387f9dfdSAndroid Build Coastguard Worker char *name;
939*387f9dfdSAndroid Build Coastguard Worker struct bcc_elf_file elf_file;
940*387f9dfdSAndroid Build Coastguard Worker bcc_elf_file_init(&elf_file);
941*387f9dfdSAndroid Build Coastguard Worker
942*387f9dfdSAndroid Build Coastguard Worker if ((err = bcc_elf_file_open(path, &elf_file)) < 0 ||
943*387f9dfdSAndroid Build Coastguard Worker (err = elf_getshdrstrndx(elf_file.elf, &stridx)) < 0)
944*387f9dfdSAndroid Build Coastguard Worker goto exit;
945*387f9dfdSAndroid Build Coastguard Worker
946*387f9dfdSAndroid Build Coastguard Worker err = -1;
947*387f9dfdSAndroid Build Coastguard Worker while ((section = elf_nextscn(elf_file.elf, section)) != 0) {
948*387f9dfdSAndroid Build Coastguard Worker if (!gelf_getshdr(section, &header))
949*387f9dfdSAndroid Build Coastguard Worker continue;
950*387f9dfdSAndroid Build Coastguard Worker
951*387f9dfdSAndroid Build Coastguard Worker name = elf_strptr(elf_file.elf, stridx, header.sh_name);
952*387f9dfdSAndroid Build Coastguard Worker if (name && !strcmp(name, ".text")) {
953*387f9dfdSAndroid Build Coastguard Worker *addr = (uint64_t)header.sh_addr;
954*387f9dfdSAndroid Build Coastguard Worker *offset = (uint64_t)header.sh_offset;
955*387f9dfdSAndroid Build Coastguard Worker err = 0;
956*387f9dfdSAndroid Build Coastguard Worker break;
957*387f9dfdSAndroid Build Coastguard Worker }
958*387f9dfdSAndroid Build Coastguard Worker }
959*387f9dfdSAndroid Build Coastguard Worker
960*387f9dfdSAndroid Build Coastguard Worker exit:
961*387f9dfdSAndroid Build Coastguard Worker bcc_elf_file_close(&elf_file);
962*387f9dfdSAndroid Build Coastguard Worker return err;
963*387f9dfdSAndroid Build Coastguard Worker }
964*387f9dfdSAndroid Build Coastguard Worker
bcc_elf_foreach_load_section(const char * path,bcc_elf_load_sectioncb callback,void * payload)965*387f9dfdSAndroid Build Coastguard Worker int bcc_elf_foreach_load_section(const char *path,
966*387f9dfdSAndroid Build Coastguard Worker bcc_elf_load_sectioncb callback,
967*387f9dfdSAndroid Build Coastguard Worker void *payload) {
968*387f9dfdSAndroid Build Coastguard Worker int err = -1, res;
969*387f9dfdSAndroid Build Coastguard Worker size_t nhdrs, i;
970*387f9dfdSAndroid Build Coastguard Worker struct bcc_elf_file elf_file;
971*387f9dfdSAndroid Build Coastguard Worker bcc_elf_file_init(&elf_file);
972*387f9dfdSAndroid Build Coastguard Worker
973*387f9dfdSAndroid Build Coastguard Worker if (bcc_elf_file_open(path, &elf_file) < 0)
974*387f9dfdSAndroid Build Coastguard Worker goto exit;
975*387f9dfdSAndroid Build Coastguard Worker
976*387f9dfdSAndroid Build Coastguard Worker if (elf_getphdrnum(elf_file.elf, &nhdrs) != 0)
977*387f9dfdSAndroid Build Coastguard Worker goto exit;
978*387f9dfdSAndroid Build Coastguard Worker
979*387f9dfdSAndroid Build Coastguard Worker GElf_Phdr header;
980*387f9dfdSAndroid Build Coastguard Worker for (i = 0; i < nhdrs; i++) {
981*387f9dfdSAndroid Build Coastguard Worker if (!gelf_getphdr(elf_file.elf, (int)i, &header))
982*387f9dfdSAndroid Build Coastguard Worker continue;
983*387f9dfdSAndroid Build Coastguard Worker if (header.p_type != PT_LOAD || !(header.p_flags & PF_X))
984*387f9dfdSAndroid Build Coastguard Worker continue;
985*387f9dfdSAndroid Build Coastguard Worker res = callback(header.p_vaddr, header.p_memsz, header.p_offset, payload);
986*387f9dfdSAndroid Build Coastguard Worker if (res < 0) {
987*387f9dfdSAndroid Build Coastguard Worker err = 1;
988*387f9dfdSAndroid Build Coastguard Worker goto exit;
989*387f9dfdSAndroid Build Coastguard Worker }
990*387f9dfdSAndroid Build Coastguard Worker }
991*387f9dfdSAndroid Build Coastguard Worker err = 0;
992*387f9dfdSAndroid Build Coastguard Worker
993*387f9dfdSAndroid Build Coastguard Worker exit:
994*387f9dfdSAndroid Build Coastguard Worker bcc_elf_file_close(&elf_file);
995*387f9dfdSAndroid Build Coastguard Worker return err;
996*387f9dfdSAndroid Build Coastguard Worker }
997*387f9dfdSAndroid Build Coastguard Worker
bcc_elf_get_type(const char * path)998*387f9dfdSAndroid Build Coastguard Worker int bcc_elf_get_type(const char *path) {
999*387f9dfdSAndroid Build Coastguard Worker GElf_Ehdr hdr;
1000*387f9dfdSAndroid Build Coastguard Worker void* res = NULL;
1001*387f9dfdSAndroid Build Coastguard Worker struct bcc_elf_file elf_file;
1002*387f9dfdSAndroid Build Coastguard Worker bcc_elf_file_init(&elf_file);
1003*387f9dfdSAndroid Build Coastguard Worker
1004*387f9dfdSAndroid Build Coastguard Worker if (bcc_elf_file_open(path, &elf_file) < 0)
1005*387f9dfdSAndroid Build Coastguard Worker return -1;
1006*387f9dfdSAndroid Build Coastguard Worker
1007*387f9dfdSAndroid Build Coastguard Worker res = (void *)gelf_getehdr(elf_file.elf, &hdr);
1008*387f9dfdSAndroid Build Coastguard Worker bcc_elf_file_close(&elf_file);
1009*387f9dfdSAndroid Build Coastguard Worker
1010*387f9dfdSAndroid Build Coastguard Worker if (!res)
1011*387f9dfdSAndroid Build Coastguard Worker return -1;
1012*387f9dfdSAndroid Build Coastguard Worker else
1013*387f9dfdSAndroid Build Coastguard Worker return hdr.e_type;
1014*387f9dfdSAndroid Build Coastguard Worker }
1015*387f9dfdSAndroid Build Coastguard Worker
bcc_elf_is_exe(const char * path)1016*387f9dfdSAndroid Build Coastguard Worker int bcc_elf_is_exe(const char *path) {
1017*387f9dfdSAndroid Build Coastguard Worker return (bcc_elf_get_type(path) != -1) && (access(path, X_OK) == 0);
1018*387f9dfdSAndroid Build Coastguard Worker }
1019*387f9dfdSAndroid Build Coastguard Worker
bcc_elf_is_shared_obj(const char * path)1020*387f9dfdSAndroid Build Coastguard Worker int bcc_elf_is_shared_obj(const char *path) {
1021*387f9dfdSAndroid Build Coastguard Worker return bcc_elf_get_type(path) == ET_DYN;
1022*387f9dfdSAndroid Build Coastguard Worker }
1023*387f9dfdSAndroid Build Coastguard Worker
bcc_elf_is_vdso(const char * name)1024*387f9dfdSAndroid Build Coastguard Worker int bcc_elf_is_vdso(const char *name) {
1025*387f9dfdSAndroid Build Coastguard Worker return strcmp(name, "[vdso]") == 0;
1026*387f9dfdSAndroid Build Coastguard Worker }
1027*387f9dfdSAndroid Build Coastguard Worker
1028*387f9dfdSAndroid Build Coastguard Worker // -2: Failed
1029*387f9dfdSAndroid Build Coastguard Worker // -1: Not initialized
1030*387f9dfdSAndroid Build Coastguard Worker // >0: Initialized
1031*387f9dfdSAndroid Build Coastguard Worker static int vdso_image_fd = -1;
1032*387f9dfdSAndroid Build Coastguard Worker
find_vdso(struct mod_info * info,int enter_ns,void * payload)1033*387f9dfdSAndroid Build Coastguard Worker static int find_vdso(struct mod_info *info, int enter_ns, void *payload) {
1034*387f9dfdSAndroid Build Coastguard Worker int fd;
1035*387f9dfdSAndroid Build Coastguard Worker char tmpfile[128];
1036*387f9dfdSAndroid Build Coastguard Worker if (!bcc_elf_is_vdso(info->name))
1037*387f9dfdSAndroid Build Coastguard Worker return 0;
1038*387f9dfdSAndroid Build Coastguard Worker
1039*387f9dfdSAndroid Build Coastguard Worker uint64_t sz = info->end_addr - info->start_addr;
1040*387f9dfdSAndroid Build Coastguard Worker void *image = malloc(sz);
1041*387f9dfdSAndroid Build Coastguard Worker if (!image)
1042*387f9dfdSAndroid Build Coastguard Worker goto on_error;
1043*387f9dfdSAndroid Build Coastguard Worker memcpy(image, (void *)info->start_addr, sz);
1044*387f9dfdSAndroid Build Coastguard Worker
1045*387f9dfdSAndroid Build Coastguard Worker snprintf(tmpfile, sizeof(tmpfile), "/tmp/bcc_%d_vdso_image_XXXXXX", getpid());
1046*387f9dfdSAndroid Build Coastguard Worker fd = mkostemp(tmpfile, O_CLOEXEC);
1047*387f9dfdSAndroid Build Coastguard Worker if (fd < 0) {
1048*387f9dfdSAndroid Build Coastguard Worker fprintf(stderr, "Unable to create temp file: %s\n", strerror(errno));
1049*387f9dfdSAndroid Build Coastguard Worker goto on_error;
1050*387f9dfdSAndroid Build Coastguard Worker }
1051*387f9dfdSAndroid Build Coastguard Worker // Unlink the file to avoid leaking
1052*387f9dfdSAndroid Build Coastguard Worker if (unlink(tmpfile) == -1)
1053*387f9dfdSAndroid Build Coastguard Worker fprintf(stderr, "Unlink %s failed: %s\n", tmpfile, strerror(errno));
1054*387f9dfdSAndroid Build Coastguard Worker
1055*387f9dfdSAndroid Build Coastguard Worker if (write(fd, image, sz) == -1) {
1056*387f9dfdSAndroid Build Coastguard Worker fprintf(stderr, "Failed to write to vDSO image: %s\n", strerror(errno));
1057*387f9dfdSAndroid Build Coastguard Worker close(fd);
1058*387f9dfdSAndroid Build Coastguard Worker goto on_error;
1059*387f9dfdSAndroid Build Coastguard Worker }
1060*387f9dfdSAndroid Build Coastguard Worker vdso_image_fd = fd;
1061*387f9dfdSAndroid Build Coastguard Worker
1062*387f9dfdSAndroid Build Coastguard Worker on_error:
1063*387f9dfdSAndroid Build Coastguard Worker if (image)
1064*387f9dfdSAndroid Build Coastguard Worker free(image);
1065*387f9dfdSAndroid Build Coastguard Worker // Always stop the iteration
1066*387f9dfdSAndroid Build Coastguard Worker return -1;
1067*387f9dfdSAndroid Build Coastguard Worker }
1068*387f9dfdSAndroid Build Coastguard Worker
bcc_elf_foreach_vdso_sym(bcc_elf_symcb callback,void * payload)1069*387f9dfdSAndroid Build Coastguard Worker int bcc_elf_foreach_vdso_sym(bcc_elf_symcb callback, void *payload) {
1070*387f9dfdSAndroid Build Coastguard Worker Elf *elf;
1071*387f9dfdSAndroid Build Coastguard Worker static struct bcc_symbol_option default_option = {
1072*387f9dfdSAndroid Build Coastguard Worker .use_debug_file = 0,
1073*387f9dfdSAndroid Build Coastguard Worker .check_debug_file_crc = 0,
1074*387f9dfdSAndroid Build Coastguard Worker .use_symbol_type = (1 << STT_FUNC) | (1 << STT_GNU_IFUNC)
1075*387f9dfdSAndroid Build Coastguard Worker };
1076*387f9dfdSAndroid Build Coastguard Worker
1077*387f9dfdSAndroid Build Coastguard Worker if (vdso_image_fd == -1) {
1078*387f9dfdSAndroid Build Coastguard Worker vdso_image_fd = -2;
1079*387f9dfdSAndroid Build Coastguard Worker bcc_procutils_each_module(getpid(), &find_vdso, NULL);
1080*387f9dfdSAndroid Build Coastguard Worker }
1081*387f9dfdSAndroid Build Coastguard Worker if (vdso_image_fd == -2)
1082*387f9dfdSAndroid Build Coastguard Worker return -1;
1083*387f9dfdSAndroid Build Coastguard Worker
1084*387f9dfdSAndroid Build Coastguard Worker if (openelf_fd(vdso_image_fd, &elf) == -1)
1085*387f9dfdSAndroid Build Coastguard Worker return -1;
1086*387f9dfdSAndroid Build Coastguard Worker
1087*387f9dfdSAndroid Build Coastguard Worker int rc = listsymbols(elf, callback, NULL, payload, &default_option, 0);
1088*387f9dfdSAndroid Build Coastguard Worker elf_end(elf);
1089*387f9dfdSAndroid Build Coastguard Worker return rc;
1090*387f9dfdSAndroid Build Coastguard Worker }
1091*387f9dfdSAndroid Build Coastguard Worker
1092*387f9dfdSAndroid Build Coastguard Worker // return value: 0 : success
1093*387f9dfdSAndroid Build Coastguard Worker // < 0 : error and no bcc lib found
1094*387f9dfdSAndroid Build Coastguard Worker // > 0 : error and bcc lib found
bcc_free_memory_with_file(const char * path)1095*387f9dfdSAndroid Build Coastguard Worker static int bcc_free_memory_with_file(const char *path) {
1096*387f9dfdSAndroid Build Coastguard Worker unsigned long sym_addr = 0, sym_shndx;
1097*387f9dfdSAndroid Build Coastguard Worker Elf_Scn *section = NULL;
1098*387f9dfdSAndroid Build Coastguard Worker int err;
1099*387f9dfdSAndroid Build Coastguard Worker GElf_Shdr header;
1100*387f9dfdSAndroid Build Coastguard Worker struct bcc_elf_file elf_file;
1101*387f9dfdSAndroid Build Coastguard Worker bcc_elf_file_init(&elf_file);
1102*387f9dfdSAndroid Build Coastguard Worker
1103*387f9dfdSAndroid Build Coastguard Worker if ((err = bcc_elf_file_open(path, &elf_file)) < 0)
1104*387f9dfdSAndroid Build Coastguard Worker goto exit;
1105*387f9dfdSAndroid Build Coastguard Worker
1106*387f9dfdSAndroid Build Coastguard Worker // get symbol address of "bcc_free_memory", which
1107*387f9dfdSAndroid Build Coastguard Worker // will be used to calculate runtime .text address
1108*387f9dfdSAndroid Build Coastguard Worker // range, esp. for shared libraries.
1109*387f9dfdSAndroid Build Coastguard Worker err = -1;
1110*387f9dfdSAndroid Build Coastguard Worker while ((section = elf_nextscn(elf_file.elf, section)) != 0) {
1111*387f9dfdSAndroid Build Coastguard Worker Elf_Data *data = NULL;
1112*387f9dfdSAndroid Build Coastguard Worker size_t symsize;
1113*387f9dfdSAndroid Build Coastguard Worker
1114*387f9dfdSAndroid Build Coastguard Worker if (!gelf_getshdr(section, &header))
1115*387f9dfdSAndroid Build Coastguard Worker continue;
1116*387f9dfdSAndroid Build Coastguard Worker
1117*387f9dfdSAndroid Build Coastguard Worker if (header.sh_type != SHT_SYMTAB && header.sh_type != SHT_DYNSYM)
1118*387f9dfdSAndroid Build Coastguard Worker continue;
1119*387f9dfdSAndroid Build Coastguard Worker
1120*387f9dfdSAndroid Build Coastguard Worker /* iterate all symbols */
1121*387f9dfdSAndroid Build Coastguard Worker symsize = header.sh_entsize;
1122*387f9dfdSAndroid Build Coastguard Worker while ((data = elf_getdata(section, data)) != 0) {
1123*387f9dfdSAndroid Build Coastguard Worker size_t i, symcount = data->d_size / symsize;
1124*387f9dfdSAndroid Build Coastguard Worker
1125*387f9dfdSAndroid Build Coastguard Worker for (i = 0; i < symcount; ++i) {
1126*387f9dfdSAndroid Build Coastguard Worker GElf_Sym sym;
1127*387f9dfdSAndroid Build Coastguard Worker
1128*387f9dfdSAndroid Build Coastguard Worker if (!gelf_getsym(data, (int)i, &sym))
1129*387f9dfdSAndroid Build Coastguard Worker continue;
1130*387f9dfdSAndroid Build Coastguard Worker
1131*387f9dfdSAndroid Build Coastguard Worker if (GELF_ST_TYPE(sym.st_info) != STT_FUNC)
1132*387f9dfdSAndroid Build Coastguard Worker continue;
1133*387f9dfdSAndroid Build Coastguard Worker
1134*387f9dfdSAndroid Build Coastguard Worker const char *name;
1135*387f9dfdSAndroid Build Coastguard Worker if ((name = elf_strptr(elf_file.elf, header.sh_link, sym.st_name)) ==
1136*387f9dfdSAndroid Build Coastguard Worker NULL)
1137*387f9dfdSAndroid Build Coastguard Worker continue;
1138*387f9dfdSAndroid Build Coastguard Worker
1139*387f9dfdSAndroid Build Coastguard Worker if (strcmp(name, "bcc_free_memory") == 0) {
1140*387f9dfdSAndroid Build Coastguard Worker sym_addr = sym.st_value;
1141*387f9dfdSAndroid Build Coastguard Worker sym_shndx = sym.st_shndx;
1142*387f9dfdSAndroid Build Coastguard Worker break;
1143*387f9dfdSAndroid Build Coastguard Worker }
1144*387f9dfdSAndroid Build Coastguard Worker }
1145*387f9dfdSAndroid Build Coastguard Worker }
1146*387f9dfdSAndroid Build Coastguard Worker }
1147*387f9dfdSAndroid Build Coastguard Worker
1148*387f9dfdSAndroid Build Coastguard Worker // Didn't find bcc_free_memory in the ELF file.
1149*387f9dfdSAndroid Build Coastguard Worker if (sym_addr == 0)
1150*387f9dfdSAndroid Build Coastguard Worker goto exit;
1151*387f9dfdSAndroid Build Coastguard Worker
1152*387f9dfdSAndroid Build Coastguard Worker int sh_idx = 0;
1153*387f9dfdSAndroid Build Coastguard Worker section = NULL;
1154*387f9dfdSAndroid Build Coastguard Worker err = 1;
1155*387f9dfdSAndroid Build Coastguard Worker while ((section = elf_nextscn(elf_file.elf, section)) != 0) {
1156*387f9dfdSAndroid Build Coastguard Worker sh_idx++;
1157*387f9dfdSAndroid Build Coastguard Worker if (!gelf_getshdr(section, &header))
1158*387f9dfdSAndroid Build Coastguard Worker continue;
1159*387f9dfdSAndroid Build Coastguard Worker
1160*387f9dfdSAndroid Build Coastguard Worker if (sh_idx == sym_shndx) {
1161*387f9dfdSAndroid Build Coastguard Worker unsigned long saddr, saddr_n, eaddr;
1162*387f9dfdSAndroid Build Coastguard Worker long page_size = sysconf(_SC_PAGESIZE);
1163*387f9dfdSAndroid Build Coastguard Worker
1164*387f9dfdSAndroid Build Coastguard Worker saddr = (unsigned long)bcc_free_memory - sym_addr + header.sh_addr;
1165*387f9dfdSAndroid Build Coastguard Worker eaddr = saddr + header.sh_size;
1166*387f9dfdSAndroid Build Coastguard Worker
1167*387f9dfdSAndroid Build Coastguard Worker // adjust saddr and eaddr, start addr needs to be page aligned
1168*387f9dfdSAndroid Build Coastguard Worker saddr_n = (saddr + page_size - 1) & ~(page_size - 1);
1169*387f9dfdSAndroid Build Coastguard Worker eaddr -= saddr_n - saddr;
1170*387f9dfdSAndroid Build Coastguard Worker
1171*387f9dfdSAndroid Build Coastguard Worker if (madvise((void *)saddr_n, eaddr - saddr_n, MADV_DONTNEED)) {
1172*387f9dfdSAndroid Build Coastguard Worker fprintf(stderr, "madvise failed, saddr %lx, eaddr %lx\n", saddr, eaddr);
1173*387f9dfdSAndroid Build Coastguard Worker goto exit;
1174*387f9dfdSAndroid Build Coastguard Worker }
1175*387f9dfdSAndroid Build Coastguard Worker
1176*387f9dfdSAndroid Build Coastguard Worker err = 0;
1177*387f9dfdSAndroid Build Coastguard Worker break;
1178*387f9dfdSAndroid Build Coastguard Worker }
1179*387f9dfdSAndroid Build Coastguard Worker }
1180*387f9dfdSAndroid Build Coastguard Worker
1181*387f9dfdSAndroid Build Coastguard Worker exit:
1182*387f9dfdSAndroid Build Coastguard Worker bcc_elf_file_close(&elf_file);
1183*387f9dfdSAndroid Build Coastguard Worker return err;
1184*387f9dfdSAndroid Build Coastguard Worker }
1185*387f9dfdSAndroid Build Coastguard Worker
1186*387f9dfdSAndroid Build Coastguard Worker // Free bcc mmemory
1187*387f9dfdSAndroid Build Coastguard Worker //
1188*387f9dfdSAndroid Build Coastguard Worker // The main purpose of this function is to free llvm/clang text memory
1189*387f9dfdSAndroid Build Coastguard Worker // through madvise MADV_DONTNEED.
1190*387f9dfdSAndroid Build Coastguard Worker //
1191*387f9dfdSAndroid Build Coastguard Worker // bcc could be linked statically or dynamically into the application.
1192*387f9dfdSAndroid Build Coastguard Worker // If it is static linking, there is no easy way to know which region
1193*387f9dfdSAndroid Build Coastguard Worker // inside .text section belongs to llvm/clang, so the whole .text section
1194*387f9dfdSAndroid Build Coastguard Worker // is freed. Otherwise, the process map is searched to find libbcc.so
1195*387f9dfdSAndroid Build Coastguard Worker // library and the whole .text section for that shared library is
1196*387f9dfdSAndroid Build Coastguard Worker // freed.
1197*387f9dfdSAndroid Build Coastguard Worker //
1198*387f9dfdSAndroid Build Coastguard Worker // Note that the text memory used by bcc (mainly llvm/clang) is reclaimable
1199*387f9dfdSAndroid Build Coastguard Worker // in the kernel as it is file backed. But the reclaim process
1200*387f9dfdSAndroid Build Coastguard Worker // may take some time if no memory pressure. So this API is mostly
1201*387f9dfdSAndroid Build Coastguard Worker // used for application who needs to immediately lowers its RssFile
1202*387f9dfdSAndroid Build Coastguard Worker // metric right after loading BPF program.
bcc_free_memory()1203*387f9dfdSAndroid Build Coastguard Worker int bcc_free_memory() {
1204*387f9dfdSAndroid Build Coastguard Worker int err;
1205*387f9dfdSAndroid Build Coastguard Worker
1206*387f9dfdSAndroid Build Coastguard Worker // First try whether bcc is statically linked or not
1207*387f9dfdSAndroid Build Coastguard Worker err = bcc_free_memory_with_file("/proc/self/exe");
1208*387f9dfdSAndroid Build Coastguard Worker if (err >= 0)
1209*387f9dfdSAndroid Build Coastguard Worker return -err;
1210*387f9dfdSAndroid Build Coastguard Worker
1211*387f9dfdSAndroid Build Coastguard Worker // Not statically linked, let us find the libbcc.so
1212*387f9dfdSAndroid Build Coastguard Worker FILE *maps = fopen("/proc/self/maps", "r");
1213*387f9dfdSAndroid Build Coastguard Worker if (!maps)
1214*387f9dfdSAndroid Build Coastguard Worker return -1;
1215*387f9dfdSAndroid Build Coastguard Worker
1216*387f9dfdSAndroid Build Coastguard Worker char *line = NULL;
1217*387f9dfdSAndroid Build Coastguard Worker size_t size;
1218*387f9dfdSAndroid Build Coastguard Worker while (getline(&line, &size, maps) > 0) {
1219*387f9dfdSAndroid Build Coastguard Worker char *libbcc = strstr(line, "libbcc.so");
1220*387f9dfdSAndroid Build Coastguard Worker if (!libbcc)
1221*387f9dfdSAndroid Build Coastguard Worker continue;
1222*387f9dfdSAndroid Build Coastguard Worker
1223*387f9dfdSAndroid Build Coastguard Worker // Parse the line and get the full libbcc.so path
1224*387f9dfdSAndroid Build Coastguard Worker unsigned long addr_start, addr_end, offset, inode;
1225*387f9dfdSAndroid Build Coastguard Worker int path_start = 0, path_end = 0;
1226*387f9dfdSAndroid Build Coastguard Worker unsigned int devmajor, devminor;
1227*387f9dfdSAndroid Build Coastguard Worker char perms[8];
1228*387f9dfdSAndroid Build Coastguard Worker if (sscanf(line, "%lx-%lx %7s %lx %x:%x %lu %n%*[^\n]%n",
1229*387f9dfdSAndroid Build Coastguard Worker &addr_start, &addr_end, perms, &offset,
1230*387f9dfdSAndroid Build Coastguard Worker &devmajor, &devminor, &inode,
1231*387f9dfdSAndroid Build Coastguard Worker &path_start, &path_end) < 7)
1232*387f9dfdSAndroid Build Coastguard Worker break;
1233*387f9dfdSAndroid Build Coastguard Worker
1234*387f9dfdSAndroid Build Coastguard Worker // Free the text in the bcc dynamic library.
1235*387f9dfdSAndroid Build Coastguard Worker char libbcc_path[4096];
1236*387f9dfdSAndroid Build Coastguard Worker memcpy(libbcc_path, line + path_start, path_end - path_start);
1237*387f9dfdSAndroid Build Coastguard Worker libbcc_path[path_end - path_start] = '\0';
1238*387f9dfdSAndroid Build Coastguard Worker err = bcc_free_memory_with_file(libbcc_path);
1239*387f9dfdSAndroid Build Coastguard Worker err = (err <= 0) ? err : -err;
1240*387f9dfdSAndroid Build Coastguard Worker }
1241*387f9dfdSAndroid Build Coastguard Worker
1242*387f9dfdSAndroid Build Coastguard Worker fclose(maps);
1243*387f9dfdSAndroid Build Coastguard Worker free(line);
1244*387f9dfdSAndroid Build Coastguard Worker return err;
1245*387f9dfdSAndroid Build Coastguard Worker }
1246*387f9dfdSAndroid Build Coastguard Worker
bcc_elf_get_buildid(const char * path,char * buildid)1247*387f9dfdSAndroid Build Coastguard Worker int bcc_elf_get_buildid(const char *path, char *buildid) {
1248*387f9dfdSAndroid Build Coastguard Worker int rc = -1;
1249*387f9dfdSAndroid Build Coastguard Worker struct bcc_elf_file elf_file;
1250*387f9dfdSAndroid Build Coastguard Worker bcc_elf_file_init(&elf_file);
1251*387f9dfdSAndroid Build Coastguard Worker
1252*387f9dfdSAndroid Build Coastguard Worker if (bcc_elf_file_open(path, &elf_file) < 0)
1253*387f9dfdSAndroid Build Coastguard Worker return -1;
1254*387f9dfdSAndroid Build Coastguard Worker
1255*387f9dfdSAndroid Build Coastguard Worker if (!find_buildid(elf_file.elf, buildid))
1256*387f9dfdSAndroid Build Coastguard Worker goto exit;
1257*387f9dfdSAndroid Build Coastguard Worker
1258*387f9dfdSAndroid Build Coastguard Worker rc = 0;
1259*387f9dfdSAndroid Build Coastguard Worker exit:
1260*387f9dfdSAndroid Build Coastguard Worker bcc_elf_file_close(&elf_file);
1261*387f9dfdSAndroid Build Coastguard Worker return rc;
1262*387f9dfdSAndroid Build Coastguard Worker }
1263*387f9dfdSAndroid Build Coastguard Worker
bcc_elf_symbol_str(const char * path,size_t section_idx,size_t str_table_idx,char * out,size_t len,int debugfile)1264*387f9dfdSAndroid Build Coastguard Worker int bcc_elf_symbol_str(const char *path, size_t section_idx,
1265*387f9dfdSAndroid Build Coastguard Worker size_t str_table_idx, char *out, size_t len,
1266*387f9dfdSAndroid Build Coastguard Worker int debugfile) {
1267*387f9dfdSAndroid Build Coastguard Worker int err = 0;
1268*387f9dfdSAndroid Build Coastguard Worker const char *name;
1269*387f9dfdSAndroid Build Coastguard Worker struct bcc_elf_file elf_file;
1270*387f9dfdSAndroid Build Coastguard Worker bcc_elf_file_init(&elf_file);
1271*387f9dfdSAndroid Build Coastguard Worker struct bcc_elf_file debug_elf_file;
1272*387f9dfdSAndroid Build Coastguard Worker bcc_elf_file_init(&debug_elf_file);
1273*387f9dfdSAndroid Build Coastguard Worker
1274*387f9dfdSAndroid Build Coastguard Worker if (!out)
1275*387f9dfdSAndroid Build Coastguard Worker return -1;
1276*387f9dfdSAndroid Build Coastguard Worker
1277*387f9dfdSAndroid Build Coastguard Worker if (bcc_elf_file_open(path, &elf_file) < 0)
1278*387f9dfdSAndroid Build Coastguard Worker return -1;
1279*387f9dfdSAndroid Build Coastguard Worker
1280*387f9dfdSAndroid Build Coastguard Worker if (debugfile) {
1281*387f9dfdSAndroid Build Coastguard Worker if (find_debug_file(elf_file.elf, path, 0, &debug_elf_file)) {
1282*387f9dfdSAndroid Build Coastguard Worker err = -1;
1283*387f9dfdSAndroid Build Coastguard Worker goto exit;
1284*387f9dfdSAndroid Build Coastguard Worker }
1285*387f9dfdSAndroid Build Coastguard Worker
1286*387f9dfdSAndroid Build Coastguard Worker if ((name = elf_strptr(debug_elf_file.elf, section_idx, str_table_idx)) ==
1287*387f9dfdSAndroid Build Coastguard Worker NULL) {
1288*387f9dfdSAndroid Build Coastguard Worker err = -1;
1289*387f9dfdSAndroid Build Coastguard Worker goto exit;
1290*387f9dfdSAndroid Build Coastguard Worker }
1291*387f9dfdSAndroid Build Coastguard Worker } else {
1292*387f9dfdSAndroid Build Coastguard Worker if ((name = elf_strptr(elf_file.elf, section_idx, str_table_idx)) == NULL) {
1293*387f9dfdSAndroid Build Coastguard Worker err = -1;
1294*387f9dfdSAndroid Build Coastguard Worker goto exit;
1295*387f9dfdSAndroid Build Coastguard Worker }
1296*387f9dfdSAndroid Build Coastguard Worker }
1297*387f9dfdSAndroid Build Coastguard Worker
1298*387f9dfdSAndroid Build Coastguard Worker strncpy(out, name, len);
1299*387f9dfdSAndroid Build Coastguard Worker
1300*387f9dfdSAndroid Build Coastguard Worker exit:
1301*387f9dfdSAndroid Build Coastguard Worker bcc_elf_file_close(&debug_elf_file);
1302*387f9dfdSAndroid Build Coastguard Worker bcc_elf_file_close(&elf_file);
1303*387f9dfdSAndroid Build Coastguard Worker return err;
1304*387f9dfdSAndroid Build Coastguard Worker }
1305*387f9dfdSAndroid Build Coastguard Worker
1306*387f9dfdSAndroid Build Coastguard Worker #if 0
1307*387f9dfdSAndroid Build Coastguard Worker #include <stdio.h>
1308*387f9dfdSAndroid Build Coastguard Worker
1309*387f9dfdSAndroid Build Coastguard Worker int main(int argc, char *argv[])
1310*387f9dfdSAndroid Build Coastguard Worker {
1311*387f9dfdSAndroid Build Coastguard Worker uint64_t addr;
1312*387f9dfdSAndroid Build Coastguard Worker if (bcc_elf_findsym(argv[1], argv[2], -1, STT_FUNC, &addr) < 0)
1313*387f9dfdSAndroid Build Coastguard Worker return -1;
1314*387f9dfdSAndroid Build Coastguard Worker
1315*387f9dfdSAndroid Build Coastguard Worker printf("%s: %p\n", argv[2], (void *)addr);
1316*387f9dfdSAndroid Build Coastguard Worker return 0;
1317*387f9dfdSAndroid Build Coastguard Worker }
1318*387f9dfdSAndroid Build Coastguard Worker #endif
1319