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