186470930SIngo Molnar #include "util.h" 286470930SIngo Molnar #include "../perf.h" 386470930SIngo Molnar #include "string.h" 486470930SIngo Molnar #include "symbol.h" 586470930SIngo Molnar 6*8f28827aSFrederic Weisbecker #include "debug.h" 7*8f28827aSFrederic 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 && 32786470930SIngo Molnar sym->st_shndx != SHN_UNDEF && 32886470930SIngo Molnar sym->st_size != 0; 32986470930SIngo Molnar } 33086470930SIngo Molnar 3316cfcc53eSMike Galbraith static inline int elf_sym__is_label(const GElf_Sym *sym) 3326cfcc53eSMike Galbraith { 3336cfcc53eSMike Galbraith return elf_sym__type(sym) == STT_NOTYPE && 3346cfcc53eSMike Galbraith sym->st_name != 0 && 3356cfcc53eSMike Galbraith sym->st_shndx != SHN_UNDEF && 3366cfcc53eSMike Galbraith sym->st_shndx != SHN_ABS; 3376cfcc53eSMike Galbraith } 3386cfcc53eSMike Galbraith 3396cfcc53eSMike Galbraith static inline const char *elf_sec__name(const GElf_Shdr *shdr, 3406cfcc53eSMike Galbraith const Elf_Data *secstrs) 3416cfcc53eSMike Galbraith { 3426cfcc53eSMike Galbraith return secstrs->d_buf + shdr->sh_name; 3436cfcc53eSMike Galbraith } 3446cfcc53eSMike Galbraith 3456cfcc53eSMike Galbraith static inline int elf_sec__is_text(const GElf_Shdr *shdr, 3466cfcc53eSMike Galbraith const Elf_Data *secstrs) 3476cfcc53eSMike Galbraith { 3486cfcc53eSMike Galbraith return strstr(elf_sec__name(shdr, secstrs), "text") != NULL; 3496cfcc53eSMike Galbraith } 3506cfcc53eSMike Galbraith 35186470930SIngo Molnar static inline const char *elf_sym__name(const GElf_Sym *sym, 35286470930SIngo Molnar const Elf_Data *symstrs) 35386470930SIngo Molnar { 35486470930SIngo Molnar return symstrs->d_buf + sym->st_name; 35586470930SIngo Molnar } 35686470930SIngo Molnar 35786470930SIngo Molnar static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, 35886470930SIngo Molnar GElf_Shdr *shp, const char *name, 35983a0944fSIngo Molnar size_t *idx) 36086470930SIngo Molnar { 36186470930SIngo Molnar Elf_Scn *sec = NULL; 36286470930SIngo Molnar size_t cnt = 1; 36386470930SIngo Molnar 36486470930SIngo Molnar while ((sec = elf_nextscn(elf, sec)) != NULL) { 36586470930SIngo Molnar char *str; 36686470930SIngo Molnar 36786470930SIngo Molnar gelf_getshdr(sec, shp); 36886470930SIngo Molnar str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name); 36986470930SIngo Molnar if (!strcmp(name, str)) { 37083a0944fSIngo Molnar if (idx) 37183a0944fSIngo Molnar *idx = cnt; 37286470930SIngo Molnar break; 37386470930SIngo Molnar } 37486470930SIngo Molnar ++cnt; 37586470930SIngo Molnar } 37686470930SIngo Molnar 37786470930SIngo Molnar return sec; 37886470930SIngo Molnar } 37986470930SIngo Molnar 38086470930SIngo Molnar #define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \ 38186470930SIngo Molnar for (idx = 0, pos = gelf_getrel(reldata, 0, &pos_mem); \ 38286470930SIngo Molnar idx < nr_entries; \ 38386470930SIngo Molnar ++idx, pos = gelf_getrel(reldata, idx, &pos_mem)) 38486470930SIngo Molnar 38586470930SIngo Molnar #define elf_section__for_each_rela(reldata, pos, pos_mem, idx, nr_entries) \ 38686470930SIngo Molnar for (idx = 0, pos = gelf_getrela(reldata, 0, &pos_mem); \ 38786470930SIngo Molnar idx < nr_entries; \ 38886470930SIngo Molnar ++idx, pos = gelf_getrela(reldata, idx, &pos_mem)) 38986470930SIngo Molnar 390a25e46c4SArnaldo Carvalho de Melo /* 391a25e46c4SArnaldo Carvalho de Melo * We need to check if we have a .dynsym, so that we can handle the 392a25e46c4SArnaldo Carvalho de Melo * .plt, synthesizing its symbols, that aren't on the symtabs (be it 393a25e46c4SArnaldo Carvalho de Melo * .dynsym or .symtab). 394a25e46c4SArnaldo Carvalho de Melo * And always look at the original dso, not at debuginfo packages, that 395a25e46c4SArnaldo Carvalho de Melo * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS). 396a25e46c4SArnaldo Carvalho de Melo */ 39783a0944fSIngo Molnar static int dso__synthesize_plt_symbols(struct dso *self, int v) 39886470930SIngo Molnar { 39986470930SIngo Molnar uint32_t nr_rel_entries, idx; 40086470930SIngo Molnar GElf_Sym sym; 4019cffa8d5SPaul Mackerras u64 plt_offset; 40286470930SIngo Molnar GElf_Shdr shdr_plt; 40386470930SIngo Molnar struct symbol *f; 404a25e46c4SArnaldo Carvalho de Melo GElf_Shdr shdr_rel_plt, shdr_dynsym; 40586470930SIngo Molnar Elf_Data *reldata, *syms, *symstrs; 406a25e46c4SArnaldo Carvalho de Melo Elf_Scn *scn_plt_rel, *scn_symstrs, *scn_dynsym; 407a25e46c4SArnaldo Carvalho de Melo size_t dynsym_idx; 408a25e46c4SArnaldo Carvalho de Melo GElf_Ehdr ehdr; 40986470930SIngo Molnar char sympltname[1024]; 410a25e46c4SArnaldo Carvalho de Melo Elf *elf; 411a25e46c4SArnaldo Carvalho de Melo int nr = 0, symidx, fd, err = 0; 41286470930SIngo Molnar 413a25e46c4SArnaldo Carvalho de Melo fd = open(self->name, O_RDONLY); 414a25e46c4SArnaldo Carvalho de Melo if (fd < 0) 415a25e46c4SArnaldo Carvalho de Melo goto out; 416a25e46c4SArnaldo Carvalho de Melo 417a25e46c4SArnaldo Carvalho de Melo elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); 418a25e46c4SArnaldo Carvalho de Melo if (elf == NULL) 419a25e46c4SArnaldo Carvalho de Melo goto out_close; 420a25e46c4SArnaldo Carvalho de Melo 421a25e46c4SArnaldo Carvalho de Melo if (gelf_getehdr(elf, &ehdr) == NULL) 422a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 423a25e46c4SArnaldo Carvalho de Melo 424a25e46c4SArnaldo Carvalho de Melo scn_dynsym = elf_section_by_name(elf, &ehdr, &shdr_dynsym, 425a25e46c4SArnaldo Carvalho de Melo ".dynsym", &dynsym_idx); 426a25e46c4SArnaldo Carvalho de Melo if (scn_dynsym == NULL) 427a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 428a25e46c4SArnaldo Carvalho de Melo 429a25e46c4SArnaldo Carvalho de Melo scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt, 43086470930SIngo Molnar ".rela.plt", NULL); 43186470930SIngo Molnar if (scn_plt_rel == NULL) { 432a25e46c4SArnaldo Carvalho de Melo scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt, 43386470930SIngo Molnar ".rel.plt", NULL); 43486470930SIngo Molnar if (scn_plt_rel == NULL) 435a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 43686470930SIngo Molnar } 43786470930SIngo Molnar 438a25e46c4SArnaldo Carvalho de Melo err = -1; 43986470930SIngo Molnar 440a25e46c4SArnaldo Carvalho de Melo if (shdr_rel_plt.sh_link != dynsym_idx) 441a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 442a25e46c4SArnaldo Carvalho de Melo 443a25e46c4SArnaldo Carvalho de Melo if (elf_section_by_name(elf, &ehdr, &shdr_plt, ".plt", NULL) == NULL) 444a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 44586470930SIngo Molnar 44686470930SIngo Molnar /* 44783a0944fSIngo Molnar * Fetch the relocation section to find the idxes to the GOT 44886470930SIngo Molnar * and the symbols in the .dynsym they refer to. 44986470930SIngo Molnar */ 45086470930SIngo Molnar reldata = elf_getdata(scn_plt_rel, NULL); 45186470930SIngo Molnar if (reldata == NULL) 452a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 45386470930SIngo Molnar 45486470930SIngo Molnar syms = elf_getdata(scn_dynsym, NULL); 45586470930SIngo Molnar if (syms == NULL) 456a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 45786470930SIngo Molnar 458a25e46c4SArnaldo Carvalho de Melo scn_symstrs = elf_getscn(elf, shdr_dynsym.sh_link); 45986470930SIngo Molnar if (scn_symstrs == NULL) 460a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 46186470930SIngo Molnar 46286470930SIngo Molnar symstrs = elf_getdata(scn_symstrs, NULL); 46386470930SIngo Molnar if (symstrs == NULL) 464a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 46586470930SIngo Molnar 46686470930SIngo Molnar nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize; 46786470930SIngo Molnar plt_offset = shdr_plt.sh_offset; 46886470930SIngo Molnar 46986470930SIngo Molnar if (shdr_rel_plt.sh_type == SHT_RELA) { 47086470930SIngo Molnar GElf_Rela pos_mem, *pos; 47186470930SIngo Molnar 47286470930SIngo Molnar elf_section__for_each_rela(reldata, pos, pos_mem, idx, 47386470930SIngo Molnar nr_rel_entries) { 47486470930SIngo Molnar symidx = GELF_R_SYM(pos->r_info); 47586470930SIngo Molnar plt_offset += shdr_plt.sh_entsize; 47686470930SIngo Molnar gelf_getsym(syms, symidx, &sym); 47786470930SIngo Molnar snprintf(sympltname, sizeof(sympltname), 47886470930SIngo Molnar "%s@plt", elf_sym__name(&sym, symstrs)); 47986470930SIngo Molnar 48086470930SIngo Molnar f = symbol__new(plt_offset, shdr_plt.sh_entsize, 48183a0944fSIngo Molnar sympltname, self->sym_priv_size, 0, v); 48286470930SIngo Molnar if (!f) 483a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 48486470930SIngo Molnar 48586470930SIngo Molnar dso__insert_symbol(self, f); 48686470930SIngo Molnar ++nr; 48786470930SIngo Molnar } 48886470930SIngo Molnar } else if (shdr_rel_plt.sh_type == SHT_REL) { 48986470930SIngo Molnar GElf_Rel pos_mem, *pos; 49086470930SIngo Molnar elf_section__for_each_rel(reldata, pos, pos_mem, idx, 49186470930SIngo Molnar nr_rel_entries) { 49286470930SIngo Molnar symidx = GELF_R_SYM(pos->r_info); 49386470930SIngo Molnar plt_offset += shdr_plt.sh_entsize; 49486470930SIngo Molnar gelf_getsym(syms, symidx, &sym); 49586470930SIngo Molnar snprintf(sympltname, sizeof(sympltname), 49686470930SIngo Molnar "%s@plt", elf_sym__name(&sym, symstrs)); 49786470930SIngo Molnar 49886470930SIngo Molnar f = symbol__new(plt_offset, shdr_plt.sh_entsize, 49983a0944fSIngo Molnar sympltname, self->sym_priv_size, 0, v); 50086470930SIngo Molnar if (!f) 501a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 50286470930SIngo Molnar 50386470930SIngo Molnar dso__insert_symbol(self, f); 50486470930SIngo Molnar ++nr; 50586470930SIngo Molnar } 50686470930SIngo Molnar } 50786470930SIngo Molnar 508a25e46c4SArnaldo Carvalho de Melo err = 0; 509a25e46c4SArnaldo Carvalho de Melo out_elf_end: 510a25e46c4SArnaldo Carvalho de Melo elf_end(elf); 511a25e46c4SArnaldo Carvalho de Melo out_close: 512a25e46c4SArnaldo Carvalho de Melo close(fd); 513a25e46c4SArnaldo Carvalho de Melo 514a25e46c4SArnaldo Carvalho de Melo if (err == 0) 51586470930SIngo Molnar return nr; 516a25e46c4SArnaldo Carvalho de Melo out: 517a25e46c4SArnaldo Carvalho de Melo fprintf(stderr, "%s: problems reading %s PLT info.\n", 518a25e46c4SArnaldo Carvalho de Melo __func__, self->name); 519a25e46c4SArnaldo Carvalho de Melo return 0; 52086470930SIngo Molnar } 52186470930SIngo Molnar 52286470930SIngo Molnar static int dso__load_sym(struct dso *self, int fd, const char *name, 52383a0944fSIngo Molnar symbol_filter_t filter, int v, struct module *mod) 52486470930SIngo Molnar { 5256cfcc53eSMike Galbraith Elf_Data *symstrs, *secstrs; 52686470930SIngo Molnar uint32_t nr_syms; 52786470930SIngo Molnar int err = -1; 52883a0944fSIngo Molnar uint32_t idx; 52986470930SIngo Molnar GElf_Ehdr ehdr; 53086470930SIngo Molnar GElf_Shdr shdr; 53186470930SIngo Molnar Elf_Data *syms; 53286470930SIngo Molnar GElf_Sym sym; 533a25e46c4SArnaldo Carvalho de Melo Elf_Scn *sec, *sec_strndx; 53486470930SIngo Molnar Elf *elf; 535d20ff6bdSMike Galbraith int nr = 0, kernel = !strcmp("[kernel]", self->name); 53686470930SIngo Molnar 53786470930SIngo Molnar elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); 53886470930SIngo Molnar if (elf == NULL) { 53983a0944fSIngo Molnar if (v) 54086470930SIngo Molnar fprintf(stderr, "%s: cannot read %s ELF file.\n", 54186470930SIngo Molnar __func__, name); 54286470930SIngo Molnar goto out_close; 54386470930SIngo Molnar } 54486470930SIngo Molnar 54586470930SIngo Molnar if (gelf_getehdr(elf, &ehdr) == NULL) { 54683a0944fSIngo Molnar if (v) 54786470930SIngo Molnar fprintf(stderr, "%s: cannot get elf header.\n", __func__); 54886470930SIngo Molnar goto out_elf_end; 54986470930SIngo Molnar } 55086470930SIngo Molnar 55186470930SIngo Molnar sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL); 55286470930SIngo Molnar if (sec == NULL) { 553a25e46c4SArnaldo Carvalho de Melo sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL); 554a25e46c4SArnaldo Carvalho de Melo if (sec == NULL) 55586470930SIngo Molnar goto out_elf_end; 55686470930SIngo Molnar } 55786470930SIngo Molnar 55886470930SIngo Molnar syms = elf_getdata(sec, NULL); 55986470930SIngo Molnar if (syms == NULL) 56086470930SIngo Molnar goto out_elf_end; 56186470930SIngo Molnar 56286470930SIngo Molnar sec = elf_getscn(elf, shdr.sh_link); 56386470930SIngo Molnar if (sec == NULL) 56486470930SIngo Molnar goto out_elf_end; 56586470930SIngo Molnar 56686470930SIngo Molnar symstrs = elf_getdata(sec, NULL); 56786470930SIngo Molnar if (symstrs == NULL) 56886470930SIngo Molnar goto out_elf_end; 56986470930SIngo Molnar 5706cfcc53eSMike Galbraith sec_strndx = elf_getscn(elf, ehdr.e_shstrndx); 5716cfcc53eSMike Galbraith if (sec_strndx == NULL) 5726cfcc53eSMike Galbraith goto out_elf_end; 5736cfcc53eSMike Galbraith 5746cfcc53eSMike Galbraith secstrs = elf_getdata(sec_strndx, NULL); 5759b30a26bSStoyan Gaydarov if (secstrs == NULL) 5766cfcc53eSMike Galbraith goto out_elf_end; 5776cfcc53eSMike Galbraith 57886470930SIngo Molnar nr_syms = shdr.sh_size / shdr.sh_entsize; 57986470930SIngo Molnar 580e9fbc9dcSArjan van de Ven memset(&sym, 0, sizeof(sym)); 581d20ff6bdSMike Galbraith if (!kernel) { 58230d7a77dSArnaldo Carvalho de Melo self->adjust_symbols = (ehdr.e_type == ET_EXEC || 58330d7a77dSArnaldo Carvalho de Melo elf_section_by_name(elf, &ehdr, &shdr, 584f5812a7aSArnaldo Carvalho de Melo ".gnu.prelink_undo", 58530d7a77dSArnaldo Carvalho de Melo NULL) != NULL); 586d20ff6bdSMike Galbraith } else self->adjust_symbols = 0; 587d20ff6bdSMike Galbraith 58883a0944fSIngo Molnar elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) { 58986470930SIngo Molnar struct symbol *f; 59083a0944fSIngo Molnar const char *elf_name; 59128ac909bSArnaldo Carvalho de Melo char *demangled; 5929cffa8d5SPaul Mackerras u64 obj_start; 5936cfcc53eSMike Galbraith struct section *section = NULL; 5946cfcc53eSMike Galbraith int is_label = elf_sym__is_label(&sym); 5956cfcc53eSMike Galbraith const char *section_name; 59686470930SIngo Molnar 5976cfcc53eSMike Galbraith if (!is_label && !elf_sym__is_function(&sym)) 59886470930SIngo Molnar continue; 59986470930SIngo Molnar 60086470930SIngo Molnar sec = elf_getscn(elf, sym.st_shndx); 60186470930SIngo Molnar if (!sec) 60286470930SIngo Molnar goto out_elf_end; 60386470930SIngo Molnar 60486470930SIngo Molnar gelf_getshdr(sec, &shdr); 6056cfcc53eSMike Galbraith 6066cfcc53eSMike Galbraith if (is_label && !elf_sec__is_text(&shdr, secstrs)) 6076cfcc53eSMike Galbraith continue; 6086cfcc53eSMike Galbraith 6096cfcc53eSMike Galbraith section_name = elf_sec__name(&shdr, secstrs); 61086470930SIngo Molnar obj_start = sym.st_value; 61186470930SIngo Molnar 61230d7a77dSArnaldo Carvalho de Melo if (self->adjust_symbols) { 61383a0944fSIngo Molnar if (v >= 2) 614520f2c34SPeter Zijlstra printf("adjusting symbol: st_value: %Lx sh_addr: %Lx sh_offset: %Lx\n", 615520f2c34SPeter Zijlstra (u64)sym.st_value, (u64)shdr.sh_addr, (u64)shdr.sh_offset); 616520f2c34SPeter Zijlstra 61786470930SIngo Molnar sym.st_value -= shdr.sh_addr - shdr.sh_offset; 618f5812a7aSArnaldo Carvalho de Melo } 61986470930SIngo Molnar 6206cfcc53eSMike Galbraith if (mod) { 6216cfcc53eSMike Galbraith section = mod->sections->find_section(mod->sections, section_name); 6226cfcc53eSMike Galbraith if (section) 6236cfcc53eSMike Galbraith sym.st_value += section->vma; 6246cfcc53eSMike Galbraith else { 6256cfcc53eSMike Galbraith fprintf(stderr, "dso__load_sym() module %s lookup of %s failed\n", 6266cfcc53eSMike Galbraith mod->name, section_name); 6276cfcc53eSMike Galbraith goto out_elf_end; 6286cfcc53eSMike Galbraith } 6296cfcc53eSMike Galbraith } 63028ac909bSArnaldo Carvalho de Melo /* 63128ac909bSArnaldo Carvalho de Melo * We need to figure out if the object was created from C++ sources 63228ac909bSArnaldo Carvalho de Melo * DWARF DW_compile_unit has this, but we don't always have access 63328ac909bSArnaldo Carvalho de Melo * to it... 63428ac909bSArnaldo Carvalho de Melo */ 63583a0944fSIngo Molnar elf_name = elf_sym__name(&sym, symstrs); 63683a0944fSIngo Molnar demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI); 63728ac909bSArnaldo Carvalho de Melo if (demangled != NULL) 63883a0944fSIngo Molnar elf_name = demangled; 6396cfcc53eSMike Galbraith 64083a0944fSIngo Molnar f = symbol__new(sym.st_value, sym.st_size, elf_name, 64183a0944fSIngo Molnar self->sym_priv_size, obj_start, v); 64228ac909bSArnaldo Carvalho de Melo free(demangled); 64386470930SIngo Molnar if (!f) 64486470930SIngo Molnar goto out_elf_end; 64586470930SIngo Molnar 64686470930SIngo Molnar if (filter && filter(self, f)) 64786470930SIngo Molnar symbol__delete(f, self->sym_priv_size); 64886470930SIngo Molnar else { 6496cfcc53eSMike Galbraith f->module = mod; 65086470930SIngo Molnar dso__insert_symbol(self, f); 65186470930SIngo Molnar nr++; 65286470930SIngo Molnar } 65386470930SIngo Molnar } 65486470930SIngo Molnar 65586470930SIngo Molnar err = nr; 65686470930SIngo Molnar out_elf_end: 65786470930SIngo Molnar elf_end(elf); 65886470930SIngo Molnar out_close: 65986470930SIngo Molnar return err; 66086470930SIngo Molnar } 66186470930SIngo Molnar 6624d1e00a8SArnaldo Carvalho de Melo #define BUILD_ID_SIZE 128 6634d1e00a8SArnaldo Carvalho de Melo 66483a0944fSIngo Molnar static char *dso__read_build_id(struct dso *self, int v) 6654d1e00a8SArnaldo Carvalho de Melo { 6664d1e00a8SArnaldo Carvalho de Melo int i; 6674d1e00a8SArnaldo Carvalho de Melo GElf_Ehdr ehdr; 6684d1e00a8SArnaldo Carvalho de Melo GElf_Shdr shdr; 6694d1e00a8SArnaldo Carvalho de Melo Elf_Data *build_id_data; 6704d1e00a8SArnaldo Carvalho de Melo Elf_Scn *sec; 6714d1e00a8SArnaldo Carvalho de Melo char *build_id = NULL, *bid; 6724d1e00a8SArnaldo Carvalho de Melo unsigned char *raw; 6734d1e00a8SArnaldo Carvalho de Melo Elf *elf; 6744d1e00a8SArnaldo Carvalho de Melo int fd = open(self->name, O_RDONLY); 6754d1e00a8SArnaldo Carvalho de Melo 6764d1e00a8SArnaldo Carvalho de Melo if (fd < 0) 6774d1e00a8SArnaldo Carvalho de Melo goto out; 6784d1e00a8SArnaldo Carvalho de Melo 6794d1e00a8SArnaldo Carvalho de Melo elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); 6804d1e00a8SArnaldo Carvalho de Melo if (elf == NULL) { 68183a0944fSIngo Molnar if (v) 6824d1e00a8SArnaldo Carvalho de Melo fprintf(stderr, "%s: cannot read %s ELF file.\n", 6834d1e00a8SArnaldo Carvalho de Melo __func__, self->name); 6844d1e00a8SArnaldo Carvalho de Melo goto out_close; 6854d1e00a8SArnaldo Carvalho de Melo } 6864d1e00a8SArnaldo Carvalho de Melo 6874d1e00a8SArnaldo Carvalho de Melo if (gelf_getehdr(elf, &ehdr) == NULL) { 68883a0944fSIngo Molnar if (v) 6894d1e00a8SArnaldo Carvalho de Melo fprintf(stderr, "%s: cannot get elf header.\n", __func__); 6904d1e00a8SArnaldo Carvalho de Melo goto out_elf_end; 6914d1e00a8SArnaldo Carvalho de Melo } 6924d1e00a8SArnaldo Carvalho de Melo 6934d1e00a8SArnaldo Carvalho de Melo sec = elf_section_by_name(elf, &ehdr, &shdr, ".note.gnu.build-id", NULL); 6944d1e00a8SArnaldo Carvalho de Melo if (sec == NULL) 6954d1e00a8SArnaldo Carvalho de Melo goto out_elf_end; 6964d1e00a8SArnaldo Carvalho de Melo 6974d1e00a8SArnaldo Carvalho de Melo build_id_data = elf_getdata(sec, NULL); 6984d1e00a8SArnaldo Carvalho de Melo if (build_id_data == NULL) 6994d1e00a8SArnaldo Carvalho de Melo goto out_elf_end; 7004d1e00a8SArnaldo Carvalho de Melo build_id = malloc(BUILD_ID_SIZE); 7014d1e00a8SArnaldo Carvalho de Melo if (build_id == NULL) 7024d1e00a8SArnaldo Carvalho de Melo goto out_elf_end; 7034d1e00a8SArnaldo Carvalho de Melo raw = build_id_data->d_buf + 16; 7044d1e00a8SArnaldo Carvalho de Melo bid = build_id; 7054d1e00a8SArnaldo Carvalho de Melo 7064d1e00a8SArnaldo Carvalho de Melo for (i = 0; i < 20; ++i) { 7074d1e00a8SArnaldo Carvalho de Melo sprintf(bid, "%02x", *raw); 7084d1e00a8SArnaldo Carvalho de Melo ++raw; 7094d1e00a8SArnaldo Carvalho de Melo bid += 2; 7104d1e00a8SArnaldo Carvalho de Melo } 71183a0944fSIngo Molnar if (v >= 2) 7124d1e00a8SArnaldo Carvalho de Melo printf("%s(%s): %s\n", __func__, self->name, build_id); 7134d1e00a8SArnaldo Carvalho de Melo out_elf_end: 7144d1e00a8SArnaldo Carvalho de Melo elf_end(elf); 7154d1e00a8SArnaldo Carvalho de Melo out_close: 7164d1e00a8SArnaldo Carvalho de Melo close(fd); 7174d1e00a8SArnaldo Carvalho de Melo out: 7184d1e00a8SArnaldo Carvalho de Melo return build_id; 7194d1e00a8SArnaldo Carvalho de Melo } 7204d1e00a8SArnaldo Carvalho de Melo 72194cb9e38SArnaldo Carvalho de Melo char dso__symtab_origin(const struct dso *self) 72294cb9e38SArnaldo Carvalho de Melo { 72394cb9e38SArnaldo Carvalho de Melo static const char origin[] = { 72494cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_KERNEL] = 'k', 72594cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_JAVA_JIT] = 'j', 72694cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_FEDORA] = 'f', 72794cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_UBUNTU] = 'u', 72894cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_BUILDID] = 'b', 72994cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_DSO] = 'd', 73094cb9e38SArnaldo Carvalho de Melo }; 73194cb9e38SArnaldo Carvalho de Melo 73294cb9e38SArnaldo Carvalho de Melo if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND) 73394cb9e38SArnaldo Carvalho de Melo return '!'; 73494cb9e38SArnaldo Carvalho de Melo return origin[self->origin]; 73594cb9e38SArnaldo Carvalho de Melo } 73694cb9e38SArnaldo Carvalho de Melo 73783a0944fSIngo Molnar int dso__load(struct dso *self, symbol_filter_t filter, int v) 73886470930SIngo Molnar { 7394d1e00a8SArnaldo Carvalho de Melo int size = PATH_MAX; 7404d1e00a8SArnaldo Carvalho de Melo char *name = malloc(size), *build_id = NULL; 74186470930SIngo Molnar int ret = -1; 74286470930SIngo Molnar int fd; 74386470930SIngo Molnar 74486470930SIngo Molnar if (!name) 74586470930SIngo Molnar return -1; 74686470930SIngo Molnar 74730d7a77dSArnaldo Carvalho de Melo self->adjust_symbols = 0; 748f5812a7aSArnaldo Carvalho de Melo 74994cb9e38SArnaldo Carvalho de Melo if (strncmp(self->name, "/tmp/perf-", 10) == 0) { 75083a0944fSIngo Molnar ret = dso__load_perf_map(self, filter, v); 75194cb9e38SArnaldo Carvalho de Melo self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT : 75294cb9e38SArnaldo Carvalho de Melo DSO__ORIG_NOT_FOUND; 75394cb9e38SArnaldo Carvalho de Melo return ret; 75494cb9e38SArnaldo Carvalho de Melo } 75594cb9e38SArnaldo Carvalho de Melo 75694cb9e38SArnaldo Carvalho de Melo self->origin = DSO__ORIG_FEDORA - 1; 75780d496beSPekka Enberg 75886470930SIngo Molnar more: 75986470930SIngo Molnar do { 76094cb9e38SArnaldo Carvalho de Melo self->origin++; 76194cb9e38SArnaldo Carvalho de Melo switch (self->origin) { 76294cb9e38SArnaldo Carvalho de Melo case DSO__ORIG_FEDORA: 76386470930SIngo Molnar snprintf(name, size, "/usr/lib/debug%s.debug", self->name); 76486470930SIngo Molnar break; 76594cb9e38SArnaldo Carvalho de Melo case DSO__ORIG_UBUNTU: 76686470930SIngo Molnar snprintf(name, size, "/usr/lib/debug%s", self->name); 76786470930SIngo Molnar break; 76894cb9e38SArnaldo Carvalho de Melo case DSO__ORIG_BUILDID: 76983a0944fSIngo Molnar build_id = dso__read_build_id(self, v); 7704d1e00a8SArnaldo Carvalho de Melo if (build_id != NULL) { 7714d1e00a8SArnaldo Carvalho de Melo snprintf(name, size, 7724d1e00a8SArnaldo Carvalho de Melo "/usr/lib/debug/.build-id/%.2s/%s.debug", 7734d1e00a8SArnaldo Carvalho de Melo build_id, build_id + 2); 7744d1e00a8SArnaldo Carvalho de Melo free(build_id); 7754d1e00a8SArnaldo Carvalho de Melo break; 7764d1e00a8SArnaldo Carvalho de Melo } 77794cb9e38SArnaldo Carvalho de Melo self->origin++; 7784d1e00a8SArnaldo Carvalho de Melo /* Fall thru */ 77994cb9e38SArnaldo Carvalho de Melo case DSO__ORIG_DSO: 78086470930SIngo Molnar snprintf(name, size, "%s", self->name); 78186470930SIngo Molnar break; 78286470930SIngo Molnar 78386470930SIngo Molnar default: 78486470930SIngo Molnar goto out; 78586470930SIngo Molnar } 78686470930SIngo Molnar 78786470930SIngo Molnar fd = open(name, O_RDONLY); 78886470930SIngo Molnar } while (fd < 0); 78986470930SIngo Molnar 79083a0944fSIngo Molnar ret = dso__load_sym(self, fd, name, filter, v, NULL); 79186470930SIngo Molnar close(fd); 79286470930SIngo Molnar 79386470930SIngo Molnar /* 79486470930SIngo Molnar * Some people seem to have debuginfo files _WITHOUT_ debug info!?!? 79586470930SIngo Molnar */ 79686470930SIngo Molnar if (!ret) 79786470930SIngo Molnar goto more; 79886470930SIngo Molnar 799a25e46c4SArnaldo Carvalho de Melo if (ret > 0) { 80083a0944fSIngo Molnar int nr_plt = dso__synthesize_plt_symbols(self, v); 801a25e46c4SArnaldo Carvalho de Melo if (nr_plt > 0) 802a25e46c4SArnaldo Carvalho de Melo ret += nr_plt; 803a25e46c4SArnaldo Carvalho de Melo } 80486470930SIngo Molnar out: 80586470930SIngo Molnar free(name); 8061340e6bbSArnaldo Carvalho de Melo if (ret < 0 && strstr(self->name, " (deleted)") != NULL) 8071340e6bbSArnaldo Carvalho de Melo return 0; 80886470930SIngo Molnar return ret; 80986470930SIngo Molnar } 81086470930SIngo Molnar 8116cfcc53eSMike Galbraith static int dso__load_module(struct dso *self, struct mod_dso *mods, const char *name, 81283a0944fSIngo Molnar symbol_filter_t filter, int v) 8136cfcc53eSMike Galbraith { 8146cfcc53eSMike Galbraith struct module *mod = mod_dso__find_module(mods, name); 8156cfcc53eSMike Galbraith int err = 0, fd; 8166cfcc53eSMike Galbraith 8176cfcc53eSMike Galbraith if (mod == NULL || !mod->active) 8186cfcc53eSMike Galbraith return err; 8196cfcc53eSMike Galbraith 8206cfcc53eSMike Galbraith fd = open(mod->path, O_RDONLY); 8216cfcc53eSMike Galbraith 8226cfcc53eSMike Galbraith if (fd < 0) 8236cfcc53eSMike Galbraith return err; 8246cfcc53eSMike Galbraith 82583a0944fSIngo Molnar err = dso__load_sym(self, fd, name, filter, v, mod); 8266cfcc53eSMike Galbraith close(fd); 8276cfcc53eSMike Galbraith 8286cfcc53eSMike Galbraith return err; 8296cfcc53eSMike Galbraith } 8306cfcc53eSMike Galbraith 83183a0944fSIngo Molnar int dso__load_modules(struct dso *self, symbol_filter_t filter, int v) 8326cfcc53eSMike Galbraith { 8336cfcc53eSMike Galbraith struct mod_dso *mods = mod_dso__new_dso("modules"); 8346cfcc53eSMike Galbraith struct module *pos; 8356cfcc53eSMike Galbraith struct rb_node *next; 8366cfcc53eSMike Galbraith int err; 8376cfcc53eSMike Galbraith 8386cfcc53eSMike Galbraith err = mod_dso__load_modules(mods); 8396cfcc53eSMike Galbraith 8406cfcc53eSMike Galbraith if (err <= 0) 8416cfcc53eSMike Galbraith return err; 8426cfcc53eSMike Galbraith 8436cfcc53eSMike Galbraith /* 8446cfcc53eSMike Galbraith * Iterate over modules, and load active symbols. 8456cfcc53eSMike Galbraith */ 8466cfcc53eSMike Galbraith next = rb_first(&mods->mods); 8476cfcc53eSMike Galbraith while (next) { 8486cfcc53eSMike Galbraith pos = rb_entry(next, struct module, rb_node); 84983a0944fSIngo Molnar err = dso__load_module(self, mods, pos->name, filter, v); 8506cfcc53eSMike Galbraith 8516cfcc53eSMike Galbraith if (err < 0) 8526cfcc53eSMike Galbraith break; 8536cfcc53eSMike Galbraith 8546cfcc53eSMike Galbraith next = rb_next(&pos->rb_node); 8556cfcc53eSMike Galbraith } 8566cfcc53eSMike Galbraith 8576cfcc53eSMike Galbraith if (err < 0) { 8586cfcc53eSMike Galbraith mod_dso__delete_modules(mods); 8596cfcc53eSMike Galbraith mod_dso__delete_self(mods); 8606cfcc53eSMike Galbraith } 8616cfcc53eSMike Galbraith 8626cfcc53eSMike Galbraith return err; 8636cfcc53eSMike Galbraith } 8646cfcc53eSMike Galbraith 8656cfcc53eSMike Galbraith static inline void dso__fill_symbol_holes(struct dso *self) 8666cfcc53eSMike Galbraith { 8676cfcc53eSMike Galbraith struct symbol *prev = NULL; 8686cfcc53eSMike Galbraith struct rb_node *nd; 8696cfcc53eSMike Galbraith 8706cfcc53eSMike Galbraith for (nd = rb_last(&self->syms); nd; nd = rb_prev(nd)) { 8716cfcc53eSMike Galbraith struct symbol *pos = rb_entry(nd, struct symbol, rb_node); 8726cfcc53eSMike Galbraith 8736cfcc53eSMike Galbraith if (prev) { 8746cfcc53eSMike Galbraith u64 hole = 0; 8756cfcc53eSMike Galbraith int alias = pos->start == prev->start; 8766cfcc53eSMike Galbraith 8776cfcc53eSMike Galbraith if (!alias) 8786cfcc53eSMike Galbraith hole = prev->start - pos->end - 1; 8796cfcc53eSMike Galbraith 8806cfcc53eSMike Galbraith if (hole || alias) { 8816cfcc53eSMike Galbraith if (alias) 8826cfcc53eSMike Galbraith pos->end = prev->end; 8836cfcc53eSMike Galbraith else if (hole) 8846cfcc53eSMike Galbraith pos->end = prev->start - 1; 8856cfcc53eSMike Galbraith } 8866cfcc53eSMike Galbraith } 8876cfcc53eSMike Galbraith prev = pos; 8886cfcc53eSMike Galbraith } 8896cfcc53eSMike Galbraith } 8906cfcc53eSMike Galbraith 89186470930SIngo Molnar static int dso__load_vmlinux(struct dso *self, const char *vmlinux, 89283a0944fSIngo Molnar symbol_filter_t filter, int v) 89386470930SIngo Molnar { 89486470930SIngo Molnar int err, fd = open(vmlinux, O_RDONLY); 89586470930SIngo Molnar 89686470930SIngo Molnar if (fd < 0) 89786470930SIngo Molnar return -1; 89886470930SIngo Molnar 89983a0944fSIngo Molnar err = dso__load_sym(self, fd, vmlinux, filter, v, NULL); 9006cfcc53eSMike Galbraith 9016cfcc53eSMike Galbraith if (err > 0) 9026cfcc53eSMike Galbraith dso__fill_symbol_holes(self); 9036cfcc53eSMike Galbraith 90486470930SIngo Molnar close(fd); 90586470930SIngo Molnar 90686470930SIngo Molnar return err; 90786470930SIngo Molnar } 90886470930SIngo Molnar 90986470930SIngo Molnar int dso__load_kernel(struct dso *self, const char *vmlinux, 91083a0944fSIngo Molnar symbol_filter_t filter, int v, int use_modules) 91186470930SIngo Molnar { 91286470930SIngo Molnar int err = -1; 91386470930SIngo Molnar 9146cfcc53eSMike Galbraith if (vmlinux) { 91583a0944fSIngo Molnar err = dso__load_vmlinux(self, vmlinux, filter, v); 91683a0944fSIngo Molnar if (err > 0 && use_modules) 91783a0944fSIngo Molnar err = dso__load_modules(self, filter, v); 9186cfcc53eSMike Galbraith } 91986470930SIngo Molnar 9209974f496SMike Galbraith if (err <= 0) 92183a0944fSIngo Molnar err = dso__load_kallsyms(self, filter, v); 92286470930SIngo Molnar 92394cb9e38SArnaldo Carvalho de Melo if (err > 0) 92494cb9e38SArnaldo Carvalho de Melo self->origin = DSO__ORIG_KERNEL; 92594cb9e38SArnaldo Carvalho de Melo 92686470930SIngo Molnar return err; 92786470930SIngo Molnar } 92886470930SIngo Molnar 929cd84c2acSFrederic Weisbecker LIST_HEAD(dsos); 930cd84c2acSFrederic Weisbecker struct dso *kernel_dso; 931cd84c2acSFrederic Weisbecker struct dso *vdso; 932cd84c2acSFrederic Weisbecker struct dso *hypervisor_dso; 933cd84c2acSFrederic Weisbecker 93483a0944fSIngo Molnar const char *vmlinux_name = "vmlinux"; 935cd84c2acSFrederic Weisbecker int modules; 936cd84c2acSFrederic Weisbecker 937cd84c2acSFrederic Weisbecker static void dsos__add(struct dso *dso) 938cd84c2acSFrederic Weisbecker { 939cd84c2acSFrederic Weisbecker list_add_tail(&dso->node, &dsos); 940cd84c2acSFrederic Weisbecker } 941cd84c2acSFrederic Weisbecker 942cd84c2acSFrederic Weisbecker static struct dso *dsos__find(const char *name) 943cd84c2acSFrederic Weisbecker { 944cd84c2acSFrederic Weisbecker struct dso *pos; 945cd84c2acSFrederic Weisbecker 946cd84c2acSFrederic Weisbecker list_for_each_entry(pos, &dsos, node) 947cd84c2acSFrederic Weisbecker if (strcmp(pos->name, name) == 0) 948cd84c2acSFrederic Weisbecker return pos; 949cd84c2acSFrederic Weisbecker return NULL; 950cd84c2acSFrederic Weisbecker } 951cd84c2acSFrederic Weisbecker 952cd84c2acSFrederic Weisbecker struct dso *dsos__findnew(const char *name) 953cd84c2acSFrederic Weisbecker { 954cd84c2acSFrederic Weisbecker struct dso *dso = dsos__find(name); 955cd84c2acSFrederic Weisbecker int nr; 956cd84c2acSFrederic Weisbecker 957cd84c2acSFrederic Weisbecker if (dso) 958cd84c2acSFrederic Weisbecker return dso; 959cd84c2acSFrederic Weisbecker 960cd84c2acSFrederic Weisbecker dso = dso__new(name, 0); 961cd84c2acSFrederic Weisbecker if (!dso) 962cd84c2acSFrederic Weisbecker goto out_delete_dso; 963cd84c2acSFrederic Weisbecker 964cd84c2acSFrederic Weisbecker nr = dso__load(dso, NULL, verbose); 965cd84c2acSFrederic Weisbecker if (nr < 0) { 966cd84c2acSFrederic Weisbecker eprintf("Failed to open: %s\n", name); 967cd84c2acSFrederic Weisbecker goto out_delete_dso; 968cd84c2acSFrederic Weisbecker } 969cd84c2acSFrederic Weisbecker if (!nr) 970cd84c2acSFrederic Weisbecker eprintf("No symbols found in: %s, maybe install a debug package?\n", name); 971cd84c2acSFrederic Weisbecker 972cd84c2acSFrederic Weisbecker dsos__add(dso); 973cd84c2acSFrederic Weisbecker 974cd84c2acSFrederic Weisbecker return dso; 975cd84c2acSFrederic Weisbecker 976cd84c2acSFrederic Weisbecker out_delete_dso: 977cd84c2acSFrederic Weisbecker dso__delete(dso); 978cd84c2acSFrederic Weisbecker return NULL; 979cd84c2acSFrederic Weisbecker } 980cd84c2acSFrederic Weisbecker 981cd84c2acSFrederic Weisbecker void dsos__fprintf(FILE *fp) 982cd84c2acSFrederic Weisbecker { 983cd84c2acSFrederic Weisbecker struct dso *pos; 984cd84c2acSFrederic Weisbecker 985cd84c2acSFrederic Weisbecker list_for_each_entry(pos, &dsos, node) 986cd84c2acSFrederic Weisbecker dso__fprintf(pos, fp); 987cd84c2acSFrederic Weisbecker } 988cd84c2acSFrederic Weisbecker 989cd84c2acSFrederic Weisbecker static struct symbol *vdso__find_symbol(struct dso *dso, u64 ip) 990cd84c2acSFrederic Weisbecker { 991cd84c2acSFrederic Weisbecker return dso__find_symbol(dso, ip); 992cd84c2acSFrederic Weisbecker } 993cd84c2acSFrederic Weisbecker 994cd84c2acSFrederic Weisbecker int load_kernel(void) 995cd84c2acSFrederic Weisbecker { 996cd84c2acSFrederic Weisbecker int err; 997cd84c2acSFrederic Weisbecker 998cd84c2acSFrederic Weisbecker kernel_dso = dso__new("[kernel]", 0); 999cd84c2acSFrederic Weisbecker if (!kernel_dso) 1000cd84c2acSFrederic Weisbecker return -1; 1001cd84c2acSFrederic Weisbecker 100283a0944fSIngo Molnar err = dso__load_kernel(kernel_dso, vmlinux_name, NULL, verbose, modules); 1003cd84c2acSFrederic Weisbecker if (err <= 0) { 1004cd84c2acSFrederic Weisbecker dso__delete(kernel_dso); 1005cd84c2acSFrederic Weisbecker kernel_dso = NULL; 1006cd84c2acSFrederic Weisbecker } else 1007cd84c2acSFrederic Weisbecker dsos__add(kernel_dso); 1008cd84c2acSFrederic Weisbecker 1009cd84c2acSFrederic Weisbecker vdso = dso__new("[vdso]", 0); 1010cd84c2acSFrederic Weisbecker if (!vdso) 1011cd84c2acSFrederic Weisbecker return -1; 1012cd84c2acSFrederic Weisbecker 1013cd84c2acSFrederic Weisbecker vdso->find_symbol = vdso__find_symbol; 1014cd84c2acSFrederic Weisbecker 1015cd84c2acSFrederic Weisbecker dsos__add(vdso); 1016cd84c2acSFrederic Weisbecker 1017cd84c2acSFrederic Weisbecker hypervisor_dso = dso__new("[hypervisor]", 0); 1018cd84c2acSFrederic Weisbecker if (!hypervisor_dso) 1019cd84c2acSFrederic Weisbecker return -1; 1020cd84c2acSFrederic Weisbecker dsos__add(hypervisor_dso); 1021cd84c2acSFrederic Weisbecker 1022cd84c2acSFrederic Weisbecker return err; 1023cd84c2acSFrederic Weisbecker } 1024cd84c2acSFrederic Weisbecker 1025cd84c2acSFrederic Weisbecker 102686470930SIngo Molnar void symbol__init(void) 102786470930SIngo Molnar { 102886470930SIngo Molnar elf_version(EV_CURRENT); 102986470930SIngo Molnar } 1030