xref: /linux/tools/perf/util/symbol.c (revision 8f28827a162fd1e8da4e96bed69b06d2606e8322)
186470930SIngo Molnar #include "util.h"
286470930SIngo Molnar #include "../perf.h"
386470930SIngo Molnar #include "string.h"
486470930SIngo Molnar #include "symbol.h"
586470930SIngo Molnar 
6*8f28827aSFrederic Weisbecker #include "debug.h"
7*8f28827aSFrederic Weisbecker 
886470930SIngo Molnar #include <libelf.h>
986470930SIngo Molnar #include <gelf.h>
1086470930SIngo Molnar #include <elf.h>
112cdbc46dSPeter Zijlstra 
1286470930SIngo Molnar const char *sym_hist_filter;
1386470930SIngo Molnar 
1494cb9e38SArnaldo Carvalho de Melo enum dso_origin {
1594cb9e38SArnaldo Carvalho de Melo 	DSO__ORIG_KERNEL = 0,
1694cb9e38SArnaldo Carvalho de Melo 	DSO__ORIG_JAVA_JIT,
1794cb9e38SArnaldo Carvalho de Melo 	DSO__ORIG_FEDORA,
1894cb9e38SArnaldo Carvalho de Melo 	DSO__ORIG_UBUNTU,
1994cb9e38SArnaldo Carvalho de Melo 	DSO__ORIG_BUILDID,
2094cb9e38SArnaldo Carvalho de Melo 	DSO__ORIG_DSO,
2194cb9e38SArnaldo Carvalho de Melo 	DSO__ORIG_NOT_FOUND,
2294cb9e38SArnaldo Carvalho de Melo };
2394cb9e38SArnaldo Carvalho de Melo 
249cffa8d5SPaul Mackerras static struct symbol *symbol__new(u64 start, u64 len,
2586470930SIngo Molnar 				  const char *name, unsigned int priv_size,
2683a0944fSIngo Molnar 				  u64 obj_start, int v)
2786470930SIngo Molnar {
2886470930SIngo Molnar 	size_t namelen = strlen(name) + 1;
2986470930SIngo Molnar 	struct symbol *self = calloc(1, priv_size + sizeof(*self) + namelen);
3086470930SIngo Molnar 
3186470930SIngo Molnar 	if (!self)
3286470930SIngo Molnar 		return NULL;
3386470930SIngo Molnar 
3483a0944fSIngo Molnar 	if (v >= 2)
3586470930SIngo Molnar 		printf("new symbol: %016Lx [%08lx]: %s, hist: %p, obj_start: %p\n",
369cffa8d5SPaul Mackerras 			(u64)start, (unsigned long)len, name, self->hist, (void *)(unsigned long)obj_start);
3786470930SIngo Molnar 
3886470930SIngo Molnar 	self->obj_start= obj_start;
3986470930SIngo Molnar 	self->hist = NULL;
4086470930SIngo Molnar 	self->hist_sum = 0;
4186470930SIngo Molnar 
4286470930SIngo Molnar 	if (sym_hist_filter && !strcmp(name, sym_hist_filter))
439cffa8d5SPaul Mackerras 		self->hist = calloc(sizeof(u64), len);
4486470930SIngo Molnar 
4586470930SIngo Molnar 	if (priv_size) {
4686470930SIngo Molnar 		memset(self, 0, priv_size);
4786470930SIngo Molnar 		self = ((void *)self) + priv_size;
4886470930SIngo Molnar 	}
4986470930SIngo Molnar 	self->start = start;
506cfcc53eSMike Galbraith 	self->end   = len ? start + len - 1 : start;
5186470930SIngo Molnar 	memcpy(self->name, name, namelen);
5286470930SIngo Molnar 
5386470930SIngo Molnar 	return self;
5486470930SIngo Molnar }
5586470930SIngo Molnar 
5686470930SIngo Molnar static void symbol__delete(struct symbol *self, unsigned int priv_size)
5786470930SIngo Molnar {
5886470930SIngo Molnar 	free(((void *)self) - priv_size);
5986470930SIngo Molnar }
6086470930SIngo Molnar 
6186470930SIngo Molnar static size_t symbol__fprintf(struct symbol *self, FILE *fp)
6286470930SIngo Molnar {
636cfcc53eSMike Galbraith 	if (!self->module)
6486470930SIngo Molnar 		return fprintf(fp, " %llx-%llx %s\n",
6586470930SIngo Molnar 		       self->start, self->end, self->name);
666cfcc53eSMike Galbraith 	else
676cfcc53eSMike Galbraith 		return fprintf(fp, " %llx-%llx %s \t[%s]\n",
686cfcc53eSMike Galbraith 		       self->start, self->end, self->name, self->module->name);
6986470930SIngo Molnar }
7086470930SIngo Molnar 
7186470930SIngo Molnar struct dso *dso__new(const char *name, unsigned int sym_priv_size)
7286470930SIngo Molnar {
7386470930SIngo Molnar 	struct dso *self = malloc(sizeof(*self) + strlen(name) + 1);
7486470930SIngo Molnar 
7586470930SIngo Molnar 	if (self != NULL) {
7686470930SIngo Molnar 		strcpy(self->name, name);
7786470930SIngo Molnar 		self->syms = RB_ROOT;
7886470930SIngo Molnar 		self->sym_priv_size = sym_priv_size;
7986470930SIngo Molnar 		self->find_symbol = dso__find_symbol;
8052d422deSArnaldo Carvalho de Melo 		self->slen_calculated = 0;
8194cb9e38SArnaldo Carvalho de Melo 		self->origin = DSO__ORIG_NOT_FOUND;
8286470930SIngo Molnar 	}
8386470930SIngo Molnar 
8486470930SIngo Molnar 	return self;
8586470930SIngo Molnar }
8686470930SIngo Molnar 
8786470930SIngo Molnar static void dso__delete_symbols(struct dso *self)
8886470930SIngo Molnar {
8986470930SIngo Molnar 	struct symbol *pos;
9086470930SIngo Molnar 	struct rb_node *next = rb_first(&self->syms);
9186470930SIngo Molnar 
9286470930SIngo Molnar 	while (next) {
9386470930SIngo Molnar 		pos = rb_entry(next, struct symbol, rb_node);
9486470930SIngo Molnar 		next = rb_next(&pos->rb_node);
9586470930SIngo Molnar 		rb_erase(&pos->rb_node, &self->syms);
9686470930SIngo Molnar 		symbol__delete(pos, self->sym_priv_size);
9786470930SIngo Molnar 	}
9886470930SIngo Molnar }
9986470930SIngo Molnar 
10086470930SIngo Molnar void dso__delete(struct dso *self)
10186470930SIngo Molnar {
10286470930SIngo Molnar 	dso__delete_symbols(self);
10386470930SIngo Molnar 	free(self);
10486470930SIngo Molnar }
10586470930SIngo Molnar 
10686470930SIngo Molnar static void dso__insert_symbol(struct dso *self, struct symbol *sym)
10786470930SIngo Molnar {
10886470930SIngo Molnar 	struct rb_node **p = &self->syms.rb_node;
10986470930SIngo Molnar 	struct rb_node *parent = NULL;
1109cffa8d5SPaul Mackerras 	const u64 ip = sym->start;
11186470930SIngo Molnar 	struct symbol *s;
11286470930SIngo Molnar 
11386470930SIngo Molnar 	while (*p != NULL) {
11486470930SIngo Molnar 		parent = *p;
11586470930SIngo Molnar 		s = rb_entry(parent, struct symbol, rb_node);
11686470930SIngo Molnar 		if (ip < s->start)
11786470930SIngo Molnar 			p = &(*p)->rb_left;
11886470930SIngo Molnar 		else
11986470930SIngo Molnar 			p = &(*p)->rb_right;
12086470930SIngo Molnar 	}
12186470930SIngo Molnar 	rb_link_node(&sym->rb_node, parent, p);
12286470930SIngo Molnar 	rb_insert_color(&sym->rb_node, &self->syms);
12386470930SIngo Molnar }
12486470930SIngo Molnar 
1259cffa8d5SPaul Mackerras struct symbol *dso__find_symbol(struct dso *self, u64 ip)
12686470930SIngo Molnar {
12786470930SIngo Molnar 	struct rb_node *n;
12886470930SIngo Molnar 
12986470930SIngo Molnar 	if (self == NULL)
13086470930SIngo Molnar 		return NULL;
13186470930SIngo Molnar 
13286470930SIngo Molnar 	n = self->syms.rb_node;
13386470930SIngo Molnar 
13486470930SIngo Molnar 	while (n) {
13586470930SIngo Molnar 		struct symbol *s = rb_entry(n, struct symbol, rb_node);
13686470930SIngo Molnar 
13786470930SIngo Molnar 		if (ip < s->start)
13886470930SIngo Molnar 			n = n->rb_left;
13986470930SIngo Molnar 		else if (ip > s->end)
14086470930SIngo Molnar 			n = n->rb_right;
14186470930SIngo Molnar 		else
14286470930SIngo Molnar 			return s;
14386470930SIngo Molnar 	}
14486470930SIngo Molnar 
14586470930SIngo Molnar 	return NULL;
14686470930SIngo Molnar }
14786470930SIngo Molnar 
14886470930SIngo Molnar size_t dso__fprintf(struct dso *self, FILE *fp)
14986470930SIngo Molnar {
15086470930SIngo Molnar 	size_t ret = fprintf(fp, "dso: %s\n", self->name);
15186470930SIngo Molnar 
15286470930SIngo Molnar 	struct rb_node *nd;
15386470930SIngo Molnar 	for (nd = rb_first(&self->syms); nd; nd = rb_next(nd)) {
15486470930SIngo Molnar 		struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
15586470930SIngo Molnar 		ret += symbol__fprintf(pos, fp);
15686470930SIngo Molnar 	}
15786470930SIngo Molnar 
15886470930SIngo Molnar 	return ret;
15986470930SIngo Molnar }
16086470930SIngo Molnar 
16183a0944fSIngo Molnar static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int v)
16286470930SIngo Molnar {
16386470930SIngo Molnar 	struct rb_node *nd, *prevnd;
16486470930SIngo Molnar 	char *line = NULL;
16586470930SIngo Molnar 	size_t n;
16686470930SIngo Molnar 	FILE *file = fopen("/proc/kallsyms", "r");
1679974f496SMike Galbraith 	int count = 0;
16886470930SIngo Molnar 
16986470930SIngo Molnar 	if (file == NULL)
17086470930SIngo Molnar 		goto out_failure;
17186470930SIngo Molnar 
17286470930SIngo Molnar 	while (!feof(file)) {
1739cffa8d5SPaul Mackerras 		u64 start;
17486470930SIngo Molnar 		struct symbol *sym;
17586470930SIngo Molnar 		int line_len, len;
17686470930SIngo Molnar 		char symbol_type;
17786470930SIngo Molnar 
17886470930SIngo Molnar 		line_len = getline(&line, &n, file);
17986470930SIngo Molnar 		if (line_len < 0)
18086470930SIngo Molnar 			break;
18186470930SIngo Molnar 
18286470930SIngo Molnar 		if (!line)
18386470930SIngo Molnar 			goto out_failure;
18486470930SIngo Molnar 
18586470930SIngo Molnar 		line[--line_len] = '\0'; /* \n */
18686470930SIngo Molnar 
18786470930SIngo Molnar 		len = hex2u64(line, &start);
18886470930SIngo Molnar 
18986470930SIngo Molnar 		len++;
19086470930SIngo Molnar 		if (len + 2 >= line_len)
19186470930SIngo Molnar 			continue;
19286470930SIngo Molnar 
19386470930SIngo Molnar 		symbol_type = toupper(line[len]);
19486470930SIngo Molnar 		/*
19586470930SIngo Molnar 		 * We're interested only in code ('T'ext)
19686470930SIngo Molnar 		 */
19786470930SIngo Molnar 		if (symbol_type != 'T' && symbol_type != 'W')
19886470930SIngo Molnar 			continue;
19986470930SIngo Molnar 		/*
20086470930SIngo Molnar 		 * Well fix up the end later, when we have all sorted.
20186470930SIngo Molnar 		 */
20286470930SIngo Molnar 		sym = symbol__new(start, 0xdead, line + len + 2,
20383a0944fSIngo Molnar 				  self->sym_priv_size, 0, v);
20486470930SIngo Molnar 
20586470930SIngo Molnar 		if (sym == NULL)
20686470930SIngo Molnar 			goto out_delete_line;
20786470930SIngo Molnar 
20886470930SIngo Molnar 		if (filter && filter(self, sym))
20986470930SIngo Molnar 			symbol__delete(sym, self->sym_priv_size);
2109974f496SMike Galbraith 		else {
21186470930SIngo Molnar 			dso__insert_symbol(self, sym);
2129974f496SMike Galbraith 			count++;
2139974f496SMike Galbraith 		}
21486470930SIngo Molnar 	}
21586470930SIngo Molnar 
21686470930SIngo Molnar 	/*
21786470930SIngo Molnar 	 * Now that we have all sorted out, just set the ->end of all
21886470930SIngo Molnar 	 * symbols
21986470930SIngo Molnar 	 */
22086470930SIngo Molnar 	prevnd = rb_first(&self->syms);
22186470930SIngo Molnar 
22286470930SIngo Molnar 	if (prevnd == NULL)
22386470930SIngo Molnar 		goto out_delete_line;
22486470930SIngo Molnar 
22586470930SIngo Molnar 	for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
22686470930SIngo Molnar 		struct symbol *prev = rb_entry(prevnd, struct symbol, rb_node),
22786470930SIngo Molnar 			      *curr = rb_entry(nd, struct symbol, rb_node);
22886470930SIngo Molnar 
22986470930SIngo Molnar 		prev->end = curr->start - 1;
23086470930SIngo Molnar 		prevnd = nd;
23186470930SIngo Molnar 	}
23286470930SIngo Molnar 
23386470930SIngo Molnar 	free(line);
23486470930SIngo Molnar 	fclose(file);
23586470930SIngo Molnar 
2369974f496SMike Galbraith 	return count;
23786470930SIngo Molnar 
23886470930SIngo Molnar out_delete_line:
23986470930SIngo Molnar 	free(line);
24086470930SIngo Molnar out_failure:
24186470930SIngo Molnar 	return -1;
24286470930SIngo Molnar }
24386470930SIngo Molnar 
24483a0944fSIngo Molnar static int dso__load_perf_map(struct dso *self, symbol_filter_t filter, int v)
24580d496beSPekka Enberg {
24680d496beSPekka Enberg 	char *line = NULL;
24780d496beSPekka Enberg 	size_t n;
24880d496beSPekka Enberg 	FILE *file;
24980d496beSPekka Enberg 	int nr_syms = 0;
25080d496beSPekka Enberg 
25180d496beSPekka Enberg 	file = fopen(self->name, "r");
25280d496beSPekka Enberg 	if (file == NULL)
25380d496beSPekka Enberg 		goto out_failure;
25480d496beSPekka Enberg 
25580d496beSPekka Enberg 	while (!feof(file)) {
2569cffa8d5SPaul Mackerras 		u64 start, size;
25780d496beSPekka Enberg 		struct symbol *sym;
25880d496beSPekka Enberg 		int line_len, len;
25980d496beSPekka Enberg 
26080d496beSPekka Enberg 		line_len = getline(&line, &n, file);
26180d496beSPekka Enberg 		if (line_len < 0)
26280d496beSPekka Enberg 			break;
26380d496beSPekka Enberg 
26480d496beSPekka Enberg 		if (!line)
26580d496beSPekka Enberg 			goto out_failure;
26680d496beSPekka Enberg 
26780d496beSPekka Enberg 		line[--line_len] = '\0'; /* \n */
26880d496beSPekka Enberg 
26980d496beSPekka Enberg 		len = hex2u64(line, &start);
27080d496beSPekka Enberg 
27180d496beSPekka Enberg 		len++;
27280d496beSPekka Enberg 		if (len + 2 >= line_len)
27380d496beSPekka Enberg 			continue;
27480d496beSPekka Enberg 
27580d496beSPekka Enberg 		len += hex2u64(line + len, &size);
27680d496beSPekka Enberg 
27780d496beSPekka Enberg 		len++;
27880d496beSPekka Enberg 		if (len + 2 >= line_len)
27980d496beSPekka Enberg 			continue;
28080d496beSPekka Enberg 
28180d496beSPekka Enberg 		sym = symbol__new(start, size, line + len,
28283a0944fSIngo Molnar 				  self->sym_priv_size, start, v);
28380d496beSPekka Enberg 
28480d496beSPekka Enberg 		if (sym == NULL)
28580d496beSPekka Enberg 			goto out_delete_line;
28680d496beSPekka Enberg 
28780d496beSPekka Enberg 		if (filter && filter(self, sym))
28880d496beSPekka Enberg 			symbol__delete(sym, self->sym_priv_size);
28980d496beSPekka Enberg 		else {
29080d496beSPekka Enberg 			dso__insert_symbol(self, sym);
29180d496beSPekka Enberg 			nr_syms++;
29280d496beSPekka Enberg 		}
29380d496beSPekka Enberg 	}
29480d496beSPekka Enberg 
29580d496beSPekka Enberg 	free(line);
29680d496beSPekka Enberg 	fclose(file);
29780d496beSPekka Enberg 
29880d496beSPekka Enberg 	return nr_syms;
29980d496beSPekka Enberg 
30080d496beSPekka Enberg out_delete_line:
30180d496beSPekka Enberg 	free(line);
30280d496beSPekka Enberg out_failure:
30380d496beSPekka Enberg 	return -1;
30480d496beSPekka Enberg }
30580d496beSPekka Enberg 
30686470930SIngo Molnar /**
30786470930SIngo Molnar  * elf_symtab__for_each_symbol - iterate thru all the symbols
30886470930SIngo Molnar  *
30986470930SIngo Molnar  * @self: struct elf_symtab instance to iterate
31083a0944fSIngo Molnar  * @idx: uint32_t idx
31186470930SIngo Molnar  * @sym: GElf_Sym iterator
31286470930SIngo Molnar  */
31383a0944fSIngo Molnar #define elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) \
31483a0944fSIngo Molnar 	for (idx = 0, gelf_getsym(syms, idx, &sym);\
31583a0944fSIngo Molnar 	     idx < nr_syms; \
31683a0944fSIngo Molnar 	     idx++, gelf_getsym(syms, idx, &sym))
31786470930SIngo Molnar 
31886470930SIngo Molnar static inline uint8_t elf_sym__type(const GElf_Sym *sym)
31986470930SIngo Molnar {
32086470930SIngo Molnar 	return GELF_ST_TYPE(sym->st_info);
32186470930SIngo Molnar }
32286470930SIngo Molnar 
32386470930SIngo Molnar static inline int elf_sym__is_function(const GElf_Sym *sym)
32486470930SIngo Molnar {
32586470930SIngo Molnar 	return elf_sym__type(sym) == STT_FUNC &&
32686470930SIngo Molnar 	       sym->st_name != 0 &&
32786470930SIngo Molnar 	       sym->st_shndx != SHN_UNDEF &&
32886470930SIngo Molnar 	       sym->st_size != 0;
32986470930SIngo Molnar }
33086470930SIngo Molnar 
3316cfcc53eSMike Galbraith static inline int elf_sym__is_label(const GElf_Sym *sym)
3326cfcc53eSMike Galbraith {
3336cfcc53eSMike Galbraith 	return elf_sym__type(sym) == STT_NOTYPE &&
3346cfcc53eSMike Galbraith 		sym->st_name != 0 &&
3356cfcc53eSMike Galbraith 		sym->st_shndx != SHN_UNDEF &&
3366cfcc53eSMike Galbraith 		sym->st_shndx != SHN_ABS;
3376cfcc53eSMike Galbraith }
3386cfcc53eSMike Galbraith 
3396cfcc53eSMike Galbraith static inline const char *elf_sec__name(const GElf_Shdr *shdr,
3406cfcc53eSMike Galbraith 					const Elf_Data *secstrs)
3416cfcc53eSMike Galbraith {
3426cfcc53eSMike Galbraith 	return secstrs->d_buf + shdr->sh_name;
3436cfcc53eSMike Galbraith }
3446cfcc53eSMike Galbraith 
3456cfcc53eSMike Galbraith static inline int elf_sec__is_text(const GElf_Shdr *shdr,
3466cfcc53eSMike Galbraith 					const Elf_Data *secstrs)
3476cfcc53eSMike Galbraith {
3486cfcc53eSMike Galbraith 	return strstr(elf_sec__name(shdr, secstrs), "text") != NULL;
3496cfcc53eSMike Galbraith }
3506cfcc53eSMike Galbraith 
35186470930SIngo Molnar static inline const char *elf_sym__name(const GElf_Sym *sym,
35286470930SIngo Molnar 					const Elf_Data *symstrs)
35386470930SIngo Molnar {
35486470930SIngo Molnar 	return symstrs->d_buf + sym->st_name;
35586470930SIngo Molnar }
35686470930SIngo Molnar 
35786470930SIngo Molnar static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
35886470930SIngo Molnar 				    GElf_Shdr *shp, const char *name,
35983a0944fSIngo Molnar 				    size_t *idx)
36086470930SIngo Molnar {
36186470930SIngo Molnar 	Elf_Scn *sec = NULL;
36286470930SIngo Molnar 	size_t cnt = 1;
36386470930SIngo Molnar 
36486470930SIngo Molnar 	while ((sec = elf_nextscn(elf, sec)) != NULL) {
36586470930SIngo Molnar 		char *str;
36686470930SIngo Molnar 
36786470930SIngo Molnar 		gelf_getshdr(sec, shp);
36886470930SIngo Molnar 		str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name);
36986470930SIngo Molnar 		if (!strcmp(name, str)) {
37083a0944fSIngo Molnar 			if (idx)
37183a0944fSIngo Molnar 				*idx = cnt;
37286470930SIngo Molnar 			break;
37386470930SIngo Molnar 		}
37486470930SIngo Molnar 		++cnt;
37586470930SIngo Molnar 	}
37686470930SIngo Molnar 
37786470930SIngo Molnar 	return sec;
37886470930SIngo Molnar }
37986470930SIngo Molnar 
38086470930SIngo Molnar #define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \
38186470930SIngo Molnar 	for (idx = 0, pos = gelf_getrel(reldata, 0, &pos_mem); \
38286470930SIngo Molnar 	     idx < nr_entries; \
38386470930SIngo Molnar 	     ++idx, pos = gelf_getrel(reldata, idx, &pos_mem))
38486470930SIngo Molnar 
38586470930SIngo Molnar #define elf_section__for_each_rela(reldata, pos, pos_mem, idx, nr_entries) \
38686470930SIngo Molnar 	for (idx = 0, pos = gelf_getrela(reldata, 0, &pos_mem); \
38786470930SIngo Molnar 	     idx < nr_entries; \
38886470930SIngo Molnar 	     ++idx, pos = gelf_getrela(reldata, idx, &pos_mem))
38986470930SIngo Molnar 
390a25e46c4SArnaldo Carvalho de Melo /*
391a25e46c4SArnaldo Carvalho de Melo  * We need to check if we have a .dynsym, so that we can handle the
392a25e46c4SArnaldo Carvalho de Melo  * .plt, synthesizing its symbols, that aren't on the symtabs (be it
393a25e46c4SArnaldo Carvalho de Melo  * .dynsym or .symtab).
394a25e46c4SArnaldo Carvalho de Melo  * And always look at the original dso, not at debuginfo packages, that
395a25e46c4SArnaldo Carvalho de Melo  * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS).
396a25e46c4SArnaldo Carvalho de Melo  */
39783a0944fSIngo Molnar static int dso__synthesize_plt_symbols(struct  dso *self, int v)
39886470930SIngo Molnar {
39986470930SIngo Molnar 	uint32_t nr_rel_entries, idx;
40086470930SIngo Molnar 	GElf_Sym sym;
4019cffa8d5SPaul Mackerras 	u64 plt_offset;
40286470930SIngo Molnar 	GElf_Shdr shdr_plt;
40386470930SIngo Molnar 	struct symbol *f;
404a25e46c4SArnaldo Carvalho de Melo 	GElf_Shdr shdr_rel_plt, shdr_dynsym;
40586470930SIngo Molnar 	Elf_Data *reldata, *syms, *symstrs;
406a25e46c4SArnaldo Carvalho de Melo 	Elf_Scn *scn_plt_rel, *scn_symstrs, *scn_dynsym;
407a25e46c4SArnaldo Carvalho de Melo 	size_t dynsym_idx;
408a25e46c4SArnaldo Carvalho de Melo 	GElf_Ehdr ehdr;
40986470930SIngo Molnar 	char sympltname[1024];
410a25e46c4SArnaldo Carvalho de Melo 	Elf *elf;
411a25e46c4SArnaldo Carvalho de Melo 	int nr = 0, symidx, fd, err = 0;
41286470930SIngo Molnar 
413a25e46c4SArnaldo Carvalho de Melo 	fd = open(self->name, O_RDONLY);
414a25e46c4SArnaldo Carvalho de Melo 	if (fd < 0)
415a25e46c4SArnaldo Carvalho de Melo 		goto out;
416a25e46c4SArnaldo Carvalho de Melo 
417a25e46c4SArnaldo Carvalho de Melo 	elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
418a25e46c4SArnaldo Carvalho de Melo 	if (elf == NULL)
419a25e46c4SArnaldo Carvalho de Melo 		goto out_close;
420a25e46c4SArnaldo Carvalho de Melo 
421a25e46c4SArnaldo Carvalho de Melo 	if (gelf_getehdr(elf, &ehdr) == NULL)
422a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
423a25e46c4SArnaldo Carvalho de Melo 
424a25e46c4SArnaldo Carvalho de Melo 	scn_dynsym = elf_section_by_name(elf, &ehdr, &shdr_dynsym,
425a25e46c4SArnaldo Carvalho de Melo 					 ".dynsym", &dynsym_idx);
426a25e46c4SArnaldo Carvalho de Melo 	if (scn_dynsym == NULL)
427a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
428a25e46c4SArnaldo Carvalho de Melo 
429a25e46c4SArnaldo Carvalho de Melo 	scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
43086470930SIngo Molnar 					  ".rela.plt", NULL);
43186470930SIngo Molnar 	if (scn_plt_rel == NULL) {
432a25e46c4SArnaldo Carvalho de Melo 		scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
43386470930SIngo Molnar 						  ".rel.plt", NULL);
43486470930SIngo Molnar 		if (scn_plt_rel == NULL)
435a25e46c4SArnaldo Carvalho de Melo 			goto out_elf_end;
43686470930SIngo Molnar 	}
43786470930SIngo Molnar 
438a25e46c4SArnaldo Carvalho de Melo 	err = -1;
43986470930SIngo Molnar 
440a25e46c4SArnaldo Carvalho de Melo 	if (shdr_rel_plt.sh_link != dynsym_idx)
441a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
442a25e46c4SArnaldo Carvalho de Melo 
443a25e46c4SArnaldo Carvalho de Melo 	if (elf_section_by_name(elf, &ehdr, &shdr_plt, ".plt", NULL) == NULL)
444a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
44586470930SIngo Molnar 
44686470930SIngo Molnar 	/*
44783a0944fSIngo Molnar 	 * Fetch the relocation section to find the idxes to the GOT
44886470930SIngo Molnar 	 * and the symbols in the .dynsym they refer to.
44986470930SIngo Molnar 	 */
45086470930SIngo Molnar 	reldata = elf_getdata(scn_plt_rel, NULL);
45186470930SIngo Molnar 	if (reldata == NULL)
452a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
45386470930SIngo Molnar 
45486470930SIngo Molnar 	syms = elf_getdata(scn_dynsym, NULL);
45586470930SIngo Molnar 	if (syms == NULL)
456a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
45786470930SIngo Molnar 
458a25e46c4SArnaldo Carvalho de Melo 	scn_symstrs = elf_getscn(elf, shdr_dynsym.sh_link);
45986470930SIngo Molnar 	if (scn_symstrs == NULL)
460a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
46186470930SIngo Molnar 
46286470930SIngo Molnar 	symstrs = elf_getdata(scn_symstrs, NULL);
46386470930SIngo Molnar 	if (symstrs == NULL)
464a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
46586470930SIngo Molnar 
46686470930SIngo Molnar 	nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize;
46786470930SIngo Molnar 	plt_offset = shdr_plt.sh_offset;
46886470930SIngo Molnar 
46986470930SIngo Molnar 	if (shdr_rel_plt.sh_type == SHT_RELA) {
47086470930SIngo Molnar 		GElf_Rela pos_mem, *pos;
47186470930SIngo Molnar 
47286470930SIngo Molnar 		elf_section__for_each_rela(reldata, pos, pos_mem, idx,
47386470930SIngo Molnar 					   nr_rel_entries) {
47486470930SIngo Molnar 			symidx = GELF_R_SYM(pos->r_info);
47586470930SIngo Molnar 			plt_offset += shdr_plt.sh_entsize;
47686470930SIngo Molnar 			gelf_getsym(syms, symidx, &sym);
47786470930SIngo Molnar 			snprintf(sympltname, sizeof(sympltname),
47886470930SIngo Molnar 				 "%s@plt", elf_sym__name(&sym, symstrs));
47986470930SIngo Molnar 
48086470930SIngo Molnar 			f = symbol__new(plt_offset, shdr_plt.sh_entsize,
48183a0944fSIngo Molnar 					sympltname, self->sym_priv_size, 0, v);
48286470930SIngo Molnar 			if (!f)
483a25e46c4SArnaldo Carvalho de Melo 				goto out_elf_end;
48486470930SIngo Molnar 
48586470930SIngo Molnar 			dso__insert_symbol(self, f);
48686470930SIngo Molnar 			++nr;
48786470930SIngo Molnar 		}
48886470930SIngo Molnar 	} else if (shdr_rel_plt.sh_type == SHT_REL) {
48986470930SIngo Molnar 		GElf_Rel pos_mem, *pos;
49086470930SIngo Molnar 		elf_section__for_each_rel(reldata, pos, pos_mem, idx,
49186470930SIngo Molnar 					  nr_rel_entries) {
49286470930SIngo Molnar 			symidx = GELF_R_SYM(pos->r_info);
49386470930SIngo Molnar 			plt_offset += shdr_plt.sh_entsize;
49486470930SIngo Molnar 			gelf_getsym(syms, symidx, &sym);
49586470930SIngo Molnar 			snprintf(sympltname, sizeof(sympltname),
49686470930SIngo Molnar 				 "%s@plt", elf_sym__name(&sym, symstrs));
49786470930SIngo Molnar 
49886470930SIngo Molnar 			f = symbol__new(plt_offset, shdr_plt.sh_entsize,
49983a0944fSIngo Molnar 					sympltname, self->sym_priv_size, 0, v);
50086470930SIngo Molnar 			if (!f)
501a25e46c4SArnaldo Carvalho de Melo 				goto out_elf_end;
50286470930SIngo Molnar 
50386470930SIngo Molnar 			dso__insert_symbol(self, f);
50486470930SIngo Molnar 			++nr;
50586470930SIngo Molnar 		}
50686470930SIngo Molnar 	}
50786470930SIngo Molnar 
508a25e46c4SArnaldo Carvalho de Melo 	err = 0;
509a25e46c4SArnaldo Carvalho de Melo out_elf_end:
510a25e46c4SArnaldo Carvalho de Melo 	elf_end(elf);
511a25e46c4SArnaldo Carvalho de Melo out_close:
512a25e46c4SArnaldo Carvalho de Melo 	close(fd);
513a25e46c4SArnaldo Carvalho de Melo 
514a25e46c4SArnaldo Carvalho de Melo 	if (err == 0)
51586470930SIngo Molnar 		return nr;
516a25e46c4SArnaldo Carvalho de Melo out:
517a25e46c4SArnaldo Carvalho de Melo 	fprintf(stderr, "%s: problems reading %s PLT info.\n",
518a25e46c4SArnaldo Carvalho de Melo 		__func__, self->name);
519a25e46c4SArnaldo Carvalho de Melo 	return 0;
52086470930SIngo Molnar }
52186470930SIngo Molnar 
52286470930SIngo Molnar static int dso__load_sym(struct dso *self, int fd, const char *name,
52383a0944fSIngo Molnar 			 symbol_filter_t filter, int v, struct module *mod)
52486470930SIngo Molnar {
5256cfcc53eSMike Galbraith 	Elf_Data *symstrs, *secstrs;
52686470930SIngo Molnar 	uint32_t nr_syms;
52786470930SIngo Molnar 	int err = -1;
52883a0944fSIngo Molnar 	uint32_t idx;
52986470930SIngo Molnar 	GElf_Ehdr ehdr;
53086470930SIngo Molnar 	GElf_Shdr shdr;
53186470930SIngo Molnar 	Elf_Data *syms;
53286470930SIngo Molnar 	GElf_Sym sym;
533a25e46c4SArnaldo Carvalho de Melo 	Elf_Scn *sec, *sec_strndx;
53486470930SIngo Molnar 	Elf *elf;
535d20ff6bdSMike Galbraith 	int nr = 0, kernel = !strcmp("[kernel]", self->name);
53686470930SIngo Molnar 
53786470930SIngo Molnar 	elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
53886470930SIngo Molnar 	if (elf == NULL) {
53983a0944fSIngo Molnar 		if (v)
54086470930SIngo Molnar 			fprintf(stderr, "%s: cannot read %s ELF file.\n",
54186470930SIngo Molnar 				__func__, name);
54286470930SIngo Molnar 		goto out_close;
54386470930SIngo Molnar 	}
54486470930SIngo Molnar 
54586470930SIngo Molnar 	if (gelf_getehdr(elf, &ehdr) == NULL) {
54683a0944fSIngo Molnar 		if (v)
54786470930SIngo Molnar 			fprintf(stderr, "%s: cannot get elf header.\n", __func__);
54886470930SIngo Molnar 		goto out_elf_end;
54986470930SIngo Molnar 	}
55086470930SIngo Molnar 
55186470930SIngo Molnar 	sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL);
55286470930SIngo Molnar 	if (sec == NULL) {
553a25e46c4SArnaldo Carvalho de Melo 		sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL);
554a25e46c4SArnaldo Carvalho de Melo 		if (sec == NULL)
55586470930SIngo Molnar 			goto out_elf_end;
55686470930SIngo Molnar 	}
55786470930SIngo Molnar 
55886470930SIngo Molnar 	syms = elf_getdata(sec, NULL);
55986470930SIngo Molnar 	if (syms == NULL)
56086470930SIngo Molnar 		goto out_elf_end;
56186470930SIngo Molnar 
56286470930SIngo Molnar 	sec = elf_getscn(elf, shdr.sh_link);
56386470930SIngo Molnar 	if (sec == NULL)
56486470930SIngo Molnar 		goto out_elf_end;
56586470930SIngo Molnar 
56686470930SIngo Molnar 	symstrs = elf_getdata(sec, NULL);
56786470930SIngo Molnar 	if (symstrs == NULL)
56886470930SIngo Molnar 		goto out_elf_end;
56986470930SIngo Molnar 
5706cfcc53eSMike Galbraith 	sec_strndx = elf_getscn(elf, ehdr.e_shstrndx);
5716cfcc53eSMike Galbraith 	if (sec_strndx == NULL)
5726cfcc53eSMike Galbraith 		goto out_elf_end;
5736cfcc53eSMike Galbraith 
5746cfcc53eSMike Galbraith 	secstrs = elf_getdata(sec_strndx, NULL);
5759b30a26bSStoyan Gaydarov 	if (secstrs == NULL)
5766cfcc53eSMike Galbraith 		goto out_elf_end;
5776cfcc53eSMike Galbraith 
57886470930SIngo Molnar 	nr_syms = shdr.sh_size / shdr.sh_entsize;
57986470930SIngo Molnar 
580e9fbc9dcSArjan van de Ven 	memset(&sym, 0, sizeof(sym));
581d20ff6bdSMike Galbraith 	if (!kernel) {
58230d7a77dSArnaldo Carvalho de Melo 		self->adjust_symbols = (ehdr.e_type == ET_EXEC ||
58330d7a77dSArnaldo Carvalho de Melo 				elf_section_by_name(elf, &ehdr, &shdr,
584f5812a7aSArnaldo Carvalho de Melo 						     ".gnu.prelink_undo",
58530d7a77dSArnaldo Carvalho de Melo 						     NULL) != NULL);
586d20ff6bdSMike Galbraith 	} else self->adjust_symbols = 0;
587d20ff6bdSMike Galbraith 
58883a0944fSIngo Molnar 	elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) {
58986470930SIngo Molnar 		struct symbol *f;
59083a0944fSIngo Molnar 		const char *elf_name;
59128ac909bSArnaldo Carvalho de Melo 		char *demangled;
5929cffa8d5SPaul Mackerras 		u64 obj_start;
5936cfcc53eSMike Galbraith 		struct section *section = NULL;
5946cfcc53eSMike Galbraith 		int is_label = elf_sym__is_label(&sym);
5956cfcc53eSMike Galbraith 		const char *section_name;
59686470930SIngo Molnar 
5976cfcc53eSMike Galbraith 		if (!is_label && !elf_sym__is_function(&sym))
59886470930SIngo Molnar 			continue;
59986470930SIngo Molnar 
60086470930SIngo Molnar 		sec = elf_getscn(elf, sym.st_shndx);
60186470930SIngo Molnar 		if (!sec)
60286470930SIngo Molnar 			goto out_elf_end;
60386470930SIngo Molnar 
60486470930SIngo Molnar 		gelf_getshdr(sec, &shdr);
6056cfcc53eSMike Galbraith 
6066cfcc53eSMike Galbraith 		if (is_label && !elf_sec__is_text(&shdr, secstrs))
6076cfcc53eSMike Galbraith 			continue;
6086cfcc53eSMike Galbraith 
6096cfcc53eSMike Galbraith 		section_name = elf_sec__name(&shdr, secstrs);
61086470930SIngo Molnar 		obj_start = sym.st_value;
61186470930SIngo Molnar 
61230d7a77dSArnaldo Carvalho de Melo 		if (self->adjust_symbols) {
61383a0944fSIngo Molnar 			if (v >= 2)
614520f2c34SPeter Zijlstra 				printf("adjusting symbol: st_value: %Lx sh_addr: %Lx sh_offset: %Lx\n",
615520f2c34SPeter Zijlstra 					(u64)sym.st_value, (u64)shdr.sh_addr, (u64)shdr.sh_offset);
616520f2c34SPeter Zijlstra 
61786470930SIngo Molnar 			sym.st_value -= shdr.sh_addr - shdr.sh_offset;
618f5812a7aSArnaldo Carvalho de Melo 		}
61986470930SIngo Molnar 
6206cfcc53eSMike Galbraith 		if (mod) {
6216cfcc53eSMike Galbraith 			section = mod->sections->find_section(mod->sections, section_name);
6226cfcc53eSMike Galbraith 			if (section)
6236cfcc53eSMike Galbraith 				sym.st_value += section->vma;
6246cfcc53eSMike Galbraith 			else {
6256cfcc53eSMike Galbraith 				fprintf(stderr, "dso__load_sym() module %s lookup of %s failed\n",
6266cfcc53eSMike Galbraith 					mod->name, section_name);
6276cfcc53eSMike Galbraith 				goto out_elf_end;
6286cfcc53eSMike Galbraith 			}
6296cfcc53eSMike Galbraith 		}
63028ac909bSArnaldo Carvalho de Melo 		/*
63128ac909bSArnaldo Carvalho de Melo 		 * We need to figure out if the object was created from C++ sources
63228ac909bSArnaldo Carvalho de Melo 		 * DWARF DW_compile_unit has this, but we don't always have access
63328ac909bSArnaldo Carvalho de Melo 		 * to it...
63428ac909bSArnaldo Carvalho de Melo 		 */
63583a0944fSIngo Molnar 		elf_name = elf_sym__name(&sym, symstrs);
63683a0944fSIngo Molnar 		demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI);
63728ac909bSArnaldo Carvalho de Melo 		if (demangled != NULL)
63883a0944fSIngo Molnar 			elf_name = demangled;
6396cfcc53eSMike Galbraith 
64083a0944fSIngo Molnar 		f = symbol__new(sym.st_value, sym.st_size, elf_name,
64183a0944fSIngo Molnar 				self->sym_priv_size, obj_start, v);
64228ac909bSArnaldo Carvalho de Melo 		free(demangled);
64386470930SIngo Molnar 		if (!f)
64486470930SIngo Molnar 			goto out_elf_end;
64586470930SIngo Molnar 
64686470930SIngo Molnar 		if (filter && filter(self, f))
64786470930SIngo Molnar 			symbol__delete(f, self->sym_priv_size);
64886470930SIngo Molnar 		else {
6496cfcc53eSMike Galbraith 			f->module = mod;
65086470930SIngo Molnar 			dso__insert_symbol(self, f);
65186470930SIngo Molnar 			nr++;
65286470930SIngo Molnar 		}
65386470930SIngo Molnar 	}
65486470930SIngo Molnar 
65586470930SIngo Molnar 	err = nr;
65686470930SIngo Molnar out_elf_end:
65786470930SIngo Molnar 	elf_end(elf);
65886470930SIngo Molnar out_close:
65986470930SIngo Molnar 	return err;
66086470930SIngo Molnar }
66186470930SIngo Molnar 
6624d1e00a8SArnaldo Carvalho de Melo #define BUILD_ID_SIZE 128
6634d1e00a8SArnaldo Carvalho de Melo 
66483a0944fSIngo Molnar static char *dso__read_build_id(struct dso *self, int v)
6654d1e00a8SArnaldo Carvalho de Melo {
6664d1e00a8SArnaldo Carvalho de Melo 	int i;
6674d1e00a8SArnaldo Carvalho de Melo 	GElf_Ehdr ehdr;
6684d1e00a8SArnaldo Carvalho de Melo 	GElf_Shdr shdr;
6694d1e00a8SArnaldo Carvalho de Melo 	Elf_Data *build_id_data;
6704d1e00a8SArnaldo Carvalho de Melo 	Elf_Scn *sec;
6714d1e00a8SArnaldo Carvalho de Melo 	char *build_id = NULL, *bid;
6724d1e00a8SArnaldo Carvalho de Melo 	unsigned char *raw;
6734d1e00a8SArnaldo Carvalho de Melo 	Elf *elf;
6744d1e00a8SArnaldo Carvalho de Melo 	int fd = open(self->name, O_RDONLY);
6754d1e00a8SArnaldo Carvalho de Melo 
6764d1e00a8SArnaldo Carvalho de Melo 	if (fd < 0)
6774d1e00a8SArnaldo Carvalho de Melo 		goto out;
6784d1e00a8SArnaldo Carvalho de Melo 
6794d1e00a8SArnaldo Carvalho de Melo 	elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
6804d1e00a8SArnaldo Carvalho de Melo 	if (elf == NULL) {
68183a0944fSIngo Molnar 		if (v)
6824d1e00a8SArnaldo Carvalho de Melo 			fprintf(stderr, "%s: cannot read %s ELF file.\n",
6834d1e00a8SArnaldo Carvalho de Melo 				__func__, self->name);
6844d1e00a8SArnaldo Carvalho de Melo 		goto out_close;
6854d1e00a8SArnaldo Carvalho de Melo 	}
6864d1e00a8SArnaldo Carvalho de Melo 
6874d1e00a8SArnaldo Carvalho de Melo 	if (gelf_getehdr(elf, &ehdr) == NULL) {
68883a0944fSIngo Molnar 		if (v)
6894d1e00a8SArnaldo Carvalho de Melo 			fprintf(stderr, "%s: cannot get elf header.\n", __func__);
6904d1e00a8SArnaldo Carvalho de Melo 		goto out_elf_end;
6914d1e00a8SArnaldo Carvalho de Melo 	}
6924d1e00a8SArnaldo Carvalho de Melo 
6934d1e00a8SArnaldo Carvalho de Melo 	sec = elf_section_by_name(elf, &ehdr, &shdr, ".note.gnu.build-id", NULL);
6944d1e00a8SArnaldo Carvalho de Melo 	if (sec == NULL)
6954d1e00a8SArnaldo Carvalho de Melo 		goto out_elf_end;
6964d1e00a8SArnaldo Carvalho de Melo 
6974d1e00a8SArnaldo Carvalho de Melo 	build_id_data = elf_getdata(sec, NULL);
6984d1e00a8SArnaldo Carvalho de Melo 	if (build_id_data == NULL)
6994d1e00a8SArnaldo Carvalho de Melo 		goto out_elf_end;
7004d1e00a8SArnaldo Carvalho de Melo 	build_id = malloc(BUILD_ID_SIZE);
7014d1e00a8SArnaldo Carvalho de Melo 	if (build_id == NULL)
7024d1e00a8SArnaldo Carvalho de Melo 		goto out_elf_end;
7034d1e00a8SArnaldo Carvalho de Melo 	raw = build_id_data->d_buf + 16;
7044d1e00a8SArnaldo Carvalho de Melo 	bid = build_id;
7054d1e00a8SArnaldo Carvalho de Melo 
7064d1e00a8SArnaldo Carvalho de Melo 	for (i = 0; i < 20; ++i) {
7074d1e00a8SArnaldo Carvalho de Melo 		sprintf(bid, "%02x", *raw);
7084d1e00a8SArnaldo Carvalho de Melo 		++raw;
7094d1e00a8SArnaldo Carvalho de Melo 		bid += 2;
7104d1e00a8SArnaldo Carvalho de Melo 	}
71183a0944fSIngo Molnar 	if (v >= 2)
7124d1e00a8SArnaldo Carvalho de Melo 		printf("%s(%s): %s\n", __func__, self->name, build_id);
7134d1e00a8SArnaldo Carvalho de Melo out_elf_end:
7144d1e00a8SArnaldo Carvalho de Melo 	elf_end(elf);
7154d1e00a8SArnaldo Carvalho de Melo out_close:
7164d1e00a8SArnaldo Carvalho de Melo 	close(fd);
7174d1e00a8SArnaldo Carvalho de Melo out:
7184d1e00a8SArnaldo Carvalho de Melo 	return build_id;
7194d1e00a8SArnaldo Carvalho de Melo }
7204d1e00a8SArnaldo Carvalho de Melo 
72194cb9e38SArnaldo Carvalho de Melo char dso__symtab_origin(const struct dso *self)
72294cb9e38SArnaldo Carvalho de Melo {
72394cb9e38SArnaldo Carvalho de Melo 	static const char origin[] = {
72494cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_KERNEL] =   'k',
72594cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_JAVA_JIT] = 'j',
72694cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_FEDORA] =   'f',
72794cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_UBUNTU] =   'u',
72894cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_BUILDID] =  'b',
72994cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_DSO] =      'd',
73094cb9e38SArnaldo Carvalho de Melo 	};
73194cb9e38SArnaldo Carvalho de Melo 
73294cb9e38SArnaldo Carvalho de Melo 	if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND)
73394cb9e38SArnaldo Carvalho de Melo 		return '!';
73494cb9e38SArnaldo Carvalho de Melo 	return origin[self->origin];
73594cb9e38SArnaldo Carvalho de Melo }
73694cb9e38SArnaldo Carvalho de Melo 
73783a0944fSIngo Molnar int dso__load(struct dso *self, symbol_filter_t filter, int v)
73886470930SIngo Molnar {
7394d1e00a8SArnaldo Carvalho de Melo 	int size = PATH_MAX;
7404d1e00a8SArnaldo Carvalho de Melo 	char *name = malloc(size), *build_id = NULL;
74186470930SIngo Molnar 	int ret = -1;
74286470930SIngo Molnar 	int fd;
74386470930SIngo Molnar 
74486470930SIngo Molnar 	if (!name)
74586470930SIngo Molnar 		return -1;
74686470930SIngo Molnar 
74730d7a77dSArnaldo Carvalho de Melo 	self->adjust_symbols = 0;
748f5812a7aSArnaldo Carvalho de Melo 
74994cb9e38SArnaldo Carvalho de Melo 	if (strncmp(self->name, "/tmp/perf-", 10) == 0) {
75083a0944fSIngo Molnar 		ret = dso__load_perf_map(self, filter, v);
75194cb9e38SArnaldo Carvalho de Melo 		self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT :
75294cb9e38SArnaldo Carvalho de Melo 					 DSO__ORIG_NOT_FOUND;
75394cb9e38SArnaldo Carvalho de Melo 		return ret;
75494cb9e38SArnaldo Carvalho de Melo 	}
75594cb9e38SArnaldo Carvalho de Melo 
75694cb9e38SArnaldo Carvalho de Melo 	self->origin = DSO__ORIG_FEDORA - 1;
75780d496beSPekka Enberg 
75886470930SIngo Molnar more:
75986470930SIngo Molnar 	do {
76094cb9e38SArnaldo Carvalho de Melo 		self->origin++;
76194cb9e38SArnaldo Carvalho de Melo 		switch (self->origin) {
76294cb9e38SArnaldo Carvalho de Melo 		case DSO__ORIG_FEDORA:
76386470930SIngo Molnar 			snprintf(name, size, "/usr/lib/debug%s.debug", self->name);
76486470930SIngo Molnar 			break;
76594cb9e38SArnaldo Carvalho de Melo 		case DSO__ORIG_UBUNTU:
76686470930SIngo Molnar 			snprintf(name, size, "/usr/lib/debug%s", self->name);
76786470930SIngo Molnar 			break;
76894cb9e38SArnaldo Carvalho de Melo 		case DSO__ORIG_BUILDID:
76983a0944fSIngo Molnar 			build_id = dso__read_build_id(self, v);
7704d1e00a8SArnaldo Carvalho de Melo 			if (build_id != NULL) {
7714d1e00a8SArnaldo Carvalho de Melo 				snprintf(name, size,
7724d1e00a8SArnaldo Carvalho de Melo 					 "/usr/lib/debug/.build-id/%.2s/%s.debug",
7734d1e00a8SArnaldo Carvalho de Melo 					build_id, build_id + 2);
7744d1e00a8SArnaldo Carvalho de Melo 				free(build_id);
7754d1e00a8SArnaldo Carvalho de Melo 				break;
7764d1e00a8SArnaldo Carvalho de Melo 			}
77794cb9e38SArnaldo Carvalho de Melo 			self->origin++;
7784d1e00a8SArnaldo Carvalho de Melo 			/* Fall thru */
77994cb9e38SArnaldo Carvalho de Melo 		case DSO__ORIG_DSO:
78086470930SIngo Molnar 			snprintf(name, size, "%s", self->name);
78186470930SIngo Molnar 			break;
78286470930SIngo Molnar 
78386470930SIngo Molnar 		default:
78486470930SIngo Molnar 			goto out;
78586470930SIngo Molnar 		}
78686470930SIngo Molnar 
78786470930SIngo Molnar 		fd = open(name, O_RDONLY);
78886470930SIngo Molnar 	} while (fd < 0);
78986470930SIngo Molnar 
79083a0944fSIngo Molnar 	ret = dso__load_sym(self, fd, name, filter, v, NULL);
79186470930SIngo Molnar 	close(fd);
79286470930SIngo Molnar 
79386470930SIngo Molnar 	/*
79486470930SIngo Molnar 	 * Some people seem to have debuginfo files _WITHOUT_ debug info!?!?
79586470930SIngo Molnar 	 */
79686470930SIngo Molnar 	if (!ret)
79786470930SIngo Molnar 		goto more;
79886470930SIngo Molnar 
799a25e46c4SArnaldo Carvalho de Melo 	if (ret > 0) {
80083a0944fSIngo Molnar 		int nr_plt = dso__synthesize_plt_symbols(self, v);
801a25e46c4SArnaldo Carvalho de Melo 		if (nr_plt > 0)
802a25e46c4SArnaldo Carvalho de Melo 			ret += nr_plt;
803a25e46c4SArnaldo Carvalho de Melo 	}
80486470930SIngo Molnar out:
80586470930SIngo Molnar 	free(name);
8061340e6bbSArnaldo Carvalho de Melo 	if (ret < 0 && strstr(self->name, " (deleted)") != NULL)
8071340e6bbSArnaldo Carvalho de Melo 		return 0;
80886470930SIngo Molnar 	return ret;
80986470930SIngo Molnar }
81086470930SIngo Molnar 
8116cfcc53eSMike Galbraith static int dso__load_module(struct dso *self, struct mod_dso *mods, const char *name,
81283a0944fSIngo Molnar 			     symbol_filter_t filter, int v)
8136cfcc53eSMike Galbraith {
8146cfcc53eSMike Galbraith 	struct module *mod = mod_dso__find_module(mods, name);
8156cfcc53eSMike Galbraith 	int err = 0, fd;
8166cfcc53eSMike Galbraith 
8176cfcc53eSMike Galbraith 	if (mod == NULL || !mod->active)
8186cfcc53eSMike Galbraith 		return err;
8196cfcc53eSMike Galbraith 
8206cfcc53eSMike Galbraith 	fd = open(mod->path, O_RDONLY);
8216cfcc53eSMike Galbraith 
8226cfcc53eSMike Galbraith 	if (fd < 0)
8236cfcc53eSMike Galbraith 		return err;
8246cfcc53eSMike Galbraith 
82583a0944fSIngo Molnar 	err = dso__load_sym(self, fd, name, filter, v, mod);
8266cfcc53eSMike Galbraith 	close(fd);
8276cfcc53eSMike Galbraith 
8286cfcc53eSMike Galbraith 	return err;
8296cfcc53eSMike Galbraith }
8306cfcc53eSMike Galbraith 
83183a0944fSIngo Molnar int dso__load_modules(struct dso *self, symbol_filter_t filter, int v)
8326cfcc53eSMike Galbraith {
8336cfcc53eSMike Galbraith 	struct mod_dso *mods = mod_dso__new_dso("modules");
8346cfcc53eSMike Galbraith 	struct module *pos;
8356cfcc53eSMike Galbraith 	struct rb_node *next;
8366cfcc53eSMike Galbraith 	int err;
8376cfcc53eSMike Galbraith 
8386cfcc53eSMike Galbraith 	err = mod_dso__load_modules(mods);
8396cfcc53eSMike Galbraith 
8406cfcc53eSMike Galbraith 	if (err <= 0)
8416cfcc53eSMike Galbraith 		return err;
8426cfcc53eSMike Galbraith 
8436cfcc53eSMike Galbraith 	/*
8446cfcc53eSMike Galbraith 	 * Iterate over modules, and load active symbols.
8456cfcc53eSMike Galbraith 	 */
8466cfcc53eSMike Galbraith 	next = rb_first(&mods->mods);
8476cfcc53eSMike Galbraith 	while (next) {
8486cfcc53eSMike Galbraith 		pos = rb_entry(next, struct module, rb_node);
84983a0944fSIngo Molnar 		err = dso__load_module(self, mods, pos->name, filter, v);
8506cfcc53eSMike Galbraith 
8516cfcc53eSMike Galbraith 		if (err < 0)
8526cfcc53eSMike Galbraith 			break;
8536cfcc53eSMike Galbraith 
8546cfcc53eSMike Galbraith 		next = rb_next(&pos->rb_node);
8556cfcc53eSMike Galbraith 	}
8566cfcc53eSMike Galbraith 
8576cfcc53eSMike Galbraith 	if (err < 0) {
8586cfcc53eSMike Galbraith 		mod_dso__delete_modules(mods);
8596cfcc53eSMike Galbraith 		mod_dso__delete_self(mods);
8606cfcc53eSMike Galbraith 	}
8616cfcc53eSMike Galbraith 
8626cfcc53eSMike Galbraith 	return err;
8636cfcc53eSMike Galbraith }
8646cfcc53eSMike Galbraith 
8656cfcc53eSMike Galbraith static inline void dso__fill_symbol_holes(struct dso *self)
8666cfcc53eSMike Galbraith {
8676cfcc53eSMike Galbraith 	struct symbol *prev = NULL;
8686cfcc53eSMike Galbraith 	struct rb_node *nd;
8696cfcc53eSMike Galbraith 
8706cfcc53eSMike Galbraith 	for (nd = rb_last(&self->syms); nd; nd = rb_prev(nd)) {
8716cfcc53eSMike Galbraith 		struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
8726cfcc53eSMike Galbraith 
8736cfcc53eSMike Galbraith 		if (prev) {
8746cfcc53eSMike Galbraith 			u64 hole = 0;
8756cfcc53eSMike Galbraith 			int alias = pos->start == prev->start;
8766cfcc53eSMike Galbraith 
8776cfcc53eSMike Galbraith 			if (!alias)
8786cfcc53eSMike Galbraith 				hole = prev->start - pos->end - 1;
8796cfcc53eSMike Galbraith 
8806cfcc53eSMike Galbraith 			if (hole || alias) {
8816cfcc53eSMike Galbraith 				if (alias)
8826cfcc53eSMike Galbraith 					pos->end = prev->end;
8836cfcc53eSMike Galbraith 				else if (hole)
8846cfcc53eSMike Galbraith 					pos->end = prev->start - 1;
8856cfcc53eSMike Galbraith 			}
8866cfcc53eSMike Galbraith 		}
8876cfcc53eSMike Galbraith 		prev = pos;
8886cfcc53eSMike Galbraith 	}
8896cfcc53eSMike Galbraith }
8906cfcc53eSMike Galbraith 
89186470930SIngo Molnar static int dso__load_vmlinux(struct dso *self, const char *vmlinux,
89283a0944fSIngo Molnar 			     symbol_filter_t filter, int v)
89386470930SIngo Molnar {
89486470930SIngo Molnar 	int err, fd = open(vmlinux, O_RDONLY);
89586470930SIngo Molnar 
89686470930SIngo Molnar 	if (fd < 0)
89786470930SIngo Molnar 		return -1;
89886470930SIngo Molnar 
89983a0944fSIngo Molnar 	err = dso__load_sym(self, fd, vmlinux, filter, v, NULL);
9006cfcc53eSMike Galbraith 
9016cfcc53eSMike Galbraith 	if (err > 0)
9026cfcc53eSMike Galbraith 		dso__fill_symbol_holes(self);
9036cfcc53eSMike Galbraith 
90486470930SIngo Molnar 	close(fd);
90586470930SIngo Molnar 
90686470930SIngo Molnar 	return err;
90786470930SIngo Molnar }
90886470930SIngo Molnar 
90986470930SIngo Molnar int dso__load_kernel(struct dso *self, const char *vmlinux,
91083a0944fSIngo Molnar 		     symbol_filter_t filter, int v, int use_modules)
91186470930SIngo Molnar {
91286470930SIngo Molnar 	int err = -1;
91386470930SIngo Molnar 
9146cfcc53eSMike Galbraith 	if (vmlinux) {
91583a0944fSIngo Molnar 		err = dso__load_vmlinux(self, vmlinux, filter, v);
91683a0944fSIngo Molnar 		if (err > 0 && use_modules)
91783a0944fSIngo Molnar 			err = dso__load_modules(self, filter, v);
9186cfcc53eSMike Galbraith 	}
91986470930SIngo Molnar 
9209974f496SMike Galbraith 	if (err <= 0)
92183a0944fSIngo Molnar 		err = dso__load_kallsyms(self, filter, v);
92286470930SIngo Molnar 
92394cb9e38SArnaldo Carvalho de Melo 	if (err > 0)
92494cb9e38SArnaldo Carvalho de Melo 		self->origin = DSO__ORIG_KERNEL;
92594cb9e38SArnaldo Carvalho de Melo 
92686470930SIngo Molnar 	return err;
92786470930SIngo Molnar }
92886470930SIngo Molnar 
929cd84c2acSFrederic Weisbecker LIST_HEAD(dsos);
930cd84c2acSFrederic Weisbecker struct dso	*kernel_dso;
931cd84c2acSFrederic Weisbecker struct dso	*vdso;
932cd84c2acSFrederic Weisbecker struct dso	*hypervisor_dso;
933cd84c2acSFrederic Weisbecker 
93483a0944fSIngo Molnar const char	*vmlinux_name = "vmlinux";
935cd84c2acSFrederic Weisbecker int		modules;
936cd84c2acSFrederic Weisbecker 
937cd84c2acSFrederic Weisbecker static void dsos__add(struct dso *dso)
938cd84c2acSFrederic Weisbecker {
939cd84c2acSFrederic Weisbecker 	list_add_tail(&dso->node, &dsos);
940cd84c2acSFrederic Weisbecker }
941cd84c2acSFrederic Weisbecker 
942cd84c2acSFrederic Weisbecker static struct dso *dsos__find(const char *name)
943cd84c2acSFrederic Weisbecker {
944cd84c2acSFrederic Weisbecker 	struct dso *pos;
945cd84c2acSFrederic Weisbecker 
946cd84c2acSFrederic Weisbecker 	list_for_each_entry(pos, &dsos, node)
947cd84c2acSFrederic Weisbecker 		if (strcmp(pos->name, name) == 0)
948cd84c2acSFrederic Weisbecker 			return pos;
949cd84c2acSFrederic Weisbecker 	return NULL;
950cd84c2acSFrederic Weisbecker }
951cd84c2acSFrederic Weisbecker 
952cd84c2acSFrederic Weisbecker struct dso *dsos__findnew(const char *name)
953cd84c2acSFrederic Weisbecker {
954cd84c2acSFrederic Weisbecker 	struct dso *dso = dsos__find(name);
955cd84c2acSFrederic Weisbecker 	int nr;
956cd84c2acSFrederic Weisbecker 
957cd84c2acSFrederic Weisbecker 	if (dso)
958cd84c2acSFrederic Weisbecker 		return dso;
959cd84c2acSFrederic Weisbecker 
960cd84c2acSFrederic Weisbecker 	dso = dso__new(name, 0);
961cd84c2acSFrederic Weisbecker 	if (!dso)
962cd84c2acSFrederic Weisbecker 		goto out_delete_dso;
963cd84c2acSFrederic Weisbecker 
964cd84c2acSFrederic Weisbecker 	nr = dso__load(dso, NULL, verbose);
965cd84c2acSFrederic Weisbecker 	if (nr < 0) {
966cd84c2acSFrederic Weisbecker 		eprintf("Failed to open: %s\n", name);
967cd84c2acSFrederic Weisbecker 		goto out_delete_dso;
968cd84c2acSFrederic Weisbecker 	}
969cd84c2acSFrederic Weisbecker 	if (!nr)
970cd84c2acSFrederic Weisbecker 		eprintf("No symbols found in: %s, maybe install a debug package?\n", name);
971cd84c2acSFrederic Weisbecker 
972cd84c2acSFrederic Weisbecker 	dsos__add(dso);
973cd84c2acSFrederic Weisbecker 
974cd84c2acSFrederic Weisbecker 	return dso;
975cd84c2acSFrederic Weisbecker 
976cd84c2acSFrederic Weisbecker out_delete_dso:
977cd84c2acSFrederic Weisbecker 	dso__delete(dso);
978cd84c2acSFrederic Weisbecker 	return NULL;
979cd84c2acSFrederic Weisbecker }
980cd84c2acSFrederic Weisbecker 
981cd84c2acSFrederic Weisbecker void dsos__fprintf(FILE *fp)
982cd84c2acSFrederic Weisbecker {
983cd84c2acSFrederic Weisbecker 	struct dso *pos;
984cd84c2acSFrederic Weisbecker 
985cd84c2acSFrederic Weisbecker 	list_for_each_entry(pos, &dsos, node)
986cd84c2acSFrederic Weisbecker 		dso__fprintf(pos, fp);
987cd84c2acSFrederic Weisbecker }
988cd84c2acSFrederic Weisbecker 
989cd84c2acSFrederic Weisbecker static struct symbol *vdso__find_symbol(struct dso *dso, u64 ip)
990cd84c2acSFrederic Weisbecker {
991cd84c2acSFrederic Weisbecker 	return dso__find_symbol(dso, ip);
992cd84c2acSFrederic Weisbecker }
993cd84c2acSFrederic Weisbecker 
994cd84c2acSFrederic Weisbecker int load_kernel(void)
995cd84c2acSFrederic Weisbecker {
996cd84c2acSFrederic Weisbecker 	int err;
997cd84c2acSFrederic Weisbecker 
998cd84c2acSFrederic Weisbecker 	kernel_dso = dso__new("[kernel]", 0);
999cd84c2acSFrederic Weisbecker 	if (!kernel_dso)
1000cd84c2acSFrederic Weisbecker 		return -1;
1001cd84c2acSFrederic Weisbecker 
100283a0944fSIngo Molnar 	err = dso__load_kernel(kernel_dso, vmlinux_name, NULL, verbose, modules);
1003cd84c2acSFrederic Weisbecker 	if (err <= 0) {
1004cd84c2acSFrederic Weisbecker 		dso__delete(kernel_dso);
1005cd84c2acSFrederic Weisbecker 		kernel_dso = NULL;
1006cd84c2acSFrederic Weisbecker 	} else
1007cd84c2acSFrederic Weisbecker 		dsos__add(kernel_dso);
1008cd84c2acSFrederic Weisbecker 
1009cd84c2acSFrederic Weisbecker 	vdso = dso__new("[vdso]", 0);
1010cd84c2acSFrederic Weisbecker 	if (!vdso)
1011cd84c2acSFrederic Weisbecker 		return -1;
1012cd84c2acSFrederic Weisbecker 
1013cd84c2acSFrederic Weisbecker 	vdso->find_symbol = vdso__find_symbol;
1014cd84c2acSFrederic Weisbecker 
1015cd84c2acSFrederic Weisbecker 	dsos__add(vdso);
1016cd84c2acSFrederic Weisbecker 
1017cd84c2acSFrederic Weisbecker 	hypervisor_dso = dso__new("[hypervisor]", 0);
1018cd84c2acSFrederic Weisbecker 	if (!hypervisor_dso)
1019cd84c2acSFrederic Weisbecker 		return -1;
1020cd84c2acSFrederic Weisbecker 	dsos__add(hypervisor_dso);
1021cd84c2acSFrederic Weisbecker 
1022cd84c2acSFrederic Weisbecker 	return err;
1023cd84c2acSFrederic Weisbecker }
1024cd84c2acSFrederic Weisbecker 
1025cd84c2acSFrederic Weisbecker 
102686470930SIngo Molnar void symbol__init(void)
102786470930SIngo Molnar {
102886470930SIngo Molnar 	elf_version(EV_CURRENT);
102986470930SIngo Molnar }
1030