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> 928ac909bSArnaldo Carvalho de Melo #include <bfd.h> 1086470930SIngo Molnar 1186470930SIngo Molnar const char *sym_hist_filter; 1286470930SIngo Molnar 1328ac909bSArnaldo Carvalho de Melo #ifndef DMGL_PARAMS 1428ac909bSArnaldo Carvalho de Melo #define DMGL_PARAMS (1 << 0) /* Include function args */ 1528ac909bSArnaldo Carvalho de Melo #define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */ 1628ac909bSArnaldo Carvalho de Melo #endif 1728ac909bSArnaldo Carvalho de Melo 189cffa8d5SPaul Mackerras static struct symbol *symbol__new(u64 start, u64 len, 1986470930SIngo Molnar const char *name, unsigned int priv_size, 209cffa8d5SPaul Mackerras u64 obj_start, int verbose) 2186470930SIngo Molnar { 2286470930SIngo Molnar size_t namelen = strlen(name) + 1; 2386470930SIngo Molnar struct symbol *self = calloc(1, priv_size + sizeof(*self) + namelen); 2486470930SIngo Molnar 2586470930SIngo Molnar if (!self) 2686470930SIngo Molnar return NULL; 2786470930SIngo Molnar 2886470930SIngo Molnar if (verbose >= 2) 2986470930SIngo Molnar printf("new symbol: %016Lx [%08lx]: %s, hist: %p, obj_start: %p\n", 309cffa8d5SPaul Mackerras (u64)start, (unsigned long)len, name, self->hist, (void *)(unsigned long)obj_start); 3186470930SIngo Molnar 3286470930SIngo Molnar self->obj_start= obj_start; 3386470930SIngo Molnar self->hist = NULL; 3486470930SIngo Molnar self->hist_sum = 0; 3586470930SIngo Molnar 3686470930SIngo Molnar if (sym_hist_filter && !strcmp(name, sym_hist_filter)) 379cffa8d5SPaul Mackerras self->hist = calloc(sizeof(u64), len); 3886470930SIngo Molnar 3986470930SIngo Molnar if (priv_size) { 4086470930SIngo Molnar memset(self, 0, priv_size); 4186470930SIngo Molnar self = ((void *)self) + priv_size; 4286470930SIngo Molnar } 4386470930SIngo Molnar self->start = start; 446cfcc53eSMike Galbraith self->end = len ? start + len - 1 : start; 4586470930SIngo Molnar memcpy(self->name, name, namelen); 4686470930SIngo Molnar 4786470930SIngo Molnar return self; 4886470930SIngo Molnar } 4986470930SIngo Molnar 5086470930SIngo Molnar static void symbol__delete(struct symbol *self, unsigned int priv_size) 5186470930SIngo Molnar { 5286470930SIngo Molnar free(((void *)self) - priv_size); 5386470930SIngo Molnar } 5486470930SIngo Molnar 5586470930SIngo Molnar static size_t symbol__fprintf(struct symbol *self, FILE *fp) 5686470930SIngo Molnar { 576cfcc53eSMike Galbraith if (!self->module) 5886470930SIngo Molnar return fprintf(fp, " %llx-%llx %s\n", 5986470930SIngo Molnar self->start, self->end, self->name); 606cfcc53eSMike Galbraith else 616cfcc53eSMike Galbraith return fprintf(fp, " %llx-%llx %s \t[%s]\n", 626cfcc53eSMike Galbraith self->start, self->end, self->name, self->module->name); 6386470930SIngo Molnar } 6486470930SIngo Molnar 6586470930SIngo Molnar struct dso *dso__new(const char *name, unsigned int sym_priv_size) 6686470930SIngo Molnar { 6786470930SIngo Molnar struct dso *self = malloc(sizeof(*self) + strlen(name) + 1); 6886470930SIngo Molnar 6986470930SIngo Molnar if (self != NULL) { 7086470930SIngo Molnar strcpy(self->name, name); 7186470930SIngo Molnar self->syms = RB_ROOT; 7286470930SIngo Molnar self->sym_priv_size = sym_priv_size; 7386470930SIngo Molnar self->find_symbol = dso__find_symbol; 7452d422deSArnaldo Carvalho de Melo self->slen_calculated = 0; 7586470930SIngo Molnar } 7686470930SIngo Molnar 7786470930SIngo Molnar return self; 7886470930SIngo Molnar } 7986470930SIngo Molnar 8086470930SIngo Molnar static void dso__delete_symbols(struct dso *self) 8186470930SIngo Molnar { 8286470930SIngo Molnar struct symbol *pos; 8386470930SIngo Molnar struct rb_node *next = rb_first(&self->syms); 8486470930SIngo Molnar 8586470930SIngo Molnar while (next) { 8686470930SIngo Molnar pos = rb_entry(next, struct symbol, rb_node); 8786470930SIngo Molnar next = rb_next(&pos->rb_node); 8886470930SIngo Molnar rb_erase(&pos->rb_node, &self->syms); 8986470930SIngo Molnar symbol__delete(pos, self->sym_priv_size); 9086470930SIngo Molnar } 9186470930SIngo Molnar } 9286470930SIngo Molnar 9386470930SIngo Molnar void dso__delete(struct dso *self) 9486470930SIngo Molnar { 9586470930SIngo Molnar dso__delete_symbols(self); 9686470930SIngo Molnar free(self); 9786470930SIngo Molnar } 9886470930SIngo Molnar 9986470930SIngo Molnar static void dso__insert_symbol(struct dso *self, struct symbol *sym) 10086470930SIngo Molnar { 10186470930SIngo Molnar struct rb_node **p = &self->syms.rb_node; 10286470930SIngo Molnar struct rb_node *parent = NULL; 1039cffa8d5SPaul Mackerras const u64 ip = sym->start; 10486470930SIngo Molnar struct symbol *s; 10586470930SIngo Molnar 10686470930SIngo Molnar while (*p != NULL) { 10786470930SIngo Molnar parent = *p; 10886470930SIngo Molnar s = rb_entry(parent, struct symbol, rb_node); 10986470930SIngo Molnar if (ip < s->start) 11086470930SIngo Molnar p = &(*p)->rb_left; 11186470930SIngo Molnar else 11286470930SIngo Molnar p = &(*p)->rb_right; 11386470930SIngo Molnar } 11486470930SIngo Molnar rb_link_node(&sym->rb_node, parent, p); 11586470930SIngo Molnar rb_insert_color(&sym->rb_node, &self->syms); 11686470930SIngo Molnar } 11786470930SIngo Molnar 1189cffa8d5SPaul Mackerras struct symbol *dso__find_symbol(struct dso *self, u64 ip) 11986470930SIngo Molnar { 12086470930SIngo Molnar struct rb_node *n; 12186470930SIngo Molnar 12286470930SIngo Molnar if (self == NULL) 12386470930SIngo Molnar return NULL; 12486470930SIngo Molnar 12586470930SIngo Molnar n = self->syms.rb_node; 12686470930SIngo Molnar 12786470930SIngo Molnar while (n) { 12886470930SIngo Molnar struct symbol *s = rb_entry(n, struct symbol, rb_node); 12986470930SIngo Molnar 13086470930SIngo Molnar if (ip < s->start) 13186470930SIngo Molnar n = n->rb_left; 13286470930SIngo Molnar else if (ip > s->end) 13386470930SIngo Molnar n = n->rb_right; 13486470930SIngo Molnar else 13586470930SIngo Molnar return s; 13686470930SIngo Molnar } 13786470930SIngo Molnar 13886470930SIngo Molnar return NULL; 13986470930SIngo Molnar } 14086470930SIngo Molnar 14186470930SIngo Molnar size_t dso__fprintf(struct dso *self, FILE *fp) 14286470930SIngo Molnar { 14386470930SIngo Molnar size_t ret = fprintf(fp, "dso: %s\n", self->name); 14486470930SIngo Molnar 14586470930SIngo Molnar struct rb_node *nd; 14686470930SIngo Molnar for (nd = rb_first(&self->syms); nd; nd = rb_next(nd)) { 14786470930SIngo Molnar struct symbol *pos = rb_entry(nd, struct symbol, rb_node); 14886470930SIngo Molnar ret += symbol__fprintf(pos, fp); 14986470930SIngo Molnar } 15086470930SIngo Molnar 15186470930SIngo Molnar return ret; 15286470930SIngo Molnar } 15386470930SIngo Molnar 15486470930SIngo Molnar static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int verbose) 15586470930SIngo Molnar { 15686470930SIngo Molnar struct rb_node *nd, *prevnd; 15786470930SIngo Molnar char *line = NULL; 15886470930SIngo Molnar size_t n; 15986470930SIngo Molnar FILE *file = fopen("/proc/kallsyms", "r"); 1609974f496SMike Galbraith int count = 0; 16186470930SIngo Molnar 16286470930SIngo Molnar if (file == NULL) 16386470930SIngo Molnar goto out_failure; 16486470930SIngo Molnar 16586470930SIngo Molnar while (!feof(file)) { 1669cffa8d5SPaul Mackerras u64 start; 16786470930SIngo Molnar struct symbol *sym; 16886470930SIngo Molnar int line_len, len; 16986470930SIngo Molnar char symbol_type; 17086470930SIngo Molnar 17186470930SIngo Molnar line_len = getline(&line, &n, file); 17286470930SIngo Molnar if (line_len < 0) 17386470930SIngo Molnar break; 17486470930SIngo Molnar 17586470930SIngo Molnar if (!line) 17686470930SIngo Molnar goto out_failure; 17786470930SIngo Molnar 17886470930SIngo Molnar line[--line_len] = '\0'; /* \n */ 17986470930SIngo Molnar 18086470930SIngo Molnar len = hex2u64(line, &start); 18186470930SIngo Molnar 18286470930SIngo Molnar len++; 18386470930SIngo Molnar if (len + 2 >= line_len) 18486470930SIngo Molnar continue; 18586470930SIngo Molnar 18686470930SIngo Molnar symbol_type = toupper(line[len]); 18786470930SIngo Molnar /* 18886470930SIngo Molnar * We're interested only in code ('T'ext) 18986470930SIngo Molnar */ 19086470930SIngo Molnar if (symbol_type != 'T' && symbol_type != 'W') 19186470930SIngo Molnar continue; 19286470930SIngo Molnar /* 19386470930SIngo Molnar * Well fix up the end later, when we have all sorted. 19486470930SIngo Molnar */ 19586470930SIngo Molnar sym = symbol__new(start, 0xdead, line + len + 2, 19686470930SIngo Molnar self->sym_priv_size, 0, verbose); 19786470930SIngo Molnar 19886470930SIngo Molnar if (sym == NULL) 19986470930SIngo Molnar goto out_delete_line; 20086470930SIngo Molnar 20186470930SIngo Molnar if (filter && filter(self, sym)) 20286470930SIngo Molnar symbol__delete(sym, self->sym_priv_size); 2039974f496SMike Galbraith else { 20486470930SIngo Molnar dso__insert_symbol(self, sym); 2059974f496SMike Galbraith count++; 2069974f496SMike Galbraith } 20786470930SIngo Molnar } 20886470930SIngo Molnar 20986470930SIngo Molnar /* 21086470930SIngo Molnar * Now that we have all sorted out, just set the ->end of all 21186470930SIngo Molnar * symbols 21286470930SIngo Molnar */ 21386470930SIngo Molnar prevnd = rb_first(&self->syms); 21486470930SIngo Molnar 21586470930SIngo Molnar if (prevnd == NULL) 21686470930SIngo Molnar goto out_delete_line; 21786470930SIngo Molnar 21886470930SIngo Molnar for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) { 21986470930SIngo Molnar struct symbol *prev = rb_entry(prevnd, struct symbol, rb_node), 22086470930SIngo Molnar *curr = rb_entry(nd, struct symbol, rb_node); 22186470930SIngo Molnar 22286470930SIngo Molnar prev->end = curr->start - 1; 22386470930SIngo Molnar prevnd = nd; 22486470930SIngo Molnar } 22586470930SIngo Molnar 22686470930SIngo Molnar free(line); 22786470930SIngo Molnar fclose(file); 22886470930SIngo Molnar 2299974f496SMike Galbraith return count; 23086470930SIngo Molnar 23186470930SIngo Molnar out_delete_line: 23286470930SIngo Molnar free(line); 23386470930SIngo Molnar out_failure: 23486470930SIngo Molnar return -1; 23586470930SIngo Molnar } 23686470930SIngo Molnar 23780d496beSPekka Enberg static int dso__load_perf_map(struct dso *self, symbol_filter_t filter, int verbose) 23880d496beSPekka Enberg { 23980d496beSPekka Enberg char *line = NULL; 24080d496beSPekka Enberg size_t n; 24180d496beSPekka Enberg FILE *file; 24280d496beSPekka Enberg int nr_syms = 0; 24380d496beSPekka Enberg 24480d496beSPekka Enberg file = fopen(self->name, "r"); 24580d496beSPekka Enberg if (file == NULL) 24680d496beSPekka Enberg goto out_failure; 24780d496beSPekka Enberg 24880d496beSPekka Enberg while (!feof(file)) { 2499cffa8d5SPaul Mackerras u64 start, size; 25080d496beSPekka Enberg struct symbol *sym; 25180d496beSPekka Enberg int line_len, len; 25280d496beSPekka Enberg 25380d496beSPekka Enberg line_len = getline(&line, &n, file); 25480d496beSPekka Enberg if (line_len < 0) 25580d496beSPekka Enberg break; 25680d496beSPekka Enberg 25780d496beSPekka Enberg if (!line) 25880d496beSPekka Enberg goto out_failure; 25980d496beSPekka Enberg 26080d496beSPekka Enberg line[--line_len] = '\0'; /* \n */ 26180d496beSPekka Enberg 26280d496beSPekka Enberg len = hex2u64(line, &start); 26380d496beSPekka Enberg 26480d496beSPekka Enberg len++; 26580d496beSPekka Enberg if (len + 2 >= line_len) 26680d496beSPekka Enberg continue; 26780d496beSPekka Enberg 26880d496beSPekka Enberg len += hex2u64(line + len, &size); 26980d496beSPekka Enberg 27080d496beSPekka Enberg len++; 27180d496beSPekka Enberg if (len + 2 >= line_len) 27280d496beSPekka Enberg continue; 27380d496beSPekka Enberg 27480d496beSPekka Enberg sym = symbol__new(start, size, line + len, 27580d496beSPekka Enberg self->sym_priv_size, start, verbose); 27680d496beSPekka Enberg 27780d496beSPekka Enberg if (sym == NULL) 27880d496beSPekka Enberg goto out_delete_line; 27980d496beSPekka Enberg 28080d496beSPekka Enberg if (filter && filter(self, sym)) 28180d496beSPekka Enberg symbol__delete(sym, self->sym_priv_size); 28280d496beSPekka Enberg else { 28380d496beSPekka Enberg dso__insert_symbol(self, sym); 28480d496beSPekka Enberg nr_syms++; 28580d496beSPekka Enberg } 28680d496beSPekka Enberg } 28780d496beSPekka Enberg 28880d496beSPekka Enberg free(line); 28980d496beSPekka Enberg fclose(file); 29080d496beSPekka Enberg 29180d496beSPekka Enberg return nr_syms; 29280d496beSPekka Enberg 29380d496beSPekka Enberg out_delete_line: 29480d496beSPekka Enberg free(line); 29580d496beSPekka Enberg out_failure: 29680d496beSPekka Enberg return -1; 29780d496beSPekka Enberg } 29880d496beSPekka Enberg 29986470930SIngo Molnar /** 30086470930SIngo Molnar * elf_symtab__for_each_symbol - iterate thru all the symbols 30186470930SIngo Molnar * 30286470930SIngo Molnar * @self: struct elf_symtab instance to iterate 30386470930SIngo Molnar * @index: uint32_t index 30486470930SIngo Molnar * @sym: GElf_Sym iterator 30586470930SIngo Molnar */ 30686470930SIngo Molnar #define elf_symtab__for_each_symbol(syms, nr_syms, index, sym) \ 30786470930SIngo Molnar for (index = 0, gelf_getsym(syms, index, &sym);\ 30886470930SIngo Molnar index < nr_syms; \ 30986470930SIngo Molnar index++, gelf_getsym(syms, index, &sym)) 31086470930SIngo Molnar 31186470930SIngo Molnar static inline uint8_t elf_sym__type(const GElf_Sym *sym) 31286470930SIngo Molnar { 31386470930SIngo Molnar return GELF_ST_TYPE(sym->st_info); 31486470930SIngo Molnar } 31586470930SIngo Molnar 31686470930SIngo Molnar static inline int elf_sym__is_function(const GElf_Sym *sym) 31786470930SIngo Molnar { 31886470930SIngo Molnar return elf_sym__type(sym) == STT_FUNC && 31986470930SIngo Molnar sym->st_name != 0 && 32086470930SIngo Molnar sym->st_shndx != SHN_UNDEF && 32186470930SIngo Molnar sym->st_size != 0; 32286470930SIngo Molnar } 32386470930SIngo Molnar 3246cfcc53eSMike Galbraith static inline int elf_sym__is_label(const GElf_Sym *sym) 3256cfcc53eSMike Galbraith { 3266cfcc53eSMike Galbraith return elf_sym__type(sym) == STT_NOTYPE && 3276cfcc53eSMike Galbraith sym->st_name != 0 && 3286cfcc53eSMike Galbraith sym->st_shndx != SHN_UNDEF && 3296cfcc53eSMike Galbraith sym->st_shndx != SHN_ABS; 3306cfcc53eSMike Galbraith } 3316cfcc53eSMike Galbraith 3326cfcc53eSMike Galbraith static inline const char *elf_sec__name(const GElf_Shdr *shdr, 3336cfcc53eSMike Galbraith const Elf_Data *secstrs) 3346cfcc53eSMike Galbraith { 3356cfcc53eSMike Galbraith return secstrs->d_buf + shdr->sh_name; 3366cfcc53eSMike Galbraith } 3376cfcc53eSMike Galbraith 3386cfcc53eSMike Galbraith static inline int elf_sec__is_text(const GElf_Shdr *shdr, 3396cfcc53eSMike Galbraith const Elf_Data *secstrs) 3406cfcc53eSMike Galbraith { 3416cfcc53eSMike Galbraith return strstr(elf_sec__name(shdr, secstrs), "text") != NULL; 3426cfcc53eSMike Galbraith } 3436cfcc53eSMike Galbraith 34486470930SIngo Molnar static inline const char *elf_sym__name(const GElf_Sym *sym, 34586470930SIngo Molnar const Elf_Data *symstrs) 34686470930SIngo Molnar { 34786470930SIngo Molnar return symstrs->d_buf + sym->st_name; 34886470930SIngo Molnar } 34986470930SIngo Molnar 35086470930SIngo Molnar static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, 35186470930SIngo Molnar GElf_Shdr *shp, const char *name, 35286470930SIngo Molnar size_t *index) 35386470930SIngo Molnar { 35486470930SIngo Molnar Elf_Scn *sec = NULL; 35586470930SIngo Molnar size_t cnt = 1; 35686470930SIngo Molnar 35786470930SIngo Molnar while ((sec = elf_nextscn(elf, sec)) != NULL) { 35886470930SIngo Molnar char *str; 35986470930SIngo Molnar 36086470930SIngo Molnar gelf_getshdr(sec, shp); 36186470930SIngo Molnar str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name); 36286470930SIngo Molnar if (!strcmp(name, str)) { 36386470930SIngo Molnar if (index) 36486470930SIngo Molnar *index = cnt; 36586470930SIngo Molnar break; 36686470930SIngo Molnar } 36786470930SIngo Molnar ++cnt; 36886470930SIngo Molnar } 36986470930SIngo Molnar 37086470930SIngo Molnar return sec; 37186470930SIngo Molnar } 37286470930SIngo Molnar 37386470930SIngo Molnar #define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \ 37486470930SIngo Molnar for (idx = 0, pos = gelf_getrel(reldata, 0, &pos_mem); \ 37586470930SIngo Molnar idx < nr_entries; \ 37686470930SIngo Molnar ++idx, pos = gelf_getrel(reldata, idx, &pos_mem)) 37786470930SIngo Molnar 37886470930SIngo Molnar #define elf_section__for_each_rela(reldata, pos, pos_mem, idx, nr_entries) \ 37986470930SIngo Molnar for (idx = 0, pos = gelf_getrela(reldata, 0, &pos_mem); \ 38086470930SIngo Molnar idx < nr_entries; \ 38186470930SIngo Molnar ++idx, pos = gelf_getrela(reldata, idx, &pos_mem)) 38286470930SIngo Molnar 383a25e46c4SArnaldo Carvalho de Melo /* 384a25e46c4SArnaldo Carvalho de Melo * We need to check if we have a .dynsym, so that we can handle the 385a25e46c4SArnaldo Carvalho de Melo * .plt, synthesizing its symbols, that aren't on the symtabs (be it 386a25e46c4SArnaldo Carvalho de Melo * .dynsym or .symtab). 387a25e46c4SArnaldo Carvalho de Melo * And always look at the original dso, not at debuginfo packages, that 388a25e46c4SArnaldo Carvalho de Melo * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS). 389a25e46c4SArnaldo Carvalho de Melo */ 390a25e46c4SArnaldo Carvalho de Melo static int dso__synthesize_plt_symbols(struct dso *self, int verbose) 39186470930SIngo Molnar { 39286470930SIngo Molnar uint32_t nr_rel_entries, idx; 39386470930SIngo Molnar GElf_Sym sym; 3949cffa8d5SPaul Mackerras u64 plt_offset; 39586470930SIngo Molnar GElf_Shdr shdr_plt; 39686470930SIngo Molnar struct symbol *f; 397a25e46c4SArnaldo Carvalho de Melo GElf_Shdr shdr_rel_plt, shdr_dynsym; 39886470930SIngo Molnar Elf_Data *reldata, *syms, *symstrs; 399a25e46c4SArnaldo Carvalho de Melo Elf_Scn *scn_plt_rel, *scn_symstrs, *scn_dynsym; 400a25e46c4SArnaldo Carvalho de Melo size_t dynsym_idx; 401a25e46c4SArnaldo Carvalho de Melo GElf_Ehdr ehdr; 40286470930SIngo Molnar char sympltname[1024]; 403a25e46c4SArnaldo Carvalho de Melo Elf *elf; 404a25e46c4SArnaldo Carvalho de Melo int nr = 0, symidx, fd, err = 0; 40586470930SIngo Molnar 406a25e46c4SArnaldo Carvalho de Melo fd = open(self->name, O_RDONLY); 407a25e46c4SArnaldo Carvalho de Melo if (fd < 0) 408a25e46c4SArnaldo Carvalho de Melo goto out; 409a25e46c4SArnaldo Carvalho de Melo 410a25e46c4SArnaldo Carvalho de Melo elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); 411a25e46c4SArnaldo Carvalho de Melo if (elf == NULL) 412a25e46c4SArnaldo Carvalho de Melo goto out_close; 413a25e46c4SArnaldo Carvalho de Melo 414a25e46c4SArnaldo Carvalho de Melo if (gelf_getehdr(elf, &ehdr) == NULL) 415a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 416a25e46c4SArnaldo Carvalho de Melo 417a25e46c4SArnaldo Carvalho de Melo scn_dynsym = elf_section_by_name(elf, &ehdr, &shdr_dynsym, 418a25e46c4SArnaldo Carvalho de Melo ".dynsym", &dynsym_idx); 419a25e46c4SArnaldo Carvalho de Melo if (scn_dynsym == NULL) 420a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 421a25e46c4SArnaldo Carvalho de Melo 422a25e46c4SArnaldo Carvalho de Melo scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt, 42386470930SIngo Molnar ".rela.plt", NULL); 42486470930SIngo Molnar if (scn_plt_rel == NULL) { 425a25e46c4SArnaldo Carvalho de Melo scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt, 42686470930SIngo Molnar ".rel.plt", NULL); 42786470930SIngo Molnar if (scn_plt_rel == NULL) 428a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 42986470930SIngo Molnar } 43086470930SIngo Molnar 431a25e46c4SArnaldo Carvalho de Melo err = -1; 43286470930SIngo Molnar 433a25e46c4SArnaldo Carvalho de Melo if (shdr_rel_plt.sh_link != dynsym_idx) 434a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 435a25e46c4SArnaldo Carvalho de Melo 436a25e46c4SArnaldo Carvalho de Melo if (elf_section_by_name(elf, &ehdr, &shdr_plt, ".plt", NULL) == NULL) 437a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 43886470930SIngo Molnar 43986470930SIngo Molnar /* 44086470930SIngo Molnar * Fetch the relocation section to find the indexes to the GOT 44186470930SIngo Molnar * and the symbols in the .dynsym they refer to. 44286470930SIngo Molnar */ 44386470930SIngo Molnar reldata = elf_getdata(scn_plt_rel, NULL); 44486470930SIngo Molnar if (reldata == NULL) 445a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 44686470930SIngo Molnar 44786470930SIngo Molnar syms = elf_getdata(scn_dynsym, NULL); 44886470930SIngo Molnar if (syms == NULL) 449a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 45086470930SIngo Molnar 451a25e46c4SArnaldo Carvalho de Melo scn_symstrs = elf_getscn(elf, shdr_dynsym.sh_link); 45286470930SIngo Molnar if (scn_symstrs == NULL) 453a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 45486470930SIngo Molnar 45586470930SIngo Molnar symstrs = elf_getdata(scn_symstrs, NULL); 45686470930SIngo Molnar if (symstrs == NULL) 457a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 45886470930SIngo Molnar 45986470930SIngo Molnar nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize; 46086470930SIngo Molnar plt_offset = shdr_plt.sh_offset; 46186470930SIngo Molnar 46286470930SIngo Molnar if (shdr_rel_plt.sh_type == SHT_RELA) { 46386470930SIngo Molnar GElf_Rela pos_mem, *pos; 46486470930SIngo Molnar 46586470930SIngo Molnar elf_section__for_each_rela(reldata, pos, pos_mem, idx, 46686470930SIngo Molnar nr_rel_entries) { 46786470930SIngo Molnar symidx = GELF_R_SYM(pos->r_info); 46886470930SIngo Molnar plt_offset += shdr_plt.sh_entsize; 46986470930SIngo Molnar gelf_getsym(syms, symidx, &sym); 47086470930SIngo Molnar snprintf(sympltname, sizeof(sympltname), 47186470930SIngo Molnar "%s@plt", elf_sym__name(&sym, symstrs)); 47286470930SIngo Molnar 47386470930SIngo Molnar f = symbol__new(plt_offset, shdr_plt.sh_entsize, 47486470930SIngo Molnar sympltname, self->sym_priv_size, 0, verbose); 47586470930SIngo Molnar if (!f) 476a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 47786470930SIngo Molnar 47886470930SIngo Molnar dso__insert_symbol(self, f); 47986470930SIngo Molnar ++nr; 48086470930SIngo Molnar } 48186470930SIngo Molnar } else if (shdr_rel_plt.sh_type == SHT_REL) { 48286470930SIngo Molnar GElf_Rel pos_mem, *pos; 48386470930SIngo Molnar elf_section__for_each_rel(reldata, pos, pos_mem, idx, 48486470930SIngo Molnar nr_rel_entries) { 48586470930SIngo Molnar symidx = GELF_R_SYM(pos->r_info); 48686470930SIngo Molnar plt_offset += shdr_plt.sh_entsize; 48786470930SIngo Molnar gelf_getsym(syms, symidx, &sym); 48886470930SIngo Molnar snprintf(sympltname, sizeof(sympltname), 48986470930SIngo Molnar "%s@plt", elf_sym__name(&sym, symstrs)); 49086470930SIngo Molnar 49186470930SIngo Molnar f = symbol__new(plt_offset, shdr_plt.sh_entsize, 49286470930SIngo Molnar sympltname, self->sym_priv_size, 0, verbose); 49386470930SIngo Molnar if (!f) 494a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 49586470930SIngo Molnar 49686470930SIngo Molnar dso__insert_symbol(self, f); 49786470930SIngo Molnar ++nr; 49886470930SIngo Molnar } 49986470930SIngo Molnar } 50086470930SIngo Molnar 501a25e46c4SArnaldo Carvalho de Melo err = 0; 502a25e46c4SArnaldo Carvalho de Melo out_elf_end: 503a25e46c4SArnaldo Carvalho de Melo elf_end(elf); 504a25e46c4SArnaldo Carvalho de Melo out_close: 505a25e46c4SArnaldo Carvalho de Melo close(fd); 506a25e46c4SArnaldo Carvalho de Melo 507a25e46c4SArnaldo Carvalho de Melo if (err == 0) 50886470930SIngo Molnar return nr; 509a25e46c4SArnaldo Carvalho de Melo out: 510a25e46c4SArnaldo Carvalho de Melo fprintf(stderr, "%s: problems reading %s PLT info.\n", 511a25e46c4SArnaldo Carvalho de Melo __func__, self->name); 512a25e46c4SArnaldo Carvalho de Melo return 0; 51386470930SIngo Molnar } 51486470930SIngo Molnar 51586470930SIngo Molnar static int dso__load_sym(struct dso *self, int fd, const char *name, 5166cfcc53eSMike Galbraith symbol_filter_t filter, int verbose, struct module *mod) 51786470930SIngo Molnar { 5186cfcc53eSMike Galbraith Elf_Data *symstrs, *secstrs; 51986470930SIngo Molnar uint32_t nr_syms; 52086470930SIngo Molnar int err = -1; 52186470930SIngo Molnar uint32_t index; 52286470930SIngo Molnar GElf_Ehdr ehdr; 52386470930SIngo Molnar GElf_Shdr shdr; 52486470930SIngo Molnar Elf_Data *syms; 52586470930SIngo Molnar GElf_Sym sym; 526a25e46c4SArnaldo Carvalho de Melo Elf_Scn *sec, *sec_strndx; 52786470930SIngo Molnar Elf *elf; 528*d20ff6bdSMike Galbraith int nr = 0, kernel = !strcmp("[kernel]", self->name); 52986470930SIngo Molnar 53086470930SIngo Molnar elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); 53186470930SIngo Molnar if (elf == NULL) { 53286470930SIngo Molnar if (verbose) 53386470930SIngo Molnar fprintf(stderr, "%s: cannot read %s ELF file.\n", 53486470930SIngo Molnar __func__, name); 53586470930SIngo Molnar goto out_close; 53686470930SIngo Molnar } 53786470930SIngo Molnar 53886470930SIngo Molnar if (gelf_getehdr(elf, &ehdr) == NULL) { 53986470930SIngo Molnar if (verbose) 54086470930SIngo Molnar fprintf(stderr, "%s: cannot get elf header.\n", __func__); 54186470930SIngo Molnar goto out_elf_end; 54286470930SIngo Molnar } 54386470930SIngo Molnar 54486470930SIngo Molnar sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL); 54586470930SIngo Molnar if (sec == NULL) { 546a25e46c4SArnaldo Carvalho de Melo sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL); 547a25e46c4SArnaldo Carvalho de Melo if (sec == NULL) 54886470930SIngo Molnar goto out_elf_end; 54986470930SIngo Molnar } 55086470930SIngo Molnar 55186470930SIngo Molnar syms = elf_getdata(sec, NULL); 55286470930SIngo Molnar if (syms == NULL) 55386470930SIngo Molnar goto out_elf_end; 55486470930SIngo Molnar 55586470930SIngo Molnar sec = elf_getscn(elf, shdr.sh_link); 55686470930SIngo Molnar if (sec == NULL) 55786470930SIngo Molnar goto out_elf_end; 55886470930SIngo Molnar 55986470930SIngo Molnar symstrs = elf_getdata(sec, NULL); 56086470930SIngo Molnar if (symstrs == NULL) 56186470930SIngo Molnar goto out_elf_end; 56286470930SIngo Molnar 5636cfcc53eSMike Galbraith sec_strndx = elf_getscn(elf, ehdr.e_shstrndx); 5646cfcc53eSMike Galbraith if (sec_strndx == NULL) 5656cfcc53eSMike Galbraith goto out_elf_end; 5666cfcc53eSMike Galbraith 5676cfcc53eSMike Galbraith secstrs = elf_getdata(sec_strndx, NULL); 5686cfcc53eSMike Galbraith if (symstrs == NULL) 5696cfcc53eSMike Galbraith goto out_elf_end; 5706cfcc53eSMike Galbraith 57186470930SIngo Molnar nr_syms = shdr.sh_size / shdr.sh_entsize; 57286470930SIngo Molnar 573e9fbc9dcSArjan van de Ven memset(&sym, 0, sizeof(sym)); 574*d20ff6bdSMike Galbraith if (!kernel) { 57530d7a77dSArnaldo Carvalho de Melo self->adjust_symbols = (ehdr.e_type == ET_EXEC || 57630d7a77dSArnaldo Carvalho de Melo elf_section_by_name(elf, &ehdr, &shdr, 577f5812a7aSArnaldo Carvalho de Melo ".gnu.prelink_undo", 57830d7a77dSArnaldo Carvalho de Melo NULL) != NULL); 579*d20ff6bdSMike Galbraith } else self->adjust_symbols = 0; 580*d20ff6bdSMike Galbraith 58186470930SIngo Molnar elf_symtab__for_each_symbol(syms, nr_syms, index, sym) { 58286470930SIngo Molnar struct symbol *f; 58328ac909bSArnaldo Carvalho de Melo const char *name; 58428ac909bSArnaldo Carvalho de Melo char *demangled; 5859cffa8d5SPaul Mackerras u64 obj_start; 5866cfcc53eSMike Galbraith struct section *section = NULL; 5876cfcc53eSMike Galbraith int is_label = elf_sym__is_label(&sym); 5886cfcc53eSMike Galbraith const char *section_name; 58986470930SIngo Molnar 5906cfcc53eSMike Galbraith if (!is_label && !elf_sym__is_function(&sym)) 59186470930SIngo Molnar continue; 59286470930SIngo Molnar 59386470930SIngo Molnar sec = elf_getscn(elf, sym.st_shndx); 59486470930SIngo Molnar if (!sec) 59586470930SIngo Molnar goto out_elf_end; 59686470930SIngo Molnar 59786470930SIngo Molnar gelf_getshdr(sec, &shdr); 5986cfcc53eSMike Galbraith 5996cfcc53eSMike Galbraith if (is_label && !elf_sec__is_text(&shdr, secstrs)) 6006cfcc53eSMike Galbraith continue; 6016cfcc53eSMike Galbraith 6026cfcc53eSMike Galbraith section_name = elf_sec__name(&shdr, secstrs); 60386470930SIngo Molnar obj_start = sym.st_value; 60486470930SIngo Molnar 60530d7a77dSArnaldo Carvalho de Melo if (self->adjust_symbols) { 606520f2c34SPeter Zijlstra if (verbose >= 2) 607520f2c34SPeter Zijlstra printf("adjusting symbol: st_value: %Lx sh_addr: %Lx sh_offset: %Lx\n", 608520f2c34SPeter Zijlstra (u64)sym.st_value, (u64)shdr.sh_addr, (u64)shdr.sh_offset); 609520f2c34SPeter Zijlstra 61086470930SIngo Molnar sym.st_value -= shdr.sh_addr - shdr.sh_offset; 611f5812a7aSArnaldo Carvalho de Melo } 61286470930SIngo Molnar 6136cfcc53eSMike Galbraith if (mod) { 6146cfcc53eSMike Galbraith section = mod->sections->find_section(mod->sections, section_name); 6156cfcc53eSMike Galbraith if (section) 6166cfcc53eSMike Galbraith sym.st_value += section->vma; 6176cfcc53eSMike Galbraith else { 6186cfcc53eSMike Galbraith fprintf(stderr, "dso__load_sym() module %s lookup of %s failed\n", 6196cfcc53eSMike Galbraith mod->name, section_name); 6206cfcc53eSMike Galbraith goto out_elf_end; 6216cfcc53eSMike Galbraith } 6226cfcc53eSMike Galbraith } 62328ac909bSArnaldo Carvalho de Melo /* 62428ac909bSArnaldo Carvalho de Melo * We need to figure out if the object was created from C++ sources 62528ac909bSArnaldo Carvalho de Melo * DWARF DW_compile_unit has this, but we don't always have access 62628ac909bSArnaldo Carvalho de Melo * to it... 62728ac909bSArnaldo Carvalho de Melo */ 62828ac909bSArnaldo Carvalho de Melo name = elf_sym__name(&sym, symstrs); 62928ac909bSArnaldo Carvalho de Melo demangled = bfd_demangle(NULL, name, DMGL_PARAMS | DMGL_ANSI); 63028ac909bSArnaldo Carvalho de Melo if (demangled != NULL) 63128ac909bSArnaldo Carvalho de Melo name = demangled; 6326cfcc53eSMike Galbraith 63328ac909bSArnaldo Carvalho de Melo f = symbol__new(sym.st_value, sym.st_size, name, 63486470930SIngo Molnar self->sym_priv_size, obj_start, verbose); 63528ac909bSArnaldo Carvalho de Melo free(demangled); 63686470930SIngo Molnar if (!f) 63786470930SIngo Molnar goto out_elf_end; 63886470930SIngo Molnar 63986470930SIngo Molnar if (filter && filter(self, f)) 64086470930SIngo Molnar symbol__delete(f, self->sym_priv_size); 64186470930SIngo Molnar else { 6426cfcc53eSMike Galbraith f->module = mod; 64386470930SIngo Molnar dso__insert_symbol(self, f); 64486470930SIngo Molnar nr++; 64586470930SIngo Molnar } 64686470930SIngo Molnar } 64786470930SIngo Molnar 64886470930SIngo Molnar err = nr; 64986470930SIngo Molnar out_elf_end: 65086470930SIngo Molnar elf_end(elf); 65186470930SIngo Molnar out_close: 65286470930SIngo Molnar return err; 65386470930SIngo Molnar } 65486470930SIngo Molnar 65586470930SIngo Molnar int dso__load(struct dso *self, symbol_filter_t filter, int verbose) 65686470930SIngo Molnar { 65786470930SIngo Molnar int size = strlen(self->name) + sizeof("/usr/lib/debug%s.debug"); 65886470930SIngo Molnar char *name = malloc(size); 65986470930SIngo Molnar int variant = 0; 66086470930SIngo Molnar int ret = -1; 66186470930SIngo Molnar int fd; 66286470930SIngo Molnar 66386470930SIngo Molnar if (!name) 66486470930SIngo Molnar return -1; 66586470930SIngo Molnar 66630d7a77dSArnaldo Carvalho de Melo self->adjust_symbols = 0; 667f5812a7aSArnaldo Carvalho de Melo 66880d496beSPekka Enberg if (strncmp(self->name, "/tmp/perf-", 10) == 0) 66980d496beSPekka Enberg return dso__load_perf_map(self, filter, verbose); 67080d496beSPekka Enberg 67186470930SIngo Molnar more: 67286470930SIngo Molnar do { 67386470930SIngo Molnar switch (variant) { 67486470930SIngo Molnar case 0: /* Fedora */ 67586470930SIngo Molnar snprintf(name, size, "/usr/lib/debug%s.debug", self->name); 67686470930SIngo Molnar break; 67786470930SIngo Molnar case 1: /* Ubuntu */ 67886470930SIngo Molnar snprintf(name, size, "/usr/lib/debug%s", self->name); 67986470930SIngo Molnar break; 68086470930SIngo Molnar case 2: /* Sane people */ 68186470930SIngo Molnar snprintf(name, size, "%s", self->name); 68286470930SIngo Molnar break; 68386470930SIngo Molnar 68486470930SIngo Molnar default: 68586470930SIngo Molnar goto out; 68686470930SIngo Molnar } 68786470930SIngo Molnar variant++; 68886470930SIngo Molnar 68986470930SIngo Molnar fd = open(name, O_RDONLY); 69086470930SIngo Molnar } while (fd < 0); 69186470930SIngo Molnar 6926cfcc53eSMike Galbraith ret = dso__load_sym(self, fd, name, filter, verbose, NULL); 69386470930SIngo Molnar close(fd); 69486470930SIngo Molnar 69586470930SIngo Molnar /* 69686470930SIngo Molnar * Some people seem to have debuginfo files _WITHOUT_ debug info!?!? 69786470930SIngo Molnar */ 69886470930SIngo Molnar if (!ret) 69986470930SIngo Molnar goto more; 70086470930SIngo Molnar 701a25e46c4SArnaldo Carvalho de Melo if (ret > 0) { 702a25e46c4SArnaldo Carvalho de Melo int nr_plt = dso__synthesize_plt_symbols(self, verbose); 703a25e46c4SArnaldo Carvalho de Melo if (nr_plt > 0) 704a25e46c4SArnaldo Carvalho de Melo ret += nr_plt; 705a25e46c4SArnaldo Carvalho de Melo } 70686470930SIngo Molnar out: 70786470930SIngo Molnar free(name); 70886470930SIngo Molnar return ret; 70986470930SIngo Molnar } 71086470930SIngo Molnar 7116cfcc53eSMike Galbraith static int dso__load_module(struct dso *self, struct mod_dso *mods, const char *name, 7126cfcc53eSMike Galbraith symbol_filter_t filter, int verbose) 7136cfcc53eSMike Galbraith { 7146cfcc53eSMike Galbraith struct module *mod = mod_dso__find_module(mods, name); 7156cfcc53eSMike Galbraith int err = 0, fd; 7166cfcc53eSMike Galbraith 7176cfcc53eSMike Galbraith if (mod == NULL || !mod->active) 7186cfcc53eSMike Galbraith return err; 7196cfcc53eSMike Galbraith 7206cfcc53eSMike Galbraith fd = open(mod->path, O_RDONLY); 7216cfcc53eSMike Galbraith 7226cfcc53eSMike Galbraith if (fd < 0) 7236cfcc53eSMike Galbraith return err; 7246cfcc53eSMike Galbraith 7256cfcc53eSMike Galbraith err = dso__load_sym(self, fd, name, filter, verbose, mod); 7266cfcc53eSMike Galbraith close(fd); 7276cfcc53eSMike Galbraith 7286cfcc53eSMike Galbraith return err; 7296cfcc53eSMike Galbraith } 7306cfcc53eSMike Galbraith 7316cfcc53eSMike Galbraith int dso__load_modules(struct dso *self, symbol_filter_t filter, int verbose) 7326cfcc53eSMike Galbraith { 7336cfcc53eSMike Galbraith struct mod_dso *mods = mod_dso__new_dso("modules"); 7346cfcc53eSMike Galbraith struct module *pos; 7356cfcc53eSMike Galbraith struct rb_node *next; 7366cfcc53eSMike Galbraith int err; 7376cfcc53eSMike Galbraith 7386cfcc53eSMike Galbraith err = mod_dso__load_modules(mods); 7396cfcc53eSMike Galbraith 7406cfcc53eSMike Galbraith if (err <= 0) 7416cfcc53eSMike Galbraith return err; 7426cfcc53eSMike Galbraith 7436cfcc53eSMike Galbraith /* 7446cfcc53eSMike Galbraith * Iterate over modules, and load active symbols. 7456cfcc53eSMike Galbraith */ 7466cfcc53eSMike Galbraith next = rb_first(&mods->mods); 7476cfcc53eSMike Galbraith while (next) { 7486cfcc53eSMike Galbraith pos = rb_entry(next, struct module, rb_node); 7496cfcc53eSMike Galbraith err = dso__load_module(self, mods, pos->name, filter, verbose); 7506cfcc53eSMike Galbraith 7516cfcc53eSMike Galbraith if (err < 0) 7526cfcc53eSMike Galbraith break; 7536cfcc53eSMike Galbraith 7546cfcc53eSMike Galbraith next = rb_next(&pos->rb_node); 7556cfcc53eSMike Galbraith } 7566cfcc53eSMike Galbraith 7576cfcc53eSMike Galbraith if (err < 0) { 7586cfcc53eSMike Galbraith mod_dso__delete_modules(mods); 7596cfcc53eSMike Galbraith mod_dso__delete_self(mods); 7606cfcc53eSMike Galbraith } 7616cfcc53eSMike Galbraith 7626cfcc53eSMike Galbraith return err; 7636cfcc53eSMike Galbraith } 7646cfcc53eSMike Galbraith 7656cfcc53eSMike Galbraith static inline void dso__fill_symbol_holes(struct dso *self) 7666cfcc53eSMike Galbraith { 7676cfcc53eSMike Galbraith struct symbol *prev = NULL; 7686cfcc53eSMike Galbraith struct rb_node *nd; 7696cfcc53eSMike Galbraith 7706cfcc53eSMike Galbraith for (nd = rb_last(&self->syms); nd; nd = rb_prev(nd)) { 7716cfcc53eSMike Galbraith struct symbol *pos = rb_entry(nd, struct symbol, rb_node); 7726cfcc53eSMike Galbraith 7736cfcc53eSMike Galbraith if (prev) { 7746cfcc53eSMike Galbraith u64 hole = 0; 7756cfcc53eSMike Galbraith int alias = pos->start == prev->start; 7766cfcc53eSMike Galbraith 7776cfcc53eSMike Galbraith if (!alias) 7786cfcc53eSMike Galbraith hole = prev->start - pos->end - 1; 7796cfcc53eSMike Galbraith 7806cfcc53eSMike Galbraith if (hole || alias) { 7816cfcc53eSMike Galbraith if (alias) 7826cfcc53eSMike Galbraith pos->end = prev->end; 7836cfcc53eSMike Galbraith else if (hole) 7846cfcc53eSMike Galbraith pos->end = prev->start - 1; 7856cfcc53eSMike Galbraith } 7866cfcc53eSMike Galbraith } 7876cfcc53eSMike Galbraith prev = pos; 7886cfcc53eSMike Galbraith } 7896cfcc53eSMike Galbraith } 7906cfcc53eSMike Galbraith 79186470930SIngo Molnar static int dso__load_vmlinux(struct dso *self, const char *vmlinux, 79286470930SIngo Molnar symbol_filter_t filter, int verbose) 79386470930SIngo Molnar { 79486470930SIngo Molnar int err, fd = open(vmlinux, O_RDONLY); 79586470930SIngo Molnar 79686470930SIngo Molnar if (fd < 0) 79786470930SIngo Molnar return -1; 79886470930SIngo Molnar 7996cfcc53eSMike Galbraith err = dso__load_sym(self, fd, vmlinux, filter, verbose, NULL); 8006cfcc53eSMike Galbraith 8016cfcc53eSMike Galbraith if (err > 0) 8026cfcc53eSMike Galbraith dso__fill_symbol_holes(self); 8036cfcc53eSMike Galbraith 80486470930SIngo Molnar close(fd); 80586470930SIngo Molnar 80686470930SIngo Molnar return err; 80786470930SIngo Molnar } 80886470930SIngo Molnar 80986470930SIngo Molnar int dso__load_kernel(struct dso *self, const char *vmlinux, 8106cfcc53eSMike Galbraith symbol_filter_t filter, int verbose, int modules) 81186470930SIngo Molnar { 81286470930SIngo Molnar int err = -1; 81386470930SIngo Molnar 8146cfcc53eSMike Galbraith if (vmlinux) { 81586470930SIngo Molnar err = dso__load_vmlinux(self, vmlinux, filter, verbose); 8166cfcc53eSMike Galbraith if (err > 0 && modules) 8176cfcc53eSMike Galbraith err = dso__load_modules(self, filter, verbose); 8186cfcc53eSMike Galbraith } 81986470930SIngo Molnar 8209974f496SMike Galbraith if (err <= 0) 82186470930SIngo Molnar err = dso__load_kallsyms(self, filter, verbose); 82286470930SIngo Molnar 82386470930SIngo Molnar return err; 82486470930SIngo Molnar } 82586470930SIngo Molnar 82686470930SIngo Molnar void symbol__init(void) 82786470930SIngo Molnar { 82886470930SIngo Molnar elf_version(EV_CURRENT); 82986470930SIngo Molnar } 830