18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci#include <asm/bug.h>
38c2ecf20Sopenharmony_ci#include <linux/kernel.h>
48c2ecf20Sopenharmony_ci#include <linux/string.h>
58c2ecf20Sopenharmony_ci#include <linux/zalloc.h>
68c2ecf20Sopenharmony_ci#include <sys/time.h>
78c2ecf20Sopenharmony_ci#include <sys/resource.h>
88c2ecf20Sopenharmony_ci#include <sys/types.h>
98c2ecf20Sopenharmony_ci#include <sys/stat.h>
108c2ecf20Sopenharmony_ci#include <unistd.h>
118c2ecf20Sopenharmony_ci#include <errno.h>
128c2ecf20Sopenharmony_ci#include <fcntl.h>
138c2ecf20Sopenharmony_ci#include <stdlib.h>
148c2ecf20Sopenharmony_ci#include <bpf/libbpf.h>
158c2ecf20Sopenharmony_ci#include "bpf-event.h"
168c2ecf20Sopenharmony_ci#include "compress.h"
178c2ecf20Sopenharmony_ci#include "env.h"
188c2ecf20Sopenharmony_ci#include "namespaces.h"
198c2ecf20Sopenharmony_ci#include "path.h"
208c2ecf20Sopenharmony_ci#include "map.h"
218c2ecf20Sopenharmony_ci#include "symbol.h"
228c2ecf20Sopenharmony_ci#include "srcline.h"
238c2ecf20Sopenharmony_ci#include "dso.h"
248c2ecf20Sopenharmony_ci#include "dsos.h"
258c2ecf20Sopenharmony_ci#include "machine.h"
268c2ecf20Sopenharmony_ci#include "auxtrace.h"
278c2ecf20Sopenharmony_ci#include "util.h" /* O_CLOEXEC for older systems */
288c2ecf20Sopenharmony_ci#include "debug.h"
298c2ecf20Sopenharmony_ci#include "string2.h"
308c2ecf20Sopenharmony_ci#include "vdso.h"
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_cistatic const char * const debuglink_paths[] = {
338c2ecf20Sopenharmony_ci	"%.0s%s",
348c2ecf20Sopenharmony_ci	"%s/%s",
358c2ecf20Sopenharmony_ci	"%s/.debug/%s",
368c2ecf20Sopenharmony_ci	"/usr/lib/debug%s/%s"
378c2ecf20Sopenharmony_ci};
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_cichar dso__symtab_origin(const struct dso *dso)
408c2ecf20Sopenharmony_ci{
418c2ecf20Sopenharmony_ci	static const char origin[] = {
428c2ecf20Sopenharmony_ci		[DSO_BINARY_TYPE__KALLSYMS]			= 'k',
438c2ecf20Sopenharmony_ci		[DSO_BINARY_TYPE__VMLINUX]			= 'v',
448c2ecf20Sopenharmony_ci		[DSO_BINARY_TYPE__JAVA_JIT]			= 'j',
458c2ecf20Sopenharmony_ci		[DSO_BINARY_TYPE__DEBUGLINK]			= 'l',
468c2ecf20Sopenharmony_ci		[DSO_BINARY_TYPE__BUILD_ID_CACHE]		= 'B',
478c2ecf20Sopenharmony_ci		[DSO_BINARY_TYPE__BUILD_ID_CACHE_DEBUGINFO]	= 'D',
488c2ecf20Sopenharmony_ci		[DSO_BINARY_TYPE__FEDORA_DEBUGINFO]		= 'f',
498c2ecf20Sopenharmony_ci		[DSO_BINARY_TYPE__UBUNTU_DEBUGINFO]		= 'u',
508c2ecf20Sopenharmony_ci		[DSO_BINARY_TYPE__MIXEDUP_UBUNTU_DEBUGINFO]	= 'x',
518c2ecf20Sopenharmony_ci		[DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO]	= 'o',
528c2ecf20Sopenharmony_ci		[DSO_BINARY_TYPE__BUILDID_DEBUGINFO]		= 'b',
538c2ecf20Sopenharmony_ci		[DSO_BINARY_TYPE__SYSTEM_PATH_DSO]		= 'd',
548c2ecf20Sopenharmony_ci		[DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE]		= 'K',
558c2ecf20Sopenharmony_ci		[DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP]	= 'm',
568c2ecf20Sopenharmony_ci		[DSO_BINARY_TYPE__GUEST_KALLSYMS]		= 'g',
578c2ecf20Sopenharmony_ci		[DSO_BINARY_TYPE__GUEST_KMODULE]		= 'G',
588c2ecf20Sopenharmony_ci		[DSO_BINARY_TYPE__GUEST_KMODULE_COMP]		= 'M',
598c2ecf20Sopenharmony_ci		[DSO_BINARY_TYPE__GUEST_VMLINUX]		= 'V',
608c2ecf20Sopenharmony_ci	};
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci	if (dso == NULL || dso->symtab_type == DSO_BINARY_TYPE__NOT_FOUND)
638c2ecf20Sopenharmony_ci		return '!';
648c2ecf20Sopenharmony_ci	return origin[dso->symtab_type];
658c2ecf20Sopenharmony_ci}
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ciint dso__read_binary_type_filename(const struct dso *dso,
688c2ecf20Sopenharmony_ci				   enum dso_binary_type type,
698c2ecf20Sopenharmony_ci				   char *root_dir, char *filename, size_t size)
708c2ecf20Sopenharmony_ci{
718c2ecf20Sopenharmony_ci	char build_id_hex[SBUILD_ID_SIZE];
728c2ecf20Sopenharmony_ci	int ret = 0;
738c2ecf20Sopenharmony_ci	size_t len;
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci	switch (type) {
768c2ecf20Sopenharmony_ci	case DSO_BINARY_TYPE__DEBUGLINK:
778c2ecf20Sopenharmony_ci	{
788c2ecf20Sopenharmony_ci		const char *last_slash;
798c2ecf20Sopenharmony_ci		char dso_dir[PATH_MAX];
808c2ecf20Sopenharmony_ci		char symfile[PATH_MAX];
818c2ecf20Sopenharmony_ci		unsigned int i;
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci		len = __symbol__join_symfs(filename, size, dso->long_name);
848c2ecf20Sopenharmony_ci		last_slash = filename + len;
858c2ecf20Sopenharmony_ci		while (last_slash != filename && *last_slash != '/')
868c2ecf20Sopenharmony_ci			last_slash--;
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci		strncpy(dso_dir, filename, last_slash - filename);
898c2ecf20Sopenharmony_ci		dso_dir[last_slash-filename] = '\0';
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci		if (!is_regular_file(filename)) {
928c2ecf20Sopenharmony_ci			ret = -1;
938c2ecf20Sopenharmony_ci			break;
948c2ecf20Sopenharmony_ci		}
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci		ret = filename__read_debuglink(filename, symfile, PATH_MAX);
978c2ecf20Sopenharmony_ci		if (ret)
988c2ecf20Sopenharmony_ci			break;
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci		/* Check predefined locations where debug file might reside */
1018c2ecf20Sopenharmony_ci		ret = -1;
1028c2ecf20Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(debuglink_paths); i++) {
1038c2ecf20Sopenharmony_ci			snprintf(filename, size,
1048c2ecf20Sopenharmony_ci					debuglink_paths[i], dso_dir, symfile);
1058c2ecf20Sopenharmony_ci			if (is_regular_file(filename)) {
1068c2ecf20Sopenharmony_ci				ret = 0;
1078c2ecf20Sopenharmony_ci				break;
1088c2ecf20Sopenharmony_ci			}
1098c2ecf20Sopenharmony_ci		}
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci		break;
1128c2ecf20Sopenharmony_ci	}
1138c2ecf20Sopenharmony_ci	case DSO_BINARY_TYPE__BUILD_ID_CACHE:
1148c2ecf20Sopenharmony_ci		if (dso__build_id_filename(dso, filename, size, false) == NULL)
1158c2ecf20Sopenharmony_ci			ret = -1;
1168c2ecf20Sopenharmony_ci		break;
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	case DSO_BINARY_TYPE__BUILD_ID_CACHE_DEBUGINFO:
1198c2ecf20Sopenharmony_ci		if (dso__build_id_filename(dso, filename, size, true) == NULL)
1208c2ecf20Sopenharmony_ci			ret = -1;
1218c2ecf20Sopenharmony_ci		break;
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	case DSO_BINARY_TYPE__FEDORA_DEBUGINFO:
1248c2ecf20Sopenharmony_ci		len = __symbol__join_symfs(filename, size, "/usr/lib/debug");
1258c2ecf20Sopenharmony_ci		snprintf(filename + len, size - len, "%s.debug", dso->long_name);
1268c2ecf20Sopenharmony_ci		break;
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	case DSO_BINARY_TYPE__UBUNTU_DEBUGINFO:
1298c2ecf20Sopenharmony_ci		len = __symbol__join_symfs(filename, size, "/usr/lib/debug");
1308c2ecf20Sopenharmony_ci		snprintf(filename + len, size - len, "%s", dso->long_name);
1318c2ecf20Sopenharmony_ci		break;
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	case DSO_BINARY_TYPE__MIXEDUP_UBUNTU_DEBUGINFO:
1348c2ecf20Sopenharmony_ci		/*
1358c2ecf20Sopenharmony_ci		 * Ubuntu can mixup /usr/lib with /lib, putting debuginfo in
1368c2ecf20Sopenharmony_ci		 * /usr/lib/debug/lib when it is expected to be in
1378c2ecf20Sopenharmony_ci		 * /usr/lib/debug/usr/lib
1388c2ecf20Sopenharmony_ci		 */
1398c2ecf20Sopenharmony_ci		if (strlen(dso->long_name) < 9 ||
1408c2ecf20Sopenharmony_ci		    strncmp(dso->long_name, "/usr/lib/", 9)) {
1418c2ecf20Sopenharmony_ci			ret = -1;
1428c2ecf20Sopenharmony_ci			break;
1438c2ecf20Sopenharmony_ci		}
1448c2ecf20Sopenharmony_ci		len = __symbol__join_symfs(filename, size, "/usr/lib/debug");
1458c2ecf20Sopenharmony_ci		snprintf(filename + len, size - len, "%s", dso->long_name + 4);
1468c2ecf20Sopenharmony_ci		break;
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	case DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO:
1498c2ecf20Sopenharmony_ci	{
1508c2ecf20Sopenharmony_ci		const char *last_slash;
1518c2ecf20Sopenharmony_ci		size_t dir_size;
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci		last_slash = dso->long_name + dso->long_name_len;
1548c2ecf20Sopenharmony_ci		while (last_slash != dso->long_name && *last_slash != '/')
1558c2ecf20Sopenharmony_ci			last_slash--;
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci		len = __symbol__join_symfs(filename, size, "");
1588c2ecf20Sopenharmony_ci		dir_size = last_slash - dso->long_name + 2;
1598c2ecf20Sopenharmony_ci		if (dir_size > (size - len)) {
1608c2ecf20Sopenharmony_ci			ret = -1;
1618c2ecf20Sopenharmony_ci			break;
1628c2ecf20Sopenharmony_ci		}
1638c2ecf20Sopenharmony_ci		len += scnprintf(filename + len, dir_size, "%s",  dso->long_name);
1648c2ecf20Sopenharmony_ci		len += scnprintf(filename + len , size - len, ".debug%s",
1658c2ecf20Sopenharmony_ci								last_slash);
1668c2ecf20Sopenharmony_ci		break;
1678c2ecf20Sopenharmony_ci	}
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	case DSO_BINARY_TYPE__BUILDID_DEBUGINFO:
1708c2ecf20Sopenharmony_ci		if (!dso->has_build_id) {
1718c2ecf20Sopenharmony_ci			ret = -1;
1728c2ecf20Sopenharmony_ci			break;
1738c2ecf20Sopenharmony_ci		}
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci		build_id__sprintf(&dso->bid, build_id_hex);
1768c2ecf20Sopenharmony_ci		len = __symbol__join_symfs(filename, size, "/usr/lib/debug/.build-id/");
1778c2ecf20Sopenharmony_ci		snprintf(filename + len, size - len, "%.2s/%s.debug",
1788c2ecf20Sopenharmony_ci			 build_id_hex, build_id_hex + 2);
1798c2ecf20Sopenharmony_ci		break;
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	case DSO_BINARY_TYPE__VMLINUX:
1828c2ecf20Sopenharmony_ci	case DSO_BINARY_TYPE__GUEST_VMLINUX:
1838c2ecf20Sopenharmony_ci	case DSO_BINARY_TYPE__SYSTEM_PATH_DSO:
1848c2ecf20Sopenharmony_ci		__symbol__join_symfs(filename, size, dso->long_name);
1858c2ecf20Sopenharmony_ci		break;
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci	case DSO_BINARY_TYPE__GUEST_KMODULE:
1888c2ecf20Sopenharmony_ci	case DSO_BINARY_TYPE__GUEST_KMODULE_COMP:
1898c2ecf20Sopenharmony_ci		path__join3(filename, size, symbol_conf.symfs,
1908c2ecf20Sopenharmony_ci			    root_dir, dso->long_name);
1918c2ecf20Sopenharmony_ci		break;
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE:
1948c2ecf20Sopenharmony_ci	case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP:
1958c2ecf20Sopenharmony_ci		__symbol__join_symfs(filename, size, dso->long_name);
1968c2ecf20Sopenharmony_ci		break;
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci	case DSO_BINARY_TYPE__KCORE:
1998c2ecf20Sopenharmony_ci	case DSO_BINARY_TYPE__GUEST_KCORE:
2008c2ecf20Sopenharmony_ci		snprintf(filename, size, "%s", dso->long_name);
2018c2ecf20Sopenharmony_ci		break;
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	default:
2048c2ecf20Sopenharmony_ci	case DSO_BINARY_TYPE__KALLSYMS:
2058c2ecf20Sopenharmony_ci	case DSO_BINARY_TYPE__GUEST_KALLSYMS:
2068c2ecf20Sopenharmony_ci	case DSO_BINARY_TYPE__JAVA_JIT:
2078c2ecf20Sopenharmony_ci	case DSO_BINARY_TYPE__BPF_PROG_INFO:
2088c2ecf20Sopenharmony_ci	case DSO_BINARY_TYPE__BPF_IMAGE:
2098c2ecf20Sopenharmony_ci	case DSO_BINARY_TYPE__OOL:
2108c2ecf20Sopenharmony_ci	case DSO_BINARY_TYPE__NOT_FOUND:
2118c2ecf20Sopenharmony_ci		ret = -1;
2128c2ecf20Sopenharmony_ci		break;
2138c2ecf20Sopenharmony_ci	}
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci	return ret;
2168c2ecf20Sopenharmony_ci}
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_cienum {
2198c2ecf20Sopenharmony_ci	COMP_ID__NONE = 0,
2208c2ecf20Sopenharmony_ci};
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_cistatic const struct {
2238c2ecf20Sopenharmony_ci	const char *fmt;
2248c2ecf20Sopenharmony_ci	int (*decompress)(const char *input, int output);
2258c2ecf20Sopenharmony_ci	bool (*is_compressed)(const char *input);
2268c2ecf20Sopenharmony_ci} compressions[] = {
2278c2ecf20Sopenharmony_ci	[COMP_ID__NONE] = { .fmt = NULL, },
2288c2ecf20Sopenharmony_ci#ifdef HAVE_ZLIB_SUPPORT
2298c2ecf20Sopenharmony_ci	{ "gz", gzip_decompress_to_file, gzip_is_compressed },
2308c2ecf20Sopenharmony_ci#endif
2318c2ecf20Sopenharmony_ci#ifdef HAVE_LZMA_SUPPORT
2328c2ecf20Sopenharmony_ci	{ "xz", lzma_decompress_to_file, lzma_is_compressed },
2338c2ecf20Sopenharmony_ci#endif
2348c2ecf20Sopenharmony_ci	{ NULL, NULL, NULL },
2358c2ecf20Sopenharmony_ci};
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_cistatic int is_supported_compression(const char *ext)
2388c2ecf20Sopenharmony_ci{
2398c2ecf20Sopenharmony_ci	unsigned i;
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	for (i = 1; compressions[i].fmt; i++) {
2428c2ecf20Sopenharmony_ci		if (!strcmp(ext, compressions[i].fmt))
2438c2ecf20Sopenharmony_ci			return i;
2448c2ecf20Sopenharmony_ci	}
2458c2ecf20Sopenharmony_ci	return COMP_ID__NONE;
2468c2ecf20Sopenharmony_ci}
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_cibool is_kernel_module(const char *pathname, int cpumode)
2498c2ecf20Sopenharmony_ci{
2508c2ecf20Sopenharmony_ci	struct kmod_path m;
2518c2ecf20Sopenharmony_ci	int mode = cpumode & PERF_RECORD_MISC_CPUMODE_MASK;
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	WARN_ONCE(mode != cpumode,
2548c2ecf20Sopenharmony_ci		  "Internal error: passing unmasked cpumode (%x) to is_kernel_module",
2558c2ecf20Sopenharmony_ci		  cpumode);
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	switch (mode) {
2588c2ecf20Sopenharmony_ci	case PERF_RECORD_MISC_USER:
2598c2ecf20Sopenharmony_ci	case PERF_RECORD_MISC_HYPERVISOR:
2608c2ecf20Sopenharmony_ci	case PERF_RECORD_MISC_GUEST_USER:
2618c2ecf20Sopenharmony_ci		return false;
2628c2ecf20Sopenharmony_ci	/* Treat PERF_RECORD_MISC_CPUMODE_UNKNOWN as kernel */
2638c2ecf20Sopenharmony_ci	default:
2648c2ecf20Sopenharmony_ci		if (kmod_path__parse(&m, pathname)) {
2658c2ecf20Sopenharmony_ci			pr_err("Failed to check whether %s is a kernel module or not. Assume it is.",
2668c2ecf20Sopenharmony_ci					pathname);
2678c2ecf20Sopenharmony_ci			return true;
2688c2ecf20Sopenharmony_ci		}
2698c2ecf20Sopenharmony_ci	}
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci	return m.kmod;
2728c2ecf20Sopenharmony_ci}
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_cibool dso__needs_decompress(struct dso *dso)
2758c2ecf20Sopenharmony_ci{
2768c2ecf20Sopenharmony_ci	return dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP ||
2778c2ecf20Sopenharmony_ci		dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE_COMP;
2788c2ecf20Sopenharmony_ci}
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_cistatic int decompress_kmodule(struct dso *dso, const char *name,
2818c2ecf20Sopenharmony_ci			      char *pathname, size_t len)
2828c2ecf20Sopenharmony_ci{
2838c2ecf20Sopenharmony_ci	char tmpbuf[] = KMOD_DECOMP_NAME;
2848c2ecf20Sopenharmony_ci	int fd = -1;
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci	if (!dso__needs_decompress(dso))
2878c2ecf20Sopenharmony_ci		return -1;
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci	if (dso->comp == COMP_ID__NONE)
2908c2ecf20Sopenharmony_ci		return -1;
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci	/*
2938c2ecf20Sopenharmony_ci	 * We have proper compression id for DSO and yet the file
2948c2ecf20Sopenharmony_ci	 * behind the 'name' can still be plain uncompressed object.
2958c2ecf20Sopenharmony_ci	 *
2968c2ecf20Sopenharmony_ci	 * The reason is behind the logic we open the DSO object files,
2978c2ecf20Sopenharmony_ci	 * when we try all possible 'debug' objects until we find the
2988c2ecf20Sopenharmony_ci	 * data. So even if the DSO is represented by 'krava.xz' module,
2998c2ecf20Sopenharmony_ci	 * we can end up here opening ~/.debug/....23432432/debug' file
3008c2ecf20Sopenharmony_ci	 * which is not compressed.
3018c2ecf20Sopenharmony_ci	 *
3028c2ecf20Sopenharmony_ci	 * To keep this transparent, we detect this and return the file
3038c2ecf20Sopenharmony_ci	 * descriptor to the uncompressed file.
3048c2ecf20Sopenharmony_ci	 */
3058c2ecf20Sopenharmony_ci	if (!compressions[dso->comp].is_compressed(name))
3068c2ecf20Sopenharmony_ci		return open(name, O_RDONLY);
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci	fd = mkstemp(tmpbuf);
3098c2ecf20Sopenharmony_ci	if (fd < 0) {
3108c2ecf20Sopenharmony_ci		dso->load_errno = errno;
3118c2ecf20Sopenharmony_ci		return -1;
3128c2ecf20Sopenharmony_ci	}
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	if (compressions[dso->comp].decompress(name, fd)) {
3158c2ecf20Sopenharmony_ci		dso->load_errno = DSO_LOAD_ERRNO__DECOMPRESSION_FAILURE;
3168c2ecf20Sopenharmony_ci		close(fd);
3178c2ecf20Sopenharmony_ci		fd = -1;
3188c2ecf20Sopenharmony_ci	}
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci	if (!pathname || (fd < 0))
3218c2ecf20Sopenharmony_ci		unlink(tmpbuf);
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci	if (pathname && (fd >= 0))
3248c2ecf20Sopenharmony_ci		strlcpy(pathname, tmpbuf, len);
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	return fd;
3278c2ecf20Sopenharmony_ci}
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ciint dso__decompress_kmodule_fd(struct dso *dso, const char *name)
3308c2ecf20Sopenharmony_ci{
3318c2ecf20Sopenharmony_ci	return decompress_kmodule(dso, name, NULL, 0);
3328c2ecf20Sopenharmony_ci}
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ciint dso__decompress_kmodule_path(struct dso *dso, const char *name,
3358c2ecf20Sopenharmony_ci				 char *pathname, size_t len)
3368c2ecf20Sopenharmony_ci{
3378c2ecf20Sopenharmony_ci	int fd = decompress_kmodule(dso, name, pathname, len);
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	close(fd);
3408c2ecf20Sopenharmony_ci	return fd >= 0 ? 0 : -1;
3418c2ecf20Sopenharmony_ci}
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci/*
3448c2ecf20Sopenharmony_ci * Parses kernel module specified in @path and updates
3458c2ecf20Sopenharmony_ci * @m argument like:
3468c2ecf20Sopenharmony_ci *
3478c2ecf20Sopenharmony_ci *    @comp - true if @path contains supported compression suffix,
3488c2ecf20Sopenharmony_ci *            false otherwise
3498c2ecf20Sopenharmony_ci *    @kmod - true if @path contains '.ko' suffix in right position,
3508c2ecf20Sopenharmony_ci *            false otherwise
3518c2ecf20Sopenharmony_ci *    @name - if (@alloc_name && @kmod) is true, it contains strdup-ed base name
3528c2ecf20Sopenharmony_ci *            of the kernel module without suffixes, otherwise strudup-ed
3538c2ecf20Sopenharmony_ci *            base name of @path
3548c2ecf20Sopenharmony_ci *    @ext  - if (@alloc_ext && @comp) is true, it contains strdup-ed string
3558c2ecf20Sopenharmony_ci *            the compression suffix
3568c2ecf20Sopenharmony_ci *
3578c2ecf20Sopenharmony_ci * Returns 0 if there's no strdup error, -ENOMEM otherwise.
3588c2ecf20Sopenharmony_ci */
3598c2ecf20Sopenharmony_ciint __kmod_path__parse(struct kmod_path *m, const char *path,
3608c2ecf20Sopenharmony_ci		       bool alloc_name)
3618c2ecf20Sopenharmony_ci{
3628c2ecf20Sopenharmony_ci	const char *name = strrchr(path, '/');
3638c2ecf20Sopenharmony_ci	const char *ext  = strrchr(path, '.');
3648c2ecf20Sopenharmony_ci	bool is_simple_name = false;
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci	memset(m, 0x0, sizeof(*m));
3678c2ecf20Sopenharmony_ci	name = name ? name + 1 : path;
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci	/*
3708c2ecf20Sopenharmony_ci	 * '.' is also a valid character for module name. For example:
3718c2ecf20Sopenharmony_ci	 * [aaa.bbb] is a valid module name. '[' should have higher
3728c2ecf20Sopenharmony_ci	 * priority than '.ko' suffix.
3738c2ecf20Sopenharmony_ci	 *
3748c2ecf20Sopenharmony_ci	 * The kernel names are from machine__mmap_name. Such
3758c2ecf20Sopenharmony_ci	 * name should belong to kernel itself, not kernel module.
3768c2ecf20Sopenharmony_ci	 */
3778c2ecf20Sopenharmony_ci	if (name[0] == '[') {
3788c2ecf20Sopenharmony_ci		is_simple_name = true;
3798c2ecf20Sopenharmony_ci		if ((strncmp(name, "[kernel.kallsyms]", 17) == 0) ||
3808c2ecf20Sopenharmony_ci		    (strncmp(name, "[guest.kernel.kallsyms", 22) == 0) ||
3818c2ecf20Sopenharmony_ci		    (strncmp(name, "[vdso]", 6) == 0) ||
3828c2ecf20Sopenharmony_ci		    (strncmp(name, "[vdso32]", 8) == 0) ||
3838c2ecf20Sopenharmony_ci		    (strncmp(name, "[vdsox32]", 9) == 0) ||
3848c2ecf20Sopenharmony_ci		    (strncmp(name, "[vsyscall]", 10) == 0)) {
3858c2ecf20Sopenharmony_ci			m->kmod = false;
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci		} else
3888c2ecf20Sopenharmony_ci			m->kmod = true;
3898c2ecf20Sopenharmony_ci	}
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci	/* No extension, just return name. */
3928c2ecf20Sopenharmony_ci	if ((ext == NULL) || is_simple_name) {
3938c2ecf20Sopenharmony_ci		if (alloc_name) {
3948c2ecf20Sopenharmony_ci			m->name = strdup(name);
3958c2ecf20Sopenharmony_ci			return m->name ? 0 : -ENOMEM;
3968c2ecf20Sopenharmony_ci		}
3978c2ecf20Sopenharmony_ci		return 0;
3988c2ecf20Sopenharmony_ci	}
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_ci	m->comp = is_supported_compression(ext + 1);
4018c2ecf20Sopenharmony_ci	if (m->comp > COMP_ID__NONE)
4028c2ecf20Sopenharmony_ci		ext -= 3;
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_ci	/* Check .ko extension only if there's enough name left. */
4058c2ecf20Sopenharmony_ci	if (ext > name)
4068c2ecf20Sopenharmony_ci		m->kmod = !strncmp(ext, ".ko", 3);
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci	if (alloc_name) {
4098c2ecf20Sopenharmony_ci		if (m->kmod) {
4108c2ecf20Sopenharmony_ci			if (asprintf(&m->name, "[%.*s]", (int) (ext - name), name) == -1)
4118c2ecf20Sopenharmony_ci				return -ENOMEM;
4128c2ecf20Sopenharmony_ci		} else {
4138c2ecf20Sopenharmony_ci			if (asprintf(&m->name, "%s", name) == -1)
4148c2ecf20Sopenharmony_ci				return -ENOMEM;
4158c2ecf20Sopenharmony_ci		}
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ci		strreplace(m->name, '-', '_');
4188c2ecf20Sopenharmony_ci	}
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_ci	return 0;
4218c2ecf20Sopenharmony_ci}
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_civoid dso__set_module_info(struct dso *dso, struct kmod_path *m,
4248c2ecf20Sopenharmony_ci			  struct machine *machine)
4258c2ecf20Sopenharmony_ci{
4268c2ecf20Sopenharmony_ci	if (machine__is_host(machine))
4278c2ecf20Sopenharmony_ci		dso->symtab_type = DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE;
4288c2ecf20Sopenharmony_ci	else
4298c2ecf20Sopenharmony_ci		dso->symtab_type = DSO_BINARY_TYPE__GUEST_KMODULE;
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci	/* _KMODULE_COMP should be next to _KMODULE */
4328c2ecf20Sopenharmony_ci	if (m->kmod && m->comp) {
4338c2ecf20Sopenharmony_ci		dso->symtab_type++;
4348c2ecf20Sopenharmony_ci		dso->comp = m->comp;
4358c2ecf20Sopenharmony_ci	}
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci	dso__set_short_name(dso, strdup(m->name), true);
4388c2ecf20Sopenharmony_ci}
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ci/*
4418c2ecf20Sopenharmony_ci * Global list of open DSOs and the counter.
4428c2ecf20Sopenharmony_ci */
4438c2ecf20Sopenharmony_cistatic LIST_HEAD(dso__data_open);
4448c2ecf20Sopenharmony_cistatic long dso__data_open_cnt;
4458c2ecf20Sopenharmony_cistatic pthread_mutex_t dso__data_open_lock = PTHREAD_MUTEX_INITIALIZER;
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_cistatic void dso__list_add(struct dso *dso)
4488c2ecf20Sopenharmony_ci{
4498c2ecf20Sopenharmony_ci	list_add_tail(&dso->data.open_entry, &dso__data_open);
4508c2ecf20Sopenharmony_ci	dso__data_open_cnt++;
4518c2ecf20Sopenharmony_ci}
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_cistatic void dso__list_del(struct dso *dso)
4548c2ecf20Sopenharmony_ci{
4558c2ecf20Sopenharmony_ci	list_del_init(&dso->data.open_entry);
4568c2ecf20Sopenharmony_ci	WARN_ONCE(dso__data_open_cnt <= 0,
4578c2ecf20Sopenharmony_ci		  "DSO data fd counter out of bounds.");
4588c2ecf20Sopenharmony_ci	dso__data_open_cnt--;
4598c2ecf20Sopenharmony_ci}
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_cistatic void close_first_dso(void);
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_cistatic int do_open(char *name)
4648c2ecf20Sopenharmony_ci{
4658c2ecf20Sopenharmony_ci	int fd;
4668c2ecf20Sopenharmony_ci	char sbuf[STRERR_BUFSIZE];
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci	do {
4698c2ecf20Sopenharmony_ci		fd = open(name, O_RDONLY|O_CLOEXEC);
4708c2ecf20Sopenharmony_ci		if (fd >= 0)
4718c2ecf20Sopenharmony_ci			return fd;
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_ci		pr_debug("dso open failed: %s\n",
4748c2ecf20Sopenharmony_ci			 str_error_r(errno, sbuf, sizeof(sbuf)));
4758c2ecf20Sopenharmony_ci		if (!dso__data_open_cnt || errno != EMFILE)
4768c2ecf20Sopenharmony_ci			break;
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_ci		close_first_dso();
4798c2ecf20Sopenharmony_ci	} while (1);
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_ci	return -1;
4828c2ecf20Sopenharmony_ci}
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_cistatic int __open_dso(struct dso *dso, struct machine *machine)
4858c2ecf20Sopenharmony_ci{
4868c2ecf20Sopenharmony_ci	int fd = -EINVAL;
4878c2ecf20Sopenharmony_ci	char *root_dir = (char *)"";
4888c2ecf20Sopenharmony_ci	char *name = malloc(PATH_MAX);
4898c2ecf20Sopenharmony_ci	bool decomp = false;
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_ci	if (!name)
4928c2ecf20Sopenharmony_ci		return -ENOMEM;
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_ci	if (machine)
4958c2ecf20Sopenharmony_ci		root_dir = machine->root_dir;
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_ci	if (dso__read_binary_type_filename(dso, dso->binary_type,
4988c2ecf20Sopenharmony_ci					    root_dir, name, PATH_MAX))
4998c2ecf20Sopenharmony_ci		goto out;
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_ci	if (!is_regular_file(name))
5028c2ecf20Sopenharmony_ci		goto out;
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_ci	if (dso__needs_decompress(dso)) {
5058c2ecf20Sopenharmony_ci		char newpath[KMOD_DECOMP_LEN];
5068c2ecf20Sopenharmony_ci		size_t len = sizeof(newpath);
5078c2ecf20Sopenharmony_ci
5088c2ecf20Sopenharmony_ci		if (dso__decompress_kmodule_path(dso, name, newpath, len) < 0) {
5098c2ecf20Sopenharmony_ci			fd = -dso->load_errno;
5108c2ecf20Sopenharmony_ci			goto out;
5118c2ecf20Sopenharmony_ci		}
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_ci		decomp = true;
5148c2ecf20Sopenharmony_ci		strcpy(name, newpath);
5158c2ecf20Sopenharmony_ci	}
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci	fd = do_open(name);
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_ci	if (decomp)
5208c2ecf20Sopenharmony_ci		unlink(name);
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_ciout:
5238c2ecf20Sopenharmony_ci	free(name);
5248c2ecf20Sopenharmony_ci	return fd;
5258c2ecf20Sopenharmony_ci}
5268c2ecf20Sopenharmony_ci
5278c2ecf20Sopenharmony_cistatic void check_data_close(void);
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_ci/**
5308c2ecf20Sopenharmony_ci * dso_close - Open DSO data file
5318c2ecf20Sopenharmony_ci * @dso: dso object
5328c2ecf20Sopenharmony_ci *
5338c2ecf20Sopenharmony_ci * Open @dso's data file descriptor and updates
5348c2ecf20Sopenharmony_ci * list/count of open DSO objects.
5358c2ecf20Sopenharmony_ci */
5368c2ecf20Sopenharmony_cistatic int open_dso(struct dso *dso, struct machine *machine)
5378c2ecf20Sopenharmony_ci{
5388c2ecf20Sopenharmony_ci	int fd;
5398c2ecf20Sopenharmony_ci	struct nscookie nsc;
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_ci	if (dso->binary_type != DSO_BINARY_TYPE__BUILD_ID_CACHE)
5428c2ecf20Sopenharmony_ci		nsinfo__mountns_enter(dso->nsinfo, &nsc);
5438c2ecf20Sopenharmony_ci	fd = __open_dso(dso, machine);
5448c2ecf20Sopenharmony_ci	if (dso->binary_type != DSO_BINARY_TYPE__BUILD_ID_CACHE)
5458c2ecf20Sopenharmony_ci		nsinfo__mountns_exit(&nsc);
5468c2ecf20Sopenharmony_ci
5478c2ecf20Sopenharmony_ci	if (fd >= 0) {
5488c2ecf20Sopenharmony_ci		dso__list_add(dso);
5498c2ecf20Sopenharmony_ci		/*
5508c2ecf20Sopenharmony_ci		 * Check if we crossed the allowed number
5518c2ecf20Sopenharmony_ci		 * of opened DSOs and close one if needed.
5528c2ecf20Sopenharmony_ci		 */
5538c2ecf20Sopenharmony_ci		check_data_close();
5548c2ecf20Sopenharmony_ci	}
5558c2ecf20Sopenharmony_ci
5568c2ecf20Sopenharmony_ci	return fd;
5578c2ecf20Sopenharmony_ci}
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_cistatic void close_data_fd(struct dso *dso)
5608c2ecf20Sopenharmony_ci{
5618c2ecf20Sopenharmony_ci	if (dso->data.fd >= 0) {
5628c2ecf20Sopenharmony_ci		close(dso->data.fd);
5638c2ecf20Sopenharmony_ci		dso->data.fd = -1;
5648c2ecf20Sopenharmony_ci		dso->data.file_size = 0;
5658c2ecf20Sopenharmony_ci		dso__list_del(dso);
5668c2ecf20Sopenharmony_ci	}
5678c2ecf20Sopenharmony_ci}
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_ci/**
5708c2ecf20Sopenharmony_ci * dso_close - Close DSO data file
5718c2ecf20Sopenharmony_ci * @dso: dso object
5728c2ecf20Sopenharmony_ci *
5738c2ecf20Sopenharmony_ci * Close @dso's data file descriptor and updates
5748c2ecf20Sopenharmony_ci * list/count of open DSO objects.
5758c2ecf20Sopenharmony_ci */
5768c2ecf20Sopenharmony_cistatic void close_dso(struct dso *dso)
5778c2ecf20Sopenharmony_ci{
5788c2ecf20Sopenharmony_ci	close_data_fd(dso);
5798c2ecf20Sopenharmony_ci}
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_cistatic void close_first_dso(void)
5828c2ecf20Sopenharmony_ci{
5838c2ecf20Sopenharmony_ci	struct dso *dso;
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_ci	dso = list_first_entry(&dso__data_open, struct dso, data.open_entry);
5868c2ecf20Sopenharmony_ci	close_dso(dso);
5878c2ecf20Sopenharmony_ci}
5888c2ecf20Sopenharmony_ci
5898c2ecf20Sopenharmony_cistatic rlim_t get_fd_limit(void)
5908c2ecf20Sopenharmony_ci{
5918c2ecf20Sopenharmony_ci	struct rlimit l;
5928c2ecf20Sopenharmony_ci	rlim_t limit = 0;
5938c2ecf20Sopenharmony_ci
5948c2ecf20Sopenharmony_ci	/* Allow half of the current open fd limit. */
5958c2ecf20Sopenharmony_ci	if (getrlimit(RLIMIT_NOFILE, &l) == 0) {
5968c2ecf20Sopenharmony_ci		if (l.rlim_cur == RLIM_INFINITY)
5978c2ecf20Sopenharmony_ci			limit = l.rlim_cur;
5988c2ecf20Sopenharmony_ci		else
5998c2ecf20Sopenharmony_ci			limit = l.rlim_cur / 2;
6008c2ecf20Sopenharmony_ci	} else {
6018c2ecf20Sopenharmony_ci		pr_err("failed to get fd limit\n");
6028c2ecf20Sopenharmony_ci		limit = 1;
6038c2ecf20Sopenharmony_ci	}
6048c2ecf20Sopenharmony_ci
6058c2ecf20Sopenharmony_ci	return limit;
6068c2ecf20Sopenharmony_ci}
6078c2ecf20Sopenharmony_ci
6088c2ecf20Sopenharmony_cistatic rlim_t fd_limit;
6098c2ecf20Sopenharmony_ci
6108c2ecf20Sopenharmony_ci/*
6118c2ecf20Sopenharmony_ci * Used only by tests/dso-data.c to reset the environment
6128c2ecf20Sopenharmony_ci * for tests. I dont expect we should change this during
6138c2ecf20Sopenharmony_ci * standard runtime.
6148c2ecf20Sopenharmony_ci */
6158c2ecf20Sopenharmony_civoid reset_fd_limit(void)
6168c2ecf20Sopenharmony_ci{
6178c2ecf20Sopenharmony_ci	fd_limit = 0;
6188c2ecf20Sopenharmony_ci}
6198c2ecf20Sopenharmony_ci
6208c2ecf20Sopenharmony_cistatic bool may_cache_fd(void)
6218c2ecf20Sopenharmony_ci{
6228c2ecf20Sopenharmony_ci	if (!fd_limit)
6238c2ecf20Sopenharmony_ci		fd_limit = get_fd_limit();
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_ci	if (fd_limit == RLIM_INFINITY)
6268c2ecf20Sopenharmony_ci		return true;
6278c2ecf20Sopenharmony_ci
6288c2ecf20Sopenharmony_ci	return fd_limit > (rlim_t) dso__data_open_cnt;
6298c2ecf20Sopenharmony_ci}
6308c2ecf20Sopenharmony_ci
6318c2ecf20Sopenharmony_ci/*
6328c2ecf20Sopenharmony_ci * Check and close LRU dso if we crossed allowed limit
6338c2ecf20Sopenharmony_ci * for opened dso file descriptors. The limit is half
6348c2ecf20Sopenharmony_ci * of the RLIMIT_NOFILE files opened.
6358c2ecf20Sopenharmony_ci*/
6368c2ecf20Sopenharmony_cistatic void check_data_close(void)
6378c2ecf20Sopenharmony_ci{
6388c2ecf20Sopenharmony_ci	bool cache_fd = may_cache_fd();
6398c2ecf20Sopenharmony_ci
6408c2ecf20Sopenharmony_ci	if (!cache_fd)
6418c2ecf20Sopenharmony_ci		close_first_dso();
6428c2ecf20Sopenharmony_ci}
6438c2ecf20Sopenharmony_ci
6448c2ecf20Sopenharmony_ci/**
6458c2ecf20Sopenharmony_ci * dso__data_close - Close DSO data file
6468c2ecf20Sopenharmony_ci * @dso: dso object
6478c2ecf20Sopenharmony_ci *
6488c2ecf20Sopenharmony_ci * External interface to close @dso's data file descriptor.
6498c2ecf20Sopenharmony_ci */
6508c2ecf20Sopenharmony_civoid dso__data_close(struct dso *dso)
6518c2ecf20Sopenharmony_ci{
6528c2ecf20Sopenharmony_ci	pthread_mutex_lock(&dso__data_open_lock);
6538c2ecf20Sopenharmony_ci	close_dso(dso);
6548c2ecf20Sopenharmony_ci	pthread_mutex_unlock(&dso__data_open_lock);
6558c2ecf20Sopenharmony_ci}
6568c2ecf20Sopenharmony_ci
6578c2ecf20Sopenharmony_cistatic void try_to_open_dso(struct dso *dso, struct machine *machine)
6588c2ecf20Sopenharmony_ci{
6598c2ecf20Sopenharmony_ci	enum dso_binary_type binary_type_data[] = {
6608c2ecf20Sopenharmony_ci		DSO_BINARY_TYPE__BUILD_ID_CACHE,
6618c2ecf20Sopenharmony_ci		DSO_BINARY_TYPE__SYSTEM_PATH_DSO,
6628c2ecf20Sopenharmony_ci		DSO_BINARY_TYPE__NOT_FOUND,
6638c2ecf20Sopenharmony_ci	};
6648c2ecf20Sopenharmony_ci	int i = 0;
6658c2ecf20Sopenharmony_ci
6668c2ecf20Sopenharmony_ci	if (dso->data.fd >= 0)
6678c2ecf20Sopenharmony_ci		return;
6688c2ecf20Sopenharmony_ci
6698c2ecf20Sopenharmony_ci	if (dso->binary_type != DSO_BINARY_TYPE__NOT_FOUND) {
6708c2ecf20Sopenharmony_ci		dso->data.fd = open_dso(dso, machine);
6718c2ecf20Sopenharmony_ci		goto out;
6728c2ecf20Sopenharmony_ci	}
6738c2ecf20Sopenharmony_ci
6748c2ecf20Sopenharmony_ci	do {
6758c2ecf20Sopenharmony_ci		dso->binary_type = binary_type_data[i++];
6768c2ecf20Sopenharmony_ci
6778c2ecf20Sopenharmony_ci		dso->data.fd = open_dso(dso, machine);
6788c2ecf20Sopenharmony_ci		if (dso->data.fd >= 0)
6798c2ecf20Sopenharmony_ci			goto out;
6808c2ecf20Sopenharmony_ci
6818c2ecf20Sopenharmony_ci	} while (dso->binary_type != DSO_BINARY_TYPE__NOT_FOUND);
6828c2ecf20Sopenharmony_ciout:
6838c2ecf20Sopenharmony_ci	if (dso->data.fd >= 0)
6848c2ecf20Sopenharmony_ci		dso->data.status = DSO_DATA_STATUS_OK;
6858c2ecf20Sopenharmony_ci	else
6868c2ecf20Sopenharmony_ci		dso->data.status = DSO_DATA_STATUS_ERROR;
6878c2ecf20Sopenharmony_ci}
6888c2ecf20Sopenharmony_ci
6898c2ecf20Sopenharmony_ci/**
6908c2ecf20Sopenharmony_ci * dso__data_get_fd - Get dso's data file descriptor
6918c2ecf20Sopenharmony_ci * @dso: dso object
6928c2ecf20Sopenharmony_ci * @machine: machine object
6938c2ecf20Sopenharmony_ci *
6948c2ecf20Sopenharmony_ci * External interface to find dso's file, open it and
6958c2ecf20Sopenharmony_ci * returns file descriptor.  It should be paired with
6968c2ecf20Sopenharmony_ci * dso__data_put_fd() if it returns non-negative value.
6978c2ecf20Sopenharmony_ci */
6988c2ecf20Sopenharmony_ciint dso__data_get_fd(struct dso *dso, struct machine *machine)
6998c2ecf20Sopenharmony_ci{
7008c2ecf20Sopenharmony_ci	if (dso->data.status == DSO_DATA_STATUS_ERROR)
7018c2ecf20Sopenharmony_ci		return -1;
7028c2ecf20Sopenharmony_ci
7038c2ecf20Sopenharmony_ci	if (pthread_mutex_lock(&dso__data_open_lock) < 0)
7048c2ecf20Sopenharmony_ci		return -1;
7058c2ecf20Sopenharmony_ci
7068c2ecf20Sopenharmony_ci	try_to_open_dso(dso, machine);
7078c2ecf20Sopenharmony_ci
7088c2ecf20Sopenharmony_ci	if (dso->data.fd < 0)
7098c2ecf20Sopenharmony_ci		pthread_mutex_unlock(&dso__data_open_lock);
7108c2ecf20Sopenharmony_ci
7118c2ecf20Sopenharmony_ci	return dso->data.fd;
7128c2ecf20Sopenharmony_ci}
7138c2ecf20Sopenharmony_ci
7148c2ecf20Sopenharmony_civoid dso__data_put_fd(struct dso *dso __maybe_unused)
7158c2ecf20Sopenharmony_ci{
7168c2ecf20Sopenharmony_ci	pthread_mutex_unlock(&dso__data_open_lock);
7178c2ecf20Sopenharmony_ci}
7188c2ecf20Sopenharmony_ci
7198c2ecf20Sopenharmony_cibool dso__data_status_seen(struct dso *dso, enum dso_data_status_seen by)
7208c2ecf20Sopenharmony_ci{
7218c2ecf20Sopenharmony_ci	u32 flag = 1 << by;
7228c2ecf20Sopenharmony_ci
7238c2ecf20Sopenharmony_ci	if (dso->data.status_seen & flag)
7248c2ecf20Sopenharmony_ci		return true;
7258c2ecf20Sopenharmony_ci
7268c2ecf20Sopenharmony_ci	dso->data.status_seen |= flag;
7278c2ecf20Sopenharmony_ci
7288c2ecf20Sopenharmony_ci	return false;
7298c2ecf20Sopenharmony_ci}
7308c2ecf20Sopenharmony_ci
7318c2ecf20Sopenharmony_cistatic ssize_t bpf_read(struct dso *dso, u64 offset, char *data)
7328c2ecf20Sopenharmony_ci{
7338c2ecf20Sopenharmony_ci	struct bpf_prog_info_node *node;
7348c2ecf20Sopenharmony_ci	ssize_t size = DSO__DATA_CACHE_SIZE;
7358c2ecf20Sopenharmony_ci	u64 len;
7368c2ecf20Sopenharmony_ci	u8 *buf;
7378c2ecf20Sopenharmony_ci
7388c2ecf20Sopenharmony_ci	node = perf_env__find_bpf_prog_info(dso->bpf_prog.env, dso->bpf_prog.id);
7398c2ecf20Sopenharmony_ci	if (!node || !node->info_linear) {
7408c2ecf20Sopenharmony_ci		dso->data.status = DSO_DATA_STATUS_ERROR;
7418c2ecf20Sopenharmony_ci		return -1;
7428c2ecf20Sopenharmony_ci	}
7438c2ecf20Sopenharmony_ci
7448c2ecf20Sopenharmony_ci	len = node->info_linear->info.jited_prog_len;
7458c2ecf20Sopenharmony_ci	buf = (u8 *)(uintptr_t)node->info_linear->info.jited_prog_insns;
7468c2ecf20Sopenharmony_ci
7478c2ecf20Sopenharmony_ci	if (offset >= len)
7488c2ecf20Sopenharmony_ci		return -1;
7498c2ecf20Sopenharmony_ci
7508c2ecf20Sopenharmony_ci	size = (ssize_t)min(len - offset, (u64)size);
7518c2ecf20Sopenharmony_ci	memcpy(data, buf + offset, size);
7528c2ecf20Sopenharmony_ci	return size;
7538c2ecf20Sopenharmony_ci}
7548c2ecf20Sopenharmony_ci
7558c2ecf20Sopenharmony_cistatic int bpf_size(struct dso *dso)
7568c2ecf20Sopenharmony_ci{
7578c2ecf20Sopenharmony_ci	struct bpf_prog_info_node *node;
7588c2ecf20Sopenharmony_ci
7598c2ecf20Sopenharmony_ci	node = perf_env__find_bpf_prog_info(dso->bpf_prog.env, dso->bpf_prog.id);
7608c2ecf20Sopenharmony_ci	if (!node || !node->info_linear) {
7618c2ecf20Sopenharmony_ci		dso->data.status = DSO_DATA_STATUS_ERROR;
7628c2ecf20Sopenharmony_ci		return -1;
7638c2ecf20Sopenharmony_ci	}
7648c2ecf20Sopenharmony_ci
7658c2ecf20Sopenharmony_ci	dso->data.file_size = node->info_linear->info.jited_prog_len;
7668c2ecf20Sopenharmony_ci	return 0;
7678c2ecf20Sopenharmony_ci}
7688c2ecf20Sopenharmony_ci
7698c2ecf20Sopenharmony_cistatic void
7708c2ecf20Sopenharmony_cidso_cache__free(struct dso *dso)
7718c2ecf20Sopenharmony_ci{
7728c2ecf20Sopenharmony_ci	struct rb_root *root = &dso->data.cache;
7738c2ecf20Sopenharmony_ci	struct rb_node *next = rb_first(root);
7748c2ecf20Sopenharmony_ci
7758c2ecf20Sopenharmony_ci	pthread_mutex_lock(&dso->lock);
7768c2ecf20Sopenharmony_ci	while (next) {
7778c2ecf20Sopenharmony_ci		struct dso_cache *cache;
7788c2ecf20Sopenharmony_ci
7798c2ecf20Sopenharmony_ci		cache = rb_entry(next, struct dso_cache, rb_node);
7808c2ecf20Sopenharmony_ci		next = rb_next(&cache->rb_node);
7818c2ecf20Sopenharmony_ci		rb_erase(&cache->rb_node, root);
7828c2ecf20Sopenharmony_ci		free(cache);
7838c2ecf20Sopenharmony_ci	}
7848c2ecf20Sopenharmony_ci	pthread_mutex_unlock(&dso->lock);
7858c2ecf20Sopenharmony_ci}
7868c2ecf20Sopenharmony_ci
7878c2ecf20Sopenharmony_cistatic struct dso_cache *__dso_cache__find(struct dso *dso, u64 offset)
7888c2ecf20Sopenharmony_ci{
7898c2ecf20Sopenharmony_ci	const struct rb_root *root = &dso->data.cache;
7908c2ecf20Sopenharmony_ci	struct rb_node * const *p = &root->rb_node;
7918c2ecf20Sopenharmony_ci	const struct rb_node *parent = NULL;
7928c2ecf20Sopenharmony_ci	struct dso_cache *cache;
7938c2ecf20Sopenharmony_ci
7948c2ecf20Sopenharmony_ci	while (*p != NULL) {
7958c2ecf20Sopenharmony_ci		u64 end;
7968c2ecf20Sopenharmony_ci
7978c2ecf20Sopenharmony_ci		parent = *p;
7988c2ecf20Sopenharmony_ci		cache = rb_entry(parent, struct dso_cache, rb_node);
7998c2ecf20Sopenharmony_ci		end = cache->offset + DSO__DATA_CACHE_SIZE;
8008c2ecf20Sopenharmony_ci
8018c2ecf20Sopenharmony_ci		if (offset < cache->offset)
8028c2ecf20Sopenharmony_ci			p = &(*p)->rb_left;
8038c2ecf20Sopenharmony_ci		else if (offset >= end)
8048c2ecf20Sopenharmony_ci			p = &(*p)->rb_right;
8058c2ecf20Sopenharmony_ci		else
8068c2ecf20Sopenharmony_ci			return cache;
8078c2ecf20Sopenharmony_ci	}
8088c2ecf20Sopenharmony_ci
8098c2ecf20Sopenharmony_ci	return NULL;
8108c2ecf20Sopenharmony_ci}
8118c2ecf20Sopenharmony_ci
8128c2ecf20Sopenharmony_cistatic struct dso_cache *
8138c2ecf20Sopenharmony_cidso_cache__insert(struct dso *dso, struct dso_cache *new)
8148c2ecf20Sopenharmony_ci{
8158c2ecf20Sopenharmony_ci	struct rb_root *root = &dso->data.cache;
8168c2ecf20Sopenharmony_ci	struct rb_node **p = &root->rb_node;
8178c2ecf20Sopenharmony_ci	struct rb_node *parent = NULL;
8188c2ecf20Sopenharmony_ci	struct dso_cache *cache;
8198c2ecf20Sopenharmony_ci	u64 offset = new->offset;
8208c2ecf20Sopenharmony_ci
8218c2ecf20Sopenharmony_ci	pthread_mutex_lock(&dso->lock);
8228c2ecf20Sopenharmony_ci	while (*p != NULL) {
8238c2ecf20Sopenharmony_ci		u64 end;
8248c2ecf20Sopenharmony_ci
8258c2ecf20Sopenharmony_ci		parent = *p;
8268c2ecf20Sopenharmony_ci		cache = rb_entry(parent, struct dso_cache, rb_node);
8278c2ecf20Sopenharmony_ci		end = cache->offset + DSO__DATA_CACHE_SIZE;
8288c2ecf20Sopenharmony_ci
8298c2ecf20Sopenharmony_ci		if (offset < cache->offset)
8308c2ecf20Sopenharmony_ci			p = &(*p)->rb_left;
8318c2ecf20Sopenharmony_ci		else if (offset >= end)
8328c2ecf20Sopenharmony_ci			p = &(*p)->rb_right;
8338c2ecf20Sopenharmony_ci		else
8348c2ecf20Sopenharmony_ci			goto out;
8358c2ecf20Sopenharmony_ci	}
8368c2ecf20Sopenharmony_ci
8378c2ecf20Sopenharmony_ci	rb_link_node(&new->rb_node, parent, p);
8388c2ecf20Sopenharmony_ci	rb_insert_color(&new->rb_node, root);
8398c2ecf20Sopenharmony_ci
8408c2ecf20Sopenharmony_ci	cache = NULL;
8418c2ecf20Sopenharmony_ciout:
8428c2ecf20Sopenharmony_ci	pthread_mutex_unlock(&dso->lock);
8438c2ecf20Sopenharmony_ci	return cache;
8448c2ecf20Sopenharmony_ci}
8458c2ecf20Sopenharmony_ci
8468c2ecf20Sopenharmony_cistatic ssize_t dso_cache__memcpy(struct dso_cache *cache, u64 offset, u8 *data,
8478c2ecf20Sopenharmony_ci				 u64 size, bool out)
8488c2ecf20Sopenharmony_ci{
8498c2ecf20Sopenharmony_ci	u64 cache_offset = offset - cache->offset;
8508c2ecf20Sopenharmony_ci	u64 cache_size   = min(cache->size - cache_offset, size);
8518c2ecf20Sopenharmony_ci
8528c2ecf20Sopenharmony_ci	if (out)
8538c2ecf20Sopenharmony_ci		memcpy(data, cache->data + cache_offset, cache_size);
8548c2ecf20Sopenharmony_ci	else
8558c2ecf20Sopenharmony_ci		memcpy(cache->data + cache_offset, data, cache_size);
8568c2ecf20Sopenharmony_ci	return cache_size;
8578c2ecf20Sopenharmony_ci}
8588c2ecf20Sopenharmony_ci
8598c2ecf20Sopenharmony_cistatic ssize_t file_read(struct dso *dso, struct machine *machine,
8608c2ecf20Sopenharmony_ci			 u64 offset, char *data)
8618c2ecf20Sopenharmony_ci{
8628c2ecf20Sopenharmony_ci	ssize_t ret;
8638c2ecf20Sopenharmony_ci
8648c2ecf20Sopenharmony_ci	pthread_mutex_lock(&dso__data_open_lock);
8658c2ecf20Sopenharmony_ci
8668c2ecf20Sopenharmony_ci	/*
8678c2ecf20Sopenharmony_ci	 * dso->data.fd might be closed if other thread opened another
8688c2ecf20Sopenharmony_ci	 * file (dso) due to open file limit (RLIMIT_NOFILE).
8698c2ecf20Sopenharmony_ci	 */
8708c2ecf20Sopenharmony_ci	try_to_open_dso(dso, machine);
8718c2ecf20Sopenharmony_ci
8728c2ecf20Sopenharmony_ci	if (dso->data.fd < 0) {
8738c2ecf20Sopenharmony_ci		dso->data.status = DSO_DATA_STATUS_ERROR;
8748c2ecf20Sopenharmony_ci		ret = -errno;
8758c2ecf20Sopenharmony_ci		goto out;
8768c2ecf20Sopenharmony_ci	}
8778c2ecf20Sopenharmony_ci
8788c2ecf20Sopenharmony_ci	ret = pread(dso->data.fd, data, DSO__DATA_CACHE_SIZE, offset);
8798c2ecf20Sopenharmony_ciout:
8808c2ecf20Sopenharmony_ci	pthread_mutex_unlock(&dso__data_open_lock);
8818c2ecf20Sopenharmony_ci	return ret;
8828c2ecf20Sopenharmony_ci}
8838c2ecf20Sopenharmony_ci
8848c2ecf20Sopenharmony_cistatic struct dso_cache *dso_cache__populate(struct dso *dso,
8858c2ecf20Sopenharmony_ci					     struct machine *machine,
8868c2ecf20Sopenharmony_ci					     u64 offset, ssize_t *ret)
8878c2ecf20Sopenharmony_ci{
8888c2ecf20Sopenharmony_ci	u64 cache_offset = offset & DSO__DATA_CACHE_MASK;
8898c2ecf20Sopenharmony_ci	struct dso_cache *cache;
8908c2ecf20Sopenharmony_ci	struct dso_cache *old;
8918c2ecf20Sopenharmony_ci
8928c2ecf20Sopenharmony_ci	cache = zalloc(sizeof(*cache) + DSO__DATA_CACHE_SIZE);
8938c2ecf20Sopenharmony_ci	if (!cache) {
8948c2ecf20Sopenharmony_ci		*ret = -ENOMEM;
8958c2ecf20Sopenharmony_ci		return NULL;
8968c2ecf20Sopenharmony_ci	}
8978c2ecf20Sopenharmony_ci
8988c2ecf20Sopenharmony_ci	if (dso->binary_type == DSO_BINARY_TYPE__BPF_PROG_INFO)
8998c2ecf20Sopenharmony_ci		*ret = bpf_read(dso, cache_offset, cache->data);
9008c2ecf20Sopenharmony_ci	else if (dso->binary_type == DSO_BINARY_TYPE__OOL)
9018c2ecf20Sopenharmony_ci		*ret = DSO__DATA_CACHE_SIZE;
9028c2ecf20Sopenharmony_ci	else
9038c2ecf20Sopenharmony_ci		*ret = file_read(dso, machine, cache_offset, cache->data);
9048c2ecf20Sopenharmony_ci
9058c2ecf20Sopenharmony_ci	if (*ret <= 0) {
9068c2ecf20Sopenharmony_ci		free(cache);
9078c2ecf20Sopenharmony_ci		return NULL;
9088c2ecf20Sopenharmony_ci	}
9098c2ecf20Sopenharmony_ci
9108c2ecf20Sopenharmony_ci	cache->offset = cache_offset;
9118c2ecf20Sopenharmony_ci	cache->size   = *ret;
9128c2ecf20Sopenharmony_ci
9138c2ecf20Sopenharmony_ci	old = dso_cache__insert(dso, cache);
9148c2ecf20Sopenharmony_ci	if (old) {
9158c2ecf20Sopenharmony_ci		/* we lose the race */
9168c2ecf20Sopenharmony_ci		free(cache);
9178c2ecf20Sopenharmony_ci		cache = old;
9188c2ecf20Sopenharmony_ci	}
9198c2ecf20Sopenharmony_ci
9208c2ecf20Sopenharmony_ci	return cache;
9218c2ecf20Sopenharmony_ci}
9228c2ecf20Sopenharmony_ci
9238c2ecf20Sopenharmony_cistatic struct dso_cache *dso_cache__find(struct dso *dso,
9248c2ecf20Sopenharmony_ci					 struct machine *machine,
9258c2ecf20Sopenharmony_ci					 u64 offset,
9268c2ecf20Sopenharmony_ci					 ssize_t *ret)
9278c2ecf20Sopenharmony_ci{
9288c2ecf20Sopenharmony_ci	struct dso_cache *cache = __dso_cache__find(dso, offset);
9298c2ecf20Sopenharmony_ci
9308c2ecf20Sopenharmony_ci	return cache ? cache : dso_cache__populate(dso, machine, offset, ret);
9318c2ecf20Sopenharmony_ci}
9328c2ecf20Sopenharmony_ci
9338c2ecf20Sopenharmony_cistatic ssize_t dso_cache_io(struct dso *dso, struct machine *machine,
9348c2ecf20Sopenharmony_ci			    u64 offset, u8 *data, ssize_t size, bool out)
9358c2ecf20Sopenharmony_ci{
9368c2ecf20Sopenharmony_ci	struct dso_cache *cache;
9378c2ecf20Sopenharmony_ci	ssize_t ret = 0;
9388c2ecf20Sopenharmony_ci
9398c2ecf20Sopenharmony_ci	cache = dso_cache__find(dso, machine, offset, &ret);
9408c2ecf20Sopenharmony_ci	if (!cache)
9418c2ecf20Sopenharmony_ci		return ret;
9428c2ecf20Sopenharmony_ci
9438c2ecf20Sopenharmony_ci	return dso_cache__memcpy(cache, offset, data, size, out);
9448c2ecf20Sopenharmony_ci}
9458c2ecf20Sopenharmony_ci
9468c2ecf20Sopenharmony_ci/*
9478c2ecf20Sopenharmony_ci * Reads and caches dso data DSO__DATA_CACHE_SIZE size chunks
9488c2ecf20Sopenharmony_ci * in the rb_tree. Any read to already cached data is served
9498c2ecf20Sopenharmony_ci * by cached data. Writes update the cache only, not the backing file.
9508c2ecf20Sopenharmony_ci */
9518c2ecf20Sopenharmony_cistatic ssize_t cached_io(struct dso *dso, struct machine *machine,
9528c2ecf20Sopenharmony_ci			 u64 offset, u8 *data, ssize_t size, bool out)
9538c2ecf20Sopenharmony_ci{
9548c2ecf20Sopenharmony_ci	ssize_t r = 0;
9558c2ecf20Sopenharmony_ci	u8 *p = data;
9568c2ecf20Sopenharmony_ci
9578c2ecf20Sopenharmony_ci	do {
9588c2ecf20Sopenharmony_ci		ssize_t ret;
9598c2ecf20Sopenharmony_ci
9608c2ecf20Sopenharmony_ci		ret = dso_cache_io(dso, machine, offset, p, size, out);
9618c2ecf20Sopenharmony_ci		if (ret < 0)
9628c2ecf20Sopenharmony_ci			return ret;
9638c2ecf20Sopenharmony_ci
9648c2ecf20Sopenharmony_ci		/* Reached EOF, return what we have. */
9658c2ecf20Sopenharmony_ci		if (!ret)
9668c2ecf20Sopenharmony_ci			break;
9678c2ecf20Sopenharmony_ci
9688c2ecf20Sopenharmony_ci		BUG_ON(ret > size);
9698c2ecf20Sopenharmony_ci
9708c2ecf20Sopenharmony_ci		r      += ret;
9718c2ecf20Sopenharmony_ci		p      += ret;
9728c2ecf20Sopenharmony_ci		offset += ret;
9738c2ecf20Sopenharmony_ci		size   -= ret;
9748c2ecf20Sopenharmony_ci
9758c2ecf20Sopenharmony_ci	} while (size);
9768c2ecf20Sopenharmony_ci
9778c2ecf20Sopenharmony_ci	return r;
9788c2ecf20Sopenharmony_ci}
9798c2ecf20Sopenharmony_ci
9808c2ecf20Sopenharmony_cistatic int file_size(struct dso *dso, struct machine *machine)
9818c2ecf20Sopenharmony_ci{
9828c2ecf20Sopenharmony_ci	int ret = 0;
9838c2ecf20Sopenharmony_ci	struct stat st;
9848c2ecf20Sopenharmony_ci	char sbuf[STRERR_BUFSIZE];
9858c2ecf20Sopenharmony_ci
9868c2ecf20Sopenharmony_ci	pthread_mutex_lock(&dso__data_open_lock);
9878c2ecf20Sopenharmony_ci
9888c2ecf20Sopenharmony_ci	/*
9898c2ecf20Sopenharmony_ci	 * dso->data.fd might be closed if other thread opened another
9908c2ecf20Sopenharmony_ci	 * file (dso) due to open file limit (RLIMIT_NOFILE).
9918c2ecf20Sopenharmony_ci	 */
9928c2ecf20Sopenharmony_ci	try_to_open_dso(dso, machine);
9938c2ecf20Sopenharmony_ci
9948c2ecf20Sopenharmony_ci	if (dso->data.fd < 0) {
9958c2ecf20Sopenharmony_ci		ret = -errno;
9968c2ecf20Sopenharmony_ci		dso->data.status = DSO_DATA_STATUS_ERROR;
9978c2ecf20Sopenharmony_ci		goto out;
9988c2ecf20Sopenharmony_ci	}
9998c2ecf20Sopenharmony_ci
10008c2ecf20Sopenharmony_ci	if (fstat(dso->data.fd, &st) < 0) {
10018c2ecf20Sopenharmony_ci		ret = -errno;
10028c2ecf20Sopenharmony_ci		pr_err("dso cache fstat failed: %s\n",
10038c2ecf20Sopenharmony_ci		       str_error_r(errno, sbuf, sizeof(sbuf)));
10048c2ecf20Sopenharmony_ci		dso->data.status = DSO_DATA_STATUS_ERROR;
10058c2ecf20Sopenharmony_ci		goto out;
10068c2ecf20Sopenharmony_ci	}
10078c2ecf20Sopenharmony_ci	dso->data.file_size = st.st_size;
10088c2ecf20Sopenharmony_ci
10098c2ecf20Sopenharmony_ciout:
10108c2ecf20Sopenharmony_ci	pthread_mutex_unlock(&dso__data_open_lock);
10118c2ecf20Sopenharmony_ci	return ret;
10128c2ecf20Sopenharmony_ci}
10138c2ecf20Sopenharmony_ci
10148c2ecf20Sopenharmony_ciint dso__data_file_size(struct dso *dso, struct machine *machine)
10158c2ecf20Sopenharmony_ci{
10168c2ecf20Sopenharmony_ci	if (dso->data.file_size)
10178c2ecf20Sopenharmony_ci		return 0;
10188c2ecf20Sopenharmony_ci
10198c2ecf20Sopenharmony_ci	if (dso->data.status == DSO_DATA_STATUS_ERROR)
10208c2ecf20Sopenharmony_ci		return -1;
10218c2ecf20Sopenharmony_ci
10228c2ecf20Sopenharmony_ci	if (dso->binary_type == DSO_BINARY_TYPE__BPF_PROG_INFO)
10238c2ecf20Sopenharmony_ci		return bpf_size(dso);
10248c2ecf20Sopenharmony_ci
10258c2ecf20Sopenharmony_ci	return file_size(dso, machine);
10268c2ecf20Sopenharmony_ci}
10278c2ecf20Sopenharmony_ci
10288c2ecf20Sopenharmony_ci/**
10298c2ecf20Sopenharmony_ci * dso__data_size - Return dso data size
10308c2ecf20Sopenharmony_ci * @dso: dso object
10318c2ecf20Sopenharmony_ci * @machine: machine object
10328c2ecf20Sopenharmony_ci *
10338c2ecf20Sopenharmony_ci * Return: dso data size
10348c2ecf20Sopenharmony_ci */
10358c2ecf20Sopenharmony_cioff_t dso__data_size(struct dso *dso, struct machine *machine)
10368c2ecf20Sopenharmony_ci{
10378c2ecf20Sopenharmony_ci	if (dso__data_file_size(dso, machine))
10388c2ecf20Sopenharmony_ci		return -1;
10398c2ecf20Sopenharmony_ci
10408c2ecf20Sopenharmony_ci	/* For now just estimate dso data size is close to file size */
10418c2ecf20Sopenharmony_ci	return dso->data.file_size;
10428c2ecf20Sopenharmony_ci}
10438c2ecf20Sopenharmony_ci
10448c2ecf20Sopenharmony_cistatic ssize_t data_read_write_offset(struct dso *dso, struct machine *machine,
10458c2ecf20Sopenharmony_ci				      u64 offset, u8 *data, ssize_t size,
10468c2ecf20Sopenharmony_ci				      bool out)
10478c2ecf20Sopenharmony_ci{
10488c2ecf20Sopenharmony_ci	if (dso__data_file_size(dso, machine))
10498c2ecf20Sopenharmony_ci		return -1;
10508c2ecf20Sopenharmony_ci
10518c2ecf20Sopenharmony_ci	/* Check the offset sanity. */
10528c2ecf20Sopenharmony_ci	if (offset > dso->data.file_size)
10538c2ecf20Sopenharmony_ci		return -1;
10548c2ecf20Sopenharmony_ci
10558c2ecf20Sopenharmony_ci	if (offset + size < offset)
10568c2ecf20Sopenharmony_ci		return -1;
10578c2ecf20Sopenharmony_ci
10588c2ecf20Sopenharmony_ci	return cached_io(dso, machine, offset, data, size, out);
10598c2ecf20Sopenharmony_ci}
10608c2ecf20Sopenharmony_ci
10618c2ecf20Sopenharmony_ci/**
10628c2ecf20Sopenharmony_ci * dso__data_read_offset - Read data from dso file offset
10638c2ecf20Sopenharmony_ci * @dso: dso object
10648c2ecf20Sopenharmony_ci * @machine: machine object
10658c2ecf20Sopenharmony_ci * @offset: file offset
10668c2ecf20Sopenharmony_ci * @data: buffer to store data
10678c2ecf20Sopenharmony_ci * @size: size of the @data buffer
10688c2ecf20Sopenharmony_ci *
10698c2ecf20Sopenharmony_ci * External interface to read data from dso file offset. Open
10708c2ecf20Sopenharmony_ci * dso data file and use cached_read to get the data.
10718c2ecf20Sopenharmony_ci */
10728c2ecf20Sopenharmony_cissize_t dso__data_read_offset(struct dso *dso, struct machine *machine,
10738c2ecf20Sopenharmony_ci			      u64 offset, u8 *data, ssize_t size)
10748c2ecf20Sopenharmony_ci{
10758c2ecf20Sopenharmony_ci	if (dso->data.status == DSO_DATA_STATUS_ERROR)
10768c2ecf20Sopenharmony_ci		return -1;
10778c2ecf20Sopenharmony_ci
10788c2ecf20Sopenharmony_ci	return data_read_write_offset(dso, machine, offset, data, size, true);
10798c2ecf20Sopenharmony_ci}
10808c2ecf20Sopenharmony_ci
10818c2ecf20Sopenharmony_ci/**
10828c2ecf20Sopenharmony_ci * dso__data_read_addr - Read data from dso address
10838c2ecf20Sopenharmony_ci * @dso: dso object
10848c2ecf20Sopenharmony_ci * @machine: machine object
10858c2ecf20Sopenharmony_ci * @add: virtual memory address
10868c2ecf20Sopenharmony_ci * @data: buffer to store data
10878c2ecf20Sopenharmony_ci * @size: size of the @data buffer
10888c2ecf20Sopenharmony_ci *
10898c2ecf20Sopenharmony_ci * External interface to read data from dso address.
10908c2ecf20Sopenharmony_ci */
10918c2ecf20Sopenharmony_cissize_t dso__data_read_addr(struct dso *dso, struct map *map,
10928c2ecf20Sopenharmony_ci			    struct machine *machine, u64 addr,
10938c2ecf20Sopenharmony_ci			    u8 *data, ssize_t size)
10948c2ecf20Sopenharmony_ci{
10958c2ecf20Sopenharmony_ci	u64 offset = map->map_ip(map, addr);
10968c2ecf20Sopenharmony_ci	return dso__data_read_offset(dso, machine, offset, data, size);
10978c2ecf20Sopenharmony_ci}
10988c2ecf20Sopenharmony_ci
10998c2ecf20Sopenharmony_ci/**
11008c2ecf20Sopenharmony_ci * dso__data_write_cache_offs - Write data to dso data cache at file offset
11018c2ecf20Sopenharmony_ci * @dso: dso object
11028c2ecf20Sopenharmony_ci * @machine: machine object
11038c2ecf20Sopenharmony_ci * @offset: file offset
11048c2ecf20Sopenharmony_ci * @data: buffer to write
11058c2ecf20Sopenharmony_ci * @size: size of the @data buffer
11068c2ecf20Sopenharmony_ci *
11078c2ecf20Sopenharmony_ci * Write into the dso file data cache, but do not change the file itself.
11088c2ecf20Sopenharmony_ci */
11098c2ecf20Sopenharmony_cissize_t dso__data_write_cache_offs(struct dso *dso, struct machine *machine,
11108c2ecf20Sopenharmony_ci				   u64 offset, const u8 *data_in, ssize_t size)
11118c2ecf20Sopenharmony_ci{
11128c2ecf20Sopenharmony_ci	u8 *data = (u8 *)data_in; /* cast away const to use same fns for r/w */
11138c2ecf20Sopenharmony_ci
11148c2ecf20Sopenharmony_ci	if (dso->data.status == DSO_DATA_STATUS_ERROR)
11158c2ecf20Sopenharmony_ci		return -1;
11168c2ecf20Sopenharmony_ci
11178c2ecf20Sopenharmony_ci	return data_read_write_offset(dso, machine, offset, data, size, false);
11188c2ecf20Sopenharmony_ci}
11198c2ecf20Sopenharmony_ci
11208c2ecf20Sopenharmony_ci/**
11218c2ecf20Sopenharmony_ci * dso__data_write_cache_addr - Write data to dso data cache at dso address
11228c2ecf20Sopenharmony_ci * @dso: dso object
11238c2ecf20Sopenharmony_ci * @machine: machine object
11248c2ecf20Sopenharmony_ci * @add: virtual memory address
11258c2ecf20Sopenharmony_ci * @data: buffer to write
11268c2ecf20Sopenharmony_ci * @size: size of the @data buffer
11278c2ecf20Sopenharmony_ci *
11288c2ecf20Sopenharmony_ci * External interface to write into the dso file data cache, but do not change
11298c2ecf20Sopenharmony_ci * the file itself.
11308c2ecf20Sopenharmony_ci */
11318c2ecf20Sopenharmony_cissize_t dso__data_write_cache_addr(struct dso *dso, struct map *map,
11328c2ecf20Sopenharmony_ci				   struct machine *machine, u64 addr,
11338c2ecf20Sopenharmony_ci				   const u8 *data, ssize_t size)
11348c2ecf20Sopenharmony_ci{
11358c2ecf20Sopenharmony_ci	u64 offset = map->map_ip(map, addr);
11368c2ecf20Sopenharmony_ci	return dso__data_write_cache_offs(dso, machine, offset, data, size);
11378c2ecf20Sopenharmony_ci}
11388c2ecf20Sopenharmony_ci
11398c2ecf20Sopenharmony_cistruct map *dso__new_map(const char *name)
11408c2ecf20Sopenharmony_ci{
11418c2ecf20Sopenharmony_ci	struct map *map = NULL;
11428c2ecf20Sopenharmony_ci	struct dso *dso = dso__new(name);
11438c2ecf20Sopenharmony_ci
11448c2ecf20Sopenharmony_ci	if (dso) {
11458c2ecf20Sopenharmony_ci		map = map__new2(0, dso);
11468c2ecf20Sopenharmony_ci		dso__put(dso);
11478c2ecf20Sopenharmony_ci	}
11488c2ecf20Sopenharmony_ci
11498c2ecf20Sopenharmony_ci	return map;
11508c2ecf20Sopenharmony_ci}
11518c2ecf20Sopenharmony_ci
11528c2ecf20Sopenharmony_cistruct dso *machine__findnew_kernel(struct machine *machine, const char *name,
11538c2ecf20Sopenharmony_ci				    const char *short_name, int dso_type)
11548c2ecf20Sopenharmony_ci{
11558c2ecf20Sopenharmony_ci	/*
11568c2ecf20Sopenharmony_ci	 * The kernel dso could be created by build_id processing.
11578c2ecf20Sopenharmony_ci	 */
11588c2ecf20Sopenharmony_ci	struct dso *dso = machine__findnew_dso(machine, name);
11598c2ecf20Sopenharmony_ci
11608c2ecf20Sopenharmony_ci	/*
11618c2ecf20Sopenharmony_ci	 * We need to run this in all cases, since during the build_id
11628c2ecf20Sopenharmony_ci	 * processing we had no idea this was the kernel dso.
11638c2ecf20Sopenharmony_ci	 */
11648c2ecf20Sopenharmony_ci	if (dso != NULL) {
11658c2ecf20Sopenharmony_ci		dso__set_short_name(dso, short_name, false);
11668c2ecf20Sopenharmony_ci		dso->kernel = dso_type;
11678c2ecf20Sopenharmony_ci	}
11688c2ecf20Sopenharmony_ci
11698c2ecf20Sopenharmony_ci	return dso;
11708c2ecf20Sopenharmony_ci}
11718c2ecf20Sopenharmony_ci
11728c2ecf20Sopenharmony_cistatic void dso__set_long_name_id(struct dso *dso, const char *name, struct dso_id *id, bool name_allocated)
11738c2ecf20Sopenharmony_ci{
11748c2ecf20Sopenharmony_ci	struct rb_root *root = dso->root;
11758c2ecf20Sopenharmony_ci
11768c2ecf20Sopenharmony_ci	if (name == NULL)
11778c2ecf20Sopenharmony_ci		return;
11788c2ecf20Sopenharmony_ci
11798c2ecf20Sopenharmony_ci	if (dso->long_name_allocated)
11808c2ecf20Sopenharmony_ci		free((char *)dso->long_name);
11818c2ecf20Sopenharmony_ci
11828c2ecf20Sopenharmony_ci	if (root) {
11838c2ecf20Sopenharmony_ci		rb_erase(&dso->rb_node, root);
11848c2ecf20Sopenharmony_ci		/*
11858c2ecf20Sopenharmony_ci		 * __dsos__findnew_link_by_longname_id() isn't guaranteed to
11868c2ecf20Sopenharmony_ci		 * add it back, so a clean removal is required here.
11878c2ecf20Sopenharmony_ci		 */
11888c2ecf20Sopenharmony_ci		RB_CLEAR_NODE(&dso->rb_node);
11898c2ecf20Sopenharmony_ci		dso->root = NULL;
11908c2ecf20Sopenharmony_ci	}
11918c2ecf20Sopenharmony_ci
11928c2ecf20Sopenharmony_ci	dso->long_name		 = name;
11938c2ecf20Sopenharmony_ci	dso->long_name_len	 = strlen(name);
11948c2ecf20Sopenharmony_ci	dso->long_name_allocated = name_allocated;
11958c2ecf20Sopenharmony_ci
11968c2ecf20Sopenharmony_ci	if (root)
11978c2ecf20Sopenharmony_ci		__dsos__findnew_link_by_longname_id(root, dso, NULL, id);
11988c2ecf20Sopenharmony_ci}
11998c2ecf20Sopenharmony_ci
12008c2ecf20Sopenharmony_civoid dso__set_long_name(struct dso *dso, const char *name, bool name_allocated)
12018c2ecf20Sopenharmony_ci{
12028c2ecf20Sopenharmony_ci	dso__set_long_name_id(dso, name, NULL, name_allocated);
12038c2ecf20Sopenharmony_ci}
12048c2ecf20Sopenharmony_ci
12058c2ecf20Sopenharmony_civoid dso__set_short_name(struct dso *dso, const char *name, bool name_allocated)
12068c2ecf20Sopenharmony_ci{
12078c2ecf20Sopenharmony_ci	if (name == NULL)
12088c2ecf20Sopenharmony_ci		return;
12098c2ecf20Sopenharmony_ci
12108c2ecf20Sopenharmony_ci	if (dso->short_name_allocated)
12118c2ecf20Sopenharmony_ci		free((char *)dso->short_name);
12128c2ecf20Sopenharmony_ci
12138c2ecf20Sopenharmony_ci	dso->short_name		  = name;
12148c2ecf20Sopenharmony_ci	dso->short_name_len	  = strlen(name);
12158c2ecf20Sopenharmony_ci	dso->short_name_allocated = name_allocated;
12168c2ecf20Sopenharmony_ci}
12178c2ecf20Sopenharmony_ci
12188c2ecf20Sopenharmony_ciint dso__name_len(const struct dso *dso)
12198c2ecf20Sopenharmony_ci{
12208c2ecf20Sopenharmony_ci	if (!dso)
12218c2ecf20Sopenharmony_ci		return strlen("[unknown]");
12228c2ecf20Sopenharmony_ci	if (verbose > 0)
12238c2ecf20Sopenharmony_ci		return dso->long_name_len;
12248c2ecf20Sopenharmony_ci
12258c2ecf20Sopenharmony_ci	return dso->short_name_len;
12268c2ecf20Sopenharmony_ci}
12278c2ecf20Sopenharmony_ci
12288c2ecf20Sopenharmony_cibool dso__loaded(const struct dso *dso)
12298c2ecf20Sopenharmony_ci{
12308c2ecf20Sopenharmony_ci	return dso->loaded;
12318c2ecf20Sopenharmony_ci}
12328c2ecf20Sopenharmony_ci
12338c2ecf20Sopenharmony_cibool dso__sorted_by_name(const struct dso *dso)
12348c2ecf20Sopenharmony_ci{
12358c2ecf20Sopenharmony_ci	return dso->sorted_by_name;
12368c2ecf20Sopenharmony_ci}
12378c2ecf20Sopenharmony_ci
12388c2ecf20Sopenharmony_civoid dso__set_sorted_by_name(struct dso *dso)
12398c2ecf20Sopenharmony_ci{
12408c2ecf20Sopenharmony_ci	dso->sorted_by_name = true;
12418c2ecf20Sopenharmony_ci}
12428c2ecf20Sopenharmony_ci
12438c2ecf20Sopenharmony_cistruct dso *dso__new_id(const char *name, struct dso_id *id)
12448c2ecf20Sopenharmony_ci{
12458c2ecf20Sopenharmony_ci	struct dso *dso = calloc(1, sizeof(*dso) + strlen(name) + 1);
12468c2ecf20Sopenharmony_ci
12478c2ecf20Sopenharmony_ci	if (dso != NULL) {
12488c2ecf20Sopenharmony_ci		strcpy(dso->name, name);
12498c2ecf20Sopenharmony_ci		if (id)
12508c2ecf20Sopenharmony_ci			dso->id = *id;
12518c2ecf20Sopenharmony_ci		dso__set_long_name_id(dso, dso->name, id, false);
12528c2ecf20Sopenharmony_ci		dso__set_short_name(dso, dso->name, false);
12538c2ecf20Sopenharmony_ci		dso->symbols = dso->symbol_names = RB_ROOT_CACHED;
12548c2ecf20Sopenharmony_ci		dso->data.cache = RB_ROOT;
12558c2ecf20Sopenharmony_ci		dso->inlined_nodes = RB_ROOT_CACHED;
12568c2ecf20Sopenharmony_ci		dso->srclines = RB_ROOT_CACHED;
12578c2ecf20Sopenharmony_ci		dso->data.fd = -1;
12588c2ecf20Sopenharmony_ci		dso->data.status = DSO_DATA_STATUS_UNKNOWN;
12598c2ecf20Sopenharmony_ci		dso->symtab_type = DSO_BINARY_TYPE__NOT_FOUND;
12608c2ecf20Sopenharmony_ci		dso->binary_type = DSO_BINARY_TYPE__NOT_FOUND;
12618c2ecf20Sopenharmony_ci		dso->is_64_bit = (sizeof(void *) == 8);
12628c2ecf20Sopenharmony_ci		dso->loaded = 0;
12638c2ecf20Sopenharmony_ci		dso->rel = 0;
12648c2ecf20Sopenharmony_ci		dso->sorted_by_name = 0;
12658c2ecf20Sopenharmony_ci		dso->has_build_id = 0;
12668c2ecf20Sopenharmony_ci		dso->has_srcline = 1;
12678c2ecf20Sopenharmony_ci		dso->a2l_fails = 1;
12688c2ecf20Sopenharmony_ci		dso->kernel = DSO_SPACE__USER;
12698c2ecf20Sopenharmony_ci		dso->needs_swap = DSO_SWAP__UNSET;
12708c2ecf20Sopenharmony_ci		dso->comp = COMP_ID__NONE;
12718c2ecf20Sopenharmony_ci		RB_CLEAR_NODE(&dso->rb_node);
12728c2ecf20Sopenharmony_ci		dso->root = NULL;
12738c2ecf20Sopenharmony_ci		INIT_LIST_HEAD(&dso->node);
12748c2ecf20Sopenharmony_ci		INIT_LIST_HEAD(&dso->data.open_entry);
12758c2ecf20Sopenharmony_ci		pthread_mutex_init(&dso->lock, NULL);
12768c2ecf20Sopenharmony_ci		refcount_set(&dso->refcnt, 1);
12778c2ecf20Sopenharmony_ci	}
12788c2ecf20Sopenharmony_ci
12798c2ecf20Sopenharmony_ci	return dso;
12808c2ecf20Sopenharmony_ci}
12818c2ecf20Sopenharmony_ci
12828c2ecf20Sopenharmony_cistruct dso *dso__new(const char *name)
12838c2ecf20Sopenharmony_ci{
12848c2ecf20Sopenharmony_ci	return dso__new_id(name, NULL);
12858c2ecf20Sopenharmony_ci}
12868c2ecf20Sopenharmony_ci
12878c2ecf20Sopenharmony_civoid dso__delete(struct dso *dso)
12888c2ecf20Sopenharmony_ci{
12898c2ecf20Sopenharmony_ci	if (!RB_EMPTY_NODE(&dso->rb_node))
12908c2ecf20Sopenharmony_ci		pr_err("DSO %s is still in rbtree when being deleted!\n",
12918c2ecf20Sopenharmony_ci		       dso->long_name);
12928c2ecf20Sopenharmony_ci
12938c2ecf20Sopenharmony_ci	/* free inlines first, as they reference symbols */
12948c2ecf20Sopenharmony_ci	inlines__tree_delete(&dso->inlined_nodes);
12958c2ecf20Sopenharmony_ci	srcline__tree_delete(&dso->srclines);
12968c2ecf20Sopenharmony_ci	symbols__delete(&dso->symbols);
12978c2ecf20Sopenharmony_ci
12988c2ecf20Sopenharmony_ci	if (dso->short_name_allocated) {
12998c2ecf20Sopenharmony_ci		zfree((char **)&dso->short_name);
13008c2ecf20Sopenharmony_ci		dso->short_name_allocated = false;
13018c2ecf20Sopenharmony_ci	}
13028c2ecf20Sopenharmony_ci
13038c2ecf20Sopenharmony_ci	if (dso->long_name_allocated) {
13048c2ecf20Sopenharmony_ci		zfree((char **)&dso->long_name);
13058c2ecf20Sopenharmony_ci		dso->long_name_allocated = false;
13068c2ecf20Sopenharmony_ci	}
13078c2ecf20Sopenharmony_ci
13088c2ecf20Sopenharmony_ci	dso__data_close(dso);
13098c2ecf20Sopenharmony_ci	auxtrace_cache__free(dso->auxtrace_cache);
13108c2ecf20Sopenharmony_ci	dso_cache__free(dso);
13118c2ecf20Sopenharmony_ci	dso__free_a2l(dso);
13128c2ecf20Sopenharmony_ci	zfree(&dso->symsrc_filename);
13138c2ecf20Sopenharmony_ci	nsinfo__zput(dso->nsinfo);
13148c2ecf20Sopenharmony_ci	pthread_mutex_destroy(&dso->lock);
13158c2ecf20Sopenharmony_ci	free(dso);
13168c2ecf20Sopenharmony_ci}
13178c2ecf20Sopenharmony_ci
13188c2ecf20Sopenharmony_cistruct dso *dso__get(struct dso *dso)
13198c2ecf20Sopenharmony_ci{
13208c2ecf20Sopenharmony_ci	if (dso)
13218c2ecf20Sopenharmony_ci		refcount_inc(&dso->refcnt);
13228c2ecf20Sopenharmony_ci	return dso;
13238c2ecf20Sopenharmony_ci}
13248c2ecf20Sopenharmony_ci
13258c2ecf20Sopenharmony_civoid dso__put(struct dso *dso)
13268c2ecf20Sopenharmony_ci{
13278c2ecf20Sopenharmony_ci	if (dso && refcount_dec_and_test(&dso->refcnt))
13288c2ecf20Sopenharmony_ci		dso__delete(dso);
13298c2ecf20Sopenharmony_ci}
13308c2ecf20Sopenharmony_ci
13318c2ecf20Sopenharmony_civoid dso__set_build_id(struct dso *dso, struct build_id *bid)
13328c2ecf20Sopenharmony_ci{
13338c2ecf20Sopenharmony_ci	dso->bid = *bid;
13348c2ecf20Sopenharmony_ci	dso->has_build_id = 1;
13358c2ecf20Sopenharmony_ci}
13368c2ecf20Sopenharmony_ci
13378c2ecf20Sopenharmony_cibool dso__build_id_equal(const struct dso *dso, struct build_id *bid)
13388c2ecf20Sopenharmony_ci{
13398c2ecf20Sopenharmony_ci	if (dso->bid.size > bid->size && dso->bid.size == BUILD_ID_SIZE) {
13408c2ecf20Sopenharmony_ci		/*
13418c2ecf20Sopenharmony_ci		 * For the backward compatibility, it allows a build-id has
13428c2ecf20Sopenharmony_ci		 * trailing zeros.
13438c2ecf20Sopenharmony_ci		 */
13448c2ecf20Sopenharmony_ci		return !memcmp(dso->bid.data, bid->data, bid->size) &&
13458c2ecf20Sopenharmony_ci			!memchr_inv(&dso->bid.data[bid->size], 0,
13468c2ecf20Sopenharmony_ci				    dso->bid.size - bid->size);
13478c2ecf20Sopenharmony_ci	}
13488c2ecf20Sopenharmony_ci
13498c2ecf20Sopenharmony_ci	return dso->bid.size == bid->size &&
13508c2ecf20Sopenharmony_ci	       memcmp(dso->bid.data, bid->data, dso->bid.size) == 0;
13518c2ecf20Sopenharmony_ci}
13528c2ecf20Sopenharmony_ci
13538c2ecf20Sopenharmony_civoid dso__read_running_kernel_build_id(struct dso *dso, struct machine *machine)
13548c2ecf20Sopenharmony_ci{
13558c2ecf20Sopenharmony_ci	char path[PATH_MAX];
13568c2ecf20Sopenharmony_ci
13578c2ecf20Sopenharmony_ci	if (machine__is_default_guest(machine))
13588c2ecf20Sopenharmony_ci		return;
13598c2ecf20Sopenharmony_ci	sprintf(path, "%s/sys/kernel/notes", machine->root_dir);
13608c2ecf20Sopenharmony_ci	if (sysfs__read_build_id(path, &dso->bid) == 0)
13618c2ecf20Sopenharmony_ci		dso->has_build_id = true;
13628c2ecf20Sopenharmony_ci}
13638c2ecf20Sopenharmony_ci
13648c2ecf20Sopenharmony_ciint dso__kernel_module_get_build_id(struct dso *dso,
13658c2ecf20Sopenharmony_ci				    const char *root_dir)
13668c2ecf20Sopenharmony_ci{
13678c2ecf20Sopenharmony_ci	char filename[PATH_MAX];
13688c2ecf20Sopenharmony_ci	/*
13698c2ecf20Sopenharmony_ci	 * kernel module short names are of the form "[module]" and
13708c2ecf20Sopenharmony_ci	 * we need just "module" here.
13718c2ecf20Sopenharmony_ci	 */
13728c2ecf20Sopenharmony_ci	const char *name = dso->short_name + 1;
13738c2ecf20Sopenharmony_ci
13748c2ecf20Sopenharmony_ci	snprintf(filename, sizeof(filename),
13758c2ecf20Sopenharmony_ci		 "%s/sys/module/%.*s/notes/.note.gnu.build-id",
13768c2ecf20Sopenharmony_ci		 root_dir, (int)strlen(name) - 1, name);
13778c2ecf20Sopenharmony_ci
13788c2ecf20Sopenharmony_ci	if (sysfs__read_build_id(filename, &dso->bid) == 0)
13798c2ecf20Sopenharmony_ci		dso->has_build_id = true;
13808c2ecf20Sopenharmony_ci
13818c2ecf20Sopenharmony_ci	return 0;
13828c2ecf20Sopenharmony_ci}
13838c2ecf20Sopenharmony_ci
13848c2ecf20Sopenharmony_cistatic size_t dso__fprintf_buildid(struct dso *dso, FILE *fp)
13858c2ecf20Sopenharmony_ci{
13868c2ecf20Sopenharmony_ci	char sbuild_id[SBUILD_ID_SIZE];
13878c2ecf20Sopenharmony_ci
13888c2ecf20Sopenharmony_ci	build_id__sprintf(&dso->bid, sbuild_id);
13898c2ecf20Sopenharmony_ci	return fprintf(fp, "%s", sbuild_id);
13908c2ecf20Sopenharmony_ci}
13918c2ecf20Sopenharmony_ci
13928c2ecf20Sopenharmony_cisize_t dso__fprintf(struct dso *dso, FILE *fp)
13938c2ecf20Sopenharmony_ci{
13948c2ecf20Sopenharmony_ci	struct rb_node *nd;
13958c2ecf20Sopenharmony_ci	size_t ret = fprintf(fp, "dso: %s (", dso->short_name);
13968c2ecf20Sopenharmony_ci
13978c2ecf20Sopenharmony_ci	if (dso->short_name != dso->long_name)
13988c2ecf20Sopenharmony_ci		ret += fprintf(fp, "%s, ", dso->long_name);
13998c2ecf20Sopenharmony_ci	ret += fprintf(fp, "%sloaded, ", dso__loaded(dso) ? "" : "NOT ");
14008c2ecf20Sopenharmony_ci	ret += dso__fprintf_buildid(dso, fp);
14018c2ecf20Sopenharmony_ci	ret += fprintf(fp, ")\n");
14028c2ecf20Sopenharmony_ci	for (nd = rb_first_cached(&dso->symbols); nd; nd = rb_next(nd)) {
14038c2ecf20Sopenharmony_ci		struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
14048c2ecf20Sopenharmony_ci		ret += symbol__fprintf(pos, fp);
14058c2ecf20Sopenharmony_ci	}
14068c2ecf20Sopenharmony_ci
14078c2ecf20Sopenharmony_ci	return ret;
14088c2ecf20Sopenharmony_ci}
14098c2ecf20Sopenharmony_ci
14108c2ecf20Sopenharmony_cienum dso_type dso__type(struct dso *dso, struct machine *machine)
14118c2ecf20Sopenharmony_ci{
14128c2ecf20Sopenharmony_ci	int fd;
14138c2ecf20Sopenharmony_ci	enum dso_type type = DSO__TYPE_UNKNOWN;
14148c2ecf20Sopenharmony_ci
14158c2ecf20Sopenharmony_ci	fd = dso__data_get_fd(dso, machine);
14168c2ecf20Sopenharmony_ci	if (fd >= 0) {
14178c2ecf20Sopenharmony_ci		type = dso__type_fd(fd);
14188c2ecf20Sopenharmony_ci		dso__data_put_fd(dso);
14198c2ecf20Sopenharmony_ci	}
14208c2ecf20Sopenharmony_ci
14218c2ecf20Sopenharmony_ci	return type;
14228c2ecf20Sopenharmony_ci}
14238c2ecf20Sopenharmony_ci
14248c2ecf20Sopenharmony_ciint dso__strerror_load(struct dso *dso, char *buf, size_t buflen)
14258c2ecf20Sopenharmony_ci{
14268c2ecf20Sopenharmony_ci	int idx, errnum = dso->load_errno;
14278c2ecf20Sopenharmony_ci	/*
14288c2ecf20Sopenharmony_ci	 * This must have a same ordering as the enum dso_load_errno.
14298c2ecf20Sopenharmony_ci	 */
14308c2ecf20Sopenharmony_ci	static const char *dso_load__error_str[] = {
14318c2ecf20Sopenharmony_ci	"Internal tools/perf/ library error",
14328c2ecf20Sopenharmony_ci	"Invalid ELF file",
14338c2ecf20Sopenharmony_ci	"Can not read build id",
14348c2ecf20Sopenharmony_ci	"Mismatching build id",
14358c2ecf20Sopenharmony_ci	"Decompression failure",
14368c2ecf20Sopenharmony_ci	};
14378c2ecf20Sopenharmony_ci
14388c2ecf20Sopenharmony_ci	BUG_ON(buflen == 0);
14398c2ecf20Sopenharmony_ci
14408c2ecf20Sopenharmony_ci	if (errnum >= 0) {
14418c2ecf20Sopenharmony_ci		const char *err = str_error_r(errnum, buf, buflen);
14428c2ecf20Sopenharmony_ci
14438c2ecf20Sopenharmony_ci		if (err != buf)
14448c2ecf20Sopenharmony_ci			scnprintf(buf, buflen, "%s", err);
14458c2ecf20Sopenharmony_ci
14468c2ecf20Sopenharmony_ci		return 0;
14478c2ecf20Sopenharmony_ci	}
14488c2ecf20Sopenharmony_ci
14498c2ecf20Sopenharmony_ci	if (errnum <  __DSO_LOAD_ERRNO__START || errnum >= __DSO_LOAD_ERRNO__END)
14508c2ecf20Sopenharmony_ci		return -1;
14518c2ecf20Sopenharmony_ci
14528c2ecf20Sopenharmony_ci	idx = errnum - __DSO_LOAD_ERRNO__START;
14538c2ecf20Sopenharmony_ci	scnprintf(buf, buflen, "%s", dso_load__error_str[idx]);
14548c2ecf20Sopenharmony_ci	return 0;
14558c2ecf20Sopenharmony_ci}
1456