blob: c425db63a7cdd026e6843c8190ed6d77240d4f70 [file] [log] [blame]
Vicent Marti411f6982016-04-20 13:24:54 +02001/*
2 * Copyright (c) 2016 GitHub, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Vicent Martib8f0f092016-04-20 13:24:54 +020016#include <sys/types.h>
17#include <sys/stat.h>
Sasha Goldshtein01553852017-02-09 03:58:09 -050018#include <sys/mman.h>
Teng Qin1670d332017-10-06 18:08:33 -070019#include <errno.h>
Vicent Martib8f0f092016-04-20 13:24:54 +020020#include <fcntl.h>
21#include <unistd.h>
22#include <string.h>
Sasha Goldshtein01553852017-02-09 03:58:09 -050023#include <libgen.h>
24#include <stdio.h>
25#include <stdlib.h>
26#include <limits.h>
Vicent Martib8f0f092016-04-20 13:24:54 +020027
28#include <gelf.h>
Vicent Martic1c23732016-04-20 13:24:54 +020029#include "bcc_elf.h"
Teng Qin1670d332017-10-06 18:08:33 -070030#include "bcc_proc.h"
Teng Qin0336a292017-05-04 00:09:20 -070031#include "bcc_syms.h"
32
Vicent Martib8f0f092016-04-20 13:24:54 +020033#define NT_STAPSDT 3
Teng Qin0336a292017-05-04 00:09:20 -070034#define ELF_ST_TYPE(x) (((uint32_t) x) & 0xf)
Vicent Martib8f0f092016-04-20 13:24:54 +020035
Teng Qin1670d332017-10-06 18:08:33 -070036static int openelf_fd(int fd, Elf **elf_out) {
Vicent Martic1c23732016-04-20 13:24:54 +020037 if (elf_version(EV_CURRENT) == EV_NONE)
38 return -1;
Vicent Martib8f0f092016-04-20 13:24:54 +020039
Teng Qin1670d332017-10-06 18:08:33 -070040 *elf_out = elf_begin(fd, ELF_C_READ, 0);
41 if (*elf_out == NULL)
42 return -1;
43
44 return 0;
45}
46
47static int openelf(const char *path, Elf **elf_out, int *fd_out) {
Vicent Martic1c23732016-04-20 13:24:54 +020048 *fd_out = open(path, O_RDONLY);
49 if (*fd_out < 0)
50 return -1;
Vicent Martib8f0f092016-04-20 13:24:54 +020051
Teng Qin1670d332017-10-06 18:08:33 -070052 if (openelf_fd(*fd_out, elf_out) == -1) {
Vicent Martic1c23732016-04-20 13:24:54 +020053 close(*fd_out);
54 return -1;
55 }
Vicent Martib8f0f092016-04-20 13:24:54 +020056
Vicent Martic1c23732016-04-20 13:24:54 +020057 return 0;
Vicent Martib8f0f092016-04-20 13:24:54 +020058}
59
Vicent Martic1c23732016-04-20 13:24:54 +020060static const char *parse_stapsdt_note(struct bcc_elf_usdt *probe,
61 const char *desc, int elf_class) {
62 if (elf_class == ELFCLASS32) {
63 probe->pc = *((uint32_t *)(desc));
64 probe->base_addr = *((uint32_t *)(desc + 4));
65 probe->semaphore = *((uint32_t *)(desc + 8));
66 desc = desc + 12;
67 } else {
68 probe->pc = *((uint64_t *)(desc));
69 probe->base_addr = *((uint64_t *)(desc + 8));
70 probe->semaphore = *((uint64_t *)(desc + 16));
71 desc = desc + 24;
72 }
Vicent Martib8f0f092016-04-20 13:24:54 +020073
Vicent Martic1c23732016-04-20 13:24:54 +020074 probe->provider = desc;
75 desc += strlen(desc) + 1;
Vicent Martib8f0f092016-04-20 13:24:54 +020076
Vicent Martic1c23732016-04-20 13:24:54 +020077 probe->name = desc;
78 desc += strlen(desc) + 1;
Vicent Martib8f0f092016-04-20 13:24:54 +020079
Vicent Martic1c23732016-04-20 13:24:54 +020080 probe->arg_fmt = desc;
81 desc += strlen(desc) + 1;
Vicent Martib8f0f092016-04-20 13:24:54 +020082
Vicent Martic1c23732016-04-20 13:24:54 +020083 return desc;
Vicent Martib8f0f092016-04-20 13:24:54 +020084}
85
Vicent Martic1c23732016-04-20 13:24:54 +020086static int do_note_segment(Elf_Scn *section, int elf_class,
87 bcc_elf_probecb callback, const char *binpath,
Yonghong Songbf2a8112018-01-11 11:45:11 -080088 uint64_t first_inst_offset, void *payload) {
Vicent Martic1c23732016-04-20 13:24:54 +020089 Elf_Data *data = NULL;
Vicent Martib8f0f092016-04-20 13:24:54 +020090
Vicent Martic1c23732016-04-20 13:24:54 +020091 while ((data = elf_getdata(section, data)) != 0) {
92 size_t offset = 0;
93 GElf_Nhdr hdr;
94 size_t name_off, desc_off;
Vicent Martib8f0f092016-04-20 13:24:54 +020095
Vicent Martic1c23732016-04-20 13:24:54 +020096 while ((offset = gelf_getnote(data, offset, &hdr, &name_off, &desc_off)) !=
97 0) {
98 const char *desc, *desc_end;
99 struct bcc_elf_usdt probe;
Vicent Martib8f0f092016-04-20 13:24:54 +0200100
Vicent Martic1c23732016-04-20 13:24:54 +0200101 if (hdr.n_type != NT_STAPSDT)
102 continue;
Vicent Martib8f0f092016-04-20 13:24:54 +0200103
Vicent Martic1c23732016-04-20 13:24:54 +0200104 if (hdr.n_namesz != 8)
105 continue;
Vicent Martib8f0f092016-04-20 13:24:54 +0200106
Vicent Martic1c23732016-04-20 13:24:54 +0200107 if (memcmp((const char *)data->d_buf + name_off, "stapsdt", 8) != 0)
108 continue;
Vicent Martib8f0f092016-04-20 13:24:54 +0200109
Vicent Martic1c23732016-04-20 13:24:54 +0200110 desc = (const char *)data->d_buf + desc_off;
111 desc_end = desc + hdr.n_descsz;
Vicent Martib8f0f092016-04-20 13:24:54 +0200112
Yonghong Songbf2a8112018-01-11 11:45:11 -0800113 if (parse_stapsdt_note(&probe, desc, elf_class) == desc_end) {
114 if (probe.pc < first_inst_offset)
115 fprintf(stderr,
116 "WARNING: invalid address 0x%lx for probe (%s,%s) in binary %s\n",
117 probe.pc, probe.provider, probe.name, binpath);
118 else
119 callback(binpath, &probe, payload);
120 }
Vicent Martic1c23732016-04-20 13:24:54 +0200121 }
122 }
123 return 0;
Vicent Martib8f0f092016-04-20 13:24:54 +0200124}
125
Vicent Martic1c23732016-04-20 13:24:54 +0200126static int listprobes(Elf *e, bcc_elf_probecb callback, const char *binpath,
127 void *payload) {
128 Elf_Scn *section = NULL;
129 size_t stridx;
130 int elf_class = gelf_getclass(e);
Yonghong Songbf2a8112018-01-11 11:45:11 -0800131 uint64_t first_inst_offset = 0;
Vicent Martib8f0f092016-04-20 13:24:54 +0200132
Vicent Martic1c23732016-04-20 13:24:54 +0200133 if (elf_getshdrstrndx(e, &stridx) != 0)
134 return -1;
Vicent Martib8f0f092016-04-20 13:24:54 +0200135
Yonghong Songbf2a8112018-01-11 11:45:11 -0800136 // Get the offset to the first instruction
137 while ((section = elf_nextscn(e, section)) != 0) {
138 GElf_Shdr header;
139
140 if (!gelf_getshdr(section, &header))
141 continue;
142
143 // The elf file section layout is based on increasing virtual address,
144 // getting the first section with SHF_EXECINSTR is enough.
145 if (header.sh_flags & SHF_EXECINSTR) {
146 first_inst_offset = header.sh_addr;
147 break;
148 }
149 }
150
Vicent Martic1c23732016-04-20 13:24:54 +0200151 while ((section = elf_nextscn(e, section)) != 0) {
152 GElf_Shdr header;
153 char *name;
Vicent Martib8f0f092016-04-20 13:24:54 +0200154
Vicent Martic1c23732016-04-20 13:24:54 +0200155 if (!gelf_getshdr(section, &header))
156 continue;
Vicent Martib8f0f092016-04-20 13:24:54 +0200157
Vicent Martic1c23732016-04-20 13:24:54 +0200158 if (header.sh_type != SHT_NOTE)
159 continue;
Vicent Martib8f0f092016-04-20 13:24:54 +0200160
Vicent Martic1c23732016-04-20 13:24:54 +0200161 name = elf_strptr(e, stridx, header.sh_name);
162 if (name && !strcmp(name, ".note.stapsdt")) {
Yonghong Songbf2a8112018-01-11 11:45:11 -0800163 if (do_note_segment(section, elf_class, callback, binpath,
164 first_inst_offset, payload) < 0)
Vicent Martic1c23732016-04-20 13:24:54 +0200165 return -1;
166 }
167 }
Vicent Martib8f0f092016-04-20 13:24:54 +0200168
Vicent Martic1c23732016-04-20 13:24:54 +0200169 return 0;
Vicent Martib8f0f092016-04-20 13:24:54 +0200170}
171
Vicent Martic1c23732016-04-20 13:24:54 +0200172int bcc_elf_foreach_usdt(const char *path, bcc_elf_probecb callback,
173 void *payload) {
174 Elf *e;
175 int fd, res;
Vicent Martib8f0f092016-04-20 13:24:54 +0200176
Vicent Martic1c23732016-04-20 13:24:54 +0200177 if (openelf(path, &e, &fd) < 0)
178 return -1;
Vicent Martib8f0f092016-04-20 13:24:54 +0200179
Vicent Martic1c23732016-04-20 13:24:54 +0200180 res = listprobes(e, callback, path, payload);
181 elf_end(e);
182 close(fd);
Vicent Martib8f0f092016-04-20 13:24:54 +0200183
Vicent Martic1c23732016-04-20 13:24:54 +0200184 return res;
Vicent Martib8f0f092016-04-20 13:24:54 +0200185}
186
Vicent Martic1c23732016-04-20 13:24:54 +0200187static int list_in_scn(Elf *e, Elf_Scn *section, size_t stridx, size_t symsize,
Teng Qin0336a292017-05-04 00:09:20 -0700188 struct bcc_symbol_option *option,
Vicent Martic1c23732016-04-20 13:24:54 +0200189 bcc_elf_symcb callback, void *payload) {
190 Elf_Data *data = NULL;
Vicent Martib8f0f092016-04-20 13:24:54 +0200191
Vicent Martic1c23732016-04-20 13:24:54 +0200192 while ((data = elf_getdata(section, data)) != 0) {
193 size_t i, symcount = data->d_size / symsize;
Vicent Martib8f0f092016-04-20 13:24:54 +0200194
Vicent Martic1c23732016-04-20 13:24:54 +0200195 if (data->d_size % symsize)
196 return -1;
Vicent Martib8f0f092016-04-20 13:24:54 +0200197
Vicent Martic1c23732016-04-20 13:24:54 +0200198 for (i = 0; i < symcount; ++i) {
199 GElf_Sym sym;
200 const char *name;
Vicent Martib8f0f092016-04-20 13:24:54 +0200201
Vicent Martic1c23732016-04-20 13:24:54 +0200202 if (!gelf_getsym(data, (int)i, &sym))
203 continue;
Vicent Martib8f0f092016-04-20 13:24:54 +0200204
Vicent Martic1c23732016-04-20 13:24:54 +0200205 if ((name = elf_strptr(e, stridx, sym.st_name)) == NULL)
206 continue;
Teng Qin0336a292017-05-04 00:09:20 -0700207 if (name[0] == 0)
208 continue;
209
210 if (sym.st_value == 0)
211 continue;
212
Teng Qin91fc7212017-09-13 17:21:13 -0700213 uint32_t st_type = ELF_ST_TYPE(sym.st_info);
Teng Qin91fc7212017-09-13 17:21:13 -0700214 if (!(option->use_symbol_type & (1 << st_type)))
Teng Qin0336a292017-05-04 00:09:20 -0700215 continue;
Vicent Martib8f0f092016-04-20 13:24:54 +0200216
Teng Qincf130832017-05-10 12:51:17 -0700217 if (callback(name, sym.st_value, sym.st_size, payload) < 0)
Sasha Goldshtein07175d02016-10-06 01:11:55 +0300218 return 1; // signal termination to caller
Vicent Martic1c23732016-04-20 13:24:54 +0200219 }
220 }
Vicent Martib8f0f092016-04-20 13:24:54 +0200221
Vicent Martic1c23732016-04-20 13:24:54 +0200222 return 0;
Vicent Martib8f0f092016-04-20 13:24:54 +0200223}
224
Teng Qin0336a292017-05-04 00:09:20 -0700225static int listsymbols(Elf *e, bcc_elf_symcb callback, void *payload,
226 struct bcc_symbol_option *option) {
Vicent Martic1c23732016-04-20 13:24:54 +0200227 Elf_Scn *section = NULL;
Vicent Martib8f0f092016-04-20 13:24:54 +0200228
Vicent Martic1c23732016-04-20 13:24:54 +0200229 while ((section = elf_nextscn(e, section)) != 0) {
230 GElf_Shdr header;
Vicent Martib8f0f092016-04-20 13:24:54 +0200231
Vicent Martic1c23732016-04-20 13:24:54 +0200232 if (!gelf_getshdr(section, &header))
233 continue;
Vicent Martib8f0f092016-04-20 13:24:54 +0200234
Vicent Martic1c23732016-04-20 13:24:54 +0200235 if (header.sh_type != SHT_SYMTAB && header.sh_type != SHT_DYNSYM)
236 continue;
Vicent Martib8f0f092016-04-20 13:24:54 +0200237
Sasha Goldshtein07175d02016-10-06 01:11:55 +0300238 int rc = list_in_scn(e, section, header.sh_link, header.sh_entsize,
Teng Qin0336a292017-05-04 00:09:20 -0700239 option, callback, payload);
Sasha Goldshtein07175d02016-10-06 01:11:55 +0300240 if (rc == 1)
241 break; // callback signaled termination
242
243 if (rc < 0)
244 return rc;
Vicent Martic1c23732016-04-20 13:24:54 +0200245 }
Vicent Martib8f0f092016-04-20 13:24:54 +0200246
Vicent Martic1c23732016-04-20 13:24:54 +0200247 return 0;
Vicent Martib8f0f092016-04-20 13:24:54 +0200248}
249
Sasha Goldshtein01553852017-02-09 03:58:09 -0500250static Elf_Data * get_section_elf_data(Elf *e, const char *section_name) {
251 Elf_Scn *section = NULL;
252 GElf_Shdr header;
253 char *name;
254
255 size_t stridx;
256 if (elf_getshdrstrndx(e, &stridx) != 0)
257 return NULL;
258
259 while ((section = elf_nextscn(e, section)) != 0) {
260 if (!gelf_getshdr(section, &header))
261 continue;
262
263 name = elf_strptr(e, stridx, header.sh_name);
264 if (name && !strcmp(name, section_name)) {
265 return elf_getdata(section, NULL);
266 }
267 }
268
269 return NULL;
270}
271
272static int find_debuglink(Elf *e, char **debug_file, unsigned int *crc) {
273 Elf_Data *data = NULL;
274
275 *debug_file = NULL;
276 *crc = 0;
277
278 data = get_section_elf_data(e, ".gnu_debuglink");
279 if (!data || data->d_size <= 5)
280 return 0;
281
282 *debug_file = (char *)data->d_buf;
283 *crc = *(unsigned int*)((char *)data->d_buf + data->d_size - 4);
284
285 return *debug_file ? 1 : 0;
286}
287
288static int find_buildid(Elf *e, char *buildid) {
289 Elf_Data *data = get_section_elf_data(e, ".note.gnu.build-id");
Sasha Goldshteine5d33df2017-02-11 19:35:14 -0500290 if (!data || data->d_size <= 16 || strcmp((char *)data->d_buf + 12, "GNU"))
Sasha Goldshtein01553852017-02-09 03:58:09 -0500291 return 0;
292
293 char *buf = (char *)data->d_buf + 16;
294 size_t length = data->d_size - 16;
Mark Draytonf498e592017-02-21 22:25:57 +0000295 size_t i = 0;
296 for (i = 0; i < length; ++i) {
Sasha Goldshtein01553852017-02-09 03:58:09 -0500297 sprintf(buildid + (i * 2), "%02hhx", buf[i]);
298 }
299
300 return 1;
301}
302
303// The CRC algorithm used by GNU debuglink. Taken from:
304// https://sourceware.org/gdb/onlinedocs/gdb/Separate-Debug-Files.html
305static unsigned int gnu_debuglink_crc32(unsigned int crc,
306 char *buf, size_t len) {
307 static const unsigned int crc32_table[256] =
308 {
309 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419,
310 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4,
311 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07,
312 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
313 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856,
314 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
315 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,
316 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
317 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,
318 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a,
319 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599,
320 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
321 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190,
322 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,
323 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e,
324 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
325 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed,
326 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
327 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3,
328 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
329 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,
330 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5,
331 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010,
332 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
333 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17,
334 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6,
335 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,
336 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
337 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344,
338 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
339 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a,
340 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
341 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1,
342 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c,
343 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,
344 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
345 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe,
346 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31,
347 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c,
348 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
349 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b,
350 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
351 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1,
352 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
353 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,
354 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7,
355 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66,
356 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
357 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,
358 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8,
359 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b,
360 0x2d02ef8d
361 };
362 char *end;
363
364 crc = ~crc & 0xffffffff;
365 for (end = buf + len; buf < end; ++buf)
366 crc = crc32_table[(crc ^ *buf) & 0xff] ^ (crc >> 8);
367 return ~crc & 0xffffffff;
368}
369
370static int verify_checksum(const char *file, unsigned int crc) {
371 struct stat st;
372 int fd;
373 void *buf;
374 unsigned int actual;
375
376 fd = open(file, O_RDONLY);
377 if (fd < 0)
378 return 0;
379
jeromemarchandb84714a2018-08-08 18:09:44 +0200380 if (fstat(fd, &st) < 0) {
381 close(fd);
Sasha Goldshtein01553852017-02-09 03:58:09 -0500382 return 0;
jeromemarchandb84714a2018-08-08 18:09:44 +0200383 }
Sasha Goldshtein01553852017-02-09 03:58:09 -0500384
385 buf = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
386 if (!buf) {
387 close(fd);
388 return 0;
389 }
390
391 actual = gnu_debuglink_crc32(0, buf, st.st_size);
392
393 munmap(buf, st.st_size);
394 close(fd);
395 return actual == crc;
396}
397
Teng Qin0336a292017-05-04 00:09:20 -0700398static char *find_debug_via_debuglink(Elf *e, const char *binpath,
399 int check_crc) {
Sasha Goldshtein01553852017-02-09 03:58:09 -0500400 char fullpath[PATH_MAX];
401 char *bindir = NULL;
402 char *res = NULL;
403 unsigned int crc;
404 char *name; // the name of the debuginfo file
405
406 if (!find_debuglink(e, &name, &crc))
407 return NULL;
408
409 bindir = strdup(binpath);
410 bindir = dirname(bindir);
411
Sasha Goldshteina359a902017-04-13 19:14:00 +0300412 // Search for the file in 'binpath', but ignore the file we find if it
413 // matches the binary itself: the binary will always be probed later on,
414 // and it might contain poorer symbols (e.g. stripped or partial symbols)
415 // than the external debuginfo that might be available elsewhere.
Nan Xiao03797792017-07-29 10:47:24 +0800416 snprintf(fullpath, sizeof(fullpath),"%s/%s", bindir, name);
Sasha Goldshteina359a902017-04-13 19:14:00 +0300417 if (strcmp(fullpath, binpath) != 0 && access(fullpath, F_OK) != -1) {
Sasha Goldshtein01553852017-02-09 03:58:09 -0500418 res = strdup(fullpath);
419 goto DONE;
420 }
421
422 // Search for the file in 'binpath'/.debug
Nan Xiao03797792017-07-29 10:47:24 +0800423 snprintf(fullpath, sizeof(fullpath), "%s/.debug/%s", bindir, name);
Sasha Goldshtein01553852017-02-09 03:58:09 -0500424 if (access(fullpath, F_OK) != -1) {
425 res = strdup(fullpath);
426 goto DONE;
427 }
428
429 // Search for the file in the global debug directory /usr/lib/debug/'binpath'
Nan Xiao03797792017-07-29 10:47:24 +0800430 snprintf(fullpath, sizeof(fullpath), "/usr/lib/debug%s/%s", bindir, name);
Sasha Goldshtein01553852017-02-09 03:58:09 -0500431 if (access(fullpath, F_OK) != -1) {
432 res = strdup(fullpath);
433 goto DONE;
434 }
435
436DONE:
437 free(bindir);
jeromemarchandb84714a2018-08-08 18:09:44 +0200438 if (res && check_crc && !verify_checksum(res, crc))
Teng Qin0336a292017-05-04 00:09:20 -0700439 return NULL;
440 return res;
Sasha Goldshtein01553852017-02-09 03:58:09 -0500441}
442
443static char *find_debug_via_buildid(Elf *e) {
444 char fullpath[PATH_MAX];
445 char buildid[128]; // currently 40 seems to be default, let's be safe
446
447 if (!find_buildid(e, buildid))
448 return NULL;
449
450 // Search for the file in the global debug directory with a sub-path:
451 // mm/nnnnnn...nnnn.debug
452 // Where mm are the first two characters of the buildid, and nnnn are the
453 // rest of the build id, followed by .debug.
Nan Xiao03797792017-07-29 10:47:24 +0800454 snprintf(fullpath, sizeof(fullpath), "/usr/lib/debug/.build-id/%c%c/%s.debug",
Sasha Goldshtein01553852017-02-09 03:58:09 -0500455 buildid[0], buildid[1], buildid + 2);
456 if (access(fullpath, F_OK) != -1) {
457 return strdup(fullpath);
458 }
459
460 return NULL;
461}
462
463static int foreach_sym_core(const char *path, bcc_elf_symcb callback,
Teng Qin0336a292017-05-04 00:09:20 -0700464 struct bcc_symbol_option *option, void *payload,
465 int is_debug_file) {
Vicent Martic1c23732016-04-20 13:24:54 +0200466 Elf *e;
467 int fd, res;
Sasha Goldshtein01553852017-02-09 03:58:09 -0500468 char *debug_file;
Vicent Martib8f0f092016-04-20 13:24:54 +0200469
Teng Qin0336a292017-05-04 00:09:20 -0700470 if (!option)
471 return -1;
472
Vicent Martic1c23732016-04-20 13:24:54 +0200473 if (openelf(path, &e, &fd) < 0)
474 return -1;
Vicent Martib8f0f092016-04-20 13:24:54 +0200475
Sasha Goldshtein01553852017-02-09 03:58:09 -0500476 // If there is a separate debuginfo file, try to locate and read it, first
477 // using the build-id section, then using the debuglink section. These are
478 // also the rules that GDB folows.
479 // See: https://sourceware.org/gdb/onlinedocs/gdb/Separate-Debug-Files.html
Teng Qin0336a292017-05-04 00:09:20 -0700480 if (option->use_debug_file && !is_debug_file) {
Sasha Goldshtein01553852017-02-09 03:58:09 -0500481 // The is_debug_file argument helps avoid infinitely resolving debuginfo
482 // files for debuginfo files and so on.
483 debug_file = find_debug_via_buildid(e);
484 if (!debug_file)
Teng Qin0336a292017-05-04 00:09:20 -0700485 debug_file = find_debug_via_debuglink(e, path,
486 option->check_debug_file_crc);
Sasha Goldshtein01553852017-02-09 03:58:09 -0500487 if (debug_file) {
Teng Qin0336a292017-05-04 00:09:20 -0700488 foreach_sym_core(debug_file, callback, option, payload, 1);
Sasha Goldshtein01553852017-02-09 03:58:09 -0500489 free(debug_file);
490 }
491 }
492
Teng Qin0336a292017-05-04 00:09:20 -0700493 res = listsymbols(e, callback, payload, option);
Vicent Martic1c23732016-04-20 13:24:54 +0200494 elf_end(e);
495 close(fd);
496 return res;
Vicent Martib8f0f092016-04-20 13:24:54 +0200497}
498
Sasha Goldshtein01553852017-02-09 03:58:09 -0500499int bcc_elf_foreach_sym(const char *path, bcc_elf_symcb callback,
Teng Qin0336a292017-05-04 00:09:20 -0700500 void *option, void *payload) {
501 return foreach_sym_core(
502 path, callback, (struct bcc_symbol_option*)option, payload, 0);
Sasha Goldshtein01553852017-02-09 03:58:09 -0500503}
504
Joel Fernandes5a1106c2018-04-07 10:43:15 +0000505int bcc_elf_get_text_scn_info(const char *path, uint64_t *addr,
506 uint64_t *offset) {
507 Elf *e = NULL;
508 int fd = -1, err;
509 Elf_Scn *section = NULL;
510 GElf_Shdr header;
511 size_t stridx;
512 char *name;
513
514 if ((err = openelf(path, &e, &fd)) < 0 ||
515 (err = elf_getshdrstrndx(e, &stridx)) < 0)
516 goto exit;
517
518 err = -1;
519 while ((section = elf_nextscn(e, section)) != 0) {
520 if (!gelf_getshdr(section, &header))
521 continue;
522
523 name = elf_strptr(e, stridx, header.sh_name);
524 if (name && !strcmp(name, ".text")) {
525 *addr = (uint64_t)header.sh_addr;
526 *offset = (uint64_t)header.sh_offset;
527 err = 0;
528 break;
529 }
530 }
531
532exit:
533 if (e)
534 elf_end(e);
535 if (fd >= 0)
536 close(fd);
537 return err;
538}
539
Teng Qina8f6db92017-09-20 16:06:38 -0700540int bcc_elf_foreach_load_section(const char *path,
541 bcc_elf_load_sectioncb callback,
542 void *payload) {
543 Elf *e = NULL;
544 int fd = -1, err = -1, res;
545 size_t nhdrs, i;
546
547 if (openelf(path, &e, &fd) < 0)
548 goto exit;
549
550 if (elf_getphdrnum(e, &nhdrs) != 0)
551 goto exit;
552
553 GElf_Phdr header;
554 for (i = 0; i < nhdrs; i++) {
555 if (!gelf_getphdr(e, (int)i, &header))
556 continue;
557 if (header.p_type != PT_LOAD || !(header.p_flags & PF_X))
558 continue;
559 res = callback(header.p_vaddr, header.p_memsz, header.p_offset, payload);
560 if (res < 0) {
561 err = 1;
562 goto exit;
563 }
564 }
565 err = 0;
566
567exit:
568 if (e)
569 elf_end(e);
570 if (fd >= 0)
571 close(fd);
572 return err;
573}
574
Teng Qind82e8132017-05-04 12:09:14 -0700575int bcc_elf_get_type(const char *path) {
Vicent Martic1c23732016-04-20 13:24:54 +0200576 Elf *e;
577 GElf_Ehdr hdr;
Teng Qind82e8132017-05-04 12:09:14 -0700578 int fd;
579 void* res = NULL;
Vicent Martib8f0f092016-04-20 13:24:54 +0200580
Vicent Martic1c23732016-04-20 13:24:54 +0200581 if (openelf(path, &e, &fd) < 0)
582 return -1;
Vicent Martib8f0f092016-04-20 13:24:54 +0200583
Teng Qind82e8132017-05-04 12:09:14 -0700584 res = (void*)gelf_getehdr(e, &hdr);
Vicent Martic1c23732016-04-20 13:24:54 +0200585 elf_end(e);
586 close(fd);
Vicent Martib8f0f092016-04-20 13:24:54 +0200587
Teng Qind82e8132017-05-04 12:09:14 -0700588 if (!res)
589 return -1;
590 else
591 return hdr.e_type;
592}
593
594int bcc_elf_is_exe(const char *path) {
595 return (bcc_elf_get_type(path) != -1) && (access(path, X_OK) == 0);
596}
597
598int bcc_elf_is_shared_obj(const char *path) {
599 return bcc_elf_get_type(path) == ET_DYN;
Vicent Martib8f0f092016-04-20 13:24:54 +0200600}
601
Teng Qin1670d332017-10-06 18:08:33 -0700602int bcc_elf_is_vdso(const char *name) {
603 return strcmp(name, "[vdso]") == 0;
604}
605
606// -2: Failed
607// -1: Not initialized
608// >0: Initialized
609static int vdso_image_fd = -1;
610
611static int find_vdso(const char *name, uint64_t st, uint64_t en,
612 uint64_t offset, bool enter_ns, void *payload) {
613 int fd;
614 char tmpfile[128];
615 if (!bcc_elf_is_vdso(name))
616 return 0;
617
618 void *image = malloc(en - st);
619 if (!image)
620 goto on_error;
621 memcpy(image, (void *)st, en - st);
622
623 snprintf(tmpfile, sizeof(tmpfile), "/tmp/bcc_%d_vdso_image_XXXXXX", getpid());
624 fd = mkostemp(tmpfile, O_CLOEXEC);
625 if (fd < 0) {
626 fprintf(stderr, "Unable to create temp file: %s\n", strerror(errno));
627 goto on_error;
628 }
629 // Unlink the file to avoid leaking
630 if (unlink(tmpfile) == -1)
631 fprintf(stderr, "Unlink %s failed: %s\n", tmpfile, strerror(errno));
632
633 if (write(fd, image, en - st) == -1) {
634 fprintf(stderr, "Failed to write to vDSO image: %s\n", strerror(errno));
635 close(fd);
636 goto on_error;
637 }
638 vdso_image_fd = fd;
639
640on_error:
641 if (image)
642 free(image);
643 // Always stop the iteration
644 return -1;
645}
646
647int bcc_elf_foreach_vdso_sym(bcc_elf_symcb callback, void *payload) {
648 Elf *elf;
649 static struct bcc_symbol_option default_option = {
650 .use_debug_file = 0,
651 .check_debug_file_crc = 0,
652 .use_symbol_type = (1 << STT_FUNC) | (1 << STT_GNU_IFUNC)
653 };
654
655 if (vdso_image_fd == -1) {
656 vdso_image_fd = -2;
657 bcc_procutils_each_module(getpid(), &find_vdso, NULL);
658 }
659 if (vdso_image_fd == -2)
660 return -1;
661
662 if (openelf_fd(vdso_image_fd, &elf) == -1)
663 return -1;
664
665 return listsymbols(elf, callback, payload, &default_option);
666}
667
Vicent Martib8f0f092016-04-20 13:24:54 +0200668#if 0
669#include <stdio.h>
670
671int main(int argc, char *argv[])
672{
Sasha Goldshtein01553852017-02-09 03:58:09 -0500673 uint64_t addr;
674 if (bcc_elf_findsym(argv[1], argv[2], -1, STT_FUNC, &addr) < 0)
675 return -1;
Vicent Martib8f0f092016-04-20 13:24:54 +0200676
Sasha Goldshtein01553852017-02-09 03:58:09 -0500677 printf("%s: %p\n", argv[2], (void *)addr);
678 return 0;
Vicent Martib8f0f092016-04-20 13:24:54 +0200679}
680#endif