1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 25aab621bSArnaldo Carvalho de Melo #include <dirent.h> 35aab621bSArnaldo Carvalho de Melo #include <errno.h> 45aab621bSArnaldo Carvalho de Melo #include <stdlib.h> 55aab621bSArnaldo Carvalho de Melo #include <stdio.h> 65aab621bSArnaldo Carvalho de Melo #include <string.h> 78859aedeSIgor Lubashev #include <linux/capability.h> 8877a7a11SArnaldo Carvalho de Melo #include <linux/kernel.h> 9e9814df8SArnaldo Carvalho de Melo #include <linux/mman.h> 108520a98dSArnaldo Carvalho de Melo #include <linux/string.h> 112a1292cbSAndi Kleen #include <linux/time64.h> 125aab621bSArnaldo Carvalho de Melo #include <sys/types.h> 135aab621bSArnaldo Carvalho de Melo #include <sys/stat.h> 145aab621bSArnaldo Carvalho de Melo #include <sys/param.h> 155aab621bSArnaldo Carvalho de Melo #include <fcntl.h> 165aab621bSArnaldo Carvalho de Melo #include <unistd.h> 179486aa38SArnaldo Carvalho de Melo #include <inttypes.h> 18b01141f4SArnaldo Carvalho de Melo #include "annotate.h" 19b36f19d5SArnaldo Carvalho de Melo #include "build-id.h" 208859aedeSIgor Lubashev #include "cap.h" 21fac583fdSArnaldo Carvalho de Melo #include "dso.h" 22fb71c86cSArnaldo Carvalho de Melo #include "util.h" // lsdir() 238a6c5b26SArnaldo Carvalho de Melo #include "debug.h" 248859aedeSIgor Lubashev #include "event.h" 2569d2591aSArnaldo Carvalho de Melo #include "machine.h" 261101f69aSArnaldo Carvalho de Melo #include "map.h" 2786470930SIngo Molnar #include "symbol.h" 28d3300a3cSArnaldo Carvalho de Melo #include "map_symbol.h" 29d3300a3cSArnaldo Carvalho de Melo #include "mem-events.h" 30ad3003a6SIan Rogers #include "mem-info.h" 31b1d1b094SArnaldo Carvalho de Melo #include "symsrc.h" 325aab621bSArnaldo Carvalho de Melo #include "strlist.h" 33e03eaa40SDavid Ahern #include "intlist.h" 34843ff37bSKrister Johansen #include "namespaces.h" 350a7e6d1bSNamhyung Kim #include "header.h" 369a3993d4SArnaldo Carvalho de Melo #include "path.h" 373052ba56SArnaldo Carvalho de Melo #include <linux/ctype.h> 387f7c536fSArnaldo Carvalho de Melo #include <linux/zalloc.h> 3986470930SIngo Molnar 4086470930SIngo Molnar #include <elf.h> 41f1617b40SArnaldo Carvalho de Melo #include <limits.h> 42c506c96bSArnaldo Carvalho de Melo #include <symbol/kallsyms.h> 43439d473bSArnaldo Carvalho de Melo #include <sys/utsname.h> 442cdbc46dSPeter Zijlstra 45be39db9fSArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *dso, struct map *map); 46be39db9fSArnaldo Carvalho de Melo static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map); 47608c34deSArnaldo Carvalho de Melo static bool symbol__is_idle(const char *name); 48608c34deSArnaldo Carvalho de Melo 493f067dcaSArnaldo Carvalho de Melo int vmlinux_path__nr_entries; 503f067dcaSArnaldo Carvalho de Melo char **vmlinux_path; 51439d473bSArnaldo Carvalho de Melo 5275be6cf4SArnaldo Carvalho de Melo struct symbol_conf symbol_conf = { 5352bab886SAndi Kleen .nanosecs = false, 54b32d133aSArnaldo Carvalho de Melo .use_modules = true, 55b32d133aSArnaldo Carvalho de Melo .try_vmlinux_path = true, 56328ccdacSNamhyung Kim .demangle = true, 57763122adSAvi Kivity .demangle_kernel = false, 58e511db5eSNamhyung Kim .cumulate_callchain = true, 592a1292cbSAndi Kleen .time_quantum = 100 * NSEC_PER_MSEC, /* 100ms */ 60c8302367SJiri Olsa .show_hist_headers = true, 61ec5761eaSDavid Ahern .symfs = "", 621e9abf8bSNamhyung Kim .event_group = true, 63d8a88dd2SMilian Wolff .inline_name = true, 644968ac8fSAndi Kleen .res_sample = 0, 65b32d133aSArnaldo Carvalho de Melo }; 66b32d133aSArnaldo Carvalho de Melo 67ff0bd799SIan Rogers struct map_list_node { 68ff0bd799SIan Rogers struct list_head node; 69ff0bd799SIan Rogers struct map *map; 70ff0bd799SIan Rogers }; 71ff0bd799SIan Rogers 72ff0bd799SIan Rogers static struct map_list_node *map_list_node__new(void) 73ff0bd799SIan Rogers { 74ff0bd799SIan Rogers return malloc(sizeof(struct map_list_node)); 75ff0bd799SIan Rogers } 76ff0bd799SIan Rogers 7744f24cb3SJiri Olsa static enum dso_binary_type binary_type_symtab[] = { 7844f24cb3SJiri Olsa DSO_BINARY_TYPE__KALLSYMS, 7944f24cb3SJiri Olsa DSO_BINARY_TYPE__GUEST_KALLSYMS, 8044f24cb3SJiri Olsa DSO_BINARY_TYPE__JAVA_JIT, 8144f24cb3SJiri Olsa DSO_BINARY_TYPE__DEBUGLINK, 8244f24cb3SJiri Olsa DSO_BINARY_TYPE__BUILD_ID_CACHE, 83d2396999SKrister Johansen DSO_BINARY_TYPE__BUILD_ID_CACHE_DEBUGINFO, 8444f24cb3SJiri Olsa DSO_BINARY_TYPE__FEDORA_DEBUGINFO, 8544f24cb3SJiri Olsa DSO_BINARY_TYPE__UBUNTU_DEBUGINFO, 8644f24cb3SJiri Olsa DSO_BINARY_TYPE__BUILDID_DEBUGINFO, 8744f24cb3SJiri Olsa DSO_BINARY_TYPE__SYSTEM_PATH_DSO, 8844f24cb3SJiri Olsa DSO_BINARY_TYPE__GUEST_KMODULE, 89c00c48fcSNamhyung Kim DSO_BINARY_TYPE__GUEST_KMODULE_COMP, 9044f24cb3SJiri Olsa DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE, 91c00c48fcSNamhyung Kim DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP, 929cd00941SRicardo Ribalda Delgado DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO, 9385afd355SAdrian Hunter DSO_BINARY_TYPE__MIXEDUP_UBUNTU_DEBUGINFO, 9444f24cb3SJiri Olsa DSO_BINARY_TYPE__NOT_FOUND, 9544f24cb3SJiri Olsa }; 9644f24cb3SJiri Olsa 97028df767SJiri Olsa #define DSO_BINARY_TYPE__SYMTAB_CNT ARRAY_SIZE(binary_type_symtab) 9844f24cb3SJiri Olsa 993183f8caSArnaldo Carvalho de Melo static bool symbol_type__filter(char symbol_type) 1006893d4eeSArnaldo Carvalho de Melo { 10131877908SAnton Blanchard symbol_type = toupper(symbol_type); 1022be732c0SArnaldo Carvalho de Melo return symbol_type == 'T' || symbol_type == 'W' || symbol_type == 'D' || symbol_type == 'B'; 1036893d4eeSArnaldo Carvalho de Melo } 1046893d4eeSArnaldo Carvalho de Melo 105694bf407SAnton Blanchard static int prefix_underscores_count(const char *str) 106694bf407SAnton Blanchard { 107694bf407SAnton Blanchard const char *tail = str; 108694bf407SAnton Blanchard 109694bf407SAnton Blanchard while (*tail == '_') 110694bf407SAnton Blanchard tail++; 111694bf407SAnton Blanchard 112694bf407SAnton Blanchard return tail - str; 113694bf407SAnton Blanchard } 114694bf407SAnton Blanchard 1154b3a2716SMasami Hiramatsu const char * __weak arch__normalize_symbol_name(const char *name) 1164b3a2716SMasami Hiramatsu { 1174b3a2716SMasami Hiramatsu return name; 1184b3a2716SMasami Hiramatsu } 1194b3a2716SMasami Hiramatsu 120d8040645SPaul Clarke int __weak arch__compare_symbol_names(const char *namea, const char *nameb) 121d8040645SPaul Clarke { 122d8040645SPaul Clarke return strcmp(namea, nameb); 123d8040645SPaul Clarke } 124d8040645SPaul Clarke 125d8040645SPaul Clarke int __weak arch__compare_symbol_names_n(const char *namea, const char *nameb, 126d8040645SPaul Clarke unsigned int n) 127d8040645SPaul Clarke { 128d8040645SPaul Clarke return strncmp(namea, nameb, n); 129d8040645SPaul Clarke } 130d8040645SPaul Clarke 131fb6d5942SNaveen N. Rao int __weak arch__choose_best_symbol(struct symbol *syma, 132fb6d5942SNaveen N. Rao struct symbol *symb __maybe_unused) 133fb6d5942SNaveen N. Rao { 134fb6d5942SNaveen N. Rao /* Avoid "SyS" kernel syscall aliases */ 135fb6d5942SNaveen N. Rao if (strlen(syma->name) >= 3 && !strncmp(syma->name, "SyS", 3)) 136fb6d5942SNaveen N. Rao return SYMBOL_B; 137fb6d5942SNaveen N. Rao if (strlen(syma->name) >= 10 && !strncmp(syma->name, "compat_SyS", 10)) 138fb6d5942SNaveen N. Rao return SYMBOL_B; 139fb6d5942SNaveen N. Rao 140fb6d5942SNaveen N. Rao return SYMBOL_A; 141fb6d5942SNaveen N. Rao } 142694bf407SAnton Blanchard 143694bf407SAnton Blanchard static int choose_best_symbol(struct symbol *syma, struct symbol *symb) 144694bf407SAnton Blanchard { 145694bf407SAnton Blanchard s64 a; 146694bf407SAnton Blanchard s64 b; 1473445432bSAdrian Hunter size_t na, nb; 148694bf407SAnton Blanchard 149694bf407SAnton Blanchard /* Prefer a symbol with non zero length */ 150694bf407SAnton Blanchard a = syma->end - syma->start; 151694bf407SAnton Blanchard b = symb->end - symb->start; 152694bf407SAnton Blanchard if ((b == 0) && (a > 0)) 153694bf407SAnton Blanchard return SYMBOL_A; 154694bf407SAnton Blanchard else if ((a == 0) && (b > 0)) 155694bf407SAnton Blanchard return SYMBOL_B; 156694bf407SAnton Blanchard 157694bf407SAnton Blanchard /* Prefer a non weak symbol over a weak one */ 158694bf407SAnton Blanchard a = syma->binding == STB_WEAK; 159694bf407SAnton Blanchard b = symb->binding == STB_WEAK; 160694bf407SAnton Blanchard if (b && !a) 161694bf407SAnton Blanchard return SYMBOL_A; 162694bf407SAnton Blanchard if (a && !b) 163694bf407SAnton Blanchard return SYMBOL_B; 164694bf407SAnton Blanchard 165694bf407SAnton Blanchard /* Prefer a global symbol over a non global one */ 166694bf407SAnton Blanchard a = syma->binding == STB_GLOBAL; 167694bf407SAnton Blanchard b = symb->binding == STB_GLOBAL; 168694bf407SAnton Blanchard if (a && !b) 169694bf407SAnton Blanchard return SYMBOL_A; 170694bf407SAnton Blanchard if (b && !a) 171694bf407SAnton Blanchard return SYMBOL_B; 172694bf407SAnton Blanchard 173694bf407SAnton Blanchard /* Prefer a symbol with less underscores */ 174694bf407SAnton Blanchard a = prefix_underscores_count(syma->name); 175694bf407SAnton Blanchard b = prefix_underscores_count(symb->name); 176694bf407SAnton Blanchard if (b > a) 177694bf407SAnton Blanchard return SYMBOL_A; 178694bf407SAnton Blanchard else if (a > b) 179694bf407SAnton Blanchard return SYMBOL_B; 180694bf407SAnton Blanchard 1813445432bSAdrian Hunter /* Choose the symbol with the longest name */ 1823445432bSAdrian Hunter na = strlen(syma->name); 1833445432bSAdrian Hunter nb = strlen(symb->name); 1843445432bSAdrian Hunter if (na > nb) 185694bf407SAnton Blanchard return SYMBOL_A; 1863445432bSAdrian Hunter else if (na < nb) 187694bf407SAnton Blanchard return SYMBOL_B; 1883445432bSAdrian Hunter 189fb6d5942SNaveen N. Rao return arch__choose_best_symbol(syma, symb); 190694bf407SAnton Blanchard } 191694bf407SAnton Blanchard 1927137ff50SDavidlohr Bueso void symbols__fixup_duplicate(struct rb_root_cached *symbols) 193694bf407SAnton Blanchard { 194694bf407SAnton Blanchard struct rb_node *nd; 195694bf407SAnton Blanchard struct symbol *curr, *next; 196694bf407SAnton Blanchard 197c97b40e4SArnaldo Carvalho de Melo if (symbol_conf.allow_aliases) 198c97b40e4SArnaldo Carvalho de Melo return; 199c97b40e4SArnaldo Carvalho de Melo 2007137ff50SDavidlohr Bueso nd = rb_first_cached(symbols); 201694bf407SAnton Blanchard 202694bf407SAnton Blanchard while (nd) { 203694bf407SAnton Blanchard curr = rb_entry(nd, struct symbol, rb_node); 204694bf407SAnton Blanchard again: 205694bf407SAnton Blanchard nd = rb_next(&curr->rb_node); 206694bf407SAnton Blanchard if (!nd) 207694bf407SAnton Blanchard break; 208694bf407SAnton Blanchard 20921ce931eSIan Rogers next = rb_entry(nd, struct symbol, rb_node); 210694bf407SAnton Blanchard if (curr->start != next->start) 211694bf407SAnton Blanchard continue; 212694bf407SAnton Blanchard 213694bf407SAnton Blanchard if (choose_best_symbol(curr, next) == SYMBOL_A) { 21405963491SAdrian Hunter if (next->type == STT_GNU_IFUNC) 21505963491SAdrian Hunter curr->ifunc_alias = true; 2167137ff50SDavidlohr Bueso rb_erase_cached(&next->rb_node, symbols); 217d4f74eb8SChenggang Qin symbol__delete(next); 218694bf407SAnton Blanchard goto again; 219694bf407SAnton Blanchard } else { 22005963491SAdrian Hunter if (curr->type == STT_GNU_IFUNC) 22105963491SAdrian Hunter next->ifunc_alias = true; 222694bf407SAnton Blanchard nd = rb_next(&curr->rb_node); 2237137ff50SDavidlohr Bueso rb_erase_cached(&curr->rb_node, symbols); 224d4f74eb8SChenggang Qin symbol__delete(curr); 225694bf407SAnton Blanchard } 226694bf407SAnton Blanchard } 227694bf407SAnton Blanchard } 228694bf407SAnton Blanchard 2298799ebceSNamhyung Kim /* Update zero-sized symbols using the address of the next symbol */ 2308799ebceSNamhyung Kim void symbols__fixup_end(struct rb_root_cached *symbols, bool is_kallsyms) 231af427bf5SArnaldo Carvalho de Melo { 2327137ff50SDavidlohr Bueso struct rb_node *nd, *prevnd = rb_first_cached(symbols); 2332e538c4aSArnaldo Carvalho de Melo struct symbol *curr, *prev; 234af427bf5SArnaldo Carvalho de Melo 235af427bf5SArnaldo Carvalho de Melo if (prevnd == NULL) 236af427bf5SArnaldo Carvalho de Melo return; 237af427bf5SArnaldo Carvalho de Melo 2382e538c4aSArnaldo Carvalho de Melo curr = rb_entry(prevnd, struct symbol, rb_node); 2392e538c4aSArnaldo Carvalho de Melo 240af427bf5SArnaldo Carvalho de Melo for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) { 2412e538c4aSArnaldo Carvalho de Melo prev = curr; 2422e538c4aSArnaldo Carvalho de Melo curr = rb_entry(nd, struct symbol, rb_node); 243af427bf5SArnaldo Carvalho de Melo 2448799ebceSNamhyung Kim /* 2458799ebceSNamhyung Kim * On some architecture kernel text segment start is located at 2468799ebceSNamhyung Kim * some low memory address, while modules are located at high 2478799ebceSNamhyung Kim * memory addresses (or vice versa). The gap between end of 2488799ebceSNamhyung Kim * kernel text segment and beginning of first module's text 2498799ebceSNamhyung Kim * segment is very big. Therefore do not fill this gap and do 2508799ebceSNamhyung Kim * not assign it to the kernel dso map (kallsyms). 2518799ebceSNamhyung Kim * 252bacefe0cSNamhyung Kim * Also BPF code can be allocated separately from text segments 253bacefe0cSNamhyung Kim * and modules. So the last entry in a module should not fill 254bacefe0cSNamhyung Kim * the gap too. 255bacefe0cSNamhyung Kim * 2568799ebceSNamhyung Kim * In kallsyms, it determines module symbols using '[' character 2578799ebceSNamhyung Kim * like in: 2588799ebceSNamhyung Kim * ffffffffc1937000 T hdmi_driver_init [snd_hda_codec_hdmi] 2598799ebceSNamhyung Kim */ 2608799ebceSNamhyung Kim if (prev->end == prev->start) { 261bacefe0cSNamhyung Kim const char *prev_mod; 262bacefe0cSNamhyung Kim const char *curr_mod; 263bacefe0cSNamhyung Kim 264bacefe0cSNamhyung Kim if (!is_kallsyms) { 265bacefe0cSNamhyung Kim prev->end = curr->start; 266bacefe0cSNamhyung Kim continue; 267bacefe0cSNamhyung Kim } 268bacefe0cSNamhyung Kim 269bacefe0cSNamhyung Kim prev_mod = strchr(prev->name, '['); 270bacefe0cSNamhyung Kim curr_mod = strchr(curr->name, '['); 271bacefe0cSNamhyung Kim 2728799ebceSNamhyung Kim /* Last kernel/module symbol mapped to end of page */ 273bacefe0cSNamhyung Kim if (!prev_mod != !curr_mod) 274bacefe0cSNamhyung Kim prev->end = roundup(prev->end + 4096, 4096); 275bacefe0cSNamhyung Kim /* Last symbol in the previous module */ 276bacefe0cSNamhyung Kim else if (prev_mod && strcmp(prev_mod, curr_mod)) 2778799ebceSNamhyung Kim prev->end = roundup(prev->end + 4096, 4096); 2788799ebceSNamhyung Kim else 2798799ebceSNamhyung Kim prev->end = curr->start; 2808799ebceSNamhyung Kim 2818799ebceSNamhyung Kim pr_debug4("%s sym:%s end:%#" PRIx64 "\n", 2828799ebceSNamhyung Kim __func__, prev->name, prev->end); 2838799ebceSNamhyung Kim } 284af427bf5SArnaldo Carvalho de Melo } 285af427bf5SArnaldo Carvalho de Melo 2862e538c4aSArnaldo Carvalho de Melo /* Last entry */ 2872e538c4aSArnaldo Carvalho de Melo if (curr->end == curr->start) 288e7ede72aSDaniel Borkmann curr->end = roundup(curr->start, 4096) + 4096; 2892e538c4aSArnaldo Carvalho de Melo } 2902e538c4aSArnaldo Carvalho de Melo 291af30bffaSArnaldo Carvalho de Melo struct symbol *symbol__new(u64 start, u64 len, u8 binding, u8 type, const char *name) 29286470930SIngo Molnar { 29386470930SIngo Molnar size_t namelen = strlen(name) + 1; 294aeafcbafSArnaldo Carvalho de Melo struct symbol *sym = calloc(1, (symbol_conf.priv_size + 295aeafcbafSArnaldo Carvalho de Melo sizeof(*sym) + namelen)); 296aeafcbafSArnaldo Carvalho de Melo if (sym == NULL) 29786470930SIngo Molnar return NULL; 29886470930SIngo Molnar 299b01141f4SArnaldo Carvalho de Melo if (symbol_conf.priv_size) { 300b01141f4SArnaldo Carvalho de Melo if (symbol_conf.init_annotation) { 301b01141f4SArnaldo Carvalho de Melo struct annotation *notes = (void *)sym; 3024f74f187SIan Rogers annotation__init(notes); 303b01141f4SArnaldo Carvalho de Melo } 304aeafcbafSArnaldo Carvalho de Melo sym = ((void *)sym) + symbol_conf.priv_size; 305b01141f4SArnaldo Carvalho de Melo } 30636479484SArnaldo Carvalho de Melo 307aeafcbafSArnaldo Carvalho de Melo sym->start = start; 3082c241bd3SArnaldo Carvalho de Melo sym->end = len ? start + len : start; 309af30bffaSArnaldo Carvalho de Melo sym->type = type; 310aeafcbafSArnaldo Carvalho de Melo sym->binding = binding; 311aeafcbafSArnaldo Carvalho de Melo sym->namelen = namelen - 1; 312e4204992SArnaldo Carvalho de Melo 313aeafcbafSArnaldo Carvalho de Melo pr_debug4("%s: %s %#" PRIx64 "-%#" PRIx64 "\n", 314aeafcbafSArnaldo Carvalho de Melo __func__, name, start, sym->end); 315aeafcbafSArnaldo Carvalho de Melo memcpy(sym->name, name, namelen); 316e4204992SArnaldo Carvalho de Melo 317aeafcbafSArnaldo Carvalho de Melo return sym; 31886470930SIngo Molnar } 31986470930SIngo Molnar 320aeafcbafSArnaldo Carvalho de Melo void symbol__delete(struct symbol *sym) 32186470930SIngo Molnar { 3224f74f187SIan Rogers if (symbol_conf.priv_size) { 3234f74f187SIan Rogers if (symbol_conf.init_annotation) { 3244f74f187SIan Rogers struct annotation *notes = symbol__annotation(sym); 3254f74f187SIan Rogers 3264f74f187SIan Rogers annotation__exit(notes); 3274f74f187SIan Rogers } 3284f74f187SIan Rogers } 329aeafcbafSArnaldo Carvalho de Melo free(((void *)sym) - symbol_conf.priv_size); 33086470930SIngo Molnar } 33186470930SIngo Molnar 3327137ff50SDavidlohr Bueso void symbols__delete(struct rb_root_cached *symbols) 33386470930SIngo Molnar { 33486470930SIngo Molnar struct symbol *pos; 3357137ff50SDavidlohr Bueso struct rb_node *next = rb_first_cached(symbols); 33686470930SIngo Molnar 33786470930SIngo Molnar while (next) { 33886470930SIngo Molnar pos = rb_entry(next, struct symbol, rb_node); 33986470930SIngo Molnar next = rb_next(&pos->rb_node); 3407137ff50SDavidlohr Bueso rb_erase_cached(&pos->rb_node, symbols); 34100a192b3SArnaldo Carvalho de Melo symbol__delete(pos); 34286470930SIngo Molnar } 34386470930SIngo Molnar } 34486470930SIngo Molnar 3457137ff50SDavidlohr Bueso void __symbols__insert(struct rb_root_cached *symbols, 3467137ff50SDavidlohr Bueso struct symbol *sym, bool kernel) 34786470930SIngo Molnar { 3487137ff50SDavidlohr Bueso struct rb_node **p = &symbols->rb_root.rb_node; 34986470930SIngo Molnar struct rb_node *parent = NULL; 3509cffa8d5SPaul Mackerras const u64 ip = sym->start; 35186470930SIngo Molnar struct symbol *s; 3527137ff50SDavidlohr Bueso bool leftmost = true; 35386470930SIngo Molnar 354608c34deSArnaldo Carvalho de Melo if (kernel) { 355608c34deSArnaldo Carvalho de Melo const char *name = sym->name; 356608c34deSArnaldo Carvalho de Melo /* 357608c34deSArnaldo Carvalho de Melo * ppc64 uses function descriptors and appends a '.' to the 358608c34deSArnaldo Carvalho de Melo * start of every instruction address. Remove it. 359608c34deSArnaldo Carvalho de Melo */ 360608c34deSArnaldo Carvalho de Melo if (name[0] == '.') 361608c34deSArnaldo Carvalho de Melo name++; 362608c34deSArnaldo Carvalho de Melo sym->idle = symbol__is_idle(name); 363608c34deSArnaldo Carvalho de Melo } 364608c34deSArnaldo Carvalho de Melo 36586470930SIngo Molnar while (*p != NULL) { 36686470930SIngo Molnar parent = *p; 36786470930SIngo Molnar s = rb_entry(parent, struct symbol, rb_node); 36886470930SIngo Molnar if (ip < s->start) 36986470930SIngo Molnar p = &(*p)->rb_left; 3707137ff50SDavidlohr Bueso else { 37186470930SIngo Molnar p = &(*p)->rb_right; 3727137ff50SDavidlohr Bueso leftmost = false; 3737137ff50SDavidlohr Bueso } 37486470930SIngo Molnar } 37586470930SIngo Molnar rb_link_node(&sym->rb_node, parent, p); 3767137ff50SDavidlohr Bueso rb_insert_color_cached(&sym->rb_node, symbols, leftmost); 37786470930SIngo Molnar } 37886470930SIngo Molnar 3797137ff50SDavidlohr Bueso void symbols__insert(struct rb_root_cached *symbols, struct symbol *sym) 380608c34deSArnaldo Carvalho de Melo { 381608c34deSArnaldo Carvalho de Melo __symbols__insert(symbols, sym, false); 382608c34deSArnaldo Carvalho de Melo } 383608c34deSArnaldo Carvalho de Melo 3847137ff50SDavidlohr Bueso static struct symbol *symbols__find(struct rb_root_cached *symbols, u64 ip) 38586470930SIngo Molnar { 38686470930SIngo Molnar struct rb_node *n; 38786470930SIngo Molnar 388aeafcbafSArnaldo Carvalho de Melo if (symbols == NULL) 38986470930SIngo Molnar return NULL; 39086470930SIngo Molnar 3917137ff50SDavidlohr Bueso n = symbols->rb_root.rb_node; 39286470930SIngo Molnar 39386470930SIngo Molnar while (n) { 39486470930SIngo Molnar struct symbol *s = rb_entry(n, struct symbol, rb_node); 39586470930SIngo Molnar 39686470930SIngo Molnar if (ip < s->start) 39786470930SIngo Molnar n = n->rb_left; 3989c7b37cdSChris Phlipot else if (ip > s->end || (ip == s->end && ip != s->start)) 39986470930SIngo Molnar n = n->rb_right; 40086470930SIngo Molnar else 40186470930SIngo Molnar return s; 40286470930SIngo Molnar } 40386470930SIngo Molnar 40486470930SIngo Molnar return NULL; 40586470930SIngo Molnar } 40686470930SIngo Molnar 4077137ff50SDavidlohr Bueso static struct symbol *symbols__first(struct rb_root_cached *symbols) 4088e0cf965SAdrian Hunter { 4097137ff50SDavidlohr Bueso struct rb_node *n = rb_first_cached(symbols); 4108e0cf965SAdrian Hunter 4118e0cf965SAdrian Hunter if (n) 4128e0cf965SAdrian Hunter return rb_entry(n, struct symbol, rb_node); 4138e0cf965SAdrian Hunter 4148e0cf965SAdrian Hunter return NULL; 4158e0cf965SAdrian Hunter } 4168e0cf965SAdrian Hunter 4177137ff50SDavidlohr Bueso static struct symbol *symbols__last(struct rb_root_cached *symbols) 418cd67f99fSAdrian Hunter { 4197137ff50SDavidlohr Bueso struct rb_node *n = rb_last(&symbols->rb_root); 420cd67f99fSAdrian Hunter 421cd67f99fSAdrian Hunter if (n) 422cd67f99fSAdrian Hunter return rb_entry(n, struct symbol, rb_node); 423cd67f99fSAdrian Hunter 424cd67f99fSAdrian Hunter return NULL; 425cd67f99fSAdrian Hunter } 426cd67f99fSAdrian Hunter 4279c00a81bSAdrian Hunter static struct symbol *symbols__next(struct symbol *sym) 4289c00a81bSAdrian Hunter { 4299c00a81bSAdrian Hunter struct rb_node *n = rb_next(&sym->rb_node); 4309c00a81bSAdrian Hunter 4319c00a81bSAdrian Hunter if (n) 4329c00a81bSAdrian Hunter return rb_entry(n, struct symbol, rb_node); 4339c00a81bSAdrian Hunter 4349c00a81bSAdrian Hunter return NULL; 4359c00a81bSAdrian Hunter } 4369c00a81bSAdrian Hunter 437259dce91SIan Rogers static int symbols__sort_name_cmp(const void *vlhs, const void *vrhs) 43879406cd7SArnaldo Carvalho de Melo { 439259dce91SIan Rogers const struct symbol *lhs = *((const struct symbol **)vlhs); 440259dce91SIan Rogers const struct symbol *rhs = *((const struct symbol **)vrhs); 44102a9d037SRabin Vincent 442259dce91SIan Rogers return strcmp(lhs->name, rhs->name); 44379406cd7SArnaldo Carvalho de Melo } 44479406cd7SArnaldo Carvalho de Melo 445259dce91SIan Rogers static struct symbol **symbols__sort_by_name(struct rb_root_cached *source, size_t *len) 44679406cd7SArnaldo Carvalho de Melo { 44779406cd7SArnaldo Carvalho de Melo struct rb_node *nd; 448259dce91SIan Rogers struct symbol **result; 449259dce91SIan Rogers size_t i = 0, size = 0; 450259dce91SIan Rogers 451259dce91SIan Rogers for (nd = rb_first_cached(source); nd; nd = rb_next(nd)) 452259dce91SIan Rogers size++; 453259dce91SIan Rogers 454259dce91SIan Rogers result = malloc(sizeof(*result) * size); 455259dce91SIan Rogers if (!result) 456259dce91SIan Rogers return NULL; 45779406cd7SArnaldo Carvalho de Melo 4587137ff50SDavidlohr Bueso for (nd = rb_first_cached(source); nd; nd = rb_next(nd)) { 45979406cd7SArnaldo Carvalho de Melo struct symbol *pos = rb_entry(nd, struct symbol, rb_node); 460259dce91SIan Rogers 461259dce91SIan Rogers result[i++] = pos; 46279406cd7SArnaldo Carvalho de Melo } 463259dce91SIan Rogers qsort(result, size, sizeof(*result), symbols__sort_name_cmp); 464259dce91SIan Rogers *len = size; 465259dce91SIan Rogers return result; 46679406cd7SArnaldo Carvalho de Melo } 46779406cd7SArnaldo Carvalho de Melo 468d8040645SPaul Clarke int symbol__match_symbol_name(const char *name, const char *str, 469d8040645SPaul Clarke enum symbol_tag_include includes) 470d8040645SPaul Clarke { 471d8040645SPaul Clarke const char *versioning; 472d8040645SPaul Clarke 473d8040645SPaul Clarke if (includes == SYMBOL_TAG_INCLUDE__DEFAULT_ONLY && 474d8040645SPaul Clarke (versioning = strstr(name, "@@"))) { 475d8040645SPaul Clarke int len = strlen(str); 476d8040645SPaul Clarke 477d8040645SPaul Clarke if (len < versioning - name) 478d8040645SPaul Clarke len = versioning - name; 479d8040645SPaul Clarke 480d8040645SPaul Clarke return arch__compare_symbol_names_n(name, str, len); 481d8040645SPaul Clarke } else 482d8040645SPaul Clarke return arch__compare_symbol_names(name, str); 483d8040645SPaul Clarke } 484d8040645SPaul Clarke 485259dce91SIan Rogers static struct symbol *symbols__find_by_name(struct symbol *symbols[], 486259dce91SIan Rogers size_t symbols_len, 487d8040645SPaul Clarke const char *name, 488259dce91SIan Rogers enum symbol_tag_include includes, 489259dce91SIan Rogers size_t *found_idx) 49079406cd7SArnaldo Carvalho de Melo { 491259dce91SIan Rogers size_t i, lower = 0, upper = symbols_len; 49278a175c4SJames Clark struct symbol *s = NULL; 49378a175c4SJames Clark 49478a175c4SJames Clark if (found_idx) 49578a175c4SJames Clark *found_idx = SIZE_MAX; 49679406cd7SArnaldo Carvalho de Melo 497259dce91SIan Rogers if (!symbols_len) 49879406cd7SArnaldo Carvalho de Melo return NULL; 49979406cd7SArnaldo Carvalho de Melo 500259dce91SIan Rogers while (lower < upper) { 50179406cd7SArnaldo Carvalho de Melo int cmp; 50279406cd7SArnaldo Carvalho de Melo 503259dce91SIan Rogers i = (lower + upper) / 2; 50478a175c4SJames Clark cmp = symbol__match_symbol_name(symbols[i]->name, name, includes); 50579406cd7SArnaldo Carvalho de Melo 506d8040645SPaul Clarke if (cmp > 0) 507259dce91SIan Rogers upper = i; 508d8040645SPaul Clarke else if (cmp < 0) 509259dce91SIan Rogers lower = i + 1; 510259dce91SIan Rogers else { 511259dce91SIan Rogers if (found_idx) 512259dce91SIan Rogers *found_idx = i; 51378a175c4SJames Clark s = symbols[i]; 514de480999SNamhyung Kim break; 51579406cd7SArnaldo Carvalho de Melo } 516259dce91SIan Rogers } 51778a175c4SJames Clark if (s && includes != SYMBOL_TAG_INCLUDE__DEFAULT_ONLY) { 518de480999SNamhyung Kim /* return first symbol that has same name (if any) */ 519259dce91SIan Rogers for (; i > 0; i--) { 520259dce91SIan Rogers struct symbol *tmp = symbols[i - 1]; 521de480999SNamhyung Kim 522259dce91SIan Rogers if (!arch__compare_symbol_names(tmp->name, s->name)) { 523259dce91SIan Rogers if (found_idx) 524259dce91SIan Rogers *found_idx = i - 1; 52578a175c4SJames Clark s = tmp; 526259dce91SIan Rogers } else 527de480999SNamhyung Kim break; 528de480999SNamhyung Kim } 529259dce91SIan Rogers } 53078a175c4SJames Clark assert(!found_idx || !s || s == symbols[*found_idx]); 531259dce91SIan Rogers return s; 53279406cd7SArnaldo Carvalho de Melo } 53379406cd7SArnaldo Carvalho de Melo 534c0b4dffbSArnaldo Carvalho de Melo void dso__reset_find_symbol_cache(struct dso *dso) 535c0b4dffbSArnaldo Carvalho de Melo { 536ee756ef7SIan Rogers dso__set_last_find_result_addr(dso, 0); 537ee756ef7SIan Rogers dso__set_last_find_result_symbol(dso, NULL); 538c0b4dffbSArnaldo Carvalho de Melo } 539c0b4dffbSArnaldo Carvalho de Melo 5403183f8caSArnaldo Carvalho de Melo void dso__insert_symbol(struct dso *dso, struct symbol *sym) 541ae93a6c7SChris Phlipot { 542ee756ef7SIan Rogers __symbols__insert(dso__symbols(dso), sym, dso__kernel(dso)); 543ae93a6c7SChris Phlipot 544ae93a6c7SChris Phlipot /* update the symbol cache if necessary */ 545ee756ef7SIan Rogers if (dso__last_find_result_addr(dso) >= sym->start && 546ee756ef7SIan Rogers (dso__last_find_result_addr(dso) < sym->end || 547ae93a6c7SChris Phlipot sym->start == sym->end)) { 548ee756ef7SIan Rogers dso__set_last_find_result_symbol(dso, sym); 549ae93a6c7SChris Phlipot } 550ae93a6c7SChris Phlipot } 551ae93a6c7SChris Phlipot 552ab8bf5f2STommi Rantala void dso__delete_symbol(struct dso *dso, struct symbol *sym) 553ab8bf5f2STommi Rantala { 554ee756ef7SIan Rogers rb_erase_cached(&sym->rb_node, dso__symbols(dso)); 555ab8bf5f2STommi Rantala symbol__delete(sym); 556ab8bf5f2STommi Rantala dso__reset_find_symbol_cache(dso); 557ab8bf5f2STommi Rantala } 558ab8bf5f2STommi Rantala 5593183f8caSArnaldo Carvalho de Melo struct symbol *dso__find_symbol(struct dso *dso, u64 addr) 560fcf1203aSArnaldo Carvalho de Melo { 561ee756ef7SIan Rogers if (dso__last_find_result_addr(dso) != addr || dso__last_find_result_symbol(dso) == NULL) { 562ee756ef7SIan Rogers dso__set_last_find_result_addr(dso, addr); 563ee756ef7SIan Rogers dso__set_last_find_result_symbol(dso, symbols__find(dso__symbols(dso), addr)); 564b685ac22SArnaldo Carvalho de Melo } 565b685ac22SArnaldo Carvalho de Melo 566ee756ef7SIan Rogers return dso__last_find_result_symbol(dso); 5678e0cf965SAdrian Hunter } 5688e0cf965SAdrian Hunter 569a2db72c5SAdrian Hunter struct symbol *dso__find_symbol_nocache(struct dso *dso, u64 addr) 570a2db72c5SAdrian Hunter { 571ee756ef7SIan Rogers return symbols__find(dso__symbols(dso), addr); 572a2db72c5SAdrian Hunter } 573a2db72c5SAdrian Hunter 5745cf88a63SArnaldo Carvalho de Melo struct symbol *dso__first_symbol(struct dso *dso) 5755cf88a63SArnaldo Carvalho de Melo { 576ee756ef7SIan Rogers return symbols__first(dso__symbols(dso)); 577cd67f99fSAdrian Hunter } 578cd67f99fSAdrian Hunter 5795cf88a63SArnaldo Carvalho de Melo struct symbol *dso__last_symbol(struct dso *dso) 5805cf88a63SArnaldo Carvalho de Melo { 581ee756ef7SIan Rogers return symbols__last(dso__symbols(dso)); 5825cf88a63SArnaldo Carvalho de Melo } 5835cf88a63SArnaldo Carvalho de Melo 5849c00a81bSAdrian Hunter struct symbol *dso__next_symbol(struct symbol *sym) 5859c00a81bSAdrian Hunter { 5869c00a81bSAdrian Hunter return symbols__next(sym); 5879c00a81bSAdrian Hunter } 5889c00a81bSAdrian Hunter 589259dce91SIan Rogers struct symbol *dso__next_symbol_by_name(struct dso *dso, size_t *idx) 59018bd7264SArnaldo Carvalho de Melo { 591ee756ef7SIan Rogers if (*idx + 1 >= dso__symbol_names_len(dso)) 592259dce91SIan Rogers return NULL; 59318bd7264SArnaldo Carvalho de Melo 594259dce91SIan Rogers ++*idx; 595ee756ef7SIan Rogers return dso__symbol_names(dso)[*idx]; 59618bd7264SArnaldo Carvalho de Melo } 59718bd7264SArnaldo Carvalho de Melo 59818bd7264SArnaldo Carvalho de Melo /* 599af07eeb0SArnaldo Carvalho de Melo * Returns first symbol that matched with @name. 60018bd7264SArnaldo Carvalho de Melo */ 601259dce91SIan Rogers struct symbol *dso__find_symbol_by_name(struct dso *dso, const char *name, size_t *idx) 60279406cd7SArnaldo Carvalho de Melo { 603ee756ef7SIan Rogers struct symbol *s = symbols__find_by_name(dso__symbol_names(dso), 604ee756ef7SIan Rogers dso__symbol_names_len(dso), 605259dce91SIan Rogers name, SYMBOL_TAG_INCLUDE__NONE, idx); 606ee756ef7SIan Rogers if (!s) { 607ee756ef7SIan Rogers s = symbols__find_by_name(dso__symbol_names(dso), dso__symbol_names_len(dso), 608259dce91SIan Rogers name, SYMBOL_TAG_INCLUDE__DEFAULT_ONLY, idx); 609ee756ef7SIan Rogers } 610d8040645SPaul Clarke return s; 61179406cd7SArnaldo Carvalho de Melo } 61279406cd7SArnaldo Carvalho de Melo 6133183f8caSArnaldo Carvalho de Melo void dso__sort_by_name(struct dso *dso) 61479406cd7SArnaldo Carvalho de Melo { 615ee756ef7SIan Rogers mutex_lock(dso__lock(dso)); 616ce5b2934SIan Rogers if (!dso__sorted_by_name(dso)) { 617259dce91SIan Rogers size_t len; 618259dce91SIan Rogers 619ee756ef7SIan Rogers dso__set_symbol_names(dso, symbols__sort_by_name(dso__symbols(dso), &len)); 620ee756ef7SIan Rogers if (dso__symbol_names(dso)) { 621ee756ef7SIan Rogers dso__set_symbol_names_len(dso, len); 6223183f8caSArnaldo Carvalho de Melo dso__set_sorted_by_name(dso); 623ce5b2934SIan Rogers } 624259dce91SIan Rogers } 625ee756ef7SIan Rogers mutex_unlock(dso__lock(dso)); 62679406cd7SArnaldo Carvalho de Melo } 62779406cd7SArnaldo Carvalho de Melo 62832add10fSIan Rogers /* 62932add10fSIan Rogers * While we find nice hex chars, build a long_val. 63032add10fSIan Rogers * Return number of chars processed. 63132add10fSIan Rogers */ 63232add10fSIan Rogers static int hex2u64(const char *ptr, u64 *long_val) 63332add10fSIan Rogers { 63432add10fSIan Rogers char *p; 63532add10fSIan Rogers 63632add10fSIan Rogers *long_val = strtoull(ptr, &p, 16); 63732add10fSIan Rogers 63832add10fSIan Rogers return p - ptr; 63932add10fSIan Rogers } 64032add10fSIan Rogers 64132add10fSIan Rogers 642316d70d6SAdrian Hunter int modules__parse(const char *filename, void *arg, 643316d70d6SAdrian Hunter int (*process_module)(void *arg, const char *name, 6449ad4652bSThomas Richter u64 start, u64 size)) 645316d70d6SAdrian Hunter { 646316d70d6SAdrian Hunter char *line = NULL; 647316d70d6SAdrian Hunter size_t n; 648316d70d6SAdrian Hunter FILE *file; 649316d70d6SAdrian Hunter int err = 0; 650316d70d6SAdrian Hunter 651316d70d6SAdrian Hunter file = fopen(filename, "r"); 652316d70d6SAdrian Hunter if (file == NULL) 653316d70d6SAdrian Hunter return -1; 654316d70d6SAdrian Hunter 655316d70d6SAdrian Hunter while (1) { 656316d70d6SAdrian Hunter char name[PATH_MAX]; 6579ad4652bSThomas Richter u64 start, size; 6589ad4652bSThomas Richter char *sep, *endptr; 659316d70d6SAdrian Hunter ssize_t line_len; 660316d70d6SAdrian Hunter 661316d70d6SAdrian Hunter line_len = getline(&line, &n, file); 662316d70d6SAdrian Hunter if (line_len < 0) { 663316d70d6SAdrian Hunter if (feof(file)) 664316d70d6SAdrian Hunter break; 665316d70d6SAdrian Hunter err = -1; 666316d70d6SAdrian Hunter goto out; 667316d70d6SAdrian Hunter } 668316d70d6SAdrian Hunter 669316d70d6SAdrian Hunter if (!line) { 670316d70d6SAdrian Hunter err = -1; 671316d70d6SAdrian Hunter goto out; 672316d70d6SAdrian Hunter } 673316d70d6SAdrian Hunter 674316d70d6SAdrian Hunter line[--line_len] = '\0'; /* \n */ 675316d70d6SAdrian Hunter 676316d70d6SAdrian Hunter sep = strrchr(line, 'x'); 677316d70d6SAdrian Hunter if (sep == NULL) 678316d70d6SAdrian Hunter continue; 679316d70d6SAdrian Hunter 680316d70d6SAdrian Hunter hex2u64(sep + 1, &start); 681316d70d6SAdrian Hunter 682316d70d6SAdrian Hunter sep = strchr(line, ' '); 683316d70d6SAdrian Hunter if (sep == NULL) 684316d70d6SAdrian Hunter continue; 685316d70d6SAdrian Hunter 686316d70d6SAdrian Hunter *sep = '\0'; 687316d70d6SAdrian Hunter 688316d70d6SAdrian Hunter scnprintf(name, sizeof(name), "[%s]", line); 689316d70d6SAdrian Hunter 6909ad4652bSThomas Richter size = strtoul(sep + 1, &endptr, 0); 6919ad4652bSThomas Richter if (*endptr != ' ' && *endptr != '\t') 6929ad4652bSThomas Richter continue; 6939ad4652bSThomas Richter 6949ad4652bSThomas Richter err = process_module(arg, name, start, size); 695316d70d6SAdrian Hunter if (err) 696316d70d6SAdrian Hunter break; 697316d70d6SAdrian Hunter } 698316d70d6SAdrian Hunter out: 699316d70d6SAdrian Hunter free(line); 700316d70d6SAdrian Hunter fclose(file); 701316d70d6SAdrian Hunter return err; 702316d70d6SAdrian Hunter } 703316d70d6SAdrian Hunter 704e7110b9fSArnaldo Carvalho de Melo /* 705e7110b9fSArnaldo Carvalho de Melo * These are symbols in the kernel image, so make sure that 706e7110b9fSArnaldo Carvalho de Melo * sym is from a kernel DSO. 707e7110b9fSArnaldo Carvalho de Melo */ 708608c34deSArnaldo Carvalho de Melo static bool symbol__is_idle(const char *name) 70982d1deb0SDavid Ahern { 71082d1deb0SDavid Ahern const char * const idle_symbols[] = { 7110e71459aSKim Phillips "acpi_idle_do_entry", 7120e71459aSKim Phillips "acpi_processor_ffh_cstate_enter", 713549aff77SArnaldo Carvalho de Melo "arch_cpu_idle", 71482d1deb0SDavid Ahern "cpu_idle", 715e0336ed6SArnaldo Carvalho de Melo "cpu_startup_entry", 7160e71459aSKim Phillips "idle_cpu", 71782d1deb0SDavid Ahern "intel_idle", 71829a2fd7cSArnaldo Carvalho de Melo "intel_idle_ibrs", 71982d1deb0SDavid Ahern "default_idle", 72082d1deb0SDavid Ahern "native_safe_halt", 72182d1deb0SDavid Ahern "enter_idle", 72282d1deb0SDavid Ahern "exit_idle", 72382d1deb0SDavid Ahern "mwait_idle", 72482d1deb0SDavid Ahern "mwait_idle_with_hints", 725783abbd4SArnaldo Carvalho de Melo "mwait_idle_with_hints.constprop.0", 72682d1deb0SDavid Ahern "poll_idle", 72782d1deb0SDavid Ahern "ppc64_runlatch_off", 72882d1deb0SDavid Ahern "pseries_dedicated_idle_sleep", 72919bf119cSSven Schnelle "psw_idle", 73019bf119cSSven Schnelle "psw_idle_exit", 73182d1deb0SDavid Ahern NULL 73282d1deb0SDavid Ahern }; 73382d1deb0SDavid Ahern int i; 734bc5f15beSKim Phillips static struct strlist *idle_symbols_list; 73582d1deb0SDavid Ahern 736bc5f15beSKim Phillips if (idle_symbols_list) 737bc5f15beSKim Phillips return strlist__has_entry(idle_symbols_list, name); 73882d1deb0SDavid Ahern 739bc5f15beSKim Phillips idle_symbols_list = strlist__new(NULL, NULL); 740bc5f15beSKim Phillips 741bc5f15beSKim Phillips for (i = 0; idle_symbols[i]; i++) 742bc5f15beSKim Phillips strlist__add(idle_symbols_list, idle_symbols[i]); 743bc5f15beSKim Phillips 744bc5f15beSKim Phillips return strlist__has_entry(idle_symbols_list, name); 74582d1deb0SDavid Ahern } 74682d1deb0SDavid Ahern 747682b335aSArnaldo Carvalho de Melo static int map__process_kallsym_symbol(void *arg, const char *name, 74882151520SCody P Schafer char type, u64 start) 749682b335aSArnaldo Carvalho de Melo { 750682b335aSArnaldo Carvalho de Melo struct symbol *sym; 751333cc76cSArnaldo Carvalho de Melo struct dso *dso = arg; 752ee756ef7SIan Rogers struct rb_root_cached *root = dso__symbols(dso); 753682b335aSArnaldo Carvalho de Melo 7543183f8caSArnaldo Carvalho de Melo if (!symbol_type__filter(type)) 755682b335aSArnaldo Carvalho de Melo return 0; 756682b335aSArnaldo Carvalho de Melo 7571a86f4baSLexi Shao /* Ignore local symbols for ARM modules */ 7581a86f4baSLexi Shao if (name[0] == '$') 7591a86f4baSLexi Shao return 0; 7601a86f4baSLexi Shao 76182151520SCody P Schafer /* 76282151520SCody P Schafer * module symbols are not sorted so we add all 76382151520SCody P Schafer * symbols, setting length to 0, and rely on 76482151520SCody P Schafer * symbols__fixup_end() to fix it up. 76582151520SCody P Schafer */ 766af30bffaSArnaldo Carvalho de Melo sym = symbol__new(start, 0, kallsyms2elf_binding(type), kallsyms2elf_type(type), name); 7672e538c4aSArnaldo Carvalho de Melo if (sym == NULL) 768682b335aSArnaldo Carvalho de Melo return -ENOMEM; 76982164161SArnaldo Carvalho de Melo /* 77082164161SArnaldo Carvalho de Melo * We will pass the symbols to the filter later, in 7714e06255fSArnaldo Carvalho de Melo * map__split_kallsyms, when we have split the maps per module 77282164161SArnaldo Carvalho de Melo */ 773608c34deSArnaldo Carvalho de Melo __symbols__insert(root, sym, !strchr(name, '[')); 774a1645ce1SZhang, Yanmin 775682b335aSArnaldo Carvalho de Melo return 0; 7762e538c4aSArnaldo Carvalho de Melo } 7772e538c4aSArnaldo Carvalho de Melo 778682b335aSArnaldo Carvalho de Melo /* 779682b335aSArnaldo Carvalho de Melo * Loads the function entries in /proc/kallsyms into kernel_map->dso, 780682b335aSArnaldo Carvalho de Melo * so that we can in the next step set the symbol ->end address and then 781682b335aSArnaldo Carvalho de Melo * call kernel_maps__split_kallsyms. 782682b335aSArnaldo Carvalho de Melo */ 783333cc76cSArnaldo Carvalho de Melo static int dso__load_all_kallsyms(struct dso *dso, const char *filename) 784682b335aSArnaldo Carvalho de Melo { 785333cc76cSArnaldo Carvalho de Melo return kallsyms__parse(filename, dso, map__process_kallsym_symbol); 7862e538c4aSArnaldo Carvalho de Melo } 7872e538c4aSArnaldo Carvalho de Melo 78879b6bb73SArnaldo Carvalho de Melo static int maps__split_kallsyms_for_kcore(struct maps *kmaps, struct dso *dso) 7898e0cf965SAdrian Hunter { 7908e0cf965SAdrian Hunter struct symbol *pos; 791866548ddSAdrian Hunter int count = 0; 792ee756ef7SIan Rogers struct rb_root_cached *root = dso__symbols(dso); 793ee756ef7SIan Rogers struct rb_root_cached old_root = *root; 7947137ff50SDavidlohr Bueso struct rb_node *next = rb_first_cached(root); 7958e0cf965SAdrian Hunter 796ba92732eSWang Nan if (!kmaps) 797ba92732eSWang Nan return -1; 798ba92732eSWang Nan 7997137ff50SDavidlohr Bueso *root = RB_ROOT_CACHED; 800866548ddSAdrian Hunter 8018e0cf965SAdrian Hunter while (next) { 80242fd623bSIan Rogers struct map *curr_map; 80363df0e4bSIan Rogers struct dso *curr_map_dso; 8048e0cf965SAdrian Hunter char *module; 8058e0cf965SAdrian Hunter 8068e0cf965SAdrian Hunter pos = rb_entry(next, struct symbol, rb_node); 8078e0cf965SAdrian Hunter next = rb_next(&pos->rb_node); 8088e0cf965SAdrian Hunter 8097137ff50SDavidlohr Bueso rb_erase_cached(&pos->rb_node, &old_root); 8107137ff50SDavidlohr Bueso RB_CLEAR_NODE(&pos->rb_node); 8118e0cf965SAdrian Hunter module = strchr(pos->name, '\t'); 8128e0cf965SAdrian Hunter if (module) 8138e0cf965SAdrian Hunter *module = '\0'; 8148e0cf965SAdrian Hunter 81579b6bb73SArnaldo Carvalho de Melo curr_map = maps__find(kmaps, pos->start); 8168e0cf965SAdrian Hunter 817be39db9fSArnaldo Carvalho de Melo if (!curr_map) { 8188e0cf965SAdrian Hunter symbol__delete(pos); 819866548ddSAdrian Hunter continue; 820866548ddSAdrian Hunter } 82163df0e4bSIan Rogers curr_map_dso = map__dso(curr_map); 8222a6e5e8aSIan Rogers pos->start -= map__start(curr_map) - map__pgoff(curr_map); 823e5116f46SIan Rogers if (pos->end > map__end(curr_map)) 824e5116f46SIan Rogers pos->end = map__end(curr_map); 8258e0cf965SAdrian Hunter if (pos->end) 8262a6e5e8aSIan Rogers pos->end -= map__start(curr_map) - map__pgoff(curr_map); 827ee756ef7SIan Rogers symbols__insert(dso__symbols(curr_map_dso), pos); 8288e0cf965SAdrian Hunter ++count; 82942fd623bSIan Rogers map__put(curr_map); 8308e0cf965SAdrian Hunter } 8318e0cf965SAdrian Hunter 8328e0cf965SAdrian Hunter /* Symbols have been adjusted */ 833ee756ef7SIan Rogers dso__set_adjust_symbols(dso, true); 8348e0cf965SAdrian Hunter 835866548ddSAdrian Hunter return count; 8368e0cf965SAdrian Hunter } 8378e0cf965SAdrian Hunter 8382e538c4aSArnaldo Carvalho de Melo /* 8392e538c4aSArnaldo Carvalho de Melo * Split the symbols into maps, making sure there are no overlaps, i.e. the 8402e538c4aSArnaldo Carvalho de Melo * kernel range is broken in several maps, named [kernel].N, as we don't have 8412e538c4aSArnaldo Carvalho de Melo * the original ELF section names vmlinux have. 8422e538c4aSArnaldo Carvalho de Melo */ 84379b6bb73SArnaldo Carvalho de Melo static int maps__split_kallsyms(struct maps *kmaps, struct dso *dso, u64 delta, 84415e0e2d4SArnaldo Carvalho de Melo struct map *initial_map) 8452e538c4aSArnaldo Carvalho de Melo { 846ba92732eSWang Nan struct machine *machine; 847107ef66cSIan Rogers struct map *curr_map = map__get(initial_map); 8482e538c4aSArnaldo Carvalho de Melo struct symbol *pos; 8498a953312SArnaldo Carvalho de Melo int count = 0, moved = 0; 850ee756ef7SIan Rogers struct rb_root_cached *root = dso__symbols(dso); 8517137ff50SDavidlohr Bueso struct rb_node *next = rb_first_cached(root); 8522e538c4aSArnaldo Carvalho de Melo int kernel_range = 0; 8534d004365SAdrian Hunter bool x86_64; 8542e538c4aSArnaldo Carvalho de Melo 855ba92732eSWang Nan if (!kmaps) 856ba92732eSWang Nan return -1; 857ba92732eSWang Nan 8585ab6d715SIan Rogers machine = maps__machine(kmaps); 859ba92732eSWang Nan 8604d004365SAdrian Hunter x86_64 = machine__is(machine, "x86_64"); 8614d004365SAdrian Hunter 8622e538c4aSArnaldo Carvalho de Melo while (next) { 8632e538c4aSArnaldo Carvalho de Melo char *module; 8642e538c4aSArnaldo Carvalho de Melo 8652e538c4aSArnaldo Carvalho de Melo pos = rb_entry(next, struct symbol, rb_node); 8662e538c4aSArnaldo Carvalho de Melo next = rb_next(&pos->rb_node); 8672e538c4aSArnaldo Carvalho de Melo 8682e538c4aSArnaldo Carvalho de Melo module = strchr(pos->name, '\t'); 8692e538c4aSArnaldo Carvalho de Melo if (module) { 87063df0e4bSIan Rogers struct dso *curr_map_dso; 87163df0e4bSIan Rogers 87275be6cf4SArnaldo Carvalho de Melo if (!symbol_conf.use_modules) 8731de8e245SArnaldo Carvalho de Melo goto discard_symbol; 8741de8e245SArnaldo Carvalho de Melo 8752e538c4aSArnaldo Carvalho de Melo *module++ = '\0'; 87663df0e4bSIan Rogers curr_map_dso = map__dso(curr_map); 877ee756ef7SIan Rogers if (strcmp(dso__short_name(curr_map_dso), module)) { 87878c32f4cSIan Rogers if (!RC_CHK_EQUAL(curr_map, initial_map) && 879ee756ef7SIan Rogers dso__kernel(dso) == DSO_SPACE__KERNEL_GUEST && 88023346f21SArnaldo Carvalho de Melo machine__is_default_guest(machine)) { 881a1645ce1SZhang, Yanmin /* 882a1645ce1SZhang, Yanmin * We assume all symbols of a module are 883a1645ce1SZhang, Yanmin * continuous in * kallsyms, so curr_map 884a1645ce1SZhang, Yanmin * points to a module and all its 885a1645ce1SZhang, Yanmin * symbols are in its kmap. Mark it as 886a1645ce1SZhang, Yanmin * loaded. 887a1645ce1SZhang, Yanmin */ 88863df0e4bSIan Rogers dso__set_loaded(curr_map_dso); 889af427bf5SArnaldo Carvalho de Melo } 890b7cece76SArnaldo Carvalho de Melo 891107ef66cSIan Rogers map__zput(curr_map); 89279b6bb73SArnaldo Carvalho de Melo curr_map = maps__find_by_name(kmaps, module); 893a1645ce1SZhang, Yanmin if (curr_map == NULL) { 8942f51903bSArnaldo Carvalho de Melo pr_debug("%s/proc/{kallsyms,modules} " 895a1645ce1SZhang, Yanmin "inconsistency while looking " 896a1645ce1SZhang, Yanmin "for \"%s\" module!\n", 89723346f21SArnaldo Carvalho de Melo machine->root_dir, module); 898107ef66cSIan Rogers curr_map = map__get(initial_map); 899a1645ce1SZhang, Yanmin goto discard_symbol; 900a1645ce1SZhang, Yanmin } 90163df0e4bSIan Rogers curr_map_dso = map__dso(curr_map); 902ee756ef7SIan Rogers if (dso__loaded(curr_map_dso) && 90323346f21SArnaldo Carvalho de Melo !machine__is_default_guest(machine)) 904b7cece76SArnaldo Carvalho de Melo goto discard_symbol; 905af427bf5SArnaldo Carvalho de Melo } 90686470930SIngo Molnar /* 9072e538c4aSArnaldo Carvalho de Melo * So that we look just like we get from .ko files, 90815e0e2d4SArnaldo Carvalho de Melo * i.e. not prelinked, relative to initial_map->start. 90986470930SIngo Molnar */ 91078a1f7cdSIan Rogers pos->start = map__map_ip(curr_map, pos->start); 91178a1f7cdSIan Rogers pos->end = map__map_ip(curr_map, pos->end); 9124d004365SAdrian Hunter } else if (x86_64 && is_entry_trampoline(pos->name)) { 9134d004365SAdrian Hunter /* 9144d004365SAdrian Hunter * These symbols are not needed anymore since the 9154d004365SAdrian Hunter * trampoline maps refer to the text section and it's 9164d004365SAdrian Hunter * symbols instead. Avoid having to deal with 9174d004365SAdrian Hunter * relocations, and the assumption that the first symbol 9184d004365SAdrian Hunter * is the start of kernel text, by simply removing the 9194d004365SAdrian Hunter * symbols at this point. 9204d004365SAdrian Hunter */ 9214d004365SAdrian Hunter goto discard_symbol; 922107ef66cSIan Rogers } else if (!RC_CHK_EQUAL(curr_map, initial_map)) { 9232e538c4aSArnaldo Carvalho de Melo char dso_name[PATH_MAX]; 924aeafcbafSArnaldo Carvalho de Melo struct dso *ndso; 92586470930SIngo Molnar 926d9b62abaSAdrian Hunter if (delta) { 927d9b62abaSAdrian Hunter /* Kernel was relocated at boot time */ 928d9b62abaSAdrian Hunter pos->start -= delta; 929d9b62abaSAdrian Hunter pos->end -= delta; 930d9b62abaSAdrian Hunter } 931d9b62abaSAdrian Hunter 9328a953312SArnaldo Carvalho de Melo if (count == 0) { 933107ef66cSIan Rogers map__zput(curr_map); 934107ef66cSIan Rogers curr_map = map__get(initial_map); 935be39db9fSArnaldo Carvalho de Melo goto add_symbol; 9368a953312SArnaldo Carvalho de Melo } 9378a953312SArnaldo Carvalho de Melo 938ee756ef7SIan Rogers if (dso__kernel(dso) == DSO_SPACE__KERNEL_GUEST) 939a1645ce1SZhang, Yanmin snprintf(dso_name, sizeof(dso_name), 940a1645ce1SZhang, Yanmin "[guest.kernel].%d", 941a1645ce1SZhang, Yanmin kernel_range++); 942a1645ce1SZhang, Yanmin else 943a1645ce1SZhang, Yanmin snprintf(dso_name, sizeof(dso_name), 944a1645ce1SZhang, Yanmin "[kernel].%d", 9452e538c4aSArnaldo Carvalho de Melo kernel_range++); 94686470930SIngo Molnar 947aeafcbafSArnaldo Carvalho de Melo ndso = dso__new(dso_name); 948107ef66cSIan Rogers map__zput(curr_map); 949aeafcbafSArnaldo Carvalho de Melo if (ndso == NULL) 9502e538c4aSArnaldo Carvalho de Melo return -1; 9512e538c4aSArnaldo Carvalho de Melo 952ee756ef7SIan Rogers dso__set_kernel(ndso, dso__kernel(dso)); 953a1645ce1SZhang, Yanmin 9543183f8caSArnaldo Carvalho de Melo curr_map = map__new2(pos->start, ndso); 95537fe5fcbSZhang, Yanmin if (curr_map == NULL) { 956d3a7c489SArnaldo Carvalho de Melo dso__put(ndso); 9572e538c4aSArnaldo Carvalho de Melo return -1; 9582e538c4aSArnaldo Carvalho de Melo } 9592e538c4aSArnaldo Carvalho de Melo 9609fa688eaSIan Rogers map__set_mapping_type(curr_map, MAPPING_TYPE__IDENTITY); 961ff583dc4SIan Rogers if (maps__insert(kmaps, curr_map)) { 962107ef66cSIan Rogers map__zput(curr_map); 963ff583dc4SIan Rogers dso__put(ndso); 964ff583dc4SIan Rogers return -1; 965ff583dc4SIan Rogers } 9662e538c4aSArnaldo Carvalho de Melo ++kernel_range; 967d9b62abaSAdrian Hunter } else if (delta) { 968d9b62abaSAdrian Hunter /* Kernel was relocated at boot time */ 969d9b62abaSAdrian Hunter pos->start -= delta; 970d9b62abaSAdrian Hunter pos->end -= delta; 9712e538c4aSArnaldo Carvalho de Melo } 972be39db9fSArnaldo Carvalho de Melo add_symbol: 973107ef66cSIan Rogers if (!RC_CHK_EQUAL(curr_map, initial_map)) { 97463df0e4bSIan Rogers struct dso *curr_map_dso = map__dso(curr_map); 97563df0e4bSIan Rogers 9767137ff50SDavidlohr Bueso rb_erase_cached(&pos->rb_node, root); 977ee756ef7SIan Rogers symbols__insert(dso__symbols(curr_map_dso), pos); 9788a953312SArnaldo Carvalho de Melo ++moved; 9798a953312SArnaldo Carvalho de Melo } else 9808a953312SArnaldo Carvalho de Melo ++count; 981be39db9fSArnaldo Carvalho de Melo 982be39db9fSArnaldo Carvalho de Melo continue; 983be39db9fSArnaldo Carvalho de Melo discard_symbol: 9847137ff50SDavidlohr Bueso rb_erase_cached(&pos->rb_node, root); 985be39db9fSArnaldo Carvalho de Melo symbol__delete(pos); 98686470930SIngo Molnar } 98786470930SIngo Molnar 988107ef66cSIan Rogers if (!RC_CHK_EQUAL(curr_map, initial_map) && 989ee756ef7SIan Rogers dso__kernel(dso) == DSO_SPACE__KERNEL_GUEST && 9905ab6d715SIan Rogers machine__is_default_guest(maps__machine(kmaps))) { 99163df0e4bSIan Rogers dso__set_loaded(map__dso(curr_map)); 992a1645ce1SZhang, Yanmin } 993107ef66cSIan Rogers map__put(curr_map); 9948a953312SArnaldo Carvalho de Melo return count + moved; 99586470930SIngo Molnar } 99686470930SIngo Molnar 9973f067dcaSArnaldo Carvalho de Melo bool symbol__restricted_filename(const char *filename, 998ec80fde7SArnaldo Carvalho de Melo const char *restricted_filename) 999ec80fde7SArnaldo Carvalho de Melo { 1000ec80fde7SArnaldo Carvalho de Melo bool restricted = false; 1001ec80fde7SArnaldo Carvalho de Melo 1002ec80fde7SArnaldo Carvalho de Melo if (symbol_conf.kptr_restrict) { 1003ec80fde7SArnaldo Carvalho de Melo char *r = realpath(filename, NULL); 1004ec80fde7SArnaldo Carvalho de Melo 1005ec80fde7SArnaldo Carvalho de Melo if (r != NULL) { 1006ec80fde7SArnaldo Carvalho de Melo restricted = strcmp(r, restricted_filename) == 0; 1007ec80fde7SArnaldo Carvalho de Melo free(r); 1008ec80fde7SArnaldo Carvalho de Melo return restricted; 1009ec80fde7SArnaldo Carvalho de Melo } 1010ec80fde7SArnaldo Carvalho de Melo } 1011ec80fde7SArnaldo Carvalho de Melo 1012ec80fde7SArnaldo Carvalho de Melo return restricted; 1013ec80fde7SArnaldo Carvalho de Melo } 1014ec80fde7SArnaldo Carvalho de Melo 101552afdaf9SAdrian Hunter struct module_info { 101652afdaf9SAdrian Hunter struct rb_node rb_node; 101752afdaf9SAdrian Hunter char *name; 101852afdaf9SAdrian Hunter u64 start; 101952afdaf9SAdrian Hunter }; 102052afdaf9SAdrian Hunter 102152afdaf9SAdrian Hunter static void add_module(struct module_info *mi, struct rb_root *modules) 102252afdaf9SAdrian Hunter { 102352afdaf9SAdrian Hunter struct rb_node **p = &modules->rb_node; 102452afdaf9SAdrian Hunter struct rb_node *parent = NULL; 102552afdaf9SAdrian Hunter struct module_info *m; 102652afdaf9SAdrian Hunter 102752afdaf9SAdrian Hunter while (*p != NULL) { 102852afdaf9SAdrian Hunter parent = *p; 102952afdaf9SAdrian Hunter m = rb_entry(parent, struct module_info, rb_node); 103052afdaf9SAdrian Hunter if (strcmp(mi->name, m->name) < 0) 103152afdaf9SAdrian Hunter p = &(*p)->rb_left; 103252afdaf9SAdrian Hunter else 103352afdaf9SAdrian Hunter p = &(*p)->rb_right; 103452afdaf9SAdrian Hunter } 103552afdaf9SAdrian Hunter rb_link_node(&mi->rb_node, parent, p); 103652afdaf9SAdrian Hunter rb_insert_color(&mi->rb_node, modules); 103752afdaf9SAdrian Hunter } 103852afdaf9SAdrian Hunter 103952afdaf9SAdrian Hunter static void delete_modules(struct rb_root *modules) 104052afdaf9SAdrian Hunter { 104152afdaf9SAdrian Hunter struct module_info *mi; 104252afdaf9SAdrian Hunter struct rb_node *next = rb_first(modules); 104352afdaf9SAdrian Hunter 104452afdaf9SAdrian Hunter while (next) { 104552afdaf9SAdrian Hunter mi = rb_entry(next, struct module_info, rb_node); 104652afdaf9SAdrian Hunter next = rb_next(&mi->rb_node); 104752afdaf9SAdrian Hunter rb_erase(&mi->rb_node, modules); 104874cf249dSArnaldo Carvalho de Melo zfree(&mi->name); 104952afdaf9SAdrian Hunter free(mi); 105052afdaf9SAdrian Hunter } 105152afdaf9SAdrian Hunter } 105252afdaf9SAdrian Hunter 105352afdaf9SAdrian Hunter static struct module_info *find_module(const char *name, 105452afdaf9SAdrian Hunter struct rb_root *modules) 105552afdaf9SAdrian Hunter { 105652afdaf9SAdrian Hunter struct rb_node *n = modules->rb_node; 105752afdaf9SAdrian Hunter 105852afdaf9SAdrian Hunter while (n) { 105952afdaf9SAdrian Hunter struct module_info *m; 106052afdaf9SAdrian Hunter int cmp; 106152afdaf9SAdrian Hunter 106252afdaf9SAdrian Hunter m = rb_entry(n, struct module_info, rb_node); 106352afdaf9SAdrian Hunter cmp = strcmp(name, m->name); 106452afdaf9SAdrian Hunter if (cmp < 0) 106552afdaf9SAdrian Hunter n = n->rb_left; 106652afdaf9SAdrian Hunter else if (cmp > 0) 106752afdaf9SAdrian Hunter n = n->rb_right; 106852afdaf9SAdrian Hunter else 106952afdaf9SAdrian Hunter return m; 107052afdaf9SAdrian Hunter } 107152afdaf9SAdrian Hunter 107252afdaf9SAdrian Hunter return NULL; 107352afdaf9SAdrian Hunter } 107452afdaf9SAdrian Hunter 10759ad4652bSThomas Richter static int __read_proc_modules(void *arg, const char *name, u64 start, 10769ad4652bSThomas Richter u64 size __maybe_unused) 107752afdaf9SAdrian Hunter { 107852afdaf9SAdrian Hunter struct rb_root *modules = arg; 107952afdaf9SAdrian Hunter struct module_info *mi; 108052afdaf9SAdrian Hunter 108152afdaf9SAdrian Hunter mi = zalloc(sizeof(struct module_info)); 108252afdaf9SAdrian Hunter if (!mi) 108352afdaf9SAdrian Hunter return -ENOMEM; 108452afdaf9SAdrian Hunter 108552afdaf9SAdrian Hunter mi->name = strdup(name); 108652afdaf9SAdrian Hunter mi->start = start; 108752afdaf9SAdrian Hunter 108852afdaf9SAdrian Hunter if (!mi->name) { 108952afdaf9SAdrian Hunter free(mi); 109052afdaf9SAdrian Hunter return -ENOMEM; 109152afdaf9SAdrian Hunter } 109252afdaf9SAdrian Hunter 109352afdaf9SAdrian Hunter add_module(mi, modules); 109452afdaf9SAdrian Hunter 109552afdaf9SAdrian Hunter return 0; 109652afdaf9SAdrian Hunter } 109752afdaf9SAdrian Hunter 109852afdaf9SAdrian Hunter static int read_proc_modules(const char *filename, struct rb_root *modules) 109952afdaf9SAdrian Hunter { 110052afdaf9SAdrian Hunter if (symbol__restricted_filename(filename, "/proc/modules")) 110152afdaf9SAdrian Hunter return -1; 110252afdaf9SAdrian Hunter 110352afdaf9SAdrian Hunter if (modules__parse(filename, modules, __read_proc_modules)) { 110452afdaf9SAdrian Hunter delete_modules(modules); 110552afdaf9SAdrian Hunter return -1; 110652afdaf9SAdrian Hunter } 110752afdaf9SAdrian Hunter 110852afdaf9SAdrian Hunter return 0; 110952afdaf9SAdrian Hunter } 111052afdaf9SAdrian Hunter 1111fc1b691dSAdrian Hunter int compare_proc_modules(const char *from, const char *to) 1112fc1b691dSAdrian Hunter { 1113fc1b691dSAdrian Hunter struct rb_root from_modules = RB_ROOT; 1114fc1b691dSAdrian Hunter struct rb_root to_modules = RB_ROOT; 1115fc1b691dSAdrian Hunter struct rb_node *from_node, *to_node; 1116fc1b691dSAdrian Hunter struct module_info *from_m, *to_m; 1117fc1b691dSAdrian Hunter int ret = -1; 1118fc1b691dSAdrian Hunter 1119fc1b691dSAdrian Hunter if (read_proc_modules(from, &from_modules)) 1120fc1b691dSAdrian Hunter return -1; 1121fc1b691dSAdrian Hunter 1122fc1b691dSAdrian Hunter if (read_proc_modules(to, &to_modules)) 1123fc1b691dSAdrian Hunter goto out_delete_from; 1124fc1b691dSAdrian Hunter 1125fc1b691dSAdrian Hunter from_node = rb_first(&from_modules); 1126fc1b691dSAdrian Hunter to_node = rb_first(&to_modules); 1127fc1b691dSAdrian Hunter while (from_node) { 1128fc1b691dSAdrian Hunter if (!to_node) 1129fc1b691dSAdrian Hunter break; 1130fc1b691dSAdrian Hunter 1131fc1b691dSAdrian Hunter from_m = rb_entry(from_node, struct module_info, rb_node); 1132fc1b691dSAdrian Hunter to_m = rb_entry(to_node, struct module_info, rb_node); 1133fc1b691dSAdrian Hunter 1134fc1b691dSAdrian Hunter if (from_m->start != to_m->start || 1135fc1b691dSAdrian Hunter strcmp(from_m->name, to_m->name)) 1136fc1b691dSAdrian Hunter break; 1137fc1b691dSAdrian Hunter 1138fc1b691dSAdrian Hunter from_node = rb_next(from_node); 1139fc1b691dSAdrian Hunter to_node = rb_next(to_node); 1140fc1b691dSAdrian Hunter } 1141fc1b691dSAdrian Hunter 1142fc1b691dSAdrian Hunter if (!from_node && !to_node) 1143fc1b691dSAdrian Hunter ret = 0; 1144fc1b691dSAdrian Hunter 1145fc1b691dSAdrian Hunter delete_modules(&to_modules); 1146fc1b691dSAdrian Hunter out_delete_from: 1147fc1b691dSAdrian Hunter delete_modules(&from_modules); 1148fc1b691dSAdrian Hunter 1149fc1b691dSAdrian Hunter return ret; 1150fc1b691dSAdrian Hunter } 1151fc1b691dSAdrian Hunter 1152111350c6SIan Rogers static int do_validate_kcore_modules_cb(struct map *old_map, void *data) 1153111350c6SIan Rogers { 1154111350c6SIan Rogers struct rb_root *modules = data; 1155111350c6SIan Rogers struct module_info *mi; 1156111350c6SIan Rogers struct dso *dso; 1157111350c6SIan Rogers 1158111350c6SIan Rogers if (!__map__is_kmodule(old_map)) 1159111350c6SIan Rogers return 0; 1160111350c6SIan Rogers 1161111350c6SIan Rogers dso = map__dso(old_map); 1162111350c6SIan Rogers /* Module must be in memory at the same address */ 1163ee756ef7SIan Rogers mi = find_module(dso__short_name(dso), modules); 1164111350c6SIan Rogers if (!mi || mi->start != map__start(old_map)) 1165111350c6SIan Rogers return -EINVAL; 1166111350c6SIan Rogers 1167111350c6SIan Rogers return 0; 1168111350c6SIan Rogers } 1169111350c6SIan Rogers 117079b6bb73SArnaldo Carvalho de Melo static int do_validate_kcore_modules(const char *filename, struct maps *kmaps) 117152afdaf9SAdrian Hunter { 117252afdaf9SAdrian Hunter struct rb_root modules = RB_ROOT; 117352afdaf9SAdrian Hunter int err; 117452afdaf9SAdrian Hunter 117552afdaf9SAdrian Hunter err = read_proc_modules(filename, &modules); 117652afdaf9SAdrian Hunter if (err) 117752afdaf9SAdrian Hunter return err; 117852afdaf9SAdrian Hunter 1179111350c6SIan Rogers err = maps__for_each_map(kmaps, do_validate_kcore_modules_cb, &modules); 118052afdaf9SAdrian Hunter 118152afdaf9SAdrian Hunter delete_modules(&modules); 118252afdaf9SAdrian Hunter return err; 118352afdaf9SAdrian Hunter } 118452afdaf9SAdrian Hunter 118552afdaf9SAdrian Hunter /* 118652afdaf9SAdrian Hunter * If kallsyms is referenced by name then we look for filename in the same 118752afdaf9SAdrian Hunter * directory. 118852afdaf9SAdrian Hunter */ 118952afdaf9SAdrian Hunter static bool filename_from_kallsyms_filename(char *filename, 119052afdaf9SAdrian Hunter const char *base_name, 119152afdaf9SAdrian Hunter const char *kallsyms_filename) 119252afdaf9SAdrian Hunter { 119352afdaf9SAdrian Hunter char *name; 119452afdaf9SAdrian Hunter 119552afdaf9SAdrian Hunter strcpy(filename, kallsyms_filename); 119652afdaf9SAdrian Hunter name = strrchr(filename, '/'); 119752afdaf9SAdrian Hunter if (!name) 119852afdaf9SAdrian Hunter return false; 119952afdaf9SAdrian Hunter 120052afdaf9SAdrian Hunter name += 1; 120152afdaf9SAdrian Hunter 120252afdaf9SAdrian Hunter if (!strcmp(name, "kallsyms")) { 120352afdaf9SAdrian Hunter strcpy(name, base_name); 120452afdaf9SAdrian Hunter return true; 120552afdaf9SAdrian Hunter } 120652afdaf9SAdrian Hunter 120752afdaf9SAdrian Hunter return false; 120852afdaf9SAdrian Hunter } 120952afdaf9SAdrian Hunter 121052afdaf9SAdrian Hunter static int validate_kcore_modules(const char *kallsyms_filename, 121152afdaf9SAdrian Hunter struct map *map) 121252afdaf9SAdrian Hunter { 121379b6bb73SArnaldo Carvalho de Melo struct maps *kmaps = map__kmaps(map); 121452afdaf9SAdrian Hunter char modules_filename[PATH_MAX]; 121552afdaf9SAdrian Hunter 1216ba92732eSWang Nan if (!kmaps) 1217ba92732eSWang Nan return -EINVAL; 1218ba92732eSWang Nan 121952afdaf9SAdrian Hunter if (!filename_from_kallsyms_filename(modules_filename, "modules", 122052afdaf9SAdrian Hunter kallsyms_filename)) 122152afdaf9SAdrian Hunter return -EINVAL; 122252afdaf9SAdrian Hunter 12235759a682SAdrian Hunter if (do_validate_kcore_modules(modules_filename, kmaps)) 122452afdaf9SAdrian Hunter return -EINVAL; 122552afdaf9SAdrian Hunter 122652afdaf9SAdrian Hunter return 0; 122752afdaf9SAdrian Hunter } 122852afdaf9SAdrian Hunter 1229a00d28cbSAdrian Hunter static int validate_kcore_addresses(const char *kallsyms_filename, 1230a00d28cbSAdrian Hunter struct map *map) 1231a00d28cbSAdrian Hunter { 1232a00d28cbSAdrian Hunter struct kmap *kmap = map__kmap(map); 1233a00d28cbSAdrian Hunter 1234ba92732eSWang Nan if (!kmap) 1235ba92732eSWang Nan return -EINVAL; 1236ba92732eSWang Nan 1237a00d28cbSAdrian Hunter if (kmap->ref_reloc_sym && kmap->ref_reloc_sym->name) { 1238a00d28cbSAdrian Hunter u64 start; 1239a00d28cbSAdrian Hunter 1240b843f62aSArnaldo Carvalho de Melo if (kallsyms__get_function_start(kallsyms_filename, 1241b843f62aSArnaldo Carvalho de Melo kmap->ref_reloc_sym->name, &start)) 1242b843f62aSArnaldo Carvalho de Melo return -ENOENT; 1243a00d28cbSAdrian Hunter if (start != kmap->ref_reloc_sym->addr) 1244a00d28cbSAdrian Hunter return -EINVAL; 1245a00d28cbSAdrian Hunter } 1246a00d28cbSAdrian Hunter 1247a00d28cbSAdrian Hunter return validate_kcore_modules(kallsyms_filename, map); 1248a00d28cbSAdrian Hunter } 1249a00d28cbSAdrian Hunter 12508e0cf965SAdrian Hunter struct kcore_mapfn_data { 12518e0cf965SAdrian Hunter struct dso *dso; 12528e0cf965SAdrian Hunter struct list_head maps; 12538e0cf965SAdrian Hunter }; 12548e0cf965SAdrian Hunter 12558e0cf965SAdrian Hunter static int kcore_mapfn(u64 start, u64 len, u64 pgoff, void *data) 12568e0cf965SAdrian Hunter { 12578e0cf965SAdrian Hunter struct kcore_mapfn_data *md = data; 125883720209SIan Rogers struct map_list_node *list_node = map_list_node__new(); 12598e0cf965SAdrian Hunter 126083720209SIan Rogers if (!list_node) 12618e0cf965SAdrian Hunter return -ENOMEM; 12628e0cf965SAdrian Hunter 126383720209SIan Rogers list_node->map = map__new2(start, md->dso); 126483720209SIan Rogers if (!list_node->map) { 126583720209SIan Rogers free(list_node); 126683720209SIan Rogers return -ENOMEM; 126783720209SIan Rogers } 12688e0cf965SAdrian Hunter 1269e6a9efceSArnaldo Carvalho de Melo map__set_end(list_node->map, map__start(list_node->map) + len); 1270e6a9efceSArnaldo Carvalho de Melo map__set_pgoff(list_node->map, pgoff); 127183720209SIan Rogers 127283720209SIan Rogers list_add(&list_node->node, &md->maps); 12738e0cf965SAdrian Hunter 12748e0cf965SAdrian Hunter return 0; 12758e0cf965SAdrian Hunter } 12768e0cf965SAdrian Hunter 12778d5847a6SIan Rogers static bool remove_old_maps(struct map *map, void *data) 12788d5847a6SIan Rogers { 12798d5847a6SIan Rogers const struct map *map_to_save = data; 12808d5847a6SIan Rogers 12818d5847a6SIan Rogers /* 12828d5847a6SIan Rogers * We need to preserve eBPF maps even if they are covered by kcore, 12838d5847a6SIan Rogers * because we need to access eBPF dso for source data. 12848d5847a6SIan Rogers */ 12858d5847a6SIan Rogers return !RC_CHK_EQUAL(map, map_to_save) && !__map__is_bpf_prog(map); 12868d5847a6SIan Rogers } 12878d5847a6SIan Rogers 12888e0cf965SAdrian Hunter static int dso__load_kcore(struct dso *dso, struct map *map, 12898e0cf965SAdrian Hunter const char *kallsyms_filename) 12908e0cf965SAdrian Hunter { 129179b6bb73SArnaldo Carvalho de Melo struct maps *kmaps = map__kmaps(map); 12928e0cf965SAdrian Hunter struct kcore_mapfn_data md; 1293f30232b2SJames Clark struct map *map_ref, *replacement_map = NULL; 12941c5aae77SAdrian Hunter struct machine *machine; 12958e0cf965SAdrian Hunter bool is_64_bit; 12968e0cf965SAdrian Hunter int err, fd; 12978e0cf965SAdrian Hunter char kcore_filename[PATH_MAX]; 129856549978SAdrian Hunter u64 stext; 12998e0cf965SAdrian Hunter 1300ba92732eSWang Nan if (!kmaps) 1301ba92732eSWang Nan return -EINVAL; 1302ba92732eSWang Nan 13035ab6d715SIan Rogers machine = maps__machine(kmaps); 13041c5aae77SAdrian Hunter 13058e0cf965SAdrian Hunter /* This function requires that the map is the kernel map */ 1306efdd5c6bSArnaldo Carvalho de Melo if (!__map__is_kernel(map)) 13078e0cf965SAdrian Hunter return -EINVAL; 13088e0cf965SAdrian Hunter 130952afdaf9SAdrian Hunter if (!filename_from_kallsyms_filename(kcore_filename, "kcore", 13108e0cf965SAdrian Hunter kallsyms_filename)) 13118e0cf965SAdrian Hunter return -EINVAL; 13128e0cf965SAdrian Hunter 1313a00d28cbSAdrian Hunter /* Modules and kernel must be present at their original addresses */ 1314a00d28cbSAdrian Hunter if (validate_kcore_addresses(kallsyms_filename, map)) 131552afdaf9SAdrian Hunter return -EINVAL; 131652afdaf9SAdrian Hunter 13178e0cf965SAdrian Hunter md.dso = dso; 13188e0cf965SAdrian Hunter INIT_LIST_HEAD(&md.maps); 13198e0cf965SAdrian Hunter 13208e0cf965SAdrian Hunter fd = open(kcore_filename, O_RDONLY); 132136c8bb56SLi Zhang if (fd < 0) { 1322133de940SAdrian Hunter pr_debug("Failed to open %s. Note /proc/kcore requires CAP_SYS_RAWIO capability to access.\n", 132336c8bb56SLi Zhang kcore_filename); 13248e0cf965SAdrian Hunter return -EINVAL; 132536c8bb56SLi Zhang } 13268e0cf965SAdrian Hunter 13278e0cf965SAdrian Hunter /* Read new maps into temporary lists */ 1328ddee3f2bSIan Rogers err = file__read_maps(fd, map__prot(map) & PROT_EXEC, kcore_mapfn, &md, 13298e0cf965SAdrian Hunter &is_64_bit); 13308e0cf965SAdrian Hunter if (err) 13318e0cf965SAdrian Hunter goto out_err; 1332ee756ef7SIan Rogers dso__set_is_64_bit(dso, is_64_bit); 13338e0cf965SAdrian Hunter 13348e0cf965SAdrian Hunter if (list_empty(&md.maps)) { 13358e0cf965SAdrian Hunter err = -EINVAL; 13368e0cf965SAdrian Hunter goto out_err; 13378e0cf965SAdrian Hunter } 13388e0cf965SAdrian Hunter 13398e0cf965SAdrian Hunter /* Remove old maps */ 13408d5847a6SIan Rogers maps__remove_maps(kmaps, remove_old_maps, map); 13411c5aae77SAdrian Hunter machine->trampolines_mapped = false; 13428e0cf965SAdrian Hunter 134356549978SAdrian Hunter /* Find the kernel map using the '_stext' symbol */ 134456549978SAdrian Hunter if (!kallsyms__get_function_start(kallsyms_filename, "_stext", &stext)) { 13451c249565SKrister Johansen u64 replacement_size = 0; 134683720209SIan Rogers struct map_list_node *new_node; 13471c249565SKrister Johansen 134883720209SIan Rogers list_for_each_entry(new_node, &md.maps, node) { 134983720209SIan Rogers struct map *new_map = new_node->map; 1350e5116f46SIan Rogers u64 new_size = map__size(new_map); 13511c249565SKrister Johansen 1352e5116f46SIan Rogers if (!(stext >= map__start(new_map) && stext < map__end(new_map))) 13531c249565SKrister Johansen continue; 13541c249565SKrister Johansen 13551c249565SKrister Johansen /* 13561c249565SKrister Johansen * On some architectures, ARM64 for example, the kernel 13571c249565SKrister Johansen * text can get allocated inside of the vmalloc segment. 13581c249565SKrister Johansen * Select the smallest matching segment, in case stext 13591c249565SKrister Johansen * falls within more than one in the list. 13601c249565SKrister Johansen */ 13611c249565SKrister Johansen if (!replacement_map || new_size < replacement_size) { 13628e0cf965SAdrian Hunter replacement_map = new_map; 13631c249565SKrister Johansen replacement_size = new_size; 13648e0cf965SAdrian Hunter } 13658e0cf965SAdrian Hunter } 136656549978SAdrian Hunter } 13678e0cf965SAdrian Hunter 13688e0cf965SAdrian Hunter if (!replacement_map) 136983720209SIan Rogers replacement_map = list_entry(md.maps.next, struct map_list_node, node)->map; 13708e0cf965SAdrian Hunter 1371f30232b2SJames Clark /* 1372f30232b2SJames Clark * Update addresses of vmlinux map. Re-insert it to ensure maps are 1373f30232b2SJames Clark * correctly ordered. Do this before using maps__merge_in() for the 1374f30232b2SJames Clark * remaining maps so vmlinux gets split if necessary. 1375f30232b2SJames Clark */ 1376f30232b2SJames Clark map_ref = map__get(map); 1377f30232b2SJames Clark maps__remove(kmaps, map_ref); 1378f30232b2SJames Clark 1379f30232b2SJames Clark map__set_start(map_ref, map__start(replacement_map)); 1380f30232b2SJames Clark map__set_end(map_ref, map__end(replacement_map)); 1381f30232b2SJames Clark map__set_pgoff(map_ref, map__pgoff(replacement_map)); 1382f30232b2SJames Clark map__set_mapping_type(map_ref, map__mapping_type(replacement_map)); 1383f30232b2SJames Clark 1384f30232b2SJames Clark err = maps__insert(kmaps, map_ref); 1385f30232b2SJames Clark map__put(map_ref); 1386f30232b2SJames Clark if (err) 1387f30232b2SJames Clark goto out_err; 1388f30232b2SJames Clark 13898e0cf965SAdrian Hunter /* Add new maps */ 13908e0cf965SAdrian Hunter while (!list_empty(&md.maps)) { 139183720209SIan Rogers struct map_list_node *new_node = list_entry(md.maps.next, struct map_list_node, node); 139283720209SIan Rogers struct map *new_map = new_node->map; 139383720209SIan Rogers 139483720209SIan Rogers list_del_init(&new_node->node); 139583720209SIan Rogers 1396f30232b2SJames Clark /* skip if replacement_map, already inserted above */ 1397f30232b2SJames Clark if (!RC_CHK_EQUAL(new_map, replacement_map)) { 1398fb5a88d4SJiri Olsa /* 1399fb5a88d4SJiri Olsa * Merge kcore map into existing maps, 1400fb5a88d4SJiri Olsa * and ensure that current maps (eBPF) 1401fb5a88d4SJiri Olsa * stay intact. 1402fb5a88d4SJiri Olsa */ 1403ff583dc4SIan Rogers if (maps__merge_in(kmaps, new_map)) { 1404ff583dc4SIan Rogers err = -EINVAL; 1405fb5a88d4SJiri Olsa goto out_err; 1406fb5a88d4SJiri Olsa } 1407ff583dc4SIan Rogers } 140883720209SIan Rogers free(new_node); 14098e0cf965SAdrian Hunter } 14108e0cf965SAdrian Hunter 14111c5aae77SAdrian Hunter if (machine__is(machine, "x86_64")) { 14121c5aae77SAdrian Hunter u64 addr; 14131c5aae77SAdrian Hunter 14141c5aae77SAdrian Hunter /* 14151c5aae77SAdrian Hunter * If one of the corresponding symbols is there, assume the 14161c5aae77SAdrian Hunter * entry trampoline maps are too. 14171c5aae77SAdrian Hunter */ 14181c5aae77SAdrian Hunter if (!kallsyms__get_function_start(kallsyms_filename, 14191c5aae77SAdrian Hunter ENTRY_TRAMPOLINE_NAME, 14201c5aae77SAdrian Hunter &addr)) 14211c5aae77SAdrian Hunter machine->trampolines_mapped = true; 14221c5aae77SAdrian Hunter } 14231c5aae77SAdrian Hunter 14248e0cf965SAdrian Hunter /* 14258e0cf965SAdrian Hunter * Set the data type and long name so that kcore can be read via 14268e0cf965SAdrian Hunter * dso__data_read_addr(). 14278e0cf965SAdrian Hunter */ 1428ee756ef7SIan Rogers if (dso__kernel(dso) == DSO_SPACE__KERNEL_GUEST) 1429ee756ef7SIan Rogers dso__set_binary_type(dso, DSO_BINARY_TYPE__GUEST_KCORE); 14308e0cf965SAdrian Hunter else 1431ee756ef7SIan Rogers dso__set_binary_type(dso, DSO_BINARY_TYPE__KCORE); 14327e155d4dSArnaldo Carvalho de Melo dso__set_long_name(dso, strdup(kcore_filename), true); 14338e0cf965SAdrian Hunter 14348e0cf965SAdrian Hunter close(fd); 14358e0cf965SAdrian Hunter 1436ddee3f2bSIan Rogers if (map__prot(map) & PROT_EXEC) 14378e0cf965SAdrian Hunter pr_debug("Using %s for kernel object code\n", kcore_filename); 14388e0cf965SAdrian Hunter else 14398e0cf965SAdrian Hunter pr_debug("Using %s for kernel data\n", kcore_filename); 14408e0cf965SAdrian Hunter 14418e0cf965SAdrian Hunter return 0; 14428e0cf965SAdrian Hunter 14438e0cf965SAdrian Hunter out_err: 14448e0cf965SAdrian Hunter while (!list_empty(&md.maps)) { 144583720209SIan Rogers struct map_list_node *list_node; 144683720209SIan Rogers 144783720209SIan Rogers list_node = list_entry(md.maps.next, struct map_list_node, node); 144883720209SIan Rogers list_del_init(&list_node->node); 144983720209SIan Rogers map__zput(list_node->map); 145083720209SIan Rogers free(list_node); 14518e0cf965SAdrian Hunter } 14528e0cf965SAdrian Hunter close(fd); 1453ff583dc4SIan Rogers return err; 14548e0cf965SAdrian Hunter } 14558e0cf965SAdrian Hunter 1456d9b62abaSAdrian Hunter /* 1457d9b62abaSAdrian Hunter * If the kernel is relocated at boot time, kallsyms won't match. Compute the 1458d9b62abaSAdrian Hunter * delta based on the relocation reference symbol. 1459d9b62abaSAdrian Hunter */ 1460019c6820SArnaldo Carvalho de Melo static int kallsyms__delta(struct kmap *kmap, const char *filename, u64 *delta) 1461d9b62abaSAdrian Hunter { 1462d9b62abaSAdrian Hunter u64 addr; 1463d9b62abaSAdrian Hunter 1464d9b62abaSAdrian Hunter if (!kmap->ref_reloc_sym || !kmap->ref_reloc_sym->name) 1465d9b62abaSAdrian Hunter return 0; 1466d9b62abaSAdrian Hunter 1467b843f62aSArnaldo Carvalho de Melo if (kallsyms__get_function_start(filename, kmap->ref_reloc_sym->name, &addr)) 1468d9b62abaSAdrian Hunter return -1; 1469d9b62abaSAdrian Hunter 1470d9b62abaSAdrian Hunter *delta = addr - kmap->ref_reloc_sym->addr; 1471d9b62abaSAdrian Hunter return 0; 1472d9b62abaSAdrian Hunter } 1473d9b62abaSAdrian Hunter 1474e02092b9SArnaldo Carvalho de Melo int __dso__load_kallsyms(struct dso *dso, const char *filename, 1475be39db9fSArnaldo Carvalho de Melo struct map *map, bool no_kcore) 14762e538c4aSArnaldo Carvalho de Melo { 1477019c6820SArnaldo Carvalho de Melo struct kmap *kmap = map__kmap(map); 1478d9b62abaSAdrian Hunter u64 delta = 0; 1479d9b62abaSAdrian Hunter 1480ec80fde7SArnaldo Carvalho de Melo if (symbol__restricted_filename(filename, "/proc/kallsyms")) 1481ec80fde7SArnaldo Carvalho de Melo return -1; 1482ec80fde7SArnaldo Carvalho de Melo 1483019c6820SArnaldo Carvalho de Melo if (!kmap || !kmap->kmaps) 1484019c6820SArnaldo Carvalho de Melo return -1; 1485019c6820SArnaldo Carvalho de Melo 1486333cc76cSArnaldo Carvalho de Melo if (dso__load_all_kallsyms(dso, filename) < 0) 14872e538c4aSArnaldo Carvalho de Melo return -1; 14882e538c4aSArnaldo Carvalho de Melo 1489019c6820SArnaldo Carvalho de Melo if (kallsyms__delta(kmap, filename, &delta)) 1490d9b62abaSAdrian Hunter return -1; 1491d9b62abaSAdrian Hunter 1492ee756ef7SIan Rogers symbols__fixup_end(dso__symbols(dso), true); 1493ee756ef7SIan Rogers symbols__fixup_duplicate(dso__symbols(dso)); 14943f5a4272SAnton Blanchard 1495ee756ef7SIan Rogers if (dso__kernel(dso) == DSO_SPACE__KERNEL_GUEST) 1496ee756ef7SIan Rogers dso__set_symtab_type(dso, DSO_BINARY_TYPE__GUEST_KALLSYMS); 1497a1645ce1SZhang, Yanmin else 1498ee756ef7SIan Rogers dso__set_symtab_type(dso, DSO_BINARY_TYPE__KALLSYMS); 14992e538c4aSArnaldo Carvalho de Melo 1500e02092b9SArnaldo Carvalho de Melo if (!no_kcore && !dso__load_kcore(dso, map, filename)) 150179b6bb73SArnaldo Carvalho de Melo return maps__split_kallsyms_for_kcore(kmap->kmaps, dso); 15028e0cf965SAdrian Hunter else 150379b6bb73SArnaldo Carvalho de Melo return maps__split_kallsyms(kmap->kmaps, dso, delta, map); 1504af427bf5SArnaldo Carvalho de Melo } 1505af427bf5SArnaldo Carvalho de Melo 1506e02092b9SArnaldo Carvalho de Melo int dso__load_kallsyms(struct dso *dso, const char *filename, 1507be39db9fSArnaldo Carvalho de Melo struct map *map) 1508e02092b9SArnaldo Carvalho de Melo { 1509be39db9fSArnaldo Carvalho de Melo return __dso__load_kallsyms(dso, filename, map, false); 1510e02092b9SArnaldo Carvalho de Melo } 1511e02092b9SArnaldo Carvalho de Melo 15123183f8caSArnaldo Carvalho de Melo static int dso__load_perf_map(const char *map_path, struct dso *dso) 151380d496beSPekka Enberg { 151480d496beSPekka Enberg char *line = NULL; 151580d496beSPekka Enberg size_t n; 151680d496beSPekka Enberg FILE *file; 151780d496beSPekka Enberg int nr_syms = 0; 151880d496beSPekka Enberg 1519bf2e710bSKrister Johansen file = fopen(map_path, "r"); 152080d496beSPekka Enberg if (file == NULL) 152180d496beSPekka Enberg goto out_failure; 152280d496beSPekka Enberg 152380d496beSPekka Enberg while (!feof(file)) { 15249cffa8d5SPaul Mackerras u64 start, size; 152580d496beSPekka Enberg struct symbol *sym; 152680d496beSPekka Enberg int line_len, len; 152780d496beSPekka Enberg 152880d496beSPekka Enberg line_len = getline(&line, &n, file); 152980d496beSPekka Enberg if (line_len < 0) 153080d496beSPekka Enberg break; 153180d496beSPekka Enberg 153280d496beSPekka Enberg if (!line) 153380d496beSPekka Enberg goto out_failure; 153480d496beSPekka Enberg 153580d496beSPekka Enberg line[--line_len] = '\0'; /* \n */ 153680d496beSPekka Enberg 153780d496beSPekka Enberg len = hex2u64(line, &start); 153880d496beSPekka Enberg 153980d496beSPekka Enberg len++; 154080d496beSPekka Enberg if (len + 2 >= line_len) 154180d496beSPekka Enberg continue; 154280d496beSPekka Enberg 154380d496beSPekka Enberg len += hex2u64(line + len, &size); 154480d496beSPekka Enberg 154580d496beSPekka Enberg len++; 154680d496beSPekka Enberg if (len + 2 >= line_len) 154780d496beSPekka Enberg continue; 154880d496beSPekka Enberg 1549af30bffaSArnaldo Carvalho de Melo sym = symbol__new(start, size, STB_GLOBAL, STT_FUNC, line + len); 155080d496beSPekka Enberg 155180d496beSPekka Enberg if (sym == NULL) 155280d496beSPekka Enberg goto out_delete_line; 155380d496beSPekka Enberg 1554ee756ef7SIan Rogers symbols__insert(dso__symbols(dso), sym); 155580d496beSPekka Enberg nr_syms++; 155680d496beSPekka Enberg } 155780d496beSPekka Enberg 155880d496beSPekka Enberg free(line); 155980d496beSPekka Enberg fclose(file); 156080d496beSPekka Enberg 156180d496beSPekka Enberg return nr_syms; 156280d496beSPekka Enberg 156380d496beSPekka Enberg out_delete_line: 156480d496beSPekka Enberg free(line); 156580d496beSPekka Enberg out_failure: 156680d496beSPekka Enberg return -1; 156780d496beSPekka Enberg } 156880d496beSPekka Enberg 1569eac9a434SRemi Bernon #ifdef HAVE_LIBBFD_SUPPORT 1570eac9a434SRemi Bernon #define PACKAGE 'perf' 1571eac9a434SRemi Bernon #include <bfd.h> 1572eac9a434SRemi Bernon 1573eac9a434SRemi Bernon static int bfd_symbols__cmpvalue(const void *a, const void *b) 1574eac9a434SRemi Bernon { 1575eac9a434SRemi Bernon const asymbol *as = *(const asymbol **)a, *bs = *(const asymbol **)b; 1576eac9a434SRemi Bernon 1577eac9a434SRemi Bernon if (bfd_asymbol_value(as) != bfd_asymbol_value(bs)) 1578eac9a434SRemi Bernon return bfd_asymbol_value(as) - bfd_asymbol_value(bs); 1579eac9a434SRemi Bernon 1580eac9a434SRemi Bernon return bfd_asymbol_name(as)[0] - bfd_asymbol_name(bs)[0]; 1581eac9a434SRemi Bernon } 1582eac9a434SRemi Bernon 1583eac9a434SRemi Bernon static int bfd2elf_binding(asymbol *symbol) 1584eac9a434SRemi Bernon { 1585eac9a434SRemi Bernon if (symbol->flags & BSF_WEAK) 1586eac9a434SRemi Bernon return STB_WEAK; 1587eac9a434SRemi Bernon if (symbol->flags & BSF_GLOBAL) 1588eac9a434SRemi Bernon return STB_GLOBAL; 1589eac9a434SRemi Bernon if (symbol->flags & BSF_LOCAL) 1590eac9a434SRemi Bernon return STB_LOCAL; 1591eac9a434SRemi Bernon return -1; 1592eac9a434SRemi Bernon } 1593eac9a434SRemi Bernon 1594eac9a434SRemi Bernon int dso__load_bfd_symbols(struct dso *dso, const char *debugfile) 1595eac9a434SRemi Bernon { 1596eac9a434SRemi Bernon int err = -1; 159796de68ffSDmitry Safonov long symbols_size, symbols_count, i; 1598eac9a434SRemi Bernon asection *section; 1599eac9a434SRemi Bernon asymbol **symbols, *sym; 1600eac9a434SRemi Bernon struct symbol *symbol; 1601eac9a434SRemi Bernon bfd *abfd; 1602eac9a434SRemi Bernon u64 start, len; 1603eac9a434SRemi Bernon 160400a34234SNicholas Fraser abfd = bfd_openr(debugfile, NULL); 1605eac9a434SRemi Bernon if (!abfd) 1606eac9a434SRemi Bernon return -1; 1607eac9a434SRemi Bernon 1608eac9a434SRemi Bernon if (!bfd_check_format(abfd, bfd_object)) { 1609eac9a434SRemi Bernon pr_debug2("%s: cannot read %s bfd file.\n", __func__, 1610*1553419cSIan Rogers dso__long_name(dso)); 1611eac9a434SRemi Bernon goto out_close; 1612eac9a434SRemi Bernon } 1613eac9a434SRemi Bernon 1614eac9a434SRemi Bernon if (bfd_get_flavour(abfd) == bfd_target_elf_flavour) 1615eac9a434SRemi Bernon goto out_close; 1616eac9a434SRemi Bernon 1617eac9a434SRemi Bernon symbols_size = bfd_get_symtab_upper_bound(abfd); 1618eac9a434SRemi Bernon if (symbols_size == 0) { 1619eac9a434SRemi Bernon bfd_close(abfd); 1620eac9a434SRemi Bernon return 0; 1621eac9a434SRemi Bernon } 1622eac9a434SRemi Bernon 1623eac9a434SRemi Bernon if (symbols_size < 0) 1624eac9a434SRemi Bernon goto out_close; 1625eac9a434SRemi Bernon 1626eac9a434SRemi Bernon symbols = malloc(symbols_size); 1627eac9a434SRemi Bernon if (!symbols) 1628eac9a434SRemi Bernon goto out_close; 1629eac9a434SRemi Bernon 1630eac9a434SRemi Bernon symbols_count = bfd_canonicalize_symtab(abfd, symbols); 1631eac9a434SRemi Bernon if (symbols_count < 0) 1632eac9a434SRemi Bernon goto out_free; 1633eac9a434SRemi Bernon 1634d2930edeSRemi Bernon section = bfd_get_section_by_name(abfd, ".text"); 1635d2930edeSRemi Bernon if (section) { 1636d2930edeSRemi Bernon for (i = 0; i < symbols_count; ++i) { 1637d2930edeSRemi Bernon if (!strcmp(bfd_asymbol_name(symbols[i]), "__ImageBase") || 1638d2930edeSRemi Bernon !strcmp(bfd_asymbol_name(symbols[i]), "__image_base__")) 1639d2930edeSRemi Bernon break; 1640d2930edeSRemi Bernon } 1641d2930edeSRemi Bernon if (i < symbols_count) { 1642d2930edeSRemi Bernon /* PE symbols can only have 4 bytes, so use .text high bits */ 1643*1553419cSIan Rogers u64 text_offset = (section->vma - (u32)section->vma) 1644*1553419cSIan Rogers + (u32)bfd_asymbol_value(symbols[i]); 1645*1553419cSIan Rogers dso__set_text_offset(dso, text_offset); 1646*1553419cSIan Rogers dso__set_text_end(dso, (section->vma - text_offset) + section->size); 1647d2930edeSRemi Bernon } else { 1648*1553419cSIan Rogers dso__set_text_offset(dso, section->vma - section->filepos); 1649*1553419cSIan Rogers dso__set_text_end(dso, section->filepos + section->size); 1650d2930edeSRemi Bernon } 1651d2930edeSRemi Bernon } 1652d2930edeSRemi Bernon 1653eac9a434SRemi Bernon qsort(symbols, symbols_count, sizeof(asymbol *), bfd_symbols__cmpvalue); 1654eac9a434SRemi Bernon 1655eac9a434SRemi Bernon #ifdef bfd_get_section 1656eac9a434SRemi Bernon #define bfd_asymbol_section bfd_get_section 1657eac9a434SRemi Bernon #endif 1658eac9a434SRemi Bernon for (i = 0; i < symbols_count; ++i) { 1659eac9a434SRemi Bernon sym = symbols[i]; 1660eac9a434SRemi Bernon section = bfd_asymbol_section(sym); 1661eac9a434SRemi Bernon if (bfd2elf_binding(sym) < 0) 1662eac9a434SRemi Bernon continue; 1663eac9a434SRemi Bernon 1664eac9a434SRemi Bernon while (i + 1 < symbols_count && 1665eac9a434SRemi Bernon bfd_asymbol_section(symbols[i + 1]) == section && 1666eac9a434SRemi Bernon bfd2elf_binding(symbols[i + 1]) < 0) 1667eac9a434SRemi Bernon i++; 1668eac9a434SRemi Bernon 1669eac9a434SRemi Bernon if (i + 1 < symbols_count && 1670eac9a434SRemi Bernon bfd_asymbol_section(symbols[i + 1]) == section) 1671eac9a434SRemi Bernon len = symbols[i + 1]->value - sym->value; 1672eac9a434SRemi Bernon else 1673eac9a434SRemi Bernon len = section->size - sym->value; 1674eac9a434SRemi Bernon 1675*1553419cSIan Rogers start = bfd_asymbol_value(sym) - dso__text_offset(dso); 1676eac9a434SRemi Bernon symbol = symbol__new(start, len, bfd2elf_binding(sym), STT_FUNC, 1677eac9a434SRemi Bernon bfd_asymbol_name(sym)); 1678eac9a434SRemi Bernon if (!symbol) 1679eac9a434SRemi Bernon goto out_free; 1680eac9a434SRemi Bernon 1681ee756ef7SIan Rogers symbols__insert(dso__symbols(dso), symbol); 1682eac9a434SRemi Bernon } 1683eac9a434SRemi Bernon #ifdef bfd_get_section 1684eac9a434SRemi Bernon #undef bfd_asymbol_section 1685eac9a434SRemi Bernon #endif 1686eac9a434SRemi Bernon 1687ee756ef7SIan Rogers symbols__fixup_end(dso__symbols(dso), false); 1688ee756ef7SIan Rogers symbols__fixup_duplicate(dso__symbols(dso)); 1689ee756ef7SIan Rogers dso__set_adjust_symbols(dso, true); 1690eac9a434SRemi Bernon 1691eac9a434SRemi Bernon err = 0; 1692eac9a434SRemi Bernon out_free: 1693eac9a434SRemi Bernon free(symbols); 1694eac9a434SRemi Bernon out_close: 1695eac9a434SRemi Bernon bfd_close(abfd); 1696eac9a434SRemi Bernon return err; 1697eac9a434SRemi Bernon } 1698eac9a434SRemi Bernon #endif 1699eac9a434SRemi Bernon 17001029f9feSNamhyung Kim static bool dso__is_compatible_symtab_type(struct dso *dso, bool kmod, 17011029f9feSNamhyung Kim enum dso_binary_type type) 17021029f9feSNamhyung Kim { 17031029f9feSNamhyung Kim switch (type) { 17041029f9feSNamhyung Kim case DSO_BINARY_TYPE__JAVA_JIT: 17051029f9feSNamhyung Kim case DSO_BINARY_TYPE__DEBUGLINK: 17061029f9feSNamhyung Kim case DSO_BINARY_TYPE__SYSTEM_PATH_DSO: 17071029f9feSNamhyung Kim case DSO_BINARY_TYPE__FEDORA_DEBUGINFO: 17081029f9feSNamhyung Kim case DSO_BINARY_TYPE__UBUNTU_DEBUGINFO: 170985afd355SAdrian Hunter case DSO_BINARY_TYPE__MIXEDUP_UBUNTU_DEBUGINFO: 17101029f9feSNamhyung Kim case DSO_BINARY_TYPE__BUILDID_DEBUGINFO: 17111029f9feSNamhyung Kim case DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO: 1712ee756ef7SIan Rogers return !kmod && dso__kernel(dso) == DSO_SPACE__USER; 17131029f9feSNamhyung Kim 17141029f9feSNamhyung Kim case DSO_BINARY_TYPE__KALLSYMS: 17151029f9feSNamhyung Kim case DSO_BINARY_TYPE__VMLINUX: 17161029f9feSNamhyung Kim case DSO_BINARY_TYPE__KCORE: 1717ee756ef7SIan Rogers return dso__kernel(dso) == DSO_SPACE__KERNEL; 17181029f9feSNamhyung Kim 17191029f9feSNamhyung Kim case DSO_BINARY_TYPE__GUEST_KALLSYMS: 17201029f9feSNamhyung Kim case DSO_BINARY_TYPE__GUEST_VMLINUX: 17211029f9feSNamhyung Kim case DSO_BINARY_TYPE__GUEST_KCORE: 1722ee756ef7SIan Rogers return dso__kernel(dso) == DSO_SPACE__KERNEL_GUEST; 17231029f9feSNamhyung Kim 17241029f9feSNamhyung Kim case DSO_BINARY_TYPE__GUEST_KMODULE: 1725c00c48fcSNamhyung Kim case DSO_BINARY_TYPE__GUEST_KMODULE_COMP: 17261029f9feSNamhyung Kim case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE: 1727c00c48fcSNamhyung Kim case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP: 17281029f9feSNamhyung Kim /* 17291029f9feSNamhyung Kim * kernel modules know their symtab type - it's set when 1730a94ab91aSArnaldo Carvalho de Melo * creating a module dso in machine__addnew_module_map(). 17311029f9feSNamhyung Kim */ 1732ee756ef7SIan Rogers return kmod && dso__symtab_type(dso) == type; 17331029f9feSNamhyung Kim 17341029f9feSNamhyung Kim case DSO_BINARY_TYPE__BUILD_ID_CACHE: 1735d2396999SKrister Johansen case DSO_BINARY_TYPE__BUILD_ID_CACHE_DEBUGINFO: 17361029f9feSNamhyung Kim return true; 17371029f9feSNamhyung Kim 17389b86d04dSSong Liu case DSO_BINARY_TYPE__BPF_PROG_INFO: 17393c29d448SJiri Olsa case DSO_BINARY_TYPE__BPF_IMAGE: 1740789e2419SAdrian Hunter case DSO_BINARY_TYPE__OOL: 17411029f9feSNamhyung Kim case DSO_BINARY_TYPE__NOT_FOUND: 17421029f9feSNamhyung Kim default: 17431029f9feSNamhyung Kim return false; 17441029f9feSNamhyung Kim } 17451029f9feSNamhyung Kim } 17461029f9feSNamhyung Kim 1747bf2e710bSKrister Johansen /* Checks for the existence of the perf-<pid>.map file in two different 1748bf2e710bSKrister Johansen * locations. First, if the process is a separate mount namespace, check in 1749bf2e710bSKrister Johansen * that namespace using the pid of the innermost pid namespace. If's not in a 1750bf2e710bSKrister Johansen * namespace, or the file can't be found there, try in the mount namespace of 1751bf2e710bSKrister Johansen * the tracing process using our view of its pid. 1752bf2e710bSKrister Johansen */ 1753bf2e710bSKrister Johansen static int dso__find_perf_map(char *filebuf, size_t bufsz, 1754bf2e710bSKrister Johansen struct nsinfo **nsip) 1755bf2e710bSKrister Johansen { 1756bf2e710bSKrister Johansen struct nscookie nsc; 1757bf2e710bSKrister Johansen struct nsinfo *nsi; 1758bf2e710bSKrister Johansen struct nsinfo *nnsi; 1759bf2e710bSKrister Johansen int rc = -1; 1760bf2e710bSKrister Johansen 1761bf2e710bSKrister Johansen nsi = *nsip; 1762bf2e710bSKrister Johansen 1763bcaf0a97SIan Rogers if (nsinfo__need_setns(nsi)) { 1764bcaf0a97SIan Rogers snprintf(filebuf, bufsz, "/tmp/perf-%d.map", nsinfo__nstgid(nsi)); 1765bf2e710bSKrister Johansen nsinfo__mountns_enter(nsi, &nsc); 1766bf2e710bSKrister Johansen rc = access(filebuf, R_OK); 1767bf2e710bSKrister Johansen nsinfo__mountns_exit(&nsc); 1768bf2e710bSKrister Johansen if (rc == 0) 1769bf2e710bSKrister Johansen return rc; 1770bf2e710bSKrister Johansen } 1771bf2e710bSKrister Johansen 1772bf2e710bSKrister Johansen nnsi = nsinfo__copy(nsi); 1773bf2e710bSKrister Johansen if (nnsi) { 1774bf2e710bSKrister Johansen nsinfo__put(nsi); 1775bf2e710bSKrister Johansen 1776bcaf0a97SIan Rogers nsinfo__clear_need_setns(nnsi); 1777bcaf0a97SIan Rogers snprintf(filebuf, bufsz, "/tmp/perf-%d.map", nsinfo__tgid(nnsi)); 1778bf2e710bSKrister Johansen *nsip = nnsi; 1779bf2e710bSKrister Johansen rc = 0; 1780bf2e710bSKrister Johansen } 1781bf2e710bSKrister Johansen 1782bf2e710bSKrister Johansen return rc; 1783bf2e710bSKrister Johansen } 1784bf2e710bSKrister Johansen 1785be39db9fSArnaldo Carvalho de Melo int dso__load(struct dso *dso, struct map *map) 178686470930SIngo Molnar { 1787c338aee8SArnaldo Carvalho de Melo char *name; 178886470930SIngo Molnar int ret = -1; 178944f24cb3SJiri Olsa u_int i; 179093fcce96SArnaldo Carvalho de Melo struct machine *machine = NULL; 179144f24cb3SJiri Olsa char *root_dir = (char *) ""; 17923aafe5aeSCody P Schafer int ss_pos = 0; 17933aafe5aeSCody P Schafer struct symsrc ss_[2]; 17943aafe5aeSCody P Schafer struct symsrc *syms_ss = NULL, *runtime_ss = NULL; 17951029f9feSNamhyung Kim bool kmod; 1796bf2e710bSKrister Johansen bool perfmap; 1797f766819cSJiri Olsa struct build_id bid; 1798843ff37bSKrister Johansen struct nscookie nsc; 1799bf2e710bSKrister Johansen char newmapname[PATH_MAX]; 1800ee756ef7SIan Rogers const char *map_path = dso__long_name(dso); 1801bf2e710bSKrister Johansen 1802ee756ef7SIan Rogers mutex_lock(dso__lock(dso)); 1803b0979f00SAthira Rajeev perfmap = is_perf_pid_map_name(map_path); 1804b0979f00SAthira Rajeev 1805bf2e710bSKrister Johansen if (perfmap) { 1806ee756ef7SIan Rogers if (dso__nsinfo(dso) && 1807ee756ef7SIan Rogers (dso__find_perf_map(newmapname, sizeof(newmapname), 1808ee756ef7SIan Rogers dso__nsinfo_ptr(dso)) == 0)) { 1809bf2e710bSKrister Johansen map_path = newmapname; 1810bf2e710bSKrister Johansen } 1811bf2e710bSKrister Johansen } 181286470930SIngo Molnar 1813ee756ef7SIan Rogers nsinfo__mountns_enter(dso__nsinfo(dso), &nsc); 181466bd8424SArnaldo Carvalho de Melo 18154a936edcSNamhyung Kim /* check again under the dso->lock */ 18163183f8caSArnaldo Carvalho de Melo if (dso__loaded(dso)) { 18174a936edcSNamhyung Kim ret = 1; 18184a936edcSNamhyung Kim goto out; 18194a936edcSNamhyung Kim } 18204a936edcSNamhyung Kim 1821e988a5b5SNamhyung Kim kmod = dso__is_kmod(dso); 1822b5c09518SArnaldo Carvalho de Melo 1823ee756ef7SIan Rogers if (dso__kernel(dso) && !kmod) { 1824ee756ef7SIan Rogers if (dso__kernel(dso) == DSO_SPACE__KERNEL) 1825be39db9fSArnaldo Carvalho de Melo ret = dso__load_kernel_sym(dso, map); 1826ee756ef7SIan Rogers else if (dso__kernel(dso) == DSO_SPACE__KERNEL_GUEST) 1827be39db9fSArnaldo Carvalho de Melo ret = dso__load_guest_kernel_sym(dso, map); 18284a936edcSNamhyung Kim 18295ab6d715SIan Rogers machine = maps__machine(map__kmaps(map)); 18304d99e413SAdrian Hunter if (machine__is(machine, "x86_64")) 18314d99e413SAdrian Hunter machine__map_x86_64_entry_trampolines(machine, dso); 18324a936edcSNamhyung Kim goto out; 18334a936edcSNamhyung Kim } 1834a1645ce1SZhang, Yanmin 1835ee756ef7SIan Rogers dso__set_adjust_symbols(dso, false); 1836f5812a7aSArnaldo Carvalho de Melo 1837bf2e710bSKrister Johansen if (perfmap) { 18383183f8caSArnaldo Carvalho de Melo ret = dso__load_perf_map(map_path, dso); 1839ee756ef7SIan Rogers dso__set_symtab_type(dso, ret > 0 1840ee756ef7SIan Rogers ? DSO_BINARY_TYPE__JAVA_JIT 1841ee756ef7SIan Rogers : DSO_BINARY_TYPE__NOT_FOUND); 18424a936edcSNamhyung Kim goto out; 184394cb9e38SArnaldo Carvalho de Melo } 184494cb9e38SArnaldo Carvalho de Melo 184544f24cb3SJiri Olsa if (machine) 184644f24cb3SJiri Olsa root_dir = machine->root_dir; 184744f24cb3SJiri Olsa 1848164c800eSDavid Ahern name = malloc(PATH_MAX); 1849164c800eSDavid Ahern if (!name) 18504a936edcSNamhyung Kim goto out; 1851164c800eSDavid Ahern 18525baecbcdSDima Kogan /* 18535baecbcdSDima Kogan * Read the build id if possible. This is required for 18545baecbcdSDima Kogan * DSO_BINARY_TYPE__BUILDID_DEBUGINFO to work 18555baecbcdSDima Kogan */ 1856ee756ef7SIan Rogers if (!dso__has_build_id(dso) && 1857ee756ef7SIan Rogers is_regular_file(dso__long_name(dso))) { 1858ee756ef7SIan Rogers __symbol__join_symfs(name, PATH_MAX, dso__long_name(dso)); 1859f766819cSJiri Olsa if (filename__read_build_id(name, &bid) > 0) 18608dfdf440SJiri Olsa dso__set_build_id(dso, &bid); 18619b200653SVictor Kamensky } 18625baecbcdSDima Kogan 18631029f9feSNamhyung Kim /* 18641029f9feSNamhyung Kim * Iterate over candidate debug images. 18653aafe5aeSCody P Schafer * Keep track of "interesting" ones (those which have a symtab, dynsym, 18663aafe5aeSCody P Schafer * and/or opd section) for processing. 18676da80ce8SDave Martin */ 186844f24cb3SJiri Olsa for (i = 0; i < DSO_BINARY_TYPE__SYMTAB_CNT; i++) { 18693aafe5aeSCody P Schafer struct symsrc *ss = &ss_[ss_pos]; 18703aafe5aeSCody P Schafer bool next_slot = false; 1871f045b8c4SKrister Johansen bool is_reg; 1872d2396999SKrister Johansen bool nsexit; 1873eac9a434SRemi Bernon int bfdrc = -1; 1874c3962961SJiri Olsa int sirc = -1; 187544f24cb3SJiri Olsa 1876005f9294SCody P Schafer enum dso_binary_type symtab_type = binary_type_symtab[i]; 187744f24cb3SJiri Olsa 1878d2396999SKrister Johansen nsexit = (symtab_type == DSO_BINARY_TYPE__BUILD_ID_CACHE || 1879d2396999SKrister Johansen symtab_type == DSO_BINARY_TYPE__BUILD_ID_CACHE_DEBUGINFO); 1880d2396999SKrister Johansen 18811029f9feSNamhyung Kim if (!dso__is_compatible_symtab_type(dso, kmod, symtab_type)) 18821029f9feSNamhyung Kim continue; 18831029f9feSNamhyung Kim 1884ee4e9625SArnaldo Carvalho de Melo if (dso__read_binary_type_filename(dso, symtab_type, 188544f24cb3SJiri Olsa root_dir, name, PATH_MAX)) 18866da80ce8SDave Martin continue; 188786470930SIngo Molnar 1888d2396999SKrister Johansen if (nsexit) 1889f045b8c4SKrister Johansen nsinfo__mountns_exit(&nsc); 189040356721SJiri Olsa 1891f045b8c4SKrister Johansen is_reg = is_regular_file(name); 1892ee756ef7SIan Rogers if (!is_reg && errno == ENOENT && dso__nsinfo(dso)) { 18937031edacSArnaldo Carvalho de Melo char *new_name = dso__filename_with_chroot(dso, name); 189467fd1892SNamhyung Kim if (new_name) { 189567fd1892SNamhyung Kim is_reg = is_regular_file(new_name); 189667fd1892SNamhyung Kim strlcpy(name, new_name, PATH_MAX); 189767fd1892SNamhyung Kim free(new_name); 189867fd1892SNamhyung Kim } 189967fd1892SNamhyung Kim } 190067fd1892SNamhyung Kim 1901eac9a434SRemi Bernon #ifdef HAVE_LIBBFD_SUPPORT 1902c3962961SJiri Olsa if (is_reg) 1903eac9a434SRemi Bernon bfdrc = dso__load_bfd_symbols(dso, name); 1904eac9a434SRemi Bernon #endif 1905eac9a434SRemi Bernon if (is_reg && bfdrc < 0) 1906f045b8c4SKrister Johansen sirc = symsrc__init(ss, dso, name, symtab_type); 1907f045b8c4SKrister Johansen 1908d2396999SKrister Johansen if (nsexit) 1909ee756ef7SIan Rogers nsinfo__mountns_enter(dso__nsinfo(dso), &nsc); 1910f045b8c4SKrister Johansen 191177771a97SNicholas Fraser if (bfdrc == 0) { 191277771a97SNicholas Fraser ret = 0; 1913eac9a434SRemi Bernon break; 191477771a97SNicholas Fraser } 1915eac9a434SRemi Bernon 1916c3962961SJiri Olsa if (!is_reg || sirc < 0) 19176da80ce8SDave Martin continue; 19186da80ce8SDave Martin 19193aafe5aeSCody P Schafer if (!syms_ss && symsrc__has_symtab(ss)) { 19203aafe5aeSCody P Schafer syms_ss = ss; 19213aafe5aeSCody P Schafer next_slot = true; 1922ee756ef7SIan Rogers if (!dso__symsrc_filename(dso)) 1923ee756ef7SIan Rogers dso__set_symsrc_filename(dso, strdup(name)); 1924d26cd12bSCody P Schafer } 1925d26cd12bSCody P Schafer 19263aafe5aeSCody P Schafer if (!runtime_ss && symsrc__possibly_runtime(ss)) { 19273aafe5aeSCody P Schafer runtime_ss = ss; 19283aafe5aeSCody P Schafer next_slot = true; 1929a44f605bSCody P Schafer } 193086470930SIngo Molnar 19313aafe5aeSCody P Schafer if (next_slot) { 19323aafe5aeSCody P Schafer ss_pos++; 193333ff581eSJiri Olsa 19343aafe5aeSCody P Schafer if (syms_ss && runtime_ss) 19356da80ce8SDave Martin break; 193698e9f03bSNamhyung Kim } else { 193798e9f03bSNamhyung Kim symsrc__destroy(ss); 1938a25e46c4SArnaldo Carvalho de Melo } 19393aafe5aeSCody P Schafer 19406da80ce8SDave Martin } 19416da80ce8SDave Martin 19423aafe5aeSCody P Schafer if (!runtime_ss && !syms_ss) 19433aafe5aeSCody P Schafer goto out_free; 19443aafe5aeSCody P Schafer 19453aafe5aeSCody P Schafer if (runtime_ss && !syms_ss) { 19463aafe5aeSCody P Schafer syms_ss = runtime_ss; 194760e4b10cSArnaldo Carvalho de Melo } 194860e4b10cSArnaldo Carvalho de Melo 19493aafe5aeSCody P Schafer /* We'll have to hope for the best */ 19503aafe5aeSCody P Schafer if (!runtime_ss && syms_ss) 19513aafe5aeSCody P Schafer runtime_ss = syms_ss; 19523aafe5aeSCody P Schafer 19531029f9feSNamhyung Kim if (syms_ss) 1954be39db9fSArnaldo Carvalho de Melo ret = dso__load_sym(dso, map, syms_ss, runtime_ss, kmod); 19551029f9feSNamhyung Kim else 19563aafe5aeSCody P Schafer ret = -1; 19573aafe5aeSCody P Schafer 1958f47b58b7SDavid Ahern if (ret > 0) { 19593aafe5aeSCody P Schafer int nr_plt; 19603aafe5aeSCody P Schafer 19613183f8caSArnaldo Carvalho de Melo nr_plt = dso__synthesize_plt_symbols(dso, runtime_ss); 19623aafe5aeSCody P Schafer if (nr_plt > 0) 19633aafe5aeSCody P Schafer ret += nr_plt; 19643aafe5aeSCody P Schafer } 19653aafe5aeSCody P Schafer 19663aafe5aeSCody P Schafer for (; ss_pos > 0; ss_pos--) 19673aafe5aeSCody P Schafer symsrc__destroy(&ss_[ss_pos - 1]); 19683aafe5aeSCody P Schafer out_free: 196986470930SIngo Molnar free(name); 1970ee756ef7SIan Rogers if (ret < 0 && strstr(dso__name(dso), " (deleted)") != NULL) 19714a936edcSNamhyung Kim ret = 0; 19724a936edcSNamhyung Kim out: 19733183f8caSArnaldo Carvalho de Melo dso__set_loaded(dso); 1974ee756ef7SIan Rogers mutex_unlock(dso__lock(dso)); 1975843ff37bSKrister Johansen nsinfo__mountns_exit(&nsc); 19764a936edcSNamhyung Kim 197786470930SIngo Molnar return ret; 197886470930SIngo Molnar } 197986470930SIngo Molnar 198025626e19SJames Clark /* 198125626e19SJames Clark * Always takes ownership of vmlinux when vmlinux_allocated == true, even if 198225626e19SJames Clark * it returns an error. 198325626e19SJames Clark */ 1984aeafcbafSArnaldo Carvalho de Melo int dso__load_vmlinux(struct dso *dso, struct map *map, 1985be39db9fSArnaldo Carvalho de Melo const char *vmlinux, bool vmlinux_allocated) 198686470930SIngo Molnar { 1987b68e2f91SCody P Schafer int err = -1; 1988b68e2f91SCody P Schafer struct symsrc ss; 1989ec5761eaSDavid Ahern char symfs_vmlinux[PATH_MAX]; 1990005f9294SCody P Schafer enum dso_binary_type symtab_type; 199186470930SIngo Molnar 19925698d2c9SNamhyung Kim if (vmlinux[0] == '/') 19935698d2c9SNamhyung Kim snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s", vmlinux); 19945698d2c9SNamhyung Kim else 1995972f393bSArnaldo Carvalho de Melo symbol__join_symfs(symfs_vmlinux, vmlinux); 199686470930SIngo Molnar 1997ee756ef7SIan Rogers if (dso__kernel(dso) == DSO_SPACE__KERNEL_GUEST) 1998005f9294SCody P Schafer symtab_type = DSO_BINARY_TYPE__GUEST_VMLINUX; 199921ea4539SCody P Schafer else 2000005f9294SCody P Schafer symtab_type = DSO_BINARY_TYPE__VMLINUX; 200121ea4539SCody P Schafer 200225626e19SJames Clark if (symsrc__init(&ss, dso, symfs_vmlinux, symtab_type)) { 200325626e19SJames Clark if (vmlinux_allocated) 200425626e19SJames Clark free((char *) vmlinux); 2005b68e2f91SCody P Schafer return -1; 200625626e19SJames Clark } 2007b68e2f91SCody P Schafer 2008e59fea47SAthira Rajeev /* 2009e59fea47SAthira Rajeev * dso__load_sym() may copy 'dso' which will result in the copies having 2010e59fea47SAthira Rajeev * an incorrect long name unless we set it here first. 2011e59fea47SAthira Rajeev */ 2012e59fea47SAthira Rajeev dso__set_long_name(dso, vmlinux, vmlinux_allocated); 2013ee756ef7SIan Rogers if (dso__kernel(dso) == DSO_SPACE__KERNEL_GUEST) 2014ee756ef7SIan Rogers dso__set_binary_type(dso, DSO_BINARY_TYPE__GUEST_VMLINUX); 201539b12f78SAdrian Hunter else 2016ee756ef7SIan Rogers dso__set_binary_type(dso, DSO_BINARY_TYPE__VMLINUX); 2017e59fea47SAthira Rajeev 2018e59fea47SAthira Rajeev err = dso__load_sym(dso, map, &ss, &ss, 0); 2019e59fea47SAthira Rajeev symsrc__destroy(&ss); 2020e59fea47SAthira Rajeev 2021e59fea47SAthira Rajeev if (err > 0) { 20223183f8caSArnaldo Carvalho de Melo dso__set_loaded(dso); 2023ec5761eaSDavid Ahern pr_debug("Using %s for symbols\n", symfs_vmlinux); 2024515850e4SCody P Schafer } 20253846df2eSArnaldo Carvalho de Melo 202686470930SIngo Molnar return err; 202786470930SIngo Molnar } 202886470930SIngo Molnar 2029be39db9fSArnaldo Carvalho de Melo int dso__load_vmlinux_path(struct dso *dso, struct map *map) 2030a19afe46SArnaldo Carvalho de Melo { 2031a19afe46SArnaldo Carvalho de Melo int i, err = 0; 203200dc8657SNamhyung Kim char *filename = NULL; 2033a19afe46SArnaldo Carvalho de Melo 2034dc38218eSArnaldo Carvalho de Melo pr_debug("Looking at the vmlinux_path (%d entries long)\n", 2035dc38218eSArnaldo Carvalho de Melo vmlinux_path__nr_entries + 1); 2036dc38218eSArnaldo Carvalho de Melo 2037dc38218eSArnaldo Carvalho de Melo for (i = 0; i < vmlinux_path__nr_entries; ++i) { 2038be39db9fSArnaldo Carvalho de Melo err = dso__load_vmlinux(dso, map, vmlinux_path[i], false); 2039dc38218eSArnaldo Carvalho de Melo if (err > 0) 2040dc38218eSArnaldo Carvalho de Melo goto out; 2041dc38218eSArnaldo Carvalho de Melo } 2042dc38218eSArnaldo Carvalho de Melo 204300dc8657SNamhyung Kim if (!symbol_conf.ignore_vmlinux_buildid) 2044d2396999SKrister Johansen filename = dso__build_id_filename(dso, NULL, 0, false); 20455ad90e4eSArnaldo Carvalho de Melo if (filename != NULL) { 2046be39db9fSArnaldo Carvalho de Melo err = dso__load_vmlinux(dso, map, filename, true); 20475230fb7dSArnaldo Carvalho de Melo if (err > 0) 20485ad90e4eSArnaldo Carvalho de Melo goto out; 20495ad90e4eSArnaldo Carvalho de Melo } 20505ad90e4eSArnaldo Carvalho de Melo out: 2051a19afe46SArnaldo Carvalho de Melo return err; 2052a19afe46SArnaldo Carvalho de Melo } 2053a19afe46SArnaldo Carvalho de Melo 2054c48903b8SMasami Hiramatsu static bool visible_dir_filter(const char *name, struct dirent *d) 2055c48903b8SMasami Hiramatsu { 2056c48903b8SMasami Hiramatsu if (d->d_type != DT_DIR) 2057c48903b8SMasami Hiramatsu return false; 2058c48903b8SMasami Hiramatsu return lsdir_no_dot_filter(name, d); 2059c48903b8SMasami Hiramatsu } 2060c48903b8SMasami Hiramatsu 20610544d422SAdrian Hunter static int find_matching_kcore(struct map *map, char *dir, size_t dir_sz) 20620544d422SAdrian Hunter { 20630544d422SAdrian Hunter char kallsyms_filename[PATH_MAX]; 20640544d422SAdrian Hunter int ret = -1; 2065c48903b8SMasami Hiramatsu struct strlist *dirs; 2066c48903b8SMasami Hiramatsu struct str_node *nd; 20670544d422SAdrian Hunter 2068c48903b8SMasami Hiramatsu dirs = lsdir(dir, visible_dir_filter); 2069c48903b8SMasami Hiramatsu if (!dirs) 20700544d422SAdrian Hunter return -1; 20710544d422SAdrian Hunter 2072602a1f4dSArnaldo Carvalho de Melo strlist__for_each_entry(nd, dirs) { 20730544d422SAdrian Hunter scnprintf(kallsyms_filename, sizeof(kallsyms_filename), 2074c48903b8SMasami Hiramatsu "%s/%s/kallsyms", dir, nd->s); 2075a00d28cbSAdrian Hunter if (!validate_kcore_addresses(kallsyms_filename, map)) { 20760544d422SAdrian Hunter strlcpy(dir, kallsyms_filename, dir_sz); 20770544d422SAdrian Hunter ret = 0; 20780544d422SAdrian Hunter break; 20790544d422SAdrian Hunter } 20800544d422SAdrian Hunter } 20810544d422SAdrian Hunter 2082c48903b8SMasami Hiramatsu strlist__delete(dirs); 20830544d422SAdrian Hunter 20840544d422SAdrian Hunter return ret; 20850544d422SAdrian Hunter } 20860544d422SAdrian Hunter 208711870d71SMasami Hiramatsu /* 208811870d71SMasami Hiramatsu * Use open(O_RDONLY) to check readability directly instead of access(R_OK) 208911870d71SMasami Hiramatsu * since access(R_OK) only checks with real UID/GID but open() use effective 209011870d71SMasami Hiramatsu * UID/GID and actual capabilities (e.g. /proc/kcore requires CAP_SYS_RAWIO). 209111870d71SMasami Hiramatsu */ 209211870d71SMasami Hiramatsu static bool filename__readable(const char *file) 209311870d71SMasami Hiramatsu { 209411870d71SMasami Hiramatsu int fd = open(file, O_RDONLY); 209511870d71SMasami Hiramatsu if (fd < 0) 209611870d71SMasami Hiramatsu return false; 209711870d71SMasami Hiramatsu close(fd); 209811870d71SMasami Hiramatsu return true; 209911870d71SMasami Hiramatsu } 210011870d71SMasami Hiramatsu 21010544d422SAdrian Hunter static char *dso__find_kallsyms(struct dso *dso, struct map *map) 21020544d422SAdrian Hunter { 21033ff1b8c8SJiri Olsa struct build_id bid; 2104b5d8bbe8SMasami Hiramatsu char sbuild_id[SBUILD_ID_SIZE]; 21050544d422SAdrian Hunter bool is_host = false; 21060544d422SAdrian Hunter char path[PATH_MAX]; 21070544d422SAdrian Hunter 2108ee756ef7SIan Rogers if (!dso__has_build_id(dso)) { 21090544d422SAdrian Hunter /* 21100544d422SAdrian Hunter * Last resort, if we don't have a build-id and couldn't find 21110544d422SAdrian Hunter * any vmlinux file, try the running kernel kallsyms table. 21120544d422SAdrian Hunter */ 21130544d422SAdrian Hunter goto proc_kallsyms; 21140544d422SAdrian Hunter } 21150544d422SAdrian Hunter 21163ff1b8c8SJiri Olsa if (sysfs__read_build_id("/sys/kernel/notes", &bid) == 0) 211739be8d01SJiri Olsa is_host = dso__build_id_equal(dso, &bid); 21180544d422SAdrian Hunter 21194e4b6c06SMasami Hiramatsu /* Try a fast path for /proc/kallsyms if possible */ 21200544d422SAdrian Hunter if (is_host) { 21210544d422SAdrian Hunter /* 212211870d71SMasami Hiramatsu * Do not check the build-id cache, unless we know we cannot use 212311870d71SMasami Hiramatsu * /proc/kcore or module maps don't match to /proc/kallsyms. 212411870d71SMasami Hiramatsu * To check readability of /proc/kcore, do not use access(R_OK) 212511870d71SMasami Hiramatsu * since /proc/kcore requires CAP_SYS_RAWIO to read and access 212611870d71SMasami Hiramatsu * can't check it. 21270544d422SAdrian Hunter */ 212811870d71SMasami Hiramatsu if (filename__readable("/proc/kcore") && 212911870d71SMasami Hiramatsu !validate_kcore_addresses("/proc/kallsyms", map)) 21300544d422SAdrian Hunter goto proc_kallsyms; 21310544d422SAdrian Hunter } 21320544d422SAdrian Hunter 2133ee756ef7SIan Rogers build_id__sprintf(dso__bid(dso), sbuild_id); 21344e4b6c06SMasami Hiramatsu 2135449867e3SAdrian Hunter /* Find kallsyms in build-id cache with kcore */ 21364e4b6c06SMasami Hiramatsu scnprintf(path, sizeof(path), "%s/%s/%s", 21374e4b6c06SMasami Hiramatsu buildid_dir, DSO__NAME_KCORE, sbuild_id); 21384e4b6c06SMasami Hiramatsu 2139449867e3SAdrian Hunter if (!find_matching_kcore(map, path, sizeof(path))) 2140449867e3SAdrian Hunter return strdup(path); 2141449867e3SAdrian Hunter 21424e4b6c06SMasami Hiramatsu /* Use current /proc/kallsyms if possible */ 21434e4b6c06SMasami Hiramatsu if (is_host) { 21444e4b6c06SMasami Hiramatsu proc_kallsyms: 21454e4b6c06SMasami Hiramatsu return strdup("/proc/kallsyms"); 21464e4b6c06SMasami Hiramatsu } 21474e4b6c06SMasami Hiramatsu 21484e4b6c06SMasami Hiramatsu /* Finally, find a cache of kallsyms */ 214901412261SMasami Hiramatsu if (!build_id_cache__kallsyms_path(sbuild_id, path, sizeof(path))) { 21500544d422SAdrian Hunter pr_err("No kallsyms or vmlinux with build-id %s was found\n", 21510544d422SAdrian Hunter sbuild_id); 21520544d422SAdrian Hunter return NULL; 21530544d422SAdrian Hunter } 21540544d422SAdrian Hunter 21550544d422SAdrian Hunter return strdup(path); 21560544d422SAdrian Hunter } 21570544d422SAdrian Hunter 2158be39db9fSArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *dso, struct map *map) 215986470930SIngo Molnar { 2160cc612d81SArnaldo Carvalho de Melo int err; 21619e201442SArnaldo Carvalho de Melo const char *kallsyms_filename = NULL; 21629e201442SArnaldo Carvalho de Melo char *kallsyms_allocated_filename = NULL; 2163ca8ea73aSJiri Olsa char *filename = NULL; 2164ca8ea73aSJiri Olsa 2165dc8d6ab2SArnaldo Carvalho de Melo /* 2166b226a5a7SDavid Ahern * Step 1: if the user specified a kallsyms or vmlinux filename, use 2167b226a5a7SDavid Ahern * it and only it, reporting errors to the user if it cannot be used. 2168dc8d6ab2SArnaldo Carvalho de Melo * 2169dc8d6ab2SArnaldo Carvalho de Melo * For instance, try to analyse an ARM perf.data file _without_ a 2170dc8d6ab2SArnaldo Carvalho de Melo * build-id, or if the user specifies the wrong path to the right 2171dc8d6ab2SArnaldo Carvalho de Melo * vmlinux file, obviously we can't fallback to another vmlinux (a 2172dc8d6ab2SArnaldo Carvalho de Melo * x86_86 one, on the machine where analysis is being performed, say), 2173dc8d6ab2SArnaldo Carvalho de Melo * or worse, /proc/kallsyms. 2174dc8d6ab2SArnaldo Carvalho de Melo * 2175dc8d6ab2SArnaldo Carvalho de Melo * If the specified file _has_ a build-id and there is a build-id 2176dc8d6ab2SArnaldo Carvalho de Melo * section in the perf.data file, we will still do the expected 2177dc8d6ab2SArnaldo Carvalho de Melo * validation in dso__load_vmlinux and will bail out if they don't 2178dc8d6ab2SArnaldo Carvalho de Melo * match. 2179dc8d6ab2SArnaldo Carvalho de Melo */ 2180b226a5a7SDavid Ahern if (symbol_conf.kallsyms_name != NULL) { 2181b226a5a7SDavid Ahern kallsyms_filename = symbol_conf.kallsyms_name; 2182b226a5a7SDavid Ahern goto do_kallsyms; 2183b226a5a7SDavid Ahern } 2184b226a5a7SDavid Ahern 2185fc2be696SWilly Tarreau if (!symbol_conf.ignore_vmlinux && symbol_conf.vmlinux_name != NULL) { 2186be39db9fSArnaldo Carvalho de Melo return dso__load_vmlinux(dso, map, symbol_conf.vmlinux_name, false); 2187dc8d6ab2SArnaldo Carvalho de Melo } 2188439d473bSArnaldo Carvalho de Melo 2189ca8ea73aSJiri Olsa /* 2190ca8ea73aSJiri Olsa * Before checking on common vmlinux locations, check if it's 2191ca8ea73aSJiri Olsa * stored as standard build id binary (not kallsyms) under 2192ca8ea73aSJiri Olsa * .debug cache. 2193ca8ea73aSJiri Olsa */ 2194ca8ea73aSJiri Olsa if (!symbol_conf.ignore_vmlinux_buildid) 2195ca8ea73aSJiri Olsa filename = __dso__build_id_filename(dso, NULL, 0, false, false); 2196ca8ea73aSJiri Olsa if (filename != NULL) { 2197ca8ea73aSJiri Olsa err = dso__load_vmlinux(dso, map, filename, true); 2198ca8ea73aSJiri Olsa if (err > 0) 2199ca8ea73aSJiri Olsa return err; 2200ca8ea73aSJiri Olsa } 2201ca8ea73aSJiri Olsa 2202fc2be696SWilly Tarreau if (!symbol_conf.ignore_vmlinux && vmlinux_path != NULL) { 2203be39db9fSArnaldo Carvalho de Melo err = dso__load_vmlinux_path(dso, map); 2204a19afe46SArnaldo Carvalho de Melo if (err > 0) 220539b12f78SAdrian Hunter return err; 2206cc612d81SArnaldo Carvalho de Melo } 2207cc612d81SArnaldo Carvalho de Melo 2208ec5761eaSDavid Ahern /* do not try local files if a symfs was given */ 2209ec5761eaSDavid Ahern if (symbol_conf.symfs[0] != 0) 2210ec5761eaSDavid Ahern return -1; 2211ec5761eaSDavid Ahern 22120544d422SAdrian Hunter kallsyms_allocated_filename = dso__find_kallsyms(dso, map); 22130544d422SAdrian Hunter if (!kallsyms_allocated_filename) 22148d0591f6SArnaldo Carvalho de Melo return -1; 22158d0591f6SArnaldo Carvalho de Melo 221619fc2dedSArnaldo Carvalho de Melo kallsyms_filename = kallsyms_allocated_filename; 221719fc2dedSArnaldo Carvalho de Melo 2218dc8d6ab2SArnaldo Carvalho de Melo do_kallsyms: 2219be39db9fSArnaldo Carvalho de Melo err = dso__load_kallsyms(dso, kallsyms_filename, map); 22203846df2eSArnaldo Carvalho de Melo if (err > 0) 22213846df2eSArnaldo Carvalho de Melo pr_debug("Using %s for symbols\n", kallsyms_filename); 2222dc8d6ab2SArnaldo Carvalho de Melo free(kallsyms_allocated_filename); 2223dc8d6ab2SArnaldo Carvalho de Melo 22248e0cf965SAdrian Hunter if (err > 0 && !dso__is_kcore(dso)) { 2225ee756ef7SIan Rogers dso__set_binary_type(dso, DSO_BINARY_TYPE__KALLSYMS); 22260a77582fSMasami Hiramatsu dso__set_long_name(dso, DSO__NAME_KALLSYMS, false); 22276a4694a4SArnaldo Carvalho de Melo map__fixup_start(map); 22286a4694a4SArnaldo Carvalho de Melo map__fixup_end(map); 2229439d473bSArnaldo Carvalho de Melo } 223094cb9e38SArnaldo Carvalho de Melo 223186470930SIngo Molnar return err; 223286470930SIngo Molnar } 223386470930SIngo Molnar 2234be39db9fSArnaldo Carvalho de Melo static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map) 2235a1645ce1SZhang, Yanmin { 2236a1645ce1SZhang, Yanmin int err; 2237a5367ecbSAdrian Hunter const char *kallsyms_filename; 22385ab6d715SIan Rogers struct machine *machine = maps__machine(map__kmaps(map)); 2239a1645ce1SZhang, Yanmin char path[PATH_MAX]; 2240a1645ce1SZhang, Yanmin 2241a5367ecbSAdrian Hunter if (machine->kallsyms_filename) { 2242a5367ecbSAdrian Hunter kallsyms_filename = machine->kallsyms_filename; 2243a5367ecbSAdrian Hunter } else if (machine__is_default_guest(machine)) { 2244a1645ce1SZhang, Yanmin /* 2245a1645ce1SZhang, Yanmin * if the user specified a vmlinux filename, use it and only 2246a1645ce1SZhang, Yanmin * it, reporting errors to the user if it cannot be used. 2247a1645ce1SZhang, Yanmin * Or use file guest_kallsyms inputted by user on commandline 2248a1645ce1SZhang, Yanmin */ 2249a1645ce1SZhang, Yanmin if (symbol_conf.default_guest_vmlinux_name != NULL) { 2250aeafcbafSArnaldo Carvalho de Melo err = dso__load_vmlinux(dso, map, 22515230fb7dSArnaldo Carvalho de Melo symbol_conf.default_guest_vmlinux_name, 2252be39db9fSArnaldo Carvalho de Melo false); 225339b12f78SAdrian Hunter return err; 2254a1645ce1SZhang, Yanmin } 2255a1645ce1SZhang, Yanmin 2256a1645ce1SZhang, Yanmin kallsyms_filename = symbol_conf.default_guest_kallsyms; 2257a1645ce1SZhang, Yanmin if (!kallsyms_filename) 2258a1645ce1SZhang, Yanmin return -1; 2259a1645ce1SZhang, Yanmin } else { 226023346f21SArnaldo Carvalho de Melo sprintf(path, "%s/proc/kallsyms", machine->root_dir); 2261a1645ce1SZhang, Yanmin kallsyms_filename = path; 2262a1645ce1SZhang, Yanmin } 2263a1645ce1SZhang, Yanmin 2264be39db9fSArnaldo Carvalho de Melo err = dso__load_kallsyms(dso, kallsyms_filename, map); 22658e0cf965SAdrian Hunter if (err > 0) 226639b12f78SAdrian Hunter pr_debug("Using %s for symbols\n", kallsyms_filename); 22678e0cf965SAdrian Hunter if (err > 0 && !dso__is_kcore(dso)) { 2268ee756ef7SIan Rogers dso__set_binary_type(dso, DSO_BINARY_TYPE__GUEST_KALLSYMS); 22698c7f1bb3SJiri Olsa dso__set_long_name(dso, machine->mmap_name, false); 2270a1645ce1SZhang, Yanmin map__fixup_start(map); 2271a1645ce1SZhang, Yanmin map__fixup_end(map); 2272a1645ce1SZhang, Yanmin } 2273a1645ce1SZhang, Yanmin 2274a1645ce1SZhang, Yanmin return err; 2275a1645ce1SZhang, Yanmin } 2276cd84c2acSFrederic Weisbecker 2277cc612d81SArnaldo Carvalho de Melo static void vmlinux_path__exit(void) 22782446042cSArnaldo Carvalho de Melo { 227904662523SArnaldo Carvalho de Melo while (--vmlinux_path__nr_entries >= 0) 228004662523SArnaldo Carvalho de Melo zfree(&vmlinux_path[vmlinux_path__nr_entries]); 2281c4f03547SWang Nan vmlinux_path__nr_entries = 0; 2282cc612d81SArnaldo Carvalho de Melo 228304662523SArnaldo Carvalho de Melo zfree(&vmlinux_path); 2284cc612d81SArnaldo Carvalho de Melo } 2285cc612d81SArnaldo Carvalho de Melo 2286aac48647SEkaterina Tumanova static const char * const vmlinux_paths[] = { 2287aac48647SEkaterina Tumanova "vmlinux", 2288aac48647SEkaterina Tumanova "/boot/vmlinux" 2289aac48647SEkaterina Tumanova }; 2290aac48647SEkaterina Tumanova 2291aac48647SEkaterina Tumanova static const char * const vmlinux_paths_upd[] = { 2292aac48647SEkaterina Tumanova "/boot/vmlinux-%s", 2293aac48647SEkaterina Tumanova "/usr/lib/debug/boot/vmlinux-%s", 2294aac48647SEkaterina Tumanova "/lib/modules/%s/build/vmlinux", 2295f55ae954SEkaterina Tumanova "/usr/lib/debug/lib/modules/%s/vmlinux", 2296f55ae954SEkaterina Tumanova "/usr/lib/debug/boot/vmlinux-%s.debug" 2297aac48647SEkaterina Tumanova }; 2298aac48647SEkaterina Tumanova 2299aac48647SEkaterina Tumanova static int vmlinux_path__add(const char *new_entry) 2300aac48647SEkaterina Tumanova { 2301aac48647SEkaterina Tumanova vmlinux_path[vmlinux_path__nr_entries] = strdup(new_entry); 2302aac48647SEkaterina Tumanova if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 2303aac48647SEkaterina Tumanova return -1; 2304aac48647SEkaterina Tumanova ++vmlinux_path__nr_entries; 2305aac48647SEkaterina Tumanova 2306aac48647SEkaterina Tumanova return 0; 2307aac48647SEkaterina Tumanova } 2308aac48647SEkaterina Tumanova 2309ce80d3beSKan Liang static int vmlinux_path__init(struct perf_env *env) 2310cc612d81SArnaldo Carvalho de Melo { 2311cc612d81SArnaldo Carvalho de Melo struct utsname uts; 2312cc612d81SArnaldo Carvalho de Melo char bf[PATH_MAX]; 23130a7e6d1bSNamhyung Kim char *kernel_version; 2314aac48647SEkaterina Tumanova unsigned int i; 2315cc612d81SArnaldo Carvalho de Melo 2316aac48647SEkaterina Tumanova vmlinux_path = malloc(sizeof(char *) * (ARRAY_SIZE(vmlinux_paths) + 2317aac48647SEkaterina Tumanova ARRAY_SIZE(vmlinux_paths_upd))); 2318cc612d81SArnaldo Carvalho de Melo if (vmlinux_path == NULL) 2319cc612d81SArnaldo Carvalho de Melo return -1; 2320cc612d81SArnaldo Carvalho de Melo 2321aac48647SEkaterina Tumanova for (i = 0; i < ARRAY_SIZE(vmlinux_paths); i++) 2322aac48647SEkaterina Tumanova if (vmlinux_path__add(vmlinux_paths[i]) < 0) 2323cc612d81SArnaldo Carvalho de Melo goto out_fail; 2324ec5761eaSDavid Ahern 23250a7e6d1bSNamhyung Kim /* only try kernel version if no symfs was given */ 2326ec5761eaSDavid Ahern if (symbol_conf.symfs[0] != 0) 2327ec5761eaSDavid Ahern return 0; 2328ec5761eaSDavid Ahern 23290a7e6d1bSNamhyung Kim if (env) { 23300a7e6d1bSNamhyung Kim kernel_version = env->os_release; 23310a7e6d1bSNamhyung Kim } else { 2332ec5761eaSDavid Ahern if (uname(&uts) < 0) 2333e96c674fSNamhyung Kim goto out_fail; 2334ec5761eaSDavid Ahern 23350a7e6d1bSNamhyung Kim kernel_version = uts.release; 23360a7e6d1bSNamhyung Kim } 23370a7e6d1bSNamhyung Kim 2338aac48647SEkaterina Tumanova for (i = 0; i < ARRAY_SIZE(vmlinux_paths_upd); i++) { 2339aac48647SEkaterina Tumanova snprintf(bf, sizeof(bf), vmlinux_paths_upd[i], kernel_version); 2340aac48647SEkaterina Tumanova if (vmlinux_path__add(bf) < 0) 2341cc612d81SArnaldo Carvalho de Melo goto out_fail; 2342aac48647SEkaterina Tumanova } 2343cc612d81SArnaldo Carvalho de Melo 2344cc612d81SArnaldo Carvalho de Melo return 0; 2345cc612d81SArnaldo Carvalho de Melo 2346cc612d81SArnaldo Carvalho de Melo out_fail: 2347cc612d81SArnaldo Carvalho de Melo vmlinux_path__exit(); 2348cc612d81SArnaldo Carvalho de Melo return -1; 2349cc612d81SArnaldo Carvalho de Melo } 2350cc612d81SArnaldo Carvalho de Melo 23513bfe5f81SDavid Ahern int setup_list(struct strlist **list, const char *list_str, 2352655000e7SArnaldo Carvalho de Melo const char *list_name) 2353655000e7SArnaldo Carvalho de Melo { 2354655000e7SArnaldo Carvalho de Melo if (list_str == NULL) 2355655000e7SArnaldo Carvalho de Melo return 0; 2356655000e7SArnaldo Carvalho de Melo 23574a77e218SArnaldo Carvalho de Melo *list = strlist__new(list_str, NULL); 2358655000e7SArnaldo Carvalho de Melo if (!*list) { 2359655000e7SArnaldo Carvalho de Melo pr_err("problems parsing %s list\n", list_name); 2360655000e7SArnaldo Carvalho de Melo return -1; 2361655000e7SArnaldo Carvalho de Melo } 23620bc2f2f7SArnaldo Carvalho de Melo 23630bc2f2f7SArnaldo Carvalho de Melo symbol_conf.has_filter = true; 2364655000e7SArnaldo Carvalho de Melo return 0; 2365655000e7SArnaldo Carvalho de Melo } 2366655000e7SArnaldo Carvalho de Melo 2367e03eaa40SDavid Ahern int setup_intlist(struct intlist **list, const char *list_str, 2368e03eaa40SDavid Ahern const char *list_name) 2369e03eaa40SDavid Ahern { 2370e03eaa40SDavid Ahern if (list_str == NULL) 2371e03eaa40SDavid Ahern return 0; 2372e03eaa40SDavid Ahern 2373e03eaa40SDavid Ahern *list = intlist__new(list_str); 2374e03eaa40SDavid Ahern if (!*list) { 2375e03eaa40SDavid Ahern pr_err("problems parsing %s list\n", list_name); 2376e03eaa40SDavid Ahern return -1; 2377e03eaa40SDavid Ahern } 2378e03eaa40SDavid Ahern return 0; 2379e03eaa40SDavid Ahern } 2380e03eaa40SDavid Ahern 238161d9fc44SJin Yao static int setup_addrlist(struct intlist **addr_list, struct strlist *sym_list) 238261d9fc44SJin Yao { 238361d9fc44SJin Yao struct str_node *pos, *tmp; 238461d9fc44SJin Yao unsigned long val; 238561d9fc44SJin Yao char *sep; 238661d9fc44SJin Yao const char *end; 238761d9fc44SJin Yao int i = 0, err; 238861d9fc44SJin Yao 238961d9fc44SJin Yao *addr_list = intlist__new(NULL); 239061d9fc44SJin Yao if (!*addr_list) 239161d9fc44SJin Yao return -1; 239261d9fc44SJin Yao 239361d9fc44SJin Yao strlist__for_each_entry_safe(pos, tmp, sym_list) { 239461d9fc44SJin Yao errno = 0; 239561d9fc44SJin Yao val = strtoul(pos->s, &sep, 16); 239661d9fc44SJin Yao if (errno || (sep == pos->s)) 239761d9fc44SJin Yao continue; 239861d9fc44SJin Yao 239961d9fc44SJin Yao if (*sep != '\0') { 240061d9fc44SJin Yao end = pos->s + strlen(pos->s) - 1; 240161d9fc44SJin Yao while (end >= sep && isspace(*end)) 240261d9fc44SJin Yao end--; 240361d9fc44SJin Yao 240461d9fc44SJin Yao if (end >= sep) 240561d9fc44SJin Yao continue; 240661d9fc44SJin Yao } 240761d9fc44SJin Yao 240861d9fc44SJin Yao err = intlist__add(*addr_list, val); 240961d9fc44SJin Yao if (err) 241061d9fc44SJin Yao break; 241161d9fc44SJin Yao 241261d9fc44SJin Yao strlist__remove(sym_list, pos); 241361d9fc44SJin Yao i++; 241461d9fc44SJin Yao } 241561d9fc44SJin Yao 241661d9fc44SJin Yao if (i == 0) { 241761d9fc44SJin Yao intlist__delete(*addr_list); 241861d9fc44SJin Yao *addr_list = NULL; 241961d9fc44SJin Yao } 242061d9fc44SJin Yao 242161d9fc44SJin Yao return 0; 242261d9fc44SJin Yao } 242361d9fc44SJin Yao 2424ec80fde7SArnaldo Carvalho de Melo static bool symbol__read_kptr_restrict(void) 2425ec80fde7SArnaldo Carvalho de Melo { 2426ec80fde7SArnaldo Carvalho de Melo bool value = false; 2427ec80fde7SArnaldo Carvalho de Melo FILE *fp = fopen("/proc/sys/kernel/kptr_restrict", "r"); 242838272dc4SWang Nan 2429ec80fde7SArnaldo Carvalho de Melo if (fp != NULL) { 2430ec80fde7SArnaldo Carvalho de Melo char line[8]; 2431ec80fde7SArnaldo Carvalho de Melo 2432ec80fde7SArnaldo Carvalho de Melo if (fgets(line, sizeof(line), fp) != NULL) 24338859aedeSIgor Lubashev value = perf_cap__capable(CAP_SYSLOG) ? 24348859aedeSIgor Lubashev (atoi(line) >= 2) : 24358859aedeSIgor Lubashev (atoi(line) != 0); 2436ec80fde7SArnaldo Carvalho de Melo 2437ec80fde7SArnaldo Carvalho de Melo fclose(fp); 2438ec80fde7SArnaldo Carvalho de Melo } 2439ec80fde7SArnaldo Carvalho de Melo 24408859aedeSIgor Lubashev /* Per kernel/kallsyms.c: 24418859aedeSIgor Lubashev * we also restrict when perf_event_paranoid > 1 w/o CAP_SYSLOG 24428859aedeSIgor Lubashev */ 24438859aedeSIgor Lubashev if (perf_event_paranoid() > 1 && !perf_cap__capable(CAP_SYSLOG)) 24448859aedeSIgor Lubashev value = true; 24458859aedeSIgor Lubashev 2446ec80fde7SArnaldo Carvalho de Melo return value; 2447ec80fde7SArnaldo Carvalho de Melo } 2448ec80fde7SArnaldo Carvalho de Melo 2449b01141f4SArnaldo Carvalho de Melo int symbol__annotation_init(void) 2450b01141f4SArnaldo Carvalho de Melo { 24517b366142SArnaldo Carvalho de Melo if (symbol_conf.init_annotation) 24527b366142SArnaldo Carvalho de Melo return 0; 24537b366142SArnaldo Carvalho de Melo 2454b01141f4SArnaldo Carvalho de Melo if (symbol_conf.initialized) { 2455b01141f4SArnaldo Carvalho de Melo pr_err("Annotation needs to be init before symbol__init()\n"); 2456b01141f4SArnaldo Carvalho de Melo return -1; 2457b01141f4SArnaldo Carvalho de Melo } 2458b01141f4SArnaldo Carvalho de Melo 2459b01141f4SArnaldo Carvalho de Melo symbol_conf.priv_size += sizeof(struct annotation); 2460b01141f4SArnaldo Carvalho de Melo symbol_conf.init_annotation = true; 2461b01141f4SArnaldo Carvalho de Melo return 0; 2462b01141f4SArnaldo Carvalho de Melo } 2463b01141f4SArnaldo Carvalho de Melo 2464ce80d3beSKan Liang int symbol__init(struct perf_env *env) 2465cc612d81SArnaldo Carvalho de Melo { 2466ec5761eaSDavid Ahern const char *symfs; 2467ec5761eaSDavid Ahern 246885e00b55SJovi Zhang if (symbol_conf.initialized) 246985e00b55SJovi Zhang return 0; 247085e00b55SJovi Zhang 24719ac3e487SIrina Tirdea symbol_conf.priv_size = PERF_ALIGN(symbol_conf.priv_size, sizeof(u64)); 24724d439517SDavid S. Miller 2473166ccc9cSNamhyung Kim symbol__elf_init(); 2474166ccc9cSNamhyung Kim 24750a7e6d1bSNamhyung Kim if (symbol_conf.try_vmlinux_path && vmlinux_path__init(env) < 0) 2476cc612d81SArnaldo Carvalho de Melo return -1; 2477cc612d81SArnaldo Carvalho de Melo 2478c410a338SArnaldo Carvalho de Melo if (symbol_conf.field_sep && *symbol_conf.field_sep == '.') { 2479c410a338SArnaldo Carvalho de Melo pr_err("'.' is the only non valid --field-separator argument\n"); 2480c410a338SArnaldo Carvalho de Melo return -1; 2481c410a338SArnaldo Carvalho de Melo } 2482c410a338SArnaldo Carvalho de Melo 2483655000e7SArnaldo Carvalho de Melo if (setup_list(&symbol_conf.dso_list, 2484655000e7SArnaldo Carvalho de Melo symbol_conf.dso_list_str, "dso") < 0) 2485655000e7SArnaldo Carvalho de Melo return -1; 2486655000e7SArnaldo Carvalho de Melo 2487655000e7SArnaldo Carvalho de Melo if (setup_list(&symbol_conf.comm_list, 2488655000e7SArnaldo Carvalho de Melo symbol_conf.comm_list_str, "comm") < 0) 2489655000e7SArnaldo Carvalho de Melo goto out_free_dso_list; 2490655000e7SArnaldo Carvalho de Melo 2491e03eaa40SDavid Ahern if (setup_intlist(&symbol_conf.pid_list, 2492e03eaa40SDavid Ahern symbol_conf.pid_list_str, "pid") < 0) 2493e03eaa40SDavid Ahern goto out_free_comm_list; 2494e03eaa40SDavid Ahern 2495e03eaa40SDavid Ahern if (setup_intlist(&symbol_conf.tid_list, 2496e03eaa40SDavid Ahern symbol_conf.tid_list_str, "tid") < 0) 2497e03eaa40SDavid Ahern goto out_free_pid_list; 2498e03eaa40SDavid Ahern 2499655000e7SArnaldo Carvalho de Melo if (setup_list(&symbol_conf.sym_list, 2500655000e7SArnaldo Carvalho de Melo symbol_conf.sym_list_str, "symbol") < 0) 2501e03eaa40SDavid Ahern goto out_free_tid_list; 2502655000e7SArnaldo Carvalho de Melo 250361d9fc44SJin Yao if (symbol_conf.sym_list && 250461d9fc44SJin Yao setup_addrlist(&symbol_conf.addr_list, symbol_conf.sym_list) < 0) 250561d9fc44SJin Yao goto out_free_sym_list; 250661d9fc44SJin Yao 250764eff7d9SDavid Ahern if (setup_list(&symbol_conf.bt_stop_list, 250864eff7d9SDavid Ahern symbol_conf.bt_stop_list_str, "symbol") < 0) 250964eff7d9SDavid Ahern goto out_free_sym_list; 251064eff7d9SDavid Ahern 2511ec5761eaSDavid Ahern /* 2512ec5761eaSDavid Ahern * A path to symbols of "/" is identical to "" 2513ec5761eaSDavid Ahern * reset here for simplicity. 2514ec5761eaSDavid Ahern */ 2515ec5761eaSDavid Ahern symfs = realpath(symbol_conf.symfs, NULL); 2516ec5761eaSDavid Ahern if (symfs == NULL) 2517ec5761eaSDavid Ahern symfs = symbol_conf.symfs; 2518ec5761eaSDavid Ahern if (strcmp(symfs, "/") == 0) 2519ec5761eaSDavid Ahern symbol_conf.symfs = ""; 2520ec5761eaSDavid Ahern if (symfs != symbol_conf.symfs) 2521ec5761eaSDavid Ahern free((void *)symfs); 2522ec5761eaSDavid Ahern 2523ec80fde7SArnaldo Carvalho de Melo symbol_conf.kptr_restrict = symbol__read_kptr_restrict(); 2524ec80fde7SArnaldo Carvalho de Melo 252585e00b55SJovi Zhang symbol_conf.initialized = true; 25264aa65636SArnaldo Carvalho de Melo return 0; 2527655000e7SArnaldo Carvalho de Melo 252864eff7d9SDavid Ahern out_free_sym_list: 252964eff7d9SDavid Ahern strlist__delete(symbol_conf.sym_list); 253061d9fc44SJin Yao intlist__delete(symbol_conf.addr_list); 2531e03eaa40SDavid Ahern out_free_tid_list: 2532e03eaa40SDavid Ahern intlist__delete(symbol_conf.tid_list); 2533e03eaa40SDavid Ahern out_free_pid_list: 2534e03eaa40SDavid Ahern intlist__delete(symbol_conf.pid_list); 2535655000e7SArnaldo Carvalho de Melo out_free_comm_list: 2536655000e7SArnaldo Carvalho de Melo strlist__delete(symbol_conf.comm_list); 2537d74c896bSNamhyung Kim out_free_dso_list: 2538d74c896bSNamhyung Kim strlist__delete(symbol_conf.dso_list); 2539655000e7SArnaldo Carvalho de Melo return -1; 2540cc612d81SArnaldo Carvalho de Melo } 2541cc612d81SArnaldo Carvalho de Melo 2542d65a458bSArnaldo Carvalho de Melo void symbol__exit(void) 2543d65a458bSArnaldo Carvalho de Melo { 254485e00b55SJovi Zhang if (!symbol_conf.initialized) 254585e00b55SJovi Zhang return; 254664eff7d9SDavid Ahern strlist__delete(symbol_conf.bt_stop_list); 2547d65a458bSArnaldo Carvalho de Melo strlist__delete(symbol_conf.sym_list); 2548d65a458bSArnaldo Carvalho de Melo strlist__delete(symbol_conf.dso_list); 2549d65a458bSArnaldo Carvalho de Melo strlist__delete(symbol_conf.comm_list); 2550e03eaa40SDavid Ahern intlist__delete(symbol_conf.tid_list); 2551e03eaa40SDavid Ahern intlist__delete(symbol_conf.pid_list); 255261d9fc44SJin Yao intlist__delete(symbol_conf.addr_list); 2553d65a458bSArnaldo Carvalho de Melo vmlinux_path__exit(); 2554d65a458bSArnaldo Carvalho de Melo symbol_conf.sym_list = symbol_conf.dso_list = symbol_conf.comm_list = NULL; 255564eff7d9SDavid Ahern symbol_conf.bt_stop_list = NULL; 255685e00b55SJovi Zhang symbol_conf.initialized = false; 2557d65a458bSArnaldo Carvalho de Melo } 2558a7066709SHe Kuang 2559a7066709SHe Kuang int symbol__config_symfs(const struct option *opt __maybe_unused, 2560a7066709SHe Kuang const char *dir, int unset __maybe_unused) 2561a7066709SHe Kuang { 2562a7066709SHe Kuang char *bf = NULL; 2563a7066709SHe Kuang int ret; 2564a7066709SHe Kuang 2565a7066709SHe Kuang symbol_conf.symfs = strdup(dir); 2566a7066709SHe Kuang if (symbol_conf.symfs == NULL) 2567a7066709SHe Kuang return -ENOMEM; 2568a7066709SHe Kuang 2569a7066709SHe Kuang /* skip the locally configured cache if a symfs is given, and 2570a7066709SHe Kuang * config buildid dir to symfs/.debug 2571a7066709SHe Kuang */ 2572a7066709SHe Kuang ret = asprintf(&bf, "%s/%s", dir, ".debug"); 2573a7066709SHe Kuang if (ret < 0) 2574a7066709SHe Kuang return -ENOMEM; 2575a7066709SHe Kuang 2576a7066709SHe Kuang set_buildid_dir(bf); 2577a7066709SHe Kuang 2578a7066709SHe Kuang free(bf); 2579a7066709SHe Kuang return 0; 2580a7066709SHe Kuang } 25819f87498fSJiri Olsa 2582a3df50abSJames Clark /* 2583a3df50abSJames Clark * Checks that user supplied symbol kernel files are accessible because 2584a3df50abSJames Clark * the default mechanism for accessing elf files fails silently. i.e. if 2585a3df50abSJames Clark * debug syms for a build ID aren't found perf carries on normally. When 2586a3df50abSJames Clark * they are user supplied we should assume that the user doesn't want to 2587a3df50abSJames Clark * silently fail. 2588a3df50abSJames Clark */ 2589a3df50abSJames Clark int symbol__validate_sym_arguments(void) 2590a3df50abSJames Clark { 2591a3df50abSJames Clark if (symbol_conf.vmlinux_name && 2592a3df50abSJames Clark access(symbol_conf.vmlinux_name, R_OK)) { 2593a3df50abSJames Clark pr_err("Invalid file: %s\n", symbol_conf.vmlinux_name); 2594a3df50abSJames Clark return -EINVAL; 2595a3df50abSJames Clark } 2596a3df50abSJames Clark if (symbol_conf.kallsyms_name && 2597a3df50abSJames Clark access(symbol_conf.kallsyms_name, R_OK)) { 2598a3df50abSJames Clark pr_err("Invalid file: %s\n", symbol_conf.kallsyms_name); 2599a3df50abSJames Clark return -EINVAL; 2600a3df50abSJames Clark } 2601a3df50abSJames Clark return 0; 2602a3df50abSJames Clark } 2603