xref: /openbmc/linux/tools/perf/util/map.c (revision 5759a682)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
266e274f3SFrederic Weisbecker #include "symbol.h"
3c6e718ffSArnaldo Carvalho de Melo #include <errno.h>
49486aa38SArnaldo Carvalho de Melo #include <inttypes.h>
54b8cf846SArnaldo Carvalho de Melo #include <limits.h>
666e274f3SFrederic Weisbecker #include <stdlib.h>
766e274f3SFrederic Weisbecker #include <string.h>
866e274f3SFrederic Weisbecker #include <stdio.h>
9a1645ce1SZhang, Yanmin #include <unistd.h>
10fbef103fSArnaldo Carvalho de Melo #include <uapi/linux/mman.h> /* To get things like MAP_HUGETLB even on older libc headers */
114b8cf846SArnaldo Carvalho de Melo #include "map.h"
125cd95c2dSDavid Ahern #include "thread.h"
137dbf4dcfSJiri Olsa #include "vdso.h"
14ebb296c2SJiri Olsa #include "build-id.h"
15cc8fae1dSAdrian Hunter #include "util.h"
16acebd408SJiri Olsa #include "debug.h"
172a03068cSAdrian Hunter #include "machine.h"
188e16017dSArnaldo Carvalho de Melo #include <linux/string.h>
19632a5cabSArnaldo Carvalho de Melo #include "srcline.h"
20843ff37bSKrister Johansen #include "namespaces.h"
216c502584SJiri Olsa #include "unwind.h"
2266e274f3SFrederic Weisbecker 
236a2ffcddSArnaldo Carvalho de Melo static void __maps__insert(struct maps *maps, struct map *map);
246a2ffcddSArnaldo Carvalho de Melo 
250ac3348eSWang Nan static inline int is_anon_memory(const char *filename, u32 flags)
2666e274f3SFrederic Weisbecker {
27fbef103fSArnaldo Carvalho de Melo 	return flags & MAP_HUGETLB ||
280ac3348eSWang Nan 	       !strcmp(filename, "//anon") ||
29b2be5451SYannick Brosseau 	       !strncmp(filename, "/dev/zero", sizeof("/dev/zero") - 1) ||
30b2be5451SYannick Brosseau 	       !strncmp(filename, "/anon_hugepage", sizeof("/anon_hugepage") - 1);
3166e274f3SFrederic Weisbecker }
3266e274f3SFrederic Weisbecker 
3387ffef79SJiri Olsa static inline int is_no_dso_memory(const char *filename)
3487ffef79SJiri Olsa {
351e82574dSNamhyung Kim 	return !strncmp(filename, "[stack", 6) ||
36700be564SDon Zickus 	       !strncmp(filename, "/SYSV",5)   ||
3787ffef79SJiri Olsa 	       !strcmp(filename, "[heap]");
3887ffef79SJiri Olsa }
3987ffef79SJiri Olsa 
40eca81836SMichael Lentine static inline int is_android_lib(const char *filename)
41eca81836SMichael Lentine {
42eca81836SMichael Lentine 	return !strncmp(filename, "/data/app-lib", 13) ||
43eca81836SMichael Lentine 	       !strncmp(filename, "/system/lib", 11);
44eca81836SMichael Lentine }
45eca81836SMichael Lentine 
46eca81836SMichael Lentine static inline bool replace_android_lib(const char *filename, char *newfilename)
47eca81836SMichael Lentine {
48eca81836SMichael Lentine 	const char *libname;
49eca81836SMichael Lentine 	char *app_abi;
50eca81836SMichael Lentine 	size_t app_abi_length, new_length;
51eca81836SMichael Lentine 	size_t lib_length = 0;
52eca81836SMichael Lentine 
53eca81836SMichael Lentine 	libname  = strrchr(filename, '/');
54eca81836SMichael Lentine 	if (libname)
55eca81836SMichael Lentine 		lib_length = strlen(libname);
56eca81836SMichael Lentine 
57eca81836SMichael Lentine 	app_abi = getenv("APP_ABI");
58eca81836SMichael Lentine 	if (!app_abi)
59eca81836SMichael Lentine 		return false;
60eca81836SMichael Lentine 
61eca81836SMichael Lentine 	app_abi_length = strlen(app_abi);
62eca81836SMichael Lentine 
63eca81836SMichael Lentine 	if (!strncmp(filename, "/data/app-lib", 13)) {
64eca81836SMichael Lentine 		char *apk_path;
65eca81836SMichael Lentine 
66eca81836SMichael Lentine 		if (!app_abi_length)
67eca81836SMichael Lentine 			return false;
68eca81836SMichael Lentine 
69eca81836SMichael Lentine 		new_length = 7 + app_abi_length + lib_length;
70eca81836SMichael Lentine 
71eca81836SMichael Lentine 		apk_path = getenv("APK_PATH");
72eca81836SMichael Lentine 		if (apk_path) {
73eca81836SMichael Lentine 			new_length += strlen(apk_path) + 1;
74eca81836SMichael Lentine 			if (new_length > PATH_MAX)
75eca81836SMichael Lentine 				return false;
76eca81836SMichael Lentine 			snprintf(newfilename, new_length,
77eca81836SMichael Lentine 				 "%s/libs/%s/%s", apk_path, app_abi, libname);
78eca81836SMichael Lentine 		} else {
79eca81836SMichael Lentine 			if (new_length > PATH_MAX)
80eca81836SMichael Lentine 				return false;
81eca81836SMichael Lentine 			snprintf(newfilename, new_length,
82eca81836SMichael Lentine 				 "libs/%s/%s", app_abi, libname);
83eca81836SMichael Lentine 		}
84eca81836SMichael Lentine 		return true;
85eca81836SMichael Lentine 	}
86eca81836SMichael Lentine 
87eca81836SMichael Lentine 	if (!strncmp(filename, "/system/lib/", 11)) {
88eca81836SMichael Lentine 		char *ndk, *app;
89eca81836SMichael Lentine 		const char *arch;
90eca81836SMichael Lentine 		size_t ndk_length;
91eca81836SMichael Lentine 		size_t app_length;
92eca81836SMichael Lentine 
93eca81836SMichael Lentine 		ndk = getenv("NDK_ROOT");
94eca81836SMichael Lentine 		app = getenv("APP_PLATFORM");
95eca81836SMichael Lentine 
96eca81836SMichael Lentine 		if (!(ndk && app))
97eca81836SMichael Lentine 			return false;
98eca81836SMichael Lentine 
99eca81836SMichael Lentine 		ndk_length = strlen(ndk);
100eca81836SMichael Lentine 		app_length = strlen(app);
101eca81836SMichael Lentine 
102eca81836SMichael Lentine 		if (!(ndk_length && app_length && app_abi_length))
103eca81836SMichael Lentine 			return false;
104eca81836SMichael Lentine 
105eca81836SMichael Lentine 		arch = !strncmp(app_abi, "arm", 3) ? "arm" :
106eca81836SMichael Lentine 		       !strncmp(app_abi, "mips", 4) ? "mips" :
107eca81836SMichael Lentine 		       !strncmp(app_abi, "x86", 3) ? "x86" : NULL;
108eca81836SMichael Lentine 
109eca81836SMichael Lentine 		if (!arch)
110eca81836SMichael Lentine 			return false;
111eca81836SMichael Lentine 
112eca81836SMichael Lentine 		new_length = 27 + ndk_length +
113eca81836SMichael Lentine 			     app_length + lib_length
114eca81836SMichael Lentine 			   + strlen(arch);
115eca81836SMichael Lentine 
116eca81836SMichael Lentine 		if (new_length > PATH_MAX)
117eca81836SMichael Lentine 			return false;
118eca81836SMichael Lentine 		snprintf(newfilename, new_length,
119eca81836SMichael Lentine 			"%s/platforms/%s/arch-%s/usr/lib/%s",
120eca81836SMichael Lentine 			ndk, app, arch, libname);
121eca81836SMichael Lentine 
122eca81836SMichael Lentine 		return true;
123eca81836SMichael Lentine 	}
124eca81836SMichael Lentine 	return false;
125eca81836SMichael Lentine }
126eca81836SMichael Lentine 
1273183f8caSArnaldo Carvalho de Melo void map__init(struct map *map, u64 start, u64 end, u64 pgoff, struct dso *dso)
128afb7b4f0SArnaldo Carvalho de Melo {
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;
133d3a7c489SArnaldo Carvalho de Melo 	map->dso      = dso__get(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->erange_warned = false;
139e3a42cddSElena Reshetova 	refcount_set(&map->refcnt, 1);
140afb7b4f0SArnaldo Carvalho de Melo }
141afb7b4f0SArnaldo Carvalho de Melo 
1422a03068cSAdrian Hunter struct map *map__new(struct machine *machine, u64 start, u64 len,
143bf2e710bSKrister Johansen 		     u64 pgoff, u32 d_maj, u32 d_min, u64 ino,
1447ef80703SDon Zickus 		     u64 ino_gen, u32 prot, u32 flags, char *filename,
1453183f8caSArnaldo Carvalho de Melo 		     struct thread *thread)
14666e274f3SFrederic Weisbecker {
147237a7e04SArnaldo Carvalho de Melo 	struct map *map = malloc(sizeof(*map));
148bf2e710bSKrister Johansen 	struct nsinfo *nsi = NULL;
149bf2e710bSKrister Johansen 	struct nsinfo *nnsi;
15066e274f3SFrederic Weisbecker 
151237a7e04SArnaldo Carvalho de Melo 	if (map != NULL) {
15266e274f3SFrederic Weisbecker 		char newfilename[PATH_MAX];
153afb7b4f0SArnaldo Carvalho de Melo 		struct dso *dso;
154eca81836SMichael Lentine 		int anon, no_dso, vdso, android;
15566e274f3SFrederic Weisbecker 
156eca81836SMichael Lentine 		android = is_android_lib(filename);
1570ac3348eSWang Nan 		anon = is_anon_memory(filename, flags);
1587dbf4dcfSJiri Olsa 		vdso = is_vdso_map(filename);
15987ffef79SJiri Olsa 		no_dso = is_no_dso_memory(filename);
16066e274f3SFrederic Weisbecker 
1615c5e854bSStephane Eranian 		map->maj = d_maj;
1625c5e854bSStephane Eranian 		map->min = d_min;
1635c5e854bSStephane Eranian 		map->ino = ino;
1645c5e854bSStephane Eranian 		map->ino_generation = ino_gen;
1657ef80703SDon Zickus 		map->prot = prot;
1667ef80703SDon Zickus 		map->flags = flags;
167bf2e710bSKrister Johansen 		nsi = nsinfo__get(thread->nsinfo);
1685c5e854bSStephane Eranian 
169d183b261SArnaldo Carvalho de Melo 		if ((anon || no_dso) && nsi && (prot & PROT_EXEC)) {
170bf2e710bSKrister Johansen 			snprintf(newfilename, sizeof(newfilename),
171bf2e710bSKrister Johansen 				 "/tmp/perf-%d.map", nsi->pid);
17266e274f3SFrederic Weisbecker 			filename = newfilename;
17366e274f3SFrederic Weisbecker 		}
17466e274f3SFrederic Weisbecker 
175eca81836SMichael Lentine 		if (android) {
176eca81836SMichael Lentine 			if (replace_android_lib(filename, newfilename))
177eca81836SMichael Lentine 				filename = newfilename;
178eca81836SMichael Lentine 		}
179eca81836SMichael Lentine 
1807dbf4dcfSJiri Olsa 		if (vdso) {
181bf2e710bSKrister Johansen 			/* The vdso maps are always on the host and not the
182bf2e710bSKrister Johansen 			 * container.  Ensure that we don't use setns to look
183bf2e710bSKrister Johansen 			 * them up.
184bf2e710bSKrister Johansen 			 */
185bf2e710bSKrister Johansen 			nnsi = nsinfo__copy(nsi);
186bf2e710bSKrister Johansen 			if (nnsi) {
187bf2e710bSKrister Johansen 				nsinfo__put(nsi);
188bf2e710bSKrister Johansen 				nnsi->need_setns = false;
189bf2e710bSKrister Johansen 				nsi = nnsi;
190bf2e710bSKrister Johansen 			}
1917dbf4dcfSJiri Olsa 			pgoff = 0;
1929a4388c7SArnaldo Carvalho de Melo 			dso = machine__findnew_vdso(machine, thread);
1937dbf4dcfSJiri Olsa 		} else
194aa7cc2aeSArnaldo Carvalho de Melo 			dso = machine__findnew_dso(machine, filename);
1957dbf4dcfSJiri Olsa 
196afb7b4f0SArnaldo Carvalho de Melo 		if (dso == NULL)
19766e274f3SFrederic Weisbecker 			goto out_delete;
19866e274f3SFrederic Weisbecker 
1993183f8caSArnaldo Carvalho de Melo 		map__init(map, start, start + len, pgoff, dso);
200afb7b4f0SArnaldo Carvalho de Melo 
20187ffef79SJiri Olsa 		if (anon || no_dso) {
202237a7e04SArnaldo Carvalho de Melo 			map->map_ip = map->unmap_ip = identity__map_ip;
20387ffef79SJiri Olsa 
20487ffef79SJiri Olsa 			/*
20587ffef79SJiri Olsa 			 * Set memory without DSO as loaded. All map__find_*
20687ffef79SJiri Olsa 			 * functions still return NULL, and we avoid the
20787ffef79SJiri Olsa 			 * unnecessary map__load warning.
20887ffef79SJiri Olsa 			 */
209d183b261SArnaldo Carvalho de Melo 			if (!(prot & PROT_EXEC))
2103183f8caSArnaldo Carvalho de Melo 				dso__set_loaded(dso);
2118d92c02aSArnaldo Carvalho de Melo 		}
212bf2e710bSKrister Johansen 		dso->nsinfo = nsi;
213d3a7c489SArnaldo Carvalho de Melo 		dso__put(dso);
21466e274f3SFrederic Weisbecker 	}
215237a7e04SArnaldo Carvalho de Melo 	return map;
21666e274f3SFrederic Weisbecker out_delete:
217bf2e710bSKrister Johansen 	nsinfo__put(nsi);
218237a7e04SArnaldo Carvalho de Melo 	free(map);
21966e274f3SFrederic Weisbecker 	return NULL;
22066e274f3SFrederic Weisbecker }
22166e274f3SFrederic Weisbecker 
222e5a1845fSNamhyung Kim /*
223e5a1845fSNamhyung Kim  * Constructor variant for modules (where we know from /proc/modules where
224e5a1845fSNamhyung Kim  * they are loaded) and for vmlinux, where only after we load all the
225e5a1845fSNamhyung Kim  * symbols we'll know where it starts and ends.
226e5a1845fSNamhyung Kim  */
2273183f8caSArnaldo Carvalho de Melo struct map *map__new2(u64 start, struct dso *dso)
228e5a1845fSNamhyung Kim {
229e5a1845fSNamhyung Kim 	struct map *map = calloc(1, (sizeof(*map) +
230e5a1845fSNamhyung Kim 				     (dso->kernel ? sizeof(struct kmap) : 0)));
231e5a1845fSNamhyung Kim 	if (map != NULL) {
232e5a1845fSNamhyung Kim 		/*
233e5a1845fSNamhyung Kim 		 * ->end will be filled after we load all the symbols
234e5a1845fSNamhyung Kim 		 */
2353183f8caSArnaldo Carvalho de Melo 		map__init(map, start, 0, 0, dso);
236e5a1845fSNamhyung Kim 	}
237e5a1845fSNamhyung Kim 
238e5a1845fSNamhyung Kim 	return map;
239e5a1845fSNamhyung Kim }
240e5a1845fSNamhyung Kim 
241e6ce7126SArnaldo Carvalho de Melo /*
242e6ce7126SArnaldo Carvalho de Melo  * Use this and __map__is_kmodule() for map instances that are in
243e6ce7126SArnaldo Carvalho de Melo  * machine->kmaps, and thus have map->groups->machine all properly set, to
244e6ce7126SArnaldo Carvalho de Melo  * disambiguate between the kernel and modules.
245e6ce7126SArnaldo Carvalho de Melo  *
246e6ce7126SArnaldo Carvalho de Melo  * When the need arises, introduce map__is_{kernel,kmodule)() that
247e6ce7126SArnaldo Carvalho de Melo  * checks (map->groups != NULL && map->groups->machine != NULL &&
248e6ce7126SArnaldo Carvalho de Melo  * map->dso->kernel) before calling __map__is_{kernel,kmodule}())
249e6ce7126SArnaldo Carvalho de Melo  */
250e6ce7126SArnaldo Carvalho de Melo bool __map__is_kernel(const struct map *map)
251e6ce7126SArnaldo Carvalho de Melo {
2523183f8caSArnaldo Carvalho de Melo 	return machine__kernel_map(map->groups->machine) == map;
253e6ce7126SArnaldo Carvalho de Melo }
254e6ce7126SArnaldo Carvalho de Melo 
2555759a682SAdrian Hunter bool __map__is_extra_kernel_map(const struct map *map)
2565759a682SAdrian Hunter {
2575759a682SAdrian Hunter 	struct kmap *kmap = __map__kmap((struct map *)map);
2585759a682SAdrian Hunter 
2595759a682SAdrian Hunter 	return kmap && kmap->name[0];
2605759a682SAdrian Hunter }
2615759a682SAdrian Hunter 
262e94b861aSArnaldo Carvalho de Melo bool map__has_symbols(const struct map *map)
263e94b861aSArnaldo Carvalho de Melo {
2643183f8caSArnaldo Carvalho de Melo 	return dso__has_symbols(map->dso);
265e94b861aSArnaldo Carvalho de Melo }
266e94b861aSArnaldo Carvalho de Melo 
267d3a7c489SArnaldo Carvalho de Melo static void map__exit(struct map *map)
268c338aee8SArnaldo Carvalho de Melo {
269facf3f06SArnaldo Carvalho de Melo 	BUG_ON(!RB_EMPTY_NODE(&map->rb_node));
270d3a7c489SArnaldo Carvalho de Melo 	dso__zput(map->dso);
271d3a7c489SArnaldo Carvalho de Melo }
272d3a7c489SArnaldo Carvalho de Melo 
273d3a7c489SArnaldo Carvalho de Melo void map__delete(struct map *map)
274d3a7c489SArnaldo Carvalho de Melo {
275d3a7c489SArnaldo Carvalho de Melo 	map__exit(map);
276237a7e04SArnaldo Carvalho de Melo 	free(map);
277c338aee8SArnaldo Carvalho de Melo }
278c338aee8SArnaldo Carvalho de Melo 
27984c2cafaSArnaldo Carvalho de Melo void map__put(struct map *map)
28084c2cafaSArnaldo Carvalho de Melo {
281e3a42cddSElena Reshetova 	if (map && refcount_dec_and_test(&map->refcnt))
28284c2cafaSArnaldo Carvalho de Melo 		map__delete(map);
28384c2cafaSArnaldo Carvalho de Melo }
28484c2cafaSArnaldo Carvalho de Melo 
285237a7e04SArnaldo Carvalho de Melo void map__fixup_start(struct map *map)
286c338aee8SArnaldo Carvalho de Melo {
2873183f8caSArnaldo Carvalho de Melo 	struct rb_root *symbols = &map->dso->symbols;
288fcf1203aSArnaldo Carvalho de Melo 	struct rb_node *nd = rb_first(symbols);
289c338aee8SArnaldo Carvalho de Melo 	if (nd != NULL) {
290c338aee8SArnaldo Carvalho de Melo 		struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
291237a7e04SArnaldo Carvalho de Melo 		map->start = sym->start;
292c338aee8SArnaldo Carvalho de Melo 	}
293c338aee8SArnaldo Carvalho de Melo }
294c338aee8SArnaldo Carvalho de Melo 
295237a7e04SArnaldo Carvalho de Melo void map__fixup_end(struct map *map)
296c338aee8SArnaldo Carvalho de Melo {
2973183f8caSArnaldo Carvalho de Melo 	struct rb_root *symbols = &map->dso->symbols;
298fcf1203aSArnaldo Carvalho de Melo 	struct rb_node *nd = rb_last(symbols);
299c338aee8SArnaldo Carvalho de Melo 	if (nd != NULL) {
300c338aee8SArnaldo Carvalho de Melo 		struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
301237a7e04SArnaldo Carvalho de Melo 		map->end = sym->end;
302c338aee8SArnaldo Carvalho de Melo 	}
303c338aee8SArnaldo Carvalho de Melo }
304c338aee8SArnaldo Carvalho de Melo 
305d70a5402SArnaldo Carvalho de Melo #define DSO__DELETED "(deleted)"
306d70a5402SArnaldo Carvalho de Melo 
307be39db9fSArnaldo Carvalho de Melo int map__load(struct map *map)
30866bd8424SArnaldo Carvalho de Melo {
309237a7e04SArnaldo Carvalho de Melo 	const char *name = map->dso->long_name;
310a128168dSMasami Hiramatsu 	int nr;
31166bd8424SArnaldo Carvalho de Melo 
3123183f8caSArnaldo Carvalho de Melo 	if (dso__loaded(map->dso))
313a128168dSMasami Hiramatsu 		return 0;
314a128168dSMasami Hiramatsu 
315be39db9fSArnaldo Carvalho de Melo 	nr = dso__load(map->dso, map);
31666bd8424SArnaldo Carvalho de Melo 	if (nr < 0) {
317237a7e04SArnaldo Carvalho de Melo 		if (map->dso->has_build_id) {
318b5d8bbe8SMasami Hiramatsu 			char sbuild_id[SBUILD_ID_SIZE];
3198d06367fSArnaldo Carvalho de Melo 
320237a7e04SArnaldo Carvalho de Melo 			build_id__sprintf(map->dso->build_id,
321237a7e04SArnaldo Carvalho de Melo 					  sizeof(map->dso->build_id),
3228d06367fSArnaldo Carvalho de Melo 					  sbuild_id);
3238d06367fSArnaldo Carvalho de Melo 			pr_warning("%s with build id %s not found",
32479406cd7SArnaldo Carvalho de Melo 				   name, sbuild_id);
3258d06367fSArnaldo Carvalho de Melo 		} else
32679406cd7SArnaldo Carvalho de Melo 			pr_warning("Failed to open %s", name);
32779406cd7SArnaldo Carvalho de Melo 
3288d06367fSArnaldo Carvalho de Melo 		pr_warning(", continuing without symbols\n");
32979406cd7SArnaldo Carvalho de Melo 		return -1;
33066bd8424SArnaldo Carvalho de Melo 	} else if (nr == 0) {
33189fe808aSIngo Molnar #ifdef HAVE_LIBELF_SUPPORT
332d70a5402SArnaldo Carvalho de Melo 		const size_t len = strlen(name);
333d70a5402SArnaldo Carvalho de Melo 		const size_t real_len = len - sizeof(DSO__DELETED);
334d70a5402SArnaldo Carvalho de Melo 
335d70a5402SArnaldo Carvalho de Melo 		if (len > sizeof(DSO__DELETED) &&
336900b20d5SIngo Molnar 		    strcmp(name + real_len + 1, DSO__DELETED) == 0) {
337e77b15bdSDavid Ahern 			pr_warning("%.*s was updated (is prelink enabled?). "
338e77b15bdSDavid Ahern 				"Restart the long running apps that use it!\n",
339900b20d5SIngo Molnar 				   (int)real_len, name);
340900b20d5SIngo Molnar 		} else {
34179406cd7SArnaldo Carvalho de Melo 			pr_warning("no symbols found in %s, maybe install "
34279406cd7SArnaldo Carvalho de Melo 				   "a debug package?\n", name);
34366bd8424SArnaldo Carvalho de Melo 		}
344393be2e3SNamhyung Kim #endif
34579406cd7SArnaldo Carvalho de Melo 		return -1;
34679406cd7SArnaldo Carvalho de Melo 	}
34779406cd7SArnaldo Carvalho de Melo 
34879406cd7SArnaldo Carvalho de Melo 	return 0;
34979406cd7SArnaldo Carvalho de Melo }
35079406cd7SArnaldo Carvalho de Melo 
351be39db9fSArnaldo Carvalho de Melo struct symbol *map__find_symbol(struct map *map, u64 addr)
35279406cd7SArnaldo Carvalho de Melo {
353be39db9fSArnaldo Carvalho de Melo 	if (map__load(map) < 0)
35479406cd7SArnaldo Carvalho de Melo 		return NULL;
35579406cd7SArnaldo Carvalho de Melo 
3563183f8caSArnaldo Carvalho de Melo 	return dso__find_symbol(map->dso, addr);
35766bd8424SArnaldo Carvalho de Melo }
35866bd8424SArnaldo Carvalho de Melo 
359be39db9fSArnaldo Carvalho de Melo struct symbol *map__find_symbol_by_name(struct map *map, const char *name)
36079406cd7SArnaldo Carvalho de Melo {
361be39db9fSArnaldo Carvalho de Melo 	if (map__load(map) < 0)
36279406cd7SArnaldo Carvalho de Melo 		return NULL;
36379406cd7SArnaldo Carvalho de Melo 
3643183f8caSArnaldo Carvalho de Melo 	if (!dso__sorted_by_name(map->dso))
3653183f8caSArnaldo Carvalho de Melo 		dso__sort_by_name(map->dso);
36679406cd7SArnaldo Carvalho de Melo 
3673183f8caSArnaldo Carvalho de Melo 	return dso__find_symbol_by_name(map->dso, name);
36879406cd7SArnaldo Carvalho de Melo }
36979406cd7SArnaldo Carvalho de Melo 
37066671d00SArnaldo Carvalho de Melo struct map *map__clone(struct map *from)
37166e274f3SFrederic Weisbecker {
37266671d00SArnaldo Carvalho de Melo 	struct map *map = memdup(from, sizeof(*map));
37366671d00SArnaldo Carvalho de Melo 
37466671d00SArnaldo Carvalho de Melo 	if (map != NULL) {
375e3a42cddSElena Reshetova 		refcount_set(&map->refcnt, 1);
37666671d00SArnaldo Carvalho de Melo 		RB_CLEAR_NODE(&map->rb_node);
37766671d00SArnaldo Carvalho de Melo 		dso__get(map->dso);
37866671d00SArnaldo Carvalho de Melo 		map->groups = NULL;
37966671d00SArnaldo Carvalho de Melo 	}
38066671d00SArnaldo Carvalho de Melo 
38166671d00SArnaldo Carvalho de Melo 	return map;
38266e274f3SFrederic Weisbecker }
38366e274f3SFrederic Weisbecker 
38466e274f3SFrederic Weisbecker int map__overlap(struct map *l, struct map *r)
38566e274f3SFrederic Weisbecker {
38666e274f3SFrederic Weisbecker 	if (l->start > r->start) {
38766e274f3SFrederic Weisbecker 		struct map *t = l;
38866e274f3SFrederic Weisbecker 		l = r;
38966e274f3SFrederic Weisbecker 		r = t;
39066e274f3SFrederic Weisbecker 	}
39166e274f3SFrederic Weisbecker 
39266e274f3SFrederic Weisbecker 	if (l->end > r->start)
39366e274f3SFrederic Weisbecker 		return 1;
39466e274f3SFrederic Weisbecker 
39566e274f3SFrederic Weisbecker 	return 0;
39666e274f3SFrederic Weisbecker }
39766e274f3SFrederic Weisbecker 
398237a7e04SArnaldo Carvalho de Melo size_t map__fprintf(struct map *map, FILE *fp)
39966e274f3SFrederic Weisbecker {
4009486aa38SArnaldo Carvalho de Melo 	return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %" PRIx64 " %s\n",
401237a7e04SArnaldo Carvalho de Melo 		       map->start, map->end, map->pgoff, map->dso->name);
40266e274f3SFrederic Weisbecker }
4037a2b6209SKirill Smelkov 
404547a92e0SAkihiro Nagai size_t map__fprintf_dsoname(struct map *map, FILE *fp)
405547a92e0SAkihiro Nagai {
4068f28f19aSFeng Tang 	const char *dsoname = "[unknown]";
407547a92e0SAkihiro Nagai 
4085eae7d84SArnaldo Carvalho de Melo 	if (map && map->dso) {
4090bc8d205SAkihiro Nagai 		if (symbol_conf.show_kernel_path && map->dso->long_name)
4100bc8d205SAkihiro Nagai 			dsoname = map->dso->long_name;
4115eae7d84SArnaldo Carvalho de Melo 		else
412547a92e0SAkihiro Nagai 			dsoname = map->dso->name;
4138f28f19aSFeng Tang 	}
414547a92e0SAkihiro Nagai 
415547a92e0SAkihiro Nagai 	return fprintf(fp, "%s", dsoname);
416547a92e0SAkihiro Nagai }
417547a92e0SAkihiro Nagai 
418cc8fae1dSAdrian Hunter int map__fprintf_srcline(struct map *map, u64 addr, const char *prefix,
419cc8fae1dSAdrian Hunter 			 FILE *fp)
420cc8fae1dSAdrian Hunter {
421cc8fae1dSAdrian Hunter 	char *srcline;
422cc8fae1dSAdrian Hunter 	int ret = 0;
423cc8fae1dSAdrian Hunter 
424cc8fae1dSAdrian Hunter 	if (map && map->dso) {
425cc8fae1dSAdrian Hunter 		srcline = get_srcline(map->dso,
4265dfa210eSMilian Wolff 				      map__rip_2objdump(map, addr), NULL,
427935f5a9dSJin Yao 				      true, true, addr);
428cc8fae1dSAdrian Hunter 		if (srcline != SRCLINE_UNKNOWN)
429cc8fae1dSAdrian Hunter 			ret = fprintf(fp, "%s%s", prefix, srcline);
430cc8fae1dSAdrian Hunter 		free_srcline(srcline);
431cc8fae1dSAdrian Hunter 	}
432cc8fae1dSAdrian Hunter 	return ret;
433cc8fae1dSAdrian Hunter }
434cc8fae1dSAdrian Hunter 
4351d5077bdSAdrian Hunter /**
4361d5077bdSAdrian Hunter  * map__rip_2objdump - convert symbol start address to objdump address.
4371d5077bdSAdrian Hunter  * @map: memory map
4381d5077bdSAdrian Hunter  * @rip: symbol start address
4391d5077bdSAdrian Hunter  *
4407a2b6209SKirill Smelkov  * objdump wants/reports absolute IPs for ET_EXEC, and RIPs for ET_DYN.
4410131c4ecSAdrian Hunter  * map->dso->adjust_symbols==1 for ET_EXEC-like cases except ET_REL which is
4420131c4ecSAdrian Hunter  * relative to section start.
4431d5077bdSAdrian Hunter  *
4441d5077bdSAdrian Hunter  * Return: Address suitable for passing to "objdump --start-address="
4457a2b6209SKirill Smelkov  */
4467a2b6209SKirill Smelkov u64 map__rip_2objdump(struct map *map, u64 rip)
4477a2b6209SKirill Smelkov {
4480131c4ecSAdrian Hunter 	if (!map->dso->adjust_symbols)
4490131c4ecSAdrian Hunter 		return rip;
4500131c4ecSAdrian Hunter 
4510131c4ecSAdrian Hunter 	if (map->dso->rel)
4520131c4ecSAdrian Hunter 		return rip - map->pgoff;
4530131c4ecSAdrian Hunter 
454a58f7033SWang Nan 	/*
455a58f7033SWang Nan 	 * kernel modules also have DSO_TYPE_USER in dso->kernel,
456a58f7033SWang Nan 	 * but all kernel modules are ET_REL, so won't get here.
457a58f7033SWang Nan 	 */
458a58f7033SWang Nan 	if (map->dso->kernel == DSO_TYPE_USER)
459a58f7033SWang Nan 		return rip + map->dso->text_offset;
460a58f7033SWang Nan 
4619176753dSAdrian Hunter 	return map->unmap_ip(map, rip) - map->reloc;
4627a2b6209SKirill Smelkov }
463ee11b90bSKirill Smelkov 
4641d5077bdSAdrian Hunter /**
4651d5077bdSAdrian Hunter  * map__objdump_2mem - convert objdump address to a memory address.
4661d5077bdSAdrian Hunter  * @map: memory map
4671d5077bdSAdrian Hunter  * @ip: objdump address
4681d5077bdSAdrian Hunter  *
4691d5077bdSAdrian Hunter  * Closely related to map__rip_2objdump(), this function takes an address from
4701d5077bdSAdrian Hunter  * objdump and converts it to a memory address.  Note this assumes that @map
4711d5077bdSAdrian Hunter  * contains the address.  To be sure the result is valid, check it forwards
4721d5077bdSAdrian Hunter  * e.g. map__rip_2objdump(map->map_ip(map, map__objdump_2mem(map, ip))) == ip
4731d5077bdSAdrian Hunter  *
4741d5077bdSAdrian Hunter  * Return: Memory address.
4751d5077bdSAdrian Hunter  */
4761d5077bdSAdrian Hunter u64 map__objdump_2mem(struct map *map, u64 ip)
4771d5077bdSAdrian Hunter {
4781d5077bdSAdrian Hunter 	if (!map->dso->adjust_symbols)
4791d5077bdSAdrian Hunter 		return map->unmap_ip(map, ip);
4801d5077bdSAdrian Hunter 
4811d5077bdSAdrian Hunter 	if (map->dso->rel)
4821d5077bdSAdrian Hunter 		return map->unmap_ip(map, ip + map->pgoff);
4831d5077bdSAdrian Hunter 
484a58f7033SWang Nan 	/*
485a58f7033SWang Nan 	 * kernel modules also have DSO_TYPE_USER in dso->kernel,
486a58f7033SWang Nan 	 * but all kernel modules are ET_REL, so won't get here.
487a58f7033SWang Nan 	 */
488a58f7033SWang Nan 	if (map->dso->kernel == DSO_TYPE_USER)
489a58f7033SWang Nan 		return map->unmap_ip(map, ip - map->dso->text_offset);
490a58f7033SWang Nan 
4919176753dSAdrian Hunter 	return ip + map->reloc;
4921d5077bdSAdrian Hunter }
4931d5077bdSAdrian Hunter 
4941eee78aeSArnaldo Carvalho de Melo static void maps__init(struct maps *maps)
4951eee78aeSArnaldo Carvalho de Melo {
4961eee78aeSArnaldo Carvalho de Melo 	maps->entries = RB_ROOT;
4970a7c74eaSArnaldo Carvalho de Melo 	init_rwsem(&maps->lock);
4981eee78aeSArnaldo Carvalho de Melo }
4991eee78aeSArnaldo Carvalho de Melo 
50011246c70SArnaldo Carvalho de Melo void map_groups__init(struct map_groups *mg, struct machine *machine)
501c6e718ffSArnaldo Carvalho de Melo {
5023183f8caSArnaldo Carvalho de Melo 	maps__init(&mg->maps);
50311246c70SArnaldo Carvalho de Melo 	mg->machine = machine;
504ead05e8fSElena Reshetova 	refcount_set(&mg->refcnt, 1);
505c6e718ffSArnaldo Carvalho de Melo }
506c6e718ffSArnaldo Carvalho de Melo 
5076a2ffcddSArnaldo Carvalho de Melo static void __maps__purge(struct maps *maps)
508591765fdSArnaldo Carvalho de Melo {
5091eee78aeSArnaldo Carvalho de Melo 	struct rb_root *root = &maps->entries;
5101eee78aeSArnaldo Carvalho de Melo 	struct rb_node *next = rb_first(root);
511591765fdSArnaldo Carvalho de Melo 
512591765fdSArnaldo Carvalho de Melo 	while (next) {
513591765fdSArnaldo Carvalho de Melo 		struct map *pos = rb_entry(next, struct map, rb_node);
514591765fdSArnaldo Carvalho de Melo 
515591765fdSArnaldo Carvalho de Melo 		next = rb_next(&pos->rb_node);
516facf3f06SArnaldo Carvalho de Melo 		rb_erase_init(&pos->rb_node, root);
51784c2cafaSArnaldo Carvalho de Melo 		map__put(pos);
518591765fdSArnaldo Carvalho de Melo 	}
519591765fdSArnaldo Carvalho de Melo }
520591765fdSArnaldo Carvalho de Melo 
5211eee78aeSArnaldo Carvalho de Melo static void maps__exit(struct maps *maps)
5221eee78aeSArnaldo Carvalho de Melo {
5230a7c74eaSArnaldo Carvalho de Melo 	down_write(&maps->lock);
5246a2ffcddSArnaldo Carvalho de Melo 	__maps__purge(maps);
5250a7c74eaSArnaldo Carvalho de Melo 	up_write(&maps->lock);
5261eee78aeSArnaldo Carvalho de Melo }
5271eee78aeSArnaldo Carvalho de Melo 
52898dfd55dSArnaldo Carvalho de Melo void map_groups__exit(struct map_groups *mg)
529591765fdSArnaldo Carvalho de Melo {
5303183f8caSArnaldo Carvalho de Melo 	maps__exit(&mg->maps);
531591765fdSArnaldo Carvalho de Melo }
532591765fdSArnaldo Carvalho de Melo 
53329ce3612SAdrian Hunter bool map_groups__empty(struct map_groups *mg)
53429ce3612SAdrian Hunter {
5353183f8caSArnaldo Carvalho de Melo 	return !maps__first(&mg->maps);
53629ce3612SAdrian Hunter }
53729ce3612SAdrian Hunter 
53811246c70SArnaldo Carvalho de Melo struct map_groups *map_groups__new(struct machine *machine)
53993d5731dSArnaldo Carvalho de Melo {
54093d5731dSArnaldo Carvalho de Melo 	struct map_groups *mg = malloc(sizeof(*mg));
54193d5731dSArnaldo Carvalho de Melo 
54293d5731dSArnaldo Carvalho de Melo 	if (mg != NULL)
54311246c70SArnaldo Carvalho de Melo 		map_groups__init(mg, machine);
54493d5731dSArnaldo Carvalho de Melo 
54593d5731dSArnaldo Carvalho de Melo 	return mg;
54693d5731dSArnaldo Carvalho de Melo }
54793d5731dSArnaldo Carvalho de Melo 
54893d5731dSArnaldo Carvalho de Melo void map_groups__delete(struct map_groups *mg)
54993d5731dSArnaldo Carvalho de Melo {
55093d5731dSArnaldo Carvalho de Melo 	map_groups__exit(mg);
55193d5731dSArnaldo Carvalho de Melo 	free(mg);
55293d5731dSArnaldo Carvalho de Melo }
55393d5731dSArnaldo Carvalho de Melo 
554a26ca671SArnaldo Carvalho de Melo void map_groups__put(struct map_groups *mg)
555a26ca671SArnaldo Carvalho de Melo {
556ead05e8fSElena Reshetova 	if (mg && refcount_dec_and_test(&mg->refcnt))
557a26ca671SArnaldo Carvalho de Melo 		map_groups__delete(mg);
558a26ca671SArnaldo Carvalho de Melo }
559a26ca671SArnaldo Carvalho de Melo 
56098dfd55dSArnaldo Carvalho de Melo struct symbol *map_groups__find_symbol(struct map_groups *mg,
5613183f8caSArnaldo Carvalho de Melo 				       u64 addr, struct map **mapp)
5624b8cf846SArnaldo Carvalho de Melo {
5633183f8caSArnaldo Carvalho de Melo 	struct map *map = map_groups__find(mg, addr);
5644b8cf846SArnaldo Carvalho de Melo 
5654afc81cdSMasami Hiramatsu 	/* Ensure map is loaded before using map->map_ip */
566be39db9fSArnaldo Carvalho de Melo 	if (map != NULL && map__load(map) >= 0) {
5677e5e1b14SArnaldo Carvalho de Melo 		if (mapp != NULL)
5687e5e1b14SArnaldo Carvalho de Melo 			*mapp = map;
569be39db9fSArnaldo Carvalho de Melo 		return map__find_symbol(map, map->map_ip(map, addr));
5707e5e1b14SArnaldo Carvalho de Melo 	}
5717e5e1b14SArnaldo Carvalho de Melo 
5727e5e1b14SArnaldo Carvalho de Melo 	return NULL;
5737e5e1b14SArnaldo Carvalho de Melo }
5747e5e1b14SArnaldo Carvalho de Melo 
575b7f9ff56SArnaldo Carvalho de Melo struct symbol *maps__find_symbol_by_name(struct maps *maps, const char *name,
576be39db9fSArnaldo Carvalho de Melo 					 struct map **mapp)
5777e5e1b14SArnaldo Carvalho de Melo {
5786a2ffcddSArnaldo Carvalho de Melo 	struct symbol *sym;
5797e5e1b14SArnaldo Carvalho de Melo 	struct rb_node *nd;
5807e5e1b14SArnaldo Carvalho de Melo 
5810a7c74eaSArnaldo Carvalho de Melo 	down_read(&maps->lock);
5826a2ffcddSArnaldo Carvalho de Melo 
5836a2ffcddSArnaldo Carvalho de Melo 	for (nd = rb_first(&maps->entries); nd; nd = rb_next(nd)) {
5847e5e1b14SArnaldo Carvalho de Melo 		struct map *pos = rb_entry(nd, struct map, rb_node);
5856a2ffcddSArnaldo Carvalho de Melo 
586be39db9fSArnaldo Carvalho de Melo 		sym = map__find_symbol_by_name(pos, name);
5877e5e1b14SArnaldo Carvalho de Melo 
5887e5e1b14SArnaldo Carvalho de Melo 		if (sym == NULL)
5897e5e1b14SArnaldo Carvalho de Melo 			continue;
5907e5e1b14SArnaldo Carvalho de Melo 		if (mapp != NULL)
5917e5e1b14SArnaldo Carvalho de Melo 			*mapp = pos;
5926a2ffcddSArnaldo Carvalho de Melo 		goto out;
5937e5e1b14SArnaldo Carvalho de Melo 	}
5944b8cf846SArnaldo Carvalho de Melo 
5956a2ffcddSArnaldo Carvalho de Melo 	sym = NULL;
5966a2ffcddSArnaldo Carvalho de Melo out:
5970a7c74eaSArnaldo Carvalho de Melo 	up_read(&maps->lock);
5986a2ffcddSArnaldo Carvalho de Melo 	return sym;
5994b8cf846SArnaldo Carvalho de Melo }
6004b8cf846SArnaldo Carvalho de Melo 
601b7f9ff56SArnaldo Carvalho de Melo struct symbol *map_groups__find_symbol_by_name(struct map_groups *mg,
602b7f9ff56SArnaldo Carvalho de Melo 					       const char *name,
603be39db9fSArnaldo Carvalho de Melo 					       struct map **mapp)
604b7f9ff56SArnaldo Carvalho de Melo {
6053183f8caSArnaldo Carvalho de Melo 	return maps__find_symbol_by_name(&mg->maps, name, mapp);
606b7f9ff56SArnaldo Carvalho de Melo }
607b7f9ff56SArnaldo Carvalho de Melo 
608be39db9fSArnaldo Carvalho de Melo int map_groups__find_ams(struct addr_map_symbol *ams)
6094e987712SArnaldo Carvalho de Melo {
61077faf4d0SStephane Eranian 	if (ams->addr < ams->map->start || ams->addr >= ams->map->end) {
6114e987712SArnaldo Carvalho de Melo 		if (ams->map->groups == NULL)
6124e987712SArnaldo Carvalho de Melo 			return -1;
6133183f8caSArnaldo Carvalho de Melo 		ams->map = map_groups__find(ams->map->groups, ams->addr);
6144e987712SArnaldo Carvalho de Melo 		if (ams->map == NULL)
6154e987712SArnaldo Carvalho de Melo 			return -1;
6164e987712SArnaldo Carvalho de Melo 	}
6174e987712SArnaldo Carvalho de Melo 
6184e987712SArnaldo Carvalho de Melo 	ams->al_addr = ams->map->map_ip(ams->map, ams->addr);
619be39db9fSArnaldo Carvalho de Melo 	ams->sym = map__find_symbol(ams->map, ams->al_addr);
6204e987712SArnaldo Carvalho de Melo 
6214e987712SArnaldo Carvalho de Melo 	return ams->sym ? 0 : -1;
6224e987712SArnaldo Carvalho de Melo }
6234e987712SArnaldo Carvalho de Melo 
6246a2ffcddSArnaldo Carvalho de Melo static size_t maps__fprintf(struct maps *maps, FILE *fp)
625c6e718ffSArnaldo Carvalho de Melo {
6266a2ffcddSArnaldo Carvalho de Melo 	size_t printed = 0;
627c6e718ffSArnaldo Carvalho de Melo 	struct rb_node *nd;
628c6e718ffSArnaldo Carvalho de Melo 
6290a7c74eaSArnaldo Carvalho de Melo 	down_read(&maps->lock);
6306a2ffcddSArnaldo Carvalho de Melo 
6316a2ffcddSArnaldo Carvalho de Melo 	for (nd = rb_first(&maps->entries); nd; nd = rb_next(nd)) {
632c6e718ffSArnaldo Carvalho de Melo 		struct map *pos = rb_entry(nd, struct map, rb_node);
633c6e718ffSArnaldo Carvalho de Melo 		printed += fprintf(fp, "Map:");
634c6e718ffSArnaldo Carvalho de Melo 		printed += map__fprintf(pos, fp);
635c6e718ffSArnaldo Carvalho de Melo 		if (verbose > 2) {
6363183f8caSArnaldo Carvalho de Melo 			printed += dso__fprintf(pos->dso, fp);
637c6e718ffSArnaldo Carvalho de Melo 			printed += fprintf(fp, "--\n");
638c6e718ffSArnaldo Carvalho de Melo 		}
639c6e718ffSArnaldo Carvalho de Melo 	}
640c6e718ffSArnaldo Carvalho de Melo 
6410a7c74eaSArnaldo Carvalho de Melo 	up_read(&maps->lock);
6426a2ffcddSArnaldo Carvalho de Melo 
643c6e718ffSArnaldo Carvalho de Melo 	return printed;
644c6e718ffSArnaldo Carvalho de Melo }
645c6e718ffSArnaldo Carvalho de Melo 
6465c24b67aSArnaldo Carvalho de Melo size_t map_groups__fprintf(struct map_groups *mg, FILE *fp)
647c6e718ffSArnaldo Carvalho de Melo {
6483183f8caSArnaldo Carvalho de Melo 	return maps__fprintf(&mg->maps, fp);
649c6e718ffSArnaldo Carvalho de Melo }
650c6e718ffSArnaldo Carvalho de Melo 
651cb8382e0SJiri Olsa static void __map_groups__insert(struct map_groups *mg, struct map *map)
652cb8382e0SJiri Olsa {
6533183f8caSArnaldo Carvalho de Melo 	__maps__insert(&mg->maps, map);
654cb8382e0SJiri Olsa 	map->groups = mg;
655cb8382e0SJiri Olsa }
656cb8382e0SJiri Olsa 
6576a2ffcddSArnaldo Carvalho de Melo static int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp)
658c6e718ffSArnaldo Carvalho de Melo {
6596a2ffcddSArnaldo Carvalho de Melo 	struct rb_root *root;
6606a2ffcddSArnaldo Carvalho de Melo 	struct rb_node *next;
6610a1eae39SArnaldo Carvalho de Melo 	int err = 0;
662c6e718ffSArnaldo Carvalho de Melo 
6630a7c74eaSArnaldo Carvalho de Melo 	down_write(&maps->lock);
6646a2ffcddSArnaldo Carvalho de Melo 
6656a2ffcddSArnaldo Carvalho de Melo 	root = &maps->entries;
6666a2ffcddSArnaldo Carvalho de Melo 	next = rb_first(root);
6676a2ffcddSArnaldo Carvalho de Melo 
668c6e718ffSArnaldo Carvalho de Melo 	while (next) {
669c6e718ffSArnaldo Carvalho de Melo 		struct map *pos = rb_entry(next, struct map, rb_node);
670c6e718ffSArnaldo Carvalho de Melo 		next = rb_next(&pos->rb_node);
671c6e718ffSArnaldo Carvalho de Melo 
672c6e718ffSArnaldo Carvalho de Melo 		if (!map__overlap(pos, map))
673c6e718ffSArnaldo Carvalho de Melo 			continue;
674c6e718ffSArnaldo Carvalho de Melo 
675c6e718ffSArnaldo Carvalho de Melo 		if (verbose >= 2) {
67621e8c810SAlexis Berlemont 
67721e8c810SAlexis Berlemont 			if (use_browser) {
67821e8c810SAlexis Berlemont 				pr_warning("overlapping maps in %s "
67921e8c810SAlexis Berlemont 					   "(disable tui for more info)\n",
68021e8c810SAlexis Berlemont 					   map->dso->name);
68121e8c810SAlexis Berlemont 			} else {
682c6e718ffSArnaldo Carvalho de Melo 				fputs("overlapping maps:\n", fp);
683c6e718ffSArnaldo Carvalho de Melo 				map__fprintf(map, fp);
684c6e718ffSArnaldo Carvalho de Melo 				map__fprintf(pos, fp);
685c6e718ffSArnaldo Carvalho de Melo 			}
68621e8c810SAlexis Berlemont 		}
687c6e718ffSArnaldo Carvalho de Melo 
688facf3f06SArnaldo Carvalho de Melo 		rb_erase_init(&pos->rb_node, root);
689c6e718ffSArnaldo Carvalho de Melo 		/*
690c6e718ffSArnaldo Carvalho de Melo 		 * Now check if we need to create new maps for areas not
691c6e718ffSArnaldo Carvalho de Melo 		 * overlapped by the new map:
692c6e718ffSArnaldo Carvalho de Melo 		 */
693c6e718ffSArnaldo Carvalho de Melo 		if (map->start > pos->start) {
694c6e718ffSArnaldo Carvalho de Melo 			struct map *before = map__clone(pos);
695c6e718ffSArnaldo Carvalho de Melo 
6960a1eae39SArnaldo Carvalho de Melo 			if (before == NULL) {
6970a1eae39SArnaldo Carvalho de Melo 				err = -ENOMEM;
69884c2cafaSArnaldo Carvalho de Melo 				goto put_map;
6990a1eae39SArnaldo Carvalho de Melo 			}
700c6e718ffSArnaldo Carvalho de Melo 
70177faf4d0SStephane Eranian 			before->end = map->start;
702cb8382e0SJiri Olsa 			__map_groups__insert(pos->groups, before);
70321e8c810SAlexis Berlemont 			if (verbose >= 2 && !use_browser)
704c6e718ffSArnaldo Carvalho de Melo 				map__fprintf(before, fp);
705d91130e9SMasami Hiramatsu 			map__put(before);
706c6e718ffSArnaldo Carvalho de Melo 		}
707c6e718ffSArnaldo Carvalho de Melo 
708c6e718ffSArnaldo Carvalho de Melo 		if (map->end < pos->end) {
709c6e718ffSArnaldo Carvalho de Melo 			struct map *after = map__clone(pos);
710c6e718ffSArnaldo Carvalho de Melo 
7110a1eae39SArnaldo Carvalho de Melo 			if (after == NULL) {
7120a1eae39SArnaldo Carvalho de Melo 				err = -ENOMEM;
71384c2cafaSArnaldo Carvalho de Melo 				goto put_map;
7140a1eae39SArnaldo Carvalho de Melo 			}
715c6e718ffSArnaldo Carvalho de Melo 
71677faf4d0SStephane Eranian 			after->start = map->end;
717cb8382e0SJiri Olsa 			__map_groups__insert(pos->groups, after);
71821e8c810SAlexis Berlemont 			if (verbose >= 2 && !use_browser)
719c6e718ffSArnaldo Carvalho de Melo 				map__fprintf(after, fp);
720d91130e9SMasami Hiramatsu 			map__put(after);
721c6e718ffSArnaldo Carvalho de Melo 		}
72284c2cafaSArnaldo Carvalho de Melo put_map:
72384c2cafaSArnaldo Carvalho de Melo 		map__put(pos);
7240a1eae39SArnaldo Carvalho de Melo 
7250a1eae39SArnaldo Carvalho de Melo 		if (err)
7266a2ffcddSArnaldo Carvalho de Melo 			goto out;
7276a2ffcddSArnaldo Carvalho de Melo 	}
7286a2ffcddSArnaldo Carvalho de Melo 
7296a2ffcddSArnaldo Carvalho de Melo 	err = 0;
7306a2ffcddSArnaldo Carvalho de Melo out:
7310a7c74eaSArnaldo Carvalho de Melo 	up_write(&maps->lock);
7320a1eae39SArnaldo Carvalho de Melo 	return err;
733c6e718ffSArnaldo Carvalho de Melo }
734c6e718ffSArnaldo Carvalho de Melo 
7356a2ffcddSArnaldo Carvalho de Melo int map_groups__fixup_overlappings(struct map_groups *mg, struct map *map,
7366a2ffcddSArnaldo Carvalho de Melo 				   FILE *fp)
7376a2ffcddSArnaldo Carvalho de Melo {
7383183f8caSArnaldo Carvalho de Melo 	return maps__fixup_overlappings(&mg->maps, map, fp);
739c6e718ffSArnaldo Carvalho de Melo }
740c6e718ffSArnaldo Carvalho de Melo 
741c6e718ffSArnaldo Carvalho de Melo /*
742c6e718ffSArnaldo Carvalho de Melo  * XXX This should not really _copy_ te maps, but refcount them.
743c6e718ffSArnaldo Carvalho de Melo  */
7443183f8caSArnaldo Carvalho de Melo int map_groups__clone(struct thread *thread, struct map_groups *parent)
745c6e718ffSArnaldo Carvalho de Melo {
7466c502584SJiri Olsa 	struct map_groups *mg = thread->mg;
7476a2ffcddSArnaldo Carvalho de Melo 	int err = -ENOMEM;
7484bb7123dSArnaldo Carvalho de Melo 	struct map *map;
7493183f8caSArnaldo Carvalho de Melo 	struct maps *maps = &parent->maps;
7504bb7123dSArnaldo Carvalho de Melo 
7510a7c74eaSArnaldo Carvalho de Melo 	down_read(&maps->lock);
7526a2ffcddSArnaldo Carvalho de Melo 
7534bb7123dSArnaldo Carvalho de Melo 	for (map = maps__first(maps); map; map = map__next(map)) {
754c6e718ffSArnaldo Carvalho de Melo 		struct map *new = map__clone(map);
755c6e718ffSArnaldo Carvalho de Melo 		if (new == NULL)
7566a2ffcddSArnaldo Carvalho de Melo 			goto out_unlock;
7576c502584SJiri Olsa 
7586c502584SJiri Olsa 		err = unwind__prepare_access(thread, new, NULL);
7596c502584SJiri Olsa 		if (err)
7606c502584SJiri Olsa 			goto out_unlock;
7616c502584SJiri Olsa 
76298dfd55dSArnaldo Carvalho de Melo 		map_groups__insert(mg, new);
763bae32b50SMasami Hiramatsu 		map__put(new);
764c6e718ffSArnaldo Carvalho de Melo 	}
7656a2ffcddSArnaldo Carvalho de Melo 
7666a2ffcddSArnaldo Carvalho de Melo 	err = 0;
7676a2ffcddSArnaldo Carvalho de Melo out_unlock:
7680a7c74eaSArnaldo Carvalho de Melo 	up_read(&maps->lock);
7696a2ffcddSArnaldo Carvalho de Melo 	return err;
770c6e718ffSArnaldo Carvalho de Melo }
771c6e718ffSArnaldo Carvalho de Melo 
7726a2ffcddSArnaldo Carvalho de Melo static void __maps__insert(struct maps *maps, struct map *map)
7734b8cf846SArnaldo Carvalho de Melo {
7741eee78aeSArnaldo Carvalho de Melo 	struct rb_node **p = &maps->entries.rb_node;
7754b8cf846SArnaldo Carvalho de Melo 	struct rb_node *parent = NULL;
7764b8cf846SArnaldo Carvalho de Melo 	const u64 ip = map->start;
7774b8cf846SArnaldo Carvalho de Melo 	struct map *m;
7784b8cf846SArnaldo Carvalho de Melo 
7794b8cf846SArnaldo Carvalho de Melo 	while (*p != NULL) {
7804b8cf846SArnaldo Carvalho de Melo 		parent = *p;
7814b8cf846SArnaldo Carvalho de Melo 		m = rb_entry(parent, struct map, rb_node);
7824b8cf846SArnaldo Carvalho de Melo 		if (ip < m->start)
7834b8cf846SArnaldo Carvalho de Melo 			p = &(*p)->rb_left;
7844b8cf846SArnaldo Carvalho de Melo 		else
7854b8cf846SArnaldo Carvalho de Melo 			p = &(*p)->rb_right;
7864b8cf846SArnaldo Carvalho de Melo 	}
7874b8cf846SArnaldo Carvalho de Melo 
7884b8cf846SArnaldo Carvalho de Melo 	rb_link_node(&map->rb_node, parent, p);
7891eee78aeSArnaldo Carvalho de Melo 	rb_insert_color(&map->rb_node, &maps->entries);
79084c2cafaSArnaldo Carvalho de Melo 	map__get(map);
7914b8cf846SArnaldo Carvalho de Melo }
7924b8cf846SArnaldo Carvalho de Melo 
7936a2ffcddSArnaldo Carvalho de Melo void maps__insert(struct maps *maps, struct map *map)
7946a2ffcddSArnaldo Carvalho de Melo {
7950a7c74eaSArnaldo Carvalho de Melo 	down_write(&maps->lock);
7966a2ffcddSArnaldo Carvalho de Melo 	__maps__insert(maps, map);
7970a7c74eaSArnaldo Carvalho de Melo 	up_write(&maps->lock);
7986a2ffcddSArnaldo Carvalho de Melo }
7996a2ffcddSArnaldo Carvalho de Melo 
8006a2ffcddSArnaldo Carvalho de Melo static void __maps__remove(struct maps *maps, struct map *map)
801076c6e45SArnaldo Carvalho de Melo {
802facf3f06SArnaldo Carvalho de Melo 	rb_erase_init(&map->rb_node, &maps->entries);
80384c2cafaSArnaldo Carvalho de Melo 	map__put(map);
804076c6e45SArnaldo Carvalho de Melo }
805076c6e45SArnaldo Carvalho de Melo 
8066a2ffcddSArnaldo Carvalho de Melo void maps__remove(struct maps *maps, struct map *map)
8076a2ffcddSArnaldo Carvalho de Melo {
8080a7c74eaSArnaldo Carvalho de Melo 	down_write(&maps->lock);
8096a2ffcddSArnaldo Carvalho de Melo 	__maps__remove(maps, map);
8100a7c74eaSArnaldo Carvalho de Melo 	up_write(&maps->lock);
8116a2ffcddSArnaldo Carvalho de Melo }
8126a2ffcddSArnaldo Carvalho de Melo 
8131eee78aeSArnaldo Carvalho de Melo struct map *maps__find(struct maps *maps, u64 ip)
8144b8cf846SArnaldo Carvalho de Melo {
8156a2ffcddSArnaldo Carvalho de Melo 	struct rb_node **p, *parent = NULL;
8164b8cf846SArnaldo Carvalho de Melo 	struct map *m;
8174b8cf846SArnaldo Carvalho de Melo 
8180a7c74eaSArnaldo Carvalho de Melo 	down_read(&maps->lock);
8196a2ffcddSArnaldo Carvalho de Melo 
8206a2ffcddSArnaldo Carvalho de Melo 	p = &maps->entries.rb_node;
8214b8cf846SArnaldo Carvalho de Melo 	while (*p != NULL) {
8224b8cf846SArnaldo Carvalho de Melo 		parent = *p;
8234b8cf846SArnaldo Carvalho de Melo 		m = rb_entry(parent, struct map, rb_node);
8244b8cf846SArnaldo Carvalho de Melo 		if (ip < m->start)
8254b8cf846SArnaldo Carvalho de Melo 			p = &(*p)->rb_left;
8264955ea22SNamhyung Kim 		else if (ip >= m->end)
8274b8cf846SArnaldo Carvalho de Melo 			p = &(*p)->rb_right;
8284b8cf846SArnaldo Carvalho de Melo 		else
8296a2ffcddSArnaldo Carvalho de Melo 			goto out;
8304b8cf846SArnaldo Carvalho de Melo 	}
8314b8cf846SArnaldo Carvalho de Melo 
8326a2ffcddSArnaldo Carvalho de Melo 	m = NULL;
8336a2ffcddSArnaldo Carvalho de Melo out:
8340a7c74eaSArnaldo Carvalho de Melo 	up_read(&maps->lock);
8356a2ffcddSArnaldo Carvalho de Melo 	return m;
8364b8cf846SArnaldo Carvalho de Melo }
8378e0cf965SAdrian Hunter 
8381eee78aeSArnaldo Carvalho de Melo struct map *maps__first(struct maps *maps)
8398e0cf965SAdrian Hunter {
8401eee78aeSArnaldo Carvalho de Melo 	struct rb_node *first = rb_first(&maps->entries);
8418e0cf965SAdrian Hunter 
8428e0cf965SAdrian Hunter 	if (first)
8438e0cf965SAdrian Hunter 		return rb_entry(first, struct map, rb_node);
8448e0cf965SAdrian Hunter 	return NULL;
8458e0cf965SAdrian Hunter }
8468e0cf965SAdrian Hunter 
8474d4dee9aSArnaldo Carvalho de Melo struct map *map__next(struct map *map)
8488e0cf965SAdrian Hunter {
8498e0cf965SAdrian Hunter 	struct rb_node *next = rb_next(&map->rb_node);
8508e0cf965SAdrian Hunter 
8518e0cf965SAdrian Hunter 	if (next)
8528e0cf965SAdrian Hunter 		return rb_entry(next, struct map, rb_node);
8538e0cf965SAdrian Hunter 	return NULL;
8548e0cf965SAdrian Hunter }
855ba92732eSWang Nan 
8565759a682SAdrian Hunter struct kmap *__map__kmap(struct map *map)
8575759a682SAdrian Hunter {
8585759a682SAdrian Hunter 	if (!map->dso || !map->dso->kernel)
8595759a682SAdrian Hunter 		return NULL;
8605759a682SAdrian Hunter 	return (struct kmap *)(map + 1);
8615759a682SAdrian Hunter }
8625759a682SAdrian Hunter 
863ba92732eSWang Nan struct kmap *map__kmap(struct map *map)
864ba92732eSWang Nan {
8655759a682SAdrian Hunter 	struct kmap *kmap = __map__kmap(map);
8665759a682SAdrian Hunter 
8675759a682SAdrian Hunter 	if (!kmap)
868ba92732eSWang Nan 		pr_err("Internal error: map__kmap with a non-kernel map\n");
8695759a682SAdrian Hunter 	return kmap;
870ba92732eSWang Nan }
871ba92732eSWang Nan 
872ba92732eSWang Nan struct map_groups *map__kmaps(struct map *map)
873ba92732eSWang Nan {
874ba92732eSWang Nan 	struct kmap *kmap = map__kmap(map);
875ba92732eSWang Nan 
876ba92732eSWang Nan 	if (!kmap || !kmap->kmaps) {
877ba92732eSWang Nan 		pr_err("Internal error: map__kmaps with a non-kernel map\n");
878ba92732eSWang Nan 		return NULL;
879ba92732eSWang Nan 	}
880ba92732eSWang Nan 	return kmap->kmaps;
881ba92732eSWang Nan }
882