diff options
author | Peter Zijlstra <a.p.zijlstra@chello.nl> | 2009-07-22 12:05:48 -0400 |
---|---|---|
committer | Peter Zijlstra <a.p.zijlstra@chello.nl> | 2009-07-22 12:05:48 -0400 |
commit | 1d2f37945d1b3a14086c5ea802486778b635cf97 (patch) | |
tree | b40a1a596a29acc1511f661c27f284dd06b0bc9d /tools/perf/util | |
parent | 1483b19f8f5e8ad0c8816de368b099322dad4db5 (diff) | |
parent | f1c6a58121f9846ac665b0fbd3cbab90ce8bcbac (diff) |
Merge commit 'tip/perfcounters/core' into perf-counters-for-linus
Diffstat (limited to 'tools/perf/util')
-rw-r--r-- | tools/perf/util/include/linux/kernel.h | 8 | ||||
-rw-r--r-- | tools/perf/util/strlist.c | 20 | ||||
-rw-r--r-- | tools/perf/util/strlist.h | 11 | ||||
-rw-r--r-- | tools/perf/util/symbol.c | 117 | ||||
-rw-r--r-- | tools/perf/util/symbol.h | 1 |
5 files changed, 102 insertions, 55 deletions
diff --git a/tools/perf/util/include/linux/kernel.h b/tools/perf/util/include/linux/kernel.h index 99c1b3d1edd9..a6b87390cb52 100644 --- a/tools/perf/util/include/linux/kernel.h +++ b/tools/perf/util/include/linux/kernel.h | |||
@@ -18,4 +18,12 @@ | |||
18 | (type *)((char *)__mptr - offsetof(type, member)); }) | 18 | (type *)((char *)__mptr - offsetof(type, member)); }) |
19 | #endif | 19 | #endif |
20 | 20 | ||
21 | #ifndef max | ||
22 | #define max(x, y) ({ \ | ||
23 | typeof(x) _max1 = (x); \ | ||
24 | typeof(y) _max2 = (y); \ | ||
25 | (void) (&_max1 == &_max2); \ | ||
26 | _max1 > _max2 ? _max1 : _max2; }) | ||
27 | #endif | ||
28 | |||
21 | #endif | 29 | #endif |
diff --git a/tools/perf/util/strlist.c b/tools/perf/util/strlist.c index 025a78edfffe..7ad38171dc2b 100644 --- a/tools/perf/util/strlist.c +++ b/tools/perf/util/strlist.c | |||
@@ -64,6 +64,7 @@ int strlist__add(struct strlist *self, const char *new_entry) | |||
64 | 64 | ||
65 | rb_link_node(&sn->rb_node, parent, p); | 65 | rb_link_node(&sn->rb_node, parent, p); |
66 | rb_insert_color(&sn->rb_node, &self->entries); | 66 | rb_insert_color(&sn->rb_node, &self->entries); |
67 | ++self->nr_entries; | ||
67 | 68 | ||
68 | return 0; | 69 | return 0; |
69 | } | 70 | } |
@@ -155,8 +156,9 @@ struct strlist *strlist__new(bool dupstr, const char *slist) | |||
155 | struct strlist *self = malloc(sizeof(*self)); | 156 | struct strlist *self = malloc(sizeof(*self)); |
156 | 157 | ||
157 | if (self != NULL) { | 158 | if (self != NULL) { |
158 | self->entries = RB_ROOT; | 159 | self->entries = RB_ROOT; |
159 | self->dupstr = dupstr; | 160 | self->dupstr = dupstr; |
161 | self->nr_entries = 0; | ||
160 | if (slist && strlist__parse_list(self, slist) != 0) | 162 | if (slist && strlist__parse_list(self, slist) != 0) |
161 | goto out_error; | 163 | goto out_error; |
162 | } | 164 | } |
@@ -182,3 +184,17 @@ void strlist__delete(struct strlist *self) | |||
182 | free(self); | 184 | free(self); |
183 | } | 185 | } |
184 | } | 186 | } |
187 | |||
188 | struct str_node *strlist__entry(const struct strlist *self, unsigned int idx) | ||
189 | { | ||
190 | struct rb_node *nd; | ||
191 | |||
192 | for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) { | ||
193 | struct str_node *pos = rb_entry(nd, struct str_node, rb_node); | ||
194 | |||
195 | if (!idx--) | ||
196 | return pos; | ||
197 | } | ||
198 | |||
199 | return NULL; | ||
200 | } | ||
diff --git a/tools/perf/util/strlist.h b/tools/perf/util/strlist.h index 2fdcfee87586..921818e44a54 100644 --- a/tools/perf/util/strlist.h +++ b/tools/perf/util/strlist.h | |||
@@ -11,7 +11,8 @@ struct str_node { | |||
11 | 11 | ||
12 | struct strlist { | 12 | struct strlist { |
13 | struct rb_root entries; | 13 | struct rb_root entries; |
14 | bool dupstr; | 14 | unsigned int nr_entries; |
15 | bool dupstr; | ||
15 | }; | 16 | }; |
16 | 17 | ||
17 | struct strlist *strlist__new(bool dupstr, const char *slist); | 18 | struct strlist *strlist__new(bool dupstr, const char *slist); |
@@ -21,11 +22,17 @@ void strlist__remove(struct strlist *self, struct str_node *sn); | |||
21 | int strlist__load(struct strlist *self, const char *filename); | 22 | int strlist__load(struct strlist *self, const char *filename); |
22 | int strlist__add(struct strlist *self, const char *str); | 23 | int strlist__add(struct strlist *self, const char *str); |
23 | 24 | ||
25 | struct str_node *strlist__entry(const struct strlist *self, unsigned int idx); | ||
24 | bool strlist__has_entry(struct strlist *self, const char *entry); | 26 | bool strlist__has_entry(struct strlist *self, const char *entry); |
25 | 27 | ||
26 | static inline bool strlist__empty(const struct strlist *self) | 28 | static inline bool strlist__empty(const struct strlist *self) |
27 | { | 29 | { |
28 | return rb_first(&self->entries) == NULL; | 30 | return self->nr_entries == 0; |
31 | } | ||
32 | |||
33 | static inline unsigned int strlist__nr_entries(const struct strlist *self) | ||
34 | { | ||
35 | return self->nr_entries; | ||
29 | } | 36 | } |
30 | 37 | ||
31 | int strlist__parse_list(struct strlist *self, const char *s); | 38 | int strlist__parse_list(struct strlist *self, const char *s); |
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 4683b67b5ee4..f40266b4845d 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c | |||
@@ -65,6 +65,7 @@ struct dso *dso__new(const char *name, unsigned int sym_priv_size) | |||
65 | self->syms = RB_ROOT; | 65 | self->syms = RB_ROOT; |
66 | self->sym_priv_size = sym_priv_size; | 66 | self->sym_priv_size = sym_priv_size; |
67 | self->find_symbol = dso__find_symbol; | 67 | self->find_symbol = dso__find_symbol; |
68 | self->slen_calculated = 0; | ||
68 | } | 69 | } |
69 | 70 | ||
70 | return self; | 71 | return self; |
@@ -373,36 +374,61 @@ static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, | |||
373 | idx < nr_entries; \ | 374 | idx < nr_entries; \ |
374 | ++idx, pos = gelf_getrela(reldata, idx, &pos_mem)) | 375 | ++idx, pos = gelf_getrela(reldata, idx, &pos_mem)) |
375 | 376 | ||
376 | static int dso__synthesize_plt_symbols(struct dso *self, Elf *elf, | 377 | /* |
377 | GElf_Ehdr *ehdr, Elf_Scn *scn_dynsym, | 378 | * We need to check if we have a .dynsym, so that we can handle the |
378 | GElf_Shdr *shdr_dynsym, | 379 | * .plt, synthesizing its symbols, that aren't on the symtabs (be it |
379 | 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) | ||
380 | { | 385 | { |
381 | uint32_t nr_rel_entries, idx; | 386 | uint32_t nr_rel_entries, idx; |
382 | GElf_Sym sym; | 387 | GElf_Sym sym; |
383 | u64 plt_offset; | 388 | u64 plt_offset; |
384 | GElf_Shdr shdr_plt; | 389 | GElf_Shdr shdr_plt; |
385 | struct symbol *f; | 390 | struct symbol *f; |
386 | GElf_Shdr shdr_rel_plt; | 391 | GElf_Shdr shdr_rel_plt, shdr_dynsym; |
387 | Elf_Data *reldata, *syms, *symstrs; | 392 | Elf_Data *reldata, *syms, *symstrs; |
388 | 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; | ||
389 | char sympltname[1024]; | 396 | char sympltname[1024]; |
390 | 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; | ||
391 | 415 | ||
392 | 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, |
393 | ".rela.plt", NULL); | 417 | ".rela.plt", NULL); |
394 | if (scn_plt_rel == NULL) { | 418 | if (scn_plt_rel == NULL) { |
395 | 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, |
396 | ".rel.plt", NULL); | 420 | ".rel.plt", NULL); |
397 | if (scn_plt_rel == NULL) | 421 | if (scn_plt_rel == NULL) |
398 | return 0; | 422 | goto out_elf_end; |
399 | } | 423 | } |
400 | 424 | ||
425 | err = -1; | ||
426 | |||
401 | if (shdr_rel_plt.sh_link != dynsym_idx) | 427 | if (shdr_rel_plt.sh_link != dynsym_idx) |
402 | return 0; | 428 | goto out_elf_end; |
403 | 429 | ||
404 | 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) |
405 | return 0; | 431 | goto out_elf_end; |
406 | 432 | ||
407 | /* | 433 | /* |
408 | * Fetch the relocation section to find the indexes to the GOT | 434 | * Fetch the relocation section to find the indexes to the GOT |
@@ -410,19 +436,19 @@ static int dso__synthesize_plt_symbols(struct dso *self, Elf *elf, | |||
410 | */ | 436 | */ |
411 | reldata = elf_getdata(scn_plt_rel, NULL); | 437 | reldata = elf_getdata(scn_plt_rel, NULL); |
412 | if (reldata == NULL) | 438 | if (reldata == NULL) |
413 | return -1; | 439 | goto out_elf_end; |
414 | 440 | ||
415 | syms = elf_getdata(scn_dynsym, NULL); | 441 | syms = elf_getdata(scn_dynsym, NULL); |
416 | if (syms == NULL) | 442 | if (syms == NULL) |
417 | return -1; | 443 | goto out_elf_end; |
418 | 444 | ||
419 | scn_symstrs = elf_getscn(elf, shdr_dynsym->sh_link); | 445 | scn_symstrs = elf_getscn(elf, shdr_dynsym.sh_link); |
420 | if (scn_symstrs == NULL) | 446 | if (scn_symstrs == NULL) |
421 | return -1; | 447 | goto out_elf_end; |
422 | 448 | ||
423 | symstrs = elf_getdata(scn_symstrs, NULL); | 449 | symstrs = elf_getdata(scn_symstrs, NULL); |
424 | if (symstrs == NULL) | 450 | if (symstrs == NULL) |
425 | return -1; | 451 | goto out_elf_end; |
426 | 452 | ||
427 | 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; |
428 | plt_offset = shdr_plt.sh_offset; | 454 | plt_offset = shdr_plt.sh_offset; |
@@ -441,7 +467,7 @@ static int dso__synthesize_plt_symbols(struct dso *self, Elf *elf, | |||
441 | f = symbol__new(plt_offset, shdr_plt.sh_entsize, | 467 | f = symbol__new(plt_offset, shdr_plt.sh_entsize, |
442 | sympltname, self->sym_priv_size, 0, verbose); | 468 | sympltname, self->sym_priv_size, 0, verbose); |
443 | if (!f) | 469 | if (!f) |
444 | return -1; | 470 | goto out_elf_end; |
445 | 471 | ||
446 | dso__insert_symbol(self, f); | 472 | dso__insert_symbol(self, f); |
447 | ++nr; | 473 | ++nr; |
@@ -459,19 +485,25 @@ static int dso__synthesize_plt_symbols(struct dso *self, Elf *elf, | |||
459 | f = symbol__new(plt_offset, shdr_plt.sh_entsize, | 485 | f = symbol__new(plt_offset, shdr_plt.sh_entsize, |
460 | sympltname, self->sym_priv_size, 0, verbose); | 486 | sympltname, self->sym_priv_size, 0, verbose); |
461 | if (!f) | 487 | if (!f) |
462 | return -1; | 488 | goto out_elf_end; |
463 | 489 | ||
464 | dso__insert_symbol(self, f); | 490 | dso__insert_symbol(self, f); |
465 | ++nr; | 491 | ++nr; |
466 | } | 492 | } |
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 | } | 493 | } |
473 | 494 | ||
474 | 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; | ||
475 | } | 507 | } |
476 | 508 | ||
477 | 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, |
@@ -485,9 +517,8 @@ static int dso__load_sym(struct dso *self, int fd, const char *name, | |||
485 | GElf_Shdr shdr; | 517 | GElf_Shdr shdr; |
486 | Elf_Data *syms; | 518 | Elf_Data *syms; |
487 | GElf_Sym sym; | 519 | GElf_Sym sym; |
488 | Elf_Scn *sec, *sec_dynsym, *sec_strndx; | 520 | Elf_Scn *sec, *sec_strndx; |
489 | Elf *elf; | 521 | Elf *elf; |
490 | size_t dynsym_idx; | ||
491 | int nr = 0; | 522 | int nr = 0; |
492 | 523 | ||
493 | elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); | 524 | elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); |
@@ -504,32 +535,11 @@ static int dso__load_sym(struct dso *self, int fd, const char *name, | |||
504 | goto out_elf_end; | 535 | goto out_elf_end; |
505 | } | 536 | } |
506 | 537 | ||
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); | 538 | sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL); |
527 | if (sec == NULL) { | 539 | if (sec == NULL) { |
528 | if (sec_dynsym == NULL) | 540 | sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL); |
541 | if (sec == NULL) | ||
529 | goto out_elf_end; | 542 | goto out_elf_end; |
530 | |||
531 | sec = sec_dynsym; | ||
532 | gelf_getshdr(sec, &shdr); | ||
533 | } | 543 | } |
534 | 544 | ||
535 | syms = elf_getdata(sec, NULL); | 545 | syms = elf_getdata(sec, NULL); |
@@ -668,6 +678,11 @@ more: | |||
668 | if (!ret) | 678 | if (!ret) |
669 | goto more; | 679 | goto more; |
670 | 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 | } | ||
671 | out: | 686 | out: |
672 | free(name); | 687 | free(name); |
673 | return ret; | 688 | return ret; |
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 7918cffb23cd..2f92b21c712d 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h | |||
@@ -25,6 +25,7 @@ struct dso { | |||
25 | struct symbol *(*find_symbol)(struct dso *, u64 ip); | 25 | struct symbol *(*find_symbol)(struct dso *, u64 ip); |
26 | unsigned int sym_priv_size; | 26 | unsigned int sym_priv_size; |
27 | unsigned char adjust_symbols; | 27 | unsigned char adjust_symbols; |
28 | unsigned char slen_calculated; | ||
28 | char name[0]; | 29 | char name[0]; |
29 | }; | 30 | }; |
30 | 31 | ||