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 { 205*1eee78aeSArnaldo Carvalho de Melo struct maps *maps = &mg->maps[type]; 2064bb7123dSArnaldo Carvalho de Melo struct map *next, *curr; 207af427bf5SArnaldo Carvalho de Melo 2084bb7123dSArnaldo Carvalho de Melo curr = maps__first(maps); 2094bb7123dSArnaldo Carvalho de Melo if (curr == NULL) 210af427bf5SArnaldo Carvalho de Melo return; 211af427bf5SArnaldo Carvalho de Melo 2124bb7123dSArnaldo Carvalho de Melo for (next = map__next(curr); next; next = map__next(curr)) { 2134bb7123dSArnaldo Carvalho de Melo curr->end = next->start; 2144bb7123dSArnaldo Carvalho de Melo curr = next; 2152e538c4aSArnaldo Carvalho de Melo } 21690c83218SArnaldo Carvalho de Melo 21790c83218SArnaldo Carvalho de Melo /* 21890c83218SArnaldo Carvalho de Melo * We still haven't the actual symbols, so guess the 21990c83218SArnaldo Carvalho de Melo * last map final address. 22090c83218SArnaldo Carvalho de Melo */ 2219d1faba5SIan Munsie curr->end = ~0ULL; 222af427bf5SArnaldo Carvalho de Melo } 223af427bf5SArnaldo Carvalho de Melo 224e5a1845fSNamhyung Kim struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name) 22586470930SIngo Molnar { 22686470930SIngo Molnar size_t namelen = strlen(name) + 1; 227aeafcbafSArnaldo Carvalho de Melo struct symbol *sym = calloc(1, (symbol_conf.priv_size + 228aeafcbafSArnaldo Carvalho de Melo sizeof(*sym) + namelen)); 229aeafcbafSArnaldo Carvalho de Melo if (sym == NULL) 23086470930SIngo Molnar return NULL; 23186470930SIngo Molnar 23275be6cf4SArnaldo Carvalho de Melo if (symbol_conf.priv_size) 233aeafcbafSArnaldo Carvalho de Melo sym = ((void *)sym) + symbol_conf.priv_size; 23436479484SArnaldo Carvalho de Melo 235aeafcbafSArnaldo Carvalho de Melo sym->start = start; 2362c241bd3SArnaldo Carvalho de Melo sym->end = len ? start + len : start; 237aeafcbafSArnaldo Carvalho de Melo sym->binding = binding; 238aeafcbafSArnaldo Carvalho de Melo sym->namelen = namelen - 1; 239e4204992SArnaldo Carvalho de Melo 240aeafcbafSArnaldo Carvalho de Melo pr_debug4("%s: %s %#" PRIx64 "-%#" PRIx64 "\n", 241aeafcbafSArnaldo Carvalho de Melo __func__, name, start, sym->end); 242aeafcbafSArnaldo Carvalho de Melo memcpy(sym->name, name, namelen); 243e4204992SArnaldo Carvalho de Melo 244aeafcbafSArnaldo Carvalho de Melo return sym; 24586470930SIngo Molnar } 24686470930SIngo Molnar 247aeafcbafSArnaldo Carvalho de Melo void symbol__delete(struct symbol *sym) 24886470930SIngo Molnar { 249aeafcbafSArnaldo Carvalho de Melo free(((void *)sym) - symbol_conf.priv_size); 25086470930SIngo Molnar } 25186470930SIngo Molnar 252cdd059d7SJiri Olsa size_t symbol__fprintf(struct symbol *sym, FILE *fp) 25386470930SIngo Molnar { 2549486aa38SArnaldo Carvalho de Melo return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %c %s\n", 255aeafcbafSArnaldo Carvalho de Melo sym->start, sym->end, 256aeafcbafSArnaldo Carvalho de Melo sym->binding == STB_GLOBAL ? 'g' : 257aeafcbafSArnaldo Carvalho de Melo sym->binding == STB_LOCAL ? 'l' : 'w', 258aeafcbafSArnaldo Carvalho de Melo sym->name); 25986470930SIngo Molnar } 26086470930SIngo Molnar 261a978f2abSAkihiro Nagai size_t symbol__fprintf_symname_offs(const struct symbol *sym, 262a978f2abSAkihiro Nagai const struct addr_location *al, FILE *fp) 263a978f2abSAkihiro Nagai { 264a978f2abSAkihiro Nagai unsigned long offset; 265a978f2abSAkihiro Nagai size_t length; 266a978f2abSAkihiro Nagai 267a978f2abSAkihiro Nagai if (sym && sym->name) { 268a978f2abSAkihiro Nagai length = fprintf(fp, "%s", sym->name); 269a978f2abSAkihiro Nagai if (al) { 2700b8c25d9SDavid Ahern if (al->addr < sym->end) 271a978f2abSAkihiro Nagai offset = al->addr - sym->start; 2720b8c25d9SDavid Ahern else 2730b8c25d9SDavid Ahern offset = al->addr - al->map->start - sym->start; 274a978f2abSAkihiro Nagai length += fprintf(fp, "+0x%lx", offset); 275a978f2abSAkihiro Nagai } 276a978f2abSAkihiro Nagai return length; 277a978f2abSAkihiro Nagai } else 278a978f2abSAkihiro Nagai return fprintf(fp, "[unknown]"); 279a978f2abSAkihiro Nagai } 280a978f2abSAkihiro Nagai 281547a92e0SAkihiro Nagai size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp) 282547a92e0SAkihiro Nagai { 283a978f2abSAkihiro Nagai return symbol__fprintf_symname_offs(sym, NULL, fp); 284547a92e0SAkihiro Nagai } 285547a92e0SAkihiro Nagai 286cdd059d7SJiri Olsa void symbols__delete(struct rb_root *symbols) 28786470930SIngo Molnar { 28886470930SIngo Molnar struct symbol *pos; 289aeafcbafSArnaldo Carvalho de Melo struct rb_node *next = rb_first(symbols); 29086470930SIngo Molnar 29186470930SIngo Molnar while (next) { 29286470930SIngo Molnar pos = rb_entry(next, struct symbol, rb_node); 29386470930SIngo Molnar next = rb_next(&pos->rb_node); 294aeafcbafSArnaldo Carvalho de Melo rb_erase(&pos->rb_node, symbols); 29500a192b3SArnaldo Carvalho de Melo symbol__delete(pos); 29686470930SIngo Molnar } 29786470930SIngo Molnar } 29886470930SIngo Molnar 299e5a1845fSNamhyung Kim void symbols__insert(struct rb_root *symbols, struct symbol *sym) 30086470930SIngo Molnar { 301aeafcbafSArnaldo Carvalho de Melo struct rb_node **p = &symbols->rb_node; 30286470930SIngo Molnar struct rb_node *parent = NULL; 3039cffa8d5SPaul Mackerras const u64 ip = sym->start; 30486470930SIngo Molnar struct symbol *s; 30586470930SIngo Molnar 30686470930SIngo Molnar while (*p != NULL) { 30786470930SIngo Molnar parent = *p; 30886470930SIngo Molnar s = rb_entry(parent, struct symbol, rb_node); 30986470930SIngo Molnar if (ip < s->start) 31086470930SIngo Molnar p = &(*p)->rb_left; 31186470930SIngo Molnar else 31286470930SIngo Molnar p = &(*p)->rb_right; 31386470930SIngo Molnar } 31486470930SIngo Molnar rb_link_node(&sym->rb_node, parent, p); 315aeafcbafSArnaldo Carvalho de Melo rb_insert_color(&sym->rb_node, symbols); 31686470930SIngo Molnar } 31786470930SIngo Molnar 318aeafcbafSArnaldo Carvalho de Melo static struct symbol *symbols__find(struct rb_root *symbols, u64 ip) 31986470930SIngo Molnar { 32086470930SIngo Molnar struct rb_node *n; 32186470930SIngo Molnar 322aeafcbafSArnaldo Carvalho de Melo if (symbols == NULL) 32386470930SIngo Molnar return NULL; 32486470930SIngo Molnar 325aeafcbafSArnaldo Carvalho de Melo n = symbols->rb_node; 32686470930SIngo Molnar 32786470930SIngo Molnar while (n) { 32886470930SIngo Molnar struct symbol *s = rb_entry(n, struct symbol, rb_node); 32986470930SIngo Molnar 33086470930SIngo Molnar if (ip < s->start) 33186470930SIngo Molnar n = n->rb_left; 3322c241bd3SArnaldo Carvalho de Melo else if (ip >= s->end) 33386470930SIngo Molnar n = n->rb_right; 33486470930SIngo Molnar else 33586470930SIngo Molnar return s; 33686470930SIngo Molnar } 33786470930SIngo Molnar 33886470930SIngo Molnar return NULL; 33986470930SIngo Molnar } 34086470930SIngo Molnar 3418e0cf965SAdrian Hunter static struct symbol *symbols__first(struct rb_root *symbols) 3428e0cf965SAdrian Hunter { 3438e0cf965SAdrian Hunter struct rb_node *n = rb_first(symbols); 3448e0cf965SAdrian Hunter 3458e0cf965SAdrian Hunter if (n) 3468e0cf965SAdrian Hunter return rb_entry(n, struct symbol, rb_node); 3478e0cf965SAdrian Hunter 3488e0cf965SAdrian Hunter return NULL; 3498e0cf965SAdrian Hunter } 3508e0cf965SAdrian Hunter 3519c00a81bSAdrian Hunter static struct symbol *symbols__next(struct symbol *sym) 3529c00a81bSAdrian Hunter { 3539c00a81bSAdrian Hunter struct rb_node *n = rb_next(&sym->rb_node); 3549c00a81bSAdrian Hunter 3559c00a81bSAdrian Hunter if (n) 3569c00a81bSAdrian Hunter return rb_entry(n, struct symbol, rb_node); 3579c00a81bSAdrian Hunter 3589c00a81bSAdrian Hunter return NULL; 3599c00a81bSAdrian Hunter } 3609c00a81bSAdrian Hunter 36179406cd7SArnaldo Carvalho de Melo struct symbol_name_rb_node { 36279406cd7SArnaldo Carvalho de Melo struct rb_node rb_node; 36379406cd7SArnaldo Carvalho de Melo struct symbol sym; 36479406cd7SArnaldo Carvalho de Melo }; 36579406cd7SArnaldo Carvalho de Melo 366aeafcbafSArnaldo Carvalho de Melo static void symbols__insert_by_name(struct rb_root *symbols, struct symbol *sym) 36779406cd7SArnaldo Carvalho de Melo { 368aeafcbafSArnaldo Carvalho de Melo struct rb_node **p = &symbols->rb_node; 36979406cd7SArnaldo Carvalho de Melo struct rb_node *parent = NULL; 37002a9d037SRabin Vincent struct symbol_name_rb_node *symn, *s; 37102a9d037SRabin Vincent 37202a9d037SRabin Vincent symn = container_of(sym, struct symbol_name_rb_node, sym); 37379406cd7SArnaldo Carvalho de Melo 37479406cd7SArnaldo Carvalho de Melo while (*p != NULL) { 37579406cd7SArnaldo Carvalho de Melo parent = *p; 37679406cd7SArnaldo Carvalho de Melo s = rb_entry(parent, struct symbol_name_rb_node, rb_node); 37779406cd7SArnaldo Carvalho de Melo if (strcmp(sym->name, s->sym.name) < 0) 37879406cd7SArnaldo Carvalho de Melo p = &(*p)->rb_left; 37979406cd7SArnaldo Carvalho de Melo else 38079406cd7SArnaldo Carvalho de Melo p = &(*p)->rb_right; 38179406cd7SArnaldo Carvalho de Melo } 38279406cd7SArnaldo Carvalho de Melo rb_link_node(&symn->rb_node, parent, p); 383aeafcbafSArnaldo Carvalho de Melo rb_insert_color(&symn->rb_node, symbols); 38479406cd7SArnaldo Carvalho de Melo } 38579406cd7SArnaldo Carvalho de Melo 386aeafcbafSArnaldo Carvalho de Melo static void symbols__sort_by_name(struct rb_root *symbols, 387aeafcbafSArnaldo Carvalho de Melo struct rb_root *source) 38879406cd7SArnaldo Carvalho de Melo { 38979406cd7SArnaldo Carvalho de Melo struct rb_node *nd; 39079406cd7SArnaldo Carvalho de Melo 39179406cd7SArnaldo Carvalho de Melo for (nd = rb_first(source); nd; nd = rb_next(nd)) { 39279406cd7SArnaldo Carvalho de Melo struct symbol *pos = rb_entry(nd, struct symbol, rb_node); 393aeafcbafSArnaldo Carvalho de Melo symbols__insert_by_name(symbols, pos); 39479406cd7SArnaldo Carvalho de Melo } 39579406cd7SArnaldo Carvalho de Melo } 39679406cd7SArnaldo Carvalho de Melo 397aeafcbafSArnaldo Carvalho de Melo static struct symbol *symbols__find_by_name(struct rb_root *symbols, 398aeafcbafSArnaldo Carvalho de Melo const char *name) 39979406cd7SArnaldo Carvalho de Melo { 40079406cd7SArnaldo Carvalho de Melo struct rb_node *n; 4015bcaaca3SMartin Liška struct symbol_name_rb_node *s = NULL; 40279406cd7SArnaldo Carvalho de Melo 403aeafcbafSArnaldo Carvalho de Melo if (symbols == NULL) 40479406cd7SArnaldo Carvalho de Melo return NULL; 40579406cd7SArnaldo Carvalho de Melo 406aeafcbafSArnaldo Carvalho de Melo n = symbols->rb_node; 40779406cd7SArnaldo Carvalho de Melo 40879406cd7SArnaldo Carvalho de Melo while (n) { 40979406cd7SArnaldo Carvalho de Melo int cmp; 41079406cd7SArnaldo Carvalho de Melo 41179406cd7SArnaldo Carvalho de Melo s = rb_entry(n, struct symbol_name_rb_node, rb_node); 412031b84c4SNaveen N. Rao cmp = arch__compare_symbol_names(name, s->sym.name); 41379406cd7SArnaldo Carvalho de Melo 41479406cd7SArnaldo Carvalho de Melo if (cmp < 0) 41579406cd7SArnaldo Carvalho de Melo n = n->rb_left; 41679406cd7SArnaldo Carvalho de Melo else if (cmp > 0) 41779406cd7SArnaldo Carvalho de Melo n = n->rb_right; 41879406cd7SArnaldo Carvalho de Melo else 419de480999SNamhyung Kim break; 42079406cd7SArnaldo Carvalho de Melo } 42179406cd7SArnaldo Carvalho de Melo 422de480999SNamhyung Kim if (n == NULL) 42379406cd7SArnaldo Carvalho de Melo return NULL; 424de480999SNamhyung Kim 425de480999SNamhyung Kim /* return first symbol that has same name (if any) */ 426de480999SNamhyung Kim for (n = rb_prev(n); n; n = rb_prev(n)) { 427de480999SNamhyung Kim struct symbol_name_rb_node *tmp; 428de480999SNamhyung Kim 429de480999SNamhyung Kim tmp = rb_entry(n, struct symbol_name_rb_node, rb_node); 430031b84c4SNaveen N. Rao if (arch__compare_symbol_names(tmp->sym.name, s->sym.name)) 431de480999SNamhyung Kim break; 432de480999SNamhyung Kim 433de480999SNamhyung Kim s = tmp; 434de480999SNamhyung Kim } 435de480999SNamhyung Kim 436de480999SNamhyung Kim return &s->sym; 43779406cd7SArnaldo Carvalho de Melo } 43879406cd7SArnaldo Carvalho de Melo 439aeafcbafSArnaldo Carvalho de Melo struct symbol *dso__find_symbol(struct dso *dso, 44079406cd7SArnaldo Carvalho de Melo enum map_type type, u64 addr) 441fcf1203aSArnaldo Carvalho de Melo { 442aeafcbafSArnaldo Carvalho de Melo return symbols__find(&dso->symbols[type], addr); 443fcf1203aSArnaldo Carvalho de Melo } 444fcf1203aSArnaldo Carvalho de Melo 4459c00a81bSAdrian Hunter struct symbol *dso__first_symbol(struct dso *dso, enum map_type type) 4468e0cf965SAdrian Hunter { 4478e0cf965SAdrian Hunter return symbols__first(&dso->symbols[type]); 4488e0cf965SAdrian Hunter } 4498e0cf965SAdrian Hunter 4509c00a81bSAdrian Hunter struct symbol *dso__next_symbol(struct symbol *sym) 4519c00a81bSAdrian Hunter { 4529c00a81bSAdrian Hunter return symbols__next(sym); 4539c00a81bSAdrian Hunter } 4549c00a81bSAdrian Hunter 45518bd7264SArnaldo Carvalho de Melo struct symbol *symbol__next_by_name(struct symbol *sym) 45618bd7264SArnaldo Carvalho de Melo { 45718bd7264SArnaldo Carvalho de Melo struct symbol_name_rb_node *s = container_of(sym, struct symbol_name_rb_node, sym); 45818bd7264SArnaldo Carvalho de Melo struct rb_node *n = rb_next(&s->rb_node); 45918bd7264SArnaldo Carvalho de Melo 46018bd7264SArnaldo Carvalho de Melo return n ? &rb_entry(n, struct symbol_name_rb_node, rb_node)->sym : NULL; 46118bd7264SArnaldo Carvalho de Melo } 46218bd7264SArnaldo Carvalho de Melo 46318bd7264SArnaldo Carvalho de Melo /* 46418bd7264SArnaldo Carvalho de Melo * Teturns first symbol that matched with @name. 46518bd7264SArnaldo Carvalho de Melo */ 466aeafcbafSArnaldo Carvalho de Melo struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type, 46779406cd7SArnaldo Carvalho de Melo const char *name) 46879406cd7SArnaldo Carvalho de Melo { 469aeafcbafSArnaldo Carvalho de Melo return symbols__find_by_name(&dso->symbol_names[type], name); 47079406cd7SArnaldo Carvalho de Melo } 47179406cd7SArnaldo Carvalho de Melo 472aeafcbafSArnaldo Carvalho de Melo void dso__sort_by_name(struct dso *dso, enum map_type type) 47379406cd7SArnaldo Carvalho de Melo { 474aeafcbafSArnaldo Carvalho de Melo dso__set_sorted_by_name(dso, type); 475aeafcbafSArnaldo Carvalho de Melo return symbols__sort_by_name(&dso->symbol_names[type], 476aeafcbafSArnaldo Carvalho de Melo &dso->symbols[type]); 47779406cd7SArnaldo Carvalho de Melo } 47879406cd7SArnaldo Carvalho de Melo 479aeafcbafSArnaldo Carvalho de Melo size_t dso__fprintf_symbols_by_name(struct dso *dso, 480aeafcbafSArnaldo Carvalho de Melo enum map_type type, FILE *fp) 48190f18e63SSrikar Dronamraju { 48290f18e63SSrikar Dronamraju size_t ret = 0; 48390f18e63SSrikar Dronamraju struct rb_node *nd; 48490f18e63SSrikar Dronamraju struct symbol_name_rb_node *pos; 48590f18e63SSrikar Dronamraju 486aeafcbafSArnaldo Carvalho de Melo for (nd = rb_first(&dso->symbol_names[type]); nd; nd = rb_next(nd)) { 48790f18e63SSrikar Dronamraju pos = rb_entry(nd, struct symbol_name_rb_node, rb_node); 48890f18e63SSrikar Dronamraju fprintf(fp, "%s\n", pos->sym.name); 48990f18e63SSrikar Dronamraju } 49090f18e63SSrikar Dronamraju 49190f18e63SSrikar Dronamraju return ret; 49290f18e63SSrikar Dronamraju } 49390f18e63SSrikar Dronamraju 494316d70d6SAdrian Hunter int modules__parse(const char *filename, void *arg, 495316d70d6SAdrian Hunter int (*process_module)(void *arg, const char *name, 496316d70d6SAdrian Hunter u64 start)) 497316d70d6SAdrian Hunter { 498316d70d6SAdrian Hunter char *line = NULL; 499316d70d6SAdrian Hunter size_t n; 500316d70d6SAdrian Hunter FILE *file; 501316d70d6SAdrian Hunter int err = 0; 502316d70d6SAdrian Hunter 503316d70d6SAdrian Hunter file = fopen(filename, "r"); 504316d70d6SAdrian Hunter if (file == NULL) 505316d70d6SAdrian Hunter return -1; 506316d70d6SAdrian Hunter 507316d70d6SAdrian Hunter while (1) { 508316d70d6SAdrian Hunter char name[PATH_MAX]; 509316d70d6SAdrian Hunter u64 start; 510316d70d6SAdrian Hunter char *sep; 511316d70d6SAdrian Hunter ssize_t line_len; 512316d70d6SAdrian Hunter 513316d70d6SAdrian Hunter line_len = getline(&line, &n, file); 514316d70d6SAdrian Hunter if (line_len < 0) { 515316d70d6SAdrian Hunter if (feof(file)) 516316d70d6SAdrian Hunter break; 517316d70d6SAdrian Hunter err = -1; 518316d70d6SAdrian Hunter goto out; 519316d70d6SAdrian Hunter } 520316d70d6SAdrian Hunter 521316d70d6SAdrian Hunter if (!line) { 522316d70d6SAdrian Hunter err = -1; 523316d70d6SAdrian Hunter goto out; 524316d70d6SAdrian Hunter } 525316d70d6SAdrian Hunter 526316d70d6SAdrian Hunter line[--line_len] = '\0'; /* \n */ 527316d70d6SAdrian Hunter 528316d70d6SAdrian Hunter sep = strrchr(line, 'x'); 529316d70d6SAdrian Hunter if (sep == NULL) 530316d70d6SAdrian Hunter continue; 531316d70d6SAdrian Hunter 532316d70d6SAdrian Hunter hex2u64(sep + 1, &start); 533316d70d6SAdrian Hunter 534316d70d6SAdrian Hunter sep = strchr(line, ' '); 535316d70d6SAdrian Hunter if (sep == NULL) 536316d70d6SAdrian Hunter continue; 537316d70d6SAdrian Hunter 538316d70d6SAdrian Hunter *sep = '\0'; 539316d70d6SAdrian Hunter 540316d70d6SAdrian Hunter scnprintf(name, sizeof(name), "[%s]", line); 541316d70d6SAdrian Hunter 542316d70d6SAdrian Hunter err = process_module(arg, name, start); 543316d70d6SAdrian Hunter if (err) 544316d70d6SAdrian Hunter break; 545316d70d6SAdrian Hunter } 546316d70d6SAdrian Hunter out: 547316d70d6SAdrian Hunter free(line); 548316d70d6SAdrian Hunter fclose(file); 549316d70d6SAdrian Hunter return err; 550316d70d6SAdrian Hunter } 551316d70d6SAdrian Hunter 552682b335aSArnaldo Carvalho de Melo struct process_kallsyms_args { 553682b335aSArnaldo Carvalho de Melo struct map *map; 554682b335aSArnaldo Carvalho de Melo struct dso *dso; 555682b335aSArnaldo Carvalho de Melo }; 556682b335aSArnaldo Carvalho de Melo 557e7110b9fSArnaldo Carvalho de Melo /* 558e7110b9fSArnaldo Carvalho de Melo * These are symbols in the kernel image, so make sure that 559e7110b9fSArnaldo Carvalho de Melo * sym is from a kernel DSO. 560e7110b9fSArnaldo Carvalho de Melo */ 56182d1deb0SDavid Ahern bool symbol__is_idle(struct symbol *sym) 56282d1deb0SDavid Ahern { 56382d1deb0SDavid Ahern const char * const idle_symbols[] = { 56482d1deb0SDavid Ahern "cpu_idle", 565e0336ed6SArnaldo Carvalho de Melo "cpu_startup_entry", 56682d1deb0SDavid Ahern "intel_idle", 56782d1deb0SDavid Ahern "default_idle", 56882d1deb0SDavid Ahern "native_safe_halt", 56982d1deb0SDavid Ahern "enter_idle", 57082d1deb0SDavid Ahern "exit_idle", 57182d1deb0SDavid Ahern "mwait_idle", 57282d1deb0SDavid Ahern "mwait_idle_with_hints", 57382d1deb0SDavid Ahern "poll_idle", 57482d1deb0SDavid Ahern "ppc64_runlatch_off", 57582d1deb0SDavid Ahern "pseries_dedicated_idle_sleep", 57682d1deb0SDavid Ahern NULL 57782d1deb0SDavid Ahern }; 57882d1deb0SDavid Ahern 57982d1deb0SDavid Ahern int i; 58082d1deb0SDavid Ahern 58182d1deb0SDavid Ahern if (!sym) 58282d1deb0SDavid Ahern return false; 58382d1deb0SDavid Ahern 58482d1deb0SDavid Ahern for (i = 0; idle_symbols[i]; i++) { 58582d1deb0SDavid Ahern if (!strcmp(idle_symbols[i], sym->name)) 58682d1deb0SDavid Ahern return true; 58782d1deb0SDavid Ahern } 58882d1deb0SDavid Ahern 58982d1deb0SDavid Ahern return false; 59082d1deb0SDavid Ahern } 59182d1deb0SDavid Ahern 592682b335aSArnaldo Carvalho de Melo static int map__process_kallsym_symbol(void *arg, const char *name, 59382151520SCody P Schafer char type, u64 start) 594682b335aSArnaldo Carvalho de Melo { 595682b335aSArnaldo Carvalho de Melo struct symbol *sym; 596682b335aSArnaldo Carvalho de Melo struct process_kallsyms_args *a = arg; 597682b335aSArnaldo Carvalho de Melo struct rb_root *root = &a->dso->symbols[a->map->type]; 598682b335aSArnaldo Carvalho de Melo 599682b335aSArnaldo Carvalho de Melo if (!symbol_type__is_a(type, a->map->type)) 600682b335aSArnaldo Carvalho de Melo return 0; 601682b335aSArnaldo Carvalho de Melo 60282151520SCody P Schafer /* 60382151520SCody P Schafer * module symbols are not sorted so we add all 60482151520SCody P Schafer * symbols, setting length to 0, and rely on 60582151520SCody P Schafer * symbols__fixup_end() to fix it up. 60682151520SCody P Schafer */ 60782151520SCody P Schafer sym = symbol__new(start, 0, kallsyms2elf_type(type), name); 6082e538c4aSArnaldo Carvalho de Melo if (sym == NULL) 609682b335aSArnaldo Carvalho de Melo return -ENOMEM; 61082164161SArnaldo Carvalho de Melo /* 61182164161SArnaldo Carvalho de Melo * We will pass the symbols to the filter later, in 6124e06255fSArnaldo Carvalho de Melo * map__split_kallsyms, when we have split the maps per module 61382164161SArnaldo Carvalho de Melo */ 6144e06255fSArnaldo Carvalho de Melo symbols__insert(root, sym); 615a1645ce1SZhang, Yanmin 616682b335aSArnaldo Carvalho de Melo return 0; 6172e538c4aSArnaldo Carvalho de Melo } 6182e538c4aSArnaldo Carvalho de Melo 619682b335aSArnaldo Carvalho de Melo /* 620682b335aSArnaldo Carvalho de Melo * Loads the function entries in /proc/kallsyms into kernel_map->dso, 621682b335aSArnaldo Carvalho de Melo * so that we can in the next step set the symbol ->end address and then 622682b335aSArnaldo Carvalho de Melo * call kernel_maps__split_kallsyms. 623682b335aSArnaldo Carvalho de Melo */ 624aeafcbafSArnaldo Carvalho de Melo static int dso__load_all_kallsyms(struct dso *dso, const char *filename, 6259e201442SArnaldo Carvalho de Melo struct map *map) 626682b335aSArnaldo Carvalho de Melo { 627aeafcbafSArnaldo Carvalho de Melo struct process_kallsyms_args args = { .map = map, .dso = dso, }; 6289e201442SArnaldo Carvalho de Melo return kallsyms__parse(filename, &args, map__process_kallsym_symbol); 6292e538c4aSArnaldo Carvalho de Melo } 6302e538c4aSArnaldo Carvalho de Melo 6318e0cf965SAdrian Hunter static int dso__split_kallsyms_for_kcore(struct dso *dso, struct map *map, 6328e0cf965SAdrian Hunter symbol_filter_t filter) 6338e0cf965SAdrian Hunter { 634ba92732eSWang Nan struct map_groups *kmaps = map__kmaps(map); 6358e0cf965SAdrian Hunter struct map *curr_map; 6368e0cf965SAdrian Hunter struct symbol *pos; 6378e0cf965SAdrian Hunter int count = 0, moved = 0; 6388e0cf965SAdrian Hunter struct rb_root *root = &dso->symbols[map->type]; 6398e0cf965SAdrian Hunter struct rb_node *next = rb_first(root); 6408e0cf965SAdrian Hunter 641ba92732eSWang Nan if (!kmaps) 642ba92732eSWang Nan return -1; 643ba92732eSWang Nan 6448e0cf965SAdrian Hunter while (next) { 6458e0cf965SAdrian Hunter char *module; 6468e0cf965SAdrian Hunter 6478e0cf965SAdrian Hunter pos = rb_entry(next, struct symbol, rb_node); 6488e0cf965SAdrian Hunter next = rb_next(&pos->rb_node); 6498e0cf965SAdrian Hunter 6508e0cf965SAdrian Hunter module = strchr(pos->name, '\t'); 6518e0cf965SAdrian Hunter if (module) 6528e0cf965SAdrian Hunter *module = '\0'; 6538e0cf965SAdrian Hunter 6548e0cf965SAdrian Hunter curr_map = map_groups__find(kmaps, map->type, pos->start); 6558e0cf965SAdrian Hunter 6568e0cf965SAdrian Hunter if (!curr_map || (filter && filter(curr_map, pos))) { 6578e0cf965SAdrian Hunter rb_erase(&pos->rb_node, root); 6588e0cf965SAdrian Hunter symbol__delete(pos); 6598e0cf965SAdrian Hunter } else { 6608e0cf965SAdrian Hunter pos->start -= curr_map->start - curr_map->pgoff; 6618e0cf965SAdrian Hunter if (pos->end) 6628e0cf965SAdrian Hunter pos->end -= curr_map->start - curr_map->pgoff; 6638e0cf965SAdrian Hunter if (curr_map != map) { 6648e0cf965SAdrian Hunter rb_erase(&pos->rb_node, root); 6658e0cf965SAdrian Hunter symbols__insert( 6668e0cf965SAdrian Hunter &curr_map->dso->symbols[curr_map->type], 6678e0cf965SAdrian Hunter pos); 6688e0cf965SAdrian Hunter ++moved; 6698e0cf965SAdrian Hunter } else { 6708e0cf965SAdrian Hunter ++count; 6718e0cf965SAdrian Hunter } 6728e0cf965SAdrian Hunter } 6738e0cf965SAdrian Hunter } 6748e0cf965SAdrian Hunter 6758e0cf965SAdrian Hunter /* Symbols have been adjusted */ 6768e0cf965SAdrian Hunter dso->adjust_symbols = 1; 6778e0cf965SAdrian Hunter 6788e0cf965SAdrian Hunter return count + moved; 6798e0cf965SAdrian Hunter } 6808e0cf965SAdrian Hunter 6812e538c4aSArnaldo Carvalho de Melo /* 6822e538c4aSArnaldo Carvalho de Melo * Split the symbols into maps, making sure there are no overlaps, i.e. the 6832e538c4aSArnaldo Carvalho de Melo * kernel range is broken in several maps, named [kernel].N, as we don't have 6842e538c4aSArnaldo Carvalho de Melo * the original ELF section names vmlinux have. 6852e538c4aSArnaldo Carvalho de Melo */ 686d9b62abaSAdrian Hunter static int dso__split_kallsyms(struct dso *dso, struct map *map, u64 delta, 6879de89fe7SArnaldo Carvalho de Melo symbol_filter_t filter) 6882e538c4aSArnaldo Carvalho de Melo { 689ba92732eSWang Nan struct map_groups *kmaps = map__kmaps(map); 690ba92732eSWang Nan struct machine *machine; 6914e06255fSArnaldo Carvalho de Melo struct map *curr_map = map; 6922e538c4aSArnaldo Carvalho de Melo struct symbol *pos; 6938a953312SArnaldo Carvalho de Melo int count = 0, moved = 0; 694aeafcbafSArnaldo Carvalho de Melo struct rb_root *root = &dso->symbols[map->type]; 6954e06255fSArnaldo Carvalho de Melo struct rb_node *next = rb_first(root); 6962e538c4aSArnaldo Carvalho de Melo int kernel_range = 0; 6972e538c4aSArnaldo Carvalho de Melo 698ba92732eSWang Nan if (!kmaps) 699ba92732eSWang Nan return -1; 700ba92732eSWang Nan 701ba92732eSWang Nan machine = kmaps->machine; 702ba92732eSWang Nan 7032e538c4aSArnaldo Carvalho de Melo while (next) { 7042e538c4aSArnaldo Carvalho de Melo char *module; 7052e538c4aSArnaldo Carvalho de Melo 7062e538c4aSArnaldo Carvalho de Melo pos = rb_entry(next, struct symbol, rb_node); 7072e538c4aSArnaldo Carvalho de Melo next = rb_next(&pos->rb_node); 7082e538c4aSArnaldo Carvalho de Melo 7092e538c4aSArnaldo Carvalho de Melo module = strchr(pos->name, '\t'); 7102e538c4aSArnaldo Carvalho de Melo if (module) { 71175be6cf4SArnaldo Carvalho de Melo if (!symbol_conf.use_modules) 7121de8e245SArnaldo Carvalho de Melo goto discard_symbol; 7131de8e245SArnaldo Carvalho de Melo 7142e538c4aSArnaldo Carvalho de Melo *module++ = '\0'; 7152e538c4aSArnaldo Carvalho de Melo 716b7cece76SArnaldo Carvalho de Melo if (strcmp(curr_map->dso->short_name, module)) { 717a1645ce1SZhang, Yanmin if (curr_map != map && 718aeafcbafSArnaldo Carvalho de Melo dso->kernel == DSO_TYPE_GUEST_KERNEL && 71923346f21SArnaldo Carvalho de Melo machine__is_default_guest(machine)) { 720a1645ce1SZhang, Yanmin /* 721a1645ce1SZhang, Yanmin * We assume all symbols of a module are 722a1645ce1SZhang, Yanmin * continuous in * kallsyms, so curr_map 723a1645ce1SZhang, Yanmin * points to a module and all its 724a1645ce1SZhang, Yanmin * symbols are in its kmap. Mark it as 725a1645ce1SZhang, Yanmin * loaded. 726a1645ce1SZhang, Yanmin */ 727a1645ce1SZhang, Yanmin dso__set_loaded(curr_map->dso, 728a1645ce1SZhang, Yanmin curr_map->type); 729af427bf5SArnaldo Carvalho de Melo } 730b7cece76SArnaldo Carvalho de Melo 731a1645ce1SZhang, Yanmin curr_map = map_groups__find_by_name(kmaps, 732a1645ce1SZhang, Yanmin map->type, module); 733a1645ce1SZhang, Yanmin if (curr_map == NULL) { 7342f51903bSArnaldo Carvalho de Melo pr_debug("%s/proc/{kallsyms,modules} " 735a1645ce1SZhang, Yanmin "inconsistency while looking " 736a1645ce1SZhang, Yanmin "for \"%s\" module!\n", 73723346f21SArnaldo Carvalho de Melo machine->root_dir, module); 738a1645ce1SZhang, Yanmin curr_map = map; 739a1645ce1SZhang, Yanmin goto discard_symbol; 740a1645ce1SZhang, Yanmin } 741a1645ce1SZhang, Yanmin 742a1645ce1SZhang, Yanmin if (curr_map->dso->loaded && 74323346f21SArnaldo Carvalho de Melo !machine__is_default_guest(machine)) 744b7cece76SArnaldo Carvalho de Melo goto discard_symbol; 745af427bf5SArnaldo Carvalho de Melo } 74686470930SIngo Molnar /* 7472e538c4aSArnaldo Carvalho de Melo * So that we look just like we get from .ko files, 7482e538c4aSArnaldo Carvalho de Melo * i.e. not prelinked, relative to map->start. 74986470930SIngo Molnar */ 7504e06255fSArnaldo Carvalho de Melo pos->start = curr_map->map_ip(curr_map, pos->start); 7514e06255fSArnaldo Carvalho de Melo pos->end = curr_map->map_ip(curr_map, pos->end); 7524e06255fSArnaldo Carvalho de Melo } else if (curr_map != map) { 7532e538c4aSArnaldo Carvalho de Melo char dso_name[PATH_MAX]; 754aeafcbafSArnaldo Carvalho de Melo struct dso *ndso; 75586470930SIngo Molnar 756d9b62abaSAdrian Hunter if (delta) { 757d9b62abaSAdrian Hunter /* Kernel was relocated at boot time */ 758d9b62abaSAdrian Hunter pos->start -= delta; 759d9b62abaSAdrian Hunter pos->end -= delta; 760d9b62abaSAdrian Hunter } 761d9b62abaSAdrian Hunter 7628a953312SArnaldo Carvalho de Melo if (count == 0) { 7638a953312SArnaldo Carvalho de Melo curr_map = map; 7648a953312SArnaldo Carvalho de Melo goto filter_symbol; 7658a953312SArnaldo Carvalho de Melo } 7668a953312SArnaldo Carvalho de Melo 767aeafcbafSArnaldo Carvalho de Melo if (dso->kernel == DSO_TYPE_GUEST_KERNEL) 768a1645ce1SZhang, Yanmin snprintf(dso_name, sizeof(dso_name), 769a1645ce1SZhang, Yanmin "[guest.kernel].%d", 770a1645ce1SZhang, Yanmin kernel_range++); 771a1645ce1SZhang, Yanmin else 772a1645ce1SZhang, Yanmin snprintf(dso_name, sizeof(dso_name), 773a1645ce1SZhang, Yanmin "[kernel].%d", 7742e538c4aSArnaldo Carvalho de Melo kernel_range++); 77586470930SIngo Molnar 776aeafcbafSArnaldo Carvalho de Melo ndso = dso__new(dso_name); 777aeafcbafSArnaldo Carvalho de Melo if (ndso == NULL) 7782e538c4aSArnaldo Carvalho de Melo return -1; 7792e538c4aSArnaldo Carvalho de Melo 780aeafcbafSArnaldo Carvalho de Melo ndso->kernel = dso->kernel; 781a1645ce1SZhang, Yanmin 782aeafcbafSArnaldo Carvalho de Melo curr_map = map__new2(pos->start, ndso, map->type); 78337fe5fcbSZhang, Yanmin if (curr_map == NULL) { 784aeafcbafSArnaldo Carvalho de Melo dso__delete(ndso); 7852e538c4aSArnaldo Carvalho de Melo return -1; 7862e538c4aSArnaldo Carvalho de Melo } 7872e538c4aSArnaldo Carvalho de Melo 7884e06255fSArnaldo Carvalho de Melo curr_map->map_ip = curr_map->unmap_ip = identity__map_ip; 7899de89fe7SArnaldo Carvalho de Melo map_groups__insert(kmaps, curr_map); 7902e538c4aSArnaldo Carvalho de Melo ++kernel_range; 791d9b62abaSAdrian Hunter } else if (delta) { 792d9b62abaSAdrian Hunter /* Kernel was relocated at boot time */ 793d9b62abaSAdrian Hunter pos->start -= delta; 794d9b62abaSAdrian Hunter pos->end -= delta; 7952e538c4aSArnaldo Carvalho de Melo } 7968a953312SArnaldo Carvalho de Melo filter_symbol: 7974e06255fSArnaldo Carvalho de Melo if (filter && filter(curr_map, pos)) { 7981de8e245SArnaldo Carvalho de Melo discard_symbol: rb_erase(&pos->rb_node, root); 79900a192b3SArnaldo Carvalho de Melo symbol__delete(pos); 8002e538c4aSArnaldo Carvalho de Melo } else { 8014e06255fSArnaldo Carvalho de Melo if (curr_map != map) { 8024e06255fSArnaldo Carvalho de Melo rb_erase(&pos->rb_node, root); 8034e06255fSArnaldo Carvalho de Melo symbols__insert(&curr_map->dso->symbols[curr_map->type], pos); 8048a953312SArnaldo Carvalho de Melo ++moved; 8058a953312SArnaldo Carvalho de Melo } else 8068a953312SArnaldo Carvalho de Melo ++count; 8079974f496SMike Galbraith } 80886470930SIngo Molnar } 80986470930SIngo Molnar 810a1645ce1SZhang, Yanmin if (curr_map != map && 811aeafcbafSArnaldo Carvalho de Melo dso->kernel == DSO_TYPE_GUEST_KERNEL && 81223346f21SArnaldo Carvalho de Melo machine__is_default_guest(kmaps->machine)) { 813a1645ce1SZhang, Yanmin dso__set_loaded(curr_map->dso, curr_map->type); 814a1645ce1SZhang, Yanmin } 815a1645ce1SZhang, Yanmin 8168a953312SArnaldo Carvalho de Melo return count + moved; 81786470930SIngo Molnar } 81886470930SIngo Molnar 8193f067dcaSArnaldo Carvalho de Melo bool symbol__restricted_filename(const char *filename, 820ec80fde7SArnaldo Carvalho de Melo const char *restricted_filename) 821ec80fde7SArnaldo Carvalho de Melo { 822ec80fde7SArnaldo Carvalho de Melo bool restricted = false; 823ec80fde7SArnaldo Carvalho de Melo 824ec80fde7SArnaldo Carvalho de Melo if (symbol_conf.kptr_restrict) { 825ec80fde7SArnaldo Carvalho de Melo char *r = realpath(filename, NULL); 826ec80fde7SArnaldo Carvalho de Melo 827ec80fde7SArnaldo Carvalho de Melo if (r != NULL) { 828ec80fde7SArnaldo Carvalho de Melo restricted = strcmp(r, restricted_filename) == 0; 829ec80fde7SArnaldo Carvalho de Melo free(r); 830ec80fde7SArnaldo Carvalho de Melo return restricted; 831ec80fde7SArnaldo Carvalho de Melo } 832ec80fde7SArnaldo Carvalho de Melo } 833ec80fde7SArnaldo Carvalho de Melo 834ec80fde7SArnaldo Carvalho de Melo return restricted; 835ec80fde7SArnaldo Carvalho de Melo } 836ec80fde7SArnaldo Carvalho de Melo 83752afdaf9SAdrian Hunter struct module_info { 83852afdaf9SAdrian Hunter struct rb_node rb_node; 83952afdaf9SAdrian Hunter char *name; 84052afdaf9SAdrian Hunter u64 start; 84152afdaf9SAdrian Hunter }; 84252afdaf9SAdrian Hunter 84352afdaf9SAdrian Hunter static void add_module(struct module_info *mi, struct rb_root *modules) 84452afdaf9SAdrian Hunter { 84552afdaf9SAdrian Hunter struct rb_node **p = &modules->rb_node; 84652afdaf9SAdrian Hunter struct rb_node *parent = NULL; 84752afdaf9SAdrian Hunter struct module_info *m; 84852afdaf9SAdrian Hunter 84952afdaf9SAdrian Hunter while (*p != NULL) { 85052afdaf9SAdrian Hunter parent = *p; 85152afdaf9SAdrian Hunter m = rb_entry(parent, struct module_info, rb_node); 85252afdaf9SAdrian Hunter if (strcmp(mi->name, m->name) < 0) 85352afdaf9SAdrian Hunter p = &(*p)->rb_left; 85452afdaf9SAdrian Hunter else 85552afdaf9SAdrian Hunter p = &(*p)->rb_right; 85652afdaf9SAdrian Hunter } 85752afdaf9SAdrian Hunter rb_link_node(&mi->rb_node, parent, p); 85852afdaf9SAdrian Hunter rb_insert_color(&mi->rb_node, modules); 85952afdaf9SAdrian Hunter } 86052afdaf9SAdrian Hunter 86152afdaf9SAdrian Hunter static void delete_modules(struct rb_root *modules) 86252afdaf9SAdrian Hunter { 86352afdaf9SAdrian Hunter struct module_info *mi; 86452afdaf9SAdrian Hunter struct rb_node *next = rb_first(modules); 86552afdaf9SAdrian Hunter 86652afdaf9SAdrian Hunter while (next) { 86752afdaf9SAdrian Hunter mi = rb_entry(next, struct module_info, rb_node); 86852afdaf9SAdrian Hunter next = rb_next(&mi->rb_node); 86952afdaf9SAdrian Hunter rb_erase(&mi->rb_node, modules); 87074cf249dSArnaldo Carvalho de Melo zfree(&mi->name); 87152afdaf9SAdrian Hunter free(mi); 87252afdaf9SAdrian Hunter } 87352afdaf9SAdrian Hunter } 87452afdaf9SAdrian Hunter 87552afdaf9SAdrian Hunter static struct module_info *find_module(const char *name, 87652afdaf9SAdrian Hunter struct rb_root *modules) 87752afdaf9SAdrian Hunter { 87852afdaf9SAdrian Hunter struct rb_node *n = modules->rb_node; 87952afdaf9SAdrian Hunter 88052afdaf9SAdrian Hunter while (n) { 88152afdaf9SAdrian Hunter struct module_info *m; 88252afdaf9SAdrian Hunter int cmp; 88352afdaf9SAdrian Hunter 88452afdaf9SAdrian Hunter m = rb_entry(n, struct module_info, rb_node); 88552afdaf9SAdrian Hunter cmp = strcmp(name, m->name); 88652afdaf9SAdrian Hunter if (cmp < 0) 88752afdaf9SAdrian Hunter n = n->rb_left; 88852afdaf9SAdrian Hunter else if (cmp > 0) 88952afdaf9SAdrian Hunter n = n->rb_right; 89052afdaf9SAdrian Hunter else 89152afdaf9SAdrian Hunter return m; 89252afdaf9SAdrian Hunter } 89352afdaf9SAdrian Hunter 89452afdaf9SAdrian Hunter return NULL; 89552afdaf9SAdrian Hunter } 89652afdaf9SAdrian Hunter 89752afdaf9SAdrian Hunter static int __read_proc_modules(void *arg, const char *name, u64 start) 89852afdaf9SAdrian Hunter { 89952afdaf9SAdrian Hunter struct rb_root *modules = arg; 90052afdaf9SAdrian Hunter struct module_info *mi; 90152afdaf9SAdrian Hunter 90252afdaf9SAdrian Hunter mi = zalloc(sizeof(struct module_info)); 90352afdaf9SAdrian Hunter if (!mi) 90452afdaf9SAdrian Hunter return -ENOMEM; 90552afdaf9SAdrian Hunter 90652afdaf9SAdrian Hunter mi->name = strdup(name); 90752afdaf9SAdrian Hunter mi->start = start; 90852afdaf9SAdrian Hunter 90952afdaf9SAdrian Hunter if (!mi->name) { 91052afdaf9SAdrian Hunter free(mi); 91152afdaf9SAdrian Hunter return -ENOMEM; 91252afdaf9SAdrian Hunter } 91352afdaf9SAdrian Hunter 91452afdaf9SAdrian Hunter add_module(mi, modules); 91552afdaf9SAdrian Hunter 91652afdaf9SAdrian Hunter return 0; 91752afdaf9SAdrian Hunter } 91852afdaf9SAdrian Hunter 91952afdaf9SAdrian Hunter static int read_proc_modules(const char *filename, struct rb_root *modules) 92052afdaf9SAdrian Hunter { 92152afdaf9SAdrian Hunter if (symbol__restricted_filename(filename, "/proc/modules")) 92252afdaf9SAdrian Hunter return -1; 92352afdaf9SAdrian Hunter 92452afdaf9SAdrian Hunter if (modules__parse(filename, modules, __read_proc_modules)) { 92552afdaf9SAdrian Hunter delete_modules(modules); 92652afdaf9SAdrian Hunter return -1; 92752afdaf9SAdrian Hunter } 92852afdaf9SAdrian Hunter 92952afdaf9SAdrian Hunter return 0; 93052afdaf9SAdrian Hunter } 93152afdaf9SAdrian Hunter 932fc1b691dSAdrian Hunter int compare_proc_modules(const char *from, const char *to) 933fc1b691dSAdrian Hunter { 934fc1b691dSAdrian Hunter struct rb_root from_modules = RB_ROOT; 935fc1b691dSAdrian Hunter struct rb_root to_modules = RB_ROOT; 936fc1b691dSAdrian Hunter struct rb_node *from_node, *to_node; 937fc1b691dSAdrian Hunter struct module_info *from_m, *to_m; 938fc1b691dSAdrian Hunter int ret = -1; 939fc1b691dSAdrian Hunter 940fc1b691dSAdrian Hunter if (read_proc_modules(from, &from_modules)) 941fc1b691dSAdrian Hunter return -1; 942fc1b691dSAdrian Hunter 943fc1b691dSAdrian Hunter if (read_proc_modules(to, &to_modules)) 944fc1b691dSAdrian Hunter goto out_delete_from; 945fc1b691dSAdrian Hunter 946fc1b691dSAdrian Hunter from_node = rb_first(&from_modules); 947fc1b691dSAdrian Hunter to_node = rb_first(&to_modules); 948fc1b691dSAdrian Hunter while (from_node) { 949fc1b691dSAdrian Hunter if (!to_node) 950fc1b691dSAdrian Hunter break; 951fc1b691dSAdrian Hunter 952fc1b691dSAdrian Hunter from_m = rb_entry(from_node, struct module_info, rb_node); 953fc1b691dSAdrian Hunter to_m = rb_entry(to_node, struct module_info, rb_node); 954fc1b691dSAdrian Hunter 955fc1b691dSAdrian Hunter if (from_m->start != to_m->start || 956fc1b691dSAdrian Hunter strcmp(from_m->name, to_m->name)) 957fc1b691dSAdrian Hunter break; 958fc1b691dSAdrian Hunter 959fc1b691dSAdrian Hunter from_node = rb_next(from_node); 960fc1b691dSAdrian Hunter to_node = rb_next(to_node); 961fc1b691dSAdrian Hunter } 962fc1b691dSAdrian Hunter 963fc1b691dSAdrian Hunter if (!from_node && !to_node) 964fc1b691dSAdrian Hunter ret = 0; 965fc1b691dSAdrian Hunter 966fc1b691dSAdrian Hunter delete_modules(&to_modules); 967fc1b691dSAdrian Hunter out_delete_from: 968fc1b691dSAdrian Hunter delete_modules(&from_modules); 969fc1b691dSAdrian Hunter 970fc1b691dSAdrian Hunter return ret; 971fc1b691dSAdrian Hunter } 972fc1b691dSAdrian Hunter 97352afdaf9SAdrian Hunter static int do_validate_kcore_modules(const char *filename, struct map *map, 97452afdaf9SAdrian Hunter struct map_groups *kmaps) 97552afdaf9SAdrian Hunter { 97652afdaf9SAdrian Hunter struct rb_root modules = RB_ROOT; 97752afdaf9SAdrian Hunter struct map *old_map; 97852afdaf9SAdrian Hunter int err; 97952afdaf9SAdrian Hunter 98052afdaf9SAdrian Hunter err = read_proc_modules(filename, &modules); 98152afdaf9SAdrian Hunter if (err) 98252afdaf9SAdrian Hunter return err; 98352afdaf9SAdrian Hunter 98452afdaf9SAdrian Hunter old_map = map_groups__first(kmaps, map->type); 98552afdaf9SAdrian Hunter while (old_map) { 98652afdaf9SAdrian Hunter struct map *next = map_groups__next(old_map); 98752afdaf9SAdrian Hunter struct module_info *mi; 98852afdaf9SAdrian Hunter 98952afdaf9SAdrian Hunter if (old_map == map || old_map->start == map->start) { 99052afdaf9SAdrian Hunter /* The kernel map */ 99152afdaf9SAdrian Hunter old_map = next; 99252afdaf9SAdrian Hunter continue; 99352afdaf9SAdrian Hunter } 99452afdaf9SAdrian Hunter 99552afdaf9SAdrian Hunter /* Module must be in memory at the same address */ 99652afdaf9SAdrian Hunter mi = find_module(old_map->dso->short_name, &modules); 99752afdaf9SAdrian Hunter if (!mi || mi->start != old_map->start) { 99852afdaf9SAdrian Hunter err = -EINVAL; 99952afdaf9SAdrian Hunter goto out; 100052afdaf9SAdrian Hunter } 100152afdaf9SAdrian Hunter 100252afdaf9SAdrian Hunter old_map = next; 100352afdaf9SAdrian Hunter } 100452afdaf9SAdrian Hunter out: 100552afdaf9SAdrian Hunter delete_modules(&modules); 100652afdaf9SAdrian Hunter return err; 100752afdaf9SAdrian Hunter } 100852afdaf9SAdrian Hunter 100952afdaf9SAdrian Hunter /* 101052afdaf9SAdrian Hunter * If kallsyms is referenced by name then we look for filename in the same 101152afdaf9SAdrian Hunter * directory. 101252afdaf9SAdrian Hunter */ 101352afdaf9SAdrian Hunter static bool filename_from_kallsyms_filename(char *filename, 101452afdaf9SAdrian Hunter const char *base_name, 101552afdaf9SAdrian Hunter const char *kallsyms_filename) 101652afdaf9SAdrian Hunter { 101752afdaf9SAdrian Hunter char *name; 101852afdaf9SAdrian Hunter 101952afdaf9SAdrian Hunter strcpy(filename, kallsyms_filename); 102052afdaf9SAdrian Hunter name = strrchr(filename, '/'); 102152afdaf9SAdrian Hunter if (!name) 102252afdaf9SAdrian Hunter return false; 102352afdaf9SAdrian Hunter 102452afdaf9SAdrian Hunter name += 1; 102552afdaf9SAdrian Hunter 102652afdaf9SAdrian Hunter if (!strcmp(name, "kallsyms")) { 102752afdaf9SAdrian Hunter strcpy(name, base_name); 102852afdaf9SAdrian Hunter return true; 102952afdaf9SAdrian Hunter } 103052afdaf9SAdrian Hunter 103152afdaf9SAdrian Hunter return false; 103252afdaf9SAdrian Hunter } 103352afdaf9SAdrian Hunter 103452afdaf9SAdrian Hunter static int validate_kcore_modules(const char *kallsyms_filename, 103552afdaf9SAdrian Hunter struct map *map) 103652afdaf9SAdrian Hunter { 1037ba92732eSWang Nan struct map_groups *kmaps = map__kmaps(map); 103852afdaf9SAdrian Hunter char modules_filename[PATH_MAX]; 103952afdaf9SAdrian Hunter 1040ba92732eSWang Nan if (!kmaps) 1041ba92732eSWang Nan return -EINVAL; 1042ba92732eSWang Nan 104352afdaf9SAdrian Hunter if (!filename_from_kallsyms_filename(modules_filename, "modules", 104452afdaf9SAdrian Hunter kallsyms_filename)) 104552afdaf9SAdrian Hunter return -EINVAL; 104652afdaf9SAdrian Hunter 104752afdaf9SAdrian Hunter if (do_validate_kcore_modules(modules_filename, map, kmaps)) 104852afdaf9SAdrian Hunter return -EINVAL; 104952afdaf9SAdrian Hunter 105052afdaf9SAdrian Hunter return 0; 105152afdaf9SAdrian Hunter } 105252afdaf9SAdrian Hunter 1053a00d28cbSAdrian Hunter static int validate_kcore_addresses(const char *kallsyms_filename, 1054a00d28cbSAdrian Hunter struct map *map) 1055a00d28cbSAdrian Hunter { 1056a00d28cbSAdrian Hunter struct kmap *kmap = map__kmap(map); 1057a00d28cbSAdrian Hunter 1058ba92732eSWang Nan if (!kmap) 1059ba92732eSWang Nan return -EINVAL; 1060ba92732eSWang Nan 1061a00d28cbSAdrian Hunter if (kmap->ref_reloc_sym && kmap->ref_reloc_sym->name) { 1062a00d28cbSAdrian Hunter u64 start; 1063a00d28cbSAdrian Hunter 1064a00d28cbSAdrian Hunter start = kallsyms__get_function_start(kallsyms_filename, 1065a00d28cbSAdrian Hunter kmap->ref_reloc_sym->name); 1066a00d28cbSAdrian Hunter if (start != kmap->ref_reloc_sym->addr) 1067a00d28cbSAdrian Hunter return -EINVAL; 1068a00d28cbSAdrian Hunter } 1069a00d28cbSAdrian Hunter 1070a00d28cbSAdrian Hunter return validate_kcore_modules(kallsyms_filename, map); 1071a00d28cbSAdrian Hunter } 1072a00d28cbSAdrian Hunter 10738e0cf965SAdrian Hunter struct kcore_mapfn_data { 10748e0cf965SAdrian Hunter struct dso *dso; 10758e0cf965SAdrian Hunter enum map_type type; 10768e0cf965SAdrian Hunter struct list_head maps; 10778e0cf965SAdrian Hunter }; 10788e0cf965SAdrian Hunter 10798e0cf965SAdrian Hunter static int kcore_mapfn(u64 start, u64 len, u64 pgoff, void *data) 10808e0cf965SAdrian Hunter { 10818e0cf965SAdrian Hunter struct kcore_mapfn_data *md = data; 10828e0cf965SAdrian Hunter struct map *map; 10838e0cf965SAdrian Hunter 10848e0cf965SAdrian Hunter map = map__new2(start, md->dso, md->type); 10858e0cf965SAdrian Hunter if (map == NULL) 10868e0cf965SAdrian Hunter return -ENOMEM; 10878e0cf965SAdrian Hunter 10888e0cf965SAdrian Hunter map->end = map->start + len; 10898e0cf965SAdrian Hunter map->pgoff = pgoff; 10908e0cf965SAdrian Hunter 10918e0cf965SAdrian Hunter list_add(&map->node, &md->maps); 10928e0cf965SAdrian Hunter 10938e0cf965SAdrian Hunter return 0; 10948e0cf965SAdrian Hunter } 10958e0cf965SAdrian Hunter 10968e0cf965SAdrian Hunter static int dso__load_kcore(struct dso *dso, struct map *map, 10978e0cf965SAdrian Hunter const char *kallsyms_filename) 10988e0cf965SAdrian Hunter { 1099ba92732eSWang Nan struct map_groups *kmaps = map__kmaps(map); 1100ba92732eSWang Nan struct machine *machine; 11018e0cf965SAdrian Hunter struct kcore_mapfn_data md; 11028e0cf965SAdrian Hunter struct map *old_map, *new_map, *replacement_map = NULL; 11038e0cf965SAdrian Hunter bool is_64_bit; 11048e0cf965SAdrian Hunter int err, fd; 11058e0cf965SAdrian Hunter char kcore_filename[PATH_MAX]; 11068e0cf965SAdrian Hunter struct symbol *sym; 11078e0cf965SAdrian Hunter 1108ba92732eSWang Nan if (!kmaps) 1109ba92732eSWang Nan return -EINVAL; 1110ba92732eSWang Nan 1111ba92732eSWang Nan machine = kmaps->machine; 1112ba92732eSWang Nan 11138e0cf965SAdrian Hunter /* This function requires that the map is the kernel map */ 11148e0cf965SAdrian Hunter if (map != machine->vmlinux_maps[map->type]) 11158e0cf965SAdrian Hunter return -EINVAL; 11168e0cf965SAdrian Hunter 111752afdaf9SAdrian Hunter if (!filename_from_kallsyms_filename(kcore_filename, "kcore", 11188e0cf965SAdrian Hunter kallsyms_filename)) 11198e0cf965SAdrian Hunter return -EINVAL; 11208e0cf965SAdrian Hunter 1121a00d28cbSAdrian Hunter /* Modules and kernel must be present at their original addresses */ 1122a00d28cbSAdrian Hunter if (validate_kcore_addresses(kallsyms_filename, map)) 112352afdaf9SAdrian Hunter return -EINVAL; 112452afdaf9SAdrian Hunter 11258e0cf965SAdrian Hunter md.dso = dso; 11268e0cf965SAdrian Hunter md.type = map->type; 11278e0cf965SAdrian Hunter INIT_LIST_HEAD(&md.maps); 11288e0cf965SAdrian Hunter 11298e0cf965SAdrian Hunter fd = open(kcore_filename, O_RDONLY); 11308e0cf965SAdrian Hunter if (fd < 0) 11318e0cf965SAdrian Hunter return -EINVAL; 11328e0cf965SAdrian Hunter 11338e0cf965SAdrian Hunter /* Read new maps into temporary lists */ 11348e0cf965SAdrian Hunter err = file__read_maps(fd, md.type == MAP__FUNCTION, kcore_mapfn, &md, 11358e0cf965SAdrian Hunter &is_64_bit); 11368e0cf965SAdrian Hunter if (err) 11378e0cf965SAdrian Hunter goto out_err; 1138c6d8f2a4SAdrian Hunter dso->is_64_bit = is_64_bit; 11398e0cf965SAdrian Hunter 11408e0cf965SAdrian Hunter if (list_empty(&md.maps)) { 11418e0cf965SAdrian Hunter err = -EINVAL; 11428e0cf965SAdrian Hunter goto out_err; 11438e0cf965SAdrian Hunter } 11448e0cf965SAdrian Hunter 11458e0cf965SAdrian Hunter /* Remove old maps */ 11468e0cf965SAdrian Hunter old_map = map_groups__first(kmaps, map->type); 11478e0cf965SAdrian Hunter while (old_map) { 11488e0cf965SAdrian Hunter struct map *next = map_groups__next(old_map); 11498e0cf965SAdrian Hunter 11508e0cf965SAdrian Hunter if (old_map != map) 11518e0cf965SAdrian Hunter map_groups__remove(kmaps, old_map); 11528e0cf965SAdrian Hunter old_map = next; 11538e0cf965SAdrian Hunter } 11548e0cf965SAdrian Hunter 11558e0cf965SAdrian Hunter /* Find the kernel map using the first symbol */ 11568e0cf965SAdrian Hunter sym = dso__first_symbol(dso, map->type); 11578e0cf965SAdrian Hunter list_for_each_entry(new_map, &md.maps, node) { 11588e0cf965SAdrian Hunter if (sym && sym->start >= new_map->start && 11598e0cf965SAdrian Hunter sym->start < new_map->end) { 11608e0cf965SAdrian Hunter replacement_map = new_map; 11618e0cf965SAdrian Hunter break; 11628e0cf965SAdrian Hunter } 11638e0cf965SAdrian Hunter } 11648e0cf965SAdrian Hunter 11658e0cf965SAdrian Hunter if (!replacement_map) 11668e0cf965SAdrian Hunter replacement_map = list_entry(md.maps.next, struct map, node); 11678e0cf965SAdrian Hunter 11688e0cf965SAdrian Hunter /* Add new maps */ 11698e0cf965SAdrian Hunter while (!list_empty(&md.maps)) { 11708e0cf965SAdrian Hunter new_map = list_entry(md.maps.next, struct map, node); 11718e0cf965SAdrian Hunter list_del(&new_map->node); 11728e0cf965SAdrian Hunter if (new_map == replacement_map) { 11738e0cf965SAdrian Hunter map->start = new_map->start; 11748e0cf965SAdrian Hunter map->end = new_map->end; 11758e0cf965SAdrian Hunter map->pgoff = new_map->pgoff; 11768e0cf965SAdrian Hunter map->map_ip = new_map->map_ip; 11778e0cf965SAdrian Hunter map->unmap_ip = new_map->unmap_ip; 11788e0cf965SAdrian Hunter map__delete(new_map); 11798e0cf965SAdrian Hunter /* Ensure maps are correctly ordered */ 11808e0cf965SAdrian Hunter map_groups__remove(kmaps, map); 11818e0cf965SAdrian Hunter map_groups__insert(kmaps, map); 11828e0cf965SAdrian Hunter } else { 11838e0cf965SAdrian Hunter map_groups__insert(kmaps, new_map); 11848e0cf965SAdrian Hunter } 11858e0cf965SAdrian Hunter } 11868e0cf965SAdrian Hunter 11878e0cf965SAdrian Hunter /* 11888e0cf965SAdrian Hunter * Set the data type and long name so that kcore can be read via 11898e0cf965SAdrian Hunter * dso__data_read_addr(). 11908e0cf965SAdrian Hunter */ 11918e0cf965SAdrian Hunter if (dso->kernel == DSO_TYPE_GUEST_KERNEL) 11925f70619dSArnaldo Carvalho de Melo dso->binary_type = DSO_BINARY_TYPE__GUEST_KCORE; 11938e0cf965SAdrian Hunter else 11945f70619dSArnaldo Carvalho de Melo dso->binary_type = DSO_BINARY_TYPE__KCORE; 11957e155d4dSArnaldo Carvalho de Melo dso__set_long_name(dso, strdup(kcore_filename), true); 11968e0cf965SAdrian Hunter 11978e0cf965SAdrian Hunter close(fd); 11988e0cf965SAdrian Hunter 11998e0cf965SAdrian Hunter if (map->type == MAP__FUNCTION) 12008e0cf965SAdrian Hunter pr_debug("Using %s for kernel object code\n", kcore_filename); 12018e0cf965SAdrian Hunter else 12028e0cf965SAdrian Hunter pr_debug("Using %s for kernel data\n", kcore_filename); 12038e0cf965SAdrian Hunter 12048e0cf965SAdrian Hunter return 0; 12058e0cf965SAdrian Hunter 12068e0cf965SAdrian Hunter out_err: 12078e0cf965SAdrian Hunter while (!list_empty(&md.maps)) { 12088e0cf965SAdrian Hunter map = list_entry(md.maps.next, struct map, node); 12098e0cf965SAdrian Hunter list_del(&map->node); 12108e0cf965SAdrian Hunter map__delete(map); 12118e0cf965SAdrian Hunter } 12128e0cf965SAdrian Hunter close(fd); 12138e0cf965SAdrian Hunter return -EINVAL; 12148e0cf965SAdrian Hunter } 12158e0cf965SAdrian Hunter 1216d9b62abaSAdrian Hunter /* 1217d9b62abaSAdrian Hunter * If the kernel is relocated at boot time, kallsyms won't match. Compute the 1218d9b62abaSAdrian Hunter * delta based on the relocation reference symbol. 1219d9b62abaSAdrian Hunter */ 1220d9b62abaSAdrian Hunter static int kallsyms__delta(struct map *map, const char *filename, u64 *delta) 1221d9b62abaSAdrian Hunter { 1222d9b62abaSAdrian Hunter struct kmap *kmap = map__kmap(map); 1223d9b62abaSAdrian Hunter u64 addr; 1224d9b62abaSAdrian Hunter 1225ba92732eSWang Nan if (!kmap) 1226ba92732eSWang Nan return -1; 1227ba92732eSWang Nan 1228d9b62abaSAdrian Hunter if (!kmap->ref_reloc_sym || !kmap->ref_reloc_sym->name) 1229d9b62abaSAdrian Hunter return 0; 1230d9b62abaSAdrian Hunter 1231d9b62abaSAdrian Hunter addr = kallsyms__get_function_start(filename, 1232d9b62abaSAdrian Hunter kmap->ref_reloc_sym->name); 1233d9b62abaSAdrian Hunter if (!addr) 1234d9b62abaSAdrian Hunter return -1; 1235d9b62abaSAdrian Hunter 1236d9b62abaSAdrian Hunter *delta = addr - kmap->ref_reloc_sym->addr; 1237d9b62abaSAdrian Hunter return 0; 1238d9b62abaSAdrian Hunter } 1239d9b62abaSAdrian Hunter 1240aeafcbafSArnaldo Carvalho de Melo int dso__load_kallsyms(struct dso *dso, const char *filename, 12419de89fe7SArnaldo Carvalho de Melo struct map *map, symbol_filter_t filter) 12422e538c4aSArnaldo Carvalho de Melo { 1243d9b62abaSAdrian Hunter u64 delta = 0; 1244d9b62abaSAdrian Hunter 1245ec80fde7SArnaldo Carvalho de Melo if (symbol__restricted_filename(filename, "/proc/kallsyms")) 1246ec80fde7SArnaldo Carvalho de Melo return -1; 1247ec80fde7SArnaldo Carvalho de Melo 1248aeafcbafSArnaldo Carvalho de Melo if (dso__load_all_kallsyms(dso, filename, map) < 0) 12492e538c4aSArnaldo Carvalho de Melo return -1; 12502e538c4aSArnaldo Carvalho de Melo 1251d9b62abaSAdrian Hunter if (kallsyms__delta(map, filename, &delta)) 1252d9b62abaSAdrian Hunter return -1; 1253d9b62abaSAdrian Hunter 1254694bf407SAnton Blanchard symbols__fixup_duplicate(&dso->symbols[map->type]); 12553f5a4272SAnton Blanchard symbols__fixup_end(&dso->symbols[map->type]); 12563f5a4272SAnton Blanchard 1257aeafcbafSArnaldo Carvalho de Melo if (dso->kernel == DSO_TYPE_GUEST_KERNEL) 125844f24cb3SJiri Olsa dso->symtab_type = DSO_BINARY_TYPE__GUEST_KALLSYMS; 1259a1645ce1SZhang, Yanmin else 126044f24cb3SJiri Olsa dso->symtab_type = DSO_BINARY_TYPE__KALLSYMS; 12612e538c4aSArnaldo Carvalho de Melo 12628e0cf965SAdrian Hunter if (!dso__load_kcore(dso, map, filename)) 12638e0cf965SAdrian Hunter return dso__split_kallsyms_for_kcore(dso, map, filter); 12648e0cf965SAdrian Hunter else 1265d9b62abaSAdrian Hunter return dso__split_kallsyms(dso, map, delta, filter); 1266af427bf5SArnaldo Carvalho de Melo } 1267af427bf5SArnaldo Carvalho de Melo 1268aeafcbafSArnaldo Carvalho de Melo static int dso__load_perf_map(struct dso *dso, struct map *map, 12696beba7adSArnaldo Carvalho de Melo symbol_filter_t filter) 127080d496beSPekka Enberg { 127180d496beSPekka Enberg char *line = NULL; 127280d496beSPekka Enberg size_t n; 127380d496beSPekka Enberg FILE *file; 127480d496beSPekka Enberg int nr_syms = 0; 127580d496beSPekka Enberg 1276aeafcbafSArnaldo Carvalho de Melo file = fopen(dso->long_name, "r"); 127780d496beSPekka Enberg if (file == NULL) 127880d496beSPekka Enberg goto out_failure; 127980d496beSPekka Enberg 128080d496beSPekka Enberg while (!feof(file)) { 12819cffa8d5SPaul Mackerras u64 start, size; 128280d496beSPekka Enberg struct symbol *sym; 128380d496beSPekka Enberg int line_len, len; 128480d496beSPekka Enberg 128580d496beSPekka Enberg line_len = getline(&line, &n, file); 128680d496beSPekka Enberg if (line_len < 0) 128780d496beSPekka Enberg break; 128880d496beSPekka Enberg 128980d496beSPekka Enberg if (!line) 129080d496beSPekka Enberg goto out_failure; 129180d496beSPekka Enberg 129280d496beSPekka Enberg line[--line_len] = '\0'; /* \n */ 129380d496beSPekka Enberg 129480d496beSPekka Enberg len = hex2u64(line, &start); 129580d496beSPekka Enberg 129680d496beSPekka Enberg len++; 129780d496beSPekka Enberg if (len + 2 >= line_len) 129880d496beSPekka Enberg continue; 129980d496beSPekka Enberg 130080d496beSPekka Enberg len += hex2u64(line + len, &size); 130180d496beSPekka Enberg 130280d496beSPekka Enberg len++; 130380d496beSPekka Enberg if (len + 2 >= line_len) 130480d496beSPekka Enberg continue; 130580d496beSPekka Enberg 1306c408fedfSArnaldo Carvalho de Melo sym = symbol__new(start, size, STB_GLOBAL, line + len); 130780d496beSPekka Enberg 130880d496beSPekka Enberg if (sym == NULL) 130980d496beSPekka Enberg goto out_delete_line; 131080d496beSPekka Enberg 1311439d473bSArnaldo Carvalho de Melo if (filter && filter(map, sym)) 131200a192b3SArnaldo Carvalho de Melo symbol__delete(sym); 131380d496beSPekka Enberg else { 1314aeafcbafSArnaldo Carvalho de Melo symbols__insert(&dso->symbols[map->type], sym); 131580d496beSPekka Enberg nr_syms++; 131680d496beSPekka Enberg } 131780d496beSPekka Enberg } 131880d496beSPekka Enberg 131980d496beSPekka Enberg free(line); 132080d496beSPekka Enberg fclose(file); 132180d496beSPekka Enberg 132280d496beSPekka Enberg return nr_syms; 132380d496beSPekka Enberg 132480d496beSPekka Enberg out_delete_line: 132580d496beSPekka Enberg free(line); 132680d496beSPekka Enberg out_failure: 132780d496beSPekka Enberg return -1; 132880d496beSPekka Enberg } 132980d496beSPekka Enberg 13301029f9feSNamhyung Kim static bool dso__is_compatible_symtab_type(struct dso *dso, bool kmod, 13311029f9feSNamhyung Kim enum dso_binary_type type) 13321029f9feSNamhyung Kim { 13331029f9feSNamhyung Kim switch (type) { 13341029f9feSNamhyung Kim case DSO_BINARY_TYPE__JAVA_JIT: 13351029f9feSNamhyung Kim case DSO_BINARY_TYPE__DEBUGLINK: 13361029f9feSNamhyung Kim case DSO_BINARY_TYPE__SYSTEM_PATH_DSO: 13371029f9feSNamhyung Kim case DSO_BINARY_TYPE__FEDORA_DEBUGINFO: 13381029f9feSNamhyung Kim case DSO_BINARY_TYPE__UBUNTU_DEBUGINFO: 13391029f9feSNamhyung Kim case DSO_BINARY_TYPE__BUILDID_DEBUGINFO: 13401029f9feSNamhyung Kim case DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO: 13411029f9feSNamhyung Kim return !kmod && dso->kernel == DSO_TYPE_USER; 13421029f9feSNamhyung Kim 13431029f9feSNamhyung Kim case DSO_BINARY_TYPE__KALLSYMS: 13441029f9feSNamhyung Kim case DSO_BINARY_TYPE__VMLINUX: 13451029f9feSNamhyung Kim case DSO_BINARY_TYPE__KCORE: 13461029f9feSNamhyung Kim return dso->kernel == DSO_TYPE_KERNEL; 13471029f9feSNamhyung Kim 13481029f9feSNamhyung Kim case DSO_BINARY_TYPE__GUEST_KALLSYMS: 13491029f9feSNamhyung Kim case DSO_BINARY_TYPE__GUEST_VMLINUX: 13501029f9feSNamhyung Kim case DSO_BINARY_TYPE__GUEST_KCORE: 13511029f9feSNamhyung Kim return dso->kernel == DSO_TYPE_GUEST_KERNEL; 13521029f9feSNamhyung Kim 13531029f9feSNamhyung Kim case DSO_BINARY_TYPE__GUEST_KMODULE: 1354c00c48fcSNamhyung Kim case DSO_BINARY_TYPE__GUEST_KMODULE_COMP: 13551029f9feSNamhyung Kim case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE: 1356c00c48fcSNamhyung Kim case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP: 13571029f9feSNamhyung Kim /* 13581029f9feSNamhyung Kim * kernel modules know their symtab type - it's set when 13591029f9feSNamhyung Kim * creating a module dso in machine__new_module(). 13601029f9feSNamhyung Kim */ 13611029f9feSNamhyung Kim return kmod && dso->symtab_type == type; 13621029f9feSNamhyung Kim 13631029f9feSNamhyung Kim case DSO_BINARY_TYPE__BUILD_ID_CACHE: 13641029f9feSNamhyung Kim return true; 13651029f9feSNamhyung Kim 13661029f9feSNamhyung Kim case DSO_BINARY_TYPE__NOT_FOUND: 13671029f9feSNamhyung Kim default: 13681029f9feSNamhyung Kim return false; 13691029f9feSNamhyung Kim } 13701029f9feSNamhyung Kim } 13711029f9feSNamhyung Kim 1372aeafcbafSArnaldo Carvalho de Melo int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter) 137386470930SIngo Molnar { 1374c338aee8SArnaldo Carvalho de Melo char *name; 137586470930SIngo Molnar int ret = -1; 137644f24cb3SJiri Olsa u_int i; 137723346f21SArnaldo Carvalho de Melo struct machine *machine; 137844f24cb3SJiri Olsa char *root_dir = (char *) ""; 13793aafe5aeSCody P Schafer int ss_pos = 0; 13803aafe5aeSCody P Schafer struct symsrc ss_[2]; 13813aafe5aeSCody P Schafer struct symsrc *syms_ss = NULL, *runtime_ss = NULL; 13821029f9feSNamhyung Kim bool kmod; 138386470930SIngo Molnar 13844a936edcSNamhyung Kim pthread_mutex_lock(&dso->lock); 138566bd8424SArnaldo Carvalho de Melo 13864a936edcSNamhyung Kim /* check again under the dso->lock */ 13874a936edcSNamhyung Kim if (dso__loaded(dso, map->type)) { 13884a936edcSNamhyung Kim ret = 1; 13894a936edcSNamhyung Kim goto out; 13904a936edcSNamhyung Kim } 13914a936edcSNamhyung Kim 13924a936edcSNamhyung Kim if (dso->kernel) { 1393aeafcbafSArnaldo Carvalho de Melo if (dso->kernel == DSO_TYPE_KERNEL) 13944a936edcSNamhyung Kim ret = dso__load_kernel_sym(dso, map, filter); 1395aeafcbafSArnaldo Carvalho de Melo else if (dso->kernel == DSO_TYPE_GUEST_KERNEL) 13964a936edcSNamhyung Kim ret = dso__load_guest_kernel_sym(dso, map, filter); 13974a936edcSNamhyung Kim 13984a936edcSNamhyung Kim goto out; 13994a936edcSNamhyung Kim } 1400a1645ce1SZhang, Yanmin 140123346f21SArnaldo Carvalho de Melo if (map->groups && map->groups->machine) 140223346f21SArnaldo Carvalho de Melo machine = map->groups->machine; 1403a1645ce1SZhang, Yanmin else 140423346f21SArnaldo Carvalho de Melo machine = NULL; 1405c338aee8SArnaldo Carvalho de Melo 1406aeafcbafSArnaldo Carvalho de Melo dso->adjust_symbols = 0; 1407f5812a7aSArnaldo Carvalho de Melo 1408aeafcbafSArnaldo Carvalho de Melo if (strncmp(dso->name, "/tmp/perf-", 10) == 0) { 1409981c1252SPekka Enberg struct stat st; 1410981c1252SPekka Enberg 1411e9b52ef2SVasiliy Kulikov if (lstat(dso->name, &st) < 0) 14124a936edcSNamhyung Kim goto out; 1413981c1252SPekka Enberg 1414981c1252SPekka Enberg if (st.st_uid && (st.st_uid != geteuid())) { 1415981c1252SPekka Enberg pr_warning("File %s not owned by current user or root, " 1416981c1252SPekka Enberg "ignoring it.\n", dso->name); 14174a936edcSNamhyung Kim goto out; 1418981c1252SPekka Enberg } 1419981c1252SPekka Enberg 1420aeafcbafSArnaldo Carvalho de Melo ret = dso__load_perf_map(dso, map, filter); 142144f24cb3SJiri Olsa dso->symtab_type = ret > 0 ? DSO_BINARY_TYPE__JAVA_JIT : 142244f24cb3SJiri Olsa DSO_BINARY_TYPE__NOT_FOUND; 14234a936edcSNamhyung Kim goto out; 142494cb9e38SArnaldo Carvalho de Melo } 142594cb9e38SArnaldo Carvalho de Melo 142644f24cb3SJiri Olsa if (machine) 142744f24cb3SJiri Olsa root_dir = machine->root_dir; 142844f24cb3SJiri Olsa 1429164c800eSDavid Ahern name = malloc(PATH_MAX); 1430164c800eSDavid Ahern if (!name) 14314a936edcSNamhyung Kim goto out; 1432164c800eSDavid Ahern 14331029f9feSNamhyung Kim kmod = dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE || 1434c00c48fcSNamhyung Kim dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP || 1435c00c48fcSNamhyung Kim dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE || 1436c00c48fcSNamhyung Kim dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE_COMP; 14371029f9feSNamhyung Kim 14381029f9feSNamhyung Kim /* 14391029f9feSNamhyung Kim * Iterate over candidate debug images. 14403aafe5aeSCody P Schafer * Keep track of "interesting" ones (those which have a symtab, dynsym, 14413aafe5aeSCody P Schafer * and/or opd section) for processing. 14426da80ce8SDave Martin */ 144344f24cb3SJiri Olsa for (i = 0; i < DSO_BINARY_TYPE__SYMTAB_CNT; i++) { 14443aafe5aeSCody P Schafer struct symsrc *ss = &ss_[ss_pos]; 14453aafe5aeSCody P Schafer bool next_slot = false; 144644f24cb3SJiri Olsa 1447005f9294SCody P Schafer enum dso_binary_type symtab_type = binary_type_symtab[i]; 144844f24cb3SJiri Olsa 14491029f9feSNamhyung Kim if (!dso__is_compatible_symtab_type(dso, kmod, symtab_type)) 14501029f9feSNamhyung Kim continue; 14511029f9feSNamhyung Kim 1452ee4e9625SArnaldo Carvalho de Melo if (dso__read_binary_type_filename(dso, symtab_type, 145344f24cb3SJiri Olsa root_dir, name, PATH_MAX)) 14546da80ce8SDave Martin continue; 145586470930SIngo Molnar 14566da80ce8SDave Martin /* Name is now the name of the next image to try */ 14573aafe5aeSCody P Schafer if (symsrc__init(ss, dso, name, symtab_type) < 0) 14586da80ce8SDave Martin continue; 14596da80ce8SDave Martin 14603aafe5aeSCody P Schafer if (!syms_ss && symsrc__has_symtab(ss)) { 14613aafe5aeSCody P Schafer syms_ss = ss; 14623aafe5aeSCody P Schafer next_slot = true; 14630058aef6SAdrian Hunter if (!dso->symsrc_filename) 14640058aef6SAdrian Hunter dso->symsrc_filename = strdup(name); 1465d26cd12bSCody P Schafer } 1466d26cd12bSCody P Schafer 14673aafe5aeSCody P Schafer if (!runtime_ss && symsrc__possibly_runtime(ss)) { 14683aafe5aeSCody P Schafer runtime_ss = ss; 14693aafe5aeSCody P Schafer next_slot = true; 1470a44f605bSCody P Schafer } 147186470930SIngo Molnar 14723aafe5aeSCody P Schafer if (next_slot) { 14733aafe5aeSCody P Schafer ss_pos++; 147433ff581eSJiri Olsa 14753aafe5aeSCody P Schafer if (syms_ss && runtime_ss) 14766da80ce8SDave Martin break; 147798e9f03bSNamhyung Kim } else { 147898e9f03bSNamhyung Kim symsrc__destroy(ss); 1479a25e46c4SArnaldo Carvalho de Melo } 14803aafe5aeSCody P Schafer 14816da80ce8SDave Martin } 14826da80ce8SDave Martin 14833aafe5aeSCody P Schafer if (!runtime_ss && !syms_ss) 14843aafe5aeSCody P Schafer goto out_free; 14853aafe5aeSCody P Schafer 14863aafe5aeSCody P Schafer if (runtime_ss && !syms_ss) { 14873aafe5aeSCody P Schafer syms_ss = runtime_ss; 148860e4b10cSArnaldo Carvalho de Melo } 148960e4b10cSArnaldo Carvalho de Melo 14903aafe5aeSCody P Schafer /* We'll have to hope for the best */ 14913aafe5aeSCody P Schafer if (!runtime_ss && syms_ss) 14923aafe5aeSCody P Schafer runtime_ss = syms_ss; 14933aafe5aeSCody P Schafer 14941029f9feSNamhyung Kim if (syms_ss) 14951029f9feSNamhyung Kim ret = dso__load_sym(dso, map, syms_ss, runtime_ss, filter, kmod); 14961029f9feSNamhyung Kim else 14973aafe5aeSCody P Schafer ret = -1; 14983aafe5aeSCody P Schafer 1499f47b58b7SDavid Ahern if (ret > 0) { 15003aafe5aeSCody P Schafer int nr_plt; 15013aafe5aeSCody P Schafer 15023aafe5aeSCody P Schafer nr_plt = dso__synthesize_plt_symbols(dso, runtime_ss, map, filter); 15033aafe5aeSCody P Schafer if (nr_plt > 0) 15043aafe5aeSCody P Schafer ret += nr_plt; 15053aafe5aeSCody P Schafer } 15063aafe5aeSCody P Schafer 15073aafe5aeSCody P Schafer for (; ss_pos > 0; ss_pos--) 15083aafe5aeSCody P Schafer symsrc__destroy(&ss_[ss_pos - 1]); 15093aafe5aeSCody P Schafer out_free: 151086470930SIngo Molnar free(name); 1511aeafcbafSArnaldo Carvalho de Melo if (ret < 0 && strstr(dso->name, " (deleted)") != NULL) 15124a936edcSNamhyung Kim ret = 0; 15134a936edcSNamhyung Kim out: 15144a936edcSNamhyung Kim dso__set_loaded(dso, map->type); 15154a936edcSNamhyung Kim pthread_mutex_unlock(&dso->lock); 15164a936edcSNamhyung Kim 151786470930SIngo Molnar return ret; 151886470930SIngo Molnar } 151986470930SIngo Molnar 1520aeafcbafSArnaldo Carvalho de Melo struct map *map_groups__find_by_name(struct map_groups *mg, 152179406cd7SArnaldo Carvalho de Melo enum map_type type, const char *name) 1522439d473bSArnaldo Carvalho de Melo { 1523*1eee78aeSArnaldo Carvalho de Melo struct maps *maps = &mg->maps[type]; 15244bb7123dSArnaldo Carvalho de Melo struct map *map; 1525439d473bSArnaldo Carvalho de Melo 15264bb7123dSArnaldo Carvalho de Melo for (map = maps__first(maps); map; map = map__next(map)) { 1527b7cece76SArnaldo Carvalho de Melo if (map->dso && strcmp(map->dso->short_name, name) == 0) 1528439d473bSArnaldo Carvalho de Melo return map; 1529439d473bSArnaldo Carvalho de Melo } 1530439d473bSArnaldo Carvalho de Melo 1531439d473bSArnaldo Carvalho de Melo return NULL; 1532439d473bSArnaldo Carvalho de Melo } 1533439d473bSArnaldo Carvalho de Melo 1534aeafcbafSArnaldo Carvalho de Melo int dso__load_vmlinux(struct dso *dso, struct map *map, 15355230fb7dSArnaldo Carvalho de Melo const char *vmlinux, bool vmlinux_allocated, 15365230fb7dSArnaldo Carvalho de Melo symbol_filter_t filter) 153786470930SIngo Molnar { 1538b68e2f91SCody P Schafer int err = -1; 1539b68e2f91SCody P Schafer struct symsrc ss; 1540ec5761eaSDavid Ahern char symfs_vmlinux[PATH_MAX]; 1541005f9294SCody P Schafer enum dso_binary_type symtab_type; 154286470930SIngo Molnar 15435698d2c9SNamhyung Kim if (vmlinux[0] == '/') 15445698d2c9SNamhyung Kim snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s", vmlinux); 15455698d2c9SNamhyung Kim else 1546972f393bSArnaldo Carvalho de Melo symbol__join_symfs(symfs_vmlinux, vmlinux); 154786470930SIngo Molnar 154821ea4539SCody P Schafer if (dso->kernel == DSO_TYPE_GUEST_KERNEL) 1549005f9294SCody P Schafer symtab_type = DSO_BINARY_TYPE__GUEST_VMLINUX; 155021ea4539SCody P Schafer else 1551005f9294SCody P Schafer symtab_type = DSO_BINARY_TYPE__VMLINUX; 155221ea4539SCody P Schafer 1553005f9294SCody P Schafer if (symsrc__init(&ss, dso, symfs_vmlinux, symtab_type)) 1554b68e2f91SCody P Schafer return -1; 1555b68e2f91SCody P Schafer 1556261360b6SCody P Schafer err = dso__load_sym(dso, map, &ss, &ss, filter, 0); 1557b68e2f91SCody P Schafer symsrc__destroy(&ss); 155886470930SIngo Molnar 1559515850e4SCody P Schafer if (err > 0) { 156039b12f78SAdrian Hunter if (dso->kernel == DSO_TYPE_GUEST_KERNEL) 15615f70619dSArnaldo Carvalho de Melo dso->binary_type = DSO_BINARY_TYPE__GUEST_VMLINUX; 156239b12f78SAdrian Hunter else 15635f70619dSArnaldo Carvalho de Melo dso->binary_type = DSO_BINARY_TYPE__VMLINUX; 1564bf4414aeSArnaldo Carvalho de Melo dso__set_long_name(dso, vmlinux, vmlinux_allocated); 1565515850e4SCody P Schafer dso__set_loaded(dso, map->type); 1566ec5761eaSDavid Ahern pr_debug("Using %s for symbols\n", symfs_vmlinux); 1567515850e4SCody P Schafer } 15683846df2eSArnaldo Carvalho de Melo 156986470930SIngo Molnar return err; 157086470930SIngo Molnar } 157186470930SIngo Molnar 1572aeafcbafSArnaldo Carvalho de Melo int dso__load_vmlinux_path(struct dso *dso, struct map *map, 15739de89fe7SArnaldo Carvalho de Melo symbol_filter_t filter) 1574a19afe46SArnaldo Carvalho de Melo { 1575a19afe46SArnaldo Carvalho de Melo int i, err = 0; 157600dc8657SNamhyung Kim char *filename = NULL; 1577a19afe46SArnaldo Carvalho de Melo 157800dc8657SNamhyung Kim if (!symbol_conf.ignore_vmlinux_buildid) 1579aeafcbafSArnaldo Carvalho de Melo filename = dso__build_id_filename(dso, NULL, 0); 15805ad90e4eSArnaldo Carvalho de Melo if (filename != NULL) { 15815230fb7dSArnaldo Carvalho de Melo err = dso__load_vmlinux(dso, map, filename, true, filter); 15825230fb7dSArnaldo Carvalho de Melo if (err > 0) 15835ad90e4eSArnaldo Carvalho de Melo goto out; 15845ad90e4eSArnaldo Carvalho de Melo free(filename); 15855ad90e4eSArnaldo Carvalho de Melo } 1586a19afe46SArnaldo Carvalho de Melo 158700dc8657SNamhyung Kim pr_debug("Looking at the vmlinux_path (%d entries long)\n", 158800dc8657SNamhyung Kim vmlinux_path__nr_entries + 1); 158900dc8657SNamhyung Kim 1590a19afe46SArnaldo Carvalho de Melo for (i = 0; i < vmlinux_path__nr_entries; ++i) { 15915230fb7dSArnaldo Carvalho de Melo err = dso__load_vmlinux(dso, map, vmlinux_path[i], false, filter); 15925230fb7dSArnaldo Carvalho de Melo if (err > 0) 1593a19afe46SArnaldo Carvalho de Melo break; 1594a19afe46SArnaldo Carvalho de Melo } 15955ad90e4eSArnaldo Carvalho de Melo out: 1596a19afe46SArnaldo Carvalho de Melo return err; 1597a19afe46SArnaldo Carvalho de Melo } 1598a19afe46SArnaldo Carvalho de Melo 15990544d422SAdrian Hunter static int find_matching_kcore(struct map *map, char *dir, size_t dir_sz) 16000544d422SAdrian Hunter { 16010544d422SAdrian Hunter char kallsyms_filename[PATH_MAX]; 16020544d422SAdrian Hunter struct dirent *dent; 16030544d422SAdrian Hunter int ret = -1; 16040544d422SAdrian Hunter DIR *d; 16050544d422SAdrian Hunter 16060544d422SAdrian Hunter d = opendir(dir); 16070544d422SAdrian Hunter if (!d) 16080544d422SAdrian Hunter return -1; 16090544d422SAdrian Hunter 16100544d422SAdrian Hunter while (1) { 16110544d422SAdrian Hunter dent = readdir(d); 16120544d422SAdrian Hunter if (!dent) 16130544d422SAdrian Hunter break; 16140544d422SAdrian Hunter if (dent->d_type != DT_DIR) 16150544d422SAdrian Hunter continue; 16160544d422SAdrian Hunter scnprintf(kallsyms_filename, sizeof(kallsyms_filename), 16170544d422SAdrian Hunter "%s/%s/kallsyms", dir, dent->d_name); 1618a00d28cbSAdrian Hunter if (!validate_kcore_addresses(kallsyms_filename, map)) { 16190544d422SAdrian Hunter strlcpy(dir, kallsyms_filename, dir_sz); 16200544d422SAdrian Hunter ret = 0; 16210544d422SAdrian Hunter break; 16220544d422SAdrian Hunter } 16230544d422SAdrian Hunter } 16240544d422SAdrian Hunter 16250544d422SAdrian Hunter closedir(d); 16260544d422SAdrian Hunter 16270544d422SAdrian Hunter return ret; 16280544d422SAdrian Hunter } 16290544d422SAdrian Hunter 16300544d422SAdrian Hunter static char *dso__find_kallsyms(struct dso *dso, struct map *map) 16310544d422SAdrian Hunter { 16320544d422SAdrian Hunter u8 host_build_id[BUILD_ID_SIZE]; 16330544d422SAdrian Hunter char sbuild_id[BUILD_ID_SIZE * 2 + 1]; 16340544d422SAdrian Hunter bool is_host = false; 16350544d422SAdrian Hunter char path[PATH_MAX]; 16360544d422SAdrian Hunter 16370544d422SAdrian Hunter if (!dso->has_build_id) { 16380544d422SAdrian Hunter /* 16390544d422SAdrian Hunter * Last resort, if we don't have a build-id and couldn't find 16400544d422SAdrian Hunter * any vmlinux file, try the running kernel kallsyms table. 16410544d422SAdrian Hunter */ 16420544d422SAdrian Hunter goto proc_kallsyms; 16430544d422SAdrian Hunter } 16440544d422SAdrian Hunter 16450544d422SAdrian Hunter if (sysfs__read_build_id("/sys/kernel/notes", host_build_id, 16460544d422SAdrian Hunter sizeof(host_build_id)) == 0) 16470544d422SAdrian Hunter is_host = dso__build_id_equal(dso, host_build_id); 16480544d422SAdrian Hunter 16490544d422SAdrian Hunter build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id); 16500544d422SAdrian Hunter 1651449867e3SAdrian Hunter scnprintf(path, sizeof(path), "%s/[kernel.kcore]/%s", buildid_dir, 1652449867e3SAdrian Hunter sbuild_id); 1653449867e3SAdrian Hunter 16540544d422SAdrian Hunter /* Use /proc/kallsyms if possible */ 16550544d422SAdrian Hunter if (is_host) { 16560544d422SAdrian Hunter DIR *d; 16570544d422SAdrian Hunter int fd; 16580544d422SAdrian Hunter 16590544d422SAdrian Hunter /* If no cached kcore go with /proc/kallsyms */ 16600544d422SAdrian Hunter d = opendir(path); 16610544d422SAdrian Hunter if (!d) 16620544d422SAdrian Hunter goto proc_kallsyms; 16630544d422SAdrian Hunter closedir(d); 16640544d422SAdrian Hunter 16650544d422SAdrian Hunter /* 16660544d422SAdrian Hunter * Do not check the build-id cache, until we know we cannot use 16670544d422SAdrian Hunter * /proc/kcore. 16680544d422SAdrian Hunter */ 16690544d422SAdrian Hunter fd = open("/proc/kcore", O_RDONLY); 16700544d422SAdrian Hunter if (fd != -1) { 16710544d422SAdrian Hunter close(fd); 16720544d422SAdrian Hunter /* If module maps match go with /proc/kallsyms */ 1673a00d28cbSAdrian Hunter if (!validate_kcore_addresses("/proc/kallsyms", map)) 16740544d422SAdrian Hunter goto proc_kallsyms; 16750544d422SAdrian Hunter } 16760544d422SAdrian Hunter 16770544d422SAdrian Hunter /* Find kallsyms in build-id cache with kcore */ 16780544d422SAdrian Hunter if (!find_matching_kcore(map, path, sizeof(path))) 16790544d422SAdrian Hunter return strdup(path); 16800544d422SAdrian Hunter 16810544d422SAdrian Hunter goto proc_kallsyms; 16820544d422SAdrian Hunter } 16830544d422SAdrian Hunter 1684449867e3SAdrian Hunter /* Find kallsyms in build-id cache with kcore */ 1685449867e3SAdrian Hunter if (!find_matching_kcore(map, path, sizeof(path))) 1686449867e3SAdrian Hunter return strdup(path); 1687449867e3SAdrian Hunter 16880544d422SAdrian Hunter scnprintf(path, sizeof(path), "%s/[kernel.kallsyms]/%s", 16890544d422SAdrian Hunter buildid_dir, sbuild_id); 16900544d422SAdrian Hunter 16910544d422SAdrian Hunter if (access(path, F_OK)) { 16920544d422SAdrian Hunter pr_err("No kallsyms or vmlinux with build-id %s was found\n", 16930544d422SAdrian Hunter sbuild_id); 16940544d422SAdrian Hunter return NULL; 16950544d422SAdrian Hunter } 16960544d422SAdrian Hunter 16970544d422SAdrian Hunter return strdup(path); 16980544d422SAdrian Hunter 16990544d422SAdrian Hunter proc_kallsyms: 17000544d422SAdrian Hunter return strdup("/proc/kallsyms"); 17010544d422SAdrian Hunter } 17020544d422SAdrian Hunter 1703aeafcbafSArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *dso, struct map *map, 17049de89fe7SArnaldo Carvalho de Melo symbol_filter_t filter) 170586470930SIngo Molnar { 1706cc612d81SArnaldo Carvalho de Melo int err; 17079e201442SArnaldo Carvalho de Melo const char *kallsyms_filename = NULL; 17089e201442SArnaldo Carvalho de Melo char *kallsyms_allocated_filename = NULL; 1709dc8d6ab2SArnaldo Carvalho de Melo /* 1710b226a5a7SDavid Ahern * Step 1: if the user specified a kallsyms or vmlinux filename, use 1711b226a5a7SDavid Ahern * it and only it, reporting errors to the user if it cannot be used. 1712dc8d6ab2SArnaldo Carvalho de Melo * 1713dc8d6ab2SArnaldo Carvalho de Melo * For instance, try to analyse an ARM perf.data file _without_ a 1714dc8d6ab2SArnaldo Carvalho de Melo * build-id, or if the user specifies the wrong path to the right 1715dc8d6ab2SArnaldo Carvalho de Melo * vmlinux file, obviously we can't fallback to another vmlinux (a 1716dc8d6ab2SArnaldo Carvalho de Melo * x86_86 one, on the machine where analysis is being performed, say), 1717dc8d6ab2SArnaldo Carvalho de Melo * or worse, /proc/kallsyms. 1718dc8d6ab2SArnaldo Carvalho de Melo * 1719dc8d6ab2SArnaldo Carvalho de Melo * If the specified file _has_ a build-id and there is a build-id 1720dc8d6ab2SArnaldo Carvalho de Melo * section in the perf.data file, we will still do the expected 1721dc8d6ab2SArnaldo Carvalho de Melo * validation in dso__load_vmlinux and will bail out if they don't 1722dc8d6ab2SArnaldo Carvalho de Melo * match. 1723dc8d6ab2SArnaldo Carvalho de Melo */ 1724b226a5a7SDavid Ahern if (symbol_conf.kallsyms_name != NULL) { 1725b226a5a7SDavid Ahern kallsyms_filename = symbol_conf.kallsyms_name; 1726b226a5a7SDavid Ahern goto do_kallsyms; 1727b226a5a7SDavid Ahern } 1728b226a5a7SDavid Ahern 1729fc2be696SWilly Tarreau if (!symbol_conf.ignore_vmlinux && symbol_conf.vmlinux_name != NULL) { 17305230fb7dSArnaldo Carvalho de Melo return dso__load_vmlinux(dso, map, symbol_conf.vmlinux_name, 17315230fb7dSArnaldo Carvalho de Melo false, filter); 1732dc8d6ab2SArnaldo Carvalho de Melo } 1733439d473bSArnaldo Carvalho de Melo 1734fc2be696SWilly Tarreau if (!symbol_conf.ignore_vmlinux && vmlinux_path != NULL) { 1735aeafcbafSArnaldo Carvalho de Melo err = dso__load_vmlinux_path(dso, map, filter); 1736a19afe46SArnaldo Carvalho de Melo if (err > 0) 173739b12f78SAdrian Hunter return err; 1738cc612d81SArnaldo Carvalho de Melo } 1739cc612d81SArnaldo Carvalho de Melo 1740ec5761eaSDavid Ahern /* do not try local files if a symfs was given */ 1741ec5761eaSDavid Ahern if (symbol_conf.symfs[0] != 0) 1742ec5761eaSDavid Ahern return -1; 1743ec5761eaSDavid Ahern 17440544d422SAdrian Hunter kallsyms_allocated_filename = dso__find_kallsyms(dso, map); 17450544d422SAdrian Hunter if (!kallsyms_allocated_filename) 17468d0591f6SArnaldo Carvalho de Melo return -1; 17478d0591f6SArnaldo Carvalho de Melo 174819fc2dedSArnaldo Carvalho de Melo kallsyms_filename = kallsyms_allocated_filename; 174919fc2dedSArnaldo Carvalho de Melo 1750dc8d6ab2SArnaldo Carvalho de Melo do_kallsyms: 1751aeafcbafSArnaldo Carvalho de Melo err = dso__load_kallsyms(dso, kallsyms_filename, map, filter); 17523846df2eSArnaldo Carvalho de Melo if (err > 0) 17533846df2eSArnaldo Carvalho de Melo pr_debug("Using %s for symbols\n", kallsyms_filename); 1754dc8d6ab2SArnaldo Carvalho de Melo free(kallsyms_allocated_filename); 1755dc8d6ab2SArnaldo Carvalho de Melo 17568e0cf965SAdrian Hunter if (err > 0 && !dso__is_kcore(dso)) { 1757bdac0bcfSAdrian Hunter dso->binary_type = DSO_BINARY_TYPE__KALLSYMS; 1758bf4414aeSArnaldo Carvalho de Melo dso__set_long_name(dso, "[kernel.kallsyms]", false); 17596a4694a4SArnaldo Carvalho de Melo map__fixup_start(map); 17606a4694a4SArnaldo Carvalho de Melo map__fixup_end(map); 1761439d473bSArnaldo Carvalho de Melo } 176294cb9e38SArnaldo Carvalho de Melo 176386470930SIngo Molnar return err; 176486470930SIngo Molnar } 176586470930SIngo Molnar 1766aeafcbafSArnaldo Carvalho de Melo static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map, 1767a1645ce1SZhang, Yanmin symbol_filter_t filter) 1768a1645ce1SZhang, Yanmin { 1769a1645ce1SZhang, Yanmin int err; 1770a1645ce1SZhang, Yanmin const char *kallsyms_filename = NULL; 177123346f21SArnaldo Carvalho de Melo struct machine *machine; 1772a1645ce1SZhang, Yanmin char path[PATH_MAX]; 1773a1645ce1SZhang, Yanmin 1774a1645ce1SZhang, Yanmin if (!map->groups) { 1775a1645ce1SZhang, Yanmin pr_debug("Guest kernel map hasn't the point to groups\n"); 1776a1645ce1SZhang, Yanmin return -1; 1777a1645ce1SZhang, Yanmin } 177823346f21SArnaldo Carvalho de Melo machine = map->groups->machine; 1779a1645ce1SZhang, Yanmin 178023346f21SArnaldo Carvalho de Melo if (machine__is_default_guest(machine)) { 1781a1645ce1SZhang, Yanmin /* 1782a1645ce1SZhang, Yanmin * if the user specified a vmlinux filename, use it and only 1783a1645ce1SZhang, Yanmin * it, reporting errors to the user if it cannot be used. 1784a1645ce1SZhang, Yanmin * Or use file guest_kallsyms inputted by user on commandline 1785a1645ce1SZhang, Yanmin */ 1786a1645ce1SZhang, Yanmin if (symbol_conf.default_guest_vmlinux_name != NULL) { 1787aeafcbafSArnaldo Carvalho de Melo err = dso__load_vmlinux(dso, map, 17885230fb7dSArnaldo Carvalho de Melo symbol_conf.default_guest_vmlinux_name, 17895230fb7dSArnaldo Carvalho de Melo false, filter); 179039b12f78SAdrian Hunter return err; 1791a1645ce1SZhang, Yanmin } 1792a1645ce1SZhang, Yanmin 1793a1645ce1SZhang, Yanmin kallsyms_filename = symbol_conf.default_guest_kallsyms; 1794a1645ce1SZhang, Yanmin if (!kallsyms_filename) 1795a1645ce1SZhang, Yanmin return -1; 1796a1645ce1SZhang, Yanmin } else { 179723346f21SArnaldo Carvalho de Melo sprintf(path, "%s/proc/kallsyms", machine->root_dir); 1798a1645ce1SZhang, Yanmin kallsyms_filename = path; 1799a1645ce1SZhang, Yanmin } 1800a1645ce1SZhang, Yanmin 1801aeafcbafSArnaldo Carvalho de Melo err = dso__load_kallsyms(dso, kallsyms_filename, map, filter); 18028e0cf965SAdrian Hunter if (err > 0) 180339b12f78SAdrian Hunter pr_debug("Using %s for symbols\n", kallsyms_filename); 18048e0cf965SAdrian Hunter if (err > 0 && !dso__is_kcore(dso)) { 1805bdac0bcfSAdrian Hunter dso->binary_type = DSO_BINARY_TYPE__GUEST_KALLSYMS; 180648ea8f54SArnaldo Carvalho de Melo machine__mmap_name(machine, path, sizeof(path)); 18077e155d4dSArnaldo Carvalho de Melo dso__set_long_name(dso, strdup(path), true); 1808a1645ce1SZhang, Yanmin map__fixup_start(map); 1809a1645ce1SZhang, Yanmin map__fixup_end(map); 1810a1645ce1SZhang, Yanmin } 1811a1645ce1SZhang, Yanmin 1812a1645ce1SZhang, Yanmin return err; 1813a1645ce1SZhang, Yanmin } 1814cd84c2acSFrederic Weisbecker 1815cc612d81SArnaldo Carvalho de Melo static void vmlinux_path__exit(void) 18162446042cSArnaldo Carvalho de Melo { 181704662523SArnaldo Carvalho de Melo while (--vmlinux_path__nr_entries >= 0) 181804662523SArnaldo Carvalho de Melo zfree(&vmlinux_path[vmlinux_path__nr_entries]); 1819c4f03547SWang Nan vmlinux_path__nr_entries = 0; 1820cc612d81SArnaldo Carvalho de Melo 182104662523SArnaldo Carvalho de Melo zfree(&vmlinux_path); 1822cc612d81SArnaldo Carvalho de Melo } 1823cc612d81SArnaldo Carvalho de Melo 18240a7e6d1bSNamhyung Kim static int vmlinux_path__init(struct perf_session_env *env) 1825cc612d81SArnaldo Carvalho de Melo { 1826cc612d81SArnaldo Carvalho de Melo struct utsname uts; 1827cc612d81SArnaldo Carvalho de Melo char bf[PATH_MAX]; 18280a7e6d1bSNamhyung Kim char *kernel_version; 1829cc612d81SArnaldo Carvalho de Melo 1830c657f423SAnton Blanchard vmlinux_path = malloc(sizeof(char *) * 6); 1831cc612d81SArnaldo Carvalho de Melo if (vmlinux_path == NULL) 1832cc612d81SArnaldo Carvalho de Melo return -1; 1833cc612d81SArnaldo Carvalho de Melo 1834cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup("vmlinux"); 1835cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 1836cc612d81SArnaldo Carvalho de Melo goto out_fail; 1837cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 1838cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup("/boot/vmlinux"); 1839cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 1840cc612d81SArnaldo Carvalho de Melo goto out_fail; 1841cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 1842ec5761eaSDavid Ahern 18430a7e6d1bSNamhyung Kim /* only try kernel version if no symfs was given */ 1844ec5761eaSDavid Ahern if (symbol_conf.symfs[0] != 0) 1845ec5761eaSDavid Ahern return 0; 1846ec5761eaSDavid Ahern 18470a7e6d1bSNamhyung Kim if (env) { 18480a7e6d1bSNamhyung Kim kernel_version = env->os_release; 18490a7e6d1bSNamhyung Kim } else { 1850ec5761eaSDavid Ahern if (uname(&uts) < 0) 1851e96c674fSNamhyung Kim goto out_fail; 1852ec5761eaSDavid Ahern 18530a7e6d1bSNamhyung Kim kernel_version = uts.release; 18540a7e6d1bSNamhyung Kim } 18550a7e6d1bSNamhyung Kim 18560a7e6d1bSNamhyung Kim snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", kernel_version); 1857cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); 1858cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 1859cc612d81SArnaldo Carvalho de Melo goto out_fail; 1860cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 1861c657f423SAnton Blanchard snprintf(bf, sizeof(bf), "/usr/lib/debug/boot/vmlinux-%s", 1862c657f423SAnton Blanchard kernel_version); 1863c657f423SAnton Blanchard vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); 1864c657f423SAnton Blanchard if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 1865c657f423SAnton Blanchard goto out_fail; 1866c657f423SAnton Blanchard ++vmlinux_path__nr_entries; 18670a7e6d1bSNamhyung Kim snprintf(bf, sizeof(bf), "/lib/modules/%s/build/vmlinux", kernel_version); 1868cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); 1869cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 1870cc612d81SArnaldo Carvalho de Melo goto out_fail; 1871cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 1872cc612d81SArnaldo Carvalho de Melo snprintf(bf, sizeof(bf), "/usr/lib/debug/lib/modules/%s/vmlinux", 18730a7e6d1bSNamhyung Kim 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; 1878cc612d81SArnaldo Carvalho de Melo 1879cc612d81SArnaldo Carvalho de Melo return 0; 1880cc612d81SArnaldo Carvalho de Melo 1881cc612d81SArnaldo Carvalho de Melo out_fail: 1882cc612d81SArnaldo Carvalho de Melo vmlinux_path__exit(); 1883cc612d81SArnaldo Carvalho de Melo return -1; 1884cc612d81SArnaldo Carvalho de Melo } 1885cc612d81SArnaldo Carvalho de Melo 18863bfe5f81SDavid Ahern int setup_list(struct strlist **list, const char *list_str, 1887655000e7SArnaldo Carvalho de Melo const char *list_name) 1888655000e7SArnaldo Carvalho de Melo { 1889655000e7SArnaldo Carvalho de Melo if (list_str == NULL) 1890655000e7SArnaldo Carvalho de Melo return 0; 1891655000e7SArnaldo Carvalho de Melo 1892655000e7SArnaldo Carvalho de Melo *list = strlist__new(true, list_str); 1893655000e7SArnaldo Carvalho de Melo if (!*list) { 1894655000e7SArnaldo Carvalho de Melo pr_err("problems parsing %s list\n", list_name); 1895655000e7SArnaldo Carvalho de Melo return -1; 1896655000e7SArnaldo Carvalho de Melo } 1897655000e7SArnaldo Carvalho de Melo return 0; 1898655000e7SArnaldo Carvalho de Melo } 1899655000e7SArnaldo Carvalho de Melo 1900e03eaa40SDavid Ahern int setup_intlist(struct intlist **list, const char *list_str, 1901e03eaa40SDavid Ahern const char *list_name) 1902e03eaa40SDavid Ahern { 1903e03eaa40SDavid Ahern if (list_str == NULL) 1904e03eaa40SDavid Ahern return 0; 1905e03eaa40SDavid Ahern 1906e03eaa40SDavid Ahern *list = intlist__new(list_str); 1907e03eaa40SDavid Ahern if (!*list) { 1908e03eaa40SDavid Ahern pr_err("problems parsing %s list\n", list_name); 1909e03eaa40SDavid Ahern return -1; 1910e03eaa40SDavid Ahern } 1911e03eaa40SDavid Ahern return 0; 1912e03eaa40SDavid Ahern } 1913e03eaa40SDavid Ahern 1914ec80fde7SArnaldo Carvalho de Melo static bool symbol__read_kptr_restrict(void) 1915ec80fde7SArnaldo Carvalho de Melo { 1916ec80fde7SArnaldo Carvalho de Melo bool value = false; 1917ec80fde7SArnaldo Carvalho de Melo 1918ec80fde7SArnaldo Carvalho de Melo if (geteuid() != 0) { 1919ec80fde7SArnaldo Carvalho de Melo FILE *fp = fopen("/proc/sys/kernel/kptr_restrict", "r"); 1920ec80fde7SArnaldo Carvalho de Melo if (fp != NULL) { 1921ec80fde7SArnaldo Carvalho de Melo char line[8]; 1922ec80fde7SArnaldo Carvalho de Melo 1923ec80fde7SArnaldo Carvalho de Melo if (fgets(line, sizeof(line), fp) != NULL) 1924ec80fde7SArnaldo Carvalho de Melo value = atoi(line) != 0; 1925ec80fde7SArnaldo Carvalho de Melo 1926ec80fde7SArnaldo Carvalho de Melo fclose(fp); 1927ec80fde7SArnaldo Carvalho de Melo } 1928ec80fde7SArnaldo Carvalho de Melo } 1929ec80fde7SArnaldo Carvalho de Melo 1930ec80fde7SArnaldo Carvalho de Melo return value; 1931ec80fde7SArnaldo Carvalho de Melo } 1932ec80fde7SArnaldo Carvalho de Melo 19330a7e6d1bSNamhyung Kim int symbol__init(struct perf_session_env *env) 1934cc612d81SArnaldo Carvalho de Melo { 1935ec5761eaSDavid Ahern const char *symfs; 1936ec5761eaSDavid Ahern 193785e00b55SJovi Zhang if (symbol_conf.initialized) 193885e00b55SJovi Zhang return 0; 193985e00b55SJovi Zhang 19409ac3e487SIrina Tirdea symbol_conf.priv_size = PERF_ALIGN(symbol_conf.priv_size, sizeof(u64)); 19414d439517SDavid S. Miller 1942166ccc9cSNamhyung Kim symbol__elf_init(); 1943166ccc9cSNamhyung Kim 194475be6cf4SArnaldo Carvalho de Melo if (symbol_conf.sort_by_name) 194575be6cf4SArnaldo Carvalho de Melo symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) - 194679406cd7SArnaldo Carvalho de Melo sizeof(struct symbol)); 1947b32d133aSArnaldo Carvalho de Melo 19480a7e6d1bSNamhyung Kim if (symbol_conf.try_vmlinux_path && vmlinux_path__init(env) < 0) 1949cc612d81SArnaldo Carvalho de Melo return -1; 1950cc612d81SArnaldo Carvalho de Melo 1951c410a338SArnaldo Carvalho de Melo if (symbol_conf.field_sep && *symbol_conf.field_sep == '.') { 1952c410a338SArnaldo Carvalho de Melo pr_err("'.' is the only non valid --field-separator argument\n"); 1953c410a338SArnaldo Carvalho de Melo return -1; 1954c410a338SArnaldo Carvalho de Melo } 1955c410a338SArnaldo Carvalho de Melo 1956655000e7SArnaldo Carvalho de Melo if (setup_list(&symbol_conf.dso_list, 1957655000e7SArnaldo Carvalho de Melo symbol_conf.dso_list_str, "dso") < 0) 1958655000e7SArnaldo Carvalho de Melo return -1; 1959655000e7SArnaldo Carvalho de Melo 1960655000e7SArnaldo Carvalho de Melo if (setup_list(&symbol_conf.comm_list, 1961655000e7SArnaldo Carvalho de Melo symbol_conf.comm_list_str, "comm") < 0) 1962655000e7SArnaldo Carvalho de Melo goto out_free_dso_list; 1963655000e7SArnaldo Carvalho de Melo 1964e03eaa40SDavid Ahern if (setup_intlist(&symbol_conf.pid_list, 1965e03eaa40SDavid Ahern symbol_conf.pid_list_str, "pid") < 0) 1966e03eaa40SDavid Ahern goto out_free_comm_list; 1967e03eaa40SDavid Ahern 1968e03eaa40SDavid Ahern if (setup_intlist(&symbol_conf.tid_list, 1969e03eaa40SDavid Ahern symbol_conf.tid_list_str, "tid") < 0) 1970e03eaa40SDavid Ahern goto out_free_pid_list; 1971e03eaa40SDavid Ahern 1972655000e7SArnaldo Carvalho de Melo if (setup_list(&symbol_conf.sym_list, 1973655000e7SArnaldo Carvalho de Melo symbol_conf.sym_list_str, "symbol") < 0) 1974e03eaa40SDavid Ahern goto out_free_tid_list; 1975655000e7SArnaldo Carvalho de Melo 1976ec5761eaSDavid Ahern /* 1977ec5761eaSDavid Ahern * A path to symbols of "/" is identical to "" 1978ec5761eaSDavid Ahern * reset here for simplicity. 1979ec5761eaSDavid Ahern */ 1980ec5761eaSDavid Ahern symfs = realpath(symbol_conf.symfs, NULL); 1981ec5761eaSDavid Ahern if (symfs == NULL) 1982ec5761eaSDavid Ahern symfs = symbol_conf.symfs; 1983ec5761eaSDavid Ahern if (strcmp(symfs, "/") == 0) 1984ec5761eaSDavid Ahern symbol_conf.symfs = ""; 1985ec5761eaSDavid Ahern if (symfs != symbol_conf.symfs) 1986ec5761eaSDavid Ahern free((void *)symfs); 1987ec5761eaSDavid Ahern 1988ec80fde7SArnaldo Carvalho de Melo symbol_conf.kptr_restrict = symbol__read_kptr_restrict(); 1989ec80fde7SArnaldo Carvalho de Melo 199085e00b55SJovi Zhang symbol_conf.initialized = true; 19914aa65636SArnaldo Carvalho de Melo return 0; 1992655000e7SArnaldo Carvalho de Melo 1993e03eaa40SDavid Ahern out_free_tid_list: 1994e03eaa40SDavid Ahern intlist__delete(symbol_conf.tid_list); 1995e03eaa40SDavid Ahern out_free_pid_list: 1996e03eaa40SDavid Ahern intlist__delete(symbol_conf.pid_list); 1997655000e7SArnaldo Carvalho de Melo out_free_comm_list: 1998655000e7SArnaldo Carvalho de Melo strlist__delete(symbol_conf.comm_list); 1999d74c896bSNamhyung Kim out_free_dso_list: 2000d74c896bSNamhyung Kim strlist__delete(symbol_conf.dso_list); 2001655000e7SArnaldo Carvalho de Melo return -1; 2002cc612d81SArnaldo Carvalho de Melo } 2003cc612d81SArnaldo Carvalho de Melo 2004d65a458bSArnaldo Carvalho de Melo void symbol__exit(void) 2005d65a458bSArnaldo Carvalho de Melo { 200685e00b55SJovi Zhang if (!symbol_conf.initialized) 200785e00b55SJovi Zhang return; 2008d65a458bSArnaldo Carvalho de Melo strlist__delete(symbol_conf.sym_list); 2009d65a458bSArnaldo Carvalho de Melo strlist__delete(symbol_conf.dso_list); 2010d65a458bSArnaldo Carvalho de Melo strlist__delete(symbol_conf.comm_list); 2011e03eaa40SDavid Ahern intlist__delete(symbol_conf.tid_list); 2012e03eaa40SDavid Ahern intlist__delete(symbol_conf.pid_list); 2013d65a458bSArnaldo Carvalho de Melo vmlinux_path__exit(); 2014d65a458bSArnaldo Carvalho de Melo symbol_conf.sym_list = symbol_conf.dso_list = symbol_conf.comm_list = NULL; 201585e00b55SJovi Zhang symbol_conf.initialized = false; 2016d65a458bSArnaldo Carvalho de Melo } 2017