15aab621bSArnaldo Carvalho de Melo #include <dirent.h> 25aab621bSArnaldo Carvalho de Melo #include <errno.h> 35aab621bSArnaldo Carvalho de Melo #include <stdlib.h> 45aab621bSArnaldo Carvalho de Melo #include <stdio.h> 55aab621bSArnaldo Carvalho de Melo #include <string.h> 65aab621bSArnaldo Carvalho de Melo #include <sys/types.h> 75aab621bSArnaldo Carvalho de Melo #include <sys/stat.h> 85aab621bSArnaldo Carvalho de Melo #include <sys/param.h> 95aab621bSArnaldo Carvalho de Melo #include <fcntl.h> 105aab621bSArnaldo Carvalho de Melo #include <unistd.h> 119486aa38SArnaldo Carvalho de Melo #include <inttypes.h> 12b36f19d5SArnaldo Carvalho de Melo #include "build-id.h" 13e334c726SNamhyung Kim #include "util.h" 148a6c5b26SArnaldo Carvalho de Melo #include "debug.h" 1569d2591aSArnaldo Carvalho de Melo #include "machine.h" 1686470930SIngo Molnar #include "symbol.h" 175aab621bSArnaldo Carvalho de Melo #include "strlist.h" 18e03eaa40SDavid Ahern #include "intlist.h" 190a7e6d1bSNamhyung Kim #include "header.h" 2086470930SIngo Molnar 2186470930SIngo Molnar #include <elf.h> 22f1617b40SArnaldo Carvalho de Melo #include <limits.h> 23c506c96bSArnaldo Carvalho de Melo #include <symbol/kallsyms.h> 24439d473bSArnaldo Carvalho de Melo #include <sys/utsname.h> 252cdbc46dSPeter Zijlstra 26aeafcbafSArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *dso, struct map *map, 279de89fe7SArnaldo Carvalho de Melo symbol_filter_t filter); 28aeafcbafSArnaldo Carvalho de Melo static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map, 29a1645ce1SZhang, Yanmin symbol_filter_t filter); 303f067dcaSArnaldo Carvalho de Melo int vmlinux_path__nr_entries; 313f067dcaSArnaldo Carvalho de Melo char **vmlinux_path; 32439d473bSArnaldo Carvalho de Melo 3375be6cf4SArnaldo Carvalho de Melo struct symbol_conf symbol_conf = { 34b32d133aSArnaldo Carvalho de Melo .use_modules = true, 35b32d133aSArnaldo Carvalho de Melo .try_vmlinux_path = true, 363e6a2a7fSStephane Eranian .annotate_src = true, 37328ccdacSNamhyung Kim .demangle = true, 38763122adSAvi Kivity .demangle_kernel = false, 39e511db5eSNamhyung Kim .cumulate_callchain = true, 40c8302367SJiri Olsa .show_hist_headers = true, 41ec5761eaSDavid Ahern .symfs = "", 42b32d133aSArnaldo Carvalho de Melo }; 43b32d133aSArnaldo Carvalho de Melo 4444f24cb3SJiri Olsa static enum dso_binary_type binary_type_symtab[] = { 4544f24cb3SJiri Olsa DSO_BINARY_TYPE__KALLSYMS, 4644f24cb3SJiri Olsa DSO_BINARY_TYPE__GUEST_KALLSYMS, 4744f24cb3SJiri Olsa DSO_BINARY_TYPE__JAVA_JIT, 4844f24cb3SJiri Olsa DSO_BINARY_TYPE__DEBUGLINK, 4944f24cb3SJiri Olsa DSO_BINARY_TYPE__BUILD_ID_CACHE, 5044f24cb3SJiri Olsa DSO_BINARY_TYPE__FEDORA_DEBUGINFO, 5144f24cb3SJiri Olsa DSO_BINARY_TYPE__UBUNTU_DEBUGINFO, 5244f24cb3SJiri Olsa DSO_BINARY_TYPE__BUILDID_DEBUGINFO, 5344f24cb3SJiri Olsa DSO_BINARY_TYPE__SYSTEM_PATH_DSO, 5444f24cb3SJiri Olsa DSO_BINARY_TYPE__GUEST_KMODULE, 55c00c48fcSNamhyung Kim DSO_BINARY_TYPE__GUEST_KMODULE_COMP, 5644f24cb3SJiri Olsa DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE, 57c00c48fcSNamhyung Kim DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP, 589cd00941SRicardo Ribalda Delgado DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO, 5944f24cb3SJiri Olsa DSO_BINARY_TYPE__NOT_FOUND, 6044f24cb3SJiri Olsa }; 6144f24cb3SJiri Olsa 62028df767SJiri Olsa #define DSO_BINARY_TYPE__SYMTAB_CNT ARRAY_SIZE(binary_type_symtab) 6344f24cb3SJiri Olsa 6436a3e646SArnaldo Carvalho de Melo bool symbol_type__is_a(char symbol_type, enum map_type map_type) 656893d4eeSArnaldo Carvalho de Melo { 6631877908SAnton Blanchard symbol_type = toupper(symbol_type); 6731877908SAnton Blanchard 686893d4eeSArnaldo Carvalho de Melo switch (map_type) { 696893d4eeSArnaldo Carvalho de Melo case MAP__FUNCTION: 706893d4eeSArnaldo Carvalho de Melo return symbol_type == 'T' || symbol_type == 'W'; 71f1dfa0b1SArnaldo Carvalho de Melo case MAP__VARIABLE: 7231877908SAnton Blanchard return symbol_type == 'D'; 736893d4eeSArnaldo Carvalho de Melo default: 746893d4eeSArnaldo Carvalho de Melo return false; 756893d4eeSArnaldo Carvalho de Melo } 766893d4eeSArnaldo Carvalho de Melo } 776893d4eeSArnaldo Carvalho de Melo 78694bf407SAnton Blanchard static int prefix_underscores_count(const char *str) 79694bf407SAnton Blanchard { 80694bf407SAnton Blanchard const char *tail = str; 81694bf407SAnton Blanchard 82694bf407SAnton Blanchard while (*tail == '_') 83694bf407SAnton Blanchard tail++; 84694bf407SAnton Blanchard 85694bf407SAnton Blanchard return tail - str; 86694bf407SAnton Blanchard } 87694bf407SAnton Blanchard 88fb6d5942SNaveen N. Rao int __weak arch__choose_best_symbol(struct symbol *syma, 89fb6d5942SNaveen N. Rao struct symbol *symb __maybe_unused) 90fb6d5942SNaveen N. Rao { 91fb6d5942SNaveen N. Rao /* Avoid "SyS" kernel syscall aliases */ 92fb6d5942SNaveen N. Rao if (strlen(syma->name) >= 3 && !strncmp(syma->name, "SyS", 3)) 93fb6d5942SNaveen N. Rao return SYMBOL_B; 94fb6d5942SNaveen N. Rao if (strlen(syma->name) >= 10 && !strncmp(syma->name, "compat_SyS", 10)) 95fb6d5942SNaveen N. Rao return SYMBOL_B; 96fb6d5942SNaveen N. Rao 97fb6d5942SNaveen N. Rao return SYMBOL_A; 98fb6d5942SNaveen N. Rao } 99694bf407SAnton Blanchard 100694bf407SAnton Blanchard static int choose_best_symbol(struct symbol *syma, struct symbol *symb) 101694bf407SAnton Blanchard { 102694bf407SAnton Blanchard s64 a; 103694bf407SAnton Blanchard s64 b; 1043445432bSAdrian Hunter size_t na, nb; 105694bf407SAnton Blanchard 106694bf407SAnton Blanchard /* Prefer a symbol with non zero length */ 107694bf407SAnton Blanchard a = syma->end - syma->start; 108694bf407SAnton Blanchard b = symb->end - symb->start; 109694bf407SAnton Blanchard if ((b == 0) && (a > 0)) 110694bf407SAnton Blanchard return SYMBOL_A; 111694bf407SAnton Blanchard else if ((a == 0) && (b > 0)) 112694bf407SAnton Blanchard return SYMBOL_B; 113694bf407SAnton Blanchard 114694bf407SAnton Blanchard /* Prefer a non weak symbol over a weak one */ 115694bf407SAnton Blanchard a = syma->binding == STB_WEAK; 116694bf407SAnton Blanchard b = symb->binding == STB_WEAK; 117694bf407SAnton Blanchard if (b && !a) 118694bf407SAnton Blanchard return SYMBOL_A; 119694bf407SAnton Blanchard if (a && !b) 120694bf407SAnton Blanchard return SYMBOL_B; 121694bf407SAnton Blanchard 122694bf407SAnton Blanchard /* Prefer a global symbol over a non global one */ 123694bf407SAnton Blanchard a = syma->binding == STB_GLOBAL; 124694bf407SAnton Blanchard b = symb->binding == STB_GLOBAL; 125694bf407SAnton Blanchard if (a && !b) 126694bf407SAnton Blanchard return SYMBOL_A; 127694bf407SAnton Blanchard if (b && !a) 128694bf407SAnton Blanchard return SYMBOL_B; 129694bf407SAnton Blanchard 130694bf407SAnton Blanchard /* Prefer a symbol with less underscores */ 131694bf407SAnton Blanchard a = prefix_underscores_count(syma->name); 132694bf407SAnton Blanchard b = prefix_underscores_count(symb->name); 133694bf407SAnton Blanchard if (b > a) 134694bf407SAnton Blanchard return SYMBOL_A; 135694bf407SAnton Blanchard else if (a > b) 136694bf407SAnton Blanchard return SYMBOL_B; 137694bf407SAnton Blanchard 1383445432bSAdrian Hunter /* Choose the symbol with the longest name */ 1393445432bSAdrian Hunter na = strlen(syma->name); 1403445432bSAdrian Hunter nb = strlen(symb->name); 1413445432bSAdrian Hunter if (na > nb) 142694bf407SAnton Blanchard return SYMBOL_A; 1433445432bSAdrian Hunter else if (na < nb) 144694bf407SAnton Blanchard return SYMBOL_B; 1453445432bSAdrian Hunter 146fb6d5942SNaveen N. Rao return arch__choose_best_symbol(syma, symb); 147694bf407SAnton Blanchard } 148694bf407SAnton Blanchard 149e5a1845fSNamhyung Kim void symbols__fixup_duplicate(struct rb_root *symbols) 150694bf407SAnton Blanchard { 151694bf407SAnton Blanchard struct rb_node *nd; 152694bf407SAnton Blanchard struct symbol *curr, *next; 153694bf407SAnton Blanchard 154694bf407SAnton Blanchard nd = rb_first(symbols); 155694bf407SAnton Blanchard 156694bf407SAnton Blanchard while (nd) { 157694bf407SAnton Blanchard curr = rb_entry(nd, struct symbol, rb_node); 158694bf407SAnton Blanchard again: 159694bf407SAnton Blanchard nd = rb_next(&curr->rb_node); 160694bf407SAnton Blanchard next = rb_entry(nd, struct symbol, rb_node); 161694bf407SAnton Blanchard 162694bf407SAnton Blanchard if (!nd) 163694bf407SAnton Blanchard break; 164694bf407SAnton Blanchard 165694bf407SAnton Blanchard if (curr->start != next->start) 166694bf407SAnton Blanchard continue; 167694bf407SAnton Blanchard 168694bf407SAnton Blanchard if (choose_best_symbol(curr, next) == SYMBOL_A) { 169694bf407SAnton Blanchard rb_erase(&next->rb_node, symbols); 170d4f74eb8SChenggang Qin symbol__delete(next); 171694bf407SAnton Blanchard goto again; 172694bf407SAnton Blanchard } else { 173694bf407SAnton Blanchard nd = rb_next(&curr->rb_node); 174694bf407SAnton Blanchard rb_erase(&curr->rb_node, symbols); 175d4f74eb8SChenggang Qin symbol__delete(curr); 176694bf407SAnton Blanchard } 177694bf407SAnton Blanchard } 178694bf407SAnton Blanchard } 179694bf407SAnton Blanchard 180e5a1845fSNamhyung Kim void symbols__fixup_end(struct rb_root *symbols) 181af427bf5SArnaldo Carvalho de Melo { 182aeafcbafSArnaldo Carvalho de Melo struct rb_node *nd, *prevnd = rb_first(symbols); 1832e538c4aSArnaldo Carvalho de Melo struct symbol *curr, *prev; 184af427bf5SArnaldo Carvalho de Melo 185af427bf5SArnaldo Carvalho de Melo if (prevnd == NULL) 186af427bf5SArnaldo Carvalho de Melo return; 187af427bf5SArnaldo Carvalho de Melo 1882e538c4aSArnaldo Carvalho de Melo curr = rb_entry(prevnd, struct symbol, rb_node); 1892e538c4aSArnaldo Carvalho de Melo 190af427bf5SArnaldo Carvalho de Melo for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) { 1912e538c4aSArnaldo Carvalho de Melo prev = curr; 1922e538c4aSArnaldo Carvalho de Melo curr = rb_entry(nd, struct symbol, rb_node); 193af427bf5SArnaldo Carvalho de Melo 1943b01a413SArnaldo Carvalho de Melo if (prev->end == prev->start && prev->end != curr->start) 1952c241bd3SArnaldo Carvalho de Melo prev->end = curr->start; 196af427bf5SArnaldo Carvalho de Melo } 197af427bf5SArnaldo Carvalho de Melo 1982e538c4aSArnaldo Carvalho de Melo /* Last entry */ 1992e538c4aSArnaldo Carvalho de Melo if (curr->end == curr->start) 2002e538c4aSArnaldo Carvalho de Melo curr->end = roundup(curr->start, 4096); 2012e538c4aSArnaldo Carvalho de Melo } 2022e538c4aSArnaldo Carvalho de Melo 203e5a1845fSNamhyung Kim void __map_groups__fixup_end(struct map_groups *mg, enum map_type type) 204af427bf5SArnaldo Carvalho de Melo { 2051eee78aeSArnaldo Carvalho de Melo struct maps *maps = &mg->maps[type]; 2064bb7123dSArnaldo Carvalho de Melo struct map *next, *curr; 207af427bf5SArnaldo Carvalho de Melo 2086a2ffcddSArnaldo Carvalho de Melo pthread_rwlock_wrlock(&maps->lock); 2096a2ffcddSArnaldo Carvalho de Melo 2104bb7123dSArnaldo Carvalho de Melo curr = maps__first(maps); 2114bb7123dSArnaldo Carvalho de Melo if (curr == NULL) 2126a2ffcddSArnaldo Carvalho de Melo goto out_unlock; 213af427bf5SArnaldo Carvalho de Melo 2144bb7123dSArnaldo Carvalho de Melo for (next = map__next(curr); next; next = map__next(curr)) { 2154bb7123dSArnaldo Carvalho de Melo curr->end = next->start; 2164bb7123dSArnaldo Carvalho de Melo curr = next; 2172e538c4aSArnaldo Carvalho de Melo } 21890c83218SArnaldo Carvalho de Melo 21990c83218SArnaldo Carvalho de Melo /* 22090c83218SArnaldo Carvalho de Melo * We still haven't the actual symbols, so guess the 22190c83218SArnaldo Carvalho de Melo * last map final address. 22290c83218SArnaldo Carvalho de Melo */ 2239d1faba5SIan Munsie curr->end = ~0ULL; 2246a2ffcddSArnaldo Carvalho de Melo 2256a2ffcddSArnaldo Carvalho de Melo out_unlock: 2266a2ffcddSArnaldo Carvalho de Melo pthread_rwlock_unlock(&maps->lock); 227af427bf5SArnaldo Carvalho de Melo } 228af427bf5SArnaldo Carvalho de Melo 229e5a1845fSNamhyung Kim struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name) 23086470930SIngo Molnar { 23186470930SIngo Molnar size_t namelen = strlen(name) + 1; 232aeafcbafSArnaldo Carvalho de Melo struct symbol *sym = calloc(1, (symbol_conf.priv_size + 233aeafcbafSArnaldo Carvalho de Melo sizeof(*sym) + namelen)); 234aeafcbafSArnaldo Carvalho de Melo if (sym == NULL) 23586470930SIngo Molnar return NULL; 23686470930SIngo Molnar 23775be6cf4SArnaldo Carvalho de Melo if (symbol_conf.priv_size) 238aeafcbafSArnaldo Carvalho de Melo sym = ((void *)sym) + symbol_conf.priv_size; 23936479484SArnaldo Carvalho de Melo 240aeafcbafSArnaldo Carvalho de Melo sym->start = start; 2412c241bd3SArnaldo Carvalho de Melo sym->end = len ? start + len : start; 242aeafcbafSArnaldo Carvalho de Melo sym->binding = binding; 243aeafcbafSArnaldo Carvalho de Melo sym->namelen = namelen - 1; 244e4204992SArnaldo Carvalho de Melo 245aeafcbafSArnaldo Carvalho de Melo pr_debug4("%s: %s %#" PRIx64 "-%#" PRIx64 "\n", 246aeafcbafSArnaldo Carvalho de Melo __func__, name, start, sym->end); 247aeafcbafSArnaldo Carvalho de Melo memcpy(sym->name, name, namelen); 248e4204992SArnaldo Carvalho de Melo 249aeafcbafSArnaldo Carvalho de Melo return sym; 25086470930SIngo Molnar } 25186470930SIngo Molnar 252aeafcbafSArnaldo Carvalho de Melo void symbol__delete(struct symbol *sym) 25386470930SIngo Molnar { 254aeafcbafSArnaldo Carvalho de Melo free(((void *)sym) - symbol_conf.priv_size); 25586470930SIngo Molnar } 25686470930SIngo Molnar 257cdd059d7SJiri Olsa size_t symbol__fprintf(struct symbol *sym, FILE *fp) 25886470930SIngo Molnar { 2599486aa38SArnaldo Carvalho de Melo return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %c %s\n", 260aeafcbafSArnaldo Carvalho de Melo sym->start, sym->end, 261aeafcbafSArnaldo Carvalho de Melo sym->binding == STB_GLOBAL ? 'g' : 262aeafcbafSArnaldo Carvalho de Melo sym->binding == STB_LOCAL ? 'l' : 'w', 263aeafcbafSArnaldo Carvalho de Melo sym->name); 26486470930SIngo Molnar } 26586470930SIngo Molnar 266a978f2abSAkihiro Nagai size_t symbol__fprintf_symname_offs(const struct symbol *sym, 267a978f2abSAkihiro Nagai const struct addr_location *al, FILE *fp) 268a978f2abSAkihiro Nagai { 269a978f2abSAkihiro Nagai unsigned long offset; 270a978f2abSAkihiro Nagai size_t length; 271a978f2abSAkihiro Nagai 272a978f2abSAkihiro Nagai if (sym && sym->name) { 273a978f2abSAkihiro Nagai length = fprintf(fp, "%s", sym->name); 274a978f2abSAkihiro Nagai if (al) { 2750b8c25d9SDavid Ahern if (al->addr < sym->end) 276a978f2abSAkihiro Nagai offset = al->addr - sym->start; 2770b8c25d9SDavid Ahern else 2780b8c25d9SDavid Ahern offset = al->addr - al->map->start - sym->start; 279a978f2abSAkihiro Nagai length += fprintf(fp, "+0x%lx", offset); 280a978f2abSAkihiro Nagai } 281a978f2abSAkihiro Nagai return length; 282a978f2abSAkihiro Nagai } else 283a978f2abSAkihiro Nagai return fprintf(fp, "[unknown]"); 284a978f2abSAkihiro Nagai } 285a978f2abSAkihiro Nagai 286547a92e0SAkihiro Nagai size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp) 287547a92e0SAkihiro Nagai { 288a978f2abSAkihiro Nagai return symbol__fprintf_symname_offs(sym, NULL, fp); 289547a92e0SAkihiro Nagai } 290547a92e0SAkihiro Nagai 291cdd059d7SJiri Olsa void symbols__delete(struct rb_root *symbols) 29286470930SIngo Molnar { 29386470930SIngo Molnar struct symbol *pos; 294aeafcbafSArnaldo Carvalho de Melo struct rb_node *next = rb_first(symbols); 29586470930SIngo Molnar 29686470930SIngo Molnar while (next) { 29786470930SIngo Molnar pos = rb_entry(next, struct symbol, rb_node); 29886470930SIngo Molnar next = rb_next(&pos->rb_node); 299aeafcbafSArnaldo Carvalho de Melo rb_erase(&pos->rb_node, symbols); 30000a192b3SArnaldo Carvalho de Melo symbol__delete(pos); 30186470930SIngo Molnar } 30286470930SIngo Molnar } 30386470930SIngo Molnar 304e5a1845fSNamhyung Kim void symbols__insert(struct rb_root *symbols, struct symbol *sym) 30586470930SIngo Molnar { 306aeafcbafSArnaldo Carvalho de Melo struct rb_node **p = &symbols->rb_node; 30786470930SIngo Molnar struct rb_node *parent = NULL; 3089cffa8d5SPaul Mackerras const u64 ip = sym->start; 30986470930SIngo Molnar struct symbol *s; 31086470930SIngo Molnar 31186470930SIngo Molnar while (*p != NULL) { 31286470930SIngo Molnar parent = *p; 31386470930SIngo Molnar s = rb_entry(parent, struct symbol, rb_node); 31486470930SIngo Molnar if (ip < s->start) 31586470930SIngo Molnar p = &(*p)->rb_left; 31686470930SIngo Molnar else 31786470930SIngo Molnar p = &(*p)->rb_right; 31886470930SIngo Molnar } 31986470930SIngo Molnar rb_link_node(&sym->rb_node, parent, p); 320aeafcbafSArnaldo Carvalho de Melo rb_insert_color(&sym->rb_node, symbols); 32186470930SIngo Molnar } 32286470930SIngo Molnar 323aeafcbafSArnaldo Carvalho de Melo static struct symbol *symbols__find(struct rb_root *symbols, u64 ip) 32486470930SIngo Molnar { 32586470930SIngo Molnar struct rb_node *n; 32686470930SIngo Molnar 327aeafcbafSArnaldo Carvalho de Melo if (symbols == NULL) 32886470930SIngo Molnar return NULL; 32986470930SIngo Molnar 330aeafcbafSArnaldo Carvalho de Melo n = symbols->rb_node; 33186470930SIngo Molnar 33286470930SIngo Molnar while (n) { 33386470930SIngo Molnar struct symbol *s = rb_entry(n, struct symbol, rb_node); 33486470930SIngo Molnar 33586470930SIngo Molnar if (ip < s->start) 33686470930SIngo Molnar n = n->rb_left; 3372c241bd3SArnaldo Carvalho de Melo else if (ip >= s->end) 33886470930SIngo Molnar n = n->rb_right; 33986470930SIngo Molnar else 34086470930SIngo Molnar return s; 34186470930SIngo Molnar } 34286470930SIngo Molnar 34386470930SIngo Molnar return NULL; 34486470930SIngo Molnar } 34586470930SIngo Molnar 3468e0cf965SAdrian Hunter static struct symbol *symbols__first(struct rb_root *symbols) 3478e0cf965SAdrian Hunter { 3488e0cf965SAdrian Hunter struct rb_node *n = rb_first(symbols); 3498e0cf965SAdrian Hunter 3508e0cf965SAdrian Hunter if (n) 3518e0cf965SAdrian Hunter return rb_entry(n, struct symbol, rb_node); 3528e0cf965SAdrian Hunter 3538e0cf965SAdrian Hunter return NULL; 3548e0cf965SAdrian Hunter } 3558e0cf965SAdrian Hunter 3569c00a81bSAdrian Hunter static struct symbol *symbols__next(struct symbol *sym) 3579c00a81bSAdrian Hunter { 3589c00a81bSAdrian Hunter struct rb_node *n = rb_next(&sym->rb_node); 3599c00a81bSAdrian Hunter 3609c00a81bSAdrian Hunter if (n) 3619c00a81bSAdrian Hunter return rb_entry(n, struct symbol, rb_node); 3629c00a81bSAdrian Hunter 3639c00a81bSAdrian Hunter return NULL; 3649c00a81bSAdrian Hunter } 3659c00a81bSAdrian Hunter 36679406cd7SArnaldo Carvalho de Melo struct symbol_name_rb_node { 36779406cd7SArnaldo Carvalho de Melo struct rb_node rb_node; 36879406cd7SArnaldo Carvalho de Melo struct symbol sym; 36979406cd7SArnaldo Carvalho de Melo }; 37079406cd7SArnaldo Carvalho de Melo 371aeafcbafSArnaldo Carvalho de Melo static void symbols__insert_by_name(struct rb_root *symbols, struct symbol *sym) 37279406cd7SArnaldo Carvalho de Melo { 373aeafcbafSArnaldo Carvalho de Melo struct rb_node **p = &symbols->rb_node; 37479406cd7SArnaldo Carvalho de Melo struct rb_node *parent = NULL; 37502a9d037SRabin Vincent struct symbol_name_rb_node *symn, *s; 37602a9d037SRabin Vincent 37702a9d037SRabin Vincent symn = container_of(sym, struct symbol_name_rb_node, sym); 37879406cd7SArnaldo Carvalho de Melo 37979406cd7SArnaldo Carvalho de Melo while (*p != NULL) { 38079406cd7SArnaldo Carvalho de Melo parent = *p; 38179406cd7SArnaldo Carvalho de Melo s = rb_entry(parent, struct symbol_name_rb_node, rb_node); 38279406cd7SArnaldo Carvalho de Melo if (strcmp(sym->name, s->sym.name) < 0) 38379406cd7SArnaldo Carvalho de Melo p = &(*p)->rb_left; 38479406cd7SArnaldo Carvalho de Melo else 38579406cd7SArnaldo Carvalho de Melo p = &(*p)->rb_right; 38679406cd7SArnaldo Carvalho de Melo } 38779406cd7SArnaldo Carvalho de Melo rb_link_node(&symn->rb_node, parent, p); 388aeafcbafSArnaldo Carvalho de Melo rb_insert_color(&symn->rb_node, symbols); 38979406cd7SArnaldo Carvalho de Melo } 39079406cd7SArnaldo Carvalho de Melo 391aeafcbafSArnaldo Carvalho de Melo static void symbols__sort_by_name(struct rb_root *symbols, 392aeafcbafSArnaldo Carvalho de Melo struct rb_root *source) 39379406cd7SArnaldo Carvalho de Melo { 39479406cd7SArnaldo Carvalho de Melo struct rb_node *nd; 39579406cd7SArnaldo Carvalho de Melo 39679406cd7SArnaldo Carvalho de Melo for (nd = rb_first(source); nd; nd = rb_next(nd)) { 39779406cd7SArnaldo Carvalho de Melo struct symbol *pos = rb_entry(nd, struct symbol, rb_node); 398aeafcbafSArnaldo Carvalho de Melo symbols__insert_by_name(symbols, pos); 39979406cd7SArnaldo Carvalho de Melo } 40079406cd7SArnaldo Carvalho de Melo } 40179406cd7SArnaldo Carvalho de Melo 402aeafcbafSArnaldo Carvalho de Melo static struct symbol *symbols__find_by_name(struct rb_root *symbols, 403aeafcbafSArnaldo Carvalho de Melo const char *name) 40479406cd7SArnaldo Carvalho de Melo { 40579406cd7SArnaldo Carvalho de Melo struct rb_node *n; 4065bcaaca3SMartin Liška struct symbol_name_rb_node *s = NULL; 40779406cd7SArnaldo Carvalho de Melo 408aeafcbafSArnaldo Carvalho de Melo if (symbols == NULL) 40979406cd7SArnaldo Carvalho de Melo return NULL; 41079406cd7SArnaldo Carvalho de Melo 411aeafcbafSArnaldo Carvalho de Melo n = symbols->rb_node; 41279406cd7SArnaldo Carvalho de Melo 41379406cd7SArnaldo Carvalho de Melo while (n) { 41479406cd7SArnaldo Carvalho de Melo int cmp; 41579406cd7SArnaldo Carvalho de Melo 41679406cd7SArnaldo Carvalho de Melo s = rb_entry(n, struct symbol_name_rb_node, rb_node); 417031b84c4SNaveen N. Rao cmp = arch__compare_symbol_names(name, s->sym.name); 41879406cd7SArnaldo Carvalho de Melo 41979406cd7SArnaldo Carvalho de Melo if (cmp < 0) 42079406cd7SArnaldo Carvalho de Melo n = n->rb_left; 42179406cd7SArnaldo Carvalho de Melo else if (cmp > 0) 42279406cd7SArnaldo Carvalho de Melo n = n->rb_right; 42379406cd7SArnaldo Carvalho de Melo else 424de480999SNamhyung Kim break; 42579406cd7SArnaldo Carvalho de Melo } 42679406cd7SArnaldo Carvalho de Melo 427de480999SNamhyung Kim if (n == NULL) 42879406cd7SArnaldo Carvalho de Melo return NULL; 429de480999SNamhyung Kim 430de480999SNamhyung Kim /* return first symbol that has same name (if any) */ 431de480999SNamhyung Kim for (n = rb_prev(n); n; n = rb_prev(n)) { 432de480999SNamhyung Kim struct symbol_name_rb_node *tmp; 433de480999SNamhyung Kim 434de480999SNamhyung Kim tmp = rb_entry(n, struct symbol_name_rb_node, rb_node); 435031b84c4SNaveen N. Rao if (arch__compare_symbol_names(tmp->sym.name, s->sym.name)) 436de480999SNamhyung Kim break; 437de480999SNamhyung Kim 438de480999SNamhyung Kim s = tmp; 439de480999SNamhyung Kim } 440de480999SNamhyung Kim 441de480999SNamhyung Kim return &s->sym; 44279406cd7SArnaldo Carvalho de Melo } 44379406cd7SArnaldo Carvalho de Melo 444c0b4dffbSArnaldo Carvalho de Melo void dso__reset_find_symbol_cache(struct dso *dso) 445c0b4dffbSArnaldo Carvalho de Melo { 446c0b4dffbSArnaldo Carvalho de Melo enum map_type type; 447c0b4dffbSArnaldo Carvalho de Melo 448c0b4dffbSArnaldo Carvalho de Melo for (type = MAP__FUNCTION; type <= MAP__VARIABLE; ++type) { 449c0b4dffbSArnaldo Carvalho de Melo dso->last_find_result[type].addr = 0; 450c0b4dffbSArnaldo Carvalho de Melo dso->last_find_result[type].symbol = NULL; 451c0b4dffbSArnaldo Carvalho de Melo } 452c0b4dffbSArnaldo Carvalho de Melo } 453c0b4dffbSArnaldo Carvalho de Melo 454aeafcbafSArnaldo Carvalho de Melo struct symbol *dso__find_symbol(struct dso *dso, 45579406cd7SArnaldo Carvalho de Melo enum map_type type, u64 addr) 456fcf1203aSArnaldo Carvalho de Melo { 457b685ac22SArnaldo Carvalho de Melo if (dso->last_find_result[type].addr != addr) { 458b685ac22SArnaldo Carvalho de Melo dso->last_find_result[type].addr = addr; 459b685ac22SArnaldo Carvalho de Melo dso->last_find_result[type].symbol = symbols__find(&dso->symbols[type], addr); 460b685ac22SArnaldo Carvalho de Melo } 461b685ac22SArnaldo Carvalho de Melo 462b685ac22SArnaldo Carvalho de Melo return dso->last_find_result[type].symbol; 463fcf1203aSArnaldo Carvalho de Melo } 464fcf1203aSArnaldo Carvalho de Melo 4659c00a81bSAdrian Hunter struct symbol *dso__first_symbol(struct dso *dso, enum map_type type) 4668e0cf965SAdrian Hunter { 4678e0cf965SAdrian Hunter return symbols__first(&dso->symbols[type]); 4688e0cf965SAdrian Hunter } 4698e0cf965SAdrian Hunter 4709c00a81bSAdrian Hunter struct symbol *dso__next_symbol(struct symbol *sym) 4719c00a81bSAdrian Hunter { 4729c00a81bSAdrian Hunter return symbols__next(sym); 4739c00a81bSAdrian Hunter } 4749c00a81bSAdrian Hunter 47518bd7264SArnaldo Carvalho de Melo struct symbol *symbol__next_by_name(struct symbol *sym) 47618bd7264SArnaldo Carvalho de Melo { 47718bd7264SArnaldo Carvalho de Melo struct symbol_name_rb_node *s = container_of(sym, struct symbol_name_rb_node, sym); 47818bd7264SArnaldo Carvalho de Melo struct rb_node *n = rb_next(&s->rb_node); 47918bd7264SArnaldo Carvalho de Melo 48018bd7264SArnaldo Carvalho de Melo return n ? &rb_entry(n, struct symbol_name_rb_node, rb_node)->sym : NULL; 48118bd7264SArnaldo Carvalho de Melo } 48218bd7264SArnaldo Carvalho de Melo 48318bd7264SArnaldo Carvalho de Melo /* 48418bd7264SArnaldo Carvalho de Melo * Teturns first symbol that matched with @name. 48518bd7264SArnaldo Carvalho de Melo */ 486aeafcbafSArnaldo Carvalho de Melo struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type, 48779406cd7SArnaldo Carvalho de Melo const char *name) 48879406cd7SArnaldo Carvalho de Melo { 489aeafcbafSArnaldo Carvalho de Melo return symbols__find_by_name(&dso->symbol_names[type], name); 49079406cd7SArnaldo Carvalho de Melo } 49179406cd7SArnaldo Carvalho de Melo 492aeafcbafSArnaldo Carvalho de Melo void dso__sort_by_name(struct dso *dso, enum map_type type) 49379406cd7SArnaldo Carvalho de Melo { 494aeafcbafSArnaldo Carvalho de Melo dso__set_sorted_by_name(dso, type); 495aeafcbafSArnaldo Carvalho de Melo return symbols__sort_by_name(&dso->symbol_names[type], 496aeafcbafSArnaldo Carvalho de Melo &dso->symbols[type]); 49779406cd7SArnaldo Carvalho de Melo } 49879406cd7SArnaldo Carvalho de Melo 499aeafcbafSArnaldo Carvalho de Melo size_t dso__fprintf_symbols_by_name(struct dso *dso, 500aeafcbafSArnaldo Carvalho de Melo enum map_type type, FILE *fp) 50190f18e63SSrikar Dronamraju { 50290f18e63SSrikar Dronamraju size_t ret = 0; 50390f18e63SSrikar Dronamraju struct rb_node *nd; 50490f18e63SSrikar Dronamraju struct symbol_name_rb_node *pos; 50590f18e63SSrikar Dronamraju 506aeafcbafSArnaldo Carvalho de Melo for (nd = rb_first(&dso->symbol_names[type]); nd; nd = rb_next(nd)) { 50790f18e63SSrikar Dronamraju pos = rb_entry(nd, struct symbol_name_rb_node, rb_node); 50890f18e63SSrikar Dronamraju fprintf(fp, "%s\n", pos->sym.name); 50990f18e63SSrikar Dronamraju } 51090f18e63SSrikar Dronamraju 51190f18e63SSrikar Dronamraju return ret; 51290f18e63SSrikar Dronamraju } 51390f18e63SSrikar Dronamraju 514316d70d6SAdrian Hunter int modules__parse(const char *filename, void *arg, 515316d70d6SAdrian Hunter int (*process_module)(void *arg, const char *name, 516316d70d6SAdrian Hunter u64 start)) 517316d70d6SAdrian Hunter { 518316d70d6SAdrian Hunter char *line = NULL; 519316d70d6SAdrian Hunter size_t n; 520316d70d6SAdrian Hunter FILE *file; 521316d70d6SAdrian Hunter int err = 0; 522316d70d6SAdrian Hunter 523316d70d6SAdrian Hunter file = fopen(filename, "r"); 524316d70d6SAdrian Hunter if (file == NULL) 525316d70d6SAdrian Hunter return -1; 526316d70d6SAdrian Hunter 527316d70d6SAdrian Hunter while (1) { 528316d70d6SAdrian Hunter char name[PATH_MAX]; 529316d70d6SAdrian Hunter u64 start; 530316d70d6SAdrian Hunter char *sep; 531316d70d6SAdrian Hunter ssize_t line_len; 532316d70d6SAdrian Hunter 533316d70d6SAdrian Hunter line_len = getline(&line, &n, file); 534316d70d6SAdrian Hunter if (line_len < 0) { 535316d70d6SAdrian Hunter if (feof(file)) 536316d70d6SAdrian Hunter break; 537316d70d6SAdrian Hunter err = -1; 538316d70d6SAdrian Hunter goto out; 539316d70d6SAdrian Hunter } 540316d70d6SAdrian Hunter 541316d70d6SAdrian Hunter if (!line) { 542316d70d6SAdrian Hunter err = -1; 543316d70d6SAdrian Hunter goto out; 544316d70d6SAdrian Hunter } 545316d70d6SAdrian Hunter 546316d70d6SAdrian Hunter line[--line_len] = '\0'; /* \n */ 547316d70d6SAdrian Hunter 548316d70d6SAdrian Hunter sep = strrchr(line, 'x'); 549316d70d6SAdrian Hunter if (sep == NULL) 550316d70d6SAdrian Hunter continue; 551316d70d6SAdrian Hunter 552316d70d6SAdrian Hunter hex2u64(sep + 1, &start); 553316d70d6SAdrian Hunter 554316d70d6SAdrian Hunter sep = strchr(line, ' '); 555316d70d6SAdrian Hunter if (sep == NULL) 556316d70d6SAdrian Hunter continue; 557316d70d6SAdrian Hunter 558316d70d6SAdrian Hunter *sep = '\0'; 559316d70d6SAdrian Hunter 560316d70d6SAdrian Hunter scnprintf(name, sizeof(name), "[%s]", line); 561316d70d6SAdrian Hunter 562316d70d6SAdrian Hunter err = process_module(arg, name, start); 563316d70d6SAdrian Hunter if (err) 564316d70d6SAdrian Hunter break; 565316d70d6SAdrian Hunter } 566316d70d6SAdrian Hunter out: 567316d70d6SAdrian Hunter free(line); 568316d70d6SAdrian Hunter fclose(file); 569316d70d6SAdrian Hunter return err; 570316d70d6SAdrian Hunter } 571316d70d6SAdrian Hunter 572682b335aSArnaldo Carvalho de Melo struct process_kallsyms_args { 573682b335aSArnaldo Carvalho de Melo struct map *map; 574682b335aSArnaldo Carvalho de Melo struct dso *dso; 575682b335aSArnaldo Carvalho de Melo }; 576682b335aSArnaldo Carvalho de Melo 577e7110b9fSArnaldo Carvalho de Melo /* 578e7110b9fSArnaldo Carvalho de Melo * These are symbols in the kernel image, so make sure that 579e7110b9fSArnaldo Carvalho de Melo * sym is from a kernel DSO. 580e7110b9fSArnaldo Carvalho de Melo */ 58182d1deb0SDavid Ahern bool symbol__is_idle(struct symbol *sym) 58282d1deb0SDavid Ahern { 58382d1deb0SDavid Ahern const char * const idle_symbols[] = { 58482d1deb0SDavid Ahern "cpu_idle", 585e0336ed6SArnaldo Carvalho de Melo "cpu_startup_entry", 58682d1deb0SDavid Ahern "intel_idle", 58782d1deb0SDavid Ahern "default_idle", 58882d1deb0SDavid Ahern "native_safe_halt", 58982d1deb0SDavid Ahern "enter_idle", 59082d1deb0SDavid Ahern "exit_idle", 59182d1deb0SDavid Ahern "mwait_idle", 59282d1deb0SDavid Ahern "mwait_idle_with_hints", 59382d1deb0SDavid Ahern "poll_idle", 59482d1deb0SDavid Ahern "ppc64_runlatch_off", 59582d1deb0SDavid Ahern "pseries_dedicated_idle_sleep", 59682d1deb0SDavid Ahern NULL 59782d1deb0SDavid Ahern }; 59882d1deb0SDavid Ahern 59982d1deb0SDavid Ahern int i; 60082d1deb0SDavid Ahern 60182d1deb0SDavid Ahern if (!sym) 60282d1deb0SDavid Ahern return false; 60382d1deb0SDavid Ahern 60482d1deb0SDavid Ahern for (i = 0; idle_symbols[i]; i++) { 60582d1deb0SDavid Ahern if (!strcmp(idle_symbols[i], sym->name)) 60682d1deb0SDavid Ahern return true; 60782d1deb0SDavid Ahern } 60882d1deb0SDavid Ahern 60982d1deb0SDavid Ahern return false; 61082d1deb0SDavid Ahern } 61182d1deb0SDavid Ahern 612682b335aSArnaldo Carvalho de Melo static int map__process_kallsym_symbol(void *arg, const char *name, 61382151520SCody P Schafer char type, u64 start) 614682b335aSArnaldo Carvalho de Melo { 615682b335aSArnaldo Carvalho de Melo struct symbol *sym; 616682b335aSArnaldo Carvalho de Melo struct process_kallsyms_args *a = arg; 617682b335aSArnaldo Carvalho de Melo struct rb_root *root = &a->dso->symbols[a->map->type]; 618682b335aSArnaldo Carvalho de Melo 619682b335aSArnaldo Carvalho de Melo if (!symbol_type__is_a(type, a->map->type)) 620682b335aSArnaldo Carvalho de Melo return 0; 621682b335aSArnaldo Carvalho de Melo 62282151520SCody P Schafer /* 62382151520SCody P Schafer * module symbols are not sorted so we add all 62482151520SCody P Schafer * symbols, setting length to 0, and rely on 62582151520SCody P Schafer * symbols__fixup_end() to fix it up. 62682151520SCody P Schafer */ 6278e947f1eSArnaldo Carvalho de Melo sym = symbol__new(start, 0, kallsyms2elf_binding(type), name); 6282e538c4aSArnaldo Carvalho de Melo if (sym == NULL) 629682b335aSArnaldo Carvalho de Melo return -ENOMEM; 63082164161SArnaldo Carvalho de Melo /* 63182164161SArnaldo Carvalho de Melo * We will pass the symbols to the filter later, in 6324e06255fSArnaldo Carvalho de Melo * map__split_kallsyms, when we have split the maps per module 63382164161SArnaldo Carvalho de Melo */ 6344e06255fSArnaldo Carvalho de Melo symbols__insert(root, sym); 635a1645ce1SZhang, Yanmin 636682b335aSArnaldo Carvalho de Melo return 0; 6372e538c4aSArnaldo Carvalho de Melo } 6382e538c4aSArnaldo Carvalho de Melo 639682b335aSArnaldo Carvalho de Melo /* 640682b335aSArnaldo Carvalho de Melo * Loads the function entries in /proc/kallsyms into kernel_map->dso, 641682b335aSArnaldo Carvalho de Melo * so that we can in the next step set the symbol ->end address and then 642682b335aSArnaldo Carvalho de Melo * call kernel_maps__split_kallsyms. 643682b335aSArnaldo Carvalho de Melo */ 644aeafcbafSArnaldo Carvalho de Melo static int dso__load_all_kallsyms(struct dso *dso, const char *filename, 6459e201442SArnaldo Carvalho de Melo struct map *map) 646682b335aSArnaldo Carvalho de Melo { 647aeafcbafSArnaldo Carvalho de Melo struct process_kallsyms_args args = { .map = map, .dso = dso, }; 6489e201442SArnaldo Carvalho de Melo return kallsyms__parse(filename, &args, map__process_kallsym_symbol); 6492e538c4aSArnaldo Carvalho de Melo } 6502e538c4aSArnaldo Carvalho de Melo 6518e0cf965SAdrian Hunter static int dso__split_kallsyms_for_kcore(struct dso *dso, struct map *map, 6528e0cf965SAdrian Hunter symbol_filter_t filter) 6538e0cf965SAdrian Hunter { 654ba92732eSWang Nan struct map_groups *kmaps = map__kmaps(map); 6558e0cf965SAdrian Hunter struct map *curr_map; 6568e0cf965SAdrian Hunter struct symbol *pos; 657866548ddSAdrian Hunter int count = 0; 658866548ddSAdrian Hunter struct rb_root old_root = dso->symbols[map->type]; 6598e0cf965SAdrian Hunter struct rb_root *root = &dso->symbols[map->type]; 6608e0cf965SAdrian Hunter struct rb_node *next = rb_first(root); 6618e0cf965SAdrian Hunter 662ba92732eSWang Nan if (!kmaps) 663ba92732eSWang Nan return -1; 664ba92732eSWang Nan 665866548ddSAdrian Hunter *root = RB_ROOT; 666866548ddSAdrian Hunter 6678e0cf965SAdrian Hunter while (next) { 6688e0cf965SAdrian Hunter char *module; 6698e0cf965SAdrian Hunter 6708e0cf965SAdrian Hunter pos = rb_entry(next, struct symbol, rb_node); 6718e0cf965SAdrian Hunter next = rb_next(&pos->rb_node); 6728e0cf965SAdrian Hunter 673866548ddSAdrian Hunter rb_erase_init(&pos->rb_node, &old_root); 674866548ddSAdrian Hunter 6758e0cf965SAdrian Hunter module = strchr(pos->name, '\t'); 6768e0cf965SAdrian Hunter if (module) 6778e0cf965SAdrian Hunter *module = '\0'; 6788e0cf965SAdrian Hunter 6798e0cf965SAdrian Hunter curr_map = map_groups__find(kmaps, map->type, pos->start); 6808e0cf965SAdrian Hunter 6818e0cf965SAdrian Hunter if (!curr_map || (filter && filter(curr_map, pos))) { 6828e0cf965SAdrian Hunter symbol__delete(pos); 683866548ddSAdrian Hunter continue; 684866548ddSAdrian Hunter } 685866548ddSAdrian Hunter 6868e0cf965SAdrian Hunter pos->start -= curr_map->start - curr_map->pgoff; 6878e0cf965SAdrian Hunter if (pos->end) 6888e0cf965SAdrian Hunter pos->end -= curr_map->start - curr_map->pgoff; 689866548ddSAdrian Hunter symbols__insert(&curr_map->dso->symbols[curr_map->type], pos); 6908e0cf965SAdrian Hunter ++count; 6918e0cf965SAdrian Hunter } 6928e0cf965SAdrian Hunter 6938e0cf965SAdrian Hunter /* Symbols have been adjusted */ 6948e0cf965SAdrian Hunter dso->adjust_symbols = 1; 6958e0cf965SAdrian Hunter 696866548ddSAdrian Hunter return count; 6978e0cf965SAdrian Hunter } 6988e0cf965SAdrian Hunter 6992e538c4aSArnaldo Carvalho de Melo /* 7002e538c4aSArnaldo Carvalho de Melo * Split the symbols into maps, making sure there are no overlaps, i.e. the 7012e538c4aSArnaldo Carvalho de Melo * kernel range is broken in several maps, named [kernel].N, as we don't have 7022e538c4aSArnaldo Carvalho de Melo * the original ELF section names vmlinux have. 7032e538c4aSArnaldo Carvalho de Melo */ 704d9b62abaSAdrian Hunter static int dso__split_kallsyms(struct dso *dso, struct map *map, u64 delta, 7059de89fe7SArnaldo Carvalho de Melo symbol_filter_t filter) 7062e538c4aSArnaldo Carvalho de Melo { 707ba92732eSWang Nan struct map_groups *kmaps = map__kmaps(map); 708ba92732eSWang Nan struct machine *machine; 7094e06255fSArnaldo Carvalho de Melo struct map *curr_map = map; 7102e538c4aSArnaldo Carvalho de Melo struct symbol *pos; 7118a953312SArnaldo Carvalho de Melo int count = 0, moved = 0; 712aeafcbafSArnaldo Carvalho de Melo struct rb_root *root = &dso->symbols[map->type]; 7134e06255fSArnaldo Carvalho de Melo struct rb_node *next = rb_first(root); 7142e538c4aSArnaldo Carvalho de Melo int kernel_range = 0; 7152e538c4aSArnaldo Carvalho de Melo 716ba92732eSWang Nan if (!kmaps) 717ba92732eSWang Nan return -1; 718ba92732eSWang Nan 719ba92732eSWang Nan machine = kmaps->machine; 720ba92732eSWang Nan 7212e538c4aSArnaldo Carvalho de Melo while (next) { 7222e538c4aSArnaldo Carvalho de Melo char *module; 7232e538c4aSArnaldo Carvalho de Melo 7242e538c4aSArnaldo Carvalho de Melo pos = rb_entry(next, struct symbol, rb_node); 7252e538c4aSArnaldo Carvalho de Melo next = rb_next(&pos->rb_node); 7262e538c4aSArnaldo Carvalho de Melo 7272e538c4aSArnaldo Carvalho de Melo module = strchr(pos->name, '\t'); 7282e538c4aSArnaldo Carvalho de Melo if (module) { 72975be6cf4SArnaldo Carvalho de Melo if (!symbol_conf.use_modules) 7301de8e245SArnaldo Carvalho de Melo goto discard_symbol; 7311de8e245SArnaldo Carvalho de Melo 7322e538c4aSArnaldo Carvalho de Melo *module++ = '\0'; 7332e538c4aSArnaldo Carvalho de Melo 734b7cece76SArnaldo Carvalho de Melo if (strcmp(curr_map->dso->short_name, module)) { 735a1645ce1SZhang, Yanmin if (curr_map != map && 736aeafcbafSArnaldo Carvalho de Melo dso->kernel == DSO_TYPE_GUEST_KERNEL && 73723346f21SArnaldo Carvalho de Melo machine__is_default_guest(machine)) { 738a1645ce1SZhang, Yanmin /* 739a1645ce1SZhang, Yanmin * We assume all symbols of a module are 740a1645ce1SZhang, Yanmin * continuous in * kallsyms, so curr_map 741a1645ce1SZhang, Yanmin * points to a module and all its 742a1645ce1SZhang, Yanmin * symbols are in its kmap. Mark it as 743a1645ce1SZhang, Yanmin * loaded. 744a1645ce1SZhang, Yanmin */ 745a1645ce1SZhang, Yanmin dso__set_loaded(curr_map->dso, 746a1645ce1SZhang, Yanmin curr_map->type); 747af427bf5SArnaldo Carvalho de Melo } 748b7cece76SArnaldo Carvalho de Melo 749a1645ce1SZhang, Yanmin curr_map = map_groups__find_by_name(kmaps, 750a1645ce1SZhang, Yanmin map->type, module); 751a1645ce1SZhang, Yanmin if (curr_map == NULL) { 7522f51903bSArnaldo Carvalho de Melo pr_debug("%s/proc/{kallsyms,modules} " 753a1645ce1SZhang, Yanmin "inconsistency while looking " 754a1645ce1SZhang, Yanmin "for \"%s\" module!\n", 75523346f21SArnaldo Carvalho de Melo machine->root_dir, module); 756a1645ce1SZhang, Yanmin curr_map = map; 757a1645ce1SZhang, Yanmin goto discard_symbol; 758a1645ce1SZhang, Yanmin } 759a1645ce1SZhang, Yanmin 760a1645ce1SZhang, Yanmin if (curr_map->dso->loaded && 76123346f21SArnaldo Carvalho de Melo !machine__is_default_guest(machine)) 762b7cece76SArnaldo Carvalho de Melo goto discard_symbol; 763af427bf5SArnaldo Carvalho de Melo } 76486470930SIngo Molnar /* 7652e538c4aSArnaldo Carvalho de Melo * So that we look just like we get from .ko files, 7662e538c4aSArnaldo Carvalho de Melo * i.e. not prelinked, relative to map->start. 76786470930SIngo Molnar */ 7684e06255fSArnaldo Carvalho de Melo pos->start = curr_map->map_ip(curr_map, pos->start); 7694e06255fSArnaldo Carvalho de Melo pos->end = curr_map->map_ip(curr_map, pos->end); 7704e06255fSArnaldo Carvalho de Melo } else if (curr_map != map) { 7712e538c4aSArnaldo Carvalho de Melo char dso_name[PATH_MAX]; 772aeafcbafSArnaldo Carvalho de Melo struct dso *ndso; 77386470930SIngo Molnar 774d9b62abaSAdrian Hunter if (delta) { 775d9b62abaSAdrian Hunter /* Kernel was relocated at boot time */ 776d9b62abaSAdrian Hunter pos->start -= delta; 777d9b62abaSAdrian Hunter pos->end -= delta; 778d9b62abaSAdrian Hunter } 779d9b62abaSAdrian Hunter 7808a953312SArnaldo Carvalho de Melo if (count == 0) { 7818a953312SArnaldo Carvalho de Melo curr_map = map; 7828a953312SArnaldo Carvalho de Melo goto filter_symbol; 7838a953312SArnaldo Carvalho de Melo } 7848a953312SArnaldo Carvalho de Melo 785aeafcbafSArnaldo Carvalho de Melo if (dso->kernel == DSO_TYPE_GUEST_KERNEL) 786a1645ce1SZhang, Yanmin snprintf(dso_name, sizeof(dso_name), 787a1645ce1SZhang, Yanmin "[guest.kernel].%d", 788a1645ce1SZhang, Yanmin kernel_range++); 789a1645ce1SZhang, Yanmin else 790a1645ce1SZhang, Yanmin snprintf(dso_name, sizeof(dso_name), 791a1645ce1SZhang, Yanmin "[kernel].%d", 7922e538c4aSArnaldo Carvalho de Melo kernel_range++); 79386470930SIngo Molnar 794aeafcbafSArnaldo Carvalho de Melo ndso = dso__new(dso_name); 795aeafcbafSArnaldo Carvalho de Melo if (ndso == NULL) 7962e538c4aSArnaldo Carvalho de Melo return -1; 7972e538c4aSArnaldo Carvalho de Melo 798aeafcbafSArnaldo Carvalho de Melo ndso->kernel = dso->kernel; 799a1645ce1SZhang, Yanmin 800aeafcbafSArnaldo Carvalho de Melo curr_map = map__new2(pos->start, ndso, map->type); 80137fe5fcbSZhang, Yanmin if (curr_map == NULL) { 802d3a7c489SArnaldo Carvalho de Melo dso__put(ndso); 8032e538c4aSArnaldo Carvalho de Melo return -1; 8042e538c4aSArnaldo Carvalho de Melo } 8052e538c4aSArnaldo Carvalho de Melo 8064e06255fSArnaldo Carvalho de Melo curr_map->map_ip = curr_map->unmap_ip = identity__map_ip; 8079de89fe7SArnaldo Carvalho de Melo map_groups__insert(kmaps, curr_map); 8082e538c4aSArnaldo Carvalho de Melo ++kernel_range; 809d9b62abaSAdrian Hunter } else if (delta) { 810d9b62abaSAdrian Hunter /* Kernel was relocated at boot time */ 811d9b62abaSAdrian Hunter pos->start -= delta; 812d9b62abaSAdrian Hunter pos->end -= delta; 8132e538c4aSArnaldo Carvalho de Melo } 8148a953312SArnaldo Carvalho de Melo filter_symbol: 8154e06255fSArnaldo Carvalho de Melo if (filter && filter(curr_map, pos)) { 8161de8e245SArnaldo Carvalho de Melo discard_symbol: rb_erase(&pos->rb_node, root); 81700a192b3SArnaldo Carvalho de Melo symbol__delete(pos); 8182e538c4aSArnaldo Carvalho de Melo } else { 8194e06255fSArnaldo Carvalho de Melo if (curr_map != map) { 8204e06255fSArnaldo Carvalho de Melo rb_erase(&pos->rb_node, root); 8214e06255fSArnaldo Carvalho de Melo symbols__insert(&curr_map->dso->symbols[curr_map->type], pos); 8228a953312SArnaldo Carvalho de Melo ++moved; 8238a953312SArnaldo Carvalho de Melo } else 8248a953312SArnaldo Carvalho de Melo ++count; 8259974f496SMike Galbraith } 82686470930SIngo Molnar } 82786470930SIngo Molnar 828a1645ce1SZhang, Yanmin if (curr_map != map && 829aeafcbafSArnaldo Carvalho de Melo dso->kernel == DSO_TYPE_GUEST_KERNEL && 83023346f21SArnaldo Carvalho de Melo machine__is_default_guest(kmaps->machine)) { 831a1645ce1SZhang, Yanmin dso__set_loaded(curr_map->dso, curr_map->type); 832a1645ce1SZhang, Yanmin } 833a1645ce1SZhang, Yanmin 8348a953312SArnaldo Carvalho de Melo return count + moved; 83586470930SIngo Molnar } 83686470930SIngo Molnar 8373f067dcaSArnaldo Carvalho de Melo bool symbol__restricted_filename(const char *filename, 838ec80fde7SArnaldo Carvalho de Melo const char *restricted_filename) 839ec80fde7SArnaldo Carvalho de Melo { 840ec80fde7SArnaldo Carvalho de Melo bool restricted = false; 841ec80fde7SArnaldo Carvalho de Melo 842ec80fde7SArnaldo Carvalho de Melo if (symbol_conf.kptr_restrict) { 843ec80fde7SArnaldo Carvalho de Melo char *r = realpath(filename, NULL); 844ec80fde7SArnaldo Carvalho de Melo 845ec80fde7SArnaldo Carvalho de Melo if (r != NULL) { 846ec80fde7SArnaldo Carvalho de Melo restricted = strcmp(r, restricted_filename) == 0; 847ec80fde7SArnaldo Carvalho de Melo free(r); 848ec80fde7SArnaldo Carvalho de Melo return restricted; 849ec80fde7SArnaldo Carvalho de Melo } 850ec80fde7SArnaldo Carvalho de Melo } 851ec80fde7SArnaldo Carvalho de Melo 852ec80fde7SArnaldo Carvalho de Melo return restricted; 853ec80fde7SArnaldo Carvalho de Melo } 854ec80fde7SArnaldo Carvalho de Melo 85552afdaf9SAdrian Hunter struct module_info { 85652afdaf9SAdrian Hunter struct rb_node rb_node; 85752afdaf9SAdrian Hunter char *name; 85852afdaf9SAdrian Hunter u64 start; 85952afdaf9SAdrian Hunter }; 86052afdaf9SAdrian Hunter 86152afdaf9SAdrian Hunter static void add_module(struct module_info *mi, struct rb_root *modules) 86252afdaf9SAdrian Hunter { 86352afdaf9SAdrian Hunter struct rb_node **p = &modules->rb_node; 86452afdaf9SAdrian Hunter struct rb_node *parent = NULL; 86552afdaf9SAdrian Hunter struct module_info *m; 86652afdaf9SAdrian Hunter 86752afdaf9SAdrian Hunter while (*p != NULL) { 86852afdaf9SAdrian Hunter parent = *p; 86952afdaf9SAdrian Hunter m = rb_entry(parent, struct module_info, rb_node); 87052afdaf9SAdrian Hunter if (strcmp(mi->name, m->name) < 0) 87152afdaf9SAdrian Hunter p = &(*p)->rb_left; 87252afdaf9SAdrian Hunter else 87352afdaf9SAdrian Hunter p = &(*p)->rb_right; 87452afdaf9SAdrian Hunter } 87552afdaf9SAdrian Hunter rb_link_node(&mi->rb_node, parent, p); 87652afdaf9SAdrian Hunter rb_insert_color(&mi->rb_node, modules); 87752afdaf9SAdrian Hunter } 87852afdaf9SAdrian Hunter 87952afdaf9SAdrian Hunter static void delete_modules(struct rb_root *modules) 88052afdaf9SAdrian Hunter { 88152afdaf9SAdrian Hunter struct module_info *mi; 88252afdaf9SAdrian Hunter struct rb_node *next = rb_first(modules); 88352afdaf9SAdrian Hunter 88452afdaf9SAdrian Hunter while (next) { 88552afdaf9SAdrian Hunter mi = rb_entry(next, struct module_info, rb_node); 88652afdaf9SAdrian Hunter next = rb_next(&mi->rb_node); 88752afdaf9SAdrian Hunter rb_erase(&mi->rb_node, modules); 88874cf249dSArnaldo Carvalho de Melo zfree(&mi->name); 88952afdaf9SAdrian Hunter free(mi); 89052afdaf9SAdrian Hunter } 89152afdaf9SAdrian Hunter } 89252afdaf9SAdrian Hunter 89352afdaf9SAdrian Hunter static struct module_info *find_module(const char *name, 89452afdaf9SAdrian Hunter struct rb_root *modules) 89552afdaf9SAdrian Hunter { 89652afdaf9SAdrian Hunter struct rb_node *n = modules->rb_node; 89752afdaf9SAdrian Hunter 89852afdaf9SAdrian Hunter while (n) { 89952afdaf9SAdrian Hunter struct module_info *m; 90052afdaf9SAdrian Hunter int cmp; 90152afdaf9SAdrian Hunter 90252afdaf9SAdrian Hunter m = rb_entry(n, struct module_info, rb_node); 90352afdaf9SAdrian Hunter cmp = strcmp(name, m->name); 90452afdaf9SAdrian Hunter if (cmp < 0) 90552afdaf9SAdrian Hunter n = n->rb_left; 90652afdaf9SAdrian Hunter else if (cmp > 0) 90752afdaf9SAdrian Hunter n = n->rb_right; 90852afdaf9SAdrian Hunter else 90952afdaf9SAdrian Hunter return m; 91052afdaf9SAdrian Hunter } 91152afdaf9SAdrian Hunter 91252afdaf9SAdrian Hunter return NULL; 91352afdaf9SAdrian Hunter } 91452afdaf9SAdrian Hunter 91552afdaf9SAdrian Hunter static int __read_proc_modules(void *arg, const char *name, u64 start) 91652afdaf9SAdrian Hunter { 91752afdaf9SAdrian Hunter struct rb_root *modules = arg; 91852afdaf9SAdrian Hunter struct module_info *mi; 91952afdaf9SAdrian Hunter 92052afdaf9SAdrian Hunter mi = zalloc(sizeof(struct module_info)); 92152afdaf9SAdrian Hunter if (!mi) 92252afdaf9SAdrian Hunter return -ENOMEM; 92352afdaf9SAdrian Hunter 92452afdaf9SAdrian Hunter mi->name = strdup(name); 92552afdaf9SAdrian Hunter mi->start = start; 92652afdaf9SAdrian Hunter 92752afdaf9SAdrian Hunter if (!mi->name) { 92852afdaf9SAdrian Hunter free(mi); 92952afdaf9SAdrian Hunter return -ENOMEM; 93052afdaf9SAdrian Hunter } 93152afdaf9SAdrian Hunter 93252afdaf9SAdrian Hunter add_module(mi, modules); 93352afdaf9SAdrian Hunter 93452afdaf9SAdrian Hunter return 0; 93552afdaf9SAdrian Hunter } 93652afdaf9SAdrian Hunter 93752afdaf9SAdrian Hunter static int read_proc_modules(const char *filename, struct rb_root *modules) 93852afdaf9SAdrian Hunter { 93952afdaf9SAdrian Hunter if (symbol__restricted_filename(filename, "/proc/modules")) 94052afdaf9SAdrian Hunter return -1; 94152afdaf9SAdrian Hunter 94252afdaf9SAdrian Hunter if (modules__parse(filename, modules, __read_proc_modules)) { 94352afdaf9SAdrian Hunter delete_modules(modules); 94452afdaf9SAdrian Hunter return -1; 94552afdaf9SAdrian Hunter } 94652afdaf9SAdrian Hunter 94752afdaf9SAdrian Hunter return 0; 94852afdaf9SAdrian Hunter } 94952afdaf9SAdrian Hunter 950fc1b691dSAdrian Hunter int compare_proc_modules(const char *from, const char *to) 951fc1b691dSAdrian Hunter { 952fc1b691dSAdrian Hunter struct rb_root from_modules = RB_ROOT; 953fc1b691dSAdrian Hunter struct rb_root to_modules = RB_ROOT; 954fc1b691dSAdrian Hunter struct rb_node *from_node, *to_node; 955fc1b691dSAdrian Hunter struct module_info *from_m, *to_m; 956fc1b691dSAdrian Hunter int ret = -1; 957fc1b691dSAdrian Hunter 958fc1b691dSAdrian Hunter if (read_proc_modules(from, &from_modules)) 959fc1b691dSAdrian Hunter return -1; 960fc1b691dSAdrian Hunter 961fc1b691dSAdrian Hunter if (read_proc_modules(to, &to_modules)) 962fc1b691dSAdrian Hunter goto out_delete_from; 963fc1b691dSAdrian Hunter 964fc1b691dSAdrian Hunter from_node = rb_first(&from_modules); 965fc1b691dSAdrian Hunter to_node = rb_first(&to_modules); 966fc1b691dSAdrian Hunter while (from_node) { 967fc1b691dSAdrian Hunter if (!to_node) 968fc1b691dSAdrian Hunter break; 969fc1b691dSAdrian Hunter 970fc1b691dSAdrian Hunter from_m = rb_entry(from_node, struct module_info, rb_node); 971fc1b691dSAdrian Hunter to_m = rb_entry(to_node, struct module_info, rb_node); 972fc1b691dSAdrian Hunter 973fc1b691dSAdrian Hunter if (from_m->start != to_m->start || 974fc1b691dSAdrian Hunter strcmp(from_m->name, to_m->name)) 975fc1b691dSAdrian Hunter break; 976fc1b691dSAdrian Hunter 977fc1b691dSAdrian Hunter from_node = rb_next(from_node); 978fc1b691dSAdrian Hunter to_node = rb_next(to_node); 979fc1b691dSAdrian Hunter } 980fc1b691dSAdrian Hunter 981fc1b691dSAdrian Hunter if (!from_node && !to_node) 982fc1b691dSAdrian Hunter ret = 0; 983fc1b691dSAdrian Hunter 984fc1b691dSAdrian Hunter delete_modules(&to_modules); 985fc1b691dSAdrian Hunter out_delete_from: 986fc1b691dSAdrian Hunter delete_modules(&from_modules); 987fc1b691dSAdrian Hunter 988fc1b691dSAdrian Hunter return ret; 989fc1b691dSAdrian Hunter } 990fc1b691dSAdrian Hunter 99152afdaf9SAdrian Hunter static int do_validate_kcore_modules(const char *filename, struct map *map, 99252afdaf9SAdrian Hunter struct map_groups *kmaps) 99352afdaf9SAdrian Hunter { 99452afdaf9SAdrian Hunter struct rb_root modules = RB_ROOT; 99552afdaf9SAdrian Hunter struct map *old_map; 99652afdaf9SAdrian Hunter int err; 99752afdaf9SAdrian Hunter 99852afdaf9SAdrian Hunter err = read_proc_modules(filename, &modules); 99952afdaf9SAdrian Hunter if (err) 100052afdaf9SAdrian Hunter return err; 100152afdaf9SAdrian Hunter 100252afdaf9SAdrian Hunter old_map = map_groups__first(kmaps, map->type); 100352afdaf9SAdrian Hunter while (old_map) { 100452afdaf9SAdrian Hunter struct map *next = map_groups__next(old_map); 100552afdaf9SAdrian Hunter struct module_info *mi; 100652afdaf9SAdrian Hunter 100752afdaf9SAdrian Hunter if (old_map == map || old_map->start == map->start) { 100852afdaf9SAdrian Hunter /* The kernel map */ 100952afdaf9SAdrian Hunter old_map = next; 101052afdaf9SAdrian Hunter continue; 101152afdaf9SAdrian Hunter } 101252afdaf9SAdrian Hunter 101352afdaf9SAdrian Hunter /* Module must be in memory at the same address */ 101452afdaf9SAdrian Hunter mi = find_module(old_map->dso->short_name, &modules); 101552afdaf9SAdrian Hunter if (!mi || mi->start != old_map->start) { 101652afdaf9SAdrian Hunter err = -EINVAL; 101752afdaf9SAdrian Hunter goto out; 101852afdaf9SAdrian Hunter } 101952afdaf9SAdrian Hunter 102052afdaf9SAdrian Hunter old_map = next; 102152afdaf9SAdrian Hunter } 102252afdaf9SAdrian Hunter out: 102352afdaf9SAdrian Hunter delete_modules(&modules); 102452afdaf9SAdrian Hunter return err; 102552afdaf9SAdrian Hunter } 102652afdaf9SAdrian Hunter 102752afdaf9SAdrian Hunter /* 102852afdaf9SAdrian Hunter * If kallsyms is referenced by name then we look for filename in the same 102952afdaf9SAdrian Hunter * directory. 103052afdaf9SAdrian Hunter */ 103152afdaf9SAdrian Hunter static bool filename_from_kallsyms_filename(char *filename, 103252afdaf9SAdrian Hunter const char *base_name, 103352afdaf9SAdrian Hunter const char *kallsyms_filename) 103452afdaf9SAdrian Hunter { 103552afdaf9SAdrian Hunter char *name; 103652afdaf9SAdrian Hunter 103752afdaf9SAdrian Hunter strcpy(filename, kallsyms_filename); 103852afdaf9SAdrian Hunter name = strrchr(filename, '/'); 103952afdaf9SAdrian Hunter if (!name) 104052afdaf9SAdrian Hunter return false; 104152afdaf9SAdrian Hunter 104252afdaf9SAdrian Hunter name += 1; 104352afdaf9SAdrian Hunter 104452afdaf9SAdrian Hunter if (!strcmp(name, "kallsyms")) { 104552afdaf9SAdrian Hunter strcpy(name, base_name); 104652afdaf9SAdrian Hunter return true; 104752afdaf9SAdrian Hunter } 104852afdaf9SAdrian Hunter 104952afdaf9SAdrian Hunter return false; 105052afdaf9SAdrian Hunter } 105152afdaf9SAdrian Hunter 105252afdaf9SAdrian Hunter static int validate_kcore_modules(const char *kallsyms_filename, 105352afdaf9SAdrian Hunter struct map *map) 105452afdaf9SAdrian Hunter { 1055ba92732eSWang Nan struct map_groups *kmaps = map__kmaps(map); 105652afdaf9SAdrian Hunter char modules_filename[PATH_MAX]; 105752afdaf9SAdrian Hunter 1058ba92732eSWang Nan if (!kmaps) 1059ba92732eSWang Nan return -EINVAL; 1060ba92732eSWang Nan 106152afdaf9SAdrian Hunter if (!filename_from_kallsyms_filename(modules_filename, "modules", 106252afdaf9SAdrian Hunter kallsyms_filename)) 106352afdaf9SAdrian Hunter return -EINVAL; 106452afdaf9SAdrian Hunter 106552afdaf9SAdrian Hunter if (do_validate_kcore_modules(modules_filename, map, kmaps)) 106652afdaf9SAdrian Hunter return -EINVAL; 106752afdaf9SAdrian Hunter 106852afdaf9SAdrian Hunter return 0; 106952afdaf9SAdrian Hunter } 107052afdaf9SAdrian Hunter 1071a00d28cbSAdrian Hunter static int validate_kcore_addresses(const char *kallsyms_filename, 1072a00d28cbSAdrian Hunter struct map *map) 1073a00d28cbSAdrian Hunter { 1074a00d28cbSAdrian Hunter struct kmap *kmap = map__kmap(map); 1075a00d28cbSAdrian Hunter 1076ba92732eSWang Nan if (!kmap) 1077ba92732eSWang Nan return -EINVAL; 1078ba92732eSWang Nan 1079a00d28cbSAdrian Hunter if (kmap->ref_reloc_sym && kmap->ref_reloc_sym->name) { 1080a00d28cbSAdrian Hunter u64 start; 1081a00d28cbSAdrian Hunter 1082a00d28cbSAdrian Hunter start = kallsyms__get_function_start(kallsyms_filename, 1083a00d28cbSAdrian Hunter kmap->ref_reloc_sym->name); 1084a00d28cbSAdrian Hunter if (start != kmap->ref_reloc_sym->addr) 1085a00d28cbSAdrian Hunter return -EINVAL; 1086a00d28cbSAdrian Hunter } 1087a00d28cbSAdrian Hunter 1088a00d28cbSAdrian Hunter return validate_kcore_modules(kallsyms_filename, map); 1089a00d28cbSAdrian Hunter } 1090a00d28cbSAdrian Hunter 10918e0cf965SAdrian Hunter struct kcore_mapfn_data { 10928e0cf965SAdrian Hunter struct dso *dso; 10938e0cf965SAdrian Hunter enum map_type type; 10948e0cf965SAdrian Hunter struct list_head maps; 10958e0cf965SAdrian Hunter }; 10968e0cf965SAdrian Hunter 10978e0cf965SAdrian Hunter static int kcore_mapfn(u64 start, u64 len, u64 pgoff, void *data) 10988e0cf965SAdrian Hunter { 10998e0cf965SAdrian Hunter struct kcore_mapfn_data *md = data; 11008e0cf965SAdrian Hunter struct map *map; 11018e0cf965SAdrian Hunter 11028e0cf965SAdrian Hunter map = map__new2(start, md->dso, md->type); 11038e0cf965SAdrian Hunter if (map == NULL) 11048e0cf965SAdrian Hunter return -ENOMEM; 11058e0cf965SAdrian Hunter 11068e0cf965SAdrian Hunter map->end = map->start + len; 11078e0cf965SAdrian Hunter map->pgoff = pgoff; 11088e0cf965SAdrian Hunter 11098e0cf965SAdrian Hunter list_add(&map->node, &md->maps); 11108e0cf965SAdrian Hunter 11118e0cf965SAdrian Hunter return 0; 11128e0cf965SAdrian Hunter } 11138e0cf965SAdrian Hunter 11148e0cf965SAdrian Hunter static int dso__load_kcore(struct dso *dso, struct map *map, 11158e0cf965SAdrian Hunter const char *kallsyms_filename) 11168e0cf965SAdrian Hunter { 1117ba92732eSWang Nan struct map_groups *kmaps = map__kmaps(map); 1118ba92732eSWang Nan struct machine *machine; 11198e0cf965SAdrian Hunter struct kcore_mapfn_data md; 11208e0cf965SAdrian Hunter struct map *old_map, *new_map, *replacement_map = NULL; 11218e0cf965SAdrian Hunter bool is_64_bit; 11228e0cf965SAdrian Hunter int err, fd; 11238e0cf965SAdrian Hunter char kcore_filename[PATH_MAX]; 11248e0cf965SAdrian Hunter struct symbol *sym; 11258e0cf965SAdrian Hunter 1126ba92732eSWang Nan if (!kmaps) 1127ba92732eSWang Nan return -EINVAL; 1128ba92732eSWang Nan 1129ba92732eSWang Nan machine = kmaps->machine; 1130ba92732eSWang Nan 11318e0cf965SAdrian Hunter /* This function requires that the map is the kernel map */ 11328e0cf965SAdrian Hunter if (map != machine->vmlinux_maps[map->type]) 11338e0cf965SAdrian Hunter return -EINVAL; 11348e0cf965SAdrian Hunter 113552afdaf9SAdrian Hunter if (!filename_from_kallsyms_filename(kcore_filename, "kcore", 11368e0cf965SAdrian Hunter kallsyms_filename)) 11378e0cf965SAdrian Hunter return -EINVAL; 11388e0cf965SAdrian Hunter 1139a00d28cbSAdrian Hunter /* Modules and kernel must be present at their original addresses */ 1140a00d28cbSAdrian Hunter if (validate_kcore_addresses(kallsyms_filename, map)) 114152afdaf9SAdrian Hunter return -EINVAL; 114252afdaf9SAdrian Hunter 11438e0cf965SAdrian Hunter md.dso = dso; 11448e0cf965SAdrian Hunter md.type = map->type; 11458e0cf965SAdrian Hunter INIT_LIST_HEAD(&md.maps); 11468e0cf965SAdrian Hunter 11478e0cf965SAdrian Hunter fd = open(kcore_filename, O_RDONLY); 114836c8bb56SLi Zhang if (fd < 0) { 1149133de940SAdrian Hunter pr_debug("Failed to open %s. Note /proc/kcore requires CAP_SYS_RAWIO capability to access.\n", 115036c8bb56SLi Zhang kcore_filename); 11518e0cf965SAdrian Hunter return -EINVAL; 115236c8bb56SLi Zhang } 11538e0cf965SAdrian Hunter 11548e0cf965SAdrian Hunter /* Read new maps into temporary lists */ 11558e0cf965SAdrian Hunter err = file__read_maps(fd, md.type == MAP__FUNCTION, kcore_mapfn, &md, 11568e0cf965SAdrian Hunter &is_64_bit); 11578e0cf965SAdrian Hunter if (err) 11588e0cf965SAdrian Hunter goto out_err; 1159c6d8f2a4SAdrian Hunter dso->is_64_bit = is_64_bit; 11608e0cf965SAdrian Hunter 11618e0cf965SAdrian Hunter if (list_empty(&md.maps)) { 11628e0cf965SAdrian Hunter err = -EINVAL; 11638e0cf965SAdrian Hunter goto out_err; 11648e0cf965SAdrian Hunter } 11658e0cf965SAdrian Hunter 11668e0cf965SAdrian Hunter /* Remove old maps */ 11678e0cf965SAdrian Hunter old_map = map_groups__first(kmaps, map->type); 11688e0cf965SAdrian Hunter while (old_map) { 11698e0cf965SAdrian Hunter struct map *next = map_groups__next(old_map); 11708e0cf965SAdrian Hunter 11718e0cf965SAdrian Hunter if (old_map != map) 11728e0cf965SAdrian Hunter map_groups__remove(kmaps, old_map); 11738e0cf965SAdrian Hunter old_map = next; 11748e0cf965SAdrian Hunter } 11758e0cf965SAdrian Hunter 11768e0cf965SAdrian Hunter /* Find the kernel map using the first symbol */ 11778e0cf965SAdrian Hunter sym = dso__first_symbol(dso, map->type); 11788e0cf965SAdrian Hunter list_for_each_entry(new_map, &md.maps, node) { 11798e0cf965SAdrian Hunter if (sym && sym->start >= new_map->start && 11808e0cf965SAdrian Hunter sym->start < new_map->end) { 11818e0cf965SAdrian Hunter replacement_map = new_map; 11828e0cf965SAdrian Hunter break; 11838e0cf965SAdrian Hunter } 11848e0cf965SAdrian Hunter } 11858e0cf965SAdrian Hunter 11868e0cf965SAdrian Hunter if (!replacement_map) 11878e0cf965SAdrian Hunter replacement_map = list_entry(md.maps.next, struct map, node); 11888e0cf965SAdrian Hunter 11898e0cf965SAdrian Hunter /* Add new maps */ 11908e0cf965SAdrian Hunter while (!list_empty(&md.maps)) { 11918e0cf965SAdrian Hunter new_map = list_entry(md.maps.next, struct map, node); 1192facf3f06SArnaldo Carvalho de Melo list_del_init(&new_map->node); 11938e0cf965SAdrian Hunter if (new_map == replacement_map) { 11948e0cf965SAdrian Hunter map->start = new_map->start; 11958e0cf965SAdrian Hunter map->end = new_map->end; 11968e0cf965SAdrian Hunter map->pgoff = new_map->pgoff; 11978e0cf965SAdrian Hunter map->map_ip = new_map->map_ip; 11988e0cf965SAdrian Hunter map->unmap_ip = new_map->unmap_ip; 11998e0cf965SAdrian Hunter /* Ensure maps are correctly ordered */ 120084c2cafaSArnaldo Carvalho de Melo map__get(map); 12018e0cf965SAdrian Hunter map_groups__remove(kmaps, map); 12028e0cf965SAdrian Hunter map_groups__insert(kmaps, map); 120384c2cafaSArnaldo Carvalho de Melo map__put(map); 12048e0cf965SAdrian Hunter } else { 12058e0cf965SAdrian Hunter map_groups__insert(kmaps, new_map); 12068e0cf965SAdrian Hunter } 120784c2cafaSArnaldo Carvalho de Melo 120884c2cafaSArnaldo Carvalho de Melo map__put(new_map); 12098e0cf965SAdrian Hunter } 12108e0cf965SAdrian Hunter 12118e0cf965SAdrian Hunter /* 12128e0cf965SAdrian Hunter * Set the data type and long name so that kcore can be read via 12138e0cf965SAdrian Hunter * dso__data_read_addr(). 12148e0cf965SAdrian Hunter */ 12158e0cf965SAdrian Hunter if (dso->kernel == DSO_TYPE_GUEST_KERNEL) 12165f70619dSArnaldo Carvalho de Melo dso->binary_type = DSO_BINARY_TYPE__GUEST_KCORE; 12178e0cf965SAdrian Hunter else 12185f70619dSArnaldo Carvalho de Melo dso->binary_type = DSO_BINARY_TYPE__KCORE; 12197e155d4dSArnaldo Carvalho de Melo dso__set_long_name(dso, strdup(kcore_filename), true); 12208e0cf965SAdrian Hunter 12218e0cf965SAdrian Hunter close(fd); 12228e0cf965SAdrian Hunter 12238e0cf965SAdrian Hunter if (map->type == MAP__FUNCTION) 12248e0cf965SAdrian Hunter pr_debug("Using %s for kernel object code\n", kcore_filename); 12258e0cf965SAdrian Hunter else 12268e0cf965SAdrian Hunter pr_debug("Using %s for kernel data\n", kcore_filename); 12278e0cf965SAdrian Hunter 12288e0cf965SAdrian Hunter return 0; 12298e0cf965SAdrian Hunter 12308e0cf965SAdrian Hunter out_err: 12318e0cf965SAdrian Hunter while (!list_empty(&md.maps)) { 12328e0cf965SAdrian Hunter map = list_entry(md.maps.next, struct map, node); 1233facf3f06SArnaldo Carvalho de Melo list_del_init(&map->node); 123484c2cafaSArnaldo Carvalho de Melo map__put(map); 12358e0cf965SAdrian Hunter } 12368e0cf965SAdrian Hunter close(fd); 12378e0cf965SAdrian Hunter return -EINVAL; 12388e0cf965SAdrian Hunter } 12398e0cf965SAdrian Hunter 1240d9b62abaSAdrian Hunter /* 1241d9b62abaSAdrian Hunter * If the kernel is relocated at boot time, kallsyms won't match. Compute the 1242d9b62abaSAdrian Hunter * delta based on the relocation reference symbol. 1243d9b62abaSAdrian Hunter */ 1244d9b62abaSAdrian Hunter static int kallsyms__delta(struct map *map, const char *filename, u64 *delta) 1245d9b62abaSAdrian Hunter { 1246d9b62abaSAdrian Hunter struct kmap *kmap = map__kmap(map); 1247d9b62abaSAdrian Hunter u64 addr; 1248d9b62abaSAdrian Hunter 1249ba92732eSWang Nan if (!kmap) 1250ba92732eSWang Nan return -1; 1251ba92732eSWang Nan 1252d9b62abaSAdrian Hunter if (!kmap->ref_reloc_sym || !kmap->ref_reloc_sym->name) 1253d9b62abaSAdrian Hunter return 0; 1254d9b62abaSAdrian Hunter 1255d9b62abaSAdrian Hunter addr = kallsyms__get_function_start(filename, 1256d9b62abaSAdrian Hunter kmap->ref_reloc_sym->name); 1257d9b62abaSAdrian Hunter if (!addr) 1258d9b62abaSAdrian Hunter return -1; 1259d9b62abaSAdrian Hunter 1260d9b62abaSAdrian Hunter *delta = addr - kmap->ref_reloc_sym->addr; 1261d9b62abaSAdrian Hunter return 0; 1262d9b62abaSAdrian Hunter } 1263d9b62abaSAdrian Hunter 1264aeafcbafSArnaldo Carvalho de Melo int dso__load_kallsyms(struct dso *dso, const char *filename, 12659de89fe7SArnaldo Carvalho de Melo struct map *map, symbol_filter_t filter) 12662e538c4aSArnaldo Carvalho de Melo { 1267d9b62abaSAdrian Hunter u64 delta = 0; 1268d9b62abaSAdrian Hunter 1269ec80fde7SArnaldo Carvalho de Melo if (symbol__restricted_filename(filename, "/proc/kallsyms")) 1270ec80fde7SArnaldo Carvalho de Melo return -1; 1271ec80fde7SArnaldo Carvalho de Melo 1272aeafcbafSArnaldo Carvalho de Melo if (dso__load_all_kallsyms(dso, filename, map) < 0) 12732e538c4aSArnaldo Carvalho de Melo return -1; 12742e538c4aSArnaldo Carvalho de Melo 1275d9b62abaSAdrian Hunter if (kallsyms__delta(map, filename, &delta)) 1276d9b62abaSAdrian Hunter return -1; 1277d9b62abaSAdrian Hunter 1278694bf407SAnton Blanchard symbols__fixup_duplicate(&dso->symbols[map->type]); 12793f5a4272SAnton Blanchard symbols__fixup_end(&dso->symbols[map->type]); 12803f5a4272SAnton Blanchard 1281aeafcbafSArnaldo Carvalho de Melo if (dso->kernel == DSO_TYPE_GUEST_KERNEL) 128244f24cb3SJiri Olsa dso->symtab_type = DSO_BINARY_TYPE__GUEST_KALLSYMS; 1283a1645ce1SZhang, Yanmin else 128444f24cb3SJiri Olsa dso->symtab_type = DSO_BINARY_TYPE__KALLSYMS; 12852e538c4aSArnaldo Carvalho de Melo 12868e0cf965SAdrian Hunter if (!dso__load_kcore(dso, map, filename)) 12878e0cf965SAdrian Hunter return dso__split_kallsyms_for_kcore(dso, map, filter); 12888e0cf965SAdrian Hunter else 1289d9b62abaSAdrian Hunter return dso__split_kallsyms(dso, map, delta, filter); 1290af427bf5SArnaldo Carvalho de Melo } 1291af427bf5SArnaldo Carvalho de Melo 1292aeafcbafSArnaldo Carvalho de Melo static int dso__load_perf_map(struct dso *dso, struct map *map, 12936beba7adSArnaldo Carvalho de Melo symbol_filter_t filter) 129480d496beSPekka Enberg { 129580d496beSPekka Enberg char *line = NULL; 129680d496beSPekka Enberg size_t n; 129780d496beSPekka Enberg FILE *file; 129880d496beSPekka Enberg int nr_syms = 0; 129980d496beSPekka Enberg 1300aeafcbafSArnaldo Carvalho de Melo file = fopen(dso->long_name, "r"); 130180d496beSPekka Enberg if (file == NULL) 130280d496beSPekka Enberg goto out_failure; 130380d496beSPekka Enberg 130480d496beSPekka Enberg while (!feof(file)) { 13059cffa8d5SPaul Mackerras u64 start, size; 130680d496beSPekka Enberg struct symbol *sym; 130780d496beSPekka Enberg int line_len, len; 130880d496beSPekka Enberg 130980d496beSPekka Enberg line_len = getline(&line, &n, file); 131080d496beSPekka Enberg if (line_len < 0) 131180d496beSPekka Enberg break; 131280d496beSPekka Enberg 131380d496beSPekka Enberg if (!line) 131480d496beSPekka Enberg goto out_failure; 131580d496beSPekka Enberg 131680d496beSPekka Enberg line[--line_len] = '\0'; /* \n */ 131780d496beSPekka Enberg 131880d496beSPekka Enberg len = hex2u64(line, &start); 131980d496beSPekka Enberg 132080d496beSPekka Enberg len++; 132180d496beSPekka Enberg if (len + 2 >= line_len) 132280d496beSPekka Enberg continue; 132380d496beSPekka Enberg 132480d496beSPekka Enberg len += hex2u64(line + len, &size); 132580d496beSPekka Enberg 132680d496beSPekka Enberg len++; 132780d496beSPekka Enberg if (len + 2 >= line_len) 132880d496beSPekka Enberg continue; 132980d496beSPekka Enberg 1330c408fedfSArnaldo Carvalho de Melo sym = symbol__new(start, size, STB_GLOBAL, line + len); 133180d496beSPekka Enberg 133280d496beSPekka Enberg if (sym == NULL) 133380d496beSPekka Enberg goto out_delete_line; 133480d496beSPekka Enberg 1335439d473bSArnaldo Carvalho de Melo if (filter && filter(map, sym)) 133600a192b3SArnaldo Carvalho de Melo symbol__delete(sym); 133780d496beSPekka Enberg else { 1338aeafcbafSArnaldo Carvalho de Melo symbols__insert(&dso->symbols[map->type], sym); 133980d496beSPekka Enberg nr_syms++; 134080d496beSPekka Enberg } 134180d496beSPekka Enberg } 134280d496beSPekka Enberg 134380d496beSPekka Enberg free(line); 134480d496beSPekka Enberg fclose(file); 134580d496beSPekka Enberg 134680d496beSPekka Enberg return nr_syms; 134780d496beSPekka Enberg 134880d496beSPekka Enberg out_delete_line: 134980d496beSPekka Enberg free(line); 135080d496beSPekka Enberg out_failure: 135180d496beSPekka Enberg return -1; 135280d496beSPekka Enberg } 135380d496beSPekka Enberg 13541029f9feSNamhyung Kim static bool dso__is_compatible_symtab_type(struct dso *dso, bool kmod, 13551029f9feSNamhyung Kim enum dso_binary_type type) 13561029f9feSNamhyung Kim { 13571029f9feSNamhyung Kim switch (type) { 13581029f9feSNamhyung Kim case DSO_BINARY_TYPE__JAVA_JIT: 13591029f9feSNamhyung Kim case DSO_BINARY_TYPE__DEBUGLINK: 13601029f9feSNamhyung Kim case DSO_BINARY_TYPE__SYSTEM_PATH_DSO: 13611029f9feSNamhyung Kim case DSO_BINARY_TYPE__FEDORA_DEBUGINFO: 13621029f9feSNamhyung Kim case DSO_BINARY_TYPE__UBUNTU_DEBUGINFO: 13631029f9feSNamhyung Kim case DSO_BINARY_TYPE__BUILDID_DEBUGINFO: 13641029f9feSNamhyung Kim case DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO: 13651029f9feSNamhyung Kim return !kmod && dso->kernel == DSO_TYPE_USER; 13661029f9feSNamhyung Kim 13671029f9feSNamhyung Kim case DSO_BINARY_TYPE__KALLSYMS: 13681029f9feSNamhyung Kim case DSO_BINARY_TYPE__VMLINUX: 13691029f9feSNamhyung Kim case DSO_BINARY_TYPE__KCORE: 13701029f9feSNamhyung Kim return dso->kernel == DSO_TYPE_KERNEL; 13711029f9feSNamhyung Kim 13721029f9feSNamhyung Kim case DSO_BINARY_TYPE__GUEST_KALLSYMS: 13731029f9feSNamhyung Kim case DSO_BINARY_TYPE__GUEST_VMLINUX: 13741029f9feSNamhyung Kim case DSO_BINARY_TYPE__GUEST_KCORE: 13751029f9feSNamhyung Kim return dso->kernel == DSO_TYPE_GUEST_KERNEL; 13761029f9feSNamhyung Kim 13771029f9feSNamhyung Kim case DSO_BINARY_TYPE__GUEST_KMODULE: 1378c00c48fcSNamhyung Kim case DSO_BINARY_TYPE__GUEST_KMODULE_COMP: 13791029f9feSNamhyung Kim case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE: 1380c00c48fcSNamhyung Kim case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP: 13811029f9feSNamhyung Kim /* 13821029f9feSNamhyung Kim * kernel modules know their symtab type - it's set when 13839f2de315SArnaldo Carvalho de Melo * creating a module dso in machine__findnew_module_map(). 13841029f9feSNamhyung Kim */ 13851029f9feSNamhyung Kim return kmod && dso->symtab_type == type; 13861029f9feSNamhyung Kim 13871029f9feSNamhyung Kim case DSO_BINARY_TYPE__BUILD_ID_CACHE: 13881029f9feSNamhyung Kim return true; 13891029f9feSNamhyung Kim 13901029f9feSNamhyung Kim case DSO_BINARY_TYPE__NOT_FOUND: 13911029f9feSNamhyung Kim default: 13921029f9feSNamhyung Kim return false; 13931029f9feSNamhyung Kim } 13941029f9feSNamhyung Kim } 13951029f9feSNamhyung Kim 1396aeafcbafSArnaldo Carvalho de Melo int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter) 139786470930SIngo Molnar { 1398c338aee8SArnaldo Carvalho de Melo char *name; 139986470930SIngo Molnar int ret = -1; 140044f24cb3SJiri Olsa u_int i; 140123346f21SArnaldo Carvalho de Melo struct machine *machine; 140244f24cb3SJiri Olsa char *root_dir = (char *) ""; 14033aafe5aeSCody P Schafer int ss_pos = 0; 14043aafe5aeSCody P Schafer struct symsrc ss_[2]; 14053aafe5aeSCody P Schafer struct symsrc *syms_ss = NULL, *runtime_ss = NULL; 14061029f9feSNamhyung Kim bool kmod; 14075baecbcdSDima Kogan unsigned char build_id[BUILD_ID_SIZE]; 140886470930SIngo Molnar 14094a936edcSNamhyung Kim pthread_mutex_lock(&dso->lock); 141066bd8424SArnaldo Carvalho de Melo 14114a936edcSNamhyung Kim /* check again under the dso->lock */ 14124a936edcSNamhyung Kim if (dso__loaded(dso, map->type)) { 14134a936edcSNamhyung Kim ret = 1; 14144a936edcSNamhyung Kim goto out; 14154a936edcSNamhyung Kim } 14164a936edcSNamhyung Kim 14174a936edcSNamhyung Kim if (dso->kernel) { 1418aeafcbafSArnaldo Carvalho de Melo if (dso->kernel == DSO_TYPE_KERNEL) 14194a936edcSNamhyung Kim ret = dso__load_kernel_sym(dso, map, filter); 1420aeafcbafSArnaldo Carvalho de Melo else if (dso->kernel == DSO_TYPE_GUEST_KERNEL) 14214a936edcSNamhyung Kim ret = dso__load_guest_kernel_sym(dso, map, filter); 14224a936edcSNamhyung Kim 14234a936edcSNamhyung Kim goto out; 14244a936edcSNamhyung Kim } 1425a1645ce1SZhang, Yanmin 142623346f21SArnaldo Carvalho de Melo if (map->groups && map->groups->machine) 142723346f21SArnaldo Carvalho de Melo machine = map->groups->machine; 1428a1645ce1SZhang, Yanmin else 142923346f21SArnaldo Carvalho de Melo machine = NULL; 1430c338aee8SArnaldo Carvalho de Melo 1431aeafcbafSArnaldo Carvalho de Melo dso->adjust_symbols = 0; 1432f5812a7aSArnaldo Carvalho de Melo 1433aeafcbafSArnaldo Carvalho de Melo if (strncmp(dso->name, "/tmp/perf-", 10) == 0) { 1434981c1252SPekka Enberg struct stat st; 1435981c1252SPekka Enberg 1436e9b52ef2SVasiliy Kulikov if (lstat(dso->name, &st) < 0) 14374a936edcSNamhyung Kim goto out; 1438981c1252SPekka Enberg 1439*2059fc7aSArnaldo Carvalho de Melo if (!symbol_conf.force && st.st_uid && (st.st_uid != geteuid())) { 1440981c1252SPekka Enberg pr_warning("File %s not owned by current user or root, " 1441*2059fc7aSArnaldo Carvalho de Melo "ignoring it (use -f to override).\n", dso->name); 14424a936edcSNamhyung Kim goto out; 1443981c1252SPekka Enberg } 1444981c1252SPekka Enberg 1445aeafcbafSArnaldo Carvalho de Melo ret = dso__load_perf_map(dso, map, filter); 144644f24cb3SJiri Olsa dso->symtab_type = ret > 0 ? DSO_BINARY_TYPE__JAVA_JIT : 144744f24cb3SJiri Olsa DSO_BINARY_TYPE__NOT_FOUND; 14484a936edcSNamhyung Kim goto out; 144994cb9e38SArnaldo Carvalho de Melo } 145094cb9e38SArnaldo Carvalho de Melo 145144f24cb3SJiri Olsa if (machine) 145244f24cb3SJiri Olsa root_dir = machine->root_dir; 145344f24cb3SJiri Olsa 1454164c800eSDavid Ahern name = malloc(PATH_MAX); 1455164c800eSDavid Ahern if (!name) 14564a936edcSNamhyung Kim goto out; 1457164c800eSDavid Ahern 14581029f9feSNamhyung Kim kmod = dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE || 1459c00c48fcSNamhyung Kim dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP || 1460c00c48fcSNamhyung Kim dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE || 1461c00c48fcSNamhyung Kim dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE_COMP; 14621029f9feSNamhyung Kim 14635baecbcdSDima Kogan 14645baecbcdSDima Kogan /* 14655baecbcdSDima Kogan * Read the build id if possible. This is required for 14665baecbcdSDima Kogan * DSO_BINARY_TYPE__BUILDID_DEBUGINFO to work 14675baecbcdSDima Kogan */ 14685baecbcdSDima Kogan if (filename__read_build_id(dso->name, build_id, BUILD_ID_SIZE) > 0) 14695baecbcdSDima Kogan dso__set_build_id(dso, build_id); 14705baecbcdSDima Kogan 14711029f9feSNamhyung Kim /* 14721029f9feSNamhyung Kim * Iterate over candidate debug images. 14733aafe5aeSCody P Schafer * Keep track of "interesting" ones (those which have a symtab, dynsym, 14743aafe5aeSCody P Schafer * and/or opd section) for processing. 14756da80ce8SDave Martin */ 147644f24cb3SJiri Olsa for (i = 0; i < DSO_BINARY_TYPE__SYMTAB_CNT; i++) { 14773aafe5aeSCody P Schafer struct symsrc *ss = &ss_[ss_pos]; 14783aafe5aeSCody P Schafer bool next_slot = false; 147944f24cb3SJiri Olsa 1480005f9294SCody P Schafer enum dso_binary_type symtab_type = binary_type_symtab[i]; 148144f24cb3SJiri Olsa 14821029f9feSNamhyung Kim if (!dso__is_compatible_symtab_type(dso, kmod, symtab_type)) 14831029f9feSNamhyung Kim continue; 14841029f9feSNamhyung Kim 1485ee4e9625SArnaldo Carvalho de Melo if (dso__read_binary_type_filename(dso, symtab_type, 148644f24cb3SJiri Olsa root_dir, name, PATH_MAX)) 14876da80ce8SDave Martin continue; 148886470930SIngo Molnar 14896da80ce8SDave Martin /* Name is now the name of the next image to try */ 14903aafe5aeSCody P Schafer if (symsrc__init(ss, dso, name, symtab_type) < 0) 14916da80ce8SDave Martin continue; 14926da80ce8SDave Martin 14933aafe5aeSCody P Schafer if (!syms_ss && symsrc__has_symtab(ss)) { 14943aafe5aeSCody P Schafer syms_ss = ss; 14953aafe5aeSCody P Schafer next_slot = true; 14960058aef6SAdrian Hunter if (!dso->symsrc_filename) 14970058aef6SAdrian Hunter dso->symsrc_filename = strdup(name); 1498d26cd12bSCody P Schafer } 1499d26cd12bSCody P Schafer 15003aafe5aeSCody P Schafer if (!runtime_ss && symsrc__possibly_runtime(ss)) { 15013aafe5aeSCody P Schafer runtime_ss = ss; 15023aafe5aeSCody P Schafer next_slot = true; 1503a44f605bSCody P Schafer } 150486470930SIngo Molnar 15053aafe5aeSCody P Schafer if (next_slot) { 15063aafe5aeSCody P Schafer ss_pos++; 150733ff581eSJiri Olsa 15083aafe5aeSCody P Schafer if (syms_ss && runtime_ss) 15096da80ce8SDave Martin break; 151098e9f03bSNamhyung Kim } else { 151198e9f03bSNamhyung Kim symsrc__destroy(ss); 1512a25e46c4SArnaldo Carvalho de Melo } 15133aafe5aeSCody P Schafer 15146da80ce8SDave Martin } 15156da80ce8SDave Martin 15163aafe5aeSCody P Schafer if (!runtime_ss && !syms_ss) 15173aafe5aeSCody P Schafer goto out_free; 15183aafe5aeSCody P Schafer 15193aafe5aeSCody P Schafer if (runtime_ss && !syms_ss) { 15203aafe5aeSCody P Schafer syms_ss = runtime_ss; 152160e4b10cSArnaldo Carvalho de Melo } 152260e4b10cSArnaldo Carvalho de Melo 15233aafe5aeSCody P Schafer /* We'll have to hope for the best */ 15243aafe5aeSCody P Schafer if (!runtime_ss && syms_ss) 15253aafe5aeSCody P Schafer runtime_ss = syms_ss; 15263aafe5aeSCody P Schafer 15271029f9feSNamhyung Kim if (syms_ss) 15281029f9feSNamhyung Kim ret = dso__load_sym(dso, map, syms_ss, runtime_ss, filter, kmod); 15291029f9feSNamhyung Kim else 15303aafe5aeSCody P Schafer ret = -1; 15313aafe5aeSCody P Schafer 1532f47b58b7SDavid Ahern if (ret > 0) { 15333aafe5aeSCody P Schafer int nr_plt; 15343aafe5aeSCody P Schafer 15353aafe5aeSCody P Schafer nr_plt = dso__synthesize_plt_symbols(dso, runtime_ss, map, filter); 15363aafe5aeSCody P Schafer if (nr_plt > 0) 15373aafe5aeSCody P Schafer ret += nr_plt; 15383aafe5aeSCody P Schafer } 15393aafe5aeSCody P Schafer 15403aafe5aeSCody P Schafer for (; ss_pos > 0; ss_pos--) 15413aafe5aeSCody P Schafer symsrc__destroy(&ss_[ss_pos - 1]); 15423aafe5aeSCody P Schafer out_free: 154386470930SIngo Molnar free(name); 1544aeafcbafSArnaldo Carvalho de Melo if (ret < 0 && strstr(dso->name, " (deleted)") != NULL) 15454a936edcSNamhyung Kim ret = 0; 15464a936edcSNamhyung Kim out: 15474a936edcSNamhyung Kim dso__set_loaded(dso, map->type); 15484a936edcSNamhyung Kim pthread_mutex_unlock(&dso->lock); 15494a936edcSNamhyung Kim 155086470930SIngo Molnar return ret; 155186470930SIngo Molnar } 155286470930SIngo Molnar 1553aeafcbafSArnaldo Carvalho de Melo struct map *map_groups__find_by_name(struct map_groups *mg, 155479406cd7SArnaldo Carvalho de Melo enum map_type type, const char *name) 1555439d473bSArnaldo Carvalho de Melo { 15561eee78aeSArnaldo Carvalho de Melo struct maps *maps = &mg->maps[type]; 15574bb7123dSArnaldo Carvalho de Melo struct map *map; 1558439d473bSArnaldo Carvalho de Melo 15596a2ffcddSArnaldo Carvalho de Melo pthread_rwlock_rdlock(&maps->lock); 15606a2ffcddSArnaldo Carvalho de Melo 15614bb7123dSArnaldo Carvalho de Melo for (map = maps__first(maps); map; map = map__next(map)) { 1562b7cece76SArnaldo Carvalho de Melo if (map->dso && strcmp(map->dso->short_name, name) == 0) 15636a2ffcddSArnaldo Carvalho de Melo goto out_unlock; 1564439d473bSArnaldo Carvalho de Melo } 1565439d473bSArnaldo Carvalho de Melo 15666a2ffcddSArnaldo Carvalho de Melo map = NULL; 15676a2ffcddSArnaldo Carvalho de Melo 15686a2ffcddSArnaldo Carvalho de Melo out_unlock: 15696a2ffcddSArnaldo Carvalho de Melo pthread_rwlock_unlock(&maps->lock); 15706a2ffcddSArnaldo Carvalho de Melo return map; 1571439d473bSArnaldo Carvalho de Melo } 1572439d473bSArnaldo Carvalho de Melo 1573aeafcbafSArnaldo Carvalho de Melo int dso__load_vmlinux(struct dso *dso, struct map *map, 15745230fb7dSArnaldo Carvalho de Melo const char *vmlinux, bool vmlinux_allocated, 15755230fb7dSArnaldo Carvalho de Melo symbol_filter_t filter) 157686470930SIngo Molnar { 1577b68e2f91SCody P Schafer int err = -1; 1578b68e2f91SCody P Schafer struct symsrc ss; 1579ec5761eaSDavid Ahern char symfs_vmlinux[PATH_MAX]; 1580005f9294SCody P Schafer enum dso_binary_type symtab_type; 158186470930SIngo Molnar 15825698d2c9SNamhyung Kim if (vmlinux[0] == '/') 15835698d2c9SNamhyung Kim snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s", vmlinux); 15845698d2c9SNamhyung Kim else 1585972f393bSArnaldo Carvalho de Melo symbol__join_symfs(symfs_vmlinux, vmlinux); 158686470930SIngo Molnar 158721ea4539SCody P Schafer if (dso->kernel == DSO_TYPE_GUEST_KERNEL) 1588005f9294SCody P Schafer symtab_type = DSO_BINARY_TYPE__GUEST_VMLINUX; 158921ea4539SCody P Schafer else 1590005f9294SCody P Schafer symtab_type = DSO_BINARY_TYPE__VMLINUX; 159121ea4539SCody P Schafer 1592005f9294SCody P Schafer if (symsrc__init(&ss, dso, symfs_vmlinux, symtab_type)) 1593b68e2f91SCody P Schafer return -1; 1594b68e2f91SCody P Schafer 1595261360b6SCody P Schafer err = dso__load_sym(dso, map, &ss, &ss, filter, 0); 1596b68e2f91SCody P Schafer symsrc__destroy(&ss); 159786470930SIngo Molnar 1598515850e4SCody P Schafer if (err > 0) { 159939b12f78SAdrian Hunter if (dso->kernel == DSO_TYPE_GUEST_KERNEL) 16005f70619dSArnaldo Carvalho de Melo dso->binary_type = DSO_BINARY_TYPE__GUEST_VMLINUX; 160139b12f78SAdrian Hunter else 16025f70619dSArnaldo Carvalho de Melo dso->binary_type = DSO_BINARY_TYPE__VMLINUX; 1603bf4414aeSArnaldo Carvalho de Melo dso__set_long_name(dso, vmlinux, vmlinux_allocated); 1604515850e4SCody P Schafer dso__set_loaded(dso, map->type); 1605ec5761eaSDavid Ahern pr_debug("Using %s for symbols\n", symfs_vmlinux); 1606515850e4SCody P Schafer } 16073846df2eSArnaldo Carvalho de Melo 160886470930SIngo Molnar return err; 160986470930SIngo Molnar } 161086470930SIngo Molnar 1611aeafcbafSArnaldo Carvalho de Melo int dso__load_vmlinux_path(struct dso *dso, struct map *map, 16129de89fe7SArnaldo Carvalho de Melo symbol_filter_t filter) 1613a19afe46SArnaldo Carvalho de Melo { 1614a19afe46SArnaldo Carvalho de Melo int i, err = 0; 161500dc8657SNamhyung Kim char *filename = NULL; 1616a19afe46SArnaldo Carvalho de Melo 1617dc38218eSArnaldo Carvalho de Melo pr_debug("Looking at the vmlinux_path (%d entries long)\n", 1618dc38218eSArnaldo Carvalho de Melo vmlinux_path__nr_entries + 1); 1619dc38218eSArnaldo Carvalho de Melo 1620dc38218eSArnaldo Carvalho de Melo for (i = 0; i < vmlinux_path__nr_entries; ++i) { 1621dc38218eSArnaldo Carvalho de Melo err = dso__load_vmlinux(dso, map, vmlinux_path[i], false, filter); 1622dc38218eSArnaldo Carvalho de Melo if (err > 0) 1623dc38218eSArnaldo Carvalho de Melo goto out; 1624dc38218eSArnaldo Carvalho de Melo } 1625dc38218eSArnaldo Carvalho de Melo 162600dc8657SNamhyung Kim if (!symbol_conf.ignore_vmlinux_buildid) 1627aeafcbafSArnaldo Carvalho de Melo filename = dso__build_id_filename(dso, NULL, 0); 16285ad90e4eSArnaldo Carvalho de Melo if (filename != NULL) { 16295230fb7dSArnaldo Carvalho de Melo err = dso__load_vmlinux(dso, map, filename, true, filter); 16305230fb7dSArnaldo Carvalho de Melo if (err > 0) 16315ad90e4eSArnaldo Carvalho de Melo goto out; 16325ad90e4eSArnaldo Carvalho de Melo free(filename); 16335ad90e4eSArnaldo Carvalho de Melo } 16345ad90e4eSArnaldo Carvalho de Melo out: 1635a19afe46SArnaldo Carvalho de Melo return err; 1636a19afe46SArnaldo Carvalho de Melo } 1637a19afe46SArnaldo Carvalho de Melo 16380544d422SAdrian Hunter static int find_matching_kcore(struct map *map, char *dir, size_t dir_sz) 16390544d422SAdrian Hunter { 16400544d422SAdrian Hunter char kallsyms_filename[PATH_MAX]; 16410544d422SAdrian Hunter struct dirent *dent; 16420544d422SAdrian Hunter int ret = -1; 16430544d422SAdrian Hunter DIR *d; 16440544d422SAdrian Hunter 16450544d422SAdrian Hunter d = opendir(dir); 16460544d422SAdrian Hunter if (!d) 16470544d422SAdrian Hunter return -1; 16480544d422SAdrian Hunter 16490544d422SAdrian Hunter while (1) { 16500544d422SAdrian Hunter dent = readdir(d); 16510544d422SAdrian Hunter if (!dent) 16520544d422SAdrian Hunter break; 16530544d422SAdrian Hunter if (dent->d_type != DT_DIR) 16540544d422SAdrian Hunter continue; 16550544d422SAdrian Hunter scnprintf(kallsyms_filename, sizeof(kallsyms_filename), 16560544d422SAdrian Hunter "%s/%s/kallsyms", dir, dent->d_name); 1657a00d28cbSAdrian Hunter if (!validate_kcore_addresses(kallsyms_filename, map)) { 16580544d422SAdrian Hunter strlcpy(dir, kallsyms_filename, dir_sz); 16590544d422SAdrian Hunter ret = 0; 16600544d422SAdrian Hunter break; 16610544d422SAdrian Hunter } 16620544d422SAdrian Hunter } 16630544d422SAdrian Hunter 16640544d422SAdrian Hunter closedir(d); 16650544d422SAdrian Hunter 16660544d422SAdrian Hunter return ret; 16670544d422SAdrian Hunter } 16680544d422SAdrian Hunter 16690544d422SAdrian Hunter static char *dso__find_kallsyms(struct dso *dso, struct map *map) 16700544d422SAdrian Hunter { 16710544d422SAdrian Hunter u8 host_build_id[BUILD_ID_SIZE]; 16720544d422SAdrian Hunter char sbuild_id[BUILD_ID_SIZE * 2 + 1]; 16730544d422SAdrian Hunter bool is_host = false; 16740544d422SAdrian Hunter char path[PATH_MAX]; 16750544d422SAdrian Hunter 16760544d422SAdrian Hunter if (!dso->has_build_id) { 16770544d422SAdrian Hunter /* 16780544d422SAdrian Hunter * Last resort, if we don't have a build-id and couldn't find 16790544d422SAdrian Hunter * any vmlinux file, try the running kernel kallsyms table. 16800544d422SAdrian Hunter */ 16810544d422SAdrian Hunter goto proc_kallsyms; 16820544d422SAdrian Hunter } 16830544d422SAdrian Hunter 16840544d422SAdrian Hunter if (sysfs__read_build_id("/sys/kernel/notes", host_build_id, 16850544d422SAdrian Hunter sizeof(host_build_id)) == 0) 16860544d422SAdrian Hunter is_host = dso__build_id_equal(dso, host_build_id); 16870544d422SAdrian Hunter 16880544d422SAdrian Hunter build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id); 16890544d422SAdrian Hunter 1690449867e3SAdrian Hunter scnprintf(path, sizeof(path), "%s/[kernel.kcore]/%s", buildid_dir, 1691449867e3SAdrian Hunter sbuild_id); 1692449867e3SAdrian Hunter 16930544d422SAdrian Hunter /* Use /proc/kallsyms if possible */ 16940544d422SAdrian Hunter if (is_host) { 16950544d422SAdrian Hunter DIR *d; 16960544d422SAdrian Hunter int fd; 16970544d422SAdrian Hunter 16980544d422SAdrian Hunter /* If no cached kcore go with /proc/kallsyms */ 16990544d422SAdrian Hunter d = opendir(path); 17000544d422SAdrian Hunter if (!d) 17010544d422SAdrian Hunter goto proc_kallsyms; 17020544d422SAdrian Hunter closedir(d); 17030544d422SAdrian Hunter 17040544d422SAdrian Hunter /* 17050544d422SAdrian Hunter * Do not check the build-id cache, until we know we cannot use 17060544d422SAdrian Hunter * /proc/kcore. 17070544d422SAdrian Hunter */ 17080544d422SAdrian Hunter fd = open("/proc/kcore", O_RDONLY); 17090544d422SAdrian Hunter if (fd != -1) { 17100544d422SAdrian Hunter close(fd); 17110544d422SAdrian Hunter /* If module maps match go with /proc/kallsyms */ 1712a00d28cbSAdrian Hunter if (!validate_kcore_addresses("/proc/kallsyms", map)) 17130544d422SAdrian Hunter goto proc_kallsyms; 17140544d422SAdrian Hunter } 17150544d422SAdrian Hunter 17160544d422SAdrian Hunter /* Find kallsyms in build-id cache with kcore */ 17170544d422SAdrian Hunter if (!find_matching_kcore(map, path, sizeof(path))) 17180544d422SAdrian Hunter return strdup(path); 17190544d422SAdrian Hunter 17200544d422SAdrian Hunter goto proc_kallsyms; 17210544d422SAdrian Hunter } 17220544d422SAdrian Hunter 1723449867e3SAdrian Hunter /* Find kallsyms in build-id cache with kcore */ 1724449867e3SAdrian Hunter if (!find_matching_kcore(map, path, sizeof(path))) 1725449867e3SAdrian Hunter return strdup(path); 1726449867e3SAdrian Hunter 17270544d422SAdrian Hunter scnprintf(path, sizeof(path), "%s/[kernel.kallsyms]/%s", 17280544d422SAdrian Hunter buildid_dir, sbuild_id); 17290544d422SAdrian Hunter 17300544d422SAdrian Hunter if (access(path, F_OK)) { 17310544d422SAdrian Hunter pr_err("No kallsyms or vmlinux with build-id %s was found\n", 17320544d422SAdrian Hunter sbuild_id); 17330544d422SAdrian Hunter return NULL; 17340544d422SAdrian Hunter } 17350544d422SAdrian Hunter 17360544d422SAdrian Hunter return strdup(path); 17370544d422SAdrian Hunter 17380544d422SAdrian Hunter proc_kallsyms: 17390544d422SAdrian Hunter return strdup("/proc/kallsyms"); 17400544d422SAdrian Hunter } 17410544d422SAdrian Hunter 1742aeafcbafSArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *dso, struct map *map, 17439de89fe7SArnaldo Carvalho de Melo symbol_filter_t filter) 174486470930SIngo Molnar { 1745cc612d81SArnaldo Carvalho de Melo int err; 17469e201442SArnaldo Carvalho de Melo const char *kallsyms_filename = NULL; 17479e201442SArnaldo Carvalho de Melo char *kallsyms_allocated_filename = NULL; 1748dc8d6ab2SArnaldo Carvalho de Melo /* 1749b226a5a7SDavid Ahern * Step 1: if the user specified a kallsyms or vmlinux filename, use 1750b226a5a7SDavid Ahern * it and only it, reporting errors to the user if it cannot be used. 1751dc8d6ab2SArnaldo Carvalho de Melo * 1752dc8d6ab2SArnaldo Carvalho de Melo * For instance, try to analyse an ARM perf.data file _without_ a 1753dc8d6ab2SArnaldo Carvalho de Melo * build-id, or if the user specifies the wrong path to the right 1754dc8d6ab2SArnaldo Carvalho de Melo * vmlinux file, obviously we can't fallback to another vmlinux (a 1755dc8d6ab2SArnaldo Carvalho de Melo * x86_86 one, on the machine where analysis is being performed, say), 1756dc8d6ab2SArnaldo Carvalho de Melo * or worse, /proc/kallsyms. 1757dc8d6ab2SArnaldo Carvalho de Melo * 1758dc8d6ab2SArnaldo Carvalho de Melo * If the specified file _has_ a build-id and there is a build-id 1759dc8d6ab2SArnaldo Carvalho de Melo * section in the perf.data file, we will still do the expected 1760dc8d6ab2SArnaldo Carvalho de Melo * validation in dso__load_vmlinux and will bail out if they don't 1761dc8d6ab2SArnaldo Carvalho de Melo * match. 1762dc8d6ab2SArnaldo Carvalho de Melo */ 1763b226a5a7SDavid Ahern if (symbol_conf.kallsyms_name != NULL) { 1764b226a5a7SDavid Ahern kallsyms_filename = symbol_conf.kallsyms_name; 1765b226a5a7SDavid Ahern goto do_kallsyms; 1766b226a5a7SDavid Ahern } 1767b226a5a7SDavid Ahern 1768fc2be696SWilly Tarreau if (!symbol_conf.ignore_vmlinux && symbol_conf.vmlinux_name != NULL) { 17695230fb7dSArnaldo Carvalho de Melo return dso__load_vmlinux(dso, map, symbol_conf.vmlinux_name, 17705230fb7dSArnaldo Carvalho de Melo false, filter); 1771dc8d6ab2SArnaldo Carvalho de Melo } 1772439d473bSArnaldo Carvalho de Melo 1773fc2be696SWilly Tarreau if (!symbol_conf.ignore_vmlinux && vmlinux_path != NULL) { 1774aeafcbafSArnaldo Carvalho de Melo err = dso__load_vmlinux_path(dso, map, filter); 1775a19afe46SArnaldo Carvalho de Melo if (err > 0) 177639b12f78SAdrian Hunter return err; 1777cc612d81SArnaldo Carvalho de Melo } 1778cc612d81SArnaldo Carvalho de Melo 1779ec5761eaSDavid Ahern /* do not try local files if a symfs was given */ 1780ec5761eaSDavid Ahern if (symbol_conf.symfs[0] != 0) 1781ec5761eaSDavid Ahern return -1; 1782ec5761eaSDavid Ahern 17830544d422SAdrian Hunter kallsyms_allocated_filename = dso__find_kallsyms(dso, map); 17840544d422SAdrian Hunter if (!kallsyms_allocated_filename) 17858d0591f6SArnaldo Carvalho de Melo return -1; 17868d0591f6SArnaldo Carvalho de Melo 178719fc2dedSArnaldo Carvalho de Melo kallsyms_filename = kallsyms_allocated_filename; 178819fc2dedSArnaldo Carvalho de Melo 1789dc8d6ab2SArnaldo Carvalho de Melo do_kallsyms: 1790aeafcbafSArnaldo Carvalho de Melo err = dso__load_kallsyms(dso, kallsyms_filename, map, filter); 17913846df2eSArnaldo Carvalho de Melo if (err > 0) 17923846df2eSArnaldo Carvalho de Melo pr_debug("Using %s for symbols\n", kallsyms_filename); 1793dc8d6ab2SArnaldo Carvalho de Melo free(kallsyms_allocated_filename); 1794dc8d6ab2SArnaldo Carvalho de Melo 17958e0cf965SAdrian Hunter if (err > 0 && !dso__is_kcore(dso)) { 1796bdac0bcfSAdrian Hunter dso->binary_type = DSO_BINARY_TYPE__KALLSYMS; 1797bf4414aeSArnaldo Carvalho de Melo dso__set_long_name(dso, "[kernel.kallsyms]", false); 17986a4694a4SArnaldo Carvalho de Melo map__fixup_start(map); 17996a4694a4SArnaldo Carvalho de Melo map__fixup_end(map); 1800439d473bSArnaldo Carvalho de Melo } 180194cb9e38SArnaldo Carvalho de Melo 180286470930SIngo Molnar return err; 180386470930SIngo Molnar } 180486470930SIngo Molnar 1805aeafcbafSArnaldo Carvalho de Melo static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map, 1806a1645ce1SZhang, Yanmin symbol_filter_t filter) 1807a1645ce1SZhang, Yanmin { 1808a1645ce1SZhang, Yanmin int err; 1809a1645ce1SZhang, Yanmin const char *kallsyms_filename = NULL; 181023346f21SArnaldo Carvalho de Melo struct machine *machine; 1811a1645ce1SZhang, Yanmin char path[PATH_MAX]; 1812a1645ce1SZhang, Yanmin 1813a1645ce1SZhang, Yanmin if (!map->groups) { 1814a1645ce1SZhang, Yanmin pr_debug("Guest kernel map hasn't the point to groups\n"); 1815a1645ce1SZhang, Yanmin return -1; 1816a1645ce1SZhang, Yanmin } 181723346f21SArnaldo Carvalho de Melo machine = map->groups->machine; 1818a1645ce1SZhang, Yanmin 181923346f21SArnaldo Carvalho de Melo if (machine__is_default_guest(machine)) { 1820a1645ce1SZhang, Yanmin /* 1821a1645ce1SZhang, Yanmin * if the user specified a vmlinux filename, use it and only 1822a1645ce1SZhang, Yanmin * it, reporting errors to the user if it cannot be used. 1823a1645ce1SZhang, Yanmin * Or use file guest_kallsyms inputted by user on commandline 1824a1645ce1SZhang, Yanmin */ 1825a1645ce1SZhang, Yanmin if (symbol_conf.default_guest_vmlinux_name != NULL) { 1826aeafcbafSArnaldo Carvalho de Melo err = dso__load_vmlinux(dso, map, 18275230fb7dSArnaldo Carvalho de Melo symbol_conf.default_guest_vmlinux_name, 18285230fb7dSArnaldo Carvalho de Melo false, filter); 182939b12f78SAdrian Hunter return err; 1830a1645ce1SZhang, Yanmin } 1831a1645ce1SZhang, Yanmin 1832a1645ce1SZhang, Yanmin kallsyms_filename = symbol_conf.default_guest_kallsyms; 1833a1645ce1SZhang, Yanmin if (!kallsyms_filename) 1834a1645ce1SZhang, Yanmin return -1; 1835a1645ce1SZhang, Yanmin } else { 183623346f21SArnaldo Carvalho de Melo sprintf(path, "%s/proc/kallsyms", machine->root_dir); 1837a1645ce1SZhang, Yanmin kallsyms_filename = path; 1838a1645ce1SZhang, Yanmin } 1839a1645ce1SZhang, Yanmin 1840aeafcbafSArnaldo Carvalho de Melo err = dso__load_kallsyms(dso, kallsyms_filename, map, filter); 18418e0cf965SAdrian Hunter if (err > 0) 184239b12f78SAdrian Hunter pr_debug("Using %s for symbols\n", kallsyms_filename); 18438e0cf965SAdrian Hunter if (err > 0 && !dso__is_kcore(dso)) { 1844bdac0bcfSAdrian Hunter dso->binary_type = DSO_BINARY_TYPE__GUEST_KALLSYMS; 184548ea8f54SArnaldo Carvalho de Melo machine__mmap_name(machine, path, sizeof(path)); 18467e155d4dSArnaldo Carvalho de Melo dso__set_long_name(dso, strdup(path), true); 1847a1645ce1SZhang, Yanmin map__fixup_start(map); 1848a1645ce1SZhang, Yanmin map__fixup_end(map); 1849a1645ce1SZhang, Yanmin } 1850a1645ce1SZhang, Yanmin 1851a1645ce1SZhang, Yanmin return err; 1852a1645ce1SZhang, Yanmin } 1853cd84c2acSFrederic Weisbecker 1854cc612d81SArnaldo Carvalho de Melo static void vmlinux_path__exit(void) 18552446042cSArnaldo Carvalho de Melo { 185604662523SArnaldo Carvalho de Melo while (--vmlinux_path__nr_entries >= 0) 185704662523SArnaldo Carvalho de Melo zfree(&vmlinux_path[vmlinux_path__nr_entries]); 1858c4f03547SWang Nan vmlinux_path__nr_entries = 0; 1859cc612d81SArnaldo Carvalho de Melo 186004662523SArnaldo Carvalho de Melo zfree(&vmlinux_path); 1861cc612d81SArnaldo Carvalho de Melo } 1862cc612d81SArnaldo Carvalho de Melo 1863ce80d3beSKan Liang static int vmlinux_path__init(struct perf_env *env) 1864cc612d81SArnaldo Carvalho de Melo { 1865cc612d81SArnaldo Carvalho de Melo struct utsname uts; 1866cc612d81SArnaldo Carvalho de Melo char bf[PATH_MAX]; 18670a7e6d1bSNamhyung Kim char *kernel_version; 1868cc612d81SArnaldo Carvalho de Melo 1869c657f423SAnton Blanchard vmlinux_path = malloc(sizeof(char *) * 6); 1870cc612d81SArnaldo Carvalho de Melo if (vmlinux_path == NULL) 1871cc612d81SArnaldo Carvalho de Melo return -1; 1872cc612d81SArnaldo Carvalho de Melo 1873cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup("vmlinux"); 1874cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 1875cc612d81SArnaldo Carvalho de Melo goto out_fail; 1876cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 1877cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup("/boot/vmlinux"); 1878cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 1879cc612d81SArnaldo Carvalho de Melo goto out_fail; 1880cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 1881ec5761eaSDavid Ahern 18820a7e6d1bSNamhyung Kim /* only try kernel version if no symfs was given */ 1883ec5761eaSDavid Ahern if (symbol_conf.symfs[0] != 0) 1884ec5761eaSDavid Ahern return 0; 1885ec5761eaSDavid Ahern 18860a7e6d1bSNamhyung Kim if (env) { 18870a7e6d1bSNamhyung Kim kernel_version = env->os_release; 18880a7e6d1bSNamhyung Kim } else { 1889ec5761eaSDavid Ahern if (uname(&uts) < 0) 1890e96c674fSNamhyung Kim goto out_fail; 1891ec5761eaSDavid Ahern 18920a7e6d1bSNamhyung Kim kernel_version = uts.release; 18930a7e6d1bSNamhyung Kim } 18940a7e6d1bSNamhyung Kim 18950a7e6d1bSNamhyung Kim snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", kernel_version); 1896cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); 1897cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 1898cc612d81SArnaldo Carvalho de Melo goto out_fail; 1899cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 1900c657f423SAnton Blanchard snprintf(bf, sizeof(bf), "/usr/lib/debug/boot/vmlinux-%s", 1901c657f423SAnton Blanchard kernel_version); 1902c657f423SAnton Blanchard vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); 1903c657f423SAnton Blanchard if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 1904c657f423SAnton Blanchard goto out_fail; 1905c657f423SAnton Blanchard ++vmlinux_path__nr_entries; 19060a7e6d1bSNamhyung Kim snprintf(bf, sizeof(bf), "/lib/modules/%s/build/vmlinux", kernel_version); 1907cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); 1908cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 1909cc612d81SArnaldo Carvalho de Melo goto out_fail; 1910cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 1911cc612d81SArnaldo Carvalho de Melo snprintf(bf, sizeof(bf), "/usr/lib/debug/lib/modules/%s/vmlinux", 19120a7e6d1bSNamhyung Kim kernel_version); 1913cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); 1914cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 1915cc612d81SArnaldo Carvalho de Melo goto out_fail; 1916cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 1917cc612d81SArnaldo Carvalho de Melo 1918cc612d81SArnaldo Carvalho de Melo return 0; 1919cc612d81SArnaldo Carvalho de Melo 1920cc612d81SArnaldo Carvalho de Melo out_fail: 1921cc612d81SArnaldo Carvalho de Melo vmlinux_path__exit(); 1922cc612d81SArnaldo Carvalho de Melo return -1; 1923cc612d81SArnaldo Carvalho de Melo } 1924cc612d81SArnaldo Carvalho de Melo 19253bfe5f81SDavid Ahern int setup_list(struct strlist **list, const char *list_str, 1926655000e7SArnaldo Carvalho de Melo const char *list_name) 1927655000e7SArnaldo Carvalho de Melo { 1928655000e7SArnaldo Carvalho de Melo if (list_str == NULL) 1929655000e7SArnaldo Carvalho de Melo return 0; 1930655000e7SArnaldo Carvalho de Melo 19314a77e218SArnaldo Carvalho de Melo *list = strlist__new(list_str, NULL); 1932655000e7SArnaldo Carvalho de Melo if (!*list) { 1933655000e7SArnaldo Carvalho de Melo pr_err("problems parsing %s list\n", list_name); 1934655000e7SArnaldo Carvalho de Melo return -1; 1935655000e7SArnaldo Carvalho de Melo } 19360bc2f2f7SArnaldo Carvalho de Melo 19370bc2f2f7SArnaldo Carvalho de Melo symbol_conf.has_filter = true; 1938655000e7SArnaldo Carvalho de Melo return 0; 1939655000e7SArnaldo Carvalho de Melo } 1940655000e7SArnaldo Carvalho de Melo 1941e03eaa40SDavid Ahern int setup_intlist(struct intlist **list, const char *list_str, 1942e03eaa40SDavid Ahern const char *list_name) 1943e03eaa40SDavid Ahern { 1944e03eaa40SDavid Ahern if (list_str == NULL) 1945e03eaa40SDavid Ahern return 0; 1946e03eaa40SDavid Ahern 1947e03eaa40SDavid Ahern *list = intlist__new(list_str); 1948e03eaa40SDavid Ahern if (!*list) { 1949e03eaa40SDavid Ahern pr_err("problems parsing %s list\n", list_name); 1950e03eaa40SDavid Ahern return -1; 1951e03eaa40SDavid Ahern } 1952e03eaa40SDavid Ahern return 0; 1953e03eaa40SDavid Ahern } 1954e03eaa40SDavid Ahern 1955ec80fde7SArnaldo Carvalho de Melo static bool symbol__read_kptr_restrict(void) 1956ec80fde7SArnaldo Carvalho de Melo { 1957ec80fde7SArnaldo Carvalho de Melo bool value = false; 1958ec80fde7SArnaldo Carvalho de Melo 1959ec80fde7SArnaldo Carvalho de Melo if (geteuid() != 0) { 1960ec80fde7SArnaldo Carvalho de Melo FILE *fp = fopen("/proc/sys/kernel/kptr_restrict", "r"); 1961ec80fde7SArnaldo Carvalho de Melo if (fp != NULL) { 1962ec80fde7SArnaldo Carvalho de Melo char line[8]; 1963ec80fde7SArnaldo Carvalho de Melo 1964ec80fde7SArnaldo Carvalho de Melo if (fgets(line, sizeof(line), fp) != NULL) 1965ec80fde7SArnaldo Carvalho de Melo value = atoi(line) != 0; 1966ec80fde7SArnaldo Carvalho de Melo 1967ec80fde7SArnaldo Carvalho de Melo fclose(fp); 1968ec80fde7SArnaldo Carvalho de Melo } 1969ec80fde7SArnaldo Carvalho de Melo } 1970ec80fde7SArnaldo Carvalho de Melo 1971ec80fde7SArnaldo Carvalho de Melo return value; 1972ec80fde7SArnaldo Carvalho de Melo } 1973ec80fde7SArnaldo Carvalho de Melo 1974ce80d3beSKan Liang int symbol__init(struct perf_env *env) 1975cc612d81SArnaldo Carvalho de Melo { 1976ec5761eaSDavid Ahern const char *symfs; 1977ec5761eaSDavid Ahern 197885e00b55SJovi Zhang if (symbol_conf.initialized) 197985e00b55SJovi Zhang return 0; 198085e00b55SJovi Zhang 19819ac3e487SIrina Tirdea symbol_conf.priv_size = PERF_ALIGN(symbol_conf.priv_size, sizeof(u64)); 19824d439517SDavid S. Miller 1983166ccc9cSNamhyung Kim symbol__elf_init(); 1984166ccc9cSNamhyung Kim 198575be6cf4SArnaldo Carvalho de Melo if (symbol_conf.sort_by_name) 198675be6cf4SArnaldo Carvalho de Melo symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) - 198779406cd7SArnaldo Carvalho de Melo sizeof(struct symbol)); 1988b32d133aSArnaldo Carvalho de Melo 19890a7e6d1bSNamhyung Kim if (symbol_conf.try_vmlinux_path && vmlinux_path__init(env) < 0) 1990cc612d81SArnaldo Carvalho de Melo return -1; 1991cc612d81SArnaldo Carvalho de Melo 1992c410a338SArnaldo Carvalho de Melo if (symbol_conf.field_sep && *symbol_conf.field_sep == '.') { 1993c410a338SArnaldo Carvalho de Melo pr_err("'.' is the only non valid --field-separator argument\n"); 1994c410a338SArnaldo Carvalho de Melo return -1; 1995c410a338SArnaldo Carvalho de Melo } 1996c410a338SArnaldo Carvalho de Melo 1997655000e7SArnaldo Carvalho de Melo if (setup_list(&symbol_conf.dso_list, 1998655000e7SArnaldo Carvalho de Melo symbol_conf.dso_list_str, "dso") < 0) 1999655000e7SArnaldo Carvalho de Melo return -1; 2000655000e7SArnaldo Carvalho de Melo 2001655000e7SArnaldo Carvalho de Melo if (setup_list(&symbol_conf.comm_list, 2002655000e7SArnaldo Carvalho de Melo symbol_conf.comm_list_str, "comm") < 0) 2003655000e7SArnaldo Carvalho de Melo goto out_free_dso_list; 2004655000e7SArnaldo Carvalho de Melo 2005e03eaa40SDavid Ahern if (setup_intlist(&symbol_conf.pid_list, 2006e03eaa40SDavid Ahern symbol_conf.pid_list_str, "pid") < 0) 2007e03eaa40SDavid Ahern goto out_free_comm_list; 2008e03eaa40SDavid Ahern 2009e03eaa40SDavid Ahern if (setup_intlist(&symbol_conf.tid_list, 2010e03eaa40SDavid Ahern symbol_conf.tid_list_str, "tid") < 0) 2011e03eaa40SDavid Ahern goto out_free_pid_list; 2012e03eaa40SDavid Ahern 2013655000e7SArnaldo Carvalho de Melo if (setup_list(&symbol_conf.sym_list, 2014655000e7SArnaldo Carvalho de Melo symbol_conf.sym_list_str, "symbol") < 0) 2015e03eaa40SDavid Ahern goto out_free_tid_list; 2016655000e7SArnaldo Carvalho de Melo 2017ec5761eaSDavid Ahern /* 2018ec5761eaSDavid Ahern * A path to symbols of "/" is identical to "" 2019ec5761eaSDavid Ahern * reset here for simplicity. 2020ec5761eaSDavid Ahern */ 2021ec5761eaSDavid Ahern symfs = realpath(symbol_conf.symfs, NULL); 2022ec5761eaSDavid Ahern if (symfs == NULL) 2023ec5761eaSDavid Ahern symfs = symbol_conf.symfs; 2024ec5761eaSDavid Ahern if (strcmp(symfs, "/") == 0) 2025ec5761eaSDavid Ahern symbol_conf.symfs = ""; 2026ec5761eaSDavid Ahern if (symfs != symbol_conf.symfs) 2027ec5761eaSDavid Ahern free((void *)symfs); 2028ec5761eaSDavid Ahern 2029ec80fde7SArnaldo Carvalho de Melo symbol_conf.kptr_restrict = symbol__read_kptr_restrict(); 2030ec80fde7SArnaldo Carvalho de Melo 203185e00b55SJovi Zhang symbol_conf.initialized = true; 20324aa65636SArnaldo Carvalho de Melo return 0; 2033655000e7SArnaldo Carvalho de Melo 2034e03eaa40SDavid Ahern out_free_tid_list: 2035e03eaa40SDavid Ahern intlist__delete(symbol_conf.tid_list); 2036e03eaa40SDavid Ahern out_free_pid_list: 2037e03eaa40SDavid Ahern intlist__delete(symbol_conf.pid_list); 2038655000e7SArnaldo Carvalho de Melo out_free_comm_list: 2039655000e7SArnaldo Carvalho de Melo strlist__delete(symbol_conf.comm_list); 2040d74c896bSNamhyung Kim out_free_dso_list: 2041d74c896bSNamhyung Kim strlist__delete(symbol_conf.dso_list); 2042655000e7SArnaldo Carvalho de Melo return -1; 2043cc612d81SArnaldo Carvalho de Melo } 2044cc612d81SArnaldo Carvalho de Melo 2045d65a458bSArnaldo Carvalho de Melo void symbol__exit(void) 2046d65a458bSArnaldo Carvalho de Melo { 204785e00b55SJovi Zhang if (!symbol_conf.initialized) 204885e00b55SJovi Zhang return; 2049d65a458bSArnaldo Carvalho de Melo strlist__delete(symbol_conf.sym_list); 2050d65a458bSArnaldo Carvalho de Melo strlist__delete(symbol_conf.dso_list); 2051d65a458bSArnaldo Carvalho de Melo strlist__delete(symbol_conf.comm_list); 2052e03eaa40SDavid Ahern intlist__delete(symbol_conf.tid_list); 2053e03eaa40SDavid Ahern intlist__delete(symbol_conf.pid_list); 2054d65a458bSArnaldo Carvalho de Melo vmlinux_path__exit(); 2055d65a458bSArnaldo Carvalho de Melo symbol_conf.sym_list = symbol_conf.dso_list = symbol_conf.comm_list = NULL; 205685e00b55SJovi Zhang symbol_conf.initialized = false; 2057d65a458bSArnaldo Carvalho de Melo } 2058