186470930SIngo Molnar #include "util.h" 286470930SIngo Molnar #include "../perf.h" 386470930SIngo Molnar #include "string.h" 486470930SIngo Molnar #include "symbol.h" 586470930SIngo Molnar 68f28827aSFrederic Weisbecker #include "debug.h" 78f28827aSFrederic Weisbecker 886470930SIngo Molnar #include <libelf.h> 986470930SIngo Molnar #include <gelf.h> 1086470930SIngo Molnar #include <elf.h> 112cdbc46dSPeter Zijlstra 1286470930SIngo Molnar const char *sym_hist_filter; 1386470930SIngo Molnar 1494cb9e38SArnaldo Carvalho de Melo enum dso_origin { 1594cb9e38SArnaldo Carvalho de Melo DSO__ORIG_KERNEL = 0, 1694cb9e38SArnaldo Carvalho de Melo DSO__ORIG_JAVA_JIT, 1794cb9e38SArnaldo Carvalho de Melo DSO__ORIG_FEDORA, 1894cb9e38SArnaldo Carvalho de Melo DSO__ORIG_UBUNTU, 1994cb9e38SArnaldo Carvalho de Melo DSO__ORIG_BUILDID, 2094cb9e38SArnaldo Carvalho de Melo DSO__ORIG_DSO, 2194cb9e38SArnaldo Carvalho de Melo DSO__ORIG_NOT_FOUND, 2294cb9e38SArnaldo Carvalho de Melo }; 2394cb9e38SArnaldo Carvalho de Melo 249cffa8d5SPaul Mackerras static struct symbol *symbol__new(u64 start, u64 len, 2586470930SIngo Molnar const char *name, unsigned int priv_size, 2683a0944fSIngo Molnar u64 obj_start, int v) 2786470930SIngo Molnar { 2886470930SIngo Molnar size_t namelen = strlen(name) + 1; 2986470930SIngo Molnar struct symbol *self = calloc(1, priv_size + sizeof(*self) + namelen); 3086470930SIngo Molnar 3186470930SIngo Molnar if (!self) 3286470930SIngo Molnar return NULL; 3386470930SIngo Molnar 3483a0944fSIngo Molnar if (v >= 2) 3586470930SIngo Molnar printf("new symbol: %016Lx [%08lx]: %s, hist: %p, obj_start: %p\n", 369cffa8d5SPaul Mackerras (u64)start, (unsigned long)len, name, self->hist, (void *)(unsigned long)obj_start); 3786470930SIngo Molnar 3886470930SIngo Molnar self->obj_start= obj_start; 3986470930SIngo Molnar self->hist = NULL; 4086470930SIngo Molnar self->hist_sum = 0; 4186470930SIngo Molnar 4286470930SIngo Molnar if (sym_hist_filter && !strcmp(name, sym_hist_filter)) 439cffa8d5SPaul Mackerras self->hist = calloc(sizeof(u64), len); 4486470930SIngo Molnar 4586470930SIngo Molnar if (priv_size) { 4686470930SIngo Molnar memset(self, 0, priv_size); 4786470930SIngo Molnar self = ((void *)self) + priv_size; 4886470930SIngo Molnar } 4986470930SIngo Molnar self->start = start; 506cfcc53eSMike Galbraith self->end = len ? start + len - 1 : start; 5186470930SIngo Molnar memcpy(self->name, name, namelen); 5286470930SIngo Molnar 5386470930SIngo Molnar return self; 5486470930SIngo Molnar } 5586470930SIngo Molnar 5686470930SIngo Molnar static void symbol__delete(struct symbol *self, unsigned int priv_size) 5786470930SIngo Molnar { 5886470930SIngo Molnar free(((void *)self) - priv_size); 5986470930SIngo Molnar } 6086470930SIngo Molnar 6186470930SIngo Molnar static size_t symbol__fprintf(struct symbol *self, FILE *fp) 6286470930SIngo Molnar { 636cfcc53eSMike Galbraith if (!self->module) 6486470930SIngo Molnar return fprintf(fp, " %llx-%llx %s\n", 6586470930SIngo Molnar self->start, self->end, self->name); 666cfcc53eSMike Galbraith else 676cfcc53eSMike Galbraith return fprintf(fp, " %llx-%llx %s \t[%s]\n", 686cfcc53eSMike Galbraith self->start, self->end, self->name, self->module->name); 6986470930SIngo Molnar } 7086470930SIngo Molnar 7186470930SIngo Molnar struct dso *dso__new(const char *name, unsigned int sym_priv_size) 7286470930SIngo Molnar { 7386470930SIngo Molnar struct dso *self = malloc(sizeof(*self) + strlen(name) + 1); 7486470930SIngo Molnar 7586470930SIngo Molnar if (self != NULL) { 7686470930SIngo Molnar strcpy(self->name, name); 7786470930SIngo Molnar self->syms = RB_ROOT; 7886470930SIngo Molnar self->sym_priv_size = sym_priv_size; 7986470930SIngo Molnar self->find_symbol = dso__find_symbol; 8052d422deSArnaldo Carvalho de Melo self->slen_calculated = 0; 8194cb9e38SArnaldo Carvalho de Melo self->origin = DSO__ORIG_NOT_FOUND; 8286470930SIngo Molnar } 8386470930SIngo Molnar 8486470930SIngo Molnar return self; 8586470930SIngo Molnar } 8686470930SIngo Molnar 8786470930SIngo Molnar static void dso__delete_symbols(struct dso *self) 8886470930SIngo Molnar { 8986470930SIngo Molnar struct symbol *pos; 9086470930SIngo Molnar struct rb_node *next = rb_first(&self->syms); 9186470930SIngo Molnar 9286470930SIngo Molnar while (next) { 9386470930SIngo Molnar pos = rb_entry(next, struct symbol, rb_node); 9486470930SIngo Molnar next = rb_next(&pos->rb_node); 9586470930SIngo Molnar rb_erase(&pos->rb_node, &self->syms); 9686470930SIngo Molnar symbol__delete(pos, self->sym_priv_size); 9786470930SIngo Molnar } 9886470930SIngo Molnar } 9986470930SIngo Molnar 10086470930SIngo Molnar void dso__delete(struct dso *self) 10186470930SIngo Molnar { 10286470930SIngo Molnar dso__delete_symbols(self); 10386470930SIngo Molnar free(self); 10486470930SIngo Molnar } 10586470930SIngo Molnar 10686470930SIngo Molnar static void dso__insert_symbol(struct dso *self, struct symbol *sym) 10786470930SIngo Molnar { 10886470930SIngo Molnar struct rb_node **p = &self->syms.rb_node; 10986470930SIngo Molnar struct rb_node *parent = NULL; 1109cffa8d5SPaul Mackerras const u64 ip = sym->start; 11186470930SIngo Molnar struct symbol *s; 11286470930SIngo Molnar 11386470930SIngo Molnar while (*p != NULL) { 11486470930SIngo Molnar parent = *p; 11586470930SIngo Molnar s = rb_entry(parent, struct symbol, rb_node); 11686470930SIngo Molnar if (ip < s->start) 11786470930SIngo Molnar p = &(*p)->rb_left; 11886470930SIngo Molnar else 11986470930SIngo Molnar p = &(*p)->rb_right; 12086470930SIngo Molnar } 12186470930SIngo Molnar rb_link_node(&sym->rb_node, parent, p); 12286470930SIngo Molnar rb_insert_color(&sym->rb_node, &self->syms); 12386470930SIngo Molnar } 12486470930SIngo Molnar 1259cffa8d5SPaul Mackerras struct symbol *dso__find_symbol(struct dso *self, u64 ip) 12686470930SIngo Molnar { 12786470930SIngo Molnar struct rb_node *n; 12886470930SIngo Molnar 12986470930SIngo Molnar if (self == NULL) 13086470930SIngo Molnar return NULL; 13186470930SIngo Molnar 13286470930SIngo Molnar n = self->syms.rb_node; 13386470930SIngo Molnar 13486470930SIngo Molnar while (n) { 13586470930SIngo Molnar struct symbol *s = rb_entry(n, struct symbol, rb_node); 13686470930SIngo Molnar 13786470930SIngo Molnar if (ip < s->start) 13886470930SIngo Molnar n = n->rb_left; 13986470930SIngo Molnar else if (ip > s->end) 14086470930SIngo Molnar n = n->rb_right; 14186470930SIngo Molnar else 14286470930SIngo Molnar return s; 14386470930SIngo Molnar } 14486470930SIngo Molnar 14586470930SIngo Molnar return NULL; 14686470930SIngo Molnar } 14786470930SIngo Molnar 14886470930SIngo Molnar size_t dso__fprintf(struct dso *self, FILE *fp) 14986470930SIngo Molnar { 15086470930SIngo Molnar size_t ret = fprintf(fp, "dso: %s\n", self->name); 15186470930SIngo Molnar 15286470930SIngo Molnar struct rb_node *nd; 15386470930SIngo Molnar for (nd = rb_first(&self->syms); nd; nd = rb_next(nd)) { 15486470930SIngo Molnar struct symbol *pos = rb_entry(nd, struct symbol, rb_node); 15586470930SIngo Molnar ret += symbol__fprintf(pos, fp); 15686470930SIngo Molnar } 15786470930SIngo Molnar 15886470930SIngo Molnar return ret; 15986470930SIngo Molnar } 16086470930SIngo Molnar 16183a0944fSIngo Molnar static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int v) 16286470930SIngo Molnar { 16386470930SIngo Molnar struct rb_node *nd, *prevnd; 16486470930SIngo Molnar char *line = NULL; 16586470930SIngo Molnar size_t n; 16686470930SIngo Molnar FILE *file = fopen("/proc/kallsyms", "r"); 1679974f496SMike Galbraith int count = 0; 16886470930SIngo Molnar 16986470930SIngo Molnar if (file == NULL) 17086470930SIngo Molnar goto out_failure; 17186470930SIngo Molnar 17286470930SIngo Molnar while (!feof(file)) { 1739cffa8d5SPaul Mackerras u64 start; 17486470930SIngo Molnar struct symbol *sym; 17586470930SIngo Molnar int line_len, len; 17686470930SIngo Molnar char symbol_type; 17786470930SIngo Molnar 17886470930SIngo Molnar line_len = getline(&line, &n, file); 17986470930SIngo Molnar if (line_len < 0) 18086470930SIngo Molnar break; 18186470930SIngo Molnar 18286470930SIngo Molnar if (!line) 18386470930SIngo Molnar goto out_failure; 18486470930SIngo Molnar 18586470930SIngo Molnar line[--line_len] = '\0'; /* \n */ 18686470930SIngo Molnar 18786470930SIngo Molnar len = hex2u64(line, &start); 18886470930SIngo Molnar 18986470930SIngo Molnar len++; 19086470930SIngo Molnar if (len + 2 >= line_len) 19186470930SIngo Molnar continue; 19286470930SIngo Molnar 19386470930SIngo Molnar symbol_type = toupper(line[len]); 19486470930SIngo Molnar /* 19586470930SIngo Molnar * We're interested only in code ('T'ext) 19686470930SIngo Molnar */ 19786470930SIngo Molnar if (symbol_type != 'T' && symbol_type != 'W') 19886470930SIngo Molnar continue; 19986470930SIngo Molnar /* 20086470930SIngo Molnar * Well fix up the end later, when we have all sorted. 20186470930SIngo Molnar */ 20286470930SIngo Molnar sym = symbol__new(start, 0xdead, line + len + 2, 20383a0944fSIngo Molnar self->sym_priv_size, 0, v); 20486470930SIngo Molnar 20586470930SIngo Molnar if (sym == NULL) 20686470930SIngo Molnar goto out_delete_line; 20786470930SIngo Molnar 20886470930SIngo Molnar if (filter && filter(self, sym)) 20986470930SIngo Molnar symbol__delete(sym, self->sym_priv_size); 2109974f496SMike Galbraith else { 21186470930SIngo Molnar dso__insert_symbol(self, sym); 2129974f496SMike Galbraith count++; 2139974f496SMike Galbraith } 21486470930SIngo Molnar } 21586470930SIngo Molnar 21686470930SIngo Molnar /* 21786470930SIngo Molnar * Now that we have all sorted out, just set the ->end of all 21886470930SIngo Molnar * symbols 21986470930SIngo Molnar */ 22086470930SIngo Molnar prevnd = rb_first(&self->syms); 22186470930SIngo Molnar 22286470930SIngo Molnar if (prevnd == NULL) 22386470930SIngo Molnar goto out_delete_line; 22486470930SIngo Molnar 22586470930SIngo Molnar for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) { 22686470930SIngo Molnar struct symbol *prev = rb_entry(prevnd, struct symbol, rb_node), 22786470930SIngo Molnar *curr = rb_entry(nd, struct symbol, rb_node); 22886470930SIngo Molnar 22986470930SIngo Molnar prev->end = curr->start - 1; 23086470930SIngo Molnar prevnd = nd; 23186470930SIngo Molnar } 23286470930SIngo Molnar 23386470930SIngo Molnar free(line); 23486470930SIngo Molnar fclose(file); 23586470930SIngo Molnar 2369974f496SMike Galbraith return count; 23786470930SIngo Molnar 23886470930SIngo Molnar out_delete_line: 23986470930SIngo Molnar free(line); 24086470930SIngo Molnar out_failure: 24186470930SIngo Molnar return -1; 24286470930SIngo Molnar } 24386470930SIngo Molnar 24483a0944fSIngo Molnar static int dso__load_perf_map(struct dso *self, symbol_filter_t filter, int v) 24580d496beSPekka Enberg { 24680d496beSPekka Enberg char *line = NULL; 24780d496beSPekka Enberg size_t n; 24880d496beSPekka Enberg FILE *file; 24980d496beSPekka Enberg int nr_syms = 0; 25080d496beSPekka Enberg 25180d496beSPekka Enberg file = fopen(self->name, "r"); 25280d496beSPekka Enberg if (file == NULL) 25380d496beSPekka Enberg goto out_failure; 25480d496beSPekka Enberg 25580d496beSPekka Enberg while (!feof(file)) { 2569cffa8d5SPaul Mackerras u64 start, size; 25780d496beSPekka Enberg struct symbol *sym; 25880d496beSPekka Enberg int line_len, len; 25980d496beSPekka Enberg 26080d496beSPekka Enberg line_len = getline(&line, &n, file); 26180d496beSPekka Enberg if (line_len < 0) 26280d496beSPekka Enberg break; 26380d496beSPekka Enberg 26480d496beSPekka Enberg if (!line) 26580d496beSPekka Enberg goto out_failure; 26680d496beSPekka Enberg 26780d496beSPekka Enberg line[--line_len] = '\0'; /* \n */ 26880d496beSPekka Enberg 26980d496beSPekka Enberg len = hex2u64(line, &start); 27080d496beSPekka Enberg 27180d496beSPekka Enberg len++; 27280d496beSPekka Enberg if (len + 2 >= line_len) 27380d496beSPekka Enberg continue; 27480d496beSPekka Enberg 27580d496beSPekka Enberg len += hex2u64(line + len, &size); 27680d496beSPekka Enberg 27780d496beSPekka Enberg len++; 27880d496beSPekka Enberg if (len + 2 >= line_len) 27980d496beSPekka Enberg continue; 28080d496beSPekka Enberg 28180d496beSPekka Enberg sym = symbol__new(start, size, line + len, 28283a0944fSIngo Molnar self->sym_priv_size, start, v); 28380d496beSPekka Enberg 28480d496beSPekka Enberg if (sym == NULL) 28580d496beSPekka Enberg goto out_delete_line; 28680d496beSPekka Enberg 28780d496beSPekka Enberg if (filter && filter(self, sym)) 28880d496beSPekka Enberg symbol__delete(sym, self->sym_priv_size); 28980d496beSPekka Enberg else { 29080d496beSPekka Enberg dso__insert_symbol(self, sym); 29180d496beSPekka Enberg nr_syms++; 29280d496beSPekka Enberg } 29380d496beSPekka Enberg } 29480d496beSPekka Enberg 29580d496beSPekka Enberg free(line); 29680d496beSPekka Enberg fclose(file); 29780d496beSPekka Enberg 29880d496beSPekka Enberg return nr_syms; 29980d496beSPekka Enberg 30080d496beSPekka Enberg out_delete_line: 30180d496beSPekka Enberg free(line); 30280d496beSPekka Enberg out_failure: 30380d496beSPekka Enberg return -1; 30480d496beSPekka Enberg } 30580d496beSPekka Enberg 30686470930SIngo Molnar /** 30786470930SIngo Molnar * elf_symtab__for_each_symbol - iterate thru all the symbols 30886470930SIngo Molnar * 30986470930SIngo Molnar * @self: struct elf_symtab instance to iterate 31083a0944fSIngo Molnar * @idx: uint32_t idx 31186470930SIngo Molnar * @sym: GElf_Sym iterator 31286470930SIngo Molnar */ 31383a0944fSIngo Molnar #define elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) \ 31483a0944fSIngo Molnar for (idx = 0, gelf_getsym(syms, idx, &sym);\ 31583a0944fSIngo Molnar idx < nr_syms; \ 31683a0944fSIngo Molnar idx++, gelf_getsym(syms, idx, &sym)) 31786470930SIngo Molnar 31886470930SIngo Molnar static inline uint8_t elf_sym__type(const GElf_Sym *sym) 31986470930SIngo Molnar { 32086470930SIngo Molnar return GELF_ST_TYPE(sym->st_info); 32186470930SIngo Molnar } 32286470930SIngo Molnar 32386470930SIngo Molnar static inline int elf_sym__is_function(const GElf_Sym *sym) 32486470930SIngo Molnar { 32586470930SIngo Molnar return elf_sym__type(sym) == STT_FUNC && 32686470930SIngo Molnar sym->st_name != 0 && 327*81833130SArnaldo Carvalho de Melo sym->st_shndx != SHN_UNDEF; 32886470930SIngo Molnar } 32986470930SIngo Molnar 3306cfcc53eSMike Galbraith static inline int elf_sym__is_label(const GElf_Sym *sym) 3316cfcc53eSMike Galbraith { 3326cfcc53eSMike Galbraith return elf_sym__type(sym) == STT_NOTYPE && 3336cfcc53eSMike Galbraith sym->st_name != 0 && 3346cfcc53eSMike Galbraith sym->st_shndx != SHN_UNDEF && 3356cfcc53eSMike Galbraith sym->st_shndx != SHN_ABS; 3366cfcc53eSMike Galbraith } 3376cfcc53eSMike Galbraith 3386cfcc53eSMike Galbraith static inline const char *elf_sec__name(const GElf_Shdr *shdr, 3396cfcc53eSMike Galbraith const Elf_Data *secstrs) 3406cfcc53eSMike Galbraith { 3416cfcc53eSMike Galbraith return secstrs->d_buf + shdr->sh_name; 3426cfcc53eSMike Galbraith } 3436cfcc53eSMike Galbraith 3446cfcc53eSMike Galbraith static inline int elf_sec__is_text(const GElf_Shdr *shdr, 3456cfcc53eSMike Galbraith const Elf_Data *secstrs) 3466cfcc53eSMike Galbraith { 3476cfcc53eSMike Galbraith return strstr(elf_sec__name(shdr, secstrs), "text") != NULL; 3486cfcc53eSMike Galbraith } 3496cfcc53eSMike Galbraith 35086470930SIngo Molnar static inline const char *elf_sym__name(const GElf_Sym *sym, 35186470930SIngo Molnar const Elf_Data *symstrs) 35286470930SIngo Molnar { 35386470930SIngo Molnar return symstrs->d_buf + sym->st_name; 35486470930SIngo Molnar } 35586470930SIngo Molnar 35686470930SIngo Molnar static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, 35786470930SIngo Molnar GElf_Shdr *shp, const char *name, 35883a0944fSIngo Molnar size_t *idx) 35986470930SIngo Molnar { 36086470930SIngo Molnar Elf_Scn *sec = NULL; 36186470930SIngo Molnar size_t cnt = 1; 36286470930SIngo Molnar 36386470930SIngo Molnar while ((sec = elf_nextscn(elf, sec)) != NULL) { 36486470930SIngo Molnar char *str; 36586470930SIngo Molnar 36686470930SIngo Molnar gelf_getshdr(sec, shp); 36786470930SIngo Molnar str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name); 36886470930SIngo Molnar if (!strcmp(name, str)) { 36983a0944fSIngo Molnar if (idx) 37083a0944fSIngo Molnar *idx = cnt; 37186470930SIngo Molnar break; 37286470930SIngo Molnar } 37386470930SIngo Molnar ++cnt; 37486470930SIngo Molnar } 37586470930SIngo Molnar 37686470930SIngo Molnar return sec; 37786470930SIngo Molnar } 37886470930SIngo Molnar 37986470930SIngo Molnar #define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \ 38086470930SIngo Molnar for (idx = 0, pos = gelf_getrel(reldata, 0, &pos_mem); \ 38186470930SIngo Molnar idx < nr_entries; \ 38286470930SIngo Molnar ++idx, pos = gelf_getrel(reldata, idx, &pos_mem)) 38386470930SIngo Molnar 38486470930SIngo Molnar #define elf_section__for_each_rela(reldata, pos, pos_mem, idx, nr_entries) \ 38586470930SIngo Molnar for (idx = 0, pos = gelf_getrela(reldata, 0, &pos_mem); \ 38686470930SIngo Molnar idx < nr_entries; \ 38786470930SIngo Molnar ++idx, pos = gelf_getrela(reldata, idx, &pos_mem)) 38886470930SIngo Molnar 389a25e46c4SArnaldo Carvalho de Melo /* 390a25e46c4SArnaldo Carvalho de Melo * We need to check if we have a .dynsym, so that we can handle the 391a25e46c4SArnaldo Carvalho de Melo * .plt, synthesizing its symbols, that aren't on the symtabs (be it 392a25e46c4SArnaldo Carvalho de Melo * .dynsym or .symtab). 393a25e46c4SArnaldo Carvalho de Melo * And always look at the original dso, not at debuginfo packages, that 394a25e46c4SArnaldo Carvalho de Melo * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS). 395a25e46c4SArnaldo Carvalho de Melo */ 39683a0944fSIngo Molnar static int dso__synthesize_plt_symbols(struct dso *self, int v) 39786470930SIngo Molnar { 39886470930SIngo Molnar uint32_t nr_rel_entries, idx; 39986470930SIngo Molnar GElf_Sym sym; 4009cffa8d5SPaul Mackerras u64 plt_offset; 40186470930SIngo Molnar GElf_Shdr shdr_plt; 40286470930SIngo Molnar struct symbol *f; 403a25e46c4SArnaldo Carvalho de Melo GElf_Shdr shdr_rel_plt, shdr_dynsym; 40486470930SIngo Molnar Elf_Data *reldata, *syms, *symstrs; 405a25e46c4SArnaldo Carvalho de Melo Elf_Scn *scn_plt_rel, *scn_symstrs, *scn_dynsym; 406a25e46c4SArnaldo Carvalho de Melo size_t dynsym_idx; 407a25e46c4SArnaldo Carvalho de Melo GElf_Ehdr ehdr; 40886470930SIngo Molnar char sympltname[1024]; 409a25e46c4SArnaldo Carvalho de Melo Elf *elf; 410a25e46c4SArnaldo Carvalho de Melo int nr = 0, symidx, fd, err = 0; 41186470930SIngo Molnar 412a25e46c4SArnaldo Carvalho de Melo fd = open(self->name, O_RDONLY); 413a25e46c4SArnaldo Carvalho de Melo if (fd < 0) 414a25e46c4SArnaldo Carvalho de Melo goto out; 415a25e46c4SArnaldo Carvalho de Melo 416a25e46c4SArnaldo Carvalho de Melo elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); 417a25e46c4SArnaldo Carvalho de Melo if (elf == NULL) 418a25e46c4SArnaldo Carvalho de Melo goto out_close; 419a25e46c4SArnaldo Carvalho de Melo 420a25e46c4SArnaldo Carvalho de Melo if (gelf_getehdr(elf, &ehdr) == NULL) 421a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 422a25e46c4SArnaldo Carvalho de Melo 423a25e46c4SArnaldo Carvalho de Melo scn_dynsym = elf_section_by_name(elf, &ehdr, &shdr_dynsym, 424a25e46c4SArnaldo Carvalho de Melo ".dynsym", &dynsym_idx); 425a25e46c4SArnaldo Carvalho de Melo if (scn_dynsym == NULL) 426a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 427a25e46c4SArnaldo Carvalho de Melo 428a25e46c4SArnaldo Carvalho de Melo scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt, 42986470930SIngo Molnar ".rela.plt", NULL); 43086470930SIngo Molnar if (scn_plt_rel == NULL) { 431a25e46c4SArnaldo Carvalho de Melo scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt, 43286470930SIngo Molnar ".rel.plt", NULL); 43386470930SIngo Molnar if (scn_plt_rel == NULL) 434a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 43586470930SIngo Molnar } 43686470930SIngo Molnar 437a25e46c4SArnaldo Carvalho de Melo err = -1; 43886470930SIngo Molnar 439a25e46c4SArnaldo Carvalho de Melo if (shdr_rel_plt.sh_link != dynsym_idx) 440a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 441a25e46c4SArnaldo Carvalho de Melo 442a25e46c4SArnaldo Carvalho de Melo if (elf_section_by_name(elf, &ehdr, &shdr_plt, ".plt", NULL) == NULL) 443a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 44486470930SIngo Molnar 44586470930SIngo Molnar /* 44683a0944fSIngo Molnar * Fetch the relocation section to find the idxes to the GOT 44786470930SIngo Molnar * and the symbols in the .dynsym they refer to. 44886470930SIngo Molnar */ 44986470930SIngo Molnar reldata = elf_getdata(scn_plt_rel, NULL); 45086470930SIngo Molnar if (reldata == NULL) 451a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 45286470930SIngo Molnar 45386470930SIngo Molnar syms = elf_getdata(scn_dynsym, NULL); 45486470930SIngo Molnar if (syms == NULL) 455a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 45686470930SIngo Molnar 457a25e46c4SArnaldo Carvalho de Melo scn_symstrs = elf_getscn(elf, shdr_dynsym.sh_link); 45886470930SIngo Molnar if (scn_symstrs == NULL) 459a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 46086470930SIngo Molnar 46186470930SIngo Molnar symstrs = elf_getdata(scn_symstrs, NULL); 46286470930SIngo Molnar if (symstrs == NULL) 463a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 46486470930SIngo Molnar 46586470930SIngo Molnar nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize; 46686470930SIngo Molnar plt_offset = shdr_plt.sh_offset; 46786470930SIngo Molnar 46886470930SIngo Molnar if (shdr_rel_plt.sh_type == SHT_RELA) { 46986470930SIngo Molnar GElf_Rela pos_mem, *pos; 47086470930SIngo Molnar 47186470930SIngo Molnar elf_section__for_each_rela(reldata, pos, pos_mem, idx, 47286470930SIngo Molnar nr_rel_entries) { 47386470930SIngo Molnar symidx = GELF_R_SYM(pos->r_info); 47486470930SIngo Molnar plt_offset += shdr_plt.sh_entsize; 47586470930SIngo Molnar gelf_getsym(syms, symidx, &sym); 47686470930SIngo Molnar snprintf(sympltname, sizeof(sympltname), 47786470930SIngo Molnar "%s@plt", elf_sym__name(&sym, symstrs)); 47886470930SIngo Molnar 47986470930SIngo Molnar f = symbol__new(plt_offset, shdr_plt.sh_entsize, 48083a0944fSIngo Molnar sympltname, self->sym_priv_size, 0, v); 48186470930SIngo Molnar if (!f) 482a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 48386470930SIngo Molnar 48486470930SIngo Molnar dso__insert_symbol(self, f); 48586470930SIngo Molnar ++nr; 48686470930SIngo Molnar } 48786470930SIngo Molnar } else if (shdr_rel_plt.sh_type == SHT_REL) { 48886470930SIngo Molnar GElf_Rel pos_mem, *pos; 48986470930SIngo Molnar elf_section__for_each_rel(reldata, pos, pos_mem, idx, 49086470930SIngo Molnar nr_rel_entries) { 49186470930SIngo Molnar symidx = GELF_R_SYM(pos->r_info); 49286470930SIngo Molnar plt_offset += shdr_plt.sh_entsize; 49386470930SIngo Molnar gelf_getsym(syms, symidx, &sym); 49486470930SIngo Molnar snprintf(sympltname, sizeof(sympltname), 49586470930SIngo Molnar "%s@plt", elf_sym__name(&sym, symstrs)); 49686470930SIngo Molnar 49786470930SIngo Molnar f = symbol__new(plt_offset, shdr_plt.sh_entsize, 49883a0944fSIngo Molnar sympltname, self->sym_priv_size, 0, v); 49986470930SIngo Molnar if (!f) 500a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 50186470930SIngo Molnar 50286470930SIngo Molnar dso__insert_symbol(self, f); 50386470930SIngo Molnar ++nr; 50486470930SIngo Molnar } 50586470930SIngo Molnar } 50686470930SIngo Molnar 507a25e46c4SArnaldo Carvalho de Melo err = 0; 508a25e46c4SArnaldo Carvalho de Melo out_elf_end: 509a25e46c4SArnaldo Carvalho de Melo elf_end(elf); 510a25e46c4SArnaldo Carvalho de Melo out_close: 511a25e46c4SArnaldo Carvalho de Melo close(fd); 512a25e46c4SArnaldo Carvalho de Melo 513a25e46c4SArnaldo Carvalho de Melo if (err == 0) 51486470930SIngo Molnar return nr; 515a25e46c4SArnaldo Carvalho de Melo out: 516a25e46c4SArnaldo Carvalho de Melo fprintf(stderr, "%s: problems reading %s PLT info.\n", 517a25e46c4SArnaldo Carvalho de Melo __func__, self->name); 518a25e46c4SArnaldo Carvalho de Melo return 0; 51986470930SIngo Molnar } 52086470930SIngo Molnar 52186470930SIngo Molnar static int dso__load_sym(struct dso *self, int fd, const char *name, 52283a0944fSIngo Molnar symbol_filter_t filter, int v, struct module *mod) 52386470930SIngo Molnar { 5246cfcc53eSMike Galbraith Elf_Data *symstrs, *secstrs; 52586470930SIngo Molnar uint32_t nr_syms; 52686470930SIngo Molnar int err = -1; 52783a0944fSIngo Molnar uint32_t idx; 52886470930SIngo Molnar GElf_Ehdr ehdr; 52986470930SIngo Molnar GElf_Shdr shdr; 53086470930SIngo Molnar Elf_Data *syms; 53186470930SIngo Molnar GElf_Sym sym; 532a25e46c4SArnaldo Carvalho de Melo Elf_Scn *sec, *sec_strndx; 53386470930SIngo Molnar Elf *elf; 534d20ff6bdSMike Galbraith int nr = 0, kernel = !strcmp("[kernel]", self->name); 53586470930SIngo Molnar 53686470930SIngo Molnar elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); 53786470930SIngo Molnar if (elf == NULL) { 53883a0944fSIngo Molnar if (v) 53986470930SIngo Molnar fprintf(stderr, "%s: cannot read %s ELF file.\n", 54086470930SIngo Molnar __func__, name); 54186470930SIngo Molnar goto out_close; 54286470930SIngo Molnar } 54386470930SIngo Molnar 54486470930SIngo Molnar if (gelf_getehdr(elf, &ehdr) == NULL) { 54583a0944fSIngo Molnar if (v) 54686470930SIngo Molnar fprintf(stderr, "%s: cannot get elf header.\n", __func__); 54786470930SIngo Molnar goto out_elf_end; 54886470930SIngo Molnar } 54986470930SIngo Molnar 55086470930SIngo Molnar sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL); 55186470930SIngo Molnar if (sec == NULL) { 552a25e46c4SArnaldo Carvalho de Melo sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL); 553a25e46c4SArnaldo Carvalho de Melo if (sec == NULL) 55486470930SIngo Molnar goto out_elf_end; 55586470930SIngo Molnar } 55686470930SIngo Molnar 55786470930SIngo Molnar syms = elf_getdata(sec, NULL); 55886470930SIngo Molnar if (syms == NULL) 55986470930SIngo Molnar goto out_elf_end; 56086470930SIngo Molnar 56186470930SIngo Molnar sec = elf_getscn(elf, shdr.sh_link); 56286470930SIngo Molnar if (sec == NULL) 56386470930SIngo Molnar goto out_elf_end; 56486470930SIngo Molnar 56586470930SIngo Molnar symstrs = elf_getdata(sec, NULL); 56686470930SIngo Molnar if (symstrs == NULL) 56786470930SIngo Molnar goto out_elf_end; 56886470930SIngo Molnar 5696cfcc53eSMike Galbraith sec_strndx = elf_getscn(elf, ehdr.e_shstrndx); 5706cfcc53eSMike Galbraith if (sec_strndx == NULL) 5716cfcc53eSMike Galbraith goto out_elf_end; 5726cfcc53eSMike Galbraith 5736cfcc53eSMike Galbraith secstrs = elf_getdata(sec_strndx, NULL); 5749b30a26bSStoyan Gaydarov if (secstrs == NULL) 5756cfcc53eSMike Galbraith goto out_elf_end; 5766cfcc53eSMike Galbraith 57786470930SIngo Molnar nr_syms = shdr.sh_size / shdr.sh_entsize; 57886470930SIngo Molnar 579e9fbc9dcSArjan van de Ven memset(&sym, 0, sizeof(sym)); 580d20ff6bdSMike Galbraith if (!kernel) { 58130d7a77dSArnaldo Carvalho de Melo self->adjust_symbols = (ehdr.e_type == ET_EXEC || 58230d7a77dSArnaldo Carvalho de Melo elf_section_by_name(elf, &ehdr, &shdr, 583f5812a7aSArnaldo Carvalho de Melo ".gnu.prelink_undo", 58430d7a77dSArnaldo Carvalho de Melo NULL) != NULL); 585d20ff6bdSMike Galbraith } else self->adjust_symbols = 0; 586d20ff6bdSMike Galbraith 58783a0944fSIngo Molnar elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) { 58886470930SIngo Molnar struct symbol *f; 58983a0944fSIngo Molnar const char *elf_name; 59028ac909bSArnaldo Carvalho de Melo char *demangled; 5919cffa8d5SPaul Mackerras u64 obj_start; 5926cfcc53eSMike Galbraith struct section *section = NULL; 5936cfcc53eSMike Galbraith int is_label = elf_sym__is_label(&sym); 5946cfcc53eSMike Galbraith const char *section_name; 59586470930SIngo Molnar 5966cfcc53eSMike Galbraith if (!is_label && !elf_sym__is_function(&sym)) 59786470930SIngo Molnar continue; 59886470930SIngo Molnar 59986470930SIngo Molnar sec = elf_getscn(elf, sym.st_shndx); 60086470930SIngo Molnar if (!sec) 60186470930SIngo Molnar goto out_elf_end; 60286470930SIngo Molnar 60386470930SIngo Molnar gelf_getshdr(sec, &shdr); 6046cfcc53eSMike Galbraith 6056cfcc53eSMike Galbraith if (is_label && !elf_sec__is_text(&shdr, secstrs)) 6066cfcc53eSMike Galbraith continue; 6076cfcc53eSMike Galbraith 6086cfcc53eSMike Galbraith section_name = elf_sec__name(&shdr, secstrs); 60986470930SIngo Molnar obj_start = sym.st_value; 61086470930SIngo Molnar 61130d7a77dSArnaldo Carvalho de Melo if (self->adjust_symbols) { 61283a0944fSIngo Molnar if (v >= 2) 613520f2c34SPeter Zijlstra printf("adjusting symbol: st_value: %Lx sh_addr: %Lx sh_offset: %Lx\n", 614520f2c34SPeter Zijlstra (u64)sym.st_value, (u64)shdr.sh_addr, (u64)shdr.sh_offset); 615520f2c34SPeter Zijlstra 61686470930SIngo Molnar sym.st_value -= shdr.sh_addr - shdr.sh_offset; 617f5812a7aSArnaldo Carvalho de Melo } 61886470930SIngo Molnar 6196cfcc53eSMike Galbraith if (mod) { 6206cfcc53eSMike Galbraith section = mod->sections->find_section(mod->sections, section_name); 6216cfcc53eSMike Galbraith if (section) 6226cfcc53eSMike Galbraith sym.st_value += section->vma; 6236cfcc53eSMike Galbraith else { 6246cfcc53eSMike Galbraith fprintf(stderr, "dso__load_sym() module %s lookup of %s failed\n", 6256cfcc53eSMike Galbraith mod->name, section_name); 6266cfcc53eSMike Galbraith goto out_elf_end; 6276cfcc53eSMike Galbraith } 6286cfcc53eSMike Galbraith } 62928ac909bSArnaldo Carvalho de Melo /* 63028ac909bSArnaldo Carvalho de Melo * We need to figure out if the object was created from C++ sources 63128ac909bSArnaldo Carvalho de Melo * DWARF DW_compile_unit has this, but we don't always have access 63228ac909bSArnaldo Carvalho de Melo * to it... 63328ac909bSArnaldo Carvalho de Melo */ 63483a0944fSIngo Molnar elf_name = elf_sym__name(&sym, symstrs); 63583a0944fSIngo Molnar demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI); 63628ac909bSArnaldo Carvalho de Melo if (demangled != NULL) 63783a0944fSIngo Molnar elf_name = demangled; 6386cfcc53eSMike Galbraith 63983a0944fSIngo Molnar f = symbol__new(sym.st_value, sym.st_size, elf_name, 64083a0944fSIngo Molnar self->sym_priv_size, obj_start, v); 64128ac909bSArnaldo Carvalho de Melo free(demangled); 64286470930SIngo Molnar if (!f) 64386470930SIngo Molnar goto out_elf_end; 64486470930SIngo Molnar 64586470930SIngo Molnar if (filter && filter(self, f)) 64686470930SIngo Molnar symbol__delete(f, self->sym_priv_size); 64786470930SIngo Molnar else { 6486cfcc53eSMike Galbraith f->module = mod; 64986470930SIngo Molnar dso__insert_symbol(self, f); 65086470930SIngo Molnar nr++; 65186470930SIngo Molnar } 65286470930SIngo Molnar } 65386470930SIngo Molnar 65486470930SIngo Molnar err = nr; 65586470930SIngo Molnar out_elf_end: 65686470930SIngo Molnar elf_end(elf); 65786470930SIngo Molnar out_close: 65886470930SIngo Molnar return err; 65986470930SIngo Molnar } 66086470930SIngo Molnar 6614d1e00a8SArnaldo Carvalho de Melo #define BUILD_ID_SIZE 128 6624d1e00a8SArnaldo Carvalho de Melo 66383a0944fSIngo Molnar static char *dso__read_build_id(struct dso *self, int v) 6644d1e00a8SArnaldo Carvalho de Melo { 6654d1e00a8SArnaldo Carvalho de Melo int i; 6664d1e00a8SArnaldo Carvalho de Melo GElf_Ehdr ehdr; 6674d1e00a8SArnaldo Carvalho de Melo GElf_Shdr shdr; 6684d1e00a8SArnaldo Carvalho de Melo Elf_Data *build_id_data; 6694d1e00a8SArnaldo Carvalho de Melo Elf_Scn *sec; 6704d1e00a8SArnaldo Carvalho de Melo char *build_id = NULL, *bid; 6714d1e00a8SArnaldo Carvalho de Melo unsigned char *raw; 6724d1e00a8SArnaldo Carvalho de Melo Elf *elf; 6734d1e00a8SArnaldo Carvalho de Melo int fd = open(self->name, O_RDONLY); 6744d1e00a8SArnaldo Carvalho de Melo 6754d1e00a8SArnaldo Carvalho de Melo if (fd < 0) 6764d1e00a8SArnaldo Carvalho de Melo goto out; 6774d1e00a8SArnaldo Carvalho de Melo 6784d1e00a8SArnaldo Carvalho de Melo elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); 6794d1e00a8SArnaldo Carvalho de Melo if (elf == NULL) { 68083a0944fSIngo Molnar if (v) 6814d1e00a8SArnaldo Carvalho de Melo fprintf(stderr, "%s: cannot read %s ELF file.\n", 6824d1e00a8SArnaldo Carvalho de Melo __func__, self->name); 6834d1e00a8SArnaldo Carvalho de Melo goto out_close; 6844d1e00a8SArnaldo Carvalho de Melo } 6854d1e00a8SArnaldo Carvalho de Melo 6864d1e00a8SArnaldo Carvalho de Melo if (gelf_getehdr(elf, &ehdr) == NULL) { 68783a0944fSIngo Molnar if (v) 6884d1e00a8SArnaldo Carvalho de Melo fprintf(stderr, "%s: cannot get elf header.\n", __func__); 6894d1e00a8SArnaldo Carvalho de Melo goto out_elf_end; 6904d1e00a8SArnaldo Carvalho de Melo } 6914d1e00a8SArnaldo Carvalho de Melo 6924d1e00a8SArnaldo Carvalho de Melo sec = elf_section_by_name(elf, &ehdr, &shdr, ".note.gnu.build-id", NULL); 6934d1e00a8SArnaldo Carvalho de Melo if (sec == NULL) 6944d1e00a8SArnaldo Carvalho de Melo goto out_elf_end; 6954d1e00a8SArnaldo Carvalho de Melo 6964d1e00a8SArnaldo Carvalho de Melo build_id_data = elf_getdata(sec, NULL); 6974d1e00a8SArnaldo Carvalho de Melo if (build_id_data == NULL) 6984d1e00a8SArnaldo Carvalho de Melo goto out_elf_end; 6994d1e00a8SArnaldo Carvalho de Melo build_id = malloc(BUILD_ID_SIZE); 7004d1e00a8SArnaldo Carvalho de Melo if (build_id == NULL) 7014d1e00a8SArnaldo Carvalho de Melo goto out_elf_end; 7024d1e00a8SArnaldo Carvalho de Melo raw = build_id_data->d_buf + 16; 7034d1e00a8SArnaldo Carvalho de Melo bid = build_id; 7044d1e00a8SArnaldo Carvalho de Melo 7054d1e00a8SArnaldo Carvalho de Melo for (i = 0; i < 20; ++i) { 7064d1e00a8SArnaldo Carvalho de Melo sprintf(bid, "%02x", *raw); 7074d1e00a8SArnaldo Carvalho de Melo ++raw; 7084d1e00a8SArnaldo Carvalho de Melo bid += 2; 7094d1e00a8SArnaldo Carvalho de Melo } 71083a0944fSIngo Molnar if (v >= 2) 7114d1e00a8SArnaldo Carvalho de Melo printf("%s(%s): %s\n", __func__, self->name, build_id); 7124d1e00a8SArnaldo Carvalho de Melo out_elf_end: 7134d1e00a8SArnaldo Carvalho de Melo elf_end(elf); 7144d1e00a8SArnaldo Carvalho de Melo out_close: 7154d1e00a8SArnaldo Carvalho de Melo close(fd); 7164d1e00a8SArnaldo Carvalho de Melo out: 7174d1e00a8SArnaldo Carvalho de Melo return build_id; 7184d1e00a8SArnaldo Carvalho de Melo } 7194d1e00a8SArnaldo Carvalho de Melo 72094cb9e38SArnaldo Carvalho de Melo char dso__symtab_origin(const struct dso *self) 72194cb9e38SArnaldo Carvalho de Melo { 72294cb9e38SArnaldo Carvalho de Melo static const char origin[] = { 72394cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_KERNEL] = 'k', 72494cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_JAVA_JIT] = 'j', 72594cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_FEDORA] = 'f', 72694cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_UBUNTU] = 'u', 72794cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_BUILDID] = 'b', 72894cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_DSO] = 'd', 72994cb9e38SArnaldo Carvalho de Melo }; 73094cb9e38SArnaldo Carvalho de Melo 73194cb9e38SArnaldo Carvalho de Melo if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND) 73294cb9e38SArnaldo Carvalho de Melo return '!'; 73394cb9e38SArnaldo Carvalho de Melo return origin[self->origin]; 73494cb9e38SArnaldo Carvalho de Melo } 73594cb9e38SArnaldo Carvalho de Melo 73683a0944fSIngo Molnar int dso__load(struct dso *self, symbol_filter_t filter, int v) 73786470930SIngo Molnar { 7384d1e00a8SArnaldo Carvalho de Melo int size = PATH_MAX; 7394d1e00a8SArnaldo Carvalho de Melo char *name = malloc(size), *build_id = NULL; 74086470930SIngo Molnar int ret = -1; 74186470930SIngo Molnar int fd; 74286470930SIngo Molnar 74386470930SIngo Molnar if (!name) 74486470930SIngo Molnar return -1; 74586470930SIngo Molnar 74630d7a77dSArnaldo Carvalho de Melo self->adjust_symbols = 0; 747f5812a7aSArnaldo Carvalho de Melo 74894cb9e38SArnaldo Carvalho de Melo if (strncmp(self->name, "/tmp/perf-", 10) == 0) { 74983a0944fSIngo Molnar ret = dso__load_perf_map(self, filter, v); 75094cb9e38SArnaldo Carvalho de Melo self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT : 75194cb9e38SArnaldo Carvalho de Melo DSO__ORIG_NOT_FOUND; 75294cb9e38SArnaldo Carvalho de Melo return ret; 75394cb9e38SArnaldo Carvalho de Melo } 75494cb9e38SArnaldo Carvalho de Melo 75594cb9e38SArnaldo Carvalho de Melo self->origin = DSO__ORIG_FEDORA - 1; 75680d496beSPekka Enberg 75786470930SIngo Molnar more: 75886470930SIngo Molnar do { 75994cb9e38SArnaldo Carvalho de Melo self->origin++; 76094cb9e38SArnaldo Carvalho de Melo switch (self->origin) { 76194cb9e38SArnaldo Carvalho de Melo case DSO__ORIG_FEDORA: 76286470930SIngo Molnar snprintf(name, size, "/usr/lib/debug%s.debug", self->name); 76386470930SIngo Molnar break; 76494cb9e38SArnaldo Carvalho de Melo case DSO__ORIG_UBUNTU: 76586470930SIngo Molnar snprintf(name, size, "/usr/lib/debug%s", self->name); 76686470930SIngo Molnar break; 76794cb9e38SArnaldo Carvalho de Melo case DSO__ORIG_BUILDID: 76883a0944fSIngo Molnar build_id = dso__read_build_id(self, v); 7694d1e00a8SArnaldo Carvalho de Melo if (build_id != NULL) { 7704d1e00a8SArnaldo Carvalho de Melo snprintf(name, size, 7714d1e00a8SArnaldo Carvalho de Melo "/usr/lib/debug/.build-id/%.2s/%s.debug", 7724d1e00a8SArnaldo Carvalho de Melo build_id, build_id + 2); 7734d1e00a8SArnaldo Carvalho de Melo free(build_id); 7744d1e00a8SArnaldo Carvalho de Melo break; 7754d1e00a8SArnaldo Carvalho de Melo } 77694cb9e38SArnaldo Carvalho de Melo self->origin++; 7774d1e00a8SArnaldo Carvalho de Melo /* Fall thru */ 77894cb9e38SArnaldo Carvalho de Melo case DSO__ORIG_DSO: 77986470930SIngo Molnar snprintf(name, size, "%s", self->name); 78086470930SIngo Molnar break; 78186470930SIngo Molnar 78286470930SIngo Molnar default: 78386470930SIngo Molnar goto out; 78486470930SIngo Molnar } 78586470930SIngo Molnar 78686470930SIngo Molnar fd = open(name, O_RDONLY); 78786470930SIngo Molnar } while (fd < 0); 78886470930SIngo Molnar 78983a0944fSIngo Molnar ret = dso__load_sym(self, fd, name, filter, v, NULL); 79086470930SIngo Molnar close(fd); 79186470930SIngo Molnar 79286470930SIngo Molnar /* 79386470930SIngo Molnar * Some people seem to have debuginfo files _WITHOUT_ debug info!?!? 79486470930SIngo Molnar */ 79586470930SIngo Molnar if (!ret) 79686470930SIngo Molnar goto more; 79786470930SIngo Molnar 798a25e46c4SArnaldo Carvalho de Melo if (ret > 0) { 79983a0944fSIngo Molnar int nr_plt = dso__synthesize_plt_symbols(self, v); 800a25e46c4SArnaldo Carvalho de Melo if (nr_plt > 0) 801a25e46c4SArnaldo Carvalho de Melo ret += nr_plt; 802a25e46c4SArnaldo Carvalho de Melo } 80386470930SIngo Molnar out: 80486470930SIngo Molnar free(name); 8051340e6bbSArnaldo Carvalho de Melo if (ret < 0 && strstr(self->name, " (deleted)") != NULL) 8061340e6bbSArnaldo Carvalho de Melo return 0; 80786470930SIngo Molnar return ret; 80886470930SIngo Molnar } 80986470930SIngo Molnar 8106cfcc53eSMike Galbraith static int dso__load_module(struct dso *self, struct mod_dso *mods, const char *name, 81183a0944fSIngo Molnar symbol_filter_t filter, int v) 8126cfcc53eSMike Galbraith { 8136cfcc53eSMike Galbraith struct module *mod = mod_dso__find_module(mods, name); 8146cfcc53eSMike Galbraith int err = 0, fd; 8156cfcc53eSMike Galbraith 8166cfcc53eSMike Galbraith if (mod == NULL || !mod->active) 8176cfcc53eSMike Galbraith return err; 8186cfcc53eSMike Galbraith 8196cfcc53eSMike Galbraith fd = open(mod->path, O_RDONLY); 8206cfcc53eSMike Galbraith 8216cfcc53eSMike Galbraith if (fd < 0) 8226cfcc53eSMike Galbraith return err; 8236cfcc53eSMike Galbraith 82483a0944fSIngo Molnar err = dso__load_sym(self, fd, name, filter, v, mod); 8256cfcc53eSMike Galbraith close(fd); 8266cfcc53eSMike Galbraith 8276cfcc53eSMike Galbraith return err; 8286cfcc53eSMike Galbraith } 8296cfcc53eSMike Galbraith 83083a0944fSIngo Molnar int dso__load_modules(struct dso *self, symbol_filter_t filter, int v) 8316cfcc53eSMike Galbraith { 8326cfcc53eSMike Galbraith struct mod_dso *mods = mod_dso__new_dso("modules"); 8336cfcc53eSMike Galbraith struct module *pos; 8346cfcc53eSMike Galbraith struct rb_node *next; 835508c4d08SMike Galbraith int err, count = 0; 8366cfcc53eSMike Galbraith 8376cfcc53eSMike Galbraith err = mod_dso__load_modules(mods); 8386cfcc53eSMike Galbraith 8396cfcc53eSMike Galbraith if (err <= 0) 8406cfcc53eSMike Galbraith return err; 8416cfcc53eSMike Galbraith 8426cfcc53eSMike Galbraith /* 8436cfcc53eSMike Galbraith * Iterate over modules, and load active symbols. 8446cfcc53eSMike Galbraith */ 8456cfcc53eSMike Galbraith next = rb_first(&mods->mods); 8466cfcc53eSMike Galbraith while (next) { 8476cfcc53eSMike Galbraith pos = rb_entry(next, struct module, rb_node); 84883a0944fSIngo Molnar err = dso__load_module(self, mods, pos->name, filter, v); 8496cfcc53eSMike Galbraith 8506cfcc53eSMike Galbraith if (err < 0) 8516cfcc53eSMike Galbraith break; 8526cfcc53eSMike Galbraith 8536cfcc53eSMike Galbraith next = rb_next(&pos->rb_node); 854508c4d08SMike Galbraith count += err; 8556cfcc53eSMike Galbraith } 8566cfcc53eSMike Galbraith 8576cfcc53eSMike Galbraith if (err < 0) { 8586cfcc53eSMike Galbraith mod_dso__delete_modules(mods); 8596cfcc53eSMike Galbraith mod_dso__delete_self(mods); 860508c4d08SMike Galbraith return err; 8616cfcc53eSMike Galbraith } 8626cfcc53eSMike Galbraith 863508c4d08SMike Galbraith return count; 8646cfcc53eSMike Galbraith } 8656cfcc53eSMike Galbraith 8666cfcc53eSMike Galbraith static inline void dso__fill_symbol_holes(struct dso *self) 8676cfcc53eSMike Galbraith { 8686cfcc53eSMike Galbraith struct symbol *prev = NULL; 8696cfcc53eSMike Galbraith struct rb_node *nd; 8706cfcc53eSMike Galbraith 8716cfcc53eSMike Galbraith for (nd = rb_last(&self->syms); nd; nd = rb_prev(nd)) { 8726cfcc53eSMike Galbraith struct symbol *pos = rb_entry(nd, struct symbol, rb_node); 8736cfcc53eSMike Galbraith 8746cfcc53eSMike Galbraith if (prev) { 8756cfcc53eSMike Galbraith u64 hole = 0; 8766cfcc53eSMike Galbraith int alias = pos->start == prev->start; 8776cfcc53eSMike Galbraith 8786cfcc53eSMike Galbraith if (!alias) 8796cfcc53eSMike Galbraith hole = prev->start - pos->end - 1; 8806cfcc53eSMike Galbraith 8816cfcc53eSMike Galbraith if (hole || alias) { 8826cfcc53eSMike Galbraith if (alias) 8836cfcc53eSMike Galbraith pos->end = prev->end; 8846cfcc53eSMike Galbraith else if (hole) 8856cfcc53eSMike Galbraith pos->end = prev->start - 1; 8866cfcc53eSMike Galbraith } 8876cfcc53eSMike Galbraith } 8886cfcc53eSMike Galbraith prev = pos; 8896cfcc53eSMike Galbraith } 8906cfcc53eSMike Galbraith } 8916cfcc53eSMike Galbraith 89286470930SIngo Molnar static int dso__load_vmlinux(struct dso *self, const char *vmlinux, 89383a0944fSIngo Molnar symbol_filter_t filter, int v) 89486470930SIngo Molnar { 89586470930SIngo Molnar int err, fd = open(vmlinux, O_RDONLY); 89686470930SIngo Molnar 89786470930SIngo Molnar if (fd < 0) 89886470930SIngo Molnar return -1; 89986470930SIngo Molnar 90083a0944fSIngo Molnar err = dso__load_sym(self, fd, vmlinux, filter, v, NULL); 9016cfcc53eSMike Galbraith 9026cfcc53eSMike Galbraith if (err > 0) 9036cfcc53eSMike Galbraith dso__fill_symbol_holes(self); 9046cfcc53eSMike Galbraith 90586470930SIngo Molnar close(fd); 90686470930SIngo Molnar 90786470930SIngo Molnar return err; 90886470930SIngo Molnar } 90986470930SIngo Molnar 91086470930SIngo Molnar int dso__load_kernel(struct dso *self, const char *vmlinux, 91183a0944fSIngo Molnar symbol_filter_t filter, int v, int use_modules) 91286470930SIngo Molnar { 91386470930SIngo Molnar int err = -1; 91486470930SIngo Molnar 9156cfcc53eSMike Galbraith if (vmlinux) { 91683a0944fSIngo Molnar err = dso__load_vmlinux(self, vmlinux, filter, v); 917508c4d08SMike Galbraith if (err > 0 && use_modules) { 918508c4d08SMike Galbraith int syms = dso__load_modules(self, filter, v); 919508c4d08SMike Galbraith 920508c4d08SMike Galbraith if (syms < 0) { 921508c4d08SMike Galbraith fprintf(stderr, "dso__load_modules failed!\n"); 922508c4d08SMike Galbraith return syms; 923508c4d08SMike Galbraith } 924508c4d08SMike Galbraith err += syms; 925508c4d08SMike Galbraith } 9266cfcc53eSMike Galbraith } 92786470930SIngo Molnar 9289974f496SMike Galbraith if (err <= 0) 92983a0944fSIngo Molnar err = dso__load_kallsyms(self, filter, v); 93086470930SIngo Molnar 93194cb9e38SArnaldo Carvalho de Melo if (err > 0) 93294cb9e38SArnaldo Carvalho de Melo self->origin = DSO__ORIG_KERNEL; 93394cb9e38SArnaldo Carvalho de Melo 93486470930SIngo Molnar return err; 93586470930SIngo Molnar } 93686470930SIngo Molnar 937cd84c2acSFrederic Weisbecker LIST_HEAD(dsos); 938cd84c2acSFrederic Weisbecker struct dso *kernel_dso; 939cd84c2acSFrederic Weisbecker struct dso *vdso; 940cd84c2acSFrederic Weisbecker struct dso *hypervisor_dso; 941cd84c2acSFrederic Weisbecker 94283a0944fSIngo Molnar const char *vmlinux_name = "vmlinux"; 943cd84c2acSFrederic Weisbecker int modules; 944cd84c2acSFrederic Weisbecker 945cd84c2acSFrederic Weisbecker static void dsos__add(struct dso *dso) 946cd84c2acSFrederic Weisbecker { 947cd84c2acSFrederic Weisbecker list_add_tail(&dso->node, &dsos); 948cd84c2acSFrederic Weisbecker } 949cd84c2acSFrederic Weisbecker 950cd84c2acSFrederic Weisbecker static struct dso *dsos__find(const char *name) 951cd84c2acSFrederic Weisbecker { 952cd84c2acSFrederic Weisbecker struct dso *pos; 953cd84c2acSFrederic Weisbecker 954cd84c2acSFrederic Weisbecker list_for_each_entry(pos, &dsos, node) 955cd84c2acSFrederic Weisbecker if (strcmp(pos->name, name) == 0) 956cd84c2acSFrederic Weisbecker return pos; 957cd84c2acSFrederic Weisbecker return NULL; 958cd84c2acSFrederic Weisbecker } 959cd84c2acSFrederic Weisbecker 960cd84c2acSFrederic Weisbecker struct dso *dsos__findnew(const char *name) 961cd84c2acSFrederic Weisbecker { 962cd84c2acSFrederic Weisbecker struct dso *dso = dsos__find(name); 963cd84c2acSFrederic Weisbecker int nr; 964cd84c2acSFrederic Weisbecker 965cd84c2acSFrederic Weisbecker if (dso) 966cd84c2acSFrederic Weisbecker return dso; 967cd84c2acSFrederic Weisbecker 968cd84c2acSFrederic Weisbecker dso = dso__new(name, 0); 969cd84c2acSFrederic Weisbecker if (!dso) 970cd84c2acSFrederic Weisbecker goto out_delete_dso; 971cd84c2acSFrederic Weisbecker 972cd84c2acSFrederic Weisbecker nr = dso__load(dso, NULL, verbose); 973cd84c2acSFrederic Weisbecker if (nr < 0) { 974cd84c2acSFrederic Weisbecker eprintf("Failed to open: %s\n", name); 975cd84c2acSFrederic Weisbecker goto out_delete_dso; 976cd84c2acSFrederic Weisbecker } 977cd84c2acSFrederic Weisbecker if (!nr) 978cd84c2acSFrederic Weisbecker eprintf("No symbols found in: %s, maybe install a debug package?\n", name); 979cd84c2acSFrederic Weisbecker 980cd84c2acSFrederic Weisbecker dsos__add(dso); 981cd84c2acSFrederic Weisbecker 982cd84c2acSFrederic Weisbecker return dso; 983cd84c2acSFrederic Weisbecker 984cd84c2acSFrederic Weisbecker out_delete_dso: 985cd84c2acSFrederic Weisbecker dso__delete(dso); 986cd84c2acSFrederic Weisbecker return NULL; 987cd84c2acSFrederic Weisbecker } 988cd84c2acSFrederic Weisbecker 989cd84c2acSFrederic Weisbecker void dsos__fprintf(FILE *fp) 990cd84c2acSFrederic Weisbecker { 991cd84c2acSFrederic Weisbecker struct dso *pos; 992cd84c2acSFrederic Weisbecker 993cd84c2acSFrederic Weisbecker list_for_each_entry(pos, &dsos, node) 994cd84c2acSFrederic Weisbecker dso__fprintf(pos, fp); 995cd84c2acSFrederic Weisbecker } 996cd84c2acSFrederic Weisbecker 997cd84c2acSFrederic Weisbecker static struct symbol *vdso__find_symbol(struct dso *dso, u64 ip) 998cd84c2acSFrederic Weisbecker { 999cd84c2acSFrederic Weisbecker return dso__find_symbol(dso, ip); 1000cd84c2acSFrederic Weisbecker } 1001cd84c2acSFrederic Weisbecker 1002cd84c2acSFrederic Weisbecker int load_kernel(void) 1003cd84c2acSFrederic Weisbecker { 1004cd84c2acSFrederic Weisbecker int err; 1005cd84c2acSFrederic Weisbecker 1006cd84c2acSFrederic Weisbecker kernel_dso = dso__new("[kernel]", 0); 1007cd84c2acSFrederic Weisbecker if (!kernel_dso) 1008cd84c2acSFrederic Weisbecker return -1; 1009cd84c2acSFrederic Weisbecker 101083a0944fSIngo Molnar err = dso__load_kernel(kernel_dso, vmlinux_name, NULL, verbose, modules); 1011cd84c2acSFrederic Weisbecker if (err <= 0) { 1012cd84c2acSFrederic Weisbecker dso__delete(kernel_dso); 1013cd84c2acSFrederic Weisbecker kernel_dso = NULL; 1014cd84c2acSFrederic Weisbecker } else 1015cd84c2acSFrederic Weisbecker dsos__add(kernel_dso); 1016cd84c2acSFrederic Weisbecker 1017cd84c2acSFrederic Weisbecker vdso = dso__new("[vdso]", 0); 1018cd84c2acSFrederic Weisbecker if (!vdso) 1019cd84c2acSFrederic Weisbecker return -1; 1020cd84c2acSFrederic Weisbecker 1021cd84c2acSFrederic Weisbecker vdso->find_symbol = vdso__find_symbol; 1022cd84c2acSFrederic Weisbecker 1023cd84c2acSFrederic Weisbecker dsos__add(vdso); 1024cd84c2acSFrederic Weisbecker 1025cd84c2acSFrederic Weisbecker hypervisor_dso = dso__new("[hypervisor]", 0); 1026cd84c2acSFrederic Weisbecker if (!hypervisor_dso) 1027cd84c2acSFrederic Weisbecker return -1; 1028cd84c2acSFrederic Weisbecker dsos__add(hypervisor_dso); 1029cd84c2acSFrederic Weisbecker 1030cd84c2acSFrederic Weisbecker return err; 1031cd84c2acSFrederic Weisbecker } 1032cd84c2acSFrederic Weisbecker 1033cd84c2acSFrederic Weisbecker 103486470930SIngo Molnar void symbol__init(void) 103586470930SIngo Molnar { 103686470930SIngo Molnar elf_version(EV_CURRENT); 103786470930SIngo Molnar } 1038