Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jbarnes...
[linux-2.6] / tools / perf / util / symbol.c
1 #include "util.h"
2 #include "../perf.h"
3 #include "string.h"
4 #include "symbol.h"
5
6 #include <libelf.h>
7 #include <gelf.h>
8 #include <elf.h>
9
10 const char *sym_hist_filter;
11
12 static struct symbol *symbol__new(u64 start, u64 len,
13                                   const char *name, unsigned int priv_size,
14                                   u64 obj_start, int verbose)
15 {
16         size_t namelen = strlen(name) + 1;
17         struct symbol *self = calloc(1, priv_size + sizeof(*self) + namelen);
18
19         if (!self)
20                 return NULL;
21
22         if (verbose >= 2)
23                 printf("new symbol: %016Lx [%08lx]: %s, hist: %p, obj_start: %p\n",
24                         (u64)start, (unsigned long)len, name, self->hist, (void *)(unsigned long)obj_start);
25
26         self->obj_start= obj_start;
27         self->hist = NULL;
28         self->hist_sum = 0;
29
30         if (sym_hist_filter && !strcmp(name, sym_hist_filter))
31                 self->hist = calloc(sizeof(u64), len);
32
33         if (priv_size) {
34                 memset(self, 0, priv_size);
35                 self = ((void *)self) + priv_size;
36         }
37         self->start = start;
38         self->end   = start + len - 1;
39         memcpy(self->name, name, namelen);
40
41         return self;
42 }
43
44 static void symbol__delete(struct symbol *self, unsigned int priv_size)
45 {
46         free(((void *)self) - priv_size);
47 }
48
49 static size_t symbol__fprintf(struct symbol *self, FILE *fp)
50 {
51         return fprintf(fp, " %llx-%llx %s\n",
52                        self->start, self->end, self->name);
53 }
54
55 struct dso *dso__new(const char *name, unsigned int sym_priv_size)
56 {
57         struct dso *self = malloc(sizeof(*self) + strlen(name) + 1);
58
59         if (self != NULL) {
60                 strcpy(self->name, name);
61                 self->syms = RB_ROOT;
62                 self->sym_priv_size = sym_priv_size;
63                 self->find_symbol = dso__find_symbol;
64         }
65
66         return self;
67 }
68
69 static void dso__delete_symbols(struct dso *self)
70 {
71         struct symbol *pos;
72         struct rb_node *next = rb_first(&self->syms);
73
74         while (next) {
75                 pos = rb_entry(next, struct symbol, rb_node);
76                 next = rb_next(&pos->rb_node);
77                 rb_erase(&pos->rb_node, &self->syms);
78                 symbol__delete(pos, self->sym_priv_size);
79         }
80 }
81
82 void dso__delete(struct dso *self)
83 {
84         dso__delete_symbols(self);
85         free(self);
86 }
87
88 static void dso__insert_symbol(struct dso *self, struct symbol *sym)
89 {
90         struct rb_node **p = &self->syms.rb_node;
91         struct rb_node *parent = NULL;
92         const u64 ip = sym->start;
93         struct symbol *s;
94
95         while (*p != NULL) {
96                 parent = *p;
97                 s = rb_entry(parent, struct symbol, rb_node);
98                 if (ip < s->start)
99                         p = &(*p)->rb_left;
100                 else
101                         p = &(*p)->rb_right;
102         }
103         rb_link_node(&sym->rb_node, parent, p);
104         rb_insert_color(&sym->rb_node, &self->syms);
105 }
106
107 struct symbol *dso__find_symbol(struct dso *self, u64 ip)
108 {
109         struct rb_node *n;
110
111         if (self == NULL)
112                 return NULL;
113
114         n = self->syms.rb_node;
115
116         while (n) {
117                 struct symbol *s = rb_entry(n, struct symbol, rb_node);
118
119                 if (ip < s->start)
120                         n = n->rb_left;
121                 else if (ip > s->end)
122                         n = n->rb_right;
123                 else
124                         return s;
125         }
126
127         return NULL;
128 }
129
130 size_t dso__fprintf(struct dso *self, FILE *fp)
131 {
132         size_t ret = fprintf(fp, "dso: %s\n", self->name);
133
134         struct rb_node *nd;
135         for (nd = rb_first(&self->syms); nd; nd = rb_next(nd)) {
136                 struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
137                 ret += symbol__fprintf(pos, fp);
138         }
139
140         return ret;
141 }
142
143 static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int verbose)
144 {
145         struct rb_node *nd, *prevnd;
146         char *line = NULL;
147         size_t n;
148         FILE *file = fopen("/proc/kallsyms", "r");
149
150         if (file == NULL)
151                 goto out_failure;
152
153         while (!feof(file)) {
154                 u64 start;
155                 struct symbol *sym;
156                 int line_len, len;
157                 char symbol_type;
158
159                 line_len = getline(&line, &n, file);
160                 if (line_len < 0)
161                         break;
162
163                 if (!line)
164                         goto out_failure;
165
166                 line[--line_len] = '\0'; /* \n */
167
168                 len = hex2u64(line, &start);
169
170                 len++;
171                 if (len + 2 >= line_len)
172                         continue;
173
174                 symbol_type = toupper(line[len]);
175                 /*
176                  * We're interested only in code ('T'ext)
177                  */
178                 if (symbol_type != 'T' && symbol_type != 'W')
179                         continue;
180                 /*
181                  * Well fix up the end later, when we have all sorted.
182                  */
183                 sym = symbol__new(start, 0xdead, line + len + 2,
184                                   self->sym_priv_size, 0, verbose);
185
186                 if (sym == NULL)
187                         goto out_delete_line;
188
189                 if (filter && filter(self, sym))
190                         symbol__delete(sym, self->sym_priv_size);
191                 else
192                         dso__insert_symbol(self, sym);
193         }
194
195         /*
196          * Now that we have all sorted out, just set the ->end of all
197          * symbols
198          */
199         prevnd = rb_first(&self->syms);
200
201         if (prevnd == NULL)
202                 goto out_delete_line;
203
204         for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
205                 struct symbol *prev = rb_entry(prevnd, struct symbol, rb_node),
206                               *curr = rb_entry(nd, struct symbol, rb_node);
207
208                 prev->end = curr->start - 1;
209                 prevnd = nd;
210         }
211
212         free(line);
213         fclose(file);
214
215         return 0;
216
217 out_delete_line:
218         free(line);
219 out_failure:
220         return -1;
221 }
222
223 static int dso__load_perf_map(struct dso *self, symbol_filter_t filter, int verbose)
224 {
225         char *line = NULL;
226         size_t n;
227         FILE *file;
228         int nr_syms = 0;
229
230         file = fopen(self->name, "r");
231         if (file == NULL)
232                 goto out_failure;
233
234         while (!feof(file)) {
235                 u64 start, size;
236                 struct symbol *sym;
237                 int line_len, len;
238
239                 line_len = getline(&line, &n, file);
240                 if (line_len < 0)
241                         break;
242
243                 if (!line)
244                         goto out_failure;
245
246                 line[--line_len] = '\0'; /* \n */
247
248                 len = hex2u64(line, &start);
249
250                 len++;
251                 if (len + 2 >= line_len)
252                         continue;
253
254                 len += hex2u64(line + len, &size);
255
256                 len++;
257                 if (len + 2 >= line_len)
258                         continue;
259
260                 sym = symbol__new(start, size, line + len,
261                                   self->sym_priv_size, start, verbose);
262
263                 if (sym == NULL)
264                         goto out_delete_line;
265
266                 if (filter && filter(self, sym))
267                         symbol__delete(sym, self->sym_priv_size);
268                 else {
269                         dso__insert_symbol(self, sym);
270                         nr_syms++;
271                 }
272         }
273
274         free(line);
275         fclose(file);
276
277         return nr_syms;
278
279 out_delete_line:
280         free(line);
281 out_failure:
282         return -1;
283 }
284
285 /**
286  * elf_symtab__for_each_symbol - iterate thru all the symbols
287  *
288  * @self: struct elf_symtab instance to iterate
289  * @index: uint32_t index
290  * @sym: GElf_Sym iterator
291  */
292 #define elf_symtab__for_each_symbol(syms, nr_syms, index, sym) \
293         for (index = 0, gelf_getsym(syms, index, &sym);\
294              index < nr_syms; \
295              index++, gelf_getsym(syms, index, &sym))
296
297 static inline uint8_t elf_sym__type(const GElf_Sym *sym)
298 {
299         return GELF_ST_TYPE(sym->st_info);
300 }
301
302 static inline int elf_sym__is_function(const GElf_Sym *sym)
303 {
304         return elf_sym__type(sym) == STT_FUNC &&
305                sym->st_name != 0 &&
306                sym->st_shndx != SHN_UNDEF &&
307                sym->st_size != 0;
308 }
309
310 static inline const char *elf_sym__name(const GElf_Sym *sym,
311                                         const Elf_Data *symstrs)
312 {
313         return symstrs->d_buf + sym->st_name;
314 }
315
316 static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
317                                     GElf_Shdr *shp, const char *name,
318                                     size_t *index)
319 {
320         Elf_Scn *sec = NULL;
321         size_t cnt = 1;
322
323         while ((sec = elf_nextscn(elf, sec)) != NULL) {
324                 char *str;
325
326                 gelf_getshdr(sec, shp);
327                 str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name);
328                 if (!strcmp(name, str)) {
329                         if (index)
330                                 *index = cnt;
331                         break;
332                 }
333                 ++cnt;
334         }
335
336         return sec;
337 }
338
339 #define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \
340         for (idx = 0, pos = gelf_getrel(reldata, 0, &pos_mem); \
341              idx < nr_entries; \
342              ++idx, pos = gelf_getrel(reldata, idx, &pos_mem))
343
344 #define elf_section__for_each_rela(reldata, pos, pos_mem, idx, nr_entries) \
345         for (idx = 0, pos = gelf_getrela(reldata, 0, &pos_mem); \
346              idx < nr_entries; \
347              ++idx, pos = gelf_getrela(reldata, idx, &pos_mem))
348
349 static int dso__synthesize_plt_symbols(struct  dso *self, Elf *elf,
350                                        GElf_Ehdr *ehdr, Elf_Scn *scn_dynsym,
351                                        GElf_Shdr *shdr_dynsym,
352                                        size_t dynsym_idx, int verbose)
353 {
354         uint32_t nr_rel_entries, idx;
355         GElf_Sym sym;
356         u64 plt_offset;
357         GElf_Shdr shdr_plt;
358         struct symbol *f;
359         GElf_Shdr shdr_rel_plt;
360         Elf_Data *reldata, *syms, *symstrs;
361         Elf_Scn *scn_plt_rel, *scn_symstrs;
362         char sympltname[1024];
363         int nr = 0, symidx;
364
365         scn_plt_rel = elf_section_by_name(elf, ehdr, &shdr_rel_plt,
366                                           ".rela.plt", NULL);
367         if (scn_plt_rel == NULL) {
368                 scn_plt_rel = elf_section_by_name(elf, ehdr, &shdr_rel_plt,
369                                                   ".rel.plt", NULL);
370                 if (scn_plt_rel == NULL)
371                         return 0;
372         }
373
374         if (shdr_rel_plt.sh_link != dynsym_idx)
375                 return 0;
376
377         if (elf_section_by_name(elf, ehdr, &shdr_plt, ".plt", NULL) == NULL)
378                 return 0;
379
380         /*
381          * Fetch the relocation section to find the indexes to the GOT
382          * and the symbols in the .dynsym they refer to.
383          */
384         reldata = elf_getdata(scn_plt_rel, NULL);
385         if (reldata == NULL)
386                 return -1;
387
388         syms = elf_getdata(scn_dynsym, NULL);
389         if (syms == NULL)
390                 return -1;
391
392         scn_symstrs = elf_getscn(elf, shdr_dynsym->sh_link);
393         if (scn_symstrs == NULL)
394                 return -1;
395
396         symstrs = elf_getdata(scn_symstrs, NULL);
397         if (symstrs == NULL)
398                 return -1;
399
400         nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize;
401         plt_offset = shdr_plt.sh_offset;
402
403         if (shdr_rel_plt.sh_type == SHT_RELA) {
404                 GElf_Rela pos_mem, *pos;
405
406                 elf_section__for_each_rela(reldata, pos, pos_mem, idx,
407                                            nr_rel_entries) {
408                         symidx = GELF_R_SYM(pos->r_info);
409                         plt_offset += shdr_plt.sh_entsize;
410                         gelf_getsym(syms, symidx, &sym);
411                         snprintf(sympltname, sizeof(sympltname),
412                                  "%s@plt", elf_sym__name(&sym, symstrs));
413
414                         f = symbol__new(plt_offset, shdr_plt.sh_entsize,
415                                         sympltname, self->sym_priv_size, 0, verbose);
416                         if (!f)
417                                 return -1;
418
419                         dso__insert_symbol(self, f);
420                         ++nr;
421                 }
422         } else if (shdr_rel_plt.sh_type == SHT_REL) {
423                 GElf_Rel pos_mem, *pos;
424                 elf_section__for_each_rel(reldata, pos, pos_mem, idx,
425                                           nr_rel_entries) {
426                         symidx = GELF_R_SYM(pos->r_info);
427                         plt_offset += shdr_plt.sh_entsize;
428                         gelf_getsym(syms, symidx, &sym);
429                         snprintf(sympltname, sizeof(sympltname),
430                                  "%s@plt", elf_sym__name(&sym, symstrs));
431
432                         f = symbol__new(plt_offset, shdr_plt.sh_entsize,
433                                         sympltname, self->sym_priv_size, 0, verbose);
434                         if (!f)
435                                 return -1;
436
437                         dso__insert_symbol(self, f);
438                         ++nr;
439                 }
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         }
446
447         return nr;
448 }
449
450 static int dso__load_sym(struct dso *self, int fd, const char *name,
451                          symbol_filter_t filter, int verbose)
452 {
453         Elf_Data *symstrs;
454         uint32_t nr_syms;
455         int err = -1;
456         uint32_t index;
457         GElf_Ehdr ehdr;
458         GElf_Shdr shdr;
459         Elf_Data *syms;
460         GElf_Sym sym;
461         Elf_Scn *sec, *sec_dynsym;
462         Elf *elf;
463         size_t dynsym_idx;
464         int nr = 0;
465
466         elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
467         if (elf == NULL) {
468                 if (verbose)
469                         fprintf(stderr, "%s: cannot read %s ELF file.\n",
470                                 __func__, name);
471                 goto out_close;
472         }
473
474         if (gelf_getehdr(elf, &ehdr) == NULL) {
475                 if (verbose)
476                         fprintf(stderr, "%s: cannot get elf header.\n", __func__);
477                 goto out_elf_end;
478         }
479
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);
500         if (sec == NULL) {
501                 if (sec_dynsym == NULL)
502                         goto out_elf_end;
503
504                 sec = sec_dynsym;
505                 gelf_getshdr(sec, &shdr);
506         }
507
508         syms = elf_getdata(sec, NULL);
509         if (syms == NULL)
510                 goto out_elf_end;
511
512         sec = elf_getscn(elf, shdr.sh_link);
513         if (sec == NULL)
514                 goto out_elf_end;
515
516         symstrs = elf_getdata(sec, NULL);
517         if (symstrs == NULL)
518                 goto out_elf_end;
519
520         nr_syms = shdr.sh_size / shdr.sh_entsize;
521
522         memset(&sym, 0, sizeof(sym));
523         self->prelinked = elf_section_by_name(elf, &ehdr, &shdr,
524                                               ".gnu.prelink_undo",
525                                               NULL) != NULL;
526         elf_symtab__for_each_symbol(syms, nr_syms, index, sym) {
527                 struct symbol *f;
528                 u64 obj_start;
529
530                 if (!elf_sym__is_function(&sym))
531                         continue;
532
533                 sec = elf_getscn(elf, sym.st_shndx);
534                 if (!sec)
535                         goto out_elf_end;
536
537                 gelf_getshdr(sec, &shdr);
538                 obj_start = sym.st_value;
539
540                 if (self->prelinked) {
541                         if (verbose >= 2)
542                                 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);
544
545                         sym.st_value -= shdr.sh_addr - shdr.sh_offset;
546                 }
547
548                 f = symbol__new(sym.st_value, sym.st_size,
549                                 elf_sym__name(&sym, symstrs),
550                                 self->sym_priv_size, obj_start, verbose);
551                 if (!f)
552                         goto out_elf_end;
553
554                 if (filter && filter(self, f))
555                         symbol__delete(f, self->sym_priv_size);
556                 else {
557                         dso__insert_symbol(self, f);
558                         nr++;
559                 }
560         }
561
562         err = nr;
563 out_elf_end:
564         elf_end(elf);
565 out_close:
566         return err;
567 }
568
569 int dso__load(struct dso *self, symbol_filter_t filter, int verbose)
570 {
571         int size = strlen(self->name) + sizeof("/usr/lib/debug%s.debug");
572         char *name = malloc(size);
573         int variant = 0;
574         int ret = -1;
575         int fd;
576
577         if (!name)
578                 return -1;
579
580         self->prelinked = 0;
581
582         if (strncmp(self->name, "/tmp/perf-", 10) == 0)
583                 return dso__load_perf_map(self, filter, verbose);
584
585 more:
586         do {
587                 switch (variant) {
588                 case 0: /* Fedora */
589                         snprintf(name, size, "/usr/lib/debug%s.debug", self->name);
590                         break;
591                 case 1: /* Ubuntu */
592                         snprintf(name, size, "/usr/lib/debug%s", self->name);
593                         break;
594                 case 2: /* Sane people */
595                         snprintf(name, size, "%s", self->name);
596                         break;
597
598                 default:
599                         goto out;
600                 }
601                 variant++;
602
603                 fd = open(name, O_RDONLY);
604         } while (fd < 0);
605
606         ret = dso__load_sym(self, fd, name, filter, verbose);
607         close(fd);
608
609         /*
610          * Some people seem to have debuginfo files _WITHOUT_ debug info!?!?
611          */
612         if (!ret)
613                 goto more;
614
615 out:
616         free(name);
617         return ret;
618 }
619
620 static int dso__load_vmlinux(struct dso *self, const char *vmlinux,
621                              symbol_filter_t filter, int verbose)
622 {
623         int err, fd = open(vmlinux, O_RDONLY);
624
625         if (fd < 0)
626                 return -1;
627
628         err = dso__load_sym(self, fd, vmlinux, filter, verbose);
629         close(fd);
630
631         return err;
632 }
633
634 int dso__load_kernel(struct dso *self, const char *vmlinux,
635                      symbol_filter_t filter, int verbose)
636 {
637         int err = -1;
638
639         if (vmlinux)
640                 err = dso__load_vmlinux(self, vmlinux, filter, verbose);
641
642         if (err < 0)
643                 err = dso__load_kallsyms(self, filter, verbose);
644
645         return err;
646 }
647
648 void symbol__init(void)
649 {
650         elf_version(EV_CURRENT);
651 }