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 5175be6cf4SArnaldo Carvalho de Melo struct symbol_conf symbol_conf = { 5252bab886SAndi Kleen .nanosecs = false, 53b32d133aSArnaldo Carvalho de Melo .use_modules = true, 54b32d133aSArnaldo Carvalho de Melo .try_vmlinux_path = true, 55328ccdacSNamhyung Kim .demangle = true, 56763122adSAvi Kivity .demangle_kernel = false, 57e511db5eSNamhyung Kim .cumulate_callchain = true, 582a1292cbSAndi Kleen .time_quantum = 100 * NSEC_PER_MSEC, /* 100ms */ 59c8302367SJiri Olsa .show_hist_headers = true, 60ec5761eaSDavid Ahern .symfs = "", 611e9abf8bSNamhyung Kim .event_group = true, 62d8a88dd2SMilian Wolff .inline_name = true, 634968ac8fSAndi Kleen .res_sample = 0, 64b32d133aSArnaldo Carvalho de Melo }; 65b32d133aSArnaldo Carvalho de Melo 6644f24cb3SJiri Olsa static enum dso_binary_type binary_type_symtab[] = { 6744f24cb3SJiri Olsa DSO_BINARY_TYPE__KALLSYMS, 6844f24cb3SJiri Olsa DSO_BINARY_TYPE__GUEST_KALLSYMS, 6944f24cb3SJiri Olsa DSO_BINARY_TYPE__JAVA_JIT, 7044f24cb3SJiri Olsa DSO_BINARY_TYPE__DEBUGLINK, 7144f24cb3SJiri Olsa DSO_BINARY_TYPE__BUILD_ID_CACHE, 72d2396999SKrister Johansen DSO_BINARY_TYPE__BUILD_ID_CACHE_DEBUGINFO, 7344f24cb3SJiri Olsa DSO_BINARY_TYPE__FEDORA_DEBUGINFO, 7444f24cb3SJiri Olsa DSO_BINARY_TYPE__UBUNTU_DEBUGINFO, 7544f24cb3SJiri Olsa DSO_BINARY_TYPE__BUILDID_DEBUGINFO, 7644f24cb3SJiri Olsa DSO_BINARY_TYPE__SYSTEM_PATH_DSO, 7744f24cb3SJiri Olsa DSO_BINARY_TYPE__GUEST_KMODULE, 78c00c48fcSNamhyung Kim DSO_BINARY_TYPE__GUEST_KMODULE_COMP, 7944f24cb3SJiri Olsa DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE, 80c00c48fcSNamhyung Kim DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP, 819cd00941SRicardo Ribalda Delgado DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO, 8285afd355SAdrian Hunter DSO_BINARY_TYPE__MIXEDUP_UBUNTU_DEBUGINFO, 8344f24cb3SJiri Olsa DSO_BINARY_TYPE__NOT_FOUND, 8444f24cb3SJiri Olsa }; 8544f24cb3SJiri Olsa 86028df767SJiri Olsa #define DSO_BINARY_TYPE__SYMTAB_CNT ARRAY_SIZE(binary_type_symtab) 8744f24cb3SJiri Olsa 883183f8caSArnaldo Carvalho de Melo static bool symbol_type__filter(char symbol_type) 896893d4eeSArnaldo Carvalho de Melo { 9031877908SAnton Blanchard symbol_type = toupper(symbol_type); 912be732c0SArnaldo Carvalho de Melo return symbol_type == 'T' || symbol_type == 'W' || symbol_type == 'D' || symbol_type == 'B'; 926893d4eeSArnaldo Carvalho de Melo } 936893d4eeSArnaldo Carvalho de Melo 94694bf407SAnton Blanchard static int prefix_underscores_count(const char *str) 95694bf407SAnton Blanchard { 96694bf407SAnton Blanchard const char *tail = str; 97694bf407SAnton Blanchard 98694bf407SAnton Blanchard while (*tail == '_') 99694bf407SAnton Blanchard tail++; 100694bf407SAnton Blanchard 101694bf407SAnton Blanchard return tail - str; 102694bf407SAnton Blanchard } 103694bf407SAnton Blanchard 104b9c0a649SThomas Richter void __weak arch__symbols__fixup_end(struct symbol *p, struct symbol *c) 105b9c0a649SThomas Richter { 106b9c0a649SThomas Richter p->end = c->start; 107b9c0a649SThomas Richter } 108b9c0a649SThomas Richter 1094b3a2716SMasami Hiramatsu const char * __weak arch__normalize_symbol_name(const char *name) 1104b3a2716SMasami Hiramatsu { 1114b3a2716SMasami Hiramatsu return name; 1124b3a2716SMasami Hiramatsu } 1134b3a2716SMasami Hiramatsu 114d8040645SPaul Clarke int __weak arch__compare_symbol_names(const char *namea, const char *nameb) 115d8040645SPaul Clarke { 116d8040645SPaul Clarke return strcmp(namea, nameb); 117d8040645SPaul Clarke } 118d8040645SPaul Clarke 119d8040645SPaul Clarke int __weak arch__compare_symbol_names_n(const char *namea, const char *nameb, 120d8040645SPaul Clarke unsigned int n) 121d8040645SPaul Clarke { 122d8040645SPaul Clarke return strncmp(namea, nameb, n); 123d8040645SPaul Clarke } 124d8040645SPaul Clarke 125fb6d5942SNaveen N. Rao int __weak arch__choose_best_symbol(struct symbol *syma, 126fb6d5942SNaveen N. Rao struct symbol *symb __maybe_unused) 127fb6d5942SNaveen N. Rao { 128fb6d5942SNaveen N. Rao /* Avoid "SyS" kernel syscall aliases */ 129fb6d5942SNaveen N. Rao if (strlen(syma->name) >= 3 && !strncmp(syma->name, "SyS", 3)) 130fb6d5942SNaveen N. Rao return SYMBOL_B; 131fb6d5942SNaveen N. Rao if (strlen(syma->name) >= 10 && !strncmp(syma->name, "compat_SyS", 10)) 132fb6d5942SNaveen N. Rao return SYMBOL_B; 133fb6d5942SNaveen N. Rao 134fb6d5942SNaveen N. Rao return SYMBOL_A; 135fb6d5942SNaveen N. Rao } 136694bf407SAnton Blanchard 137694bf407SAnton Blanchard static int choose_best_symbol(struct symbol *syma, struct symbol *symb) 138694bf407SAnton Blanchard { 139694bf407SAnton Blanchard s64 a; 140694bf407SAnton Blanchard s64 b; 1413445432bSAdrian Hunter size_t na, nb; 142694bf407SAnton Blanchard 143694bf407SAnton Blanchard /* Prefer a symbol with non zero length */ 144694bf407SAnton Blanchard a = syma->end - syma->start; 145694bf407SAnton Blanchard b = symb->end - symb->start; 146694bf407SAnton Blanchard if ((b == 0) && (a > 0)) 147694bf407SAnton Blanchard return SYMBOL_A; 148694bf407SAnton Blanchard else if ((a == 0) && (b > 0)) 149694bf407SAnton Blanchard return SYMBOL_B; 150694bf407SAnton Blanchard 151694bf407SAnton Blanchard /* Prefer a non weak symbol over a weak one */ 152694bf407SAnton Blanchard a = syma->binding == STB_WEAK; 153694bf407SAnton Blanchard b = symb->binding == STB_WEAK; 154694bf407SAnton Blanchard if (b && !a) 155694bf407SAnton Blanchard return SYMBOL_A; 156694bf407SAnton Blanchard if (a && !b) 157694bf407SAnton Blanchard return SYMBOL_B; 158694bf407SAnton Blanchard 159694bf407SAnton Blanchard /* Prefer a global symbol over a non global one */ 160694bf407SAnton Blanchard a = syma->binding == STB_GLOBAL; 161694bf407SAnton Blanchard b = symb->binding == STB_GLOBAL; 162694bf407SAnton Blanchard if (a && !b) 163694bf407SAnton Blanchard return SYMBOL_A; 164694bf407SAnton Blanchard if (b && !a) 165694bf407SAnton Blanchard return SYMBOL_B; 166694bf407SAnton Blanchard 167694bf407SAnton Blanchard /* Prefer a symbol with less underscores */ 168694bf407SAnton Blanchard a = prefix_underscores_count(syma->name); 169694bf407SAnton Blanchard b = prefix_underscores_count(symb->name); 170694bf407SAnton Blanchard if (b > a) 171694bf407SAnton Blanchard return SYMBOL_A; 172694bf407SAnton Blanchard else if (a > b) 173694bf407SAnton Blanchard return SYMBOL_B; 174694bf407SAnton Blanchard 1753445432bSAdrian Hunter /* Choose the symbol with the longest name */ 1763445432bSAdrian Hunter na = strlen(syma->name); 1773445432bSAdrian Hunter nb = strlen(symb->name); 1783445432bSAdrian Hunter if (na > nb) 179694bf407SAnton Blanchard return SYMBOL_A; 1803445432bSAdrian Hunter else if (na < nb) 181694bf407SAnton Blanchard return SYMBOL_B; 1823445432bSAdrian Hunter 183fb6d5942SNaveen N. Rao return arch__choose_best_symbol(syma, symb); 184694bf407SAnton Blanchard } 185694bf407SAnton Blanchard 1867137ff50SDavidlohr Bueso void symbols__fixup_duplicate(struct rb_root_cached *symbols) 187694bf407SAnton Blanchard { 188694bf407SAnton Blanchard struct rb_node *nd; 189694bf407SAnton Blanchard struct symbol *curr, *next; 190694bf407SAnton Blanchard 191c97b40e4SArnaldo Carvalho de Melo if (symbol_conf.allow_aliases) 192c97b40e4SArnaldo Carvalho de Melo return; 193c97b40e4SArnaldo Carvalho de Melo 1947137ff50SDavidlohr Bueso nd = rb_first_cached(symbols); 195694bf407SAnton Blanchard 196694bf407SAnton Blanchard while (nd) { 197694bf407SAnton Blanchard curr = rb_entry(nd, struct symbol, rb_node); 198694bf407SAnton Blanchard again: 199694bf407SAnton Blanchard nd = rb_next(&curr->rb_node); 200694bf407SAnton Blanchard next = rb_entry(nd, struct symbol, rb_node); 201694bf407SAnton Blanchard 202694bf407SAnton Blanchard if (!nd) 203694bf407SAnton Blanchard break; 204694bf407SAnton Blanchard 205694bf407SAnton Blanchard if (curr->start != next->start) 206694bf407SAnton Blanchard continue; 207694bf407SAnton Blanchard 208694bf407SAnton Blanchard if (choose_best_symbol(curr, next) == SYMBOL_A) { 2097137ff50SDavidlohr Bueso rb_erase_cached(&next->rb_node, symbols); 210d4f74eb8SChenggang Qin symbol__delete(next); 211694bf407SAnton Blanchard goto again; 212694bf407SAnton Blanchard } else { 213694bf407SAnton Blanchard nd = rb_next(&curr->rb_node); 2147137ff50SDavidlohr Bueso rb_erase_cached(&curr->rb_node, symbols); 215d4f74eb8SChenggang Qin symbol__delete(curr); 216694bf407SAnton Blanchard } 217694bf407SAnton Blanchard } 218694bf407SAnton Blanchard } 219694bf407SAnton Blanchard 220*838425f2SNamhyung Kim void symbols__fixup_end(struct rb_root_cached *symbols, 221*838425f2SNamhyung Kim bool is_kallsyms __maybe_unused) 222af427bf5SArnaldo Carvalho de Melo { 2237137ff50SDavidlohr Bueso struct rb_node *nd, *prevnd = rb_first_cached(symbols); 2242e538c4aSArnaldo Carvalho de Melo struct symbol *curr, *prev; 225af427bf5SArnaldo Carvalho de Melo 226af427bf5SArnaldo Carvalho de Melo if (prevnd == NULL) 227af427bf5SArnaldo Carvalho de Melo return; 228af427bf5SArnaldo Carvalho de Melo 2292e538c4aSArnaldo Carvalho de Melo curr = rb_entry(prevnd, struct symbol, rb_node); 2302e538c4aSArnaldo Carvalho de Melo 231af427bf5SArnaldo Carvalho de Melo for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) { 2322e538c4aSArnaldo Carvalho de Melo prev = curr; 2332e538c4aSArnaldo Carvalho de Melo curr = rb_entry(nd, struct symbol, rb_node); 234af427bf5SArnaldo Carvalho de Melo 2353cf6a32fSMichael Petlan if (prev->end == prev->start || prev->end != curr->start) 236b9c0a649SThomas Richter arch__symbols__fixup_end(prev, curr); 237af427bf5SArnaldo Carvalho de Melo } 238af427bf5SArnaldo Carvalho de Melo 2392e538c4aSArnaldo Carvalho de Melo /* Last entry */ 2402e538c4aSArnaldo Carvalho de Melo if (curr->end == curr->start) 241e7ede72aSDaniel Borkmann curr->end = roundup(curr->start, 4096) + 4096; 2422e538c4aSArnaldo Carvalho de Melo } 2432e538c4aSArnaldo Carvalho de Melo 2449a29ceeeSArnaldo Carvalho de Melo void maps__fixup_end(struct maps *maps) 245af427bf5SArnaldo Carvalho de Melo { 2468efc4f05SArnaldo Carvalho de Melo struct map *prev = NULL, *curr; 247af427bf5SArnaldo Carvalho de Melo 2480a7c74eaSArnaldo Carvalho de Melo down_write(&maps->lock); 2496a2ffcddSArnaldo Carvalho de Melo 2508efc4f05SArnaldo Carvalho de Melo maps__for_each_entry(maps, curr) { 2518efc4f05SArnaldo Carvalho de Melo if (prev != NULL && !prev->end) 2528efc4f05SArnaldo Carvalho de Melo prev->end = curr->start; 253af427bf5SArnaldo Carvalho de Melo 2548efc4f05SArnaldo Carvalho de Melo prev = curr; 2552e538c4aSArnaldo Carvalho de Melo } 25690c83218SArnaldo Carvalho de Melo 25790c83218SArnaldo Carvalho de Melo /* 25890c83218SArnaldo Carvalho de Melo * We still haven't the actual symbols, so guess the 25990c83218SArnaldo Carvalho de Melo * last map final address. 26090c83218SArnaldo Carvalho de Melo */ 2618efc4f05SArnaldo Carvalho de Melo if (curr && !curr->end) 2629d1faba5SIan Munsie curr->end = ~0ULL; 2636a2ffcddSArnaldo Carvalho de Melo 2640a7c74eaSArnaldo Carvalho de Melo up_write(&maps->lock); 265af427bf5SArnaldo Carvalho de Melo } 266af427bf5SArnaldo Carvalho de Melo 267af30bffaSArnaldo Carvalho de Melo struct symbol *symbol__new(u64 start, u64 len, u8 binding, u8 type, const char *name) 26886470930SIngo Molnar { 26986470930SIngo Molnar size_t namelen = strlen(name) + 1; 270aeafcbafSArnaldo Carvalho de Melo struct symbol *sym = calloc(1, (symbol_conf.priv_size + 271aeafcbafSArnaldo Carvalho de Melo sizeof(*sym) + namelen)); 272aeafcbafSArnaldo Carvalho de Melo if (sym == NULL) 27386470930SIngo Molnar return NULL; 27486470930SIngo Molnar 275b01141f4SArnaldo Carvalho de Melo if (symbol_conf.priv_size) { 276b01141f4SArnaldo Carvalho de Melo if (symbol_conf.init_annotation) { 277b01141f4SArnaldo Carvalho de Melo struct annotation *notes = (void *)sym; 2784f74f187SIan Rogers annotation__init(notes); 279b01141f4SArnaldo Carvalho de Melo } 280aeafcbafSArnaldo Carvalho de Melo sym = ((void *)sym) + symbol_conf.priv_size; 281b01141f4SArnaldo Carvalho de Melo } 28236479484SArnaldo Carvalho de Melo 283aeafcbafSArnaldo Carvalho de Melo sym->start = start; 2842c241bd3SArnaldo Carvalho de Melo sym->end = len ? start + len : start; 285af30bffaSArnaldo Carvalho de Melo sym->type = type; 286aeafcbafSArnaldo Carvalho de Melo sym->binding = binding; 287aeafcbafSArnaldo Carvalho de Melo sym->namelen = namelen - 1; 288e4204992SArnaldo Carvalho de Melo 289aeafcbafSArnaldo Carvalho de Melo pr_debug4("%s: %s %#" PRIx64 "-%#" PRIx64 "\n", 290aeafcbafSArnaldo Carvalho de Melo __func__, name, start, sym->end); 291aeafcbafSArnaldo Carvalho de Melo memcpy(sym->name, name, namelen); 292e4204992SArnaldo Carvalho de Melo 293aeafcbafSArnaldo Carvalho de Melo return sym; 29486470930SIngo Molnar } 29586470930SIngo Molnar 296aeafcbafSArnaldo Carvalho de Melo void symbol__delete(struct symbol *sym) 29786470930SIngo Molnar { 2984f74f187SIan Rogers if (symbol_conf.priv_size) { 2994f74f187SIan Rogers if (symbol_conf.init_annotation) { 3004f74f187SIan Rogers struct annotation *notes = symbol__annotation(sym); 3014f74f187SIan Rogers 3024f74f187SIan Rogers annotation__exit(notes); 3034f74f187SIan Rogers } 3044f74f187SIan Rogers } 305aeafcbafSArnaldo Carvalho de Melo free(((void *)sym) - symbol_conf.priv_size); 30686470930SIngo Molnar } 30786470930SIngo Molnar 3087137ff50SDavidlohr Bueso void symbols__delete(struct rb_root_cached *symbols) 30986470930SIngo Molnar { 31086470930SIngo Molnar struct symbol *pos; 3117137ff50SDavidlohr Bueso struct rb_node *next = rb_first_cached(symbols); 31286470930SIngo Molnar 31386470930SIngo Molnar while (next) { 31486470930SIngo Molnar pos = rb_entry(next, struct symbol, rb_node); 31586470930SIngo Molnar next = rb_next(&pos->rb_node); 3167137ff50SDavidlohr Bueso rb_erase_cached(&pos->rb_node, symbols); 31700a192b3SArnaldo Carvalho de Melo symbol__delete(pos); 31886470930SIngo Molnar } 31986470930SIngo Molnar } 32086470930SIngo Molnar 3217137ff50SDavidlohr Bueso void __symbols__insert(struct rb_root_cached *symbols, 3227137ff50SDavidlohr Bueso struct symbol *sym, bool kernel) 32386470930SIngo Molnar { 3247137ff50SDavidlohr Bueso struct rb_node **p = &symbols->rb_root.rb_node; 32586470930SIngo Molnar struct rb_node *parent = NULL; 3269cffa8d5SPaul Mackerras const u64 ip = sym->start; 32786470930SIngo Molnar struct symbol *s; 3287137ff50SDavidlohr Bueso bool leftmost = true; 32986470930SIngo Molnar 330608c34deSArnaldo Carvalho de Melo if (kernel) { 331608c34deSArnaldo Carvalho de Melo const char *name = sym->name; 332608c34deSArnaldo Carvalho de Melo /* 333608c34deSArnaldo Carvalho de Melo * ppc64 uses function descriptors and appends a '.' to the 334608c34deSArnaldo Carvalho de Melo * start of every instruction address. Remove it. 335608c34deSArnaldo Carvalho de Melo */ 336608c34deSArnaldo Carvalho de Melo if (name[0] == '.') 337608c34deSArnaldo Carvalho de Melo name++; 338608c34deSArnaldo Carvalho de Melo sym->idle = symbol__is_idle(name); 339608c34deSArnaldo Carvalho de Melo } 340608c34deSArnaldo Carvalho de Melo 34186470930SIngo Molnar while (*p != NULL) { 34286470930SIngo Molnar parent = *p; 34386470930SIngo Molnar s = rb_entry(parent, struct symbol, rb_node); 34486470930SIngo Molnar if (ip < s->start) 34586470930SIngo Molnar p = &(*p)->rb_left; 3467137ff50SDavidlohr Bueso else { 34786470930SIngo Molnar p = &(*p)->rb_right; 3487137ff50SDavidlohr Bueso leftmost = false; 3497137ff50SDavidlohr Bueso } 35086470930SIngo Molnar } 35186470930SIngo Molnar rb_link_node(&sym->rb_node, parent, p); 3527137ff50SDavidlohr Bueso rb_insert_color_cached(&sym->rb_node, symbols, leftmost); 35386470930SIngo Molnar } 35486470930SIngo Molnar 3557137ff50SDavidlohr Bueso void symbols__insert(struct rb_root_cached *symbols, struct symbol *sym) 356608c34deSArnaldo Carvalho de Melo { 357608c34deSArnaldo Carvalho de Melo __symbols__insert(symbols, sym, false); 358608c34deSArnaldo Carvalho de Melo } 359608c34deSArnaldo Carvalho de Melo 3607137ff50SDavidlohr Bueso static struct symbol *symbols__find(struct rb_root_cached *symbols, u64 ip) 36186470930SIngo Molnar { 36286470930SIngo Molnar struct rb_node *n; 36386470930SIngo Molnar 364aeafcbafSArnaldo Carvalho de Melo if (symbols == NULL) 36586470930SIngo Molnar return NULL; 36686470930SIngo Molnar 3677137ff50SDavidlohr Bueso n = symbols->rb_root.rb_node; 36886470930SIngo Molnar 36986470930SIngo Molnar while (n) { 37086470930SIngo Molnar struct symbol *s = rb_entry(n, struct symbol, rb_node); 37186470930SIngo Molnar 37286470930SIngo Molnar if (ip < s->start) 37386470930SIngo Molnar n = n->rb_left; 3749c7b37cdSChris Phlipot else if (ip > s->end || (ip == s->end && ip != s->start)) 37586470930SIngo Molnar n = n->rb_right; 37686470930SIngo Molnar else 37786470930SIngo Molnar return s; 37886470930SIngo Molnar } 37986470930SIngo Molnar 38086470930SIngo Molnar return NULL; 38186470930SIngo Molnar } 38286470930SIngo Molnar 3837137ff50SDavidlohr Bueso static struct symbol *symbols__first(struct rb_root_cached *symbols) 3848e0cf965SAdrian Hunter { 3857137ff50SDavidlohr Bueso struct rb_node *n = rb_first_cached(symbols); 3868e0cf965SAdrian Hunter 3878e0cf965SAdrian Hunter if (n) 3888e0cf965SAdrian Hunter return rb_entry(n, struct symbol, rb_node); 3898e0cf965SAdrian Hunter 3908e0cf965SAdrian Hunter return NULL; 3918e0cf965SAdrian Hunter } 3928e0cf965SAdrian Hunter 3937137ff50SDavidlohr Bueso static struct symbol *symbols__last(struct rb_root_cached *symbols) 394cd67f99fSAdrian Hunter { 3957137ff50SDavidlohr Bueso struct rb_node *n = rb_last(&symbols->rb_root); 396cd67f99fSAdrian Hunter 397cd67f99fSAdrian Hunter if (n) 398cd67f99fSAdrian Hunter return rb_entry(n, struct symbol, rb_node); 399cd67f99fSAdrian Hunter 400cd67f99fSAdrian Hunter return NULL; 401cd67f99fSAdrian Hunter } 402cd67f99fSAdrian Hunter 4039c00a81bSAdrian Hunter static struct symbol *symbols__next(struct symbol *sym) 4049c00a81bSAdrian Hunter { 4059c00a81bSAdrian Hunter struct rb_node *n = rb_next(&sym->rb_node); 4069c00a81bSAdrian Hunter 4079c00a81bSAdrian Hunter if (n) 4089c00a81bSAdrian Hunter return rb_entry(n, struct symbol, rb_node); 4099c00a81bSAdrian Hunter 4109c00a81bSAdrian Hunter return NULL; 4119c00a81bSAdrian Hunter } 4129c00a81bSAdrian Hunter 4137137ff50SDavidlohr Bueso static void symbols__insert_by_name(struct rb_root_cached *symbols, struct symbol *sym) 41479406cd7SArnaldo Carvalho de Melo { 4157137ff50SDavidlohr Bueso struct rb_node **p = &symbols->rb_root.rb_node; 41679406cd7SArnaldo Carvalho de Melo struct rb_node *parent = NULL; 41702a9d037SRabin Vincent struct symbol_name_rb_node *symn, *s; 4187137ff50SDavidlohr Bueso bool leftmost = true; 41902a9d037SRabin Vincent 42002a9d037SRabin Vincent symn = container_of(sym, struct symbol_name_rb_node, sym); 42179406cd7SArnaldo Carvalho de Melo 42279406cd7SArnaldo Carvalho de Melo while (*p != NULL) { 42379406cd7SArnaldo Carvalho de Melo parent = *p; 42479406cd7SArnaldo Carvalho de Melo s = rb_entry(parent, struct symbol_name_rb_node, rb_node); 42579406cd7SArnaldo Carvalho de Melo if (strcmp(sym->name, s->sym.name) < 0) 42679406cd7SArnaldo Carvalho de Melo p = &(*p)->rb_left; 4277137ff50SDavidlohr Bueso else { 42879406cd7SArnaldo Carvalho de Melo p = &(*p)->rb_right; 4297137ff50SDavidlohr Bueso leftmost = false; 4307137ff50SDavidlohr Bueso } 43179406cd7SArnaldo Carvalho de Melo } 43279406cd7SArnaldo Carvalho de Melo rb_link_node(&symn->rb_node, parent, p); 4337137ff50SDavidlohr Bueso rb_insert_color_cached(&symn->rb_node, symbols, leftmost); 43479406cd7SArnaldo Carvalho de Melo } 43579406cd7SArnaldo Carvalho de Melo 4367137ff50SDavidlohr Bueso static void symbols__sort_by_name(struct rb_root_cached *symbols, 4377137ff50SDavidlohr Bueso struct rb_root_cached *source) 43879406cd7SArnaldo Carvalho de Melo { 43979406cd7SArnaldo Carvalho de Melo struct rb_node *nd; 44079406cd7SArnaldo Carvalho de Melo 4417137ff50SDavidlohr Bueso for (nd = rb_first_cached(source); nd; nd = rb_next(nd)) { 44279406cd7SArnaldo Carvalho de Melo struct symbol *pos = rb_entry(nd, struct symbol, rb_node); 443aeafcbafSArnaldo Carvalho de Melo symbols__insert_by_name(symbols, pos); 44479406cd7SArnaldo Carvalho de Melo } 44579406cd7SArnaldo Carvalho de Melo } 44679406cd7SArnaldo Carvalho de Melo 447d8040645SPaul Clarke int symbol__match_symbol_name(const char *name, const char *str, 448d8040645SPaul Clarke enum symbol_tag_include includes) 449d8040645SPaul Clarke { 450d8040645SPaul Clarke const char *versioning; 451d8040645SPaul Clarke 452d8040645SPaul Clarke if (includes == SYMBOL_TAG_INCLUDE__DEFAULT_ONLY && 453d8040645SPaul Clarke (versioning = strstr(name, "@@"))) { 454d8040645SPaul Clarke int len = strlen(str); 455d8040645SPaul Clarke 456d8040645SPaul Clarke if (len < versioning - name) 457d8040645SPaul Clarke len = versioning - name; 458d8040645SPaul Clarke 459d8040645SPaul Clarke return arch__compare_symbol_names_n(name, str, len); 460d8040645SPaul Clarke } else 461d8040645SPaul Clarke return arch__compare_symbol_names(name, str); 462d8040645SPaul Clarke } 463d8040645SPaul Clarke 4647137ff50SDavidlohr Bueso static struct symbol *symbols__find_by_name(struct rb_root_cached *symbols, 465d8040645SPaul Clarke const char *name, 466d8040645SPaul Clarke enum symbol_tag_include includes) 46779406cd7SArnaldo Carvalho de Melo { 46879406cd7SArnaldo Carvalho de Melo struct rb_node *n; 4695bcaaca3SMartin Liška struct symbol_name_rb_node *s = NULL; 47079406cd7SArnaldo Carvalho de Melo 471aeafcbafSArnaldo Carvalho de Melo if (symbols == NULL) 47279406cd7SArnaldo Carvalho de Melo return NULL; 47379406cd7SArnaldo Carvalho de Melo 4747137ff50SDavidlohr Bueso n = symbols->rb_root.rb_node; 47579406cd7SArnaldo Carvalho de Melo 47679406cd7SArnaldo Carvalho de Melo while (n) { 47779406cd7SArnaldo Carvalho de Melo int cmp; 47879406cd7SArnaldo Carvalho de Melo 47979406cd7SArnaldo Carvalho de Melo s = rb_entry(n, struct symbol_name_rb_node, rb_node); 480d8040645SPaul Clarke cmp = symbol__match_symbol_name(s->sym.name, name, includes); 48179406cd7SArnaldo Carvalho de Melo 482d8040645SPaul Clarke if (cmp > 0) 48379406cd7SArnaldo Carvalho de Melo n = n->rb_left; 484d8040645SPaul Clarke else if (cmp < 0) 48579406cd7SArnaldo Carvalho de Melo n = n->rb_right; 48679406cd7SArnaldo Carvalho de Melo else 487de480999SNamhyung Kim break; 48879406cd7SArnaldo Carvalho de Melo } 48979406cd7SArnaldo Carvalho de Melo 490de480999SNamhyung Kim if (n == NULL) 49179406cd7SArnaldo Carvalho de Melo return NULL; 492de480999SNamhyung Kim 493d8040645SPaul Clarke if (includes != SYMBOL_TAG_INCLUDE__DEFAULT_ONLY) 494de480999SNamhyung Kim /* return first symbol that has same name (if any) */ 495de480999SNamhyung Kim for (n = rb_prev(n); n; n = rb_prev(n)) { 496de480999SNamhyung Kim struct symbol_name_rb_node *tmp; 497de480999SNamhyung Kim 498de480999SNamhyung Kim tmp = rb_entry(n, struct symbol_name_rb_node, rb_node); 499031b84c4SNaveen N. Rao if (arch__compare_symbol_names(tmp->sym.name, s->sym.name)) 500de480999SNamhyung Kim break; 501de480999SNamhyung Kim 502de480999SNamhyung Kim s = tmp; 503de480999SNamhyung Kim } 504de480999SNamhyung Kim 505de480999SNamhyung Kim return &s->sym; 50679406cd7SArnaldo Carvalho de Melo } 50779406cd7SArnaldo Carvalho de Melo 508c0b4dffbSArnaldo Carvalho de Melo void dso__reset_find_symbol_cache(struct dso *dso) 509c0b4dffbSArnaldo Carvalho de Melo { 5103183f8caSArnaldo Carvalho de Melo dso->last_find_result.addr = 0; 5113183f8caSArnaldo Carvalho de Melo dso->last_find_result.symbol = NULL; 512c0b4dffbSArnaldo Carvalho de Melo } 513c0b4dffbSArnaldo Carvalho de Melo 5143183f8caSArnaldo Carvalho de Melo void dso__insert_symbol(struct dso *dso, struct symbol *sym) 515ae93a6c7SChris Phlipot { 5163183f8caSArnaldo Carvalho de Melo __symbols__insert(&dso->symbols, sym, dso->kernel); 517ae93a6c7SChris Phlipot 518ae93a6c7SChris Phlipot /* update the symbol cache if necessary */ 5193183f8caSArnaldo Carvalho de Melo if (dso->last_find_result.addr >= sym->start && 5203183f8caSArnaldo Carvalho de Melo (dso->last_find_result.addr < sym->end || 521ae93a6c7SChris Phlipot sym->start == sym->end)) { 5223183f8caSArnaldo Carvalho de Melo dso->last_find_result.symbol = sym; 523ae93a6c7SChris Phlipot } 524ae93a6c7SChris Phlipot } 525ae93a6c7SChris Phlipot 526ab8bf5f2STommi Rantala void dso__delete_symbol(struct dso *dso, struct symbol *sym) 527ab8bf5f2STommi Rantala { 528ab8bf5f2STommi Rantala rb_erase_cached(&sym->rb_node, &dso->symbols); 529ab8bf5f2STommi Rantala symbol__delete(sym); 530ab8bf5f2STommi Rantala dso__reset_find_symbol_cache(dso); 531ab8bf5f2STommi Rantala } 532ab8bf5f2STommi Rantala 5333183f8caSArnaldo Carvalho de Melo struct symbol *dso__find_symbol(struct dso *dso, u64 addr) 534fcf1203aSArnaldo Carvalho de Melo { 5353183f8caSArnaldo Carvalho de Melo if (dso->last_find_result.addr != addr || dso->last_find_result.symbol == NULL) { 5363183f8caSArnaldo Carvalho de Melo dso->last_find_result.addr = addr; 5373183f8caSArnaldo Carvalho de Melo dso->last_find_result.symbol = symbols__find(&dso->symbols, addr); 538b685ac22SArnaldo Carvalho de Melo } 539b685ac22SArnaldo Carvalho de Melo 5403183f8caSArnaldo Carvalho de Melo return dso->last_find_result.symbol; 5418e0cf965SAdrian Hunter } 5428e0cf965SAdrian Hunter 5435cf88a63SArnaldo Carvalho de Melo struct symbol *dso__first_symbol(struct dso *dso) 5445cf88a63SArnaldo Carvalho de Melo { 5453183f8caSArnaldo Carvalho de Melo return symbols__first(&dso->symbols); 546cd67f99fSAdrian Hunter } 547cd67f99fSAdrian Hunter 5485cf88a63SArnaldo Carvalho de Melo struct symbol *dso__last_symbol(struct dso *dso) 5495cf88a63SArnaldo Carvalho de Melo { 5503183f8caSArnaldo Carvalho de Melo return symbols__last(&dso->symbols); 5515cf88a63SArnaldo Carvalho de Melo } 5525cf88a63SArnaldo Carvalho de Melo 5539c00a81bSAdrian Hunter struct symbol *dso__next_symbol(struct symbol *sym) 5549c00a81bSAdrian Hunter { 5559c00a81bSAdrian Hunter return symbols__next(sym); 5569c00a81bSAdrian Hunter } 5579c00a81bSAdrian Hunter 55818bd7264SArnaldo Carvalho de Melo struct symbol *symbol__next_by_name(struct symbol *sym) 55918bd7264SArnaldo Carvalho de Melo { 56018bd7264SArnaldo Carvalho de Melo struct symbol_name_rb_node *s = container_of(sym, struct symbol_name_rb_node, sym); 56118bd7264SArnaldo Carvalho de Melo struct rb_node *n = rb_next(&s->rb_node); 56218bd7264SArnaldo Carvalho de Melo 56318bd7264SArnaldo Carvalho de Melo return n ? &rb_entry(n, struct symbol_name_rb_node, rb_node)->sym : NULL; 56418bd7264SArnaldo Carvalho de Melo } 56518bd7264SArnaldo Carvalho de Melo 56618bd7264SArnaldo Carvalho de Melo /* 567af07eeb0SArnaldo Carvalho de Melo * Returns first symbol that matched with @name. 56818bd7264SArnaldo Carvalho de Melo */ 5693183f8caSArnaldo Carvalho de Melo struct symbol *dso__find_symbol_by_name(struct dso *dso, const char *name) 57079406cd7SArnaldo Carvalho de Melo { 5713183f8caSArnaldo Carvalho de Melo struct symbol *s = symbols__find_by_name(&dso->symbol_names, name, 572d8040645SPaul Clarke SYMBOL_TAG_INCLUDE__NONE); 573d8040645SPaul Clarke if (!s) 5743183f8caSArnaldo Carvalho de Melo s = symbols__find_by_name(&dso->symbol_names, name, 575d8040645SPaul Clarke SYMBOL_TAG_INCLUDE__DEFAULT_ONLY); 576d8040645SPaul Clarke return s; 57779406cd7SArnaldo Carvalho de Melo } 57879406cd7SArnaldo Carvalho de Melo 5793183f8caSArnaldo Carvalho de Melo void dso__sort_by_name(struct dso *dso) 58079406cd7SArnaldo Carvalho de Melo { 5813183f8caSArnaldo Carvalho de Melo dso__set_sorted_by_name(dso); 5823183f8caSArnaldo Carvalho de Melo return symbols__sort_by_name(&dso->symbol_names, &dso->symbols); 58379406cd7SArnaldo Carvalho de Melo } 58479406cd7SArnaldo Carvalho de Melo 58532add10fSIan Rogers /* 58632add10fSIan Rogers * While we find nice hex chars, build a long_val. 58732add10fSIan Rogers * Return number of chars processed. 58832add10fSIan Rogers */ 58932add10fSIan Rogers static int hex2u64(const char *ptr, u64 *long_val) 59032add10fSIan Rogers { 59132add10fSIan Rogers char *p; 59232add10fSIan Rogers 59332add10fSIan Rogers *long_val = strtoull(ptr, &p, 16); 59432add10fSIan Rogers 59532add10fSIan Rogers return p - ptr; 59632add10fSIan Rogers } 59732add10fSIan Rogers 59832add10fSIan Rogers 599316d70d6SAdrian Hunter int modules__parse(const char *filename, void *arg, 600316d70d6SAdrian Hunter int (*process_module)(void *arg, const char *name, 6019ad4652bSThomas Richter u64 start, u64 size)) 602316d70d6SAdrian Hunter { 603316d70d6SAdrian Hunter char *line = NULL; 604316d70d6SAdrian Hunter size_t n; 605316d70d6SAdrian Hunter FILE *file; 606316d70d6SAdrian Hunter int err = 0; 607316d70d6SAdrian Hunter 608316d70d6SAdrian Hunter file = fopen(filename, "r"); 609316d70d6SAdrian Hunter if (file == NULL) 610316d70d6SAdrian Hunter return -1; 611316d70d6SAdrian Hunter 612316d70d6SAdrian Hunter while (1) { 613316d70d6SAdrian Hunter char name[PATH_MAX]; 6149ad4652bSThomas Richter u64 start, size; 6159ad4652bSThomas Richter char *sep, *endptr; 616316d70d6SAdrian Hunter ssize_t line_len; 617316d70d6SAdrian Hunter 618316d70d6SAdrian Hunter line_len = getline(&line, &n, file); 619316d70d6SAdrian Hunter if (line_len < 0) { 620316d70d6SAdrian Hunter if (feof(file)) 621316d70d6SAdrian Hunter break; 622316d70d6SAdrian Hunter err = -1; 623316d70d6SAdrian Hunter goto out; 624316d70d6SAdrian Hunter } 625316d70d6SAdrian Hunter 626316d70d6SAdrian Hunter if (!line) { 627316d70d6SAdrian Hunter err = -1; 628316d70d6SAdrian Hunter goto out; 629316d70d6SAdrian Hunter } 630316d70d6SAdrian Hunter 631316d70d6SAdrian Hunter line[--line_len] = '\0'; /* \n */ 632316d70d6SAdrian Hunter 633316d70d6SAdrian Hunter sep = strrchr(line, 'x'); 634316d70d6SAdrian Hunter if (sep == NULL) 635316d70d6SAdrian Hunter continue; 636316d70d6SAdrian Hunter 637316d70d6SAdrian Hunter hex2u64(sep + 1, &start); 638316d70d6SAdrian Hunter 639316d70d6SAdrian Hunter sep = strchr(line, ' '); 640316d70d6SAdrian Hunter if (sep == NULL) 641316d70d6SAdrian Hunter continue; 642316d70d6SAdrian Hunter 643316d70d6SAdrian Hunter *sep = '\0'; 644316d70d6SAdrian Hunter 645316d70d6SAdrian Hunter scnprintf(name, sizeof(name), "[%s]", line); 646316d70d6SAdrian Hunter 6479ad4652bSThomas Richter size = strtoul(sep + 1, &endptr, 0); 6489ad4652bSThomas Richter if (*endptr != ' ' && *endptr != '\t') 6499ad4652bSThomas Richter continue; 6509ad4652bSThomas Richter 6519ad4652bSThomas Richter err = process_module(arg, name, start, size); 652316d70d6SAdrian Hunter if (err) 653316d70d6SAdrian Hunter break; 654316d70d6SAdrian Hunter } 655316d70d6SAdrian Hunter out: 656316d70d6SAdrian Hunter free(line); 657316d70d6SAdrian Hunter fclose(file); 658316d70d6SAdrian Hunter return err; 659316d70d6SAdrian Hunter } 660316d70d6SAdrian Hunter 661e7110b9fSArnaldo Carvalho de Melo /* 662e7110b9fSArnaldo Carvalho de Melo * These are symbols in the kernel image, so make sure that 663e7110b9fSArnaldo Carvalho de Melo * sym is from a kernel DSO. 664e7110b9fSArnaldo Carvalho de Melo */ 665608c34deSArnaldo Carvalho de Melo static bool symbol__is_idle(const char *name) 66682d1deb0SDavid Ahern { 66782d1deb0SDavid Ahern const char * const idle_symbols[] = { 6680e71459aSKim Phillips "acpi_idle_do_entry", 6690e71459aSKim Phillips "acpi_processor_ffh_cstate_enter", 670549aff77SArnaldo Carvalho de Melo "arch_cpu_idle", 67182d1deb0SDavid Ahern "cpu_idle", 672e0336ed6SArnaldo Carvalho de Melo "cpu_startup_entry", 6730e71459aSKim Phillips "idle_cpu", 67482d1deb0SDavid Ahern "intel_idle", 67582d1deb0SDavid Ahern "default_idle", 67682d1deb0SDavid Ahern "native_safe_halt", 67782d1deb0SDavid Ahern "enter_idle", 67882d1deb0SDavid Ahern "exit_idle", 67982d1deb0SDavid Ahern "mwait_idle", 68082d1deb0SDavid Ahern "mwait_idle_with_hints", 681783abbd4SArnaldo Carvalho de Melo "mwait_idle_with_hints.constprop.0", 68282d1deb0SDavid Ahern "poll_idle", 68382d1deb0SDavid Ahern "ppc64_runlatch_off", 68482d1deb0SDavid Ahern "pseries_dedicated_idle_sleep", 68519bf119cSSven Schnelle "psw_idle", 68619bf119cSSven Schnelle "psw_idle_exit", 68782d1deb0SDavid Ahern NULL 68882d1deb0SDavid Ahern }; 68982d1deb0SDavid Ahern int i; 690bc5f15beSKim Phillips static struct strlist *idle_symbols_list; 69182d1deb0SDavid Ahern 692bc5f15beSKim Phillips if (idle_symbols_list) 693bc5f15beSKim Phillips return strlist__has_entry(idle_symbols_list, name); 69482d1deb0SDavid Ahern 695bc5f15beSKim Phillips idle_symbols_list = strlist__new(NULL, NULL); 696bc5f15beSKim Phillips 697bc5f15beSKim Phillips for (i = 0; idle_symbols[i]; i++) 698bc5f15beSKim Phillips strlist__add(idle_symbols_list, idle_symbols[i]); 699bc5f15beSKim Phillips 700bc5f15beSKim Phillips return strlist__has_entry(idle_symbols_list, name); 70182d1deb0SDavid Ahern } 70282d1deb0SDavid Ahern 703682b335aSArnaldo Carvalho de Melo static int map__process_kallsym_symbol(void *arg, const char *name, 70482151520SCody P Schafer char type, u64 start) 705682b335aSArnaldo Carvalho de Melo { 706682b335aSArnaldo Carvalho de Melo struct symbol *sym; 707333cc76cSArnaldo Carvalho de Melo struct dso *dso = arg; 7087137ff50SDavidlohr Bueso struct rb_root_cached *root = &dso->symbols; 709682b335aSArnaldo Carvalho de Melo 7103183f8caSArnaldo Carvalho de Melo if (!symbol_type__filter(type)) 711682b335aSArnaldo Carvalho de Melo return 0; 712682b335aSArnaldo Carvalho de Melo 7131a86f4baSLexi Shao /* Ignore local symbols for ARM modules */ 7141a86f4baSLexi Shao if (name[0] == '$') 7151a86f4baSLexi Shao return 0; 7161a86f4baSLexi Shao 71782151520SCody P Schafer /* 71882151520SCody P Schafer * module symbols are not sorted so we add all 71982151520SCody P Schafer * symbols, setting length to 0, and rely on 72082151520SCody P Schafer * symbols__fixup_end() to fix it up. 72182151520SCody P Schafer */ 722af30bffaSArnaldo Carvalho de Melo sym = symbol__new(start, 0, kallsyms2elf_binding(type), kallsyms2elf_type(type), name); 7232e538c4aSArnaldo Carvalho de Melo if (sym == NULL) 724682b335aSArnaldo Carvalho de Melo return -ENOMEM; 72582164161SArnaldo Carvalho de Melo /* 72682164161SArnaldo Carvalho de Melo * We will pass the symbols to the filter later, in 7274e06255fSArnaldo Carvalho de Melo * map__split_kallsyms, when we have split the maps per module 72882164161SArnaldo Carvalho de Melo */ 729608c34deSArnaldo Carvalho de Melo __symbols__insert(root, sym, !strchr(name, '[')); 730a1645ce1SZhang, Yanmin 731682b335aSArnaldo Carvalho de Melo return 0; 7322e538c4aSArnaldo Carvalho de Melo } 7332e538c4aSArnaldo Carvalho de Melo 734682b335aSArnaldo Carvalho de Melo /* 735682b335aSArnaldo Carvalho de Melo * Loads the function entries in /proc/kallsyms into kernel_map->dso, 736682b335aSArnaldo Carvalho de Melo * so that we can in the next step set the symbol ->end address and then 737682b335aSArnaldo Carvalho de Melo * call kernel_maps__split_kallsyms. 738682b335aSArnaldo Carvalho de Melo */ 739333cc76cSArnaldo Carvalho de Melo static int dso__load_all_kallsyms(struct dso *dso, const char *filename) 740682b335aSArnaldo Carvalho de Melo { 741333cc76cSArnaldo Carvalho de Melo return kallsyms__parse(filename, dso, map__process_kallsym_symbol); 7422e538c4aSArnaldo Carvalho de Melo } 7432e538c4aSArnaldo Carvalho de Melo 74479b6bb73SArnaldo Carvalho de Melo static int maps__split_kallsyms_for_kcore(struct maps *kmaps, struct dso *dso) 7458e0cf965SAdrian Hunter { 7468e0cf965SAdrian Hunter struct map *curr_map; 7478e0cf965SAdrian Hunter struct symbol *pos; 748866548ddSAdrian Hunter int count = 0; 7497137ff50SDavidlohr Bueso struct rb_root_cached old_root = dso->symbols; 7507137ff50SDavidlohr Bueso struct rb_root_cached *root = &dso->symbols; 7517137ff50SDavidlohr Bueso struct rb_node *next = rb_first_cached(root); 7528e0cf965SAdrian Hunter 753ba92732eSWang Nan if (!kmaps) 754ba92732eSWang Nan return -1; 755ba92732eSWang Nan 7567137ff50SDavidlohr Bueso *root = RB_ROOT_CACHED; 757866548ddSAdrian Hunter 7588e0cf965SAdrian Hunter while (next) { 7598e0cf965SAdrian Hunter char *module; 7608e0cf965SAdrian Hunter 7618e0cf965SAdrian Hunter pos = rb_entry(next, struct symbol, rb_node); 7628e0cf965SAdrian Hunter next = rb_next(&pos->rb_node); 7638e0cf965SAdrian Hunter 7647137ff50SDavidlohr Bueso rb_erase_cached(&pos->rb_node, &old_root); 7657137ff50SDavidlohr Bueso RB_CLEAR_NODE(&pos->rb_node); 7668e0cf965SAdrian Hunter module = strchr(pos->name, '\t'); 7678e0cf965SAdrian Hunter if (module) 7688e0cf965SAdrian Hunter *module = '\0'; 7698e0cf965SAdrian Hunter 77079b6bb73SArnaldo Carvalho de Melo curr_map = maps__find(kmaps, pos->start); 7718e0cf965SAdrian Hunter 772be39db9fSArnaldo Carvalho de Melo if (!curr_map) { 7738e0cf965SAdrian Hunter symbol__delete(pos); 774866548ddSAdrian Hunter continue; 775866548ddSAdrian Hunter } 776866548ddSAdrian Hunter 7778e0cf965SAdrian Hunter pos->start -= curr_map->start - curr_map->pgoff; 778d6d45745SAdrian Hunter if (pos->end > curr_map->end) 779d6d45745SAdrian Hunter pos->end = curr_map->end; 7808e0cf965SAdrian Hunter if (pos->end) 7818e0cf965SAdrian Hunter pos->end -= curr_map->start - curr_map->pgoff; 7823183f8caSArnaldo Carvalho de Melo symbols__insert(&curr_map->dso->symbols, pos); 7838e0cf965SAdrian Hunter ++count; 7848e0cf965SAdrian Hunter } 7858e0cf965SAdrian Hunter 7868e0cf965SAdrian Hunter /* Symbols have been adjusted */ 7878e0cf965SAdrian Hunter dso->adjust_symbols = 1; 7888e0cf965SAdrian Hunter 789866548ddSAdrian Hunter return count; 7908e0cf965SAdrian Hunter } 7918e0cf965SAdrian Hunter 7922e538c4aSArnaldo Carvalho de Melo /* 7932e538c4aSArnaldo Carvalho de Melo * Split the symbols into maps, making sure there are no overlaps, i.e. the 7942e538c4aSArnaldo Carvalho de Melo * kernel range is broken in several maps, named [kernel].N, as we don't have 7952e538c4aSArnaldo Carvalho de Melo * the original ELF section names vmlinux have. 7962e538c4aSArnaldo Carvalho de Melo */ 79779b6bb73SArnaldo Carvalho de Melo static int maps__split_kallsyms(struct maps *kmaps, struct dso *dso, u64 delta, 79815e0e2d4SArnaldo Carvalho de Melo struct map *initial_map) 7992e538c4aSArnaldo Carvalho de Melo { 800ba92732eSWang Nan struct machine *machine; 80115e0e2d4SArnaldo Carvalho de Melo struct map *curr_map = initial_map; 8022e538c4aSArnaldo Carvalho de Melo struct symbol *pos; 8038a953312SArnaldo Carvalho de Melo int count = 0, moved = 0; 8047137ff50SDavidlohr Bueso struct rb_root_cached *root = &dso->symbols; 8057137ff50SDavidlohr Bueso struct rb_node *next = rb_first_cached(root); 8062e538c4aSArnaldo Carvalho de Melo int kernel_range = 0; 8074d004365SAdrian Hunter bool x86_64; 8082e538c4aSArnaldo Carvalho de Melo 809ba92732eSWang Nan if (!kmaps) 810ba92732eSWang Nan return -1; 811ba92732eSWang Nan 812ba92732eSWang Nan machine = kmaps->machine; 813ba92732eSWang Nan 8144d004365SAdrian Hunter x86_64 = machine__is(machine, "x86_64"); 8154d004365SAdrian Hunter 8162e538c4aSArnaldo Carvalho de Melo while (next) { 8172e538c4aSArnaldo Carvalho de Melo char *module; 8182e538c4aSArnaldo Carvalho de Melo 8192e538c4aSArnaldo Carvalho de Melo pos = rb_entry(next, struct symbol, rb_node); 8202e538c4aSArnaldo Carvalho de Melo next = rb_next(&pos->rb_node); 8212e538c4aSArnaldo Carvalho de Melo 8222e538c4aSArnaldo Carvalho de Melo module = strchr(pos->name, '\t'); 8232e538c4aSArnaldo Carvalho de Melo if (module) { 82475be6cf4SArnaldo Carvalho de Melo if (!symbol_conf.use_modules) 8251de8e245SArnaldo Carvalho de Melo goto discard_symbol; 8261de8e245SArnaldo Carvalho de Melo 8272e538c4aSArnaldo Carvalho de Melo *module++ = '\0'; 8282e538c4aSArnaldo Carvalho de Melo 829b7cece76SArnaldo Carvalho de Melo if (strcmp(curr_map->dso->short_name, module)) { 83015e0e2d4SArnaldo Carvalho de Melo if (curr_map != initial_map && 8311c695c88SJiri Olsa dso->kernel == DSO_SPACE__KERNEL_GUEST && 83223346f21SArnaldo Carvalho de Melo machine__is_default_guest(machine)) { 833a1645ce1SZhang, Yanmin /* 834a1645ce1SZhang, Yanmin * We assume all symbols of a module are 835a1645ce1SZhang, Yanmin * continuous in * kallsyms, so curr_map 836a1645ce1SZhang, Yanmin * points to a module and all its 837a1645ce1SZhang, Yanmin * symbols are in its kmap. Mark it as 838a1645ce1SZhang, Yanmin * loaded. 839a1645ce1SZhang, Yanmin */ 8403183f8caSArnaldo Carvalho de Melo dso__set_loaded(curr_map->dso); 841af427bf5SArnaldo Carvalho de Melo } 842b7cece76SArnaldo Carvalho de Melo 84379b6bb73SArnaldo Carvalho de Melo curr_map = maps__find_by_name(kmaps, module); 844a1645ce1SZhang, Yanmin if (curr_map == NULL) { 8452f51903bSArnaldo Carvalho de Melo pr_debug("%s/proc/{kallsyms,modules} " 846a1645ce1SZhang, Yanmin "inconsistency while looking " 847a1645ce1SZhang, Yanmin "for \"%s\" module!\n", 84823346f21SArnaldo Carvalho de Melo machine->root_dir, module); 84915e0e2d4SArnaldo Carvalho de Melo curr_map = initial_map; 850a1645ce1SZhang, Yanmin goto discard_symbol; 851a1645ce1SZhang, Yanmin } 852a1645ce1SZhang, Yanmin 853a1645ce1SZhang, Yanmin if (curr_map->dso->loaded && 85423346f21SArnaldo Carvalho de Melo !machine__is_default_guest(machine)) 855b7cece76SArnaldo Carvalho de Melo goto discard_symbol; 856af427bf5SArnaldo Carvalho de Melo } 85786470930SIngo Molnar /* 8582e538c4aSArnaldo Carvalho de Melo * So that we look just like we get from .ko files, 85915e0e2d4SArnaldo Carvalho de Melo * i.e. not prelinked, relative to initial_map->start. 86086470930SIngo Molnar */ 8614e06255fSArnaldo Carvalho de Melo pos->start = curr_map->map_ip(curr_map, pos->start); 8624e06255fSArnaldo Carvalho de Melo pos->end = curr_map->map_ip(curr_map, pos->end); 8634d004365SAdrian Hunter } else if (x86_64 && is_entry_trampoline(pos->name)) { 8644d004365SAdrian Hunter /* 8654d004365SAdrian Hunter * These symbols are not needed anymore since the 8664d004365SAdrian Hunter * trampoline maps refer to the text section and it's 8674d004365SAdrian Hunter * symbols instead. Avoid having to deal with 8684d004365SAdrian Hunter * relocations, and the assumption that the first symbol 8694d004365SAdrian Hunter * is the start of kernel text, by simply removing the 8704d004365SAdrian Hunter * symbols at this point. 8714d004365SAdrian Hunter */ 8724d004365SAdrian Hunter goto discard_symbol; 87315e0e2d4SArnaldo Carvalho de Melo } else if (curr_map != initial_map) { 8742e538c4aSArnaldo Carvalho de Melo char dso_name[PATH_MAX]; 875aeafcbafSArnaldo Carvalho de Melo struct dso *ndso; 87686470930SIngo Molnar 877d9b62abaSAdrian Hunter if (delta) { 878d9b62abaSAdrian Hunter /* Kernel was relocated at boot time */ 879d9b62abaSAdrian Hunter pos->start -= delta; 880d9b62abaSAdrian Hunter pos->end -= delta; 881d9b62abaSAdrian Hunter } 882d9b62abaSAdrian Hunter 8838a953312SArnaldo Carvalho de Melo if (count == 0) { 88415e0e2d4SArnaldo Carvalho de Melo curr_map = initial_map; 885be39db9fSArnaldo Carvalho de Melo goto add_symbol; 8868a953312SArnaldo Carvalho de Melo } 8878a953312SArnaldo Carvalho de Melo 8881c695c88SJiri Olsa if (dso->kernel == DSO_SPACE__KERNEL_GUEST) 889a1645ce1SZhang, Yanmin snprintf(dso_name, sizeof(dso_name), 890a1645ce1SZhang, Yanmin "[guest.kernel].%d", 891a1645ce1SZhang, Yanmin kernel_range++); 892a1645ce1SZhang, Yanmin else 893a1645ce1SZhang, Yanmin snprintf(dso_name, sizeof(dso_name), 894a1645ce1SZhang, Yanmin "[kernel].%d", 8952e538c4aSArnaldo Carvalho de Melo kernel_range++); 89686470930SIngo Molnar 897aeafcbafSArnaldo Carvalho de Melo ndso = dso__new(dso_name); 898aeafcbafSArnaldo Carvalho de Melo if (ndso == NULL) 8992e538c4aSArnaldo Carvalho de Melo return -1; 9002e538c4aSArnaldo Carvalho de Melo 901aeafcbafSArnaldo Carvalho de Melo ndso->kernel = dso->kernel; 902a1645ce1SZhang, Yanmin 9033183f8caSArnaldo Carvalho de Melo curr_map = map__new2(pos->start, ndso); 90437fe5fcbSZhang, Yanmin if (curr_map == NULL) { 905d3a7c489SArnaldo Carvalho de Melo dso__put(ndso); 9062e538c4aSArnaldo Carvalho de Melo return -1; 9072e538c4aSArnaldo Carvalho de Melo } 9082e538c4aSArnaldo Carvalho de Melo 9094e06255fSArnaldo Carvalho de Melo curr_map->map_ip = curr_map->unmap_ip = identity__map_ip; 91079b6bb73SArnaldo Carvalho de Melo maps__insert(kmaps, curr_map); 9112e538c4aSArnaldo Carvalho de Melo ++kernel_range; 912d9b62abaSAdrian Hunter } else if (delta) { 913d9b62abaSAdrian Hunter /* Kernel was relocated at boot time */ 914d9b62abaSAdrian Hunter pos->start -= delta; 915d9b62abaSAdrian Hunter pos->end -= delta; 9162e538c4aSArnaldo Carvalho de Melo } 917be39db9fSArnaldo Carvalho de Melo add_symbol: 91815e0e2d4SArnaldo Carvalho de Melo if (curr_map != initial_map) { 9197137ff50SDavidlohr Bueso rb_erase_cached(&pos->rb_node, root); 9203183f8caSArnaldo Carvalho de Melo symbols__insert(&curr_map->dso->symbols, pos); 9218a953312SArnaldo Carvalho de Melo ++moved; 9228a953312SArnaldo Carvalho de Melo } else 9238a953312SArnaldo Carvalho de Melo ++count; 924be39db9fSArnaldo Carvalho de Melo 925be39db9fSArnaldo Carvalho de Melo continue; 926be39db9fSArnaldo Carvalho de Melo discard_symbol: 9277137ff50SDavidlohr Bueso rb_erase_cached(&pos->rb_node, root); 928be39db9fSArnaldo Carvalho de Melo symbol__delete(pos); 92986470930SIngo Molnar } 93086470930SIngo Molnar 93115e0e2d4SArnaldo Carvalho de Melo if (curr_map != initial_map && 9321c695c88SJiri Olsa dso->kernel == DSO_SPACE__KERNEL_GUEST && 93323346f21SArnaldo Carvalho de Melo machine__is_default_guest(kmaps->machine)) { 9343183f8caSArnaldo Carvalho de Melo dso__set_loaded(curr_map->dso); 935a1645ce1SZhang, Yanmin } 936a1645ce1SZhang, Yanmin 9378a953312SArnaldo Carvalho de Melo return count + moved; 93886470930SIngo Molnar } 93986470930SIngo Molnar 9403f067dcaSArnaldo Carvalho de Melo bool symbol__restricted_filename(const char *filename, 941ec80fde7SArnaldo Carvalho de Melo const char *restricted_filename) 942ec80fde7SArnaldo Carvalho de Melo { 943ec80fde7SArnaldo Carvalho de Melo bool restricted = false; 944ec80fde7SArnaldo Carvalho de Melo 945ec80fde7SArnaldo Carvalho de Melo if (symbol_conf.kptr_restrict) { 946ec80fde7SArnaldo Carvalho de Melo char *r = realpath(filename, NULL); 947ec80fde7SArnaldo Carvalho de Melo 948ec80fde7SArnaldo Carvalho de Melo if (r != NULL) { 949ec80fde7SArnaldo Carvalho de Melo restricted = strcmp(r, restricted_filename) == 0; 950ec80fde7SArnaldo Carvalho de Melo free(r); 951ec80fde7SArnaldo Carvalho de Melo return restricted; 952ec80fde7SArnaldo Carvalho de Melo } 953ec80fde7SArnaldo Carvalho de Melo } 954ec80fde7SArnaldo Carvalho de Melo 955ec80fde7SArnaldo Carvalho de Melo return restricted; 956ec80fde7SArnaldo Carvalho de Melo } 957ec80fde7SArnaldo Carvalho de Melo 95852afdaf9SAdrian Hunter struct module_info { 95952afdaf9SAdrian Hunter struct rb_node rb_node; 96052afdaf9SAdrian Hunter char *name; 96152afdaf9SAdrian Hunter u64 start; 96252afdaf9SAdrian Hunter }; 96352afdaf9SAdrian Hunter 96452afdaf9SAdrian Hunter static void add_module(struct module_info *mi, struct rb_root *modules) 96552afdaf9SAdrian Hunter { 96652afdaf9SAdrian Hunter struct rb_node **p = &modules->rb_node; 96752afdaf9SAdrian Hunter struct rb_node *parent = NULL; 96852afdaf9SAdrian Hunter struct module_info *m; 96952afdaf9SAdrian Hunter 97052afdaf9SAdrian Hunter while (*p != NULL) { 97152afdaf9SAdrian Hunter parent = *p; 97252afdaf9SAdrian Hunter m = rb_entry(parent, struct module_info, rb_node); 97352afdaf9SAdrian Hunter if (strcmp(mi->name, m->name) < 0) 97452afdaf9SAdrian Hunter p = &(*p)->rb_left; 97552afdaf9SAdrian Hunter else 97652afdaf9SAdrian Hunter p = &(*p)->rb_right; 97752afdaf9SAdrian Hunter } 97852afdaf9SAdrian Hunter rb_link_node(&mi->rb_node, parent, p); 97952afdaf9SAdrian Hunter rb_insert_color(&mi->rb_node, modules); 98052afdaf9SAdrian Hunter } 98152afdaf9SAdrian Hunter 98252afdaf9SAdrian Hunter static void delete_modules(struct rb_root *modules) 98352afdaf9SAdrian Hunter { 98452afdaf9SAdrian Hunter struct module_info *mi; 98552afdaf9SAdrian Hunter struct rb_node *next = rb_first(modules); 98652afdaf9SAdrian Hunter 98752afdaf9SAdrian Hunter while (next) { 98852afdaf9SAdrian Hunter mi = rb_entry(next, struct module_info, rb_node); 98952afdaf9SAdrian Hunter next = rb_next(&mi->rb_node); 99052afdaf9SAdrian Hunter rb_erase(&mi->rb_node, modules); 99174cf249dSArnaldo Carvalho de Melo zfree(&mi->name); 99252afdaf9SAdrian Hunter free(mi); 99352afdaf9SAdrian Hunter } 99452afdaf9SAdrian Hunter } 99552afdaf9SAdrian Hunter 99652afdaf9SAdrian Hunter static struct module_info *find_module(const char *name, 99752afdaf9SAdrian Hunter struct rb_root *modules) 99852afdaf9SAdrian Hunter { 99952afdaf9SAdrian Hunter struct rb_node *n = modules->rb_node; 100052afdaf9SAdrian Hunter 100152afdaf9SAdrian Hunter while (n) { 100252afdaf9SAdrian Hunter struct module_info *m; 100352afdaf9SAdrian Hunter int cmp; 100452afdaf9SAdrian Hunter 100552afdaf9SAdrian Hunter m = rb_entry(n, struct module_info, rb_node); 100652afdaf9SAdrian Hunter cmp = strcmp(name, m->name); 100752afdaf9SAdrian Hunter if (cmp < 0) 100852afdaf9SAdrian Hunter n = n->rb_left; 100952afdaf9SAdrian Hunter else if (cmp > 0) 101052afdaf9SAdrian Hunter n = n->rb_right; 101152afdaf9SAdrian Hunter else 101252afdaf9SAdrian Hunter return m; 101352afdaf9SAdrian Hunter } 101452afdaf9SAdrian Hunter 101552afdaf9SAdrian Hunter return NULL; 101652afdaf9SAdrian Hunter } 101752afdaf9SAdrian Hunter 10189ad4652bSThomas Richter static int __read_proc_modules(void *arg, const char *name, u64 start, 10199ad4652bSThomas Richter u64 size __maybe_unused) 102052afdaf9SAdrian Hunter { 102152afdaf9SAdrian Hunter struct rb_root *modules = arg; 102252afdaf9SAdrian Hunter struct module_info *mi; 102352afdaf9SAdrian Hunter 102452afdaf9SAdrian Hunter mi = zalloc(sizeof(struct module_info)); 102552afdaf9SAdrian Hunter if (!mi) 102652afdaf9SAdrian Hunter return -ENOMEM; 102752afdaf9SAdrian Hunter 102852afdaf9SAdrian Hunter mi->name = strdup(name); 102952afdaf9SAdrian Hunter mi->start = start; 103052afdaf9SAdrian Hunter 103152afdaf9SAdrian Hunter if (!mi->name) { 103252afdaf9SAdrian Hunter free(mi); 103352afdaf9SAdrian Hunter return -ENOMEM; 103452afdaf9SAdrian Hunter } 103552afdaf9SAdrian Hunter 103652afdaf9SAdrian Hunter add_module(mi, modules); 103752afdaf9SAdrian Hunter 103852afdaf9SAdrian Hunter return 0; 103952afdaf9SAdrian Hunter } 104052afdaf9SAdrian Hunter 104152afdaf9SAdrian Hunter static int read_proc_modules(const char *filename, struct rb_root *modules) 104252afdaf9SAdrian Hunter { 104352afdaf9SAdrian Hunter if (symbol__restricted_filename(filename, "/proc/modules")) 104452afdaf9SAdrian Hunter return -1; 104552afdaf9SAdrian Hunter 104652afdaf9SAdrian Hunter if (modules__parse(filename, modules, __read_proc_modules)) { 104752afdaf9SAdrian Hunter delete_modules(modules); 104852afdaf9SAdrian Hunter return -1; 104952afdaf9SAdrian Hunter } 105052afdaf9SAdrian Hunter 105152afdaf9SAdrian Hunter return 0; 105252afdaf9SAdrian Hunter } 105352afdaf9SAdrian Hunter 1054fc1b691dSAdrian Hunter int compare_proc_modules(const char *from, const char *to) 1055fc1b691dSAdrian Hunter { 1056fc1b691dSAdrian Hunter struct rb_root from_modules = RB_ROOT; 1057fc1b691dSAdrian Hunter struct rb_root to_modules = RB_ROOT; 1058fc1b691dSAdrian Hunter struct rb_node *from_node, *to_node; 1059fc1b691dSAdrian Hunter struct module_info *from_m, *to_m; 1060fc1b691dSAdrian Hunter int ret = -1; 1061fc1b691dSAdrian Hunter 1062fc1b691dSAdrian Hunter if (read_proc_modules(from, &from_modules)) 1063fc1b691dSAdrian Hunter return -1; 1064fc1b691dSAdrian Hunter 1065fc1b691dSAdrian Hunter if (read_proc_modules(to, &to_modules)) 1066fc1b691dSAdrian Hunter goto out_delete_from; 1067fc1b691dSAdrian Hunter 1068fc1b691dSAdrian Hunter from_node = rb_first(&from_modules); 1069fc1b691dSAdrian Hunter to_node = rb_first(&to_modules); 1070fc1b691dSAdrian Hunter while (from_node) { 1071fc1b691dSAdrian Hunter if (!to_node) 1072fc1b691dSAdrian Hunter break; 1073fc1b691dSAdrian Hunter 1074fc1b691dSAdrian Hunter from_m = rb_entry(from_node, struct module_info, rb_node); 1075fc1b691dSAdrian Hunter to_m = rb_entry(to_node, struct module_info, rb_node); 1076fc1b691dSAdrian Hunter 1077fc1b691dSAdrian Hunter if (from_m->start != to_m->start || 1078fc1b691dSAdrian Hunter strcmp(from_m->name, to_m->name)) 1079fc1b691dSAdrian Hunter break; 1080fc1b691dSAdrian Hunter 1081fc1b691dSAdrian Hunter from_node = rb_next(from_node); 1082fc1b691dSAdrian Hunter to_node = rb_next(to_node); 1083fc1b691dSAdrian Hunter } 1084fc1b691dSAdrian Hunter 1085fc1b691dSAdrian Hunter if (!from_node && !to_node) 1086fc1b691dSAdrian Hunter ret = 0; 1087fc1b691dSAdrian Hunter 1088fc1b691dSAdrian Hunter delete_modules(&to_modules); 1089fc1b691dSAdrian Hunter out_delete_from: 1090fc1b691dSAdrian Hunter delete_modules(&from_modules); 1091fc1b691dSAdrian Hunter 1092fc1b691dSAdrian Hunter return ret; 1093fc1b691dSAdrian Hunter } 1094fc1b691dSAdrian Hunter 109579b6bb73SArnaldo Carvalho de Melo static int do_validate_kcore_modules(const char *filename, struct maps *kmaps) 109652afdaf9SAdrian Hunter { 109752afdaf9SAdrian Hunter struct rb_root modules = RB_ROOT; 109852afdaf9SAdrian Hunter struct map *old_map; 109952afdaf9SAdrian Hunter int err; 110052afdaf9SAdrian Hunter 110152afdaf9SAdrian Hunter err = read_proc_modules(filename, &modules); 110252afdaf9SAdrian Hunter if (err) 110352afdaf9SAdrian Hunter return err; 110452afdaf9SAdrian Hunter 110579b6bb73SArnaldo Carvalho de Melo maps__for_each_entry(kmaps, old_map) { 110652afdaf9SAdrian Hunter struct module_info *mi; 110752afdaf9SAdrian Hunter 11085759a682SAdrian Hunter if (!__map__is_kmodule(old_map)) { 110952afdaf9SAdrian Hunter continue; 111052afdaf9SAdrian Hunter } 111152afdaf9SAdrian Hunter 111252afdaf9SAdrian Hunter /* Module must be in memory at the same address */ 111352afdaf9SAdrian Hunter mi = find_module(old_map->dso->short_name, &modules); 111452afdaf9SAdrian Hunter if (!mi || mi->start != old_map->start) { 111552afdaf9SAdrian Hunter err = -EINVAL; 111652afdaf9SAdrian Hunter goto out; 111752afdaf9SAdrian Hunter } 111852afdaf9SAdrian Hunter } 111952afdaf9SAdrian Hunter out: 112052afdaf9SAdrian Hunter delete_modules(&modules); 112152afdaf9SAdrian Hunter return err; 112252afdaf9SAdrian Hunter } 112352afdaf9SAdrian Hunter 112452afdaf9SAdrian Hunter /* 112552afdaf9SAdrian Hunter * If kallsyms is referenced by name then we look for filename in the same 112652afdaf9SAdrian Hunter * directory. 112752afdaf9SAdrian Hunter */ 112852afdaf9SAdrian Hunter static bool filename_from_kallsyms_filename(char *filename, 112952afdaf9SAdrian Hunter const char *base_name, 113052afdaf9SAdrian Hunter const char *kallsyms_filename) 113152afdaf9SAdrian Hunter { 113252afdaf9SAdrian Hunter char *name; 113352afdaf9SAdrian Hunter 113452afdaf9SAdrian Hunter strcpy(filename, kallsyms_filename); 113552afdaf9SAdrian Hunter name = strrchr(filename, '/'); 113652afdaf9SAdrian Hunter if (!name) 113752afdaf9SAdrian Hunter return false; 113852afdaf9SAdrian Hunter 113952afdaf9SAdrian Hunter name += 1; 114052afdaf9SAdrian Hunter 114152afdaf9SAdrian Hunter if (!strcmp(name, "kallsyms")) { 114252afdaf9SAdrian Hunter strcpy(name, base_name); 114352afdaf9SAdrian Hunter return true; 114452afdaf9SAdrian Hunter } 114552afdaf9SAdrian Hunter 114652afdaf9SAdrian Hunter return false; 114752afdaf9SAdrian Hunter } 114852afdaf9SAdrian Hunter 114952afdaf9SAdrian Hunter static int validate_kcore_modules(const char *kallsyms_filename, 115052afdaf9SAdrian Hunter struct map *map) 115152afdaf9SAdrian Hunter { 115279b6bb73SArnaldo Carvalho de Melo struct maps *kmaps = map__kmaps(map); 115352afdaf9SAdrian Hunter char modules_filename[PATH_MAX]; 115452afdaf9SAdrian Hunter 1155ba92732eSWang Nan if (!kmaps) 1156ba92732eSWang Nan return -EINVAL; 1157ba92732eSWang Nan 115852afdaf9SAdrian Hunter if (!filename_from_kallsyms_filename(modules_filename, "modules", 115952afdaf9SAdrian Hunter kallsyms_filename)) 116052afdaf9SAdrian Hunter return -EINVAL; 116152afdaf9SAdrian Hunter 11625759a682SAdrian Hunter if (do_validate_kcore_modules(modules_filename, kmaps)) 116352afdaf9SAdrian Hunter return -EINVAL; 116452afdaf9SAdrian Hunter 116552afdaf9SAdrian Hunter return 0; 116652afdaf9SAdrian Hunter } 116752afdaf9SAdrian Hunter 1168a00d28cbSAdrian Hunter static int validate_kcore_addresses(const char *kallsyms_filename, 1169a00d28cbSAdrian Hunter struct map *map) 1170a00d28cbSAdrian Hunter { 1171a00d28cbSAdrian Hunter struct kmap *kmap = map__kmap(map); 1172a00d28cbSAdrian Hunter 1173ba92732eSWang Nan if (!kmap) 1174ba92732eSWang Nan return -EINVAL; 1175ba92732eSWang Nan 1176a00d28cbSAdrian Hunter if (kmap->ref_reloc_sym && kmap->ref_reloc_sym->name) { 1177a00d28cbSAdrian Hunter u64 start; 1178a00d28cbSAdrian Hunter 1179b843f62aSArnaldo Carvalho de Melo if (kallsyms__get_function_start(kallsyms_filename, 1180b843f62aSArnaldo Carvalho de Melo kmap->ref_reloc_sym->name, &start)) 1181b843f62aSArnaldo Carvalho de Melo return -ENOENT; 1182a00d28cbSAdrian Hunter if (start != kmap->ref_reloc_sym->addr) 1183a00d28cbSAdrian Hunter return -EINVAL; 1184a00d28cbSAdrian Hunter } 1185a00d28cbSAdrian Hunter 1186a00d28cbSAdrian Hunter return validate_kcore_modules(kallsyms_filename, map); 1187a00d28cbSAdrian Hunter } 1188a00d28cbSAdrian Hunter 11898e0cf965SAdrian Hunter struct kcore_mapfn_data { 11908e0cf965SAdrian Hunter struct dso *dso; 11918e0cf965SAdrian Hunter struct list_head maps; 11928e0cf965SAdrian Hunter }; 11938e0cf965SAdrian Hunter 11948e0cf965SAdrian Hunter static int kcore_mapfn(u64 start, u64 len, u64 pgoff, void *data) 11958e0cf965SAdrian Hunter { 11968e0cf965SAdrian Hunter struct kcore_mapfn_data *md = data; 11978e0cf965SAdrian Hunter struct map *map; 11988e0cf965SAdrian Hunter 11993183f8caSArnaldo Carvalho de Melo map = map__new2(start, md->dso); 12008e0cf965SAdrian Hunter if (map == NULL) 12018e0cf965SAdrian Hunter return -ENOMEM; 12028e0cf965SAdrian Hunter 12038e0cf965SAdrian Hunter map->end = map->start + len; 12048e0cf965SAdrian Hunter map->pgoff = pgoff; 12058e0cf965SAdrian Hunter 12068e0cf965SAdrian Hunter list_add(&map->node, &md->maps); 12078e0cf965SAdrian Hunter 12088e0cf965SAdrian Hunter return 0; 12098e0cf965SAdrian Hunter } 12108e0cf965SAdrian Hunter 1211fb5a88d4SJiri Olsa /* 121279b6bb73SArnaldo Carvalho de Melo * Merges map into maps by splitting the new map within the existing map 121379b6bb73SArnaldo Carvalho de Melo * regions. 1214fb5a88d4SJiri Olsa */ 121579b6bb73SArnaldo Carvalho de Melo int maps__merge_in(struct maps *kmaps, struct map *new_map) 1216fb5a88d4SJiri Olsa { 1217fb5a88d4SJiri Olsa struct map *old_map; 1218fb5a88d4SJiri Olsa LIST_HEAD(merged); 1219fb5a88d4SJiri Olsa 122079b6bb73SArnaldo Carvalho de Melo maps__for_each_entry(kmaps, old_map) { 1221fb5a88d4SJiri Olsa /* no overload with this one */ 1222fb5a88d4SJiri Olsa if (new_map->end < old_map->start || 1223fb5a88d4SJiri Olsa new_map->start >= old_map->end) 1224fb5a88d4SJiri Olsa continue; 1225fb5a88d4SJiri Olsa 1226fb5a88d4SJiri Olsa if (new_map->start < old_map->start) { 1227fb5a88d4SJiri Olsa /* 1228fb5a88d4SJiri Olsa * |new...... 1229fb5a88d4SJiri Olsa * |old.... 1230fb5a88d4SJiri Olsa */ 1231fb5a88d4SJiri Olsa if (new_map->end < old_map->end) { 1232fb5a88d4SJiri Olsa /* 1233fb5a88d4SJiri Olsa * |new......| -> |new..| 1234fb5a88d4SJiri Olsa * |old....| -> |old....| 1235fb5a88d4SJiri Olsa */ 1236fb5a88d4SJiri Olsa new_map->end = old_map->start; 1237fb5a88d4SJiri Olsa } else { 1238fb5a88d4SJiri Olsa /* 1239fb5a88d4SJiri Olsa * |new.............| -> |new..| |new..| 1240fb5a88d4SJiri Olsa * |old....| -> |old....| 1241fb5a88d4SJiri Olsa */ 1242fb5a88d4SJiri Olsa struct map *m = map__clone(new_map); 1243fb5a88d4SJiri Olsa 1244fb5a88d4SJiri Olsa if (!m) 1245fb5a88d4SJiri Olsa return -ENOMEM; 1246fb5a88d4SJiri Olsa 1247fb5a88d4SJiri Olsa m->end = old_map->start; 1248fb5a88d4SJiri Olsa list_add_tail(&m->node, &merged); 12490affd0e5SAdrian Hunter new_map->pgoff += old_map->end - new_map->start; 1250fb5a88d4SJiri Olsa new_map->start = old_map->end; 1251fb5a88d4SJiri Olsa } 1252fb5a88d4SJiri Olsa } else { 1253fb5a88d4SJiri Olsa /* 1254fb5a88d4SJiri Olsa * |new...... 1255fb5a88d4SJiri Olsa * |old.... 1256fb5a88d4SJiri Olsa */ 1257fb5a88d4SJiri Olsa if (new_map->end < old_map->end) { 1258fb5a88d4SJiri Olsa /* 1259fb5a88d4SJiri Olsa * |new..| -> x 1260fb5a88d4SJiri Olsa * |old.........| -> |old.........| 1261fb5a88d4SJiri Olsa */ 1262fb5a88d4SJiri Olsa map__put(new_map); 1263fb5a88d4SJiri Olsa new_map = NULL; 1264fb5a88d4SJiri Olsa break; 1265fb5a88d4SJiri Olsa } else { 1266fb5a88d4SJiri Olsa /* 1267fb5a88d4SJiri Olsa * |new......| -> |new...| 1268fb5a88d4SJiri Olsa * |old....| -> |old....| 1269fb5a88d4SJiri Olsa */ 12700affd0e5SAdrian Hunter new_map->pgoff += old_map->end - new_map->start; 1271fb5a88d4SJiri Olsa new_map->start = old_map->end; 1272fb5a88d4SJiri Olsa } 1273fb5a88d4SJiri Olsa } 1274fb5a88d4SJiri Olsa } 1275fb5a88d4SJiri Olsa 1276fb5a88d4SJiri Olsa while (!list_empty(&merged)) { 1277fb5a88d4SJiri Olsa old_map = list_entry(merged.next, struct map, node); 1278fb5a88d4SJiri Olsa list_del_init(&old_map->node); 127979b6bb73SArnaldo Carvalho de Melo maps__insert(kmaps, old_map); 1280fb5a88d4SJiri Olsa map__put(old_map); 1281fb5a88d4SJiri Olsa } 1282fb5a88d4SJiri Olsa 1283fb5a88d4SJiri Olsa if (new_map) { 128479b6bb73SArnaldo Carvalho de Melo maps__insert(kmaps, new_map); 1285fb5a88d4SJiri Olsa map__put(new_map); 1286fb5a88d4SJiri Olsa } 1287fb5a88d4SJiri Olsa return 0; 1288fb5a88d4SJiri Olsa } 1289fb5a88d4SJiri Olsa 12908e0cf965SAdrian Hunter static int dso__load_kcore(struct dso *dso, struct map *map, 12918e0cf965SAdrian Hunter const char *kallsyms_filename) 12928e0cf965SAdrian Hunter { 129379b6bb73SArnaldo Carvalho de Melo struct maps *kmaps = map__kmaps(map); 12948e0cf965SAdrian Hunter struct kcore_mapfn_data md; 129550481461SArnaldo Carvalho de Melo struct map *old_map, *new_map, *replacement_map = NULL, *next; 12961c5aae77SAdrian Hunter struct machine *machine; 12978e0cf965SAdrian Hunter bool is_64_bit; 12988e0cf965SAdrian Hunter int err, fd; 12998e0cf965SAdrian Hunter char kcore_filename[PATH_MAX]; 130056549978SAdrian Hunter u64 stext; 13018e0cf965SAdrian Hunter 1302ba92732eSWang Nan if (!kmaps) 1303ba92732eSWang Nan return -EINVAL; 1304ba92732eSWang Nan 13051c5aae77SAdrian Hunter machine = kmaps->machine; 13061c5aae77SAdrian Hunter 13078e0cf965SAdrian Hunter /* This function requires that the map is the kernel map */ 1308efdd5c6bSArnaldo Carvalho de Melo if (!__map__is_kernel(map)) 13098e0cf965SAdrian Hunter return -EINVAL; 13108e0cf965SAdrian Hunter 131152afdaf9SAdrian Hunter if (!filename_from_kallsyms_filename(kcore_filename, "kcore", 13128e0cf965SAdrian Hunter kallsyms_filename)) 13138e0cf965SAdrian Hunter return -EINVAL; 13148e0cf965SAdrian Hunter 1315a00d28cbSAdrian Hunter /* Modules and kernel must be present at their original addresses */ 1316a00d28cbSAdrian Hunter if (validate_kcore_addresses(kallsyms_filename, map)) 131752afdaf9SAdrian Hunter return -EINVAL; 131852afdaf9SAdrian Hunter 13198e0cf965SAdrian Hunter md.dso = dso; 13208e0cf965SAdrian Hunter INIT_LIST_HEAD(&md.maps); 13218e0cf965SAdrian Hunter 13228e0cf965SAdrian Hunter fd = open(kcore_filename, O_RDONLY); 132336c8bb56SLi Zhang if (fd < 0) { 1324133de940SAdrian Hunter pr_debug("Failed to open %s. Note /proc/kcore requires CAP_SYS_RAWIO capability to access.\n", 132536c8bb56SLi Zhang kcore_filename); 13268e0cf965SAdrian Hunter return -EINVAL; 132736c8bb56SLi Zhang } 13288e0cf965SAdrian Hunter 13298e0cf965SAdrian Hunter /* Read new maps into temporary lists */ 1330e9814df8SArnaldo Carvalho de Melo err = file__read_maps(fd, map->prot & PROT_EXEC, kcore_mapfn, &md, 13318e0cf965SAdrian Hunter &is_64_bit); 13328e0cf965SAdrian Hunter if (err) 13338e0cf965SAdrian Hunter goto out_err; 1334c6d8f2a4SAdrian Hunter dso->is_64_bit = is_64_bit; 13358e0cf965SAdrian Hunter 13368e0cf965SAdrian Hunter if (list_empty(&md.maps)) { 13378e0cf965SAdrian Hunter err = -EINVAL; 13388e0cf965SAdrian Hunter goto out_err; 13398e0cf965SAdrian Hunter } 13408e0cf965SAdrian Hunter 13418e0cf965SAdrian Hunter /* Remove old maps */ 134279b6bb73SArnaldo Carvalho de Melo maps__for_each_entry_safe(kmaps, old_map, next) { 1343fb5a88d4SJiri Olsa /* 1344fb5a88d4SJiri Olsa * We need to preserve eBPF maps even if they are 1345fb5a88d4SJiri Olsa * covered by kcore, because we need to access 1346fb5a88d4SJiri Olsa * eBPF dso for source data. 1347fb5a88d4SJiri Olsa */ 1348fb5a88d4SJiri Olsa if (old_map != map && !__map__is_bpf_prog(old_map)) 134979b6bb73SArnaldo Carvalho de Melo maps__remove(kmaps, old_map); 13508e0cf965SAdrian Hunter } 13511c5aae77SAdrian Hunter machine->trampolines_mapped = false; 13528e0cf965SAdrian Hunter 135356549978SAdrian Hunter /* Find the kernel map using the '_stext' symbol */ 135456549978SAdrian Hunter if (!kallsyms__get_function_start(kallsyms_filename, "_stext", &stext)) { 13558e0cf965SAdrian Hunter list_for_each_entry(new_map, &md.maps, node) { 135656549978SAdrian Hunter if (stext >= new_map->start && stext < new_map->end) { 13578e0cf965SAdrian Hunter replacement_map = new_map; 13588e0cf965SAdrian Hunter break; 13598e0cf965SAdrian Hunter } 13608e0cf965SAdrian Hunter } 136156549978SAdrian Hunter } 13628e0cf965SAdrian Hunter 13638e0cf965SAdrian Hunter if (!replacement_map) 13648e0cf965SAdrian Hunter replacement_map = list_entry(md.maps.next, struct map, node); 13658e0cf965SAdrian Hunter 13668e0cf965SAdrian Hunter /* Add new maps */ 13678e0cf965SAdrian Hunter while (!list_empty(&md.maps)) { 13688e0cf965SAdrian Hunter new_map = list_entry(md.maps.next, struct map, node); 1369facf3f06SArnaldo Carvalho de Melo list_del_init(&new_map->node); 13708e0cf965SAdrian Hunter if (new_map == replacement_map) { 13718e0cf965SAdrian Hunter map->start = new_map->start; 13728e0cf965SAdrian Hunter map->end = new_map->end; 13738e0cf965SAdrian Hunter map->pgoff = new_map->pgoff; 13748e0cf965SAdrian Hunter map->map_ip = new_map->map_ip; 13758e0cf965SAdrian Hunter map->unmap_ip = new_map->unmap_ip; 13768e0cf965SAdrian Hunter /* Ensure maps are correctly ordered */ 137784c2cafaSArnaldo Carvalho de Melo map__get(map); 137879b6bb73SArnaldo Carvalho de Melo maps__remove(kmaps, map); 137979b6bb73SArnaldo Carvalho de Melo maps__insert(kmaps, map); 138084c2cafaSArnaldo Carvalho de Melo map__put(map); 138184c2cafaSArnaldo Carvalho de Melo map__put(new_map); 1382fb5a88d4SJiri Olsa } else { 1383fb5a88d4SJiri Olsa /* 1384fb5a88d4SJiri Olsa * Merge kcore map into existing maps, 1385fb5a88d4SJiri Olsa * and ensure that current maps (eBPF) 1386fb5a88d4SJiri Olsa * stay intact. 1387fb5a88d4SJiri Olsa */ 138879b6bb73SArnaldo Carvalho de Melo if (maps__merge_in(kmaps, new_map)) 1389fb5a88d4SJiri Olsa goto out_err; 1390fb5a88d4SJiri Olsa } 13918e0cf965SAdrian Hunter } 13928e0cf965SAdrian Hunter 13931c5aae77SAdrian Hunter if (machine__is(machine, "x86_64")) { 13941c5aae77SAdrian Hunter u64 addr; 13951c5aae77SAdrian Hunter 13961c5aae77SAdrian Hunter /* 13971c5aae77SAdrian Hunter * If one of the corresponding symbols is there, assume the 13981c5aae77SAdrian Hunter * entry trampoline maps are too. 13991c5aae77SAdrian Hunter */ 14001c5aae77SAdrian Hunter if (!kallsyms__get_function_start(kallsyms_filename, 14011c5aae77SAdrian Hunter ENTRY_TRAMPOLINE_NAME, 14021c5aae77SAdrian Hunter &addr)) 14031c5aae77SAdrian Hunter machine->trampolines_mapped = true; 14041c5aae77SAdrian Hunter } 14051c5aae77SAdrian Hunter 14068e0cf965SAdrian Hunter /* 14078e0cf965SAdrian Hunter * Set the data type and long name so that kcore can be read via 14088e0cf965SAdrian Hunter * dso__data_read_addr(). 14098e0cf965SAdrian Hunter */ 14101c695c88SJiri Olsa if (dso->kernel == DSO_SPACE__KERNEL_GUEST) 14115f70619dSArnaldo Carvalho de Melo dso->binary_type = DSO_BINARY_TYPE__GUEST_KCORE; 14128e0cf965SAdrian Hunter else 14135f70619dSArnaldo Carvalho de Melo dso->binary_type = DSO_BINARY_TYPE__KCORE; 14147e155d4dSArnaldo Carvalho de Melo dso__set_long_name(dso, strdup(kcore_filename), true); 14158e0cf965SAdrian Hunter 14168e0cf965SAdrian Hunter close(fd); 14178e0cf965SAdrian Hunter 1418e9814df8SArnaldo Carvalho de Melo if (map->prot & PROT_EXEC) 14198e0cf965SAdrian Hunter pr_debug("Using %s for kernel object code\n", kcore_filename); 14208e0cf965SAdrian Hunter else 14218e0cf965SAdrian Hunter pr_debug("Using %s for kernel data\n", kcore_filename); 14228e0cf965SAdrian Hunter 14238e0cf965SAdrian Hunter return 0; 14248e0cf965SAdrian Hunter 14258e0cf965SAdrian Hunter out_err: 14268e0cf965SAdrian Hunter while (!list_empty(&md.maps)) { 14278e0cf965SAdrian Hunter map = list_entry(md.maps.next, struct map, node); 1428facf3f06SArnaldo Carvalho de Melo list_del_init(&map->node); 142984c2cafaSArnaldo Carvalho de Melo map__put(map); 14308e0cf965SAdrian Hunter } 14318e0cf965SAdrian Hunter close(fd); 14328e0cf965SAdrian Hunter return -EINVAL; 14338e0cf965SAdrian Hunter } 14348e0cf965SAdrian Hunter 1435d9b62abaSAdrian Hunter /* 1436d9b62abaSAdrian Hunter * If the kernel is relocated at boot time, kallsyms won't match. Compute the 1437d9b62abaSAdrian Hunter * delta based on the relocation reference symbol. 1438d9b62abaSAdrian Hunter */ 1439019c6820SArnaldo Carvalho de Melo static int kallsyms__delta(struct kmap *kmap, const char *filename, u64 *delta) 1440d9b62abaSAdrian Hunter { 1441d9b62abaSAdrian Hunter u64 addr; 1442d9b62abaSAdrian Hunter 1443d9b62abaSAdrian Hunter if (!kmap->ref_reloc_sym || !kmap->ref_reloc_sym->name) 1444d9b62abaSAdrian Hunter return 0; 1445d9b62abaSAdrian Hunter 1446b843f62aSArnaldo Carvalho de Melo if (kallsyms__get_function_start(filename, kmap->ref_reloc_sym->name, &addr)) 1447d9b62abaSAdrian Hunter return -1; 1448d9b62abaSAdrian Hunter 1449d9b62abaSAdrian Hunter *delta = addr - kmap->ref_reloc_sym->addr; 1450d9b62abaSAdrian Hunter return 0; 1451d9b62abaSAdrian Hunter } 1452d9b62abaSAdrian Hunter 1453e02092b9SArnaldo Carvalho de Melo int __dso__load_kallsyms(struct dso *dso, const char *filename, 1454be39db9fSArnaldo Carvalho de Melo struct map *map, bool no_kcore) 14552e538c4aSArnaldo Carvalho de Melo { 1456019c6820SArnaldo Carvalho de Melo struct kmap *kmap = map__kmap(map); 1457d9b62abaSAdrian Hunter u64 delta = 0; 1458d9b62abaSAdrian Hunter 1459ec80fde7SArnaldo Carvalho de Melo if (symbol__restricted_filename(filename, "/proc/kallsyms")) 1460ec80fde7SArnaldo Carvalho de Melo return -1; 1461ec80fde7SArnaldo Carvalho de Melo 1462019c6820SArnaldo Carvalho de Melo if (!kmap || !kmap->kmaps) 1463019c6820SArnaldo Carvalho de Melo return -1; 1464019c6820SArnaldo Carvalho de Melo 1465333cc76cSArnaldo Carvalho de Melo if (dso__load_all_kallsyms(dso, filename) < 0) 14662e538c4aSArnaldo Carvalho de Melo return -1; 14672e538c4aSArnaldo Carvalho de Melo 1468019c6820SArnaldo Carvalho de Melo if (kallsyms__delta(kmap, filename, &delta)) 1469d9b62abaSAdrian Hunter return -1; 1470d9b62abaSAdrian Hunter 1471*838425f2SNamhyung Kim symbols__fixup_end(&dso->symbols, true); 14723183f8caSArnaldo Carvalho de Melo symbols__fixup_duplicate(&dso->symbols); 14733f5a4272SAnton Blanchard 14741c695c88SJiri Olsa if (dso->kernel == DSO_SPACE__KERNEL_GUEST) 147544f24cb3SJiri Olsa dso->symtab_type = DSO_BINARY_TYPE__GUEST_KALLSYMS; 1476a1645ce1SZhang, Yanmin else 147744f24cb3SJiri Olsa dso->symtab_type = DSO_BINARY_TYPE__KALLSYMS; 14782e538c4aSArnaldo Carvalho de Melo 1479e02092b9SArnaldo Carvalho de Melo if (!no_kcore && !dso__load_kcore(dso, map, filename)) 148079b6bb73SArnaldo Carvalho de Melo return maps__split_kallsyms_for_kcore(kmap->kmaps, dso); 14818e0cf965SAdrian Hunter else 148279b6bb73SArnaldo Carvalho de Melo return maps__split_kallsyms(kmap->kmaps, dso, delta, map); 1483af427bf5SArnaldo Carvalho de Melo } 1484af427bf5SArnaldo Carvalho de Melo 1485e02092b9SArnaldo Carvalho de Melo int dso__load_kallsyms(struct dso *dso, const char *filename, 1486be39db9fSArnaldo Carvalho de Melo struct map *map) 1487e02092b9SArnaldo Carvalho de Melo { 1488be39db9fSArnaldo Carvalho de Melo return __dso__load_kallsyms(dso, filename, map, false); 1489e02092b9SArnaldo Carvalho de Melo } 1490e02092b9SArnaldo Carvalho de Melo 14913183f8caSArnaldo Carvalho de Melo static int dso__load_perf_map(const char *map_path, struct dso *dso) 149280d496beSPekka Enberg { 149380d496beSPekka Enberg char *line = NULL; 149480d496beSPekka Enberg size_t n; 149580d496beSPekka Enberg FILE *file; 149680d496beSPekka Enberg int nr_syms = 0; 149780d496beSPekka Enberg 1498bf2e710bSKrister Johansen file = fopen(map_path, "r"); 149980d496beSPekka Enberg if (file == NULL) 150080d496beSPekka Enberg goto out_failure; 150180d496beSPekka Enberg 150280d496beSPekka Enberg while (!feof(file)) { 15039cffa8d5SPaul Mackerras u64 start, size; 150480d496beSPekka Enberg struct symbol *sym; 150580d496beSPekka Enberg int line_len, len; 150680d496beSPekka Enberg 150780d496beSPekka Enberg line_len = getline(&line, &n, file); 150880d496beSPekka Enberg if (line_len < 0) 150980d496beSPekka Enberg break; 151080d496beSPekka Enberg 151180d496beSPekka Enberg if (!line) 151280d496beSPekka Enberg goto out_failure; 151380d496beSPekka Enberg 151480d496beSPekka Enberg line[--line_len] = '\0'; /* \n */ 151580d496beSPekka Enberg 151680d496beSPekka Enberg len = hex2u64(line, &start); 151780d496beSPekka Enberg 151880d496beSPekka Enberg len++; 151980d496beSPekka Enberg if (len + 2 >= line_len) 152080d496beSPekka Enberg continue; 152180d496beSPekka Enberg 152280d496beSPekka Enberg len += hex2u64(line + len, &size); 152380d496beSPekka Enberg 152480d496beSPekka Enberg len++; 152580d496beSPekka Enberg if (len + 2 >= line_len) 152680d496beSPekka Enberg continue; 152780d496beSPekka Enberg 1528af30bffaSArnaldo Carvalho de Melo sym = symbol__new(start, size, STB_GLOBAL, STT_FUNC, line + len); 152980d496beSPekka Enberg 153080d496beSPekka Enberg if (sym == NULL) 153180d496beSPekka Enberg goto out_delete_line; 153280d496beSPekka Enberg 15333183f8caSArnaldo Carvalho de Melo symbols__insert(&dso->symbols, sym); 153480d496beSPekka Enberg nr_syms++; 153580d496beSPekka Enberg } 153680d496beSPekka Enberg 153780d496beSPekka Enberg free(line); 153880d496beSPekka Enberg fclose(file); 153980d496beSPekka Enberg 154080d496beSPekka Enberg return nr_syms; 154180d496beSPekka Enberg 154280d496beSPekka Enberg out_delete_line: 154380d496beSPekka Enberg free(line); 154480d496beSPekka Enberg out_failure: 154580d496beSPekka Enberg return -1; 154680d496beSPekka Enberg } 154780d496beSPekka Enberg 1548eac9a434SRemi Bernon #ifdef HAVE_LIBBFD_SUPPORT 1549eac9a434SRemi Bernon #define PACKAGE 'perf' 1550eac9a434SRemi Bernon #include <bfd.h> 1551eac9a434SRemi Bernon 1552eac9a434SRemi Bernon static int bfd_symbols__cmpvalue(const void *a, const void *b) 1553eac9a434SRemi Bernon { 1554eac9a434SRemi Bernon const asymbol *as = *(const asymbol **)a, *bs = *(const asymbol **)b; 1555eac9a434SRemi Bernon 1556eac9a434SRemi Bernon if (bfd_asymbol_value(as) != bfd_asymbol_value(bs)) 1557eac9a434SRemi Bernon return bfd_asymbol_value(as) - bfd_asymbol_value(bs); 1558eac9a434SRemi Bernon 1559eac9a434SRemi Bernon return bfd_asymbol_name(as)[0] - bfd_asymbol_name(bs)[0]; 1560eac9a434SRemi Bernon } 1561eac9a434SRemi Bernon 1562eac9a434SRemi Bernon static int bfd2elf_binding(asymbol *symbol) 1563eac9a434SRemi Bernon { 1564eac9a434SRemi Bernon if (symbol->flags & BSF_WEAK) 1565eac9a434SRemi Bernon return STB_WEAK; 1566eac9a434SRemi Bernon if (symbol->flags & BSF_GLOBAL) 1567eac9a434SRemi Bernon return STB_GLOBAL; 1568eac9a434SRemi Bernon if (symbol->flags & BSF_LOCAL) 1569eac9a434SRemi Bernon return STB_LOCAL; 1570eac9a434SRemi Bernon return -1; 1571eac9a434SRemi Bernon } 1572eac9a434SRemi Bernon 1573eac9a434SRemi Bernon int dso__load_bfd_symbols(struct dso *dso, const char *debugfile) 1574eac9a434SRemi Bernon { 1575eac9a434SRemi Bernon int err = -1; 157696de68ffSDmitry Safonov long symbols_size, symbols_count, i; 1577eac9a434SRemi Bernon asection *section; 1578eac9a434SRemi Bernon asymbol **symbols, *sym; 1579eac9a434SRemi Bernon struct symbol *symbol; 1580eac9a434SRemi Bernon bfd *abfd; 1581eac9a434SRemi Bernon u64 start, len; 1582eac9a434SRemi Bernon 158300a34234SNicholas Fraser abfd = bfd_openr(debugfile, NULL); 1584eac9a434SRemi Bernon if (!abfd) 1585eac9a434SRemi Bernon return -1; 1586eac9a434SRemi Bernon 1587eac9a434SRemi Bernon if (!bfd_check_format(abfd, bfd_object)) { 1588eac9a434SRemi Bernon pr_debug2("%s: cannot read %s bfd file.\n", __func__, 1589eac9a434SRemi Bernon dso->long_name); 1590eac9a434SRemi Bernon goto out_close; 1591eac9a434SRemi Bernon } 1592eac9a434SRemi Bernon 1593eac9a434SRemi Bernon if (bfd_get_flavour(abfd) == bfd_target_elf_flavour) 1594eac9a434SRemi Bernon goto out_close; 1595eac9a434SRemi Bernon 1596eac9a434SRemi Bernon symbols_size = bfd_get_symtab_upper_bound(abfd); 1597eac9a434SRemi Bernon if (symbols_size == 0) { 1598eac9a434SRemi Bernon bfd_close(abfd); 1599eac9a434SRemi Bernon return 0; 1600eac9a434SRemi Bernon } 1601eac9a434SRemi Bernon 1602eac9a434SRemi Bernon if (symbols_size < 0) 1603eac9a434SRemi Bernon goto out_close; 1604eac9a434SRemi Bernon 1605eac9a434SRemi Bernon symbols = malloc(symbols_size); 1606eac9a434SRemi Bernon if (!symbols) 1607eac9a434SRemi Bernon goto out_close; 1608eac9a434SRemi Bernon 1609eac9a434SRemi Bernon symbols_count = bfd_canonicalize_symtab(abfd, symbols); 1610eac9a434SRemi Bernon if (symbols_count < 0) 1611eac9a434SRemi Bernon goto out_free; 1612eac9a434SRemi Bernon 1613d2930edeSRemi Bernon section = bfd_get_section_by_name(abfd, ".text"); 1614d2930edeSRemi Bernon if (section) { 1615d2930edeSRemi Bernon for (i = 0; i < symbols_count; ++i) { 1616d2930edeSRemi Bernon if (!strcmp(bfd_asymbol_name(symbols[i]), "__ImageBase") || 1617d2930edeSRemi Bernon !strcmp(bfd_asymbol_name(symbols[i]), "__image_base__")) 1618d2930edeSRemi Bernon break; 1619d2930edeSRemi Bernon } 1620d2930edeSRemi Bernon if (i < symbols_count) { 1621d2930edeSRemi Bernon /* PE symbols can only have 4 bytes, so use .text high bits */ 1622d2930edeSRemi Bernon dso->text_offset = section->vma - (u32)section->vma; 1623d2930edeSRemi Bernon dso->text_offset += (u32)bfd_asymbol_value(symbols[i]); 1624d2930edeSRemi Bernon } else { 1625d2930edeSRemi Bernon dso->text_offset = section->vma - section->filepos; 1626d2930edeSRemi Bernon } 1627d2930edeSRemi Bernon } 1628d2930edeSRemi Bernon 1629eac9a434SRemi Bernon qsort(symbols, symbols_count, sizeof(asymbol *), bfd_symbols__cmpvalue); 1630eac9a434SRemi Bernon 1631eac9a434SRemi Bernon #ifdef bfd_get_section 1632eac9a434SRemi Bernon #define bfd_asymbol_section bfd_get_section 1633eac9a434SRemi Bernon #endif 1634eac9a434SRemi Bernon for (i = 0; i < symbols_count; ++i) { 1635eac9a434SRemi Bernon sym = symbols[i]; 1636eac9a434SRemi Bernon section = bfd_asymbol_section(sym); 1637eac9a434SRemi Bernon if (bfd2elf_binding(sym) < 0) 1638eac9a434SRemi Bernon continue; 1639eac9a434SRemi Bernon 1640eac9a434SRemi Bernon while (i + 1 < symbols_count && 1641eac9a434SRemi Bernon bfd_asymbol_section(symbols[i + 1]) == section && 1642eac9a434SRemi Bernon bfd2elf_binding(symbols[i + 1]) < 0) 1643eac9a434SRemi Bernon i++; 1644eac9a434SRemi Bernon 1645eac9a434SRemi Bernon if (i + 1 < symbols_count && 1646eac9a434SRemi Bernon bfd_asymbol_section(symbols[i + 1]) == section) 1647eac9a434SRemi Bernon len = symbols[i + 1]->value - sym->value; 1648eac9a434SRemi Bernon else 1649eac9a434SRemi Bernon len = section->size - sym->value; 1650eac9a434SRemi Bernon 1651eac9a434SRemi Bernon start = bfd_asymbol_value(sym) - dso->text_offset; 1652eac9a434SRemi Bernon symbol = symbol__new(start, len, bfd2elf_binding(sym), STT_FUNC, 1653eac9a434SRemi Bernon bfd_asymbol_name(sym)); 1654eac9a434SRemi Bernon if (!symbol) 1655eac9a434SRemi Bernon goto out_free; 1656eac9a434SRemi Bernon 1657eac9a434SRemi Bernon symbols__insert(&dso->symbols, symbol); 1658eac9a434SRemi Bernon } 1659eac9a434SRemi Bernon #ifdef bfd_get_section 1660eac9a434SRemi Bernon #undef bfd_asymbol_section 1661eac9a434SRemi Bernon #endif 1662eac9a434SRemi Bernon 1663*838425f2SNamhyung Kim symbols__fixup_end(&dso->symbols, false); 1664eac9a434SRemi Bernon symbols__fixup_duplicate(&dso->symbols); 1665eac9a434SRemi Bernon dso->adjust_symbols = 1; 1666eac9a434SRemi Bernon 1667eac9a434SRemi Bernon err = 0; 1668eac9a434SRemi Bernon out_free: 1669eac9a434SRemi Bernon free(symbols); 1670eac9a434SRemi Bernon out_close: 1671eac9a434SRemi Bernon bfd_close(abfd); 1672eac9a434SRemi Bernon return err; 1673eac9a434SRemi Bernon } 1674eac9a434SRemi Bernon #endif 1675eac9a434SRemi Bernon 16761029f9feSNamhyung Kim static bool dso__is_compatible_symtab_type(struct dso *dso, bool kmod, 16771029f9feSNamhyung Kim enum dso_binary_type type) 16781029f9feSNamhyung Kim { 16791029f9feSNamhyung Kim switch (type) { 16801029f9feSNamhyung Kim case DSO_BINARY_TYPE__JAVA_JIT: 16811029f9feSNamhyung Kim case DSO_BINARY_TYPE__DEBUGLINK: 16821029f9feSNamhyung Kim case DSO_BINARY_TYPE__SYSTEM_PATH_DSO: 16831029f9feSNamhyung Kim case DSO_BINARY_TYPE__FEDORA_DEBUGINFO: 16841029f9feSNamhyung Kim case DSO_BINARY_TYPE__UBUNTU_DEBUGINFO: 168585afd355SAdrian Hunter case DSO_BINARY_TYPE__MIXEDUP_UBUNTU_DEBUGINFO: 16861029f9feSNamhyung Kim case DSO_BINARY_TYPE__BUILDID_DEBUGINFO: 16871029f9feSNamhyung Kim case DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO: 16881c695c88SJiri Olsa return !kmod && dso->kernel == DSO_SPACE__USER; 16891029f9feSNamhyung Kim 16901029f9feSNamhyung Kim case DSO_BINARY_TYPE__KALLSYMS: 16911029f9feSNamhyung Kim case DSO_BINARY_TYPE__VMLINUX: 16921029f9feSNamhyung Kim case DSO_BINARY_TYPE__KCORE: 16931c695c88SJiri Olsa return dso->kernel == DSO_SPACE__KERNEL; 16941029f9feSNamhyung Kim 16951029f9feSNamhyung Kim case DSO_BINARY_TYPE__GUEST_KALLSYMS: 16961029f9feSNamhyung Kim case DSO_BINARY_TYPE__GUEST_VMLINUX: 16971029f9feSNamhyung Kim case DSO_BINARY_TYPE__GUEST_KCORE: 16981c695c88SJiri Olsa return dso->kernel == DSO_SPACE__KERNEL_GUEST; 16991029f9feSNamhyung Kim 17001029f9feSNamhyung Kim case DSO_BINARY_TYPE__GUEST_KMODULE: 1701c00c48fcSNamhyung Kim case DSO_BINARY_TYPE__GUEST_KMODULE_COMP: 17021029f9feSNamhyung Kim case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE: 1703c00c48fcSNamhyung Kim case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP: 17041029f9feSNamhyung Kim /* 17051029f9feSNamhyung Kim * kernel modules know their symtab type - it's set when 1706a94ab91aSArnaldo Carvalho de Melo * creating a module dso in machine__addnew_module_map(). 17071029f9feSNamhyung Kim */ 17081029f9feSNamhyung Kim return kmod && dso->symtab_type == type; 17091029f9feSNamhyung Kim 17101029f9feSNamhyung Kim case DSO_BINARY_TYPE__BUILD_ID_CACHE: 1711d2396999SKrister Johansen case DSO_BINARY_TYPE__BUILD_ID_CACHE_DEBUGINFO: 17121029f9feSNamhyung Kim return true; 17131029f9feSNamhyung Kim 17149b86d04dSSong Liu case DSO_BINARY_TYPE__BPF_PROG_INFO: 17153c29d448SJiri Olsa case DSO_BINARY_TYPE__BPF_IMAGE: 1716789e2419SAdrian Hunter case DSO_BINARY_TYPE__OOL: 17171029f9feSNamhyung Kim case DSO_BINARY_TYPE__NOT_FOUND: 17181029f9feSNamhyung Kim default: 17191029f9feSNamhyung Kim return false; 17201029f9feSNamhyung Kim } 17211029f9feSNamhyung Kim } 17221029f9feSNamhyung Kim 1723bf2e710bSKrister Johansen /* Checks for the existence of the perf-<pid>.map file in two different 1724bf2e710bSKrister Johansen * locations. First, if the process is a separate mount namespace, check in 1725bf2e710bSKrister Johansen * that namespace using the pid of the innermost pid namespace. If's not in a 1726bf2e710bSKrister Johansen * namespace, or the file can't be found there, try in the mount namespace of 1727bf2e710bSKrister Johansen * the tracing process using our view of its pid. 1728bf2e710bSKrister Johansen */ 1729bf2e710bSKrister Johansen static int dso__find_perf_map(char *filebuf, size_t bufsz, 1730bf2e710bSKrister Johansen struct nsinfo **nsip) 1731bf2e710bSKrister Johansen { 1732bf2e710bSKrister Johansen struct nscookie nsc; 1733bf2e710bSKrister Johansen struct nsinfo *nsi; 1734bf2e710bSKrister Johansen struct nsinfo *nnsi; 1735bf2e710bSKrister Johansen int rc = -1; 1736bf2e710bSKrister Johansen 1737bf2e710bSKrister Johansen nsi = *nsip; 1738bf2e710bSKrister Johansen 1739bcaf0a97SIan Rogers if (nsinfo__need_setns(nsi)) { 1740bcaf0a97SIan Rogers snprintf(filebuf, bufsz, "/tmp/perf-%d.map", nsinfo__nstgid(nsi)); 1741bf2e710bSKrister Johansen nsinfo__mountns_enter(nsi, &nsc); 1742bf2e710bSKrister Johansen rc = access(filebuf, R_OK); 1743bf2e710bSKrister Johansen nsinfo__mountns_exit(&nsc); 1744bf2e710bSKrister Johansen if (rc == 0) 1745bf2e710bSKrister Johansen return rc; 1746bf2e710bSKrister Johansen } 1747bf2e710bSKrister Johansen 1748bf2e710bSKrister Johansen nnsi = nsinfo__copy(nsi); 1749bf2e710bSKrister Johansen if (nnsi) { 1750bf2e710bSKrister Johansen nsinfo__put(nsi); 1751bf2e710bSKrister Johansen 1752bcaf0a97SIan Rogers nsinfo__clear_need_setns(nnsi); 1753bcaf0a97SIan Rogers snprintf(filebuf, bufsz, "/tmp/perf-%d.map", nsinfo__tgid(nnsi)); 1754bf2e710bSKrister Johansen *nsip = nnsi; 1755bf2e710bSKrister Johansen rc = 0; 1756bf2e710bSKrister Johansen } 1757bf2e710bSKrister Johansen 1758bf2e710bSKrister Johansen return rc; 1759bf2e710bSKrister Johansen } 1760bf2e710bSKrister Johansen 1761be39db9fSArnaldo Carvalho de Melo int dso__load(struct dso *dso, struct map *map) 176286470930SIngo Molnar { 1763c338aee8SArnaldo Carvalho de Melo char *name; 176486470930SIngo Molnar int ret = -1; 176544f24cb3SJiri Olsa u_int i; 176693fcce96SArnaldo Carvalho de Melo struct machine *machine = NULL; 176744f24cb3SJiri Olsa char *root_dir = (char *) ""; 17683aafe5aeSCody P Schafer int ss_pos = 0; 17693aafe5aeSCody P Schafer struct symsrc ss_[2]; 17703aafe5aeSCody P Schafer struct symsrc *syms_ss = NULL, *runtime_ss = NULL; 17711029f9feSNamhyung Kim bool kmod; 1772bf2e710bSKrister Johansen bool perfmap; 1773f766819cSJiri Olsa struct build_id bid; 1774843ff37bSKrister Johansen struct nscookie nsc; 1775bf2e710bSKrister Johansen char newmapname[PATH_MAX]; 1776bf2e710bSKrister Johansen const char *map_path = dso->long_name; 1777bf2e710bSKrister Johansen 1778bf2e710bSKrister Johansen perfmap = strncmp(dso->name, "/tmp/perf-", 10) == 0; 1779bf2e710bSKrister Johansen if (perfmap) { 1780bf2e710bSKrister Johansen if (dso->nsinfo && (dso__find_perf_map(newmapname, 1781bf2e710bSKrister Johansen sizeof(newmapname), &dso->nsinfo) == 0)) { 1782bf2e710bSKrister Johansen map_path = newmapname; 1783bf2e710bSKrister Johansen } 1784bf2e710bSKrister Johansen } 178586470930SIngo Molnar 1786843ff37bSKrister Johansen nsinfo__mountns_enter(dso->nsinfo, &nsc); 17874a936edcSNamhyung Kim pthread_mutex_lock(&dso->lock); 178866bd8424SArnaldo Carvalho de Melo 17894a936edcSNamhyung Kim /* check again under the dso->lock */ 17903183f8caSArnaldo Carvalho de Melo if (dso__loaded(dso)) { 17914a936edcSNamhyung Kim ret = 1; 17924a936edcSNamhyung Kim goto out; 17934a936edcSNamhyung Kim } 17944a936edcSNamhyung Kim 1795b5c09518SArnaldo Carvalho de Melo kmod = dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE || 1796b5c09518SArnaldo Carvalho de Melo dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP || 1797b5c09518SArnaldo Carvalho de Melo dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE || 1798b5c09518SArnaldo Carvalho de Melo dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE_COMP; 1799b5c09518SArnaldo Carvalho de Melo 1800b5c09518SArnaldo Carvalho de Melo if (dso->kernel && !kmod) { 18011c695c88SJiri Olsa if (dso->kernel == DSO_SPACE__KERNEL) 1802be39db9fSArnaldo Carvalho de Melo ret = dso__load_kernel_sym(dso, map); 18031c695c88SJiri Olsa else if (dso->kernel == DSO_SPACE__KERNEL_GUEST) 1804be39db9fSArnaldo Carvalho de Melo ret = dso__load_guest_kernel_sym(dso, map); 18054a936edcSNamhyung Kim 180693fcce96SArnaldo Carvalho de Melo machine = map__kmaps(map)->machine; 18074d99e413SAdrian Hunter if (machine__is(machine, "x86_64")) 18084d99e413SAdrian Hunter machine__map_x86_64_entry_trampolines(machine, dso); 18094a936edcSNamhyung Kim goto out; 18104a936edcSNamhyung Kim } 1811a1645ce1SZhang, Yanmin 1812aeafcbafSArnaldo Carvalho de Melo dso->adjust_symbols = 0; 1813f5812a7aSArnaldo Carvalho de Melo 1814bf2e710bSKrister Johansen if (perfmap) { 18153183f8caSArnaldo Carvalho de Melo ret = dso__load_perf_map(map_path, dso); 181644f24cb3SJiri Olsa dso->symtab_type = ret > 0 ? DSO_BINARY_TYPE__JAVA_JIT : 181744f24cb3SJiri Olsa DSO_BINARY_TYPE__NOT_FOUND; 18184a936edcSNamhyung Kim goto out; 181994cb9e38SArnaldo Carvalho de Melo } 182094cb9e38SArnaldo Carvalho de Melo 182144f24cb3SJiri Olsa if (machine) 182244f24cb3SJiri Olsa root_dir = machine->root_dir; 182344f24cb3SJiri Olsa 1824164c800eSDavid Ahern name = malloc(PATH_MAX); 1825164c800eSDavid Ahern if (!name) 18264a936edcSNamhyung Kim goto out; 1827164c800eSDavid Ahern 18285baecbcdSDima Kogan /* 18295baecbcdSDima Kogan * Read the build id if possible. This is required for 18305baecbcdSDima Kogan * DSO_BINARY_TYPE__BUILDID_DEBUGINFO to work 18315baecbcdSDima Kogan */ 1832ed6c166cSKan Liang if (!dso->has_build_id && 18339b200653SVictor Kamensky is_regular_file(dso->long_name)) { 18349b200653SVictor Kamensky __symbol__join_symfs(name, PATH_MAX, dso->long_name); 1835f766819cSJiri Olsa if (filename__read_build_id(name, &bid) > 0) 18368dfdf440SJiri Olsa dso__set_build_id(dso, &bid); 18379b200653SVictor Kamensky } 18385baecbcdSDima Kogan 18391029f9feSNamhyung Kim /* 18401029f9feSNamhyung Kim * Iterate over candidate debug images. 18413aafe5aeSCody P Schafer * Keep track of "interesting" ones (those which have a symtab, dynsym, 18423aafe5aeSCody P Schafer * and/or opd section) for processing. 18436da80ce8SDave Martin */ 184444f24cb3SJiri Olsa for (i = 0; i < DSO_BINARY_TYPE__SYMTAB_CNT; i++) { 18453aafe5aeSCody P Schafer struct symsrc *ss = &ss_[ss_pos]; 18463aafe5aeSCody P Schafer bool next_slot = false; 1847f045b8c4SKrister Johansen bool is_reg; 1848d2396999SKrister Johansen bool nsexit; 1849eac9a434SRemi Bernon int bfdrc = -1; 1850c3962961SJiri Olsa int sirc = -1; 185144f24cb3SJiri Olsa 1852005f9294SCody P Schafer enum dso_binary_type symtab_type = binary_type_symtab[i]; 185344f24cb3SJiri Olsa 1854d2396999SKrister Johansen nsexit = (symtab_type == DSO_BINARY_TYPE__BUILD_ID_CACHE || 1855d2396999SKrister Johansen symtab_type == DSO_BINARY_TYPE__BUILD_ID_CACHE_DEBUGINFO); 1856d2396999SKrister Johansen 18571029f9feSNamhyung Kim if (!dso__is_compatible_symtab_type(dso, kmod, symtab_type)) 18581029f9feSNamhyung Kim continue; 18591029f9feSNamhyung Kim 1860ee4e9625SArnaldo Carvalho de Melo if (dso__read_binary_type_filename(dso, symtab_type, 186144f24cb3SJiri Olsa root_dir, name, PATH_MAX)) 18626da80ce8SDave Martin continue; 186386470930SIngo Molnar 1864d2396999SKrister Johansen if (nsexit) 1865f045b8c4SKrister Johansen nsinfo__mountns_exit(&nsc); 186640356721SJiri Olsa 1867f045b8c4SKrister Johansen is_reg = is_regular_file(name); 186867fd1892SNamhyung Kim if (!is_reg && errno == ENOENT && dso->nsinfo) { 186967fd1892SNamhyung Kim char *new_name = filename_with_chroot(dso->nsinfo->pid, 187067fd1892SNamhyung Kim name); 187167fd1892SNamhyung Kim if (new_name) { 187267fd1892SNamhyung Kim is_reg = is_regular_file(new_name); 187367fd1892SNamhyung Kim strlcpy(name, new_name, PATH_MAX); 187467fd1892SNamhyung Kim free(new_name); 187567fd1892SNamhyung Kim } 187667fd1892SNamhyung Kim } 187767fd1892SNamhyung Kim 1878eac9a434SRemi Bernon #ifdef HAVE_LIBBFD_SUPPORT 1879c3962961SJiri Olsa if (is_reg) 1880eac9a434SRemi Bernon bfdrc = dso__load_bfd_symbols(dso, name); 1881eac9a434SRemi Bernon #endif 1882eac9a434SRemi Bernon if (is_reg && bfdrc < 0) 1883f045b8c4SKrister Johansen sirc = symsrc__init(ss, dso, name, symtab_type); 1884f045b8c4SKrister Johansen 1885d2396999SKrister Johansen if (nsexit) 1886f045b8c4SKrister Johansen nsinfo__mountns_enter(dso->nsinfo, &nsc); 1887f045b8c4SKrister Johansen 188877771a97SNicholas Fraser if (bfdrc == 0) { 188977771a97SNicholas Fraser ret = 0; 1890eac9a434SRemi Bernon break; 189177771a97SNicholas Fraser } 1892eac9a434SRemi Bernon 1893c3962961SJiri Olsa if (!is_reg || sirc < 0) 18946da80ce8SDave Martin continue; 18956da80ce8SDave Martin 18963aafe5aeSCody P Schafer if (!syms_ss && symsrc__has_symtab(ss)) { 18973aafe5aeSCody P Schafer syms_ss = ss; 18983aafe5aeSCody P Schafer next_slot = true; 18990058aef6SAdrian Hunter if (!dso->symsrc_filename) 19000058aef6SAdrian Hunter dso->symsrc_filename = strdup(name); 1901d26cd12bSCody P Schafer } 1902d26cd12bSCody P Schafer 19033aafe5aeSCody P Schafer if (!runtime_ss && symsrc__possibly_runtime(ss)) { 19043aafe5aeSCody P Schafer runtime_ss = ss; 19053aafe5aeSCody P Schafer next_slot = true; 1906a44f605bSCody P Schafer } 190786470930SIngo Molnar 19083aafe5aeSCody P Schafer if (next_slot) { 19093aafe5aeSCody P Schafer ss_pos++; 191033ff581eSJiri Olsa 19113aafe5aeSCody P Schafer if (syms_ss && runtime_ss) 19126da80ce8SDave Martin break; 191398e9f03bSNamhyung Kim } else { 191498e9f03bSNamhyung Kim symsrc__destroy(ss); 1915a25e46c4SArnaldo Carvalho de Melo } 19163aafe5aeSCody P Schafer 19176da80ce8SDave Martin } 19186da80ce8SDave Martin 19193aafe5aeSCody P Schafer if (!runtime_ss && !syms_ss) 19203aafe5aeSCody P Schafer goto out_free; 19213aafe5aeSCody P Schafer 19223aafe5aeSCody P Schafer if (runtime_ss && !syms_ss) { 19233aafe5aeSCody P Schafer syms_ss = runtime_ss; 192460e4b10cSArnaldo Carvalho de Melo } 192560e4b10cSArnaldo Carvalho de Melo 19263aafe5aeSCody P Schafer /* We'll have to hope for the best */ 19273aafe5aeSCody P Schafer if (!runtime_ss && syms_ss) 19283aafe5aeSCody P Schafer runtime_ss = syms_ss; 19293aafe5aeSCody P Schafer 19301029f9feSNamhyung Kim if (syms_ss) 1931be39db9fSArnaldo Carvalho de Melo ret = dso__load_sym(dso, map, syms_ss, runtime_ss, kmod); 19321029f9feSNamhyung Kim else 19333aafe5aeSCody P Schafer ret = -1; 19343aafe5aeSCody P Schafer 1935f47b58b7SDavid Ahern if (ret > 0) { 19363aafe5aeSCody P Schafer int nr_plt; 19373aafe5aeSCody P Schafer 19383183f8caSArnaldo Carvalho de Melo nr_plt = dso__synthesize_plt_symbols(dso, runtime_ss); 19393aafe5aeSCody P Schafer if (nr_plt > 0) 19403aafe5aeSCody P Schafer ret += nr_plt; 19413aafe5aeSCody P Schafer } 19423aafe5aeSCody P Schafer 19433aafe5aeSCody P Schafer for (; ss_pos > 0; ss_pos--) 19443aafe5aeSCody P Schafer symsrc__destroy(&ss_[ss_pos - 1]); 19453aafe5aeSCody P Schafer out_free: 194686470930SIngo Molnar free(name); 1947aeafcbafSArnaldo Carvalho de Melo if (ret < 0 && strstr(dso->name, " (deleted)") != NULL) 19484a936edcSNamhyung Kim ret = 0; 19494a936edcSNamhyung Kim out: 19503183f8caSArnaldo Carvalho de Melo dso__set_loaded(dso); 19514a936edcSNamhyung Kim pthread_mutex_unlock(&dso->lock); 1952843ff37bSKrister Johansen nsinfo__mountns_exit(&nsc); 19534a936edcSNamhyung Kim 195486470930SIngo Molnar return ret; 195586470930SIngo Molnar } 195686470930SIngo Molnar 1957a7c2b572SArnaldo Carvalho de Melo static int map__strcmp(const void *a, const void *b) 1958a7c2b572SArnaldo Carvalho de Melo { 1959a7c2b572SArnaldo Carvalho de Melo const struct map *ma = *(const struct map **)a, *mb = *(const struct map **)b; 1960a7c2b572SArnaldo Carvalho de Melo return strcmp(ma->dso->short_name, mb->dso->short_name); 1961a7c2b572SArnaldo Carvalho de Melo } 1962a7c2b572SArnaldo Carvalho de Melo 1963a7c2b572SArnaldo Carvalho de Melo static int map__strcmp_name(const void *name, const void *b) 1964a7c2b572SArnaldo Carvalho de Melo { 1965a7c2b572SArnaldo Carvalho de Melo const struct map *map = *(const struct map **)b; 1966a7c2b572SArnaldo Carvalho de Melo return strcmp(name, map->dso->short_name); 1967a7c2b572SArnaldo Carvalho de Melo } 1968a7c2b572SArnaldo Carvalho de Melo 19699a29ceeeSArnaldo Carvalho de Melo void __maps__sort_by_name(struct maps *maps) 1970a7c2b572SArnaldo Carvalho de Melo { 19719a29ceeeSArnaldo Carvalho de Melo qsort(maps->maps_by_name, maps->nr_maps, sizeof(struct map *), map__strcmp); 1972a7c2b572SArnaldo Carvalho de Melo } 1973a7c2b572SArnaldo Carvalho de Melo 19749a29ceeeSArnaldo Carvalho de Melo static int map__groups__sort_by_name_from_rbtree(struct maps *maps) 1975a7c2b572SArnaldo Carvalho de Melo { 1976a7c2b572SArnaldo Carvalho de Melo struct map *map; 19779a29ceeeSArnaldo Carvalho de Melo struct map **maps_by_name = realloc(maps->maps_by_name, maps->nr_maps * sizeof(map)); 1978a7c2b572SArnaldo Carvalho de Melo int i = 0; 1979a7c2b572SArnaldo Carvalho de Melo 1980a7c2b572SArnaldo Carvalho de Melo if (maps_by_name == NULL) 1981a7c2b572SArnaldo Carvalho de Melo return -1; 1982a7c2b572SArnaldo Carvalho de Melo 19839a29ceeeSArnaldo Carvalho de Melo maps->maps_by_name = maps_by_name; 19849a29ceeeSArnaldo Carvalho de Melo maps->nr_maps_allocated = maps->nr_maps; 1985a7c2b572SArnaldo Carvalho de Melo 19869a29ceeeSArnaldo Carvalho de Melo maps__for_each_entry(maps, map) 1987a7c2b572SArnaldo Carvalho de Melo maps_by_name[i++] = map; 1988a7c2b572SArnaldo Carvalho de Melo 19899a29ceeeSArnaldo Carvalho de Melo __maps__sort_by_name(maps); 1990a7c2b572SArnaldo Carvalho de Melo return 0; 1991a7c2b572SArnaldo Carvalho de Melo } 1992a7c2b572SArnaldo Carvalho de Melo 19939a29ceeeSArnaldo Carvalho de Melo static struct map *__maps__find_by_name(struct maps *maps, const char *name) 1994a7c2b572SArnaldo Carvalho de Melo { 1995a7c2b572SArnaldo Carvalho de Melo struct map **mapp; 1996a7c2b572SArnaldo Carvalho de Melo 19979a29ceeeSArnaldo Carvalho de Melo if (maps->maps_by_name == NULL && 19989a29ceeeSArnaldo Carvalho de Melo map__groups__sort_by_name_from_rbtree(maps)) 1999a7c2b572SArnaldo Carvalho de Melo return NULL; 2000a7c2b572SArnaldo Carvalho de Melo 20019a29ceeeSArnaldo Carvalho de Melo mapp = bsearch(name, maps->maps_by_name, maps->nr_maps, sizeof(*mapp), map__strcmp_name); 2002a7c2b572SArnaldo Carvalho de Melo if (mapp) 2003a7c2b572SArnaldo Carvalho de Melo return *mapp; 2004a7c2b572SArnaldo Carvalho de Melo return NULL; 2005a7c2b572SArnaldo Carvalho de Melo } 2006a7c2b572SArnaldo Carvalho de Melo 20079a29ceeeSArnaldo Carvalho de Melo struct map *maps__find_by_name(struct maps *maps, const char *name) 2008439d473bSArnaldo Carvalho de Melo { 20094bb7123dSArnaldo Carvalho de Melo struct map *map; 2010439d473bSArnaldo Carvalho de Melo 20110a7c74eaSArnaldo Carvalho de Melo down_read(&maps->lock); 20126a2ffcddSArnaldo Carvalho de Melo 20139a29ceeeSArnaldo Carvalho de Melo if (maps->last_search_by_name && strcmp(maps->last_search_by_name->dso->short_name, name) == 0) { 20149a29ceeeSArnaldo Carvalho de Melo map = maps->last_search_by_name; 20156a2ffcddSArnaldo Carvalho de Melo goto out_unlock; 20161ae14516SArnaldo Carvalho de Melo } 2017a7c2b572SArnaldo Carvalho de Melo /* 20189a29ceeeSArnaldo Carvalho de Melo * If we have maps->maps_by_name, then the name isn't in the rbtree, 20199a29ceeeSArnaldo Carvalho de Melo * as maps->maps_by_name mirrors the rbtree when lookups by name are 2020a7c2b572SArnaldo Carvalho de Melo * made. 2021a7c2b572SArnaldo Carvalho de Melo */ 20229a29ceeeSArnaldo Carvalho de Melo map = __maps__find_by_name(maps, name); 20239a29ceeeSArnaldo Carvalho de Melo if (map || maps->maps_by_name != NULL) 2024a7c2b572SArnaldo Carvalho de Melo goto out_unlock; 20251ae14516SArnaldo Carvalho de Melo 2026a7c2b572SArnaldo Carvalho de Melo /* Fallback to traversing the rbtree... */ 20271ae14516SArnaldo Carvalho de Melo maps__for_each_entry(maps, map) 20281ae14516SArnaldo Carvalho de Melo if (strcmp(map->dso->short_name, name) == 0) { 20299a29ceeeSArnaldo Carvalho de Melo maps->last_search_by_name = map; 20301ae14516SArnaldo Carvalho de Melo goto out_unlock; 20311ae14516SArnaldo Carvalho de Melo } 2032439d473bSArnaldo Carvalho de Melo 20336a2ffcddSArnaldo Carvalho de Melo map = NULL; 20346a2ffcddSArnaldo Carvalho de Melo 20356a2ffcddSArnaldo Carvalho de Melo out_unlock: 20360a7c74eaSArnaldo Carvalho de Melo up_read(&maps->lock); 20376a2ffcddSArnaldo Carvalho de Melo return map; 2038439d473bSArnaldo Carvalho de Melo } 2039439d473bSArnaldo Carvalho de Melo 2040aeafcbafSArnaldo Carvalho de Melo int dso__load_vmlinux(struct dso *dso, struct map *map, 2041be39db9fSArnaldo Carvalho de Melo const char *vmlinux, bool vmlinux_allocated) 204286470930SIngo Molnar { 2043b68e2f91SCody P Schafer int err = -1; 2044b68e2f91SCody P Schafer struct symsrc ss; 2045ec5761eaSDavid Ahern char symfs_vmlinux[PATH_MAX]; 2046005f9294SCody P Schafer enum dso_binary_type symtab_type; 204786470930SIngo Molnar 20485698d2c9SNamhyung Kim if (vmlinux[0] == '/') 20495698d2c9SNamhyung Kim snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s", vmlinux); 20505698d2c9SNamhyung Kim else 2051972f393bSArnaldo Carvalho de Melo symbol__join_symfs(symfs_vmlinux, vmlinux); 205286470930SIngo Molnar 20531c695c88SJiri Olsa if (dso->kernel == DSO_SPACE__KERNEL_GUEST) 2054005f9294SCody P Schafer symtab_type = DSO_BINARY_TYPE__GUEST_VMLINUX; 205521ea4539SCody P Schafer else 2056005f9294SCody P Schafer symtab_type = DSO_BINARY_TYPE__VMLINUX; 205721ea4539SCody P Schafer 2058005f9294SCody P Schafer if (symsrc__init(&ss, dso, symfs_vmlinux, symtab_type)) 2059b68e2f91SCody P Schafer return -1; 2060b68e2f91SCody P Schafer 2061be39db9fSArnaldo Carvalho de Melo err = dso__load_sym(dso, map, &ss, &ss, 0); 2062b68e2f91SCody P Schafer symsrc__destroy(&ss); 206386470930SIngo Molnar 2064515850e4SCody P Schafer if (err > 0) { 20651c695c88SJiri Olsa if (dso->kernel == DSO_SPACE__KERNEL_GUEST) 20665f70619dSArnaldo Carvalho de Melo dso->binary_type = DSO_BINARY_TYPE__GUEST_VMLINUX; 206739b12f78SAdrian Hunter else 20685f70619dSArnaldo Carvalho de Melo dso->binary_type = DSO_BINARY_TYPE__VMLINUX; 2069bf4414aeSArnaldo Carvalho de Melo dso__set_long_name(dso, vmlinux, vmlinux_allocated); 20703183f8caSArnaldo Carvalho de Melo dso__set_loaded(dso); 2071ec5761eaSDavid Ahern pr_debug("Using %s for symbols\n", symfs_vmlinux); 2072515850e4SCody P Schafer } 20733846df2eSArnaldo Carvalho de Melo 207486470930SIngo Molnar return err; 207586470930SIngo Molnar } 207686470930SIngo Molnar 2077be39db9fSArnaldo Carvalho de Melo int dso__load_vmlinux_path(struct dso *dso, struct map *map) 2078a19afe46SArnaldo Carvalho de Melo { 2079a19afe46SArnaldo Carvalho de Melo int i, err = 0; 208000dc8657SNamhyung Kim char *filename = NULL; 2081a19afe46SArnaldo Carvalho de Melo 2082dc38218eSArnaldo Carvalho de Melo pr_debug("Looking at the vmlinux_path (%d entries long)\n", 2083dc38218eSArnaldo Carvalho de Melo vmlinux_path__nr_entries + 1); 2084dc38218eSArnaldo Carvalho de Melo 2085dc38218eSArnaldo Carvalho de Melo for (i = 0; i < vmlinux_path__nr_entries; ++i) { 2086be39db9fSArnaldo Carvalho de Melo err = dso__load_vmlinux(dso, map, vmlinux_path[i], false); 2087dc38218eSArnaldo Carvalho de Melo if (err > 0) 2088dc38218eSArnaldo Carvalho de Melo goto out; 2089dc38218eSArnaldo Carvalho de Melo } 2090dc38218eSArnaldo Carvalho de Melo 209100dc8657SNamhyung Kim if (!symbol_conf.ignore_vmlinux_buildid) 2092d2396999SKrister Johansen filename = dso__build_id_filename(dso, NULL, 0, false); 20935ad90e4eSArnaldo Carvalho de Melo if (filename != NULL) { 2094be39db9fSArnaldo Carvalho de Melo err = dso__load_vmlinux(dso, map, filename, true); 20955230fb7dSArnaldo Carvalho de Melo if (err > 0) 20965ad90e4eSArnaldo Carvalho de Melo goto out; 20975ad90e4eSArnaldo Carvalho de Melo free(filename); 20985ad90e4eSArnaldo Carvalho de Melo } 20995ad90e4eSArnaldo Carvalho de Melo out: 2100a19afe46SArnaldo Carvalho de Melo return err; 2101a19afe46SArnaldo Carvalho de Melo } 2102a19afe46SArnaldo Carvalho de Melo 2103c48903b8SMasami Hiramatsu static bool visible_dir_filter(const char *name, struct dirent *d) 2104c48903b8SMasami Hiramatsu { 2105c48903b8SMasami Hiramatsu if (d->d_type != DT_DIR) 2106c48903b8SMasami Hiramatsu return false; 2107c48903b8SMasami Hiramatsu return lsdir_no_dot_filter(name, d); 2108c48903b8SMasami Hiramatsu } 2109c48903b8SMasami Hiramatsu 21100544d422SAdrian Hunter static int find_matching_kcore(struct map *map, char *dir, size_t dir_sz) 21110544d422SAdrian Hunter { 21120544d422SAdrian Hunter char kallsyms_filename[PATH_MAX]; 21130544d422SAdrian Hunter int ret = -1; 2114c48903b8SMasami Hiramatsu struct strlist *dirs; 2115c48903b8SMasami Hiramatsu struct str_node *nd; 21160544d422SAdrian Hunter 2117c48903b8SMasami Hiramatsu dirs = lsdir(dir, visible_dir_filter); 2118c48903b8SMasami Hiramatsu if (!dirs) 21190544d422SAdrian Hunter return -1; 21200544d422SAdrian Hunter 2121602a1f4dSArnaldo Carvalho de Melo strlist__for_each_entry(nd, dirs) { 21220544d422SAdrian Hunter scnprintf(kallsyms_filename, sizeof(kallsyms_filename), 2123c48903b8SMasami Hiramatsu "%s/%s/kallsyms", dir, nd->s); 2124a00d28cbSAdrian Hunter if (!validate_kcore_addresses(kallsyms_filename, map)) { 21250544d422SAdrian Hunter strlcpy(dir, kallsyms_filename, dir_sz); 21260544d422SAdrian Hunter ret = 0; 21270544d422SAdrian Hunter break; 21280544d422SAdrian Hunter } 21290544d422SAdrian Hunter } 21300544d422SAdrian Hunter 2131c48903b8SMasami Hiramatsu strlist__delete(dirs); 21320544d422SAdrian Hunter 21330544d422SAdrian Hunter return ret; 21340544d422SAdrian Hunter } 21350544d422SAdrian Hunter 213611870d71SMasami Hiramatsu /* 213711870d71SMasami Hiramatsu * Use open(O_RDONLY) to check readability directly instead of access(R_OK) 213811870d71SMasami Hiramatsu * since access(R_OK) only checks with real UID/GID but open() use effective 213911870d71SMasami Hiramatsu * UID/GID and actual capabilities (e.g. /proc/kcore requires CAP_SYS_RAWIO). 214011870d71SMasami Hiramatsu */ 214111870d71SMasami Hiramatsu static bool filename__readable(const char *file) 214211870d71SMasami Hiramatsu { 214311870d71SMasami Hiramatsu int fd = open(file, O_RDONLY); 214411870d71SMasami Hiramatsu if (fd < 0) 214511870d71SMasami Hiramatsu return false; 214611870d71SMasami Hiramatsu close(fd); 214711870d71SMasami Hiramatsu return true; 214811870d71SMasami Hiramatsu } 214911870d71SMasami Hiramatsu 21500544d422SAdrian Hunter static char *dso__find_kallsyms(struct dso *dso, struct map *map) 21510544d422SAdrian Hunter { 21523ff1b8c8SJiri Olsa struct build_id bid; 2153b5d8bbe8SMasami Hiramatsu char sbuild_id[SBUILD_ID_SIZE]; 21540544d422SAdrian Hunter bool is_host = false; 21550544d422SAdrian Hunter char path[PATH_MAX]; 21560544d422SAdrian Hunter 21570544d422SAdrian Hunter if (!dso->has_build_id) { 21580544d422SAdrian Hunter /* 21590544d422SAdrian Hunter * Last resort, if we don't have a build-id and couldn't find 21600544d422SAdrian Hunter * any vmlinux file, try the running kernel kallsyms table. 21610544d422SAdrian Hunter */ 21620544d422SAdrian Hunter goto proc_kallsyms; 21630544d422SAdrian Hunter } 21640544d422SAdrian Hunter 21653ff1b8c8SJiri Olsa if (sysfs__read_build_id("/sys/kernel/notes", &bid) == 0) 216639be8d01SJiri Olsa is_host = dso__build_id_equal(dso, &bid); 21670544d422SAdrian Hunter 21684e4b6c06SMasami Hiramatsu /* Try a fast path for /proc/kallsyms if possible */ 21690544d422SAdrian Hunter if (is_host) { 21700544d422SAdrian Hunter /* 217111870d71SMasami Hiramatsu * Do not check the build-id cache, unless we know we cannot use 217211870d71SMasami Hiramatsu * /proc/kcore or module maps don't match to /proc/kallsyms. 217311870d71SMasami Hiramatsu * To check readability of /proc/kcore, do not use access(R_OK) 217411870d71SMasami Hiramatsu * since /proc/kcore requires CAP_SYS_RAWIO to read and access 217511870d71SMasami Hiramatsu * can't check it. 21760544d422SAdrian Hunter */ 217711870d71SMasami Hiramatsu if (filename__readable("/proc/kcore") && 217811870d71SMasami Hiramatsu !validate_kcore_addresses("/proc/kallsyms", map)) 21790544d422SAdrian Hunter goto proc_kallsyms; 21800544d422SAdrian Hunter } 21810544d422SAdrian Hunter 2182bf541169SJiri Olsa build_id__sprintf(&dso->bid, sbuild_id); 21834e4b6c06SMasami Hiramatsu 2184449867e3SAdrian Hunter /* Find kallsyms in build-id cache with kcore */ 21854e4b6c06SMasami Hiramatsu scnprintf(path, sizeof(path), "%s/%s/%s", 21864e4b6c06SMasami Hiramatsu buildid_dir, DSO__NAME_KCORE, sbuild_id); 21874e4b6c06SMasami Hiramatsu 2188449867e3SAdrian Hunter if (!find_matching_kcore(map, path, sizeof(path))) 2189449867e3SAdrian Hunter return strdup(path); 2190449867e3SAdrian Hunter 21914e4b6c06SMasami Hiramatsu /* Use current /proc/kallsyms if possible */ 21924e4b6c06SMasami Hiramatsu if (is_host) { 21934e4b6c06SMasami Hiramatsu proc_kallsyms: 21944e4b6c06SMasami Hiramatsu return strdup("/proc/kallsyms"); 21954e4b6c06SMasami Hiramatsu } 21964e4b6c06SMasami Hiramatsu 21974e4b6c06SMasami Hiramatsu /* Finally, find a cache of kallsyms */ 219801412261SMasami Hiramatsu if (!build_id_cache__kallsyms_path(sbuild_id, path, sizeof(path))) { 21990544d422SAdrian Hunter pr_err("No kallsyms or vmlinux with build-id %s was found\n", 22000544d422SAdrian Hunter sbuild_id); 22010544d422SAdrian Hunter return NULL; 22020544d422SAdrian Hunter } 22030544d422SAdrian Hunter 22040544d422SAdrian Hunter return strdup(path); 22050544d422SAdrian Hunter } 22060544d422SAdrian Hunter 2207be39db9fSArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *dso, struct map *map) 220886470930SIngo Molnar { 2209cc612d81SArnaldo Carvalho de Melo int err; 22109e201442SArnaldo Carvalho de Melo const char *kallsyms_filename = NULL; 22119e201442SArnaldo Carvalho de Melo char *kallsyms_allocated_filename = NULL; 2212ca8ea73aSJiri Olsa char *filename = NULL; 2213ca8ea73aSJiri Olsa 2214dc8d6ab2SArnaldo Carvalho de Melo /* 2215b226a5a7SDavid Ahern * Step 1: if the user specified a kallsyms or vmlinux filename, use 2216b226a5a7SDavid Ahern * it and only it, reporting errors to the user if it cannot be used. 2217dc8d6ab2SArnaldo Carvalho de Melo * 2218dc8d6ab2SArnaldo Carvalho de Melo * For instance, try to analyse an ARM perf.data file _without_ a 2219dc8d6ab2SArnaldo Carvalho de Melo * build-id, or if the user specifies the wrong path to the right 2220dc8d6ab2SArnaldo Carvalho de Melo * vmlinux file, obviously we can't fallback to another vmlinux (a 2221dc8d6ab2SArnaldo Carvalho de Melo * x86_86 one, on the machine where analysis is being performed, say), 2222dc8d6ab2SArnaldo Carvalho de Melo * or worse, /proc/kallsyms. 2223dc8d6ab2SArnaldo Carvalho de Melo * 2224dc8d6ab2SArnaldo Carvalho de Melo * If the specified file _has_ a build-id and there is a build-id 2225dc8d6ab2SArnaldo Carvalho de Melo * section in the perf.data file, we will still do the expected 2226dc8d6ab2SArnaldo Carvalho de Melo * validation in dso__load_vmlinux and will bail out if they don't 2227dc8d6ab2SArnaldo Carvalho de Melo * match. 2228dc8d6ab2SArnaldo Carvalho de Melo */ 2229b226a5a7SDavid Ahern if (symbol_conf.kallsyms_name != NULL) { 2230b226a5a7SDavid Ahern kallsyms_filename = symbol_conf.kallsyms_name; 2231b226a5a7SDavid Ahern goto do_kallsyms; 2232b226a5a7SDavid Ahern } 2233b226a5a7SDavid Ahern 2234fc2be696SWilly Tarreau if (!symbol_conf.ignore_vmlinux && symbol_conf.vmlinux_name != NULL) { 2235be39db9fSArnaldo Carvalho de Melo return dso__load_vmlinux(dso, map, symbol_conf.vmlinux_name, false); 2236dc8d6ab2SArnaldo Carvalho de Melo } 2237439d473bSArnaldo Carvalho de Melo 2238ca8ea73aSJiri Olsa /* 2239ca8ea73aSJiri Olsa * Before checking on common vmlinux locations, check if it's 2240ca8ea73aSJiri Olsa * stored as standard build id binary (not kallsyms) under 2241ca8ea73aSJiri Olsa * .debug cache. 2242ca8ea73aSJiri Olsa */ 2243ca8ea73aSJiri Olsa if (!symbol_conf.ignore_vmlinux_buildid) 2244ca8ea73aSJiri Olsa filename = __dso__build_id_filename(dso, NULL, 0, false, false); 2245ca8ea73aSJiri Olsa if (filename != NULL) { 2246ca8ea73aSJiri Olsa err = dso__load_vmlinux(dso, map, filename, true); 2247ca8ea73aSJiri Olsa if (err > 0) 2248ca8ea73aSJiri Olsa return err; 2249ca8ea73aSJiri Olsa free(filename); 2250ca8ea73aSJiri Olsa } 2251ca8ea73aSJiri Olsa 2252fc2be696SWilly Tarreau if (!symbol_conf.ignore_vmlinux && vmlinux_path != NULL) { 2253be39db9fSArnaldo Carvalho de Melo err = dso__load_vmlinux_path(dso, map); 2254a19afe46SArnaldo Carvalho de Melo if (err > 0) 225539b12f78SAdrian Hunter return err; 2256cc612d81SArnaldo Carvalho de Melo } 2257cc612d81SArnaldo Carvalho de Melo 2258ec5761eaSDavid Ahern /* do not try local files if a symfs was given */ 2259ec5761eaSDavid Ahern if (symbol_conf.symfs[0] != 0) 2260ec5761eaSDavid Ahern return -1; 2261ec5761eaSDavid Ahern 22620544d422SAdrian Hunter kallsyms_allocated_filename = dso__find_kallsyms(dso, map); 22630544d422SAdrian Hunter if (!kallsyms_allocated_filename) 22648d0591f6SArnaldo Carvalho de Melo return -1; 22658d0591f6SArnaldo Carvalho de Melo 226619fc2dedSArnaldo Carvalho de Melo kallsyms_filename = kallsyms_allocated_filename; 226719fc2dedSArnaldo Carvalho de Melo 2268dc8d6ab2SArnaldo Carvalho de Melo do_kallsyms: 2269be39db9fSArnaldo Carvalho de Melo err = dso__load_kallsyms(dso, kallsyms_filename, map); 22703846df2eSArnaldo Carvalho de Melo if (err > 0) 22713846df2eSArnaldo Carvalho de Melo pr_debug("Using %s for symbols\n", kallsyms_filename); 2272dc8d6ab2SArnaldo Carvalho de Melo free(kallsyms_allocated_filename); 2273dc8d6ab2SArnaldo Carvalho de Melo 22748e0cf965SAdrian Hunter if (err > 0 && !dso__is_kcore(dso)) { 2275bdac0bcfSAdrian Hunter dso->binary_type = DSO_BINARY_TYPE__KALLSYMS; 22760a77582fSMasami Hiramatsu dso__set_long_name(dso, DSO__NAME_KALLSYMS, false); 22776a4694a4SArnaldo Carvalho de Melo map__fixup_start(map); 22786a4694a4SArnaldo Carvalho de Melo map__fixup_end(map); 2279439d473bSArnaldo Carvalho de Melo } 228094cb9e38SArnaldo Carvalho de Melo 228186470930SIngo Molnar return err; 228286470930SIngo Molnar } 228386470930SIngo Molnar 2284be39db9fSArnaldo Carvalho de Melo static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map) 2285a1645ce1SZhang, Yanmin { 2286a1645ce1SZhang, Yanmin int err; 2287a1645ce1SZhang, Yanmin const char *kallsyms_filename = NULL; 228893fcce96SArnaldo Carvalho de Melo struct machine *machine = map__kmaps(map)->machine; 2289a1645ce1SZhang, Yanmin char path[PATH_MAX]; 2290a1645ce1SZhang, Yanmin 229123346f21SArnaldo Carvalho de Melo if (machine__is_default_guest(machine)) { 2292a1645ce1SZhang, Yanmin /* 2293a1645ce1SZhang, Yanmin * if the user specified a vmlinux filename, use it and only 2294a1645ce1SZhang, Yanmin * it, reporting errors to the user if it cannot be used. 2295a1645ce1SZhang, Yanmin * Or use file guest_kallsyms inputted by user on commandline 2296a1645ce1SZhang, Yanmin */ 2297a1645ce1SZhang, Yanmin if (symbol_conf.default_guest_vmlinux_name != NULL) { 2298aeafcbafSArnaldo Carvalho de Melo err = dso__load_vmlinux(dso, map, 22995230fb7dSArnaldo Carvalho de Melo symbol_conf.default_guest_vmlinux_name, 2300be39db9fSArnaldo Carvalho de Melo false); 230139b12f78SAdrian Hunter return err; 2302a1645ce1SZhang, Yanmin } 2303a1645ce1SZhang, Yanmin 2304a1645ce1SZhang, Yanmin kallsyms_filename = symbol_conf.default_guest_kallsyms; 2305a1645ce1SZhang, Yanmin if (!kallsyms_filename) 2306a1645ce1SZhang, Yanmin return -1; 2307a1645ce1SZhang, Yanmin } else { 230823346f21SArnaldo Carvalho de Melo sprintf(path, "%s/proc/kallsyms", machine->root_dir); 2309a1645ce1SZhang, Yanmin kallsyms_filename = path; 2310a1645ce1SZhang, Yanmin } 2311a1645ce1SZhang, Yanmin 2312be39db9fSArnaldo Carvalho de Melo err = dso__load_kallsyms(dso, kallsyms_filename, map); 23138e0cf965SAdrian Hunter if (err > 0) 231439b12f78SAdrian Hunter pr_debug("Using %s for symbols\n", kallsyms_filename); 23158e0cf965SAdrian Hunter if (err > 0 && !dso__is_kcore(dso)) { 2316bdac0bcfSAdrian Hunter dso->binary_type = DSO_BINARY_TYPE__GUEST_KALLSYMS; 23178c7f1bb3SJiri Olsa dso__set_long_name(dso, machine->mmap_name, false); 2318a1645ce1SZhang, Yanmin map__fixup_start(map); 2319a1645ce1SZhang, Yanmin map__fixup_end(map); 2320a1645ce1SZhang, Yanmin } 2321a1645ce1SZhang, Yanmin 2322a1645ce1SZhang, Yanmin return err; 2323a1645ce1SZhang, Yanmin } 2324cd84c2acSFrederic Weisbecker 2325cc612d81SArnaldo Carvalho de Melo static void vmlinux_path__exit(void) 23262446042cSArnaldo Carvalho de Melo { 232704662523SArnaldo Carvalho de Melo while (--vmlinux_path__nr_entries >= 0) 232804662523SArnaldo Carvalho de Melo zfree(&vmlinux_path[vmlinux_path__nr_entries]); 2329c4f03547SWang Nan vmlinux_path__nr_entries = 0; 2330cc612d81SArnaldo Carvalho de Melo 233104662523SArnaldo Carvalho de Melo zfree(&vmlinux_path); 2332cc612d81SArnaldo Carvalho de Melo } 2333cc612d81SArnaldo Carvalho de Melo 2334aac48647SEkaterina Tumanova static const char * const vmlinux_paths[] = { 2335aac48647SEkaterina Tumanova "vmlinux", 2336aac48647SEkaterina Tumanova "/boot/vmlinux" 2337aac48647SEkaterina Tumanova }; 2338aac48647SEkaterina Tumanova 2339aac48647SEkaterina Tumanova static const char * const vmlinux_paths_upd[] = { 2340aac48647SEkaterina Tumanova "/boot/vmlinux-%s", 2341aac48647SEkaterina Tumanova "/usr/lib/debug/boot/vmlinux-%s", 2342aac48647SEkaterina Tumanova "/lib/modules/%s/build/vmlinux", 2343f55ae954SEkaterina Tumanova "/usr/lib/debug/lib/modules/%s/vmlinux", 2344f55ae954SEkaterina Tumanova "/usr/lib/debug/boot/vmlinux-%s.debug" 2345aac48647SEkaterina Tumanova }; 2346aac48647SEkaterina Tumanova 2347aac48647SEkaterina Tumanova static int vmlinux_path__add(const char *new_entry) 2348aac48647SEkaterina Tumanova { 2349aac48647SEkaterina Tumanova vmlinux_path[vmlinux_path__nr_entries] = strdup(new_entry); 2350aac48647SEkaterina Tumanova if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 2351aac48647SEkaterina Tumanova return -1; 2352aac48647SEkaterina Tumanova ++vmlinux_path__nr_entries; 2353aac48647SEkaterina Tumanova 2354aac48647SEkaterina Tumanova return 0; 2355aac48647SEkaterina Tumanova } 2356aac48647SEkaterina Tumanova 2357ce80d3beSKan Liang static int vmlinux_path__init(struct perf_env *env) 2358cc612d81SArnaldo Carvalho de Melo { 2359cc612d81SArnaldo Carvalho de Melo struct utsname uts; 2360cc612d81SArnaldo Carvalho de Melo char bf[PATH_MAX]; 23610a7e6d1bSNamhyung Kim char *kernel_version; 2362aac48647SEkaterina Tumanova unsigned int i; 2363cc612d81SArnaldo Carvalho de Melo 2364aac48647SEkaterina Tumanova vmlinux_path = malloc(sizeof(char *) * (ARRAY_SIZE(vmlinux_paths) + 2365aac48647SEkaterina Tumanova ARRAY_SIZE(vmlinux_paths_upd))); 2366cc612d81SArnaldo Carvalho de Melo if (vmlinux_path == NULL) 2367cc612d81SArnaldo Carvalho de Melo return -1; 2368cc612d81SArnaldo Carvalho de Melo 2369aac48647SEkaterina Tumanova for (i = 0; i < ARRAY_SIZE(vmlinux_paths); i++) 2370aac48647SEkaterina Tumanova if (vmlinux_path__add(vmlinux_paths[i]) < 0) 2371cc612d81SArnaldo Carvalho de Melo goto out_fail; 2372ec5761eaSDavid Ahern 23730a7e6d1bSNamhyung Kim /* only try kernel version if no symfs was given */ 2374ec5761eaSDavid Ahern if (symbol_conf.symfs[0] != 0) 2375ec5761eaSDavid Ahern return 0; 2376ec5761eaSDavid Ahern 23770a7e6d1bSNamhyung Kim if (env) { 23780a7e6d1bSNamhyung Kim kernel_version = env->os_release; 23790a7e6d1bSNamhyung Kim } else { 2380ec5761eaSDavid Ahern if (uname(&uts) < 0) 2381e96c674fSNamhyung Kim goto out_fail; 2382ec5761eaSDavid Ahern 23830a7e6d1bSNamhyung Kim kernel_version = uts.release; 23840a7e6d1bSNamhyung Kim } 23850a7e6d1bSNamhyung Kim 2386aac48647SEkaterina Tumanova for (i = 0; i < ARRAY_SIZE(vmlinux_paths_upd); i++) { 2387aac48647SEkaterina Tumanova snprintf(bf, sizeof(bf), vmlinux_paths_upd[i], kernel_version); 2388aac48647SEkaterina Tumanova if (vmlinux_path__add(bf) < 0) 2389cc612d81SArnaldo Carvalho de Melo goto out_fail; 2390aac48647SEkaterina Tumanova } 2391cc612d81SArnaldo Carvalho de Melo 2392cc612d81SArnaldo Carvalho de Melo return 0; 2393cc612d81SArnaldo Carvalho de Melo 2394cc612d81SArnaldo Carvalho de Melo out_fail: 2395cc612d81SArnaldo Carvalho de Melo vmlinux_path__exit(); 2396cc612d81SArnaldo Carvalho de Melo return -1; 2397cc612d81SArnaldo Carvalho de Melo } 2398cc612d81SArnaldo Carvalho de Melo 23993bfe5f81SDavid Ahern int setup_list(struct strlist **list, const char *list_str, 2400655000e7SArnaldo Carvalho de Melo const char *list_name) 2401655000e7SArnaldo Carvalho de Melo { 2402655000e7SArnaldo Carvalho de Melo if (list_str == NULL) 2403655000e7SArnaldo Carvalho de Melo return 0; 2404655000e7SArnaldo Carvalho de Melo 24054a77e218SArnaldo Carvalho de Melo *list = strlist__new(list_str, NULL); 2406655000e7SArnaldo Carvalho de Melo if (!*list) { 2407655000e7SArnaldo Carvalho de Melo pr_err("problems parsing %s list\n", list_name); 2408655000e7SArnaldo Carvalho de Melo return -1; 2409655000e7SArnaldo Carvalho de Melo } 24100bc2f2f7SArnaldo Carvalho de Melo 24110bc2f2f7SArnaldo Carvalho de Melo symbol_conf.has_filter = true; 2412655000e7SArnaldo Carvalho de Melo return 0; 2413655000e7SArnaldo Carvalho de Melo } 2414655000e7SArnaldo Carvalho de Melo 2415e03eaa40SDavid Ahern int setup_intlist(struct intlist **list, const char *list_str, 2416e03eaa40SDavid Ahern const char *list_name) 2417e03eaa40SDavid Ahern { 2418e03eaa40SDavid Ahern if (list_str == NULL) 2419e03eaa40SDavid Ahern return 0; 2420e03eaa40SDavid Ahern 2421e03eaa40SDavid Ahern *list = intlist__new(list_str); 2422e03eaa40SDavid Ahern if (!*list) { 2423e03eaa40SDavid Ahern pr_err("problems parsing %s list\n", list_name); 2424e03eaa40SDavid Ahern return -1; 2425e03eaa40SDavid Ahern } 2426e03eaa40SDavid Ahern return 0; 2427e03eaa40SDavid Ahern } 2428e03eaa40SDavid Ahern 242961d9fc44SJin Yao static int setup_addrlist(struct intlist **addr_list, struct strlist *sym_list) 243061d9fc44SJin Yao { 243161d9fc44SJin Yao struct str_node *pos, *tmp; 243261d9fc44SJin Yao unsigned long val; 243361d9fc44SJin Yao char *sep; 243461d9fc44SJin Yao const char *end; 243561d9fc44SJin Yao int i = 0, err; 243661d9fc44SJin Yao 243761d9fc44SJin Yao *addr_list = intlist__new(NULL); 243861d9fc44SJin Yao if (!*addr_list) 243961d9fc44SJin Yao return -1; 244061d9fc44SJin Yao 244161d9fc44SJin Yao strlist__for_each_entry_safe(pos, tmp, sym_list) { 244261d9fc44SJin Yao errno = 0; 244361d9fc44SJin Yao val = strtoul(pos->s, &sep, 16); 244461d9fc44SJin Yao if (errno || (sep == pos->s)) 244561d9fc44SJin Yao continue; 244661d9fc44SJin Yao 244761d9fc44SJin Yao if (*sep != '\0') { 244861d9fc44SJin Yao end = pos->s + strlen(pos->s) - 1; 244961d9fc44SJin Yao while (end >= sep && isspace(*end)) 245061d9fc44SJin Yao end--; 245161d9fc44SJin Yao 245261d9fc44SJin Yao if (end >= sep) 245361d9fc44SJin Yao continue; 245461d9fc44SJin Yao } 245561d9fc44SJin Yao 245661d9fc44SJin Yao err = intlist__add(*addr_list, val); 245761d9fc44SJin Yao if (err) 245861d9fc44SJin Yao break; 245961d9fc44SJin Yao 246061d9fc44SJin Yao strlist__remove(sym_list, pos); 246161d9fc44SJin Yao i++; 246261d9fc44SJin Yao } 246361d9fc44SJin Yao 246461d9fc44SJin Yao if (i == 0) { 246561d9fc44SJin Yao intlist__delete(*addr_list); 246661d9fc44SJin Yao *addr_list = NULL; 246761d9fc44SJin Yao } 246861d9fc44SJin Yao 246961d9fc44SJin Yao return 0; 247061d9fc44SJin Yao } 247161d9fc44SJin Yao 2472ec80fde7SArnaldo Carvalho de Melo static bool symbol__read_kptr_restrict(void) 2473ec80fde7SArnaldo Carvalho de Melo { 2474ec80fde7SArnaldo Carvalho de Melo bool value = false; 2475ec80fde7SArnaldo Carvalho de Melo FILE *fp = fopen("/proc/sys/kernel/kptr_restrict", "r"); 247638272dc4SWang Nan 2477ec80fde7SArnaldo Carvalho de Melo if (fp != NULL) { 2478ec80fde7SArnaldo Carvalho de Melo char line[8]; 2479ec80fde7SArnaldo Carvalho de Melo 2480ec80fde7SArnaldo Carvalho de Melo if (fgets(line, sizeof(line), fp) != NULL) 24818859aedeSIgor Lubashev value = perf_cap__capable(CAP_SYSLOG) ? 24828859aedeSIgor Lubashev (atoi(line) >= 2) : 24838859aedeSIgor Lubashev (atoi(line) != 0); 2484ec80fde7SArnaldo Carvalho de Melo 2485ec80fde7SArnaldo Carvalho de Melo fclose(fp); 2486ec80fde7SArnaldo Carvalho de Melo } 2487ec80fde7SArnaldo Carvalho de Melo 24888859aedeSIgor Lubashev /* Per kernel/kallsyms.c: 24898859aedeSIgor Lubashev * we also restrict when perf_event_paranoid > 1 w/o CAP_SYSLOG 24908859aedeSIgor Lubashev */ 24918859aedeSIgor Lubashev if (perf_event_paranoid() > 1 && !perf_cap__capable(CAP_SYSLOG)) 24928859aedeSIgor Lubashev value = true; 24938859aedeSIgor Lubashev 2494ec80fde7SArnaldo Carvalho de Melo return value; 2495ec80fde7SArnaldo Carvalho de Melo } 2496ec80fde7SArnaldo Carvalho de Melo 2497b01141f4SArnaldo Carvalho de Melo int symbol__annotation_init(void) 2498b01141f4SArnaldo Carvalho de Melo { 24997b366142SArnaldo Carvalho de Melo if (symbol_conf.init_annotation) 25007b366142SArnaldo Carvalho de Melo return 0; 25017b366142SArnaldo Carvalho de Melo 2502b01141f4SArnaldo Carvalho de Melo if (symbol_conf.initialized) { 2503b01141f4SArnaldo Carvalho de Melo pr_err("Annotation needs to be init before symbol__init()\n"); 2504b01141f4SArnaldo Carvalho de Melo return -1; 2505b01141f4SArnaldo Carvalho de Melo } 2506b01141f4SArnaldo Carvalho de Melo 2507b01141f4SArnaldo Carvalho de Melo symbol_conf.priv_size += sizeof(struct annotation); 2508b01141f4SArnaldo Carvalho de Melo symbol_conf.init_annotation = true; 2509b01141f4SArnaldo Carvalho de Melo return 0; 2510b01141f4SArnaldo Carvalho de Melo } 2511b01141f4SArnaldo Carvalho de Melo 2512ce80d3beSKan Liang int symbol__init(struct perf_env *env) 2513cc612d81SArnaldo Carvalho de Melo { 2514ec5761eaSDavid Ahern const char *symfs; 2515ec5761eaSDavid Ahern 251685e00b55SJovi Zhang if (symbol_conf.initialized) 251785e00b55SJovi Zhang return 0; 251885e00b55SJovi Zhang 25199ac3e487SIrina Tirdea symbol_conf.priv_size = PERF_ALIGN(symbol_conf.priv_size, sizeof(u64)); 25204d439517SDavid S. Miller 2521166ccc9cSNamhyung Kim symbol__elf_init(); 2522166ccc9cSNamhyung Kim 252375be6cf4SArnaldo Carvalho de Melo if (symbol_conf.sort_by_name) 252475be6cf4SArnaldo Carvalho de Melo symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) - 252579406cd7SArnaldo Carvalho de Melo sizeof(struct symbol)); 2526b32d133aSArnaldo Carvalho de Melo 25270a7e6d1bSNamhyung Kim if (symbol_conf.try_vmlinux_path && vmlinux_path__init(env) < 0) 2528cc612d81SArnaldo Carvalho de Melo return -1; 2529cc612d81SArnaldo Carvalho de Melo 2530c410a338SArnaldo Carvalho de Melo if (symbol_conf.field_sep && *symbol_conf.field_sep == '.') { 2531c410a338SArnaldo Carvalho de Melo pr_err("'.' is the only non valid --field-separator argument\n"); 2532c410a338SArnaldo Carvalho de Melo return -1; 2533c410a338SArnaldo Carvalho de Melo } 2534c410a338SArnaldo Carvalho de Melo 2535655000e7SArnaldo Carvalho de Melo if (setup_list(&symbol_conf.dso_list, 2536655000e7SArnaldo Carvalho de Melo symbol_conf.dso_list_str, "dso") < 0) 2537655000e7SArnaldo Carvalho de Melo return -1; 2538655000e7SArnaldo Carvalho de Melo 2539655000e7SArnaldo Carvalho de Melo if (setup_list(&symbol_conf.comm_list, 2540655000e7SArnaldo Carvalho de Melo symbol_conf.comm_list_str, "comm") < 0) 2541655000e7SArnaldo Carvalho de Melo goto out_free_dso_list; 2542655000e7SArnaldo Carvalho de Melo 2543e03eaa40SDavid Ahern if (setup_intlist(&symbol_conf.pid_list, 2544e03eaa40SDavid Ahern symbol_conf.pid_list_str, "pid") < 0) 2545e03eaa40SDavid Ahern goto out_free_comm_list; 2546e03eaa40SDavid Ahern 2547e03eaa40SDavid Ahern if (setup_intlist(&symbol_conf.tid_list, 2548e03eaa40SDavid Ahern symbol_conf.tid_list_str, "tid") < 0) 2549e03eaa40SDavid Ahern goto out_free_pid_list; 2550e03eaa40SDavid Ahern 2551655000e7SArnaldo Carvalho de Melo if (setup_list(&symbol_conf.sym_list, 2552655000e7SArnaldo Carvalho de Melo symbol_conf.sym_list_str, "symbol") < 0) 2553e03eaa40SDavid Ahern goto out_free_tid_list; 2554655000e7SArnaldo Carvalho de Melo 255561d9fc44SJin Yao if (symbol_conf.sym_list && 255661d9fc44SJin Yao setup_addrlist(&symbol_conf.addr_list, symbol_conf.sym_list) < 0) 255761d9fc44SJin Yao goto out_free_sym_list; 255861d9fc44SJin Yao 255964eff7d9SDavid Ahern if (setup_list(&symbol_conf.bt_stop_list, 256064eff7d9SDavid Ahern symbol_conf.bt_stop_list_str, "symbol") < 0) 256164eff7d9SDavid Ahern goto out_free_sym_list; 256264eff7d9SDavid Ahern 2563ec5761eaSDavid Ahern /* 2564ec5761eaSDavid Ahern * A path to symbols of "/" is identical to "" 2565ec5761eaSDavid Ahern * reset here for simplicity. 2566ec5761eaSDavid Ahern */ 2567ec5761eaSDavid Ahern symfs = realpath(symbol_conf.symfs, NULL); 2568ec5761eaSDavid Ahern if (symfs == NULL) 2569ec5761eaSDavid Ahern symfs = symbol_conf.symfs; 2570ec5761eaSDavid Ahern if (strcmp(symfs, "/") == 0) 2571ec5761eaSDavid Ahern symbol_conf.symfs = ""; 2572ec5761eaSDavid Ahern if (symfs != symbol_conf.symfs) 2573ec5761eaSDavid Ahern free((void *)symfs); 2574ec5761eaSDavid Ahern 2575ec80fde7SArnaldo Carvalho de Melo symbol_conf.kptr_restrict = symbol__read_kptr_restrict(); 2576ec80fde7SArnaldo Carvalho de Melo 257785e00b55SJovi Zhang symbol_conf.initialized = true; 25784aa65636SArnaldo Carvalho de Melo return 0; 2579655000e7SArnaldo Carvalho de Melo 258064eff7d9SDavid Ahern out_free_sym_list: 258164eff7d9SDavid Ahern strlist__delete(symbol_conf.sym_list); 258261d9fc44SJin Yao intlist__delete(symbol_conf.addr_list); 2583e03eaa40SDavid Ahern out_free_tid_list: 2584e03eaa40SDavid Ahern intlist__delete(symbol_conf.tid_list); 2585e03eaa40SDavid Ahern out_free_pid_list: 2586e03eaa40SDavid Ahern intlist__delete(symbol_conf.pid_list); 2587655000e7SArnaldo Carvalho de Melo out_free_comm_list: 2588655000e7SArnaldo Carvalho de Melo strlist__delete(symbol_conf.comm_list); 2589d74c896bSNamhyung Kim out_free_dso_list: 2590d74c896bSNamhyung Kim strlist__delete(symbol_conf.dso_list); 2591655000e7SArnaldo Carvalho de Melo return -1; 2592cc612d81SArnaldo Carvalho de Melo } 2593cc612d81SArnaldo Carvalho de Melo 2594d65a458bSArnaldo Carvalho de Melo void symbol__exit(void) 2595d65a458bSArnaldo Carvalho de Melo { 259685e00b55SJovi Zhang if (!symbol_conf.initialized) 259785e00b55SJovi Zhang return; 259864eff7d9SDavid Ahern strlist__delete(symbol_conf.bt_stop_list); 2599d65a458bSArnaldo Carvalho de Melo strlist__delete(symbol_conf.sym_list); 2600d65a458bSArnaldo Carvalho de Melo strlist__delete(symbol_conf.dso_list); 2601d65a458bSArnaldo Carvalho de Melo strlist__delete(symbol_conf.comm_list); 2602e03eaa40SDavid Ahern intlist__delete(symbol_conf.tid_list); 2603e03eaa40SDavid Ahern intlist__delete(symbol_conf.pid_list); 260461d9fc44SJin Yao intlist__delete(symbol_conf.addr_list); 2605d65a458bSArnaldo Carvalho de Melo vmlinux_path__exit(); 2606d65a458bSArnaldo Carvalho de Melo symbol_conf.sym_list = symbol_conf.dso_list = symbol_conf.comm_list = NULL; 260764eff7d9SDavid Ahern symbol_conf.bt_stop_list = NULL; 260885e00b55SJovi Zhang symbol_conf.initialized = false; 2609d65a458bSArnaldo Carvalho de Melo } 2610a7066709SHe Kuang 2611a7066709SHe Kuang int symbol__config_symfs(const struct option *opt __maybe_unused, 2612a7066709SHe Kuang const char *dir, int unset __maybe_unused) 2613a7066709SHe Kuang { 2614a7066709SHe Kuang char *bf = NULL; 2615a7066709SHe Kuang int ret; 2616a7066709SHe Kuang 2617a7066709SHe Kuang symbol_conf.symfs = strdup(dir); 2618a7066709SHe Kuang if (symbol_conf.symfs == NULL) 2619a7066709SHe Kuang return -ENOMEM; 2620a7066709SHe Kuang 2621a7066709SHe Kuang /* skip the locally configured cache if a symfs is given, and 2622a7066709SHe Kuang * config buildid dir to symfs/.debug 2623a7066709SHe Kuang */ 2624a7066709SHe Kuang ret = asprintf(&bf, "%s/%s", dir, ".debug"); 2625a7066709SHe Kuang if (ret < 0) 2626a7066709SHe Kuang return -ENOMEM; 2627a7066709SHe Kuang 2628a7066709SHe Kuang set_buildid_dir(bf); 2629a7066709SHe Kuang 2630a7066709SHe Kuang free(bf); 2631a7066709SHe Kuang return 0; 2632a7066709SHe Kuang } 26339f87498fSJiri Olsa 26349f87498fSJiri Olsa struct mem_info *mem_info__get(struct mem_info *mi) 26359f87498fSJiri Olsa { 26369f87498fSJiri Olsa if (mi) 26379f87498fSJiri Olsa refcount_inc(&mi->refcnt); 26389f87498fSJiri Olsa return mi; 26399f87498fSJiri Olsa } 26409f87498fSJiri Olsa 26419f87498fSJiri Olsa void mem_info__put(struct mem_info *mi) 26429f87498fSJiri Olsa { 26439f87498fSJiri Olsa if (mi && refcount_dec_and_test(&mi->refcnt)) 26449f87498fSJiri Olsa free(mi); 26459f87498fSJiri Olsa } 26469f87498fSJiri Olsa 26479f87498fSJiri Olsa struct mem_info *mem_info__new(void) 26489f87498fSJiri Olsa { 26499f87498fSJiri Olsa struct mem_info *mi = zalloc(sizeof(*mi)); 26509f87498fSJiri Olsa 26519f87498fSJiri Olsa if (mi) 26529f87498fSJiri Olsa refcount_set(&mi->refcnt, 1); 26539f87498fSJiri Olsa return mi; 26549f87498fSJiri Olsa } 2655a3df50abSJames Clark 2656a3df50abSJames Clark /* 2657a3df50abSJames Clark * Checks that user supplied symbol kernel files are accessible because 2658a3df50abSJames Clark * the default mechanism for accessing elf files fails silently. i.e. if 2659a3df50abSJames Clark * debug syms for a build ID aren't found perf carries on normally. When 2660a3df50abSJames Clark * they are user supplied we should assume that the user doesn't want to 2661a3df50abSJames Clark * silently fail. 2662a3df50abSJames Clark */ 2663a3df50abSJames Clark int symbol__validate_sym_arguments(void) 2664a3df50abSJames Clark { 2665a3df50abSJames Clark if (symbol_conf.vmlinux_name && 2666a3df50abSJames Clark access(symbol_conf.vmlinux_name, R_OK)) { 2667a3df50abSJames Clark pr_err("Invalid file: %s\n", symbol_conf.vmlinux_name); 2668a3df50abSJames Clark return -EINVAL; 2669a3df50abSJames Clark } 2670a3df50abSJames Clark if (symbol_conf.kallsyms_name && 2671a3df50abSJames Clark access(symbol_conf.kallsyms_name, R_OK)) { 2672a3df50abSJames Clark pr_err("Invalid file: %s\n", symbol_conf.kallsyms_name); 2673a3df50abSJames Clark return -EINVAL; 2674a3df50abSJames Clark } 2675a3df50abSJames Clark return 0; 2676a3df50abSJames Clark } 2677