xref: /linux/tools/perf/util/symbol.c (revision d20ff6bd6bba2e7e6681fa17565347b410c46ab3)
186470930SIngo Molnar #include "util.h"
286470930SIngo Molnar #include "../perf.h"
386470930SIngo Molnar #include "string.h"
486470930SIngo Molnar #include "symbol.h"
586470930SIngo Molnar 
686470930SIngo Molnar #include <libelf.h>
786470930SIngo Molnar #include <gelf.h>
886470930SIngo Molnar #include <elf.h>
928ac909bSArnaldo Carvalho de Melo #include <bfd.h>
1086470930SIngo Molnar 
1186470930SIngo Molnar const char *sym_hist_filter;
1286470930SIngo Molnar 
1328ac909bSArnaldo Carvalho de Melo #ifndef DMGL_PARAMS
1428ac909bSArnaldo Carvalho de Melo #define DMGL_PARAMS      (1 << 0)       /* Include function args */
1528ac909bSArnaldo Carvalho de Melo #define DMGL_ANSI        (1 << 1)       /* Include const, volatile, etc */
1628ac909bSArnaldo Carvalho de Melo #endif
1728ac909bSArnaldo Carvalho de Melo 
189cffa8d5SPaul Mackerras static struct symbol *symbol__new(u64 start, u64 len,
1986470930SIngo Molnar 				  const char *name, unsigned int priv_size,
209cffa8d5SPaul Mackerras 				  u64 obj_start, int verbose)
2186470930SIngo Molnar {
2286470930SIngo Molnar 	size_t namelen = strlen(name) + 1;
2386470930SIngo Molnar 	struct symbol *self = calloc(1, priv_size + sizeof(*self) + namelen);
2486470930SIngo Molnar 
2586470930SIngo Molnar 	if (!self)
2686470930SIngo Molnar 		return NULL;
2786470930SIngo Molnar 
2886470930SIngo Molnar 	if (verbose >= 2)
2986470930SIngo Molnar 		printf("new symbol: %016Lx [%08lx]: %s, hist: %p, obj_start: %p\n",
309cffa8d5SPaul Mackerras 			(u64)start, (unsigned long)len, name, self->hist, (void *)(unsigned long)obj_start);
3186470930SIngo Molnar 
3286470930SIngo Molnar 	self->obj_start= obj_start;
3386470930SIngo Molnar 	self->hist = NULL;
3486470930SIngo Molnar 	self->hist_sum = 0;
3586470930SIngo Molnar 
3686470930SIngo Molnar 	if (sym_hist_filter && !strcmp(name, sym_hist_filter))
379cffa8d5SPaul Mackerras 		self->hist = calloc(sizeof(u64), len);
3886470930SIngo Molnar 
3986470930SIngo Molnar 	if (priv_size) {
4086470930SIngo Molnar 		memset(self, 0, priv_size);
4186470930SIngo Molnar 		self = ((void *)self) + priv_size;
4286470930SIngo Molnar 	}
4386470930SIngo Molnar 	self->start = start;
446cfcc53eSMike Galbraith 	self->end   = len ? start + len - 1 : start;
4586470930SIngo Molnar 	memcpy(self->name, name, namelen);
4686470930SIngo Molnar 
4786470930SIngo Molnar 	return self;
4886470930SIngo Molnar }
4986470930SIngo Molnar 
5086470930SIngo Molnar static void symbol__delete(struct symbol *self, unsigned int priv_size)
5186470930SIngo Molnar {
5286470930SIngo Molnar 	free(((void *)self) - priv_size);
5386470930SIngo Molnar }
5486470930SIngo Molnar 
5586470930SIngo Molnar static size_t symbol__fprintf(struct symbol *self, FILE *fp)
5686470930SIngo Molnar {
576cfcc53eSMike Galbraith 	if (!self->module)
5886470930SIngo Molnar 		return fprintf(fp, " %llx-%llx %s\n",
5986470930SIngo Molnar 		       self->start, self->end, self->name);
606cfcc53eSMike Galbraith 	else
616cfcc53eSMike Galbraith 		return fprintf(fp, " %llx-%llx %s \t[%s]\n",
626cfcc53eSMike Galbraith 		       self->start, self->end, self->name, self->module->name);
6386470930SIngo Molnar }
6486470930SIngo Molnar 
6586470930SIngo Molnar struct dso *dso__new(const char *name, unsigned int sym_priv_size)
6686470930SIngo Molnar {
6786470930SIngo Molnar 	struct dso *self = malloc(sizeof(*self) + strlen(name) + 1);
6886470930SIngo Molnar 
6986470930SIngo Molnar 	if (self != NULL) {
7086470930SIngo Molnar 		strcpy(self->name, name);
7186470930SIngo Molnar 		self->syms = RB_ROOT;
7286470930SIngo Molnar 		self->sym_priv_size = sym_priv_size;
7386470930SIngo Molnar 		self->find_symbol = dso__find_symbol;
7452d422deSArnaldo Carvalho de Melo 		self->slen_calculated = 0;
7586470930SIngo Molnar 	}
7686470930SIngo Molnar 
7786470930SIngo Molnar 	return self;
7886470930SIngo Molnar }
7986470930SIngo Molnar 
8086470930SIngo Molnar static void dso__delete_symbols(struct dso *self)
8186470930SIngo Molnar {
8286470930SIngo Molnar 	struct symbol *pos;
8386470930SIngo Molnar 	struct rb_node *next = rb_first(&self->syms);
8486470930SIngo Molnar 
8586470930SIngo Molnar 	while (next) {
8686470930SIngo Molnar 		pos = rb_entry(next, struct symbol, rb_node);
8786470930SIngo Molnar 		next = rb_next(&pos->rb_node);
8886470930SIngo Molnar 		rb_erase(&pos->rb_node, &self->syms);
8986470930SIngo Molnar 		symbol__delete(pos, self->sym_priv_size);
9086470930SIngo Molnar 	}
9186470930SIngo Molnar }
9286470930SIngo Molnar 
9386470930SIngo Molnar void dso__delete(struct dso *self)
9486470930SIngo Molnar {
9586470930SIngo Molnar 	dso__delete_symbols(self);
9686470930SIngo Molnar 	free(self);
9786470930SIngo Molnar }
9886470930SIngo Molnar 
9986470930SIngo Molnar static void dso__insert_symbol(struct dso *self, struct symbol *sym)
10086470930SIngo Molnar {
10186470930SIngo Molnar 	struct rb_node **p = &self->syms.rb_node;
10286470930SIngo Molnar 	struct rb_node *parent = NULL;
1039cffa8d5SPaul Mackerras 	const u64 ip = sym->start;
10486470930SIngo Molnar 	struct symbol *s;
10586470930SIngo Molnar 
10686470930SIngo Molnar 	while (*p != NULL) {
10786470930SIngo Molnar 		parent = *p;
10886470930SIngo Molnar 		s = rb_entry(parent, struct symbol, rb_node);
10986470930SIngo Molnar 		if (ip < s->start)
11086470930SIngo Molnar 			p = &(*p)->rb_left;
11186470930SIngo Molnar 		else
11286470930SIngo Molnar 			p = &(*p)->rb_right;
11386470930SIngo Molnar 	}
11486470930SIngo Molnar 	rb_link_node(&sym->rb_node, parent, p);
11586470930SIngo Molnar 	rb_insert_color(&sym->rb_node, &self->syms);
11686470930SIngo Molnar }
11786470930SIngo Molnar 
1189cffa8d5SPaul Mackerras struct symbol *dso__find_symbol(struct dso *self, u64 ip)
11986470930SIngo Molnar {
12086470930SIngo Molnar 	struct rb_node *n;
12186470930SIngo Molnar 
12286470930SIngo Molnar 	if (self == NULL)
12386470930SIngo Molnar 		return NULL;
12486470930SIngo Molnar 
12586470930SIngo Molnar 	n = self->syms.rb_node;
12686470930SIngo Molnar 
12786470930SIngo Molnar 	while (n) {
12886470930SIngo Molnar 		struct symbol *s = rb_entry(n, struct symbol, rb_node);
12986470930SIngo Molnar 
13086470930SIngo Molnar 		if (ip < s->start)
13186470930SIngo Molnar 			n = n->rb_left;
13286470930SIngo Molnar 		else if (ip > s->end)
13386470930SIngo Molnar 			n = n->rb_right;
13486470930SIngo Molnar 		else
13586470930SIngo Molnar 			return s;
13686470930SIngo Molnar 	}
13786470930SIngo Molnar 
13886470930SIngo Molnar 	return NULL;
13986470930SIngo Molnar }
14086470930SIngo Molnar 
14186470930SIngo Molnar size_t dso__fprintf(struct dso *self, FILE *fp)
14286470930SIngo Molnar {
14386470930SIngo Molnar 	size_t ret = fprintf(fp, "dso: %s\n", self->name);
14486470930SIngo Molnar 
14586470930SIngo Molnar 	struct rb_node *nd;
14686470930SIngo Molnar 	for (nd = rb_first(&self->syms); nd; nd = rb_next(nd)) {
14786470930SIngo Molnar 		struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
14886470930SIngo Molnar 		ret += symbol__fprintf(pos, fp);
14986470930SIngo Molnar 	}
15086470930SIngo Molnar 
15186470930SIngo Molnar 	return ret;
15286470930SIngo Molnar }
15386470930SIngo Molnar 
15486470930SIngo Molnar static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int verbose)
15586470930SIngo Molnar {
15686470930SIngo Molnar 	struct rb_node *nd, *prevnd;
15786470930SIngo Molnar 	char *line = NULL;
15886470930SIngo Molnar 	size_t n;
15986470930SIngo Molnar 	FILE *file = fopen("/proc/kallsyms", "r");
1609974f496SMike Galbraith 	int count = 0;
16186470930SIngo Molnar 
16286470930SIngo Molnar 	if (file == NULL)
16386470930SIngo Molnar 		goto out_failure;
16486470930SIngo Molnar 
16586470930SIngo Molnar 	while (!feof(file)) {
1669cffa8d5SPaul Mackerras 		u64 start;
16786470930SIngo Molnar 		struct symbol *sym;
16886470930SIngo Molnar 		int line_len, len;
16986470930SIngo Molnar 		char symbol_type;
17086470930SIngo Molnar 
17186470930SIngo Molnar 		line_len = getline(&line, &n, file);
17286470930SIngo Molnar 		if (line_len < 0)
17386470930SIngo Molnar 			break;
17486470930SIngo Molnar 
17586470930SIngo Molnar 		if (!line)
17686470930SIngo Molnar 			goto out_failure;
17786470930SIngo Molnar 
17886470930SIngo Molnar 		line[--line_len] = '\0'; /* \n */
17986470930SIngo Molnar 
18086470930SIngo Molnar 		len = hex2u64(line, &start);
18186470930SIngo Molnar 
18286470930SIngo Molnar 		len++;
18386470930SIngo Molnar 		if (len + 2 >= line_len)
18486470930SIngo Molnar 			continue;
18586470930SIngo Molnar 
18686470930SIngo Molnar 		symbol_type = toupper(line[len]);
18786470930SIngo Molnar 		/*
18886470930SIngo Molnar 		 * We're interested only in code ('T'ext)
18986470930SIngo Molnar 		 */
19086470930SIngo Molnar 		if (symbol_type != 'T' && symbol_type != 'W')
19186470930SIngo Molnar 			continue;
19286470930SIngo Molnar 		/*
19386470930SIngo Molnar 		 * Well fix up the end later, when we have all sorted.
19486470930SIngo Molnar 		 */
19586470930SIngo Molnar 		sym = symbol__new(start, 0xdead, line + len + 2,
19686470930SIngo Molnar 				  self->sym_priv_size, 0, verbose);
19786470930SIngo Molnar 
19886470930SIngo Molnar 		if (sym == NULL)
19986470930SIngo Molnar 			goto out_delete_line;
20086470930SIngo Molnar 
20186470930SIngo Molnar 		if (filter && filter(self, sym))
20286470930SIngo Molnar 			symbol__delete(sym, self->sym_priv_size);
2039974f496SMike Galbraith 		else {
20486470930SIngo Molnar 			dso__insert_symbol(self, sym);
2059974f496SMike Galbraith 			count++;
2069974f496SMike Galbraith 		}
20786470930SIngo Molnar 	}
20886470930SIngo Molnar 
20986470930SIngo Molnar 	/*
21086470930SIngo Molnar 	 * Now that we have all sorted out, just set the ->end of all
21186470930SIngo Molnar 	 * symbols
21286470930SIngo Molnar 	 */
21386470930SIngo Molnar 	prevnd = rb_first(&self->syms);
21486470930SIngo Molnar 
21586470930SIngo Molnar 	if (prevnd == NULL)
21686470930SIngo Molnar 		goto out_delete_line;
21786470930SIngo Molnar 
21886470930SIngo Molnar 	for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
21986470930SIngo Molnar 		struct symbol *prev = rb_entry(prevnd, struct symbol, rb_node),
22086470930SIngo Molnar 			      *curr = rb_entry(nd, struct symbol, rb_node);
22186470930SIngo Molnar 
22286470930SIngo Molnar 		prev->end = curr->start - 1;
22386470930SIngo Molnar 		prevnd = nd;
22486470930SIngo Molnar 	}
22586470930SIngo Molnar 
22686470930SIngo Molnar 	free(line);
22786470930SIngo Molnar 	fclose(file);
22886470930SIngo Molnar 
2299974f496SMike Galbraith 	return count;
23086470930SIngo Molnar 
23186470930SIngo Molnar out_delete_line:
23286470930SIngo Molnar 	free(line);
23386470930SIngo Molnar out_failure:
23486470930SIngo Molnar 	return -1;
23586470930SIngo Molnar }
23686470930SIngo Molnar 
23780d496beSPekka Enberg static int dso__load_perf_map(struct dso *self, symbol_filter_t filter, int verbose)
23880d496beSPekka Enberg {
23980d496beSPekka Enberg 	char *line = NULL;
24080d496beSPekka Enberg 	size_t n;
24180d496beSPekka Enberg 	FILE *file;
24280d496beSPekka Enberg 	int nr_syms = 0;
24380d496beSPekka Enberg 
24480d496beSPekka Enberg 	file = fopen(self->name, "r");
24580d496beSPekka Enberg 	if (file == NULL)
24680d496beSPekka Enberg 		goto out_failure;
24780d496beSPekka Enberg 
24880d496beSPekka Enberg 	while (!feof(file)) {
2499cffa8d5SPaul Mackerras 		u64 start, size;
25080d496beSPekka Enberg 		struct symbol *sym;
25180d496beSPekka Enberg 		int line_len, len;
25280d496beSPekka Enberg 
25380d496beSPekka Enberg 		line_len = getline(&line, &n, file);
25480d496beSPekka Enberg 		if (line_len < 0)
25580d496beSPekka Enberg 			break;
25680d496beSPekka Enberg 
25780d496beSPekka Enberg 		if (!line)
25880d496beSPekka Enberg 			goto out_failure;
25980d496beSPekka Enberg 
26080d496beSPekka Enberg 		line[--line_len] = '\0'; /* \n */
26180d496beSPekka Enberg 
26280d496beSPekka Enberg 		len = hex2u64(line, &start);
26380d496beSPekka Enberg 
26480d496beSPekka Enberg 		len++;
26580d496beSPekka Enberg 		if (len + 2 >= line_len)
26680d496beSPekka Enberg 			continue;
26780d496beSPekka Enberg 
26880d496beSPekka Enberg 		len += hex2u64(line + len, &size);
26980d496beSPekka Enberg 
27080d496beSPekka Enberg 		len++;
27180d496beSPekka Enberg 		if (len + 2 >= line_len)
27280d496beSPekka Enberg 			continue;
27380d496beSPekka Enberg 
27480d496beSPekka Enberg 		sym = symbol__new(start, size, line + len,
27580d496beSPekka Enberg 				  self->sym_priv_size, start, verbose);
27680d496beSPekka Enberg 
27780d496beSPekka Enberg 		if (sym == NULL)
27880d496beSPekka Enberg 			goto out_delete_line;
27980d496beSPekka Enberg 
28080d496beSPekka Enberg 		if (filter && filter(self, sym))
28180d496beSPekka Enberg 			symbol__delete(sym, self->sym_priv_size);
28280d496beSPekka Enberg 		else {
28380d496beSPekka Enberg 			dso__insert_symbol(self, sym);
28480d496beSPekka Enberg 			nr_syms++;
28580d496beSPekka Enberg 		}
28680d496beSPekka Enberg 	}
28780d496beSPekka Enberg 
28880d496beSPekka Enberg 	free(line);
28980d496beSPekka Enberg 	fclose(file);
29080d496beSPekka Enberg 
29180d496beSPekka Enberg 	return nr_syms;
29280d496beSPekka Enberg 
29380d496beSPekka Enberg out_delete_line:
29480d496beSPekka Enberg 	free(line);
29580d496beSPekka Enberg out_failure:
29680d496beSPekka Enberg 	return -1;
29780d496beSPekka Enberg }
29880d496beSPekka Enberg 
29986470930SIngo Molnar /**
30086470930SIngo Molnar  * elf_symtab__for_each_symbol - iterate thru all the symbols
30186470930SIngo Molnar  *
30286470930SIngo Molnar  * @self: struct elf_symtab instance to iterate
30386470930SIngo Molnar  * @index: uint32_t index
30486470930SIngo Molnar  * @sym: GElf_Sym iterator
30586470930SIngo Molnar  */
30686470930SIngo Molnar #define elf_symtab__for_each_symbol(syms, nr_syms, index, sym) \
30786470930SIngo Molnar 	for (index = 0, gelf_getsym(syms, index, &sym);\
30886470930SIngo Molnar 	     index < nr_syms; \
30986470930SIngo Molnar 	     index++, gelf_getsym(syms, index, &sym))
31086470930SIngo Molnar 
31186470930SIngo Molnar static inline uint8_t elf_sym__type(const GElf_Sym *sym)
31286470930SIngo Molnar {
31386470930SIngo Molnar 	return GELF_ST_TYPE(sym->st_info);
31486470930SIngo Molnar }
31586470930SIngo Molnar 
31686470930SIngo Molnar static inline int elf_sym__is_function(const GElf_Sym *sym)
31786470930SIngo Molnar {
31886470930SIngo Molnar 	return elf_sym__type(sym) == STT_FUNC &&
31986470930SIngo Molnar 	       sym->st_name != 0 &&
32086470930SIngo Molnar 	       sym->st_shndx != SHN_UNDEF &&
32186470930SIngo Molnar 	       sym->st_size != 0;
32286470930SIngo Molnar }
32386470930SIngo Molnar 
3246cfcc53eSMike Galbraith static inline int elf_sym__is_label(const GElf_Sym *sym)
3256cfcc53eSMike Galbraith {
3266cfcc53eSMike Galbraith 	return elf_sym__type(sym) == STT_NOTYPE &&
3276cfcc53eSMike Galbraith 		sym->st_name != 0 &&
3286cfcc53eSMike Galbraith 		sym->st_shndx != SHN_UNDEF &&
3296cfcc53eSMike Galbraith 		sym->st_shndx != SHN_ABS;
3306cfcc53eSMike Galbraith }
3316cfcc53eSMike Galbraith 
3326cfcc53eSMike Galbraith static inline const char *elf_sec__name(const GElf_Shdr *shdr,
3336cfcc53eSMike Galbraith 					const Elf_Data *secstrs)
3346cfcc53eSMike Galbraith {
3356cfcc53eSMike Galbraith 	return secstrs->d_buf + shdr->sh_name;
3366cfcc53eSMike Galbraith }
3376cfcc53eSMike Galbraith 
3386cfcc53eSMike Galbraith static inline int elf_sec__is_text(const GElf_Shdr *shdr,
3396cfcc53eSMike Galbraith 					const Elf_Data *secstrs)
3406cfcc53eSMike Galbraith {
3416cfcc53eSMike Galbraith 	return strstr(elf_sec__name(shdr, secstrs), "text") != NULL;
3426cfcc53eSMike Galbraith }
3436cfcc53eSMike Galbraith 
34486470930SIngo Molnar static inline const char *elf_sym__name(const GElf_Sym *sym,
34586470930SIngo Molnar 					const Elf_Data *symstrs)
34686470930SIngo Molnar {
34786470930SIngo Molnar 	return symstrs->d_buf + sym->st_name;
34886470930SIngo Molnar }
34986470930SIngo Molnar 
35086470930SIngo Molnar static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
35186470930SIngo Molnar 				    GElf_Shdr *shp, const char *name,
35286470930SIngo Molnar 				    size_t *index)
35386470930SIngo Molnar {
35486470930SIngo Molnar 	Elf_Scn *sec = NULL;
35586470930SIngo Molnar 	size_t cnt = 1;
35686470930SIngo Molnar 
35786470930SIngo Molnar 	while ((sec = elf_nextscn(elf, sec)) != NULL) {
35886470930SIngo Molnar 		char *str;
35986470930SIngo Molnar 
36086470930SIngo Molnar 		gelf_getshdr(sec, shp);
36186470930SIngo Molnar 		str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name);
36286470930SIngo Molnar 		if (!strcmp(name, str)) {
36386470930SIngo Molnar 			if (index)
36486470930SIngo Molnar 				*index = cnt;
36586470930SIngo Molnar 			break;
36686470930SIngo Molnar 		}
36786470930SIngo Molnar 		++cnt;
36886470930SIngo Molnar 	}
36986470930SIngo Molnar 
37086470930SIngo Molnar 	return sec;
37186470930SIngo Molnar }
37286470930SIngo Molnar 
37386470930SIngo Molnar #define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \
37486470930SIngo Molnar 	for (idx = 0, pos = gelf_getrel(reldata, 0, &pos_mem); \
37586470930SIngo Molnar 	     idx < nr_entries; \
37686470930SIngo Molnar 	     ++idx, pos = gelf_getrel(reldata, idx, &pos_mem))
37786470930SIngo Molnar 
37886470930SIngo Molnar #define elf_section__for_each_rela(reldata, pos, pos_mem, idx, nr_entries) \
37986470930SIngo Molnar 	for (idx = 0, pos = gelf_getrela(reldata, 0, &pos_mem); \
38086470930SIngo Molnar 	     idx < nr_entries; \
38186470930SIngo Molnar 	     ++idx, pos = gelf_getrela(reldata, idx, &pos_mem))
38286470930SIngo Molnar 
383a25e46c4SArnaldo Carvalho de Melo /*
384a25e46c4SArnaldo Carvalho de Melo  * We need to check if we have a .dynsym, so that we can handle the
385a25e46c4SArnaldo Carvalho de Melo  * .plt, synthesizing its symbols, that aren't on the symtabs (be it
386a25e46c4SArnaldo Carvalho de Melo  * .dynsym or .symtab).
387a25e46c4SArnaldo Carvalho de Melo  * And always look at the original dso, not at debuginfo packages, that
388a25e46c4SArnaldo Carvalho de Melo  * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS).
389a25e46c4SArnaldo Carvalho de Melo  */
390a25e46c4SArnaldo Carvalho de Melo static int dso__synthesize_plt_symbols(struct  dso *self, int verbose)
39186470930SIngo Molnar {
39286470930SIngo Molnar 	uint32_t nr_rel_entries, idx;
39386470930SIngo Molnar 	GElf_Sym sym;
3949cffa8d5SPaul Mackerras 	u64 plt_offset;
39586470930SIngo Molnar 	GElf_Shdr shdr_plt;
39686470930SIngo Molnar 	struct symbol *f;
397a25e46c4SArnaldo Carvalho de Melo 	GElf_Shdr shdr_rel_plt, shdr_dynsym;
39886470930SIngo Molnar 	Elf_Data *reldata, *syms, *symstrs;
399a25e46c4SArnaldo Carvalho de Melo 	Elf_Scn *scn_plt_rel, *scn_symstrs, *scn_dynsym;
400a25e46c4SArnaldo Carvalho de Melo 	size_t dynsym_idx;
401a25e46c4SArnaldo Carvalho de Melo 	GElf_Ehdr ehdr;
40286470930SIngo Molnar 	char sympltname[1024];
403a25e46c4SArnaldo Carvalho de Melo 	Elf *elf;
404a25e46c4SArnaldo Carvalho de Melo 	int nr = 0, symidx, fd, err = 0;
40586470930SIngo Molnar 
406a25e46c4SArnaldo Carvalho de Melo 	fd = open(self->name, O_RDONLY);
407a25e46c4SArnaldo Carvalho de Melo 	if (fd < 0)
408a25e46c4SArnaldo Carvalho de Melo 		goto out;
409a25e46c4SArnaldo Carvalho de Melo 
410a25e46c4SArnaldo Carvalho de Melo 	elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
411a25e46c4SArnaldo Carvalho de Melo 	if (elf == NULL)
412a25e46c4SArnaldo Carvalho de Melo 		goto out_close;
413a25e46c4SArnaldo Carvalho de Melo 
414a25e46c4SArnaldo Carvalho de Melo 	if (gelf_getehdr(elf, &ehdr) == NULL)
415a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
416a25e46c4SArnaldo Carvalho de Melo 
417a25e46c4SArnaldo Carvalho de Melo 	scn_dynsym = elf_section_by_name(elf, &ehdr, &shdr_dynsym,
418a25e46c4SArnaldo Carvalho de Melo 					 ".dynsym", &dynsym_idx);
419a25e46c4SArnaldo Carvalho de Melo 	if (scn_dynsym == NULL)
420a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
421a25e46c4SArnaldo Carvalho de Melo 
422a25e46c4SArnaldo Carvalho de Melo 	scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
42386470930SIngo Molnar 					  ".rela.plt", NULL);
42486470930SIngo Molnar 	if (scn_plt_rel == NULL) {
425a25e46c4SArnaldo Carvalho de Melo 		scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
42686470930SIngo Molnar 						  ".rel.plt", NULL);
42786470930SIngo Molnar 		if (scn_plt_rel == NULL)
428a25e46c4SArnaldo Carvalho de Melo 			goto out_elf_end;
42986470930SIngo Molnar 	}
43086470930SIngo Molnar 
431a25e46c4SArnaldo Carvalho de Melo 	err = -1;
43286470930SIngo Molnar 
433a25e46c4SArnaldo Carvalho de Melo 	if (shdr_rel_plt.sh_link != dynsym_idx)
434a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
435a25e46c4SArnaldo Carvalho de Melo 
436a25e46c4SArnaldo Carvalho de Melo 	if (elf_section_by_name(elf, &ehdr, &shdr_plt, ".plt", NULL) == NULL)
437a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
43886470930SIngo Molnar 
43986470930SIngo Molnar 	/*
44086470930SIngo Molnar 	 * Fetch the relocation section to find the indexes to the GOT
44186470930SIngo Molnar 	 * and the symbols in the .dynsym they refer to.
44286470930SIngo Molnar 	 */
44386470930SIngo Molnar 	reldata = elf_getdata(scn_plt_rel, NULL);
44486470930SIngo Molnar 	if (reldata == NULL)
445a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
44686470930SIngo Molnar 
44786470930SIngo Molnar 	syms = elf_getdata(scn_dynsym, NULL);
44886470930SIngo Molnar 	if (syms == NULL)
449a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
45086470930SIngo Molnar 
451a25e46c4SArnaldo Carvalho de Melo 	scn_symstrs = elf_getscn(elf, shdr_dynsym.sh_link);
45286470930SIngo Molnar 	if (scn_symstrs == NULL)
453a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
45486470930SIngo Molnar 
45586470930SIngo Molnar 	symstrs = elf_getdata(scn_symstrs, NULL);
45686470930SIngo Molnar 	if (symstrs == NULL)
457a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
45886470930SIngo Molnar 
45986470930SIngo Molnar 	nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize;
46086470930SIngo Molnar 	plt_offset = shdr_plt.sh_offset;
46186470930SIngo Molnar 
46286470930SIngo Molnar 	if (shdr_rel_plt.sh_type == SHT_RELA) {
46386470930SIngo Molnar 		GElf_Rela pos_mem, *pos;
46486470930SIngo Molnar 
46586470930SIngo Molnar 		elf_section__for_each_rela(reldata, pos, pos_mem, idx,
46686470930SIngo Molnar 					   nr_rel_entries) {
46786470930SIngo Molnar 			symidx = GELF_R_SYM(pos->r_info);
46886470930SIngo Molnar 			plt_offset += shdr_plt.sh_entsize;
46986470930SIngo Molnar 			gelf_getsym(syms, symidx, &sym);
47086470930SIngo Molnar 			snprintf(sympltname, sizeof(sympltname),
47186470930SIngo Molnar 				 "%s@plt", elf_sym__name(&sym, symstrs));
47286470930SIngo Molnar 
47386470930SIngo Molnar 			f = symbol__new(plt_offset, shdr_plt.sh_entsize,
47486470930SIngo Molnar 					sympltname, self->sym_priv_size, 0, verbose);
47586470930SIngo Molnar 			if (!f)
476a25e46c4SArnaldo Carvalho de Melo 				goto out_elf_end;
47786470930SIngo Molnar 
47886470930SIngo Molnar 			dso__insert_symbol(self, f);
47986470930SIngo Molnar 			++nr;
48086470930SIngo Molnar 		}
48186470930SIngo Molnar 	} else if (shdr_rel_plt.sh_type == SHT_REL) {
48286470930SIngo Molnar 		GElf_Rel pos_mem, *pos;
48386470930SIngo Molnar 		elf_section__for_each_rel(reldata, pos, pos_mem, idx,
48486470930SIngo Molnar 					  nr_rel_entries) {
48586470930SIngo Molnar 			symidx = GELF_R_SYM(pos->r_info);
48686470930SIngo Molnar 			plt_offset += shdr_plt.sh_entsize;
48786470930SIngo Molnar 			gelf_getsym(syms, symidx, &sym);
48886470930SIngo Molnar 			snprintf(sympltname, sizeof(sympltname),
48986470930SIngo Molnar 				 "%s@plt", elf_sym__name(&sym, symstrs));
49086470930SIngo Molnar 
49186470930SIngo Molnar 			f = symbol__new(plt_offset, shdr_plt.sh_entsize,
49286470930SIngo Molnar 					sympltname, self->sym_priv_size, 0, verbose);
49386470930SIngo Molnar 			if (!f)
494a25e46c4SArnaldo Carvalho de Melo 				goto out_elf_end;
49586470930SIngo Molnar 
49686470930SIngo Molnar 			dso__insert_symbol(self, f);
49786470930SIngo Molnar 			++nr;
49886470930SIngo Molnar 		}
49986470930SIngo Molnar 	}
50086470930SIngo Molnar 
501a25e46c4SArnaldo Carvalho de Melo 	err = 0;
502a25e46c4SArnaldo Carvalho de Melo out_elf_end:
503a25e46c4SArnaldo Carvalho de Melo 	elf_end(elf);
504a25e46c4SArnaldo Carvalho de Melo out_close:
505a25e46c4SArnaldo Carvalho de Melo 	close(fd);
506a25e46c4SArnaldo Carvalho de Melo 
507a25e46c4SArnaldo Carvalho de Melo 	if (err == 0)
50886470930SIngo Molnar 		return nr;
509a25e46c4SArnaldo Carvalho de Melo out:
510a25e46c4SArnaldo Carvalho de Melo 	fprintf(stderr, "%s: problems reading %s PLT info.\n",
511a25e46c4SArnaldo Carvalho de Melo 		__func__, self->name);
512a25e46c4SArnaldo Carvalho de Melo 	return 0;
51386470930SIngo Molnar }
51486470930SIngo Molnar 
51586470930SIngo Molnar static int dso__load_sym(struct dso *self, int fd, const char *name,
5166cfcc53eSMike Galbraith 			 symbol_filter_t filter, int verbose, struct module *mod)
51786470930SIngo Molnar {
5186cfcc53eSMike Galbraith 	Elf_Data *symstrs, *secstrs;
51986470930SIngo Molnar 	uint32_t nr_syms;
52086470930SIngo Molnar 	int err = -1;
52186470930SIngo Molnar 	uint32_t index;
52286470930SIngo Molnar 	GElf_Ehdr ehdr;
52386470930SIngo Molnar 	GElf_Shdr shdr;
52486470930SIngo Molnar 	Elf_Data *syms;
52586470930SIngo Molnar 	GElf_Sym sym;
526a25e46c4SArnaldo Carvalho de Melo 	Elf_Scn *sec, *sec_strndx;
52786470930SIngo Molnar 	Elf *elf;
528*d20ff6bdSMike Galbraith 	int nr = 0, kernel = !strcmp("[kernel]", self->name);
52986470930SIngo Molnar 
53086470930SIngo Molnar 	elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
53186470930SIngo Molnar 	if (elf == NULL) {
53286470930SIngo Molnar 		if (verbose)
53386470930SIngo Molnar 			fprintf(stderr, "%s: cannot read %s ELF file.\n",
53486470930SIngo Molnar 				__func__, name);
53586470930SIngo Molnar 		goto out_close;
53686470930SIngo Molnar 	}
53786470930SIngo Molnar 
53886470930SIngo Molnar 	if (gelf_getehdr(elf, &ehdr) == NULL) {
53986470930SIngo Molnar 		if (verbose)
54086470930SIngo Molnar 			fprintf(stderr, "%s: cannot get elf header.\n", __func__);
54186470930SIngo Molnar 		goto out_elf_end;
54286470930SIngo Molnar 	}
54386470930SIngo Molnar 
54486470930SIngo Molnar 	sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL);
54586470930SIngo Molnar 	if (sec == NULL) {
546a25e46c4SArnaldo Carvalho de Melo 		sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL);
547a25e46c4SArnaldo Carvalho de Melo 		if (sec == NULL)
54886470930SIngo Molnar 			goto out_elf_end;
54986470930SIngo Molnar 	}
55086470930SIngo Molnar 
55186470930SIngo Molnar 	syms = elf_getdata(sec, NULL);
55286470930SIngo Molnar 	if (syms == NULL)
55386470930SIngo Molnar 		goto out_elf_end;
55486470930SIngo Molnar 
55586470930SIngo Molnar 	sec = elf_getscn(elf, shdr.sh_link);
55686470930SIngo Molnar 	if (sec == NULL)
55786470930SIngo Molnar 		goto out_elf_end;
55886470930SIngo Molnar 
55986470930SIngo Molnar 	symstrs = elf_getdata(sec, NULL);
56086470930SIngo Molnar 	if (symstrs == NULL)
56186470930SIngo Molnar 		goto out_elf_end;
56286470930SIngo Molnar 
5636cfcc53eSMike Galbraith 	sec_strndx = elf_getscn(elf, ehdr.e_shstrndx);
5646cfcc53eSMike Galbraith 	if (sec_strndx == NULL)
5656cfcc53eSMike Galbraith 		goto out_elf_end;
5666cfcc53eSMike Galbraith 
5676cfcc53eSMike Galbraith 	secstrs = elf_getdata(sec_strndx, NULL);
5686cfcc53eSMike Galbraith 	if (symstrs == NULL)
5696cfcc53eSMike Galbraith 		goto out_elf_end;
5706cfcc53eSMike Galbraith 
57186470930SIngo Molnar 	nr_syms = shdr.sh_size / shdr.sh_entsize;
57286470930SIngo Molnar 
573e9fbc9dcSArjan van de Ven 	memset(&sym, 0, sizeof(sym));
574*d20ff6bdSMike Galbraith 	if (!kernel) {
57530d7a77dSArnaldo Carvalho de Melo 		self->adjust_symbols = (ehdr.e_type == ET_EXEC ||
57630d7a77dSArnaldo Carvalho de Melo 				elf_section_by_name(elf, &ehdr, &shdr,
577f5812a7aSArnaldo Carvalho de Melo 						     ".gnu.prelink_undo",
57830d7a77dSArnaldo Carvalho de Melo 						     NULL) != NULL);
579*d20ff6bdSMike Galbraith 	} else self->adjust_symbols = 0;
580*d20ff6bdSMike Galbraith 
58186470930SIngo Molnar 	elf_symtab__for_each_symbol(syms, nr_syms, index, sym) {
58286470930SIngo Molnar 		struct symbol *f;
58328ac909bSArnaldo Carvalho de Melo 		const char *name;
58428ac909bSArnaldo Carvalho de Melo 		char *demangled;
5859cffa8d5SPaul Mackerras 		u64 obj_start;
5866cfcc53eSMike Galbraith 		struct section *section = NULL;
5876cfcc53eSMike Galbraith 		int is_label = elf_sym__is_label(&sym);
5886cfcc53eSMike Galbraith 		const char *section_name;
58986470930SIngo Molnar 
5906cfcc53eSMike Galbraith 		if (!is_label && !elf_sym__is_function(&sym))
59186470930SIngo Molnar 			continue;
59286470930SIngo Molnar 
59386470930SIngo Molnar 		sec = elf_getscn(elf, sym.st_shndx);
59486470930SIngo Molnar 		if (!sec)
59586470930SIngo Molnar 			goto out_elf_end;
59686470930SIngo Molnar 
59786470930SIngo Molnar 		gelf_getshdr(sec, &shdr);
5986cfcc53eSMike Galbraith 
5996cfcc53eSMike Galbraith 		if (is_label && !elf_sec__is_text(&shdr, secstrs))
6006cfcc53eSMike Galbraith 			continue;
6016cfcc53eSMike Galbraith 
6026cfcc53eSMike Galbraith 		section_name = elf_sec__name(&shdr, secstrs);
60386470930SIngo Molnar 		obj_start = sym.st_value;
60486470930SIngo Molnar 
60530d7a77dSArnaldo Carvalho de Melo 		if (self->adjust_symbols) {
606520f2c34SPeter Zijlstra 			if (verbose >= 2)
607520f2c34SPeter Zijlstra 				printf("adjusting symbol: st_value: %Lx sh_addr: %Lx sh_offset: %Lx\n",
608520f2c34SPeter Zijlstra 					(u64)sym.st_value, (u64)shdr.sh_addr, (u64)shdr.sh_offset);
609520f2c34SPeter Zijlstra 
61086470930SIngo Molnar 			sym.st_value -= shdr.sh_addr - shdr.sh_offset;
611f5812a7aSArnaldo Carvalho de Melo 		}
61286470930SIngo Molnar 
6136cfcc53eSMike Galbraith 		if (mod) {
6146cfcc53eSMike Galbraith 			section = mod->sections->find_section(mod->sections, section_name);
6156cfcc53eSMike Galbraith 			if (section)
6166cfcc53eSMike Galbraith 				sym.st_value += section->vma;
6176cfcc53eSMike Galbraith 			else {
6186cfcc53eSMike Galbraith 				fprintf(stderr, "dso__load_sym() module %s lookup of %s failed\n",
6196cfcc53eSMike Galbraith 					mod->name, section_name);
6206cfcc53eSMike Galbraith 				goto out_elf_end;
6216cfcc53eSMike Galbraith 			}
6226cfcc53eSMike Galbraith 		}
62328ac909bSArnaldo Carvalho de Melo 		/*
62428ac909bSArnaldo Carvalho de Melo 		 * We need to figure out if the object was created from C++ sources
62528ac909bSArnaldo Carvalho de Melo 		 * DWARF DW_compile_unit has this, but we don't always have access
62628ac909bSArnaldo Carvalho de Melo 		 * to it...
62728ac909bSArnaldo Carvalho de Melo 		 */
62828ac909bSArnaldo Carvalho de Melo 		name = elf_sym__name(&sym, symstrs);
62928ac909bSArnaldo Carvalho de Melo 		demangled = bfd_demangle(NULL, name, DMGL_PARAMS | DMGL_ANSI);
63028ac909bSArnaldo Carvalho de Melo 		if (demangled != NULL)
63128ac909bSArnaldo Carvalho de Melo 			name = demangled;
6326cfcc53eSMike Galbraith 
63328ac909bSArnaldo Carvalho de Melo 		f = symbol__new(sym.st_value, sym.st_size, name,
63486470930SIngo Molnar 				self->sym_priv_size, obj_start, verbose);
63528ac909bSArnaldo Carvalho de Melo 		free(demangled);
63686470930SIngo Molnar 		if (!f)
63786470930SIngo Molnar 			goto out_elf_end;
63886470930SIngo Molnar 
63986470930SIngo Molnar 		if (filter && filter(self, f))
64086470930SIngo Molnar 			symbol__delete(f, self->sym_priv_size);
64186470930SIngo Molnar 		else {
6426cfcc53eSMike Galbraith 			f->module = mod;
64386470930SIngo Molnar 			dso__insert_symbol(self, f);
64486470930SIngo Molnar 			nr++;
64586470930SIngo Molnar 		}
64686470930SIngo Molnar 	}
64786470930SIngo Molnar 
64886470930SIngo Molnar 	err = nr;
64986470930SIngo Molnar out_elf_end:
65086470930SIngo Molnar 	elf_end(elf);
65186470930SIngo Molnar out_close:
65286470930SIngo Molnar 	return err;
65386470930SIngo Molnar }
65486470930SIngo Molnar 
65586470930SIngo Molnar int dso__load(struct dso *self, symbol_filter_t filter, int verbose)
65686470930SIngo Molnar {
65786470930SIngo Molnar 	int size = strlen(self->name) + sizeof("/usr/lib/debug%s.debug");
65886470930SIngo Molnar 	char *name = malloc(size);
65986470930SIngo Molnar 	int variant = 0;
66086470930SIngo Molnar 	int ret = -1;
66186470930SIngo Molnar 	int fd;
66286470930SIngo Molnar 
66386470930SIngo Molnar 	if (!name)
66486470930SIngo Molnar 		return -1;
66586470930SIngo Molnar 
66630d7a77dSArnaldo Carvalho de Melo 	self->adjust_symbols = 0;
667f5812a7aSArnaldo Carvalho de Melo 
66880d496beSPekka Enberg 	if (strncmp(self->name, "/tmp/perf-", 10) == 0)
66980d496beSPekka Enberg 		return dso__load_perf_map(self, filter, verbose);
67080d496beSPekka Enberg 
67186470930SIngo Molnar more:
67286470930SIngo Molnar 	do {
67386470930SIngo Molnar 		switch (variant) {
67486470930SIngo Molnar 		case 0: /* Fedora */
67586470930SIngo Molnar 			snprintf(name, size, "/usr/lib/debug%s.debug", self->name);
67686470930SIngo Molnar 			break;
67786470930SIngo Molnar 		case 1: /* Ubuntu */
67886470930SIngo Molnar 			snprintf(name, size, "/usr/lib/debug%s", self->name);
67986470930SIngo Molnar 			break;
68086470930SIngo Molnar 		case 2: /* Sane people */
68186470930SIngo Molnar 			snprintf(name, size, "%s", self->name);
68286470930SIngo Molnar 			break;
68386470930SIngo Molnar 
68486470930SIngo Molnar 		default:
68586470930SIngo Molnar 			goto out;
68686470930SIngo Molnar 		}
68786470930SIngo Molnar 		variant++;
68886470930SIngo Molnar 
68986470930SIngo Molnar 		fd = open(name, O_RDONLY);
69086470930SIngo Molnar 	} while (fd < 0);
69186470930SIngo Molnar 
6926cfcc53eSMike Galbraith 	ret = dso__load_sym(self, fd, name, filter, verbose, NULL);
69386470930SIngo Molnar 	close(fd);
69486470930SIngo Molnar 
69586470930SIngo Molnar 	/*
69686470930SIngo Molnar 	 * Some people seem to have debuginfo files _WITHOUT_ debug info!?!?
69786470930SIngo Molnar 	 */
69886470930SIngo Molnar 	if (!ret)
69986470930SIngo Molnar 		goto more;
70086470930SIngo Molnar 
701a25e46c4SArnaldo Carvalho de Melo 	if (ret > 0) {
702a25e46c4SArnaldo Carvalho de Melo 		int nr_plt = dso__synthesize_plt_symbols(self, verbose);
703a25e46c4SArnaldo Carvalho de Melo 		if (nr_plt > 0)
704a25e46c4SArnaldo Carvalho de Melo 			ret += nr_plt;
705a25e46c4SArnaldo Carvalho de Melo 	}
70686470930SIngo Molnar out:
70786470930SIngo Molnar 	free(name);
70886470930SIngo Molnar 	return ret;
70986470930SIngo Molnar }
71086470930SIngo Molnar 
7116cfcc53eSMike Galbraith static int dso__load_module(struct dso *self, struct mod_dso *mods, const char *name,
7126cfcc53eSMike Galbraith 			     symbol_filter_t filter, int verbose)
7136cfcc53eSMike Galbraith {
7146cfcc53eSMike Galbraith 	struct module *mod = mod_dso__find_module(mods, name);
7156cfcc53eSMike Galbraith 	int err = 0, fd;
7166cfcc53eSMike Galbraith 
7176cfcc53eSMike Galbraith 	if (mod == NULL || !mod->active)
7186cfcc53eSMike Galbraith 		return err;
7196cfcc53eSMike Galbraith 
7206cfcc53eSMike Galbraith 	fd = open(mod->path, O_RDONLY);
7216cfcc53eSMike Galbraith 
7226cfcc53eSMike Galbraith 	if (fd < 0)
7236cfcc53eSMike Galbraith 		return err;
7246cfcc53eSMike Galbraith 
7256cfcc53eSMike Galbraith 	err = dso__load_sym(self, fd, name, filter, verbose, mod);
7266cfcc53eSMike Galbraith 	close(fd);
7276cfcc53eSMike Galbraith 
7286cfcc53eSMike Galbraith 	return err;
7296cfcc53eSMike Galbraith }
7306cfcc53eSMike Galbraith 
7316cfcc53eSMike Galbraith int dso__load_modules(struct dso *self, symbol_filter_t filter, int verbose)
7326cfcc53eSMike Galbraith {
7336cfcc53eSMike Galbraith 	struct mod_dso *mods = mod_dso__new_dso("modules");
7346cfcc53eSMike Galbraith 	struct module *pos;
7356cfcc53eSMike Galbraith 	struct rb_node *next;
7366cfcc53eSMike Galbraith 	int err;
7376cfcc53eSMike Galbraith 
7386cfcc53eSMike Galbraith 	err = mod_dso__load_modules(mods);
7396cfcc53eSMike Galbraith 
7406cfcc53eSMike Galbraith 	if (err <= 0)
7416cfcc53eSMike Galbraith 		return err;
7426cfcc53eSMike Galbraith 
7436cfcc53eSMike Galbraith 	/*
7446cfcc53eSMike Galbraith 	 * Iterate over modules, and load active symbols.
7456cfcc53eSMike Galbraith 	 */
7466cfcc53eSMike Galbraith 	next = rb_first(&mods->mods);
7476cfcc53eSMike Galbraith 	while (next) {
7486cfcc53eSMike Galbraith 		pos = rb_entry(next, struct module, rb_node);
7496cfcc53eSMike Galbraith 		err = dso__load_module(self, mods, pos->name, filter, verbose);
7506cfcc53eSMike Galbraith 
7516cfcc53eSMike Galbraith 		if (err < 0)
7526cfcc53eSMike Galbraith 			break;
7536cfcc53eSMike Galbraith 
7546cfcc53eSMike Galbraith 		next = rb_next(&pos->rb_node);
7556cfcc53eSMike Galbraith 	}
7566cfcc53eSMike Galbraith 
7576cfcc53eSMike Galbraith 	if (err < 0) {
7586cfcc53eSMike Galbraith 		mod_dso__delete_modules(mods);
7596cfcc53eSMike Galbraith 		mod_dso__delete_self(mods);
7606cfcc53eSMike Galbraith 	}
7616cfcc53eSMike Galbraith 
7626cfcc53eSMike Galbraith 	return err;
7636cfcc53eSMike Galbraith }
7646cfcc53eSMike Galbraith 
7656cfcc53eSMike Galbraith static inline void dso__fill_symbol_holes(struct dso *self)
7666cfcc53eSMike Galbraith {
7676cfcc53eSMike Galbraith 	struct symbol *prev = NULL;
7686cfcc53eSMike Galbraith 	struct rb_node *nd;
7696cfcc53eSMike Galbraith 
7706cfcc53eSMike Galbraith 	for (nd = rb_last(&self->syms); nd; nd = rb_prev(nd)) {
7716cfcc53eSMike Galbraith 		struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
7726cfcc53eSMike Galbraith 
7736cfcc53eSMike Galbraith 		if (prev) {
7746cfcc53eSMike Galbraith 			u64 hole = 0;
7756cfcc53eSMike Galbraith 			int alias = pos->start == prev->start;
7766cfcc53eSMike Galbraith 
7776cfcc53eSMike Galbraith 			if (!alias)
7786cfcc53eSMike Galbraith 				hole = prev->start - pos->end - 1;
7796cfcc53eSMike Galbraith 
7806cfcc53eSMike Galbraith 			if (hole || alias) {
7816cfcc53eSMike Galbraith 				if (alias)
7826cfcc53eSMike Galbraith 					pos->end = prev->end;
7836cfcc53eSMike Galbraith 				else if (hole)
7846cfcc53eSMike Galbraith 					pos->end = prev->start - 1;
7856cfcc53eSMike Galbraith 			}
7866cfcc53eSMike Galbraith 		}
7876cfcc53eSMike Galbraith 		prev = pos;
7886cfcc53eSMike Galbraith 	}
7896cfcc53eSMike Galbraith }
7906cfcc53eSMike Galbraith 
79186470930SIngo Molnar static int dso__load_vmlinux(struct dso *self, const char *vmlinux,
79286470930SIngo Molnar 			     symbol_filter_t filter, int verbose)
79386470930SIngo Molnar {
79486470930SIngo Molnar 	int err, fd = open(vmlinux, O_RDONLY);
79586470930SIngo Molnar 
79686470930SIngo Molnar 	if (fd < 0)
79786470930SIngo Molnar 		return -1;
79886470930SIngo Molnar 
7996cfcc53eSMike Galbraith 	err = dso__load_sym(self, fd, vmlinux, filter, verbose, NULL);
8006cfcc53eSMike Galbraith 
8016cfcc53eSMike Galbraith 	if (err > 0)
8026cfcc53eSMike Galbraith 		dso__fill_symbol_holes(self);
8036cfcc53eSMike Galbraith 
80486470930SIngo Molnar 	close(fd);
80586470930SIngo Molnar 
80686470930SIngo Molnar 	return err;
80786470930SIngo Molnar }
80886470930SIngo Molnar 
80986470930SIngo Molnar int dso__load_kernel(struct dso *self, const char *vmlinux,
8106cfcc53eSMike Galbraith 		     symbol_filter_t filter, int verbose, int modules)
81186470930SIngo Molnar {
81286470930SIngo Molnar 	int err = -1;
81386470930SIngo Molnar 
8146cfcc53eSMike Galbraith 	if (vmlinux) {
81586470930SIngo Molnar 		err = dso__load_vmlinux(self, vmlinux, filter, verbose);
8166cfcc53eSMike Galbraith 		if (err > 0 && modules)
8176cfcc53eSMike Galbraith 			err = dso__load_modules(self, filter, verbose);
8186cfcc53eSMike Galbraith 	}
81986470930SIngo Molnar 
8209974f496SMike Galbraith 	if (err <= 0)
82186470930SIngo Molnar 		err = dso__load_kallsyms(self, filter, verbose);
82286470930SIngo Molnar 
82386470930SIngo Molnar 	return err;
82486470930SIngo Molnar }
82586470930SIngo Molnar 
82686470930SIngo Molnar void symbol__init(void)
82786470930SIngo Molnar {
82886470930SIngo Molnar 	elf_version(EV_CURRENT);
82986470930SIngo Molnar }
830