xref: /linux/tools/perf/util/symbol.c (revision 84087126d50400789b44459cfc45721778e6ebb0)
186470930SIngo Molnar #include "util.h"
286470930SIngo Molnar #include "../perf.h"
386470930SIngo Molnar #include "string.h"
486470930SIngo Molnar #include "symbol.h"
586470930SIngo Molnar 
68f28827aSFrederic Weisbecker #include "debug.h"
78f28827aSFrederic 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 &&
32781833130SArnaldo Carvalho de Melo 	       sym->st_shndx != SHN_UNDEF;
32886470930SIngo Molnar }
32986470930SIngo Molnar 
3306cfcc53eSMike Galbraith static inline int elf_sym__is_label(const GElf_Sym *sym)
3316cfcc53eSMike Galbraith {
3326cfcc53eSMike Galbraith 	return elf_sym__type(sym) == STT_NOTYPE &&
3336cfcc53eSMike Galbraith 		sym->st_name != 0 &&
3346cfcc53eSMike Galbraith 		sym->st_shndx != SHN_UNDEF &&
3356cfcc53eSMike Galbraith 		sym->st_shndx != SHN_ABS;
3366cfcc53eSMike Galbraith }
3376cfcc53eSMike Galbraith 
3386cfcc53eSMike Galbraith static inline const char *elf_sec__name(const GElf_Shdr *shdr,
3396cfcc53eSMike Galbraith 					const Elf_Data *secstrs)
3406cfcc53eSMike Galbraith {
3416cfcc53eSMike Galbraith 	return secstrs->d_buf + shdr->sh_name;
3426cfcc53eSMike Galbraith }
3436cfcc53eSMike Galbraith 
3446cfcc53eSMike Galbraith static inline int elf_sec__is_text(const GElf_Shdr *shdr,
3456cfcc53eSMike Galbraith 					const Elf_Data *secstrs)
3466cfcc53eSMike Galbraith {
3476cfcc53eSMike Galbraith 	return strstr(elf_sec__name(shdr, secstrs), "text") != NULL;
3486cfcc53eSMike Galbraith }
3496cfcc53eSMike Galbraith 
35086470930SIngo Molnar static inline const char *elf_sym__name(const GElf_Sym *sym,
35186470930SIngo Molnar 					const Elf_Data *symstrs)
35286470930SIngo Molnar {
35386470930SIngo Molnar 	return symstrs->d_buf + sym->st_name;
35486470930SIngo Molnar }
35586470930SIngo Molnar 
35686470930SIngo Molnar static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
35786470930SIngo Molnar 				    GElf_Shdr *shp, const char *name,
35883a0944fSIngo Molnar 				    size_t *idx)
35986470930SIngo Molnar {
36086470930SIngo Molnar 	Elf_Scn *sec = NULL;
36186470930SIngo Molnar 	size_t cnt = 1;
36286470930SIngo Molnar 
36386470930SIngo Molnar 	while ((sec = elf_nextscn(elf, sec)) != NULL) {
36486470930SIngo Molnar 		char *str;
36586470930SIngo Molnar 
36686470930SIngo Molnar 		gelf_getshdr(sec, shp);
36786470930SIngo Molnar 		str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name);
36886470930SIngo Molnar 		if (!strcmp(name, str)) {
36983a0944fSIngo Molnar 			if (idx)
37083a0944fSIngo Molnar 				*idx = cnt;
37186470930SIngo Molnar 			break;
37286470930SIngo Molnar 		}
37386470930SIngo Molnar 		++cnt;
37486470930SIngo Molnar 	}
37586470930SIngo Molnar 
37686470930SIngo Molnar 	return sec;
37786470930SIngo Molnar }
37886470930SIngo Molnar 
37986470930SIngo Molnar #define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \
38086470930SIngo Molnar 	for (idx = 0, pos = gelf_getrel(reldata, 0, &pos_mem); \
38186470930SIngo Molnar 	     idx < nr_entries; \
38286470930SIngo Molnar 	     ++idx, pos = gelf_getrel(reldata, idx, &pos_mem))
38386470930SIngo Molnar 
38486470930SIngo Molnar #define elf_section__for_each_rela(reldata, pos, pos_mem, idx, nr_entries) \
38586470930SIngo Molnar 	for (idx = 0, pos = gelf_getrela(reldata, 0, &pos_mem); \
38686470930SIngo Molnar 	     idx < nr_entries; \
38786470930SIngo Molnar 	     ++idx, pos = gelf_getrela(reldata, idx, &pos_mem))
38886470930SIngo Molnar 
389a25e46c4SArnaldo Carvalho de Melo /*
390a25e46c4SArnaldo Carvalho de Melo  * We need to check if we have a .dynsym, so that we can handle the
391a25e46c4SArnaldo Carvalho de Melo  * .plt, synthesizing its symbols, that aren't on the symtabs (be it
392a25e46c4SArnaldo Carvalho de Melo  * .dynsym or .symtab).
393a25e46c4SArnaldo Carvalho de Melo  * And always look at the original dso, not at debuginfo packages, that
394a25e46c4SArnaldo Carvalho de Melo  * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS).
395a25e46c4SArnaldo Carvalho de Melo  */
39683a0944fSIngo Molnar static int dso__synthesize_plt_symbols(struct  dso *self, int v)
39786470930SIngo Molnar {
39886470930SIngo Molnar 	uint32_t nr_rel_entries, idx;
39986470930SIngo Molnar 	GElf_Sym sym;
4009cffa8d5SPaul Mackerras 	u64 plt_offset;
40186470930SIngo Molnar 	GElf_Shdr shdr_plt;
40286470930SIngo Molnar 	struct symbol *f;
403a25e46c4SArnaldo Carvalho de Melo 	GElf_Shdr shdr_rel_plt, shdr_dynsym;
40486470930SIngo Molnar 	Elf_Data *reldata, *syms, *symstrs;
405a25e46c4SArnaldo Carvalho de Melo 	Elf_Scn *scn_plt_rel, *scn_symstrs, *scn_dynsym;
406a25e46c4SArnaldo Carvalho de Melo 	size_t dynsym_idx;
407a25e46c4SArnaldo Carvalho de Melo 	GElf_Ehdr ehdr;
40886470930SIngo Molnar 	char sympltname[1024];
409a25e46c4SArnaldo Carvalho de Melo 	Elf *elf;
410a25e46c4SArnaldo Carvalho de Melo 	int nr = 0, symidx, fd, err = 0;
41186470930SIngo Molnar 
412a25e46c4SArnaldo Carvalho de Melo 	fd = open(self->name, O_RDONLY);
413a25e46c4SArnaldo Carvalho de Melo 	if (fd < 0)
414a25e46c4SArnaldo Carvalho de Melo 		goto out;
415a25e46c4SArnaldo Carvalho de Melo 
416*84087126SMarti Raudsepp 	elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
417a25e46c4SArnaldo Carvalho de Melo 	if (elf == NULL)
418a25e46c4SArnaldo Carvalho de Melo 		goto out_close;
419a25e46c4SArnaldo Carvalho de Melo 
420a25e46c4SArnaldo Carvalho de Melo 	if (gelf_getehdr(elf, &ehdr) == NULL)
421a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
422a25e46c4SArnaldo Carvalho de Melo 
423a25e46c4SArnaldo Carvalho de Melo 	scn_dynsym = elf_section_by_name(elf, &ehdr, &shdr_dynsym,
424a25e46c4SArnaldo Carvalho de Melo 					 ".dynsym", &dynsym_idx);
425a25e46c4SArnaldo Carvalho de Melo 	if (scn_dynsym == NULL)
426a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
427a25e46c4SArnaldo Carvalho de Melo 
428a25e46c4SArnaldo Carvalho de Melo 	scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
42986470930SIngo Molnar 					  ".rela.plt", NULL);
43086470930SIngo Molnar 	if (scn_plt_rel == NULL) {
431a25e46c4SArnaldo Carvalho de Melo 		scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
43286470930SIngo Molnar 						  ".rel.plt", NULL);
43386470930SIngo Molnar 		if (scn_plt_rel == NULL)
434a25e46c4SArnaldo Carvalho de Melo 			goto out_elf_end;
43586470930SIngo Molnar 	}
43686470930SIngo Molnar 
437a25e46c4SArnaldo Carvalho de Melo 	err = -1;
43886470930SIngo Molnar 
439a25e46c4SArnaldo Carvalho de Melo 	if (shdr_rel_plt.sh_link != dynsym_idx)
440a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
441a25e46c4SArnaldo Carvalho de Melo 
442a25e46c4SArnaldo Carvalho de Melo 	if (elf_section_by_name(elf, &ehdr, &shdr_plt, ".plt", NULL) == NULL)
443a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
44486470930SIngo Molnar 
44586470930SIngo Molnar 	/*
44683a0944fSIngo Molnar 	 * Fetch the relocation section to find the idxes to the GOT
44786470930SIngo Molnar 	 * and the symbols in the .dynsym they refer to.
44886470930SIngo Molnar 	 */
44986470930SIngo Molnar 	reldata = elf_getdata(scn_plt_rel, NULL);
45086470930SIngo Molnar 	if (reldata == NULL)
451a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
45286470930SIngo Molnar 
45386470930SIngo Molnar 	syms = elf_getdata(scn_dynsym, NULL);
45486470930SIngo Molnar 	if (syms == NULL)
455a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
45686470930SIngo Molnar 
457a25e46c4SArnaldo Carvalho de Melo 	scn_symstrs = elf_getscn(elf, shdr_dynsym.sh_link);
45886470930SIngo Molnar 	if (scn_symstrs == NULL)
459a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
46086470930SIngo Molnar 
46186470930SIngo Molnar 	symstrs = elf_getdata(scn_symstrs, NULL);
46286470930SIngo Molnar 	if (symstrs == NULL)
463a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
46486470930SIngo Molnar 
46586470930SIngo Molnar 	nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize;
46686470930SIngo Molnar 	plt_offset = shdr_plt.sh_offset;
46786470930SIngo Molnar 
46886470930SIngo Molnar 	if (shdr_rel_plt.sh_type == SHT_RELA) {
46986470930SIngo Molnar 		GElf_Rela pos_mem, *pos;
47086470930SIngo Molnar 
47186470930SIngo Molnar 		elf_section__for_each_rela(reldata, pos, pos_mem, idx,
47286470930SIngo Molnar 					   nr_rel_entries) {
47386470930SIngo Molnar 			symidx = GELF_R_SYM(pos->r_info);
47486470930SIngo Molnar 			plt_offset += shdr_plt.sh_entsize;
47586470930SIngo Molnar 			gelf_getsym(syms, symidx, &sym);
47686470930SIngo Molnar 			snprintf(sympltname, sizeof(sympltname),
47786470930SIngo Molnar 				 "%s@plt", elf_sym__name(&sym, symstrs));
47886470930SIngo Molnar 
47986470930SIngo Molnar 			f = symbol__new(plt_offset, shdr_plt.sh_entsize,
48083a0944fSIngo Molnar 					sympltname, self->sym_priv_size, 0, v);
48186470930SIngo Molnar 			if (!f)
482a25e46c4SArnaldo Carvalho de Melo 				goto out_elf_end;
48386470930SIngo Molnar 
48486470930SIngo Molnar 			dso__insert_symbol(self, f);
48586470930SIngo Molnar 			++nr;
48686470930SIngo Molnar 		}
48786470930SIngo Molnar 	} else if (shdr_rel_plt.sh_type == SHT_REL) {
48886470930SIngo Molnar 		GElf_Rel pos_mem, *pos;
48986470930SIngo Molnar 		elf_section__for_each_rel(reldata, pos, pos_mem, idx,
49086470930SIngo Molnar 					  nr_rel_entries) {
49186470930SIngo Molnar 			symidx = GELF_R_SYM(pos->r_info);
49286470930SIngo Molnar 			plt_offset += shdr_plt.sh_entsize;
49386470930SIngo Molnar 			gelf_getsym(syms, symidx, &sym);
49486470930SIngo Molnar 			snprintf(sympltname, sizeof(sympltname),
49586470930SIngo Molnar 				 "%s@plt", elf_sym__name(&sym, symstrs));
49686470930SIngo Molnar 
49786470930SIngo Molnar 			f = symbol__new(plt_offset, shdr_plt.sh_entsize,
49883a0944fSIngo Molnar 					sympltname, self->sym_priv_size, 0, v);
49986470930SIngo Molnar 			if (!f)
500a25e46c4SArnaldo Carvalho de Melo 				goto out_elf_end;
50186470930SIngo Molnar 
50286470930SIngo Molnar 			dso__insert_symbol(self, f);
50386470930SIngo Molnar 			++nr;
50486470930SIngo Molnar 		}
50586470930SIngo Molnar 	}
50686470930SIngo Molnar 
507a25e46c4SArnaldo Carvalho de Melo 	err = 0;
508a25e46c4SArnaldo Carvalho de Melo out_elf_end:
509a25e46c4SArnaldo Carvalho de Melo 	elf_end(elf);
510a25e46c4SArnaldo Carvalho de Melo out_close:
511a25e46c4SArnaldo Carvalho de Melo 	close(fd);
512a25e46c4SArnaldo Carvalho de Melo 
513a25e46c4SArnaldo Carvalho de Melo 	if (err == 0)
51486470930SIngo Molnar 		return nr;
515a25e46c4SArnaldo Carvalho de Melo out:
516a25e46c4SArnaldo Carvalho de Melo 	fprintf(stderr, "%s: problems reading %s PLT info.\n",
517a25e46c4SArnaldo Carvalho de Melo 		__func__, self->name);
518a25e46c4SArnaldo Carvalho de Melo 	return 0;
51986470930SIngo Molnar }
52086470930SIngo Molnar 
52186470930SIngo Molnar static int dso__load_sym(struct dso *self, int fd, const char *name,
52283a0944fSIngo Molnar 			 symbol_filter_t filter, int v, struct module *mod)
52386470930SIngo Molnar {
5246cfcc53eSMike Galbraith 	Elf_Data *symstrs, *secstrs;
52586470930SIngo Molnar 	uint32_t nr_syms;
52686470930SIngo Molnar 	int err = -1;
52783a0944fSIngo Molnar 	uint32_t idx;
52886470930SIngo Molnar 	GElf_Ehdr ehdr;
52986470930SIngo Molnar 	GElf_Shdr shdr;
53086470930SIngo Molnar 	Elf_Data *syms;
53186470930SIngo Molnar 	GElf_Sym sym;
532a25e46c4SArnaldo Carvalho de Melo 	Elf_Scn *sec, *sec_strndx;
53386470930SIngo Molnar 	Elf *elf;
534d20ff6bdSMike Galbraith 	int nr = 0, kernel = !strcmp("[kernel]", self->name);
53586470930SIngo Molnar 
536*84087126SMarti Raudsepp 	elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
53786470930SIngo Molnar 	if (elf == NULL) {
53883a0944fSIngo Molnar 		if (v)
53986470930SIngo Molnar 			fprintf(stderr, "%s: cannot read %s ELF file.\n",
54086470930SIngo Molnar 				__func__, name);
54186470930SIngo Molnar 		goto out_close;
54286470930SIngo Molnar 	}
54386470930SIngo Molnar 
54486470930SIngo Molnar 	if (gelf_getehdr(elf, &ehdr) == NULL) {
54583a0944fSIngo Molnar 		if (v)
54686470930SIngo Molnar 			fprintf(stderr, "%s: cannot get elf header.\n", __func__);
54786470930SIngo Molnar 		goto out_elf_end;
54886470930SIngo Molnar 	}
54986470930SIngo Molnar 
55086470930SIngo Molnar 	sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL);
55186470930SIngo Molnar 	if (sec == NULL) {
552a25e46c4SArnaldo Carvalho de Melo 		sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL);
553a25e46c4SArnaldo Carvalho de Melo 		if (sec == NULL)
55486470930SIngo Molnar 			goto out_elf_end;
55586470930SIngo Molnar 	}
55686470930SIngo Molnar 
55786470930SIngo Molnar 	syms = elf_getdata(sec, NULL);
55886470930SIngo Molnar 	if (syms == NULL)
55986470930SIngo Molnar 		goto out_elf_end;
56086470930SIngo Molnar 
56186470930SIngo Molnar 	sec = elf_getscn(elf, shdr.sh_link);
56286470930SIngo Molnar 	if (sec == NULL)
56386470930SIngo Molnar 		goto out_elf_end;
56486470930SIngo Molnar 
56586470930SIngo Molnar 	symstrs = elf_getdata(sec, NULL);
56686470930SIngo Molnar 	if (symstrs == NULL)
56786470930SIngo Molnar 		goto out_elf_end;
56886470930SIngo Molnar 
5696cfcc53eSMike Galbraith 	sec_strndx = elf_getscn(elf, ehdr.e_shstrndx);
5706cfcc53eSMike Galbraith 	if (sec_strndx == NULL)
5716cfcc53eSMike Galbraith 		goto out_elf_end;
5726cfcc53eSMike Galbraith 
5736cfcc53eSMike Galbraith 	secstrs = elf_getdata(sec_strndx, NULL);
5749b30a26bSStoyan Gaydarov 	if (secstrs == NULL)
5756cfcc53eSMike Galbraith 		goto out_elf_end;
5766cfcc53eSMike Galbraith 
57786470930SIngo Molnar 	nr_syms = shdr.sh_size / shdr.sh_entsize;
57886470930SIngo Molnar 
579e9fbc9dcSArjan van de Ven 	memset(&sym, 0, sizeof(sym));
580d20ff6bdSMike Galbraith 	if (!kernel) {
58130d7a77dSArnaldo Carvalho de Melo 		self->adjust_symbols = (ehdr.e_type == ET_EXEC ||
58230d7a77dSArnaldo Carvalho de Melo 				elf_section_by_name(elf, &ehdr, &shdr,
583f5812a7aSArnaldo Carvalho de Melo 						     ".gnu.prelink_undo",
58430d7a77dSArnaldo Carvalho de Melo 						     NULL) != NULL);
585d20ff6bdSMike Galbraith 	} else self->adjust_symbols = 0;
586d20ff6bdSMike Galbraith 
58783a0944fSIngo Molnar 	elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) {
58886470930SIngo Molnar 		struct symbol *f;
58983a0944fSIngo Molnar 		const char *elf_name;
59028ac909bSArnaldo Carvalho de Melo 		char *demangled;
5919cffa8d5SPaul Mackerras 		u64 obj_start;
5926cfcc53eSMike Galbraith 		struct section *section = NULL;
5936cfcc53eSMike Galbraith 		int is_label = elf_sym__is_label(&sym);
5946cfcc53eSMike Galbraith 		const char *section_name;
59586470930SIngo Molnar 
5966cfcc53eSMike Galbraith 		if (!is_label && !elf_sym__is_function(&sym))
59786470930SIngo Molnar 			continue;
59886470930SIngo Molnar 
59986470930SIngo Molnar 		sec = elf_getscn(elf, sym.st_shndx);
60086470930SIngo Molnar 		if (!sec)
60186470930SIngo Molnar 			goto out_elf_end;
60286470930SIngo Molnar 
60386470930SIngo Molnar 		gelf_getshdr(sec, &shdr);
6046cfcc53eSMike Galbraith 
6056cfcc53eSMike Galbraith 		if (is_label && !elf_sec__is_text(&shdr, secstrs))
6066cfcc53eSMike Galbraith 			continue;
6076cfcc53eSMike Galbraith 
6086cfcc53eSMike Galbraith 		section_name = elf_sec__name(&shdr, secstrs);
60986470930SIngo Molnar 		obj_start = sym.st_value;
61086470930SIngo Molnar 
61130d7a77dSArnaldo Carvalho de Melo 		if (self->adjust_symbols) {
61283a0944fSIngo Molnar 			if (v >= 2)
613520f2c34SPeter Zijlstra 				printf("adjusting symbol: st_value: %Lx sh_addr: %Lx sh_offset: %Lx\n",
614520f2c34SPeter Zijlstra 					(u64)sym.st_value, (u64)shdr.sh_addr, (u64)shdr.sh_offset);
615520f2c34SPeter Zijlstra 
61686470930SIngo Molnar 			sym.st_value -= shdr.sh_addr - shdr.sh_offset;
617f5812a7aSArnaldo Carvalho de Melo 		}
61886470930SIngo Molnar 
6196cfcc53eSMike Galbraith 		if (mod) {
6206cfcc53eSMike Galbraith 			section = mod->sections->find_section(mod->sections, section_name);
6216cfcc53eSMike Galbraith 			if (section)
6226cfcc53eSMike Galbraith 				sym.st_value += section->vma;
6236cfcc53eSMike Galbraith 			else {
6246cfcc53eSMike Galbraith 				fprintf(stderr, "dso__load_sym() module %s lookup of %s failed\n",
6256cfcc53eSMike Galbraith 					mod->name, section_name);
6266cfcc53eSMike Galbraith 				goto out_elf_end;
6276cfcc53eSMike Galbraith 			}
6286cfcc53eSMike Galbraith 		}
62928ac909bSArnaldo Carvalho de Melo 		/*
63028ac909bSArnaldo Carvalho de Melo 		 * We need to figure out if the object was created from C++ sources
63128ac909bSArnaldo Carvalho de Melo 		 * DWARF DW_compile_unit has this, but we don't always have access
63228ac909bSArnaldo Carvalho de Melo 		 * to it...
63328ac909bSArnaldo Carvalho de Melo 		 */
63483a0944fSIngo Molnar 		elf_name = elf_sym__name(&sym, symstrs);
63583a0944fSIngo Molnar 		demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI);
63628ac909bSArnaldo Carvalho de Melo 		if (demangled != NULL)
63783a0944fSIngo Molnar 			elf_name = demangled;
6386cfcc53eSMike Galbraith 
63983a0944fSIngo Molnar 		f = symbol__new(sym.st_value, sym.st_size, elf_name,
64083a0944fSIngo Molnar 				self->sym_priv_size, obj_start, v);
64128ac909bSArnaldo Carvalho de Melo 		free(demangled);
64286470930SIngo Molnar 		if (!f)
64386470930SIngo Molnar 			goto out_elf_end;
64486470930SIngo Molnar 
64586470930SIngo Molnar 		if (filter && filter(self, f))
64686470930SIngo Molnar 			symbol__delete(f, self->sym_priv_size);
64786470930SIngo Molnar 		else {
6486cfcc53eSMike Galbraith 			f->module = mod;
64986470930SIngo Molnar 			dso__insert_symbol(self, f);
65086470930SIngo Molnar 			nr++;
65186470930SIngo Molnar 		}
65286470930SIngo Molnar 	}
65386470930SIngo Molnar 
65486470930SIngo Molnar 	err = nr;
65586470930SIngo Molnar out_elf_end:
65686470930SIngo Molnar 	elf_end(elf);
65786470930SIngo Molnar out_close:
65886470930SIngo Molnar 	return err;
65986470930SIngo Molnar }
66086470930SIngo Molnar 
6614d1e00a8SArnaldo Carvalho de Melo #define BUILD_ID_SIZE 128
6624d1e00a8SArnaldo Carvalho de Melo 
66383a0944fSIngo Molnar static char *dso__read_build_id(struct dso *self, int v)
6644d1e00a8SArnaldo Carvalho de Melo {
6654d1e00a8SArnaldo Carvalho de Melo 	int i;
6664d1e00a8SArnaldo Carvalho de Melo 	GElf_Ehdr ehdr;
6674d1e00a8SArnaldo Carvalho de Melo 	GElf_Shdr shdr;
6684d1e00a8SArnaldo Carvalho de Melo 	Elf_Data *build_id_data;
6694d1e00a8SArnaldo Carvalho de Melo 	Elf_Scn *sec;
6704d1e00a8SArnaldo Carvalho de Melo 	char *build_id = NULL, *bid;
6714d1e00a8SArnaldo Carvalho de Melo 	unsigned char *raw;
6724d1e00a8SArnaldo Carvalho de Melo 	Elf *elf;
6734d1e00a8SArnaldo Carvalho de Melo 	int fd = open(self->name, O_RDONLY);
6744d1e00a8SArnaldo Carvalho de Melo 
6754d1e00a8SArnaldo Carvalho de Melo 	if (fd < 0)
6764d1e00a8SArnaldo Carvalho de Melo 		goto out;
6774d1e00a8SArnaldo Carvalho de Melo 
678*84087126SMarti Raudsepp 	elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
6794d1e00a8SArnaldo Carvalho de Melo 	if (elf == NULL) {
68083a0944fSIngo Molnar 		if (v)
6814d1e00a8SArnaldo Carvalho de Melo 			fprintf(stderr, "%s: cannot read %s ELF file.\n",
6824d1e00a8SArnaldo Carvalho de Melo 				__func__, self->name);
6834d1e00a8SArnaldo Carvalho de Melo 		goto out_close;
6844d1e00a8SArnaldo Carvalho de Melo 	}
6854d1e00a8SArnaldo Carvalho de Melo 
6864d1e00a8SArnaldo Carvalho de Melo 	if (gelf_getehdr(elf, &ehdr) == NULL) {
68783a0944fSIngo Molnar 		if (v)
6884d1e00a8SArnaldo Carvalho de Melo 			fprintf(stderr, "%s: cannot get elf header.\n", __func__);
6894d1e00a8SArnaldo Carvalho de Melo 		goto out_elf_end;
6904d1e00a8SArnaldo Carvalho de Melo 	}
6914d1e00a8SArnaldo Carvalho de Melo 
6924d1e00a8SArnaldo Carvalho de Melo 	sec = elf_section_by_name(elf, &ehdr, &shdr, ".note.gnu.build-id", NULL);
6934d1e00a8SArnaldo Carvalho de Melo 	if (sec == NULL)
6944d1e00a8SArnaldo Carvalho de Melo 		goto out_elf_end;
6954d1e00a8SArnaldo Carvalho de Melo 
6964d1e00a8SArnaldo Carvalho de Melo 	build_id_data = elf_getdata(sec, NULL);
6974d1e00a8SArnaldo Carvalho de Melo 	if (build_id_data == NULL)
6984d1e00a8SArnaldo Carvalho de Melo 		goto out_elf_end;
6994d1e00a8SArnaldo Carvalho de Melo 	build_id = malloc(BUILD_ID_SIZE);
7004d1e00a8SArnaldo Carvalho de Melo 	if (build_id == NULL)
7014d1e00a8SArnaldo Carvalho de Melo 		goto out_elf_end;
7024d1e00a8SArnaldo Carvalho de Melo 	raw = build_id_data->d_buf + 16;
7034d1e00a8SArnaldo Carvalho de Melo 	bid = build_id;
7044d1e00a8SArnaldo Carvalho de Melo 
7054d1e00a8SArnaldo Carvalho de Melo 	for (i = 0; i < 20; ++i) {
7064d1e00a8SArnaldo Carvalho de Melo 		sprintf(bid, "%02x", *raw);
7074d1e00a8SArnaldo Carvalho de Melo 		++raw;
7084d1e00a8SArnaldo Carvalho de Melo 		bid += 2;
7094d1e00a8SArnaldo Carvalho de Melo 	}
71083a0944fSIngo Molnar 	if (v >= 2)
7114d1e00a8SArnaldo Carvalho de Melo 		printf("%s(%s): %s\n", __func__, self->name, build_id);
7124d1e00a8SArnaldo Carvalho de Melo out_elf_end:
7134d1e00a8SArnaldo Carvalho de Melo 	elf_end(elf);
7144d1e00a8SArnaldo Carvalho de Melo out_close:
7154d1e00a8SArnaldo Carvalho de Melo 	close(fd);
7164d1e00a8SArnaldo Carvalho de Melo out:
7174d1e00a8SArnaldo Carvalho de Melo 	return build_id;
7184d1e00a8SArnaldo Carvalho de Melo }
7194d1e00a8SArnaldo Carvalho de Melo 
72094cb9e38SArnaldo Carvalho de Melo char dso__symtab_origin(const struct dso *self)
72194cb9e38SArnaldo Carvalho de Melo {
72294cb9e38SArnaldo Carvalho de Melo 	static const char origin[] = {
72394cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_KERNEL] =   'k',
72494cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_JAVA_JIT] = 'j',
72594cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_FEDORA] =   'f',
72694cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_UBUNTU] =   'u',
72794cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_BUILDID] =  'b',
72894cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_DSO] =      'd',
72994cb9e38SArnaldo Carvalho de Melo 	};
73094cb9e38SArnaldo Carvalho de Melo 
73194cb9e38SArnaldo Carvalho de Melo 	if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND)
73294cb9e38SArnaldo Carvalho de Melo 		return '!';
73394cb9e38SArnaldo Carvalho de Melo 	return origin[self->origin];
73494cb9e38SArnaldo Carvalho de Melo }
73594cb9e38SArnaldo Carvalho de Melo 
73683a0944fSIngo Molnar int dso__load(struct dso *self, symbol_filter_t filter, int v)
73786470930SIngo Molnar {
7384d1e00a8SArnaldo Carvalho de Melo 	int size = PATH_MAX;
7394d1e00a8SArnaldo Carvalho de Melo 	char *name = malloc(size), *build_id = NULL;
74086470930SIngo Molnar 	int ret = -1;
74186470930SIngo Molnar 	int fd;
74286470930SIngo Molnar 
74386470930SIngo Molnar 	if (!name)
74486470930SIngo Molnar 		return -1;
74586470930SIngo Molnar 
74630d7a77dSArnaldo Carvalho de Melo 	self->adjust_symbols = 0;
747f5812a7aSArnaldo Carvalho de Melo 
74894cb9e38SArnaldo Carvalho de Melo 	if (strncmp(self->name, "/tmp/perf-", 10) == 0) {
74983a0944fSIngo Molnar 		ret = dso__load_perf_map(self, filter, v);
75094cb9e38SArnaldo Carvalho de Melo 		self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT :
75194cb9e38SArnaldo Carvalho de Melo 					 DSO__ORIG_NOT_FOUND;
75294cb9e38SArnaldo Carvalho de Melo 		return ret;
75394cb9e38SArnaldo Carvalho de Melo 	}
75494cb9e38SArnaldo Carvalho de Melo 
75594cb9e38SArnaldo Carvalho de Melo 	self->origin = DSO__ORIG_FEDORA - 1;
75680d496beSPekka Enberg 
75786470930SIngo Molnar more:
75886470930SIngo Molnar 	do {
75994cb9e38SArnaldo Carvalho de Melo 		self->origin++;
76094cb9e38SArnaldo Carvalho de Melo 		switch (self->origin) {
76194cb9e38SArnaldo Carvalho de Melo 		case DSO__ORIG_FEDORA:
76286470930SIngo Molnar 			snprintf(name, size, "/usr/lib/debug%s.debug", self->name);
76386470930SIngo Molnar 			break;
76494cb9e38SArnaldo Carvalho de Melo 		case DSO__ORIG_UBUNTU:
76586470930SIngo Molnar 			snprintf(name, size, "/usr/lib/debug%s", self->name);
76686470930SIngo Molnar 			break;
76794cb9e38SArnaldo Carvalho de Melo 		case DSO__ORIG_BUILDID:
76883a0944fSIngo Molnar 			build_id = dso__read_build_id(self, v);
7694d1e00a8SArnaldo Carvalho de Melo 			if (build_id != NULL) {
7704d1e00a8SArnaldo Carvalho de Melo 				snprintf(name, size,
7714d1e00a8SArnaldo Carvalho de Melo 					 "/usr/lib/debug/.build-id/%.2s/%s.debug",
7724d1e00a8SArnaldo Carvalho de Melo 					build_id, build_id + 2);
7734d1e00a8SArnaldo Carvalho de Melo 				free(build_id);
7744d1e00a8SArnaldo Carvalho de Melo 				break;
7754d1e00a8SArnaldo Carvalho de Melo 			}
77694cb9e38SArnaldo Carvalho de Melo 			self->origin++;
7774d1e00a8SArnaldo Carvalho de Melo 			/* Fall thru */
77894cb9e38SArnaldo Carvalho de Melo 		case DSO__ORIG_DSO:
77986470930SIngo Molnar 			snprintf(name, size, "%s", self->name);
78086470930SIngo Molnar 			break;
78186470930SIngo Molnar 
78286470930SIngo Molnar 		default:
78386470930SIngo Molnar 			goto out;
78486470930SIngo Molnar 		}
78586470930SIngo Molnar 
78686470930SIngo Molnar 		fd = open(name, O_RDONLY);
78786470930SIngo Molnar 	} while (fd < 0);
78886470930SIngo Molnar 
78983a0944fSIngo Molnar 	ret = dso__load_sym(self, fd, name, filter, v, NULL);
79086470930SIngo Molnar 	close(fd);
79186470930SIngo Molnar 
79286470930SIngo Molnar 	/*
79386470930SIngo Molnar 	 * Some people seem to have debuginfo files _WITHOUT_ debug info!?!?
79486470930SIngo Molnar 	 */
79586470930SIngo Molnar 	if (!ret)
79686470930SIngo Molnar 		goto more;
79786470930SIngo Molnar 
798a25e46c4SArnaldo Carvalho de Melo 	if (ret > 0) {
79983a0944fSIngo Molnar 		int nr_plt = dso__synthesize_plt_symbols(self, v);
800a25e46c4SArnaldo Carvalho de Melo 		if (nr_plt > 0)
801a25e46c4SArnaldo Carvalho de Melo 			ret += nr_plt;
802a25e46c4SArnaldo Carvalho de Melo 	}
80386470930SIngo Molnar out:
80486470930SIngo Molnar 	free(name);
8051340e6bbSArnaldo Carvalho de Melo 	if (ret < 0 && strstr(self->name, " (deleted)") != NULL)
8061340e6bbSArnaldo Carvalho de Melo 		return 0;
80786470930SIngo Molnar 	return ret;
80886470930SIngo Molnar }
80986470930SIngo Molnar 
8106cfcc53eSMike Galbraith static int dso__load_module(struct dso *self, struct mod_dso *mods, const char *name,
81183a0944fSIngo Molnar 			     symbol_filter_t filter, int v)
8126cfcc53eSMike Galbraith {
8136cfcc53eSMike Galbraith 	struct module *mod = mod_dso__find_module(mods, name);
8146cfcc53eSMike Galbraith 	int err = 0, fd;
8156cfcc53eSMike Galbraith 
8166cfcc53eSMike Galbraith 	if (mod == NULL || !mod->active)
8176cfcc53eSMike Galbraith 		return err;
8186cfcc53eSMike Galbraith 
8196cfcc53eSMike Galbraith 	fd = open(mod->path, O_RDONLY);
8206cfcc53eSMike Galbraith 
8216cfcc53eSMike Galbraith 	if (fd < 0)
8226cfcc53eSMike Galbraith 		return err;
8236cfcc53eSMike Galbraith 
82483a0944fSIngo Molnar 	err = dso__load_sym(self, fd, name, filter, v, mod);
8256cfcc53eSMike Galbraith 	close(fd);
8266cfcc53eSMike Galbraith 
8276cfcc53eSMike Galbraith 	return err;
8286cfcc53eSMike Galbraith }
8296cfcc53eSMike Galbraith 
83083a0944fSIngo Molnar int dso__load_modules(struct dso *self, symbol_filter_t filter, int v)
8316cfcc53eSMike Galbraith {
8326cfcc53eSMike Galbraith 	struct mod_dso *mods = mod_dso__new_dso("modules");
8336cfcc53eSMike Galbraith 	struct module *pos;
8346cfcc53eSMike Galbraith 	struct rb_node *next;
835508c4d08SMike Galbraith 	int err, count = 0;
8366cfcc53eSMike Galbraith 
8376cfcc53eSMike Galbraith 	err = mod_dso__load_modules(mods);
8386cfcc53eSMike Galbraith 
8396cfcc53eSMike Galbraith 	if (err <= 0)
8406cfcc53eSMike Galbraith 		return err;
8416cfcc53eSMike Galbraith 
8426cfcc53eSMike Galbraith 	/*
8436cfcc53eSMike Galbraith 	 * Iterate over modules, and load active symbols.
8446cfcc53eSMike Galbraith 	 */
8456cfcc53eSMike Galbraith 	next = rb_first(&mods->mods);
8466cfcc53eSMike Galbraith 	while (next) {
8476cfcc53eSMike Galbraith 		pos = rb_entry(next, struct module, rb_node);
84883a0944fSIngo Molnar 		err = dso__load_module(self, mods, pos->name, filter, v);
8496cfcc53eSMike Galbraith 
8506cfcc53eSMike Galbraith 		if (err < 0)
8516cfcc53eSMike Galbraith 			break;
8526cfcc53eSMike Galbraith 
8536cfcc53eSMike Galbraith 		next = rb_next(&pos->rb_node);
854508c4d08SMike Galbraith 		count += err;
8556cfcc53eSMike Galbraith 	}
8566cfcc53eSMike Galbraith 
8576cfcc53eSMike Galbraith 	if (err < 0) {
8586cfcc53eSMike Galbraith 		mod_dso__delete_modules(mods);
8596cfcc53eSMike Galbraith 		mod_dso__delete_self(mods);
860508c4d08SMike Galbraith 		return err;
8616cfcc53eSMike Galbraith 	}
8626cfcc53eSMike Galbraith 
863508c4d08SMike Galbraith 	return count;
8646cfcc53eSMike Galbraith }
8656cfcc53eSMike Galbraith 
8666cfcc53eSMike Galbraith static inline void dso__fill_symbol_holes(struct dso *self)
8676cfcc53eSMike Galbraith {
8686cfcc53eSMike Galbraith 	struct symbol *prev = NULL;
8696cfcc53eSMike Galbraith 	struct rb_node *nd;
8706cfcc53eSMike Galbraith 
8716cfcc53eSMike Galbraith 	for (nd = rb_last(&self->syms); nd; nd = rb_prev(nd)) {
8726cfcc53eSMike Galbraith 		struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
8736cfcc53eSMike Galbraith 
8746cfcc53eSMike Galbraith 		if (prev) {
8756cfcc53eSMike Galbraith 			u64 hole = 0;
8766cfcc53eSMike Galbraith 			int alias = pos->start == prev->start;
8776cfcc53eSMike Galbraith 
8786cfcc53eSMike Galbraith 			if (!alias)
8796cfcc53eSMike Galbraith 				hole = prev->start - pos->end - 1;
8806cfcc53eSMike Galbraith 
8816cfcc53eSMike Galbraith 			if (hole || alias) {
8826cfcc53eSMike Galbraith 				if (alias)
8836cfcc53eSMike Galbraith 					pos->end = prev->end;
8846cfcc53eSMike Galbraith 				else if (hole)
8856cfcc53eSMike Galbraith 					pos->end = prev->start - 1;
8866cfcc53eSMike Galbraith 			}
8876cfcc53eSMike Galbraith 		}
8886cfcc53eSMike Galbraith 		prev = pos;
8896cfcc53eSMike Galbraith 	}
8906cfcc53eSMike Galbraith }
8916cfcc53eSMike Galbraith 
89286470930SIngo Molnar static int dso__load_vmlinux(struct dso *self, const char *vmlinux,
89383a0944fSIngo Molnar 			     symbol_filter_t filter, int v)
89486470930SIngo Molnar {
89586470930SIngo Molnar 	int err, fd = open(vmlinux, O_RDONLY);
89686470930SIngo Molnar 
89786470930SIngo Molnar 	if (fd < 0)
89886470930SIngo Molnar 		return -1;
89986470930SIngo Molnar 
90083a0944fSIngo Molnar 	err = dso__load_sym(self, fd, vmlinux, filter, v, NULL);
9016cfcc53eSMike Galbraith 
9026cfcc53eSMike Galbraith 	if (err > 0)
9036cfcc53eSMike Galbraith 		dso__fill_symbol_holes(self);
9046cfcc53eSMike Galbraith 
90586470930SIngo Molnar 	close(fd);
90686470930SIngo Molnar 
90786470930SIngo Molnar 	return err;
90886470930SIngo Molnar }
90986470930SIngo Molnar 
91086470930SIngo Molnar int dso__load_kernel(struct dso *self, const char *vmlinux,
91183a0944fSIngo Molnar 		     symbol_filter_t filter, int v, int use_modules)
91286470930SIngo Molnar {
91386470930SIngo Molnar 	int err = -1;
91486470930SIngo Molnar 
9156cfcc53eSMike Galbraith 	if (vmlinux) {
91683a0944fSIngo Molnar 		err = dso__load_vmlinux(self, vmlinux, filter, v);
917508c4d08SMike Galbraith 		if (err > 0 && use_modules) {
918508c4d08SMike Galbraith 			int syms = dso__load_modules(self, filter, v);
919508c4d08SMike Galbraith 
920508c4d08SMike Galbraith 			if (syms < 0) {
921508c4d08SMike Galbraith 				fprintf(stderr, "dso__load_modules failed!\n");
922508c4d08SMike Galbraith 				return syms;
923508c4d08SMike Galbraith 			}
924508c4d08SMike Galbraith 			err += syms;
925508c4d08SMike Galbraith 		}
9266cfcc53eSMike Galbraith 	}
92786470930SIngo Molnar 
9289974f496SMike Galbraith 	if (err <= 0)
92983a0944fSIngo Molnar 		err = dso__load_kallsyms(self, filter, v);
93086470930SIngo Molnar 
93194cb9e38SArnaldo Carvalho de Melo 	if (err > 0)
93294cb9e38SArnaldo Carvalho de Melo 		self->origin = DSO__ORIG_KERNEL;
93394cb9e38SArnaldo Carvalho de Melo 
93486470930SIngo Molnar 	return err;
93586470930SIngo Molnar }
93686470930SIngo Molnar 
937cd84c2acSFrederic Weisbecker LIST_HEAD(dsos);
938cd84c2acSFrederic Weisbecker struct dso	*kernel_dso;
939cd84c2acSFrederic Weisbecker struct dso	*vdso;
940cd84c2acSFrederic Weisbecker struct dso	*hypervisor_dso;
941cd84c2acSFrederic Weisbecker 
94283a0944fSIngo Molnar const char	*vmlinux_name = "vmlinux";
943cd84c2acSFrederic Weisbecker int		modules;
944cd84c2acSFrederic Weisbecker 
945cd84c2acSFrederic Weisbecker static void dsos__add(struct dso *dso)
946cd84c2acSFrederic Weisbecker {
947cd84c2acSFrederic Weisbecker 	list_add_tail(&dso->node, &dsos);
948cd84c2acSFrederic Weisbecker }
949cd84c2acSFrederic Weisbecker 
950cd84c2acSFrederic Weisbecker static struct dso *dsos__find(const char *name)
951cd84c2acSFrederic Weisbecker {
952cd84c2acSFrederic Weisbecker 	struct dso *pos;
953cd84c2acSFrederic Weisbecker 
954cd84c2acSFrederic Weisbecker 	list_for_each_entry(pos, &dsos, node)
955cd84c2acSFrederic Weisbecker 		if (strcmp(pos->name, name) == 0)
956cd84c2acSFrederic Weisbecker 			return pos;
957cd84c2acSFrederic Weisbecker 	return NULL;
958cd84c2acSFrederic Weisbecker }
959cd84c2acSFrederic Weisbecker 
960cd84c2acSFrederic Weisbecker struct dso *dsos__findnew(const char *name)
961cd84c2acSFrederic Weisbecker {
962cd84c2acSFrederic Weisbecker 	struct dso *dso = dsos__find(name);
963cd84c2acSFrederic Weisbecker 	int nr;
964cd84c2acSFrederic Weisbecker 
965cd84c2acSFrederic Weisbecker 	if (dso)
966cd84c2acSFrederic Weisbecker 		return dso;
967cd84c2acSFrederic Weisbecker 
968cd84c2acSFrederic Weisbecker 	dso = dso__new(name, 0);
969cd84c2acSFrederic Weisbecker 	if (!dso)
970cd84c2acSFrederic Weisbecker 		goto out_delete_dso;
971cd84c2acSFrederic Weisbecker 
972cd84c2acSFrederic Weisbecker 	nr = dso__load(dso, NULL, verbose);
973cd84c2acSFrederic Weisbecker 	if (nr < 0) {
974cd84c2acSFrederic Weisbecker 		eprintf("Failed to open: %s\n", name);
975cd84c2acSFrederic Weisbecker 		goto out_delete_dso;
976cd84c2acSFrederic Weisbecker 	}
977cd84c2acSFrederic Weisbecker 	if (!nr)
978cd84c2acSFrederic Weisbecker 		eprintf("No symbols found in: %s, maybe install a debug package?\n", name);
979cd84c2acSFrederic Weisbecker 
980cd84c2acSFrederic Weisbecker 	dsos__add(dso);
981cd84c2acSFrederic Weisbecker 
982cd84c2acSFrederic Weisbecker 	return dso;
983cd84c2acSFrederic Weisbecker 
984cd84c2acSFrederic Weisbecker out_delete_dso:
985cd84c2acSFrederic Weisbecker 	dso__delete(dso);
986cd84c2acSFrederic Weisbecker 	return NULL;
987cd84c2acSFrederic Weisbecker }
988cd84c2acSFrederic Weisbecker 
989cd84c2acSFrederic Weisbecker void dsos__fprintf(FILE *fp)
990cd84c2acSFrederic Weisbecker {
991cd84c2acSFrederic Weisbecker 	struct dso *pos;
992cd84c2acSFrederic Weisbecker 
993cd84c2acSFrederic Weisbecker 	list_for_each_entry(pos, &dsos, node)
994cd84c2acSFrederic Weisbecker 		dso__fprintf(pos, fp);
995cd84c2acSFrederic Weisbecker }
996cd84c2acSFrederic Weisbecker 
997cd84c2acSFrederic Weisbecker static struct symbol *vdso__find_symbol(struct dso *dso, u64 ip)
998cd84c2acSFrederic Weisbecker {
999cd84c2acSFrederic Weisbecker 	return dso__find_symbol(dso, ip);
1000cd84c2acSFrederic Weisbecker }
1001cd84c2acSFrederic Weisbecker 
1002cd84c2acSFrederic Weisbecker int load_kernel(void)
1003cd84c2acSFrederic Weisbecker {
1004cd84c2acSFrederic Weisbecker 	int err;
1005cd84c2acSFrederic Weisbecker 
1006cd84c2acSFrederic Weisbecker 	kernel_dso = dso__new("[kernel]", 0);
1007cd84c2acSFrederic Weisbecker 	if (!kernel_dso)
1008cd84c2acSFrederic Weisbecker 		return -1;
1009cd84c2acSFrederic Weisbecker 
101083a0944fSIngo Molnar 	err = dso__load_kernel(kernel_dso, vmlinux_name, NULL, verbose, modules);
1011cd84c2acSFrederic Weisbecker 	if (err <= 0) {
1012cd84c2acSFrederic Weisbecker 		dso__delete(kernel_dso);
1013cd84c2acSFrederic Weisbecker 		kernel_dso = NULL;
1014cd84c2acSFrederic Weisbecker 	} else
1015cd84c2acSFrederic Weisbecker 		dsos__add(kernel_dso);
1016cd84c2acSFrederic Weisbecker 
1017cd84c2acSFrederic Weisbecker 	vdso = dso__new("[vdso]", 0);
1018cd84c2acSFrederic Weisbecker 	if (!vdso)
1019cd84c2acSFrederic Weisbecker 		return -1;
1020cd84c2acSFrederic Weisbecker 
1021cd84c2acSFrederic Weisbecker 	vdso->find_symbol = vdso__find_symbol;
1022cd84c2acSFrederic Weisbecker 
1023cd84c2acSFrederic Weisbecker 	dsos__add(vdso);
1024cd84c2acSFrederic Weisbecker 
1025cd84c2acSFrederic Weisbecker 	hypervisor_dso = dso__new("[hypervisor]", 0);
1026cd84c2acSFrederic Weisbecker 	if (!hypervisor_dso)
1027cd84c2acSFrederic Weisbecker 		return -1;
1028cd84c2acSFrederic Weisbecker 	dsos__add(hypervisor_dso);
1029cd84c2acSFrederic Weisbecker 
1030cd84c2acSFrederic Weisbecker 	return err;
1031cd84c2acSFrederic Weisbecker }
1032cd84c2acSFrederic Weisbecker 
1033cd84c2acSFrederic Weisbecker 
103486470930SIngo Molnar void symbol__init(void)
103586470930SIngo Molnar {
103686470930SIngo Molnar 	elf_version(EV_CURRENT);
103786470930SIngo Molnar }
1038