diff options
Diffstat (limited to 'tools/perf/util/symbol.c')
-rw-r--r-- | tools/perf/util/symbol.c | 405 |
1 files changed, 331 insertions, 74 deletions
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 78c2efde01b7..16ddca202948 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c | |||
@@ -7,8 +7,23 @@ | |||
7 | #include <gelf.h> | 7 | #include <gelf.h> |
8 | #include <elf.h> | 8 | #include <elf.h> |
9 | 9 | ||
10 | #ifndef NO_DEMANGLE | ||
11 | #include <bfd.h> | ||
12 | #else | ||
13 | static inline | ||
14 | char *bfd_demangle(void __used *v, const char __used *c, int __used i) | ||
15 | { | ||
16 | return NULL; | ||
17 | } | ||
18 | #endif | ||
19 | |||
10 | const char *sym_hist_filter; | 20 | const char *sym_hist_filter; |
11 | 21 | ||
22 | #ifndef DMGL_PARAMS | ||
23 | #define DMGL_PARAMS (1 << 0) /* Include function args */ | ||
24 | #define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */ | ||
25 | #endif | ||
26 | |||
12 | static struct symbol *symbol__new(u64 start, u64 len, | 27 | static struct symbol *symbol__new(u64 start, u64 len, |
13 | const char *name, unsigned int priv_size, | 28 | const char *name, unsigned int priv_size, |
14 | u64 obj_start, int verbose) | 29 | u64 obj_start, int verbose) |
@@ -35,7 +50,7 @@ static struct symbol *symbol__new(u64 start, u64 len, | |||
35 | self = ((void *)self) + priv_size; | 50 | self = ((void *)self) + priv_size; |
36 | } | 51 | } |
37 | self->start = start; | 52 | self->start = start; |
38 | self->end = start + len - 1; | 53 | self->end = len ? start + len - 1 : start; |
39 | memcpy(self->name, name, namelen); | 54 | memcpy(self->name, name, namelen); |
40 | 55 | ||
41 | return self; | 56 | return self; |
@@ -48,8 +63,12 @@ static void symbol__delete(struct symbol *self, unsigned int priv_size) | |||
48 | 63 | ||
49 | static size_t symbol__fprintf(struct symbol *self, FILE *fp) | 64 | static size_t symbol__fprintf(struct symbol *self, FILE *fp) |
50 | { | 65 | { |
51 | return fprintf(fp, " %llx-%llx %s\n", | 66 | if (!self->module) |
67 | return fprintf(fp, " %llx-%llx %s\n", | ||
52 | self->start, self->end, self->name); | 68 | self->start, self->end, self->name); |
69 | else | ||
70 | return fprintf(fp, " %llx-%llx %s \t[%s]\n", | ||
71 | self->start, self->end, self->name, self->module->name); | ||
53 | } | 72 | } |
54 | 73 | ||
55 | struct dso *dso__new(const char *name, unsigned int sym_priv_size) | 74 | struct dso *dso__new(const char *name, unsigned int sym_priv_size) |
@@ -61,6 +80,7 @@ struct dso *dso__new(const char *name, unsigned int sym_priv_size) | |||
61 | self->syms = RB_ROOT; | 80 | self->syms = RB_ROOT; |
62 | self->sym_priv_size = sym_priv_size; | 81 | self->sym_priv_size = sym_priv_size; |
63 | self->find_symbol = dso__find_symbol; | 82 | self->find_symbol = dso__find_symbol; |
83 | self->slen_calculated = 0; | ||
64 | } | 84 | } |
65 | 85 | ||
66 | return self; | 86 | return self; |
@@ -146,6 +166,7 @@ static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int verb | |||
146 | char *line = NULL; | 166 | char *line = NULL; |
147 | size_t n; | 167 | size_t n; |
148 | FILE *file = fopen("/proc/kallsyms", "r"); | 168 | FILE *file = fopen("/proc/kallsyms", "r"); |
169 | int count = 0; | ||
149 | 170 | ||
150 | if (file == NULL) | 171 | if (file == NULL) |
151 | goto out_failure; | 172 | goto out_failure; |
@@ -188,8 +209,10 @@ static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int verb | |||
188 | 209 | ||
189 | if (filter && filter(self, sym)) | 210 | if (filter && filter(self, sym)) |
190 | symbol__delete(sym, self->sym_priv_size); | 211 | symbol__delete(sym, self->sym_priv_size); |
191 | else | 212 | else { |
192 | dso__insert_symbol(self, sym); | 213 | dso__insert_symbol(self, sym); |
214 | count++; | ||
215 | } | ||
193 | } | 216 | } |
194 | 217 | ||
195 | /* | 218 | /* |
@@ -212,7 +235,7 @@ static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int verb | |||
212 | free(line); | 235 | free(line); |
213 | fclose(file); | 236 | fclose(file); |
214 | 237 | ||
215 | return 0; | 238 | return count; |
216 | 239 | ||
217 | out_delete_line: | 240 | out_delete_line: |
218 | free(line); | 241 | free(line); |
@@ -307,6 +330,26 @@ static inline int elf_sym__is_function(const GElf_Sym *sym) | |||
307 | sym->st_size != 0; | 330 | sym->st_size != 0; |
308 | } | 331 | } |
309 | 332 | ||
333 | static inline int elf_sym__is_label(const GElf_Sym *sym) | ||
334 | { | ||
335 | return elf_sym__type(sym) == STT_NOTYPE && | ||
336 | sym->st_name != 0 && | ||
337 | sym->st_shndx != SHN_UNDEF && | ||
338 | sym->st_shndx != SHN_ABS; | ||
339 | } | ||
340 | |||
341 | static inline const char *elf_sec__name(const GElf_Shdr *shdr, | ||
342 | const Elf_Data *secstrs) | ||
343 | { | ||
344 | return secstrs->d_buf + shdr->sh_name; | ||
345 | } | ||
346 | |||
347 | static inline int elf_sec__is_text(const GElf_Shdr *shdr, | ||
348 | const Elf_Data *secstrs) | ||
349 | { | ||
350 | return strstr(elf_sec__name(shdr, secstrs), "text") != NULL; | ||
351 | } | ||
352 | |||
310 | static inline const char *elf_sym__name(const GElf_Sym *sym, | 353 | static inline const char *elf_sym__name(const GElf_Sym *sym, |
311 | const Elf_Data *symstrs) | 354 | const Elf_Data *symstrs) |
312 | { | 355 | { |
@@ -346,36 +389,61 @@ static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, | |||
346 | idx < nr_entries; \ | 389 | idx < nr_entries; \ |
347 | ++idx, pos = gelf_getrela(reldata, idx, &pos_mem)) | 390 | ++idx, pos = gelf_getrela(reldata, idx, &pos_mem)) |
348 | 391 | ||
349 | static int dso__synthesize_plt_symbols(struct dso *self, Elf *elf, | 392 | /* |
350 | GElf_Ehdr *ehdr, Elf_Scn *scn_dynsym, | 393 | * We need to check if we have a .dynsym, so that we can handle the |
351 | GElf_Shdr *shdr_dynsym, | 394 | * .plt, synthesizing its symbols, that aren't on the symtabs (be it |
352 | size_t dynsym_idx, int verbose) | 395 | * .dynsym or .symtab). |
396 | * And always look at the original dso, not at debuginfo packages, that | ||
397 | * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS). | ||
398 | */ | ||
399 | static int dso__synthesize_plt_symbols(struct dso *self, int verbose) | ||
353 | { | 400 | { |
354 | uint32_t nr_rel_entries, idx; | 401 | uint32_t nr_rel_entries, idx; |
355 | GElf_Sym sym; | 402 | GElf_Sym sym; |
356 | u64 plt_offset; | 403 | u64 plt_offset; |
357 | GElf_Shdr shdr_plt; | 404 | GElf_Shdr shdr_plt; |
358 | struct symbol *f; | 405 | struct symbol *f; |
359 | GElf_Shdr shdr_rel_plt; | 406 | GElf_Shdr shdr_rel_plt, shdr_dynsym; |
360 | Elf_Data *reldata, *syms, *symstrs; | 407 | Elf_Data *reldata, *syms, *symstrs; |
361 | Elf_Scn *scn_plt_rel, *scn_symstrs; | 408 | Elf_Scn *scn_plt_rel, *scn_symstrs, *scn_dynsym; |
409 | size_t dynsym_idx; | ||
410 | GElf_Ehdr ehdr; | ||
362 | char sympltname[1024]; | 411 | char sympltname[1024]; |
363 | int nr = 0, symidx; | 412 | Elf *elf; |
413 | int nr = 0, symidx, fd, err = 0; | ||
414 | |||
415 | fd = open(self->name, O_RDONLY); | ||
416 | if (fd < 0) | ||
417 | goto out; | ||
418 | |||
419 | elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); | ||
420 | if (elf == NULL) | ||
421 | goto out_close; | ||
364 | 422 | ||
365 | scn_plt_rel = elf_section_by_name(elf, ehdr, &shdr_rel_plt, | 423 | if (gelf_getehdr(elf, &ehdr) == NULL) |
424 | goto out_elf_end; | ||
425 | |||
426 | scn_dynsym = elf_section_by_name(elf, &ehdr, &shdr_dynsym, | ||
427 | ".dynsym", &dynsym_idx); | ||
428 | if (scn_dynsym == NULL) | ||
429 | goto out_elf_end; | ||
430 | |||
431 | scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt, | ||
366 | ".rela.plt", NULL); | 432 | ".rela.plt", NULL); |
367 | if (scn_plt_rel == NULL) { | 433 | if (scn_plt_rel == NULL) { |
368 | scn_plt_rel = elf_section_by_name(elf, ehdr, &shdr_rel_plt, | 434 | scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt, |
369 | ".rel.plt", NULL); | 435 | ".rel.plt", NULL); |
370 | if (scn_plt_rel == NULL) | 436 | if (scn_plt_rel == NULL) |
371 | return 0; | 437 | goto out_elf_end; |
372 | } | 438 | } |
373 | 439 | ||
440 | err = -1; | ||
441 | |||
374 | if (shdr_rel_plt.sh_link != dynsym_idx) | 442 | if (shdr_rel_plt.sh_link != dynsym_idx) |
375 | return 0; | 443 | goto out_elf_end; |
376 | 444 | ||
377 | if (elf_section_by_name(elf, ehdr, &shdr_plt, ".plt", NULL) == NULL) | 445 | if (elf_section_by_name(elf, &ehdr, &shdr_plt, ".plt", NULL) == NULL) |
378 | return 0; | 446 | goto out_elf_end; |
379 | 447 | ||
380 | /* | 448 | /* |
381 | * Fetch the relocation section to find the indexes to the GOT | 449 | * Fetch the relocation section to find the indexes to the GOT |
@@ -383,19 +451,19 @@ static int dso__synthesize_plt_symbols(struct dso *self, Elf *elf, | |||
383 | */ | 451 | */ |
384 | reldata = elf_getdata(scn_plt_rel, NULL); | 452 | reldata = elf_getdata(scn_plt_rel, NULL); |
385 | if (reldata == NULL) | 453 | if (reldata == NULL) |
386 | return -1; | 454 | goto out_elf_end; |
387 | 455 | ||
388 | syms = elf_getdata(scn_dynsym, NULL); | 456 | syms = elf_getdata(scn_dynsym, NULL); |
389 | if (syms == NULL) | 457 | if (syms == NULL) |
390 | return -1; | 458 | goto out_elf_end; |
391 | 459 | ||
392 | scn_symstrs = elf_getscn(elf, shdr_dynsym->sh_link); | 460 | scn_symstrs = elf_getscn(elf, shdr_dynsym.sh_link); |
393 | if (scn_symstrs == NULL) | 461 | if (scn_symstrs == NULL) |
394 | return -1; | 462 | goto out_elf_end; |
395 | 463 | ||
396 | symstrs = elf_getdata(scn_symstrs, NULL); | 464 | symstrs = elf_getdata(scn_symstrs, NULL); |
397 | if (symstrs == NULL) | 465 | if (symstrs == NULL) |
398 | return -1; | 466 | goto out_elf_end; |
399 | 467 | ||
400 | nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize; | 468 | nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize; |
401 | plt_offset = shdr_plt.sh_offset; | 469 | plt_offset = shdr_plt.sh_offset; |
@@ -414,7 +482,7 @@ static int dso__synthesize_plt_symbols(struct dso *self, Elf *elf, | |||
414 | f = symbol__new(plt_offset, shdr_plt.sh_entsize, | 482 | f = symbol__new(plt_offset, shdr_plt.sh_entsize, |
415 | sympltname, self->sym_priv_size, 0, verbose); | 483 | sympltname, self->sym_priv_size, 0, verbose); |
416 | if (!f) | 484 | if (!f) |
417 | return -1; | 485 | goto out_elf_end; |
418 | 486 | ||
419 | dso__insert_symbol(self, f); | 487 | dso__insert_symbol(self, f); |
420 | ++nr; | 488 | ++nr; |
@@ -432,25 +500,31 @@ static int dso__synthesize_plt_symbols(struct dso *self, Elf *elf, | |||
432 | f = symbol__new(plt_offset, shdr_plt.sh_entsize, | 500 | f = symbol__new(plt_offset, shdr_plt.sh_entsize, |
433 | sympltname, self->sym_priv_size, 0, verbose); | 501 | sympltname, self->sym_priv_size, 0, verbose); |
434 | if (!f) | 502 | if (!f) |
435 | return -1; | 503 | goto out_elf_end; |
436 | 504 | ||
437 | dso__insert_symbol(self, f); | 505 | dso__insert_symbol(self, f); |
438 | ++nr; | 506 | ++nr; |
439 | } | 507 | } |
440 | } else { | ||
441 | /* | ||
442 | * TODO: There are still one more shdr_rel_plt.sh_type | ||
443 | * I have to investigate, but probably should be ignored. | ||
444 | */ | ||
445 | } | 508 | } |
446 | 509 | ||
447 | return nr; | 510 | err = 0; |
511 | out_elf_end: | ||
512 | elf_end(elf); | ||
513 | out_close: | ||
514 | close(fd); | ||
515 | |||
516 | if (err == 0) | ||
517 | return nr; | ||
518 | out: | ||
519 | fprintf(stderr, "%s: problems reading %s PLT info.\n", | ||
520 | __func__, self->name); | ||
521 | return 0; | ||
448 | } | 522 | } |
449 | 523 | ||
450 | static int dso__load_sym(struct dso *self, int fd, const char *name, | 524 | static int dso__load_sym(struct dso *self, int fd, const char *name, |
451 | symbol_filter_t filter, int verbose) | 525 | symbol_filter_t filter, int verbose, struct module *mod) |
452 | { | 526 | { |
453 | Elf_Data *symstrs; | 527 | Elf_Data *symstrs, *secstrs; |
454 | uint32_t nr_syms; | 528 | uint32_t nr_syms; |
455 | int err = -1; | 529 | int err = -1; |
456 | uint32_t index; | 530 | uint32_t index; |
@@ -458,10 +532,9 @@ static int dso__load_sym(struct dso *self, int fd, const char *name, | |||
458 | GElf_Shdr shdr; | 532 | GElf_Shdr shdr; |
459 | Elf_Data *syms; | 533 | Elf_Data *syms; |
460 | GElf_Sym sym; | 534 | GElf_Sym sym; |
461 | Elf_Scn *sec, *sec_dynsym; | 535 | Elf_Scn *sec, *sec_strndx; |
462 | Elf *elf; | 536 | Elf *elf; |
463 | size_t dynsym_idx; | 537 | int nr = 0, kernel = !strcmp("[kernel]", self->name); |
464 | int nr = 0; | ||
465 | 538 | ||
466 | elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); | 539 | elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); |
467 | if (elf == NULL) { | 540 | if (elf == NULL) { |
@@ -477,32 +550,11 @@ static int dso__load_sym(struct dso *self, int fd, const char *name, | |||
477 | goto out_elf_end; | 550 | goto out_elf_end; |
478 | } | 551 | } |
479 | 552 | ||
480 | /* | ||
481 | * We need to check if we have a .dynsym, so that we can handle the | ||
482 | * .plt, synthesizing its symbols, that aren't on the symtabs (be it | ||
483 | * .dynsym or .symtab) | ||
484 | */ | ||
485 | sec_dynsym = elf_section_by_name(elf, &ehdr, &shdr, | ||
486 | ".dynsym", &dynsym_idx); | ||
487 | if (sec_dynsym != NULL) { | ||
488 | nr = dso__synthesize_plt_symbols(self, elf, &ehdr, | ||
489 | sec_dynsym, &shdr, | ||
490 | dynsym_idx, verbose); | ||
491 | if (nr < 0) | ||
492 | goto out_elf_end; | ||
493 | } | ||
494 | |||
495 | /* | ||
496 | * But if we have a full .symtab (that is a superset of .dynsym) we | ||
497 | * should add the symbols not in the .dynsyn | ||
498 | */ | ||
499 | sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL); | 553 | sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL); |
500 | if (sec == NULL) { | 554 | if (sec == NULL) { |
501 | if (sec_dynsym == NULL) | 555 | sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL); |
556 | if (sec == NULL) | ||
502 | goto out_elf_end; | 557 | goto out_elf_end; |
503 | |||
504 | sec = sec_dynsym; | ||
505 | gelf_getshdr(sec, &shdr); | ||
506 | } | 558 | } |
507 | 559 | ||
508 | syms = elf_getdata(sec, NULL); | 560 | syms = elf_getdata(sec, NULL); |
@@ -517,17 +569,34 @@ static int dso__load_sym(struct dso *self, int fd, const char *name, | |||
517 | if (symstrs == NULL) | 569 | if (symstrs == NULL) |
518 | goto out_elf_end; | 570 | goto out_elf_end; |
519 | 571 | ||
572 | sec_strndx = elf_getscn(elf, ehdr.e_shstrndx); | ||
573 | if (sec_strndx == NULL) | ||
574 | goto out_elf_end; | ||
575 | |||
576 | secstrs = elf_getdata(sec_strndx, NULL); | ||
577 | if (secstrs == NULL) | ||
578 | goto out_elf_end; | ||
579 | |||
520 | nr_syms = shdr.sh_size / shdr.sh_entsize; | 580 | nr_syms = shdr.sh_size / shdr.sh_entsize; |
521 | 581 | ||
522 | memset(&sym, 0, sizeof(sym)); | 582 | memset(&sym, 0, sizeof(sym)); |
523 | self->prelinked = elf_section_by_name(elf, &ehdr, &shdr, | 583 | if (!kernel) { |
524 | ".gnu.prelink_undo", | 584 | self->adjust_symbols = (ehdr.e_type == ET_EXEC || |
525 | NULL) != NULL; | 585 | elf_section_by_name(elf, &ehdr, &shdr, |
586 | ".gnu.prelink_undo", | ||
587 | NULL) != NULL); | ||
588 | } else self->adjust_symbols = 0; | ||
589 | |||
526 | elf_symtab__for_each_symbol(syms, nr_syms, index, sym) { | 590 | elf_symtab__for_each_symbol(syms, nr_syms, index, sym) { |
527 | struct symbol *f; | 591 | struct symbol *f; |
592 | const char *name; | ||
593 | char *demangled; | ||
528 | u64 obj_start; | 594 | u64 obj_start; |
595 | struct section *section = NULL; | ||
596 | int is_label = elf_sym__is_label(&sym); | ||
597 | const char *section_name; | ||
529 | 598 | ||
530 | if (!elf_sym__is_function(&sym)) | 599 | if (!is_label && !elf_sym__is_function(&sym)) |
531 | continue; | 600 | continue; |
532 | 601 | ||
533 | sec = elf_getscn(elf, sym.st_shndx); | 602 | sec = elf_getscn(elf, sym.st_shndx); |
@@ -535,9 +604,14 @@ static int dso__load_sym(struct dso *self, int fd, const char *name, | |||
535 | goto out_elf_end; | 604 | goto out_elf_end; |
536 | 605 | ||
537 | gelf_getshdr(sec, &shdr); | 606 | gelf_getshdr(sec, &shdr); |
607 | |||
608 | if (is_label && !elf_sec__is_text(&shdr, secstrs)) | ||
609 | continue; | ||
610 | |||
611 | section_name = elf_sec__name(&shdr, secstrs); | ||
538 | obj_start = sym.st_value; | 612 | obj_start = sym.st_value; |
539 | 613 | ||
540 | if (self->prelinked) { | 614 | if (self->adjust_symbols) { |
541 | if (verbose >= 2) | 615 | if (verbose >= 2) |
542 | printf("adjusting symbol: st_value: %Lx sh_addr: %Lx sh_offset: %Lx\n", | 616 | printf("adjusting symbol: st_value: %Lx sh_addr: %Lx sh_offset: %Lx\n", |
543 | (u64)sym.st_value, (u64)shdr.sh_addr, (u64)shdr.sh_offset); | 617 | (u64)sym.st_value, (u64)shdr.sh_addr, (u64)shdr.sh_offset); |
@@ -545,15 +619,36 @@ static int dso__load_sym(struct dso *self, int fd, const char *name, | |||
545 | sym.st_value -= shdr.sh_addr - shdr.sh_offset; | 619 | sym.st_value -= shdr.sh_addr - shdr.sh_offset; |
546 | } | 620 | } |
547 | 621 | ||
548 | f = symbol__new(sym.st_value, sym.st_size, | 622 | if (mod) { |
549 | elf_sym__name(&sym, symstrs), | 623 | section = mod->sections->find_section(mod->sections, section_name); |
624 | if (section) | ||
625 | sym.st_value += section->vma; | ||
626 | else { | ||
627 | fprintf(stderr, "dso__load_sym() module %s lookup of %s failed\n", | ||
628 | mod->name, section_name); | ||
629 | goto out_elf_end; | ||
630 | } | ||
631 | } | ||
632 | /* | ||
633 | * We need to figure out if the object was created from C++ sources | ||
634 | * DWARF DW_compile_unit has this, but we don't always have access | ||
635 | * to it... | ||
636 | */ | ||
637 | name = elf_sym__name(&sym, symstrs); | ||
638 | demangled = bfd_demangle(NULL, name, DMGL_PARAMS | DMGL_ANSI); | ||
639 | if (demangled != NULL) | ||
640 | name = demangled; | ||
641 | |||
642 | f = symbol__new(sym.st_value, sym.st_size, name, | ||
550 | self->sym_priv_size, obj_start, verbose); | 643 | self->sym_priv_size, obj_start, verbose); |
644 | free(demangled); | ||
551 | if (!f) | 645 | if (!f) |
552 | goto out_elf_end; | 646 | goto out_elf_end; |
553 | 647 | ||
554 | if (filter && filter(self, f)) | 648 | if (filter && filter(self, f)) |
555 | symbol__delete(f, self->sym_priv_size); | 649 | symbol__delete(f, self->sym_priv_size); |
556 | else { | 650 | else { |
651 | f->module = mod; | ||
557 | dso__insert_symbol(self, f); | 652 | dso__insert_symbol(self, f); |
558 | nr++; | 653 | nr++; |
559 | } | 654 | } |
@@ -566,10 +661,69 @@ out_close: | |||
566 | return err; | 661 | return err; |
567 | } | 662 | } |
568 | 663 | ||
664 | #define BUILD_ID_SIZE 128 | ||
665 | |||
666 | static char *dso__read_build_id(struct dso *self, int verbose) | ||
667 | { | ||
668 | int i; | ||
669 | GElf_Ehdr ehdr; | ||
670 | GElf_Shdr shdr; | ||
671 | Elf_Data *build_id_data; | ||
672 | Elf_Scn *sec; | ||
673 | char *build_id = NULL, *bid; | ||
674 | unsigned char *raw; | ||
675 | Elf *elf; | ||
676 | int fd = open(self->name, O_RDONLY); | ||
677 | |||
678 | if (fd < 0) | ||
679 | goto out; | ||
680 | |||
681 | elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); | ||
682 | if (elf == NULL) { | ||
683 | if (verbose) | ||
684 | fprintf(stderr, "%s: cannot read %s ELF file.\n", | ||
685 | __func__, self->name); | ||
686 | goto out_close; | ||
687 | } | ||
688 | |||
689 | if (gelf_getehdr(elf, &ehdr) == NULL) { | ||
690 | if (verbose) | ||
691 | fprintf(stderr, "%s: cannot get elf header.\n", __func__); | ||
692 | goto out_elf_end; | ||
693 | } | ||
694 | |||
695 | sec = elf_section_by_name(elf, &ehdr, &shdr, ".note.gnu.build-id", NULL); | ||
696 | if (sec == NULL) | ||
697 | goto out_elf_end; | ||
698 | |||
699 | build_id_data = elf_getdata(sec, NULL); | ||
700 | if (build_id_data == NULL) | ||
701 | goto out_elf_end; | ||
702 | build_id = malloc(BUILD_ID_SIZE); | ||
703 | if (build_id == NULL) | ||
704 | goto out_elf_end; | ||
705 | raw = build_id_data->d_buf + 16; | ||
706 | bid = build_id; | ||
707 | |||
708 | for (i = 0; i < 20; ++i) { | ||
709 | sprintf(bid, "%02x", *raw); | ||
710 | ++raw; | ||
711 | bid += 2; | ||
712 | } | ||
713 | if (verbose) | ||
714 | printf("%s(%s): %s\n", __func__, self->name, build_id); | ||
715 | out_elf_end: | ||
716 | elf_end(elf); | ||
717 | out_close: | ||
718 | close(fd); | ||
719 | out: | ||
720 | return build_id; | ||
721 | } | ||
722 | |||
569 | int dso__load(struct dso *self, symbol_filter_t filter, int verbose) | 723 | int dso__load(struct dso *self, symbol_filter_t filter, int verbose) |
570 | { | 724 | { |
571 | int size = strlen(self->name) + sizeof("/usr/lib/debug%s.debug"); | 725 | int size = PATH_MAX; |
572 | char *name = malloc(size); | 726 | char *name = malloc(size), *build_id = NULL; |
573 | int variant = 0; | 727 | int variant = 0; |
574 | int ret = -1; | 728 | int ret = -1; |
575 | int fd; | 729 | int fd; |
@@ -577,7 +731,7 @@ int dso__load(struct dso *self, symbol_filter_t filter, int verbose) | |||
577 | if (!name) | 731 | if (!name) |
578 | return -1; | 732 | return -1; |
579 | 733 | ||
580 | self->prelinked = 0; | 734 | self->adjust_symbols = 0; |
581 | 735 | ||
582 | if (strncmp(self->name, "/tmp/perf-", 10) == 0) | 736 | if (strncmp(self->name, "/tmp/perf-", 10) == 0) |
583 | return dso__load_perf_map(self, filter, verbose); | 737 | return dso__load_perf_map(self, filter, verbose); |
@@ -591,7 +745,18 @@ more: | |||
591 | case 1: /* Ubuntu */ | 745 | case 1: /* Ubuntu */ |
592 | snprintf(name, size, "/usr/lib/debug%s", self->name); | 746 | snprintf(name, size, "/usr/lib/debug%s", self->name); |
593 | break; | 747 | break; |
594 | case 2: /* Sane people */ | 748 | case 2: |
749 | build_id = dso__read_build_id(self, verbose); | ||
750 | if (build_id != NULL) { | ||
751 | snprintf(name, size, | ||
752 | "/usr/lib/debug/.build-id/%.2s/%s.debug", | ||
753 | build_id, build_id + 2); | ||
754 | free(build_id); | ||
755 | break; | ||
756 | } | ||
757 | variant++; | ||
758 | /* Fall thru */ | ||
759 | case 3: /* Sane people */ | ||
595 | snprintf(name, size, "%s", self->name); | 760 | snprintf(name, size, "%s", self->name); |
596 | break; | 761 | break; |
597 | 762 | ||
@@ -603,7 +768,7 @@ more: | |||
603 | fd = open(name, O_RDONLY); | 768 | fd = open(name, O_RDONLY); |
604 | } while (fd < 0); | 769 | } while (fd < 0); |
605 | 770 | ||
606 | ret = dso__load_sym(self, fd, name, filter, verbose); | 771 | ret = dso__load_sym(self, fd, name, filter, verbose, NULL); |
607 | close(fd); | 772 | close(fd); |
608 | 773 | ||
609 | /* | 774 | /* |
@@ -612,11 +777,96 @@ more: | |||
612 | if (!ret) | 777 | if (!ret) |
613 | goto more; | 778 | goto more; |
614 | 779 | ||
780 | if (ret > 0) { | ||
781 | int nr_plt = dso__synthesize_plt_symbols(self, verbose); | ||
782 | if (nr_plt > 0) | ||
783 | ret += nr_plt; | ||
784 | } | ||
615 | out: | 785 | out: |
616 | free(name); | 786 | free(name); |
617 | return ret; | 787 | return ret; |
618 | } | 788 | } |
619 | 789 | ||
790 | static int dso__load_module(struct dso *self, struct mod_dso *mods, const char *name, | ||
791 | symbol_filter_t filter, int verbose) | ||
792 | { | ||
793 | struct module *mod = mod_dso__find_module(mods, name); | ||
794 | int err = 0, fd; | ||
795 | |||
796 | if (mod == NULL || !mod->active) | ||
797 | return err; | ||
798 | |||
799 | fd = open(mod->path, O_RDONLY); | ||
800 | |||
801 | if (fd < 0) | ||
802 | return err; | ||
803 | |||
804 | err = dso__load_sym(self, fd, name, filter, verbose, mod); | ||
805 | close(fd); | ||
806 | |||
807 | return err; | ||
808 | } | ||
809 | |||
810 | int dso__load_modules(struct dso *self, symbol_filter_t filter, int verbose) | ||
811 | { | ||
812 | struct mod_dso *mods = mod_dso__new_dso("modules"); | ||
813 | struct module *pos; | ||
814 | struct rb_node *next; | ||
815 | int err; | ||
816 | |||
817 | err = mod_dso__load_modules(mods); | ||
818 | |||
819 | if (err <= 0) | ||
820 | return err; | ||
821 | |||
822 | /* | ||
823 | * Iterate over modules, and load active symbols. | ||
824 | */ | ||
825 | next = rb_first(&mods->mods); | ||
826 | while (next) { | ||
827 | pos = rb_entry(next, struct module, rb_node); | ||
828 | err = dso__load_module(self, mods, pos->name, filter, verbose); | ||
829 | |||
830 | if (err < 0) | ||
831 | break; | ||
832 | |||
833 | next = rb_next(&pos->rb_node); | ||
834 | } | ||
835 | |||
836 | if (err < 0) { | ||
837 | mod_dso__delete_modules(mods); | ||
838 | mod_dso__delete_self(mods); | ||
839 | } | ||
840 | |||
841 | return err; | ||
842 | } | ||
843 | |||
844 | static inline void dso__fill_symbol_holes(struct dso *self) | ||
845 | { | ||
846 | struct symbol *prev = NULL; | ||
847 | struct rb_node *nd; | ||
848 | |||
849 | for (nd = rb_last(&self->syms); nd; nd = rb_prev(nd)) { | ||
850 | struct symbol *pos = rb_entry(nd, struct symbol, rb_node); | ||
851 | |||
852 | if (prev) { | ||
853 | u64 hole = 0; | ||
854 | int alias = pos->start == prev->start; | ||
855 | |||
856 | if (!alias) | ||
857 | hole = prev->start - pos->end - 1; | ||
858 | |||
859 | if (hole || alias) { | ||
860 | if (alias) | ||
861 | pos->end = prev->end; | ||
862 | else if (hole) | ||
863 | pos->end = prev->start - 1; | ||
864 | } | ||
865 | } | ||
866 | prev = pos; | ||
867 | } | ||
868 | } | ||
869 | |||
620 | static int dso__load_vmlinux(struct dso *self, const char *vmlinux, | 870 | static int dso__load_vmlinux(struct dso *self, const char *vmlinux, |
621 | symbol_filter_t filter, int verbose) | 871 | symbol_filter_t filter, int verbose) |
622 | { | 872 | { |
@@ -625,21 +875,28 @@ static int dso__load_vmlinux(struct dso *self, const char *vmlinux, | |||
625 | if (fd < 0) | 875 | if (fd < 0) |
626 | return -1; | 876 | return -1; |
627 | 877 | ||
628 | err = dso__load_sym(self, fd, vmlinux, filter, verbose); | 878 | err = dso__load_sym(self, fd, vmlinux, filter, verbose, NULL); |
879 | |||
880 | if (err > 0) | ||
881 | dso__fill_symbol_holes(self); | ||
882 | |||
629 | close(fd); | 883 | close(fd); |
630 | 884 | ||
631 | return err; | 885 | return err; |
632 | } | 886 | } |
633 | 887 | ||
634 | int dso__load_kernel(struct dso *self, const char *vmlinux, | 888 | int dso__load_kernel(struct dso *self, const char *vmlinux, |
635 | symbol_filter_t filter, int verbose) | 889 | symbol_filter_t filter, int verbose, int modules) |
636 | { | 890 | { |
637 | int err = -1; | 891 | int err = -1; |
638 | 892 | ||
639 | if (vmlinux) | 893 | if (vmlinux) { |
640 | err = dso__load_vmlinux(self, vmlinux, filter, verbose); | 894 | err = dso__load_vmlinux(self, vmlinux, filter, verbose); |
895 | if (err > 0 && modules) | ||
896 | err = dso__load_modules(self, filter, verbose); | ||
897 | } | ||
641 | 898 | ||
642 | if (err < 0) | 899 | if (err <= 0) |
643 | err = dso__load_kallsyms(self, filter, verbose); | 900 | err = dso__load_kallsyms(self, filter, verbose); |
644 | 901 | ||
645 | return err; | 902 | return err; |