18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci#include "symbol.h" 38c2ecf20Sopenharmony_ci#include <assert.h> 48c2ecf20Sopenharmony_ci#include <errno.h> 58c2ecf20Sopenharmony_ci#include <inttypes.h> 68c2ecf20Sopenharmony_ci#include <limits.h> 78c2ecf20Sopenharmony_ci#include <stdlib.h> 88c2ecf20Sopenharmony_ci#include <string.h> 98c2ecf20Sopenharmony_ci#include <stdio.h> 108c2ecf20Sopenharmony_ci#include <unistd.h> 118c2ecf20Sopenharmony_ci#include <uapi/linux/mman.h> /* To get things like MAP_HUGETLB even on older libc headers */ 128c2ecf20Sopenharmony_ci#include "dso.h" 138c2ecf20Sopenharmony_ci#include "map.h" 148c2ecf20Sopenharmony_ci#include "map_symbol.h" 158c2ecf20Sopenharmony_ci#include "thread.h" 168c2ecf20Sopenharmony_ci#include "vdso.h" 178c2ecf20Sopenharmony_ci#include "build-id.h" 188c2ecf20Sopenharmony_ci#include "debug.h" 198c2ecf20Sopenharmony_ci#include "machine.h" 208c2ecf20Sopenharmony_ci#include <linux/string.h> 218c2ecf20Sopenharmony_ci#include <linux/zalloc.h> 228c2ecf20Sopenharmony_ci#include "srcline.h" 238c2ecf20Sopenharmony_ci#include "namespaces.h" 248c2ecf20Sopenharmony_ci#include "unwind.h" 258c2ecf20Sopenharmony_ci#include "srccode.h" 268c2ecf20Sopenharmony_ci#include "ui/ui.h" 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_cistatic void __maps__insert(struct maps *maps, struct map *map); 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_cistatic inline int is_android_lib(const char *filename) 318c2ecf20Sopenharmony_ci{ 328c2ecf20Sopenharmony_ci return strstarts(filename, "/data/app-lib/") || 338c2ecf20Sopenharmony_ci strstarts(filename, "/system/lib/"); 348c2ecf20Sopenharmony_ci} 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_cistatic inline bool replace_android_lib(const char *filename, char *newfilename) 378c2ecf20Sopenharmony_ci{ 388c2ecf20Sopenharmony_ci const char *libname; 398c2ecf20Sopenharmony_ci char *app_abi; 408c2ecf20Sopenharmony_ci size_t app_abi_length, new_length; 418c2ecf20Sopenharmony_ci size_t lib_length = 0; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci libname = strrchr(filename, '/'); 448c2ecf20Sopenharmony_ci if (libname) 458c2ecf20Sopenharmony_ci lib_length = strlen(libname); 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci app_abi = getenv("APP_ABI"); 488c2ecf20Sopenharmony_ci if (!app_abi) 498c2ecf20Sopenharmony_ci return false; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci app_abi_length = strlen(app_abi); 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci if (strstarts(filename, "/data/app-lib/")) { 548c2ecf20Sopenharmony_ci char *apk_path; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci if (!app_abi_length) 578c2ecf20Sopenharmony_ci return false; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci new_length = 7 + app_abi_length + lib_length; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci apk_path = getenv("APK_PATH"); 628c2ecf20Sopenharmony_ci if (apk_path) { 638c2ecf20Sopenharmony_ci new_length += strlen(apk_path) + 1; 648c2ecf20Sopenharmony_ci if (new_length > PATH_MAX) 658c2ecf20Sopenharmony_ci return false; 668c2ecf20Sopenharmony_ci snprintf(newfilename, new_length, 678c2ecf20Sopenharmony_ci "%s/libs/%s/%s", apk_path, app_abi, libname); 688c2ecf20Sopenharmony_ci } else { 698c2ecf20Sopenharmony_ci if (new_length > PATH_MAX) 708c2ecf20Sopenharmony_ci return false; 718c2ecf20Sopenharmony_ci snprintf(newfilename, new_length, 728c2ecf20Sopenharmony_ci "libs/%s/%s", app_abi, libname); 738c2ecf20Sopenharmony_ci } 748c2ecf20Sopenharmony_ci return true; 758c2ecf20Sopenharmony_ci } 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci if (strstarts(filename, "/system/lib/")) { 788c2ecf20Sopenharmony_ci char *ndk, *app; 798c2ecf20Sopenharmony_ci const char *arch; 808c2ecf20Sopenharmony_ci int ndk_length, app_length; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci ndk = getenv("NDK_ROOT"); 838c2ecf20Sopenharmony_ci app = getenv("APP_PLATFORM"); 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci if (!(ndk && app)) 868c2ecf20Sopenharmony_ci return false; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci ndk_length = strlen(ndk); 898c2ecf20Sopenharmony_ci app_length = strlen(app); 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci if (!(ndk_length && app_length && app_abi_length)) 928c2ecf20Sopenharmony_ci return false; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci arch = !strncmp(app_abi, "arm", 3) ? "arm" : 958c2ecf20Sopenharmony_ci !strncmp(app_abi, "mips", 4) ? "mips" : 968c2ecf20Sopenharmony_ci !strncmp(app_abi, "x86", 3) ? "x86" : NULL; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci if (!arch) 998c2ecf20Sopenharmony_ci return false; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci new_length = 27 + ndk_length + 1028c2ecf20Sopenharmony_ci app_length + lib_length 1038c2ecf20Sopenharmony_ci + strlen(arch); 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci if (new_length > PATH_MAX) 1068c2ecf20Sopenharmony_ci return false; 1078c2ecf20Sopenharmony_ci snprintf(newfilename, new_length, 1088c2ecf20Sopenharmony_ci "%.*s/platforms/%.*s/arch-%s/usr/lib/%s", 1098c2ecf20Sopenharmony_ci ndk_length, ndk, app_length, app, arch, libname); 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci return true; 1128c2ecf20Sopenharmony_ci } 1138c2ecf20Sopenharmony_ci return false; 1148c2ecf20Sopenharmony_ci} 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_civoid map__init(struct map *map, u64 start, u64 end, u64 pgoff, struct dso *dso) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci map->start = start; 1198c2ecf20Sopenharmony_ci map->end = end; 1208c2ecf20Sopenharmony_ci map->pgoff = pgoff; 1218c2ecf20Sopenharmony_ci map->reloc = 0; 1228c2ecf20Sopenharmony_ci map->dso = dso__get(dso); 1238c2ecf20Sopenharmony_ci map->map_ip = map__map_ip; 1248c2ecf20Sopenharmony_ci map->unmap_ip = map__unmap_ip; 1258c2ecf20Sopenharmony_ci RB_CLEAR_NODE(&map->rb_node); 1268c2ecf20Sopenharmony_ci map->erange_warned = false; 1278c2ecf20Sopenharmony_ci refcount_set(&map->refcnt, 1); 1288c2ecf20Sopenharmony_ci} 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_cistruct map *map__new(struct machine *machine, u64 start, u64 len, 1318c2ecf20Sopenharmony_ci u64 pgoff, struct dso_id *id, 1328c2ecf20Sopenharmony_ci u32 prot, u32 flags, char *filename, 1338c2ecf20Sopenharmony_ci struct thread *thread) 1348c2ecf20Sopenharmony_ci{ 1358c2ecf20Sopenharmony_ci struct map *map = malloc(sizeof(*map)); 1368c2ecf20Sopenharmony_ci struct nsinfo *nsi = NULL; 1378c2ecf20Sopenharmony_ci struct nsinfo *nnsi; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci if (map != NULL) { 1408c2ecf20Sopenharmony_ci char newfilename[PATH_MAX]; 1418c2ecf20Sopenharmony_ci struct dso *dso; 1428c2ecf20Sopenharmony_ci int anon, no_dso, vdso, android; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci android = is_android_lib(filename); 1458c2ecf20Sopenharmony_ci anon = is_anon_memory(filename) || flags & MAP_HUGETLB; 1468c2ecf20Sopenharmony_ci vdso = is_vdso_map(filename); 1478c2ecf20Sopenharmony_ci no_dso = is_no_dso_memory(filename); 1488c2ecf20Sopenharmony_ci map->prot = prot; 1498c2ecf20Sopenharmony_ci map->flags = flags; 1508c2ecf20Sopenharmony_ci nsi = nsinfo__get(thread->nsinfo); 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci if ((anon || no_dso) && nsi && (prot & PROT_EXEC)) { 1538c2ecf20Sopenharmony_ci snprintf(newfilename, sizeof(newfilename), 1548c2ecf20Sopenharmony_ci "/tmp/perf-%d.map", nsi->pid); 1558c2ecf20Sopenharmony_ci filename = newfilename; 1568c2ecf20Sopenharmony_ci } 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci if (android) { 1598c2ecf20Sopenharmony_ci if (replace_android_lib(filename, newfilename)) 1608c2ecf20Sopenharmony_ci filename = newfilename; 1618c2ecf20Sopenharmony_ci } 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci if (vdso) { 1648c2ecf20Sopenharmony_ci /* The vdso maps are always on the host and not the 1658c2ecf20Sopenharmony_ci * container. Ensure that we don't use setns to look 1668c2ecf20Sopenharmony_ci * them up. 1678c2ecf20Sopenharmony_ci */ 1688c2ecf20Sopenharmony_ci nnsi = nsinfo__copy(nsi); 1698c2ecf20Sopenharmony_ci if (nnsi) { 1708c2ecf20Sopenharmony_ci nsinfo__put(nsi); 1718c2ecf20Sopenharmony_ci nnsi->need_setns = false; 1728c2ecf20Sopenharmony_ci nsi = nnsi; 1738c2ecf20Sopenharmony_ci } 1748c2ecf20Sopenharmony_ci pgoff = 0; 1758c2ecf20Sopenharmony_ci dso = machine__findnew_vdso(machine, thread); 1768c2ecf20Sopenharmony_ci } else 1778c2ecf20Sopenharmony_ci dso = machine__findnew_dso_id(machine, filename, id); 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci if (dso == NULL) 1808c2ecf20Sopenharmony_ci goto out_delete; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci map__init(map, start, start + len, pgoff, dso); 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci if (anon || no_dso) { 1858c2ecf20Sopenharmony_ci map->map_ip = map->unmap_ip = identity__map_ip; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci /* 1888c2ecf20Sopenharmony_ci * Set memory without DSO as loaded. All map__find_* 1898c2ecf20Sopenharmony_ci * functions still return NULL, and we avoid the 1908c2ecf20Sopenharmony_ci * unnecessary map__load warning. 1918c2ecf20Sopenharmony_ci */ 1928c2ecf20Sopenharmony_ci if (!(prot & PROT_EXEC)) 1938c2ecf20Sopenharmony_ci dso__set_loaded(dso); 1948c2ecf20Sopenharmony_ci } 1958c2ecf20Sopenharmony_ci dso->nsinfo = nsi; 1968c2ecf20Sopenharmony_ci dso__put(dso); 1978c2ecf20Sopenharmony_ci } 1988c2ecf20Sopenharmony_ci return map; 1998c2ecf20Sopenharmony_ciout_delete: 2008c2ecf20Sopenharmony_ci nsinfo__put(nsi); 2018c2ecf20Sopenharmony_ci free(map); 2028c2ecf20Sopenharmony_ci return NULL; 2038c2ecf20Sopenharmony_ci} 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci/* 2068c2ecf20Sopenharmony_ci * Constructor variant for modules (where we know from /proc/modules where 2078c2ecf20Sopenharmony_ci * they are loaded) and for vmlinux, where only after we load all the 2088c2ecf20Sopenharmony_ci * symbols we'll know where it starts and ends. 2098c2ecf20Sopenharmony_ci */ 2108c2ecf20Sopenharmony_cistruct map *map__new2(u64 start, struct dso *dso) 2118c2ecf20Sopenharmony_ci{ 2128c2ecf20Sopenharmony_ci struct map *map = calloc(1, (sizeof(*map) + 2138c2ecf20Sopenharmony_ci (dso->kernel ? sizeof(struct kmap) : 0))); 2148c2ecf20Sopenharmony_ci if (map != NULL) { 2158c2ecf20Sopenharmony_ci /* 2168c2ecf20Sopenharmony_ci * ->end will be filled after we load all the symbols 2178c2ecf20Sopenharmony_ci */ 2188c2ecf20Sopenharmony_ci map__init(map, start, 0, 0, dso); 2198c2ecf20Sopenharmony_ci } 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci return map; 2228c2ecf20Sopenharmony_ci} 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_cibool __map__is_kernel(const struct map *map) 2258c2ecf20Sopenharmony_ci{ 2268c2ecf20Sopenharmony_ci if (!map->dso->kernel) 2278c2ecf20Sopenharmony_ci return false; 2288c2ecf20Sopenharmony_ci return machine__kernel_map(map__kmaps((struct map *)map)->machine) == map; 2298c2ecf20Sopenharmony_ci} 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_cibool __map__is_extra_kernel_map(const struct map *map) 2328c2ecf20Sopenharmony_ci{ 2338c2ecf20Sopenharmony_ci struct kmap *kmap = __map__kmap((struct map *)map); 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci return kmap && kmap->name[0]; 2368c2ecf20Sopenharmony_ci} 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_cibool __map__is_bpf_prog(const struct map *map) 2398c2ecf20Sopenharmony_ci{ 2408c2ecf20Sopenharmony_ci const char *name; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci if (map->dso->binary_type == DSO_BINARY_TYPE__BPF_PROG_INFO) 2438c2ecf20Sopenharmony_ci return true; 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci /* 2468c2ecf20Sopenharmony_ci * If PERF_RECORD_BPF_EVENT is not included, the dso will not have 2478c2ecf20Sopenharmony_ci * type of DSO_BINARY_TYPE__BPF_PROG_INFO. In such cases, we can 2488c2ecf20Sopenharmony_ci * guess the type based on name. 2498c2ecf20Sopenharmony_ci */ 2508c2ecf20Sopenharmony_ci name = map->dso->short_name; 2518c2ecf20Sopenharmony_ci return name && (strstr(name, "bpf_prog_") == name); 2528c2ecf20Sopenharmony_ci} 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_cibool __map__is_bpf_image(const struct map *map) 2558c2ecf20Sopenharmony_ci{ 2568c2ecf20Sopenharmony_ci const char *name; 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci if (map->dso->binary_type == DSO_BINARY_TYPE__BPF_IMAGE) 2598c2ecf20Sopenharmony_ci return true; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci /* 2628c2ecf20Sopenharmony_ci * If PERF_RECORD_KSYMBOL is not included, the dso will not have 2638c2ecf20Sopenharmony_ci * type of DSO_BINARY_TYPE__BPF_IMAGE. In such cases, we can 2648c2ecf20Sopenharmony_ci * guess the type based on name. 2658c2ecf20Sopenharmony_ci */ 2668c2ecf20Sopenharmony_ci name = map->dso->short_name; 2678c2ecf20Sopenharmony_ci return name && is_bpf_image(name); 2688c2ecf20Sopenharmony_ci} 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_cibool __map__is_ool(const struct map *map) 2718c2ecf20Sopenharmony_ci{ 2728c2ecf20Sopenharmony_ci return map->dso && map->dso->binary_type == DSO_BINARY_TYPE__OOL; 2738c2ecf20Sopenharmony_ci} 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_cibool map__has_symbols(const struct map *map) 2768c2ecf20Sopenharmony_ci{ 2778c2ecf20Sopenharmony_ci return dso__has_symbols(map->dso); 2788c2ecf20Sopenharmony_ci} 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_cistatic void map__exit(struct map *map) 2818c2ecf20Sopenharmony_ci{ 2828c2ecf20Sopenharmony_ci BUG_ON(refcount_read(&map->refcnt) != 0); 2838c2ecf20Sopenharmony_ci dso__zput(map->dso); 2848c2ecf20Sopenharmony_ci} 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_civoid map__delete(struct map *map) 2878c2ecf20Sopenharmony_ci{ 2888c2ecf20Sopenharmony_ci map__exit(map); 2898c2ecf20Sopenharmony_ci free(map); 2908c2ecf20Sopenharmony_ci} 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_civoid map__put(struct map *map) 2938c2ecf20Sopenharmony_ci{ 2948c2ecf20Sopenharmony_ci if (map && refcount_dec_and_test(&map->refcnt)) 2958c2ecf20Sopenharmony_ci map__delete(map); 2968c2ecf20Sopenharmony_ci} 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_civoid map__fixup_start(struct map *map) 2998c2ecf20Sopenharmony_ci{ 3008c2ecf20Sopenharmony_ci struct rb_root_cached *symbols = &map->dso->symbols; 3018c2ecf20Sopenharmony_ci struct rb_node *nd = rb_first_cached(symbols); 3028c2ecf20Sopenharmony_ci if (nd != NULL) { 3038c2ecf20Sopenharmony_ci struct symbol *sym = rb_entry(nd, struct symbol, rb_node); 3048c2ecf20Sopenharmony_ci map->start = sym->start; 3058c2ecf20Sopenharmony_ci } 3068c2ecf20Sopenharmony_ci} 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_civoid map__fixup_end(struct map *map) 3098c2ecf20Sopenharmony_ci{ 3108c2ecf20Sopenharmony_ci struct rb_root_cached *symbols = &map->dso->symbols; 3118c2ecf20Sopenharmony_ci struct rb_node *nd = rb_last(&symbols->rb_root); 3128c2ecf20Sopenharmony_ci if (nd != NULL) { 3138c2ecf20Sopenharmony_ci struct symbol *sym = rb_entry(nd, struct symbol, rb_node); 3148c2ecf20Sopenharmony_ci map->end = sym->end; 3158c2ecf20Sopenharmony_ci } 3168c2ecf20Sopenharmony_ci} 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci#define DSO__DELETED "(deleted)" 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ciint map__load(struct map *map) 3218c2ecf20Sopenharmony_ci{ 3228c2ecf20Sopenharmony_ci const char *name = map->dso->long_name; 3238c2ecf20Sopenharmony_ci int nr; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci if (dso__loaded(map->dso)) 3268c2ecf20Sopenharmony_ci return 0; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci nr = dso__load(map->dso, map); 3298c2ecf20Sopenharmony_ci if (nr < 0) { 3308c2ecf20Sopenharmony_ci if (map->dso->has_build_id) { 3318c2ecf20Sopenharmony_ci char sbuild_id[SBUILD_ID_SIZE]; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci build_id__sprintf(&map->dso->bid, sbuild_id); 3348c2ecf20Sopenharmony_ci pr_debug("%s with build id %s not found", name, sbuild_id); 3358c2ecf20Sopenharmony_ci } else 3368c2ecf20Sopenharmony_ci pr_debug("Failed to open %s", name); 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci pr_debug(", continuing without symbols\n"); 3398c2ecf20Sopenharmony_ci return -1; 3408c2ecf20Sopenharmony_ci } else if (nr == 0) { 3418c2ecf20Sopenharmony_ci#ifdef HAVE_LIBELF_SUPPORT 3428c2ecf20Sopenharmony_ci const size_t len = strlen(name); 3438c2ecf20Sopenharmony_ci const size_t real_len = len - sizeof(DSO__DELETED); 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci if (len > sizeof(DSO__DELETED) && 3468c2ecf20Sopenharmony_ci strcmp(name + real_len + 1, DSO__DELETED) == 0) { 3478c2ecf20Sopenharmony_ci pr_debug("%.*s was updated (is prelink enabled?). " 3488c2ecf20Sopenharmony_ci "Restart the long running apps that use it!\n", 3498c2ecf20Sopenharmony_ci (int)real_len, name); 3508c2ecf20Sopenharmony_ci } else { 3518c2ecf20Sopenharmony_ci pr_debug("no symbols found in %s, maybe install a debug package?\n", name); 3528c2ecf20Sopenharmony_ci } 3538c2ecf20Sopenharmony_ci#endif 3548c2ecf20Sopenharmony_ci return -1; 3558c2ecf20Sopenharmony_ci } 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci return 0; 3588c2ecf20Sopenharmony_ci} 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_cistruct symbol *map__find_symbol(struct map *map, u64 addr) 3618c2ecf20Sopenharmony_ci{ 3628c2ecf20Sopenharmony_ci if (map__load(map) < 0) 3638c2ecf20Sopenharmony_ci return NULL; 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci return dso__find_symbol(map->dso, addr); 3668c2ecf20Sopenharmony_ci} 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_cistruct symbol *map__find_symbol_by_name(struct map *map, const char *name) 3698c2ecf20Sopenharmony_ci{ 3708c2ecf20Sopenharmony_ci if (map__load(map) < 0) 3718c2ecf20Sopenharmony_ci return NULL; 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci if (!dso__sorted_by_name(map->dso)) 3748c2ecf20Sopenharmony_ci dso__sort_by_name(map->dso); 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci return dso__find_symbol_by_name(map->dso, name); 3778c2ecf20Sopenharmony_ci} 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_cistruct map *map__clone(struct map *from) 3808c2ecf20Sopenharmony_ci{ 3818c2ecf20Sopenharmony_ci size_t size = sizeof(struct map); 3828c2ecf20Sopenharmony_ci struct map *map; 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci if (from->dso && from->dso->kernel) 3858c2ecf20Sopenharmony_ci size += sizeof(struct kmap); 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci map = memdup(from, size); 3888c2ecf20Sopenharmony_ci if (map != NULL) { 3898c2ecf20Sopenharmony_ci refcount_set(&map->refcnt, 1); 3908c2ecf20Sopenharmony_ci RB_CLEAR_NODE(&map->rb_node); 3918c2ecf20Sopenharmony_ci dso__get(map->dso); 3928c2ecf20Sopenharmony_ci } 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci return map; 3958c2ecf20Sopenharmony_ci} 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_cisize_t map__fprintf(struct map *map, FILE *fp) 3988c2ecf20Sopenharmony_ci{ 3998c2ecf20Sopenharmony_ci return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %" PRIx64 " %s\n", 4008c2ecf20Sopenharmony_ci map->start, map->end, map->pgoff, map->dso->name); 4018c2ecf20Sopenharmony_ci} 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_cisize_t map__fprintf_dsoname(struct map *map, FILE *fp) 4048c2ecf20Sopenharmony_ci{ 4058c2ecf20Sopenharmony_ci char buf[symbol_conf.pad_output_len_dso + 1]; 4068c2ecf20Sopenharmony_ci const char *dsoname = "[unknown]"; 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci if (map && map->dso) { 4098c2ecf20Sopenharmony_ci if (symbol_conf.show_kernel_path && map->dso->long_name) 4108c2ecf20Sopenharmony_ci dsoname = map->dso->long_name; 4118c2ecf20Sopenharmony_ci else 4128c2ecf20Sopenharmony_ci dsoname = map->dso->name; 4138c2ecf20Sopenharmony_ci } 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci if (symbol_conf.pad_output_len_dso) { 4168c2ecf20Sopenharmony_ci scnprintf_pad(buf, symbol_conf.pad_output_len_dso, "%s", dsoname); 4178c2ecf20Sopenharmony_ci dsoname = buf; 4188c2ecf20Sopenharmony_ci } 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci return fprintf(fp, "%s", dsoname); 4218c2ecf20Sopenharmony_ci} 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_cichar *map__srcline(struct map *map, u64 addr, struct symbol *sym) 4248c2ecf20Sopenharmony_ci{ 4258c2ecf20Sopenharmony_ci if (map == NULL) 4268c2ecf20Sopenharmony_ci return SRCLINE_UNKNOWN; 4278c2ecf20Sopenharmony_ci return get_srcline(map->dso, map__rip_2objdump(map, addr), sym, true, true, addr); 4288c2ecf20Sopenharmony_ci} 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ciint map__fprintf_srcline(struct map *map, u64 addr, const char *prefix, 4318c2ecf20Sopenharmony_ci FILE *fp) 4328c2ecf20Sopenharmony_ci{ 4338c2ecf20Sopenharmony_ci int ret = 0; 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci if (map && map->dso) { 4368c2ecf20Sopenharmony_ci char *srcline = map__srcline(map, addr, NULL); 4378c2ecf20Sopenharmony_ci if (strncmp(srcline, SRCLINE_UNKNOWN, strlen(SRCLINE_UNKNOWN)) != 0) 4388c2ecf20Sopenharmony_ci ret = fprintf(fp, "%s%s", prefix, srcline); 4398c2ecf20Sopenharmony_ci free_srcline(srcline); 4408c2ecf20Sopenharmony_ci } 4418c2ecf20Sopenharmony_ci return ret; 4428c2ecf20Sopenharmony_ci} 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_civoid srccode_state_free(struct srccode_state *state) 4458c2ecf20Sopenharmony_ci{ 4468c2ecf20Sopenharmony_ci zfree(&state->srcfile); 4478c2ecf20Sopenharmony_ci state->line = 0; 4488c2ecf20Sopenharmony_ci} 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci/** 4518c2ecf20Sopenharmony_ci * map__rip_2objdump - convert symbol start address to objdump address. 4528c2ecf20Sopenharmony_ci * @map: memory map 4538c2ecf20Sopenharmony_ci * @rip: symbol start address 4548c2ecf20Sopenharmony_ci * 4558c2ecf20Sopenharmony_ci * objdump wants/reports absolute IPs for ET_EXEC, and RIPs for ET_DYN. 4568c2ecf20Sopenharmony_ci * map->dso->adjust_symbols==1 for ET_EXEC-like cases except ET_REL which is 4578c2ecf20Sopenharmony_ci * relative to section start. 4588c2ecf20Sopenharmony_ci * 4598c2ecf20Sopenharmony_ci * Return: Address suitable for passing to "objdump --start-address=" 4608c2ecf20Sopenharmony_ci */ 4618c2ecf20Sopenharmony_ciu64 map__rip_2objdump(struct map *map, u64 rip) 4628c2ecf20Sopenharmony_ci{ 4638c2ecf20Sopenharmony_ci struct kmap *kmap = __map__kmap(map); 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci /* 4668c2ecf20Sopenharmony_ci * vmlinux does not have program headers for PTI entry trampolines and 4678c2ecf20Sopenharmony_ci * kcore may not either. However the trampoline object code is on the 4688c2ecf20Sopenharmony_ci * main kernel map, so just use that instead. 4698c2ecf20Sopenharmony_ci */ 4708c2ecf20Sopenharmony_ci if (kmap && is_entry_trampoline(kmap->name) && kmap->kmaps && kmap->kmaps->machine) { 4718c2ecf20Sopenharmony_ci struct map *kernel_map = machine__kernel_map(kmap->kmaps->machine); 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci if (kernel_map) 4748c2ecf20Sopenharmony_ci map = kernel_map; 4758c2ecf20Sopenharmony_ci } 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci if (!map->dso->adjust_symbols) 4788c2ecf20Sopenharmony_ci return rip; 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci if (map->dso->rel) 4818c2ecf20Sopenharmony_ci return rip - map->pgoff; 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci /* 4848c2ecf20Sopenharmony_ci * kernel modules also have DSO_TYPE_USER in dso->kernel, 4858c2ecf20Sopenharmony_ci * but all kernel modules are ET_REL, so won't get here. 4868c2ecf20Sopenharmony_ci */ 4878c2ecf20Sopenharmony_ci if (map->dso->kernel == DSO_SPACE__USER) 4888c2ecf20Sopenharmony_ci return rip + map->dso->text_offset; 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci return map->unmap_ip(map, rip) - map->reloc; 4918c2ecf20Sopenharmony_ci} 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci/** 4948c2ecf20Sopenharmony_ci * map__objdump_2mem - convert objdump address to a memory address. 4958c2ecf20Sopenharmony_ci * @map: memory map 4968c2ecf20Sopenharmony_ci * @ip: objdump address 4978c2ecf20Sopenharmony_ci * 4988c2ecf20Sopenharmony_ci * Closely related to map__rip_2objdump(), this function takes an address from 4998c2ecf20Sopenharmony_ci * objdump and converts it to a memory address. Note this assumes that @map 5008c2ecf20Sopenharmony_ci * contains the address. To be sure the result is valid, check it forwards 5018c2ecf20Sopenharmony_ci * e.g. map__rip_2objdump(map->map_ip(map, map__objdump_2mem(map, ip))) == ip 5028c2ecf20Sopenharmony_ci * 5038c2ecf20Sopenharmony_ci * Return: Memory address. 5048c2ecf20Sopenharmony_ci */ 5058c2ecf20Sopenharmony_ciu64 map__objdump_2mem(struct map *map, u64 ip) 5068c2ecf20Sopenharmony_ci{ 5078c2ecf20Sopenharmony_ci if (!map->dso->adjust_symbols) 5088c2ecf20Sopenharmony_ci return map->unmap_ip(map, ip); 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci if (map->dso->rel) 5118c2ecf20Sopenharmony_ci return map->unmap_ip(map, ip + map->pgoff); 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci /* 5148c2ecf20Sopenharmony_ci * kernel modules also have DSO_TYPE_USER in dso->kernel, 5158c2ecf20Sopenharmony_ci * but all kernel modules are ET_REL, so won't get here. 5168c2ecf20Sopenharmony_ci */ 5178c2ecf20Sopenharmony_ci if (map->dso->kernel == DSO_SPACE__USER) 5188c2ecf20Sopenharmony_ci return map->unmap_ip(map, ip - map->dso->text_offset); 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci return ip + map->reloc; 5218c2ecf20Sopenharmony_ci} 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_civoid maps__init(struct maps *maps, struct machine *machine) 5248c2ecf20Sopenharmony_ci{ 5258c2ecf20Sopenharmony_ci maps->entries = RB_ROOT; 5268c2ecf20Sopenharmony_ci init_rwsem(&maps->lock); 5278c2ecf20Sopenharmony_ci maps->machine = machine; 5288c2ecf20Sopenharmony_ci maps->last_search_by_name = NULL; 5298c2ecf20Sopenharmony_ci maps->nr_maps = 0; 5308c2ecf20Sopenharmony_ci maps->maps_by_name = NULL; 5318c2ecf20Sopenharmony_ci refcount_set(&maps->refcnt, 1); 5328c2ecf20Sopenharmony_ci} 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_cistatic void __maps__free_maps_by_name(struct maps *maps) 5358c2ecf20Sopenharmony_ci{ 5368c2ecf20Sopenharmony_ci /* 5378c2ecf20Sopenharmony_ci * Free everything to try to do it from the rbtree in the next search 5388c2ecf20Sopenharmony_ci */ 5398c2ecf20Sopenharmony_ci zfree(&maps->maps_by_name); 5408c2ecf20Sopenharmony_ci maps->nr_maps_allocated = 0; 5418c2ecf20Sopenharmony_ci} 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_civoid maps__insert(struct maps *maps, struct map *map) 5448c2ecf20Sopenharmony_ci{ 5458c2ecf20Sopenharmony_ci down_write(&maps->lock); 5468c2ecf20Sopenharmony_ci __maps__insert(maps, map); 5478c2ecf20Sopenharmony_ci ++maps->nr_maps; 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci if (map->dso && map->dso->kernel) { 5508c2ecf20Sopenharmony_ci struct kmap *kmap = map__kmap(map); 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci if (kmap) 5538c2ecf20Sopenharmony_ci kmap->kmaps = maps; 5548c2ecf20Sopenharmony_ci else 5558c2ecf20Sopenharmony_ci pr_err("Internal error: kernel dso with non kernel map\n"); 5568c2ecf20Sopenharmony_ci } 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci /* 5608c2ecf20Sopenharmony_ci * If we already performed some search by name, then we need to add the just 5618c2ecf20Sopenharmony_ci * inserted map and resort. 5628c2ecf20Sopenharmony_ci */ 5638c2ecf20Sopenharmony_ci if (maps->maps_by_name) { 5648c2ecf20Sopenharmony_ci if (maps->nr_maps > maps->nr_maps_allocated) { 5658c2ecf20Sopenharmony_ci int nr_allocate = maps->nr_maps * 2; 5668c2ecf20Sopenharmony_ci struct map **maps_by_name = realloc(maps->maps_by_name, nr_allocate * sizeof(map)); 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci if (maps_by_name == NULL) { 5698c2ecf20Sopenharmony_ci __maps__free_maps_by_name(maps); 5708c2ecf20Sopenharmony_ci up_write(&maps->lock); 5718c2ecf20Sopenharmony_ci return; 5728c2ecf20Sopenharmony_ci } 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci maps->maps_by_name = maps_by_name; 5758c2ecf20Sopenharmony_ci maps->nr_maps_allocated = nr_allocate; 5768c2ecf20Sopenharmony_ci } 5778c2ecf20Sopenharmony_ci maps->maps_by_name[maps->nr_maps - 1] = map; 5788c2ecf20Sopenharmony_ci __maps__sort_by_name(maps); 5798c2ecf20Sopenharmony_ci } 5808c2ecf20Sopenharmony_ci up_write(&maps->lock); 5818c2ecf20Sopenharmony_ci} 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_cistatic void __maps__remove(struct maps *maps, struct map *map) 5848c2ecf20Sopenharmony_ci{ 5858c2ecf20Sopenharmony_ci rb_erase_init(&map->rb_node, &maps->entries); 5868c2ecf20Sopenharmony_ci map__put(map); 5878c2ecf20Sopenharmony_ci} 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_civoid maps__remove(struct maps *maps, struct map *map) 5908c2ecf20Sopenharmony_ci{ 5918c2ecf20Sopenharmony_ci down_write(&maps->lock); 5928c2ecf20Sopenharmony_ci if (maps->last_search_by_name == map) 5938c2ecf20Sopenharmony_ci maps->last_search_by_name = NULL; 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci __maps__remove(maps, map); 5968c2ecf20Sopenharmony_ci --maps->nr_maps; 5978c2ecf20Sopenharmony_ci if (maps->maps_by_name) 5988c2ecf20Sopenharmony_ci __maps__free_maps_by_name(maps); 5998c2ecf20Sopenharmony_ci up_write(&maps->lock); 6008c2ecf20Sopenharmony_ci} 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_cistatic void __maps__purge(struct maps *maps) 6038c2ecf20Sopenharmony_ci{ 6048c2ecf20Sopenharmony_ci struct map *pos, *next; 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci maps__for_each_entry_safe(maps, pos, next) { 6078c2ecf20Sopenharmony_ci rb_erase_init(&pos->rb_node, &maps->entries); 6088c2ecf20Sopenharmony_ci map__put(pos); 6098c2ecf20Sopenharmony_ci } 6108c2ecf20Sopenharmony_ci} 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_civoid maps__exit(struct maps *maps) 6138c2ecf20Sopenharmony_ci{ 6148c2ecf20Sopenharmony_ci down_write(&maps->lock); 6158c2ecf20Sopenharmony_ci __maps__purge(maps); 6168c2ecf20Sopenharmony_ci up_write(&maps->lock); 6178c2ecf20Sopenharmony_ci} 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_cibool maps__empty(struct maps *maps) 6208c2ecf20Sopenharmony_ci{ 6218c2ecf20Sopenharmony_ci return !maps__first(maps); 6228c2ecf20Sopenharmony_ci} 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_cistruct maps *maps__new(struct machine *machine) 6258c2ecf20Sopenharmony_ci{ 6268c2ecf20Sopenharmony_ci struct maps *maps = zalloc(sizeof(*maps)); 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci if (maps != NULL) 6298c2ecf20Sopenharmony_ci maps__init(maps, machine); 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci return maps; 6328c2ecf20Sopenharmony_ci} 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_civoid maps__delete(struct maps *maps) 6358c2ecf20Sopenharmony_ci{ 6368c2ecf20Sopenharmony_ci maps__exit(maps); 6378c2ecf20Sopenharmony_ci unwind__finish_access(maps); 6388c2ecf20Sopenharmony_ci free(maps); 6398c2ecf20Sopenharmony_ci} 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_civoid maps__put(struct maps *maps) 6428c2ecf20Sopenharmony_ci{ 6438c2ecf20Sopenharmony_ci if (maps && refcount_dec_and_test(&maps->refcnt)) 6448c2ecf20Sopenharmony_ci maps__delete(maps); 6458c2ecf20Sopenharmony_ci} 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_cistruct symbol *maps__find_symbol(struct maps *maps, u64 addr, struct map **mapp) 6488c2ecf20Sopenharmony_ci{ 6498c2ecf20Sopenharmony_ci struct map *map = maps__find(maps, addr); 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci /* Ensure map is loaded before using map->map_ip */ 6528c2ecf20Sopenharmony_ci if (map != NULL && map__load(map) >= 0) { 6538c2ecf20Sopenharmony_ci if (mapp != NULL) 6548c2ecf20Sopenharmony_ci *mapp = map; 6558c2ecf20Sopenharmony_ci return map__find_symbol(map, map->map_ip(map, addr)); 6568c2ecf20Sopenharmony_ci } 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci return NULL; 6598c2ecf20Sopenharmony_ci} 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_cistatic bool map__contains_symbol(struct map *map, struct symbol *sym) 6628c2ecf20Sopenharmony_ci{ 6638c2ecf20Sopenharmony_ci u64 ip = map->unmap_ip(map, sym->start); 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci return ip >= map->start && ip < map->end; 6668c2ecf20Sopenharmony_ci} 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_cistruct symbol *maps__find_symbol_by_name(struct maps *maps, const char *name, struct map **mapp) 6698c2ecf20Sopenharmony_ci{ 6708c2ecf20Sopenharmony_ci struct symbol *sym; 6718c2ecf20Sopenharmony_ci struct map *pos; 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci down_read(&maps->lock); 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci maps__for_each_entry(maps, pos) { 6768c2ecf20Sopenharmony_ci sym = map__find_symbol_by_name(pos, name); 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci if (sym == NULL) 6798c2ecf20Sopenharmony_ci continue; 6808c2ecf20Sopenharmony_ci if (!map__contains_symbol(pos, sym)) { 6818c2ecf20Sopenharmony_ci sym = NULL; 6828c2ecf20Sopenharmony_ci continue; 6838c2ecf20Sopenharmony_ci } 6848c2ecf20Sopenharmony_ci if (mapp != NULL) 6858c2ecf20Sopenharmony_ci *mapp = pos; 6868c2ecf20Sopenharmony_ci goto out; 6878c2ecf20Sopenharmony_ci } 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci sym = NULL; 6908c2ecf20Sopenharmony_ciout: 6918c2ecf20Sopenharmony_ci up_read(&maps->lock); 6928c2ecf20Sopenharmony_ci return sym; 6938c2ecf20Sopenharmony_ci} 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ciint maps__find_ams(struct maps *maps, struct addr_map_symbol *ams) 6968c2ecf20Sopenharmony_ci{ 6978c2ecf20Sopenharmony_ci if (ams->addr < ams->ms.map->start || ams->addr >= ams->ms.map->end) { 6988c2ecf20Sopenharmony_ci if (maps == NULL) 6998c2ecf20Sopenharmony_ci return -1; 7008c2ecf20Sopenharmony_ci ams->ms.map = maps__find(maps, ams->addr); 7018c2ecf20Sopenharmony_ci if (ams->ms.map == NULL) 7028c2ecf20Sopenharmony_ci return -1; 7038c2ecf20Sopenharmony_ci } 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci ams->al_addr = ams->ms.map->map_ip(ams->ms.map, ams->addr); 7068c2ecf20Sopenharmony_ci ams->ms.sym = map__find_symbol(ams->ms.map, ams->al_addr); 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci return ams->ms.sym ? 0 : -1; 7098c2ecf20Sopenharmony_ci} 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_cisize_t maps__fprintf(struct maps *maps, FILE *fp) 7128c2ecf20Sopenharmony_ci{ 7138c2ecf20Sopenharmony_ci size_t printed = 0; 7148c2ecf20Sopenharmony_ci struct map *pos; 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci down_read(&maps->lock); 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci maps__for_each_entry(maps, pos) { 7198c2ecf20Sopenharmony_ci printed += fprintf(fp, "Map:"); 7208c2ecf20Sopenharmony_ci printed += map__fprintf(pos, fp); 7218c2ecf20Sopenharmony_ci if (verbose > 2) { 7228c2ecf20Sopenharmony_ci printed += dso__fprintf(pos->dso, fp); 7238c2ecf20Sopenharmony_ci printed += fprintf(fp, "--\n"); 7248c2ecf20Sopenharmony_ci } 7258c2ecf20Sopenharmony_ci } 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci up_read(&maps->lock); 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci return printed; 7308c2ecf20Sopenharmony_ci} 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ciint maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp) 7338c2ecf20Sopenharmony_ci{ 7348c2ecf20Sopenharmony_ci struct rb_root *root; 7358c2ecf20Sopenharmony_ci struct rb_node *next, *first; 7368c2ecf20Sopenharmony_ci int err = 0; 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci down_write(&maps->lock); 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci root = &maps->entries; 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci /* 7438c2ecf20Sopenharmony_ci * Find first map where end > map->start. 7448c2ecf20Sopenharmony_ci * Same as find_vma() in kernel. 7458c2ecf20Sopenharmony_ci */ 7468c2ecf20Sopenharmony_ci next = root->rb_node; 7478c2ecf20Sopenharmony_ci first = NULL; 7488c2ecf20Sopenharmony_ci while (next) { 7498c2ecf20Sopenharmony_ci struct map *pos = rb_entry(next, struct map, rb_node); 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci if (pos->end > map->start) { 7528c2ecf20Sopenharmony_ci first = next; 7538c2ecf20Sopenharmony_ci if (pos->start <= map->start) 7548c2ecf20Sopenharmony_ci break; 7558c2ecf20Sopenharmony_ci next = next->rb_left; 7568c2ecf20Sopenharmony_ci } else 7578c2ecf20Sopenharmony_ci next = next->rb_right; 7588c2ecf20Sopenharmony_ci } 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_ci next = first; 7618c2ecf20Sopenharmony_ci while (next) { 7628c2ecf20Sopenharmony_ci struct map *pos = rb_entry(next, struct map, rb_node); 7638c2ecf20Sopenharmony_ci next = rb_next(&pos->rb_node); 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci /* 7668c2ecf20Sopenharmony_ci * Stop if current map starts after map->end. 7678c2ecf20Sopenharmony_ci * Maps are ordered by start: next will not overlap for sure. 7688c2ecf20Sopenharmony_ci */ 7698c2ecf20Sopenharmony_ci if (pos->start >= map->end) 7708c2ecf20Sopenharmony_ci break; 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_ci if (verbose >= 2) { 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci if (use_browser) { 7758c2ecf20Sopenharmony_ci pr_debug("overlapping maps in %s (disable tui for more info)\n", 7768c2ecf20Sopenharmony_ci map->dso->name); 7778c2ecf20Sopenharmony_ci } else { 7788c2ecf20Sopenharmony_ci fputs("overlapping maps:\n", fp); 7798c2ecf20Sopenharmony_ci map__fprintf(map, fp); 7808c2ecf20Sopenharmony_ci map__fprintf(pos, fp); 7818c2ecf20Sopenharmony_ci } 7828c2ecf20Sopenharmony_ci } 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci rb_erase_init(&pos->rb_node, root); 7858c2ecf20Sopenharmony_ci /* 7868c2ecf20Sopenharmony_ci * Now check if we need to create new maps for areas not 7878c2ecf20Sopenharmony_ci * overlapped by the new map: 7888c2ecf20Sopenharmony_ci */ 7898c2ecf20Sopenharmony_ci if (map->start > pos->start) { 7908c2ecf20Sopenharmony_ci struct map *before = map__clone(pos); 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci if (before == NULL) { 7938c2ecf20Sopenharmony_ci err = -ENOMEM; 7948c2ecf20Sopenharmony_ci goto put_map; 7958c2ecf20Sopenharmony_ci } 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_ci before->end = map->start; 7988c2ecf20Sopenharmony_ci __maps__insert(maps, before); 7998c2ecf20Sopenharmony_ci if (verbose >= 2 && !use_browser) 8008c2ecf20Sopenharmony_ci map__fprintf(before, fp); 8018c2ecf20Sopenharmony_ci map__put(before); 8028c2ecf20Sopenharmony_ci } 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci if (map->end < pos->end) { 8058c2ecf20Sopenharmony_ci struct map *after = map__clone(pos); 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_ci if (after == NULL) { 8088c2ecf20Sopenharmony_ci err = -ENOMEM; 8098c2ecf20Sopenharmony_ci goto put_map; 8108c2ecf20Sopenharmony_ci } 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci after->start = map->end; 8138c2ecf20Sopenharmony_ci after->pgoff += map->end - pos->start; 8148c2ecf20Sopenharmony_ci assert(pos->map_ip(pos, map->end) == after->map_ip(after, map->end)); 8158c2ecf20Sopenharmony_ci __maps__insert(maps, after); 8168c2ecf20Sopenharmony_ci if (verbose >= 2 && !use_browser) 8178c2ecf20Sopenharmony_ci map__fprintf(after, fp); 8188c2ecf20Sopenharmony_ci map__put(after); 8198c2ecf20Sopenharmony_ci } 8208c2ecf20Sopenharmony_ciput_map: 8218c2ecf20Sopenharmony_ci map__put(pos); 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci if (err) 8248c2ecf20Sopenharmony_ci goto out; 8258c2ecf20Sopenharmony_ci } 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci err = 0; 8288c2ecf20Sopenharmony_ciout: 8298c2ecf20Sopenharmony_ci up_write(&maps->lock); 8308c2ecf20Sopenharmony_ci return err; 8318c2ecf20Sopenharmony_ci} 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci/* 8348c2ecf20Sopenharmony_ci * XXX This should not really _copy_ te maps, but refcount them. 8358c2ecf20Sopenharmony_ci */ 8368c2ecf20Sopenharmony_ciint maps__clone(struct thread *thread, struct maps *parent) 8378c2ecf20Sopenharmony_ci{ 8388c2ecf20Sopenharmony_ci struct maps *maps = thread->maps; 8398c2ecf20Sopenharmony_ci int err; 8408c2ecf20Sopenharmony_ci struct map *map; 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_ci down_read(&parent->lock); 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci maps__for_each_entry(parent, map) { 8458c2ecf20Sopenharmony_ci struct map *new = map__clone(map); 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci if (new == NULL) { 8488c2ecf20Sopenharmony_ci err = -ENOMEM; 8498c2ecf20Sopenharmony_ci goto out_unlock; 8508c2ecf20Sopenharmony_ci } 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci err = unwind__prepare_access(maps, new, NULL); 8538c2ecf20Sopenharmony_ci if (err) 8548c2ecf20Sopenharmony_ci goto out_unlock; 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci maps__insert(maps, new); 8578c2ecf20Sopenharmony_ci map__put(new); 8588c2ecf20Sopenharmony_ci } 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci err = 0; 8618c2ecf20Sopenharmony_ciout_unlock: 8628c2ecf20Sopenharmony_ci up_read(&parent->lock); 8638c2ecf20Sopenharmony_ci return err; 8648c2ecf20Sopenharmony_ci} 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_cistatic void __maps__insert(struct maps *maps, struct map *map) 8678c2ecf20Sopenharmony_ci{ 8688c2ecf20Sopenharmony_ci struct rb_node **p = &maps->entries.rb_node; 8698c2ecf20Sopenharmony_ci struct rb_node *parent = NULL; 8708c2ecf20Sopenharmony_ci const u64 ip = map->start; 8718c2ecf20Sopenharmony_ci struct map *m; 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci while (*p != NULL) { 8748c2ecf20Sopenharmony_ci parent = *p; 8758c2ecf20Sopenharmony_ci m = rb_entry(parent, struct map, rb_node); 8768c2ecf20Sopenharmony_ci if (ip < m->start) 8778c2ecf20Sopenharmony_ci p = &(*p)->rb_left; 8788c2ecf20Sopenharmony_ci else 8798c2ecf20Sopenharmony_ci p = &(*p)->rb_right; 8808c2ecf20Sopenharmony_ci } 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci rb_link_node(&map->rb_node, parent, p); 8838c2ecf20Sopenharmony_ci rb_insert_color(&map->rb_node, &maps->entries); 8848c2ecf20Sopenharmony_ci map__get(map); 8858c2ecf20Sopenharmony_ci} 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_cistruct map *maps__find(struct maps *maps, u64 ip) 8888c2ecf20Sopenharmony_ci{ 8898c2ecf20Sopenharmony_ci struct rb_node *p; 8908c2ecf20Sopenharmony_ci struct map *m; 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci down_read(&maps->lock); 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci p = maps->entries.rb_node; 8958c2ecf20Sopenharmony_ci while (p != NULL) { 8968c2ecf20Sopenharmony_ci m = rb_entry(p, struct map, rb_node); 8978c2ecf20Sopenharmony_ci if (ip < m->start) 8988c2ecf20Sopenharmony_ci p = p->rb_left; 8998c2ecf20Sopenharmony_ci else if (ip >= m->end) 9008c2ecf20Sopenharmony_ci p = p->rb_right; 9018c2ecf20Sopenharmony_ci else 9028c2ecf20Sopenharmony_ci goto out; 9038c2ecf20Sopenharmony_ci } 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci m = NULL; 9068c2ecf20Sopenharmony_ciout: 9078c2ecf20Sopenharmony_ci up_read(&maps->lock); 9088c2ecf20Sopenharmony_ci return m; 9098c2ecf20Sopenharmony_ci} 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_cistruct map *maps__first(struct maps *maps) 9128c2ecf20Sopenharmony_ci{ 9138c2ecf20Sopenharmony_ci struct rb_node *first = rb_first(&maps->entries); 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ci if (first) 9168c2ecf20Sopenharmony_ci return rb_entry(first, struct map, rb_node); 9178c2ecf20Sopenharmony_ci return NULL; 9188c2ecf20Sopenharmony_ci} 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_cistatic struct map *__map__next(struct map *map) 9218c2ecf20Sopenharmony_ci{ 9228c2ecf20Sopenharmony_ci struct rb_node *next = rb_next(&map->rb_node); 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_ci if (next) 9258c2ecf20Sopenharmony_ci return rb_entry(next, struct map, rb_node); 9268c2ecf20Sopenharmony_ci return NULL; 9278c2ecf20Sopenharmony_ci} 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_cistruct map *map__next(struct map *map) 9308c2ecf20Sopenharmony_ci{ 9318c2ecf20Sopenharmony_ci return map ? __map__next(map) : NULL; 9328c2ecf20Sopenharmony_ci} 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_cistruct kmap *__map__kmap(struct map *map) 9358c2ecf20Sopenharmony_ci{ 9368c2ecf20Sopenharmony_ci if (!map->dso || !map->dso->kernel) 9378c2ecf20Sopenharmony_ci return NULL; 9388c2ecf20Sopenharmony_ci return (struct kmap *)(map + 1); 9398c2ecf20Sopenharmony_ci} 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_cistruct kmap *map__kmap(struct map *map) 9428c2ecf20Sopenharmony_ci{ 9438c2ecf20Sopenharmony_ci struct kmap *kmap = __map__kmap(map); 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_ci if (!kmap) 9468c2ecf20Sopenharmony_ci pr_err("Internal error: map__kmap with a non-kernel map\n"); 9478c2ecf20Sopenharmony_ci return kmap; 9488c2ecf20Sopenharmony_ci} 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_cistruct maps *map__kmaps(struct map *map) 9518c2ecf20Sopenharmony_ci{ 9528c2ecf20Sopenharmony_ci struct kmap *kmap = map__kmap(map); 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_ci if (!kmap || !kmap->kmaps) { 9558c2ecf20Sopenharmony_ci pr_err("Internal error: map__kmaps with a non-kernel map\n"); 9568c2ecf20Sopenharmony_ci return NULL; 9578c2ecf20Sopenharmony_ci } 9588c2ecf20Sopenharmony_ci return kmap->kmaps; 9598c2ecf20Sopenharmony_ci} 960