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" 1886470930SIngo Molnar 1986470930SIngo Molnar #include <elf.h> 20f1617b40SArnaldo Carvalho de Melo #include <limits.h> 21439d473bSArnaldo Carvalho de Melo #include <sys/utsname.h> 222cdbc46dSPeter Zijlstra 233b01a413SArnaldo Carvalho de Melo #ifndef KSYM_NAME_LEN 24c752d040SRicardo Ribalda Delgado #define KSYM_NAME_LEN 256 253b01a413SArnaldo Carvalho de Melo #endif 263b01a413SArnaldo Carvalho de Melo 27aeafcbafSArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *dso, struct map *map, 289de89fe7SArnaldo Carvalho de Melo symbol_filter_t filter); 29aeafcbafSArnaldo Carvalho de Melo static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map, 30a1645ce1SZhang, Yanmin symbol_filter_t filter); 313f067dcaSArnaldo Carvalho de Melo int vmlinux_path__nr_entries; 323f067dcaSArnaldo Carvalho de Melo char **vmlinux_path; 33439d473bSArnaldo Carvalho de Melo 3475be6cf4SArnaldo Carvalho de Melo struct symbol_conf symbol_conf = { 35b32d133aSArnaldo Carvalho de Melo .use_modules = true, 36b32d133aSArnaldo Carvalho de Melo .try_vmlinux_path = true, 373e6a2a7fSStephane Eranian .annotate_src = true, 38328ccdacSNamhyung Kim .demangle = true, 39ec5761eaSDavid Ahern .symfs = "", 40b32d133aSArnaldo Carvalho de Melo }; 41b32d133aSArnaldo Carvalho de Melo 4244f24cb3SJiri Olsa static enum dso_binary_type binary_type_symtab[] = { 4344f24cb3SJiri Olsa DSO_BINARY_TYPE__KALLSYMS, 4444f24cb3SJiri Olsa DSO_BINARY_TYPE__GUEST_KALLSYMS, 4544f24cb3SJiri Olsa DSO_BINARY_TYPE__JAVA_JIT, 4644f24cb3SJiri Olsa DSO_BINARY_TYPE__DEBUGLINK, 4744f24cb3SJiri Olsa DSO_BINARY_TYPE__BUILD_ID_CACHE, 4844f24cb3SJiri Olsa DSO_BINARY_TYPE__FEDORA_DEBUGINFO, 4944f24cb3SJiri Olsa DSO_BINARY_TYPE__UBUNTU_DEBUGINFO, 5044f24cb3SJiri Olsa DSO_BINARY_TYPE__BUILDID_DEBUGINFO, 5144f24cb3SJiri Olsa DSO_BINARY_TYPE__SYSTEM_PATH_DSO, 5244f24cb3SJiri Olsa DSO_BINARY_TYPE__GUEST_KMODULE, 5344f24cb3SJiri Olsa DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE, 549cd00941SRicardo Ribalda Delgado DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO, 5544f24cb3SJiri Olsa DSO_BINARY_TYPE__NOT_FOUND, 5644f24cb3SJiri Olsa }; 5744f24cb3SJiri Olsa 58028df767SJiri Olsa #define DSO_BINARY_TYPE__SYMTAB_CNT ARRAY_SIZE(binary_type_symtab) 5944f24cb3SJiri Olsa 6036a3e646SArnaldo Carvalho de Melo bool symbol_type__is_a(char symbol_type, enum map_type map_type) 616893d4eeSArnaldo Carvalho de Melo { 6231877908SAnton Blanchard symbol_type = toupper(symbol_type); 6331877908SAnton Blanchard 646893d4eeSArnaldo Carvalho de Melo switch (map_type) { 656893d4eeSArnaldo Carvalho de Melo case MAP__FUNCTION: 666893d4eeSArnaldo Carvalho de Melo return symbol_type == 'T' || symbol_type == 'W'; 67f1dfa0b1SArnaldo Carvalho de Melo case MAP__VARIABLE: 6831877908SAnton Blanchard return symbol_type == 'D'; 696893d4eeSArnaldo Carvalho de Melo default: 706893d4eeSArnaldo Carvalho de Melo return false; 716893d4eeSArnaldo Carvalho de Melo } 726893d4eeSArnaldo Carvalho de Melo } 736893d4eeSArnaldo Carvalho de Melo 74694bf407SAnton Blanchard static int prefix_underscores_count(const char *str) 75694bf407SAnton Blanchard { 76694bf407SAnton Blanchard const char *tail = str; 77694bf407SAnton Blanchard 78694bf407SAnton Blanchard while (*tail == '_') 79694bf407SAnton Blanchard tail++; 80694bf407SAnton Blanchard 81694bf407SAnton Blanchard return tail - str; 82694bf407SAnton Blanchard } 83694bf407SAnton Blanchard 84694bf407SAnton Blanchard #define SYMBOL_A 0 85694bf407SAnton Blanchard #define SYMBOL_B 1 86694bf407SAnton Blanchard 87694bf407SAnton Blanchard static int choose_best_symbol(struct symbol *syma, struct symbol *symb) 88694bf407SAnton Blanchard { 89694bf407SAnton Blanchard s64 a; 90694bf407SAnton Blanchard s64 b; 913445432bSAdrian Hunter size_t na, nb; 92694bf407SAnton Blanchard 93694bf407SAnton Blanchard /* Prefer a symbol with non zero length */ 94694bf407SAnton Blanchard a = syma->end - syma->start; 95694bf407SAnton Blanchard b = symb->end - symb->start; 96694bf407SAnton Blanchard if ((b == 0) && (a > 0)) 97694bf407SAnton Blanchard return SYMBOL_A; 98694bf407SAnton Blanchard else if ((a == 0) && (b > 0)) 99694bf407SAnton Blanchard return SYMBOL_B; 100694bf407SAnton Blanchard 101694bf407SAnton Blanchard /* Prefer a non weak symbol over a weak one */ 102694bf407SAnton Blanchard a = syma->binding == STB_WEAK; 103694bf407SAnton Blanchard b = symb->binding == STB_WEAK; 104694bf407SAnton Blanchard if (b && !a) 105694bf407SAnton Blanchard return SYMBOL_A; 106694bf407SAnton Blanchard if (a && !b) 107694bf407SAnton Blanchard return SYMBOL_B; 108694bf407SAnton Blanchard 109694bf407SAnton Blanchard /* Prefer a global symbol over a non global one */ 110694bf407SAnton Blanchard a = syma->binding == STB_GLOBAL; 111694bf407SAnton Blanchard b = symb->binding == STB_GLOBAL; 112694bf407SAnton Blanchard if (a && !b) 113694bf407SAnton Blanchard return SYMBOL_A; 114694bf407SAnton Blanchard if (b && !a) 115694bf407SAnton Blanchard return SYMBOL_B; 116694bf407SAnton Blanchard 117694bf407SAnton Blanchard /* Prefer a symbol with less underscores */ 118694bf407SAnton Blanchard a = prefix_underscores_count(syma->name); 119694bf407SAnton Blanchard b = prefix_underscores_count(symb->name); 120694bf407SAnton Blanchard if (b > a) 121694bf407SAnton Blanchard return SYMBOL_A; 122694bf407SAnton Blanchard else if (a > b) 123694bf407SAnton Blanchard return SYMBOL_B; 124694bf407SAnton Blanchard 1253445432bSAdrian Hunter /* Choose the symbol with the longest name */ 1263445432bSAdrian Hunter na = strlen(syma->name); 1273445432bSAdrian Hunter nb = strlen(symb->name); 1283445432bSAdrian Hunter if (na > nb) 129694bf407SAnton Blanchard return SYMBOL_A; 1303445432bSAdrian Hunter else if (na < nb) 131694bf407SAnton Blanchard return SYMBOL_B; 1323445432bSAdrian Hunter 1333445432bSAdrian Hunter /* Avoid "SyS" kernel syscall aliases */ 1343445432bSAdrian Hunter if (na >= 3 && !strncmp(syma->name, "SyS", 3)) 1353445432bSAdrian Hunter return SYMBOL_B; 1363445432bSAdrian Hunter if (na >= 10 && !strncmp(syma->name, "compat_SyS", 10)) 1373445432bSAdrian Hunter return SYMBOL_B; 1383445432bSAdrian Hunter 1393445432bSAdrian Hunter return SYMBOL_A; 140694bf407SAnton Blanchard } 141694bf407SAnton Blanchard 142e5a1845fSNamhyung Kim void symbols__fixup_duplicate(struct rb_root *symbols) 143694bf407SAnton Blanchard { 144694bf407SAnton Blanchard struct rb_node *nd; 145694bf407SAnton Blanchard struct symbol *curr, *next; 146694bf407SAnton Blanchard 147694bf407SAnton Blanchard nd = rb_first(symbols); 148694bf407SAnton Blanchard 149694bf407SAnton Blanchard while (nd) { 150694bf407SAnton Blanchard curr = rb_entry(nd, struct symbol, rb_node); 151694bf407SAnton Blanchard again: 152694bf407SAnton Blanchard nd = rb_next(&curr->rb_node); 153694bf407SAnton Blanchard next = rb_entry(nd, struct symbol, rb_node); 154694bf407SAnton Blanchard 155694bf407SAnton Blanchard if (!nd) 156694bf407SAnton Blanchard break; 157694bf407SAnton Blanchard 158694bf407SAnton Blanchard if (curr->start != next->start) 159694bf407SAnton Blanchard continue; 160694bf407SAnton Blanchard 161694bf407SAnton Blanchard if (choose_best_symbol(curr, next) == SYMBOL_A) { 162694bf407SAnton Blanchard rb_erase(&next->rb_node, symbols); 163d4f74eb8SChenggang Qin symbol__delete(next); 164694bf407SAnton Blanchard goto again; 165694bf407SAnton Blanchard } else { 166694bf407SAnton Blanchard nd = rb_next(&curr->rb_node); 167694bf407SAnton Blanchard rb_erase(&curr->rb_node, symbols); 168d4f74eb8SChenggang Qin symbol__delete(curr); 169694bf407SAnton Blanchard } 170694bf407SAnton Blanchard } 171694bf407SAnton Blanchard } 172694bf407SAnton Blanchard 173e5a1845fSNamhyung Kim void symbols__fixup_end(struct rb_root *symbols) 174af427bf5SArnaldo Carvalho de Melo { 175aeafcbafSArnaldo Carvalho de Melo struct rb_node *nd, *prevnd = rb_first(symbols); 1762e538c4aSArnaldo Carvalho de Melo struct symbol *curr, *prev; 177af427bf5SArnaldo Carvalho de Melo 178af427bf5SArnaldo Carvalho de Melo if (prevnd == NULL) 179af427bf5SArnaldo Carvalho de Melo return; 180af427bf5SArnaldo Carvalho de Melo 1812e538c4aSArnaldo Carvalho de Melo curr = rb_entry(prevnd, struct symbol, rb_node); 1822e538c4aSArnaldo Carvalho de Melo 183af427bf5SArnaldo Carvalho de Melo for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) { 1842e538c4aSArnaldo Carvalho de Melo prev = curr; 1852e538c4aSArnaldo Carvalho de Melo curr = rb_entry(nd, struct symbol, rb_node); 186af427bf5SArnaldo Carvalho de Melo 1873b01a413SArnaldo Carvalho de Melo if (prev->end == prev->start && prev->end != curr->start) 188af427bf5SArnaldo Carvalho de Melo prev->end = curr->start - 1; 189af427bf5SArnaldo Carvalho de Melo } 190af427bf5SArnaldo Carvalho de Melo 1912e538c4aSArnaldo Carvalho de Melo /* Last entry */ 1922e538c4aSArnaldo Carvalho de Melo if (curr->end == curr->start) 1932e538c4aSArnaldo Carvalho de Melo curr->end = roundup(curr->start, 4096); 1942e538c4aSArnaldo Carvalho de Melo } 1952e538c4aSArnaldo Carvalho de Melo 196e5a1845fSNamhyung Kim void __map_groups__fixup_end(struct map_groups *mg, enum map_type type) 197af427bf5SArnaldo Carvalho de Melo { 198af427bf5SArnaldo Carvalho de Melo struct map *prev, *curr; 199aeafcbafSArnaldo Carvalho de Melo struct rb_node *nd, *prevnd = rb_first(&mg->maps[type]); 200af427bf5SArnaldo Carvalho de Melo 201af427bf5SArnaldo Carvalho de Melo if (prevnd == NULL) 202af427bf5SArnaldo Carvalho de Melo return; 203af427bf5SArnaldo Carvalho de Melo 204af427bf5SArnaldo Carvalho de Melo curr = rb_entry(prevnd, struct map, rb_node); 205af427bf5SArnaldo Carvalho de Melo 206af427bf5SArnaldo Carvalho de Melo for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) { 207af427bf5SArnaldo Carvalho de Melo prev = curr; 208af427bf5SArnaldo Carvalho de Melo curr = rb_entry(nd, struct map, rb_node); 209af427bf5SArnaldo Carvalho de Melo prev->end = curr->start - 1; 2102e538c4aSArnaldo Carvalho de Melo } 21190c83218SArnaldo Carvalho de Melo 21290c83218SArnaldo Carvalho de Melo /* 21390c83218SArnaldo Carvalho de Melo * We still haven't the actual symbols, so guess the 21490c83218SArnaldo Carvalho de Melo * last map final address. 21590c83218SArnaldo Carvalho de Melo */ 2169d1faba5SIan Munsie curr->end = ~0ULL; 217af427bf5SArnaldo Carvalho de Melo } 218af427bf5SArnaldo Carvalho de Melo 219e5a1845fSNamhyung Kim struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name) 22086470930SIngo Molnar { 22186470930SIngo Molnar size_t namelen = strlen(name) + 1; 222aeafcbafSArnaldo Carvalho de Melo struct symbol *sym = calloc(1, (symbol_conf.priv_size + 223aeafcbafSArnaldo Carvalho de Melo sizeof(*sym) + namelen)); 224aeafcbafSArnaldo Carvalho de Melo if (sym == NULL) 22586470930SIngo Molnar return NULL; 22686470930SIngo Molnar 22775be6cf4SArnaldo Carvalho de Melo if (symbol_conf.priv_size) 228aeafcbafSArnaldo Carvalho de Melo sym = ((void *)sym) + symbol_conf.priv_size; 22936479484SArnaldo Carvalho de Melo 230aeafcbafSArnaldo Carvalho de Melo sym->start = start; 231aeafcbafSArnaldo Carvalho de Melo sym->end = len ? start + len - 1 : start; 232aeafcbafSArnaldo Carvalho de Melo sym->binding = binding; 233aeafcbafSArnaldo Carvalho de Melo sym->namelen = namelen - 1; 234e4204992SArnaldo Carvalho de Melo 235aeafcbafSArnaldo Carvalho de Melo pr_debug4("%s: %s %#" PRIx64 "-%#" PRIx64 "\n", 236aeafcbafSArnaldo Carvalho de Melo __func__, name, start, sym->end); 237aeafcbafSArnaldo Carvalho de Melo memcpy(sym->name, name, namelen); 238e4204992SArnaldo Carvalho de Melo 239aeafcbafSArnaldo Carvalho de Melo return sym; 24086470930SIngo Molnar } 24186470930SIngo Molnar 242aeafcbafSArnaldo Carvalho de Melo void symbol__delete(struct symbol *sym) 24386470930SIngo Molnar { 244aeafcbafSArnaldo Carvalho de Melo free(((void *)sym) - symbol_conf.priv_size); 24586470930SIngo Molnar } 24686470930SIngo Molnar 247cdd059d7SJiri Olsa size_t symbol__fprintf(struct symbol *sym, FILE *fp) 24886470930SIngo Molnar { 2499486aa38SArnaldo Carvalho de Melo return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %c %s\n", 250aeafcbafSArnaldo Carvalho de Melo sym->start, sym->end, 251aeafcbafSArnaldo Carvalho de Melo sym->binding == STB_GLOBAL ? 'g' : 252aeafcbafSArnaldo Carvalho de Melo sym->binding == STB_LOCAL ? 'l' : 'w', 253aeafcbafSArnaldo Carvalho de Melo sym->name); 25486470930SIngo Molnar } 25586470930SIngo Molnar 256a978f2abSAkihiro Nagai size_t symbol__fprintf_symname_offs(const struct symbol *sym, 257a978f2abSAkihiro Nagai const struct addr_location *al, FILE *fp) 258a978f2abSAkihiro Nagai { 259a978f2abSAkihiro Nagai unsigned long offset; 260a978f2abSAkihiro Nagai size_t length; 261a978f2abSAkihiro Nagai 262a978f2abSAkihiro Nagai if (sym && sym->name) { 263a978f2abSAkihiro Nagai length = fprintf(fp, "%s", sym->name); 264a978f2abSAkihiro Nagai if (al) { 2650b8c25d9SDavid Ahern if (al->addr < sym->end) 266a978f2abSAkihiro Nagai offset = al->addr - sym->start; 2670b8c25d9SDavid Ahern else 2680b8c25d9SDavid Ahern offset = al->addr - al->map->start - sym->start; 269a978f2abSAkihiro Nagai length += fprintf(fp, "+0x%lx", offset); 270a978f2abSAkihiro Nagai } 271a978f2abSAkihiro Nagai return length; 272a978f2abSAkihiro Nagai } else 273a978f2abSAkihiro Nagai return fprintf(fp, "[unknown]"); 274a978f2abSAkihiro Nagai } 275a978f2abSAkihiro Nagai 276547a92e0SAkihiro Nagai size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp) 277547a92e0SAkihiro Nagai { 278a978f2abSAkihiro Nagai return symbol__fprintf_symname_offs(sym, NULL, fp); 279547a92e0SAkihiro Nagai } 280547a92e0SAkihiro Nagai 281cdd059d7SJiri Olsa void symbols__delete(struct rb_root *symbols) 28286470930SIngo Molnar { 28386470930SIngo Molnar struct symbol *pos; 284aeafcbafSArnaldo Carvalho de Melo struct rb_node *next = rb_first(symbols); 28586470930SIngo Molnar 28686470930SIngo Molnar while (next) { 28786470930SIngo Molnar pos = rb_entry(next, struct symbol, rb_node); 28886470930SIngo Molnar next = rb_next(&pos->rb_node); 289aeafcbafSArnaldo Carvalho de Melo rb_erase(&pos->rb_node, symbols); 29000a192b3SArnaldo Carvalho de Melo symbol__delete(pos); 29186470930SIngo Molnar } 29286470930SIngo Molnar } 29386470930SIngo Molnar 294e5a1845fSNamhyung Kim void symbols__insert(struct rb_root *symbols, struct symbol *sym) 29586470930SIngo Molnar { 296aeafcbafSArnaldo Carvalho de Melo struct rb_node **p = &symbols->rb_node; 29786470930SIngo Molnar struct rb_node *parent = NULL; 2989cffa8d5SPaul Mackerras const u64 ip = sym->start; 29986470930SIngo Molnar struct symbol *s; 30086470930SIngo Molnar 30186470930SIngo Molnar while (*p != NULL) { 30286470930SIngo Molnar parent = *p; 30386470930SIngo Molnar s = rb_entry(parent, struct symbol, rb_node); 30486470930SIngo Molnar if (ip < s->start) 30586470930SIngo Molnar p = &(*p)->rb_left; 30686470930SIngo Molnar else 30786470930SIngo Molnar p = &(*p)->rb_right; 30886470930SIngo Molnar } 30986470930SIngo Molnar rb_link_node(&sym->rb_node, parent, p); 310aeafcbafSArnaldo Carvalho de Melo rb_insert_color(&sym->rb_node, symbols); 31186470930SIngo Molnar } 31286470930SIngo Molnar 313aeafcbafSArnaldo Carvalho de Melo static struct symbol *symbols__find(struct rb_root *symbols, u64 ip) 31486470930SIngo Molnar { 31586470930SIngo Molnar struct rb_node *n; 31686470930SIngo Molnar 317aeafcbafSArnaldo Carvalho de Melo if (symbols == NULL) 31886470930SIngo Molnar return NULL; 31986470930SIngo Molnar 320aeafcbafSArnaldo Carvalho de Melo n = symbols->rb_node; 32186470930SIngo Molnar 32286470930SIngo Molnar while (n) { 32386470930SIngo Molnar struct symbol *s = rb_entry(n, struct symbol, rb_node); 32486470930SIngo Molnar 32586470930SIngo Molnar if (ip < s->start) 32686470930SIngo Molnar n = n->rb_left; 32786470930SIngo Molnar else if (ip > s->end) 32886470930SIngo Molnar n = n->rb_right; 32986470930SIngo Molnar else 33086470930SIngo Molnar return s; 33186470930SIngo Molnar } 33286470930SIngo Molnar 33386470930SIngo Molnar return NULL; 33486470930SIngo Molnar } 33586470930SIngo Molnar 3368e0cf965SAdrian Hunter static struct symbol *symbols__first(struct rb_root *symbols) 3378e0cf965SAdrian Hunter { 3388e0cf965SAdrian Hunter struct rb_node *n = rb_first(symbols); 3398e0cf965SAdrian Hunter 3408e0cf965SAdrian Hunter if (n) 3418e0cf965SAdrian Hunter return rb_entry(n, struct symbol, rb_node); 3428e0cf965SAdrian Hunter 3438e0cf965SAdrian Hunter return NULL; 3448e0cf965SAdrian Hunter } 3458e0cf965SAdrian Hunter 34679406cd7SArnaldo Carvalho de Melo struct symbol_name_rb_node { 34779406cd7SArnaldo Carvalho de Melo struct rb_node rb_node; 34879406cd7SArnaldo Carvalho de Melo struct symbol sym; 34979406cd7SArnaldo Carvalho de Melo }; 35079406cd7SArnaldo Carvalho de Melo 351aeafcbafSArnaldo Carvalho de Melo static void symbols__insert_by_name(struct rb_root *symbols, struct symbol *sym) 35279406cd7SArnaldo Carvalho de Melo { 353aeafcbafSArnaldo Carvalho de Melo struct rb_node **p = &symbols->rb_node; 35479406cd7SArnaldo Carvalho de Melo struct rb_node *parent = NULL; 35502a9d037SRabin Vincent struct symbol_name_rb_node *symn, *s; 35602a9d037SRabin Vincent 35702a9d037SRabin Vincent symn = container_of(sym, struct symbol_name_rb_node, sym); 35879406cd7SArnaldo Carvalho de Melo 35979406cd7SArnaldo Carvalho de Melo while (*p != NULL) { 36079406cd7SArnaldo Carvalho de Melo parent = *p; 36179406cd7SArnaldo Carvalho de Melo s = rb_entry(parent, struct symbol_name_rb_node, rb_node); 36279406cd7SArnaldo Carvalho de Melo if (strcmp(sym->name, s->sym.name) < 0) 36379406cd7SArnaldo Carvalho de Melo p = &(*p)->rb_left; 36479406cd7SArnaldo Carvalho de Melo else 36579406cd7SArnaldo Carvalho de Melo p = &(*p)->rb_right; 36679406cd7SArnaldo Carvalho de Melo } 36779406cd7SArnaldo Carvalho de Melo rb_link_node(&symn->rb_node, parent, p); 368aeafcbafSArnaldo Carvalho de Melo rb_insert_color(&symn->rb_node, symbols); 36979406cd7SArnaldo Carvalho de Melo } 37079406cd7SArnaldo Carvalho de Melo 371aeafcbafSArnaldo Carvalho de Melo static void symbols__sort_by_name(struct rb_root *symbols, 372aeafcbafSArnaldo Carvalho de Melo struct rb_root *source) 37379406cd7SArnaldo Carvalho de Melo { 37479406cd7SArnaldo Carvalho de Melo struct rb_node *nd; 37579406cd7SArnaldo Carvalho de Melo 37679406cd7SArnaldo Carvalho de Melo for (nd = rb_first(source); nd; nd = rb_next(nd)) { 37779406cd7SArnaldo Carvalho de Melo struct symbol *pos = rb_entry(nd, struct symbol, rb_node); 378aeafcbafSArnaldo Carvalho de Melo symbols__insert_by_name(symbols, pos); 37979406cd7SArnaldo Carvalho de Melo } 38079406cd7SArnaldo Carvalho de Melo } 38179406cd7SArnaldo Carvalho de Melo 382aeafcbafSArnaldo Carvalho de Melo static struct symbol *symbols__find_by_name(struct rb_root *symbols, 383aeafcbafSArnaldo Carvalho de Melo const char *name) 38479406cd7SArnaldo Carvalho de Melo { 38579406cd7SArnaldo Carvalho de Melo struct rb_node *n; 38679406cd7SArnaldo Carvalho de Melo 387aeafcbafSArnaldo Carvalho de Melo if (symbols == NULL) 38879406cd7SArnaldo Carvalho de Melo return NULL; 38979406cd7SArnaldo Carvalho de Melo 390aeafcbafSArnaldo Carvalho de Melo n = symbols->rb_node; 39179406cd7SArnaldo Carvalho de Melo 39279406cd7SArnaldo Carvalho de Melo while (n) { 39379406cd7SArnaldo Carvalho de Melo struct symbol_name_rb_node *s; 39479406cd7SArnaldo Carvalho de Melo int cmp; 39579406cd7SArnaldo Carvalho de Melo 39679406cd7SArnaldo Carvalho de Melo s = rb_entry(n, struct symbol_name_rb_node, rb_node); 39779406cd7SArnaldo Carvalho de Melo cmp = strcmp(name, s->sym.name); 39879406cd7SArnaldo Carvalho de Melo 39979406cd7SArnaldo Carvalho de Melo if (cmp < 0) 40079406cd7SArnaldo Carvalho de Melo n = n->rb_left; 40179406cd7SArnaldo Carvalho de Melo else if (cmp > 0) 40279406cd7SArnaldo Carvalho de Melo n = n->rb_right; 40379406cd7SArnaldo Carvalho de Melo else 40479406cd7SArnaldo Carvalho de Melo return &s->sym; 40579406cd7SArnaldo Carvalho de Melo } 40679406cd7SArnaldo Carvalho de Melo 40779406cd7SArnaldo Carvalho de Melo return NULL; 40879406cd7SArnaldo Carvalho de Melo } 40979406cd7SArnaldo Carvalho de Melo 410aeafcbafSArnaldo Carvalho de Melo struct symbol *dso__find_symbol(struct dso *dso, 41179406cd7SArnaldo Carvalho de Melo enum map_type type, u64 addr) 412fcf1203aSArnaldo Carvalho de Melo { 413aeafcbafSArnaldo Carvalho de Melo return symbols__find(&dso->symbols[type], addr); 414fcf1203aSArnaldo Carvalho de Melo } 415fcf1203aSArnaldo Carvalho de Melo 4168e0cf965SAdrian Hunter struct symbol *dso__first_symbol(struct dso *dso, enum map_type type) 4178e0cf965SAdrian Hunter { 4188e0cf965SAdrian Hunter return symbols__first(&dso->symbols[type]); 4198e0cf965SAdrian Hunter } 4208e0cf965SAdrian Hunter 421aeafcbafSArnaldo Carvalho de Melo struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type, 42279406cd7SArnaldo Carvalho de Melo const char *name) 42379406cd7SArnaldo Carvalho de Melo { 424aeafcbafSArnaldo Carvalho de Melo return symbols__find_by_name(&dso->symbol_names[type], name); 42579406cd7SArnaldo Carvalho de Melo } 42679406cd7SArnaldo Carvalho de Melo 427aeafcbafSArnaldo Carvalho de Melo void dso__sort_by_name(struct dso *dso, enum map_type type) 42879406cd7SArnaldo Carvalho de Melo { 429aeafcbafSArnaldo Carvalho de Melo dso__set_sorted_by_name(dso, type); 430aeafcbafSArnaldo Carvalho de Melo return symbols__sort_by_name(&dso->symbol_names[type], 431aeafcbafSArnaldo Carvalho de Melo &dso->symbols[type]); 43279406cd7SArnaldo Carvalho de Melo } 43379406cd7SArnaldo Carvalho de Melo 434aeafcbafSArnaldo Carvalho de Melo size_t dso__fprintf_symbols_by_name(struct dso *dso, 435aeafcbafSArnaldo Carvalho de Melo enum map_type type, FILE *fp) 43690f18e63SSrikar Dronamraju { 43790f18e63SSrikar Dronamraju size_t ret = 0; 43890f18e63SSrikar Dronamraju struct rb_node *nd; 43990f18e63SSrikar Dronamraju struct symbol_name_rb_node *pos; 44090f18e63SSrikar Dronamraju 441aeafcbafSArnaldo Carvalho de Melo for (nd = rb_first(&dso->symbol_names[type]); nd; nd = rb_next(nd)) { 44290f18e63SSrikar Dronamraju pos = rb_entry(nd, struct symbol_name_rb_node, rb_node); 44390f18e63SSrikar Dronamraju fprintf(fp, "%s\n", pos->sym.name); 44490f18e63SSrikar Dronamraju } 44590f18e63SSrikar Dronamraju 44690f18e63SSrikar Dronamraju return ret; 44790f18e63SSrikar Dronamraju } 44890f18e63SSrikar Dronamraju 4499e201442SArnaldo Carvalho de Melo int kallsyms__parse(const char *filename, void *arg, 4509e201442SArnaldo Carvalho de Melo int (*process_symbol)(void *arg, const char *name, 45182151520SCody P Schafer char type, u64 start)) 45286470930SIngo Molnar { 45386470930SIngo Molnar char *line = NULL; 45486470930SIngo Molnar size_t n; 4553b01a413SArnaldo Carvalho de Melo int err = -1; 4569e201442SArnaldo Carvalho de Melo FILE *file = fopen(filename, "r"); 45786470930SIngo Molnar 45886470930SIngo Molnar if (file == NULL) 45986470930SIngo Molnar goto out_failure; 46086470930SIngo Molnar 4613b01a413SArnaldo Carvalho de Melo err = 0; 4623b01a413SArnaldo Carvalho de Melo 46386470930SIngo Molnar while (!feof(file)) { 4649cffa8d5SPaul Mackerras u64 start; 46586470930SIngo Molnar int line_len, len; 46686470930SIngo Molnar char symbol_type; 4672e538c4aSArnaldo Carvalho de Melo char *symbol_name; 46886470930SIngo Molnar 46986470930SIngo Molnar line_len = getline(&line, &n, file); 470a1645ce1SZhang, Yanmin if (line_len < 0 || !line) 47186470930SIngo Molnar break; 47286470930SIngo Molnar 47386470930SIngo Molnar line[--line_len] = '\0'; /* \n */ 47486470930SIngo Molnar 47586470930SIngo Molnar len = hex2u64(line, &start); 47686470930SIngo Molnar 47786470930SIngo Molnar len++; 47886470930SIngo Molnar if (len + 2 >= line_len) 47986470930SIngo Molnar continue; 48086470930SIngo Molnar 48131877908SAnton Blanchard symbol_type = line[len]; 4823b01a413SArnaldo Carvalho de Melo len += 2; 4833b01a413SArnaldo Carvalho de Melo symbol_name = line + len; 4843b01a413SArnaldo Carvalho de Melo len = line_len - len; 485682b335aSArnaldo Carvalho de Melo 4863b01a413SArnaldo Carvalho de Melo if (len >= KSYM_NAME_LEN) { 4873b01a413SArnaldo Carvalho de Melo err = -1; 4883b01a413SArnaldo Carvalho de Melo break; 4893b01a413SArnaldo Carvalho de Melo } 4903b01a413SArnaldo Carvalho de Melo 4913f5a4272SAnton Blanchard err = process_symbol(arg, symbol_name, 49282151520SCody P Schafer symbol_type, start); 493682b335aSArnaldo Carvalho de Melo if (err) 494682b335aSArnaldo Carvalho de Melo break; 495682b335aSArnaldo Carvalho de Melo } 496682b335aSArnaldo Carvalho de Melo 497682b335aSArnaldo Carvalho de Melo free(line); 498682b335aSArnaldo Carvalho de Melo fclose(file); 499682b335aSArnaldo Carvalho de Melo return err; 500682b335aSArnaldo Carvalho de Melo 501682b335aSArnaldo Carvalho de Melo out_failure: 502682b335aSArnaldo Carvalho de Melo return -1; 503682b335aSArnaldo Carvalho de Melo } 504682b335aSArnaldo Carvalho de Melo 505316d70d6SAdrian Hunter int modules__parse(const char *filename, void *arg, 506316d70d6SAdrian Hunter int (*process_module)(void *arg, const char *name, 507316d70d6SAdrian Hunter u64 start)) 508316d70d6SAdrian Hunter { 509316d70d6SAdrian Hunter char *line = NULL; 510316d70d6SAdrian Hunter size_t n; 511316d70d6SAdrian Hunter FILE *file; 512316d70d6SAdrian Hunter int err = 0; 513316d70d6SAdrian Hunter 514316d70d6SAdrian Hunter file = fopen(filename, "r"); 515316d70d6SAdrian Hunter if (file == NULL) 516316d70d6SAdrian Hunter return -1; 517316d70d6SAdrian Hunter 518316d70d6SAdrian Hunter while (1) { 519316d70d6SAdrian Hunter char name[PATH_MAX]; 520316d70d6SAdrian Hunter u64 start; 521316d70d6SAdrian Hunter char *sep; 522316d70d6SAdrian Hunter ssize_t line_len; 523316d70d6SAdrian Hunter 524316d70d6SAdrian Hunter line_len = getline(&line, &n, file); 525316d70d6SAdrian Hunter if (line_len < 0) { 526316d70d6SAdrian Hunter if (feof(file)) 527316d70d6SAdrian Hunter break; 528316d70d6SAdrian Hunter err = -1; 529316d70d6SAdrian Hunter goto out; 530316d70d6SAdrian Hunter } 531316d70d6SAdrian Hunter 532316d70d6SAdrian Hunter if (!line) { 533316d70d6SAdrian Hunter err = -1; 534316d70d6SAdrian Hunter goto out; 535316d70d6SAdrian Hunter } 536316d70d6SAdrian Hunter 537316d70d6SAdrian Hunter line[--line_len] = '\0'; /* \n */ 538316d70d6SAdrian Hunter 539316d70d6SAdrian Hunter sep = strrchr(line, 'x'); 540316d70d6SAdrian Hunter if (sep == NULL) 541316d70d6SAdrian Hunter continue; 542316d70d6SAdrian Hunter 543316d70d6SAdrian Hunter hex2u64(sep + 1, &start); 544316d70d6SAdrian Hunter 545316d70d6SAdrian Hunter sep = strchr(line, ' '); 546316d70d6SAdrian Hunter if (sep == NULL) 547316d70d6SAdrian Hunter continue; 548316d70d6SAdrian Hunter 549316d70d6SAdrian Hunter *sep = '\0'; 550316d70d6SAdrian Hunter 551316d70d6SAdrian Hunter scnprintf(name, sizeof(name), "[%s]", line); 552316d70d6SAdrian Hunter 553316d70d6SAdrian Hunter err = process_module(arg, name, start); 554316d70d6SAdrian Hunter if (err) 555316d70d6SAdrian Hunter break; 556316d70d6SAdrian Hunter } 557316d70d6SAdrian Hunter out: 558316d70d6SAdrian Hunter free(line); 559316d70d6SAdrian Hunter fclose(file); 560316d70d6SAdrian Hunter return err; 561316d70d6SAdrian Hunter } 562316d70d6SAdrian Hunter 563682b335aSArnaldo Carvalho de Melo struct process_kallsyms_args { 564682b335aSArnaldo Carvalho de Melo struct map *map; 565682b335aSArnaldo Carvalho de Melo struct dso *dso; 566682b335aSArnaldo Carvalho de Melo }; 567682b335aSArnaldo Carvalho de Melo 568c408fedfSArnaldo Carvalho de Melo static u8 kallsyms2elf_type(char type) 569c408fedfSArnaldo Carvalho de Melo { 570c408fedfSArnaldo Carvalho de Melo if (type == 'W') 571c408fedfSArnaldo Carvalho de Melo return STB_WEAK; 572c408fedfSArnaldo Carvalho de Melo 573c408fedfSArnaldo Carvalho de Melo return isupper(type) ? STB_GLOBAL : STB_LOCAL; 574c408fedfSArnaldo Carvalho de Melo } 575c408fedfSArnaldo Carvalho de Melo 576*82d1deb0SDavid Ahern bool symbol__is_idle(struct symbol *sym) 577*82d1deb0SDavid Ahern { 578*82d1deb0SDavid Ahern const char * const idle_symbols[] = { 579*82d1deb0SDavid Ahern "cpu_idle", 580*82d1deb0SDavid Ahern "intel_idle", 581*82d1deb0SDavid Ahern "default_idle", 582*82d1deb0SDavid Ahern "native_safe_halt", 583*82d1deb0SDavid Ahern "enter_idle", 584*82d1deb0SDavid Ahern "exit_idle", 585*82d1deb0SDavid Ahern "mwait_idle", 586*82d1deb0SDavid Ahern "mwait_idle_with_hints", 587*82d1deb0SDavid Ahern "poll_idle", 588*82d1deb0SDavid Ahern "ppc64_runlatch_off", 589*82d1deb0SDavid Ahern "pseries_dedicated_idle_sleep", 590*82d1deb0SDavid Ahern NULL 591*82d1deb0SDavid Ahern }; 592*82d1deb0SDavid Ahern 593*82d1deb0SDavid Ahern int i; 594*82d1deb0SDavid Ahern 595*82d1deb0SDavid Ahern if (!sym) 596*82d1deb0SDavid Ahern return false; 597*82d1deb0SDavid Ahern 598*82d1deb0SDavid Ahern for (i = 0; idle_symbols[i]; i++) { 599*82d1deb0SDavid Ahern if (!strcmp(idle_symbols[i], sym->name)) 600*82d1deb0SDavid Ahern return true; 601*82d1deb0SDavid Ahern } 602*82d1deb0SDavid Ahern 603*82d1deb0SDavid Ahern return false; 604*82d1deb0SDavid Ahern } 605*82d1deb0SDavid Ahern 606682b335aSArnaldo Carvalho de Melo static int map__process_kallsym_symbol(void *arg, const char *name, 60782151520SCody P Schafer char type, u64 start) 608682b335aSArnaldo Carvalho de Melo { 609682b335aSArnaldo Carvalho de Melo struct symbol *sym; 610682b335aSArnaldo Carvalho de Melo struct process_kallsyms_args *a = arg; 611682b335aSArnaldo Carvalho de Melo struct rb_root *root = &a->dso->symbols[a->map->type]; 612682b335aSArnaldo Carvalho de Melo 613682b335aSArnaldo Carvalho de Melo if (!symbol_type__is_a(type, a->map->type)) 614682b335aSArnaldo Carvalho de Melo return 0; 615682b335aSArnaldo Carvalho de Melo 61682151520SCody P Schafer /* 61782151520SCody P Schafer * module symbols are not sorted so we add all 61882151520SCody P Schafer * symbols, setting length to 0, and rely on 61982151520SCody P Schafer * symbols__fixup_end() to fix it up. 62082151520SCody P Schafer */ 62182151520SCody P Schafer sym = symbol__new(start, 0, kallsyms2elf_type(type), name); 6222e538c4aSArnaldo Carvalho de Melo if (sym == NULL) 623682b335aSArnaldo Carvalho de Melo return -ENOMEM; 62482164161SArnaldo Carvalho de Melo /* 62582164161SArnaldo Carvalho de Melo * We will pass the symbols to the filter later, in 6264e06255fSArnaldo Carvalho de Melo * map__split_kallsyms, when we have split the maps per module 62782164161SArnaldo Carvalho de Melo */ 6284e06255fSArnaldo Carvalho de Melo symbols__insert(root, sym); 629a1645ce1SZhang, Yanmin 630682b335aSArnaldo Carvalho de Melo return 0; 6312e538c4aSArnaldo Carvalho de Melo } 6322e538c4aSArnaldo Carvalho de Melo 633682b335aSArnaldo Carvalho de Melo /* 634682b335aSArnaldo Carvalho de Melo * Loads the function entries in /proc/kallsyms into kernel_map->dso, 635682b335aSArnaldo Carvalho de Melo * so that we can in the next step set the symbol ->end address and then 636682b335aSArnaldo Carvalho de Melo * call kernel_maps__split_kallsyms. 637682b335aSArnaldo Carvalho de Melo */ 638aeafcbafSArnaldo Carvalho de Melo static int dso__load_all_kallsyms(struct dso *dso, const char *filename, 6399e201442SArnaldo Carvalho de Melo struct map *map) 640682b335aSArnaldo Carvalho de Melo { 641aeafcbafSArnaldo Carvalho de Melo struct process_kallsyms_args args = { .map = map, .dso = dso, }; 6429e201442SArnaldo Carvalho de Melo return kallsyms__parse(filename, &args, map__process_kallsym_symbol); 6432e538c4aSArnaldo Carvalho de Melo } 6442e538c4aSArnaldo Carvalho de Melo 6458e0cf965SAdrian Hunter static int dso__split_kallsyms_for_kcore(struct dso *dso, struct map *map, 6468e0cf965SAdrian Hunter symbol_filter_t filter) 6478e0cf965SAdrian Hunter { 6488e0cf965SAdrian Hunter struct map_groups *kmaps = map__kmap(map)->kmaps; 6498e0cf965SAdrian Hunter struct map *curr_map; 6508e0cf965SAdrian Hunter struct symbol *pos; 6518e0cf965SAdrian Hunter int count = 0, moved = 0; 6528e0cf965SAdrian Hunter struct rb_root *root = &dso->symbols[map->type]; 6538e0cf965SAdrian Hunter struct rb_node *next = rb_first(root); 6548e0cf965SAdrian Hunter 6558e0cf965SAdrian Hunter while (next) { 6568e0cf965SAdrian Hunter char *module; 6578e0cf965SAdrian Hunter 6588e0cf965SAdrian Hunter pos = rb_entry(next, struct symbol, rb_node); 6598e0cf965SAdrian Hunter next = rb_next(&pos->rb_node); 6608e0cf965SAdrian Hunter 6618e0cf965SAdrian Hunter module = strchr(pos->name, '\t'); 6628e0cf965SAdrian Hunter if (module) 6638e0cf965SAdrian Hunter *module = '\0'; 6648e0cf965SAdrian Hunter 6658e0cf965SAdrian Hunter curr_map = map_groups__find(kmaps, map->type, pos->start); 6668e0cf965SAdrian Hunter 6678e0cf965SAdrian Hunter if (!curr_map || (filter && filter(curr_map, pos))) { 6688e0cf965SAdrian Hunter rb_erase(&pos->rb_node, root); 6698e0cf965SAdrian Hunter symbol__delete(pos); 6708e0cf965SAdrian Hunter } else { 6718e0cf965SAdrian Hunter pos->start -= curr_map->start - curr_map->pgoff; 6728e0cf965SAdrian Hunter if (pos->end) 6738e0cf965SAdrian Hunter pos->end -= curr_map->start - curr_map->pgoff; 6748e0cf965SAdrian Hunter if (curr_map != map) { 6758e0cf965SAdrian Hunter rb_erase(&pos->rb_node, root); 6768e0cf965SAdrian Hunter symbols__insert( 6778e0cf965SAdrian Hunter &curr_map->dso->symbols[curr_map->type], 6788e0cf965SAdrian Hunter pos); 6798e0cf965SAdrian Hunter ++moved; 6808e0cf965SAdrian Hunter } else { 6818e0cf965SAdrian Hunter ++count; 6828e0cf965SAdrian Hunter } 6838e0cf965SAdrian Hunter } 6848e0cf965SAdrian Hunter } 6858e0cf965SAdrian Hunter 6868e0cf965SAdrian Hunter /* Symbols have been adjusted */ 6878e0cf965SAdrian Hunter dso->adjust_symbols = 1; 6888e0cf965SAdrian Hunter 6898e0cf965SAdrian Hunter return count + moved; 6908e0cf965SAdrian Hunter } 6918e0cf965SAdrian Hunter 6922e538c4aSArnaldo Carvalho de Melo /* 6932e538c4aSArnaldo Carvalho de Melo * Split the symbols into maps, making sure there are no overlaps, i.e. the 6942e538c4aSArnaldo Carvalho de Melo * kernel range is broken in several maps, named [kernel].N, as we don't have 6952e538c4aSArnaldo Carvalho de Melo * the original ELF section names vmlinux have. 6962e538c4aSArnaldo Carvalho de Melo */ 697aeafcbafSArnaldo Carvalho de Melo static int dso__split_kallsyms(struct dso *dso, struct map *map, 6989de89fe7SArnaldo Carvalho de Melo symbol_filter_t filter) 6992e538c4aSArnaldo Carvalho de Melo { 7009de89fe7SArnaldo Carvalho de Melo struct map_groups *kmaps = map__kmap(map)->kmaps; 70123346f21SArnaldo Carvalho de Melo struct machine *machine = kmaps->machine; 7024e06255fSArnaldo Carvalho de Melo struct map *curr_map = map; 7032e538c4aSArnaldo Carvalho de Melo struct symbol *pos; 7048a953312SArnaldo Carvalho de Melo int count = 0, moved = 0; 705aeafcbafSArnaldo Carvalho de Melo struct rb_root *root = &dso->symbols[map->type]; 7064e06255fSArnaldo Carvalho de Melo struct rb_node *next = rb_first(root); 7072e538c4aSArnaldo Carvalho de Melo int kernel_range = 0; 7082e538c4aSArnaldo Carvalho de Melo 7092e538c4aSArnaldo Carvalho de Melo while (next) { 7102e538c4aSArnaldo Carvalho de Melo char *module; 7112e538c4aSArnaldo Carvalho de Melo 7122e538c4aSArnaldo Carvalho de Melo pos = rb_entry(next, struct symbol, rb_node); 7132e538c4aSArnaldo Carvalho de Melo next = rb_next(&pos->rb_node); 7142e538c4aSArnaldo Carvalho de Melo 7152e538c4aSArnaldo Carvalho de Melo module = strchr(pos->name, '\t'); 7162e538c4aSArnaldo Carvalho de Melo if (module) { 71775be6cf4SArnaldo Carvalho de Melo if (!symbol_conf.use_modules) 7181de8e245SArnaldo Carvalho de Melo goto discard_symbol; 7191de8e245SArnaldo Carvalho de Melo 7202e538c4aSArnaldo Carvalho de Melo *module++ = '\0'; 7212e538c4aSArnaldo Carvalho de Melo 722b7cece76SArnaldo Carvalho de Melo if (strcmp(curr_map->dso->short_name, module)) { 723a1645ce1SZhang, Yanmin if (curr_map != map && 724aeafcbafSArnaldo Carvalho de Melo dso->kernel == DSO_TYPE_GUEST_KERNEL && 72523346f21SArnaldo Carvalho de Melo machine__is_default_guest(machine)) { 726a1645ce1SZhang, Yanmin /* 727a1645ce1SZhang, Yanmin * We assume all symbols of a module are 728a1645ce1SZhang, Yanmin * continuous in * kallsyms, so curr_map 729a1645ce1SZhang, Yanmin * points to a module and all its 730a1645ce1SZhang, Yanmin * symbols are in its kmap. Mark it as 731a1645ce1SZhang, Yanmin * loaded. 732a1645ce1SZhang, Yanmin */ 733a1645ce1SZhang, Yanmin dso__set_loaded(curr_map->dso, 734a1645ce1SZhang, Yanmin curr_map->type); 735af427bf5SArnaldo Carvalho de Melo } 736b7cece76SArnaldo Carvalho de Melo 737a1645ce1SZhang, Yanmin curr_map = map_groups__find_by_name(kmaps, 738a1645ce1SZhang, Yanmin map->type, module); 739a1645ce1SZhang, Yanmin if (curr_map == NULL) { 7402f51903bSArnaldo Carvalho de Melo pr_debug("%s/proc/{kallsyms,modules} " 741a1645ce1SZhang, Yanmin "inconsistency while looking " 742a1645ce1SZhang, Yanmin "for \"%s\" module!\n", 74323346f21SArnaldo Carvalho de Melo machine->root_dir, module); 744a1645ce1SZhang, Yanmin curr_map = map; 745a1645ce1SZhang, Yanmin goto discard_symbol; 746a1645ce1SZhang, Yanmin } 747a1645ce1SZhang, Yanmin 748a1645ce1SZhang, Yanmin if (curr_map->dso->loaded && 74923346f21SArnaldo Carvalho de Melo !machine__is_default_guest(machine)) 750b7cece76SArnaldo Carvalho de Melo goto discard_symbol; 751af427bf5SArnaldo Carvalho de Melo } 75286470930SIngo Molnar /* 7532e538c4aSArnaldo Carvalho de Melo * So that we look just like we get from .ko files, 7542e538c4aSArnaldo Carvalho de Melo * i.e. not prelinked, relative to map->start. 75586470930SIngo Molnar */ 7564e06255fSArnaldo Carvalho de Melo pos->start = curr_map->map_ip(curr_map, pos->start); 7574e06255fSArnaldo Carvalho de Melo pos->end = curr_map->map_ip(curr_map, pos->end); 7584e06255fSArnaldo Carvalho de Melo } else if (curr_map != map) { 7592e538c4aSArnaldo Carvalho de Melo char dso_name[PATH_MAX]; 760aeafcbafSArnaldo Carvalho de Melo struct dso *ndso; 76186470930SIngo Molnar 7628a953312SArnaldo Carvalho de Melo if (count == 0) { 7638a953312SArnaldo Carvalho de Melo curr_map = map; 7648a953312SArnaldo Carvalho de Melo goto filter_symbol; 7658a953312SArnaldo Carvalho de Melo } 7668a953312SArnaldo Carvalho de Melo 767aeafcbafSArnaldo Carvalho de Melo if (dso->kernel == DSO_TYPE_GUEST_KERNEL) 768a1645ce1SZhang, Yanmin snprintf(dso_name, sizeof(dso_name), 769a1645ce1SZhang, Yanmin "[guest.kernel].%d", 770a1645ce1SZhang, Yanmin kernel_range++); 771a1645ce1SZhang, Yanmin else 772a1645ce1SZhang, Yanmin snprintf(dso_name, sizeof(dso_name), 773a1645ce1SZhang, Yanmin "[kernel].%d", 7742e538c4aSArnaldo Carvalho de Melo kernel_range++); 77586470930SIngo Molnar 776aeafcbafSArnaldo Carvalho de Melo ndso = dso__new(dso_name); 777aeafcbafSArnaldo Carvalho de Melo if (ndso == NULL) 7782e538c4aSArnaldo Carvalho de Melo return -1; 7792e538c4aSArnaldo Carvalho de Melo 780aeafcbafSArnaldo Carvalho de Melo ndso->kernel = dso->kernel; 781a1645ce1SZhang, Yanmin 782aeafcbafSArnaldo Carvalho de Melo curr_map = map__new2(pos->start, ndso, map->type); 78337fe5fcbSZhang, Yanmin if (curr_map == NULL) { 784aeafcbafSArnaldo Carvalho de Melo dso__delete(ndso); 7852e538c4aSArnaldo Carvalho de Melo return -1; 7862e538c4aSArnaldo Carvalho de Melo } 7872e538c4aSArnaldo Carvalho de Melo 7884e06255fSArnaldo Carvalho de Melo curr_map->map_ip = curr_map->unmap_ip = identity__map_ip; 7899de89fe7SArnaldo Carvalho de Melo map_groups__insert(kmaps, curr_map); 7902e538c4aSArnaldo Carvalho de Melo ++kernel_range; 7912e538c4aSArnaldo Carvalho de Melo } 7928a953312SArnaldo Carvalho de Melo filter_symbol: 7934e06255fSArnaldo Carvalho de Melo if (filter && filter(curr_map, pos)) { 7941de8e245SArnaldo Carvalho de Melo discard_symbol: rb_erase(&pos->rb_node, root); 79500a192b3SArnaldo Carvalho de Melo symbol__delete(pos); 7962e538c4aSArnaldo Carvalho de Melo } else { 7974e06255fSArnaldo Carvalho de Melo if (curr_map != map) { 7984e06255fSArnaldo Carvalho de Melo rb_erase(&pos->rb_node, root); 7994e06255fSArnaldo Carvalho de Melo symbols__insert(&curr_map->dso->symbols[curr_map->type], pos); 8008a953312SArnaldo Carvalho de Melo ++moved; 8018a953312SArnaldo Carvalho de Melo } else 8028a953312SArnaldo Carvalho de Melo ++count; 8039974f496SMike Galbraith } 80486470930SIngo Molnar } 80586470930SIngo Molnar 806a1645ce1SZhang, Yanmin if (curr_map != map && 807aeafcbafSArnaldo Carvalho de Melo dso->kernel == DSO_TYPE_GUEST_KERNEL && 80823346f21SArnaldo Carvalho de Melo machine__is_default_guest(kmaps->machine)) { 809a1645ce1SZhang, Yanmin dso__set_loaded(curr_map->dso, curr_map->type); 810a1645ce1SZhang, Yanmin } 811a1645ce1SZhang, Yanmin 8128a953312SArnaldo Carvalho de Melo return count + moved; 81386470930SIngo Molnar } 81486470930SIngo Molnar 8153f067dcaSArnaldo Carvalho de Melo bool symbol__restricted_filename(const char *filename, 816ec80fde7SArnaldo Carvalho de Melo const char *restricted_filename) 817ec80fde7SArnaldo Carvalho de Melo { 818ec80fde7SArnaldo Carvalho de Melo bool restricted = false; 819ec80fde7SArnaldo Carvalho de Melo 820ec80fde7SArnaldo Carvalho de Melo if (symbol_conf.kptr_restrict) { 821ec80fde7SArnaldo Carvalho de Melo char *r = realpath(filename, NULL); 822ec80fde7SArnaldo Carvalho de Melo 823ec80fde7SArnaldo Carvalho de Melo if (r != NULL) { 824ec80fde7SArnaldo Carvalho de Melo restricted = strcmp(r, restricted_filename) == 0; 825ec80fde7SArnaldo Carvalho de Melo free(r); 826ec80fde7SArnaldo Carvalho de Melo return restricted; 827ec80fde7SArnaldo Carvalho de Melo } 828ec80fde7SArnaldo Carvalho de Melo } 829ec80fde7SArnaldo Carvalho de Melo 830ec80fde7SArnaldo Carvalho de Melo return restricted; 831ec80fde7SArnaldo Carvalho de Melo } 832ec80fde7SArnaldo Carvalho de Melo 83352afdaf9SAdrian Hunter struct module_info { 83452afdaf9SAdrian Hunter struct rb_node rb_node; 83552afdaf9SAdrian Hunter char *name; 83652afdaf9SAdrian Hunter u64 start; 83752afdaf9SAdrian Hunter }; 83852afdaf9SAdrian Hunter 83952afdaf9SAdrian Hunter static void add_module(struct module_info *mi, struct rb_root *modules) 84052afdaf9SAdrian Hunter { 84152afdaf9SAdrian Hunter struct rb_node **p = &modules->rb_node; 84252afdaf9SAdrian Hunter struct rb_node *parent = NULL; 84352afdaf9SAdrian Hunter struct module_info *m; 84452afdaf9SAdrian Hunter 84552afdaf9SAdrian Hunter while (*p != NULL) { 84652afdaf9SAdrian Hunter parent = *p; 84752afdaf9SAdrian Hunter m = rb_entry(parent, struct module_info, rb_node); 84852afdaf9SAdrian Hunter if (strcmp(mi->name, m->name) < 0) 84952afdaf9SAdrian Hunter p = &(*p)->rb_left; 85052afdaf9SAdrian Hunter else 85152afdaf9SAdrian Hunter p = &(*p)->rb_right; 85252afdaf9SAdrian Hunter } 85352afdaf9SAdrian Hunter rb_link_node(&mi->rb_node, parent, p); 85452afdaf9SAdrian Hunter rb_insert_color(&mi->rb_node, modules); 85552afdaf9SAdrian Hunter } 85652afdaf9SAdrian Hunter 85752afdaf9SAdrian Hunter static void delete_modules(struct rb_root *modules) 85852afdaf9SAdrian Hunter { 85952afdaf9SAdrian Hunter struct module_info *mi; 86052afdaf9SAdrian Hunter struct rb_node *next = rb_first(modules); 86152afdaf9SAdrian Hunter 86252afdaf9SAdrian Hunter while (next) { 86352afdaf9SAdrian Hunter mi = rb_entry(next, struct module_info, rb_node); 86452afdaf9SAdrian Hunter next = rb_next(&mi->rb_node); 86552afdaf9SAdrian Hunter rb_erase(&mi->rb_node, modules); 86652afdaf9SAdrian Hunter free(mi->name); 86752afdaf9SAdrian Hunter free(mi); 86852afdaf9SAdrian Hunter } 86952afdaf9SAdrian Hunter } 87052afdaf9SAdrian Hunter 87152afdaf9SAdrian Hunter static struct module_info *find_module(const char *name, 87252afdaf9SAdrian Hunter struct rb_root *modules) 87352afdaf9SAdrian Hunter { 87452afdaf9SAdrian Hunter struct rb_node *n = modules->rb_node; 87552afdaf9SAdrian Hunter 87652afdaf9SAdrian Hunter while (n) { 87752afdaf9SAdrian Hunter struct module_info *m; 87852afdaf9SAdrian Hunter int cmp; 87952afdaf9SAdrian Hunter 88052afdaf9SAdrian Hunter m = rb_entry(n, struct module_info, rb_node); 88152afdaf9SAdrian Hunter cmp = strcmp(name, m->name); 88252afdaf9SAdrian Hunter if (cmp < 0) 88352afdaf9SAdrian Hunter n = n->rb_left; 88452afdaf9SAdrian Hunter else if (cmp > 0) 88552afdaf9SAdrian Hunter n = n->rb_right; 88652afdaf9SAdrian Hunter else 88752afdaf9SAdrian Hunter return m; 88852afdaf9SAdrian Hunter } 88952afdaf9SAdrian Hunter 89052afdaf9SAdrian Hunter return NULL; 89152afdaf9SAdrian Hunter } 89252afdaf9SAdrian Hunter 89352afdaf9SAdrian Hunter static int __read_proc_modules(void *arg, const char *name, u64 start) 89452afdaf9SAdrian Hunter { 89552afdaf9SAdrian Hunter struct rb_root *modules = arg; 89652afdaf9SAdrian Hunter struct module_info *mi; 89752afdaf9SAdrian Hunter 89852afdaf9SAdrian Hunter mi = zalloc(sizeof(struct module_info)); 89952afdaf9SAdrian Hunter if (!mi) 90052afdaf9SAdrian Hunter return -ENOMEM; 90152afdaf9SAdrian Hunter 90252afdaf9SAdrian Hunter mi->name = strdup(name); 90352afdaf9SAdrian Hunter mi->start = start; 90452afdaf9SAdrian Hunter 90552afdaf9SAdrian Hunter if (!mi->name) { 90652afdaf9SAdrian Hunter free(mi); 90752afdaf9SAdrian Hunter return -ENOMEM; 90852afdaf9SAdrian Hunter } 90952afdaf9SAdrian Hunter 91052afdaf9SAdrian Hunter add_module(mi, modules); 91152afdaf9SAdrian Hunter 91252afdaf9SAdrian Hunter return 0; 91352afdaf9SAdrian Hunter } 91452afdaf9SAdrian Hunter 91552afdaf9SAdrian Hunter static int read_proc_modules(const char *filename, struct rb_root *modules) 91652afdaf9SAdrian Hunter { 91752afdaf9SAdrian Hunter if (symbol__restricted_filename(filename, "/proc/modules")) 91852afdaf9SAdrian Hunter return -1; 91952afdaf9SAdrian Hunter 92052afdaf9SAdrian Hunter if (modules__parse(filename, modules, __read_proc_modules)) { 92152afdaf9SAdrian Hunter delete_modules(modules); 92252afdaf9SAdrian Hunter return -1; 92352afdaf9SAdrian Hunter } 92452afdaf9SAdrian Hunter 92552afdaf9SAdrian Hunter return 0; 92652afdaf9SAdrian Hunter } 92752afdaf9SAdrian Hunter 928fc1b691dSAdrian Hunter int compare_proc_modules(const char *from, const char *to) 929fc1b691dSAdrian Hunter { 930fc1b691dSAdrian Hunter struct rb_root from_modules = RB_ROOT; 931fc1b691dSAdrian Hunter struct rb_root to_modules = RB_ROOT; 932fc1b691dSAdrian Hunter struct rb_node *from_node, *to_node; 933fc1b691dSAdrian Hunter struct module_info *from_m, *to_m; 934fc1b691dSAdrian Hunter int ret = -1; 935fc1b691dSAdrian Hunter 936fc1b691dSAdrian Hunter if (read_proc_modules(from, &from_modules)) 937fc1b691dSAdrian Hunter return -1; 938fc1b691dSAdrian Hunter 939fc1b691dSAdrian Hunter if (read_proc_modules(to, &to_modules)) 940fc1b691dSAdrian Hunter goto out_delete_from; 941fc1b691dSAdrian Hunter 942fc1b691dSAdrian Hunter from_node = rb_first(&from_modules); 943fc1b691dSAdrian Hunter to_node = rb_first(&to_modules); 944fc1b691dSAdrian Hunter while (from_node) { 945fc1b691dSAdrian Hunter if (!to_node) 946fc1b691dSAdrian Hunter break; 947fc1b691dSAdrian Hunter 948fc1b691dSAdrian Hunter from_m = rb_entry(from_node, struct module_info, rb_node); 949fc1b691dSAdrian Hunter to_m = rb_entry(to_node, struct module_info, rb_node); 950fc1b691dSAdrian Hunter 951fc1b691dSAdrian Hunter if (from_m->start != to_m->start || 952fc1b691dSAdrian Hunter strcmp(from_m->name, to_m->name)) 953fc1b691dSAdrian Hunter break; 954fc1b691dSAdrian Hunter 955fc1b691dSAdrian Hunter from_node = rb_next(from_node); 956fc1b691dSAdrian Hunter to_node = rb_next(to_node); 957fc1b691dSAdrian Hunter } 958fc1b691dSAdrian Hunter 959fc1b691dSAdrian Hunter if (!from_node && !to_node) 960fc1b691dSAdrian Hunter ret = 0; 961fc1b691dSAdrian Hunter 962fc1b691dSAdrian Hunter delete_modules(&to_modules); 963fc1b691dSAdrian Hunter out_delete_from: 964fc1b691dSAdrian Hunter delete_modules(&from_modules); 965fc1b691dSAdrian Hunter 966fc1b691dSAdrian Hunter return ret; 967fc1b691dSAdrian Hunter } 968fc1b691dSAdrian Hunter 96952afdaf9SAdrian Hunter static int do_validate_kcore_modules(const char *filename, struct map *map, 97052afdaf9SAdrian Hunter struct map_groups *kmaps) 97152afdaf9SAdrian Hunter { 97252afdaf9SAdrian Hunter struct rb_root modules = RB_ROOT; 97352afdaf9SAdrian Hunter struct map *old_map; 97452afdaf9SAdrian Hunter int err; 97552afdaf9SAdrian Hunter 97652afdaf9SAdrian Hunter err = read_proc_modules(filename, &modules); 97752afdaf9SAdrian Hunter if (err) 97852afdaf9SAdrian Hunter return err; 97952afdaf9SAdrian Hunter 98052afdaf9SAdrian Hunter old_map = map_groups__first(kmaps, map->type); 98152afdaf9SAdrian Hunter while (old_map) { 98252afdaf9SAdrian Hunter struct map *next = map_groups__next(old_map); 98352afdaf9SAdrian Hunter struct module_info *mi; 98452afdaf9SAdrian Hunter 98552afdaf9SAdrian Hunter if (old_map == map || old_map->start == map->start) { 98652afdaf9SAdrian Hunter /* The kernel map */ 98752afdaf9SAdrian Hunter old_map = next; 98852afdaf9SAdrian Hunter continue; 98952afdaf9SAdrian Hunter } 99052afdaf9SAdrian Hunter 99152afdaf9SAdrian Hunter /* Module must be in memory at the same address */ 99252afdaf9SAdrian Hunter mi = find_module(old_map->dso->short_name, &modules); 99352afdaf9SAdrian Hunter if (!mi || mi->start != old_map->start) { 99452afdaf9SAdrian Hunter err = -EINVAL; 99552afdaf9SAdrian Hunter goto out; 99652afdaf9SAdrian Hunter } 99752afdaf9SAdrian Hunter 99852afdaf9SAdrian Hunter old_map = next; 99952afdaf9SAdrian Hunter } 100052afdaf9SAdrian Hunter out: 100152afdaf9SAdrian Hunter delete_modules(&modules); 100252afdaf9SAdrian Hunter return err; 100352afdaf9SAdrian Hunter } 100452afdaf9SAdrian Hunter 100552afdaf9SAdrian Hunter /* 100652afdaf9SAdrian Hunter * If kallsyms is referenced by name then we look for filename in the same 100752afdaf9SAdrian Hunter * directory. 100852afdaf9SAdrian Hunter */ 100952afdaf9SAdrian Hunter static bool filename_from_kallsyms_filename(char *filename, 101052afdaf9SAdrian Hunter const char *base_name, 101152afdaf9SAdrian Hunter const char *kallsyms_filename) 101252afdaf9SAdrian Hunter { 101352afdaf9SAdrian Hunter char *name; 101452afdaf9SAdrian Hunter 101552afdaf9SAdrian Hunter strcpy(filename, kallsyms_filename); 101652afdaf9SAdrian Hunter name = strrchr(filename, '/'); 101752afdaf9SAdrian Hunter if (!name) 101852afdaf9SAdrian Hunter return false; 101952afdaf9SAdrian Hunter 102052afdaf9SAdrian Hunter name += 1; 102152afdaf9SAdrian Hunter 102252afdaf9SAdrian Hunter if (!strcmp(name, "kallsyms")) { 102352afdaf9SAdrian Hunter strcpy(name, base_name); 102452afdaf9SAdrian Hunter return true; 102552afdaf9SAdrian Hunter } 102652afdaf9SAdrian Hunter 102752afdaf9SAdrian Hunter return false; 102852afdaf9SAdrian Hunter } 102952afdaf9SAdrian Hunter 103052afdaf9SAdrian Hunter static int validate_kcore_modules(const char *kallsyms_filename, 103152afdaf9SAdrian Hunter struct map *map) 103252afdaf9SAdrian Hunter { 103352afdaf9SAdrian Hunter struct map_groups *kmaps = map__kmap(map)->kmaps; 103452afdaf9SAdrian Hunter char modules_filename[PATH_MAX]; 103552afdaf9SAdrian Hunter 103652afdaf9SAdrian Hunter if (!filename_from_kallsyms_filename(modules_filename, "modules", 103752afdaf9SAdrian Hunter kallsyms_filename)) 103852afdaf9SAdrian Hunter return -EINVAL; 103952afdaf9SAdrian Hunter 104052afdaf9SAdrian Hunter if (do_validate_kcore_modules(modules_filename, map, kmaps)) 104152afdaf9SAdrian Hunter return -EINVAL; 104252afdaf9SAdrian Hunter 104352afdaf9SAdrian Hunter return 0; 104452afdaf9SAdrian Hunter } 104552afdaf9SAdrian Hunter 10468e0cf965SAdrian Hunter struct kcore_mapfn_data { 10478e0cf965SAdrian Hunter struct dso *dso; 10488e0cf965SAdrian Hunter enum map_type type; 10498e0cf965SAdrian Hunter struct list_head maps; 10508e0cf965SAdrian Hunter }; 10518e0cf965SAdrian Hunter 10528e0cf965SAdrian Hunter static int kcore_mapfn(u64 start, u64 len, u64 pgoff, void *data) 10538e0cf965SAdrian Hunter { 10548e0cf965SAdrian Hunter struct kcore_mapfn_data *md = data; 10558e0cf965SAdrian Hunter struct map *map; 10568e0cf965SAdrian Hunter 10578e0cf965SAdrian Hunter map = map__new2(start, md->dso, md->type); 10588e0cf965SAdrian Hunter if (map == NULL) 10598e0cf965SAdrian Hunter return -ENOMEM; 10608e0cf965SAdrian Hunter 10618e0cf965SAdrian Hunter map->end = map->start + len; 10628e0cf965SAdrian Hunter map->pgoff = pgoff; 10638e0cf965SAdrian Hunter 10648e0cf965SAdrian Hunter list_add(&map->node, &md->maps); 10658e0cf965SAdrian Hunter 10668e0cf965SAdrian Hunter return 0; 10678e0cf965SAdrian Hunter } 10688e0cf965SAdrian Hunter 10698e0cf965SAdrian Hunter static int dso__load_kcore(struct dso *dso, struct map *map, 10708e0cf965SAdrian Hunter const char *kallsyms_filename) 10718e0cf965SAdrian Hunter { 10728e0cf965SAdrian Hunter struct map_groups *kmaps = map__kmap(map)->kmaps; 10738e0cf965SAdrian Hunter struct machine *machine = kmaps->machine; 10748e0cf965SAdrian Hunter struct kcore_mapfn_data md; 10758e0cf965SAdrian Hunter struct map *old_map, *new_map, *replacement_map = NULL; 10768e0cf965SAdrian Hunter bool is_64_bit; 10778e0cf965SAdrian Hunter int err, fd; 10788e0cf965SAdrian Hunter char kcore_filename[PATH_MAX]; 10798e0cf965SAdrian Hunter struct symbol *sym; 10808e0cf965SAdrian Hunter 10818e0cf965SAdrian Hunter /* This function requires that the map is the kernel map */ 10828e0cf965SAdrian Hunter if (map != machine->vmlinux_maps[map->type]) 10838e0cf965SAdrian Hunter return -EINVAL; 10848e0cf965SAdrian Hunter 108552afdaf9SAdrian Hunter if (!filename_from_kallsyms_filename(kcore_filename, "kcore", 10868e0cf965SAdrian Hunter kallsyms_filename)) 10878e0cf965SAdrian Hunter return -EINVAL; 10888e0cf965SAdrian Hunter 108952afdaf9SAdrian Hunter /* All modules must be present at their original addresses */ 109052afdaf9SAdrian Hunter if (validate_kcore_modules(kallsyms_filename, map)) 109152afdaf9SAdrian Hunter return -EINVAL; 109252afdaf9SAdrian Hunter 10938e0cf965SAdrian Hunter md.dso = dso; 10948e0cf965SAdrian Hunter md.type = map->type; 10958e0cf965SAdrian Hunter INIT_LIST_HEAD(&md.maps); 10968e0cf965SAdrian Hunter 10978e0cf965SAdrian Hunter fd = open(kcore_filename, O_RDONLY); 10988e0cf965SAdrian Hunter if (fd < 0) 10998e0cf965SAdrian Hunter return -EINVAL; 11008e0cf965SAdrian Hunter 11018e0cf965SAdrian Hunter /* Read new maps into temporary lists */ 11028e0cf965SAdrian Hunter err = file__read_maps(fd, md.type == MAP__FUNCTION, kcore_mapfn, &md, 11038e0cf965SAdrian Hunter &is_64_bit); 11048e0cf965SAdrian Hunter if (err) 11058e0cf965SAdrian Hunter goto out_err; 11068e0cf965SAdrian Hunter 11078e0cf965SAdrian Hunter if (list_empty(&md.maps)) { 11088e0cf965SAdrian Hunter err = -EINVAL; 11098e0cf965SAdrian Hunter goto out_err; 11108e0cf965SAdrian Hunter } 11118e0cf965SAdrian Hunter 11128e0cf965SAdrian Hunter /* Remove old maps */ 11138e0cf965SAdrian Hunter old_map = map_groups__first(kmaps, map->type); 11148e0cf965SAdrian Hunter while (old_map) { 11158e0cf965SAdrian Hunter struct map *next = map_groups__next(old_map); 11168e0cf965SAdrian Hunter 11178e0cf965SAdrian Hunter if (old_map != map) 11188e0cf965SAdrian Hunter map_groups__remove(kmaps, old_map); 11198e0cf965SAdrian Hunter old_map = next; 11208e0cf965SAdrian Hunter } 11218e0cf965SAdrian Hunter 11228e0cf965SAdrian Hunter /* Find the kernel map using the first symbol */ 11238e0cf965SAdrian Hunter sym = dso__first_symbol(dso, map->type); 11248e0cf965SAdrian Hunter list_for_each_entry(new_map, &md.maps, node) { 11258e0cf965SAdrian Hunter if (sym && sym->start >= new_map->start && 11268e0cf965SAdrian Hunter sym->start < new_map->end) { 11278e0cf965SAdrian Hunter replacement_map = new_map; 11288e0cf965SAdrian Hunter break; 11298e0cf965SAdrian Hunter } 11308e0cf965SAdrian Hunter } 11318e0cf965SAdrian Hunter 11328e0cf965SAdrian Hunter if (!replacement_map) 11338e0cf965SAdrian Hunter replacement_map = list_entry(md.maps.next, struct map, node); 11348e0cf965SAdrian Hunter 11358e0cf965SAdrian Hunter /* Add new maps */ 11368e0cf965SAdrian Hunter while (!list_empty(&md.maps)) { 11378e0cf965SAdrian Hunter new_map = list_entry(md.maps.next, struct map, node); 11388e0cf965SAdrian Hunter list_del(&new_map->node); 11398e0cf965SAdrian Hunter if (new_map == replacement_map) { 11408e0cf965SAdrian Hunter map->start = new_map->start; 11418e0cf965SAdrian Hunter map->end = new_map->end; 11428e0cf965SAdrian Hunter map->pgoff = new_map->pgoff; 11438e0cf965SAdrian Hunter map->map_ip = new_map->map_ip; 11448e0cf965SAdrian Hunter map->unmap_ip = new_map->unmap_ip; 11458e0cf965SAdrian Hunter map__delete(new_map); 11468e0cf965SAdrian Hunter /* Ensure maps are correctly ordered */ 11478e0cf965SAdrian Hunter map_groups__remove(kmaps, map); 11488e0cf965SAdrian Hunter map_groups__insert(kmaps, map); 11498e0cf965SAdrian Hunter } else { 11508e0cf965SAdrian Hunter map_groups__insert(kmaps, new_map); 11518e0cf965SAdrian Hunter } 11528e0cf965SAdrian Hunter } 11538e0cf965SAdrian Hunter 11548e0cf965SAdrian Hunter /* 11558e0cf965SAdrian Hunter * Set the data type and long name so that kcore can be read via 11568e0cf965SAdrian Hunter * dso__data_read_addr(). 11578e0cf965SAdrian Hunter */ 11588e0cf965SAdrian Hunter if (dso->kernel == DSO_TYPE_GUEST_KERNEL) 11598e0cf965SAdrian Hunter dso->data_type = DSO_BINARY_TYPE__GUEST_KCORE; 11608e0cf965SAdrian Hunter else 11618e0cf965SAdrian Hunter dso->data_type = DSO_BINARY_TYPE__KCORE; 11628e0cf965SAdrian Hunter dso__set_long_name(dso, strdup(kcore_filename)); 11638e0cf965SAdrian Hunter 11648e0cf965SAdrian Hunter close(fd); 11658e0cf965SAdrian Hunter 11668e0cf965SAdrian Hunter if (map->type == MAP__FUNCTION) 11678e0cf965SAdrian Hunter pr_debug("Using %s for kernel object code\n", kcore_filename); 11688e0cf965SAdrian Hunter else 11698e0cf965SAdrian Hunter pr_debug("Using %s for kernel data\n", kcore_filename); 11708e0cf965SAdrian Hunter 11718e0cf965SAdrian Hunter return 0; 11728e0cf965SAdrian Hunter 11738e0cf965SAdrian Hunter out_err: 11748e0cf965SAdrian Hunter while (!list_empty(&md.maps)) { 11758e0cf965SAdrian Hunter map = list_entry(md.maps.next, struct map, node); 11768e0cf965SAdrian Hunter list_del(&map->node); 11778e0cf965SAdrian Hunter map__delete(map); 11788e0cf965SAdrian Hunter } 11798e0cf965SAdrian Hunter close(fd); 11808e0cf965SAdrian Hunter return -EINVAL; 11818e0cf965SAdrian Hunter } 11828e0cf965SAdrian Hunter 1183aeafcbafSArnaldo Carvalho de Melo int dso__load_kallsyms(struct dso *dso, const char *filename, 11849de89fe7SArnaldo Carvalho de Melo struct map *map, symbol_filter_t filter) 11852e538c4aSArnaldo Carvalho de Melo { 1186ec80fde7SArnaldo Carvalho de Melo if (symbol__restricted_filename(filename, "/proc/kallsyms")) 1187ec80fde7SArnaldo Carvalho de Melo return -1; 1188ec80fde7SArnaldo Carvalho de Melo 1189aeafcbafSArnaldo Carvalho de Melo if (dso__load_all_kallsyms(dso, filename, map) < 0) 11902e538c4aSArnaldo Carvalho de Melo return -1; 11912e538c4aSArnaldo Carvalho de Melo 1192694bf407SAnton Blanchard symbols__fixup_duplicate(&dso->symbols[map->type]); 11933f5a4272SAnton Blanchard symbols__fixup_end(&dso->symbols[map->type]); 11943f5a4272SAnton Blanchard 1195aeafcbafSArnaldo Carvalho de Melo if (dso->kernel == DSO_TYPE_GUEST_KERNEL) 119644f24cb3SJiri Olsa dso->symtab_type = DSO_BINARY_TYPE__GUEST_KALLSYMS; 1197a1645ce1SZhang, Yanmin else 119844f24cb3SJiri Olsa dso->symtab_type = DSO_BINARY_TYPE__KALLSYMS; 11992e538c4aSArnaldo Carvalho de Melo 12008e0cf965SAdrian Hunter if (!dso__load_kcore(dso, map, filename)) 12018e0cf965SAdrian Hunter return dso__split_kallsyms_for_kcore(dso, map, filter); 12028e0cf965SAdrian Hunter else 1203aeafcbafSArnaldo Carvalho de Melo return dso__split_kallsyms(dso, map, filter); 1204af427bf5SArnaldo Carvalho de Melo } 1205af427bf5SArnaldo Carvalho de Melo 1206aeafcbafSArnaldo Carvalho de Melo static int dso__load_perf_map(struct dso *dso, struct map *map, 12076beba7adSArnaldo Carvalho de Melo symbol_filter_t filter) 120880d496beSPekka Enberg { 120980d496beSPekka Enberg char *line = NULL; 121080d496beSPekka Enberg size_t n; 121180d496beSPekka Enberg FILE *file; 121280d496beSPekka Enberg int nr_syms = 0; 121380d496beSPekka Enberg 1214aeafcbafSArnaldo Carvalho de Melo file = fopen(dso->long_name, "r"); 121580d496beSPekka Enberg if (file == NULL) 121680d496beSPekka Enberg goto out_failure; 121780d496beSPekka Enberg 121880d496beSPekka Enberg while (!feof(file)) { 12199cffa8d5SPaul Mackerras u64 start, size; 122080d496beSPekka Enberg struct symbol *sym; 122180d496beSPekka Enberg int line_len, len; 122280d496beSPekka Enberg 122380d496beSPekka Enberg line_len = getline(&line, &n, file); 122480d496beSPekka Enberg if (line_len < 0) 122580d496beSPekka Enberg break; 122680d496beSPekka Enberg 122780d496beSPekka Enberg if (!line) 122880d496beSPekka Enberg goto out_failure; 122980d496beSPekka Enberg 123080d496beSPekka Enberg line[--line_len] = '\0'; /* \n */ 123180d496beSPekka Enberg 123280d496beSPekka Enberg len = hex2u64(line, &start); 123380d496beSPekka Enberg 123480d496beSPekka Enberg len++; 123580d496beSPekka Enberg if (len + 2 >= line_len) 123680d496beSPekka Enberg continue; 123780d496beSPekka Enberg 123880d496beSPekka Enberg len += hex2u64(line + len, &size); 123980d496beSPekka Enberg 124080d496beSPekka Enberg len++; 124180d496beSPekka Enberg if (len + 2 >= line_len) 124280d496beSPekka Enberg continue; 124380d496beSPekka Enberg 1244c408fedfSArnaldo Carvalho de Melo sym = symbol__new(start, size, STB_GLOBAL, line + len); 124580d496beSPekka Enberg 124680d496beSPekka Enberg if (sym == NULL) 124780d496beSPekka Enberg goto out_delete_line; 124880d496beSPekka Enberg 1249439d473bSArnaldo Carvalho de Melo if (filter && filter(map, sym)) 125000a192b3SArnaldo Carvalho de Melo symbol__delete(sym); 125180d496beSPekka Enberg else { 1252aeafcbafSArnaldo Carvalho de Melo symbols__insert(&dso->symbols[map->type], sym); 125380d496beSPekka Enberg nr_syms++; 125480d496beSPekka Enberg } 125580d496beSPekka Enberg } 125680d496beSPekka Enberg 125780d496beSPekka Enberg free(line); 125880d496beSPekka Enberg fclose(file); 125980d496beSPekka Enberg 126080d496beSPekka Enberg return nr_syms; 126180d496beSPekka Enberg 126280d496beSPekka Enberg out_delete_line: 126380d496beSPekka Enberg free(line); 126480d496beSPekka Enberg out_failure: 126580d496beSPekka Enberg return -1; 126680d496beSPekka Enberg } 126780d496beSPekka Enberg 1268aeafcbafSArnaldo Carvalho de Melo int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter) 126986470930SIngo Molnar { 1270c338aee8SArnaldo Carvalho de Melo char *name; 127186470930SIngo Molnar int ret = -1; 127244f24cb3SJiri Olsa u_int i; 127323346f21SArnaldo Carvalho de Melo struct machine *machine; 127444f24cb3SJiri Olsa char *root_dir = (char *) ""; 12753aafe5aeSCody P Schafer int ss_pos = 0; 12763aafe5aeSCody P Schafer struct symsrc ss_[2]; 12773aafe5aeSCody P Schafer struct symsrc *syms_ss = NULL, *runtime_ss = NULL; 127886470930SIngo Molnar 1279aeafcbafSArnaldo Carvalho de Melo dso__set_loaded(dso, map->type); 128066bd8424SArnaldo Carvalho de Melo 1281aeafcbafSArnaldo Carvalho de Melo if (dso->kernel == DSO_TYPE_KERNEL) 1282aeafcbafSArnaldo Carvalho de Melo return dso__load_kernel_sym(dso, map, filter); 1283aeafcbafSArnaldo Carvalho de Melo else if (dso->kernel == DSO_TYPE_GUEST_KERNEL) 1284aeafcbafSArnaldo Carvalho de Melo return dso__load_guest_kernel_sym(dso, map, filter); 1285a1645ce1SZhang, Yanmin 128623346f21SArnaldo Carvalho de Melo if (map->groups && map->groups->machine) 128723346f21SArnaldo Carvalho de Melo machine = map->groups->machine; 1288a1645ce1SZhang, Yanmin else 128923346f21SArnaldo Carvalho de Melo machine = NULL; 1290c338aee8SArnaldo Carvalho de Melo 1291aeafcbafSArnaldo Carvalho de Melo dso->adjust_symbols = 0; 1292f5812a7aSArnaldo Carvalho de Melo 1293aeafcbafSArnaldo Carvalho de Melo if (strncmp(dso->name, "/tmp/perf-", 10) == 0) { 1294981c1252SPekka Enberg struct stat st; 1295981c1252SPekka Enberg 1296e9b52ef2SVasiliy Kulikov if (lstat(dso->name, &st) < 0) 1297981c1252SPekka Enberg return -1; 1298981c1252SPekka Enberg 1299981c1252SPekka Enberg if (st.st_uid && (st.st_uid != geteuid())) { 1300981c1252SPekka Enberg pr_warning("File %s not owned by current user or root, " 1301981c1252SPekka Enberg "ignoring it.\n", dso->name); 1302981c1252SPekka Enberg return -1; 1303981c1252SPekka Enberg } 1304981c1252SPekka Enberg 1305aeafcbafSArnaldo Carvalho de Melo ret = dso__load_perf_map(dso, map, filter); 130644f24cb3SJiri Olsa dso->symtab_type = ret > 0 ? DSO_BINARY_TYPE__JAVA_JIT : 130744f24cb3SJiri Olsa DSO_BINARY_TYPE__NOT_FOUND; 130894cb9e38SArnaldo Carvalho de Melo return ret; 130994cb9e38SArnaldo Carvalho de Melo } 131094cb9e38SArnaldo Carvalho de Melo 131144f24cb3SJiri Olsa if (machine) 131244f24cb3SJiri Olsa root_dir = machine->root_dir; 131344f24cb3SJiri Olsa 1314164c800eSDavid Ahern name = malloc(PATH_MAX); 1315164c800eSDavid Ahern if (!name) 1316164c800eSDavid Ahern return -1; 1317164c800eSDavid Ahern 13186da80ce8SDave Martin /* Iterate over candidate debug images. 13193aafe5aeSCody P Schafer * Keep track of "interesting" ones (those which have a symtab, dynsym, 13203aafe5aeSCody P Schafer * and/or opd section) for processing. 13216da80ce8SDave Martin */ 132244f24cb3SJiri Olsa for (i = 0; i < DSO_BINARY_TYPE__SYMTAB_CNT; i++) { 13233aafe5aeSCody P Schafer struct symsrc *ss = &ss_[ss_pos]; 13243aafe5aeSCody P Schafer bool next_slot = false; 132544f24cb3SJiri Olsa 1326005f9294SCody P Schafer enum dso_binary_type symtab_type = binary_type_symtab[i]; 132744f24cb3SJiri Olsa 1328005f9294SCody P Schafer if (dso__binary_type_file(dso, symtab_type, 132944f24cb3SJiri Olsa root_dir, name, PATH_MAX)) 13306da80ce8SDave Martin continue; 133186470930SIngo Molnar 13326da80ce8SDave Martin /* Name is now the name of the next image to try */ 13333aafe5aeSCody P Schafer if (symsrc__init(ss, dso, name, symtab_type) < 0) 13346da80ce8SDave Martin continue; 13356da80ce8SDave Martin 13363aafe5aeSCody P Schafer if (!syms_ss && symsrc__has_symtab(ss)) { 13373aafe5aeSCody P Schafer syms_ss = ss; 13383aafe5aeSCody P Schafer next_slot = true; 1339d26cd12bSCody P Schafer } 1340d26cd12bSCody P Schafer 13413aafe5aeSCody P Schafer if (!runtime_ss && symsrc__possibly_runtime(ss)) { 13423aafe5aeSCody P Schafer runtime_ss = ss; 13433aafe5aeSCody P Schafer next_slot = true; 1344a44f605bSCody P Schafer } 134586470930SIngo Molnar 13463aafe5aeSCody P Schafer if (next_slot) { 13473aafe5aeSCody P Schafer ss_pos++; 134833ff581eSJiri Olsa 13493aafe5aeSCody P Schafer if (syms_ss && runtime_ss) 13506da80ce8SDave Martin break; 1351a25e46c4SArnaldo Carvalho de Melo } 13523aafe5aeSCody P Schafer 13536da80ce8SDave Martin } 13546da80ce8SDave Martin 13553aafe5aeSCody P Schafer if (!runtime_ss && !syms_ss) 13563aafe5aeSCody P Schafer goto out_free; 13573aafe5aeSCody P Schafer 13583aafe5aeSCody P Schafer if (runtime_ss && !syms_ss) { 13593aafe5aeSCody P Schafer syms_ss = runtime_ss; 136060e4b10cSArnaldo Carvalho de Melo } 136160e4b10cSArnaldo Carvalho de Melo 13623aafe5aeSCody P Schafer /* We'll have to hope for the best */ 13633aafe5aeSCody P Schafer if (!runtime_ss && syms_ss) 13643aafe5aeSCody P Schafer runtime_ss = syms_ss; 13653aafe5aeSCody P Schafer 13660131c4ecSAdrian Hunter if (syms_ss) { 13670131c4ecSAdrian Hunter int km; 13680131c4ecSAdrian Hunter 13690131c4ecSAdrian Hunter km = dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE || 13700131c4ecSAdrian Hunter dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE; 13710131c4ecSAdrian Hunter ret = dso__load_sym(dso, map, syms_ss, runtime_ss, filter, km); 13720131c4ecSAdrian Hunter } else { 13733aafe5aeSCody P Schafer ret = -1; 13740131c4ecSAdrian Hunter } 13753aafe5aeSCody P Schafer 1376f47b58b7SDavid Ahern if (ret > 0) { 13773aafe5aeSCody P Schafer int nr_plt; 13783aafe5aeSCody P Schafer 13793aafe5aeSCody P Schafer nr_plt = dso__synthesize_plt_symbols(dso, runtime_ss, map, filter); 13803aafe5aeSCody P Schafer if (nr_plt > 0) 13813aafe5aeSCody P Schafer ret += nr_plt; 13823aafe5aeSCody P Schafer } 13833aafe5aeSCody P Schafer 13843aafe5aeSCody P Schafer for (; ss_pos > 0; ss_pos--) 13853aafe5aeSCody P Schafer symsrc__destroy(&ss_[ss_pos - 1]); 13863aafe5aeSCody P Schafer out_free: 138786470930SIngo Molnar free(name); 1388aeafcbafSArnaldo Carvalho de Melo if (ret < 0 && strstr(dso->name, " (deleted)") != NULL) 13891340e6bbSArnaldo Carvalho de Melo return 0; 139086470930SIngo Molnar return ret; 139186470930SIngo Molnar } 139286470930SIngo Molnar 1393aeafcbafSArnaldo Carvalho de Melo struct map *map_groups__find_by_name(struct map_groups *mg, 139479406cd7SArnaldo Carvalho de Melo enum map_type type, const char *name) 1395439d473bSArnaldo Carvalho de Melo { 1396439d473bSArnaldo Carvalho de Melo struct rb_node *nd; 1397439d473bSArnaldo Carvalho de Melo 1398aeafcbafSArnaldo Carvalho de Melo for (nd = rb_first(&mg->maps[type]); nd; nd = rb_next(nd)) { 1399439d473bSArnaldo Carvalho de Melo struct map *map = rb_entry(nd, struct map, rb_node); 1400439d473bSArnaldo Carvalho de Melo 1401b7cece76SArnaldo Carvalho de Melo if (map->dso && strcmp(map->dso->short_name, name) == 0) 1402439d473bSArnaldo Carvalho de Melo return map; 1403439d473bSArnaldo Carvalho de Melo } 1404439d473bSArnaldo Carvalho de Melo 1405439d473bSArnaldo Carvalho de Melo return NULL; 1406439d473bSArnaldo Carvalho de Melo } 1407439d473bSArnaldo Carvalho de Melo 1408aeafcbafSArnaldo Carvalho de Melo int dso__load_vmlinux(struct dso *dso, struct map *map, 14096beba7adSArnaldo Carvalho de Melo const char *vmlinux, symbol_filter_t filter) 141086470930SIngo Molnar { 1411b68e2f91SCody P Schafer int err = -1; 1412b68e2f91SCody P Schafer struct symsrc ss; 1413ec5761eaSDavid Ahern char symfs_vmlinux[PATH_MAX]; 1414005f9294SCody P Schafer enum dso_binary_type symtab_type; 141586470930SIngo Molnar 14165698d2c9SNamhyung Kim if (vmlinux[0] == '/') 14175698d2c9SNamhyung Kim snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s", vmlinux); 14185698d2c9SNamhyung Kim else 1419a639dc64SArnaldo Carvalho de Melo snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s%s", 1420ec5761eaSDavid Ahern symbol_conf.symfs, vmlinux); 142186470930SIngo Molnar 142221ea4539SCody P Schafer if (dso->kernel == DSO_TYPE_GUEST_KERNEL) 1423005f9294SCody P Schafer symtab_type = DSO_BINARY_TYPE__GUEST_VMLINUX; 142421ea4539SCody P Schafer else 1425005f9294SCody P Schafer symtab_type = DSO_BINARY_TYPE__VMLINUX; 142621ea4539SCody P Schafer 1427005f9294SCody P Schafer if (symsrc__init(&ss, dso, symfs_vmlinux, symtab_type)) 1428b68e2f91SCody P Schafer return -1; 1429b68e2f91SCody P Schafer 1430261360b6SCody P Schafer err = dso__load_sym(dso, map, &ss, &ss, filter, 0); 1431b68e2f91SCody P Schafer symsrc__destroy(&ss); 143286470930SIngo Molnar 1433515850e4SCody P Schafer if (err > 0) { 143439b12f78SAdrian Hunter if (dso->kernel == DSO_TYPE_GUEST_KERNEL) 143539b12f78SAdrian Hunter dso->data_type = DSO_BINARY_TYPE__GUEST_VMLINUX; 143639b12f78SAdrian Hunter else 143739b12f78SAdrian Hunter dso->data_type = DSO_BINARY_TYPE__VMLINUX; 1438515850e4SCody P Schafer dso__set_long_name(dso, (char *)vmlinux); 1439515850e4SCody P Schafer dso__set_loaded(dso, map->type); 1440ec5761eaSDavid Ahern pr_debug("Using %s for symbols\n", symfs_vmlinux); 1441515850e4SCody P Schafer } 14423846df2eSArnaldo Carvalho de Melo 144386470930SIngo Molnar return err; 144486470930SIngo Molnar } 144586470930SIngo Molnar 1446aeafcbafSArnaldo Carvalho de Melo int dso__load_vmlinux_path(struct dso *dso, struct map *map, 14479de89fe7SArnaldo Carvalho de Melo symbol_filter_t filter) 1448a19afe46SArnaldo Carvalho de Melo { 1449a19afe46SArnaldo Carvalho de Melo int i, err = 0; 14505ad90e4eSArnaldo Carvalho de Melo char *filename; 1451a19afe46SArnaldo Carvalho de Melo 1452a19afe46SArnaldo Carvalho de Melo pr_debug("Looking at the vmlinux_path (%d entries long)\n", 14535ad90e4eSArnaldo Carvalho de Melo vmlinux_path__nr_entries + 1); 14545ad90e4eSArnaldo Carvalho de Melo 1455aeafcbafSArnaldo Carvalho de Melo filename = dso__build_id_filename(dso, NULL, 0); 14565ad90e4eSArnaldo Carvalho de Melo if (filename != NULL) { 1457aeafcbafSArnaldo Carvalho de Melo err = dso__load_vmlinux(dso, map, filename, filter); 1458b7c14a0bSDavid Ahern if (err > 0) { 1459b7c14a0bSDavid Ahern dso->lname_alloc = 1; 14605ad90e4eSArnaldo Carvalho de Melo goto out; 1461b7c14a0bSDavid Ahern } 14625ad90e4eSArnaldo Carvalho de Melo free(filename); 14635ad90e4eSArnaldo Carvalho de Melo } 1464a19afe46SArnaldo Carvalho de Melo 1465a19afe46SArnaldo Carvalho de Melo for (i = 0; i < vmlinux_path__nr_entries; ++i) { 1466aeafcbafSArnaldo Carvalho de Melo err = dso__load_vmlinux(dso, map, vmlinux_path[i], filter); 1467a19afe46SArnaldo Carvalho de Melo if (err > 0) { 1468aeafcbafSArnaldo Carvalho de Melo dso__set_long_name(dso, strdup(vmlinux_path[i])); 1469b7c14a0bSDavid Ahern dso->lname_alloc = 1; 1470a19afe46SArnaldo Carvalho de Melo break; 1471a19afe46SArnaldo Carvalho de Melo } 1472a19afe46SArnaldo Carvalho de Melo } 14735ad90e4eSArnaldo Carvalho de Melo out: 1474a19afe46SArnaldo Carvalho de Melo return err; 1475a19afe46SArnaldo Carvalho de Melo } 1476a19afe46SArnaldo Carvalho de Melo 14770544d422SAdrian Hunter static int find_matching_kcore(struct map *map, char *dir, size_t dir_sz) 14780544d422SAdrian Hunter { 14790544d422SAdrian Hunter char kallsyms_filename[PATH_MAX]; 14800544d422SAdrian Hunter struct dirent *dent; 14810544d422SAdrian Hunter int ret = -1; 14820544d422SAdrian Hunter DIR *d; 14830544d422SAdrian Hunter 14840544d422SAdrian Hunter d = opendir(dir); 14850544d422SAdrian Hunter if (!d) 14860544d422SAdrian Hunter return -1; 14870544d422SAdrian Hunter 14880544d422SAdrian Hunter while (1) { 14890544d422SAdrian Hunter dent = readdir(d); 14900544d422SAdrian Hunter if (!dent) 14910544d422SAdrian Hunter break; 14920544d422SAdrian Hunter if (dent->d_type != DT_DIR) 14930544d422SAdrian Hunter continue; 14940544d422SAdrian Hunter scnprintf(kallsyms_filename, sizeof(kallsyms_filename), 14950544d422SAdrian Hunter "%s/%s/kallsyms", dir, dent->d_name); 14960544d422SAdrian Hunter if (!validate_kcore_modules(kallsyms_filename, map)) { 14970544d422SAdrian Hunter strlcpy(dir, kallsyms_filename, dir_sz); 14980544d422SAdrian Hunter ret = 0; 14990544d422SAdrian Hunter break; 15000544d422SAdrian Hunter } 15010544d422SAdrian Hunter } 15020544d422SAdrian Hunter 15030544d422SAdrian Hunter closedir(d); 15040544d422SAdrian Hunter 15050544d422SAdrian Hunter return ret; 15060544d422SAdrian Hunter } 15070544d422SAdrian Hunter 15080544d422SAdrian Hunter static char *dso__find_kallsyms(struct dso *dso, struct map *map) 15090544d422SAdrian Hunter { 15100544d422SAdrian Hunter u8 host_build_id[BUILD_ID_SIZE]; 15110544d422SAdrian Hunter char sbuild_id[BUILD_ID_SIZE * 2 + 1]; 15120544d422SAdrian Hunter bool is_host = false; 15130544d422SAdrian Hunter char path[PATH_MAX]; 15140544d422SAdrian Hunter 15150544d422SAdrian Hunter if (!dso->has_build_id) { 15160544d422SAdrian Hunter /* 15170544d422SAdrian Hunter * Last resort, if we don't have a build-id and couldn't find 15180544d422SAdrian Hunter * any vmlinux file, try the running kernel kallsyms table. 15190544d422SAdrian Hunter */ 15200544d422SAdrian Hunter goto proc_kallsyms; 15210544d422SAdrian Hunter } 15220544d422SAdrian Hunter 15230544d422SAdrian Hunter if (sysfs__read_build_id("/sys/kernel/notes", host_build_id, 15240544d422SAdrian Hunter sizeof(host_build_id)) == 0) 15250544d422SAdrian Hunter is_host = dso__build_id_equal(dso, host_build_id); 15260544d422SAdrian Hunter 15270544d422SAdrian Hunter build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id); 15280544d422SAdrian Hunter 15290544d422SAdrian Hunter /* Use /proc/kallsyms if possible */ 15300544d422SAdrian Hunter if (is_host) { 15310544d422SAdrian Hunter DIR *d; 15320544d422SAdrian Hunter int fd; 15330544d422SAdrian Hunter 15340544d422SAdrian Hunter /* If no cached kcore go with /proc/kallsyms */ 15350544d422SAdrian Hunter scnprintf(path, sizeof(path), "%s/[kernel.kcore]/%s", 15360544d422SAdrian Hunter buildid_dir, sbuild_id); 15370544d422SAdrian Hunter d = opendir(path); 15380544d422SAdrian Hunter if (!d) 15390544d422SAdrian Hunter goto proc_kallsyms; 15400544d422SAdrian Hunter closedir(d); 15410544d422SAdrian Hunter 15420544d422SAdrian Hunter /* 15430544d422SAdrian Hunter * Do not check the build-id cache, until we know we cannot use 15440544d422SAdrian Hunter * /proc/kcore. 15450544d422SAdrian Hunter */ 15460544d422SAdrian Hunter fd = open("/proc/kcore", O_RDONLY); 15470544d422SAdrian Hunter if (fd != -1) { 15480544d422SAdrian Hunter close(fd); 15490544d422SAdrian Hunter /* If module maps match go with /proc/kallsyms */ 15500544d422SAdrian Hunter if (!validate_kcore_modules("/proc/kallsyms", map)) 15510544d422SAdrian Hunter goto proc_kallsyms; 15520544d422SAdrian Hunter } 15530544d422SAdrian Hunter 15540544d422SAdrian Hunter /* Find kallsyms in build-id cache with kcore */ 15550544d422SAdrian Hunter if (!find_matching_kcore(map, path, sizeof(path))) 15560544d422SAdrian Hunter return strdup(path); 15570544d422SAdrian Hunter 15580544d422SAdrian Hunter goto proc_kallsyms; 15590544d422SAdrian Hunter } 15600544d422SAdrian Hunter 15610544d422SAdrian Hunter scnprintf(path, sizeof(path), "%s/[kernel.kallsyms]/%s", 15620544d422SAdrian Hunter buildid_dir, sbuild_id); 15630544d422SAdrian Hunter 15640544d422SAdrian Hunter if (access(path, F_OK)) { 15650544d422SAdrian Hunter pr_err("No kallsyms or vmlinux with build-id %s was found\n", 15660544d422SAdrian Hunter sbuild_id); 15670544d422SAdrian Hunter return NULL; 15680544d422SAdrian Hunter } 15690544d422SAdrian Hunter 15700544d422SAdrian Hunter return strdup(path); 15710544d422SAdrian Hunter 15720544d422SAdrian Hunter proc_kallsyms: 15730544d422SAdrian Hunter return strdup("/proc/kallsyms"); 15740544d422SAdrian Hunter } 15750544d422SAdrian Hunter 1576aeafcbafSArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *dso, struct map *map, 15779de89fe7SArnaldo Carvalho de Melo symbol_filter_t filter) 157886470930SIngo Molnar { 1579cc612d81SArnaldo Carvalho de Melo int err; 15809e201442SArnaldo Carvalho de Melo const char *kallsyms_filename = NULL; 15819e201442SArnaldo Carvalho de Melo char *kallsyms_allocated_filename = NULL; 1582dc8d6ab2SArnaldo Carvalho de Melo /* 1583b226a5a7SDavid Ahern * Step 1: if the user specified a kallsyms or vmlinux filename, use 1584b226a5a7SDavid Ahern * it and only it, reporting errors to the user if it cannot be used. 1585dc8d6ab2SArnaldo Carvalho de Melo * 1586dc8d6ab2SArnaldo Carvalho de Melo * For instance, try to analyse an ARM perf.data file _without_ a 1587dc8d6ab2SArnaldo Carvalho de Melo * build-id, or if the user specifies the wrong path to the right 1588dc8d6ab2SArnaldo Carvalho de Melo * vmlinux file, obviously we can't fallback to another vmlinux (a 1589dc8d6ab2SArnaldo Carvalho de Melo * x86_86 one, on the machine where analysis is being performed, say), 1590dc8d6ab2SArnaldo Carvalho de Melo * or worse, /proc/kallsyms. 1591dc8d6ab2SArnaldo Carvalho de Melo * 1592dc8d6ab2SArnaldo Carvalho de Melo * If the specified file _has_ a build-id and there is a build-id 1593dc8d6ab2SArnaldo Carvalho de Melo * section in the perf.data file, we will still do the expected 1594dc8d6ab2SArnaldo Carvalho de Melo * validation in dso__load_vmlinux and will bail out if they don't 1595dc8d6ab2SArnaldo Carvalho de Melo * match. 1596dc8d6ab2SArnaldo Carvalho de Melo */ 1597b226a5a7SDavid Ahern if (symbol_conf.kallsyms_name != NULL) { 1598b226a5a7SDavid Ahern kallsyms_filename = symbol_conf.kallsyms_name; 1599b226a5a7SDavid Ahern goto do_kallsyms; 1600b226a5a7SDavid Ahern } 1601b226a5a7SDavid Ahern 1602fc2be696SWilly Tarreau if (!symbol_conf.ignore_vmlinux && symbol_conf.vmlinux_name != NULL) { 1603aeafcbafSArnaldo Carvalho de Melo err = dso__load_vmlinux(dso, map, 1604dc8d6ab2SArnaldo Carvalho de Melo symbol_conf.vmlinux_name, filter); 1605e7dadc00SArnaldo Carvalho de Melo if (err > 0) { 1606aeafcbafSArnaldo Carvalho de Melo dso__set_long_name(dso, 1607e7dadc00SArnaldo Carvalho de Melo strdup(symbol_conf.vmlinux_name)); 1608b7c14a0bSDavid Ahern dso->lname_alloc = 1; 160939b12f78SAdrian Hunter return err; 1610e7dadc00SArnaldo Carvalho de Melo } 1611e7dadc00SArnaldo Carvalho de Melo return err; 1612dc8d6ab2SArnaldo Carvalho de Melo } 1613439d473bSArnaldo Carvalho de Melo 1614fc2be696SWilly Tarreau if (!symbol_conf.ignore_vmlinux && vmlinux_path != NULL) { 1615aeafcbafSArnaldo Carvalho de Melo err = dso__load_vmlinux_path(dso, map, filter); 1616a19afe46SArnaldo Carvalho de Melo if (err > 0) 161739b12f78SAdrian Hunter return err; 1618cc612d81SArnaldo Carvalho de Melo } 1619cc612d81SArnaldo Carvalho de Melo 1620ec5761eaSDavid Ahern /* do not try local files if a symfs was given */ 1621ec5761eaSDavid Ahern if (symbol_conf.symfs[0] != 0) 1622ec5761eaSDavid Ahern return -1; 1623ec5761eaSDavid Ahern 16240544d422SAdrian Hunter kallsyms_allocated_filename = dso__find_kallsyms(dso, map); 16250544d422SAdrian Hunter if (!kallsyms_allocated_filename) 16268d0591f6SArnaldo Carvalho de Melo return -1; 16278d0591f6SArnaldo Carvalho de Melo 162819fc2dedSArnaldo Carvalho de Melo kallsyms_filename = kallsyms_allocated_filename; 162919fc2dedSArnaldo Carvalho de Melo 1630dc8d6ab2SArnaldo Carvalho de Melo do_kallsyms: 1631aeafcbafSArnaldo Carvalho de Melo err = dso__load_kallsyms(dso, kallsyms_filename, map, filter); 16323846df2eSArnaldo Carvalho de Melo if (err > 0) 16333846df2eSArnaldo Carvalho de Melo pr_debug("Using %s for symbols\n", kallsyms_filename); 1634dc8d6ab2SArnaldo Carvalho de Melo free(kallsyms_allocated_filename); 1635dc8d6ab2SArnaldo Carvalho de Melo 16368e0cf965SAdrian Hunter if (err > 0 && !dso__is_kcore(dso)) { 1637aeafcbafSArnaldo Carvalho de Melo dso__set_long_name(dso, strdup("[kernel.kallsyms]")); 16386a4694a4SArnaldo Carvalho de Melo map__fixup_start(map); 16396a4694a4SArnaldo Carvalho de Melo map__fixup_end(map); 1640439d473bSArnaldo Carvalho de Melo } 164194cb9e38SArnaldo Carvalho de Melo 164286470930SIngo Molnar return err; 164386470930SIngo Molnar } 164486470930SIngo Molnar 1645aeafcbafSArnaldo Carvalho de Melo static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map, 1646a1645ce1SZhang, Yanmin symbol_filter_t filter) 1647a1645ce1SZhang, Yanmin { 1648a1645ce1SZhang, Yanmin int err; 1649a1645ce1SZhang, Yanmin const char *kallsyms_filename = NULL; 165023346f21SArnaldo Carvalho de Melo struct machine *machine; 1651a1645ce1SZhang, Yanmin char path[PATH_MAX]; 1652a1645ce1SZhang, Yanmin 1653a1645ce1SZhang, Yanmin if (!map->groups) { 1654a1645ce1SZhang, Yanmin pr_debug("Guest kernel map hasn't the point to groups\n"); 1655a1645ce1SZhang, Yanmin return -1; 1656a1645ce1SZhang, Yanmin } 165723346f21SArnaldo Carvalho de Melo machine = map->groups->machine; 1658a1645ce1SZhang, Yanmin 165923346f21SArnaldo Carvalho de Melo if (machine__is_default_guest(machine)) { 1660a1645ce1SZhang, Yanmin /* 1661a1645ce1SZhang, Yanmin * if the user specified a vmlinux filename, use it and only 1662a1645ce1SZhang, Yanmin * it, reporting errors to the user if it cannot be used. 1663a1645ce1SZhang, Yanmin * Or use file guest_kallsyms inputted by user on commandline 1664a1645ce1SZhang, Yanmin */ 1665a1645ce1SZhang, Yanmin if (symbol_conf.default_guest_vmlinux_name != NULL) { 1666aeafcbafSArnaldo Carvalho de Melo err = dso__load_vmlinux(dso, map, 1667a1645ce1SZhang, Yanmin symbol_conf.default_guest_vmlinux_name, filter); 166839b12f78SAdrian Hunter return err; 1669a1645ce1SZhang, Yanmin } 1670a1645ce1SZhang, Yanmin 1671a1645ce1SZhang, Yanmin kallsyms_filename = symbol_conf.default_guest_kallsyms; 1672a1645ce1SZhang, Yanmin if (!kallsyms_filename) 1673a1645ce1SZhang, Yanmin return -1; 1674a1645ce1SZhang, Yanmin } else { 167523346f21SArnaldo Carvalho de Melo sprintf(path, "%s/proc/kallsyms", machine->root_dir); 1676a1645ce1SZhang, Yanmin kallsyms_filename = path; 1677a1645ce1SZhang, Yanmin } 1678a1645ce1SZhang, Yanmin 1679aeafcbafSArnaldo Carvalho de Melo err = dso__load_kallsyms(dso, kallsyms_filename, map, filter); 16808e0cf965SAdrian Hunter if (err > 0) 168139b12f78SAdrian Hunter pr_debug("Using %s for symbols\n", kallsyms_filename); 16828e0cf965SAdrian Hunter if (err > 0 && !dso__is_kcore(dso)) { 168348ea8f54SArnaldo Carvalho de Melo machine__mmap_name(machine, path, sizeof(path)); 1684aeafcbafSArnaldo Carvalho de Melo dso__set_long_name(dso, strdup(path)); 1685a1645ce1SZhang, Yanmin map__fixup_start(map); 1686a1645ce1SZhang, Yanmin map__fixup_end(map); 1687a1645ce1SZhang, Yanmin } 1688a1645ce1SZhang, Yanmin 1689a1645ce1SZhang, Yanmin return err; 1690a1645ce1SZhang, Yanmin } 1691cd84c2acSFrederic Weisbecker 1692cc612d81SArnaldo Carvalho de Melo static void vmlinux_path__exit(void) 16932446042cSArnaldo Carvalho de Melo { 1694cc612d81SArnaldo Carvalho de Melo while (--vmlinux_path__nr_entries >= 0) { 1695cc612d81SArnaldo Carvalho de Melo free(vmlinux_path[vmlinux_path__nr_entries]); 1696cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = NULL; 1697cc612d81SArnaldo Carvalho de Melo } 1698cc612d81SArnaldo Carvalho de Melo 1699cc612d81SArnaldo Carvalho de Melo free(vmlinux_path); 1700cc612d81SArnaldo Carvalho de Melo vmlinux_path = NULL; 1701cc612d81SArnaldo Carvalho de Melo } 1702cc612d81SArnaldo Carvalho de Melo 1703cc612d81SArnaldo Carvalho de Melo static int vmlinux_path__init(void) 1704cc612d81SArnaldo Carvalho de Melo { 1705cc612d81SArnaldo Carvalho de Melo struct utsname uts; 1706cc612d81SArnaldo Carvalho de Melo char bf[PATH_MAX]; 1707cc612d81SArnaldo Carvalho de Melo 1708cc612d81SArnaldo Carvalho de Melo vmlinux_path = malloc(sizeof(char *) * 5); 1709cc612d81SArnaldo Carvalho de Melo if (vmlinux_path == NULL) 1710cc612d81SArnaldo Carvalho de Melo return -1; 1711cc612d81SArnaldo Carvalho de Melo 1712cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup("vmlinux"); 1713cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 1714cc612d81SArnaldo Carvalho de Melo goto out_fail; 1715cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 1716cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup("/boot/vmlinux"); 1717cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 1718cc612d81SArnaldo Carvalho de Melo goto out_fail; 1719cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 1720ec5761eaSDavid Ahern 1721ec5761eaSDavid Ahern /* only try running kernel version if no symfs was given */ 1722ec5761eaSDavid Ahern if (symbol_conf.symfs[0] != 0) 1723ec5761eaSDavid Ahern return 0; 1724ec5761eaSDavid Ahern 1725ec5761eaSDavid Ahern if (uname(&uts) < 0) 1726ec5761eaSDavid Ahern return -1; 1727ec5761eaSDavid Ahern 1728cc612d81SArnaldo Carvalho de Melo snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", uts.release); 1729cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); 1730cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 1731cc612d81SArnaldo Carvalho de Melo goto out_fail; 1732cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 1733cc612d81SArnaldo Carvalho de Melo snprintf(bf, sizeof(bf), "/lib/modules/%s/build/vmlinux", uts.release); 1734cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); 1735cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 1736cc612d81SArnaldo Carvalho de Melo goto out_fail; 1737cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 1738cc612d81SArnaldo Carvalho de Melo snprintf(bf, sizeof(bf), "/usr/lib/debug/lib/modules/%s/vmlinux", 1739cc612d81SArnaldo Carvalho de Melo uts.release); 1740cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); 1741cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 1742cc612d81SArnaldo Carvalho de Melo goto out_fail; 1743cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 1744cc612d81SArnaldo Carvalho de Melo 1745cc612d81SArnaldo Carvalho de Melo return 0; 1746cc612d81SArnaldo Carvalho de Melo 1747cc612d81SArnaldo Carvalho de Melo out_fail: 1748cc612d81SArnaldo Carvalho de Melo vmlinux_path__exit(); 1749cc612d81SArnaldo Carvalho de Melo return -1; 1750cc612d81SArnaldo Carvalho de Melo } 1751cc612d81SArnaldo Carvalho de Melo 1752655000e7SArnaldo Carvalho de Melo static int setup_list(struct strlist **list, const char *list_str, 1753655000e7SArnaldo Carvalho de Melo const char *list_name) 1754655000e7SArnaldo Carvalho de Melo { 1755655000e7SArnaldo Carvalho de Melo if (list_str == NULL) 1756655000e7SArnaldo Carvalho de Melo return 0; 1757655000e7SArnaldo Carvalho de Melo 1758655000e7SArnaldo Carvalho de Melo *list = strlist__new(true, list_str); 1759655000e7SArnaldo Carvalho de Melo if (!*list) { 1760655000e7SArnaldo Carvalho de Melo pr_err("problems parsing %s list\n", list_name); 1761655000e7SArnaldo Carvalho de Melo return -1; 1762655000e7SArnaldo Carvalho de Melo } 1763655000e7SArnaldo Carvalho de Melo return 0; 1764655000e7SArnaldo Carvalho de Melo } 1765655000e7SArnaldo Carvalho de Melo 1766ec80fde7SArnaldo Carvalho de Melo static bool symbol__read_kptr_restrict(void) 1767ec80fde7SArnaldo Carvalho de Melo { 1768ec80fde7SArnaldo Carvalho de Melo bool value = false; 1769ec80fde7SArnaldo Carvalho de Melo 1770ec80fde7SArnaldo Carvalho de Melo if (geteuid() != 0) { 1771ec80fde7SArnaldo Carvalho de Melo FILE *fp = fopen("/proc/sys/kernel/kptr_restrict", "r"); 1772ec80fde7SArnaldo Carvalho de Melo if (fp != NULL) { 1773ec80fde7SArnaldo Carvalho de Melo char line[8]; 1774ec80fde7SArnaldo Carvalho de Melo 1775ec80fde7SArnaldo Carvalho de Melo if (fgets(line, sizeof(line), fp) != NULL) 1776ec80fde7SArnaldo Carvalho de Melo value = atoi(line) != 0; 1777ec80fde7SArnaldo Carvalho de Melo 1778ec80fde7SArnaldo Carvalho de Melo fclose(fp); 1779ec80fde7SArnaldo Carvalho de Melo } 1780ec80fde7SArnaldo Carvalho de Melo } 1781ec80fde7SArnaldo Carvalho de Melo 1782ec80fde7SArnaldo Carvalho de Melo return value; 1783ec80fde7SArnaldo Carvalho de Melo } 1784ec80fde7SArnaldo Carvalho de Melo 178575be6cf4SArnaldo Carvalho de Melo int symbol__init(void) 1786cc612d81SArnaldo Carvalho de Melo { 1787ec5761eaSDavid Ahern const char *symfs; 1788ec5761eaSDavid Ahern 178985e00b55SJovi Zhang if (symbol_conf.initialized) 179085e00b55SJovi Zhang return 0; 179185e00b55SJovi Zhang 17929ac3e487SIrina Tirdea symbol_conf.priv_size = PERF_ALIGN(symbol_conf.priv_size, sizeof(u64)); 17934d439517SDavid S. Miller 1794166ccc9cSNamhyung Kim symbol__elf_init(); 1795166ccc9cSNamhyung Kim 179675be6cf4SArnaldo Carvalho de Melo if (symbol_conf.sort_by_name) 179775be6cf4SArnaldo Carvalho de Melo symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) - 179879406cd7SArnaldo Carvalho de Melo sizeof(struct symbol)); 1799b32d133aSArnaldo Carvalho de Melo 180075be6cf4SArnaldo Carvalho de Melo if (symbol_conf.try_vmlinux_path && vmlinux_path__init() < 0) 1801cc612d81SArnaldo Carvalho de Melo return -1; 1802cc612d81SArnaldo Carvalho de Melo 1803c410a338SArnaldo Carvalho de Melo if (symbol_conf.field_sep && *symbol_conf.field_sep == '.') { 1804c410a338SArnaldo Carvalho de Melo pr_err("'.' is the only non valid --field-separator argument\n"); 1805c410a338SArnaldo Carvalho de Melo return -1; 1806c410a338SArnaldo Carvalho de Melo } 1807c410a338SArnaldo Carvalho de Melo 1808655000e7SArnaldo Carvalho de Melo if (setup_list(&symbol_conf.dso_list, 1809655000e7SArnaldo Carvalho de Melo symbol_conf.dso_list_str, "dso") < 0) 1810655000e7SArnaldo Carvalho de Melo return -1; 1811655000e7SArnaldo Carvalho de Melo 1812655000e7SArnaldo Carvalho de Melo if (setup_list(&symbol_conf.comm_list, 1813655000e7SArnaldo Carvalho de Melo symbol_conf.comm_list_str, "comm") < 0) 1814655000e7SArnaldo Carvalho de Melo goto out_free_dso_list; 1815655000e7SArnaldo Carvalho de Melo 1816655000e7SArnaldo Carvalho de Melo if (setup_list(&symbol_conf.sym_list, 1817655000e7SArnaldo Carvalho de Melo symbol_conf.sym_list_str, "symbol") < 0) 1818655000e7SArnaldo Carvalho de Melo goto out_free_comm_list; 1819655000e7SArnaldo Carvalho de Melo 1820ec5761eaSDavid Ahern /* 1821ec5761eaSDavid Ahern * A path to symbols of "/" is identical to "" 1822ec5761eaSDavid Ahern * reset here for simplicity. 1823ec5761eaSDavid Ahern */ 1824ec5761eaSDavid Ahern symfs = realpath(symbol_conf.symfs, NULL); 1825ec5761eaSDavid Ahern if (symfs == NULL) 1826ec5761eaSDavid Ahern symfs = symbol_conf.symfs; 1827ec5761eaSDavid Ahern if (strcmp(symfs, "/") == 0) 1828ec5761eaSDavid Ahern symbol_conf.symfs = ""; 1829ec5761eaSDavid Ahern if (symfs != symbol_conf.symfs) 1830ec5761eaSDavid Ahern free((void *)symfs); 1831ec5761eaSDavid Ahern 1832ec80fde7SArnaldo Carvalho de Melo symbol_conf.kptr_restrict = symbol__read_kptr_restrict(); 1833ec80fde7SArnaldo Carvalho de Melo 183485e00b55SJovi Zhang symbol_conf.initialized = true; 18354aa65636SArnaldo Carvalho de Melo return 0; 1836655000e7SArnaldo Carvalho de Melo 1837655000e7SArnaldo Carvalho de Melo out_free_comm_list: 1838655000e7SArnaldo Carvalho de Melo strlist__delete(symbol_conf.comm_list); 1839d74c896bSNamhyung Kim out_free_dso_list: 1840d74c896bSNamhyung Kim strlist__delete(symbol_conf.dso_list); 1841655000e7SArnaldo Carvalho de Melo return -1; 1842cc612d81SArnaldo Carvalho de Melo } 1843cc612d81SArnaldo Carvalho de Melo 1844d65a458bSArnaldo Carvalho de Melo void symbol__exit(void) 1845d65a458bSArnaldo Carvalho de Melo { 184685e00b55SJovi Zhang if (!symbol_conf.initialized) 184785e00b55SJovi Zhang return; 1848d65a458bSArnaldo Carvalho de Melo strlist__delete(symbol_conf.sym_list); 1849d65a458bSArnaldo Carvalho de Melo strlist__delete(symbol_conf.dso_list); 1850d65a458bSArnaldo Carvalho de Melo strlist__delete(symbol_conf.comm_list); 1851d65a458bSArnaldo Carvalho de Melo vmlinux_path__exit(); 1852d65a458bSArnaldo Carvalho de Melo symbol_conf.sym_list = symbol_conf.dso_list = symbol_conf.comm_list = NULL; 185385e00b55SJovi Zhang symbol_conf.initialized = false; 1854d65a458bSArnaldo Carvalho de Melo } 1855