xref: /linux/tools/perf/util/symbol.c (revision c408fedfc4a1fa16e611ffd6f3280301b38614be)
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 
134*c408fedfSArnaldo Carvalho de Melo static struct symbol *symbol__new(u64 start, u64 len, u8 binding,
135*c408fedfSArnaldo 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;
148*c408fedfSArnaldo 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 {
165*c408fedfSArnaldo Carvalho de Melo 	return fprintf(fp, " %llx-%llx %c %s\n",
166*c408fedfSArnaldo Carvalho de Melo 		       self->start, self->end,
167*c408fedfSArnaldo Carvalho de Melo 		       self->binding == STB_GLOBAL ? 'g' :
168*c408fedfSArnaldo Carvalho de Melo 		       self->binding == STB_LOCAL  ? 'l' : 'w',
169*c408fedfSArnaldo 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 
461*c408fedfSArnaldo Carvalho de Melo static u8 kallsyms2elf_type(char type)
462*c408fedfSArnaldo Carvalho de Melo {
463*c408fedfSArnaldo Carvalho de Melo 	if (type == 'W')
464*c408fedfSArnaldo Carvalho de Melo 		return STB_WEAK;
465*c408fedfSArnaldo Carvalho de Melo 
466*c408fedfSArnaldo Carvalho de Melo 	return isupper(type) ? STB_GLOBAL : STB_LOCAL;
467*c408fedfSArnaldo Carvalho de Melo }
468*c408fedfSArnaldo 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 	 */
482*c408fedfSArnaldo 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 
677*c408fedfSArnaldo 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,
889*c408fedfSArnaldo 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,
911*c408fedfSArnaldo 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 
108270c3856bSEric B Munson 		if (opdsec && sym.st_shndx == opdidx) {
108370c3856bSEric B Munson 			u32 offset = sym.st_value - opdshdr.sh_addr;
108470c3856bSEric B Munson 			u64 *opd = opddata->d_buf + offset;
108570c3856bSEric B Munson 			sym.st_value = *opd;
108670c3856bSEric B Munson 			sym.st_shndx = elf_addr_to_index(elf, sym.st_value);
108770c3856bSEric B Munson 		}
108870c3856bSEric B Munson 
108986470930SIngo Molnar 		sec = elf_getscn(elf, sym.st_shndx);
109086470930SIngo Molnar 		if (!sec)
109186470930SIngo Molnar 			goto out_elf_end;
109286470930SIngo Molnar 
109386470930SIngo Molnar 		gelf_getshdr(sec, &shdr);
10946cfcc53eSMike Galbraith 
1095d45868d3SArnaldo Carvalho de Melo 		if (is_label && !elf_sec__is_a(&shdr, secstrs, map->type))
10966cfcc53eSMike Galbraith 			continue;
10976cfcc53eSMike Galbraith 
10986cfcc53eSMike Galbraith 		section_name = elf_sec__name(&shdr, secstrs);
109986470930SIngo Molnar 
1100a1645ce1SZhang, Yanmin 		if (self->kernel != DSO_TYPE_USER || kmodule) {
11012e538c4aSArnaldo Carvalho de Melo 			char dso_name[PATH_MAX];
11022e538c4aSArnaldo Carvalho de Melo 
11032e538c4aSArnaldo Carvalho de Melo 			if (strcmp(section_name,
1104b63be8d7SArnaldo Carvalho de Melo 				   (curr_dso->short_name +
1105b63be8d7SArnaldo Carvalho de Melo 				    self->short_name_len)) == 0)
11062e538c4aSArnaldo Carvalho de Melo 				goto new_symbol;
11072e538c4aSArnaldo Carvalho de Melo 
11082e538c4aSArnaldo Carvalho de Melo 			if (strcmp(section_name, ".text") == 0) {
11092e538c4aSArnaldo Carvalho de Melo 				curr_map = map;
11102e538c4aSArnaldo Carvalho de Melo 				curr_dso = self;
11112e538c4aSArnaldo Carvalho de Melo 				goto new_symbol;
1112af427bf5SArnaldo Carvalho de Melo 			}
1113af427bf5SArnaldo Carvalho de Melo 
11142e538c4aSArnaldo Carvalho de Melo 			snprintf(dso_name, sizeof(dso_name),
11152e538c4aSArnaldo Carvalho de Melo 				 "%s%s", self->short_name, section_name);
11162e538c4aSArnaldo Carvalho de Melo 
11179de89fe7SArnaldo Carvalho de Melo 			curr_map = map_groups__find_by_name(kmap->kmaps, map->type, dso_name);
11182e538c4aSArnaldo Carvalho de Melo 			if (curr_map == NULL) {
11192e538c4aSArnaldo Carvalho de Melo 				u64 start = sym.st_value;
11202e538c4aSArnaldo Carvalho de Melo 
11212e538c4aSArnaldo Carvalho de Melo 				if (kmodule)
11222e538c4aSArnaldo Carvalho de Melo 					start += map->start + shdr.sh_offset;
11232e538c4aSArnaldo Carvalho de Melo 
112400a192b3SArnaldo Carvalho de Melo 				curr_dso = dso__new(dso_name);
11252e538c4aSArnaldo Carvalho de Melo 				if (curr_dso == NULL)
11262e538c4aSArnaldo Carvalho de Melo 					goto out_elf_end;
1127a1645ce1SZhang, Yanmin 				curr_dso->kernel = self->kernel;
11283610583cSArnaldo Carvalho de Melo 				curr_map = map__new2(start, curr_dso,
11296275ce2dSArnaldo Carvalho de Melo 						     map->type);
11302e538c4aSArnaldo Carvalho de Melo 				if (curr_map == NULL) {
11312e538c4aSArnaldo Carvalho de Melo 					dso__delete(curr_dso);
11322e538c4aSArnaldo Carvalho de Melo 					goto out_elf_end;
11332e538c4aSArnaldo Carvalho de Melo 				}
1134ed52ce2eSArnaldo Carvalho de Melo 				curr_map->map_ip = identity__map_ip;
1135ed52ce2eSArnaldo Carvalho de Melo 				curr_map->unmap_ip = identity__map_ip;
1136b0a9ab62SArnaldo Carvalho de Melo 				curr_dso->origin = self->origin;
11379de89fe7SArnaldo Carvalho de Melo 				map_groups__insert(kmap->kmaps, curr_map);
1138a1645ce1SZhang, Yanmin 				dsos__add(&self->node, curr_dso);
11396275ce2dSArnaldo Carvalho de Melo 				dso__set_loaded(curr_dso, map->type);
11402e538c4aSArnaldo Carvalho de Melo 			} else
11412e538c4aSArnaldo Carvalho de Melo 				curr_dso = curr_map->dso;
11422e538c4aSArnaldo Carvalho de Melo 
11432e538c4aSArnaldo Carvalho de Melo 			goto new_symbol;
11442e538c4aSArnaldo Carvalho de Melo 		}
11452e538c4aSArnaldo Carvalho de Melo 
11462e538c4aSArnaldo Carvalho de Melo 		if (curr_dso->adjust_symbols) {
114729a9f66dSArnaldo Carvalho de Melo 			pr_debug4("%s: adjusting symbol: st_value: %#Lx "
114829a9f66dSArnaldo Carvalho de Melo 				  "sh_addr: %#Lx sh_offset: %#Lx\n", __func__,
114929a9f66dSArnaldo Carvalho de Melo 				  (u64)sym.st_value, (u64)shdr.sh_addr,
115029a9f66dSArnaldo Carvalho de Melo 				  (u64)shdr.sh_offset);
115186470930SIngo Molnar 			sym.st_value -= shdr.sh_addr - shdr.sh_offset;
1152af427bf5SArnaldo Carvalho de Melo 		}
115328ac909bSArnaldo Carvalho de Melo 		/*
115428ac909bSArnaldo Carvalho de Melo 		 * We need to figure out if the object was created from C++ sources
115528ac909bSArnaldo Carvalho de Melo 		 * DWARF DW_compile_unit has this, but we don't always have access
115628ac909bSArnaldo Carvalho de Melo 		 * to it...
115728ac909bSArnaldo Carvalho de Melo 		 */
115883a0944fSIngo Molnar 		demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI);
115928ac909bSArnaldo Carvalho de Melo 		if (demangled != NULL)
116083a0944fSIngo Molnar 			elf_name = demangled;
11612e538c4aSArnaldo Carvalho de Melo new_symbol:
1162*c408fedfSArnaldo Carvalho de Melo 		f = symbol__new(sym.st_value, sym.st_size,
1163*c408fedfSArnaldo Carvalho de Melo 				GELF_ST_BIND(sym.st_info), elf_name);
116428ac909bSArnaldo Carvalho de Melo 		free(demangled);
116586470930SIngo Molnar 		if (!f)
116686470930SIngo Molnar 			goto out_elf_end;
116786470930SIngo Molnar 
11682e538c4aSArnaldo Carvalho de Melo 		if (filter && filter(curr_map, f))
116900a192b3SArnaldo Carvalho de Melo 			symbol__delete(f);
117086470930SIngo Molnar 		else {
11716a4694a4SArnaldo Carvalho de Melo 			symbols__insert(&curr_dso->symbols[curr_map->type], f);
117286470930SIngo Molnar 			nr++;
117386470930SIngo Molnar 		}
117486470930SIngo Molnar 	}
117586470930SIngo Molnar 
11762e538c4aSArnaldo Carvalho de Melo 	/*
11772e538c4aSArnaldo Carvalho de Melo 	 * For misannotated, zeroed, ASM function sizes.
11782e538c4aSArnaldo Carvalho de Melo 	 */
11796275ce2dSArnaldo Carvalho de Melo 	if (nr > 0) {
11806a4694a4SArnaldo Carvalho de Melo 		symbols__fixup_end(&self->symbols[map->type]);
11816275ce2dSArnaldo Carvalho de Melo 		if (kmap) {
11826275ce2dSArnaldo Carvalho de Melo 			/*
11836275ce2dSArnaldo Carvalho de Melo 			 * We need to fixup this here too because we create new
11846275ce2dSArnaldo Carvalho de Melo 			 * maps here, for things like vsyscall sections.
11856275ce2dSArnaldo Carvalho de Melo 			 */
11866275ce2dSArnaldo Carvalho de Melo 			__map_groups__fixup_end(kmap->kmaps, map->type);
11876275ce2dSArnaldo Carvalho de Melo 		}
11886275ce2dSArnaldo Carvalho de Melo 	}
118986470930SIngo Molnar 	err = nr;
119086470930SIngo Molnar out_elf_end:
119186470930SIngo Molnar 	elf_end(elf);
119286470930SIngo Molnar out_close:
119386470930SIngo Molnar 	return err;
119486470930SIngo Molnar }
119586470930SIngo Molnar 
119678075caaSArnaldo Carvalho de Melo static bool dso__build_id_equal(const struct dso *self, u8 *build_id)
119778075caaSArnaldo Carvalho de Melo {
119878075caaSArnaldo Carvalho de Melo 	return memcmp(self->build_id, build_id, sizeof(self->build_id)) == 0;
119978075caaSArnaldo Carvalho de Melo }
120078075caaSArnaldo Carvalho de Melo 
1201a1645ce1SZhang, Yanmin bool __dsos__read_build_ids(struct list_head *head, bool with_hits)
120257f395a7SFrederic Weisbecker {
1203e30a3d12SArnaldo Carvalho de Melo 	bool have_build_id = false;
120457f395a7SFrederic Weisbecker 	struct dso *pos;
120557f395a7SFrederic Weisbecker 
12066122e4e4SArnaldo Carvalho de Melo 	list_for_each_entry(pos, head, node) {
12076122e4e4SArnaldo Carvalho de Melo 		if (with_hits && !pos->hit)
12086122e4e4SArnaldo Carvalho de Melo 			continue;
1209f6e1467dSArnaldo Carvalho de Melo 		if (pos->has_build_id) {
1210f6e1467dSArnaldo Carvalho de Melo 			have_build_id = true;
1211f6e1467dSArnaldo Carvalho de Melo 			continue;
1212f6e1467dSArnaldo Carvalho de Melo 		}
1213e30a3d12SArnaldo Carvalho de Melo 		if (filename__read_build_id(pos->long_name, pos->build_id,
1214e30a3d12SArnaldo Carvalho de Melo 					    sizeof(pos->build_id)) > 0) {
1215e30a3d12SArnaldo Carvalho de Melo 			have_build_id	  = true;
1216e30a3d12SArnaldo Carvalho de Melo 			pos->has_build_id = true;
121757f395a7SFrederic Weisbecker 		}
12186122e4e4SArnaldo Carvalho de Melo 	}
121957f395a7SFrederic Weisbecker 
1220e30a3d12SArnaldo Carvalho de Melo 	return have_build_id;
122157f395a7SFrederic Weisbecker }
122257f395a7SFrederic Weisbecker 
1223fd7a346eSArnaldo Carvalho de Melo /*
1224fd7a346eSArnaldo Carvalho de Melo  * Align offset to 4 bytes as needed for note name and descriptor data.
1225fd7a346eSArnaldo Carvalho de Melo  */
1226fd7a346eSArnaldo Carvalho de Melo #define NOTE_ALIGN(n) (((n) + 3) & -4U)
1227fd7a346eSArnaldo Carvalho de Melo 
122821916c38SDave Martin static int elf_read_build_id(Elf *elf, void *bf, size_t size)
12294d1e00a8SArnaldo Carvalho de Melo {
123021916c38SDave Martin 	int err = -1;
12314d1e00a8SArnaldo Carvalho de Melo 	GElf_Ehdr ehdr;
12324d1e00a8SArnaldo Carvalho de Melo 	GElf_Shdr shdr;
1233fd7a346eSArnaldo Carvalho de Melo 	Elf_Data *data;
12344d1e00a8SArnaldo Carvalho de Melo 	Elf_Scn *sec;
1235e57cfcdaSPekka Enberg 	Elf_Kind ek;
1236fd7a346eSArnaldo Carvalho de Melo 	void *ptr;
12374d1e00a8SArnaldo Carvalho de Melo 
12382643ce11SArnaldo Carvalho de Melo 	if (size < BUILD_ID_SIZE)
12392643ce11SArnaldo Carvalho de Melo 		goto out;
12402643ce11SArnaldo Carvalho de Melo 
1241e57cfcdaSPekka Enberg 	ek = elf_kind(elf);
1242e57cfcdaSPekka Enberg 	if (ek != ELF_K_ELF)
124321916c38SDave Martin 		goto out;
1244e57cfcdaSPekka Enberg 
12454d1e00a8SArnaldo Carvalho de Melo 	if (gelf_getehdr(elf, &ehdr) == NULL) {
12466beba7adSArnaldo Carvalho de Melo 		pr_err("%s: cannot get elf header.\n", __func__);
124721916c38SDave Martin 		goto out;
12484d1e00a8SArnaldo Carvalho de Melo 	}
12494d1e00a8SArnaldo Carvalho de Melo 
12502643ce11SArnaldo Carvalho de Melo 	sec = elf_section_by_name(elf, &ehdr, &shdr,
12512643ce11SArnaldo Carvalho de Melo 				  ".note.gnu.build-id", NULL);
1252fd7a346eSArnaldo Carvalho de Melo 	if (sec == NULL) {
1253fd7a346eSArnaldo Carvalho de Melo 		sec = elf_section_by_name(elf, &ehdr, &shdr,
1254fd7a346eSArnaldo Carvalho de Melo 					  ".notes", NULL);
12554d1e00a8SArnaldo Carvalho de Melo 		if (sec == NULL)
125621916c38SDave Martin 			goto out;
1257fd7a346eSArnaldo Carvalho de Melo 	}
12584d1e00a8SArnaldo Carvalho de Melo 
1259fd7a346eSArnaldo Carvalho de Melo 	data = elf_getdata(sec, NULL);
1260fd7a346eSArnaldo Carvalho de Melo 	if (data == NULL)
126121916c38SDave Martin 		goto out;
1262fd7a346eSArnaldo Carvalho de Melo 
1263fd7a346eSArnaldo Carvalho de Melo 	ptr = data->d_buf;
1264fd7a346eSArnaldo Carvalho de Melo 	while (ptr < (data->d_buf + data->d_size)) {
1265fd7a346eSArnaldo Carvalho de Melo 		GElf_Nhdr *nhdr = ptr;
1266fd7a346eSArnaldo Carvalho de Melo 		int namesz = NOTE_ALIGN(nhdr->n_namesz),
1267fd7a346eSArnaldo Carvalho de Melo 		    descsz = NOTE_ALIGN(nhdr->n_descsz);
1268fd7a346eSArnaldo Carvalho de Melo 		const char *name;
1269fd7a346eSArnaldo Carvalho de Melo 
1270fd7a346eSArnaldo Carvalho de Melo 		ptr += sizeof(*nhdr);
1271fd7a346eSArnaldo Carvalho de Melo 		name = ptr;
1272fd7a346eSArnaldo Carvalho de Melo 		ptr += namesz;
1273fd7a346eSArnaldo Carvalho de Melo 		if (nhdr->n_type == NT_GNU_BUILD_ID &&
1274fd7a346eSArnaldo Carvalho de Melo 		    nhdr->n_namesz == sizeof("GNU")) {
1275fd7a346eSArnaldo Carvalho de Melo 			if (memcmp(name, "GNU", sizeof("GNU")) == 0) {
1276fd7a346eSArnaldo Carvalho de Melo 				memcpy(bf, ptr, BUILD_ID_SIZE);
12772643ce11SArnaldo Carvalho de Melo 				err = BUILD_ID_SIZE;
1278fd7a346eSArnaldo Carvalho de Melo 				break;
1279fd7a346eSArnaldo Carvalho de Melo 			}
1280fd7a346eSArnaldo Carvalho de Melo 		}
1281fd7a346eSArnaldo Carvalho de Melo 		ptr += descsz;
1282fd7a346eSArnaldo Carvalho de Melo 	}
128321916c38SDave Martin 
128421916c38SDave Martin out:
128521916c38SDave Martin 	return err;
128621916c38SDave Martin }
128721916c38SDave Martin 
128821916c38SDave Martin int filename__read_build_id(const char *filename, void *bf, size_t size)
128921916c38SDave Martin {
129021916c38SDave Martin 	int fd, err = -1;
129121916c38SDave Martin 	Elf *elf;
129221916c38SDave Martin 
129321916c38SDave Martin 	if (size < BUILD_ID_SIZE)
129421916c38SDave Martin 		goto out;
129521916c38SDave Martin 
129621916c38SDave Martin 	fd = open(filename, O_RDONLY);
129721916c38SDave Martin 	if (fd < 0)
129821916c38SDave Martin 		goto out;
129921916c38SDave Martin 
130021916c38SDave Martin 	elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
130121916c38SDave Martin 	if (elf == NULL) {
130221916c38SDave Martin 		pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename);
130321916c38SDave Martin 		goto out_close;
130421916c38SDave Martin 	}
130521916c38SDave Martin 
130621916c38SDave Martin 	err = elf_read_build_id(elf, bf, size);
130721916c38SDave Martin 
13082643ce11SArnaldo Carvalho de Melo 	elf_end(elf);
13092643ce11SArnaldo Carvalho de Melo out_close:
13102643ce11SArnaldo Carvalho de Melo 	close(fd);
13112643ce11SArnaldo Carvalho de Melo out:
13122643ce11SArnaldo Carvalho de Melo 	return err;
13132643ce11SArnaldo Carvalho de Melo }
13142643ce11SArnaldo Carvalho de Melo 
1315f1617b40SArnaldo Carvalho de Melo int sysfs__read_build_id(const char *filename, void *build_id, size_t size)
1316f1617b40SArnaldo Carvalho de Melo {
1317f1617b40SArnaldo Carvalho de Melo 	int fd, err = -1;
1318f1617b40SArnaldo Carvalho de Melo 
1319f1617b40SArnaldo Carvalho de Melo 	if (size < BUILD_ID_SIZE)
1320f1617b40SArnaldo Carvalho de Melo 		goto out;
1321f1617b40SArnaldo Carvalho de Melo 
1322f1617b40SArnaldo Carvalho de Melo 	fd = open(filename, O_RDONLY);
1323f1617b40SArnaldo Carvalho de Melo 	if (fd < 0)
1324f1617b40SArnaldo Carvalho de Melo 		goto out;
1325f1617b40SArnaldo Carvalho de Melo 
1326f1617b40SArnaldo Carvalho de Melo 	while (1) {
1327f1617b40SArnaldo Carvalho de Melo 		char bf[BUFSIZ];
1328f1617b40SArnaldo Carvalho de Melo 		GElf_Nhdr nhdr;
1329f1617b40SArnaldo Carvalho de Melo 		int namesz, descsz;
1330f1617b40SArnaldo Carvalho de Melo 
1331f1617b40SArnaldo Carvalho de Melo 		if (read(fd, &nhdr, sizeof(nhdr)) != sizeof(nhdr))
1332f1617b40SArnaldo Carvalho de Melo 			break;
1333f1617b40SArnaldo Carvalho de Melo 
1334fd7a346eSArnaldo Carvalho de Melo 		namesz = NOTE_ALIGN(nhdr.n_namesz);
1335fd7a346eSArnaldo Carvalho de Melo 		descsz = NOTE_ALIGN(nhdr.n_descsz);
1336f1617b40SArnaldo Carvalho de Melo 		if (nhdr.n_type == NT_GNU_BUILD_ID &&
1337f1617b40SArnaldo Carvalho de Melo 		    nhdr.n_namesz == sizeof("GNU")) {
1338f1617b40SArnaldo Carvalho de Melo 			if (read(fd, bf, namesz) != namesz)
1339f1617b40SArnaldo Carvalho de Melo 				break;
1340f1617b40SArnaldo Carvalho de Melo 			if (memcmp(bf, "GNU", sizeof("GNU")) == 0) {
1341f1617b40SArnaldo Carvalho de Melo 				if (read(fd, build_id,
1342f1617b40SArnaldo Carvalho de Melo 				    BUILD_ID_SIZE) == BUILD_ID_SIZE) {
1343f1617b40SArnaldo Carvalho de Melo 					err = 0;
1344f1617b40SArnaldo Carvalho de Melo 					break;
1345f1617b40SArnaldo Carvalho de Melo 				}
1346f1617b40SArnaldo Carvalho de Melo 			} else if (read(fd, bf, descsz) != descsz)
1347f1617b40SArnaldo Carvalho de Melo 				break;
1348f1617b40SArnaldo Carvalho de Melo 		} else {
1349f1617b40SArnaldo Carvalho de Melo 			int n = namesz + descsz;
1350f1617b40SArnaldo Carvalho de Melo 			if (read(fd, bf, n) != n)
1351f1617b40SArnaldo Carvalho de Melo 				break;
1352f1617b40SArnaldo Carvalho de Melo 		}
1353f1617b40SArnaldo Carvalho de Melo 	}
1354f1617b40SArnaldo Carvalho de Melo 	close(fd);
1355f1617b40SArnaldo Carvalho de Melo out:
1356f1617b40SArnaldo Carvalho de Melo 	return err;
1357f1617b40SArnaldo Carvalho de Melo }
1358f1617b40SArnaldo Carvalho de Melo 
135994cb9e38SArnaldo Carvalho de Melo char dso__symtab_origin(const struct dso *self)
136094cb9e38SArnaldo Carvalho de Melo {
136194cb9e38SArnaldo Carvalho de Melo 	static const char origin[] = {
136294cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_KERNEL] =   'k',
136394cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_JAVA_JIT] = 'j',
13644cf40131SArnaldo Carvalho de Melo 		[DSO__ORIG_BUILD_ID_CACHE] = 'B',
136594cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_FEDORA] =   'f',
136694cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_UBUNTU] =   'u',
136794cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_BUILDID] =  'b',
136894cb9e38SArnaldo Carvalho de Melo 		[DSO__ORIG_DSO] =      'd',
1369439d473bSArnaldo Carvalho de Melo 		[DSO__ORIG_KMODULE] =  'K',
1370a1645ce1SZhang, Yanmin 		[DSO__ORIG_GUEST_KERNEL] =  'g',
1371a1645ce1SZhang, Yanmin 		[DSO__ORIG_GUEST_KMODULE] =  'G',
137294cb9e38SArnaldo Carvalho de Melo 	};
137394cb9e38SArnaldo Carvalho de Melo 
137494cb9e38SArnaldo Carvalho de Melo 	if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND)
137594cb9e38SArnaldo Carvalho de Melo 		return '!';
137694cb9e38SArnaldo Carvalho de Melo 	return origin[self->origin];
137794cb9e38SArnaldo Carvalho de Melo }
137894cb9e38SArnaldo Carvalho de Melo 
13799de89fe7SArnaldo Carvalho de Melo int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
138086470930SIngo Molnar {
13814d1e00a8SArnaldo Carvalho de Melo 	int size = PATH_MAX;
1382c338aee8SArnaldo Carvalho de Melo 	char *name;
138386470930SIngo Molnar 	int ret = -1;
138486470930SIngo Molnar 	int fd;
138523346f21SArnaldo Carvalho de Melo 	struct machine *machine;
1386a1645ce1SZhang, Yanmin 	const char *root_dir;
13876da80ce8SDave Martin 	int want_symtab;
138886470930SIngo Molnar 
13893610583cSArnaldo Carvalho de Melo 	dso__set_loaded(self, map->type);
139066bd8424SArnaldo Carvalho de Melo 
1391a1645ce1SZhang, Yanmin 	if (self->kernel == DSO_TYPE_KERNEL)
13929de89fe7SArnaldo Carvalho de Melo 		return dso__load_kernel_sym(self, map, filter);
1393a1645ce1SZhang, Yanmin 	else if (self->kernel == DSO_TYPE_GUEST_KERNEL)
1394a1645ce1SZhang, Yanmin 		return dso__load_guest_kernel_sym(self, map, filter);
1395a1645ce1SZhang, Yanmin 
139623346f21SArnaldo Carvalho de Melo 	if (map->groups && map->groups->machine)
139723346f21SArnaldo Carvalho de Melo 		machine = map->groups->machine;
1398a1645ce1SZhang, Yanmin 	else
139923346f21SArnaldo Carvalho de Melo 		machine = NULL;
1400c338aee8SArnaldo Carvalho de Melo 
1401c338aee8SArnaldo Carvalho de Melo 	name = malloc(size);
140286470930SIngo Molnar 	if (!name)
140386470930SIngo Molnar 		return -1;
140486470930SIngo Molnar 
140530d7a77dSArnaldo Carvalho de Melo 	self->adjust_symbols = 0;
1406f5812a7aSArnaldo Carvalho de Melo 
140794cb9e38SArnaldo Carvalho de Melo 	if (strncmp(self->name, "/tmp/perf-", 10) == 0) {
14086beba7adSArnaldo Carvalho de Melo 		ret = dso__load_perf_map(self, map, filter);
140994cb9e38SArnaldo Carvalho de Melo 		self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT :
141094cb9e38SArnaldo Carvalho de Melo 					 DSO__ORIG_NOT_FOUND;
141194cb9e38SArnaldo Carvalho de Melo 		return ret;
141294cb9e38SArnaldo Carvalho de Melo 	}
141394cb9e38SArnaldo Carvalho de Melo 
14146da80ce8SDave Martin 	/* Iterate over candidate debug images.
14156da80ce8SDave Martin 	 * On the first pass, only load images if they have a full symtab.
14166da80ce8SDave Martin 	 * Failing that, do a second pass where we accept .dynsym also
14176da80ce8SDave Martin 	 */
14186da80ce8SDave Martin 	for (self->origin = DSO__ORIG_BUILD_ID_CACHE, want_symtab = 1;
14196da80ce8SDave Martin 	     self->origin != DSO__ORIG_NOT_FOUND;
14206da80ce8SDave Martin 	     self->origin++) {
142194cb9e38SArnaldo Carvalho de Melo 		switch (self->origin) {
14226da80ce8SDave Martin 		case DSO__ORIG_BUILD_ID_CACHE:
14236da80ce8SDave Martin 			if (dso__build_id_filename(self, name, size) == NULL)
14246da80ce8SDave Martin 				continue;
14256da80ce8SDave Martin 			break;
142694cb9e38SArnaldo Carvalho de Melo 		case DSO__ORIG_FEDORA:
1427439d473bSArnaldo Carvalho de Melo 			snprintf(name, size, "/usr/lib/debug%s.debug",
1428439d473bSArnaldo Carvalho de Melo 				 self->long_name);
142986470930SIngo Molnar 			break;
143094cb9e38SArnaldo Carvalho de Melo 		case DSO__ORIG_UBUNTU:
1431439d473bSArnaldo Carvalho de Melo 			snprintf(name, size, "/usr/lib/debug%s",
1432439d473bSArnaldo Carvalho de Melo 				 self->long_name);
143386470930SIngo Molnar 			break;
14346da80ce8SDave Martin 		case DSO__ORIG_BUILDID: {
1435b36f19d5SArnaldo Carvalho de Melo 			char build_id_hex[BUILD_ID_SIZE * 2 + 1];
14366da80ce8SDave Martin 
14376da80ce8SDave Martin 			if (!self->has_build_id)
14386da80ce8SDave Martin 				continue;
14396da80ce8SDave Martin 
144021916c38SDave Martin 			build_id__sprintf(self->build_id,
144121916c38SDave Martin 					  sizeof(self->build_id),
1442d3379ab9SArnaldo Carvalho de Melo 					  build_id_hex);
14434d1e00a8SArnaldo Carvalho de Melo 			snprintf(name, size,
14444d1e00a8SArnaldo Carvalho de Melo 				 "/usr/lib/debug/.build-id/%.2s/%s.debug",
1445d3379ab9SArnaldo Carvalho de Melo 				 build_id_hex, build_id_hex + 2);
14464d1e00a8SArnaldo Carvalho de Melo 			}
14476da80ce8SDave Martin 			break;
144894cb9e38SArnaldo Carvalho de Melo 		case DSO__ORIG_DSO:
1449439d473bSArnaldo Carvalho de Melo 			snprintf(name, size, "%s", self->long_name);
145086470930SIngo Molnar 			break;
1451a1645ce1SZhang, Yanmin 		case DSO__ORIG_GUEST_KMODULE:
145223346f21SArnaldo Carvalho de Melo 			if (map->groups && map->groups->machine)
145323346f21SArnaldo Carvalho de Melo 				root_dir = map->groups->machine->root_dir;
1454a1645ce1SZhang, Yanmin 			else
1455a1645ce1SZhang, Yanmin 				root_dir = "";
1456a1645ce1SZhang, Yanmin 			snprintf(name, size, "%s%s", root_dir, self->long_name);
1457a1645ce1SZhang, Yanmin 			break;
145886470930SIngo Molnar 
145986470930SIngo Molnar 		default:
14606da80ce8SDave Martin 			/*
14616da80ce8SDave Martin 			 * If we wanted a full symtab but no image had one,
14626da80ce8SDave Martin 			 * relax our requirements and repeat the search.
14636da80ce8SDave Martin 			 */
14646da80ce8SDave Martin 			if (want_symtab) {
14656da80ce8SDave Martin 				want_symtab = 0;
14666da80ce8SDave Martin 				self->origin = DSO__ORIG_BUILD_ID_CACHE;
14676da80ce8SDave Martin 			} else
14686da80ce8SDave Martin 				continue;
146986470930SIngo Molnar 		}
147086470930SIngo Molnar 
14716da80ce8SDave Martin 		/* Name is now the name of the next image to try */
14726da80ce8SDave Martin 		fd = open(name, O_RDONLY);
14736da80ce8SDave Martin 		if (fd < 0)
14746da80ce8SDave Martin 			continue;
14756da80ce8SDave Martin 
14766da80ce8SDave Martin 		ret = dso__load_sym(self, map, name, fd, filter, 0,
14776da80ce8SDave Martin 				    want_symtab);
147886470930SIngo Molnar 		close(fd);
147986470930SIngo Molnar 
148086470930SIngo Molnar 		/*
14816da80ce8SDave Martin 		 * Some people seem to have debuginfo files _WITHOUT_ debug
14826da80ce8SDave Martin 		 * info!?!?
148386470930SIngo Molnar 		 */
148486470930SIngo Molnar 		if (!ret)
14856da80ce8SDave Martin 			continue;
148686470930SIngo Molnar 
1487a25e46c4SArnaldo Carvalho de Melo 		if (ret > 0) {
148882164161SArnaldo Carvalho de Melo 			int nr_plt = dso__synthesize_plt_symbols(self, map, filter);
1489a25e46c4SArnaldo Carvalho de Melo 			if (nr_plt > 0)
1490a25e46c4SArnaldo Carvalho de Melo 				ret += nr_plt;
14916da80ce8SDave Martin 			break;
1492a25e46c4SArnaldo Carvalho de Melo 		}
14936da80ce8SDave Martin 	}
14946da80ce8SDave Martin 
149586470930SIngo Molnar 	free(name);
14961340e6bbSArnaldo Carvalho de Melo 	if (ret < 0 && strstr(self->name, " (deleted)") != NULL)
14971340e6bbSArnaldo Carvalho de Melo 		return 0;
149886470930SIngo Molnar 	return ret;
149986470930SIngo Molnar }
150086470930SIngo Molnar 
150179406cd7SArnaldo Carvalho de Melo struct map *map_groups__find_by_name(struct map_groups *self,
150279406cd7SArnaldo Carvalho de Melo 				     enum map_type type, const char *name)
1503439d473bSArnaldo Carvalho de Melo {
1504439d473bSArnaldo Carvalho de Melo 	struct rb_node *nd;
1505439d473bSArnaldo Carvalho de Melo 
150679406cd7SArnaldo Carvalho de Melo 	for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) {
1507439d473bSArnaldo Carvalho de Melo 		struct map *map = rb_entry(nd, struct map, rb_node);
1508439d473bSArnaldo Carvalho de Melo 
1509b7cece76SArnaldo Carvalho de Melo 		if (map->dso && strcmp(map->dso->short_name, name) == 0)
1510439d473bSArnaldo Carvalho de Melo 			return map;
1511439d473bSArnaldo Carvalho de Melo 	}
1512439d473bSArnaldo Carvalho de Melo 
1513439d473bSArnaldo Carvalho de Melo 	return NULL;
1514439d473bSArnaldo Carvalho de Melo }
1515439d473bSArnaldo Carvalho de Melo 
1516a1645ce1SZhang, Yanmin static int dso__kernel_module_get_build_id(struct dso *self,
1517a1645ce1SZhang, Yanmin 				const char *root_dir)
1518b7cece76SArnaldo Carvalho de Melo {
1519b7cece76SArnaldo Carvalho de Melo 	char filename[PATH_MAX];
1520b7cece76SArnaldo Carvalho de Melo 	/*
1521b7cece76SArnaldo Carvalho de Melo 	 * kernel module short names are of the form "[module]" and
1522b7cece76SArnaldo Carvalho de Melo 	 * we need just "module" here.
1523b7cece76SArnaldo Carvalho de Melo 	 */
1524b7cece76SArnaldo Carvalho de Melo 	const char *name = self->short_name + 1;
1525b7cece76SArnaldo Carvalho de Melo 
1526b7cece76SArnaldo Carvalho de Melo 	snprintf(filename, sizeof(filename),
1527a1645ce1SZhang, Yanmin 		 "%s/sys/module/%.*s/notes/.note.gnu.build-id",
1528a1645ce1SZhang, Yanmin 		 root_dir, (int)strlen(name) - 1, name);
1529b7cece76SArnaldo Carvalho de Melo 
1530b7cece76SArnaldo Carvalho de Melo 	if (sysfs__read_build_id(filename, self->build_id,
1531b7cece76SArnaldo Carvalho de Melo 				 sizeof(self->build_id)) == 0)
1532b7cece76SArnaldo Carvalho de Melo 		self->has_build_id = true;
1533b7cece76SArnaldo Carvalho de Melo 
1534b7cece76SArnaldo Carvalho de Melo 	return 0;
1535b7cece76SArnaldo Carvalho de Melo }
1536b7cece76SArnaldo Carvalho de Melo 
1537a1645ce1SZhang, Yanmin static int map_groups__set_modules_path_dir(struct map_groups *self,
1538a1645ce1SZhang, Yanmin 				const char *dir_name)
15396cfcc53eSMike Galbraith {
1540439d473bSArnaldo Carvalho de Melo 	struct dirent *dent;
15415aab621bSArnaldo Carvalho de Melo 	DIR *dir = opendir(dir_name);
154274534341SGui Jianfeng 	int ret = 0;
15436cfcc53eSMike Galbraith 
1544439d473bSArnaldo Carvalho de Melo 	if (!dir) {
15455aab621bSArnaldo Carvalho de Melo 		pr_debug("%s: cannot open %s dir\n", __func__, dir_name);
1546439d473bSArnaldo Carvalho de Melo 		return -1;
1547439d473bSArnaldo Carvalho de Melo 	}
15486cfcc53eSMike Galbraith 
1549439d473bSArnaldo Carvalho de Melo 	while ((dent = readdir(dir)) != NULL) {
1550439d473bSArnaldo Carvalho de Melo 		char path[PATH_MAX];
1551a1645ce1SZhang, Yanmin 		struct stat st;
1552439d473bSArnaldo Carvalho de Melo 
1553a1645ce1SZhang, Yanmin 		/*sshfs might return bad dent->d_type, so we have to stat*/
1554a1645ce1SZhang, Yanmin 		sprintf(path, "%s/%s", dir_name, dent->d_name);
1555a1645ce1SZhang, Yanmin 		if (stat(path, &st))
1556a1645ce1SZhang, Yanmin 			continue;
1557a1645ce1SZhang, Yanmin 
1558a1645ce1SZhang, Yanmin 		if (S_ISDIR(st.st_mode)) {
1559439d473bSArnaldo Carvalho de Melo 			if (!strcmp(dent->d_name, ".") ||
1560439d473bSArnaldo Carvalho de Melo 			    !strcmp(dent->d_name, ".."))
1561439d473bSArnaldo Carvalho de Melo 				continue;
1562439d473bSArnaldo Carvalho de Melo 
1563439d473bSArnaldo Carvalho de Melo 			snprintf(path, sizeof(path), "%s/%s",
15645aab621bSArnaldo Carvalho de Melo 				 dir_name, dent->d_name);
156574534341SGui Jianfeng 			ret = map_groups__set_modules_path_dir(self, path);
156674534341SGui Jianfeng 			if (ret < 0)
156774534341SGui Jianfeng 				goto out;
1568439d473bSArnaldo Carvalho de Melo 		} else {
1569439d473bSArnaldo Carvalho de Melo 			char *dot = strrchr(dent->d_name, '.'),
1570439d473bSArnaldo Carvalho de Melo 			     dso_name[PATH_MAX];
1571439d473bSArnaldo Carvalho de Melo 			struct map *map;
1572cfc10d3bSArnaldo Carvalho de Melo 			char *long_name;
1573439d473bSArnaldo Carvalho de Melo 
1574439d473bSArnaldo Carvalho de Melo 			if (dot == NULL || strcmp(dot, ".ko"))
1575439d473bSArnaldo Carvalho de Melo 				continue;
1576439d473bSArnaldo Carvalho de Melo 			snprintf(dso_name, sizeof(dso_name), "[%.*s]",
1577439d473bSArnaldo Carvalho de Melo 				 (int)(dot - dent->d_name), dent->d_name);
1578439d473bSArnaldo Carvalho de Melo 
1579a2a99e8eSArnaldo Carvalho de Melo 			strxfrchar(dso_name, '-', '_');
15809de89fe7SArnaldo Carvalho de Melo 			map = map_groups__find_by_name(self, MAP__FUNCTION, dso_name);
1581439d473bSArnaldo Carvalho de Melo 			if (map == NULL)
1582439d473bSArnaldo Carvalho de Melo 				continue;
1583439d473bSArnaldo Carvalho de Melo 
1584439d473bSArnaldo Carvalho de Melo 			snprintf(path, sizeof(path), "%s/%s",
15855aab621bSArnaldo Carvalho de Melo 				 dir_name, dent->d_name);
1586439d473bSArnaldo Carvalho de Melo 
1587cfc10d3bSArnaldo Carvalho de Melo 			long_name = strdup(path);
158874534341SGui Jianfeng 			if (long_name == NULL) {
158974534341SGui Jianfeng 				ret = -1;
159074534341SGui Jianfeng 				goto out;
159174534341SGui Jianfeng 			}
1592cfc10d3bSArnaldo Carvalho de Melo 			dso__set_long_name(map->dso, long_name);
15936e406257SArnaldo Carvalho de Melo 			map->dso->lname_alloc = 1;
1594a1645ce1SZhang, Yanmin 			dso__kernel_module_get_build_id(map->dso, "");
1595439d473bSArnaldo Carvalho de Melo 		}
1596439d473bSArnaldo Carvalho de Melo 	}
1597439d473bSArnaldo Carvalho de Melo 
159874534341SGui Jianfeng out:
1599439d473bSArnaldo Carvalho de Melo 	closedir(dir);
160074534341SGui Jianfeng 	return ret;
1601439d473bSArnaldo Carvalho de Melo }
1602439d473bSArnaldo Carvalho de Melo 
1603a1645ce1SZhang, Yanmin static char *get_kernel_version(const char *root_dir)
1604439d473bSArnaldo Carvalho de Melo {
1605a1645ce1SZhang, Yanmin 	char version[PATH_MAX];
1606a1645ce1SZhang, Yanmin 	FILE *file;
1607a1645ce1SZhang, Yanmin 	char *name, *tmp;
1608a1645ce1SZhang, Yanmin 	const char *prefix = "Linux version ";
1609a1645ce1SZhang, Yanmin 
1610a1645ce1SZhang, Yanmin 	sprintf(version, "%s/proc/version", root_dir);
1611a1645ce1SZhang, Yanmin 	file = fopen(version, "r");
1612a1645ce1SZhang, Yanmin 	if (!file)
1613a1645ce1SZhang, Yanmin 		return NULL;
1614a1645ce1SZhang, Yanmin 
1615a1645ce1SZhang, Yanmin 	version[0] = '\0';
1616a1645ce1SZhang, Yanmin 	tmp = fgets(version, sizeof(version), file);
1617a1645ce1SZhang, Yanmin 	fclose(file);
1618a1645ce1SZhang, Yanmin 
1619a1645ce1SZhang, Yanmin 	name = strstr(version, prefix);
1620a1645ce1SZhang, Yanmin 	if (!name)
1621a1645ce1SZhang, Yanmin 		return NULL;
1622a1645ce1SZhang, Yanmin 	name += strlen(prefix);
1623a1645ce1SZhang, Yanmin 	tmp = strchr(name, ' ');
1624a1645ce1SZhang, Yanmin 	if (tmp)
1625a1645ce1SZhang, Yanmin 		*tmp = '\0';
1626a1645ce1SZhang, Yanmin 
1627a1645ce1SZhang, Yanmin 	return strdup(name);
1628a1645ce1SZhang, Yanmin }
1629a1645ce1SZhang, Yanmin 
1630d28c6223SArnaldo Carvalho de Melo static int machine__set_modules_path(struct machine *self)
1631a1645ce1SZhang, Yanmin {
1632a1645ce1SZhang, Yanmin 	char *version;
1633439d473bSArnaldo Carvalho de Melo 	char modules_path[PATH_MAX];
1634439d473bSArnaldo Carvalho de Melo 
1635d28c6223SArnaldo Carvalho de Melo 	version = get_kernel_version(self->root_dir);
1636a1645ce1SZhang, Yanmin 	if (!version)
1637439d473bSArnaldo Carvalho de Melo 		return -1;
1638439d473bSArnaldo Carvalho de Melo 
1639a1645ce1SZhang, Yanmin 	snprintf(modules_path, sizeof(modules_path), "%s/lib/modules/%s/kernel",
1640d28c6223SArnaldo Carvalho de Melo 		 self->root_dir, version);
1641a1645ce1SZhang, Yanmin 	free(version);
1642439d473bSArnaldo Carvalho de Melo 
1643d28c6223SArnaldo Carvalho de Melo 	return map_groups__set_modules_path_dir(&self->kmaps, modules_path);
1644439d473bSArnaldo Carvalho de Melo }
16456cfcc53eSMike Galbraith 
16466cfcc53eSMike Galbraith /*
1647439d473bSArnaldo Carvalho de Melo  * Constructor variant for modules (where we know from /proc/modules where
1648439d473bSArnaldo Carvalho de Melo  * they are loaded) and for vmlinux, where only after we load all the
1649439d473bSArnaldo Carvalho de Melo  * symbols we'll know where it starts and ends.
16506cfcc53eSMike Galbraith  */
16513610583cSArnaldo Carvalho de Melo static struct map *map__new2(u64 start, struct dso *dso, enum map_type type)
1652439d473bSArnaldo Carvalho de Melo {
16535aab621bSArnaldo Carvalho de Melo 	struct map *self = calloc(1, (sizeof(*self) +
16545aab621bSArnaldo Carvalho de Melo 				      (dso->kernel ? sizeof(struct kmap) : 0)));
1655439d473bSArnaldo Carvalho de Melo 	if (self != NULL) {
1656439d473bSArnaldo Carvalho de Melo 		/*
1657afb7b4f0SArnaldo Carvalho de Melo 		 * ->end will be filled after we load all the symbols
1658439d473bSArnaldo Carvalho de Melo 		 */
16593610583cSArnaldo Carvalho de Melo 		map__init(self, type, start, 0, 0, dso);
1660439d473bSArnaldo Carvalho de Melo 	}
1661afb7b4f0SArnaldo Carvalho de Melo 
1662439d473bSArnaldo Carvalho de Melo 	return self;
1663439d473bSArnaldo Carvalho de Melo }
1664439d473bSArnaldo Carvalho de Melo 
1665d28c6223SArnaldo Carvalho de Melo struct map *machine__new_module(struct machine *self, u64 start,
1666d28c6223SArnaldo Carvalho de Melo 				const char *filename)
1667b7cece76SArnaldo Carvalho de Melo {
1668b7cece76SArnaldo Carvalho de Melo 	struct map *map;
1669d28c6223SArnaldo Carvalho de Melo 	struct dso *dso = __dsos__findnew(&self->kernel_dsos, filename);
1670b7cece76SArnaldo Carvalho de Melo 
1671b7cece76SArnaldo Carvalho de Melo 	if (dso == NULL)
1672b7cece76SArnaldo Carvalho de Melo 		return NULL;
1673b7cece76SArnaldo Carvalho de Melo 
1674b7cece76SArnaldo Carvalho de Melo 	map = map__new2(start, dso, MAP__FUNCTION);
1675b7cece76SArnaldo Carvalho de Melo 	if (map == NULL)
1676b7cece76SArnaldo Carvalho de Melo 		return NULL;
1677b7cece76SArnaldo Carvalho de Melo 
1678d28c6223SArnaldo Carvalho de Melo 	if (machine__is_host(self))
1679b7cece76SArnaldo Carvalho de Melo 		dso->origin = DSO__ORIG_KMODULE;
1680a1645ce1SZhang, Yanmin 	else
1681a1645ce1SZhang, Yanmin 		dso->origin = DSO__ORIG_GUEST_KMODULE;
1682d28c6223SArnaldo Carvalho de Melo 	map_groups__insert(&self->kmaps, map);
1683b7cece76SArnaldo Carvalho de Melo 	return map;
1684b7cece76SArnaldo Carvalho de Melo }
1685b7cece76SArnaldo Carvalho de Melo 
1686d28c6223SArnaldo Carvalho de Melo static int machine__create_modules(struct machine *self)
1687439d473bSArnaldo Carvalho de Melo {
1688439d473bSArnaldo Carvalho de Melo 	char *line = NULL;
1689439d473bSArnaldo Carvalho de Melo 	size_t n;
1690a1645ce1SZhang, Yanmin 	FILE *file;
1691439d473bSArnaldo Carvalho de Melo 	struct map *map;
1692a1645ce1SZhang, Yanmin 	const char *modules;
1693a1645ce1SZhang, Yanmin 	char path[PATH_MAX];
1694439d473bSArnaldo Carvalho de Melo 
1695d28c6223SArnaldo Carvalho de Melo 	if (machine__is_default_guest(self))
1696a1645ce1SZhang, Yanmin 		modules = symbol_conf.default_guest_modules;
1697a1645ce1SZhang, Yanmin 	else {
1698d28c6223SArnaldo Carvalho de Melo 		sprintf(path, "%s/proc/modules", self->root_dir);
1699a1645ce1SZhang, Yanmin 		modules = path;
1700a1645ce1SZhang, Yanmin 	}
1701a1645ce1SZhang, Yanmin 
1702a1645ce1SZhang, Yanmin 	file = fopen(modules, "r");
1703439d473bSArnaldo Carvalho de Melo 	if (file == NULL)
1704439d473bSArnaldo Carvalho de Melo 		return -1;
1705439d473bSArnaldo Carvalho de Melo 
1706439d473bSArnaldo Carvalho de Melo 	while (!feof(file)) {
1707439d473bSArnaldo Carvalho de Melo 		char name[PATH_MAX];
1708439d473bSArnaldo Carvalho de Melo 		u64 start;
1709439d473bSArnaldo Carvalho de Melo 		char *sep;
1710439d473bSArnaldo Carvalho de Melo 		int line_len;
1711439d473bSArnaldo Carvalho de Melo 
1712439d473bSArnaldo Carvalho de Melo 		line_len = getline(&line, &n, file);
1713439d473bSArnaldo Carvalho de Melo 		if (line_len < 0)
17146cfcc53eSMike Galbraith 			break;
17156cfcc53eSMike Galbraith 
1716439d473bSArnaldo Carvalho de Melo 		if (!line)
1717439d473bSArnaldo Carvalho de Melo 			goto out_failure;
1718439d473bSArnaldo Carvalho de Melo 
1719439d473bSArnaldo Carvalho de Melo 		line[--line_len] = '\0'; /* \n */
1720439d473bSArnaldo Carvalho de Melo 
1721439d473bSArnaldo Carvalho de Melo 		sep = strrchr(line, 'x');
1722439d473bSArnaldo Carvalho de Melo 		if (sep == NULL)
1723439d473bSArnaldo Carvalho de Melo 			continue;
1724439d473bSArnaldo Carvalho de Melo 
1725439d473bSArnaldo Carvalho de Melo 		hex2u64(sep + 1, &start);
1726439d473bSArnaldo Carvalho de Melo 
1727439d473bSArnaldo Carvalho de Melo 		sep = strchr(line, ' ');
1728439d473bSArnaldo Carvalho de Melo 		if (sep == NULL)
1729439d473bSArnaldo Carvalho de Melo 			continue;
1730439d473bSArnaldo Carvalho de Melo 
1731439d473bSArnaldo Carvalho de Melo 		*sep = '\0';
1732439d473bSArnaldo Carvalho de Melo 
1733439d473bSArnaldo Carvalho de Melo 		snprintf(name, sizeof(name), "[%s]", line);
1734d28c6223SArnaldo Carvalho de Melo 		map = machine__new_module(self, start, name);
1735b7cece76SArnaldo Carvalho de Melo 		if (map == NULL)
1736439d473bSArnaldo Carvalho de Melo 			goto out_delete_line;
1737d28c6223SArnaldo Carvalho de Melo 		dso__kernel_module_get_build_id(map->dso, self->root_dir);
17386cfcc53eSMike Galbraith 	}
17396cfcc53eSMike Galbraith 
1740439d473bSArnaldo Carvalho de Melo 	free(line);
1741439d473bSArnaldo Carvalho de Melo 	fclose(file);
1742439d473bSArnaldo Carvalho de Melo 
1743d28c6223SArnaldo Carvalho de Melo 	return machine__set_modules_path(self);
1744439d473bSArnaldo Carvalho de Melo 
1745439d473bSArnaldo Carvalho de Melo out_delete_line:
1746439d473bSArnaldo Carvalho de Melo 	free(line);
1747439d473bSArnaldo Carvalho de Melo out_failure:
1748439d473bSArnaldo Carvalho de Melo 	return -1;
17496cfcc53eSMike Galbraith }
17506cfcc53eSMike Galbraith 
17519958e1f0SArnaldo Carvalho de Melo static int dso__load_vmlinux(struct dso *self, struct map *map,
17526beba7adSArnaldo Carvalho de Melo 			     const char *vmlinux, symbol_filter_t filter)
175386470930SIngo Molnar {
1754fbd733b8SArnaldo Carvalho de Melo 	int err = -1, fd;
175586470930SIngo Molnar 
1756fbd733b8SArnaldo Carvalho de Melo 	fd = open(vmlinux, O_RDONLY);
175786470930SIngo Molnar 	if (fd < 0)
175886470930SIngo Molnar 		return -1;
175986470930SIngo Molnar 
17603610583cSArnaldo Carvalho de Melo 	dso__set_loaded(self, map->type);
17616da80ce8SDave Martin 	err = dso__load_sym(self, map, vmlinux, fd, filter, 0, 0);
176286470930SIngo Molnar 	close(fd);
176386470930SIngo Molnar 
17643846df2eSArnaldo Carvalho de Melo 	if (err > 0)
17653846df2eSArnaldo Carvalho de Melo 		pr_debug("Using %s for symbols\n", vmlinux);
17663846df2eSArnaldo Carvalho de Melo 
176786470930SIngo Molnar 	return err;
176886470930SIngo Molnar }
176986470930SIngo Molnar 
1770a19afe46SArnaldo Carvalho de Melo int dso__load_vmlinux_path(struct dso *self, struct map *map,
17719de89fe7SArnaldo Carvalho de Melo 			   symbol_filter_t filter)
1772a19afe46SArnaldo Carvalho de Melo {
1773a19afe46SArnaldo Carvalho de Melo 	int i, err = 0;
17745ad90e4eSArnaldo Carvalho de Melo 	char *filename;
1775a19afe46SArnaldo Carvalho de Melo 
1776a19afe46SArnaldo Carvalho de Melo 	pr_debug("Looking at the vmlinux_path (%d entries long)\n",
17775ad90e4eSArnaldo Carvalho de Melo 		 vmlinux_path__nr_entries + 1);
17785ad90e4eSArnaldo Carvalho de Melo 
17795ad90e4eSArnaldo Carvalho de Melo 	filename = dso__build_id_filename(self, NULL, 0);
17805ad90e4eSArnaldo Carvalho de Melo 	if (filename != NULL) {
17815ad90e4eSArnaldo Carvalho de Melo 		err = dso__load_vmlinux(self, map, filename, filter);
17825ad90e4eSArnaldo Carvalho de Melo 		if (err > 0) {
17835ad90e4eSArnaldo Carvalho de Melo 			dso__set_long_name(self, filename);
17845ad90e4eSArnaldo Carvalho de Melo 			goto out;
17855ad90e4eSArnaldo Carvalho de Melo 		}
17865ad90e4eSArnaldo Carvalho de Melo 		free(filename);
17875ad90e4eSArnaldo Carvalho de Melo 	}
1788a19afe46SArnaldo Carvalho de Melo 
1789a19afe46SArnaldo Carvalho de Melo 	for (i = 0; i < vmlinux_path__nr_entries; ++i) {
17909de89fe7SArnaldo Carvalho de Melo 		err = dso__load_vmlinux(self, map, vmlinux_path[i], filter);
1791a19afe46SArnaldo Carvalho de Melo 		if (err > 0) {
1792a19afe46SArnaldo Carvalho de Melo 			dso__set_long_name(self, strdup(vmlinux_path[i]));
1793a19afe46SArnaldo Carvalho de Melo 			break;
1794a19afe46SArnaldo Carvalho de Melo 		}
1795a19afe46SArnaldo Carvalho de Melo 	}
17965ad90e4eSArnaldo Carvalho de Melo out:
1797a19afe46SArnaldo Carvalho de Melo 	return err;
1798a19afe46SArnaldo Carvalho de Melo }
1799a19afe46SArnaldo Carvalho de Melo 
1800c338aee8SArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *self, struct map *map,
18019de89fe7SArnaldo Carvalho de Melo 				symbol_filter_t filter)
180286470930SIngo Molnar {
1803cc612d81SArnaldo Carvalho de Melo 	int err;
18049e201442SArnaldo Carvalho de Melo 	const char *kallsyms_filename = NULL;
18059e201442SArnaldo Carvalho de Melo 	char *kallsyms_allocated_filename = NULL;
1806dc8d6ab2SArnaldo Carvalho de Melo 	/*
1807dc8d6ab2SArnaldo Carvalho de Melo 	 * Step 1: if the user specified a vmlinux filename, use it and only
1808dc8d6ab2SArnaldo Carvalho de Melo 	 * it, reporting errors to the user if it cannot be used.
1809dc8d6ab2SArnaldo Carvalho de Melo 	 *
1810dc8d6ab2SArnaldo Carvalho de Melo 	 * For instance, try to analyse an ARM perf.data file _without_ a
1811dc8d6ab2SArnaldo Carvalho de Melo 	 * build-id, or if the user specifies the wrong path to the right
1812dc8d6ab2SArnaldo Carvalho de Melo 	 * vmlinux file, obviously we can't fallback to another vmlinux (a
1813dc8d6ab2SArnaldo Carvalho de Melo 	 * x86_86 one, on the machine where analysis is being performed, say),
1814dc8d6ab2SArnaldo Carvalho de Melo 	 * or worse, /proc/kallsyms.
1815dc8d6ab2SArnaldo Carvalho de Melo 	 *
1816dc8d6ab2SArnaldo Carvalho de Melo 	 * If the specified file _has_ a build-id and there is a build-id
1817dc8d6ab2SArnaldo Carvalho de Melo 	 * section in the perf.data file, we will still do the expected
1818dc8d6ab2SArnaldo Carvalho de Melo 	 * validation in dso__load_vmlinux and will bail out if they don't
1819dc8d6ab2SArnaldo Carvalho de Melo 	 * match.
1820dc8d6ab2SArnaldo Carvalho de Melo 	 */
1821dc8d6ab2SArnaldo Carvalho de Melo 	if (symbol_conf.vmlinux_name != NULL) {
18229de89fe7SArnaldo Carvalho de Melo 		err = dso__load_vmlinux(self, map,
1823dc8d6ab2SArnaldo Carvalho de Melo 					symbol_conf.vmlinux_name, filter);
1824e7dadc00SArnaldo Carvalho de Melo 		if (err > 0) {
1825e7dadc00SArnaldo Carvalho de Melo 			dso__set_long_name(self,
1826e7dadc00SArnaldo Carvalho de Melo 					   strdup(symbol_conf.vmlinux_name));
1827e7dadc00SArnaldo Carvalho de Melo 			goto out_fixup;
1828e7dadc00SArnaldo Carvalho de Melo 		}
1829e7dadc00SArnaldo Carvalho de Melo 		return err;
1830dc8d6ab2SArnaldo Carvalho de Melo 	}
1831439d473bSArnaldo Carvalho de Melo 
1832cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path != NULL) {
18339de89fe7SArnaldo Carvalho de Melo 		err = dso__load_vmlinux_path(self, map, filter);
1834a19afe46SArnaldo Carvalho de Melo 		if (err > 0)
1835cc612d81SArnaldo Carvalho de Melo 			goto out_fixup;
1836cc612d81SArnaldo Carvalho de Melo 	}
1837cc612d81SArnaldo Carvalho de Melo 
1838b7cece76SArnaldo Carvalho de Melo 	/*
1839b7cece76SArnaldo Carvalho de Melo 	 * Say the kernel DSO was created when processing the build-id header table,
1840b7cece76SArnaldo Carvalho de Melo 	 * we have a build-id, so check if it is the same as the running kernel,
1841b7cece76SArnaldo Carvalho de Melo 	 * using it if it is.
1842b7cece76SArnaldo Carvalho de Melo 	 */
1843b7cece76SArnaldo Carvalho de Melo 	if (self->has_build_id) {
1844b7cece76SArnaldo Carvalho de Melo 		u8 kallsyms_build_id[BUILD_ID_SIZE];
18459e201442SArnaldo Carvalho de Melo 		char sbuild_id[BUILD_ID_SIZE * 2 + 1];
1846b7cece76SArnaldo Carvalho de Melo 
1847b7cece76SArnaldo Carvalho de Melo 		if (sysfs__read_build_id("/sys/kernel/notes", kallsyms_build_id,
18488d0591f6SArnaldo Carvalho de Melo 					 sizeof(kallsyms_build_id)) == 0) {
18499e201442SArnaldo Carvalho de Melo 			if (dso__build_id_equal(self, kallsyms_build_id)) {
18509e201442SArnaldo Carvalho de Melo 				kallsyms_filename = "/proc/kallsyms";
1851b7cece76SArnaldo Carvalho de Melo 				goto do_kallsyms;
18528d0591f6SArnaldo Carvalho de Melo 			}
18539e201442SArnaldo Carvalho de Melo 		}
1854dc8d6ab2SArnaldo Carvalho de Melo 		/*
1855dc8d6ab2SArnaldo Carvalho de Melo 		 * Now look if we have it on the build-id cache in
1856dc8d6ab2SArnaldo Carvalho de Melo 		 * $HOME/.debug/[kernel.kallsyms].
1857dc8d6ab2SArnaldo Carvalho de Melo 		 */
18589e201442SArnaldo Carvalho de Melo 		build_id__sprintf(self->build_id, sizeof(self->build_id),
18599e201442SArnaldo Carvalho de Melo 				  sbuild_id);
18609e201442SArnaldo Carvalho de Melo 
18619e201442SArnaldo Carvalho de Melo 		if (asprintf(&kallsyms_allocated_filename,
18629e201442SArnaldo Carvalho de Melo 			     "%s/.debug/[kernel.kallsyms]/%s",
18633846df2eSArnaldo Carvalho de Melo 			     getenv("HOME"), sbuild_id) == -1) {
18643846df2eSArnaldo Carvalho de Melo 			pr_err("Not enough memory for kallsyms file lookup\n");
18658d0591f6SArnaldo Carvalho de Melo 			return -1;
18663846df2eSArnaldo Carvalho de Melo 		}
18678d0591f6SArnaldo Carvalho de Melo 
186819fc2dedSArnaldo Carvalho de Melo 		kallsyms_filename = kallsyms_allocated_filename;
186919fc2dedSArnaldo Carvalho de Melo 
1870dc8d6ab2SArnaldo Carvalho de Melo 		if (access(kallsyms_filename, F_OK)) {
18713846df2eSArnaldo Carvalho de Melo 			pr_err("No kallsyms or vmlinux with build-id %s "
18723846df2eSArnaldo Carvalho de Melo 			       "was found\n", sbuild_id);
18739e201442SArnaldo Carvalho de Melo 			free(kallsyms_allocated_filename);
1874dc8d6ab2SArnaldo Carvalho de Melo 			return -1;
1875ef6ae724SArnaldo Carvalho de Melo 		}
1876dc8d6ab2SArnaldo Carvalho de Melo 	} else {
1877dc8d6ab2SArnaldo Carvalho de Melo 		/*
1878dc8d6ab2SArnaldo Carvalho de Melo 		 * Last resort, if we don't have a build-id and couldn't find
1879dc8d6ab2SArnaldo Carvalho de Melo 		 * any vmlinux file, try the running kernel kallsyms table.
1880dc8d6ab2SArnaldo Carvalho de Melo 		 */
1881dc8d6ab2SArnaldo Carvalho de Melo 		kallsyms_filename = "/proc/kallsyms";
1882dc8d6ab2SArnaldo Carvalho de Melo 	}
1883dc8d6ab2SArnaldo Carvalho de Melo 
1884dc8d6ab2SArnaldo Carvalho de Melo do_kallsyms:
18859de89fe7SArnaldo Carvalho de Melo 	err = dso__load_kallsyms(self, kallsyms_filename, map, filter);
18863846df2eSArnaldo Carvalho de Melo 	if (err > 0)
18873846df2eSArnaldo Carvalho de Melo 		pr_debug("Using %s for symbols\n", kallsyms_filename);
1888dc8d6ab2SArnaldo Carvalho de Melo 	free(kallsyms_allocated_filename);
1889dc8d6ab2SArnaldo Carvalho de Melo 
1890439d473bSArnaldo Carvalho de Melo 	if (err > 0) {
1891cc612d81SArnaldo Carvalho de Melo out_fixup:
1892e1c7c6a4SArnaldo Carvalho de Melo 		if (kallsyms_filename != NULL)
1893dc8d6ab2SArnaldo Carvalho de Melo 			dso__set_long_name(self, strdup("[kernel.kallsyms]"));
18946a4694a4SArnaldo Carvalho de Melo 		map__fixup_start(map);
18956a4694a4SArnaldo Carvalho de Melo 		map__fixup_end(map);
1896439d473bSArnaldo Carvalho de Melo 	}
189794cb9e38SArnaldo Carvalho de Melo 
189886470930SIngo Molnar 	return err;
189986470930SIngo Molnar }
190086470930SIngo Molnar 
1901a1645ce1SZhang, Yanmin static int dso__load_guest_kernel_sym(struct dso *self, struct map *map,
1902a1645ce1SZhang, Yanmin 				symbol_filter_t filter)
1903a1645ce1SZhang, Yanmin {
1904a1645ce1SZhang, Yanmin 	int err;
1905a1645ce1SZhang, Yanmin 	const char *kallsyms_filename = NULL;
190623346f21SArnaldo Carvalho de Melo 	struct machine *machine;
1907a1645ce1SZhang, Yanmin 	char path[PATH_MAX];
1908a1645ce1SZhang, Yanmin 
1909a1645ce1SZhang, Yanmin 	if (!map->groups) {
1910a1645ce1SZhang, Yanmin 		pr_debug("Guest kernel map hasn't the point to groups\n");
1911a1645ce1SZhang, Yanmin 		return -1;
1912a1645ce1SZhang, Yanmin 	}
191323346f21SArnaldo Carvalho de Melo 	machine = map->groups->machine;
1914a1645ce1SZhang, Yanmin 
191523346f21SArnaldo Carvalho de Melo 	if (machine__is_default_guest(machine)) {
1916a1645ce1SZhang, Yanmin 		/*
1917a1645ce1SZhang, Yanmin 		 * if the user specified a vmlinux filename, use it and only
1918a1645ce1SZhang, Yanmin 		 * it, reporting errors to the user if it cannot be used.
1919a1645ce1SZhang, Yanmin 		 * Or use file guest_kallsyms inputted by user on commandline
1920a1645ce1SZhang, Yanmin 		 */
1921a1645ce1SZhang, Yanmin 		if (symbol_conf.default_guest_vmlinux_name != NULL) {
1922a1645ce1SZhang, Yanmin 			err = dso__load_vmlinux(self, map,
1923a1645ce1SZhang, Yanmin 				symbol_conf.default_guest_vmlinux_name, filter);
1924a1645ce1SZhang, Yanmin 			goto out_try_fixup;
1925a1645ce1SZhang, Yanmin 		}
1926a1645ce1SZhang, Yanmin 
1927a1645ce1SZhang, Yanmin 		kallsyms_filename = symbol_conf.default_guest_kallsyms;
1928a1645ce1SZhang, Yanmin 		if (!kallsyms_filename)
1929a1645ce1SZhang, Yanmin 			return -1;
1930a1645ce1SZhang, Yanmin 	} else {
193123346f21SArnaldo Carvalho de Melo 		sprintf(path, "%s/proc/kallsyms", machine->root_dir);
1932a1645ce1SZhang, Yanmin 		kallsyms_filename = path;
1933a1645ce1SZhang, Yanmin 	}
1934a1645ce1SZhang, Yanmin 
1935a1645ce1SZhang, Yanmin 	err = dso__load_kallsyms(self, kallsyms_filename, map, filter);
1936a1645ce1SZhang, Yanmin 	if (err > 0)
1937a1645ce1SZhang, Yanmin 		pr_debug("Using %s for symbols\n", kallsyms_filename);
1938a1645ce1SZhang, Yanmin 
1939a1645ce1SZhang, Yanmin out_try_fixup:
1940a1645ce1SZhang, Yanmin 	if (err > 0) {
1941a1645ce1SZhang, Yanmin 		if (kallsyms_filename != NULL) {
194248ea8f54SArnaldo Carvalho de Melo 			machine__mmap_name(machine, path, sizeof(path));
194323346f21SArnaldo Carvalho de Melo 			dso__set_long_name(self, strdup(path));
1944a1645ce1SZhang, Yanmin 		}
1945a1645ce1SZhang, Yanmin 		map__fixup_start(map);
1946a1645ce1SZhang, Yanmin 		map__fixup_end(map);
1947a1645ce1SZhang, Yanmin 	}
1948a1645ce1SZhang, Yanmin 
1949a1645ce1SZhang, Yanmin 	return err;
1950a1645ce1SZhang, Yanmin }
1951cd84c2acSFrederic Weisbecker 
1952b0da954aSArnaldo Carvalho de Melo static void dsos__add(struct list_head *head, struct dso *dso)
1953cd84c2acSFrederic Weisbecker {
1954b0da954aSArnaldo Carvalho de Melo 	list_add_tail(&dso->node, head);
1955cd84c2acSFrederic Weisbecker }
1956cd84c2acSFrederic Weisbecker 
1957b0da954aSArnaldo Carvalho de Melo static struct dso *dsos__find(struct list_head *head, const char *name)
1958cd84c2acSFrederic Weisbecker {
1959cd84c2acSFrederic Weisbecker 	struct dso *pos;
1960cd84c2acSFrederic Weisbecker 
1961b0da954aSArnaldo Carvalho de Melo 	list_for_each_entry(pos, head, node)
1962cf4e5b08SArnaldo Carvalho de Melo 		if (strcmp(pos->long_name, name) == 0)
1963cd84c2acSFrederic Weisbecker 			return pos;
1964cd84c2acSFrederic Weisbecker 	return NULL;
1965cd84c2acSFrederic Weisbecker }
1966cd84c2acSFrederic Weisbecker 
1967a89e5abeSArnaldo Carvalho de Melo struct dso *__dsos__findnew(struct list_head *head, const char *name)
1968cd84c2acSFrederic Weisbecker {
1969a89e5abeSArnaldo Carvalho de Melo 	struct dso *dso = dsos__find(head, name);
1970cd84c2acSFrederic Weisbecker 
1971e4204992SArnaldo Carvalho de Melo 	if (!dso) {
197200a192b3SArnaldo Carvalho de Melo 		dso = dso__new(name);
1973cfc10d3bSArnaldo Carvalho de Melo 		if (dso != NULL) {
1974a89e5abeSArnaldo Carvalho de Melo 			dsos__add(head, dso);
1975cfc10d3bSArnaldo Carvalho de Melo 			dso__set_basename(dso);
1976cfc10d3bSArnaldo Carvalho de Melo 		}
1977e4204992SArnaldo Carvalho de Melo 	}
1978cd84c2acSFrederic Weisbecker 
1979cd84c2acSFrederic Weisbecker 	return dso;
1980cd84c2acSFrederic Weisbecker }
1981cd84c2acSFrederic Weisbecker 
19821f626bc3SArnaldo Carvalho de Melo size_t __dsos__fprintf(struct list_head *head, FILE *fp)
1983cd84c2acSFrederic Weisbecker {
1984cd84c2acSFrederic Weisbecker 	struct dso *pos;
1985cbf69680SArnaldo Carvalho de Melo 	size_t ret = 0;
1986cd84c2acSFrederic Weisbecker 
198795011c60SArnaldo Carvalho de Melo 	list_for_each_entry(pos, head, node) {
198895011c60SArnaldo Carvalho de Melo 		int i;
198995011c60SArnaldo Carvalho de Melo 		for (i = 0; i < MAP__NR_TYPES; ++i)
1990cbf69680SArnaldo Carvalho de Melo 			ret += dso__fprintf(pos, i, fp);
1991cd84c2acSFrederic Weisbecker 	}
1992cd84c2acSFrederic Weisbecker 
1993cbf69680SArnaldo Carvalho de Melo 	return ret;
1994cbf69680SArnaldo Carvalho de Melo }
1995cbf69680SArnaldo Carvalho de Melo 
1996cbf69680SArnaldo Carvalho de Melo size_t machines__fprintf_dsos(struct rb_root *self, FILE *fp)
1997b0da954aSArnaldo Carvalho de Melo {
1998a1645ce1SZhang, Yanmin 	struct rb_node *nd;
1999cbf69680SArnaldo Carvalho de Melo 	size_t ret = 0;
2000a1645ce1SZhang, Yanmin 
2001cbf69680SArnaldo Carvalho de Melo 	for (nd = rb_first(self); nd; nd = rb_next(nd)) {
200223346f21SArnaldo Carvalho de Melo 		struct machine *pos = rb_entry(nd, struct machine, rb_node);
2003cbf69680SArnaldo Carvalho de Melo 		ret += __dsos__fprintf(&pos->kernel_dsos, fp);
2004cbf69680SArnaldo Carvalho de Melo 		ret += __dsos__fprintf(&pos->user_dsos, fp);
2005a1645ce1SZhang, Yanmin 	}
2006cbf69680SArnaldo Carvalho de Melo 
2007cbf69680SArnaldo Carvalho de Melo 	return ret;
2008b0da954aSArnaldo Carvalho de Melo }
2009b0da954aSArnaldo Carvalho de Melo 
201088d3d9b7SArnaldo Carvalho de Melo static size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp,
201188d3d9b7SArnaldo Carvalho de Melo 				      bool with_hits)
20129e03eb2dSArnaldo Carvalho de Melo {
20139e03eb2dSArnaldo Carvalho de Melo 	struct dso *pos;
20149e03eb2dSArnaldo Carvalho de Melo 	size_t ret = 0;
20159e03eb2dSArnaldo Carvalho de Melo 
2016b0da954aSArnaldo Carvalho de Melo 	list_for_each_entry(pos, head, node) {
201788d3d9b7SArnaldo Carvalho de Melo 		if (with_hits && !pos->hit)
201888d3d9b7SArnaldo Carvalho de Melo 			continue;
20199e03eb2dSArnaldo Carvalho de Melo 		ret += dso__fprintf_buildid(pos, fp);
20209e03eb2dSArnaldo Carvalho de Melo 		ret += fprintf(fp, " %s\n", pos->long_name);
20219e03eb2dSArnaldo Carvalho de Melo 	}
20229e03eb2dSArnaldo Carvalho de Melo 	return ret;
20239e03eb2dSArnaldo Carvalho de Melo }
20249e03eb2dSArnaldo Carvalho de Melo 
2025f869097eSArnaldo Carvalho de Melo size_t machine__fprintf_dsos_buildid(struct machine *self, FILE *fp, bool with_hits)
2026f869097eSArnaldo Carvalho de Melo {
2027f869097eSArnaldo Carvalho de Melo 	return __dsos__fprintf_buildid(&self->kernel_dsos, fp, with_hits) +
2028f869097eSArnaldo Carvalho de Melo 	       __dsos__fprintf_buildid(&self->user_dsos, fp, with_hits);
2029f869097eSArnaldo Carvalho de Melo }
2030f869097eSArnaldo Carvalho de Melo 
2031cbf69680SArnaldo Carvalho de Melo size_t machines__fprintf_dsos_buildid(struct rb_root *self, FILE *fp, bool with_hits)
2032b0da954aSArnaldo Carvalho de Melo {
2033a1645ce1SZhang, Yanmin 	struct rb_node *nd;
2034a1645ce1SZhang, Yanmin 	size_t ret = 0;
2035a1645ce1SZhang, Yanmin 
2036cbf69680SArnaldo Carvalho de Melo 	for (nd = rb_first(self); nd; nd = rb_next(nd)) {
203723346f21SArnaldo Carvalho de Melo 		struct machine *pos = rb_entry(nd, struct machine, rb_node);
2038f869097eSArnaldo Carvalho de Melo 		ret += machine__fprintf_dsos_buildid(pos, fp, with_hits);
2039a1645ce1SZhang, Yanmin 	}
2040a1645ce1SZhang, Yanmin 	return ret;
2041b0da954aSArnaldo Carvalho de Melo }
2042b0da954aSArnaldo Carvalho de Melo 
2043fd1d908cSArnaldo Carvalho de Melo struct dso *dso__new_kernel(const char *name)
2044fd1d908cSArnaldo Carvalho de Melo {
2045fd1d908cSArnaldo Carvalho de Melo 	struct dso *self = dso__new(name ?: "[kernel.kallsyms]");
2046fd1d908cSArnaldo Carvalho de Melo 
2047fd1d908cSArnaldo Carvalho de Melo 	if (self != NULL) {
2048b63be8d7SArnaldo Carvalho de Melo 		dso__set_short_name(self, "[kernel]");
2049a1645ce1SZhang, Yanmin 		self->kernel = DSO_TYPE_KERNEL;
2050fd1d908cSArnaldo Carvalho de Melo 	}
2051fd1d908cSArnaldo Carvalho de Melo 
2052fd1d908cSArnaldo Carvalho de Melo 	return self;
2053fd1d908cSArnaldo Carvalho de Melo }
2054fd1d908cSArnaldo Carvalho de Melo 
205523346f21SArnaldo Carvalho de Melo static struct dso *dso__new_guest_kernel(struct machine *machine,
2056a1645ce1SZhang, Yanmin 					const char *name)
2057fd1d908cSArnaldo Carvalho de Melo {
205848ea8f54SArnaldo Carvalho de Melo 	char bf[PATH_MAX];
205948ea8f54SArnaldo Carvalho de Melo 	struct dso *self = dso__new(name ?: machine__mmap_name(machine, bf, sizeof(bf)));
2060a1645ce1SZhang, Yanmin 
2061a1645ce1SZhang, Yanmin 	if (self != NULL) {
2062a1645ce1SZhang, Yanmin 		dso__set_short_name(self, "[guest.kernel]");
2063a1645ce1SZhang, Yanmin 		self->kernel = DSO_TYPE_GUEST_KERNEL;
2064a1645ce1SZhang, Yanmin 	}
2065a1645ce1SZhang, Yanmin 
2066a1645ce1SZhang, Yanmin 	return self;
2067a1645ce1SZhang, Yanmin }
2068a1645ce1SZhang, Yanmin 
206923346f21SArnaldo Carvalho de Melo void dso__read_running_kernel_build_id(struct dso *self, struct machine *machine)
2070a1645ce1SZhang, Yanmin {
2071a1645ce1SZhang, Yanmin 	char path[PATH_MAX];
2072a1645ce1SZhang, Yanmin 
207323346f21SArnaldo Carvalho de Melo 	if (machine__is_default_guest(machine))
2074a1645ce1SZhang, Yanmin 		return;
207523346f21SArnaldo Carvalho de Melo 	sprintf(path, "%s/sys/kernel/notes", machine->root_dir);
2076a1645ce1SZhang, Yanmin 	if (sysfs__read_build_id(path, self->build_id,
2077fd1d908cSArnaldo Carvalho de Melo 				 sizeof(self->build_id)) == 0)
2078fd1d908cSArnaldo Carvalho de Melo 		self->has_build_id = true;
2079fd1d908cSArnaldo Carvalho de Melo }
2080fd1d908cSArnaldo Carvalho de Melo 
20815c0541d5SArnaldo Carvalho de Melo static struct dso *machine__create_kernel(struct machine *self)
2082cd84c2acSFrederic Weisbecker {
2083a1645ce1SZhang, Yanmin 	const char *vmlinux_name = NULL;
2084a1645ce1SZhang, Yanmin 	struct dso *kernel;
2085cd84c2acSFrederic Weisbecker 
20865c0541d5SArnaldo Carvalho de Melo 	if (machine__is_host(self)) {
2087a1645ce1SZhang, Yanmin 		vmlinux_name = symbol_conf.vmlinux_name;
2088a1645ce1SZhang, Yanmin 		kernel = dso__new_kernel(vmlinux_name);
2089a1645ce1SZhang, Yanmin 	} else {
20905c0541d5SArnaldo Carvalho de Melo 		if (machine__is_default_guest(self))
2091a1645ce1SZhang, Yanmin 			vmlinux_name = symbol_conf.default_guest_vmlinux_name;
20925c0541d5SArnaldo Carvalho de Melo 		kernel = dso__new_guest_kernel(self, vmlinux_name);
20938d92c02aSArnaldo Carvalho de Melo 	}
2094cd84c2acSFrederic Weisbecker 
2095a1645ce1SZhang, Yanmin 	if (kernel != NULL) {
20965c0541d5SArnaldo Carvalho de Melo 		dso__read_running_kernel_build_id(kernel, self);
20975c0541d5SArnaldo Carvalho de Melo 		dsos__add(&self->kernel_dsos, kernel);
2098a1645ce1SZhang, Yanmin 	}
2099f1dfa0b1SArnaldo Carvalho de Melo 	return kernel;
2100f1dfa0b1SArnaldo Carvalho de Melo }
2101f1dfa0b1SArnaldo Carvalho de Melo 
2102d28c6223SArnaldo Carvalho de Melo int __machine__create_kernel_maps(struct machine *self, struct dso *kernel)
2103f1dfa0b1SArnaldo Carvalho de Melo {
2104de176489SArnaldo Carvalho de Melo 	enum map_type type;
2105f1dfa0b1SArnaldo Carvalho de Melo 
2106de176489SArnaldo Carvalho de Melo 	for (type = 0; type < MAP__NR_TYPES; ++type) {
21079de89fe7SArnaldo Carvalho de Melo 		struct kmap *kmap;
21089de89fe7SArnaldo Carvalho de Melo 
2109d28c6223SArnaldo Carvalho de Melo 		self->vmlinux_maps[type] = map__new2(0, kernel, type);
2110d28c6223SArnaldo Carvalho de Melo 		if (self->vmlinux_maps[type] == NULL)
2111f1dfa0b1SArnaldo Carvalho de Melo 			return -1;
2112f1dfa0b1SArnaldo Carvalho de Melo 
2113d28c6223SArnaldo Carvalho de Melo 		self->vmlinux_maps[type]->map_ip =
2114d28c6223SArnaldo Carvalho de Melo 			self->vmlinux_maps[type]->unmap_ip = identity__map_ip;
21159de89fe7SArnaldo Carvalho de Melo 
2116d28c6223SArnaldo Carvalho de Melo 		kmap = map__kmap(self->vmlinux_maps[type]);
2117d28c6223SArnaldo Carvalho de Melo 		kmap->kmaps = &self->kmaps;
2118d28c6223SArnaldo Carvalho de Melo 		map_groups__insert(&self->kmaps, self->vmlinux_maps[type]);
2119f1dfa0b1SArnaldo Carvalho de Melo 	}
2120f1dfa0b1SArnaldo Carvalho de Melo 
2121f1dfa0b1SArnaldo Carvalho de Melo 	return 0;
21222446042cSArnaldo Carvalho de Melo }
21232446042cSArnaldo Carvalho de Melo 
2124076c6e45SArnaldo Carvalho de Melo void machine__destroy_kernel_maps(struct machine *self)
2125076c6e45SArnaldo Carvalho de Melo {
2126076c6e45SArnaldo Carvalho de Melo 	enum map_type type;
2127076c6e45SArnaldo Carvalho de Melo 
2128076c6e45SArnaldo Carvalho de Melo 	for (type = 0; type < MAP__NR_TYPES; ++type) {
2129076c6e45SArnaldo Carvalho de Melo 		struct kmap *kmap;
2130076c6e45SArnaldo Carvalho de Melo 
2131076c6e45SArnaldo Carvalho de Melo 		if (self->vmlinux_maps[type] == NULL)
2132076c6e45SArnaldo Carvalho de Melo 			continue;
2133076c6e45SArnaldo Carvalho de Melo 
2134076c6e45SArnaldo Carvalho de Melo 		kmap = map__kmap(self->vmlinux_maps[type]);
2135076c6e45SArnaldo Carvalho de Melo 		map_groups__remove(&self->kmaps, self->vmlinux_maps[type]);
2136076c6e45SArnaldo Carvalho de Melo 		if (kmap->ref_reloc_sym) {
2137076c6e45SArnaldo Carvalho de Melo 			/*
2138076c6e45SArnaldo Carvalho de Melo 			 * ref_reloc_sym is shared among all maps, so free just
2139076c6e45SArnaldo Carvalho de Melo 			 * on one of them.
2140076c6e45SArnaldo Carvalho de Melo 			 */
2141076c6e45SArnaldo Carvalho de Melo 			if (type == MAP__FUNCTION) {
2142076c6e45SArnaldo Carvalho de Melo 				free((char *)kmap->ref_reloc_sym->name);
2143076c6e45SArnaldo Carvalho de Melo 				kmap->ref_reloc_sym->name = NULL;
2144076c6e45SArnaldo Carvalho de Melo 				free(kmap->ref_reloc_sym);
2145076c6e45SArnaldo Carvalho de Melo 			}
2146076c6e45SArnaldo Carvalho de Melo 			kmap->ref_reloc_sym = NULL;
2147076c6e45SArnaldo Carvalho de Melo 		}
2148076c6e45SArnaldo Carvalho de Melo 
2149076c6e45SArnaldo Carvalho de Melo 		map__delete(self->vmlinux_maps[type]);
2150076c6e45SArnaldo Carvalho de Melo 		self->vmlinux_maps[type] = NULL;
2151076c6e45SArnaldo Carvalho de Melo 	}
2152076c6e45SArnaldo Carvalho de Melo }
2153076c6e45SArnaldo Carvalho de Melo 
21545c0541d5SArnaldo Carvalho de Melo int machine__create_kernel_maps(struct machine *self)
21555c0541d5SArnaldo Carvalho de Melo {
21565c0541d5SArnaldo Carvalho de Melo 	struct dso *kernel = machine__create_kernel(self);
21575c0541d5SArnaldo Carvalho de Melo 
21585c0541d5SArnaldo Carvalho de Melo 	if (kernel == NULL ||
21595c0541d5SArnaldo Carvalho de Melo 	    __machine__create_kernel_maps(self, kernel) < 0)
21605c0541d5SArnaldo Carvalho de Melo 		return -1;
21615c0541d5SArnaldo Carvalho de Melo 
21625c0541d5SArnaldo Carvalho de Melo 	if (symbol_conf.use_modules && machine__create_modules(self) < 0)
21635c0541d5SArnaldo Carvalho de Melo 		pr_debug("Problems creating module maps, continuing anyway...\n");
21645c0541d5SArnaldo Carvalho de Melo 	/*
21655c0541d5SArnaldo Carvalho de Melo 	 * Now that we have all the maps created, just set the ->end of them:
21665c0541d5SArnaldo Carvalho de Melo 	 */
21675c0541d5SArnaldo Carvalho de Melo 	map_groups__fixup_end(&self->kmaps);
21685c0541d5SArnaldo Carvalho de Melo 	return 0;
21695c0541d5SArnaldo Carvalho de Melo }
21705c0541d5SArnaldo Carvalho de Melo 
2171cc612d81SArnaldo Carvalho de Melo static void vmlinux_path__exit(void)
21722446042cSArnaldo Carvalho de Melo {
2173cc612d81SArnaldo Carvalho de Melo 	while (--vmlinux_path__nr_entries >= 0) {
2174cc612d81SArnaldo Carvalho de Melo 		free(vmlinux_path[vmlinux_path__nr_entries]);
2175cc612d81SArnaldo Carvalho de Melo 		vmlinux_path[vmlinux_path__nr_entries] = NULL;
2176cc612d81SArnaldo Carvalho de Melo 	}
2177cc612d81SArnaldo Carvalho de Melo 
2178cc612d81SArnaldo Carvalho de Melo 	free(vmlinux_path);
2179cc612d81SArnaldo Carvalho de Melo 	vmlinux_path = NULL;
2180cc612d81SArnaldo Carvalho de Melo }
2181cc612d81SArnaldo Carvalho de Melo 
2182cc612d81SArnaldo Carvalho de Melo static int vmlinux_path__init(void)
2183cc612d81SArnaldo Carvalho de Melo {
2184cc612d81SArnaldo Carvalho de Melo 	struct utsname uts;
2185cc612d81SArnaldo Carvalho de Melo 	char bf[PATH_MAX];
2186cc612d81SArnaldo Carvalho de Melo 
2187cc612d81SArnaldo Carvalho de Melo 	if (uname(&uts) < 0)
21882446042cSArnaldo Carvalho de Melo 		return -1;
21892446042cSArnaldo Carvalho de Melo 
2190cc612d81SArnaldo Carvalho de Melo 	vmlinux_path = malloc(sizeof(char *) * 5);
2191cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path == NULL)
2192cc612d81SArnaldo Carvalho de Melo 		return -1;
2193cc612d81SArnaldo Carvalho de Melo 
2194cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup("vmlinux");
2195cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
2196cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
2197cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
2198cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup("/boot/vmlinux");
2199cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
2200cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
2201cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
2202cc612d81SArnaldo Carvalho de Melo 	snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", uts.release);
2203cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
2204cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
2205cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
2206cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
2207cc612d81SArnaldo Carvalho de Melo 	snprintf(bf, sizeof(bf), "/lib/modules/%s/build/vmlinux", uts.release);
2208cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
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), "/usr/lib/debug/lib/modules/%s/vmlinux",
2213cc612d81SArnaldo Carvalho de Melo 		 uts.release);
2214cc612d81SArnaldo Carvalho de Melo 	vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
2215cc612d81SArnaldo Carvalho de Melo 	if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
2216cc612d81SArnaldo Carvalho de Melo 		goto out_fail;
2217cc612d81SArnaldo Carvalho de Melo 	++vmlinux_path__nr_entries;
2218cc612d81SArnaldo Carvalho de Melo 
2219cc612d81SArnaldo Carvalho de Melo 	return 0;
2220cc612d81SArnaldo Carvalho de Melo 
2221cc612d81SArnaldo Carvalho de Melo out_fail:
2222cc612d81SArnaldo Carvalho de Melo 	vmlinux_path__exit();
2223cc612d81SArnaldo Carvalho de Melo 	return -1;
2224cc612d81SArnaldo Carvalho de Melo }
2225cc612d81SArnaldo Carvalho de Melo 
22265ad90e4eSArnaldo Carvalho de Melo size_t machine__fprintf_vmlinux_path(struct machine *self, FILE *fp)
2227b0a9ab62SArnaldo Carvalho de Melo {
2228b0a9ab62SArnaldo Carvalho de Melo 	int i;
2229b0a9ab62SArnaldo Carvalho de Melo 	size_t printed = 0;
22305ad90e4eSArnaldo Carvalho de Melo 	struct dso *kdso = self->vmlinux_maps[MAP__FUNCTION]->dso;
22315ad90e4eSArnaldo Carvalho de Melo 
22325ad90e4eSArnaldo Carvalho de Melo 	if (kdso->has_build_id) {
22335ad90e4eSArnaldo Carvalho de Melo 		char filename[PATH_MAX];
22345ad90e4eSArnaldo Carvalho de Melo 		if (dso__build_id_filename(kdso, filename, sizeof(filename)))
22355ad90e4eSArnaldo Carvalho de Melo 			printed += fprintf(fp, "[0] %s\n", filename);
22365ad90e4eSArnaldo Carvalho de Melo 	}
2237b0a9ab62SArnaldo Carvalho de Melo 
2238b0a9ab62SArnaldo Carvalho de Melo 	for (i = 0; i < vmlinux_path__nr_entries; ++i)
22395ad90e4eSArnaldo Carvalho de Melo 		printed += fprintf(fp, "[%d] %s\n",
22405ad90e4eSArnaldo Carvalho de Melo 				   i + kdso->has_build_id, vmlinux_path[i]);
2241b0a9ab62SArnaldo Carvalho de Melo 
2242b0a9ab62SArnaldo Carvalho de Melo 	return printed;
2243b0a9ab62SArnaldo Carvalho de Melo }
2244b0a9ab62SArnaldo Carvalho de Melo 
2245655000e7SArnaldo Carvalho de Melo static int setup_list(struct strlist **list, const char *list_str,
2246655000e7SArnaldo Carvalho de Melo 		      const char *list_name)
2247655000e7SArnaldo Carvalho de Melo {
2248655000e7SArnaldo Carvalho de Melo 	if (list_str == NULL)
2249655000e7SArnaldo Carvalho de Melo 		return 0;
2250655000e7SArnaldo Carvalho de Melo 
2251655000e7SArnaldo Carvalho de Melo 	*list = strlist__new(true, list_str);
2252655000e7SArnaldo Carvalho de Melo 	if (!*list) {
2253655000e7SArnaldo Carvalho de Melo 		pr_err("problems parsing %s list\n", list_name);
2254655000e7SArnaldo Carvalho de Melo 		return -1;
2255655000e7SArnaldo Carvalho de Melo 	}
2256655000e7SArnaldo Carvalho de Melo 	return 0;
2257655000e7SArnaldo Carvalho de Melo }
2258655000e7SArnaldo Carvalho de Melo 
225975be6cf4SArnaldo Carvalho de Melo int symbol__init(void)
2260cc612d81SArnaldo Carvalho de Melo {
226195011c60SArnaldo Carvalho de Melo 	elf_version(EV_CURRENT);
226275be6cf4SArnaldo Carvalho de Melo 	if (symbol_conf.sort_by_name)
226375be6cf4SArnaldo Carvalho de Melo 		symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) -
226479406cd7SArnaldo Carvalho de Melo 					  sizeof(struct symbol));
2265b32d133aSArnaldo Carvalho de Melo 
226675be6cf4SArnaldo Carvalho de Melo 	if (symbol_conf.try_vmlinux_path && vmlinux_path__init() < 0)
2267cc612d81SArnaldo Carvalho de Melo 		return -1;
2268cc612d81SArnaldo Carvalho de Melo 
2269c410a338SArnaldo Carvalho de Melo 	if (symbol_conf.field_sep && *symbol_conf.field_sep == '.') {
2270c410a338SArnaldo Carvalho de Melo 		pr_err("'.' is the only non valid --field-separator argument\n");
2271c410a338SArnaldo Carvalho de Melo 		return -1;
2272c410a338SArnaldo Carvalho de Melo 	}
2273c410a338SArnaldo Carvalho de Melo 
2274655000e7SArnaldo Carvalho de Melo 	if (setup_list(&symbol_conf.dso_list,
2275655000e7SArnaldo Carvalho de Melo 		       symbol_conf.dso_list_str, "dso") < 0)
2276655000e7SArnaldo Carvalho de Melo 		return -1;
2277655000e7SArnaldo Carvalho de Melo 
2278655000e7SArnaldo Carvalho de Melo 	if (setup_list(&symbol_conf.comm_list,
2279655000e7SArnaldo Carvalho de Melo 		       symbol_conf.comm_list_str, "comm") < 0)
2280655000e7SArnaldo Carvalho de Melo 		goto out_free_dso_list;
2281655000e7SArnaldo Carvalho de Melo 
2282655000e7SArnaldo Carvalho de Melo 	if (setup_list(&symbol_conf.sym_list,
2283655000e7SArnaldo Carvalho de Melo 		       symbol_conf.sym_list_str, "symbol") < 0)
2284655000e7SArnaldo Carvalho de Melo 		goto out_free_comm_list;
2285655000e7SArnaldo Carvalho de Melo 
22864aa65636SArnaldo Carvalho de Melo 	return 0;
2287655000e7SArnaldo Carvalho de Melo 
2288655000e7SArnaldo Carvalho de Melo out_free_dso_list:
2289655000e7SArnaldo Carvalho de Melo 	strlist__delete(symbol_conf.dso_list);
2290655000e7SArnaldo Carvalho de Melo out_free_comm_list:
2291655000e7SArnaldo Carvalho de Melo 	strlist__delete(symbol_conf.comm_list);
2292655000e7SArnaldo Carvalho de Melo 	return -1;
2293cc612d81SArnaldo Carvalho de Melo }
2294cc612d81SArnaldo Carvalho de Melo 
2295d65a458bSArnaldo Carvalho de Melo void symbol__exit(void)
2296d65a458bSArnaldo Carvalho de Melo {
2297d65a458bSArnaldo Carvalho de Melo 	strlist__delete(symbol_conf.sym_list);
2298d65a458bSArnaldo Carvalho de Melo 	strlist__delete(symbol_conf.dso_list);
2299d65a458bSArnaldo Carvalho de Melo 	strlist__delete(symbol_conf.comm_list);
2300d65a458bSArnaldo Carvalho de Melo 	vmlinux_path__exit();
2301d65a458bSArnaldo Carvalho de Melo 	symbol_conf.sym_list = symbol_conf.dso_list = symbol_conf.comm_list = NULL;
2302d65a458bSArnaldo Carvalho de Melo }
2303d65a458bSArnaldo Carvalho de Melo 
2304d28c6223SArnaldo Carvalho de Melo int machines__create_kernel_maps(struct rb_root *self, pid_t pid)
23054aa65636SArnaldo Carvalho de Melo {
2306d28c6223SArnaldo Carvalho de Melo 	struct machine *machine = machines__findnew(self, pid);
23079de89fe7SArnaldo Carvalho de Melo 
230823346f21SArnaldo Carvalho de Melo 	if (machine == NULL)
2309a1645ce1SZhang, Yanmin 		return -1;
23104aa65636SArnaldo Carvalho de Melo 
23115c0541d5SArnaldo Carvalho de Melo 	return machine__create_kernel_maps(machine);
2312cd84c2acSFrederic Weisbecker }
23135aab621bSArnaldo Carvalho de Melo 
23145aab621bSArnaldo Carvalho de Melo static int hex(char ch)
23155aab621bSArnaldo Carvalho de Melo {
23165aab621bSArnaldo Carvalho de Melo 	if ((ch >= '0') && (ch <= '9'))
23175aab621bSArnaldo Carvalho de Melo 		return ch - '0';
23185aab621bSArnaldo Carvalho de Melo 	if ((ch >= 'a') && (ch <= 'f'))
23195aab621bSArnaldo Carvalho de Melo 		return ch - 'a' + 10;
23205aab621bSArnaldo Carvalho de Melo 	if ((ch >= 'A') && (ch <= 'F'))
23215aab621bSArnaldo Carvalho de Melo 		return ch - 'A' + 10;
23225aab621bSArnaldo Carvalho de Melo 	return -1;
23235aab621bSArnaldo Carvalho de Melo }
23245aab621bSArnaldo Carvalho de Melo 
23255aab621bSArnaldo Carvalho de Melo /*
23265aab621bSArnaldo Carvalho de Melo  * While we find nice hex chars, build a long_val.
23275aab621bSArnaldo Carvalho de Melo  * Return number of chars processed.
23285aab621bSArnaldo Carvalho de Melo  */
23295aab621bSArnaldo Carvalho de Melo int hex2u64(const char *ptr, u64 *long_val)
23305aab621bSArnaldo Carvalho de Melo {
23315aab621bSArnaldo Carvalho de Melo 	const char *p = ptr;
23325aab621bSArnaldo Carvalho de Melo 	*long_val = 0;
23335aab621bSArnaldo Carvalho de Melo 
23345aab621bSArnaldo Carvalho de Melo 	while (*p) {
23355aab621bSArnaldo Carvalho de Melo 		const int hex_val = hex(*p);
23365aab621bSArnaldo Carvalho de Melo 
23375aab621bSArnaldo Carvalho de Melo 		if (hex_val < 0)
23385aab621bSArnaldo Carvalho de Melo 			break;
23395aab621bSArnaldo Carvalho de Melo 
23405aab621bSArnaldo Carvalho de Melo 		*long_val = (*long_val << 4) | hex_val;
23415aab621bSArnaldo Carvalho de Melo 		p++;
23425aab621bSArnaldo Carvalho de Melo 	}
23435aab621bSArnaldo Carvalho de Melo 
23445aab621bSArnaldo Carvalho de Melo 	return p - ptr;
23455aab621bSArnaldo Carvalho de Melo }
23465aab621bSArnaldo Carvalho de Melo 
23475aab621bSArnaldo Carvalho de Melo char *strxfrchar(char *s, char from, char to)
23485aab621bSArnaldo Carvalho de Melo {
23495aab621bSArnaldo Carvalho de Melo 	char *p = s;
23505aab621bSArnaldo Carvalho de Melo 
23515aab621bSArnaldo Carvalho de Melo 	while ((p = strchr(p, from)) != NULL)
23525aab621bSArnaldo Carvalho de Melo 		*p++ = to;
23535aab621bSArnaldo Carvalho de Melo 
23545aab621bSArnaldo Carvalho de Melo 	return s;
23555aab621bSArnaldo Carvalho de Melo }
2356a1645ce1SZhang, Yanmin 
2357d28c6223SArnaldo Carvalho de Melo int machines__create_guest_kernel_maps(struct rb_root *self)
2358a1645ce1SZhang, Yanmin {
2359a1645ce1SZhang, Yanmin 	int ret = 0;
2360a1645ce1SZhang, Yanmin 	struct dirent **namelist = NULL;
2361a1645ce1SZhang, Yanmin 	int i, items = 0;
2362a1645ce1SZhang, Yanmin 	char path[PATH_MAX];
2363a1645ce1SZhang, Yanmin 	pid_t pid;
2364a1645ce1SZhang, Yanmin 
2365a1645ce1SZhang, Yanmin 	if (symbol_conf.default_guest_vmlinux_name ||
2366a1645ce1SZhang, Yanmin 	    symbol_conf.default_guest_modules ||
2367a1645ce1SZhang, Yanmin 	    symbol_conf.default_guest_kallsyms) {
2368d28c6223SArnaldo Carvalho de Melo 		machines__create_kernel_maps(self, DEFAULT_GUEST_KERNEL_ID);
2369a1645ce1SZhang, Yanmin 	}
2370a1645ce1SZhang, Yanmin 
2371a1645ce1SZhang, Yanmin 	if (symbol_conf.guestmount) {
2372a1645ce1SZhang, Yanmin 		items = scandir(symbol_conf.guestmount, &namelist, NULL, NULL);
2373a1645ce1SZhang, Yanmin 		if (items <= 0)
2374a1645ce1SZhang, Yanmin 			return -ENOENT;
2375a1645ce1SZhang, Yanmin 		for (i = 0; i < items; i++) {
2376a1645ce1SZhang, Yanmin 			if (!isdigit(namelist[i]->d_name[0])) {
2377a1645ce1SZhang, Yanmin 				/* Filter out . and .. */
2378a1645ce1SZhang, Yanmin 				continue;
2379a1645ce1SZhang, Yanmin 			}
2380a1645ce1SZhang, Yanmin 			pid = atoi(namelist[i]->d_name);
2381a1645ce1SZhang, Yanmin 			sprintf(path, "%s/%s/proc/kallsyms",
2382a1645ce1SZhang, Yanmin 				symbol_conf.guestmount,
2383a1645ce1SZhang, Yanmin 				namelist[i]->d_name);
2384a1645ce1SZhang, Yanmin 			ret = access(path, R_OK);
2385a1645ce1SZhang, Yanmin 			if (ret) {
2386a1645ce1SZhang, Yanmin 				pr_debug("Can't access file %s\n", path);
2387a1645ce1SZhang, Yanmin 				goto failure;
2388a1645ce1SZhang, Yanmin 			}
2389d28c6223SArnaldo Carvalho de Melo 			machines__create_kernel_maps(self, pid);
2390a1645ce1SZhang, Yanmin 		}
2391a1645ce1SZhang, Yanmin failure:
2392a1645ce1SZhang, Yanmin 		free(namelist);
2393a1645ce1SZhang, Yanmin 	}
2394a1645ce1SZhang, Yanmin 
2395a1645ce1SZhang, Yanmin 	return ret;
2396a1645ce1SZhang, Yanmin }
23975c0541d5SArnaldo Carvalho de Melo 
2398076c6e45SArnaldo Carvalho de Melo void machines__destroy_guest_kernel_maps(struct rb_root *self)
2399076c6e45SArnaldo Carvalho de Melo {
2400076c6e45SArnaldo Carvalho de Melo 	struct rb_node *next = rb_first(self);
2401076c6e45SArnaldo Carvalho de Melo 
2402076c6e45SArnaldo Carvalho de Melo 	while (next) {
2403076c6e45SArnaldo Carvalho de Melo 		struct machine *pos = rb_entry(next, struct machine, rb_node);
2404076c6e45SArnaldo Carvalho de Melo 
2405076c6e45SArnaldo Carvalho de Melo 		next = rb_next(&pos->rb_node);
2406076c6e45SArnaldo Carvalho de Melo 		rb_erase(&pos->rb_node, self);
2407076c6e45SArnaldo Carvalho de Melo 		machine__delete(pos);
2408076c6e45SArnaldo Carvalho de Melo 	}
2409076c6e45SArnaldo Carvalho de Melo }
2410076c6e45SArnaldo Carvalho de Melo 
24115c0541d5SArnaldo Carvalho de Melo int machine__load_kallsyms(struct machine *self, const char *filename,
24125c0541d5SArnaldo Carvalho de Melo 			   enum map_type type, symbol_filter_t filter)
24135c0541d5SArnaldo Carvalho de Melo {
24145c0541d5SArnaldo Carvalho de Melo 	struct map *map = self->vmlinux_maps[type];
24155c0541d5SArnaldo Carvalho de Melo 	int ret = dso__load_kallsyms(map->dso, filename, map, filter);
24165c0541d5SArnaldo Carvalho de Melo 
24175c0541d5SArnaldo Carvalho de Melo 	if (ret > 0) {
24185c0541d5SArnaldo Carvalho de Melo 		dso__set_loaded(map->dso, type);
24195c0541d5SArnaldo Carvalho de Melo 		/*
24205c0541d5SArnaldo Carvalho de Melo 		 * Since /proc/kallsyms will have multiple sessions for the
24215c0541d5SArnaldo Carvalho de Melo 		 * kernel, with modules between them, fixup the end of all
24225c0541d5SArnaldo Carvalho de Melo 		 * sections.
24235c0541d5SArnaldo Carvalho de Melo 		 */
24245c0541d5SArnaldo Carvalho de Melo 		__map_groups__fixup_end(&self->kmaps, type);
24255c0541d5SArnaldo Carvalho de Melo 	}
24265c0541d5SArnaldo Carvalho de Melo 
24275c0541d5SArnaldo Carvalho de Melo 	return ret;
24285c0541d5SArnaldo Carvalho de Melo }
24295c0541d5SArnaldo Carvalho de Melo 
24305c0541d5SArnaldo Carvalho de Melo int machine__load_vmlinux_path(struct machine *self, enum map_type type,
24315c0541d5SArnaldo Carvalho de Melo 			       symbol_filter_t filter)
24325c0541d5SArnaldo Carvalho de Melo {
24335c0541d5SArnaldo Carvalho de Melo 	struct map *map = self->vmlinux_maps[type];
24345c0541d5SArnaldo Carvalho de Melo 	int ret = dso__load_vmlinux_path(map->dso, map, filter);
24355c0541d5SArnaldo Carvalho de Melo 
24365c0541d5SArnaldo Carvalho de Melo 	if (ret > 0) {
24375c0541d5SArnaldo Carvalho de Melo 		dso__set_loaded(map->dso, type);
24385c0541d5SArnaldo Carvalho de Melo 		map__reloc_vmlinux(map);
24395c0541d5SArnaldo Carvalho de Melo 	}
24405c0541d5SArnaldo Carvalho de Melo 
24415c0541d5SArnaldo Carvalho de Melo 	return ret;
24425c0541d5SArnaldo Carvalho de Melo }
2443