aboutsummaryrefslogtreecommitdiffstats
path: root/Documentation
diff options
context:
space:
mode:
authorArnaldo Carvalho de Melo <acme@redhat.com>2009-05-28 13:55:04 -0400
committerIngo Molnar <mingo@elte.hu>2009-05-28 17:25:42 -0400
commita2928c42a5d69328c3578b41bd4d72f6658cf7dc (patch)
tree09cf963c18e03482183cdf0b82a23a74b7722f6a /Documentation
parentc93f7669098eb97c5376e5396e3dfb734c17df4f (diff)
perf_counter tools: Move symbol resolution classes from report to libperf
Will be used by perf top as well. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Paul Mackerras <paulus@samba.org> Cc: Mike Galbraith <efault@gmx.de> Cc: Steven Rostedt <rostedt@goodmis.org> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> LKML-Reference: <20090528175504.GC4747@ghostprotocols.net> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'Documentation')
-rw-r--r--Documentation/perf_counter/Makefile2
-rw-r--r--Documentation/perf_counter/builtin-report.c458
-rw-r--r--Documentation/perf_counter/util/symbol.c421
-rw-r--r--Documentation/perf_counter/util/symbol.h33
4 files changed, 471 insertions, 443 deletions
diff --git a/Documentation/perf_counter/Makefile b/Documentation/perf_counter/Makefile
index 51b13f989833..bd29a5c00100 100644
--- a/Documentation/perf_counter/Makefile
+++ b/Documentation/perf_counter/Makefile
@@ -298,6 +298,7 @@ LIB_H += util/help.h
298LIB_H += util/strbuf.h 298LIB_H += util/strbuf.h
299LIB_H += util/run-command.h 299LIB_H += util/run-command.h
300LIB_H += util/sigchain.h 300LIB_H += util/sigchain.h
301LIB_H += util/symbol.h
301 302
302LIB_OBJS += util/abspath.o 303LIB_OBJS += util/abspath.o
303LIB_OBJS += util/alias.o 304LIB_OBJS += util/alias.o
@@ -317,6 +318,7 @@ LIB_OBJS += util/strbuf.o
317LIB_OBJS += util/usage.o 318LIB_OBJS += util/usage.o
318LIB_OBJS += util/wrapper.o 319LIB_OBJS += util/wrapper.o
319LIB_OBJS += util/sigchain.o 320LIB_OBJS += util/sigchain.o
321LIB_OBJS += util/symbol.o
320LIB_OBJS += util/pager.o 322LIB_OBJS += util/pager.o
321 323
322BUILTIN_OBJS += builtin-help.o 324BUILTIN_OBJS += builtin-help.o
diff --git a/Documentation/perf_counter/builtin-report.c b/Documentation/perf_counter/builtin-report.c
index 9fdf8224ee61..04fc7ec0c359 100644
--- a/Documentation/perf_counter/builtin-report.c
+++ b/Documentation/perf_counter/builtin-report.c
@@ -1,13 +1,10 @@
1#include "util/util.h" 1#include "util/util.h"
2#include "builtin.h" 2#include "builtin.h"
3 3
4#include <libelf.h>
5#include <gelf.h>
6#include <elf.h>
7
8#include "util/list.h" 4#include "util/list.h"
9#include "util/cache.h" 5#include "util/cache.h"
10#include "util/rbtree.h" 6#include "util/rbtree.h"
7#include "util/symbol.h"
11 8
12#include "perf.h" 9#include "perf.h"
13 10
@@ -62,305 +59,6 @@ typedef union event_union {
62 struct comm_event comm; 59 struct comm_event comm;
63} event_t; 60} event_t;
64 61
65struct symbol {
66 struct rb_node rb_node;
67 __u64 start;
68 __u64 end;
69 char name[0];
70};
71
72static struct symbol *symbol__new(uint64_t start, uint64_t len, const char *name)
73{
74 struct symbol *self = malloc(sizeof(*self) + strlen(name) + 1);
75
76 if (self != NULL) {
77 self->start = start;
78 self->end = start + len;
79 strcpy(self->name, name);
80 }
81
82 return self;
83}
84
85static void symbol__delete(struct symbol *self)
86{
87 free(self);
88}
89
90static size_t symbol__fprintf(struct symbol *self, FILE *fp)
91{
92 return fprintf(fp, " %llx-%llx %s\n",
93 self->start, self->end, self->name);
94}
95
96struct dso {
97 struct list_head node;
98 struct rb_root syms;
99 char name[0];
100};
101
102static struct dso *dso__new(const char *name)
103{
104 struct dso *self = malloc(sizeof(*self) + strlen(name) + 1);
105
106 if (self != NULL) {
107 strcpy(self->name, name);
108 self->syms = RB_ROOT;
109 }
110
111 return self;
112}
113
114static void dso__delete_symbols(struct dso *self)
115{
116 struct symbol *pos;
117 struct rb_node *next = rb_first(&self->syms);
118
119 while (next) {
120 pos = rb_entry(next, struct symbol, rb_node);
121 next = rb_next(&pos->rb_node);
122 symbol__delete(pos);
123 }
124}
125
126static void dso__delete(struct dso *self)
127{
128 dso__delete_symbols(self);
129 free(self);
130}
131
132static void dso__insert_symbol(struct dso *self, struct symbol *sym)
133{
134 struct rb_node **p = &self->syms.rb_node;
135 struct rb_node *parent = NULL;
136 const uint64_t ip = sym->start;
137 struct symbol *s;
138
139 while (*p != NULL) {
140 parent = *p;
141 s = rb_entry(parent, struct symbol, rb_node);
142 if (ip < s->start)
143 p = &(*p)->rb_left;
144 else
145 p = &(*p)->rb_right;
146 }
147 rb_link_node(&sym->rb_node, parent, p);
148 rb_insert_color(&sym->rb_node, &self->syms);
149}
150
151static struct symbol *dso__find_symbol(struct dso *self, uint64_t ip)
152{
153 struct rb_node *n;
154
155 if (self == NULL)
156 return NULL;
157
158 n = self->syms.rb_node;
159
160 while (n) {
161 struct symbol *s = rb_entry(n, struct symbol, rb_node);
162
163 if (ip < s->start)
164 n = n->rb_left;
165 else if (ip > s->end)
166 n = n->rb_right;
167 else
168 return s;
169 }
170
171 return NULL;
172}
173
174/**
175 * elf_symtab__for_each_symbol - iterate thru all the symbols
176 *
177 * @self: struct elf_symtab instance to iterate
178 * @index: uint32_t index
179 * @sym: GElf_Sym iterator
180 */
181#define elf_symtab__for_each_symbol(syms, nr_syms, index, sym) \
182 for (index = 0, gelf_getsym(syms, index, &sym);\
183 index < nr_syms; \
184 index++, gelf_getsym(syms, index, &sym))
185
186static inline uint8_t elf_sym__type(const GElf_Sym *sym)
187{
188 return GELF_ST_TYPE(sym->st_info);
189}
190
191static inline int elf_sym__is_function(const GElf_Sym *sym)
192{
193 return elf_sym__type(sym) == STT_FUNC &&
194 sym->st_name != 0 &&
195 sym->st_shndx != SHN_UNDEF &&
196 sym->st_size != 0;
197}
198
199static inline const char *elf_sym__name(const GElf_Sym *sym,
200 const Elf_Data *symstrs)
201{
202 return symstrs->d_buf + sym->st_name;
203}
204
205static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
206 GElf_Shdr *shp, const char *name,
207 size_t *index)
208{
209 Elf_Scn *sec = NULL;
210 size_t cnt = 1;
211
212 while ((sec = elf_nextscn(elf, sec)) != NULL) {
213 char *str;
214
215 gelf_getshdr(sec, shp);
216 str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name);
217 if (!strcmp(name, str)) {
218 if (index)
219 *index = cnt;
220 break;
221 }
222 ++cnt;
223 }
224
225 return sec;
226}
227
228static int dso__load_sym(struct dso *self, int fd, char *name)
229{
230 Elf_Data *symstrs;
231 uint32_t nr_syms;
232 int err = -1;
233 uint32_t index;
234 GElf_Ehdr ehdr;
235 GElf_Shdr shdr;
236 Elf_Data *syms;
237 GElf_Sym sym;
238 Elf_Scn *sec;
239 Elf *elf;
240 int nr = 0;
241
242 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
243 if (elf == NULL) {
244 fprintf(stderr, "%s: cannot read %s ELF file.\n",
245 __func__, name);
246 goto out_close;
247 }
248
249 if (gelf_getehdr(elf, &ehdr) == NULL) {
250 fprintf(stderr, "%s: cannot get elf header.\n", __func__);
251 goto out_elf_end;
252 }
253
254 sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL);
255 if (sec == NULL)
256 sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL);
257
258 if (sec == NULL)
259 goto out_elf_end;
260
261 syms = elf_getdata(sec, NULL);
262 if (syms == NULL)
263 goto out_elf_end;
264
265 sec = elf_getscn(elf, shdr.sh_link);
266 if (sec == NULL)
267 goto out_elf_end;
268
269 symstrs = elf_getdata(sec, NULL);
270 if (symstrs == NULL)
271 goto out_elf_end;
272
273 nr_syms = shdr.sh_size / shdr.sh_entsize;
274
275 elf_symtab__for_each_symbol(syms, nr_syms, index, sym) {
276 struct symbol *f;
277
278 if (!elf_sym__is_function(&sym))
279 continue;
280
281 sec = elf_getscn(elf, sym.st_shndx);
282 if (!sec)
283 goto out_elf_end;
284
285 gelf_getshdr(sec, &shdr);
286 sym.st_value -= shdr.sh_addr - shdr.sh_offset;
287
288 f = symbol__new(sym.st_value, sym.st_size,
289 elf_sym__name(&sym, symstrs));
290 if (!f)
291 goto out_elf_end;
292
293 dso__insert_symbol(self, f);
294
295 nr++;
296 }
297
298 err = nr;
299out_elf_end:
300 elf_end(elf);
301out_close:
302 return err;
303}
304
305static int dso__load(struct dso *self)
306{
307 int size = strlen(self->name) + sizeof("/usr/lib/debug%s.debug");
308 char *name = malloc(size);
309 int variant = 0;
310 int ret = -1;
311 int fd;
312
313 if (!name)
314 return -1;
315
316more:
317 do {
318 switch (variant) {
319 case 0: /* Fedora */
320 snprintf(name, size, "/usr/lib/debug%s.debug", self->name);
321 break;
322 case 1: /* Ubuntu */
323 snprintf(name, size, "/usr/lib/debug%s", self->name);
324 break;
325 case 2: /* Sane people */
326 snprintf(name, size, "%s", self->name);
327 break;
328
329 default:
330 goto out;
331 }
332 variant++;
333
334 fd = open(name, O_RDONLY);
335 } while (fd < 0);
336
337 ret = dso__load_sym(self, fd, name);
338 close(fd);
339
340 /*
341 * Some people seem to have debuginfo files _WITHOUT_ debug info!?!?
342 */
343 if (!ret)
344 goto more;
345
346out:
347 free(name);
348 return ret;
349}
350
351static size_t dso__fprintf(struct dso *self, FILE *fp)
352{
353 size_t ret = fprintf(fp, "dso: %s\n", self->name);
354
355 struct rb_node *nd;
356 for (nd = rb_first(&self->syms); nd; nd = rb_next(nd)) {
357 struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
358 ret += symbol__fprintf(pos, fp);
359 }
360
361 return ret;
362}
363
364static LIST_HEAD(dsos); 62static LIST_HEAD(dsos);
365static struct dso *kernel_dso; 63static struct dso *kernel_dso;
366 64
@@ -418,153 +116,27 @@ static void dsos__fprintf(FILE *fp)
418 dso__fprintf(pos, fp); 116 dso__fprintf(pos, fp);
419} 117}
420 118
421static int hex(char ch)
422{
423 if ((ch >= '0') && (ch <= '9'))
424 return ch - '0';
425 if ((ch >= 'a') && (ch <= 'f'))
426 return ch - 'a' + 10;
427 if ((ch >= 'A') && (ch <= 'F'))
428 return ch - 'A' + 10;
429 return -1;
430}
431
432/*
433 * While we find nice hex chars, build a long_val.
434 * Return number of chars processed.
435 */
436static int hex2long(char *ptr, unsigned long *long_val)
437{
438 const char *p = ptr;
439 *long_val = 0;
440
441 while (*p) {
442 const int hex_val = hex(*p);
443
444 if (hex_val < 0)
445 break;
446
447 *long_val = (*long_val << 4) | hex_val;
448 p++;
449 }
450
451 return p - ptr;
452}
453
454static int load_kallsyms(void)
455{
456 struct rb_node *nd, *prevnd;
457 char *line = NULL;
458 FILE *file;
459 size_t n;
460
461 kernel_dso = dso__new("[kernel]");
462 if (kernel_dso == NULL)
463 return -1;
464
465 file = fopen("/proc/kallsyms", "r");
466 if (file == NULL)
467 goto out_delete_dso;
468
469 while (!feof(file)) {
470 unsigned long start;
471 struct symbol *sym;
472 int line_len, len;
473 char symbol_type;
474
475 line_len = getline(&line, &n, file);
476 if (line_len < 0)
477 break;
478
479 if (!line)
480 goto out_delete_dso;
481
482 line[--line_len] = '\0'; /* \n */
483
484 len = hex2long(line, &start);
485
486 len++;
487 if (len + 2 >= line_len)
488 continue;
489
490 symbol_type = toupper(line[len]);
491 /*
492 * We're interested only in code ('T'ext)
493 */
494 if (symbol_type != 'T' && symbol_type != 'W')
495 continue;
496 /*
497 * Well fix up the end later, when we have all sorted.
498 */
499 sym = symbol__new(start, 0xdead, line + len + 2);
500
501 if (sym == NULL)
502 goto out_delete_dso;
503
504 dso__insert_symbol(kernel_dso, sym);
505 }
506
507 /*
508 * Now that we have all sorted out, just set the ->end of all
509 * symbols
510 */
511 prevnd = rb_first(&kernel_dso->syms);
512
513 if (prevnd == NULL)
514 goto out_delete_line;
515
516 for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
517 struct symbol *prev = rb_entry(prevnd, struct symbol, rb_node),
518 *curr = rb_entry(nd, struct symbol, rb_node);
519
520 prev->end = curr->start - 1;
521 prevnd = nd;
522 }
523
524 dsos__add(kernel_dso);
525 free(line);
526 fclose(file);
527
528 return 0;
529
530out_delete_line:
531 free(line);
532out_delete_dso:
533 dso__delete(kernel_dso);
534 return -1;
535}
536
537static int load_kernel(void) 119static int load_kernel(void)
538{ 120{
539 int fd, nr; 121 int err = -1;
540
541 if (!vmlinux)
542 goto kallsyms;
543
544 fd = open(vmlinux, O_RDONLY);
545 if (fd < 0)
546 goto kallsyms;
547 122
548 kernel_dso = dso__new("[kernel]"); 123 kernel_dso = dso__new("[kernel]");
549 if (!kernel_dso) 124 if (!kernel_dso)
550 goto fail_open; 125 return -1;
551
552 nr = dso__load_sym(kernel_dso, fd, vmlinux);
553 126
554 if (nr <= 0) 127 if (vmlinux)
555 goto fail_load; 128 err = dso__load_vmlinux(kernel_dso, vmlinux);
556 129
557 dsos__add(kernel_dso); 130 if (err)
558 close(fd); 131 err = dso__load_kallsyms(kernel_dso);
559 132
560 return 0; 133 if (err) {
134 dso__delete(kernel_dso);
135 kernel_dso = NULL;
136 } else
137 dsos__add(kernel_dso);
561 138
562fail_load: 139 return err;
563 dso__delete(kernel_dso);
564fail_open:
565 close(fd);
566kallsyms:
567 return load_kallsyms();
568} 140}
569 141
570struct map { 142struct map {
@@ -1050,7 +622,7 @@ static int __cmd_report(void)
1050 } 622 }
1051 623
1052 if (load_kernel() < 0) { 624 if (load_kernel() < 0) {
1053 perror("failed to open kallsyms"); 625 perror("failed to load kernel symbols");
1054 return EXIT_FAILURE; 626 return EXIT_FAILURE;
1055 } 627 }
1056 628
@@ -1247,7 +819,7 @@ static const struct option options[] = {
1247 819
1248int cmd_report(int argc, const char **argv, const char *prefix) 820int cmd_report(int argc, const char **argv, const char *prefix)
1249{ 821{
1250 elf_version(EV_CURRENT); 822 symbol__init();
1251 823
1252 page_size = getpagesize(); 824 page_size = getpagesize();
1253 825
diff --git a/Documentation/perf_counter/util/symbol.c b/Documentation/perf_counter/util/symbol.c
new file mode 100644
index 000000000000..d06de2cfcdc6
--- /dev/null
+++ b/Documentation/perf_counter/util/symbol.c
@@ -0,0 +1,421 @@
1#include "util.h"
2#include "../perf.h"
3#include "symbol.h"
4
5#include <libelf.h>
6#include <gelf.h>
7#include <elf.h>
8
9static struct symbol *symbol__new(uint64_t start, uint64_t len,
10 const char *name)
11{
12 struct symbol *self = malloc(sizeof(*self) + strlen(name) + 1);
13
14 if (self != NULL) {
15 self->start = start;
16 self->end = start + len;
17 strcpy(self->name, name);
18 }
19
20 return self;
21}
22
23static void symbol__delete(struct symbol *self)
24{
25 free(self);
26}
27
28static size_t symbol__fprintf(struct symbol *self, FILE *fp)
29{
30 return fprintf(fp, " %llx-%llx %s\n",
31 self->start, self->end, self->name);
32}
33
34struct dso *dso__new(const char *name)
35{
36 struct dso *self = malloc(sizeof(*self) + strlen(name) + 1);
37
38 if (self != NULL) {
39 strcpy(self->name, name);
40 self->syms = RB_ROOT;
41 }
42
43 return self;
44}
45
46static void dso__delete_symbols(struct dso *self)
47{
48 struct symbol *pos;
49 struct rb_node *next = rb_first(&self->syms);
50
51 while (next) {
52 pos = rb_entry(next, struct symbol, rb_node);
53 next = rb_next(&pos->rb_node);
54 symbol__delete(pos);
55 }
56}
57
58void dso__delete(struct dso *self)
59{
60 dso__delete_symbols(self);
61 free(self);
62}
63
64static void dso__insert_symbol(struct dso *self, struct symbol *sym)
65{
66 struct rb_node **p = &self->syms.rb_node;
67 struct rb_node *parent = NULL;
68 const uint64_t ip = sym->start;
69 struct symbol *s;
70
71 while (*p != NULL) {
72 parent = *p;
73 s = rb_entry(parent, struct symbol, rb_node);
74 if (ip < s->start)
75 p = &(*p)->rb_left;
76 else
77 p = &(*p)->rb_right;
78 }
79 rb_link_node(&sym->rb_node, parent, p);
80 rb_insert_color(&sym->rb_node, &self->syms);
81}
82
83struct symbol *dso__find_symbol(struct dso *self, uint64_t ip)
84{
85 struct rb_node *n;
86
87 if (self == NULL)
88 return NULL;
89
90 n = self->syms.rb_node;
91
92 while (n) {
93 struct symbol *s = rb_entry(n, struct symbol, rb_node);
94
95 if (ip < s->start)
96 n = n->rb_left;
97 else if (ip > s->end)
98 n = n->rb_right;
99 else
100 return s;
101 }
102
103 return NULL;
104}
105
106size_t dso__fprintf(struct dso *self, FILE *fp)
107{
108 size_t ret = fprintf(fp, "dso: %s\n", self->name);
109
110 struct rb_node *nd;
111 for (nd = rb_first(&self->syms); nd; nd = rb_next(nd)) {
112 struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
113 ret += symbol__fprintf(pos, fp);
114 }
115
116 return ret;
117}
118
119static int hex(char ch)
120{
121 if ((ch >= '0') && (ch <= '9'))
122 return ch - '0';
123 if ((ch >= 'a') && (ch <= 'f'))
124 return ch - 'a' + 10;
125 if ((ch >= 'A') && (ch <= 'F'))
126 return ch - 'A' + 10;
127 return -1;
128}
129
130/*
131 * While we find nice hex chars, build a long_val.
132 * Return number of chars processed.
133 */
134static int hex2long(char *ptr, unsigned long *long_val)
135{
136 const char *p = ptr;
137 *long_val = 0;
138
139 while (*p) {
140 const int hex_val = hex(*p);
141
142 if (hex_val < 0)
143 break;
144
145 *long_val = (*long_val << 4) | hex_val;
146 p++;
147 }
148
149 return p - ptr;
150}
151
152int dso__load_kallsyms(struct dso *self)
153{
154 struct rb_node *nd, *prevnd;
155 char *line = NULL;
156 size_t n;
157 FILE *file = fopen("/proc/kallsyms", "r");
158
159 if (file == NULL)
160 goto out_failure;
161
162 while (!feof(file)) {
163 unsigned long start;
164 struct symbol *sym;
165 int line_len, len;
166 char symbol_type;
167
168 line_len = getline(&line, &n, file);
169 if (line_len < 0)
170 break;
171
172 if (!line)
173 goto out_failure;
174
175 line[--line_len] = '\0'; /* \n */
176
177 len = hex2long(line, &start);
178
179 len++;
180 if (len + 2 >= line_len)
181 continue;
182
183 symbol_type = toupper(line[len]);
184 /*
185 * We're interested only in code ('T'ext)
186 */
187 if (symbol_type != 'T' && symbol_type != 'W')
188 continue;
189 /*
190 * Well fix up the end later, when we have all sorted.
191 */
192 sym = symbol__new(start, 0xdead, line + len + 2);
193
194 if (sym == NULL)
195 goto out_delete_line;
196
197 dso__insert_symbol(self, sym);
198 }
199
200 /*
201 * Now that we have all sorted out, just set the ->end of all
202 * symbols
203 */
204 prevnd = rb_first(&self->syms);
205
206 if (prevnd == NULL)
207 goto out_delete_line;
208
209 for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
210 struct symbol *prev = rb_entry(prevnd, struct symbol, rb_node),
211 *curr = rb_entry(nd, struct symbol, rb_node);
212
213 prev->end = curr->start - 1;
214 prevnd = nd;
215 }
216
217 free(line);
218 fclose(file);
219
220 return 0;
221
222out_delete_line:
223 free(line);
224out_failure:
225 return -1;
226}
227
228/**
229 * elf_symtab__for_each_symbol - iterate thru all the symbols
230 *
231 * @self: struct elf_symtab instance to iterate
232 * @index: uint32_t index
233 * @sym: GElf_Sym iterator
234 */
235#define elf_symtab__for_each_symbol(syms, nr_syms, index, sym) \
236 for (index = 0, gelf_getsym(syms, index, &sym);\
237 index < nr_syms; \
238 index++, gelf_getsym(syms, index, &sym))
239
240static inline uint8_t elf_sym__type(const GElf_Sym *sym)
241{
242 return GELF_ST_TYPE(sym->st_info);
243}
244
245static inline int elf_sym__is_function(const GElf_Sym *sym)
246{
247 return elf_sym__type(sym) == STT_FUNC &&
248 sym->st_name != 0 &&
249 sym->st_shndx != SHN_UNDEF &&
250 sym->st_size != 0;
251}
252
253static inline const char *elf_sym__name(const GElf_Sym *sym,
254 const Elf_Data *symstrs)
255{
256 return symstrs->d_buf + sym->st_name;
257}
258
259static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
260 GElf_Shdr *shp, const char *name,
261 size_t *index)
262{
263 Elf_Scn *sec = NULL;
264 size_t cnt = 1;
265
266 while ((sec = elf_nextscn(elf, sec)) != NULL) {
267 char *str;
268
269 gelf_getshdr(sec, shp);
270 str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name);
271 if (!strcmp(name, str)) {
272 if (index)
273 *index = cnt;
274 break;
275 }
276 ++cnt;
277 }
278
279 return sec;
280}
281
282static int dso__load_sym(struct dso *self, int fd, const char *name)
283{
284 Elf_Data *symstrs;
285 uint32_t nr_syms;
286 int err = -1;
287 uint32_t index;
288 GElf_Ehdr ehdr;
289 GElf_Shdr shdr;
290 Elf_Data *syms;
291 GElf_Sym sym;
292 Elf_Scn *sec;
293 Elf *elf;
294 int nr = 0;
295
296 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
297 if (elf == NULL) {
298 fprintf(stderr, "%s: cannot read %s ELF file.\n",
299 __func__, name);
300 goto out_close;
301 }
302
303 if (gelf_getehdr(elf, &ehdr) == NULL) {
304 fprintf(stderr, "%s: cannot get elf header.\n", __func__);
305 goto out_elf_end;
306 }
307
308 sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL);
309 if (sec == NULL)
310 sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL);
311
312 if (sec == NULL)
313 goto out_elf_end;
314
315 syms = elf_getdata(sec, NULL);
316 if (syms == NULL)
317 goto out_elf_end;
318
319 sec = elf_getscn(elf, shdr.sh_link);
320 if (sec == NULL)
321 goto out_elf_end;
322
323 symstrs = elf_getdata(sec, NULL);
324 if (symstrs == NULL)
325 goto out_elf_end;
326
327 nr_syms = shdr.sh_size / shdr.sh_entsize;
328
329 elf_symtab__for_each_symbol(syms, nr_syms, index, sym) {
330 struct symbol *f;
331
332 if (!elf_sym__is_function(&sym))
333 continue;
334
335 sec = elf_getscn(elf, sym.st_shndx);
336 if (!sec)
337 goto out_elf_end;
338
339 gelf_getshdr(sec, &shdr);
340 sym.st_value -= shdr.sh_addr - shdr.sh_offset;
341
342 f = symbol__new(sym.st_value, sym.st_size,
343 elf_sym__name(&sym, symstrs));
344 if (!f)
345 goto out_elf_end;
346
347 dso__insert_symbol(self, f);
348
349 nr++;
350 }
351
352 err = nr;
353out_elf_end:
354 elf_end(elf);
355out_close:
356 return err;
357}
358
359int dso__load(struct dso *self)
360{
361 int size = strlen(self->name) + sizeof("/usr/lib/debug%s.debug");
362 char *name = malloc(size);
363 int variant = 0;
364 int ret = -1;
365 int fd;
366
367 if (!name)
368 return -1;
369
370more:
371 do {
372 switch (variant) {
373 case 0: /* Fedora */
374 snprintf(name, size, "/usr/lib/debug%s.debug", self->name);
375 break;
376 case 1: /* Ubuntu */
377 snprintf(name, size, "/usr/lib/debug%s", self->name);
378 break;
379 case 2: /* Sane people */
380 snprintf(name, size, "%s", self->name);
381 break;
382
383 default:
384 goto out;
385 }
386 variant++;
387
388 fd = open(name, O_RDONLY);
389 } while (fd < 0);
390
391 ret = dso__load_sym(self, fd, name);
392 close(fd);
393
394 /*
395 * Some people seem to have debuginfo files _WITHOUT_ debug info!?!?
396 */
397 if (!ret)
398 goto more;
399
400out:
401 free(name);
402 return ret;
403}
404
405int dso__load_vmlinux(struct dso *self, const char *vmlinux)
406{
407 int err, fd = open(vmlinux, O_RDONLY);
408
409 if (fd < 0)
410 return -1;
411
412 err = dso__load_sym(self, fd, vmlinux);
413 close(fd);
414
415 return err;
416}
417
418void symbol__init(void)
419{
420 elf_version(EV_CURRENT);
421}
diff --git a/Documentation/perf_counter/util/symbol.h b/Documentation/perf_counter/util/symbol.h
new file mode 100644
index 000000000000..6dffe76a28f0
--- /dev/null
+++ b/Documentation/perf_counter/util/symbol.h
@@ -0,0 +1,33 @@
1#ifndef _PERF_SYMBOL_
2#define _PERF_SYMBOL_ 1
3
4#include <linux/types.h>
5#include "list.h"
6#include "rbtree.h"
7
8struct symbol {
9 struct rb_node rb_node;
10 __u64 start;
11 __u64 end;
12 char name[0];
13};
14
15struct dso {
16 struct list_head node;
17 struct rb_root syms;
18 char name[0];
19};
20
21struct dso *dso__new(const char *name);
22void dso__delete(struct dso *self);
23
24struct symbol *dso__find_symbol(struct dso *self, uint64_t ip);
25
26int dso__load_kallsyms(struct dso *self);
27int dso__load_vmlinux(struct dso *self, const char *vmlinux);
28int dso__load(struct dso *self);
29
30size_t dso__fprintf(struct dso *self, FILE *fp);
31
32void symbol__init(void);
33#endif /* _PERF_SYMBOL_ */