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, 8244f24cb3SJiri Olsa DSO_BINARY_TYPE__NOT_FOUND, 8344f24cb3SJiri Olsa }; 8444f24cb3SJiri Olsa 85028df767SJiri Olsa #define DSO_BINARY_TYPE__SYMTAB_CNT ARRAY_SIZE(binary_type_symtab) 8644f24cb3SJiri Olsa 873183f8caSArnaldo Carvalho de Melo static bool symbol_type__filter(char symbol_type) 886893d4eeSArnaldo Carvalho de Melo { 8931877908SAnton Blanchard symbol_type = toupper(symbol_type); 902be732c0SArnaldo Carvalho de Melo return symbol_type == 'T' || symbol_type == 'W' || symbol_type == 'D' || symbol_type == 'B'; 916893d4eeSArnaldo Carvalho de Melo } 926893d4eeSArnaldo Carvalho de Melo 93694bf407SAnton Blanchard static int prefix_underscores_count(const char *str) 94694bf407SAnton Blanchard { 95694bf407SAnton Blanchard const char *tail = str; 96694bf407SAnton Blanchard 97694bf407SAnton Blanchard while (*tail == '_') 98694bf407SAnton Blanchard tail++; 99694bf407SAnton Blanchard 100694bf407SAnton Blanchard return tail - str; 101694bf407SAnton Blanchard } 102694bf407SAnton Blanchard 103b9c0a649SThomas Richter void __weak arch__symbols__fixup_end(struct symbol *p, struct symbol *c) 104b9c0a649SThomas Richter { 105b9c0a649SThomas Richter p->end = c->start; 106b9c0a649SThomas Richter } 107b9c0a649SThomas Richter 1084b3a2716SMasami Hiramatsu const char * __weak arch__normalize_symbol_name(const char *name) 1094b3a2716SMasami Hiramatsu { 1104b3a2716SMasami Hiramatsu return name; 1114b3a2716SMasami Hiramatsu } 1124b3a2716SMasami Hiramatsu 113d8040645SPaul Clarke int __weak arch__compare_symbol_names(const char *namea, const char *nameb) 114d8040645SPaul Clarke { 115d8040645SPaul Clarke return strcmp(namea, nameb); 116d8040645SPaul Clarke } 117d8040645SPaul Clarke 118d8040645SPaul Clarke int __weak arch__compare_symbol_names_n(const char *namea, const char *nameb, 119d8040645SPaul Clarke unsigned int n) 120d8040645SPaul Clarke { 121d8040645SPaul Clarke return strncmp(namea, nameb, n); 122d8040645SPaul Clarke } 123d8040645SPaul Clarke 124fb6d5942SNaveen N. Rao int __weak arch__choose_best_symbol(struct symbol *syma, 125fb6d5942SNaveen N. Rao struct symbol *symb __maybe_unused) 126fb6d5942SNaveen N. Rao { 127fb6d5942SNaveen N. Rao /* Avoid "SyS" kernel syscall aliases */ 128fb6d5942SNaveen N. Rao if (strlen(syma->name) >= 3 && !strncmp(syma->name, "SyS", 3)) 129fb6d5942SNaveen N. Rao return SYMBOL_B; 130fb6d5942SNaveen N. Rao if (strlen(syma->name) >= 10 && !strncmp(syma->name, "compat_SyS", 10)) 131fb6d5942SNaveen N. Rao return SYMBOL_B; 132fb6d5942SNaveen N. Rao 133fb6d5942SNaveen N. Rao return SYMBOL_A; 134fb6d5942SNaveen N. Rao } 135694bf407SAnton Blanchard 136694bf407SAnton Blanchard static int choose_best_symbol(struct symbol *syma, struct symbol *symb) 137694bf407SAnton Blanchard { 138694bf407SAnton Blanchard s64 a; 139694bf407SAnton Blanchard s64 b; 1403445432bSAdrian Hunter size_t na, nb; 141694bf407SAnton Blanchard 142694bf407SAnton Blanchard /* Prefer a symbol with non zero length */ 143694bf407SAnton Blanchard a = syma->end - syma->start; 144694bf407SAnton Blanchard b = symb->end - symb->start; 145694bf407SAnton Blanchard if ((b == 0) && (a > 0)) 146694bf407SAnton Blanchard return SYMBOL_A; 147694bf407SAnton Blanchard else if ((a == 0) && (b > 0)) 148694bf407SAnton Blanchard return SYMBOL_B; 149694bf407SAnton Blanchard 150694bf407SAnton Blanchard /* Prefer a non weak symbol over a weak one */ 151694bf407SAnton Blanchard a = syma->binding == STB_WEAK; 152694bf407SAnton Blanchard b = symb->binding == STB_WEAK; 153694bf407SAnton Blanchard if (b && !a) 154694bf407SAnton Blanchard return SYMBOL_A; 155694bf407SAnton Blanchard if (a && !b) 156694bf407SAnton Blanchard return SYMBOL_B; 157694bf407SAnton Blanchard 158694bf407SAnton Blanchard /* Prefer a global symbol over a non global one */ 159694bf407SAnton Blanchard a = syma->binding == STB_GLOBAL; 160694bf407SAnton Blanchard b = symb->binding == STB_GLOBAL; 161694bf407SAnton Blanchard if (a && !b) 162694bf407SAnton Blanchard return SYMBOL_A; 163694bf407SAnton Blanchard if (b && !a) 164694bf407SAnton Blanchard return SYMBOL_B; 165694bf407SAnton Blanchard 166694bf407SAnton Blanchard /* Prefer a symbol with less underscores */ 167694bf407SAnton Blanchard a = prefix_underscores_count(syma->name); 168694bf407SAnton Blanchard b = prefix_underscores_count(symb->name); 169694bf407SAnton Blanchard if (b > a) 170694bf407SAnton Blanchard return SYMBOL_A; 171694bf407SAnton Blanchard else if (a > b) 172694bf407SAnton Blanchard return SYMBOL_B; 173694bf407SAnton Blanchard 1743445432bSAdrian Hunter /* Choose the symbol with the longest name */ 1753445432bSAdrian Hunter na = strlen(syma->name); 1763445432bSAdrian Hunter nb = strlen(symb->name); 1773445432bSAdrian Hunter if (na > nb) 178694bf407SAnton Blanchard return SYMBOL_A; 1793445432bSAdrian Hunter else if (na < nb) 180694bf407SAnton Blanchard return SYMBOL_B; 1813445432bSAdrian Hunter 182fb6d5942SNaveen N. Rao return arch__choose_best_symbol(syma, symb); 183694bf407SAnton Blanchard } 184694bf407SAnton Blanchard 1857137ff50SDavidlohr Bueso void symbols__fixup_duplicate(struct rb_root_cached *symbols) 186694bf407SAnton Blanchard { 187694bf407SAnton Blanchard struct rb_node *nd; 188694bf407SAnton Blanchard struct symbol *curr, *next; 189694bf407SAnton Blanchard 190c97b40e4SArnaldo Carvalho de Melo if (symbol_conf.allow_aliases) 191c97b40e4SArnaldo Carvalho de Melo return; 192c97b40e4SArnaldo Carvalho de Melo 1937137ff50SDavidlohr Bueso nd = rb_first_cached(symbols); 194694bf407SAnton Blanchard 195694bf407SAnton Blanchard while (nd) { 196694bf407SAnton Blanchard curr = rb_entry(nd, struct symbol, rb_node); 197694bf407SAnton Blanchard again: 198694bf407SAnton Blanchard nd = rb_next(&curr->rb_node); 199694bf407SAnton Blanchard next = rb_entry(nd, struct symbol, rb_node); 200694bf407SAnton Blanchard 201694bf407SAnton Blanchard if (!nd) 202694bf407SAnton Blanchard break; 203694bf407SAnton Blanchard 204694bf407SAnton Blanchard if (curr->start != next->start) 205694bf407SAnton Blanchard continue; 206694bf407SAnton Blanchard 207694bf407SAnton Blanchard if (choose_best_symbol(curr, next) == SYMBOL_A) { 2087137ff50SDavidlohr Bueso rb_erase_cached(&next->rb_node, symbols); 209d4f74eb8SChenggang Qin symbol__delete(next); 210694bf407SAnton Blanchard goto again; 211694bf407SAnton Blanchard } else { 212694bf407SAnton Blanchard nd = rb_next(&curr->rb_node); 2137137ff50SDavidlohr Bueso rb_erase_cached(&curr->rb_node, symbols); 214d4f74eb8SChenggang Qin symbol__delete(curr); 215694bf407SAnton Blanchard } 216694bf407SAnton Blanchard } 217694bf407SAnton Blanchard } 218694bf407SAnton Blanchard 2197137ff50SDavidlohr Bueso void symbols__fixup_end(struct rb_root_cached *symbols) 220af427bf5SArnaldo Carvalho de Melo { 2217137ff50SDavidlohr Bueso struct rb_node *nd, *prevnd = rb_first_cached(symbols); 2222e538c4aSArnaldo Carvalho de Melo struct symbol *curr, *prev; 223af427bf5SArnaldo Carvalho de Melo 224af427bf5SArnaldo Carvalho de Melo if (prevnd == NULL) 225af427bf5SArnaldo Carvalho de Melo return; 226af427bf5SArnaldo Carvalho de Melo 2272e538c4aSArnaldo Carvalho de Melo curr = rb_entry(prevnd, struct symbol, rb_node); 2282e538c4aSArnaldo Carvalho de Melo 229af427bf5SArnaldo Carvalho de Melo for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) { 2302e538c4aSArnaldo Carvalho de Melo prev = curr; 2312e538c4aSArnaldo Carvalho de Melo curr = rb_entry(nd, struct symbol, rb_node); 232af427bf5SArnaldo Carvalho de Melo 2333b01a413SArnaldo Carvalho de Melo if (prev->end == prev->start && prev->end != curr->start) 234b9c0a649SThomas Richter arch__symbols__fixup_end(prev, curr); 235af427bf5SArnaldo Carvalho de Melo } 236af427bf5SArnaldo Carvalho de Melo 2372e538c4aSArnaldo Carvalho de Melo /* Last entry */ 2382e538c4aSArnaldo Carvalho de Melo if (curr->end == curr->start) 239e7ede72aSDaniel Borkmann curr->end = roundup(curr->start, 4096) + 4096; 2402e538c4aSArnaldo Carvalho de Melo } 2412e538c4aSArnaldo Carvalho de Melo 2429a29ceeeSArnaldo Carvalho de Melo void maps__fixup_end(struct maps *maps) 243af427bf5SArnaldo Carvalho de Melo { 2448efc4f05SArnaldo Carvalho de Melo struct map *prev = NULL, *curr; 245af427bf5SArnaldo Carvalho de Melo 2460a7c74eaSArnaldo Carvalho de Melo down_write(&maps->lock); 2476a2ffcddSArnaldo Carvalho de Melo 2488efc4f05SArnaldo Carvalho de Melo maps__for_each_entry(maps, curr) { 2498efc4f05SArnaldo Carvalho de Melo if (prev != NULL && !prev->end) 2508efc4f05SArnaldo Carvalho de Melo prev->end = curr->start; 251af427bf5SArnaldo Carvalho de Melo 2528efc4f05SArnaldo Carvalho de Melo prev = curr; 2532e538c4aSArnaldo Carvalho de Melo } 25490c83218SArnaldo Carvalho de Melo 25590c83218SArnaldo Carvalho de Melo /* 25690c83218SArnaldo Carvalho de Melo * We still haven't the actual symbols, so guess the 25790c83218SArnaldo Carvalho de Melo * last map final address. 25890c83218SArnaldo Carvalho de Melo */ 2598efc4f05SArnaldo Carvalho de Melo if (curr && !curr->end) 2609d1faba5SIan Munsie curr->end = ~0ULL; 2616a2ffcddSArnaldo Carvalho de Melo 2620a7c74eaSArnaldo Carvalho de Melo up_write(&maps->lock); 263af427bf5SArnaldo Carvalho de Melo } 264af427bf5SArnaldo Carvalho de Melo 265af30bffaSArnaldo Carvalho de Melo struct symbol *symbol__new(u64 start, u64 len, u8 binding, u8 type, const char *name) 26686470930SIngo Molnar { 26786470930SIngo Molnar size_t namelen = strlen(name) + 1; 268aeafcbafSArnaldo Carvalho de Melo struct symbol *sym = calloc(1, (symbol_conf.priv_size + 269aeafcbafSArnaldo Carvalho de Melo sizeof(*sym) + namelen)); 270aeafcbafSArnaldo Carvalho de Melo if (sym == NULL) 27186470930SIngo Molnar return NULL; 27286470930SIngo Molnar 273b01141f4SArnaldo Carvalho de Melo if (symbol_conf.priv_size) { 274b01141f4SArnaldo Carvalho de Melo if (symbol_conf.init_annotation) { 275b01141f4SArnaldo Carvalho de Melo struct annotation *notes = (void *)sym; 276b01141f4SArnaldo Carvalho de Melo pthread_mutex_init(¬es->lock, NULL); 277b01141f4SArnaldo Carvalho de Melo } 278aeafcbafSArnaldo Carvalho de Melo sym = ((void *)sym) + symbol_conf.priv_size; 279b01141f4SArnaldo Carvalho de Melo } 28036479484SArnaldo Carvalho de Melo 281aeafcbafSArnaldo Carvalho de Melo sym->start = start; 2822c241bd3SArnaldo Carvalho de Melo sym->end = len ? start + len : start; 283af30bffaSArnaldo Carvalho de Melo sym->type = type; 284aeafcbafSArnaldo Carvalho de Melo sym->binding = binding; 285aeafcbafSArnaldo Carvalho de Melo sym->namelen = namelen - 1; 286e4204992SArnaldo Carvalho de Melo 287aeafcbafSArnaldo Carvalho de Melo pr_debug4("%s: %s %#" PRIx64 "-%#" PRIx64 "\n", 288aeafcbafSArnaldo Carvalho de Melo __func__, name, start, sym->end); 289aeafcbafSArnaldo Carvalho de Melo memcpy(sym->name, name, namelen); 290e4204992SArnaldo Carvalho de Melo 291aeafcbafSArnaldo Carvalho de Melo return sym; 29286470930SIngo Molnar } 29386470930SIngo Molnar 294aeafcbafSArnaldo Carvalho de Melo void symbol__delete(struct symbol *sym) 29586470930SIngo Molnar { 296aeafcbafSArnaldo Carvalho de Melo free(((void *)sym) - symbol_conf.priv_size); 29786470930SIngo Molnar } 29886470930SIngo Molnar 2997137ff50SDavidlohr Bueso void symbols__delete(struct rb_root_cached *symbols) 30086470930SIngo Molnar { 30186470930SIngo Molnar struct symbol *pos; 3027137ff50SDavidlohr Bueso struct rb_node *next = rb_first_cached(symbols); 30386470930SIngo Molnar 30486470930SIngo Molnar while (next) { 30586470930SIngo Molnar pos = rb_entry(next, struct symbol, rb_node); 30686470930SIngo Molnar next = rb_next(&pos->rb_node); 3077137ff50SDavidlohr Bueso rb_erase_cached(&pos->rb_node, symbols); 30800a192b3SArnaldo Carvalho de Melo symbol__delete(pos); 30986470930SIngo Molnar } 31086470930SIngo Molnar } 31186470930SIngo Molnar 3127137ff50SDavidlohr Bueso void __symbols__insert(struct rb_root_cached *symbols, 3137137ff50SDavidlohr Bueso struct symbol *sym, bool kernel) 31486470930SIngo Molnar { 3157137ff50SDavidlohr Bueso struct rb_node **p = &symbols->rb_root.rb_node; 31686470930SIngo Molnar struct rb_node *parent = NULL; 3179cffa8d5SPaul Mackerras const u64 ip = sym->start; 31886470930SIngo Molnar struct symbol *s; 3197137ff50SDavidlohr Bueso bool leftmost = true; 32086470930SIngo Molnar 321608c34deSArnaldo Carvalho de Melo if (kernel) { 322608c34deSArnaldo Carvalho de Melo const char *name = sym->name; 323608c34deSArnaldo Carvalho de Melo /* 324608c34deSArnaldo Carvalho de Melo * ppc64 uses function descriptors and appends a '.' to the 325608c34deSArnaldo Carvalho de Melo * start of every instruction address. Remove it. 326608c34deSArnaldo Carvalho de Melo */ 327608c34deSArnaldo Carvalho de Melo if (name[0] == '.') 328608c34deSArnaldo Carvalho de Melo name++; 329608c34deSArnaldo Carvalho de Melo sym->idle = symbol__is_idle(name); 330608c34deSArnaldo Carvalho de Melo } 331608c34deSArnaldo Carvalho de Melo 33286470930SIngo Molnar while (*p != NULL) { 33386470930SIngo Molnar parent = *p; 33486470930SIngo Molnar s = rb_entry(parent, struct symbol, rb_node); 33586470930SIngo Molnar if (ip < s->start) 33686470930SIngo Molnar p = &(*p)->rb_left; 3377137ff50SDavidlohr Bueso else { 33886470930SIngo Molnar p = &(*p)->rb_right; 3397137ff50SDavidlohr Bueso leftmost = false; 3407137ff50SDavidlohr Bueso } 34186470930SIngo Molnar } 34286470930SIngo Molnar rb_link_node(&sym->rb_node, parent, p); 3437137ff50SDavidlohr Bueso rb_insert_color_cached(&sym->rb_node, symbols, leftmost); 34486470930SIngo Molnar } 34586470930SIngo Molnar 3467137ff50SDavidlohr Bueso void symbols__insert(struct rb_root_cached *symbols, struct symbol *sym) 347608c34deSArnaldo Carvalho de Melo { 348608c34deSArnaldo Carvalho de Melo __symbols__insert(symbols, sym, false); 349608c34deSArnaldo Carvalho de Melo } 350608c34deSArnaldo Carvalho de Melo 3517137ff50SDavidlohr Bueso static struct symbol *symbols__find(struct rb_root_cached *symbols, u64 ip) 35286470930SIngo Molnar { 35386470930SIngo Molnar struct rb_node *n; 35486470930SIngo Molnar 355aeafcbafSArnaldo Carvalho de Melo if (symbols == NULL) 35686470930SIngo Molnar return NULL; 35786470930SIngo Molnar 3587137ff50SDavidlohr Bueso n = symbols->rb_root.rb_node; 35986470930SIngo Molnar 36086470930SIngo Molnar while (n) { 36186470930SIngo Molnar struct symbol *s = rb_entry(n, struct symbol, rb_node); 36286470930SIngo Molnar 36386470930SIngo Molnar if (ip < s->start) 36486470930SIngo Molnar n = n->rb_left; 3659c7b37cdSChris Phlipot else if (ip > s->end || (ip == s->end && ip != s->start)) 36686470930SIngo Molnar n = n->rb_right; 36786470930SIngo Molnar else 36886470930SIngo Molnar return s; 36986470930SIngo Molnar } 37086470930SIngo Molnar 37186470930SIngo Molnar return NULL; 37286470930SIngo Molnar } 37386470930SIngo Molnar 3747137ff50SDavidlohr Bueso static struct symbol *symbols__first(struct rb_root_cached *symbols) 3758e0cf965SAdrian Hunter { 3767137ff50SDavidlohr Bueso struct rb_node *n = rb_first_cached(symbols); 3778e0cf965SAdrian Hunter 3788e0cf965SAdrian Hunter if (n) 3798e0cf965SAdrian Hunter return rb_entry(n, struct symbol, rb_node); 3808e0cf965SAdrian Hunter 3818e0cf965SAdrian Hunter return NULL; 3828e0cf965SAdrian Hunter } 3838e0cf965SAdrian Hunter 3847137ff50SDavidlohr Bueso static struct symbol *symbols__last(struct rb_root_cached *symbols) 385cd67f99fSAdrian Hunter { 3867137ff50SDavidlohr Bueso struct rb_node *n = rb_last(&symbols->rb_root); 387cd67f99fSAdrian Hunter 388cd67f99fSAdrian Hunter if (n) 389cd67f99fSAdrian Hunter return rb_entry(n, struct symbol, rb_node); 390cd67f99fSAdrian Hunter 391cd67f99fSAdrian Hunter return NULL; 392cd67f99fSAdrian Hunter } 393cd67f99fSAdrian Hunter 3949c00a81bSAdrian Hunter static struct symbol *symbols__next(struct symbol *sym) 3959c00a81bSAdrian Hunter { 3969c00a81bSAdrian Hunter struct rb_node *n = rb_next(&sym->rb_node); 3979c00a81bSAdrian Hunter 3989c00a81bSAdrian Hunter if (n) 3999c00a81bSAdrian Hunter return rb_entry(n, struct symbol, rb_node); 4009c00a81bSAdrian Hunter 4019c00a81bSAdrian Hunter return NULL; 4029c00a81bSAdrian Hunter } 4039c00a81bSAdrian Hunter 4047137ff50SDavidlohr Bueso static void symbols__insert_by_name(struct rb_root_cached *symbols, struct symbol *sym) 40579406cd7SArnaldo Carvalho de Melo { 4067137ff50SDavidlohr Bueso struct rb_node **p = &symbols->rb_root.rb_node; 40779406cd7SArnaldo Carvalho de Melo struct rb_node *parent = NULL; 40802a9d037SRabin Vincent struct symbol_name_rb_node *symn, *s; 4097137ff50SDavidlohr Bueso bool leftmost = true; 41002a9d037SRabin Vincent 41102a9d037SRabin Vincent symn = container_of(sym, struct symbol_name_rb_node, sym); 41279406cd7SArnaldo Carvalho de Melo 41379406cd7SArnaldo Carvalho de Melo while (*p != NULL) { 41479406cd7SArnaldo Carvalho de Melo parent = *p; 41579406cd7SArnaldo Carvalho de Melo s = rb_entry(parent, struct symbol_name_rb_node, rb_node); 41679406cd7SArnaldo Carvalho de Melo if (strcmp(sym->name, s->sym.name) < 0) 41779406cd7SArnaldo Carvalho de Melo p = &(*p)->rb_left; 4187137ff50SDavidlohr Bueso else { 41979406cd7SArnaldo Carvalho de Melo p = &(*p)->rb_right; 4207137ff50SDavidlohr Bueso leftmost = false; 4217137ff50SDavidlohr Bueso } 42279406cd7SArnaldo Carvalho de Melo } 42379406cd7SArnaldo Carvalho de Melo rb_link_node(&symn->rb_node, parent, p); 4247137ff50SDavidlohr Bueso rb_insert_color_cached(&symn->rb_node, symbols, leftmost); 42579406cd7SArnaldo Carvalho de Melo } 42679406cd7SArnaldo Carvalho de Melo 4277137ff50SDavidlohr Bueso static void symbols__sort_by_name(struct rb_root_cached *symbols, 4287137ff50SDavidlohr Bueso struct rb_root_cached *source) 42979406cd7SArnaldo Carvalho de Melo { 43079406cd7SArnaldo Carvalho de Melo struct rb_node *nd; 43179406cd7SArnaldo Carvalho de Melo 4327137ff50SDavidlohr Bueso for (nd = rb_first_cached(source); nd; nd = rb_next(nd)) { 43379406cd7SArnaldo Carvalho de Melo struct symbol *pos = rb_entry(nd, struct symbol, rb_node); 434aeafcbafSArnaldo Carvalho de Melo symbols__insert_by_name(symbols, pos); 43579406cd7SArnaldo Carvalho de Melo } 43679406cd7SArnaldo Carvalho de Melo } 43779406cd7SArnaldo Carvalho de Melo 438d8040645SPaul Clarke int symbol__match_symbol_name(const char *name, const char *str, 439d8040645SPaul Clarke enum symbol_tag_include includes) 440d8040645SPaul Clarke { 441d8040645SPaul Clarke const char *versioning; 442d8040645SPaul Clarke 443d8040645SPaul Clarke if (includes == SYMBOL_TAG_INCLUDE__DEFAULT_ONLY && 444d8040645SPaul Clarke (versioning = strstr(name, "@@"))) { 445d8040645SPaul Clarke int len = strlen(str); 446d8040645SPaul Clarke 447d8040645SPaul Clarke if (len < versioning - name) 448d8040645SPaul Clarke len = versioning - name; 449d8040645SPaul Clarke 450d8040645SPaul Clarke return arch__compare_symbol_names_n(name, str, len); 451d8040645SPaul Clarke } else 452d8040645SPaul Clarke return arch__compare_symbol_names(name, str); 453d8040645SPaul Clarke } 454d8040645SPaul Clarke 4557137ff50SDavidlohr Bueso static struct symbol *symbols__find_by_name(struct rb_root_cached *symbols, 456d8040645SPaul Clarke const char *name, 457d8040645SPaul Clarke enum symbol_tag_include includes) 45879406cd7SArnaldo Carvalho de Melo { 45979406cd7SArnaldo Carvalho de Melo struct rb_node *n; 4605bcaaca3SMartin Liška struct symbol_name_rb_node *s = NULL; 46179406cd7SArnaldo Carvalho de Melo 462aeafcbafSArnaldo Carvalho de Melo if (symbols == NULL) 46379406cd7SArnaldo Carvalho de Melo return NULL; 46479406cd7SArnaldo Carvalho de Melo 4657137ff50SDavidlohr Bueso n = symbols->rb_root.rb_node; 46679406cd7SArnaldo Carvalho de Melo 46779406cd7SArnaldo Carvalho de Melo while (n) { 46879406cd7SArnaldo Carvalho de Melo int cmp; 46979406cd7SArnaldo Carvalho de Melo 47079406cd7SArnaldo Carvalho de Melo s = rb_entry(n, struct symbol_name_rb_node, rb_node); 471d8040645SPaul Clarke cmp = symbol__match_symbol_name(s->sym.name, name, includes); 47279406cd7SArnaldo Carvalho de Melo 473d8040645SPaul Clarke if (cmp > 0) 47479406cd7SArnaldo Carvalho de Melo n = n->rb_left; 475d8040645SPaul Clarke else if (cmp < 0) 47679406cd7SArnaldo Carvalho de Melo n = n->rb_right; 47779406cd7SArnaldo Carvalho de Melo else 478de480999SNamhyung Kim break; 47979406cd7SArnaldo Carvalho de Melo } 48079406cd7SArnaldo Carvalho de Melo 481de480999SNamhyung Kim if (n == NULL) 48279406cd7SArnaldo Carvalho de Melo return NULL; 483de480999SNamhyung Kim 484d8040645SPaul Clarke if (includes != SYMBOL_TAG_INCLUDE__DEFAULT_ONLY) 485de480999SNamhyung Kim /* return first symbol that has same name (if any) */ 486de480999SNamhyung Kim for (n = rb_prev(n); n; n = rb_prev(n)) { 487de480999SNamhyung Kim struct symbol_name_rb_node *tmp; 488de480999SNamhyung Kim 489de480999SNamhyung Kim tmp = rb_entry(n, struct symbol_name_rb_node, rb_node); 490031b84c4SNaveen N. Rao if (arch__compare_symbol_names(tmp->sym.name, s->sym.name)) 491de480999SNamhyung Kim break; 492de480999SNamhyung Kim 493de480999SNamhyung Kim s = tmp; 494de480999SNamhyung Kim } 495de480999SNamhyung Kim 496de480999SNamhyung Kim return &s->sym; 49779406cd7SArnaldo Carvalho de Melo } 49879406cd7SArnaldo Carvalho de Melo 499c0b4dffbSArnaldo Carvalho de Melo void dso__reset_find_symbol_cache(struct dso *dso) 500c0b4dffbSArnaldo Carvalho de Melo { 5013183f8caSArnaldo Carvalho de Melo dso->last_find_result.addr = 0; 5023183f8caSArnaldo Carvalho de Melo dso->last_find_result.symbol = NULL; 503c0b4dffbSArnaldo Carvalho de Melo } 504c0b4dffbSArnaldo Carvalho de Melo 5053183f8caSArnaldo Carvalho de Melo void dso__insert_symbol(struct dso *dso, struct symbol *sym) 506ae93a6c7SChris Phlipot { 5073183f8caSArnaldo Carvalho de Melo __symbols__insert(&dso->symbols, sym, dso->kernel); 508ae93a6c7SChris Phlipot 509ae93a6c7SChris Phlipot /* update the symbol cache if necessary */ 5103183f8caSArnaldo Carvalho de Melo if (dso->last_find_result.addr >= sym->start && 5113183f8caSArnaldo Carvalho de Melo (dso->last_find_result.addr < sym->end || 512ae93a6c7SChris Phlipot sym->start == sym->end)) { 5133183f8caSArnaldo Carvalho de Melo dso->last_find_result.symbol = sym; 514ae93a6c7SChris Phlipot } 515ae93a6c7SChris Phlipot } 516ae93a6c7SChris Phlipot 5173183f8caSArnaldo Carvalho de Melo struct symbol *dso__find_symbol(struct dso *dso, u64 addr) 518fcf1203aSArnaldo Carvalho de Melo { 5193183f8caSArnaldo Carvalho de Melo if (dso->last_find_result.addr != addr || dso->last_find_result.symbol == NULL) { 5203183f8caSArnaldo Carvalho de Melo dso->last_find_result.addr = addr; 5213183f8caSArnaldo Carvalho de Melo dso->last_find_result.symbol = symbols__find(&dso->symbols, addr); 522b685ac22SArnaldo Carvalho de Melo } 523b685ac22SArnaldo Carvalho de Melo 5243183f8caSArnaldo Carvalho de Melo return dso->last_find_result.symbol; 5258e0cf965SAdrian Hunter } 5268e0cf965SAdrian Hunter 5275cf88a63SArnaldo Carvalho de Melo struct symbol *dso__first_symbol(struct dso *dso) 5285cf88a63SArnaldo Carvalho de Melo { 5293183f8caSArnaldo Carvalho de Melo return symbols__first(&dso->symbols); 530cd67f99fSAdrian Hunter } 531cd67f99fSAdrian Hunter 5325cf88a63SArnaldo Carvalho de Melo struct symbol *dso__last_symbol(struct dso *dso) 5335cf88a63SArnaldo Carvalho de Melo { 5343183f8caSArnaldo Carvalho de Melo return symbols__last(&dso->symbols); 5355cf88a63SArnaldo Carvalho de Melo } 5365cf88a63SArnaldo Carvalho de Melo 5379c00a81bSAdrian Hunter struct symbol *dso__next_symbol(struct symbol *sym) 5389c00a81bSAdrian Hunter { 5399c00a81bSAdrian Hunter return symbols__next(sym); 5409c00a81bSAdrian Hunter } 5419c00a81bSAdrian Hunter 54218bd7264SArnaldo Carvalho de Melo struct symbol *symbol__next_by_name(struct symbol *sym) 54318bd7264SArnaldo Carvalho de Melo { 54418bd7264SArnaldo Carvalho de Melo struct symbol_name_rb_node *s = container_of(sym, struct symbol_name_rb_node, sym); 54518bd7264SArnaldo Carvalho de Melo struct rb_node *n = rb_next(&s->rb_node); 54618bd7264SArnaldo Carvalho de Melo 54718bd7264SArnaldo Carvalho de Melo return n ? &rb_entry(n, struct symbol_name_rb_node, rb_node)->sym : NULL; 54818bd7264SArnaldo Carvalho de Melo } 54918bd7264SArnaldo Carvalho de Melo 55018bd7264SArnaldo Carvalho de Melo /* 551af07eeb0SArnaldo Carvalho de Melo * Returns first symbol that matched with @name. 55218bd7264SArnaldo Carvalho de Melo */ 5533183f8caSArnaldo Carvalho de Melo struct symbol *dso__find_symbol_by_name(struct dso *dso, const char *name) 55479406cd7SArnaldo Carvalho de Melo { 5553183f8caSArnaldo Carvalho de Melo struct symbol *s = symbols__find_by_name(&dso->symbol_names, name, 556d8040645SPaul Clarke SYMBOL_TAG_INCLUDE__NONE); 557d8040645SPaul Clarke if (!s) 5583183f8caSArnaldo Carvalho de Melo s = symbols__find_by_name(&dso->symbol_names, name, 559d8040645SPaul Clarke SYMBOL_TAG_INCLUDE__DEFAULT_ONLY); 560d8040645SPaul Clarke return s; 56179406cd7SArnaldo Carvalho de Melo } 56279406cd7SArnaldo Carvalho de Melo 5633183f8caSArnaldo Carvalho de Melo void dso__sort_by_name(struct dso *dso) 56479406cd7SArnaldo Carvalho de Melo { 5653183f8caSArnaldo Carvalho de Melo dso__set_sorted_by_name(dso); 5663183f8caSArnaldo Carvalho de Melo return symbols__sort_by_name(&dso->symbol_names, &dso->symbols); 56779406cd7SArnaldo Carvalho de Melo } 56879406cd7SArnaldo Carvalho de Melo 569316d70d6SAdrian Hunter int modules__parse(const char *filename, void *arg, 570316d70d6SAdrian Hunter int (*process_module)(void *arg, const char *name, 5719ad4652bSThomas Richter u64 start, u64 size)) 572316d70d6SAdrian Hunter { 573316d70d6SAdrian Hunter char *line = NULL; 574316d70d6SAdrian Hunter size_t n; 575316d70d6SAdrian Hunter FILE *file; 576316d70d6SAdrian Hunter int err = 0; 577316d70d6SAdrian Hunter 578316d70d6SAdrian Hunter file = fopen(filename, "r"); 579316d70d6SAdrian Hunter if (file == NULL) 580316d70d6SAdrian Hunter return -1; 581316d70d6SAdrian Hunter 582316d70d6SAdrian Hunter while (1) { 583316d70d6SAdrian Hunter char name[PATH_MAX]; 5849ad4652bSThomas Richter u64 start, size; 5859ad4652bSThomas Richter char *sep, *endptr; 586316d70d6SAdrian Hunter ssize_t line_len; 587316d70d6SAdrian Hunter 588316d70d6SAdrian Hunter line_len = getline(&line, &n, file); 589316d70d6SAdrian Hunter if (line_len < 0) { 590316d70d6SAdrian Hunter if (feof(file)) 591316d70d6SAdrian Hunter break; 592316d70d6SAdrian Hunter err = -1; 593316d70d6SAdrian Hunter goto out; 594316d70d6SAdrian Hunter } 595316d70d6SAdrian Hunter 596316d70d6SAdrian Hunter if (!line) { 597316d70d6SAdrian Hunter err = -1; 598316d70d6SAdrian Hunter goto out; 599316d70d6SAdrian Hunter } 600316d70d6SAdrian Hunter 601316d70d6SAdrian Hunter line[--line_len] = '\0'; /* \n */ 602316d70d6SAdrian Hunter 603316d70d6SAdrian Hunter sep = strrchr(line, 'x'); 604316d70d6SAdrian Hunter if (sep == NULL) 605316d70d6SAdrian Hunter continue; 606316d70d6SAdrian Hunter 607316d70d6SAdrian Hunter hex2u64(sep + 1, &start); 608316d70d6SAdrian Hunter 609316d70d6SAdrian Hunter sep = strchr(line, ' '); 610316d70d6SAdrian Hunter if (sep == NULL) 611316d70d6SAdrian Hunter continue; 612316d70d6SAdrian Hunter 613316d70d6SAdrian Hunter *sep = '\0'; 614316d70d6SAdrian Hunter 615316d70d6SAdrian Hunter scnprintf(name, sizeof(name), "[%s]", line); 616316d70d6SAdrian Hunter 6179ad4652bSThomas Richter size = strtoul(sep + 1, &endptr, 0); 6189ad4652bSThomas Richter if (*endptr != ' ' && *endptr != '\t') 6199ad4652bSThomas Richter continue; 6209ad4652bSThomas Richter 6219ad4652bSThomas Richter err = process_module(arg, name, start, size); 622316d70d6SAdrian Hunter if (err) 623316d70d6SAdrian Hunter break; 624316d70d6SAdrian Hunter } 625316d70d6SAdrian Hunter out: 626316d70d6SAdrian Hunter free(line); 627316d70d6SAdrian Hunter fclose(file); 628316d70d6SAdrian Hunter return err; 629316d70d6SAdrian Hunter } 630316d70d6SAdrian Hunter 631e7110b9fSArnaldo Carvalho de Melo /* 632e7110b9fSArnaldo Carvalho de Melo * These are symbols in the kernel image, so make sure that 633e7110b9fSArnaldo Carvalho de Melo * sym is from a kernel DSO. 634e7110b9fSArnaldo Carvalho de Melo */ 635608c34deSArnaldo Carvalho de Melo static bool symbol__is_idle(const char *name) 63682d1deb0SDavid Ahern { 63782d1deb0SDavid Ahern const char * const idle_symbols[] = { 638*0e71459aSKim Phillips "acpi_idle_do_entry", 639*0e71459aSKim Phillips "acpi_processor_ffh_cstate_enter", 640549aff77SArnaldo Carvalho de Melo "arch_cpu_idle", 64182d1deb0SDavid Ahern "cpu_idle", 642e0336ed6SArnaldo Carvalho de Melo "cpu_startup_entry", 643*0e71459aSKim Phillips "idle_cpu", 64482d1deb0SDavid Ahern "intel_idle", 64582d1deb0SDavid Ahern "default_idle", 64682d1deb0SDavid Ahern "native_safe_halt", 64782d1deb0SDavid Ahern "enter_idle", 64882d1deb0SDavid Ahern "exit_idle", 64982d1deb0SDavid Ahern "mwait_idle", 65082d1deb0SDavid Ahern "mwait_idle_with_hints", 65182d1deb0SDavid Ahern "poll_idle", 65282d1deb0SDavid Ahern "ppc64_runlatch_off", 65382d1deb0SDavid Ahern "pseries_dedicated_idle_sleep", 65482d1deb0SDavid Ahern NULL 65582d1deb0SDavid Ahern }; 65682d1deb0SDavid Ahern int i; 65782d1deb0SDavid Ahern 65882d1deb0SDavid Ahern for (i = 0; idle_symbols[i]; i++) { 659608c34deSArnaldo Carvalho de Melo if (!strcmp(idle_symbols[i], name)) 66082d1deb0SDavid Ahern return true; 66182d1deb0SDavid Ahern } 66282d1deb0SDavid Ahern 66382d1deb0SDavid Ahern return false; 66482d1deb0SDavid Ahern } 66582d1deb0SDavid Ahern 666682b335aSArnaldo Carvalho de Melo static int map__process_kallsym_symbol(void *arg, const char *name, 66782151520SCody P Schafer char type, u64 start) 668682b335aSArnaldo Carvalho de Melo { 669682b335aSArnaldo Carvalho de Melo struct symbol *sym; 670333cc76cSArnaldo Carvalho de Melo struct dso *dso = arg; 6717137ff50SDavidlohr Bueso struct rb_root_cached *root = &dso->symbols; 672682b335aSArnaldo Carvalho de Melo 6733183f8caSArnaldo Carvalho de Melo if (!symbol_type__filter(type)) 674682b335aSArnaldo Carvalho de Melo return 0; 675682b335aSArnaldo Carvalho de Melo 67682151520SCody P Schafer /* 67782151520SCody P Schafer * module symbols are not sorted so we add all 67882151520SCody P Schafer * symbols, setting length to 0, and rely on 67982151520SCody P Schafer * symbols__fixup_end() to fix it up. 68082151520SCody P Schafer */ 681af30bffaSArnaldo Carvalho de Melo sym = symbol__new(start, 0, kallsyms2elf_binding(type), kallsyms2elf_type(type), name); 6822e538c4aSArnaldo Carvalho de Melo if (sym == NULL) 683682b335aSArnaldo Carvalho de Melo return -ENOMEM; 68482164161SArnaldo Carvalho de Melo /* 68582164161SArnaldo Carvalho de Melo * We will pass the symbols to the filter later, in 6864e06255fSArnaldo Carvalho de Melo * map__split_kallsyms, when we have split the maps per module 68782164161SArnaldo Carvalho de Melo */ 688608c34deSArnaldo Carvalho de Melo __symbols__insert(root, sym, !strchr(name, '[')); 689a1645ce1SZhang, Yanmin 690682b335aSArnaldo Carvalho de Melo return 0; 6912e538c4aSArnaldo Carvalho de Melo } 6922e538c4aSArnaldo Carvalho de Melo 693682b335aSArnaldo Carvalho de Melo /* 694682b335aSArnaldo Carvalho de Melo * Loads the function entries in /proc/kallsyms into kernel_map->dso, 695682b335aSArnaldo Carvalho de Melo * so that we can in the next step set the symbol ->end address and then 696682b335aSArnaldo Carvalho de Melo * call kernel_maps__split_kallsyms. 697682b335aSArnaldo Carvalho de Melo */ 698333cc76cSArnaldo Carvalho de Melo static int dso__load_all_kallsyms(struct dso *dso, const char *filename) 699682b335aSArnaldo Carvalho de Melo { 700333cc76cSArnaldo Carvalho de Melo return kallsyms__parse(filename, dso, map__process_kallsym_symbol); 7012e538c4aSArnaldo Carvalho de Melo } 7022e538c4aSArnaldo Carvalho de Melo 70379b6bb73SArnaldo Carvalho de Melo static int maps__split_kallsyms_for_kcore(struct maps *kmaps, struct dso *dso) 7048e0cf965SAdrian Hunter { 7058e0cf965SAdrian Hunter struct map *curr_map; 7068e0cf965SAdrian Hunter struct symbol *pos; 707866548ddSAdrian Hunter int count = 0; 7087137ff50SDavidlohr Bueso struct rb_root_cached old_root = dso->symbols; 7097137ff50SDavidlohr Bueso struct rb_root_cached *root = &dso->symbols; 7107137ff50SDavidlohr Bueso struct rb_node *next = rb_first_cached(root); 7118e0cf965SAdrian Hunter 712ba92732eSWang Nan if (!kmaps) 713ba92732eSWang Nan return -1; 714ba92732eSWang Nan 7157137ff50SDavidlohr Bueso *root = RB_ROOT_CACHED; 716866548ddSAdrian Hunter 7178e0cf965SAdrian Hunter while (next) { 7188e0cf965SAdrian Hunter char *module; 7198e0cf965SAdrian Hunter 7208e0cf965SAdrian Hunter pos = rb_entry(next, struct symbol, rb_node); 7218e0cf965SAdrian Hunter next = rb_next(&pos->rb_node); 7228e0cf965SAdrian Hunter 7237137ff50SDavidlohr Bueso rb_erase_cached(&pos->rb_node, &old_root); 7247137ff50SDavidlohr Bueso RB_CLEAR_NODE(&pos->rb_node); 7258e0cf965SAdrian Hunter module = strchr(pos->name, '\t'); 7268e0cf965SAdrian Hunter if (module) 7278e0cf965SAdrian Hunter *module = '\0'; 7288e0cf965SAdrian Hunter 72979b6bb73SArnaldo Carvalho de Melo curr_map = maps__find(kmaps, pos->start); 7308e0cf965SAdrian Hunter 731be39db9fSArnaldo Carvalho de Melo if (!curr_map) { 7328e0cf965SAdrian Hunter symbol__delete(pos); 733866548ddSAdrian Hunter continue; 734866548ddSAdrian Hunter } 735866548ddSAdrian Hunter 7368e0cf965SAdrian Hunter pos->start -= curr_map->start - curr_map->pgoff; 737d6d45745SAdrian Hunter if (pos->end > curr_map->end) 738d6d45745SAdrian Hunter pos->end = curr_map->end; 7398e0cf965SAdrian Hunter if (pos->end) 7408e0cf965SAdrian Hunter pos->end -= curr_map->start - curr_map->pgoff; 7413183f8caSArnaldo Carvalho de Melo symbols__insert(&curr_map->dso->symbols, pos); 7428e0cf965SAdrian Hunter ++count; 7438e0cf965SAdrian Hunter } 7448e0cf965SAdrian Hunter 7458e0cf965SAdrian Hunter /* Symbols have been adjusted */ 7468e0cf965SAdrian Hunter dso->adjust_symbols = 1; 7478e0cf965SAdrian Hunter 748866548ddSAdrian Hunter return count; 7498e0cf965SAdrian Hunter } 7508e0cf965SAdrian Hunter 7512e538c4aSArnaldo Carvalho de Melo /* 7522e538c4aSArnaldo Carvalho de Melo * Split the symbols into maps, making sure there are no overlaps, i.e. the 7532e538c4aSArnaldo Carvalho de Melo * kernel range is broken in several maps, named [kernel].N, as we don't have 7542e538c4aSArnaldo Carvalho de Melo * the original ELF section names vmlinux have. 7552e538c4aSArnaldo Carvalho de Melo */ 75679b6bb73SArnaldo Carvalho de Melo static int maps__split_kallsyms(struct maps *kmaps, struct dso *dso, u64 delta, 75715e0e2d4SArnaldo Carvalho de Melo struct map *initial_map) 7582e538c4aSArnaldo Carvalho de Melo { 759ba92732eSWang Nan struct machine *machine; 76015e0e2d4SArnaldo Carvalho de Melo struct map *curr_map = initial_map; 7612e538c4aSArnaldo Carvalho de Melo struct symbol *pos; 7628a953312SArnaldo Carvalho de Melo int count = 0, moved = 0; 7637137ff50SDavidlohr Bueso struct rb_root_cached *root = &dso->symbols; 7647137ff50SDavidlohr Bueso struct rb_node *next = rb_first_cached(root); 7652e538c4aSArnaldo Carvalho de Melo int kernel_range = 0; 7664d004365SAdrian Hunter bool x86_64; 7672e538c4aSArnaldo Carvalho de Melo 768ba92732eSWang Nan if (!kmaps) 769ba92732eSWang Nan return -1; 770ba92732eSWang Nan 771ba92732eSWang Nan machine = kmaps->machine; 772ba92732eSWang Nan 7734d004365SAdrian Hunter x86_64 = machine__is(machine, "x86_64"); 7744d004365SAdrian Hunter 7752e538c4aSArnaldo Carvalho de Melo while (next) { 7762e538c4aSArnaldo Carvalho de Melo char *module; 7772e538c4aSArnaldo Carvalho de Melo 7782e538c4aSArnaldo Carvalho de Melo pos = rb_entry(next, struct symbol, rb_node); 7792e538c4aSArnaldo Carvalho de Melo next = rb_next(&pos->rb_node); 7802e538c4aSArnaldo Carvalho de Melo 7812e538c4aSArnaldo Carvalho de Melo module = strchr(pos->name, '\t'); 7822e538c4aSArnaldo Carvalho de Melo if (module) { 78375be6cf4SArnaldo Carvalho de Melo if (!symbol_conf.use_modules) 7841de8e245SArnaldo Carvalho de Melo goto discard_symbol; 7851de8e245SArnaldo Carvalho de Melo 7862e538c4aSArnaldo Carvalho de Melo *module++ = '\0'; 7872e538c4aSArnaldo Carvalho de Melo 788b7cece76SArnaldo Carvalho de Melo if (strcmp(curr_map->dso->short_name, module)) { 78915e0e2d4SArnaldo Carvalho de Melo if (curr_map != initial_map && 790aeafcbafSArnaldo Carvalho de Melo dso->kernel == DSO_TYPE_GUEST_KERNEL && 79123346f21SArnaldo Carvalho de Melo machine__is_default_guest(machine)) { 792a1645ce1SZhang, Yanmin /* 793a1645ce1SZhang, Yanmin * We assume all symbols of a module are 794a1645ce1SZhang, Yanmin * continuous in * kallsyms, so curr_map 795a1645ce1SZhang, Yanmin * points to a module and all its 796a1645ce1SZhang, Yanmin * symbols are in its kmap. Mark it as 797a1645ce1SZhang, Yanmin * loaded. 798a1645ce1SZhang, Yanmin */ 7993183f8caSArnaldo Carvalho de Melo dso__set_loaded(curr_map->dso); 800af427bf5SArnaldo Carvalho de Melo } 801b7cece76SArnaldo Carvalho de Melo 80279b6bb73SArnaldo Carvalho de Melo curr_map = maps__find_by_name(kmaps, module); 803a1645ce1SZhang, Yanmin if (curr_map == NULL) { 8042f51903bSArnaldo Carvalho de Melo pr_debug("%s/proc/{kallsyms,modules} " 805a1645ce1SZhang, Yanmin "inconsistency while looking " 806a1645ce1SZhang, Yanmin "for \"%s\" module!\n", 80723346f21SArnaldo Carvalho de Melo machine->root_dir, module); 80815e0e2d4SArnaldo Carvalho de Melo curr_map = initial_map; 809a1645ce1SZhang, Yanmin goto discard_symbol; 810a1645ce1SZhang, Yanmin } 811a1645ce1SZhang, Yanmin 812a1645ce1SZhang, Yanmin if (curr_map->dso->loaded && 81323346f21SArnaldo Carvalho de Melo !machine__is_default_guest(machine)) 814b7cece76SArnaldo Carvalho de Melo goto discard_symbol; 815af427bf5SArnaldo Carvalho de Melo } 81686470930SIngo Molnar /* 8172e538c4aSArnaldo Carvalho de Melo * So that we look just like we get from .ko files, 81815e0e2d4SArnaldo Carvalho de Melo * i.e. not prelinked, relative to initial_map->start. 81986470930SIngo Molnar */ 8204e06255fSArnaldo Carvalho de Melo pos->start = curr_map->map_ip(curr_map, pos->start); 8214e06255fSArnaldo Carvalho de Melo pos->end = curr_map->map_ip(curr_map, pos->end); 8224d004365SAdrian Hunter } else if (x86_64 && is_entry_trampoline(pos->name)) { 8234d004365SAdrian Hunter /* 8244d004365SAdrian Hunter * These symbols are not needed anymore since the 8254d004365SAdrian Hunter * trampoline maps refer to the text section and it's 8264d004365SAdrian Hunter * symbols instead. Avoid having to deal with 8274d004365SAdrian Hunter * relocations, and the assumption that the first symbol 8284d004365SAdrian Hunter * is the start of kernel text, by simply removing the 8294d004365SAdrian Hunter * symbols at this point. 8304d004365SAdrian Hunter */ 8314d004365SAdrian Hunter goto discard_symbol; 83215e0e2d4SArnaldo Carvalho de Melo } else if (curr_map != initial_map) { 8332e538c4aSArnaldo Carvalho de Melo char dso_name[PATH_MAX]; 834aeafcbafSArnaldo Carvalho de Melo struct dso *ndso; 83586470930SIngo Molnar 836d9b62abaSAdrian Hunter if (delta) { 837d9b62abaSAdrian Hunter /* Kernel was relocated at boot time */ 838d9b62abaSAdrian Hunter pos->start -= delta; 839d9b62abaSAdrian Hunter pos->end -= delta; 840d9b62abaSAdrian Hunter } 841d9b62abaSAdrian Hunter 8428a953312SArnaldo Carvalho de Melo if (count == 0) { 84315e0e2d4SArnaldo Carvalho de Melo curr_map = initial_map; 844be39db9fSArnaldo Carvalho de Melo goto add_symbol; 8458a953312SArnaldo Carvalho de Melo } 8468a953312SArnaldo Carvalho de Melo 847aeafcbafSArnaldo Carvalho de Melo if (dso->kernel == DSO_TYPE_GUEST_KERNEL) 848a1645ce1SZhang, Yanmin snprintf(dso_name, sizeof(dso_name), 849a1645ce1SZhang, Yanmin "[guest.kernel].%d", 850a1645ce1SZhang, Yanmin kernel_range++); 851a1645ce1SZhang, Yanmin else 852a1645ce1SZhang, Yanmin snprintf(dso_name, sizeof(dso_name), 853a1645ce1SZhang, Yanmin "[kernel].%d", 8542e538c4aSArnaldo Carvalho de Melo kernel_range++); 85586470930SIngo Molnar 856aeafcbafSArnaldo Carvalho de Melo ndso = dso__new(dso_name); 857aeafcbafSArnaldo Carvalho de Melo if (ndso == NULL) 8582e538c4aSArnaldo Carvalho de Melo return -1; 8592e538c4aSArnaldo Carvalho de Melo 860aeafcbafSArnaldo Carvalho de Melo ndso->kernel = dso->kernel; 861a1645ce1SZhang, Yanmin 8623183f8caSArnaldo Carvalho de Melo curr_map = map__new2(pos->start, ndso); 86337fe5fcbSZhang, Yanmin if (curr_map == NULL) { 864d3a7c489SArnaldo Carvalho de Melo dso__put(ndso); 8652e538c4aSArnaldo Carvalho de Melo return -1; 8662e538c4aSArnaldo Carvalho de Melo } 8672e538c4aSArnaldo Carvalho de Melo 8684e06255fSArnaldo Carvalho de Melo curr_map->map_ip = curr_map->unmap_ip = identity__map_ip; 86979b6bb73SArnaldo Carvalho de Melo maps__insert(kmaps, curr_map); 8702e538c4aSArnaldo Carvalho de Melo ++kernel_range; 871d9b62abaSAdrian Hunter } else if (delta) { 872d9b62abaSAdrian Hunter /* Kernel was relocated at boot time */ 873d9b62abaSAdrian Hunter pos->start -= delta; 874d9b62abaSAdrian Hunter pos->end -= delta; 8752e538c4aSArnaldo Carvalho de Melo } 876be39db9fSArnaldo Carvalho de Melo add_symbol: 87715e0e2d4SArnaldo Carvalho de Melo if (curr_map != initial_map) { 8787137ff50SDavidlohr Bueso rb_erase_cached(&pos->rb_node, root); 8793183f8caSArnaldo Carvalho de Melo symbols__insert(&curr_map->dso->symbols, pos); 8808a953312SArnaldo Carvalho de Melo ++moved; 8818a953312SArnaldo Carvalho de Melo } else 8828a953312SArnaldo Carvalho de Melo ++count; 883be39db9fSArnaldo Carvalho de Melo 884be39db9fSArnaldo Carvalho de Melo continue; 885be39db9fSArnaldo Carvalho de Melo discard_symbol: 8867137ff50SDavidlohr Bueso rb_erase_cached(&pos->rb_node, root); 887be39db9fSArnaldo Carvalho de Melo symbol__delete(pos); 88886470930SIngo Molnar } 88986470930SIngo Molnar 89015e0e2d4SArnaldo Carvalho de Melo if (curr_map != initial_map && 891aeafcbafSArnaldo Carvalho de Melo dso->kernel == DSO_TYPE_GUEST_KERNEL && 89223346f21SArnaldo Carvalho de Melo machine__is_default_guest(kmaps->machine)) { 8933183f8caSArnaldo Carvalho de Melo dso__set_loaded(curr_map->dso); 894a1645ce1SZhang, Yanmin } 895a1645ce1SZhang, Yanmin 8968a953312SArnaldo Carvalho de Melo return count + moved; 89786470930SIngo Molnar } 89886470930SIngo Molnar 8993f067dcaSArnaldo Carvalho de Melo bool symbol__restricted_filename(const char *filename, 900ec80fde7SArnaldo Carvalho de Melo const char *restricted_filename) 901ec80fde7SArnaldo Carvalho de Melo { 902ec80fde7SArnaldo Carvalho de Melo bool restricted = false; 903ec80fde7SArnaldo Carvalho de Melo 904ec80fde7SArnaldo Carvalho de Melo if (symbol_conf.kptr_restrict) { 905ec80fde7SArnaldo Carvalho de Melo char *r = realpath(filename, NULL); 906ec80fde7SArnaldo Carvalho de Melo 907ec80fde7SArnaldo Carvalho de Melo if (r != NULL) { 908ec80fde7SArnaldo Carvalho de Melo restricted = strcmp(r, restricted_filename) == 0; 909ec80fde7SArnaldo Carvalho de Melo free(r); 910ec80fde7SArnaldo Carvalho de Melo return restricted; 911ec80fde7SArnaldo Carvalho de Melo } 912ec80fde7SArnaldo Carvalho de Melo } 913ec80fde7SArnaldo Carvalho de Melo 914ec80fde7SArnaldo Carvalho de Melo return restricted; 915ec80fde7SArnaldo Carvalho de Melo } 916ec80fde7SArnaldo Carvalho de Melo 91752afdaf9SAdrian Hunter struct module_info { 91852afdaf9SAdrian Hunter struct rb_node rb_node; 91952afdaf9SAdrian Hunter char *name; 92052afdaf9SAdrian Hunter u64 start; 92152afdaf9SAdrian Hunter }; 92252afdaf9SAdrian Hunter 92352afdaf9SAdrian Hunter static void add_module(struct module_info *mi, struct rb_root *modules) 92452afdaf9SAdrian Hunter { 92552afdaf9SAdrian Hunter struct rb_node **p = &modules->rb_node; 92652afdaf9SAdrian Hunter struct rb_node *parent = NULL; 92752afdaf9SAdrian Hunter struct module_info *m; 92852afdaf9SAdrian Hunter 92952afdaf9SAdrian Hunter while (*p != NULL) { 93052afdaf9SAdrian Hunter parent = *p; 93152afdaf9SAdrian Hunter m = rb_entry(parent, struct module_info, rb_node); 93252afdaf9SAdrian Hunter if (strcmp(mi->name, m->name) < 0) 93352afdaf9SAdrian Hunter p = &(*p)->rb_left; 93452afdaf9SAdrian Hunter else 93552afdaf9SAdrian Hunter p = &(*p)->rb_right; 93652afdaf9SAdrian Hunter } 93752afdaf9SAdrian Hunter rb_link_node(&mi->rb_node, parent, p); 93852afdaf9SAdrian Hunter rb_insert_color(&mi->rb_node, modules); 93952afdaf9SAdrian Hunter } 94052afdaf9SAdrian Hunter 94152afdaf9SAdrian Hunter static void delete_modules(struct rb_root *modules) 94252afdaf9SAdrian Hunter { 94352afdaf9SAdrian Hunter struct module_info *mi; 94452afdaf9SAdrian Hunter struct rb_node *next = rb_first(modules); 94552afdaf9SAdrian Hunter 94652afdaf9SAdrian Hunter while (next) { 94752afdaf9SAdrian Hunter mi = rb_entry(next, struct module_info, rb_node); 94852afdaf9SAdrian Hunter next = rb_next(&mi->rb_node); 94952afdaf9SAdrian Hunter rb_erase(&mi->rb_node, modules); 95074cf249dSArnaldo Carvalho de Melo zfree(&mi->name); 95152afdaf9SAdrian Hunter free(mi); 95252afdaf9SAdrian Hunter } 95352afdaf9SAdrian Hunter } 95452afdaf9SAdrian Hunter 95552afdaf9SAdrian Hunter static struct module_info *find_module(const char *name, 95652afdaf9SAdrian Hunter struct rb_root *modules) 95752afdaf9SAdrian Hunter { 95852afdaf9SAdrian Hunter struct rb_node *n = modules->rb_node; 95952afdaf9SAdrian Hunter 96052afdaf9SAdrian Hunter while (n) { 96152afdaf9SAdrian Hunter struct module_info *m; 96252afdaf9SAdrian Hunter int cmp; 96352afdaf9SAdrian Hunter 96452afdaf9SAdrian Hunter m = rb_entry(n, struct module_info, rb_node); 96552afdaf9SAdrian Hunter cmp = strcmp(name, m->name); 96652afdaf9SAdrian Hunter if (cmp < 0) 96752afdaf9SAdrian Hunter n = n->rb_left; 96852afdaf9SAdrian Hunter else if (cmp > 0) 96952afdaf9SAdrian Hunter n = n->rb_right; 97052afdaf9SAdrian Hunter else 97152afdaf9SAdrian Hunter return m; 97252afdaf9SAdrian Hunter } 97352afdaf9SAdrian Hunter 97452afdaf9SAdrian Hunter return NULL; 97552afdaf9SAdrian Hunter } 97652afdaf9SAdrian Hunter 9779ad4652bSThomas Richter static int __read_proc_modules(void *arg, const char *name, u64 start, 9789ad4652bSThomas Richter u64 size __maybe_unused) 97952afdaf9SAdrian Hunter { 98052afdaf9SAdrian Hunter struct rb_root *modules = arg; 98152afdaf9SAdrian Hunter struct module_info *mi; 98252afdaf9SAdrian Hunter 98352afdaf9SAdrian Hunter mi = zalloc(sizeof(struct module_info)); 98452afdaf9SAdrian Hunter if (!mi) 98552afdaf9SAdrian Hunter return -ENOMEM; 98652afdaf9SAdrian Hunter 98752afdaf9SAdrian Hunter mi->name = strdup(name); 98852afdaf9SAdrian Hunter mi->start = start; 98952afdaf9SAdrian Hunter 99052afdaf9SAdrian Hunter if (!mi->name) { 99152afdaf9SAdrian Hunter free(mi); 99252afdaf9SAdrian Hunter return -ENOMEM; 99352afdaf9SAdrian Hunter } 99452afdaf9SAdrian Hunter 99552afdaf9SAdrian Hunter add_module(mi, modules); 99652afdaf9SAdrian Hunter 99752afdaf9SAdrian Hunter return 0; 99852afdaf9SAdrian Hunter } 99952afdaf9SAdrian Hunter 100052afdaf9SAdrian Hunter static int read_proc_modules(const char *filename, struct rb_root *modules) 100152afdaf9SAdrian Hunter { 100252afdaf9SAdrian Hunter if (symbol__restricted_filename(filename, "/proc/modules")) 100352afdaf9SAdrian Hunter return -1; 100452afdaf9SAdrian Hunter 100552afdaf9SAdrian Hunter if (modules__parse(filename, modules, __read_proc_modules)) { 100652afdaf9SAdrian Hunter delete_modules(modules); 100752afdaf9SAdrian Hunter return -1; 100852afdaf9SAdrian Hunter } 100952afdaf9SAdrian Hunter 101052afdaf9SAdrian Hunter return 0; 101152afdaf9SAdrian Hunter } 101252afdaf9SAdrian Hunter 1013fc1b691dSAdrian Hunter int compare_proc_modules(const char *from, const char *to) 1014fc1b691dSAdrian Hunter { 1015fc1b691dSAdrian Hunter struct rb_root from_modules = RB_ROOT; 1016fc1b691dSAdrian Hunter struct rb_root to_modules = RB_ROOT; 1017fc1b691dSAdrian Hunter struct rb_node *from_node, *to_node; 1018fc1b691dSAdrian Hunter struct module_info *from_m, *to_m; 1019fc1b691dSAdrian Hunter int ret = -1; 1020fc1b691dSAdrian Hunter 1021fc1b691dSAdrian Hunter if (read_proc_modules(from, &from_modules)) 1022fc1b691dSAdrian Hunter return -1; 1023fc1b691dSAdrian Hunter 1024fc1b691dSAdrian Hunter if (read_proc_modules(to, &to_modules)) 1025fc1b691dSAdrian Hunter goto out_delete_from; 1026fc1b691dSAdrian Hunter 1027fc1b691dSAdrian Hunter from_node = rb_first(&from_modules); 1028fc1b691dSAdrian Hunter to_node = rb_first(&to_modules); 1029fc1b691dSAdrian Hunter while (from_node) { 1030fc1b691dSAdrian Hunter if (!to_node) 1031fc1b691dSAdrian Hunter break; 1032fc1b691dSAdrian Hunter 1033fc1b691dSAdrian Hunter from_m = rb_entry(from_node, struct module_info, rb_node); 1034fc1b691dSAdrian Hunter to_m = rb_entry(to_node, struct module_info, rb_node); 1035fc1b691dSAdrian Hunter 1036fc1b691dSAdrian Hunter if (from_m->start != to_m->start || 1037fc1b691dSAdrian Hunter strcmp(from_m->name, to_m->name)) 1038fc1b691dSAdrian Hunter break; 1039fc1b691dSAdrian Hunter 1040fc1b691dSAdrian Hunter from_node = rb_next(from_node); 1041fc1b691dSAdrian Hunter to_node = rb_next(to_node); 1042fc1b691dSAdrian Hunter } 1043fc1b691dSAdrian Hunter 1044fc1b691dSAdrian Hunter if (!from_node && !to_node) 1045fc1b691dSAdrian Hunter ret = 0; 1046fc1b691dSAdrian Hunter 1047fc1b691dSAdrian Hunter delete_modules(&to_modules); 1048fc1b691dSAdrian Hunter out_delete_from: 1049fc1b691dSAdrian Hunter delete_modules(&from_modules); 1050fc1b691dSAdrian Hunter 1051fc1b691dSAdrian Hunter return ret; 1052fc1b691dSAdrian Hunter } 1053fc1b691dSAdrian Hunter 105479b6bb73SArnaldo Carvalho de Melo static int do_validate_kcore_modules(const char *filename, struct maps *kmaps) 105552afdaf9SAdrian Hunter { 105652afdaf9SAdrian Hunter struct rb_root modules = RB_ROOT; 105752afdaf9SAdrian Hunter struct map *old_map; 105852afdaf9SAdrian Hunter int err; 105952afdaf9SAdrian Hunter 106052afdaf9SAdrian Hunter err = read_proc_modules(filename, &modules); 106152afdaf9SAdrian Hunter if (err) 106252afdaf9SAdrian Hunter return err; 106352afdaf9SAdrian Hunter 106479b6bb73SArnaldo Carvalho de Melo maps__for_each_entry(kmaps, old_map) { 106552afdaf9SAdrian Hunter struct module_info *mi; 106652afdaf9SAdrian Hunter 10675759a682SAdrian Hunter if (!__map__is_kmodule(old_map)) { 106852afdaf9SAdrian Hunter continue; 106952afdaf9SAdrian Hunter } 107052afdaf9SAdrian Hunter 107152afdaf9SAdrian Hunter /* Module must be in memory at the same address */ 107252afdaf9SAdrian Hunter mi = find_module(old_map->dso->short_name, &modules); 107352afdaf9SAdrian Hunter if (!mi || mi->start != old_map->start) { 107452afdaf9SAdrian Hunter err = -EINVAL; 107552afdaf9SAdrian Hunter goto out; 107652afdaf9SAdrian Hunter } 107752afdaf9SAdrian Hunter } 107852afdaf9SAdrian Hunter out: 107952afdaf9SAdrian Hunter delete_modules(&modules); 108052afdaf9SAdrian Hunter return err; 108152afdaf9SAdrian Hunter } 108252afdaf9SAdrian Hunter 108352afdaf9SAdrian Hunter /* 108452afdaf9SAdrian Hunter * If kallsyms is referenced by name then we look for filename in the same 108552afdaf9SAdrian Hunter * directory. 108652afdaf9SAdrian Hunter */ 108752afdaf9SAdrian Hunter static bool filename_from_kallsyms_filename(char *filename, 108852afdaf9SAdrian Hunter const char *base_name, 108952afdaf9SAdrian Hunter const char *kallsyms_filename) 109052afdaf9SAdrian Hunter { 109152afdaf9SAdrian Hunter char *name; 109252afdaf9SAdrian Hunter 109352afdaf9SAdrian Hunter strcpy(filename, kallsyms_filename); 109452afdaf9SAdrian Hunter name = strrchr(filename, '/'); 109552afdaf9SAdrian Hunter if (!name) 109652afdaf9SAdrian Hunter return false; 109752afdaf9SAdrian Hunter 109852afdaf9SAdrian Hunter name += 1; 109952afdaf9SAdrian Hunter 110052afdaf9SAdrian Hunter if (!strcmp(name, "kallsyms")) { 110152afdaf9SAdrian Hunter strcpy(name, base_name); 110252afdaf9SAdrian Hunter return true; 110352afdaf9SAdrian Hunter } 110452afdaf9SAdrian Hunter 110552afdaf9SAdrian Hunter return false; 110652afdaf9SAdrian Hunter } 110752afdaf9SAdrian Hunter 110852afdaf9SAdrian Hunter static int validate_kcore_modules(const char *kallsyms_filename, 110952afdaf9SAdrian Hunter struct map *map) 111052afdaf9SAdrian Hunter { 111179b6bb73SArnaldo Carvalho de Melo struct maps *kmaps = map__kmaps(map); 111252afdaf9SAdrian Hunter char modules_filename[PATH_MAX]; 111352afdaf9SAdrian Hunter 1114ba92732eSWang Nan if (!kmaps) 1115ba92732eSWang Nan return -EINVAL; 1116ba92732eSWang Nan 111752afdaf9SAdrian Hunter if (!filename_from_kallsyms_filename(modules_filename, "modules", 111852afdaf9SAdrian Hunter kallsyms_filename)) 111952afdaf9SAdrian Hunter return -EINVAL; 112052afdaf9SAdrian Hunter 11215759a682SAdrian Hunter if (do_validate_kcore_modules(modules_filename, kmaps)) 112252afdaf9SAdrian Hunter return -EINVAL; 112352afdaf9SAdrian Hunter 112452afdaf9SAdrian Hunter return 0; 112552afdaf9SAdrian Hunter } 112652afdaf9SAdrian Hunter 1127a00d28cbSAdrian Hunter static int validate_kcore_addresses(const char *kallsyms_filename, 1128a00d28cbSAdrian Hunter struct map *map) 1129a00d28cbSAdrian Hunter { 1130a00d28cbSAdrian Hunter struct kmap *kmap = map__kmap(map); 1131a00d28cbSAdrian Hunter 1132ba92732eSWang Nan if (!kmap) 1133ba92732eSWang Nan return -EINVAL; 1134ba92732eSWang Nan 1135a00d28cbSAdrian Hunter if (kmap->ref_reloc_sym && kmap->ref_reloc_sym->name) { 1136a00d28cbSAdrian Hunter u64 start; 1137a00d28cbSAdrian Hunter 1138b843f62aSArnaldo Carvalho de Melo if (kallsyms__get_function_start(kallsyms_filename, 1139b843f62aSArnaldo Carvalho de Melo kmap->ref_reloc_sym->name, &start)) 1140b843f62aSArnaldo Carvalho de Melo return -ENOENT; 1141a00d28cbSAdrian Hunter if (start != kmap->ref_reloc_sym->addr) 1142a00d28cbSAdrian Hunter return -EINVAL; 1143a00d28cbSAdrian Hunter } 1144a00d28cbSAdrian Hunter 1145a00d28cbSAdrian Hunter return validate_kcore_modules(kallsyms_filename, map); 1146a00d28cbSAdrian Hunter } 1147a00d28cbSAdrian Hunter 11488e0cf965SAdrian Hunter struct kcore_mapfn_data { 11498e0cf965SAdrian Hunter struct dso *dso; 11508e0cf965SAdrian Hunter struct list_head maps; 11518e0cf965SAdrian Hunter }; 11528e0cf965SAdrian Hunter 11538e0cf965SAdrian Hunter static int kcore_mapfn(u64 start, u64 len, u64 pgoff, void *data) 11548e0cf965SAdrian Hunter { 11558e0cf965SAdrian Hunter struct kcore_mapfn_data *md = data; 11568e0cf965SAdrian Hunter struct map *map; 11578e0cf965SAdrian Hunter 11583183f8caSArnaldo Carvalho de Melo map = map__new2(start, md->dso); 11598e0cf965SAdrian Hunter if (map == NULL) 11608e0cf965SAdrian Hunter return -ENOMEM; 11618e0cf965SAdrian Hunter 11628e0cf965SAdrian Hunter map->end = map->start + len; 11638e0cf965SAdrian Hunter map->pgoff = pgoff; 11648e0cf965SAdrian Hunter 11658e0cf965SAdrian Hunter list_add(&map->node, &md->maps); 11668e0cf965SAdrian Hunter 11678e0cf965SAdrian Hunter return 0; 11688e0cf965SAdrian Hunter } 11698e0cf965SAdrian Hunter 1170fb5a88d4SJiri Olsa /* 117179b6bb73SArnaldo Carvalho de Melo * Merges map into maps by splitting the new map within the existing map 117279b6bb73SArnaldo Carvalho de Melo * regions. 1173fb5a88d4SJiri Olsa */ 117479b6bb73SArnaldo Carvalho de Melo int maps__merge_in(struct maps *kmaps, struct map *new_map) 1175fb5a88d4SJiri Olsa { 1176fb5a88d4SJiri Olsa struct map *old_map; 1177fb5a88d4SJiri Olsa LIST_HEAD(merged); 1178fb5a88d4SJiri Olsa 117979b6bb73SArnaldo Carvalho de Melo maps__for_each_entry(kmaps, old_map) { 1180fb5a88d4SJiri Olsa /* no overload with this one */ 1181fb5a88d4SJiri Olsa if (new_map->end < old_map->start || 1182fb5a88d4SJiri Olsa new_map->start >= old_map->end) 1183fb5a88d4SJiri Olsa continue; 1184fb5a88d4SJiri Olsa 1185fb5a88d4SJiri Olsa if (new_map->start < old_map->start) { 1186fb5a88d4SJiri Olsa /* 1187fb5a88d4SJiri Olsa * |new...... 1188fb5a88d4SJiri Olsa * |old.... 1189fb5a88d4SJiri Olsa */ 1190fb5a88d4SJiri Olsa if (new_map->end < old_map->end) { 1191fb5a88d4SJiri Olsa /* 1192fb5a88d4SJiri Olsa * |new......| -> |new..| 1193fb5a88d4SJiri Olsa * |old....| -> |old....| 1194fb5a88d4SJiri Olsa */ 1195fb5a88d4SJiri Olsa new_map->end = old_map->start; 1196fb5a88d4SJiri Olsa } else { 1197fb5a88d4SJiri Olsa /* 1198fb5a88d4SJiri Olsa * |new.............| -> |new..| |new..| 1199fb5a88d4SJiri Olsa * |old....| -> |old....| 1200fb5a88d4SJiri Olsa */ 1201fb5a88d4SJiri Olsa struct map *m = map__clone(new_map); 1202fb5a88d4SJiri Olsa 1203fb5a88d4SJiri Olsa if (!m) 1204fb5a88d4SJiri Olsa return -ENOMEM; 1205fb5a88d4SJiri Olsa 1206fb5a88d4SJiri Olsa m->end = old_map->start; 1207fb5a88d4SJiri Olsa list_add_tail(&m->node, &merged); 1208fb5a88d4SJiri Olsa new_map->start = old_map->end; 1209fb5a88d4SJiri Olsa } 1210fb5a88d4SJiri Olsa } else { 1211fb5a88d4SJiri Olsa /* 1212fb5a88d4SJiri Olsa * |new...... 1213fb5a88d4SJiri Olsa * |old.... 1214fb5a88d4SJiri Olsa */ 1215fb5a88d4SJiri Olsa if (new_map->end < old_map->end) { 1216fb5a88d4SJiri Olsa /* 1217fb5a88d4SJiri Olsa * |new..| -> x 1218fb5a88d4SJiri Olsa * |old.........| -> |old.........| 1219fb5a88d4SJiri Olsa */ 1220fb5a88d4SJiri Olsa map__put(new_map); 1221fb5a88d4SJiri Olsa new_map = NULL; 1222fb5a88d4SJiri Olsa break; 1223fb5a88d4SJiri Olsa } else { 1224fb5a88d4SJiri Olsa /* 1225fb5a88d4SJiri Olsa * |new......| -> |new...| 1226fb5a88d4SJiri Olsa * |old....| -> |old....| 1227fb5a88d4SJiri Olsa */ 1228fb5a88d4SJiri Olsa new_map->start = old_map->end; 1229fb5a88d4SJiri Olsa } 1230fb5a88d4SJiri Olsa } 1231fb5a88d4SJiri Olsa } 1232fb5a88d4SJiri Olsa 1233fb5a88d4SJiri Olsa while (!list_empty(&merged)) { 1234fb5a88d4SJiri Olsa old_map = list_entry(merged.next, struct map, node); 1235fb5a88d4SJiri Olsa list_del_init(&old_map->node); 123679b6bb73SArnaldo Carvalho de Melo maps__insert(kmaps, old_map); 1237fb5a88d4SJiri Olsa map__put(old_map); 1238fb5a88d4SJiri Olsa } 1239fb5a88d4SJiri Olsa 1240fb5a88d4SJiri Olsa if (new_map) { 124179b6bb73SArnaldo Carvalho de Melo maps__insert(kmaps, new_map); 1242fb5a88d4SJiri Olsa map__put(new_map); 1243fb5a88d4SJiri Olsa } 1244fb5a88d4SJiri Olsa return 0; 1245fb5a88d4SJiri Olsa } 1246fb5a88d4SJiri Olsa 12478e0cf965SAdrian Hunter static int dso__load_kcore(struct dso *dso, struct map *map, 12488e0cf965SAdrian Hunter const char *kallsyms_filename) 12498e0cf965SAdrian Hunter { 125079b6bb73SArnaldo Carvalho de Melo struct maps *kmaps = map__kmaps(map); 12518e0cf965SAdrian Hunter struct kcore_mapfn_data md; 125250481461SArnaldo Carvalho de Melo struct map *old_map, *new_map, *replacement_map = NULL, *next; 12531c5aae77SAdrian Hunter struct machine *machine; 12548e0cf965SAdrian Hunter bool is_64_bit; 12558e0cf965SAdrian Hunter int err, fd; 12568e0cf965SAdrian Hunter char kcore_filename[PATH_MAX]; 125756549978SAdrian Hunter u64 stext; 12588e0cf965SAdrian Hunter 1259ba92732eSWang Nan if (!kmaps) 1260ba92732eSWang Nan return -EINVAL; 1261ba92732eSWang Nan 12621c5aae77SAdrian Hunter machine = kmaps->machine; 12631c5aae77SAdrian Hunter 12648e0cf965SAdrian Hunter /* This function requires that the map is the kernel map */ 1265efdd5c6bSArnaldo Carvalho de Melo if (!__map__is_kernel(map)) 12668e0cf965SAdrian Hunter return -EINVAL; 12678e0cf965SAdrian Hunter 126852afdaf9SAdrian Hunter if (!filename_from_kallsyms_filename(kcore_filename, "kcore", 12698e0cf965SAdrian Hunter kallsyms_filename)) 12708e0cf965SAdrian Hunter return -EINVAL; 12718e0cf965SAdrian Hunter 1272a00d28cbSAdrian Hunter /* Modules and kernel must be present at their original addresses */ 1273a00d28cbSAdrian Hunter if (validate_kcore_addresses(kallsyms_filename, map)) 127452afdaf9SAdrian Hunter return -EINVAL; 127552afdaf9SAdrian Hunter 12768e0cf965SAdrian Hunter md.dso = dso; 12778e0cf965SAdrian Hunter INIT_LIST_HEAD(&md.maps); 12788e0cf965SAdrian Hunter 12798e0cf965SAdrian Hunter fd = open(kcore_filename, O_RDONLY); 128036c8bb56SLi Zhang if (fd < 0) { 1281133de940SAdrian Hunter pr_debug("Failed to open %s. Note /proc/kcore requires CAP_SYS_RAWIO capability to access.\n", 128236c8bb56SLi Zhang kcore_filename); 12838e0cf965SAdrian Hunter return -EINVAL; 128436c8bb56SLi Zhang } 12858e0cf965SAdrian Hunter 12868e0cf965SAdrian Hunter /* Read new maps into temporary lists */ 1287e9814df8SArnaldo Carvalho de Melo err = file__read_maps(fd, map->prot & PROT_EXEC, kcore_mapfn, &md, 12888e0cf965SAdrian Hunter &is_64_bit); 12898e0cf965SAdrian Hunter if (err) 12908e0cf965SAdrian Hunter goto out_err; 1291c6d8f2a4SAdrian Hunter dso->is_64_bit = is_64_bit; 12928e0cf965SAdrian Hunter 12938e0cf965SAdrian Hunter if (list_empty(&md.maps)) { 12948e0cf965SAdrian Hunter err = -EINVAL; 12958e0cf965SAdrian Hunter goto out_err; 12968e0cf965SAdrian Hunter } 12978e0cf965SAdrian Hunter 12988e0cf965SAdrian Hunter /* Remove old maps */ 129979b6bb73SArnaldo Carvalho de Melo maps__for_each_entry_safe(kmaps, old_map, next) { 1300fb5a88d4SJiri Olsa /* 1301fb5a88d4SJiri Olsa * We need to preserve eBPF maps even if they are 1302fb5a88d4SJiri Olsa * covered by kcore, because we need to access 1303fb5a88d4SJiri Olsa * eBPF dso for source data. 1304fb5a88d4SJiri Olsa */ 1305fb5a88d4SJiri Olsa if (old_map != map && !__map__is_bpf_prog(old_map)) 130679b6bb73SArnaldo Carvalho de Melo maps__remove(kmaps, old_map); 13078e0cf965SAdrian Hunter } 13081c5aae77SAdrian Hunter machine->trampolines_mapped = false; 13098e0cf965SAdrian Hunter 131056549978SAdrian Hunter /* Find the kernel map using the '_stext' symbol */ 131156549978SAdrian Hunter if (!kallsyms__get_function_start(kallsyms_filename, "_stext", &stext)) { 13128e0cf965SAdrian Hunter list_for_each_entry(new_map, &md.maps, node) { 131356549978SAdrian Hunter if (stext >= new_map->start && stext < new_map->end) { 13148e0cf965SAdrian Hunter replacement_map = new_map; 13158e0cf965SAdrian Hunter break; 13168e0cf965SAdrian Hunter } 13178e0cf965SAdrian Hunter } 131856549978SAdrian Hunter } 13198e0cf965SAdrian Hunter 13208e0cf965SAdrian Hunter if (!replacement_map) 13218e0cf965SAdrian Hunter replacement_map = list_entry(md.maps.next, struct map, node); 13228e0cf965SAdrian Hunter 13238e0cf965SAdrian Hunter /* Add new maps */ 13248e0cf965SAdrian Hunter while (!list_empty(&md.maps)) { 13258e0cf965SAdrian Hunter new_map = list_entry(md.maps.next, struct map, node); 1326facf3f06SArnaldo Carvalho de Melo list_del_init(&new_map->node); 13278e0cf965SAdrian Hunter if (new_map == replacement_map) { 13288e0cf965SAdrian Hunter map->start = new_map->start; 13298e0cf965SAdrian Hunter map->end = new_map->end; 13308e0cf965SAdrian Hunter map->pgoff = new_map->pgoff; 13318e0cf965SAdrian Hunter map->map_ip = new_map->map_ip; 13328e0cf965SAdrian Hunter map->unmap_ip = new_map->unmap_ip; 13338e0cf965SAdrian Hunter /* Ensure maps are correctly ordered */ 133484c2cafaSArnaldo Carvalho de Melo map__get(map); 133579b6bb73SArnaldo Carvalho de Melo maps__remove(kmaps, map); 133679b6bb73SArnaldo Carvalho de Melo maps__insert(kmaps, map); 133784c2cafaSArnaldo Carvalho de Melo map__put(map); 133884c2cafaSArnaldo Carvalho de Melo map__put(new_map); 1339fb5a88d4SJiri Olsa } else { 1340fb5a88d4SJiri Olsa /* 1341fb5a88d4SJiri Olsa * Merge kcore map into existing maps, 1342fb5a88d4SJiri Olsa * and ensure that current maps (eBPF) 1343fb5a88d4SJiri Olsa * stay intact. 1344fb5a88d4SJiri Olsa */ 134579b6bb73SArnaldo Carvalho de Melo if (maps__merge_in(kmaps, new_map)) 1346fb5a88d4SJiri Olsa goto out_err; 1347fb5a88d4SJiri Olsa } 13488e0cf965SAdrian Hunter } 13498e0cf965SAdrian Hunter 13501c5aae77SAdrian Hunter if (machine__is(machine, "x86_64")) { 13511c5aae77SAdrian Hunter u64 addr; 13521c5aae77SAdrian Hunter 13531c5aae77SAdrian Hunter /* 13541c5aae77SAdrian Hunter * If one of the corresponding symbols is there, assume the 13551c5aae77SAdrian Hunter * entry trampoline maps are too. 13561c5aae77SAdrian Hunter */ 13571c5aae77SAdrian Hunter if (!kallsyms__get_function_start(kallsyms_filename, 13581c5aae77SAdrian Hunter ENTRY_TRAMPOLINE_NAME, 13591c5aae77SAdrian Hunter &addr)) 13601c5aae77SAdrian Hunter machine->trampolines_mapped = true; 13611c5aae77SAdrian Hunter } 13621c5aae77SAdrian Hunter 13638e0cf965SAdrian Hunter /* 13648e0cf965SAdrian Hunter * Set the data type and long name so that kcore can be read via 13658e0cf965SAdrian Hunter * dso__data_read_addr(). 13668e0cf965SAdrian Hunter */ 13678e0cf965SAdrian Hunter if (dso->kernel == DSO_TYPE_GUEST_KERNEL) 13685f70619dSArnaldo Carvalho de Melo dso->binary_type = DSO_BINARY_TYPE__GUEST_KCORE; 13698e0cf965SAdrian Hunter else 13705f70619dSArnaldo Carvalho de Melo dso->binary_type = DSO_BINARY_TYPE__KCORE; 13717e155d4dSArnaldo Carvalho de Melo dso__set_long_name(dso, strdup(kcore_filename), true); 13728e0cf965SAdrian Hunter 13738e0cf965SAdrian Hunter close(fd); 13748e0cf965SAdrian Hunter 1375e9814df8SArnaldo Carvalho de Melo if (map->prot & PROT_EXEC) 13768e0cf965SAdrian Hunter pr_debug("Using %s for kernel object code\n", kcore_filename); 13778e0cf965SAdrian Hunter else 13788e0cf965SAdrian Hunter pr_debug("Using %s for kernel data\n", kcore_filename); 13798e0cf965SAdrian Hunter 13808e0cf965SAdrian Hunter return 0; 13818e0cf965SAdrian Hunter 13828e0cf965SAdrian Hunter out_err: 13838e0cf965SAdrian Hunter while (!list_empty(&md.maps)) { 13848e0cf965SAdrian Hunter map = list_entry(md.maps.next, struct map, node); 1385facf3f06SArnaldo Carvalho de Melo list_del_init(&map->node); 138684c2cafaSArnaldo Carvalho de Melo map__put(map); 13878e0cf965SAdrian Hunter } 13888e0cf965SAdrian Hunter close(fd); 13898e0cf965SAdrian Hunter return -EINVAL; 13908e0cf965SAdrian Hunter } 13918e0cf965SAdrian Hunter 1392d9b62abaSAdrian Hunter /* 1393d9b62abaSAdrian Hunter * If the kernel is relocated at boot time, kallsyms won't match. Compute the 1394d9b62abaSAdrian Hunter * delta based on the relocation reference symbol. 1395d9b62abaSAdrian Hunter */ 1396019c6820SArnaldo Carvalho de Melo static int kallsyms__delta(struct kmap *kmap, const char *filename, u64 *delta) 1397d9b62abaSAdrian Hunter { 1398d9b62abaSAdrian Hunter u64 addr; 1399d9b62abaSAdrian Hunter 1400d9b62abaSAdrian Hunter if (!kmap->ref_reloc_sym || !kmap->ref_reloc_sym->name) 1401d9b62abaSAdrian Hunter return 0; 1402d9b62abaSAdrian Hunter 1403b843f62aSArnaldo Carvalho de Melo if (kallsyms__get_function_start(filename, kmap->ref_reloc_sym->name, &addr)) 1404d9b62abaSAdrian Hunter return -1; 1405d9b62abaSAdrian Hunter 1406d9b62abaSAdrian Hunter *delta = addr - kmap->ref_reloc_sym->addr; 1407d9b62abaSAdrian Hunter return 0; 1408d9b62abaSAdrian Hunter } 1409d9b62abaSAdrian Hunter 1410e02092b9SArnaldo Carvalho de Melo int __dso__load_kallsyms(struct dso *dso, const char *filename, 1411be39db9fSArnaldo Carvalho de Melo struct map *map, bool no_kcore) 14122e538c4aSArnaldo Carvalho de Melo { 1413019c6820SArnaldo Carvalho de Melo struct kmap *kmap = map__kmap(map); 1414d9b62abaSAdrian Hunter u64 delta = 0; 1415d9b62abaSAdrian Hunter 1416ec80fde7SArnaldo Carvalho de Melo if (symbol__restricted_filename(filename, "/proc/kallsyms")) 1417ec80fde7SArnaldo Carvalho de Melo return -1; 1418ec80fde7SArnaldo Carvalho de Melo 1419019c6820SArnaldo Carvalho de Melo if (!kmap || !kmap->kmaps) 1420019c6820SArnaldo Carvalho de Melo return -1; 1421019c6820SArnaldo Carvalho de Melo 1422333cc76cSArnaldo Carvalho de Melo if (dso__load_all_kallsyms(dso, filename) < 0) 14232e538c4aSArnaldo Carvalho de Melo return -1; 14242e538c4aSArnaldo Carvalho de Melo 1425019c6820SArnaldo Carvalho de Melo if (kallsyms__delta(kmap, filename, &delta)) 1426d9b62abaSAdrian Hunter return -1; 1427d9b62abaSAdrian Hunter 14283183f8caSArnaldo Carvalho de Melo symbols__fixup_end(&dso->symbols); 14293183f8caSArnaldo Carvalho de Melo symbols__fixup_duplicate(&dso->symbols); 14303f5a4272SAnton Blanchard 1431aeafcbafSArnaldo Carvalho de Melo if (dso->kernel == DSO_TYPE_GUEST_KERNEL) 143244f24cb3SJiri Olsa dso->symtab_type = DSO_BINARY_TYPE__GUEST_KALLSYMS; 1433a1645ce1SZhang, Yanmin else 143444f24cb3SJiri Olsa dso->symtab_type = DSO_BINARY_TYPE__KALLSYMS; 14352e538c4aSArnaldo Carvalho de Melo 1436e02092b9SArnaldo Carvalho de Melo if (!no_kcore && !dso__load_kcore(dso, map, filename)) 143779b6bb73SArnaldo Carvalho de Melo return maps__split_kallsyms_for_kcore(kmap->kmaps, dso); 14388e0cf965SAdrian Hunter else 143979b6bb73SArnaldo Carvalho de Melo return maps__split_kallsyms(kmap->kmaps, dso, delta, map); 1440af427bf5SArnaldo Carvalho de Melo } 1441af427bf5SArnaldo Carvalho de Melo 1442e02092b9SArnaldo Carvalho de Melo int dso__load_kallsyms(struct dso *dso, const char *filename, 1443be39db9fSArnaldo Carvalho de Melo struct map *map) 1444e02092b9SArnaldo Carvalho de Melo { 1445be39db9fSArnaldo Carvalho de Melo return __dso__load_kallsyms(dso, filename, map, false); 1446e02092b9SArnaldo Carvalho de Melo } 1447e02092b9SArnaldo Carvalho de Melo 14483183f8caSArnaldo Carvalho de Melo static int dso__load_perf_map(const char *map_path, struct dso *dso) 144980d496beSPekka Enberg { 145080d496beSPekka Enberg char *line = NULL; 145180d496beSPekka Enberg size_t n; 145280d496beSPekka Enberg FILE *file; 145380d496beSPekka Enberg int nr_syms = 0; 145480d496beSPekka Enberg 1455bf2e710bSKrister Johansen file = fopen(map_path, "r"); 145680d496beSPekka Enberg if (file == NULL) 145780d496beSPekka Enberg goto out_failure; 145880d496beSPekka Enberg 145980d496beSPekka Enberg while (!feof(file)) { 14609cffa8d5SPaul Mackerras u64 start, size; 146180d496beSPekka Enberg struct symbol *sym; 146280d496beSPekka Enberg int line_len, len; 146380d496beSPekka Enberg 146480d496beSPekka Enberg line_len = getline(&line, &n, file); 146580d496beSPekka Enberg if (line_len < 0) 146680d496beSPekka Enberg break; 146780d496beSPekka Enberg 146880d496beSPekka Enberg if (!line) 146980d496beSPekka Enberg goto out_failure; 147080d496beSPekka Enberg 147180d496beSPekka Enberg line[--line_len] = '\0'; /* \n */ 147280d496beSPekka Enberg 147380d496beSPekka Enberg len = hex2u64(line, &start); 147480d496beSPekka Enberg 147580d496beSPekka Enberg len++; 147680d496beSPekka Enberg if (len + 2 >= line_len) 147780d496beSPekka Enberg continue; 147880d496beSPekka Enberg 147980d496beSPekka Enberg len += hex2u64(line + len, &size); 148080d496beSPekka Enberg 148180d496beSPekka Enberg len++; 148280d496beSPekka Enberg if (len + 2 >= line_len) 148380d496beSPekka Enberg continue; 148480d496beSPekka Enberg 1485af30bffaSArnaldo Carvalho de Melo sym = symbol__new(start, size, STB_GLOBAL, STT_FUNC, line + len); 148680d496beSPekka Enberg 148780d496beSPekka Enberg if (sym == NULL) 148880d496beSPekka Enberg goto out_delete_line; 148980d496beSPekka Enberg 14903183f8caSArnaldo Carvalho de Melo symbols__insert(&dso->symbols, sym); 149180d496beSPekka Enberg nr_syms++; 149280d496beSPekka Enberg } 149380d496beSPekka Enberg 149480d496beSPekka Enberg free(line); 149580d496beSPekka Enberg fclose(file); 149680d496beSPekka Enberg 149780d496beSPekka Enberg return nr_syms; 149880d496beSPekka Enberg 149980d496beSPekka Enberg out_delete_line: 150080d496beSPekka Enberg free(line); 150180d496beSPekka Enberg out_failure: 150280d496beSPekka Enberg return -1; 150380d496beSPekka Enberg } 150480d496beSPekka Enberg 15051029f9feSNamhyung Kim static bool dso__is_compatible_symtab_type(struct dso *dso, bool kmod, 15061029f9feSNamhyung Kim enum dso_binary_type type) 15071029f9feSNamhyung Kim { 15081029f9feSNamhyung Kim switch (type) { 15091029f9feSNamhyung Kim case DSO_BINARY_TYPE__JAVA_JIT: 15101029f9feSNamhyung Kim case DSO_BINARY_TYPE__DEBUGLINK: 15111029f9feSNamhyung Kim case DSO_BINARY_TYPE__SYSTEM_PATH_DSO: 15121029f9feSNamhyung Kim case DSO_BINARY_TYPE__FEDORA_DEBUGINFO: 15131029f9feSNamhyung Kim case DSO_BINARY_TYPE__UBUNTU_DEBUGINFO: 15141029f9feSNamhyung Kim case DSO_BINARY_TYPE__BUILDID_DEBUGINFO: 15151029f9feSNamhyung Kim case DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO: 15161029f9feSNamhyung Kim return !kmod && dso->kernel == DSO_TYPE_USER; 15171029f9feSNamhyung Kim 15181029f9feSNamhyung Kim case DSO_BINARY_TYPE__KALLSYMS: 15191029f9feSNamhyung Kim case DSO_BINARY_TYPE__VMLINUX: 15201029f9feSNamhyung Kim case DSO_BINARY_TYPE__KCORE: 15211029f9feSNamhyung Kim return dso->kernel == DSO_TYPE_KERNEL; 15221029f9feSNamhyung Kim 15231029f9feSNamhyung Kim case DSO_BINARY_TYPE__GUEST_KALLSYMS: 15241029f9feSNamhyung Kim case DSO_BINARY_TYPE__GUEST_VMLINUX: 15251029f9feSNamhyung Kim case DSO_BINARY_TYPE__GUEST_KCORE: 15261029f9feSNamhyung Kim return dso->kernel == DSO_TYPE_GUEST_KERNEL; 15271029f9feSNamhyung Kim 15281029f9feSNamhyung Kim case DSO_BINARY_TYPE__GUEST_KMODULE: 1529c00c48fcSNamhyung Kim case DSO_BINARY_TYPE__GUEST_KMODULE_COMP: 15301029f9feSNamhyung Kim case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE: 1531c00c48fcSNamhyung Kim case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP: 15321029f9feSNamhyung Kim /* 15331029f9feSNamhyung Kim * kernel modules know their symtab type - it's set when 1534a94ab91aSArnaldo Carvalho de Melo * creating a module dso in machine__addnew_module_map(). 15351029f9feSNamhyung Kim */ 15361029f9feSNamhyung Kim return kmod && dso->symtab_type == type; 15371029f9feSNamhyung Kim 15381029f9feSNamhyung Kim case DSO_BINARY_TYPE__BUILD_ID_CACHE: 1539d2396999SKrister Johansen case DSO_BINARY_TYPE__BUILD_ID_CACHE_DEBUGINFO: 15401029f9feSNamhyung Kim return true; 15411029f9feSNamhyung Kim 15429b86d04dSSong Liu case DSO_BINARY_TYPE__BPF_PROG_INFO: 15431029f9feSNamhyung Kim case DSO_BINARY_TYPE__NOT_FOUND: 15441029f9feSNamhyung Kim default: 15451029f9feSNamhyung Kim return false; 15461029f9feSNamhyung Kim } 15471029f9feSNamhyung Kim } 15481029f9feSNamhyung Kim 1549bf2e710bSKrister Johansen /* Checks for the existence of the perf-<pid>.map file in two different 1550bf2e710bSKrister Johansen * locations. First, if the process is a separate mount namespace, check in 1551bf2e710bSKrister Johansen * that namespace using the pid of the innermost pid namespace. If's not in a 1552bf2e710bSKrister Johansen * namespace, or the file can't be found there, try in the mount namespace of 1553bf2e710bSKrister Johansen * the tracing process using our view of its pid. 1554bf2e710bSKrister Johansen */ 1555bf2e710bSKrister Johansen static int dso__find_perf_map(char *filebuf, size_t bufsz, 1556bf2e710bSKrister Johansen struct nsinfo **nsip) 1557bf2e710bSKrister Johansen { 1558bf2e710bSKrister Johansen struct nscookie nsc; 1559bf2e710bSKrister Johansen struct nsinfo *nsi; 1560bf2e710bSKrister Johansen struct nsinfo *nnsi; 1561bf2e710bSKrister Johansen int rc = -1; 1562bf2e710bSKrister Johansen 1563bf2e710bSKrister Johansen nsi = *nsip; 1564bf2e710bSKrister Johansen 1565bf2e710bSKrister Johansen if (nsi->need_setns) { 1566bf2e710bSKrister Johansen snprintf(filebuf, bufsz, "/tmp/perf-%d.map", nsi->nstgid); 1567bf2e710bSKrister Johansen nsinfo__mountns_enter(nsi, &nsc); 1568bf2e710bSKrister Johansen rc = access(filebuf, R_OK); 1569bf2e710bSKrister Johansen nsinfo__mountns_exit(&nsc); 1570bf2e710bSKrister Johansen if (rc == 0) 1571bf2e710bSKrister Johansen return rc; 1572bf2e710bSKrister Johansen } 1573bf2e710bSKrister Johansen 1574bf2e710bSKrister Johansen nnsi = nsinfo__copy(nsi); 1575bf2e710bSKrister Johansen if (nnsi) { 1576bf2e710bSKrister Johansen nsinfo__put(nsi); 1577bf2e710bSKrister Johansen 1578bf2e710bSKrister Johansen nnsi->need_setns = false; 1579bf2e710bSKrister Johansen snprintf(filebuf, bufsz, "/tmp/perf-%d.map", nnsi->tgid); 1580bf2e710bSKrister Johansen *nsip = nnsi; 1581bf2e710bSKrister Johansen rc = 0; 1582bf2e710bSKrister Johansen } 1583bf2e710bSKrister Johansen 1584bf2e710bSKrister Johansen return rc; 1585bf2e710bSKrister Johansen } 1586bf2e710bSKrister Johansen 1587be39db9fSArnaldo Carvalho de Melo int dso__load(struct dso *dso, struct map *map) 158886470930SIngo Molnar { 1589c338aee8SArnaldo Carvalho de Melo char *name; 159086470930SIngo Molnar int ret = -1; 159144f24cb3SJiri Olsa u_int i; 159293fcce96SArnaldo Carvalho de Melo struct machine *machine = NULL; 159344f24cb3SJiri Olsa char *root_dir = (char *) ""; 15943aafe5aeSCody P Schafer int ss_pos = 0; 15953aafe5aeSCody P Schafer struct symsrc ss_[2]; 15963aafe5aeSCody P Schafer struct symsrc *syms_ss = NULL, *runtime_ss = NULL; 15971029f9feSNamhyung Kim bool kmod; 1598bf2e710bSKrister Johansen bool perfmap; 15995baecbcdSDima Kogan unsigned char build_id[BUILD_ID_SIZE]; 1600843ff37bSKrister Johansen struct nscookie nsc; 1601bf2e710bSKrister Johansen char newmapname[PATH_MAX]; 1602bf2e710bSKrister Johansen const char *map_path = dso->long_name; 1603bf2e710bSKrister Johansen 1604bf2e710bSKrister Johansen perfmap = strncmp(dso->name, "/tmp/perf-", 10) == 0; 1605bf2e710bSKrister Johansen if (perfmap) { 1606bf2e710bSKrister Johansen if (dso->nsinfo && (dso__find_perf_map(newmapname, 1607bf2e710bSKrister Johansen sizeof(newmapname), &dso->nsinfo) == 0)) { 1608bf2e710bSKrister Johansen map_path = newmapname; 1609bf2e710bSKrister Johansen } 1610bf2e710bSKrister Johansen } 161186470930SIngo Molnar 1612843ff37bSKrister Johansen nsinfo__mountns_enter(dso->nsinfo, &nsc); 16134a936edcSNamhyung Kim pthread_mutex_lock(&dso->lock); 161466bd8424SArnaldo Carvalho de Melo 16154a936edcSNamhyung Kim /* check again under the dso->lock */ 16163183f8caSArnaldo Carvalho de Melo if (dso__loaded(dso)) { 16174a936edcSNamhyung Kim ret = 1; 16184a936edcSNamhyung Kim goto out; 16194a936edcSNamhyung Kim } 16204a936edcSNamhyung Kim 16214a936edcSNamhyung Kim if (dso->kernel) { 1622aeafcbafSArnaldo Carvalho de Melo if (dso->kernel == DSO_TYPE_KERNEL) 1623be39db9fSArnaldo Carvalho de Melo ret = dso__load_kernel_sym(dso, map); 1624aeafcbafSArnaldo Carvalho de Melo else if (dso->kernel == DSO_TYPE_GUEST_KERNEL) 1625be39db9fSArnaldo Carvalho de Melo ret = dso__load_guest_kernel_sym(dso, map); 16264a936edcSNamhyung Kim 162793fcce96SArnaldo Carvalho de Melo machine = map__kmaps(map)->machine; 16284d99e413SAdrian Hunter if (machine__is(machine, "x86_64")) 16294d99e413SAdrian Hunter machine__map_x86_64_entry_trampolines(machine, dso); 16304a936edcSNamhyung Kim goto out; 16314a936edcSNamhyung Kim } 1632a1645ce1SZhang, Yanmin 1633aeafcbafSArnaldo Carvalho de Melo dso->adjust_symbols = 0; 1634f5812a7aSArnaldo Carvalho de Melo 1635bf2e710bSKrister Johansen if (perfmap) { 16363183f8caSArnaldo Carvalho de Melo ret = dso__load_perf_map(map_path, dso); 163744f24cb3SJiri Olsa dso->symtab_type = ret > 0 ? DSO_BINARY_TYPE__JAVA_JIT : 163844f24cb3SJiri Olsa DSO_BINARY_TYPE__NOT_FOUND; 16394a936edcSNamhyung Kim goto out; 164094cb9e38SArnaldo Carvalho de Melo } 164194cb9e38SArnaldo Carvalho de Melo 164244f24cb3SJiri Olsa if (machine) 164344f24cb3SJiri Olsa root_dir = machine->root_dir; 164444f24cb3SJiri Olsa 1645164c800eSDavid Ahern name = malloc(PATH_MAX); 1646164c800eSDavid Ahern if (!name) 16474a936edcSNamhyung Kim goto out; 1648164c800eSDavid Ahern 16491029f9feSNamhyung Kim kmod = dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE || 1650c00c48fcSNamhyung Kim dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP || 1651c00c48fcSNamhyung Kim dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE || 1652c00c48fcSNamhyung Kim dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE_COMP; 16531029f9feSNamhyung Kim 16545baecbcdSDima Kogan 16555baecbcdSDima Kogan /* 16565baecbcdSDima Kogan * Read the build id if possible. This is required for 16575baecbcdSDima Kogan * DSO_BINARY_TYPE__BUILDID_DEBUGINFO to work 16585baecbcdSDima Kogan */ 1659ed6c166cSKan Liang if (!dso->has_build_id && 16609b200653SVictor Kamensky is_regular_file(dso->long_name)) { 16619b200653SVictor Kamensky __symbol__join_symfs(name, PATH_MAX, dso->long_name); 16629b200653SVictor Kamensky if (filename__read_build_id(name, build_id, BUILD_ID_SIZE) > 0) 16635baecbcdSDima Kogan dso__set_build_id(dso, build_id); 16649b200653SVictor Kamensky } 16655baecbcdSDima Kogan 16661029f9feSNamhyung Kim /* 16671029f9feSNamhyung Kim * Iterate over candidate debug images. 16683aafe5aeSCody P Schafer * Keep track of "interesting" ones (those which have a symtab, dynsym, 16693aafe5aeSCody P Schafer * and/or opd section) for processing. 16706da80ce8SDave Martin */ 167144f24cb3SJiri Olsa for (i = 0; i < DSO_BINARY_TYPE__SYMTAB_CNT; i++) { 16723aafe5aeSCody P Schafer struct symsrc *ss = &ss_[ss_pos]; 16733aafe5aeSCody P Schafer bool next_slot = false; 1674f045b8c4SKrister Johansen bool is_reg; 1675d2396999SKrister Johansen bool nsexit; 1676c3962961SJiri Olsa int sirc = -1; 167744f24cb3SJiri Olsa 1678005f9294SCody P Schafer enum dso_binary_type symtab_type = binary_type_symtab[i]; 167944f24cb3SJiri Olsa 1680d2396999SKrister Johansen nsexit = (symtab_type == DSO_BINARY_TYPE__BUILD_ID_CACHE || 1681d2396999SKrister Johansen symtab_type == DSO_BINARY_TYPE__BUILD_ID_CACHE_DEBUGINFO); 1682d2396999SKrister Johansen 16831029f9feSNamhyung Kim if (!dso__is_compatible_symtab_type(dso, kmod, symtab_type)) 16841029f9feSNamhyung Kim continue; 16851029f9feSNamhyung Kim 1686ee4e9625SArnaldo Carvalho de Melo if (dso__read_binary_type_filename(dso, symtab_type, 168744f24cb3SJiri Olsa root_dir, name, PATH_MAX)) 16886da80ce8SDave Martin continue; 168986470930SIngo Molnar 1690d2396999SKrister Johansen if (nsexit) 1691f045b8c4SKrister Johansen nsinfo__mountns_exit(&nsc); 169240356721SJiri Olsa 1693f045b8c4SKrister Johansen is_reg = is_regular_file(name); 1694c3962961SJiri Olsa if (is_reg) 1695f045b8c4SKrister Johansen sirc = symsrc__init(ss, dso, name, symtab_type); 1696f045b8c4SKrister Johansen 1697d2396999SKrister Johansen if (nsexit) 1698f045b8c4SKrister Johansen nsinfo__mountns_enter(dso->nsinfo, &nsc); 1699f045b8c4SKrister Johansen 1700c3962961SJiri Olsa if (!is_reg || sirc < 0) 17016da80ce8SDave Martin continue; 17026da80ce8SDave Martin 17033aafe5aeSCody P Schafer if (!syms_ss && symsrc__has_symtab(ss)) { 17043aafe5aeSCody P Schafer syms_ss = ss; 17053aafe5aeSCody P Schafer next_slot = true; 17060058aef6SAdrian Hunter if (!dso->symsrc_filename) 17070058aef6SAdrian Hunter dso->symsrc_filename = strdup(name); 1708d26cd12bSCody P Schafer } 1709d26cd12bSCody P Schafer 17103aafe5aeSCody P Schafer if (!runtime_ss && symsrc__possibly_runtime(ss)) { 17113aafe5aeSCody P Schafer runtime_ss = ss; 17123aafe5aeSCody P Schafer next_slot = true; 1713a44f605bSCody P Schafer } 171486470930SIngo Molnar 17153aafe5aeSCody P Schafer if (next_slot) { 17163aafe5aeSCody P Schafer ss_pos++; 171733ff581eSJiri Olsa 17183aafe5aeSCody P Schafer if (syms_ss && runtime_ss) 17196da80ce8SDave Martin break; 172098e9f03bSNamhyung Kim } else { 172198e9f03bSNamhyung Kim symsrc__destroy(ss); 1722a25e46c4SArnaldo Carvalho de Melo } 17233aafe5aeSCody P Schafer 17246da80ce8SDave Martin } 17256da80ce8SDave Martin 17263aafe5aeSCody P Schafer if (!runtime_ss && !syms_ss) 17273aafe5aeSCody P Schafer goto out_free; 17283aafe5aeSCody P Schafer 17293aafe5aeSCody P Schafer if (runtime_ss && !syms_ss) { 17303aafe5aeSCody P Schafer syms_ss = runtime_ss; 173160e4b10cSArnaldo Carvalho de Melo } 173260e4b10cSArnaldo Carvalho de Melo 17333aafe5aeSCody P Schafer /* We'll have to hope for the best */ 17343aafe5aeSCody P Schafer if (!runtime_ss && syms_ss) 17353aafe5aeSCody P Schafer runtime_ss = syms_ss; 17363aafe5aeSCody P Schafer 17371029f9feSNamhyung Kim if (syms_ss) 1738be39db9fSArnaldo Carvalho de Melo ret = dso__load_sym(dso, map, syms_ss, runtime_ss, kmod); 17391029f9feSNamhyung Kim else 17403aafe5aeSCody P Schafer ret = -1; 17413aafe5aeSCody P Schafer 1742f47b58b7SDavid Ahern if (ret > 0) { 17433aafe5aeSCody P Schafer int nr_plt; 17443aafe5aeSCody P Schafer 17453183f8caSArnaldo Carvalho de Melo nr_plt = dso__synthesize_plt_symbols(dso, runtime_ss); 17463aafe5aeSCody P Schafer if (nr_plt > 0) 17473aafe5aeSCody P Schafer ret += nr_plt; 17483aafe5aeSCody P Schafer } 17493aafe5aeSCody P Schafer 17503aafe5aeSCody P Schafer for (; ss_pos > 0; ss_pos--) 17513aafe5aeSCody P Schafer symsrc__destroy(&ss_[ss_pos - 1]); 17523aafe5aeSCody P Schafer out_free: 175386470930SIngo Molnar free(name); 1754aeafcbafSArnaldo Carvalho de Melo if (ret < 0 && strstr(dso->name, " (deleted)") != NULL) 17554a936edcSNamhyung Kim ret = 0; 17564a936edcSNamhyung Kim out: 17573183f8caSArnaldo Carvalho de Melo dso__set_loaded(dso); 17584a936edcSNamhyung Kim pthread_mutex_unlock(&dso->lock); 1759843ff37bSKrister Johansen nsinfo__mountns_exit(&nsc); 17604a936edcSNamhyung Kim 176186470930SIngo Molnar return ret; 176286470930SIngo Molnar } 176386470930SIngo Molnar 1764a7c2b572SArnaldo Carvalho de Melo static int map__strcmp(const void *a, const void *b) 1765a7c2b572SArnaldo Carvalho de Melo { 1766a7c2b572SArnaldo Carvalho de Melo const struct map *ma = *(const struct map **)a, *mb = *(const struct map **)b; 1767a7c2b572SArnaldo Carvalho de Melo return strcmp(ma->dso->short_name, mb->dso->short_name); 1768a7c2b572SArnaldo Carvalho de Melo } 1769a7c2b572SArnaldo Carvalho de Melo 1770a7c2b572SArnaldo Carvalho de Melo static int map__strcmp_name(const void *name, const void *b) 1771a7c2b572SArnaldo Carvalho de Melo { 1772a7c2b572SArnaldo Carvalho de Melo const struct map *map = *(const struct map **)b; 1773a7c2b572SArnaldo Carvalho de Melo return strcmp(name, map->dso->short_name); 1774a7c2b572SArnaldo Carvalho de Melo } 1775a7c2b572SArnaldo Carvalho de Melo 17769a29ceeeSArnaldo Carvalho de Melo void __maps__sort_by_name(struct maps *maps) 1777a7c2b572SArnaldo Carvalho de Melo { 17789a29ceeeSArnaldo Carvalho de Melo qsort(maps->maps_by_name, maps->nr_maps, sizeof(struct map *), map__strcmp); 1779a7c2b572SArnaldo Carvalho de Melo } 1780a7c2b572SArnaldo Carvalho de Melo 17819a29ceeeSArnaldo Carvalho de Melo static int map__groups__sort_by_name_from_rbtree(struct maps *maps) 1782a7c2b572SArnaldo Carvalho de Melo { 1783a7c2b572SArnaldo Carvalho de Melo struct map *map; 17849a29ceeeSArnaldo Carvalho de Melo struct map **maps_by_name = realloc(maps->maps_by_name, maps->nr_maps * sizeof(map)); 1785a7c2b572SArnaldo Carvalho de Melo int i = 0; 1786a7c2b572SArnaldo Carvalho de Melo 1787a7c2b572SArnaldo Carvalho de Melo if (maps_by_name == NULL) 1788a7c2b572SArnaldo Carvalho de Melo return -1; 1789a7c2b572SArnaldo Carvalho de Melo 17909a29ceeeSArnaldo Carvalho de Melo maps->maps_by_name = maps_by_name; 17919a29ceeeSArnaldo Carvalho de Melo maps->nr_maps_allocated = maps->nr_maps; 1792a7c2b572SArnaldo Carvalho de Melo 17939a29ceeeSArnaldo Carvalho de Melo maps__for_each_entry(maps, map) 1794a7c2b572SArnaldo Carvalho de Melo maps_by_name[i++] = map; 1795a7c2b572SArnaldo Carvalho de Melo 17969a29ceeeSArnaldo Carvalho de Melo __maps__sort_by_name(maps); 1797a7c2b572SArnaldo Carvalho de Melo return 0; 1798a7c2b572SArnaldo Carvalho de Melo } 1799a7c2b572SArnaldo Carvalho de Melo 18009a29ceeeSArnaldo Carvalho de Melo static struct map *__maps__find_by_name(struct maps *maps, const char *name) 1801a7c2b572SArnaldo Carvalho de Melo { 1802a7c2b572SArnaldo Carvalho de Melo struct map **mapp; 1803a7c2b572SArnaldo Carvalho de Melo 18049a29ceeeSArnaldo Carvalho de Melo if (maps->maps_by_name == NULL && 18059a29ceeeSArnaldo Carvalho de Melo map__groups__sort_by_name_from_rbtree(maps)) 1806a7c2b572SArnaldo Carvalho de Melo return NULL; 1807a7c2b572SArnaldo Carvalho de Melo 18089a29ceeeSArnaldo Carvalho de Melo mapp = bsearch(name, maps->maps_by_name, maps->nr_maps, sizeof(*mapp), map__strcmp_name); 1809a7c2b572SArnaldo Carvalho de Melo if (mapp) 1810a7c2b572SArnaldo Carvalho de Melo return *mapp; 1811a7c2b572SArnaldo Carvalho de Melo return NULL; 1812a7c2b572SArnaldo Carvalho de Melo } 1813a7c2b572SArnaldo Carvalho de Melo 18149a29ceeeSArnaldo Carvalho de Melo struct map *maps__find_by_name(struct maps *maps, const char *name) 1815439d473bSArnaldo Carvalho de Melo { 18164bb7123dSArnaldo Carvalho de Melo struct map *map; 1817439d473bSArnaldo Carvalho de Melo 18180a7c74eaSArnaldo Carvalho de Melo down_read(&maps->lock); 18196a2ffcddSArnaldo Carvalho de Melo 18209a29ceeeSArnaldo Carvalho de Melo if (maps->last_search_by_name && strcmp(maps->last_search_by_name->dso->short_name, name) == 0) { 18219a29ceeeSArnaldo Carvalho de Melo map = maps->last_search_by_name; 18226a2ffcddSArnaldo Carvalho de Melo goto out_unlock; 18231ae14516SArnaldo Carvalho de Melo } 1824a7c2b572SArnaldo Carvalho de Melo /* 18259a29ceeeSArnaldo Carvalho de Melo * If we have maps->maps_by_name, then the name isn't in the rbtree, 18269a29ceeeSArnaldo Carvalho de Melo * as maps->maps_by_name mirrors the rbtree when lookups by name are 1827a7c2b572SArnaldo Carvalho de Melo * made. 1828a7c2b572SArnaldo Carvalho de Melo */ 18299a29ceeeSArnaldo Carvalho de Melo map = __maps__find_by_name(maps, name); 18309a29ceeeSArnaldo Carvalho de Melo if (map || maps->maps_by_name != NULL) 1831a7c2b572SArnaldo Carvalho de Melo goto out_unlock; 18321ae14516SArnaldo Carvalho de Melo 1833a7c2b572SArnaldo Carvalho de Melo /* Fallback to traversing the rbtree... */ 18341ae14516SArnaldo Carvalho de Melo maps__for_each_entry(maps, map) 18351ae14516SArnaldo Carvalho de Melo if (strcmp(map->dso->short_name, name) == 0) { 18369a29ceeeSArnaldo Carvalho de Melo maps->last_search_by_name = map; 18371ae14516SArnaldo Carvalho de Melo goto out_unlock; 18381ae14516SArnaldo Carvalho de Melo } 1839439d473bSArnaldo Carvalho de Melo 18406a2ffcddSArnaldo Carvalho de Melo map = NULL; 18416a2ffcddSArnaldo Carvalho de Melo 18426a2ffcddSArnaldo Carvalho de Melo out_unlock: 18430a7c74eaSArnaldo Carvalho de Melo up_read(&maps->lock); 18446a2ffcddSArnaldo Carvalho de Melo return map; 1845439d473bSArnaldo Carvalho de Melo } 1846439d473bSArnaldo Carvalho de Melo 1847aeafcbafSArnaldo Carvalho de Melo int dso__load_vmlinux(struct dso *dso, struct map *map, 1848be39db9fSArnaldo Carvalho de Melo const char *vmlinux, bool vmlinux_allocated) 184986470930SIngo Molnar { 1850b68e2f91SCody P Schafer int err = -1; 1851b68e2f91SCody P Schafer struct symsrc ss; 1852ec5761eaSDavid Ahern char symfs_vmlinux[PATH_MAX]; 1853005f9294SCody P Schafer enum dso_binary_type symtab_type; 185486470930SIngo Molnar 18555698d2c9SNamhyung Kim if (vmlinux[0] == '/') 18565698d2c9SNamhyung Kim snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s", vmlinux); 18575698d2c9SNamhyung Kim else 1858972f393bSArnaldo Carvalho de Melo symbol__join_symfs(symfs_vmlinux, vmlinux); 185986470930SIngo Molnar 186021ea4539SCody P Schafer if (dso->kernel == DSO_TYPE_GUEST_KERNEL) 1861005f9294SCody P Schafer symtab_type = DSO_BINARY_TYPE__GUEST_VMLINUX; 186221ea4539SCody P Schafer else 1863005f9294SCody P Schafer symtab_type = DSO_BINARY_TYPE__VMLINUX; 186421ea4539SCody P Schafer 1865005f9294SCody P Schafer if (symsrc__init(&ss, dso, symfs_vmlinux, symtab_type)) 1866b68e2f91SCody P Schafer return -1; 1867b68e2f91SCody P Schafer 1868be39db9fSArnaldo Carvalho de Melo err = dso__load_sym(dso, map, &ss, &ss, 0); 1869b68e2f91SCody P Schafer symsrc__destroy(&ss); 187086470930SIngo Molnar 1871515850e4SCody P Schafer if (err > 0) { 187239b12f78SAdrian Hunter if (dso->kernel == DSO_TYPE_GUEST_KERNEL) 18735f70619dSArnaldo Carvalho de Melo dso->binary_type = DSO_BINARY_TYPE__GUEST_VMLINUX; 187439b12f78SAdrian Hunter else 18755f70619dSArnaldo Carvalho de Melo dso->binary_type = DSO_BINARY_TYPE__VMLINUX; 1876bf4414aeSArnaldo Carvalho de Melo dso__set_long_name(dso, vmlinux, vmlinux_allocated); 18773183f8caSArnaldo Carvalho de Melo dso__set_loaded(dso); 1878ec5761eaSDavid Ahern pr_debug("Using %s for symbols\n", symfs_vmlinux); 1879515850e4SCody P Schafer } 18803846df2eSArnaldo Carvalho de Melo 188186470930SIngo Molnar return err; 188286470930SIngo Molnar } 188386470930SIngo Molnar 1884be39db9fSArnaldo Carvalho de Melo int dso__load_vmlinux_path(struct dso *dso, struct map *map) 1885a19afe46SArnaldo Carvalho de Melo { 1886a19afe46SArnaldo Carvalho de Melo int i, err = 0; 188700dc8657SNamhyung Kim char *filename = NULL; 1888a19afe46SArnaldo Carvalho de Melo 1889dc38218eSArnaldo Carvalho de Melo pr_debug("Looking at the vmlinux_path (%d entries long)\n", 1890dc38218eSArnaldo Carvalho de Melo vmlinux_path__nr_entries + 1); 1891dc38218eSArnaldo Carvalho de Melo 1892dc38218eSArnaldo Carvalho de Melo for (i = 0; i < vmlinux_path__nr_entries; ++i) { 1893be39db9fSArnaldo Carvalho de Melo err = dso__load_vmlinux(dso, map, vmlinux_path[i], false); 1894dc38218eSArnaldo Carvalho de Melo if (err > 0) 1895dc38218eSArnaldo Carvalho de Melo goto out; 1896dc38218eSArnaldo Carvalho de Melo } 1897dc38218eSArnaldo Carvalho de Melo 189800dc8657SNamhyung Kim if (!symbol_conf.ignore_vmlinux_buildid) 1899d2396999SKrister Johansen filename = dso__build_id_filename(dso, NULL, 0, false); 19005ad90e4eSArnaldo Carvalho de Melo if (filename != NULL) { 1901be39db9fSArnaldo Carvalho de Melo err = dso__load_vmlinux(dso, map, filename, true); 19025230fb7dSArnaldo Carvalho de Melo if (err > 0) 19035ad90e4eSArnaldo Carvalho de Melo goto out; 19045ad90e4eSArnaldo Carvalho de Melo free(filename); 19055ad90e4eSArnaldo Carvalho de Melo } 19065ad90e4eSArnaldo Carvalho de Melo out: 1907a19afe46SArnaldo Carvalho de Melo return err; 1908a19afe46SArnaldo Carvalho de Melo } 1909a19afe46SArnaldo Carvalho de Melo 1910c48903b8SMasami Hiramatsu static bool visible_dir_filter(const char *name, struct dirent *d) 1911c48903b8SMasami Hiramatsu { 1912c48903b8SMasami Hiramatsu if (d->d_type != DT_DIR) 1913c48903b8SMasami Hiramatsu return false; 1914c48903b8SMasami Hiramatsu return lsdir_no_dot_filter(name, d); 1915c48903b8SMasami Hiramatsu } 1916c48903b8SMasami Hiramatsu 19170544d422SAdrian Hunter static int find_matching_kcore(struct map *map, char *dir, size_t dir_sz) 19180544d422SAdrian Hunter { 19190544d422SAdrian Hunter char kallsyms_filename[PATH_MAX]; 19200544d422SAdrian Hunter int ret = -1; 1921c48903b8SMasami Hiramatsu struct strlist *dirs; 1922c48903b8SMasami Hiramatsu struct str_node *nd; 19230544d422SAdrian Hunter 1924c48903b8SMasami Hiramatsu dirs = lsdir(dir, visible_dir_filter); 1925c48903b8SMasami Hiramatsu if (!dirs) 19260544d422SAdrian Hunter return -1; 19270544d422SAdrian Hunter 1928602a1f4dSArnaldo Carvalho de Melo strlist__for_each_entry(nd, dirs) { 19290544d422SAdrian Hunter scnprintf(kallsyms_filename, sizeof(kallsyms_filename), 1930c48903b8SMasami Hiramatsu "%s/%s/kallsyms", dir, nd->s); 1931a00d28cbSAdrian Hunter if (!validate_kcore_addresses(kallsyms_filename, map)) { 19320544d422SAdrian Hunter strlcpy(dir, kallsyms_filename, dir_sz); 19330544d422SAdrian Hunter ret = 0; 19340544d422SAdrian Hunter break; 19350544d422SAdrian Hunter } 19360544d422SAdrian Hunter } 19370544d422SAdrian Hunter 1938c48903b8SMasami Hiramatsu strlist__delete(dirs); 19390544d422SAdrian Hunter 19400544d422SAdrian Hunter return ret; 19410544d422SAdrian Hunter } 19420544d422SAdrian Hunter 194311870d71SMasami Hiramatsu /* 194411870d71SMasami Hiramatsu * Use open(O_RDONLY) to check readability directly instead of access(R_OK) 194511870d71SMasami Hiramatsu * since access(R_OK) only checks with real UID/GID but open() use effective 194611870d71SMasami Hiramatsu * UID/GID and actual capabilities (e.g. /proc/kcore requires CAP_SYS_RAWIO). 194711870d71SMasami Hiramatsu */ 194811870d71SMasami Hiramatsu static bool filename__readable(const char *file) 194911870d71SMasami Hiramatsu { 195011870d71SMasami Hiramatsu int fd = open(file, O_RDONLY); 195111870d71SMasami Hiramatsu if (fd < 0) 195211870d71SMasami Hiramatsu return false; 195311870d71SMasami Hiramatsu close(fd); 195411870d71SMasami Hiramatsu return true; 195511870d71SMasami Hiramatsu } 195611870d71SMasami Hiramatsu 19570544d422SAdrian Hunter static char *dso__find_kallsyms(struct dso *dso, struct map *map) 19580544d422SAdrian Hunter { 19590544d422SAdrian Hunter u8 host_build_id[BUILD_ID_SIZE]; 1960b5d8bbe8SMasami Hiramatsu char sbuild_id[SBUILD_ID_SIZE]; 19610544d422SAdrian Hunter bool is_host = false; 19620544d422SAdrian Hunter char path[PATH_MAX]; 19630544d422SAdrian Hunter 19640544d422SAdrian Hunter if (!dso->has_build_id) { 19650544d422SAdrian Hunter /* 19660544d422SAdrian Hunter * Last resort, if we don't have a build-id and couldn't find 19670544d422SAdrian Hunter * any vmlinux file, try the running kernel kallsyms table. 19680544d422SAdrian Hunter */ 19690544d422SAdrian Hunter goto proc_kallsyms; 19700544d422SAdrian Hunter } 19710544d422SAdrian Hunter 19720544d422SAdrian Hunter if (sysfs__read_build_id("/sys/kernel/notes", host_build_id, 19730544d422SAdrian Hunter sizeof(host_build_id)) == 0) 19740544d422SAdrian Hunter is_host = dso__build_id_equal(dso, host_build_id); 19750544d422SAdrian Hunter 19764e4b6c06SMasami Hiramatsu /* Try a fast path for /proc/kallsyms if possible */ 19770544d422SAdrian Hunter if (is_host) { 19780544d422SAdrian Hunter /* 197911870d71SMasami Hiramatsu * Do not check the build-id cache, unless we know we cannot use 198011870d71SMasami Hiramatsu * /proc/kcore or module maps don't match to /proc/kallsyms. 198111870d71SMasami Hiramatsu * To check readability of /proc/kcore, do not use access(R_OK) 198211870d71SMasami Hiramatsu * since /proc/kcore requires CAP_SYS_RAWIO to read and access 198311870d71SMasami Hiramatsu * can't check it. 19840544d422SAdrian Hunter */ 198511870d71SMasami Hiramatsu if (filename__readable("/proc/kcore") && 198611870d71SMasami Hiramatsu !validate_kcore_addresses("/proc/kallsyms", map)) 19870544d422SAdrian Hunter goto proc_kallsyms; 19880544d422SAdrian Hunter } 19890544d422SAdrian Hunter 19904e4b6c06SMasami Hiramatsu build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id); 19914e4b6c06SMasami Hiramatsu 1992449867e3SAdrian Hunter /* Find kallsyms in build-id cache with kcore */ 19934e4b6c06SMasami Hiramatsu scnprintf(path, sizeof(path), "%s/%s/%s", 19944e4b6c06SMasami Hiramatsu buildid_dir, DSO__NAME_KCORE, sbuild_id); 19954e4b6c06SMasami Hiramatsu 1996449867e3SAdrian Hunter if (!find_matching_kcore(map, path, sizeof(path))) 1997449867e3SAdrian Hunter return strdup(path); 1998449867e3SAdrian Hunter 19994e4b6c06SMasami Hiramatsu /* Use current /proc/kallsyms if possible */ 20004e4b6c06SMasami Hiramatsu if (is_host) { 20014e4b6c06SMasami Hiramatsu proc_kallsyms: 20024e4b6c06SMasami Hiramatsu return strdup("/proc/kallsyms"); 20034e4b6c06SMasami Hiramatsu } 20044e4b6c06SMasami Hiramatsu 20054e4b6c06SMasami Hiramatsu /* Finally, find a cache of kallsyms */ 200601412261SMasami Hiramatsu if (!build_id_cache__kallsyms_path(sbuild_id, path, sizeof(path))) { 20070544d422SAdrian Hunter pr_err("No kallsyms or vmlinux with build-id %s was found\n", 20080544d422SAdrian Hunter sbuild_id); 20090544d422SAdrian Hunter return NULL; 20100544d422SAdrian Hunter } 20110544d422SAdrian Hunter 20120544d422SAdrian Hunter return strdup(path); 20130544d422SAdrian Hunter } 20140544d422SAdrian Hunter 2015be39db9fSArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *dso, struct map *map) 201686470930SIngo Molnar { 2017cc612d81SArnaldo Carvalho de Melo int err; 20189e201442SArnaldo Carvalho de Melo const char *kallsyms_filename = NULL; 20199e201442SArnaldo Carvalho de Melo char *kallsyms_allocated_filename = NULL; 2020dc8d6ab2SArnaldo Carvalho de Melo /* 2021b226a5a7SDavid Ahern * Step 1: if the user specified a kallsyms or vmlinux filename, use 2022b226a5a7SDavid Ahern * it and only it, reporting errors to the user if it cannot be used. 2023dc8d6ab2SArnaldo Carvalho de Melo * 2024dc8d6ab2SArnaldo Carvalho de Melo * For instance, try to analyse an ARM perf.data file _without_ a 2025dc8d6ab2SArnaldo Carvalho de Melo * build-id, or if the user specifies the wrong path to the right 2026dc8d6ab2SArnaldo Carvalho de Melo * vmlinux file, obviously we can't fallback to another vmlinux (a 2027dc8d6ab2SArnaldo Carvalho de Melo * x86_86 one, on the machine where analysis is being performed, say), 2028dc8d6ab2SArnaldo Carvalho de Melo * or worse, /proc/kallsyms. 2029dc8d6ab2SArnaldo Carvalho de Melo * 2030dc8d6ab2SArnaldo Carvalho de Melo * If the specified file _has_ a build-id and there is a build-id 2031dc8d6ab2SArnaldo Carvalho de Melo * section in the perf.data file, we will still do the expected 2032dc8d6ab2SArnaldo Carvalho de Melo * validation in dso__load_vmlinux and will bail out if they don't 2033dc8d6ab2SArnaldo Carvalho de Melo * match. 2034dc8d6ab2SArnaldo Carvalho de Melo */ 2035b226a5a7SDavid Ahern if (symbol_conf.kallsyms_name != NULL) { 2036b226a5a7SDavid Ahern kallsyms_filename = symbol_conf.kallsyms_name; 2037b226a5a7SDavid Ahern goto do_kallsyms; 2038b226a5a7SDavid Ahern } 2039b226a5a7SDavid Ahern 2040fc2be696SWilly Tarreau if (!symbol_conf.ignore_vmlinux && symbol_conf.vmlinux_name != NULL) { 2041be39db9fSArnaldo Carvalho de Melo return dso__load_vmlinux(dso, map, symbol_conf.vmlinux_name, false); 2042dc8d6ab2SArnaldo Carvalho de Melo } 2043439d473bSArnaldo Carvalho de Melo 2044fc2be696SWilly Tarreau if (!symbol_conf.ignore_vmlinux && vmlinux_path != NULL) { 2045be39db9fSArnaldo Carvalho de Melo err = dso__load_vmlinux_path(dso, map); 2046a19afe46SArnaldo Carvalho de Melo if (err > 0) 204739b12f78SAdrian Hunter return err; 2048cc612d81SArnaldo Carvalho de Melo } 2049cc612d81SArnaldo Carvalho de Melo 2050ec5761eaSDavid Ahern /* do not try local files if a symfs was given */ 2051ec5761eaSDavid Ahern if (symbol_conf.symfs[0] != 0) 2052ec5761eaSDavid Ahern return -1; 2053ec5761eaSDavid Ahern 20540544d422SAdrian Hunter kallsyms_allocated_filename = dso__find_kallsyms(dso, map); 20550544d422SAdrian Hunter if (!kallsyms_allocated_filename) 20568d0591f6SArnaldo Carvalho de Melo return -1; 20578d0591f6SArnaldo Carvalho de Melo 205819fc2dedSArnaldo Carvalho de Melo kallsyms_filename = kallsyms_allocated_filename; 205919fc2dedSArnaldo Carvalho de Melo 2060dc8d6ab2SArnaldo Carvalho de Melo do_kallsyms: 2061be39db9fSArnaldo Carvalho de Melo err = dso__load_kallsyms(dso, kallsyms_filename, map); 20623846df2eSArnaldo Carvalho de Melo if (err > 0) 20633846df2eSArnaldo Carvalho de Melo pr_debug("Using %s for symbols\n", kallsyms_filename); 2064dc8d6ab2SArnaldo Carvalho de Melo free(kallsyms_allocated_filename); 2065dc8d6ab2SArnaldo Carvalho de Melo 20668e0cf965SAdrian Hunter if (err > 0 && !dso__is_kcore(dso)) { 2067bdac0bcfSAdrian Hunter dso->binary_type = DSO_BINARY_TYPE__KALLSYMS; 20680a77582fSMasami Hiramatsu dso__set_long_name(dso, DSO__NAME_KALLSYMS, false); 20696a4694a4SArnaldo Carvalho de Melo map__fixup_start(map); 20706a4694a4SArnaldo Carvalho de Melo map__fixup_end(map); 2071439d473bSArnaldo Carvalho de Melo } 207294cb9e38SArnaldo Carvalho de Melo 207386470930SIngo Molnar return err; 207486470930SIngo Molnar } 207586470930SIngo Molnar 2076be39db9fSArnaldo Carvalho de Melo static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map) 2077a1645ce1SZhang, Yanmin { 2078a1645ce1SZhang, Yanmin int err; 2079a1645ce1SZhang, Yanmin const char *kallsyms_filename = NULL; 208093fcce96SArnaldo Carvalho de Melo struct machine *machine = map__kmaps(map)->machine; 2081a1645ce1SZhang, Yanmin char path[PATH_MAX]; 2082a1645ce1SZhang, Yanmin 208323346f21SArnaldo Carvalho de Melo if (machine__is_default_guest(machine)) { 2084a1645ce1SZhang, Yanmin /* 2085a1645ce1SZhang, Yanmin * if the user specified a vmlinux filename, use it and only 2086a1645ce1SZhang, Yanmin * it, reporting errors to the user if it cannot be used. 2087a1645ce1SZhang, Yanmin * Or use file guest_kallsyms inputted by user on commandline 2088a1645ce1SZhang, Yanmin */ 2089a1645ce1SZhang, Yanmin if (symbol_conf.default_guest_vmlinux_name != NULL) { 2090aeafcbafSArnaldo Carvalho de Melo err = dso__load_vmlinux(dso, map, 20915230fb7dSArnaldo Carvalho de Melo symbol_conf.default_guest_vmlinux_name, 2092be39db9fSArnaldo Carvalho de Melo false); 209339b12f78SAdrian Hunter return err; 2094a1645ce1SZhang, Yanmin } 2095a1645ce1SZhang, Yanmin 2096a1645ce1SZhang, Yanmin kallsyms_filename = symbol_conf.default_guest_kallsyms; 2097a1645ce1SZhang, Yanmin if (!kallsyms_filename) 2098a1645ce1SZhang, Yanmin return -1; 2099a1645ce1SZhang, Yanmin } else { 210023346f21SArnaldo Carvalho de Melo sprintf(path, "%s/proc/kallsyms", machine->root_dir); 2101a1645ce1SZhang, Yanmin kallsyms_filename = path; 2102a1645ce1SZhang, Yanmin } 2103a1645ce1SZhang, Yanmin 2104be39db9fSArnaldo Carvalho de Melo err = dso__load_kallsyms(dso, kallsyms_filename, map); 21058e0cf965SAdrian Hunter if (err > 0) 210639b12f78SAdrian Hunter pr_debug("Using %s for symbols\n", kallsyms_filename); 21078e0cf965SAdrian Hunter if (err > 0 && !dso__is_kcore(dso)) { 2108bdac0bcfSAdrian Hunter dso->binary_type = DSO_BINARY_TYPE__GUEST_KALLSYMS; 21098c7f1bb3SJiri Olsa dso__set_long_name(dso, machine->mmap_name, false); 2110a1645ce1SZhang, Yanmin map__fixup_start(map); 2111a1645ce1SZhang, Yanmin map__fixup_end(map); 2112a1645ce1SZhang, Yanmin } 2113a1645ce1SZhang, Yanmin 2114a1645ce1SZhang, Yanmin return err; 2115a1645ce1SZhang, Yanmin } 2116cd84c2acSFrederic Weisbecker 2117cc612d81SArnaldo Carvalho de Melo static void vmlinux_path__exit(void) 21182446042cSArnaldo Carvalho de Melo { 211904662523SArnaldo Carvalho de Melo while (--vmlinux_path__nr_entries >= 0) 212004662523SArnaldo Carvalho de Melo zfree(&vmlinux_path[vmlinux_path__nr_entries]); 2121c4f03547SWang Nan vmlinux_path__nr_entries = 0; 2122cc612d81SArnaldo Carvalho de Melo 212304662523SArnaldo Carvalho de Melo zfree(&vmlinux_path); 2124cc612d81SArnaldo Carvalho de Melo } 2125cc612d81SArnaldo Carvalho de Melo 2126aac48647SEkaterina Tumanova static const char * const vmlinux_paths[] = { 2127aac48647SEkaterina Tumanova "vmlinux", 2128aac48647SEkaterina Tumanova "/boot/vmlinux" 2129aac48647SEkaterina Tumanova }; 2130aac48647SEkaterina Tumanova 2131aac48647SEkaterina Tumanova static const char * const vmlinux_paths_upd[] = { 2132aac48647SEkaterina Tumanova "/boot/vmlinux-%s", 2133aac48647SEkaterina Tumanova "/usr/lib/debug/boot/vmlinux-%s", 2134aac48647SEkaterina Tumanova "/lib/modules/%s/build/vmlinux", 2135f55ae954SEkaterina Tumanova "/usr/lib/debug/lib/modules/%s/vmlinux", 2136f55ae954SEkaterina Tumanova "/usr/lib/debug/boot/vmlinux-%s.debug" 2137aac48647SEkaterina Tumanova }; 2138aac48647SEkaterina Tumanova 2139aac48647SEkaterina Tumanova static int vmlinux_path__add(const char *new_entry) 2140aac48647SEkaterina Tumanova { 2141aac48647SEkaterina Tumanova vmlinux_path[vmlinux_path__nr_entries] = strdup(new_entry); 2142aac48647SEkaterina Tumanova if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 2143aac48647SEkaterina Tumanova return -1; 2144aac48647SEkaterina Tumanova ++vmlinux_path__nr_entries; 2145aac48647SEkaterina Tumanova 2146aac48647SEkaterina Tumanova return 0; 2147aac48647SEkaterina Tumanova } 2148aac48647SEkaterina Tumanova 2149ce80d3beSKan Liang static int vmlinux_path__init(struct perf_env *env) 2150cc612d81SArnaldo Carvalho de Melo { 2151cc612d81SArnaldo Carvalho de Melo struct utsname uts; 2152cc612d81SArnaldo Carvalho de Melo char bf[PATH_MAX]; 21530a7e6d1bSNamhyung Kim char *kernel_version; 2154aac48647SEkaterina Tumanova unsigned int i; 2155cc612d81SArnaldo Carvalho de Melo 2156aac48647SEkaterina Tumanova vmlinux_path = malloc(sizeof(char *) * (ARRAY_SIZE(vmlinux_paths) + 2157aac48647SEkaterina Tumanova ARRAY_SIZE(vmlinux_paths_upd))); 2158cc612d81SArnaldo Carvalho de Melo if (vmlinux_path == NULL) 2159cc612d81SArnaldo Carvalho de Melo return -1; 2160cc612d81SArnaldo Carvalho de Melo 2161aac48647SEkaterina Tumanova for (i = 0; i < ARRAY_SIZE(vmlinux_paths); i++) 2162aac48647SEkaterina Tumanova if (vmlinux_path__add(vmlinux_paths[i]) < 0) 2163cc612d81SArnaldo Carvalho de Melo goto out_fail; 2164ec5761eaSDavid Ahern 21650a7e6d1bSNamhyung Kim /* only try kernel version if no symfs was given */ 2166ec5761eaSDavid Ahern if (symbol_conf.symfs[0] != 0) 2167ec5761eaSDavid Ahern return 0; 2168ec5761eaSDavid Ahern 21690a7e6d1bSNamhyung Kim if (env) { 21700a7e6d1bSNamhyung Kim kernel_version = env->os_release; 21710a7e6d1bSNamhyung Kim } else { 2172ec5761eaSDavid Ahern if (uname(&uts) < 0) 2173e96c674fSNamhyung Kim goto out_fail; 2174ec5761eaSDavid Ahern 21750a7e6d1bSNamhyung Kim kernel_version = uts.release; 21760a7e6d1bSNamhyung Kim } 21770a7e6d1bSNamhyung Kim 2178aac48647SEkaterina Tumanova for (i = 0; i < ARRAY_SIZE(vmlinux_paths_upd); i++) { 2179aac48647SEkaterina Tumanova snprintf(bf, sizeof(bf), vmlinux_paths_upd[i], kernel_version); 2180aac48647SEkaterina Tumanova if (vmlinux_path__add(bf) < 0) 2181cc612d81SArnaldo Carvalho de Melo goto out_fail; 2182aac48647SEkaterina Tumanova } 2183cc612d81SArnaldo Carvalho de Melo 2184cc612d81SArnaldo Carvalho de Melo return 0; 2185cc612d81SArnaldo Carvalho de Melo 2186cc612d81SArnaldo Carvalho de Melo out_fail: 2187cc612d81SArnaldo Carvalho de Melo vmlinux_path__exit(); 2188cc612d81SArnaldo Carvalho de Melo return -1; 2189cc612d81SArnaldo Carvalho de Melo } 2190cc612d81SArnaldo Carvalho de Melo 21913bfe5f81SDavid Ahern int setup_list(struct strlist **list, const char *list_str, 2192655000e7SArnaldo Carvalho de Melo const char *list_name) 2193655000e7SArnaldo Carvalho de Melo { 2194655000e7SArnaldo Carvalho de Melo if (list_str == NULL) 2195655000e7SArnaldo Carvalho de Melo return 0; 2196655000e7SArnaldo Carvalho de Melo 21974a77e218SArnaldo Carvalho de Melo *list = strlist__new(list_str, NULL); 2198655000e7SArnaldo Carvalho de Melo if (!*list) { 2199655000e7SArnaldo Carvalho de Melo pr_err("problems parsing %s list\n", list_name); 2200655000e7SArnaldo Carvalho de Melo return -1; 2201655000e7SArnaldo Carvalho de Melo } 22020bc2f2f7SArnaldo Carvalho de Melo 22030bc2f2f7SArnaldo Carvalho de Melo symbol_conf.has_filter = true; 2204655000e7SArnaldo Carvalho de Melo return 0; 2205655000e7SArnaldo Carvalho de Melo } 2206655000e7SArnaldo Carvalho de Melo 2207e03eaa40SDavid Ahern int setup_intlist(struct intlist **list, const char *list_str, 2208e03eaa40SDavid Ahern const char *list_name) 2209e03eaa40SDavid Ahern { 2210e03eaa40SDavid Ahern if (list_str == NULL) 2211e03eaa40SDavid Ahern return 0; 2212e03eaa40SDavid Ahern 2213e03eaa40SDavid Ahern *list = intlist__new(list_str); 2214e03eaa40SDavid Ahern if (!*list) { 2215e03eaa40SDavid Ahern pr_err("problems parsing %s list\n", list_name); 2216e03eaa40SDavid Ahern return -1; 2217e03eaa40SDavid Ahern } 2218e03eaa40SDavid Ahern return 0; 2219e03eaa40SDavid Ahern } 2220e03eaa40SDavid Ahern 2221ec80fde7SArnaldo Carvalho de Melo static bool symbol__read_kptr_restrict(void) 2222ec80fde7SArnaldo Carvalho de Melo { 2223ec80fde7SArnaldo Carvalho de Melo bool value = false; 2224ec80fde7SArnaldo Carvalho de Melo FILE *fp = fopen("/proc/sys/kernel/kptr_restrict", "r"); 222538272dc4SWang Nan 2226ec80fde7SArnaldo Carvalho de Melo if (fp != NULL) { 2227ec80fde7SArnaldo Carvalho de Melo char line[8]; 2228ec80fde7SArnaldo Carvalho de Melo 2229ec80fde7SArnaldo Carvalho de Melo if (fgets(line, sizeof(line), fp) != NULL) 22308859aedeSIgor Lubashev value = perf_cap__capable(CAP_SYSLOG) ? 22318859aedeSIgor Lubashev (atoi(line) >= 2) : 22328859aedeSIgor Lubashev (atoi(line) != 0); 2233ec80fde7SArnaldo Carvalho de Melo 2234ec80fde7SArnaldo Carvalho de Melo fclose(fp); 2235ec80fde7SArnaldo Carvalho de Melo } 2236ec80fde7SArnaldo Carvalho de Melo 22378859aedeSIgor Lubashev /* Per kernel/kallsyms.c: 22388859aedeSIgor Lubashev * we also restrict when perf_event_paranoid > 1 w/o CAP_SYSLOG 22398859aedeSIgor Lubashev */ 22408859aedeSIgor Lubashev if (perf_event_paranoid() > 1 && !perf_cap__capable(CAP_SYSLOG)) 22418859aedeSIgor Lubashev value = true; 22428859aedeSIgor Lubashev 2243ec80fde7SArnaldo Carvalho de Melo return value; 2244ec80fde7SArnaldo Carvalho de Melo } 2245ec80fde7SArnaldo Carvalho de Melo 2246b01141f4SArnaldo Carvalho de Melo int symbol__annotation_init(void) 2247b01141f4SArnaldo Carvalho de Melo { 22487b366142SArnaldo Carvalho de Melo if (symbol_conf.init_annotation) 22497b366142SArnaldo Carvalho de Melo return 0; 22507b366142SArnaldo Carvalho de Melo 2251b01141f4SArnaldo Carvalho de Melo if (symbol_conf.initialized) { 2252b01141f4SArnaldo Carvalho de Melo pr_err("Annotation needs to be init before symbol__init()\n"); 2253b01141f4SArnaldo Carvalho de Melo return -1; 2254b01141f4SArnaldo Carvalho de Melo } 2255b01141f4SArnaldo Carvalho de Melo 2256b01141f4SArnaldo Carvalho de Melo symbol_conf.priv_size += sizeof(struct annotation); 2257b01141f4SArnaldo Carvalho de Melo symbol_conf.init_annotation = true; 2258b01141f4SArnaldo Carvalho de Melo return 0; 2259b01141f4SArnaldo Carvalho de Melo } 2260b01141f4SArnaldo Carvalho de Melo 2261ce80d3beSKan Liang int symbol__init(struct perf_env *env) 2262cc612d81SArnaldo Carvalho de Melo { 2263ec5761eaSDavid Ahern const char *symfs; 2264ec5761eaSDavid Ahern 226585e00b55SJovi Zhang if (symbol_conf.initialized) 226685e00b55SJovi Zhang return 0; 226785e00b55SJovi Zhang 22689ac3e487SIrina Tirdea symbol_conf.priv_size = PERF_ALIGN(symbol_conf.priv_size, sizeof(u64)); 22694d439517SDavid S. Miller 2270166ccc9cSNamhyung Kim symbol__elf_init(); 2271166ccc9cSNamhyung Kim 227275be6cf4SArnaldo Carvalho de Melo if (symbol_conf.sort_by_name) 227375be6cf4SArnaldo Carvalho de Melo symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) - 227479406cd7SArnaldo Carvalho de Melo sizeof(struct symbol)); 2275b32d133aSArnaldo Carvalho de Melo 22760a7e6d1bSNamhyung Kim if (symbol_conf.try_vmlinux_path && vmlinux_path__init(env) < 0) 2277cc612d81SArnaldo Carvalho de Melo return -1; 2278cc612d81SArnaldo Carvalho de Melo 2279c410a338SArnaldo Carvalho de Melo if (symbol_conf.field_sep && *symbol_conf.field_sep == '.') { 2280c410a338SArnaldo Carvalho de Melo pr_err("'.' is the only non valid --field-separator argument\n"); 2281c410a338SArnaldo Carvalho de Melo return -1; 2282c410a338SArnaldo Carvalho de Melo } 2283c410a338SArnaldo Carvalho de Melo 2284655000e7SArnaldo Carvalho de Melo if (setup_list(&symbol_conf.dso_list, 2285655000e7SArnaldo Carvalho de Melo symbol_conf.dso_list_str, "dso") < 0) 2286655000e7SArnaldo Carvalho de Melo return -1; 2287655000e7SArnaldo Carvalho de Melo 2288655000e7SArnaldo Carvalho de Melo if (setup_list(&symbol_conf.comm_list, 2289655000e7SArnaldo Carvalho de Melo symbol_conf.comm_list_str, "comm") < 0) 2290655000e7SArnaldo Carvalho de Melo goto out_free_dso_list; 2291655000e7SArnaldo Carvalho de Melo 2292e03eaa40SDavid Ahern if (setup_intlist(&symbol_conf.pid_list, 2293e03eaa40SDavid Ahern symbol_conf.pid_list_str, "pid") < 0) 2294e03eaa40SDavid Ahern goto out_free_comm_list; 2295e03eaa40SDavid Ahern 2296e03eaa40SDavid Ahern if (setup_intlist(&symbol_conf.tid_list, 2297e03eaa40SDavid Ahern symbol_conf.tid_list_str, "tid") < 0) 2298e03eaa40SDavid Ahern goto out_free_pid_list; 2299e03eaa40SDavid Ahern 2300655000e7SArnaldo Carvalho de Melo if (setup_list(&symbol_conf.sym_list, 2301655000e7SArnaldo Carvalho de Melo symbol_conf.sym_list_str, "symbol") < 0) 2302e03eaa40SDavid Ahern goto out_free_tid_list; 2303655000e7SArnaldo Carvalho de Melo 230464eff7d9SDavid Ahern if (setup_list(&symbol_conf.bt_stop_list, 230564eff7d9SDavid Ahern symbol_conf.bt_stop_list_str, "symbol") < 0) 230664eff7d9SDavid Ahern goto out_free_sym_list; 230764eff7d9SDavid Ahern 2308ec5761eaSDavid Ahern /* 2309ec5761eaSDavid Ahern * A path to symbols of "/" is identical to "" 2310ec5761eaSDavid Ahern * reset here for simplicity. 2311ec5761eaSDavid Ahern */ 2312ec5761eaSDavid Ahern symfs = realpath(symbol_conf.symfs, NULL); 2313ec5761eaSDavid Ahern if (symfs == NULL) 2314ec5761eaSDavid Ahern symfs = symbol_conf.symfs; 2315ec5761eaSDavid Ahern if (strcmp(symfs, "/") == 0) 2316ec5761eaSDavid Ahern symbol_conf.symfs = ""; 2317ec5761eaSDavid Ahern if (symfs != symbol_conf.symfs) 2318ec5761eaSDavid Ahern free((void *)symfs); 2319ec5761eaSDavid Ahern 2320ec80fde7SArnaldo Carvalho de Melo symbol_conf.kptr_restrict = symbol__read_kptr_restrict(); 2321ec80fde7SArnaldo Carvalho de Melo 232285e00b55SJovi Zhang symbol_conf.initialized = true; 23234aa65636SArnaldo Carvalho de Melo return 0; 2324655000e7SArnaldo Carvalho de Melo 232564eff7d9SDavid Ahern out_free_sym_list: 232664eff7d9SDavid Ahern strlist__delete(symbol_conf.sym_list); 2327e03eaa40SDavid Ahern out_free_tid_list: 2328e03eaa40SDavid Ahern intlist__delete(symbol_conf.tid_list); 2329e03eaa40SDavid Ahern out_free_pid_list: 2330e03eaa40SDavid Ahern intlist__delete(symbol_conf.pid_list); 2331655000e7SArnaldo Carvalho de Melo out_free_comm_list: 2332655000e7SArnaldo Carvalho de Melo strlist__delete(symbol_conf.comm_list); 2333d74c896bSNamhyung Kim out_free_dso_list: 2334d74c896bSNamhyung Kim strlist__delete(symbol_conf.dso_list); 2335655000e7SArnaldo Carvalho de Melo return -1; 2336cc612d81SArnaldo Carvalho de Melo } 2337cc612d81SArnaldo Carvalho de Melo 2338d65a458bSArnaldo Carvalho de Melo void symbol__exit(void) 2339d65a458bSArnaldo Carvalho de Melo { 234085e00b55SJovi Zhang if (!symbol_conf.initialized) 234185e00b55SJovi Zhang return; 234264eff7d9SDavid Ahern strlist__delete(symbol_conf.bt_stop_list); 2343d65a458bSArnaldo Carvalho de Melo strlist__delete(symbol_conf.sym_list); 2344d65a458bSArnaldo Carvalho de Melo strlist__delete(symbol_conf.dso_list); 2345d65a458bSArnaldo Carvalho de Melo strlist__delete(symbol_conf.comm_list); 2346e03eaa40SDavid Ahern intlist__delete(symbol_conf.tid_list); 2347e03eaa40SDavid Ahern intlist__delete(symbol_conf.pid_list); 2348d65a458bSArnaldo Carvalho de Melo vmlinux_path__exit(); 2349d65a458bSArnaldo Carvalho de Melo symbol_conf.sym_list = symbol_conf.dso_list = symbol_conf.comm_list = NULL; 235064eff7d9SDavid Ahern symbol_conf.bt_stop_list = NULL; 235185e00b55SJovi Zhang symbol_conf.initialized = false; 2352d65a458bSArnaldo Carvalho de Melo } 2353a7066709SHe Kuang 2354a7066709SHe Kuang int symbol__config_symfs(const struct option *opt __maybe_unused, 2355a7066709SHe Kuang const char *dir, int unset __maybe_unused) 2356a7066709SHe Kuang { 2357a7066709SHe Kuang char *bf = NULL; 2358a7066709SHe Kuang int ret; 2359a7066709SHe Kuang 2360a7066709SHe Kuang symbol_conf.symfs = strdup(dir); 2361a7066709SHe Kuang if (symbol_conf.symfs == NULL) 2362a7066709SHe Kuang return -ENOMEM; 2363a7066709SHe Kuang 2364a7066709SHe Kuang /* skip the locally configured cache if a symfs is given, and 2365a7066709SHe Kuang * config buildid dir to symfs/.debug 2366a7066709SHe Kuang */ 2367a7066709SHe Kuang ret = asprintf(&bf, "%s/%s", dir, ".debug"); 2368a7066709SHe Kuang if (ret < 0) 2369a7066709SHe Kuang return -ENOMEM; 2370a7066709SHe Kuang 2371a7066709SHe Kuang set_buildid_dir(bf); 2372a7066709SHe Kuang 2373a7066709SHe Kuang free(bf); 2374a7066709SHe Kuang return 0; 2375a7066709SHe Kuang } 23769f87498fSJiri Olsa 23779f87498fSJiri Olsa struct mem_info *mem_info__get(struct mem_info *mi) 23789f87498fSJiri Olsa { 23799f87498fSJiri Olsa if (mi) 23809f87498fSJiri Olsa refcount_inc(&mi->refcnt); 23819f87498fSJiri Olsa return mi; 23829f87498fSJiri Olsa } 23839f87498fSJiri Olsa 23849f87498fSJiri Olsa void mem_info__put(struct mem_info *mi) 23859f87498fSJiri Olsa { 23869f87498fSJiri Olsa if (mi && refcount_dec_and_test(&mi->refcnt)) 23879f87498fSJiri Olsa free(mi); 23889f87498fSJiri Olsa } 23899f87498fSJiri Olsa 23909f87498fSJiri Olsa struct mem_info *mem_info__new(void) 23919f87498fSJiri Olsa { 23929f87498fSJiri Olsa struct mem_info *mi = zalloc(sizeof(*mi)); 23939f87498fSJiri Olsa 23949f87498fSJiri Olsa if (mi) 23959f87498fSJiri Olsa refcount_set(&mi->refcnt, 1); 23969f87498fSJiri Olsa return mi; 23979f87498fSJiri Olsa } 2398