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