15aab621bSArnaldo Carvalho de Melo #include <dirent.h> 25aab621bSArnaldo Carvalho de Melo #include <errno.h> 35aab621bSArnaldo Carvalho de Melo #include <stdlib.h> 45aab621bSArnaldo Carvalho de Melo #include <stdio.h> 55aab621bSArnaldo Carvalho de Melo #include <string.h> 65aab621bSArnaldo Carvalho de Melo #include <sys/types.h> 75aab621bSArnaldo Carvalho de Melo #include <sys/stat.h> 85aab621bSArnaldo Carvalho de Melo #include <sys/param.h> 95aab621bSArnaldo Carvalho de Melo #include <fcntl.h> 105aab621bSArnaldo Carvalho de Melo #include <unistd.h> 119486aa38SArnaldo Carvalho de Melo #include <inttypes.h> 12b36f19d5SArnaldo Carvalho de Melo #include "build-id.h" 13e334c726SNamhyung Kim #include "util.h" 148a6c5b26SArnaldo Carvalho de Melo #include "debug.h" 1569d2591aSArnaldo Carvalho de Melo #include "machine.h" 1686470930SIngo Molnar #include "symbol.h" 175aab621bSArnaldo Carvalho de Melo #include "strlist.h" 18e03eaa40SDavid Ahern #include "intlist.h" 190a7e6d1bSNamhyung Kim #include "header.h" 2086470930SIngo Molnar 2186470930SIngo Molnar #include <elf.h> 22f1617b40SArnaldo Carvalho de Melo #include <limits.h> 23c506c96bSArnaldo Carvalho de Melo #include <symbol/kallsyms.h> 24439d473bSArnaldo Carvalho de Melo #include <sys/utsname.h> 252cdbc46dSPeter Zijlstra 26aeafcbafSArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *dso, struct map *map, 279de89fe7SArnaldo Carvalho de Melo symbol_filter_t filter); 28aeafcbafSArnaldo Carvalho de Melo static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map, 29a1645ce1SZhang, Yanmin symbol_filter_t filter); 303f067dcaSArnaldo Carvalho de Melo int vmlinux_path__nr_entries; 313f067dcaSArnaldo Carvalho de Melo char **vmlinux_path; 32439d473bSArnaldo Carvalho de Melo 3375be6cf4SArnaldo Carvalho de Melo struct symbol_conf symbol_conf = { 34b32d133aSArnaldo Carvalho de Melo .use_modules = true, 35b32d133aSArnaldo Carvalho de Melo .try_vmlinux_path = true, 363e6a2a7fSStephane Eranian .annotate_src = true, 37328ccdacSNamhyung Kim .demangle = true, 38763122adSAvi Kivity .demangle_kernel = false, 39e511db5eSNamhyung Kim .cumulate_callchain = true, 40c8302367SJiri Olsa .show_hist_headers = true, 41ec5761eaSDavid Ahern .symfs = "", 42b32d133aSArnaldo Carvalho de Melo }; 43b32d133aSArnaldo Carvalho de Melo 4444f24cb3SJiri Olsa static enum dso_binary_type binary_type_symtab[] = { 4544f24cb3SJiri Olsa DSO_BINARY_TYPE__KALLSYMS, 4644f24cb3SJiri Olsa DSO_BINARY_TYPE__GUEST_KALLSYMS, 4744f24cb3SJiri Olsa DSO_BINARY_TYPE__JAVA_JIT, 4844f24cb3SJiri Olsa DSO_BINARY_TYPE__DEBUGLINK, 4944f24cb3SJiri Olsa DSO_BINARY_TYPE__BUILD_ID_CACHE, 5044f24cb3SJiri Olsa DSO_BINARY_TYPE__FEDORA_DEBUGINFO, 5144f24cb3SJiri Olsa DSO_BINARY_TYPE__UBUNTU_DEBUGINFO, 5244f24cb3SJiri Olsa DSO_BINARY_TYPE__BUILDID_DEBUGINFO, 5344f24cb3SJiri Olsa DSO_BINARY_TYPE__SYSTEM_PATH_DSO, 5444f24cb3SJiri Olsa DSO_BINARY_TYPE__GUEST_KMODULE, 55c00c48fcSNamhyung Kim DSO_BINARY_TYPE__GUEST_KMODULE_COMP, 5644f24cb3SJiri Olsa DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE, 57c00c48fcSNamhyung Kim DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP, 589cd00941SRicardo Ribalda Delgado DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO, 5944f24cb3SJiri Olsa DSO_BINARY_TYPE__NOT_FOUND, 6044f24cb3SJiri Olsa }; 6144f24cb3SJiri Olsa 62028df767SJiri Olsa #define DSO_BINARY_TYPE__SYMTAB_CNT ARRAY_SIZE(binary_type_symtab) 6344f24cb3SJiri Olsa 6436a3e646SArnaldo Carvalho de Melo bool symbol_type__is_a(char symbol_type, enum map_type map_type) 656893d4eeSArnaldo Carvalho de Melo { 6631877908SAnton Blanchard symbol_type = toupper(symbol_type); 6731877908SAnton Blanchard 686893d4eeSArnaldo Carvalho de Melo switch (map_type) { 696893d4eeSArnaldo Carvalho de Melo case MAP__FUNCTION: 706893d4eeSArnaldo Carvalho de Melo return symbol_type == 'T' || symbol_type == 'W'; 71f1dfa0b1SArnaldo Carvalho de Melo case MAP__VARIABLE: 7231877908SAnton Blanchard return symbol_type == 'D'; 736893d4eeSArnaldo Carvalho de Melo default: 746893d4eeSArnaldo Carvalho de Melo return false; 756893d4eeSArnaldo Carvalho de Melo } 766893d4eeSArnaldo Carvalho de Melo } 776893d4eeSArnaldo Carvalho de Melo 78694bf407SAnton Blanchard static int prefix_underscores_count(const char *str) 79694bf407SAnton Blanchard { 80694bf407SAnton Blanchard const char *tail = str; 81694bf407SAnton Blanchard 82694bf407SAnton Blanchard while (*tail == '_') 83694bf407SAnton Blanchard tail++; 84694bf407SAnton Blanchard 85694bf407SAnton Blanchard return tail - str; 86694bf407SAnton Blanchard } 87694bf407SAnton Blanchard 88fb6d5942SNaveen N. Rao int __weak arch__choose_best_symbol(struct symbol *syma, 89fb6d5942SNaveen N. Rao struct symbol *symb __maybe_unused) 90fb6d5942SNaveen N. Rao { 91fb6d5942SNaveen N. Rao /* Avoid "SyS" kernel syscall aliases */ 92fb6d5942SNaveen N. Rao if (strlen(syma->name) >= 3 && !strncmp(syma->name, "SyS", 3)) 93fb6d5942SNaveen N. Rao return SYMBOL_B; 94fb6d5942SNaveen N. Rao if (strlen(syma->name) >= 10 && !strncmp(syma->name, "compat_SyS", 10)) 95fb6d5942SNaveen N. Rao return SYMBOL_B; 96fb6d5942SNaveen N. Rao 97fb6d5942SNaveen N. Rao return SYMBOL_A; 98fb6d5942SNaveen N. Rao } 99694bf407SAnton Blanchard 100694bf407SAnton Blanchard static int choose_best_symbol(struct symbol *syma, struct symbol *symb) 101694bf407SAnton Blanchard { 102694bf407SAnton Blanchard s64 a; 103694bf407SAnton Blanchard s64 b; 1043445432bSAdrian Hunter size_t na, nb; 105694bf407SAnton Blanchard 106694bf407SAnton Blanchard /* Prefer a symbol with non zero length */ 107694bf407SAnton Blanchard a = syma->end - syma->start; 108694bf407SAnton Blanchard b = symb->end - symb->start; 109694bf407SAnton Blanchard if ((b == 0) && (a > 0)) 110694bf407SAnton Blanchard return SYMBOL_A; 111694bf407SAnton Blanchard else if ((a == 0) && (b > 0)) 112694bf407SAnton Blanchard return SYMBOL_B; 113694bf407SAnton Blanchard 114694bf407SAnton Blanchard /* Prefer a non weak symbol over a weak one */ 115694bf407SAnton Blanchard a = syma->binding == STB_WEAK; 116694bf407SAnton Blanchard b = symb->binding == STB_WEAK; 117694bf407SAnton Blanchard if (b && !a) 118694bf407SAnton Blanchard return SYMBOL_A; 119694bf407SAnton Blanchard if (a && !b) 120694bf407SAnton Blanchard return SYMBOL_B; 121694bf407SAnton Blanchard 122694bf407SAnton Blanchard /* Prefer a global symbol over a non global one */ 123694bf407SAnton Blanchard a = syma->binding == STB_GLOBAL; 124694bf407SAnton Blanchard b = symb->binding == STB_GLOBAL; 125694bf407SAnton Blanchard if (a && !b) 126694bf407SAnton Blanchard return SYMBOL_A; 127694bf407SAnton Blanchard if (b && !a) 128694bf407SAnton Blanchard return SYMBOL_B; 129694bf407SAnton Blanchard 130694bf407SAnton Blanchard /* Prefer a symbol with less underscores */ 131694bf407SAnton Blanchard a = prefix_underscores_count(syma->name); 132694bf407SAnton Blanchard b = prefix_underscores_count(symb->name); 133694bf407SAnton Blanchard if (b > a) 134694bf407SAnton Blanchard return SYMBOL_A; 135694bf407SAnton Blanchard else if (a > b) 136694bf407SAnton Blanchard return SYMBOL_B; 137694bf407SAnton Blanchard 1383445432bSAdrian Hunter /* Choose the symbol with the longest name */ 1393445432bSAdrian Hunter na = strlen(syma->name); 1403445432bSAdrian Hunter nb = strlen(symb->name); 1413445432bSAdrian Hunter if (na > nb) 142694bf407SAnton Blanchard return SYMBOL_A; 1433445432bSAdrian Hunter else if (na < nb) 144694bf407SAnton Blanchard return SYMBOL_B; 1453445432bSAdrian Hunter 146fb6d5942SNaveen N. Rao return arch__choose_best_symbol(syma, symb); 147694bf407SAnton Blanchard } 148694bf407SAnton Blanchard 149e5a1845fSNamhyung Kim void symbols__fixup_duplicate(struct rb_root *symbols) 150694bf407SAnton Blanchard { 151694bf407SAnton Blanchard struct rb_node *nd; 152694bf407SAnton Blanchard struct symbol *curr, *next; 153694bf407SAnton Blanchard 154694bf407SAnton Blanchard nd = rb_first(symbols); 155694bf407SAnton Blanchard 156694bf407SAnton Blanchard while (nd) { 157694bf407SAnton Blanchard curr = rb_entry(nd, struct symbol, rb_node); 158694bf407SAnton Blanchard again: 159694bf407SAnton Blanchard nd = rb_next(&curr->rb_node); 160694bf407SAnton Blanchard next = rb_entry(nd, struct symbol, rb_node); 161694bf407SAnton Blanchard 162694bf407SAnton Blanchard if (!nd) 163694bf407SAnton Blanchard break; 164694bf407SAnton Blanchard 165694bf407SAnton Blanchard if (curr->start != next->start) 166694bf407SAnton Blanchard continue; 167694bf407SAnton Blanchard 168694bf407SAnton Blanchard if (choose_best_symbol(curr, next) == SYMBOL_A) { 169694bf407SAnton Blanchard rb_erase(&next->rb_node, symbols); 170d4f74eb8SChenggang Qin symbol__delete(next); 171694bf407SAnton Blanchard goto again; 172694bf407SAnton Blanchard } else { 173694bf407SAnton Blanchard nd = rb_next(&curr->rb_node); 174694bf407SAnton Blanchard rb_erase(&curr->rb_node, symbols); 175d4f74eb8SChenggang Qin symbol__delete(curr); 176694bf407SAnton Blanchard } 177694bf407SAnton Blanchard } 178694bf407SAnton Blanchard } 179694bf407SAnton Blanchard 180e5a1845fSNamhyung Kim void symbols__fixup_end(struct rb_root *symbols) 181af427bf5SArnaldo Carvalho de Melo { 182aeafcbafSArnaldo Carvalho de Melo struct rb_node *nd, *prevnd = rb_first(symbols); 1832e538c4aSArnaldo Carvalho de Melo struct symbol *curr, *prev; 184af427bf5SArnaldo Carvalho de Melo 185af427bf5SArnaldo Carvalho de Melo if (prevnd == NULL) 186af427bf5SArnaldo Carvalho de Melo return; 187af427bf5SArnaldo Carvalho de Melo 1882e538c4aSArnaldo Carvalho de Melo curr = rb_entry(prevnd, struct symbol, rb_node); 1892e538c4aSArnaldo Carvalho de Melo 190af427bf5SArnaldo Carvalho de Melo for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) { 1912e538c4aSArnaldo Carvalho de Melo prev = curr; 1922e538c4aSArnaldo Carvalho de Melo curr = rb_entry(nd, struct symbol, rb_node); 193af427bf5SArnaldo Carvalho de Melo 1943b01a413SArnaldo Carvalho de Melo if (prev->end == prev->start && prev->end != curr->start) 1952c241bd3SArnaldo Carvalho de Melo prev->end = curr->start; 196af427bf5SArnaldo Carvalho de Melo } 197af427bf5SArnaldo Carvalho de Melo 1982e538c4aSArnaldo Carvalho de Melo /* Last entry */ 1992e538c4aSArnaldo Carvalho de Melo if (curr->end == curr->start) 2002e538c4aSArnaldo Carvalho de Melo curr->end = roundup(curr->start, 4096); 2012e538c4aSArnaldo Carvalho de Melo } 2022e538c4aSArnaldo Carvalho de Melo 203e5a1845fSNamhyung Kim void __map_groups__fixup_end(struct map_groups *mg, enum map_type type) 204af427bf5SArnaldo Carvalho de Melo { 2051eee78aeSArnaldo Carvalho de Melo struct maps *maps = &mg->maps[type]; 2064bb7123dSArnaldo Carvalho de Melo struct map *next, *curr; 207af427bf5SArnaldo Carvalho de Melo 2086a2ffcddSArnaldo Carvalho de Melo pthread_rwlock_wrlock(&maps->lock); 2096a2ffcddSArnaldo Carvalho de Melo 2104bb7123dSArnaldo Carvalho de Melo curr = maps__first(maps); 2114bb7123dSArnaldo Carvalho de Melo if (curr == NULL) 2126a2ffcddSArnaldo Carvalho de Melo goto out_unlock; 213af427bf5SArnaldo Carvalho de Melo 2144bb7123dSArnaldo Carvalho de Melo for (next = map__next(curr); next; next = map__next(curr)) { 2154bb7123dSArnaldo Carvalho de Melo curr->end = next->start; 2164bb7123dSArnaldo Carvalho de Melo curr = next; 2172e538c4aSArnaldo Carvalho de Melo } 21890c83218SArnaldo Carvalho de Melo 21990c83218SArnaldo Carvalho de Melo /* 22090c83218SArnaldo Carvalho de Melo * We still haven't the actual symbols, so guess the 22190c83218SArnaldo Carvalho de Melo * last map final address. 22290c83218SArnaldo Carvalho de Melo */ 2239d1faba5SIan Munsie curr->end = ~0ULL; 2246a2ffcddSArnaldo Carvalho de Melo 2256a2ffcddSArnaldo Carvalho de Melo out_unlock: 2266a2ffcddSArnaldo Carvalho de Melo pthread_rwlock_unlock(&maps->lock); 227af427bf5SArnaldo Carvalho de Melo } 228af427bf5SArnaldo Carvalho de Melo 229e5a1845fSNamhyung Kim struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name) 23086470930SIngo Molnar { 23186470930SIngo Molnar size_t namelen = strlen(name) + 1; 232aeafcbafSArnaldo Carvalho de Melo struct symbol *sym = calloc(1, (symbol_conf.priv_size + 233aeafcbafSArnaldo Carvalho de Melo sizeof(*sym) + namelen)); 234aeafcbafSArnaldo Carvalho de Melo if (sym == NULL) 23586470930SIngo Molnar return NULL; 23686470930SIngo Molnar 23775be6cf4SArnaldo Carvalho de Melo if (symbol_conf.priv_size) 238aeafcbafSArnaldo Carvalho de Melo sym = ((void *)sym) + symbol_conf.priv_size; 23936479484SArnaldo Carvalho de Melo 240aeafcbafSArnaldo Carvalho de Melo sym->start = start; 2412c241bd3SArnaldo Carvalho de Melo sym->end = len ? start + len : start; 242aeafcbafSArnaldo Carvalho de Melo sym->binding = binding; 243aeafcbafSArnaldo Carvalho de Melo sym->namelen = namelen - 1; 244e4204992SArnaldo Carvalho de Melo 245aeafcbafSArnaldo Carvalho de Melo pr_debug4("%s: %s %#" PRIx64 "-%#" PRIx64 "\n", 246aeafcbafSArnaldo Carvalho de Melo __func__, name, start, sym->end); 247aeafcbafSArnaldo Carvalho de Melo memcpy(sym->name, name, namelen); 248e4204992SArnaldo Carvalho de Melo 249aeafcbafSArnaldo Carvalho de Melo return sym; 25086470930SIngo Molnar } 25186470930SIngo Molnar 252aeafcbafSArnaldo Carvalho de Melo void symbol__delete(struct symbol *sym) 25386470930SIngo Molnar { 254aeafcbafSArnaldo Carvalho de Melo free(((void *)sym) - symbol_conf.priv_size); 25586470930SIngo Molnar } 25686470930SIngo Molnar 257cdd059d7SJiri Olsa size_t symbol__fprintf(struct symbol *sym, FILE *fp) 25886470930SIngo Molnar { 2599486aa38SArnaldo Carvalho de Melo return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %c %s\n", 260aeafcbafSArnaldo Carvalho de Melo sym->start, sym->end, 261aeafcbafSArnaldo Carvalho de Melo sym->binding == STB_GLOBAL ? 'g' : 262aeafcbafSArnaldo Carvalho de Melo sym->binding == STB_LOCAL ? 'l' : 'w', 263aeafcbafSArnaldo Carvalho de Melo sym->name); 26486470930SIngo Molnar } 26586470930SIngo Molnar 266a978f2abSAkihiro Nagai size_t symbol__fprintf_symname_offs(const struct symbol *sym, 267a978f2abSAkihiro Nagai const struct addr_location *al, FILE *fp) 268a978f2abSAkihiro Nagai { 269a978f2abSAkihiro Nagai unsigned long offset; 270a978f2abSAkihiro Nagai size_t length; 271a978f2abSAkihiro Nagai 272a978f2abSAkihiro Nagai if (sym && sym->name) { 273a978f2abSAkihiro Nagai length = fprintf(fp, "%s", sym->name); 274a978f2abSAkihiro Nagai if (al) { 2750b8c25d9SDavid Ahern if (al->addr < sym->end) 276a978f2abSAkihiro Nagai offset = al->addr - sym->start; 2770b8c25d9SDavid Ahern else 2780b8c25d9SDavid Ahern offset = al->addr - al->map->start - sym->start; 279a978f2abSAkihiro Nagai length += fprintf(fp, "+0x%lx", offset); 280a978f2abSAkihiro Nagai } 281a978f2abSAkihiro Nagai return length; 282a978f2abSAkihiro Nagai } else 283a978f2abSAkihiro Nagai return fprintf(fp, "[unknown]"); 284a978f2abSAkihiro Nagai } 285a978f2abSAkihiro Nagai 286547a92e0SAkihiro Nagai size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp) 287547a92e0SAkihiro Nagai { 288a978f2abSAkihiro Nagai return symbol__fprintf_symname_offs(sym, NULL, fp); 289547a92e0SAkihiro Nagai } 290547a92e0SAkihiro Nagai 291cdd059d7SJiri Olsa void symbols__delete(struct rb_root *symbols) 29286470930SIngo Molnar { 29386470930SIngo Molnar struct symbol *pos; 294aeafcbafSArnaldo Carvalho de Melo struct rb_node *next = rb_first(symbols); 29586470930SIngo Molnar 29686470930SIngo Molnar while (next) { 29786470930SIngo Molnar pos = rb_entry(next, struct symbol, rb_node); 29886470930SIngo Molnar next = rb_next(&pos->rb_node); 299aeafcbafSArnaldo Carvalho de Melo rb_erase(&pos->rb_node, symbols); 30000a192b3SArnaldo Carvalho de Melo symbol__delete(pos); 30186470930SIngo Molnar } 30286470930SIngo Molnar } 30386470930SIngo Molnar 304e5a1845fSNamhyung Kim void symbols__insert(struct rb_root *symbols, struct symbol *sym) 30586470930SIngo Molnar { 306aeafcbafSArnaldo Carvalho de Melo struct rb_node **p = &symbols->rb_node; 30786470930SIngo Molnar struct rb_node *parent = NULL; 3089cffa8d5SPaul Mackerras const u64 ip = sym->start; 30986470930SIngo Molnar struct symbol *s; 31086470930SIngo Molnar 31186470930SIngo Molnar while (*p != NULL) { 31286470930SIngo Molnar parent = *p; 31386470930SIngo Molnar s = rb_entry(parent, struct symbol, rb_node); 31486470930SIngo Molnar if (ip < s->start) 31586470930SIngo Molnar p = &(*p)->rb_left; 31686470930SIngo Molnar else 31786470930SIngo Molnar p = &(*p)->rb_right; 31886470930SIngo Molnar } 31986470930SIngo Molnar rb_link_node(&sym->rb_node, parent, p); 320aeafcbafSArnaldo Carvalho de Melo rb_insert_color(&sym->rb_node, symbols); 32186470930SIngo Molnar } 32286470930SIngo Molnar 323aeafcbafSArnaldo Carvalho de Melo static struct symbol *symbols__find(struct rb_root *symbols, u64 ip) 32486470930SIngo Molnar { 32586470930SIngo Molnar struct rb_node *n; 32686470930SIngo Molnar 327aeafcbafSArnaldo Carvalho de Melo if (symbols == NULL) 32886470930SIngo Molnar return NULL; 32986470930SIngo Molnar 330aeafcbafSArnaldo Carvalho de Melo n = symbols->rb_node; 33186470930SIngo Molnar 33286470930SIngo Molnar while (n) { 33386470930SIngo Molnar struct symbol *s = rb_entry(n, struct symbol, rb_node); 33486470930SIngo Molnar 33586470930SIngo Molnar if (ip < s->start) 33686470930SIngo Molnar n = n->rb_left; 3372c241bd3SArnaldo Carvalho de Melo else if (ip >= s->end) 33886470930SIngo Molnar n = n->rb_right; 33986470930SIngo Molnar else 34086470930SIngo Molnar return s; 34186470930SIngo Molnar } 34286470930SIngo Molnar 34386470930SIngo Molnar return NULL; 34486470930SIngo Molnar } 34586470930SIngo Molnar 3468e0cf965SAdrian Hunter static struct symbol *symbols__first(struct rb_root *symbols) 3478e0cf965SAdrian Hunter { 3488e0cf965SAdrian Hunter struct rb_node *n = rb_first(symbols); 3498e0cf965SAdrian Hunter 3508e0cf965SAdrian Hunter if (n) 3518e0cf965SAdrian Hunter return rb_entry(n, struct symbol, rb_node); 3528e0cf965SAdrian Hunter 3538e0cf965SAdrian Hunter return NULL; 3548e0cf965SAdrian Hunter } 3558e0cf965SAdrian Hunter 3569c00a81bSAdrian Hunter static struct symbol *symbols__next(struct symbol *sym) 3579c00a81bSAdrian Hunter { 3589c00a81bSAdrian Hunter struct rb_node *n = rb_next(&sym->rb_node); 3599c00a81bSAdrian Hunter 3609c00a81bSAdrian Hunter if (n) 3619c00a81bSAdrian Hunter return rb_entry(n, struct symbol, rb_node); 3629c00a81bSAdrian Hunter 3639c00a81bSAdrian Hunter return NULL; 3649c00a81bSAdrian Hunter } 3659c00a81bSAdrian Hunter 36679406cd7SArnaldo Carvalho de Melo struct symbol_name_rb_node { 36779406cd7SArnaldo Carvalho de Melo struct rb_node rb_node; 36879406cd7SArnaldo Carvalho de Melo struct symbol sym; 36979406cd7SArnaldo Carvalho de Melo }; 37079406cd7SArnaldo Carvalho de Melo 371aeafcbafSArnaldo Carvalho de Melo static void symbols__insert_by_name(struct rb_root *symbols, struct symbol *sym) 37279406cd7SArnaldo Carvalho de Melo { 373aeafcbafSArnaldo Carvalho de Melo struct rb_node **p = &symbols->rb_node; 37479406cd7SArnaldo Carvalho de Melo struct rb_node *parent = NULL; 37502a9d037SRabin Vincent struct symbol_name_rb_node *symn, *s; 37602a9d037SRabin Vincent 37702a9d037SRabin Vincent symn = container_of(sym, struct symbol_name_rb_node, sym); 37879406cd7SArnaldo Carvalho de Melo 37979406cd7SArnaldo Carvalho de Melo while (*p != NULL) { 38079406cd7SArnaldo Carvalho de Melo parent = *p; 38179406cd7SArnaldo Carvalho de Melo s = rb_entry(parent, struct symbol_name_rb_node, rb_node); 38279406cd7SArnaldo Carvalho de Melo if (strcmp(sym->name, s->sym.name) < 0) 38379406cd7SArnaldo Carvalho de Melo p = &(*p)->rb_left; 38479406cd7SArnaldo Carvalho de Melo else 38579406cd7SArnaldo Carvalho de Melo p = &(*p)->rb_right; 38679406cd7SArnaldo Carvalho de Melo } 38779406cd7SArnaldo Carvalho de Melo rb_link_node(&symn->rb_node, parent, p); 388aeafcbafSArnaldo Carvalho de Melo rb_insert_color(&symn->rb_node, symbols); 38979406cd7SArnaldo Carvalho de Melo } 39079406cd7SArnaldo Carvalho de Melo 391aeafcbafSArnaldo Carvalho de Melo static void symbols__sort_by_name(struct rb_root *symbols, 392aeafcbafSArnaldo Carvalho de Melo struct rb_root *source) 39379406cd7SArnaldo Carvalho de Melo { 39479406cd7SArnaldo Carvalho de Melo struct rb_node *nd; 39579406cd7SArnaldo Carvalho de Melo 39679406cd7SArnaldo Carvalho de Melo for (nd = rb_first(source); nd; nd = rb_next(nd)) { 39779406cd7SArnaldo Carvalho de Melo struct symbol *pos = rb_entry(nd, struct symbol, rb_node); 398aeafcbafSArnaldo Carvalho de Melo symbols__insert_by_name(symbols, pos); 39979406cd7SArnaldo Carvalho de Melo } 40079406cd7SArnaldo Carvalho de Melo } 40179406cd7SArnaldo Carvalho de Melo 402aeafcbafSArnaldo Carvalho de Melo static struct symbol *symbols__find_by_name(struct rb_root *symbols, 403aeafcbafSArnaldo Carvalho de Melo const char *name) 40479406cd7SArnaldo Carvalho de Melo { 40579406cd7SArnaldo Carvalho de Melo struct rb_node *n; 4065bcaaca3SMartin Liška struct symbol_name_rb_node *s = NULL; 40779406cd7SArnaldo Carvalho de Melo 408aeafcbafSArnaldo Carvalho de Melo if (symbols == NULL) 40979406cd7SArnaldo Carvalho de Melo return NULL; 41079406cd7SArnaldo Carvalho de Melo 411aeafcbafSArnaldo Carvalho de Melo n = symbols->rb_node; 41279406cd7SArnaldo Carvalho de Melo 41379406cd7SArnaldo Carvalho de Melo while (n) { 41479406cd7SArnaldo Carvalho de Melo int cmp; 41579406cd7SArnaldo Carvalho de Melo 41679406cd7SArnaldo Carvalho de Melo s = rb_entry(n, struct symbol_name_rb_node, rb_node); 417031b84c4SNaveen N. Rao cmp = arch__compare_symbol_names(name, s->sym.name); 41879406cd7SArnaldo Carvalho de Melo 41979406cd7SArnaldo Carvalho de Melo if (cmp < 0) 42079406cd7SArnaldo Carvalho de Melo n = n->rb_left; 42179406cd7SArnaldo Carvalho de Melo else if (cmp > 0) 42279406cd7SArnaldo Carvalho de Melo n = n->rb_right; 42379406cd7SArnaldo Carvalho de Melo else 424de480999SNamhyung Kim break; 42579406cd7SArnaldo Carvalho de Melo } 42679406cd7SArnaldo Carvalho de Melo 427de480999SNamhyung Kim if (n == NULL) 42879406cd7SArnaldo Carvalho de Melo return NULL; 429de480999SNamhyung Kim 430de480999SNamhyung Kim /* return first symbol that has same name (if any) */ 431de480999SNamhyung Kim for (n = rb_prev(n); n; n = rb_prev(n)) { 432de480999SNamhyung Kim struct symbol_name_rb_node *tmp; 433de480999SNamhyung Kim 434de480999SNamhyung Kim tmp = rb_entry(n, struct symbol_name_rb_node, rb_node); 435031b84c4SNaveen N. Rao if (arch__compare_symbol_names(tmp->sym.name, s->sym.name)) 436de480999SNamhyung Kim break; 437de480999SNamhyung Kim 438de480999SNamhyung Kim s = tmp; 439de480999SNamhyung Kim } 440de480999SNamhyung Kim 441de480999SNamhyung Kim return &s->sym; 44279406cd7SArnaldo Carvalho de Melo } 44379406cd7SArnaldo Carvalho de Melo 444aeafcbafSArnaldo Carvalho de Melo struct symbol *dso__find_symbol(struct dso *dso, 44579406cd7SArnaldo Carvalho de Melo enum map_type type, u64 addr) 446fcf1203aSArnaldo Carvalho de Melo { 447aeafcbafSArnaldo Carvalho de Melo return symbols__find(&dso->symbols[type], addr); 448fcf1203aSArnaldo Carvalho de Melo } 449fcf1203aSArnaldo Carvalho de Melo 4509c00a81bSAdrian Hunter struct symbol *dso__first_symbol(struct dso *dso, enum map_type type) 4518e0cf965SAdrian Hunter { 4528e0cf965SAdrian Hunter return symbols__first(&dso->symbols[type]); 4538e0cf965SAdrian Hunter } 4548e0cf965SAdrian Hunter 4559c00a81bSAdrian Hunter struct symbol *dso__next_symbol(struct symbol *sym) 4569c00a81bSAdrian Hunter { 4579c00a81bSAdrian Hunter return symbols__next(sym); 4589c00a81bSAdrian Hunter } 4599c00a81bSAdrian Hunter 46018bd7264SArnaldo Carvalho de Melo struct symbol *symbol__next_by_name(struct symbol *sym) 46118bd7264SArnaldo Carvalho de Melo { 46218bd7264SArnaldo Carvalho de Melo struct symbol_name_rb_node *s = container_of(sym, struct symbol_name_rb_node, sym); 46318bd7264SArnaldo Carvalho de Melo struct rb_node *n = rb_next(&s->rb_node); 46418bd7264SArnaldo Carvalho de Melo 46518bd7264SArnaldo Carvalho de Melo return n ? &rb_entry(n, struct symbol_name_rb_node, rb_node)->sym : NULL; 46618bd7264SArnaldo Carvalho de Melo } 46718bd7264SArnaldo Carvalho de Melo 46818bd7264SArnaldo Carvalho de Melo /* 46918bd7264SArnaldo Carvalho de Melo * Teturns first symbol that matched with @name. 47018bd7264SArnaldo Carvalho de Melo */ 471aeafcbafSArnaldo Carvalho de Melo struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type, 47279406cd7SArnaldo Carvalho de Melo const char *name) 47379406cd7SArnaldo Carvalho de Melo { 474aeafcbafSArnaldo Carvalho de Melo return symbols__find_by_name(&dso->symbol_names[type], name); 47579406cd7SArnaldo Carvalho de Melo } 47679406cd7SArnaldo Carvalho de Melo 477aeafcbafSArnaldo Carvalho de Melo void dso__sort_by_name(struct dso *dso, enum map_type type) 47879406cd7SArnaldo Carvalho de Melo { 479aeafcbafSArnaldo Carvalho de Melo dso__set_sorted_by_name(dso, type); 480aeafcbafSArnaldo Carvalho de Melo return symbols__sort_by_name(&dso->symbol_names[type], 481aeafcbafSArnaldo Carvalho de Melo &dso->symbols[type]); 48279406cd7SArnaldo Carvalho de Melo } 48379406cd7SArnaldo Carvalho de Melo 484aeafcbafSArnaldo Carvalho de Melo size_t dso__fprintf_symbols_by_name(struct dso *dso, 485aeafcbafSArnaldo Carvalho de Melo enum map_type type, FILE *fp) 48690f18e63SSrikar Dronamraju { 48790f18e63SSrikar Dronamraju size_t ret = 0; 48890f18e63SSrikar Dronamraju struct rb_node *nd; 48990f18e63SSrikar Dronamraju struct symbol_name_rb_node *pos; 49090f18e63SSrikar Dronamraju 491aeafcbafSArnaldo Carvalho de Melo for (nd = rb_first(&dso->symbol_names[type]); nd; nd = rb_next(nd)) { 49290f18e63SSrikar Dronamraju pos = rb_entry(nd, struct symbol_name_rb_node, rb_node); 49390f18e63SSrikar Dronamraju fprintf(fp, "%s\n", pos->sym.name); 49490f18e63SSrikar Dronamraju } 49590f18e63SSrikar Dronamraju 49690f18e63SSrikar Dronamraju return ret; 49790f18e63SSrikar Dronamraju } 49890f18e63SSrikar Dronamraju 499316d70d6SAdrian Hunter int modules__parse(const char *filename, void *arg, 500316d70d6SAdrian Hunter int (*process_module)(void *arg, const char *name, 501316d70d6SAdrian Hunter u64 start)) 502316d70d6SAdrian Hunter { 503316d70d6SAdrian Hunter char *line = NULL; 504316d70d6SAdrian Hunter size_t n; 505316d70d6SAdrian Hunter FILE *file; 506316d70d6SAdrian Hunter int err = 0; 507316d70d6SAdrian Hunter 508316d70d6SAdrian Hunter file = fopen(filename, "r"); 509316d70d6SAdrian Hunter if (file == NULL) 510316d70d6SAdrian Hunter return -1; 511316d70d6SAdrian Hunter 512316d70d6SAdrian Hunter while (1) { 513316d70d6SAdrian Hunter char name[PATH_MAX]; 514316d70d6SAdrian Hunter u64 start; 515316d70d6SAdrian Hunter char *sep; 516316d70d6SAdrian Hunter ssize_t line_len; 517316d70d6SAdrian Hunter 518316d70d6SAdrian Hunter line_len = getline(&line, &n, file); 519316d70d6SAdrian Hunter if (line_len < 0) { 520316d70d6SAdrian Hunter if (feof(file)) 521316d70d6SAdrian Hunter break; 522316d70d6SAdrian Hunter err = -1; 523316d70d6SAdrian Hunter goto out; 524316d70d6SAdrian Hunter } 525316d70d6SAdrian Hunter 526316d70d6SAdrian Hunter if (!line) { 527316d70d6SAdrian Hunter err = -1; 528316d70d6SAdrian Hunter goto out; 529316d70d6SAdrian Hunter } 530316d70d6SAdrian Hunter 531316d70d6SAdrian Hunter line[--line_len] = '\0'; /* \n */ 532316d70d6SAdrian Hunter 533316d70d6SAdrian Hunter sep = strrchr(line, 'x'); 534316d70d6SAdrian Hunter if (sep == NULL) 535316d70d6SAdrian Hunter continue; 536316d70d6SAdrian Hunter 537316d70d6SAdrian Hunter hex2u64(sep + 1, &start); 538316d70d6SAdrian Hunter 539316d70d6SAdrian Hunter sep = strchr(line, ' '); 540316d70d6SAdrian Hunter if (sep == NULL) 541316d70d6SAdrian Hunter continue; 542316d70d6SAdrian Hunter 543316d70d6SAdrian Hunter *sep = '\0'; 544316d70d6SAdrian Hunter 545316d70d6SAdrian Hunter scnprintf(name, sizeof(name), "[%s]", line); 546316d70d6SAdrian Hunter 547316d70d6SAdrian Hunter err = process_module(arg, name, start); 548316d70d6SAdrian Hunter if (err) 549316d70d6SAdrian Hunter break; 550316d70d6SAdrian Hunter } 551316d70d6SAdrian Hunter out: 552316d70d6SAdrian Hunter free(line); 553316d70d6SAdrian Hunter fclose(file); 554316d70d6SAdrian Hunter return err; 555316d70d6SAdrian Hunter } 556316d70d6SAdrian Hunter 557682b335aSArnaldo Carvalho de Melo struct process_kallsyms_args { 558682b335aSArnaldo Carvalho de Melo struct map *map; 559682b335aSArnaldo Carvalho de Melo struct dso *dso; 560682b335aSArnaldo Carvalho de Melo }; 561682b335aSArnaldo Carvalho de Melo 562e7110b9fSArnaldo Carvalho de Melo /* 563e7110b9fSArnaldo Carvalho de Melo * These are symbols in the kernel image, so make sure that 564e7110b9fSArnaldo Carvalho de Melo * sym is from a kernel DSO. 565e7110b9fSArnaldo Carvalho de Melo */ 56682d1deb0SDavid Ahern bool symbol__is_idle(struct symbol *sym) 56782d1deb0SDavid Ahern { 56882d1deb0SDavid Ahern const char * const idle_symbols[] = { 56982d1deb0SDavid Ahern "cpu_idle", 570e0336ed6SArnaldo Carvalho de Melo "cpu_startup_entry", 57182d1deb0SDavid Ahern "intel_idle", 57282d1deb0SDavid Ahern "default_idle", 57382d1deb0SDavid Ahern "native_safe_halt", 57482d1deb0SDavid Ahern "enter_idle", 57582d1deb0SDavid Ahern "exit_idle", 57682d1deb0SDavid Ahern "mwait_idle", 57782d1deb0SDavid Ahern "mwait_idle_with_hints", 57882d1deb0SDavid Ahern "poll_idle", 57982d1deb0SDavid Ahern "ppc64_runlatch_off", 58082d1deb0SDavid Ahern "pseries_dedicated_idle_sleep", 58182d1deb0SDavid Ahern NULL 58282d1deb0SDavid Ahern }; 58382d1deb0SDavid Ahern 58482d1deb0SDavid Ahern int i; 58582d1deb0SDavid Ahern 58682d1deb0SDavid Ahern if (!sym) 58782d1deb0SDavid Ahern return false; 58882d1deb0SDavid Ahern 58982d1deb0SDavid Ahern for (i = 0; idle_symbols[i]; i++) { 59082d1deb0SDavid Ahern if (!strcmp(idle_symbols[i], sym->name)) 59182d1deb0SDavid Ahern return true; 59282d1deb0SDavid Ahern } 59382d1deb0SDavid Ahern 59482d1deb0SDavid Ahern return false; 59582d1deb0SDavid Ahern } 59682d1deb0SDavid Ahern 597682b335aSArnaldo Carvalho de Melo static int map__process_kallsym_symbol(void *arg, const char *name, 59882151520SCody P Schafer char type, u64 start) 599682b335aSArnaldo Carvalho de Melo { 600682b335aSArnaldo Carvalho de Melo struct symbol *sym; 601682b335aSArnaldo Carvalho de Melo struct process_kallsyms_args *a = arg; 602682b335aSArnaldo Carvalho de Melo struct rb_root *root = &a->dso->symbols[a->map->type]; 603682b335aSArnaldo Carvalho de Melo 604682b335aSArnaldo Carvalho de Melo if (!symbol_type__is_a(type, a->map->type)) 605682b335aSArnaldo Carvalho de Melo return 0; 606682b335aSArnaldo Carvalho de Melo 60782151520SCody P Schafer /* 60882151520SCody P Schafer * module symbols are not sorted so we add all 60982151520SCody P Schafer * symbols, setting length to 0, and rely on 61082151520SCody P Schafer * symbols__fixup_end() to fix it up. 61182151520SCody P Schafer */ 61282151520SCody P Schafer sym = symbol__new(start, 0, kallsyms2elf_type(type), name); 6132e538c4aSArnaldo Carvalho de Melo if (sym == NULL) 614682b335aSArnaldo Carvalho de Melo return -ENOMEM; 61582164161SArnaldo Carvalho de Melo /* 61682164161SArnaldo Carvalho de Melo * We will pass the symbols to the filter later, in 6174e06255fSArnaldo Carvalho de Melo * map__split_kallsyms, when we have split the maps per module 61882164161SArnaldo Carvalho de Melo */ 6194e06255fSArnaldo Carvalho de Melo symbols__insert(root, sym); 620a1645ce1SZhang, Yanmin 621682b335aSArnaldo Carvalho de Melo return 0; 6222e538c4aSArnaldo Carvalho de Melo } 6232e538c4aSArnaldo Carvalho de Melo 624682b335aSArnaldo Carvalho de Melo /* 625682b335aSArnaldo Carvalho de Melo * Loads the function entries in /proc/kallsyms into kernel_map->dso, 626682b335aSArnaldo Carvalho de Melo * so that we can in the next step set the symbol ->end address and then 627682b335aSArnaldo Carvalho de Melo * call kernel_maps__split_kallsyms. 628682b335aSArnaldo Carvalho de Melo */ 629aeafcbafSArnaldo Carvalho de Melo static int dso__load_all_kallsyms(struct dso *dso, const char *filename, 6309e201442SArnaldo Carvalho de Melo struct map *map) 631682b335aSArnaldo Carvalho de Melo { 632aeafcbafSArnaldo Carvalho de Melo struct process_kallsyms_args args = { .map = map, .dso = dso, }; 6339e201442SArnaldo Carvalho de Melo return kallsyms__parse(filename, &args, map__process_kallsym_symbol); 6342e538c4aSArnaldo Carvalho de Melo } 6352e538c4aSArnaldo Carvalho de Melo 6368e0cf965SAdrian Hunter static int dso__split_kallsyms_for_kcore(struct dso *dso, struct map *map, 6378e0cf965SAdrian Hunter symbol_filter_t filter) 6388e0cf965SAdrian Hunter { 639ba92732eSWang Nan struct map_groups *kmaps = map__kmaps(map); 6408e0cf965SAdrian Hunter struct map *curr_map; 6418e0cf965SAdrian Hunter struct symbol *pos; 6428e0cf965SAdrian Hunter int count = 0, moved = 0; 6438e0cf965SAdrian Hunter struct rb_root *root = &dso->symbols[map->type]; 6448e0cf965SAdrian Hunter struct rb_node *next = rb_first(root); 6458e0cf965SAdrian Hunter 646ba92732eSWang Nan if (!kmaps) 647ba92732eSWang Nan return -1; 648ba92732eSWang Nan 6498e0cf965SAdrian Hunter while (next) { 6508e0cf965SAdrian Hunter char *module; 6518e0cf965SAdrian Hunter 6528e0cf965SAdrian Hunter pos = rb_entry(next, struct symbol, rb_node); 6538e0cf965SAdrian Hunter next = rb_next(&pos->rb_node); 6548e0cf965SAdrian Hunter 6558e0cf965SAdrian Hunter module = strchr(pos->name, '\t'); 6568e0cf965SAdrian Hunter if (module) 6578e0cf965SAdrian Hunter *module = '\0'; 6588e0cf965SAdrian Hunter 6598e0cf965SAdrian Hunter curr_map = map_groups__find(kmaps, map->type, pos->start); 6608e0cf965SAdrian Hunter 6618e0cf965SAdrian Hunter if (!curr_map || (filter && filter(curr_map, pos))) { 662facf3f06SArnaldo Carvalho de Melo rb_erase_init(&pos->rb_node, root); 6638e0cf965SAdrian Hunter symbol__delete(pos); 6648e0cf965SAdrian Hunter } else { 6658e0cf965SAdrian Hunter pos->start -= curr_map->start - curr_map->pgoff; 6668e0cf965SAdrian Hunter if (pos->end) 6678e0cf965SAdrian Hunter pos->end -= curr_map->start - curr_map->pgoff; 6688e0cf965SAdrian Hunter if (curr_map != map) { 669facf3f06SArnaldo Carvalho de Melo rb_erase_init(&pos->rb_node, root); 6708e0cf965SAdrian Hunter symbols__insert( 6718e0cf965SAdrian Hunter &curr_map->dso->symbols[curr_map->type], 6728e0cf965SAdrian Hunter pos); 6738e0cf965SAdrian Hunter ++moved; 6748e0cf965SAdrian Hunter } else { 6758e0cf965SAdrian Hunter ++count; 6768e0cf965SAdrian Hunter } 6778e0cf965SAdrian Hunter } 6788e0cf965SAdrian Hunter } 6798e0cf965SAdrian Hunter 6808e0cf965SAdrian Hunter /* Symbols have been adjusted */ 6818e0cf965SAdrian Hunter dso->adjust_symbols = 1; 6828e0cf965SAdrian Hunter 6838e0cf965SAdrian Hunter return count + moved; 6848e0cf965SAdrian Hunter } 6858e0cf965SAdrian Hunter 6862e538c4aSArnaldo Carvalho de Melo /* 6872e538c4aSArnaldo Carvalho de Melo * Split the symbols into maps, making sure there are no overlaps, i.e. the 6882e538c4aSArnaldo Carvalho de Melo * kernel range is broken in several maps, named [kernel].N, as we don't have 6892e538c4aSArnaldo Carvalho de Melo * the original ELF section names vmlinux have. 6902e538c4aSArnaldo Carvalho de Melo */ 691d9b62abaSAdrian Hunter static int dso__split_kallsyms(struct dso *dso, struct map *map, u64 delta, 6929de89fe7SArnaldo Carvalho de Melo symbol_filter_t filter) 6932e538c4aSArnaldo Carvalho de Melo { 694ba92732eSWang Nan struct map_groups *kmaps = map__kmaps(map); 695ba92732eSWang Nan struct machine *machine; 6964e06255fSArnaldo Carvalho de Melo struct map *curr_map = map; 6972e538c4aSArnaldo Carvalho de Melo struct symbol *pos; 6988a953312SArnaldo Carvalho de Melo int count = 0, moved = 0; 699aeafcbafSArnaldo Carvalho de Melo struct rb_root *root = &dso->symbols[map->type]; 7004e06255fSArnaldo Carvalho de Melo struct rb_node *next = rb_first(root); 7012e538c4aSArnaldo Carvalho de Melo int kernel_range = 0; 7022e538c4aSArnaldo Carvalho de Melo 703ba92732eSWang Nan if (!kmaps) 704ba92732eSWang Nan return -1; 705ba92732eSWang Nan 706ba92732eSWang Nan machine = kmaps->machine; 707ba92732eSWang Nan 7082e538c4aSArnaldo Carvalho de Melo while (next) { 7092e538c4aSArnaldo Carvalho de Melo char *module; 7102e538c4aSArnaldo Carvalho de Melo 7112e538c4aSArnaldo Carvalho de Melo pos = rb_entry(next, struct symbol, rb_node); 7122e538c4aSArnaldo Carvalho de Melo next = rb_next(&pos->rb_node); 7132e538c4aSArnaldo Carvalho de Melo 7142e538c4aSArnaldo Carvalho de Melo module = strchr(pos->name, '\t'); 7152e538c4aSArnaldo Carvalho de Melo if (module) { 71675be6cf4SArnaldo Carvalho de Melo if (!symbol_conf.use_modules) 7171de8e245SArnaldo Carvalho de Melo goto discard_symbol; 7181de8e245SArnaldo Carvalho de Melo 7192e538c4aSArnaldo Carvalho de Melo *module++ = '\0'; 7202e538c4aSArnaldo Carvalho de Melo 721b7cece76SArnaldo Carvalho de Melo if (strcmp(curr_map->dso->short_name, module)) { 722a1645ce1SZhang, Yanmin if (curr_map != map && 723aeafcbafSArnaldo Carvalho de Melo dso->kernel == DSO_TYPE_GUEST_KERNEL && 72423346f21SArnaldo Carvalho de Melo machine__is_default_guest(machine)) { 725a1645ce1SZhang, Yanmin /* 726a1645ce1SZhang, Yanmin * We assume all symbols of a module are 727a1645ce1SZhang, Yanmin * continuous in * kallsyms, so curr_map 728a1645ce1SZhang, Yanmin * points to a module and all its 729a1645ce1SZhang, Yanmin * symbols are in its kmap. Mark it as 730a1645ce1SZhang, Yanmin * loaded. 731a1645ce1SZhang, Yanmin */ 732a1645ce1SZhang, Yanmin dso__set_loaded(curr_map->dso, 733a1645ce1SZhang, Yanmin curr_map->type); 734af427bf5SArnaldo Carvalho de Melo } 735b7cece76SArnaldo Carvalho de Melo 736a1645ce1SZhang, Yanmin curr_map = map_groups__find_by_name(kmaps, 737a1645ce1SZhang, Yanmin map->type, module); 738a1645ce1SZhang, Yanmin if (curr_map == NULL) { 7392f51903bSArnaldo Carvalho de Melo pr_debug("%s/proc/{kallsyms,modules} " 740a1645ce1SZhang, Yanmin "inconsistency while looking " 741a1645ce1SZhang, Yanmin "for \"%s\" module!\n", 74223346f21SArnaldo Carvalho de Melo machine->root_dir, module); 743a1645ce1SZhang, Yanmin curr_map = map; 744a1645ce1SZhang, Yanmin goto discard_symbol; 745a1645ce1SZhang, Yanmin } 746a1645ce1SZhang, Yanmin 747a1645ce1SZhang, Yanmin if (curr_map->dso->loaded && 74823346f21SArnaldo Carvalho de Melo !machine__is_default_guest(machine)) 749b7cece76SArnaldo Carvalho de Melo goto discard_symbol; 750af427bf5SArnaldo Carvalho de Melo } 75186470930SIngo Molnar /* 7522e538c4aSArnaldo Carvalho de Melo * So that we look just like we get from .ko files, 7532e538c4aSArnaldo Carvalho de Melo * i.e. not prelinked, relative to map->start. 75486470930SIngo Molnar */ 7554e06255fSArnaldo Carvalho de Melo pos->start = curr_map->map_ip(curr_map, pos->start); 7564e06255fSArnaldo Carvalho de Melo pos->end = curr_map->map_ip(curr_map, pos->end); 7574e06255fSArnaldo Carvalho de Melo } else if (curr_map != map) { 7582e538c4aSArnaldo Carvalho de Melo char dso_name[PATH_MAX]; 759aeafcbafSArnaldo Carvalho de Melo struct dso *ndso; 76086470930SIngo Molnar 761d9b62abaSAdrian Hunter if (delta) { 762d9b62abaSAdrian Hunter /* Kernel was relocated at boot time */ 763d9b62abaSAdrian Hunter pos->start -= delta; 764d9b62abaSAdrian Hunter pos->end -= delta; 765d9b62abaSAdrian Hunter } 766d9b62abaSAdrian Hunter 7678a953312SArnaldo Carvalho de Melo if (count == 0) { 7688a953312SArnaldo Carvalho de Melo curr_map = map; 7698a953312SArnaldo Carvalho de Melo goto filter_symbol; 7708a953312SArnaldo Carvalho de Melo } 7718a953312SArnaldo Carvalho de Melo 772aeafcbafSArnaldo Carvalho de Melo if (dso->kernel == DSO_TYPE_GUEST_KERNEL) 773a1645ce1SZhang, Yanmin snprintf(dso_name, sizeof(dso_name), 774a1645ce1SZhang, Yanmin "[guest.kernel].%d", 775a1645ce1SZhang, Yanmin kernel_range++); 776a1645ce1SZhang, Yanmin else 777a1645ce1SZhang, Yanmin snprintf(dso_name, sizeof(dso_name), 778a1645ce1SZhang, Yanmin "[kernel].%d", 7792e538c4aSArnaldo Carvalho de Melo kernel_range++); 78086470930SIngo Molnar 781aeafcbafSArnaldo Carvalho de Melo ndso = dso__new(dso_name); 782aeafcbafSArnaldo Carvalho de Melo if (ndso == NULL) 7832e538c4aSArnaldo Carvalho de Melo return -1; 7842e538c4aSArnaldo Carvalho de Melo 785aeafcbafSArnaldo Carvalho de Melo ndso->kernel = dso->kernel; 786a1645ce1SZhang, Yanmin 787aeafcbafSArnaldo Carvalho de Melo curr_map = map__new2(pos->start, ndso, map->type); 78837fe5fcbSZhang, Yanmin if (curr_map == NULL) { 789d3a7c489SArnaldo Carvalho de Melo dso__put(ndso); 7902e538c4aSArnaldo Carvalho de Melo return -1; 7912e538c4aSArnaldo Carvalho de Melo } 7922e538c4aSArnaldo Carvalho de Melo 7934e06255fSArnaldo Carvalho de Melo curr_map->map_ip = curr_map->unmap_ip = identity__map_ip; 7949de89fe7SArnaldo Carvalho de Melo map_groups__insert(kmaps, curr_map); 7952e538c4aSArnaldo Carvalho de Melo ++kernel_range; 796d9b62abaSAdrian Hunter } else if (delta) { 797d9b62abaSAdrian Hunter /* Kernel was relocated at boot time */ 798d9b62abaSAdrian Hunter pos->start -= delta; 799d9b62abaSAdrian Hunter pos->end -= delta; 8002e538c4aSArnaldo Carvalho de Melo } 8018a953312SArnaldo Carvalho de Melo filter_symbol: 8024e06255fSArnaldo Carvalho de Melo if (filter && filter(curr_map, pos)) { 8031de8e245SArnaldo Carvalho de Melo discard_symbol: rb_erase(&pos->rb_node, root); 80400a192b3SArnaldo Carvalho de Melo symbol__delete(pos); 8052e538c4aSArnaldo Carvalho de Melo } else { 8064e06255fSArnaldo Carvalho de Melo if (curr_map != map) { 8074e06255fSArnaldo Carvalho de Melo rb_erase(&pos->rb_node, root); 8084e06255fSArnaldo Carvalho de Melo symbols__insert(&curr_map->dso->symbols[curr_map->type], pos); 8098a953312SArnaldo Carvalho de Melo ++moved; 8108a953312SArnaldo Carvalho de Melo } else 8118a953312SArnaldo Carvalho de Melo ++count; 8129974f496SMike Galbraith } 81386470930SIngo Molnar } 81486470930SIngo Molnar 815a1645ce1SZhang, Yanmin if (curr_map != map && 816aeafcbafSArnaldo Carvalho de Melo dso->kernel == DSO_TYPE_GUEST_KERNEL && 81723346f21SArnaldo Carvalho de Melo machine__is_default_guest(kmaps->machine)) { 818a1645ce1SZhang, Yanmin dso__set_loaded(curr_map->dso, curr_map->type); 819a1645ce1SZhang, Yanmin } 820a1645ce1SZhang, Yanmin 8218a953312SArnaldo Carvalho de Melo return count + moved; 82286470930SIngo Molnar } 82386470930SIngo Molnar 8243f067dcaSArnaldo Carvalho de Melo bool symbol__restricted_filename(const char *filename, 825ec80fde7SArnaldo Carvalho de Melo const char *restricted_filename) 826ec80fde7SArnaldo Carvalho de Melo { 827ec80fde7SArnaldo Carvalho de Melo bool restricted = false; 828ec80fde7SArnaldo Carvalho de Melo 829ec80fde7SArnaldo Carvalho de Melo if (symbol_conf.kptr_restrict) { 830ec80fde7SArnaldo Carvalho de Melo char *r = realpath(filename, NULL); 831ec80fde7SArnaldo Carvalho de Melo 832ec80fde7SArnaldo Carvalho de Melo if (r != NULL) { 833ec80fde7SArnaldo Carvalho de Melo restricted = strcmp(r, restricted_filename) == 0; 834ec80fde7SArnaldo Carvalho de Melo free(r); 835ec80fde7SArnaldo Carvalho de Melo return restricted; 836ec80fde7SArnaldo Carvalho de Melo } 837ec80fde7SArnaldo Carvalho de Melo } 838ec80fde7SArnaldo Carvalho de Melo 839ec80fde7SArnaldo Carvalho de Melo return restricted; 840ec80fde7SArnaldo Carvalho de Melo } 841ec80fde7SArnaldo Carvalho de Melo 84252afdaf9SAdrian Hunter struct module_info { 84352afdaf9SAdrian Hunter struct rb_node rb_node; 84452afdaf9SAdrian Hunter char *name; 84552afdaf9SAdrian Hunter u64 start; 84652afdaf9SAdrian Hunter }; 84752afdaf9SAdrian Hunter 84852afdaf9SAdrian Hunter static void add_module(struct module_info *mi, struct rb_root *modules) 84952afdaf9SAdrian Hunter { 85052afdaf9SAdrian Hunter struct rb_node **p = &modules->rb_node; 85152afdaf9SAdrian Hunter struct rb_node *parent = NULL; 85252afdaf9SAdrian Hunter struct module_info *m; 85352afdaf9SAdrian Hunter 85452afdaf9SAdrian Hunter while (*p != NULL) { 85552afdaf9SAdrian Hunter parent = *p; 85652afdaf9SAdrian Hunter m = rb_entry(parent, struct module_info, rb_node); 85752afdaf9SAdrian Hunter if (strcmp(mi->name, m->name) < 0) 85852afdaf9SAdrian Hunter p = &(*p)->rb_left; 85952afdaf9SAdrian Hunter else 86052afdaf9SAdrian Hunter p = &(*p)->rb_right; 86152afdaf9SAdrian Hunter } 86252afdaf9SAdrian Hunter rb_link_node(&mi->rb_node, parent, p); 86352afdaf9SAdrian Hunter rb_insert_color(&mi->rb_node, modules); 86452afdaf9SAdrian Hunter } 86552afdaf9SAdrian Hunter 86652afdaf9SAdrian Hunter static void delete_modules(struct rb_root *modules) 86752afdaf9SAdrian Hunter { 86852afdaf9SAdrian Hunter struct module_info *mi; 86952afdaf9SAdrian Hunter struct rb_node *next = rb_first(modules); 87052afdaf9SAdrian Hunter 87152afdaf9SAdrian Hunter while (next) { 87252afdaf9SAdrian Hunter mi = rb_entry(next, struct module_info, rb_node); 87352afdaf9SAdrian Hunter next = rb_next(&mi->rb_node); 87452afdaf9SAdrian Hunter rb_erase(&mi->rb_node, modules); 87574cf249dSArnaldo Carvalho de Melo zfree(&mi->name); 87652afdaf9SAdrian Hunter free(mi); 87752afdaf9SAdrian Hunter } 87852afdaf9SAdrian Hunter } 87952afdaf9SAdrian Hunter 88052afdaf9SAdrian Hunter static struct module_info *find_module(const char *name, 88152afdaf9SAdrian Hunter struct rb_root *modules) 88252afdaf9SAdrian Hunter { 88352afdaf9SAdrian Hunter struct rb_node *n = modules->rb_node; 88452afdaf9SAdrian Hunter 88552afdaf9SAdrian Hunter while (n) { 88652afdaf9SAdrian Hunter struct module_info *m; 88752afdaf9SAdrian Hunter int cmp; 88852afdaf9SAdrian Hunter 88952afdaf9SAdrian Hunter m = rb_entry(n, struct module_info, rb_node); 89052afdaf9SAdrian Hunter cmp = strcmp(name, m->name); 89152afdaf9SAdrian Hunter if (cmp < 0) 89252afdaf9SAdrian Hunter n = n->rb_left; 89352afdaf9SAdrian Hunter else if (cmp > 0) 89452afdaf9SAdrian Hunter n = n->rb_right; 89552afdaf9SAdrian Hunter else 89652afdaf9SAdrian Hunter return m; 89752afdaf9SAdrian Hunter } 89852afdaf9SAdrian Hunter 89952afdaf9SAdrian Hunter return NULL; 90052afdaf9SAdrian Hunter } 90152afdaf9SAdrian Hunter 90252afdaf9SAdrian Hunter static int __read_proc_modules(void *arg, const char *name, u64 start) 90352afdaf9SAdrian Hunter { 90452afdaf9SAdrian Hunter struct rb_root *modules = arg; 90552afdaf9SAdrian Hunter struct module_info *mi; 90652afdaf9SAdrian Hunter 90752afdaf9SAdrian Hunter mi = zalloc(sizeof(struct module_info)); 90852afdaf9SAdrian Hunter if (!mi) 90952afdaf9SAdrian Hunter return -ENOMEM; 91052afdaf9SAdrian Hunter 91152afdaf9SAdrian Hunter mi->name = strdup(name); 91252afdaf9SAdrian Hunter mi->start = start; 91352afdaf9SAdrian Hunter 91452afdaf9SAdrian Hunter if (!mi->name) { 91552afdaf9SAdrian Hunter free(mi); 91652afdaf9SAdrian Hunter return -ENOMEM; 91752afdaf9SAdrian Hunter } 91852afdaf9SAdrian Hunter 91952afdaf9SAdrian Hunter add_module(mi, modules); 92052afdaf9SAdrian Hunter 92152afdaf9SAdrian Hunter return 0; 92252afdaf9SAdrian Hunter } 92352afdaf9SAdrian Hunter 92452afdaf9SAdrian Hunter static int read_proc_modules(const char *filename, struct rb_root *modules) 92552afdaf9SAdrian Hunter { 92652afdaf9SAdrian Hunter if (symbol__restricted_filename(filename, "/proc/modules")) 92752afdaf9SAdrian Hunter return -1; 92852afdaf9SAdrian Hunter 92952afdaf9SAdrian Hunter if (modules__parse(filename, modules, __read_proc_modules)) { 93052afdaf9SAdrian Hunter delete_modules(modules); 93152afdaf9SAdrian Hunter return -1; 93252afdaf9SAdrian Hunter } 93352afdaf9SAdrian Hunter 93452afdaf9SAdrian Hunter return 0; 93552afdaf9SAdrian Hunter } 93652afdaf9SAdrian Hunter 937fc1b691dSAdrian Hunter int compare_proc_modules(const char *from, const char *to) 938fc1b691dSAdrian Hunter { 939fc1b691dSAdrian Hunter struct rb_root from_modules = RB_ROOT; 940fc1b691dSAdrian Hunter struct rb_root to_modules = RB_ROOT; 941fc1b691dSAdrian Hunter struct rb_node *from_node, *to_node; 942fc1b691dSAdrian Hunter struct module_info *from_m, *to_m; 943fc1b691dSAdrian Hunter int ret = -1; 944fc1b691dSAdrian Hunter 945fc1b691dSAdrian Hunter if (read_proc_modules(from, &from_modules)) 946fc1b691dSAdrian Hunter return -1; 947fc1b691dSAdrian Hunter 948fc1b691dSAdrian Hunter if (read_proc_modules(to, &to_modules)) 949fc1b691dSAdrian Hunter goto out_delete_from; 950fc1b691dSAdrian Hunter 951fc1b691dSAdrian Hunter from_node = rb_first(&from_modules); 952fc1b691dSAdrian Hunter to_node = rb_first(&to_modules); 953fc1b691dSAdrian Hunter while (from_node) { 954fc1b691dSAdrian Hunter if (!to_node) 955fc1b691dSAdrian Hunter break; 956fc1b691dSAdrian Hunter 957fc1b691dSAdrian Hunter from_m = rb_entry(from_node, struct module_info, rb_node); 958fc1b691dSAdrian Hunter to_m = rb_entry(to_node, struct module_info, rb_node); 959fc1b691dSAdrian Hunter 960fc1b691dSAdrian Hunter if (from_m->start != to_m->start || 961fc1b691dSAdrian Hunter strcmp(from_m->name, to_m->name)) 962fc1b691dSAdrian Hunter break; 963fc1b691dSAdrian Hunter 964fc1b691dSAdrian Hunter from_node = rb_next(from_node); 965fc1b691dSAdrian Hunter to_node = rb_next(to_node); 966fc1b691dSAdrian Hunter } 967fc1b691dSAdrian Hunter 968fc1b691dSAdrian Hunter if (!from_node && !to_node) 969fc1b691dSAdrian Hunter ret = 0; 970fc1b691dSAdrian Hunter 971fc1b691dSAdrian Hunter delete_modules(&to_modules); 972fc1b691dSAdrian Hunter out_delete_from: 973fc1b691dSAdrian Hunter delete_modules(&from_modules); 974fc1b691dSAdrian Hunter 975fc1b691dSAdrian Hunter return ret; 976fc1b691dSAdrian Hunter } 977fc1b691dSAdrian Hunter 97852afdaf9SAdrian Hunter static int do_validate_kcore_modules(const char *filename, struct map *map, 97952afdaf9SAdrian Hunter struct map_groups *kmaps) 98052afdaf9SAdrian Hunter { 98152afdaf9SAdrian Hunter struct rb_root modules = RB_ROOT; 98252afdaf9SAdrian Hunter struct map *old_map; 98352afdaf9SAdrian Hunter int err; 98452afdaf9SAdrian Hunter 98552afdaf9SAdrian Hunter err = read_proc_modules(filename, &modules); 98652afdaf9SAdrian Hunter if (err) 98752afdaf9SAdrian Hunter return err; 98852afdaf9SAdrian Hunter 98952afdaf9SAdrian Hunter old_map = map_groups__first(kmaps, map->type); 99052afdaf9SAdrian Hunter while (old_map) { 99152afdaf9SAdrian Hunter struct map *next = map_groups__next(old_map); 99252afdaf9SAdrian Hunter struct module_info *mi; 99352afdaf9SAdrian Hunter 99452afdaf9SAdrian Hunter if (old_map == map || old_map->start == map->start) { 99552afdaf9SAdrian Hunter /* The kernel map */ 99652afdaf9SAdrian Hunter old_map = next; 99752afdaf9SAdrian Hunter continue; 99852afdaf9SAdrian Hunter } 99952afdaf9SAdrian Hunter 100052afdaf9SAdrian Hunter /* Module must be in memory at the same address */ 100152afdaf9SAdrian Hunter mi = find_module(old_map->dso->short_name, &modules); 100252afdaf9SAdrian Hunter if (!mi || mi->start != old_map->start) { 100352afdaf9SAdrian Hunter err = -EINVAL; 100452afdaf9SAdrian Hunter goto out; 100552afdaf9SAdrian Hunter } 100652afdaf9SAdrian Hunter 100752afdaf9SAdrian Hunter old_map = next; 100852afdaf9SAdrian Hunter } 100952afdaf9SAdrian Hunter out: 101052afdaf9SAdrian Hunter delete_modules(&modules); 101152afdaf9SAdrian Hunter return err; 101252afdaf9SAdrian Hunter } 101352afdaf9SAdrian Hunter 101452afdaf9SAdrian Hunter /* 101552afdaf9SAdrian Hunter * If kallsyms is referenced by name then we look for filename in the same 101652afdaf9SAdrian Hunter * directory. 101752afdaf9SAdrian Hunter */ 101852afdaf9SAdrian Hunter static bool filename_from_kallsyms_filename(char *filename, 101952afdaf9SAdrian Hunter const char *base_name, 102052afdaf9SAdrian Hunter const char *kallsyms_filename) 102152afdaf9SAdrian Hunter { 102252afdaf9SAdrian Hunter char *name; 102352afdaf9SAdrian Hunter 102452afdaf9SAdrian Hunter strcpy(filename, kallsyms_filename); 102552afdaf9SAdrian Hunter name = strrchr(filename, '/'); 102652afdaf9SAdrian Hunter if (!name) 102752afdaf9SAdrian Hunter return false; 102852afdaf9SAdrian Hunter 102952afdaf9SAdrian Hunter name += 1; 103052afdaf9SAdrian Hunter 103152afdaf9SAdrian Hunter if (!strcmp(name, "kallsyms")) { 103252afdaf9SAdrian Hunter strcpy(name, base_name); 103352afdaf9SAdrian Hunter return true; 103452afdaf9SAdrian Hunter } 103552afdaf9SAdrian Hunter 103652afdaf9SAdrian Hunter return false; 103752afdaf9SAdrian Hunter } 103852afdaf9SAdrian Hunter 103952afdaf9SAdrian Hunter static int validate_kcore_modules(const char *kallsyms_filename, 104052afdaf9SAdrian Hunter struct map *map) 104152afdaf9SAdrian Hunter { 1042ba92732eSWang Nan struct map_groups *kmaps = map__kmaps(map); 104352afdaf9SAdrian Hunter char modules_filename[PATH_MAX]; 104452afdaf9SAdrian Hunter 1045ba92732eSWang Nan if (!kmaps) 1046ba92732eSWang Nan return -EINVAL; 1047ba92732eSWang Nan 104852afdaf9SAdrian Hunter if (!filename_from_kallsyms_filename(modules_filename, "modules", 104952afdaf9SAdrian Hunter kallsyms_filename)) 105052afdaf9SAdrian Hunter return -EINVAL; 105152afdaf9SAdrian Hunter 105252afdaf9SAdrian Hunter if (do_validate_kcore_modules(modules_filename, map, kmaps)) 105352afdaf9SAdrian Hunter return -EINVAL; 105452afdaf9SAdrian Hunter 105552afdaf9SAdrian Hunter return 0; 105652afdaf9SAdrian Hunter } 105752afdaf9SAdrian Hunter 1058a00d28cbSAdrian Hunter static int validate_kcore_addresses(const char *kallsyms_filename, 1059a00d28cbSAdrian Hunter struct map *map) 1060a00d28cbSAdrian Hunter { 1061a00d28cbSAdrian Hunter struct kmap *kmap = map__kmap(map); 1062a00d28cbSAdrian Hunter 1063ba92732eSWang Nan if (!kmap) 1064ba92732eSWang Nan return -EINVAL; 1065ba92732eSWang Nan 1066a00d28cbSAdrian Hunter if (kmap->ref_reloc_sym && kmap->ref_reloc_sym->name) { 1067a00d28cbSAdrian Hunter u64 start; 1068a00d28cbSAdrian Hunter 1069a00d28cbSAdrian Hunter start = kallsyms__get_function_start(kallsyms_filename, 1070a00d28cbSAdrian Hunter kmap->ref_reloc_sym->name); 1071a00d28cbSAdrian Hunter if (start != kmap->ref_reloc_sym->addr) 1072a00d28cbSAdrian Hunter return -EINVAL; 1073a00d28cbSAdrian Hunter } 1074a00d28cbSAdrian Hunter 1075a00d28cbSAdrian Hunter return validate_kcore_modules(kallsyms_filename, map); 1076a00d28cbSAdrian Hunter } 1077a00d28cbSAdrian Hunter 10788e0cf965SAdrian Hunter struct kcore_mapfn_data { 10798e0cf965SAdrian Hunter struct dso *dso; 10808e0cf965SAdrian Hunter enum map_type type; 10818e0cf965SAdrian Hunter struct list_head maps; 10828e0cf965SAdrian Hunter }; 10838e0cf965SAdrian Hunter 10848e0cf965SAdrian Hunter static int kcore_mapfn(u64 start, u64 len, u64 pgoff, void *data) 10858e0cf965SAdrian Hunter { 10868e0cf965SAdrian Hunter struct kcore_mapfn_data *md = data; 10878e0cf965SAdrian Hunter struct map *map; 10888e0cf965SAdrian Hunter 10898e0cf965SAdrian Hunter map = map__new2(start, md->dso, md->type); 10908e0cf965SAdrian Hunter if (map == NULL) 10918e0cf965SAdrian Hunter return -ENOMEM; 10928e0cf965SAdrian Hunter 10938e0cf965SAdrian Hunter map->end = map->start + len; 10948e0cf965SAdrian Hunter map->pgoff = pgoff; 10958e0cf965SAdrian Hunter 10968e0cf965SAdrian Hunter list_add(&map->node, &md->maps); 10978e0cf965SAdrian Hunter 10988e0cf965SAdrian Hunter return 0; 10998e0cf965SAdrian Hunter } 11008e0cf965SAdrian Hunter 11018e0cf965SAdrian Hunter static int dso__load_kcore(struct dso *dso, struct map *map, 11028e0cf965SAdrian Hunter const char *kallsyms_filename) 11038e0cf965SAdrian Hunter { 1104ba92732eSWang Nan struct map_groups *kmaps = map__kmaps(map); 1105ba92732eSWang Nan struct machine *machine; 11068e0cf965SAdrian Hunter struct kcore_mapfn_data md; 11078e0cf965SAdrian Hunter struct map *old_map, *new_map, *replacement_map = NULL; 11088e0cf965SAdrian Hunter bool is_64_bit; 11098e0cf965SAdrian Hunter int err, fd; 11108e0cf965SAdrian Hunter char kcore_filename[PATH_MAX]; 11118e0cf965SAdrian Hunter struct symbol *sym; 11128e0cf965SAdrian Hunter 1113ba92732eSWang Nan if (!kmaps) 1114ba92732eSWang Nan return -EINVAL; 1115ba92732eSWang Nan 1116ba92732eSWang Nan machine = kmaps->machine; 1117ba92732eSWang Nan 11188e0cf965SAdrian Hunter /* This function requires that the map is the kernel map */ 11198e0cf965SAdrian Hunter if (map != machine->vmlinux_maps[map->type]) 11208e0cf965SAdrian Hunter return -EINVAL; 11218e0cf965SAdrian Hunter 112252afdaf9SAdrian Hunter if (!filename_from_kallsyms_filename(kcore_filename, "kcore", 11238e0cf965SAdrian Hunter kallsyms_filename)) 11248e0cf965SAdrian Hunter return -EINVAL; 11258e0cf965SAdrian Hunter 1126a00d28cbSAdrian Hunter /* Modules and kernel must be present at their original addresses */ 1127a00d28cbSAdrian Hunter if (validate_kcore_addresses(kallsyms_filename, map)) 112852afdaf9SAdrian Hunter return -EINVAL; 112952afdaf9SAdrian Hunter 11308e0cf965SAdrian Hunter md.dso = dso; 11318e0cf965SAdrian Hunter md.type = map->type; 11328e0cf965SAdrian Hunter INIT_LIST_HEAD(&md.maps); 11338e0cf965SAdrian Hunter 11348e0cf965SAdrian Hunter fd = open(kcore_filename, O_RDONLY); 113536c8bb56SLi Zhang if (fd < 0) { 113636c8bb56SLi Zhang pr_err("%s requires CAP_SYS_RAWIO capability to access.\n", 113736c8bb56SLi Zhang kcore_filename); 11388e0cf965SAdrian Hunter return -EINVAL; 113936c8bb56SLi Zhang } 11408e0cf965SAdrian Hunter 11418e0cf965SAdrian Hunter /* Read new maps into temporary lists */ 11428e0cf965SAdrian Hunter err = file__read_maps(fd, md.type == MAP__FUNCTION, kcore_mapfn, &md, 11438e0cf965SAdrian Hunter &is_64_bit); 11448e0cf965SAdrian Hunter if (err) 11458e0cf965SAdrian Hunter goto out_err; 1146c6d8f2a4SAdrian Hunter dso->is_64_bit = is_64_bit; 11478e0cf965SAdrian Hunter 11488e0cf965SAdrian Hunter if (list_empty(&md.maps)) { 11498e0cf965SAdrian Hunter err = -EINVAL; 11508e0cf965SAdrian Hunter goto out_err; 11518e0cf965SAdrian Hunter } 11528e0cf965SAdrian Hunter 11538e0cf965SAdrian Hunter /* Remove old maps */ 11548e0cf965SAdrian Hunter old_map = map_groups__first(kmaps, map->type); 11558e0cf965SAdrian Hunter while (old_map) { 11568e0cf965SAdrian Hunter struct map *next = map_groups__next(old_map); 11578e0cf965SAdrian Hunter 11588e0cf965SAdrian Hunter if (old_map != map) 11598e0cf965SAdrian Hunter map_groups__remove(kmaps, old_map); 11608e0cf965SAdrian Hunter old_map = next; 11618e0cf965SAdrian Hunter } 11628e0cf965SAdrian Hunter 11638e0cf965SAdrian Hunter /* Find the kernel map using the first symbol */ 11648e0cf965SAdrian Hunter sym = dso__first_symbol(dso, map->type); 11658e0cf965SAdrian Hunter list_for_each_entry(new_map, &md.maps, node) { 11668e0cf965SAdrian Hunter if (sym && sym->start >= new_map->start && 11678e0cf965SAdrian Hunter sym->start < new_map->end) { 11688e0cf965SAdrian Hunter replacement_map = new_map; 11698e0cf965SAdrian Hunter break; 11708e0cf965SAdrian Hunter } 11718e0cf965SAdrian Hunter } 11728e0cf965SAdrian Hunter 11738e0cf965SAdrian Hunter if (!replacement_map) 11748e0cf965SAdrian Hunter replacement_map = list_entry(md.maps.next, struct map, node); 11758e0cf965SAdrian Hunter 11768e0cf965SAdrian Hunter /* Add new maps */ 11778e0cf965SAdrian Hunter while (!list_empty(&md.maps)) { 11788e0cf965SAdrian Hunter new_map = list_entry(md.maps.next, struct map, node); 1179facf3f06SArnaldo Carvalho de Melo list_del_init(&new_map->node); 11808e0cf965SAdrian Hunter if (new_map == replacement_map) { 11818e0cf965SAdrian Hunter map->start = new_map->start; 11828e0cf965SAdrian Hunter map->end = new_map->end; 11838e0cf965SAdrian Hunter map->pgoff = new_map->pgoff; 11848e0cf965SAdrian Hunter map->map_ip = new_map->map_ip; 11858e0cf965SAdrian Hunter map->unmap_ip = new_map->unmap_ip; 11868e0cf965SAdrian Hunter /* Ensure maps are correctly ordered */ 118784c2cafaSArnaldo Carvalho de Melo map__get(map); 11888e0cf965SAdrian Hunter map_groups__remove(kmaps, map); 11898e0cf965SAdrian Hunter map_groups__insert(kmaps, map); 119084c2cafaSArnaldo Carvalho de Melo map__put(map); 11918e0cf965SAdrian Hunter } else { 11928e0cf965SAdrian Hunter map_groups__insert(kmaps, new_map); 11938e0cf965SAdrian Hunter } 119484c2cafaSArnaldo Carvalho de Melo 119584c2cafaSArnaldo Carvalho de Melo map__put(new_map); 11968e0cf965SAdrian Hunter } 11978e0cf965SAdrian Hunter 11988e0cf965SAdrian Hunter /* 11998e0cf965SAdrian Hunter * Set the data type and long name so that kcore can be read via 12008e0cf965SAdrian Hunter * dso__data_read_addr(). 12018e0cf965SAdrian Hunter */ 12028e0cf965SAdrian Hunter if (dso->kernel == DSO_TYPE_GUEST_KERNEL) 12035f70619dSArnaldo Carvalho de Melo dso->binary_type = DSO_BINARY_TYPE__GUEST_KCORE; 12048e0cf965SAdrian Hunter else 12055f70619dSArnaldo Carvalho de Melo dso->binary_type = DSO_BINARY_TYPE__KCORE; 12067e155d4dSArnaldo Carvalho de Melo dso__set_long_name(dso, strdup(kcore_filename), true); 12078e0cf965SAdrian Hunter 12088e0cf965SAdrian Hunter close(fd); 12098e0cf965SAdrian Hunter 12108e0cf965SAdrian Hunter if (map->type == MAP__FUNCTION) 12118e0cf965SAdrian Hunter pr_debug("Using %s for kernel object code\n", kcore_filename); 12128e0cf965SAdrian Hunter else 12138e0cf965SAdrian Hunter pr_debug("Using %s for kernel data\n", kcore_filename); 12148e0cf965SAdrian Hunter 12158e0cf965SAdrian Hunter return 0; 12168e0cf965SAdrian Hunter 12178e0cf965SAdrian Hunter out_err: 12188e0cf965SAdrian Hunter while (!list_empty(&md.maps)) { 12198e0cf965SAdrian Hunter map = list_entry(md.maps.next, struct map, node); 1220facf3f06SArnaldo Carvalho de Melo list_del_init(&map->node); 122184c2cafaSArnaldo Carvalho de Melo map__put(map); 12228e0cf965SAdrian Hunter } 12238e0cf965SAdrian Hunter close(fd); 12248e0cf965SAdrian Hunter return -EINVAL; 12258e0cf965SAdrian Hunter } 12268e0cf965SAdrian Hunter 1227d9b62abaSAdrian Hunter /* 1228d9b62abaSAdrian Hunter * If the kernel is relocated at boot time, kallsyms won't match. Compute the 1229d9b62abaSAdrian Hunter * delta based on the relocation reference symbol. 1230d9b62abaSAdrian Hunter */ 1231d9b62abaSAdrian Hunter static int kallsyms__delta(struct map *map, const char *filename, u64 *delta) 1232d9b62abaSAdrian Hunter { 1233d9b62abaSAdrian Hunter struct kmap *kmap = map__kmap(map); 1234d9b62abaSAdrian Hunter u64 addr; 1235d9b62abaSAdrian Hunter 1236ba92732eSWang Nan if (!kmap) 1237ba92732eSWang Nan return -1; 1238ba92732eSWang Nan 1239d9b62abaSAdrian Hunter if (!kmap->ref_reloc_sym || !kmap->ref_reloc_sym->name) 1240d9b62abaSAdrian Hunter return 0; 1241d9b62abaSAdrian Hunter 1242d9b62abaSAdrian Hunter addr = kallsyms__get_function_start(filename, 1243d9b62abaSAdrian Hunter kmap->ref_reloc_sym->name); 1244d9b62abaSAdrian Hunter if (!addr) 1245d9b62abaSAdrian Hunter return -1; 1246d9b62abaSAdrian Hunter 1247d9b62abaSAdrian Hunter *delta = addr - kmap->ref_reloc_sym->addr; 1248d9b62abaSAdrian Hunter return 0; 1249d9b62abaSAdrian Hunter } 1250d9b62abaSAdrian Hunter 1251aeafcbafSArnaldo Carvalho de Melo int dso__load_kallsyms(struct dso *dso, const char *filename, 12529de89fe7SArnaldo Carvalho de Melo struct map *map, symbol_filter_t filter) 12532e538c4aSArnaldo Carvalho de Melo { 1254d9b62abaSAdrian Hunter u64 delta = 0; 1255d9b62abaSAdrian Hunter 1256ec80fde7SArnaldo Carvalho de Melo if (symbol__restricted_filename(filename, "/proc/kallsyms")) 1257ec80fde7SArnaldo Carvalho de Melo return -1; 1258ec80fde7SArnaldo Carvalho de Melo 1259aeafcbafSArnaldo Carvalho de Melo if (dso__load_all_kallsyms(dso, filename, map) < 0) 12602e538c4aSArnaldo Carvalho de Melo return -1; 12612e538c4aSArnaldo Carvalho de Melo 1262d9b62abaSAdrian Hunter if (kallsyms__delta(map, filename, &delta)) 1263d9b62abaSAdrian Hunter return -1; 1264d9b62abaSAdrian Hunter 1265694bf407SAnton Blanchard symbols__fixup_duplicate(&dso->symbols[map->type]); 12663f5a4272SAnton Blanchard symbols__fixup_end(&dso->symbols[map->type]); 12673f5a4272SAnton Blanchard 1268aeafcbafSArnaldo Carvalho de Melo if (dso->kernel == DSO_TYPE_GUEST_KERNEL) 126944f24cb3SJiri Olsa dso->symtab_type = DSO_BINARY_TYPE__GUEST_KALLSYMS; 1270a1645ce1SZhang, Yanmin else 127144f24cb3SJiri Olsa dso->symtab_type = DSO_BINARY_TYPE__KALLSYMS; 12722e538c4aSArnaldo Carvalho de Melo 12738e0cf965SAdrian Hunter if (!dso__load_kcore(dso, map, filename)) 12748e0cf965SAdrian Hunter return dso__split_kallsyms_for_kcore(dso, map, filter); 12758e0cf965SAdrian Hunter else 1276d9b62abaSAdrian Hunter return dso__split_kallsyms(dso, map, delta, filter); 1277af427bf5SArnaldo Carvalho de Melo } 1278af427bf5SArnaldo Carvalho de Melo 1279aeafcbafSArnaldo Carvalho de Melo static int dso__load_perf_map(struct dso *dso, struct map *map, 12806beba7adSArnaldo Carvalho de Melo symbol_filter_t filter) 128180d496beSPekka Enberg { 128280d496beSPekka Enberg char *line = NULL; 128380d496beSPekka Enberg size_t n; 128480d496beSPekka Enberg FILE *file; 128580d496beSPekka Enberg int nr_syms = 0; 128680d496beSPekka Enberg 1287aeafcbafSArnaldo Carvalho de Melo file = fopen(dso->long_name, "r"); 128880d496beSPekka Enberg if (file == NULL) 128980d496beSPekka Enberg goto out_failure; 129080d496beSPekka Enberg 129180d496beSPekka Enberg while (!feof(file)) { 12929cffa8d5SPaul Mackerras u64 start, size; 129380d496beSPekka Enberg struct symbol *sym; 129480d496beSPekka Enberg int line_len, len; 129580d496beSPekka Enberg 129680d496beSPekka Enberg line_len = getline(&line, &n, file); 129780d496beSPekka Enberg if (line_len < 0) 129880d496beSPekka Enberg break; 129980d496beSPekka Enberg 130080d496beSPekka Enberg if (!line) 130180d496beSPekka Enberg goto out_failure; 130280d496beSPekka Enberg 130380d496beSPekka Enberg line[--line_len] = '\0'; /* \n */ 130480d496beSPekka Enberg 130580d496beSPekka Enberg len = hex2u64(line, &start); 130680d496beSPekka Enberg 130780d496beSPekka Enberg len++; 130880d496beSPekka Enberg if (len + 2 >= line_len) 130980d496beSPekka Enberg continue; 131080d496beSPekka Enberg 131180d496beSPekka Enberg len += hex2u64(line + len, &size); 131280d496beSPekka Enberg 131380d496beSPekka Enberg len++; 131480d496beSPekka Enberg if (len + 2 >= line_len) 131580d496beSPekka Enberg continue; 131680d496beSPekka Enberg 1317c408fedfSArnaldo Carvalho de Melo sym = symbol__new(start, size, STB_GLOBAL, line + len); 131880d496beSPekka Enberg 131980d496beSPekka Enberg if (sym == NULL) 132080d496beSPekka Enberg goto out_delete_line; 132180d496beSPekka Enberg 1322439d473bSArnaldo Carvalho de Melo if (filter && filter(map, sym)) 132300a192b3SArnaldo Carvalho de Melo symbol__delete(sym); 132480d496beSPekka Enberg else { 1325aeafcbafSArnaldo Carvalho de Melo symbols__insert(&dso->symbols[map->type], sym); 132680d496beSPekka Enberg nr_syms++; 132780d496beSPekka Enberg } 132880d496beSPekka Enberg } 132980d496beSPekka Enberg 133080d496beSPekka Enberg free(line); 133180d496beSPekka Enberg fclose(file); 133280d496beSPekka Enberg 133380d496beSPekka Enberg return nr_syms; 133480d496beSPekka Enberg 133580d496beSPekka Enberg out_delete_line: 133680d496beSPekka Enberg free(line); 133780d496beSPekka Enberg out_failure: 133880d496beSPekka Enberg return -1; 133980d496beSPekka Enberg } 134080d496beSPekka Enberg 13411029f9feSNamhyung Kim static bool dso__is_compatible_symtab_type(struct dso *dso, bool kmod, 13421029f9feSNamhyung Kim enum dso_binary_type type) 13431029f9feSNamhyung Kim { 13441029f9feSNamhyung Kim switch (type) { 13451029f9feSNamhyung Kim case DSO_BINARY_TYPE__JAVA_JIT: 13461029f9feSNamhyung Kim case DSO_BINARY_TYPE__DEBUGLINK: 13471029f9feSNamhyung Kim case DSO_BINARY_TYPE__SYSTEM_PATH_DSO: 13481029f9feSNamhyung Kim case DSO_BINARY_TYPE__FEDORA_DEBUGINFO: 13491029f9feSNamhyung Kim case DSO_BINARY_TYPE__UBUNTU_DEBUGINFO: 13501029f9feSNamhyung Kim case DSO_BINARY_TYPE__BUILDID_DEBUGINFO: 13511029f9feSNamhyung Kim case DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO: 13521029f9feSNamhyung Kim return !kmod && dso->kernel == DSO_TYPE_USER; 13531029f9feSNamhyung Kim 13541029f9feSNamhyung Kim case DSO_BINARY_TYPE__KALLSYMS: 13551029f9feSNamhyung Kim case DSO_BINARY_TYPE__VMLINUX: 13561029f9feSNamhyung Kim case DSO_BINARY_TYPE__KCORE: 13571029f9feSNamhyung Kim return dso->kernel == DSO_TYPE_KERNEL; 13581029f9feSNamhyung Kim 13591029f9feSNamhyung Kim case DSO_BINARY_TYPE__GUEST_KALLSYMS: 13601029f9feSNamhyung Kim case DSO_BINARY_TYPE__GUEST_VMLINUX: 13611029f9feSNamhyung Kim case DSO_BINARY_TYPE__GUEST_KCORE: 13621029f9feSNamhyung Kim return dso->kernel == DSO_TYPE_GUEST_KERNEL; 13631029f9feSNamhyung Kim 13641029f9feSNamhyung Kim case DSO_BINARY_TYPE__GUEST_KMODULE: 1365c00c48fcSNamhyung Kim case DSO_BINARY_TYPE__GUEST_KMODULE_COMP: 13661029f9feSNamhyung Kim case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE: 1367c00c48fcSNamhyung Kim case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP: 13681029f9feSNamhyung Kim /* 13691029f9feSNamhyung Kim * kernel modules know their symtab type - it's set when 13709f2de315SArnaldo Carvalho de Melo * creating a module dso in machine__findnew_module_map(). 13711029f9feSNamhyung Kim */ 13721029f9feSNamhyung Kim return kmod && dso->symtab_type == type; 13731029f9feSNamhyung Kim 13741029f9feSNamhyung Kim case DSO_BINARY_TYPE__BUILD_ID_CACHE: 13751029f9feSNamhyung Kim return true; 13761029f9feSNamhyung Kim 13771029f9feSNamhyung Kim case DSO_BINARY_TYPE__NOT_FOUND: 13781029f9feSNamhyung Kim default: 13791029f9feSNamhyung Kim return false; 13801029f9feSNamhyung Kim } 13811029f9feSNamhyung Kim } 13821029f9feSNamhyung Kim 1383aeafcbafSArnaldo Carvalho de Melo int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter) 138486470930SIngo Molnar { 1385c338aee8SArnaldo Carvalho de Melo char *name; 138686470930SIngo Molnar int ret = -1; 138744f24cb3SJiri Olsa u_int i; 138823346f21SArnaldo Carvalho de Melo struct machine *machine; 138944f24cb3SJiri Olsa char *root_dir = (char *) ""; 13903aafe5aeSCody P Schafer int ss_pos = 0; 13913aafe5aeSCody P Schafer struct symsrc ss_[2]; 13923aafe5aeSCody P Schafer struct symsrc *syms_ss = NULL, *runtime_ss = NULL; 13931029f9feSNamhyung Kim bool kmod; 139486470930SIngo Molnar 13954a936edcSNamhyung Kim pthread_mutex_lock(&dso->lock); 139666bd8424SArnaldo Carvalho de Melo 13974a936edcSNamhyung Kim /* check again under the dso->lock */ 13984a936edcSNamhyung Kim if (dso__loaded(dso, map->type)) { 13994a936edcSNamhyung Kim ret = 1; 14004a936edcSNamhyung Kim goto out; 14014a936edcSNamhyung Kim } 14024a936edcSNamhyung Kim 14034a936edcSNamhyung Kim if (dso->kernel) { 1404aeafcbafSArnaldo Carvalho de Melo if (dso->kernel == DSO_TYPE_KERNEL) 14054a936edcSNamhyung Kim ret = dso__load_kernel_sym(dso, map, filter); 1406aeafcbafSArnaldo Carvalho de Melo else if (dso->kernel == DSO_TYPE_GUEST_KERNEL) 14074a936edcSNamhyung Kim ret = dso__load_guest_kernel_sym(dso, map, filter); 14084a936edcSNamhyung Kim 14094a936edcSNamhyung Kim goto out; 14104a936edcSNamhyung Kim } 1411a1645ce1SZhang, Yanmin 141223346f21SArnaldo Carvalho de Melo if (map->groups && map->groups->machine) 141323346f21SArnaldo Carvalho de Melo machine = map->groups->machine; 1414a1645ce1SZhang, Yanmin else 141523346f21SArnaldo Carvalho de Melo machine = NULL; 1416c338aee8SArnaldo Carvalho de Melo 1417aeafcbafSArnaldo Carvalho de Melo dso->adjust_symbols = 0; 1418f5812a7aSArnaldo Carvalho de Melo 1419aeafcbafSArnaldo Carvalho de Melo if (strncmp(dso->name, "/tmp/perf-", 10) == 0) { 1420981c1252SPekka Enberg struct stat st; 1421981c1252SPekka Enberg 1422e9b52ef2SVasiliy Kulikov if (lstat(dso->name, &st) < 0) 14234a936edcSNamhyung Kim goto out; 1424981c1252SPekka Enberg 1425981c1252SPekka Enberg if (st.st_uid && (st.st_uid != geteuid())) { 1426981c1252SPekka Enberg pr_warning("File %s not owned by current user or root, " 1427981c1252SPekka Enberg "ignoring it.\n", dso->name); 14284a936edcSNamhyung Kim goto out; 1429981c1252SPekka Enberg } 1430981c1252SPekka Enberg 1431aeafcbafSArnaldo Carvalho de Melo ret = dso__load_perf_map(dso, map, filter); 143244f24cb3SJiri Olsa dso->symtab_type = ret > 0 ? DSO_BINARY_TYPE__JAVA_JIT : 143344f24cb3SJiri Olsa DSO_BINARY_TYPE__NOT_FOUND; 14344a936edcSNamhyung Kim goto out; 143594cb9e38SArnaldo Carvalho de Melo } 143694cb9e38SArnaldo Carvalho de Melo 143744f24cb3SJiri Olsa if (machine) 143844f24cb3SJiri Olsa root_dir = machine->root_dir; 143944f24cb3SJiri Olsa 1440164c800eSDavid Ahern name = malloc(PATH_MAX); 1441164c800eSDavid Ahern if (!name) 14424a936edcSNamhyung Kim goto out; 1443164c800eSDavid Ahern 14441029f9feSNamhyung Kim kmod = dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE || 1445c00c48fcSNamhyung Kim dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP || 1446c00c48fcSNamhyung Kim dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE || 1447c00c48fcSNamhyung Kim dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE_COMP; 14481029f9feSNamhyung Kim 14491029f9feSNamhyung Kim /* 14501029f9feSNamhyung Kim * Iterate over candidate debug images. 14513aafe5aeSCody P Schafer * Keep track of "interesting" ones (those which have a symtab, dynsym, 14523aafe5aeSCody P Schafer * and/or opd section) for processing. 14536da80ce8SDave Martin */ 145444f24cb3SJiri Olsa for (i = 0; i < DSO_BINARY_TYPE__SYMTAB_CNT; i++) { 14553aafe5aeSCody P Schafer struct symsrc *ss = &ss_[ss_pos]; 14563aafe5aeSCody P Schafer bool next_slot = false; 145744f24cb3SJiri Olsa 1458005f9294SCody P Schafer enum dso_binary_type symtab_type = binary_type_symtab[i]; 145944f24cb3SJiri Olsa 14601029f9feSNamhyung Kim if (!dso__is_compatible_symtab_type(dso, kmod, symtab_type)) 14611029f9feSNamhyung Kim continue; 14621029f9feSNamhyung Kim 1463ee4e9625SArnaldo Carvalho de Melo if (dso__read_binary_type_filename(dso, symtab_type, 146444f24cb3SJiri Olsa root_dir, name, PATH_MAX)) 14656da80ce8SDave Martin continue; 146686470930SIngo Molnar 14676da80ce8SDave Martin /* Name is now the name of the next image to try */ 14683aafe5aeSCody P Schafer if (symsrc__init(ss, dso, name, symtab_type) < 0) 14696da80ce8SDave Martin continue; 14706da80ce8SDave Martin 14713aafe5aeSCody P Schafer if (!syms_ss && symsrc__has_symtab(ss)) { 14723aafe5aeSCody P Schafer syms_ss = ss; 14733aafe5aeSCody P Schafer next_slot = true; 14740058aef6SAdrian Hunter if (!dso->symsrc_filename) 14750058aef6SAdrian Hunter dso->symsrc_filename = strdup(name); 1476d26cd12bSCody P Schafer } 1477d26cd12bSCody P Schafer 14783aafe5aeSCody P Schafer if (!runtime_ss && symsrc__possibly_runtime(ss)) { 14793aafe5aeSCody P Schafer runtime_ss = ss; 14803aafe5aeSCody P Schafer next_slot = true; 1481a44f605bSCody P Schafer } 148286470930SIngo Molnar 14833aafe5aeSCody P Schafer if (next_slot) { 14843aafe5aeSCody P Schafer ss_pos++; 148533ff581eSJiri Olsa 14863aafe5aeSCody P Schafer if (syms_ss && runtime_ss) 14876da80ce8SDave Martin break; 148898e9f03bSNamhyung Kim } else { 148998e9f03bSNamhyung Kim symsrc__destroy(ss); 1490a25e46c4SArnaldo Carvalho de Melo } 14913aafe5aeSCody P Schafer 14926da80ce8SDave Martin } 14936da80ce8SDave Martin 14943aafe5aeSCody P Schafer if (!runtime_ss && !syms_ss) 14953aafe5aeSCody P Schafer goto out_free; 14963aafe5aeSCody P Schafer 14973aafe5aeSCody P Schafer if (runtime_ss && !syms_ss) { 14983aafe5aeSCody P Schafer syms_ss = runtime_ss; 149960e4b10cSArnaldo Carvalho de Melo } 150060e4b10cSArnaldo Carvalho de Melo 15013aafe5aeSCody P Schafer /* We'll have to hope for the best */ 15023aafe5aeSCody P Schafer if (!runtime_ss && syms_ss) 15033aafe5aeSCody P Schafer runtime_ss = syms_ss; 15043aafe5aeSCody P Schafer 15051029f9feSNamhyung Kim if (syms_ss) 15061029f9feSNamhyung Kim ret = dso__load_sym(dso, map, syms_ss, runtime_ss, filter, kmod); 15071029f9feSNamhyung Kim else 15083aafe5aeSCody P Schafer ret = -1; 15093aafe5aeSCody P Schafer 1510f47b58b7SDavid Ahern if (ret > 0) { 15113aafe5aeSCody P Schafer int nr_plt; 15123aafe5aeSCody P Schafer 15133aafe5aeSCody P Schafer nr_plt = dso__synthesize_plt_symbols(dso, runtime_ss, map, filter); 15143aafe5aeSCody P Schafer if (nr_plt > 0) 15153aafe5aeSCody P Schafer ret += nr_plt; 15163aafe5aeSCody P Schafer } 15173aafe5aeSCody P Schafer 15183aafe5aeSCody P Schafer for (; ss_pos > 0; ss_pos--) 15193aafe5aeSCody P Schafer symsrc__destroy(&ss_[ss_pos - 1]); 15203aafe5aeSCody P Schafer out_free: 152186470930SIngo Molnar free(name); 1522aeafcbafSArnaldo Carvalho de Melo if (ret < 0 && strstr(dso->name, " (deleted)") != NULL) 15234a936edcSNamhyung Kim ret = 0; 15244a936edcSNamhyung Kim out: 15254a936edcSNamhyung Kim dso__set_loaded(dso, map->type); 15264a936edcSNamhyung Kim pthread_mutex_unlock(&dso->lock); 15274a936edcSNamhyung Kim 152886470930SIngo Molnar return ret; 152986470930SIngo Molnar } 153086470930SIngo Molnar 1531aeafcbafSArnaldo Carvalho de Melo struct map *map_groups__find_by_name(struct map_groups *mg, 153279406cd7SArnaldo Carvalho de Melo enum map_type type, const char *name) 1533439d473bSArnaldo Carvalho de Melo { 15341eee78aeSArnaldo Carvalho de Melo struct maps *maps = &mg->maps[type]; 15354bb7123dSArnaldo Carvalho de Melo struct map *map; 1536439d473bSArnaldo Carvalho de Melo 15376a2ffcddSArnaldo Carvalho de Melo pthread_rwlock_rdlock(&maps->lock); 15386a2ffcddSArnaldo Carvalho de Melo 15394bb7123dSArnaldo Carvalho de Melo for (map = maps__first(maps); map; map = map__next(map)) { 1540b7cece76SArnaldo Carvalho de Melo if (map->dso && strcmp(map->dso->short_name, name) == 0) 15416a2ffcddSArnaldo Carvalho de Melo goto out_unlock; 1542439d473bSArnaldo Carvalho de Melo } 1543439d473bSArnaldo Carvalho de Melo 15446a2ffcddSArnaldo Carvalho de Melo map = NULL; 15456a2ffcddSArnaldo Carvalho de Melo 15466a2ffcddSArnaldo Carvalho de Melo out_unlock: 15476a2ffcddSArnaldo Carvalho de Melo pthread_rwlock_unlock(&maps->lock); 15486a2ffcddSArnaldo Carvalho de Melo return map; 1549439d473bSArnaldo Carvalho de Melo } 1550439d473bSArnaldo Carvalho de Melo 1551aeafcbafSArnaldo Carvalho de Melo int dso__load_vmlinux(struct dso *dso, struct map *map, 15525230fb7dSArnaldo Carvalho de Melo const char *vmlinux, bool vmlinux_allocated, 15535230fb7dSArnaldo Carvalho de Melo symbol_filter_t filter) 155486470930SIngo Molnar { 1555b68e2f91SCody P Schafer int err = -1; 1556b68e2f91SCody P Schafer struct symsrc ss; 1557ec5761eaSDavid Ahern char symfs_vmlinux[PATH_MAX]; 1558005f9294SCody P Schafer enum dso_binary_type symtab_type; 155986470930SIngo Molnar 15605698d2c9SNamhyung Kim if (vmlinux[0] == '/') 15615698d2c9SNamhyung Kim snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s", vmlinux); 15625698d2c9SNamhyung Kim else 1563972f393bSArnaldo Carvalho de Melo symbol__join_symfs(symfs_vmlinux, vmlinux); 156486470930SIngo Molnar 156521ea4539SCody P Schafer if (dso->kernel == DSO_TYPE_GUEST_KERNEL) 1566005f9294SCody P Schafer symtab_type = DSO_BINARY_TYPE__GUEST_VMLINUX; 156721ea4539SCody P Schafer else 1568005f9294SCody P Schafer symtab_type = DSO_BINARY_TYPE__VMLINUX; 156921ea4539SCody P Schafer 1570005f9294SCody P Schafer if (symsrc__init(&ss, dso, symfs_vmlinux, symtab_type)) 1571b68e2f91SCody P Schafer return -1; 1572b68e2f91SCody P Schafer 1573261360b6SCody P Schafer err = dso__load_sym(dso, map, &ss, &ss, filter, 0); 1574b68e2f91SCody P Schafer symsrc__destroy(&ss); 157586470930SIngo Molnar 1576515850e4SCody P Schafer if (err > 0) { 157739b12f78SAdrian Hunter if (dso->kernel == DSO_TYPE_GUEST_KERNEL) 15785f70619dSArnaldo Carvalho de Melo dso->binary_type = DSO_BINARY_TYPE__GUEST_VMLINUX; 157939b12f78SAdrian Hunter else 15805f70619dSArnaldo Carvalho de Melo dso->binary_type = DSO_BINARY_TYPE__VMLINUX; 1581bf4414aeSArnaldo Carvalho de Melo dso__set_long_name(dso, vmlinux, vmlinux_allocated); 1582515850e4SCody P Schafer dso__set_loaded(dso, map->type); 1583ec5761eaSDavid Ahern pr_debug("Using %s for symbols\n", symfs_vmlinux); 1584515850e4SCody P Schafer } 15853846df2eSArnaldo Carvalho de Melo 158686470930SIngo Molnar return err; 158786470930SIngo Molnar } 158886470930SIngo Molnar 1589aeafcbafSArnaldo Carvalho de Melo int dso__load_vmlinux_path(struct dso *dso, struct map *map, 15909de89fe7SArnaldo Carvalho de Melo symbol_filter_t filter) 1591a19afe46SArnaldo Carvalho de Melo { 1592a19afe46SArnaldo Carvalho de Melo int i, err = 0; 159300dc8657SNamhyung Kim char *filename = NULL; 1594a19afe46SArnaldo Carvalho de Melo 159500dc8657SNamhyung Kim if (!symbol_conf.ignore_vmlinux_buildid) 1596aeafcbafSArnaldo Carvalho de Melo filename = dso__build_id_filename(dso, NULL, 0); 15975ad90e4eSArnaldo Carvalho de Melo if (filename != NULL) { 15985230fb7dSArnaldo Carvalho de Melo err = dso__load_vmlinux(dso, map, filename, true, filter); 15995230fb7dSArnaldo Carvalho de Melo if (err > 0) 16005ad90e4eSArnaldo Carvalho de Melo goto out; 16015ad90e4eSArnaldo Carvalho de Melo free(filename); 16025ad90e4eSArnaldo Carvalho de Melo } 1603a19afe46SArnaldo Carvalho de Melo 160400dc8657SNamhyung Kim pr_debug("Looking at the vmlinux_path (%d entries long)\n", 160500dc8657SNamhyung Kim vmlinux_path__nr_entries + 1); 160600dc8657SNamhyung Kim 1607a19afe46SArnaldo Carvalho de Melo for (i = 0; i < vmlinux_path__nr_entries; ++i) { 16085230fb7dSArnaldo Carvalho de Melo err = dso__load_vmlinux(dso, map, vmlinux_path[i], false, filter); 16095230fb7dSArnaldo Carvalho de Melo if (err > 0) 1610a19afe46SArnaldo Carvalho de Melo break; 1611a19afe46SArnaldo Carvalho de Melo } 16125ad90e4eSArnaldo Carvalho de Melo out: 1613a19afe46SArnaldo Carvalho de Melo return err; 1614a19afe46SArnaldo Carvalho de Melo } 1615a19afe46SArnaldo Carvalho de Melo 16160544d422SAdrian Hunter static int find_matching_kcore(struct map *map, char *dir, size_t dir_sz) 16170544d422SAdrian Hunter { 16180544d422SAdrian Hunter char kallsyms_filename[PATH_MAX]; 16190544d422SAdrian Hunter struct dirent *dent; 16200544d422SAdrian Hunter int ret = -1; 16210544d422SAdrian Hunter DIR *d; 16220544d422SAdrian Hunter 16230544d422SAdrian Hunter d = opendir(dir); 16240544d422SAdrian Hunter if (!d) 16250544d422SAdrian Hunter return -1; 16260544d422SAdrian Hunter 16270544d422SAdrian Hunter while (1) { 16280544d422SAdrian Hunter dent = readdir(d); 16290544d422SAdrian Hunter if (!dent) 16300544d422SAdrian Hunter break; 16310544d422SAdrian Hunter if (dent->d_type != DT_DIR) 16320544d422SAdrian Hunter continue; 16330544d422SAdrian Hunter scnprintf(kallsyms_filename, sizeof(kallsyms_filename), 16340544d422SAdrian Hunter "%s/%s/kallsyms", dir, dent->d_name); 1635a00d28cbSAdrian Hunter if (!validate_kcore_addresses(kallsyms_filename, map)) { 16360544d422SAdrian Hunter strlcpy(dir, kallsyms_filename, dir_sz); 16370544d422SAdrian Hunter ret = 0; 16380544d422SAdrian Hunter break; 16390544d422SAdrian Hunter } 16400544d422SAdrian Hunter } 16410544d422SAdrian Hunter 16420544d422SAdrian Hunter closedir(d); 16430544d422SAdrian Hunter 16440544d422SAdrian Hunter return ret; 16450544d422SAdrian Hunter } 16460544d422SAdrian Hunter 16470544d422SAdrian Hunter static char *dso__find_kallsyms(struct dso *dso, struct map *map) 16480544d422SAdrian Hunter { 16490544d422SAdrian Hunter u8 host_build_id[BUILD_ID_SIZE]; 16500544d422SAdrian Hunter char sbuild_id[BUILD_ID_SIZE * 2 + 1]; 16510544d422SAdrian Hunter bool is_host = false; 16520544d422SAdrian Hunter char path[PATH_MAX]; 16530544d422SAdrian Hunter 16540544d422SAdrian Hunter if (!dso->has_build_id) { 16550544d422SAdrian Hunter /* 16560544d422SAdrian Hunter * Last resort, if we don't have a build-id and couldn't find 16570544d422SAdrian Hunter * any vmlinux file, try the running kernel kallsyms table. 16580544d422SAdrian Hunter */ 16590544d422SAdrian Hunter goto proc_kallsyms; 16600544d422SAdrian Hunter } 16610544d422SAdrian Hunter 16620544d422SAdrian Hunter if (sysfs__read_build_id("/sys/kernel/notes", host_build_id, 16630544d422SAdrian Hunter sizeof(host_build_id)) == 0) 16640544d422SAdrian Hunter is_host = dso__build_id_equal(dso, host_build_id); 16650544d422SAdrian Hunter 16660544d422SAdrian Hunter build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id); 16670544d422SAdrian Hunter 1668449867e3SAdrian Hunter scnprintf(path, sizeof(path), "%s/[kernel.kcore]/%s", buildid_dir, 1669449867e3SAdrian Hunter sbuild_id); 1670449867e3SAdrian Hunter 16710544d422SAdrian Hunter /* Use /proc/kallsyms if possible */ 16720544d422SAdrian Hunter if (is_host) { 16730544d422SAdrian Hunter DIR *d; 16740544d422SAdrian Hunter int fd; 16750544d422SAdrian Hunter 16760544d422SAdrian Hunter /* If no cached kcore go with /proc/kallsyms */ 16770544d422SAdrian Hunter d = opendir(path); 16780544d422SAdrian Hunter if (!d) 16790544d422SAdrian Hunter goto proc_kallsyms; 16800544d422SAdrian Hunter closedir(d); 16810544d422SAdrian Hunter 16820544d422SAdrian Hunter /* 16830544d422SAdrian Hunter * Do not check the build-id cache, until we know we cannot use 16840544d422SAdrian Hunter * /proc/kcore. 16850544d422SAdrian Hunter */ 16860544d422SAdrian Hunter fd = open("/proc/kcore", O_RDONLY); 16870544d422SAdrian Hunter if (fd != -1) { 16880544d422SAdrian Hunter close(fd); 16890544d422SAdrian Hunter /* If module maps match go with /proc/kallsyms */ 1690a00d28cbSAdrian Hunter if (!validate_kcore_addresses("/proc/kallsyms", map)) 16910544d422SAdrian Hunter goto proc_kallsyms; 16920544d422SAdrian Hunter } 16930544d422SAdrian Hunter 16940544d422SAdrian Hunter /* Find kallsyms in build-id cache with kcore */ 16950544d422SAdrian Hunter if (!find_matching_kcore(map, path, sizeof(path))) 16960544d422SAdrian Hunter return strdup(path); 16970544d422SAdrian Hunter 16980544d422SAdrian Hunter goto proc_kallsyms; 16990544d422SAdrian Hunter } 17000544d422SAdrian Hunter 1701449867e3SAdrian Hunter /* Find kallsyms in build-id cache with kcore */ 1702449867e3SAdrian Hunter if (!find_matching_kcore(map, path, sizeof(path))) 1703449867e3SAdrian Hunter return strdup(path); 1704449867e3SAdrian Hunter 17050544d422SAdrian Hunter scnprintf(path, sizeof(path), "%s/[kernel.kallsyms]/%s", 17060544d422SAdrian Hunter buildid_dir, sbuild_id); 17070544d422SAdrian Hunter 17080544d422SAdrian Hunter if (access(path, F_OK)) { 17090544d422SAdrian Hunter pr_err("No kallsyms or vmlinux with build-id %s was found\n", 17100544d422SAdrian Hunter sbuild_id); 17110544d422SAdrian Hunter return NULL; 17120544d422SAdrian Hunter } 17130544d422SAdrian Hunter 17140544d422SAdrian Hunter return strdup(path); 17150544d422SAdrian Hunter 17160544d422SAdrian Hunter proc_kallsyms: 17170544d422SAdrian Hunter return strdup("/proc/kallsyms"); 17180544d422SAdrian Hunter } 17190544d422SAdrian Hunter 1720aeafcbafSArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *dso, struct map *map, 17219de89fe7SArnaldo Carvalho de Melo symbol_filter_t filter) 172286470930SIngo Molnar { 1723cc612d81SArnaldo Carvalho de Melo int err; 17249e201442SArnaldo Carvalho de Melo const char *kallsyms_filename = NULL; 17259e201442SArnaldo Carvalho de Melo char *kallsyms_allocated_filename = NULL; 1726dc8d6ab2SArnaldo Carvalho de Melo /* 1727b226a5a7SDavid Ahern * Step 1: if the user specified a kallsyms or vmlinux filename, use 1728b226a5a7SDavid Ahern * it and only it, reporting errors to the user if it cannot be used. 1729dc8d6ab2SArnaldo Carvalho de Melo * 1730dc8d6ab2SArnaldo Carvalho de Melo * For instance, try to analyse an ARM perf.data file _without_ a 1731dc8d6ab2SArnaldo Carvalho de Melo * build-id, or if the user specifies the wrong path to the right 1732dc8d6ab2SArnaldo Carvalho de Melo * vmlinux file, obviously we can't fallback to another vmlinux (a 1733dc8d6ab2SArnaldo Carvalho de Melo * x86_86 one, on the machine where analysis is being performed, say), 1734dc8d6ab2SArnaldo Carvalho de Melo * or worse, /proc/kallsyms. 1735dc8d6ab2SArnaldo Carvalho de Melo * 1736dc8d6ab2SArnaldo Carvalho de Melo * If the specified file _has_ a build-id and there is a build-id 1737dc8d6ab2SArnaldo Carvalho de Melo * section in the perf.data file, we will still do the expected 1738dc8d6ab2SArnaldo Carvalho de Melo * validation in dso__load_vmlinux and will bail out if they don't 1739dc8d6ab2SArnaldo Carvalho de Melo * match. 1740dc8d6ab2SArnaldo Carvalho de Melo */ 1741b226a5a7SDavid Ahern if (symbol_conf.kallsyms_name != NULL) { 1742b226a5a7SDavid Ahern kallsyms_filename = symbol_conf.kallsyms_name; 1743b226a5a7SDavid Ahern goto do_kallsyms; 1744b226a5a7SDavid Ahern } 1745b226a5a7SDavid Ahern 1746fc2be696SWilly Tarreau if (!symbol_conf.ignore_vmlinux && symbol_conf.vmlinux_name != NULL) { 17475230fb7dSArnaldo Carvalho de Melo return dso__load_vmlinux(dso, map, symbol_conf.vmlinux_name, 17485230fb7dSArnaldo Carvalho de Melo false, filter); 1749dc8d6ab2SArnaldo Carvalho de Melo } 1750439d473bSArnaldo Carvalho de Melo 1751fc2be696SWilly Tarreau if (!symbol_conf.ignore_vmlinux && vmlinux_path != NULL) { 1752aeafcbafSArnaldo Carvalho de Melo err = dso__load_vmlinux_path(dso, map, filter); 1753a19afe46SArnaldo Carvalho de Melo if (err > 0) 175439b12f78SAdrian Hunter return err; 1755cc612d81SArnaldo Carvalho de Melo } 1756cc612d81SArnaldo Carvalho de Melo 1757ec5761eaSDavid Ahern /* do not try local files if a symfs was given */ 1758ec5761eaSDavid Ahern if (symbol_conf.symfs[0] != 0) 1759ec5761eaSDavid Ahern return -1; 1760ec5761eaSDavid Ahern 17610544d422SAdrian Hunter kallsyms_allocated_filename = dso__find_kallsyms(dso, map); 17620544d422SAdrian Hunter if (!kallsyms_allocated_filename) 17638d0591f6SArnaldo Carvalho de Melo return -1; 17648d0591f6SArnaldo Carvalho de Melo 176519fc2dedSArnaldo Carvalho de Melo kallsyms_filename = kallsyms_allocated_filename; 176619fc2dedSArnaldo Carvalho de Melo 1767dc8d6ab2SArnaldo Carvalho de Melo do_kallsyms: 1768aeafcbafSArnaldo Carvalho de Melo err = dso__load_kallsyms(dso, kallsyms_filename, map, filter); 17693846df2eSArnaldo Carvalho de Melo if (err > 0) 17703846df2eSArnaldo Carvalho de Melo pr_debug("Using %s for symbols\n", kallsyms_filename); 1771dc8d6ab2SArnaldo Carvalho de Melo free(kallsyms_allocated_filename); 1772dc8d6ab2SArnaldo Carvalho de Melo 17738e0cf965SAdrian Hunter if (err > 0 && !dso__is_kcore(dso)) { 1774bdac0bcfSAdrian Hunter dso->binary_type = DSO_BINARY_TYPE__KALLSYMS; 1775bf4414aeSArnaldo Carvalho de Melo dso__set_long_name(dso, "[kernel.kallsyms]", false); 17766a4694a4SArnaldo Carvalho de Melo map__fixup_start(map); 17776a4694a4SArnaldo Carvalho de Melo map__fixup_end(map); 1778439d473bSArnaldo Carvalho de Melo } 177994cb9e38SArnaldo Carvalho de Melo 178086470930SIngo Molnar return err; 178186470930SIngo Molnar } 178286470930SIngo Molnar 1783aeafcbafSArnaldo Carvalho de Melo static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map, 1784a1645ce1SZhang, Yanmin symbol_filter_t filter) 1785a1645ce1SZhang, Yanmin { 1786a1645ce1SZhang, Yanmin int err; 1787a1645ce1SZhang, Yanmin const char *kallsyms_filename = NULL; 178823346f21SArnaldo Carvalho de Melo struct machine *machine; 1789a1645ce1SZhang, Yanmin char path[PATH_MAX]; 1790a1645ce1SZhang, Yanmin 1791a1645ce1SZhang, Yanmin if (!map->groups) { 1792a1645ce1SZhang, Yanmin pr_debug("Guest kernel map hasn't the point to groups\n"); 1793a1645ce1SZhang, Yanmin return -1; 1794a1645ce1SZhang, Yanmin } 179523346f21SArnaldo Carvalho de Melo machine = map->groups->machine; 1796a1645ce1SZhang, Yanmin 179723346f21SArnaldo Carvalho de Melo if (machine__is_default_guest(machine)) { 1798a1645ce1SZhang, Yanmin /* 1799a1645ce1SZhang, Yanmin * if the user specified a vmlinux filename, use it and only 1800a1645ce1SZhang, Yanmin * it, reporting errors to the user if it cannot be used. 1801a1645ce1SZhang, Yanmin * Or use file guest_kallsyms inputted by user on commandline 1802a1645ce1SZhang, Yanmin */ 1803a1645ce1SZhang, Yanmin if (symbol_conf.default_guest_vmlinux_name != NULL) { 1804aeafcbafSArnaldo Carvalho de Melo err = dso__load_vmlinux(dso, map, 18055230fb7dSArnaldo Carvalho de Melo symbol_conf.default_guest_vmlinux_name, 18065230fb7dSArnaldo Carvalho de Melo false, filter); 180739b12f78SAdrian Hunter return err; 1808a1645ce1SZhang, Yanmin } 1809a1645ce1SZhang, Yanmin 1810a1645ce1SZhang, Yanmin kallsyms_filename = symbol_conf.default_guest_kallsyms; 1811a1645ce1SZhang, Yanmin if (!kallsyms_filename) 1812a1645ce1SZhang, Yanmin return -1; 1813a1645ce1SZhang, Yanmin } else { 181423346f21SArnaldo Carvalho de Melo sprintf(path, "%s/proc/kallsyms", machine->root_dir); 1815a1645ce1SZhang, Yanmin kallsyms_filename = path; 1816a1645ce1SZhang, Yanmin } 1817a1645ce1SZhang, Yanmin 1818aeafcbafSArnaldo Carvalho de Melo err = dso__load_kallsyms(dso, kallsyms_filename, map, filter); 18198e0cf965SAdrian Hunter if (err > 0) 182039b12f78SAdrian Hunter pr_debug("Using %s for symbols\n", kallsyms_filename); 18218e0cf965SAdrian Hunter if (err > 0 && !dso__is_kcore(dso)) { 1822bdac0bcfSAdrian Hunter dso->binary_type = DSO_BINARY_TYPE__GUEST_KALLSYMS; 182348ea8f54SArnaldo Carvalho de Melo machine__mmap_name(machine, path, sizeof(path)); 18247e155d4dSArnaldo Carvalho de Melo dso__set_long_name(dso, strdup(path), true); 1825a1645ce1SZhang, Yanmin map__fixup_start(map); 1826a1645ce1SZhang, Yanmin map__fixup_end(map); 1827a1645ce1SZhang, Yanmin } 1828a1645ce1SZhang, Yanmin 1829a1645ce1SZhang, Yanmin return err; 1830a1645ce1SZhang, Yanmin } 1831cd84c2acSFrederic Weisbecker 1832cc612d81SArnaldo Carvalho de Melo static void vmlinux_path__exit(void) 18332446042cSArnaldo Carvalho de Melo { 183404662523SArnaldo Carvalho de Melo while (--vmlinux_path__nr_entries >= 0) 183504662523SArnaldo Carvalho de Melo zfree(&vmlinux_path[vmlinux_path__nr_entries]); 1836c4f03547SWang Nan vmlinux_path__nr_entries = 0; 1837cc612d81SArnaldo Carvalho de Melo 183804662523SArnaldo Carvalho de Melo zfree(&vmlinux_path); 1839cc612d81SArnaldo Carvalho de Melo } 1840cc612d81SArnaldo Carvalho de Melo 18410a7e6d1bSNamhyung Kim static int vmlinux_path__init(struct perf_session_env *env) 1842cc612d81SArnaldo Carvalho de Melo { 1843cc612d81SArnaldo Carvalho de Melo struct utsname uts; 1844cc612d81SArnaldo Carvalho de Melo char bf[PATH_MAX]; 18450a7e6d1bSNamhyung Kim char *kernel_version; 1846cc612d81SArnaldo Carvalho de Melo 1847c657f423SAnton Blanchard vmlinux_path = malloc(sizeof(char *) * 6); 1848cc612d81SArnaldo Carvalho de Melo if (vmlinux_path == NULL) 1849cc612d81SArnaldo Carvalho de Melo return -1; 1850cc612d81SArnaldo Carvalho de Melo 1851cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup("vmlinux"); 1852cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 1853cc612d81SArnaldo Carvalho de Melo goto out_fail; 1854cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 1855cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup("/boot/vmlinux"); 1856cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 1857cc612d81SArnaldo Carvalho de Melo goto out_fail; 1858cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 1859ec5761eaSDavid Ahern 18600a7e6d1bSNamhyung Kim /* only try kernel version if no symfs was given */ 1861ec5761eaSDavid Ahern if (symbol_conf.symfs[0] != 0) 1862ec5761eaSDavid Ahern return 0; 1863ec5761eaSDavid Ahern 18640a7e6d1bSNamhyung Kim if (env) { 18650a7e6d1bSNamhyung Kim kernel_version = env->os_release; 18660a7e6d1bSNamhyung Kim } else { 1867ec5761eaSDavid Ahern if (uname(&uts) < 0) 1868e96c674fSNamhyung Kim goto out_fail; 1869ec5761eaSDavid Ahern 18700a7e6d1bSNamhyung Kim kernel_version = uts.release; 18710a7e6d1bSNamhyung Kim } 18720a7e6d1bSNamhyung Kim 18730a7e6d1bSNamhyung Kim snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", kernel_version); 1874cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); 1875cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 1876cc612d81SArnaldo Carvalho de Melo goto out_fail; 1877cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 1878c657f423SAnton Blanchard snprintf(bf, sizeof(bf), "/usr/lib/debug/boot/vmlinux-%s", 1879c657f423SAnton Blanchard kernel_version); 1880c657f423SAnton Blanchard vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); 1881c657f423SAnton Blanchard if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 1882c657f423SAnton Blanchard goto out_fail; 1883c657f423SAnton Blanchard ++vmlinux_path__nr_entries; 18840a7e6d1bSNamhyung Kim snprintf(bf, sizeof(bf), "/lib/modules/%s/build/vmlinux", kernel_version); 1885cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); 1886cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 1887cc612d81SArnaldo Carvalho de Melo goto out_fail; 1888cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 1889cc612d81SArnaldo Carvalho de Melo snprintf(bf, sizeof(bf), "/usr/lib/debug/lib/modules/%s/vmlinux", 18900a7e6d1bSNamhyung Kim kernel_version); 1891cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); 1892cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 1893cc612d81SArnaldo Carvalho de Melo goto out_fail; 1894cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 1895cc612d81SArnaldo Carvalho de Melo 1896cc612d81SArnaldo Carvalho de Melo return 0; 1897cc612d81SArnaldo Carvalho de Melo 1898cc612d81SArnaldo Carvalho de Melo out_fail: 1899cc612d81SArnaldo Carvalho de Melo vmlinux_path__exit(); 1900cc612d81SArnaldo Carvalho de Melo return -1; 1901cc612d81SArnaldo Carvalho de Melo } 1902cc612d81SArnaldo Carvalho de Melo 19033bfe5f81SDavid Ahern int setup_list(struct strlist **list, const char *list_str, 1904655000e7SArnaldo Carvalho de Melo const char *list_name) 1905655000e7SArnaldo Carvalho de Melo { 1906655000e7SArnaldo Carvalho de Melo if (list_str == NULL) 1907655000e7SArnaldo Carvalho de Melo return 0; 1908655000e7SArnaldo Carvalho de Melo 1909655000e7SArnaldo Carvalho de Melo *list = strlist__new(true, list_str); 1910655000e7SArnaldo Carvalho de Melo if (!*list) { 1911655000e7SArnaldo Carvalho de Melo pr_err("problems parsing %s list\n", list_name); 1912655000e7SArnaldo Carvalho de Melo return -1; 1913655000e7SArnaldo Carvalho de Melo } 1914*0bc2f2f7SArnaldo Carvalho de Melo 1915*0bc2f2f7SArnaldo Carvalho de Melo symbol_conf.has_filter = true; 1916655000e7SArnaldo Carvalho de Melo return 0; 1917655000e7SArnaldo Carvalho de Melo } 1918655000e7SArnaldo Carvalho de Melo 1919e03eaa40SDavid Ahern int setup_intlist(struct intlist **list, const char *list_str, 1920e03eaa40SDavid Ahern const char *list_name) 1921e03eaa40SDavid Ahern { 1922e03eaa40SDavid Ahern if (list_str == NULL) 1923e03eaa40SDavid Ahern return 0; 1924e03eaa40SDavid Ahern 1925e03eaa40SDavid Ahern *list = intlist__new(list_str); 1926e03eaa40SDavid Ahern if (!*list) { 1927e03eaa40SDavid Ahern pr_err("problems parsing %s list\n", list_name); 1928e03eaa40SDavid Ahern return -1; 1929e03eaa40SDavid Ahern } 1930e03eaa40SDavid Ahern return 0; 1931e03eaa40SDavid Ahern } 1932e03eaa40SDavid Ahern 1933ec80fde7SArnaldo Carvalho de Melo static bool symbol__read_kptr_restrict(void) 1934ec80fde7SArnaldo Carvalho de Melo { 1935ec80fde7SArnaldo Carvalho de Melo bool value = false; 1936ec80fde7SArnaldo Carvalho de Melo 1937ec80fde7SArnaldo Carvalho de Melo if (geteuid() != 0) { 1938ec80fde7SArnaldo Carvalho de Melo FILE *fp = fopen("/proc/sys/kernel/kptr_restrict", "r"); 1939ec80fde7SArnaldo Carvalho de Melo if (fp != NULL) { 1940ec80fde7SArnaldo Carvalho de Melo char line[8]; 1941ec80fde7SArnaldo Carvalho de Melo 1942ec80fde7SArnaldo Carvalho de Melo if (fgets(line, sizeof(line), fp) != NULL) 1943ec80fde7SArnaldo Carvalho de Melo value = atoi(line) != 0; 1944ec80fde7SArnaldo Carvalho de Melo 1945ec80fde7SArnaldo Carvalho de Melo fclose(fp); 1946ec80fde7SArnaldo Carvalho de Melo } 1947ec80fde7SArnaldo Carvalho de Melo } 1948ec80fde7SArnaldo Carvalho de Melo 1949ec80fde7SArnaldo Carvalho de Melo return value; 1950ec80fde7SArnaldo Carvalho de Melo } 1951ec80fde7SArnaldo Carvalho de Melo 19520a7e6d1bSNamhyung Kim int symbol__init(struct perf_session_env *env) 1953cc612d81SArnaldo Carvalho de Melo { 1954ec5761eaSDavid Ahern const char *symfs; 1955ec5761eaSDavid Ahern 195685e00b55SJovi Zhang if (symbol_conf.initialized) 195785e00b55SJovi Zhang return 0; 195885e00b55SJovi Zhang 19599ac3e487SIrina Tirdea symbol_conf.priv_size = PERF_ALIGN(symbol_conf.priv_size, sizeof(u64)); 19604d439517SDavid S. Miller 1961166ccc9cSNamhyung Kim symbol__elf_init(); 1962166ccc9cSNamhyung Kim 196375be6cf4SArnaldo Carvalho de Melo if (symbol_conf.sort_by_name) 196475be6cf4SArnaldo Carvalho de Melo symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) - 196579406cd7SArnaldo Carvalho de Melo sizeof(struct symbol)); 1966b32d133aSArnaldo Carvalho de Melo 19670a7e6d1bSNamhyung Kim if (symbol_conf.try_vmlinux_path && vmlinux_path__init(env) < 0) 1968cc612d81SArnaldo Carvalho de Melo return -1; 1969cc612d81SArnaldo Carvalho de Melo 1970c410a338SArnaldo Carvalho de Melo if (symbol_conf.field_sep && *symbol_conf.field_sep == '.') { 1971c410a338SArnaldo Carvalho de Melo pr_err("'.' is the only non valid --field-separator argument\n"); 1972c410a338SArnaldo Carvalho de Melo return -1; 1973c410a338SArnaldo Carvalho de Melo } 1974c410a338SArnaldo Carvalho de Melo 1975655000e7SArnaldo Carvalho de Melo if (setup_list(&symbol_conf.dso_list, 1976655000e7SArnaldo Carvalho de Melo symbol_conf.dso_list_str, "dso") < 0) 1977655000e7SArnaldo Carvalho de Melo return -1; 1978655000e7SArnaldo Carvalho de Melo 1979655000e7SArnaldo Carvalho de Melo if (setup_list(&symbol_conf.comm_list, 1980655000e7SArnaldo Carvalho de Melo symbol_conf.comm_list_str, "comm") < 0) 1981655000e7SArnaldo Carvalho de Melo goto out_free_dso_list; 1982655000e7SArnaldo Carvalho de Melo 1983e03eaa40SDavid Ahern if (setup_intlist(&symbol_conf.pid_list, 1984e03eaa40SDavid Ahern symbol_conf.pid_list_str, "pid") < 0) 1985e03eaa40SDavid Ahern goto out_free_comm_list; 1986e03eaa40SDavid Ahern 1987e03eaa40SDavid Ahern if (setup_intlist(&symbol_conf.tid_list, 1988e03eaa40SDavid Ahern symbol_conf.tid_list_str, "tid") < 0) 1989e03eaa40SDavid Ahern goto out_free_pid_list; 1990e03eaa40SDavid Ahern 1991655000e7SArnaldo Carvalho de Melo if (setup_list(&symbol_conf.sym_list, 1992655000e7SArnaldo Carvalho de Melo symbol_conf.sym_list_str, "symbol") < 0) 1993e03eaa40SDavid Ahern goto out_free_tid_list; 1994655000e7SArnaldo Carvalho de Melo 1995ec5761eaSDavid Ahern /* 1996ec5761eaSDavid Ahern * A path to symbols of "/" is identical to "" 1997ec5761eaSDavid Ahern * reset here for simplicity. 1998ec5761eaSDavid Ahern */ 1999ec5761eaSDavid Ahern symfs = realpath(symbol_conf.symfs, NULL); 2000ec5761eaSDavid Ahern if (symfs == NULL) 2001ec5761eaSDavid Ahern symfs = symbol_conf.symfs; 2002ec5761eaSDavid Ahern if (strcmp(symfs, "/") == 0) 2003ec5761eaSDavid Ahern symbol_conf.symfs = ""; 2004ec5761eaSDavid Ahern if (symfs != symbol_conf.symfs) 2005ec5761eaSDavid Ahern free((void *)symfs); 2006ec5761eaSDavid Ahern 2007ec80fde7SArnaldo Carvalho de Melo symbol_conf.kptr_restrict = symbol__read_kptr_restrict(); 2008ec80fde7SArnaldo Carvalho de Melo 200985e00b55SJovi Zhang symbol_conf.initialized = true; 20104aa65636SArnaldo Carvalho de Melo return 0; 2011655000e7SArnaldo Carvalho de Melo 2012e03eaa40SDavid Ahern out_free_tid_list: 2013e03eaa40SDavid Ahern intlist__delete(symbol_conf.tid_list); 2014e03eaa40SDavid Ahern out_free_pid_list: 2015e03eaa40SDavid Ahern intlist__delete(symbol_conf.pid_list); 2016655000e7SArnaldo Carvalho de Melo out_free_comm_list: 2017655000e7SArnaldo Carvalho de Melo strlist__delete(symbol_conf.comm_list); 2018d74c896bSNamhyung Kim out_free_dso_list: 2019d74c896bSNamhyung Kim strlist__delete(symbol_conf.dso_list); 2020655000e7SArnaldo Carvalho de Melo return -1; 2021cc612d81SArnaldo Carvalho de Melo } 2022cc612d81SArnaldo Carvalho de Melo 2023d65a458bSArnaldo Carvalho de Melo void symbol__exit(void) 2024d65a458bSArnaldo Carvalho de Melo { 202585e00b55SJovi Zhang if (!symbol_conf.initialized) 202685e00b55SJovi Zhang return; 2027d65a458bSArnaldo Carvalho de Melo strlist__delete(symbol_conf.sym_list); 2028d65a458bSArnaldo Carvalho de Melo strlist__delete(symbol_conf.dso_list); 2029d65a458bSArnaldo Carvalho de Melo strlist__delete(symbol_conf.comm_list); 2030e03eaa40SDavid Ahern intlist__delete(symbol_conf.tid_list); 2031e03eaa40SDavid Ahern intlist__delete(symbol_conf.pid_list); 2032d65a458bSArnaldo Carvalho de Melo vmlinux_path__exit(); 2033d65a458bSArnaldo Carvalho de Melo symbol_conf.sym_list = symbol_conf.dso_list = symbol_conf.comm_list = NULL; 203485e00b55SJovi Zhang symbol_conf.initialized = false; 2035d65a458bSArnaldo Carvalho de Melo } 2036