xref: /linux/tools/perf/util/symbol.c (revision 52d422de22b26d96bbdfbc605eb31c2994df6d0b)
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