1 /* 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 */ 16 #include <sys/types.h> 17 #include <sys/stat.h> 18 #include <sys/mman.h> 19 #include <errno.h> 20 #include <fcntl.h> 21 #include <unistd.h> 22 #include <string.h> 23 #include <libgen.h> 24 #include <stdio.h> 25 #include <stdlib.h> 26 #include <limits.h> 27 28 #include <gelf.h> 29 #include "bcc_elf.h" 30 #include "bcc_proc.h" 31 #include "bcc_syms.h" 32 33 #define NT_STAPSDT 3 34 #define ELF_ST_TYPE(x) (((uint32_t) x) & 0xf) 35 36 static int openelf_fd(int fd, Elf **elf_out) { 37 if (elf_version(EV_CURRENT) == EV_NONE) 38 return -1; 39 40 *elf_out = elf_begin(fd, ELF_C_READ, 0); 41 if (*elf_out == NULL) 42 return -1; 43 44 return 0; 45 } 46 47 static int openelf(const char *path, Elf **elf_out, int *fd_out) { 48 *fd_out = open(path, O_RDONLY); 49 if (*fd_out < 0) 50 return -1; 51 52 if (openelf_fd(*fd_out, elf_out) == -1) { 53 close(*fd_out); 54 return -1; 55 } 56 57 return 0; 58 } 59 60 static 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 } 73 74 probe->provider = desc; 75 desc += strlen(desc) + 1; 76 77 probe->name = desc; 78 desc += strlen(desc) + 1; 79 80 probe->arg_fmt = desc; 81 desc += strlen(desc) + 1; 82 83 return desc; 84 } 85 86 static int do_note_segment(Elf_Scn *section, int elf_class, 87 bcc_elf_probecb callback, const char *binpath, 88 uint64_t first_inst_offset, void *payload) { 89 Elf_Data *data = NULL; 90 91 while ((data = elf_getdata(section, data)) != 0) { 92 size_t offset = 0; 93 GElf_Nhdr hdr; 94 size_t name_off, desc_off; 95 96 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; 100 101 if (hdr.n_type != NT_STAPSDT) 102 continue; 103 104 if (hdr.n_namesz != 8) 105 continue; 106 107 if (memcmp((const char *)data->d_buf + name_off, "stapsdt", 8) != 0) 108 continue; 109 110 desc = (const char *)data->d_buf + desc_off; 111 desc_end = desc + hdr.n_descsz; 112 113 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 } 121 } 122 } 123 return 0; 124 } 125 126 static 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); 131 uint64_t first_inst_offset = 0; 132 133 if (elf_getshdrstrndx(e, &stridx) != 0) 134 return -1; 135 136 // 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 151 while ((section = elf_nextscn(e, section)) != 0) { 152 GElf_Shdr header; 153 char *name; 154 155 if (!gelf_getshdr(section, &header)) 156 continue; 157 158 if (header.sh_type != SHT_NOTE) 159 continue; 160 161 name = elf_strptr(e, stridx, header.sh_name); 162 if (name && !strcmp(name, ".note.stapsdt")) { 163 if (do_note_segment(section, elf_class, callback, binpath, 164 first_inst_offset, payload) < 0) 165 return -1; 166 } 167 } 168 169 return 0; 170 } 171 172 int bcc_elf_foreach_usdt(const char *path, bcc_elf_probecb callback, 173 void *payload) { 174 Elf *e; 175 int fd, res; 176 177 if (openelf(path, &e, &fd) < 0) 178 return -1; 179 180 res = listprobes(e, callback, path, payload); 181 elf_end(e); 182 close(fd); 183 184 return res; 185 } 186 187 static int list_in_scn(Elf *e, Elf_Scn *section, size_t stridx, size_t symsize, 188 struct bcc_symbol_option *option, 189 bcc_elf_symcb callback, void *payload) { 190 Elf_Data *data = NULL; 191 192 while ((data = elf_getdata(section, data)) != 0) { 193 size_t i, symcount = data->d_size / symsize; 194 195 if (data->d_size % symsize) 196 return -1; 197 198 for (i = 0; i < symcount; ++i) { 199 GElf_Sym sym; 200 const char *name; 201 202 if (!gelf_getsym(data, (int)i, &sym)) 203 continue; 204 205 if ((name = elf_strptr(e, stridx, sym.st_name)) == NULL) 206 continue; 207 if (name[0] == 0) 208 continue; 209 210 if (sym.st_value == 0) 211 continue; 212 213 uint32_t st_type = ELF_ST_TYPE(sym.st_info); 214 if (!(option->use_symbol_type & (1 << st_type))) 215 continue; 216 217 if (callback(name, sym.st_value, sym.st_size, payload) < 0) 218 return 1; // signal termination to caller 219 } 220 } 221 222 return 0; 223 } 224 225 static int listsymbols(Elf *e, bcc_elf_symcb callback, void *payload, 226 struct bcc_symbol_option *option) { 227 Elf_Scn *section = NULL; 228 229 while ((section = elf_nextscn(e, section)) != 0) { 230 GElf_Shdr header; 231 232 if (!gelf_getshdr(section, &header)) 233 continue; 234 235 if (header.sh_type != SHT_SYMTAB && header.sh_type != SHT_DYNSYM) 236 continue; 237 238 int rc = list_in_scn(e, section, header.sh_link, header.sh_entsize, 239 option, callback, payload); 240 if (rc == 1) 241 break; // callback signaled termination 242 243 if (rc < 0) 244 return rc; 245 } 246 247 return 0; 248 } 249 250 static 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 272 static 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 288 static int find_buildid(Elf *e, char *buildid) { 289 Elf_Data *data = get_section_elf_data(e, ".note.gnu.build-id"); 290 if (!data || data->d_size <= 16 || strcmp((char *)data->d_buf + 12, "GNU")) 291 return 0; 292 293 char *buf = (char *)data->d_buf + 16; 294 size_t length = data->d_size - 16; 295 size_t i = 0; 296 for (i = 0; i < length; ++i) { 297 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 305 static 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 370 static 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 380 if (fstat(fd, &st) < 0) { 381 close(fd); 382 return 0; 383 } 384 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 398 static char *find_debug_via_debuglink(Elf *e, const char *binpath, 399 int check_crc) { 400 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 412 // 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. 416 snprintf(fullpath, sizeof(fullpath),"%s/%s", bindir, name); 417 if (strcmp(fullpath, binpath) != 0 && access(fullpath, F_OK) != -1) { 418 res = strdup(fullpath); 419 goto DONE; 420 } 421 422 // Search for the file in 'binpath'/.debug 423 snprintf(fullpath, sizeof(fullpath), "%s/.debug/%s", bindir, name); 424 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' 430 snprintf(fullpath, sizeof(fullpath), "/usr/lib/debug%s/%s", bindir, name); 431 if (access(fullpath, F_OK) != -1) { 432 res = strdup(fullpath); 433 goto DONE; 434 } 435 436 DONE: 437 free(bindir); 438 if (res && check_crc && !verify_checksum(res, crc)) 439 return NULL; 440 return res; 441 } 442 443 static 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. 454 snprintf(fullpath, sizeof(fullpath), "/usr/lib/debug/.build-id/%c%c/%s.debug", 455 buildid[0], buildid[1], buildid + 2); 456 if (access(fullpath, F_OK) != -1) { 457 return strdup(fullpath); 458 } 459 460 return NULL; 461 } 462 463 static int foreach_sym_core(const char *path, bcc_elf_symcb callback, 464 struct bcc_symbol_option *option, void *payload, 465 int is_debug_file) { 466 Elf *e; 467 int fd, res; 468 char *debug_file; 469 470 if (!option) 471 return -1; 472 473 if (openelf(path, &e, &fd) < 0) 474 return -1; 475 476 // 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 480 if (option->use_debug_file && !is_debug_file) { 481 // 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) 485 debug_file = find_debug_via_debuglink(e, path, 486 option->check_debug_file_crc); 487 if (debug_file) { 488 foreach_sym_core(debug_file, callback, option, payload, 1); 489 free(debug_file); 490 } 491 } 492 493 res = listsymbols(e, callback, payload, option); 494 elf_end(e); 495 close(fd); 496 return res; 497 } 498 499 int bcc_elf_foreach_sym(const char *path, bcc_elf_symcb callback, 500 void *option, void *payload) { 501 return foreach_sym_core( 502 path, callback, (struct bcc_symbol_option*)option, payload, 0); 503 } 504 505 int 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 532 exit: 533 if (e) 534 elf_end(e); 535 if (fd >= 0) 536 close(fd); 537 return err; 538 } 539 540 int 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 567 exit: 568 if (e) 569 elf_end(e); 570 if (fd >= 0) 571 close(fd); 572 return err; 573 } 574 575 int bcc_elf_get_type(const char *path) { 576 Elf *e; 577 GElf_Ehdr hdr; 578 int fd; 579 void* res = NULL; 580 581 if (openelf(path, &e, &fd) < 0) 582 return -1; 583 584 res = (void*)gelf_getehdr(e, &hdr); 585 elf_end(e); 586 close(fd); 587 588 if (!res) 589 return -1; 590 else 591 return hdr.e_type; 592 } 593 594 int bcc_elf_is_exe(const char *path) { 595 return (bcc_elf_get_type(path) != -1) && (access(path, X_OK) == 0); 596 } 597 598 int bcc_elf_is_shared_obj(const char *path) { 599 return bcc_elf_get_type(path) == ET_DYN; 600 } 601 602 int 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 609 static int vdso_image_fd = -1; 610 611 static 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 640 on_error: 641 if (image) 642 free(image); 643 // Always stop the iteration 644 return -1; 645 } 646 647 int 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 668 #if 0 669 #include <stdio.h> 670 671 int main(int argc, char *argv[]) 672 { 673 uint64_t addr; 674 if (bcc_elf_findsym(argv[1], argv[2], -1, STT_FUNC, &addr) < 0) 675 return -1; 676 677 printf("%s: %p\n", argv[2], (void *)addr); 678 return 0; 679 } 680 #endif 681