void symbols__fixup_duplicate(struct rb_root *symbols) { struct rb_node *nd; struct symbol *curr, *next; nd = rb_first(symbols); while (nd) { curr = rb_entry(nd, struct symbol, rb_node); again: nd = rb_next(&curr->rb_node); next = rb_entry(nd, struct symbol, rb_node); if (!nd) break; if (curr->start != next->start) continue; if (choose_best_symbol(curr, next) == SYMBOL_A) { rb_erase(&next->rb_node, symbols); symbol__delete(next); goto again; } else { nd = rb_next(&curr->rb_node); rb_erase(&curr->rb_node, symbols); symbol__delete(curr); } } }
void symbols__delete(struct rb_root *symbols) { struct symbol *pos; struct rb_node *next = rb_first(symbols); while (next) { pos = rb_entry(next, struct symbol, rb_node); next = rb_next(&pos->rb_node); rb_erase(&pos->rb_node, symbols); symbol__delete(pos); } }
static void dso__delete_symbols(struct dso *self) { struct symbol *pos; struct rb_node *next = rb_first(&self->syms); while (next) { pos = rb_entry(next, struct symbol, rb_node); next = rb_next(&pos->rb_node); rb_erase(&pos->rb_node, &self->syms); symbol__delete(pos, self->sym_priv_size); } }
static int perf_session__add_hist_entry(struct perf_session *self, struct addr_location *al, u64 count) { bool hit; struct hist_entry *he; if (sym_hist_filter != NULL && (al->sym == NULL || strcmp(sym_hist_filter, al->sym->name) != 0)) { /* We're only interested in a symbol named sym_hist_filter */ if (al->sym != NULL) { rb_erase(&al->sym->rb_node, &al->map->dso->symbols[al->map->type]); symbol__delete(al->sym); } return 0; } he = __perf_session__add_hist_entry(self, al, NULL, count, &hit); if (he == NULL) return -ENOMEM; return annotate__hist_hit(he, al->addr); }
/* * We need to check if we have a .dynsym, so that we can handle the * .plt, synthesizing its symbols, that aren't on the symtabs (be it * .dynsym or .symtab). * And always look at the original dso, not at debuginfo packages, that * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS). */ int dso__synthesize_plt_symbols(struct dso *dso, struct symsrc *ss, struct map *map, symbol_filter_t filter) { uint32_t nr_rel_entries, idx; GElf_Sym sym; u64 plt_offset; GElf_Shdr shdr_plt; struct symbol *f; GElf_Shdr shdr_rel_plt, shdr_dynsym; Elf_Data *reldata, *syms, *symstrs; Elf_Scn *scn_plt_rel, *scn_symstrs, *scn_dynsym; size_t dynsym_idx; GElf_Ehdr ehdr; char sympltname[1024]; Elf *elf; int nr = 0, symidx, err = 0; if (!ss->dynsym) return 0; elf = ss->elf; ehdr = ss->ehdr; scn_dynsym = ss->dynsym; shdr_dynsym = ss->dynshdr; dynsym_idx = ss->dynsym_idx; if (scn_dynsym == NULL) goto out_elf_end; scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt, ".rela.plt", NULL); if (scn_plt_rel == NULL) { scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt, ".rel.plt", NULL); if (scn_plt_rel == NULL) goto out_elf_end; } err = -1; if (shdr_rel_plt.sh_link != dynsym_idx) goto out_elf_end; if (elf_section_by_name(elf, &ehdr, &shdr_plt, ".plt", NULL) == NULL) goto out_elf_end; /* * Fetch the relocation section to find the idxes to the GOT * and the symbols in the .dynsym they refer to. */ reldata = elf_getdata(scn_plt_rel, NULL); if (reldata == NULL) goto out_elf_end; syms = elf_getdata(scn_dynsym, NULL); if (syms == NULL) goto out_elf_end; scn_symstrs = elf_getscn(elf, shdr_dynsym.sh_link); if (scn_symstrs == NULL) goto out_elf_end; symstrs = elf_getdata(scn_symstrs, NULL); if (symstrs == NULL) goto out_elf_end; if (symstrs->d_size == 0) goto out_elf_end; nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize; plt_offset = shdr_plt.sh_offset; if (shdr_rel_plt.sh_type == SHT_RELA) { GElf_Rela pos_mem, *pos; elf_section__for_each_rela(reldata, pos, pos_mem, idx, nr_rel_entries) { symidx = GELF_R_SYM(pos->r_info); plt_offset += shdr_plt.sh_entsize; gelf_getsym(syms, symidx, &sym); snprintf(sympltname, sizeof(sympltname), "%s@plt", elf_sym__name(&sym, symstrs)); f = symbol__new(plt_offset, shdr_plt.sh_entsize, STB_GLOBAL, sympltname); if (!f) goto out_elf_end; if (filter && filter(map, f)) symbol__delete(f); else { symbols__insert(&dso->symbols[map->type], f); ++nr; } }
static int dso__load_perf_map(struct dso *self, symbol_filter_t filter, int verbose) { char *line = NULL; size_t n; FILE *file; int nr_syms = 0; file = fopen(self->name, "r"); if (file == NULL) goto out_failure; while (!feof(file)) { u64 start, size; struct symbol *sym; int line_len, len; line_len = getline(&line, &n, file); if (line_len < 0) break; if (!line) goto out_failure; line[--line_len] = '\0'; /* \n */ len = hex2u64(line, &start); len++; if (len + 2 >= line_len) continue; len += hex2u64(line + len, &size); len++; if (len + 2 >= line_len) continue; sym = symbol__new(start, size, line + len, self->sym_priv_size, start, verbose); if (sym == NULL) goto out_delete_line; if (filter && filter(self, sym)) symbol__delete(sym, self->sym_priv_size); else { dso__insert_symbol(self, sym); nr_syms++; } } free(line); fclose(file); return nr_syms; out_delete_line: free(line); out_failure: return -1; }
static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int verbose) { struct rb_node *nd, *prevnd; char *line = NULL; size_t n; FILE *file = fopen("/proc/kallsyms", "r"); int count = 0; if (file == NULL) goto out_failure; while (!feof(file)) { u64 start; struct symbol *sym; int line_len, len; char symbol_type; line_len = getline(&line, &n, file); if (line_len < 0) break; if (!line) goto out_failure; line[--line_len] = '\0'; /* \n */ len = hex2u64(line, &start); len++; if (len + 2 >= line_len) continue; symbol_type = toupper(line[len]); /* * We're interested only in code ('T'ext) */ if (symbol_type != 'T' && symbol_type != 'W') continue; /* * Well fix up the end later, when we have all sorted. */ sym = symbol__new(start, 0xdead, line + len + 2, self->sym_priv_size, 0, verbose); if (sym == NULL) goto out_delete_line; if (filter && filter(self, sym)) symbol__delete(sym, self->sym_priv_size); else { dso__insert_symbol(self, sym); count++; } } /* * Now that we have all sorted out, just set the ->end of all * symbols */ prevnd = rb_first(&self->syms); if (prevnd == NULL) goto out_delete_line; for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) { struct symbol *prev = rb_entry(prevnd, struct symbol, rb_node), *curr = rb_entry(nd, struct symbol, rb_node); prev->end = curr->start - 1; prevnd = nd; } free(line); fclose(file); return count; out_delete_line: free(line); out_failure: return -1; }