xref: /linux/tools/perf/util/symbol.c (revision 864709302a80f26fa9da3be5b47304f0b8bae192)
1*86470930SIngo Molnar #include "util.h"
2*86470930SIngo Molnar #include "../perf.h"
3*86470930SIngo Molnar #include "string.h"
4*86470930SIngo Molnar #include "symbol.h"
5*86470930SIngo Molnar 
6*86470930SIngo Molnar #include <libelf.h>
7*86470930SIngo Molnar #include <gelf.h>
8*86470930SIngo Molnar #include <elf.h>
9*86470930SIngo Molnar 
10*86470930SIngo Molnar const char *sym_hist_filter;
11*86470930SIngo Molnar 
12*86470930SIngo Molnar static struct symbol *symbol__new(uint64_t start, uint64_t len,
13*86470930SIngo Molnar 				  const char *name, unsigned int priv_size,
14*86470930SIngo Molnar 				  uint64_t obj_start, int verbose)
15*86470930SIngo Molnar {
16*86470930SIngo Molnar 	size_t namelen = strlen(name) + 1;
17*86470930SIngo Molnar 	struct symbol *self = calloc(1, priv_size + sizeof(*self) + namelen);
18*86470930SIngo Molnar 
19*86470930SIngo Molnar 	if (!self)
20*86470930SIngo Molnar 		return NULL;
21*86470930SIngo Molnar 
22*86470930SIngo Molnar 	if (verbose >= 2)
23*86470930SIngo Molnar 		printf("new symbol: %016Lx [%08lx]: %s, hist: %p, obj_start: %p\n",
24*86470930SIngo Molnar 			(__u64)start, len, name, self->hist, (void *)obj_start);
25*86470930SIngo Molnar 
26*86470930SIngo Molnar 	self->obj_start= obj_start;
27*86470930SIngo Molnar 	self->hist = NULL;
28*86470930SIngo Molnar 	self->hist_sum = 0;
29*86470930SIngo Molnar 
30*86470930SIngo Molnar 	if (sym_hist_filter && !strcmp(name, sym_hist_filter))
31*86470930SIngo Molnar 		self->hist = calloc(sizeof(__u64), len);
32*86470930SIngo Molnar 
33*86470930SIngo Molnar 	if (priv_size) {
34*86470930SIngo Molnar 		memset(self, 0, priv_size);
35*86470930SIngo Molnar 		self = ((void *)self) + priv_size;
36*86470930SIngo Molnar 	}
37*86470930SIngo Molnar 	self->start = start;
38*86470930SIngo Molnar 	self->end   = start + len - 1;
39*86470930SIngo Molnar 	memcpy(self->name, name, namelen);
40*86470930SIngo Molnar 
41*86470930SIngo Molnar 	return self;
42*86470930SIngo Molnar }
43*86470930SIngo Molnar 
44*86470930SIngo Molnar static void symbol__delete(struct symbol *self, unsigned int priv_size)
45*86470930SIngo Molnar {
46*86470930SIngo Molnar 	free(((void *)self) - priv_size);
47*86470930SIngo Molnar }
48*86470930SIngo Molnar 
49*86470930SIngo Molnar static size_t symbol__fprintf(struct symbol *self, FILE *fp)
50*86470930SIngo Molnar {
51*86470930SIngo Molnar 	return fprintf(fp, " %llx-%llx %s\n",
52*86470930SIngo Molnar 		       self->start, self->end, self->name);
53*86470930SIngo Molnar }
54*86470930SIngo Molnar 
55*86470930SIngo Molnar struct dso *dso__new(const char *name, unsigned int sym_priv_size)
56*86470930SIngo Molnar {
57*86470930SIngo Molnar 	struct dso *self = malloc(sizeof(*self) + strlen(name) + 1);
58*86470930SIngo Molnar 
59*86470930SIngo Molnar 	if (self != NULL) {
60*86470930SIngo Molnar 		strcpy(self->name, name);
61*86470930SIngo Molnar 		self->syms = RB_ROOT;
62*86470930SIngo Molnar 		self->sym_priv_size = sym_priv_size;
63*86470930SIngo Molnar 		self->find_symbol = dso__find_symbol;
64*86470930SIngo Molnar 	}
65*86470930SIngo Molnar 
66*86470930SIngo Molnar 	return self;
67*86470930SIngo Molnar }
68*86470930SIngo Molnar 
69*86470930SIngo Molnar static void dso__delete_symbols(struct dso *self)
70*86470930SIngo Molnar {
71*86470930SIngo Molnar 	struct symbol *pos;
72*86470930SIngo Molnar 	struct rb_node *next = rb_first(&self->syms);
73*86470930SIngo Molnar 
74*86470930SIngo Molnar 	while (next) {
75*86470930SIngo Molnar 		pos = rb_entry(next, struct symbol, rb_node);
76*86470930SIngo Molnar 		next = rb_next(&pos->rb_node);
77*86470930SIngo Molnar 		rb_erase(&pos->rb_node, &self->syms);
78*86470930SIngo Molnar 		symbol__delete(pos, self->sym_priv_size);
79*86470930SIngo Molnar 	}
80*86470930SIngo Molnar }
81*86470930SIngo Molnar 
82*86470930SIngo Molnar void dso__delete(struct dso *self)
83*86470930SIngo Molnar {
84*86470930SIngo Molnar 	dso__delete_symbols(self);
85*86470930SIngo Molnar 	free(self);
86*86470930SIngo Molnar }
87*86470930SIngo Molnar 
88*86470930SIngo Molnar static void dso__insert_symbol(struct dso *self, struct symbol *sym)
89*86470930SIngo Molnar {
90*86470930SIngo Molnar 	struct rb_node **p = &self->syms.rb_node;
91*86470930SIngo Molnar 	struct rb_node *parent = NULL;
92*86470930SIngo Molnar 	const uint64_t ip = sym->start;
93*86470930SIngo Molnar 	struct symbol *s;
94*86470930SIngo Molnar 
95*86470930SIngo Molnar 	while (*p != NULL) {
96*86470930SIngo Molnar 		parent = *p;
97*86470930SIngo Molnar 		s = rb_entry(parent, struct symbol, rb_node);
98*86470930SIngo Molnar 		if (ip < s->start)
99*86470930SIngo Molnar 			p = &(*p)->rb_left;
100*86470930SIngo Molnar 		else
101*86470930SIngo Molnar 			p = &(*p)->rb_right;
102*86470930SIngo Molnar 	}
103*86470930SIngo Molnar 	rb_link_node(&sym->rb_node, parent, p);
104*86470930SIngo Molnar 	rb_insert_color(&sym->rb_node, &self->syms);
105*86470930SIngo Molnar }
106*86470930SIngo Molnar 
107*86470930SIngo Molnar struct symbol *dso__find_symbol(struct dso *self, uint64_t ip)
108*86470930SIngo Molnar {
109*86470930SIngo Molnar 	struct rb_node *n;
110*86470930SIngo Molnar 
111*86470930SIngo Molnar 	if (self == NULL)
112*86470930SIngo Molnar 		return NULL;
113*86470930SIngo Molnar 
114*86470930SIngo Molnar 	n = self->syms.rb_node;
115*86470930SIngo Molnar 
116*86470930SIngo Molnar 	while (n) {
117*86470930SIngo Molnar 		struct symbol *s = rb_entry(n, struct symbol, rb_node);
118*86470930SIngo Molnar 
119*86470930SIngo Molnar 		if (ip < s->start)
120*86470930SIngo Molnar 			n = n->rb_left;
121*86470930SIngo Molnar 		else if (ip > s->end)
122*86470930SIngo Molnar 			n = n->rb_right;
123*86470930SIngo Molnar 		else
124*86470930SIngo Molnar 			return s;
125*86470930SIngo Molnar 	}
126*86470930SIngo Molnar 
127*86470930SIngo Molnar 	return NULL;
128*86470930SIngo Molnar }
129*86470930SIngo Molnar 
130*86470930SIngo Molnar size_t dso__fprintf(struct dso *self, FILE *fp)
131*86470930SIngo Molnar {
132*86470930SIngo Molnar 	size_t ret = fprintf(fp, "dso: %s\n", self->name);
133*86470930SIngo Molnar 
134*86470930SIngo Molnar 	struct rb_node *nd;
135*86470930SIngo Molnar 	for (nd = rb_first(&self->syms); nd; nd = rb_next(nd)) {
136*86470930SIngo Molnar 		struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
137*86470930SIngo Molnar 		ret += symbol__fprintf(pos, fp);
138*86470930SIngo Molnar 	}
139*86470930SIngo Molnar 
140*86470930SIngo Molnar 	return ret;
141*86470930SIngo Molnar }
142*86470930SIngo Molnar 
143*86470930SIngo Molnar static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int verbose)
144*86470930SIngo Molnar {
145*86470930SIngo Molnar 	struct rb_node *nd, *prevnd;
146*86470930SIngo Molnar 	char *line = NULL;
147*86470930SIngo Molnar 	size_t n;
148*86470930SIngo Molnar 	FILE *file = fopen("/proc/kallsyms", "r");
149*86470930SIngo Molnar 
150*86470930SIngo Molnar 	if (file == NULL)
151*86470930SIngo Molnar 		goto out_failure;
152*86470930SIngo Molnar 
153*86470930SIngo Molnar 	while (!feof(file)) {
154*86470930SIngo Molnar 		__u64 start;
155*86470930SIngo Molnar 		struct symbol *sym;
156*86470930SIngo Molnar 		int line_len, len;
157*86470930SIngo Molnar 		char symbol_type;
158*86470930SIngo Molnar 
159*86470930SIngo Molnar 		line_len = getline(&line, &n, file);
160*86470930SIngo Molnar 		if (line_len < 0)
161*86470930SIngo Molnar 			break;
162*86470930SIngo Molnar 
163*86470930SIngo Molnar 		if (!line)
164*86470930SIngo Molnar 			goto out_failure;
165*86470930SIngo Molnar 
166*86470930SIngo Molnar 		line[--line_len] = '\0'; /* \n */
167*86470930SIngo Molnar 
168*86470930SIngo Molnar 		len = hex2u64(line, &start);
169*86470930SIngo Molnar 
170*86470930SIngo Molnar 		len++;
171*86470930SIngo Molnar 		if (len + 2 >= line_len)
172*86470930SIngo Molnar 			continue;
173*86470930SIngo Molnar 
174*86470930SIngo Molnar 		symbol_type = toupper(line[len]);
175*86470930SIngo Molnar 		/*
176*86470930SIngo Molnar 		 * We're interested only in code ('T'ext)
177*86470930SIngo Molnar 		 */
178*86470930SIngo Molnar 		if (symbol_type != 'T' && symbol_type != 'W')
179*86470930SIngo Molnar 			continue;
180*86470930SIngo Molnar 		/*
181*86470930SIngo Molnar 		 * Well fix up the end later, when we have all sorted.
182*86470930SIngo Molnar 		 */
183*86470930SIngo Molnar 		sym = symbol__new(start, 0xdead, line + len + 2,
184*86470930SIngo Molnar 				  self->sym_priv_size, 0, verbose);
185*86470930SIngo Molnar 
186*86470930SIngo Molnar 		if (sym == NULL)
187*86470930SIngo Molnar 			goto out_delete_line;
188*86470930SIngo Molnar 
189*86470930SIngo Molnar 		if (filter && filter(self, sym))
190*86470930SIngo Molnar 			symbol__delete(sym, self->sym_priv_size);
191*86470930SIngo Molnar 		else
192*86470930SIngo Molnar 			dso__insert_symbol(self, sym);
193*86470930SIngo Molnar 	}
194*86470930SIngo Molnar 
195*86470930SIngo Molnar 	/*
196*86470930SIngo Molnar 	 * Now that we have all sorted out, just set the ->end of all
197*86470930SIngo Molnar 	 * symbols
198*86470930SIngo Molnar 	 */
199*86470930SIngo Molnar 	prevnd = rb_first(&self->syms);
200*86470930SIngo Molnar 
201*86470930SIngo Molnar 	if (prevnd == NULL)
202*86470930SIngo Molnar 		goto out_delete_line;
203*86470930SIngo Molnar 
204*86470930SIngo Molnar 	for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
205*86470930SIngo Molnar 		struct symbol *prev = rb_entry(prevnd, struct symbol, rb_node),
206*86470930SIngo Molnar 			      *curr = rb_entry(nd, struct symbol, rb_node);
207*86470930SIngo Molnar 
208*86470930SIngo Molnar 		prev->end = curr->start - 1;
209*86470930SIngo Molnar 		prevnd = nd;
210*86470930SIngo Molnar 	}
211*86470930SIngo Molnar 
212*86470930SIngo Molnar 	free(line);
213*86470930SIngo Molnar 	fclose(file);
214*86470930SIngo Molnar 
215*86470930SIngo Molnar 	return 0;
216*86470930SIngo Molnar 
217*86470930SIngo Molnar out_delete_line:
218*86470930SIngo Molnar 	free(line);
219*86470930SIngo Molnar out_failure:
220*86470930SIngo Molnar 	return -1;
221*86470930SIngo Molnar }
222*86470930SIngo Molnar 
223*86470930SIngo Molnar /**
224*86470930SIngo Molnar  * elf_symtab__for_each_symbol - iterate thru all the symbols
225*86470930SIngo Molnar  *
226*86470930SIngo Molnar  * @self: struct elf_symtab instance to iterate
227*86470930SIngo Molnar  * @index: uint32_t index
228*86470930SIngo Molnar  * @sym: GElf_Sym iterator
229*86470930SIngo Molnar  */
230*86470930SIngo Molnar #define elf_symtab__for_each_symbol(syms, nr_syms, index, sym) \
231*86470930SIngo Molnar 	for (index = 0, gelf_getsym(syms, index, &sym);\
232*86470930SIngo Molnar 	     index < nr_syms; \
233*86470930SIngo Molnar 	     index++, gelf_getsym(syms, index, &sym))
234*86470930SIngo Molnar 
235*86470930SIngo Molnar static inline uint8_t elf_sym__type(const GElf_Sym *sym)
236*86470930SIngo Molnar {
237*86470930SIngo Molnar 	return GELF_ST_TYPE(sym->st_info);
238*86470930SIngo Molnar }
239*86470930SIngo Molnar 
240*86470930SIngo Molnar static inline int elf_sym__is_function(const GElf_Sym *sym)
241*86470930SIngo Molnar {
242*86470930SIngo Molnar 	return elf_sym__type(sym) == STT_FUNC &&
243*86470930SIngo Molnar 	       sym->st_name != 0 &&
244*86470930SIngo Molnar 	       sym->st_shndx != SHN_UNDEF &&
245*86470930SIngo Molnar 	       sym->st_size != 0;
246*86470930SIngo Molnar }
247*86470930SIngo Molnar 
248*86470930SIngo Molnar static inline const char *elf_sym__name(const GElf_Sym *sym,
249*86470930SIngo Molnar 					const Elf_Data *symstrs)
250*86470930SIngo Molnar {
251*86470930SIngo Molnar 	return symstrs->d_buf + sym->st_name;
252*86470930SIngo Molnar }
253*86470930SIngo Molnar 
254*86470930SIngo Molnar static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
255*86470930SIngo Molnar 				    GElf_Shdr *shp, const char *name,
256*86470930SIngo Molnar 				    size_t *index)
257*86470930SIngo Molnar {
258*86470930SIngo Molnar 	Elf_Scn *sec = NULL;
259*86470930SIngo Molnar 	size_t cnt = 1;
260*86470930SIngo Molnar 
261*86470930SIngo Molnar 	while ((sec = elf_nextscn(elf, sec)) != NULL) {
262*86470930SIngo Molnar 		char *str;
263*86470930SIngo Molnar 
264*86470930SIngo Molnar 		gelf_getshdr(sec, shp);
265*86470930SIngo Molnar 		str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name);
266*86470930SIngo Molnar 		if (!strcmp(name, str)) {
267*86470930SIngo Molnar 			if (index)
268*86470930SIngo Molnar 				*index = cnt;
269*86470930SIngo Molnar 			break;
270*86470930SIngo Molnar 		}
271*86470930SIngo Molnar 		++cnt;
272*86470930SIngo Molnar 	}
273*86470930SIngo Molnar 
274*86470930SIngo Molnar 	return sec;
275*86470930SIngo Molnar }
276*86470930SIngo Molnar 
277*86470930SIngo Molnar #define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \
278*86470930SIngo Molnar 	for (idx = 0, pos = gelf_getrel(reldata, 0, &pos_mem); \
279*86470930SIngo Molnar 	     idx < nr_entries; \
280*86470930SIngo Molnar 	     ++idx, pos = gelf_getrel(reldata, idx, &pos_mem))
281*86470930SIngo Molnar 
282*86470930SIngo Molnar #define elf_section__for_each_rela(reldata, pos, pos_mem, idx, nr_entries) \
283*86470930SIngo Molnar 	for (idx = 0, pos = gelf_getrela(reldata, 0, &pos_mem); \
284*86470930SIngo Molnar 	     idx < nr_entries; \
285*86470930SIngo Molnar 	     ++idx, pos = gelf_getrela(reldata, idx, &pos_mem))
286*86470930SIngo Molnar 
287*86470930SIngo Molnar static int dso__synthesize_plt_symbols(struct  dso *self, Elf *elf,
288*86470930SIngo Molnar 				       GElf_Ehdr *ehdr, Elf_Scn *scn_dynsym,
289*86470930SIngo Molnar 				       GElf_Shdr *shdr_dynsym,
290*86470930SIngo Molnar 				       size_t dynsym_idx, int verbose)
291*86470930SIngo Molnar {
292*86470930SIngo Molnar 	uint32_t nr_rel_entries, idx;
293*86470930SIngo Molnar 	GElf_Sym sym;
294*86470930SIngo Molnar 	__u64 plt_offset;
295*86470930SIngo Molnar 	GElf_Shdr shdr_plt;
296*86470930SIngo Molnar 	struct symbol *f;
297*86470930SIngo Molnar 	GElf_Shdr shdr_rel_plt;
298*86470930SIngo Molnar 	Elf_Data *reldata, *syms, *symstrs;
299*86470930SIngo Molnar 	Elf_Scn *scn_plt_rel, *scn_symstrs;
300*86470930SIngo Molnar 	char sympltname[1024];
301*86470930SIngo Molnar 	int nr = 0, symidx;
302*86470930SIngo Molnar 
303*86470930SIngo Molnar 	scn_plt_rel = elf_section_by_name(elf, ehdr, &shdr_rel_plt,
304*86470930SIngo Molnar 					  ".rela.plt", NULL);
305*86470930SIngo Molnar 	if (scn_plt_rel == NULL) {
306*86470930SIngo Molnar 		scn_plt_rel = elf_section_by_name(elf, ehdr, &shdr_rel_plt,
307*86470930SIngo Molnar 						  ".rel.plt", NULL);
308*86470930SIngo Molnar 		if (scn_plt_rel == NULL)
309*86470930SIngo Molnar 			return 0;
310*86470930SIngo Molnar 	}
311*86470930SIngo Molnar 
312*86470930SIngo Molnar 	if (shdr_rel_plt.sh_link != dynsym_idx)
313*86470930SIngo Molnar 		return 0;
314*86470930SIngo Molnar 
315*86470930SIngo Molnar 	if (elf_section_by_name(elf, ehdr, &shdr_plt, ".plt", NULL) == NULL)
316*86470930SIngo Molnar 		return 0;
317*86470930SIngo Molnar 
318*86470930SIngo Molnar 	/*
319*86470930SIngo Molnar 	 * Fetch the relocation section to find the indexes to the GOT
320*86470930SIngo Molnar 	 * and the symbols in the .dynsym they refer to.
321*86470930SIngo Molnar 	 */
322*86470930SIngo Molnar 	reldata = elf_getdata(scn_plt_rel, NULL);
323*86470930SIngo Molnar 	if (reldata == NULL)
324*86470930SIngo Molnar 		return -1;
325*86470930SIngo Molnar 
326*86470930SIngo Molnar 	syms = elf_getdata(scn_dynsym, NULL);
327*86470930SIngo Molnar 	if (syms == NULL)
328*86470930SIngo Molnar 		return -1;
329*86470930SIngo Molnar 
330*86470930SIngo Molnar 	scn_symstrs = elf_getscn(elf, shdr_dynsym->sh_link);
331*86470930SIngo Molnar 	if (scn_symstrs == NULL)
332*86470930SIngo Molnar 		return -1;
333*86470930SIngo Molnar 
334*86470930SIngo Molnar 	symstrs = elf_getdata(scn_symstrs, NULL);
335*86470930SIngo Molnar 	if (symstrs == NULL)
336*86470930SIngo Molnar 		return -1;
337*86470930SIngo Molnar 
338*86470930SIngo Molnar 	nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize;
339*86470930SIngo Molnar 	plt_offset = shdr_plt.sh_offset;
340*86470930SIngo Molnar 
341*86470930SIngo Molnar 	if (shdr_rel_plt.sh_type == SHT_RELA) {
342*86470930SIngo Molnar 		GElf_Rela pos_mem, *pos;
343*86470930SIngo Molnar 
344*86470930SIngo Molnar 		elf_section__for_each_rela(reldata, pos, pos_mem, idx,
345*86470930SIngo Molnar 					   nr_rel_entries) {
346*86470930SIngo Molnar 			symidx = GELF_R_SYM(pos->r_info);
347*86470930SIngo Molnar 			plt_offset += shdr_plt.sh_entsize;
348*86470930SIngo Molnar 			gelf_getsym(syms, symidx, &sym);
349*86470930SIngo Molnar 			snprintf(sympltname, sizeof(sympltname),
350*86470930SIngo Molnar 				 "%s@plt", elf_sym__name(&sym, symstrs));
351*86470930SIngo Molnar 
352*86470930SIngo Molnar 			f = symbol__new(plt_offset, shdr_plt.sh_entsize,
353*86470930SIngo Molnar 					sympltname, self->sym_priv_size, 0, verbose);
354*86470930SIngo Molnar 			if (!f)
355*86470930SIngo Molnar 				return -1;
356*86470930SIngo Molnar 
357*86470930SIngo Molnar 			dso__insert_symbol(self, f);
358*86470930SIngo Molnar 			++nr;
359*86470930SIngo Molnar 		}
360*86470930SIngo Molnar 	} else if (shdr_rel_plt.sh_type == SHT_REL) {
361*86470930SIngo Molnar 		GElf_Rel pos_mem, *pos;
362*86470930SIngo Molnar 		elf_section__for_each_rel(reldata, pos, pos_mem, idx,
363*86470930SIngo Molnar 					  nr_rel_entries) {
364*86470930SIngo Molnar 			symidx = GELF_R_SYM(pos->r_info);
365*86470930SIngo Molnar 			plt_offset += shdr_plt.sh_entsize;
366*86470930SIngo Molnar 			gelf_getsym(syms, symidx, &sym);
367*86470930SIngo Molnar 			snprintf(sympltname, sizeof(sympltname),
368*86470930SIngo Molnar 				 "%s@plt", elf_sym__name(&sym, symstrs));
369*86470930SIngo Molnar 
370*86470930SIngo Molnar 			f = symbol__new(plt_offset, shdr_plt.sh_entsize,
371*86470930SIngo Molnar 					sympltname, self->sym_priv_size, 0, verbose);
372*86470930SIngo Molnar 			if (!f)
373*86470930SIngo Molnar 				return -1;
374*86470930SIngo Molnar 
375*86470930SIngo Molnar 			dso__insert_symbol(self, f);
376*86470930SIngo Molnar 			++nr;
377*86470930SIngo Molnar 		}
378*86470930SIngo Molnar 	} else {
379*86470930SIngo Molnar 		/*
380*86470930SIngo Molnar 		 * TODO: There are still one more shdr_rel_plt.sh_type
381*86470930SIngo Molnar 		 * I have to investigate, but probably should be ignored.
382*86470930SIngo Molnar 		 */
383*86470930SIngo Molnar 	}
384*86470930SIngo Molnar 
385*86470930SIngo Molnar 	return nr;
386*86470930SIngo Molnar }
387*86470930SIngo Molnar 
388*86470930SIngo Molnar static int dso__load_sym(struct dso *self, int fd, const char *name,
389*86470930SIngo Molnar 			 symbol_filter_t filter, int verbose)
390*86470930SIngo Molnar {
391*86470930SIngo Molnar 	Elf_Data *symstrs;
392*86470930SIngo Molnar 	uint32_t nr_syms;
393*86470930SIngo Molnar 	int err = -1;
394*86470930SIngo Molnar 	uint32_t index;
395*86470930SIngo Molnar 	GElf_Ehdr ehdr;
396*86470930SIngo Molnar 	GElf_Shdr shdr;
397*86470930SIngo Molnar 	Elf_Data *syms;
398*86470930SIngo Molnar 	GElf_Sym sym;
399*86470930SIngo Molnar 	Elf_Scn *sec, *sec_dynsym;
400*86470930SIngo Molnar 	Elf *elf;
401*86470930SIngo Molnar 	size_t dynsym_idx;
402*86470930SIngo Molnar 	int nr = 0;
403*86470930SIngo Molnar 
404*86470930SIngo Molnar 	elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
405*86470930SIngo Molnar 	if (elf == NULL) {
406*86470930SIngo Molnar 		if (verbose)
407*86470930SIngo Molnar 			fprintf(stderr, "%s: cannot read %s ELF file.\n",
408*86470930SIngo Molnar 				__func__, name);
409*86470930SIngo Molnar 		goto out_close;
410*86470930SIngo Molnar 	}
411*86470930SIngo Molnar 
412*86470930SIngo Molnar 	if (gelf_getehdr(elf, &ehdr) == NULL) {
413*86470930SIngo Molnar 		if (verbose)
414*86470930SIngo Molnar 			fprintf(stderr, "%s: cannot get elf header.\n", __func__);
415*86470930SIngo Molnar 		goto out_elf_end;
416*86470930SIngo Molnar 	}
417*86470930SIngo Molnar 
418*86470930SIngo Molnar 	/*
419*86470930SIngo Molnar 	 * We need to check if we have a .dynsym, so that we can handle the
420*86470930SIngo Molnar 	 * .plt, synthesizing its symbols, that aren't on the symtabs (be it
421*86470930SIngo Molnar 	 * .dynsym or .symtab)
422*86470930SIngo Molnar 	 */
423*86470930SIngo Molnar 	sec_dynsym = elf_section_by_name(elf, &ehdr, &shdr,
424*86470930SIngo Molnar 					 ".dynsym", &dynsym_idx);
425*86470930SIngo Molnar 	if (sec_dynsym != NULL) {
426*86470930SIngo Molnar 		nr = dso__synthesize_plt_symbols(self, elf, &ehdr,
427*86470930SIngo Molnar 						 sec_dynsym, &shdr,
428*86470930SIngo Molnar 						 dynsym_idx, verbose);
429*86470930SIngo Molnar 		if (nr < 0)
430*86470930SIngo Molnar 			goto out_elf_end;
431*86470930SIngo Molnar 	}
432*86470930SIngo Molnar 
433*86470930SIngo Molnar 	/*
434*86470930SIngo Molnar 	 * But if we have a full .symtab (that is a superset of .dynsym) we
435*86470930SIngo Molnar 	 * should add the symbols not in the .dynsyn
436*86470930SIngo Molnar 	 */
437*86470930SIngo Molnar 	sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL);
438*86470930SIngo Molnar 	if (sec == NULL) {
439*86470930SIngo Molnar 		if (sec_dynsym == NULL)
440*86470930SIngo Molnar 			goto out_elf_end;
441*86470930SIngo Molnar 
442*86470930SIngo Molnar 		sec = sec_dynsym;
443*86470930SIngo Molnar 		gelf_getshdr(sec, &shdr);
444*86470930SIngo Molnar 	}
445*86470930SIngo Molnar 
446*86470930SIngo Molnar 	syms = elf_getdata(sec, NULL);
447*86470930SIngo Molnar 	if (syms == NULL)
448*86470930SIngo Molnar 		goto out_elf_end;
449*86470930SIngo Molnar 
450*86470930SIngo Molnar 	sec = elf_getscn(elf, shdr.sh_link);
451*86470930SIngo Molnar 	if (sec == NULL)
452*86470930SIngo Molnar 		goto out_elf_end;
453*86470930SIngo Molnar 
454*86470930SIngo Molnar 	symstrs = elf_getdata(sec, NULL);
455*86470930SIngo Molnar 	if (symstrs == NULL)
456*86470930SIngo Molnar 		goto out_elf_end;
457*86470930SIngo Molnar 
458*86470930SIngo Molnar 	nr_syms = shdr.sh_size / shdr.sh_entsize;
459*86470930SIngo Molnar 
460*86470930SIngo Molnar 	elf_symtab__for_each_symbol(syms, nr_syms, index, sym) {
461*86470930SIngo Molnar 		struct symbol *f;
462*86470930SIngo Molnar 		uint64_t obj_start;
463*86470930SIngo Molnar 
464*86470930SIngo Molnar 		if (!elf_sym__is_function(&sym))
465*86470930SIngo Molnar 			continue;
466*86470930SIngo Molnar 
467*86470930SIngo Molnar 		sec = elf_getscn(elf, sym.st_shndx);
468*86470930SIngo Molnar 		if (!sec)
469*86470930SIngo Molnar 			goto out_elf_end;
470*86470930SIngo Molnar 
471*86470930SIngo Molnar 		gelf_getshdr(sec, &shdr);
472*86470930SIngo Molnar 		obj_start = sym.st_value;
473*86470930SIngo Molnar 
474*86470930SIngo Molnar 		sym.st_value -= shdr.sh_addr - shdr.sh_offset;
475*86470930SIngo Molnar 
476*86470930SIngo Molnar 		f = symbol__new(sym.st_value, sym.st_size,
477*86470930SIngo Molnar 				elf_sym__name(&sym, symstrs),
478*86470930SIngo Molnar 				self->sym_priv_size, obj_start, verbose);
479*86470930SIngo Molnar 		if (!f)
480*86470930SIngo Molnar 			goto out_elf_end;
481*86470930SIngo Molnar 
482*86470930SIngo Molnar 		if (filter && filter(self, f))
483*86470930SIngo Molnar 			symbol__delete(f, self->sym_priv_size);
484*86470930SIngo Molnar 		else {
485*86470930SIngo Molnar 			dso__insert_symbol(self, f);
486*86470930SIngo Molnar 			nr++;
487*86470930SIngo Molnar 		}
488*86470930SIngo Molnar 	}
489*86470930SIngo Molnar 
490*86470930SIngo Molnar 	err = nr;
491*86470930SIngo Molnar out_elf_end:
492*86470930SIngo Molnar 	elf_end(elf);
493*86470930SIngo Molnar out_close:
494*86470930SIngo Molnar 	return err;
495*86470930SIngo Molnar }
496*86470930SIngo Molnar 
497*86470930SIngo Molnar int dso__load(struct dso *self, symbol_filter_t filter, int verbose)
498*86470930SIngo Molnar {
499*86470930SIngo Molnar 	int size = strlen(self->name) + sizeof("/usr/lib/debug%s.debug");
500*86470930SIngo Molnar 	char *name = malloc(size);
501*86470930SIngo Molnar 	int variant = 0;
502*86470930SIngo Molnar 	int ret = -1;
503*86470930SIngo Molnar 	int fd;
504*86470930SIngo Molnar 
505*86470930SIngo Molnar 	if (!name)
506*86470930SIngo Molnar 		return -1;
507*86470930SIngo Molnar 
508*86470930SIngo Molnar more:
509*86470930SIngo Molnar 	do {
510*86470930SIngo Molnar 		switch (variant) {
511*86470930SIngo Molnar 		case 0: /* Fedora */
512*86470930SIngo Molnar 			snprintf(name, size, "/usr/lib/debug%s.debug", self->name);
513*86470930SIngo Molnar 			break;
514*86470930SIngo Molnar 		case 1: /* Ubuntu */
515*86470930SIngo Molnar 			snprintf(name, size, "/usr/lib/debug%s", self->name);
516*86470930SIngo Molnar 			break;
517*86470930SIngo Molnar 		case 2: /* Sane people */
518*86470930SIngo Molnar 			snprintf(name, size, "%s", self->name);
519*86470930SIngo Molnar 			break;
520*86470930SIngo Molnar 
521*86470930SIngo Molnar 		default:
522*86470930SIngo Molnar 			goto out;
523*86470930SIngo Molnar 		}
524*86470930SIngo Molnar 		variant++;
525*86470930SIngo Molnar 
526*86470930SIngo Molnar 		fd = open(name, O_RDONLY);
527*86470930SIngo Molnar 	} while (fd < 0);
528*86470930SIngo Molnar 
529*86470930SIngo Molnar 	ret = dso__load_sym(self, fd, name, filter, verbose);
530*86470930SIngo Molnar 	close(fd);
531*86470930SIngo Molnar 
532*86470930SIngo Molnar 	/*
533*86470930SIngo Molnar 	 * Some people seem to have debuginfo files _WITHOUT_ debug info!?!?
534*86470930SIngo Molnar 	 */
535*86470930SIngo Molnar 	if (!ret)
536*86470930SIngo Molnar 		goto more;
537*86470930SIngo Molnar 
538*86470930SIngo Molnar out:
539*86470930SIngo Molnar 	free(name);
540*86470930SIngo Molnar 	return ret;
541*86470930SIngo Molnar }
542*86470930SIngo Molnar 
543*86470930SIngo Molnar static int dso__load_vmlinux(struct dso *self, const char *vmlinux,
544*86470930SIngo Molnar 			     symbol_filter_t filter, int verbose)
545*86470930SIngo Molnar {
546*86470930SIngo Molnar 	int err, fd = open(vmlinux, O_RDONLY);
547*86470930SIngo Molnar 
548*86470930SIngo Molnar 	if (fd < 0)
549*86470930SIngo Molnar 		return -1;
550*86470930SIngo Molnar 
551*86470930SIngo Molnar 	err = dso__load_sym(self, fd, vmlinux, filter, verbose);
552*86470930SIngo Molnar 	close(fd);
553*86470930SIngo Molnar 
554*86470930SIngo Molnar 	return err;
555*86470930SIngo Molnar }
556*86470930SIngo Molnar 
557*86470930SIngo Molnar int dso__load_kernel(struct dso *self, const char *vmlinux,
558*86470930SIngo Molnar 		     symbol_filter_t filter, int verbose)
559*86470930SIngo Molnar {
560*86470930SIngo Molnar 	int err = -1;
561*86470930SIngo Molnar 
562*86470930SIngo Molnar 	if (vmlinux)
563*86470930SIngo Molnar 		err = dso__load_vmlinux(self, vmlinux, filter, verbose);
564*86470930SIngo Molnar 
565*86470930SIngo Molnar 	if (err)
566*86470930SIngo Molnar 		err = dso__load_kallsyms(self, filter, verbose);
567*86470930SIngo Molnar 
568*86470930SIngo Molnar 	return err;
569*86470930SIngo Molnar }
570*86470930SIngo Molnar 
571*86470930SIngo Molnar void symbol__init(void)
572*86470930SIngo Molnar {
573*86470930SIngo Molnar 	elf_version(EV_CURRENT);
574*86470930SIngo Molnar }
575