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