162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci#include <inttypes.h> 362306a36Sopenharmony_ci#include <limits.h> 462306a36Sopenharmony_ci#include <stdio.h> 562306a36Sopenharmony_ci#include <stdlib.h> 662306a36Sopenharmony_ci#include <string.h> 762306a36Sopenharmony_ci#include <linux/string.h> 862306a36Sopenharmony_ci#include <linux/zalloc.h> 962306a36Sopenharmony_ci#include <uapi/linux/mman.h> /* To get things like MAP_HUGETLB even on older libc headers */ 1062306a36Sopenharmony_ci#include "debug.h" 1162306a36Sopenharmony_ci#include "dso.h" 1262306a36Sopenharmony_ci#include "map.h" 1362306a36Sopenharmony_ci#include "namespaces.h" 1462306a36Sopenharmony_ci#include "srcline.h" 1562306a36Sopenharmony_ci#include "symbol.h" 1662306a36Sopenharmony_ci#include "thread.h" 1762306a36Sopenharmony_ci#include "vdso.h" 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_cistatic inline int is_android_lib(const char *filename) 2062306a36Sopenharmony_ci{ 2162306a36Sopenharmony_ci return strstarts(filename, "/data/app-lib/") || 2262306a36Sopenharmony_ci strstarts(filename, "/system/lib/"); 2362306a36Sopenharmony_ci} 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_cistatic inline bool replace_android_lib(const char *filename, char *newfilename) 2662306a36Sopenharmony_ci{ 2762306a36Sopenharmony_ci const char *libname; 2862306a36Sopenharmony_ci char *app_abi; 2962306a36Sopenharmony_ci size_t app_abi_length, new_length; 3062306a36Sopenharmony_ci size_t lib_length = 0; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci libname = strrchr(filename, '/'); 3362306a36Sopenharmony_ci if (libname) 3462306a36Sopenharmony_ci lib_length = strlen(libname); 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci app_abi = getenv("APP_ABI"); 3762306a36Sopenharmony_ci if (!app_abi) 3862306a36Sopenharmony_ci return false; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci app_abi_length = strlen(app_abi); 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci if (strstarts(filename, "/data/app-lib/")) { 4362306a36Sopenharmony_ci char *apk_path; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci if (!app_abi_length) 4662306a36Sopenharmony_ci return false; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci new_length = 7 + app_abi_length + lib_length; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci apk_path = getenv("APK_PATH"); 5162306a36Sopenharmony_ci if (apk_path) { 5262306a36Sopenharmony_ci new_length += strlen(apk_path) + 1; 5362306a36Sopenharmony_ci if (new_length > PATH_MAX) 5462306a36Sopenharmony_ci return false; 5562306a36Sopenharmony_ci snprintf(newfilename, new_length, 5662306a36Sopenharmony_ci "%s/libs/%s/%s", apk_path, app_abi, libname); 5762306a36Sopenharmony_ci } else { 5862306a36Sopenharmony_ci if (new_length > PATH_MAX) 5962306a36Sopenharmony_ci return false; 6062306a36Sopenharmony_ci snprintf(newfilename, new_length, 6162306a36Sopenharmony_ci "libs/%s/%s", app_abi, libname); 6262306a36Sopenharmony_ci } 6362306a36Sopenharmony_ci return true; 6462306a36Sopenharmony_ci } 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci if (strstarts(filename, "/system/lib/")) { 6762306a36Sopenharmony_ci char *ndk, *app; 6862306a36Sopenharmony_ci const char *arch; 6962306a36Sopenharmony_ci int ndk_length, app_length; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci ndk = getenv("NDK_ROOT"); 7262306a36Sopenharmony_ci app = getenv("APP_PLATFORM"); 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci if (!(ndk && app)) 7562306a36Sopenharmony_ci return false; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci ndk_length = strlen(ndk); 7862306a36Sopenharmony_ci app_length = strlen(app); 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci if (!(ndk_length && app_length && app_abi_length)) 8162306a36Sopenharmony_ci return false; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci arch = !strncmp(app_abi, "arm", 3) ? "arm" : 8462306a36Sopenharmony_ci !strncmp(app_abi, "mips", 4) ? "mips" : 8562306a36Sopenharmony_ci !strncmp(app_abi, "x86", 3) ? "x86" : NULL; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci if (!arch) 8862306a36Sopenharmony_ci return false; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci new_length = 27 + ndk_length + 9162306a36Sopenharmony_ci app_length + lib_length 9262306a36Sopenharmony_ci + strlen(arch); 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci if (new_length > PATH_MAX) 9562306a36Sopenharmony_ci return false; 9662306a36Sopenharmony_ci snprintf(newfilename, new_length, 9762306a36Sopenharmony_ci "%.*s/platforms/%.*s/arch-%s/usr/lib/%s", 9862306a36Sopenharmony_ci ndk_length, ndk, app_length, app, arch, libname); 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci return true; 10162306a36Sopenharmony_ci } 10262306a36Sopenharmony_ci return false; 10362306a36Sopenharmony_ci} 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_civoid map__init(struct map *map, u64 start, u64 end, u64 pgoff, struct dso *dso) 10662306a36Sopenharmony_ci{ 10762306a36Sopenharmony_ci map__set_start(map, start); 10862306a36Sopenharmony_ci map__set_end(map, end); 10962306a36Sopenharmony_ci map__set_pgoff(map, pgoff); 11062306a36Sopenharmony_ci map__set_reloc(map, 0); 11162306a36Sopenharmony_ci map__set_dso(map, dso__get(dso)); 11262306a36Sopenharmony_ci map__set_map_ip(map, map__dso_map_ip); 11362306a36Sopenharmony_ci map__set_unmap_ip(map, map__dso_unmap_ip); 11462306a36Sopenharmony_ci map__set_erange_warned(map, false); 11562306a36Sopenharmony_ci refcount_set(map__refcnt(map), 1); 11662306a36Sopenharmony_ci} 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_cistruct map *map__new(struct machine *machine, u64 start, u64 len, 11962306a36Sopenharmony_ci u64 pgoff, struct dso_id *id, 12062306a36Sopenharmony_ci u32 prot, u32 flags, struct build_id *bid, 12162306a36Sopenharmony_ci char *filename, struct thread *thread) 12262306a36Sopenharmony_ci{ 12362306a36Sopenharmony_ci struct map *result; 12462306a36Sopenharmony_ci RC_STRUCT(map) *map; 12562306a36Sopenharmony_ci struct nsinfo *nsi = NULL; 12662306a36Sopenharmony_ci struct nsinfo *nnsi; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci map = malloc(sizeof(*map)); 12962306a36Sopenharmony_ci if (ADD_RC_CHK(result, map)) { 13062306a36Sopenharmony_ci char newfilename[PATH_MAX]; 13162306a36Sopenharmony_ci struct dso *dso, *header_bid_dso; 13262306a36Sopenharmony_ci int anon, no_dso, vdso, android; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci android = is_android_lib(filename); 13562306a36Sopenharmony_ci anon = is_anon_memory(filename) || flags & MAP_HUGETLB; 13662306a36Sopenharmony_ci vdso = is_vdso_map(filename); 13762306a36Sopenharmony_ci no_dso = is_no_dso_memory(filename); 13862306a36Sopenharmony_ci map->prot = prot; 13962306a36Sopenharmony_ci map->flags = flags; 14062306a36Sopenharmony_ci nsi = nsinfo__get(thread__nsinfo(thread)); 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci if ((anon || no_dso) && nsi && (prot & PROT_EXEC)) { 14362306a36Sopenharmony_ci snprintf(newfilename, sizeof(newfilename), 14462306a36Sopenharmony_ci "/tmp/perf-%d.map", nsinfo__pid(nsi)); 14562306a36Sopenharmony_ci filename = newfilename; 14662306a36Sopenharmony_ci } 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci if (android) { 14962306a36Sopenharmony_ci if (replace_android_lib(filename, newfilename)) 15062306a36Sopenharmony_ci filename = newfilename; 15162306a36Sopenharmony_ci } 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci if (vdso) { 15462306a36Sopenharmony_ci /* The vdso maps are always on the host and not the 15562306a36Sopenharmony_ci * container. Ensure that we don't use setns to look 15662306a36Sopenharmony_ci * them up. 15762306a36Sopenharmony_ci */ 15862306a36Sopenharmony_ci nnsi = nsinfo__copy(nsi); 15962306a36Sopenharmony_ci if (nnsi) { 16062306a36Sopenharmony_ci nsinfo__put(nsi); 16162306a36Sopenharmony_ci nsinfo__clear_need_setns(nnsi); 16262306a36Sopenharmony_ci nsi = nnsi; 16362306a36Sopenharmony_ci } 16462306a36Sopenharmony_ci pgoff = 0; 16562306a36Sopenharmony_ci dso = machine__findnew_vdso(machine, thread); 16662306a36Sopenharmony_ci } else 16762306a36Sopenharmony_ci dso = machine__findnew_dso_id(machine, filename, id); 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci if (dso == NULL) 17062306a36Sopenharmony_ci goto out_delete; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci map__init(result, start, start + len, pgoff, dso); 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci if (anon || no_dso) { 17562306a36Sopenharmony_ci map->map_ip = map->unmap_ip = identity__map_ip; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci /* 17862306a36Sopenharmony_ci * Set memory without DSO as loaded. All map__find_* 17962306a36Sopenharmony_ci * functions still return NULL, and we avoid the 18062306a36Sopenharmony_ci * unnecessary map__load warning. 18162306a36Sopenharmony_ci */ 18262306a36Sopenharmony_ci if (!(prot & PROT_EXEC)) 18362306a36Sopenharmony_ci dso__set_loaded(dso); 18462306a36Sopenharmony_ci } 18562306a36Sopenharmony_ci mutex_lock(&dso->lock); 18662306a36Sopenharmony_ci nsinfo__put(dso->nsinfo); 18762306a36Sopenharmony_ci dso->nsinfo = nsi; 18862306a36Sopenharmony_ci mutex_unlock(&dso->lock); 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci if (build_id__is_defined(bid)) { 19162306a36Sopenharmony_ci dso__set_build_id(dso, bid); 19262306a36Sopenharmony_ci } else { 19362306a36Sopenharmony_ci /* 19462306a36Sopenharmony_ci * If the mmap event had no build ID, search for an existing dso from the 19562306a36Sopenharmony_ci * build ID header by name. Otherwise only the dso loaded at the time of 19662306a36Sopenharmony_ci * reading the header will have the build ID set and all future mmaps will 19762306a36Sopenharmony_ci * have it missing. 19862306a36Sopenharmony_ci */ 19962306a36Sopenharmony_ci down_read(&machine->dsos.lock); 20062306a36Sopenharmony_ci header_bid_dso = __dsos__find(&machine->dsos, filename, false); 20162306a36Sopenharmony_ci up_read(&machine->dsos.lock); 20262306a36Sopenharmony_ci if (header_bid_dso && header_bid_dso->header_build_id) { 20362306a36Sopenharmony_ci dso__set_build_id(dso, &header_bid_dso->bid); 20462306a36Sopenharmony_ci dso->header_build_id = 1; 20562306a36Sopenharmony_ci } 20662306a36Sopenharmony_ci } 20762306a36Sopenharmony_ci dso__put(dso); 20862306a36Sopenharmony_ci } 20962306a36Sopenharmony_ci return result; 21062306a36Sopenharmony_ciout_delete: 21162306a36Sopenharmony_ci nsinfo__put(nsi); 21262306a36Sopenharmony_ci RC_CHK_FREE(result); 21362306a36Sopenharmony_ci return NULL; 21462306a36Sopenharmony_ci} 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci/* 21762306a36Sopenharmony_ci * Constructor variant for modules (where we know from /proc/modules where 21862306a36Sopenharmony_ci * they are loaded) and for vmlinux, where only after we load all the 21962306a36Sopenharmony_ci * symbols we'll know where it starts and ends. 22062306a36Sopenharmony_ci */ 22162306a36Sopenharmony_cistruct map *map__new2(u64 start, struct dso *dso) 22262306a36Sopenharmony_ci{ 22362306a36Sopenharmony_ci struct map *result; 22462306a36Sopenharmony_ci RC_STRUCT(map) *map; 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci map = calloc(1, sizeof(*map) + (dso->kernel ? sizeof(struct kmap) : 0)); 22762306a36Sopenharmony_ci if (ADD_RC_CHK(result, map)) { 22862306a36Sopenharmony_ci /* 22962306a36Sopenharmony_ci * ->end will be filled after we load all the symbols 23062306a36Sopenharmony_ci */ 23162306a36Sopenharmony_ci map__init(result, start, 0, 0, dso); 23262306a36Sopenharmony_ci } 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci return result; 23562306a36Sopenharmony_ci} 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_cibool __map__is_kernel(const struct map *map) 23862306a36Sopenharmony_ci{ 23962306a36Sopenharmony_ci if (!map__dso(map)->kernel) 24062306a36Sopenharmony_ci return false; 24162306a36Sopenharmony_ci return machine__kernel_map(maps__machine(map__kmaps((struct map *)map))) == map; 24262306a36Sopenharmony_ci} 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_cibool __map__is_extra_kernel_map(const struct map *map) 24562306a36Sopenharmony_ci{ 24662306a36Sopenharmony_ci struct kmap *kmap = __map__kmap((struct map *)map); 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci return kmap && kmap->name[0]; 24962306a36Sopenharmony_ci} 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_cibool __map__is_bpf_prog(const struct map *map) 25262306a36Sopenharmony_ci{ 25362306a36Sopenharmony_ci const char *name; 25462306a36Sopenharmony_ci struct dso *dso = map__dso(map); 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci if (dso->binary_type == DSO_BINARY_TYPE__BPF_PROG_INFO) 25762306a36Sopenharmony_ci return true; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci /* 26062306a36Sopenharmony_ci * If PERF_RECORD_BPF_EVENT is not included, the dso will not have 26162306a36Sopenharmony_ci * type of DSO_BINARY_TYPE__BPF_PROG_INFO. In such cases, we can 26262306a36Sopenharmony_ci * guess the type based on name. 26362306a36Sopenharmony_ci */ 26462306a36Sopenharmony_ci name = dso->short_name; 26562306a36Sopenharmony_ci return name && (strstr(name, "bpf_prog_") == name); 26662306a36Sopenharmony_ci} 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_cibool __map__is_bpf_image(const struct map *map) 26962306a36Sopenharmony_ci{ 27062306a36Sopenharmony_ci const char *name; 27162306a36Sopenharmony_ci struct dso *dso = map__dso(map); 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci if (dso->binary_type == DSO_BINARY_TYPE__BPF_IMAGE) 27462306a36Sopenharmony_ci return true; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci /* 27762306a36Sopenharmony_ci * If PERF_RECORD_KSYMBOL is not included, the dso will not have 27862306a36Sopenharmony_ci * type of DSO_BINARY_TYPE__BPF_IMAGE. In such cases, we can 27962306a36Sopenharmony_ci * guess the type based on name. 28062306a36Sopenharmony_ci */ 28162306a36Sopenharmony_ci name = dso->short_name; 28262306a36Sopenharmony_ci return name && is_bpf_image(name); 28362306a36Sopenharmony_ci} 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_cibool __map__is_ool(const struct map *map) 28662306a36Sopenharmony_ci{ 28762306a36Sopenharmony_ci const struct dso *dso = map__dso(map); 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci return dso && dso->binary_type == DSO_BINARY_TYPE__OOL; 29062306a36Sopenharmony_ci} 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_cibool map__has_symbols(const struct map *map) 29362306a36Sopenharmony_ci{ 29462306a36Sopenharmony_ci return dso__has_symbols(map__dso(map)); 29562306a36Sopenharmony_ci} 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_cistatic void map__exit(struct map *map) 29862306a36Sopenharmony_ci{ 29962306a36Sopenharmony_ci BUG_ON(refcount_read(map__refcnt(map)) != 0); 30062306a36Sopenharmony_ci dso__zput(RC_CHK_ACCESS(map)->dso); 30162306a36Sopenharmony_ci} 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_civoid map__delete(struct map *map) 30462306a36Sopenharmony_ci{ 30562306a36Sopenharmony_ci map__exit(map); 30662306a36Sopenharmony_ci RC_CHK_FREE(map); 30762306a36Sopenharmony_ci} 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_civoid map__put(struct map *map) 31062306a36Sopenharmony_ci{ 31162306a36Sopenharmony_ci if (map && refcount_dec_and_test(map__refcnt(map))) 31262306a36Sopenharmony_ci map__delete(map); 31362306a36Sopenharmony_ci else 31462306a36Sopenharmony_ci RC_CHK_PUT(map); 31562306a36Sopenharmony_ci} 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_civoid map__fixup_start(struct map *map) 31862306a36Sopenharmony_ci{ 31962306a36Sopenharmony_ci struct dso *dso = map__dso(map); 32062306a36Sopenharmony_ci struct rb_root_cached *symbols = &dso->symbols; 32162306a36Sopenharmony_ci struct rb_node *nd = rb_first_cached(symbols); 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci if (nd != NULL) { 32462306a36Sopenharmony_ci struct symbol *sym = rb_entry(nd, struct symbol, rb_node); 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci map__set_start(map, sym->start); 32762306a36Sopenharmony_ci } 32862306a36Sopenharmony_ci} 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_civoid map__fixup_end(struct map *map) 33162306a36Sopenharmony_ci{ 33262306a36Sopenharmony_ci struct dso *dso = map__dso(map); 33362306a36Sopenharmony_ci struct rb_root_cached *symbols = &dso->symbols; 33462306a36Sopenharmony_ci struct rb_node *nd = rb_last(&symbols->rb_root); 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci if (nd != NULL) { 33762306a36Sopenharmony_ci struct symbol *sym = rb_entry(nd, struct symbol, rb_node); 33862306a36Sopenharmony_ci map__set_end(map, sym->end); 33962306a36Sopenharmony_ci } 34062306a36Sopenharmony_ci} 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci#define DSO__DELETED "(deleted)" 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ciint map__load(struct map *map) 34562306a36Sopenharmony_ci{ 34662306a36Sopenharmony_ci struct dso *dso = map__dso(map); 34762306a36Sopenharmony_ci const char *name = dso->long_name; 34862306a36Sopenharmony_ci int nr; 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci if (dso__loaded(dso)) 35162306a36Sopenharmony_ci return 0; 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci nr = dso__load(dso, map); 35462306a36Sopenharmony_ci if (nr < 0) { 35562306a36Sopenharmony_ci if (dso->has_build_id) { 35662306a36Sopenharmony_ci char sbuild_id[SBUILD_ID_SIZE]; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci build_id__sprintf(&dso->bid, sbuild_id); 35962306a36Sopenharmony_ci pr_debug("%s with build id %s not found", name, sbuild_id); 36062306a36Sopenharmony_ci } else 36162306a36Sopenharmony_ci pr_debug("Failed to open %s", name); 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci pr_debug(", continuing without symbols\n"); 36462306a36Sopenharmony_ci return -1; 36562306a36Sopenharmony_ci } else if (nr == 0) { 36662306a36Sopenharmony_ci#ifdef HAVE_LIBELF_SUPPORT 36762306a36Sopenharmony_ci const size_t len = strlen(name); 36862306a36Sopenharmony_ci const size_t real_len = len - sizeof(DSO__DELETED); 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci if (len > sizeof(DSO__DELETED) && 37162306a36Sopenharmony_ci strcmp(name + real_len + 1, DSO__DELETED) == 0) { 37262306a36Sopenharmony_ci pr_debug("%.*s was updated (is prelink enabled?). " 37362306a36Sopenharmony_ci "Restart the long running apps that use it!\n", 37462306a36Sopenharmony_ci (int)real_len, name); 37562306a36Sopenharmony_ci } else { 37662306a36Sopenharmony_ci pr_debug("no symbols found in %s, maybe install a debug package?\n", name); 37762306a36Sopenharmony_ci } 37862306a36Sopenharmony_ci#endif 37962306a36Sopenharmony_ci return -1; 38062306a36Sopenharmony_ci } 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci return 0; 38362306a36Sopenharmony_ci} 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_cistruct symbol *map__find_symbol(struct map *map, u64 addr) 38662306a36Sopenharmony_ci{ 38762306a36Sopenharmony_ci if (map__load(map) < 0) 38862306a36Sopenharmony_ci return NULL; 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci return dso__find_symbol(map__dso(map), addr); 39162306a36Sopenharmony_ci} 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_cistruct symbol *map__find_symbol_by_name_idx(struct map *map, const char *name, size_t *idx) 39462306a36Sopenharmony_ci{ 39562306a36Sopenharmony_ci struct dso *dso; 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci if (map__load(map) < 0) 39862306a36Sopenharmony_ci return NULL; 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci dso = map__dso(map); 40162306a36Sopenharmony_ci dso__sort_by_name(dso); 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci return dso__find_symbol_by_name(dso, name, idx); 40462306a36Sopenharmony_ci} 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_cistruct symbol *map__find_symbol_by_name(struct map *map, const char *name) 40762306a36Sopenharmony_ci{ 40862306a36Sopenharmony_ci size_t idx; 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci return map__find_symbol_by_name_idx(map, name, &idx); 41162306a36Sopenharmony_ci} 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_cistruct map *map__clone(struct map *from) 41462306a36Sopenharmony_ci{ 41562306a36Sopenharmony_ci struct map *result; 41662306a36Sopenharmony_ci RC_STRUCT(map) *map; 41762306a36Sopenharmony_ci size_t size = sizeof(RC_STRUCT(map)); 41862306a36Sopenharmony_ci struct dso *dso = map__dso(from); 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci if (dso && dso->kernel) 42162306a36Sopenharmony_ci size += sizeof(struct kmap); 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci map = memdup(RC_CHK_ACCESS(from), size); 42462306a36Sopenharmony_ci if (ADD_RC_CHK(result, map)) { 42562306a36Sopenharmony_ci refcount_set(&map->refcnt, 1); 42662306a36Sopenharmony_ci map->dso = dso__get(dso); 42762306a36Sopenharmony_ci } 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci return result; 43062306a36Sopenharmony_ci} 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_cisize_t map__fprintf(struct map *map, FILE *fp) 43362306a36Sopenharmony_ci{ 43462306a36Sopenharmony_ci const struct dso *dso = map__dso(map); 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %" PRIx64 " %s\n", 43762306a36Sopenharmony_ci map__start(map), map__end(map), map__pgoff(map), dso->name); 43862306a36Sopenharmony_ci} 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_cistatic bool prefer_dso_long_name(const struct dso *dso, bool print_off) 44162306a36Sopenharmony_ci{ 44262306a36Sopenharmony_ci return dso->long_name && 44362306a36Sopenharmony_ci (symbol_conf.show_kernel_path || 44462306a36Sopenharmony_ci (print_off && (dso->name[0] == '[' || dso__is_kcore(dso)))); 44562306a36Sopenharmony_ci} 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_cistatic size_t __map__fprintf_dsoname(struct map *map, bool print_off, FILE *fp) 44862306a36Sopenharmony_ci{ 44962306a36Sopenharmony_ci char buf[symbol_conf.pad_output_len_dso + 1]; 45062306a36Sopenharmony_ci const char *dsoname = "[unknown]"; 45162306a36Sopenharmony_ci const struct dso *dso = map ? map__dso(map) : NULL; 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci if (dso) { 45462306a36Sopenharmony_ci if (prefer_dso_long_name(dso, print_off)) 45562306a36Sopenharmony_ci dsoname = dso->long_name; 45662306a36Sopenharmony_ci else 45762306a36Sopenharmony_ci dsoname = dso->name; 45862306a36Sopenharmony_ci } 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci if (symbol_conf.pad_output_len_dso) { 46162306a36Sopenharmony_ci scnprintf_pad(buf, symbol_conf.pad_output_len_dso, "%s", dsoname); 46262306a36Sopenharmony_ci dsoname = buf; 46362306a36Sopenharmony_ci } 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci return fprintf(fp, "%s", dsoname); 46662306a36Sopenharmony_ci} 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_cisize_t map__fprintf_dsoname(struct map *map, FILE *fp) 46962306a36Sopenharmony_ci{ 47062306a36Sopenharmony_ci return __map__fprintf_dsoname(map, false, fp); 47162306a36Sopenharmony_ci} 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_cisize_t map__fprintf_dsoname_dsoff(struct map *map, bool print_off, u64 addr, FILE *fp) 47462306a36Sopenharmony_ci{ 47562306a36Sopenharmony_ci const struct dso *dso = map ? map__dso(map) : NULL; 47662306a36Sopenharmony_ci int printed = 0; 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci if (print_off && (!dso || !dso__is_object_file(dso))) 47962306a36Sopenharmony_ci print_off = false; 48062306a36Sopenharmony_ci printed += fprintf(fp, " ("); 48162306a36Sopenharmony_ci printed += __map__fprintf_dsoname(map, print_off, fp); 48262306a36Sopenharmony_ci if (print_off) 48362306a36Sopenharmony_ci printed += fprintf(fp, "+0x%" PRIx64, addr); 48462306a36Sopenharmony_ci printed += fprintf(fp, ")"); 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci return printed; 48762306a36Sopenharmony_ci} 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_cichar *map__srcline(struct map *map, u64 addr, struct symbol *sym) 49062306a36Sopenharmony_ci{ 49162306a36Sopenharmony_ci if (map == NULL) 49262306a36Sopenharmony_ci return SRCLINE_UNKNOWN; 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci return get_srcline(map__dso(map), map__rip_2objdump(map, addr), sym, true, true, addr); 49562306a36Sopenharmony_ci} 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ciint map__fprintf_srcline(struct map *map, u64 addr, const char *prefix, 49862306a36Sopenharmony_ci FILE *fp) 49962306a36Sopenharmony_ci{ 50062306a36Sopenharmony_ci const struct dso *dso = map ? map__dso(map) : NULL; 50162306a36Sopenharmony_ci int ret = 0; 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci if (dso) { 50462306a36Sopenharmony_ci char *srcline = map__srcline(map, addr, NULL); 50562306a36Sopenharmony_ci if (srcline != SRCLINE_UNKNOWN) 50662306a36Sopenharmony_ci ret = fprintf(fp, "%s%s", prefix, srcline); 50762306a36Sopenharmony_ci zfree_srcline(&srcline); 50862306a36Sopenharmony_ci } 50962306a36Sopenharmony_ci return ret; 51062306a36Sopenharmony_ci} 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_civoid srccode_state_free(struct srccode_state *state) 51362306a36Sopenharmony_ci{ 51462306a36Sopenharmony_ci zfree(&state->srcfile); 51562306a36Sopenharmony_ci state->line = 0; 51662306a36Sopenharmony_ci} 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci/** 51962306a36Sopenharmony_ci * map__rip_2objdump - convert symbol start address to objdump address. 52062306a36Sopenharmony_ci * @map: memory map 52162306a36Sopenharmony_ci * @rip: symbol start address 52262306a36Sopenharmony_ci * 52362306a36Sopenharmony_ci * objdump wants/reports absolute IPs for ET_EXEC, and RIPs for ET_DYN. 52462306a36Sopenharmony_ci * map->dso->adjust_symbols==1 for ET_EXEC-like cases except ET_REL which is 52562306a36Sopenharmony_ci * relative to section start. 52662306a36Sopenharmony_ci * 52762306a36Sopenharmony_ci * Return: Address suitable for passing to "objdump --start-address=" 52862306a36Sopenharmony_ci */ 52962306a36Sopenharmony_ciu64 map__rip_2objdump(struct map *map, u64 rip) 53062306a36Sopenharmony_ci{ 53162306a36Sopenharmony_ci struct kmap *kmap = __map__kmap(map); 53262306a36Sopenharmony_ci const struct dso *dso = map__dso(map); 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci /* 53562306a36Sopenharmony_ci * vmlinux does not have program headers for PTI entry trampolines and 53662306a36Sopenharmony_ci * kcore may not either. However the trampoline object code is on the 53762306a36Sopenharmony_ci * main kernel map, so just use that instead. 53862306a36Sopenharmony_ci */ 53962306a36Sopenharmony_ci if (kmap && is_entry_trampoline(kmap->name) && kmap->kmaps) { 54062306a36Sopenharmony_ci struct machine *machine = maps__machine(kmap->kmaps); 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci if (machine) { 54362306a36Sopenharmony_ci struct map *kernel_map = machine__kernel_map(machine); 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci if (kernel_map) 54662306a36Sopenharmony_ci map = kernel_map; 54762306a36Sopenharmony_ci } 54862306a36Sopenharmony_ci } 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci if (!dso->adjust_symbols) 55162306a36Sopenharmony_ci return rip; 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci if (dso->rel) 55462306a36Sopenharmony_ci return rip - map__pgoff(map); 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci /* 55762306a36Sopenharmony_ci * kernel modules also have DSO_TYPE_USER in dso->kernel, 55862306a36Sopenharmony_ci * but all kernel modules are ET_REL, so won't get here. 55962306a36Sopenharmony_ci */ 56062306a36Sopenharmony_ci if (dso->kernel == DSO_SPACE__USER) 56162306a36Sopenharmony_ci return rip + dso->text_offset; 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci return map__unmap_ip(map, rip) - map__reloc(map); 56462306a36Sopenharmony_ci} 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci/** 56762306a36Sopenharmony_ci * map__objdump_2mem - convert objdump address to a memory address. 56862306a36Sopenharmony_ci * @map: memory map 56962306a36Sopenharmony_ci * @ip: objdump address 57062306a36Sopenharmony_ci * 57162306a36Sopenharmony_ci * Closely related to map__rip_2objdump(), this function takes an address from 57262306a36Sopenharmony_ci * objdump and converts it to a memory address. Note this assumes that @map 57362306a36Sopenharmony_ci * contains the address. To be sure the result is valid, check it forwards 57462306a36Sopenharmony_ci * e.g. map__rip_2objdump(map__map_ip(map, map__objdump_2mem(map, ip))) == ip 57562306a36Sopenharmony_ci * 57662306a36Sopenharmony_ci * Return: Memory address. 57762306a36Sopenharmony_ci */ 57862306a36Sopenharmony_ciu64 map__objdump_2mem(struct map *map, u64 ip) 57962306a36Sopenharmony_ci{ 58062306a36Sopenharmony_ci const struct dso *dso = map__dso(map); 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci if (!dso->adjust_symbols) 58362306a36Sopenharmony_ci return map__unmap_ip(map, ip); 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci if (dso->rel) 58662306a36Sopenharmony_ci return map__unmap_ip(map, ip + map__pgoff(map)); 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci /* 58962306a36Sopenharmony_ci * kernel modules also have DSO_TYPE_USER in dso->kernel, 59062306a36Sopenharmony_ci * but all kernel modules are ET_REL, so won't get here. 59162306a36Sopenharmony_ci */ 59262306a36Sopenharmony_ci if (dso->kernel == DSO_SPACE__USER) 59362306a36Sopenharmony_ci return map__unmap_ip(map, ip - dso->text_offset); 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci return ip + map__reloc(map); 59662306a36Sopenharmony_ci} 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_cibool map__contains_symbol(const struct map *map, const struct symbol *sym) 59962306a36Sopenharmony_ci{ 60062306a36Sopenharmony_ci u64 ip = map__unmap_ip(map, sym->start); 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci return ip >= map__start(map) && ip < map__end(map); 60362306a36Sopenharmony_ci} 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_cistruct kmap *__map__kmap(struct map *map) 60662306a36Sopenharmony_ci{ 60762306a36Sopenharmony_ci const struct dso *dso = map__dso(map); 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci if (!dso || !dso->kernel) 61062306a36Sopenharmony_ci return NULL; 61162306a36Sopenharmony_ci return (struct kmap *)(&RC_CHK_ACCESS(map)[1]); 61262306a36Sopenharmony_ci} 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_cistruct kmap *map__kmap(struct map *map) 61562306a36Sopenharmony_ci{ 61662306a36Sopenharmony_ci struct kmap *kmap = __map__kmap(map); 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci if (!kmap) 61962306a36Sopenharmony_ci pr_err("Internal error: map__kmap with a non-kernel map\n"); 62062306a36Sopenharmony_ci return kmap; 62162306a36Sopenharmony_ci} 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_cistruct maps *map__kmaps(struct map *map) 62462306a36Sopenharmony_ci{ 62562306a36Sopenharmony_ci struct kmap *kmap = map__kmap(map); 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci if (!kmap || !kmap->kmaps) { 62862306a36Sopenharmony_ci pr_err("Internal error: map__kmaps with a non-kernel map\n"); 62962306a36Sopenharmony_ci return NULL; 63062306a36Sopenharmony_ci } 63162306a36Sopenharmony_ci return kmap->kmaps; 63262306a36Sopenharmony_ci} 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ciu64 map__dso_map_ip(const struct map *map, u64 ip) 63562306a36Sopenharmony_ci{ 63662306a36Sopenharmony_ci return ip - map__start(map) + map__pgoff(map); 63762306a36Sopenharmony_ci} 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ciu64 map__dso_unmap_ip(const struct map *map, u64 ip) 64062306a36Sopenharmony_ci{ 64162306a36Sopenharmony_ci return ip + map__start(map) - map__pgoff(map); 64262306a36Sopenharmony_ci} 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ciu64 identity__map_ip(const struct map *map __maybe_unused, u64 ip) 64562306a36Sopenharmony_ci{ 64662306a36Sopenharmony_ci return ip; 64762306a36Sopenharmony_ci} 648