xref: /linux/tools/perf/util/symbol.c (revision 628ada0cb03666dd463f7c25947eaccdf440c309)
186470930SIngo Molnar #include "util.h"
286470930SIngo Molnar #include "../perf.h"
3655000e7SArnaldo Carvalho de Melo #include "sort.h"
486470930SIngo Molnar #include "string.h"
586470930SIngo Molnar #include "symbol.h"
6439d473bSArnaldo Carvalho de Melo #include "thread.h"
786470930SIngo Molnar 
88f28827aSFrederic Weisbecker #include "debug.h"
98f28827aSFrederic Weisbecker 
10b32d133aSArnaldo Carvalho de Melo #include <asm/bug.h>
1186470930SIngo Molnar #include <libelf.h>
1286470930SIngo Molnar #include <gelf.h>
1386470930SIngo Molnar #include <elf.h>
14f1617b40SArnaldo Carvalho de Melo #include <limits.h>
15439d473bSArnaldo Carvalho de Melo #include <sys/utsname.h>
162cdbc46dSPeter Zijlstra 
17c12e15e7SArnaldo Carvalho de Melo #ifndef NT_GNU_BUILD_ID
18c12e15e7SArnaldo Carvalho de Melo #define NT_GNU_BUILD_ID 3
19c12e15e7SArnaldo Carvalho de Melo #endif
20c12e15e7SArnaldo Carvalho de Melo 
2194cb9e38SArnaldo Carvalho de Melo enum dso_origin {
2294cb9e38SArnaldo Carvalho de Melo 	DSO__ORIG_KERNEL = 0,
2394cb9e38SArnaldo Carvalho de Melo 	DSO__ORIG_JAVA_JIT,
244cf40131SArnaldo Carvalho de Melo 	DSO__ORIG_BUILD_ID_CACHE,
2594cb9e38SArnaldo Carvalho de Melo 	DSO__ORIG_FEDORA,
2694cb9e38SArnaldo Carvalho de Melo 	DSO__ORIG_UBUNTU,
2794cb9e38SArnaldo Carvalho de Melo 	DSO__ORIG_BUILDID,
2894cb9e38SArnaldo Carvalho de Melo 	DSO__ORIG_DSO,
29439d473bSArnaldo Carvalho de Melo 	DSO__ORIG_KMODULE,
3094cb9e38SArnaldo Carvalho de Melo 	DSO__ORIG_NOT_FOUND,
3194cb9e38SArnaldo Carvalho de Melo };
3294cb9e38SArnaldo Carvalho de Melo 
33b0da954aSArnaldo Carvalho de Melo static void dsos__add(struct list_head *head, struct dso *dso);
343610583cSArnaldo Carvalho de Melo static struct map *map__new2(u64 start, struct dso *dso, enum map_type type);
35c338aee8SArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *self, struct map *map,
369de89fe7SArnaldo Carvalho de Melo 				symbol_filter_t filter);
37cc612d81SArnaldo Carvalho de Melo static int vmlinux_path__nr_entries;
38cc612d81SArnaldo Carvalho de Melo static char **vmlinux_path;
39439d473bSArnaldo Carvalho de Melo 
4075be6cf4SArnaldo Carvalho de Melo struct symbol_conf symbol_conf = {
41d599db3fSArnaldo Carvalho de Melo 	.exclude_other	  = true,
42b32d133aSArnaldo Carvalho de Melo 	.use_modules	  = true,
43b32d133aSArnaldo Carvalho de Melo 	.try_vmlinux_path = true,
44b32d133aSArnaldo Carvalho de Melo };
45b32d133aSArnaldo Carvalho de Melo 
463610583cSArnaldo Carvalho de Melo bool dso__loaded(const struct dso *self, enum map_type type)
473610583cSArnaldo Carvalho de Melo {
483610583cSArnaldo Carvalho de Melo 	return self->loaded & (1 << type);
493610583cSArnaldo Carvalho de Melo }
503610583cSArnaldo Carvalho de Melo 
5179406cd7SArnaldo Carvalho de Melo bool dso__sorted_by_name(const struct dso *self, enum map_type type)
5279406cd7SArnaldo Carvalho de Melo {
5379406cd7SArnaldo Carvalho de Melo 	return self->sorted_by_name & (1 << type);
5479406cd7SArnaldo Carvalho de Melo }
5579406cd7SArnaldo Carvalho de Melo 
5679406cd7SArnaldo Carvalho de Melo static void dso__set_sorted_by_name(struct dso *self, enum map_type type)
5779406cd7SArnaldo Carvalho de Melo {
5879406cd7SArnaldo Carvalho de Melo 	self->sorted_by_name |= (1 << type);
5979406cd7SArnaldo Carvalho de Melo }
6079406cd7SArnaldo Carvalho de Melo 
6136a3e646SArnaldo Carvalho de Melo bool symbol_type__is_a(char symbol_type, enum map_type map_type)
626893d4eeSArnaldo Carvalho de Melo {
636893d4eeSArnaldo Carvalho de Melo 	switch (map_type) {
646893d4eeSArnaldo Carvalho de Melo 	case MAP__FUNCTION:
656893d4eeSArnaldo Carvalho de Melo 		return symbol_type == 'T' || symbol_type == 'W';
66f1dfa0b1SArnaldo Carvalho de Melo 	case MAP__VARIABLE:
67f1dfa0b1SArnaldo Carvalho de Melo 		return symbol_type == 'D' || symbol_type == 'd';
686893d4eeSArnaldo Carvalho de Melo 	default:
696893d4eeSArnaldo Carvalho de Melo 		return false;
706893d4eeSArnaldo Carvalho de Melo 	}
716893d4eeSArnaldo Carvalho de Melo }
726893d4eeSArnaldo Carvalho de Melo 
73fcf1203aSArnaldo Carvalho de Melo static void symbols__fixup_end(struct rb_root *self)
74af427bf5SArnaldo Carvalho de Melo {
75fcf1203aSArnaldo Carvalho de Melo 	struct rb_node *nd, *prevnd = rb_first(self);
762e538c4aSArnaldo Carvalho de Melo 	struct symbol *curr, *prev;
77af427bf5SArnaldo Carvalho de Melo 
78af427bf5SArnaldo Carvalho de Melo 	if (prevnd == NULL)
79af427bf5SArnaldo Carvalho de Melo 		return;
80af427bf5SArnaldo Carvalho de Melo 
812e538c4aSArnaldo Carvalho de Melo 	curr = rb_entry(prevnd, struct symbol, rb_node);
822e538c4aSArnaldo Carvalho de Melo 
83af427bf5SArnaldo Carvalho de Melo 	for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
842e538c4aSArnaldo Carvalho de Melo 		prev = curr;
852e538c4aSArnaldo Carvalho de Melo 		curr = rb_entry(nd, struct symbol, rb_node);
86af427bf5SArnaldo Carvalho de Melo 
87af427bf5SArnaldo Carvalho de Melo 		if (prev->end == prev->start)
88af427bf5SArnaldo Carvalho de Melo 			prev->end = curr->start - 1;
89af427bf5SArnaldo Carvalho de Melo 	}
90af427bf5SArnaldo Carvalho de Melo 
912e538c4aSArnaldo Carvalho de Melo 	/* Last entry */
922e538c4aSArnaldo Carvalho de Melo 	if (curr->end == curr->start)
932e538c4aSArnaldo Carvalho de Melo 		curr->end = roundup(curr->start, 4096);
942e538c4aSArnaldo Carvalho de Melo }
952e538c4aSArnaldo Carvalho de Melo 
969958e1f0SArnaldo Carvalho de Melo static void __map_groups__fixup_end(struct map_groups *self, enum map_type type)
97af427bf5SArnaldo Carvalho de Melo {
98af427bf5SArnaldo Carvalho de Melo 	struct map *prev, *curr;
9995011c60SArnaldo Carvalho de Melo 	struct rb_node *nd, *prevnd = rb_first(&self->maps[type]);
100af427bf5SArnaldo Carvalho de Melo 
101af427bf5SArnaldo Carvalho de Melo 	if (prevnd == NULL)
102af427bf5SArnaldo Carvalho de Melo 		return;
103af427bf5SArnaldo Carvalho de Melo 
104af427bf5SArnaldo Carvalho de Melo 	curr = rb_entry(prevnd, struct map, rb_node);
105af427bf5SArnaldo Carvalho de Melo 
106af427bf5SArnaldo Carvalho de Melo 	for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
107af427bf5SArnaldo Carvalho de Melo 		prev = curr;
108af427bf5SArnaldo Carvalho de Melo 		curr = rb_entry(nd, struct map, rb_node);
109af427bf5SArnaldo Carvalho de Melo 		prev->end = curr->start - 1;
1102e538c4aSArnaldo Carvalho de Melo 	}
11190c83218SArnaldo Carvalho de Melo 
11290c83218SArnaldo Carvalho de Melo 	/*
11390c83218SArnaldo Carvalho de Melo 	 * We still haven't the actual symbols, so guess the
11490c83218SArnaldo Carvalho de Melo 	 * last map final address.
11590c83218SArnaldo Carvalho de Melo 	 */
11690c83218SArnaldo Carvalho de Melo 	curr->end = ~0UL;
117af427bf5SArnaldo Carvalho de Melo }
118af427bf5SArnaldo Carvalho de Melo 
1199958e1f0SArnaldo Carvalho de Melo static void map_groups__fixup_end(struct map_groups *self)
12023ea4a3fSArnaldo Carvalho de Melo {
12123ea4a3fSArnaldo Carvalho de Melo 	int i;
12223ea4a3fSArnaldo Carvalho de Melo 	for (i = 0; i < MAP__NR_TYPES; ++i)
1239958e1f0SArnaldo Carvalho de Melo 		__map_groups__fixup_end(self, i);
12423ea4a3fSArnaldo Carvalho de Melo }
12523ea4a3fSArnaldo Carvalho de Melo 
12600a192b3SArnaldo Carvalho de Melo static struct symbol *symbol__new(u64 start, u64 len, const char *name)
12786470930SIngo Molnar {
12886470930SIngo Molnar 	size_t namelen = strlen(name) + 1;
12975be6cf4SArnaldo Carvalho de Melo 	struct symbol *self = zalloc(symbol_conf.priv_size +
13036479484SArnaldo Carvalho de Melo 				     sizeof(*self) + namelen);
13136479484SArnaldo Carvalho de Melo 	if (self == NULL)
13286470930SIngo Molnar 		return NULL;
13386470930SIngo Molnar 
13475be6cf4SArnaldo Carvalho de Melo 	if (symbol_conf.priv_size)
13575be6cf4SArnaldo Carvalho de Melo 		self = ((void *)self) + symbol_conf.priv_size;
13636479484SArnaldo Carvalho de Melo 
13786470930SIngo Molnar 	self->start = start;
1386cfcc53eSMike Galbraith 	self->end   = len ? start + len - 1 : start;
139e4204992SArnaldo Carvalho de Melo 
14029a9f66dSArnaldo Carvalho de Melo 	pr_debug4("%s: %s %#Lx-%#Lx\n", __func__, name, start, self->end);
141e4204992SArnaldo Carvalho de Melo 
14286470930SIngo Molnar 	memcpy(self->name, name, namelen);
14386470930SIngo Molnar 
14486470930SIngo Molnar 	return self;
14586470930SIngo Molnar }
14686470930SIngo Molnar 
147*628ada0cSArnaldo Carvalho de Melo void symbol__delete(struct symbol *self)
14886470930SIngo Molnar {
14975be6cf4SArnaldo Carvalho de Melo 	free(((void *)self) - symbol_conf.priv_size);
15086470930SIngo Molnar }
15186470930SIngo Molnar 
15286470930SIngo Molnar static size_t symbol__fprintf(struct symbol *self, FILE *fp)
15386470930SIngo Molnar {
15486470930SIngo Molnar 	return fprintf(fp, " %llx-%llx %s\n",
15586470930SIngo Molnar 		       self->start, self->end, self->name);
15686470930SIngo Molnar }
15786470930SIngo Molnar 
158b7cece76SArnaldo Carvalho de Melo void dso__set_long_name(struct dso *self, char *name)
159cfc10d3bSArnaldo Carvalho de Melo {
160ef6ae724SArnaldo Carvalho de Melo 	if (name == NULL)
161ef6ae724SArnaldo Carvalho de Melo 		return;
162cfc10d3bSArnaldo Carvalho de Melo 	self->long_name = name;
163cfc10d3bSArnaldo Carvalho de Melo 	self->long_name_len = strlen(name);
164cfc10d3bSArnaldo Carvalho de Melo }
165cfc10d3bSArnaldo Carvalho de Melo 
166cfc10d3bSArnaldo Carvalho de Melo static void dso__set_basename(struct dso *self)
167cfc10d3bSArnaldo Carvalho de Melo {
168cfc10d3bSArnaldo Carvalho de Melo 	self->short_name = basename(self->long_name);
169cfc10d3bSArnaldo Carvalho de Melo }
170cfc10d3bSArnaldo Carvalho de Melo 
17100a192b3SArnaldo Carvalho de Melo struct dso *dso__new(const char *name)
17286470930SIngo Molnar {
173b7cece76SArnaldo Carvalho de Melo 	struct dso *self = zalloc(sizeof(*self) + strlen(name) + 1);
17486470930SIngo Molnar 
17586470930SIngo Molnar 	if (self != NULL) {
1766a4694a4SArnaldo Carvalho de Melo 		int i;
17786470930SIngo Molnar 		strcpy(self->name, name);
178cfc10d3bSArnaldo Carvalho de Melo 		dso__set_long_name(self, self->name);
179439d473bSArnaldo Carvalho de Melo 		self->short_name = self->name;
1806a4694a4SArnaldo Carvalho de Melo 		for (i = 0; i < MAP__NR_TYPES; ++i)
18179406cd7SArnaldo Carvalho de Melo 			self->symbols[i] = self->symbol_names[i] = RB_ROOT;
18252d422deSArnaldo Carvalho de Melo 		self->slen_calculated = 0;
18394cb9e38SArnaldo Carvalho de Melo 		self->origin = DSO__ORIG_NOT_FOUND;
1848d06367fSArnaldo Carvalho de Melo 		self->loaded = 0;
18579406cd7SArnaldo Carvalho de Melo 		self->sorted_by_name = 0;
1868d06367fSArnaldo Carvalho de Melo 		self->has_build_id = 0;
18786470930SIngo Molnar 	}
18886470930SIngo Molnar 
18986470930SIngo Molnar 	return self;
19086470930SIngo Molnar }
19186470930SIngo Molnar 
192fcf1203aSArnaldo Carvalho de Melo static void symbols__delete(struct rb_root *self)
19386470930SIngo Molnar {
19486470930SIngo Molnar 	struct symbol *pos;
195fcf1203aSArnaldo Carvalho de Melo 	struct rb_node *next = rb_first(self);
19686470930SIngo Molnar 
19786470930SIngo Molnar 	while (next) {
19886470930SIngo Molnar 		pos = rb_entry(next, struct symbol, rb_node);
19986470930SIngo Molnar 		next = rb_next(&pos->rb_node);
200fcf1203aSArnaldo Carvalho de Melo 		rb_erase(&pos->rb_node, self);
20100a192b3SArnaldo Carvalho de Melo 		symbol__delete(pos);
20286470930SIngo Molnar 	}
20386470930SIngo Molnar }
20486470930SIngo Molnar 
20586470930SIngo Molnar void dso__delete(struct dso *self)
20686470930SIngo Molnar {
2076a4694a4SArnaldo Carvalho de Melo 	int i;
2086a4694a4SArnaldo Carvalho de Melo 	for (i = 0; i < MAP__NR_TYPES; ++i)
2096a4694a4SArnaldo Carvalho de Melo 		symbols__delete(&self->symbols[i]);
210439d473bSArnaldo Carvalho de Melo 	if (self->long_name != self->name)
211439d473bSArnaldo Carvalho de Melo 		free(self->long_name);
21286470930SIngo Molnar 	free(self);
21386470930SIngo Molnar }
21486470930SIngo Molnar 
2158d06367fSArnaldo Carvalho de Melo void dso__set_build_id(struct dso *self, void *build_id)
2168d06367fSArnaldo Carvalho de Melo {
2178d06367fSArnaldo Carvalho de Melo 	memcpy(self->build_id, build_id, sizeof(self->build_id));
2188d06367fSArnaldo Carvalho de Melo 	self->has_build_id = 1;
2198d06367fSArnaldo Carvalho de Melo }
2208d06367fSArnaldo Carvalho de Melo 
221fcf1203aSArnaldo Carvalho de Melo static void symbols__insert(struct rb_root *self, struct symbol *sym)
22286470930SIngo Molnar {
223fcf1203aSArnaldo Carvalho de Melo 	struct rb_node **p = &self->rb_node;
22486470930SIngo Molnar 	struct rb_node *parent = NULL;
2259cffa8d5SPaul Mackerras 	const u64 ip = sym->start;
22686470930SIngo Molnar 	struct symbol *s;
22786470930SIngo Molnar 
22886470930SIngo Molnar 	while (*p != NULL) {
22986470930SIngo Molnar 		parent = *p;
23086470930SIngo Molnar 		s = rb_entry(parent, struct symbol, rb_node);
23186470930SIngo Molnar 		if (ip < s->start)
23286470930SIngo Molnar 			p = &(*p)->rb_left;
23386470930SIngo Molnar 		else
23486470930SIngo Molnar 			p = &(*p)->rb_right;
23586470930SIngo Molnar 	}
23686470930SIngo Molnar 	rb_link_node(&sym->rb_node, parent, p);
237fcf1203aSArnaldo Carvalho de Melo 	rb_insert_color(&sym->rb_node, self);
23886470930SIngo Molnar }
23986470930SIngo Molnar 
240fcf1203aSArnaldo Carvalho de Melo static struct symbol *symbols__find(struct rb_root *self, u64 ip)
24186470930SIngo Molnar {
24286470930SIngo Molnar 	struct rb_node *n;
24386470930SIngo Molnar 
24486470930SIngo Molnar 	if (self == NULL)
24586470930SIngo Molnar 		return NULL;
24686470930SIngo Molnar 
247fcf1203aSArnaldo Carvalho de Melo 	n = self->rb_node;
24886470930SIngo Molnar 
24986470930SIngo Molnar 	while (n) {
25086470930SIngo Molnar 		struct symbol *s = rb_entry(n, struct symbol, rb_node);
25186470930SIngo Molnar 
25286470930SIngo Molnar 		if (ip < s->start)
25386470930SIngo Molnar 			n = n->rb_left;
25486470930SIngo Molnar 		else if (ip > s->end)
25586470930SIngo Molnar 			n = n->rb_right;
25686470930SIngo Molnar 		else
25786470930SIngo Molnar 			return s;
25886470930SIngo Molnar 	}
25986470930SIngo Molnar 
26086470930SIngo Molnar 	return NULL;
26186470930SIngo Molnar }
26286470930SIngo Molnar 
26379406cd7SArnaldo Carvalho de Melo struct symbol_name_rb_node {
26479406cd7SArnaldo Carvalho de Melo 	struct rb_node	rb_node;
26579406cd7SArnaldo Carvalho de Melo 	struct symbol	sym;
26679406cd7SArnaldo Carvalho de Melo };
26779406cd7SArnaldo Carvalho de Melo 
26879406cd7SArnaldo Carvalho de Melo static void symbols__insert_by_name(struct rb_root *self, struct symbol *sym)
26979406cd7SArnaldo Carvalho de Melo {
27079406cd7SArnaldo Carvalho de Melo 	struct rb_node **p = &self->rb_node;
27179406cd7SArnaldo Carvalho de Melo 	struct rb_node *parent = NULL;
27279406cd7SArnaldo Carvalho de Melo 	struct symbol_name_rb_node *symn = ((void *)sym) - sizeof(*parent), *s;
27379406cd7SArnaldo Carvalho de Melo 
27479406cd7SArnaldo Carvalho de Melo 	while (*p != NULL) {
27579406cd7SArnaldo Carvalho de Melo 		parent = *p;
27679406cd7SArnaldo Carvalho de Melo 		s = rb_entry(parent, struct symbol_name_rb_node, rb_node);
27779406cd7SArnaldo Carvalho de Melo 		if (strcmp(sym->name, s->sym.name) < 0)
27879406cd7SArnaldo Carvalho de Melo 			p = &(*p)->rb_left;
27979406cd7SArnaldo Carvalho de Melo 		else
28079406cd7SArnaldo Carvalho de Melo 			p = &(*p)->rb_right;
28179406cd7SArnaldo Carvalho de Melo 	}
28279406cd7SArnaldo Carvalho de Melo 	rb_link_node(&symn->rb_node, parent, p);
28379406cd7SArnaldo Carvalho de Melo 	rb_insert_color(&symn->rb_node, self);
28479406cd7SArnaldo Carvalho de Melo }
28579406cd7SArnaldo Carvalho de Melo 
28679406cd7SArnaldo Carvalho de Melo static void symbols__sort_by_name(struct rb_root *self, struct rb_root *source)
28779406cd7SArnaldo Carvalho de Melo {
28879406cd7SArnaldo Carvalho de Melo 	struct rb_node *nd;
28979406cd7SArnaldo Carvalho de Melo 
29079406cd7SArnaldo Carvalho de Melo 	for (nd = rb_first(source); nd; nd = rb_next(nd)) {
29179406cd7SArnaldo Carvalho de Melo 		struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
29279406cd7SArnaldo Carvalho de Melo 		symbols__insert_by_name(self, pos);
29379406cd7SArnaldo Carvalho de Melo 	}
29479406cd7SArnaldo Carvalho de Melo }
29579406cd7SArnaldo Carvalho de Melo 
29679406cd7SArnaldo Carvalho de Melo static struct symbol *symbols__find_by_name(struct rb_root *self, const char *name)
29779406cd7SArnaldo Carvalho de Melo {
29879406cd7SArnaldo Carvalho de Melo 	struct rb_node *n;
29979406cd7SArnaldo Carvalho de Melo 
30079406cd7SArnaldo Carvalho de Melo 	if (self == NULL)
30179406cd7SArnaldo Carvalho de Melo 		return NULL;
30279406cd7SArnaldo Carvalho de Melo 
30379406cd7SArnaldo Carvalho de Melo 	n = self->rb_node;
30479406cd7SArnaldo Carvalho de Melo 
30579406cd7SArnaldo Carvalho de Melo 	while (n) {
30679406cd7SArnaldo Carvalho de Melo 		struct symbol_name_rb_node *s;
30779406cd7SArnaldo Carvalho de Melo 		int cmp;
30879406cd7SArnaldo Carvalho de Melo 
30979406cd7SArnaldo Carvalho de Melo 		s = rb_entry(n, struct symbol_name_rb_node, rb_node);
31079406cd7SArnaldo Carvalho de Melo 		cmp = strcmp(name, s->sym.name);
31179406cd7SArnaldo Carvalho de Melo 
31279406cd7SArnaldo Carvalho de Melo 		if (cmp < 0)
31379406cd7SArnaldo Carvalho de Melo 			n = n->rb_left;
31479406cd7SArnaldo Carvalho de Melo 		else if (cmp > 0)
31579406cd7SArnaldo Carvalho de Melo 			n = n->rb_right;
31679406cd7SArnaldo Carvalho de Melo 		else
31779406cd7SArnaldo Carvalho de Melo 			return &s->sym;
31879406cd7SArnaldo Carvalho de Melo 	}
31979406cd7SArnaldo Carvalho de Melo 
32079406cd7SArnaldo Carvalho de Melo 	return NULL;
32179406cd7SArnaldo Carvalho de Melo }
32279406cd7SArnaldo Carvalho de Melo 
32379406cd7SArnaldo Carvalho de Melo struct symbol *dso__find_symbol(struct dso *self,
32479406cd7SArnaldo Carvalho de Melo 				enum map_type type, u64 addr)
325fcf1203aSArnaldo Carvalho de Melo {
3266a4694a4SArnaldo Carvalho de Melo 	return symbols__find(&self->symbols[type], addr);
327fcf1203aSArnaldo Carvalho de Melo }
328fcf1203aSArnaldo Carvalho de Melo 
32979406cd7SArnaldo Carvalho de Melo struct symbol *dso__find_symbol_by_name(struct dso *self, enum map_type type,
33079406cd7SArnaldo Carvalho de Melo 					const char *name)
33179406cd7SArnaldo Carvalho de Melo {
33279406cd7SArnaldo Carvalho de Melo 	return symbols__find_by_name(&self->symbol_names[type], name);
33379406cd7SArnaldo Carvalho de Melo }
33479406cd7SArnaldo Carvalho de Melo 
33579406cd7SArnaldo Carvalho de Melo void dso__sort_by_name(struct dso *self, enum map_type type)
33679406cd7SArnaldo Carvalho de Melo {
33779406cd7SArnaldo Carvalho de Melo 	dso__set_sorted_by_name(self, type);
33879406cd7SArnaldo Carvalho de Melo 	return symbols__sort_by_name(&self->symbol_names[type],
33979406cd7SArnaldo Carvalho de Melo 				     &self->symbols[type]);
34079406cd7SArnaldo Carvalho de Melo }
34179406cd7SArnaldo Carvalho de Melo 
342ef12a141SArnaldo Carvalho de Melo int build_id__sprintf(const u8 *self, int len, char *bf)
3438d06367fSArnaldo Carvalho de Melo {
3448d06367fSArnaldo Carvalho de Melo 	char *bid = bf;
345ef12a141SArnaldo Carvalho de Melo 	const u8 *raw = self;
3468d06367fSArnaldo Carvalho de Melo 	int i;
3478d06367fSArnaldo Carvalho de Melo 
3488d06367fSArnaldo Carvalho de Melo 	for (i = 0; i < len; ++i) {
3498d06367fSArnaldo Carvalho de Melo 		sprintf(bid, "%02x", *raw);
3508d06367fSArnaldo Carvalho de Melo 		++raw;
3518d06367fSArnaldo Carvalho de Melo 		bid += 2;
3528d06367fSArnaldo Carvalho de Melo 	}
3538d06367fSArnaldo Carvalho de Melo 
3548d06367fSArnaldo Carvalho de Melo 	return raw - self;
3558d06367fSArnaldo Carvalho de Melo }
3568d06367fSArnaldo Carvalho de Melo 
3579e03eb2dSArnaldo Carvalho de Melo size_t dso__fprintf_buildid(struct dso *self, FILE *fp)
35886470930SIngo Molnar {
3598d06367fSArnaldo Carvalho de Melo 	char sbuild_id[BUILD_ID_SIZE * 2 + 1];
3608d06367fSArnaldo Carvalho de Melo 
3618d06367fSArnaldo Carvalho de Melo 	build_id__sprintf(self->build_id, sizeof(self->build_id), sbuild_id);
3629e03eb2dSArnaldo Carvalho de Melo 	return fprintf(fp, "%s", sbuild_id);
3639e03eb2dSArnaldo Carvalho de Melo }
3649e03eb2dSArnaldo Carvalho de Melo 
36595011c60SArnaldo Carvalho de Melo size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp)
3669e03eb2dSArnaldo Carvalho de Melo {
3679e03eb2dSArnaldo Carvalho de Melo 	struct rb_node *nd;
3689e03eb2dSArnaldo Carvalho de Melo 	size_t ret = fprintf(fp, "dso: %s (", self->short_name);
3699e03eb2dSArnaldo Carvalho de Melo 
3703846df2eSArnaldo Carvalho de Melo 	if (self->short_name != self->long_name)
3713846df2eSArnaldo Carvalho de Melo 		ret += fprintf(fp, "%s, ", self->long_name);
3723846df2eSArnaldo Carvalho de Melo 	ret += fprintf(fp, "%s, %sloaded, ", map_type__name[type],
3733846df2eSArnaldo Carvalho de Melo 		       self->loaded ? "" : "NOT ");
3749e03eb2dSArnaldo Carvalho de Melo 	ret += dso__fprintf_buildid(self, fp);
3756a4694a4SArnaldo Carvalho de Melo 	ret += fprintf(fp, ")\n");
37695011c60SArnaldo Carvalho de Melo 	for (nd = rb_first(&self->symbols[type]); nd; nd = rb_next(nd)) {
37786470930SIngo Molnar 		struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
37886470930SIngo Molnar 		ret += symbol__fprintf(pos, fp);
37986470930SIngo Molnar 	}
38086470930SIngo Molnar 
38186470930SIngo Molnar 	return ret;
38286470930SIngo Molnar }
38386470930SIngo Molnar 
3849e201442SArnaldo Carvalho de Melo int kallsyms__parse(const char *filename, void *arg,
3859e201442SArnaldo Carvalho de Melo 		    int (*process_symbol)(void *arg, const char *name,
386682b335aSArnaldo Carvalho de Melo 						     char type, u64 start))
38786470930SIngo Molnar {
38886470930SIngo Molnar 	char *line = NULL;
38986470930SIngo Molnar 	size_t n;
390682b335aSArnaldo Carvalho de Melo 	int err = 0;
3919e201442SArnaldo Carvalho de Melo 	FILE *file = fopen(filename, "r");
39286470930SIngo Molnar 
39386470930SIngo Molnar 	if (file == NULL)
39486470930SIngo Molnar 		goto out_failure;
39586470930SIngo Molnar 
39686470930SIngo Molnar 	while (!feof(file)) {
3979cffa8d5SPaul Mackerras 		u64 start;
39886470930SIngo Molnar 		int line_len, len;
39986470930SIngo Molnar 		char symbol_type;
4002e538c4aSArnaldo Carvalho de Melo 		char *symbol_name;
40186470930SIngo Molnar 
40286470930SIngo Molnar 		line_len = getline(&line, &n, file);
40386470930SIngo Molnar 		if (line_len < 0)
40486470930SIngo Molnar 			break;
40586470930SIngo Molnar 
40686470930SIngo Molnar 		if (!line)
40786470930SIngo Molnar 			goto out_failure;
40886470930SIngo Molnar 
40986470930SIngo Molnar 		line[--line_len] = '\0'; /* \n */
41086470930SIngo Molnar 
41186470930SIngo Molnar 		len = hex2u64(line, &start);
41286470930SIngo Molnar 
41386470930SIngo Molnar 		len++;
41486470930SIngo Molnar 		if (len + 2 >= line_len)
41586470930SIngo Molnar 			continue;
41686470930SIngo Molnar 
41786470930SIngo Molnar 		symbol_type = toupper(line[len]);
418af427bf5SArnaldo Carvalho de Melo 		symbol_name = line + len + 2;
419682b335aSArnaldo Carvalho de Melo 
420682b335aSArnaldo Carvalho de Melo 		err = process_symbol(arg, symbol_name, symbol_type, start);
421682b335aSArnaldo Carvalho de Melo 		if (err)
422682b335aSArnaldo Carvalho de Melo 			break;
423682b335aSArnaldo Carvalho de Melo 	}
424682b335aSArnaldo Carvalho de Melo 
425682b335aSArnaldo Carvalho de Melo 	free(line);
426682b335aSArnaldo Carvalho de Melo 	fclose(file);
427682b335aSArnaldo Carvalho de Melo 	return err;
428682b335aSArnaldo Carvalho de Melo 
429682b335aSArnaldo Carvalho de Melo out_failure:
430682b335aSArnaldo Carvalho de Melo 	return -1;
431682b335aSArnaldo Carvalho de Melo }
432682b335aSArnaldo Carvalho de Melo 
433682b335aSArnaldo Carvalho de Melo struct process_kallsyms_args {
434682b335aSArnaldo Carvalho de Melo 	struct map *map;
435682b335aSArnaldo Carvalho de Melo 	struct dso *dso;
436682b335aSArnaldo Carvalho de Melo };
437682b335aSArnaldo Carvalho de Melo 
438682b335aSArnaldo Carvalho de Melo static int map__process_kallsym_symbol(void *arg, const char *name,
439682b335aSArnaldo Carvalho de Melo 				       char type, u64 start)
440682b335aSArnaldo Carvalho de Melo {
441682b335aSArnaldo Carvalho de Melo 	struct symbol *sym;
442682b335aSArnaldo Carvalho de Melo 	struct process_kallsyms_args *a = arg;
443682b335aSArnaldo Carvalho de Melo 	struct rb_root *root = &a->dso->symbols[a->map->type];
444682b335aSArnaldo Carvalho de Melo 
445682b335aSArnaldo Carvalho de Melo 	if (!symbol_type__is_a(type, a->map->type))
446682b335aSArnaldo Carvalho de Melo 		return 0;
447682b335aSArnaldo Carvalho de Melo 
4482e538c4aSArnaldo Carvalho de Melo 	/*
4492e538c4aSArnaldo Carvalho de Melo 	 * Will fix up the end later, when we have all symbols sorted.
4502e538c4aSArnaldo Carvalho de Melo 	 */
451682b335aSArnaldo Carvalho de Melo 	sym = symbol__new(start, 0, name);
452af427bf5SArnaldo Carvalho de Melo 
4532e538c4aSArnaldo Carvalho de Melo 	if (sym == NULL)
454682b335aSArnaldo Carvalho de Melo 		return -ENOMEM;
45582164161SArnaldo Carvalho de Melo 	/*
45682164161SArnaldo Carvalho de Melo 	 * We will pass the symbols to the filter later, in
4574e06255fSArnaldo Carvalho de Melo 	 * map__split_kallsyms, when we have split the maps per module
45882164161SArnaldo Carvalho de Melo 	 */
4594e06255fSArnaldo Carvalho de Melo 	symbols__insert(root, sym);
460682b335aSArnaldo Carvalho de Melo 	return 0;
4612e538c4aSArnaldo Carvalho de Melo }
4622e538c4aSArnaldo Carvalho de Melo 
463682b335aSArnaldo Carvalho de Melo /*
464682b335aSArnaldo Carvalho de Melo  * Loads the function entries in /proc/kallsyms into kernel_map->dso,
465682b335aSArnaldo Carvalho de Melo  * so that we can in the next step set the symbol ->end address and then
466682b335aSArnaldo Carvalho de Melo  * call kernel_maps__split_kallsyms.
467682b335aSArnaldo Carvalho de Melo  */
4689e201442SArnaldo Carvalho de Melo static int dso__load_all_kallsyms(struct dso *self, const char *filename,
4699e201442SArnaldo Carvalho de Melo 				  struct map *map)
470682b335aSArnaldo Carvalho de Melo {
471682b335aSArnaldo Carvalho de Melo 	struct process_kallsyms_args args = { .map = map, .dso = self, };
4729e201442SArnaldo Carvalho de Melo 	return kallsyms__parse(filename, &args, map__process_kallsym_symbol);
4732e538c4aSArnaldo Carvalho de Melo }
4742e538c4aSArnaldo Carvalho de Melo 
4752e538c4aSArnaldo Carvalho de Melo /*
4762e538c4aSArnaldo Carvalho de Melo  * Split the symbols into maps, making sure there are no overlaps, i.e. the
4772e538c4aSArnaldo Carvalho de Melo  * kernel range is broken in several maps, named [kernel].N, as we don't have
4782e538c4aSArnaldo Carvalho de Melo  * the original ELF section names vmlinux have.
4792e538c4aSArnaldo Carvalho de Melo  */
4809958e1f0SArnaldo Carvalho de Melo static int dso__split_kallsyms(struct dso *self, struct map *map,
4819de89fe7SArnaldo Carvalho de Melo 			       symbol_filter_t filter)
4822e538c4aSArnaldo Carvalho de Melo {
4839de89fe7SArnaldo Carvalho de Melo 	struct map_groups *kmaps = map__kmap(map)->kmaps;
4844e06255fSArnaldo Carvalho de Melo 	struct map *curr_map = map;
4852e538c4aSArnaldo Carvalho de Melo 	struct symbol *pos;
4862e538c4aSArnaldo Carvalho de Melo 	int count = 0;
4874e06255fSArnaldo Carvalho de Melo 	struct rb_root *root = &self->symbols[map->type];
4884e06255fSArnaldo Carvalho de Melo 	struct rb_node *next = rb_first(root);
4892e538c4aSArnaldo Carvalho de Melo 	int kernel_range = 0;
4902e538c4aSArnaldo Carvalho de Melo 
4912e538c4aSArnaldo Carvalho de Melo 	while (next) {
4922e538c4aSArnaldo Carvalho de Melo 		char *module;
4932e538c4aSArnaldo Carvalho de Melo 
4942e538c4aSArnaldo Carvalho de Melo 		pos = rb_entry(next, struct symbol, rb_node);
4952e538c4aSArnaldo Carvalho de Melo 		next = rb_next(&pos->rb_node);
4962e538c4aSArnaldo Carvalho de Melo 
4972e538c4aSArnaldo Carvalho de Melo 		module = strchr(pos->name, '\t');
4982e538c4aSArnaldo Carvalho de Melo 		if (module) {
49975be6cf4SArnaldo Carvalho de Melo 			if (!symbol_conf.use_modules)
5001de8e245SArnaldo Carvalho de Melo 				goto discard_symbol;
5011de8e245SArnaldo Carvalho de Melo 
5022e538c4aSArnaldo Carvalho de Melo 			*module++ = '\0';
5032e538c4aSArnaldo Carvalho de Melo 
504b7cece76SArnaldo Carvalho de Melo 			if (strcmp(curr_map->dso->short_name, module)) {
5059de89fe7SArnaldo Carvalho de Melo 				curr_map = map_groups__find_by_name(kmaps, map->type, module);
5064e06255fSArnaldo Carvalho de Melo 				if (curr_map == NULL) {
50795011c60SArnaldo Carvalho de Melo 					pr_debug("/proc/{kallsyms,modules} "
508b7cece76SArnaldo Carvalho de Melo 					         "inconsistency while looking "
509b7cece76SArnaldo Carvalho de Melo 						 "for \"%s\" module!\n", module);
510af427bf5SArnaldo Carvalho de Melo 					return -1;
511af427bf5SArnaldo Carvalho de Melo 				}
512b7cece76SArnaldo Carvalho de Melo 
513b7cece76SArnaldo Carvalho de Melo 				if (curr_map->dso->loaded)
514b7cece76SArnaldo Carvalho de Melo 					goto discard_symbol;
515af427bf5SArnaldo Carvalho de Melo 			}
51686470930SIngo Molnar 			/*
5172e538c4aSArnaldo Carvalho de Melo 			 * So that we look just like we get from .ko files,
5182e538c4aSArnaldo Carvalho de Melo 			 * i.e. not prelinked, relative to map->start.
51986470930SIngo Molnar 			 */
5204e06255fSArnaldo Carvalho de Melo 			pos->start = curr_map->map_ip(curr_map, pos->start);
5214e06255fSArnaldo Carvalho de Melo 			pos->end   = curr_map->map_ip(curr_map, pos->end);
5224e06255fSArnaldo Carvalho de Melo 		} else if (curr_map != map) {
5232e538c4aSArnaldo Carvalho de Melo 			char dso_name[PATH_MAX];
5242e538c4aSArnaldo Carvalho de Melo 			struct dso *dso;
52586470930SIngo Molnar 
5262e538c4aSArnaldo Carvalho de Melo 			snprintf(dso_name, sizeof(dso_name), "[kernel].%d",
5272e538c4aSArnaldo Carvalho de Melo 				 kernel_range++);
52886470930SIngo Molnar 
52900a192b3SArnaldo Carvalho de Melo 			dso = dso__new(dso_name);
5302e538c4aSArnaldo Carvalho de Melo 			if (dso == NULL)
5312e538c4aSArnaldo Carvalho de Melo 				return -1;
5322e538c4aSArnaldo Carvalho de Melo 
5334e06255fSArnaldo Carvalho de Melo 			curr_map = map__new2(pos->start, dso, map->type);
53437fe5fcbSZhang, Yanmin 			if (curr_map == NULL) {
5352e538c4aSArnaldo Carvalho de Melo 				dso__delete(dso);
5362e538c4aSArnaldo Carvalho de Melo 				return -1;
5372e538c4aSArnaldo Carvalho de Melo 			}
5382e538c4aSArnaldo Carvalho de Melo 
5394e06255fSArnaldo Carvalho de Melo 			curr_map->map_ip = curr_map->unmap_ip = identity__map_ip;
5409de89fe7SArnaldo Carvalho de Melo 			map_groups__insert(kmaps, curr_map);
5412e538c4aSArnaldo Carvalho de Melo 			++kernel_range;
5422e538c4aSArnaldo Carvalho de Melo 		}
5432e538c4aSArnaldo Carvalho de Melo 
5444e06255fSArnaldo Carvalho de Melo 		if (filter && filter(curr_map, pos)) {
5451de8e245SArnaldo Carvalho de Melo discard_symbol:		rb_erase(&pos->rb_node, root);
54600a192b3SArnaldo Carvalho de Melo 			symbol__delete(pos);
5472e538c4aSArnaldo Carvalho de Melo 		} else {
5484e06255fSArnaldo Carvalho de Melo 			if (curr_map != map) {
5494e06255fSArnaldo Carvalho de Melo 				rb_erase(&pos->rb_node, root);
5504e06255fSArnaldo Carvalho de Melo 				symbols__insert(&curr_map->dso->symbols[curr_map->type], pos);
5512e538c4aSArnaldo Carvalho de Melo 			}
5529974f496SMike Galbraith 			count++;
5539974f496SMike Galbraith 		}
55486470930SIngo Molnar 	}
55586470930SIngo Molnar 
5569974f496SMike Galbraith 	return count;
55786470930SIngo Molnar }
55886470930SIngo Molnar 
5599de89fe7SArnaldo Carvalho de Melo int dso__load_kallsyms(struct dso *self, const char *filename,
5609de89fe7SArnaldo Carvalho de Melo 		       struct map *map, symbol_filter_t filter)
5612e538c4aSArnaldo Carvalho de Melo {
5629e201442SArnaldo Carvalho de Melo 	if (dso__load_all_kallsyms(self, filename, map) < 0)
5632e538c4aSArnaldo Carvalho de Melo 		return -1;
5642e538c4aSArnaldo Carvalho de Melo 
5654e06255fSArnaldo Carvalho de Melo 	symbols__fixup_end(&self->symbols[map->type]);
5664e06255fSArnaldo Carvalho de Melo 	self->origin = DSO__ORIG_KERNEL;
5672e538c4aSArnaldo Carvalho de Melo 
5689de89fe7SArnaldo Carvalho de Melo 	return dso__split_kallsyms(self, map, filter);
569af427bf5SArnaldo Carvalho de Melo }
570af427bf5SArnaldo Carvalho de Melo 
571439d473bSArnaldo Carvalho de Melo static int dso__load_perf_map(struct dso *self, struct map *map,
5726beba7adSArnaldo Carvalho de Melo 			      symbol_filter_t filter)
57380d496beSPekka Enberg {
57480d496beSPekka Enberg 	char *line = NULL;
57580d496beSPekka Enberg 	size_t n;
57680d496beSPekka Enberg 	FILE *file;
57780d496beSPekka Enberg 	int nr_syms = 0;
57880d496beSPekka Enberg 
579439d473bSArnaldo Carvalho de Melo 	file = fopen(self->long_name, "r");
58080d496beSPekka Enberg 	if (file == NULL)
58180d496beSPekka Enberg 		goto out_failure;
58280d496beSPekka Enberg 
58380d496beSPekka Enberg 	while (!feof(file)) {
5849cffa8d5SPaul Mackerras 		u64 start, size;
58580d496beSPekka Enberg 		struct symbol *sym;
58680d496beSPekka Enberg 		int line_len, len;
58780d496beSPekka Enberg 
58880d496beSPekka Enberg 		line_len = getline(&line, &n, file);
58980d496beSPekka Enberg 		if (line_len < 0)
59080d496beSPekka Enberg 			break;
59180d496beSPekka Enberg 
59280d496beSPekka Enberg 		if (!line)
59380d496beSPekka Enberg 			goto out_failure;
59480d496beSPekka Enberg 
59580d496beSPekka Enberg 		line[--line_len] = '\0'; /* \n */
59680d496beSPekka Enberg 
59780d496beSPekka Enberg 		len = hex2u64(line, &start);
59880d496beSPekka Enberg 
59980d496beSPekka Enberg 		len++;
60080d496beSPekka Enberg 		if (len + 2 >= line_len)
60180d496beSPekka Enberg 			continue;
60280d496beSPekka Enberg 
60380d496beSPekka Enberg 		len += hex2u64(line + len, &size);
60480d496beSPekka Enberg 
60580d496beSPekka Enberg 		len++;
60680d496beSPekka Enberg 		if (len + 2 >= line_len)
60780d496beSPekka Enberg 			continue;
60880d496beSPekka Enberg 
60900a192b3SArnaldo Carvalho de Melo 		sym = symbol__new(start, size, line + len);
61080d496beSPekka Enberg 
61180d496beSPekka Enberg 		if (sym == NULL)
61280d496beSPekka Enberg 			goto out_delete_line;
61380d496beSPekka Enberg 
614439d473bSArnaldo Carvalho de Melo 		if (filter && filter(map, sym))
61500a192b3SArnaldo Carvalho de Melo 			symbol__delete(sym);
61680d496beSPekka Enberg 		else {
6176a4694a4SArnaldo Carvalho de Melo 			symbols__insert(&self->symbols[map->type], sym);
61880d496beSPekka Enberg 			nr_syms++;
61980d496beSPekka Enberg 		}
62080d496beSPekka Enberg 	}
62180d496beSPekka Enberg 
62280d496beSPekka Enberg 	free(line);
62380d496beSPekka Enberg 	fclose(file);
62480d496beSPekka Enberg 
62580d496beSPekka Enberg 	return nr_syms;
62680d496beSPekka Enberg 
62780d496beSPekka Enberg out_delete_line:
62880d496beSPekka Enberg 	free(line);
62980d496beSPekka Enberg out_failure:
63080d496beSPekka Enberg 	return -1;
63180d496beSPekka Enberg }
63280d496beSPekka Enberg 
63386470930SIngo Molnar /**
63486470930SIngo Molnar  * elf_symtab__for_each_symbol - iterate thru all the symbols
63586470930SIngo Molnar  *
63686470930SIngo Molnar  * @self: struct elf_symtab instance to iterate
63783a0944fSIngo Molnar  * @idx: uint32_t idx
63886470930SIngo Molnar  * @sym: GElf_Sym iterator
63986470930SIngo Molnar  */
64083a0944fSIngo Molnar #define elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) \
64183a0944fSIngo Molnar 	for (idx = 0, gelf_getsym(syms, idx, &sym);\
64283a0944fSIngo Molnar 	     idx < nr_syms; \
64383a0944fSIngo Molnar 	     idx++, gelf_getsym(syms, idx, &sym))
64486470930SIngo Molnar 
64586470930SIngo Molnar static inline uint8_t elf_sym__type(const GElf_Sym *sym)
64686470930SIngo Molnar {
64786470930SIngo Molnar 	return GELF_ST_TYPE(sym->st_info);
64886470930SIngo Molnar }
64986470930SIngo Molnar 
65086470930SIngo Molnar static inline int elf_sym__is_function(const GElf_Sym *sym)
65186470930SIngo Molnar {
65286470930SIngo Molnar 	return elf_sym__type(sym) == STT_FUNC &&
65386470930SIngo Molnar 	       sym->st_name != 0 &&
65481833130SArnaldo Carvalho de Melo 	       sym->st_shndx != SHN_UNDEF;
65586470930SIngo Molnar }
65686470930SIngo Molnar 
657f1dfa0b1SArnaldo Carvalho de Melo static inline bool elf_sym__is_object(const GElf_Sym *sym)
658f1dfa0b1SArnaldo Carvalho de Melo {
659f1dfa0b1SArnaldo Carvalho de Melo 	return elf_sym__type(sym) == STT_OBJECT &&
660f1dfa0b1SArnaldo Carvalho de Melo 		sym->st_name != 0 &&
661f1dfa0b1SArnaldo Carvalho de Melo 		sym->st_shndx != SHN_UNDEF;
662f1dfa0b1SArnaldo Carvalho de Melo }
663f1dfa0b1SArnaldo Carvalho de Melo 
6646cfcc53eSMike Galbraith static inline int elf_sym__is_label(const GElf_Sym *sym)
6656cfcc53eSMike Galbraith {
6666cfcc53eSMike Galbraith 	return elf_sym__type(sym) == STT_NOTYPE &&
6676cfcc53eSMike Galbraith 		sym->st_name != 0 &&
6686cfcc53eSMike Galbraith 		sym->st_shndx != SHN_UNDEF &&
6696cfcc53eSMike Galbraith 		sym->st_shndx != SHN_ABS;
6706cfcc53eSMike Galbraith }
6716cfcc53eSMike Galbraith 
6726cfcc53eSMike Galbraith static inline const char *elf_sec__name(const GElf_Shdr *shdr,
6736cfcc53eSMike Galbraith 					const Elf_Data *secstrs)
6746cfcc53eSMike Galbraith {
6756cfcc53eSMike Galbraith 	return secstrs->d_buf + shdr->sh_name;
6766cfcc53eSMike Galbraith }
6776cfcc53eSMike Galbraith 
6786cfcc53eSMike Galbraith static inline int elf_sec__is_text(const GElf_Shdr *shdr,
6796cfcc53eSMike Galbraith 					const Elf_Data *secstrs)
6806cfcc53eSMike Galbraith {
6816cfcc53eSMike Galbraith 	return strstr(elf_sec__name(shdr, secstrs), "text") != NULL;
6826cfcc53eSMike Galbraith }
6836cfcc53eSMike Galbraith 
684f1dfa0b1SArnaldo Carvalho de Melo static inline bool elf_sec__is_data(const GElf_Shdr *shdr,
685f1dfa0b1SArnaldo Carvalho de Melo 				    const Elf_Data *secstrs)
686f1dfa0b1SArnaldo Carvalho de Melo {
687f1dfa0b1SArnaldo Carvalho de Melo 	return strstr(elf_sec__name(shdr, secstrs), "data") != NULL;
688f1dfa0b1SArnaldo Carvalho de Melo }
689f1dfa0b1SArnaldo Carvalho de Melo 
69086470930SIngo Molnar static inline const char *elf_sym__name(const GElf_Sym *sym,
69186470930SIngo Molnar 					const Elf_Data *symstrs)
69286470930SIngo Molnar {
69386470930SIngo Molnar 	return symstrs->d_buf + sym->st_name;
69486470930SIngo Molnar }
69586470930SIngo Molnar 
69686470930SIngo Molnar static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
69786470930SIngo Molnar 				    GElf_Shdr *shp, const char *name,
69883a0944fSIngo Molnar 				    size_t *idx)
69986470930SIngo Molnar {
70086470930SIngo Molnar 	Elf_Scn *sec = NULL;
70186470930SIngo Molnar 	size_t cnt = 1;
70286470930SIngo Molnar 
70386470930SIngo Molnar 	while ((sec = elf_nextscn(elf, sec)) != NULL) {
70486470930SIngo Molnar 		char *str;
70586470930SIngo Molnar 
70686470930SIngo Molnar 		gelf_getshdr(sec, shp);
70786470930SIngo Molnar 		str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name);
70886470930SIngo Molnar 		if (!strcmp(name, str)) {
70983a0944fSIngo Molnar 			if (idx)
71083a0944fSIngo Molnar 				*idx = cnt;
71186470930SIngo Molnar 			break;
71286470930SIngo Molnar 		}
71386470930SIngo Molnar 		++cnt;
71486470930SIngo Molnar 	}
71586470930SIngo Molnar 
71686470930SIngo Molnar 	return sec;
71786470930SIngo Molnar }
71886470930SIngo Molnar 
71986470930SIngo Molnar #define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \
72086470930SIngo Molnar 	for (idx = 0, pos = gelf_getrel(reldata, 0, &pos_mem); \
72186470930SIngo Molnar 	     idx < nr_entries; \
72286470930SIngo Molnar 	     ++idx, pos = gelf_getrel(reldata, idx, &pos_mem))
72386470930SIngo Molnar 
72486470930SIngo Molnar #define elf_section__for_each_rela(reldata, pos, pos_mem, idx, nr_entries) \
72586470930SIngo Molnar 	for (idx = 0, pos = gelf_getrela(reldata, 0, &pos_mem); \
72686470930SIngo Molnar 	     idx < nr_entries; \
72786470930SIngo Molnar 	     ++idx, pos = gelf_getrela(reldata, idx, &pos_mem))
72886470930SIngo Molnar 
729a25e46c4SArnaldo Carvalho de Melo /*
730a25e46c4SArnaldo Carvalho de Melo  * We need to check if we have a .dynsym, so that we can handle the
731a25e46c4SArnaldo Carvalho de Melo  * .plt, synthesizing its symbols, that aren't on the symtabs (be it
732a25e46c4SArnaldo Carvalho de Melo  * .dynsym or .symtab).
733a25e46c4SArnaldo Carvalho de Melo  * And always look at the original dso, not at debuginfo packages, that
734a25e46c4SArnaldo Carvalho de Melo  * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS).
735a25e46c4SArnaldo Carvalho de Melo  */
73682164161SArnaldo Carvalho de Melo static int dso__synthesize_plt_symbols(struct  dso *self, struct map *map,
73782164161SArnaldo Carvalho de Melo 				       symbol_filter_t filter)
73886470930SIngo Molnar {
73986470930SIngo Molnar 	uint32_t nr_rel_entries, idx;
74086470930SIngo Molnar 	GElf_Sym sym;
7419cffa8d5SPaul Mackerras 	u64 plt_offset;
74286470930SIngo Molnar 	GElf_Shdr shdr_plt;
74386470930SIngo Molnar 	struct symbol *f;
744a25e46c4SArnaldo Carvalho de Melo 	GElf_Shdr shdr_rel_plt, shdr_dynsym;
74586470930SIngo Molnar 	Elf_Data *reldata, *syms, *symstrs;
746a25e46c4SArnaldo Carvalho de Melo 	Elf_Scn *scn_plt_rel, *scn_symstrs, *scn_dynsym;
747a25e46c4SArnaldo Carvalho de Melo 	size_t dynsym_idx;
748a25e46c4SArnaldo Carvalho de Melo 	GElf_Ehdr ehdr;
74986470930SIngo Molnar 	char sympltname[1024];
750a25e46c4SArnaldo Carvalho de Melo 	Elf *elf;
751a25e46c4SArnaldo Carvalho de Melo 	int nr = 0, symidx, fd, err = 0;
75286470930SIngo Molnar 
753439d473bSArnaldo Carvalho de Melo 	fd = open(self->long_name, O_RDONLY);
754a25e46c4SArnaldo Carvalho de Melo 	if (fd < 0)
755a25e46c4SArnaldo Carvalho de Melo 		goto out;
756a25e46c4SArnaldo Carvalho de Melo 
75784087126SMarti Raudsepp 	elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
758a25e46c4SArnaldo Carvalho de Melo 	if (elf == NULL)
759a25e46c4SArnaldo Carvalho de Melo 		goto out_close;
760a25e46c4SArnaldo Carvalho de Melo 
761a25e46c4SArnaldo Carvalho de Melo 	if (gelf_getehdr(elf, &ehdr) == NULL)
762a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
763a25e46c4SArnaldo Carvalho de Melo 
764a25e46c4SArnaldo Carvalho de Melo 	scn_dynsym = elf_section_by_name(elf, &ehdr, &shdr_dynsym,
765a25e46c4SArnaldo Carvalho de Melo 					 ".dynsym", &dynsym_idx);
766a25e46c4SArnaldo Carvalho de Melo 	if (scn_dynsym == NULL)
767a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
768a25e46c4SArnaldo Carvalho de Melo 
769a25e46c4SArnaldo Carvalho de Melo 	scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
77086470930SIngo Molnar 					  ".rela.plt", NULL);
77186470930SIngo Molnar 	if (scn_plt_rel == NULL) {
772a25e46c4SArnaldo Carvalho de Melo 		scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
77386470930SIngo Molnar 						  ".rel.plt", NULL);
77486470930SIngo Molnar 		if (scn_plt_rel == NULL)
775a25e46c4SArnaldo Carvalho de Melo 			goto out_elf_end;
77686470930SIngo Molnar 	}
77786470930SIngo Molnar 
778a25e46c4SArnaldo Carvalho de Melo 	err = -1;
77986470930SIngo Molnar 
780a25e46c4SArnaldo Carvalho de Melo 	if (shdr_rel_plt.sh_link != dynsym_idx)
781a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
782a25e46c4SArnaldo Carvalho de Melo 
783a25e46c4SArnaldo Carvalho de Melo 	if (elf_section_by_name(elf, &ehdr, &shdr_plt, ".plt", NULL) == NULL)
784a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
78586470930SIngo Molnar 
78686470930SIngo Molnar 	/*
78783a0944fSIngo Molnar 	 * Fetch the relocation section to find the idxes to the GOT
78886470930SIngo Molnar 	 * and the symbols in the .dynsym they refer to.
78986470930SIngo Molnar 	 */
79086470930SIngo Molnar 	reldata = elf_getdata(scn_plt_rel, NULL);
79186470930SIngo Molnar 	if (reldata == NULL)
792a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
79386470930SIngo Molnar 
79486470930SIngo Molnar 	syms = elf_getdata(scn_dynsym, NULL);
79586470930SIngo Molnar 	if (syms == NULL)
796a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
79786470930SIngo Molnar 
798a25e46c4SArnaldo Carvalho de Melo 	scn_symstrs = elf_getscn(elf, shdr_dynsym.sh_link);
79986470930SIngo Molnar 	if (scn_symstrs == NULL)
800a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
80186470930SIngo Molnar 
80286470930SIngo Molnar 	symstrs = elf_getdata(scn_symstrs, NULL);
80386470930SIngo Molnar 	if (symstrs == NULL)
804a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
80586470930SIngo Molnar 
80686470930SIngo Molnar 	nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize;
80786470930SIngo Molnar 	plt_offset = shdr_plt.sh_offset;
80886470930SIngo Molnar 
80986470930SIngo Molnar 	if (shdr_rel_plt.sh_type == SHT_RELA) {
81086470930SIngo Molnar 		GElf_Rela pos_mem, *pos;
81186470930SIngo Molnar 
81286470930SIngo Molnar 		elf_section__for_each_rela(reldata, pos, pos_mem, idx,
81386470930SIngo Molnar 					   nr_rel_entries) {
81486470930SIngo Molnar 			symidx = GELF_R_SYM(pos->r_info);
81586470930SIngo Molnar 			plt_offset += shdr_plt.sh_entsize;
81686470930SIngo Molnar 			gelf_getsym(syms, symidx, &sym);
81786470930SIngo Molnar 			snprintf(sympltname, sizeof(sympltname),
81886470930SIngo Molnar 				 "%s@plt", elf_sym__name(&sym, symstrs));
81986470930SIngo Molnar 
82086470930SIngo Molnar 			f = symbol__new(plt_offset, shdr_plt.sh_entsize,
82100a192b3SArnaldo Carvalho de Melo 					sympltname);
82286470930SIngo Molnar 			if (!f)
823a25e46c4SArnaldo Carvalho de Melo 				goto out_elf_end;
82486470930SIngo Molnar 
82582164161SArnaldo Carvalho de Melo 			if (filter && filter(map, f))
82682164161SArnaldo Carvalho de Melo 				symbol__delete(f);
82782164161SArnaldo Carvalho de Melo 			else {
8286a4694a4SArnaldo Carvalho de Melo 				symbols__insert(&self->symbols[map->type], f);
82986470930SIngo Molnar 				++nr;
83086470930SIngo Molnar 			}
83182164161SArnaldo Carvalho de Melo 		}
83286470930SIngo Molnar 	} else if (shdr_rel_plt.sh_type == SHT_REL) {
83386470930SIngo Molnar 		GElf_Rel pos_mem, *pos;
83486470930SIngo Molnar 		elf_section__for_each_rel(reldata, pos, pos_mem, idx,
83586470930SIngo Molnar 					  nr_rel_entries) {
83686470930SIngo Molnar 			symidx = GELF_R_SYM(pos->r_info);
83786470930SIngo Molnar 			plt_offset += shdr_plt.sh_entsize;
83886470930SIngo Molnar 			gelf_getsym(syms, symidx, &sym);
83986470930SIngo Molnar 			snprintf(sympltname, sizeof(sympltname),
84086470930SIngo Molnar 				 "%s@plt", elf_sym__name(&sym, symstrs));
84186470930SIngo Molnar 
84286470930SIngo Molnar 			f = symbol__new(plt_offset, shdr_plt.sh_entsize,
84300a192b3SArnaldo Carvalho de Melo 					sympltname);
84486470930SIngo Molnar 			if (!f)
845a25e46c4SArnaldo Carvalho de Melo 				goto out_elf_end;
84686470930SIngo Molnar 
84782164161SArnaldo Carvalho de Melo 			if (filter && filter(map, f))
84882164161SArnaldo Carvalho de Melo 				symbol__delete(f);
84982164161SArnaldo Carvalho de Melo 			else {
8506a4694a4SArnaldo Carvalho de Melo 				symbols__insert(&self->symbols[map->type], f);
85186470930SIngo Molnar 				++nr;
85286470930SIngo Molnar 			}
85386470930SIngo Molnar 		}
85482164161SArnaldo Carvalho de Melo 	}
85586470930SIngo Molnar 
856a25e46c4SArnaldo Carvalho de Melo 	err = 0;
857a25e46c4SArnaldo Carvalho de Melo out_elf_end:
858a25e46c4SArnaldo Carvalho de Melo 	elf_end(elf);
859a25e46c4SArnaldo Carvalho de Melo out_close:
860a25e46c4SArnaldo Carvalho de Melo 	close(fd);
861a25e46c4SArnaldo Carvalho de Melo 
862a25e46c4SArnaldo Carvalho de Melo 	if (err == 0)
86386470930SIngo Molnar 		return nr;
864a25e46c4SArnaldo Carvalho de Melo out:
8656beba7adSArnaldo Carvalho de Melo 	pr_warning("%s: problems reading %s PLT info.\n",
866439d473bSArnaldo Carvalho de Melo 		   __func__, self->long_name);
867a25e46c4SArnaldo Carvalho de Melo 	return 0;
86886470930SIngo Molnar }
86986470930SIngo Molnar 
870d45868d3SArnaldo Carvalho de Melo static bool elf_sym__is_a(GElf_Sym *self, enum map_type type)
871d45868d3SArnaldo Carvalho de Melo {
872d45868d3SArnaldo Carvalho de Melo 	switch (type) {
873d45868d3SArnaldo Carvalho de Melo 	case MAP__FUNCTION:
874d45868d3SArnaldo Carvalho de Melo 		return elf_sym__is_function(self);
875f1dfa0b1SArnaldo Carvalho de Melo 	case MAP__VARIABLE:
876f1dfa0b1SArnaldo Carvalho de Melo 		return elf_sym__is_object(self);
877d45868d3SArnaldo Carvalho de Melo 	default:
878d45868d3SArnaldo Carvalho de Melo 		return false;
879d45868d3SArnaldo Carvalho de Melo 	}
880d45868d3SArnaldo Carvalho de Melo }
881d45868d3SArnaldo Carvalho de Melo 
882d45868d3SArnaldo Carvalho de Melo static bool elf_sec__is_a(GElf_Shdr *self, Elf_Data *secstrs, enum map_type type)
883d45868d3SArnaldo Carvalho de Melo {
884d45868d3SArnaldo Carvalho de Melo 	switch (type) {
885d45868d3SArnaldo Carvalho de Melo 	case MAP__FUNCTION:
886d45868d3SArnaldo Carvalho de Melo 		return elf_sec__is_text(self, secstrs);
887f1dfa0b1SArnaldo Carvalho de Melo 	case MAP__VARIABLE:
888f1dfa0b1SArnaldo Carvalho de Melo 		return elf_sec__is_data(self, secstrs);
889d45868d3SArnaldo Carvalho de Melo 	default:
890d45868d3SArnaldo Carvalho de Melo 		return false;
891d45868d3SArnaldo Carvalho de Melo 	}
892d45868d3SArnaldo Carvalho de Melo }
893d45868d3SArnaldo Carvalho de Melo 
8949de89fe7SArnaldo Carvalho de Melo static int dso__load_sym(struct dso *self, struct map *map, const char *name,
8959de89fe7SArnaldo Carvalho de Melo 			 int fd, symbol_filter_t filter, int kmodule)
89686470930SIngo Molnar {
8979de89fe7SArnaldo Carvalho de Melo 	struct kmap *kmap = self->kernel ? map__kmap(map) : NULL;
8982e538c4aSArnaldo Carvalho de Melo 	struct map *curr_map = map;
8992e538c4aSArnaldo Carvalho de Melo 	struct dso *curr_dso = self;
9002e538c4aSArnaldo Carvalho de Melo 	size_t dso_name_len = strlen(self->short_name);
9016cfcc53eSMike Galbraith 	Elf_Data *symstrs, *secstrs;
90286470930SIngo Molnar 	uint32_t nr_syms;
90386470930SIngo Molnar 	int err = -1;
90483a0944fSIngo Molnar 	uint32_t idx;
90586470930SIngo Molnar 	GElf_Ehdr ehdr;
90686470930SIngo Molnar 	GElf_Shdr shdr;
90786470930SIngo Molnar 	Elf_Data *syms;
90886470930SIngo Molnar 	GElf_Sym sym;
909a25e46c4SArnaldo Carvalho de Melo 	Elf_Scn *sec, *sec_strndx;
91086470930SIngo Molnar 	Elf *elf;
911439d473bSArnaldo Carvalho de Melo 	int nr = 0;
91286470930SIngo Molnar 
91384087126SMarti Raudsepp 	elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
91486470930SIngo Molnar 	if (elf == NULL) {
9156beba7adSArnaldo Carvalho de Melo 		pr_err("%s: cannot read %s ELF file.\n", __func__, name);
91686470930SIngo Molnar 		goto out_close;
91786470930SIngo Molnar 	}
91886470930SIngo Molnar 
91986470930SIngo Molnar 	if (gelf_getehdr(elf, &ehdr) == NULL) {
9206beba7adSArnaldo Carvalho de Melo 		pr_err("%s: cannot get elf header.\n", __func__);
92186470930SIngo Molnar 		goto out_elf_end;
92286470930SIngo Molnar 	}
92386470930SIngo Molnar 
92486470930SIngo Molnar 	sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL);
92586470930SIngo Molnar 	if (sec == NULL) {
926a25e46c4SArnaldo Carvalho de Melo 		sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL);
927a25e46c4SArnaldo Carvalho de Melo 		if (sec == NULL)
92886470930SIngo Molnar 			goto out_elf_end;
92986470930SIngo Molnar 	}
93086470930SIngo Molnar 
93186470930SIngo Molnar 	syms = elf_getdata(sec, NULL);
93286470930SIngo Molnar 	if (syms == NULL)
93386470930SIngo Molnar 		goto out_elf_end;
93486470930SIngo Molnar 
93586470930SIngo Molnar 	sec = elf_getscn(elf, shdr.sh_link);
93686470930SIngo Molnar 	if (sec == NULL)
93786470930SIngo Molnar 		goto out_elf_end;
93886470930SIngo Molnar 
93986470930SIngo Molnar 	symstrs = elf_getdata(sec, NULL);
94086470930SIngo Molnar 	if (symstrs == NULL)
94186470930SIngo Molnar 		goto out_elf_end;
94286470930SIngo Molnar 
9436cfcc53eSMike Galbraith 	sec_strndx = elf_getscn(elf, ehdr.e_shstrndx);
9446cfcc53eSMike Galbraith 	if (sec_strndx == NULL)
9456cfcc53eSMike Galbraith 		goto out_elf_end;
9466cfcc53eSMike Galbraith 
9476cfcc53eSMike Galbraith 	secstrs = elf_getdata(sec_strndx, NULL);
9489b30a26bSStoyan Gaydarov 	if (secstrs == NULL)
9496cfcc53eSMike Galbraith 		goto out_elf_end;
9506cfcc53eSMike Galbraith 
95186470930SIngo Molnar 	nr_syms = shdr.sh_size / shdr.sh_entsize;
95286470930SIngo Molnar 
953e9fbc9dcSArjan van de Ven 	memset(&sym, 0, sizeof(sym));
9549de89fe7SArnaldo Carvalho de Melo 	if (!self->kernel) {
95530d7a77dSArnaldo Carvalho de Melo 		self->adjust_symbols = (ehdr.e_type == ET_EXEC ||
95630d7a77dSArnaldo Carvalho de Melo 				elf_section_by_name(elf, &ehdr, &shdr,
957f5812a7aSArnaldo Carvalho de Melo 						     ".gnu.prelink_undo",
95830d7a77dSArnaldo Carvalho de Melo 						     NULL) != NULL);
959d20ff6bdSMike Galbraith 	} else self->adjust_symbols = 0;
960d20ff6bdSMike Galbraith 
96183a0944fSIngo Molnar 	elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) {
96286470930SIngo Molnar 		struct symbol *f;
96356b03f3cSArnaldo Carvalho de Melo 		const char *elf_name = elf_sym__name(&sym, symstrs);
9642e538c4aSArnaldo Carvalho de Melo 		char *demangled = NULL;
9656cfcc53eSMike Galbraith 		int is_label = elf_sym__is_label(&sym);
9666cfcc53eSMike Galbraith 		const char *section_name;
96786470930SIngo Molnar 
9689de89fe7SArnaldo Carvalho de Melo 		if (kmap && kmap->ref_reloc_sym && kmap->ref_reloc_sym->name &&
9699de89fe7SArnaldo Carvalho de Melo 		    strcmp(elf_name, kmap->ref_reloc_sym->name) == 0)
9709de89fe7SArnaldo Carvalho de Melo 			kmap->ref_reloc_sym->unrelocated_addr = sym.st_value;
97156b03f3cSArnaldo Carvalho de Melo 
972d45868d3SArnaldo Carvalho de Melo 		if (!is_label && !elf_sym__is_a(&sym, map->type))
97386470930SIngo Molnar 			continue;
97486470930SIngo Molnar 
97586470930SIngo Molnar 		sec = elf_getscn(elf, sym.st_shndx);
97686470930SIngo Molnar 		if (!sec)
97786470930SIngo Molnar 			goto out_elf_end;
97886470930SIngo Molnar 
97986470930SIngo Molnar 		gelf_getshdr(sec, &shdr);
9806cfcc53eSMike Galbraith 
981d45868d3SArnaldo Carvalho de Melo 		if (is_label && !elf_sec__is_a(&shdr, secstrs, map->type))
9826cfcc53eSMike Galbraith 			continue;
9836cfcc53eSMike Galbraith 
9846cfcc53eSMike Galbraith 		section_name = elf_sec__name(&shdr, secstrs);
98586470930SIngo Molnar 
9869de89fe7SArnaldo Carvalho de Melo 		if (self->kernel || kmodule) {
9872e538c4aSArnaldo Carvalho de Melo 			char dso_name[PATH_MAX];
9882e538c4aSArnaldo Carvalho de Melo 
9892e538c4aSArnaldo Carvalho de Melo 			if (strcmp(section_name,
9902e538c4aSArnaldo Carvalho de Melo 				   curr_dso->short_name + dso_name_len) == 0)
9912e538c4aSArnaldo Carvalho de Melo 				goto new_symbol;
9922e538c4aSArnaldo Carvalho de Melo 
9932e538c4aSArnaldo Carvalho de Melo 			if (strcmp(section_name, ".text") == 0) {
9942e538c4aSArnaldo Carvalho de Melo 				curr_map = map;
9952e538c4aSArnaldo Carvalho de Melo 				curr_dso = self;
9962e538c4aSArnaldo Carvalho de Melo 				goto new_symbol;
997af427bf5SArnaldo Carvalho de Melo 			}
998af427bf5SArnaldo Carvalho de Melo 
9992e538c4aSArnaldo Carvalho de Melo 			snprintf(dso_name, sizeof(dso_name),
10002e538c4aSArnaldo Carvalho de Melo 				 "%s%s", self->short_name, section_name);
10012e538c4aSArnaldo Carvalho de Melo 
10029de89fe7SArnaldo Carvalho de Melo 			curr_map = map_groups__find_by_name(kmap->kmaps, map->type, dso_name);
10032e538c4aSArnaldo Carvalho de Melo 			if (curr_map == NULL) {
10042e538c4aSArnaldo Carvalho de Melo 				u64 start = sym.st_value;
10052e538c4aSArnaldo Carvalho de Melo 
10062e538c4aSArnaldo Carvalho de Melo 				if (kmodule)
10072e538c4aSArnaldo Carvalho de Melo 					start += map->start + shdr.sh_offset;
10082e538c4aSArnaldo Carvalho de Melo 
100900a192b3SArnaldo Carvalho de Melo 				curr_dso = dso__new(dso_name);
10102e538c4aSArnaldo Carvalho de Melo 				if (curr_dso == NULL)
10112e538c4aSArnaldo Carvalho de Melo 					goto out_elf_end;
10123610583cSArnaldo Carvalho de Melo 				curr_map = map__new2(start, curr_dso,
10136275ce2dSArnaldo Carvalho de Melo 						     map->type);
10142e538c4aSArnaldo Carvalho de Melo 				if (curr_map == NULL) {
10152e538c4aSArnaldo Carvalho de Melo 					dso__delete(curr_dso);
10162e538c4aSArnaldo Carvalho de Melo 					goto out_elf_end;
10172e538c4aSArnaldo Carvalho de Melo 				}
1018ed52ce2eSArnaldo Carvalho de Melo 				curr_map->map_ip = identity__map_ip;
1019ed52ce2eSArnaldo Carvalho de Melo 				curr_map->unmap_ip = identity__map_ip;
10202e538c4aSArnaldo Carvalho de Melo 				curr_dso->origin = DSO__ORIG_KERNEL;
10219de89fe7SArnaldo Carvalho de Melo 				map_groups__insert(kmap->kmaps, curr_map);
1022b0da954aSArnaldo Carvalho de Melo 				dsos__add(&dsos__kernel, curr_dso);
10236275ce2dSArnaldo Carvalho de Melo 				dso__set_loaded(curr_dso, map->type);
10242e538c4aSArnaldo Carvalho de Melo 			} else
10252e538c4aSArnaldo Carvalho de Melo 				curr_dso = curr_map->dso;
10262e538c4aSArnaldo Carvalho de Melo 
10272e538c4aSArnaldo Carvalho de Melo 			goto new_symbol;
10282e538c4aSArnaldo Carvalho de Melo 		}
10292e538c4aSArnaldo Carvalho de Melo 
10302e538c4aSArnaldo Carvalho de Melo 		if (curr_dso->adjust_symbols) {
103129a9f66dSArnaldo Carvalho de Melo 			pr_debug4("%s: adjusting symbol: st_value: %#Lx "
103229a9f66dSArnaldo Carvalho de Melo 				  "sh_addr: %#Lx sh_offset: %#Lx\n", __func__,
103329a9f66dSArnaldo Carvalho de Melo 				  (u64)sym.st_value, (u64)shdr.sh_addr,
103429a9f66dSArnaldo Carvalho de Melo 				  (u64)shdr.sh_offset);
103586470930SIngo Molnar 			sym.st_value -= shdr.sh_addr - shdr.sh_offset;
1036af427bf5SArnaldo Carvalho de Melo 		}
103728ac909bSArnaldo Carvalho de Melo 		/*
103828ac909bSArnaldo Carvalho de Melo 		 * We need to figure out if the object was created from C++ sources
103928ac909bSArnaldo Carvalho de Melo 		 * DWARF DW_compile_unit has this, but we don't always have access
104028ac909bSArnaldo Carvalho de Melo 		 * to it...
104128ac909bSArnaldo Carvalho de Melo 		 */
104283a0944fSIngo Molnar 		demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI);
104328ac909bSArnaldo Carvalho de Melo 		if (demangled != NULL)
104483a0944fSIngo Molnar 			elf_name = demangled;
10452e538c4aSArnaldo Carvalho de Melo new_symbol:
104600a192b3SArnaldo Carvalho de Melo 		f = symbol__new(sym.st_value, sym.st_size, elf_name);
104728ac909bSArnaldo Carvalho de Melo 		free(demangled);
104886470930SIngo Molnar 		if (!f)
104986470930SIngo Molnar 			goto out_elf_end;
105086470930SIngo Molnar 
10512e538c4aSArnaldo Carvalho de Melo 		if (filter && filter(curr_map, f))
105200a192b3SArnaldo Carvalho de Melo 			symbol__delete(f);
105386470930SIngo Molnar 		else {
10546a4694a4SArnaldo Carvalho de Melo 			symbols__insert(&curr_dso->symbols[curr_map->type], f);
105586470930SIngo Molnar 			nr++;
105686470930SIngo Molnar 		}
105786470930SIngo Molnar 	}
105886470930SIngo Molnar 
10592e538c4aSArnaldo Carvalho de Melo 	/*
10602e538c4aSArnaldo Carvalho de Melo 	 * For misannotated, zeroed, ASM function sizes.
10612e538c4aSArnaldo Carvalho de Melo 	 */
10626275ce2dSArnaldo Carvalho de Melo 	if (nr > 0) {
10636a4694a4SArnaldo Carvalho de Melo 		symbols__fixup_end(&self->symbols[map->type]);
10646275ce2dSArnaldo Carvalho de Melo 		if (kmap) {
10656275ce2dSArnaldo Carvalho de Melo 			/*
10666275ce2dSArnaldo Carvalho de Melo 			 * We need to fixup this here too because we create new
10676275ce2dSArnaldo Carvalho de Melo 			 * maps here, for things like vsyscall sections.
10686275ce2dSArnaldo Carvalho de Melo 			 */
10696275ce2dSArnaldo Carvalho de Melo 			__map_groups__fixup_end(kmap->kmaps, map->type);
10706275ce2dSArnaldo Carvalho de Melo 		}
10716275ce2dSArnaldo Carvalho de Melo 	}
107286470930SIngo Molnar 	err = nr;
107386470930SIngo Molnar out_elf_end:
107486470930SIngo Molnar 	elf_end(elf);
107586470930SIngo Molnar out_close:
107686470930SIngo Molnar 	return err;
107786470930SIngo Molnar }
107886470930SIngo Molnar 
107978075caaSArnaldo Carvalho de Melo static bool dso__build_id_equal(const struct dso *self, u8 *build_id)
108078075caaSArnaldo Carvalho de Melo {
108178075caaSArnaldo Carvalho de Melo 	return memcmp(self->build_id, build_id, sizeof(self->build_id)) == 0;
108278075caaSArnaldo Carvalho de Melo }
108378075caaSArnaldo Carvalho de Melo 
10846122e4e4SArnaldo Carvalho de Melo static bool __dsos__read_build_ids(struct list_head *head, bool with_hits)
108557f395a7SFrederic Weisbecker {
1086e30a3d12SArnaldo Carvalho de Melo 	bool have_build_id = false;
108757f395a7SFrederic Weisbecker 	struct dso *pos;
108857f395a7SFrederic Weisbecker 
10896122e4e4SArnaldo Carvalho de Melo 	list_for_each_entry(pos, head, node) {
10906122e4e4SArnaldo Carvalho de Melo 		if (with_hits && !pos->hit)
10916122e4e4SArnaldo Carvalho de Melo 			continue;
1092e30a3d12SArnaldo Carvalho de Melo 		if (filename__read_build_id(pos->long_name, pos->build_id,
1093e30a3d12SArnaldo Carvalho de Melo 					    sizeof(pos->build_id)) > 0) {
1094e30a3d12SArnaldo Carvalho de Melo 			have_build_id	  = true;
1095e30a3d12SArnaldo Carvalho de Melo 			pos->has_build_id = true;
109657f395a7SFrederic Weisbecker 		}
10976122e4e4SArnaldo Carvalho de Melo 	}
109857f395a7SFrederic Weisbecker 
1099e30a3d12SArnaldo Carvalho de Melo 	return have_build_id;
110057f395a7SFrederic Weisbecker }
110157f395a7SFrederic Weisbecker 
11026122e4e4SArnaldo Carvalho de Melo bool dsos__read_build_ids(bool with_hits)
1103b0da954aSArnaldo Carvalho de Melo {
11046122e4e4SArnaldo Carvalho de Melo 	bool kbuildids = __dsos__read_build_ids(&dsos__kernel, with_hits),
11056122e4e4SArnaldo Carvalho de Melo 	     ubuildids = __dsos__read_build_ids(&dsos__user, with_hits);
11068b4825bfSArnaldo Carvalho de Melo 	return kbuildids || ubuildids;
1107b0da954aSArnaldo Carvalho de Melo }
1108b0da954aSArnaldo Carvalho de Melo 
1109fd7a346eSArnaldo Carvalho de Melo /*
1110fd7a346eSArnaldo Carvalho de Melo  * Align offset to 4 bytes as needed for note name and descriptor data.
1111fd7a346eSArnaldo Carvalho de Melo  */
1112fd7a346eSArnaldo Carvalho de Melo #define NOTE_ALIGN(n) (((n) + 3) & -4U)
1113fd7a346eSArnaldo Carvalho de Melo 
11142643ce11SArnaldo Carvalho de Melo int filename__read_build_id(const char *filename, void *bf, size_t size)
11154d1e00a8SArnaldo Carvalho de Melo {
11162643ce11SArnaldo Carvalho de Melo 	int fd, err = -1;
11174d1e00a8SArnaldo Carvalho de Melo 	GElf_Ehdr ehdr;
11184d1e00a8SArnaldo Carvalho de Melo 	GElf_Shdr shdr;
1119fd7a346eSArnaldo Carvalho de Melo 	Elf_Data *data;
11204d1e00a8SArnaldo Carvalho de Melo 	Elf_Scn *sec;
1121e57cfcdaSPekka Enberg 	Elf_Kind ek;
1122fd7a346eSArnaldo Carvalho de Melo 	void *ptr;
11234d1e00a8SArnaldo Carvalho de Melo 	Elf *elf;
11244d1e00a8SArnaldo Carvalho de Melo 
11252643ce11SArnaldo Carvalho de Melo 	if (size < BUILD_ID_SIZE)
11262643ce11SArnaldo Carvalho de Melo 		goto out;
11272643ce11SArnaldo Carvalho de Melo 
11282643ce11SArnaldo Carvalho de Melo 	fd = open(filename, O_RDONLY);
11294d1e00a8SArnaldo Carvalho de Melo 	if (fd < 0)
11304d1e00a8SArnaldo Carvalho de Melo 		goto out;
11314d1e00a8SArnaldo Carvalho de Melo 
113284087126SMarti Raudsepp 	elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
11334d1e00a8SArnaldo Carvalho de Melo 	if (elf == NULL) {
11348d06367fSArnaldo Carvalho de Melo 		pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename);
11354d1e00a8SArnaldo Carvalho de Melo 		goto out_close;
11364d1e00a8SArnaldo Carvalho de Melo 	}
11374d1e00a8SArnaldo Carvalho de Melo 
1138e57cfcdaSPekka Enberg 	ek = elf_kind(elf);
1139e57cfcdaSPekka Enberg 	if (ek != ELF_K_ELF)
1140e57cfcdaSPekka Enberg 		goto out_elf_end;
1141e57cfcdaSPekka Enberg 
11424d1e00a8SArnaldo Carvalho de Melo 	if (gelf_getehdr(elf, &ehdr) == NULL) {
11436beba7adSArnaldo Carvalho de Melo 		pr_err("%s: cannot get elf header.\n", __func__);
11444d1e00a8SArnaldo Carvalho de Melo 		goto out_elf_end;
11454d1e00a8SArnaldo Carvalho de Melo 	}
11464d1e00a8SArnaldo Carvalho de Melo 
11472643ce11SArnaldo Carvalho de Melo 	sec = elf_section_by_name(elf, &ehdr, &shdr,
11482643ce11SArnaldo Carvalho de Melo 				  ".note.gnu.build-id", NULL);
1149fd7a346eSArnaldo Carvalho de Melo 	if (sec == NULL) {
1150fd7a346eSArnaldo Carvalho de Melo 		sec = elf_section_by_name(elf, &ehdr, &shdr,
1151fd7a346eSArnaldo Carvalho de Melo 					  ".notes", NULL);
11524d1e00a8SArnaldo Carvalho de Melo 		if (sec == NULL)
11534d1e00a8SArnaldo Carvalho de Melo 			goto out_elf_end;
1154fd7a346eSArnaldo Carvalho de Melo 	}
11554d1e00a8SArnaldo Carvalho de Melo 
1156fd7a346eSArnaldo Carvalho de Melo 	data = elf_getdata(sec, NULL);
1157fd7a346eSArnaldo Carvalho de Melo 	if (data == NULL)
11584d1e00a8SArnaldo Carvalho de Melo 		goto out_elf_end;
1159fd7a346eSArnaldo Carvalho de Melo 
1160fd7a346eSArnaldo Carvalho de Melo 	ptr = data->d_buf;
1161fd7a346eSArnaldo Carvalho de Melo 	while (ptr < (data->d_buf + data->d_size)) {
1162fd7a346eSArnaldo Carvalho de Melo 		GElf_Nhdr *nhdr = ptr;
1163fd7a346eSArnaldo Carvalho de Melo 		int namesz = NOTE_ALIGN(nhdr->n_namesz),
1164fd7a346eSArnaldo Carvalho de Melo 		    descsz = NOTE_ALIGN(nhdr->n_descsz);
1165fd7a346eSArnaldo Carvalho de Melo 		const char *name;
1166fd7a346eSArnaldo Carvalho de Melo 
1167fd7a346eSArnaldo Carvalho de Melo 		ptr += sizeof(*nhdr);
1168fd7a346eSArnaldo Carvalho de Melo 		name = ptr;
1169fd7a346eSArnaldo Carvalho de Melo 		ptr += namesz;
1170fd7a346eSArnaldo Carvalho de Melo 		if (nhdr->n_type == NT_GNU_BUILD_ID &&
1171fd7a346eSArnaldo Carvalho de Melo 		    nhdr->n_namesz == sizeof("GNU")) {
1172fd7a346eSArnaldo Carvalho de Melo 			if (memcmp(name, "GNU", sizeof("GNU")) == 0) {
1173fd7a346eSArnaldo Carvalho de Melo 				memcpy(bf, ptr, BUILD_ID_SIZE);
11742643ce11SArnaldo Carvalho de Melo 				err = BUILD_ID_SIZE;
1175fd7a346eSArnaldo Carvalho de Melo 				break;
1176fd7a346eSArnaldo Carvalho de Melo 			}
1177fd7a346eSArnaldo Carvalho de Melo 		}
1178fd7a346eSArnaldo Carvalho de Melo 		ptr += descsz;
1179fd7a346eSArnaldo Carvalho de Melo 	}
11802643ce11SArnaldo Carvalho de Melo out_elf_end:
11812643ce11SArnaldo Carvalho de Melo 	elf_end(elf);
11822643ce11SArnaldo Carvalho de Melo out_close:
11832643ce11SArnaldo Carvalho de Melo 	close(fd);
11842643ce11SArnaldo Carvalho de Melo out:
11852643ce11SArnaldo Carvalho de Melo 	return err;
11862643ce11SArnaldo Carvalho de Melo }
11872643ce11SArnaldo Carvalho de Melo 
1188f1617b40SArnaldo Carvalho de Melo int sysfs__read_build_id(const char *filename, void *build_id, size_t size)
1189f1617b40SArnaldo Carvalho de Melo {
1190f1617b40SArnaldo Carvalho de Melo 	int fd, err = -1;
1191f1617b40SArnaldo Carvalho de Melo 
1192f1617b40SArnaldo Carvalho de Melo 	if (size < BUILD_ID_SIZE)
1193f1617b40SArnaldo Carvalho de Melo 		goto out;
1194f1617b40SArnaldo Carvalho de Melo 
1195f1617b40SArnaldo Carvalho de Melo 	fd = open(filename, O_RDONLY);
1196f1617b40SArnaldo Carvalho de Melo 	if (fd < 0)
1197f1617b40SArnaldo Carvalho de Melo 		goto out;
1198f1617b40SArnaldo Carvalho de Melo 
1199f1617b40SArnaldo Carvalho de Melo 	while (1) {
1200f1617b40SArnaldo Carvalho de Melo 		char bf[BUFSIZ];
1201f1617b40SArnaldo Carvalho de Melo 		GElf_Nhdr nhdr;
1202f1617b40SArnaldo Carvalho de Melo 		int namesz, descsz;
1203f1617b40SArnaldo Carvalho de Melo 
1204f1617b40SArnaldo Carvalho de Melo 		if (read(fd, &nhdr, sizeof(nhdr)) != sizeof(nhdr))
1205f1617b40SArnaldo Carvalho de Melo 			break;
1206f1617b40SArnaldo Carvalho de Melo 
1207fd7a346eSArnaldo Carvalho de Melo 		namesz = NOTE_ALIGN(nhdr.n_namesz);
1208fd7a346eSArnaldo Carvalho de Melo 		descsz = NOTE_ALIGN(nhdr.n_descsz);
1209f1617b40SArnaldo Carvalho de Melo 		if (nhdr.n_type == NT_GNU_BUILD_ID &&
1210f1617b40SArnaldo Carvalho de Melo 		    nhdr.n_namesz == sizeof("GNU")) {
1211f1617b40SArnaldo Carvalho de Melo 			if (read(fd, bf, namesz) != namesz)
1212f1617b40SArnaldo Carvalho de Melo 				break;
1213f1617b40SArnaldo Carvalho de Melo 			if (memcmp(bf, "GNU", sizeof("GNU")) == 0) {
1214f1617b40SArnaldo Carvalho de Melo 				if (read(fd, build_id,
1215f1617b40SArnaldo Carvalho de Melo 				    BUILD_ID_SIZE) == BUILD_ID_SIZE) {
1216f1617b40SArnaldo Carvalho de Melo 					err = 0;
1217f1617b40SArnaldo Carvalho de Melo 					break;
1218f1617b40SArnaldo Carvalho de Melo 				}
1219f1617b40SArnaldo Carvalho de Melo 			} else if (read(fd, bf, descsz) != descsz)
1220f1617b40SArnaldo Carvalho de Melo 				break;
1221f1617b40SArnaldo Carvalho de Melo 		} else {
1222f1617b40SArnaldo Carvalho de Melo 			int n = namesz + descsz;
1223f1617b40SArnaldo Carvalho de Melo 			if (read(fd, bf, n) != n)
1224f1617b40SArnaldo Carvalho de Melo 				break;
1225f1617b40SArnaldo Carvalho de Melo 		}
1226f1617b40SArnaldo Carvalho de Melo 	}
1227f1617b40SArnaldo Carvalho de Melo 	close(fd);
1228f1617b40SArnaldo Carvalho de Melo out:
1229f1617b40SArnaldo Carvalho de Melo 	return err;
1230f1617b40SArnaldo Carvalho de Melo }
1231f1617b40SArnaldo Carvalho de Melo 
123294cb9e38SArnaldo Carvalho de Melo char dso__symtab_origin(const struct dso *self)
123394cb9e38SArnaldo Carvalho de Melo {
123494cb9e38SArnaldo Carvalho de Melo 	static const char origin[] = {
123594cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_KERNEL] =   'k',
123694cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_JAVA_JIT] = 'j',
12374cf40131SArnaldo Carvalho de Melo 		[DSO__ORIG_BUILD_ID_CACHE] = 'B',
123894cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_FEDORA] =   'f',
123994cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_UBUNTU] =   'u',
124094cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_BUILDID] =  'b',
124194cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_DSO] =      'd',
1242439d473bSArnaldo Carvalho de Melo 		[DSO__ORIG_KMODULE] =  'K',
124394cb9e38SArnaldo Carvalho de Melo 	};
124494cb9e38SArnaldo Carvalho de Melo 
124594cb9e38SArnaldo Carvalho de Melo 	if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND)
124694cb9e38SArnaldo Carvalho de Melo 		return '!';
124794cb9e38SArnaldo Carvalho de Melo 	return origin[self->origin];
124894cb9e38SArnaldo Carvalho de Melo }
124994cb9e38SArnaldo Carvalho de Melo 
12509de89fe7SArnaldo Carvalho de Melo int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
125186470930SIngo Molnar {
12524d1e00a8SArnaldo Carvalho de Melo 	int size = PATH_MAX;
1253c338aee8SArnaldo Carvalho de Melo 	char *name;
1254d3379ab9SArnaldo Carvalho de Melo 	u8 build_id[BUILD_ID_SIZE];
12554cf40131SArnaldo Carvalho de Melo 	char build_id_hex[BUILD_ID_SIZE * 2 + 1];
125686470930SIngo Molnar 	int ret = -1;
125786470930SIngo Molnar 	int fd;
125886470930SIngo Molnar 
12593610583cSArnaldo Carvalho de Melo 	dso__set_loaded(self, map->type);
126066bd8424SArnaldo Carvalho de Melo 
1261c338aee8SArnaldo Carvalho de Melo 	if (self->kernel)
12629de89fe7SArnaldo Carvalho de Melo 		return dso__load_kernel_sym(self, map, filter);
1263c338aee8SArnaldo Carvalho de Melo 
1264c338aee8SArnaldo Carvalho de Melo 	name = malloc(size);
126586470930SIngo Molnar 	if (!name)
126686470930SIngo Molnar 		return -1;
126786470930SIngo Molnar 
126830d7a77dSArnaldo Carvalho de Melo 	self->adjust_symbols = 0;
1269f5812a7aSArnaldo Carvalho de Melo 
127094cb9e38SArnaldo Carvalho de Melo 	if (strncmp(self->name, "/tmp/perf-", 10) == 0) {
12716beba7adSArnaldo Carvalho de Melo 		ret = dso__load_perf_map(self, map, filter);
127294cb9e38SArnaldo Carvalho de Melo 		self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT :
127394cb9e38SArnaldo Carvalho de Melo 					 DSO__ORIG_NOT_FOUND;
127494cb9e38SArnaldo Carvalho de Melo 		return ret;
127594cb9e38SArnaldo Carvalho de Melo 	}
127694cb9e38SArnaldo Carvalho de Melo 
12774cf40131SArnaldo Carvalho de Melo 	self->origin = DSO__ORIG_BUILD_ID_CACHE;
127880d496beSPekka Enberg 
12794cf40131SArnaldo Carvalho de Melo 	if (self->has_build_id) {
12804cf40131SArnaldo Carvalho de Melo 		build_id__sprintf(self->build_id, sizeof(self->build_id),
12814cf40131SArnaldo Carvalho de Melo 				  build_id_hex);
12824cf40131SArnaldo Carvalho de Melo 		snprintf(name, size, "%s/%s/.build-id/%.2s/%s",
12834cf40131SArnaldo Carvalho de Melo 			 getenv("HOME"), DEBUG_CACHE_DIR,
12844cf40131SArnaldo Carvalho de Melo 			 build_id_hex, build_id_hex + 2);
12854cf40131SArnaldo Carvalho de Melo 		goto open_file;
12864cf40131SArnaldo Carvalho de Melo 	}
128786470930SIngo Molnar more:
128886470930SIngo Molnar 	do {
128994cb9e38SArnaldo Carvalho de Melo 		self->origin++;
129094cb9e38SArnaldo Carvalho de Melo 		switch (self->origin) {
129194cb9e38SArnaldo Carvalho de Melo 		case DSO__ORIG_FEDORA:
1292439d473bSArnaldo Carvalho de Melo 			snprintf(name, size, "/usr/lib/debug%s.debug",
1293439d473bSArnaldo Carvalho de Melo 				 self->long_name);
129486470930SIngo Molnar 			break;
129594cb9e38SArnaldo Carvalho de Melo 		case DSO__ORIG_UBUNTU:
1296439d473bSArnaldo Carvalho de Melo 			snprintf(name, size, "/usr/lib/debug%s",
1297439d473bSArnaldo Carvalho de Melo 				 self->long_name);
129886470930SIngo Molnar 			break;
129994cb9e38SArnaldo Carvalho de Melo 		case DSO__ORIG_BUILDID:
1300d3379ab9SArnaldo Carvalho de Melo 			if (filename__read_build_id(self->long_name, build_id,
1301d3379ab9SArnaldo Carvalho de Melo 						    sizeof(build_id))) {
1302d3379ab9SArnaldo Carvalho de Melo 				build_id__sprintf(build_id, sizeof(build_id),
1303d3379ab9SArnaldo Carvalho de Melo 						  build_id_hex);
13044d1e00a8SArnaldo Carvalho de Melo 				snprintf(name, size,
13054d1e00a8SArnaldo Carvalho de Melo 					 "/usr/lib/debug/.build-id/%.2s/%s.debug",
1306d3379ab9SArnaldo Carvalho de Melo 					build_id_hex, build_id_hex + 2);
1307d3379ab9SArnaldo Carvalho de Melo 				if (self->has_build_id)
13088d06367fSArnaldo Carvalho de Melo 					goto compare_build_id;
1309d3379ab9SArnaldo Carvalho de Melo 				break;
13104d1e00a8SArnaldo Carvalho de Melo 			}
131194cb9e38SArnaldo Carvalho de Melo 			self->origin++;
13124d1e00a8SArnaldo Carvalho de Melo 			/* Fall thru */
131394cb9e38SArnaldo Carvalho de Melo 		case DSO__ORIG_DSO:
1314439d473bSArnaldo Carvalho de Melo 			snprintf(name, size, "%s", self->long_name);
131586470930SIngo Molnar 			break;
131686470930SIngo Molnar 
131786470930SIngo Molnar 		default:
131886470930SIngo Molnar 			goto out;
131986470930SIngo Molnar 		}
132086470930SIngo Molnar 
13218d06367fSArnaldo Carvalho de Melo 		if (self->has_build_id) {
1322d3379ab9SArnaldo Carvalho de Melo 			if (filename__read_build_id(name, build_id,
1323d3379ab9SArnaldo Carvalho de Melo 						    sizeof(build_id)) < 0)
13248d06367fSArnaldo Carvalho de Melo 				goto more;
13258d06367fSArnaldo Carvalho de Melo compare_build_id:
132678075caaSArnaldo Carvalho de Melo 			if (!dso__build_id_equal(self, build_id))
13278d06367fSArnaldo Carvalho de Melo 				goto more;
13288d06367fSArnaldo Carvalho de Melo 		}
13294cf40131SArnaldo Carvalho de Melo open_file:
133086470930SIngo Molnar 		fd = open(name, O_RDONLY);
133186470930SIngo Molnar 	} while (fd < 0);
133286470930SIngo Molnar 
13339de89fe7SArnaldo Carvalho de Melo 	ret = dso__load_sym(self, map, name, fd, filter, 0);
133486470930SIngo Molnar 	close(fd);
133586470930SIngo Molnar 
133686470930SIngo Molnar 	/*
133786470930SIngo Molnar 	 * Some people seem to have debuginfo files _WITHOUT_ debug info!?!?
133886470930SIngo Molnar 	 */
133986470930SIngo Molnar 	if (!ret)
134086470930SIngo Molnar 		goto more;
134186470930SIngo Molnar 
1342a25e46c4SArnaldo Carvalho de Melo 	if (ret > 0) {
134382164161SArnaldo Carvalho de Melo 		int nr_plt = dso__synthesize_plt_symbols(self, map, filter);
1344a25e46c4SArnaldo Carvalho de Melo 		if (nr_plt > 0)
1345a25e46c4SArnaldo Carvalho de Melo 			ret += nr_plt;
1346a25e46c4SArnaldo Carvalho de Melo 	}
134786470930SIngo Molnar out:
134886470930SIngo Molnar 	free(name);
13491340e6bbSArnaldo Carvalho de Melo 	if (ret < 0 && strstr(self->name, " (deleted)") != NULL)
13501340e6bbSArnaldo Carvalho de Melo 		return 0;
135186470930SIngo Molnar 	return ret;
135286470930SIngo Molnar }
135386470930SIngo Molnar 
135479406cd7SArnaldo Carvalho de Melo struct map *map_groups__find_by_name(struct map_groups *self,
135579406cd7SArnaldo Carvalho de Melo 				     enum map_type type, const char *name)
1356439d473bSArnaldo Carvalho de Melo {
1357439d473bSArnaldo Carvalho de Melo 	struct rb_node *nd;
1358439d473bSArnaldo Carvalho de Melo 
135979406cd7SArnaldo Carvalho de Melo 	for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) {
1360439d473bSArnaldo Carvalho de Melo 		struct map *map = rb_entry(nd, struct map, rb_node);
1361439d473bSArnaldo Carvalho de Melo 
1362b7cece76SArnaldo Carvalho de Melo 		if (map->dso && strcmp(map->dso->short_name, name) == 0)
1363439d473bSArnaldo Carvalho de Melo 			return map;
1364439d473bSArnaldo Carvalho de Melo 	}
1365439d473bSArnaldo Carvalho de Melo 
1366439d473bSArnaldo Carvalho de Melo 	return NULL;
1367439d473bSArnaldo Carvalho de Melo }
1368439d473bSArnaldo Carvalho de Melo 
1369b7cece76SArnaldo Carvalho de Melo static int dso__kernel_module_get_build_id(struct dso *self)
1370b7cece76SArnaldo Carvalho de Melo {
1371b7cece76SArnaldo Carvalho de Melo 	char filename[PATH_MAX];
1372b7cece76SArnaldo Carvalho de Melo 	/*
1373b7cece76SArnaldo Carvalho de Melo 	 * kernel module short names are of the form "[module]" and
1374b7cece76SArnaldo Carvalho de Melo 	 * we need just "module" here.
1375b7cece76SArnaldo Carvalho de Melo 	 */
1376b7cece76SArnaldo Carvalho de Melo 	const char *name = self->short_name + 1;
1377b7cece76SArnaldo Carvalho de Melo 
1378b7cece76SArnaldo Carvalho de Melo 	snprintf(filename, sizeof(filename),
1379b7cece76SArnaldo Carvalho de Melo 		 "/sys/module/%.*s/notes/.note.gnu.build-id",
1380b7cece76SArnaldo Carvalho de Melo 		 (int)strlen(name - 1), name);
1381b7cece76SArnaldo Carvalho de Melo 
1382b7cece76SArnaldo Carvalho de Melo 	if (sysfs__read_build_id(filename, self->build_id,
1383b7cece76SArnaldo Carvalho de Melo 				 sizeof(self->build_id)) == 0)
1384b7cece76SArnaldo Carvalho de Melo 		self->has_build_id = true;
1385b7cece76SArnaldo Carvalho de Melo 
1386b7cece76SArnaldo Carvalho de Melo 	return 0;
1387b7cece76SArnaldo Carvalho de Melo }
1388b7cece76SArnaldo Carvalho de Melo 
13899de89fe7SArnaldo Carvalho de Melo static int map_groups__set_modules_path_dir(struct map_groups *self, char *dirname)
13906cfcc53eSMike Galbraith {
1391439d473bSArnaldo Carvalho de Melo 	struct dirent *dent;
1392439d473bSArnaldo Carvalho de Melo 	DIR *dir = opendir(dirname);
13936cfcc53eSMike Galbraith 
1394439d473bSArnaldo Carvalho de Melo 	if (!dir) {
139587f8ea4cSArnaldo Carvalho de Melo 		pr_debug("%s: cannot open %s dir\n", __func__, dirname);
1396439d473bSArnaldo Carvalho de Melo 		return -1;
1397439d473bSArnaldo Carvalho de Melo 	}
13986cfcc53eSMike Galbraith 
1399439d473bSArnaldo Carvalho de Melo 	while ((dent = readdir(dir)) != NULL) {
1400439d473bSArnaldo Carvalho de Melo 		char path[PATH_MAX];
1401439d473bSArnaldo Carvalho de Melo 
1402439d473bSArnaldo Carvalho de Melo 		if (dent->d_type == DT_DIR) {
1403439d473bSArnaldo Carvalho de Melo 			if (!strcmp(dent->d_name, ".") ||
1404439d473bSArnaldo Carvalho de Melo 			    !strcmp(dent->d_name, ".."))
1405439d473bSArnaldo Carvalho de Melo 				continue;
1406439d473bSArnaldo Carvalho de Melo 
1407439d473bSArnaldo Carvalho de Melo 			snprintf(path, sizeof(path), "%s/%s",
1408439d473bSArnaldo Carvalho de Melo 				 dirname, dent->d_name);
14099de89fe7SArnaldo Carvalho de Melo 			if (map_groups__set_modules_path_dir(self, path) < 0)
1410439d473bSArnaldo Carvalho de Melo 				goto failure;
1411439d473bSArnaldo Carvalho de Melo 		} else {
1412439d473bSArnaldo Carvalho de Melo 			char *dot = strrchr(dent->d_name, '.'),
1413439d473bSArnaldo Carvalho de Melo 			     dso_name[PATH_MAX];
1414439d473bSArnaldo Carvalho de Melo 			struct map *map;
1415cfc10d3bSArnaldo Carvalho de Melo 			char *long_name;
1416439d473bSArnaldo Carvalho de Melo 
1417439d473bSArnaldo Carvalho de Melo 			if (dot == NULL || strcmp(dot, ".ko"))
1418439d473bSArnaldo Carvalho de Melo 				continue;
1419439d473bSArnaldo Carvalho de Melo 			snprintf(dso_name, sizeof(dso_name), "[%.*s]",
1420439d473bSArnaldo Carvalho de Melo 				 (int)(dot - dent->d_name), dent->d_name);
1421439d473bSArnaldo Carvalho de Melo 
1422a2a99e8eSArnaldo Carvalho de Melo 			strxfrchar(dso_name, '-', '_');
14239de89fe7SArnaldo Carvalho de Melo 			map = map_groups__find_by_name(self, MAP__FUNCTION, dso_name);
1424439d473bSArnaldo Carvalho de Melo 			if (map == NULL)
1425439d473bSArnaldo Carvalho de Melo 				continue;
1426439d473bSArnaldo Carvalho de Melo 
1427439d473bSArnaldo Carvalho de Melo 			snprintf(path, sizeof(path), "%s/%s",
1428439d473bSArnaldo Carvalho de Melo 				 dirname, dent->d_name);
1429439d473bSArnaldo Carvalho de Melo 
1430cfc10d3bSArnaldo Carvalho de Melo 			long_name = strdup(path);
1431cfc10d3bSArnaldo Carvalho de Melo 			if (long_name == NULL)
1432439d473bSArnaldo Carvalho de Melo 				goto failure;
1433cfc10d3bSArnaldo Carvalho de Melo 			dso__set_long_name(map->dso, long_name);
1434b7cece76SArnaldo Carvalho de Melo 			dso__kernel_module_get_build_id(map->dso);
1435439d473bSArnaldo Carvalho de Melo 		}
1436439d473bSArnaldo Carvalho de Melo 	}
1437439d473bSArnaldo Carvalho de Melo 
1438c338aee8SArnaldo Carvalho de Melo 	return 0;
1439439d473bSArnaldo Carvalho de Melo failure:
1440439d473bSArnaldo Carvalho de Melo 	closedir(dir);
1441439d473bSArnaldo Carvalho de Melo 	return -1;
1442439d473bSArnaldo Carvalho de Melo }
1443439d473bSArnaldo Carvalho de Melo 
14449de89fe7SArnaldo Carvalho de Melo static int map_groups__set_modules_path(struct map_groups *self)
1445439d473bSArnaldo Carvalho de Melo {
1446439d473bSArnaldo Carvalho de Melo 	struct utsname uts;
1447439d473bSArnaldo Carvalho de Melo 	char modules_path[PATH_MAX];
1448439d473bSArnaldo Carvalho de Melo 
1449439d473bSArnaldo Carvalho de Melo 	if (uname(&uts) < 0)
1450439d473bSArnaldo Carvalho de Melo 		return -1;
1451439d473bSArnaldo Carvalho de Melo 
1452439d473bSArnaldo Carvalho de Melo 	snprintf(modules_path, sizeof(modules_path), "/lib/modules/%s/kernel",
1453439d473bSArnaldo Carvalho de Melo 		 uts.release);
1454439d473bSArnaldo Carvalho de Melo 
14559de89fe7SArnaldo Carvalho de Melo 	return map_groups__set_modules_path_dir(self, modules_path);
1456439d473bSArnaldo Carvalho de Melo }
14576cfcc53eSMike Galbraith 
14586cfcc53eSMike Galbraith /*
1459439d473bSArnaldo Carvalho de Melo  * Constructor variant for modules (where we know from /proc/modules where
1460439d473bSArnaldo Carvalho de Melo  * they are loaded) and for vmlinux, where only after we load all the
1461439d473bSArnaldo Carvalho de Melo  * symbols we'll know where it starts and ends.
14626cfcc53eSMike Galbraith  */
14633610583cSArnaldo Carvalho de Melo static struct map *map__new2(u64 start, struct dso *dso, enum map_type type)
1464439d473bSArnaldo Carvalho de Melo {
14659de89fe7SArnaldo Carvalho de Melo 	struct map *self = zalloc(sizeof(*self) +
14669de89fe7SArnaldo Carvalho de Melo 				  (dso->kernel ? sizeof(struct kmap) : 0));
1467439d473bSArnaldo Carvalho de Melo 	if (self != NULL) {
1468439d473bSArnaldo Carvalho de Melo 		/*
1469afb7b4f0SArnaldo Carvalho de Melo 		 * ->end will be filled after we load all the symbols
1470439d473bSArnaldo Carvalho de Melo 		 */
14713610583cSArnaldo Carvalho de Melo 		map__init(self, type, start, 0, 0, dso);
1472439d473bSArnaldo Carvalho de Melo 	}
1473afb7b4f0SArnaldo Carvalho de Melo 
1474439d473bSArnaldo Carvalho de Melo 	return self;
1475439d473bSArnaldo Carvalho de Melo }
1476439d473bSArnaldo Carvalho de Melo 
14779de89fe7SArnaldo Carvalho de Melo struct map *map_groups__new_module(struct map_groups *self, u64 start,
1478b7cece76SArnaldo Carvalho de Melo 				   const char *filename)
1479b7cece76SArnaldo Carvalho de Melo {
1480b7cece76SArnaldo Carvalho de Melo 	struct map *map;
1481b7cece76SArnaldo Carvalho de Melo 	struct dso *dso = __dsos__findnew(&dsos__kernel, filename);
1482b7cece76SArnaldo Carvalho de Melo 
1483b7cece76SArnaldo Carvalho de Melo 	if (dso == NULL)
1484b7cece76SArnaldo Carvalho de Melo 		return NULL;
1485b7cece76SArnaldo Carvalho de Melo 
1486b7cece76SArnaldo Carvalho de Melo 	map = map__new2(start, dso, MAP__FUNCTION);
1487b7cece76SArnaldo Carvalho de Melo 	if (map == NULL)
1488b7cece76SArnaldo Carvalho de Melo 		return NULL;
1489b7cece76SArnaldo Carvalho de Melo 
1490b7cece76SArnaldo Carvalho de Melo 	dso->origin = DSO__ORIG_KMODULE;
14919de89fe7SArnaldo Carvalho de Melo 	map_groups__insert(self, map);
1492b7cece76SArnaldo Carvalho de Melo 	return map;
1493b7cece76SArnaldo Carvalho de Melo }
1494b7cece76SArnaldo Carvalho de Melo 
14959de89fe7SArnaldo Carvalho de Melo static int map_groups__create_modules(struct map_groups *self)
1496439d473bSArnaldo Carvalho de Melo {
1497439d473bSArnaldo Carvalho de Melo 	char *line = NULL;
1498439d473bSArnaldo Carvalho de Melo 	size_t n;
1499439d473bSArnaldo Carvalho de Melo 	FILE *file = fopen("/proc/modules", "r");
1500439d473bSArnaldo Carvalho de Melo 	struct map *map;
1501439d473bSArnaldo Carvalho de Melo 
1502439d473bSArnaldo Carvalho de Melo 	if (file == NULL)
1503439d473bSArnaldo Carvalho de Melo 		return -1;
1504439d473bSArnaldo Carvalho de Melo 
1505439d473bSArnaldo Carvalho de Melo 	while (!feof(file)) {
1506439d473bSArnaldo Carvalho de Melo 		char name[PATH_MAX];
1507439d473bSArnaldo Carvalho de Melo 		u64 start;
1508439d473bSArnaldo Carvalho de Melo 		char *sep;
1509439d473bSArnaldo Carvalho de Melo 		int line_len;
1510439d473bSArnaldo Carvalho de Melo 
1511439d473bSArnaldo Carvalho de Melo 		line_len = getline(&line, &n, file);
1512439d473bSArnaldo Carvalho de Melo 		if (line_len < 0)
15136cfcc53eSMike Galbraith 			break;
15146cfcc53eSMike Galbraith 
1515439d473bSArnaldo Carvalho de Melo 		if (!line)
1516439d473bSArnaldo Carvalho de Melo 			goto out_failure;
1517439d473bSArnaldo Carvalho de Melo 
1518439d473bSArnaldo Carvalho de Melo 		line[--line_len] = '\0'; /* \n */
1519439d473bSArnaldo Carvalho de Melo 
1520439d473bSArnaldo Carvalho de Melo 		sep = strrchr(line, 'x');
1521439d473bSArnaldo Carvalho de Melo 		if (sep == NULL)
1522439d473bSArnaldo Carvalho de Melo 			continue;
1523439d473bSArnaldo Carvalho de Melo 
1524439d473bSArnaldo Carvalho de Melo 		hex2u64(sep + 1, &start);
1525439d473bSArnaldo Carvalho de Melo 
1526439d473bSArnaldo Carvalho de Melo 		sep = strchr(line, ' ');
1527439d473bSArnaldo Carvalho de Melo 		if (sep == NULL)
1528439d473bSArnaldo Carvalho de Melo 			continue;
1529439d473bSArnaldo Carvalho de Melo 
1530439d473bSArnaldo Carvalho de Melo 		*sep = '\0';
1531439d473bSArnaldo Carvalho de Melo 
1532439d473bSArnaldo Carvalho de Melo 		snprintf(name, sizeof(name), "[%s]", line);
15339de89fe7SArnaldo Carvalho de Melo 		map = map_groups__new_module(self, start, name);
1534b7cece76SArnaldo Carvalho de Melo 		if (map == NULL)
1535439d473bSArnaldo Carvalho de Melo 			goto out_delete_line;
1536b7cece76SArnaldo Carvalho de Melo 		dso__kernel_module_get_build_id(map->dso);
15376cfcc53eSMike Galbraith 	}
15386cfcc53eSMike Galbraith 
1539439d473bSArnaldo Carvalho de Melo 	free(line);
1540439d473bSArnaldo Carvalho de Melo 	fclose(file);
1541439d473bSArnaldo Carvalho de Melo 
15429de89fe7SArnaldo Carvalho de Melo 	return map_groups__set_modules_path(self);
1543439d473bSArnaldo Carvalho de Melo 
1544439d473bSArnaldo Carvalho de Melo out_delete_line:
1545439d473bSArnaldo Carvalho de Melo 	free(line);
1546439d473bSArnaldo Carvalho de Melo out_failure:
1547439d473bSArnaldo Carvalho de Melo 	return -1;
15486cfcc53eSMike Galbraith }
15496cfcc53eSMike Galbraith 
15509958e1f0SArnaldo Carvalho de Melo static int dso__load_vmlinux(struct dso *self, struct map *map,
15516beba7adSArnaldo Carvalho de Melo 			     const char *vmlinux, symbol_filter_t filter)
155286470930SIngo Molnar {
1553fbd733b8SArnaldo Carvalho de Melo 	int err = -1, fd;
155486470930SIngo Molnar 
1555fbd733b8SArnaldo Carvalho de Melo 	if (self->has_build_id) {
1556fbd733b8SArnaldo Carvalho de Melo 		u8 build_id[BUILD_ID_SIZE];
155766bd8424SArnaldo Carvalho de Melo 
1558fbd733b8SArnaldo Carvalho de Melo 		if (filename__read_build_id(vmlinux, build_id,
1559fbd733b8SArnaldo Carvalho de Melo 					    sizeof(build_id)) < 0) {
1560fbd733b8SArnaldo Carvalho de Melo 			pr_debug("No build_id in %s, ignoring it\n", vmlinux);
1561fbd733b8SArnaldo Carvalho de Melo 			return -1;
1562fbd733b8SArnaldo Carvalho de Melo 		}
1563fbd733b8SArnaldo Carvalho de Melo 		if (!dso__build_id_equal(self, build_id)) {
1564fbd733b8SArnaldo Carvalho de Melo 			char expected_build_id[BUILD_ID_SIZE * 2 + 1],
1565fbd733b8SArnaldo Carvalho de Melo 			     vmlinux_build_id[BUILD_ID_SIZE * 2 + 1];
1566fbd733b8SArnaldo Carvalho de Melo 
1567fbd733b8SArnaldo Carvalho de Melo 			build_id__sprintf(self->build_id,
1568fbd733b8SArnaldo Carvalho de Melo 					  sizeof(self->build_id),
1569fbd733b8SArnaldo Carvalho de Melo 					  expected_build_id);
1570fbd733b8SArnaldo Carvalho de Melo 			build_id__sprintf(build_id, sizeof(build_id),
1571fbd733b8SArnaldo Carvalho de Melo 					  vmlinux_build_id);
1572fbd733b8SArnaldo Carvalho de Melo 			pr_debug("build_id in %s is %s while expected is %s, "
1573fbd733b8SArnaldo Carvalho de Melo 				 "ignoring it\n", vmlinux, vmlinux_build_id,
1574fbd733b8SArnaldo Carvalho de Melo 				 expected_build_id);
1575fbd733b8SArnaldo Carvalho de Melo 			return -1;
1576fbd733b8SArnaldo Carvalho de Melo 		}
1577fbd733b8SArnaldo Carvalho de Melo 	}
1578fbd733b8SArnaldo Carvalho de Melo 
1579fbd733b8SArnaldo Carvalho de Melo 	fd = open(vmlinux, O_RDONLY);
158086470930SIngo Molnar 	if (fd < 0)
158186470930SIngo Molnar 		return -1;
158286470930SIngo Molnar 
15833610583cSArnaldo Carvalho de Melo 	dso__set_loaded(self, map->type);
15849de89fe7SArnaldo Carvalho de Melo 	err = dso__load_sym(self, map, vmlinux, fd, filter, 0);
158586470930SIngo Molnar 	close(fd);
158686470930SIngo Molnar 
15873846df2eSArnaldo Carvalho de Melo 	if (err > 0)
15883846df2eSArnaldo Carvalho de Melo 		pr_debug("Using %s for symbols\n", vmlinux);
15893846df2eSArnaldo Carvalho de Melo 
159086470930SIngo Molnar 	return err;
159186470930SIngo Molnar }
159286470930SIngo Molnar 
1593a19afe46SArnaldo Carvalho de Melo int dso__load_vmlinux_path(struct dso *self, struct map *map,
15949de89fe7SArnaldo Carvalho de Melo 			   symbol_filter_t filter)
1595a19afe46SArnaldo Carvalho de Melo {
1596a19afe46SArnaldo Carvalho de Melo 	int i, err = 0;
1597a19afe46SArnaldo Carvalho de Melo 
1598a19afe46SArnaldo Carvalho de Melo 	pr_debug("Looking at the vmlinux_path (%d entries long)\n",
1599a19afe46SArnaldo Carvalho de Melo 		 vmlinux_path__nr_entries);
1600a19afe46SArnaldo Carvalho de Melo 
1601a19afe46SArnaldo Carvalho de Melo 	for (i = 0; i < vmlinux_path__nr_entries; ++i) {
16029de89fe7SArnaldo Carvalho de Melo 		err = dso__load_vmlinux(self, map, vmlinux_path[i], filter);
1603a19afe46SArnaldo Carvalho de Melo 		if (err > 0) {
1604a19afe46SArnaldo Carvalho de Melo 			dso__set_long_name(self, strdup(vmlinux_path[i]));
1605a19afe46SArnaldo Carvalho de Melo 			break;
1606a19afe46SArnaldo Carvalho de Melo 		}
1607a19afe46SArnaldo Carvalho de Melo 	}
1608a19afe46SArnaldo Carvalho de Melo 
1609a19afe46SArnaldo Carvalho de Melo 	return err;
1610a19afe46SArnaldo Carvalho de Melo }
1611a19afe46SArnaldo Carvalho de Melo 
1612c338aee8SArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *self, struct map *map,
16139de89fe7SArnaldo Carvalho de Melo 				symbol_filter_t filter)
161486470930SIngo Molnar {
1615cc612d81SArnaldo Carvalho de Melo 	int err;
16169e201442SArnaldo Carvalho de Melo 	const char *kallsyms_filename = NULL;
16179e201442SArnaldo Carvalho de Melo 	char *kallsyms_allocated_filename = NULL;
1618dc8d6ab2SArnaldo Carvalho de Melo 	/*
1619dc8d6ab2SArnaldo Carvalho de Melo 	 * Step 1: if the user specified a vmlinux filename, use it and only
1620dc8d6ab2SArnaldo Carvalho de Melo 	 * it, reporting errors to the user if it cannot be used.
1621dc8d6ab2SArnaldo Carvalho de Melo 	 *
1622dc8d6ab2SArnaldo Carvalho de Melo 	 * For instance, try to analyse an ARM perf.data file _without_ a
1623dc8d6ab2SArnaldo Carvalho de Melo 	 * build-id, or if the user specifies the wrong path to the right
1624dc8d6ab2SArnaldo Carvalho de Melo 	 * vmlinux file, obviously we can't fallback to another vmlinux (a
1625dc8d6ab2SArnaldo Carvalho de Melo 	 * x86_86 one, on the machine where analysis is being performed, say),
1626dc8d6ab2SArnaldo Carvalho de Melo 	 * or worse, /proc/kallsyms.
1627dc8d6ab2SArnaldo Carvalho de Melo 	 *
1628dc8d6ab2SArnaldo Carvalho de Melo 	 * If the specified file _has_ a build-id and there is a build-id
1629dc8d6ab2SArnaldo Carvalho de Melo 	 * section in the perf.data file, we will still do the expected
1630dc8d6ab2SArnaldo Carvalho de Melo 	 * validation in dso__load_vmlinux and will bail out if they don't
1631dc8d6ab2SArnaldo Carvalho de Melo 	 * match.
1632dc8d6ab2SArnaldo Carvalho de Melo 	 */
1633dc8d6ab2SArnaldo Carvalho de Melo 	if (symbol_conf.vmlinux_name != NULL) {
16349de89fe7SArnaldo Carvalho de Melo 		err = dso__load_vmlinux(self, map,
1635dc8d6ab2SArnaldo Carvalho de Melo 					symbol_conf.vmlinux_name, filter);
1636dc8d6ab2SArnaldo Carvalho de Melo 		goto out_try_fixup;
1637dc8d6ab2SArnaldo Carvalho de Melo 	}
1638439d473bSArnaldo Carvalho de Melo 
1639cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path != NULL) {
16409de89fe7SArnaldo Carvalho de Melo 		err = dso__load_vmlinux_path(self, map, filter);
1641a19afe46SArnaldo Carvalho de Melo 		if (err > 0)
1642cc612d81SArnaldo Carvalho de Melo 			goto out_fixup;
1643cc612d81SArnaldo Carvalho de Melo 	}
1644cc612d81SArnaldo Carvalho de Melo 
1645b7cece76SArnaldo Carvalho de Melo 	/*
1646b7cece76SArnaldo Carvalho de Melo 	 * Say the kernel DSO was created when processing the build-id header table,
1647b7cece76SArnaldo Carvalho de Melo 	 * we have a build-id, so check if it is the same as the running kernel,
1648b7cece76SArnaldo Carvalho de Melo 	 * using it if it is.
1649b7cece76SArnaldo Carvalho de Melo 	 */
1650b7cece76SArnaldo Carvalho de Melo 	if (self->has_build_id) {
1651b7cece76SArnaldo Carvalho de Melo 		u8 kallsyms_build_id[BUILD_ID_SIZE];
16529e201442SArnaldo Carvalho de Melo 		char sbuild_id[BUILD_ID_SIZE * 2 + 1];
1653b7cece76SArnaldo Carvalho de Melo 
1654b7cece76SArnaldo Carvalho de Melo 		if (sysfs__read_build_id("/sys/kernel/notes", kallsyms_build_id,
16558d0591f6SArnaldo Carvalho de Melo 					 sizeof(kallsyms_build_id)) == 0) {
16569e201442SArnaldo Carvalho de Melo 			if (dso__build_id_equal(self, kallsyms_build_id)) {
16579e201442SArnaldo Carvalho de Melo 				kallsyms_filename = "/proc/kallsyms";
1658b7cece76SArnaldo Carvalho de Melo 				goto do_kallsyms;
16598d0591f6SArnaldo Carvalho de Melo 			}
16609e201442SArnaldo Carvalho de Melo 		}
1661dc8d6ab2SArnaldo Carvalho de Melo 		/*
1662dc8d6ab2SArnaldo Carvalho de Melo 		 * Now look if we have it on the build-id cache in
1663dc8d6ab2SArnaldo Carvalho de Melo 		 * $HOME/.debug/[kernel.kallsyms].
1664dc8d6ab2SArnaldo Carvalho de Melo 		 */
16659e201442SArnaldo Carvalho de Melo 		build_id__sprintf(self->build_id, sizeof(self->build_id),
16669e201442SArnaldo Carvalho de Melo 				  sbuild_id);
16679e201442SArnaldo Carvalho de Melo 
16689e201442SArnaldo Carvalho de Melo 		if (asprintf(&kallsyms_allocated_filename,
16699e201442SArnaldo Carvalho de Melo 			     "%s/.debug/[kernel.kallsyms]/%s",
16703846df2eSArnaldo Carvalho de Melo 			     getenv("HOME"), sbuild_id) == -1) {
16713846df2eSArnaldo Carvalho de Melo 			pr_err("Not enough memory for kallsyms file lookup\n");
16728d0591f6SArnaldo Carvalho de Melo 			return -1;
16733846df2eSArnaldo Carvalho de Melo 		}
16748d0591f6SArnaldo Carvalho de Melo 
167519fc2dedSArnaldo Carvalho de Melo 		kallsyms_filename = kallsyms_allocated_filename;
167619fc2dedSArnaldo Carvalho de Melo 
1677dc8d6ab2SArnaldo Carvalho de Melo 		if (access(kallsyms_filename, F_OK)) {
16783846df2eSArnaldo Carvalho de Melo 			pr_err("No kallsyms or vmlinux with build-id %s "
16793846df2eSArnaldo Carvalho de Melo 			       "was found\n", sbuild_id);
16809e201442SArnaldo Carvalho de Melo 			free(kallsyms_allocated_filename);
1681dc8d6ab2SArnaldo Carvalho de Melo 			return -1;
1682ef6ae724SArnaldo Carvalho de Melo 		}
1683dc8d6ab2SArnaldo Carvalho de Melo 	} else {
1684dc8d6ab2SArnaldo Carvalho de Melo 		/*
1685dc8d6ab2SArnaldo Carvalho de Melo 		 * Last resort, if we don't have a build-id and couldn't find
1686dc8d6ab2SArnaldo Carvalho de Melo 		 * any vmlinux file, try the running kernel kallsyms table.
1687dc8d6ab2SArnaldo Carvalho de Melo 		 */
1688dc8d6ab2SArnaldo Carvalho de Melo 		kallsyms_filename = "/proc/kallsyms";
1689dc8d6ab2SArnaldo Carvalho de Melo 	}
1690dc8d6ab2SArnaldo Carvalho de Melo 
1691dc8d6ab2SArnaldo Carvalho de Melo do_kallsyms:
16929de89fe7SArnaldo Carvalho de Melo 	err = dso__load_kallsyms(self, kallsyms_filename, map, filter);
16933846df2eSArnaldo Carvalho de Melo 	if (err > 0)
16943846df2eSArnaldo Carvalho de Melo 		pr_debug("Using %s for symbols\n", kallsyms_filename);
1695dc8d6ab2SArnaldo Carvalho de Melo 	free(kallsyms_allocated_filename);
1696dc8d6ab2SArnaldo Carvalho de Melo 
1697dc8d6ab2SArnaldo Carvalho de Melo out_try_fixup:
1698439d473bSArnaldo Carvalho de Melo 	if (err > 0) {
1699cc612d81SArnaldo Carvalho de Melo out_fixup:
1700e1c7c6a4SArnaldo Carvalho de Melo 		if (kallsyms_filename != NULL)
1701dc8d6ab2SArnaldo Carvalho de Melo 			dso__set_long_name(self, strdup("[kernel.kallsyms]"));
17026a4694a4SArnaldo Carvalho de Melo 		map__fixup_start(map);
17036a4694a4SArnaldo Carvalho de Melo 		map__fixup_end(map);
1704439d473bSArnaldo Carvalho de Melo 	}
170594cb9e38SArnaldo Carvalho de Melo 
170686470930SIngo Molnar 	return err;
170786470930SIngo Molnar }
170886470930SIngo Molnar 
1709b0da954aSArnaldo Carvalho de Melo LIST_HEAD(dsos__user);
1710b0da954aSArnaldo Carvalho de Melo LIST_HEAD(dsos__kernel);
1711cd84c2acSFrederic Weisbecker 
1712b0da954aSArnaldo Carvalho de Melo static void dsos__add(struct list_head *head, struct dso *dso)
1713cd84c2acSFrederic Weisbecker {
1714b0da954aSArnaldo Carvalho de Melo 	list_add_tail(&dso->node, head);
1715cd84c2acSFrederic Weisbecker }
1716cd84c2acSFrederic Weisbecker 
1717b0da954aSArnaldo Carvalho de Melo static struct dso *dsos__find(struct list_head *head, const char *name)
1718cd84c2acSFrederic Weisbecker {
1719cd84c2acSFrederic Weisbecker 	struct dso *pos;
1720cd84c2acSFrederic Weisbecker 
1721b0da954aSArnaldo Carvalho de Melo 	list_for_each_entry(pos, head, node)
1722cf4e5b08SArnaldo Carvalho de Melo 		if (strcmp(pos->long_name, name) == 0)
1723cd84c2acSFrederic Weisbecker 			return pos;
1724cd84c2acSFrederic Weisbecker 	return NULL;
1725cd84c2acSFrederic Weisbecker }
1726cd84c2acSFrederic Weisbecker 
1727a89e5abeSArnaldo Carvalho de Melo struct dso *__dsos__findnew(struct list_head *head, const char *name)
1728cd84c2acSFrederic Weisbecker {
1729a89e5abeSArnaldo Carvalho de Melo 	struct dso *dso = dsos__find(head, name);
1730cd84c2acSFrederic Weisbecker 
1731e4204992SArnaldo Carvalho de Melo 	if (!dso) {
173200a192b3SArnaldo Carvalho de Melo 		dso = dso__new(name);
1733cfc10d3bSArnaldo Carvalho de Melo 		if (dso != NULL) {
1734a89e5abeSArnaldo Carvalho de Melo 			dsos__add(head, dso);
1735cfc10d3bSArnaldo Carvalho de Melo 			dso__set_basename(dso);
1736cfc10d3bSArnaldo Carvalho de Melo 		}
1737e4204992SArnaldo Carvalho de Melo 	}
1738cd84c2acSFrederic Weisbecker 
1739cd84c2acSFrederic Weisbecker 	return dso;
1740cd84c2acSFrederic Weisbecker }
1741cd84c2acSFrederic Weisbecker 
1742b0da954aSArnaldo Carvalho de Melo static void __dsos__fprintf(struct list_head *head, FILE *fp)
1743cd84c2acSFrederic Weisbecker {
1744cd84c2acSFrederic Weisbecker 	struct dso *pos;
1745cd84c2acSFrederic Weisbecker 
174695011c60SArnaldo Carvalho de Melo 	list_for_each_entry(pos, head, node) {
174795011c60SArnaldo Carvalho de Melo 		int i;
174895011c60SArnaldo Carvalho de Melo 		for (i = 0; i < MAP__NR_TYPES; ++i)
174995011c60SArnaldo Carvalho de Melo 			dso__fprintf(pos, i, fp);
175095011c60SArnaldo Carvalho de Melo 	}
1751cd84c2acSFrederic Weisbecker }
1752cd84c2acSFrederic Weisbecker 
1753b0da954aSArnaldo Carvalho de Melo void dsos__fprintf(FILE *fp)
1754b0da954aSArnaldo Carvalho de Melo {
1755b0da954aSArnaldo Carvalho de Melo 	__dsos__fprintf(&dsos__kernel, fp);
1756b0da954aSArnaldo Carvalho de Melo 	__dsos__fprintf(&dsos__user, fp);
1757b0da954aSArnaldo Carvalho de Melo }
1758b0da954aSArnaldo Carvalho de Melo 
175988d3d9b7SArnaldo Carvalho de Melo static size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp,
176088d3d9b7SArnaldo Carvalho de Melo 				      bool with_hits)
17619e03eb2dSArnaldo Carvalho de Melo {
17629e03eb2dSArnaldo Carvalho de Melo 	struct dso *pos;
17639e03eb2dSArnaldo Carvalho de Melo 	size_t ret = 0;
17649e03eb2dSArnaldo Carvalho de Melo 
1765b0da954aSArnaldo Carvalho de Melo 	list_for_each_entry(pos, head, node) {
176688d3d9b7SArnaldo Carvalho de Melo 		if (with_hits && !pos->hit)
176788d3d9b7SArnaldo Carvalho de Melo 			continue;
17689e03eb2dSArnaldo Carvalho de Melo 		ret += dso__fprintf_buildid(pos, fp);
17699e03eb2dSArnaldo Carvalho de Melo 		ret += fprintf(fp, " %s\n", pos->long_name);
17709e03eb2dSArnaldo Carvalho de Melo 	}
17719e03eb2dSArnaldo Carvalho de Melo 	return ret;
17729e03eb2dSArnaldo Carvalho de Melo }
17739e03eb2dSArnaldo Carvalho de Melo 
177488d3d9b7SArnaldo Carvalho de Melo size_t dsos__fprintf_buildid(FILE *fp, bool with_hits)
1775b0da954aSArnaldo Carvalho de Melo {
177688d3d9b7SArnaldo Carvalho de Melo 	return (__dsos__fprintf_buildid(&dsos__kernel, fp, with_hits) +
177788d3d9b7SArnaldo Carvalho de Melo 		__dsos__fprintf_buildid(&dsos__user, fp, with_hits));
1778b0da954aSArnaldo Carvalho de Melo }
1779b0da954aSArnaldo Carvalho de Melo 
1780fd1d908cSArnaldo Carvalho de Melo struct dso *dso__new_kernel(const char *name)
1781fd1d908cSArnaldo Carvalho de Melo {
1782fd1d908cSArnaldo Carvalho de Melo 	struct dso *self = dso__new(name ?: "[kernel.kallsyms]");
1783fd1d908cSArnaldo Carvalho de Melo 
1784fd1d908cSArnaldo Carvalho de Melo 	if (self != NULL) {
1785fd1d908cSArnaldo Carvalho de Melo 		self->short_name = "[kernel]";
1786fd1d908cSArnaldo Carvalho de Melo 		self->kernel	 = 1;
1787fd1d908cSArnaldo Carvalho de Melo 	}
1788fd1d908cSArnaldo Carvalho de Melo 
1789fd1d908cSArnaldo Carvalho de Melo 	return self;
1790fd1d908cSArnaldo Carvalho de Melo }
1791fd1d908cSArnaldo Carvalho de Melo 
1792fd1d908cSArnaldo Carvalho de Melo void dso__read_running_kernel_build_id(struct dso *self)
1793fd1d908cSArnaldo Carvalho de Melo {
1794fd1d908cSArnaldo Carvalho de Melo 	if (sysfs__read_build_id("/sys/kernel/notes", self->build_id,
1795fd1d908cSArnaldo Carvalho de Melo 				 sizeof(self->build_id)) == 0)
1796fd1d908cSArnaldo Carvalho de Melo 		self->has_build_id = true;
1797fd1d908cSArnaldo Carvalho de Melo }
1798fd1d908cSArnaldo Carvalho de Melo 
1799f1dfa0b1SArnaldo Carvalho de Melo static struct dso *dsos__create_kernel(const char *vmlinux)
1800cd84c2acSFrederic Weisbecker {
1801fd1d908cSArnaldo Carvalho de Melo 	struct dso *kernel = dso__new_kernel(vmlinux);
1802cd84c2acSFrederic Weisbecker 
18038d92c02aSArnaldo Carvalho de Melo 	if (kernel != NULL) {
1804fd1d908cSArnaldo Carvalho de Melo 		dso__read_running_kernel_build_id(kernel);
1805b0da954aSArnaldo Carvalho de Melo 		dsos__add(&dsos__kernel, kernel);
18068d92c02aSArnaldo Carvalho de Melo 	}
1807cd84c2acSFrederic Weisbecker 
1808f1dfa0b1SArnaldo Carvalho de Melo 	return kernel;
1809f1dfa0b1SArnaldo Carvalho de Melo }
1810f1dfa0b1SArnaldo Carvalho de Melo 
1811b7cece76SArnaldo Carvalho de Melo int __map_groups__create_kernel_maps(struct map_groups *self,
1812de176489SArnaldo Carvalho de Melo 				     struct map *vmlinux_maps[MAP__NR_TYPES],
1813b7cece76SArnaldo Carvalho de Melo 				     struct dso *kernel)
1814f1dfa0b1SArnaldo Carvalho de Melo {
1815de176489SArnaldo Carvalho de Melo 	enum map_type type;
1816f1dfa0b1SArnaldo Carvalho de Melo 
1817de176489SArnaldo Carvalho de Melo 	for (type = 0; type < MAP__NR_TYPES; ++type) {
18189de89fe7SArnaldo Carvalho de Melo 		struct kmap *kmap;
18199de89fe7SArnaldo Carvalho de Melo 
1820de176489SArnaldo Carvalho de Melo 		vmlinux_maps[type] = map__new2(0, kernel, type);
1821de176489SArnaldo Carvalho de Melo 		if (vmlinux_maps[type] == NULL)
1822f1dfa0b1SArnaldo Carvalho de Melo 			return -1;
1823f1dfa0b1SArnaldo Carvalho de Melo 
1824de176489SArnaldo Carvalho de Melo 		vmlinux_maps[type]->map_ip =
1825de176489SArnaldo Carvalho de Melo 			vmlinux_maps[type]->unmap_ip = identity__map_ip;
18269de89fe7SArnaldo Carvalho de Melo 
18279de89fe7SArnaldo Carvalho de Melo 		kmap = map__kmap(vmlinux_maps[type]);
18289de89fe7SArnaldo Carvalho de Melo 		kmap->kmaps = self;
1829de176489SArnaldo Carvalho de Melo 		map_groups__insert(self, vmlinux_maps[type]);
1830f1dfa0b1SArnaldo Carvalho de Melo 	}
1831f1dfa0b1SArnaldo Carvalho de Melo 
1832f1dfa0b1SArnaldo Carvalho de Melo 	return 0;
18332446042cSArnaldo Carvalho de Melo }
18342446042cSArnaldo Carvalho de Melo 
1835cc612d81SArnaldo Carvalho de Melo static void vmlinux_path__exit(void)
18362446042cSArnaldo Carvalho de Melo {
1837cc612d81SArnaldo Carvalho de Melo 	while (--vmlinux_path__nr_entries >= 0) {
1838cc612d81SArnaldo Carvalho de Melo 		free(vmlinux_path[vmlinux_path__nr_entries]);
1839cc612d81SArnaldo Carvalho de Melo 		vmlinux_path[vmlinux_path__nr_entries] = NULL;
1840cc612d81SArnaldo Carvalho de Melo 	}
1841cc612d81SArnaldo Carvalho de Melo 
1842cc612d81SArnaldo Carvalho de Melo 	free(vmlinux_path);
1843cc612d81SArnaldo Carvalho de Melo 	vmlinux_path = NULL;
1844cc612d81SArnaldo Carvalho de Melo }
1845cc612d81SArnaldo Carvalho de Melo 
1846cc612d81SArnaldo Carvalho de Melo static int vmlinux_path__init(void)
1847cc612d81SArnaldo Carvalho de Melo {
1848cc612d81SArnaldo Carvalho de Melo 	struct utsname uts;
1849cc612d81SArnaldo Carvalho de Melo 	char bf[PATH_MAX];
1850cc612d81SArnaldo Carvalho de Melo 
1851cc612d81SArnaldo Carvalho de Melo 	if (uname(&uts) < 0)
18522446042cSArnaldo Carvalho de Melo 		return -1;
18532446042cSArnaldo Carvalho de Melo 
1854cc612d81SArnaldo Carvalho de Melo 	vmlinux_path = malloc(sizeof(char *) * 5);
1855cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path == NULL)
1856cc612d81SArnaldo Carvalho de Melo 		return -1;
1857cc612d81SArnaldo Carvalho de Melo 
1858cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup("vmlinux");
1859cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1860cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
1861cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
1862cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup("/boot/vmlinux");
1863cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1864cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
1865cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
1866cc612d81SArnaldo Carvalho de Melo 	snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", uts.release);
1867cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1868cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1869cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
1870cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
1871cc612d81SArnaldo Carvalho de Melo 	snprintf(bf, sizeof(bf), "/lib/modules/%s/build/vmlinux", uts.release);
1872cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1873cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1874cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
1875cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
1876cc612d81SArnaldo Carvalho de Melo 	snprintf(bf, sizeof(bf), "/usr/lib/debug/lib/modules/%s/vmlinux",
1877cc612d81SArnaldo Carvalho de Melo 		 uts.release);
1878cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1879cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1880cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
1881cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
1882cc612d81SArnaldo Carvalho de Melo 
1883cc612d81SArnaldo Carvalho de Melo 	return 0;
1884cc612d81SArnaldo Carvalho de Melo 
1885cc612d81SArnaldo Carvalho de Melo out_fail:
1886cc612d81SArnaldo Carvalho de Melo 	vmlinux_path__exit();
1887cc612d81SArnaldo Carvalho de Melo 	return -1;
1888cc612d81SArnaldo Carvalho de Melo }
1889cc612d81SArnaldo Carvalho de Melo 
1890655000e7SArnaldo Carvalho de Melo static int setup_list(struct strlist **list, const char *list_str,
1891655000e7SArnaldo Carvalho de Melo 		      const char *list_name)
1892655000e7SArnaldo Carvalho de Melo {
1893655000e7SArnaldo Carvalho de Melo 	if (list_str == NULL)
1894655000e7SArnaldo Carvalho de Melo 		return 0;
1895655000e7SArnaldo Carvalho de Melo 
1896655000e7SArnaldo Carvalho de Melo 	*list = strlist__new(true, list_str);
1897655000e7SArnaldo Carvalho de Melo 	if (!*list) {
1898655000e7SArnaldo Carvalho de Melo 		pr_err("problems parsing %s list\n", list_name);
1899655000e7SArnaldo Carvalho de Melo 		return -1;
1900655000e7SArnaldo Carvalho de Melo 	}
1901655000e7SArnaldo Carvalho de Melo 	return 0;
1902655000e7SArnaldo Carvalho de Melo }
1903655000e7SArnaldo Carvalho de Melo 
190475be6cf4SArnaldo Carvalho de Melo int symbol__init(void)
1905cc612d81SArnaldo Carvalho de Melo {
190695011c60SArnaldo Carvalho de Melo 	elf_version(EV_CURRENT);
190775be6cf4SArnaldo Carvalho de Melo 	if (symbol_conf.sort_by_name)
190875be6cf4SArnaldo Carvalho de Melo 		symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) -
190979406cd7SArnaldo Carvalho de Melo 					  sizeof(struct symbol));
1910b32d133aSArnaldo Carvalho de Melo 
191175be6cf4SArnaldo Carvalho de Melo 	if (symbol_conf.try_vmlinux_path && vmlinux_path__init() < 0)
1912cc612d81SArnaldo Carvalho de Melo 		return -1;
1913cc612d81SArnaldo Carvalho de Melo 
1914c410a338SArnaldo Carvalho de Melo 	if (symbol_conf.field_sep && *symbol_conf.field_sep == '.') {
1915c410a338SArnaldo Carvalho de Melo 		pr_err("'.' is the only non valid --field-separator argument\n");
1916c410a338SArnaldo Carvalho de Melo 		return -1;
1917c410a338SArnaldo Carvalho de Melo 	}
1918c410a338SArnaldo Carvalho de Melo 
1919655000e7SArnaldo Carvalho de Melo 	if (setup_list(&symbol_conf.dso_list,
1920655000e7SArnaldo Carvalho de Melo 		       symbol_conf.dso_list_str, "dso") < 0)
1921655000e7SArnaldo Carvalho de Melo 		return -1;
1922655000e7SArnaldo Carvalho de Melo 
1923655000e7SArnaldo Carvalho de Melo 	if (setup_list(&symbol_conf.comm_list,
1924655000e7SArnaldo Carvalho de Melo 		       symbol_conf.comm_list_str, "comm") < 0)
1925655000e7SArnaldo Carvalho de Melo 		goto out_free_dso_list;
1926655000e7SArnaldo Carvalho de Melo 
1927655000e7SArnaldo Carvalho de Melo 	if (setup_list(&symbol_conf.sym_list,
1928655000e7SArnaldo Carvalho de Melo 		       symbol_conf.sym_list_str, "symbol") < 0)
1929655000e7SArnaldo Carvalho de Melo 		goto out_free_comm_list;
1930655000e7SArnaldo Carvalho de Melo 
19314aa65636SArnaldo Carvalho de Melo 	return 0;
1932655000e7SArnaldo Carvalho de Melo 
1933655000e7SArnaldo Carvalho de Melo out_free_dso_list:
1934655000e7SArnaldo Carvalho de Melo 	strlist__delete(symbol_conf.dso_list);
1935655000e7SArnaldo Carvalho de Melo out_free_comm_list:
1936655000e7SArnaldo Carvalho de Melo 	strlist__delete(symbol_conf.comm_list);
1937655000e7SArnaldo Carvalho de Melo 	return -1;
1938cc612d81SArnaldo Carvalho de Melo }
1939cc612d81SArnaldo Carvalho de Melo 
19409de89fe7SArnaldo Carvalho de Melo int map_groups__create_kernel_maps(struct map_groups *self,
19419de89fe7SArnaldo Carvalho de Melo 				   struct map *vmlinux_maps[MAP__NR_TYPES])
19424aa65636SArnaldo Carvalho de Melo {
19439de89fe7SArnaldo Carvalho de Melo 	struct dso *kernel = dsos__create_kernel(symbol_conf.vmlinux_name);
19449de89fe7SArnaldo Carvalho de Melo 
19459de89fe7SArnaldo Carvalho de Melo 	if (kernel == NULL)
19464aa65636SArnaldo Carvalho de Melo 		return -1;
19474aa65636SArnaldo Carvalho de Melo 
19489de89fe7SArnaldo Carvalho de Melo 	if (__map_groups__create_kernel_maps(self, vmlinux_maps, kernel) < 0)
19499de89fe7SArnaldo Carvalho de Melo 		return -1;
19509de89fe7SArnaldo Carvalho de Melo 
19519de89fe7SArnaldo Carvalho de Melo 	if (symbol_conf.use_modules && map_groups__create_modules(self) < 0)
195210fe12efSArnaldo Carvalho de Melo 		pr_debug("Problems creating module maps, continuing anyway...\n");
195390c83218SArnaldo Carvalho de Melo 	/*
195490c83218SArnaldo Carvalho de Melo 	 * Now that we have all the maps created, just set the ->end of them:
195590c83218SArnaldo Carvalho de Melo 	 */
19569de89fe7SArnaldo Carvalho de Melo 	map_groups__fixup_end(self);
19576671cb16SArnaldo Carvalho de Melo 	return 0;
1958cd84c2acSFrederic Weisbecker }
1959