diff options
author | Peter Zijlstra <a.p.zijlstra@chello.nl> | 2009-07-22 18:05:48 +0200 |
---|---|---|
committer | Peter Zijlstra <a.p.zijlstra@chello.nl> | 2009-07-22 18:05:48 +0200 |
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 @@ (type *)((char *)__mptr - offsetof(type, member)); }) #endif +#ifndef max +#define max(x, y) ({ \ + typeof(x) _max1 = (x); \ + typeof(y) _max2 = (y); \ + (void) (&_max1 == &_max2); \ + _max1 > _max2 ? _max1 : _max2; }) +#endif + #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) rb_link_node(&sn->rb_node, parent, p); rb_insert_color(&sn->rb_node, &self->entries); + ++self->nr_entries; return 0; } @@ -155,8 +156,9 @@ struct strlist *strlist__new(bool dupstr, const char *slist) struct strlist *self = malloc(sizeof(*self)); if (self != NULL) { - self->entries = RB_ROOT; - self->dupstr = dupstr; + self->entries = RB_ROOT; + self->dupstr = dupstr; + self->nr_entries = 0; if (slist && strlist__parse_list(self, slist) != 0) goto out_error; } @@ -182,3 +184,17 @@ void strlist__delete(struct strlist *self) free(self); } } + +struct str_node *strlist__entry(const struct strlist *self, unsigned int idx) +{ + struct rb_node *nd; + + for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) { + struct str_node *pos = rb_entry(nd, struct str_node, rb_node); + + if (!idx--) + return pos; + } + + return NULL; +} 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 { struct strlist { struct rb_root entries; - bool dupstr; + unsigned int nr_entries; + bool dupstr; }; struct strlist *strlist__new(bool dupstr, const char *slist); @@ -21,11 +22,17 @@ void strlist__remove(struct strlist *self, struct str_node *sn); int strlist__load(struct strlist *self, const char *filename); int strlist__add(struct strlist *self, const char *str); +struct str_node *strlist__entry(const struct strlist *self, unsigned int idx); bool strlist__has_entry(struct strlist *self, const char *entry); static inline bool strlist__empty(const struct strlist *self) { - return rb_first(&self->entries) == NULL; + return self->nr_entries == 0; +} + +static inline unsigned int strlist__nr_entries(const struct strlist *self) +{ + return self->nr_entries; } 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) self->syms = RB_ROOT; self->sym_priv_size = sym_priv_size; self->find_symbol = dso__find_symbol; + self->slen_calculated = 0; } return self; @@ -373,36 +374,61 @@ static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, idx < nr_entries; \ ++idx, pos = gelf_getrela(reldata, idx, &pos_mem)) -static int dso__synthesize_plt_symbols(struct dso *self, Elf *elf, - GElf_Ehdr *ehdr, Elf_Scn *scn_dynsym, - GElf_Shdr *shdr_dynsym, - size_t dynsym_idx, int verbose) +/* + * We need to check if we have a .dynsym, so that we can handle the + * .plt, synthesizing its symbols, that aren't on the symtabs (be it + * .dynsym or .symtab). + * And always look at the original dso, not at debuginfo packages, that + * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS). + */ +static int dso__synthesize_plt_symbols(struct dso *self, int verbose) { uint32_t nr_rel_entries, idx; GElf_Sym sym; u64 plt_offset; GElf_Shdr shdr_plt; struct symbol *f; - GElf_Shdr shdr_rel_plt; + GElf_Shdr shdr_rel_plt, shdr_dynsym; Elf_Data *reldata, *syms, *symstrs; - Elf_Scn *scn_plt_rel, *scn_symstrs; + Elf_Scn *scn_plt_rel, *scn_symstrs, *scn_dynsym; + size_t dynsym_idx; + GElf_Ehdr ehdr; char sympltname[1024]; - int nr = 0, symidx; + Elf *elf; + int nr = 0, symidx, fd, err = 0; + + fd = open(self->name, O_RDONLY); + if (fd < 0) + goto out; + + elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); + if (elf == NULL) + goto out_close; + + if (gelf_getehdr(elf, &ehdr) == NULL) + goto out_elf_end; + + scn_dynsym = elf_section_by_name(elf, &ehdr, &shdr_dynsym, + ".dynsym", &dynsym_idx); + if (scn_dynsym == NULL) + goto out_elf_end; - scn_plt_rel = elf_section_by_name(elf, ehdr, &shdr_rel_plt, + scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt, ".rela.plt", NULL); if (scn_plt_rel == NULL) { - scn_plt_rel = elf_section_by_name(elf, ehdr, &shdr_rel_plt, + scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt, ".rel.plt", NULL); if (scn_plt_rel == NULL) - return 0; + goto out_elf_end; } + err = -1; + if (shdr_rel_plt.sh_link != dynsym_idx) - return 0; + goto out_elf_end; - if (elf_section_by_name(elf, ehdr, &shdr_plt, ".plt", NULL) == NULL) - return 0; + if (elf_section_by_name(elf, &ehdr, &shdr_plt, ".plt", NULL) == NULL) + goto out_elf_end; /* * 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, */ reldata = elf_getdata(scn_plt_rel, NULL); if (reldata == NULL) - return -1; + goto out_elf_end; syms = elf_getdata(scn_dynsym, NULL); if (syms == NULL) - return -1; + goto out_elf_end; - scn_symstrs = elf_getscn(elf, shdr_dynsym->sh_link); + scn_symstrs = elf_getscn(elf, shdr_dynsym.sh_link); if (scn_symstrs == NULL) - return -1; + goto out_elf_end; symstrs = elf_getdata(scn_symstrs, NULL); if (symstrs == NULL) - return -1; + goto out_elf_end; nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize; plt_offset = shdr_plt.sh_offset; @@ -441,7 +467,7 @@ static int dso__synthesize_plt_symbols(struct dso *self, Elf *elf, f = symbol__new(plt_offset, shdr_plt.sh_entsize, sympltname, self->sym_priv_size, 0, verbose); if (!f) - return -1; + goto out_elf_end; dso__insert_symbol(self, f); ++nr; @@ -459,19 +485,25 @@ static int dso__synthesize_plt_symbols(struct dso *self, Elf *elf, f = symbol__new(plt_offset, shdr_plt.sh_entsize, sympltname, self->sym_priv_size, 0, verbose); if (!f) - return -1; + goto out_elf_end; dso__insert_symbol(self, f); ++nr; } - } else { - /* - * TODO: There are still one more shdr_rel_plt.sh_type - * I have to investigate, but probably should be ignored. - */ } - return nr; + err = 0; +out_elf_end: + elf_end(elf); +out_close: + close(fd); + + if (err == 0) + return nr; +out: + fprintf(stderr, "%s: problems reading %s PLT info.\n", + __func__, self->name); + return 0; } 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, GElf_Shdr shdr; Elf_Data *syms; GElf_Sym sym; - Elf_Scn *sec, *sec_dynsym, *sec_strndx; + Elf_Scn *sec, *sec_strndx; Elf *elf; - size_t dynsym_idx; int nr = 0; 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, goto out_elf_end; } - /* - * We need to check if we have a .dynsym, so that we can handle the - * .plt, synthesizing its symbols, that aren't on the symtabs (be it - * .dynsym or .symtab) - */ - sec_dynsym = elf_section_by_name(elf, &ehdr, &shdr, - ".dynsym", &dynsym_idx); - if (sec_dynsym != NULL) { - nr = dso__synthesize_plt_symbols(self, elf, &ehdr, - sec_dynsym, &shdr, - dynsym_idx, verbose); - if (nr < 0) - goto out_elf_end; - } - - /* - * But if we have a full .symtab (that is a superset of .dynsym) we - * should add the symbols not in the .dynsyn - */ sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL); if (sec == NULL) { - if (sec_dynsym == NULL) + sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL); + if (sec == NULL) goto out_elf_end; - - sec = sec_dynsym; - gelf_getshdr(sec, &shdr); } syms = elf_getdata(sec, NULL); @@ -668,6 +678,11 @@ more: if (!ret) goto more; + if (ret > 0) { + int nr_plt = dso__synthesize_plt_symbols(self, verbose); + if (nr_plt > 0) + ret += nr_plt; + } out: free(name); 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 { struct symbol *(*find_symbol)(struct dso *, u64 ip); unsigned int sym_priv_size; unsigned char adjust_symbols; + unsigned char slen_calculated; char name[0]; }; |