diff options
author | Arnaldo Carvalho de Melo <acme@redhat.com> | 2009-07-11 11:18:36 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-07-11 13:20:26 -0400 |
commit | a25e46c46311316cd1b3f27f8bb036df1693c032 (patch) | |
tree | 271937d116b3bd343f91948440321fa80e7702ab /tools/perf/util/symbol.c | |
parent | 021191b35cdfb1b5ee6e78ed5ae010114a40902c (diff) |
perf_counter tools: PLT info is stripped in -debuginfo packages
So we need to get the richer .symtab from the debuginfo
packages but the PLT info from the original DSO where we have
just the leaner .dynsym symtab.
Example:
| [acme@doppio pahole]$ perf report --sort comm,dso,symbol > before
| [acme@doppio pahole]$ perf report --sort comm,dso,symbol > after
| [acme@doppio pahole]$ diff -U1 before after
| --- before 2009-07-11 11:04:22.688595741 -0300
| +++ after 2009-07-11 11:04:33.380595676 -0300
| @@ -80,3 +80,2 @@
| 0.07% pahole ./build/pahole [.] pahole_stealer
| - 0.06% pahole /usr/lib64/libdw-0.141.so [.] 0x00000000007140
| 0.06% pahole /usr/lib64/libdw-0.141.so [.] __libdw_getabbrev
| @@ -91,2 +90,3 @@
| 0.06% pahole [kernel] [k] free_hot_cold_page
| + 0.06% pahole /usr/lib64/libdw-0.141.so [.] tfind@plt
| 0.05% pahole ./build/libdwarves.so.1.0.0 [.] ftype__add_parameter
| @@ -242,2 +242,3 @@
| 0.01% pahole [kernel] [k] account_group_user_time
| + 0.01% pahole /usr/lib64/libdw-0.141.so [.] strlen@plt
| 0.01% pahole ./build/pahole [.] strcmp@plt
| [acme@doppio pahole]$
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
LKML-Reference: <1247325517-12272-4-git-send-email-acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'tools/perf/util/symbol.c')
-rw-r--r-- | tools/perf/util/symbol.c | 116 |
1 files changed, 65 insertions, 51 deletions
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 8efe7e41109a..f40266b4845d 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c | |||
@@ -374,36 +374,61 @@ static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, | |||
374 | idx < nr_entries; \ | 374 | idx < nr_entries; \ |
375 | ++idx, pos = gelf_getrela(reldata, idx, &pos_mem)) | 375 | ++idx, pos = gelf_getrela(reldata, idx, &pos_mem)) |
376 | 376 | ||
377 | static int dso__synthesize_plt_symbols(struct dso *self, Elf *elf, | 377 | /* |
378 | GElf_Ehdr *ehdr, Elf_Scn *scn_dynsym, | 378 | * We need to check if we have a .dynsym, so that we can handle the |
379 | GElf_Shdr *shdr_dynsym, | 379 | * .plt, synthesizing its symbols, that aren't on the symtabs (be it |
380 | size_t dynsym_idx, int verbose) | 380 | * .dynsym or .symtab). |
381 | * And always look at the original dso, not at debuginfo packages, that | ||
382 | * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS). | ||
383 | */ | ||
384 | static int dso__synthesize_plt_symbols(struct dso *self, int verbose) | ||
381 | { | 385 | { |
382 | uint32_t nr_rel_entries, idx; | 386 | uint32_t nr_rel_entries, idx; |
383 | GElf_Sym sym; | 387 | GElf_Sym sym; |
384 | u64 plt_offset; | 388 | u64 plt_offset; |
385 | GElf_Shdr shdr_plt; | 389 | GElf_Shdr shdr_plt; |
386 | struct symbol *f; | 390 | struct symbol *f; |
387 | GElf_Shdr shdr_rel_plt; | 391 | GElf_Shdr shdr_rel_plt, shdr_dynsym; |
388 | Elf_Data *reldata, *syms, *symstrs; | 392 | Elf_Data *reldata, *syms, *symstrs; |
389 | Elf_Scn *scn_plt_rel, *scn_symstrs; | 393 | Elf_Scn *scn_plt_rel, *scn_symstrs, *scn_dynsym; |
394 | size_t dynsym_idx; | ||
395 | GElf_Ehdr ehdr; | ||
390 | char sympltname[1024]; | 396 | char sympltname[1024]; |
391 | int nr = 0, symidx; | 397 | Elf *elf; |
398 | int nr = 0, symidx, fd, err = 0; | ||
399 | |||
400 | fd = open(self->name, O_RDONLY); | ||
401 | if (fd < 0) | ||
402 | goto out; | ||
403 | |||
404 | elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); | ||
405 | if (elf == NULL) | ||
406 | goto out_close; | ||
407 | |||
408 | if (gelf_getehdr(elf, &ehdr) == NULL) | ||
409 | goto out_elf_end; | ||
410 | |||
411 | scn_dynsym = elf_section_by_name(elf, &ehdr, &shdr_dynsym, | ||
412 | ".dynsym", &dynsym_idx); | ||
413 | if (scn_dynsym == NULL) | ||
414 | goto out_elf_end; | ||
392 | 415 | ||
393 | scn_plt_rel = elf_section_by_name(elf, ehdr, &shdr_rel_plt, | 416 | scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt, |
394 | ".rela.plt", NULL); | 417 | ".rela.plt", NULL); |
395 | if (scn_plt_rel == NULL) { | 418 | if (scn_plt_rel == NULL) { |
396 | scn_plt_rel = elf_section_by_name(elf, ehdr, &shdr_rel_plt, | 419 | scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt, |
397 | ".rel.plt", NULL); | 420 | ".rel.plt", NULL); |
398 | if (scn_plt_rel == NULL) | 421 | if (scn_plt_rel == NULL) |
399 | return 0; | 422 | goto out_elf_end; |
400 | } | 423 | } |
401 | 424 | ||
425 | err = -1; | ||
426 | |||
402 | if (shdr_rel_plt.sh_link != dynsym_idx) | 427 | if (shdr_rel_plt.sh_link != dynsym_idx) |
403 | return 0; | 428 | goto out_elf_end; |
404 | 429 | ||
405 | if (elf_section_by_name(elf, ehdr, &shdr_plt, ".plt", NULL) == NULL) | 430 | if (elf_section_by_name(elf, &ehdr, &shdr_plt, ".plt", NULL) == NULL) |
406 | return 0; | 431 | goto out_elf_end; |
407 | 432 | ||
408 | /* | 433 | /* |
409 | * Fetch the relocation section to find the indexes to the GOT | 434 | * Fetch the relocation section to find the indexes to the GOT |
@@ -411,19 +436,19 @@ static int dso__synthesize_plt_symbols(struct dso *self, Elf *elf, | |||
411 | */ | 436 | */ |
412 | reldata = elf_getdata(scn_plt_rel, NULL); | 437 | reldata = elf_getdata(scn_plt_rel, NULL); |
413 | if (reldata == NULL) | 438 | if (reldata == NULL) |
414 | return -1; | 439 | goto out_elf_end; |
415 | 440 | ||
416 | syms = elf_getdata(scn_dynsym, NULL); | 441 | syms = elf_getdata(scn_dynsym, NULL); |
417 | if (syms == NULL) | 442 | if (syms == NULL) |
418 | return -1; | 443 | goto out_elf_end; |
419 | 444 | ||
420 | scn_symstrs = elf_getscn(elf, shdr_dynsym->sh_link); | 445 | scn_symstrs = elf_getscn(elf, shdr_dynsym.sh_link); |
421 | if (scn_symstrs == NULL) | 446 | if (scn_symstrs == NULL) |
422 | return -1; | 447 | goto out_elf_end; |
423 | 448 | ||
424 | symstrs = elf_getdata(scn_symstrs, NULL); | 449 | symstrs = elf_getdata(scn_symstrs, NULL); |
425 | if (symstrs == NULL) | 450 | if (symstrs == NULL) |
426 | return -1; | 451 | goto out_elf_end; |
427 | 452 | ||
428 | nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize; | 453 | nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize; |
429 | plt_offset = shdr_plt.sh_offset; | 454 | plt_offset = shdr_plt.sh_offset; |
@@ -442,7 +467,7 @@ static int dso__synthesize_plt_symbols(struct dso *self, Elf *elf, | |||
442 | f = symbol__new(plt_offset, shdr_plt.sh_entsize, | 467 | f = symbol__new(plt_offset, shdr_plt.sh_entsize, |
443 | sympltname, self->sym_priv_size, 0, verbose); | 468 | sympltname, self->sym_priv_size, 0, verbose); |
444 | if (!f) | 469 | if (!f) |
445 | return -1; | 470 | goto out_elf_end; |
446 | 471 | ||
447 | dso__insert_symbol(self, f); | 472 | dso__insert_symbol(self, f); |
448 | ++nr; | 473 | ++nr; |
@@ -460,19 +485,25 @@ static int dso__synthesize_plt_symbols(struct dso *self, Elf *elf, | |||
460 | f = symbol__new(plt_offset, shdr_plt.sh_entsize, | 485 | f = symbol__new(plt_offset, shdr_plt.sh_entsize, |
461 | sympltname, self->sym_priv_size, 0, verbose); | 486 | sympltname, self->sym_priv_size, 0, verbose); |
462 | if (!f) | 487 | if (!f) |
463 | return -1; | 488 | goto out_elf_end; |
464 | 489 | ||
465 | dso__insert_symbol(self, f); | 490 | dso__insert_symbol(self, f); |
466 | ++nr; | 491 | ++nr; |
467 | } | 492 | } |
468 | } else { | ||
469 | /* | ||
470 | * TODO: There are still one more shdr_rel_plt.sh_type | ||
471 | * I have to investigate, but probably should be ignored. | ||
472 | */ | ||
473 | } | 493 | } |
474 | 494 | ||
475 | return nr; | 495 | err = 0; |
496 | out_elf_end: | ||
497 | elf_end(elf); | ||
498 | out_close: | ||
499 | close(fd); | ||
500 | |||
501 | if (err == 0) | ||
502 | return nr; | ||
503 | out: | ||
504 | fprintf(stderr, "%s: problems reading %s PLT info.\n", | ||
505 | __func__, self->name); | ||
506 | return 0; | ||
476 | } | 507 | } |
477 | 508 | ||
478 | static int dso__load_sym(struct dso *self, int fd, const char *name, | 509 | static int dso__load_sym(struct dso *self, int fd, const char *name, |
@@ -486,9 +517,8 @@ static int dso__load_sym(struct dso *self, int fd, const char *name, | |||
486 | GElf_Shdr shdr; | 517 | GElf_Shdr shdr; |
487 | Elf_Data *syms; | 518 | Elf_Data *syms; |
488 | GElf_Sym sym; | 519 | GElf_Sym sym; |
489 | Elf_Scn *sec, *sec_dynsym, *sec_strndx; | 520 | Elf_Scn *sec, *sec_strndx; |
490 | Elf *elf; | 521 | Elf *elf; |
491 | size_t dynsym_idx; | ||
492 | int nr = 0; | 522 | int nr = 0; |
493 | 523 | ||
494 | elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); | 524 | elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); |
@@ -505,32 +535,11 @@ static int dso__load_sym(struct dso *self, int fd, const char *name, | |||
505 | goto out_elf_end; | 535 | goto out_elf_end; |
506 | } | 536 | } |
507 | 537 | ||
508 | /* | ||
509 | * We need to check if we have a .dynsym, so that we can handle the | ||
510 | * .plt, synthesizing its symbols, that aren't on the symtabs (be it | ||
511 | * .dynsym or .symtab) | ||
512 | */ | ||
513 | sec_dynsym = elf_section_by_name(elf, &ehdr, &shdr, | ||
514 | ".dynsym", &dynsym_idx); | ||
515 | if (sec_dynsym != NULL) { | ||
516 | nr = dso__synthesize_plt_symbols(self, elf, &ehdr, | ||
517 | sec_dynsym, &shdr, | ||
518 | dynsym_idx, verbose); | ||
519 | if (nr < 0) | ||
520 | goto out_elf_end; | ||
521 | } | ||
522 | |||
523 | /* | ||
524 | * But if we have a full .symtab (that is a superset of .dynsym) we | ||
525 | * should add the symbols not in the .dynsyn | ||
526 | */ | ||
527 | sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL); | 538 | sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL); |
528 | if (sec == NULL) { | 539 | if (sec == NULL) { |
529 | if (sec_dynsym == NULL) | 540 | sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL); |
541 | if (sec == NULL) | ||
530 | goto out_elf_end; | 542 | goto out_elf_end; |
531 | |||
532 | sec = sec_dynsym; | ||
533 | gelf_getshdr(sec, &shdr); | ||
534 | } | 543 | } |
535 | 544 | ||
536 | syms = elf_getdata(sec, NULL); | 545 | syms = elf_getdata(sec, NULL); |
@@ -669,6 +678,11 @@ more: | |||
669 | if (!ret) | 678 | if (!ret) |
670 | goto more; | 679 | goto more; |
671 | 680 | ||
681 | if (ret > 0) { | ||
682 | int nr_plt = dso__synthesize_plt_symbols(self, verbose); | ||
683 | if (nr_plt > 0) | ||
684 | ret += nr_plt; | ||
685 | } | ||
672 | out: | 686 | out: |
673 | free(name); | 687 | free(name); |
674 | return ret; | 688 | return ret; |