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