18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci#include <dirent.h> 38c2ecf20Sopenharmony_ci#include <errno.h> 48c2ecf20Sopenharmony_ci#include <stdlib.h> 58c2ecf20Sopenharmony_ci#include <stdio.h> 68c2ecf20Sopenharmony_ci#include <string.h> 78c2ecf20Sopenharmony_ci#include <linux/capability.h> 88c2ecf20Sopenharmony_ci#include <linux/kernel.h> 98c2ecf20Sopenharmony_ci#include <linux/mman.h> 108c2ecf20Sopenharmony_ci#include <linux/string.h> 118c2ecf20Sopenharmony_ci#include <linux/time64.h> 128c2ecf20Sopenharmony_ci#include <sys/types.h> 138c2ecf20Sopenharmony_ci#include <sys/stat.h> 148c2ecf20Sopenharmony_ci#include <sys/param.h> 158c2ecf20Sopenharmony_ci#include <fcntl.h> 168c2ecf20Sopenharmony_ci#include <unistd.h> 178c2ecf20Sopenharmony_ci#include <inttypes.h> 188c2ecf20Sopenharmony_ci#include "annotate.h" 198c2ecf20Sopenharmony_ci#include "build-id.h" 208c2ecf20Sopenharmony_ci#include "cap.h" 218c2ecf20Sopenharmony_ci#include "dso.h" 228c2ecf20Sopenharmony_ci#include "util.h" // lsdir() 238c2ecf20Sopenharmony_ci#include "debug.h" 248c2ecf20Sopenharmony_ci#include "event.h" 258c2ecf20Sopenharmony_ci#include "machine.h" 268c2ecf20Sopenharmony_ci#include "map.h" 278c2ecf20Sopenharmony_ci#include "symbol.h" 288c2ecf20Sopenharmony_ci#include "map_symbol.h" 298c2ecf20Sopenharmony_ci#include "mem-events.h" 308c2ecf20Sopenharmony_ci#include "symsrc.h" 318c2ecf20Sopenharmony_ci#include "strlist.h" 328c2ecf20Sopenharmony_ci#include "intlist.h" 338c2ecf20Sopenharmony_ci#include "namespaces.h" 348c2ecf20Sopenharmony_ci#include "header.h" 358c2ecf20Sopenharmony_ci#include "path.h" 368c2ecf20Sopenharmony_ci#include <linux/ctype.h> 378c2ecf20Sopenharmony_ci#include <linux/zalloc.h> 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci#include <elf.h> 408c2ecf20Sopenharmony_ci#include <limits.h> 418c2ecf20Sopenharmony_ci#include <symbol/kallsyms.h> 428c2ecf20Sopenharmony_ci#include <sys/utsname.h> 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_cistatic int dso__load_kernel_sym(struct dso *dso, struct map *map); 458c2ecf20Sopenharmony_cistatic int dso__load_guest_kernel_sym(struct dso *dso, struct map *map); 468c2ecf20Sopenharmony_cistatic bool symbol__is_idle(const char *name); 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ciint vmlinux_path__nr_entries; 498c2ecf20Sopenharmony_cichar **vmlinux_path; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_cistruct symbol_conf symbol_conf = { 528c2ecf20Sopenharmony_ci .nanosecs = false, 538c2ecf20Sopenharmony_ci .use_modules = true, 548c2ecf20Sopenharmony_ci .try_vmlinux_path = true, 558c2ecf20Sopenharmony_ci .demangle = true, 568c2ecf20Sopenharmony_ci .demangle_kernel = false, 578c2ecf20Sopenharmony_ci .cumulate_callchain = true, 588c2ecf20Sopenharmony_ci .time_quantum = 100 * NSEC_PER_MSEC, /* 100ms */ 598c2ecf20Sopenharmony_ci .show_hist_headers = true, 608c2ecf20Sopenharmony_ci .symfs = "", 618c2ecf20Sopenharmony_ci .event_group = true, 628c2ecf20Sopenharmony_ci .inline_name = true, 638c2ecf20Sopenharmony_ci .res_sample = 0, 648c2ecf20Sopenharmony_ci}; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_cistatic enum dso_binary_type binary_type_symtab[] = { 678c2ecf20Sopenharmony_ci DSO_BINARY_TYPE__KALLSYMS, 688c2ecf20Sopenharmony_ci DSO_BINARY_TYPE__GUEST_KALLSYMS, 698c2ecf20Sopenharmony_ci DSO_BINARY_TYPE__JAVA_JIT, 708c2ecf20Sopenharmony_ci DSO_BINARY_TYPE__DEBUGLINK, 718c2ecf20Sopenharmony_ci DSO_BINARY_TYPE__BUILD_ID_CACHE, 728c2ecf20Sopenharmony_ci DSO_BINARY_TYPE__BUILD_ID_CACHE_DEBUGINFO, 738c2ecf20Sopenharmony_ci DSO_BINARY_TYPE__FEDORA_DEBUGINFO, 748c2ecf20Sopenharmony_ci DSO_BINARY_TYPE__UBUNTU_DEBUGINFO, 758c2ecf20Sopenharmony_ci DSO_BINARY_TYPE__BUILDID_DEBUGINFO, 768c2ecf20Sopenharmony_ci DSO_BINARY_TYPE__SYSTEM_PATH_DSO, 778c2ecf20Sopenharmony_ci DSO_BINARY_TYPE__GUEST_KMODULE, 788c2ecf20Sopenharmony_ci DSO_BINARY_TYPE__GUEST_KMODULE_COMP, 798c2ecf20Sopenharmony_ci DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE, 808c2ecf20Sopenharmony_ci DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP, 818c2ecf20Sopenharmony_ci DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO, 828c2ecf20Sopenharmony_ci DSO_BINARY_TYPE__MIXEDUP_UBUNTU_DEBUGINFO, 838c2ecf20Sopenharmony_ci DSO_BINARY_TYPE__NOT_FOUND, 848c2ecf20Sopenharmony_ci}; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci#define DSO_BINARY_TYPE__SYMTAB_CNT ARRAY_SIZE(binary_type_symtab) 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_cistatic bool symbol_type__filter(char symbol_type) 898c2ecf20Sopenharmony_ci{ 908c2ecf20Sopenharmony_ci symbol_type = toupper(symbol_type); 918c2ecf20Sopenharmony_ci return symbol_type == 'T' || symbol_type == 'W' || symbol_type == 'D' || symbol_type == 'B'; 928c2ecf20Sopenharmony_ci} 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_cistatic int prefix_underscores_count(const char *str) 958c2ecf20Sopenharmony_ci{ 968c2ecf20Sopenharmony_ci const char *tail = str; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci while (*tail == '_') 998c2ecf20Sopenharmony_ci tail++; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci return tail - str; 1028c2ecf20Sopenharmony_ci} 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ciconst char * __weak arch__normalize_symbol_name(const char *name) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci return name; 1078c2ecf20Sopenharmony_ci} 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ciint __weak arch__compare_symbol_names(const char *namea, const char *nameb) 1108c2ecf20Sopenharmony_ci{ 1118c2ecf20Sopenharmony_ci return strcmp(namea, nameb); 1128c2ecf20Sopenharmony_ci} 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ciint __weak arch__compare_symbol_names_n(const char *namea, const char *nameb, 1158c2ecf20Sopenharmony_ci unsigned int n) 1168c2ecf20Sopenharmony_ci{ 1178c2ecf20Sopenharmony_ci return strncmp(namea, nameb, n); 1188c2ecf20Sopenharmony_ci} 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ciint __weak arch__choose_best_symbol(struct symbol *syma, 1218c2ecf20Sopenharmony_ci struct symbol *symb __maybe_unused) 1228c2ecf20Sopenharmony_ci{ 1238c2ecf20Sopenharmony_ci /* Avoid "SyS" kernel syscall aliases */ 1248c2ecf20Sopenharmony_ci if (strlen(syma->name) >= 3 && !strncmp(syma->name, "SyS", 3)) 1258c2ecf20Sopenharmony_ci return SYMBOL_B; 1268c2ecf20Sopenharmony_ci if (strlen(syma->name) >= 10 && !strncmp(syma->name, "compat_SyS", 10)) 1278c2ecf20Sopenharmony_ci return SYMBOL_B; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci return SYMBOL_A; 1308c2ecf20Sopenharmony_ci} 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_cistatic int choose_best_symbol(struct symbol *syma, struct symbol *symb) 1338c2ecf20Sopenharmony_ci{ 1348c2ecf20Sopenharmony_ci s64 a; 1358c2ecf20Sopenharmony_ci s64 b; 1368c2ecf20Sopenharmony_ci size_t na, nb; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci /* Prefer a symbol with non zero length */ 1398c2ecf20Sopenharmony_ci a = syma->end - syma->start; 1408c2ecf20Sopenharmony_ci b = symb->end - symb->start; 1418c2ecf20Sopenharmony_ci if ((b == 0) && (a > 0)) 1428c2ecf20Sopenharmony_ci return SYMBOL_A; 1438c2ecf20Sopenharmony_ci else if ((a == 0) && (b > 0)) 1448c2ecf20Sopenharmony_ci return SYMBOL_B; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci /* Prefer a non weak symbol over a weak one */ 1478c2ecf20Sopenharmony_ci a = syma->binding == STB_WEAK; 1488c2ecf20Sopenharmony_ci b = symb->binding == STB_WEAK; 1498c2ecf20Sopenharmony_ci if (b && !a) 1508c2ecf20Sopenharmony_ci return SYMBOL_A; 1518c2ecf20Sopenharmony_ci if (a && !b) 1528c2ecf20Sopenharmony_ci return SYMBOL_B; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci /* Prefer a global symbol over a non global one */ 1558c2ecf20Sopenharmony_ci a = syma->binding == STB_GLOBAL; 1568c2ecf20Sopenharmony_ci b = symb->binding == STB_GLOBAL; 1578c2ecf20Sopenharmony_ci if (a && !b) 1588c2ecf20Sopenharmony_ci return SYMBOL_A; 1598c2ecf20Sopenharmony_ci if (b && !a) 1608c2ecf20Sopenharmony_ci return SYMBOL_B; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci /* Prefer a symbol with less underscores */ 1638c2ecf20Sopenharmony_ci a = prefix_underscores_count(syma->name); 1648c2ecf20Sopenharmony_ci b = prefix_underscores_count(symb->name); 1658c2ecf20Sopenharmony_ci if (b > a) 1668c2ecf20Sopenharmony_ci return SYMBOL_A; 1678c2ecf20Sopenharmony_ci else if (a > b) 1688c2ecf20Sopenharmony_ci return SYMBOL_B; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci /* Choose the symbol with the longest name */ 1718c2ecf20Sopenharmony_ci na = strlen(syma->name); 1728c2ecf20Sopenharmony_ci nb = strlen(symb->name); 1738c2ecf20Sopenharmony_ci if (na > nb) 1748c2ecf20Sopenharmony_ci return SYMBOL_A; 1758c2ecf20Sopenharmony_ci else if (na < nb) 1768c2ecf20Sopenharmony_ci return SYMBOL_B; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci return arch__choose_best_symbol(syma, symb); 1798c2ecf20Sopenharmony_ci} 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_civoid symbols__fixup_duplicate(struct rb_root_cached *symbols) 1828c2ecf20Sopenharmony_ci{ 1838c2ecf20Sopenharmony_ci struct rb_node *nd; 1848c2ecf20Sopenharmony_ci struct symbol *curr, *next; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci if (symbol_conf.allow_aliases) 1878c2ecf20Sopenharmony_ci return; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci nd = rb_first_cached(symbols); 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci while (nd) { 1928c2ecf20Sopenharmony_ci curr = rb_entry(nd, struct symbol, rb_node); 1938c2ecf20Sopenharmony_ciagain: 1948c2ecf20Sopenharmony_ci nd = rb_next(&curr->rb_node); 1958c2ecf20Sopenharmony_ci next = rb_entry(nd, struct symbol, rb_node); 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci if (!nd) 1988c2ecf20Sopenharmony_ci break; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci if (curr->start != next->start) 2018c2ecf20Sopenharmony_ci continue; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci if (choose_best_symbol(curr, next) == SYMBOL_A) { 2048c2ecf20Sopenharmony_ci rb_erase_cached(&next->rb_node, symbols); 2058c2ecf20Sopenharmony_ci symbol__delete(next); 2068c2ecf20Sopenharmony_ci goto again; 2078c2ecf20Sopenharmony_ci } else { 2088c2ecf20Sopenharmony_ci nd = rb_next(&curr->rb_node); 2098c2ecf20Sopenharmony_ci rb_erase_cached(&curr->rb_node, symbols); 2108c2ecf20Sopenharmony_ci symbol__delete(curr); 2118c2ecf20Sopenharmony_ci } 2128c2ecf20Sopenharmony_ci } 2138c2ecf20Sopenharmony_ci} 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci/* Update zero-sized symbols using the address of the next symbol */ 2168c2ecf20Sopenharmony_civoid symbols__fixup_end(struct rb_root_cached *symbols, bool is_kallsyms) 2178c2ecf20Sopenharmony_ci{ 2188c2ecf20Sopenharmony_ci struct rb_node *nd, *prevnd = rb_first_cached(symbols); 2198c2ecf20Sopenharmony_ci struct symbol *curr, *prev; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci if (prevnd == NULL) 2228c2ecf20Sopenharmony_ci return; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci curr = rb_entry(prevnd, struct symbol, rb_node); 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) { 2278c2ecf20Sopenharmony_ci prev = curr; 2288c2ecf20Sopenharmony_ci curr = rb_entry(nd, struct symbol, rb_node); 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci /* 2318c2ecf20Sopenharmony_ci * On some architecture kernel text segment start is located at 2328c2ecf20Sopenharmony_ci * some low memory address, while modules are located at high 2338c2ecf20Sopenharmony_ci * memory addresses (or vice versa). The gap between end of 2348c2ecf20Sopenharmony_ci * kernel text segment and beginning of first module's text 2358c2ecf20Sopenharmony_ci * segment is very big. Therefore do not fill this gap and do 2368c2ecf20Sopenharmony_ci * not assign it to the kernel dso map (kallsyms). 2378c2ecf20Sopenharmony_ci * 2388c2ecf20Sopenharmony_ci * In kallsyms, it determines module symbols using '[' character 2398c2ecf20Sopenharmony_ci * like in: 2408c2ecf20Sopenharmony_ci * ffffffffc1937000 T hdmi_driver_init [snd_hda_codec_hdmi] 2418c2ecf20Sopenharmony_ci */ 2428c2ecf20Sopenharmony_ci if (prev->end == prev->start) { 2438c2ecf20Sopenharmony_ci /* Last kernel/module symbol mapped to end of page */ 2448c2ecf20Sopenharmony_ci if (is_kallsyms && (!strchr(prev->name, '[') != 2458c2ecf20Sopenharmony_ci !strchr(curr->name, '['))) 2468c2ecf20Sopenharmony_ci prev->end = roundup(prev->end + 4096, 4096); 2478c2ecf20Sopenharmony_ci else 2488c2ecf20Sopenharmony_ci prev->end = curr->start; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci pr_debug4("%s sym:%s end:%#" PRIx64 "\n", 2518c2ecf20Sopenharmony_ci __func__, prev->name, prev->end); 2528c2ecf20Sopenharmony_ci } 2538c2ecf20Sopenharmony_ci } 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci /* Last entry */ 2568c2ecf20Sopenharmony_ci if (curr->end == curr->start) 2578c2ecf20Sopenharmony_ci curr->end = roundup(curr->start, 4096) + 4096; 2588c2ecf20Sopenharmony_ci} 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_civoid maps__fixup_end(struct maps *maps) 2618c2ecf20Sopenharmony_ci{ 2628c2ecf20Sopenharmony_ci struct map *prev = NULL, *curr; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci down_write(&maps->lock); 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci maps__for_each_entry(maps, curr) { 2678c2ecf20Sopenharmony_ci if (prev != NULL && !prev->end) 2688c2ecf20Sopenharmony_ci prev->end = curr->start; 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci prev = curr; 2718c2ecf20Sopenharmony_ci } 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci /* 2748c2ecf20Sopenharmony_ci * We still haven't the actual symbols, so guess the 2758c2ecf20Sopenharmony_ci * last map final address. 2768c2ecf20Sopenharmony_ci */ 2778c2ecf20Sopenharmony_ci if (curr && !curr->end) 2788c2ecf20Sopenharmony_ci curr->end = ~0ULL; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci up_write(&maps->lock); 2818c2ecf20Sopenharmony_ci} 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_cistruct symbol *symbol__new(u64 start, u64 len, u8 binding, u8 type, const char *name) 2848c2ecf20Sopenharmony_ci{ 2858c2ecf20Sopenharmony_ci size_t namelen = strlen(name) + 1; 2868c2ecf20Sopenharmony_ci struct symbol *sym = calloc(1, (symbol_conf.priv_size + 2878c2ecf20Sopenharmony_ci sizeof(*sym) + namelen)); 2888c2ecf20Sopenharmony_ci if (sym == NULL) 2898c2ecf20Sopenharmony_ci return NULL; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci if (symbol_conf.priv_size) { 2928c2ecf20Sopenharmony_ci if (symbol_conf.init_annotation) { 2938c2ecf20Sopenharmony_ci struct annotation *notes = (void *)sym; 2948c2ecf20Sopenharmony_ci pthread_mutex_init(¬es->lock, NULL); 2958c2ecf20Sopenharmony_ci } 2968c2ecf20Sopenharmony_ci sym = ((void *)sym) + symbol_conf.priv_size; 2978c2ecf20Sopenharmony_ci } 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci sym->start = start; 3008c2ecf20Sopenharmony_ci sym->end = len ? start + len : start; 3018c2ecf20Sopenharmony_ci sym->type = type; 3028c2ecf20Sopenharmony_ci sym->binding = binding; 3038c2ecf20Sopenharmony_ci sym->namelen = namelen - 1; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci pr_debug4("%s: %s %#" PRIx64 "-%#" PRIx64 "\n", 3068c2ecf20Sopenharmony_ci __func__, name, start, sym->end); 3078c2ecf20Sopenharmony_ci memcpy(sym->name, name, namelen); 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci return sym; 3108c2ecf20Sopenharmony_ci} 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_civoid symbol__delete(struct symbol *sym) 3138c2ecf20Sopenharmony_ci{ 3148c2ecf20Sopenharmony_ci free(((void *)sym) - symbol_conf.priv_size); 3158c2ecf20Sopenharmony_ci} 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_civoid symbols__delete(struct rb_root_cached *symbols) 3188c2ecf20Sopenharmony_ci{ 3198c2ecf20Sopenharmony_ci struct symbol *pos; 3208c2ecf20Sopenharmony_ci struct rb_node *next = rb_first_cached(symbols); 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci while (next) { 3238c2ecf20Sopenharmony_ci pos = rb_entry(next, struct symbol, rb_node); 3248c2ecf20Sopenharmony_ci next = rb_next(&pos->rb_node); 3258c2ecf20Sopenharmony_ci rb_erase_cached(&pos->rb_node, symbols); 3268c2ecf20Sopenharmony_ci symbol__delete(pos); 3278c2ecf20Sopenharmony_ci } 3288c2ecf20Sopenharmony_ci} 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_civoid __symbols__insert(struct rb_root_cached *symbols, 3318c2ecf20Sopenharmony_ci struct symbol *sym, bool kernel) 3328c2ecf20Sopenharmony_ci{ 3338c2ecf20Sopenharmony_ci struct rb_node **p = &symbols->rb_root.rb_node; 3348c2ecf20Sopenharmony_ci struct rb_node *parent = NULL; 3358c2ecf20Sopenharmony_ci const u64 ip = sym->start; 3368c2ecf20Sopenharmony_ci struct symbol *s; 3378c2ecf20Sopenharmony_ci bool leftmost = true; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci if (kernel) { 3408c2ecf20Sopenharmony_ci const char *name = sym->name; 3418c2ecf20Sopenharmony_ci /* 3428c2ecf20Sopenharmony_ci * ppc64 uses function descriptors and appends a '.' to the 3438c2ecf20Sopenharmony_ci * start of every instruction address. Remove it. 3448c2ecf20Sopenharmony_ci */ 3458c2ecf20Sopenharmony_ci if (name[0] == '.') 3468c2ecf20Sopenharmony_ci name++; 3478c2ecf20Sopenharmony_ci sym->idle = symbol__is_idle(name); 3488c2ecf20Sopenharmony_ci } 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci while (*p != NULL) { 3518c2ecf20Sopenharmony_ci parent = *p; 3528c2ecf20Sopenharmony_ci s = rb_entry(parent, struct symbol, rb_node); 3538c2ecf20Sopenharmony_ci if (ip < s->start) 3548c2ecf20Sopenharmony_ci p = &(*p)->rb_left; 3558c2ecf20Sopenharmony_ci else { 3568c2ecf20Sopenharmony_ci p = &(*p)->rb_right; 3578c2ecf20Sopenharmony_ci leftmost = false; 3588c2ecf20Sopenharmony_ci } 3598c2ecf20Sopenharmony_ci } 3608c2ecf20Sopenharmony_ci rb_link_node(&sym->rb_node, parent, p); 3618c2ecf20Sopenharmony_ci rb_insert_color_cached(&sym->rb_node, symbols, leftmost); 3628c2ecf20Sopenharmony_ci} 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_civoid symbols__insert(struct rb_root_cached *symbols, struct symbol *sym) 3658c2ecf20Sopenharmony_ci{ 3668c2ecf20Sopenharmony_ci __symbols__insert(symbols, sym, false); 3678c2ecf20Sopenharmony_ci} 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_cistatic struct symbol *symbols__find(struct rb_root_cached *symbols, u64 ip) 3708c2ecf20Sopenharmony_ci{ 3718c2ecf20Sopenharmony_ci struct rb_node *n; 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci if (symbols == NULL) 3748c2ecf20Sopenharmony_ci return NULL; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci n = symbols->rb_root.rb_node; 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci while (n) { 3798c2ecf20Sopenharmony_ci struct symbol *s = rb_entry(n, struct symbol, rb_node); 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci if (ip < s->start) 3828c2ecf20Sopenharmony_ci n = n->rb_left; 3838c2ecf20Sopenharmony_ci else if (ip > s->end || (ip == s->end && ip != s->start)) 3848c2ecf20Sopenharmony_ci n = n->rb_right; 3858c2ecf20Sopenharmony_ci else 3868c2ecf20Sopenharmony_ci return s; 3878c2ecf20Sopenharmony_ci } 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci return NULL; 3908c2ecf20Sopenharmony_ci} 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_cistatic struct symbol *symbols__first(struct rb_root_cached *symbols) 3938c2ecf20Sopenharmony_ci{ 3948c2ecf20Sopenharmony_ci struct rb_node *n = rb_first_cached(symbols); 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci if (n) 3978c2ecf20Sopenharmony_ci return rb_entry(n, struct symbol, rb_node); 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci return NULL; 4008c2ecf20Sopenharmony_ci} 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_cistatic struct symbol *symbols__last(struct rb_root_cached *symbols) 4038c2ecf20Sopenharmony_ci{ 4048c2ecf20Sopenharmony_ci struct rb_node *n = rb_last(&symbols->rb_root); 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci if (n) 4078c2ecf20Sopenharmony_ci return rb_entry(n, struct symbol, rb_node); 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci return NULL; 4108c2ecf20Sopenharmony_ci} 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_cistatic struct symbol *symbols__next(struct symbol *sym) 4138c2ecf20Sopenharmony_ci{ 4148c2ecf20Sopenharmony_ci struct rb_node *n = rb_next(&sym->rb_node); 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci if (n) 4178c2ecf20Sopenharmony_ci return rb_entry(n, struct symbol, rb_node); 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci return NULL; 4208c2ecf20Sopenharmony_ci} 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_cistatic void symbols__insert_by_name(struct rb_root_cached *symbols, struct symbol *sym) 4238c2ecf20Sopenharmony_ci{ 4248c2ecf20Sopenharmony_ci struct rb_node **p = &symbols->rb_root.rb_node; 4258c2ecf20Sopenharmony_ci struct rb_node *parent = NULL; 4268c2ecf20Sopenharmony_ci struct symbol_name_rb_node *symn, *s; 4278c2ecf20Sopenharmony_ci bool leftmost = true; 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci symn = container_of(sym, struct symbol_name_rb_node, sym); 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci while (*p != NULL) { 4328c2ecf20Sopenharmony_ci parent = *p; 4338c2ecf20Sopenharmony_ci s = rb_entry(parent, struct symbol_name_rb_node, rb_node); 4348c2ecf20Sopenharmony_ci if (strcmp(sym->name, s->sym.name) < 0) 4358c2ecf20Sopenharmony_ci p = &(*p)->rb_left; 4368c2ecf20Sopenharmony_ci else { 4378c2ecf20Sopenharmony_ci p = &(*p)->rb_right; 4388c2ecf20Sopenharmony_ci leftmost = false; 4398c2ecf20Sopenharmony_ci } 4408c2ecf20Sopenharmony_ci } 4418c2ecf20Sopenharmony_ci rb_link_node(&symn->rb_node, parent, p); 4428c2ecf20Sopenharmony_ci rb_insert_color_cached(&symn->rb_node, symbols, leftmost); 4438c2ecf20Sopenharmony_ci} 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_cistatic void symbols__sort_by_name(struct rb_root_cached *symbols, 4468c2ecf20Sopenharmony_ci struct rb_root_cached *source) 4478c2ecf20Sopenharmony_ci{ 4488c2ecf20Sopenharmony_ci struct rb_node *nd; 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci for (nd = rb_first_cached(source); nd; nd = rb_next(nd)) { 4518c2ecf20Sopenharmony_ci struct symbol *pos = rb_entry(nd, struct symbol, rb_node); 4528c2ecf20Sopenharmony_ci symbols__insert_by_name(symbols, pos); 4538c2ecf20Sopenharmony_ci } 4548c2ecf20Sopenharmony_ci} 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ciint symbol__match_symbol_name(const char *name, const char *str, 4578c2ecf20Sopenharmony_ci enum symbol_tag_include includes) 4588c2ecf20Sopenharmony_ci{ 4598c2ecf20Sopenharmony_ci const char *versioning; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci if (includes == SYMBOL_TAG_INCLUDE__DEFAULT_ONLY && 4628c2ecf20Sopenharmony_ci (versioning = strstr(name, "@@"))) { 4638c2ecf20Sopenharmony_ci int len = strlen(str); 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci if (len < versioning - name) 4668c2ecf20Sopenharmony_ci len = versioning - name; 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci return arch__compare_symbol_names_n(name, str, len); 4698c2ecf20Sopenharmony_ci } else 4708c2ecf20Sopenharmony_ci return arch__compare_symbol_names(name, str); 4718c2ecf20Sopenharmony_ci} 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_cistatic struct symbol *symbols__find_by_name(struct rb_root_cached *symbols, 4748c2ecf20Sopenharmony_ci const char *name, 4758c2ecf20Sopenharmony_ci enum symbol_tag_include includes) 4768c2ecf20Sopenharmony_ci{ 4778c2ecf20Sopenharmony_ci struct rb_node *n; 4788c2ecf20Sopenharmony_ci struct symbol_name_rb_node *s = NULL; 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci if (symbols == NULL) 4818c2ecf20Sopenharmony_ci return NULL; 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci n = symbols->rb_root.rb_node; 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci while (n) { 4868c2ecf20Sopenharmony_ci int cmp; 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci s = rb_entry(n, struct symbol_name_rb_node, rb_node); 4898c2ecf20Sopenharmony_ci cmp = symbol__match_symbol_name(s->sym.name, name, includes); 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci if (cmp > 0) 4928c2ecf20Sopenharmony_ci n = n->rb_left; 4938c2ecf20Sopenharmony_ci else if (cmp < 0) 4948c2ecf20Sopenharmony_ci n = n->rb_right; 4958c2ecf20Sopenharmony_ci else 4968c2ecf20Sopenharmony_ci break; 4978c2ecf20Sopenharmony_ci } 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci if (n == NULL) 5008c2ecf20Sopenharmony_ci return NULL; 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci if (includes != SYMBOL_TAG_INCLUDE__DEFAULT_ONLY) 5038c2ecf20Sopenharmony_ci /* return first symbol that has same name (if any) */ 5048c2ecf20Sopenharmony_ci for (n = rb_prev(n); n; n = rb_prev(n)) { 5058c2ecf20Sopenharmony_ci struct symbol_name_rb_node *tmp; 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci tmp = rb_entry(n, struct symbol_name_rb_node, rb_node); 5088c2ecf20Sopenharmony_ci if (arch__compare_symbol_names(tmp->sym.name, s->sym.name)) 5098c2ecf20Sopenharmony_ci break; 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci s = tmp; 5128c2ecf20Sopenharmony_ci } 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci return &s->sym; 5158c2ecf20Sopenharmony_ci} 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_civoid dso__reset_find_symbol_cache(struct dso *dso) 5188c2ecf20Sopenharmony_ci{ 5198c2ecf20Sopenharmony_ci dso->last_find_result.addr = 0; 5208c2ecf20Sopenharmony_ci dso->last_find_result.symbol = NULL; 5218c2ecf20Sopenharmony_ci} 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_civoid dso__insert_symbol(struct dso *dso, struct symbol *sym) 5248c2ecf20Sopenharmony_ci{ 5258c2ecf20Sopenharmony_ci __symbols__insert(&dso->symbols, sym, dso->kernel); 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci /* update the symbol cache if necessary */ 5288c2ecf20Sopenharmony_ci if (dso->last_find_result.addr >= sym->start && 5298c2ecf20Sopenharmony_ci (dso->last_find_result.addr < sym->end || 5308c2ecf20Sopenharmony_ci sym->start == sym->end)) { 5318c2ecf20Sopenharmony_ci dso->last_find_result.symbol = sym; 5328c2ecf20Sopenharmony_ci } 5338c2ecf20Sopenharmony_ci} 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_civoid dso__delete_symbol(struct dso *dso, struct symbol *sym) 5368c2ecf20Sopenharmony_ci{ 5378c2ecf20Sopenharmony_ci rb_erase_cached(&sym->rb_node, &dso->symbols); 5388c2ecf20Sopenharmony_ci symbol__delete(sym); 5398c2ecf20Sopenharmony_ci dso__reset_find_symbol_cache(dso); 5408c2ecf20Sopenharmony_ci} 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_cistruct symbol *dso__find_symbol(struct dso *dso, u64 addr) 5438c2ecf20Sopenharmony_ci{ 5448c2ecf20Sopenharmony_ci if (dso->last_find_result.addr != addr || dso->last_find_result.symbol == NULL) { 5458c2ecf20Sopenharmony_ci dso->last_find_result.addr = addr; 5468c2ecf20Sopenharmony_ci dso->last_find_result.symbol = symbols__find(&dso->symbols, addr); 5478c2ecf20Sopenharmony_ci } 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci return dso->last_find_result.symbol; 5508c2ecf20Sopenharmony_ci} 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_cistruct symbol *dso__first_symbol(struct dso *dso) 5538c2ecf20Sopenharmony_ci{ 5548c2ecf20Sopenharmony_ci return symbols__first(&dso->symbols); 5558c2ecf20Sopenharmony_ci} 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_cistruct symbol *dso__last_symbol(struct dso *dso) 5588c2ecf20Sopenharmony_ci{ 5598c2ecf20Sopenharmony_ci return symbols__last(&dso->symbols); 5608c2ecf20Sopenharmony_ci} 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_cistruct symbol *dso__next_symbol(struct symbol *sym) 5638c2ecf20Sopenharmony_ci{ 5648c2ecf20Sopenharmony_ci return symbols__next(sym); 5658c2ecf20Sopenharmony_ci} 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_cistruct symbol *symbol__next_by_name(struct symbol *sym) 5688c2ecf20Sopenharmony_ci{ 5698c2ecf20Sopenharmony_ci struct symbol_name_rb_node *s = container_of(sym, struct symbol_name_rb_node, sym); 5708c2ecf20Sopenharmony_ci struct rb_node *n = rb_next(&s->rb_node); 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci return n ? &rb_entry(n, struct symbol_name_rb_node, rb_node)->sym : NULL; 5738c2ecf20Sopenharmony_ci} 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci /* 5768c2ecf20Sopenharmony_ci * Returns first symbol that matched with @name. 5778c2ecf20Sopenharmony_ci */ 5788c2ecf20Sopenharmony_cistruct symbol *dso__find_symbol_by_name(struct dso *dso, const char *name) 5798c2ecf20Sopenharmony_ci{ 5808c2ecf20Sopenharmony_ci struct symbol *s = symbols__find_by_name(&dso->symbol_names, name, 5818c2ecf20Sopenharmony_ci SYMBOL_TAG_INCLUDE__NONE); 5828c2ecf20Sopenharmony_ci if (!s) 5838c2ecf20Sopenharmony_ci s = symbols__find_by_name(&dso->symbol_names, name, 5848c2ecf20Sopenharmony_ci SYMBOL_TAG_INCLUDE__DEFAULT_ONLY); 5858c2ecf20Sopenharmony_ci return s; 5868c2ecf20Sopenharmony_ci} 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_civoid dso__sort_by_name(struct dso *dso) 5898c2ecf20Sopenharmony_ci{ 5908c2ecf20Sopenharmony_ci dso__set_sorted_by_name(dso); 5918c2ecf20Sopenharmony_ci return symbols__sort_by_name(&dso->symbol_names, &dso->symbols); 5928c2ecf20Sopenharmony_ci} 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci/* 5958c2ecf20Sopenharmony_ci * While we find nice hex chars, build a long_val. 5968c2ecf20Sopenharmony_ci * Return number of chars processed. 5978c2ecf20Sopenharmony_ci */ 5988c2ecf20Sopenharmony_cistatic int hex2u64(const char *ptr, u64 *long_val) 5998c2ecf20Sopenharmony_ci{ 6008c2ecf20Sopenharmony_ci char *p; 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci *long_val = strtoull(ptr, &p, 16); 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci return p - ptr; 6058c2ecf20Sopenharmony_ci} 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ciint modules__parse(const char *filename, void *arg, 6098c2ecf20Sopenharmony_ci int (*process_module)(void *arg, const char *name, 6108c2ecf20Sopenharmony_ci u64 start, u64 size)) 6118c2ecf20Sopenharmony_ci{ 6128c2ecf20Sopenharmony_ci char *line = NULL; 6138c2ecf20Sopenharmony_ci size_t n; 6148c2ecf20Sopenharmony_ci FILE *file; 6158c2ecf20Sopenharmony_ci int err = 0; 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci file = fopen(filename, "r"); 6188c2ecf20Sopenharmony_ci if (file == NULL) 6198c2ecf20Sopenharmony_ci return -1; 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci while (1) { 6228c2ecf20Sopenharmony_ci char name[PATH_MAX]; 6238c2ecf20Sopenharmony_ci u64 start, size; 6248c2ecf20Sopenharmony_ci char *sep, *endptr; 6258c2ecf20Sopenharmony_ci ssize_t line_len; 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci line_len = getline(&line, &n, file); 6288c2ecf20Sopenharmony_ci if (line_len < 0) { 6298c2ecf20Sopenharmony_ci if (feof(file)) 6308c2ecf20Sopenharmony_ci break; 6318c2ecf20Sopenharmony_ci err = -1; 6328c2ecf20Sopenharmony_ci goto out; 6338c2ecf20Sopenharmony_ci } 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci if (!line) { 6368c2ecf20Sopenharmony_ci err = -1; 6378c2ecf20Sopenharmony_ci goto out; 6388c2ecf20Sopenharmony_ci } 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci line[--line_len] = '\0'; /* \n */ 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci sep = strrchr(line, 'x'); 6438c2ecf20Sopenharmony_ci if (sep == NULL) 6448c2ecf20Sopenharmony_ci continue; 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci hex2u64(sep + 1, &start); 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci sep = strchr(line, ' '); 6498c2ecf20Sopenharmony_ci if (sep == NULL) 6508c2ecf20Sopenharmony_ci continue; 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci *sep = '\0'; 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci scnprintf(name, sizeof(name), "[%s]", line); 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci size = strtoul(sep + 1, &endptr, 0); 6578c2ecf20Sopenharmony_ci if (*endptr != ' ' && *endptr != '\t') 6588c2ecf20Sopenharmony_ci continue; 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci err = process_module(arg, name, start, size); 6618c2ecf20Sopenharmony_ci if (err) 6628c2ecf20Sopenharmony_ci break; 6638c2ecf20Sopenharmony_ci } 6648c2ecf20Sopenharmony_ciout: 6658c2ecf20Sopenharmony_ci free(line); 6668c2ecf20Sopenharmony_ci fclose(file); 6678c2ecf20Sopenharmony_ci return err; 6688c2ecf20Sopenharmony_ci} 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci/* 6718c2ecf20Sopenharmony_ci * These are symbols in the kernel image, so make sure that 6728c2ecf20Sopenharmony_ci * sym is from a kernel DSO. 6738c2ecf20Sopenharmony_ci */ 6748c2ecf20Sopenharmony_cistatic bool symbol__is_idle(const char *name) 6758c2ecf20Sopenharmony_ci{ 6768c2ecf20Sopenharmony_ci const char * const idle_symbols[] = { 6778c2ecf20Sopenharmony_ci "acpi_idle_do_entry", 6788c2ecf20Sopenharmony_ci "acpi_processor_ffh_cstate_enter", 6798c2ecf20Sopenharmony_ci "arch_cpu_idle", 6808c2ecf20Sopenharmony_ci "cpu_idle", 6818c2ecf20Sopenharmony_ci "cpu_startup_entry", 6828c2ecf20Sopenharmony_ci "idle_cpu", 6838c2ecf20Sopenharmony_ci "intel_idle", 6848c2ecf20Sopenharmony_ci "default_idle", 6858c2ecf20Sopenharmony_ci "native_safe_halt", 6868c2ecf20Sopenharmony_ci "enter_idle", 6878c2ecf20Sopenharmony_ci "exit_idle", 6888c2ecf20Sopenharmony_ci "mwait_idle", 6898c2ecf20Sopenharmony_ci "mwait_idle_with_hints", 6908c2ecf20Sopenharmony_ci "mwait_idle_with_hints.constprop.0", 6918c2ecf20Sopenharmony_ci "poll_idle", 6928c2ecf20Sopenharmony_ci "ppc64_runlatch_off", 6938c2ecf20Sopenharmony_ci "pseries_dedicated_idle_sleep", 6948c2ecf20Sopenharmony_ci "psw_idle", 6958c2ecf20Sopenharmony_ci "psw_idle_exit", 6968c2ecf20Sopenharmony_ci NULL 6978c2ecf20Sopenharmony_ci }; 6988c2ecf20Sopenharmony_ci int i; 6998c2ecf20Sopenharmony_ci static struct strlist *idle_symbols_list; 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci if (idle_symbols_list) 7028c2ecf20Sopenharmony_ci return strlist__has_entry(idle_symbols_list, name); 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci idle_symbols_list = strlist__new(NULL, NULL); 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci for (i = 0; idle_symbols[i]; i++) 7078c2ecf20Sopenharmony_ci strlist__add(idle_symbols_list, idle_symbols[i]); 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci return strlist__has_entry(idle_symbols_list, name); 7108c2ecf20Sopenharmony_ci} 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_cistatic int map__process_kallsym_symbol(void *arg, const char *name, 7138c2ecf20Sopenharmony_ci char type, u64 start) 7148c2ecf20Sopenharmony_ci{ 7158c2ecf20Sopenharmony_ci struct symbol *sym; 7168c2ecf20Sopenharmony_ci struct dso *dso = arg; 7178c2ecf20Sopenharmony_ci struct rb_root_cached *root = &dso->symbols; 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci if (!symbol_type__filter(type)) 7208c2ecf20Sopenharmony_ci return 0; 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci /* 7238c2ecf20Sopenharmony_ci * module symbols are not sorted so we add all 7248c2ecf20Sopenharmony_ci * symbols, setting length to 0, and rely on 7258c2ecf20Sopenharmony_ci * symbols__fixup_end() to fix it up. 7268c2ecf20Sopenharmony_ci */ 7278c2ecf20Sopenharmony_ci sym = symbol__new(start, 0, kallsyms2elf_binding(type), kallsyms2elf_type(type), name); 7288c2ecf20Sopenharmony_ci if (sym == NULL) 7298c2ecf20Sopenharmony_ci return -ENOMEM; 7308c2ecf20Sopenharmony_ci /* 7318c2ecf20Sopenharmony_ci * We will pass the symbols to the filter later, in 7328c2ecf20Sopenharmony_ci * map__split_kallsyms, when we have split the maps per module 7338c2ecf20Sopenharmony_ci */ 7348c2ecf20Sopenharmony_ci __symbols__insert(root, sym, !strchr(name, '[')); 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci return 0; 7378c2ecf20Sopenharmony_ci} 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci/* 7408c2ecf20Sopenharmony_ci * Loads the function entries in /proc/kallsyms into kernel_map->dso, 7418c2ecf20Sopenharmony_ci * so that we can in the next step set the symbol ->end address and then 7428c2ecf20Sopenharmony_ci * call kernel_maps__split_kallsyms. 7438c2ecf20Sopenharmony_ci */ 7448c2ecf20Sopenharmony_cistatic int dso__load_all_kallsyms(struct dso *dso, const char *filename) 7458c2ecf20Sopenharmony_ci{ 7468c2ecf20Sopenharmony_ci return kallsyms__parse(filename, dso, map__process_kallsym_symbol); 7478c2ecf20Sopenharmony_ci} 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_cistatic int maps__split_kallsyms_for_kcore(struct maps *kmaps, struct dso *dso) 7508c2ecf20Sopenharmony_ci{ 7518c2ecf20Sopenharmony_ci struct map *curr_map; 7528c2ecf20Sopenharmony_ci struct symbol *pos; 7538c2ecf20Sopenharmony_ci int count = 0; 7548c2ecf20Sopenharmony_ci struct rb_root_cached old_root = dso->symbols; 7558c2ecf20Sopenharmony_ci struct rb_root_cached *root = &dso->symbols; 7568c2ecf20Sopenharmony_ci struct rb_node *next = rb_first_cached(root); 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ci if (!kmaps) 7598c2ecf20Sopenharmony_ci return -1; 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci *root = RB_ROOT_CACHED; 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci while (next) { 7648c2ecf20Sopenharmony_ci char *module; 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci pos = rb_entry(next, struct symbol, rb_node); 7678c2ecf20Sopenharmony_ci next = rb_next(&pos->rb_node); 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci rb_erase_cached(&pos->rb_node, &old_root); 7708c2ecf20Sopenharmony_ci RB_CLEAR_NODE(&pos->rb_node); 7718c2ecf20Sopenharmony_ci module = strchr(pos->name, '\t'); 7728c2ecf20Sopenharmony_ci if (module) 7738c2ecf20Sopenharmony_ci *module = '\0'; 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci curr_map = maps__find(kmaps, pos->start); 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci if (!curr_map) { 7788c2ecf20Sopenharmony_ci symbol__delete(pos); 7798c2ecf20Sopenharmony_ci continue; 7808c2ecf20Sopenharmony_ci } 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci pos->start -= curr_map->start - curr_map->pgoff; 7838c2ecf20Sopenharmony_ci if (pos->end > curr_map->end) 7848c2ecf20Sopenharmony_ci pos->end = curr_map->end; 7858c2ecf20Sopenharmony_ci if (pos->end) 7868c2ecf20Sopenharmony_ci pos->end -= curr_map->start - curr_map->pgoff; 7878c2ecf20Sopenharmony_ci symbols__insert(&curr_map->dso->symbols, pos); 7888c2ecf20Sopenharmony_ci ++count; 7898c2ecf20Sopenharmony_ci } 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_ci /* Symbols have been adjusted */ 7928c2ecf20Sopenharmony_ci dso->adjust_symbols = 1; 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci return count; 7958c2ecf20Sopenharmony_ci} 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_ci/* 7988c2ecf20Sopenharmony_ci * Split the symbols into maps, making sure there are no overlaps, i.e. the 7998c2ecf20Sopenharmony_ci * kernel range is broken in several maps, named [kernel].N, as we don't have 8008c2ecf20Sopenharmony_ci * the original ELF section names vmlinux have. 8018c2ecf20Sopenharmony_ci */ 8028c2ecf20Sopenharmony_cistatic int maps__split_kallsyms(struct maps *kmaps, struct dso *dso, u64 delta, 8038c2ecf20Sopenharmony_ci struct map *initial_map) 8048c2ecf20Sopenharmony_ci{ 8058c2ecf20Sopenharmony_ci struct machine *machine; 8068c2ecf20Sopenharmony_ci struct map *curr_map = initial_map; 8078c2ecf20Sopenharmony_ci struct symbol *pos; 8088c2ecf20Sopenharmony_ci int count = 0, moved = 0; 8098c2ecf20Sopenharmony_ci struct rb_root_cached *root = &dso->symbols; 8108c2ecf20Sopenharmony_ci struct rb_node *next = rb_first_cached(root); 8118c2ecf20Sopenharmony_ci int kernel_range = 0; 8128c2ecf20Sopenharmony_ci bool x86_64; 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci if (!kmaps) 8158c2ecf20Sopenharmony_ci return -1; 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci machine = kmaps->machine; 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci x86_64 = machine__is(machine, "x86_64"); 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci while (next) { 8228c2ecf20Sopenharmony_ci char *module; 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci pos = rb_entry(next, struct symbol, rb_node); 8258c2ecf20Sopenharmony_ci next = rb_next(&pos->rb_node); 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci module = strchr(pos->name, '\t'); 8288c2ecf20Sopenharmony_ci if (module) { 8298c2ecf20Sopenharmony_ci if (!symbol_conf.use_modules) 8308c2ecf20Sopenharmony_ci goto discard_symbol; 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ci *module++ = '\0'; 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci if (strcmp(curr_map->dso->short_name, module)) { 8358c2ecf20Sopenharmony_ci if (curr_map != initial_map && 8368c2ecf20Sopenharmony_ci dso->kernel == DSO_SPACE__KERNEL_GUEST && 8378c2ecf20Sopenharmony_ci machine__is_default_guest(machine)) { 8388c2ecf20Sopenharmony_ci /* 8398c2ecf20Sopenharmony_ci * We assume all symbols of a module are 8408c2ecf20Sopenharmony_ci * continuous in * kallsyms, so curr_map 8418c2ecf20Sopenharmony_ci * points to a module and all its 8428c2ecf20Sopenharmony_ci * symbols are in its kmap. Mark it as 8438c2ecf20Sopenharmony_ci * loaded. 8448c2ecf20Sopenharmony_ci */ 8458c2ecf20Sopenharmony_ci dso__set_loaded(curr_map->dso); 8468c2ecf20Sopenharmony_ci } 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci curr_map = maps__find_by_name(kmaps, module); 8498c2ecf20Sopenharmony_ci if (curr_map == NULL) { 8508c2ecf20Sopenharmony_ci pr_debug("%s/proc/{kallsyms,modules} " 8518c2ecf20Sopenharmony_ci "inconsistency while looking " 8528c2ecf20Sopenharmony_ci "for \"%s\" module!\n", 8538c2ecf20Sopenharmony_ci machine->root_dir, module); 8548c2ecf20Sopenharmony_ci curr_map = initial_map; 8558c2ecf20Sopenharmony_ci goto discard_symbol; 8568c2ecf20Sopenharmony_ci } 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_ci if (curr_map->dso->loaded && 8598c2ecf20Sopenharmony_ci !machine__is_default_guest(machine)) 8608c2ecf20Sopenharmony_ci goto discard_symbol; 8618c2ecf20Sopenharmony_ci } 8628c2ecf20Sopenharmony_ci /* 8638c2ecf20Sopenharmony_ci * So that we look just like we get from .ko files, 8648c2ecf20Sopenharmony_ci * i.e. not prelinked, relative to initial_map->start. 8658c2ecf20Sopenharmony_ci */ 8668c2ecf20Sopenharmony_ci pos->start = curr_map->map_ip(curr_map, pos->start); 8678c2ecf20Sopenharmony_ci pos->end = curr_map->map_ip(curr_map, pos->end); 8688c2ecf20Sopenharmony_ci } else if (x86_64 && is_entry_trampoline(pos->name)) { 8698c2ecf20Sopenharmony_ci /* 8708c2ecf20Sopenharmony_ci * These symbols are not needed anymore since the 8718c2ecf20Sopenharmony_ci * trampoline maps refer to the text section and it's 8728c2ecf20Sopenharmony_ci * symbols instead. Avoid having to deal with 8738c2ecf20Sopenharmony_ci * relocations, and the assumption that the first symbol 8748c2ecf20Sopenharmony_ci * is the start of kernel text, by simply removing the 8758c2ecf20Sopenharmony_ci * symbols at this point. 8768c2ecf20Sopenharmony_ci */ 8778c2ecf20Sopenharmony_ci goto discard_symbol; 8788c2ecf20Sopenharmony_ci } else if (curr_map != initial_map) { 8798c2ecf20Sopenharmony_ci char dso_name[PATH_MAX]; 8808c2ecf20Sopenharmony_ci struct dso *ndso; 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci if (delta) { 8838c2ecf20Sopenharmony_ci /* Kernel was relocated at boot time */ 8848c2ecf20Sopenharmony_ci pos->start -= delta; 8858c2ecf20Sopenharmony_ci pos->end -= delta; 8868c2ecf20Sopenharmony_ci } 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci if (count == 0) { 8898c2ecf20Sopenharmony_ci curr_map = initial_map; 8908c2ecf20Sopenharmony_ci goto add_symbol; 8918c2ecf20Sopenharmony_ci } 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_ci if (dso->kernel == DSO_SPACE__KERNEL_GUEST) 8948c2ecf20Sopenharmony_ci snprintf(dso_name, sizeof(dso_name), 8958c2ecf20Sopenharmony_ci "[guest.kernel].%d", 8968c2ecf20Sopenharmony_ci kernel_range++); 8978c2ecf20Sopenharmony_ci else 8988c2ecf20Sopenharmony_ci snprintf(dso_name, sizeof(dso_name), 8998c2ecf20Sopenharmony_ci "[kernel].%d", 9008c2ecf20Sopenharmony_ci kernel_range++); 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci ndso = dso__new(dso_name); 9038c2ecf20Sopenharmony_ci if (ndso == NULL) 9048c2ecf20Sopenharmony_ci return -1; 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_ci ndso->kernel = dso->kernel; 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_ci curr_map = map__new2(pos->start, ndso); 9098c2ecf20Sopenharmony_ci if (curr_map == NULL) { 9108c2ecf20Sopenharmony_ci dso__put(ndso); 9118c2ecf20Sopenharmony_ci return -1; 9128c2ecf20Sopenharmony_ci } 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_ci curr_map->map_ip = curr_map->unmap_ip = identity__map_ip; 9158c2ecf20Sopenharmony_ci maps__insert(kmaps, curr_map); 9168c2ecf20Sopenharmony_ci ++kernel_range; 9178c2ecf20Sopenharmony_ci } else if (delta) { 9188c2ecf20Sopenharmony_ci /* Kernel was relocated at boot time */ 9198c2ecf20Sopenharmony_ci pos->start -= delta; 9208c2ecf20Sopenharmony_ci pos->end -= delta; 9218c2ecf20Sopenharmony_ci } 9228c2ecf20Sopenharmony_ciadd_symbol: 9238c2ecf20Sopenharmony_ci if (curr_map != initial_map) { 9248c2ecf20Sopenharmony_ci rb_erase_cached(&pos->rb_node, root); 9258c2ecf20Sopenharmony_ci symbols__insert(&curr_map->dso->symbols, pos); 9268c2ecf20Sopenharmony_ci ++moved; 9278c2ecf20Sopenharmony_ci } else 9288c2ecf20Sopenharmony_ci ++count; 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_ci continue; 9318c2ecf20Sopenharmony_cidiscard_symbol: 9328c2ecf20Sopenharmony_ci rb_erase_cached(&pos->rb_node, root); 9338c2ecf20Sopenharmony_ci symbol__delete(pos); 9348c2ecf20Sopenharmony_ci } 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_ci if (curr_map != initial_map && 9378c2ecf20Sopenharmony_ci dso->kernel == DSO_SPACE__KERNEL_GUEST && 9388c2ecf20Sopenharmony_ci machine__is_default_guest(kmaps->machine)) { 9398c2ecf20Sopenharmony_ci dso__set_loaded(curr_map->dso); 9408c2ecf20Sopenharmony_ci } 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ci return count + moved; 9438c2ecf20Sopenharmony_ci} 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_cibool symbol__restricted_filename(const char *filename, 9468c2ecf20Sopenharmony_ci const char *restricted_filename) 9478c2ecf20Sopenharmony_ci{ 9488c2ecf20Sopenharmony_ci bool restricted = false; 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_ci if (symbol_conf.kptr_restrict) { 9518c2ecf20Sopenharmony_ci char *r = realpath(filename, NULL); 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_ci if (r != NULL) { 9548c2ecf20Sopenharmony_ci restricted = strcmp(r, restricted_filename) == 0; 9558c2ecf20Sopenharmony_ci free(r); 9568c2ecf20Sopenharmony_ci return restricted; 9578c2ecf20Sopenharmony_ci } 9588c2ecf20Sopenharmony_ci } 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_ci return restricted; 9618c2ecf20Sopenharmony_ci} 9628c2ecf20Sopenharmony_ci 9638c2ecf20Sopenharmony_cistruct module_info { 9648c2ecf20Sopenharmony_ci struct rb_node rb_node; 9658c2ecf20Sopenharmony_ci char *name; 9668c2ecf20Sopenharmony_ci u64 start; 9678c2ecf20Sopenharmony_ci}; 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_cistatic void add_module(struct module_info *mi, struct rb_root *modules) 9708c2ecf20Sopenharmony_ci{ 9718c2ecf20Sopenharmony_ci struct rb_node **p = &modules->rb_node; 9728c2ecf20Sopenharmony_ci struct rb_node *parent = NULL; 9738c2ecf20Sopenharmony_ci struct module_info *m; 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_ci while (*p != NULL) { 9768c2ecf20Sopenharmony_ci parent = *p; 9778c2ecf20Sopenharmony_ci m = rb_entry(parent, struct module_info, rb_node); 9788c2ecf20Sopenharmony_ci if (strcmp(mi->name, m->name) < 0) 9798c2ecf20Sopenharmony_ci p = &(*p)->rb_left; 9808c2ecf20Sopenharmony_ci else 9818c2ecf20Sopenharmony_ci p = &(*p)->rb_right; 9828c2ecf20Sopenharmony_ci } 9838c2ecf20Sopenharmony_ci rb_link_node(&mi->rb_node, parent, p); 9848c2ecf20Sopenharmony_ci rb_insert_color(&mi->rb_node, modules); 9858c2ecf20Sopenharmony_ci} 9868c2ecf20Sopenharmony_ci 9878c2ecf20Sopenharmony_cistatic void delete_modules(struct rb_root *modules) 9888c2ecf20Sopenharmony_ci{ 9898c2ecf20Sopenharmony_ci struct module_info *mi; 9908c2ecf20Sopenharmony_ci struct rb_node *next = rb_first(modules); 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_ci while (next) { 9938c2ecf20Sopenharmony_ci mi = rb_entry(next, struct module_info, rb_node); 9948c2ecf20Sopenharmony_ci next = rb_next(&mi->rb_node); 9958c2ecf20Sopenharmony_ci rb_erase(&mi->rb_node, modules); 9968c2ecf20Sopenharmony_ci zfree(&mi->name); 9978c2ecf20Sopenharmony_ci free(mi); 9988c2ecf20Sopenharmony_ci } 9998c2ecf20Sopenharmony_ci} 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_cistatic struct module_info *find_module(const char *name, 10028c2ecf20Sopenharmony_ci struct rb_root *modules) 10038c2ecf20Sopenharmony_ci{ 10048c2ecf20Sopenharmony_ci struct rb_node *n = modules->rb_node; 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_ci while (n) { 10078c2ecf20Sopenharmony_ci struct module_info *m; 10088c2ecf20Sopenharmony_ci int cmp; 10098c2ecf20Sopenharmony_ci 10108c2ecf20Sopenharmony_ci m = rb_entry(n, struct module_info, rb_node); 10118c2ecf20Sopenharmony_ci cmp = strcmp(name, m->name); 10128c2ecf20Sopenharmony_ci if (cmp < 0) 10138c2ecf20Sopenharmony_ci n = n->rb_left; 10148c2ecf20Sopenharmony_ci else if (cmp > 0) 10158c2ecf20Sopenharmony_ci n = n->rb_right; 10168c2ecf20Sopenharmony_ci else 10178c2ecf20Sopenharmony_ci return m; 10188c2ecf20Sopenharmony_ci } 10198c2ecf20Sopenharmony_ci 10208c2ecf20Sopenharmony_ci return NULL; 10218c2ecf20Sopenharmony_ci} 10228c2ecf20Sopenharmony_ci 10238c2ecf20Sopenharmony_cistatic int __read_proc_modules(void *arg, const char *name, u64 start, 10248c2ecf20Sopenharmony_ci u64 size __maybe_unused) 10258c2ecf20Sopenharmony_ci{ 10268c2ecf20Sopenharmony_ci struct rb_root *modules = arg; 10278c2ecf20Sopenharmony_ci struct module_info *mi; 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_ci mi = zalloc(sizeof(struct module_info)); 10308c2ecf20Sopenharmony_ci if (!mi) 10318c2ecf20Sopenharmony_ci return -ENOMEM; 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ci mi->name = strdup(name); 10348c2ecf20Sopenharmony_ci mi->start = start; 10358c2ecf20Sopenharmony_ci 10368c2ecf20Sopenharmony_ci if (!mi->name) { 10378c2ecf20Sopenharmony_ci free(mi); 10388c2ecf20Sopenharmony_ci return -ENOMEM; 10398c2ecf20Sopenharmony_ci } 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_ci add_module(mi, modules); 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_ci return 0; 10448c2ecf20Sopenharmony_ci} 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_cistatic int read_proc_modules(const char *filename, struct rb_root *modules) 10478c2ecf20Sopenharmony_ci{ 10488c2ecf20Sopenharmony_ci if (symbol__restricted_filename(filename, "/proc/modules")) 10498c2ecf20Sopenharmony_ci return -1; 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_ci if (modules__parse(filename, modules, __read_proc_modules)) { 10528c2ecf20Sopenharmony_ci delete_modules(modules); 10538c2ecf20Sopenharmony_ci return -1; 10548c2ecf20Sopenharmony_ci } 10558c2ecf20Sopenharmony_ci 10568c2ecf20Sopenharmony_ci return 0; 10578c2ecf20Sopenharmony_ci} 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_ciint compare_proc_modules(const char *from, const char *to) 10608c2ecf20Sopenharmony_ci{ 10618c2ecf20Sopenharmony_ci struct rb_root from_modules = RB_ROOT; 10628c2ecf20Sopenharmony_ci struct rb_root to_modules = RB_ROOT; 10638c2ecf20Sopenharmony_ci struct rb_node *from_node, *to_node; 10648c2ecf20Sopenharmony_ci struct module_info *from_m, *to_m; 10658c2ecf20Sopenharmony_ci int ret = -1; 10668c2ecf20Sopenharmony_ci 10678c2ecf20Sopenharmony_ci if (read_proc_modules(from, &from_modules)) 10688c2ecf20Sopenharmony_ci return -1; 10698c2ecf20Sopenharmony_ci 10708c2ecf20Sopenharmony_ci if (read_proc_modules(to, &to_modules)) 10718c2ecf20Sopenharmony_ci goto out_delete_from; 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_ci from_node = rb_first(&from_modules); 10748c2ecf20Sopenharmony_ci to_node = rb_first(&to_modules); 10758c2ecf20Sopenharmony_ci while (from_node) { 10768c2ecf20Sopenharmony_ci if (!to_node) 10778c2ecf20Sopenharmony_ci break; 10788c2ecf20Sopenharmony_ci 10798c2ecf20Sopenharmony_ci from_m = rb_entry(from_node, struct module_info, rb_node); 10808c2ecf20Sopenharmony_ci to_m = rb_entry(to_node, struct module_info, rb_node); 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_ci if (from_m->start != to_m->start || 10838c2ecf20Sopenharmony_ci strcmp(from_m->name, to_m->name)) 10848c2ecf20Sopenharmony_ci break; 10858c2ecf20Sopenharmony_ci 10868c2ecf20Sopenharmony_ci from_node = rb_next(from_node); 10878c2ecf20Sopenharmony_ci to_node = rb_next(to_node); 10888c2ecf20Sopenharmony_ci } 10898c2ecf20Sopenharmony_ci 10908c2ecf20Sopenharmony_ci if (!from_node && !to_node) 10918c2ecf20Sopenharmony_ci ret = 0; 10928c2ecf20Sopenharmony_ci 10938c2ecf20Sopenharmony_ci delete_modules(&to_modules); 10948c2ecf20Sopenharmony_ciout_delete_from: 10958c2ecf20Sopenharmony_ci delete_modules(&from_modules); 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_ci return ret; 10988c2ecf20Sopenharmony_ci} 10998c2ecf20Sopenharmony_ci 11008c2ecf20Sopenharmony_cistatic int do_validate_kcore_modules(const char *filename, struct maps *kmaps) 11018c2ecf20Sopenharmony_ci{ 11028c2ecf20Sopenharmony_ci struct rb_root modules = RB_ROOT; 11038c2ecf20Sopenharmony_ci struct map *old_map; 11048c2ecf20Sopenharmony_ci int err; 11058c2ecf20Sopenharmony_ci 11068c2ecf20Sopenharmony_ci err = read_proc_modules(filename, &modules); 11078c2ecf20Sopenharmony_ci if (err) 11088c2ecf20Sopenharmony_ci return err; 11098c2ecf20Sopenharmony_ci 11108c2ecf20Sopenharmony_ci maps__for_each_entry(kmaps, old_map) { 11118c2ecf20Sopenharmony_ci struct module_info *mi; 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_ci if (!__map__is_kmodule(old_map)) { 11148c2ecf20Sopenharmony_ci continue; 11158c2ecf20Sopenharmony_ci } 11168c2ecf20Sopenharmony_ci 11178c2ecf20Sopenharmony_ci /* Module must be in memory at the same address */ 11188c2ecf20Sopenharmony_ci mi = find_module(old_map->dso->short_name, &modules); 11198c2ecf20Sopenharmony_ci if (!mi || mi->start != old_map->start) { 11208c2ecf20Sopenharmony_ci err = -EINVAL; 11218c2ecf20Sopenharmony_ci goto out; 11228c2ecf20Sopenharmony_ci } 11238c2ecf20Sopenharmony_ci } 11248c2ecf20Sopenharmony_ciout: 11258c2ecf20Sopenharmony_ci delete_modules(&modules); 11268c2ecf20Sopenharmony_ci return err; 11278c2ecf20Sopenharmony_ci} 11288c2ecf20Sopenharmony_ci 11298c2ecf20Sopenharmony_ci/* 11308c2ecf20Sopenharmony_ci * If kallsyms is referenced by name then we look for filename in the same 11318c2ecf20Sopenharmony_ci * directory. 11328c2ecf20Sopenharmony_ci */ 11338c2ecf20Sopenharmony_cistatic bool filename_from_kallsyms_filename(char *filename, 11348c2ecf20Sopenharmony_ci const char *base_name, 11358c2ecf20Sopenharmony_ci const char *kallsyms_filename) 11368c2ecf20Sopenharmony_ci{ 11378c2ecf20Sopenharmony_ci char *name; 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_ci strcpy(filename, kallsyms_filename); 11408c2ecf20Sopenharmony_ci name = strrchr(filename, '/'); 11418c2ecf20Sopenharmony_ci if (!name) 11428c2ecf20Sopenharmony_ci return false; 11438c2ecf20Sopenharmony_ci 11448c2ecf20Sopenharmony_ci name += 1; 11458c2ecf20Sopenharmony_ci 11468c2ecf20Sopenharmony_ci if (!strcmp(name, "kallsyms")) { 11478c2ecf20Sopenharmony_ci strcpy(name, base_name); 11488c2ecf20Sopenharmony_ci return true; 11498c2ecf20Sopenharmony_ci } 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_ci return false; 11528c2ecf20Sopenharmony_ci} 11538c2ecf20Sopenharmony_ci 11548c2ecf20Sopenharmony_cistatic int validate_kcore_modules(const char *kallsyms_filename, 11558c2ecf20Sopenharmony_ci struct map *map) 11568c2ecf20Sopenharmony_ci{ 11578c2ecf20Sopenharmony_ci struct maps *kmaps = map__kmaps(map); 11588c2ecf20Sopenharmony_ci char modules_filename[PATH_MAX]; 11598c2ecf20Sopenharmony_ci 11608c2ecf20Sopenharmony_ci if (!kmaps) 11618c2ecf20Sopenharmony_ci return -EINVAL; 11628c2ecf20Sopenharmony_ci 11638c2ecf20Sopenharmony_ci if (!filename_from_kallsyms_filename(modules_filename, "modules", 11648c2ecf20Sopenharmony_ci kallsyms_filename)) 11658c2ecf20Sopenharmony_ci return -EINVAL; 11668c2ecf20Sopenharmony_ci 11678c2ecf20Sopenharmony_ci if (do_validate_kcore_modules(modules_filename, kmaps)) 11688c2ecf20Sopenharmony_ci return -EINVAL; 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_ci return 0; 11718c2ecf20Sopenharmony_ci} 11728c2ecf20Sopenharmony_ci 11738c2ecf20Sopenharmony_cistatic int validate_kcore_addresses(const char *kallsyms_filename, 11748c2ecf20Sopenharmony_ci struct map *map) 11758c2ecf20Sopenharmony_ci{ 11768c2ecf20Sopenharmony_ci struct kmap *kmap = map__kmap(map); 11778c2ecf20Sopenharmony_ci 11788c2ecf20Sopenharmony_ci if (!kmap) 11798c2ecf20Sopenharmony_ci return -EINVAL; 11808c2ecf20Sopenharmony_ci 11818c2ecf20Sopenharmony_ci if (kmap->ref_reloc_sym && kmap->ref_reloc_sym->name) { 11828c2ecf20Sopenharmony_ci u64 start; 11838c2ecf20Sopenharmony_ci 11848c2ecf20Sopenharmony_ci if (kallsyms__get_function_start(kallsyms_filename, 11858c2ecf20Sopenharmony_ci kmap->ref_reloc_sym->name, &start)) 11868c2ecf20Sopenharmony_ci return -ENOENT; 11878c2ecf20Sopenharmony_ci if (start != kmap->ref_reloc_sym->addr) 11888c2ecf20Sopenharmony_ci return -EINVAL; 11898c2ecf20Sopenharmony_ci } 11908c2ecf20Sopenharmony_ci 11918c2ecf20Sopenharmony_ci return validate_kcore_modules(kallsyms_filename, map); 11928c2ecf20Sopenharmony_ci} 11938c2ecf20Sopenharmony_ci 11948c2ecf20Sopenharmony_cistruct kcore_mapfn_data { 11958c2ecf20Sopenharmony_ci struct dso *dso; 11968c2ecf20Sopenharmony_ci struct list_head maps; 11978c2ecf20Sopenharmony_ci}; 11988c2ecf20Sopenharmony_ci 11998c2ecf20Sopenharmony_cistatic int kcore_mapfn(u64 start, u64 len, u64 pgoff, void *data) 12008c2ecf20Sopenharmony_ci{ 12018c2ecf20Sopenharmony_ci struct kcore_mapfn_data *md = data; 12028c2ecf20Sopenharmony_ci struct map *map; 12038c2ecf20Sopenharmony_ci 12048c2ecf20Sopenharmony_ci map = map__new2(start, md->dso); 12058c2ecf20Sopenharmony_ci if (map == NULL) 12068c2ecf20Sopenharmony_ci return -ENOMEM; 12078c2ecf20Sopenharmony_ci 12088c2ecf20Sopenharmony_ci map->end = map->start + len; 12098c2ecf20Sopenharmony_ci map->pgoff = pgoff; 12108c2ecf20Sopenharmony_ci 12118c2ecf20Sopenharmony_ci list_add(&map->node, &md->maps); 12128c2ecf20Sopenharmony_ci 12138c2ecf20Sopenharmony_ci return 0; 12148c2ecf20Sopenharmony_ci} 12158c2ecf20Sopenharmony_ci 12168c2ecf20Sopenharmony_ci/* 12178c2ecf20Sopenharmony_ci * Merges map into maps by splitting the new map within the existing map 12188c2ecf20Sopenharmony_ci * regions. 12198c2ecf20Sopenharmony_ci */ 12208c2ecf20Sopenharmony_ciint maps__merge_in(struct maps *kmaps, struct map *new_map) 12218c2ecf20Sopenharmony_ci{ 12228c2ecf20Sopenharmony_ci struct map *old_map; 12238c2ecf20Sopenharmony_ci LIST_HEAD(merged); 12248c2ecf20Sopenharmony_ci 12258c2ecf20Sopenharmony_ci maps__for_each_entry(kmaps, old_map) { 12268c2ecf20Sopenharmony_ci /* no overload with this one */ 12278c2ecf20Sopenharmony_ci if (new_map->end < old_map->start || 12288c2ecf20Sopenharmony_ci new_map->start >= old_map->end) 12298c2ecf20Sopenharmony_ci continue; 12308c2ecf20Sopenharmony_ci 12318c2ecf20Sopenharmony_ci if (new_map->start < old_map->start) { 12328c2ecf20Sopenharmony_ci /* 12338c2ecf20Sopenharmony_ci * |new...... 12348c2ecf20Sopenharmony_ci * |old.... 12358c2ecf20Sopenharmony_ci */ 12368c2ecf20Sopenharmony_ci if (new_map->end < old_map->end) { 12378c2ecf20Sopenharmony_ci /* 12388c2ecf20Sopenharmony_ci * |new......| -> |new..| 12398c2ecf20Sopenharmony_ci * |old....| -> |old....| 12408c2ecf20Sopenharmony_ci */ 12418c2ecf20Sopenharmony_ci new_map->end = old_map->start; 12428c2ecf20Sopenharmony_ci } else { 12438c2ecf20Sopenharmony_ci /* 12448c2ecf20Sopenharmony_ci * |new.............| -> |new..| |new..| 12458c2ecf20Sopenharmony_ci * |old....| -> |old....| 12468c2ecf20Sopenharmony_ci */ 12478c2ecf20Sopenharmony_ci struct map *m = map__clone(new_map); 12488c2ecf20Sopenharmony_ci 12498c2ecf20Sopenharmony_ci if (!m) 12508c2ecf20Sopenharmony_ci return -ENOMEM; 12518c2ecf20Sopenharmony_ci 12528c2ecf20Sopenharmony_ci m->end = old_map->start; 12538c2ecf20Sopenharmony_ci list_add_tail(&m->node, &merged); 12548c2ecf20Sopenharmony_ci new_map->pgoff += old_map->end - new_map->start; 12558c2ecf20Sopenharmony_ci new_map->start = old_map->end; 12568c2ecf20Sopenharmony_ci } 12578c2ecf20Sopenharmony_ci } else { 12588c2ecf20Sopenharmony_ci /* 12598c2ecf20Sopenharmony_ci * |new...... 12608c2ecf20Sopenharmony_ci * |old.... 12618c2ecf20Sopenharmony_ci */ 12628c2ecf20Sopenharmony_ci if (new_map->end < old_map->end) { 12638c2ecf20Sopenharmony_ci /* 12648c2ecf20Sopenharmony_ci * |new..| -> x 12658c2ecf20Sopenharmony_ci * |old.........| -> |old.........| 12668c2ecf20Sopenharmony_ci */ 12678c2ecf20Sopenharmony_ci map__put(new_map); 12688c2ecf20Sopenharmony_ci new_map = NULL; 12698c2ecf20Sopenharmony_ci break; 12708c2ecf20Sopenharmony_ci } else { 12718c2ecf20Sopenharmony_ci /* 12728c2ecf20Sopenharmony_ci * |new......| -> |new...| 12738c2ecf20Sopenharmony_ci * |old....| -> |old....| 12748c2ecf20Sopenharmony_ci */ 12758c2ecf20Sopenharmony_ci new_map->pgoff += old_map->end - new_map->start; 12768c2ecf20Sopenharmony_ci new_map->start = old_map->end; 12778c2ecf20Sopenharmony_ci } 12788c2ecf20Sopenharmony_ci } 12798c2ecf20Sopenharmony_ci } 12808c2ecf20Sopenharmony_ci 12818c2ecf20Sopenharmony_ci while (!list_empty(&merged)) { 12828c2ecf20Sopenharmony_ci old_map = list_entry(merged.next, struct map, node); 12838c2ecf20Sopenharmony_ci list_del_init(&old_map->node); 12848c2ecf20Sopenharmony_ci maps__insert(kmaps, old_map); 12858c2ecf20Sopenharmony_ci map__put(old_map); 12868c2ecf20Sopenharmony_ci } 12878c2ecf20Sopenharmony_ci 12888c2ecf20Sopenharmony_ci if (new_map) { 12898c2ecf20Sopenharmony_ci maps__insert(kmaps, new_map); 12908c2ecf20Sopenharmony_ci map__put(new_map); 12918c2ecf20Sopenharmony_ci } 12928c2ecf20Sopenharmony_ci return 0; 12938c2ecf20Sopenharmony_ci} 12948c2ecf20Sopenharmony_ci 12958c2ecf20Sopenharmony_cistatic int dso__load_kcore(struct dso *dso, struct map *map, 12968c2ecf20Sopenharmony_ci const char *kallsyms_filename) 12978c2ecf20Sopenharmony_ci{ 12988c2ecf20Sopenharmony_ci struct maps *kmaps = map__kmaps(map); 12998c2ecf20Sopenharmony_ci struct kcore_mapfn_data md; 13008c2ecf20Sopenharmony_ci struct map *old_map, *new_map, *replacement_map = NULL, *next; 13018c2ecf20Sopenharmony_ci struct machine *machine; 13028c2ecf20Sopenharmony_ci bool is_64_bit; 13038c2ecf20Sopenharmony_ci int err, fd; 13048c2ecf20Sopenharmony_ci char kcore_filename[PATH_MAX]; 13058c2ecf20Sopenharmony_ci u64 stext; 13068c2ecf20Sopenharmony_ci 13078c2ecf20Sopenharmony_ci if (!kmaps) 13088c2ecf20Sopenharmony_ci return -EINVAL; 13098c2ecf20Sopenharmony_ci 13108c2ecf20Sopenharmony_ci machine = kmaps->machine; 13118c2ecf20Sopenharmony_ci 13128c2ecf20Sopenharmony_ci /* This function requires that the map is the kernel map */ 13138c2ecf20Sopenharmony_ci if (!__map__is_kernel(map)) 13148c2ecf20Sopenharmony_ci return -EINVAL; 13158c2ecf20Sopenharmony_ci 13168c2ecf20Sopenharmony_ci if (!filename_from_kallsyms_filename(kcore_filename, "kcore", 13178c2ecf20Sopenharmony_ci kallsyms_filename)) 13188c2ecf20Sopenharmony_ci return -EINVAL; 13198c2ecf20Sopenharmony_ci 13208c2ecf20Sopenharmony_ci /* Modules and kernel must be present at their original addresses */ 13218c2ecf20Sopenharmony_ci if (validate_kcore_addresses(kallsyms_filename, map)) 13228c2ecf20Sopenharmony_ci return -EINVAL; 13238c2ecf20Sopenharmony_ci 13248c2ecf20Sopenharmony_ci md.dso = dso; 13258c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&md.maps); 13268c2ecf20Sopenharmony_ci 13278c2ecf20Sopenharmony_ci fd = open(kcore_filename, O_RDONLY); 13288c2ecf20Sopenharmony_ci if (fd < 0) { 13298c2ecf20Sopenharmony_ci pr_debug("Failed to open %s. Note /proc/kcore requires CAP_SYS_RAWIO capability to access.\n", 13308c2ecf20Sopenharmony_ci kcore_filename); 13318c2ecf20Sopenharmony_ci return -EINVAL; 13328c2ecf20Sopenharmony_ci } 13338c2ecf20Sopenharmony_ci 13348c2ecf20Sopenharmony_ci /* Read new maps into temporary lists */ 13358c2ecf20Sopenharmony_ci err = file__read_maps(fd, map->prot & PROT_EXEC, kcore_mapfn, &md, 13368c2ecf20Sopenharmony_ci &is_64_bit); 13378c2ecf20Sopenharmony_ci if (err) 13388c2ecf20Sopenharmony_ci goto out_err; 13398c2ecf20Sopenharmony_ci dso->is_64_bit = is_64_bit; 13408c2ecf20Sopenharmony_ci 13418c2ecf20Sopenharmony_ci if (list_empty(&md.maps)) { 13428c2ecf20Sopenharmony_ci err = -EINVAL; 13438c2ecf20Sopenharmony_ci goto out_err; 13448c2ecf20Sopenharmony_ci } 13458c2ecf20Sopenharmony_ci 13468c2ecf20Sopenharmony_ci /* Remove old maps */ 13478c2ecf20Sopenharmony_ci maps__for_each_entry_safe(kmaps, old_map, next) { 13488c2ecf20Sopenharmony_ci /* 13498c2ecf20Sopenharmony_ci * We need to preserve eBPF maps even if they are 13508c2ecf20Sopenharmony_ci * covered by kcore, because we need to access 13518c2ecf20Sopenharmony_ci * eBPF dso for source data. 13528c2ecf20Sopenharmony_ci */ 13538c2ecf20Sopenharmony_ci if (old_map != map && !__map__is_bpf_prog(old_map)) 13548c2ecf20Sopenharmony_ci maps__remove(kmaps, old_map); 13558c2ecf20Sopenharmony_ci } 13568c2ecf20Sopenharmony_ci machine->trampolines_mapped = false; 13578c2ecf20Sopenharmony_ci 13588c2ecf20Sopenharmony_ci /* Find the kernel map using the '_stext' symbol */ 13598c2ecf20Sopenharmony_ci if (!kallsyms__get_function_start(kallsyms_filename, "_stext", &stext)) { 13608c2ecf20Sopenharmony_ci list_for_each_entry(new_map, &md.maps, node) { 13618c2ecf20Sopenharmony_ci if (stext >= new_map->start && stext < new_map->end) { 13628c2ecf20Sopenharmony_ci replacement_map = new_map; 13638c2ecf20Sopenharmony_ci break; 13648c2ecf20Sopenharmony_ci } 13658c2ecf20Sopenharmony_ci } 13668c2ecf20Sopenharmony_ci } 13678c2ecf20Sopenharmony_ci 13688c2ecf20Sopenharmony_ci if (!replacement_map) 13698c2ecf20Sopenharmony_ci replacement_map = list_entry(md.maps.next, struct map, node); 13708c2ecf20Sopenharmony_ci 13718c2ecf20Sopenharmony_ci /* Add new maps */ 13728c2ecf20Sopenharmony_ci while (!list_empty(&md.maps)) { 13738c2ecf20Sopenharmony_ci new_map = list_entry(md.maps.next, struct map, node); 13748c2ecf20Sopenharmony_ci list_del_init(&new_map->node); 13758c2ecf20Sopenharmony_ci if (new_map == replacement_map) { 13768c2ecf20Sopenharmony_ci map->start = new_map->start; 13778c2ecf20Sopenharmony_ci map->end = new_map->end; 13788c2ecf20Sopenharmony_ci map->pgoff = new_map->pgoff; 13798c2ecf20Sopenharmony_ci map->map_ip = new_map->map_ip; 13808c2ecf20Sopenharmony_ci map->unmap_ip = new_map->unmap_ip; 13818c2ecf20Sopenharmony_ci /* Ensure maps are correctly ordered */ 13828c2ecf20Sopenharmony_ci map__get(map); 13838c2ecf20Sopenharmony_ci maps__remove(kmaps, map); 13848c2ecf20Sopenharmony_ci maps__insert(kmaps, map); 13858c2ecf20Sopenharmony_ci map__put(map); 13868c2ecf20Sopenharmony_ci map__put(new_map); 13878c2ecf20Sopenharmony_ci } else { 13888c2ecf20Sopenharmony_ci /* 13898c2ecf20Sopenharmony_ci * Merge kcore map into existing maps, 13908c2ecf20Sopenharmony_ci * and ensure that current maps (eBPF) 13918c2ecf20Sopenharmony_ci * stay intact. 13928c2ecf20Sopenharmony_ci */ 13938c2ecf20Sopenharmony_ci if (maps__merge_in(kmaps, new_map)) 13948c2ecf20Sopenharmony_ci goto out_err; 13958c2ecf20Sopenharmony_ci } 13968c2ecf20Sopenharmony_ci } 13978c2ecf20Sopenharmony_ci 13988c2ecf20Sopenharmony_ci if (machine__is(machine, "x86_64")) { 13998c2ecf20Sopenharmony_ci u64 addr; 14008c2ecf20Sopenharmony_ci 14018c2ecf20Sopenharmony_ci /* 14028c2ecf20Sopenharmony_ci * If one of the corresponding symbols is there, assume the 14038c2ecf20Sopenharmony_ci * entry trampoline maps are too. 14048c2ecf20Sopenharmony_ci */ 14058c2ecf20Sopenharmony_ci if (!kallsyms__get_function_start(kallsyms_filename, 14068c2ecf20Sopenharmony_ci ENTRY_TRAMPOLINE_NAME, 14078c2ecf20Sopenharmony_ci &addr)) 14088c2ecf20Sopenharmony_ci machine->trampolines_mapped = true; 14098c2ecf20Sopenharmony_ci } 14108c2ecf20Sopenharmony_ci 14118c2ecf20Sopenharmony_ci /* 14128c2ecf20Sopenharmony_ci * Set the data type and long name so that kcore can be read via 14138c2ecf20Sopenharmony_ci * dso__data_read_addr(). 14148c2ecf20Sopenharmony_ci */ 14158c2ecf20Sopenharmony_ci if (dso->kernel == DSO_SPACE__KERNEL_GUEST) 14168c2ecf20Sopenharmony_ci dso->binary_type = DSO_BINARY_TYPE__GUEST_KCORE; 14178c2ecf20Sopenharmony_ci else 14188c2ecf20Sopenharmony_ci dso->binary_type = DSO_BINARY_TYPE__KCORE; 14198c2ecf20Sopenharmony_ci dso__set_long_name(dso, strdup(kcore_filename), true); 14208c2ecf20Sopenharmony_ci 14218c2ecf20Sopenharmony_ci close(fd); 14228c2ecf20Sopenharmony_ci 14238c2ecf20Sopenharmony_ci if (map->prot & PROT_EXEC) 14248c2ecf20Sopenharmony_ci pr_debug("Using %s for kernel object code\n", kcore_filename); 14258c2ecf20Sopenharmony_ci else 14268c2ecf20Sopenharmony_ci pr_debug("Using %s for kernel data\n", kcore_filename); 14278c2ecf20Sopenharmony_ci 14288c2ecf20Sopenharmony_ci return 0; 14298c2ecf20Sopenharmony_ci 14308c2ecf20Sopenharmony_ciout_err: 14318c2ecf20Sopenharmony_ci while (!list_empty(&md.maps)) { 14328c2ecf20Sopenharmony_ci map = list_entry(md.maps.next, struct map, node); 14338c2ecf20Sopenharmony_ci list_del_init(&map->node); 14348c2ecf20Sopenharmony_ci map__put(map); 14358c2ecf20Sopenharmony_ci } 14368c2ecf20Sopenharmony_ci close(fd); 14378c2ecf20Sopenharmony_ci return -EINVAL; 14388c2ecf20Sopenharmony_ci} 14398c2ecf20Sopenharmony_ci 14408c2ecf20Sopenharmony_ci/* 14418c2ecf20Sopenharmony_ci * If the kernel is relocated at boot time, kallsyms won't match. Compute the 14428c2ecf20Sopenharmony_ci * delta based on the relocation reference symbol. 14438c2ecf20Sopenharmony_ci */ 14448c2ecf20Sopenharmony_cistatic int kallsyms__delta(struct kmap *kmap, const char *filename, u64 *delta) 14458c2ecf20Sopenharmony_ci{ 14468c2ecf20Sopenharmony_ci u64 addr; 14478c2ecf20Sopenharmony_ci 14488c2ecf20Sopenharmony_ci if (!kmap->ref_reloc_sym || !kmap->ref_reloc_sym->name) 14498c2ecf20Sopenharmony_ci return 0; 14508c2ecf20Sopenharmony_ci 14518c2ecf20Sopenharmony_ci if (kallsyms__get_function_start(filename, kmap->ref_reloc_sym->name, &addr)) 14528c2ecf20Sopenharmony_ci return -1; 14538c2ecf20Sopenharmony_ci 14548c2ecf20Sopenharmony_ci *delta = addr - kmap->ref_reloc_sym->addr; 14558c2ecf20Sopenharmony_ci return 0; 14568c2ecf20Sopenharmony_ci} 14578c2ecf20Sopenharmony_ci 14588c2ecf20Sopenharmony_ciint __dso__load_kallsyms(struct dso *dso, const char *filename, 14598c2ecf20Sopenharmony_ci struct map *map, bool no_kcore) 14608c2ecf20Sopenharmony_ci{ 14618c2ecf20Sopenharmony_ci struct kmap *kmap = map__kmap(map); 14628c2ecf20Sopenharmony_ci u64 delta = 0; 14638c2ecf20Sopenharmony_ci 14648c2ecf20Sopenharmony_ci if (symbol__restricted_filename(filename, "/proc/kallsyms")) 14658c2ecf20Sopenharmony_ci return -1; 14668c2ecf20Sopenharmony_ci 14678c2ecf20Sopenharmony_ci if (!kmap || !kmap->kmaps) 14688c2ecf20Sopenharmony_ci return -1; 14698c2ecf20Sopenharmony_ci 14708c2ecf20Sopenharmony_ci if (dso__load_all_kallsyms(dso, filename) < 0) 14718c2ecf20Sopenharmony_ci return -1; 14728c2ecf20Sopenharmony_ci 14738c2ecf20Sopenharmony_ci if (kallsyms__delta(kmap, filename, &delta)) 14748c2ecf20Sopenharmony_ci return -1; 14758c2ecf20Sopenharmony_ci 14768c2ecf20Sopenharmony_ci symbols__fixup_end(&dso->symbols, true); 14778c2ecf20Sopenharmony_ci symbols__fixup_duplicate(&dso->symbols); 14788c2ecf20Sopenharmony_ci 14798c2ecf20Sopenharmony_ci if (dso->kernel == DSO_SPACE__KERNEL_GUEST) 14808c2ecf20Sopenharmony_ci dso->symtab_type = DSO_BINARY_TYPE__GUEST_KALLSYMS; 14818c2ecf20Sopenharmony_ci else 14828c2ecf20Sopenharmony_ci dso->symtab_type = DSO_BINARY_TYPE__KALLSYMS; 14838c2ecf20Sopenharmony_ci 14848c2ecf20Sopenharmony_ci if (!no_kcore && !dso__load_kcore(dso, map, filename)) 14858c2ecf20Sopenharmony_ci return maps__split_kallsyms_for_kcore(kmap->kmaps, dso); 14868c2ecf20Sopenharmony_ci else 14878c2ecf20Sopenharmony_ci return maps__split_kallsyms(kmap->kmaps, dso, delta, map); 14888c2ecf20Sopenharmony_ci} 14898c2ecf20Sopenharmony_ci 14908c2ecf20Sopenharmony_ciint dso__load_kallsyms(struct dso *dso, const char *filename, 14918c2ecf20Sopenharmony_ci struct map *map) 14928c2ecf20Sopenharmony_ci{ 14938c2ecf20Sopenharmony_ci return __dso__load_kallsyms(dso, filename, map, false); 14948c2ecf20Sopenharmony_ci} 14958c2ecf20Sopenharmony_ci 14968c2ecf20Sopenharmony_cistatic int dso__load_perf_map(const char *map_path, struct dso *dso) 14978c2ecf20Sopenharmony_ci{ 14988c2ecf20Sopenharmony_ci char *line = NULL; 14998c2ecf20Sopenharmony_ci size_t n; 15008c2ecf20Sopenharmony_ci FILE *file; 15018c2ecf20Sopenharmony_ci int nr_syms = 0; 15028c2ecf20Sopenharmony_ci 15038c2ecf20Sopenharmony_ci file = fopen(map_path, "r"); 15048c2ecf20Sopenharmony_ci if (file == NULL) 15058c2ecf20Sopenharmony_ci goto out_failure; 15068c2ecf20Sopenharmony_ci 15078c2ecf20Sopenharmony_ci while (!feof(file)) { 15088c2ecf20Sopenharmony_ci u64 start, size; 15098c2ecf20Sopenharmony_ci struct symbol *sym; 15108c2ecf20Sopenharmony_ci int line_len, len; 15118c2ecf20Sopenharmony_ci 15128c2ecf20Sopenharmony_ci line_len = getline(&line, &n, file); 15138c2ecf20Sopenharmony_ci if (line_len < 0) 15148c2ecf20Sopenharmony_ci break; 15158c2ecf20Sopenharmony_ci 15168c2ecf20Sopenharmony_ci if (!line) 15178c2ecf20Sopenharmony_ci goto out_failure; 15188c2ecf20Sopenharmony_ci 15198c2ecf20Sopenharmony_ci line[--line_len] = '\0'; /* \n */ 15208c2ecf20Sopenharmony_ci 15218c2ecf20Sopenharmony_ci len = hex2u64(line, &start); 15228c2ecf20Sopenharmony_ci 15238c2ecf20Sopenharmony_ci len++; 15248c2ecf20Sopenharmony_ci if (len + 2 >= line_len) 15258c2ecf20Sopenharmony_ci continue; 15268c2ecf20Sopenharmony_ci 15278c2ecf20Sopenharmony_ci len += hex2u64(line + len, &size); 15288c2ecf20Sopenharmony_ci 15298c2ecf20Sopenharmony_ci len++; 15308c2ecf20Sopenharmony_ci if (len + 2 >= line_len) 15318c2ecf20Sopenharmony_ci continue; 15328c2ecf20Sopenharmony_ci 15338c2ecf20Sopenharmony_ci sym = symbol__new(start, size, STB_GLOBAL, STT_FUNC, line + len); 15348c2ecf20Sopenharmony_ci 15358c2ecf20Sopenharmony_ci if (sym == NULL) 15368c2ecf20Sopenharmony_ci goto out_delete_line; 15378c2ecf20Sopenharmony_ci 15388c2ecf20Sopenharmony_ci symbols__insert(&dso->symbols, sym); 15398c2ecf20Sopenharmony_ci nr_syms++; 15408c2ecf20Sopenharmony_ci } 15418c2ecf20Sopenharmony_ci 15428c2ecf20Sopenharmony_ci free(line); 15438c2ecf20Sopenharmony_ci fclose(file); 15448c2ecf20Sopenharmony_ci 15458c2ecf20Sopenharmony_ci return nr_syms; 15468c2ecf20Sopenharmony_ci 15478c2ecf20Sopenharmony_ciout_delete_line: 15488c2ecf20Sopenharmony_ci free(line); 15498c2ecf20Sopenharmony_ciout_failure: 15508c2ecf20Sopenharmony_ci return -1; 15518c2ecf20Sopenharmony_ci} 15528c2ecf20Sopenharmony_ci 15538c2ecf20Sopenharmony_ci#ifdef HAVE_LIBBFD_SUPPORT 15548c2ecf20Sopenharmony_ci#define PACKAGE 'perf' 15558c2ecf20Sopenharmony_ci#include <bfd.h> 15568c2ecf20Sopenharmony_ci 15578c2ecf20Sopenharmony_cistatic int bfd_symbols__cmpvalue(const void *a, const void *b) 15588c2ecf20Sopenharmony_ci{ 15598c2ecf20Sopenharmony_ci const asymbol *as = *(const asymbol **)a, *bs = *(const asymbol **)b; 15608c2ecf20Sopenharmony_ci 15618c2ecf20Sopenharmony_ci if (bfd_asymbol_value(as) != bfd_asymbol_value(bs)) 15628c2ecf20Sopenharmony_ci return bfd_asymbol_value(as) - bfd_asymbol_value(bs); 15638c2ecf20Sopenharmony_ci 15648c2ecf20Sopenharmony_ci return bfd_asymbol_name(as)[0] - bfd_asymbol_name(bs)[0]; 15658c2ecf20Sopenharmony_ci} 15668c2ecf20Sopenharmony_ci 15678c2ecf20Sopenharmony_cistatic int bfd2elf_binding(asymbol *symbol) 15688c2ecf20Sopenharmony_ci{ 15698c2ecf20Sopenharmony_ci if (symbol->flags & BSF_WEAK) 15708c2ecf20Sopenharmony_ci return STB_WEAK; 15718c2ecf20Sopenharmony_ci if (symbol->flags & BSF_GLOBAL) 15728c2ecf20Sopenharmony_ci return STB_GLOBAL; 15738c2ecf20Sopenharmony_ci if (symbol->flags & BSF_LOCAL) 15748c2ecf20Sopenharmony_ci return STB_LOCAL; 15758c2ecf20Sopenharmony_ci return -1; 15768c2ecf20Sopenharmony_ci} 15778c2ecf20Sopenharmony_ci 15788c2ecf20Sopenharmony_ciint dso__load_bfd_symbols(struct dso *dso, const char *debugfile) 15798c2ecf20Sopenharmony_ci{ 15808c2ecf20Sopenharmony_ci int err = -1; 15818c2ecf20Sopenharmony_ci long symbols_size, symbols_count, i; 15828c2ecf20Sopenharmony_ci asection *section; 15838c2ecf20Sopenharmony_ci asymbol **symbols, *sym; 15848c2ecf20Sopenharmony_ci struct symbol *symbol; 15858c2ecf20Sopenharmony_ci bfd *abfd; 15868c2ecf20Sopenharmony_ci u64 start, len; 15878c2ecf20Sopenharmony_ci 15888c2ecf20Sopenharmony_ci abfd = bfd_openr(dso->long_name, NULL); 15898c2ecf20Sopenharmony_ci if (!abfd) 15908c2ecf20Sopenharmony_ci return -1; 15918c2ecf20Sopenharmony_ci 15928c2ecf20Sopenharmony_ci if (!bfd_check_format(abfd, bfd_object)) { 15938c2ecf20Sopenharmony_ci pr_debug2("%s: cannot read %s bfd file.\n", __func__, 15948c2ecf20Sopenharmony_ci dso->long_name); 15958c2ecf20Sopenharmony_ci goto out_close; 15968c2ecf20Sopenharmony_ci } 15978c2ecf20Sopenharmony_ci 15988c2ecf20Sopenharmony_ci if (bfd_get_flavour(abfd) == bfd_target_elf_flavour) 15998c2ecf20Sopenharmony_ci goto out_close; 16008c2ecf20Sopenharmony_ci 16018c2ecf20Sopenharmony_ci section = bfd_get_section_by_name(abfd, ".text"); 16028c2ecf20Sopenharmony_ci if (section) 16038c2ecf20Sopenharmony_ci dso->text_offset = section->vma - section->filepos; 16048c2ecf20Sopenharmony_ci 16058c2ecf20Sopenharmony_ci bfd_close(abfd); 16068c2ecf20Sopenharmony_ci 16078c2ecf20Sopenharmony_ci abfd = bfd_openr(debugfile, NULL); 16088c2ecf20Sopenharmony_ci if (!abfd) 16098c2ecf20Sopenharmony_ci return -1; 16108c2ecf20Sopenharmony_ci 16118c2ecf20Sopenharmony_ci if (!bfd_check_format(abfd, bfd_object)) { 16128c2ecf20Sopenharmony_ci pr_debug2("%s: cannot read %s bfd file.\n", __func__, 16138c2ecf20Sopenharmony_ci debugfile); 16148c2ecf20Sopenharmony_ci goto out_close; 16158c2ecf20Sopenharmony_ci } 16168c2ecf20Sopenharmony_ci 16178c2ecf20Sopenharmony_ci if (bfd_get_flavour(abfd) == bfd_target_elf_flavour) 16188c2ecf20Sopenharmony_ci goto out_close; 16198c2ecf20Sopenharmony_ci 16208c2ecf20Sopenharmony_ci symbols_size = bfd_get_symtab_upper_bound(abfd); 16218c2ecf20Sopenharmony_ci if (symbols_size == 0) { 16228c2ecf20Sopenharmony_ci bfd_close(abfd); 16238c2ecf20Sopenharmony_ci return 0; 16248c2ecf20Sopenharmony_ci } 16258c2ecf20Sopenharmony_ci 16268c2ecf20Sopenharmony_ci if (symbols_size < 0) 16278c2ecf20Sopenharmony_ci goto out_close; 16288c2ecf20Sopenharmony_ci 16298c2ecf20Sopenharmony_ci symbols = malloc(symbols_size); 16308c2ecf20Sopenharmony_ci if (!symbols) 16318c2ecf20Sopenharmony_ci goto out_close; 16328c2ecf20Sopenharmony_ci 16338c2ecf20Sopenharmony_ci symbols_count = bfd_canonicalize_symtab(abfd, symbols); 16348c2ecf20Sopenharmony_ci if (symbols_count < 0) 16358c2ecf20Sopenharmony_ci goto out_free; 16368c2ecf20Sopenharmony_ci 16378c2ecf20Sopenharmony_ci qsort(symbols, symbols_count, sizeof(asymbol *), bfd_symbols__cmpvalue); 16388c2ecf20Sopenharmony_ci 16398c2ecf20Sopenharmony_ci#ifdef bfd_get_section 16408c2ecf20Sopenharmony_ci#define bfd_asymbol_section bfd_get_section 16418c2ecf20Sopenharmony_ci#endif 16428c2ecf20Sopenharmony_ci for (i = 0; i < symbols_count; ++i) { 16438c2ecf20Sopenharmony_ci sym = symbols[i]; 16448c2ecf20Sopenharmony_ci section = bfd_asymbol_section(sym); 16458c2ecf20Sopenharmony_ci if (bfd2elf_binding(sym) < 0) 16468c2ecf20Sopenharmony_ci continue; 16478c2ecf20Sopenharmony_ci 16488c2ecf20Sopenharmony_ci while (i + 1 < symbols_count && 16498c2ecf20Sopenharmony_ci bfd_asymbol_section(symbols[i + 1]) == section && 16508c2ecf20Sopenharmony_ci bfd2elf_binding(symbols[i + 1]) < 0) 16518c2ecf20Sopenharmony_ci i++; 16528c2ecf20Sopenharmony_ci 16538c2ecf20Sopenharmony_ci if (i + 1 < symbols_count && 16548c2ecf20Sopenharmony_ci bfd_asymbol_section(symbols[i + 1]) == section) 16558c2ecf20Sopenharmony_ci len = symbols[i + 1]->value - sym->value; 16568c2ecf20Sopenharmony_ci else 16578c2ecf20Sopenharmony_ci len = section->size - sym->value; 16588c2ecf20Sopenharmony_ci 16598c2ecf20Sopenharmony_ci start = bfd_asymbol_value(sym) - dso->text_offset; 16608c2ecf20Sopenharmony_ci symbol = symbol__new(start, len, bfd2elf_binding(sym), STT_FUNC, 16618c2ecf20Sopenharmony_ci bfd_asymbol_name(sym)); 16628c2ecf20Sopenharmony_ci if (!symbol) 16638c2ecf20Sopenharmony_ci goto out_free; 16648c2ecf20Sopenharmony_ci 16658c2ecf20Sopenharmony_ci symbols__insert(&dso->symbols, symbol); 16668c2ecf20Sopenharmony_ci } 16678c2ecf20Sopenharmony_ci#ifdef bfd_get_section 16688c2ecf20Sopenharmony_ci#undef bfd_asymbol_section 16698c2ecf20Sopenharmony_ci#endif 16708c2ecf20Sopenharmony_ci 16718c2ecf20Sopenharmony_ci symbols__fixup_end(&dso->symbols, false); 16728c2ecf20Sopenharmony_ci symbols__fixup_duplicate(&dso->symbols); 16738c2ecf20Sopenharmony_ci dso->adjust_symbols = 1; 16748c2ecf20Sopenharmony_ci 16758c2ecf20Sopenharmony_ci err = 0; 16768c2ecf20Sopenharmony_ciout_free: 16778c2ecf20Sopenharmony_ci free(symbols); 16788c2ecf20Sopenharmony_ciout_close: 16798c2ecf20Sopenharmony_ci bfd_close(abfd); 16808c2ecf20Sopenharmony_ci return err; 16818c2ecf20Sopenharmony_ci} 16828c2ecf20Sopenharmony_ci#endif 16838c2ecf20Sopenharmony_ci 16848c2ecf20Sopenharmony_cistatic bool dso__is_compatible_symtab_type(struct dso *dso, bool kmod, 16858c2ecf20Sopenharmony_ci enum dso_binary_type type) 16868c2ecf20Sopenharmony_ci{ 16878c2ecf20Sopenharmony_ci switch (type) { 16888c2ecf20Sopenharmony_ci case DSO_BINARY_TYPE__JAVA_JIT: 16898c2ecf20Sopenharmony_ci case DSO_BINARY_TYPE__DEBUGLINK: 16908c2ecf20Sopenharmony_ci case DSO_BINARY_TYPE__SYSTEM_PATH_DSO: 16918c2ecf20Sopenharmony_ci case DSO_BINARY_TYPE__FEDORA_DEBUGINFO: 16928c2ecf20Sopenharmony_ci case DSO_BINARY_TYPE__UBUNTU_DEBUGINFO: 16938c2ecf20Sopenharmony_ci case DSO_BINARY_TYPE__MIXEDUP_UBUNTU_DEBUGINFO: 16948c2ecf20Sopenharmony_ci case DSO_BINARY_TYPE__BUILDID_DEBUGINFO: 16958c2ecf20Sopenharmony_ci case DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO: 16968c2ecf20Sopenharmony_ci return !kmod && dso->kernel == DSO_SPACE__USER; 16978c2ecf20Sopenharmony_ci 16988c2ecf20Sopenharmony_ci case DSO_BINARY_TYPE__KALLSYMS: 16998c2ecf20Sopenharmony_ci case DSO_BINARY_TYPE__VMLINUX: 17008c2ecf20Sopenharmony_ci case DSO_BINARY_TYPE__KCORE: 17018c2ecf20Sopenharmony_ci return dso->kernel == DSO_SPACE__KERNEL; 17028c2ecf20Sopenharmony_ci 17038c2ecf20Sopenharmony_ci case DSO_BINARY_TYPE__GUEST_KALLSYMS: 17048c2ecf20Sopenharmony_ci case DSO_BINARY_TYPE__GUEST_VMLINUX: 17058c2ecf20Sopenharmony_ci case DSO_BINARY_TYPE__GUEST_KCORE: 17068c2ecf20Sopenharmony_ci return dso->kernel == DSO_SPACE__KERNEL_GUEST; 17078c2ecf20Sopenharmony_ci 17088c2ecf20Sopenharmony_ci case DSO_BINARY_TYPE__GUEST_KMODULE: 17098c2ecf20Sopenharmony_ci case DSO_BINARY_TYPE__GUEST_KMODULE_COMP: 17108c2ecf20Sopenharmony_ci case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE: 17118c2ecf20Sopenharmony_ci case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP: 17128c2ecf20Sopenharmony_ci /* 17138c2ecf20Sopenharmony_ci * kernel modules know their symtab type - it's set when 17148c2ecf20Sopenharmony_ci * creating a module dso in machine__addnew_module_map(). 17158c2ecf20Sopenharmony_ci */ 17168c2ecf20Sopenharmony_ci return kmod && dso->symtab_type == type; 17178c2ecf20Sopenharmony_ci 17188c2ecf20Sopenharmony_ci case DSO_BINARY_TYPE__BUILD_ID_CACHE: 17198c2ecf20Sopenharmony_ci case DSO_BINARY_TYPE__BUILD_ID_CACHE_DEBUGINFO: 17208c2ecf20Sopenharmony_ci return true; 17218c2ecf20Sopenharmony_ci 17228c2ecf20Sopenharmony_ci case DSO_BINARY_TYPE__BPF_PROG_INFO: 17238c2ecf20Sopenharmony_ci case DSO_BINARY_TYPE__BPF_IMAGE: 17248c2ecf20Sopenharmony_ci case DSO_BINARY_TYPE__OOL: 17258c2ecf20Sopenharmony_ci case DSO_BINARY_TYPE__NOT_FOUND: 17268c2ecf20Sopenharmony_ci default: 17278c2ecf20Sopenharmony_ci return false; 17288c2ecf20Sopenharmony_ci } 17298c2ecf20Sopenharmony_ci} 17308c2ecf20Sopenharmony_ci 17318c2ecf20Sopenharmony_ci/* Checks for the existence of the perf-<pid>.map file in two different 17328c2ecf20Sopenharmony_ci * locations. First, if the process is a separate mount namespace, check in 17338c2ecf20Sopenharmony_ci * that namespace using the pid of the innermost pid namespace. If's not in a 17348c2ecf20Sopenharmony_ci * namespace, or the file can't be found there, try in the mount namespace of 17358c2ecf20Sopenharmony_ci * the tracing process using our view of its pid. 17368c2ecf20Sopenharmony_ci */ 17378c2ecf20Sopenharmony_cistatic int dso__find_perf_map(char *filebuf, size_t bufsz, 17388c2ecf20Sopenharmony_ci struct nsinfo **nsip) 17398c2ecf20Sopenharmony_ci{ 17408c2ecf20Sopenharmony_ci struct nscookie nsc; 17418c2ecf20Sopenharmony_ci struct nsinfo *nsi; 17428c2ecf20Sopenharmony_ci struct nsinfo *nnsi; 17438c2ecf20Sopenharmony_ci int rc = -1; 17448c2ecf20Sopenharmony_ci 17458c2ecf20Sopenharmony_ci nsi = *nsip; 17468c2ecf20Sopenharmony_ci 17478c2ecf20Sopenharmony_ci if (nsi->need_setns) { 17488c2ecf20Sopenharmony_ci snprintf(filebuf, bufsz, "/tmp/perf-%d.map", nsi->nstgid); 17498c2ecf20Sopenharmony_ci nsinfo__mountns_enter(nsi, &nsc); 17508c2ecf20Sopenharmony_ci rc = access(filebuf, R_OK); 17518c2ecf20Sopenharmony_ci nsinfo__mountns_exit(&nsc); 17528c2ecf20Sopenharmony_ci if (rc == 0) 17538c2ecf20Sopenharmony_ci return rc; 17548c2ecf20Sopenharmony_ci } 17558c2ecf20Sopenharmony_ci 17568c2ecf20Sopenharmony_ci nnsi = nsinfo__copy(nsi); 17578c2ecf20Sopenharmony_ci if (nnsi) { 17588c2ecf20Sopenharmony_ci nsinfo__put(nsi); 17598c2ecf20Sopenharmony_ci 17608c2ecf20Sopenharmony_ci nnsi->need_setns = false; 17618c2ecf20Sopenharmony_ci snprintf(filebuf, bufsz, "/tmp/perf-%d.map", nnsi->tgid); 17628c2ecf20Sopenharmony_ci *nsip = nnsi; 17638c2ecf20Sopenharmony_ci rc = 0; 17648c2ecf20Sopenharmony_ci } 17658c2ecf20Sopenharmony_ci 17668c2ecf20Sopenharmony_ci return rc; 17678c2ecf20Sopenharmony_ci} 17688c2ecf20Sopenharmony_ci 17698c2ecf20Sopenharmony_ciint dso__load(struct dso *dso, struct map *map) 17708c2ecf20Sopenharmony_ci{ 17718c2ecf20Sopenharmony_ci char *name; 17728c2ecf20Sopenharmony_ci int ret = -1; 17738c2ecf20Sopenharmony_ci u_int i; 17748c2ecf20Sopenharmony_ci struct machine *machine = NULL; 17758c2ecf20Sopenharmony_ci char *root_dir = (char *) ""; 17768c2ecf20Sopenharmony_ci int ss_pos = 0; 17778c2ecf20Sopenharmony_ci struct symsrc ss_[2]; 17788c2ecf20Sopenharmony_ci struct symsrc *syms_ss = NULL, *runtime_ss = NULL; 17798c2ecf20Sopenharmony_ci bool kmod; 17808c2ecf20Sopenharmony_ci bool perfmap; 17818c2ecf20Sopenharmony_ci struct build_id bid; 17828c2ecf20Sopenharmony_ci struct nscookie nsc; 17838c2ecf20Sopenharmony_ci char newmapname[PATH_MAX]; 17848c2ecf20Sopenharmony_ci const char *map_path = dso->long_name; 17858c2ecf20Sopenharmony_ci 17868c2ecf20Sopenharmony_ci perfmap = strncmp(dso->name, "/tmp/perf-", 10) == 0; 17878c2ecf20Sopenharmony_ci if (perfmap) { 17888c2ecf20Sopenharmony_ci if (dso->nsinfo && (dso__find_perf_map(newmapname, 17898c2ecf20Sopenharmony_ci sizeof(newmapname), &dso->nsinfo) == 0)) { 17908c2ecf20Sopenharmony_ci map_path = newmapname; 17918c2ecf20Sopenharmony_ci } 17928c2ecf20Sopenharmony_ci } 17938c2ecf20Sopenharmony_ci 17948c2ecf20Sopenharmony_ci nsinfo__mountns_enter(dso->nsinfo, &nsc); 17958c2ecf20Sopenharmony_ci pthread_mutex_lock(&dso->lock); 17968c2ecf20Sopenharmony_ci 17978c2ecf20Sopenharmony_ci /* check again under the dso->lock */ 17988c2ecf20Sopenharmony_ci if (dso__loaded(dso)) { 17998c2ecf20Sopenharmony_ci ret = 1; 18008c2ecf20Sopenharmony_ci goto out; 18018c2ecf20Sopenharmony_ci } 18028c2ecf20Sopenharmony_ci 18038c2ecf20Sopenharmony_ci kmod = dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE || 18048c2ecf20Sopenharmony_ci dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP || 18058c2ecf20Sopenharmony_ci dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE || 18068c2ecf20Sopenharmony_ci dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE_COMP; 18078c2ecf20Sopenharmony_ci 18088c2ecf20Sopenharmony_ci if (dso->kernel && !kmod) { 18098c2ecf20Sopenharmony_ci if (dso->kernel == DSO_SPACE__KERNEL) 18108c2ecf20Sopenharmony_ci ret = dso__load_kernel_sym(dso, map); 18118c2ecf20Sopenharmony_ci else if (dso->kernel == DSO_SPACE__KERNEL_GUEST) 18128c2ecf20Sopenharmony_ci ret = dso__load_guest_kernel_sym(dso, map); 18138c2ecf20Sopenharmony_ci 18148c2ecf20Sopenharmony_ci machine = map__kmaps(map)->machine; 18158c2ecf20Sopenharmony_ci if (machine__is(machine, "x86_64")) 18168c2ecf20Sopenharmony_ci machine__map_x86_64_entry_trampolines(machine, dso); 18178c2ecf20Sopenharmony_ci goto out; 18188c2ecf20Sopenharmony_ci } 18198c2ecf20Sopenharmony_ci 18208c2ecf20Sopenharmony_ci dso->adjust_symbols = 0; 18218c2ecf20Sopenharmony_ci 18228c2ecf20Sopenharmony_ci if (perfmap) { 18238c2ecf20Sopenharmony_ci ret = dso__load_perf_map(map_path, dso); 18248c2ecf20Sopenharmony_ci dso->symtab_type = ret > 0 ? DSO_BINARY_TYPE__JAVA_JIT : 18258c2ecf20Sopenharmony_ci DSO_BINARY_TYPE__NOT_FOUND; 18268c2ecf20Sopenharmony_ci goto out; 18278c2ecf20Sopenharmony_ci } 18288c2ecf20Sopenharmony_ci 18298c2ecf20Sopenharmony_ci if (machine) 18308c2ecf20Sopenharmony_ci root_dir = machine->root_dir; 18318c2ecf20Sopenharmony_ci 18328c2ecf20Sopenharmony_ci name = malloc(PATH_MAX); 18338c2ecf20Sopenharmony_ci if (!name) 18348c2ecf20Sopenharmony_ci goto out; 18358c2ecf20Sopenharmony_ci 18368c2ecf20Sopenharmony_ci /* 18378c2ecf20Sopenharmony_ci * Read the build id if possible. This is required for 18388c2ecf20Sopenharmony_ci * DSO_BINARY_TYPE__BUILDID_DEBUGINFO to work 18398c2ecf20Sopenharmony_ci */ 18408c2ecf20Sopenharmony_ci if (!dso->has_build_id && 18418c2ecf20Sopenharmony_ci is_regular_file(dso->long_name)) { 18428c2ecf20Sopenharmony_ci __symbol__join_symfs(name, PATH_MAX, dso->long_name); 18438c2ecf20Sopenharmony_ci if (filename__read_build_id(name, &bid) > 0) 18448c2ecf20Sopenharmony_ci dso__set_build_id(dso, &bid); 18458c2ecf20Sopenharmony_ci } 18468c2ecf20Sopenharmony_ci 18478c2ecf20Sopenharmony_ci /* 18488c2ecf20Sopenharmony_ci * Iterate over candidate debug images. 18498c2ecf20Sopenharmony_ci * Keep track of "interesting" ones (those which have a symtab, dynsym, 18508c2ecf20Sopenharmony_ci * and/or opd section) for processing. 18518c2ecf20Sopenharmony_ci */ 18528c2ecf20Sopenharmony_ci for (i = 0; i < DSO_BINARY_TYPE__SYMTAB_CNT; i++) { 18538c2ecf20Sopenharmony_ci struct symsrc *ss = &ss_[ss_pos]; 18548c2ecf20Sopenharmony_ci bool next_slot = false; 18558c2ecf20Sopenharmony_ci bool is_reg; 18568c2ecf20Sopenharmony_ci bool nsexit; 18578c2ecf20Sopenharmony_ci int bfdrc = -1; 18588c2ecf20Sopenharmony_ci int sirc = -1; 18598c2ecf20Sopenharmony_ci 18608c2ecf20Sopenharmony_ci enum dso_binary_type symtab_type = binary_type_symtab[i]; 18618c2ecf20Sopenharmony_ci 18628c2ecf20Sopenharmony_ci nsexit = (symtab_type == DSO_BINARY_TYPE__BUILD_ID_CACHE || 18638c2ecf20Sopenharmony_ci symtab_type == DSO_BINARY_TYPE__BUILD_ID_CACHE_DEBUGINFO); 18648c2ecf20Sopenharmony_ci 18658c2ecf20Sopenharmony_ci if (!dso__is_compatible_symtab_type(dso, kmod, symtab_type)) 18668c2ecf20Sopenharmony_ci continue; 18678c2ecf20Sopenharmony_ci 18688c2ecf20Sopenharmony_ci if (dso__read_binary_type_filename(dso, symtab_type, 18698c2ecf20Sopenharmony_ci root_dir, name, PATH_MAX)) 18708c2ecf20Sopenharmony_ci continue; 18718c2ecf20Sopenharmony_ci 18728c2ecf20Sopenharmony_ci if (nsexit) 18738c2ecf20Sopenharmony_ci nsinfo__mountns_exit(&nsc); 18748c2ecf20Sopenharmony_ci 18758c2ecf20Sopenharmony_ci is_reg = is_regular_file(name); 18768c2ecf20Sopenharmony_ci#ifdef HAVE_LIBBFD_SUPPORT 18778c2ecf20Sopenharmony_ci if (is_reg) 18788c2ecf20Sopenharmony_ci bfdrc = dso__load_bfd_symbols(dso, name); 18798c2ecf20Sopenharmony_ci#endif 18808c2ecf20Sopenharmony_ci if (is_reg && bfdrc < 0) 18818c2ecf20Sopenharmony_ci sirc = symsrc__init(ss, dso, name, symtab_type); 18828c2ecf20Sopenharmony_ci 18838c2ecf20Sopenharmony_ci if (nsexit) 18848c2ecf20Sopenharmony_ci nsinfo__mountns_enter(dso->nsinfo, &nsc); 18858c2ecf20Sopenharmony_ci 18868c2ecf20Sopenharmony_ci if (bfdrc == 0) { 18878c2ecf20Sopenharmony_ci ret = 0; 18888c2ecf20Sopenharmony_ci break; 18898c2ecf20Sopenharmony_ci } 18908c2ecf20Sopenharmony_ci 18918c2ecf20Sopenharmony_ci if (!is_reg || sirc < 0) 18928c2ecf20Sopenharmony_ci continue; 18938c2ecf20Sopenharmony_ci 18948c2ecf20Sopenharmony_ci if (!syms_ss && symsrc__has_symtab(ss)) { 18958c2ecf20Sopenharmony_ci syms_ss = ss; 18968c2ecf20Sopenharmony_ci next_slot = true; 18978c2ecf20Sopenharmony_ci if (!dso->symsrc_filename) 18988c2ecf20Sopenharmony_ci dso->symsrc_filename = strdup(name); 18998c2ecf20Sopenharmony_ci } 19008c2ecf20Sopenharmony_ci 19018c2ecf20Sopenharmony_ci if (!runtime_ss && symsrc__possibly_runtime(ss)) { 19028c2ecf20Sopenharmony_ci runtime_ss = ss; 19038c2ecf20Sopenharmony_ci next_slot = true; 19048c2ecf20Sopenharmony_ci } 19058c2ecf20Sopenharmony_ci 19068c2ecf20Sopenharmony_ci if (next_slot) { 19078c2ecf20Sopenharmony_ci ss_pos++; 19088c2ecf20Sopenharmony_ci 19098c2ecf20Sopenharmony_ci if (syms_ss && runtime_ss) 19108c2ecf20Sopenharmony_ci break; 19118c2ecf20Sopenharmony_ci } else { 19128c2ecf20Sopenharmony_ci symsrc__destroy(ss); 19138c2ecf20Sopenharmony_ci } 19148c2ecf20Sopenharmony_ci 19158c2ecf20Sopenharmony_ci } 19168c2ecf20Sopenharmony_ci 19178c2ecf20Sopenharmony_ci if (!runtime_ss && !syms_ss) 19188c2ecf20Sopenharmony_ci goto out_free; 19198c2ecf20Sopenharmony_ci 19208c2ecf20Sopenharmony_ci if (runtime_ss && !syms_ss) { 19218c2ecf20Sopenharmony_ci syms_ss = runtime_ss; 19228c2ecf20Sopenharmony_ci } 19238c2ecf20Sopenharmony_ci 19248c2ecf20Sopenharmony_ci /* We'll have to hope for the best */ 19258c2ecf20Sopenharmony_ci if (!runtime_ss && syms_ss) 19268c2ecf20Sopenharmony_ci runtime_ss = syms_ss; 19278c2ecf20Sopenharmony_ci 19288c2ecf20Sopenharmony_ci if (syms_ss) 19298c2ecf20Sopenharmony_ci ret = dso__load_sym(dso, map, syms_ss, runtime_ss, kmod); 19308c2ecf20Sopenharmony_ci else 19318c2ecf20Sopenharmony_ci ret = -1; 19328c2ecf20Sopenharmony_ci 19338c2ecf20Sopenharmony_ci if (ret > 0) { 19348c2ecf20Sopenharmony_ci int nr_plt; 19358c2ecf20Sopenharmony_ci 19368c2ecf20Sopenharmony_ci nr_plt = dso__synthesize_plt_symbols(dso, runtime_ss); 19378c2ecf20Sopenharmony_ci if (nr_plt > 0) 19388c2ecf20Sopenharmony_ci ret += nr_plt; 19398c2ecf20Sopenharmony_ci } 19408c2ecf20Sopenharmony_ci 19418c2ecf20Sopenharmony_ci for (; ss_pos > 0; ss_pos--) 19428c2ecf20Sopenharmony_ci symsrc__destroy(&ss_[ss_pos - 1]); 19438c2ecf20Sopenharmony_ciout_free: 19448c2ecf20Sopenharmony_ci free(name); 19458c2ecf20Sopenharmony_ci if (ret < 0 && strstr(dso->name, " (deleted)") != NULL) 19468c2ecf20Sopenharmony_ci ret = 0; 19478c2ecf20Sopenharmony_ciout: 19488c2ecf20Sopenharmony_ci dso__set_loaded(dso); 19498c2ecf20Sopenharmony_ci pthread_mutex_unlock(&dso->lock); 19508c2ecf20Sopenharmony_ci nsinfo__mountns_exit(&nsc); 19518c2ecf20Sopenharmony_ci 19528c2ecf20Sopenharmony_ci return ret; 19538c2ecf20Sopenharmony_ci} 19548c2ecf20Sopenharmony_ci 19558c2ecf20Sopenharmony_cistatic int map__strcmp(const void *a, const void *b) 19568c2ecf20Sopenharmony_ci{ 19578c2ecf20Sopenharmony_ci const struct map *ma = *(const struct map **)a, *mb = *(const struct map **)b; 19588c2ecf20Sopenharmony_ci return strcmp(ma->dso->short_name, mb->dso->short_name); 19598c2ecf20Sopenharmony_ci} 19608c2ecf20Sopenharmony_ci 19618c2ecf20Sopenharmony_cistatic int map__strcmp_name(const void *name, const void *b) 19628c2ecf20Sopenharmony_ci{ 19638c2ecf20Sopenharmony_ci const struct map *map = *(const struct map **)b; 19648c2ecf20Sopenharmony_ci return strcmp(name, map->dso->short_name); 19658c2ecf20Sopenharmony_ci} 19668c2ecf20Sopenharmony_ci 19678c2ecf20Sopenharmony_civoid __maps__sort_by_name(struct maps *maps) 19688c2ecf20Sopenharmony_ci{ 19698c2ecf20Sopenharmony_ci qsort(maps->maps_by_name, maps->nr_maps, sizeof(struct map *), map__strcmp); 19708c2ecf20Sopenharmony_ci} 19718c2ecf20Sopenharmony_ci 19728c2ecf20Sopenharmony_cistatic int map__groups__sort_by_name_from_rbtree(struct maps *maps) 19738c2ecf20Sopenharmony_ci{ 19748c2ecf20Sopenharmony_ci struct map *map; 19758c2ecf20Sopenharmony_ci struct map **maps_by_name = realloc(maps->maps_by_name, maps->nr_maps * sizeof(map)); 19768c2ecf20Sopenharmony_ci int i = 0; 19778c2ecf20Sopenharmony_ci 19788c2ecf20Sopenharmony_ci if (maps_by_name == NULL) 19798c2ecf20Sopenharmony_ci return -1; 19808c2ecf20Sopenharmony_ci 19818c2ecf20Sopenharmony_ci maps->maps_by_name = maps_by_name; 19828c2ecf20Sopenharmony_ci maps->nr_maps_allocated = maps->nr_maps; 19838c2ecf20Sopenharmony_ci 19848c2ecf20Sopenharmony_ci maps__for_each_entry(maps, map) 19858c2ecf20Sopenharmony_ci maps_by_name[i++] = map; 19868c2ecf20Sopenharmony_ci 19878c2ecf20Sopenharmony_ci __maps__sort_by_name(maps); 19888c2ecf20Sopenharmony_ci return 0; 19898c2ecf20Sopenharmony_ci} 19908c2ecf20Sopenharmony_ci 19918c2ecf20Sopenharmony_cistatic struct map *__maps__find_by_name(struct maps *maps, const char *name) 19928c2ecf20Sopenharmony_ci{ 19938c2ecf20Sopenharmony_ci struct map **mapp; 19948c2ecf20Sopenharmony_ci 19958c2ecf20Sopenharmony_ci if (maps->maps_by_name == NULL && 19968c2ecf20Sopenharmony_ci map__groups__sort_by_name_from_rbtree(maps)) 19978c2ecf20Sopenharmony_ci return NULL; 19988c2ecf20Sopenharmony_ci 19998c2ecf20Sopenharmony_ci mapp = bsearch(name, maps->maps_by_name, maps->nr_maps, sizeof(*mapp), map__strcmp_name); 20008c2ecf20Sopenharmony_ci if (mapp) 20018c2ecf20Sopenharmony_ci return *mapp; 20028c2ecf20Sopenharmony_ci return NULL; 20038c2ecf20Sopenharmony_ci} 20048c2ecf20Sopenharmony_ci 20058c2ecf20Sopenharmony_cistruct map *maps__find_by_name(struct maps *maps, const char *name) 20068c2ecf20Sopenharmony_ci{ 20078c2ecf20Sopenharmony_ci struct map *map; 20088c2ecf20Sopenharmony_ci 20098c2ecf20Sopenharmony_ci down_read(&maps->lock); 20108c2ecf20Sopenharmony_ci 20118c2ecf20Sopenharmony_ci if (maps->last_search_by_name && strcmp(maps->last_search_by_name->dso->short_name, name) == 0) { 20128c2ecf20Sopenharmony_ci map = maps->last_search_by_name; 20138c2ecf20Sopenharmony_ci goto out_unlock; 20148c2ecf20Sopenharmony_ci } 20158c2ecf20Sopenharmony_ci /* 20168c2ecf20Sopenharmony_ci * If we have maps->maps_by_name, then the name isn't in the rbtree, 20178c2ecf20Sopenharmony_ci * as maps->maps_by_name mirrors the rbtree when lookups by name are 20188c2ecf20Sopenharmony_ci * made. 20198c2ecf20Sopenharmony_ci */ 20208c2ecf20Sopenharmony_ci map = __maps__find_by_name(maps, name); 20218c2ecf20Sopenharmony_ci if (map || maps->maps_by_name != NULL) 20228c2ecf20Sopenharmony_ci goto out_unlock; 20238c2ecf20Sopenharmony_ci 20248c2ecf20Sopenharmony_ci /* Fallback to traversing the rbtree... */ 20258c2ecf20Sopenharmony_ci maps__for_each_entry(maps, map) 20268c2ecf20Sopenharmony_ci if (strcmp(map->dso->short_name, name) == 0) { 20278c2ecf20Sopenharmony_ci maps->last_search_by_name = map; 20288c2ecf20Sopenharmony_ci goto out_unlock; 20298c2ecf20Sopenharmony_ci } 20308c2ecf20Sopenharmony_ci 20318c2ecf20Sopenharmony_ci map = NULL; 20328c2ecf20Sopenharmony_ci 20338c2ecf20Sopenharmony_ciout_unlock: 20348c2ecf20Sopenharmony_ci up_read(&maps->lock); 20358c2ecf20Sopenharmony_ci return map; 20368c2ecf20Sopenharmony_ci} 20378c2ecf20Sopenharmony_ci 20388c2ecf20Sopenharmony_ciint dso__load_vmlinux(struct dso *dso, struct map *map, 20398c2ecf20Sopenharmony_ci const char *vmlinux, bool vmlinux_allocated) 20408c2ecf20Sopenharmony_ci{ 20418c2ecf20Sopenharmony_ci int err = -1; 20428c2ecf20Sopenharmony_ci struct symsrc ss; 20438c2ecf20Sopenharmony_ci char symfs_vmlinux[PATH_MAX]; 20448c2ecf20Sopenharmony_ci enum dso_binary_type symtab_type; 20458c2ecf20Sopenharmony_ci 20468c2ecf20Sopenharmony_ci if (vmlinux[0] == '/') 20478c2ecf20Sopenharmony_ci snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s", vmlinux); 20488c2ecf20Sopenharmony_ci else 20498c2ecf20Sopenharmony_ci symbol__join_symfs(symfs_vmlinux, vmlinux); 20508c2ecf20Sopenharmony_ci 20518c2ecf20Sopenharmony_ci if (dso->kernel == DSO_SPACE__KERNEL_GUEST) 20528c2ecf20Sopenharmony_ci symtab_type = DSO_BINARY_TYPE__GUEST_VMLINUX; 20538c2ecf20Sopenharmony_ci else 20548c2ecf20Sopenharmony_ci symtab_type = DSO_BINARY_TYPE__VMLINUX; 20558c2ecf20Sopenharmony_ci 20568c2ecf20Sopenharmony_ci if (symsrc__init(&ss, dso, symfs_vmlinux, symtab_type)) 20578c2ecf20Sopenharmony_ci return -1; 20588c2ecf20Sopenharmony_ci 20598c2ecf20Sopenharmony_ci err = dso__load_sym(dso, map, &ss, &ss, 0); 20608c2ecf20Sopenharmony_ci symsrc__destroy(&ss); 20618c2ecf20Sopenharmony_ci 20628c2ecf20Sopenharmony_ci if (err > 0) { 20638c2ecf20Sopenharmony_ci if (dso->kernel == DSO_SPACE__KERNEL_GUEST) 20648c2ecf20Sopenharmony_ci dso->binary_type = DSO_BINARY_TYPE__GUEST_VMLINUX; 20658c2ecf20Sopenharmony_ci else 20668c2ecf20Sopenharmony_ci dso->binary_type = DSO_BINARY_TYPE__VMLINUX; 20678c2ecf20Sopenharmony_ci dso__set_long_name(dso, vmlinux, vmlinux_allocated); 20688c2ecf20Sopenharmony_ci dso__set_loaded(dso); 20698c2ecf20Sopenharmony_ci pr_debug("Using %s for symbols\n", symfs_vmlinux); 20708c2ecf20Sopenharmony_ci } 20718c2ecf20Sopenharmony_ci 20728c2ecf20Sopenharmony_ci return err; 20738c2ecf20Sopenharmony_ci} 20748c2ecf20Sopenharmony_ci 20758c2ecf20Sopenharmony_ciint dso__load_vmlinux_path(struct dso *dso, struct map *map) 20768c2ecf20Sopenharmony_ci{ 20778c2ecf20Sopenharmony_ci int i, err = 0; 20788c2ecf20Sopenharmony_ci char *filename = NULL; 20798c2ecf20Sopenharmony_ci 20808c2ecf20Sopenharmony_ci pr_debug("Looking at the vmlinux_path (%d entries long)\n", 20818c2ecf20Sopenharmony_ci vmlinux_path__nr_entries + 1); 20828c2ecf20Sopenharmony_ci 20838c2ecf20Sopenharmony_ci for (i = 0; i < vmlinux_path__nr_entries; ++i) { 20848c2ecf20Sopenharmony_ci err = dso__load_vmlinux(dso, map, vmlinux_path[i], false); 20858c2ecf20Sopenharmony_ci if (err > 0) 20868c2ecf20Sopenharmony_ci goto out; 20878c2ecf20Sopenharmony_ci } 20888c2ecf20Sopenharmony_ci 20898c2ecf20Sopenharmony_ci if (!symbol_conf.ignore_vmlinux_buildid) 20908c2ecf20Sopenharmony_ci filename = dso__build_id_filename(dso, NULL, 0, false); 20918c2ecf20Sopenharmony_ci if (filename != NULL) { 20928c2ecf20Sopenharmony_ci err = dso__load_vmlinux(dso, map, filename, true); 20938c2ecf20Sopenharmony_ci if (err > 0) 20948c2ecf20Sopenharmony_ci goto out; 20958c2ecf20Sopenharmony_ci free(filename); 20968c2ecf20Sopenharmony_ci } 20978c2ecf20Sopenharmony_ciout: 20988c2ecf20Sopenharmony_ci return err; 20998c2ecf20Sopenharmony_ci} 21008c2ecf20Sopenharmony_ci 21018c2ecf20Sopenharmony_cistatic bool visible_dir_filter(const char *name, struct dirent *d) 21028c2ecf20Sopenharmony_ci{ 21038c2ecf20Sopenharmony_ci if (d->d_type != DT_DIR) 21048c2ecf20Sopenharmony_ci return false; 21058c2ecf20Sopenharmony_ci return lsdir_no_dot_filter(name, d); 21068c2ecf20Sopenharmony_ci} 21078c2ecf20Sopenharmony_ci 21088c2ecf20Sopenharmony_cistatic int find_matching_kcore(struct map *map, char *dir, size_t dir_sz) 21098c2ecf20Sopenharmony_ci{ 21108c2ecf20Sopenharmony_ci char kallsyms_filename[PATH_MAX]; 21118c2ecf20Sopenharmony_ci int ret = -1; 21128c2ecf20Sopenharmony_ci struct strlist *dirs; 21138c2ecf20Sopenharmony_ci struct str_node *nd; 21148c2ecf20Sopenharmony_ci 21158c2ecf20Sopenharmony_ci dirs = lsdir(dir, visible_dir_filter); 21168c2ecf20Sopenharmony_ci if (!dirs) 21178c2ecf20Sopenharmony_ci return -1; 21188c2ecf20Sopenharmony_ci 21198c2ecf20Sopenharmony_ci strlist__for_each_entry(nd, dirs) { 21208c2ecf20Sopenharmony_ci scnprintf(kallsyms_filename, sizeof(kallsyms_filename), 21218c2ecf20Sopenharmony_ci "%s/%s/kallsyms", dir, nd->s); 21228c2ecf20Sopenharmony_ci if (!validate_kcore_addresses(kallsyms_filename, map)) { 21238c2ecf20Sopenharmony_ci strlcpy(dir, kallsyms_filename, dir_sz); 21248c2ecf20Sopenharmony_ci ret = 0; 21258c2ecf20Sopenharmony_ci break; 21268c2ecf20Sopenharmony_ci } 21278c2ecf20Sopenharmony_ci } 21288c2ecf20Sopenharmony_ci 21298c2ecf20Sopenharmony_ci strlist__delete(dirs); 21308c2ecf20Sopenharmony_ci 21318c2ecf20Sopenharmony_ci return ret; 21328c2ecf20Sopenharmony_ci} 21338c2ecf20Sopenharmony_ci 21348c2ecf20Sopenharmony_ci/* 21358c2ecf20Sopenharmony_ci * Use open(O_RDONLY) to check readability directly instead of access(R_OK) 21368c2ecf20Sopenharmony_ci * since access(R_OK) only checks with real UID/GID but open() use effective 21378c2ecf20Sopenharmony_ci * UID/GID and actual capabilities (e.g. /proc/kcore requires CAP_SYS_RAWIO). 21388c2ecf20Sopenharmony_ci */ 21398c2ecf20Sopenharmony_cistatic bool filename__readable(const char *file) 21408c2ecf20Sopenharmony_ci{ 21418c2ecf20Sopenharmony_ci int fd = open(file, O_RDONLY); 21428c2ecf20Sopenharmony_ci if (fd < 0) 21438c2ecf20Sopenharmony_ci return false; 21448c2ecf20Sopenharmony_ci close(fd); 21458c2ecf20Sopenharmony_ci return true; 21468c2ecf20Sopenharmony_ci} 21478c2ecf20Sopenharmony_ci 21488c2ecf20Sopenharmony_cistatic char *dso__find_kallsyms(struct dso *dso, struct map *map) 21498c2ecf20Sopenharmony_ci{ 21508c2ecf20Sopenharmony_ci struct build_id bid; 21518c2ecf20Sopenharmony_ci char sbuild_id[SBUILD_ID_SIZE]; 21528c2ecf20Sopenharmony_ci bool is_host = false; 21538c2ecf20Sopenharmony_ci char path[PATH_MAX]; 21548c2ecf20Sopenharmony_ci 21558c2ecf20Sopenharmony_ci if (!dso->has_build_id) { 21568c2ecf20Sopenharmony_ci /* 21578c2ecf20Sopenharmony_ci * Last resort, if we don't have a build-id and couldn't find 21588c2ecf20Sopenharmony_ci * any vmlinux file, try the running kernel kallsyms table. 21598c2ecf20Sopenharmony_ci */ 21608c2ecf20Sopenharmony_ci goto proc_kallsyms; 21618c2ecf20Sopenharmony_ci } 21628c2ecf20Sopenharmony_ci 21638c2ecf20Sopenharmony_ci if (sysfs__read_build_id("/sys/kernel/notes", &bid) == 0) 21648c2ecf20Sopenharmony_ci is_host = dso__build_id_equal(dso, &bid); 21658c2ecf20Sopenharmony_ci 21668c2ecf20Sopenharmony_ci /* Try a fast path for /proc/kallsyms if possible */ 21678c2ecf20Sopenharmony_ci if (is_host) { 21688c2ecf20Sopenharmony_ci /* 21698c2ecf20Sopenharmony_ci * Do not check the build-id cache, unless we know we cannot use 21708c2ecf20Sopenharmony_ci * /proc/kcore or module maps don't match to /proc/kallsyms. 21718c2ecf20Sopenharmony_ci * To check readability of /proc/kcore, do not use access(R_OK) 21728c2ecf20Sopenharmony_ci * since /proc/kcore requires CAP_SYS_RAWIO to read and access 21738c2ecf20Sopenharmony_ci * can't check it. 21748c2ecf20Sopenharmony_ci */ 21758c2ecf20Sopenharmony_ci if (filename__readable("/proc/kcore") && 21768c2ecf20Sopenharmony_ci !validate_kcore_addresses("/proc/kallsyms", map)) 21778c2ecf20Sopenharmony_ci goto proc_kallsyms; 21788c2ecf20Sopenharmony_ci } 21798c2ecf20Sopenharmony_ci 21808c2ecf20Sopenharmony_ci build_id__sprintf(&dso->bid, sbuild_id); 21818c2ecf20Sopenharmony_ci 21828c2ecf20Sopenharmony_ci /* Find kallsyms in build-id cache with kcore */ 21838c2ecf20Sopenharmony_ci scnprintf(path, sizeof(path), "%s/%s/%s", 21848c2ecf20Sopenharmony_ci buildid_dir, DSO__NAME_KCORE, sbuild_id); 21858c2ecf20Sopenharmony_ci 21868c2ecf20Sopenharmony_ci if (!find_matching_kcore(map, path, sizeof(path))) 21878c2ecf20Sopenharmony_ci return strdup(path); 21888c2ecf20Sopenharmony_ci 21898c2ecf20Sopenharmony_ci /* Use current /proc/kallsyms if possible */ 21908c2ecf20Sopenharmony_ci if (is_host) { 21918c2ecf20Sopenharmony_ciproc_kallsyms: 21928c2ecf20Sopenharmony_ci return strdup("/proc/kallsyms"); 21938c2ecf20Sopenharmony_ci } 21948c2ecf20Sopenharmony_ci 21958c2ecf20Sopenharmony_ci /* Finally, find a cache of kallsyms */ 21968c2ecf20Sopenharmony_ci if (!build_id_cache__kallsyms_path(sbuild_id, path, sizeof(path))) { 21978c2ecf20Sopenharmony_ci pr_err("No kallsyms or vmlinux with build-id %s was found\n", 21988c2ecf20Sopenharmony_ci sbuild_id); 21998c2ecf20Sopenharmony_ci return NULL; 22008c2ecf20Sopenharmony_ci } 22018c2ecf20Sopenharmony_ci 22028c2ecf20Sopenharmony_ci return strdup(path); 22038c2ecf20Sopenharmony_ci} 22048c2ecf20Sopenharmony_ci 22058c2ecf20Sopenharmony_cistatic int dso__load_kernel_sym(struct dso *dso, struct map *map) 22068c2ecf20Sopenharmony_ci{ 22078c2ecf20Sopenharmony_ci int err; 22088c2ecf20Sopenharmony_ci const char *kallsyms_filename = NULL; 22098c2ecf20Sopenharmony_ci char *kallsyms_allocated_filename = NULL; 22108c2ecf20Sopenharmony_ci /* 22118c2ecf20Sopenharmony_ci * Step 1: if the user specified a kallsyms or vmlinux filename, use 22128c2ecf20Sopenharmony_ci * it and only it, reporting errors to the user if it cannot be used. 22138c2ecf20Sopenharmony_ci * 22148c2ecf20Sopenharmony_ci * For instance, try to analyse an ARM perf.data file _without_ a 22158c2ecf20Sopenharmony_ci * build-id, or if the user specifies the wrong path to the right 22168c2ecf20Sopenharmony_ci * vmlinux file, obviously we can't fallback to another vmlinux (a 22178c2ecf20Sopenharmony_ci * x86_86 one, on the machine where analysis is being performed, say), 22188c2ecf20Sopenharmony_ci * or worse, /proc/kallsyms. 22198c2ecf20Sopenharmony_ci * 22208c2ecf20Sopenharmony_ci * If the specified file _has_ a build-id and there is a build-id 22218c2ecf20Sopenharmony_ci * section in the perf.data file, we will still do the expected 22228c2ecf20Sopenharmony_ci * validation in dso__load_vmlinux and will bail out if they don't 22238c2ecf20Sopenharmony_ci * match. 22248c2ecf20Sopenharmony_ci */ 22258c2ecf20Sopenharmony_ci if (symbol_conf.kallsyms_name != NULL) { 22268c2ecf20Sopenharmony_ci kallsyms_filename = symbol_conf.kallsyms_name; 22278c2ecf20Sopenharmony_ci goto do_kallsyms; 22288c2ecf20Sopenharmony_ci } 22298c2ecf20Sopenharmony_ci 22308c2ecf20Sopenharmony_ci if (!symbol_conf.ignore_vmlinux && symbol_conf.vmlinux_name != NULL) { 22318c2ecf20Sopenharmony_ci return dso__load_vmlinux(dso, map, symbol_conf.vmlinux_name, false); 22328c2ecf20Sopenharmony_ci } 22338c2ecf20Sopenharmony_ci 22348c2ecf20Sopenharmony_ci if (!symbol_conf.ignore_vmlinux && vmlinux_path != NULL) { 22358c2ecf20Sopenharmony_ci err = dso__load_vmlinux_path(dso, map); 22368c2ecf20Sopenharmony_ci if (err > 0) 22378c2ecf20Sopenharmony_ci return err; 22388c2ecf20Sopenharmony_ci } 22398c2ecf20Sopenharmony_ci 22408c2ecf20Sopenharmony_ci /* do not try local files if a symfs was given */ 22418c2ecf20Sopenharmony_ci if (symbol_conf.symfs[0] != 0) 22428c2ecf20Sopenharmony_ci return -1; 22438c2ecf20Sopenharmony_ci 22448c2ecf20Sopenharmony_ci kallsyms_allocated_filename = dso__find_kallsyms(dso, map); 22458c2ecf20Sopenharmony_ci if (!kallsyms_allocated_filename) 22468c2ecf20Sopenharmony_ci return -1; 22478c2ecf20Sopenharmony_ci 22488c2ecf20Sopenharmony_ci kallsyms_filename = kallsyms_allocated_filename; 22498c2ecf20Sopenharmony_ci 22508c2ecf20Sopenharmony_cido_kallsyms: 22518c2ecf20Sopenharmony_ci err = dso__load_kallsyms(dso, kallsyms_filename, map); 22528c2ecf20Sopenharmony_ci if (err > 0) 22538c2ecf20Sopenharmony_ci pr_debug("Using %s for symbols\n", kallsyms_filename); 22548c2ecf20Sopenharmony_ci free(kallsyms_allocated_filename); 22558c2ecf20Sopenharmony_ci 22568c2ecf20Sopenharmony_ci if (err > 0 && !dso__is_kcore(dso)) { 22578c2ecf20Sopenharmony_ci dso->binary_type = DSO_BINARY_TYPE__KALLSYMS; 22588c2ecf20Sopenharmony_ci dso__set_long_name(dso, DSO__NAME_KALLSYMS, false); 22598c2ecf20Sopenharmony_ci map__fixup_start(map); 22608c2ecf20Sopenharmony_ci map__fixup_end(map); 22618c2ecf20Sopenharmony_ci } 22628c2ecf20Sopenharmony_ci 22638c2ecf20Sopenharmony_ci return err; 22648c2ecf20Sopenharmony_ci} 22658c2ecf20Sopenharmony_ci 22668c2ecf20Sopenharmony_cistatic int dso__load_guest_kernel_sym(struct dso *dso, struct map *map) 22678c2ecf20Sopenharmony_ci{ 22688c2ecf20Sopenharmony_ci int err; 22698c2ecf20Sopenharmony_ci const char *kallsyms_filename = NULL; 22708c2ecf20Sopenharmony_ci struct machine *machine = map__kmaps(map)->machine; 22718c2ecf20Sopenharmony_ci char path[PATH_MAX]; 22728c2ecf20Sopenharmony_ci 22738c2ecf20Sopenharmony_ci if (machine__is_default_guest(machine)) { 22748c2ecf20Sopenharmony_ci /* 22758c2ecf20Sopenharmony_ci * if the user specified a vmlinux filename, use it and only 22768c2ecf20Sopenharmony_ci * it, reporting errors to the user if it cannot be used. 22778c2ecf20Sopenharmony_ci * Or use file guest_kallsyms inputted by user on commandline 22788c2ecf20Sopenharmony_ci */ 22798c2ecf20Sopenharmony_ci if (symbol_conf.default_guest_vmlinux_name != NULL) { 22808c2ecf20Sopenharmony_ci err = dso__load_vmlinux(dso, map, 22818c2ecf20Sopenharmony_ci symbol_conf.default_guest_vmlinux_name, 22828c2ecf20Sopenharmony_ci false); 22838c2ecf20Sopenharmony_ci return err; 22848c2ecf20Sopenharmony_ci } 22858c2ecf20Sopenharmony_ci 22868c2ecf20Sopenharmony_ci kallsyms_filename = symbol_conf.default_guest_kallsyms; 22878c2ecf20Sopenharmony_ci if (!kallsyms_filename) 22888c2ecf20Sopenharmony_ci return -1; 22898c2ecf20Sopenharmony_ci } else { 22908c2ecf20Sopenharmony_ci sprintf(path, "%s/proc/kallsyms", machine->root_dir); 22918c2ecf20Sopenharmony_ci kallsyms_filename = path; 22928c2ecf20Sopenharmony_ci } 22938c2ecf20Sopenharmony_ci 22948c2ecf20Sopenharmony_ci err = dso__load_kallsyms(dso, kallsyms_filename, map); 22958c2ecf20Sopenharmony_ci if (err > 0) 22968c2ecf20Sopenharmony_ci pr_debug("Using %s for symbols\n", kallsyms_filename); 22978c2ecf20Sopenharmony_ci if (err > 0 && !dso__is_kcore(dso)) { 22988c2ecf20Sopenharmony_ci dso->binary_type = DSO_BINARY_TYPE__GUEST_KALLSYMS; 22998c2ecf20Sopenharmony_ci dso__set_long_name(dso, machine->mmap_name, false); 23008c2ecf20Sopenharmony_ci map__fixup_start(map); 23018c2ecf20Sopenharmony_ci map__fixup_end(map); 23028c2ecf20Sopenharmony_ci } 23038c2ecf20Sopenharmony_ci 23048c2ecf20Sopenharmony_ci return err; 23058c2ecf20Sopenharmony_ci} 23068c2ecf20Sopenharmony_ci 23078c2ecf20Sopenharmony_cistatic void vmlinux_path__exit(void) 23088c2ecf20Sopenharmony_ci{ 23098c2ecf20Sopenharmony_ci while (--vmlinux_path__nr_entries >= 0) 23108c2ecf20Sopenharmony_ci zfree(&vmlinux_path[vmlinux_path__nr_entries]); 23118c2ecf20Sopenharmony_ci vmlinux_path__nr_entries = 0; 23128c2ecf20Sopenharmony_ci 23138c2ecf20Sopenharmony_ci zfree(&vmlinux_path); 23148c2ecf20Sopenharmony_ci} 23158c2ecf20Sopenharmony_ci 23168c2ecf20Sopenharmony_cistatic const char * const vmlinux_paths[] = { 23178c2ecf20Sopenharmony_ci "vmlinux", 23188c2ecf20Sopenharmony_ci "/boot/vmlinux" 23198c2ecf20Sopenharmony_ci}; 23208c2ecf20Sopenharmony_ci 23218c2ecf20Sopenharmony_cistatic const char * const vmlinux_paths_upd[] = { 23228c2ecf20Sopenharmony_ci "/boot/vmlinux-%s", 23238c2ecf20Sopenharmony_ci "/usr/lib/debug/boot/vmlinux-%s", 23248c2ecf20Sopenharmony_ci "/lib/modules/%s/build/vmlinux", 23258c2ecf20Sopenharmony_ci "/usr/lib/debug/lib/modules/%s/vmlinux", 23268c2ecf20Sopenharmony_ci "/usr/lib/debug/boot/vmlinux-%s.debug" 23278c2ecf20Sopenharmony_ci}; 23288c2ecf20Sopenharmony_ci 23298c2ecf20Sopenharmony_cistatic int vmlinux_path__add(const char *new_entry) 23308c2ecf20Sopenharmony_ci{ 23318c2ecf20Sopenharmony_ci vmlinux_path[vmlinux_path__nr_entries] = strdup(new_entry); 23328c2ecf20Sopenharmony_ci if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 23338c2ecf20Sopenharmony_ci return -1; 23348c2ecf20Sopenharmony_ci ++vmlinux_path__nr_entries; 23358c2ecf20Sopenharmony_ci 23368c2ecf20Sopenharmony_ci return 0; 23378c2ecf20Sopenharmony_ci} 23388c2ecf20Sopenharmony_ci 23398c2ecf20Sopenharmony_cistatic int vmlinux_path__init(struct perf_env *env) 23408c2ecf20Sopenharmony_ci{ 23418c2ecf20Sopenharmony_ci struct utsname uts; 23428c2ecf20Sopenharmony_ci char bf[PATH_MAX]; 23438c2ecf20Sopenharmony_ci char *kernel_version; 23448c2ecf20Sopenharmony_ci unsigned int i; 23458c2ecf20Sopenharmony_ci 23468c2ecf20Sopenharmony_ci vmlinux_path = malloc(sizeof(char *) * (ARRAY_SIZE(vmlinux_paths) + 23478c2ecf20Sopenharmony_ci ARRAY_SIZE(vmlinux_paths_upd))); 23488c2ecf20Sopenharmony_ci if (vmlinux_path == NULL) 23498c2ecf20Sopenharmony_ci return -1; 23508c2ecf20Sopenharmony_ci 23518c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(vmlinux_paths); i++) 23528c2ecf20Sopenharmony_ci if (vmlinux_path__add(vmlinux_paths[i]) < 0) 23538c2ecf20Sopenharmony_ci goto out_fail; 23548c2ecf20Sopenharmony_ci 23558c2ecf20Sopenharmony_ci /* only try kernel version if no symfs was given */ 23568c2ecf20Sopenharmony_ci if (symbol_conf.symfs[0] != 0) 23578c2ecf20Sopenharmony_ci return 0; 23588c2ecf20Sopenharmony_ci 23598c2ecf20Sopenharmony_ci if (env) { 23608c2ecf20Sopenharmony_ci kernel_version = env->os_release; 23618c2ecf20Sopenharmony_ci } else { 23628c2ecf20Sopenharmony_ci if (uname(&uts) < 0) 23638c2ecf20Sopenharmony_ci goto out_fail; 23648c2ecf20Sopenharmony_ci 23658c2ecf20Sopenharmony_ci kernel_version = uts.release; 23668c2ecf20Sopenharmony_ci } 23678c2ecf20Sopenharmony_ci 23688c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(vmlinux_paths_upd); i++) { 23698c2ecf20Sopenharmony_ci snprintf(bf, sizeof(bf), vmlinux_paths_upd[i], kernel_version); 23708c2ecf20Sopenharmony_ci if (vmlinux_path__add(bf) < 0) 23718c2ecf20Sopenharmony_ci goto out_fail; 23728c2ecf20Sopenharmony_ci } 23738c2ecf20Sopenharmony_ci 23748c2ecf20Sopenharmony_ci return 0; 23758c2ecf20Sopenharmony_ci 23768c2ecf20Sopenharmony_ciout_fail: 23778c2ecf20Sopenharmony_ci vmlinux_path__exit(); 23788c2ecf20Sopenharmony_ci return -1; 23798c2ecf20Sopenharmony_ci} 23808c2ecf20Sopenharmony_ci 23818c2ecf20Sopenharmony_ciint setup_list(struct strlist **list, const char *list_str, 23828c2ecf20Sopenharmony_ci const char *list_name) 23838c2ecf20Sopenharmony_ci{ 23848c2ecf20Sopenharmony_ci if (list_str == NULL) 23858c2ecf20Sopenharmony_ci return 0; 23868c2ecf20Sopenharmony_ci 23878c2ecf20Sopenharmony_ci *list = strlist__new(list_str, NULL); 23888c2ecf20Sopenharmony_ci if (!*list) { 23898c2ecf20Sopenharmony_ci pr_err("problems parsing %s list\n", list_name); 23908c2ecf20Sopenharmony_ci return -1; 23918c2ecf20Sopenharmony_ci } 23928c2ecf20Sopenharmony_ci 23938c2ecf20Sopenharmony_ci symbol_conf.has_filter = true; 23948c2ecf20Sopenharmony_ci return 0; 23958c2ecf20Sopenharmony_ci} 23968c2ecf20Sopenharmony_ci 23978c2ecf20Sopenharmony_ciint setup_intlist(struct intlist **list, const char *list_str, 23988c2ecf20Sopenharmony_ci const char *list_name) 23998c2ecf20Sopenharmony_ci{ 24008c2ecf20Sopenharmony_ci if (list_str == NULL) 24018c2ecf20Sopenharmony_ci return 0; 24028c2ecf20Sopenharmony_ci 24038c2ecf20Sopenharmony_ci *list = intlist__new(list_str); 24048c2ecf20Sopenharmony_ci if (!*list) { 24058c2ecf20Sopenharmony_ci pr_err("problems parsing %s list\n", list_name); 24068c2ecf20Sopenharmony_ci return -1; 24078c2ecf20Sopenharmony_ci } 24088c2ecf20Sopenharmony_ci return 0; 24098c2ecf20Sopenharmony_ci} 24108c2ecf20Sopenharmony_ci 24118c2ecf20Sopenharmony_cistatic bool symbol__read_kptr_restrict(void) 24128c2ecf20Sopenharmony_ci{ 24138c2ecf20Sopenharmony_ci bool value = false; 24148c2ecf20Sopenharmony_ci FILE *fp = fopen("/proc/sys/kernel/kptr_restrict", "r"); 24158c2ecf20Sopenharmony_ci 24168c2ecf20Sopenharmony_ci if (fp != NULL) { 24178c2ecf20Sopenharmony_ci char line[8]; 24188c2ecf20Sopenharmony_ci 24198c2ecf20Sopenharmony_ci if (fgets(line, sizeof(line), fp) != NULL) 24208c2ecf20Sopenharmony_ci value = perf_cap__capable(CAP_SYSLOG) ? 24218c2ecf20Sopenharmony_ci (atoi(line) >= 2) : 24228c2ecf20Sopenharmony_ci (atoi(line) != 0); 24238c2ecf20Sopenharmony_ci 24248c2ecf20Sopenharmony_ci fclose(fp); 24258c2ecf20Sopenharmony_ci } 24268c2ecf20Sopenharmony_ci 24278c2ecf20Sopenharmony_ci /* Per kernel/kallsyms.c: 24288c2ecf20Sopenharmony_ci * we also restrict when perf_event_paranoid > 1 w/o CAP_SYSLOG 24298c2ecf20Sopenharmony_ci */ 24308c2ecf20Sopenharmony_ci if (perf_event_paranoid() > 1 && !perf_cap__capable(CAP_SYSLOG)) 24318c2ecf20Sopenharmony_ci value = true; 24328c2ecf20Sopenharmony_ci 24338c2ecf20Sopenharmony_ci return value; 24348c2ecf20Sopenharmony_ci} 24358c2ecf20Sopenharmony_ci 24368c2ecf20Sopenharmony_ciint symbol__annotation_init(void) 24378c2ecf20Sopenharmony_ci{ 24388c2ecf20Sopenharmony_ci if (symbol_conf.init_annotation) 24398c2ecf20Sopenharmony_ci return 0; 24408c2ecf20Sopenharmony_ci 24418c2ecf20Sopenharmony_ci if (symbol_conf.initialized) { 24428c2ecf20Sopenharmony_ci pr_err("Annotation needs to be init before symbol__init()\n"); 24438c2ecf20Sopenharmony_ci return -1; 24448c2ecf20Sopenharmony_ci } 24458c2ecf20Sopenharmony_ci 24468c2ecf20Sopenharmony_ci symbol_conf.priv_size += sizeof(struct annotation); 24478c2ecf20Sopenharmony_ci symbol_conf.init_annotation = true; 24488c2ecf20Sopenharmony_ci return 0; 24498c2ecf20Sopenharmony_ci} 24508c2ecf20Sopenharmony_ci 24518c2ecf20Sopenharmony_ciint symbol__init(struct perf_env *env) 24528c2ecf20Sopenharmony_ci{ 24538c2ecf20Sopenharmony_ci const char *symfs; 24548c2ecf20Sopenharmony_ci 24558c2ecf20Sopenharmony_ci if (symbol_conf.initialized) 24568c2ecf20Sopenharmony_ci return 0; 24578c2ecf20Sopenharmony_ci 24588c2ecf20Sopenharmony_ci symbol_conf.priv_size = PERF_ALIGN(symbol_conf.priv_size, sizeof(u64)); 24598c2ecf20Sopenharmony_ci 24608c2ecf20Sopenharmony_ci symbol__elf_init(); 24618c2ecf20Sopenharmony_ci 24628c2ecf20Sopenharmony_ci if (symbol_conf.sort_by_name) 24638c2ecf20Sopenharmony_ci symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) - 24648c2ecf20Sopenharmony_ci sizeof(struct symbol)); 24658c2ecf20Sopenharmony_ci 24668c2ecf20Sopenharmony_ci if (symbol_conf.try_vmlinux_path && vmlinux_path__init(env) < 0) 24678c2ecf20Sopenharmony_ci return -1; 24688c2ecf20Sopenharmony_ci 24698c2ecf20Sopenharmony_ci if (symbol_conf.field_sep && *symbol_conf.field_sep == '.') { 24708c2ecf20Sopenharmony_ci pr_err("'.' is the only non valid --field-separator argument\n"); 24718c2ecf20Sopenharmony_ci return -1; 24728c2ecf20Sopenharmony_ci } 24738c2ecf20Sopenharmony_ci 24748c2ecf20Sopenharmony_ci if (setup_list(&symbol_conf.dso_list, 24758c2ecf20Sopenharmony_ci symbol_conf.dso_list_str, "dso") < 0) 24768c2ecf20Sopenharmony_ci return -1; 24778c2ecf20Sopenharmony_ci 24788c2ecf20Sopenharmony_ci if (setup_list(&symbol_conf.comm_list, 24798c2ecf20Sopenharmony_ci symbol_conf.comm_list_str, "comm") < 0) 24808c2ecf20Sopenharmony_ci goto out_free_dso_list; 24818c2ecf20Sopenharmony_ci 24828c2ecf20Sopenharmony_ci if (setup_intlist(&symbol_conf.pid_list, 24838c2ecf20Sopenharmony_ci symbol_conf.pid_list_str, "pid") < 0) 24848c2ecf20Sopenharmony_ci goto out_free_comm_list; 24858c2ecf20Sopenharmony_ci 24868c2ecf20Sopenharmony_ci if (setup_intlist(&symbol_conf.tid_list, 24878c2ecf20Sopenharmony_ci symbol_conf.tid_list_str, "tid") < 0) 24888c2ecf20Sopenharmony_ci goto out_free_pid_list; 24898c2ecf20Sopenharmony_ci 24908c2ecf20Sopenharmony_ci if (setup_list(&symbol_conf.sym_list, 24918c2ecf20Sopenharmony_ci symbol_conf.sym_list_str, "symbol") < 0) 24928c2ecf20Sopenharmony_ci goto out_free_tid_list; 24938c2ecf20Sopenharmony_ci 24948c2ecf20Sopenharmony_ci if (setup_list(&symbol_conf.bt_stop_list, 24958c2ecf20Sopenharmony_ci symbol_conf.bt_stop_list_str, "symbol") < 0) 24968c2ecf20Sopenharmony_ci goto out_free_sym_list; 24978c2ecf20Sopenharmony_ci 24988c2ecf20Sopenharmony_ci /* 24998c2ecf20Sopenharmony_ci * A path to symbols of "/" is identical to "" 25008c2ecf20Sopenharmony_ci * reset here for simplicity. 25018c2ecf20Sopenharmony_ci */ 25028c2ecf20Sopenharmony_ci symfs = realpath(symbol_conf.symfs, NULL); 25038c2ecf20Sopenharmony_ci if (symfs == NULL) 25048c2ecf20Sopenharmony_ci symfs = symbol_conf.symfs; 25058c2ecf20Sopenharmony_ci if (strcmp(symfs, "/") == 0) 25068c2ecf20Sopenharmony_ci symbol_conf.symfs = ""; 25078c2ecf20Sopenharmony_ci if (symfs != symbol_conf.symfs) 25088c2ecf20Sopenharmony_ci free((void *)symfs); 25098c2ecf20Sopenharmony_ci 25108c2ecf20Sopenharmony_ci symbol_conf.kptr_restrict = symbol__read_kptr_restrict(); 25118c2ecf20Sopenharmony_ci 25128c2ecf20Sopenharmony_ci symbol_conf.initialized = true; 25138c2ecf20Sopenharmony_ci return 0; 25148c2ecf20Sopenharmony_ci 25158c2ecf20Sopenharmony_ciout_free_sym_list: 25168c2ecf20Sopenharmony_ci strlist__delete(symbol_conf.sym_list); 25178c2ecf20Sopenharmony_ciout_free_tid_list: 25188c2ecf20Sopenharmony_ci intlist__delete(symbol_conf.tid_list); 25198c2ecf20Sopenharmony_ciout_free_pid_list: 25208c2ecf20Sopenharmony_ci intlist__delete(symbol_conf.pid_list); 25218c2ecf20Sopenharmony_ciout_free_comm_list: 25228c2ecf20Sopenharmony_ci strlist__delete(symbol_conf.comm_list); 25238c2ecf20Sopenharmony_ciout_free_dso_list: 25248c2ecf20Sopenharmony_ci strlist__delete(symbol_conf.dso_list); 25258c2ecf20Sopenharmony_ci return -1; 25268c2ecf20Sopenharmony_ci} 25278c2ecf20Sopenharmony_ci 25288c2ecf20Sopenharmony_civoid symbol__exit(void) 25298c2ecf20Sopenharmony_ci{ 25308c2ecf20Sopenharmony_ci if (!symbol_conf.initialized) 25318c2ecf20Sopenharmony_ci return; 25328c2ecf20Sopenharmony_ci strlist__delete(symbol_conf.bt_stop_list); 25338c2ecf20Sopenharmony_ci strlist__delete(symbol_conf.sym_list); 25348c2ecf20Sopenharmony_ci strlist__delete(symbol_conf.dso_list); 25358c2ecf20Sopenharmony_ci strlist__delete(symbol_conf.comm_list); 25368c2ecf20Sopenharmony_ci intlist__delete(symbol_conf.tid_list); 25378c2ecf20Sopenharmony_ci intlist__delete(symbol_conf.pid_list); 25388c2ecf20Sopenharmony_ci vmlinux_path__exit(); 25398c2ecf20Sopenharmony_ci symbol_conf.sym_list = symbol_conf.dso_list = symbol_conf.comm_list = NULL; 25408c2ecf20Sopenharmony_ci symbol_conf.bt_stop_list = NULL; 25418c2ecf20Sopenharmony_ci symbol_conf.initialized = false; 25428c2ecf20Sopenharmony_ci} 25438c2ecf20Sopenharmony_ci 25448c2ecf20Sopenharmony_ciint symbol__config_symfs(const struct option *opt __maybe_unused, 25458c2ecf20Sopenharmony_ci const char *dir, int unset __maybe_unused) 25468c2ecf20Sopenharmony_ci{ 25478c2ecf20Sopenharmony_ci char *bf = NULL; 25488c2ecf20Sopenharmony_ci int ret; 25498c2ecf20Sopenharmony_ci 25508c2ecf20Sopenharmony_ci symbol_conf.symfs = strdup(dir); 25518c2ecf20Sopenharmony_ci if (symbol_conf.symfs == NULL) 25528c2ecf20Sopenharmony_ci return -ENOMEM; 25538c2ecf20Sopenharmony_ci 25548c2ecf20Sopenharmony_ci /* skip the locally configured cache if a symfs is given, and 25558c2ecf20Sopenharmony_ci * config buildid dir to symfs/.debug 25568c2ecf20Sopenharmony_ci */ 25578c2ecf20Sopenharmony_ci ret = asprintf(&bf, "%s/%s", dir, ".debug"); 25588c2ecf20Sopenharmony_ci if (ret < 0) 25598c2ecf20Sopenharmony_ci return -ENOMEM; 25608c2ecf20Sopenharmony_ci 25618c2ecf20Sopenharmony_ci set_buildid_dir(bf); 25628c2ecf20Sopenharmony_ci 25638c2ecf20Sopenharmony_ci free(bf); 25648c2ecf20Sopenharmony_ci return 0; 25658c2ecf20Sopenharmony_ci} 25668c2ecf20Sopenharmony_ci 25678c2ecf20Sopenharmony_cistruct mem_info *mem_info__get(struct mem_info *mi) 25688c2ecf20Sopenharmony_ci{ 25698c2ecf20Sopenharmony_ci if (mi) 25708c2ecf20Sopenharmony_ci refcount_inc(&mi->refcnt); 25718c2ecf20Sopenharmony_ci return mi; 25728c2ecf20Sopenharmony_ci} 25738c2ecf20Sopenharmony_ci 25748c2ecf20Sopenharmony_civoid mem_info__put(struct mem_info *mi) 25758c2ecf20Sopenharmony_ci{ 25768c2ecf20Sopenharmony_ci if (mi && refcount_dec_and_test(&mi->refcnt)) 25778c2ecf20Sopenharmony_ci free(mi); 25788c2ecf20Sopenharmony_ci} 25798c2ecf20Sopenharmony_ci 25808c2ecf20Sopenharmony_cistruct mem_info *mem_info__new(void) 25818c2ecf20Sopenharmony_ci{ 25828c2ecf20Sopenharmony_ci struct mem_info *mi = zalloc(sizeof(*mi)); 25838c2ecf20Sopenharmony_ci 25848c2ecf20Sopenharmony_ci if (mi) 25858c2ecf20Sopenharmony_ci refcount_set(&mi->refcnt, 1); 25868c2ecf20Sopenharmony_ci return mi; 25878c2ecf20Sopenharmony_ci} 2588