xref: /linux/tools/perf/util/symbol.c (revision a89e5abe3efcc7facc666d3985769278937f86b0)
186470930SIngo Molnar #include "util.h"
286470930SIngo Molnar #include "../perf.h"
34aa65636SArnaldo Carvalho de Melo #include "session.h"
4655000e7SArnaldo Carvalho de Melo #include "sort.h"
586470930SIngo Molnar #include "string.h"
686470930SIngo Molnar #include "symbol.h"
7439d473bSArnaldo Carvalho de Melo #include "thread.h"
886470930SIngo Molnar 
98f28827aSFrederic Weisbecker #include "debug.h"
108f28827aSFrederic Weisbecker 
11b32d133aSArnaldo Carvalho de Melo #include <asm/bug.h>
1286470930SIngo Molnar #include <libelf.h>
1386470930SIngo Molnar #include <gelf.h>
1486470930SIngo Molnar #include <elf.h>
15f1617b40SArnaldo Carvalho de Melo #include <limits.h>
16439d473bSArnaldo Carvalho de Melo #include <sys/utsname.h>
172cdbc46dSPeter Zijlstra 
18c12e15e7SArnaldo Carvalho de Melo #ifndef NT_GNU_BUILD_ID
19c12e15e7SArnaldo Carvalho de Melo #define NT_GNU_BUILD_ID 3
20c12e15e7SArnaldo Carvalho de Melo #endif
21c12e15e7SArnaldo Carvalho de Melo 
2294cb9e38SArnaldo Carvalho de Melo enum dso_origin {
2394cb9e38SArnaldo Carvalho de Melo 	DSO__ORIG_KERNEL = 0,
2494cb9e38SArnaldo Carvalho de Melo 	DSO__ORIG_JAVA_JIT,
254cf40131SArnaldo Carvalho de Melo 	DSO__ORIG_BUILD_ID_CACHE,
2694cb9e38SArnaldo Carvalho de Melo 	DSO__ORIG_FEDORA,
2794cb9e38SArnaldo Carvalho de Melo 	DSO__ORIG_UBUNTU,
2894cb9e38SArnaldo Carvalho de Melo 	DSO__ORIG_BUILDID,
2994cb9e38SArnaldo Carvalho de Melo 	DSO__ORIG_DSO,
30439d473bSArnaldo Carvalho de Melo 	DSO__ORIG_KMODULE,
3194cb9e38SArnaldo Carvalho de Melo 	DSO__ORIG_NOT_FOUND,
3294cb9e38SArnaldo Carvalho de Melo };
3394cb9e38SArnaldo Carvalho de Melo 
34b0da954aSArnaldo Carvalho de Melo static void dsos__add(struct list_head *head, struct dso *dso);
353610583cSArnaldo Carvalho de Melo static struct map *map__new2(u64 start, struct dso *dso, enum map_type type);
36c338aee8SArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *self, struct map *map,
374aa65636SArnaldo Carvalho de Melo 				struct perf_session *session, symbol_filter_t filter);
38cc612d81SArnaldo Carvalho de Melo static int vmlinux_path__nr_entries;
39cc612d81SArnaldo Carvalho de Melo static char **vmlinux_path;
40439d473bSArnaldo Carvalho de Melo 
4175be6cf4SArnaldo Carvalho de Melo struct symbol_conf symbol_conf = {
42d599db3fSArnaldo Carvalho de Melo 	.exclude_other	  = true,
43b32d133aSArnaldo Carvalho de Melo 	.use_modules	  = true,
44b32d133aSArnaldo Carvalho de Melo 	.try_vmlinux_path = true,
45b32d133aSArnaldo Carvalho de Melo };
46b32d133aSArnaldo Carvalho de Melo 
473610583cSArnaldo Carvalho de Melo bool dso__loaded(const struct dso *self, enum map_type type)
483610583cSArnaldo Carvalho de Melo {
493610583cSArnaldo Carvalho de Melo 	return self->loaded & (1 << type);
503610583cSArnaldo Carvalho de Melo }
513610583cSArnaldo Carvalho de Melo 
5279406cd7SArnaldo Carvalho de Melo bool dso__sorted_by_name(const struct dso *self, enum map_type type)
5379406cd7SArnaldo Carvalho de Melo {
5479406cd7SArnaldo Carvalho de Melo 	return self->sorted_by_name & (1 << type);
5579406cd7SArnaldo Carvalho de Melo }
5679406cd7SArnaldo Carvalho de Melo 
573610583cSArnaldo Carvalho de Melo static void dso__set_loaded(struct dso *self, enum map_type type)
583610583cSArnaldo Carvalho de Melo {
593610583cSArnaldo Carvalho de Melo 	self->loaded |= (1 << type);
603610583cSArnaldo Carvalho de Melo }
613610583cSArnaldo Carvalho de Melo 
6279406cd7SArnaldo Carvalho de Melo static void dso__set_sorted_by_name(struct dso *self, enum map_type type)
6379406cd7SArnaldo Carvalho de Melo {
6479406cd7SArnaldo Carvalho de Melo 	self->sorted_by_name |= (1 << type);
6579406cd7SArnaldo Carvalho de Melo }
6679406cd7SArnaldo Carvalho de Melo 
6736a3e646SArnaldo Carvalho de Melo bool symbol_type__is_a(char symbol_type, enum map_type map_type)
686893d4eeSArnaldo Carvalho de Melo {
696893d4eeSArnaldo Carvalho de Melo 	switch (map_type) {
706893d4eeSArnaldo Carvalho de Melo 	case MAP__FUNCTION:
716893d4eeSArnaldo Carvalho de Melo 		return symbol_type == 'T' || symbol_type == 'W';
72f1dfa0b1SArnaldo Carvalho de Melo 	case MAP__VARIABLE:
73f1dfa0b1SArnaldo Carvalho de Melo 		return symbol_type == 'D' || symbol_type == 'd';
746893d4eeSArnaldo Carvalho de Melo 	default:
756893d4eeSArnaldo Carvalho de Melo 		return false;
766893d4eeSArnaldo Carvalho de Melo 	}
776893d4eeSArnaldo Carvalho de Melo }
786893d4eeSArnaldo Carvalho de Melo 
79fcf1203aSArnaldo Carvalho de Melo static void symbols__fixup_end(struct rb_root *self)
80af427bf5SArnaldo Carvalho de Melo {
81fcf1203aSArnaldo Carvalho de Melo 	struct rb_node *nd, *prevnd = rb_first(self);
822e538c4aSArnaldo Carvalho de Melo 	struct symbol *curr, *prev;
83af427bf5SArnaldo Carvalho de Melo 
84af427bf5SArnaldo Carvalho de Melo 	if (prevnd == NULL)
85af427bf5SArnaldo Carvalho de Melo 		return;
86af427bf5SArnaldo Carvalho de Melo 
872e538c4aSArnaldo Carvalho de Melo 	curr = rb_entry(prevnd, struct symbol, rb_node);
882e538c4aSArnaldo Carvalho de Melo 
89af427bf5SArnaldo Carvalho de Melo 	for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
902e538c4aSArnaldo Carvalho de Melo 		prev = curr;
912e538c4aSArnaldo Carvalho de Melo 		curr = rb_entry(nd, struct symbol, rb_node);
92af427bf5SArnaldo Carvalho de Melo 
93af427bf5SArnaldo Carvalho de Melo 		if (prev->end == prev->start)
94af427bf5SArnaldo Carvalho de Melo 			prev->end = curr->start - 1;
95af427bf5SArnaldo Carvalho de Melo 	}
96af427bf5SArnaldo Carvalho de Melo 
972e538c4aSArnaldo Carvalho de Melo 	/* Last entry */
982e538c4aSArnaldo Carvalho de Melo 	if (curr->end == curr->start)
992e538c4aSArnaldo Carvalho de Melo 		curr->end = roundup(curr->start, 4096);
1002e538c4aSArnaldo Carvalho de Melo }
1012e538c4aSArnaldo Carvalho de Melo 
1029958e1f0SArnaldo Carvalho de Melo static void __map_groups__fixup_end(struct map_groups *self, enum map_type type)
103af427bf5SArnaldo Carvalho de Melo {
104af427bf5SArnaldo Carvalho de Melo 	struct map *prev, *curr;
10595011c60SArnaldo Carvalho de Melo 	struct rb_node *nd, *prevnd = rb_first(&self->maps[type]);
106af427bf5SArnaldo Carvalho de Melo 
107af427bf5SArnaldo Carvalho de Melo 	if (prevnd == NULL)
108af427bf5SArnaldo Carvalho de Melo 		return;
109af427bf5SArnaldo Carvalho de Melo 
110af427bf5SArnaldo Carvalho de Melo 	curr = rb_entry(prevnd, struct map, rb_node);
111af427bf5SArnaldo Carvalho de Melo 
112af427bf5SArnaldo Carvalho de Melo 	for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
113af427bf5SArnaldo Carvalho de Melo 		prev = curr;
114af427bf5SArnaldo Carvalho de Melo 		curr = rb_entry(nd, struct map, rb_node);
115af427bf5SArnaldo Carvalho de Melo 		prev->end = curr->start - 1;
1162e538c4aSArnaldo Carvalho de Melo 	}
11790c83218SArnaldo Carvalho de Melo 
11890c83218SArnaldo Carvalho de Melo 	/*
11990c83218SArnaldo Carvalho de Melo 	 * We still haven't the actual symbols, so guess the
12090c83218SArnaldo Carvalho de Melo 	 * last map final address.
12190c83218SArnaldo Carvalho de Melo 	 */
12290c83218SArnaldo Carvalho de Melo 	curr->end = ~0UL;
123af427bf5SArnaldo Carvalho de Melo }
124af427bf5SArnaldo Carvalho de Melo 
1259958e1f0SArnaldo Carvalho de Melo static void map_groups__fixup_end(struct map_groups *self)
12623ea4a3fSArnaldo Carvalho de Melo {
12723ea4a3fSArnaldo Carvalho de Melo 	int i;
12823ea4a3fSArnaldo Carvalho de Melo 	for (i = 0; i < MAP__NR_TYPES; ++i)
1299958e1f0SArnaldo Carvalho de Melo 		__map_groups__fixup_end(self, i);
13023ea4a3fSArnaldo Carvalho de Melo }
13123ea4a3fSArnaldo Carvalho de Melo 
13200a192b3SArnaldo Carvalho de Melo static struct symbol *symbol__new(u64 start, u64 len, const char *name)
13386470930SIngo Molnar {
13486470930SIngo Molnar 	size_t namelen = strlen(name) + 1;
13575be6cf4SArnaldo Carvalho de Melo 	struct symbol *self = zalloc(symbol_conf.priv_size +
13636479484SArnaldo Carvalho de Melo 				     sizeof(*self) + namelen);
13736479484SArnaldo Carvalho de Melo 	if (self == NULL)
13886470930SIngo Molnar 		return NULL;
13986470930SIngo Molnar 
14075be6cf4SArnaldo Carvalho de Melo 	if (symbol_conf.priv_size)
14175be6cf4SArnaldo Carvalho de Melo 		self = ((void *)self) + symbol_conf.priv_size;
14236479484SArnaldo Carvalho de Melo 
14386470930SIngo Molnar 	self->start = start;
1446cfcc53eSMike Galbraith 	self->end   = len ? start + len - 1 : start;
145e4204992SArnaldo Carvalho de Melo 
1466beba7adSArnaldo Carvalho de Melo 	pr_debug3("%s: %s %#Lx-%#Lx\n", __func__, name, start, self->end);
147e4204992SArnaldo Carvalho de Melo 
14886470930SIngo Molnar 	memcpy(self->name, name, namelen);
14986470930SIngo Molnar 
15086470930SIngo Molnar 	return self;
15186470930SIngo Molnar }
15286470930SIngo Molnar 
15300a192b3SArnaldo Carvalho de Melo static void symbol__delete(struct symbol *self)
15486470930SIngo Molnar {
15575be6cf4SArnaldo Carvalho de Melo 	free(((void *)self) - symbol_conf.priv_size);
15686470930SIngo Molnar }
15786470930SIngo Molnar 
15886470930SIngo Molnar static size_t symbol__fprintf(struct symbol *self, FILE *fp)
15986470930SIngo Molnar {
16086470930SIngo Molnar 	return fprintf(fp, " %llx-%llx %s\n",
16186470930SIngo Molnar 		       self->start, self->end, self->name);
16286470930SIngo Molnar }
16386470930SIngo Molnar 
164cfc10d3bSArnaldo Carvalho de Melo static void dso__set_long_name(struct dso *self, char *name)
165cfc10d3bSArnaldo Carvalho de Melo {
166ef6ae724SArnaldo Carvalho de Melo 	if (name == NULL)
167ef6ae724SArnaldo Carvalho de Melo 		return;
168cfc10d3bSArnaldo Carvalho de Melo 	self->long_name = name;
169cfc10d3bSArnaldo Carvalho de Melo 	self->long_name_len = strlen(name);
170cfc10d3bSArnaldo Carvalho de Melo }
171cfc10d3bSArnaldo Carvalho de Melo 
172cfc10d3bSArnaldo Carvalho de Melo static void dso__set_basename(struct dso *self)
173cfc10d3bSArnaldo Carvalho de Melo {
174cfc10d3bSArnaldo Carvalho de Melo 	self->short_name = basename(self->long_name);
175cfc10d3bSArnaldo Carvalho de Melo }
176cfc10d3bSArnaldo Carvalho de Melo 
17700a192b3SArnaldo Carvalho de Melo struct dso *dso__new(const char *name)
17886470930SIngo Molnar {
17986470930SIngo Molnar 	struct dso *self = malloc(sizeof(*self) + strlen(name) + 1);
18086470930SIngo Molnar 
18186470930SIngo Molnar 	if (self != NULL) {
1826a4694a4SArnaldo Carvalho de Melo 		int i;
18386470930SIngo Molnar 		strcpy(self->name, name);
184cfc10d3bSArnaldo Carvalho de Melo 		dso__set_long_name(self, self->name);
185439d473bSArnaldo Carvalho de Melo 		self->short_name = self->name;
1866a4694a4SArnaldo Carvalho de Melo 		for (i = 0; i < MAP__NR_TYPES; ++i)
18779406cd7SArnaldo Carvalho de Melo 			self->symbols[i] = self->symbol_names[i] = RB_ROOT;
18852d422deSArnaldo Carvalho de Melo 		self->slen_calculated = 0;
18994cb9e38SArnaldo Carvalho de Melo 		self->origin = DSO__ORIG_NOT_FOUND;
1908d06367fSArnaldo Carvalho de Melo 		self->loaded = 0;
19179406cd7SArnaldo Carvalho de Melo 		self->sorted_by_name = 0;
1928d06367fSArnaldo Carvalho de Melo 		self->has_build_id = 0;
19386470930SIngo Molnar 	}
19486470930SIngo Molnar 
19586470930SIngo Molnar 	return self;
19686470930SIngo Molnar }
19786470930SIngo Molnar 
198fcf1203aSArnaldo Carvalho de Melo static void symbols__delete(struct rb_root *self)
19986470930SIngo Molnar {
20086470930SIngo Molnar 	struct symbol *pos;
201fcf1203aSArnaldo Carvalho de Melo 	struct rb_node *next = rb_first(self);
20286470930SIngo Molnar 
20386470930SIngo Molnar 	while (next) {
20486470930SIngo Molnar 		pos = rb_entry(next, struct symbol, rb_node);
20586470930SIngo Molnar 		next = rb_next(&pos->rb_node);
206fcf1203aSArnaldo Carvalho de Melo 		rb_erase(&pos->rb_node, self);
20700a192b3SArnaldo Carvalho de Melo 		symbol__delete(pos);
20886470930SIngo Molnar 	}
20986470930SIngo Molnar }
21086470930SIngo Molnar 
21186470930SIngo Molnar void dso__delete(struct dso *self)
21286470930SIngo Molnar {
2136a4694a4SArnaldo Carvalho de Melo 	int i;
2146a4694a4SArnaldo Carvalho de Melo 	for (i = 0; i < MAP__NR_TYPES; ++i)
2156a4694a4SArnaldo Carvalho de Melo 		symbols__delete(&self->symbols[i]);
216439d473bSArnaldo Carvalho de Melo 	if (self->long_name != self->name)
217439d473bSArnaldo Carvalho de Melo 		free(self->long_name);
21886470930SIngo Molnar 	free(self);
21986470930SIngo Molnar }
22086470930SIngo Molnar 
2218d06367fSArnaldo Carvalho de Melo void dso__set_build_id(struct dso *self, void *build_id)
2228d06367fSArnaldo Carvalho de Melo {
2238d06367fSArnaldo Carvalho de Melo 	memcpy(self->build_id, build_id, sizeof(self->build_id));
2248d06367fSArnaldo Carvalho de Melo 	self->has_build_id = 1;
2258d06367fSArnaldo Carvalho de Melo }
2268d06367fSArnaldo Carvalho de Melo 
227fcf1203aSArnaldo Carvalho de Melo static void symbols__insert(struct rb_root *self, struct symbol *sym)
22886470930SIngo Molnar {
229fcf1203aSArnaldo Carvalho de Melo 	struct rb_node **p = &self->rb_node;
23086470930SIngo Molnar 	struct rb_node *parent = NULL;
2319cffa8d5SPaul Mackerras 	const u64 ip = sym->start;
23286470930SIngo Molnar 	struct symbol *s;
23386470930SIngo Molnar 
23486470930SIngo Molnar 	while (*p != NULL) {
23586470930SIngo Molnar 		parent = *p;
23686470930SIngo Molnar 		s = rb_entry(parent, struct symbol, rb_node);
23786470930SIngo Molnar 		if (ip < s->start)
23886470930SIngo Molnar 			p = &(*p)->rb_left;
23986470930SIngo Molnar 		else
24086470930SIngo Molnar 			p = &(*p)->rb_right;
24186470930SIngo Molnar 	}
24286470930SIngo Molnar 	rb_link_node(&sym->rb_node, parent, p);
243fcf1203aSArnaldo Carvalho de Melo 	rb_insert_color(&sym->rb_node, self);
24486470930SIngo Molnar }
24586470930SIngo Molnar 
246fcf1203aSArnaldo Carvalho de Melo static struct symbol *symbols__find(struct rb_root *self, u64 ip)
24786470930SIngo Molnar {
24886470930SIngo Molnar 	struct rb_node *n;
24986470930SIngo Molnar 
25086470930SIngo Molnar 	if (self == NULL)
25186470930SIngo Molnar 		return NULL;
25286470930SIngo Molnar 
253fcf1203aSArnaldo Carvalho de Melo 	n = self->rb_node;
25486470930SIngo Molnar 
25586470930SIngo Molnar 	while (n) {
25686470930SIngo Molnar 		struct symbol *s = rb_entry(n, struct symbol, rb_node);
25786470930SIngo Molnar 
25886470930SIngo Molnar 		if (ip < s->start)
25986470930SIngo Molnar 			n = n->rb_left;
26086470930SIngo Molnar 		else if (ip > s->end)
26186470930SIngo Molnar 			n = n->rb_right;
26286470930SIngo Molnar 		else
26386470930SIngo Molnar 			return s;
26486470930SIngo Molnar 	}
26586470930SIngo Molnar 
26686470930SIngo Molnar 	return NULL;
26786470930SIngo Molnar }
26886470930SIngo Molnar 
26979406cd7SArnaldo Carvalho de Melo struct symbol_name_rb_node {
27079406cd7SArnaldo Carvalho de Melo 	struct rb_node	rb_node;
27179406cd7SArnaldo Carvalho de Melo 	struct symbol	sym;
27279406cd7SArnaldo Carvalho de Melo };
27379406cd7SArnaldo Carvalho de Melo 
27479406cd7SArnaldo Carvalho de Melo static void symbols__insert_by_name(struct rb_root *self, struct symbol *sym)
27579406cd7SArnaldo Carvalho de Melo {
27679406cd7SArnaldo Carvalho de Melo 	struct rb_node **p = &self->rb_node;
27779406cd7SArnaldo Carvalho de Melo 	struct rb_node *parent = NULL;
27879406cd7SArnaldo Carvalho de Melo 	struct symbol_name_rb_node *symn = ((void *)sym) - sizeof(*parent), *s;
27979406cd7SArnaldo Carvalho de Melo 
28079406cd7SArnaldo Carvalho de Melo 	while (*p != NULL) {
28179406cd7SArnaldo Carvalho de Melo 		parent = *p;
28279406cd7SArnaldo Carvalho de Melo 		s = rb_entry(parent, struct symbol_name_rb_node, rb_node);
28379406cd7SArnaldo Carvalho de Melo 		if (strcmp(sym->name, s->sym.name) < 0)
28479406cd7SArnaldo Carvalho de Melo 			p = &(*p)->rb_left;
28579406cd7SArnaldo Carvalho de Melo 		else
28679406cd7SArnaldo Carvalho de Melo 			p = &(*p)->rb_right;
28779406cd7SArnaldo Carvalho de Melo 	}
28879406cd7SArnaldo Carvalho de Melo 	rb_link_node(&symn->rb_node, parent, p);
28979406cd7SArnaldo Carvalho de Melo 	rb_insert_color(&symn->rb_node, self);
29079406cd7SArnaldo Carvalho de Melo }
29179406cd7SArnaldo Carvalho de Melo 
29279406cd7SArnaldo Carvalho de Melo static void symbols__sort_by_name(struct rb_root *self, struct rb_root *source)
29379406cd7SArnaldo Carvalho de Melo {
29479406cd7SArnaldo Carvalho de Melo 	struct rb_node *nd;
29579406cd7SArnaldo Carvalho de Melo 
29679406cd7SArnaldo Carvalho de Melo 	for (nd = rb_first(source); nd; nd = rb_next(nd)) {
29779406cd7SArnaldo Carvalho de Melo 		struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
29879406cd7SArnaldo Carvalho de Melo 		symbols__insert_by_name(self, pos);
29979406cd7SArnaldo Carvalho de Melo 	}
30079406cd7SArnaldo Carvalho de Melo }
30179406cd7SArnaldo Carvalho de Melo 
30279406cd7SArnaldo Carvalho de Melo static struct symbol *symbols__find_by_name(struct rb_root *self, const char *name)
30379406cd7SArnaldo Carvalho de Melo {
30479406cd7SArnaldo Carvalho de Melo 	struct rb_node *n;
30579406cd7SArnaldo Carvalho de Melo 
30679406cd7SArnaldo Carvalho de Melo 	if (self == NULL)
30779406cd7SArnaldo Carvalho de Melo 		return NULL;
30879406cd7SArnaldo Carvalho de Melo 
30979406cd7SArnaldo Carvalho de Melo 	n = self->rb_node;
31079406cd7SArnaldo Carvalho de Melo 
31179406cd7SArnaldo Carvalho de Melo 	while (n) {
31279406cd7SArnaldo Carvalho de Melo 		struct symbol_name_rb_node *s;
31379406cd7SArnaldo Carvalho de Melo 		int cmp;
31479406cd7SArnaldo Carvalho de Melo 
31579406cd7SArnaldo Carvalho de Melo 		s = rb_entry(n, struct symbol_name_rb_node, rb_node);
31679406cd7SArnaldo Carvalho de Melo 		cmp = strcmp(name, s->sym.name);
31779406cd7SArnaldo Carvalho de Melo 
31879406cd7SArnaldo Carvalho de Melo 		if (cmp < 0)
31979406cd7SArnaldo Carvalho de Melo 			n = n->rb_left;
32079406cd7SArnaldo Carvalho de Melo 		else if (cmp > 0)
32179406cd7SArnaldo Carvalho de Melo 			n = n->rb_right;
32279406cd7SArnaldo Carvalho de Melo 		else
32379406cd7SArnaldo Carvalho de Melo 			return &s->sym;
32479406cd7SArnaldo Carvalho de Melo 	}
32579406cd7SArnaldo Carvalho de Melo 
32679406cd7SArnaldo Carvalho de Melo 	return NULL;
32779406cd7SArnaldo Carvalho de Melo }
32879406cd7SArnaldo Carvalho de Melo 
32979406cd7SArnaldo Carvalho de Melo struct symbol *dso__find_symbol(struct dso *self,
33079406cd7SArnaldo Carvalho de Melo 				enum map_type type, u64 addr)
331fcf1203aSArnaldo Carvalho de Melo {
3326a4694a4SArnaldo Carvalho de Melo 	return symbols__find(&self->symbols[type], addr);
333fcf1203aSArnaldo Carvalho de Melo }
334fcf1203aSArnaldo Carvalho de Melo 
33579406cd7SArnaldo Carvalho de Melo struct symbol *dso__find_symbol_by_name(struct dso *self, enum map_type type,
33679406cd7SArnaldo Carvalho de Melo 					const char *name)
33779406cd7SArnaldo Carvalho de Melo {
33879406cd7SArnaldo Carvalho de Melo 	return symbols__find_by_name(&self->symbol_names[type], name);
33979406cd7SArnaldo Carvalho de Melo }
34079406cd7SArnaldo Carvalho de Melo 
34179406cd7SArnaldo Carvalho de Melo void dso__sort_by_name(struct dso *self, enum map_type type)
34279406cd7SArnaldo Carvalho de Melo {
34379406cd7SArnaldo Carvalho de Melo 	dso__set_sorted_by_name(self, type);
34479406cd7SArnaldo Carvalho de Melo 	return symbols__sort_by_name(&self->symbol_names[type],
34579406cd7SArnaldo Carvalho de Melo 				     &self->symbols[type]);
34679406cd7SArnaldo Carvalho de Melo }
34779406cd7SArnaldo Carvalho de Melo 
3488d06367fSArnaldo Carvalho de Melo int build_id__sprintf(u8 *self, int len, char *bf)
3498d06367fSArnaldo Carvalho de Melo {
3508d06367fSArnaldo Carvalho de Melo 	char *bid = bf;
3518d06367fSArnaldo Carvalho de Melo 	u8 *raw = self;
3528d06367fSArnaldo Carvalho de Melo 	int i;
3538d06367fSArnaldo Carvalho de Melo 
3548d06367fSArnaldo Carvalho de Melo 	for (i = 0; i < len; ++i) {
3558d06367fSArnaldo Carvalho de Melo 		sprintf(bid, "%02x", *raw);
3568d06367fSArnaldo Carvalho de Melo 		++raw;
3578d06367fSArnaldo Carvalho de Melo 		bid += 2;
3588d06367fSArnaldo Carvalho de Melo 	}
3598d06367fSArnaldo Carvalho de Melo 
3608d06367fSArnaldo Carvalho de Melo 	return raw - self;
3618d06367fSArnaldo Carvalho de Melo }
3628d06367fSArnaldo Carvalho de Melo 
3639e03eb2dSArnaldo Carvalho de Melo size_t dso__fprintf_buildid(struct dso *self, FILE *fp)
36486470930SIngo Molnar {
3658d06367fSArnaldo Carvalho de Melo 	char sbuild_id[BUILD_ID_SIZE * 2 + 1];
3668d06367fSArnaldo Carvalho de Melo 
3678d06367fSArnaldo Carvalho de Melo 	build_id__sprintf(self->build_id, sizeof(self->build_id), sbuild_id);
3689e03eb2dSArnaldo Carvalho de Melo 	return fprintf(fp, "%s", sbuild_id);
3699e03eb2dSArnaldo Carvalho de Melo }
3709e03eb2dSArnaldo Carvalho de Melo 
37195011c60SArnaldo Carvalho de Melo size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp)
3729e03eb2dSArnaldo Carvalho de Melo {
3739e03eb2dSArnaldo Carvalho de Melo 	struct rb_node *nd;
3749e03eb2dSArnaldo Carvalho de Melo 	size_t ret = fprintf(fp, "dso: %s (", self->short_name);
3759e03eb2dSArnaldo Carvalho de Melo 
3769e03eb2dSArnaldo Carvalho de Melo 	ret += dso__fprintf_buildid(self, fp);
3776a4694a4SArnaldo Carvalho de Melo 	ret += fprintf(fp, ")\n");
37895011c60SArnaldo Carvalho de Melo 	for (nd = rb_first(&self->symbols[type]); nd; nd = rb_next(nd)) {
37986470930SIngo Molnar 		struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
38086470930SIngo Molnar 		ret += symbol__fprintf(pos, fp);
38186470930SIngo Molnar 	}
38286470930SIngo Molnar 
38386470930SIngo Molnar 	return ret;
38486470930SIngo Molnar }
38586470930SIngo Molnar 
386682b335aSArnaldo Carvalho de Melo int kallsyms__parse(void *arg, int (*process_symbol)(void *arg, const char *name,
387682b335aSArnaldo Carvalho de Melo 						     char type, u64 start))
38886470930SIngo Molnar {
38986470930SIngo Molnar 	char *line = NULL;
39086470930SIngo Molnar 	size_t n;
391682b335aSArnaldo Carvalho de Melo 	int err = 0;
39286470930SIngo Molnar 	FILE *file = fopen("/proc/kallsyms", "r");
39386470930SIngo Molnar 
39486470930SIngo Molnar 	if (file == NULL)
39586470930SIngo Molnar 		goto out_failure;
39686470930SIngo Molnar 
39786470930SIngo Molnar 	while (!feof(file)) {
3989cffa8d5SPaul Mackerras 		u64 start;
39986470930SIngo Molnar 		int line_len, len;
40086470930SIngo Molnar 		char symbol_type;
4012e538c4aSArnaldo Carvalho de Melo 		char *symbol_name;
40286470930SIngo Molnar 
40386470930SIngo Molnar 		line_len = getline(&line, &n, file);
40486470930SIngo Molnar 		if (line_len < 0)
40586470930SIngo Molnar 			break;
40686470930SIngo Molnar 
40786470930SIngo Molnar 		if (!line)
40886470930SIngo Molnar 			goto out_failure;
40986470930SIngo Molnar 
41086470930SIngo Molnar 		line[--line_len] = '\0'; /* \n */
41186470930SIngo Molnar 
41286470930SIngo Molnar 		len = hex2u64(line, &start);
41386470930SIngo Molnar 
41486470930SIngo Molnar 		len++;
41586470930SIngo Molnar 		if (len + 2 >= line_len)
41686470930SIngo Molnar 			continue;
41786470930SIngo Molnar 
41886470930SIngo Molnar 		symbol_type = toupper(line[len]);
419af427bf5SArnaldo Carvalho de Melo 		symbol_name = line + len + 2;
420682b335aSArnaldo Carvalho de Melo 
421682b335aSArnaldo Carvalho de Melo 		err = process_symbol(arg, symbol_name, symbol_type, start);
422682b335aSArnaldo Carvalho de Melo 		if (err)
423682b335aSArnaldo Carvalho de Melo 			break;
424682b335aSArnaldo Carvalho de Melo 	}
425682b335aSArnaldo Carvalho de Melo 
426682b335aSArnaldo Carvalho de Melo 	free(line);
427682b335aSArnaldo Carvalho de Melo 	fclose(file);
428682b335aSArnaldo Carvalho de Melo 	return err;
429682b335aSArnaldo Carvalho de Melo 
430682b335aSArnaldo Carvalho de Melo out_failure:
431682b335aSArnaldo Carvalho de Melo 	return -1;
432682b335aSArnaldo Carvalho de Melo }
433682b335aSArnaldo Carvalho de Melo 
434682b335aSArnaldo Carvalho de Melo struct process_kallsyms_args {
435682b335aSArnaldo Carvalho de Melo 	struct map *map;
436682b335aSArnaldo Carvalho de Melo 	struct dso *dso;
437682b335aSArnaldo Carvalho de Melo };
438682b335aSArnaldo Carvalho de Melo 
439682b335aSArnaldo Carvalho de Melo static int map__process_kallsym_symbol(void *arg, const char *name,
440682b335aSArnaldo Carvalho de Melo 				       char type, u64 start)
441682b335aSArnaldo Carvalho de Melo {
442682b335aSArnaldo Carvalho de Melo 	struct symbol *sym;
443682b335aSArnaldo Carvalho de Melo 	struct process_kallsyms_args *a = arg;
444682b335aSArnaldo Carvalho de Melo 	struct rb_root *root = &a->dso->symbols[a->map->type];
445682b335aSArnaldo Carvalho de Melo 
446682b335aSArnaldo Carvalho de Melo 	if (!symbol_type__is_a(type, a->map->type))
447682b335aSArnaldo Carvalho de Melo 		return 0;
448682b335aSArnaldo Carvalho de Melo 
4492e538c4aSArnaldo Carvalho de Melo 	/*
4502e538c4aSArnaldo Carvalho de Melo 	 * Will fix up the end later, when we have all symbols sorted.
4512e538c4aSArnaldo Carvalho de Melo 	 */
452682b335aSArnaldo Carvalho de Melo 	sym = symbol__new(start, 0, name);
453af427bf5SArnaldo Carvalho de Melo 
4542e538c4aSArnaldo Carvalho de Melo 	if (sym == NULL)
455682b335aSArnaldo Carvalho de Melo 		return -ENOMEM;
45682164161SArnaldo Carvalho de Melo 	/*
45782164161SArnaldo Carvalho de Melo 	 * We will pass the symbols to the filter later, in
4584e06255fSArnaldo Carvalho de Melo 	 * map__split_kallsyms, when we have split the maps per module
45982164161SArnaldo Carvalho de Melo 	 */
4604e06255fSArnaldo Carvalho de Melo 	symbols__insert(root, sym);
461682b335aSArnaldo Carvalho de Melo 	return 0;
4622e538c4aSArnaldo Carvalho de Melo }
4632e538c4aSArnaldo Carvalho de Melo 
464682b335aSArnaldo Carvalho de Melo /*
465682b335aSArnaldo Carvalho de Melo  * Loads the function entries in /proc/kallsyms into kernel_map->dso,
466682b335aSArnaldo Carvalho de Melo  * so that we can in the next step set the symbol ->end address and then
467682b335aSArnaldo Carvalho de Melo  * call kernel_maps__split_kallsyms.
468682b335aSArnaldo Carvalho de Melo  */
469682b335aSArnaldo Carvalho de Melo static int dso__load_all_kallsyms(struct dso *self, struct map *map)
470682b335aSArnaldo Carvalho de Melo {
471682b335aSArnaldo Carvalho de Melo 	struct process_kallsyms_args args = { .map = map, .dso = self, };
472682b335aSArnaldo Carvalho de Melo 	return kallsyms__parse(&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,
4814aa65636SArnaldo Carvalho de Melo 			       struct perf_session *session, symbol_filter_t filter)
4822e538c4aSArnaldo Carvalho de Melo {
4834e06255fSArnaldo Carvalho de Melo 	struct map *curr_map = map;
4842e538c4aSArnaldo Carvalho de Melo 	struct symbol *pos;
4852e538c4aSArnaldo Carvalho de Melo 	int count = 0;
4864e06255fSArnaldo Carvalho de Melo 	struct rb_root *root = &self->symbols[map->type];
4874e06255fSArnaldo Carvalho de Melo 	struct rb_node *next = rb_first(root);
4882e538c4aSArnaldo Carvalho de Melo 	int kernel_range = 0;
4892e538c4aSArnaldo Carvalho de Melo 
4902e538c4aSArnaldo Carvalho de Melo 	while (next) {
4912e538c4aSArnaldo Carvalho de Melo 		char *module;
4922e538c4aSArnaldo Carvalho de Melo 
4932e538c4aSArnaldo Carvalho de Melo 		pos = rb_entry(next, struct symbol, rb_node);
4942e538c4aSArnaldo Carvalho de Melo 		next = rb_next(&pos->rb_node);
4952e538c4aSArnaldo Carvalho de Melo 
4962e538c4aSArnaldo Carvalho de Melo 		module = strchr(pos->name, '\t');
4972e538c4aSArnaldo Carvalho de Melo 		if (module) {
49875be6cf4SArnaldo Carvalho de Melo 			if (!symbol_conf.use_modules)
4991de8e245SArnaldo Carvalho de Melo 				goto discard_symbol;
5001de8e245SArnaldo Carvalho de Melo 
5012e538c4aSArnaldo Carvalho de Melo 			*module++ = '\0';
5022e538c4aSArnaldo Carvalho de Melo 
5034e06255fSArnaldo Carvalho de Melo 			if (strcmp(self->name, module)) {
5044aa65636SArnaldo Carvalho de Melo 				curr_map = map_groups__find_by_name(&session->kmaps, map->type, module);
5054e06255fSArnaldo Carvalho de Melo 				if (curr_map == NULL) {
50695011c60SArnaldo Carvalho de Melo 					pr_debug("/proc/{kallsyms,modules} "
5076beba7adSArnaldo Carvalho de Melo 					         "inconsistency!\n");
508af427bf5SArnaldo Carvalho de Melo 					return -1;
509af427bf5SArnaldo Carvalho de Melo 				}
510af427bf5SArnaldo Carvalho de Melo 			}
51186470930SIngo Molnar 			/*
5122e538c4aSArnaldo Carvalho de Melo 			 * So that we look just like we get from .ko files,
5132e538c4aSArnaldo Carvalho de Melo 			 * i.e. not prelinked, relative to map->start.
51486470930SIngo Molnar 			 */
5154e06255fSArnaldo Carvalho de Melo 			pos->start = curr_map->map_ip(curr_map, pos->start);
5164e06255fSArnaldo Carvalho de Melo 			pos->end   = curr_map->map_ip(curr_map, pos->end);
5174e06255fSArnaldo Carvalho de Melo 		} else if (curr_map != map) {
5182e538c4aSArnaldo Carvalho de Melo 			char dso_name[PATH_MAX];
5192e538c4aSArnaldo Carvalho de Melo 			struct dso *dso;
52086470930SIngo Molnar 
5212e538c4aSArnaldo Carvalho de Melo 			snprintf(dso_name, sizeof(dso_name), "[kernel].%d",
5222e538c4aSArnaldo Carvalho de Melo 				 kernel_range++);
52386470930SIngo Molnar 
52400a192b3SArnaldo Carvalho de Melo 			dso = dso__new(dso_name);
5252e538c4aSArnaldo Carvalho de Melo 			if (dso == NULL)
5262e538c4aSArnaldo Carvalho de Melo 				return -1;
5272e538c4aSArnaldo Carvalho de Melo 
5284e06255fSArnaldo Carvalho de Melo 			curr_map = map__new2(pos->start, dso, map->type);
5292e538c4aSArnaldo Carvalho de Melo 			if (map == NULL) {
5302e538c4aSArnaldo Carvalho de Melo 				dso__delete(dso);
5312e538c4aSArnaldo Carvalho de Melo 				return -1;
5322e538c4aSArnaldo Carvalho de Melo 			}
5332e538c4aSArnaldo Carvalho de Melo 
5344e06255fSArnaldo Carvalho de Melo 			curr_map->map_ip = curr_map->unmap_ip = identity__map_ip;
5354aa65636SArnaldo Carvalho de Melo 			map_groups__insert(&session->kmaps, curr_map);
5362e538c4aSArnaldo Carvalho de Melo 			++kernel_range;
5372e538c4aSArnaldo Carvalho de Melo 		}
5382e538c4aSArnaldo Carvalho de Melo 
5394e06255fSArnaldo Carvalho de Melo 		if (filter && filter(curr_map, pos)) {
5401de8e245SArnaldo Carvalho de Melo discard_symbol:		rb_erase(&pos->rb_node, root);
54100a192b3SArnaldo Carvalho de Melo 			symbol__delete(pos);
5422e538c4aSArnaldo Carvalho de Melo 		} else {
5434e06255fSArnaldo Carvalho de Melo 			if (curr_map != map) {
5444e06255fSArnaldo Carvalho de Melo 				rb_erase(&pos->rb_node, root);
5454e06255fSArnaldo Carvalho de Melo 				symbols__insert(&curr_map->dso->symbols[curr_map->type], pos);
5462e538c4aSArnaldo Carvalho de Melo 			}
5479974f496SMike Galbraith 			count++;
5489974f496SMike Galbraith 		}
54986470930SIngo Molnar 	}
55086470930SIngo Molnar 
5519974f496SMike Galbraith 	return count;
55286470930SIngo Molnar }
55386470930SIngo Molnar 
5542e538c4aSArnaldo Carvalho de Melo 
5554e06255fSArnaldo Carvalho de Melo static int dso__load_kallsyms(struct dso *self, struct map *map,
5564aa65636SArnaldo Carvalho de Melo 			      struct perf_session *session, symbol_filter_t filter)
5572e538c4aSArnaldo Carvalho de Melo {
5584e06255fSArnaldo Carvalho de Melo 	if (dso__load_all_kallsyms(self, map) < 0)
5592e538c4aSArnaldo Carvalho de Melo 		return -1;
5602e538c4aSArnaldo Carvalho de Melo 
5614e06255fSArnaldo Carvalho de Melo 	symbols__fixup_end(&self->symbols[map->type]);
5624e06255fSArnaldo Carvalho de Melo 	self->origin = DSO__ORIG_KERNEL;
5632e538c4aSArnaldo Carvalho de Melo 
5644aa65636SArnaldo Carvalho de Melo 	return dso__split_kallsyms(self, map, session, filter);
565af427bf5SArnaldo Carvalho de Melo }
566af427bf5SArnaldo Carvalho de Melo 
567439d473bSArnaldo Carvalho de Melo static int dso__load_perf_map(struct dso *self, struct map *map,
5686beba7adSArnaldo Carvalho de Melo 			      symbol_filter_t filter)
56980d496beSPekka Enberg {
57080d496beSPekka Enberg 	char *line = NULL;
57180d496beSPekka Enberg 	size_t n;
57280d496beSPekka Enberg 	FILE *file;
57380d496beSPekka Enberg 	int nr_syms = 0;
57480d496beSPekka Enberg 
575439d473bSArnaldo Carvalho de Melo 	file = fopen(self->long_name, "r");
57680d496beSPekka Enberg 	if (file == NULL)
57780d496beSPekka Enberg 		goto out_failure;
57880d496beSPekka Enberg 
57980d496beSPekka Enberg 	while (!feof(file)) {
5809cffa8d5SPaul Mackerras 		u64 start, size;
58180d496beSPekka Enberg 		struct symbol *sym;
58280d496beSPekka Enberg 		int line_len, len;
58380d496beSPekka Enberg 
58480d496beSPekka Enberg 		line_len = getline(&line, &n, file);
58580d496beSPekka Enberg 		if (line_len < 0)
58680d496beSPekka Enberg 			break;
58780d496beSPekka Enberg 
58880d496beSPekka Enberg 		if (!line)
58980d496beSPekka Enberg 			goto out_failure;
59080d496beSPekka Enberg 
59180d496beSPekka Enberg 		line[--line_len] = '\0'; /* \n */
59280d496beSPekka Enberg 
59380d496beSPekka Enberg 		len = hex2u64(line, &start);
59480d496beSPekka Enberg 
59580d496beSPekka Enberg 		len++;
59680d496beSPekka Enberg 		if (len + 2 >= line_len)
59780d496beSPekka Enberg 			continue;
59880d496beSPekka Enberg 
59980d496beSPekka Enberg 		len += hex2u64(line + len, &size);
60080d496beSPekka Enberg 
60180d496beSPekka Enberg 		len++;
60280d496beSPekka Enberg 		if (len + 2 >= line_len)
60380d496beSPekka Enberg 			continue;
60480d496beSPekka Enberg 
60500a192b3SArnaldo Carvalho de Melo 		sym = symbol__new(start, size, line + len);
60680d496beSPekka Enberg 
60780d496beSPekka Enberg 		if (sym == NULL)
60880d496beSPekka Enberg 			goto out_delete_line;
60980d496beSPekka Enberg 
610439d473bSArnaldo Carvalho de Melo 		if (filter && filter(map, sym))
61100a192b3SArnaldo Carvalho de Melo 			symbol__delete(sym);
61280d496beSPekka Enberg 		else {
6136a4694a4SArnaldo Carvalho de Melo 			symbols__insert(&self->symbols[map->type], sym);
61480d496beSPekka Enberg 			nr_syms++;
61580d496beSPekka Enberg 		}
61680d496beSPekka Enberg 	}
61780d496beSPekka Enberg 
61880d496beSPekka Enberg 	free(line);
61980d496beSPekka Enberg 	fclose(file);
62080d496beSPekka Enberg 
62180d496beSPekka Enberg 	return nr_syms;
62280d496beSPekka Enberg 
62380d496beSPekka Enberg out_delete_line:
62480d496beSPekka Enberg 	free(line);
62580d496beSPekka Enberg out_failure:
62680d496beSPekka Enberg 	return -1;
62780d496beSPekka Enberg }
62880d496beSPekka Enberg 
62986470930SIngo Molnar /**
63086470930SIngo Molnar  * elf_symtab__for_each_symbol - iterate thru all the symbols
63186470930SIngo Molnar  *
63286470930SIngo Molnar  * @self: struct elf_symtab instance to iterate
63383a0944fSIngo Molnar  * @idx: uint32_t idx
63486470930SIngo Molnar  * @sym: GElf_Sym iterator
63586470930SIngo Molnar  */
63683a0944fSIngo Molnar #define elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) \
63783a0944fSIngo Molnar 	for (idx = 0, gelf_getsym(syms, idx, &sym);\
63883a0944fSIngo Molnar 	     idx < nr_syms; \
63983a0944fSIngo Molnar 	     idx++, gelf_getsym(syms, idx, &sym))
64086470930SIngo Molnar 
64186470930SIngo Molnar static inline uint8_t elf_sym__type(const GElf_Sym *sym)
64286470930SIngo Molnar {
64386470930SIngo Molnar 	return GELF_ST_TYPE(sym->st_info);
64486470930SIngo Molnar }
64586470930SIngo Molnar 
64686470930SIngo Molnar static inline int elf_sym__is_function(const GElf_Sym *sym)
64786470930SIngo Molnar {
64886470930SIngo Molnar 	return elf_sym__type(sym) == STT_FUNC &&
64986470930SIngo Molnar 	       sym->st_name != 0 &&
65081833130SArnaldo Carvalho de Melo 	       sym->st_shndx != SHN_UNDEF;
65186470930SIngo Molnar }
65286470930SIngo Molnar 
653f1dfa0b1SArnaldo Carvalho de Melo static inline bool elf_sym__is_object(const GElf_Sym *sym)
654f1dfa0b1SArnaldo Carvalho de Melo {
655f1dfa0b1SArnaldo Carvalho de Melo 	return elf_sym__type(sym) == STT_OBJECT &&
656f1dfa0b1SArnaldo Carvalho de Melo 		sym->st_name != 0 &&
657f1dfa0b1SArnaldo Carvalho de Melo 		sym->st_shndx != SHN_UNDEF;
658f1dfa0b1SArnaldo Carvalho de Melo }
659f1dfa0b1SArnaldo Carvalho de Melo 
6606cfcc53eSMike Galbraith static inline int elf_sym__is_label(const GElf_Sym *sym)
6616cfcc53eSMike Galbraith {
6626cfcc53eSMike Galbraith 	return elf_sym__type(sym) == STT_NOTYPE &&
6636cfcc53eSMike Galbraith 		sym->st_name != 0 &&
6646cfcc53eSMike Galbraith 		sym->st_shndx != SHN_UNDEF &&
6656cfcc53eSMike Galbraith 		sym->st_shndx != SHN_ABS;
6666cfcc53eSMike Galbraith }
6676cfcc53eSMike Galbraith 
6686cfcc53eSMike Galbraith static inline const char *elf_sec__name(const GElf_Shdr *shdr,
6696cfcc53eSMike Galbraith 					const Elf_Data *secstrs)
6706cfcc53eSMike Galbraith {
6716cfcc53eSMike Galbraith 	return secstrs->d_buf + shdr->sh_name;
6726cfcc53eSMike Galbraith }
6736cfcc53eSMike Galbraith 
6746cfcc53eSMike Galbraith static inline int elf_sec__is_text(const GElf_Shdr *shdr,
6756cfcc53eSMike Galbraith 					const Elf_Data *secstrs)
6766cfcc53eSMike Galbraith {
6776cfcc53eSMike Galbraith 	return strstr(elf_sec__name(shdr, secstrs), "text") != NULL;
6786cfcc53eSMike Galbraith }
6796cfcc53eSMike Galbraith 
680f1dfa0b1SArnaldo Carvalho de Melo static inline bool elf_sec__is_data(const GElf_Shdr *shdr,
681f1dfa0b1SArnaldo Carvalho de Melo 				    const Elf_Data *secstrs)
682f1dfa0b1SArnaldo Carvalho de Melo {
683f1dfa0b1SArnaldo Carvalho de Melo 	return strstr(elf_sec__name(shdr, secstrs), "data") != NULL;
684f1dfa0b1SArnaldo Carvalho de Melo }
685f1dfa0b1SArnaldo Carvalho de Melo 
68686470930SIngo Molnar static inline const char *elf_sym__name(const GElf_Sym *sym,
68786470930SIngo Molnar 					const Elf_Data *symstrs)
68886470930SIngo Molnar {
68986470930SIngo Molnar 	return symstrs->d_buf + sym->st_name;
69086470930SIngo Molnar }
69186470930SIngo Molnar 
69286470930SIngo Molnar static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
69386470930SIngo Molnar 				    GElf_Shdr *shp, const char *name,
69483a0944fSIngo Molnar 				    size_t *idx)
69586470930SIngo Molnar {
69686470930SIngo Molnar 	Elf_Scn *sec = NULL;
69786470930SIngo Molnar 	size_t cnt = 1;
69886470930SIngo Molnar 
69986470930SIngo Molnar 	while ((sec = elf_nextscn(elf, sec)) != NULL) {
70086470930SIngo Molnar 		char *str;
70186470930SIngo Molnar 
70286470930SIngo Molnar 		gelf_getshdr(sec, shp);
70386470930SIngo Molnar 		str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name);
70486470930SIngo Molnar 		if (!strcmp(name, str)) {
70583a0944fSIngo Molnar 			if (idx)
70683a0944fSIngo Molnar 				*idx = cnt;
70786470930SIngo Molnar 			break;
70886470930SIngo Molnar 		}
70986470930SIngo Molnar 		++cnt;
71086470930SIngo Molnar 	}
71186470930SIngo Molnar 
71286470930SIngo Molnar 	return sec;
71386470930SIngo Molnar }
71486470930SIngo Molnar 
71586470930SIngo Molnar #define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \
71686470930SIngo Molnar 	for (idx = 0, pos = gelf_getrel(reldata, 0, &pos_mem); \
71786470930SIngo Molnar 	     idx < nr_entries; \
71886470930SIngo Molnar 	     ++idx, pos = gelf_getrel(reldata, idx, &pos_mem))
71986470930SIngo Molnar 
72086470930SIngo Molnar #define elf_section__for_each_rela(reldata, pos, pos_mem, idx, nr_entries) \
72186470930SIngo Molnar 	for (idx = 0, pos = gelf_getrela(reldata, 0, &pos_mem); \
72286470930SIngo Molnar 	     idx < nr_entries; \
72386470930SIngo Molnar 	     ++idx, pos = gelf_getrela(reldata, idx, &pos_mem))
72486470930SIngo Molnar 
725a25e46c4SArnaldo Carvalho de Melo /*
726a25e46c4SArnaldo Carvalho de Melo  * We need to check if we have a .dynsym, so that we can handle the
727a25e46c4SArnaldo Carvalho de Melo  * .plt, synthesizing its symbols, that aren't on the symtabs (be it
728a25e46c4SArnaldo Carvalho de Melo  * .dynsym or .symtab).
729a25e46c4SArnaldo Carvalho de Melo  * And always look at the original dso, not at debuginfo packages, that
730a25e46c4SArnaldo Carvalho de Melo  * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS).
731a25e46c4SArnaldo Carvalho de Melo  */
73282164161SArnaldo Carvalho de Melo static int dso__synthesize_plt_symbols(struct  dso *self, struct map *map,
73382164161SArnaldo Carvalho de Melo 				       symbol_filter_t filter)
73486470930SIngo Molnar {
73586470930SIngo Molnar 	uint32_t nr_rel_entries, idx;
73686470930SIngo Molnar 	GElf_Sym sym;
7379cffa8d5SPaul Mackerras 	u64 plt_offset;
73886470930SIngo Molnar 	GElf_Shdr shdr_plt;
73986470930SIngo Molnar 	struct symbol *f;
740a25e46c4SArnaldo Carvalho de Melo 	GElf_Shdr shdr_rel_plt, shdr_dynsym;
74186470930SIngo Molnar 	Elf_Data *reldata, *syms, *symstrs;
742a25e46c4SArnaldo Carvalho de Melo 	Elf_Scn *scn_plt_rel, *scn_symstrs, *scn_dynsym;
743a25e46c4SArnaldo Carvalho de Melo 	size_t dynsym_idx;
744a25e46c4SArnaldo Carvalho de Melo 	GElf_Ehdr ehdr;
74586470930SIngo Molnar 	char sympltname[1024];
746a25e46c4SArnaldo Carvalho de Melo 	Elf *elf;
747a25e46c4SArnaldo Carvalho de Melo 	int nr = 0, symidx, fd, err = 0;
74886470930SIngo Molnar 
749439d473bSArnaldo Carvalho de Melo 	fd = open(self->long_name, O_RDONLY);
750a25e46c4SArnaldo Carvalho de Melo 	if (fd < 0)
751a25e46c4SArnaldo Carvalho de Melo 		goto out;
752a25e46c4SArnaldo Carvalho de Melo 
75384087126SMarti Raudsepp 	elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
754a25e46c4SArnaldo Carvalho de Melo 	if (elf == NULL)
755a25e46c4SArnaldo Carvalho de Melo 		goto out_close;
756a25e46c4SArnaldo Carvalho de Melo 
757a25e46c4SArnaldo Carvalho de Melo 	if (gelf_getehdr(elf, &ehdr) == NULL)
758a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
759a25e46c4SArnaldo Carvalho de Melo 
760a25e46c4SArnaldo Carvalho de Melo 	scn_dynsym = elf_section_by_name(elf, &ehdr, &shdr_dynsym,
761a25e46c4SArnaldo Carvalho de Melo 					 ".dynsym", &dynsym_idx);
762a25e46c4SArnaldo Carvalho de Melo 	if (scn_dynsym == NULL)
763a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
764a25e46c4SArnaldo Carvalho de Melo 
765a25e46c4SArnaldo Carvalho de Melo 	scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
76686470930SIngo Molnar 					  ".rela.plt", NULL);
76786470930SIngo Molnar 	if (scn_plt_rel == NULL) {
768a25e46c4SArnaldo Carvalho de Melo 		scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
76986470930SIngo Molnar 						  ".rel.plt", NULL);
77086470930SIngo Molnar 		if (scn_plt_rel == NULL)
771a25e46c4SArnaldo Carvalho de Melo 			goto out_elf_end;
77286470930SIngo Molnar 	}
77386470930SIngo Molnar 
774a25e46c4SArnaldo Carvalho de Melo 	err = -1;
77586470930SIngo Molnar 
776a25e46c4SArnaldo Carvalho de Melo 	if (shdr_rel_plt.sh_link != dynsym_idx)
777a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
778a25e46c4SArnaldo Carvalho de Melo 
779a25e46c4SArnaldo Carvalho de Melo 	if (elf_section_by_name(elf, &ehdr, &shdr_plt, ".plt", NULL) == NULL)
780a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
78186470930SIngo Molnar 
78286470930SIngo Molnar 	/*
78383a0944fSIngo Molnar 	 * Fetch the relocation section to find the idxes to the GOT
78486470930SIngo Molnar 	 * and the symbols in the .dynsym they refer to.
78586470930SIngo Molnar 	 */
78686470930SIngo Molnar 	reldata = elf_getdata(scn_plt_rel, NULL);
78786470930SIngo Molnar 	if (reldata == NULL)
788a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
78986470930SIngo Molnar 
79086470930SIngo Molnar 	syms = elf_getdata(scn_dynsym, NULL);
79186470930SIngo Molnar 	if (syms == NULL)
792a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
79386470930SIngo Molnar 
794a25e46c4SArnaldo Carvalho de Melo 	scn_symstrs = elf_getscn(elf, shdr_dynsym.sh_link);
79586470930SIngo Molnar 	if (scn_symstrs == NULL)
796a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
79786470930SIngo Molnar 
79886470930SIngo Molnar 	symstrs = elf_getdata(scn_symstrs, NULL);
79986470930SIngo Molnar 	if (symstrs == NULL)
800a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
80186470930SIngo Molnar 
80286470930SIngo Molnar 	nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize;
80386470930SIngo Molnar 	plt_offset = shdr_plt.sh_offset;
80486470930SIngo Molnar 
80586470930SIngo Molnar 	if (shdr_rel_plt.sh_type == SHT_RELA) {
80686470930SIngo Molnar 		GElf_Rela pos_mem, *pos;
80786470930SIngo Molnar 
80886470930SIngo Molnar 		elf_section__for_each_rela(reldata, pos, pos_mem, idx,
80986470930SIngo Molnar 					   nr_rel_entries) {
81086470930SIngo Molnar 			symidx = GELF_R_SYM(pos->r_info);
81186470930SIngo Molnar 			plt_offset += shdr_plt.sh_entsize;
81286470930SIngo Molnar 			gelf_getsym(syms, symidx, &sym);
81386470930SIngo Molnar 			snprintf(sympltname, sizeof(sympltname),
81486470930SIngo Molnar 				 "%s@plt", elf_sym__name(&sym, symstrs));
81586470930SIngo Molnar 
81686470930SIngo Molnar 			f = symbol__new(plt_offset, shdr_plt.sh_entsize,
81700a192b3SArnaldo Carvalho de Melo 					sympltname);
81886470930SIngo Molnar 			if (!f)
819a25e46c4SArnaldo Carvalho de Melo 				goto out_elf_end;
82086470930SIngo Molnar 
82182164161SArnaldo Carvalho de Melo 			if (filter && filter(map, f))
82282164161SArnaldo Carvalho de Melo 				symbol__delete(f);
82382164161SArnaldo Carvalho de Melo 			else {
8246a4694a4SArnaldo Carvalho de Melo 				symbols__insert(&self->symbols[map->type], f);
82586470930SIngo Molnar 				++nr;
82686470930SIngo Molnar 			}
82782164161SArnaldo Carvalho de Melo 		}
82886470930SIngo Molnar 	} else if (shdr_rel_plt.sh_type == SHT_REL) {
82986470930SIngo Molnar 		GElf_Rel pos_mem, *pos;
83086470930SIngo Molnar 		elf_section__for_each_rel(reldata, pos, pos_mem, idx,
83186470930SIngo Molnar 					  nr_rel_entries) {
83286470930SIngo Molnar 			symidx = GELF_R_SYM(pos->r_info);
83386470930SIngo Molnar 			plt_offset += shdr_plt.sh_entsize;
83486470930SIngo Molnar 			gelf_getsym(syms, symidx, &sym);
83586470930SIngo Molnar 			snprintf(sympltname, sizeof(sympltname),
83686470930SIngo Molnar 				 "%s@plt", elf_sym__name(&sym, symstrs));
83786470930SIngo Molnar 
83886470930SIngo Molnar 			f = symbol__new(plt_offset, shdr_plt.sh_entsize,
83900a192b3SArnaldo Carvalho de Melo 					sympltname);
84086470930SIngo Molnar 			if (!f)
841a25e46c4SArnaldo Carvalho de Melo 				goto out_elf_end;
84286470930SIngo Molnar 
84382164161SArnaldo Carvalho de Melo 			if (filter && filter(map, f))
84482164161SArnaldo Carvalho de Melo 				symbol__delete(f);
84582164161SArnaldo Carvalho de Melo 			else {
8466a4694a4SArnaldo Carvalho de Melo 				symbols__insert(&self->symbols[map->type], f);
84786470930SIngo Molnar 				++nr;
84886470930SIngo Molnar 			}
84986470930SIngo Molnar 		}
85082164161SArnaldo Carvalho de Melo 	}
85186470930SIngo Molnar 
852a25e46c4SArnaldo Carvalho de Melo 	err = 0;
853a25e46c4SArnaldo Carvalho de Melo out_elf_end:
854a25e46c4SArnaldo Carvalho de Melo 	elf_end(elf);
855a25e46c4SArnaldo Carvalho de Melo out_close:
856a25e46c4SArnaldo Carvalho de Melo 	close(fd);
857a25e46c4SArnaldo Carvalho de Melo 
858a25e46c4SArnaldo Carvalho de Melo 	if (err == 0)
85986470930SIngo Molnar 		return nr;
860a25e46c4SArnaldo Carvalho de Melo out:
8616beba7adSArnaldo Carvalho de Melo 	pr_warning("%s: problems reading %s PLT info.\n",
862439d473bSArnaldo Carvalho de Melo 		   __func__, self->long_name);
863a25e46c4SArnaldo Carvalho de Melo 	return 0;
86486470930SIngo Molnar }
86586470930SIngo Molnar 
866d45868d3SArnaldo Carvalho de Melo static bool elf_sym__is_a(GElf_Sym *self, enum map_type type)
867d45868d3SArnaldo Carvalho de Melo {
868d45868d3SArnaldo Carvalho de Melo 	switch (type) {
869d45868d3SArnaldo Carvalho de Melo 	case MAP__FUNCTION:
870d45868d3SArnaldo Carvalho de Melo 		return elf_sym__is_function(self);
871f1dfa0b1SArnaldo Carvalho de Melo 	case MAP__VARIABLE:
872f1dfa0b1SArnaldo Carvalho de Melo 		return elf_sym__is_object(self);
873d45868d3SArnaldo Carvalho de Melo 	default:
874d45868d3SArnaldo Carvalho de Melo 		return false;
875d45868d3SArnaldo Carvalho de Melo 	}
876d45868d3SArnaldo Carvalho de Melo }
877d45868d3SArnaldo Carvalho de Melo 
878d45868d3SArnaldo Carvalho de Melo static bool elf_sec__is_a(GElf_Shdr *self, Elf_Data *secstrs, enum map_type type)
879d45868d3SArnaldo Carvalho de Melo {
880d45868d3SArnaldo Carvalho de Melo 	switch (type) {
881d45868d3SArnaldo Carvalho de Melo 	case MAP__FUNCTION:
882d45868d3SArnaldo Carvalho de Melo 		return elf_sec__is_text(self, secstrs);
883f1dfa0b1SArnaldo Carvalho de Melo 	case MAP__VARIABLE:
884f1dfa0b1SArnaldo Carvalho de Melo 		return elf_sec__is_data(self, secstrs);
885d45868d3SArnaldo Carvalho de Melo 	default:
886d45868d3SArnaldo Carvalho de Melo 		return false;
887d45868d3SArnaldo Carvalho de Melo 	}
888d45868d3SArnaldo Carvalho de Melo }
889d45868d3SArnaldo Carvalho de Melo 
89095011c60SArnaldo Carvalho de Melo static int dso__load_sym(struct dso *self, struct map *map,
8914aa65636SArnaldo Carvalho de Melo 			 struct perf_session *session, const char *name, int fd,
89295011c60SArnaldo Carvalho de Melo 			 symbol_filter_t filter, int kernel, int kmodule)
89386470930SIngo Molnar {
8942e538c4aSArnaldo Carvalho de Melo 	struct map *curr_map = map;
8952e538c4aSArnaldo Carvalho de Melo 	struct dso *curr_dso = self;
8962e538c4aSArnaldo Carvalho de Melo 	size_t dso_name_len = strlen(self->short_name);
8976cfcc53eSMike Galbraith 	Elf_Data *symstrs, *secstrs;
89886470930SIngo Molnar 	uint32_t nr_syms;
89986470930SIngo Molnar 	int err = -1;
90083a0944fSIngo Molnar 	uint32_t idx;
90186470930SIngo Molnar 	GElf_Ehdr ehdr;
90286470930SIngo Molnar 	GElf_Shdr shdr;
90386470930SIngo Molnar 	Elf_Data *syms;
90486470930SIngo Molnar 	GElf_Sym sym;
905a25e46c4SArnaldo Carvalho de Melo 	Elf_Scn *sec, *sec_strndx;
90686470930SIngo Molnar 	Elf *elf;
907439d473bSArnaldo Carvalho de Melo 	int nr = 0;
90886470930SIngo Molnar 
90984087126SMarti Raudsepp 	elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
91086470930SIngo Molnar 	if (elf == NULL) {
9116beba7adSArnaldo Carvalho de Melo 		pr_err("%s: cannot read %s ELF file.\n", __func__, name);
91286470930SIngo Molnar 		goto out_close;
91386470930SIngo Molnar 	}
91486470930SIngo Molnar 
91586470930SIngo Molnar 	if (gelf_getehdr(elf, &ehdr) == NULL) {
9166beba7adSArnaldo Carvalho de Melo 		pr_err("%s: cannot get elf header.\n", __func__);
91786470930SIngo Molnar 		goto out_elf_end;
91886470930SIngo Molnar 	}
91986470930SIngo Molnar 
92086470930SIngo Molnar 	sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL);
92186470930SIngo Molnar 	if (sec == NULL) {
922a25e46c4SArnaldo Carvalho de Melo 		sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL);
923a25e46c4SArnaldo Carvalho de Melo 		if (sec == NULL)
92486470930SIngo Molnar 			goto out_elf_end;
92586470930SIngo Molnar 	}
92686470930SIngo Molnar 
92786470930SIngo Molnar 	syms = elf_getdata(sec, NULL);
92886470930SIngo Molnar 	if (syms == NULL)
92986470930SIngo Molnar 		goto out_elf_end;
93086470930SIngo Molnar 
93186470930SIngo Molnar 	sec = elf_getscn(elf, shdr.sh_link);
93286470930SIngo Molnar 	if (sec == NULL)
93386470930SIngo Molnar 		goto out_elf_end;
93486470930SIngo Molnar 
93586470930SIngo Molnar 	symstrs = elf_getdata(sec, NULL);
93686470930SIngo Molnar 	if (symstrs == NULL)
93786470930SIngo Molnar 		goto out_elf_end;
93886470930SIngo Molnar 
9396cfcc53eSMike Galbraith 	sec_strndx = elf_getscn(elf, ehdr.e_shstrndx);
9406cfcc53eSMike Galbraith 	if (sec_strndx == NULL)
9416cfcc53eSMike Galbraith 		goto out_elf_end;
9426cfcc53eSMike Galbraith 
9436cfcc53eSMike Galbraith 	secstrs = elf_getdata(sec_strndx, NULL);
9449b30a26bSStoyan Gaydarov 	if (secstrs == NULL)
9456cfcc53eSMike Galbraith 		goto out_elf_end;
9466cfcc53eSMike Galbraith 
94786470930SIngo Molnar 	nr_syms = shdr.sh_size / shdr.sh_entsize;
94886470930SIngo Molnar 
949e9fbc9dcSArjan van de Ven 	memset(&sym, 0, sizeof(sym));
950d20ff6bdSMike Galbraith 	if (!kernel) {
95130d7a77dSArnaldo Carvalho de Melo 		self->adjust_symbols = (ehdr.e_type == ET_EXEC ||
95230d7a77dSArnaldo Carvalho de Melo 				elf_section_by_name(elf, &ehdr, &shdr,
953f5812a7aSArnaldo Carvalho de Melo 						     ".gnu.prelink_undo",
95430d7a77dSArnaldo Carvalho de Melo 						     NULL) != NULL);
955d20ff6bdSMike Galbraith 	} else self->adjust_symbols = 0;
956d20ff6bdSMike Galbraith 
95783a0944fSIngo Molnar 	elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) {
95886470930SIngo Molnar 		struct symbol *f;
95956b03f3cSArnaldo Carvalho de Melo 		const char *elf_name = elf_sym__name(&sym, symstrs);
9602e538c4aSArnaldo Carvalho de Melo 		char *demangled = NULL;
9616cfcc53eSMike Galbraith 		int is_label = elf_sym__is_label(&sym);
9626cfcc53eSMike Galbraith 		const char *section_name;
96386470930SIngo Molnar 
96456b03f3cSArnaldo Carvalho de Melo 		if (kernel && session->ref_reloc_sym.name != NULL &&
96556b03f3cSArnaldo Carvalho de Melo 		    strcmp(elf_name, session->ref_reloc_sym.name) == 0)
96656b03f3cSArnaldo Carvalho de Melo 			perf_session__reloc_vmlinux_maps(session, sym.st_value);
96756b03f3cSArnaldo Carvalho de Melo 
968d45868d3SArnaldo Carvalho de Melo 		if (!is_label && !elf_sym__is_a(&sym, map->type))
96986470930SIngo Molnar 			continue;
97086470930SIngo Molnar 
97186470930SIngo Molnar 		sec = elf_getscn(elf, sym.st_shndx);
97286470930SIngo Molnar 		if (!sec)
97386470930SIngo Molnar 			goto out_elf_end;
97486470930SIngo Molnar 
97586470930SIngo Molnar 		gelf_getshdr(sec, &shdr);
9766cfcc53eSMike Galbraith 
977d45868d3SArnaldo Carvalho de Melo 		if (is_label && !elf_sec__is_a(&shdr, secstrs, map->type))
9786cfcc53eSMike Galbraith 			continue;
9796cfcc53eSMike Galbraith 
9806cfcc53eSMike Galbraith 		section_name = elf_sec__name(&shdr, secstrs);
98186470930SIngo Molnar 
9822e538c4aSArnaldo Carvalho de Melo 		if (kernel || kmodule) {
9832e538c4aSArnaldo Carvalho de Melo 			char dso_name[PATH_MAX];
9842e538c4aSArnaldo Carvalho de Melo 
9852e538c4aSArnaldo Carvalho de Melo 			if (strcmp(section_name,
9862e538c4aSArnaldo Carvalho de Melo 				   curr_dso->short_name + dso_name_len) == 0)
9872e538c4aSArnaldo Carvalho de Melo 				goto new_symbol;
9882e538c4aSArnaldo Carvalho de Melo 
9892e538c4aSArnaldo Carvalho de Melo 			if (strcmp(section_name, ".text") == 0) {
9902e538c4aSArnaldo Carvalho de Melo 				curr_map = map;
9912e538c4aSArnaldo Carvalho de Melo 				curr_dso = self;
9922e538c4aSArnaldo Carvalho de Melo 				goto new_symbol;
993af427bf5SArnaldo Carvalho de Melo 			}
994af427bf5SArnaldo Carvalho de Melo 
9952e538c4aSArnaldo Carvalho de Melo 			snprintf(dso_name, sizeof(dso_name),
9962e538c4aSArnaldo Carvalho de Melo 				 "%s%s", self->short_name, section_name);
9972e538c4aSArnaldo Carvalho de Melo 
9984aa65636SArnaldo Carvalho de Melo 			curr_map = map_groups__find_by_name(&session->kmaps, map->type, dso_name);
9992e538c4aSArnaldo Carvalho de Melo 			if (curr_map == NULL) {
10002e538c4aSArnaldo Carvalho de Melo 				u64 start = sym.st_value;
10012e538c4aSArnaldo Carvalho de Melo 
10022e538c4aSArnaldo Carvalho de Melo 				if (kmodule)
10032e538c4aSArnaldo Carvalho de Melo 					start += map->start + shdr.sh_offset;
10042e538c4aSArnaldo Carvalho de Melo 
100500a192b3SArnaldo Carvalho de Melo 				curr_dso = dso__new(dso_name);
10062e538c4aSArnaldo Carvalho de Melo 				if (curr_dso == NULL)
10072e538c4aSArnaldo Carvalho de Melo 					goto out_elf_end;
10083610583cSArnaldo Carvalho de Melo 				curr_map = map__new2(start, curr_dso,
10093610583cSArnaldo Carvalho de Melo 						     MAP__FUNCTION);
10102e538c4aSArnaldo Carvalho de Melo 				if (curr_map == NULL) {
10112e538c4aSArnaldo Carvalho de Melo 					dso__delete(curr_dso);
10122e538c4aSArnaldo Carvalho de Melo 					goto out_elf_end;
10132e538c4aSArnaldo Carvalho de Melo 				}
1014ed52ce2eSArnaldo Carvalho de Melo 				curr_map->map_ip = identity__map_ip;
1015ed52ce2eSArnaldo Carvalho de Melo 				curr_map->unmap_ip = identity__map_ip;
10162e538c4aSArnaldo Carvalho de Melo 				curr_dso->origin = DSO__ORIG_KERNEL;
10174aa65636SArnaldo Carvalho de Melo 				map_groups__insert(&session->kmaps, curr_map);
1018b0da954aSArnaldo Carvalho de Melo 				dsos__add(&dsos__kernel, curr_dso);
10192e538c4aSArnaldo Carvalho de Melo 			} else
10202e538c4aSArnaldo Carvalho de Melo 				curr_dso = curr_map->dso;
10212e538c4aSArnaldo Carvalho de Melo 
10222e538c4aSArnaldo Carvalho de Melo 			goto new_symbol;
10232e538c4aSArnaldo Carvalho de Melo 		}
10242e538c4aSArnaldo Carvalho de Melo 
10252e538c4aSArnaldo Carvalho de Melo 		if (curr_dso->adjust_symbols) {
10266beba7adSArnaldo Carvalho de Melo 			pr_debug2("adjusting symbol: st_value: %Lx sh_addr: "
10276beba7adSArnaldo Carvalho de Melo 				  "%Lx sh_offset: %Lx\n", (u64)sym.st_value,
10286beba7adSArnaldo Carvalho de Melo 				  (u64)shdr.sh_addr, (u64)shdr.sh_offset);
102986470930SIngo Molnar 			sym.st_value -= shdr.sh_addr - shdr.sh_offset;
1030af427bf5SArnaldo Carvalho de Melo 		}
103128ac909bSArnaldo Carvalho de Melo 		/*
103228ac909bSArnaldo Carvalho de Melo 		 * We need to figure out if the object was created from C++ sources
103328ac909bSArnaldo Carvalho de Melo 		 * DWARF DW_compile_unit has this, but we don't always have access
103428ac909bSArnaldo Carvalho de Melo 		 * to it...
103528ac909bSArnaldo Carvalho de Melo 		 */
103683a0944fSIngo Molnar 		demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI);
103728ac909bSArnaldo Carvalho de Melo 		if (demangled != NULL)
103883a0944fSIngo Molnar 			elf_name = demangled;
10392e538c4aSArnaldo Carvalho de Melo new_symbol:
104000a192b3SArnaldo Carvalho de Melo 		f = symbol__new(sym.st_value, sym.st_size, elf_name);
104128ac909bSArnaldo Carvalho de Melo 		free(demangled);
104286470930SIngo Molnar 		if (!f)
104386470930SIngo Molnar 			goto out_elf_end;
104486470930SIngo Molnar 
10452e538c4aSArnaldo Carvalho de Melo 		if (filter && filter(curr_map, f))
104600a192b3SArnaldo Carvalho de Melo 			symbol__delete(f);
104786470930SIngo Molnar 		else {
10486a4694a4SArnaldo Carvalho de Melo 			symbols__insert(&curr_dso->symbols[curr_map->type], f);
104986470930SIngo Molnar 			nr++;
105086470930SIngo Molnar 		}
105186470930SIngo Molnar 	}
105286470930SIngo Molnar 
10532e538c4aSArnaldo Carvalho de Melo 	/*
10542e538c4aSArnaldo Carvalho de Melo 	 * For misannotated, zeroed, ASM function sizes.
10552e538c4aSArnaldo Carvalho de Melo 	 */
10562e538c4aSArnaldo Carvalho de Melo 	if (nr > 0)
10576a4694a4SArnaldo Carvalho de Melo 		symbols__fixup_end(&self->symbols[map->type]);
105886470930SIngo Molnar 	err = nr;
105986470930SIngo Molnar out_elf_end:
106086470930SIngo Molnar 	elf_end(elf);
106186470930SIngo Molnar out_close:
106286470930SIngo Molnar 	return err;
106386470930SIngo Molnar }
106486470930SIngo Molnar 
106578075caaSArnaldo Carvalho de Melo static bool dso__build_id_equal(const struct dso *self, u8 *build_id)
106678075caaSArnaldo Carvalho de Melo {
106778075caaSArnaldo Carvalho de Melo 	return memcmp(self->build_id, build_id, sizeof(self->build_id)) == 0;
106878075caaSArnaldo Carvalho de Melo }
106978075caaSArnaldo Carvalho de Melo 
1070b0da954aSArnaldo Carvalho de Melo static bool __dsos__read_build_ids(struct list_head *head)
107157f395a7SFrederic Weisbecker {
1072e30a3d12SArnaldo Carvalho de Melo 	bool have_build_id = false;
107357f395a7SFrederic Weisbecker 	struct dso *pos;
107457f395a7SFrederic Weisbecker 
1075b0da954aSArnaldo Carvalho de Melo 	list_for_each_entry(pos, head, node)
1076e30a3d12SArnaldo Carvalho de Melo 		if (filename__read_build_id(pos->long_name, pos->build_id,
1077e30a3d12SArnaldo Carvalho de Melo 					    sizeof(pos->build_id)) > 0) {
1078e30a3d12SArnaldo Carvalho de Melo 			have_build_id	  = true;
1079e30a3d12SArnaldo Carvalho de Melo 			pos->has_build_id = true;
108057f395a7SFrederic Weisbecker 		}
108157f395a7SFrederic Weisbecker 
1082e30a3d12SArnaldo Carvalho de Melo 	return have_build_id;
108357f395a7SFrederic Weisbecker }
108457f395a7SFrederic Weisbecker 
1085b0da954aSArnaldo Carvalho de Melo bool dsos__read_build_ids(void)
1086b0da954aSArnaldo Carvalho de Melo {
10878b4825bfSArnaldo Carvalho de Melo 	bool kbuildids = __dsos__read_build_ids(&dsos__kernel),
10888b4825bfSArnaldo Carvalho de Melo 	     ubuildids = __dsos__read_build_ids(&dsos__user);
10898b4825bfSArnaldo Carvalho de Melo 	return kbuildids || ubuildids;
1090b0da954aSArnaldo Carvalho de Melo }
1091b0da954aSArnaldo Carvalho de Melo 
1092fd7a346eSArnaldo Carvalho de Melo /*
1093fd7a346eSArnaldo Carvalho de Melo  * Align offset to 4 bytes as needed for note name and descriptor data.
1094fd7a346eSArnaldo Carvalho de Melo  */
1095fd7a346eSArnaldo Carvalho de Melo #define NOTE_ALIGN(n) (((n) + 3) & -4U)
1096fd7a346eSArnaldo Carvalho de Melo 
10972643ce11SArnaldo Carvalho de Melo int filename__read_build_id(const char *filename, void *bf, size_t size)
10984d1e00a8SArnaldo Carvalho de Melo {
10992643ce11SArnaldo Carvalho de Melo 	int fd, err = -1;
11004d1e00a8SArnaldo Carvalho de Melo 	GElf_Ehdr ehdr;
11014d1e00a8SArnaldo Carvalho de Melo 	GElf_Shdr shdr;
1102fd7a346eSArnaldo Carvalho de Melo 	Elf_Data *data;
11034d1e00a8SArnaldo Carvalho de Melo 	Elf_Scn *sec;
1104e57cfcdaSPekka Enberg 	Elf_Kind ek;
1105fd7a346eSArnaldo Carvalho de Melo 	void *ptr;
11064d1e00a8SArnaldo Carvalho de Melo 	Elf *elf;
11074d1e00a8SArnaldo Carvalho de Melo 
11082643ce11SArnaldo Carvalho de Melo 	if (size < BUILD_ID_SIZE)
11092643ce11SArnaldo Carvalho de Melo 		goto out;
11102643ce11SArnaldo Carvalho de Melo 
11112643ce11SArnaldo Carvalho de Melo 	fd = open(filename, O_RDONLY);
11124d1e00a8SArnaldo Carvalho de Melo 	if (fd < 0)
11134d1e00a8SArnaldo Carvalho de Melo 		goto out;
11144d1e00a8SArnaldo Carvalho de Melo 
111584087126SMarti Raudsepp 	elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
11164d1e00a8SArnaldo Carvalho de Melo 	if (elf == NULL) {
11178d06367fSArnaldo Carvalho de Melo 		pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename);
11184d1e00a8SArnaldo Carvalho de Melo 		goto out_close;
11194d1e00a8SArnaldo Carvalho de Melo 	}
11204d1e00a8SArnaldo Carvalho de Melo 
1121e57cfcdaSPekka Enberg 	ek = elf_kind(elf);
1122e57cfcdaSPekka Enberg 	if (ek != ELF_K_ELF)
1123e57cfcdaSPekka Enberg 		goto out_elf_end;
1124e57cfcdaSPekka Enberg 
11254d1e00a8SArnaldo Carvalho de Melo 	if (gelf_getehdr(elf, &ehdr) == NULL) {
11266beba7adSArnaldo Carvalho de Melo 		pr_err("%s: cannot get elf header.\n", __func__);
11274d1e00a8SArnaldo Carvalho de Melo 		goto out_elf_end;
11284d1e00a8SArnaldo Carvalho de Melo 	}
11294d1e00a8SArnaldo Carvalho de Melo 
11302643ce11SArnaldo Carvalho de Melo 	sec = elf_section_by_name(elf, &ehdr, &shdr,
11312643ce11SArnaldo Carvalho de Melo 				  ".note.gnu.build-id", NULL);
1132fd7a346eSArnaldo Carvalho de Melo 	if (sec == NULL) {
1133fd7a346eSArnaldo Carvalho de Melo 		sec = elf_section_by_name(elf, &ehdr, &shdr,
1134fd7a346eSArnaldo Carvalho de Melo 					  ".notes", NULL);
11354d1e00a8SArnaldo Carvalho de Melo 		if (sec == NULL)
11364d1e00a8SArnaldo Carvalho de Melo 			goto out_elf_end;
1137fd7a346eSArnaldo Carvalho de Melo 	}
11384d1e00a8SArnaldo Carvalho de Melo 
1139fd7a346eSArnaldo Carvalho de Melo 	data = elf_getdata(sec, NULL);
1140fd7a346eSArnaldo Carvalho de Melo 	if (data == NULL)
11414d1e00a8SArnaldo Carvalho de Melo 		goto out_elf_end;
1142fd7a346eSArnaldo Carvalho de Melo 
1143fd7a346eSArnaldo Carvalho de Melo 	ptr = data->d_buf;
1144fd7a346eSArnaldo Carvalho de Melo 	while (ptr < (data->d_buf + data->d_size)) {
1145fd7a346eSArnaldo Carvalho de Melo 		GElf_Nhdr *nhdr = ptr;
1146fd7a346eSArnaldo Carvalho de Melo 		int namesz = NOTE_ALIGN(nhdr->n_namesz),
1147fd7a346eSArnaldo Carvalho de Melo 		    descsz = NOTE_ALIGN(nhdr->n_descsz);
1148fd7a346eSArnaldo Carvalho de Melo 		const char *name;
1149fd7a346eSArnaldo Carvalho de Melo 
1150fd7a346eSArnaldo Carvalho de Melo 		ptr += sizeof(*nhdr);
1151fd7a346eSArnaldo Carvalho de Melo 		name = ptr;
1152fd7a346eSArnaldo Carvalho de Melo 		ptr += namesz;
1153fd7a346eSArnaldo Carvalho de Melo 		if (nhdr->n_type == NT_GNU_BUILD_ID &&
1154fd7a346eSArnaldo Carvalho de Melo 		    nhdr->n_namesz == sizeof("GNU")) {
1155fd7a346eSArnaldo Carvalho de Melo 			if (memcmp(name, "GNU", sizeof("GNU")) == 0) {
1156fd7a346eSArnaldo Carvalho de Melo 				memcpy(bf, ptr, BUILD_ID_SIZE);
11572643ce11SArnaldo Carvalho de Melo 				err = BUILD_ID_SIZE;
1158fd7a346eSArnaldo Carvalho de Melo 				break;
1159fd7a346eSArnaldo Carvalho de Melo 			}
1160fd7a346eSArnaldo Carvalho de Melo 		}
1161fd7a346eSArnaldo Carvalho de Melo 		ptr += descsz;
1162fd7a346eSArnaldo Carvalho de Melo 	}
11632643ce11SArnaldo Carvalho de Melo out_elf_end:
11642643ce11SArnaldo Carvalho de Melo 	elf_end(elf);
11652643ce11SArnaldo Carvalho de Melo out_close:
11662643ce11SArnaldo Carvalho de Melo 	close(fd);
11672643ce11SArnaldo Carvalho de Melo out:
11682643ce11SArnaldo Carvalho de Melo 	return err;
11692643ce11SArnaldo Carvalho de Melo }
11702643ce11SArnaldo Carvalho de Melo 
1171f1617b40SArnaldo Carvalho de Melo int sysfs__read_build_id(const char *filename, void *build_id, size_t size)
1172f1617b40SArnaldo Carvalho de Melo {
1173f1617b40SArnaldo Carvalho de Melo 	int fd, err = -1;
1174f1617b40SArnaldo Carvalho de Melo 
1175f1617b40SArnaldo Carvalho de Melo 	if (size < BUILD_ID_SIZE)
1176f1617b40SArnaldo Carvalho de Melo 		goto out;
1177f1617b40SArnaldo Carvalho de Melo 
1178f1617b40SArnaldo Carvalho de Melo 	fd = open(filename, O_RDONLY);
1179f1617b40SArnaldo Carvalho de Melo 	if (fd < 0)
1180f1617b40SArnaldo Carvalho de Melo 		goto out;
1181f1617b40SArnaldo Carvalho de Melo 
1182f1617b40SArnaldo Carvalho de Melo 	while (1) {
1183f1617b40SArnaldo Carvalho de Melo 		char bf[BUFSIZ];
1184f1617b40SArnaldo Carvalho de Melo 		GElf_Nhdr nhdr;
1185f1617b40SArnaldo Carvalho de Melo 		int namesz, descsz;
1186f1617b40SArnaldo Carvalho de Melo 
1187f1617b40SArnaldo Carvalho de Melo 		if (read(fd, &nhdr, sizeof(nhdr)) != sizeof(nhdr))
1188f1617b40SArnaldo Carvalho de Melo 			break;
1189f1617b40SArnaldo Carvalho de Melo 
1190fd7a346eSArnaldo Carvalho de Melo 		namesz = NOTE_ALIGN(nhdr.n_namesz);
1191fd7a346eSArnaldo Carvalho de Melo 		descsz = NOTE_ALIGN(nhdr.n_descsz);
1192f1617b40SArnaldo Carvalho de Melo 		if (nhdr.n_type == NT_GNU_BUILD_ID &&
1193f1617b40SArnaldo Carvalho de Melo 		    nhdr.n_namesz == sizeof("GNU")) {
1194f1617b40SArnaldo Carvalho de Melo 			if (read(fd, bf, namesz) != namesz)
1195f1617b40SArnaldo Carvalho de Melo 				break;
1196f1617b40SArnaldo Carvalho de Melo 			if (memcmp(bf, "GNU", sizeof("GNU")) == 0) {
1197f1617b40SArnaldo Carvalho de Melo 				if (read(fd, build_id,
1198f1617b40SArnaldo Carvalho de Melo 				    BUILD_ID_SIZE) == BUILD_ID_SIZE) {
1199f1617b40SArnaldo Carvalho de Melo 					err = 0;
1200f1617b40SArnaldo Carvalho de Melo 					break;
1201f1617b40SArnaldo Carvalho de Melo 				}
1202f1617b40SArnaldo Carvalho de Melo 			} else if (read(fd, bf, descsz) != descsz)
1203f1617b40SArnaldo Carvalho de Melo 				break;
1204f1617b40SArnaldo Carvalho de Melo 		} else {
1205f1617b40SArnaldo Carvalho de Melo 			int n = namesz + descsz;
1206f1617b40SArnaldo Carvalho de Melo 			if (read(fd, bf, n) != n)
1207f1617b40SArnaldo Carvalho de Melo 				break;
1208f1617b40SArnaldo Carvalho de Melo 		}
1209f1617b40SArnaldo Carvalho de Melo 	}
1210f1617b40SArnaldo Carvalho de Melo 	close(fd);
1211f1617b40SArnaldo Carvalho de Melo out:
1212f1617b40SArnaldo Carvalho de Melo 	return err;
1213f1617b40SArnaldo Carvalho de Melo }
1214f1617b40SArnaldo Carvalho de Melo 
121594cb9e38SArnaldo Carvalho de Melo char dso__symtab_origin(const struct dso *self)
121694cb9e38SArnaldo Carvalho de Melo {
121794cb9e38SArnaldo Carvalho de Melo 	static const char origin[] = {
121894cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_KERNEL] =   'k',
121994cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_JAVA_JIT] = 'j',
12204cf40131SArnaldo Carvalho de Melo 		[DSO__ORIG_BUILD_ID_CACHE] = 'B',
122194cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_FEDORA] =   'f',
122294cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_UBUNTU] =   'u',
122394cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_BUILDID] =  'b',
122494cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_DSO] =      'd',
1225439d473bSArnaldo Carvalho de Melo 		[DSO__ORIG_KMODULE] =  'K',
122694cb9e38SArnaldo Carvalho de Melo 	};
122794cb9e38SArnaldo Carvalho de Melo 
122894cb9e38SArnaldo Carvalho de Melo 	if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND)
122994cb9e38SArnaldo Carvalho de Melo 		return '!';
123094cb9e38SArnaldo Carvalho de Melo 	return origin[self->origin];
123194cb9e38SArnaldo Carvalho de Melo }
123294cb9e38SArnaldo Carvalho de Melo 
12334aa65636SArnaldo Carvalho de Melo int dso__load(struct dso *self, struct map *map, struct perf_session *session,
12344aa65636SArnaldo Carvalho de Melo 	      symbol_filter_t filter)
123586470930SIngo Molnar {
12364d1e00a8SArnaldo Carvalho de Melo 	int size = PATH_MAX;
1237c338aee8SArnaldo Carvalho de Melo 	char *name;
1238d3379ab9SArnaldo Carvalho de Melo 	u8 build_id[BUILD_ID_SIZE];
12394cf40131SArnaldo Carvalho de Melo 	char build_id_hex[BUILD_ID_SIZE * 2 + 1];
124086470930SIngo Molnar 	int ret = -1;
124186470930SIngo Molnar 	int fd;
124286470930SIngo Molnar 
12433610583cSArnaldo Carvalho de Melo 	dso__set_loaded(self, map->type);
124466bd8424SArnaldo Carvalho de Melo 
1245c338aee8SArnaldo Carvalho de Melo 	if (self->kernel)
12464aa65636SArnaldo Carvalho de Melo 		return dso__load_kernel_sym(self, map, session, filter);
1247c338aee8SArnaldo Carvalho de Melo 
1248c338aee8SArnaldo Carvalho de Melo 	name = malloc(size);
124986470930SIngo Molnar 	if (!name)
125086470930SIngo Molnar 		return -1;
125186470930SIngo Molnar 
125230d7a77dSArnaldo Carvalho de Melo 	self->adjust_symbols = 0;
1253f5812a7aSArnaldo Carvalho de Melo 
125494cb9e38SArnaldo Carvalho de Melo 	if (strncmp(self->name, "/tmp/perf-", 10) == 0) {
12556beba7adSArnaldo Carvalho de Melo 		ret = dso__load_perf_map(self, map, filter);
125694cb9e38SArnaldo Carvalho de Melo 		self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT :
125794cb9e38SArnaldo Carvalho de Melo 					 DSO__ORIG_NOT_FOUND;
125894cb9e38SArnaldo Carvalho de Melo 		return ret;
125994cb9e38SArnaldo Carvalho de Melo 	}
126094cb9e38SArnaldo Carvalho de Melo 
12614cf40131SArnaldo Carvalho de Melo 	self->origin = DSO__ORIG_BUILD_ID_CACHE;
126280d496beSPekka Enberg 
12634cf40131SArnaldo Carvalho de Melo 	if (self->has_build_id) {
12644cf40131SArnaldo Carvalho de Melo 		build_id__sprintf(self->build_id, sizeof(self->build_id),
12654cf40131SArnaldo Carvalho de Melo 				  build_id_hex);
12664cf40131SArnaldo Carvalho de Melo 		snprintf(name, size, "%s/%s/.build-id/%.2s/%s",
12674cf40131SArnaldo Carvalho de Melo 			 getenv("HOME"), DEBUG_CACHE_DIR,
12684cf40131SArnaldo Carvalho de Melo 			 build_id_hex, build_id_hex + 2);
12694cf40131SArnaldo Carvalho de Melo 		goto open_file;
12704cf40131SArnaldo Carvalho de Melo 	}
127186470930SIngo Molnar more:
127286470930SIngo Molnar 	do {
127394cb9e38SArnaldo Carvalho de Melo 		self->origin++;
127494cb9e38SArnaldo Carvalho de Melo 		switch (self->origin) {
127594cb9e38SArnaldo Carvalho de Melo 		case DSO__ORIG_FEDORA:
1276439d473bSArnaldo Carvalho de Melo 			snprintf(name, size, "/usr/lib/debug%s.debug",
1277439d473bSArnaldo Carvalho de Melo 				 self->long_name);
127886470930SIngo Molnar 			break;
127994cb9e38SArnaldo Carvalho de Melo 		case DSO__ORIG_UBUNTU:
1280439d473bSArnaldo Carvalho de Melo 			snprintf(name, size, "/usr/lib/debug%s",
1281439d473bSArnaldo Carvalho de Melo 				 self->long_name);
128286470930SIngo Molnar 			break;
128394cb9e38SArnaldo Carvalho de Melo 		case DSO__ORIG_BUILDID:
1284d3379ab9SArnaldo Carvalho de Melo 			if (filename__read_build_id(self->long_name, build_id,
1285d3379ab9SArnaldo Carvalho de Melo 						    sizeof(build_id))) {
1286d3379ab9SArnaldo Carvalho de Melo 				build_id__sprintf(build_id, sizeof(build_id),
1287d3379ab9SArnaldo Carvalho de Melo 						  build_id_hex);
12884d1e00a8SArnaldo Carvalho de Melo 				snprintf(name, size,
12894d1e00a8SArnaldo Carvalho de Melo 					 "/usr/lib/debug/.build-id/%.2s/%s.debug",
1290d3379ab9SArnaldo Carvalho de Melo 					build_id_hex, build_id_hex + 2);
1291d3379ab9SArnaldo Carvalho de Melo 				if (self->has_build_id)
12928d06367fSArnaldo Carvalho de Melo 					goto compare_build_id;
1293d3379ab9SArnaldo Carvalho de Melo 				break;
12944d1e00a8SArnaldo Carvalho de Melo 			}
129594cb9e38SArnaldo Carvalho de Melo 			self->origin++;
12964d1e00a8SArnaldo Carvalho de Melo 			/* Fall thru */
129794cb9e38SArnaldo Carvalho de Melo 		case DSO__ORIG_DSO:
1298439d473bSArnaldo Carvalho de Melo 			snprintf(name, size, "%s", self->long_name);
129986470930SIngo Molnar 			break;
130086470930SIngo Molnar 
130186470930SIngo Molnar 		default:
130286470930SIngo Molnar 			goto out;
130386470930SIngo Molnar 		}
130486470930SIngo Molnar 
13058d06367fSArnaldo Carvalho de Melo 		if (self->has_build_id) {
1306d3379ab9SArnaldo Carvalho de Melo 			if (filename__read_build_id(name, build_id,
1307d3379ab9SArnaldo Carvalho de Melo 						    sizeof(build_id)) < 0)
13088d06367fSArnaldo Carvalho de Melo 				goto more;
13098d06367fSArnaldo Carvalho de Melo compare_build_id:
131078075caaSArnaldo Carvalho de Melo 			if (!dso__build_id_equal(self, build_id))
13118d06367fSArnaldo Carvalho de Melo 				goto more;
13128d06367fSArnaldo Carvalho de Melo 		}
13134cf40131SArnaldo Carvalho de Melo open_file:
131486470930SIngo Molnar 		fd = open(name, O_RDONLY);
131586470930SIngo Molnar 	} while (fd < 0);
131686470930SIngo Molnar 
131795011c60SArnaldo Carvalho de Melo 	ret = dso__load_sym(self, map, NULL, name, fd, filter, 0, 0);
131886470930SIngo Molnar 	close(fd);
131986470930SIngo Molnar 
132086470930SIngo Molnar 	/*
132186470930SIngo Molnar 	 * Some people seem to have debuginfo files _WITHOUT_ debug info!?!?
132286470930SIngo Molnar 	 */
132386470930SIngo Molnar 	if (!ret)
132486470930SIngo Molnar 		goto more;
132586470930SIngo Molnar 
1326a25e46c4SArnaldo Carvalho de Melo 	if (ret > 0) {
132782164161SArnaldo Carvalho de Melo 		int nr_plt = dso__synthesize_plt_symbols(self, map, filter);
1328a25e46c4SArnaldo Carvalho de Melo 		if (nr_plt > 0)
1329a25e46c4SArnaldo Carvalho de Melo 			ret += nr_plt;
1330a25e46c4SArnaldo Carvalho de Melo 	}
133186470930SIngo Molnar out:
133286470930SIngo Molnar 	free(name);
13331340e6bbSArnaldo Carvalho de Melo 	if (ret < 0 && strstr(self->name, " (deleted)") != NULL)
13341340e6bbSArnaldo Carvalho de Melo 		return 0;
133586470930SIngo Molnar 	return ret;
133686470930SIngo Molnar }
133786470930SIngo Molnar 
133879406cd7SArnaldo Carvalho de Melo struct map *map_groups__find_by_name(struct map_groups *self,
133979406cd7SArnaldo Carvalho de Melo 				     enum map_type type, const char *name)
1340439d473bSArnaldo Carvalho de Melo {
1341439d473bSArnaldo Carvalho de Melo 	struct rb_node *nd;
1342439d473bSArnaldo Carvalho de Melo 
134379406cd7SArnaldo Carvalho de Melo 	for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) {
1344439d473bSArnaldo Carvalho de Melo 		struct map *map = rb_entry(nd, struct map, rb_node);
1345439d473bSArnaldo Carvalho de Melo 
1346439d473bSArnaldo Carvalho de Melo 		if (map->dso && strcmp(map->dso->name, name) == 0)
1347439d473bSArnaldo Carvalho de Melo 			return map;
1348439d473bSArnaldo Carvalho de Melo 	}
1349439d473bSArnaldo Carvalho de Melo 
1350439d473bSArnaldo Carvalho de Melo 	return NULL;
1351439d473bSArnaldo Carvalho de Melo }
1352439d473bSArnaldo Carvalho de Melo 
13534aa65636SArnaldo Carvalho de Melo static int perf_session__set_modules_path_dir(struct perf_session *self, char *dirname)
13546cfcc53eSMike Galbraith {
1355439d473bSArnaldo Carvalho de Melo 	struct dirent *dent;
1356439d473bSArnaldo Carvalho de Melo 	DIR *dir = opendir(dirname);
13576cfcc53eSMike Galbraith 
1358439d473bSArnaldo Carvalho de Melo 	if (!dir) {
135987f8ea4cSArnaldo Carvalho de Melo 		pr_debug("%s: cannot open %s dir\n", __func__, dirname);
1360439d473bSArnaldo Carvalho de Melo 		return -1;
1361439d473bSArnaldo Carvalho de Melo 	}
13626cfcc53eSMike Galbraith 
1363439d473bSArnaldo Carvalho de Melo 	while ((dent = readdir(dir)) != NULL) {
1364439d473bSArnaldo Carvalho de Melo 		char path[PATH_MAX];
1365439d473bSArnaldo Carvalho de Melo 
1366439d473bSArnaldo Carvalho de Melo 		if (dent->d_type == DT_DIR) {
1367439d473bSArnaldo Carvalho de Melo 			if (!strcmp(dent->d_name, ".") ||
1368439d473bSArnaldo Carvalho de Melo 			    !strcmp(dent->d_name, ".."))
1369439d473bSArnaldo Carvalho de Melo 				continue;
1370439d473bSArnaldo Carvalho de Melo 
1371439d473bSArnaldo Carvalho de Melo 			snprintf(path, sizeof(path), "%s/%s",
1372439d473bSArnaldo Carvalho de Melo 				 dirname, dent->d_name);
13734aa65636SArnaldo Carvalho de Melo 			if (perf_session__set_modules_path_dir(self, path) < 0)
1374439d473bSArnaldo Carvalho de Melo 				goto failure;
1375439d473bSArnaldo Carvalho de Melo 		} else {
1376439d473bSArnaldo Carvalho de Melo 			char *dot = strrchr(dent->d_name, '.'),
1377439d473bSArnaldo Carvalho de Melo 			     dso_name[PATH_MAX];
1378439d473bSArnaldo Carvalho de Melo 			struct map *map;
1379cfc10d3bSArnaldo Carvalho de Melo 			char *long_name;
1380439d473bSArnaldo Carvalho de Melo 
1381439d473bSArnaldo Carvalho de Melo 			if (dot == NULL || strcmp(dot, ".ko"))
1382439d473bSArnaldo Carvalho de Melo 				continue;
1383439d473bSArnaldo Carvalho de Melo 			snprintf(dso_name, sizeof(dso_name), "[%.*s]",
1384439d473bSArnaldo Carvalho de Melo 				 (int)(dot - dent->d_name), dent->d_name);
1385439d473bSArnaldo Carvalho de Melo 
1386a2a99e8eSArnaldo Carvalho de Melo 			strxfrchar(dso_name, '-', '_');
13874aa65636SArnaldo Carvalho de Melo 			map = map_groups__find_by_name(&self->kmaps, MAP__FUNCTION, dso_name);
1388439d473bSArnaldo Carvalho de Melo 			if (map == NULL)
1389439d473bSArnaldo Carvalho de Melo 				continue;
1390439d473bSArnaldo Carvalho de Melo 
1391439d473bSArnaldo Carvalho de Melo 			snprintf(path, sizeof(path), "%s/%s",
1392439d473bSArnaldo Carvalho de Melo 				 dirname, dent->d_name);
1393439d473bSArnaldo Carvalho de Melo 
1394cfc10d3bSArnaldo Carvalho de Melo 			long_name = strdup(path);
1395cfc10d3bSArnaldo Carvalho de Melo 			if (long_name == NULL)
1396439d473bSArnaldo Carvalho de Melo 				goto failure;
1397cfc10d3bSArnaldo Carvalho de Melo 			dso__set_long_name(map->dso, long_name);
1398439d473bSArnaldo Carvalho de Melo 		}
1399439d473bSArnaldo Carvalho de Melo 	}
1400439d473bSArnaldo Carvalho de Melo 
1401c338aee8SArnaldo Carvalho de Melo 	return 0;
1402439d473bSArnaldo Carvalho de Melo failure:
1403439d473bSArnaldo Carvalho de Melo 	closedir(dir);
1404439d473bSArnaldo Carvalho de Melo 	return -1;
1405439d473bSArnaldo Carvalho de Melo }
1406439d473bSArnaldo Carvalho de Melo 
14074aa65636SArnaldo Carvalho de Melo static int perf_session__set_modules_path(struct perf_session *self)
1408439d473bSArnaldo Carvalho de Melo {
1409439d473bSArnaldo Carvalho de Melo 	struct utsname uts;
1410439d473bSArnaldo Carvalho de Melo 	char modules_path[PATH_MAX];
1411439d473bSArnaldo Carvalho de Melo 
1412439d473bSArnaldo Carvalho de Melo 	if (uname(&uts) < 0)
1413439d473bSArnaldo Carvalho de Melo 		return -1;
1414439d473bSArnaldo Carvalho de Melo 
1415439d473bSArnaldo Carvalho de Melo 	snprintf(modules_path, sizeof(modules_path), "/lib/modules/%s/kernel",
1416439d473bSArnaldo Carvalho de Melo 		 uts.release);
1417439d473bSArnaldo Carvalho de Melo 
14184aa65636SArnaldo Carvalho de Melo 	return perf_session__set_modules_path_dir(self, modules_path);
1419439d473bSArnaldo Carvalho de Melo }
14206cfcc53eSMike Galbraith 
14216cfcc53eSMike Galbraith /*
1422439d473bSArnaldo Carvalho de Melo  * Constructor variant for modules (where we know from /proc/modules where
1423439d473bSArnaldo Carvalho de Melo  * they are loaded) and for vmlinux, where only after we load all the
1424439d473bSArnaldo Carvalho de Melo  * symbols we'll know where it starts and ends.
14256cfcc53eSMike Galbraith  */
14263610583cSArnaldo Carvalho de Melo static struct map *map__new2(u64 start, struct dso *dso, enum map_type type)
1427439d473bSArnaldo Carvalho de Melo {
1428439d473bSArnaldo Carvalho de Melo 	struct map *self = malloc(sizeof(*self));
14296cfcc53eSMike Galbraith 
1430439d473bSArnaldo Carvalho de Melo 	if (self != NULL) {
1431439d473bSArnaldo Carvalho de Melo 		/*
1432afb7b4f0SArnaldo Carvalho de Melo 		 * ->end will be filled after we load all the symbols
1433439d473bSArnaldo Carvalho de Melo 		 */
14343610583cSArnaldo Carvalho de Melo 		map__init(self, type, start, 0, 0, dso);
1435439d473bSArnaldo Carvalho de Melo 	}
1436afb7b4f0SArnaldo Carvalho de Melo 
1437439d473bSArnaldo Carvalho de Melo 	return self;
1438439d473bSArnaldo Carvalho de Melo }
1439439d473bSArnaldo Carvalho de Melo 
14404aa65636SArnaldo Carvalho de Melo static int perf_session__create_module_maps(struct perf_session *self)
1441439d473bSArnaldo Carvalho de Melo {
1442439d473bSArnaldo Carvalho de Melo 	char *line = NULL;
1443439d473bSArnaldo Carvalho de Melo 	size_t n;
1444439d473bSArnaldo Carvalho de Melo 	FILE *file = fopen("/proc/modules", "r");
1445439d473bSArnaldo Carvalho de Melo 	struct map *map;
1446439d473bSArnaldo Carvalho de Melo 
1447439d473bSArnaldo Carvalho de Melo 	if (file == NULL)
1448439d473bSArnaldo Carvalho de Melo 		return -1;
1449439d473bSArnaldo Carvalho de Melo 
1450439d473bSArnaldo Carvalho de Melo 	while (!feof(file)) {
1451439d473bSArnaldo Carvalho de Melo 		char name[PATH_MAX];
1452439d473bSArnaldo Carvalho de Melo 		u64 start;
1453439d473bSArnaldo Carvalho de Melo 		struct dso *dso;
1454439d473bSArnaldo Carvalho de Melo 		char *sep;
1455439d473bSArnaldo Carvalho de Melo 		int line_len;
1456439d473bSArnaldo Carvalho de Melo 
1457439d473bSArnaldo Carvalho de Melo 		line_len = getline(&line, &n, file);
1458439d473bSArnaldo Carvalho de Melo 		if (line_len < 0)
14596cfcc53eSMike Galbraith 			break;
14606cfcc53eSMike Galbraith 
1461439d473bSArnaldo Carvalho de Melo 		if (!line)
1462439d473bSArnaldo Carvalho de Melo 			goto out_failure;
1463439d473bSArnaldo Carvalho de Melo 
1464439d473bSArnaldo Carvalho de Melo 		line[--line_len] = '\0'; /* \n */
1465439d473bSArnaldo Carvalho de Melo 
1466439d473bSArnaldo Carvalho de Melo 		sep = strrchr(line, 'x');
1467439d473bSArnaldo Carvalho de Melo 		if (sep == NULL)
1468439d473bSArnaldo Carvalho de Melo 			continue;
1469439d473bSArnaldo Carvalho de Melo 
1470439d473bSArnaldo Carvalho de Melo 		hex2u64(sep + 1, &start);
1471439d473bSArnaldo Carvalho de Melo 
1472439d473bSArnaldo Carvalho de Melo 		sep = strchr(line, ' ');
1473439d473bSArnaldo Carvalho de Melo 		if (sep == NULL)
1474439d473bSArnaldo Carvalho de Melo 			continue;
1475439d473bSArnaldo Carvalho de Melo 
1476439d473bSArnaldo Carvalho de Melo 		*sep = '\0';
1477439d473bSArnaldo Carvalho de Melo 
1478439d473bSArnaldo Carvalho de Melo 		snprintf(name, sizeof(name), "[%s]", line);
147900a192b3SArnaldo Carvalho de Melo 		dso = dso__new(name);
1480439d473bSArnaldo Carvalho de Melo 
1481439d473bSArnaldo Carvalho de Melo 		if (dso == NULL)
1482439d473bSArnaldo Carvalho de Melo 			goto out_delete_line;
1483439d473bSArnaldo Carvalho de Melo 
14843610583cSArnaldo Carvalho de Melo 		map = map__new2(start, dso, MAP__FUNCTION);
1485439d473bSArnaldo Carvalho de Melo 		if (map == NULL) {
1486439d473bSArnaldo Carvalho de Melo 			dso__delete(dso);
1487439d473bSArnaldo Carvalho de Melo 			goto out_delete_line;
14886cfcc53eSMike Galbraith 		}
14896cfcc53eSMike Galbraith 
1490f1617b40SArnaldo Carvalho de Melo 		snprintf(name, sizeof(name),
1491f1617b40SArnaldo Carvalho de Melo 			 "/sys/module/%s/notes/.note.gnu.build-id", line);
1492f1617b40SArnaldo Carvalho de Melo 		if (sysfs__read_build_id(name, dso->build_id,
1493f1617b40SArnaldo Carvalho de Melo 					 sizeof(dso->build_id)) == 0)
1494f1617b40SArnaldo Carvalho de Melo 			dso->has_build_id = true;
1495f1617b40SArnaldo Carvalho de Melo 
1496439d473bSArnaldo Carvalho de Melo 		dso->origin = DSO__ORIG_KMODULE;
14974aa65636SArnaldo Carvalho de Melo 		map_groups__insert(&self->kmaps, map);
1498b0da954aSArnaldo Carvalho de Melo 		dsos__add(&dsos__kernel, dso);
14996cfcc53eSMike Galbraith 	}
15006cfcc53eSMike Galbraith 
1501439d473bSArnaldo Carvalho de Melo 	free(line);
1502439d473bSArnaldo Carvalho de Melo 	fclose(file);
1503439d473bSArnaldo Carvalho de Melo 
15044aa65636SArnaldo Carvalho de Melo 	return perf_session__set_modules_path(self);
1505439d473bSArnaldo Carvalho de Melo 
1506439d473bSArnaldo Carvalho de Melo out_delete_line:
1507439d473bSArnaldo Carvalho de Melo 	free(line);
1508439d473bSArnaldo Carvalho de Melo out_failure:
1509439d473bSArnaldo Carvalho de Melo 	return -1;
15106cfcc53eSMike Galbraith }
15116cfcc53eSMike Galbraith 
15129958e1f0SArnaldo Carvalho de Melo static int dso__load_vmlinux(struct dso *self, struct map *map,
15134aa65636SArnaldo Carvalho de Melo 			     struct perf_session *session,
15146beba7adSArnaldo Carvalho de Melo 			     const char *vmlinux, symbol_filter_t filter)
151586470930SIngo Molnar {
1516fbd733b8SArnaldo Carvalho de Melo 	int err = -1, fd;
151786470930SIngo Molnar 
1518fbd733b8SArnaldo Carvalho de Melo 	if (self->has_build_id) {
1519fbd733b8SArnaldo Carvalho de Melo 		u8 build_id[BUILD_ID_SIZE];
152066bd8424SArnaldo Carvalho de Melo 
1521fbd733b8SArnaldo Carvalho de Melo 		if (filename__read_build_id(vmlinux, build_id,
1522fbd733b8SArnaldo Carvalho de Melo 					    sizeof(build_id)) < 0) {
1523fbd733b8SArnaldo Carvalho de Melo 			pr_debug("No build_id in %s, ignoring it\n", vmlinux);
1524fbd733b8SArnaldo Carvalho de Melo 			return -1;
1525fbd733b8SArnaldo Carvalho de Melo 		}
1526fbd733b8SArnaldo Carvalho de Melo 		if (!dso__build_id_equal(self, build_id)) {
1527fbd733b8SArnaldo Carvalho de Melo 			char expected_build_id[BUILD_ID_SIZE * 2 + 1],
1528fbd733b8SArnaldo Carvalho de Melo 			     vmlinux_build_id[BUILD_ID_SIZE * 2 + 1];
1529fbd733b8SArnaldo Carvalho de Melo 
1530fbd733b8SArnaldo Carvalho de Melo 			build_id__sprintf(self->build_id,
1531fbd733b8SArnaldo Carvalho de Melo 					  sizeof(self->build_id),
1532fbd733b8SArnaldo Carvalho de Melo 					  expected_build_id);
1533fbd733b8SArnaldo Carvalho de Melo 			build_id__sprintf(build_id, sizeof(build_id),
1534fbd733b8SArnaldo Carvalho de Melo 					  vmlinux_build_id);
1535fbd733b8SArnaldo Carvalho de Melo 			pr_debug("build_id in %s is %s while expected is %s, "
1536fbd733b8SArnaldo Carvalho de Melo 				 "ignoring it\n", vmlinux, vmlinux_build_id,
1537fbd733b8SArnaldo Carvalho de Melo 				 expected_build_id);
1538fbd733b8SArnaldo Carvalho de Melo 			return -1;
1539fbd733b8SArnaldo Carvalho de Melo 		}
1540fbd733b8SArnaldo Carvalho de Melo 	}
1541fbd733b8SArnaldo Carvalho de Melo 
1542fbd733b8SArnaldo Carvalho de Melo 	fd = open(vmlinux, O_RDONLY);
154386470930SIngo Molnar 	if (fd < 0)
154486470930SIngo Molnar 		return -1;
154586470930SIngo Molnar 
15463610583cSArnaldo Carvalho de Melo 	dso__set_loaded(self, map->type);
15474aa65636SArnaldo Carvalho de Melo 	err = dso__load_sym(self, map, session, self->long_name, fd, filter, 1, 0);
154886470930SIngo Molnar 	close(fd);
154986470930SIngo Molnar 
155086470930SIngo Molnar 	return err;
155186470930SIngo Molnar }
155286470930SIngo Molnar 
1553c338aee8SArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *self, struct map *map,
15544aa65636SArnaldo Carvalho de Melo 				struct perf_session *session, symbol_filter_t filter)
155586470930SIngo Molnar {
1556cc612d81SArnaldo Carvalho de Melo 	int err;
1557cc612d81SArnaldo Carvalho de Melo 	bool is_kallsyms;
1558439d473bSArnaldo Carvalho de Melo 
1559cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path != NULL) {
1560cc612d81SArnaldo Carvalho de Melo 		int i;
1561cc612d81SArnaldo Carvalho de Melo 		pr_debug("Looking at the vmlinux_path (%d entries long)\n",
1562cc612d81SArnaldo Carvalho de Melo 			 vmlinux_path__nr_entries);
1563cc612d81SArnaldo Carvalho de Melo 		for (i = 0; i < vmlinux_path__nr_entries; ++i) {
15644aa65636SArnaldo Carvalho de Melo 			err = dso__load_vmlinux(self, map, session,
156595011c60SArnaldo Carvalho de Melo 						vmlinux_path[i], filter);
1566cc612d81SArnaldo Carvalho de Melo 			if (err > 0) {
1567cc612d81SArnaldo Carvalho de Melo 				pr_debug("Using %s for symbols\n",
1568cc612d81SArnaldo Carvalho de Melo 					 vmlinux_path[i]);
1569cc612d81SArnaldo Carvalho de Melo 				dso__set_long_name(self,
1570cc612d81SArnaldo Carvalho de Melo 						   strdup(vmlinux_path[i]));
1571cc612d81SArnaldo Carvalho de Melo 				goto out_fixup;
1572cc612d81SArnaldo Carvalho de Melo 			}
1573cc612d81SArnaldo Carvalho de Melo 		}
1574cc612d81SArnaldo Carvalho de Melo 	}
1575cc612d81SArnaldo Carvalho de Melo 
1576cc612d81SArnaldo Carvalho de Melo 	is_kallsyms = self->long_name[0] == '[';
1577cc612d81SArnaldo Carvalho de Melo 	if (is_kallsyms)
1578cc612d81SArnaldo Carvalho de Melo 		goto do_kallsyms;
1579cc612d81SArnaldo Carvalho de Melo 
15804aa65636SArnaldo Carvalho de Melo 	err = dso__load_vmlinux(self, map, session, self->long_name, filter);
1581ef6ae724SArnaldo Carvalho de Melo 	if (err <= 0) {
1582cc612d81SArnaldo Carvalho de Melo 		pr_info("The file %s cannot be used, "
1583cc612d81SArnaldo Carvalho de Melo 			"trying to use /proc/kallsyms...", self->long_name);
1584cc612d81SArnaldo Carvalho de Melo do_kallsyms:
15854aa65636SArnaldo Carvalho de Melo 		err = dso__load_kallsyms(self, map, session, filter);
1586cc612d81SArnaldo Carvalho de Melo 		if (err > 0 && !is_kallsyms)
1587ef6ae724SArnaldo Carvalho de Melo                         dso__set_long_name(self, strdup("[kernel.kallsyms]"));
1588ef6ae724SArnaldo Carvalho de Melo 	}
158986470930SIngo Molnar 
1590439d473bSArnaldo Carvalho de Melo 	if (err > 0) {
1591cc612d81SArnaldo Carvalho de Melo out_fixup:
15926a4694a4SArnaldo Carvalho de Melo 		map__fixup_start(map);
15936a4694a4SArnaldo Carvalho de Melo 		map__fixup_end(map);
1594439d473bSArnaldo Carvalho de Melo 	}
159594cb9e38SArnaldo Carvalho de Melo 
159686470930SIngo Molnar 	return err;
159786470930SIngo Molnar }
159886470930SIngo Molnar 
1599b0da954aSArnaldo Carvalho de Melo LIST_HEAD(dsos__user);
1600b0da954aSArnaldo Carvalho de Melo LIST_HEAD(dsos__kernel);
1601cd84c2acSFrederic Weisbecker struct dso *vdso;
1602cd84c2acSFrederic Weisbecker 
1603b0da954aSArnaldo Carvalho de Melo static void dsos__add(struct list_head *head, struct dso *dso)
1604cd84c2acSFrederic Weisbecker {
1605b0da954aSArnaldo Carvalho de Melo 	list_add_tail(&dso->node, head);
1606cd84c2acSFrederic Weisbecker }
1607cd84c2acSFrederic Weisbecker 
1608b0da954aSArnaldo Carvalho de Melo static struct dso *dsos__find(struct list_head *head, const char *name)
1609cd84c2acSFrederic Weisbecker {
1610cd84c2acSFrederic Weisbecker 	struct dso *pos;
1611cd84c2acSFrederic Weisbecker 
1612b0da954aSArnaldo Carvalho de Melo 	list_for_each_entry(pos, head, node)
1613cd84c2acSFrederic Weisbecker 		if (strcmp(pos->name, name) == 0)
1614cd84c2acSFrederic Weisbecker 			return pos;
1615cd84c2acSFrederic Weisbecker 	return NULL;
1616cd84c2acSFrederic Weisbecker }
1617cd84c2acSFrederic Weisbecker 
1618*a89e5abeSArnaldo Carvalho de Melo struct dso *__dsos__findnew(struct list_head *head, const char *name)
1619cd84c2acSFrederic Weisbecker {
1620*a89e5abeSArnaldo Carvalho de Melo 	struct dso *dso = dsos__find(head, name);
1621cd84c2acSFrederic Weisbecker 
1622e4204992SArnaldo Carvalho de Melo 	if (!dso) {
162300a192b3SArnaldo Carvalho de Melo 		dso = dso__new(name);
1624cfc10d3bSArnaldo Carvalho de Melo 		if (dso != NULL) {
1625*a89e5abeSArnaldo Carvalho de Melo 			dsos__add(head, dso);
1626cfc10d3bSArnaldo Carvalho de Melo 			dso__set_basename(dso);
1627cfc10d3bSArnaldo Carvalho de Melo 		}
1628e4204992SArnaldo Carvalho de Melo 	}
1629cd84c2acSFrederic Weisbecker 
1630cd84c2acSFrederic Weisbecker 	return dso;
1631cd84c2acSFrederic Weisbecker }
1632cd84c2acSFrederic Weisbecker 
1633b0da954aSArnaldo Carvalho de Melo static void __dsos__fprintf(struct list_head *head, FILE *fp)
1634cd84c2acSFrederic Weisbecker {
1635cd84c2acSFrederic Weisbecker 	struct dso *pos;
1636cd84c2acSFrederic Weisbecker 
163795011c60SArnaldo Carvalho de Melo 	list_for_each_entry(pos, head, node) {
163895011c60SArnaldo Carvalho de Melo 		int i;
163995011c60SArnaldo Carvalho de Melo 		for (i = 0; i < MAP__NR_TYPES; ++i)
164095011c60SArnaldo Carvalho de Melo 			dso__fprintf(pos, i, fp);
164195011c60SArnaldo Carvalho de Melo 	}
1642cd84c2acSFrederic Weisbecker }
1643cd84c2acSFrederic Weisbecker 
1644b0da954aSArnaldo Carvalho de Melo void dsos__fprintf(FILE *fp)
1645b0da954aSArnaldo Carvalho de Melo {
1646b0da954aSArnaldo Carvalho de Melo 	__dsos__fprintf(&dsos__kernel, fp);
1647b0da954aSArnaldo Carvalho de Melo 	__dsos__fprintf(&dsos__user, fp);
1648b0da954aSArnaldo Carvalho de Melo }
1649b0da954aSArnaldo Carvalho de Melo 
1650b0da954aSArnaldo Carvalho de Melo static size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp)
16519e03eb2dSArnaldo Carvalho de Melo {
16529e03eb2dSArnaldo Carvalho de Melo 	struct dso *pos;
16539e03eb2dSArnaldo Carvalho de Melo 	size_t ret = 0;
16549e03eb2dSArnaldo Carvalho de Melo 
1655b0da954aSArnaldo Carvalho de Melo 	list_for_each_entry(pos, head, node) {
16569e03eb2dSArnaldo Carvalho de Melo 		ret += dso__fprintf_buildid(pos, fp);
16579e03eb2dSArnaldo Carvalho de Melo 		ret += fprintf(fp, " %s\n", pos->long_name);
16589e03eb2dSArnaldo Carvalho de Melo 	}
16599e03eb2dSArnaldo Carvalho de Melo 	return ret;
16609e03eb2dSArnaldo Carvalho de Melo }
16619e03eb2dSArnaldo Carvalho de Melo 
1662b0da954aSArnaldo Carvalho de Melo size_t dsos__fprintf_buildid(FILE *fp)
1663b0da954aSArnaldo Carvalho de Melo {
1664b0da954aSArnaldo Carvalho de Melo 	return (__dsos__fprintf_buildid(&dsos__kernel, fp) +
1665b0da954aSArnaldo Carvalho de Melo 		__dsos__fprintf_buildid(&dsos__user, fp));
1666b0da954aSArnaldo Carvalho de Melo }
1667b0da954aSArnaldo Carvalho de Melo 
1668f1dfa0b1SArnaldo Carvalho de Melo static struct dso *dsos__create_kernel(const char *vmlinux)
1669cd84c2acSFrederic Weisbecker {
167095011c60SArnaldo Carvalho de Melo 	struct dso *kernel = dso__new(vmlinux ?: "[kernel.kallsyms]");
1671cd84c2acSFrederic Weisbecker 
16722446042cSArnaldo Carvalho de Melo 	if (kernel == NULL)
1673f1dfa0b1SArnaldo Carvalho de Melo 		return NULL;
1674c338aee8SArnaldo Carvalho de Melo 
16752446042cSArnaldo Carvalho de Melo 	kernel->short_name = "[kernel]";
1676c338aee8SArnaldo Carvalho de Melo 	kernel->kernel	   = 1;
1677cc612d81SArnaldo Carvalho de Melo 
167800a192b3SArnaldo Carvalho de Melo 	vdso = dso__new("[vdso]");
1679c338aee8SArnaldo Carvalho de Melo 	if (vdso == NULL)
1680f1dfa0b1SArnaldo Carvalho de Melo 		goto out_delete_kernel_dso;
16813610583cSArnaldo Carvalho de Melo 	dso__set_loaded(vdso, MAP__FUNCTION);
1682cd84c2acSFrederic Weisbecker 
16832446042cSArnaldo Carvalho de Melo 	if (sysfs__read_build_id("/sys/kernel/notes", kernel->build_id,
16842446042cSArnaldo Carvalho de Melo 				 sizeof(kernel->build_id)) == 0)
16852446042cSArnaldo Carvalho de Melo 		kernel->has_build_id = true;
16862446042cSArnaldo Carvalho de Melo 
1687b0da954aSArnaldo Carvalho de Melo 	dsos__add(&dsos__kernel, kernel);
1688b0da954aSArnaldo Carvalho de Melo 	dsos__add(&dsos__user, vdso);
1689cd84c2acSFrederic Weisbecker 
1690f1dfa0b1SArnaldo Carvalho de Melo 	return kernel;
1691c338aee8SArnaldo Carvalho de Melo 
1692c338aee8SArnaldo Carvalho de Melo out_delete_kernel_dso:
1693c338aee8SArnaldo Carvalho de Melo 	dso__delete(kernel);
1694f1dfa0b1SArnaldo Carvalho de Melo 	return NULL;
1695f1dfa0b1SArnaldo Carvalho de Melo }
1696f1dfa0b1SArnaldo Carvalho de Melo 
1697de176489SArnaldo Carvalho de Melo static int map_groups__create_kernel_maps(struct map_groups *self,
1698de176489SArnaldo Carvalho de Melo 					  struct map *vmlinux_maps[MAP__NR_TYPES],
1699de176489SArnaldo Carvalho de Melo 					  const char *vmlinux)
1700f1dfa0b1SArnaldo Carvalho de Melo {
1701f1dfa0b1SArnaldo Carvalho de Melo 	struct dso *kernel = dsos__create_kernel(vmlinux);
1702de176489SArnaldo Carvalho de Melo 	enum map_type type;
1703f1dfa0b1SArnaldo Carvalho de Melo 
1704f1dfa0b1SArnaldo Carvalho de Melo 	if (kernel == NULL)
1705c338aee8SArnaldo Carvalho de Melo 		return -1;
1706f1dfa0b1SArnaldo Carvalho de Melo 
1707de176489SArnaldo Carvalho de Melo 	for (type = 0; type < MAP__NR_TYPES; ++type) {
1708de176489SArnaldo Carvalho de Melo 		vmlinux_maps[type] = map__new2(0, kernel, type);
1709de176489SArnaldo Carvalho de Melo 		if (vmlinux_maps[type] == NULL)
1710f1dfa0b1SArnaldo Carvalho de Melo 			return -1;
1711f1dfa0b1SArnaldo Carvalho de Melo 
1712de176489SArnaldo Carvalho de Melo 		vmlinux_maps[type]->map_ip =
1713de176489SArnaldo Carvalho de Melo 			vmlinux_maps[type]->unmap_ip = identity__map_ip;
1714de176489SArnaldo Carvalho de Melo 		map_groups__insert(self, vmlinux_maps[type]);
1715f1dfa0b1SArnaldo Carvalho de Melo 	}
1716f1dfa0b1SArnaldo Carvalho de Melo 
1717f1dfa0b1SArnaldo Carvalho de Melo 	return 0;
17182446042cSArnaldo Carvalho de Melo }
17192446042cSArnaldo Carvalho de Melo 
1720cc612d81SArnaldo Carvalho de Melo static void vmlinux_path__exit(void)
17212446042cSArnaldo Carvalho de Melo {
1722cc612d81SArnaldo Carvalho de Melo 	while (--vmlinux_path__nr_entries >= 0) {
1723cc612d81SArnaldo Carvalho de Melo 		free(vmlinux_path[vmlinux_path__nr_entries]);
1724cc612d81SArnaldo Carvalho de Melo 		vmlinux_path[vmlinux_path__nr_entries] = NULL;
1725cc612d81SArnaldo Carvalho de Melo 	}
1726cc612d81SArnaldo Carvalho de Melo 
1727cc612d81SArnaldo Carvalho de Melo 	free(vmlinux_path);
1728cc612d81SArnaldo Carvalho de Melo 	vmlinux_path = NULL;
1729cc612d81SArnaldo Carvalho de Melo }
1730cc612d81SArnaldo Carvalho de Melo 
1731cc612d81SArnaldo Carvalho de Melo static int vmlinux_path__init(void)
1732cc612d81SArnaldo Carvalho de Melo {
1733cc612d81SArnaldo Carvalho de Melo 	struct utsname uts;
1734cc612d81SArnaldo Carvalho de Melo 	char bf[PATH_MAX];
1735cc612d81SArnaldo Carvalho de Melo 
1736cc612d81SArnaldo Carvalho de Melo 	if (uname(&uts) < 0)
17372446042cSArnaldo Carvalho de Melo 		return -1;
17382446042cSArnaldo Carvalho de Melo 
1739cc612d81SArnaldo Carvalho de Melo 	vmlinux_path = malloc(sizeof(char *) * 5);
1740cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path == NULL)
1741cc612d81SArnaldo Carvalho de Melo 		return -1;
1742cc612d81SArnaldo Carvalho de Melo 
1743cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup("vmlinux");
1744cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1745cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
1746cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
1747cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup("/boot/vmlinux");
1748cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1749cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
1750cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
1751cc612d81SArnaldo Carvalho de Melo 	snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", uts.release);
1752cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1753cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1754cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
1755cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
1756cc612d81SArnaldo Carvalho de Melo 	snprintf(bf, sizeof(bf), "/lib/modules/%s/build/vmlinux", uts.release);
1757cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1758cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1759cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
1760cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
1761cc612d81SArnaldo Carvalho de Melo 	snprintf(bf, sizeof(bf), "/usr/lib/debug/lib/modules/%s/vmlinux",
1762cc612d81SArnaldo Carvalho de Melo 		 uts.release);
1763cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1764cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1765cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
1766cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
1767cc612d81SArnaldo Carvalho de Melo 
1768cc612d81SArnaldo Carvalho de Melo 	return 0;
1769cc612d81SArnaldo Carvalho de Melo 
1770cc612d81SArnaldo Carvalho de Melo out_fail:
1771cc612d81SArnaldo Carvalho de Melo 	vmlinux_path__exit();
1772cc612d81SArnaldo Carvalho de Melo 	return -1;
1773cc612d81SArnaldo Carvalho de Melo }
1774cc612d81SArnaldo Carvalho de Melo 
1775655000e7SArnaldo Carvalho de Melo static int setup_list(struct strlist **list, const char *list_str,
1776655000e7SArnaldo Carvalho de Melo 		      const char *list_name)
1777655000e7SArnaldo Carvalho de Melo {
1778655000e7SArnaldo Carvalho de Melo 	if (list_str == NULL)
1779655000e7SArnaldo Carvalho de Melo 		return 0;
1780655000e7SArnaldo Carvalho de Melo 
1781655000e7SArnaldo Carvalho de Melo 	*list = strlist__new(true, list_str);
1782655000e7SArnaldo Carvalho de Melo 	if (!*list) {
1783655000e7SArnaldo Carvalho de Melo 		pr_err("problems parsing %s list\n", list_name);
1784655000e7SArnaldo Carvalho de Melo 		return -1;
1785655000e7SArnaldo Carvalho de Melo 	}
1786655000e7SArnaldo Carvalho de Melo 	return 0;
1787655000e7SArnaldo Carvalho de Melo }
1788655000e7SArnaldo Carvalho de Melo 
178975be6cf4SArnaldo Carvalho de Melo int symbol__init(void)
1790cc612d81SArnaldo Carvalho de Melo {
179195011c60SArnaldo Carvalho de Melo 	elf_version(EV_CURRENT);
179275be6cf4SArnaldo Carvalho de Melo 	if (symbol_conf.sort_by_name)
179375be6cf4SArnaldo Carvalho de Melo 		symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) -
179479406cd7SArnaldo Carvalho de Melo 					  sizeof(struct symbol));
1795b32d133aSArnaldo Carvalho de Melo 
179675be6cf4SArnaldo Carvalho de Melo 	if (symbol_conf.try_vmlinux_path && vmlinux_path__init() < 0)
1797cc612d81SArnaldo Carvalho de Melo 		return -1;
1798cc612d81SArnaldo Carvalho de Melo 
1799c410a338SArnaldo Carvalho de Melo 	if (symbol_conf.field_sep && *symbol_conf.field_sep == '.') {
1800c410a338SArnaldo Carvalho de Melo 		pr_err("'.' is the only non valid --field-separator argument\n");
1801c410a338SArnaldo Carvalho de Melo 		return -1;
1802c410a338SArnaldo Carvalho de Melo 	}
1803c410a338SArnaldo Carvalho de Melo 
1804655000e7SArnaldo Carvalho de Melo 	if (setup_list(&symbol_conf.dso_list,
1805655000e7SArnaldo Carvalho de Melo 		       symbol_conf.dso_list_str, "dso") < 0)
1806655000e7SArnaldo Carvalho de Melo 		return -1;
1807655000e7SArnaldo Carvalho de Melo 
1808655000e7SArnaldo Carvalho de Melo 	if (setup_list(&symbol_conf.comm_list,
1809655000e7SArnaldo Carvalho de Melo 		       symbol_conf.comm_list_str, "comm") < 0)
1810655000e7SArnaldo Carvalho de Melo 		goto out_free_dso_list;
1811655000e7SArnaldo Carvalho de Melo 
1812655000e7SArnaldo Carvalho de Melo 	if (setup_list(&symbol_conf.sym_list,
1813655000e7SArnaldo Carvalho de Melo 		       symbol_conf.sym_list_str, "symbol") < 0)
1814655000e7SArnaldo Carvalho de Melo 		goto out_free_comm_list;
1815655000e7SArnaldo Carvalho de Melo 
18164aa65636SArnaldo Carvalho de Melo 	return 0;
1817655000e7SArnaldo Carvalho de Melo 
1818655000e7SArnaldo Carvalho de Melo out_free_dso_list:
1819655000e7SArnaldo Carvalho de Melo 	strlist__delete(symbol_conf.dso_list);
1820655000e7SArnaldo Carvalho de Melo out_free_comm_list:
1821655000e7SArnaldo Carvalho de Melo 	strlist__delete(symbol_conf.comm_list);
1822655000e7SArnaldo Carvalho de Melo 	return -1;
1823cc612d81SArnaldo Carvalho de Melo }
1824cc612d81SArnaldo Carvalho de Melo 
182575be6cf4SArnaldo Carvalho de Melo int perf_session__create_kernel_maps(struct perf_session *self)
18264aa65636SArnaldo Carvalho de Melo {
1827de176489SArnaldo Carvalho de Melo 	if (map_groups__create_kernel_maps(&self->kmaps, self->vmlinux_maps,
182875be6cf4SArnaldo Carvalho de Melo 					   symbol_conf.vmlinux_name) < 0)
18294aa65636SArnaldo Carvalho de Melo 		return -1;
18304aa65636SArnaldo Carvalho de Melo 
183175be6cf4SArnaldo Carvalho de Melo 	if (symbol_conf.use_modules &&
183275be6cf4SArnaldo Carvalho de Melo 	    perf_session__create_module_maps(self) < 0)
18334aa65636SArnaldo Carvalho de Melo 		pr_debug("Failed to load list of modules for session %s, "
18344aa65636SArnaldo Carvalho de Melo 			 "continuing...\n", self->filename);
183590c83218SArnaldo Carvalho de Melo 	/*
183690c83218SArnaldo Carvalho de Melo 	 * Now that we have all the maps created, just set the ->end of them:
183790c83218SArnaldo Carvalho de Melo 	 */
18384aa65636SArnaldo Carvalho de Melo 	map_groups__fixup_end(&self->kmaps);
18396671cb16SArnaldo Carvalho de Melo 	return 0;
1840cd84c2acSFrederic Weisbecker }
1841