xref: /openbmc/linux/tools/perf/util/dso.c (revision 40f3b2d20b52b090976a60fe56fb838a45eb362f)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
2bda6ee4aSJiri Olsa #include <asm/bug.h>
3877a7a11SArnaldo Carvalho de Melo #include <linux/kernel.h>
4c6580451SJiri Olsa #include <sys/time.h>
5c6580451SJiri Olsa #include <sys/resource.h>
67a8ef4c4SArnaldo Carvalho de Melo #include <sys/types.h>
77a8ef4c4SArnaldo Carvalho de Melo #include <sys/stat.h>
87a8ef4c4SArnaldo Carvalho de Melo #include <unistd.h>
9a43783aeSArnaldo Carvalho de Melo #include <errno.h>
10c23c2a0fSArnaldo Carvalho de Melo #include <fcntl.h>
1168c0188eSArnaldo Carvalho de Melo #include <libgen.h>
12611f0afeSArnaldo Carvalho de Melo #include "compress.h"
13*40f3b2d2SArnaldo Carvalho de Melo #include "namespaces.h"
149a3993d4SArnaldo Carvalho de Melo #include "path.h"
15cdd059d7SJiri Olsa #include "symbol.h"
1611ea2515SMilian Wolff #include "srcline.h"
17cdd059d7SJiri Olsa #include "dso.h"
1869d2591aSArnaldo Carvalho de Melo #include "machine.h"
19cfe9174fSAdrian Hunter #include "auxtrace.h"
20cdd059d7SJiri Olsa #include "util.h"
21cdd059d7SJiri Olsa #include "debug.h"
22a067558eSArnaldo Carvalho de Melo #include "string2.h"
236ae98ba6SHe Kuang #include "vdso.h"
24cdd059d7SJiri Olsa 
259343e45bSMatija Glavinic Pecotic static const char * const debuglink_paths[] = {
269343e45bSMatija Glavinic Pecotic 	"%.0s%s",
279343e45bSMatija Glavinic Pecotic 	"%s/%s",
289343e45bSMatija Glavinic Pecotic 	"%s/.debug/%s",
299343e45bSMatija Glavinic Pecotic 	"/usr/lib/debug%s/%s"
309343e45bSMatija Glavinic Pecotic };
319343e45bSMatija Glavinic Pecotic 
32cdd059d7SJiri Olsa char dso__symtab_origin(const struct dso *dso)
33cdd059d7SJiri Olsa {
34cdd059d7SJiri Olsa 	static const char origin[] = {
35cdd059d7SJiri Olsa 		[DSO_BINARY_TYPE__KALLSYMS]			= 'k',
36cdd059d7SJiri Olsa 		[DSO_BINARY_TYPE__VMLINUX]			= 'v',
37cdd059d7SJiri Olsa 		[DSO_BINARY_TYPE__JAVA_JIT]			= 'j',
38cdd059d7SJiri Olsa 		[DSO_BINARY_TYPE__DEBUGLINK]			= 'l',
39cdd059d7SJiri Olsa 		[DSO_BINARY_TYPE__BUILD_ID_CACHE]		= 'B',
40d2396999SKrister Johansen 		[DSO_BINARY_TYPE__BUILD_ID_CACHE_DEBUGINFO]	= 'D',
41cdd059d7SJiri Olsa 		[DSO_BINARY_TYPE__FEDORA_DEBUGINFO]		= 'f',
42cdd059d7SJiri Olsa 		[DSO_BINARY_TYPE__UBUNTU_DEBUGINFO]		= 'u',
439cd00941SRicardo Ribalda Delgado 		[DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO]	= 'o',
44cdd059d7SJiri Olsa 		[DSO_BINARY_TYPE__BUILDID_DEBUGINFO]		= 'b',
45cdd059d7SJiri Olsa 		[DSO_BINARY_TYPE__SYSTEM_PATH_DSO]		= 'd',
46cdd059d7SJiri Olsa 		[DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE]		= 'K',
47c00c48fcSNamhyung Kim 		[DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP]	= 'm',
48cdd059d7SJiri Olsa 		[DSO_BINARY_TYPE__GUEST_KALLSYMS]		= 'g',
49cdd059d7SJiri Olsa 		[DSO_BINARY_TYPE__GUEST_KMODULE]		= 'G',
50c00c48fcSNamhyung Kim 		[DSO_BINARY_TYPE__GUEST_KMODULE_COMP]		= 'M',
51cdd059d7SJiri Olsa 		[DSO_BINARY_TYPE__GUEST_VMLINUX]		= 'V',
52cdd059d7SJiri Olsa 	};
53cdd059d7SJiri Olsa 
54cdd059d7SJiri Olsa 	if (dso == NULL || dso->symtab_type == DSO_BINARY_TYPE__NOT_FOUND)
55cdd059d7SJiri Olsa 		return '!';
56cdd059d7SJiri Olsa 	return origin[dso->symtab_type];
57cdd059d7SJiri Olsa }
58cdd059d7SJiri Olsa 
59ee4e9625SArnaldo Carvalho de Melo int dso__read_binary_type_filename(const struct dso *dso,
60ee4e9625SArnaldo Carvalho de Melo 				   enum dso_binary_type type,
617d2a5122SArnaldo Carvalho de Melo 				   char *root_dir, char *filename, size_t size)
62cdd059d7SJiri Olsa {
63b5d8bbe8SMasami Hiramatsu 	char build_id_hex[SBUILD_ID_SIZE];
64cdd059d7SJiri Olsa 	int ret = 0;
65972f393bSArnaldo Carvalho de Melo 	size_t len;
66cdd059d7SJiri Olsa 
67cdd059d7SJiri Olsa 	switch (type) {
689343e45bSMatija Glavinic Pecotic 	case DSO_BINARY_TYPE__DEBUGLINK:
699343e45bSMatija Glavinic Pecotic 	{
709343e45bSMatija Glavinic Pecotic 		const char *last_slash;
719343e45bSMatija Glavinic Pecotic 		char dso_dir[PATH_MAX];
729343e45bSMatija Glavinic Pecotic 		char symfile[PATH_MAX];
739343e45bSMatija Glavinic Pecotic 		unsigned int i;
74cdd059d7SJiri Olsa 
75dc6254cfSVictor Kamensky 		len = __symbol__join_symfs(filename, size, dso->long_name);
769343e45bSMatija Glavinic Pecotic 		last_slash = filename + len;
779343e45bSMatija Glavinic Pecotic 		while (last_slash != filename && *last_slash != '/')
789343e45bSMatija Glavinic Pecotic 			last_slash--;
7940356721SJiri Olsa 
809343e45bSMatija Glavinic Pecotic 		strncpy(dso_dir, filename, last_slash - filename);
819343e45bSMatija Glavinic Pecotic 		dso_dir[last_slash-filename] = '\0';
829343e45bSMatija Glavinic Pecotic 
839343e45bSMatija Glavinic Pecotic 		if (!is_regular_file(filename)) {
8440356721SJiri Olsa 			ret = -1;
859343e45bSMatija Glavinic Pecotic 			break;
869343e45bSMatija Glavinic Pecotic 		}
879343e45bSMatija Glavinic Pecotic 
889343e45bSMatija Glavinic Pecotic 		ret = filename__read_debuglink(filename, symfile, PATH_MAX);
899343e45bSMatija Glavinic Pecotic 		if (ret)
9040356721SJiri Olsa 			break;
9140356721SJiri Olsa 
929343e45bSMatija Glavinic Pecotic 		/* Check predefined locations where debug file might reside */
939343e45bSMatija Glavinic Pecotic 		ret = -1;
949343e45bSMatija Glavinic Pecotic 		for (i = 0; i < ARRAY_SIZE(debuglink_paths); i++) {
959343e45bSMatija Glavinic Pecotic 			snprintf(filename, size,
969343e45bSMatija Glavinic Pecotic 					debuglink_paths[i], dso_dir, symfile);
979343e45bSMatija Glavinic Pecotic 			if (is_regular_file(filename)) {
989343e45bSMatija Glavinic Pecotic 				ret = 0;
99cdd059d7SJiri Olsa 				break;
1009343e45bSMatija Glavinic Pecotic 			}
1019343e45bSMatija Glavinic Pecotic 		}
1029343e45bSMatija Glavinic Pecotic 
1039343e45bSMatija Glavinic Pecotic 		break;
1049343e45bSMatija Glavinic Pecotic 	}
105cdd059d7SJiri Olsa 	case DSO_BINARY_TYPE__BUILD_ID_CACHE:
106d2396999SKrister Johansen 		if (dso__build_id_filename(dso, filename, size, false) == NULL)
107d2396999SKrister Johansen 			ret = -1;
108d2396999SKrister Johansen 		break;
109d2396999SKrister Johansen 
110d2396999SKrister Johansen 	case DSO_BINARY_TYPE__BUILD_ID_CACHE_DEBUGINFO:
111d2396999SKrister Johansen 		if (dso__build_id_filename(dso, filename, size, true) == NULL)
112cdd059d7SJiri Olsa 			ret = -1;
113cdd059d7SJiri Olsa 		break;
114cdd059d7SJiri Olsa 
115cdd059d7SJiri Olsa 	case DSO_BINARY_TYPE__FEDORA_DEBUGINFO:
116972f393bSArnaldo Carvalho de Melo 		len = __symbol__join_symfs(filename, size, "/usr/lib/debug");
117972f393bSArnaldo Carvalho de Melo 		snprintf(filename + len, size - len, "%s.debug", dso->long_name);
118cdd059d7SJiri Olsa 		break;
119cdd059d7SJiri Olsa 
120cdd059d7SJiri Olsa 	case DSO_BINARY_TYPE__UBUNTU_DEBUGINFO:
121972f393bSArnaldo Carvalho de Melo 		len = __symbol__join_symfs(filename, size, "/usr/lib/debug");
122972f393bSArnaldo Carvalho de Melo 		snprintf(filename + len, size - len, "%s", dso->long_name);
123cdd059d7SJiri Olsa 		break;
124cdd059d7SJiri Olsa 
1259cd00941SRicardo Ribalda Delgado 	case DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO:
1269cd00941SRicardo Ribalda Delgado 	{
127bf4414aeSArnaldo Carvalho de Melo 		const char *last_slash;
1289cd00941SRicardo Ribalda Delgado 		size_t dir_size;
1299cd00941SRicardo Ribalda Delgado 
1309cd00941SRicardo Ribalda Delgado 		last_slash = dso->long_name + dso->long_name_len;
1319cd00941SRicardo Ribalda Delgado 		while (last_slash != dso->long_name && *last_slash != '/')
1329cd00941SRicardo Ribalda Delgado 			last_slash--;
1339cd00941SRicardo Ribalda Delgado 
134972f393bSArnaldo Carvalho de Melo 		len = __symbol__join_symfs(filename, size, "");
1359cd00941SRicardo Ribalda Delgado 		dir_size = last_slash - dso->long_name + 2;
1369cd00941SRicardo Ribalda Delgado 		if (dir_size > (size - len)) {
1379cd00941SRicardo Ribalda Delgado 			ret = -1;
1389cd00941SRicardo Ribalda Delgado 			break;
1399cd00941SRicardo Ribalda Delgado 		}
1407d2a5122SArnaldo Carvalho de Melo 		len += scnprintf(filename + len, dir_size, "%s",  dso->long_name);
1417d2a5122SArnaldo Carvalho de Melo 		len += scnprintf(filename + len , size - len, ".debug%s",
1429cd00941SRicardo Ribalda Delgado 								last_slash);
1439cd00941SRicardo Ribalda Delgado 		break;
1449cd00941SRicardo Ribalda Delgado 	}
1459cd00941SRicardo Ribalda Delgado 
146cdd059d7SJiri Olsa 	case DSO_BINARY_TYPE__BUILDID_DEBUGINFO:
147cdd059d7SJiri Olsa 		if (!dso->has_build_id) {
148cdd059d7SJiri Olsa 			ret = -1;
149cdd059d7SJiri Olsa 			break;
150cdd059d7SJiri Olsa 		}
151cdd059d7SJiri Olsa 
152cdd059d7SJiri Olsa 		build_id__sprintf(dso->build_id,
153cdd059d7SJiri Olsa 				  sizeof(dso->build_id),
154cdd059d7SJiri Olsa 				  build_id_hex);
155972f393bSArnaldo Carvalho de Melo 		len = __symbol__join_symfs(filename, size, "/usr/lib/debug/.build-id/");
156972f393bSArnaldo Carvalho de Melo 		snprintf(filename + len, size - len, "%.2s/%s.debug",
157972f393bSArnaldo Carvalho de Melo 			 build_id_hex, build_id_hex + 2);
158cdd059d7SJiri Olsa 		break;
159cdd059d7SJiri Olsa 
16039b12f78SAdrian Hunter 	case DSO_BINARY_TYPE__VMLINUX:
16139b12f78SAdrian Hunter 	case DSO_BINARY_TYPE__GUEST_VMLINUX:
162cdd059d7SJiri Olsa 	case DSO_BINARY_TYPE__SYSTEM_PATH_DSO:
163972f393bSArnaldo Carvalho de Melo 		__symbol__join_symfs(filename, size, dso->long_name);
164cdd059d7SJiri Olsa 		break;
165cdd059d7SJiri Olsa 
166cdd059d7SJiri Olsa 	case DSO_BINARY_TYPE__GUEST_KMODULE:
167c00c48fcSNamhyung Kim 	case DSO_BINARY_TYPE__GUEST_KMODULE_COMP:
168972f393bSArnaldo Carvalho de Melo 		path__join3(filename, size, symbol_conf.symfs,
169cdd059d7SJiri Olsa 			    root_dir, dso->long_name);
170cdd059d7SJiri Olsa 		break;
171cdd059d7SJiri Olsa 
172cdd059d7SJiri Olsa 	case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE:
173c00c48fcSNamhyung Kim 	case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP:
174972f393bSArnaldo Carvalho de Melo 		__symbol__join_symfs(filename, size, dso->long_name);
175cdd059d7SJiri Olsa 		break;
176cdd059d7SJiri Olsa 
1778e0cf965SAdrian Hunter 	case DSO_BINARY_TYPE__KCORE:
1788e0cf965SAdrian Hunter 	case DSO_BINARY_TYPE__GUEST_KCORE:
1797d2a5122SArnaldo Carvalho de Melo 		snprintf(filename, size, "%s", dso->long_name);
1808e0cf965SAdrian Hunter 		break;
1818e0cf965SAdrian Hunter 
182cdd059d7SJiri Olsa 	default:
183cdd059d7SJiri Olsa 	case DSO_BINARY_TYPE__KALLSYMS:
184cdd059d7SJiri Olsa 	case DSO_BINARY_TYPE__GUEST_KALLSYMS:
185cdd059d7SJiri Olsa 	case DSO_BINARY_TYPE__JAVA_JIT:
186cdd059d7SJiri Olsa 	case DSO_BINARY_TYPE__NOT_FOUND:
187cdd059d7SJiri Olsa 		ret = -1;
188cdd059d7SJiri Olsa 		break;
189cdd059d7SJiri Olsa 	}
190cdd059d7SJiri Olsa 
191cdd059d7SJiri Olsa 	return ret;
192cdd059d7SJiri Olsa }
193cdd059d7SJiri Olsa 
1944b838b0dSJiri Olsa enum {
1954b838b0dSJiri Olsa 	COMP_ID__NONE = 0,
1964b838b0dSJiri Olsa };
1974b838b0dSJiri Olsa 
198c00c48fcSNamhyung Kim static const struct {
199c00c48fcSNamhyung Kim 	const char *fmt;
200c00c48fcSNamhyung Kim 	int (*decompress)(const char *input, int output);
2018b42b7e5SJiri Olsa 	bool (*is_compressed)(const char *input);
202c00c48fcSNamhyung Kim } compressions[] = {
2034b838b0dSJiri Olsa 	[COMP_ID__NONE] = { .fmt = NULL, },
204e92ce12eSNamhyung Kim #ifdef HAVE_ZLIB_SUPPORT
2058b42b7e5SJiri Olsa 	{ "gz", gzip_decompress_to_file, gzip_is_compressed },
206e92ce12eSNamhyung Kim #endif
20780a32e5bSJiri Olsa #ifdef HAVE_LZMA_SUPPORT
2088b42b7e5SJiri Olsa 	{ "xz", lzma_decompress_to_file, lzma_is_compressed },
20980a32e5bSJiri Olsa #endif
2108b42b7e5SJiri Olsa 	{ NULL, NULL, NULL },
211c00c48fcSNamhyung Kim };
212c00c48fcSNamhyung Kim 
2134b838b0dSJiri Olsa static int is_supported_compression(const char *ext)
214c00c48fcSNamhyung Kim {
215c00c48fcSNamhyung Kim 	unsigned i;
216c00c48fcSNamhyung Kim 
2174b838b0dSJiri Olsa 	for (i = 1; compressions[i].fmt; i++) {
218c00c48fcSNamhyung Kim 		if (!strcmp(ext, compressions[i].fmt))
2194b838b0dSJiri Olsa 			return i;
220c00c48fcSNamhyung Kim 	}
2214b838b0dSJiri Olsa 	return COMP_ID__NONE;
222c00c48fcSNamhyung Kim }
223c00c48fcSNamhyung Kim 
2241f121b03SWang Nan bool is_kernel_module(const char *pathname, int cpumode)
225c00c48fcSNamhyung Kim {
2268dee9ff1SJiri Olsa 	struct kmod_path m;
2271f121b03SWang Nan 	int mode = cpumode & PERF_RECORD_MISC_CPUMODE_MASK;
228c00c48fcSNamhyung Kim 
2291f121b03SWang Nan 	WARN_ONCE(mode != cpumode,
2301f121b03SWang Nan 		  "Internal error: passing unmasked cpumode (%x) to is_kernel_module",
2311f121b03SWang Nan 		  cpumode);
2321f121b03SWang Nan 
2331f121b03SWang Nan 	switch (mode) {
2341f121b03SWang Nan 	case PERF_RECORD_MISC_USER:
2351f121b03SWang Nan 	case PERF_RECORD_MISC_HYPERVISOR:
2361f121b03SWang Nan 	case PERF_RECORD_MISC_GUEST_USER:
2371f121b03SWang Nan 		return false;
2381f121b03SWang Nan 	/* Treat PERF_RECORD_MISC_CPUMODE_UNKNOWN as kernel */
2391f121b03SWang Nan 	default:
2401f121b03SWang Nan 		if (kmod_path__parse(&m, pathname)) {
2411f121b03SWang Nan 			pr_err("Failed to check whether %s is a kernel module or not. Assume it is.",
2421f121b03SWang Nan 					pathname);
2431f121b03SWang Nan 			return true;
2441f121b03SWang Nan 		}
2451f121b03SWang Nan 	}
246c00c48fcSNamhyung Kim 
2478dee9ff1SJiri Olsa 	return m.kmod;
248c00c48fcSNamhyung Kim }
249c00c48fcSNamhyung Kim 
250c00c48fcSNamhyung Kim bool dso__needs_decompress(struct dso *dso)
251c00c48fcSNamhyung Kim {
252c00c48fcSNamhyung Kim 	return dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP ||
253c00c48fcSNamhyung Kim 		dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE_COMP;
254c00c48fcSNamhyung Kim }
255c00c48fcSNamhyung Kim 
256c9a8a613SJiri Olsa static int decompress_kmodule(struct dso *dso, const char *name,
257c9a8a613SJiri Olsa 			      char *pathname, size_t len)
25842b3fa67SNamhyung Kim {
259c9a8a613SJiri Olsa 	char tmpbuf[] = KMOD_DECOMP_NAME;
26042b3fa67SNamhyung Kim 	int fd = -1;
26142b3fa67SNamhyung Kim 
26242b3fa67SNamhyung Kim 	if (!dso__needs_decompress(dso))
26342b3fa67SNamhyung Kim 		return -1;
26442b3fa67SNamhyung Kim 
265dde755a9SJiri Olsa 	if (dso->comp == COMP_ID__NONE)
26642b3fa67SNamhyung Kim 		return -1;
26742b3fa67SNamhyung Kim 
2688b42b7e5SJiri Olsa 	/*
2698b42b7e5SJiri Olsa 	 * We have proper compression id for DSO and yet the file
2708b42b7e5SJiri Olsa 	 * behind the 'name' can still be plain uncompressed object.
2718b42b7e5SJiri Olsa 	 *
2728b42b7e5SJiri Olsa 	 * The reason is behind the logic we open the DSO object files,
2738b42b7e5SJiri Olsa 	 * when we try all possible 'debug' objects until we find the
2748b42b7e5SJiri Olsa 	 * data. So even if the DSO is represented by 'krava.xz' module,
2758b42b7e5SJiri Olsa 	 * we can end up here opening ~/.debug/....23432432/debug' file
2768b42b7e5SJiri Olsa 	 * which is not compressed.
2778b42b7e5SJiri Olsa 	 *
2788b42b7e5SJiri Olsa 	 * To keep this transparent, we detect this and return the file
2798b42b7e5SJiri Olsa 	 * descriptor to the uncompressed file.
2808b42b7e5SJiri Olsa 	 */
2818b42b7e5SJiri Olsa 	if (!compressions[dso->comp].is_compressed(name))
2828b42b7e5SJiri Olsa 		return open(name, O_RDONLY);
2838b42b7e5SJiri Olsa 
28442b3fa67SNamhyung Kim 	fd = mkstemp(tmpbuf);
28542b3fa67SNamhyung Kim 	if (fd < 0) {
28642b3fa67SNamhyung Kim 		dso->load_errno = errno;
287dde755a9SJiri Olsa 		return -1;
28842b3fa67SNamhyung Kim 	}
28942b3fa67SNamhyung Kim 
290dde755a9SJiri Olsa 	if (compressions[dso->comp].decompress(name, fd)) {
29142b3fa67SNamhyung Kim 		dso->load_errno = DSO_LOAD_ERRNO__DECOMPRESSION_FAILURE;
29242b3fa67SNamhyung Kim 		close(fd);
29342b3fa67SNamhyung Kim 		fd = -1;
29442b3fa67SNamhyung Kim 	}
29542b3fa67SNamhyung Kim 
296c9a8a613SJiri Olsa 	if (!pathname || (fd < 0))
297c9a8a613SJiri Olsa 		unlink(tmpbuf);
298c9a8a613SJiri Olsa 
299c9a8a613SJiri Olsa 	if (pathname && (fd >= 0))
300fca5085cSArnaldo Carvalho de Melo 		strlcpy(pathname, tmpbuf, len);
301c9a8a613SJiri Olsa 
30242b3fa67SNamhyung Kim 	return fd;
30342b3fa67SNamhyung Kim }
30442b3fa67SNamhyung Kim 
30542b3fa67SNamhyung Kim int dso__decompress_kmodule_fd(struct dso *dso, const char *name)
30642b3fa67SNamhyung Kim {
307c9a8a613SJiri Olsa 	return decompress_kmodule(dso, name, NULL, 0);
30842b3fa67SNamhyung Kim }
30942b3fa67SNamhyung Kim 
31042b3fa67SNamhyung Kim int dso__decompress_kmodule_path(struct dso *dso, const char *name,
31142b3fa67SNamhyung Kim 				 char *pathname, size_t len)
31242b3fa67SNamhyung Kim {
313c9a8a613SJiri Olsa 	int fd = decompress_kmodule(dso, name, pathname, len);
31442b3fa67SNamhyung Kim 
31542b3fa67SNamhyung Kim 	close(fd);
316c9a8a613SJiri Olsa 	return fd >= 0 ? 0 : -1;
31742b3fa67SNamhyung Kim }
31842b3fa67SNamhyung Kim 
319eba5102dSJiri Olsa /*
3203c8a67f5SJiri Olsa  * Parses kernel module specified in @path and updates
3213c8a67f5SJiri Olsa  * @m argument like:
3223c8a67f5SJiri Olsa  *
3233c8a67f5SJiri Olsa  *    @comp - true if @path contains supported compression suffix,
3243c8a67f5SJiri Olsa  *            false otherwise
3253c8a67f5SJiri Olsa  *    @kmod - true if @path contains '.ko' suffix in right position,
3263c8a67f5SJiri Olsa  *            false otherwise
3273c8a67f5SJiri Olsa  *    @name - if (@alloc_name && @kmod) is true, it contains strdup-ed base name
3283c8a67f5SJiri Olsa  *            of the kernel module without suffixes, otherwise strudup-ed
3293c8a67f5SJiri Olsa  *            base name of @path
3303c8a67f5SJiri Olsa  *    @ext  - if (@alloc_ext && @comp) is true, it contains strdup-ed string
3313c8a67f5SJiri Olsa  *            the compression suffix
3323c8a67f5SJiri Olsa  *
3333c8a67f5SJiri Olsa  * Returns 0 if there's no strdup error, -ENOMEM otherwise.
3343c8a67f5SJiri Olsa  */
3353c8a67f5SJiri Olsa int __kmod_path__parse(struct kmod_path *m, const char *path,
336b946cd37SJiri Olsa 		       bool alloc_name)
3373c8a67f5SJiri Olsa {
3383c8a67f5SJiri Olsa 	const char *name = strrchr(path, '/');
3393c8a67f5SJiri Olsa 	const char *ext  = strrchr(path, '.');
3401f121b03SWang Nan 	bool is_simple_name = false;
3413c8a67f5SJiri Olsa 
3423c8a67f5SJiri Olsa 	memset(m, 0x0, sizeof(*m));
3433c8a67f5SJiri Olsa 	name = name ? name + 1 : path;
3443c8a67f5SJiri Olsa 
3451f121b03SWang Nan 	/*
3461f121b03SWang Nan 	 * '.' is also a valid character for module name. For example:
3471f121b03SWang Nan 	 * [aaa.bbb] is a valid module name. '[' should have higher
3481f121b03SWang Nan 	 * priority than '.ko' suffix.
3491f121b03SWang Nan 	 *
3501f121b03SWang Nan 	 * The kernel names are from machine__mmap_name. Such
3511f121b03SWang Nan 	 * name should belong to kernel itself, not kernel module.
3521f121b03SWang Nan 	 */
3531f121b03SWang Nan 	if (name[0] == '[') {
3541f121b03SWang Nan 		is_simple_name = true;
3551f121b03SWang Nan 		if ((strncmp(name, "[kernel.kallsyms]", 17) == 0) ||
3561f121b03SWang Nan 		    (strncmp(name, "[guest.kernel.kallsyms", 22) == 0) ||
3571f121b03SWang Nan 		    (strncmp(name, "[vdso]", 6) == 0) ||
358aef4feacSAdrian Hunter 		    (strncmp(name, "[vdso32]", 8) == 0) ||
359aef4feacSAdrian Hunter 		    (strncmp(name, "[vdsox32]", 9) == 0) ||
3601f121b03SWang Nan 		    (strncmp(name, "[vsyscall]", 10) == 0)) {
3611f121b03SWang Nan 			m->kmod = false;
3621f121b03SWang Nan 
3631f121b03SWang Nan 		} else
3641f121b03SWang Nan 			m->kmod = true;
3651f121b03SWang Nan 	}
3661f121b03SWang Nan 
3673c8a67f5SJiri Olsa 	/* No extension, just return name. */
3681f121b03SWang Nan 	if ((ext == NULL) || is_simple_name) {
3693c8a67f5SJiri Olsa 		if (alloc_name) {
3703c8a67f5SJiri Olsa 			m->name = strdup(name);
3713c8a67f5SJiri Olsa 			return m->name ? 0 : -ENOMEM;
3723c8a67f5SJiri Olsa 		}
3733c8a67f5SJiri Olsa 		return 0;
3743c8a67f5SJiri Olsa 	}
3753c8a67f5SJiri Olsa 
3764b838b0dSJiri Olsa 	m->comp = is_supported_compression(ext + 1);
3774b838b0dSJiri Olsa 	if (m->comp > COMP_ID__NONE)
3783c8a67f5SJiri Olsa 		ext -= 3;
3793c8a67f5SJiri Olsa 
3803c8a67f5SJiri Olsa 	/* Check .ko extension only if there's enough name left. */
3813c8a67f5SJiri Olsa 	if (ext > name)
3823c8a67f5SJiri Olsa 		m->kmod = !strncmp(ext, ".ko", 3);
3833c8a67f5SJiri Olsa 
3843c8a67f5SJiri Olsa 	if (alloc_name) {
3853c8a67f5SJiri Olsa 		if (m->kmod) {
3863c8a67f5SJiri Olsa 			if (asprintf(&m->name, "[%.*s]", (int) (ext - name), name) == -1)
3873c8a67f5SJiri Olsa 				return -ENOMEM;
3883c8a67f5SJiri Olsa 		} else {
3893c8a67f5SJiri Olsa 			if (asprintf(&m->name, "%s", name) == -1)
3903c8a67f5SJiri Olsa 				return -ENOMEM;
3913c8a67f5SJiri Olsa 		}
3923c8a67f5SJiri Olsa 
3933c8a67f5SJiri Olsa 		strxfrchar(m->name, '-', '_');
3943c8a67f5SJiri Olsa 	}
3953c8a67f5SJiri Olsa 
3963c8a67f5SJiri Olsa 	return 0;
3973c8a67f5SJiri Olsa }
3983c8a67f5SJiri Olsa 
3996b335e8fSNamhyung Kim void dso__set_module_info(struct dso *dso, struct kmod_path *m,
4006b335e8fSNamhyung Kim 			  struct machine *machine)
4016b335e8fSNamhyung Kim {
4026b335e8fSNamhyung Kim 	if (machine__is_host(machine))
4036b335e8fSNamhyung Kim 		dso->symtab_type = DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE;
4046b335e8fSNamhyung Kim 	else
4056b335e8fSNamhyung Kim 		dso->symtab_type = DSO_BINARY_TYPE__GUEST_KMODULE;
4066b335e8fSNamhyung Kim 
4076b335e8fSNamhyung Kim 	/* _KMODULE_COMP should be next to _KMODULE */
4082af52475SJiri Olsa 	if (m->kmod && m->comp) {
4096b335e8fSNamhyung Kim 		dso->symtab_type++;
4102af52475SJiri Olsa 		dso->comp = m->comp;
4112af52475SJiri Olsa 	}
4126b335e8fSNamhyung Kim 
4136b335e8fSNamhyung Kim 	dso__set_short_name(dso, strdup(m->name), true);
4146b335e8fSNamhyung Kim }
4156b335e8fSNamhyung Kim 
4163c8a67f5SJiri Olsa /*
417bda6ee4aSJiri Olsa  * Global list of open DSOs and the counter.
418eba5102dSJiri Olsa  */
419eba5102dSJiri Olsa static LIST_HEAD(dso__data_open);
420bda6ee4aSJiri Olsa static long dso__data_open_cnt;
42133bdedceSNamhyung Kim static pthread_mutex_t dso__data_open_lock = PTHREAD_MUTEX_INITIALIZER;
422eba5102dSJiri Olsa 
423eba5102dSJiri Olsa static void dso__list_add(struct dso *dso)
424eba5102dSJiri Olsa {
425eba5102dSJiri Olsa 	list_add_tail(&dso->data.open_entry, &dso__data_open);
426bda6ee4aSJiri Olsa 	dso__data_open_cnt++;
427eba5102dSJiri Olsa }
428eba5102dSJiri Olsa 
429eba5102dSJiri Olsa static void dso__list_del(struct dso *dso)
430eba5102dSJiri Olsa {
431eba5102dSJiri Olsa 	list_del(&dso->data.open_entry);
432bda6ee4aSJiri Olsa 	WARN_ONCE(dso__data_open_cnt <= 0,
433bda6ee4aSJiri Olsa 		  "DSO data fd counter out of bounds.");
434bda6ee4aSJiri Olsa 	dso__data_open_cnt--;
435eba5102dSJiri Olsa }
436eba5102dSJiri Olsa 
437a08cae03SJiri Olsa static void close_first_dso(void);
438a08cae03SJiri Olsa 
439a08cae03SJiri Olsa static int do_open(char *name)
440a08cae03SJiri Olsa {
441a08cae03SJiri Olsa 	int fd;
4426e81c74cSMasami Hiramatsu 	char sbuf[STRERR_BUFSIZE];
443a08cae03SJiri Olsa 
444a08cae03SJiri Olsa 	do {
4454c0d8d27SWang YanQing 		fd = open(name, O_RDONLY|O_CLOEXEC);
446a08cae03SJiri Olsa 		if (fd >= 0)
447a08cae03SJiri Olsa 			return fd;
448a08cae03SJiri Olsa 
449a3c0cc2aSNamhyung Kim 		pr_debug("dso open failed: %s\n",
450c8b5f2c9SArnaldo Carvalho de Melo 			 str_error_r(errno, sbuf, sizeof(sbuf)));
451a08cae03SJiri Olsa 		if (!dso__data_open_cnt || errno != EMFILE)
452a08cae03SJiri Olsa 			break;
453a08cae03SJiri Olsa 
454a08cae03SJiri Olsa 		close_first_dso();
455a08cae03SJiri Olsa 	} while (1);
456a08cae03SJiri Olsa 
457a08cae03SJiri Olsa 	return -1;
458a08cae03SJiri Olsa }
459a08cae03SJiri Olsa 
460eba5102dSJiri Olsa static int __open_dso(struct dso *dso, struct machine *machine)
461cdd059d7SJiri Olsa {
4628ba29adfSNamhyung Kim 	int fd = -EINVAL;
463ee4e9625SArnaldo Carvalho de Melo 	char *root_dir = (char *)"";
464ee4e9625SArnaldo Carvalho de Melo 	char *name = malloc(PATH_MAX);
465d68a29c2SJiri Olsa 	bool decomp = false;
466cdd059d7SJiri Olsa 
467cdd059d7SJiri Olsa 	if (!name)
468cdd059d7SJiri Olsa 		return -ENOMEM;
469cdd059d7SJiri Olsa 
470cdd059d7SJiri Olsa 	if (machine)
471cdd059d7SJiri Olsa 		root_dir = machine->root_dir;
472cdd059d7SJiri Olsa 
4735f70619dSArnaldo Carvalho de Melo 	if (dso__read_binary_type_filename(dso, dso->binary_type,
4748ba29adfSNamhyung Kim 					    root_dir, name, PATH_MAX))
4758ba29adfSNamhyung Kim 		goto out;
476cdd059d7SJiri Olsa 
4778ba29adfSNamhyung Kim 	if (!is_regular_file(name))
4788ba29adfSNamhyung Kim 		goto out;
4793c028a0cSJiri Olsa 
4801d6b3c9bSNamhyung Kim 	if (dso__needs_decompress(dso)) {
4811d6b3c9bSNamhyung Kim 		char newpath[KMOD_DECOMP_LEN];
4821d6b3c9bSNamhyung Kim 		size_t len = sizeof(newpath);
4831d6b3c9bSNamhyung Kim 
4841d6b3c9bSNamhyung Kim 		if (dso__decompress_kmodule_path(dso, name, newpath, len) < 0) {
4858ba29adfSNamhyung Kim 			fd = -dso->load_errno;
4868ba29adfSNamhyung Kim 			goto out;
4871d6b3c9bSNamhyung Kim 		}
4881d6b3c9bSNamhyung Kim 
489d68a29c2SJiri Olsa 		decomp = true;
4901d6b3c9bSNamhyung Kim 		strcpy(name, newpath);
4911d6b3c9bSNamhyung Kim 	}
4921d6b3c9bSNamhyung Kim 
493a08cae03SJiri Olsa 	fd = do_open(name);
4941d6b3c9bSNamhyung Kim 
495d68a29c2SJiri Olsa 	if (decomp)
4961d6b3c9bSNamhyung Kim 		unlink(name);
4971d6b3c9bSNamhyung Kim 
4988ba29adfSNamhyung Kim out:
499cdd059d7SJiri Olsa 	free(name);
500cdd059d7SJiri Olsa 	return fd;
501cdd059d7SJiri Olsa }
502cdd059d7SJiri Olsa 
503c6580451SJiri Olsa static void check_data_close(void);
504c6580451SJiri Olsa 
505c1f9aa0aSJiri Olsa /**
506c1f9aa0aSJiri Olsa  * dso_close - Open DSO data file
507c1f9aa0aSJiri Olsa  * @dso: dso object
508c1f9aa0aSJiri Olsa  *
509c1f9aa0aSJiri Olsa  * Open @dso's data file descriptor and updates
510c1f9aa0aSJiri Olsa  * list/count of open DSO objects.
511c1f9aa0aSJiri Olsa  */
512eba5102dSJiri Olsa static int open_dso(struct dso *dso, struct machine *machine)
513eba5102dSJiri Olsa {
514f045b8c4SKrister Johansen 	int fd;
515f045b8c4SKrister Johansen 	struct nscookie nsc;
516f045b8c4SKrister Johansen 
517f045b8c4SKrister Johansen 	if (dso->binary_type != DSO_BINARY_TYPE__BUILD_ID_CACHE)
518f045b8c4SKrister Johansen 		nsinfo__mountns_enter(dso->nsinfo, &nsc);
519f045b8c4SKrister Johansen 	fd = __open_dso(dso, machine);
520f045b8c4SKrister Johansen 	if (dso->binary_type != DSO_BINARY_TYPE__BUILD_ID_CACHE)
521f045b8c4SKrister Johansen 		nsinfo__mountns_exit(&nsc);
522eba5102dSJiri Olsa 
523a6f6ae99SAdrian Hunter 	if (fd >= 0) {
524eba5102dSJiri Olsa 		dso__list_add(dso);
525c6580451SJiri Olsa 		/*
526c6580451SJiri Olsa 		 * Check if we crossed the allowed number
527c6580451SJiri Olsa 		 * of opened DSOs and close one if needed.
528c6580451SJiri Olsa 		 */
529c6580451SJiri Olsa 		check_data_close();
530c6580451SJiri Olsa 	}
531eba5102dSJiri Olsa 
532eba5102dSJiri Olsa 	return fd;
533eba5102dSJiri Olsa }
534eba5102dSJiri Olsa 
535eba5102dSJiri Olsa static void close_data_fd(struct dso *dso)
53653fa8eaaSJiri Olsa {
53753fa8eaaSJiri Olsa 	if (dso->data.fd >= 0) {
53853fa8eaaSJiri Olsa 		close(dso->data.fd);
53953fa8eaaSJiri Olsa 		dso->data.fd = -1;
540c3fbd2a6SJiri Olsa 		dso->data.file_size = 0;
541eba5102dSJiri Olsa 		dso__list_del(dso);
54253fa8eaaSJiri Olsa 	}
54353fa8eaaSJiri Olsa }
54453fa8eaaSJiri Olsa 
545c1f9aa0aSJiri Olsa /**
546c1f9aa0aSJiri Olsa  * dso_close - Close DSO data file
547c1f9aa0aSJiri Olsa  * @dso: dso object
548c1f9aa0aSJiri Olsa  *
549c1f9aa0aSJiri Olsa  * Close @dso's data file descriptor and updates
550c1f9aa0aSJiri Olsa  * list/count of open DSO objects.
551c1f9aa0aSJiri Olsa  */
552eba5102dSJiri Olsa static void close_dso(struct dso *dso)
553eba5102dSJiri Olsa {
554eba5102dSJiri Olsa 	close_data_fd(dso);
555eba5102dSJiri Olsa }
556eba5102dSJiri Olsa 
557c6580451SJiri Olsa static void close_first_dso(void)
558c6580451SJiri Olsa {
559c6580451SJiri Olsa 	struct dso *dso;
560c6580451SJiri Olsa 
561c6580451SJiri Olsa 	dso = list_first_entry(&dso__data_open, struct dso, data.open_entry);
562c6580451SJiri Olsa 	close_dso(dso);
563c6580451SJiri Olsa }
564c6580451SJiri Olsa 
565c6580451SJiri Olsa static rlim_t get_fd_limit(void)
566c6580451SJiri Olsa {
567c6580451SJiri Olsa 	struct rlimit l;
568c6580451SJiri Olsa 	rlim_t limit = 0;
569c6580451SJiri Olsa 
570c6580451SJiri Olsa 	/* Allow half of the current open fd limit. */
571c6580451SJiri Olsa 	if (getrlimit(RLIMIT_NOFILE, &l) == 0) {
572c6580451SJiri Olsa 		if (l.rlim_cur == RLIM_INFINITY)
573c6580451SJiri Olsa 			limit = l.rlim_cur;
574c6580451SJiri Olsa 		else
575c6580451SJiri Olsa 			limit = l.rlim_cur / 2;
576c6580451SJiri Olsa 	} else {
577c6580451SJiri Olsa 		pr_err("failed to get fd limit\n");
578c6580451SJiri Olsa 		limit = 1;
579c6580451SJiri Olsa 	}
580c6580451SJiri Olsa 
581c6580451SJiri Olsa 	return limit;
582c6580451SJiri Olsa }
583c6580451SJiri Olsa 
584f3069249SJiri Olsa static rlim_t fd_limit;
585f3069249SJiri Olsa 
586f3069249SJiri Olsa /*
587f3069249SJiri Olsa  * Used only by tests/dso-data.c to reset the environment
588f3069249SJiri Olsa  * for tests. I dont expect we should change this during
589f3069249SJiri Olsa  * standard runtime.
590f3069249SJiri Olsa  */
591f3069249SJiri Olsa void reset_fd_limit(void)
592f3069249SJiri Olsa {
593f3069249SJiri Olsa 	fd_limit = 0;
594f3069249SJiri Olsa }
595f3069249SJiri Olsa 
596c6580451SJiri Olsa static bool may_cache_fd(void)
597c6580451SJiri Olsa {
598f3069249SJiri Olsa 	if (!fd_limit)
599f3069249SJiri Olsa 		fd_limit = get_fd_limit();
600c6580451SJiri Olsa 
601f3069249SJiri Olsa 	if (fd_limit == RLIM_INFINITY)
602c6580451SJiri Olsa 		return true;
603c6580451SJiri Olsa 
604f3069249SJiri Olsa 	return fd_limit > (rlim_t) dso__data_open_cnt;
605c6580451SJiri Olsa }
606c6580451SJiri Olsa 
607c1f9aa0aSJiri Olsa /*
608c1f9aa0aSJiri Olsa  * Check and close LRU dso if we crossed allowed limit
609c1f9aa0aSJiri Olsa  * for opened dso file descriptors. The limit is half
610c1f9aa0aSJiri Olsa  * of the RLIMIT_NOFILE files opened.
611c1f9aa0aSJiri Olsa */
612c6580451SJiri Olsa static void check_data_close(void)
613c6580451SJiri Olsa {
614c6580451SJiri Olsa 	bool cache_fd = may_cache_fd();
615c6580451SJiri Olsa 
616c6580451SJiri Olsa 	if (!cache_fd)
617c6580451SJiri Olsa 		close_first_dso();
618c6580451SJiri Olsa }
619c6580451SJiri Olsa 
620c1f9aa0aSJiri Olsa /**
621c1f9aa0aSJiri Olsa  * dso__data_close - Close DSO data file
622c1f9aa0aSJiri Olsa  * @dso: dso object
623c1f9aa0aSJiri Olsa  *
624c1f9aa0aSJiri Olsa  * External interface to close @dso's data file descriptor.
625c1f9aa0aSJiri Olsa  */
626eba5102dSJiri Olsa void dso__data_close(struct dso *dso)
627eba5102dSJiri Olsa {
62833bdedceSNamhyung Kim 	pthread_mutex_lock(&dso__data_open_lock);
629eba5102dSJiri Olsa 	close_dso(dso);
63033bdedceSNamhyung Kim 	pthread_mutex_unlock(&dso__data_open_lock);
631eba5102dSJiri Olsa }
632eba5102dSJiri Olsa 
63371ff824aSNamhyung Kim static void try_to_open_dso(struct dso *dso, struct machine *machine)
634cdd059d7SJiri Olsa {
635631d34b5SArnaldo Carvalho de Melo 	enum dso_binary_type binary_type_data[] = {
636cdd059d7SJiri Olsa 		DSO_BINARY_TYPE__BUILD_ID_CACHE,
637cdd059d7SJiri Olsa 		DSO_BINARY_TYPE__SYSTEM_PATH_DSO,
638cdd059d7SJiri Olsa 		DSO_BINARY_TYPE__NOT_FOUND,
639cdd059d7SJiri Olsa 	};
640cdd059d7SJiri Olsa 	int i = 0;
641cdd059d7SJiri Olsa 
64253fa8eaaSJiri Olsa 	if (dso->data.fd >= 0)
64371ff824aSNamhyung Kim 		return;
64453fa8eaaSJiri Olsa 
64553fa8eaaSJiri Olsa 	if (dso->binary_type != DSO_BINARY_TYPE__NOT_FOUND) {
64653fa8eaaSJiri Olsa 		dso->data.fd = open_dso(dso, machine);
647c27697d6SAdrian Hunter 		goto out;
64853fa8eaaSJiri Olsa 	}
649cdd059d7SJiri Olsa 
650cdd059d7SJiri Olsa 	do {
6515f70619dSArnaldo Carvalho de Melo 		dso->binary_type = binary_type_data[i++];
652cdd059d7SJiri Olsa 
653c27697d6SAdrian Hunter 		dso->data.fd = open_dso(dso, machine);
654c27697d6SAdrian Hunter 		if (dso->data.fd >= 0)
655c27697d6SAdrian Hunter 			goto out;
656cdd059d7SJiri Olsa 
6575f70619dSArnaldo Carvalho de Melo 	} while (dso->binary_type != DSO_BINARY_TYPE__NOT_FOUND);
658c27697d6SAdrian Hunter out:
659c27697d6SAdrian Hunter 	if (dso->data.fd >= 0)
660c27697d6SAdrian Hunter 		dso->data.status = DSO_DATA_STATUS_OK;
661c27697d6SAdrian Hunter 	else
662c27697d6SAdrian Hunter 		dso->data.status = DSO_DATA_STATUS_ERROR;
66371ff824aSNamhyung Kim }
664cdd059d7SJiri Olsa 
66571ff824aSNamhyung Kim /**
6664bb11d01SNamhyung Kim  * dso__data_get_fd - Get dso's data file descriptor
66771ff824aSNamhyung Kim  * @dso: dso object
66871ff824aSNamhyung Kim  * @machine: machine object
66971ff824aSNamhyung Kim  *
67071ff824aSNamhyung Kim  * External interface to find dso's file, open it and
6714bb11d01SNamhyung Kim  * returns file descriptor.  It should be paired with
6724bb11d01SNamhyung Kim  * dso__data_put_fd() if it returns non-negative value.
67371ff824aSNamhyung Kim  */
6744bb11d01SNamhyung Kim int dso__data_get_fd(struct dso *dso, struct machine *machine)
67571ff824aSNamhyung Kim {
67671ff824aSNamhyung Kim 	if (dso->data.status == DSO_DATA_STATUS_ERROR)
67771ff824aSNamhyung Kim 		return -1;
67871ff824aSNamhyung Kim 
6794bb11d01SNamhyung Kim 	if (pthread_mutex_lock(&dso__data_open_lock) < 0)
6804bb11d01SNamhyung Kim 		return -1;
6814bb11d01SNamhyung Kim 
68271ff824aSNamhyung Kim 	try_to_open_dso(dso, machine);
6834bb11d01SNamhyung Kim 
6844bb11d01SNamhyung Kim 	if (dso->data.fd < 0)
68533bdedceSNamhyung Kim 		pthread_mutex_unlock(&dso__data_open_lock);
68671ff824aSNamhyung Kim 
687c27697d6SAdrian Hunter 	return dso->data.fd;
688cdd059d7SJiri Olsa }
689cdd059d7SJiri Olsa 
6904bb11d01SNamhyung Kim void dso__data_put_fd(struct dso *dso __maybe_unused)
6914bb11d01SNamhyung Kim {
6924bb11d01SNamhyung Kim 	pthread_mutex_unlock(&dso__data_open_lock);
6934bb11d01SNamhyung Kim }
6944bb11d01SNamhyung Kim 
695288be943SAdrian Hunter bool dso__data_status_seen(struct dso *dso, enum dso_data_status_seen by)
696288be943SAdrian Hunter {
697288be943SAdrian Hunter 	u32 flag = 1 << by;
698288be943SAdrian Hunter 
699288be943SAdrian Hunter 	if (dso->data.status_seen & flag)
700288be943SAdrian Hunter 		return true;
701288be943SAdrian Hunter 
702288be943SAdrian Hunter 	dso->data.status_seen |= flag;
703288be943SAdrian Hunter 
704288be943SAdrian Hunter 	return false;
705288be943SAdrian Hunter }
706288be943SAdrian Hunter 
707cdd059d7SJiri Olsa static void
7088e67b725SNamhyung Kim dso_cache__free(struct dso *dso)
709cdd059d7SJiri Olsa {
7108e67b725SNamhyung Kim 	struct rb_root *root = &dso->data.cache;
711cdd059d7SJiri Olsa 	struct rb_node *next = rb_first(root);
712cdd059d7SJiri Olsa 
7138e67b725SNamhyung Kim 	pthread_mutex_lock(&dso->lock);
714cdd059d7SJiri Olsa 	while (next) {
715cdd059d7SJiri Olsa 		struct dso_cache *cache;
716cdd059d7SJiri Olsa 
717cdd059d7SJiri Olsa 		cache = rb_entry(next, struct dso_cache, rb_node);
718cdd059d7SJiri Olsa 		next = rb_next(&cache->rb_node);
719cdd059d7SJiri Olsa 		rb_erase(&cache->rb_node, root);
720cdd059d7SJiri Olsa 		free(cache);
721cdd059d7SJiri Olsa 	}
7228e67b725SNamhyung Kim 	pthread_mutex_unlock(&dso->lock);
723cdd059d7SJiri Olsa }
724cdd059d7SJiri Olsa 
7258e67b725SNamhyung Kim static struct dso_cache *dso_cache__find(struct dso *dso, u64 offset)
726cdd059d7SJiri Olsa {
7278e67b725SNamhyung Kim 	const struct rb_root *root = &dso->data.cache;
7283344996eSArnaldo Carvalho de Melo 	struct rb_node * const *p = &root->rb_node;
7293344996eSArnaldo Carvalho de Melo 	const struct rb_node *parent = NULL;
730cdd059d7SJiri Olsa 	struct dso_cache *cache;
731cdd059d7SJiri Olsa 
732cdd059d7SJiri Olsa 	while (*p != NULL) {
733cdd059d7SJiri Olsa 		u64 end;
734cdd059d7SJiri Olsa 
735cdd059d7SJiri Olsa 		parent = *p;
736cdd059d7SJiri Olsa 		cache = rb_entry(parent, struct dso_cache, rb_node);
737cdd059d7SJiri Olsa 		end = cache->offset + DSO__DATA_CACHE_SIZE;
738cdd059d7SJiri Olsa 
739cdd059d7SJiri Olsa 		if (offset < cache->offset)
740cdd059d7SJiri Olsa 			p = &(*p)->rb_left;
741cdd059d7SJiri Olsa 		else if (offset >= end)
742cdd059d7SJiri Olsa 			p = &(*p)->rb_right;
743cdd059d7SJiri Olsa 		else
744cdd059d7SJiri Olsa 			return cache;
745cdd059d7SJiri Olsa 	}
7468e67b725SNamhyung Kim 
747cdd059d7SJiri Olsa 	return NULL;
748cdd059d7SJiri Olsa }
749cdd059d7SJiri Olsa 
7508e67b725SNamhyung Kim static struct dso_cache *
7518e67b725SNamhyung Kim dso_cache__insert(struct dso *dso, struct dso_cache *new)
752cdd059d7SJiri Olsa {
7538e67b725SNamhyung Kim 	struct rb_root *root = &dso->data.cache;
754cdd059d7SJiri Olsa 	struct rb_node **p = &root->rb_node;
755cdd059d7SJiri Olsa 	struct rb_node *parent = NULL;
756cdd059d7SJiri Olsa 	struct dso_cache *cache;
757cdd059d7SJiri Olsa 	u64 offset = new->offset;
758cdd059d7SJiri Olsa 
7598e67b725SNamhyung Kim 	pthread_mutex_lock(&dso->lock);
760cdd059d7SJiri Olsa 	while (*p != NULL) {
761cdd059d7SJiri Olsa 		u64 end;
762cdd059d7SJiri Olsa 
763cdd059d7SJiri Olsa 		parent = *p;
764cdd059d7SJiri Olsa 		cache = rb_entry(parent, struct dso_cache, rb_node);
765cdd059d7SJiri Olsa 		end = cache->offset + DSO__DATA_CACHE_SIZE;
766cdd059d7SJiri Olsa 
767cdd059d7SJiri Olsa 		if (offset < cache->offset)
768cdd059d7SJiri Olsa 			p = &(*p)->rb_left;
769cdd059d7SJiri Olsa 		else if (offset >= end)
770cdd059d7SJiri Olsa 			p = &(*p)->rb_right;
7718e67b725SNamhyung Kim 		else
7728e67b725SNamhyung Kim 			goto out;
773cdd059d7SJiri Olsa 	}
774cdd059d7SJiri Olsa 
775cdd059d7SJiri Olsa 	rb_link_node(&new->rb_node, parent, p);
776cdd059d7SJiri Olsa 	rb_insert_color(&new->rb_node, root);
7778e67b725SNamhyung Kim 
7788e67b725SNamhyung Kim 	cache = NULL;
7798e67b725SNamhyung Kim out:
7808e67b725SNamhyung Kim 	pthread_mutex_unlock(&dso->lock);
7818e67b725SNamhyung Kim 	return cache;
782cdd059d7SJiri Olsa }
783cdd059d7SJiri Olsa 
784cdd059d7SJiri Olsa static ssize_t
785cdd059d7SJiri Olsa dso_cache__memcpy(struct dso_cache *cache, u64 offset,
786cdd059d7SJiri Olsa 		  u8 *data, u64 size)
787cdd059d7SJiri Olsa {
788cdd059d7SJiri Olsa 	u64 cache_offset = offset - cache->offset;
789cdd059d7SJiri Olsa 	u64 cache_size   = min(cache->size - cache_offset, size);
790cdd059d7SJiri Olsa 
791cdd059d7SJiri Olsa 	memcpy(data, cache->data + cache_offset, cache_size);
792cdd059d7SJiri Olsa 	return cache_size;
793cdd059d7SJiri Olsa }
794cdd059d7SJiri Olsa 
795cdd059d7SJiri Olsa static ssize_t
79633bdedceSNamhyung Kim dso_cache__read(struct dso *dso, struct machine *machine,
79733bdedceSNamhyung Kim 		u64 offset, u8 *data, ssize_t size)
798cdd059d7SJiri Olsa {
799cdd059d7SJiri Olsa 	struct dso_cache *cache;
8008e67b725SNamhyung Kim 	struct dso_cache *old;
801cdd059d7SJiri Olsa 	ssize_t ret;
802cdd059d7SJiri Olsa 
803cdd059d7SJiri Olsa 	do {
804cdd059d7SJiri Olsa 		u64 cache_offset;
805cdd059d7SJiri Olsa 
806cdd059d7SJiri Olsa 		cache = zalloc(sizeof(*cache) + DSO__DATA_CACHE_SIZE);
807cdd059d7SJiri Olsa 		if (!cache)
80833bdedceSNamhyung Kim 			return -ENOMEM;
80933bdedceSNamhyung Kim 
81033bdedceSNamhyung Kim 		pthread_mutex_lock(&dso__data_open_lock);
81133bdedceSNamhyung Kim 
81233bdedceSNamhyung Kim 		/*
81333bdedceSNamhyung Kim 		 * dso->data.fd might be closed if other thread opened another
81433bdedceSNamhyung Kim 		 * file (dso) due to open file limit (RLIMIT_NOFILE).
81533bdedceSNamhyung Kim 		 */
81671ff824aSNamhyung Kim 		try_to_open_dso(dso, machine);
81771ff824aSNamhyung Kim 
81833bdedceSNamhyung Kim 		if (dso->data.fd < 0) {
81933bdedceSNamhyung Kim 			ret = -errno;
82033bdedceSNamhyung Kim 			dso->data.status = DSO_DATA_STATUS_ERROR;
821cdd059d7SJiri Olsa 			break;
82233bdedceSNamhyung Kim 		}
823cdd059d7SJiri Olsa 
824cdd059d7SJiri Olsa 		cache_offset = offset & DSO__DATA_CACHE_MASK;
825cdd059d7SJiri Olsa 
826c52686f9SNamhyung Kim 		ret = pread(dso->data.fd, cache->data, DSO__DATA_CACHE_SIZE, cache_offset);
827cdd059d7SJiri Olsa 		if (ret <= 0)
828cdd059d7SJiri Olsa 			break;
829cdd059d7SJiri Olsa 
830cdd059d7SJiri Olsa 		cache->offset = cache_offset;
831cdd059d7SJiri Olsa 		cache->size   = ret;
83233bdedceSNamhyung Kim 	} while (0);
83333bdedceSNamhyung Kim 
83433bdedceSNamhyung Kim 	pthread_mutex_unlock(&dso__data_open_lock);
83533bdedceSNamhyung Kim 
83633bdedceSNamhyung Kim 	if (ret > 0) {
8378e67b725SNamhyung Kim 		old = dso_cache__insert(dso, cache);
8388e67b725SNamhyung Kim 		if (old) {
8398e67b725SNamhyung Kim 			/* we lose the race */
8408e67b725SNamhyung Kim 			free(cache);
8418e67b725SNamhyung Kim 			cache = old;
8428e67b725SNamhyung Kim 		}
843cdd059d7SJiri Olsa 
844cdd059d7SJiri Olsa 		ret = dso_cache__memcpy(cache, offset, data, size);
84533bdedceSNamhyung Kim 	}
846cdd059d7SJiri Olsa 
847cdd059d7SJiri Olsa 	if (ret <= 0)
848cdd059d7SJiri Olsa 		free(cache);
849cdd059d7SJiri Olsa 
850cdd059d7SJiri Olsa 	return ret;
851cdd059d7SJiri Olsa }
852cdd059d7SJiri Olsa 
85333bdedceSNamhyung Kim static ssize_t dso_cache_read(struct dso *dso, struct machine *machine,
85433bdedceSNamhyung Kim 			      u64 offset, u8 *data, ssize_t size)
855cdd059d7SJiri Olsa {
856cdd059d7SJiri Olsa 	struct dso_cache *cache;
857cdd059d7SJiri Olsa 
8588e67b725SNamhyung Kim 	cache = dso_cache__find(dso, offset);
859cdd059d7SJiri Olsa 	if (cache)
860cdd059d7SJiri Olsa 		return dso_cache__memcpy(cache, offset, data, size);
861cdd059d7SJiri Olsa 	else
86233bdedceSNamhyung Kim 		return dso_cache__read(dso, machine, offset, data, size);
863cdd059d7SJiri Olsa }
864cdd059d7SJiri Olsa 
865c1f9aa0aSJiri Olsa /*
866c1f9aa0aSJiri Olsa  * Reads and caches dso data DSO__DATA_CACHE_SIZE size chunks
867c1f9aa0aSJiri Olsa  * in the rb_tree. Any read to already cached data is served
868c1f9aa0aSJiri Olsa  * by cached data.
869c1f9aa0aSJiri Olsa  */
87033bdedceSNamhyung Kim static ssize_t cached_read(struct dso *dso, struct machine *machine,
87133bdedceSNamhyung Kim 			   u64 offset, u8 *data, ssize_t size)
872cdd059d7SJiri Olsa {
873cdd059d7SJiri Olsa 	ssize_t r = 0;
874cdd059d7SJiri Olsa 	u8 *p = data;
875cdd059d7SJiri Olsa 
876cdd059d7SJiri Olsa 	do {
877cdd059d7SJiri Olsa 		ssize_t ret;
878cdd059d7SJiri Olsa 
87933bdedceSNamhyung Kim 		ret = dso_cache_read(dso, machine, offset, p, size);
880cdd059d7SJiri Olsa 		if (ret < 0)
881cdd059d7SJiri Olsa 			return ret;
882cdd059d7SJiri Olsa 
883cdd059d7SJiri Olsa 		/* Reached EOF, return what we have. */
884cdd059d7SJiri Olsa 		if (!ret)
885cdd059d7SJiri Olsa 			break;
886cdd059d7SJiri Olsa 
887cdd059d7SJiri Olsa 		BUG_ON(ret > size);
888cdd059d7SJiri Olsa 
889cdd059d7SJiri Olsa 		r      += ret;
890cdd059d7SJiri Olsa 		p      += ret;
891cdd059d7SJiri Olsa 		offset += ret;
892cdd059d7SJiri Olsa 		size   -= ret;
893cdd059d7SJiri Olsa 
894cdd059d7SJiri Olsa 	} while (size);
895cdd059d7SJiri Olsa 
896cdd059d7SJiri Olsa 	return r;
897cdd059d7SJiri Olsa }
898cdd059d7SJiri Olsa 
899b5c2161cSAdrian Hunter int dso__data_file_size(struct dso *dso, struct machine *machine)
900c3fbd2a6SJiri Olsa {
90133bdedceSNamhyung Kim 	int ret = 0;
902c3fbd2a6SJiri Olsa 	struct stat st;
9036e81c74cSMasami Hiramatsu 	char sbuf[STRERR_BUFSIZE];
904c3fbd2a6SJiri Olsa 
90533bdedceSNamhyung Kim 	if (dso->data.file_size)
90633bdedceSNamhyung Kim 		return 0;
90733bdedceSNamhyung Kim 
90871ff824aSNamhyung Kim 	if (dso->data.status == DSO_DATA_STATUS_ERROR)
90971ff824aSNamhyung Kim 		return -1;
91071ff824aSNamhyung Kim 
91133bdedceSNamhyung Kim 	pthread_mutex_lock(&dso__data_open_lock);
91233bdedceSNamhyung Kim 
91333bdedceSNamhyung Kim 	/*
91433bdedceSNamhyung Kim 	 * dso->data.fd might be closed if other thread opened another
91533bdedceSNamhyung Kim 	 * file (dso) due to open file limit (RLIMIT_NOFILE).
91633bdedceSNamhyung Kim 	 */
91771ff824aSNamhyung Kim 	try_to_open_dso(dso, machine);
91871ff824aSNamhyung Kim 
91933bdedceSNamhyung Kim 	if (dso->data.fd < 0) {
92033bdedceSNamhyung Kim 		ret = -errno;
92133bdedceSNamhyung Kim 		dso->data.status = DSO_DATA_STATUS_ERROR;
92233bdedceSNamhyung Kim 		goto out;
923c3fbd2a6SJiri Olsa 	}
924c3fbd2a6SJiri Olsa 
92533bdedceSNamhyung Kim 	if (fstat(dso->data.fd, &st) < 0) {
92633bdedceSNamhyung Kim 		ret = -errno;
92733bdedceSNamhyung Kim 		pr_err("dso cache fstat failed: %s\n",
928c8b5f2c9SArnaldo Carvalho de Melo 		       str_error_r(errno, sbuf, sizeof(sbuf)));
92933bdedceSNamhyung Kim 		dso->data.status = DSO_DATA_STATUS_ERROR;
93033bdedceSNamhyung Kim 		goto out;
93133bdedceSNamhyung Kim 	}
93233bdedceSNamhyung Kim 	dso->data.file_size = st.st_size;
93333bdedceSNamhyung Kim 
93433bdedceSNamhyung Kim out:
93533bdedceSNamhyung Kim 	pthread_mutex_unlock(&dso__data_open_lock);
93633bdedceSNamhyung Kim 	return ret;
937c3fbd2a6SJiri Olsa }
938c3fbd2a6SJiri Olsa 
9396d363459SAdrian Hunter /**
9406d363459SAdrian Hunter  * dso__data_size - Return dso data size
9416d363459SAdrian Hunter  * @dso: dso object
9426d363459SAdrian Hunter  * @machine: machine object
9436d363459SAdrian Hunter  *
9446d363459SAdrian Hunter  * Return: dso data size
9456d363459SAdrian Hunter  */
9466d363459SAdrian Hunter off_t dso__data_size(struct dso *dso, struct machine *machine)
9476d363459SAdrian Hunter {
948b5c2161cSAdrian Hunter 	if (dso__data_file_size(dso, machine))
9496d363459SAdrian Hunter 		return -1;
9506d363459SAdrian Hunter 
9516d363459SAdrian Hunter 	/* For now just estimate dso data size is close to file size */
9526d363459SAdrian Hunter 	return dso->data.file_size;
9536d363459SAdrian Hunter }
9546d363459SAdrian Hunter 
95533bdedceSNamhyung Kim static ssize_t data_read_offset(struct dso *dso, struct machine *machine,
95633bdedceSNamhyung Kim 				u64 offset, u8 *data, ssize_t size)
957c3fbd2a6SJiri Olsa {
958b5c2161cSAdrian Hunter 	if (dso__data_file_size(dso, machine))
959c3fbd2a6SJiri Olsa 		return -1;
960c3fbd2a6SJiri Olsa 
961c3fbd2a6SJiri Olsa 	/* Check the offset sanity. */
962c3fbd2a6SJiri Olsa 	if (offset > dso->data.file_size)
963c3fbd2a6SJiri Olsa 		return -1;
964c3fbd2a6SJiri Olsa 
965c3fbd2a6SJiri Olsa 	if (offset + size < offset)
966c3fbd2a6SJiri Olsa 		return -1;
967c3fbd2a6SJiri Olsa 
96833bdedceSNamhyung Kim 	return cached_read(dso, machine, offset, data, size);
969c3fbd2a6SJiri Olsa }
970c3fbd2a6SJiri Olsa 
971c1f9aa0aSJiri Olsa /**
972c1f9aa0aSJiri Olsa  * dso__data_read_offset - Read data from dso file offset
973c1f9aa0aSJiri Olsa  * @dso: dso object
974c1f9aa0aSJiri Olsa  * @machine: machine object
975c1f9aa0aSJiri Olsa  * @offset: file offset
976c1f9aa0aSJiri Olsa  * @data: buffer to store data
977c1f9aa0aSJiri Olsa  * @size: size of the @data buffer
978c1f9aa0aSJiri Olsa  *
979c1f9aa0aSJiri Olsa  * External interface to read data from dso file offset. Open
980c1f9aa0aSJiri Olsa  * dso data file and use cached_read to get the data.
981c1f9aa0aSJiri Olsa  */
982c3fbd2a6SJiri Olsa ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine,
983c3fbd2a6SJiri Olsa 			      u64 offset, u8 *data, ssize_t size)
984c3fbd2a6SJiri Olsa {
98533bdedceSNamhyung Kim 	if (dso->data.status == DSO_DATA_STATUS_ERROR)
986c3fbd2a6SJiri Olsa 		return -1;
987c3fbd2a6SJiri Olsa 
98833bdedceSNamhyung Kim 	return data_read_offset(dso, machine, offset, data, size);
989c3fbd2a6SJiri Olsa }
990c3fbd2a6SJiri Olsa 
991c1f9aa0aSJiri Olsa /**
992c1f9aa0aSJiri Olsa  * dso__data_read_addr - Read data from dso address
993c1f9aa0aSJiri Olsa  * @dso: dso object
994c1f9aa0aSJiri Olsa  * @machine: machine object
995c1f9aa0aSJiri Olsa  * @add: virtual memory address
996c1f9aa0aSJiri Olsa  * @data: buffer to store data
997c1f9aa0aSJiri Olsa  * @size: size of the @data buffer
998c1f9aa0aSJiri Olsa  *
999c1f9aa0aSJiri Olsa  * External interface to read data from dso address.
1000c1f9aa0aSJiri Olsa  */
1001cdd059d7SJiri Olsa ssize_t dso__data_read_addr(struct dso *dso, struct map *map,
1002cdd059d7SJiri Olsa 			    struct machine *machine, u64 addr,
1003cdd059d7SJiri Olsa 			    u8 *data, ssize_t size)
1004cdd059d7SJiri Olsa {
1005cdd059d7SJiri Olsa 	u64 offset = map->map_ip(map, addr);
1006cdd059d7SJiri Olsa 	return dso__data_read_offset(dso, machine, offset, data, size);
1007cdd059d7SJiri Olsa }
1008cdd059d7SJiri Olsa 
1009cdd059d7SJiri Olsa struct map *dso__new_map(const char *name)
1010cdd059d7SJiri Olsa {
1011cdd059d7SJiri Olsa 	struct map *map = NULL;
1012cdd059d7SJiri Olsa 	struct dso *dso = dso__new(name);
1013cdd059d7SJiri Olsa 
1014cdd059d7SJiri Olsa 	if (dso)
10153183f8caSArnaldo Carvalho de Melo 		map = map__new2(0, dso);
1016cdd059d7SJiri Olsa 
1017cdd059d7SJiri Olsa 	return map;
1018cdd059d7SJiri Olsa }
1019cdd059d7SJiri Olsa 
1020459ce518SArnaldo Carvalho de Melo struct dso *machine__findnew_kernel(struct machine *machine, const char *name,
1021cdd059d7SJiri Olsa 				    const char *short_name, int dso_type)
1022cdd059d7SJiri Olsa {
1023cdd059d7SJiri Olsa 	/*
1024cdd059d7SJiri Olsa 	 * The kernel dso could be created by build_id processing.
1025cdd059d7SJiri Olsa 	 */
1026aa7cc2aeSArnaldo Carvalho de Melo 	struct dso *dso = machine__findnew_dso(machine, name);
1027cdd059d7SJiri Olsa 
1028cdd059d7SJiri Olsa 	/*
1029cdd059d7SJiri Olsa 	 * We need to run this in all cases, since during the build_id
1030cdd059d7SJiri Olsa 	 * processing we had no idea this was the kernel dso.
1031cdd059d7SJiri Olsa 	 */
1032cdd059d7SJiri Olsa 	if (dso != NULL) {
103358a98c9cSAdrian Hunter 		dso__set_short_name(dso, short_name, false);
1034cdd059d7SJiri Olsa 		dso->kernel = dso_type;
1035cdd059d7SJiri Olsa 	}
1036cdd059d7SJiri Olsa 
1037cdd059d7SJiri Olsa 	return dso;
1038cdd059d7SJiri Olsa }
1039cdd059d7SJiri Olsa 
10404598a0a6SWaiman Long /*
10414598a0a6SWaiman Long  * Find a matching entry and/or link current entry to RB tree.
10424598a0a6SWaiman Long  * Either one of the dso or name parameter must be non-NULL or the
10434598a0a6SWaiman Long  * function will not work.
10444598a0a6SWaiman Long  */
1045e8807844SArnaldo Carvalho de Melo static struct dso *__dso__findlink_by_longname(struct rb_root *root,
10464598a0a6SWaiman Long 					       struct dso *dso, const char *name)
10474598a0a6SWaiman Long {
10484598a0a6SWaiman Long 	struct rb_node **p = &root->rb_node;
10494598a0a6SWaiman Long 	struct rb_node  *parent = NULL;
10504598a0a6SWaiman Long 
10514598a0a6SWaiman Long 	if (!name)
10524598a0a6SWaiman Long 		name = dso->long_name;
10534598a0a6SWaiman Long 	/*
10544598a0a6SWaiman Long 	 * Find node with the matching name
10554598a0a6SWaiman Long 	 */
10564598a0a6SWaiman Long 	while (*p) {
10574598a0a6SWaiman Long 		struct dso *this = rb_entry(*p, struct dso, rb_node);
10584598a0a6SWaiman Long 		int rc = strcmp(name, this->long_name);
10594598a0a6SWaiman Long 
10604598a0a6SWaiman Long 		parent = *p;
10614598a0a6SWaiman Long 		if (rc == 0) {
10624598a0a6SWaiman Long 			/*
10634598a0a6SWaiman Long 			 * In case the new DSO is a duplicate of an existing
10640f5e1558SMasahiro Yamada 			 * one, print a one-time warning & put the new entry
10654598a0a6SWaiman Long 			 * at the end of the list of duplicates.
10664598a0a6SWaiman Long 			 */
10674598a0a6SWaiman Long 			if (!dso || (dso == this))
10684598a0a6SWaiman Long 				return this;	/* Find matching dso */
10694598a0a6SWaiman Long 			/*
10704598a0a6SWaiman Long 			 * The core kernel DSOs may have duplicated long name.
10714598a0a6SWaiman Long 			 * In this case, the short name should be different.
10724598a0a6SWaiman Long 			 * Comparing the short names to differentiate the DSOs.
10734598a0a6SWaiman Long 			 */
10744598a0a6SWaiman Long 			rc = strcmp(dso->short_name, this->short_name);
10754598a0a6SWaiman Long 			if (rc == 0) {
10764598a0a6SWaiman Long 				pr_err("Duplicated dso name: %s\n", name);
10774598a0a6SWaiman Long 				return NULL;
10784598a0a6SWaiman Long 			}
10794598a0a6SWaiman Long 		}
10804598a0a6SWaiman Long 		if (rc < 0)
10814598a0a6SWaiman Long 			p = &parent->rb_left;
10824598a0a6SWaiman Long 		else
10834598a0a6SWaiman Long 			p = &parent->rb_right;
10844598a0a6SWaiman Long 	}
10854598a0a6SWaiman Long 	if (dso) {
10864598a0a6SWaiman Long 		/* Add new node and rebalance tree */
10874598a0a6SWaiman Long 		rb_link_node(&dso->rb_node, parent, p);
10884598a0a6SWaiman Long 		rb_insert_color(&dso->rb_node, root);
1089e266a753SAdrian Hunter 		dso->root = root;
10904598a0a6SWaiman Long 	}
10914598a0a6SWaiman Long 	return NULL;
10924598a0a6SWaiman Long }
10934598a0a6SWaiman Long 
1094e8807844SArnaldo Carvalho de Melo static inline struct dso *__dso__find_by_longname(struct rb_root *root,
1095e8807844SArnaldo Carvalho de Melo 						  const char *name)
10964598a0a6SWaiman Long {
1097e8807844SArnaldo Carvalho de Melo 	return __dso__findlink_by_longname(root, NULL, name);
10984598a0a6SWaiman Long }
10994598a0a6SWaiman Long 
1100bf4414aeSArnaldo Carvalho de Melo void dso__set_long_name(struct dso *dso, const char *name, bool name_allocated)
1101cdd059d7SJiri Olsa {
1102e266a753SAdrian Hunter 	struct rb_root *root = dso->root;
1103e266a753SAdrian Hunter 
1104cdd059d7SJiri Olsa 	if (name == NULL)
1105cdd059d7SJiri Olsa 		return;
11067e155d4dSArnaldo Carvalho de Melo 
11077e155d4dSArnaldo Carvalho de Melo 	if (dso->long_name_allocated)
1108bf4414aeSArnaldo Carvalho de Melo 		free((char *)dso->long_name);
11097e155d4dSArnaldo Carvalho de Melo 
1110e266a753SAdrian Hunter 	if (root) {
1111e266a753SAdrian Hunter 		rb_erase(&dso->rb_node, root);
1112e266a753SAdrian Hunter 		/*
1113e266a753SAdrian Hunter 		 * __dso__findlink_by_longname() isn't guaranteed to add it
1114e266a753SAdrian Hunter 		 * back, so a clean removal is required here.
1115e266a753SAdrian Hunter 		 */
1116e266a753SAdrian Hunter 		RB_CLEAR_NODE(&dso->rb_node);
1117e266a753SAdrian Hunter 		dso->root = NULL;
1118e266a753SAdrian Hunter 	}
1119e266a753SAdrian Hunter 
1120cdd059d7SJiri Olsa 	dso->long_name		 = name;
1121cdd059d7SJiri Olsa 	dso->long_name_len	 = strlen(name);
11227e155d4dSArnaldo Carvalho de Melo 	dso->long_name_allocated = name_allocated;
1123e266a753SAdrian Hunter 
1124e266a753SAdrian Hunter 	if (root)
1125e266a753SAdrian Hunter 		__dso__findlink_by_longname(root, dso, NULL);
1126cdd059d7SJiri Olsa }
1127cdd059d7SJiri Olsa 
112858a98c9cSAdrian Hunter void dso__set_short_name(struct dso *dso, const char *name, bool name_allocated)
1129cdd059d7SJiri Olsa {
1130cdd059d7SJiri Olsa 	if (name == NULL)
1131cdd059d7SJiri Olsa 		return;
113258a98c9cSAdrian Hunter 
113358a98c9cSAdrian Hunter 	if (dso->short_name_allocated)
113458a98c9cSAdrian Hunter 		free((char *)dso->short_name);
113558a98c9cSAdrian Hunter 
1136cdd059d7SJiri Olsa 	dso->short_name		  = name;
1137cdd059d7SJiri Olsa 	dso->short_name_len	  = strlen(name);
113858a98c9cSAdrian Hunter 	dso->short_name_allocated = name_allocated;
1139cdd059d7SJiri Olsa }
1140cdd059d7SJiri Olsa 
1141cdd059d7SJiri Olsa static void dso__set_basename(struct dso *dso)
1142cdd059d7SJiri Olsa {
1143ac5e7f84SStephane Eranian        /*
1144ac5e7f84SStephane Eranian         * basename() may modify path buffer, so we must pass
1145ac5e7f84SStephane Eranian         * a copy.
1146ac5e7f84SStephane Eranian         */
1147ac5e7f84SStephane Eranian        char *base, *lname = strdup(dso->long_name);
1148ac5e7f84SStephane Eranian 
1149ac5e7f84SStephane Eranian        if (!lname)
1150ac5e7f84SStephane Eranian                return;
1151ac5e7f84SStephane Eranian 
1152ac5e7f84SStephane Eranian        /*
1153ac5e7f84SStephane Eranian         * basename() may return a pointer to internal
1154ac5e7f84SStephane Eranian         * storage which is reused in subsequent calls
1155ac5e7f84SStephane Eranian         * so copy the result.
1156ac5e7f84SStephane Eranian         */
1157ac5e7f84SStephane Eranian        base = strdup(basename(lname));
1158ac5e7f84SStephane Eranian 
1159ac5e7f84SStephane Eranian        free(lname);
1160ac5e7f84SStephane Eranian 
1161ac5e7f84SStephane Eranian        if (!base)
1162ac5e7f84SStephane Eranian                return;
1163ac5e7f84SStephane Eranian 
1164ac5e7f84SStephane Eranian        dso__set_short_name(dso, base, true);
1165cdd059d7SJiri Olsa }
1166cdd059d7SJiri Olsa 
1167cdd059d7SJiri Olsa int dso__name_len(const struct dso *dso)
1168cdd059d7SJiri Olsa {
1169cdd059d7SJiri Olsa 	if (!dso)
1170cdd059d7SJiri Olsa 		return strlen("[unknown]");
1171bb963e16SNamhyung Kim 	if (verbose > 0)
1172cdd059d7SJiri Olsa 		return dso->long_name_len;
1173cdd059d7SJiri Olsa 
1174cdd059d7SJiri Olsa 	return dso->short_name_len;
1175cdd059d7SJiri Olsa }
1176cdd059d7SJiri Olsa 
11773183f8caSArnaldo Carvalho de Melo bool dso__loaded(const struct dso *dso)
1178cdd059d7SJiri Olsa {
11793183f8caSArnaldo Carvalho de Melo 	return dso->loaded;
1180cdd059d7SJiri Olsa }
1181cdd059d7SJiri Olsa 
11823183f8caSArnaldo Carvalho de Melo bool dso__sorted_by_name(const struct dso *dso)
1183cdd059d7SJiri Olsa {
11843183f8caSArnaldo Carvalho de Melo 	return dso->sorted_by_name;
1185cdd059d7SJiri Olsa }
1186cdd059d7SJiri Olsa 
11873183f8caSArnaldo Carvalho de Melo void dso__set_sorted_by_name(struct dso *dso)
1188cdd059d7SJiri Olsa {
11893183f8caSArnaldo Carvalho de Melo 	dso->sorted_by_name = true;
1190cdd059d7SJiri Olsa }
1191cdd059d7SJiri Olsa 
1192cdd059d7SJiri Olsa struct dso *dso__new(const char *name)
1193cdd059d7SJiri Olsa {
1194cdd059d7SJiri Olsa 	struct dso *dso = calloc(1, sizeof(*dso) + strlen(name) + 1);
1195cdd059d7SJiri Olsa 
1196cdd059d7SJiri Olsa 	if (dso != NULL) {
1197cdd059d7SJiri Olsa 		strcpy(dso->name, name);
11987e155d4dSArnaldo Carvalho de Melo 		dso__set_long_name(dso, dso->name, false);
119958a98c9cSAdrian Hunter 		dso__set_short_name(dso, dso->name, false);
12003183f8caSArnaldo Carvalho de Melo 		dso->symbols = dso->symbol_names = RB_ROOT;
1201ca40e2afSJiri Olsa 		dso->data.cache = RB_ROOT;
120211ea2515SMilian Wolff 		dso->inlined_nodes = RB_ROOT;
120321ac9d54SMilian Wolff 		dso->srclines = RB_ROOT;
120453fa8eaaSJiri Olsa 		dso->data.fd = -1;
1205c27697d6SAdrian Hunter 		dso->data.status = DSO_DATA_STATUS_UNKNOWN;
1206cdd059d7SJiri Olsa 		dso->symtab_type = DSO_BINARY_TYPE__NOT_FOUND;
12075f70619dSArnaldo Carvalho de Melo 		dso->binary_type = DSO_BINARY_TYPE__NOT_FOUND;
1208c6d8f2a4SAdrian Hunter 		dso->is_64_bit = (sizeof(void *) == 8);
1209cdd059d7SJiri Olsa 		dso->loaded = 0;
12100131c4ecSAdrian Hunter 		dso->rel = 0;
1211cdd059d7SJiri Olsa 		dso->sorted_by_name = 0;
1212cdd059d7SJiri Olsa 		dso->has_build_id = 0;
12132cc9d0efSNamhyung Kim 		dso->has_srcline = 1;
1214906049c8SAdrian Hunter 		dso->a2l_fails = 1;
1215cdd059d7SJiri Olsa 		dso->kernel = DSO_TYPE_USER;
1216cdd059d7SJiri Olsa 		dso->needs_swap = DSO_SWAP__UNSET;
12172af52475SJiri Olsa 		dso->comp = COMP_ID__NONE;
12184598a0a6SWaiman Long 		RB_CLEAR_NODE(&dso->rb_node);
1219e266a753SAdrian Hunter 		dso->root = NULL;
1220cdd059d7SJiri Olsa 		INIT_LIST_HEAD(&dso->node);
1221eba5102dSJiri Olsa 		INIT_LIST_HEAD(&dso->data.open_entry);
12224a936edcSNamhyung Kim 		pthread_mutex_init(&dso->lock, NULL);
12237100810aSElena Reshetova 		refcount_set(&dso->refcnt, 1);
1224cdd059d7SJiri Olsa 	}
1225cdd059d7SJiri Olsa 
1226cdd059d7SJiri Olsa 	return dso;
1227cdd059d7SJiri Olsa }
1228cdd059d7SJiri Olsa 
1229cdd059d7SJiri Olsa void dso__delete(struct dso *dso)
1230cdd059d7SJiri Olsa {
12314598a0a6SWaiman Long 	if (!RB_EMPTY_NODE(&dso->rb_node))
12324598a0a6SWaiman Long 		pr_err("DSO %s is still in rbtree when being deleted!\n",
12334598a0a6SWaiman Long 		       dso->long_name);
123411ea2515SMilian Wolff 
123511ea2515SMilian Wolff 	/* free inlines first, as they reference symbols */
123611ea2515SMilian Wolff 	inlines__tree_delete(&dso->inlined_nodes);
123721ac9d54SMilian Wolff 	srcline__tree_delete(&dso->srclines);
12383183f8caSArnaldo Carvalho de Melo 	symbols__delete(&dso->symbols);
1239ee021d42SArnaldo Carvalho de Melo 
1240ee021d42SArnaldo Carvalho de Melo 	if (dso->short_name_allocated) {
124104662523SArnaldo Carvalho de Melo 		zfree((char **)&dso->short_name);
1242ee021d42SArnaldo Carvalho de Melo 		dso->short_name_allocated = false;
1243ee021d42SArnaldo Carvalho de Melo 	}
1244ee021d42SArnaldo Carvalho de Melo 
1245ee021d42SArnaldo Carvalho de Melo 	if (dso->long_name_allocated) {
124604662523SArnaldo Carvalho de Melo 		zfree((char **)&dso->long_name);
1247ee021d42SArnaldo Carvalho de Melo 		dso->long_name_allocated = false;
1248ee021d42SArnaldo Carvalho de Melo 	}
1249ee021d42SArnaldo Carvalho de Melo 
125053fa8eaaSJiri Olsa 	dso__data_close(dso);
1251cfe9174fSAdrian Hunter 	auxtrace_cache__free(dso->auxtrace_cache);
12528e67b725SNamhyung Kim 	dso_cache__free(dso);
1253454ff00fSAdrian Hunter 	dso__free_a2l(dso);
125404662523SArnaldo Carvalho de Melo 	zfree(&dso->symsrc_filename);
1255843ff37bSKrister Johansen 	nsinfo__zput(dso->nsinfo);
12564a936edcSNamhyung Kim 	pthread_mutex_destroy(&dso->lock);
1257cdd059d7SJiri Olsa 	free(dso);
1258cdd059d7SJiri Olsa }
1259cdd059d7SJiri Olsa 
1260d3a7c489SArnaldo Carvalho de Melo struct dso *dso__get(struct dso *dso)
1261d3a7c489SArnaldo Carvalho de Melo {
1262d3a7c489SArnaldo Carvalho de Melo 	if (dso)
12637100810aSElena Reshetova 		refcount_inc(&dso->refcnt);
1264d3a7c489SArnaldo Carvalho de Melo 	return dso;
1265d3a7c489SArnaldo Carvalho de Melo }
1266d3a7c489SArnaldo Carvalho de Melo 
1267d3a7c489SArnaldo Carvalho de Melo void dso__put(struct dso *dso)
1268d3a7c489SArnaldo Carvalho de Melo {
12697100810aSElena Reshetova 	if (dso && refcount_dec_and_test(&dso->refcnt))
1270d3a7c489SArnaldo Carvalho de Melo 		dso__delete(dso);
1271d3a7c489SArnaldo Carvalho de Melo }
1272d3a7c489SArnaldo Carvalho de Melo 
1273cdd059d7SJiri Olsa void dso__set_build_id(struct dso *dso, void *build_id)
1274cdd059d7SJiri Olsa {
1275cdd059d7SJiri Olsa 	memcpy(dso->build_id, build_id, sizeof(dso->build_id));
1276cdd059d7SJiri Olsa 	dso->has_build_id = 1;
1277cdd059d7SJiri Olsa }
1278cdd059d7SJiri Olsa 
1279cdd059d7SJiri Olsa bool dso__build_id_equal(const struct dso *dso, u8 *build_id)
1280cdd059d7SJiri Olsa {
1281cdd059d7SJiri Olsa 	return memcmp(dso->build_id, build_id, sizeof(dso->build_id)) == 0;
1282cdd059d7SJiri Olsa }
1283cdd059d7SJiri Olsa 
1284cdd059d7SJiri Olsa void dso__read_running_kernel_build_id(struct dso *dso, struct machine *machine)
1285cdd059d7SJiri Olsa {
1286cdd059d7SJiri Olsa 	char path[PATH_MAX];
1287cdd059d7SJiri Olsa 
1288cdd059d7SJiri Olsa 	if (machine__is_default_guest(machine))
1289cdd059d7SJiri Olsa 		return;
1290cdd059d7SJiri Olsa 	sprintf(path, "%s/sys/kernel/notes", machine->root_dir);
1291cdd059d7SJiri Olsa 	if (sysfs__read_build_id(path, dso->build_id,
1292cdd059d7SJiri Olsa 				 sizeof(dso->build_id)) == 0)
1293cdd059d7SJiri Olsa 		dso->has_build_id = true;
1294cdd059d7SJiri Olsa }
1295cdd059d7SJiri Olsa 
1296cdd059d7SJiri Olsa int dso__kernel_module_get_build_id(struct dso *dso,
1297cdd059d7SJiri Olsa 				    const char *root_dir)
1298cdd059d7SJiri Olsa {
1299cdd059d7SJiri Olsa 	char filename[PATH_MAX];
1300cdd059d7SJiri Olsa 	/*
1301cdd059d7SJiri Olsa 	 * kernel module short names are of the form "[module]" and
1302cdd059d7SJiri Olsa 	 * we need just "module" here.
1303cdd059d7SJiri Olsa 	 */
1304cdd059d7SJiri Olsa 	const char *name = dso->short_name + 1;
1305cdd059d7SJiri Olsa 
1306cdd059d7SJiri Olsa 	snprintf(filename, sizeof(filename),
1307cdd059d7SJiri Olsa 		 "%s/sys/module/%.*s/notes/.note.gnu.build-id",
1308cdd059d7SJiri Olsa 		 root_dir, (int)strlen(name) - 1, name);
1309cdd059d7SJiri Olsa 
1310cdd059d7SJiri Olsa 	if (sysfs__read_build_id(filename, dso->build_id,
1311cdd059d7SJiri Olsa 				 sizeof(dso->build_id)) == 0)
1312cdd059d7SJiri Olsa 		dso->has_build_id = true;
1313cdd059d7SJiri Olsa 
1314cdd059d7SJiri Olsa 	return 0;
1315cdd059d7SJiri Olsa }
1316cdd059d7SJiri Olsa 
1317cdd059d7SJiri Olsa bool __dsos__read_build_ids(struct list_head *head, bool with_hits)
1318cdd059d7SJiri Olsa {
1319cdd059d7SJiri Olsa 	bool have_build_id = false;
1320cdd059d7SJiri Olsa 	struct dso *pos;
1321f045b8c4SKrister Johansen 	struct nscookie nsc;
1322cdd059d7SJiri Olsa 
1323cdd059d7SJiri Olsa 	list_for_each_entry(pos, head, node) {
13246ae98ba6SHe Kuang 		if (with_hits && !pos->hit && !dso__is_vdso(pos))
1325cdd059d7SJiri Olsa 			continue;
1326cdd059d7SJiri Olsa 		if (pos->has_build_id) {
1327cdd059d7SJiri Olsa 			have_build_id = true;
1328cdd059d7SJiri Olsa 			continue;
1329cdd059d7SJiri Olsa 		}
1330f045b8c4SKrister Johansen 		nsinfo__mountns_enter(pos->nsinfo, &nsc);
1331cdd059d7SJiri Olsa 		if (filename__read_build_id(pos->long_name, pos->build_id,
1332cdd059d7SJiri Olsa 					    sizeof(pos->build_id)) > 0) {
1333cdd059d7SJiri Olsa 			have_build_id	  = true;
1334cdd059d7SJiri Olsa 			pos->has_build_id = true;
1335cdd059d7SJiri Olsa 		}
1336f045b8c4SKrister Johansen 		nsinfo__mountns_exit(&nsc);
1337cdd059d7SJiri Olsa 	}
1338cdd059d7SJiri Olsa 
1339cdd059d7SJiri Olsa 	return have_build_id;
1340cdd059d7SJiri Olsa }
1341cdd059d7SJiri Olsa 
1342e8807844SArnaldo Carvalho de Melo void __dsos__add(struct dsos *dsos, struct dso *dso)
1343cdd059d7SJiri Olsa {
13448fa7d87fSWaiman Long 	list_add_tail(&dso->node, &dsos->head);
1345e8807844SArnaldo Carvalho de Melo 	__dso__findlink_by_longname(&dsos->root, dso, NULL);
1346d3a7c489SArnaldo Carvalho de Melo 	/*
1347d3a7c489SArnaldo Carvalho de Melo 	 * It is now in the linked list, grab a reference, then garbage collect
1348d3a7c489SArnaldo Carvalho de Melo 	 * this when needing memory, by looking at LRU dso instances in the
1349d3a7c489SArnaldo Carvalho de Melo 	 * list with atomic_read(&dso->refcnt) == 1, i.e. no references
1350d3a7c489SArnaldo Carvalho de Melo 	 * anywhere besides the one for the list, do, under a lock for the
1351d3a7c489SArnaldo Carvalho de Melo 	 * list: remove it from the list, then a dso__put(), that probably will
1352d3a7c489SArnaldo Carvalho de Melo 	 * be the last and will then call dso__delete(), end of life.
1353d3a7c489SArnaldo Carvalho de Melo 	 *
1354d3a7c489SArnaldo Carvalho de Melo 	 * That, or at the end of the 'struct machine' lifetime, when all
1355d3a7c489SArnaldo Carvalho de Melo 	 * 'struct dso' instances will be removed from the list, in
1356d3a7c489SArnaldo Carvalho de Melo 	 * dsos__exit(), if they have no other reference from some other data
1357d3a7c489SArnaldo Carvalho de Melo 	 * structure.
1358d3a7c489SArnaldo Carvalho de Melo 	 *
1359d3a7c489SArnaldo Carvalho de Melo 	 * E.g.: after processing a 'perf.data' file and storing references
1360d3a7c489SArnaldo Carvalho de Melo 	 * to objects instantiated while processing events, we will have
1361d3a7c489SArnaldo Carvalho de Melo 	 * references to the 'thread', 'map', 'dso' structs all from 'struct
1362d3a7c489SArnaldo Carvalho de Melo 	 * hist_entry' instances, but we may not need anything not referenced,
1363d3a7c489SArnaldo Carvalho de Melo 	 * so we might as well call machines__exit()/machines__delete() and
1364d3a7c489SArnaldo Carvalho de Melo 	 * garbage collect it.
1365d3a7c489SArnaldo Carvalho de Melo 	 */
1366d3a7c489SArnaldo Carvalho de Melo 	dso__get(dso);
1367cdd059d7SJiri Olsa }
1368cdd059d7SJiri Olsa 
1369e8807844SArnaldo Carvalho de Melo void dsos__add(struct dsos *dsos, struct dso *dso)
1370e8807844SArnaldo Carvalho de Melo {
13710a7c74eaSArnaldo Carvalho de Melo 	down_write(&dsos->lock);
1372e8807844SArnaldo Carvalho de Melo 	__dsos__add(dsos, dso);
13730a7c74eaSArnaldo Carvalho de Melo 	up_write(&dsos->lock);
1374e8807844SArnaldo Carvalho de Melo }
1375e8807844SArnaldo Carvalho de Melo 
1376e8807844SArnaldo Carvalho de Melo struct dso *__dsos__find(struct dsos *dsos, const char *name, bool cmp_short)
1377cdd059d7SJiri Olsa {
1378cdd059d7SJiri Olsa 	struct dso *pos;
1379cdd059d7SJiri Olsa 
1380f9ceffb6SWaiman Long 	if (cmp_short) {
13818fa7d87fSWaiman Long 		list_for_each_entry(pos, &dsos->head, node)
1382f9ceffb6SWaiman Long 			if (strcmp(pos->short_name, name) == 0)
1383f9ceffb6SWaiman Long 				return pos;
1384f9ceffb6SWaiman Long 		return NULL;
1385f9ceffb6SWaiman Long 	}
1386e8807844SArnaldo Carvalho de Melo 	return __dso__find_by_longname(&dsos->root, name);
1387cdd059d7SJiri Olsa }
1388cdd059d7SJiri Olsa 
1389e8807844SArnaldo Carvalho de Melo struct dso *dsos__find(struct dsos *dsos, const char *name, bool cmp_short)
1390e8807844SArnaldo Carvalho de Melo {
1391e8807844SArnaldo Carvalho de Melo 	struct dso *dso;
13920a7c74eaSArnaldo Carvalho de Melo 	down_read(&dsos->lock);
1393e8807844SArnaldo Carvalho de Melo 	dso = __dsos__find(dsos, name, cmp_short);
13940a7c74eaSArnaldo Carvalho de Melo 	up_read(&dsos->lock);
1395e8807844SArnaldo Carvalho de Melo 	return dso;
1396e8807844SArnaldo Carvalho de Melo }
1397e8807844SArnaldo Carvalho de Melo 
1398e8807844SArnaldo Carvalho de Melo struct dso *__dsos__addnew(struct dsos *dsos, const char *name)
1399cdd059d7SJiri Olsa {
1400701d8d7fSJiri Olsa 	struct dso *dso = dso__new(name);
1401cdd059d7SJiri Olsa 
1402cdd059d7SJiri Olsa 	if (dso != NULL) {
1403e8807844SArnaldo Carvalho de Melo 		__dsos__add(dsos, dso);
1404cdd059d7SJiri Olsa 		dso__set_basename(dso);
140582de26abSMasami Hiramatsu 		/* Put dso here because __dsos_add already got it */
140682de26abSMasami Hiramatsu 		dso__put(dso);
1407cdd059d7SJiri Olsa 	}
1408701d8d7fSJiri Olsa 	return dso;
1409cdd059d7SJiri Olsa }
1410cdd059d7SJiri Olsa 
1411701d8d7fSJiri Olsa struct dso *__dsos__findnew(struct dsos *dsos, const char *name)
1412701d8d7fSJiri Olsa {
1413e8807844SArnaldo Carvalho de Melo 	struct dso *dso = __dsos__find(dsos, name, false);
1414701d8d7fSJiri Olsa 
1415e8807844SArnaldo Carvalho de Melo 	return dso ? dso : __dsos__addnew(dsos, name);
1416e8807844SArnaldo Carvalho de Melo }
1417e8807844SArnaldo Carvalho de Melo 
1418e8807844SArnaldo Carvalho de Melo struct dso *dsos__findnew(struct dsos *dsos, const char *name)
1419e8807844SArnaldo Carvalho de Melo {
1420e8807844SArnaldo Carvalho de Melo 	struct dso *dso;
14210a7c74eaSArnaldo Carvalho de Melo 	down_write(&dsos->lock);
1422d3a7c489SArnaldo Carvalho de Melo 	dso = dso__get(__dsos__findnew(dsos, name));
14230a7c74eaSArnaldo Carvalho de Melo 	up_write(&dsos->lock);
1424e8807844SArnaldo Carvalho de Melo 	return dso;
1425cdd059d7SJiri Olsa }
1426cdd059d7SJiri Olsa 
1427cdd059d7SJiri Olsa size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp,
1428417c2ff6SArnaldo Carvalho de Melo 			       bool (skip)(struct dso *dso, int parm), int parm)
1429cdd059d7SJiri Olsa {
1430cdd059d7SJiri Olsa 	struct dso *pos;
1431cdd059d7SJiri Olsa 	size_t ret = 0;
1432cdd059d7SJiri Olsa 
1433cdd059d7SJiri Olsa 	list_for_each_entry(pos, head, node) {
1434417c2ff6SArnaldo Carvalho de Melo 		if (skip && skip(pos, parm))
1435cdd059d7SJiri Olsa 			continue;
1436cdd059d7SJiri Olsa 		ret += dso__fprintf_buildid(pos, fp);
1437cdd059d7SJiri Olsa 		ret += fprintf(fp, " %s\n", pos->long_name);
1438cdd059d7SJiri Olsa 	}
1439cdd059d7SJiri Olsa 	return ret;
1440cdd059d7SJiri Olsa }
1441cdd059d7SJiri Olsa 
1442cdd059d7SJiri Olsa size_t __dsos__fprintf(struct list_head *head, FILE *fp)
1443cdd059d7SJiri Olsa {
1444cdd059d7SJiri Olsa 	struct dso *pos;
1445cdd059d7SJiri Olsa 	size_t ret = 0;
1446cdd059d7SJiri Olsa 
1447cdd059d7SJiri Olsa 	list_for_each_entry(pos, head, node) {
14483183f8caSArnaldo Carvalho de Melo 		ret += dso__fprintf(pos, fp);
1449cdd059d7SJiri Olsa 	}
1450cdd059d7SJiri Olsa 
1451cdd059d7SJiri Olsa 	return ret;
1452cdd059d7SJiri Olsa }
1453cdd059d7SJiri Olsa 
1454cdd059d7SJiri Olsa size_t dso__fprintf_buildid(struct dso *dso, FILE *fp)
1455cdd059d7SJiri Olsa {
1456b5d8bbe8SMasami Hiramatsu 	char sbuild_id[SBUILD_ID_SIZE];
1457cdd059d7SJiri Olsa 
1458cdd059d7SJiri Olsa 	build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id);
1459cdd059d7SJiri Olsa 	return fprintf(fp, "%s", sbuild_id);
1460cdd059d7SJiri Olsa }
1461cdd059d7SJiri Olsa 
14623183f8caSArnaldo Carvalho de Melo size_t dso__fprintf(struct dso *dso, FILE *fp)
1463cdd059d7SJiri Olsa {
1464cdd059d7SJiri Olsa 	struct rb_node *nd;
1465cdd059d7SJiri Olsa 	size_t ret = fprintf(fp, "dso: %s (", dso->short_name);
1466cdd059d7SJiri Olsa 
1467cdd059d7SJiri Olsa 	if (dso->short_name != dso->long_name)
1468cdd059d7SJiri Olsa 		ret += fprintf(fp, "%s, ", dso->long_name);
14693183f8caSArnaldo Carvalho de Melo 	ret += fprintf(fp, "%sloaded, ", dso__loaded(dso) ? "" : "NOT ");
1470cdd059d7SJiri Olsa 	ret += dso__fprintf_buildid(dso, fp);
1471cdd059d7SJiri Olsa 	ret += fprintf(fp, ")\n");
14723183f8caSArnaldo Carvalho de Melo 	for (nd = rb_first(&dso->symbols); nd; nd = rb_next(nd)) {
1473cdd059d7SJiri Olsa 		struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
1474cdd059d7SJiri Olsa 		ret += symbol__fprintf(pos, fp);
1475cdd059d7SJiri Olsa 	}
1476cdd059d7SJiri Olsa 
1477cdd059d7SJiri Olsa 	return ret;
1478cdd059d7SJiri Olsa }
14792b5b8bb2SAdrian Hunter 
14802b5b8bb2SAdrian Hunter enum dso_type dso__type(struct dso *dso, struct machine *machine)
14812b5b8bb2SAdrian Hunter {
14822b5b8bb2SAdrian Hunter 	int fd;
14834bb11d01SNamhyung Kim 	enum dso_type type = DSO__TYPE_UNKNOWN;
14842b5b8bb2SAdrian Hunter 
14854bb11d01SNamhyung Kim 	fd = dso__data_get_fd(dso, machine);
14864bb11d01SNamhyung Kim 	if (fd >= 0) {
14874bb11d01SNamhyung Kim 		type = dso__type_fd(fd);
14884bb11d01SNamhyung Kim 		dso__data_put_fd(dso);
14894bb11d01SNamhyung Kim 	}
14902b5b8bb2SAdrian Hunter 
14914bb11d01SNamhyung Kim 	return type;
14922b5b8bb2SAdrian Hunter }
149318425f13SArnaldo Carvalho de Melo 
149418425f13SArnaldo Carvalho de Melo int dso__strerror_load(struct dso *dso, char *buf, size_t buflen)
149518425f13SArnaldo Carvalho de Melo {
149618425f13SArnaldo Carvalho de Melo 	int idx, errnum = dso->load_errno;
149718425f13SArnaldo Carvalho de Melo 	/*
149818425f13SArnaldo Carvalho de Melo 	 * This must have a same ordering as the enum dso_load_errno.
149918425f13SArnaldo Carvalho de Melo 	 */
150018425f13SArnaldo Carvalho de Melo 	static const char *dso_load__error_str[] = {
150118425f13SArnaldo Carvalho de Melo 	"Internal tools/perf/ library error",
150218425f13SArnaldo Carvalho de Melo 	"Invalid ELF file",
150318425f13SArnaldo Carvalho de Melo 	"Can not read build id",
150418425f13SArnaldo Carvalho de Melo 	"Mismatching build id",
150518425f13SArnaldo Carvalho de Melo 	"Decompression failure",
150618425f13SArnaldo Carvalho de Melo 	};
150718425f13SArnaldo Carvalho de Melo 
150818425f13SArnaldo Carvalho de Melo 	BUG_ON(buflen == 0);
150918425f13SArnaldo Carvalho de Melo 
151018425f13SArnaldo Carvalho de Melo 	if (errnum >= 0) {
1511c8b5f2c9SArnaldo Carvalho de Melo 		const char *err = str_error_r(errnum, buf, buflen);
151218425f13SArnaldo Carvalho de Melo 
151318425f13SArnaldo Carvalho de Melo 		if (err != buf)
151418425f13SArnaldo Carvalho de Melo 			scnprintf(buf, buflen, "%s", err);
151518425f13SArnaldo Carvalho de Melo 
151618425f13SArnaldo Carvalho de Melo 		return 0;
151718425f13SArnaldo Carvalho de Melo 	}
151818425f13SArnaldo Carvalho de Melo 
151918425f13SArnaldo Carvalho de Melo 	if (errnum <  __DSO_LOAD_ERRNO__START || errnum >= __DSO_LOAD_ERRNO__END)
152018425f13SArnaldo Carvalho de Melo 		return -1;
152118425f13SArnaldo Carvalho de Melo 
152218425f13SArnaldo Carvalho de Melo 	idx = errnum - __DSO_LOAD_ERRNO__START;
152318425f13SArnaldo Carvalho de Melo 	scnprintf(buf, buflen, "%s", dso_load__error_str[idx]);
152418425f13SArnaldo Carvalho de Melo 	return 0;
152518425f13SArnaldo Carvalho de Melo }
1526