xref: /aosp_15_r20/external/bcc/src/cc/bcc_elf.c (revision 387f9dfdfa2baef462e92476d413c7bc2470293e)
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