1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 266e274f3SFrederic Weisbecker #include "symbol.h" 3ee212d6eSSteve MacLean #include <assert.h> 4c6e718ffSArnaldo Carvalho de Melo #include <errno.h> 59486aa38SArnaldo Carvalho de Melo #include <inttypes.h> 64b8cf846SArnaldo Carvalho de Melo #include <limits.h> 766e274f3SFrederic Weisbecker #include <stdlib.h> 866e274f3SFrederic Weisbecker #include <string.h> 966e274f3SFrederic Weisbecker #include <stdio.h> 10a1645ce1SZhang, Yanmin #include <unistd.h> 11fbef103fSArnaldo Carvalho de Melo #include <uapi/linux/mman.h> /* To get things like MAP_HUGETLB even on older libc headers */ 124a3cec84SArnaldo Carvalho de Melo #include "dso.h" 134b8cf846SArnaldo Carvalho de Melo #include "map.h" 14d3300a3cSArnaldo Carvalho de Melo #include "map_symbol.h" 155cd95c2dSDavid Ahern #include "thread.h" 167dbf4dcfSJiri Olsa #include "vdso.h" 17ebb296c2SJiri Olsa #include "build-id.h" 18acebd408SJiri Olsa #include "debug.h" 192a03068cSAdrian Hunter #include "machine.h" 208e16017dSArnaldo Carvalho de Melo #include <linux/string.h> 217f7c536fSArnaldo Carvalho de Melo #include <linux/zalloc.h> 22632a5cabSArnaldo Carvalho de Melo #include "srcline.h" 23843ff37bSKrister Johansen #include "namespaces.h" 246c502584SJiri Olsa #include "unwind.h" 25dd2e18e9SAndi Kleen #include "srccode.h" 268520a98dSArnaldo Carvalho de Melo #include "ui/ui.h" 2766e274f3SFrederic Weisbecker 286a2ffcddSArnaldo Carvalho de Melo static void __maps__insert(struct maps *maps, struct map *map); 296a2ffcddSArnaldo Carvalho de Melo 300ac3348eSWang Nan static inline int is_anon_memory(const char *filename, u32 flags) 3166e274f3SFrederic Weisbecker { 32fbef103fSArnaldo Carvalho de Melo return flags & MAP_HUGETLB || 330ac3348eSWang Nan !strcmp(filename, "//anon") || 34b2be5451SYannick Brosseau !strncmp(filename, "/dev/zero", sizeof("/dev/zero") - 1) || 35b2be5451SYannick Brosseau !strncmp(filename, "/anon_hugepage", sizeof("/anon_hugepage") - 1); 3666e274f3SFrederic Weisbecker } 3766e274f3SFrederic Weisbecker 3887ffef79SJiri Olsa static inline int is_no_dso_memory(const char *filename) 3987ffef79SJiri Olsa { 401e82574dSNamhyung Kim return !strncmp(filename, "[stack", 6) || 41700be564SDon Zickus !strncmp(filename, "/SYSV",5) || 4287ffef79SJiri Olsa !strcmp(filename, "[heap]"); 4387ffef79SJiri Olsa } 4487ffef79SJiri Olsa 45eca81836SMichael Lentine static inline int is_android_lib(const char *filename) 46eca81836SMichael Lentine { 47bdadd647SArnaldo Carvalho de Melo return strstarts(filename, "/data/app-lib/") || 48bdadd647SArnaldo Carvalho de Melo strstarts(filename, "/system/lib/"); 49eca81836SMichael Lentine } 50eca81836SMichael Lentine 51eca81836SMichael Lentine static inline bool replace_android_lib(const char *filename, char *newfilename) 52eca81836SMichael Lentine { 53eca81836SMichael Lentine const char *libname; 54eca81836SMichael Lentine char *app_abi; 55eca81836SMichael Lentine size_t app_abi_length, new_length; 56eca81836SMichael Lentine size_t lib_length = 0; 57eca81836SMichael Lentine 58eca81836SMichael Lentine libname = strrchr(filename, '/'); 59eca81836SMichael Lentine if (libname) 60eca81836SMichael Lentine lib_length = strlen(libname); 61eca81836SMichael Lentine 62eca81836SMichael Lentine app_abi = getenv("APP_ABI"); 63eca81836SMichael Lentine if (!app_abi) 64eca81836SMichael Lentine return false; 65eca81836SMichael Lentine 66eca81836SMichael Lentine app_abi_length = strlen(app_abi); 67eca81836SMichael Lentine 68bdadd647SArnaldo Carvalho de Melo if (strstarts(filename, "/data/app-lib/")) { 69eca81836SMichael Lentine char *apk_path; 70eca81836SMichael Lentine 71eca81836SMichael Lentine if (!app_abi_length) 72eca81836SMichael Lentine return false; 73eca81836SMichael Lentine 74eca81836SMichael Lentine new_length = 7 + app_abi_length + lib_length; 75eca81836SMichael Lentine 76eca81836SMichael Lentine apk_path = getenv("APK_PATH"); 77eca81836SMichael Lentine if (apk_path) { 78eca81836SMichael Lentine new_length += strlen(apk_path) + 1; 79eca81836SMichael Lentine if (new_length > PATH_MAX) 80eca81836SMichael Lentine return false; 81eca81836SMichael Lentine snprintf(newfilename, new_length, 82eca81836SMichael Lentine "%s/libs/%s/%s", apk_path, app_abi, libname); 83eca81836SMichael Lentine } else { 84eca81836SMichael Lentine if (new_length > PATH_MAX) 85eca81836SMichael Lentine return false; 86eca81836SMichael Lentine snprintf(newfilename, new_length, 87eca81836SMichael Lentine "libs/%s/%s", app_abi, libname); 88eca81836SMichael Lentine } 89eca81836SMichael Lentine return true; 90eca81836SMichael Lentine } 91eca81836SMichael Lentine 92bdadd647SArnaldo Carvalho de Melo if (strstarts(filename, "/system/lib/")) { 93eca81836SMichael Lentine char *ndk, *app; 94eca81836SMichael Lentine const char *arch; 95eca81836SMichael Lentine size_t ndk_length; 96eca81836SMichael Lentine size_t app_length; 97eca81836SMichael Lentine 98eca81836SMichael Lentine ndk = getenv("NDK_ROOT"); 99eca81836SMichael Lentine app = getenv("APP_PLATFORM"); 100eca81836SMichael Lentine 101eca81836SMichael Lentine if (!(ndk && app)) 102eca81836SMichael Lentine return false; 103eca81836SMichael Lentine 104eca81836SMichael Lentine ndk_length = strlen(ndk); 105eca81836SMichael Lentine app_length = strlen(app); 106eca81836SMichael Lentine 107eca81836SMichael Lentine if (!(ndk_length && app_length && app_abi_length)) 108eca81836SMichael Lentine return false; 109eca81836SMichael Lentine 110eca81836SMichael Lentine arch = !strncmp(app_abi, "arm", 3) ? "arm" : 111eca81836SMichael Lentine !strncmp(app_abi, "mips", 4) ? "mips" : 112eca81836SMichael Lentine !strncmp(app_abi, "x86", 3) ? "x86" : NULL; 113eca81836SMichael Lentine 114eca81836SMichael Lentine if (!arch) 115eca81836SMichael Lentine return false; 116eca81836SMichael Lentine 117eca81836SMichael Lentine new_length = 27 + ndk_length + 118eca81836SMichael Lentine app_length + lib_length 119eca81836SMichael Lentine + strlen(arch); 120eca81836SMichael Lentine 121eca81836SMichael Lentine if (new_length > PATH_MAX) 122eca81836SMichael Lentine return false; 123eca81836SMichael Lentine snprintf(newfilename, new_length, 124eca81836SMichael Lentine "%s/platforms/%s/arch-%s/usr/lib/%s", 125eca81836SMichael Lentine ndk, app, arch, libname); 126eca81836SMichael Lentine 127eca81836SMichael Lentine return true; 128eca81836SMichael Lentine } 129eca81836SMichael Lentine return false; 130eca81836SMichael Lentine } 131eca81836SMichael Lentine 1323183f8caSArnaldo Carvalho de Melo void map__init(struct map *map, u64 start, u64 end, u64 pgoff, struct dso *dso) 133afb7b4f0SArnaldo Carvalho de Melo { 134237a7e04SArnaldo Carvalho de Melo map->start = start; 135237a7e04SArnaldo Carvalho de Melo map->end = end; 136237a7e04SArnaldo Carvalho de Melo map->pgoff = pgoff; 1379176753dSAdrian Hunter map->reloc = 0; 138d3a7c489SArnaldo Carvalho de Melo map->dso = dso__get(dso); 139237a7e04SArnaldo Carvalho de Melo map->map_ip = map__map_ip; 140237a7e04SArnaldo Carvalho de Melo map->unmap_ip = map__unmap_ip; 141237a7e04SArnaldo Carvalho de Melo RB_CLEAR_NODE(&map->rb_node); 142237a7e04SArnaldo Carvalho de Melo map->erange_warned = false; 143e3a42cddSElena Reshetova refcount_set(&map->refcnt, 1); 144afb7b4f0SArnaldo Carvalho de Melo } 145afb7b4f0SArnaldo Carvalho de Melo 1462a03068cSAdrian Hunter struct map *map__new(struct machine *machine, u64 start, u64 len, 1474a7380a5SArnaldo Carvalho de Melo u64 pgoff, struct dso_id *id, 1484a7380a5SArnaldo Carvalho de Melo u32 prot, u32 flags, char *filename, 1493183f8caSArnaldo Carvalho de Melo struct thread *thread) 15066e274f3SFrederic Weisbecker { 151237a7e04SArnaldo Carvalho de Melo struct map *map = malloc(sizeof(*map)); 152bf2e710bSKrister Johansen struct nsinfo *nsi = NULL; 153bf2e710bSKrister Johansen struct nsinfo *nnsi; 15466e274f3SFrederic Weisbecker 155237a7e04SArnaldo Carvalho de Melo if (map != NULL) { 15666e274f3SFrederic Weisbecker char newfilename[PATH_MAX]; 157afb7b4f0SArnaldo Carvalho de Melo struct dso *dso; 158eca81836SMichael Lentine int anon, no_dso, vdso, android; 15966e274f3SFrederic Weisbecker 160eca81836SMichael Lentine android = is_android_lib(filename); 1610ac3348eSWang Nan anon = is_anon_memory(filename, flags); 1627dbf4dcfSJiri Olsa vdso = is_vdso_map(filename); 16387ffef79SJiri Olsa no_dso = is_no_dso_memory(filename); 1647ef80703SDon Zickus map->prot = prot; 1657ef80703SDon Zickus map->flags = flags; 166bf2e710bSKrister Johansen nsi = nsinfo__get(thread->nsinfo); 1675c5e854bSStephane Eranian 168d183b261SArnaldo Carvalho de Melo if ((anon || no_dso) && nsi && (prot & PROT_EXEC)) { 169bf2e710bSKrister Johansen snprintf(newfilename, sizeof(newfilename), 170bf2e710bSKrister Johansen "/tmp/perf-%d.map", nsi->pid); 17166e274f3SFrederic Weisbecker filename = newfilename; 17266e274f3SFrederic Weisbecker } 17366e274f3SFrederic Weisbecker 174eca81836SMichael Lentine if (android) { 175eca81836SMichael Lentine if (replace_android_lib(filename, newfilename)) 176eca81836SMichael Lentine filename = newfilename; 177eca81836SMichael Lentine } 178eca81836SMichael Lentine 1797dbf4dcfSJiri Olsa if (vdso) { 180bf2e710bSKrister Johansen /* The vdso maps are always on the host and not the 181bf2e710bSKrister Johansen * container. Ensure that we don't use setns to look 182bf2e710bSKrister Johansen * them up. 183bf2e710bSKrister Johansen */ 184bf2e710bSKrister Johansen nnsi = nsinfo__copy(nsi); 185bf2e710bSKrister Johansen if (nnsi) { 186bf2e710bSKrister Johansen nsinfo__put(nsi); 187bf2e710bSKrister Johansen nnsi->need_setns = false; 188bf2e710bSKrister Johansen nsi = nnsi; 189bf2e710bSKrister Johansen } 1907dbf4dcfSJiri Olsa pgoff = 0; 1919a4388c7SArnaldo Carvalho de Melo dso = machine__findnew_vdso(machine, thread); 1927dbf4dcfSJiri Olsa } else 1930e3149f8SArnaldo Carvalho de Melo dso = machine__findnew_dso_id(machine, filename, id); 1947dbf4dcfSJiri Olsa 195afb7b4f0SArnaldo Carvalho de Melo if (dso == NULL) 19666e274f3SFrederic Weisbecker goto out_delete; 19766e274f3SFrederic Weisbecker 1983183f8caSArnaldo Carvalho de Melo map__init(map, start, start + len, pgoff, dso); 199afb7b4f0SArnaldo Carvalho de Melo 20087ffef79SJiri Olsa if (anon || no_dso) { 201237a7e04SArnaldo Carvalho de Melo map->map_ip = map->unmap_ip = identity__map_ip; 20287ffef79SJiri Olsa 20387ffef79SJiri Olsa /* 20487ffef79SJiri Olsa * Set memory without DSO as loaded. All map__find_* 20587ffef79SJiri Olsa * functions still return NULL, and we avoid the 20687ffef79SJiri Olsa * unnecessary map__load warning. 20787ffef79SJiri Olsa */ 208d183b261SArnaldo Carvalho de Melo if (!(prot & PROT_EXEC)) 2093183f8caSArnaldo Carvalho de Melo dso__set_loaded(dso); 2108d92c02aSArnaldo Carvalho de Melo } 211bf2e710bSKrister Johansen dso->nsinfo = nsi; 212d3a7c489SArnaldo Carvalho de Melo dso__put(dso); 21366e274f3SFrederic Weisbecker } 214237a7e04SArnaldo Carvalho de Melo return map; 21566e274f3SFrederic Weisbecker out_delete: 216bf2e710bSKrister Johansen nsinfo__put(nsi); 217237a7e04SArnaldo Carvalho de Melo free(map); 21866e274f3SFrederic Weisbecker return NULL; 21966e274f3SFrederic Weisbecker } 22066e274f3SFrederic Weisbecker 221e5a1845fSNamhyung Kim /* 222e5a1845fSNamhyung Kim * Constructor variant for modules (where we know from /proc/modules where 223e5a1845fSNamhyung Kim * they are loaded) and for vmlinux, where only after we load all the 224e5a1845fSNamhyung Kim * symbols we'll know where it starts and ends. 225e5a1845fSNamhyung Kim */ 2263183f8caSArnaldo Carvalho de Melo struct map *map__new2(u64 start, struct dso *dso) 227e5a1845fSNamhyung Kim { 228e5a1845fSNamhyung Kim struct map *map = calloc(1, (sizeof(*map) + 229e5a1845fSNamhyung Kim (dso->kernel ? sizeof(struct kmap) : 0))); 230e5a1845fSNamhyung Kim if (map != NULL) { 231e5a1845fSNamhyung Kim /* 232e5a1845fSNamhyung Kim * ->end will be filled after we load all the symbols 233e5a1845fSNamhyung Kim */ 2343183f8caSArnaldo Carvalho de Melo map__init(map, start, 0, 0, dso); 235e5a1845fSNamhyung Kim } 236e5a1845fSNamhyung Kim 237e5a1845fSNamhyung Kim return map; 238e5a1845fSNamhyung Kim } 239e5a1845fSNamhyung Kim 240e6ce7126SArnaldo Carvalho de Melo bool __map__is_kernel(const struct map *map) 241e6ce7126SArnaldo Carvalho de Melo { 242de90d513SArnaldo Carvalho de Melo if (!map->dso->kernel) 243de90d513SArnaldo Carvalho de Melo return false; 244de90d513SArnaldo Carvalho de Melo return machine__kernel_map(map__kmaps((struct map *)map)->machine) == map; 245e6ce7126SArnaldo Carvalho de Melo } 246e6ce7126SArnaldo Carvalho de Melo 2475759a682SAdrian Hunter bool __map__is_extra_kernel_map(const struct map *map) 2485759a682SAdrian Hunter { 2495759a682SAdrian Hunter struct kmap *kmap = __map__kmap((struct map *)map); 2505759a682SAdrian Hunter 2515759a682SAdrian Hunter return kmap && kmap->name[0]; 2525759a682SAdrian Hunter } 2535759a682SAdrian Hunter 254a93e0b23SSong Liu bool __map__is_bpf_prog(const struct map *map) 255a93e0b23SSong Liu { 256a93e0b23SSong Liu const char *name; 257a93e0b23SSong Liu 258a93e0b23SSong Liu if (map->dso->binary_type == DSO_BINARY_TYPE__BPF_PROG_INFO) 259a93e0b23SSong Liu return true; 260a93e0b23SSong Liu 261a93e0b23SSong Liu /* 262a93e0b23SSong Liu * If PERF_RECORD_BPF_EVENT is not included, the dso will not have 263a93e0b23SSong Liu * type of DSO_BINARY_TYPE__BPF_PROG_INFO. In such cases, we can 264a93e0b23SSong Liu * guess the type based on name. 265a93e0b23SSong Liu */ 266a93e0b23SSong Liu name = map->dso->short_name; 267a93e0b23SSong Liu return name && (strstr(name, "bpf_prog_") == name); 268a93e0b23SSong Liu } 269a93e0b23SSong Liu 270830fadfdSJiri Olsa bool __map__is_bpf_image(const struct map *map) 271830fadfdSJiri Olsa { 272830fadfdSJiri Olsa const char *name; 273830fadfdSJiri Olsa 274830fadfdSJiri Olsa if (map->dso->binary_type == DSO_BINARY_TYPE__BPF_IMAGE) 275830fadfdSJiri Olsa return true; 276830fadfdSJiri Olsa 277830fadfdSJiri Olsa /* 278830fadfdSJiri Olsa * If PERF_RECORD_KSYMBOL is not included, the dso will not have 279830fadfdSJiri Olsa * type of DSO_BINARY_TYPE__BPF_IMAGE. In such cases, we can 280830fadfdSJiri Olsa * guess the type based on name. 281830fadfdSJiri Olsa */ 282830fadfdSJiri Olsa name = map->dso->short_name; 283830fadfdSJiri Olsa return name && is_bpf_image(name); 284830fadfdSJiri Olsa } 285830fadfdSJiri Olsa 286789e2419SAdrian Hunter bool __map__is_ool(const struct map *map) 287789e2419SAdrian Hunter { 288789e2419SAdrian Hunter return map->dso && map->dso->binary_type == DSO_BINARY_TYPE__OOL; 289789e2419SAdrian Hunter } 290789e2419SAdrian Hunter 291e94b861aSArnaldo Carvalho de Melo bool map__has_symbols(const struct map *map) 292e94b861aSArnaldo Carvalho de Melo { 2933183f8caSArnaldo Carvalho de Melo return dso__has_symbols(map->dso); 294e94b861aSArnaldo Carvalho de Melo } 295e94b861aSArnaldo Carvalho de Melo 296d3a7c489SArnaldo Carvalho de Melo static void map__exit(struct map *map) 297c338aee8SArnaldo Carvalho de Melo { 298ee2555b6SArnaldo Carvalho de Melo BUG_ON(refcount_read(&map->refcnt) != 0); 299d3a7c489SArnaldo Carvalho de Melo dso__zput(map->dso); 300d3a7c489SArnaldo Carvalho de Melo } 301d3a7c489SArnaldo Carvalho de Melo 302d3a7c489SArnaldo Carvalho de Melo void map__delete(struct map *map) 303d3a7c489SArnaldo Carvalho de Melo { 304d3a7c489SArnaldo Carvalho de Melo map__exit(map); 305237a7e04SArnaldo Carvalho de Melo free(map); 306c338aee8SArnaldo Carvalho de Melo } 307c338aee8SArnaldo Carvalho de Melo 30884c2cafaSArnaldo Carvalho de Melo void map__put(struct map *map) 30984c2cafaSArnaldo Carvalho de Melo { 310e3a42cddSElena Reshetova if (map && refcount_dec_and_test(&map->refcnt)) 31184c2cafaSArnaldo Carvalho de Melo map__delete(map); 31284c2cafaSArnaldo Carvalho de Melo } 31384c2cafaSArnaldo Carvalho de Melo 314237a7e04SArnaldo Carvalho de Melo void map__fixup_start(struct map *map) 315c338aee8SArnaldo Carvalho de Melo { 3167137ff50SDavidlohr Bueso struct rb_root_cached *symbols = &map->dso->symbols; 3177137ff50SDavidlohr Bueso struct rb_node *nd = rb_first_cached(symbols); 318c338aee8SArnaldo Carvalho de Melo if (nd != NULL) { 319c338aee8SArnaldo Carvalho de Melo struct symbol *sym = rb_entry(nd, struct symbol, rb_node); 320237a7e04SArnaldo Carvalho de Melo map->start = sym->start; 321c338aee8SArnaldo Carvalho de Melo } 322c338aee8SArnaldo Carvalho de Melo } 323c338aee8SArnaldo Carvalho de Melo 324237a7e04SArnaldo Carvalho de Melo void map__fixup_end(struct map *map) 325c338aee8SArnaldo Carvalho de Melo { 3267137ff50SDavidlohr Bueso struct rb_root_cached *symbols = &map->dso->symbols; 3277137ff50SDavidlohr Bueso struct rb_node *nd = rb_last(&symbols->rb_root); 328c338aee8SArnaldo Carvalho de Melo if (nd != NULL) { 329c338aee8SArnaldo Carvalho de Melo struct symbol *sym = rb_entry(nd, struct symbol, rb_node); 330237a7e04SArnaldo Carvalho de Melo map->end = sym->end; 331c338aee8SArnaldo Carvalho de Melo } 332c338aee8SArnaldo Carvalho de Melo } 333c338aee8SArnaldo Carvalho de Melo 334d70a5402SArnaldo Carvalho de Melo #define DSO__DELETED "(deleted)" 335d70a5402SArnaldo Carvalho de Melo 336be39db9fSArnaldo Carvalho de Melo int map__load(struct map *map) 33766bd8424SArnaldo Carvalho de Melo { 338237a7e04SArnaldo Carvalho de Melo const char *name = map->dso->long_name; 339a128168dSMasami Hiramatsu int nr; 34066bd8424SArnaldo Carvalho de Melo 3413183f8caSArnaldo Carvalho de Melo if (dso__loaded(map->dso)) 342a128168dSMasami Hiramatsu return 0; 343a128168dSMasami Hiramatsu 344be39db9fSArnaldo Carvalho de Melo nr = dso__load(map->dso, map); 34566bd8424SArnaldo Carvalho de Melo if (nr < 0) { 346237a7e04SArnaldo Carvalho de Melo if (map->dso->has_build_id) { 347b5d8bbe8SMasami Hiramatsu char sbuild_id[SBUILD_ID_SIZE]; 3488d06367fSArnaldo Carvalho de Melo 349237a7e04SArnaldo Carvalho de Melo build_id__sprintf(map->dso->build_id, 350237a7e04SArnaldo Carvalho de Melo sizeof(map->dso->build_id), 3518d06367fSArnaldo Carvalho de Melo sbuild_id); 352d8e75a11SArnaldo Carvalho de Melo pr_debug("%s with build id %s not found", name, sbuild_id); 3538d06367fSArnaldo Carvalho de Melo } else 354d8e75a11SArnaldo Carvalho de Melo pr_debug("Failed to open %s", name); 35579406cd7SArnaldo Carvalho de Melo 356d8e75a11SArnaldo Carvalho de Melo pr_debug(", continuing without symbols\n"); 35779406cd7SArnaldo Carvalho de Melo return -1; 35866bd8424SArnaldo Carvalho de Melo } else if (nr == 0) { 35989fe808aSIngo Molnar #ifdef HAVE_LIBELF_SUPPORT 360d70a5402SArnaldo Carvalho de Melo const size_t len = strlen(name); 361d70a5402SArnaldo Carvalho de Melo const size_t real_len = len - sizeof(DSO__DELETED); 362d70a5402SArnaldo Carvalho de Melo 363d70a5402SArnaldo Carvalho de Melo if (len > sizeof(DSO__DELETED) && 364900b20d5SIngo Molnar strcmp(name + real_len + 1, DSO__DELETED) == 0) { 365d8e75a11SArnaldo Carvalho de Melo pr_debug("%.*s was updated (is prelink enabled?). " 366e77b15bdSDavid Ahern "Restart the long running apps that use it!\n", 367900b20d5SIngo Molnar (int)real_len, name); 368900b20d5SIngo Molnar } else { 369d8e75a11SArnaldo Carvalho de Melo pr_debug("no symbols found in %s, maybe install a debug package?\n", name); 37066bd8424SArnaldo Carvalho de Melo } 371393be2e3SNamhyung Kim #endif 37279406cd7SArnaldo Carvalho de Melo return -1; 37379406cd7SArnaldo Carvalho de Melo } 37479406cd7SArnaldo Carvalho de Melo 37579406cd7SArnaldo Carvalho de Melo return 0; 37679406cd7SArnaldo Carvalho de Melo } 37779406cd7SArnaldo Carvalho de Melo 378be39db9fSArnaldo Carvalho de Melo struct symbol *map__find_symbol(struct map *map, u64 addr) 37979406cd7SArnaldo Carvalho de Melo { 380be39db9fSArnaldo Carvalho de Melo if (map__load(map) < 0) 38179406cd7SArnaldo Carvalho de Melo return NULL; 38279406cd7SArnaldo Carvalho de Melo 3833183f8caSArnaldo Carvalho de Melo return dso__find_symbol(map->dso, addr); 38466bd8424SArnaldo Carvalho de Melo } 38566bd8424SArnaldo Carvalho de Melo 386be39db9fSArnaldo Carvalho de Melo struct symbol *map__find_symbol_by_name(struct map *map, const char *name) 38779406cd7SArnaldo Carvalho de Melo { 388be39db9fSArnaldo Carvalho de Melo if (map__load(map) < 0) 38979406cd7SArnaldo Carvalho de Melo return NULL; 39079406cd7SArnaldo Carvalho de Melo 3913183f8caSArnaldo Carvalho de Melo if (!dso__sorted_by_name(map->dso)) 3923183f8caSArnaldo Carvalho de Melo dso__sort_by_name(map->dso); 39379406cd7SArnaldo Carvalho de Melo 3943183f8caSArnaldo Carvalho de Melo return dso__find_symbol_by_name(map->dso, name); 39579406cd7SArnaldo Carvalho de Melo } 39679406cd7SArnaldo Carvalho de Melo 39766671d00SArnaldo Carvalho de Melo struct map *map__clone(struct map *from) 39866e274f3SFrederic Weisbecker { 3997ce66139SJiri Olsa size_t size = sizeof(struct map); 4007ce66139SJiri Olsa struct map *map; 40166671d00SArnaldo Carvalho de Melo 4027ce66139SJiri Olsa if (from->dso && from->dso->kernel) 4037ce66139SJiri Olsa size += sizeof(struct kmap); 4047ce66139SJiri Olsa 4057ce66139SJiri Olsa map = memdup(from, size); 40666671d00SArnaldo Carvalho de Melo if (map != NULL) { 407e3a42cddSElena Reshetova refcount_set(&map->refcnt, 1); 40866671d00SArnaldo Carvalho de Melo RB_CLEAR_NODE(&map->rb_node); 40966671d00SArnaldo Carvalho de Melo dso__get(map->dso); 41066671d00SArnaldo Carvalho de Melo } 41166671d00SArnaldo Carvalho de Melo 41266671d00SArnaldo Carvalho de Melo return map; 41366e274f3SFrederic Weisbecker } 41466e274f3SFrederic Weisbecker 415237a7e04SArnaldo Carvalho de Melo size_t map__fprintf(struct map *map, FILE *fp) 41666e274f3SFrederic Weisbecker { 4179486aa38SArnaldo Carvalho de Melo return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %" PRIx64 " %s\n", 418237a7e04SArnaldo Carvalho de Melo map->start, map->end, map->pgoff, map->dso->name); 41966e274f3SFrederic Weisbecker } 4207a2b6209SKirill Smelkov 421547a92e0SAkihiro Nagai size_t map__fprintf_dsoname(struct map *map, FILE *fp) 422547a92e0SAkihiro Nagai { 4231c492422SJiri Olsa char buf[symbol_conf.pad_output_len_dso + 1]; 4248f28f19aSFeng Tang const char *dsoname = "[unknown]"; 425547a92e0SAkihiro Nagai 4265eae7d84SArnaldo Carvalho de Melo if (map && map->dso) { 4270bc8d205SAkihiro Nagai if (symbol_conf.show_kernel_path && map->dso->long_name) 4280bc8d205SAkihiro Nagai dsoname = map->dso->long_name; 4295eae7d84SArnaldo Carvalho de Melo else 430547a92e0SAkihiro Nagai dsoname = map->dso->name; 4318f28f19aSFeng Tang } 432547a92e0SAkihiro Nagai 4331c492422SJiri Olsa if (symbol_conf.pad_output_len_dso) { 4341c492422SJiri Olsa scnprintf_pad(buf, symbol_conf.pad_output_len_dso, "%s", dsoname); 4351c492422SJiri Olsa dsoname = buf; 4361c492422SJiri Olsa } 4371c492422SJiri Olsa 438547a92e0SAkihiro Nagai return fprintf(fp, "%s", dsoname); 439547a92e0SAkihiro Nagai } 440547a92e0SAkihiro Nagai 441e2d88aaaSArnaldo Carvalho de Melo char *map__srcline(struct map *map, u64 addr, struct symbol *sym) 442e2d88aaaSArnaldo Carvalho de Melo { 443e2d88aaaSArnaldo Carvalho de Melo if (map == NULL) 444e2d88aaaSArnaldo Carvalho de Melo return SRCLINE_UNKNOWN; 445e2d88aaaSArnaldo Carvalho de Melo return get_srcline(map->dso, map__rip_2objdump(map, addr), sym, true, true, addr); 446e2d88aaaSArnaldo Carvalho de Melo } 447e2d88aaaSArnaldo Carvalho de Melo 448cc8fae1dSAdrian Hunter int map__fprintf_srcline(struct map *map, u64 addr, const char *prefix, 449cc8fae1dSAdrian Hunter FILE *fp) 450cc8fae1dSAdrian Hunter { 451cc8fae1dSAdrian Hunter int ret = 0; 452cc8fae1dSAdrian Hunter 453cc8fae1dSAdrian Hunter if (map && map->dso) { 454e2d88aaaSArnaldo Carvalho de Melo char *srcline = map__srcline(map, addr, NULL); 455c395c355SNick Desaulniers if (strncmp(srcline, SRCLINE_UNKNOWN, strlen(SRCLINE_UNKNOWN)) != 0) 456cc8fae1dSAdrian Hunter ret = fprintf(fp, "%s%s", prefix, srcline); 457cc8fae1dSAdrian Hunter free_srcline(srcline); 458cc8fae1dSAdrian Hunter } 459cc8fae1dSAdrian Hunter return ret; 460cc8fae1dSAdrian Hunter } 461cc8fae1dSAdrian Hunter 462dd2e18e9SAndi Kleen void srccode_state_free(struct srccode_state *state) 463dd2e18e9SAndi Kleen { 464dd2e18e9SAndi Kleen zfree(&state->srcfile); 465dd2e18e9SAndi Kleen state->line = 0; 466dd2e18e9SAndi Kleen } 467dd2e18e9SAndi Kleen 4681d5077bdSAdrian Hunter /** 4691d5077bdSAdrian Hunter * map__rip_2objdump - convert symbol start address to objdump address. 4701d5077bdSAdrian Hunter * @map: memory map 4711d5077bdSAdrian Hunter * @rip: symbol start address 4721d5077bdSAdrian Hunter * 4737a2b6209SKirill Smelkov * objdump wants/reports absolute IPs for ET_EXEC, and RIPs for ET_DYN. 4740131c4ecSAdrian Hunter * map->dso->adjust_symbols==1 for ET_EXEC-like cases except ET_REL which is 4750131c4ecSAdrian Hunter * relative to section start. 4761d5077bdSAdrian Hunter * 4771d5077bdSAdrian Hunter * Return: Address suitable for passing to "objdump --start-address=" 4787a2b6209SKirill Smelkov */ 4797a2b6209SKirill Smelkov u64 map__rip_2objdump(struct map *map, u64 rip) 4807a2b6209SKirill Smelkov { 48197802f3bSAdrian Hunter struct kmap *kmap = __map__kmap(map); 48297802f3bSAdrian Hunter 48397802f3bSAdrian Hunter /* 48497802f3bSAdrian Hunter * vmlinux does not have program headers for PTI entry trampolines and 48597802f3bSAdrian Hunter * kcore may not either. However the trampoline object code is on the 48697802f3bSAdrian Hunter * main kernel map, so just use that instead. 48797802f3bSAdrian Hunter */ 48897802f3bSAdrian Hunter if (kmap && is_entry_trampoline(kmap->name) && kmap->kmaps && kmap->kmaps->machine) { 48997802f3bSAdrian Hunter struct map *kernel_map = machine__kernel_map(kmap->kmaps->machine); 49097802f3bSAdrian Hunter 49197802f3bSAdrian Hunter if (kernel_map) 49297802f3bSAdrian Hunter map = kernel_map; 49397802f3bSAdrian Hunter } 49497802f3bSAdrian Hunter 4950131c4ecSAdrian Hunter if (!map->dso->adjust_symbols) 4960131c4ecSAdrian Hunter return rip; 4970131c4ecSAdrian Hunter 4980131c4ecSAdrian Hunter if (map->dso->rel) 4990131c4ecSAdrian Hunter return rip - map->pgoff; 5000131c4ecSAdrian Hunter 501a58f7033SWang Nan /* 502a58f7033SWang Nan * kernel modules also have DSO_TYPE_USER in dso->kernel, 503a58f7033SWang Nan * but all kernel modules are ET_REL, so won't get here. 504a58f7033SWang Nan */ 5051c695c88SJiri Olsa if (map->dso->kernel == DSO_SPACE__USER) 506a58f7033SWang Nan return rip + map->dso->text_offset; 507a58f7033SWang Nan 5089176753dSAdrian Hunter return map->unmap_ip(map, rip) - map->reloc; 5097a2b6209SKirill Smelkov } 510ee11b90bSKirill Smelkov 5111d5077bdSAdrian Hunter /** 5121d5077bdSAdrian Hunter * map__objdump_2mem - convert objdump address to a memory address. 5131d5077bdSAdrian Hunter * @map: memory map 5141d5077bdSAdrian Hunter * @ip: objdump address 5151d5077bdSAdrian Hunter * 5161d5077bdSAdrian Hunter * Closely related to map__rip_2objdump(), this function takes an address from 5171d5077bdSAdrian Hunter * objdump and converts it to a memory address. Note this assumes that @map 5181d5077bdSAdrian Hunter * contains the address. To be sure the result is valid, check it forwards 5191d5077bdSAdrian Hunter * e.g. map__rip_2objdump(map->map_ip(map, map__objdump_2mem(map, ip))) == ip 5201d5077bdSAdrian Hunter * 5211d5077bdSAdrian Hunter * Return: Memory address. 5221d5077bdSAdrian Hunter */ 5231d5077bdSAdrian Hunter u64 map__objdump_2mem(struct map *map, u64 ip) 5241d5077bdSAdrian Hunter { 5251d5077bdSAdrian Hunter if (!map->dso->adjust_symbols) 5261d5077bdSAdrian Hunter return map->unmap_ip(map, ip); 5271d5077bdSAdrian Hunter 5281d5077bdSAdrian Hunter if (map->dso->rel) 5291d5077bdSAdrian Hunter return map->unmap_ip(map, ip + map->pgoff); 5301d5077bdSAdrian Hunter 531a58f7033SWang Nan /* 532a58f7033SWang Nan * kernel modules also have DSO_TYPE_USER in dso->kernel, 533a58f7033SWang Nan * but all kernel modules are ET_REL, so won't get here. 534a58f7033SWang Nan */ 5351c695c88SJiri Olsa if (map->dso->kernel == DSO_SPACE__USER) 536a58f7033SWang Nan return map->unmap_ip(map, ip - map->dso->text_offset); 537a58f7033SWang Nan 5389176753dSAdrian Hunter return ip + map->reloc; 5391d5077bdSAdrian Hunter } 5401d5077bdSAdrian Hunter 5419a29ceeeSArnaldo Carvalho de Melo void maps__init(struct maps *maps, struct machine *machine) 5421eee78aeSArnaldo Carvalho de Melo { 5439a29ceeeSArnaldo Carvalho de Melo maps->entries = RB_ROOT; 5449a29ceeeSArnaldo Carvalho de Melo init_rwsem(&maps->lock); 5459a29ceeeSArnaldo Carvalho de Melo maps->machine = machine; 5469a29ceeeSArnaldo Carvalho de Melo maps->last_search_by_name = NULL; 5479a29ceeeSArnaldo Carvalho de Melo maps->nr_maps = 0; 5489a29ceeeSArnaldo Carvalho de Melo maps->maps_by_name = NULL; 5499a29ceeeSArnaldo Carvalho de Melo refcount_set(&maps->refcnt, 1); 550c6e718ffSArnaldo Carvalho de Melo } 551c6e718ffSArnaldo Carvalho de Melo 5529a29ceeeSArnaldo Carvalho de Melo static void __maps__free_maps_by_name(struct maps *maps) 553a7c2b572SArnaldo Carvalho de Melo { 554a7c2b572SArnaldo Carvalho de Melo /* 555a7c2b572SArnaldo Carvalho de Melo * Free everything to try to do it from the rbtree in the next search 556a7c2b572SArnaldo Carvalho de Melo */ 5579a29ceeeSArnaldo Carvalho de Melo zfree(&maps->maps_by_name); 5589a29ceeeSArnaldo Carvalho de Melo maps->nr_maps_allocated = 0; 559a7c2b572SArnaldo Carvalho de Melo } 560a7c2b572SArnaldo Carvalho de Melo 5619a29ceeeSArnaldo Carvalho de Melo void maps__insert(struct maps *maps, struct map *map) 56241f30914SArnaldo Carvalho de Melo { 563a7c2b572SArnaldo Carvalho de Melo down_write(&maps->lock); 564a7c2b572SArnaldo Carvalho de Melo __maps__insert(maps, map); 5659a29ceeeSArnaldo Carvalho de Melo ++maps->nr_maps; 566a7c2b572SArnaldo Carvalho de Melo 567484214f4SJiri Olsa if (map->dso && map->dso->kernel) { 568484214f4SJiri Olsa struct kmap *kmap = map__kmap(map); 569484214f4SJiri Olsa 570484214f4SJiri Olsa if (kmap) 571484214f4SJiri Olsa kmap->kmaps = maps; 572484214f4SJiri Olsa else 573484214f4SJiri Olsa pr_err("Internal error: kernel dso with non kernel map\n"); 574484214f4SJiri Olsa } 575484214f4SJiri Olsa 576484214f4SJiri Olsa 577a7c2b572SArnaldo Carvalho de Melo /* 578a7c2b572SArnaldo Carvalho de Melo * If we already performed some search by name, then we need to add the just 579a7c2b572SArnaldo Carvalho de Melo * inserted map and resort. 580a7c2b572SArnaldo Carvalho de Melo */ 5819a29ceeeSArnaldo Carvalho de Melo if (maps->maps_by_name) { 5829a29ceeeSArnaldo Carvalho de Melo if (maps->nr_maps > maps->nr_maps_allocated) { 5839a29ceeeSArnaldo Carvalho de Melo int nr_allocate = maps->nr_maps * 2; 5849a29ceeeSArnaldo Carvalho de Melo struct map **maps_by_name = realloc(maps->maps_by_name, nr_allocate * sizeof(map)); 585a7c2b572SArnaldo Carvalho de Melo 586a7c2b572SArnaldo Carvalho de Melo if (maps_by_name == NULL) { 58779b6bb73SArnaldo Carvalho de Melo __maps__free_maps_by_name(maps); 58885fc95d7SCengiz Can up_write(&maps->lock); 589a7c2b572SArnaldo Carvalho de Melo return; 590a7c2b572SArnaldo Carvalho de Melo } 591a7c2b572SArnaldo Carvalho de Melo 5929a29ceeeSArnaldo Carvalho de Melo maps->maps_by_name = maps_by_name; 5939a29ceeeSArnaldo Carvalho de Melo maps->nr_maps_allocated = nr_allocate; 594a7c2b572SArnaldo Carvalho de Melo } 5959a29ceeeSArnaldo Carvalho de Melo maps->maps_by_name[maps->nr_maps - 1] = map; 59679b6bb73SArnaldo Carvalho de Melo __maps__sort_by_name(maps); 597a7c2b572SArnaldo Carvalho de Melo } 598a7c2b572SArnaldo Carvalho de Melo up_write(&maps->lock); 59941f30914SArnaldo Carvalho de Melo } 60041f30914SArnaldo Carvalho de Melo 601a82f15e3SArnaldo Carvalho de Melo static void __maps__remove(struct maps *maps, struct map *map) 602a82f15e3SArnaldo Carvalho de Melo { 603a82f15e3SArnaldo Carvalho de Melo rb_erase_init(&map->rb_node, &maps->entries); 604a82f15e3SArnaldo Carvalho de Melo map__put(map); 605a82f15e3SArnaldo Carvalho de Melo } 606a82f15e3SArnaldo Carvalho de Melo 6079a29ceeeSArnaldo Carvalho de Melo void maps__remove(struct maps *maps, struct map *map) 6081ae14516SArnaldo Carvalho de Melo { 609a7c2b572SArnaldo Carvalho de Melo down_write(&maps->lock); 6109a29ceeeSArnaldo Carvalho de Melo if (maps->last_search_by_name == map) 6119a29ceeeSArnaldo Carvalho de Melo maps->last_search_by_name = NULL; 6121ae14516SArnaldo Carvalho de Melo 613a7c2b572SArnaldo Carvalho de Melo __maps__remove(maps, map); 6149a29ceeeSArnaldo Carvalho de Melo --maps->nr_maps; 6159a29ceeeSArnaldo Carvalho de Melo if (maps->maps_by_name) 61679b6bb73SArnaldo Carvalho de Melo __maps__free_maps_by_name(maps); 617a7c2b572SArnaldo Carvalho de Melo up_write(&maps->lock); 6181ae14516SArnaldo Carvalho de Melo } 6191ae14516SArnaldo Carvalho de Melo 6206a2ffcddSArnaldo Carvalho de Melo static void __maps__purge(struct maps *maps) 621591765fdSArnaldo Carvalho de Melo { 6228efc4f05SArnaldo Carvalho de Melo struct map *pos, *next; 623591765fdSArnaldo Carvalho de Melo 6248efc4f05SArnaldo Carvalho de Melo maps__for_each_entry_safe(maps, pos, next) { 6258efc4f05SArnaldo Carvalho de Melo rb_erase_init(&pos->rb_node, &maps->entries); 62684c2cafaSArnaldo Carvalho de Melo map__put(pos); 627da3a53a7SChangbin Du } 628da3a53a7SChangbin Du } 629da3a53a7SChangbin Du 63079b6bb73SArnaldo Carvalho de Melo void maps__exit(struct maps *maps) 6311eee78aeSArnaldo Carvalho de Melo { 6320a7c74eaSArnaldo Carvalho de Melo down_write(&maps->lock); 6336a2ffcddSArnaldo Carvalho de Melo __maps__purge(maps); 6340a7c74eaSArnaldo Carvalho de Melo up_write(&maps->lock); 6351eee78aeSArnaldo Carvalho de Melo } 6361eee78aeSArnaldo Carvalho de Melo 63779b6bb73SArnaldo Carvalho de Melo bool maps__empty(struct maps *maps) 638591765fdSArnaldo Carvalho de Melo { 63979b6bb73SArnaldo Carvalho de Melo return !maps__first(maps); 640591765fdSArnaldo Carvalho de Melo } 641591765fdSArnaldo Carvalho de Melo 64279b6bb73SArnaldo Carvalho de Melo struct maps *maps__new(struct machine *machine) 64329ce3612SAdrian Hunter { 6449a29ceeeSArnaldo Carvalho de Melo struct maps *maps = zalloc(sizeof(*maps)); 64593d5731dSArnaldo Carvalho de Melo 6469a29ceeeSArnaldo Carvalho de Melo if (maps != NULL) 64779b6bb73SArnaldo Carvalho de Melo maps__init(maps, machine); 64893d5731dSArnaldo Carvalho de Melo 6499a29ceeeSArnaldo Carvalho de Melo return maps; 65093d5731dSArnaldo Carvalho de Melo } 65193d5731dSArnaldo Carvalho de Melo 6529a29ceeeSArnaldo Carvalho de Melo void maps__delete(struct maps *maps) 65393d5731dSArnaldo Carvalho de Melo { 6549a29ceeeSArnaldo Carvalho de Melo maps__exit(maps); 6559a29ceeeSArnaldo Carvalho de Melo unwind__finish_access(maps); 6569a29ceeeSArnaldo Carvalho de Melo free(maps); 65793d5731dSArnaldo Carvalho de Melo } 65893d5731dSArnaldo Carvalho de Melo 6599a29ceeeSArnaldo Carvalho de Melo void maps__put(struct maps *maps) 660a26ca671SArnaldo Carvalho de Melo { 6619a29ceeeSArnaldo Carvalho de Melo if (maps && refcount_dec_and_test(&maps->refcnt)) 6629a29ceeeSArnaldo Carvalho de Melo maps__delete(maps); 663a26ca671SArnaldo Carvalho de Melo } 664a26ca671SArnaldo Carvalho de Melo 6659a29ceeeSArnaldo Carvalho de Melo struct symbol *maps__find_symbol(struct maps *maps, u64 addr, struct map **mapp) 6664b8cf846SArnaldo Carvalho de Melo { 6679a29ceeeSArnaldo Carvalho de Melo struct map *map = maps__find(maps, addr); 6684b8cf846SArnaldo Carvalho de Melo 6694afc81cdSMasami Hiramatsu /* Ensure map is loaded before using map->map_ip */ 670be39db9fSArnaldo Carvalho de Melo if (map != NULL && map__load(map) >= 0) { 6717e5e1b14SArnaldo Carvalho de Melo if (mapp != NULL) 6727e5e1b14SArnaldo Carvalho de Melo *mapp = map; 673be39db9fSArnaldo Carvalho de Melo return map__find_symbol(map, map->map_ip(map, addr)); 6747e5e1b14SArnaldo Carvalho de Melo } 6757e5e1b14SArnaldo Carvalho de Melo 6767e5e1b14SArnaldo Carvalho de Melo return NULL; 6777e5e1b14SArnaldo Carvalho de Melo } 6787e5e1b14SArnaldo Carvalho de Melo 67903db8b58SAdrian Hunter static bool map__contains_symbol(struct map *map, struct symbol *sym) 68003db8b58SAdrian Hunter { 68103db8b58SAdrian Hunter u64 ip = map->unmap_ip(map, sym->start); 68203db8b58SAdrian Hunter 68303db8b58SAdrian Hunter return ip >= map->start && ip < map->end; 68403db8b58SAdrian Hunter } 68503db8b58SAdrian Hunter 68679b6bb73SArnaldo Carvalho de Melo struct symbol *maps__find_symbol_by_name(struct maps *maps, const char *name, struct map **mapp) 6877e5e1b14SArnaldo Carvalho de Melo { 6886a2ffcddSArnaldo Carvalho de Melo struct symbol *sym; 6898efc4f05SArnaldo Carvalho de Melo struct map *pos; 6907e5e1b14SArnaldo Carvalho de Melo 6910a7c74eaSArnaldo Carvalho de Melo down_read(&maps->lock); 6926a2ffcddSArnaldo Carvalho de Melo 6938efc4f05SArnaldo Carvalho de Melo maps__for_each_entry(maps, pos) { 694be39db9fSArnaldo Carvalho de Melo sym = map__find_symbol_by_name(pos, name); 6957e5e1b14SArnaldo Carvalho de Melo 6967e5e1b14SArnaldo Carvalho de Melo if (sym == NULL) 6977e5e1b14SArnaldo Carvalho de Melo continue; 69803db8b58SAdrian Hunter if (!map__contains_symbol(pos, sym)) { 69903db8b58SAdrian Hunter sym = NULL; 70003db8b58SAdrian Hunter continue; 70103db8b58SAdrian Hunter } 7027e5e1b14SArnaldo Carvalho de Melo if (mapp != NULL) 7037e5e1b14SArnaldo Carvalho de Melo *mapp = pos; 7046a2ffcddSArnaldo Carvalho de Melo goto out; 7057e5e1b14SArnaldo Carvalho de Melo } 7064b8cf846SArnaldo Carvalho de Melo 7076a2ffcddSArnaldo Carvalho de Melo sym = NULL; 7086a2ffcddSArnaldo Carvalho de Melo out: 7090a7c74eaSArnaldo Carvalho de Melo up_read(&maps->lock); 7106a2ffcddSArnaldo Carvalho de Melo return sym; 7114b8cf846SArnaldo Carvalho de Melo } 7124b8cf846SArnaldo Carvalho de Melo 7139a29ceeeSArnaldo Carvalho de Melo int maps__find_ams(struct maps *maps, struct addr_map_symbol *ams) 7144e987712SArnaldo Carvalho de Melo { 715d46a4cdfSArnaldo Carvalho de Melo if (ams->addr < ams->ms.map->start || ams->addr >= ams->ms.map->end) { 7169a29ceeeSArnaldo Carvalho de Melo if (maps == NULL) 7174e987712SArnaldo Carvalho de Melo return -1; 7189a29ceeeSArnaldo Carvalho de Melo ams->ms.map = maps__find(maps, ams->addr); 719d46a4cdfSArnaldo Carvalho de Melo if (ams->ms.map == NULL) 7204e987712SArnaldo Carvalho de Melo return -1; 7214e987712SArnaldo Carvalho de Melo } 7224e987712SArnaldo Carvalho de Melo 723d46a4cdfSArnaldo Carvalho de Melo ams->al_addr = ams->ms.map->map_ip(ams->ms.map, ams->addr); 724d46a4cdfSArnaldo Carvalho de Melo ams->ms.sym = map__find_symbol(ams->ms.map, ams->al_addr); 7254e987712SArnaldo Carvalho de Melo 726d46a4cdfSArnaldo Carvalho de Melo return ams->ms.sym ? 0 : -1; 7274e987712SArnaldo Carvalho de Melo } 7284e987712SArnaldo Carvalho de Melo 72979b6bb73SArnaldo Carvalho de Melo size_t maps__fprintf(struct maps *maps, FILE *fp) 730c6e718ffSArnaldo Carvalho de Melo { 7316a2ffcddSArnaldo Carvalho de Melo size_t printed = 0; 7328efc4f05SArnaldo Carvalho de Melo struct map *pos; 733c6e718ffSArnaldo Carvalho de Melo 7340a7c74eaSArnaldo Carvalho de Melo down_read(&maps->lock); 7356a2ffcddSArnaldo Carvalho de Melo 7368efc4f05SArnaldo Carvalho de Melo maps__for_each_entry(maps, pos) { 737c6e718ffSArnaldo Carvalho de Melo printed += fprintf(fp, "Map:"); 738c6e718ffSArnaldo Carvalho de Melo printed += map__fprintf(pos, fp); 739c6e718ffSArnaldo Carvalho de Melo if (verbose > 2) { 7403183f8caSArnaldo Carvalho de Melo printed += dso__fprintf(pos->dso, fp); 741c6e718ffSArnaldo Carvalho de Melo printed += fprintf(fp, "--\n"); 742c6e718ffSArnaldo Carvalho de Melo } 743c6e718ffSArnaldo Carvalho de Melo } 744c6e718ffSArnaldo Carvalho de Melo 7450a7c74eaSArnaldo Carvalho de Melo up_read(&maps->lock); 7466a2ffcddSArnaldo Carvalho de Melo 747c6e718ffSArnaldo Carvalho de Melo return printed; 748c6e718ffSArnaldo Carvalho de Melo } 749c6e718ffSArnaldo Carvalho de Melo 75079b6bb73SArnaldo Carvalho de Melo int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp) 751c6e718ffSArnaldo Carvalho de Melo { 7526a2ffcddSArnaldo Carvalho de Melo struct rb_root *root; 7536a9405b5SKonstantin Khlebnikov struct rb_node *next, *first; 7540a1eae39SArnaldo Carvalho de Melo int err = 0; 755c6e718ffSArnaldo Carvalho de Melo 7560a7c74eaSArnaldo Carvalho de Melo down_write(&maps->lock); 7576a2ffcddSArnaldo Carvalho de Melo 7586a2ffcddSArnaldo Carvalho de Melo root = &maps->entries; 7596a2ffcddSArnaldo Carvalho de Melo 7606a9405b5SKonstantin Khlebnikov /* 7616a9405b5SKonstantin Khlebnikov * Find first map where end > map->start. 7626a9405b5SKonstantin Khlebnikov * Same as find_vma() in kernel. 7636a9405b5SKonstantin Khlebnikov */ 7646a9405b5SKonstantin Khlebnikov next = root->rb_node; 7656a9405b5SKonstantin Khlebnikov first = NULL; 7666a9405b5SKonstantin Khlebnikov while (next) { 7676a9405b5SKonstantin Khlebnikov struct map *pos = rb_entry(next, struct map, rb_node); 7686a9405b5SKonstantin Khlebnikov 7696a9405b5SKonstantin Khlebnikov if (pos->end > map->start) { 7706a9405b5SKonstantin Khlebnikov first = next; 7716a9405b5SKonstantin Khlebnikov if (pos->start <= map->start) 7726a9405b5SKonstantin Khlebnikov break; 7736a9405b5SKonstantin Khlebnikov next = next->rb_left; 7746a9405b5SKonstantin Khlebnikov } else 7756a9405b5SKonstantin Khlebnikov next = next->rb_right; 7766a9405b5SKonstantin Khlebnikov } 7776a9405b5SKonstantin Khlebnikov 7786a9405b5SKonstantin Khlebnikov next = first; 779c6e718ffSArnaldo Carvalho de Melo while (next) { 780c6e718ffSArnaldo Carvalho de Melo struct map *pos = rb_entry(next, struct map, rb_node); 781c6e718ffSArnaldo Carvalho de Melo next = rb_next(&pos->rb_node); 782c6e718ffSArnaldo Carvalho de Melo 7836a9405b5SKonstantin Khlebnikov /* 7846a9405b5SKonstantin Khlebnikov * Stop if current map starts after map->end. 7856a9405b5SKonstantin Khlebnikov * Maps are ordered by start: next will not overlap for sure. 7866a9405b5SKonstantin Khlebnikov */ 7876a9405b5SKonstantin Khlebnikov if (pos->start >= map->end) 7886a9405b5SKonstantin Khlebnikov break; 789c6e718ffSArnaldo Carvalho de Melo 790c6e718ffSArnaldo Carvalho de Melo if (verbose >= 2) { 79121e8c810SAlexis Berlemont 79221e8c810SAlexis Berlemont if (use_browser) { 793d8e75a11SArnaldo Carvalho de Melo pr_debug("overlapping maps in %s (disable tui for more info)\n", 79421e8c810SAlexis Berlemont map->dso->name); 79521e8c810SAlexis Berlemont } else { 796c6e718ffSArnaldo Carvalho de Melo fputs("overlapping maps:\n", fp); 797c6e718ffSArnaldo Carvalho de Melo map__fprintf(map, fp); 798c6e718ffSArnaldo Carvalho de Melo map__fprintf(pos, fp); 799c6e718ffSArnaldo Carvalho de Melo } 80021e8c810SAlexis Berlemont } 801c6e718ffSArnaldo Carvalho de Melo 802facf3f06SArnaldo Carvalho de Melo rb_erase_init(&pos->rb_node, root); 803c6e718ffSArnaldo Carvalho de Melo /* 804c6e718ffSArnaldo Carvalho de Melo * Now check if we need to create new maps for areas not 805c6e718ffSArnaldo Carvalho de Melo * overlapped by the new map: 806c6e718ffSArnaldo Carvalho de Melo */ 807c6e718ffSArnaldo Carvalho de Melo if (map->start > pos->start) { 808c6e718ffSArnaldo Carvalho de Melo struct map *before = map__clone(pos); 809c6e718ffSArnaldo Carvalho de Melo 8100a1eae39SArnaldo Carvalho de Melo if (before == NULL) { 8110a1eae39SArnaldo Carvalho de Melo err = -ENOMEM; 81284c2cafaSArnaldo Carvalho de Melo goto put_map; 8130a1eae39SArnaldo Carvalho de Melo } 814c6e718ffSArnaldo Carvalho de Melo 81577faf4d0SStephane Eranian before->end = map->start; 81679b6bb73SArnaldo Carvalho de Melo __maps__insert(maps, before); 81721e8c810SAlexis Berlemont if (verbose >= 2 && !use_browser) 818c6e718ffSArnaldo Carvalho de Melo map__fprintf(before, fp); 819d91130e9SMasami Hiramatsu map__put(before); 820c6e718ffSArnaldo Carvalho de Melo } 821c6e718ffSArnaldo Carvalho de Melo 822c6e718ffSArnaldo Carvalho de Melo if (map->end < pos->end) { 823c6e718ffSArnaldo Carvalho de Melo struct map *after = map__clone(pos); 824c6e718ffSArnaldo Carvalho de Melo 8250a1eae39SArnaldo Carvalho de Melo if (after == NULL) { 8260a1eae39SArnaldo Carvalho de Melo err = -ENOMEM; 82784c2cafaSArnaldo Carvalho de Melo goto put_map; 8280a1eae39SArnaldo Carvalho de Melo } 829c6e718ffSArnaldo Carvalho de Melo 83077faf4d0SStephane Eranian after->start = map->end; 831ee212d6eSSteve MacLean after->pgoff += map->end - pos->start; 832ee212d6eSSteve MacLean assert(pos->map_ip(pos, map->end) == after->map_ip(after, map->end)); 83379b6bb73SArnaldo Carvalho de Melo __maps__insert(maps, after); 83421e8c810SAlexis Berlemont if (verbose >= 2 && !use_browser) 835c6e718ffSArnaldo Carvalho de Melo map__fprintf(after, fp); 836d91130e9SMasami Hiramatsu map__put(after); 837c6e718ffSArnaldo Carvalho de Melo } 83884c2cafaSArnaldo Carvalho de Melo put_map: 83984c2cafaSArnaldo Carvalho de Melo map__put(pos); 8400a1eae39SArnaldo Carvalho de Melo 8410a1eae39SArnaldo Carvalho de Melo if (err) 8426a2ffcddSArnaldo Carvalho de Melo goto out; 8436a2ffcddSArnaldo Carvalho de Melo } 8446a2ffcddSArnaldo Carvalho de Melo 8456a2ffcddSArnaldo Carvalho de Melo err = 0; 8466a2ffcddSArnaldo Carvalho de Melo out: 8470a7c74eaSArnaldo Carvalho de Melo up_write(&maps->lock); 8480a1eae39SArnaldo Carvalho de Melo return err; 849c6e718ffSArnaldo Carvalho de Melo } 850c6e718ffSArnaldo Carvalho de Melo 851c6e718ffSArnaldo Carvalho de Melo /* 852c6e718ffSArnaldo Carvalho de Melo * XXX This should not really _copy_ te maps, but refcount them. 853c6e718ffSArnaldo Carvalho de Melo */ 85479b6bb73SArnaldo Carvalho de Melo int maps__clone(struct thread *thread, struct maps *parent) 855c6e718ffSArnaldo Carvalho de Melo { 8569a29ceeeSArnaldo Carvalho de Melo struct maps *maps = thread->maps; 8576a2ffcddSArnaldo Carvalho de Melo int err = -ENOMEM; 8584bb7123dSArnaldo Carvalho de Melo struct map *map; 8594bb7123dSArnaldo Carvalho de Melo 86079b6bb73SArnaldo Carvalho de Melo down_read(&parent->lock); 8616a2ffcddSArnaldo Carvalho de Melo 86279b6bb73SArnaldo Carvalho de Melo maps__for_each_entry(parent, map) { 863c6e718ffSArnaldo Carvalho de Melo struct map *new = map__clone(map); 864c6e718ffSArnaldo Carvalho de Melo if (new == NULL) 8656a2ffcddSArnaldo Carvalho de Melo goto out_unlock; 8666c502584SJiri Olsa 8679a29ceeeSArnaldo Carvalho de Melo err = unwind__prepare_access(maps, new, NULL); 8686c502584SJiri Olsa if (err) 8696c502584SJiri Olsa goto out_unlock; 8706c502584SJiri Olsa 8719a29ceeeSArnaldo Carvalho de Melo maps__insert(maps, new); 872bae32b50SMasami Hiramatsu map__put(new); 873c6e718ffSArnaldo Carvalho de Melo } 8746a2ffcddSArnaldo Carvalho de Melo 8756a2ffcddSArnaldo Carvalho de Melo err = 0; 8766a2ffcddSArnaldo Carvalho de Melo out_unlock: 87779b6bb73SArnaldo Carvalho de Melo up_read(&parent->lock); 8786a2ffcddSArnaldo Carvalho de Melo return err; 879c6e718ffSArnaldo Carvalho de Melo } 880c6e718ffSArnaldo Carvalho de Melo 8816a2ffcddSArnaldo Carvalho de Melo static void __maps__insert(struct maps *maps, struct map *map) 8824b8cf846SArnaldo Carvalho de Melo { 8831eee78aeSArnaldo Carvalho de Melo struct rb_node **p = &maps->entries.rb_node; 8844b8cf846SArnaldo Carvalho de Melo struct rb_node *parent = NULL; 8854b8cf846SArnaldo Carvalho de Melo const u64 ip = map->start; 8864b8cf846SArnaldo Carvalho de Melo struct map *m; 8874b8cf846SArnaldo Carvalho de Melo 8884b8cf846SArnaldo Carvalho de Melo while (*p != NULL) { 8894b8cf846SArnaldo Carvalho de Melo parent = *p; 8904b8cf846SArnaldo Carvalho de Melo m = rb_entry(parent, struct map, rb_node); 8914b8cf846SArnaldo Carvalho de Melo if (ip < m->start) 8924b8cf846SArnaldo Carvalho de Melo p = &(*p)->rb_left; 8934b8cf846SArnaldo Carvalho de Melo else 8944b8cf846SArnaldo Carvalho de Melo p = &(*p)->rb_right; 8954b8cf846SArnaldo Carvalho de Melo } 8964b8cf846SArnaldo Carvalho de Melo 8974b8cf846SArnaldo Carvalho de Melo rb_link_node(&map->rb_node, parent, p); 8981eee78aeSArnaldo Carvalho de Melo rb_insert_color(&map->rb_node, &maps->entries); 89984c2cafaSArnaldo Carvalho de Melo map__get(map); 9004b8cf846SArnaldo Carvalho de Melo } 9014b8cf846SArnaldo Carvalho de Melo 9021eee78aeSArnaldo Carvalho de Melo struct map *maps__find(struct maps *maps, u64 ip) 9034b8cf846SArnaldo Carvalho de Melo { 904b18e0888SEric Saint-Etienne struct rb_node *p; 9054b8cf846SArnaldo Carvalho de Melo struct map *m; 9064b8cf846SArnaldo Carvalho de Melo 9070a7c74eaSArnaldo Carvalho de Melo down_read(&maps->lock); 9086a2ffcddSArnaldo Carvalho de Melo 909b18e0888SEric Saint-Etienne p = maps->entries.rb_node; 910b18e0888SEric Saint-Etienne while (p != NULL) { 911b18e0888SEric Saint-Etienne m = rb_entry(p, struct map, rb_node); 9124b8cf846SArnaldo Carvalho de Melo if (ip < m->start) 913b18e0888SEric Saint-Etienne p = p->rb_left; 9144955ea22SNamhyung Kim else if (ip >= m->end) 915b18e0888SEric Saint-Etienne p = p->rb_right; 9164b8cf846SArnaldo Carvalho de Melo else 9176a2ffcddSArnaldo Carvalho de Melo goto out; 9184b8cf846SArnaldo Carvalho de Melo } 9194b8cf846SArnaldo Carvalho de Melo 9206a2ffcddSArnaldo Carvalho de Melo m = NULL; 9216a2ffcddSArnaldo Carvalho de Melo out: 9220a7c74eaSArnaldo Carvalho de Melo up_read(&maps->lock); 9236a2ffcddSArnaldo Carvalho de Melo return m; 9244b8cf846SArnaldo Carvalho de Melo } 9258e0cf965SAdrian Hunter 9261eee78aeSArnaldo Carvalho de Melo struct map *maps__first(struct maps *maps) 9278e0cf965SAdrian Hunter { 9281eee78aeSArnaldo Carvalho de Melo struct rb_node *first = rb_first(&maps->entries); 9298e0cf965SAdrian Hunter 9308e0cf965SAdrian Hunter if (first) 9318e0cf965SAdrian Hunter return rb_entry(first, struct map, rb_node); 9328e0cf965SAdrian Hunter return NULL; 9338e0cf965SAdrian Hunter } 9348e0cf965SAdrian Hunter 93520419d3aSArnaldo Carvalho de Melo static struct map *__map__next(struct map *map) 9368e0cf965SAdrian Hunter { 9378e0cf965SAdrian Hunter struct rb_node *next = rb_next(&map->rb_node); 9388e0cf965SAdrian Hunter 9398e0cf965SAdrian Hunter if (next) 9408e0cf965SAdrian Hunter return rb_entry(next, struct map, rb_node); 9418e0cf965SAdrian Hunter return NULL; 9428e0cf965SAdrian Hunter } 943ba92732eSWang Nan 94420419d3aSArnaldo Carvalho de Melo struct map *map__next(struct map *map) 94520419d3aSArnaldo Carvalho de Melo { 94620419d3aSArnaldo Carvalho de Melo return map ? __map__next(map) : NULL; 94720419d3aSArnaldo Carvalho de Melo } 94820419d3aSArnaldo Carvalho de Melo 9495759a682SAdrian Hunter struct kmap *__map__kmap(struct map *map) 9505759a682SAdrian Hunter { 9515759a682SAdrian Hunter if (!map->dso || !map->dso->kernel) 9525759a682SAdrian Hunter return NULL; 9535759a682SAdrian Hunter return (struct kmap *)(map + 1); 9545759a682SAdrian Hunter } 9555759a682SAdrian Hunter 956ba92732eSWang Nan struct kmap *map__kmap(struct map *map) 957ba92732eSWang Nan { 9585759a682SAdrian Hunter struct kmap *kmap = __map__kmap(map); 9595759a682SAdrian Hunter 9605759a682SAdrian Hunter if (!kmap) 961ba92732eSWang Nan pr_err("Internal error: map__kmap with a non-kernel map\n"); 9625759a682SAdrian Hunter return kmap; 963ba92732eSWang Nan } 964ba92732eSWang Nan 96579b6bb73SArnaldo Carvalho de Melo struct maps *map__kmaps(struct map *map) 966ba92732eSWang Nan { 967ba92732eSWang Nan struct kmap *kmap = map__kmap(map); 968ba92732eSWang Nan 969ba92732eSWang Nan if (!kmap || !kmap->kmaps) { 970ba92732eSWang Nan pr_err("Internal error: map__kmaps with a non-kernel map\n"); 971ba92732eSWang Nan return NULL; 972ba92732eSWang Nan } 973ba92732eSWang Nan return kmap->kmaps; 974ba92732eSWang Nan } 975