blob: 78c2efde01b7bee7a52665969cf0fcb87917b481 [file] [log] [blame]
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001#include "util.h"
2#include "../perf.h"
Arnaldo Carvalho de Meloa0055ae2009-06-01 17:50:19 -03003#include "string.h"
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03004#include "symbol.h"
5
6#include <libelf.h>
7#include <gelf.h>
8#include <elf.h>
9
Ingo Molnar0b73da32009-06-06 15:48:52 +020010const char *sym_hist_filter;
11
Paul Mackerras9cffa8d2009-06-19 22:21:42 +100012static struct symbol *symbol__new(u64 start, u64 len,
Ingo Molnar0b73da32009-06-06 15:48:52 +020013 const char *name, unsigned int priv_size,
Paul Mackerras9cffa8d2009-06-19 22:21:42 +100014 u64 obj_start, int verbose)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -030015{
Arnaldo Carvalho de Melo0085c9542009-05-28 14:55:13 -030016 size_t namelen = strlen(name) + 1;
Ingo Molnar0b73da32009-06-06 15:48:52 +020017 struct symbol *self = calloc(1, priv_size + sizeof(*self) + namelen);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -030018
Ingo Molnar0b73da32009-06-06 15:48:52 +020019 if (!self)
20 return NULL;
21
22 if (verbose >= 2)
23 printf("new symbol: %016Lx [%08lx]: %s, hist: %p, obj_start: %p\n",
Paul Mackerras9cffa8d2009-06-19 22:21:42 +100024 (u64)start, (unsigned long)len, name, self->hist, (void *)(unsigned long)obj_start);
Ingo Molnar0b73da32009-06-06 15:48:52 +020025
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))
Paul Mackerras9cffa8d2009-06-19 22:21:42 +100031 self->hist = calloc(sizeof(u64), len);
Ingo Molnar0b73da32009-06-06 15:48:52 +020032
33 if (priv_size) {
34 memset(self, 0, priv_size);
35 self = ((void *)self) + priv_size;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -030036 }
Ingo Molnar0b73da32009-06-06 15:48:52 +020037 self->start = start;
38 self->end = start + len - 1;
39 memcpy(self->name, name, namelen);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -030040
41 return self;
42}
43
Arnaldo Carvalho de Melo0085c9542009-05-28 14:55:13 -030044static void symbol__delete(struct symbol *self, unsigned int priv_size)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -030045{
Arnaldo Carvalho de Melo0085c9542009-05-28 14:55:13 -030046 free(((void *)self) - priv_size);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -030047}
48
49static 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
Arnaldo Carvalho de Melo0085c9542009-05-28 14:55:13 -030055struct dso *dso__new(const char *name, unsigned int sym_priv_size)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -030056{
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;
Arnaldo Carvalho de Melo0085c9542009-05-28 14:55:13 -030062 self->sym_priv_size = sym_priv_size;
Peter Zijlstrafc54db52009-06-05 14:04:59 +020063 self->find_symbol = dso__find_symbol;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -030064 }
65
66 return self;
67}
68
69static 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);
Arnaldo Carvalho de Meloc8c96522009-06-01 17:50:57 -030077 rb_erase(&pos->rb_node, &self->syms);
Arnaldo Carvalho de Melo0085c9542009-05-28 14:55:13 -030078 symbol__delete(pos, self->sym_priv_size);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -030079 }
80}
81
82void dso__delete(struct dso *self)
83{
84 dso__delete_symbols(self);
85 free(self);
86}
87
88static 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;
Paul Mackerras9cffa8d2009-06-19 22:21:42 +100092 const u64 ip = sym->start;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -030093 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
Paul Mackerras9cffa8d2009-06-19 22:21:42 +1000107struct symbol *dso__find_symbol(struct dso *self, u64 ip)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300108{
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
130size_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
Ingo Molnarbd741372009-06-04 14:13:04 +0200143static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int verbose)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300144{
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)) {
Paul Mackerras9cffa8d2009-06-19 22:21:42 +1000154 u64 start;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300155 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
Arnaldo Carvalho de Meloa0055ae2009-06-01 17:50:19 -0300168 len = hex2u64(line, &start);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300169
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 */
Arnaldo Carvalho de Melo0085c9542009-05-28 14:55:13 -0300183 sym = symbol__new(start, 0xdead, line + len + 2,
Ingo Molnar0b73da32009-06-06 15:48:52 +0200184 self->sym_priv_size, 0, verbose);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300185
186 if (sym == NULL)
187 goto out_delete_line;
188
Arnaldo Carvalho de Melo69ee69f2009-05-28 14:55:26 -0300189 if (filter && filter(self, sym))
190 symbol__delete(sym, self->sym_priv_size);
191 else
192 dso__insert_symbol(self, sym);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300193 }
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
217out_delete_line:
218 free(line);
219out_failure:
220 return -1;
221}
222
Pekka Enberg80d496b2009-06-08 21:12:48 +0300223static 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)) {
Paul Mackerras9cffa8d2009-06-19 22:21:42 +1000235 u64 start, size;
Pekka Enberg80d496b2009-06-08 21:12:48 +0300236 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
279out_delete_line:
280 free(line);
281out_failure:
282 return -1;
283}
284
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300285/**
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
297static inline uint8_t elf_sym__type(const GElf_Sym *sym)
298{
299 return GELF_ST_TYPE(sym->st_info);
300}
301
302static 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
310static 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
316static 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
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300339#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
349static int dso__synthesize_plt_symbols(struct dso *self, Elf *elf,
350 GElf_Ehdr *ehdr, Elf_Scn *scn_dynsym,
351 GElf_Shdr *shdr_dynsym,
Ingo Molnar0b73da32009-06-06 15:48:52 +0200352 size_t dynsym_idx, int verbose)
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300353{
354 uint32_t nr_rel_entries, idx;
355 GElf_Sym sym;
Paul Mackerras9cffa8d2009-06-19 22:21:42 +1000356 u64 plt_offset;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300357 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,
Ingo Molnar0b73da32009-06-06 15:48:52 +0200415 sympltname, self->sym_priv_size, 0, verbose);
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300416 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,
Ingo Molnar0b73da32009-06-06 15:48:52 +0200433 sympltname, self->sym_priv_size, 0, verbose);
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300434 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
Arnaldo Carvalho de Melo69ee69f2009-05-28 14:55:26 -0300450static int dso__load_sym(struct dso *self, int fd, const char *name,
Ingo Molnarbd741372009-06-04 14:13:04 +0200451 symbol_filter_t filter, int verbose)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300452{
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;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300461 Elf_Scn *sec, *sec_dynsym;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300462 Elf *elf;
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300463 size_t dynsym_idx;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300464 int nr = 0;
465
466 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
467 if (elf == NULL) {
Ingo Molnarbd741372009-06-04 14:13:04 +0200468 if (verbose)
469 fprintf(stderr, "%s: cannot read %s ELF file.\n",
470 __func__, name);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300471 goto out_close;
472 }
473
474 if (gelf_getehdr(elf, &ehdr) == NULL) {
Ingo Molnarbd741372009-06-04 14:13:04 +0200475 if (verbose)
476 fprintf(stderr, "%s: cannot get elf header.\n", __func__);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300477 goto out_elf_end;
478 }
479
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300480 /*
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,
Ingo Molnar0b73da32009-06-06 15:48:52 +0200490 dynsym_idx, verbose);
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300491 if (nr < 0)
492 goto out_elf_end;
493 }
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300494
Arnaldo Carvalho de Melo8ce998d2009-06-03 00:54:33 -0300495 /*
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 }
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300507
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
Arjan van de Vene9fbc9d2009-06-06 21:22:33 +0200522 memset(&sym, 0, sizeof(sym));
Arnaldo Carvalho de Melof5812a72009-06-30 11:43:17 -0300523 self->prelinked = elf_section_by_name(elf, &ehdr, &shdr,
524 ".gnu.prelink_undo",
525 NULL) != NULL;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300526 elf_symtab__for_each_symbol(syms, nr_syms, index, sym) {
527 struct symbol *f;
Paul Mackerras9cffa8d2009-06-19 22:21:42 +1000528 u64 obj_start;
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300529
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);
Ingo Molnar0b73da32009-06-06 15:48:52 +0200538 obj_start = sym.st_value;
539
Arnaldo Carvalho de Melof5812a72009-06-30 11:43:17 -0300540 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);
Peter Zijlstra520f2c32009-06-22 16:52:51 +0200544
Arnaldo Carvalho de Melof5812a72009-06-30 11:43:17 -0300545 sym.st_value -= shdr.sh_addr - shdr.sh_offset;
546 }
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300547
548 f = symbol__new(sym.st_value, sym.st_size,
Arnaldo Carvalho de Melo0085c9542009-05-28 14:55:13 -0300549 elf_sym__name(&sym, symstrs),
Ingo Molnar0b73da32009-06-06 15:48:52 +0200550 self->sym_priv_size, obj_start, verbose);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300551 if (!f)
552 goto out_elf_end;
553
Arnaldo Carvalho de Melo69ee69f2009-05-28 14:55:26 -0300554 if (filter && filter(self, f))
555 symbol__delete(f, self->sym_priv_size);
556 else {
557 dso__insert_symbol(self, f);
558 nr++;
559 }
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300560 }
561
562 err = nr;
563out_elf_end:
564 elf_end(elf);
565out_close:
566 return err;
567}
568
Ingo Molnarbd741372009-06-04 14:13:04 +0200569int dso__load(struct dso *self, symbol_filter_t filter, int verbose)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300570{
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
Arnaldo Carvalho de Melof5812a72009-06-30 11:43:17 -0300580 self->prelinked = 0;
581
Pekka Enberg80d496b2009-06-08 21:12:48 +0300582 if (strncmp(self->name, "/tmp/perf-", 10) == 0)
583 return dso__load_perf_map(self, filter, verbose);
584
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300585more:
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
Ingo Molnarbd741372009-06-04 14:13:04 +0200606 ret = dso__load_sym(self, fd, name, filter, verbose);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300607 close(fd);
608
609 /*
610 * Some people seem to have debuginfo files _WITHOUT_ debug info!?!?
611 */
612 if (!ret)
613 goto more;
614
615out:
616 free(name);
617 return ret;
618}
619
Arnaldo Carvalho de Melo69ee69f2009-05-28 14:55:26 -0300620static int dso__load_vmlinux(struct dso *self, const char *vmlinux,
Ingo Molnarbd741372009-06-04 14:13:04 +0200621 symbol_filter_t filter, int verbose)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300622{
623 int err, fd = open(vmlinux, O_RDONLY);
624
625 if (fd < 0)
626 return -1;
627
Ingo Molnarbd741372009-06-04 14:13:04 +0200628 err = dso__load_sym(self, fd, vmlinux, filter, verbose);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300629 close(fd);
630
631 return err;
632}
633
Ingo Molnarbd741372009-06-04 14:13:04 +0200634int dso__load_kernel(struct dso *self, const char *vmlinux,
635 symbol_filter_t filter, int verbose)
Arnaldo Carvalho de Meloa827c872009-05-28 14:55:19 -0300636{
637 int err = -1;
638
639 if (vmlinux)
Ingo Molnarbd741372009-06-04 14:13:04 +0200640 err = dso__load_vmlinux(self, vmlinux, filter, verbose);
Arnaldo Carvalho de Meloa827c872009-05-28 14:55:19 -0300641
Ingo Molnarc1f47b42009-06-21 13:58:51 +0200642 if (err < 0)
Ingo Molnarbd741372009-06-04 14:13:04 +0200643 err = dso__load_kallsyms(self, filter, verbose);
Arnaldo Carvalho de Meloa827c872009-05-28 14:55:19 -0300644
645 return err;
646}
647
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300648void symbol__init(void)
649{
650 elf_version(EV_CURRENT);
651}