xref: /openbmc/linux/tools/perf/util/map.c (revision ba92732e)
166e274f3SFrederic Weisbecker #include "symbol.h"
2c6e718ffSArnaldo Carvalho de Melo #include <errno.h>
39486aa38SArnaldo Carvalho de Melo #include <inttypes.h>
44b8cf846SArnaldo Carvalho de Melo #include <limits.h>
566e274f3SFrederic Weisbecker #include <stdlib.h>
666e274f3SFrederic Weisbecker #include <string.h>
766e274f3SFrederic Weisbecker #include <stdio.h>
8a1645ce1SZhang, Yanmin #include <unistd.h>
94b8cf846SArnaldo Carvalho de Melo #include "map.h"
105cd95c2dSDavid Ahern #include "thread.h"
11c80c3c26SDavid Ahern #include "strlist.h"
127dbf4dcfSJiri Olsa #include "vdso.h"
13ebb296c2SJiri Olsa #include "build-id.h"
14cc8fae1dSAdrian Hunter #include "util.h"
15acebd408SJiri Olsa #include "debug.h"
162a03068cSAdrian Hunter #include "machine.h"
178e16017dSArnaldo Carvalho de Melo #include <linux/string.h>
1866e274f3SFrederic Weisbecker 
193846df2eSArnaldo Carvalho de Melo const char *map_type__name[MAP__NR_TYPES] = {
203846df2eSArnaldo Carvalho de Melo 	[MAP__FUNCTION] = "Functions",
213846df2eSArnaldo Carvalho de Melo 	[MAP__VARIABLE] = "Variables",
223846df2eSArnaldo Carvalho de Melo };
233846df2eSArnaldo Carvalho de Melo 
2466e274f3SFrederic Weisbecker static inline int is_anon_memory(const char *filename)
2566e274f3SFrederic Weisbecker {
26d0528b5dSJoshua Zhu 	return !strcmp(filename, "//anon") ||
2789365e6cSAndi Kleen 	       !strcmp(filename, "/dev/zero (deleted)") ||
28d0528b5dSJoshua Zhu 	       !strcmp(filename, "/anon_hugepage (deleted)");
2966e274f3SFrederic Weisbecker }
3066e274f3SFrederic Weisbecker 
3187ffef79SJiri Olsa static inline int is_no_dso_memory(const char *filename)
3287ffef79SJiri Olsa {
331e82574dSNamhyung Kim 	return !strncmp(filename, "[stack", 6) ||
34700be564SDon Zickus 	       !strncmp(filename, "/SYSV",5)   ||
3587ffef79SJiri Olsa 	       !strcmp(filename, "[heap]");
3687ffef79SJiri Olsa }
3787ffef79SJiri Olsa 
38eca81836SMichael Lentine static inline int is_android_lib(const char *filename)
39eca81836SMichael Lentine {
40eca81836SMichael Lentine 	return !strncmp(filename, "/data/app-lib", 13) ||
41eca81836SMichael Lentine 	       !strncmp(filename, "/system/lib", 11);
42eca81836SMichael Lentine }
43eca81836SMichael Lentine 
44eca81836SMichael Lentine static inline bool replace_android_lib(const char *filename, char *newfilename)
45eca81836SMichael Lentine {
46eca81836SMichael Lentine 	const char *libname;
47eca81836SMichael Lentine 	char *app_abi;
48eca81836SMichael Lentine 	size_t app_abi_length, new_length;
49eca81836SMichael Lentine 	size_t lib_length = 0;
50eca81836SMichael Lentine 
51eca81836SMichael Lentine 	libname  = strrchr(filename, '/');
52eca81836SMichael Lentine 	if (libname)
53eca81836SMichael Lentine 		lib_length = strlen(libname);
54eca81836SMichael Lentine 
55eca81836SMichael Lentine 	app_abi = getenv("APP_ABI");
56eca81836SMichael Lentine 	if (!app_abi)
57eca81836SMichael Lentine 		return false;
58eca81836SMichael Lentine 
59eca81836SMichael Lentine 	app_abi_length = strlen(app_abi);
60eca81836SMichael Lentine 
61eca81836SMichael Lentine 	if (!strncmp(filename, "/data/app-lib", 13)) {
62eca81836SMichael Lentine 		char *apk_path;
63eca81836SMichael Lentine 
64eca81836SMichael Lentine 		if (!app_abi_length)
65eca81836SMichael Lentine 			return false;
66eca81836SMichael Lentine 
67eca81836SMichael Lentine 		new_length = 7 + app_abi_length + lib_length;
68eca81836SMichael Lentine 
69eca81836SMichael Lentine 		apk_path = getenv("APK_PATH");
70eca81836SMichael Lentine 		if (apk_path) {
71eca81836SMichael Lentine 			new_length += strlen(apk_path) + 1;
72eca81836SMichael Lentine 			if (new_length > PATH_MAX)
73eca81836SMichael Lentine 				return false;
74eca81836SMichael Lentine 			snprintf(newfilename, new_length,
75eca81836SMichael Lentine 				 "%s/libs/%s/%s", apk_path, app_abi, libname);
76eca81836SMichael Lentine 		} else {
77eca81836SMichael Lentine 			if (new_length > PATH_MAX)
78eca81836SMichael Lentine 				return false;
79eca81836SMichael Lentine 			snprintf(newfilename, new_length,
80eca81836SMichael Lentine 				 "libs/%s/%s", app_abi, libname);
81eca81836SMichael Lentine 		}
82eca81836SMichael Lentine 		return true;
83eca81836SMichael Lentine 	}
84eca81836SMichael Lentine 
85eca81836SMichael Lentine 	if (!strncmp(filename, "/system/lib/", 11)) {
86eca81836SMichael Lentine 		char *ndk, *app;
87eca81836SMichael Lentine 		const char *arch;
88eca81836SMichael Lentine 		size_t ndk_length;
89eca81836SMichael Lentine 		size_t app_length;
90eca81836SMichael Lentine 
91eca81836SMichael Lentine 		ndk = getenv("NDK_ROOT");
92eca81836SMichael Lentine 		app = getenv("APP_PLATFORM");
93eca81836SMichael Lentine 
94eca81836SMichael Lentine 		if (!(ndk && app))
95eca81836SMichael Lentine 			return false;
96eca81836SMichael Lentine 
97eca81836SMichael Lentine 		ndk_length = strlen(ndk);
98eca81836SMichael Lentine 		app_length = strlen(app);
99eca81836SMichael Lentine 
100eca81836SMichael Lentine 		if (!(ndk_length && app_length && app_abi_length))
101eca81836SMichael Lentine 			return false;
102eca81836SMichael Lentine 
103eca81836SMichael Lentine 		arch = !strncmp(app_abi, "arm", 3) ? "arm" :
104eca81836SMichael Lentine 		       !strncmp(app_abi, "mips", 4) ? "mips" :
105eca81836SMichael Lentine 		       !strncmp(app_abi, "x86", 3) ? "x86" : NULL;
106eca81836SMichael Lentine 
107eca81836SMichael Lentine 		if (!arch)
108eca81836SMichael Lentine 			return false;
109eca81836SMichael Lentine 
110eca81836SMichael Lentine 		new_length = 27 + ndk_length +
111eca81836SMichael Lentine 			     app_length + lib_length
112eca81836SMichael Lentine 			   + strlen(arch);
113eca81836SMichael Lentine 
114eca81836SMichael Lentine 		if (new_length > PATH_MAX)
115eca81836SMichael Lentine 			return false;
116eca81836SMichael Lentine 		snprintf(newfilename, new_length,
117eca81836SMichael Lentine 			"%s/platforms/%s/arch-%s/usr/lib/%s",
118eca81836SMichael Lentine 			ndk, app, arch, libname);
119eca81836SMichael Lentine 
120eca81836SMichael Lentine 		return true;
121eca81836SMichael Lentine 	}
122eca81836SMichael Lentine 	return false;
123eca81836SMichael Lentine }
124eca81836SMichael Lentine 
125237a7e04SArnaldo Carvalho de Melo void map__init(struct map *map, enum map_type type,
1263610583cSArnaldo Carvalho de Melo 	       u64 start, u64 end, u64 pgoff, struct dso *dso)
127afb7b4f0SArnaldo Carvalho de Melo {
128237a7e04SArnaldo Carvalho de Melo 	map->type     = type;
129237a7e04SArnaldo Carvalho de Melo 	map->start    = start;
130237a7e04SArnaldo Carvalho de Melo 	map->end      = end;
131237a7e04SArnaldo Carvalho de Melo 	map->pgoff    = pgoff;
1329176753dSAdrian Hunter 	map->reloc    = 0;
133237a7e04SArnaldo Carvalho de Melo 	map->dso      = dso;
134237a7e04SArnaldo Carvalho de Melo 	map->map_ip   = map__map_ip;
135237a7e04SArnaldo Carvalho de Melo 	map->unmap_ip = map__unmap_ip;
136237a7e04SArnaldo Carvalho de Melo 	RB_CLEAR_NODE(&map->rb_node);
137237a7e04SArnaldo Carvalho de Melo 	map->groups   = NULL;
138237a7e04SArnaldo Carvalho de Melo 	map->referenced = false;
139237a7e04SArnaldo Carvalho de Melo 	map->erange_warned = false;
140afb7b4f0SArnaldo Carvalho de Melo }
141afb7b4f0SArnaldo Carvalho de Melo 
1422a03068cSAdrian Hunter struct map *map__new(struct machine *machine, u64 start, u64 len,
1435c5e854bSStephane Eranian 		     u64 pgoff, u32 pid, u32 d_maj, u32 d_min, u64 ino,
1447ef80703SDon Zickus 		     u64 ino_gen, u32 prot, u32 flags, char *filename,
1455835eddaSAdrian Hunter 		     enum map_type type, struct thread *thread)
14666e274f3SFrederic Weisbecker {
147237a7e04SArnaldo Carvalho de Melo 	struct map *map = malloc(sizeof(*map));
14866e274f3SFrederic Weisbecker 
149237a7e04SArnaldo Carvalho de Melo 	if (map != NULL) {
15066e274f3SFrederic Weisbecker 		char newfilename[PATH_MAX];
151afb7b4f0SArnaldo Carvalho de Melo 		struct dso *dso;
152eca81836SMichael Lentine 		int anon, no_dso, vdso, android;
15366e274f3SFrederic Weisbecker 
154eca81836SMichael Lentine 		android = is_android_lib(filename);
15566e274f3SFrederic Weisbecker 		anon = is_anon_memory(filename);
1567dbf4dcfSJiri Olsa 		vdso = is_vdso_map(filename);
15787ffef79SJiri Olsa 		no_dso = is_no_dso_memory(filename);
15866e274f3SFrederic Weisbecker 
1595c5e854bSStephane Eranian 		map->maj = d_maj;
1605c5e854bSStephane Eranian 		map->min = d_min;
1615c5e854bSStephane Eranian 		map->ino = ino;
1625c5e854bSStephane Eranian 		map->ino_generation = ino_gen;
1637ef80703SDon Zickus 		map->prot = prot;
1647ef80703SDon Zickus 		map->flags = flags;
1655c5e854bSStephane Eranian 
166578c03c8SNamhyung Kim 		if ((anon || no_dso) && type == MAP__FUNCTION) {
167b177f63fSArnaldo Carvalho de Melo 			snprintf(newfilename, sizeof(newfilename), "/tmp/perf-%d.map", pid);
16866e274f3SFrederic Weisbecker 			filename = newfilename;
16966e274f3SFrederic Weisbecker 		}
17066e274f3SFrederic Weisbecker 
171eca81836SMichael Lentine 		if (android) {
172eca81836SMichael Lentine 			if (replace_android_lib(filename, newfilename))
173eca81836SMichael Lentine 				filename = newfilename;
174eca81836SMichael Lentine 		}
175eca81836SMichael Lentine 
1767dbf4dcfSJiri Olsa 		if (vdso) {
1777dbf4dcfSJiri Olsa 			pgoff = 0;
1785835eddaSAdrian Hunter 			dso = vdso__dso_findnew(machine, thread);
1797dbf4dcfSJiri Olsa 		} else
1802a03068cSAdrian Hunter 			dso = __dsos__findnew(&machine->user_dsos, filename);
1817dbf4dcfSJiri Olsa 
182afb7b4f0SArnaldo Carvalho de Melo 		if (dso == NULL)
18366e274f3SFrederic Weisbecker 			goto out_delete;
18466e274f3SFrederic Weisbecker 
185237a7e04SArnaldo Carvalho de Melo 		map__init(map, type, start, start + len, pgoff, dso);
186afb7b4f0SArnaldo Carvalho de Melo 
18787ffef79SJiri Olsa 		if (anon || no_dso) {
188237a7e04SArnaldo Carvalho de Melo 			map->map_ip = map->unmap_ip = identity__map_ip;
18987ffef79SJiri Olsa 
19087ffef79SJiri Olsa 			/*
19187ffef79SJiri Olsa 			 * Set memory without DSO as loaded. All map__find_*
19287ffef79SJiri Olsa 			 * functions still return NULL, and we avoid the
19387ffef79SJiri Olsa 			 * unnecessary map__load warning.
19487ffef79SJiri Olsa 			 */
195578c03c8SNamhyung Kim 			if (type != MAP__FUNCTION)
196237a7e04SArnaldo Carvalho de Melo 				dso__set_loaded(dso, map->type);
1978d92c02aSArnaldo Carvalho de Melo 		}
19866e274f3SFrederic Weisbecker 	}
199237a7e04SArnaldo Carvalho de Melo 	return map;
20066e274f3SFrederic Weisbecker out_delete:
201237a7e04SArnaldo Carvalho de Melo 	free(map);
20266e274f3SFrederic Weisbecker 	return NULL;
20366e274f3SFrederic Weisbecker }
20466e274f3SFrederic Weisbecker 
205e5a1845fSNamhyung Kim /*
206e5a1845fSNamhyung Kim  * Constructor variant for modules (where we know from /proc/modules where
207e5a1845fSNamhyung Kim  * they are loaded) and for vmlinux, where only after we load all the
208e5a1845fSNamhyung Kim  * symbols we'll know where it starts and ends.
209e5a1845fSNamhyung Kim  */
210e5a1845fSNamhyung Kim struct map *map__new2(u64 start, struct dso *dso, enum map_type type)
211e5a1845fSNamhyung Kim {
212e5a1845fSNamhyung Kim 	struct map *map = calloc(1, (sizeof(*map) +
213e5a1845fSNamhyung Kim 				     (dso->kernel ? sizeof(struct kmap) : 0)));
214e5a1845fSNamhyung Kim 	if (map != NULL) {
215e5a1845fSNamhyung Kim 		/*
216e5a1845fSNamhyung Kim 		 * ->end will be filled after we load all the symbols
217e5a1845fSNamhyung Kim 		 */
218e5a1845fSNamhyung Kim 		map__init(map, type, start, 0, 0, dso);
219e5a1845fSNamhyung Kim 	}
220e5a1845fSNamhyung Kim 
221e5a1845fSNamhyung Kim 	return map;
222e5a1845fSNamhyung Kim }
223e5a1845fSNamhyung Kim 
224237a7e04SArnaldo Carvalho de Melo void map__delete(struct map *map)
225c338aee8SArnaldo Carvalho de Melo {
226237a7e04SArnaldo Carvalho de Melo 	free(map);
227c338aee8SArnaldo Carvalho de Melo }
228c338aee8SArnaldo Carvalho de Melo 
229237a7e04SArnaldo Carvalho de Melo void map__fixup_start(struct map *map)
230c338aee8SArnaldo Carvalho de Melo {
231237a7e04SArnaldo Carvalho de Melo 	struct rb_root *symbols = &map->dso->symbols[map->type];
232fcf1203aSArnaldo Carvalho de Melo 	struct rb_node *nd = rb_first(symbols);
233c338aee8SArnaldo Carvalho de Melo 	if (nd != NULL) {
234c338aee8SArnaldo Carvalho de Melo 		struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
235237a7e04SArnaldo Carvalho de Melo 		map->start = sym->start;
236c338aee8SArnaldo Carvalho de Melo 	}
237c338aee8SArnaldo Carvalho de Melo }
238c338aee8SArnaldo Carvalho de Melo 
239237a7e04SArnaldo Carvalho de Melo void map__fixup_end(struct map *map)
240c338aee8SArnaldo Carvalho de Melo {
241237a7e04SArnaldo Carvalho de Melo 	struct rb_root *symbols = &map->dso->symbols[map->type];
242fcf1203aSArnaldo Carvalho de Melo 	struct rb_node *nd = rb_last(symbols);
243c338aee8SArnaldo Carvalho de Melo 	if (nd != NULL) {
244c338aee8SArnaldo Carvalho de Melo 		struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
245237a7e04SArnaldo Carvalho de Melo 		map->end = sym->end;
246c338aee8SArnaldo Carvalho de Melo 	}
247c338aee8SArnaldo Carvalho de Melo }
248c338aee8SArnaldo Carvalho de Melo 
249d70a5402SArnaldo Carvalho de Melo #define DSO__DELETED "(deleted)"
250d70a5402SArnaldo Carvalho de Melo 
251237a7e04SArnaldo Carvalho de Melo int map__load(struct map *map, symbol_filter_t filter)
25266bd8424SArnaldo Carvalho de Melo {
253237a7e04SArnaldo Carvalho de Melo 	const char *name = map->dso->long_name;
254a128168dSMasami Hiramatsu 	int nr;
25566bd8424SArnaldo Carvalho de Melo 
256237a7e04SArnaldo Carvalho de Melo 	if (dso__loaded(map->dso, map->type))
257a128168dSMasami Hiramatsu 		return 0;
258a128168dSMasami Hiramatsu 
259237a7e04SArnaldo Carvalho de Melo 	nr = dso__load(map->dso, map, filter);
26066bd8424SArnaldo Carvalho de Melo 	if (nr < 0) {
261237a7e04SArnaldo Carvalho de Melo 		if (map->dso->has_build_id) {
2628d06367fSArnaldo Carvalho de Melo 			char sbuild_id[BUILD_ID_SIZE * 2 + 1];
2638d06367fSArnaldo Carvalho de Melo 
264237a7e04SArnaldo Carvalho de Melo 			build_id__sprintf(map->dso->build_id,
265237a7e04SArnaldo Carvalho de Melo 					  sizeof(map->dso->build_id),
2668d06367fSArnaldo Carvalho de Melo 					  sbuild_id);
2678d06367fSArnaldo Carvalho de Melo 			pr_warning("%s with build id %s not found",
26879406cd7SArnaldo Carvalho de Melo 				   name, sbuild_id);
2698d06367fSArnaldo Carvalho de Melo 		} else
27079406cd7SArnaldo Carvalho de Melo 			pr_warning("Failed to open %s", name);
27179406cd7SArnaldo Carvalho de Melo 
2728d06367fSArnaldo Carvalho de Melo 		pr_warning(", continuing without symbols\n");
27379406cd7SArnaldo Carvalho de Melo 		return -1;
27466bd8424SArnaldo Carvalho de Melo 	} else if (nr == 0) {
27589fe808aSIngo Molnar #ifdef HAVE_LIBELF_SUPPORT
276d70a5402SArnaldo Carvalho de Melo 		const size_t len = strlen(name);
277d70a5402SArnaldo Carvalho de Melo 		const size_t real_len = len - sizeof(DSO__DELETED);
278d70a5402SArnaldo Carvalho de Melo 
279d70a5402SArnaldo Carvalho de Melo 		if (len > sizeof(DSO__DELETED) &&
280900b20d5SIngo Molnar 		    strcmp(name + real_len + 1, DSO__DELETED) == 0) {
281e77b15bdSDavid Ahern 			pr_warning("%.*s was updated (is prelink enabled?). "
282e77b15bdSDavid Ahern 				"Restart the long running apps that use it!\n",
283900b20d5SIngo Molnar 				   (int)real_len, name);
284900b20d5SIngo Molnar 		} else {
28579406cd7SArnaldo Carvalho de Melo 			pr_warning("no symbols found in %s, maybe install "
28679406cd7SArnaldo Carvalho de Melo 				   "a debug package?\n", name);
28766bd8424SArnaldo Carvalho de Melo 		}
288393be2e3SNamhyung Kim #endif
28979406cd7SArnaldo Carvalho de Melo 		return -1;
29079406cd7SArnaldo Carvalho de Melo 	}
29179406cd7SArnaldo Carvalho de Melo 
29279406cd7SArnaldo Carvalho de Melo 	return 0;
29379406cd7SArnaldo Carvalho de Melo }
29479406cd7SArnaldo Carvalho de Melo 
295237a7e04SArnaldo Carvalho de Melo struct symbol *map__find_symbol(struct map *map, u64 addr,
2969de89fe7SArnaldo Carvalho de Melo 				symbol_filter_t filter)
29779406cd7SArnaldo Carvalho de Melo {
298237a7e04SArnaldo Carvalho de Melo 	if (map__load(map, filter) < 0)
29979406cd7SArnaldo Carvalho de Melo 		return NULL;
30079406cd7SArnaldo Carvalho de Melo 
301237a7e04SArnaldo Carvalho de Melo 	return dso__find_symbol(map->dso, map->type, addr);
30266bd8424SArnaldo Carvalho de Melo }
30366bd8424SArnaldo Carvalho de Melo 
304237a7e04SArnaldo Carvalho de Melo struct symbol *map__find_symbol_by_name(struct map *map, const char *name,
30579406cd7SArnaldo Carvalho de Melo 					symbol_filter_t filter)
30679406cd7SArnaldo Carvalho de Melo {
307237a7e04SArnaldo Carvalho de Melo 	if (map__load(map, filter) < 0)
30879406cd7SArnaldo Carvalho de Melo 		return NULL;
30979406cd7SArnaldo Carvalho de Melo 
310237a7e04SArnaldo Carvalho de Melo 	if (!dso__sorted_by_name(map->dso, map->type))
311237a7e04SArnaldo Carvalho de Melo 		dso__sort_by_name(map->dso, map->type);
31279406cd7SArnaldo Carvalho de Melo 
313237a7e04SArnaldo Carvalho de Melo 	return dso__find_symbol_by_name(map->dso, map->type, name);
31479406cd7SArnaldo Carvalho de Melo }
31579406cd7SArnaldo Carvalho de Melo 
316237a7e04SArnaldo Carvalho de Melo struct map *map__clone(struct map *map)
31766e274f3SFrederic Weisbecker {
3188e16017dSArnaldo Carvalho de Melo 	return memdup(map, sizeof(*map));
31966e274f3SFrederic Weisbecker }
32066e274f3SFrederic Weisbecker 
32166e274f3SFrederic Weisbecker int map__overlap(struct map *l, struct map *r)
32266e274f3SFrederic Weisbecker {
32366e274f3SFrederic Weisbecker 	if (l->start > r->start) {
32466e274f3SFrederic Weisbecker 		struct map *t = l;
32566e274f3SFrederic Weisbecker 		l = r;
32666e274f3SFrederic Weisbecker 		r = t;
32766e274f3SFrederic Weisbecker 	}
32866e274f3SFrederic Weisbecker 
32966e274f3SFrederic Weisbecker 	if (l->end > r->start)
33066e274f3SFrederic Weisbecker 		return 1;
33166e274f3SFrederic Weisbecker 
33266e274f3SFrederic Weisbecker 	return 0;
33366e274f3SFrederic Weisbecker }
33466e274f3SFrederic Weisbecker 
335237a7e04SArnaldo Carvalho de Melo size_t map__fprintf(struct map *map, FILE *fp)
33666e274f3SFrederic Weisbecker {
3379486aa38SArnaldo Carvalho de Melo 	return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %" PRIx64 " %s\n",
338237a7e04SArnaldo Carvalho de Melo 		       map->start, map->end, map->pgoff, map->dso->name);
33966e274f3SFrederic Weisbecker }
3407a2b6209SKirill Smelkov 
341547a92e0SAkihiro Nagai size_t map__fprintf_dsoname(struct map *map, FILE *fp)
342547a92e0SAkihiro Nagai {
3438f28f19aSFeng Tang 	const char *dsoname = "[unknown]";
344547a92e0SAkihiro Nagai 
3450bc8d205SAkihiro Nagai 	if (map && map->dso && (map->dso->name || map->dso->long_name)) {
3460bc8d205SAkihiro Nagai 		if (symbol_conf.show_kernel_path && map->dso->long_name)
3470bc8d205SAkihiro Nagai 			dsoname = map->dso->long_name;
3480bc8d205SAkihiro Nagai 		else if (map->dso->name)
349547a92e0SAkihiro Nagai 			dsoname = map->dso->name;
3508f28f19aSFeng Tang 	}
351547a92e0SAkihiro Nagai 
352547a92e0SAkihiro Nagai 	return fprintf(fp, "%s", dsoname);
353547a92e0SAkihiro Nagai }
354547a92e0SAkihiro Nagai 
355cc8fae1dSAdrian Hunter int map__fprintf_srcline(struct map *map, u64 addr, const char *prefix,
356cc8fae1dSAdrian Hunter 			 FILE *fp)
357cc8fae1dSAdrian Hunter {
358cc8fae1dSAdrian Hunter 	char *srcline;
359cc8fae1dSAdrian Hunter 	int ret = 0;
360cc8fae1dSAdrian Hunter 
361cc8fae1dSAdrian Hunter 	if (map && map->dso) {
362cc8fae1dSAdrian Hunter 		srcline = get_srcline(map->dso,
36385c116a6SAndi Kleen 				      map__rip_2objdump(map, addr), NULL, true);
364cc8fae1dSAdrian Hunter 		if (srcline != SRCLINE_UNKNOWN)
365cc8fae1dSAdrian Hunter 			ret = fprintf(fp, "%s%s", prefix, srcline);
366cc8fae1dSAdrian Hunter 		free_srcline(srcline);
367cc8fae1dSAdrian Hunter 	}
368cc8fae1dSAdrian Hunter 	return ret;
369cc8fae1dSAdrian Hunter }
370cc8fae1dSAdrian Hunter 
3711d5077bdSAdrian Hunter /**
3721d5077bdSAdrian Hunter  * map__rip_2objdump - convert symbol start address to objdump address.
3731d5077bdSAdrian Hunter  * @map: memory map
3741d5077bdSAdrian Hunter  * @rip: symbol start address
3751d5077bdSAdrian Hunter  *
3767a2b6209SKirill Smelkov  * objdump wants/reports absolute IPs for ET_EXEC, and RIPs for ET_DYN.
3770131c4ecSAdrian Hunter  * map->dso->adjust_symbols==1 for ET_EXEC-like cases except ET_REL which is
3780131c4ecSAdrian Hunter  * relative to section start.
3791d5077bdSAdrian Hunter  *
3801d5077bdSAdrian Hunter  * Return: Address suitable for passing to "objdump --start-address="
3817a2b6209SKirill Smelkov  */
3827a2b6209SKirill Smelkov u64 map__rip_2objdump(struct map *map, u64 rip)
3837a2b6209SKirill Smelkov {
3840131c4ecSAdrian Hunter 	if (!map->dso->adjust_symbols)
3850131c4ecSAdrian Hunter 		return rip;
3860131c4ecSAdrian Hunter 
3870131c4ecSAdrian Hunter 	if (map->dso->rel)
3880131c4ecSAdrian Hunter 		return rip - map->pgoff;
3890131c4ecSAdrian Hunter 
3909176753dSAdrian Hunter 	return map->unmap_ip(map, rip) - map->reloc;
3917a2b6209SKirill Smelkov }
392ee11b90bSKirill Smelkov 
3931d5077bdSAdrian Hunter /**
3941d5077bdSAdrian Hunter  * map__objdump_2mem - convert objdump address to a memory address.
3951d5077bdSAdrian Hunter  * @map: memory map
3961d5077bdSAdrian Hunter  * @ip: objdump address
3971d5077bdSAdrian Hunter  *
3981d5077bdSAdrian Hunter  * Closely related to map__rip_2objdump(), this function takes an address from
3991d5077bdSAdrian Hunter  * objdump and converts it to a memory address.  Note this assumes that @map
4001d5077bdSAdrian Hunter  * contains the address.  To be sure the result is valid, check it forwards
4011d5077bdSAdrian Hunter  * e.g. map__rip_2objdump(map->map_ip(map, map__objdump_2mem(map, ip))) == ip
4021d5077bdSAdrian Hunter  *
4031d5077bdSAdrian Hunter  * Return: Memory address.
4041d5077bdSAdrian Hunter  */
4051d5077bdSAdrian Hunter u64 map__objdump_2mem(struct map *map, u64 ip)
4061d5077bdSAdrian Hunter {
4071d5077bdSAdrian Hunter 	if (!map->dso->adjust_symbols)
4081d5077bdSAdrian Hunter 		return map->unmap_ip(map, ip);
4091d5077bdSAdrian Hunter 
4101d5077bdSAdrian Hunter 	if (map->dso->rel)
4111d5077bdSAdrian Hunter 		return map->unmap_ip(map, ip + map->pgoff);
4121d5077bdSAdrian Hunter 
4139176753dSAdrian Hunter 	return ip + map->reloc;
4141d5077bdSAdrian Hunter }
4151d5077bdSAdrian Hunter 
41611246c70SArnaldo Carvalho de Melo void map_groups__init(struct map_groups *mg, struct machine *machine)
417c6e718ffSArnaldo Carvalho de Melo {
418c6e718ffSArnaldo Carvalho de Melo 	int i;
419c6e718ffSArnaldo Carvalho de Melo 	for (i = 0; i < MAP__NR_TYPES; ++i) {
42098dfd55dSArnaldo Carvalho de Melo 		mg->maps[i] = RB_ROOT;
42198dfd55dSArnaldo Carvalho de Melo 		INIT_LIST_HEAD(&mg->removed_maps[i]);
422c6e718ffSArnaldo Carvalho de Melo 	}
42311246c70SArnaldo Carvalho de Melo 	mg->machine = machine;
424a26ca671SArnaldo Carvalho de Melo 	mg->refcnt = 1;
425c6e718ffSArnaldo Carvalho de Melo }
426c6e718ffSArnaldo Carvalho de Melo 
42798dfd55dSArnaldo Carvalho de Melo static void maps__delete(struct rb_root *maps)
428591765fdSArnaldo Carvalho de Melo {
42998dfd55dSArnaldo Carvalho de Melo 	struct rb_node *next = rb_first(maps);
430591765fdSArnaldo Carvalho de Melo 
431591765fdSArnaldo Carvalho de Melo 	while (next) {
432591765fdSArnaldo Carvalho de Melo 		struct map *pos = rb_entry(next, struct map, rb_node);
433591765fdSArnaldo Carvalho de Melo 
434591765fdSArnaldo Carvalho de Melo 		next = rb_next(&pos->rb_node);
43598dfd55dSArnaldo Carvalho de Melo 		rb_erase(&pos->rb_node, maps);
436591765fdSArnaldo Carvalho de Melo 		map__delete(pos);
437591765fdSArnaldo Carvalho de Melo 	}
438591765fdSArnaldo Carvalho de Melo }
439591765fdSArnaldo Carvalho de Melo 
44098dfd55dSArnaldo Carvalho de Melo static void maps__delete_removed(struct list_head *maps)
441591765fdSArnaldo Carvalho de Melo {
442591765fdSArnaldo Carvalho de Melo 	struct map *pos, *n;
443591765fdSArnaldo Carvalho de Melo 
44498dfd55dSArnaldo Carvalho de Melo 	list_for_each_entry_safe(pos, n, maps, node) {
445591765fdSArnaldo Carvalho de Melo 		list_del(&pos->node);
446591765fdSArnaldo Carvalho de Melo 		map__delete(pos);
447591765fdSArnaldo Carvalho de Melo 	}
448591765fdSArnaldo Carvalho de Melo }
449591765fdSArnaldo Carvalho de Melo 
45098dfd55dSArnaldo Carvalho de Melo void map_groups__exit(struct map_groups *mg)
451591765fdSArnaldo Carvalho de Melo {
452591765fdSArnaldo Carvalho de Melo 	int i;
453591765fdSArnaldo Carvalho de Melo 
454591765fdSArnaldo Carvalho de Melo 	for (i = 0; i < MAP__NR_TYPES; ++i) {
45598dfd55dSArnaldo Carvalho de Melo 		maps__delete(&mg->maps[i]);
45698dfd55dSArnaldo Carvalho de Melo 		maps__delete_removed(&mg->removed_maps[i]);
457591765fdSArnaldo Carvalho de Melo 	}
458591765fdSArnaldo Carvalho de Melo }
459591765fdSArnaldo Carvalho de Melo 
46029ce3612SAdrian Hunter bool map_groups__empty(struct map_groups *mg)
46129ce3612SAdrian Hunter {
46229ce3612SAdrian Hunter 	int i;
46329ce3612SAdrian Hunter 
46429ce3612SAdrian Hunter 	for (i = 0; i < MAP__NR_TYPES; ++i) {
46529ce3612SAdrian Hunter 		if (maps__first(&mg->maps[i]))
46629ce3612SAdrian Hunter 			return false;
46729ce3612SAdrian Hunter 		if (!list_empty(&mg->removed_maps[i]))
46829ce3612SAdrian Hunter 			return false;
46929ce3612SAdrian Hunter 	}
47029ce3612SAdrian Hunter 
47129ce3612SAdrian Hunter 	return true;
47229ce3612SAdrian Hunter }
47329ce3612SAdrian Hunter 
47411246c70SArnaldo Carvalho de Melo struct map_groups *map_groups__new(struct machine *machine)
47593d5731dSArnaldo Carvalho de Melo {
47693d5731dSArnaldo Carvalho de Melo 	struct map_groups *mg = malloc(sizeof(*mg));
47793d5731dSArnaldo Carvalho de Melo 
47893d5731dSArnaldo Carvalho de Melo 	if (mg != NULL)
47911246c70SArnaldo Carvalho de Melo 		map_groups__init(mg, machine);
48093d5731dSArnaldo Carvalho de Melo 
48193d5731dSArnaldo Carvalho de Melo 	return mg;
48293d5731dSArnaldo Carvalho de Melo }
48393d5731dSArnaldo Carvalho de Melo 
48493d5731dSArnaldo Carvalho de Melo void map_groups__delete(struct map_groups *mg)
48593d5731dSArnaldo Carvalho de Melo {
48693d5731dSArnaldo Carvalho de Melo 	map_groups__exit(mg);
48793d5731dSArnaldo Carvalho de Melo 	free(mg);
48893d5731dSArnaldo Carvalho de Melo }
48993d5731dSArnaldo Carvalho de Melo 
490a26ca671SArnaldo Carvalho de Melo void map_groups__put(struct map_groups *mg)
491a26ca671SArnaldo Carvalho de Melo {
492a26ca671SArnaldo Carvalho de Melo 	if (--mg->refcnt == 0)
493a26ca671SArnaldo Carvalho de Melo 		map_groups__delete(mg);
494a26ca671SArnaldo Carvalho de Melo }
495a26ca671SArnaldo Carvalho de Melo 
49698dfd55dSArnaldo Carvalho de Melo void map_groups__flush(struct map_groups *mg)
497c6e718ffSArnaldo Carvalho de Melo {
498c6e718ffSArnaldo Carvalho de Melo 	int type;
499c6e718ffSArnaldo Carvalho de Melo 
500c6e718ffSArnaldo Carvalho de Melo 	for (type = 0; type < MAP__NR_TYPES; type++) {
50198dfd55dSArnaldo Carvalho de Melo 		struct rb_root *root = &mg->maps[type];
502c6e718ffSArnaldo Carvalho de Melo 		struct rb_node *next = rb_first(root);
503c6e718ffSArnaldo Carvalho de Melo 
504c6e718ffSArnaldo Carvalho de Melo 		while (next) {
505c6e718ffSArnaldo Carvalho de Melo 			struct map *pos = rb_entry(next, struct map, rb_node);
506c6e718ffSArnaldo Carvalho de Melo 			next = rb_next(&pos->rb_node);
507c6e718ffSArnaldo Carvalho de Melo 			rb_erase(&pos->rb_node, root);
508c6e718ffSArnaldo Carvalho de Melo 			/*
509c6e718ffSArnaldo Carvalho de Melo 			 * We may have references to this map, for
510c6e718ffSArnaldo Carvalho de Melo 			 * instance in some hist_entry instances, so
511c6e718ffSArnaldo Carvalho de Melo 			 * just move them to a separate list.
512c6e718ffSArnaldo Carvalho de Melo 			 */
51398dfd55dSArnaldo Carvalho de Melo 			list_add_tail(&pos->node, &mg->removed_maps[pos->type]);
514c6e718ffSArnaldo Carvalho de Melo 		}
515c6e718ffSArnaldo Carvalho de Melo 	}
516c6e718ffSArnaldo Carvalho de Melo }
517c6e718ffSArnaldo Carvalho de Melo 
51898dfd55dSArnaldo Carvalho de Melo struct symbol *map_groups__find_symbol(struct map_groups *mg,
5194b8cf846SArnaldo Carvalho de Melo 				       enum map_type type, u64 addr,
5207e5e1b14SArnaldo Carvalho de Melo 				       struct map **mapp,
5214b8cf846SArnaldo Carvalho de Melo 				       symbol_filter_t filter)
5224b8cf846SArnaldo Carvalho de Melo {
52398dfd55dSArnaldo Carvalho de Melo 	struct map *map = map_groups__find(mg, type, addr);
5244b8cf846SArnaldo Carvalho de Melo 
5254afc81cdSMasami Hiramatsu 	/* Ensure map is loaded before using map->map_ip */
5264afc81cdSMasami Hiramatsu 	if (map != NULL && map__load(map, filter) >= 0) {
5277e5e1b14SArnaldo Carvalho de Melo 		if (mapp != NULL)
5287e5e1b14SArnaldo Carvalho de Melo 			*mapp = map;
5294b8cf846SArnaldo Carvalho de Melo 		return map__find_symbol(map, map->map_ip(map, addr), filter);
5307e5e1b14SArnaldo Carvalho de Melo 	}
5317e5e1b14SArnaldo Carvalho de Melo 
5327e5e1b14SArnaldo Carvalho de Melo 	return NULL;
5337e5e1b14SArnaldo Carvalho de Melo }
5347e5e1b14SArnaldo Carvalho de Melo 
53598dfd55dSArnaldo Carvalho de Melo struct symbol *map_groups__find_symbol_by_name(struct map_groups *mg,
5367e5e1b14SArnaldo Carvalho de Melo 					       enum map_type type,
5377e5e1b14SArnaldo Carvalho de Melo 					       const char *name,
5387e5e1b14SArnaldo Carvalho de Melo 					       struct map **mapp,
5397e5e1b14SArnaldo Carvalho de Melo 					       symbol_filter_t filter)
5407e5e1b14SArnaldo Carvalho de Melo {
5417e5e1b14SArnaldo Carvalho de Melo 	struct rb_node *nd;
5427e5e1b14SArnaldo Carvalho de Melo 
54398dfd55dSArnaldo Carvalho de Melo 	for (nd = rb_first(&mg->maps[type]); nd; nd = rb_next(nd)) {
5447e5e1b14SArnaldo Carvalho de Melo 		struct map *pos = rb_entry(nd, struct map, rb_node);
5457e5e1b14SArnaldo Carvalho de Melo 		struct symbol *sym = map__find_symbol_by_name(pos, name, filter);
5467e5e1b14SArnaldo Carvalho de Melo 
5477e5e1b14SArnaldo Carvalho de Melo 		if (sym == NULL)
5487e5e1b14SArnaldo Carvalho de Melo 			continue;
5497e5e1b14SArnaldo Carvalho de Melo 		if (mapp != NULL)
5507e5e1b14SArnaldo Carvalho de Melo 			*mapp = pos;
5517e5e1b14SArnaldo Carvalho de Melo 		return sym;
5527e5e1b14SArnaldo Carvalho de Melo 	}
5534b8cf846SArnaldo Carvalho de Melo 
5544b8cf846SArnaldo Carvalho de Melo 	return NULL;
5554b8cf846SArnaldo Carvalho de Melo }
5564b8cf846SArnaldo Carvalho de Melo 
5574e987712SArnaldo Carvalho de Melo int map_groups__find_ams(struct addr_map_symbol *ams, symbol_filter_t filter)
5584e987712SArnaldo Carvalho de Melo {
55977faf4d0SStephane Eranian 	if (ams->addr < ams->map->start || ams->addr >= ams->map->end) {
5604e987712SArnaldo Carvalho de Melo 		if (ams->map->groups == NULL)
5614e987712SArnaldo Carvalho de Melo 			return -1;
5624e987712SArnaldo Carvalho de Melo 		ams->map = map_groups__find(ams->map->groups, ams->map->type,
5634e987712SArnaldo Carvalho de Melo 					    ams->addr);
5644e987712SArnaldo Carvalho de Melo 		if (ams->map == NULL)
5654e987712SArnaldo Carvalho de Melo 			return -1;
5664e987712SArnaldo Carvalho de Melo 	}
5674e987712SArnaldo Carvalho de Melo 
5684e987712SArnaldo Carvalho de Melo 	ams->al_addr = ams->map->map_ip(ams->map, ams->addr);
5694e987712SArnaldo Carvalho de Melo 	ams->sym = map__find_symbol(ams->map, ams->al_addr, filter);
5704e987712SArnaldo Carvalho de Melo 
5714e987712SArnaldo Carvalho de Melo 	return ams->sym ? 0 : -1;
5724e987712SArnaldo Carvalho de Melo }
5734e987712SArnaldo Carvalho de Melo 
574acebd408SJiri Olsa size_t __map_groups__fprintf_maps(struct map_groups *mg, enum map_type type,
575acebd408SJiri Olsa 				  FILE *fp)
576c6e718ffSArnaldo Carvalho de Melo {
577c6e718ffSArnaldo Carvalho de Melo 	size_t printed = fprintf(fp, "%s:\n", map_type__name[type]);
578c6e718ffSArnaldo Carvalho de Melo 	struct rb_node *nd;
579c6e718ffSArnaldo Carvalho de Melo 
58098dfd55dSArnaldo Carvalho de Melo 	for (nd = rb_first(&mg->maps[type]); nd; nd = rb_next(nd)) {
581c6e718ffSArnaldo Carvalho de Melo 		struct map *pos = rb_entry(nd, struct map, rb_node);
582c6e718ffSArnaldo Carvalho de Melo 		printed += fprintf(fp, "Map:");
583c6e718ffSArnaldo Carvalho de Melo 		printed += map__fprintf(pos, fp);
584c6e718ffSArnaldo Carvalho de Melo 		if (verbose > 2) {
585c6e718ffSArnaldo Carvalho de Melo 			printed += dso__fprintf(pos->dso, type, fp);
586c6e718ffSArnaldo Carvalho de Melo 			printed += fprintf(fp, "--\n");
587c6e718ffSArnaldo Carvalho de Melo 		}
588c6e718ffSArnaldo Carvalho de Melo 	}
589c6e718ffSArnaldo Carvalho de Melo 
590c6e718ffSArnaldo Carvalho de Melo 	return printed;
591c6e718ffSArnaldo Carvalho de Melo }
592c6e718ffSArnaldo Carvalho de Melo 
593acebd408SJiri Olsa static size_t map_groups__fprintf_maps(struct map_groups *mg, FILE *fp)
594c6e718ffSArnaldo Carvalho de Melo {
595c6e718ffSArnaldo Carvalho de Melo 	size_t printed = 0, i;
596c6e718ffSArnaldo Carvalho de Melo 	for (i = 0; i < MAP__NR_TYPES; ++i)
597acebd408SJiri Olsa 		printed += __map_groups__fprintf_maps(mg, i, fp);
598c6e718ffSArnaldo Carvalho de Melo 	return printed;
599c6e718ffSArnaldo Carvalho de Melo }
600c6e718ffSArnaldo Carvalho de Melo 
60198dfd55dSArnaldo Carvalho de Melo static size_t __map_groups__fprintf_removed_maps(struct map_groups *mg,
602acebd408SJiri Olsa 						 enum map_type type, FILE *fp)
603c6e718ffSArnaldo Carvalho de Melo {
604c6e718ffSArnaldo Carvalho de Melo 	struct map *pos;
605c6e718ffSArnaldo Carvalho de Melo 	size_t printed = 0;
606c6e718ffSArnaldo Carvalho de Melo 
60798dfd55dSArnaldo Carvalho de Melo 	list_for_each_entry(pos, &mg->removed_maps[type], node) {
608c6e718ffSArnaldo Carvalho de Melo 		printed += fprintf(fp, "Map:");
609c6e718ffSArnaldo Carvalho de Melo 		printed += map__fprintf(pos, fp);
610c6e718ffSArnaldo Carvalho de Melo 		if (verbose > 1) {
611c6e718ffSArnaldo Carvalho de Melo 			printed += dso__fprintf(pos->dso, type, fp);
612c6e718ffSArnaldo Carvalho de Melo 			printed += fprintf(fp, "--\n");
613c6e718ffSArnaldo Carvalho de Melo 		}
614c6e718ffSArnaldo Carvalho de Melo 	}
615c6e718ffSArnaldo Carvalho de Melo 	return printed;
616c6e718ffSArnaldo Carvalho de Melo }
617c6e718ffSArnaldo Carvalho de Melo 
61898dfd55dSArnaldo Carvalho de Melo static size_t map_groups__fprintf_removed_maps(struct map_groups *mg,
619acebd408SJiri Olsa 					       FILE *fp)
620c6e718ffSArnaldo Carvalho de Melo {
621c6e718ffSArnaldo Carvalho de Melo 	size_t printed = 0, i;
622c6e718ffSArnaldo Carvalho de Melo 	for (i = 0; i < MAP__NR_TYPES; ++i)
623acebd408SJiri Olsa 		printed += __map_groups__fprintf_removed_maps(mg, i, fp);
624c6e718ffSArnaldo Carvalho de Melo 	return printed;
625c6e718ffSArnaldo Carvalho de Melo }
626c6e718ffSArnaldo Carvalho de Melo 
627acebd408SJiri Olsa size_t map_groups__fprintf(struct map_groups *mg, FILE *fp)
628c6e718ffSArnaldo Carvalho de Melo {
629acebd408SJiri Olsa 	size_t printed = map_groups__fprintf_maps(mg, fp);
630c6e718ffSArnaldo Carvalho de Melo 	printed += fprintf(fp, "Removed maps:\n");
631acebd408SJiri Olsa 	return printed + map_groups__fprintf_removed_maps(mg, fp);
632c6e718ffSArnaldo Carvalho de Melo }
633c6e718ffSArnaldo Carvalho de Melo 
63498dfd55dSArnaldo Carvalho de Melo int map_groups__fixup_overlappings(struct map_groups *mg, struct map *map,
635acebd408SJiri Olsa 				   FILE *fp)
636c6e718ffSArnaldo Carvalho de Melo {
63798dfd55dSArnaldo Carvalho de Melo 	struct rb_root *root = &mg->maps[map->type];
638c6e718ffSArnaldo Carvalho de Melo 	struct rb_node *next = rb_first(root);
6390a1eae39SArnaldo Carvalho de Melo 	int err = 0;
640c6e718ffSArnaldo Carvalho de Melo 
641c6e718ffSArnaldo Carvalho de Melo 	while (next) {
642c6e718ffSArnaldo Carvalho de Melo 		struct map *pos = rb_entry(next, struct map, rb_node);
643c6e718ffSArnaldo Carvalho de Melo 		next = rb_next(&pos->rb_node);
644c6e718ffSArnaldo Carvalho de Melo 
645c6e718ffSArnaldo Carvalho de Melo 		if (!map__overlap(pos, map))
646c6e718ffSArnaldo Carvalho de Melo 			continue;
647c6e718ffSArnaldo Carvalho de Melo 
648c6e718ffSArnaldo Carvalho de Melo 		if (verbose >= 2) {
649c6e718ffSArnaldo Carvalho de Melo 			fputs("overlapping maps:\n", fp);
650c6e718ffSArnaldo Carvalho de Melo 			map__fprintf(map, fp);
651c6e718ffSArnaldo Carvalho de Melo 			map__fprintf(pos, fp);
652c6e718ffSArnaldo Carvalho de Melo 		}
653c6e718ffSArnaldo Carvalho de Melo 
654c6e718ffSArnaldo Carvalho de Melo 		rb_erase(&pos->rb_node, root);
655c6e718ffSArnaldo Carvalho de Melo 		/*
656c6e718ffSArnaldo Carvalho de Melo 		 * Now check if we need to create new maps for areas not
657c6e718ffSArnaldo Carvalho de Melo 		 * overlapped by the new map:
658c6e718ffSArnaldo Carvalho de Melo 		 */
659c6e718ffSArnaldo Carvalho de Melo 		if (map->start > pos->start) {
660c6e718ffSArnaldo Carvalho de Melo 			struct map *before = map__clone(pos);
661c6e718ffSArnaldo Carvalho de Melo 
6620a1eae39SArnaldo Carvalho de Melo 			if (before == NULL) {
6630a1eae39SArnaldo Carvalho de Melo 				err = -ENOMEM;
6640a1eae39SArnaldo Carvalho de Melo 				goto move_map;
6650a1eae39SArnaldo Carvalho de Melo 			}
666c6e718ffSArnaldo Carvalho de Melo 
66777faf4d0SStephane Eranian 			before->end = map->start;
66898dfd55dSArnaldo Carvalho de Melo 			map_groups__insert(mg, before);
669c6e718ffSArnaldo Carvalho de Melo 			if (verbose >= 2)
670c6e718ffSArnaldo Carvalho de Melo 				map__fprintf(before, fp);
671c6e718ffSArnaldo Carvalho de Melo 		}
672c6e718ffSArnaldo Carvalho de Melo 
673c6e718ffSArnaldo Carvalho de Melo 		if (map->end < pos->end) {
674c6e718ffSArnaldo Carvalho de Melo 			struct map *after = map__clone(pos);
675c6e718ffSArnaldo Carvalho de Melo 
6760a1eae39SArnaldo Carvalho de Melo 			if (after == NULL) {
6770a1eae39SArnaldo Carvalho de Melo 				err = -ENOMEM;
6780a1eae39SArnaldo Carvalho de Melo 				goto move_map;
6790a1eae39SArnaldo Carvalho de Melo 			}
680c6e718ffSArnaldo Carvalho de Melo 
68177faf4d0SStephane Eranian 			after->start = map->end;
68298dfd55dSArnaldo Carvalho de Melo 			map_groups__insert(mg, after);
683c6e718ffSArnaldo Carvalho de Melo 			if (verbose >= 2)
684c6e718ffSArnaldo Carvalho de Melo 				map__fprintf(after, fp);
685c6e718ffSArnaldo Carvalho de Melo 		}
6860a1eae39SArnaldo Carvalho de Melo move_map:
6870a1eae39SArnaldo Carvalho de Melo 		/*
6880a1eae39SArnaldo Carvalho de Melo 		 * If we have references, just move them to a separate list.
6890a1eae39SArnaldo Carvalho de Melo 		 */
6900a1eae39SArnaldo Carvalho de Melo 		if (pos->referenced)
69198dfd55dSArnaldo Carvalho de Melo 			list_add_tail(&pos->node, &mg->removed_maps[map->type]);
6920a1eae39SArnaldo Carvalho de Melo 		else
6930a1eae39SArnaldo Carvalho de Melo 			map__delete(pos);
6940a1eae39SArnaldo Carvalho de Melo 
6950a1eae39SArnaldo Carvalho de Melo 		if (err)
6960a1eae39SArnaldo Carvalho de Melo 			return err;
697c6e718ffSArnaldo Carvalho de Melo 	}
698c6e718ffSArnaldo Carvalho de Melo 
699c6e718ffSArnaldo Carvalho de Melo 	return 0;
700c6e718ffSArnaldo Carvalho de Melo }
701c6e718ffSArnaldo Carvalho de Melo 
702c6e718ffSArnaldo Carvalho de Melo /*
703c6e718ffSArnaldo Carvalho de Melo  * XXX This should not really _copy_ te maps, but refcount them.
704c6e718ffSArnaldo Carvalho de Melo  */
70598dfd55dSArnaldo Carvalho de Melo int map_groups__clone(struct map_groups *mg,
706c6e718ffSArnaldo Carvalho de Melo 		      struct map_groups *parent, enum map_type type)
707c6e718ffSArnaldo Carvalho de Melo {
708c6e718ffSArnaldo Carvalho de Melo 	struct rb_node *nd;
709c6e718ffSArnaldo Carvalho de Melo 	for (nd = rb_first(&parent->maps[type]); nd; nd = rb_next(nd)) {
710c6e718ffSArnaldo Carvalho de Melo 		struct map *map = rb_entry(nd, struct map, rb_node);
711c6e718ffSArnaldo Carvalho de Melo 		struct map *new = map__clone(map);
712c6e718ffSArnaldo Carvalho de Melo 		if (new == NULL)
713c6e718ffSArnaldo Carvalho de Melo 			return -ENOMEM;
71498dfd55dSArnaldo Carvalho de Melo 		map_groups__insert(mg, new);
715c6e718ffSArnaldo Carvalho de Melo 	}
716c6e718ffSArnaldo Carvalho de Melo 	return 0;
717c6e718ffSArnaldo Carvalho de Melo }
718c6e718ffSArnaldo Carvalho de Melo 
7194b8cf846SArnaldo Carvalho de Melo void maps__insert(struct rb_root *maps, struct map *map)
7204b8cf846SArnaldo Carvalho de Melo {
7214b8cf846SArnaldo Carvalho de Melo 	struct rb_node **p = &maps->rb_node;
7224b8cf846SArnaldo Carvalho de Melo 	struct rb_node *parent = NULL;
7234b8cf846SArnaldo Carvalho de Melo 	const u64 ip = map->start;
7244b8cf846SArnaldo Carvalho de Melo 	struct map *m;
7254b8cf846SArnaldo Carvalho de Melo 
7264b8cf846SArnaldo Carvalho de Melo 	while (*p != NULL) {
7274b8cf846SArnaldo Carvalho de Melo 		parent = *p;
7284b8cf846SArnaldo Carvalho de Melo 		m = rb_entry(parent, struct map, rb_node);
7294b8cf846SArnaldo Carvalho de Melo 		if (ip < m->start)
7304b8cf846SArnaldo Carvalho de Melo 			p = &(*p)->rb_left;
7314b8cf846SArnaldo Carvalho de Melo 		else
7324b8cf846SArnaldo Carvalho de Melo 			p = &(*p)->rb_right;
7334b8cf846SArnaldo Carvalho de Melo 	}
7344b8cf846SArnaldo Carvalho de Melo 
7354b8cf846SArnaldo Carvalho de Melo 	rb_link_node(&map->rb_node, parent, p);
7364b8cf846SArnaldo Carvalho de Melo 	rb_insert_color(&map->rb_node, maps);
7374b8cf846SArnaldo Carvalho de Melo }
7384b8cf846SArnaldo Carvalho de Melo 
739237a7e04SArnaldo Carvalho de Melo void maps__remove(struct rb_root *maps, struct map *map)
740076c6e45SArnaldo Carvalho de Melo {
741237a7e04SArnaldo Carvalho de Melo 	rb_erase(&map->rb_node, maps);
742076c6e45SArnaldo Carvalho de Melo }
743076c6e45SArnaldo Carvalho de Melo 
7444b8cf846SArnaldo Carvalho de Melo struct map *maps__find(struct rb_root *maps, u64 ip)
7454b8cf846SArnaldo Carvalho de Melo {
7464b8cf846SArnaldo Carvalho de Melo 	struct rb_node **p = &maps->rb_node;
7474b8cf846SArnaldo Carvalho de Melo 	struct rb_node *parent = NULL;
7484b8cf846SArnaldo Carvalho de Melo 	struct map *m;
7494b8cf846SArnaldo Carvalho de Melo 
7504b8cf846SArnaldo Carvalho de Melo 	while (*p != NULL) {
7514b8cf846SArnaldo Carvalho de Melo 		parent = *p;
7524b8cf846SArnaldo Carvalho de Melo 		m = rb_entry(parent, struct map, rb_node);
7534b8cf846SArnaldo Carvalho de Melo 		if (ip < m->start)
7544b8cf846SArnaldo Carvalho de Melo 			p = &(*p)->rb_left;
7554955ea22SNamhyung Kim 		else if (ip >= m->end)
7564b8cf846SArnaldo Carvalho de Melo 			p = &(*p)->rb_right;
7574b8cf846SArnaldo Carvalho de Melo 		else
7584b8cf846SArnaldo Carvalho de Melo 			return m;
7594b8cf846SArnaldo Carvalho de Melo 	}
7604b8cf846SArnaldo Carvalho de Melo 
7614b8cf846SArnaldo Carvalho de Melo 	return NULL;
7624b8cf846SArnaldo Carvalho de Melo }
7638e0cf965SAdrian Hunter 
7648e0cf965SAdrian Hunter struct map *maps__first(struct rb_root *maps)
7658e0cf965SAdrian Hunter {
7668e0cf965SAdrian Hunter 	struct rb_node *first = rb_first(maps);
7678e0cf965SAdrian Hunter 
7688e0cf965SAdrian Hunter 	if (first)
7698e0cf965SAdrian Hunter 		return rb_entry(first, struct map, rb_node);
7708e0cf965SAdrian Hunter 	return NULL;
7718e0cf965SAdrian Hunter }
7728e0cf965SAdrian Hunter 
7738e0cf965SAdrian Hunter struct map *maps__next(struct map *map)
7748e0cf965SAdrian Hunter {
7758e0cf965SAdrian Hunter 	struct rb_node *next = rb_next(&map->rb_node);
7768e0cf965SAdrian Hunter 
7778e0cf965SAdrian Hunter 	if (next)
7788e0cf965SAdrian Hunter 		return rb_entry(next, struct map, rb_node);
7798e0cf965SAdrian Hunter 	return NULL;
7808e0cf965SAdrian Hunter }
781ba92732eSWang Nan 
782ba92732eSWang Nan struct kmap *map__kmap(struct map *map)
783ba92732eSWang Nan {
784ba92732eSWang Nan 	if (!map->dso || !map->dso->kernel) {
785ba92732eSWang Nan 		pr_err("Internal error: map__kmap with a non-kernel map\n");
786ba92732eSWang Nan 		return NULL;
787ba92732eSWang Nan 	}
788ba92732eSWang Nan 	return (struct kmap *)(map + 1);
789ba92732eSWang Nan }
790ba92732eSWang Nan 
791ba92732eSWang Nan struct map_groups *map__kmaps(struct map *map)
792ba92732eSWang Nan {
793ba92732eSWang Nan 	struct kmap *kmap = map__kmap(map);
794ba92732eSWang Nan 
795ba92732eSWang Nan 	if (!kmap || !kmap->kmaps) {
796ba92732eSWang Nan 		pr_err("Internal error: map__kmaps with a non-kernel map\n");
797ba92732eSWang Nan 		return NULL;
798ba92732eSWang Nan 	}
799ba92732eSWang Nan 	return kmap->kmaps;
800ba92732eSWang Nan }
801