aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util/symbol.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util/symbol.c')
-rw-r--r--tools/perf/util/symbol.c145
1 files changed, 90 insertions, 55 deletions
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 4683b67b5ee4..28106059bf12 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -6,9 +6,15 @@
6#include <libelf.h> 6#include <libelf.h>
7#include <gelf.h> 7#include <gelf.h>
8#include <elf.h> 8#include <elf.h>
9#include <bfd.h>
9 10
10const char *sym_hist_filter; 11const char *sym_hist_filter;
11 12
13#ifndef DMGL_PARAMS
14#define DMGL_PARAMS (1 << 0) /* Include function args */
15#define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */
16#endif
17
12static struct symbol *symbol__new(u64 start, u64 len, 18static struct symbol *symbol__new(u64 start, u64 len,
13 const char *name, unsigned int priv_size, 19 const char *name, unsigned int priv_size,
14 u64 obj_start, int verbose) 20 u64 obj_start, int verbose)
@@ -65,6 +71,7 @@ struct dso *dso__new(const char *name, unsigned int sym_priv_size)
65 self->syms = RB_ROOT; 71 self->syms = RB_ROOT;
66 self->sym_priv_size = sym_priv_size; 72 self->sym_priv_size = sym_priv_size;
67 self->find_symbol = dso__find_symbol; 73 self->find_symbol = dso__find_symbol;
74 self->slen_calculated = 0;
68 } 75 }
69 76
70 return self; 77 return self;
@@ -373,36 +380,61 @@ static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
373 idx < nr_entries; \ 380 idx < nr_entries; \
374 ++idx, pos = gelf_getrela(reldata, idx, &pos_mem)) 381 ++idx, pos = gelf_getrela(reldata, idx, &pos_mem))
375 382
376static int dso__synthesize_plt_symbols(struct dso *self, Elf *elf, 383/*
377 GElf_Ehdr *ehdr, Elf_Scn *scn_dynsym, 384 * We need to check if we have a .dynsym, so that we can handle the
378 GElf_Shdr *shdr_dynsym, 385 * .plt, synthesizing its symbols, that aren't on the symtabs (be it
379 size_t dynsym_idx, int verbose) 386 * .dynsym or .symtab).
387 * And always look at the original dso, not at debuginfo packages, that
388 * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS).
389 */
390static int dso__synthesize_plt_symbols(struct dso *self, int verbose)
380{ 391{
381 uint32_t nr_rel_entries, idx; 392 uint32_t nr_rel_entries, idx;
382 GElf_Sym sym; 393 GElf_Sym sym;
383 u64 plt_offset; 394 u64 plt_offset;
384 GElf_Shdr shdr_plt; 395 GElf_Shdr shdr_plt;
385 struct symbol *f; 396 struct symbol *f;
386 GElf_Shdr shdr_rel_plt; 397 GElf_Shdr shdr_rel_plt, shdr_dynsym;
387 Elf_Data *reldata, *syms, *symstrs; 398 Elf_Data *reldata, *syms, *symstrs;
388 Elf_Scn *scn_plt_rel, *scn_symstrs; 399 Elf_Scn *scn_plt_rel, *scn_symstrs, *scn_dynsym;
400 size_t dynsym_idx;
401 GElf_Ehdr ehdr;
389 char sympltname[1024]; 402 char sympltname[1024];
390 int nr = 0, symidx; 403 Elf *elf;
404 int nr = 0, symidx, fd, err = 0;
405
406 fd = open(self->name, O_RDONLY);
407 if (fd < 0)
408 goto out;
409
410 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
411 if (elf == NULL)
412 goto out_close;
413
414 if (gelf_getehdr(elf, &ehdr) == NULL)
415 goto out_elf_end;
416
417 scn_dynsym = elf_section_by_name(elf, &ehdr, &shdr_dynsym,
418 ".dynsym", &dynsym_idx);
419 if (scn_dynsym == NULL)
420 goto out_elf_end;
391 421
392 scn_plt_rel = elf_section_by_name(elf, ehdr, &shdr_rel_plt, 422 scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
393 ".rela.plt", NULL); 423 ".rela.plt", NULL);
394 if (scn_plt_rel == NULL) { 424 if (scn_plt_rel == NULL) {
395 scn_plt_rel = elf_section_by_name(elf, ehdr, &shdr_rel_plt, 425 scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
396 ".rel.plt", NULL); 426 ".rel.plt", NULL);
397 if (scn_plt_rel == NULL) 427 if (scn_plt_rel == NULL)
398 return 0; 428 goto out_elf_end;
399 } 429 }
400 430
431 err = -1;
432
401 if (shdr_rel_plt.sh_link != dynsym_idx) 433 if (shdr_rel_plt.sh_link != dynsym_idx)
402 return 0; 434 goto out_elf_end;
403 435
404 if (elf_section_by_name(elf, ehdr, &shdr_plt, ".plt", NULL) == NULL) 436 if (elf_section_by_name(elf, &ehdr, &shdr_plt, ".plt", NULL) == NULL)
405 return 0; 437 goto out_elf_end;
406 438
407 /* 439 /*
408 * Fetch the relocation section to find the indexes to the GOT 440 * Fetch the relocation section to find the indexes to the GOT
@@ -410,19 +442,19 @@ static int dso__synthesize_plt_symbols(struct dso *self, Elf *elf,
410 */ 442 */
411 reldata = elf_getdata(scn_plt_rel, NULL); 443 reldata = elf_getdata(scn_plt_rel, NULL);
412 if (reldata == NULL) 444 if (reldata == NULL)
413 return -1; 445 goto out_elf_end;
414 446
415 syms = elf_getdata(scn_dynsym, NULL); 447 syms = elf_getdata(scn_dynsym, NULL);
416 if (syms == NULL) 448 if (syms == NULL)
417 return -1; 449 goto out_elf_end;
418 450
419 scn_symstrs = elf_getscn(elf, shdr_dynsym->sh_link); 451 scn_symstrs = elf_getscn(elf, shdr_dynsym.sh_link);
420 if (scn_symstrs == NULL) 452 if (scn_symstrs == NULL)
421 return -1; 453 goto out_elf_end;
422 454
423 symstrs = elf_getdata(scn_symstrs, NULL); 455 symstrs = elf_getdata(scn_symstrs, NULL);
424 if (symstrs == NULL) 456 if (symstrs == NULL)
425 return -1; 457 goto out_elf_end;
426 458
427 nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize; 459 nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize;
428 plt_offset = shdr_plt.sh_offset; 460 plt_offset = shdr_plt.sh_offset;
@@ -441,7 +473,7 @@ static int dso__synthesize_plt_symbols(struct dso *self, Elf *elf,
441 f = symbol__new(plt_offset, shdr_plt.sh_entsize, 473 f = symbol__new(plt_offset, shdr_plt.sh_entsize,
442 sympltname, self->sym_priv_size, 0, verbose); 474 sympltname, self->sym_priv_size, 0, verbose);
443 if (!f) 475 if (!f)
444 return -1; 476 goto out_elf_end;
445 477
446 dso__insert_symbol(self, f); 478 dso__insert_symbol(self, f);
447 ++nr; 479 ++nr;
@@ -459,19 +491,25 @@ static int dso__synthesize_plt_symbols(struct dso *self, Elf *elf,
459 f = symbol__new(plt_offset, shdr_plt.sh_entsize, 491 f = symbol__new(plt_offset, shdr_plt.sh_entsize,
460 sympltname, self->sym_priv_size, 0, verbose); 492 sympltname, self->sym_priv_size, 0, verbose);
461 if (!f) 493 if (!f)
462 return -1; 494 goto out_elf_end;
463 495
464 dso__insert_symbol(self, f); 496 dso__insert_symbol(self, f);
465 ++nr; 497 ++nr;
466 } 498 }
467 } else {
468 /*
469 * TODO: There are still one more shdr_rel_plt.sh_type
470 * I have to investigate, but probably should be ignored.
471 */
472 } 499 }
473 500
474 return nr; 501 err = 0;
502out_elf_end:
503 elf_end(elf);
504out_close:
505 close(fd);
506
507 if (err == 0)
508 return nr;
509out:
510 fprintf(stderr, "%s: problems reading %s PLT info.\n",
511 __func__, self->name);
512 return 0;
475} 513}
476 514
477static int dso__load_sym(struct dso *self, int fd, const char *name, 515static int dso__load_sym(struct dso *self, int fd, const char *name,
@@ -485,10 +523,9 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
485 GElf_Shdr shdr; 523 GElf_Shdr shdr;
486 Elf_Data *syms; 524 Elf_Data *syms;
487 GElf_Sym sym; 525 GElf_Sym sym;
488 Elf_Scn *sec, *sec_dynsym, *sec_strndx; 526 Elf_Scn *sec, *sec_strndx;
489 Elf *elf; 527 Elf *elf;
490 size_t dynsym_idx; 528 int nr = 0, kernel = !strcmp("[kernel]", self->name);
491 int nr = 0;
492 529
493 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); 530 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
494 if (elf == NULL) { 531 if (elf == NULL) {
@@ -504,32 +541,11 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
504 goto out_elf_end; 541 goto out_elf_end;
505 } 542 }
506 543
507 /*
508 * We need to check if we have a .dynsym, so that we can handle the
509 * .plt, synthesizing its symbols, that aren't on the symtabs (be it
510 * .dynsym or .symtab)
511 */
512 sec_dynsym = elf_section_by_name(elf, &ehdr, &shdr,
513 ".dynsym", &dynsym_idx);
514 if (sec_dynsym != NULL) {
515 nr = dso__synthesize_plt_symbols(self, elf, &ehdr,
516 sec_dynsym, &shdr,
517 dynsym_idx, verbose);
518 if (nr < 0)
519 goto out_elf_end;
520 }
521
522 /*
523 * But if we have a full .symtab (that is a superset of .dynsym) we
524 * should add the symbols not in the .dynsyn
525 */
526 sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL); 544 sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL);
527 if (sec == NULL) { 545 if (sec == NULL) {
528 if (sec_dynsym == NULL) 546 sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL);
547 if (sec == NULL)
529 goto out_elf_end; 548 goto out_elf_end;
530
531 sec = sec_dynsym;
532 gelf_getshdr(sec, &shdr);
533 } 549 }
534 550
535 syms = elf_getdata(sec, NULL); 551 syms = elf_getdata(sec, NULL);
@@ -555,12 +571,17 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
555 nr_syms = shdr.sh_size / shdr.sh_entsize; 571 nr_syms = shdr.sh_size / shdr.sh_entsize;
556 572
557 memset(&sym, 0, sizeof(sym)); 573 memset(&sym, 0, sizeof(sym));
558 self->adjust_symbols = (ehdr.e_type == ET_EXEC || 574 if (!kernel) {
575 self->adjust_symbols = (ehdr.e_type == ET_EXEC ||
559 elf_section_by_name(elf, &ehdr, &shdr, 576 elf_section_by_name(elf, &ehdr, &shdr,
560 ".gnu.prelink_undo", 577 ".gnu.prelink_undo",
561 NULL) != NULL); 578 NULL) != NULL);
579 } else self->adjust_symbols = 0;
580
562 elf_symtab__for_each_symbol(syms, nr_syms, index, sym) { 581 elf_symtab__for_each_symbol(syms, nr_syms, index, sym) {
563 struct symbol *f; 582 struct symbol *f;
583 const char *name;
584 char *demangled;
564 u64 obj_start; 585 u64 obj_start;
565 struct section *section = NULL; 586 struct section *section = NULL;
566 int is_label = elf_sym__is_label(&sym); 587 int is_label = elf_sym__is_label(&sym);
@@ -599,10 +620,19 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
599 goto out_elf_end; 620 goto out_elf_end;
600 } 621 }
601 } 622 }
623 /*
624 * We need to figure out if the object was created from C++ sources
625 * DWARF DW_compile_unit has this, but we don't always have access
626 * to it...
627 */
628 name = elf_sym__name(&sym, symstrs);
629 demangled = bfd_demangle(NULL, name, DMGL_PARAMS | DMGL_ANSI);
630 if (demangled != NULL)
631 name = demangled;
602 632
603 f = symbol__new(sym.st_value, sym.st_size, 633 f = symbol__new(sym.st_value, sym.st_size, name,
604 elf_sym__name(&sym, symstrs),
605 self->sym_priv_size, obj_start, verbose); 634 self->sym_priv_size, obj_start, verbose);
635 free(demangled);
606 if (!f) 636 if (!f)
607 goto out_elf_end; 637 goto out_elf_end;
608 638
@@ -668,6 +698,11 @@ more:
668 if (!ret) 698 if (!ret)
669 goto more; 699 goto more;
670 700
701 if (ret > 0) {
702 int nr_plt = dso__synthesize_plt_symbols(self, verbose);
703 if (nr_plt > 0)
704 ret += nr_plt;
705 }
671out: 706out:
672 free(name); 707 free(name);
673 return ret; 708 return ret;