diff options
author | Arnaldo Carvalho de Melo <acme@redhat.com> | 2009-05-18 13:28:47 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-05-26 07:52:53 -0400 |
commit | 62eb93905b3b43cea407cfbc061cc7b40ae1c6e9 (patch) | |
tree | 42ef22ce29604d1f69aabf3234ddc4c9a62ad1e6 /Documentation/perf_counter/builtin-report.c | |
parent | fd4242bb35b70557eee8d0c79f82dacc3f3b89e0 (diff) |
perf_counter: Implement dso__load using libelf
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Acked-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Corey Ashford <cjashfor@linux.vnet.ibm.com>
Cc: Marcelo Tosatti <mtosatti@redhat.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
LKML-Reference: <new-submission>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'Documentation/perf_counter/builtin-report.c')
-rw-r--r-- | Documentation/perf_counter/builtin-report.c | 122 |
1 files changed, 120 insertions, 2 deletions
diff --git a/Documentation/perf_counter/builtin-report.c b/Documentation/perf_counter/builtin-report.c index 864f68f06a9e..ad2f327a6576 100644 --- a/Documentation/perf_counter/builtin-report.c +++ b/Documentation/perf_counter/builtin-report.c | |||
@@ -8,6 +8,9 @@ | |||
8 | #include <stdlib.h> | 8 | #include <stdlib.h> |
9 | #include <string.h> | 9 | #include <string.h> |
10 | #include <limits.h> | 10 | #include <limits.h> |
11 | #include <gelf.h> | ||
12 | #include <elf.h> | ||
13 | #include <libelf.h> | ||
11 | #include <fcntl.h> | 14 | #include <fcntl.h> |
12 | #include <stdio.h> | 15 | #include <stdio.h> |
13 | #include <errno.h> | 16 | #include <errno.h> |
@@ -195,10 +198,123 @@ static struct symbol *dso__find_symbol(struct dso *self, uint64_t ip) | |||
195 | return NULL; | 198 | return NULL; |
196 | } | 199 | } |
197 | 200 | ||
201 | /** | ||
202 | * elf_symtab__for_each_symbol - iterate thru all the symbols | ||
203 | * | ||
204 | * @self: struct elf_symtab instance to iterate | ||
205 | * @index: uint32_t index | ||
206 | * @sym: GElf_Sym iterator | ||
207 | */ | ||
208 | #define elf_symtab__for_each_symbol(syms, nr_syms, index, sym) \ | ||
209 | for (index = 0, gelf_getsym(syms, index, &sym);\ | ||
210 | index < nr_syms; \ | ||
211 | index++, gelf_getsym(syms, index, &sym)) | ||
212 | |||
213 | static inline uint8_t elf_sym__type(const GElf_Sym *sym) | ||
214 | { | ||
215 | return GELF_ST_TYPE(sym->st_info); | ||
216 | } | ||
217 | |||
218 | static inline bool elf_sym__is_function(const GElf_Sym *sym) | ||
219 | { | ||
220 | return elf_sym__type(sym) == STT_FUNC && | ||
221 | sym->st_name != 0 && | ||
222 | sym->st_shndx != SHN_UNDEF; | ||
223 | } | ||
224 | |||
225 | static inline const char *elf_sym__name(const GElf_Sym *sym, | ||
226 | const Elf_Data *symstrs) | ||
227 | { | ||
228 | return symstrs->d_buf + sym->st_name; | ||
229 | } | ||
230 | |||
231 | static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, | ||
232 | GElf_Shdr *shp, const char *name, | ||
233 | size_t *index) | ||
234 | { | ||
235 | Elf_Scn *sec = NULL; | ||
236 | size_t cnt = 1; | ||
237 | |||
238 | while ((sec = elf_nextscn(elf, sec)) != NULL) { | ||
239 | char *str; | ||
240 | |||
241 | gelf_getshdr(sec, shp); | ||
242 | str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name); | ||
243 | if (!strcmp(name, str)) { | ||
244 | if (index) | ||
245 | *index = cnt; | ||
246 | break; | ||
247 | } | ||
248 | ++cnt; | ||
249 | } | ||
250 | |||
251 | return sec; | ||
252 | } | ||
253 | |||
198 | static int dso__load(struct dso *self) | 254 | static int dso__load(struct dso *self) |
199 | { | 255 | { |
200 | /* FIXME */ | 256 | int fd = open(self->name, O_RDONLY), err = -1; |
201 | return 0; | 257 | |
258 | if (fd == -1) | ||
259 | return -1; | ||
260 | |||
261 | Elf *elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); | ||
262 | if (elf == NULL) { | ||
263 | fprintf(stderr, "%s: cannot read %s ELF file.\n", | ||
264 | __func__, self->name); | ||
265 | goto out_close; | ||
266 | } | ||
267 | |||
268 | GElf_Ehdr ehdr; | ||
269 | if (gelf_getehdr(elf, &ehdr) == NULL) { | ||
270 | fprintf(stderr, "%s: cannot get elf header.\n", __func__); | ||
271 | goto out_elf_end; | ||
272 | } | ||
273 | |||
274 | GElf_Shdr shdr; | ||
275 | Elf_Scn *sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL); | ||
276 | if (sec == NULL) | ||
277 | sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL); | ||
278 | |||
279 | if (sec == NULL) | ||
280 | goto out_elf_end; | ||
281 | |||
282 | if (gelf_getshdr(sec, &shdr) == NULL) | ||
283 | goto out_elf_end; | ||
284 | |||
285 | Elf_Data *syms = elf_getdata(sec, NULL); | ||
286 | if (syms == NULL) | ||
287 | goto out_elf_end; | ||
288 | |||
289 | sec = elf_getscn(elf, shdr.sh_link); | ||
290 | if (sec == NULL) | ||
291 | goto out_elf_end; | ||
292 | |||
293 | Elf_Data *symstrs = elf_getdata(sec, NULL); | ||
294 | if (symstrs == NULL) | ||
295 | goto out_elf_end; | ||
296 | |||
297 | const uint32_t nr_syms = shdr.sh_size / shdr.sh_entsize; | ||
298 | |||
299 | GElf_Sym sym; | ||
300 | uint32_t index; | ||
301 | elf_symtab__for_each_symbol(syms, nr_syms, index, sym) { | ||
302 | if (!elf_sym__is_function(&sym)) | ||
303 | continue; | ||
304 | struct symbol *f = symbol__new(sym.st_value, sym.st_size, | ||
305 | elf_sym__name(&sym, symstrs)); | ||
306 | if (f == NULL) | ||
307 | goto out_elf_end; | ||
308 | |||
309 | dso__insert_symbol(self, f); | ||
310 | } | ||
311 | |||
312 | err = 0; | ||
313 | out_elf_end: | ||
314 | elf_end(elf); | ||
315 | out_close: | ||
316 | close(fd); | ||
317 | return err; | ||
202 | } | 318 | } |
203 | 319 | ||
204 | static size_t dso__fprintf(struct dso *self, FILE *fp) | 320 | static size_t dso__fprintf(struct dso *self, FILE *fp) |
@@ -614,6 +730,8 @@ int cmd_report(int argc, char **argv) | |||
614 | int ret, rc = EXIT_FAILURE; | 730 | int ret, rc = EXIT_FAILURE; |
615 | unsigned long total = 0; | 731 | unsigned long total = 0; |
616 | 732 | ||
733 | elf_version(EV_CURRENT); | ||
734 | |||
617 | page_size = getpagesize(); | 735 | page_size = getpagesize(); |
618 | 736 | ||
619 | process_options(argc, argv); | 737 | process_options(argc, argv); |