xref: /linux/tools/perf/util/symbol.c (revision 696b97a5d2de9e2b22699300835e675dfffe8592)
15aab621bSArnaldo Carvalho de Melo #define _GNU_SOURCE
25aab621bSArnaldo Carvalho de Melo #include <ctype.h>
35aab621bSArnaldo Carvalho de Melo #include <dirent.h>
45aab621bSArnaldo Carvalho de Melo #include <errno.h>
55aab621bSArnaldo Carvalho de Melo #include <libgen.h>
65aab621bSArnaldo Carvalho de Melo #include <stdlib.h>
75aab621bSArnaldo Carvalho de Melo #include <stdio.h>
85aab621bSArnaldo Carvalho de Melo #include <string.h>
95aab621bSArnaldo Carvalho de Melo #include <sys/types.h>
105aab621bSArnaldo Carvalho de Melo #include <sys/stat.h>
115aab621bSArnaldo Carvalho de Melo #include <sys/param.h>
125aab621bSArnaldo Carvalho de Melo #include <fcntl.h>
135aab621bSArnaldo Carvalho de Melo #include <unistd.h>
14b36f19d5SArnaldo Carvalho de Melo #include "build-id.h"
158a6c5b26SArnaldo Carvalho de Melo #include "debug.h"
1686470930SIngo Molnar #include "symbol.h"
175aab621bSArnaldo Carvalho de Melo #include "strlist.h"
1886470930SIngo Molnar 
1986470930SIngo Molnar #include <libelf.h>
2086470930SIngo Molnar #include <gelf.h>
2186470930SIngo Molnar #include <elf.h>
22f1617b40SArnaldo Carvalho de Melo #include <limits.h>
23439d473bSArnaldo Carvalho de Melo #include <sys/utsname.h>
242cdbc46dSPeter Zijlstra 
25c12e15e7SArnaldo Carvalho de Melo #ifndef NT_GNU_BUILD_ID
26c12e15e7SArnaldo Carvalho de Melo #define NT_GNU_BUILD_ID 3
27c12e15e7SArnaldo Carvalho de Melo #endif
28c12e15e7SArnaldo Carvalho de Melo 
2921916c38SDave Martin static bool dso__build_id_equal(const struct dso *self, u8 *build_id);
3021916c38SDave Martin static int elf_read_build_id(Elf *elf, void *bf, size_t size);
31b0da954aSArnaldo Carvalho de Melo static void dsos__add(struct list_head *head, struct dso *dso);
323610583cSArnaldo Carvalho de Melo static struct map *map__new2(u64 start, struct dso *dso, enum map_type type);
33c338aee8SArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *self, struct map *map,
349de89fe7SArnaldo Carvalho de Melo 				symbol_filter_t filter);
35a1645ce1SZhang, Yanmin static int dso__load_guest_kernel_sym(struct dso *self, struct map *map,
36a1645ce1SZhang, Yanmin 			symbol_filter_t filter);
37cc612d81SArnaldo Carvalho de Melo static int vmlinux_path__nr_entries;
38cc612d81SArnaldo Carvalho de Melo static char **vmlinux_path;
39439d473bSArnaldo Carvalho de Melo 
4075be6cf4SArnaldo Carvalho de Melo struct symbol_conf symbol_conf = {
41d599db3fSArnaldo Carvalho de Melo 	.exclude_other	  = true,
42b32d133aSArnaldo Carvalho de Melo 	.use_modules	  = true,
43b32d133aSArnaldo Carvalho de Melo 	.try_vmlinux_path = true,
44b32d133aSArnaldo Carvalho de Melo };
45b32d133aSArnaldo Carvalho de Melo 
468a6c5b26SArnaldo Carvalho de Melo int dso__name_len(const struct dso *self)
478a6c5b26SArnaldo Carvalho de Melo {
488a6c5b26SArnaldo Carvalho de Melo 	if (verbose)
498a6c5b26SArnaldo Carvalho de Melo 		return self->long_name_len;
508a6c5b26SArnaldo Carvalho de Melo 
518a6c5b26SArnaldo Carvalho de Melo 	return self->short_name_len;
528a6c5b26SArnaldo Carvalho de Melo }
538a6c5b26SArnaldo Carvalho de Melo 
543610583cSArnaldo Carvalho de Melo bool dso__loaded(const struct dso *self, enum map_type type)
553610583cSArnaldo Carvalho de Melo {
563610583cSArnaldo Carvalho de Melo 	return self->loaded & (1 << type);
573610583cSArnaldo Carvalho de Melo }
583610583cSArnaldo Carvalho de Melo 
5979406cd7SArnaldo Carvalho de Melo bool dso__sorted_by_name(const struct dso *self, enum map_type type)
6079406cd7SArnaldo Carvalho de Melo {
6179406cd7SArnaldo Carvalho de Melo 	return self->sorted_by_name & (1 << type);
6279406cd7SArnaldo Carvalho de Melo }
6379406cd7SArnaldo Carvalho de Melo 
6479406cd7SArnaldo Carvalho de Melo static void dso__set_sorted_by_name(struct dso *self, enum map_type type)
6579406cd7SArnaldo Carvalho de Melo {
6679406cd7SArnaldo Carvalho de Melo 	self->sorted_by_name |= (1 << type);
6779406cd7SArnaldo Carvalho de Melo }
6879406cd7SArnaldo Carvalho de Melo 
6936a3e646SArnaldo Carvalho de Melo bool symbol_type__is_a(char symbol_type, enum map_type map_type)
706893d4eeSArnaldo Carvalho de Melo {
716893d4eeSArnaldo Carvalho de Melo 	switch (map_type) {
726893d4eeSArnaldo Carvalho de Melo 	case MAP__FUNCTION:
736893d4eeSArnaldo Carvalho de Melo 		return symbol_type == 'T' || symbol_type == 'W';
74f1dfa0b1SArnaldo Carvalho de Melo 	case MAP__VARIABLE:
75f1dfa0b1SArnaldo Carvalho de Melo 		return symbol_type == 'D' || symbol_type == 'd';
766893d4eeSArnaldo Carvalho de Melo 	default:
776893d4eeSArnaldo Carvalho de Melo 		return false;
786893d4eeSArnaldo Carvalho de Melo 	}
796893d4eeSArnaldo Carvalho de Melo }
806893d4eeSArnaldo Carvalho de Melo 
81fcf1203aSArnaldo Carvalho de Melo static void symbols__fixup_end(struct rb_root *self)
82af427bf5SArnaldo Carvalho de Melo {
83fcf1203aSArnaldo Carvalho de Melo 	struct rb_node *nd, *prevnd = rb_first(self);
842e538c4aSArnaldo Carvalho de Melo 	struct symbol *curr, *prev;
85af427bf5SArnaldo Carvalho de Melo 
86af427bf5SArnaldo Carvalho de Melo 	if (prevnd == NULL)
87af427bf5SArnaldo Carvalho de Melo 		return;
88af427bf5SArnaldo Carvalho de Melo 
892e538c4aSArnaldo Carvalho de Melo 	curr = rb_entry(prevnd, struct symbol, rb_node);
902e538c4aSArnaldo Carvalho de Melo 
91af427bf5SArnaldo Carvalho de Melo 	for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
922e538c4aSArnaldo Carvalho de Melo 		prev = curr;
932e538c4aSArnaldo Carvalho de Melo 		curr = rb_entry(nd, struct symbol, rb_node);
94af427bf5SArnaldo Carvalho de Melo 
95af427bf5SArnaldo Carvalho de Melo 		if (prev->end == prev->start)
96af427bf5SArnaldo Carvalho de Melo 			prev->end = curr->start - 1;
97af427bf5SArnaldo Carvalho de Melo 	}
98af427bf5SArnaldo Carvalho de Melo 
992e538c4aSArnaldo Carvalho de Melo 	/* Last entry */
1002e538c4aSArnaldo Carvalho de Melo 	if (curr->end == curr->start)
1012e538c4aSArnaldo Carvalho de Melo 		curr->end = roundup(curr->start, 4096);
1022e538c4aSArnaldo Carvalho de Melo }
1032e538c4aSArnaldo Carvalho de Melo 
1049958e1f0SArnaldo Carvalho de Melo static void __map_groups__fixup_end(struct map_groups *self, enum map_type type)
105af427bf5SArnaldo Carvalho de Melo {
106af427bf5SArnaldo Carvalho de Melo 	struct map *prev, *curr;
10795011c60SArnaldo Carvalho de Melo 	struct rb_node *nd, *prevnd = rb_first(&self->maps[type]);
108af427bf5SArnaldo Carvalho de Melo 
109af427bf5SArnaldo Carvalho de Melo 	if (prevnd == NULL)
110af427bf5SArnaldo Carvalho de Melo 		return;
111af427bf5SArnaldo Carvalho de Melo 
112af427bf5SArnaldo Carvalho de Melo 	curr = rb_entry(prevnd, struct map, rb_node);
113af427bf5SArnaldo Carvalho de Melo 
114af427bf5SArnaldo Carvalho de Melo 	for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
115af427bf5SArnaldo Carvalho de Melo 		prev = curr;
116af427bf5SArnaldo Carvalho de Melo 		curr = rb_entry(nd, struct map, rb_node);
117af427bf5SArnaldo Carvalho de Melo 		prev->end = curr->start - 1;
1182e538c4aSArnaldo Carvalho de Melo 	}
11990c83218SArnaldo Carvalho de Melo 
12090c83218SArnaldo Carvalho de Melo 	/*
12190c83218SArnaldo Carvalho de Melo 	 * We still haven't the actual symbols, so guess the
12290c83218SArnaldo Carvalho de Melo 	 * last map final address.
12390c83218SArnaldo Carvalho de Melo 	 */
12490c83218SArnaldo Carvalho de Melo 	curr->end = ~0UL;
125af427bf5SArnaldo Carvalho de Melo }
126af427bf5SArnaldo Carvalho de Melo 
1279958e1f0SArnaldo Carvalho de Melo static void map_groups__fixup_end(struct map_groups *self)
12823ea4a3fSArnaldo Carvalho de Melo {
12923ea4a3fSArnaldo Carvalho de Melo 	int i;
13023ea4a3fSArnaldo Carvalho de Melo 	for (i = 0; i < MAP__NR_TYPES; ++i)
1319958e1f0SArnaldo Carvalho de Melo 		__map_groups__fixup_end(self, i);
13223ea4a3fSArnaldo Carvalho de Melo }
13323ea4a3fSArnaldo Carvalho de Melo 
134c408fedfSArnaldo Carvalho de Melo static struct symbol *symbol__new(u64 start, u64 len, u8 binding,
135c408fedfSArnaldo Carvalho de Melo 				  const char *name)
13686470930SIngo Molnar {
13786470930SIngo Molnar 	size_t namelen = strlen(name) + 1;
1385aab621bSArnaldo Carvalho de Melo 	struct symbol *self = calloc(1, (symbol_conf.priv_size +
1395aab621bSArnaldo Carvalho de Melo 					 sizeof(*self) + namelen));
14036479484SArnaldo Carvalho de Melo 	if (self == NULL)
14186470930SIngo Molnar 		return NULL;
14286470930SIngo Molnar 
14375be6cf4SArnaldo Carvalho de Melo 	if (symbol_conf.priv_size)
14475be6cf4SArnaldo Carvalho de Melo 		self = ((void *)self) + symbol_conf.priv_size;
14536479484SArnaldo Carvalho de Melo 
14686470930SIngo Molnar 	self->start   = start;
1476cfcc53eSMike Galbraith 	self->end     = len ? start + len - 1 : start;
148c408fedfSArnaldo Carvalho de Melo 	self->binding = binding;
149fefb0b94SArnaldo Carvalho de Melo 	self->namelen = namelen - 1;
150e4204992SArnaldo Carvalho de Melo 
15129a9f66dSArnaldo Carvalho de Melo 	pr_debug4("%s: %s %#Lx-%#Lx\n", __func__, name, start, self->end);
152e4204992SArnaldo Carvalho de Melo 
15386470930SIngo Molnar 	memcpy(self->name, name, namelen);
15486470930SIngo Molnar 
15586470930SIngo Molnar 	return self;
15686470930SIngo Molnar }
15786470930SIngo Molnar 
158628ada0cSArnaldo Carvalho de Melo void symbol__delete(struct symbol *self)
15986470930SIngo Molnar {
16075be6cf4SArnaldo Carvalho de Melo 	free(((void *)self) - symbol_conf.priv_size);
16186470930SIngo Molnar }
16286470930SIngo Molnar 
16386470930SIngo Molnar static size_t symbol__fprintf(struct symbol *self, FILE *fp)
16486470930SIngo Molnar {
165c408fedfSArnaldo Carvalho de Melo 	return fprintf(fp, " %llx-%llx %c %s\n",
166c408fedfSArnaldo Carvalho de Melo 		       self->start, self->end,
167c408fedfSArnaldo Carvalho de Melo 		       self->binding == STB_GLOBAL ? 'g' :
168c408fedfSArnaldo Carvalho de Melo 		       self->binding == STB_LOCAL  ? 'l' : 'w',
169c408fedfSArnaldo Carvalho de Melo 		       self->name);
17086470930SIngo Molnar }
17186470930SIngo Molnar 
172b7cece76SArnaldo Carvalho de Melo void dso__set_long_name(struct dso *self, char *name)
173cfc10d3bSArnaldo Carvalho de Melo {
174ef6ae724SArnaldo Carvalho de Melo 	if (name == NULL)
175ef6ae724SArnaldo Carvalho de Melo 		return;
176cfc10d3bSArnaldo Carvalho de Melo 	self->long_name = name;
177cfc10d3bSArnaldo Carvalho de Melo 	self->long_name_len = strlen(name);
178cfc10d3bSArnaldo Carvalho de Melo }
179cfc10d3bSArnaldo Carvalho de Melo 
180b63be8d7SArnaldo Carvalho de Melo static void dso__set_short_name(struct dso *self, const char *name)
181b63be8d7SArnaldo Carvalho de Melo {
182b63be8d7SArnaldo Carvalho de Melo 	if (name == NULL)
183b63be8d7SArnaldo Carvalho de Melo 		return;
184b63be8d7SArnaldo Carvalho de Melo 	self->short_name = name;
185b63be8d7SArnaldo Carvalho de Melo 	self->short_name_len = strlen(name);
186b63be8d7SArnaldo Carvalho de Melo }
187b63be8d7SArnaldo Carvalho de Melo 
188cfc10d3bSArnaldo Carvalho de Melo static void dso__set_basename(struct dso *self)
189cfc10d3bSArnaldo Carvalho de Melo {
190b63be8d7SArnaldo Carvalho de Melo 	dso__set_short_name(self, basename(self->long_name));
191cfc10d3bSArnaldo Carvalho de Melo }
192cfc10d3bSArnaldo Carvalho de Melo 
19300a192b3SArnaldo Carvalho de Melo struct dso *dso__new(const char *name)
19486470930SIngo Molnar {
1955aab621bSArnaldo Carvalho de Melo 	struct dso *self = calloc(1, sizeof(*self) + strlen(name) + 1);
19686470930SIngo Molnar 
19786470930SIngo Molnar 	if (self != NULL) {
1986a4694a4SArnaldo Carvalho de Melo 		int i;
19986470930SIngo Molnar 		strcpy(self->name, name);
200cfc10d3bSArnaldo Carvalho de Melo 		dso__set_long_name(self, self->name);
201b63be8d7SArnaldo Carvalho de Melo 		dso__set_short_name(self, self->name);
2026a4694a4SArnaldo Carvalho de Melo 		for (i = 0; i < MAP__NR_TYPES; ++i)
20379406cd7SArnaldo Carvalho de Melo 			self->symbols[i] = self->symbol_names[i] = RB_ROOT;
20452d422deSArnaldo Carvalho de Melo 		self->slen_calculated = 0;
20594cb9e38SArnaldo Carvalho de Melo 		self->origin = DSO__ORIG_NOT_FOUND;
2068d06367fSArnaldo Carvalho de Melo 		self->loaded = 0;
20779406cd7SArnaldo Carvalho de Melo 		self->sorted_by_name = 0;
2088d06367fSArnaldo Carvalho de Melo 		self->has_build_id = 0;
209a1645ce1SZhang, Yanmin 		self->kernel = DSO_TYPE_USER;
2100ab061cdSMasami Hiramatsu 		INIT_LIST_HEAD(&self->node);
21186470930SIngo Molnar 	}
21286470930SIngo Molnar 
21386470930SIngo Molnar 	return self;
21486470930SIngo Molnar }
21586470930SIngo Molnar 
216fcf1203aSArnaldo Carvalho de Melo static void symbols__delete(struct rb_root *self)
21786470930SIngo Molnar {
21886470930SIngo Molnar 	struct symbol *pos;
219fcf1203aSArnaldo Carvalho de Melo 	struct rb_node *next = rb_first(self);
22086470930SIngo Molnar 
22186470930SIngo Molnar 	while (next) {
22286470930SIngo Molnar 		pos = rb_entry(next, struct symbol, rb_node);
22386470930SIngo Molnar 		next = rb_next(&pos->rb_node);
224fcf1203aSArnaldo Carvalho de Melo 		rb_erase(&pos->rb_node, self);
22500a192b3SArnaldo Carvalho de Melo 		symbol__delete(pos);
22686470930SIngo Molnar 	}
22786470930SIngo Molnar }
22886470930SIngo Molnar 
22986470930SIngo Molnar void dso__delete(struct dso *self)
23086470930SIngo Molnar {
2316a4694a4SArnaldo Carvalho de Melo 	int i;
2326a4694a4SArnaldo Carvalho de Melo 	for (i = 0; i < MAP__NR_TYPES; ++i)
2336a4694a4SArnaldo Carvalho de Melo 		symbols__delete(&self->symbols[i]);
2346e406257SArnaldo Carvalho de Melo 	if (self->sname_alloc)
2356e406257SArnaldo Carvalho de Melo 		free((char *)self->short_name);
2366e406257SArnaldo Carvalho de Melo 	if (self->lname_alloc)
237439d473bSArnaldo Carvalho de Melo 		free(self->long_name);
23886470930SIngo Molnar 	free(self);
23986470930SIngo Molnar }
24086470930SIngo Molnar 
2418d06367fSArnaldo Carvalho de Melo void dso__set_build_id(struct dso *self, void *build_id)
2428d06367fSArnaldo Carvalho de Melo {
2438d06367fSArnaldo Carvalho de Melo 	memcpy(self->build_id, build_id, sizeof(self->build_id));
2448d06367fSArnaldo Carvalho de Melo 	self->has_build_id = 1;
2458d06367fSArnaldo Carvalho de Melo }
2468d06367fSArnaldo Carvalho de Melo 
247fcf1203aSArnaldo Carvalho de Melo static void symbols__insert(struct rb_root *self, struct symbol *sym)
24886470930SIngo Molnar {
249fcf1203aSArnaldo Carvalho de Melo 	struct rb_node **p = &self->rb_node;
25086470930SIngo Molnar 	struct rb_node *parent = NULL;
2519cffa8d5SPaul Mackerras 	const u64 ip = sym->start;
25286470930SIngo Molnar 	struct symbol *s;
25386470930SIngo Molnar 
25486470930SIngo Molnar 	while (*p != NULL) {
25586470930SIngo Molnar 		parent = *p;
25686470930SIngo Molnar 		s = rb_entry(parent, struct symbol, rb_node);
25786470930SIngo Molnar 		if (ip < s->start)
25886470930SIngo Molnar 			p = &(*p)->rb_left;
25986470930SIngo Molnar 		else
26086470930SIngo Molnar 			p = &(*p)->rb_right;
26186470930SIngo Molnar 	}
26286470930SIngo Molnar 	rb_link_node(&sym->rb_node, parent, p);
263fcf1203aSArnaldo Carvalho de Melo 	rb_insert_color(&sym->rb_node, self);
26486470930SIngo Molnar }
26586470930SIngo Molnar 
266fcf1203aSArnaldo Carvalho de Melo static struct symbol *symbols__find(struct rb_root *self, u64 ip)
26786470930SIngo Molnar {
26886470930SIngo Molnar 	struct rb_node *n;
26986470930SIngo Molnar 
27086470930SIngo Molnar 	if (self == NULL)
27186470930SIngo Molnar 		return NULL;
27286470930SIngo Molnar 
273fcf1203aSArnaldo Carvalho de Melo 	n = self->rb_node;
27486470930SIngo Molnar 
27586470930SIngo Molnar 	while (n) {
27686470930SIngo Molnar 		struct symbol *s = rb_entry(n, struct symbol, rb_node);
27786470930SIngo Molnar 
27886470930SIngo Molnar 		if (ip < s->start)
27986470930SIngo Molnar 			n = n->rb_left;
28086470930SIngo Molnar 		else if (ip > s->end)
28186470930SIngo Molnar 			n = n->rb_right;
28286470930SIngo Molnar 		else
28386470930SIngo Molnar 			return s;
28486470930SIngo Molnar 	}
28586470930SIngo Molnar 
28686470930SIngo Molnar 	return NULL;
28786470930SIngo Molnar }
28886470930SIngo Molnar 
28979406cd7SArnaldo Carvalho de Melo struct symbol_name_rb_node {
29079406cd7SArnaldo Carvalho de Melo 	struct rb_node	rb_node;
29179406cd7SArnaldo Carvalho de Melo 	struct symbol	sym;
29279406cd7SArnaldo Carvalho de Melo };
29379406cd7SArnaldo Carvalho de Melo 
29479406cd7SArnaldo Carvalho de Melo static void symbols__insert_by_name(struct rb_root *self, struct symbol *sym)
29579406cd7SArnaldo Carvalho de Melo {
29679406cd7SArnaldo Carvalho de Melo 	struct rb_node **p = &self->rb_node;
29779406cd7SArnaldo Carvalho de Melo 	struct rb_node *parent = NULL;
29879406cd7SArnaldo Carvalho de Melo 	struct symbol_name_rb_node *symn = ((void *)sym) - sizeof(*parent), *s;
29979406cd7SArnaldo Carvalho de Melo 
30079406cd7SArnaldo Carvalho de Melo 	while (*p != NULL) {
30179406cd7SArnaldo Carvalho de Melo 		parent = *p;
30279406cd7SArnaldo Carvalho de Melo 		s = rb_entry(parent, struct symbol_name_rb_node, rb_node);
30379406cd7SArnaldo Carvalho de Melo 		if (strcmp(sym->name, s->sym.name) < 0)
30479406cd7SArnaldo Carvalho de Melo 			p = &(*p)->rb_left;
30579406cd7SArnaldo Carvalho de Melo 		else
30679406cd7SArnaldo Carvalho de Melo 			p = &(*p)->rb_right;
30779406cd7SArnaldo Carvalho de Melo 	}
30879406cd7SArnaldo Carvalho de Melo 	rb_link_node(&symn->rb_node, parent, p);
30979406cd7SArnaldo Carvalho de Melo 	rb_insert_color(&symn->rb_node, self);
31079406cd7SArnaldo Carvalho de Melo }
31179406cd7SArnaldo Carvalho de Melo 
31279406cd7SArnaldo Carvalho de Melo static void symbols__sort_by_name(struct rb_root *self, struct rb_root *source)
31379406cd7SArnaldo Carvalho de Melo {
31479406cd7SArnaldo Carvalho de Melo 	struct rb_node *nd;
31579406cd7SArnaldo Carvalho de Melo 
31679406cd7SArnaldo Carvalho de Melo 	for (nd = rb_first(source); nd; nd = rb_next(nd)) {
31779406cd7SArnaldo Carvalho de Melo 		struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
31879406cd7SArnaldo Carvalho de Melo 		symbols__insert_by_name(self, pos);
31979406cd7SArnaldo Carvalho de Melo 	}
32079406cd7SArnaldo Carvalho de Melo }
32179406cd7SArnaldo Carvalho de Melo 
32279406cd7SArnaldo Carvalho de Melo static struct symbol *symbols__find_by_name(struct rb_root *self, const char *name)
32379406cd7SArnaldo Carvalho de Melo {
32479406cd7SArnaldo Carvalho de Melo 	struct rb_node *n;
32579406cd7SArnaldo Carvalho de Melo 
32679406cd7SArnaldo Carvalho de Melo 	if (self == NULL)
32779406cd7SArnaldo Carvalho de Melo 		return NULL;
32879406cd7SArnaldo Carvalho de Melo 
32979406cd7SArnaldo Carvalho de Melo 	n = self->rb_node;
33079406cd7SArnaldo Carvalho de Melo 
33179406cd7SArnaldo Carvalho de Melo 	while (n) {
33279406cd7SArnaldo Carvalho de Melo 		struct symbol_name_rb_node *s;
33379406cd7SArnaldo Carvalho de Melo 		int cmp;
33479406cd7SArnaldo Carvalho de Melo 
33579406cd7SArnaldo Carvalho de Melo 		s = rb_entry(n, struct symbol_name_rb_node, rb_node);
33679406cd7SArnaldo Carvalho de Melo 		cmp = strcmp(name, s->sym.name);
33779406cd7SArnaldo Carvalho de Melo 
33879406cd7SArnaldo Carvalho de Melo 		if (cmp < 0)
33979406cd7SArnaldo Carvalho de Melo 			n = n->rb_left;
34079406cd7SArnaldo Carvalho de Melo 		else if (cmp > 0)
34179406cd7SArnaldo Carvalho de Melo 			n = n->rb_right;
34279406cd7SArnaldo Carvalho de Melo 		else
34379406cd7SArnaldo Carvalho de Melo 			return &s->sym;
34479406cd7SArnaldo Carvalho de Melo 	}
34579406cd7SArnaldo Carvalho de Melo 
34679406cd7SArnaldo Carvalho de Melo 	return NULL;
34779406cd7SArnaldo Carvalho de Melo }
34879406cd7SArnaldo Carvalho de Melo 
34979406cd7SArnaldo Carvalho de Melo struct symbol *dso__find_symbol(struct dso *self,
35079406cd7SArnaldo Carvalho de Melo 				enum map_type type, u64 addr)
351fcf1203aSArnaldo Carvalho de Melo {
3526a4694a4SArnaldo Carvalho de Melo 	return symbols__find(&self->symbols[type], addr);
353fcf1203aSArnaldo Carvalho de Melo }
354fcf1203aSArnaldo Carvalho de Melo 
35579406cd7SArnaldo Carvalho de Melo struct symbol *dso__find_symbol_by_name(struct dso *self, enum map_type type,
35679406cd7SArnaldo Carvalho de Melo 					const char *name)
35779406cd7SArnaldo Carvalho de Melo {
35879406cd7SArnaldo Carvalho de Melo 	return symbols__find_by_name(&self->symbol_names[type], name);
35979406cd7SArnaldo Carvalho de Melo }
36079406cd7SArnaldo Carvalho de Melo 
36179406cd7SArnaldo Carvalho de Melo void dso__sort_by_name(struct dso *self, enum map_type type)
36279406cd7SArnaldo Carvalho de Melo {
36379406cd7SArnaldo Carvalho de Melo 	dso__set_sorted_by_name(self, type);
36479406cd7SArnaldo Carvalho de Melo 	return symbols__sort_by_name(&self->symbol_names[type],
36579406cd7SArnaldo Carvalho de Melo 				     &self->symbols[type]);
36679406cd7SArnaldo Carvalho de Melo }
36779406cd7SArnaldo Carvalho de Melo 
368ef12a141SArnaldo Carvalho de Melo int build_id__sprintf(const u8 *self, int len, char *bf)
3698d06367fSArnaldo Carvalho de Melo {
3708d06367fSArnaldo Carvalho de Melo 	char *bid = bf;
371ef12a141SArnaldo Carvalho de Melo 	const u8 *raw = self;
3728d06367fSArnaldo Carvalho de Melo 	int i;
3738d06367fSArnaldo Carvalho de Melo 
3748d06367fSArnaldo Carvalho de Melo 	for (i = 0; i < len; ++i) {
3758d06367fSArnaldo Carvalho de Melo 		sprintf(bid, "%02x", *raw);
3768d06367fSArnaldo Carvalho de Melo 		++raw;
3778d06367fSArnaldo Carvalho de Melo 		bid += 2;
3788d06367fSArnaldo Carvalho de Melo 	}
3798d06367fSArnaldo Carvalho de Melo 
3808d06367fSArnaldo Carvalho de Melo 	return raw - self;
3818d06367fSArnaldo Carvalho de Melo }
3828d06367fSArnaldo Carvalho de Melo 
3839e03eb2dSArnaldo Carvalho de Melo size_t dso__fprintf_buildid(struct dso *self, FILE *fp)
38486470930SIngo Molnar {
3858d06367fSArnaldo Carvalho de Melo 	char sbuild_id[BUILD_ID_SIZE * 2 + 1];
3868d06367fSArnaldo Carvalho de Melo 
3878d06367fSArnaldo Carvalho de Melo 	build_id__sprintf(self->build_id, sizeof(self->build_id), sbuild_id);
3889e03eb2dSArnaldo Carvalho de Melo 	return fprintf(fp, "%s", sbuild_id);
3899e03eb2dSArnaldo Carvalho de Melo }
3909e03eb2dSArnaldo Carvalho de Melo 
39195011c60SArnaldo Carvalho de Melo size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp)
3929e03eb2dSArnaldo Carvalho de Melo {
3939e03eb2dSArnaldo Carvalho de Melo 	struct rb_node *nd;
3949e03eb2dSArnaldo Carvalho de Melo 	size_t ret = fprintf(fp, "dso: %s (", self->short_name);
3959e03eb2dSArnaldo Carvalho de Melo 
3963846df2eSArnaldo Carvalho de Melo 	if (self->short_name != self->long_name)
3973846df2eSArnaldo Carvalho de Melo 		ret += fprintf(fp, "%s, ", self->long_name);
3983846df2eSArnaldo Carvalho de Melo 	ret += fprintf(fp, "%s, %sloaded, ", map_type__name[type],
3993846df2eSArnaldo Carvalho de Melo 		       self->loaded ? "" : "NOT ");
4009e03eb2dSArnaldo Carvalho de Melo 	ret += dso__fprintf_buildid(self, fp);
4016a4694a4SArnaldo Carvalho de Melo 	ret += fprintf(fp, ")\n");
40295011c60SArnaldo Carvalho de Melo 	for (nd = rb_first(&self->symbols[type]); nd; nd = rb_next(nd)) {
40386470930SIngo Molnar 		struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
40486470930SIngo Molnar 		ret += symbol__fprintf(pos, fp);
40586470930SIngo Molnar 	}
40686470930SIngo Molnar 
40786470930SIngo Molnar 	return ret;
40886470930SIngo Molnar }
40986470930SIngo Molnar 
4109e201442SArnaldo Carvalho de Melo int kallsyms__parse(const char *filename, void *arg,
4119e201442SArnaldo Carvalho de Melo 		    int (*process_symbol)(void *arg, const char *name,
412682b335aSArnaldo Carvalho de Melo 						     char type, u64 start))
41386470930SIngo Molnar {
41486470930SIngo Molnar 	char *line = NULL;
41586470930SIngo Molnar 	size_t n;
416682b335aSArnaldo Carvalho de Melo 	int err = 0;
4179e201442SArnaldo Carvalho de Melo 	FILE *file = fopen(filename, "r");
41886470930SIngo Molnar 
41986470930SIngo Molnar 	if (file == NULL)
42086470930SIngo Molnar 		goto out_failure;
42186470930SIngo Molnar 
42286470930SIngo Molnar 	while (!feof(file)) {
4239cffa8d5SPaul Mackerras 		u64 start;
42486470930SIngo Molnar 		int line_len, len;
42586470930SIngo Molnar 		char symbol_type;
4262e538c4aSArnaldo Carvalho de Melo 		char *symbol_name;
42786470930SIngo Molnar 
42886470930SIngo Molnar 		line_len = getline(&line, &n, file);
429a1645ce1SZhang, Yanmin 		if (line_len < 0 || !line)
43086470930SIngo Molnar 			break;
43186470930SIngo Molnar 
43286470930SIngo Molnar 		line[--line_len] = '\0'; /* \n */
43386470930SIngo Molnar 
43486470930SIngo Molnar 		len = hex2u64(line, &start);
43586470930SIngo Molnar 
43686470930SIngo Molnar 		len++;
43786470930SIngo Molnar 		if (len + 2 >= line_len)
43886470930SIngo Molnar 			continue;
43986470930SIngo Molnar 
44086470930SIngo Molnar 		symbol_type = toupper(line[len]);
441af427bf5SArnaldo Carvalho de Melo 		symbol_name = line + len + 2;
442682b335aSArnaldo Carvalho de Melo 
443682b335aSArnaldo Carvalho de Melo 		err = process_symbol(arg, symbol_name, symbol_type, start);
444682b335aSArnaldo Carvalho de Melo 		if (err)
445682b335aSArnaldo Carvalho de Melo 			break;
446682b335aSArnaldo Carvalho de Melo 	}
447682b335aSArnaldo Carvalho de Melo 
448682b335aSArnaldo Carvalho de Melo 	free(line);
449682b335aSArnaldo Carvalho de Melo 	fclose(file);
450682b335aSArnaldo Carvalho de Melo 	return err;
451682b335aSArnaldo Carvalho de Melo 
452682b335aSArnaldo Carvalho de Melo out_failure:
453682b335aSArnaldo Carvalho de Melo 	return -1;
454682b335aSArnaldo Carvalho de Melo }
455682b335aSArnaldo Carvalho de Melo 
456682b335aSArnaldo Carvalho de Melo struct process_kallsyms_args {
457682b335aSArnaldo Carvalho de Melo 	struct map *map;
458682b335aSArnaldo Carvalho de Melo 	struct dso *dso;
459682b335aSArnaldo Carvalho de Melo };
460682b335aSArnaldo Carvalho de Melo 
461c408fedfSArnaldo Carvalho de Melo static u8 kallsyms2elf_type(char type)
462c408fedfSArnaldo Carvalho de Melo {
463c408fedfSArnaldo Carvalho de Melo 	if (type == 'W')
464c408fedfSArnaldo Carvalho de Melo 		return STB_WEAK;
465c408fedfSArnaldo Carvalho de Melo 
466c408fedfSArnaldo Carvalho de Melo 	return isupper(type) ? STB_GLOBAL : STB_LOCAL;
467c408fedfSArnaldo Carvalho de Melo }
468c408fedfSArnaldo Carvalho de Melo 
469682b335aSArnaldo Carvalho de Melo static int map__process_kallsym_symbol(void *arg, const char *name,
470682b335aSArnaldo Carvalho de Melo 				       char type, u64 start)
471682b335aSArnaldo Carvalho de Melo {
472682b335aSArnaldo Carvalho de Melo 	struct symbol *sym;
473682b335aSArnaldo Carvalho de Melo 	struct process_kallsyms_args *a = arg;
474682b335aSArnaldo Carvalho de Melo 	struct rb_root *root = &a->dso->symbols[a->map->type];
475682b335aSArnaldo Carvalho de Melo 
476682b335aSArnaldo Carvalho de Melo 	if (!symbol_type__is_a(type, a->map->type))
477682b335aSArnaldo Carvalho de Melo 		return 0;
478682b335aSArnaldo Carvalho de Melo 
4792e538c4aSArnaldo Carvalho de Melo 	/*
4802e538c4aSArnaldo Carvalho de Melo 	 * Will fix up the end later, when we have all symbols sorted.
4812e538c4aSArnaldo Carvalho de Melo 	 */
482c408fedfSArnaldo Carvalho de Melo 	sym = symbol__new(start, 0, kallsyms2elf_type(type), name);
483af427bf5SArnaldo Carvalho de Melo 
4842e538c4aSArnaldo Carvalho de Melo 	if (sym == NULL)
485682b335aSArnaldo Carvalho de Melo 		return -ENOMEM;
48682164161SArnaldo Carvalho de Melo 	/*
48782164161SArnaldo Carvalho de Melo 	 * We will pass the symbols to the filter later, in
4884e06255fSArnaldo Carvalho de Melo 	 * map__split_kallsyms, when we have split the maps per module
48982164161SArnaldo Carvalho de Melo 	 */
4904e06255fSArnaldo Carvalho de Melo 	symbols__insert(root, sym);
491a1645ce1SZhang, Yanmin 
492682b335aSArnaldo Carvalho de Melo 	return 0;
4932e538c4aSArnaldo Carvalho de Melo }
4942e538c4aSArnaldo Carvalho de Melo 
495682b335aSArnaldo Carvalho de Melo /*
496682b335aSArnaldo Carvalho de Melo  * Loads the function entries in /proc/kallsyms into kernel_map->dso,
497682b335aSArnaldo Carvalho de Melo  * so that we can in the next step set the symbol ->end address and then
498682b335aSArnaldo Carvalho de Melo  * call kernel_maps__split_kallsyms.
499682b335aSArnaldo Carvalho de Melo  */
5009e201442SArnaldo Carvalho de Melo static int dso__load_all_kallsyms(struct dso *self, const char *filename,
5019e201442SArnaldo Carvalho de Melo 				  struct map *map)
502682b335aSArnaldo Carvalho de Melo {
503682b335aSArnaldo Carvalho de Melo 	struct process_kallsyms_args args = { .map = map, .dso = self, };
5049e201442SArnaldo Carvalho de Melo 	return kallsyms__parse(filename, &args, map__process_kallsym_symbol);
5052e538c4aSArnaldo Carvalho de Melo }
5062e538c4aSArnaldo Carvalho de Melo 
5072e538c4aSArnaldo Carvalho de Melo /*
5082e538c4aSArnaldo Carvalho de Melo  * Split the symbols into maps, making sure there are no overlaps, i.e. the
5092e538c4aSArnaldo Carvalho de Melo  * kernel range is broken in several maps, named [kernel].N, as we don't have
5102e538c4aSArnaldo Carvalho de Melo  * the original ELF section names vmlinux have.
5112e538c4aSArnaldo Carvalho de Melo  */
5129958e1f0SArnaldo Carvalho de Melo static int dso__split_kallsyms(struct dso *self, struct map *map,
5139de89fe7SArnaldo Carvalho de Melo 			       symbol_filter_t filter)
5142e538c4aSArnaldo Carvalho de Melo {
5159de89fe7SArnaldo Carvalho de Melo 	struct map_groups *kmaps = map__kmap(map)->kmaps;
51623346f21SArnaldo Carvalho de Melo 	struct machine *machine = kmaps->machine;
5174e06255fSArnaldo Carvalho de Melo 	struct map *curr_map = map;
5182e538c4aSArnaldo Carvalho de Melo 	struct symbol *pos;
5192e538c4aSArnaldo Carvalho de Melo 	int count = 0;
5204e06255fSArnaldo Carvalho de Melo 	struct rb_root *root = &self->symbols[map->type];
5214e06255fSArnaldo Carvalho de Melo 	struct rb_node *next = rb_first(root);
5222e538c4aSArnaldo Carvalho de Melo 	int kernel_range = 0;
5232e538c4aSArnaldo Carvalho de Melo 
5242e538c4aSArnaldo Carvalho de Melo 	while (next) {
5252e538c4aSArnaldo Carvalho de Melo 		char *module;
5262e538c4aSArnaldo Carvalho de Melo 
5272e538c4aSArnaldo Carvalho de Melo 		pos = rb_entry(next, struct symbol, rb_node);
5282e538c4aSArnaldo Carvalho de Melo 		next = rb_next(&pos->rb_node);
5292e538c4aSArnaldo Carvalho de Melo 
5302e538c4aSArnaldo Carvalho de Melo 		module = strchr(pos->name, '\t');
5312e538c4aSArnaldo Carvalho de Melo 		if (module) {
53275be6cf4SArnaldo Carvalho de Melo 			if (!symbol_conf.use_modules)
5331de8e245SArnaldo Carvalho de Melo 				goto discard_symbol;
5341de8e245SArnaldo Carvalho de Melo 
5352e538c4aSArnaldo Carvalho de Melo 			*module++ = '\0';
5362e538c4aSArnaldo Carvalho de Melo 
537b7cece76SArnaldo Carvalho de Melo 			if (strcmp(curr_map->dso->short_name, module)) {
538a1645ce1SZhang, Yanmin 				if (curr_map != map &&
539a1645ce1SZhang, Yanmin 				    self->kernel == DSO_TYPE_GUEST_KERNEL &&
54023346f21SArnaldo Carvalho de Melo 				    machine__is_default_guest(machine)) {
541a1645ce1SZhang, Yanmin 					/*
542a1645ce1SZhang, Yanmin 					 * We assume all symbols of a module are
543a1645ce1SZhang, Yanmin 					 * continuous in * kallsyms, so curr_map
544a1645ce1SZhang, Yanmin 					 * points to a module and all its
545a1645ce1SZhang, Yanmin 					 * symbols are in its kmap. Mark it as
546a1645ce1SZhang, Yanmin 					 * loaded.
547a1645ce1SZhang, Yanmin 					 */
548a1645ce1SZhang, Yanmin 					dso__set_loaded(curr_map->dso,
549a1645ce1SZhang, Yanmin 							curr_map->type);
550af427bf5SArnaldo Carvalho de Melo 				}
551b7cece76SArnaldo Carvalho de Melo 
552a1645ce1SZhang, Yanmin 				curr_map = map_groups__find_by_name(kmaps,
553a1645ce1SZhang, Yanmin 							map->type, module);
554a1645ce1SZhang, Yanmin 				if (curr_map == NULL) {
5552f51903bSArnaldo Carvalho de Melo 					pr_debug("%s/proc/{kallsyms,modules} "
556a1645ce1SZhang, Yanmin 					         "inconsistency while looking "
557a1645ce1SZhang, Yanmin 						 "for \"%s\" module!\n",
55823346f21SArnaldo Carvalho de Melo 						 machine->root_dir, module);
559a1645ce1SZhang, Yanmin 					curr_map = map;
560a1645ce1SZhang, Yanmin 					goto discard_symbol;
561a1645ce1SZhang, Yanmin 				}
562a1645ce1SZhang, Yanmin 
563a1645ce1SZhang, Yanmin 				if (curr_map->dso->loaded &&
56423346f21SArnaldo Carvalho de Melo 				    !machine__is_default_guest(machine))
565b7cece76SArnaldo Carvalho de Melo 					goto discard_symbol;
566af427bf5SArnaldo Carvalho de Melo 			}
56786470930SIngo Molnar 			/*
5682e538c4aSArnaldo Carvalho de Melo 			 * So that we look just like we get from .ko files,
5692e538c4aSArnaldo Carvalho de Melo 			 * i.e. not prelinked, relative to map->start.
57086470930SIngo Molnar 			 */
5714e06255fSArnaldo Carvalho de Melo 			pos->start = curr_map->map_ip(curr_map, pos->start);
5724e06255fSArnaldo Carvalho de Melo 			pos->end   = curr_map->map_ip(curr_map, pos->end);
5734e06255fSArnaldo Carvalho de Melo 		} else if (curr_map != map) {
5742e538c4aSArnaldo Carvalho de Melo 			char dso_name[PATH_MAX];
5752e538c4aSArnaldo Carvalho de Melo 			struct dso *dso;
57686470930SIngo Molnar 
577a1645ce1SZhang, Yanmin 			if (self->kernel == DSO_TYPE_GUEST_KERNEL)
578a1645ce1SZhang, Yanmin 				snprintf(dso_name, sizeof(dso_name),
579a1645ce1SZhang, Yanmin 					"[guest.kernel].%d",
580a1645ce1SZhang, Yanmin 					kernel_range++);
581a1645ce1SZhang, Yanmin 			else
582a1645ce1SZhang, Yanmin 				snprintf(dso_name, sizeof(dso_name),
583a1645ce1SZhang, Yanmin 					"[kernel].%d",
5842e538c4aSArnaldo Carvalho de Melo 					kernel_range++);
58586470930SIngo Molnar 
58600a192b3SArnaldo Carvalho de Melo 			dso = dso__new(dso_name);
5872e538c4aSArnaldo Carvalho de Melo 			if (dso == NULL)
5882e538c4aSArnaldo Carvalho de Melo 				return -1;
5892e538c4aSArnaldo Carvalho de Melo 
590a1645ce1SZhang, Yanmin 			dso->kernel = self->kernel;
591a1645ce1SZhang, Yanmin 
5924e06255fSArnaldo Carvalho de Melo 			curr_map = map__new2(pos->start, dso, map->type);
59337fe5fcbSZhang, Yanmin 			if (curr_map == NULL) {
5942e538c4aSArnaldo Carvalho de Melo 				dso__delete(dso);
5952e538c4aSArnaldo Carvalho de Melo 				return -1;
5962e538c4aSArnaldo Carvalho de Melo 			}
5972e538c4aSArnaldo Carvalho de Melo 
5984e06255fSArnaldo Carvalho de Melo 			curr_map->map_ip = curr_map->unmap_ip = identity__map_ip;
5999de89fe7SArnaldo Carvalho de Melo 			map_groups__insert(kmaps, curr_map);
6002e538c4aSArnaldo Carvalho de Melo 			++kernel_range;
6012e538c4aSArnaldo Carvalho de Melo 		}
6022e538c4aSArnaldo Carvalho de Melo 
6034e06255fSArnaldo Carvalho de Melo 		if (filter && filter(curr_map, pos)) {
6041de8e245SArnaldo Carvalho de Melo discard_symbol:		rb_erase(&pos->rb_node, root);
60500a192b3SArnaldo Carvalho de Melo 			symbol__delete(pos);
6062e538c4aSArnaldo Carvalho de Melo 		} else {
6074e06255fSArnaldo Carvalho de Melo 			if (curr_map != map) {
6084e06255fSArnaldo Carvalho de Melo 				rb_erase(&pos->rb_node, root);
6094e06255fSArnaldo Carvalho de Melo 				symbols__insert(&curr_map->dso->symbols[curr_map->type], pos);
6102e538c4aSArnaldo Carvalho de Melo 			}
6119974f496SMike Galbraith 			count++;
6129974f496SMike Galbraith 		}
61386470930SIngo Molnar 	}
61486470930SIngo Molnar 
615a1645ce1SZhang, Yanmin 	if (curr_map != map &&
616a1645ce1SZhang, Yanmin 	    self->kernel == DSO_TYPE_GUEST_KERNEL &&
61723346f21SArnaldo Carvalho de Melo 	    machine__is_default_guest(kmaps->machine)) {
618a1645ce1SZhang, Yanmin 		dso__set_loaded(curr_map->dso, curr_map->type);
619a1645ce1SZhang, Yanmin 	}
620a1645ce1SZhang, Yanmin 
6219974f496SMike Galbraith 	return count;
62286470930SIngo Molnar }
62386470930SIngo Molnar 
6249de89fe7SArnaldo Carvalho de Melo int dso__load_kallsyms(struct dso *self, const char *filename,
6259de89fe7SArnaldo Carvalho de Melo 		       struct map *map, symbol_filter_t filter)
6262e538c4aSArnaldo Carvalho de Melo {
6279e201442SArnaldo Carvalho de Melo 	if (dso__load_all_kallsyms(self, filename, map) < 0)
6282e538c4aSArnaldo Carvalho de Melo 		return -1;
6292e538c4aSArnaldo Carvalho de Melo 
6304e06255fSArnaldo Carvalho de Melo 	symbols__fixup_end(&self->symbols[map->type]);
631a1645ce1SZhang, Yanmin 	if (self->kernel == DSO_TYPE_GUEST_KERNEL)
632a1645ce1SZhang, Yanmin 		self->origin = DSO__ORIG_GUEST_KERNEL;
633a1645ce1SZhang, Yanmin 	else
6344e06255fSArnaldo Carvalho de Melo 		self->origin = DSO__ORIG_KERNEL;
6352e538c4aSArnaldo Carvalho de Melo 
6369de89fe7SArnaldo Carvalho de Melo 	return dso__split_kallsyms(self, map, filter);
637af427bf5SArnaldo Carvalho de Melo }
638af427bf5SArnaldo Carvalho de Melo 
639439d473bSArnaldo Carvalho de Melo static int dso__load_perf_map(struct dso *self, struct map *map,
6406beba7adSArnaldo Carvalho de Melo 			      symbol_filter_t filter)
64180d496beSPekka Enberg {
64280d496beSPekka Enberg 	char *line = NULL;
64380d496beSPekka Enberg 	size_t n;
64480d496beSPekka Enberg 	FILE *file;
64580d496beSPekka Enberg 	int nr_syms = 0;
64680d496beSPekka Enberg 
647439d473bSArnaldo Carvalho de Melo 	file = fopen(self->long_name, "r");
64880d496beSPekka Enberg 	if (file == NULL)
64980d496beSPekka Enberg 		goto out_failure;
65080d496beSPekka Enberg 
65180d496beSPekka Enberg 	while (!feof(file)) {
6529cffa8d5SPaul Mackerras 		u64 start, size;
65380d496beSPekka Enberg 		struct symbol *sym;
65480d496beSPekka Enberg 		int line_len, len;
65580d496beSPekka Enberg 
65680d496beSPekka Enberg 		line_len = getline(&line, &n, file);
65780d496beSPekka Enberg 		if (line_len < 0)
65880d496beSPekka Enberg 			break;
65980d496beSPekka Enberg 
66080d496beSPekka Enberg 		if (!line)
66180d496beSPekka Enberg 			goto out_failure;
66280d496beSPekka Enberg 
66380d496beSPekka Enberg 		line[--line_len] = '\0'; /* \n */
66480d496beSPekka Enberg 
66580d496beSPekka Enberg 		len = hex2u64(line, &start);
66680d496beSPekka Enberg 
66780d496beSPekka Enberg 		len++;
66880d496beSPekka Enberg 		if (len + 2 >= line_len)
66980d496beSPekka Enberg 			continue;
67080d496beSPekka Enberg 
67180d496beSPekka Enberg 		len += hex2u64(line + len, &size);
67280d496beSPekka Enberg 
67380d496beSPekka Enberg 		len++;
67480d496beSPekka Enberg 		if (len + 2 >= line_len)
67580d496beSPekka Enberg 			continue;
67680d496beSPekka Enberg 
677c408fedfSArnaldo Carvalho de Melo 		sym = symbol__new(start, size, STB_GLOBAL, line + len);
67880d496beSPekka Enberg 
67980d496beSPekka Enberg 		if (sym == NULL)
68080d496beSPekka Enberg 			goto out_delete_line;
68180d496beSPekka Enberg 
682439d473bSArnaldo Carvalho de Melo 		if (filter && filter(map, sym))
68300a192b3SArnaldo Carvalho de Melo 			symbol__delete(sym);
68480d496beSPekka Enberg 		else {
6856a4694a4SArnaldo Carvalho de Melo 			symbols__insert(&self->symbols[map->type], sym);
68680d496beSPekka Enberg 			nr_syms++;
68780d496beSPekka Enberg 		}
68880d496beSPekka Enberg 	}
68980d496beSPekka Enberg 
69080d496beSPekka Enberg 	free(line);
69180d496beSPekka Enberg 	fclose(file);
69280d496beSPekka Enberg 
69380d496beSPekka Enberg 	return nr_syms;
69480d496beSPekka Enberg 
69580d496beSPekka Enberg out_delete_line:
69680d496beSPekka Enberg 	free(line);
69780d496beSPekka Enberg out_failure:
69880d496beSPekka Enberg 	return -1;
69980d496beSPekka Enberg }
70080d496beSPekka Enberg 
70186470930SIngo Molnar /**
70286470930SIngo Molnar  * elf_symtab__for_each_symbol - iterate thru all the symbols
70386470930SIngo Molnar  *
70486470930SIngo Molnar  * @self: struct elf_symtab instance to iterate
70583a0944fSIngo Molnar  * @idx: uint32_t idx
70686470930SIngo Molnar  * @sym: GElf_Sym iterator
70786470930SIngo Molnar  */
70883a0944fSIngo Molnar #define elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) \
70983a0944fSIngo Molnar 	for (idx = 0, gelf_getsym(syms, idx, &sym);\
71083a0944fSIngo Molnar 	     idx < nr_syms; \
71183a0944fSIngo Molnar 	     idx++, gelf_getsym(syms, idx, &sym))
71286470930SIngo Molnar 
71386470930SIngo Molnar static inline uint8_t elf_sym__type(const GElf_Sym *sym)
71486470930SIngo Molnar {
71586470930SIngo Molnar 	return GELF_ST_TYPE(sym->st_info);
71686470930SIngo Molnar }
71786470930SIngo Molnar 
71886470930SIngo Molnar static inline int elf_sym__is_function(const GElf_Sym *sym)
71986470930SIngo Molnar {
72086470930SIngo Molnar 	return elf_sym__type(sym) == STT_FUNC &&
72186470930SIngo Molnar 	       sym->st_name != 0 &&
72281833130SArnaldo Carvalho de Melo 	       sym->st_shndx != SHN_UNDEF;
72386470930SIngo Molnar }
72486470930SIngo Molnar 
725f1dfa0b1SArnaldo Carvalho de Melo static inline bool elf_sym__is_object(const GElf_Sym *sym)
726f1dfa0b1SArnaldo Carvalho de Melo {
727f1dfa0b1SArnaldo Carvalho de Melo 	return elf_sym__type(sym) == STT_OBJECT &&
728f1dfa0b1SArnaldo Carvalho de Melo 		sym->st_name != 0 &&
729f1dfa0b1SArnaldo Carvalho de Melo 		sym->st_shndx != SHN_UNDEF;
730f1dfa0b1SArnaldo Carvalho de Melo }
731f1dfa0b1SArnaldo Carvalho de Melo 
7326cfcc53eSMike Galbraith static inline int elf_sym__is_label(const GElf_Sym *sym)
7336cfcc53eSMike Galbraith {
7346cfcc53eSMike Galbraith 	return elf_sym__type(sym) == STT_NOTYPE &&
7356cfcc53eSMike Galbraith 		sym->st_name != 0 &&
7366cfcc53eSMike Galbraith 		sym->st_shndx != SHN_UNDEF &&
7376cfcc53eSMike Galbraith 		sym->st_shndx != SHN_ABS;
7386cfcc53eSMike Galbraith }
7396cfcc53eSMike Galbraith 
7406cfcc53eSMike Galbraith static inline const char *elf_sec__name(const GElf_Shdr *shdr,
7416cfcc53eSMike Galbraith 					const Elf_Data *secstrs)
7426cfcc53eSMike Galbraith {
7436cfcc53eSMike Galbraith 	return secstrs->d_buf + shdr->sh_name;
7446cfcc53eSMike Galbraith }
7456cfcc53eSMike Galbraith 
7466cfcc53eSMike Galbraith static inline int elf_sec__is_text(const GElf_Shdr *shdr,
7476cfcc53eSMike Galbraith 					const Elf_Data *secstrs)
7486cfcc53eSMike Galbraith {
7496cfcc53eSMike Galbraith 	return strstr(elf_sec__name(shdr, secstrs), "text") != NULL;
7506cfcc53eSMike Galbraith }
7516cfcc53eSMike Galbraith 
752f1dfa0b1SArnaldo Carvalho de Melo static inline bool elf_sec__is_data(const GElf_Shdr *shdr,
753f1dfa0b1SArnaldo Carvalho de Melo 				    const Elf_Data *secstrs)
754f1dfa0b1SArnaldo Carvalho de Melo {
755f1dfa0b1SArnaldo Carvalho de Melo 	return strstr(elf_sec__name(shdr, secstrs), "data") != NULL;
756f1dfa0b1SArnaldo Carvalho de Melo }
757f1dfa0b1SArnaldo Carvalho de Melo 
75886470930SIngo Molnar static inline const char *elf_sym__name(const GElf_Sym *sym,
75986470930SIngo Molnar 					const Elf_Data *symstrs)
76086470930SIngo Molnar {
76186470930SIngo Molnar 	return symstrs->d_buf + sym->st_name;
76286470930SIngo Molnar }
76386470930SIngo Molnar 
76486470930SIngo Molnar static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
76586470930SIngo Molnar 				    GElf_Shdr *shp, const char *name,
76683a0944fSIngo Molnar 				    size_t *idx)
76786470930SIngo Molnar {
76886470930SIngo Molnar 	Elf_Scn *sec = NULL;
76986470930SIngo Molnar 	size_t cnt = 1;
77086470930SIngo Molnar 
77186470930SIngo Molnar 	while ((sec = elf_nextscn(elf, sec)) != NULL) {
77286470930SIngo Molnar 		char *str;
77386470930SIngo Molnar 
77486470930SIngo Molnar 		gelf_getshdr(sec, shp);
77586470930SIngo Molnar 		str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name);
77686470930SIngo Molnar 		if (!strcmp(name, str)) {
77783a0944fSIngo Molnar 			if (idx)
77883a0944fSIngo Molnar 				*idx = cnt;
77986470930SIngo Molnar 			break;
78086470930SIngo Molnar 		}
78186470930SIngo Molnar 		++cnt;
78286470930SIngo Molnar 	}
78386470930SIngo Molnar 
78486470930SIngo Molnar 	return sec;
78586470930SIngo Molnar }
78686470930SIngo Molnar 
78786470930SIngo Molnar #define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \
78886470930SIngo Molnar 	for (idx = 0, pos = gelf_getrel(reldata, 0, &pos_mem); \
78986470930SIngo Molnar 	     idx < nr_entries; \
79086470930SIngo Molnar 	     ++idx, pos = gelf_getrel(reldata, idx, &pos_mem))
79186470930SIngo Molnar 
79286470930SIngo Molnar #define elf_section__for_each_rela(reldata, pos, pos_mem, idx, nr_entries) \
79386470930SIngo Molnar 	for (idx = 0, pos = gelf_getrela(reldata, 0, &pos_mem); \
79486470930SIngo Molnar 	     idx < nr_entries; \
79586470930SIngo Molnar 	     ++idx, pos = gelf_getrela(reldata, idx, &pos_mem))
79686470930SIngo Molnar 
797a25e46c4SArnaldo Carvalho de Melo /*
798a25e46c4SArnaldo Carvalho de Melo  * We need to check if we have a .dynsym, so that we can handle the
799a25e46c4SArnaldo Carvalho de Melo  * .plt, synthesizing its symbols, that aren't on the symtabs (be it
800a25e46c4SArnaldo Carvalho de Melo  * .dynsym or .symtab).
801a25e46c4SArnaldo Carvalho de Melo  * And always look at the original dso, not at debuginfo packages, that
802a25e46c4SArnaldo Carvalho de Melo  * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS).
803a25e46c4SArnaldo Carvalho de Melo  */
80482164161SArnaldo Carvalho de Melo static int dso__synthesize_plt_symbols(struct  dso *self, struct map *map,
80582164161SArnaldo Carvalho de Melo 				       symbol_filter_t filter)
80686470930SIngo Molnar {
80786470930SIngo Molnar 	uint32_t nr_rel_entries, idx;
80886470930SIngo Molnar 	GElf_Sym sym;
8099cffa8d5SPaul Mackerras 	u64 plt_offset;
81086470930SIngo Molnar 	GElf_Shdr shdr_plt;
81186470930SIngo Molnar 	struct symbol *f;
812a25e46c4SArnaldo Carvalho de Melo 	GElf_Shdr shdr_rel_plt, shdr_dynsym;
81386470930SIngo Molnar 	Elf_Data *reldata, *syms, *symstrs;
814a25e46c4SArnaldo Carvalho de Melo 	Elf_Scn *scn_plt_rel, *scn_symstrs, *scn_dynsym;
815a25e46c4SArnaldo Carvalho de Melo 	size_t dynsym_idx;
816a25e46c4SArnaldo Carvalho de Melo 	GElf_Ehdr ehdr;
81786470930SIngo Molnar 	char sympltname[1024];
818a25e46c4SArnaldo Carvalho de Melo 	Elf *elf;
819a25e46c4SArnaldo Carvalho de Melo 	int nr = 0, symidx, fd, err = 0;
82086470930SIngo Molnar 
821439d473bSArnaldo Carvalho de Melo 	fd = open(self->long_name, O_RDONLY);
822a25e46c4SArnaldo Carvalho de Melo 	if (fd < 0)
823a25e46c4SArnaldo Carvalho de Melo 		goto out;
824a25e46c4SArnaldo Carvalho de Melo 
82584087126SMarti Raudsepp 	elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
826a25e46c4SArnaldo Carvalho de Melo 	if (elf == NULL)
827a25e46c4SArnaldo Carvalho de Melo 		goto out_close;
828a25e46c4SArnaldo Carvalho de Melo 
829a25e46c4SArnaldo Carvalho de Melo 	if (gelf_getehdr(elf, &ehdr) == NULL)
830a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
831a25e46c4SArnaldo Carvalho de Melo 
832a25e46c4SArnaldo Carvalho de Melo 	scn_dynsym = elf_section_by_name(elf, &ehdr, &shdr_dynsym,
833a25e46c4SArnaldo Carvalho de Melo 					 ".dynsym", &dynsym_idx);
834a25e46c4SArnaldo Carvalho de Melo 	if (scn_dynsym == NULL)
835a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
836a25e46c4SArnaldo Carvalho de Melo 
837a25e46c4SArnaldo Carvalho de Melo 	scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
83886470930SIngo Molnar 					  ".rela.plt", NULL);
83986470930SIngo Molnar 	if (scn_plt_rel == NULL) {
840a25e46c4SArnaldo Carvalho de Melo 		scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt,
84186470930SIngo Molnar 						  ".rel.plt", NULL);
84286470930SIngo Molnar 		if (scn_plt_rel == NULL)
843a25e46c4SArnaldo Carvalho de Melo 			goto out_elf_end;
84486470930SIngo Molnar 	}
84586470930SIngo Molnar 
846a25e46c4SArnaldo Carvalho de Melo 	err = -1;
84786470930SIngo Molnar 
848a25e46c4SArnaldo Carvalho de Melo 	if (shdr_rel_plt.sh_link != dynsym_idx)
849a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
850a25e46c4SArnaldo Carvalho de Melo 
851a25e46c4SArnaldo Carvalho de Melo 	if (elf_section_by_name(elf, &ehdr, &shdr_plt, ".plt", NULL) == NULL)
852a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
85386470930SIngo Molnar 
85486470930SIngo Molnar 	/*
85583a0944fSIngo Molnar 	 * Fetch the relocation section to find the idxes to the GOT
85686470930SIngo Molnar 	 * and the symbols in the .dynsym they refer to.
85786470930SIngo Molnar 	 */
85886470930SIngo Molnar 	reldata = elf_getdata(scn_plt_rel, NULL);
85986470930SIngo Molnar 	if (reldata == NULL)
860a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
86186470930SIngo Molnar 
86286470930SIngo Molnar 	syms = elf_getdata(scn_dynsym, NULL);
86386470930SIngo Molnar 	if (syms == NULL)
864a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
86586470930SIngo Molnar 
866a25e46c4SArnaldo Carvalho de Melo 	scn_symstrs = elf_getscn(elf, shdr_dynsym.sh_link);
86786470930SIngo Molnar 	if (scn_symstrs == NULL)
868a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
86986470930SIngo Molnar 
87086470930SIngo Molnar 	symstrs = elf_getdata(scn_symstrs, NULL);
87186470930SIngo Molnar 	if (symstrs == NULL)
872a25e46c4SArnaldo Carvalho de Melo 		goto out_elf_end;
87386470930SIngo Molnar 
87486470930SIngo Molnar 	nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize;
87586470930SIngo Molnar 	plt_offset = shdr_plt.sh_offset;
87686470930SIngo Molnar 
87786470930SIngo Molnar 	if (shdr_rel_plt.sh_type == SHT_RELA) {
87886470930SIngo Molnar 		GElf_Rela pos_mem, *pos;
87986470930SIngo Molnar 
88086470930SIngo Molnar 		elf_section__for_each_rela(reldata, pos, pos_mem, idx,
88186470930SIngo Molnar 					   nr_rel_entries) {
88286470930SIngo Molnar 			symidx = GELF_R_SYM(pos->r_info);
88386470930SIngo Molnar 			plt_offset += shdr_plt.sh_entsize;
88486470930SIngo Molnar 			gelf_getsym(syms, symidx, &sym);
88586470930SIngo Molnar 			snprintf(sympltname, sizeof(sympltname),
88686470930SIngo Molnar 				 "%s@plt", elf_sym__name(&sym, symstrs));
88786470930SIngo Molnar 
88886470930SIngo Molnar 			f = symbol__new(plt_offset, shdr_plt.sh_entsize,
889c408fedfSArnaldo Carvalho de Melo 					STB_GLOBAL, sympltname);
89086470930SIngo Molnar 			if (!f)
891a25e46c4SArnaldo Carvalho de Melo 				goto out_elf_end;
89286470930SIngo Molnar 
89382164161SArnaldo Carvalho de Melo 			if (filter && filter(map, f))
89482164161SArnaldo Carvalho de Melo 				symbol__delete(f);
89582164161SArnaldo Carvalho de Melo 			else {
8966a4694a4SArnaldo Carvalho de Melo 				symbols__insert(&self->symbols[map->type], f);
89786470930SIngo Molnar 				++nr;
89886470930SIngo Molnar 			}
89982164161SArnaldo Carvalho de Melo 		}
90086470930SIngo Molnar 	} else if (shdr_rel_plt.sh_type == SHT_REL) {
90186470930SIngo Molnar 		GElf_Rel pos_mem, *pos;
90286470930SIngo Molnar 		elf_section__for_each_rel(reldata, pos, pos_mem, idx,
90386470930SIngo Molnar 					  nr_rel_entries) {
90486470930SIngo Molnar 			symidx = GELF_R_SYM(pos->r_info);
90586470930SIngo Molnar 			plt_offset += shdr_plt.sh_entsize;
90686470930SIngo Molnar 			gelf_getsym(syms, symidx, &sym);
90786470930SIngo Molnar 			snprintf(sympltname, sizeof(sympltname),
90886470930SIngo Molnar 				 "%s@plt", elf_sym__name(&sym, symstrs));
90986470930SIngo Molnar 
91086470930SIngo Molnar 			f = symbol__new(plt_offset, shdr_plt.sh_entsize,
911c408fedfSArnaldo Carvalho de Melo 					STB_GLOBAL, sympltname);
91286470930SIngo Molnar 			if (!f)
913a25e46c4SArnaldo Carvalho de Melo 				goto out_elf_end;
91486470930SIngo Molnar 
91582164161SArnaldo Carvalho de Melo 			if (filter && filter(map, f))
91682164161SArnaldo Carvalho de Melo 				symbol__delete(f);
91782164161SArnaldo Carvalho de Melo 			else {
9186a4694a4SArnaldo Carvalho de Melo 				symbols__insert(&self->symbols[map->type], f);
91986470930SIngo Molnar 				++nr;
92086470930SIngo Molnar 			}
92186470930SIngo Molnar 		}
92282164161SArnaldo Carvalho de Melo 	}
92386470930SIngo Molnar 
924a25e46c4SArnaldo Carvalho de Melo 	err = 0;
925a25e46c4SArnaldo Carvalho de Melo out_elf_end:
926a25e46c4SArnaldo Carvalho de Melo 	elf_end(elf);
927a25e46c4SArnaldo Carvalho de Melo out_close:
928a25e46c4SArnaldo Carvalho de Melo 	close(fd);
929a25e46c4SArnaldo Carvalho de Melo 
930a25e46c4SArnaldo Carvalho de Melo 	if (err == 0)
93186470930SIngo Molnar 		return nr;
932a25e46c4SArnaldo Carvalho de Melo out:
933fe2197b8SArnaldo Carvalho de Melo 	pr_debug("%s: problems reading %s PLT info.\n",
934439d473bSArnaldo Carvalho de Melo 		 __func__, self->long_name);
935a25e46c4SArnaldo Carvalho de Melo 	return 0;
93686470930SIngo Molnar }
93786470930SIngo Molnar 
938d45868d3SArnaldo Carvalho de Melo static bool elf_sym__is_a(GElf_Sym *self, enum map_type type)
939d45868d3SArnaldo Carvalho de Melo {
940d45868d3SArnaldo Carvalho de Melo 	switch (type) {
941d45868d3SArnaldo Carvalho de Melo 	case MAP__FUNCTION:
942d45868d3SArnaldo Carvalho de Melo 		return elf_sym__is_function(self);
943f1dfa0b1SArnaldo Carvalho de Melo 	case MAP__VARIABLE:
944f1dfa0b1SArnaldo Carvalho de Melo 		return elf_sym__is_object(self);
945d45868d3SArnaldo Carvalho de Melo 	default:
946d45868d3SArnaldo Carvalho de Melo 		return false;
947d45868d3SArnaldo Carvalho de Melo 	}
948d45868d3SArnaldo Carvalho de Melo }
949d45868d3SArnaldo Carvalho de Melo 
950d45868d3SArnaldo Carvalho de Melo static bool elf_sec__is_a(GElf_Shdr *self, Elf_Data *secstrs, enum map_type type)
951d45868d3SArnaldo Carvalho de Melo {
952d45868d3SArnaldo Carvalho de Melo 	switch (type) {
953d45868d3SArnaldo Carvalho de Melo 	case MAP__FUNCTION:
954d45868d3SArnaldo Carvalho de Melo 		return elf_sec__is_text(self, secstrs);
955f1dfa0b1SArnaldo Carvalho de Melo 	case MAP__VARIABLE:
956f1dfa0b1SArnaldo Carvalho de Melo 		return elf_sec__is_data(self, secstrs);
957d45868d3SArnaldo Carvalho de Melo 	default:
958d45868d3SArnaldo Carvalho de Melo 		return false;
959d45868d3SArnaldo Carvalho de Melo 	}
960d45868d3SArnaldo Carvalho de Melo }
961d45868d3SArnaldo Carvalho de Melo 
96270c3856bSEric B Munson static size_t elf_addr_to_index(Elf *elf, GElf_Addr addr)
96370c3856bSEric B Munson {
96470c3856bSEric B Munson 	Elf_Scn *sec = NULL;
96570c3856bSEric B Munson 	GElf_Shdr shdr;
96670c3856bSEric B Munson 	size_t cnt = 1;
96770c3856bSEric B Munson 
96870c3856bSEric B Munson 	while ((sec = elf_nextscn(elf, sec)) != NULL) {
96970c3856bSEric B Munson 		gelf_getshdr(sec, &shdr);
97070c3856bSEric B Munson 
97170c3856bSEric B Munson 		if ((addr >= shdr.sh_addr) &&
97270c3856bSEric B Munson 		    (addr < (shdr.sh_addr + shdr.sh_size)))
97370c3856bSEric B Munson 			return cnt;
97470c3856bSEric B Munson 
97570c3856bSEric B Munson 		++cnt;
97670c3856bSEric B Munson 	}
97770c3856bSEric B Munson 
97870c3856bSEric B Munson 	return -1;
97970c3856bSEric B Munson }
98070c3856bSEric B Munson 
9819de89fe7SArnaldo Carvalho de Melo static int dso__load_sym(struct dso *self, struct map *map, const char *name,
9826da80ce8SDave Martin 			 int fd, symbol_filter_t filter, int kmodule,
9836da80ce8SDave Martin 			 int want_symtab)
98486470930SIngo Molnar {
9859de89fe7SArnaldo Carvalho de Melo 	struct kmap *kmap = self->kernel ? map__kmap(map) : NULL;
9862e538c4aSArnaldo Carvalho de Melo 	struct map *curr_map = map;
9872e538c4aSArnaldo Carvalho de Melo 	struct dso *curr_dso = self;
9886cfcc53eSMike Galbraith 	Elf_Data *symstrs, *secstrs;
98986470930SIngo Molnar 	uint32_t nr_syms;
99086470930SIngo Molnar 	int err = -1;
99183a0944fSIngo Molnar 	uint32_t idx;
99286470930SIngo Molnar 	GElf_Ehdr ehdr;
99370c3856bSEric B Munson 	GElf_Shdr shdr, opdshdr;
99470c3856bSEric B Munson 	Elf_Data *syms, *opddata = NULL;
99586470930SIngo Molnar 	GElf_Sym sym;
99670c3856bSEric B Munson 	Elf_Scn *sec, *sec_strndx, *opdsec;
99786470930SIngo Molnar 	Elf *elf;
998439d473bSArnaldo Carvalho de Melo 	int nr = 0;
99970c3856bSEric B Munson 	size_t opdidx = 0;
100086470930SIngo Molnar 
100184087126SMarti Raudsepp 	elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
100286470930SIngo Molnar 	if (elf == NULL) {
10038b1389efSDave Martin 		pr_debug("%s: cannot read %s ELF file.\n", __func__, name);
100486470930SIngo Molnar 		goto out_close;
100586470930SIngo Molnar 	}
100686470930SIngo Molnar 
100786470930SIngo Molnar 	if (gelf_getehdr(elf, &ehdr) == NULL) {
10088b1389efSDave Martin 		pr_debug("%s: cannot get elf header.\n", __func__);
100986470930SIngo Molnar 		goto out_elf_end;
101086470930SIngo Molnar 	}
101186470930SIngo Molnar 
10126da80ce8SDave Martin 	/* Always reject images with a mismatched build-id: */
101321916c38SDave Martin 	if (self->has_build_id) {
101421916c38SDave Martin 		u8 build_id[BUILD_ID_SIZE];
101521916c38SDave Martin 
101621916c38SDave Martin 		if (elf_read_build_id(elf, build_id,
101721916c38SDave Martin 				      BUILD_ID_SIZE) != BUILD_ID_SIZE)
101821916c38SDave Martin 			goto out_elf_end;
101921916c38SDave Martin 
102021916c38SDave Martin 		if (!dso__build_id_equal(self, build_id))
102121916c38SDave Martin 			goto out_elf_end;
102221916c38SDave Martin 	}
102321916c38SDave Martin 
102486470930SIngo Molnar 	sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL);
102586470930SIngo Molnar 	if (sec == NULL) {
10266da80ce8SDave Martin 		if (want_symtab)
10276da80ce8SDave Martin 			goto out_elf_end;
10286da80ce8SDave Martin 
1029a25e46c4SArnaldo Carvalho de Melo 		sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL);
1030a25e46c4SArnaldo Carvalho de Melo 		if (sec == NULL)
103186470930SIngo Molnar 			goto out_elf_end;
103286470930SIngo Molnar 	}
103386470930SIngo Molnar 
103470c3856bSEric B Munson 	opdsec = elf_section_by_name(elf, &ehdr, &opdshdr, ".opd", &opdidx);
103570c3856bSEric B Munson 	if (opdsec)
103670c3856bSEric B Munson 		opddata = elf_rawdata(opdsec, NULL);
103770c3856bSEric B Munson 
103886470930SIngo Molnar 	syms = elf_getdata(sec, NULL);
103986470930SIngo Molnar 	if (syms == NULL)
104086470930SIngo Molnar 		goto out_elf_end;
104186470930SIngo Molnar 
104286470930SIngo Molnar 	sec = elf_getscn(elf, shdr.sh_link);
104386470930SIngo Molnar 	if (sec == NULL)
104486470930SIngo Molnar 		goto out_elf_end;
104586470930SIngo Molnar 
104686470930SIngo Molnar 	symstrs = elf_getdata(sec, NULL);
104786470930SIngo Molnar 	if (symstrs == NULL)
104886470930SIngo Molnar 		goto out_elf_end;
104986470930SIngo Molnar 
10506cfcc53eSMike Galbraith 	sec_strndx = elf_getscn(elf, ehdr.e_shstrndx);
10516cfcc53eSMike Galbraith 	if (sec_strndx == NULL)
10526cfcc53eSMike Galbraith 		goto out_elf_end;
10536cfcc53eSMike Galbraith 
10546cfcc53eSMike Galbraith 	secstrs = elf_getdata(sec_strndx, NULL);
10559b30a26bSStoyan Gaydarov 	if (secstrs == NULL)
10566cfcc53eSMike Galbraith 		goto out_elf_end;
10576cfcc53eSMike Galbraith 
105886470930SIngo Molnar 	nr_syms = shdr.sh_size / shdr.sh_entsize;
105986470930SIngo Molnar 
1060e9fbc9dcSArjan van de Ven 	memset(&sym, 0, sizeof(sym));
1061a1645ce1SZhang, Yanmin 	if (self->kernel == DSO_TYPE_USER) {
106230d7a77dSArnaldo Carvalho de Melo 		self->adjust_symbols = (ehdr.e_type == ET_EXEC ||
106330d7a77dSArnaldo Carvalho de Melo 				elf_section_by_name(elf, &ehdr, &shdr,
1064f5812a7aSArnaldo Carvalho de Melo 						     ".gnu.prelink_undo",
106530d7a77dSArnaldo Carvalho de Melo 						     NULL) != NULL);
1066d20ff6bdSMike Galbraith 	} else self->adjust_symbols = 0;
1067d20ff6bdSMike Galbraith 
106883a0944fSIngo Molnar 	elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) {
106986470930SIngo Molnar 		struct symbol *f;
107056b03f3cSArnaldo Carvalho de Melo 		const char *elf_name = elf_sym__name(&sym, symstrs);
10712e538c4aSArnaldo Carvalho de Melo 		char *demangled = NULL;
10726cfcc53eSMike Galbraith 		int is_label = elf_sym__is_label(&sym);
10736cfcc53eSMike Galbraith 		const char *section_name;
107486470930SIngo Molnar 
10759de89fe7SArnaldo Carvalho de Melo 		if (kmap && kmap->ref_reloc_sym && kmap->ref_reloc_sym->name &&
10769de89fe7SArnaldo Carvalho de Melo 		    strcmp(elf_name, kmap->ref_reloc_sym->name) == 0)
10779de89fe7SArnaldo Carvalho de Melo 			kmap->ref_reloc_sym->unrelocated_addr = sym.st_value;
107856b03f3cSArnaldo Carvalho de Melo 
1079d45868d3SArnaldo Carvalho de Melo 		if (!is_label && !elf_sym__is_a(&sym, map->type))
108086470930SIngo Molnar 			continue;
108186470930SIngo Molnar 
1082*696b97a5SDave Martin 		/* Reject ARM ELF "mapping symbols": these aren't unique and
1083*696b97a5SDave Martin 		 * don't identify functions, so will confuse the profile
1084*696b97a5SDave Martin 		 * output: */
1085*696b97a5SDave Martin 		if (ehdr.e_machine == EM_ARM) {
1086*696b97a5SDave Martin 			if (!strcmp(elf_name, "$a") ||
1087*696b97a5SDave Martin 			    !strcmp(elf_name, "$d") ||
1088*696b97a5SDave Martin 			    !strcmp(elf_name, "$t"))
1089*696b97a5SDave Martin 				continue;
1090*696b97a5SDave Martin 		}
1091*696b97a5SDave Martin 
109270c3856bSEric B Munson 		if (opdsec && sym.st_shndx == opdidx) {
109370c3856bSEric B Munson 			u32 offset = sym.st_value - opdshdr.sh_addr;
109470c3856bSEric B Munson 			u64 *opd = opddata->d_buf + offset;
109570c3856bSEric B Munson 			sym.st_value = *opd;
109670c3856bSEric B Munson 			sym.st_shndx = elf_addr_to_index(elf, sym.st_value);
109770c3856bSEric B Munson 		}
109870c3856bSEric B Munson 
109986470930SIngo Molnar 		sec = elf_getscn(elf, sym.st_shndx);
110086470930SIngo Molnar 		if (!sec)
110186470930SIngo Molnar 			goto out_elf_end;
110286470930SIngo Molnar 
110386470930SIngo Molnar 		gelf_getshdr(sec, &shdr);
11046cfcc53eSMike Galbraith 
1105d45868d3SArnaldo Carvalho de Melo 		if (is_label && !elf_sec__is_a(&shdr, secstrs, map->type))
11066cfcc53eSMike Galbraith 			continue;
11076cfcc53eSMike Galbraith 
11086cfcc53eSMike Galbraith 		section_name = elf_sec__name(&shdr, secstrs);
110986470930SIngo Molnar 
1110a1645ce1SZhang, Yanmin 		if (self->kernel != DSO_TYPE_USER || kmodule) {
11112e538c4aSArnaldo Carvalho de Melo 			char dso_name[PATH_MAX];
11122e538c4aSArnaldo Carvalho de Melo 
11132e538c4aSArnaldo Carvalho de Melo 			if (strcmp(section_name,
1114b63be8d7SArnaldo Carvalho de Melo 				   (curr_dso->short_name +
1115b63be8d7SArnaldo Carvalho de Melo 				    self->short_name_len)) == 0)
11162e538c4aSArnaldo Carvalho de Melo 				goto new_symbol;
11172e538c4aSArnaldo Carvalho de Melo 
11182e538c4aSArnaldo Carvalho de Melo 			if (strcmp(section_name, ".text") == 0) {
11192e538c4aSArnaldo Carvalho de Melo 				curr_map = map;
11202e538c4aSArnaldo Carvalho de Melo 				curr_dso = self;
11212e538c4aSArnaldo Carvalho de Melo 				goto new_symbol;
1122af427bf5SArnaldo Carvalho de Melo 			}
1123af427bf5SArnaldo Carvalho de Melo 
11242e538c4aSArnaldo Carvalho de Melo 			snprintf(dso_name, sizeof(dso_name),
11252e538c4aSArnaldo Carvalho de Melo 				 "%s%s", self->short_name, section_name);
11262e538c4aSArnaldo Carvalho de Melo 
11279de89fe7SArnaldo Carvalho de Melo 			curr_map = map_groups__find_by_name(kmap->kmaps, map->type, dso_name);
11282e538c4aSArnaldo Carvalho de Melo 			if (curr_map == NULL) {
11292e538c4aSArnaldo Carvalho de Melo 				u64 start = sym.st_value;
11302e538c4aSArnaldo Carvalho de Melo 
11312e538c4aSArnaldo Carvalho de Melo 				if (kmodule)
11322e538c4aSArnaldo Carvalho de Melo 					start += map->start + shdr.sh_offset;
11332e538c4aSArnaldo Carvalho de Melo 
113400a192b3SArnaldo Carvalho de Melo 				curr_dso = dso__new(dso_name);
11352e538c4aSArnaldo Carvalho de Melo 				if (curr_dso == NULL)
11362e538c4aSArnaldo Carvalho de Melo 					goto out_elf_end;
1137a1645ce1SZhang, Yanmin 				curr_dso->kernel = self->kernel;
11383610583cSArnaldo Carvalho de Melo 				curr_map = map__new2(start, curr_dso,
11396275ce2dSArnaldo Carvalho de Melo 						     map->type);
11402e538c4aSArnaldo Carvalho de Melo 				if (curr_map == NULL) {
11412e538c4aSArnaldo Carvalho de Melo 					dso__delete(curr_dso);
11422e538c4aSArnaldo Carvalho de Melo 					goto out_elf_end;
11432e538c4aSArnaldo Carvalho de Melo 				}
1144ed52ce2eSArnaldo Carvalho de Melo 				curr_map->map_ip = identity__map_ip;
1145ed52ce2eSArnaldo Carvalho de Melo 				curr_map->unmap_ip = identity__map_ip;
1146b0a9ab62SArnaldo Carvalho de Melo 				curr_dso->origin = self->origin;
11479de89fe7SArnaldo Carvalho de Melo 				map_groups__insert(kmap->kmaps, curr_map);
1148a1645ce1SZhang, Yanmin 				dsos__add(&self->node, curr_dso);
11496275ce2dSArnaldo Carvalho de Melo 				dso__set_loaded(curr_dso, map->type);
11502e538c4aSArnaldo Carvalho de Melo 			} else
11512e538c4aSArnaldo Carvalho de Melo 				curr_dso = curr_map->dso;
11522e538c4aSArnaldo Carvalho de Melo 
11532e538c4aSArnaldo Carvalho de Melo 			goto new_symbol;
11542e538c4aSArnaldo Carvalho de Melo 		}
11552e538c4aSArnaldo Carvalho de Melo 
11562e538c4aSArnaldo Carvalho de Melo 		if (curr_dso->adjust_symbols) {
115729a9f66dSArnaldo Carvalho de Melo 			pr_debug4("%s: adjusting symbol: st_value: %#Lx "
115829a9f66dSArnaldo Carvalho de Melo 				  "sh_addr: %#Lx sh_offset: %#Lx\n", __func__,
115929a9f66dSArnaldo Carvalho de Melo 				  (u64)sym.st_value, (u64)shdr.sh_addr,
116029a9f66dSArnaldo Carvalho de Melo 				  (u64)shdr.sh_offset);
116186470930SIngo Molnar 			sym.st_value -= shdr.sh_addr - shdr.sh_offset;
1162af427bf5SArnaldo Carvalho de Melo 		}
116328ac909bSArnaldo Carvalho de Melo 		/*
116428ac909bSArnaldo Carvalho de Melo 		 * We need to figure out if the object was created from C++ sources
116528ac909bSArnaldo Carvalho de Melo 		 * DWARF DW_compile_unit has this, but we don't always have access
116628ac909bSArnaldo Carvalho de Melo 		 * to it...
116728ac909bSArnaldo Carvalho de Melo 		 */
116883a0944fSIngo Molnar 		demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI);
116928ac909bSArnaldo Carvalho de Melo 		if (demangled != NULL)
117083a0944fSIngo Molnar 			elf_name = demangled;
11712e538c4aSArnaldo Carvalho de Melo new_symbol:
1172c408fedfSArnaldo Carvalho de Melo 		f = symbol__new(sym.st_value, sym.st_size,
1173c408fedfSArnaldo Carvalho de Melo 				GELF_ST_BIND(sym.st_info), elf_name);
117428ac909bSArnaldo Carvalho de Melo 		free(demangled);
117586470930SIngo Molnar 		if (!f)
117686470930SIngo Molnar 			goto out_elf_end;
117786470930SIngo Molnar 
11782e538c4aSArnaldo Carvalho de Melo 		if (filter && filter(curr_map, f))
117900a192b3SArnaldo Carvalho de Melo 			symbol__delete(f);
118086470930SIngo Molnar 		else {
11816a4694a4SArnaldo Carvalho de Melo 			symbols__insert(&curr_dso->symbols[curr_map->type], f);
118286470930SIngo Molnar 			nr++;
118386470930SIngo Molnar 		}
118486470930SIngo Molnar 	}
118586470930SIngo Molnar 
11862e538c4aSArnaldo Carvalho de Melo 	/*
11872e538c4aSArnaldo Carvalho de Melo 	 * For misannotated, zeroed, ASM function sizes.
11882e538c4aSArnaldo Carvalho de Melo 	 */
11896275ce2dSArnaldo Carvalho de Melo 	if (nr > 0) {
11906a4694a4SArnaldo Carvalho de Melo 		symbols__fixup_end(&self->symbols[map->type]);
11916275ce2dSArnaldo Carvalho de Melo 		if (kmap) {
11926275ce2dSArnaldo Carvalho de Melo 			/*
11936275ce2dSArnaldo Carvalho de Melo 			 * We need to fixup this here too because we create new
11946275ce2dSArnaldo Carvalho de Melo 			 * maps here, for things like vsyscall sections.
11956275ce2dSArnaldo Carvalho de Melo 			 */
11966275ce2dSArnaldo Carvalho de Melo 			__map_groups__fixup_end(kmap->kmaps, map->type);
11976275ce2dSArnaldo Carvalho de Melo 		}
11986275ce2dSArnaldo Carvalho de Melo 	}
119986470930SIngo Molnar 	err = nr;
120086470930SIngo Molnar out_elf_end:
120186470930SIngo Molnar 	elf_end(elf);
120286470930SIngo Molnar out_close:
120386470930SIngo Molnar 	return err;
120486470930SIngo Molnar }
120586470930SIngo Molnar 
120678075caaSArnaldo Carvalho de Melo static bool dso__build_id_equal(const struct dso *self, u8 *build_id)
120778075caaSArnaldo Carvalho de Melo {
120878075caaSArnaldo Carvalho de Melo 	return memcmp(self->build_id, build_id, sizeof(self->build_id)) == 0;
120978075caaSArnaldo Carvalho de Melo }
121078075caaSArnaldo Carvalho de Melo 
1211a1645ce1SZhang, Yanmin bool __dsos__read_build_ids(struct list_head *head, bool with_hits)
121257f395a7SFrederic Weisbecker {
1213e30a3d12SArnaldo Carvalho de Melo 	bool have_build_id = false;
121457f395a7SFrederic Weisbecker 	struct dso *pos;
121557f395a7SFrederic Weisbecker 
12166122e4e4SArnaldo Carvalho de Melo 	list_for_each_entry(pos, head, node) {
12176122e4e4SArnaldo Carvalho de Melo 		if (with_hits && !pos->hit)
12186122e4e4SArnaldo Carvalho de Melo 			continue;
1219f6e1467dSArnaldo Carvalho de Melo 		if (pos->has_build_id) {
1220f6e1467dSArnaldo Carvalho de Melo 			have_build_id = true;
1221f6e1467dSArnaldo Carvalho de Melo 			continue;
1222f6e1467dSArnaldo Carvalho de Melo 		}
1223e30a3d12SArnaldo Carvalho de Melo 		if (filename__read_build_id(pos->long_name, pos->build_id,
1224e30a3d12SArnaldo Carvalho de Melo 					    sizeof(pos->build_id)) > 0) {
1225e30a3d12SArnaldo Carvalho de Melo 			have_build_id	  = true;
1226e30a3d12SArnaldo Carvalho de Melo 			pos->has_build_id = true;
122757f395a7SFrederic Weisbecker 		}
12286122e4e4SArnaldo Carvalho de Melo 	}
122957f395a7SFrederic Weisbecker 
1230e30a3d12SArnaldo Carvalho de Melo 	return have_build_id;
123157f395a7SFrederic Weisbecker }
123257f395a7SFrederic Weisbecker 
1233fd7a346eSArnaldo Carvalho de Melo /*
1234fd7a346eSArnaldo Carvalho de Melo  * Align offset to 4 bytes as needed for note name and descriptor data.
1235fd7a346eSArnaldo Carvalho de Melo  */
1236fd7a346eSArnaldo Carvalho de Melo #define NOTE_ALIGN(n) (((n) + 3) & -4U)
1237fd7a346eSArnaldo Carvalho de Melo 
123821916c38SDave Martin static int elf_read_build_id(Elf *elf, void *bf, size_t size)
12394d1e00a8SArnaldo Carvalho de Melo {
124021916c38SDave Martin 	int err = -1;
12414d1e00a8SArnaldo Carvalho de Melo 	GElf_Ehdr ehdr;
12424d1e00a8SArnaldo Carvalho de Melo 	GElf_Shdr shdr;
1243fd7a346eSArnaldo Carvalho de Melo 	Elf_Data *data;
12444d1e00a8SArnaldo Carvalho de Melo 	Elf_Scn *sec;
1245e57cfcdaSPekka Enberg 	Elf_Kind ek;
1246fd7a346eSArnaldo Carvalho de Melo 	void *ptr;
12474d1e00a8SArnaldo Carvalho de Melo 
12482643ce11SArnaldo Carvalho de Melo 	if (size < BUILD_ID_SIZE)
12492643ce11SArnaldo Carvalho de Melo 		goto out;
12502643ce11SArnaldo Carvalho de Melo 
1251e57cfcdaSPekka Enberg 	ek = elf_kind(elf);
1252e57cfcdaSPekka Enberg 	if (ek != ELF_K_ELF)
125321916c38SDave Martin 		goto out;
1254e57cfcdaSPekka Enberg 
12554d1e00a8SArnaldo Carvalho de Melo 	if (gelf_getehdr(elf, &ehdr) == NULL) {
12566beba7adSArnaldo Carvalho de Melo 		pr_err("%s: cannot get elf header.\n", __func__);
125721916c38SDave Martin 		goto out;
12584d1e00a8SArnaldo Carvalho de Melo 	}
12594d1e00a8SArnaldo Carvalho de Melo 
12602643ce11SArnaldo Carvalho de Melo 	sec = elf_section_by_name(elf, &ehdr, &shdr,
12612643ce11SArnaldo Carvalho de Melo 				  ".note.gnu.build-id", NULL);
1262fd7a346eSArnaldo Carvalho de Melo 	if (sec == NULL) {
1263fd7a346eSArnaldo Carvalho de Melo 		sec = elf_section_by_name(elf, &ehdr, &shdr,
1264fd7a346eSArnaldo Carvalho de Melo 					  ".notes", NULL);
12654d1e00a8SArnaldo Carvalho de Melo 		if (sec == NULL)
126621916c38SDave Martin 			goto out;
1267fd7a346eSArnaldo Carvalho de Melo 	}
12684d1e00a8SArnaldo Carvalho de Melo 
1269fd7a346eSArnaldo Carvalho de Melo 	data = elf_getdata(sec, NULL);
1270fd7a346eSArnaldo Carvalho de Melo 	if (data == NULL)
127121916c38SDave Martin 		goto out;
1272fd7a346eSArnaldo Carvalho de Melo 
1273fd7a346eSArnaldo Carvalho de Melo 	ptr = data->d_buf;
1274fd7a346eSArnaldo Carvalho de Melo 	while (ptr < (data->d_buf + data->d_size)) {
1275fd7a346eSArnaldo Carvalho de Melo 		GElf_Nhdr *nhdr = ptr;
1276fd7a346eSArnaldo Carvalho de Melo 		int namesz = NOTE_ALIGN(nhdr->n_namesz),
1277fd7a346eSArnaldo Carvalho de Melo 		    descsz = NOTE_ALIGN(nhdr->n_descsz);
1278fd7a346eSArnaldo Carvalho de Melo 		const char *name;
1279fd7a346eSArnaldo Carvalho de Melo 
1280fd7a346eSArnaldo Carvalho de Melo 		ptr += sizeof(*nhdr);
1281fd7a346eSArnaldo Carvalho de Melo 		name = ptr;
1282fd7a346eSArnaldo Carvalho de Melo 		ptr += namesz;
1283fd7a346eSArnaldo Carvalho de Melo 		if (nhdr->n_type == NT_GNU_BUILD_ID &&
1284fd7a346eSArnaldo Carvalho de Melo 		    nhdr->n_namesz == sizeof("GNU")) {
1285fd7a346eSArnaldo Carvalho de Melo 			if (memcmp(name, "GNU", sizeof("GNU")) == 0) {
1286fd7a346eSArnaldo Carvalho de Melo 				memcpy(bf, ptr, BUILD_ID_SIZE);
12872643ce11SArnaldo Carvalho de Melo 				err = BUILD_ID_SIZE;
1288fd7a346eSArnaldo Carvalho de Melo 				break;
1289fd7a346eSArnaldo Carvalho de Melo 			}
1290fd7a346eSArnaldo Carvalho de Melo 		}
1291fd7a346eSArnaldo Carvalho de Melo 		ptr += descsz;
1292fd7a346eSArnaldo Carvalho de Melo 	}
129321916c38SDave Martin 
129421916c38SDave Martin out:
129521916c38SDave Martin 	return err;
129621916c38SDave Martin }
129721916c38SDave Martin 
129821916c38SDave Martin int filename__read_build_id(const char *filename, void *bf, size_t size)
129921916c38SDave Martin {
130021916c38SDave Martin 	int fd, err = -1;
130121916c38SDave Martin 	Elf *elf;
130221916c38SDave Martin 
130321916c38SDave Martin 	if (size < BUILD_ID_SIZE)
130421916c38SDave Martin 		goto out;
130521916c38SDave Martin 
130621916c38SDave Martin 	fd = open(filename, O_RDONLY);
130721916c38SDave Martin 	if (fd < 0)
130821916c38SDave Martin 		goto out;
130921916c38SDave Martin 
131021916c38SDave Martin 	elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
131121916c38SDave Martin 	if (elf == NULL) {
131221916c38SDave Martin 		pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename);
131321916c38SDave Martin 		goto out_close;
131421916c38SDave Martin 	}
131521916c38SDave Martin 
131621916c38SDave Martin 	err = elf_read_build_id(elf, bf, size);
131721916c38SDave Martin 
13182643ce11SArnaldo Carvalho de Melo 	elf_end(elf);
13192643ce11SArnaldo Carvalho de Melo out_close:
13202643ce11SArnaldo Carvalho de Melo 	close(fd);
13212643ce11SArnaldo Carvalho de Melo out:
13222643ce11SArnaldo Carvalho de Melo 	return err;
13232643ce11SArnaldo Carvalho de Melo }
13242643ce11SArnaldo Carvalho de Melo 
1325f1617b40SArnaldo Carvalho de Melo int sysfs__read_build_id(const char *filename, void *build_id, size_t size)
1326f1617b40SArnaldo Carvalho de Melo {
1327f1617b40SArnaldo Carvalho de Melo 	int fd, err = -1;
1328f1617b40SArnaldo Carvalho de Melo 
1329f1617b40SArnaldo Carvalho de Melo 	if (size < BUILD_ID_SIZE)
1330f1617b40SArnaldo Carvalho de Melo 		goto out;
1331f1617b40SArnaldo Carvalho de Melo 
1332f1617b40SArnaldo Carvalho de Melo 	fd = open(filename, O_RDONLY);
1333f1617b40SArnaldo Carvalho de Melo 	if (fd < 0)
1334f1617b40SArnaldo Carvalho de Melo 		goto out;
1335f1617b40SArnaldo Carvalho de Melo 
1336f1617b40SArnaldo Carvalho de Melo 	while (1) {
1337f1617b40SArnaldo Carvalho de Melo 		char bf[BUFSIZ];
1338f1617b40SArnaldo Carvalho de Melo 		GElf_Nhdr nhdr;
1339f1617b40SArnaldo Carvalho de Melo 		int namesz, descsz;
1340f1617b40SArnaldo Carvalho de Melo 
1341f1617b40SArnaldo Carvalho de Melo 		if (read(fd, &nhdr, sizeof(nhdr)) != sizeof(nhdr))
1342f1617b40SArnaldo Carvalho de Melo 			break;
1343f1617b40SArnaldo Carvalho de Melo 
1344fd7a346eSArnaldo Carvalho de Melo 		namesz = NOTE_ALIGN(nhdr.n_namesz);
1345fd7a346eSArnaldo Carvalho de Melo 		descsz = NOTE_ALIGN(nhdr.n_descsz);
1346f1617b40SArnaldo Carvalho de Melo 		if (nhdr.n_type == NT_GNU_BUILD_ID &&
1347f1617b40SArnaldo Carvalho de Melo 		    nhdr.n_namesz == sizeof("GNU")) {
1348f1617b40SArnaldo Carvalho de Melo 			if (read(fd, bf, namesz) != namesz)
1349f1617b40SArnaldo Carvalho de Melo 				break;
1350f1617b40SArnaldo Carvalho de Melo 			if (memcmp(bf, "GNU", sizeof("GNU")) == 0) {
1351f1617b40SArnaldo Carvalho de Melo 				if (read(fd, build_id,
1352f1617b40SArnaldo Carvalho de Melo 				    BUILD_ID_SIZE) == BUILD_ID_SIZE) {
1353f1617b40SArnaldo Carvalho de Melo 					err = 0;
1354f1617b40SArnaldo Carvalho de Melo 					break;
1355f1617b40SArnaldo Carvalho de Melo 				}
1356f1617b40SArnaldo Carvalho de Melo 			} else if (read(fd, bf, descsz) != descsz)
1357f1617b40SArnaldo Carvalho de Melo 				break;
1358f1617b40SArnaldo Carvalho de Melo 		} else {
1359f1617b40SArnaldo Carvalho de Melo 			int n = namesz + descsz;
1360f1617b40SArnaldo Carvalho de Melo 			if (read(fd, bf, n) != n)
1361f1617b40SArnaldo Carvalho de Melo 				break;
1362f1617b40SArnaldo Carvalho de Melo 		}
1363f1617b40SArnaldo Carvalho de Melo 	}
1364f1617b40SArnaldo Carvalho de Melo 	close(fd);
1365f1617b40SArnaldo Carvalho de Melo out:
1366f1617b40SArnaldo Carvalho de Melo 	return err;
1367f1617b40SArnaldo Carvalho de Melo }
1368f1617b40SArnaldo Carvalho de Melo 
136994cb9e38SArnaldo Carvalho de Melo char dso__symtab_origin(const struct dso *self)
137094cb9e38SArnaldo Carvalho de Melo {
137194cb9e38SArnaldo Carvalho de Melo 	static const char origin[] = {
137294cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_KERNEL] =   'k',
137394cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_JAVA_JIT] = 'j',
13744cf40131SArnaldo Carvalho de Melo 		[DSO__ORIG_BUILD_ID_CACHE] = 'B',
137594cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_FEDORA] =   'f',
137694cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_UBUNTU] =   'u',
137794cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_BUILDID] =  'b',
137894cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_DSO] =      'd',
1379439d473bSArnaldo Carvalho de Melo 		[DSO__ORIG_KMODULE] =  'K',
1380a1645ce1SZhang, Yanmin 		[DSO__ORIG_GUEST_KERNEL] =  'g',
1381a1645ce1SZhang, Yanmin 		[DSO__ORIG_GUEST_KMODULE] =  'G',
138294cb9e38SArnaldo Carvalho de Melo 	};
138394cb9e38SArnaldo Carvalho de Melo 
138494cb9e38SArnaldo Carvalho de Melo 	if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND)
138594cb9e38SArnaldo Carvalho de Melo 		return '!';
138694cb9e38SArnaldo Carvalho de Melo 	return origin[self->origin];
138794cb9e38SArnaldo Carvalho de Melo }
138894cb9e38SArnaldo Carvalho de Melo 
13899de89fe7SArnaldo Carvalho de Melo int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
139086470930SIngo Molnar {
13914d1e00a8SArnaldo Carvalho de Melo 	int size = PATH_MAX;
1392c338aee8SArnaldo Carvalho de Melo 	char *name;
139386470930SIngo Molnar 	int ret = -1;
139486470930SIngo Molnar 	int fd;
139523346f21SArnaldo Carvalho de Melo 	struct machine *machine;
1396a1645ce1SZhang, Yanmin 	const char *root_dir;
13976da80ce8SDave Martin 	int want_symtab;
139886470930SIngo Molnar 
13993610583cSArnaldo Carvalho de Melo 	dso__set_loaded(self, map->type);
140066bd8424SArnaldo Carvalho de Melo 
1401a1645ce1SZhang, Yanmin 	if (self->kernel == DSO_TYPE_KERNEL)
14029de89fe7SArnaldo Carvalho de Melo 		return dso__load_kernel_sym(self, map, filter);
1403a1645ce1SZhang, Yanmin 	else if (self->kernel == DSO_TYPE_GUEST_KERNEL)
1404a1645ce1SZhang, Yanmin 		return dso__load_guest_kernel_sym(self, map, filter);
1405a1645ce1SZhang, Yanmin 
140623346f21SArnaldo Carvalho de Melo 	if (map->groups && map->groups->machine)
140723346f21SArnaldo Carvalho de Melo 		machine = map->groups->machine;
1408a1645ce1SZhang, Yanmin 	else
140923346f21SArnaldo Carvalho de Melo 		machine = NULL;
1410c338aee8SArnaldo Carvalho de Melo 
1411c338aee8SArnaldo Carvalho de Melo 	name = malloc(size);
141286470930SIngo Molnar 	if (!name)
141386470930SIngo Molnar 		return -1;
141486470930SIngo Molnar 
141530d7a77dSArnaldo Carvalho de Melo 	self->adjust_symbols = 0;
1416f5812a7aSArnaldo Carvalho de Melo 
141794cb9e38SArnaldo Carvalho de Melo 	if (strncmp(self->name, "/tmp/perf-", 10) == 0) {
14186beba7adSArnaldo Carvalho de Melo 		ret = dso__load_perf_map(self, map, filter);
141994cb9e38SArnaldo Carvalho de Melo 		self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT :
142094cb9e38SArnaldo Carvalho de Melo 					 DSO__ORIG_NOT_FOUND;
142194cb9e38SArnaldo Carvalho de Melo 		return ret;
142294cb9e38SArnaldo Carvalho de Melo 	}
142394cb9e38SArnaldo Carvalho de Melo 
14246da80ce8SDave Martin 	/* Iterate over candidate debug images.
14256da80ce8SDave Martin 	 * On the first pass, only load images if they have a full symtab.
14266da80ce8SDave Martin 	 * Failing that, do a second pass where we accept .dynsym also
14276da80ce8SDave Martin 	 */
14286da80ce8SDave Martin 	for (self->origin = DSO__ORIG_BUILD_ID_CACHE, want_symtab = 1;
14296da80ce8SDave Martin 	     self->origin != DSO__ORIG_NOT_FOUND;
14306da80ce8SDave Martin 	     self->origin++) {
143194cb9e38SArnaldo Carvalho de Melo 		switch (self->origin) {
14326da80ce8SDave Martin 		case DSO__ORIG_BUILD_ID_CACHE:
14336da80ce8SDave Martin 			if (dso__build_id_filename(self, name, size) == NULL)
14346da80ce8SDave Martin 				continue;
14356da80ce8SDave Martin 			break;
143694cb9e38SArnaldo Carvalho de Melo 		case DSO__ORIG_FEDORA:
1437439d473bSArnaldo Carvalho de Melo 			snprintf(name, size, "/usr/lib/debug%s.debug",
1438439d473bSArnaldo Carvalho de Melo 				 self->long_name);
143986470930SIngo Molnar 			break;
144094cb9e38SArnaldo Carvalho de Melo 		case DSO__ORIG_UBUNTU:
1441439d473bSArnaldo Carvalho de Melo 			snprintf(name, size, "/usr/lib/debug%s",
1442439d473bSArnaldo Carvalho de Melo 				 self->long_name);
144386470930SIngo Molnar 			break;
14446da80ce8SDave Martin 		case DSO__ORIG_BUILDID: {
1445b36f19d5SArnaldo Carvalho de Melo 			char build_id_hex[BUILD_ID_SIZE * 2 + 1];
14466da80ce8SDave Martin 
14476da80ce8SDave Martin 			if (!self->has_build_id)
14486da80ce8SDave Martin 				continue;
14496da80ce8SDave Martin 
145021916c38SDave Martin 			build_id__sprintf(self->build_id,
145121916c38SDave Martin 					  sizeof(self->build_id),
1452d3379ab9SArnaldo Carvalho de Melo 					  build_id_hex);
14534d1e00a8SArnaldo Carvalho de Melo 			snprintf(name, size,
14544d1e00a8SArnaldo Carvalho de Melo 				 "/usr/lib/debug/.build-id/%.2s/%s.debug",
1455d3379ab9SArnaldo Carvalho de Melo 				 build_id_hex, build_id_hex + 2);
14564d1e00a8SArnaldo Carvalho de Melo 			}
14576da80ce8SDave Martin 			break;
145894cb9e38SArnaldo Carvalho de Melo 		case DSO__ORIG_DSO:
1459439d473bSArnaldo Carvalho de Melo 			snprintf(name, size, "%s", self->long_name);
146086470930SIngo Molnar 			break;
1461a1645ce1SZhang, Yanmin 		case DSO__ORIG_GUEST_KMODULE:
146223346f21SArnaldo Carvalho de Melo 			if (map->groups && map->groups->machine)
146323346f21SArnaldo Carvalho de Melo 				root_dir = map->groups->machine->root_dir;
1464a1645ce1SZhang, Yanmin 			else
1465a1645ce1SZhang, Yanmin 				root_dir = "";
1466a1645ce1SZhang, Yanmin 			snprintf(name, size, "%s%s", root_dir, self->long_name);
1467a1645ce1SZhang, Yanmin 			break;
146886470930SIngo Molnar 
146986470930SIngo Molnar 		default:
14706da80ce8SDave Martin 			/*
14716da80ce8SDave Martin 			 * If we wanted a full symtab but no image had one,
14726da80ce8SDave Martin 			 * relax our requirements and repeat the search.
14736da80ce8SDave Martin 			 */
14746da80ce8SDave Martin 			if (want_symtab) {
14756da80ce8SDave Martin 				want_symtab = 0;
14766da80ce8SDave Martin 				self->origin = DSO__ORIG_BUILD_ID_CACHE;
14776da80ce8SDave Martin 			} else
14786da80ce8SDave Martin 				continue;
147986470930SIngo Molnar 		}
148086470930SIngo Molnar 
14816da80ce8SDave Martin 		/* Name is now the name of the next image to try */
14826da80ce8SDave Martin 		fd = open(name, O_RDONLY);
14836da80ce8SDave Martin 		if (fd < 0)
14846da80ce8SDave Martin 			continue;
14856da80ce8SDave Martin 
14866da80ce8SDave Martin 		ret = dso__load_sym(self, map, name, fd, filter, 0,
14876da80ce8SDave Martin 				    want_symtab);
148886470930SIngo Molnar 		close(fd);
148986470930SIngo Molnar 
149086470930SIngo Molnar 		/*
14916da80ce8SDave Martin 		 * Some people seem to have debuginfo files _WITHOUT_ debug
14926da80ce8SDave Martin 		 * info!?!?
149386470930SIngo Molnar 		 */
149486470930SIngo Molnar 		if (!ret)
14956da80ce8SDave Martin 			continue;
149686470930SIngo Molnar 
1497a25e46c4SArnaldo Carvalho de Melo 		if (ret > 0) {
149882164161SArnaldo Carvalho de Melo 			int nr_plt = dso__synthesize_plt_symbols(self, map, filter);
1499a25e46c4SArnaldo Carvalho de Melo 			if (nr_plt > 0)
1500a25e46c4SArnaldo Carvalho de Melo 				ret += nr_plt;
15016da80ce8SDave Martin 			break;
1502a25e46c4SArnaldo Carvalho de Melo 		}
15036da80ce8SDave Martin 	}
15046da80ce8SDave Martin 
150586470930SIngo Molnar 	free(name);
15061340e6bbSArnaldo Carvalho de Melo 	if (ret < 0 && strstr(self->name, " (deleted)") != NULL)
15071340e6bbSArnaldo Carvalho de Melo 		return 0;
150886470930SIngo Molnar 	return ret;
150986470930SIngo Molnar }
151086470930SIngo Molnar 
151179406cd7SArnaldo Carvalho de Melo struct map *map_groups__find_by_name(struct map_groups *self,
151279406cd7SArnaldo Carvalho de Melo 				     enum map_type type, const char *name)
1513439d473bSArnaldo Carvalho de Melo {
1514439d473bSArnaldo Carvalho de Melo 	struct rb_node *nd;
1515439d473bSArnaldo Carvalho de Melo 
151679406cd7SArnaldo Carvalho de Melo 	for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) {
1517439d473bSArnaldo Carvalho de Melo 		struct map *map = rb_entry(nd, struct map, rb_node);
1518439d473bSArnaldo Carvalho de Melo 
1519b7cece76SArnaldo Carvalho de Melo 		if (map->dso && strcmp(map->dso->short_name, name) == 0)
1520439d473bSArnaldo Carvalho de Melo 			return map;
1521439d473bSArnaldo Carvalho de Melo 	}
1522439d473bSArnaldo Carvalho de Melo 
1523439d473bSArnaldo Carvalho de Melo 	return NULL;
1524439d473bSArnaldo Carvalho de Melo }
1525439d473bSArnaldo Carvalho de Melo 
1526a1645ce1SZhang, Yanmin static int dso__kernel_module_get_build_id(struct dso *self,
1527a1645ce1SZhang, Yanmin 				const char *root_dir)
1528b7cece76SArnaldo Carvalho de Melo {
1529b7cece76SArnaldo Carvalho de Melo 	char filename[PATH_MAX];
1530b7cece76SArnaldo Carvalho de Melo 	/*
1531b7cece76SArnaldo Carvalho de Melo 	 * kernel module short names are of the form "[module]" and
1532b7cece76SArnaldo Carvalho de Melo 	 * we need just "module" here.
1533b7cece76SArnaldo Carvalho de Melo 	 */
1534b7cece76SArnaldo Carvalho de Melo 	const char *name = self->short_name + 1;
1535b7cece76SArnaldo Carvalho de Melo 
1536b7cece76SArnaldo Carvalho de Melo 	snprintf(filename, sizeof(filename),
1537a1645ce1SZhang, Yanmin 		 "%s/sys/module/%.*s/notes/.note.gnu.build-id",
1538a1645ce1SZhang, Yanmin 		 root_dir, (int)strlen(name) - 1, name);
1539b7cece76SArnaldo Carvalho de Melo 
1540b7cece76SArnaldo Carvalho de Melo 	if (sysfs__read_build_id(filename, self->build_id,
1541b7cece76SArnaldo Carvalho de Melo 				 sizeof(self->build_id)) == 0)
1542b7cece76SArnaldo Carvalho de Melo 		self->has_build_id = true;
1543b7cece76SArnaldo Carvalho de Melo 
1544b7cece76SArnaldo Carvalho de Melo 	return 0;
1545b7cece76SArnaldo Carvalho de Melo }
1546b7cece76SArnaldo Carvalho de Melo 
1547a1645ce1SZhang, Yanmin static int map_groups__set_modules_path_dir(struct map_groups *self,
1548a1645ce1SZhang, Yanmin 				const char *dir_name)
15496cfcc53eSMike Galbraith {
1550439d473bSArnaldo Carvalho de Melo 	struct dirent *dent;
15515aab621bSArnaldo Carvalho de Melo 	DIR *dir = opendir(dir_name);
155274534341SGui Jianfeng 	int ret = 0;
15536cfcc53eSMike Galbraith 
1554439d473bSArnaldo Carvalho de Melo 	if (!dir) {
15555aab621bSArnaldo Carvalho de Melo 		pr_debug("%s: cannot open %s dir\n", __func__, dir_name);
1556439d473bSArnaldo Carvalho de Melo 		return -1;
1557439d473bSArnaldo Carvalho de Melo 	}
15586cfcc53eSMike Galbraith 
1559439d473bSArnaldo Carvalho de Melo 	while ((dent = readdir(dir)) != NULL) {
1560439d473bSArnaldo Carvalho de Melo 		char path[PATH_MAX];
1561a1645ce1SZhang, Yanmin 		struct stat st;
1562439d473bSArnaldo Carvalho de Melo 
1563a1645ce1SZhang, Yanmin 		/*sshfs might return bad dent->d_type, so we have to stat*/
1564a1645ce1SZhang, Yanmin 		sprintf(path, "%s/%s", dir_name, dent->d_name);
1565a1645ce1SZhang, Yanmin 		if (stat(path, &st))
1566a1645ce1SZhang, Yanmin 			continue;
1567a1645ce1SZhang, Yanmin 
1568a1645ce1SZhang, Yanmin 		if (S_ISDIR(st.st_mode)) {
1569439d473bSArnaldo Carvalho de Melo 			if (!strcmp(dent->d_name, ".") ||
1570439d473bSArnaldo Carvalho de Melo 			    !strcmp(dent->d_name, ".."))
1571439d473bSArnaldo Carvalho de Melo 				continue;
1572439d473bSArnaldo Carvalho de Melo 
1573439d473bSArnaldo Carvalho de Melo 			snprintf(path, sizeof(path), "%s/%s",
15745aab621bSArnaldo Carvalho de Melo 				 dir_name, dent->d_name);
157574534341SGui Jianfeng 			ret = map_groups__set_modules_path_dir(self, path);
157674534341SGui Jianfeng 			if (ret < 0)
157774534341SGui Jianfeng 				goto out;
1578439d473bSArnaldo Carvalho de Melo 		} else {
1579439d473bSArnaldo Carvalho de Melo 			char *dot = strrchr(dent->d_name, '.'),
1580439d473bSArnaldo Carvalho de Melo 			     dso_name[PATH_MAX];
1581439d473bSArnaldo Carvalho de Melo 			struct map *map;
1582cfc10d3bSArnaldo Carvalho de Melo 			char *long_name;
1583439d473bSArnaldo Carvalho de Melo 
1584439d473bSArnaldo Carvalho de Melo 			if (dot == NULL || strcmp(dot, ".ko"))
1585439d473bSArnaldo Carvalho de Melo 				continue;
1586439d473bSArnaldo Carvalho de Melo 			snprintf(dso_name, sizeof(dso_name), "[%.*s]",
1587439d473bSArnaldo Carvalho de Melo 				 (int)(dot - dent->d_name), dent->d_name);
1588439d473bSArnaldo Carvalho de Melo 
1589a2a99e8eSArnaldo Carvalho de Melo 			strxfrchar(dso_name, '-', '_');
15909de89fe7SArnaldo Carvalho de Melo 			map = map_groups__find_by_name(self, MAP__FUNCTION, dso_name);
1591439d473bSArnaldo Carvalho de Melo 			if (map == NULL)
1592439d473bSArnaldo Carvalho de Melo 				continue;
1593439d473bSArnaldo Carvalho de Melo 
1594439d473bSArnaldo Carvalho de Melo 			snprintf(path, sizeof(path), "%s/%s",
15955aab621bSArnaldo Carvalho de Melo 				 dir_name, dent->d_name);
1596439d473bSArnaldo Carvalho de Melo 
1597cfc10d3bSArnaldo Carvalho de Melo 			long_name = strdup(path);
159874534341SGui Jianfeng 			if (long_name == NULL) {
159974534341SGui Jianfeng 				ret = -1;
160074534341SGui Jianfeng 				goto out;
160174534341SGui Jianfeng 			}
1602cfc10d3bSArnaldo Carvalho de Melo 			dso__set_long_name(map->dso, long_name);
16036e406257SArnaldo Carvalho de Melo 			map->dso->lname_alloc = 1;
1604a1645ce1SZhang, Yanmin 			dso__kernel_module_get_build_id(map->dso, "");
1605439d473bSArnaldo Carvalho de Melo 		}
1606439d473bSArnaldo Carvalho de Melo 	}
1607439d473bSArnaldo Carvalho de Melo 
160874534341SGui Jianfeng out:
1609439d473bSArnaldo Carvalho de Melo 	closedir(dir);
161074534341SGui Jianfeng 	return ret;
1611439d473bSArnaldo Carvalho de Melo }
1612439d473bSArnaldo Carvalho de Melo 
1613a1645ce1SZhang, Yanmin static char *get_kernel_version(const char *root_dir)
1614439d473bSArnaldo Carvalho de Melo {
1615a1645ce1SZhang, Yanmin 	char version[PATH_MAX];
1616a1645ce1SZhang, Yanmin 	FILE *file;
1617a1645ce1SZhang, Yanmin 	char *name, *tmp;
1618a1645ce1SZhang, Yanmin 	const char *prefix = "Linux version ";
1619a1645ce1SZhang, Yanmin 
1620a1645ce1SZhang, Yanmin 	sprintf(version, "%s/proc/version", root_dir);
1621a1645ce1SZhang, Yanmin 	file = fopen(version, "r");
1622a1645ce1SZhang, Yanmin 	if (!file)
1623a1645ce1SZhang, Yanmin 		return NULL;
1624a1645ce1SZhang, Yanmin 
1625a1645ce1SZhang, Yanmin 	version[0] = '\0';
1626a1645ce1SZhang, Yanmin 	tmp = fgets(version, sizeof(version), file);
1627a1645ce1SZhang, Yanmin 	fclose(file);
1628a1645ce1SZhang, Yanmin 
1629a1645ce1SZhang, Yanmin 	name = strstr(version, prefix);
1630a1645ce1SZhang, Yanmin 	if (!name)
1631a1645ce1SZhang, Yanmin 		return NULL;
1632a1645ce1SZhang, Yanmin 	name += strlen(prefix);
1633a1645ce1SZhang, Yanmin 	tmp = strchr(name, ' ');
1634a1645ce1SZhang, Yanmin 	if (tmp)
1635a1645ce1SZhang, Yanmin 		*tmp = '\0';
1636a1645ce1SZhang, Yanmin 
1637a1645ce1SZhang, Yanmin 	return strdup(name);
1638a1645ce1SZhang, Yanmin }
1639a1645ce1SZhang, Yanmin 
1640d28c6223SArnaldo Carvalho de Melo static int machine__set_modules_path(struct machine *self)
1641a1645ce1SZhang, Yanmin {
1642a1645ce1SZhang, Yanmin 	char *version;
1643439d473bSArnaldo Carvalho de Melo 	char modules_path[PATH_MAX];
1644439d473bSArnaldo Carvalho de Melo 
1645d28c6223SArnaldo Carvalho de Melo 	version = get_kernel_version(self->root_dir);
1646a1645ce1SZhang, Yanmin 	if (!version)
1647439d473bSArnaldo Carvalho de Melo 		return -1;
1648439d473bSArnaldo Carvalho de Melo 
1649a1645ce1SZhang, Yanmin 	snprintf(modules_path, sizeof(modules_path), "%s/lib/modules/%s/kernel",
1650d28c6223SArnaldo Carvalho de Melo 		 self->root_dir, version);
1651a1645ce1SZhang, Yanmin 	free(version);
1652439d473bSArnaldo Carvalho de Melo 
1653d28c6223SArnaldo Carvalho de Melo 	return map_groups__set_modules_path_dir(&self->kmaps, modules_path);
1654439d473bSArnaldo Carvalho de Melo }
16556cfcc53eSMike Galbraith 
16566cfcc53eSMike Galbraith /*
1657439d473bSArnaldo Carvalho de Melo  * Constructor variant for modules (where we know from /proc/modules where
1658439d473bSArnaldo Carvalho de Melo  * they are loaded) and for vmlinux, where only after we load all the
1659439d473bSArnaldo Carvalho de Melo  * symbols we'll know where it starts and ends.
16606cfcc53eSMike Galbraith  */
16613610583cSArnaldo Carvalho de Melo static struct map *map__new2(u64 start, struct dso *dso, enum map_type type)
1662439d473bSArnaldo Carvalho de Melo {
16635aab621bSArnaldo Carvalho de Melo 	struct map *self = calloc(1, (sizeof(*self) +
16645aab621bSArnaldo Carvalho de Melo 				      (dso->kernel ? sizeof(struct kmap) : 0)));
1665439d473bSArnaldo Carvalho de Melo 	if (self != NULL) {
1666439d473bSArnaldo Carvalho de Melo 		/*
1667afb7b4f0SArnaldo Carvalho de Melo 		 * ->end will be filled after we load all the symbols
1668439d473bSArnaldo Carvalho de Melo 		 */
16693610583cSArnaldo Carvalho de Melo 		map__init(self, type, start, 0, 0, dso);
1670439d473bSArnaldo Carvalho de Melo 	}
1671afb7b4f0SArnaldo Carvalho de Melo 
1672439d473bSArnaldo Carvalho de Melo 	return self;
1673439d473bSArnaldo Carvalho de Melo }
1674439d473bSArnaldo Carvalho de Melo 
1675d28c6223SArnaldo Carvalho de Melo struct map *machine__new_module(struct machine *self, u64 start,
1676d28c6223SArnaldo Carvalho de Melo 				const char *filename)
1677b7cece76SArnaldo Carvalho de Melo {
1678b7cece76SArnaldo Carvalho de Melo 	struct map *map;
1679d28c6223SArnaldo Carvalho de Melo 	struct dso *dso = __dsos__findnew(&self->kernel_dsos, filename);
1680b7cece76SArnaldo Carvalho de Melo 
1681b7cece76SArnaldo Carvalho de Melo 	if (dso == NULL)
1682b7cece76SArnaldo Carvalho de Melo 		return NULL;
1683b7cece76SArnaldo Carvalho de Melo 
1684b7cece76SArnaldo Carvalho de Melo 	map = map__new2(start, dso, MAP__FUNCTION);
1685b7cece76SArnaldo Carvalho de Melo 	if (map == NULL)
1686b7cece76SArnaldo Carvalho de Melo 		return NULL;
1687b7cece76SArnaldo Carvalho de Melo 
1688d28c6223SArnaldo Carvalho de Melo 	if (machine__is_host(self))
1689b7cece76SArnaldo Carvalho de Melo 		dso->origin = DSO__ORIG_KMODULE;
1690a1645ce1SZhang, Yanmin 	else
1691a1645ce1SZhang, Yanmin 		dso->origin = DSO__ORIG_GUEST_KMODULE;
1692d28c6223SArnaldo Carvalho de Melo 	map_groups__insert(&self->kmaps, map);
1693b7cece76SArnaldo Carvalho de Melo 	return map;
1694b7cece76SArnaldo Carvalho de Melo }
1695b7cece76SArnaldo Carvalho de Melo 
1696d28c6223SArnaldo Carvalho de Melo static int machine__create_modules(struct machine *self)
1697439d473bSArnaldo Carvalho de Melo {
1698439d473bSArnaldo Carvalho de Melo 	char *line = NULL;
1699439d473bSArnaldo Carvalho de Melo 	size_t n;
1700a1645ce1SZhang, Yanmin 	FILE *file;
1701439d473bSArnaldo Carvalho de Melo 	struct map *map;
1702a1645ce1SZhang, Yanmin 	const char *modules;
1703a1645ce1SZhang, Yanmin 	char path[PATH_MAX];
1704439d473bSArnaldo Carvalho de Melo 
1705d28c6223SArnaldo Carvalho de Melo 	if (machine__is_default_guest(self))
1706a1645ce1SZhang, Yanmin 		modules = symbol_conf.default_guest_modules;
1707a1645ce1SZhang, Yanmin 	else {
1708d28c6223SArnaldo Carvalho de Melo 		sprintf(path, "%s/proc/modules", self->root_dir);
1709a1645ce1SZhang, Yanmin 		modules = path;
1710a1645ce1SZhang, Yanmin 	}
1711a1645ce1SZhang, Yanmin 
1712a1645ce1SZhang, Yanmin 	file = fopen(modules, "r");
1713439d473bSArnaldo Carvalho de Melo 	if (file == NULL)
1714439d473bSArnaldo Carvalho de Melo 		return -1;
1715439d473bSArnaldo Carvalho de Melo 
1716439d473bSArnaldo Carvalho de Melo 	while (!feof(file)) {
1717439d473bSArnaldo Carvalho de Melo 		char name[PATH_MAX];
1718439d473bSArnaldo Carvalho de Melo 		u64 start;
1719439d473bSArnaldo Carvalho de Melo 		char *sep;
1720439d473bSArnaldo Carvalho de Melo 		int line_len;
1721439d473bSArnaldo Carvalho de Melo 
1722439d473bSArnaldo Carvalho de Melo 		line_len = getline(&line, &n, file);
1723439d473bSArnaldo Carvalho de Melo 		if (line_len < 0)
17246cfcc53eSMike Galbraith 			break;
17256cfcc53eSMike Galbraith 
1726439d473bSArnaldo Carvalho de Melo 		if (!line)
1727439d473bSArnaldo Carvalho de Melo 			goto out_failure;
1728439d473bSArnaldo Carvalho de Melo 
1729439d473bSArnaldo Carvalho de Melo 		line[--line_len] = '\0'; /* \n */
1730439d473bSArnaldo Carvalho de Melo 
1731439d473bSArnaldo Carvalho de Melo 		sep = strrchr(line, 'x');
1732439d473bSArnaldo Carvalho de Melo 		if (sep == NULL)
1733439d473bSArnaldo Carvalho de Melo 			continue;
1734439d473bSArnaldo Carvalho de Melo 
1735439d473bSArnaldo Carvalho de Melo 		hex2u64(sep + 1, &start);
1736439d473bSArnaldo Carvalho de Melo 
1737439d473bSArnaldo Carvalho de Melo 		sep = strchr(line, ' ');
1738439d473bSArnaldo Carvalho de Melo 		if (sep == NULL)
1739439d473bSArnaldo Carvalho de Melo 			continue;
1740439d473bSArnaldo Carvalho de Melo 
1741439d473bSArnaldo Carvalho de Melo 		*sep = '\0';
1742439d473bSArnaldo Carvalho de Melo 
1743439d473bSArnaldo Carvalho de Melo 		snprintf(name, sizeof(name), "[%s]", line);
1744d28c6223SArnaldo Carvalho de Melo 		map = machine__new_module(self, start, name);
1745b7cece76SArnaldo Carvalho de Melo 		if (map == NULL)
1746439d473bSArnaldo Carvalho de Melo 			goto out_delete_line;
1747d28c6223SArnaldo Carvalho de Melo 		dso__kernel_module_get_build_id(map->dso, self->root_dir);
17486cfcc53eSMike Galbraith 	}
17496cfcc53eSMike Galbraith 
1750439d473bSArnaldo Carvalho de Melo 	free(line);
1751439d473bSArnaldo Carvalho de Melo 	fclose(file);
1752439d473bSArnaldo Carvalho de Melo 
1753d28c6223SArnaldo Carvalho de Melo 	return machine__set_modules_path(self);
1754439d473bSArnaldo Carvalho de Melo 
1755439d473bSArnaldo Carvalho de Melo out_delete_line:
1756439d473bSArnaldo Carvalho de Melo 	free(line);
1757439d473bSArnaldo Carvalho de Melo out_failure:
1758439d473bSArnaldo Carvalho de Melo 	return -1;
17596cfcc53eSMike Galbraith }
17606cfcc53eSMike Galbraith 
17619958e1f0SArnaldo Carvalho de Melo static int dso__load_vmlinux(struct dso *self, struct map *map,
17626beba7adSArnaldo Carvalho de Melo 			     const char *vmlinux, symbol_filter_t filter)
176386470930SIngo Molnar {
1764fbd733b8SArnaldo Carvalho de Melo 	int err = -1, fd;
176586470930SIngo Molnar 
1766fbd733b8SArnaldo Carvalho de Melo 	fd = open(vmlinux, O_RDONLY);
176786470930SIngo Molnar 	if (fd < 0)
176886470930SIngo Molnar 		return -1;
176986470930SIngo Molnar 
17703610583cSArnaldo Carvalho de Melo 	dso__set_loaded(self, map->type);
17716da80ce8SDave Martin 	err = dso__load_sym(self, map, vmlinux, fd, filter, 0, 0);
177286470930SIngo Molnar 	close(fd);
177386470930SIngo Molnar 
17743846df2eSArnaldo Carvalho de Melo 	if (err > 0)
17753846df2eSArnaldo Carvalho de Melo 		pr_debug("Using %s for symbols\n", vmlinux);
17763846df2eSArnaldo Carvalho de Melo 
177786470930SIngo Molnar 	return err;
177886470930SIngo Molnar }
177986470930SIngo Molnar 
1780a19afe46SArnaldo Carvalho de Melo int dso__load_vmlinux_path(struct dso *self, struct map *map,
17819de89fe7SArnaldo Carvalho de Melo 			   symbol_filter_t filter)
1782a19afe46SArnaldo Carvalho de Melo {
1783a19afe46SArnaldo Carvalho de Melo 	int i, err = 0;
17845ad90e4eSArnaldo Carvalho de Melo 	char *filename;
1785a19afe46SArnaldo Carvalho de Melo 
1786a19afe46SArnaldo Carvalho de Melo 	pr_debug("Looking at the vmlinux_path (%d entries long)\n",
17875ad90e4eSArnaldo Carvalho de Melo 		 vmlinux_path__nr_entries + 1);
17885ad90e4eSArnaldo Carvalho de Melo 
17895ad90e4eSArnaldo Carvalho de Melo 	filename = dso__build_id_filename(self, NULL, 0);
17905ad90e4eSArnaldo Carvalho de Melo 	if (filename != NULL) {
17915ad90e4eSArnaldo Carvalho de Melo 		err = dso__load_vmlinux(self, map, filename, filter);
17925ad90e4eSArnaldo Carvalho de Melo 		if (err > 0) {
17935ad90e4eSArnaldo Carvalho de Melo 			dso__set_long_name(self, filename);
17945ad90e4eSArnaldo Carvalho de Melo 			goto out;
17955ad90e4eSArnaldo Carvalho de Melo 		}
17965ad90e4eSArnaldo Carvalho de Melo 		free(filename);
17975ad90e4eSArnaldo Carvalho de Melo 	}
1798a19afe46SArnaldo Carvalho de Melo 
1799a19afe46SArnaldo Carvalho de Melo 	for (i = 0; i < vmlinux_path__nr_entries; ++i) {
18009de89fe7SArnaldo Carvalho de Melo 		err = dso__load_vmlinux(self, map, vmlinux_path[i], filter);
1801a19afe46SArnaldo Carvalho de Melo 		if (err > 0) {
1802a19afe46SArnaldo Carvalho de Melo 			dso__set_long_name(self, strdup(vmlinux_path[i]));
1803a19afe46SArnaldo Carvalho de Melo 			break;
1804a19afe46SArnaldo Carvalho de Melo 		}
1805a19afe46SArnaldo Carvalho de Melo 	}
18065ad90e4eSArnaldo Carvalho de Melo out:
1807a19afe46SArnaldo Carvalho de Melo 	return err;
1808a19afe46SArnaldo Carvalho de Melo }
1809a19afe46SArnaldo Carvalho de Melo 
1810c338aee8SArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *self, struct map *map,
18119de89fe7SArnaldo Carvalho de Melo 				symbol_filter_t filter)
181286470930SIngo Molnar {
1813cc612d81SArnaldo Carvalho de Melo 	int err;
18149e201442SArnaldo Carvalho de Melo 	const char *kallsyms_filename = NULL;
18159e201442SArnaldo Carvalho de Melo 	char *kallsyms_allocated_filename = NULL;
1816dc8d6ab2SArnaldo Carvalho de Melo 	/*
1817dc8d6ab2SArnaldo Carvalho de Melo 	 * Step 1: if the user specified a vmlinux filename, use it and only
1818dc8d6ab2SArnaldo Carvalho de Melo 	 * it, reporting errors to the user if it cannot be used.
1819dc8d6ab2SArnaldo Carvalho de Melo 	 *
1820dc8d6ab2SArnaldo Carvalho de Melo 	 * For instance, try to analyse an ARM perf.data file _without_ a
1821dc8d6ab2SArnaldo Carvalho de Melo 	 * build-id, or if the user specifies the wrong path to the right
1822dc8d6ab2SArnaldo Carvalho de Melo 	 * vmlinux file, obviously we can't fallback to another vmlinux (a
1823dc8d6ab2SArnaldo Carvalho de Melo 	 * x86_86 one, on the machine where analysis is being performed, say),
1824dc8d6ab2SArnaldo Carvalho de Melo 	 * or worse, /proc/kallsyms.
1825dc8d6ab2SArnaldo Carvalho de Melo 	 *
1826dc8d6ab2SArnaldo Carvalho de Melo 	 * If the specified file _has_ a build-id and there is a build-id
1827dc8d6ab2SArnaldo Carvalho de Melo 	 * section in the perf.data file, we will still do the expected
1828dc8d6ab2SArnaldo Carvalho de Melo 	 * validation in dso__load_vmlinux and will bail out if they don't
1829dc8d6ab2SArnaldo Carvalho de Melo 	 * match.
1830dc8d6ab2SArnaldo Carvalho de Melo 	 */
1831dc8d6ab2SArnaldo Carvalho de Melo 	if (symbol_conf.vmlinux_name != NULL) {
18329de89fe7SArnaldo Carvalho de Melo 		err = dso__load_vmlinux(self, map,
1833dc8d6ab2SArnaldo Carvalho de Melo 					symbol_conf.vmlinux_name, filter);
1834e7dadc00SArnaldo Carvalho de Melo 		if (err > 0) {
1835e7dadc00SArnaldo Carvalho de Melo 			dso__set_long_name(self,
1836e7dadc00SArnaldo Carvalho de Melo 					   strdup(symbol_conf.vmlinux_name));
1837e7dadc00SArnaldo Carvalho de Melo 			goto out_fixup;
1838e7dadc00SArnaldo Carvalho de Melo 		}
1839e7dadc00SArnaldo Carvalho de Melo 		return err;
1840dc8d6ab2SArnaldo Carvalho de Melo 	}
1841439d473bSArnaldo Carvalho de Melo 
1842cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path != NULL) {
18439de89fe7SArnaldo Carvalho de Melo 		err = dso__load_vmlinux_path(self, map, filter);
1844a19afe46SArnaldo Carvalho de Melo 		if (err > 0)
1845cc612d81SArnaldo Carvalho de Melo 			goto out_fixup;
1846cc612d81SArnaldo Carvalho de Melo 	}
1847cc612d81SArnaldo Carvalho de Melo 
1848b7cece76SArnaldo Carvalho de Melo 	/*
1849b7cece76SArnaldo Carvalho de Melo 	 * Say the kernel DSO was created when processing the build-id header table,
1850b7cece76SArnaldo Carvalho de Melo 	 * we have a build-id, so check if it is the same as the running kernel,
1851b7cece76SArnaldo Carvalho de Melo 	 * using it if it is.
1852b7cece76SArnaldo Carvalho de Melo 	 */
1853b7cece76SArnaldo Carvalho de Melo 	if (self->has_build_id) {
1854b7cece76SArnaldo Carvalho de Melo 		u8 kallsyms_build_id[BUILD_ID_SIZE];
18559e201442SArnaldo Carvalho de Melo 		char sbuild_id[BUILD_ID_SIZE * 2 + 1];
1856b7cece76SArnaldo Carvalho de Melo 
1857b7cece76SArnaldo Carvalho de Melo 		if (sysfs__read_build_id("/sys/kernel/notes", kallsyms_build_id,
18588d0591f6SArnaldo Carvalho de Melo 					 sizeof(kallsyms_build_id)) == 0) {
18599e201442SArnaldo Carvalho de Melo 			if (dso__build_id_equal(self, kallsyms_build_id)) {
18609e201442SArnaldo Carvalho de Melo 				kallsyms_filename = "/proc/kallsyms";
1861b7cece76SArnaldo Carvalho de Melo 				goto do_kallsyms;
18628d0591f6SArnaldo Carvalho de Melo 			}
18639e201442SArnaldo Carvalho de Melo 		}
1864dc8d6ab2SArnaldo Carvalho de Melo 		/*
1865dc8d6ab2SArnaldo Carvalho de Melo 		 * Now look if we have it on the build-id cache in
1866dc8d6ab2SArnaldo Carvalho de Melo 		 * $HOME/.debug/[kernel.kallsyms].
1867dc8d6ab2SArnaldo Carvalho de Melo 		 */
18689e201442SArnaldo Carvalho de Melo 		build_id__sprintf(self->build_id, sizeof(self->build_id),
18699e201442SArnaldo Carvalho de Melo 				  sbuild_id);
18709e201442SArnaldo Carvalho de Melo 
18719e201442SArnaldo Carvalho de Melo 		if (asprintf(&kallsyms_allocated_filename,
18729e201442SArnaldo Carvalho de Melo 			     "%s/.debug/[kernel.kallsyms]/%s",
18733846df2eSArnaldo Carvalho de Melo 			     getenv("HOME"), sbuild_id) == -1) {
18743846df2eSArnaldo Carvalho de Melo 			pr_err("Not enough memory for kallsyms file lookup\n");
18758d0591f6SArnaldo Carvalho de Melo 			return -1;
18763846df2eSArnaldo Carvalho de Melo 		}
18778d0591f6SArnaldo Carvalho de Melo 
187819fc2dedSArnaldo Carvalho de Melo 		kallsyms_filename = kallsyms_allocated_filename;
187919fc2dedSArnaldo Carvalho de Melo 
1880dc8d6ab2SArnaldo Carvalho de Melo 		if (access(kallsyms_filename, F_OK)) {
18813846df2eSArnaldo Carvalho de Melo 			pr_err("No kallsyms or vmlinux with build-id %s "
18823846df2eSArnaldo Carvalho de Melo 			       "was found\n", sbuild_id);
18839e201442SArnaldo Carvalho de Melo 			free(kallsyms_allocated_filename);
1884dc8d6ab2SArnaldo Carvalho de Melo 			return -1;
1885ef6ae724SArnaldo Carvalho de Melo 		}
1886dc8d6ab2SArnaldo Carvalho de Melo 	} else {
1887dc8d6ab2SArnaldo Carvalho de Melo 		/*
1888dc8d6ab2SArnaldo Carvalho de Melo 		 * Last resort, if we don't have a build-id and couldn't find
1889dc8d6ab2SArnaldo Carvalho de Melo 		 * any vmlinux file, try the running kernel kallsyms table.
1890dc8d6ab2SArnaldo Carvalho de Melo 		 */
1891dc8d6ab2SArnaldo Carvalho de Melo 		kallsyms_filename = "/proc/kallsyms";
1892dc8d6ab2SArnaldo Carvalho de Melo 	}
1893dc8d6ab2SArnaldo Carvalho de Melo 
1894dc8d6ab2SArnaldo Carvalho de Melo do_kallsyms:
18959de89fe7SArnaldo Carvalho de Melo 	err = dso__load_kallsyms(self, kallsyms_filename, map, filter);
18963846df2eSArnaldo Carvalho de Melo 	if (err > 0)
18973846df2eSArnaldo Carvalho de Melo 		pr_debug("Using %s for symbols\n", kallsyms_filename);
1898dc8d6ab2SArnaldo Carvalho de Melo 	free(kallsyms_allocated_filename);
1899dc8d6ab2SArnaldo Carvalho de Melo 
1900439d473bSArnaldo Carvalho de Melo 	if (err > 0) {
1901cc612d81SArnaldo Carvalho de Melo out_fixup:
1902e1c7c6a4SArnaldo Carvalho de Melo 		if (kallsyms_filename != NULL)
1903dc8d6ab2SArnaldo Carvalho de Melo 			dso__set_long_name(self, strdup("[kernel.kallsyms]"));
19046a4694a4SArnaldo Carvalho de Melo 		map__fixup_start(map);
19056a4694a4SArnaldo Carvalho de Melo 		map__fixup_end(map);
1906439d473bSArnaldo Carvalho de Melo 	}
190794cb9e38SArnaldo Carvalho de Melo 
190886470930SIngo Molnar 	return err;
190986470930SIngo Molnar }
191086470930SIngo Molnar 
1911a1645ce1SZhang, Yanmin static int dso__load_guest_kernel_sym(struct dso *self, struct map *map,
1912a1645ce1SZhang, Yanmin 				symbol_filter_t filter)
1913a1645ce1SZhang, Yanmin {
1914a1645ce1SZhang, Yanmin 	int err;
1915a1645ce1SZhang, Yanmin 	const char *kallsyms_filename = NULL;
191623346f21SArnaldo Carvalho de Melo 	struct machine *machine;
1917a1645ce1SZhang, Yanmin 	char path[PATH_MAX];
1918a1645ce1SZhang, Yanmin 
1919a1645ce1SZhang, Yanmin 	if (!map->groups) {
1920a1645ce1SZhang, Yanmin 		pr_debug("Guest kernel map hasn't the point to groups\n");
1921a1645ce1SZhang, Yanmin 		return -1;
1922a1645ce1SZhang, Yanmin 	}
192323346f21SArnaldo Carvalho de Melo 	machine = map->groups->machine;
1924a1645ce1SZhang, Yanmin 
192523346f21SArnaldo Carvalho de Melo 	if (machine__is_default_guest(machine)) {
1926a1645ce1SZhang, Yanmin 		/*
1927a1645ce1SZhang, Yanmin 		 * if the user specified a vmlinux filename, use it and only
1928a1645ce1SZhang, Yanmin 		 * it, reporting errors to the user if it cannot be used.
1929a1645ce1SZhang, Yanmin 		 * Or use file guest_kallsyms inputted by user on commandline
1930a1645ce1SZhang, Yanmin 		 */
1931a1645ce1SZhang, Yanmin 		if (symbol_conf.default_guest_vmlinux_name != NULL) {
1932a1645ce1SZhang, Yanmin 			err = dso__load_vmlinux(self, map,
1933a1645ce1SZhang, Yanmin 				symbol_conf.default_guest_vmlinux_name, filter);
1934a1645ce1SZhang, Yanmin 			goto out_try_fixup;
1935a1645ce1SZhang, Yanmin 		}
1936a1645ce1SZhang, Yanmin 
1937a1645ce1SZhang, Yanmin 		kallsyms_filename = symbol_conf.default_guest_kallsyms;
1938a1645ce1SZhang, Yanmin 		if (!kallsyms_filename)
1939a1645ce1SZhang, Yanmin 			return -1;
1940a1645ce1SZhang, Yanmin 	} else {
194123346f21SArnaldo Carvalho de Melo 		sprintf(path, "%s/proc/kallsyms", machine->root_dir);
1942a1645ce1SZhang, Yanmin 		kallsyms_filename = path;
1943a1645ce1SZhang, Yanmin 	}
1944a1645ce1SZhang, Yanmin 
1945a1645ce1SZhang, Yanmin 	err = dso__load_kallsyms(self, kallsyms_filename, map, filter);
1946a1645ce1SZhang, Yanmin 	if (err > 0)
1947a1645ce1SZhang, Yanmin 		pr_debug("Using %s for symbols\n", kallsyms_filename);
1948a1645ce1SZhang, Yanmin 
1949a1645ce1SZhang, Yanmin out_try_fixup:
1950a1645ce1SZhang, Yanmin 	if (err > 0) {
1951a1645ce1SZhang, Yanmin 		if (kallsyms_filename != NULL) {
195248ea8f54SArnaldo Carvalho de Melo 			machine__mmap_name(machine, path, sizeof(path));
195323346f21SArnaldo Carvalho de Melo 			dso__set_long_name(self, strdup(path));
1954a1645ce1SZhang, Yanmin 		}
1955a1645ce1SZhang, Yanmin 		map__fixup_start(map);
1956a1645ce1SZhang, Yanmin 		map__fixup_end(map);
1957a1645ce1SZhang, Yanmin 	}
1958a1645ce1SZhang, Yanmin 
1959a1645ce1SZhang, Yanmin 	return err;
1960a1645ce1SZhang, Yanmin }
1961cd84c2acSFrederic Weisbecker 
1962b0da954aSArnaldo Carvalho de Melo static void dsos__add(struct list_head *head, struct dso *dso)
1963cd84c2acSFrederic Weisbecker {
1964b0da954aSArnaldo Carvalho de Melo 	list_add_tail(&dso->node, head);
1965cd84c2acSFrederic Weisbecker }
1966cd84c2acSFrederic Weisbecker 
1967b0da954aSArnaldo Carvalho de Melo static struct dso *dsos__find(struct list_head *head, const char *name)
1968cd84c2acSFrederic Weisbecker {
1969cd84c2acSFrederic Weisbecker 	struct dso *pos;
1970cd84c2acSFrederic Weisbecker 
1971b0da954aSArnaldo Carvalho de Melo 	list_for_each_entry(pos, head, node)
1972cf4e5b08SArnaldo Carvalho de Melo 		if (strcmp(pos->long_name, name) == 0)
1973cd84c2acSFrederic Weisbecker 			return pos;
1974cd84c2acSFrederic Weisbecker 	return NULL;
1975cd84c2acSFrederic Weisbecker }
1976cd84c2acSFrederic Weisbecker 
1977a89e5abeSArnaldo Carvalho de Melo struct dso *__dsos__findnew(struct list_head *head, const char *name)
1978cd84c2acSFrederic Weisbecker {
1979a89e5abeSArnaldo Carvalho de Melo 	struct dso *dso = dsos__find(head, name);
1980cd84c2acSFrederic Weisbecker 
1981e4204992SArnaldo Carvalho de Melo 	if (!dso) {
198200a192b3SArnaldo Carvalho de Melo 		dso = dso__new(name);
1983cfc10d3bSArnaldo Carvalho de Melo 		if (dso != NULL) {
1984a89e5abeSArnaldo Carvalho de Melo 			dsos__add(head, dso);
1985cfc10d3bSArnaldo Carvalho de Melo 			dso__set_basename(dso);
1986cfc10d3bSArnaldo Carvalho de Melo 		}
1987e4204992SArnaldo Carvalho de Melo 	}
1988cd84c2acSFrederic Weisbecker 
1989cd84c2acSFrederic Weisbecker 	return dso;
1990cd84c2acSFrederic Weisbecker }
1991cd84c2acSFrederic Weisbecker 
19921f626bc3SArnaldo Carvalho de Melo size_t __dsos__fprintf(struct list_head *head, FILE *fp)
1993cd84c2acSFrederic Weisbecker {
1994cd84c2acSFrederic Weisbecker 	struct dso *pos;
1995cbf69680SArnaldo Carvalho de Melo 	size_t ret = 0;
1996cd84c2acSFrederic Weisbecker 
199795011c60SArnaldo Carvalho de Melo 	list_for_each_entry(pos, head, node) {
199895011c60SArnaldo Carvalho de Melo 		int i;
199995011c60SArnaldo Carvalho de Melo 		for (i = 0; i < MAP__NR_TYPES; ++i)
2000cbf69680SArnaldo Carvalho de Melo 			ret += dso__fprintf(pos, i, fp);
2001cd84c2acSFrederic Weisbecker 	}
2002cd84c2acSFrederic Weisbecker 
2003cbf69680SArnaldo Carvalho de Melo 	return ret;
2004cbf69680SArnaldo Carvalho de Melo }
2005cbf69680SArnaldo Carvalho de Melo 
2006cbf69680SArnaldo Carvalho de Melo size_t machines__fprintf_dsos(struct rb_root *self, FILE *fp)
2007b0da954aSArnaldo Carvalho de Melo {
2008a1645ce1SZhang, Yanmin 	struct rb_node *nd;
2009cbf69680SArnaldo Carvalho de Melo 	size_t ret = 0;
2010a1645ce1SZhang, Yanmin 
2011cbf69680SArnaldo Carvalho de Melo 	for (nd = rb_first(self); nd; nd = rb_next(nd)) {
201223346f21SArnaldo Carvalho de Melo 		struct machine *pos = rb_entry(nd, struct machine, rb_node);
2013cbf69680SArnaldo Carvalho de Melo 		ret += __dsos__fprintf(&pos->kernel_dsos, fp);
2014cbf69680SArnaldo Carvalho de Melo 		ret += __dsos__fprintf(&pos->user_dsos, fp);
2015a1645ce1SZhang, Yanmin 	}
2016cbf69680SArnaldo Carvalho de Melo 
2017cbf69680SArnaldo Carvalho de Melo 	return ret;
2018b0da954aSArnaldo Carvalho de Melo }
2019b0da954aSArnaldo Carvalho de Melo 
202088d3d9b7SArnaldo Carvalho de Melo static size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp,
202188d3d9b7SArnaldo Carvalho de Melo 				      bool with_hits)
20229e03eb2dSArnaldo Carvalho de Melo {
20239e03eb2dSArnaldo Carvalho de Melo 	struct dso *pos;
20249e03eb2dSArnaldo Carvalho de Melo 	size_t ret = 0;
20259e03eb2dSArnaldo Carvalho de Melo 
2026b0da954aSArnaldo Carvalho de Melo 	list_for_each_entry(pos, head, node) {
202788d3d9b7SArnaldo Carvalho de Melo 		if (with_hits && !pos->hit)
202888d3d9b7SArnaldo Carvalho de Melo 			continue;
20299e03eb2dSArnaldo Carvalho de Melo 		ret += dso__fprintf_buildid(pos, fp);
20309e03eb2dSArnaldo Carvalho de Melo 		ret += fprintf(fp, " %s\n", pos->long_name);
20319e03eb2dSArnaldo Carvalho de Melo 	}
20329e03eb2dSArnaldo Carvalho de Melo 	return ret;
20339e03eb2dSArnaldo Carvalho de Melo }
20349e03eb2dSArnaldo Carvalho de Melo 
2035f869097eSArnaldo Carvalho de Melo size_t machine__fprintf_dsos_buildid(struct machine *self, FILE *fp, bool with_hits)
2036f869097eSArnaldo Carvalho de Melo {
2037f869097eSArnaldo Carvalho de Melo 	return __dsos__fprintf_buildid(&self->kernel_dsos, fp, with_hits) +
2038f869097eSArnaldo Carvalho de Melo 	       __dsos__fprintf_buildid(&self->user_dsos, fp, with_hits);
2039f869097eSArnaldo Carvalho de Melo }
2040f869097eSArnaldo Carvalho de Melo 
2041cbf69680SArnaldo Carvalho de Melo size_t machines__fprintf_dsos_buildid(struct rb_root *self, FILE *fp, bool with_hits)
2042b0da954aSArnaldo Carvalho de Melo {
2043a1645ce1SZhang, Yanmin 	struct rb_node *nd;
2044a1645ce1SZhang, Yanmin 	size_t ret = 0;
2045a1645ce1SZhang, Yanmin 
2046cbf69680SArnaldo Carvalho de Melo 	for (nd = rb_first(self); nd; nd = rb_next(nd)) {
204723346f21SArnaldo Carvalho de Melo 		struct machine *pos = rb_entry(nd, struct machine, rb_node);
2048f869097eSArnaldo Carvalho de Melo 		ret += machine__fprintf_dsos_buildid(pos, fp, with_hits);
2049a1645ce1SZhang, Yanmin 	}
2050a1645ce1SZhang, Yanmin 	return ret;
2051b0da954aSArnaldo Carvalho de Melo }
2052b0da954aSArnaldo Carvalho de Melo 
2053fd1d908cSArnaldo Carvalho de Melo struct dso *dso__new_kernel(const char *name)
2054fd1d908cSArnaldo Carvalho de Melo {
2055fd1d908cSArnaldo Carvalho de Melo 	struct dso *self = dso__new(name ?: "[kernel.kallsyms]");
2056fd1d908cSArnaldo Carvalho de Melo 
2057fd1d908cSArnaldo Carvalho de Melo 	if (self != NULL) {
2058b63be8d7SArnaldo Carvalho de Melo 		dso__set_short_name(self, "[kernel]");
2059a1645ce1SZhang, Yanmin 		self->kernel = DSO_TYPE_KERNEL;
2060fd1d908cSArnaldo Carvalho de Melo 	}
2061fd1d908cSArnaldo Carvalho de Melo 
2062fd1d908cSArnaldo Carvalho de Melo 	return self;
2063fd1d908cSArnaldo Carvalho de Melo }
2064fd1d908cSArnaldo Carvalho de Melo 
206523346f21SArnaldo Carvalho de Melo static struct dso *dso__new_guest_kernel(struct machine *machine,
2066a1645ce1SZhang, Yanmin 					const char *name)
2067fd1d908cSArnaldo Carvalho de Melo {
206848ea8f54SArnaldo Carvalho de Melo 	char bf[PATH_MAX];
206948ea8f54SArnaldo Carvalho de Melo 	struct dso *self = dso__new(name ?: machine__mmap_name(machine, bf, sizeof(bf)));
2070a1645ce1SZhang, Yanmin 
2071a1645ce1SZhang, Yanmin 	if (self != NULL) {
2072a1645ce1SZhang, Yanmin 		dso__set_short_name(self, "[guest.kernel]");
2073a1645ce1SZhang, Yanmin 		self->kernel = DSO_TYPE_GUEST_KERNEL;
2074a1645ce1SZhang, Yanmin 	}
2075a1645ce1SZhang, Yanmin 
2076a1645ce1SZhang, Yanmin 	return self;
2077a1645ce1SZhang, Yanmin }
2078a1645ce1SZhang, Yanmin 
207923346f21SArnaldo Carvalho de Melo void dso__read_running_kernel_build_id(struct dso *self, struct machine *machine)
2080a1645ce1SZhang, Yanmin {
2081a1645ce1SZhang, Yanmin 	char path[PATH_MAX];
2082a1645ce1SZhang, Yanmin 
208323346f21SArnaldo Carvalho de Melo 	if (machine__is_default_guest(machine))
2084a1645ce1SZhang, Yanmin 		return;
208523346f21SArnaldo Carvalho de Melo 	sprintf(path, "%s/sys/kernel/notes", machine->root_dir);
2086a1645ce1SZhang, Yanmin 	if (sysfs__read_build_id(path, self->build_id,
2087fd1d908cSArnaldo Carvalho de Melo 				 sizeof(self->build_id)) == 0)
2088fd1d908cSArnaldo Carvalho de Melo 		self->has_build_id = true;
2089fd1d908cSArnaldo Carvalho de Melo }
2090fd1d908cSArnaldo Carvalho de Melo 
20915c0541d5SArnaldo Carvalho de Melo static struct dso *machine__create_kernel(struct machine *self)
2092cd84c2acSFrederic Weisbecker {
2093a1645ce1SZhang, Yanmin 	const char *vmlinux_name = NULL;
2094a1645ce1SZhang, Yanmin 	struct dso *kernel;
2095cd84c2acSFrederic Weisbecker 
20965c0541d5SArnaldo Carvalho de Melo 	if (machine__is_host(self)) {
2097a1645ce1SZhang, Yanmin 		vmlinux_name = symbol_conf.vmlinux_name;
2098a1645ce1SZhang, Yanmin 		kernel = dso__new_kernel(vmlinux_name);
2099a1645ce1SZhang, Yanmin 	} else {
21005c0541d5SArnaldo Carvalho de Melo 		if (machine__is_default_guest(self))
2101a1645ce1SZhang, Yanmin 			vmlinux_name = symbol_conf.default_guest_vmlinux_name;
21025c0541d5SArnaldo Carvalho de Melo 		kernel = dso__new_guest_kernel(self, vmlinux_name);
21038d92c02aSArnaldo Carvalho de Melo 	}
2104cd84c2acSFrederic Weisbecker 
2105a1645ce1SZhang, Yanmin 	if (kernel != NULL) {
21065c0541d5SArnaldo Carvalho de Melo 		dso__read_running_kernel_build_id(kernel, self);
21075c0541d5SArnaldo Carvalho de Melo 		dsos__add(&self->kernel_dsos, kernel);
2108a1645ce1SZhang, Yanmin 	}
2109f1dfa0b1SArnaldo Carvalho de Melo 	return kernel;
2110f1dfa0b1SArnaldo Carvalho de Melo }
2111f1dfa0b1SArnaldo Carvalho de Melo 
2112d28c6223SArnaldo Carvalho de Melo int __machine__create_kernel_maps(struct machine *self, struct dso *kernel)
2113f1dfa0b1SArnaldo Carvalho de Melo {
2114de176489SArnaldo Carvalho de Melo 	enum map_type type;
2115f1dfa0b1SArnaldo Carvalho de Melo 
2116de176489SArnaldo Carvalho de Melo 	for (type = 0; type < MAP__NR_TYPES; ++type) {
21179de89fe7SArnaldo Carvalho de Melo 		struct kmap *kmap;
21189de89fe7SArnaldo Carvalho de Melo 
2119d28c6223SArnaldo Carvalho de Melo 		self->vmlinux_maps[type] = map__new2(0, kernel, type);
2120d28c6223SArnaldo Carvalho de Melo 		if (self->vmlinux_maps[type] == NULL)
2121f1dfa0b1SArnaldo Carvalho de Melo 			return -1;
2122f1dfa0b1SArnaldo Carvalho de Melo 
2123d28c6223SArnaldo Carvalho de Melo 		self->vmlinux_maps[type]->map_ip =
2124d28c6223SArnaldo Carvalho de Melo 			self->vmlinux_maps[type]->unmap_ip = identity__map_ip;
21259de89fe7SArnaldo Carvalho de Melo 
2126d28c6223SArnaldo Carvalho de Melo 		kmap = map__kmap(self->vmlinux_maps[type]);
2127d28c6223SArnaldo Carvalho de Melo 		kmap->kmaps = &self->kmaps;
2128d28c6223SArnaldo Carvalho de Melo 		map_groups__insert(&self->kmaps, self->vmlinux_maps[type]);
2129f1dfa0b1SArnaldo Carvalho de Melo 	}
2130f1dfa0b1SArnaldo Carvalho de Melo 
2131f1dfa0b1SArnaldo Carvalho de Melo 	return 0;
21322446042cSArnaldo Carvalho de Melo }
21332446042cSArnaldo Carvalho de Melo 
2134076c6e45SArnaldo Carvalho de Melo void machine__destroy_kernel_maps(struct machine *self)
2135076c6e45SArnaldo Carvalho de Melo {
2136076c6e45SArnaldo Carvalho de Melo 	enum map_type type;
2137076c6e45SArnaldo Carvalho de Melo 
2138076c6e45SArnaldo Carvalho de Melo 	for (type = 0; type < MAP__NR_TYPES; ++type) {
2139076c6e45SArnaldo Carvalho de Melo 		struct kmap *kmap;
2140076c6e45SArnaldo Carvalho de Melo 
2141076c6e45SArnaldo Carvalho de Melo 		if (self->vmlinux_maps[type] == NULL)
2142076c6e45SArnaldo Carvalho de Melo 			continue;
2143076c6e45SArnaldo Carvalho de Melo 
2144076c6e45SArnaldo Carvalho de Melo 		kmap = map__kmap(self->vmlinux_maps[type]);
2145076c6e45SArnaldo Carvalho de Melo 		map_groups__remove(&self->kmaps, self->vmlinux_maps[type]);
2146076c6e45SArnaldo Carvalho de Melo 		if (kmap->ref_reloc_sym) {
2147076c6e45SArnaldo Carvalho de Melo 			/*
2148076c6e45SArnaldo Carvalho de Melo 			 * ref_reloc_sym is shared among all maps, so free just
2149076c6e45SArnaldo Carvalho de Melo 			 * on one of them.
2150076c6e45SArnaldo Carvalho de Melo 			 */
2151076c6e45SArnaldo Carvalho de Melo 			if (type == MAP__FUNCTION) {
2152076c6e45SArnaldo Carvalho de Melo 				free((char *)kmap->ref_reloc_sym->name);
2153076c6e45SArnaldo Carvalho de Melo 				kmap->ref_reloc_sym->name = NULL;
2154076c6e45SArnaldo Carvalho de Melo 				free(kmap->ref_reloc_sym);
2155076c6e45SArnaldo Carvalho de Melo 			}
2156076c6e45SArnaldo Carvalho de Melo 			kmap->ref_reloc_sym = NULL;
2157076c6e45SArnaldo Carvalho de Melo 		}
2158076c6e45SArnaldo Carvalho de Melo 
2159076c6e45SArnaldo Carvalho de Melo 		map__delete(self->vmlinux_maps[type]);
2160076c6e45SArnaldo Carvalho de Melo 		self->vmlinux_maps[type] = NULL;
2161076c6e45SArnaldo Carvalho de Melo 	}
2162076c6e45SArnaldo Carvalho de Melo }
2163076c6e45SArnaldo Carvalho de Melo 
21645c0541d5SArnaldo Carvalho de Melo int machine__create_kernel_maps(struct machine *self)
21655c0541d5SArnaldo Carvalho de Melo {
21665c0541d5SArnaldo Carvalho de Melo 	struct dso *kernel = machine__create_kernel(self);
21675c0541d5SArnaldo Carvalho de Melo 
21685c0541d5SArnaldo Carvalho de Melo 	if (kernel == NULL ||
21695c0541d5SArnaldo Carvalho de Melo 	    __machine__create_kernel_maps(self, kernel) < 0)
21705c0541d5SArnaldo Carvalho de Melo 		return -1;
21715c0541d5SArnaldo Carvalho de Melo 
21725c0541d5SArnaldo Carvalho de Melo 	if (symbol_conf.use_modules && machine__create_modules(self) < 0)
21735c0541d5SArnaldo Carvalho de Melo 		pr_debug("Problems creating module maps, continuing anyway...\n");
21745c0541d5SArnaldo Carvalho de Melo 	/*
21755c0541d5SArnaldo Carvalho de Melo 	 * Now that we have all the maps created, just set the ->end of them:
21765c0541d5SArnaldo Carvalho de Melo 	 */
21775c0541d5SArnaldo Carvalho de Melo 	map_groups__fixup_end(&self->kmaps);
21785c0541d5SArnaldo Carvalho de Melo 	return 0;
21795c0541d5SArnaldo Carvalho de Melo }
21805c0541d5SArnaldo Carvalho de Melo 
2181cc612d81SArnaldo Carvalho de Melo static void vmlinux_path__exit(void)
21822446042cSArnaldo Carvalho de Melo {
2183cc612d81SArnaldo Carvalho de Melo 	while (--vmlinux_path__nr_entries >= 0) {
2184cc612d81SArnaldo Carvalho de Melo 		free(vmlinux_path[vmlinux_path__nr_entries]);
2185cc612d81SArnaldo Carvalho de Melo 		vmlinux_path[vmlinux_path__nr_entries] = NULL;
2186cc612d81SArnaldo Carvalho de Melo 	}
2187cc612d81SArnaldo Carvalho de Melo 
2188cc612d81SArnaldo Carvalho de Melo 	free(vmlinux_path);
2189cc612d81SArnaldo Carvalho de Melo 	vmlinux_path = NULL;
2190cc612d81SArnaldo Carvalho de Melo }
2191cc612d81SArnaldo Carvalho de Melo 
2192cc612d81SArnaldo Carvalho de Melo static int vmlinux_path__init(void)
2193cc612d81SArnaldo Carvalho de Melo {
2194cc612d81SArnaldo Carvalho de Melo 	struct utsname uts;
2195cc612d81SArnaldo Carvalho de Melo 	char bf[PATH_MAX];
2196cc612d81SArnaldo Carvalho de Melo 
2197cc612d81SArnaldo Carvalho de Melo 	if (uname(&uts) < 0)
21982446042cSArnaldo Carvalho de Melo 		return -1;
21992446042cSArnaldo Carvalho de Melo 
2200cc612d81SArnaldo Carvalho de Melo 	vmlinux_path = malloc(sizeof(char *) * 5);
2201cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path == NULL)
2202cc612d81SArnaldo Carvalho de Melo 		return -1;
2203cc612d81SArnaldo Carvalho de Melo 
2204cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup("vmlinux");
2205cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
2206cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
2207cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
2208cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup("/boot/vmlinux");
2209cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
2210cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
2211cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
2212cc612d81SArnaldo Carvalho de Melo 	snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", uts.release);
2213cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
2214cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
2215cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
2216cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
2217cc612d81SArnaldo Carvalho de Melo 	snprintf(bf, sizeof(bf), "/lib/modules/%s/build/vmlinux", uts.release);
2218cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
2219cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
2220cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
2221cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
2222cc612d81SArnaldo Carvalho de Melo 	snprintf(bf, sizeof(bf), "/usr/lib/debug/lib/modules/%s/vmlinux",
2223cc612d81SArnaldo Carvalho de Melo 		 uts.release);
2224cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
2225cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
2226cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
2227cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
2228cc612d81SArnaldo Carvalho de Melo 
2229cc612d81SArnaldo Carvalho de Melo 	return 0;
2230cc612d81SArnaldo Carvalho de Melo 
2231cc612d81SArnaldo Carvalho de Melo out_fail:
2232cc612d81SArnaldo Carvalho de Melo 	vmlinux_path__exit();
2233cc612d81SArnaldo Carvalho de Melo 	return -1;
2234cc612d81SArnaldo Carvalho de Melo }
2235cc612d81SArnaldo Carvalho de Melo 
22365ad90e4eSArnaldo Carvalho de Melo size_t machine__fprintf_vmlinux_path(struct machine *self, FILE *fp)
2237b0a9ab62SArnaldo Carvalho de Melo {
2238b0a9ab62SArnaldo Carvalho de Melo 	int i;
2239b0a9ab62SArnaldo Carvalho de Melo 	size_t printed = 0;
22405ad90e4eSArnaldo Carvalho de Melo 	struct dso *kdso = self->vmlinux_maps[MAP__FUNCTION]->dso;
22415ad90e4eSArnaldo Carvalho de Melo 
22425ad90e4eSArnaldo Carvalho de Melo 	if (kdso->has_build_id) {
22435ad90e4eSArnaldo Carvalho de Melo 		char filename[PATH_MAX];
22445ad90e4eSArnaldo Carvalho de Melo 		if (dso__build_id_filename(kdso, filename, sizeof(filename)))
22455ad90e4eSArnaldo Carvalho de Melo 			printed += fprintf(fp, "[0] %s\n", filename);
22465ad90e4eSArnaldo Carvalho de Melo 	}
2247b0a9ab62SArnaldo Carvalho de Melo 
2248b0a9ab62SArnaldo Carvalho de Melo 	for (i = 0; i < vmlinux_path__nr_entries; ++i)
22495ad90e4eSArnaldo Carvalho de Melo 		printed += fprintf(fp, "[%d] %s\n",
22505ad90e4eSArnaldo Carvalho de Melo 				   i + kdso->has_build_id, vmlinux_path[i]);
2251b0a9ab62SArnaldo Carvalho de Melo 
2252b0a9ab62SArnaldo Carvalho de Melo 	return printed;
2253b0a9ab62SArnaldo Carvalho de Melo }
2254b0a9ab62SArnaldo Carvalho de Melo 
2255655000e7SArnaldo Carvalho de Melo static int setup_list(struct strlist **list, const char *list_str,
2256655000e7SArnaldo Carvalho de Melo 		      const char *list_name)
2257655000e7SArnaldo Carvalho de Melo {
2258655000e7SArnaldo Carvalho de Melo 	if (list_str == NULL)
2259655000e7SArnaldo Carvalho de Melo 		return 0;
2260655000e7SArnaldo Carvalho de Melo 
2261655000e7SArnaldo Carvalho de Melo 	*list = strlist__new(true, list_str);
2262655000e7SArnaldo Carvalho de Melo 	if (!*list) {
2263655000e7SArnaldo Carvalho de Melo 		pr_err("problems parsing %s list\n", list_name);
2264655000e7SArnaldo Carvalho de Melo 		return -1;
2265655000e7SArnaldo Carvalho de Melo 	}
2266655000e7SArnaldo Carvalho de Melo 	return 0;
2267655000e7SArnaldo Carvalho de Melo }
2268655000e7SArnaldo Carvalho de Melo 
226975be6cf4SArnaldo Carvalho de Melo int symbol__init(void)
2270cc612d81SArnaldo Carvalho de Melo {
227195011c60SArnaldo Carvalho de Melo 	elf_version(EV_CURRENT);
227275be6cf4SArnaldo Carvalho de Melo 	if (symbol_conf.sort_by_name)
227375be6cf4SArnaldo Carvalho de Melo 		symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) -
227479406cd7SArnaldo Carvalho de Melo 					  sizeof(struct symbol));
2275b32d133aSArnaldo Carvalho de Melo 
227675be6cf4SArnaldo Carvalho de Melo 	if (symbol_conf.try_vmlinux_path && vmlinux_path__init() < 0)
2277cc612d81SArnaldo Carvalho de Melo 		return -1;
2278cc612d81SArnaldo Carvalho de Melo 
2279c410a338SArnaldo Carvalho de Melo 	if (symbol_conf.field_sep && *symbol_conf.field_sep == '.') {
2280c410a338SArnaldo Carvalho de Melo 		pr_err("'.' is the only non valid --field-separator argument\n");
2281c410a338SArnaldo Carvalho de Melo 		return -1;
2282c410a338SArnaldo Carvalho de Melo 	}
2283c410a338SArnaldo Carvalho de Melo 
2284655000e7SArnaldo Carvalho de Melo 	if (setup_list(&symbol_conf.dso_list,
2285655000e7SArnaldo Carvalho de Melo 		       symbol_conf.dso_list_str, "dso") < 0)
2286655000e7SArnaldo Carvalho de Melo 		return -1;
2287655000e7SArnaldo Carvalho de Melo 
2288655000e7SArnaldo Carvalho de Melo 	if (setup_list(&symbol_conf.comm_list,
2289655000e7SArnaldo Carvalho de Melo 		       symbol_conf.comm_list_str, "comm") < 0)
2290655000e7SArnaldo Carvalho de Melo 		goto out_free_dso_list;
2291655000e7SArnaldo Carvalho de Melo 
2292655000e7SArnaldo Carvalho de Melo 	if (setup_list(&symbol_conf.sym_list,
2293655000e7SArnaldo Carvalho de Melo 		       symbol_conf.sym_list_str, "symbol") < 0)
2294655000e7SArnaldo Carvalho de Melo 		goto out_free_comm_list;
2295655000e7SArnaldo Carvalho de Melo 
22964aa65636SArnaldo Carvalho de Melo 	return 0;
2297655000e7SArnaldo Carvalho de Melo 
2298655000e7SArnaldo Carvalho de Melo out_free_dso_list:
2299655000e7SArnaldo Carvalho de Melo 	strlist__delete(symbol_conf.dso_list);
2300655000e7SArnaldo Carvalho de Melo out_free_comm_list:
2301655000e7SArnaldo Carvalho de Melo 	strlist__delete(symbol_conf.comm_list);
2302655000e7SArnaldo Carvalho de Melo 	return -1;
2303cc612d81SArnaldo Carvalho de Melo }
2304cc612d81SArnaldo Carvalho de Melo 
2305d65a458bSArnaldo Carvalho de Melo void symbol__exit(void)
2306d65a458bSArnaldo Carvalho de Melo {
2307d65a458bSArnaldo Carvalho de Melo 	strlist__delete(symbol_conf.sym_list);
2308d65a458bSArnaldo Carvalho de Melo 	strlist__delete(symbol_conf.dso_list);
2309d65a458bSArnaldo Carvalho de Melo 	strlist__delete(symbol_conf.comm_list);
2310d65a458bSArnaldo Carvalho de Melo 	vmlinux_path__exit();
2311d65a458bSArnaldo Carvalho de Melo 	symbol_conf.sym_list = symbol_conf.dso_list = symbol_conf.comm_list = NULL;
2312d65a458bSArnaldo Carvalho de Melo }
2313d65a458bSArnaldo Carvalho de Melo 
2314d28c6223SArnaldo Carvalho de Melo int machines__create_kernel_maps(struct rb_root *self, pid_t pid)
23154aa65636SArnaldo Carvalho de Melo {
2316d28c6223SArnaldo Carvalho de Melo 	struct machine *machine = machines__findnew(self, pid);
23179de89fe7SArnaldo Carvalho de Melo 
231823346f21SArnaldo Carvalho de Melo 	if (machine == NULL)
2319a1645ce1SZhang, Yanmin 		return -1;
23204aa65636SArnaldo Carvalho de Melo 
23215c0541d5SArnaldo Carvalho de Melo 	return machine__create_kernel_maps(machine);
2322cd84c2acSFrederic Weisbecker }
23235aab621bSArnaldo Carvalho de Melo 
23245aab621bSArnaldo Carvalho de Melo static int hex(char ch)
23255aab621bSArnaldo Carvalho de Melo {
23265aab621bSArnaldo Carvalho de Melo 	if ((ch >= '0') && (ch <= '9'))
23275aab621bSArnaldo Carvalho de Melo 		return ch - '0';
23285aab621bSArnaldo Carvalho de Melo 	if ((ch >= 'a') && (ch <= 'f'))
23295aab621bSArnaldo Carvalho de Melo 		return ch - 'a' + 10;
23305aab621bSArnaldo Carvalho de Melo 	if ((ch >= 'A') && (ch <= 'F'))
23315aab621bSArnaldo Carvalho de Melo 		return ch - 'A' + 10;
23325aab621bSArnaldo Carvalho de Melo 	return -1;
23335aab621bSArnaldo Carvalho de Melo }
23345aab621bSArnaldo Carvalho de Melo 
23355aab621bSArnaldo Carvalho de Melo /*
23365aab621bSArnaldo Carvalho de Melo  * While we find nice hex chars, build a long_val.
23375aab621bSArnaldo Carvalho de Melo  * Return number of chars processed.
23385aab621bSArnaldo Carvalho de Melo  */
23395aab621bSArnaldo Carvalho de Melo int hex2u64(const char *ptr, u64 *long_val)
23405aab621bSArnaldo Carvalho de Melo {
23415aab621bSArnaldo Carvalho de Melo 	const char *p = ptr;
23425aab621bSArnaldo Carvalho de Melo 	*long_val = 0;
23435aab621bSArnaldo Carvalho de Melo 
23445aab621bSArnaldo Carvalho de Melo 	while (*p) {
23455aab621bSArnaldo Carvalho de Melo 		const int hex_val = hex(*p);
23465aab621bSArnaldo Carvalho de Melo 
23475aab621bSArnaldo Carvalho de Melo 		if (hex_val < 0)
23485aab621bSArnaldo Carvalho de Melo 			break;
23495aab621bSArnaldo Carvalho de Melo 
23505aab621bSArnaldo Carvalho de Melo 		*long_val = (*long_val << 4) | hex_val;
23515aab621bSArnaldo Carvalho de Melo 		p++;
23525aab621bSArnaldo Carvalho de Melo 	}
23535aab621bSArnaldo Carvalho de Melo 
23545aab621bSArnaldo Carvalho de Melo 	return p - ptr;
23555aab621bSArnaldo Carvalho de Melo }
23565aab621bSArnaldo Carvalho de Melo 
23575aab621bSArnaldo Carvalho de Melo char *strxfrchar(char *s, char from, char to)
23585aab621bSArnaldo Carvalho de Melo {
23595aab621bSArnaldo Carvalho de Melo 	char *p = s;
23605aab621bSArnaldo Carvalho de Melo 
23615aab621bSArnaldo Carvalho de Melo 	while ((p = strchr(p, from)) != NULL)
23625aab621bSArnaldo Carvalho de Melo 		*p++ = to;
23635aab621bSArnaldo Carvalho de Melo 
23645aab621bSArnaldo Carvalho de Melo 	return s;
23655aab621bSArnaldo Carvalho de Melo }
2366a1645ce1SZhang, Yanmin 
2367d28c6223SArnaldo Carvalho de Melo int machines__create_guest_kernel_maps(struct rb_root *self)
2368a1645ce1SZhang, Yanmin {
2369a1645ce1SZhang, Yanmin 	int ret = 0;
2370a1645ce1SZhang, Yanmin 	struct dirent **namelist = NULL;
2371a1645ce1SZhang, Yanmin 	int i, items = 0;
2372a1645ce1SZhang, Yanmin 	char path[PATH_MAX];
2373a1645ce1SZhang, Yanmin 	pid_t pid;
2374a1645ce1SZhang, Yanmin 
2375a1645ce1SZhang, Yanmin 	if (symbol_conf.default_guest_vmlinux_name ||
2376a1645ce1SZhang, Yanmin 	    symbol_conf.default_guest_modules ||
2377a1645ce1SZhang, Yanmin 	    symbol_conf.default_guest_kallsyms) {
2378d28c6223SArnaldo Carvalho de Melo 		machines__create_kernel_maps(self, DEFAULT_GUEST_KERNEL_ID);
2379a1645ce1SZhang, Yanmin 	}
2380a1645ce1SZhang, Yanmin 
2381a1645ce1SZhang, Yanmin 	if (symbol_conf.guestmount) {
2382a1645ce1SZhang, Yanmin 		items = scandir(symbol_conf.guestmount, &namelist, NULL, NULL);
2383a1645ce1SZhang, Yanmin 		if (items <= 0)
2384a1645ce1SZhang, Yanmin 			return -ENOENT;
2385a1645ce1SZhang, Yanmin 		for (i = 0; i < items; i++) {
2386a1645ce1SZhang, Yanmin 			if (!isdigit(namelist[i]->d_name[0])) {
2387a1645ce1SZhang, Yanmin 				/* Filter out . and .. */
2388a1645ce1SZhang, Yanmin 				continue;
2389a1645ce1SZhang, Yanmin 			}
2390a1645ce1SZhang, Yanmin 			pid = atoi(namelist[i]->d_name);
2391a1645ce1SZhang, Yanmin 			sprintf(path, "%s/%s/proc/kallsyms",
2392a1645ce1SZhang, Yanmin 				symbol_conf.guestmount,
2393a1645ce1SZhang, Yanmin 				namelist[i]->d_name);
2394a1645ce1SZhang, Yanmin 			ret = access(path, R_OK);
2395a1645ce1SZhang, Yanmin 			if (ret) {
2396a1645ce1SZhang, Yanmin 				pr_debug("Can't access file %s\n", path);
2397a1645ce1SZhang, Yanmin 				goto failure;
2398a1645ce1SZhang, Yanmin 			}
2399d28c6223SArnaldo Carvalho de Melo 			machines__create_kernel_maps(self, pid);
2400a1645ce1SZhang, Yanmin 		}
2401a1645ce1SZhang, Yanmin failure:
2402a1645ce1SZhang, Yanmin 		free(namelist);
2403a1645ce1SZhang, Yanmin 	}
2404a1645ce1SZhang, Yanmin 
2405a1645ce1SZhang, Yanmin 	return ret;
2406a1645ce1SZhang, Yanmin }
24075c0541d5SArnaldo Carvalho de Melo 
2408076c6e45SArnaldo Carvalho de Melo void machines__destroy_guest_kernel_maps(struct rb_root *self)
2409076c6e45SArnaldo Carvalho de Melo {
2410076c6e45SArnaldo Carvalho de Melo 	struct rb_node *next = rb_first(self);
2411076c6e45SArnaldo Carvalho de Melo 
2412076c6e45SArnaldo Carvalho de Melo 	while (next) {
2413076c6e45SArnaldo Carvalho de Melo 		struct machine *pos = rb_entry(next, struct machine, rb_node);
2414076c6e45SArnaldo Carvalho de Melo 
2415076c6e45SArnaldo Carvalho de Melo 		next = rb_next(&pos->rb_node);
2416076c6e45SArnaldo Carvalho de Melo 		rb_erase(&pos->rb_node, self);
2417076c6e45SArnaldo Carvalho de Melo 		machine__delete(pos);
2418076c6e45SArnaldo Carvalho de Melo 	}
2419076c6e45SArnaldo Carvalho de Melo }
2420076c6e45SArnaldo Carvalho de Melo 
24215c0541d5SArnaldo Carvalho de Melo int machine__load_kallsyms(struct machine *self, const char *filename,
24225c0541d5SArnaldo Carvalho de Melo 			   enum map_type type, symbol_filter_t filter)
24235c0541d5SArnaldo Carvalho de Melo {
24245c0541d5SArnaldo Carvalho de Melo 	struct map *map = self->vmlinux_maps[type];
24255c0541d5SArnaldo Carvalho de Melo 	int ret = dso__load_kallsyms(map->dso, filename, map, filter);
24265c0541d5SArnaldo Carvalho de Melo 
24275c0541d5SArnaldo Carvalho de Melo 	if (ret > 0) {
24285c0541d5SArnaldo Carvalho de Melo 		dso__set_loaded(map->dso, type);
24295c0541d5SArnaldo Carvalho de Melo 		/*
24305c0541d5SArnaldo Carvalho de Melo 		 * Since /proc/kallsyms will have multiple sessions for the
24315c0541d5SArnaldo Carvalho de Melo 		 * kernel, with modules between them, fixup the end of all
24325c0541d5SArnaldo Carvalho de Melo 		 * sections.
24335c0541d5SArnaldo Carvalho de Melo 		 */
24345c0541d5SArnaldo Carvalho de Melo 		__map_groups__fixup_end(&self->kmaps, type);
24355c0541d5SArnaldo Carvalho de Melo 	}
24365c0541d5SArnaldo Carvalho de Melo 
24375c0541d5SArnaldo Carvalho de Melo 	return ret;
24385c0541d5SArnaldo Carvalho de Melo }
24395c0541d5SArnaldo Carvalho de Melo 
24405c0541d5SArnaldo Carvalho de Melo int machine__load_vmlinux_path(struct machine *self, enum map_type type,
24415c0541d5SArnaldo Carvalho de Melo 			       symbol_filter_t filter)
24425c0541d5SArnaldo Carvalho de Melo {
24435c0541d5SArnaldo Carvalho de Melo 	struct map *map = self->vmlinux_maps[type];
24445c0541d5SArnaldo Carvalho de Melo 	int ret = dso__load_vmlinux_path(map->dso, map, filter);
24455c0541d5SArnaldo Carvalho de Melo 
24465c0541d5SArnaldo Carvalho de Melo 	if (ret > 0) {
24475c0541d5SArnaldo Carvalho de Melo 		dso__set_loaded(map->dso, type);
24485c0541d5SArnaldo Carvalho de Melo 		map__reloc_vmlinux(map);
24495c0541d5SArnaldo Carvalho de Melo 	}
24505c0541d5SArnaldo Carvalho de Melo 
24515c0541d5SArnaldo Carvalho de Melo 	return ret;
24525c0541d5SArnaldo Carvalho de Melo }
2453