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" 30b1d1b094SArnaldo Carvalho de Melo #include "symsrc.h" 315aab621bSArnaldo Carvalho de Melo #include "strlist.h" 32e03eaa40SDavid Ahern #include "intlist.h" 33843ff37bSKrister Johansen #include "namespaces.h" 340a7e6d1bSNamhyung Kim #include "header.h" 359a3993d4SArnaldo Carvalho de Melo #include "path.h" 363052ba56SArnaldo Carvalho de Melo #include <linux/ctype.h> 377f7c536fSArnaldo Carvalho de Melo #include <linux/zalloc.h> 3886470930SIngo Molnar 3986470930SIngo Molnar #include <elf.h> 40f1617b40SArnaldo Carvalho de Melo #include <limits.h> 41c506c96bSArnaldo Carvalho de Melo #include <symbol/kallsyms.h> 42439d473bSArnaldo Carvalho de Melo #include <sys/utsname.h> 432cdbc46dSPeter Zijlstra 44be39db9fSArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *dso, struct map *map); 45be39db9fSArnaldo Carvalho de Melo static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map); 46608c34deSArnaldo Carvalho de Melo static bool symbol__is_idle(const char *name); 47608c34deSArnaldo Carvalho de Melo 483f067dcaSArnaldo Carvalho de Melo int vmlinux_path__nr_entries; 493f067dcaSArnaldo Carvalho de Melo char **vmlinux_path; 50439d473bSArnaldo Carvalho de Melo 5183720209SIan Rogers struct map_list_node { 5283720209SIan Rogers struct list_head node; 5383720209SIan Rogers struct map *map; 5483720209SIan Rogers }; 5583720209SIan Rogers 5675be6cf4SArnaldo Carvalho de Melo struct symbol_conf symbol_conf = { 5752bab886SAndi Kleen .nanosecs = false, 58b32d133aSArnaldo Carvalho de Melo .use_modules = true, 59b32d133aSArnaldo Carvalho de Melo .try_vmlinux_path = true, 60328ccdacSNamhyung Kim .demangle = true, 61763122adSAvi Kivity .demangle_kernel = false, 62e511db5eSNamhyung Kim .cumulate_callchain = true, 632a1292cbSAndi Kleen .time_quantum = 100 * NSEC_PER_MSEC, /* 100ms */ 64c8302367SJiri Olsa .show_hist_headers = true, 65ec5761eaSDavid Ahern .symfs = "", 661e9abf8bSNamhyung Kim .event_group = true, 67d8a88dd2SMilian Wolff .inline_name = true, 684968ac8fSAndi Kleen .res_sample = 0, 69b32d133aSArnaldo Carvalho de Melo }; 70b32d133aSArnaldo Carvalho de Melo 7144f24cb3SJiri Olsa static enum dso_binary_type binary_type_symtab[] = { 7244f24cb3SJiri Olsa DSO_BINARY_TYPE__KALLSYMS, 7344f24cb3SJiri Olsa DSO_BINARY_TYPE__GUEST_KALLSYMS, 7444f24cb3SJiri Olsa DSO_BINARY_TYPE__JAVA_JIT, 7544f24cb3SJiri Olsa DSO_BINARY_TYPE__DEBUGLINK, 7644f24cb3SJiri Olsa DSO_BINARY_TYPE__BUILD_ID_CACHE, 77d2396999SKrister Johansen DSO_BINARY_TYPE__BUILD_ID_CACHE_DEBUGINFO, 7844f24cb3SJiri Olsa DSO_BINARY_TYPE__FEDORA_DEBUGINFO, 7944f24cb3SJiri Olsa DSO_BINARY_TYPE__UBUNTU_DEBUGINFO, 8044f24cb3SJiri Olsa DSO_BINARY_TYPE__BUILDID_DEBUGINFO, 8144f24cb3SJiri Olsa DSO_BINARY_TYPE__SYSTEM_PATH_DSO, 8244f24cb3SJiri Olsa DSO_BINARY_TYPE__GUEST_KMODULE, 83c00c48fcSNamhyung Kim DSO_BINARY_TYPE__GUEST_KMODULE_COMP, 8444f24cb3SJiri Olsa DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE, 85c00c48fcSNamhyung Kim DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP, 869cd00941SRicardo Ribalda Delgado DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO, 8785afd355SAdrian Hunter DSO_BINARY_TYPE__MIXEDUP_UBUNTU_DEBUGINFO, 8844f24cb3SJiri Olsa DSO_BINARY_TYPE__NOT_FOUND, 8944f24cb3SJiri Olsa }; 9044f24cb3SJiri Olsa 91028df767SJiri Olsa #define DSO_BINARY_TYPE__SYMTAB_CNT ARRAY_SIZE(binary_type_symtab) 9244f24cb3SJiri Olsa 9383720209SIan Rogers static struct map_list_node *map_list_node__new(void) 9483720209SIan Rogers { 9583720209SIan Rogers return malloc(sizeof(struct map_list_node)); 9683720209SIan Rogers } 9783720209SIan Rogers 983183f8caSArnaldo Carvalho de Melo static bool symbol_type__filter(char symbol_type) 996893d4eeSArnaldo Carvalho de Melo { 10031877908SAnton Blanchard symbol_type = toupper(symbol_type); 1012be732c0SArnaldo Carvalho de Melo return symbol_type == 'T' || symbol_type == 'W' || symbol_type == 'D' || symbol_type == 'B'; 1026893d4eeSArnaldo Carvalho de Melo } 1036893d4eeSArnaldo Carvalho de Melo 104694bf407SAnton Blanchard static int prefix_underscores_count(const char *str) 105694bf407SAnton Blanchard { 106694bf407SAnton Blanchard const char *tail = str; 107694bf407SAnton Blanchard 108694bf407SAnton Blanchard while (*tail == '_') 109694bf407SAnton Blanchard tail++; 110694bf407SAnton Blanchard 111694bf407SAnton Blanchard return tail - str; 112694bf407SAnton Blanchard } 113694bf407SAnton Blanchard 1144b3a2716SMasami Hiramatsu const char * __weak arch__normalize_symbol_name(const char *name) 1154b3a2716SMasami Hiramatsu { 1164b3a2716SMasami Hiramatsu return name; 1174b3a2716SMasami Hiramatsu } 1184b3a2716SMasami Hiramatsu 119d8040645SPaul Clarke int __weak arch__compare_symbol_names(const char *namea, const char *nameb) 120d8040645SPaul Clarke { 121d8040645SPaul Clarke return strcmp(namea, nameb); 122d8040645SPaul Clarke } 123d8040645SPaul Clarke 124d8040645SPaul Clarke int __weak arch__compare_symbol_names_n(const char *namea, const char *nameb, 125d8040645SPaul Clarke unsigned int n) 126d8040645SPaul Clarke { 127d8040645SPaul Clarke return strncmp(namea, nameb, n); 128d8040645SPaul Clarke } 129d8040645SPaul Clarke 130fb6d5942SNaveen N. Rao int __weak arch__choose_best_symbol(struct symbol *syma, 131fb6d5942SNaveen N. Rao struct symbol *symb __maybe_unused) 132fb6d5942SNaveen N. Rao { 133fb6d5942SNaveen N. Rao /* Avoid "SyS" kernel syscall aliases */ 134fb6d5942SNaveen N. Rao if (strlen(syma->name) >= 3 && !strncmp(syma->name, "SyS", 3)) 135fb6d5942SNaveen N. Rao return SYMBOL_B; 136fb6d5942SNaveen N. Rao if (strlen(syma->name) >= 10 && !strncmp(syma->name, "compat_SyS", 10)) 137fb6d5942SNaveen N. Rao return SYMBOL_B; 138fb6d5942SNaveen N. Rao 139fb6d5942SNaveen N. Rao return SYMBOL_A; 140fb6d5942SNaveen N. Rao } 141694bf407SAnton Blanchard 142694bf407SAnton Blanchard static int choose_best_symbol(struct symbol *syma, struct symbol *symb) 143694bf407SAnton Blanchard { 144694bf407SAnton Blanchard s64 a; 145694bf407SAnton Blanchard s64 b; 1463445432bSAdrian Hunter size_t na, nb; 147694bf407SAnton Blanchard 148694bf407SAnton Blanchard /* Prefer a symbol with non zero length */ 149694bf407SAnton Blanchard a = syma->end - syma->start; 150694bf407SAnton Blanchard b = symb->end - symb->start; 151694bf407SAnton Blanchard if ((b == 0) && (a > 0)) 152694bf407SAnton Blanchard return SYMBOL_A; 153694bf407SAnton Blanchard else if ((a == 0) && (b > 0)) 154694bf407SAnton Blanchard return SYMBOL_B; 155694bf407SAnton Blanchard 156694bf407SAnton Blanchard /* Prefer a non weak symbol over a weak one */ 157694bf407SAnton Blanchard a = syma->binding == STB_WEAK; 158694bf407SAnton Blanchard b = symb->binding == STB_WEAK; 159694bf407SAnton Blanchard if (b && !a) 160694bf407SAnton Blanchard return SYMBOL_A; 161694bf407SAnton Blanchard if (a && !b) 162694bf407SAnton Blanchard return SYMBOL_B; 163694bf407SAnton Blanchard 164694bf407SAnton Blanchard /* Prefer a global symbol over a non global one */ 165694bf407SAnton Blanchard a = syma->binding == STB_GLOBAL; 166694bf407SAnton Blanchard b = symb->binding == STB_GLOBAL; 167694bf407SAnton Blanchard if (a && !b) 168694bf407SAnton Blanchard return SYMBOL_A; 169694bf407SAnton Blanchard if (b && !a) 170694bf407SAnton Blanchard return SYMBOL_B; 171694bf407SAnton Blanchard 172694bf407SAnton Blanchard /* Prefer a symbol with less underscores */ 173694bf407SAnton Blanchard a = prefix_underscores_count(syma->name); 174694bf407SAnton Blanchard b = prefix_underscores_count(symb->name); 175694bf407SAnton Blanchard if (b > a) 176694bf407SAnton Blanchard return SYMBOL_A; 177694bf407SAnton Blanchard else if (a > b) 178694bf407SAnton Blanchard return SYMBOL_B; 179694bf407SAnton Blanchard 1803445432bSAdrian Hunter /* Choose the symbol with the longest name */ 1813445432bSAdrian Hunter na = strlen(syma->name); 1823445432bSAdrian Hunter nb = strlen(symb->name); 1833445432bSAdrian Hunter if (na > nb) 184694bf407SAnton Blanchard return SYMBOL_A; 1853445432bSAdrian Hunter else if (na < nb) 186694bf407SAnton Blanchard return SYMBOL_B; 1873445432bSAdrian Hunter 188fb6d5942SNaveen N. Rao return arch__choose_best_symbol(syma, symb); 189694bf407SAnton Blanchard } 190694bf407SAnton Blanchard 1917137ff50SDavidlohr Bueso void symbols__fixup_duplicate(struct rb_root_cached *symbols) 192694bf407SAnton Blanchard { 193694bf407SAnton Blanchard struct rb_node *nd; 194694bf407SAnton Blanchard struct symbol *curr, *next; 195694bf407SAnton Blanchard 196c97b40e4SArnaldo Carvalho de Melo if (symbol_conf.allow_aliases) 197c97b40e4SArnaldo Carvalho de Melo return; 198c97b40e4SArnaldo Carvalho de Melo 1997137ff50SDavidlohr Bueso nd = rb_first_cached(symbols); 200694bf407SAnton Blanchard 201694bf407SAnton Blanchard while (nd) { 202694bf407SAnton Blanchard curr = rb_entry(nd, struct symbol, rb_node); 203694bf407SAnton Blanchard again: 204694bf407SAnton Blanchard nd = rb_next(&curr->rb_node); 205694bf407SAnton Blanchard next = rb_entry(nd, struct symbol, rb_node); 206694bf407SAnton Blanchard 207694bf407SAnton Blanchard if (!nd) 208694bf407SAnton Blanchard break; 209694bf407SAnton Blanchard 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 * 2528799ebceSNamhyung Kim * In kallsyms, it determines module symbols using '[' character 2538799ebceSNamhyung Kim * like in: 2548799ebceSNamhyung Kim * ffffffffc1937000 T hdmi_driver_init [snd_hda_codec_hdmi] 2558799ebceSNamhyung Kim */ 2568799ebceSNamhyung Kim if (prev->end == prev->start) { 2578799ebceSNamhyung Kim /* Last kernel/module symbol mapped to end of page */ 2588799ebceSNamhyung Kim if (is_kallsyms && (!strchr(prev->name, '[') != 2598799ebceSNamhyung Kim !strchr(curr->name, '['))) 2608799ebceSNamhyung Kim prev->end = roundup(prev->end + 4096, 4096); 2618799ebceSNamhyung Kim else 2628799ebceSNamhyung Kim prev->end = curr->start; 2638799ebceSNamhyung Kim 2648799ebceSNamhyung Kim pr_debug4("%s sym:%s end:%#" PRIx64 "\n", 2658799ebceSNamhyung Kim __func__, prev->name, prev->end); 2668799ebceSNamhyung Kim } 267af427bf5SArnaldo Carvalho de Melo } 268af427bf5SArnaldo Carvalho de Melo 2692e538c4aSArnaldo Carvalho de Melo /* Last entry */ 2702e538c4aSArnaldo Carvalho de Melo if (curr->end == curr->start) 271e7ede72aSDaniel Borkmann curr->end = roundup(curr->start, 4096) + 4096; 2722e538c4aSArnaldo Carvalho de Melo } 2732e538c4aSArnaldo Carvalho de Melo 2749a29ceeeSArnaldo Carvalho de Melo void maps__fixup_end(struct maps *maps) 275af427bf5SArnaldo Carvalho de Melo { 276ff583dc4SIan Rogers struct map_rb_node *prev = NULL, *curr; 277af427bf5SArnaldo Carvalho de Melo 2785ab6d715SIan Rogers down_write(maps__lock(maps)); 2796a2ffcddSArnaldo Carvalho de Melo 2808efc4f05SArnaldo Carvalho de Melo maps__for_each_entry(maps, curr) { 281e5116f46SIan Rogers if (prev != NULL && !map__end(prev->map)) 282e5116f46SIan Rogers prev->map->end = map__start(curr->map); 283af427bf5SArnaldo Carvalho de Melo 2848efc4f05SArnaldo Carvalho de Melo prev = curr; 2852e538c4aSArnaldo Carvalho de Melo } 28690c83218SArnaldo Carvalho de Melo 28790c83218SArnaldo Carvalho de Melo /* 28890c83218SArnaldo Carvalho de Melo * We still haven't the actual symbols, so guess the 28990c83218SArnaldo Carvalho de Melo * last map final address. 29090c83218SArnaldo Carvalho de Melo */ 291e5116f46SIan Rogers if (curr && !map__end(curr->map)) 292ff583dc4SIan Rogers curr->map->end = ~0ULL; 2936a2ffcddSArnaldo Carvalho de Melo 2945ab6d715SIan Rogers up_write(maps__lock(maps)); 295af427bf5SArnaldo Carvalho de Melo } 296af427bf5SArnaldo Carvalho de Melo 297af30bffaSArnaldo Carvalho de Melo struct symbol *symbol__new(u64 start, u64 len, u8 binding, u8 type, const char *name) 29886470930SIngo Molnar { 29986470930SIngo Molnar size_t namelen = strlen(name) + 1; 300aeafcbafSArnaldo Carvalho de Melo struct symbol *sym = calloc(1, (symbol_conf.priv_size + 301aeafcbafSArnaldo Carvalho de Melo sizeof(*sym) + namelen)); 302aeafcbafSArnaldo Carvalho de Melo if (sym == NULL) 30386470930SIngo Molnar return NULL; 30486470930SIngo Molnar 305b01141f4SArnaldo Carvalho de Melo if (symbol_conf.priv_size) { 306b01141f4SArnaldo Carvalho de Melo if (symbol_conf.init_annotation) { 307b01141f4SArnaldo Carvalho de Melo struct annotation *notes = (void *)sym; 3084f74f187SIan Rogers annotation__init(notes); 309b01141f4SArnaldo Carvalho de Melo } 310aeafcbafSArnaldo Carvalho de Melo sym = ((void *)sym) + symbol_conf.priv_size; 311b01141f4SArnaldo Carvalho de Melo } 31236479484SArnaldo Carvalho de Melo 313aeafcbafSArnaldo Carvalho de Melo sym->start = start; 3142c241bd3SArnaldo Carvalho de Melo sym->end = len ? start + len : start; 315af30bffaSArnaldo Carvalho de Melo sym->type = type; 316aeafcbafSArnaldo Carvalho de Melo sym->binding = binding; 317aeafcbafSArnaldo Carvalho de Melo sym->namelen = namelen - 1; 318e4204992SArnaldo Carvalho de Melo 319aeafcbafSArnaldo Carvalho de Melo pr_debug4("%s: %s %#" PRIx64 "-%#" PRIx64 "\n", 320aeafcbafSArnaldo Carvalho de Melo __func__, name, start, sym->end); 321aeafcbafSArnaldo Carvalho de Melo memcpy(sym->name, name, namelen); 322e4204992SArnaldo Carvalho de Melo 323aeafcbafSArnaldo Carvalho de Melo return sym; 32486470930SIngo Molnar } 32586470930SIngo Molnar 326aeafcbafSArnaldo Carvalho de Melo void symbol__delete(struct symbol *sym) 32786470930SIngo Molnar { 3284f74f187SIan Rogers if (symbol_conf.priv_size) { 3294f74f187SIan Rogers if (symbol_conf.init_annotation) { 3304f74f187SIan Rogers struct annotation *notes = symbol__annotation(sym); 3314f74f187SIan Rogers 3324f74f187SIan Rogers annotation__exit(notes); 3334f74f187SIan Rogers } 3344f74f187SIan Rogers } 335aeafcbafSArnaldo Carvalho de Melo free(((void *)sym) - symbol_conf.priv_size); 33686470930SIngo Molnar } 33786470930SIngo Molnar 3387137ff50SDavidlohr Bueso void symbols__delete(struct rb_root_cached *symbols) 33986470930SIngo Molnar { 34086470930SIngo Molnar struct symbol *pos; 3417137ff50SDavidlohr Bueso struct rb_node *next = rb_first_cached(symbols); 34286470930SIngo Molnar 34386470930SIngo Molnar while (next) { 34486470930SIngo Molnar pos = rb_entry(next, struct symbol, rb_node); 34586470930SIngo Molnar next = rb_next(&pos->rb_node); 3467137ff50SDavidlohr Bueso rb_erase_cached(&pos->rb_node, symbols); 34700a192b3SArnaldo Carvalho de Melo symbol__delete(pos); 34886470930SIngo Molnar } 34986470930SIngo Molnar } 35086470930SIngo Molnar 3517137ff50SDavidlohr Bueso void __symbols__insert(struct rb_root_cached *symbols, 3527137ff50SDavidlohr Bueso struct symbol *sym, bool kernel) 35386470930SIngo Molnar { 3547137ff50SDavidlohr Bueso struct rb_node **p = &symbols->rb_root.rb_node; 35586470930SIngo Molnar struct rb_node *parent = NULL; 3569cffa8d5SPaul Mackerras const u64 ip = sym->start; 35786470930SIngo Molnar struct symbol *s; 3587137ff50SDavidlohr Bueso bool leftmost = true; 35986470930SIngo Molnar 360608c34deSArnaldo Carvalho de Melo if (kernel) { 361608c34deSArnaldo Carvalho de Melo const char *name = sym->name; 362608c34deSArnaldo Carvalho de Melo /* 363608c34deSArnaldo Carvalho de Melo * ppc64 uses function descriptors and appends a '.' to the 364608c34deSArnaldo Carvalho de Melo * start of every instruction address. Remove it. 365608c34deSArnaldo Carvalho de Melo */ 366608c34deSArnaldo Carvalho de Melo if (name[0] == '.') 367608c34deSArnaldo Carvalho de Melo name++; 368608c34deSArnaldo Carvalho de Melo sym->idle = symbol__is_idle(name); 369608c34deSArnaldo Carvalho de Melo } 370608c34deSArnaldo Carvalho de Melo 37186470930SIngo Molnar while (*p != NULL) { 37286470930SIngo Molnar parent = *p; 37386470930SIngo Molnar s = rb_entry(parent, struct symbol, rb_node); 37486470930SIngo Molnar if (ip < s->start) 37586470930SIngo Molnar p = &(*p)->rb_left; 3767137ff50SDavidlohr Bueso else { 37786470930SIngo Molnar p = &(*p)->rb_right; 3787137ff50SDavidlohr Bueso leftmost = false; 3797137ff50SDavidlohr Bueso } 38086470930SIngo Molnar } 38186470930SIngo Molnar rb_link_node(&sym->rb_node, parent, p); 3827137ff50SDavidlohr Bueso rb_insert_color_cached(&sym->rb_node, symbols, leftmost); 38386470930SIngo Molnar } 38486470930SIngo Molnar 3857137ff50SDavidlohr Bueso void symbols__insert(struct rb_root_cached *symbols, struct symbol *sym) 386608c34deSArnaldo Carvalho de Melo { 387608c34deSArnaldo Carvalho de Melo __symbols__insert(symbols, sym, false); 388608c34deSArnaldo Carvalho de Melo } 389608c34deSArnaldo Carvalho de Melo 3907137ff50SDavidlohr Bueso static struct symbol *symbols__find(struct rb_root_cached *symbols, u64 ip) 39186470930SIngo Molnar { 39286470930SIngo Molnar struct rb_node *n; 39386470930SIngo Molnar 394aeafcbafSArnaldo Carvalho de Melo if (symbols == NULL) 39586470930SIngo Molnar return NULL; 39686470930SIngo Molnar 3977137ff50SDavidlohr Bueso n = symbols->rb_root.rb_node; 39886470930SIngo Molnar 39986470930SIngo Molnar while (n) { 40086470930SIngo Molnar struct symbol *s = rb_entry(n, struct symbol, rb_node); 40186470930SIngo Molnar 40286470930SIngo Molnar if (ip < s->start) 40386470930SIngo Molnar n = n->rb_left; 4049c7b37cdSChris Phlipot else if (ip > s->end || (ip == s->end && ip != s->start)) 40586470930SIngo Molnar n = n->rb_right; 40686470930SIngo Molnar else 40786470930SIngo Molnar return s; 40886470930SIngo Molnar } 40986470930SIngo Molnar 41086470930SIngo Molnar return NULL; 41186470930SIngo Molnar } 41286470930SIngo Molnar 4137137ff50SDavidlohr Bueso static struct symbol *symbols__first(struct rb_root_cached *symbols) 4148e0cf965SAdrian Hunter { 4157137ff50SDavidlohr Bueso struct rb_node *n = rb_first_cached(symbols); 4168e0cf965SAdrian Hunter 4178e0cf965SAdrian Hunter if (n) 4188e0cf965SAdrian Hunter return rb_entry(n, struct symbol, rb_node); 4198e0cf965SAdrian Hunter 4208e0cf965SAdrian Hunter return NULL; 4218e0cf965SAdrian Hunter } 4228e0cf965SAdrian Hunter 4237137ff50SDavidlohr Bueso static struct symbol *symbols__last(struct rb_root_cached *symbols) 424cd67f99fSAdrian Hunter { 4257137ff50SDavidlohr Bueso struct rb_node *n = rb_last(&symbols->rb_root); 426cd67f99fSAdrian Hunter 427cd67f99fSAdrian Hunter if (n) 428cd67f99fSAdrian Hunter return rb_entry(n, struct symbol, rb_node); 429cd67f99fSAdrian Hunter 430cd67f99fSAdrian Hunter return NULL; 431cd67f99fSAdrian Hunter } 432cd67f99fSAdrian Hunter 4339c00a81bSAdrian Hunter static struct symbol *symbols__next(struct symbol *sym) 4349c00a81bSAdrian Hunter { 4359c00a81bSAdrian Hunter struct rb_node *n = rb_next(&sym->rb_node); 4369c00a81bSAdrian Hunter 4379c00a81bSAdrian Hunter if (n) 4389c00a81bSAdrian Hunter return rb_entry(n, struct symbol, rb_node); 4399c00a81bSAdrian Hunter 4409c00a81bSAdrian Hunter return NULL; 4419c00a81bSAdrian Hunter } 4429c00a81bSAdrian Hunter 4437137ff50SDavidlohr Bueso static void symbols__insert_by_name(struct rb_root_cached *symbols, struct symbol *sym) 44479406cd7SArnaldo Carvalho de Melo { 4457137ff50SDavidlohr Bueso struct rb_node **p = &symbols->rb_root.rb_node; 44679406cd7SArnaldo Carvalho de Melo struct rb_node *parent = NULL; 44702a9d037SRabin Vincent struct symbol_name_rb_node *symn, *s; 4487137ff50SDavidlohr Bueso bool leftmost = true; 44902a9d037SRabin Vincent 45002a9d037SRabin Vincent symn = container_of(sym, struct symbol_name_rb_node, sym); 45179406cd7SArnaldo Carvalho de Melo 45279406cd7SArnaldo Carvalho de Melo while (*p != NULL) { 45379406cd7SArnaldo Carvalho de Melo parent = *p; 45479406cd7SArnaldo Carvalho de Melo s = rb_entry(parent, struct symbol_name_rb_node, rb_node); 45579406cd7SArnaldo Carvalho de Melo if (strcmp(sym->name, s->sym.name) < 0) 45679406cd7SArnaldo Carvalho de Melo p = &(*p)->rb_left; 4577137ff50SDavidlohr Bueso else { 45879406cd7SArnaldo Carvalho de Melo p = &(*p)->rb_right; 4597137ff50SDavidlohr Bueso leftmost = false; 4607137ff50SDavidlohr Bueso } 46179406cd7SArnaldo Carvalho de Melo } 46279406cd7SArnaldo Carvalho de Melo rb_link_node(&symn->rb_node, parent, p); 4637137ff50SDavidlohr Bueso rb_insert_color_cached(&symn->rb_node, symbols, leftmost); 46479406cd7SArnaldo Carvalho de Melo } 46579406cd7SArnaldo Carvalho de Melo 4667137ff50SDavidlohr Bueso static void symbols__sort_by_name(struct rb_root_cached *symbols, 4677137ff50SDavidlohr Bueso struct rb_root_cached *source) 46879406cd7SArnaldo Carvalho de Melo { 46979406cd7SArnaldo Carvalho de Melo struct rb_node *nd; 47079406cd7SArnaldo Carvalho de Melo 4717137ff50SDavidlohr Bueso for (nd = rb_first_cached(source); nd; nd = rb_next(nd)) { 47279406cd7SArnaldo Carvalho de Melo struct symbol *pos = rb_entry(nd, struct symbol, rb_node); 473aeafcbafSArnaldo Carvalho de Melo symbols__insert_by_name(symbols, pos); 47479406cd7SArnaldo Carvalho de Melo } 47579406cd7SArnaldo Carvalho de Melo } 47679406cd7SArnaldo Carvalho de Melo 477d8040645SPaul Clarke int symbol__match_symbol_name(const char *name, const char *str, 478d8040645SPaul Clarke enum symbol_tag_include includes) 479d8040645SPaul Clarke { 480d8040645SPaul Clarke const char *versioning; 481d8040645SPaul Clarke 482d8040645SPaul Clarke if (includes == SYMBOL_TAG_INCLUDE__DEFAULT_ONLY && 483d8040645SPaul Clarke (versioning = strstr(name, "@@"))) { 484d8040645SPaul Clarke int len = strlen(str); 485d8040645SPaul Clarke 486d8040645SPaul Clarke if (len < versioning - name) 487d8040645SPaul Clarke len = versioning - name; 488d8040645SPaul Clarke 489d8040645SPaul Clarke return arch__compare_symbol_names_n(name, str, len); 490d8040645SPaul Clarke } else 491d8040645SPaul Clarke return arch__compare_symbol_names(name, str); 492d8040645SPaul Clarke } 493d8040645SPaul Clarke 4947137ff50SDavidlohr Bueso static struct symbol *symbols__find_by_name(struct rb_root_cached *symbols, 495d8040645SPaul Clarke const char *name, 496d8040645SPaul Clarke enum symbol_tag_include includes) 49779406cd7SArnaldo Carvalho de Melo { 49879406cd7SArnaldo Carvalho de Melo struct rb_node *n; 4995bcaaca3SMartin Liška struct symbol_name_rb_node *s = NULL; 50079406cd7SArnaldo Carvalho de Melo 501aeafcbafSArnaldo Carvalho de Melo if (symbols == NULL) 50279406cd7SArnaldo Carvalho de Melo return NULL; 50379406cd7SArnaldo Carvalho de Melo 5047137ff50SDavidlohr Bueso n = symbols->rb_root.rb_node; 50579406cd7SArnaldo Carvalho de Melo 50679406cd7SArnaldo Carvalho de Melo while (n) { 50779406cd7SArnaldo Carvalho de Melo int cmp; 50879406cd7SArnaldo Carvalho de Melo 50979406cd7SArnaldo Carvalho de Melo s = rb_entry(n, struct symbol_name_rb_node, rb_node); 510d8040645SPaul Clarke cmp = symbol__match_symbol_name(s->sym.name, name, includes); 51179406cd7SArnaldo Carvalho de Melo 512d8040645SPaul Clarke if (cmp > 0) 51379406cd7SArnaldo Carvalho de Melo n = n->rb_left; 514d8040645SPaul Clarke else if (cmp < 0) 51579406cd7SArnaldo Carvalho de Melo n = n->rb_right; 51679406cd7SArnaldo Carvalho de Melo else 517de480999SNamhyung Kim break; 51879406cd7SArnaldo Carvalho de Melo } 51979406cd7SArnaldo Carvalho de Melo 520de480999SNamhyung Kim if (n == NULL) 52179406cd7SArnaldo Carvalho de Melo return NULL; 522de480999SNamhyung Kim 523d8040645SPaul Clarke if (includes != SYMBOL_TAG_INCLUDE__DEFAULT_ONLY) 524de480999SNamhyung Kim /* return first symbol that has same name (if any) */ 525de480999SNamhyung Kim for (n = rb_prev(n); n; n = rb_prev(n)) { 526de480999SNamhyung Kim struct symbol_name_rb_node *tmp; 527de480999SNamhyung Kim 528de480999SNamhyung Kim tmp = rb_entry(n, struct symbol_name_rb_node, rb_node); 529031b84c4SNaveen N. Rao if (arch__compare_symbol_names(tmp->sym.name, s->sym.name)) 530de480999SNamhyung Kim break; 531de480999SNamhyung Kim 532de480999SNamhyung Kim s = tmp; 533de480999SNamhyung Kim } 534de480999SNamhyung Kim 535de480999SNamhyung Kim return &s->sym; 53679406cd7SArnaldo Carvalho de Melo } 53779406cd7SArnaldo Carvalho de Melo 538c0b4dffbSArnaldo Carvalho de Melo void dso__reset_find_symbol_cache(struct dso *dso) 539c0b4dffbSArnaldo Carvalho de Melo { 5403183f8caSArnaldo Carvalho de Melo dso->last_find_result.addr = 0; 5413183f8caSArnaldo Carvalho de Melo dso->last_find_result.symbol = NULL; 542c0b4dffbSArnaldo Carvalho de Melo } 543c0b4dffbSArnaldo Carvalho de Melo 5443183f8caSArnaldo Carvalho de Melo void dso__insert_symbol(struct dso *dso, struct symbol *sym) 545ae93a6c7SChris Phlipot { 5463183f8caSArnaldo Carvalho de Melo __symbols__insert(&dso->symbols, sym, dso->kernel); 547ae93a6c7SChris Phlipot 548ae93a6c7SChris Phlipot /* update the symbol cache if necessary */ 5493183f8caSArnaldo Carvalho de Melo if (dso->last_find_result.addr >= sym->start && 5503183f8caSArnaldo Carvalho de Melo (dso->last_find_result.addr < sym->end || 551ae93a6c7SChris Phlipot sym->start == sym->end)) { 5523183f8caSArnaldo Carvalho de Melo dso->last_find_result.symbol = sym; 553ae93a6c7SChris Phlipot } 554ae93a6c7SChris Phlipot } 555ae93a6c7SChris Phlipot 556ab8bf5f2STommi Rantala void dso__delete_symbol(struct dso *dso, struct symbol *sym) 557ab8bf5f2STommi Rantala { 558ab8bf5f2STommi Rantala rb_erase_cached(&sym->rb_node, &dso->symbols); 559ab8bf5f2STommi Rantala symbol__delete(sym); 560ab8bf5f2STommi Rantala dso__reset_find_symbol_cache(dso); 561ab8bf5f2STommi Rantala } 562ab8bf5f2STommi Rantala 5633183f8caSArnaldo Carvalho de Melo struct symbol *dso__find_symbol(struct dso *dso, u64 addr) 564fcf1203aSArnaldo Carvalho de Melo { 5653183f8caSArnaldo Carvalho de Melo if (dso->last_find_result.addr != addr || dso->last_find_result.symbol == NULL) { 5663183f8caSArnaldo Carvalho de Melo dso->last_find_result.addr = addr; 5673183f8caSArnaldo Carvalho de Melo dso->last_find_result.symbol = symbols__find(&dso->symbols, addr); 568b685ac22SArnaldo Carvalho de Melo } 569b685ac22SArnaldo Carvalho de Melo 5703183f8caSArnaldo Carvalho de Melo return dso->last_find_result.symbol; 5718e0cf965SAdrian Hunter } 5728e0cf965SAdrian Hunter 573a2db72c5SAdrian Hunter struct symbol *dso__find_symbol_nocache(struct dso *dso, u64 addr) 574a2db72c5SAdrian Hunter { 575a2db72c5SAdrian Hunter return symbols__find(&dso->symbols, addr); 576a2db72c5SAdrian Hunter } 577a2db72c5SAdrian Hunter 5785cf88a63SArnaldo Carvalho de Melo struct symbol *dso__first_symbol(struct dso *dso) 5795cf88a63SArnaldo Carvalho de Melo { 5803183f8caSArnaldo Carvalho de Melo return symbols__first(&dso->symbols); 581cd67f99fSAdrian Hunter } 582cd67f99fSAdrian Hunter 5835cf88a63SArnaldo Carvalho de Melo struct symbol *dso__last_symbol(struct dso *dso) 5845cf88a63SArnaldo Carvalho de Melo { 5853183f8caSArnaldo Carvalho de Melo return symbols__last(&dso->symbols); 5865cf88a63SArnaldo Carvalho de Melo } 5875cf88a63SArnaldo Carvalho de Melo 5889c00a81bSAdrian Hunter struct symbol *dso__next_symbol(struct symbol *sym) 5899c00a81bSAdrian Hunter { 5909c00a81bSAdrian Hunter return symbols__next(sym); 5919c00a81bSAdrian Hunter } 5929c00a81bSAdrian Hunter 59318bd7264SArnaldo Carvalho de Melo struct symbol *symbol__next_by_name(struct symbol *sym) 59418bd7264SArnaldo Carvalho de Melo { 59518bd7264SArnaldo Carvalho de Melo struct symbol_name_rb_node *s = container_of(sym, struct symbol_name_rb_node, sym); 59618bd7264SArnaldo Carvalho de Melo struct rb_node *n = rb_next(&s->rb_node); 59718bd7264SArnaldo Carvalho de Melo 59818bd7264SArnaldo Carvalho de Melo return n ? &rb_entry(n, struct symbol_name_rb_node, rb_node)->sym : NULL; 59918bd7264SArnaldo Carvalho de Melo } 60018bd7264SArnaldo Carvalho de Melo 60118bd7264SArnaldo Carvalho de Melo /* 602af07eeb0SArnaldo Carvalho de Melo * Returns first symbol that matched with @name. 60318bd7264SArnaldo Carvalho de Melo */ 6043183f8caSArnaldo Carvalho de Melo struct symbol *dso__find_symbol_by_name(struct dso *dso, const char *name) 60579406cd7SArnaldo Carvalho de Melo { 6063183f8caSArnaldo Carvalho de Melo struct symbol *s = symbols__find_by_name(&dso->symbol_names, name, 607d8040645SPaul Clarke SYMBOL_TAG_INCLUDE__NONE); 608d8040645SPaul Clarke if (!s) 6093183f8caSArnaldo Carvalho de Melo s = symbols__find_by_name(&dso->symbol_names, name, 610d8040645SPaul Clarke SYMBOL_TAG_INCLUDE__DEFAULT_ONLY); 611d8040645SPaul Clarke return s; 61279406cd7SArnaldo Carvalho de Melo } 61379406cd7SArnaldo Carvalho de Melo 6143183f8caSArnaldo Carvalho de Melo void dso__sort_by_name(struct dso *dso) 61579406cd7SArnaldo Carvalho de Melo { 6163183f8caSArnaldo Carvalho de Melo dso__set_sorted_by_name(dso); 6173183f8caSArnaldo Carvalho de Melo return symbols__sort_by_name(&dso->symbol_names, &dso->symbols); 61879406cd7SArnaldo Carvalho de Melo } 61979406cd7SArnaldo Carvalho de Melo 62032add10fSIan Rogers /* 62132add10fSIan Rogers * While we find nice hex chars, build a long_val. 62232add10fSIan Rogers * Return number of chars processed. 62332add10fSIan Rogers */ 62432add10fSIan Rogers static int hex2u64(const char *ptr, u64 *long_val) 62532add10fSIan Rogers { 62632add10fSIan Rogers char *p; 62732add10fSIan Rogers 62832add10fSIan Rogers *long_val = strtoull(ptr, &p, 16); 62932add10fSIan Rogers 63032add10fSIan Rogers return p - ptr; 63132add10fSIan Rogers } 63232add10fSIan Rogers 63332add10fSIan Rogers 634316d70d6SAdrian Hunter int modules__parse(const char *filename, void *arg, 635316d70d6SAdrian Hunter int (*process_module)(void *arg, const char *name, 6369ad4652bSThomas Richter u64 start, u64 size)) 637316d70d6SAdrian Hunter { 638316d70d6SAdrian Hunter char *line = NULL; 639316d70d6SAdrian Hunter size_t n; 640316d70d6SAdrian Hunter FILE *file; 641316d70d6SAdrian Hunter int err = 0; 642316d70d6SAdrian Hunter 643316d70d6SAdrian Hunter file = fopen(filename, "r"); 644316d70d6SAdrian Hunter if (file == NULL) 645316d70d6SAdrian Hunter return -1; 646316d70d6SAdrian Hunter 647316d70d6SAdrian Hunter while (1) { 648316d70d6SAdrian Hunter char name[PATH_MAX]; 6499ad4652bSThomas Richter u64 start, size; 6509ad4652bSThomas Richter char *sep, *endptr; 651316d70d6SAdrian Hunter ssize_t line_len; 652316d70d6SAdrian Hunter 653316d70d6SAdrian Hunter line_len = getline(&line, &n, file); 654316d70d6SAdrian Hunter if (line_len < 0) { 655316d70d6SAdrian Hunter if (feof(file)) 656316d70d6SAdrian Hunter break; 657316d70d6SAdrian Hunter err = -1; 658316d70d6SAdrian Hunter goto out; 659316d70d6SAdrian Hunter } 660316d70d6SAdrian Hunter 661316d70d6SAdrian Hunter if (!line) { 662316d70d6SAdrian Hunter err = -1; 663316d70d6SAdrian Hunter goto out; 664316d70d6SAdrian Hunter } 665316d70d6SAdrian Hunter 666316d70d6SAdrian Hunter line[--line_len] = '\0'; /* \n */ 667316d70d6SAdrian Hunter 668316d70d6SAdrian Hunter sep = strrchr(line, 'x'); 669316d70d6SAdrian Hunter if (sep == NULL) 670316d70d6SAdrian Hunter continue; 671316d70d6SAdrian Hunter 672316d70d6SAdrian Hunter hex2u64(sep + 1, &start); 673316d70d6SAdrian Hunter 674316d70d6SAdrian Hunter sep = strchr(line, ' '); 675316d70d6SAdrian Hunter if (sep == NULL) 676316d70d6SAdrian Hunter continue; 677316d70d6SAdrian Hunter 678316d70d6SAdrian Hunter *sep = '\0'; 679316d70d6SAdrian Hunter 680316d70d6SAdrian Hunter scnprintf(name, sizeof(name), "[%s]", line); 681316d70d6SAdrian Hunter 6829ad4652bSThomas Richter size = strtoul(sep + 1, &endptr, 0); 6839ad4652bSThomas Richter if (*endptr != ' ' && *endptr != '\t') 6849ad4652bSThomas Richter continue; 6859ad4652bSThomas Richter 6869ad4652bSThomas Richter err = process_module(arg, name, start, size); 687316d70d6SAdrian Hunter if (err) 688316d70d6SAdrian Hunter break; 689316d70d6SAdrian Hunter } 690316d70d6SAdrian Hunter out: 691316d70d6SAdrian Hunter free(line); 692316d70d6SAdrian Hunter fclose(file); 693316d70d6SAdrian Hunter return err; 694316d70d6SAdrian Hunter } 695316d70d6SAdrian Hunter 696e7110b9fSArnaldo Carvalho de Melo /* 697e7110b9fSArnaldo Carvalho de Melo * These are symbols in the kernel image, so make sure that 698e7110b9fSArnaldo Carvalho de Melo * sym is from a kernel DSO. 699e7110b9fSArnaldo Carvalho de Melo */ 700608c34deSArnaldo Carvalho de Melo static bool symbol__is_idle(const char *name) 70182d1deb0SDavid Ahern { 70282d1deb0SDavid Ahern const char * const idle_symbols[] = { 7030e71459aSKim Phillips "acpi_idle_do_entry", 7040e71459aSKim Phillips "acpi_processor_ffh_cstate_enter", 705549aff77SArnaldo Carvalho de Melo "arch_cpu_idle", 70682d1deb0SDavid Ahern "cpu_idle", 707e0336ed6SArnaldo Carvalho de Melo "cpu_startup_entry", 7080e71459aSKim Phillips "idle_cpu", 70982d1deb0SDavid Ahern "intel_idle", 71082d1deb0SDavid Ahern "default_idle", 71182d1deb0SDavid Ahern "native_safe_halt", 71282d1deb0SDavid Ahern "enter_idle", 71382d1deb0SDavid Ahern "exit_idle", 71482d1deb0SDavid Ahern "mwait_idle", 71582d1deb0SDavid Ahern "mwait_idle_with_hints", 716783abbd4SArnaldo Carvalho de Melo "mwait_idle_with_hints.constprop.0", 71782d1deb0SDavid Ahern "poll_idle", 71882d1deb0SDavid Ahern "ppc64_runlatch_off", 71982d1deb0SDavid Ahern "pseries_dedicated_idle_sleep", 72019bf119cSSven Schnelle "psw_idle", 72119bf119cSSven Schnelle "psw_idle_exit", 72282d1deb0SDavid Ahern NULL 72382d1deb0SDavid Ahern }; 72482d1deb0SDavid Ahern int i; 725bc5f15beSKim Phillips static struct strlist *idle_symbols_list; 72682d1deb0SDavid Ahern 727bc5f15beSKim Phillips if (idle_symbols_list) 728bc5f15beSKim Phillips return strlist__has_entry(idle_symbols_list, name); 72982d1deb0SDavid Ahern 730bc5f15beSKim Phillips idle_symbols_list = strlist__new(NULL, NULL); 731bc5f15beSKim Phillips 732bc5f15beSKim Phillips for (i = 0; idle_symbols[i]; i++) 733bc5f15beSKim Phillips strlist__add(idle_symbols_list, idle_symbols[i]); 734bc5f15beSKim Phillips 735bc5f15beSKim Phillips return strlist__has_entry(idle_symbols_list, name); 73682d1deb0SDavid Ahern } 73782d1deb0SDavid Ahern 738682b335aSArnaldo Carvalho de Melo static int map__process_kallsym_symbol(void *arg, const char *name, 73982151520SCody P Schafer char type, u64 start) 740682b335aSArnaldo Carvalho de Melo { 741682b335aSArnaldo Carvalho de Melo struct symbol *sym; 742333cc76cSArnaldo Carvalho de Melo struct dso *dso = arg; 7437137ff50SDavidlohr Bueso struct rb_root_cached *root = &dso->symbols; 744682b335aSArnaldo Carvalho de Melo 7453183f8caSArnaldo Carvalho de Melo if (!symbol_type__filter(type)) 746682b335aSArnaldo Carvalho de Melo return 0; 747682b335aSArnaldo Carvalho de Melo 7481a86f4baSLexi Shao /* Ignore local symbols for ARM modules */ 7491a86f4baSLexi Shao if (name[0] == '$') 7501a86f4baSLexi Shao return 0; 7511a86f4baSLexi Shao 75282151520SCody P Schafer /* 75382151520SCody P Schafer * module symbols are not sorted so we add all 75482151520SCody P Schafer * symbols, setting length to 0, and rely on 75582151520SCody P Schafer * symbols__fixup_end() to fix it up. 75682151520SCody P Schafer */ 757af30bffaSArnaldo Carvalho de Melo sym = symbol__new(start, 0, kallsyms2elf_binding(type), kallsyms2elf_type(type), name); 7582e538c4aSArnaldo Carvalho de Melo if (sym == NULL) 759682b335aSArnaldo Carvalho de Melo return -ENOMEM; 76082164161SArnaldo Carvalho de Melo /* 76182164161SArnaldo Carvalho de Melo * We will pass the symbols to the filter later, in 7624e06255fSArnaldo Carvalho de Melo * map__split_kallsyms, when we have split the maps per module 76382164161SArnaldo Carvalho de Melo */ 764608c34deSArnaldo Carvalho de Melo __symbols__insert(root, sym, !strchr(name, '[')); 765a1645ce1SZhang, Yanmin 766682b335aSArnaldo Carvalho de Melo return 0; 7672e538c4aSArnaldo Carvalho de Melo } 7682e538c4aSArnaldo Carvalho de Melo 769682b335aSArnaldo Carvalho de Melo /* 770682b335aSArnaldo Carvalho de Melo * Loads the function entries in /proc/kallsyms into kernel_map->dso, 771682b335aSArnaldo Carvalho de Melo * so that we can in the next step set the symbol ->end address and then 772682b335aSArnaldo Carvalho de Melo * call kernel_maps__split_kallsyms. 773682b335aSArnaldo Carvalho de Melo */ 774333cc76cSArnaldo Carvalho de Melo static int dso__load_all_kallsyms(struct dso *dso, const char *filename) 775682b335aSArnaldo Carvalho de Melo { 776333cc76cSArnaldo Carvalho de Melo return kallsyms__parse(filename, dso, map__process_kallsym_symbol); 7772e538c4aSArnaldo Carvalho de Melo } 7782e538c4aSArnaldo Carvalho de Melo 77979b6bb73SArnaldo Carvalho de Melo static int maps__split_kallsyms_for_kcore(struct maps *kmaps, struct dso *dso) 7808e0cf965SAdrian Hunter { 7818e0cf965SAdrian Hunter struct map *curr_map; 7828e0cf965SAdrian Hunter struct symbol *pos; 783866548ddSAdrian Hunter int count = 0; 7847137ff50SDavidlohr Bueso struct rb_root_cached old_root = dso->symbols; 7857137ff50SDavidlohr Bueso struct rb_root_cached *root = &dso->symbols; 7867137ff50SDavidlohr Bueso struct rb_node *next = rb_first_cached(root); 7878e0cf965SAdrian Hunter 788ba92732eSWang Nan if (!kmaps) 789ba92732eSWang Nan return -1; 790ba92732eSWang Nan 7917137ff50SDavidlohr Bueso *root = RB_ROOT_CACHED; 792866548ddSAdrian Hunter 7938e0cf965SAdrian Hunter while (next) { 79463df0e4bSIan Rogers struct dso *curr_map_dso; 7958e0cf965SAdrian Hunter char *module; 7968e0cf965SAdrian Hunter 7978e0cf965SAdrian Hunter pos = rb_entry(next, struct symbol, rb_node); 7988e0cf965SAdrian Hunter next = rb_next(&pos->rb_node); 7998e0cf965SAdrian Hunter 8007137ff50SDavidlohr Bueso rb_erase_cached(&pos->rb_node, &old_root); 8017137ff50SDavidlohr Bueso RB_CLEAR_NODE(&pos->rb_node); 8028e0cf965SAdrian Hunter module = strchr(pos->name, '\t'); 8038e0cf965SAdrian Hunter if (module) 8048e0cf965SAdrian Hunter *module = '\0'; 8058e0cf965SAdrian Hunter 80679b6bb73SArnaldo Carvalho de Melo curr_map = maps__find(kmaps, pos->start); 8078e0cf965SAdrian Hunter 808be39db9fSArnaldo Carvalho de Melo if (!curr_map) { 8098e0cf965SAdrian Hunter symbol__delete(pos); 810866548ddSAdrian Hunter continue; 811866548ddSAdrian Hunter } 81263df0e4bSIan Rogers curr_map_dso = map__dso(curr_map); 8132a6e5e8aSIan Rogers pos->start -= map__start(curr_map) - map__pgoff(curr_map); 814e5116f46SIan Rogers if (pos->end > map__end(curr_map)) 815e5116f46SIan Rogers pos->end = map__end(curr_map); 8168e0cf965SAdrian Hunter if (pos->end) 8172a6e5e8aSIan Rogers pos->end -= map__start(curr_map) - map__pgoff(curr_map); 81863df0e4bSIan Rogers symbols__insert(&curr_map_dso->symbols, pos); 8198e0cf965SAdrian Hunter ++count; 8208e0cf965SAdrian Hunter } 8218e0cf965SAdrian Hunter 8228e0cf965SAdrian Hunter /* Symbols have been adjusted */ 8238e0cf965SAdrian Hunter dso->adjust_symbols = 1; 8248e0cf965SAdrian Hunter 825866548ddSAdrian Hunter return count; 8268e0cf965SAdrian Hunter } 8278e0cf965SAdrian Hunter 8282e538c4aSArnaldo Carvalho de Melo /* 8292e538c4aSArnaldo Carvalho de Melo * Split the symbols into maps, making sure there are no overlaps, i.e. the 8302e538c4aSArnaldo Carvalho de Melo * kernel range is broken in several maps, named [kernel].N, as we don't have 8312e538c4aSArnaldo Carvalho de Melo * the original ELF section names vmlinux have. 8322e538c4aSArnaldo Carvalho de Melo */ 83379b6bb73SArnaldo Carvalho de Melo static int maps__split_kallsyms(struct maps *kmaps, struct dso *dso, u64 delta, 83415e0e2d4SArnaldo Carvalho de Melo struct map *initial_map) 8352e538c4aSArnaldo Carvalho de Melo { 836ba92732eSWang Nan struct machine *machine; 83715e0e2d4SArnaldo Carvalho de Melo struct map *curr_map = initial_map; 8382e538c4aSArnaldo Carvalho de Melo struct symbol *pos; 8398a953312SArnaldo Carvalho de Melo int count = 0, moved = 0; 8407137ff50SDavidlohr Bueso struct rb_root_cached *root = &dso->symbols; 8417137ff50SDavidlohr Bueso struct rb_node *next = rb_first_cached(root); 8422e538c4aSArnaldo Carvalho de Melo int kernel_range = 0; 8434d004365SAdrian Hunter bool x86_64; 8442e538c4aSArnaldo Carvalho de Melo 845ba92732eSWang Nan if (!kmaps) 846ba92732eSWang Nan return -1; 847ba92732eSWang Nan 8485ab6d715SIan Rogers machine = maps__machine(kmaps); 849ba92732eSWang Nan 8504d004365SAdrian Hunter x86_64 = machine__is(machine, "x86_64"); 8514d004365SAdrian Hunter 8522e538c4aSArnaldo Carvalho de Melo while (next) { 8532e538c4aSArnaldo Carvalho de Melo char *module; 8542e538c4aSArnaldo Carvalho de Melo 8552e538c4aSArnaldo Carvalho de Melo pos = rb_entry(next, struct symbol, rb_node); 8562e538c4aSArnaldo Carvalho de Melo next = rb_next(&pos->rb_node); 8572e538c4aSArnaldo Carvalho de Melo 8582e538c4aSArnaldo Carvalho de Melo module = strchr(pos->name, '\t'); 8592e538c4aSArnaldo Carvalho de Melo if (module) { 86063df0e4bSIan Rogers struct dso *curr_map_dso; 86163df0e4bSIan Rogers 86275be6cf4SArnaldo Carvalho de Melo if (!symbol_conf.use_modules) 8631de8e245SArnaldo Carvalho de Melo goto discard_symbol; 8641de8e245SArnaldo Carvalho de Melo 8652e538c4aSArnaldo Carvalho de Melo *module++ = '\0'; 86663df0e4bSIan Rogers curr_map_dso = map__dso(curr_map); 86763df0e4bSIan Rogers if (strcmp(curr_map_dso->short_name, module)) { 86815e0e2d4SArnaldo Carvalho de Melo if (curr_map != initial_map && 8691c695c88SJiri Olsa dso->kernel == DSO_SPACE__KERNEL_GUEST && 87023346f21SArnaldo Carvalho de Melo machine__is_default_guest(machine)) { 871a1645ce1SZhang, Yanmin /* 872a1645ce1SZhang, Yanmin * We assume all symbols of a module are 873a1645ce1SZhang, Yanmin * continuous in * kallsyms, so curr_map 874a1645ce1SZhang, Yanmin * points to a module and all its 875a1645ce1SZhang, Yanmin * symbols are in its kmap. Mark it as 876a1645ce1SZhang, Yanmin * loaded. 877a1645ce1SZhang, Yanmin */ 87863df0e4bSIan Rogers dso__set_loaded(curr_map_dso); 879af427bf5SArnaldo Carvalho de Melo } 880b7cece76SArnaldo Carvalho de Melo 88179b6bb73SArnaldo Carvalho de Melo curr_map = maps__find_by_name(kmaps, module); 882a1645ce1SZhang, Yanmin if (curr_map == NULL) { 8832f51903bSArnaldo Carvalho de Melo pr_debug("%s/proc/{kallsyms,modules} " 884a1645ce1SZhang, Yanmin "inconsistency while looking " 885a1645ce1SZhang, Yanmin "for \"%s\" module!\n", 88623346f21SArnaldo Carvalho de Melo machine->root_dir, module); 88715e0e2d4SArnaldo Carvalho de Melo curr_map = initial_map; 888a1645ce1SZhang, Yanmin goto discard_symbol; 889a1645ce1SZhang, Yanmin } 89063df0e4bSIan Rogers curr_map_dso = map__dso(curr_map); 89163df0e4bSIan Rogers if (curr_map_dso->loaded && 89223346f21SArnaldo Carvalho de Melo !machine__is_default_guest(machine)) 893b7cece76SArnaldo Carvalho de Melo goto discard_symbol; 894af427bf5SArnaldo Carvalho de Melo } 89586470930SIngo Molnar /* 8962e538c4aSArnaldo Carvalho de Melo * So that we look just like we get from .ko files, 89715e0e2d4SArnaldo Carvalho de Melo * i.e. not prelinked, relative to initial_map->start. 89886470930SIngo Molnar */ 89978a1f7cdSIan Rogers pos->start = map__map_ip(curr_map, pos->start); 90078a1f7cdSIan Rogers pos->end = map__map_ip(curr_map, pos->end); 9014d004365SAdrian Hunter } else if (x86_64 && is_entry_trampoline(pos->name)) { 9024d004365SAdrian Hunter /* 9034d004365SAdrian Hunter * These symbols are not needed anymore since the 9044d004365SAdrian Hunter * trampoline maps refer to the text section and it's 9054d004365SAdrian Hunter * symbols instead. Avoid having to deal with 9064d004365SAdrian Hunter * relocations, and the assumption that the first symbol 9074d004365SAdrian Hunter * is the start of kernel text, by simply removing the 9084d004365SAdrian Hunter * symbols at this point. 9094d004365SAdrian Hunter */ 9104d004365SAdrian Hunter goto discard_symbol; 91115e0e2d4SArnaldo Carvalho de Melo } else if (curr_map != initial_map) { 9122e538c4aSArnaldo Carvalho de Melo char dso_name[PATH_MAX]; 913aeafcbafSArnaldo Carvalho de Melo struct dso *ndso; 91486470930SIngo Molnar 915d9b62abaSAdrian Hunter if (delta) { 916d9b62abaSAdrian Hunter /* Kernel was relocated at boot time */ 917d9b62abaSAdrian Hunter pos->start -= delta; 918d9b62abaSAdrian Hunter pos->end -= delta; 919d9b62abaSAdrian Hunter } 920d9b62abaSAdrian Hunter 9218a953312SArnaldo Carvalho de Melo if (count == 0) { 92215e0e2d4SArnaldo Carvalho de Melo curr_map = initial_map; 923be39db9fSArnaldo Carvalho de Melo goto add_symbol; 9248a953312SArnaldo Carvalho de Melo } 9258a953312SArnaldo Carvalho de Melo 9261c695c88SJiri Olsa if (dso->kernel == DSO_SPACE__KERNEL_GUEST) 927a1645ce1SZhang, Yanmin snprintf(dso_name, sizeof(dso_name), 928a1645ce1SZhang, Yanmin "[guest.kernel].%d", 929a1645ce1SZhang, Yanmin kernel_range++); 930a1645ce1SZhang, Yanmin else 931a1645ce1SZhang, Yanmin snprintf(dso_name, sizeof(dso_name), 932a1645ce1SZhang, Yanmin "[kernel].%d", 9332e538c4aSArnaldo Carvalho de Melo kernel_range++); 93486470930SIngo Molnar 935aeafcbafSArnaldo Carvalho de Melo ndso = dso__new(dso_name); 936aeafcbafSArnaldo Carvalho de Melo if (ndso == NULL) 9372e538c4aSArnaldo Carvalho de Melo return -1; 9382e538c4aSArnaldo Carvalho de Melo 939aeafcbafSArnaldo Carvalho de Melo ndso->kernel = dso->kernel; 940a1645ce1SZhang, Yanmin 9413183f8caSArnaldo Carvalho de Melo curr_map = map__new2(pos->start, ndso); 94237fe5fcbSZhang, Yanmin if (curr_map == NULL) { 943d3a7c489SArnaldo Carvalho de Melo dso__put(ndso); 9442e538c4aSArnaldo Carvalho de Melo return -1; 9452e538c4aSArnaldo Carvalho de Melo } 9462e538c4aSArnaldo Carvalho de Melo 9474e06255fSArnaldo Carvalho de Melo curr_map->map_ip = curr_map->unmap_ip = identity__map_ip; 948ff583dc4SIan Rogers if (maps__insert(kmaps, curr_map)) { 949ff583dc4SIan Rogers dso__put(ndso); 950ff583dc4SIan Rogers return -1; 951ff583dc4SIan Rogers } 9522e538c4aSArnaldo Carvalho de Melo ++kernel_range; 953d9b62abaSAdrian Hunter } else if (delta) { 954d9b62abaSAdrian Hunter /* Kernel was relocated at boot time */ 955d9b62abaSAdrian Hunter pos->start -= delta; 956d9b62abaSAdrian Hunter pos->end -= delta; 9572e538c4aSArnaldo Carvalho de Melo } 958be39db9fSArnaldo Carvalho de Melo add_symbol: 95915e0e2d4SArnaldo Carvalho de Melo if (curr_map != initial_map) { 96063df0e4bSIan Rogers struct dso *curr_map_dso = map__dso(curr_map); 96163df0e4bSIan Rogers 9627137ff50SDavidlohr Bueso rb_erase_cached(&pos->rb_node, root); 96363df0e4bSIan Rogers symbols__insert(&curr_map_dso->symbols, pos); 9648a953312SArnaldo Carvalho de Melo ++moved; 9658a953312SArnaldo Carvalho de Melo } else 9668a953312SArnaldo Carvalho de Melo ++count; 967be39db9fSArnaldo Carvalho de Melo 968be39db9fSArnaldo Carvalho de Melo continue; 969be39db9fSArnaldo Carvalho de Melo discard_symbol: 9707137ff50SDavidlohr Bueso rb_erase_cached(&pos->rb_node, root); 971be39db9fSArnaldo Carvalho de Melo symbol__delete(pos); 97286470930SIngo Molnar } 97386470930SIngo Molnar 97415e0e2d4SArnaldo Carvalho de Melo if (curr_map != initial_map && 9751c695c88SJiri Olsa dso->kernel == DSO_SPACE__KERNEL_GUEST && 9765ab6d715SIan Rogers machine__is_default_guest(maps__machine(kmaps))) { 97763df0e4bSIan Rogers dso__set_loaded(map__dso(curr_map)); 978a1645ce1SZhang, Yanmin } 979a1645ce1SZhang, Yanmin 9808a953312SArnaldo Carvalho de Melo return count + moved; 98186470930SIngo Molnar } 98286470930SIngo Molnar 9833f067dcaSArnaldo Carvalho de Melo bool symbol__restricted_filename(const char *filename, 984ec80fde7SArnaldo Carvalho de Melo const char *restricted_filename) 985ec80fde7SArnaldo Carvalho de Melo { 986ec80fde7SArnaldo Carvalho de Melo bool restricted = false; 987ec80fde7SArnaldo Carvalho de Melo 988ec80fde7SArnaldo Carvalho de Melo if (symbol_conf.kptr_restrict) { 989ec80fde7SArnaldo Carvalho de Melo char *r = realpath(filename, NULL); 990ec80fde7SArnaldo Carvalho de Melo 991ec80fde7SArnaldo Carvalho de Melo if (r != NULL) { 992ec80fde7SArnaldo Carvalho de Melo restricted = strcmp(r, restricted_filename) == 0; 993ec80fde7SArnaldo Carvalho de Melo free(r); 994ec80fde7SArnaldo Carvalho de Melo return restricted; 995ec80fde7SArnaldo Carvalho de Melo } 996ec80fde7SArnaldo Carvalho de Melo } 997ec80fde7SArnaldo Carvalho de Melo 998ec80fde7SArnaldo Carvalho de Melo return restricted; 999ec80fde7SArnaldo Carvalho de Melo } 1000ec80fde7SArnaldo Carvalho de Melo 100152afdaf9SAdrian Hunter struct module_info { 100252afdaf9SAdrian Hunter struct rb_node rb_node; 100352afdaf9SAdrian Hunter char *name; 100452afdaf9SAdrian Hunter u64 start; 100552afdaf9SAdrian Hunter }; 100652afdaf9SAdrian Hunter 100752afdaf9SAdrian Hunter static void add_module(struct module_info *mi, struct rb_root *modules) 100852afdaf9SAdrian Hunter { 100952afdaf9SAdrian Hunter struct rb_node **p = &modules->rb_node; 101052afdaf9SAdrian Hunter struct rb_node *parent = NULL; 101152afdaf9SAdrian Hunter struct module_info *m; 101252afdaf9SAdrian Hunter 101352afdaf9SAdrian Hunter while (*p != NULL) { 101452afdaf9SAdrian Hunter parent = *p; 101552afdaf9SAdrian Hunter m = rb_entry(parent, struct module_info, rb_node); 101652afdaf9SAdrian Hunter if (strcmp(mi->name, m->name) < 0) 101752afdaf9SAdrian Hunter p = &(*p)->rb_left; 101852afdaf9SAdrian Hunter else 101952afdaf9SAdrian Hunter p = &(*p)->rb_right; 102052afdaf9SAdrian Hunter } 102152afdaf9SAdrian Hunter rb_link_node(&mi->rb_node, parent, p); 102252afdaf9SAdrian Hunter rb_insert_color(&mi->rb_node, modules); 102352afdaf9SAdrian Hunter } 102452afdaf9SAdrian Hunter 102552afdaf9SAdrian Hunter static void delete_modules(struct rb_root *modules) 102652afdaf9SAdrian Hunter { 102752afdaf9SAdrian Hunter struct module_info *mi; 102852afdaf9SAdrian Hunter struct rb_node *next = rb_first(modules); 102952afdaf9SAdrian Hunter 103052afdaf9SAdrian Hunter while (next) { 103152afdaf9SAdrian Hunter mi = rb_entry(next, struct module_info, rb_node); 103252afdaf9SAdrian Hunter next = rb_next(&mi->rb_node); 103352afdaf9SAdrian Hunter rb_erase(&mi->rb_node, modules); 103474cf249dSArnaldo Carvalho de Melo zfree(&mi->name); 103552afdaf9SAdrian Hunter free(mi); 103652afdaf9SAdrian Hunter } 103752afdaf9SAdrian Hunter } 103852afdaf9SAdrian Hunter 103952afdaf9SAdrian Hunter static struct module_info *find_module(const char *name, 104052afdaf9SAdrian Hunter struct rb_root *modules) 104152afdaf9SAdrian Hunter { 104252afdaf9SAdrian Hunter struct rb_node *n = modules->rb_node; 104352afdaf9SAdrian Hunter 104452afdaf9SAdrian Hunter while (n) { 104552afdaf9SAdrian Hunter struct module_info *m; 104652afdaf9SAdrian Hunter int cmp; 104752afdaf9SAdrian Hunter 104852afdaf9SAdrian Hunter m = rb_entry(n, struct module_info, rb_node); 104952afdaf9SAdrian Hunter cmp = strcmp(name, m->name); 105052afdaf9SAdrian Hunter if (cmp < 0) 105152afdaf9SAdrian Hunter n = n->rb_left; 105252afdaf9SAdrian Hunter else if (cmp > 0) 105352afdaf9SAdrian Hunter n = n->rb_right; 105452afdaf9SAdrian Hunter else 105552afdaf9SAdrian Hunter return m; 105652afdaf9SAdrian Hunter } 105752afdaf9SAdrian Hunter 105852afdaf9SAdrian Hunter return NULL; 105952afdaf9SAdrian Hunter } 106052afdaf9SAdrian Hunter 10619ad4652bSThomas Richter static int __read_proc_modules(void *arg, const char *name, u64 start, 10629ad4652bSThomas Richter u64 size __maybe_unused) 106352afdaf9SAdrian Hunter { 106452afdaf9SAdrian Hunter struct rb_root *modules = arg; 106552afdaf9SAdrian Hunter struct module_info *mi; 106652afdaf9SAdrian Hunter 106752afdaf9SAdrian Hunter mi = zalloc(sizeof(struct module_info)); 106852afdaf9SAdrian Hunter if (!mi) 106952afdaf9SAdrian Hunter return -ENOMEM; 107052afdaf9SAdrian Hunter 107152afdaf9SAdrian Hunter mi->name = strdup(name); 107252afdaf9SAdrian Hunter mi->start = start; 107352afdaf9SAdrian Hunter 107452afdaf9SAdrian Hunter if (!mi->name) { 107552afdaf9SAdrian Hunter free(mi); 107652afdaf9SAdrian Hunter return -ENOMEM; 107752afdaf9SAdrian Hunter } 107852afdaf9SAdrian Hunter 107952afdaf9SAdrian Hunter add_module(mi, modules); 108052afdaf9SAdrian Hunter 108152afdaf9SAdrian Hunter return 0; 108252afdaf9SAdrian Hunter } 108352afdaf9SAdrian Hunter 108452afdaf9SAdrian Hunter static int read_proc_modules(const char *filename, struct rb_root *modules) 108552afdaf9SAdrian Hunter { 108652afdaf9SAdrian Hunter if (symbol__restricted_filename(filename, "/proc/modules")) 108752afdaf9SAdrian Hunter return -1; 108852afdaf9SAdrian Hunter 108952afdaf9SAdrian Hunter if (modules__parse(filename, modules, __read_proc_modules)) { 109052afdaf9SAdrian Hunter delete_modules(modules); 109152afdaf9SAdrian Hunter return -1; 109252afdaf9SAdrian Hunter } 109352afdaf9SAdrian Hunter 109452afdaf9SAdrian Hunter return 0; 109552afdaf9SAdrian Hunter } 109652afdaf9SAdrian Hunter 1097fc1b691dSAdrian Hunter int compare_proc_modules(const char *from, const char *to) 1098fc1b691dSAdrian Hunter { 1099fc1b691dSAdrian Hunter struct rb_root from_modules = RB_ROOT; 1100fc1b691dSAdrian Hunter struct rb_root to_modules = RB_ROOT; 1101fc1b691dSAdrian Hunter struct rb_node *from_node, *to_node; 1102fc1b691dSAdrian Hunter struct module_info *from_m, *to_m; 1103fc1b691dSAdrian Hunter int ret = -1; 1104fc1b691dSAdrian Hunter 1105fc1b691dSAdrian Hunter if (read_proc_modules(from, &from_modules)) 1106fc1b691dSAdrian Hunter return -1; 1107fc1b691dSAdrian Hunter 1108fc1b691dSAdrian Hunter if (read_proc_modules(to, &to_modules)) 1109fc1b691dSAdrian Hunter goto out_delete_from; 1110fc1b691dSAdrian Hunter 1111fc1b691dSAdrian Hunter from_node = rb_first(&from_modules); 1112fc1b691dSAdrian Hunter to_node = rb_first(&to_modules); 1113fc1b691dSAdrian Hunter while (from_node) { 1114fc1b691dSAdrian Hunter if (!to_node) 1115fc1b691dSAdrian Hunter break; 1116fc1b691dSAdrian Hunter 1117fc1b691dSAdrian Hunter from_m = rb_entry(from_node, struct module_info, rb_node); 1118fc1b691dSAdrian Hunter to_m = rb_entry(to_node, struct module_info, rb_node); 1119fc1b691dSAdrian Hunter 1120fc1b691dSAdrian Hunter if (from_m->start != to_m->start || 1121fc1b691dSAdrian Hunter strcmp(from_m->name, to_m->name)) 1122fc1b691dSAdrian Hunter break; 1123fc1b691dSAdrian Hunter 1124fc1b691dSAdrian Hunter from_node = rb_next(from_node); 1125fc1b691dSAdrian Hunter to_node = rb_next(to_node); 1126fc1b691dSAdrian Hunter } 1127fc1b691dSAdrian Hunter 1128fc1b691dSAdrian Hunter if (!from_node && !to_node) 1129fc1b691dSAdrian Hunter ret = 0; 1130fc1b691dSAdrian Hunter 1131fc1b691dSAdrian Hunter delete_modules(&to_modules); 1132fc1b691dSAdrian Hunter out_delete_from: 1133fc1b691dSAdrian Hunter delete_modules(&from_modules); 1134fc1b691dSAdrian Hunter 1135fc1b691dSAdrian Hunter return ret; 1136fc1b691dSAdrian Hunter } 1137fc1b691dSAdrian Hunter 113879b6bb73SArnaldo Carvalho de Melo static int do_validate_kcore_modules(const char *filename, struct maps *kmaps) 113952afdaf9SAdrian Hunter { 114052afdaf9SAdrian Hunter struct rb_root modules = RB_ROOT; 1141ff583dc4SIan Rogers struct map_rb_node *old_node; 114252afdaf9SAdrian Hunter int err; 114352afdaf9SAdrian Hunter 114452afdaf9SAdrian Hunter err = read_proc_modules(filename, &modules); 114552afdaf9SAdrian Hunter if (err) 114652afdaf9SAdrian Hunter return err; 114752afdaf9SAdrian Hunter 1148ff583dc4SIan Rogers maps__for_each_entry(kmaps, old_node) { 1149ff583dc4SIan Rogers struct map *old_map = old_node->map; 115052afdaf9SAdrian Hunter struct module_info *mi; 115163df0e4bSIan Rogers struct dso *dso; 115252afdaf9SAdrian Hunter 11535759a682SAdrian Hunter if (!__map__is_kmodule(old_map)) { 115452afdaf9SAdrian Hunter continue; 115552afdaf9SAdrian Hunter } 115663df0e4bSIan Rogers dso = map__dso(old_map); 115752afdaf9SAdrian Hunter /* Module must be in memory at the same address */ 115863df0e4bSIan Rogers mi = find_module(dso->short_name, &modules); 1159e5116f46SIan Rogers if (!mi || mi->start != map__start(old_map)) { 116052afdaf9SAdrian Hunter err = -EINVAL; 116152afdaf9SAdrian Hunter goto out; 116252afdaf9SAdrian Hunter } 116352afdaf9SAdrian Hunter } 116452afdaf9SAdrian Hunter out: 116552afdaf9SAdrian Hunter delete_modules(&modules); 116652afdaf9SAdrian Hunter return err; 116752afdaf9SAdrian Hunter } 116852afdaf9SAdrian Hunter 116952afdaf9SAdrian Hunter /* 117052afdaf9SAdrian Hunter * If kallsyms is referenced by name then we look for filename in the same 117152afdaf9SAdrian Hunter * directory. 117252afdaf9SAdrian Hunter */ 117352afdaf9SAdrian Hunter static bool filename_from_kallsyms_filename(char *filename, 117452afdaf9SAdrian Hunter const char *base_name, 117552afdaf9SAdrian Hunter const char *kallsyms_filename) 117652afdaf9SAdrian Hunter { 117752afdaf9SAdrian Hunter char *name; 117852afdaf9SAdrian Hunter 117952afdaf9SAdrian Hunter strcpy(filename, kallsyms_filename); 118052afdaf9SAdrian Hunter name = strrchr(filename, '/'); 118152afdaf9SAdrian Hunter if (!name) 118252afdaf9SAdrian Hunter return false; 118352afdaf9SAdrian Hunter 118452afdaf9SAdrian Hunter name += 1; 118552afdaf9SAdrian Hunter 118652afdaf9SAdrian Hunter if (!strcmp(name, "kallsyms")) { 118752afdaf9SAdrian Hunter strcpy(name, base_name); 118852afdaf9SAdrian Hunter return true; 118952afdaf9SAdrian Hunter } 119052afdaf9SAdrian Hunter 119152afdaf9SAdrian Hunter return false; 119252afdaf9SAdrian Hunter } 119352afdaf9SAdrian Hunter 119452afdaf9SAdrian Hunter static int validate_kcore_modules(const char *kallsyms_filename, 119552afdaf9SAdrian Hunter struct map *map) 119652afdaf9SAdrian Hunter { 119779b6bb73SArnaldo Carvalho de Melo struct maps *kmaps = map__kmaps(map); 119852afdaf9SAdrian Hunter char modules_filename[PATH_MAX]; 119952afdaf9SAdrian Hunter 1200ba92732eSWang Nan if (!kmaps) 1201ba92732eSWang Nan return -EINVAL; 1202ba92732eSWang Nan 120352afdaf9SAdrian Hunter if (!filename_from_kallsyms_filename(modules_filename, "modules", 120452afdaf9SAdrian Hunter kallsyms_filename)) 120552afdaf9SAdrian Hunter return -EINVAL; 120652afdaf9SAdrian Hunter 12075759a682SAdrian Hunter if (do_validate_kcore_modules(modules_filename, kmaps)) 120852afdaf9SAdrian Hunter return -EINVAL; 120952afdaf9SAdrian Hunter 121052afdaf9SAdrian Hunter return 0; 121152afdaf9SAdrian Hunter } 121252afdaf9SAdrian Hunter 1213a00d28cbSAdrian Hunter static int validate_kcore_addresses(const char *kallsyms_filename, 1214a00d28cbSAdrian Hunter struct map *map) 1215a00d28cbSAdrian Hunter { 1216a00d28cbSAdrian Hunter struct kmap *kmap = map__kmap(map); 1217a00d28cbSAdrian Hunter 1218ba92732eSWang Nan if (!kmap) 1219ba92732eSWang Nan return -EINVAL; 1220ba92732eSWang Nan 1221a00d28cbSAdrian Hunter if (kmap->ref_reloc_sym && kmap->ref_reloc_sym->name) { 1222a00d28cbSAdrian Hunter u64 start; 1223a00d28cbSAdrian Hunter 1224b843f62aSArnaldo Carvalho de Melo if (kallsyms__get_function_start(kallsyms_filename, 1225b843f62aSArnaldo Carvalho de Melo kmap->ref_reloc_sym->name, &start)) 1226b843f62aSArnaldo Carvalho de Melo return -ENOENT; 1227a00d28cbSAdrian Hunter if (start != kmap->ref_reloc_sym->addr) 1228a00d28cbSAdrian Hunter return -EINVAL; 1229a00d28cbSAdrian Hunter } 1230a00d28cbSAdrian Hunter 1231a00d28cbSAdrian Hunter return validate_kcore_modules(kallsyms_filename, map); 1232a00d28cbSAdrian Hunter } 1233a00d28cbSAdrian Hunter 12348e0cf965SAdrian Hunter struct kcore_mapfn_data { 12358e0cf965SAdrian Hunter struct dso *dso; 12368e0cf965SAdrian Hunter struct list_head maps; 12378e0cf965SAdrian Hunter }; 12388e0cf965SAdrian Hunter 12398e0cf965SAdrian Hunter static int kcore_mapfn(u64 start, u64 len, u64 pgoff, void *data) 12408e0cf965SAdrian Hunter { 12418e0cf965SAdrian Hunter struct kcore_mapfn_data *md = data; 124283720209SIan Rogers struct map_list_node *list_node = map_list_node__new(); 12438e0cf965SAdrian Hunter 124483720209SIan Rogers if (!list_node) 12458e0cf965SAdrian Hunter return -ENOMEM; 12468e0cf965SAdrian Hunter 124783720209SIan Rogers list_node->map = map__new2(start, md->dso); 124883720209SIan Rogers if (!list_node->map) { 124983720209SIan Rogers free(list_node); 125083720209SIan Rogers return -ENOMEM; 125183720209SIan Rogers } 12528e0cf965SAdrian Hunter 1253e5116f46SIan Rogers list_node->map->end = map__start(list_node->map) + len; 125483720209SIan Rogers list_node->map->pgoff = pgoff; 125583720209SIan Rogers 125683720209SIan Rogers list_add(&list_node->node, &md->maps); 12578e0cf965SAdrian Hunter 12588e0cf965SAdrian Hunter return 0; 12598e0cf965SAdrian Hunter } 12608e0cf965SAdrian Hunter 1261fb5a88d4SJiri Olsa /* 126279b6bb73SArnaldo Carvalho de Melo * Merges map into maps by splitting the new map within the existing map 126379b6bb73SArnaldo Carvalho de Melo * regions. 1264fb5a88d4SJiri Olsa */ 126579b6bb73SArnaldo Carvalho de Melo int maps__merge_in(struct maps *kmaps, struct map *new_map) 1266fb5a88d4SJiri Olsa { 1267ff583dc4SIan Rogers struct map_rb_node *rb_node; 1268fb5a88d4SJiri Olsa LIST_HEAD(merged); 1269ff583dc4SIan Rogers int err = 0; 1270fb5a88d4SJiri Olsa 1271ff583dc4SIan Rogers maps__for_each_entry(kmaps, rb_node) { 1272ff583dc4SIan Rogers struct map *old_map = rb_node->map; 1273ff583dc4SIan Rogers 1274fb5a88d4SJiri Olsa /* no overload with this one */ 1275e5116f46SIan Rogers if (map__end(new_map) < map__start(old_map) || 1276e5116f46SIan Rogers map__start(new_map) >= map__end(old_map)) 1277fb5a88d4SJiri Olsa continue; 1278fb5a88d4SJiri Olsa 1279e5116f46SIan Rogers if (map__start(new_map) < map__start(old_map)) { 1280fb5a88d4SJiri Olsa /* 1281fb5a88d4SJiri Olsa * |new...... 1282fb5a88d4SJiri Olsa * |old.... 1283fb5a88d4SJiri Olsa */ 1284e5116f46SIan Rogers if (map__end(new_map) < map__end(old_map)) { 1285fb5a88d4SJiri Olsa /* 1286fb5a88d4SJiri Olsa * |new......| -> |new..| 1287fb5a88d4SJiri Olsa * |old....| -> |old....| 1288fb5a88d4SJiri Olsa */ 1289e5116f46SIan Rogers new_map->end = map__start(old_map); 1290fb5a88d4SJiri Olsa } else { 1291fb5a88d4SJiri Olsa /* 1292fb5a88d4SJiri Olsa * |new.............| -> |new..| |new..| 1293fb5a88d4SJiri Olsa * |old....| -> |old....| 1294fb5a88d4SJiri Olsa */ 129583720209SIan Rogers struct map_list_node *m = map_list_node__new(); 1296fb5a88d4SJiri Olsa 1297ff583dc4SIan Rogers if (!m) { 1298ff583dc4SIan Rogers err = -ENOMEM; 1299ff583dc4SIan Rogers goto out; 1300ff583dc4SIan Rogers } 1301fb5a88d4SJiri Olsa 130283720209SIan Rogers m->map = map__clone(new_map); 130383720209SIan Rogers if (!m->map) { 130483720209SIan Rogers free(m); 1305ff583dc4SIan Rogers err = -ENOMEM; 1306ff583dc4SIan Rogers goto out; 130783720209SIan Rogers } 130883720209SIan Rogers 1309e5116f46SIan Rogers m->map->end = map__start(old_map); 1310fb5a88d4SJiri Olsa list_add_tail(&m->node, &merged); 1311e5116f46SIan Rogers new_map->pgoff += map__end(old_map) - map__start(new_map); 1312e5116f46SIan Rogers new_map->start = map__end(old_map); 1313fb5a88d4SJiri Olsa } 1314fb5a88d4SJiri Olsa } else { 1315fb5a88d4SJiri Olsa /* 1316fb5a88d4SJiri Olsa * |new...... 1317fb5a88d4SJiri Olsa * |old.... 1318fb5a88d4SJiri Olsa */ 1319e5116f46SIan Rogers if (map__end(new_map) < map__end(old_map)) { 1320fb5a88d4SJiri Olsa /* 1321fb5a88d4SJiri Olsa * |new..| -> x 1322fb5a88d4SJiri Olsa * |old.........| -> |old.........| 1323fb5a88d4SJiri Olsa */ 1324fb5a88d4SJiri Olsa map__put(new_map); 1325fb5a88d4SJiri Olsa new_map = NULL; 1326fb5a88d4SJiri Olsa break; 1327fb5a88d4SJiri Olsa } else { 1328fb5a88d4SJiri Olsa /* 1329fb5a88d4SJiri Olsa * |new......| -> |new...| 1330fb5a88d4SJiri Olsa * |old....| -> |old....| 1331fb5a88d4SJiri Olsa */ 1332e5116f46SIan Rogers new_map->pgoff += map__end(old_map) - map__start(new_map); 1333e5116f46SIan Rogers new_map->start = map__end(old_map); 1334fb5a88d4SJiri Olsa } 1335fb5a88d4SJiri Olsa } 1336fb5a88d4SJiri Olsa } 1337fb5a88d4SJiri Olsa 1338ff583dc4SIan Rogers out: 1339fb5a88d4SJiri Olsa while (!list_empty(&merged)) { 134083720209SIan Rogers struct map_list_node *old_node; 134183720209SIan Rogers 134283720209SIan Rogers old_node = list_entry(merged.next, struct map_list_node, node); 134383720209SIan Rogers list_del_init(&old_node->node); 1344ff583dc4SIan Rogers if (!err) 1345ff583dc4SIan Rogers err = maps__insert(kmaps, old_node->map); 134683720209SIan Rogers map__put(old_node->map); 134783720209SIan Rogers free(old_node); 1348fb5a88d4SJiri Olsa } 1349fb5a88d4SJiri Olsa 1350fb5a88d4SJiri Olsa if (new_map) { 1351ff583dc4SIan Rogers if (!err) 1352ff583dc4SIan Rogers err = maps__insert(kmaps, new_map); 1353fb5a88d4SJiri Olsa map__put(new_map); 1354fb5a88d4SJiri Olsa } 1355ff583dc4SIan Rogers return err; 1356fb5a88d4SJiri Olsa } 1357fb5a88d4SJiri Olsa 13588e0cf965SAdrian Hunter static int dso__load_kcore(struct dso *dso, struct map *map, 13598e0cf965SAdrian Hunter const char *kallsyms_filename) 13608e0cf965SAdrian Hunter { 136179b6bb73SArnaldo Carvalho de Melo struct maps *kmaps = map__kmaps(map); 13628e0cf965SAdrian Hunter struct kcore_mapfn_data md; 1363ff583dc4SIan Rogers struct map *replacement_map = NULL; 1364ff583dc4SIan Rogers struct map_rb_node *old_node, *next; 13651c5aae77SAdrian Hunter struct machine *machine; 13668e0cf965SAdrian Hunter bool is_64_bit; 13678e0cf965SAdrian Hunter int err, fd; 13688e0cf965SAdrian Hunter char kcore_filename[PATH_MAX]; 136956549978SAdrian Hunter u64 stext; 13708e0cf965SAdrian Hunter 1371ba92732eSWang Nan if (!kmaps) 1372ba92732eSWang Nan return -EINVAL; 1373ba92732eSWang Nan 13745ab6d715SIan Rogers machine = maps__machine(kmaps); 13751c5aae77SAdrian Hunter 13768e0cf965SAdrian Hunter /* This function requires that the map is the kernel map */ 1377efdd5c6bSArnaldo Carvalho de Melo if (!__map__is_kernel(map)) 13788e0cf965SAdrian Hunter return -EINVAL; 13798e0cf965SAdrian Hunter 138052afdaf9SAdrian Hunter if (!filename_from_kallsyms_filename(kcore_filename, "kcore", 13818e0cf965SAdrian Hunter kallsyms_filename)) 13828e0cf965SAdrian Hunter return -EINVAL; 13838e0cf965SAdrian Hunter 1384a00d28cbSAdrian Hunter /* Modules and kernel must be present at their original addresses */ 1385a00d28cbSAdrian Hunter if (validate_kcore_addresses(kallsyms_filename, map)) 138652afdaf9SAdrian Hunter return -EINVAL; 138752afdaf9SAdrian Hunter 13888e0cf965SAdrian Hunter md.dso = dso; 13898e0cf965SAdrian Hunter INIT_LIST_HEAD(&md.maps); 13908e0cf965SAdrian Hunter 13918e0cf965SAdrian Hunter fd = open(kcore_filename, O_RDONLY); 139236c8bb56SLi Zhang if (fd < 0) { 1393133de940SAdrian Hunter pr_debug("Failed to open %s. Note /proc/kcore requires CAP_SYS_RAWIO capability to access.\n", 139436c8bb56SLi Zhang kcore_filename); 13958e0cf965SAdrian Hunter return -EINVAL; 139636c8bb56SLi Zhang } 13978e0cf965SAdrian Hunter 13988e0cf965SAdrian Hunter /* Read new maps into temporary lists */ 1399ddee3f2bSIan Rogers err = file__read_maps(fd, map__prot(map) & PROT_EXEC, kcore_mapfn, &md, 14008e0cf965SAdrian Hunter &is_64_bit); 14018e0cf965SAdrian Hunter if (err) 14028e0cf965SAdrian Hunter goto out_err; 1403c6d8f2a4SAdrian Hunter dso->is_64_bit = is_64_bit; 14048e0cf965SAdrian Hunter 14058e0cf965SAdrian Hunter if (list_empty(&md.maps)) { 14068e0cf965SAdrian Hunter err = -EINVAL; 14078e0cf965SAdrian Hunter goto out_err; 14088e0cf965SAdrian Hunter } 14098e0cf965SAdrian Hunter 14108e0cf965SAdrian Hunter /* Remove old maps */ 1411ff583dc4SIan Rogers maps__for_each_entry_safe(kmaps, old_node, next) { 1412ff583dc4SIan Rogers struct map *old_map = old_node->map; 1413ff583dc4SIan Rogers 1414fb5a88d4SJiri Olsa /* 1415fb5a88d4SJiri Olsa * We need to preserve eBPF maps even if they are 1416fb5a88d4SJiri Olsa * covered by kcore, because we need to access 1417fb5a88d4SJiri Olsa * eBPF dso for source data. 1418fb5a88d4SJiri Olsa */ 1419fb5a88d4SJiri Olsa if (old_map != map && !__map__is_bpf_prog(old_map)) 142079b6bb73SArnaldo Carvalho de Melo maps__remove(kmaps, old_map); 14218e0cf965SAdrian Hunter } 14221c5aae77SAdrian Hunter machine->trampolines_mapped = false; 14238e0cf965SAdrian Hunter 142456549978SAdrian Hunter /* Find the kernel map using the '_stext' symbol */ 142556549978SAdrian Hunter if (!kallsyms__get_function_start(kallsyms_filename, "_stext", &stext)) { 14261c249565SKrister Johansen u64 replacement_size = 0; 142783720209SIan Rogers struct map_list_node *new_node; 14281c249565SKrister Johansen 142983720209SIan Rogers list_for_each_entry(new_node, &md.maps, node) { 143083720209SIan Rogers struct map *new_map = new_node->map; 1431e5116f46SIan Rogers u64 new_size = map__size(new_map); 14321c249565SKrister Johansen 1433e5116f46SIan Rogers if (!(stext >= map__start(new_map) && stext < map__end(new_map))) 14341c249565SKrister Johansen continue; 14351c249565SKrister Johansen 14361c249565SKrister Johansen /* 14371c249565SKrister Johansen * On some architectures, ARM64 for example, the kernel 14381c249565SKrister Johansen * text can get allocated inside of the vmalloc segment. 14391c249565SKrister Johansen * Select the smallest matching segment, in case stext 14401c249565SKrister Johansen * falls within more than one in the list. 14411c249565SKrister Johansen */ 14421c249565SKrister Johansen if (!replacement_map || new_size < replacement_size) { 14438e0cf965SAdrian Hunter replacement_map = new_map; 14441c249565SKrister Johansen replacement_size = new_size; 14458e0cf965SAdrian Hunter } 14468e0cf965SAdrian Hunter } 144756549978SAdrian Hunter } 14488e0cf965SAdrian Hunter 14498e0cf965SAdrian Hunter if (!replacement_map) 145083720209SIan Rogers replacement_map = list_entry(md.maps.next, struct map_list_node, node)->map; 14518e0cf965SAdrian Hunter 14528e0cf965SAdrian Hunter /* Add new maps */ 14538e0cf965SAdrian Hunter while (!list_empty(&md.maps)) { 145483720209SIan Rogers struct map_list_node *new_node = list_entry(md.maps.next, struct map_list_node, node); 145583720209SIan Rogers struct map *new_map = new_node->map; 145683720209SIan Rogers 145783720209SIan Rogers list_del_init(&new_node->node); 145883720209SIan Rogers 14598e0cf965SAdrian Hunter if (new_map == replacement_map) { 1460e5116f46SIan Rogers map->start = map__start(new_map); 1461e5116f46SIan Rogers map->end = map__end(new_map); 14622a6e5e8aSIan Rogers map->pgoff = map__pgoff(new_map); 14638e0cf965SAdrian Hunter map->map_ip = new_map->map_ip; 14648e0cf965SAdrian Hunter map->unmap_ip = new_map->unmap_ip; 14658e0cf965SAdrian Hunter /* Ensure maps are correctly ordered */ 146684c2cafaSArnaldo Carvalho de Melo map__get(map); 146779b6bb73SArnaldo Carvalho de Melo maps__remove(kmaps, map); 1468ff583dc4SIan Rogers err = maps__insert(kmaps, map); 146984c2cafaSArnaldo Carvalho de Melo map__put(map); 147084c2cafaSArnaldo Carvalho de Melo map__put(new_map); 1471ff583dc4SIan Rogers if (err) 1472ff583dc4SIan Rogers goto out_err; 1473fb5a88d4SJiri Olsa } else { 1474fb5a88d4SJiri Olsa /* 1475fb5a88d4SJiri Olsa * Merge kcore map into existing maps, 1476fb5a88d4SJiri Olsa * and ensure that current maps (eBPF) 1477fb5a88d4SJiri Olsa * stay intact. 1478fb5a88d4SJiri Olsa */ 1479ff583dc4SIan Rogers if (maps__merge_in(kmaps, new_map)) { 1480ff583dc4SIan Rogers err = -EINVAL; 1481fb5a88d4SJiri Olsa goto out_err; 1482fb5a88d4SJiri Olsa } 1483ff583dc4SIan Rogers } 148483720209SIan Rogers free(new_node); 14858e0cf965SAdrian Hunter } 14868e0cf965SAdrian Hunter 14871c5aae77SAdrian Hunter if (machine__is(machine, "x86_64")) { 14881c5aae77SAdrian Hunter u64 addr; 14891c5aae77SAdrian Hunter 14901c5aae77SAdrian Hunter /* 14911c5aae77SAdrian Hunter * If one of the corresponding symbols is there, assume the 14921c5aae77SAdrian Hunter * entry trampoline maps are too. 14931c5aae77SAdrian Hunter */ 14941c5aae77SAdrian Hunter if (!kallsyms__get_function_start(kallsyms_filename, 14951c5aae77SAdrian Hunter ENTRY_TRAMPOLINE_NAME, 14961c5aae77SAdrian Hunter &addr)) 14971c5aae77SAdrian Hunter machine->trampolines_mapped = true; 14981c5aae77SAdrian Hunter } 14991c5aae77SAdrian Hunter 15008e0cf965SAdrian Hunter /* 15018e0cf965SAdrian Hunter * Set the data type and long name so that kcore can be read via 15028e0cf965SAdrian Hunter * dso__data_read_addr(). 15038e0cf965SAdrian Hunter */ 15041c695c88SJiri Olsa if (dso->kernel == DSO_SPACE__KERNEL_GUEST) 15055f70619dSArnaldo Carvalho de Melo dso->binary_type = DSO_BINARY_TYPE__GUEST_KCORE; 15068e0cf965SAdrian Hunter else 15075f70619dSArnaldo Carvalho de Melo dso->binary_type = DSO_BINARY_TYPE__KCORE; 15087e155d4dSArnaldo Carvalho de Melo dso__set_long_name(dso, strdup(kcore_filename), true); 15098e0cf965SAdrian Hunter 15108e0cf965SAdrian Hunter close(fd); 15118e0cf965SAdrian Hunter 1512ddee3f2bSIan Rogers if (map__prot(map) & PROT_EXEC) 15138e0cf965SAdrian Hunter pr_debug("Using %s for kernel object code\n", kcore_filename); 15148e0cf965SAdrian Hunter else 15158e0cf965SAdrian Hunter pr_debug("Using %s for kernel data\n", kcore_filename); 15168e0cf965SAdrian Hunter 15178e0cf965SAdrian Hunter return 0; 15188e0cf965SAdrian Hunter 15198e0cf965SAdrian Hunter out_err: 15208e0cf965SAdrian Hunter while (!list_empty(&md.maps)) { 152183720209SIan Rogers struct map_list_node *list_node; 152283720209SIan Rogers 152383720209SIan Rogers list_node = list_entry(md.maps.next, struct map_list_node, node); 152483720209SIan Rogers list_del_init(&list_node->node); 152583720209SIan Rogers map__zput(list_node->map); 152683720209SIan Rogers free(list_node); 15278e0cf965SAdrian Hunter } 15288e0cf965SAdrian Hunter close(fd); 1529ff583dc4SIan Rogers return err; 15308e0cf965SAdrian Hunter } 15318e0cf965SAdrian Hunter 1532d9b62abaSAdrian Hunter /* 1533d9b62abaSAdrian Hunter * If the kernel is relocated at boot time, kallsyms won't match. Compute the 1534d9b62abaSAdrian Hunter * delta based on the relocation reference symbol. 1535d9b62abaSAdrian Hunter */ 1536019c6820SArnaldo Carvalho de Melo static int kallsyms__delta(struct kmap *kmap, const char *filename, u64 *delta) 1537d9b62abaSAdrian Hunter { 1538d9b62abaSAdrian Hunter u64 addr; 1539d9b62abaSAdrian Hunter 1540d9b62abaSAdrian Hunter if (!kmap->ref_reloc_sym || !kmap->ref_reloc_sym->name) 1541d9b62abaSAdrian Hunter return 0; 1542d9b62abaSAdrian Hunter 1543b843f62aSArnaldo Carvalho de Melo if (kallsyms__get_function_start(filename, kmap->ref_reloc_sym->name, &addr)) 1544d9b62abaSAdrian Hunter return -1; 1545d9b62abaSAdrian Hunter 1546d9b62abaSAdrian Hunter *delta = addr - kmap->ref_reloc_sym->addr; 1547d9b62abaSAdrian Hunter return 0; 1548d9b62abaSAdrian Hunter } 1549d9b62abaSAdrian Hunter 1550e02092b9SArnaldo Carvalho de Melo int __dso__load_kallsyms(struct dso *dso, const char *filename, 1551be39db9fSArnaldo Carvalho de Melo struct map *map, bool no_kcore) 15522e538c4aSArnaldo Carvalho de Melo { 1553019c6820SArnaldo Carvalho de Melo struct kmap *kmap = map__kmap(map); 1554d9b62abaSAdrian Hunter u64 delta = 0; 1555d9b62abaSAdrian Hunter 1556ec80fde7SArnaldo Carvalho de Melo if (symbol__restricted_filename(filename, "/proc/kallsyms")) 1557ec80fde7SArnaldo Carvalho de Melo return -1; 1558ec80fde7SArnaldo Carvalho de Melo 1559019c6820SArnaldo Carvalho de Melo if (!kmap || !kmap->kmaps) 1560019c6820SArnaldo Carvalho de Melo return -1; 1561019c6820SArnaldo Carvalho de Melo 1562333cc76cSArnaldo Carvalho de Melo if (dso__load_all_kallsyms(dso, filename) < 0) 15632e538c4aSArnaldo Carvalho de Melo return -1; 15642e538c4aSArnaldo Carvalho de Melo 1565019c6820SArnaldo Carvalho de Melo if (kallsyms__delta(kmap, filename, &delta)) 1566d9b62abaSAdrian Hunter return -1; 1567d9b62abaSAdrian Hunter 1568838425f2SNamhyung Kim symbols__fixup_end(&dso->symbols, true); 15693183f8caSArnaldo Carvalho de Melo symbols__fixup_duplicate(&dso->symbols); 15703f5a4272SAnton Blanchard 15711c695c88SJiri Olsa if (dso->kernel == DSO_SPACE__KERNEL_GUEST) 157244f24cb3SJiri Olsa dso->symtab_type = DSO_BINARY_TYPE__GUEST_KALLSYMS; 1573a1645ce1SZhang, Yanmin else 157444f24cb3SJiri Olsa dso->symtab_type = DSO_BINARY_TYPE__KALLSYMS; 15752e538c4aSArnaldo Carvalho de Melo 1576e02092b9SArnaldo Carvalho de Melo if (!no_kcore && !dso__load_kcore(dso, map, filename)) 157779b6bb73SArnaldo Carvalho de Melo return maps__split_kallsyms_for_kcore(kmap->kmaps, dso); 15788e0cf965SAdrian Hunter else 157979b6bb73SArnaldo Carvalho de Melo return maps__split_kallsyms(kmap->kmaps, dso, delta, map); 1580af427bf5SArnaldo Carvalho de Melo } 1581af427bf5SArnaldo Carvalho de Melo 1582e02092b9SArnaldo Carvalho de Melo int dso__load_kallsyms(struct dso *dso, const char *filename, 1583be39db9fSArnaldo Carvalho de Melo struct map *map) 1584e02092b9SArnaldo Carvalho de Melo { 1585be39db9fSArnaldo Carvalho de Melo return __dso__load_kallsyms(dso, filename, map, false); 1586e02092b9SArnaldo Carvalho de Melo } 1587e02092b9SArnaldo Carvalho de Melo 15883183f8caSArnaldo Carvalho de Melo static int dso__load_perf_map(const char *map_path, struct dso *dso) 158980d496beSPekka Enberg { 159080d496beSPekka Enberg char *line = NULL; 159180d496beSPekka Enberg size_t n; 159280d496beSPekka Enberg FILE *file; 159380d496beSPekka Enberg int nr_syms = 0; 159480d496beSPekka Enberg 1595bf2e710bSKrister Johansen file = fopen(map_path, "r"); 159680d496beSPekka Enberg if (file == NULL) 159780d496beSPekka Enberg goto out_failure; 159880d496beSPekka Enberg 159980d496beSPekka Enberg while (!feof(file)) { 16009cffa8d5SPaul Mackerras u64 start, size; 160180d496beSPekka Enberg struct symbol *sym; 160280d496beSPekka Enberg int line_len, len; 160380d496beSPekka Enberg 160480d496beSPekka Enberg line_len = getline(&line, &n, file); 160580d496beSPekka Enberg if (line_len < 0) 160680d496beSPekka Enberg break; 160780d496beSPekka Enberg 160880d496beSPekka Enberg if (!line) 160980d496beSPekka Enberg goto out_failure; 161080d496beSPekka Enberg 161180d496beSPekka Enberg line[--line_len] = '\0'; /* \n */ 161280d496beSPekka Enberg 161380d496beSPekka Enberg len = hex2u64(line, &start); 161480d496beSPekka Enberg 161580d496beSPekka Enberg len++; 161680d496beSPekka Enberg if (len + 2 >= line_len) 161780d496beSPekka Enberg continue; 161880d496beSPekka Enberg 161980d496beSPekka Enberg len += hex2u64(line + len, &size); 162080d496beSPekka Enberg 162180d496beSPekka Enberg len++; 162280d496beSPekka Enberg if (len + 2 >= line_len) 162380d496beSPekka Enberg continue; 162480d496beSPekka Enberg 1625af30bffaSArnaldo Carvalho de Melo sym = symbol__new(start, size, STB_GLOBAL, STT_FUNC, line + len); 162680d496beSPekka Enberg 162780d496beSPekka Enberg if (sym == NULL) 162880d496beSPekka Enberg goto out_delete_line; 162980d496beSPekka Enberg 16303183f8caSArnaldo Carvalho de Melo symbols__insert(&dso->symbols, sym); 163180d496beSPekka Enberg nr_syms++; 163280d496beSPekka Enberg } 163380d496beSPekka Enberg 163480d496beSPekka Enberg free(line); 163580d496beSPekka Enberg fclose(file); 163680d496beSPekka Enberg 163780d496beSPekka Enberg return nr_syms; 163880d496beSPekka Enberg 163980d496beSPekka Enberg out_delete_line: 164080d496beSPekka Enberg free(line); 164180d496beSPekka Enberg out_failure: 164280d496beSPekka Enberg return -1; 164380d496beSPekka Enberg } 164480d496beSPekka Enberg 1645eac9a434SRemi Bernon #ifdef HAVE_LIBBFD_SUPPORT 1646eac9a434SRemi Bernon #define PACKAGE 'perf' 1647eac9a434SRemi Bernon #include <bfd.h> 1648eac9a434SRemi Bernon 1649eac9a434SRemi Bernon static int bfd_symbols__cmpvalue(const void *a, const void *b) 1650eac9a434SRemi Bernon { 1651eac9a434SRemi Bernon const asymbol *as = *(const asymbol **)a, *bs = *(const asymbol **)b; 1652eac9a434SRemi Bernon 1653eac9a434SRemi Bernon if (bfd_asymbol_value(as) != bfd_asymbol_value(bs)) 1654eac9a434SRemi Bernon return bfd_asymbol_value(as) - bfd_asymbol_value(bs); 1655eac9a434SRemi Bernon 1656eac9a434SRemi Bernon return bfd_asymbol_name(as)[0] - bfd_asymbol_name(bs)[0]; 1657eac9a434SRemi Bernon } 1658eac9a434SRemi Bernon 1659eac9a434SRemi Bernon static int bfd2elf_binding(asymbol *symbol) 1660eac9a434SRemi Bernon { 1661eac9a434SRemi Bernon if (symbol->flags & BSF_WEAK) 1662eac9a434SRemi Bernon return STB_WEAK; 1663eac9a434SRemi Bernon if (symbol->flags & BSF_GLOBAL) 1664eac9a434SRemi Bernon return STB_GLOBAL; 1665eac9a434SRemi Bernon if (symbol->flags & BSF_LOCAL) 1666eac9a434SRemi Bernon return STB_LOCAL; 1667eac9a434SRemi Bernon return -1; 1668eac9a434SRemi Bernon } 1669eac9a434SRemi Bernon 1670eac9a434SRemi Bernon int dso__load_bfd_symbols(struct dso *dso, const char *debugfile) 1671eac9a434SRemi Bernon { 1672eac9a434SRemi Bernon int err = -1; 167396de68ffSDmitry Safonov long symbols_size, symbols_count, i; 1674eac9a434SRemi Bernon asection *section; 1675eac9a434SRemi Bernon asymbol **symbols, *sym; 1676eac9a434SRemi Bernon struct symbol *symbol; 1677eac9a434SRemi Bernon bfd *abfd; 1678eac9a434SRemi Bernon u64 start, len; 1679eac9a434SRemi Bernon 168000a34234SNicholas Fraser abfd = bfd_openr(debugfile, NULL); 1681eac9a434SRemi Bernon if (!abfd) 1682eac9a434SRemi Bernon return -1; 1683eac9a434SRemi Bernon 1684eac9a434SRemi Bernon if (!bfd_check_format(abfd, bfd_object)) { 1685eac9a434SRemi Bernon pr_debug2("%s: cannot read %s bfd file.\n", __func__, 1686eac9a434SRemi Bernon dso->long_name); 1687eac9a434SRemi Bernon goto out_close; 1688eac9a434SRemi Bernon } 1689eac9a434SRemi Bernon 1690eac9a434SRemi Bernon if (bfd_get_flavour(abfd) == bfd_target_elf_flavour) 1691eac9a434SRemi Bernon goto out_close; 1692eac9a434SRemi Bernon 1693eac9a434SRemi Bernon symbols_size = bfd_get_symtab_upper_bound(abfd); 1694eac9a434SRemi Bernon if (symbols_size == 0) { 1695eac9a434SRemi Bernon bfd_close(abfd); 1696eac9a434SRemi Bernon return 0; 1697eac9a434SRemi Bernon } 1698eac9a434SRemi Bernon 1699eac9a434SRemi Bernon if (symbols_size < 0) 1700eac9a434SRemi Bernon goto out_close; 1701eac9a434SRemi Bernon 1702eac9a434SRemi Bernon symbols = malloc(symbols_size); 1703eac9a434SRemi Bernon if (!symbols) 1704eac9a434SRemi Bernon goto out_close; 1705eac9a434SRemi Bernon 1706eac9a434SRemi Bernon symbols_count = bfd_canonicalize_symtab(abfd, symbols); 1707eac9a434SRemi Bernon if (symbols_count < 0) 1708eac9a434SRemi Bernon goto out_free; 1709eac9a434SRemi Bernon 1710d2930edeSRemi Bernon section = bfd_get_section_by_name(abfd, ".text"); 1711d2930edeSRemi Bernon if (section) { 1712d2930edeSRemi Bernon for (i = 0; i < symbols_count; ++i) { 1713d2930edeSRemi Bernon if (!strcmp(bfd_asymbol_name(symbols[i]), "__ImageBase") || 1714d2930edeSRemi Bernon !strcmp(bfd_asymbol_name(symbols[i]), "__image_base__")) 1715d2930edeSRemi Bernon break; 1716d2930edeSRemi Bernon } 1717d2930edeSRemi Bernon if (i < symbols_count) { 1718d2930edeSRemi Bernon /* PE symbols can only have 4 bytes, so use .text high bits */ 1719d2930edeSRemi Bernon dso->text_offset = section->vma - (u32)section->vma; 1720d2930edeSRemi Bernon dso->text_offset += (u32)bfd_asymbol_value(symbols[i]); 1721d2930edeSRemi Bernon } else { 1722d2930edeSRemi Bernon dso->text_offset = section->vma - section->filepos; 1723d2930edeSRemi Bernon } 1724d2930edeSRemi Bernon } 1725d2930edeSRemi Bernon 1726eac9a434SRemi Bernon qsort(symbols, symbols_count, sizeof(asymbol *), bfd_symbols__cmpvalue); 1727eac9a434SRemi Bernon 1728eac9a434SRemi Bernon #ifdef bfd_get_section 1729eac9a434SRemi Bernon #define bfd_asymbol_section bfd_get_section 1730eac9a434SRemi Bernon #endif 1731eac9a434SRemi Bernon for (i = 0; i < symbols_count; ++i) { 1732eac9a434SRemi Bernon sym = symbols[i]; 1733eac9a434SRemi Bernon section = bfd_asymbol_section(sym); 1734eac9a434SRemi Bernon if (bfd2elf_binding(sym) < 0) 1735eac9a434SRemi Bernon continue; 1736eac9a434SRemi Bernon 1737eac9a434SRemi Bernon while (i + 1 < symbols_count && 1738eac9a434SRemi Bernon bfd_asymbol_section(symbols[i + 1]) == section && 1739eac9a434SRemi Bernon bfd2elf_binding(symbols[i + 1]) < 0) 1740eac9a434SRemi Bernon i++; 1741eac9a434SRemi Bernon 1742eac9a434SRemi Bernon if (i + 1 < symbols_count && 1743eac9a434SRemi Bernon bfd_asymbol_section(symbols[i + 1]) == section) 1744eac9a434SRemi Bernon len = symbols[i + 1]->value - sym->value; 1745eac9a434SRemi Bernon else 1746eac9a434SRemi Bernon len = section->size - sym->value; 1747eac9a434SRemi Bernon 1748eac9a434SRemi Bernon start = bfd_asymbol_value(sym) - dso->text_offset; 1749eac9a434SRemi Bernon symbol = symbol__new(start, len, bfd2elf_binding(sym), STT_FUNC, 1750eac9a434SRemi Bernon bfd_asymbol_name(sym)); 1751eac9a434SRemi Bernon if (!symbol) 1752eac9a434SRemi Bernon goto out_free; 1753eac9a434SRemi Bernon 1754eac9a434SRemi Bernon symbols__insert(&dso->symbols, symbol); 1755eac9a434SRemi Bernon } 1756eac9a434SRemi Bernon #ifdef bfd_get_section 1757eac9a434SRemi Bernon #undef bfd_asymbol_section 1758eac9a434SRemi Bernon #endif 1759eac9a434SRemi Bernon 1760838425f2SNamhyung Kim symbols__fixup_end(&dso->symbols, false); 1761eac9a434SRemi Bernon symbols__fixup_duplicate(&dso->symbols); 1762eac9a434SRemi Bernon dso->adjust_symbols = 1; 1763eac9a434SRemi Bernon 1764eac9a434SRemi Bernon err = 0; 1765eac9a434SRemi Bernon out_free: 1766eac9a434SRemi Bernon free(symbols); 1767eac9a434SRemi Bernon out_close: 1768eac9a434SRemi Bernon bfd_close(abfd); 1769eac9a434SRemi Bernon return err; 1770eac9a434SRemi Bernon } 1771eac9a434SRemi Bernon #endif 1772eac9a434SRemi Bernon 17731029f9feSNamhyung Kim static bool dso__is_compatible_symtab_type(struct dso *dso, bool kmod, 17741029f9feSNamhyung Kim enum dso_binary_type type) 17751029f9feSNamhyung Kim { 17761029f9feSNamhyung Kim switch (type) { 17771029f9feSNamhyung Kim case DSO_BINARY_TYPE__JAVA_JIT: 17781029f9feSNamhyung Kim case DSO_BINARY_TYPE__DEBUGLINK: 17791029f9feSNamhyung Kim case DSO_BINARY_TYPE__SYSTEM_PATH_DSO: 17801029f9feSNamhyung Kim case DSO_BINARY_TYPE__FEDORA_DEBUGINFO: 17811029f9feSNamhyung Kim case DSO_BINARY_TYPE__UBUNTU_DEBUGINFO: 178285afd355SAdrian Hunter case DSO_BINARY_TYPE__MIXEDUP_UBUNTU_DEBUGINFO: 17831029f9feSNamhyung Kim case DSO_BINARY_TYPE__BUILDID_DEBUGINFO: 17841029f9feSNamhyung Kim case DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO: 17851c695c88SJiri Olsa return !kmod && dso->kernel == DSO_SPACE__USER; 17861029f9feSNamhyung Kim 17871029f9feSNamhyung Kim case DSO_BINARY_TYPE__KALLSYMS: 17881029f9feSNamhyung Kim case DSO_BINARY_TYPE__VMLINUX: 17891029f9feSNamhyung Kim case DSO_BINARY_TYPE__KCORE: 17901c695c88SJiri Olsa return dso->kernel == DSO_SPACE__KERNEL; 17911029f9feSNamhyung Kim 17921029f9feSNamhyung Kim case DSO_BINARY_TYPE__GUEST_KALLSYMS: 17931029f9feSNamhyung Kim case DSO_BINARY_TYPE__GUEST_VMLINUX: 17941029f9feSNamhyung Kim case DSO_BINARY_TYPE__GUEST_KCORE: 17951c695c88SJiri Olsa return dso->kernel == DSO_SPACE__KERNEL_GUEST; 17961029f9feSNamhyung Kim 17971029f9feSNamhyung Kim case DSO_BINARY_TYPE__GUEST_KMODULE: 1798c00c48fcSNamhyung Kim case DSO_BINARY_TYPE__GUEST_KMODULE_COMP: 17991029f9feSNamhyung Kim case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE: 1800c00c48fcSNamhyung Kim case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP: 18011029f9feSNamhyung Kim /* 18021029f9feSNamhyung Kim * kernel modules know their symtab type - it's set when 1803a94ab91aSArnaldo Carvalho de Melo * creating a module dso in machine__addnew_module_map(). 18041029f9feSNamhyung Kim */ 18051029f9feSNamhyung Kim return kmod && dso->symtab_type == type; 18061029f9feSNamhyung Kim 18071029f9feSNamhyung Kim case DSO_BINARY_TYPE__BUILD_ID_CACHE: 1808d2396999SKrister Johansen case DSO_BINARY_TYPE__BUILD_ID_CACHE_DEBUGINFO: 18091029f9feSNamhyung Kim return true; 18101029f9feSNamhyung Kim 18119b86d04dSSong Liu case DSO_BINARY_TYPE__BPF_PROG_INFO: 18123c29d448SJiri Olsa case DSO_BINARY_TYPE__BPF_IMAGE: 1813789e2419SAdrian Hunter case DSO_BINARY_TYPE__OOL: 18141029f9feSNamhyung Kim case DSO_BINARY_TYPE__NOT_FOUND: 18151029f9feSNamhyung Kim default: 18161029f9feSNamhyung Kim return false; 18171029f9feSNamhyung Kim } 18181029f9feSNamhyung Kim } 18191029f9feSNamhyung Kim 1820bf2e710bSKrister Johansen /* Checks for the existence of the perf-<pid>.map file in two different 1821bf2e710bSKrister Johansen * locations. First, if the process is a separate mount namespace, check in 1822bf2e710bSKrister Johansen * that namespace using the pid of the innermost pid namespace. If's not in a 1823bf2e710bSKrister Johansen * namespace, or the file can't be found there, try in the mount namespace of 1824bf2e710bSKrister Johansen * the tracing process using our view of its pid. 1825bf2e710bSKrister Johansen */ 1826bf2e710bSKrister Johansen static int dso__find_perf_map(char *filebuf, size_t bufsz, 1827bf2e710bSKrister Johansen struct nsinfo **nsip) 1828bf2e710bSKrister Johansen { 1829bf2e710bSKrister Johansen struct nscookie nsc; 1830bf2e710bSKrister Johansen struct nsinfo *nsi; 1831bf2e710bSKrister Johansen struct nsinfo *nnsi; 1832bf2e710bSKrister Johansen int rc = -1; 1833bf2e710bSKrister Johansen 1834bf2e710bSKrister Johansen nsi = *nsip; 1835bf2e710bSKrister Johansen 1836bcaf0a97SIan Rogers if (nsinfo__need_setns(nsi)) { 1837bcaf0a97SIan Rogers snprintf(filebuf, bufsz, "/tmp/perf-%d.map", nsinfo__nstgid(nsi)); 1838bf2e710bSKrister Johansen nsinfo__mountns_enter(nsi, &nsc); 1839bf2e710bSKrister Johansen rc = access(filebuf, R_OK); 1840bf2e710bSKrister Johansen nsinfo__mountns_exit(&nsc); 1841bf2e710bSKrister Johansen if (rc == 0) 1842bf2e710bSKrister Johansen return rc; 1843bf2e710bSKrister Johansen } 1844bf2e710bSKrister Johansen 1845bf2e710bSKrister Johansen nnsi = nsinfo__copy(nsi); 1846bf2e710bSKrister Johansen if (nnsi) { 1847bf2e710bSKrister Johansen nsinfo__put(nsi); 1848bf2e710bSKrister Johansen 1849bcaf0a97SIan Rogers nsinfo__clear_need_setns(nnsi); 1850bcaf0a97SIan Rogers snprintf(filebuf, bufsz, "/tmp/perf-%d.map", nsinfo__tgid(nnsi)); 1851bf2e710bSKrister Johansen *nsip = nnsi; 1852bf2e710bSKrister Johansen rc = 0; 1853bf2e710bSKrister Johansen } 1854bf2e710bSKrister Johansen 1855bf2e710bSKrister Johansen return rc; 1856bf2e710bSKrister Johansen } 1857bf2e710bSKrister Johansen 1858be39db9fSArnaldo Carvalho de Melo int dso__load(struct dso *dso, struct map *map) 185986470930SIngo Molnar { 1860c338aee8SArnaldo Carvalho de Melo char *name; 186186470930SIngo Molnar int ret = -1; 186244f24cb3SJiri Olsa u_int i; 186393fcce96SArnaldo Carvalho de Melo struct machine *machine = NULL; 186444f24cb3SJiri Olsa char *root_dir = (char *) ""; 18653aafe5aeSCody P Schafer int ss_pos = 0; 18663aafe5aeSCody P Schafer struct symsrc ss_[2]; 18673aafe5aeSCody P Schafer struct symsrc *syms_ss = NULL, *runtime_ss = NULL; 18681029f9feSNamhyung Kim bool kmod; 1869bf2e710bSKrister Johansen bool perfmap; 1870f766819cSJiri Olsa struct build_id bid; 1871843ff37bSKrister Johansen struct nscookie nsc; 1872bf2e710bSKrister Johansen char newmapname[PATH_MAX]; 1873bf2e710bSKrister Johansen const char *map_path = dso->long_name; 1874bf2e710bSKrister Johansen 1875e54dea69SIan Rogers mutex_lock(&dso->lock); 1876bf2e710bSKrister Johansen perfmap = strncmp(dso->name, "/tmp/perf-", 10) == 0; 1877bf2e710bSKrister Johansen if (perfmap) { 1878bf2e710bSKrister Johansen if (dso->nsinfo && (dso__find_perf_map(newmapname, 1879bf2e710bSKrister Johansen sizeof(newmapname), &dso->nsinfo) == 0)) { 1880bf2e710bSKrister Johansen map_path = newmapname; 1881bf2e710bSKrister Johansen } 1882bf2e710bSKrister Johansen } 188386470930SIngo Molnar 1884843ff37bSKrister Johansen nsinfo__mountns_enter(dso->nsinfo, &nsc); 188566bd8424SArnaldo Carvalho de Melo 18864a936edcSNamhyung Kim /* check again under the dso->lock */ 18873183f8caSArnaldo Carvalho de Melo if (dso__loaded(dso)) { 18884a936edcSNamhyung Kim ret = 1; 18894a936edcSNamhyung Kim goto out; 18904a936edcSNamhyung Kim } 18914a936edcSNamhyung Kim 1892b5c09518SArnaldo Carvalho de Melo kmod = dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE || 1893b5c09518SArnaldo Carvalho de Melo dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP || 1894b5c09518SArnaldo Carvalho de Melo dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE || 1895b5c09518SArnaldo Carvalho de Melo dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE_COMP; 1896b5c09518SArnaldo Carvalho de Melo 1897b5c09518SArnaldo Carvalho de Melo if (dso->kernel && !kmod) { 18981c695c88SJiri Olsa if (dso->kernel == DSO_SPACE__KERNEL) 1899be39db9fSArnaldo Carvalho de Melo ret = dso__load_kernel_sym(dso, map); 19001c695c88SJiri Olsa else if (dso->kernel == DSO_SPACE__KERNEL_GUEST) 1901be39db9fSArnaldo Carvalho de Melo ret = dso__load_guest_kernel_sym(dso, map); 19024a936edcSNamhyung Kim 19035ab6d715SIan Rogers machine = maps__machine(map__kmaps(map)); 19044d99e413SAdrian Hunter if (machine__is(machine, "x86_64")) 19054d99e413SAdrian Hunter machine__map_x86_64_entry_trampolines(machine, dso); 19064a936edcSNamhyung Kim goto out; 19074a936edcSNamhyung Kim } 1908a1645ce1SZhang, Yanmin 1909aeafcbafSArnaldo Carvalho de Melo dso->adjust_symbols = 0; 1910f5812a7aSArnaldo Carvalho de Melo 1911bf2e710bSKrister Johansen if (perfmap) { 19123183f8caSArnaldo Carvalho de Melo ret = dso__load_perf_map(map_path, dso); 191344f24cb3SJiri Olsa dso->symtab_type = ret > 0 ? DSO_BINARY_TYPE__JAVA_JIT : 191444f24cb3SJiri Olsa DSO_BINARY_TYPE__NOT_FOUND; 19154a936edcSNamhyung Kim goto out; 191694cb9e38SArnaldo Carvalho de Melo } 191794cb9e38SArnaldo Carvalho de Melo 191844f24cb3SJiri Olsa if (machine) 191944f24cb3SJiri Olsa root_dir = machine->root_dir; 192044f24cb3SJiri Olsa 1921164c800eSDavid Ahern name = malloc(PATH_MAX); 1922164c800eSDavid Ahern if (!name) 19234a936edcSNamhyung Kim goto out; 1924164c800eSDavid Ahern 19255baecbcdSDima Kogan /* 19265baecbcdSDima Kogan * Read the build id if possible. This is required for 19275baecbcdSDima Kogan * DSO_BINARY_TYPE__BUILDID_DEBUGINFO to work 19285baecbcdSDima Kogan */ 1929ed6c166cSKan Liang if (!dso->has_build_id && 19309b200653SVictor Kamensky is_regular_file(dso->long_name)) { 19319b200653SVictor Kamensky __symbol__join_symfs(name, PATH_MAX, dso->long_name); 1932f766819cSJiri Olsa if (filename__read_build_id(name, &bid) > 0) 19338dfdf440SJiri Olsa dso__set_build_id(dso, &bid); 19349b200653SVictor Kamensky } 19355baecbcdSDima Kogan 19361029f9feSNamhyung Kim /* 19371029f9feSNamhyung Kim * Iterate over candidate debug images. 19383aafe5aeSCody P Schafer * Keep track of "interesting" ones (those which have a symtab, dynsym, 19393aafe5aeSCody P Schafer * and/or opd section) for processing. 19406da80ce8SDave Martin */ 194144f24cb3SJiri Olsa for (i = 0; i < DSO_BINARY_TYPE__SYMTAB_CNT; i++) { 19423aafe5aeSCody P Schafer struct symsrc *ss = &ss_[ss_pos]; 19433aafe5aeSCody P Schafer bool next_slot = false; 1944f045b8c4SKrister Johansen bool is_reg; 1945d2396999SKrister Johansen bool nsexit; 1946eac9a434SRemi Bernon int bfdrc = -1; 1947c3962961SJiri Olsa int sirc = -1; 194844f24cb3SJiri Olsa 1949005f9294SCody P Schafer enum dso_binary_type symtab_type = binary_type_symtab[i]; 195044f24cb3SJiri Olsa 1951d2396999SKrister Johansen nsexit = (symtab_type == DSO_BINARY_TYPE__BUILD_ID_CACHE || 1952d2396999SKrister Johansen symtab_type == DSO_BINARY_TYPE__BUILD_ID_CACHE_DEBUGINFO); 1953d2396999SKrister Johansen 19541029f9feSNamhyung Kim if (!dso__is_compatible_symtab_type(dso, kmod, symtab_type)) 19551029f9feSNamhyung Kim continue; 19561029f9feSNamhyung Kim 1957ee4e9625SArnaldo Carvalho de Melo if (dso__read_binary_type_filename(dso, symtab_type, 195844f24cb3SJiri Olsa root_dir, name, PATH_MAX)) 19596da80ce8SDave Martin continue; 196086470930SIngo Molnar 1961d2396999SKrister Johansen if (nsexit) 1962f045b8c4SKrister Johansen nsinfo__mountns_exit(&nsc); 196340356721SJiri Olsa 1964f045b8c4SKrister Johansen is_reg = is_regular_file(name); 196567fd1892SNamhyung Kim if (!is_reg && errno == ENOENT && dso->nsinfo) { 196667fd1892SNamhyung Kim char *new_name = filename_with_chroot(dso->nsinfo->pid, 196767fd1892SNamhyung Kim name); 196867fd1892SNamhyung Kim if (new_name) { 196967fd1892SNamhyung Kim is_reg = is_regular_file(new_name); 197067fd1892SNamhyung Kim strlcpy(name, new_name, PATH_MAX); 197167fd1892SNamhyung Kim free(new_name); 197267fd1892SNamhyung Kim } 197367fd1892SNamhyung Kim } 197467fd1892SNamhyung Kim 1975eac9a434SRemi Bernon #ifdef HAVE_LIBBFD_SUPPORT 1976c3962961SJiri Olsa if (is_reg) 1977eac9a434SRemi Bernon bfdrc = dso__load_bfd_symbols(dso, name); 1978eac9a434SRemi Bernon #endif 1979eac9a434SRemi Bernon if (is_reg && bfdrc < 0) 1980f045b8c4SKrister Johansen sirc = symsrc__init(ss, dso, name, symtab_type); 1981f045b8c4SKrister Johansen 1982d2396999SKrister Johansen if (nsexit) 1983f045b8c4SKrister Johansen nsinfo__mountns_enter(dso->nsinfo, &nsc); 1984f045b8c4SKrister Johansen 198577771a97SNicholas Fraser if (bfdrc == 0) { 198677771a97SNicholas Fraser ret = 0; 1987eac9a434SRemi Bernon break; 198877771a97SNicholas Fraser } 1989eac9a434SRemi Bernon 1990c3962961SJiri Olsa if (!is_reg || sirc < 0) 19916da80ce8SDave Martin continue; 19926da80ce8SDave Martin 19933aafe5aeSCody P Schafer if (!syms_ss && symsrc__has_symtab(ss)) { 19943aafe5aeSCody P Schafer syms_ss = ss; 19953aafe5aeSCody P Schafer next_slot = true; 19960058aef6SAdrian Hunter if (!dso->symsrc_filename) 19970058aef6SAdrian Hunter dso->symsrc_filename = strdup(name); 1998d26cd12bSCody P Schafer } 1999d26cd12bSCody P Schafer 20003aafe5aeSCody P Schafer if (!runtime_ss && symsrc__possibly_runtime(ss)) { 20013aafe5aeSCody P Schafer runtime_ss = ss; 20023aafe5aeSCody P Schafer next_slot = true; 2003a44f605bSCody P Schafer } 200486470930SIngo Molnar 20053aafe5aeSCody P Schafer if (next_slot) { 20063aafe5aeSCody P Schafer ss_pos++; 200733ff581eSJiri Olsa 20083aafe5aeSCody P Schafer if (syms_ss && runtime_ss) 20096da80ce8SDave Martin break; 201098e9f03bSNamhyung Kim } else { 201198e9f03bSNamhyung Kim symsrc__destroy(ss); 2012a25e46c4SArnaldo Carvalho de Melo } 20133aafe5aeSCody P Schafer 20146da80ce8SDave Martin } 20156da80ce8SDave Martin 20163aafe5aeSCody P Schafer if (!runtime_ss && !syms_ss) 20173aafe5aeSCody P Schafer goto out_free; 20183aafe5aeSCody P Schafer 20193aafe5aeSCody P Schafer if (runtime_ss && !syms_ss) { 20203aafe5aeSCody P Schafer syms_ss = runtime_ss; 202160e4b10cSArnaldo Carvalho de Melo } 202260e4b10cSArnaldo Carvalho de Melo 20233aafe5aeSCody P Schafer /* We'll have to hope for the best */ 20243aafe5aeSCody P Schafer if (!runtime_ss && syms_ss) 20253aafe5aeSCody P Schafer runtime_ss = syms_ss; 20263aafe5aeSCody P Schafer 20271029f9feSNamhyung Kim if (syms_ss) 2028be39db9fSArnaldo Carvalho de Melo ret = dso__load_sym(dso, map, syms_ss, runtime_ss, kmod); 20291029f9feSNamhyung Kim else 20303aafe5aeSCody P Schafer ret = -1; 20313aafe5aeSCody P Schafer 2032f47b58b7SDavid Ahern if (ret > 0) { 20333aafe5aeSCody P Schafer int nr_plt; 20343aafe5aeSCody P Schafer 20353183f8caSArnaldo Carvalho de Melo nr_plt = dso__synthesize_plt_symbols(dso, runtime_ss); 20363aafe5aeSCody P Schafer if (nr_plt > 0) 20373aafe5aeSCody P Schafer ret += nr_plt; 20383aafe5aeSCody P Schafer } 20393aafe5aeSCody P Schafer 20403aafe5aeSCody P Schafer for (; ss_pos > 0; ss_pos--) 20413aafe5aeSCody P Schafer symsrc__destroy(&ss_[ss_pos - 1]); 20423aafe5aeSCody P Schafer out_free: 204386470930SIngo Molnar free(name); 2044aeafcbafSArnaldo Carvalho de Melo if (ret < 0 && strstr(dso->name, " (deleted)") != NULL) 20454a936edcSNamhyung Kim ret = 0; 20464a936edcSNamhyung Kim out: 20473183f8caSArnaldo Carvalho de Melo dso__set_loaded(dso); 2048d9a0d6b8SIan Rogers mutex_unlock(&dso->lock); 2049843ff37bSKrister Johansen nsinfo__mountns_exit(&nsc); 20504a936edcSNamhyung Kim 205186470930SIngo Molnar return ret; 205286470930SIngo Molnar } 205386470930SIngo Molnar 2054a7c2b572SArnaldo Carvalho de Melo static int map__strcmp(const void *a, const void *b) 2055a7c2b572SArnaldo Carvalho de Melo { 2056*392cf49eSIan Rogers const struct map *map_a = *(const struct map **)a; 2057*392cf49eSIan Rogers const struct map *map_b = *(const struct map **)b; 2058*392cf49eSIan Rogers const struct dso *dso_a = map__dso(map_a); 2059*392cf49eSIan Rogers const struct dso *dso_b = map__dso(map_b); 2060*392cf49eSIan Rogers int ret = strcmp(dso_a->short_name, dso_b->short_name); 206163df0e4bSIan Rogers 2062*392cf49eSIan Rogers if (ret == 0 && map_a != map_b) { 2063*392cf49eSIan Rogers /* 2064*392cf49eSIan Rogers * Ensure distinct but name equal maps have an order in part to 2065*392cf49eSIan Rogers * aid reference counting. 2066*392cf49eSIan Rogers */ 2067*392cf49eSIan Rogers ret = (int)map__start(map_a) - (int)map__start(map_b); 2068*392cf49eSIan Rogers if (ret == 0) 2069*392cf49eSIan Rogers ret = (int)((intptr_t)map_a - (intptr_t)map_b); 2070*392cf49eSIan Rogers } 2071*392cf49eSIan Rogers 2072*392cf49eSIan Rogers return ret; 2073a7c2b572SArnaldo Carvalho de Melo } 2074a7c2b572SArnaldo Carvalho de Melo 2075a7c2b572SArnaldo Carvalho de Melo static int map__strcmp_name(const void *name, const void *b) 2076a7c2b572SArnaldo Carvalho de Melo { 207763df0e4bSIan Rogers const struct dso *dso = map__dso(*(const struct map **)b); 207863df0e4bSIan Rogers 207963df0e4bSIan Rogers return strcmp(name, dso->short_name); 2080a7c2b572SArnaldo Carvalho de Melo } 2081a7c2b572SArnaldo Carvalho de Melo 20829a29ceeeSArnaldo Carvalho de Melo void __maps__sort_by_name(struct maps *maps) 2083a7c2b572SArnaldo Carvalho de Melo { 20845ab6d715SIan Rogers qsort(maps__maps_by_name(maps), maps__nr_maps(maps), sizeof(struct map *), map__strcmp); 2085a7c2b572SArnaldo Carvalho de Melo } 2086a7c2b572SArnaldo Carvalho de Melo 20879a29ceeeSArnaldo Carvalho de Melo static int map__groups__sort_by_name_from_rbtree(struct maps *maps) 2088a7c2b572SArnaldo Carvalho de Melo { 2089ff583dc4SIan Rogers struct map_rb_node *rb_node; 20905ab6d715SIan Rogers struct map **maps_by_name = realloc(maps__maps_by_name(maps), 20915ab6d715SIan Rogers maps__nr_maps(maps) * sizeof(struct map *)); 2092a7c2b572SArnaldo Carvalho de Melo int i = 0; 2093a7c2b572SArnaldo Carvalho de Melo 2094a7c2b572SArnaldo Carvalho de Melo if (maps_by_name == NULL) 2095a7c2b572SArnaldo Carvalho de Melo return -1; 2096a7c2b572SArnaldo Carvalho de Melo 20975ab6d715SIan Rogers up_read(maps__lock(maps)); 20985ab6d715SIan Rogers down_write(maps__lock(maps)); 2099ec9640f7SIan Rogers 21009a29ceeeSArnaldo Carvalho de Melo maps->maps_by_name = maps_by_name; 21015ab6d715SIan Rogers maps->nr_maps_allocated = maps__nr_maps(maps); 2102a7c2b572SArnaldo Carvalho de Melo 2103ff583dc4SIan Rogers maps__for_each_entry(maps, rb_node) 2104*392cf49eSIan Rogers maps_by_name[i++] = map__get(rb_node->map); 2105a7c2b572SArnaldo Carvalho de Melo 21069a29ceeeSArnaldo Carvalho de Melo __maps__sort_by_name(maps); 2107ec9640f7SIan Rogers 21085ab6d715SIan Rogers up_write(maps__lock(maps)); 21095ab6d715SIan Rogers down_read(maps__lock(maps)); 2110ec9640f7SIan Rogers 2111a7c2b572SArnaldo Carvalho de Melo return 0; 2112a7c2b572SArnaldo Carvalho de Melo } 2113a7c2b572SArnaldo Carvalho de Melo 21149a29ceeeSArnaldo Carvalho de Melo static struct map *__maps__find_by_name(struct maps *maps, const char *name) 2115a7c2b572SArnaldo Carvalho de Melo { 2116a7c2b572SArnaldo Carvalho de Melo struct map **mapp; 2117a7c2b572SArnaldo Carvalho de Melo 21185ab6d715SIan Rogers if (maps__maps_by_name(maps) == NULL && 21199a29ceeeSArnaldo Carvalho de Melo map__groups__sort_by_name_from_rbtree(maps)) 2120a7c2b572SArnaldo Carvalho de Melo return NULL; 2121a7c2b572SArnaldo Carvalho de Melo 21225ab6d715SIan Rogers mapp = bsearch(name, maps__maps_by_name(maps), maps__nr_maps(maps), 21235ab6d715SIan Rogers sizeof(*mapp), map__strcmp_name); 2124a7c2b572SArnaldo Carvalho de Melo if (mapp) 2125a7c2b572SArnaldo Carvalho de Melo return *mapp; 2126a7c2b572SArnaldo Carvalho de Melo return NULL; 2127a7c2b572SArnaldo Carvalho de Melo } 2128a7c2b572SArnaldo Carvalho de Melo 21299a29ceeeSArnaldo Carvalho de Melo struct map *maps__find_by_name(struct maps *maps, const char *name) 2130439d473bSArnaldo Carvalho de Melo { 2131ff583dc4SIan Rogers struct map_rb_node *rb_node; 21324bb7123dSArnaldo Carvalho de Melo struct map *map; 2133439d473bSArnaldo Carvalho de Melo 21345ab6d715SIan Rogers down_read(maps__lock(maps)); 21356a2ffcddSArnaldo Carvalho de Melo 213663df0e4bSIan Rogers if (maps->last_search_by_name) { 213763df0e4bSIan Rogers const struct dso *dso = map__dso(maps->last_search_by_name); 213863df0e4bSIan Rogers 213963df0e4bSIan Rogers if (strcmp(dso->short_name, name) == 0) { 21409a29ceeeSArnaldo Carvalho de Melo map = maps->last_search_by_name; 21416a2ffcddSArnaldo Carvalho de Melo goto out_unlock; 21421ae14516SArnaldo Carvalho de Melo } 214363df0e4bSIan Rogers } 2144a7c2b572SArnaldo Carvalho de Melo /* 21459a29ceeeSArnaldo Carvalho de Melo * If we have maps->maps_by_name, then the name isn't in the rbtree, 21469a29ceeeSArnaldo Carvalho de Melo * as maps->maps_by_name mirrors the rbtree when lookups by name are 2147a7c2b572SArnaldo Carvalho de Melo * made. 2148a7c2b572SArnaldo Carvalho de Melo */ 21499a29ceeeSArnaldo Carvalho de Melo map = __maps__find_by_name(maps, name); 21505ab6d715SIan Rogers if (map || maps__maps_by_name(maps) != NULL) 2151a7c2b572SArnaldo Carvalho de Melo goto out_unlock; 21521ae14516SArnaldo Carvalho de Melo 2153a7c2b572SArnaldo Carvalho de Melo /* Fallback to traversing the rbtree... */ 2154ff583dc4SIan Rogers maps__for_each_entry(maps, rb_node) { 215563df0e4bSIan Rogers struct dso *dso; 215663df0e4bSIan Rogers 2157ff583dc4SIan Rogers map = rb_node->map; 215863df0e4bSIan Rogers dso = map__dso(map); 215963df0e4bSIan Rogers if (strcmp(dso->short_name, name) == 0) { 21609a29ceeeSArnaldo Carvalho de Melo maps->last_search_by_name = map; 21611ae14516SArnaldo Carvalho de Melo goto out_unlock; 21621ae14516SArnaldo Carvalho de Melo } 2163ff583dc4SIan Rogers } 21646a2ffcddSArnaldo Carvalho de Melo map = NULL; 21656a2ffcddSArnaldo Carvalho de Melo 21666a2ffcddSArnaldo Carvalho de Melo out_unlock: 21675ab6d715SIan Rogers up_read(maps__lock(maps)); 21686a2ffcddSArnaldo Carvalho de Melo return map; 2169439d473bSArnaldo Carvalho de Melo } 2170439d473bSArnaldo Carvalho de Melo 2171aeafcbafSArnaldo Carvalho de Melo int dso__load_vmlinux(struct dso *dso, struct map *map, 2172be39db9fSArnaldo Carvalho de Melo const char *vmlinux, bool vmlinux_allocated) 217386470930SIngo Molnar { 2174b68e2f91SCody P Schafer int err = -1; 2175b68e2f91SCody P Schafer struct symsrc ss; 2176ec5761eaSDavid Ahern char symfs_vmlinux[PATH_MAX]; 2177005f9294SCody P Schafer enum dso_binary_type symtab_type; 217886470930SIngo Molnar 21795698d2c9SNamhyung Kim if (vmlinux[0] == '/') 21805698d2c9SNamhyung Kim snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s", vmlinux); 21815698d2c9SNamhyung Kim else 2182972f393bSArnaldo Carvalho de Melo symbol__join_symfs(symfs_vmlinux, vmlinux); 218386470930SIngo Molnar 21841c695c88SJiri Olsa if (dso->kernel == DSO_SPACE__KERNEL_GUEST) 2185005f9294SCody P Schafer symtab_type = DSO_BINARY_TYPE__GUEST_VMLINUX; 218621ea4539SCody P Schafer else 2187005f9294SCody P Schafer symtab_type = DSO_BINARY_TYPE__VMLINUX; 218821ea4539SCody P Schafer 2189005f9294SCody P Schafer if (symsrc__init(&ss, dso, symfs_vmlinux, symtab_type)) 2190b68e2f91SCody P Schafer return -1; 2191b68e2f91SCody P Schafer 2192be39db9fSArnaldo Carvalho de Melo err = dso__load_sym(dso, map, &ss, &ss, 0); 2193b68e2f91SCody P Schafer symsrc__destroy(&ss); 219486470930SIngo Molnar 2195515850e4SCody P Schafer if (err > 0) { 21961c695c88SJiri Olsa if (dso->kernel == DSO_SPACE__KERNEL_GUEST) 21975f70619dSArnaldo Carvalho de Melo dso->binary_type = DSO_BINARY_TYPE__GUEST_VMLINUX; 219839b12f78SAdrian Hunter else 21995f70619dSArnaldo Carvalho de Melo dso->binary_type = DSO_BINARY_TYPE__VMLINUX; 2200bf4414aeSArnaldo Carvalho de Melo dso__set_long_name(dso, vmlinux, vmlinux_allocated); 22013183f8caSArnaldo Carvalho de Melo dso__set_loaded(dso); 2202ec5761eaSDavid Ahern pr_debug("Using %s for symbols\n", symfs_vmlinux); 2203515850e4SCody P Schafer } 22043846df2eSArnaldo Carvalho de Melo 220586470930SIngo Molnar return err; 220686470930SIngo Molnar } 220786470930SIngo Molnar 2208be39db9fSArnaldo Carvalho de Melo int dso__load_vmlinux_path(struct dso *dso, struct map *map) 2209a19afe46SArnaldo Carvalho de Melo { 2210a19afe46SArnaldo Carvalho de Melo int i, err = 0; 221100dc8657SNamhyung Kim char *filename = NULL; 2212a19afe46SArnaldo Carvalho de Melo 2213dc38218eSArnaldo Carvalho de Melo pr_debug("Looking at the vmlinux_path (%d entries long)\n", 2214dc38218eSArnaldo Carvalho de Melo vmlinux_path__nr_entries + 1); 2215dc38218eSArnaldo Carvalho de Melo 2216dc38218eSArnaldo Carvalho de Melo for (i = 0; i < vmlinux_path__nr_entries; ++i) { 2217be39db9fSArnaldo Carvalho de Melo err = dso__load_vmlinux(dso, map, vmlinux_path[i], false); 2218dc38218eSArnaldo Carvalho de Melo if (err > 0) 2219dc38218eSArnaldo Carvalho de Melo goto out; 2220dc38218eSArnaldo Carvalho de Melo } 2221dc38218eSArnaldo Carvalho de Melo 222200dc8657SNamhyung Kim if (!symbol_conf.ignore_vmlinux_buildid) 2223d2396999SKrister Johansen filename = dso__build_id_filename(dso, NULL, 0, false); 22245ad90e4eSArnaldo Carvalho de Melo if (filename != NULL) { 2225be39db9fSArnaldo Carvalho de Melo err = dso__load_vmlinux(dso, map, filename, true); 22265230fb7dSArnaldo Carvalho de Melo if (err > 0) 22275ad90e4eSArnaldo Carvalho de Melo goto out; 22285ad90e4eSArnaldo Carvalho de Melo free(filename); 22295ad90e4eSArnaldo Carvalho de Melo } 22305ad90e4eSArnaldo Carvalho de Melo out: 2231a19afe46SArnaldo Carvalho de Melo return err; 2232a19afe46SArnaldo Carvalho de Melo } 2233a19afe46SArnaldo Carvalho de Melo 2234c48903b8SMasami Hiramatsu static bool visible_dir_filter(const char *name, struct dirent *d) 2235c48903b8SMasami Hiramatsu { 2236c48903b8SMasami Hiramatsu if (d->d_type != DT_DIR) 2237c48903b8SMasami Hiramatsu return false; 2238c48903b8SMasami Hiramatsu return lsdir_no_dot_filter(name, d); 2239c48903b8SMasami Hiramatsu } 2240c48903b8SMasami Hiramatsu 22410544d422SAdrian Hunter static int find_matching_kcore(struct map *map, char *dir, size_t dir_sz) 22420544d422SAdrian Hunter { 22430544d422SAdrian Hunter char kallsyms_filename[PATH_MAX]; 22440544d422SAdrian Hunter int ret = -1; 2245c48903b8SMasami Hiramatsu struct strlist *dirs; 2246c48903b8SMasami Hiramatsu struct str_node *nd; 22470544d422SAdrian Hunter 2248c48903b8SMasami Hiramatsu dirs = lsdir(dir, visible_dir_filter); 2249c48903b8SMasami Hiramatsu if (!dirs) 22500544d422SAdrian Hunter return -1; 22510544d422SAdrian Hunter 2252602a1f4dSArnaldo Carvalho de Melo strlist__for_each_entry(nd, dirs) { 22530544d422SAdrian Hunter scnprintf(kallsyms_filename, sizeof(kallsyms_filename), 2254c48903b8SMasami Hiramatsu "%s/%s/kallsyms", dir, nd->s); 2255a00d28cbSAdrian Hunter if (!validate_kcore_addresses(kallsyms_filename, map)) { 22560544d422SAdrian Hunter strlcpy(dir, kallsyms_filename, dir_sz); 22570544d422SAdrian Hunter ret = 0; 22580544d422SAdrian Hunter break; 22590544d422SAdrian Hunter } 22600544d422SAdrian Hunter } 22610544d422SAdrian Hunter 2262c48903b8SMasami Hiramatsu strlist__delete(dirs); 22630544d422SAdrian Hunter 22640544d422SAdrian Hunter return ret; 22650544d422SAdrian Hunter } 22660544d422SAdrian Hunter 226711870d71SMasami Hiramatsu /* 226811870d71SMasami Hiramatsu * Use open(O_RDONLY) to check readability directly instead of access(R_OK) 226911870d71SMasami Hiramatsu * since access(R_OK) only checks with real UID/GID but open() use effective 227011870d71SMasami Hiramatsu * UID/GID and actual capabilities (e.g. /proc/kcore requires CAP_SYS_RAWIO). 227111870d71SMasami Hiramatsu */ 227211870d71SMasami Hiramatsu static bool filename__readable(const char *file) 227311870d71SMasami Hiramatsu { 227411870d71SMasami Hiramatsu int fd = open(file, O_RDONLY); 227511870d71SMasami Hiramatsu if (fd < 0) 227611870d71SMasami Hiramatsu return false; 227711870d71SMasami Hiramatsu close(fd); 227811870d71SMasami Hiramatsu return true; 227911870d71SMasami Hiramatsu } 228011870d71SMasami Hiramatsu 22810544d422SAdrian Hunter static char *dso__find_kallsyms(struct dso *dso, struct map *map) 22820544d422SAdrian Hunter { 22833ff1b8c8SJiri Olsa struct build_id bid; 2284b5d8bbe8SMasami Hiramatsu char sbuild_id[SBUILD_ID_SIZE]; 22850544d422SAdrian Hunter bool is_host = false; 22860544d422SAdrian Hunter char path[PATH_MAX]; 22870544d422SAdrian Hunter 22880544d422SAdrian Hunter if (!dso->has_build_id) { 22890544d422SAdrian Hunter /* 22900544d422SAdrian Hunter * Last resort, if we don't have a build-id and couldn't find 22910544d422SAdrian Hunter * any vmlinux file, try the running kernel kallsyms table. 22920544d422SAdrian Hunter */ 22930544d422SAdrian Hunter goto proc_kallsyms; 22940544d422SAdrian Hunter } 22950544d422SAdrian Hunter 22963ff1b8c8SJiri Olsa if (sysfs__read_build_id("/sys/kernel/notes", &bid) == 0) 229739be8d01SJiri Olsa is_host = dso__build_id_equal(dso, &bid); 22980544d422SAdrian Hunter 22994e4b6c06SMasami Hiramatsu /* Try a fast path for /proc/kallsyms if possible */ 23000544d422SAdrian Hunter if (is_host) { 23010544d422SAdrian Hunter /* 230211870d71SMasami Hiramatsu * Do not check the build-id cache, unless we know we cannot use 230311870d71SMasami Hiramatsu * /proc/kcore or module maps don't match to /proc/kallsyms. 230411870d71SMasami Hiramatsu * To check readability of /proc/kcore, do not use access(R_OK) 230511870d71SMasami Hiramatsu * since /proc/kcore requires CAP_SYS_RAWIO to read and access 230611870d71SMasami Hiramatsu * can't check it. 23070544d422SAdrian Hunter */ 230811870d71SMasami Hiramatsu if (filename__readable("/proc/kcore") && 230911870d71SMasami Hiramatsu !validate_kcore_addresses("/proc/kallsyms", map)) 23100544d422SAdrian Hunter goto proc_kallsyms; 23110544d422SAdrian Hunter } 23120544d422SAdrian Hunter 2313bf541169SJiri Olsa build_id__sprintf(&dso->bid, sbuild_id); 23144e4b6c06SMasami Hiramatsu 2315449867e3SAdrian Hunter /* Find kallsyms in build-id cache with kcore */ 23164e4b6c06SMasami Hiramatsu scnprintf(path, sizeof(path), "%s/%s/%s", 23174e4b6c06SMasami Hiramatsu buildid_dir, DSO__NAME_KCORE, sbuild_id); 23184e4b6c06SMasami Hiramatsu 2319449867e3SAdrian Hunter if (!find_matching_kcore(map, path, sizeof(path))) 2320449867e3SAdrian Hunter return strdup(path); 2321449867e3SAdrian Hunter 23224e4b6c06SMasami Hiramatsu /* Use current /proc/kallsyms if possible */ 23234e4b6c06SMasami Hiramatsu if (is_host) { 23244e4b6c06SMasami Hiramatsu proc_kallsyms: 23254e4b6c06SMasami Hiramatsu return strdup("/proc/kallsyms"); 23264e4b6c06SMasami Hiramatsu } 23274e4b6c06SMasami Hiramatsu 23284e4b6c06SMasami Hiramatsu /* Finally, find a cache of kallsyms */ 232901412261SMasami Hiramatsu if (!build_id_cache__kallsyms_path(sbuild_id, path, sizeof(path))) { 23300544d422SAdrian Hunter pr_err("No kallsyms or vmlinux with build-id %s was found\n", 23310544d422SAdrian Hunter sbuild_id); 23320544d422SAdrian Hunter return NULL; 23330544d422SAdrian Hunter } 23340544d422SAdrian Hunter 23350544d422SAdrian Hunter return strdup(path); 23360544d422SAdrian Hunter } 23370544d422SAdrian Hunter 2338be39db9fSArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *dso, struct map *map) 233986470930SIngo Molnar { 2340cc612d81SArnaldo Carvalho de Melo int err; 23419e201442SArnaldo Carvalho de Melo const char *kallsyms_filename = NULL; 23429e201442SArnaldo Carvalho de Melo char *kallsyms_allocated_filename = NULL; 2343ca8ea73aSJiri Olsa char *filename = NULL; 2344ca8ea73aSJiri Olsa 2345dc8d6ab2SArnaldo Carvalho de Melo /* 2346b226a5a7SDavid Ahern * Step 1: if the user specified a kallsyms or vmlinux filename, use 2347b226a5a7SDavid Ahern * it and only it, reporting errors to the user if it cannot be used. 2348dc8d6ab2SArnaldo Carvalho de Melo * 2349dc8d6ab2SArnaldo Carvalho de Melo * For instance, try to analyse an ARM perf.data file _without_ a 2350dc8d6ab2SArnaldo Carvalho de Melo * build-id, or if the user specifies the wrong path to the right 2351dc8d6ab2SArnaldo Carvalho de Melo * vmlinux file, obviously we can't fallback to another vmlinux (a 2352dc8d6ab2SArnaldo Carvalho de Melo * x86_86 one, on the machine where analysis is being performed, say), 2353dc8d6ab2SArnaldo Carvalho de Melo * or worse, /proc/kallsyms. 2354dc8d6ab2SArnaldo Carvalho de Melo * 2355dc8d6ab2SArnaldo Carvalho de Melo * If the specified file _has_ a build-id and there is a build-id 2356dc8d6ab2SArnaldo Carvalho de Melo * section in the perf.data file, we will still do the expected 2357dc8d6ab2SArnaldo Carvalho de Melo * validation in dso__load_vmlinux and will bail out if they don't 2358dc8d6ab2SArnaldo Carvalho de Melo * match. 2359dc8d6ab2SArnaldo Carvalho de Melo */ 2360b226a5a7SDavid Ahern if (symbol_conf.kallsyms_name != NULL) { 2361b226a5a7SDavid Ahern kallsyms_filename = symbol_conf.kallsyms_name; 2362b226a5a7SDavid Ahern goto do_kallsyms; 2363b226a5a7SDavid Ahern } 2364b226a5a7SDavid Ahern 2365fc2be696SWilly Tarreau if (!symbol_conf.ignore_vmlinux && symbol_conf.vmlinux_name != NULL) { 2366be39db9fSArnaldo Carvalho de Melo return dso__load_vmlinux(dso, map, symbol_conf.vmlinux_name, false); 2367dc8d6ab2SArnaldo Carvalho de Melo } 2368439d473bSArnaldo Carvalho de Melo 2369ca8ea73aSJiri Olsa /* 2370ca8ea73aSJiri Olsa * Before checking on common vmlinux locations, check if it's 2371ca8ea73aSJiri Olsa * stored as standard build id binary (not kallsyms) under 2372ca8ea73aSJiri Olsa * .debug cache. 2373ca8ea73aSJiri Olsa */ 2374ca8ea73aSJiri Olsa if (!symbol_conf.ignore_vmlinux_buildid) 2375ca8ea73aSJiri Olsa filename = __dso__build_id_filename(dso, NULL, 0, false, false); 2376ca8ea73aSJiri Olsa if (filename != NULL) { 2377ca8ea73aSJiri Olsa err = dso__load_vmlinux(dso, map, filename, true); 2378ca8ea73aSJiri Olsa if (err > 0) 2379ca8ea73aSJiri Olsa return err; 2380ca8ea73aSJiri Olsa free(filename); 2381ca8ea73aSJiri Olsa } 2382ca8ea73aSJiri Olsa 2383fc2be696SWilly Tarreau if (!symbol_conf.ignore_vmlinux && vmlinux_path != NULL) { 2384be39db9fSArnaldo Carvalho de Melo err = dso__load_vmlinux_path(dso, map); 2385a19afe46SArnaldo Carvalho de Melo if (err > 0) 238639b12f78SAdrian Hunter return err; 2387cc612d81SArnaldo Carvalho de Melo } 2388cc612d81SArnaldo Carvalho de Melo 2389ec5761eaSDavid Ahern /* do not try local files if a symfs was given */ 2390ec5761eaSDavid Ahern if (symbol_conf.symfs[0] != 0) 2391ec5761eaSDavid Ahern return -1; 2392ec5761eaSDavid Ahern 23930544d422SAdrian Hunter kallsyms_allocated_filename = dso__find_kallsyms(dso, map); 23940544d422SAdrian Hunter if (!kallsyms_allocated_filename) 23958d0591f6SArnaldo Carvalho de Melo return -1; 23968d0591f6SArnaldo Carvalho de Melo 239719fc2dedSArnaldo Carvalho de Melo kallsyms_filename = kallsyms_allocated_filename; 239819fc2dedSArnaldo Carvalho de Melo 2399dc8d6ab2SArnaldo Carvalho de Melo do_kallsyms: 2400be39db9fSArnaldo Carvalho de Melo err = dso__load_kallsyms(dso, kallsyms_filename, map); 24013846df2eSArnaldo Carvalho de Melo if (err > 0) 24023846df2eSArnaldo Carvalho de Melo pr_debug("Using %s for symbols\n", kallsyms_filename); 2403dc8d6ab2SArnaldo Carvalho de Melo free(kallsyms_allocated_filename); 2404dc8d6ab2SArnaldo Carvalho de Melo 24058e0cf965SAdrian Hunter if (err > 0 && !dso__is_kcore(dso)) { 2406bdac0bcfSAdrian Hunter dso->binary_type = DSO_BINARY_TYPE__KALLSYMS; 24070a77582fSMasami Hiramatsu dso__set_long_name(dso, DSO__NAME_KALLSYMS, false); 24086a4694a4SArnaldo Carvalho de Melo map__fixup_start(map); 24096a4694a4SArnaldo Carvalho de Melo map__fixup_end(map); 2410439d473bSArnaldo Carvalho de Melo } 241194cb9e38SArnaldo Carvalho de Melo 241286470930SIngo Molnar return err; 241386470930SIngo Molnar } 241486470930SIngo Molnar 2415be39db9fSArnaldo Carvalho de Melo static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map) 2416a1645ce1SZhang, Yanmin { 2417a1645ce1SZhang, Yanmin int err; 2418a5367ecbSAdrian Hunter const char *kallsyms_filename; 24195ab6d715SIan Rogers struct machine *machine = maps__machine(map__kmaps(map)); 2420a1645ce1SZhang, Yanmin char path[PATH_MAX]; 2421a1645ce1SZhang, Yanmin 2422a5367ecbSAdrian Hunter if (machine->kallsyms_filename) { 2423a5367ecbSAdrian Hunter kallsyms_filename = machine->kallsyms_filename; 2424a5367ecbSAdrian Hunter } else if (machine__is_default_guest(machine)) { 2425a1645ce1SZhang, Yanmin /* 2426a1645ce1SZhang, Yanmin * if the user specified a vmlinux filename, use it and only 2427a1645ce1SZhang, Yanmin * it, reporting errors to the user if it cannot be used. 2428a1645ce1SZhang, Yanmin * Or use file guest_kallsyms inputted by user on commandline 2429a1645ce1SZhang, Yanmin */ 2430a1645ce1SZhang, Yanmin if (symbol_conf.default_guest_vmlinux_name != NULL) { 2431aeafcbafSArnaldo Carvalho de Melo err = dso__load_vmlinux(dso, map, 24325230fb7dSArnaldo Carvalho de Melo symbol_conf.default_guest_vmlinux_name, 2433be39db9fSArnaldo Carvalho de Melo false); 243439b12f78SAdrian Hunter return err; 2435a1645ce1SZhang, Yanmin } 2436a1645ce1SZhang, Yanmin 2437a1645ce1SZhang, Yanmin kallsyms_filename = symbol_conf.default_guest_kallsyms; 2438a1645ce1SZhang, Yanmin if (!kallsyms_filename) 2439a1645ce1SZhang, Yanmin return -1; 2440a1645ce1SZhang, Yanmin } else { 244123346f21SArnaldo Carvalho de Melo sprintf(path, "%s/proc/kallsyms", machine->root_dir); 2442a1645ce1SZhang, Yanmin kallsyms_filename = path; 2443a1645ce1SZhang, Yanmin } 2444a1645ce1SZhang, Yanmin 2445be39db9fSArnaldo Carvalho de Melo err = dso__load_kallsyms(dso, kallsyms_filename, map); 24468e0cf965SAdrian Hunter if (err > 0) 244739b12f78SAdrian Hunter pr_debug("Using %s for symbols\n", kallsyms_filename); 24488e0cf965SAdrian Hunter if (err > 0 && !dso__is_kcore(dso)) { 2449bdac0bcfSAdrian Hunter dso->binary_type = DSO_BINARY_TYPE__GUEST_KALLSYMS; 24508c7f1bb3SJiri Olsa dso__set_long_name(dso, machine->mmap_name, false); 2451a1645ce1SZhang, Yanmin map__fixup_start(map); 2452a1645ce1SZhang, Yanmin map__fixup_end(map); 2453a1645ce1SZhang, Yanmin } 2454a1645ce1SZhang, Yanmin 2455a1645ce1SZhang, Yanmin return err; 2456a1645ce1SZhang, Yanmin } 2457cd84c2acSFrederic Weisbecker 2458cc612d81SArnaldo Carvalho de Melo static void vmlinux_path__exit(void) 24592446042cSArnaldo Carvalho de Melo { 246004662523SArnaldo Carvalho de Melo while (--vmlinux_path__nr_entries >= 0) 246104662523SArnaldo Carvalho de Melo zfree(&vmlinux_path[vmlinux_path__nr_entries]); 2462c4f03547SWang Nan vmlinux_path__nr_entries = 0; 2463cc612d81SArnaldo Carvalho de Melo 246404662523SArnaldo Carvalho de Melo zfree(&vmlinux_path); 2465cc612d81SArnaldo Carvalho de Melo } 2466cc612d81SArnaldo Carvalho de Melo 2467aac48647SEkaterina Tumanova static const char * const vmlinux_paths[] = { 2468aac48647SEkaterina Tumanova "vmlinux", 2469aac48647SEkaterina Tumanova "/boot/vmlinux" 2470aac48647SEkaterina Tumanova }; 2471aac48647SEkaterina Tumanova 2472aac48647SEkaterina Tumanova static const char * const vmlinux_paths_upd[] = { 2473aac48647SEkaterina Tumanova "/boot/vmlinux-%s", 2474aac48647SEkaterina Tumanova "/usr/lib/debug/boot/vmlinux-%s", 2475aac48647SEkaterina Tumanova "/lib/modules/%s/build/vmlinux", 2476f55ae954SEkaterina Tumanova "/usr/lib/debug/lib/modules/%s/vmlinux", 2477f55ae954SEkaterina Tumanova "/usr/lib/debug/boot/vmlinux-%s.debug" 2478aac48647SEkaterina Tumanova }; 2479aac48647SEkaterina Tumanova 2480aac48647SEkaterina Tumanova static int vmlinux_path__add(const char *new_entry) 2481aac48647SEkaterina Tumanova { 2482aac48647SEkaterina Tumanova vmlinux_path[vmlinux_path__nr_entries] = strdup(new_entry); 2483aac48647SEkaterina Tumanova if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 2484aac48647SEkaterina Tumanova return -1; 2485aac48647SEkaterina Tumanova ++vmlinux_path__nr_entries; 2486aac48647SEkaterina Tumanova 2487aac48647SEkaterina Tumanova return 0; 2488aac48647SEkaterina Tumanova } 2489aac48647SEkaterina Tumanova 2490ce80d3beSKan Liang static int vmlinux_path__init(struct perf_env *env) 2491cc612d81SArnaldo Carvalho de Melo { 2492cc612d81SArnaldo Carvalho de Melo struct utsname uts; 2493cc612d81SArnaldo Carvalho de Melo char bf[PATH_MAX]; 24940a7e6d1bSNamhyung Kim char *kernel_version; 2495aac48647SEkaterina Tumanova unsigned int i; 2496cc612d81SArnaldo Carvalho de Melo 2497aac48647SEkaterina Tumanova vmlinux_path = malloc(sizeof(char *) * (ARRAY_SIZE(vmlinux_paths) + 2498aac48647SEkaterina Tumanova ARRAY_SIZE(vmlinux_paths_upd))); 2499cc612d81SArnaldo Carvalho de Melo if (vmlinux_path == NULL) 2500cc612d81SArnaldo Carvalho de Melo return -1; 2501cc612d81SArnaldo Carvalho de Melo 2502aac48647SEkaterina Tumanova for (i = 0; i < ARRAY_SIZE(vmlinux_paths); i++) 2503aac48647SEkaterina Tumanova if (vmlinux_path__add(vmlinux_paths[i]) < 0) 2504cc612d81SArnaldo Carvalho de Melo goto out_fail; 2505ec5761eaSDavid Ahern 25060a7e6d1bSNamhyung Kim /* only try kernel version if no symfs was given */ 2507ec5761eaSDavid Ahern if (symbol_conf.symfs[0] != 0) 2508ec5761eaSDavid Ahern return 0; 2509ec5761eaSDavid Ahern 25100a7e6d1bSNamhyung Kim if (env) { 25110a7e6d1bSNamhyung Kim kernel_version = env->os_release; 25120a7e6d1bSNamhyung Kim } else { 2513ec5761eaSDavid Ahern if (uname(&uts) < 0) 2514e96c674fSNamhyung Kim goto out_fail; 2515ec5761eaSDavid Ahern 25160a7e6d1bSNamhyung Kim kernel_version = uts.release; 25170a7e6d1bSNamhyung Kim } 25180a7e6d1bSNamhyung Kim 2519aac48647SEkaterina Tumanova for (i = 0; i < ARRAY_SIZE(vmlinux_paths_upd); i++) { 2520aac48647SEkaterina Tumanova snprintf(bf, sizeof(bf), vmlinux_paths_upd[i], kernel_version); 2521aac48647SEkaterina Tumanova if (vmlinux_path__add(bf) < 0) 2522cc612d81SArnaldo Carvalho de Melo goto out_fail; 2523aac48647SEkaterina Tumanova } 2524cc612d81SArnaldo Carvalho de Melo 2525cc612d81SArnaldo Carvalho de Melo return 0; 2526cc612d81SArnaldo Carvalho de Melo 2527cc612d81SArnaldo Carvalho de Melo out_fail: 2528cc612d81SArnaldo Carvalho de Melo vmlinux_path__exit(); 2529cc612d81SArnaldo Carvalho de Melo return -1; 2530cc612d81SArnaldo Carvalho de Melo } 2531cc612d81SArnaldo Carvalho de Melo 25323bfe5f81SDavid Ahern int setup_list(struct strlist **list, const char *list_str, 2533655000e7SArnaldo Carvalho de Melo const char *list_name) 2534655000e7SArnaldo Carvalho de Melo { 2535655000e7SArnaldo Carvalho de Melo if (list_str == NULL) 2536655000e7SArnaldo Carvalho de Melo return 0; 2537655000e7SArnaldo Carvalho de Melo 25384a77e218SArnaldo Carvalho de Melo *list = strlist__new(list_str, NULL); 2539655000e7SArnaldo Carvalho de Melo if (!*list) { 2540655000e7SArnaldo Carvalho de Melo pr_err("problems parsing %s list\n", list_name); 2541655000e7SArnaldo Carvalho de Melo return -1; 2542655000e7SArnaldo Carvalho de Melo } 25430bc2f2f7SArnaldo Carvalho de Melo 25440bc2f2f7SArnaldo Carvalho de Melo symbol_conf.has_filter = true; 2545655000e7SArnaldo Carvalho de Melo return 0; 2546655000e7SArnaldo Carvalho de Melo } 2547655000e7SArnaldo Carvalho de Melo 2548e03eaa40SDavid Ahern int setup_intlist(struct intlist **list, const char *list_str, 2549e03eaa40SDavid Ahern const char *list_name) 2550e03eaa40SDavid Ahern { 2551e03eaa40SDavid Ahern if (list_str == NULL) 2552e03eaa40SDavid Ahern return 0; 2553e03eaa40SDavid Ahern 2554e03eaa40SDavid Ahern *list = intlist__new(list_str); 2555e03eaa40SDavid Ahern if (!*list) { 2556e03eaa40SDavid Ahern pr_err("problems parsing %s list\n", list_name); 2557e03eaa40SDavid Ahern return -1; 2558e03eaa40SDavid Ahern } 2559e03eaa40SDavid Ahern return 0; 2560e03eaa40SDavid Ahern } 2561e03eaa40SDavid Ahern 256261d9fc44SJin Yao static int setup_addrlist(struct intlist **addr_list, struct strlist *sym_list) 256361d9fc44SJin Yao { 256461d9fc44SJin Yao struct str_node *pos, *tmp; 256561d9fc44SJin Yao unsigned long val; 256661d9fc44SJin Yao char *sep; 256761d9fc44SJin Yao const char *end; 256861d9fc44SJin Yao int i = 0, err; 256961d9fc44SJin Yao 257061d9fc44SJin Yao *addr_list = intlist__new(NULL); 257161d9fc44SJin Yao if (!*addr_list) 257261d9fc44SJin Yao return -1; 257361d9fc44SJin Yao 257461d9fc44SJin Yao strlist__for_each_entry_safe(pos, tmp, sym_list) { 257561d9fc44SJin Yao errno = 0; 257661d9fc44SJin Yao val = strtoul(pos->s, &sep, 16); 257761d9fc44SJin Yao if (errno || (sep == pos->s)) 257861d9fc44SJin Yao continue; 257961d9fc44SJin Yao 258061d9fc44SJin Yao if (*sep != '\0') { 258161d9fc44SJin Yao end = pos->s + strlen(pos->s) - 1; 258261d9fc44SJin Yao while (end >= sep && isspace(*end)) 258361d9fc44SJin Yao end--; 258461d9fc44SJin Yao 258561d9fc44SJin Yao if (end >= sep) 258661d9fc44SJin Yao continue; 258761d9fc44SJin Yao } 258861d9fc44SJin Yao 258961d9fc44SJin Yao err = intlist__add(*addr_list, val); 259061d9fc44SJin Yao if (err) 259161d9fc44SJin Yao break; 259261d9fc44SJin Yao 259361d9fc44SJin Yao strlist__remove(sym_list, pos); 259461d9fc44SJin Yao i++; 259561d9fc44SJin Yao } 259661d9fc44SJin Yao 259761d9fc44SJin Yao if (i == 0) { 259861d9fc44SJin Yao intlist__delete(*addr_list); 259961d9fc44SJin Yao *addr_list = NULL; 260061d9fc44SJin Yao } 260161d9fc44SJin Yao 260261d9fc44SJin Yao return 0; 260361d9fc44SJin Yao } 260461d9fc44SJin Yao 2605ec80fde7SArnaldo Carvalho de Melo static bool symbol__read_kptr_restrict(void) 2606ec80fde7SArnaldo Carvalho de Melo { 2607ec80fde7SArnaldo Carvalho de Melo bool value = false; 2608ec80fde7SArnaldo Carvalho de Melo FILE *fp = fopen("/proc/sys/kernel/kptr_restrict", "r"); 260938272dc4SWang Nan 2610ec80fde7SArnaldo Carvalho de Melo if (fp != NULL) { 2611ec80fde7SArnaldo Carvalho de Melo char line[8]; 2612ec80fde7SArnaldo Carvalho de Melo 2613ec80fde7SArnaldo Carvalho de Melo if (fgets(line, sizeof(line), fp) != NULL) 26148859aedeSIgor Lubashev value = perf_cap__capable(CAP_SYSLOG) ? 26158859aedeSIgor Lubashev (atoi(line) >= 2) : 26168859aedeSIgor Lubashev (atoi(line) != 0); 2617ec80fde7SArnaldo Carvalho de Melo 2618ec80fde7SArnaldo Carvalho de Melo fclose(fp); 2619ec80fde7SArnaldo Carvalho de Melo } 2620ec80fde7SArnaldo Carvalho de Melo 26218859aedeSIgor Lubashev /* Per kernel/kallsyms.c: 26228859aedeSIgor Lubashev * we also restrict when perf_event_paranoid > 1 w/o CAP_SYSLOG 26238859aedeSIgor Lubashev */ 26248859aedeSIgor Lubashev if (perf_event_paranoid() > 1 && !perf_cap__capable(CAP_SYSLOG)) 26258859aedeSIgor Lubashev value = true; 26268859aedeSIgor Lubashev 2627ec80fde7SArnaldo Carvalho de Melo return value; 2628ec80fde7SArnaldo Carvalho de Melo } 2629ec80fde7SArnaldo Carvalho de Melo 2630b01141f4SArnaldo Carvalho de Melo int symbol__annotation_init(void) 2631b01141f4SArnaldo Carvalho de Melo { 26327b366142SArnaldo Carvalho de Melo if (symbol_conf.init_annotation) 26337b366142SArnaldo Carvalho de Melo return 0; 26347b366142SArnaldo Carvalho de Melo 2635b01141f4SArnaldo Carvalho de Melo if (symbol_conf.initialized) { 2636b01141f4SArnaldo Carvalho de Melo pr_err("Annotation needs to be init before symbol__init()\n"); 2637b01141f4SArnaldo Carvalho de Melo return -1; 2638b01141f4SArnaldo Carvalho de Melo } 2639b01141f4SArnaldo Carvalho de Melo 2640b01141f4SArnaldo Carvalho de Melo symbol_conf.priv_size += sizeof(struct annotation); 2641b01141f4SArnaldo Carvalho de Melo symbol_conf.init_annotation = true; 2642b01141f4SArnaldo Carvalho de Melo return 0; 2643b01141f4SArnaldo Carvalho de Melo } 2644b01141f4SArnaldo Carvalho de Melo 2645ce80d3beSKan Liang int symbol__init(struct perf_env *env) 2646cc612d81SArnaldo Carvalho de Melo { 2647ec5761eaSDavid Ahern const char *symfs; 2648ec5761eaSDavid Ahern 264985e00b55SJovi Zhang if (symbol_conf.initialized) 265085e00b55SJovi Zhang return 0; 265185e00b55SJovi Zhang 26529ac3e487SIrina Tirdea symbol_conf.priv_size = PERF_ALIGN(symbol_conf.priv_size, sizeof(u64)); 26534d439517SDavid S. Miller 2654166ccc9cSNamhyung Kim symbol__elf_init(); 2655166ccc9cSNamhyung Kim 265675be6cf4SArnaldo Carvalho de Melo if (symbol_conf.sort_by_name) 265775be6cf4SArnaldo Carvalho de Melo symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) - 265879406cd7SArnaldo Carvalho de Melo sizeof(struct symbol)); 2659b32d133aSArnaldo Carvalho de Melo 26600a7e6d1bSNamhyung Kim if (symbol_conf.try_vmlinux_path && vmlinux_path__init(env) < 0) 2661cc612d81SArnaldo Carvalho de Melo return -1; 2662cc612d81SArnaldo Carvalho de Melo 2663c410a338SArnaldo Carvalho de Melo if (symbol_conf.field_sep && *symbol_conf.field_sep == '.') { 2664c410a338SArnaldo Carvalho de Melo pr_err("'.' is the only non valid --field-separator argument\n"); 2665c410a338SArnaldo Carvalho de Melo return -1; 2666c410a338SArnaldo Carvalho de Melo } 2667c410a338SArnaldo Carvalho de Melo 2668655000e7SArnaldo Carvalho de Melo if (setup_list(&symbol_conf.dso_list, 2669655000e7SArnaldo Carvalho de Melo symbol_conf.dso_list_str, "dso") < 0) 2670655000e7SArnaldo Carvalho de Melo return -1; 2671655000e7SArnaldo Carvalho de Melo 2672655000e7SArnaldo Carvalho de Melo if (setup_list(&symbol_conf.comm_list, 2673655000e7SArnaldo Carvalho de Melo symbol_conf.comm_list_str, "comm") < 0) 2674655000e7SArnaldo Carvalho de Melo goto out_free_dso_list; 2675655000e7SArnaldo Carvalho de Melo 2676e03eaa40SDavid Ahern if (setup_intlist(&symbol_conf.pid_list, 2677e03eaa40SDavid Ahern symbol_conf.pid_list_str, "pid") < 0) 2678e03eaa40SDavid Ahern goto out_free_comm_list; 2679e03eaa40SDavid Ahern 2680e03eaa40SDavid Ahern if (setup_intlist(&symbol_conf.tid_list, 2681e03eaa40SDavid Ahern symbol_conf.tid_list_str, "tid") < 0) 2682e03eaa40SDavid Ahern goto out_free_pid_list; 2683e03eaa40SDavid Ahern 2684655000e7SArnaldo Carvalho de Melo if (setup_list(&symbol_conf.sym_list, 2685655000e7SArnaldo Carvalho de Melo symbol_conf.sym_list_str, "symbol") < 0) 2686e03eaa40SDavid Ahern goto out_free_tid_list; 2687655000e7SArnaldo Carvalho de Melo 268861d9fc44SJin Yao if (symbol_conf.sym_list && 268961d9fc44SJin Yao setup_addrlist(&symbol_conf.addr_list, symbol_conf.sym_list) < 0) 269061d9fc44SJin Yao goto out_free_sym_list; 269161d9fc44SJin Yao 269264eff7d9SDavid Ahern if (setup_list(&symbol_conf.bt_stop_list, 269364eff7d9SDavid Ahern symbol_conf.bt_stop_list_str, "symbol") < 0) 269464eff7d9SDavid Ahern goto out_free_sym_list; 269564eff7d9SDavid Ahern 2696ec5761eaSDavid Ahern /* 2697ec5761eaSDavid Ahern * A path to symbols of "/" is identical to "" 2698ec5761eaSDavid Ahern * reset here for simplicity. 2699ec5761eaSDavid Ahern */ 2700ec5761eaSDavid Ahern symfs = realpath(symbol_conf.symfs, NULL); 2701ec5761eaSDavid Ahern if (symfs == NULL) 2702ec5761eaSDavid Ahern symfs = symbol_conf.symfs; 2703ec5761eaSDavid Ahern if (strcmp(symfs, "/") == 0) 2704ec5761eaSDavid Ahern symbol_conf.symfs = ""; 2705ec5761eaSDavid Ahern if (symfs != symbol_conf.symfs) 2706ec5761eaSDavid Ahern free((void *)symfs); 2707ec5761eaSDavid Ahern 2708ec80fde7SArnaldo Carvalho de Melo symbol_conf.kptr_restrict = symbol__read_kptr_restrict(); 2709ec80fde7SArnaldo Carvalho de Melo 271085e00b55SJovi Zhang symbol_conf.initialized = true; 27114aa65636SArnaldo Carvalho de Melo return 0; 2712655000e7SArnaldo Carvalho de Melo 271364eff7d9SDavid Ahern out_free_sym_list: 271464eff7d9SDavid Ahern strlist__delete(symbol_conf.sym_list); 271561d9fc44SJin Yao intlist__delete(symbol_conf.addr_list); 2716e03eaa40SDavid Ahern out_free_tid_list: 2717e03eaa40SDavid Ahern intlist__delete(symbol_conf.tid_list); 2718e03eaa40SDavid Ahern out_free_pid_list: 2719e03eaa40SDavid Ahern intlist__delete(symbol_conf.pid_list); 2720655000e7SArnaldo Carvalho de Melo out_free_comm_list: 2721655000e7SArnaldo Carvalho de Melo strlist__delete(symbol_conf.comm_list); 2722d74c896bSNamhyung Kim out_free_dso_list: 2723d74c896bSNamhyung Kim strlist__delete(symbol_conf.dso_list); 2724655000e7SArnaldo Carvalho de Melo return -1; 2725cc612d81SArnaldo Carvalho de Melo } 2726cc612d81SArnaldo Carvalho de Melo 2727d65a458bSArnaldo Carvalho de Melo void symbol__exit(void) 2728d65a458bSArnaldo Carvalho de Melo { 272985e00b55SJovi Zhang if (!symbol_conf.initialized) 273085e00b55SJovi Zhang return; 273164eff7d9SDavid Ahern strlist__delete(symbol_conf.bt_stop_list); 2732d65a458bSArnaldo Carvalho de Melo strlist__delete(symbol_conf.sym_list); 2733d65a458bSArnaldo Carvalho de Melo strlist__delete(symbol_conf.dso_list); 2734d65a458bSArnaldo Carvalho de Melo strlist__delete(symbol_conf.comm_list); 2735e03eaa40SDavid Ahern intlist__delete(symbol_conf.tid_list); 2736e03eaa40SDavid Ahern intlist__delete(symbol_conf.pid_list); 273761d9fc44SJin Yao intlist__delete(symbol_conf.addr_list); 2738d65a458bSArnaldo Carvalho de Melo vmlinux_path__exit(); 2739d65a458bSArnaldo Carvalho de Melo symbol_conf.sym_list = symbol_conf.dso_list = symbol_conf.comm_list = NULL; 274064eff7d9SDavid Ahern symbol_conf.bt_stop_list = NULL; 274185e00b55SJovi Zhang symbol_conf.initialized = false; 2742d65a458bSArnaldo Carvalho de Melo } 2743a7066709SHe Kuang 2744a7066709SHe Kuang int symbol__config_symfs(const struct option *opt __maybe_unused, 2745a7066709SHe Kuang const char *dir, int unset __maybe_unused) 2746a7066709SHe Kuang { 2747a7066709SHe Kuang char *bf = NULL; 2748a7066709SHe Kuang int ret; 2749a7066709SHe Kuang 2750a7066709SHe Kuang symbol_conf.symfs = strdup(dir); 2751a7066709SHe Kuang if (symbol_conf.symfs == NULL) 2752a7066709SHe Kuang return -ENOMEM; 2753a7066709SHe Kuang 2754a7066709SHe Kuang /* skip the locally configured cache if a symfs is given, and 2755a7066709SHe Kuang * config buildid dir to symfs/.debug 2756a7066709SHe Kuang */ 2757a7066709SHe Kuang ret = asprintf(&bf, "%s/%s", dir, ".debug"); 2758a7066709SHe Kuang if (ret < 0) 2759a7066709SHe Kuang return -ENOMEM; 2760a7066709SHe Kuang 2761a7066709SHe Kuang set_buildid_dir(bf); 2762a7066709SHe Kuang 2763a7066709SHe Kuang free(bf); 2764a7066709SHe Kuang return 0; 2765a7066709SHe Kuang } 27669f87498fSJiri Olsa 27679f87498fSJiri Olsa struct mem_info *mem_info__get(struct mem_info *mi) 27689f87498fSJiri Olsa { 27699f87498fSJiri Olsa if (mi) 27709f87498fSJiri Olsa refcount_inc(&mi->refcnt); 27719f87498fSJiri Olsa return mi; 27729f87498fSJiri Olsa } 27739f87498fSJiri Olsa 27749f87498fSJiri Olsa void mem_info__put(struct mem_info *mi) 27759f87498fSJiri Olsa { 27769f87498fSJiri Olsa if (mi && refcount_dec_and_test(&mi->refcnt)) 27779f87498fSJiri Olsa free(mi); 27789f87498fSJiri Olsa } 27799f87498fSJiri Olsa 27809f87498fSJiri Olsa struct mem_info *mem_info__new(void) 27819f87498fSJiri Olsa { 27829f87498fSJiri Olsa struct mem_info *mi = zalloc(sizeof(*mi)); 27839f87498fSJiri Olsa 27849f87498fSJiri Olsa if (mi) 27859f87498fSJiri Olsa refcount_set(&mi->refcnt, 1); 27869f87498fSJiri Olsa return mi; 27879f87498fSJiri Olsa } 2788a3df50abSJames Clark 2789a3df50abSJames Clark /* 2790a3df50abSJames Clark * Checks that user supplied symbol kernel files are accessible because 2791a3df50abSJames Clark * the default mechanism for accessing elf files fails silently. i.e. if 2792a3df50abSJames Clark * debug syms for a build ID aren't found perf carries on normally. When 2793a3df50abSJames Clark * they are user supplied we should assume that the user doesn't want to 2794a3df50abSJames Clark * silently fail. 2795a3df50abSJames Clark */ 2796a3df50abSJames Clark int symbol__validate_sym_arguments(void) 2797a3df50abSJames Clark { 2798a3df50abSJames Clark if (symbol_conf.vmlinux_name && 2799a3df50abSJames Clark access(symbol_conf.vmlinux_name, R_OK)) { 2800a3df50abSJames Clark pr_err("Invalid file: %s\n", symbol_conf.vmlinux_name); 2801a3df50abSJames Clark return -EINVAL; 2802a3df50abSJames Clark } 2803a3df50abSJames Clark if (symbol_conf.kallsyms_name && 2804a3df50abSJames Clark access(symbol_conf.kallsyms_name, R_OK)) { 2805a3df50abSJames Clark pr_err("Invalid file: %s\n", symbol_conf.kallsyms_name); 2806a3df50abSJames Clark return -EINVAL; 2807a3df50abSJames Clark } 2808a3df50abSJames Clark return 0; 2809a3df50abSJames Clark } 2810