diff options
| -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; |
