186470930SIngo Molnar #include "util.h" 286470930SIngo Molnar #include "../perf.h" 386470930SIngo Molnar #include "string.h" 486470930SIngo Molnar #include "symbol.h" 586470930SIngo Molnar 686470930SIngo Molnar #include <libelf.h> 786470930SIngo Molnar #include <gelf.h> 886470930SIngo Molnar #include <elf.h> 986470930SIngo Molnar 1086470930SIngo Molnar const char *sym_hist_filter; 1186470930SIngo Molnar 129cffa8d5SPaul Mackerras static struct symbol *symbol__new(u64 start, u64 len, 1386470930SIngo Molnar const char *name, unsigned int priv_size, 149cffa8d5SPaul Mackerras u64 obj_start, int verbose) 1586470930SIngo Molnar { 1686470930SIngo Molnar size_t namelen = strlen(name) + 1; 1786470930SIngo Molnar struct symbol *self = calloc(1, priv_size + sizeof(*self) + namelen); 1886470930SIngo Molnar 1986470930SIngo Molnar if (!self) 2086470930SIngo Molnar return NULL; 2186470930SIngo Molnar 2286470930SIngo Molnar if (verbose >= 2) 2386470930SIngo Molnar printf("new symbol: %016Lx [%08lx]: %s, hist: %p, obj_start: %p\n", 249cffa8d5SPaul Mackerras (u64)start, (unsigned long)len, name, self->hist, (void *)(unsigned long)obj_start); 2586470930SIngo Molnar 2686470930SIngo Molnar self->obj_start= obj_start; 2786470930SIngo Molnar self->hist = NULL; 2886470930SIngo Molnar self->hist_sum = 0; 2986470930SIngo Molnar 3086470930SIngo Molnar if (sym_hist_filter && !strcmp(name, sym_hist_filter)) 319cffa8d5SPaul Mackerras self->hist = calloc(sizeof(u64), len); 3286470930SIngo Molnar 3386470930SIngo Molnar if (priv_size) { 3486470930SIngo Molnar memset(self, 0, priv_size); 3586470930SIngo Molnar self = ((void *)self) + priv_size; 3686470930SIngo Molnar } 3786470930SIngo Molnar self->start = start; 386cfcc53eSMike Galbraith self->end = len ? start + len - 1 : start; 3986470930SIngo Molnar memcpy(self->name, name, namelen); 4086470930SIngo Molnar 4186470930SIngo Molnar return self; 4286470930SIngo Molnar } 4386470930SIngo Molnar 4486470930SIngo Molnar static void symbol__delete(struct symbol *self, unsigned int priv_size) 4586470930SIngo Molnar { 4686470930SIngo Molnar free(((void *)self) - priv_size); 4786470930SIngo Molnar } 4886470930SIngo Molnar 4986470930SIngo Molnar static size_t symbol__fprintf(struct symbol *self, FILE *fp) 5086470930SIngo Molnar { 516cfcc53eSMike Galbraith if (!self->module) 5286470930SIngo Molnar return fprintf(fp, " %llx-%llx %s\n", 5386470930SIngo Molnar self->start, self->end, self->name); 546cfcc53eSMike Galbraith else 556cfcc53eSMike Galbraith return fprintf(fp, " %llx-%llx %s \t[%s]\n", 566cfcc53eSMike Galbraith self->start, self->end, self->name, self->module->name); 5786470930SIngo Molnar } 5886470930SIngo Molnar 5986470930SIngo Molnar struct dso *dso__new(const char *name, unsigned int sym_priv_size) 6086470930SIngo Molnar { 6186470930SIngo Molnar struct dso *self = malloc(sizeof(*self) + strlen(name) + 1); 6286470930SIngo Molnar 6386470930SIngo Molnar if (self != NULL) { 6486470930SIngo Molnar strcpy(self->name, name); 6586470930SIngo Molnar self->syms = RB_ROOT; 6686470930SIngo Molnar self->sym_priv_size = sym_priv_size; 6786470930SIngo Molnar self->find_symbol = dso__find_symbol; 68*52d422deSArnaldo Carvalho de Melo self->slen_calculated = 0; 6986470930SIngo Molnar } 7086470930SIngo Molnar 7186470930SIngo Molnar return self; 7286470930SIngo Molnar } 7386470930SIngo Molnar 7486470930SIngo Molnar static void dso__delete_symbols(struct dso *self) 7586470930SIngo Molnar { 7686470930SIngo Molnar struct symbol *pos; 7786470930SIngo Molnar struct rb_node *next = rb_first(&self->syms); 7886470930SIngo Molnar 7986470930SIngo Molnar while (next) { 8086470930SIngo Molnar pos = rb_entry(next, struct symbol, rb_node); 8186470930SIngo Molnar next = rb_next(&pos->rb_node); 8286470930SIngo Molnar rb_erase(&pos->rb_node, &self->syms); 8386470930SIngo Molnar symbol__delete(pos, self->sym_priv_size); 8486470930SIngo Molnar } 8586470930SIngo Molnar } 8686470930SIngo Molnar 8786470930SIngo Molnar void dso__delete(struct dso *self) 8886470930SIngo Molnar { 8986470930SIngo Molnar dso__delete_symbols(self); 9086470930SIngo Molnar free(self); 9186470930SIngo Molnar } 9286470930SIngo Molnar 9386470930SIngo Molnar static void dso__insert_symbol(struct dso *self, struct symbol *sym) 9486470930SIngo Molnar { 9586470930SIngo Molnar struct rb_node **p = &self->syms.rb_node; 9686470930SIngo Molnar struct rb_node *parent = NULL; 979cffa8d5SPaul Mackerras const u64 ip = sym->start; 9886470930SIngo Molnar struct symbol *s; 9986470930SIngo Molnar 10086470930SIngo Molnar while (*p != NULL) { 10186470930SIngo Molnar parent = *p; 10286470930SIngo Molnar s = rb_entry(parent, struct symbol, rb_node); 10386470930SIngo Molnar if (ip < s->start) 10486470930SIngo Molnar p = &(*p)->rb_left; 10586470930SIngo Molnar else 10686470930SIngo Molnar p = &(*p)->rb_right; 10786470930SIngo Molnar } 10886470930SIngo Molnar rb_link_node(&sym->rb_node, parent, p); 10986470930SIngo Molnar rb_insert_color(&sym->rb_node, &self->syms); 11086470930SIngo Molnar } 11186470930SIngo Molnar 1129cffa8d5SPaul Mackerras struct symbol *dso__find_symbol(struct dso *self, u64 ip) 11386470930SIngo Molnar { 11486470930SIngo Molnar struct rb_node *n; 11586470930SIngo Molnar 11686470930SIngo Molnar if (self == NULL) 11786470930SIngo Molnar return NULL; 11886470930SIngo Molnar 11986470930SIngo Molnar n = self->syms.rb_node; 12086470930SIngo Molnar 12186470930SIngo Molnar while (n) { 12286470930SIngo Molnar struct symbol *s = rb_entry(n, struct symbol, rb_node); 12386470930SIngo Molnar 12486470930SIngo Molnar if (ip < s->start) 12586470930SIngo Molnar n = n->rb_left; 12686470930SIngo Molnar else if (ip > s->end) 12786470930SIngo Molnar n = n->rb_right; 12886470930SIngo Molnar else 12986470930SIngo Molnar return s; 13086470930SIngo Molnar } 13186470930SIngo Molnar 13286470930SIngo Molnar return NULL; 13386470930SIngo Molnar } 13486470930SIngo Molnar 13586470930SIngo Molnar size_t dso__fprintf(struct dso *self, FILE *fp) 13686470930SIngo Molnar { 13786470930SIngo Molnar size_t ret = fprintf(fp, "dso: %s\n", self->name); 13886470930SIngo Molnar 13986470930SIngo Molnar struct rb_node *nd; 14086470930SIngo Molnar for (nd = rb_first(&self->syms); nd; nd = rb_next(nd)) { 14186470930SIngo Molnar struct symbol *pos = rb_entry(nd, struct symbol, rb_node); 14286470930SIngo Molnar ret += symbol__fprintf(pos, fp); 14386470930SIngo Molnar } 14486470930SIngo Molnar 14586470930SIngo Molnar return ret; 14686470930SIngo Molnar } 14786470930SIngo Molnar 14886470930SIngo Molnar static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int verbose) 14986470930SIngo Molnar { 15086470930SIngo Molnar struct rb_node *nd, *prevnd; 15186470930SIngo Molnar char *line = NULL; 15286470930SIngo Molnar size_t n; 15386470930SIngo Molnar FILE *file = fopen("/proc/kallsyms", "r"); 1549974f496SMike Galbraith int count = 0; 15586470930SIngo Molnar 15686470930SIngo Molnar if (file == NULL) 15786470930SIngo Molnar goto out_failure; 15886470930SIngo Molnar 15986470930SIngo Molnar while (!feof(file)) { 1609cffa8d5SPaul Mackerras u64 start; 16186470930SIngo Molnar struct symbol *sym; 16286470930SIngo Molnar int line_len, len; 16386470930SIngo Molnar char symbol_type; 16486470930SIngo Molnar 16586470930SIngo Molnar line_len = getline(&line, &n, file); 16686470930SIngo Molnar if (line_len < 0) 16786470930SIngo Molnar break; 16886470930SIngo Molnar 16986470930SIngo Molnar if (!line) 17086470930SIngo Molnar goto out_failure; 17186470930SIngo Molnar 17286470930SIngo Molnar line[--line_len] = '\0'; /* \n */ 17386470930SIngo Molnar 17486470930SIngo Molnar len = hex2u64(line, &start); 17586470930SIngo Molnar 17686470930SIngo Molnar len++; 17786470930SIngo Molnar if (len + 2 >= line_len) 17886470930SIngo Molnar continue; 17986470930SIngo Molnar 18086470930SIngo Molnar symbol_type = toupper(line[len]); 18186470930SIngo Molnar /* 18286470930SIngo Molnar * We're interested only in code ('T'ext) 18386470930SIngo Molnar */ 18486470930SIngo Molnar if (symbol_type != 'T' && symbol_type != 'W') 18586470930SIngo Molnar continue; 18686470930SIngo Molnar /* 18786470930SIngo Molnar * Well fix up the end later, when we have all sorted. 18886470930SIngo Molnar */ 18986470930SIngo Molnar sym = symbol__new(start, 0xdead, line + len + 2, 19086470930SIngo Molnar self->sym_priv_size, 0, verbose); 19186470930SIngo Molnar 19286470930SIngo Molnar if (sym == NULL) 19386470930SIngo Molnar goto out_delete_line; 19486470930SIngo Molnar 19586470930SIngo Molnar if (filter && filter(self, sym)) 19686470930SIngo Molnar symbol__delete(sym, self->sym_priv_size); 1979974f496SMike Galbraith else { 19886470930SIngo Molnar dso__insert_symbol(self, sym); 1999974f496SMike Galbraith count++; 2009974f496SMike Galbraith } 20186470930SIngo Molnar } 20286470930SIngo Molnar 20386470930SIngo Molnar /* 20486470930SIngo Molnar * Now that we have all sorted out, just set the ->end of all 20586470930SIngo Molnar * symbols 20686470930SIngo Molnar */ 20786470930SIngo Molnar prevnd = rb_first(&self->syms); 20886470930SIngo Molnar 20986470930SIngo Molnar if (prevnd == NULL) 21086470930SIngo Molnar goto out_delete_line; 21186470930SIngo Molnar 21286470930SIngo Molnar for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) { 21386470930SIngo Molnar struct symbol *prev = rb_entry(prevnd, struct symbol, rb_node), 21486470930SIngo Molnar *curr = rb_entry(nd, struct symbol, rb_node); 21586470930SIngo Molnar 21686470930SIngo Molnar prev->end = curr->start - 1; 21786470930SIngo Molnar prevnd = nd; 21886470930SIngo Molnar } 21986470930SIngo Molnar 22086470930SIngo Molnar free(line); 22186470930SIngo Molnar fclose(file); 22286470930SIngo Molnar 2239974f496SMike Galbraith return count; 22486470930SIngo Molnar 22586470930SIngo Molnar out_delete_line: 22686470930SIngo Molnar free(line); 22786470930SIngo Molnar out_failure: 22886470930SIngo Molnar return -1; 22986470930SIngo Molnar } 23086470930SIngo Molnar 23180d496beSPekka Enberg static int dso__load_perf_map(struct dso *self, symbol_filter_t filter, int verbose) 23280d496beSPekka Enberg { 23380d496beSPekka Enberg char *line = NULL; 23480d496beSPekka Enberg size_t n; 23580d496beSPekka Enberg FILE *file; 23680d496beSPekka Enberg int nr_syms = 0; 23780d496beSPekka Enberg 23880d496beSPekka Enberg file = fopen(self->name, "r"); 23980d496beSPekka Enberg if (file == NULL) 24080d496beSPekka Enberg goto out_failure; 24180d496beSPekka Enberg 24280d496beSPekka Enberg while (!feof(file)) { 2439cffa8d5SPaul Mackerras u64 start, size; 24480d496beSPekka Enberg struct symbol *sym; 24580d496beSPekka Enberg int line_len, len; 24680d496beSPekka Enberg 24780d496beSPekka Enberg line_len = getline(&line, &n, file); 24880d496beSPekka Enberg if (line_len < 0) 24980d496beSPekka Enberg break; 25080d496beSPekka Enberg 25180d496beSPekka Enberg if (!line) 25280d496beSPekka Enberg goto out_failure; 25380d496beSPekka Enberg 25480d496beSPekka Enberg line[--line_len] = '\0'; /* \n */ 25580d496beSPekka Enberg 25680d496beSPekka Enberg len = hex2u64(line, &start); 25780d496beSPekka Enberg 25880d496beSPekka Enberg len++; 25980d496beSPekka Enberg if (len + 2 >= line_len) 26080d496beSPekka Enberg continue; 26180d496beSPekka Enberg 26280d496beSPekka Enberg len += hex2u64(line + len, &size); 26380d496beSPekka Enberg 26480d496beSPekka Enberg len++; 26580d496beSPekka Enberg if (len + 2 >= line_len) 26680d496beSPekka Enberg continue; 26780d496beSPekka Enberg 26880d496beSPekka Enberg sym = symbol__new(start, size, line + len, 26980d496beSPekka Enberg self->sym_priv_size, start, verbose); 27080d496beSPekka Enberg 27180d496beSPekka Enberg if (sym == NULL) 27280d496beSPekka Enberg goto out_delete_line; 27380d496beSPekka Enberg 27480d496beSPekka Enberg if (filter && filter(self, sym)) 27580d496beSPekka Enberg symbol__delete(sym, self->sym_priv_size); 27680d496beSPekka Enberg else { 27780d496beSPekka Enberg dso__insert_symbol(self, sym); 27880d496beSPekka Enberg nr_syms++; 27980d496beSPekka Enberg } 28080d496beSPekka Enberg } 28180d496beSPekka Enberg 28280d496beSPekka Enberg free(line); 28380d496beSPekka Enberg fclose(file); 28480d496beSPekka Enberg 28580d496beSPekka Enberg return nr_syms; 28680d496beSPekka Enberg 28780d496beSPekka Enberg out_delete_line: 28880d496beSPekka Enberg free(line); 28980d496beSPekka Enberg out_failure: 29080d496beSPekka Enberg return -1; 29180d496beSPekka Enberg } 29280d496beSPekka Enberg 29386470930SIngo Molnar /** 29486470930SIngo Molnar * elf_symtab__for_each_symbol - iterate thru all the symbols 29586470930SIngo Molnar * 29686470930SIngo Molnar * @self: struct elf_symtab instance to iterate 29786470930SIngo Molnar * @index: uint32_t index 29886470930SIngo Molnar * @sym: GElf_Sym iterator 29986470930SIngo Molnar */ 30086470930SIngo Molnar #define elf_symtab__for_each_symbol(syms, nr_syms, index, sym) \ 30186470930SIngo Molnar for (index = 0, gelf_getsym(syms, index, &sym);\ 30286470930SIngo Molnar index < nr_syms; \ 30386470930SIngo Molnar index++, gelf_getsym(syms, index, &sym)) 30486470930SIngo Molnar 30586470930SIngo Molnar static inline uint8_t elf_sym__type(const GElf_Sym *sym) 30686470930SIngo Molnar { 30786470930SIngo Molnar return GELF_ST_TYPE(sym->st_info); 30886470930SIngo Molnar } 30986470930SIngo Molnar 31086470930SIngo Molnar static inline int elf_sym__is_function(const GElf_Sym *sym) 31186470930SIngo Molnar { 31286470930SIngo Molnar return elf_sym__type(sym) == STT_FUNC && 31386470930SIngo Molnar sym->st_name != 0 && 31486470930SIngo Molnar sym->st_shndx != SHN_UNDEF && 31586470930SIngo Molnar sym->st_size != 0; 31686470930SIngo Molnar } 31786470930SIngo Molnar 3186cfcc53eSMike Galbraith static inline int elf_sym__is_label(const GElf_Sym *sym) 3196cfcc53eSMike Galbraith { 3206cfcc53eSMike Galbraith return elf_sym__type(sym) == STT_NOTYPE && 3216cfcc53eSMike Galbraith sym->st_name != 0 && 3226cfcc53eSMike Galbraith sym->st_shndx != SHN_UNDEF && 3236cfcc53eSMike Galbraith sym->st_shndx != SHN_ABS; 3246cfcc53eSMike Galbraith } 3256cfcc53eSMike Galbraith 3266cfcc53eSMike Galbraith static inline const char *elf_sec__name(const GElf_Shdr *shdr, 3276cfcc53eSMike Galbraith const Elf_Data *secstrs) 3286cfcc53eSMike Galbraith { 3296cfcc53eSMike Galbraith return secstrs->d_buf + shdr->sh_name; 3306cfcc53eSMike Galbraith } 3316cfcc53eSMike Galbraith 3326cfcc53eSMike Galbraith static inline int elf_sec__is_text(const GElf_Shdr *shdr, 3336cfcc53eSMike Galbraith const Elf_Data *secstrs) 3346cfcc53eSMike Galbraith { 3356cfcc53eSMike Galbraith return strstr(elf_sec__name(shdr, secstrs), "text") != NULL; 3366cfcc53eSMike Galbraith } 3376cfcc53eSMike Galbraith 33886470930SIngo Molnar static inline const char *elf_sym__name(const GElf_Sym *sym, 33986470930SIngo Molnar const Elf_Data *symstrs) 34086470930SIngo Molnar { 34186470930SIngo Molnar return symstrs->d_buf + sym->st_name; 34286470930SIngo Molnar } 34386470930SIngo Molnar 34486470930SIngo Molnar static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, 34586470930SIngo Molnar GElf_Shdr *shp, const char *name, 34686470930SIngo Molnar size_t *index) 34786470930SIngo Molnar { 34886470930SIngo Molnar Elf_Scn *sec = NULL; 34986470930SIngo Molnar size_t cnt = 1; 35086470930SIngo Molnar 35186470930SIngo Molnar while ((sec = elf_nextscn(elf, sec)) != NULL) { 35286470930SIngo Molnar char *str; 35386470930SIngo Molnar 35486470930SIngo Molnar gelf_getshdr(sec, shp); 35586470930SIngo Molnar str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name); 35686470930SIngo Molnar if (!strcmp(name, str)) { 35786470930SIngo Molnar if (index) 35886470930SIngo Molnar *index = cnt; 35986470930SIngo Molnar break; 36086470930SIngo Molnar } 36186470930SIngo Molnar ++cnt; 36286470930SIngo Molnar } 36386470930SIngo Molnar 36486470930SIngo Molnar return sec; 36586470930SIngo Molnar } 36686470930SIngo Molnar 36786470930SIngo Molnar #define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \ 36886470930SIngo Molnar for (idx = 0, pos = gelf_getrel(reldata, 0, &pos_mem); \ 36986470930SIngo Molnar idx < nr_entries; \ 37086470930SIngo Molnar ++idx, pos = gelf_getrel(reldata, idx, &pos_mem)) 37186470930SIngo Molnar 37286470930SIngo Molnar #define elf_section__for_each_rela(reldata, pos, pos_mem, idx, nr_entries) \ 37386470930SIngo Molnar for (idx = 0, pos = gelf_getrela(reldata, 0, &pos_mem); \ 37486470930SIngo Molnar idx < nr_entries; \ 37586470930SIngo Molnar ++idx, pos = gelf_getrela(reldata, idx, &pos_mem)) 37686470930SIngo Molnar 37786470930SIngo Molnar static int dso__synthesize_plt_symbols(struct dso *self, Elf *elf, 37886470930SIngo Molnar GElf_Ehdr *ehdr, Elf_Scn *scn_dynsym, 37986470930SIngo Molnar GElf_Shdr *shdr_dynsym, 38086470930SIngo Molnar size_t dynsym_idx, int verbose) 38186470930SIngo Molnar { 38286470930SIngo Molnar uint32_t nr_rel_entries, idx; 38386470930SIngo Molnar GElf_Sym sym; 3849cffa8d5SPaul Mackerras u64 plt_offset; 38586470930SIngo Molnar GElf_Shdr shdr_plt; 38686470930SIngo Molnar struct symbol *f; 38786470930SIngo Molnar GElf_Shdr shdr_rel_plt; 38886470930SIngo Molnar Elf_Data *reldata, *syms, *symstrs; 38986470930SIngo Molnar Elf_Scn *scn_plt_rel, *scn_symstrs; 39086470930SIngo Molnar char sympltname[1024]; 39186470930SIngo Molnar int nr = 0, symidx; 39286470930SIngo Molnar 39386470930SIngo Molnar scn_plt_rel = elf_section_by_name(elf, ehdr, &shdr_rel_plt, 39486470930SIngo Molnar ".rela.plt", NULL); 39586470930SIngo Molnar if (scn_plt_rel == NULL) { 39686470930SIngo Molnar scn_plt_rel = elf_section_by_name(elf, ehdr, &shdr_rel_plt, 39786470930SIngo Molnar ".rel.plt", NULL); 39886470930SIngo Molnar if (scn_plt_rel == NULL) 39986470930SIngo Molnar return 0; 40086470930SIngo Molnar } 40186470930SIngo Molnar 40286470930SIngo Molnar if (shdr_rel_plt.sh_link != dynsym_idx) 40386470930SIngo Molnar return 0; 40486470930SIngo Molnar 40586470930SIngo Molnar if (elf_section_by_name(elf, ehdr, &shdr_plt, ".plt", NULL) == NULL) 40686470930SIngo Molnar return 0; 40786470930SIngo Molnar 40886470930SIngo Molnar /* 40986470930SIngo Molnar * Fetch the relocation section to find the indexes to the GOT 41086470930SIngo Molnar * and the symbols in the .dynsym they refer to. 41186470930SIngo Molnar */ 41286470930SIngo Molnar reldata = elf_getdata(scn_plt_rel, NULL); 41386470930SIngo Molnar if (reldata == NULL) 41486470930SIngo Molnar return -1; 41586470930SIngo Molnar 41686470930SIngo Molnar syms = elf_getdata(scn_dynsym, NULL); 41786470930SIngo Molnar if (syms == NULL) 41886470930SIngo Molnar return -1; 41986470930SIngo Molnar 42086470930SIngo Molnar scn_symstrs = elf_getscn(elf, shdr_dynsym->sh_link); 42186470930SIngo Molnar if (scn_symstrs == NULL) 42286470930SIngo Molnar return -1; 42386470930SIngo Molnar 42486470930SIngo Molnar symstrs = elf_getdata(scn_symstrs, NULL); 42586470930SIngo Molnar if (symstrs == NULL) 42686470930SIngo Molnar return -1; 42786470930SIngo Molnar 42886470930SIngo Molnar nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize; 42986470930SIngo Molnar plt_offset = shdr_plt.sh_offset; 43086470930SIngo Molnar 43186470930SIngo Molnar if (shdr_rel_plt.sh_type == SHT_RELA) { 43286470930SIngo Molnar GElf_Rela pos_mem, *pos; 43386470930SIngo Molnar 43486470930SIngo Molnar elf_section__for_each_rela(reldata, pos, pos_mem, idx, 43586470930SIngo Molnar nr_rel_entries) { 43686470930SIngo Molnar symidx = GELF_R_SYM(pos->r_info); 43786470930SIngo Molnar plt_offset += shdr_plt.sh_entsize; 43886470930SIngo Molnar gelf_getsym(syms, symidx, &sym); 43986470930SIngo Molnar snprintf(sympltname, sizeof(sympltname), 44086470930SIngo Molnar "%s@plt", elf_sym__name(&sym, symstrs)); 44186470930SIngo Molnar 44286470930SIngo Molnar f = symbol__new(plt_offset, shdr_plt.sh_entsize, 44386470930SIngo Molnar sympltname, self->sym_priv_size, 0, verbose); 44486470930SIngo Molnar if (!f) 44586470930SIngo Molnar return -1; 44686470930SIngo Molnar 44786470930SIngo Molnar dso__insert_symbol(self, f); 44886470930SIngo Molnar ++nr; 44986470930SIngo Molnar } 45086470930SIngo Molnar } else if (shdr_rel_plt.sh_type == SHT_REL) { 45186470930SIngo Molnar GElf_Rel pos_mem, *pos; 45286470930SIngo Molnar elf_section__for_each_rel(reldata, pos, pos_mem, idx, 45386470930SIngo Molnar nr_rel_entries) { 45486470930SIngo Molnar symidx = GELF_R_SYM(pos->r_info); 45586470930SIngo Molnar plt_offset += shdr_plt.sh_entsize; 45686470930SIngo Molnar gelf_getsym(syms, symidx, &sym); 45786470930SIngo Molnar snprintf(sympltname, sizeof(sympltname), 45886470930SIngo Molnar "%s@plt", elf_sym__name(&sym, symstrs)); 45986470930SIngo Molnar 46086470930SIngo Molnar f = symbol__new(plt_offset, shdr_plt.sh_entsize, 46186470930SIngo Molnar sympltname, self->sym_priv_size, 0, verbose); 46286470930SIngo Molnar if (!f) 46386470930SIngo Molnar return -1; 46486470930SIngo Molnar 46586470930SIngo Molnar dso__insert_symbol(self, f); 46686470930SIngo Molnar ++nr; 46786470930SIngo Molnar } 46886470930SIngo Molnar } else { 46986470930SIngo Molnar /* 47086470930SIngo Molnar * TODO: There are still one more shdr_rel_plt.sh_type 47186470930SIngo Molnar * I have to investigate, but probably should be ignored. 47286470930SIngo Molnar */ 47386470930SIngo Molnar } 47486470930SIngo Molnar 47586470930SIngo Molnar return nr; 47686470930SIngo Molnar } 47786470930SIngo Molnar 47886470930SIngo Molnar static int dso__load_sym(struct dso *self, int fd, const char *name, 4796cfcc53eSMike Galbraith symbol_filter_t filter, int verbose, struct module *mod) 48086470930SIngo Molnar { 4816cfcc53eSMike Galbraith Elf_Data *symstrs, *secstrs; 48286470930SIngo Molnar uint32_t nr_syms; 48386470930SIngo Molnar int err = -1; 48486470930SIngo Molnar uint32_t index; 48586470930SIngo Molnar GElf_Ehdr ehdr; 48686470930SIngo Molnar GElf_Shdr shdr; 48786470930SIngo Molnar Elf_Data *syms; 48886470930SIngo Molnar GElf_Sym sym; 4896cfcc53eSMike Galbraith Elf_Scn *sec, *sec_dynsym, *sec_strndx; 49086470930SIngo Molnar Elf *elf; 49186470930SIngo Molnar size_t dynsym_idx; 49286470930SIngo Molnar int nr = 0; 49386470930SIngo Molnar 49486470930SIngo Molnar elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); 49586470930SIngo Molnar if (elf == NULL) { 49686470930SIngo Molnar if (verbose) 49786470930SIngo Molnar fprintf(stderr, "%s: cannot read %s ELF file.\n", 49886470930SIngo Molnar __func__, name); 49986470930SIngo Molnar goto out_close; 50086470930SIngo Molnar } 50186470930SIngo Molnar 50286470930SIngo Molnar if (gelf_getehdr(elf, &ehdr) == NULL) { 50386470930SIngo Molnar if (verbose) 50486470930SIngo Molnar fprintf(stderr, "%s: cannot get elf header.\n", __func__); 50586470930SIngo Molnar goto out_elf_end; 50686470930SIngo Molnar } 50786470930SIngo Molnar 50886470930SIngo Molnar /* 50986470930SIngo Molnar * We need to check if we have a .dynsym, so that we can handle the 51086470930SIngo Molnar * .plt, synthesizing its symbols, that aren't on the symtabs (be it 51186470930SIngo Molnar * .dynsym or .symtab) 51286470930SIngo Molnar */ 51386470930SIngo Molnar sec_dynsym = elf_section_by_name(elf, &ehdr, &shdr, 51486470930SIngo Molnar ".dynsym", &dynsym_idx); 51586470930SIngo Molnar if (sec_dynsym != NULL) { 51686470930SIngo Molnar nr = dso__synthesize_plt_symbols(self, elf, &ehdr, 51786470930SIngo Molnar sec_dynsym, &shdr, 51886470930SIngo Molnar dynsym_idx, verbose); 51986470930SIngo Molnar if (nr < 0) 52086470930SIngo Molnar goto out_elf_end; 52186470930SIngo Molnar } 52286470930SIngo Molnar 52386470930SIngo Molnar /* 52486470930SIngo Molnar * But if we have a full .symtab (that is a superset of .dynsym) we 52586470930SIngo Molnar * should add the symbols not in the .dynsyn 52686470930SIngo Molnar */ 52786470930SIngo Molnar sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL); 52886470930SIngo Molnar if (sec == NULL) { 52986470930SIngo Molnar if (sec_dynsym == NULL) 53086470930SIngo Molnar goto out_elf_end; 53186470930SIngo Molnar 53286470930SIngo Molnar sec = sec_dynsym; 53386470930SIngo Molnar gelf_getshdr(sec, &shdr); 53486470930SIngo Molnar } 53586470930SIngo Molnar 53686470930SIngo Molnar syms = elf_getdata(sec, NULL); 53786470930SIngo Molnar if (syms == NULL) 53886470930SIngo Molnar goto out_elf_end; 53986470930SIngo Molnar 54086470930SIngo Molnar sec = elf_getscn(elf, shdr.sh_link); 54186470930SIngo Molnar if (sec == NULL) 54286470930SIngo Molnar goto out_elf_end; 54386470930SIngo Molnar 54486470930SIngo Molnar symstrs = elf_getdata(sec, NULL); 54586470930SIngo Molnar if (symstrs == NULL) 54686470930SIngo Molnar goto out_elf_end; 54786470930SIngo Molnar 5486cfcc53eSMike Galbraith sec_strndx = elf_getscn(elf, ehdr.e_shstrndx); 5496cfcc53eSMike Galbraith if (sec_strndx == NULL) 5506cfcc53eSMike Galbraith goto out_elf_end; 5516cfcc53eSMike Galbraith 5526cfcc53eSMike Galbraith secstrs = elf_getdata(sec_strndx, NULL); 5536cfcc53eSMike Galbraith if (symstrs == NULL) 5546cfcc53eSMike Galbraith goto out_elf_end; 5556cfcc53eSMike Galbraith 55686470930SIngo Molnar nr_syms = shdr.sh_size / shdr.sh_entsize; 55786470930SIngo Molnar 558e9fbc9dcSArjan van de Ven memset(&sym, 0, sizeof(sym)); 55930d7a77dSArnaldo Carvalho de Melo self->adjust_symbols = (ehdr.e_type == ET_EXEC || 56030d7a77dSArnaldo Carvalho de Melo elf_section_by_name(elf, &ehdr, &shdr, 561f5812a7aSArnaldo Carvalho de Melo ".gnu.prelink_undo", 56230d7a77dSArnaldo Carvalho de Melo NULL) != NULL); 56386470930SIngo Molnar elf_symtab__for_each_symbol(syms, nr_syms, index, sym) { 56486470930SIngo Molnar struct symbol *f; 5659cffa8d5SPaul Mackerras u64 obj_start; 5666cfcc53eSMike Galbraith struct section *section = NULL; 5676cfcc53eSMike Galbraith int is_label = elf_sym__is_label(&sym); 5686cfcc53eSMike Galbraith const char *section_name; 56986470930SIngo Molnar 5706cfcc53eSMike Galbraith if (!is_label && !elf_sym__is_function(&sym)) 57186470930SIngo Molnar continue; 57286470930SIngo Molnar 57386470930SIngo Molnar sec = elf_getscn(elf, sym.st_shndx); 57486470930SIngo Molnar if (!sec) 57586470930SIngo Molnar goto out_elf_end; 57686470930SIngo Molnar 57786470930SIngo Molnar gelf_getshdr(sec, &shdr); 5786cfcc53eSMike Galbraith 5796cfcc53eSMike Galbraith if (is_label && !elf_sec__is_text(&shdr, secstrs)) 5806cfcc53eSMike Galbraith continue; 5816cfcc53eSMike Galbraith 5826cfcc53eSMike Galbraith section_name = elf_sec__name(&shdr, secstrs); 58386470930SIngo Molnar obj_start = sym.st_value; 58486470930SIngo Molnar 58530d7a77dSArnaldo Carvalho de Melo if (self->adjust_symbols) { 586520f2c34SPeter Zijlstra if (verbose >= 2) 587520f2c34SPeter Zijlstra printf("adjusting symbol: st_value: %Lx sh_addr: %Lx sh_offset: %Lx\n", 588520f2c34SPeter Zijlstra (u64)sym.st_value, (u64)shdr.sh_addr, (u64)shdr.sh_offset); 589520f2c34SPeter Zijlstra 59086470930SIngo Molnar sym.st_value -= shdr.sh_addr - shdr.sh_offset; 591f5812a7aSArnaldo Carvalho de Melo } 59286470930SIngo Molnar 5936cfcc53eSMike Galbraith if (mod) { 5946cfcc53eSMike Galbraith section = mod->sections->find_section(mod->sections, section_name); 5956cfcc53eSMike Galbraith if (section) 5966cfcc53eSMike Galbraith sym.st_value += section->vma; 5976cfcc53eSMike Galbraith else { 5986cfcc53eSMike Galbraith fprintf(stderr, "dso__load_sym() module %s lookup of %s failed\n", 5996cfcc53eSMike Galbraith mod->name, section_name); 6006cfcc53eSMike Galbraith goto out_elf_end; 6016cfcc53eSMike Galbraith } 6026cfcc53eSMike Galbraith } 6036cfcc53eSMike Galbraith 60486470930SIngo Molnar f = symbol__new(sym.st_value, sym.st_size, 60586470930SIngo Molnar elf_sym__name(&sym, symstrs), 60686470930SIngo Molnar self->sym_priv_size, obj_start, verbose); 60786470930SIngo Molnar if (!f) 60886470930SIngo Molnar goto out_elf_end; 60986470930SIngo Molnar 61086470930SIngo Molnar if (filter && filter(self, f)) 61186470930SIngo Molnar symbol__delete(f, self->sym_priv_size); 61286470930SIngo Molnar else { 6136cfcc53eSMike Galbraith f->module = mod; 61486470930SIngo Molnar dso__insert_symbol(self, f); 61586470930SIngo Molnar nr++; 61686470930SIngo Molnar } 61786470930SIngo Molnar } 61886470930SIngo Molnar 61986470930SIngo Molnar err = nr; 62086470930SIngo Molnar out_elf_end: 62186470930SIngo Molnar elf_end(elf); 62286470930SIngo Molnar out_close: 62386470930SIngo Molnar return err; 62486470930SIngo Molnar } 62586470930SIngo Molnar 62686470930SIngo Molnar int dso__load(struct dso *self, symbol_filter_t filter, int verbose) 62786470930SIngo Molnar { 62886470930SIngo Molnar int size = strlen(self->name) + sizeof("/usr/lib/debug%s.debug"); 62986470930SIngo Molnar char *name = malloc(size); 63086470930SIngo Molnar int variant = 0; 63186470930SIngo Molnar int ret = -1; 63286470930SIngo Molnar int fd; 63386470930SIngo Molnar 63486470930SIngo Molnar if (!name) 63586470930SIngo Molnar return -1; 63686470930SIngo Molnar 63730d7a77dSArnaldo Carvalho de Melo self->adjust_symbols = 0; 638f5812a7aSArnaldo Carvalho de Melo 63980d496beSPekka Enberg if (strncmp(self->name, "/tmp/perf-", 10) == 0) 64080d496beSPekka Enberg return dso__load_perf_map(self, filter, verbose); 64180d496beSPekka Enberg 64286470930SIngo Molnar more: 64386470930SIngo Molnar do { 64486470930SIngo Molnar switch (variant) { 64586470930SIngo Molnar case 0: /* Fedora */ 64686470930SIngo Molnar snprintf(name, size, "/usr/lib/debug%s.debug", self->name); 64786470930SIngo Molnar break; 64886470930SIngo Molnar case 1: /* Ubuntu */ 64986470930SIngo Molnar snprintf(name, size, "/usr/lib/debug%s", self->name); 65086470930SIngo Molnar break; 65186470930SIngo Molnar case 2: /* Sane people */ 65286470930SIngo Molnar snprintf(name, size, "%s", self->name); 65386470930SIngo Molnar break; 65486470930SIngo Molnar 65586470930SIngo Molnar default: 65686470930SIngo Molnar goto out; 65786470930SIngo Molnar } 65886470930SIngo Molnar variant++; 65986470930SIngo Molnar 66086470930SIngo Molnar fd = open(name, O_RDONLY); 66186470930SIngo Molnar } while (fd < 0); 66286470930SIngo Molnar 6636cfcc53eSMike Galbraith ret = dso__load_sym(self, fd, name, filter, verbose, NULL); 66486470930SIngo Molnar close(fd); 66586470930SIngo Molnar 66686470930SIngo Molnar /* 66786470930SIngo Molnar * Some people seem to have debuginfo files _WITHOUT_ debug info!?!? 66886470930SIngo Molnar */ 66986470930SIngo Molnar if (!ret) 67086470930SIngo Molnar goto more; 67186470930SIngo Molnar 67286470930SIngo Molnar out: 67386470930SIngo Molnar free(name); 67486470930SIngo Molnar return ret; 67586470930SIngo Molnar } 67686470930SIngo Molnar 6776cfcc53eSMike Galbraith static int dso__load_module(struct dso *self, struct mod_dso *mods, const char *name, 6786cfcc53eSMike Galbraith symbol_filter_t filter, int verbose) 6796cfcc53eSMike Galbraith { 6806cfcc53eSMike Galbraith struct module *mod = mod_dso__find_module(mods, name); 6816cfcc53eSMike Galbraith int err = 0, fd; 6826cfcc53eSMike Galbraith 6836cfcc53eSMike Galbraith if (mod == NULL || !mod->active) 6846cfcc53eSMike Galbraith return err; 6856cfcc53eSMike Galbraith 6866cfcc53eSMike Galbraith fd = open(mod->path, O_RDONLY); 6876cfcc53eSMike Galbraith 6886cfcc53eSMike Galbraith if (fd < 0) 6896cfcc53eSMike Galbraith return err; 6906cfcc53eSMike Galbraith 6916cfcc53eSMike Galbraith err = dso__load_sym(self, fd, name, filter, verbose, mod); 6926cfcc53eSMike Galbraith close(fd); 6936cfcc53eSMike Galbraith 6946cfcc53eSMike Galbraith return err; 6956cfcc53eSMike Galbraith } 6966cfcc53eSMike Galbraith 6976cfcc53eSMike Galbraith int dso__load_modules(struct dso *self, symbol_filter_t filter, int verbose) 6986cfcc53eSMike Galbraith { 6996cfcc53eSMike Galbraith struct mod_dso *mods = mod_dso__new_dso("modules"); 7006cfcc53eSMike Galbraith struct module *pos; 7016cfcc53eSMike Galbraith struct rb_node *next; 7026cfcc53eSMike Galbraith int err; 7036cfcc53eSMike Galbraith 7046cfcc53eSMike Galbraith err = mod_dso__load_modules(mods); 7056cfcc53eSMike Galbraith 7066cfcc53eSMike Galbraith if (err <= 0) 7076cfcc53eSMike Galbraith return err; 7086cfcc53eSMike Galbraith 7096cfcc53eSMike Galbraith /* 7106cfcc53eSMike Galbraith * Iterate over modules, and load active symbols. 7116cfcc53eSMike Galbraith */ 7126cfcc53eSMike Galbraith next = rb_first(&mods->mods); 7136cfcc53eSMike Galbraith while (next) { 7146cfcc53eSMike Galbraith pos = rb_entry(next, struct module, rb_node); 7156cfcc53eSMike Galbraith err = dso__load_module(self, mods, pos->name, filter, verbose); 7166cfcc53eSMike Galbraith 7176cfcc53eSMike Galbraith if (err < 0) 7186cfcc53eSMike Galbraith break; 7196cfcc53eSMike Galbraith 7206cfcc53eSMike Galbraith next = rb_next(&pos->rb_node); 7216cfcc53eSMike Galbraith } 7226cfcc53eSMike Galbraith 7236cfcc53eSMike Galbraith if (err < 0) { 7246cfcc53eSMike Galbraith mod_dso__delete_modules(mods); 7256cfcc53eSMike Galbraith mod_dso__delete_self(mods); 7266cfcc53eSMike Galbraith } 7276cfcc53eSMike Galbraith 7286cfcc53eSMike Galbraith return err; 7296cfcc53eSMike Galbraith } 7306cfcc53eSMike Galbraith 7316cfcc53eSMike Galbraith static inline void dso__fill_symbol_holes(struct dso *self) 7326cfcc53eSMike Galbraith { 7336cfcc53eSMike Galbraith struct symbol *prev = NULL; 7346cfcc53eSMike Galbraith struct rb_node *nd; 7356cfcc53eSMike Galbraith 7366cfcc53eSMike Galbraith for (nd = rb_last(&self->syms); nd; nd = rb_prev(nd)) { 7376cfcc53eSMike Galbraith struct symbol *pos = rb_entry(nd, struct symbol, rb_node); 7386cfcc53eSMike Galbraith 7396cfcc53eSMike Galbraith if (prev) { 7406cfcc53eSMike Galbraith u64 hole = 0; 7416cfcc53eSMike Galbraith int alias = pos->start == prev->start; 7426cfcc53eSMike Galbraith 7436cfcc53eSMike Galbraith if (!alias) 7446cfcc53eSMike Galbraith hole = prev->start - pos->end - 1; 7456cfcc53eSMike Galbraith 7466cfcc53eSMike Galbraith if (hole || alias) { 7476cfcc53eSMike Galbraith if (alias) 7486cfcc53eSMike Galbraith pos->end = prev->end; 7496cfcc53eSMike Galbraith else if (hole) 7506cfcc53eSMike Galbraith pos->end = prev->start - 1; 7516cfcc53eSMike Galbraith } 7526cfcc53eSMike Galbraith } 7536cfcc53eSMike Galbraith prev = pos; 7546cfcc53eSMike Galbraith } 7556cfcc53eSMike Galbraith } 7566cfcc53eSMike Galbraith 75786470930SIngo Molnar static int dso__load_vmlinux(struct dso *self, const char *vmlinux, 75886470930SIngo Molnar symbol_filter_t filter, int verbose) 75986470930SIngo Molnar { 76086470930SIngo Molnar int err, fd = open(vmlinux, O_RDONLY); 76186470930SIngo Molnar 76286470930SIngo Molnar if (fd < 0) 76386470930SIngo Molnar return -1; 76486470930SIngo Molnar 7656cfcc53eSMike Galbraith err = dso__load_sym(self, fd, vmlinux, filter, verbose, NULL); 7666cfcc53eSMike Galbraith 7676cfcc53eSMike Galbraith if (err > 0) 7686cfcc53eSMike Galbraith dso__fill_symbol_holes(self); 7696cfcc53eSMike Galbraith 77086470930SIngo Molnar close(fd); 77186470930SIngo Molnar 77286470930SIngo Molnar return err; 77386470930SIngo Molnar } 77486470930SIngo Molnar 77586470930SIngo Molnar int dso__load_kernel(struct dso *self, const char *vmlinux, 7766cfcc53eSMike Galbraith symbol_filter_t filter, int verbose, int modules) 77786470930SIngo Molnar { 77886470930SIngo Molnar int err = -1; 77986470930SIngo Molnar 7806cfcc53eSMike Galbraith if (vmlinux) { 78186470930SIngo Molnar err = dso__load_vmlinux(self, vmlinux, filter, verbose); 7826cfcc53eSMike Galbraith if (err > 0 && modules) 7836cfcc53eSMike Galbraith err = dso__load_modules(self, filter, verbose); 7846cfcc53eSMike Galbraith } 78586470930SIngo Molnar 7869974f496SMike Galbraith if (err <= 0) 78786470930SIngo Molnar err = dso__load_kallsyms(self, filter, verbose); 78886470930SIngo Molnar 78986470930SIngo Molnar return err; 79086470930SIngo Molnar } 79186470930SIngo Molnar 79286470930SIngo Molnar void symbol__init(void) 79386470930SIngo Molnar { 79486470930SIngo Molnar elf_version(EV_CURRENT); 79586470930SIngo Molnar } 796