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)) 282e6a9efceSArnaldo Carvalho de Melo map__set_end(prev->map, 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)) 292e6a9efceSArnaldo Carvalho de Melo map__set_end(curr->map, ~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 443259dce91SIan Rogers static int symbols__sort_name_cmp(const void *vlhs, const void *vrhs) 44479406cd7SArnaldo Carvalho de Melo { 445259dce91SIan Rogers const struct symbol *lhs = *((const struct symbol **)vlhs); 446259dce91SIan Rogers const struct symbol *rhs = *((const struct symbol **)vrhs); 44702a9d037SRabin Vincent 448259dce91SIan Rogers return strcmp(lhs->name, rhs->name); 44979406cd7SArnaldo Carvalho de Melo } 45079406cd7SArnaldo Carvalho de Melo 451259dce91SIan Rogers static struct symbol **symbols__sort_by_name(struct rb_root_cached *source, size_t *len) 45279406cd7SArnaldo Carvalho de Melo { 45379406cd7SArnaldo Carvalho de Melo struct rb_node *nd; 454259dce91SIan Rogers struct symbol **result; 455259dce91SIan Rogers size_t i = 0, size = 0; 456259dce91SIan Rogers 457259dce91SIan Rogers for (nd = rb_first_cached(source); nd; nd = rb_next(nd)) 458259dce91SIan Rogers size++; 459259dce91SIan Rogers 460259dce91SIan Rogers result = malloc(sizeof(*result) * size); 461259dce91SIan Rogers if (!result) 462259dce91SIan Rogers return NULL; 46379406cd7SArnaldo Carvalho de Melo 4647137ff50SDavidlohr Bueso for (nd = rb_first_cached(source); nd; nd = rb_next(nd)) { 46579406cd7SArnaldo Carvalho de Melo struct symbol *pos = rb_entry(nd, struct symbol, rb_node); 466259dce91SIan Rogers 467259dce91SIan Rogers result[i++] = pos; 46879406cd7SArnaldo Carvalho de Melo } 469259dce91SIan Rogers qsort(result, size, sizeof(*result), symbols__sort_name_cmp); 470259dce91SIan Rogers *len = size; 471259dce91SIan Rogers return result; 47279406cd7SArnaldo Carvalho de Melo } 47379406cd7SArnaldo Carvalho de Melo 474d8040645SPaul Clarke int symbol__match_symbol_name(const char *name, const char *str, 475d8040645SPaul Clarke enum symbol_tag_include includes) 476d8040645SPaul Clarke { 477d8040645SPaul Clarke const char *versioning; 478d8040645SPaul Clarke 479d8040645SPaul Clarke if (includes == SYMBOL_TAG_INCLUDE__DEFAULT_ONLY && 480d8040645SPaul Clarke (versioning = strstr(name, "@@"))) { 481d8040645SPaul Clarke int len = strlen(str); 482d8040645SPaul Clarke 483d8040645SPaul Clarke if (len < versioning - name) 484d8040645SPaul Clarke len = versioning - name; 485d8040645SPaul Clarke 486d8040645SPaul Clarke return arch__compare_symbol_names_n(name, str, len); 487d8040645SPaul Clarke } else 488d8040645SPaul Clarke return arch__compare_symbol_names(name, str); 489d8040645SPaul Clarke } 490d8040645SPaul Clarke 491259dce91SIan Rogers static struct symbol *symbols__find_by_name(struct symbol *symbols[], 492259dce91SIan Rogers size_t symbols_len, 493d8040645SPaul Clarke const char *name, 494259dce91SIan Rogers enum symbol_tag_include includes, 495259dce91SIan Rogers size_t *found_idx) 49679406cd7SArnaldo Carvalho de Melo { 497259dce91SIan Rogers size_t i, lower = 0, upper = symbols_len; 49878a175c4SJames Clark struct symbol *s = NULL; 49978a175c4SJames Clark 50078a175c4SJames Clark if (found_idx) 50178a175c4SJames Clark *found_idx = SIZE_MAX; 50279406cd7SArnaldo Carvalho de Melo 503259dce91SIan Rogers if (!symbols_len) 50479406cd7SArnaldo Carvalho de Melo return NULL; 50579406cd7SArnaldo Carvalho de Melo 506259dce91SIan Rogers while (lower < upper) { 50779406cd7SArnaldo Carvalho de Melo int cmp; 50879406cd7SArnaldo Carvalho de Melo 509259dce91SIan Rogers i = (lower + upper) / 2; 51078a175c4SJames Clark cmp = symbol__match_symbol_name(symbols[i]->name, name, includes); 51179406cd7SArnaldo Carvalho de Melo 512d8040645SPaul Clarke if (cmp > 0) 513259dce91SIan Rogers upper = i; 514d8040645SPaul Clarke else if (cmp < 0) 515259dce91SIan Rogers lower = i + 1; 516259dce91SIan Rogers else { 517259dce91SIan Rogers if (found_idx) 518259dce91SIan Rogers *found_idx = i; 51978a175c4SJames Clark s = symbols[i]; 520de480999SNamhyung Kim break; 52179406cd7SArnaldo Carvalho de Melo } 522259dce91SIan Rogers } 52378a175c4SJames Clark if (s && includes != SYMBOL_TAG_INCLUDE__DEFAULT_ONLY) { 524de480999SNamhyung Kim /* return first symbol that has same name (if any) */ 525259dce91SIan Rogers for (; i > 0; i--) { 526259dce91SIan Rogers struct symbol *tmp = symbols[i - 1]; 527de480999SNamhyung Kim 528259dce91SIan Rogers if (!arch__compare_symbol_names(tmp->name, s->name)) { 529259dce91SIan Rogers if (found_idx) 530259dce91SIan Rogers *found_idx = i - 1; 53178a175c4SJames Clark s = tmp; 532259dce91SIan Rogers } else 533de480999SNamhyung Kim break; 534de480999SNamhyung Kim } 535259dce91SIan Rogers } 53678a175c4SJames Clark assert(!found_idx || !s || s == symbols[*found_idx]); 537259dce91SIan Rogers return s; 53879406cd7SArnaldo Carvalho de Melo } 53979406cd7SArnaldo Carvalho de Melo 540c0b4dffbSArnaldo Carvalho de Melo void dso__reset_find_symbol_cache(struct dso *dso) 541c0b4dffbSArnaldo Carvalho de Melo { 5423183f8caSArnaldo Carvalho de Melo dso->last_find_result.addr = 0; 5433183f8caSArnaldo Carvalho de Melo dso->last_find_result.symbol = NULL; 544c0b4dffbSArnaldo Carvalho de Melo } 545c0b4dffbSArnaldo Carvalho de Melo 5463183f8caSArnaldo Carvalho de Melo void dso__insert_symbol(struct dso *dso, struct symbol *sym) 547ae93a6c7SChris Phlipot { 5483183f8caSArnaldo Carvalho de Melo __symbols__insert(&dso->symbols, sym, dso->kernel); 549ae93a6c7SChris Phlipot 550ae93a6c7SChris Phlipot /* update the symbol cache if necessary */ 5513183f8caSArnaldo Carvalho de Melo if (dso->last_find_result.addr >= sym->start && 5523183f8caSArnaldo Carvalho de Melo (dso->last_find_result.addr < sym->end || 553ae93a6c7SChris Phlipot sym->start == sym->end)) { 5543183f8caSArnaldo Carvalho de Melo dso->last_find_result.symbol = sym; 555ae93a6c7SChris Phlipot } 556ae93a6c7SChris Phlipot } 557ae93a6c7SChris Phlipot 558ab8bf5f2STommi Rantala void dso__delete_symbol(struct dso *dso, struct symbol *sym) 559ab8bf5f2STommi Rantala { 560ab8bf5f2STommi Rantala rb_erase_cached(&sym->rb_node, &dso->symbols); 561ab8bf5f2STommi Rantala symbol__delete(sym); 562ab8bf5f2STommi Rantala dso__reset_find_symbol_cache(dso); 563ab8bf5f2STommi Rantala } 564ab8bf5f2STommi Rantala 5653183f8caSArnaldo Carvalho de Melo struct symbol *dso__find_symbol(struct dso *dso, u64 addr) 566fcf1203aSArnaldo Carvalho de Melo { 5673183f8caSArnaldo Carvalho de Melo if (dso->last_find_result.addr != addr || dso->last_find_result.symbol == NULL) { 5683183f8caSArnaldo Carvalho de Melo dso->last_find_result.addr = addr; 5693183f8caSArnaldo Carvalho de Melo dso->last_find_result.symbol = symbols__find(&dso->symbols, addr); 570b685ac22SArnaldo Carvalho de Melo } 571b685ac22SArnaldo Carvalho de Melo 5723183f8caSArnaldo Carvalho de Melo return dso->last_find_result.symbol; 5738e0cf965SAdrian Hunter } 5748e0cf965SAdrian Hunter 575a2db72c5SAdrian Hunter struct symbol *dso__find_symbol_nocache(struct dso *dso, u64 addr) 576a2db72c5SAdrian Hunter { 577a2db72c5SAdrian Hunter return symbols__find(&dso->symbols, addr); 578a2db72c5SAdrian Hunter } 579a2db72c5SAdrian Hunter 5805cf88a63SArnaldo Carvalho de Melo struct symbol *dso__first_symbol(struct dso *dso) 5815cf88a63SArnaldo Carvalho de Melo { 5823183f8caSArnaldo Carvalho de Melo return symbols__first(&dso->symbols); 583cd67f99fSAdrian Hunter } 584cd67f99fSAdrian Hunter 5855cf88a63SArnaldo Carvalho de Melo struct symbol *dso__last_symbol(struct dso *dso) 5865cf88a63SArnaldo Carvalho de Melo { 5873183f8caSArnaldo Carvalho de Melo return symbols__last(&dso->symbols); 5885cf88a63SArnaldo Carvalho de Melo } 5895cf88a63SArnaldo Carvalho de Melo 5909c00a81bSAdrian Hunter struct symbol *dso__next_symbol(struct symbol *sym) 5919c00a81bSAdrian Hunter { 5929c00a81bSAdrian Hunter return symbols__next(sym); 5939c00a81bSAdrian Hunter } 5949c00a81bSAdrian Hunter 595259dce91SIan Rogers struct symbol *dso__next_symbol_by_name(struct dso *dso, size_t *idx) 59618bd7264SArnaldo Carvalho de Melo { 597259dce91SIan Rogers if (*idx + 1 >= dso->symbol_names_len) 598259dce91SIan Rogers return NULL; 59918bd7264SArnaldo Carvalho de Melo 600259dce91SIan Rogers ++*idx; 601259dce91SIan Rogers return dso->symbol_names[*idx]; 60218bd7264SArnaldo Carvalho de Melo } 60318bd7264SArnaldo Carvalho de Melo 60418bd7264SArnaldo Carvalho de Melo /* 605af07eeb0SArnaldo Carvalho de Melo * Returns first symbol that matched with @name. 60618bd7264SArnaldo Carvalho de Melo */ 607259dce91SIan Rogers struct symbol *dso__find_symbol_by_name(struct dso *dso, const char *name, size_t *idx) 60879406cd7SArnaldo Carvalho de Melo { 609259dce91SIan Rogers struct symbol *s = symbols__find_by_name(dso->symbol_names, dso->symbol_names_len, 610259dce91SIan Rogers name, SYMBOL_TAG_INCLUDE__NONE, idx); 611d8040645SPaul Clarke if (!s) 612259dce91SIan Rogers s = symbols__find_by_name(dso->symbol_names, dso->symbol_names_len, 613259dce91SIan Rogers name, SYMBOL_TAG_INCLUDE__DEFAULT_ONLY, idx); 614d8040645SPaul Clarke return s; 61579406cd7SArnaldo Carvalho de Melo } 61679406cd7SArnaldo Carvalho de Melo 6173183f8caSArnaldo Carvalho de Melo void dso__sort_by_name(struct dso *dso) 61879406cd7SArnaldo Carvalho de Melo { 619ce5b2934SIan Rogers mutex_lock(&dso->lock); 620ce5b2934SIan Rogers if (!dso__sorted_by_name(dso)) { 621259dce91SIan Rogers size_t len; 622259dce91SIan Rogers 623259dce91SIan Rogers dso->symbol_names = symbols__sort_by_name(&dso->symbols, &len); 624259dce91SIan Rogers if (dso->symbol_names) { 625259dce91SIan Rogers dso->symbol_names_len = len; 6263183f8caSArnaldo Carvalho de Melo dso__set_sorted_by_name(dso); 627ce5b2934SIan Rogers } 628259dce91SIan Rogers } 629ce5b2934SIan Rogers mutex_unlock(&dso->lock); 63079406cd7SArnaldo Carvalho de Melo } 63179406cd7SArnaldo Carvalho de Melo 63232add10fSIan Rogers /* 63332add10fSIan Rogers * While we find nice hex chars, build a long_val. 63432add10fSIan Rogers * Return number of chars processed. 63532add10fSIan Rogers */ 63632add10fSIan Rogers static int hex2u64(const char *ptr, u64 *long_val) 63732add10fSIan Rogers { 63832add10fSIan Rogers char *p; 63932add10fSIan Rogers 64032add10fSIan Rogers *long_val = strtoull(ptr, &p, 16); 64132add10fSIan Rogers 64232add10fSIan Rogers return p - ptr; 64332add10fSIan Rogers } 64432add10fSIan Rogers 64532add10fSIan Rogers 646316d70d6SAdrian Hunter int modules__parse(const char *filename, void *arg, 647316d70d6SAdrian Hunter int (*process_module)(void *arg, const char *name, 6489ad4652bSThomas Richter u64 start, u64 size)) 649316d70d6SAdrian Hunter { 650316d70d6SAdrian Hunter char *line = NULL; 651316d70d6SAdrian Hunter size_t n; 652316d70d6SAdrian Hunter FILE *file; 653316d70d6SAdrian Hunter int err = 0; 654316d70d6SAdrian Hunter 655316d70d6SAdrian Hunter file = fopen(filename, "r"); 656316d70d6SAdrian Hunter if (file == NULL) 657316d70d6SAdrian Hunter return -1; 658316d70d6SAdrian Hunter 659316d70d6SAdrian Hunter while (1) { 660316d70d6SAdrian Hunter char name[PATH_MAX]; 6619ad4652bSThomas Richter u64 start, size; 6629ad4652bSThomas Richter char *sep, *endptr; 663316d70d6SAdrian Hunter ssize_t line_len; 664316d70d6SAdrian Hunter 665316d70d6SAdrian Hunter line_len = getline(&line, &n, file); 666316d70d6SAdrian Hunter if (line_len < 0) { 667316d70d6SAdrian Hunter if (feof(file)) 668316d70d6SAdrian Hunter break; 669316d70d6SAdrian Hunter err = -1; 670316d70d6SAdrian Hunter goto out; 671316d70d6SAdrian Hunter } 672316d70d6SAdrian Hunter 673316d70d6SAdrian Hunter if (!line) { 674316d70d6SAdrian Hunter err = -1; 675316d70d6SAdrian Hunter goto out; 676316d70d6SAdrian Hunter } 677316d70d6SAdrian Hunter 678316d70d6SAdrian Hunter line[--line_len] = '\0'; /* \n */ 679316d70d6SAdrian Hunter 680316d70d6SAdrian Hunter sep = strrchr(line, 'x'); 681316d70d6SAdrian Hunter if (sep == NULL) 682316d70d6SAdrian Hunter continue; 683316d70d6SAdrian Hunter 684316d70d6SAdrian Hunter hex2u64(sep + 1, &start); 685316d70d6SAdrian Hunter 686316d70d6SAdrian Hunter sep = strchr(line, ' '); 687316d70d6SAdrian Hunter if (sep == NULL) 688316d70d6SAdrian Hunter continue; 689316d70d6SAdrian Hunter 690316d70d6SAdrian Hunter *sep = '\0'; 691316d70d6SAdrian Hunter 692316d70d6SAdrian Hunter scnprintf(name, sizeof(name), "[%s]", line); 693316d70d6SAdrian Hunter 6949ad4652bSThomas Richter size = strtoul(sep + 1, &endptr, 0); 6959ad4652bSThomas Richter if (*endptr != ' ' && *endptr != '\t') 6969ad4652bSThomas Richter continue; 6979ad4652bSThomas Richter 6989ad4652bSThomas Richter err = process_module(arg, name, start, size); 699316d70d6SAdrian Hunter if (err) 700316d70d6SAdrian Hunter break; 701316d70d6SAdrian Hunter } 702316d70d6SAdrian Hunter out: 703316d70d6SAdrian Hunter free(line); 704316d70d6SAdrian Hunter fclose(file); 705316d70d6SAdrian Hunter return err; 706316d70d6SAdrian Hunter } 707316d70d6SAdrian Hunter 708e7110b9fSArnaldo Carvalho de Melo /* 709e7110b9fSArnaldo Carvalho de Melo * These are symbols in the kernel image, so make sure that 710e7110b9fSArnaldo Carvalho de Melo * sym is from a kernel DSO. 711e7110b9fSArnaldo Carvalho de Melo */ 712608c34deSArnaldo Carvalho de Melo static bool symbol__is_idle(const char *name) 71382d1deb0SDavid Ahern { 71482d1deb0SDavid Ahern const char * const idle_symbols[] = { 7150e71459aSKim Phillips "acpi_idle_do_entry", 7160e71459aSKim Phillips "acpi_processor_ffh_cstate_enter", 717549aff77SArnaldo Carvalho de Melo "arch_cpu_idle", 71882d1deb0SDavid Ahern "cpu_idle", 719e0336ed6SArnaldo Carvalho de Melo "cpu_startup_entry", 7200e71459aSKim Phillips "idle_cpu", 72182d1deb0SDavid Ahern "intel_idle", 72282d1deb0SDavid Ahern "default_idle", 72382d1deb0SDavid Ahern "native_safe_halt", 72482d1deb0SDavid Ahern "enter_idle", 72582d1deb0SDavid Ahern "exit_idle", 72682d1deb0SDavid Ahern "mwait_idle", 72782d1deb0SDavid Ahern "mwait_idle_with_hints", 728783abbd4SArnaldo Carvalho de Melo "mwait_idle_with_hints.constprop.0", 72982d1deb0SDavid Ahern "poll_idle", 73082d1deb0SDavid Ahern "ppc64_runlatch_off", 73182d1deb0SDavid Ahern "pseries_dedicated_idle_sleep", 73219bf119cSSven Schnelle "psw_idle", 73319bf119cSSven Schnelle "psw_idle_exit", 73482d1deb0SDavid Ahern NULL 73582d1deb0SDavid Ahern }; 73682d1deb0SDavid Ahern int i; 737bc5f15beSKim Phillips static struct strlist *idle_symbols_list; 73882d1deb0SDavid Ahern 739bc5f15beSKim Phillips if (idle_symbols_list) 740bc5f15beSKim Phillips return strlist__has_entry(idle_symbols_list, name); 74182d1deb0SDavid Ahern 742bc5f15beSKim Phillips idle_symbols_list = strlist__new(NULL, NULL); 743bc5f15beSKim Phillips 744bc5f15beSKim Phillips for (i = 0; idle_symbols[i]; i++) 745bc5f15beSKim Phillips strlist__add(idle_symbols_list, idle_symbols[i]); 746bc5f15beSKim Phillips 747bc5f15beSKim Phillips return strlist__has_entry(idle_symbols_list, name); 74882d1deb0SDavid Ahern } 74982d1deb0SDavid Ahern 750682b335aSArnaldo Carvalho de Melo static int map__process_kallsym_symbol(void *arg, const char *name, 75182151520SCody P Schafer char type, u64 start) 752682b335aSArnaldo Carvalho de Melo { 753682b335aSArnaldo Carvalho de Melo struct symbol *sym; 754333cc76cSArnaldo Carvalho de Melo struct dso *dso = arg; 7557137ff50SDavidlohr Bueso struct rb_root_cached *root = &dso->symbols; 756682b335aSArnaldo Carvalho de Melo 7573183f8caSArnaldo Carvalho de Melo if (!symbol_type__filter(type)) 758682b335aSArnaldo Carvalho de Melo return 0; 759682b335aSArnaldo Carvalho de Melo 7601a86f4baSLexi Shao /* Ignore local symbols for ARM modules */ 7611a86f4baSLexi Shao if (name[0] == '$') 7621a86f4baSLexi Shao return 0; 7631a86f4baSLexi Shao 76482151520SCody P Schafer /* 76582151520SCody P Schafer * module symbols are not sorted so we add all 76682151520SCody P Schafer * symbols, setting length to 0, and rely on 76782151520SCody P Schafer * symbols__fixup_end() to fix it up. 76882151520SCody P Schafer */ 769af30bffaSArnaldo Carvalho de Melo sym = symbol__new(start, 0, kallsyms2elf_binding(type), kallsyms2elf_type(type), name); 7702e538c4aSArnaldo Carvalho de Melo if (sym == NULL) 771682b335aSArnaldo Carvalho de Melo return -ENOMEM; 77282164161SArnaldo Carvalho de Melo /* 77382164161SArnaldo Carvalho de Melo * We will pass the symbols to the filter later, in 7744e06255fSArnaldo Carvalho de Melo * map__split_kallsyms, when we have split the maps per module 77582164161SArnaldo Carvalho de Melo */ 776608c34deSArnaldo Carvalho de Melo __symbols__insert(root, sym, !strchr(name, '[')); 777a1645ce1SZhang, Yanmin 778682b335aSArnaldo Carvalho de Melo return 0; 7792e538c4aSArnaldo Carvalho de Melo } 7802e538c4aSArnaldo Carvalho de Melo 781682b335aSArnaldo Carvalho de Melo /* 782682b335aSArnaldo Carvalho de Melo * Loads the function entries in /proc/kallsyms into kernel_map->dso, 783682b335aSArnaldo Carvalho de Melo * so that we can in the next step set the symbol ->end address and then 784682b335aSArnaldo Carvalho de Melo * call kernel_maps__split_kallsyms. 785682b335aSArnaldo Carvalho de Melo */ 786333cc76cSArnaldo Carvalho de Melo static int dso__load_all_kallsyms(struct dso *dso, const char *filename) 787682b335aSArnaldo Carvalho de Melo { 788333cc76cSArnaldo Carvalho de Melo return kallsyms__parse(filename, dso, map__process_kallsym_symbol); 7892e538c4aSArnaldo Carvalho de Melo } 7902e538c4aSArnaldo Carvalho de Melo 79179b6bb73SArnaldo Carvalho de Melo static int maps__split_kallsyms_for_kcore(struct maps *kmaps, struct dso *dso) 7928e0cf965SAdrian Hunter { 7938e0cf965SAdrian Hunter struct map *curr_map; 7948e0cf965SAdrian Hunter struct symbol *pos; 795866548ddSAdrian Hunter int count = 0; 7967137ff50SDavidlohr Bueso struct rb_root_cached old_root = dso->symbols; 7977137ff50SDavidlohr Bueso struct rb_root_cached *root = &dso->symbols; 7987137ff50SDavidlohr Bueso struct rb_node *next = rb_first_cached(root); 7998e0cf965SAdrian Hunter 800ba92732eSWang Nan if (!kmaps) 801ba92732eSWang Nan return -1; 802ba92732eSWang Nan 8037137ff50SDavidlohr Bueso *root = RB_ROOT_CACHED; 804866548ddSAdrian Hunter 8058e0cf965SAdrian Hunter while (next) { 80663df0e4bSIan Rogers struct dso *curr_map_dso; 8078e0cf965SAdrian Hunter char *module; 8088e0cf965SAdrian Hunter 8098e0cf965SAdrian Hunter pos = rb_entry(next, struct symbol, rb_node); 8108e0cf965SAdrian Hunter next = rb_next(&pos->rb_node); 8118e0cf965SAdrian Hunter 8127137ff50SDavidlohr Bueso rb_erase_cached(&pos->rb_node, &old_root); 8137137ff50SDavidlohr Bueso RB_CLEAR_NODE(&pos->rb_node); 8148e0cf965SAdrian Hunter module = strchr(pos->name, '\t'); 8158e0cf965SAdrian Hunter if (module) 8168e0cf965SAdrian Hunter *module = '\0'; 8178e0cf965SAdrian Hunter 81879b6bb73SArnaldo Carvalho de Melo curr_map = maps__find(kmaps, pos->start); 8198e0cf965SAdrian Hunter 820be39db9fSArnaldo Carvalho de Melo if (!curr_map) { 8218e0cf965SAdrian Hunter symbol__delete(pos); 822866548ddSAdrian Hunter continue; 823866548ddSAdrian Hunter } 82463df0e4bSIan Rogers curr_map_dso = map__dso(curr_map); 8252a6e5e8aSIan Rogers pos->start -= map__start(curr_map) - map__pgoff(curr_map); 826e5116f46SIan Rogers if (pos->end > map__end(curr_map)) 827e5116f46SIan Rogers pos->end = map__end(curr_map); 8288e0cf965SAdrian Hunter if (pos->end) 8292a6e5e8aSIan Rogers pos->end -= map__start(curr_map) - map__pgoff(curr_map); 83063df0e4bSIan Rogers symbols__insert(&curr_map_dso->symbols, pos); 8318e0cf965SAdrian Hunter ++count; 8328e0cf965SAdrian Hunter } 8338e0cf965SAdrian Hunter 8348e0cf965SAdrian Hunter /* Symbols have been adjusted */ 8358e0cf965SAdrian Hunter dso->adjust_symbols = 1; 8368e0cf965SAdrian Hunter 837866548ddSAdrian Hunter return count; 8388e0cf965SAdrian Hunter } 8398e0cf965SAdrian Hunter 8402e538c4aSArnaldo Carvalho de Melo /* 8412e538c4aSArnaldo Carvalho de Melo * Split the symbols into maps, making sure there are no overlaps, i.e. the 8422e538c4aSArnaldo Carvalho de Melo * kernel range is broken in several maps, named [kernel].N, as we don't have 8432e538c4aSArnaldo Carvalho de Melo * the original ELF section names vmlinux have. 8442e538c4aSArnaldo Carvalho de Melo */ 84579b6bb73SArnaldo Carvalho de Melo static int maps__split_kallsyms(struct maps *kmaps, struct dso *dso, u64 delta, 84615e0e2d4SArnaldo Carvalho de Melo struct map *initial_map) 8472e538c4aSArnaldo Carvalho de Melo { 848ba92732eSWang Nan struct machine *machine; 84915e0e2d4SArnaldo Carvalho de Melo struct map *curr_map = initial_map; 8502e538c4aSArnaldo Carvalho de Melo struct symbol *pos; 8518a953312SArnaldo Carvalho de Melo int count = 0, moved = 0; 8527137ff50SDavidlohr Bueso struct rb_root_cached *root = &dso->symbols; 8537137ff50SDavidlohr Bueso struct rb_node *next = rb_first_cached(root); 8542e538c4aSArnaldo Carvalho de Melo int kernel_range = 0; 8554d004365SAdrian Hunter bool x86_64; 8562e538c4aSArnaldo Carvalho de Melo 857ba92732eSWang Nan if (!kmaps) 858ba92732eSWang Nan return -1; 859ba92732eSWang Nan 8605ab6d715SIan Rogers machine = maps__machine(kmaps); 861ba92732eSWang Nan 8624d004365SAdrian Hunter x86_64 = machine__is(machine, "x86_64"); 8634d004365SAdrian Hunter 8642e538c4aSArnaldo Carvalho de Melo while (next) { 8652e538c4aSArnaldo Carvalho de Melo char *module; 8662e538c4aSArnaldo Carvalho de Melo 8672e538c4aSArnaldo Carvalho de Melo pos = rb_entry(next, struct symbol, rb_node); 8682e538c4aSArnaldo Carvalho de Melo next = rb_next(&pos->rb_node); 8692e538c4aSArnaldo Carvalho de Melo 8702e538c4aSArnaldo Carvalho de Melo module = strchr(pos->name, '\t'); 8712e538c4aSArnaldo Carvalho de Melo if (module) { 87263df0e4bSIan Rogers struct dso *curr_map_dso; 87363df0e4bSIan Rogers 87475be6cf4SArnaldo Carvalho de Melo if (!symbol_conf.use_modules) 8751de8e245SArnaldo Carvalho de Melo goto discard_symbol; 8761de8e245SArnaldo Carvalho de Melo 8772e538c4aSArnaldo Carvalho de Melo *module++ = '\0'; 87863df0e4bSIan Rogers curr_map_dso = map__dso(curr_map); 87963df0e4bSIan Rogers if (strcmp(curr_map_dso->short_name, module)) { 8802832ef81SIan Rogers if (RC_CHK_ACCESS(curr_map) != RC_CHK_ACCESS(initial_map) && 8811c695c88SJiri Olsa dso->kernel == DSO_SPACE__KERNEL_GUEST && 88223346f21SArnaldo Carvalho de Melo machine__is_default_guest(machine)) { 883a1645ce1SZhang, Yanmin /* 884a1645ce1SZhang, Yanmin * We assume all symbols of a module are 885a1645ce1SZhang, Yanmin * continuous in * kallsyms, so curr_map 886a1645ce1SZhang, Yanmin * points to a module and all its 887a1645ce1SZhang, Yanmin * symbols are in its kmap. Mark it as 888a1645ce1SZhang, Yanmin * loaded. 889a1645ce1SZhang, Yanmin */ 89063df0e4bSIan Rogers dso__set_loaded(curr_map_dso); 891af427bf5SArnaldo Carvalho de Melo } 892b7cece76SArnaldo Carvalho de Melo 89379b6bb73SArnaldo Carvalho de Melo curr_map = maps__find_by_name(kmaps, module); 894a1645ce1SZhang, Yanmin if (curr_map == NULL) { 8952f51903bSArnaldo Carvalho de Melo pr_debug("%s/proc/{kallsyms,modules} " 896a1645ce1SZhang, Yanmin "inconsistency while looking " 897a1645ce1SZhang, Yanmin "for \"%s\" module!\n", 89823346f21SArnaldo Carvalho de Melo machine->root_dir, module); 89915e0e2d4SArnaldo Carvalho de Melo curr_map = initial_map; 900a1645ce1SZhang, Yanmin goto discard_symbol; 901a1645ce1SZhang, Yanmin } 90263df0e4bSIan Rogers curr_map_dso = map__dso(curr_map); 90363df0e4bSIan Rogers if (curr_map_dso->loaded && 90423346f21SArnaldo Carvalho de Melo !machine__is_default_guest(machine)) 905b7cece76SArnaldo Carvalho de Melo goto discard_symbol; 906af427bf5SArnaldo Carvalho de Melo } 90786470930SIngo Molnar /* 9082e538c4aSArnaldo Carvalho de Melo * So that we look just like we get from .ko files, 90915e0e2d4SArnaldo Carvalho de Melo * i.e. not prelinked, relative to initial_map->start. 91086470930SIngo Molnar */ 91178a1f7cdSIan Rogers pos->start = map__map_ip(curr_map, pos->start); 91278a1f7cdSIan Rogers pos->end = map__map_ip(curr_map, pos->end); 9134d004365SAdrian Hunter } else if (x86_64 && is_entry_trampoline(pos->name)) { 9144d004365SAdrian Hunter /* 9154d004365SAdrian Hunter * These symbols are not needed anymore since the 9164d004365SAdrian Hunter * trampoline maps refer to the text section and it's 9174d004365SAdrian Hunter * symbols instead. Avoid having to deal with 9184d004365SAdrian Hunter * relocations, and the assumption that the first symbol 9194d004365SAdrian Hunter * is the start of kernel text, by simply removing the 9204d004365SAdrian Hunter * symbols at this point. 9214d004365SAdrian Hunter */ 9224d004365SAdrian Hunter goto discard_symbol; 92315e0e2d4SArnaldo Carvalho de Melo } else if (curr_map != initial_map) { 9242e538c4aSArnaldo Carvalho de Melo char dso_name[PATH_MAX]; 925aeafcbafSArnaldo Carvalho de Melo struct dso *ndso; 92686470930SIngo Molnar 927d9b62abaSAdrian Hunter if (delta) { 928d9b62abaSAdrian Hunter /* Kernel was relocated at boot time */ 929d9b62abaSAdrian Hunter pos->start -= delta; 930d9b62abaSAdrian Hunter pos->end -= delta; 931d9b62abaSAdrian Hunter } 932d9b62abaSAdrian Hunter 9338a953312SArnaldo Carvalho de Melo if (count == 0) { 93415e0e2d4SArnaldo Carvalho de Melo curr_map = initial_map; 935be39db9fSArnaldo Carvalho de Melo goto add_symbol; 9368a953312SArnaldo Carvalho de Melo } 9378a953312SArnaldo Carvalho de Melo 9381c695c88SJiri Olsa if (dso->kernel == DSO_SPACE__KERNEL_GUEST) 939a1645ce1SZhang, Yanmin snprintf(dso_name, sizeof(dso_name), 940a1645ce1SZhang, Yanmin "[guest.kernel].%d", 941a1645ce1SZhang, Yanmin kernel_range++); 942a1645ce1SZhang, Yanmin else 943a1645ce1SZhang, Yanmin snprintf(dso_name, sizeof(dso_name), 944a1645ce1SZhang, Yanmin "[kernel].%d", 9452e538c4aSArnaldo Carvalho de Melo kernel_range++); 94686470930SIngo Molnar 947aeafcbafSArnaldo Carvalho de Melo ndso = dso__new(dso_name); 948aeafcbafSArnaldo Carvalho de Melo if (ndso == NULL) 9492e538c4aSArnaldo Carvalho de Melo return -1; 9502e538c4aSArnaldo Carvalho de Melo 951aeafcbafSArnaldo Carvalho de Melo ndso->kernel = dso->kernel; 952a1645ce1SZhang, Yanmin 9533183f8caSArnaldo Carvalho de Melo curr_map = map__new2(pos->start, ndso); 95437fe5fcbSZhang, Yanmin if (curr_map == NULL) { 955d3a7c489SArnaldo Carvalho de Melo dso__put(ndso); 9562e538c4aSArnaldo Carvalho de Melo return -1; 9572e538c4aSArnaldo Carvalho de Melo } 9582e538c4aSArnaldo Carvalho de Melo 959e6a9efceSArnaldo Carvalho de Melo map__set_map_ip(curr_map, identity__map_ip); 960e6a9efceSArnaldo Carvalho de Melo map__set_unmap_ip(curr_map, identity__map_ip); 961ff583dc4SIan Rogers if (maps__insert(kmaps, curr_map)) { 962ff583dc4SIan Rogers dso__put(ndso); 963ff583dc4SIan Rogers return -1; 964ff583dc4SIan Rogers } 9652e538c4aSArnaldo Carvalho de Melo ++kernel_range; 966d9b62abaSAdrian Hunter } else if (delta) { 967d9b62abaSAdrian Hunter /* Kernel was relocated at boot time */ 968d9b62abaSAdrian Hunter pos->start -= delta; 969d9b62abaSAdrian Hunter pos->end -= delta; 9702e538c4aSArnaldo Carvalho de Melo } 971be39db9fSArnaldo Carvalho de Melo add_symbol: 97215e0e2d4SArnaldo Carvalho de Melo if (curr_map != initial_map) { 97363df0e4bSIan Rogers struct dso *curr_map_dso = map__dso(curr_map); 97463df0e4bSIan Rogers 9757137ff50SDavidlohr Bueso rb_erase_cached(&pos->rb_node, root); 97663df0e4bSIan Rogers symbols__insert(&curr_map_dso->symbols, pos); 9778a953312SArnaldo Carvalho de Melo ++moved; 9788a953312SArnaldo Carvalho de Melo } else 9798a953312SArnaldo Carvalho de Melo ++count; 980be39db9fSArnaldo Carvalho de Melo 981be39db9fSArnaldo Carvalho de Melo continue; 982be39db9fSArnaldo Carvalho de Melo discard_symbol: 9837137ff50SDavidlohr Bueso rb_erase_cached(&pos->rb_node, root); 984be39db9fSArnaldo Carvalho de Melo symbol__delete(pos); 98586470930SIngo Molnar } 98686470930SIngo Molnar 98715e0e2d4SArnaldo Carvalho de Melo if (curr_map != initial_map && 9881c695c88SJiri Olsa dso->kernel == DSO_SPACE__KERNEL_GUEST && 9895ab6d715SIan Rogers machine__is_default_guest(maps__machine(kmaps))) { 99063df0e4bSIan Rogers dso__set_loaded(map__dso(curr_map)); 991a1645ce1SZhang, Yanmin } 992a1645ce1SZhang, Yanmin 9938a953312SArnaldo Carvalho de Melo return count + moved; 99486470930SIngo Molnar } 99586470930SIngo Molnar 9963f067dcaSArnaldo Carvalho de Melo bool symbol__restricted_filename(const char *filename, 997ec80fde7SArnaldo Carvalho de Melo const char *restricted_filename) 998ec80fde7SArnaldo Carvalho de Melo { 999ec80fde7SArnaldo Carvalho de Melo bool restricted = false; 1000ec80fde7SArnaldo Carvalho de Melo 1001ec80fde7SArnaldo Carvalho de Melo if (symbol_conf.kptr_restrict) { 1002ec80fde7SArnaldo Carvalho de Melo char *r = realpath(filename, NULL); 1003ec80fde7SArnaldo Carvalho de Melo 1004ec80fde7SArnaldo Carvalho de Melo if (r != NULL) { 1005ec80fde7SArnaldo Carvalho de Melo restricted = strcmp(r, restricted_filename) == 0; 1006ec80fde7SArnaldo Carvalho de Melo free(r); 1007ec80fde7SArnaldo Carvalho de Melo return restricted; 1008ec80fde7SArnaldo Carvalho de Melo } 1009ec80fde7SArnaldo Carvalho de Melo } 1010ec80fde7SArnaldo Carvalho de Melo 1011ec80fde7SArnaldo Carvalho de Melo return restricted; 1012ec80fde7SArnaldo Carvalho de Melo } 1013ec80fde7SArnaldo Carvalho de Melo 101452afdaf9SAdrian Hunter struct module_info { 101552afdaf9SAdrian Hunter struct rb_node rb_node; 101652afdaf9SAdrian Hunter char *name; 101752afdaf9SAdrian Hunter u64 start; 101852afdaf9SAdrian Hunter }; 101952afdaf9SAdrian Hunter 102052afdaf9SAdrian Hunter static void add_module(struct module_info *mi, struct rb_root *modules) 102152afdaf9SAdrian Hunter { 102252afdaf9SAdrian Hunter struct rb_node **p = &modules->rb_node; 102352afdaf9SAdrian Hunter struct rb_node *parent = NULL; 102452afdaf9SAdrian Hunter struct module_info *m; 102552afdaf9SAdrian Hunter 102652afdaf9SAdrian Hunter while (*p != NULL) { 102752afdaf9SAdrian Hunter parent = *p; 102852afdaf9SAdrian Hunter m = rb_entry(parent, struct module_info, rb_node); 102952afdaf9SAdrian Hunter if (strcmp(mi->name, m->name) < 0) 103052afdaf9SAdrian Hunter p = &(*p)->rb_left; 103152afdaf9SAdrian Hunter else 103252afdaf9SAdrian Hunter p = &(*p)->rb_right; 103352afdaf9SAdrian Hunter } 103452afdaf9SAdrian Hunter rb_link_node(&mi->rb_node, parent, p); 103552afdaf9SAdrian Hunter rb_insert_color(&mi->rb_node, modules); 103652afdaf9SAdrian Hunter } 103752afdaf9SAdrian Hunter 103852afdaf9SAdrian Hunter static void delete_modules(struct rb_root *modules) 103952afdaf9SAdrian Hunter { 104052afdaf9SAdrian Hunter struct module_info *mi; 104152afdaf9SAdrian Hunter struct rb_node *next = rb_first(modules); 104252afdaf9SAdrian Hunter 104352afdaf9SAdrian Hunter while (next) { 104452afdaf9SAdrian Hunter mi = rb_entry(next, struct module_info, rb_node); 104552afdaf9SAdrian Hunter next = rb_next(&mi->rb_node); 104652afdaf9SAdrian Hunter rb_erase(&mi->rb_node, modules); 104774cf249dSArnaldo Carvalho de Melo zfree(&mi->name); 104852afdaf9SAdrian Hunter free(mi); 104952afdaf9SAdrian Hunter } 105052afdaf9SAdrian Hunter } 105152afdaf9SAdrian Hunter 105252afdaf9SAdrian Hunter static struct module_info *find_module(const char *name, 105352afdaf9SAdrian Hunter struct rb_root *modules) 105452afdaf9SAdrian Hunter { 105552afdaf9SAdrian Hunter struct rb_node *n = modules->rb_node; 105652afdaf9SAdrian Hunter 105752afdaf9SAdrian Hunter while (n) { 105852afdaf9SAdrian Hunter struct module_info *m; 105952afdaf9SAdrian Hunter int cmp; 106052afdaf9SAdrian Hunter 106152afdaf9SAdrian Hunter m = rb_entry(n, struct module_info, rb_node); 106252afdaf9SAdrian Hunter cmp = strcmp(name, m->name); 106352afdaf9SAdrian Hunter if (cmp < 0) 106452afdaf9SAdrian Hunter n = n->rb_left; 106552afdaf9SAdrian Hunter else if (cmp > 0) 106652afdaf9SAdrian Hunter n = n->rb_right; 106752afdaf9SAdrian Hunter else 106852afdaf9SAdrian Hunter return m; 106952afdaf9SAdrian Hunter } 107052afdaf9SAdrian Hunter 107152afdaf9SAdrian Hunter return NULL; 107252afdaf9SAdrian Hunter } 107352afdaf9SAdrian Hunter 10749ad4652bSThomas Richter static int __read_proc_modules(void *arg, const char *name, u64 start, 10759ad4652bSThomas Richter u64 size __maybe_unused) 107652afdaf9SAdrian Hunter { 107752afdaf9SAdrian Hunter struct rb_root *modules = arg; 107852afdaf9SAdrian Hunter struct module_info *mi; 107952afdaf9SAdrian Hunter 108052afdaf9SAdrian Hunter mi = zalloc(sizeof(struct module_info)); 108152afdaf9SAdrian Hunter if (!mi) 108252afdaf9SAdrian Hunter return -ENOMEM; 108352afdaf9SAdrian Hunter 108452afdaf9SAdrian Hunter mi->name = strdup(name); 108552afdaf9SAdrian Hunter mi->start = start; 108652afdaf9SAdrian Hunter 108752afdaf9SAdrian Hunter if (!mi->name) { 108852afdaf9SAdrian Hunter free(mi); 108952afdaf9SAdrian Hunter return -ENOMEM; 109052afdaf9SAdrian Hunter } 109152afdaf9SAdrian Hunter 109252afdaf9SAdrian Hunter add_module(mi, modules); 109352afdaf9SAdrian Hunter 109452afdaf9SAdrian Hunter return 0; 109552afdaf9SAdrian Hunter } 109652afdaf9SAdrian Hunter 109752afdaf9SAdrian Hunter static int read_proc_modules(const char *filename, struct rb_root *modules) 109852afdaf9SAdrian Hunter { 109952afdaf9SAdrian Hunter if (symbol__restricted_filename(filename, "/proc/modules")) 110052afdaf9SAdrian Hunter return -1; 110152afdaf9SAdrian Hunter 110252afdaf9SAdrian Hunter if (modules__parse(filename, modules, __read_proc_modules)) { 110352afdaf9SAdrian Hunter delete_modules(modules); 110452afdaf9SAdrian Hunter return -1; 110552afdaf9SAdrian Hunter } 110652afdaf9SAdrian Hunter 110752afdaf9SAdrian Hunter return 0; 110852afdaf9SAdrian Hunter } 110952afdaf9SAdrian Hunter 1110fc1b691dSAdrian Hunter int compare_proc_modules(const char *from, const char *to) 1111fc1b691dSAdrian Hunter { 1112fc1b691dSAdrian Hunter struct rb_root from_modules = RB_ROOT; 1113fc1b691dSAdrian Hunter struct rb_root to_modules = RB_ROOT; 1114fc1b691dSAdrian Hunter struct rb_node *from_node, *to_node; 1115fc1b691dSAdrian Hunter struct module_info *from_m, *to_m; 1116fc1b691dSAdrian Hunter int ret = -1; 1117fc1b691dSAdrian Hunter 1118fc1b691dSAdrian Hunter if (read_proc_modules(from, &from_modules)) 1119fc1b691dSAdrian Hunter return -1; 1120fc1b691dSAdrian Hunter 1121fc1b691dSAdrian Hunter if (read_proc_modules(to, &to_modules)) 1122fc1b691dSAdrian Hunter goto out_delete_from; 1123fc1b691dSAdrian Hunter 1124fc1b691dSAdrian Hunter from_node = rb_first(&from_modules); 1125fc1b691dSAdrian Hunter to_node = rb_first(&to_modules); 1126fc1b691dSAdrian Hunter while (from_node) { 1127fc1b691dSAdrian Hunter if (!to_node) 1128fc1b691dSAdrian Hunter break; 1129fc1b691dSAdrian Hunter 1130fc1b691dSAdrian Hunter from_m = rb_entry(from_node, struct module_info, rb_node); 1131fc1b691dSAdrian Hunter to_m = rb_entry(to_node, struct module_info, rb_node); 1132fc1b691dSAdrian Hunter 1133fc1b691dSAdrian Hunter if (from_m->start != to_m->start || 1134fc1b691dSAdrian Hunter strcmp(from_m->name, to_m->name)) 1135fc1b691dSAdrian Hunter break; 1136fc1b691dSAdrian Hunter 1137fc1b691dSAdrian Hunter from_node = rb_next(from_node); 1138fc1b691dSAdrian Hunter to_node = rb_next(to_node); 1139fc1b691dSAdrian Hunter } 1140fc1b691dSAdrian Hunter 1141fc1b691dSAdrian Hunter if (!from_node && !to_node) 1142fc1b691dSAdrian Hunter ret = 0; 1143fc1b691dSAdrian Hunter 1144fc1b691dSAdrian Hunter delete_modules(&to_modules); 1145fc1b691dSAdrian Hunter out_delete_from: 1146fc1b691dSAdrian Hunter delete_modules(&from_modules); 1147fc1b691dSAdrian Hunter 1148fc1b691dSAdrian Hunter return ret; 1149fc1b691dSAdrian Hunter } 1150fc1b691dSAdrian Hunter 115179b6bb73SArnaldo Carvalho de Melo static int do_validate_kcore_modules(const char *filename, struct maps *kmaps) 115252afdaf9SAdrian Hunter { 115352afdaf9SAdrian Hunter struct rb_root modules = RB_ROOT; 1154ff583dc4SIan Rogers struct map_rb_node *old_node; 115552afdaf9SAdrian Hunter int err; 115652afdaf9SAdrian Hunter 115752afdaf9SAdrian Hunter err = read_proc_modules(filename, &modules); 115852afdaf9SAdrian Hunter if (err) 115952afdaf9SAdrian Hunter return err; 116052afdaf9SAdrian Hunter 1161ff583dc4SIan Rogers maps__for_each_entry(kmaps, old_node) { 1162ff583dc4SIan Rogers struct map *old_map = old_node->map; 116352afdaf9SAdrian Hunter struct module_info *mi; 116463df0e4bSIan Rogers struct dso *dso; 116552afdaf9SAdrian Hunter 11665759a682SAdrian Hunter if (!__map__is_kmodule(old_map)) { 116752afdaf9SAdrian Hunter continue; 116852afdaf9SAdrian Hunter } 116963df0e4bSIan Rogers dso = map__dso(old_map); 117052afdaf9SAdrian Hunter /* Module must be in memory at the same address */ 117163df0e4bSIan Rogers mi = find_module(dso->short_name, &modules); 1172e5116f46SIan Rogers if (!mi || mi->start != map__start(old_map)) { 117352afdaf9SAdrian Hunter err = -EINVAL; 117452afdaf9SAdrian Hunter goto out; 117552afdaf9SAdrian Hunter } 117652afdaf9SAdrian Hunter } 117752afdaf9SAdrian Hunter out: 117852afdaf9SAdrian Hunter delete_modules(&modules); 117952afdaf9SAdrian Hunter return err; 118052afdaf9SAdrian Hunter } 118152afdaf9SAdrian Hunter 118252afdaf9SAdrian Hunter /* 118352afdaf9SAdrian Hunter * If kallsyms is referenced by name then we look for filename in the same 118452afdaf9SAdrian Hunter * directory. 118552afdaf9SAdrian Hunter */ 118652afdaf9SAdrian Hunter static bool filename_from_kallsyms_filename(char *filename, 118752afdaf9SAdrian Hunter const char *base_name, 118852afdaf9SAdrian Hunter const char *kallsyms_filename) 118952afdaf9SAdrian Hunter { 119052afdaf9SAdrian Hunter char *name; 119152afdaf9SAdrian Hunter 119252afdaf9SAdrian Hunter strcpy(filename, kallsyms_filename); 119352afdaf9SAdrian Hunter name = strrchr(filename, '/'); 119452afdaf9SAdrian Hunter if (!name) 119552afdaf9SAdrian Hunter return false; 119652afdaf9SAdrian Hunter 119752afdaf9SAdrian Hunter name += 1; 119852afdaf9SAdrian Hunter 119952afdaf9SAdrian Hunter if (!strcmp(name, "kallsyms")) { 120052afdaf9SAdrian Hunter strcpy(name, base_name); 120152afdaf9SAdrian Hunter return true; 120252afdaf9SAdrian Hunter } 120352afdaf9SAdrian Hunter 120452afdaf9SAdrian Hunter return false; 120552afdaf9SAdrian Hunter } 120652afdaf9SAdrian Hunter 120752afdaf9SAdrian Hunter static int validate_kcore_modules(const char *kallsyms_filename, 120852afdaf9SAdrian Hunter struct map *map) 120952afdaf9SAdrian Hunter { 121079b6bb73SArnaldo Carvalho de Melo struct maps *kmaps = map__kmaps(map); 121152afdaf9SAdrian Hunter char modules_filename[PATH_MAX]; 121252afdaf9SAdrian Hunter 1213ba92732eSWang Nan if (!kmaps) 1214ba92732eSWang Nan return -EINVAL; 1215ba92732eSWang Nan 121652afdaf9SAdrian Hunter if (!filename_from_kallsyms_filename(modules_filename, "modules", 121752afdaf9SAdrian Hunter kallsyms_filename)) 121852afdaf9SAdrian Hunter return -EINVAL; 121952afdaf9SAdrian Hunter 12205759a682SAdrian Hunter if (do_validate_kcore_modules(modules_filename, kmaps)) 122152afdaf9SAdrian Hunter return -EINVAL; 122252afdaf9SAdrian Hunter 122352afdaf9SAdrian Hunter return 0; 122452afdaf9SAdrian Hunter } 122552afdaf9SAdrian Hunter 1226a00d28cbSAdrian Hunter static int validate_kcore_addresses(const char *kallsyms_filename, 1227a00d28cbSAdrian Hunter struct map *map) 1228a00d28cbSAdrian Hunter { 1229a00d28cbSAdrian Hunter struct kmap *kmap = map__kmap(map); 1230a00d28cbSAdrian Hunter 1231ba92732eSWang Nan if (!kmap) 1232ba92732eSWang Nan return -EINVAL; 1233ba92732eSWang Nan 1234a00d28cbSAdrian Hunter if (kmap->ref_reloc_sym && kmap->ref_reloc_sym->name) { 1235a00d28cbSAdrian Hunter u64 start; 1236a00d28cbSAdrian Hunter 1237b843f62aSArnaldo Carvalho de Melo if (kallsyms__get_function_start(kallsyms_filename, 1238b843f62aSArnaldo Carvalho de Melo kmap->ref_reloc_sym->name, &start)) 1239b843f62aSArnaldo Carvalho de Melo return -ENOENT; 1240a00d28cbSAdrian Hunter if (start != kmap->ref_reloc_sym->addr) 1241a00d28cbSAdrian Hunter return -EINVAL; 1242a00d28cbSAdrian Hunter } 1243a00d28cbSAdrian Hunter 1244a00d28cbSAdrian Hunter return validate_kcore_modules(kallsyms_filename, map); 1245a00d28cbSAdrian Hunter } 1246a00d28cbSAdrian Hunter 12478e0cf965SAdrian Hunter struct kcore_mapfn_data { 12488e0cf965SAdrian Hunter struct dso *dso; 12498e0cf965SAdrian Hunter struct list_head maps; 12508e0cf965SAdrian Hunter }; 12518e0cf965SAdrian Hunter 12528e0cf965SAdrian Hunter static int kcore_mapfn(u64 start, u64 len, u64 pgoff, void *data) 12538e0cf965SAdrian Hunter { 12548e0cf965SAdrian Hunter struct kcore_mapfn_data *md = data; 125583720209SIan Rogers struct map_list_node *list_node = map_list_node__new(); 12568e0cf965SAdrian Hunter 125783720209SIan Rogers if (!list_node) 12588e0cf965SAdrian Hunter return -ENOMEM; 12598e0cf965SAdrian Hunter 126083720209SIan Rogers list_node->map = map__new2(start, md->dso); 126183720209SIan Rogers if (!list_node->map) { 126283720209SIan Rogers free(list_node); 126383720209SIan Rogers return -ENOMEM; 126483720209SIan Rogers } 12658e0cf965SAdrian Hunter 1266e6a9efceSArnaldo Carvalho de Melo map__set_end(list_node->map, map__start(list_node->map) + len); 1267e6a9efceSArnaldo Carvalho de Melo map__set_pgoff(list_node->map, pgoff); 126883720209SIan Rogers 126983720209SIan Rogers list_add(&list_node->node, &md->maps); 12708e0cf965SAdrian Hunter 12718e0cf965SAdrian Hunter return 0; 12728e0cf965SAdrian Hunter } 12738e0cf965SAdrian Hunter 1274fb5a88d4SJiri Olsa /* 127579b6bb73SArnaldo Carvalho de Melo * Merges map into maps by splitting the new map within the existing map 127679b6bb73SArnaldo Carvalho de Melo * regions. 1277fb5a88d4SJiri Olsa */ 127879b6bb73SArnaldo Carvalho de Melo int maps__merge_in(struct maps *kmaps, struct map *new_map) 1279fb5a88d4SJiri Olsa { 1280ff583dc4SIan Rogers struct map_rb_node *rb_node; 1281fb5a88d4SJiri Olsa LIST_HEAD(merged); 1282ff583dc4SIan Rogers int err = 0; 1283fb5a88d4SJiri Olsa 1284ff583dc4SIan Rogers maps__for_each_entry(kmaps, rb_node) { 1285ff583dc4SIan Rogers struct map *old_map = rb_node->map; 1286ff583dc4SIan Rogers 1287fb5a88d4SJiri Olsa /* no overload with this one */ 1288e5116f46SIan Rogers if (map__end(new_map) < map__start(old_map) || 1289e5116f46SIan Rogers map__start(new_map) >= map__end(old_map)) 1290fb5a88d4SJiri Olsa continue; 1291fb5a88d4SJiri Olsa 1292e5116f46SIan Rogers if (map__start(new_map) < map__start(old_map)) { 1293fb5a88d4SJiri Olsa /* 1294fb5a88d4SJiri Olsa * |new...... 1295fb5a88d4SJiri Olsa * |old.... 1296fb5a88d4SJiri Olsa */ 1297e5116f46SIan Rogers if (map__end(new_map) < map__end(old_map)) { 1298fb5a88d4SJiri Olsa /* 1299fb5a88d4SJiri Olsa * |new......| -> |new..| 1300fb5a88d4SJiri Olsa * |old....| -> |old....| 1301fb5a88d4SJiri Olsa */ 1302e6a9efceSArnaldo Carvalho de Melo map__set_end(new_map, map__start(old_map)); 1303fb5a88d4SJiri Olsa } else { 1304fb5a88d4SJiri Olsa /* 1305fb5a88d4SJiri Olsa * |new.............| -> |new..| |new..| 1306fb5a88d4SJiri Olsa * |old....| -> |old....| 1307fb5a88d4SJiri Olsa */ 130883720209SIan Rogers struct map_list_node *m = map_list_node__new(); 1309fb5a88d4SJiri Olsa 1310ff583dc4SIan Rogers if (!m) { 1311ff583dc4SIan Rogers err = -ENOMEM; 1312ff583dc4SIan Rogers goto out; 1313ff583dc4SIan Rogers } 1314fb5a88d4SJiri Olsa 131583720209SIan Rogers m->map = map__clone(new_map); 131683720209SIan Rogers if (!m->map) { 131783720209SIan Rogers free(m); 1318ff583dc4SIan Rogers err = -ENOMEM; 1319ff583dc4SIan Rogers goto out; 132083720209SIan Rogers } 132183720209SIan Rogers 1322e6a9efceSArnaldo Carvalho de Melo map__set_end(m->map, map__start(old_map)); 1323fb5a88d4SJiri Olsa list_add_tail(&m->node, &merged); 1324e6a9efceSArnaldo Carvalho de Melo map__add_pgoff(new_map, map__end(old_map) - map__start(new_map)); 1325e6a9efceSArnaldo Carvalho de Melo map__set_start(new_map, map__end(old_map)); 1326fb5a88d4SJiri Olsa } 1327fb5a88d4SJiri Olsa } else { 1328fb5a88d4SJiri Olsa /* 1329fb5a88d4SJiri Olsa * |new...... 1330fb5a88d4SJiri Olsa * |old.... 1331fb5a88d4SJiri Olsa */ 1332e5116f46SIan Rogers if (map__end(new_map) < map__end(old_map)) { 1333fb5a88d4SJiri Olsa /* 1334fb5a88d4SJiri Olsa * |new..| -> x 1335fb5a88d4SJiri Olsa * |old.........| -> |old.........| 1336fb5a88d4SJiri Olsa */ 1337fb5a88d4SJiri Olsa map__put(new_map); 1338fb5a88d4SJiri Olsa new_map = NULL; 1339fb5a88d4SJiri Olsa break; 1340fb5a88d4SJiri Olsa } else { 1341fb5a88d4SJiri Olsa /* 1342fb5a88d4SJiri Olsa * |new......| -> |new...| 1343fb5a88d4SJiri Olsa * |old....| -> |old....| 1344fb5a88d4SJiri Olsa */ 1345e6a9efceSArnaldo Carvalho de Melo map__add_pgoff(new_map, map__end(old_map) - map__start(new_map)); 1346e6a9efceSArnaldo Carvalho de Melo map__set_start(new_map, map__end(old_map)); 1347fb5a88d4SJiri Olsa } 1348fb5a88d4SJiri Olsa } 1349fb5a88d4SJiri Olsa } 1350fb5a88d4SJiri Olsa 1351ff583dc4SIan Rogers out: 1352fb5a88d4SJiri Olsa while (!list_empty(&merged)) { 135383720209SIan Rogers struct map_list_node *old_node; 135483720209SIan Rogers 135583720209SIan Rogers old_node = list_entry(merged.next, struct map_list_node, node); 135683720209SIan Rogers list_del_init(&old_node->node); 1357ff583dc4SIan Rogers if (!err) 1358ff583dc4SIan Rogers err = maps__insert(kmaps, old_node->map); 135983720209SIan Rogers map__put(old_node->map); 136083720209SIan Rogers free(old_node); 1361fb5a88d4SJiri Olsa } 1362fb5a88d4SJiri Olsa 1363fb5a88d4SJiri Olsa if (new_map) { 1364ff583dc4SIan Rogers if (!err) 1365ff583dc4SIan Rogers err = maps__insert(kmaps, new_map); 1366fb5a88d4SJiri Olsa map__put(new_map); 1367fb5a88d4SJiri Olsa } 1368ff583dc4SIan Rogers return err; 1369fb5a88d4SJiri Olsa } 1370fb5a88d4SJiri Olsa 13718e0cf965SAdrian Hunter static int dso__load_kcore(struct dso *dso, struct map *map, 13728e0cf965SAdrian Hunter const char *kallsyms_filename) 13738e0cf965SAdrian Hunter { 137479b6bb73SArnaldo Carvalho de Melo struct maps *kmaps = map__kmaps(map); 13758e0cf965SAdrian Hunter struct kcore_mapfn_data md; 1376ff583dc4SIan Rogers struct map *replacement_map = NULL; 1377ff583dc4SIan Rogers struct map_rb_node *old_node, *next; 13781c5aae77SAdrian Hunter struct machine *machine; 13798e0cf965SAdrian Hunter bool is_64_bit; 13808e0cf965SAdrian Hunter int err, fd; 13818e0cf965SAdrian Hunter char kcore_filename[PATH_MAX]; 138256549978SAdrian Hunter u64 stext; 13838e0cf965SAdrian Hunter 1384ba92732eSWang Nan if (!kmaps) 1385ba92732eSWang Nan return -EINVAL; 1386ba92732eSWang Nan 13875ab6d715SIan Rogers machine = maps__machine(kmaps); 13881c5aae77SAdrian Hunter 13898e0cf965SAdrian Hunter /* This function requires that the map is the kernel map */ 1390efdd5c6bSArnaldo Carvalho de Melo if (!__map__is_kernel(map)) 13918e0cf965SAdrian Hunter return -EINVAL; 13928e0cf965SAdrian Hunter 139352afdaf9SAdrian Hunter if (!filename_from_kallsyms_filename(kcore_filename, "kcore", 13948e0cf965SAdrian Hunter kallsyms_filename)) 13958e0cf965SAdrian Hunter return -EINVAL; 13968e0cf965SAdrian Hunter 1397a00d28cbSAdrian Hunter /* Modules and kernel must be present at their original addresses */ 1398a00d28cbSAdrian Hunter if (validate_kcore_addresses(kallsyms_filename, map)) 139952afdaf9SAdrian Hunter return -EINVAL; 140052afdaf9SAdrian Hunter 14018e0cf965SAdrian Hunter md.dso = dso; 14028e0cf965SAdrian Hunter INIT_LIST_HEAD(&md.maps); 14038e0cf965SAdrian Hunter 14048e0cf965SAdrian Hunter fd = open(kcore_filename, O_RDONLY); 140536c8bb56SLi Zhang if (fd < 0) { 1406133de940SAdrian Hunter pr_debug("Failed to open %s. Note /proc/kcore requires CAP_SYS_RAWIO capability to access.\n", 140736c8bb56SLi Zhang kcore_filename); 14088e0cf965SAdrian Hunter return -EINVAL; 140936c8bb56SLi Zhang } 14108e0cf965SAdrian Hunter 14118e0cf965SAdrian Hunter /* Read new maps into temporary lists */ 1412ddee3f2bSIan Rogers err = file__read_maps(fd, map__prot(map) & PROT_EXEC, kcore_mapfn, &md, 14138e0cf965SAdrian Hunter &is_64_bit); 14148e0cf965SAdrian Hunter if (err) 14158e0cf965SAdrian Hunter goto out_err; 1416c6d8f2a4SAdrian Hunter dso->is_64_bit = is_64_bit; 14178e0cf965SAdrian Hunter 14188e0cf965SAdrian Hunter if (list_empty(&md.maps)) { 14198e0cf965SAdrian Hunter err = -EINVAL; 14208e0cf965SAdrian Hunter goto out_err; 14218e0cf965SAdrian Hunter } 14228e0cf965SAdrian Hunter 14238e0cf965SAdrian Hunter /* Remove old maps */ 1424ff583dc4SIan Rogers maps__for_each_entry_safe(kmaps, old_node, next) { 1425ff583dc4SIan Rogers struct map *old_map = old_node->map; 1426ff583dc4SIan Rogers 1427fb5a88d4SJiri Olsa /* 1428fb5a88d4SJiri Olsa * We need to preserve eBPF maps even if they are 1429fb5a88d4SJiri Olsa * covered by kcore, because we need to access 1430fb5a88d4SJiri Olsa * eBPF dso for source data. 1431fb5a88d4SJiri Olsa */ 1432fb5a88d4SJiri Olsa if (old_map != map && !__map__is_bpf_prog(old_map)) 143379b6bb73SArnaldo Carvalho de Melo maps__remove(kmaps, old_map); 14348e0cf965SAdrian Hunter } 14351c5aae77SAdrian Hunter machine->trampolines_mapped = false; 14368e0cf965SAdrian Hunter 143756549978SAdrian Hunter /* Find the kernel map using the '_stext' symbol */ 143856549978SAdrian Hunter if (!kallsyms__get_function_start(kallsyms_filename, "_stext", &stext)) { 14391c249565SKrister Johansen u64 replacement_size = 0; 144083720209SIan Rogers struct map_list_node *new_node; 14411c249565SKrister Johansen 144283720209SIan Rogers list_for_each_entry(new_node, &md.maps, node) { 144383720209SIan Rogers struct map *new_map = new_node->map; 1444e5116f46SIan Rogers u64 new_size = map__size(new_map); 14451c249565SKrister Johansen 1446e5116f46SIan Rogers if (!(stext >= map__start(new_map) && stext < map__end(new_map))) 14471c249565SKrister Johansen continue; 14481c249565SKrister Johansen 14491c249565SKrister Johansen /* 14501c249565SKrister Johansen * On some architectures, ARM64 for example, the kernel 14511c249565SKrister Johansen * text can get allocated inside of the vmalloc segment. 14521c249565SKrister Johansen * Select the smallest matching segment, in case stext 14531c249565SKrister Johansen * falls within more than one in the list. 14541c249565SKrister Johansen */ 14551c249565SKrister Johansen if (!replacement_map || new_size < replacement_size) { 14568e0cf965SAdrian Hunter replacement_map = new_map; 14571c249565SKrister Johansen replacement_size = new_size; 14588e0cf965SAdrian Hunter } 14598e0cf965SAdrian Hunter } 146056549978SAdrian Hunter } 14618e0cf965SAdrian Hunter 14628e0cf965SAdrian Hunter if (!replacement_map) 146383720209SIan Rogers replacement_map = list_entry(md.maps.next, struct map_list_node, node)->map; 14648e0cf965SAdrian Hunter 14658e0cf965SAdrian Hunter /* Add new maps */ 14668e0cf965SAdrian Hunter while (!list_empty(&md.maps)) { 146783720209SIan Rogers struct map_list_node *new_node = list_entry(md.maps.next, struct map_list_node, node); 146883720209SIan Rogers struct map *new_map = new_node->map; 146983720209SIan Rogers 147083720209SIan Rogers list_del_init(&new_node->node); 147183720209SIan Rogers 14722832ef81SIan Rogers if (RC_CHK_ACCESS(new_map) == RC_CHK_ACCESS(replacement_map)) { 14730d98a7afSJames Clark struct map *map_ref; 14740d98a7afSJames Clark 1475e6a9efceSArnaldo Carvalho de Melo map__set_start(map, map__start(new_map)); 1476e6a9efceSArnaldo Carvalho de Melo map__set_end(map, map__end(new_map)); 1477e6a9efceSArnaldo Carvalho de Melo map__set_pgoff(map, map__pgoff(new_map)); 1478e6a9efceSArnaldo Carvalho de Melo map__set_map_ip(map, map__map_ip_ptr(new_map)); 1479e6a9efceSArnaldo Carvalho de Melo map__set_unmap_ip(map, map__unmap_ip_ptr(new_map)); 14808e0cf965SAdrian Hunter /* Ensure maps are correctly ordered */ 14810d98a7afSJames Clark map_ref = map__get(map); 14820d98a7afSJames Clark maps__remove(kmaps, map_ref); 14830d98a7afSJames Clark err = maps__insert(kmaps, map_ref); 14840d98a7afSJames Clark map__put(map_ref); 148584c2cafaSArnaldo Carvalho de Melo map__put(new_map); 1486ff583dc4SIan Rogers if (err) 1487ff583dc4SIan Rogers goto out_err; 1488fb5a88d4SJiri Olsa } else { 1489fb5a88d4SJiri Olsa /* 1490fb5a88d4SJiri Olsa * Merge kcore map into existing maps, 1491fb5a88d4SJiri Olsa * and ensure that current maps (eBPF) 1492fb5a88d4SJiri Olsa * stay intact. 1493fb5a88d4SJiri Olsa */ 1494ff583dc4SIan Rogers if (maps__merge_in(kmaps, new_map)) { 1495ff583dc4SIan Rogers err = -EINVAL; 1496fb5a88d4SJiri Olsa goto out_err; 1497fb5a88d4SJiri Olsa } 1498ff583dc4SIan Rogers } 149983720209SIan Rogers free(new_node); 15008e0cf965SAdrian Hunter } 15018e0cf965SAdrian Hunter 15021c5aae77SAdrian Hunter if (machine__is(machine, "x86_64")) { 15031c5aae77SAdrian Hunter u64 addr; 15041c5aae77SAdrian Hunter 15051c5aae77SAdrian Hunter /* 15061c5aae77SAdrian Hunter * If one of the corresponding symbols is there, assume the 15071c5aae77SAdrian Hunter * entry trampoline maps are too. 15081c5aae77SAdrian Hunter */ 15091c5aae77SAdrian Hunter if (!kallsyms__get_function_start(kallsyms_filename, 15101c5aae77SAdrian Hunter ENTRY_TRAMPOLINE_NAME, 15111c5aae77SAdrian Hunter &addr)) 15121c5aae77SAdrian Hunter machine->trampolines_mapped = true; 15131c5aae77SAdrian Hunter } 15141c5aae77SAdrian Hunter 15158e0cf965SAdrian Hunter /* 15168e0cf965SAdrian Hunter * Set the data type and long name so that kcore can be read via 15178e0cf965SAdrian Hunter * dso__data_read_addr(). 15188e0cf965SAdrian Hunter */ 15191c695c88SJiri Olsa if (dso->kernel == DSO_SPACE__KERNEL_GUEST) 15205f70619dSArnaldo Carvalho de Melo dso->binary_type = DSO_BINARY_TYPE__GUEST_KCORE; 15218e0cf965SAdrian Hunter else 15225f70619dSArnaldo Carvalho de Melo dso->binary_type = DSO_BINARY_TYPE__KCORE; 15237e155d4dSArnaldo Carvalho de Melo dso__set_long_name(dso, strdup(kcore_filename), true); 15248e0cf965SAdrian Hunter 15258e0cf965SAdrian Hunter close(fd); 15268e0cf965SAdrian Hunter 1527ddee3f2bSIan Rogers if (map__prot(map) & PROT_EXEC) 15288e0cf965SAdrian Hunter pr_debug("Using %s for kernel object code\n", kcore_filename); 15298e0cf965SAdrian Hunter else 15308e0cf965SAdrian Hunter pr_debug("Using %s for kernel data\n", kcore_filename); 15318e0cf965SAdrian Hunter 15328e0cf965SAdrian Hunter return 0; 15338e0cf965SAdrian Hunter 15348e0cf965SAdrian Hunter out_err: 15358e0cf965SAdrian Hunter while (!list_empty(&md.maps)) { 153683720209SIan Rogers struct map_list_node *list_node; 153783720209SIan Rogers 153883720209SIan Rogers list_node = list_entry(md.maps.next, struct map_list_node, node); 153983720209SIan Rogers list_del_init(&list_node->node); 154083720209SIan Rogers map__zput(list_node->map); 154183720209SIan Rogers free(list_node); 15428e0cf965SAdrian Hunter } 15438e0cf965SAdrian Hunter close(fd); 1544ff583dc4SIan Rogers return err; 15458e0cf965SAdrian Hunter } 15468e0cf965SAdrian Hunter 1547d9b62abaSAdrian Hunter /* 1548d9b62abaSAdrian Hunter * If the kernel is relocated at boot time, kallsyms won't match. Compute the 1549d9b62abaSAdrian Hunter * delta based on the relocation reference symbol. 1550d9b62abaSAdrian Hunter */ 1551019c6820SArnaldo Carvalho de Melo static int kallsyms__delta(struct kmap *kmap, const char *filename, u64 *delta) 1552d9b62abaSAdrian Hunter { 1553d9b62abaSAdrian Hunter u64 addr; 1554d9b62abaSAdrian Hunter 1555d9b62abaSAdrian Hunter if (!kmap->ref_reloc_sym || !kmap->ref_reloc_sym->name) 1556d9b62abaSAdrian Hunter return 0; 1557d9b62abaSAdrian Hunter 1558b843f62aSArnaldo Carvalho de Melo if (kallsyms__get_function_start(filename, kmap->ref_reloc_sym->name, &addr)) 1559d9b62abaSAdrian Hunter return -1; 1560d9b62abaSAdrian Hunter 1561d9b62abaSAdrian Hunter *delta = addr - kmap->ref_reloc_sym->addr; 1562d9b62abaSAdrian Hunter return 0; 1563d9b62abaSAdrian Hunter } 1564d9b62abaSAdrian Hunter 1565e02092b9SArnaldo Carvalho de Melo int __dso__load_kallsyms(struct dso *dso, const char *filename, 1566be39db9fSArnaldo Carvalho de Melo struct map *map, bool no_kcore) 15672e538c4aSArnaldo Carvalho de Melo { 1568019c6820SArnaldo Carvalho de Melo struct kmap *kmap = map__kmap(map); 1569d9b62abaSAdrian Hunter u64 delta = 0; 1570d9b62abaSAdrian Hunter 1571ec80fde7SArnaldo Carvalho de Melo if (symbol__restricted_filename(filename, "/proc/kallsyms")) 1572ec80fde7SArnaldo Carvalho de Melo return -1; 1573ec80fde7SArnaldo Carvalho de Melo 1574019c6820SArnaldo Carvalho de Melo if (!kmap || !kmap->kmaps) 1575019c6820SArnaldo Carvalho de Melo return -1; 1576019c6820SArnaldo Carvalho de Melo 1577333cc76cSArnaldo Carvalho de Melo if (dso__load_all_kallsyms(dso, filename) < 0) 15782e538c4aSArnaldo Carvalho de Melo return -1; 15792e538c4aSArnaldo Carvalho de Melo 1580019c6820SArnaldo Carvalho de Melo if (kallsyms__delta(kmap, filename, &delta)) 1581d9b62abaSAdrian Hunter return -1; 1582d9b62abaSAdrian Hunter 1583838425f2SNamhyung Kim symbols__fixup_end(&dso->symbols, true); 15843183f8caSArnaldo Carvalho de Melo symbols__fixup_duplicate(&dso->symbols); 15853f5a4272SAnton Blanchard 15861c695c88SJiri Olsa if (dso->kernel == DSO_SPACE__KERNEL_GUEST) 158744f24cb3SJiri Olsa dso->symtab_type = DSO_BINARY_TYPE__GUEST_KALLSYMS; 1588a1645ce1SZhang, Yanmin else 158944f24cb3SJiri Olsa dso->symtab_type = DSO_BINARY_TYPE__KALLSYMS; 15902e538c4aSArnaldo Carvalho de Melo 1591e02092b9SArnaldo Carvalho de Melo if (!no_kcore && !dso__load_kcore(dso, map, filename)) 159279b6bb73SArnaldo Carvalho de Melo return maps__split_kallsyms_for_kcore(kmap->kmaps, dso); 15938e0cf965SAdrian Hunter else 159479b6bb73SArnaldo Carvalho de Melo return maps__split_kallsyms(kmap->kmaps, dso, delta, map); 1595af427bf5SArnaldo Carvalho de Melo } 1596af427bf5SArnaldo Carvalho de Melo 1597e02092b9SArnaldo Carvalho de Melo int dso__load_kallsyms(struct dso *dso, const char *filename, 1598be39db9fSArnaldo Carvalho de Melo struct map *map) 1599e02092b9SArnaldo Carvalho de Melo { 1600be39db9fSArnaldo Carvalho de Melo return __dso__load_kallsyms(dso, filename, map, false); 1601e02092b9SArnaldo Carvalho de Melo } 1602e02092b9SArnaldo Carvalho de Melo 16033183f8caSArnaldo Carvalho de Melo static int dso__load_perf_map(const char *map_path, struct dso *dso) 160480d496beSPekka Enberg { 160580d496beSPekka Enberg char *line = NULL; 160680d496beSPekka Enberg size_t n; 160780d496beSPekka Enberg FILE *file; 160880d496beSPekka Enberg int nr_syms = 0; 160980d496beSPekka Enberg 1610bf2e710bSKrister Johansen file = fopen(map_path, "r"); 161180d496beSPekka Enberg if (file == NULL) 161280d496beSPekka Enberg goto out_failure; 161380d496beSPekka Enberg 161480d496beSPekka Enberg while (!feof(file)) { 16159cffa8d5SPaul Mackerras u64 start, size; 161680d496beSPekka Enberg struct symbol *sym; 161780d496beSPekka Enberg int line_len, len; 161880d496beSPekka Enberg 161980d496beSPekka Enberg line_len = getline(&line, &n, file); 162080d496beSPekka Enberg if (line_len < 0) 162180d496beSPekka Enberg break; 162280d496beSPekka Enberg 162380d496beSPekka Enberg if (!line) 162480d496beSPekka Enberg goto out_failure; 162580d496beSPekka Enberg 162680d496beSPekka Enberg line[--line_len] = '\0'; /* \n */ 162780d496beSPekka Enberg 162880d496beSPekka Enberg len = hex2u64(line, &start); 162980d496beSPekka Enberg 163080d496beSPekka Enberg len++; 163180d496beSPekka Enberg if (len + 2 >= line_len) 163280d496beSPekka Enberg continue; 163380d496beSPekka Enberg 163480d496beSPekka Enberg len += hex2u64(line + len, &size); 163580d496beSPekka Enberg 163680d496beSPekka Enberg len++; 163780d496beSPekka Enberg if (len + 2 >= line_len) 163880d496beSPekka Enberg continue; 163980d496beSPekka Enberg 1640af30bffaSArnaldo Carvalho de Melo sym = symbol__new(start, size, STB_GLOBAL, STT_FUNC, line + len); 164180d496beSPekka Enberg 164280d496beSPekka Enberg if (sym == NULL) 164380d496beSPekka Enberg goto out_delete_line; 164480d496beSPekka Enberg 16453183f8caSArnaldo Carvalho de Melo symbols__insert(&dso->symbols, sym); 164680d496beSPekka Enberg nr_syms++; 164780d496beSPekka Enberg } 164880d496beSPekka Enberg 164980d496beSPekka Enberg free(line); 165080d496beSPekka Enberg fclose(file); 165180d496beSPekka Enberg 165280d496beSPekka Enberg return nr_syms; 165380d496beSPekka Enberg 165480d496beSPekka Enberg out_delete_line: 165580d496beSPekka Enberg free(line); 165680d496beSPekka Enberg out_failure: 165780d496beSPekka Enberg return -1; 165880d496beSPekka Enberg } 165980d496beSPekka Enberg 1660eac9a434SRemi Bernon #ifdef HAVE_LIBBFD_SUPPORT 1661eac9a434SRemi Bernon #define PACKAGE 'perf' 1662eac9a434SRemi Bernon #include <bfd.h> 1663eac9a434SRemi Bernon 1664eac9a434SRemi Bernon static int bfd_symbols__cmpvalue(const void *a, const void *b) 1665eac9a434SRemi Bernon { 1666eac9a434SRemi Bernon const asymbol *as = *(const asymbol **)a, *bs = *(const asymbol **)b; 1667eac9a434SRemi Bernon 1668eac9a434SRemi Bernon if (bfd_asymbol_value(as) != bfd_asymbol_value(bs)) 1669eac9a434SRemi Bernon return bfd_asymbol_value(as) - bfd_asymbol_value(bs); 1670eac9a434SRemi Bernon 1671eac9a434SRemi Bernon return bfd_asymbol_name(as)[0] - bfd_asymbol_name(bs)[0]; 1672eac9a434SRemi Bernon } 1673eac9a434SRemi Bernon 1674eac9a434SRemi Bernon static int bfd2elf_binding(asymbol *symbol) 1675eac9a434SRemi Bernon { 1676eac9a434SRemi Bernon if (symbol->flags & BSF_WEAK) 1677eac9a434SRemi Bernon return STB_WEAK; 1678eac9a434SRemi Bernon if (symbol->flags & BSF_GLOBAL) 1679eac9a434SRemi Bernon return STB_GLOBAL; 1680eac9a434SRemi Bernon if (symbol->flags & BSF_LOCAL) 1681eac9a434SRemi Bernon return STB_LOCAL; 1682eac9a434SRemi Bernon return -1; 1683eac9a434SRemi Bernon } 1684eac9a434SRemi Bernon 1685eac9a434SRemi Bernon int dso__load_bfd_symbols(struct dso *dso, const char *debugfile) 1686eac9a434SRemi Bernon { 1687eac9a434SRemi Bernon int err = -1; 168896de68ffSDmitry Safonov long symbols_size, symbols_count, i; 1689eac9a434SRemi Bernon asection *section; 1690eac9a434SRemi Bernon asymbol **symbols, *sym; 1691eac9a434SRemi Bernon struct symbol *symbol; 1692eac9a434SRemi Bernon bfd *abfd; 1693eac9a434SRemi Bernon u64 start, len; 1694eac9a434SRemi Bernon 169500a34234SNicholas Fraser abfd = bfd_openr(debugfile, NULL); 1696eac9a434SRemi Bernon if (!abfd) 1697eac9a434SRemi Bernon return -1; 1698eac9a434SRemi Bernon 1699eac9a434SRemi Bernon if (!bfd_check_format(abfd, bfd_object)) { 1700eac9a434SRemi Bernon pr_debug2("%s: cannot read %s bfd file.\n", __func__, 1701eac9a434SRemi Bernon dso->long_name); 1702eac9a434SRemi Bernon goto out_close; 1703eac9a434SRemi Bernon } 1704eac9a434SRemi Bernon 1705eac9a434SRemi Bernon if (bfd_get_flavour(abfd) == bfd_target_elf_flavour) 1706eac9a434SRemi Bernon goto out_close; 1707eac9a434SRemi Bernon 1708eac9a434SRemi Bernon symbols_size = bfd_get_symtab_upper_bound(abfd); 1709eac9a434SRemi Bernon if (symbols_size == 0) { 1710eac9a434SRemi Bernon bfd_close(abfd); 1711eac9a434SRemi Bernon return 0; 1712eac9a434SRemi Bernon } 1713eac9a434SRemi Bernon 1714eac9a434SRemi Bernon if (symbols_size < 0) 1715eac9a434SRemi Bernon goto out_close; 1716eac9a434SRemi Bernon 1717eac9a434SRemi Bernon symbols = malloc(symbols_size); 1718eac9a434SRemi Bernon if (!symbols) 1719eac9a434SRemi Bernon goto out_close; 1720eac9a434SRemi Bernon 1721eac9a434SRemi Bernon symbols_count = bfd_canonicalize_symtab(abfd, symbols); 1722eac9a434SRemi Bernon if (symbols_count < 0) 1723eac9a434SRemi Bernon goto out_free; 1724eac9a434SRemi Bernon 1725d2930edeSRemi Bernon section = bfd_get_section_by_name(abfd, ".text"); 1726d2930edeSRemi Bernon if (section) { 1727d2930edeSRemi Bernon for (i = 0; i < symbols_count; ++i) { 1728d2930edeSRemi Bernon if (!strcmp(bfd_asymbol_name(symbols[i]), "__ImageBase") || 1729d2930edeSRemi Bernon !strcmp(bfd_asymbol_name(symbols[i]), "__image_base__")) 1730d2930edeSRemi Bernon break; 1731d2930edeSRemi Bernon } 1732d2930edeSRemi Bernon if (i < symbols_count) { 1733d2930edeSRemi Bernon /* PE symbols can only have 4 bytes, so use .text high bits */ 1734d2930edeSRemi Bernon dso->text_offset = section->vma - (u32)section->vma; 1735d2930edeSRemi Bernon dso->text_offset += (u32)bfd_asymbol_value(symbols[i]); 1736d2930edeSRemi Bernon } else { 1737d2930edeSRemi Bernon dso->text_offset = section->vma - section->filepos; 1738d2930edeSRemi Bernon } 1739d2930edeSRemi Bernon } 1740d2930edeSRemi Bernon 1741eac9a434SRemi Bernon qsort(symbols, symbols_count, sizeof(asymbol *), bfd_symbols__cmpvalue); 1742eac9a434SRemi Bernon 1743eac9a434SRemi Bernon #ifdef bfd_get_section 1744eac9a434SRemi Bernon #define bfd_asymbol_section bfd_get_section 1745eac9a434SRemi Bernon #endif 1746eac9a434SRemi Bernon for (i = 0; i < symbols_count; ++i) { 1747eac9a434SRemi Bernon sym = symbols[i]; 1748eac9a434SRemi Bernon section = bfd_asymbol_section(sym); 1749eac9a434SRemi Bernon if (bfd2elf_binding(sym) < 0) 1750eac9a434SRemi Bernon continue; 1751eac9a434SRemi Bernon 1752eac9a434SRemi Bernon while (i + 1 < symbols_count && 1753eac9a434SRemi Bernon bfd_asymbol_section(symbols[i + 1]) == section && 1754eac9a434SRemi Bernon bfd2elf_binding(symbols[i + 1]) < 0) 1755eac9a434SRemi Bernon i++; 1756eac9a434SRemi Bernon 1757eac9a434SRemi Bernon if (i + 1 < symbols_count && 1758eac9a434SRemi Bernon bfd_asymbol_section(symbols[i + 1]) == section) 1759eac9a434SRemi Bernon len = symbols[i + 1]->value - sym->value; 1760eac9a434SRemi Bernon else 1761eac9a434SRemi Bernon len = section->size - sym->value; 1762eac9a434SRemi Bernon 1763eac9a434SRemi Bernon start = bfd_asymbol_value(sym) - dso->text_offset; 1764eac9a434SRemi Bernon symbol = symbol__new(start, len, bfd2elf_binding(sym), STT_FUNC, 1765eac9a434SRemi Bernon bfd_asymbol_name(sym)); 1766eac9a434SRemi Bernon if (!symbol) 1767eac9a434SRemi Bernon goto out_free; 1768eac9a434SRemi Bernon 1769eac9a434SRemi Bernon symbols__insert(&dso->symbols, symbol); 1770eac9a434SRemi Bernon } 1771eac9a434SRemi Bernon #ifdef bfd_get_section 1772eac9a434SRemi Bernon #undef bfd_asymbol_section 1773eac9a434SRemi Bernon #endif 1774eac9a434SRemi Bernon 1775838425f2SNamhyung Kim symbols__fixup_end(&dso->symbols, false); 1776eac9a434SRemi Bernon symbols__fixup_duplicate(&dso->symbols); 1777eac9a434SRemi Bernon dso->adjust_symbols = 1; 1778eac9a434SRemi Bernon 1779eac9a434SRemi Bernon err = 0; 1780eac9a434SRemi Bernon out_free: 1781eac9a434SRemi Bernon free(symbols); 1782eac9a434SRemi Bernon out_close: 1783eac9a434SRemi Bernon bfd_close(abfd); 1784eac9a434SRemi Bernon return err; 1785eac9a434SRemi Bernon } 1786eac9a434SRemi Bernon #endif 1787eac9a434SRemi Bernon 17881029f9feSNamhyung Kim static bool dso__is_compatible_symtab_type(struct dso *dso, bool kmod, 17891029f9feSNamhyung Kim enum dso_binary_type type) 17901029f9feSNamhyung Kim { 17911029f9feSNamhyung Kim switch (type) { 17921029f9feSNamhyung Kim case DSO_BINARY_TYPE__JAVA_JIT: 17931029f9feSNamhyung Kim case DSO_BINARY_TYPE__DEBUGLINK: 17941029f9feSNamhyung Kim case DSO_BINARY_TYPE__SYSTEM_PATH_DSO: 17951029f9feSNamhyung Kim case DSO_BINARY_TYPE__FEDORA_DEBUGINFO: 17961029f9feSNamhyung Kim case DSO_BINARY_TYPE__UBUNTU_DEBUGINFO: 179785afd355SAdrian Hunter case DSO_BINARY_TYPE__MIXEDUP_UBUNTU_DEBUGINFO: 17981029f9feSNamhyung Kim case DSO_BINARY_TYPE__BUILDID_DEBUGINFO: 17991029f9feSNamhyung Kim case DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO: 18001c695c88SJiri Olsa return !kmod && dso->kernel == DSO_SPACE__USER; 18011029f9feSNamhyung Kim 18021029f9feSNamhyung Kim case DSO_BINARY_TYPE__KALLSYMS: 18031029f9feSNamhyung Kim case DSO_BINARY_TYPE__VMLINUX: 18041029f9feSNamhyung Kim case DSO_BINARY_TYPE__KCORE: 18051c695c88SJiri Olsa return dso->kernel == DSO_SPACE__KERNEL; 18061029f9feSNamhyung Kim 18071029f9feSNamhyung Kim case DSO_BINARY_TYPE__GUEST_KALLSYMS: 18081029f9feSNamhyung Kim case DSO_BINARY_TYPE__GUEST_VMLINUX: 18091029f9feSNamhyung Kim case DSO_BINARY_TYPE__GUEST_KCORE: 18101c695c88SJiri Olsa return dso->kernel == DSO_SPACE__KERNEL_GUEST; 18111029f9feSNamhyung Kim 18121029f9feSNamhyung Kim case DSO_BINARY_TYPE__GUEST_KMODULE: 1813c00c48fcSNamhyung Kim case DSO_BINARY_TYPE__GUEST_KMODULE_COMP: 18141029f9feSNamhyung Kim case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE: 1815c00c48fcSNamhyung Kim case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP: 18161029f9feSNamhyung Kim /* 18171029f9feSNamhyung Kim * kernel modules know their symtab type - it's set when 1818a94ab91aSArnaldo Carvalho de Melo * creating a module dso in machine__addnew_module_map(). 18191029f9feSNamhyung Kim */ 18201029f9feSNamhyung Kim return kmod && dso->symtab_type == type; 18211029f9feSNamhyung Kim 18221029f9feSNamhyung Kim case DSO_BINARY_TYPE__BUILD_ID_CACHE: 1823d2396999SKrister Johansen case DSO_BINARY_TYPE__BUILD_ID_CACHE_DEBUGINFO: 18241029f9feSNamhyung Kim return true; 18251029f9feSNamhyung Kim 18269b86d04dSSong Liu case DSO_BINARY_TYPE__BPF_PROG_INFO: 18273c29d448SJiri Olsa case DSO_BINARY_TYPE__BPF_IMAGE: 1828789e2419SAdrian Hunter case DSO_BINARY_TYPE__OOL: 18291029f9feSNamhyung Kim case DSO_BINARY_TYPE__NOT_FOUND: 18301029f9feSNamhyung Kim default: 18311029f9feSNamhyung Kim return false; 18321029f9feSNamhyung Kim } 18331029f9feSNamhyung Kim } 18341029f9feSNamhyung Kim 1835bf2e710bSKrister Johansen /* Checks for the existence of the perf-<pid>.map file in two different 1836bf2e710bSKrister Johansen * locations. First, if the process is a separate mount namespace, check in 1837bf2e710bSKrister Johansen * that namespace using the pid of the innermost pid namespace. If's not in a 1838bf2e710bSKrister Johansen * namespace, or the file can't be found there, try in the mount namespace of 1839bf2e710bSKrister Johansen * the tracing process using our view of its pid. 1840bf2e710bSKrister Johansen */ 1841bf2e710bSKrister Johansen static int dso__find_perf_map(char *filebuf, size_t bufsz, 1842bf2e710bSKrister Johansen struct nsinfo **nsip) 1843bf2e710bSKrister Johansen { 1844bf2e710bSKrister Johansen struct nscookie nsc; 1845bf2e710bSKrister Johansen struct nsinfo *nsi; 1846bf2e710bSKrister Johansen struct nsinfo *nnsi; 1847bf2e710bSKrister Johansen int rc = -1; 1848bf2e710bSKrister Johansen 1849bf2e710bSKrister Johansen nsi = *nsip; 1850bf2e710bSKrister Johansen 1851bcaf0a97SIan Rogers if (nsinfo__need_setns(nsi)) { 1852bcaf0a97SIan Rogers snprintf(filebuf, bufsz, "/tmp/perf-%d.map", nsinfo__nstgid(nsi)); 1853bf2e710bSKrister Johansen nsinfo__mountns_enter(nsi, &nsc); 1854bf2e710bSKrister Johansen rc = access(filebuf, R_OK); 1855bf2e710bSKrister Johansen nsinfo__mountns_exit(&nsc); 1856bf2e710bSKrister Johansen if (rc == 0) 1857bf2e710bSKrister Johansen return rc; 1858bf2e710bSKrister Johansen } 1859bf2e710bSKrister Johansen 1860bf2e710bSKrister Johansen nnsi = nsinfo__copy(nsi); 1861bf2e710bSKrister Johansen if (nnsi) { 1862bf2e710bSKrister Johansen nsinfo__put(nsi); 1863bf2e710bSKrister Johansen 1864bcaf0a97SIan Rogers nsinfo__clear_need_setns(nnsi); 1865bcaf0a97SIan Rogers snprintf(filebuf, bufsz, "/tmp/perf-%d.map", nsinfo__tgid(nnsi)); 1866bf2e710bSKrister Johansen *nsip = nnsi; 1867bf2e710bSKrister Johansen rc = 0; 1868bf2e710bSKrister Johansen } 1869bf2e710bSKrister Johansen 1870bf2e710bSKrister Johansen return rc; 1871bf2e710bSKrister Johansen } 1872bf2e710bSKrister Johansen 1873be39db9fSArnaldo Carvalho de Melo int dso__load(struct dso *dso, struct map *map) 187486470930SIngo Molnar { 1875c338aee8SArnaldo Carvalho de Melo char *name; 187686470930SIngo Molnar int ret = -1; 187744f24cb3SJiri Olsa u_int i; 187893fcce96SArnaldo Carvalho de Melo struct machine *machine = NULL; 187944f24cb3SJiri Olsa char *root_dir = (char *) ""; 18803aafe5aeSCody P Schafer int ss_pos = 0; 18813aafe5aeSCody P Schafer struct symsrc ss_[2]; 18823aafe5aeSCody P Schafer struct symsrc *syms_ss = NULL, *runtime_ss = NULL; 18831029f9feSNamhyung Kim bool kmod; 1884bf2e710bSKrister Johansen bool perfmap; 1885f766819cSJiri Olsa struct build_id bid; 1886843ff37bSKrister Johansen struct nscookie nsc; 1887bf2e710bSKrister Johansen char newmapname[PATH_MAX]; 1888bf2e710bSKrister Johansen const char *map_path = dso->long_name; 1889bf2e710bSKrister Johansen 1890e54dea69SIan Rogers mutex_lock(&dso->lock); 1891bf2e710bSKrister Johansen perfmap = strncmp(dso->name, "/tmp/perf-", 10) == 0; 1892bf2e710bSKrister Johansen if (perfmap) { 1893bf2e710bSKrister Johansen if (dso->nsinfo && (dso__find_perf_map(newmapname, 1894bf2e710bSKrister Johansen sizeof(newmapname), &dso->nsinfo) == 0)) { 1895bf2e710bSKrister Johansen map_path = newmapname; 1896bf2e710bSKrister Johansen } 1897bf2e710bSKrister Johansen } 189886470930SIngo Molnar 1899843ff37bSKrister Johansen nsinfo__mountns_enter(dso->nsinfo, &nsc); 190066bd8424SArnaldo Carvalho de Melo 19014a936edcSNamhyung Kim /* check again under the dso->lock */ 19023183f8caSArnaldo Carvalho de Melo if (dso__loaded(dso)) { 19034a936edcSNamhyung Kim ret = 1; 19044a936edcSNamhyung Kim goto out; 19054a936edcSNamhyung Kim } 19064a936edcSNamhyung Kim 1907b5c09518SArnaldo Carvalho de Melo kmod = dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE || 1908b5c09518SArnaldo Carvalho de Melo dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP || 1909b5c09518SArnaldo Carvalho de Melo dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE || 1910b5c09518SArnaldo Carvalho de Melo dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE_COMP; 1911b5c09518SArnaldo Carvalho de Melo 1912b5c09518SArnaldo Carvalho de Melo if (dso->kernel && !kmod) { 19131c695c88SJiri Olsa if (dso->kernel == DSO_SPACE__KERNEL) 1914be39db9fSArnaldo Carvalho de Melo ret = dso__load_kernel_sym(dso, map); 19151c695c88SJiri Olsa else if (dso->kernel == DSO_SPACE__KERNEL_GUEST) 1916be39db9fSArnaldo Carvalho de Melo ret = dso__load_guest_kernel_sym(dso, map); 19174a936edcSNamhyung Kim 19185ab6d715SIan Rogers machine = maps__machine(map__kmaps(map)); 19194d99e413SAdrian Hunter if (machine__is(machine, "x86_64")) 19204d99e413SAdrian Hunter machine__map_x86_64_entry_trampolines(machine, dso); 19214a936edcSNamhyung Kim goto out; 19224a936edcSNamhyung Kim } 1923a1645ce1SZhang, Yanmin 1924aeafcbafSArnaldo Carvalho de Melo dso->adjust_symbols = 0; 1925f5812a7aSArnaldo Carvalho de Melo 1926bf2e710bSKrister Johansen if (perfmap) { 19273183f8caSArnaldo Carvalho de Melo ret = dso__load_perf_map(map_path, dso); 192844f24cb3SJiri Olsa dso->symtab_type = ret > 0 ? DSO_BINARY_TYPE__JAVA_JIT : 192944f24cb3SJiri Olsa DSO_BINARY_TYPE__NOT_FOUND; 19304a936edcSNamhyung Kim goto out; 193194cb9e38SArnaldo Carvalho de Melo } 193294cb9e38SArnaldo Carvalho de Melo 193344f24cb3SJiri Olsa if (machine) 193444f24cb3SJiri Olsa root_dir = machine->root_dir; 193544f24cb3SJiri Olsa 1936164c800eSDavid Ahern name = malloc(PATH_MAX); 1937164c800eSDavid Ahern if (!name) 19384a936edcSNamhyung Kim goto out; 1939164c800eSDavid Ahern 19405baecbcdSDima Kogan /* 19415baecbcdSDima Kogan * Read the build id if possible. This is required for 19425baecbcdSDima Kogan * DSO_BINARY_TYPE__BUILDID_DEBUGINFO to work 19435baecbcdSDima Kogan */ 1944ed6c166cSKan Liang if (!dso->has_build_id && 19459b200653SVictor Kamensky is_regular_file(dso->long_name)) { 19469b200653SVictor Kamensky __symbol__join_symfs(name, PATH_MAX, dso->long_name); 1947f766819cSJiri Olsa if (filename__read_build_id(name, &bid) > 0) 19488dfdf440SJiri Olsa dso__set_build_id(dso, &bid); 19499b200653SVictor Kamensky } 19505baecbcdSDima Kogan 19511029f9feSNamhyung Kim /* 19521029f9feSNamhyung Kim * Iterate over candidate debug images. 19533aafe5aeSCody P Schafer * Keep track of "interesting" ones (those which have a symtab, dynsym, 19543aafe5aeSCody P Schafer * and/or opd section) for processing. 19556da80ce8SDave Martin */ 195644f24cb3SJiri Olsa for (i = 0; i < DSO_BINARY_TYPE__SYMTAB_CNT; i++) { 19573aafe5aeSCody P Schafer struct symsrc *ss = &ss_[ss_pos]; 19583aafe5aeSCody P Schafer bool next_slot = false; 1959f045b8c4SKrister Johansen bool is_reg; 1960d2396999SKrister Johansen bool nsexit; 1961eac9a434SRemi Bernon int bfdrc = -1; 1962c3962961SJiri Olsa int sirc = -1; 196344f24cb3SJiri Olsa 1964005f9294SCody P Schafer enum dso_binary_type symtab_type = binary_type_symtab[i]; 196544f24cb3SJiri Olsa 1966d2396999SKrister Johansen nsexit = (symtab_type == DSO_BINARY_TYPE__BUILD_ID_CACHE || 1967d2396999SKrister Johansen symtab_type == DSO_BINARY_TYPE__BUILD_ID_CACHE_DEBUGINFO); 1968d2396999SKrister Johansen 19691029f9feSNamhyung Kim if (!dso__is_compatible_symtab_type(dso, kmod, symtab_type)) 19701029f9feSNamhyung Kim continue; 19711029f9feSNamhyung Kim 1972ee4e9625SArnaldo Carvalho de Melo if (dso__read_binary_type_filename(dso, symtab_type, 197344f24cb3SJiri Olsa root_dir, name, PATH_MAX)) 19746da80ce8SDave Martin continue; 197586470930SIngo Molnar 1976d2396999SKrister Johansen if (nsexit) 1977f045b8c4SKrister Johansen nsinfo__mountns_exit(&nsc); 197840356721SJiri Olsa 1979f045b8c4SKrister Johansen is_reg = is_regular_file(name); 198067fd1892SNamhyung Kim if (!is_reg && errno == ENOENT && dso->nsinfo) { 19817031edacSArnaldo Carvalho de Melo char *new_name = dso__filename_with_chroot(dso, name); 198267fd1892SNamhyung Kim if (new_name) { 198367fd1892SNamhyung Kim is_reg = is_regular_file(new_name); 198467fd1892SNamhyung Kim strlcpy(name, new_name, PATH_MAX); 198567fd1892SNamhyung Kim free(new_name); 198667fd1892SNamhyung Kim } 198767fd1892SNamhyung Kim } 198867fd1892SNamhyung Kim 1989eac9a434SRemi Bernon #ifdef HAVE_LIBBFD_SUPPORT 1990c3962961SJiri Olsa if (is_reg) 1991eac9a434SRemi Bernon bfdrc = dso__load_bfd_symbols(dso, name); 1992eac9a434SRemi Bernon #endif 1993eac9a434SRemi Bernon if (is_reg && bfdrc < 0) 1994f045b8c4SKrister Johansen sirc = symsrc__init(ss, dso, name, symtab_type); 1995f045b8c4SKrister Johansen 1996d2396999SKrister Johansen if (nsexit) 1997f045b8c4SKrister Johansen nsinfo__mountns_enter(dso->nsinfo, &nsc); 1998f045b8c4SKrister Johansen 199977771a97SNicholas Fraser if (bfdrc == 0) { 200077771a97SNicholas Fraser ret = 0; 2001eac9a434SRemi Bernon break; 200277771a97SNicholas Fraser } 2003eac9a434SRemi Bernon 2004c3962961SJiri Olsa if (!is_reg || sirc < 0) 20056da80ce8SDave Martin continue; 20066da80ce8SDave Martin 20073aafe5aeSCody P Schafer if (!syms_ss && symsrc__has_symtab(ss)) { 20083aafe5aeSCody P Schafer syms_ss = ss; 20093aafe5aeSCody P Schafer next_slot = true; 20100058aef6SAdrian Hunter if (!dso->symsrc_filename) 20110058aef6SAdrian Hunter dso->symsrc_filename = strdup(name); 2012d26cd12bSCody P Schafer } 2013d26cd12bSCody P Schafer 20143aafe5aeSCody P Schafer if (!runtime_ss && symsrc__possibly_runtime(ss)) { 20153aafe5aeSCody P Schafer runtime_ss = ss; 20163aafe5aeSCody P Schafer next_slot = true; 2017a44f605bSCody P Schafer } 201886470930SIngo Molnar 20193aafe5aeSCody P Schafer if (next_slot) { 20203aafe5aeSCody P Schafer ss_pos++; 202133ff581eSJiri Olsa 20223aafe5aeSCody P Schafer if (syms_ss && runtime_ss) 20236da80ce8SDave Martin break; 202498e9f03bSNamhyung Kim } else { 202598e9f03bSNamhyung Kim symsrc__destroy(ss); 2026a25e46c4SArnaldo Carvalho de Melo } 20273aafe5aeSCody P Schafer 20286da80ce8SDave Martin } 20296da80ce8SDave Martin 20303aafe5aeSCody P Schafer if (!runtime_ss && !syms_ss) 20313aafe5aeSCody P Schafer goto out_free; 20323aafe5aeSCody P Schafer 20333aafe5aeSCody P Schafer if (runtime_ss && !syms_ss) { 20343aafe5aeSCody P Schafer syms_ss = runtime_ss; 203560e4b10cSArnaldo Carvalho de Melo } 203660e4b10cSArnaldo Carvalho de Melo 20373aafe5aeSCody P Schafer /* We'll have to hope for the best */ 20383aafe5aeSCody P Schafer if (!runtime_ss && syms_ss) 20393aafe5aeSCody P Schafer runtime_ss = syms_ss; 20403aafe5aeSCody P Schafer 20411029f9feSNamhyung Kim if (syms_ss) 2042be39db9fSArnaldo Carvalho de Melo ret = dso__load_sym(dso, map, syms_ss, runtime_ss, kmod); 20431029f9feSNamhyung Kim else 20443aafe5aeSCody P Schafer ret = -1; 20453aafe5aeSCody P Schafer 2046f47b58b7SDavid Ahern if (ret > 0) { 20473aafe5aeSCody P Schafer int nr_plt; 20483aafe5aeSCody P Schafer 20493183f8caSArnaldo Carvalho de Melo nr_plt = dso__synthesize_plt_symbols(dso, runtime_ss); 20503aafe5aeSCody P Schafer if (nr_plt > 0) 20513aafe5aeSCody P Schafer ret += nr_plt; 20523aafe5aeSCody P Schafer } 20533aafe5aeSCody P Schafer 20543aafe5aeSCody P Schafer for (; ss_pos > 0; ss_pos--) 20553aafe5aeSCody P Schafer symsrc__destroy(&ss_[ss_pos - 1]); 20563aafe5aeSCody P Schafer out_free: 205786470930SIngo Molnar free(name); 2058aeafcbafSArnaldo Carvalho de Melo if (ret < 0 && strstr(dso->name, " (deleted)") != NULL) 20594a936edcSNamhyung Kim ret = 0; 20604a936edcSNamhyung Kim out: 20613183f8caSArnaldo Carvalho de Melo dso__set_loaded(dso); 2062d9a0d6b8SIan Rogers mutex_unlock(&dso->lock); 2063843ff37bSKrister Johansen nsinfo__mountns_exit(&nsc); 20644a936edcSNamhyung Kim 206586470930SIngo Molnar return ret; 206686470930SIngo Molnar } 206786470930SIngo Molnar 2068a7c2b572SArnaldo Carvalho de Melo static int map__strcmp(const void *a, const void *b) 2069a7c2b572SArnaldo Carvalho de Melo { 2070392cf49eSIan Rogers const struct map *map_a = *(const struct map **)a; 2071392cf49eSIan Rogers const struct map *map_b = *(const struct map **)b; 2072392cf49eSIan Rogers const struct dso *dso_a = map__dso(map_a); 2073392cf49eSIan Rogers const struct dso *dso_b = map__dso(map_b); 2074392cf49eSIan Rogers int ret = strcmp(dso_a->short_name, dso_b->short_name); 207563df0e4bSIan Rogers 2076392cf49eSIan Rogers if (ret == 0 && map_a != map_b) { 2077392cf49eSIan Rogers /* 2078392cf49eSIan Rogers * Ensure distinct but name equal maps have an order in part to 2079392cf49eSIan Rogers * aid reference counting. 2080392cf49eSIan Rogers */ 2081392cf49eSIan Rogers ret = (int)map__start(map_a) - (int)map__start(map_b); 2082392cf49eSIan Rogers if (ret == 0) 2083392cf49eSIan Rogers ret = (int)((intptr_t)map_a - (intptr_t)map_b); 2084392cf49eSIan Rogers } 2085392cf49eSIan Rogers 2086392cf49eSIan Rogers return ret; 2087a7c2b572SArnaldo Carvalho de Melo } 2088a7c2b572SArnaldo Carvalho de Melo 2089a7c2b572SArnaldo Carvalho de Melo static int map__strcmp_name(const void *name, const void *b) 2090a7c2b572SArnaldo Carvalho de Melo { 209163df0e4bSIan Rogers const struct dso *dso = map__dso(*(const struct map **)b); 209263df0e4bSIan Rogers 209363df0e4bSIan Rogers return strcmp(name, dso->short_name); 2094a7c2b572SArnaldo Carvalho de Melo } 2095a7c2b572SArnaldo Carvalho de Melo 20969a29ceeeSArnaldo Carvalho de Melo void __maps__sort_by_name(struct maps *maps) 2097a7c2b572SArnaldo Carvalho de Melo { 20985ab6d715SIan Rogers qsort(maps__maps_by_name(maps), maps__nr_maps(maps), sizeof(struct map *), map__strcmp); 2099a7c2b572SArnaldo Carvalho de Melo } 2100a7c2b572SArnaldo Carvalho de Melo 21019a29ceeeSArnaldo Carvalho de Melo static int map__groups__sort_by_name_from_rbtree(struct maps *maps) 2102a7c2b572SArnaldo Carvalho de Melo { 2103ff583dc4SIan Rogers struct map_rb_node *rb_node; 21045ab6d715SIan Rogers struct map **maps_by_name = realloc(maps__maps_by_name(maps), 21055ab6d715SIan Rogers maps__nr_maps(maps) * sizeof(struct map *)); 2106a7c2b572SArnaldo Carvalho de Melo int i = 0; 2107a7c2b572SArnaldo Carvalho de Melo 2108a7c2b572SArnaldo Carvalho de Melo if (maps_by_name == NULL) 2109a7c2b572SArnaldo Carvalho de Melo return -1; 2110a7c2b572SArnaldo Carvalho de Melo 21115ab6d715SIan Rogers up_read(maps__lock(maps)); 21125ab6d715SIan Rogers down_write(maps__lock(maps)); 2113ec9640f7SIan Rogers 21148f12692bSIan Rogers RC_CHK_ACCESS(maps)->maps_by_name = maps_by_name; 21158f12692bSIan Rogers RC_CHK_ACCESS(maps)->nr_maps_allocated = maps__nr_maps(maps); 2116a7c2b572SArnaldo Carvalho de Melo 2117ff583dc4SIan Rogers maps__for_each_entry(maps, rb_node) 2118392cf49eSIan Rogers maps_by_name[i++] = map__get(rb_node->map); 2119a7c2b572SArnaldo Carvalho de Melo 21209a29ceeeSArnaldo Carvalho de Melo __maps__sort_by_name(maps); 2121ec9640f7SIan Rogers 21225ab6d715SIan Rogers up_write(maps__lock(maps)); 21235ab6d715SIan Rogers down_read(maps__lock(maps)); 2124ec9640f7SIan Rogers 2125a7c2b572SArnaldo Carvalho de Melo return 0; 2126a7c2b572SArnaldo Carvalho de Melo } 2127a7c2b572SArnaldo Carvalho de Melo 21289a29ceeeSArnaldo Carvalho de Melo static struct map *__maps__find_by_name(struct maps *maps, const char *name) 2129a7c2b572SArnaldo Carvalho de Melo { 2130a7c2b572SArnaldo Carvalho de Melo struct map **mapp; 2131a7c2b572SArnaldo Carvalho de Melo 21325ab6d715SIan Rogers if (maps__maps_by_name(maps) == NULL && 21339a29ceeeSArnaldo Carvalho de Melo map__groups__sort_by_name_from_rbtree(maps)) 2134a7c2b572SArnaldo Carvalho de Melo return NULL; 2135a7c2b572SArnaldo Carvalho de Melo 21365ab6d715SIan Rogers mapp = bsearch(name, maps__maps_by_name(maps), maps__nr_maps(maps), 21375ab6d715SIan Rogers sizeof(*mapp), map__strcmp_name); 2138a7c2b572SArnaldo Carvalho de Melo if (mapp) 2139a7c2b572SArnaldo Carvalho de Melo return *mapp; 2140a7c2b572SArnaldo Carvalho de Melo return NULL; 2141a7c2b572SArnaldo Carvalho de Melo } 2142a7c2b572SArnaldo Carvalho de Melo 21439a29ceeeSArnaldo Carvalho de Melo struct map *maps__find_by_name(struct maps *maps, const char *name) 2144439d473bSArnaldo Carvalho de Melo { 2145ff583dc4SIan Rogers struct map_rb_node *rb_node; 21464bb7123dSArnaldo Carvalho de Melo struct map *map; 2147439d473bSArnaldo Carvalho de Melo 21485ab6d715SIan Rogers down_read(maps__lock(maps)); 21496a2ffcddSArnaldo Carvalho de Melo 21508f12692bSIan Rogers 21518f12692bSIan Rogers if (RC_CHK_ACCESS(maps)->last_search_by_name) { 21528f12692bSIan Rogers const struct dso *dso = map__dso(RC_CHK_ACCESS(maps)->last_search_by_name); 215363df0e4bSIan Rogers 215463df0e4bSIan Rogers if (strcmp(dso->short_name, name) == 0) { 21558f12692bSIan Rogers map = RC_CHK_ACCESS(maps)->last_search_by_name; 21566a2ffcddSArnaldo Carvalho de Melo goto out_unlock; 21571ae14516SArnaldo Carvalho de Melo } 215863df0e4bSIan Rogers } 2159a7c2b572SArnaldo Carvalho de Melo /* 21609a29ceeeSArnaldo Carvalho de Melo * If we have maps->maps_by_name, then the name isn't in the rbtree, 21619a29ceeeSArnaldo Carvalho de Melo * as maps->maps_by_name mirrors the rbtree when lookups by name are 2162a7c2b572SArnaldo Carvalho de Melo * made. 2163a7c2b572SArnaldo Carvalho de Melo */ 21649a29ceeeSArnaldo Carvalho de Melo map = __maps__find_by_name(maps, name); 21655ab6d715SIan Rogers if (map || maps__maps_by_name(maps) != NULL) 2166a7c2b572SArnaldo Carvalho de Melo goto out_unlock; 21671ae14516SArnaldo Carvalho de Melo 2168a7c2b572SArnaldo Carvalho de Melo /* Fallback to traversing the rbtree... */ 2169ff583dc4SIan Rogers maps__for_each_entry(maps, rb_node) { 217063df0e4bSIan Rogers struct dso *dso; 217163df0e4bSIan Rogers 2172ff583dc4SIan Rogers map = rb_node->map; 217363df0e4bSIan Rogers dso = map__dso(map); 217463df0e4bSIan Rogers if (strcmp(dso->short_name, name) == 0) { 21758f12692bSIan Rogers RC_CHK_ACCESS(maps)->last_search_by_name = map; 21761ae14516SArnaldo Carvalho de Melo goto out_unlock; 21771ae14516SArnaldo Carvalho de Melo } 2178ff583dc4SIan Rogers } 21796a2ffcddSArnaldo Carvalho de Melo map = NULL; 21806a2ffcddSArnaldo Carvalho de Melo 21816a2ffcddSArnaldo Carvalho de Melo out_unlock: 21825ab6d715SIan Rogers up_read(maps__lock(maps)); 21836a2ffcddSArnaldo Carvalho de Melo return map; 2184439d473bSArnaldo Carvalho de Melo } 2185439d473bSArnaldo Carvalho de Melo 2186aeafcbafSArnaldo Carvalho de Melo int dso__load_vmlinux(struct dso *dso, struct map *map, 2187be39db9fSArnaldo Carvalho de Melo const char *vmlinux, bool vmlinux_allocated) 218886470930SIngo Molnar { 2189b68e2f91SCody P Schafer int err = -1; 2190b68e2f91SCody P Schafer struct symsrc ss; 2191ec5761eaSDavid Ahern char symfs_vmlinux[PATH_MAX]; 2192005f9294SCody P Schafer enum dso_binary_type symtab_type; 219386470930SIngo Molnar 21945698d2c9SNamhyung Kim if (vmlinux[0] == '/') 21955698d2c9SNamhyung Kim snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s", vmlinux); 21965698d2c9SNamhyung Kim else 2197972f393bSArnaldo Carvalho de Melo symbol__join_symfs(symfs_vmlinux, vmlinux); 219886470930SIngo Molnar 21991c695c88SJiri Olsa if (dso->kernel == DSO_SPACE__KERNEL_GUEST) 2200005f9294SCody P Schafer symtab_type = DSO_BINARY_TYPE__GUEST_VMLINUX; 220121ea4539SCody P Schafer else 2202005f9294SCody P Schafer symtab_type = DSO_BINARY_TYPE__VMLINUX; 220321ea4539SCody P Schafer 2204005f9294SCody P Schafer if (symsrc__init(&ss, dso, symfs_vmlinux, symtab_type)) 2205b68e2f91SCody P Schafer return -1; 2206b68e2f91SCody P Schafer 2207*e59fea47SAthira Rajeev /* 2208*e59fea47SAthira Rajeev * dso__load_sym() may copy 'dso' which will result in the copies having 2209*e59fea47SAthira Rajeev * an incorrect long name unless we set it here first. 2210*e59fea47SAthira Rajeev */ 2211*e59fea47SAthira Rajeev dso__set_long_name(dso, vmlinux, vmlinux_allocated); 22121c695c88SJiri Olsa if (dso->kernel == DSO_SPACE__KERNEL_GUEST) 22135f70619dSArnaldo Carvalho de Melo dso->binary_type = DSO_BINARY_TYPE__GUEST_VMLINUX; 221439b12f78SAdrian Hunter else 22155f70619dSArnaldo Carvalho de Melo dso->binary_type = DSO_BINARY_TYPE__VMLINUX; 2216*e59fea47SAthira Rajeev 2217*e59fea47SAthira Rajeev err = dso__load_sym(dso, map, &ss, &ss, 0); 2218*e59fea47SAthira Rajeev symsrc__destroy(&ss); 2219*e59fea47SAthira Rajeev 2220*e59fea47SAthira Rajeev if (err > 0) { 22213183f8caSArnaldo Carvalho de Melo dso__set_loaded(dso); 2222ec5761eaSDavid Ahern pr_debug("Using %s for symbols\n", symfs_vmlinux); 2223515850e4SCody P Schafer } 22243846df2eSArnaldo Carvalho de Melo 222586470930SIngo Molnar return err; 222686470930SIngo Molnar } 222786470930SIngo Molnar 2228be39db9fSArnaldo Carvalho de Melo int dso__load_vmlinux_path(struct dso *dso, struct map *map) 2229a19afe46SArnaldo Carvalho de Melo { 2230a19afe46SArnaldo Carvalho de Melo int i, err = 0; 223100dc8657SNamhyung Kim char *filename = NULL; 2232a19afe46SArnaldo Carvalho de Melo 2233dc38218eSArnaldo Carvalho de Melo pr_debug("Looking at the vmlinux_path (%d entries long)\n", 2234dc38218eSArnaldo Carvalho de Melo vmlinux_path__nr_entries + 1); 2235dc38218eSArnaldo Carvalho de Melo 2236dc38218eSArnaldo Carvalho de Melo for (i = 0; i < vmlinux_path__nr_entries; ++i) { 2237be39db9fSArnaldo Carvalho de Melo err = dso__load_vmlinux(dso, map, vmlinux_path[i], false); 2238dc38218eSArnaldo Carvalho de Melo if (err > 0) 2239dc38218eSArnaldo Carvalho de Melo goto out; 2240dc38218eSArnaldo Carvalho de Melo } 2241dc38218eSArnaldo Carvalho de Melo 224200dc8657SNamhyung Kim if (!symbol_conf.ignore_vmlinux_buildid) 2243d2396999SKrister Johansen filename = dso__build_id_filename(dso, NULL, 0, false); 22445ad90e4eSArnaldo Carvalho de Melo if (filename != NULL) { 2245be39db9fSArnaldo Carvalho de Melo err = dso__load_vmlinux(dso, map, filename, true); 22465230fb7dSArnaldo Carvalho de Melo if (err > 0) 22475ad90e4eSArnaldo Carvalho de Melo goto out; 22485ad90e4eSArnaldo Carvalho de Melo free(filename); 22495ad90e4eSArnaldo Carvalho de Melo } 22505ad90e4eSArnaldo Carvalho de Melo out: 2251a19afe46SArnaldo Carvalho de Melo return err; 2252a19afe46SArnaldo Carvalho de Melo } 2253a19afe46SArnaldo Carvalho de Melo 2254c48903b8SMasami Hiramatsu static bool visible_dir_filter(const char *name, struct dirent *d) 2255c48903b8SMasami Hiramatsu { 2256c48903b8SMasami Hiramatsu if (d->d_type != DT_DIR) 2257c48903b8SMasami Hiramatsu return false; 2258c48903b8SMasami Hiramatsu return lsdir_no_dot_filter(name, d); 2259c48903b8SMasami Hiramatsu } 2260c48903b8SMasami Hiramatsu 22610544d422SAdrian Hunter static int find_matching_kcore(struct map *map, char *dir, size_t dir_sz) 22620544d422SAdrian Hunter { 22630544d422SAdrian Hunter char kallsyms_filename[PATH_MAX]; 22640544d422SAdrian Hunter int ret = -1; 2265c48903b8SMasami Hiramatsu struct strlist *dirs; 2266c48903b8SMasami Hiramatsu struct str_node *nd; 22670544d422SAdrian Hunter 2268c48903b8SMasami Hiramatsu dirs = lsdir(dir, visible_dir_filter); 2269c48903b8SMasami Hiramatsu if (!dirs) 22700544d422SAdrian Hunter return -1; 22710544d422SAdrian Hunter 2272602a1f4dSArnaldo Carvalho de Melo strlist__for_each_entry(nd, dirs) { 22730544d422SAdrian Hunter scnprintf(kallsyms_filename, sizeof(kallsyms_filename), 2274c48903b8SMasami Hiramatsu "%s/%s/kallsyms", dir, nd->s); 2275a00d28cbSAdrian Hunter if (!validate_kcore_addresses(kallsyms_filename, map)) { 22760544d422SAdrian Hunter strlcpy(dir, kallsyms_filename, dir_sz); 22770544d422SAdrian Hunter ret = 0; 22780544d422SAdrian Hunter break; 22790544d422SAdrian Hunter } 22800544d422SAdrian Hunter } 22810544d422SAdrian Hunter 2282c48903b8SMasami Hiramatsu strlist__delete(dirs); 22830544d422SAdrian Hunter 22840544d422SAdrian Hunter return ret; 22850544d422SAdrian Hunter } 22860544d422SAdrian Hunter 228711870d71SMasami Hiramatsu /* 228811870d71SMasami Hiramatsu * Use open(O_RDONLY) to check readability directly instead of access(R_OK) 228911870d71SMasami Hiramatsu * since access(R_OK) only checks with real UID/GID but open() use effective 229011870d71SMasami Hiramatsu * UID/GID and actual capabilities (e.g. /proc/kcore requires CAP_SYS_RAWIO). 229111870d71SMasami Hiramatsu */ 229211870d71SMasami Hiramatsu static bool filename__readable(const char *file) 229311870d71SMasami Hiramatsu { 229411870d71SMasami Hiramatsu int fd = open(file, O_RDONLY); 229511870d71SMasami Hiramatsu if (fd < 0) 229611870d71SMasami Hiramatsu return false; 229711870d71SMasami Hiramatsu close(fd); 229811870d71SMasami Hiramatsu return true; 229911870d71SMasami Hiramatsu } 230011870d71SMasami Hiramatsu 23010544d422SAdrian Hunter static char *dso__find_kallsyms(struct dso *dso, struct map *map) 23020544d422SAdrian Hunter { 23033ff1b8c8SJiri Olsa struct build_id bid; 2304b5d8bbe8SMasami Hiramatsu char sbuild_id[SBUILD_ID_SIZE]; 23050544d422SAdrian Hunter bool is_host = false; 23060544d422SAdrian Hunter char path[PATH_MAX]; 23070544d422SAdrian Hunter 23080544d422SAdrian Hunter if (!dso->has_build_id) { 23090544d422SAdrian Hunter /* 23100544d422SAdrian Hunter * Last resort, if we don't have a build-id and couldn't find 23110544d422SAdrian Hunter * any vmlinux file, try the running kernel kallsyms table. 23120544d422SAdrian Hunter */ 23130544d422SAdrian Hunter goto proc_kallsyms; 23140544d422SAdrian Hunter } 23150544d422SAdrian Hunter 23163ff1b8c8SJiri Olsa if (sysfs__read_build_id("/sys/kernel/notes", &bid) == 0) 231739be8d01SJiri Olsa is_host = dso__build_id_equal(dso, &bid); 23180544d422SAdrian Hunter 23194e4b6c06SMasami Hiramatsu /* Try a fast path for /proc/kallsyms if possible */ 23200544d422SAdrian Hunter if (is_host) { 23210544d422SAdrian Hunter /* 232211870d71SMasami Hiramatsu * Do not check the build-id cache, unless we know we cannot use 232311870d71SMasami Hiramatsu * /proc/kcore or module maps don't match to /proc/kallsyms. 232411870d71SMasami Hiramatsu * To check readability of /proc/kcore, do not use access(R_OK) 232511870d71SMasami Hiramatsu * since /proc/kcore requires CAP_SYS_RAWIO to read and access 232611870d71SMasami Hiramatsu * can't check it. 23270544d422SAdrian Hunter */ 232811870d71SMasami Hiramatsu if (filename__readable("/proc/kcore") && 232911870d71SMasami Hiramatsu !validate_kcore_addresses("/proc/kallsyms", map)) 23300544d422SAdrian Hunter goto proc_kallsyms; 23310544d422SAdrian Hunter } 23320544d422SAdrian Hunter 2333bf541169SJiri Olsa build_id__sprintf(&dso->bid, sbuild_id); 23344e4b6c06SMasami Hiramatsu 2335449867e3SAdrian Hunter /* Find kallsyms in build-id cache with kcore */ 23364e4b6c06SMasami Hiramatsu scnprintf(path, sizeof(path), "%s/%s/%s", 23374e4b6c06SMasami Hiramatsu buildid_dir, DSO__NAME_KCORE, sbuild_id); 23384e4b6c06SMasami Hiramatsu 2339449867e3SAdrian Hunter if (!find_matching_kcore(map, path, sizeof(path))) 2340449867e3SAdrian Hunter return strdup(path); 2341449867e3SAdrian Hunter 23424e4b6c06SMasami Hiramatsu /* Use current /proc/kallsyms if possible */ 23434e4b6c06SMasami Hiramatsu if (is_host) { 23444e4b6c06SMasami Hiramatsu proc_kallsyms: 23454e4b6c06SMasami Hiramatsu return strdup("/proc/kallsyms"); 23464e4b6c06SMasami Hiramatsu } 23474e4b6c06SMasami Hiramatsu 23484e4b6c06SMasami Hiramatsu /* Finally, find a cache of kallsyms */ 234901412261SMasami Hiramatsu if (!build_id_cache__kallsyms_path(sbuild_id, path, sizeof(path))) { 23500544d422SAdrian Hunter pr_err("No kallsyms or vmlinux with build-id %s was found\n", 23510544d422SAdrian Hunter sbuild_id); 23520544d422SAdrian Hunter return NULL; 23530544d422SAdrian Hunter } 23540544d422SAdrian Hunter 23550544d422SAdrian Hunter return strdup(path); 23560544d422SAdrian Hunter } 23570544d422SAdrian Hunter 2358be39db9fSArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *dso, struct map *map) 235986470930SIngo Molnar { 2360cc612d81SArnaldo Carvalho de Melo int err; 23619e201442SArnaldo Carvalho de Melo const char *kallsyms_filename = NULL; 23629e201442SArnaldo Carvalho de Melo char *kallsyms_allocated_filename = NULL; 2363ca8ea73aSJiri Olsa char *filename = NULL; 2364ca8ea73aSJiri Olsa 2365dc8d6ab2SArnaldo Carvalho de Melo /* 2366b226a5a7SDavid Ahern * Step 1: if the user specified a kallsyms or vmlinux filename, use 2367b226a5a7SDavid Ahern * it and only it, reporting errors to the user if it cannot be used. 2368dc8d6ab2SArnaldo Carvalho de Melo * 2369dc8d6ab2SArnaldo Carvalho de Melo * For instance, try to analyse an ARM perf.data file _without_ a 2370dc8d6ab2SArnaldo Carvalho de Melo * build-id, or if the user specifies the wrong path to the right 2371dc8d6ab2SArnaldo Carvalho de Melo * vmlinux file, obviously we can't fallback to another vmlinux (a 2372dc8d6ab2SArnaldo Carvalho de Melo * x86_86 one, on the machine where analysis is being performed, say), 2373dc8d6ab2SArnaldo Carvalho de Melo * or worse, /proc/kallsyms. 2374dc8d6ab2SArnaldo Carvalho de Melo * 2375dc8d6ab2SArnaldo Carvalho de Melo * If the specified file _has_ a build-id and there is a build-id 2376dc8d6ab2SArnaldo Carvalho de Melo * section in the perf.data file, we will still do the expected 2377dc8d6ab2SArnaldo Carvalho de Melo * validation in dso__load_vmlinux and will bail out if they don't 2378dc8d6ab2SArnaldo Carvalho de Melo * match. 2379dc8d6ab2SArnaldo Carvalho de Melo */ 2380b226a5a7SDavid Ahern if (symbol_conf.kallsyms_name != NULL) { 2381b226a5a7SDavid Ahern kallsyms_filename = symbol_conf.kallsyms_name; 2382b226a5a7SDavid Ahern goto do_kallsyms; 2383b226a5a7SDavid Ahern } 2384b226a5a7SDavid Ahern 2385fc2be696SWilly Tarreau if (!symbol_conf.ignore_vmlinux && symbol_conf.vmlinux_name != NULL) { 2386be39db9fSArnaldo Carvalho de Melo return dso__load_vmlinux(dso, map, symbol_conf.vmlinux_name, false); 2387dc8d6ab2SArnaldo Carvalho de Melo } 2388439d473bSArnaldo Carvalho de Melo 2389ca8ea73aSJiri Olsa /* 2390ca8ea73aSJiri Olsa * Before checking on common vmlinux locations, check if it's 2391ca8ea73aSJiri Olsa * stored as standard build id binary (not kallsyms) under 2392ca8ea73aSJiri Olsa * .debug cache. 2393ca8ea73aSJiri Olsa */ 2394ca8ea73aSJiri Olsa if (!symbol_conf.ignore_vmlinux_buildid) 2395ca8ea73aSJiri Olsa filename = __dso__build_id_filename(dso, NULL, 0, false, false); 2396ca8ea73aSJiri Olsa if (filename != NULL) { 2397ca8ea73aSJiri Olsa err = dso__load_vmlinux(dso, map, filename, true); 2398ca8ea73aSJiri Olsa if (err > 0) 2399ca8ea73aSJiri Olsa return err; 2400ca8ea73aSJiri Olsa free(filename); 2401ca8ea73aSJiri Olsa } 2402ca8ea73aSJiri Olsa 2403fc2be696SWilly Tarreau if (!symbol_conf.ignore_vmlinux && vmlinux_path != NULL) { 2404be39db9fSArnaldo Carvalho de Melo err = dso__load_vmlinux_path(dso, map); 2405a19afe46SArnaldo Carvalho de Melo if (err > 0) 240639b12f78SAdrian Hunter return err; 2407cc612d81SArnaldo Carvalho de Melo } 2408cc612d81SArnaldo Carvalho de Melo 2409ec5761eaSDavid Ahern /* do not try local files if a symfs was given */ 2410ec5761eaSDavid Ahern if (symbol_conf.symfs[0] != 0) 2411ec5761eaSDavid Ahern return -1; 2412ec5761eaSDavid Ahern 24130544d422SAdrian Hunter kallsyms_allocated_filename = dso__find_kallsyms(dso, map); 24140544d422SAdrian Hunter if (!kallsyms_allocated_filename) 24158d0591f6SArnaldo Carvalho de Melo return -1; 24168d0591f6SArnaldo Carvalho de Melo 241719fc2dedSArnaldo Carvalho de Melo kallsyms_filename = kallsyms_allocated_filename; 241819fc2dedSArnaldo Carvalho de Melo 2419dc8d6ab2SArnaldo Carvalho de Melo do_kallsyms: 2420be39db9fSArnaldo Carvalho de Melo err = dso__load_kallsyms(dso, kallsyms_filename, map); 24213846df2eSArnaldo Carvalho de Melo if (err > 0) 24223846df2eSArnaldo Carvalho de Melo pr_debug("Using %s for symbols\n", kallsyms_filename); 2423dc8d6ab2SArnaldo Carvalho de Melo free(kallsyms_allocated_filename); 2424dc8d6ab2SArnaldo Carvalho de Melo 24258e0cf965SAdrian Hunter if (err > 0 && !dso__is_kcore(dso)) { 2426bdac0bcfSAdrian Hunter dso->binary_type = DSO_BINARY_TYPE__KALLSYMS; 24270a77582fSMasami Hiramatsu dso__set_long_name(dso, DSO__NAME_KALLSYMS, false); 24286a4694a4SArnaldo Carvalho de Melo map__fixup_start(map); 24296a4694a4SArnaldo Carvalho de Melo map__fixup_end(map); 2430439d473bSArnaldo Carvalho de Melo } 243194cb9e38SArnaldo Carvalho de Melo 243286470930SIngo Molnar return err; 243386470930SIngo Molnar } 243486470930SIngo Molnar 2435be39db9fSArnaldo Carvalho de Melo static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map) 2436a1645ce1SZhang, Yanmin { 2437a1645ce1SZhang, Yanmin int err; 2438a5367ecbSAdrian Hunter const char *kallsyms_filename; 24395ab6d715SIan Rogers struct machine *machine = maps__machine(map__kmaps(map)); 2440a1645ce1SZhang, Yanmin char path[PATH_MAX]; 2441a1645ce1SZhang, Yanmin 2442a5367ecbSAdrian Hunter if (machine->kallsyms_filename) { 2443a5367ecbSAdrian Hunter kallsyms_filename = machine->kallsyms_filename; 2444a5367ecbSAdrian Hunter } else if (machine__is_default_guest(machine)) { 2445a1645ce1SZhang, Yanmin /* 2446a1645ce1SZhang, Yanmin * if the user specified a vmlinux filename, use it and only 2447a1645ce1SZhang, Yanmin * it, reporting errors to the user if it cannot be used. 2448a1645ce1SZhang, Yanmin * Or use file guest_kallsyms inputted by user on commandline 2449a1645ce1SZhang, Yanmin */ 2450a1645ce1SZhang, Yanmin if (symbol_conf.default_guest_vmlinux_name != NULL) { 2451aeafcbafSArnaldo Carvalho de Melo err = dso__load_vmlinux(dso, map, 24525230fb7dSArnaldo Carvalho de Melo symbol_conf.default_guest_vmlinux_name, 2453be39db9fSArnaldo Carvalho de Melo false); 245439b12f78SAdrian Hunter return err; 2455a1645ce1SZhang, Yanmin } 2456a1645ce1SZhang, Yanmin 2457a1645ce1SZhang, Yanmin kallsyms_filename = symbol_conf.default_guest_kallsyms; 2458a1645ce1SZhang, Yanmin if (!kallsyms_filename) 2459a1645ce1SZhang, Yanmin return -1; 2460a1645ce1SZhang, Yanmin } else { 246123346f21SArnaldo Carvalho de Melo sprintf(path, "%s/proc/kallsyms", machine->root_dir); 2462a1645ce1SZhang, Yanmin kallsyms_filename = path; 2463a1645ce1SZhang, Yanmin } 2464a1645ce1SZhang, Yanmin 2465be39db9fSArnaldo Carvalho de Melo err = dso__load_kallsyms(dso, kallsyms_filename, map); 24668e0cf965SAdrian Hunter if (err > 0) 246739b12f78SAdrian Hunter pr_debug("Using %s for symbols\n", kallsyms_filename); 24688e0cf965SAdrian Hunter if (err > 0 && !dso__is_kcore(dso)) { 2469bdac0bcfSAdrian Hunter dso->binary_type = DSO_BINARY_TYPE__GUEST_KALLSYMS; 24708c7f1bb3SJiri Olsa dso__set_long_name(dso, machine->mmap_name, false); 2471a1645ce1SZhang, Yanmin map__fixup_start(map); 2472a1645ce1SZhang, Yanmin map__fixup_end(map); 2473a1645ce1SZhang, Yanmin } 2474a1645ce1SZhang, Yanmin 2475a1645ce1SZhang, Yanmin return err; 2476a1645ce1SZhang, Yanmin } 2477cd84c2acSFrederic Weisbecker 2478cc612d81SArnaldo Carvalho de Melo static void vmlinux_path__exit(void) 24792446042cSArnaldo Carvalho de Melo { 248004662523SArnaldo Carvalho de Melo while (--vmlinux_path__nr_entries >= 0) 248104662523SArnaldo Carvalho de Melo zfree(&vmlinux_path[vmlinux_path__nr_entries]); 2482c4f03547SWang Nan vmlinux_path__nr_entries = 0; 2483cc612d81SArnaldo Carvalho de Melo 248404662523SArnaldo Carvalho de Melo zfree(&vmlinux_path); 2485cc612d81SArnaldo Carvalho de Melo } 2486cc612d81SArnaldo Carvalho de Melo 2487aac48647SEkaterina Tumanova static const char * const vmlinux_paths[] = { 2488aac48647SEkaterina Tumanova "vmlinux", 2489aac48647SEkaterina Tumanova "/boot/vmlinux" 2490aac48647SEkaterina Tumanova }; 2491aac48647SEkaterina Tumanova 2492aac48647SEkaterina Tumanova static const char * const vmlinux_paths_upd[] = { 2493aac48647SEkaterina Tumanova "/boot/vmlinux-%s", 2494aac48647SEkaterina Tumanova "/usr/lib/debug/boot/vmlinux-%s", 2495aac48647SEkaterina Tumanova "/lib/modules/%s/build/vmlinux", 2496f55ae954SEkaterina Tumanova "/usr/lib/debug/lib/modules/%s/vmlinux", 2497f55ae954SEkaterina Tumanova "/usr/lib/debug/boot/vmlinux-%s.debug" 2498aac48647SEkaterina Tumanova }; 2499aac48647SEkaterina Tumanova 2500aac48647SEkaterina Tumanova static int vmlinux_path__add(const char *new_entry) 2501aac48647SEkaterina Tumanova { 2502aac48647SEkaterina Tumanova vmlinux_path[vmlinux_path__nr_entries] = strdup(new_entry); 2503aac48647SEkaterina Tumanova if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 2504aac48647SEkaterina Tumanova return -1; 2505aac48647SEkaterina Tumanova ++vmlinux_path__nr_entries; 2506aac48647SEkaterina Tumanova 2507aac48647SEkaterina Tumanova return 0; 2508aac48647SEkaterina Tumanova } 2509aac48647SEkaterina Tumanova 2510ce80d3beSKan Liang static int vmlinux_path__init(struct perf_env *env) 2511cc612d81SArnaldo Carvalho de Melo { 2512cc612d81SArnaldo Carvalho de Melo struct utsname uts; 2513cc612d81SArnaldo Carvalho de Melo char bf[PATH_MAX]; 25140a7e6d1bSNamhyung Kim char *kernel_version; 2515aac48647SEkaterina Tumanova unsigned int i; 2516cc612d81SArnaldo Carvalho de Melo 2517aac48647SEkaterina Tumanova vmlinux_path = malloc(sizeof(char *) * (ARRAY_SIZE(vmlinux_paths) + 2518aac48647SEkaterina Tumanova ARRAY_SIZE(vmlinux_paths_upd))); 2519cc612d81SArnaldo Carvalho de Melo if (vmlinux_path == NULL) 2520cc612d81SArnaldo Carvalho de Melo return -1; 2521cc612d81SArnaldo Carvalho de Melo 2522aac48647SEkaterina Tumanova for (i = 0; i < ARRAY_SIZE(vmlinux_paths); i++) 2523aac48647SEkaterina Tumanova if (vmlinux_path__add(vmlinux_paths[i]) < 0) 2524cc612d81SArnaldo Carvalho de Melo goto out_fail; 2525ec5761eaSDavid Ahern 25260a7e6d1bSNamhyung Kim /* only try kernel version if no symfs was given */ 2527ec5761eaSDavid Ahern if (symbol_conf.symfs[0] != 0) 2528ec5761eaSDavid Ahern return 0; 2529ec5761eaSDavid Ahern 25300a7e6d1bSNamhyung Kim if (env) { 25310a7e6d1bSNamhyung Kim kernel_version = env->os_release; 25320a7e6d1bSNamhyung Kim } else { 2533ec5761eaSDavid Ahern if (uname(&uts) < 0) 2534e96c674fSNamhyung Kim goto out_fail; 2535ec5761eaSDavid Ahern 25360a7e6d1bSNamhyung Kim kernel_version = uts.release; 25370a7e6d1bSNamhyung Kim } 25380a7e6d1bSNamhyung Kim 2539aac48647SEkaterina Tumanova for (i = 0; i < ARRAY_SIZE(vmlinux_paths_upd); i++) { 2540aac48647SEkaterina Tumanova snprintf(bf, sizeof(bf), vmlinux_paths_upd[i], kernel_version); 2541aac48647SEkaterina Tumanova if (vmlinux_path__add(bf) < 0) 2542cc612d81SArnaldo Carvalho de Melo goto out_fail; 2543aac48647SEkaterina Tumanova } 2544cc612d81SArnaldo Carvalho de Melo 2545cc612d81SArnaldo Carvalho de Melo return 0; 2546cc612d81SArnaldo Carvalho de Melo 2547cc612d81SArnaldo Carvalho de Melo out_fail: 2548cc612d81SArnaldo Carvalho de Melo vmlinux_path__exit(); 2549cc612d81SArnaldo Carvalho de Melo return -1; 2550cc612d81SArnaldo Carvalho de Melo } 2551cc612d81SArnaldo Carvalho de Melo 25523bfe5f81SDavid Ahern int setup_list(struct strlist **list, const char *list_str, 2553655000e7SArnaldo Carvalho de Melo const char *list_name) 2554655000e7SArnaldo Carvalho de Melo { 2555655000e7SArnaldo Carvalho de Melo if (list_str == NULL) 2556655000e7SArnaldo Carvalho de Melo return 0; 2557655000e7SArnaldo Carvalho de Melo 25584a77e218SArnaldo Carvalho de Melo *list = strlist__new(list_str, NULL); 2559655000e7SArnaldo Carvalho de Melo if (!*list) { 2560655000e7SArnaldo Carvalho de Melo pr_err("problems parsing %s list\n", list_name); 2561655000e7SArnaldo Carvalho de Melo return -1; 2562655000e7SArnaldo Carvalho de Melo } 25630bc2f2f7SArnaldo Carvalho de Melo 25640bc2f2f7SArnaldo Carvalho de Melo symbol_conf.has_filter = true; 2565655000e7SArnaldo Carvalho de Melo return 0; 2566655000e7SArnaldo Carvalho de Melo } 2567655000e7SArnaldo Carvalho de Melo 2568e03eaa40SDavid Ahern int setup_intlist(struct intlist **list, const char *list_str, 2569e03eaa40SDavid Ahern const char *list_name) 2570e03eaa40SDavid Ahern { 2571e03eaa40SDavid Ahern if (list_str == NULL) 2572e03eaa40SDavid Ahern return 0; 2573e03eaa40SDavid Ahern 2574e03eaa40SDavid Ahern *list = intlist__new(list_str); 2575e03eaa40SDavid Ahern if (!*list) { 2576e03eaa40SDavid Ahern pr_err("problems parsing %s list\n", list_name); 2577e03eaa40SDavid Ahern return -1; 2578e03eaa40SDavid Ahern } 2579e03eaa40SDavid Ahern return 0; 2580e03eaa40SDavid Ahern } 2581e03eaa40SDavid Ahern 258261d9fc44SJin Yao static int setup_addrlist(struct intlist **addr_list, struct strlist *sym_list) 258361d9fc44SJin Yao { 258461d9fc44SJin Yao struct str_node *pos, *tmp; 258561d9fc44SJin Yao unsigned long val; 258661d9fc44SJin Yao char *sep; 258761d9fc44SJin Yao const char *end; 258861d9fc44SJin Yao int i = 0, err; 258961d9fc44SJin Yao 259061d9fc44SJin Yao *addr_list = intlist__new(NULL); 259161d9fc44SJin Yao if (!*addr_list) 259261d9fc44SJin Yao return -1; 259361d9fc44SJin Yao 259461d9fc44SJin Yao strlist__for_each_entry_safe(pos, tmp, sym_list) { 259561d9fc44SJin Yao errno = 0; 259661d9fc44SJin Yao val = strtoul(pos->s, &sep, 16); 259761d9fc44SJin Yao if (errno || (sep == pos->s)) 259861d9fc44SJin Yao continue; 259961d9fc44SJin Yao 260061d9fc44SJin Yao if (*sep != '\0') { 260161d9fc44SJin Yao end = pos->s + strlen(pos->s) - 1; 260261d9fc44SJin Yao while (end >= sep && isspace(*end)) 260361d9fc44SJin Yao end--; 260461d9fc44SJin Yao 260561d9fc44SJin Yao if (end >= sep) 260661d9fc44SJin Yao continue; 260761d9fc44SJin Yao } 260861d9fc44SJin Yao 260961d9fc44SJin Yao err = intlist__add(*addr_list, val); 261061d9fc44SJin Yao if (err) 261161d9fc44SJin Yao break; 261261d9fc44SJin Yao 261361d9fc44SJin Yao strlist__remove(sym_list, pos); 261461d9fc44SJin Yao i++; 261561d9fc44SJin Yao } 261661d9fc44SJin Yao 261761d9fc44SJin Yao if (i == 0) { 261861d9fc44SJin Yao intlist__delete(*addr_list); 261961d9fc44SJin Yao *addr_list = NULL; 262061d9fc44SJin Yao } 262161d9fc44SJin Yao 262261d9fc44SJin Yao return 0; 262361d9fc44SJin Yao } 262461d9fc44SJin Yao 2625ec80fde7SArnaldo Carvalho de Melo static bool symbol__read_kptr_restrict(void) 2626ec80fde7SArnaldo Carvalho de Melo { 2627ec80fde7SArnaldo Carvalho de Melo bool value = false; 2628ec80fde7SArnaldo Carvalho de Melo FILE *fp = fopen("/proc/sys/kernel/kptr_restrict", "r"); 262938272dc4SWang Nan 2630ec80fde7SArnaldo Carvalho de Melo if (fp != NULL) { 2631ec80fde7SArnaldo Carvalho de Melo char line[8]; 2632ec80fde7SArnaldo Carvalho de Melo 2633ec80fde7SArnaldo Carvalho de Melo if (fgets(line, sizeof(line), fp) != NULL) 26348859aedeSIgor Lubashev value = perf_cap__capable(CAP_SYSLOG) ? 26358859aedeSIgor Lubashev (atoi(line) >= 2) : 26368859aedeSIgor Lubashev (atoi(line) != 0); 2637ec80fde7SArnaldo Carvalho de Melo 2638ec80fde7SArnaldo Carvalho de Melo fclose(fp); 2639ec80fde7SArnaldo Carvalho de Melo } 2640ec80fde7SArnaldo Carvalho de Melo 26418859aedeSIgor Lubashev /* Per kernel/kallsyms.c: 26428859aedeSIgor Lubashev * we also restrict when perf_event_paranoid > 1 w/o CAP_SYSLOG 26438859aedeSIgor Lubashev */ 26448859aedeSIgor Lubashev if (perf_event_paranoid() > 1 && !perf_cap__capable(CAP_SYSLOG)) 26458859aedeSIgor Lubashev value = true; 26468859aedeSIgor Lubashev 2647ec80fde7SArnaldo Carvalho de Melo return value; 2648ec80fde7SArnaldo Carvalho de Melo } 2649ec80fde7SArnaldo Carvalho de Melo 2650b01141f4SArnaldo Carvalho de Melo int symbol__annotation_init(void) 2651b01141f4SArnaldo Carvalho de Melo { 26527b366142SArnaldo Carvalho de Melo if (symbol_conf.init_annotation) 26537b366142SArnaldo Carvalho de Melo return 0; 26547b366142SArnaldo Carvalho de Melo 2655b01141f4SArnaldo Carvalho de Melo if (symbol_conf.initialized) { 2656b01141f4SArnaldo Carvalho de Melo pr_err("Annotation needs to be init before symbol__init()\n"); 2657b01141f4SArnaldo Carvalho de Melo return -1; 2658b01141f4SArnaldo Carvalho de Melo } 2659b01141f4SArnaldo Carvalho de Melo 2660b01141f4SArnaldo Carvalho de Melo symbol_conf.priv_size += sizeof(struct annotation); 2661b01141f4SArnaldo Carvalho de Melo symbol_conf.init_annotation = true; 2662b01141f4SArnaldo Carvalho de Melo return 0; 2663b01141f4SArnaldo Carvalho de Melo } 2664b01141f4SArnaldo Carvalho de Melo 2665ce80d3beSKan Liang int symbol__init(struct perf_env *env) 2666cc612d81SArnaldo Carvalho de Melo { 2667ec5761eaSDavid Ahern const char *symfs; 2668ec5761eaSDavid Ahern 266985e00b55SJovi Zhang if (symbol_conf.initialized) 267085e00b55SJovi Zhang return 0; 267185e00b55SJovi Zhang 26729ac3e487SIrina Tirdea symbol_conf.priv_size = PERF_ALIGN(symbol_conf.priv_size, sizeof(u64)); 26734d439517SDavid S. Miller 2674166ccc9cSNamhyung Kim symbol__elf_init(); 2675166ccc9cSNamhyung Kim 26760a7e6d1bSNamhyung Kim if (symbol_conf.try_vmlinux_path && vmlinux_path__init(env) < 0) 2677cc612d81SArnaldo Carvalho de Melo return -1; 2678cc612d81SArnaldo Carvalho de Melo 2679c410a338SArnaldo Carvalho de Melo if (symbol_conf.field_sep && *symbol_conf.field_sep == '.') { 2680c410a338SArnaldo Carvalho de Melo pr_err("'.' is the only non valid --field-separator argument\n"); 2681c410a338SArnaldo Carvalho de Melo return -1; 2682c410a338SArnaldo Carvalho de Melo } 2683c410a338SArnaldo Carvalho de Melo 2684655000e7SArnaldo Carvalho de Melo if (setup_list(&symbol_conf.dso_list, 2685655000e7SArnaldo Carvalho de Melo symbol_conf.dso_list_str, "dso") < 0) 2686655000e7SArnaldo Carvalho de Melo return -1; 2687655000e7SArnaldo Carvalho de Melo 2688655000e7SArnaldo Carvalho de Melo if (setup_list(&symbol_conf.comm_list, 2689655000e7SArnaldo Carvalho de Melo symbol_conf.comm_list_str, "comm") < 0) 2690655000e7SArnaldo Carvalho de Melo goto out_free_dso_list; 2691655000e7SArnaldo Carvalho de Melo 2692e03eaa40SDavid Ahern if (setup_intlist(&symbol_conf.pid_list, 2693e03eaa40SDavid Ahern symbol_conf.pid_list_str, "pid") < 0) 2694e03eaa40SDavid Ahern goto out_free_comm_list; 2695e03eaa40SDavid Ahern 2696e03eaa40SDavid Ahern if (setup_intlist(&symbol_conf.tid_list, 2697e03eaa40SDavid Ahern symbol_conf.tid_list_str, "tid") < 0) 2698e03eaa40SDavid Ahern goto out_free_pid_list; 2699e03eaa40SDavid Ahern 2700655000e7SArnaldo Carvalho de Melo if (setup_list(&symbol_conf.sym_list, 2701655000e7SArnaldo Carvalho de Melo symbol_conf.sym_list_str, "symbol") < 0) 2702e03eaa40SDavid Ahern goto out_free_tid_list; 2703655000e7SArnaldo Carvalho de Melo 270461d9fc44SJin Yao if (symbol_conf.sym_list && 270561d9fc44SJin Yao setup_addrlist(&symbol_conf.addr_list, symbol_conf.sym_list) < 0) 270661d9fc44SJin Yao goto out_free_sym_list; 270761d9fc44SJin Yao 270864eff7d9SDavid Ahern if (setup_list(&symbol_conf.bt_stop_list, 270964eff7d9SDavid Ahern symbol_conf.bt_stop_list_str, "symbol") < 0) 271064eff7d9SDavid Ahern goto out_free_sym_list; 271164eff7d9SDavid Ahern 2712ec5761eaSDavid Ahern /* 2713ec5761eaSDavid Ahern * A path to symbols of "/" is identical to "" 2714ec5761eaSDavid Ahern * reset here for simplicity. 2715ec5761eaSDavid Ahern */ 2716ec5761eaSDavid Ahern symfs = realpath(symbol_conf.symfs, NULL); 2717ec5761eaSDavid Ahern if (symfs == NULL) 2718ec5761eaSDavid Ahern symfs = symbol_conf.symfs; 2719ec5761eaSDavid Ahern if (strcmp(symfs, "/") == 0) 2720ec5761eaSDavid Ahern symbol_conf.symfs = ""; 2721ec5761eaSDavid Ahern if (symfs != symbol_conf.symfs) 2722ec5761eaSDavid Ahern free((void *)symfs); 2723ec5761eaSDavid Ahern 2724ec80fde7SArnaldo Carvalho de Melo symbol_conf.kptr_restrict = symbol__read_kptr_restrict(); 2725ec80fde7SArnaldo Carvalho de Melo 272685e00b55SJovi Zhang symbol_conf.initialized = true; 27274aa65636SArnaldo Carvalho de Melo return 0; 2728655000e7SArnaldo Carvalho de Melo 272964eff7d9SDavid Ahern out_free_sym_list: 273064eff7d9SDavid Ahern strlist__delete(symbol_conf.sym_list); 273161d9fc44SJin Yao intlist__delete(symbol_conf.addr_list); 2732e03eaa40SDavid Ahern out_free_tid_list: 2733e03eaa40SDavid Ahern intlist__delete(symbol_conf.tid_list); 2734e03eaa40SDavid Ahern out_free_pid_list: 2735e03eaa40SDavid Ahern intlist__delete(symbol_conf.pid_list); 2736655000e7SArnaldo Carvalho de Melo out_free_comm_list: 2737655000e7SArnaldo Carvalho de Melo strlist__delete(symbol_conf.comm_list); 2738d74c896bSNamhyung Kim out_free_dso_list: 2739d74c896bSNamhyung Kim strlist__delete(symbol_conf.dso_list); 2740655000e7SArnaldo Carvalho de Melo return -1; 2741cc612d81SArnaldo Carvalho de Melo } 2742cc612d81SArnaldo Carvalho de Melo 2743d65a458bSArnaldo Carvalho de Melo void symbol__exit(void) 2744d65a458bSArnaldo Carvalho de Melo { 274585e00b55SJovi Zhang if (!symbol_conf.initialized) 274685e00b55SJovi Zhang return; 274764eff7d9SDavid Ahern strlist__delete(symbol_conf.bt_stop_list); 2748d65a458bSArnaldo Carvalho de Melo strlist__delete(symbol_conf.sym_list); 2749d65a458bSArnaldo Carvalho de Melo strlist__delete(symbol_conf.dso_list); 2750d65a458bSArnaldo Carvalho de Melo strlist__delete(symbol_conf.comm_list); 2751e03eaa40SDavid Ahern intlist__delete(symbol_conf.tid_list); 2752e03eaa40SDavid Ahern intlist__delete(symbol_conf.pid_list); 275361d9fc44SJin Yao intlist__delete(symbol_conf.addr_list); 2754d65a458bSArnaldo Carvalho de Melo vmlinux_path__exit(); 2755d65a458bSArnaldo Carvalho de Melo symbol_conf.sym_list = symbol_conf.dso_list = symbol_conf.comm_list = NULL; 275664eff7d9SDavid Ahern symbol_conf.bt_stop_list = NULL; 275785e00b55SJovi Zhang symbol_conf.initialized = false; 2758d65a458bSArnaldo Carvalho de Melo } 2759a7066709SHe Kuang 2760a7066709SHe Kuang int symbol__config_symfs(const struct option *opt __maybe_unused, 2761a7066709SHe Kuang const char *dir, int unset __maybe_unused) 2762a7066709SHe Kuang { 2763a7066709SHe Kuang char *bf = NULL; 2764a7066709SHe Kuang int ret; 2765a7066709SHe Kuang 2766a7066709SHe Kuang symbol_conf.symfs = strdup(dir); 2767a7066709SHe Kuang if (symbol_conf.symfs == NULL) 2768a7066709SHe Kuang return -ENOMEM; 2769a7066709SHe Kuang 2770a7066709SHe Kuang /* skip the locally configured cache if a symfs is given, and 2771a7066709SHe Kuang * config buildid dir to symfs/.debug 2772a7066709SHe Kuang */ 2773a7066709SHe Kuang ret = asprintf(&bf, "%s/%s", dir, ".debug"); 2774a7066709SHe Kuang if (ret < 0) 2775a7066709SHe Kuang return -ENOMEM; 2776a7066709SHe Kuang 2777a7066709SHe Kuang set_buildid_dir(bf); 2778a7066709SHe Kuang 2779a7066709SHe Kuang free(bf); 2780a7066709SHe Kuang return 0; 2781a7066709SHe Kuang } 27829f87498fSJiri Olsa 27839f87498fSJiri Olsa struct mem_info *mem_info__get(struct mem_info *mi) 27849f87498fSJiri Olsa { 27859f87498fSJiri Olsa if (mi) 27869f87498fSJiri Olsa refcount_inc(&mi->refcnt); 27879f87498fSJiri Olsa return mi; 27889f87498fSJiri Olsa } 27899f87498fSJiri Olsa 27909f87498fSJiri Olsa void mem_info__put(struct mem_info *mi) 27919f87498fSJiri Olsa { 27929f87498fSJiri Olsa if (mi && refcount_dec_and_test(&mi->refcnt)) 27939f87498fSJiri Olsa free(mi); 27949f87498fSJiri Olsa } 27959f87498fSJiri Olsa 27969f87498fSJiri Olsa struct mem_info *mem_info__new(void) 27979f87498fSJiri Olsa { 27989f87498fSJiri Olsa struct mem_info *mi = zalloc(sizeof(*mi)); 27999f87498fSJiri Olsa 28009f87498fSJiri Olsa if (mi) 28019f87498fSJiri Olsa refcount_set(&mi->refcnt, 1); 28029f87498fSJiri Olsa return mi; 28039f87498fSJiri Olsa } 2804a3df50abSJames Clark 2805a3df50abSJames Clark /* 2806a3df50abSJames Clark * Checks that user supplied symbol kernel files are accessible because 2807a3df50abSJames Clark * the default mechanism for accessing elf files fails silently. i.e. if 2808a3df50abSJames Clark * debug syms for a build ID aren't found perf carries on normally. When 2809a3df50abSJames Clark * they are user supplied we should assume that the user doesn't want to 2810a3df50abSJames Clark * silently fail. 2811a3df50abSJames Clark */ 2812a3df50abSJames Clark int symbol__validate_sym_arguments(void) 2813a3df50abSJames Clark { 2814a3df50abSJames Clark if (symbol_conf.vmlinux_name && 2815a3df50abSJames Clark access(symbol_conf.vmlinux_name, R_OK)) { 2816a3df50abSJames Clark pr_err("Invalid file: %s\n", symbol_conf.vmlinux_name); 2817a3df50abSJames Clark return -EINVAL; 2818a3df50abSJames Clark } 2819a3df50abSJames Clark if (symbol_conf.kallsyms_name && 2820a3df50abSJames Clark access(symbol_conf.kallsyms_name, R_OK)) { 2821a3df50abSJames Clark pr_err("Invalid file: %s\n", symbol_conf.kallsyms_name); 2822a3df50abSJames Clark return -EINVAL; 2823a3df50abSJames Clark } 2824a3df50abSJames Clark return 0; 2825a3df50abSJames Clark } 2826