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