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, 5444f24cb3SJiri Olsa DSO_BINARY_TYPE__NOT_FOUND, 5544f24cb3SJiri Olsa }; 5644f24cb3SJiri Olsa 57028df767SJiri Olsa #define DSO_BINARY_TYPE__SYMTAB_CNT ARRAY_SIZE(binary_type_symtab) 5844f24cb3SJiri Olsa 5936a3e646SArnaldo Carvalho de Melo bool symbol_type__is_a(char symbol_type, enum map_type map_type) 606893d4eeSArnaldo Carvalho de Melo { 6131877908SAnton Blanchard symbol_type = toupper(symbol_type); 6231877908SAnton Blanchard 636893d4eeSArnaldo Carvalho de Melo switch (map_type) { 646893d4eeSArnaldo Carvalho de Melo case MAP__FUNCTION: 656893d4eeSArnaldo Carvalho de Melo return symbol_type == 'T' || symbol_type == 'W'; 66f1dfa0b1SArnaldo Carvalho de Melo case MAP__VARIABLE: 6731877908SAnton Blanchard return symbol_type == 'D'; 686893d4eeSArnaldo Carvalho de Melo default: 696893d4eeSArnaldo Carvalho de Melo return false; 706893d4eeSArnaldo Carvalho de Melo } 716893d4eeSArnaldo Carvalho de Melo } 726893d4eeSArnaldo Carvalho de Melo 73694bf407SAnton Blanchard static int prefix_underscores_count(const char *str) 74694bf407SAnton Blanchard { 75694bf407SAnton Blanchard const char *tail = str; 76694bf407SAnton Blanchard 77694bf407SAnton Blanchard while (*tail == '_') 78694bf407SAnton Blanchard tail++; 79694bf407SAnton Blanchard 80694bf407SAnton Blanchard return tail - str; 81694bf407SAnton Blanchard } 82694bf407SAnton Blanchard 83694bf407SAnton Blanchard #define SYMBOL_A 0 84694bf407SAnton Blanchard #define SYMBOL_B 1 85694bf407SAnton Blanchard 86694bf407SAnton Blanchard static int choose_best_symbol(struct symbol *syma, struct symbol *symb) 87694bf407SAnton Blanchard { 88694bf407SAnton Blanchard s64 a; 89694bf407SAnton Blanchard s64 b; 903445432bSAdrian Hunter size_t na, nb; 91694bf407SAnton Blanchard 92694bf407SAnton Blanchard /* Prefer a symbol with non zero length */ 93694bf407SAnton Blanchard a = syma->end - syma->start; 94694bf407SAnton Blanchard b = symb->end - symb->start; 95694bf407SAnton Blanchard if ((b == 0) && (a > 0)) 96694bf407SAnton Blanchard return SYMBOL_A; 97694bf407SAnton Blanchard else if ((a == 0) && (b > 0)) 98694bf407SAnton Blanchard return SYMBOL_B; 99694bf407SAnton Blanchard 100694bf407SAnton Blanchard /* Prefer a non weak symbol over a weak one */ 101694bf407SAnton Blanchard a = syma->binding == STB_WEAK; 102694bf407SAnton Blanchard b = symb->binding == STB_WEAK; 103694bf407SAnton Blanchard if (b && !a) 104694bf407SAnton Blanchard return SYMBOL_A; 105694bf407SAnton Blanchard if (a && !b) 106694bf407SAnton Blanchard return SYMBOL_B; 107694bf407SAnton Blanchard 108694bf407SAnton Blanchard /* Prefer a global symbol over a non global one */ 109694bf407SAnton Blanchard a = syma->binding == STB_GLOBAL; 110694bf407SAnton Blanchard b = symb->binding == STB_GLOBAL; 111694bf407SAnton Blanchard if (a && !b) 112694bf407SAnton Blanchard return SYMBOL_A; 113694bf407SAnton Blanchard if (b && !a) 114694bf407SAnton Blanchard return SYMBOL_B; 115694bf407SAnton Blanchard 116694bf407SAnton Blanchard /* Prefer a symbol with less underscores */ 117694bf407SAnton Blanchard a = prefix_underscores_count(syma->name); 118694bf407SAnton Blanchard b = prefix_underscores_count(symb->name); 119694bf407SAnton Blanchard if (b > a) 120694bf407SAnton Blanchard return SYMBOL_A; 121694bf407SAnton Blanchard else if (a > b) 122694bf407SAnton Blanchard return SYMBOL_B; 123694bf407SAnton Blanchard 1243445432bSAdrian Hunter /* Choose the symbol with the longest name */ 1253445432bSAdrian Hunter na = strlen(syma->name); 1263445432bSAdrian Hunter nb = strlen(symb->name); 1273445432bSAdrian Hunter if (na > nb) 128694bf407SAnton Blanchard return SYMBOL_A; 1293445432bSAdrian Hunter else if (na < nb) 130694bf407SAnton Blanchard return SYMBOL_B; 1313445432bSAdrian Hunter 1323445432bSAdrian Hunter /* Avoid "SyS" kernel syscall aliases */ 1333445432bSAdrian Hunter if (na >= 3 && !strncmp(syma->name, "SyS", 3)) 1343445432bSAdrian Hunter return SYMBOL_B; 1353445432bSAdrian Hunter if (na >= 10 && !strncmp(syma->name, "compat_SyS", 10)) 1363445432bSAdrian Hunter return SYMBOL_B; 1373445432bSAdrian Hunter 1383445432bSAdrian Hunter return SYMBOL_A; 139694bf407SAnton Blanchard } 140694bf407SAnton Blanchard 141e5a1845fSNamhyung Kim void symbols__fixup_duplicate(struct rb_root *symbols) 142694bf407SAnton Blanchard { 143694bf407SAnton Blanchard struct rb_node *nd; 144694bf407SAnton Blanchard struct symbol *curr, *next; 145694bf407SAnton Blanchard 146694bf407SAnton Blanchard nd = rb_first(symbols); 147694bf407SAnton Blanchard 148694bf407SAnton Blanchard while (nd) { 149694bf407SAnton Blanchard curr = rb_entry(nd, struct symbol, rb_node); 150694bf407SAnton Blanchard again: 151694bf407SAnton Blanchard nd = rb_next(&curr->rb_node); 152694bf407SAnton Blanchard next = rb_entry(nd, struct symbol, rb_node); 153694bf407SAnton Blanchard 154694bf407SAnton Blanchard if (!nd) 155694bf407SAnton Blanchard break; 156694bf407SAnton Blanchard 157694bf407SAnton Blanchard if (curr->start != next->start) 158694bf407SAnton Blanchard continue; 159694bf407SAnton Blanchard 160694bf407SAnton Blanchard if (choose_best_symbol(curr, next) == SYMBOL_A) { 161694bf407SAnton Blanchard rb_erase(&next->rb_node, symbols); 162694bf407SAnton Blanchard goto again; 163694bf407SAnton Blanchard } else { 164694bf407SAnton Blanchard nd = rb_next(&curr->rb_node); 165694bf407SAnton Blanchard rb_erase(&curr->rb_node, symbols); 166694bf407SAnton Blanchard } 167694bf407SAnton Blanchard } 168694bf407SAnton Blanchard } 169694bf407SAnton Blanchard 170e5a1845fSNamhyung Kim void symbols__fixup_end(struct rb_root *symbols) 171af427bf5SArnaldo Carvalho de Melo { 172aeafcbafSArnaldo Carvalho de Melo struct rb_node *nd, *prevnd = rb_first(symbols); 1732e538c4aSArnaldo Carvalho de Melo struct symbol *curr, *prev; 174af427bf5SArnaldo Carvalho de Melo 175af427bf5SArnaldo Carvalho de Melo if (prevnd == NULL) 176af427bf5SArnaldo Carvalho de Melo return; 177af427bf5SArnaldo Carvalho de Melo 1782e538c4aSArnaldo Carvalho de Melo curr = rb_entry(prevnd, struct symbol, rb_node); 1792e538c4aSArnaldo Carvalho de Melo 180af427bf5SArnaldo Carvalho de Melo for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) { 1812e538c4aSArnaldo Carvalho de Melo prev = curr; 1822e538c4aSArnaldo Carvalho de Melo curr = rb_entry(nd, struct symbol, rb_node); 183af427bf5SArnaldo Carvalho de Melo 1843b01a413SArnaldo Carvalho de Melo if (prev->end == prev->start && prev->end != curr->start) 185af427bf5SArnaldo Carvalho de Melo prev->end = curr->start - 1; 186af427bf5SArnaldo Carvalho de Melo } 187af427bf5SArnaldo Carvalho de Melo 1882e538c4aSArnaldo Carvalho de Melo /* Last entry */ 1892e538c4aSArnaldo Carvalho de Melo if (curr->end == curr->start) 1902e538c4aSArnaldo Carvalho de Melo curr->end = roundup(curr->start, 4096); 1912e538c4aSArnaldo Carvalho de Melo } 1922e538c4aSArnaldo Carvalho de Melo 193e5a1845fSNamhyung Kim void __map_groups__fixup_end(struct map_groups *mg, enum map_type type) 194af427bf5SArnaldo Carvalho de Melo { 195af427bf5SArnaldo Carvalho de Melo struct map *prev, *curr; 196aeafcbafSArnaldo Carvalho de Melo struct rb_node *nd, *prevnd = rb_first(&mg->maps[type]); 197af427bf5SArnaldo Carvalho de Melo 198af427bf5SArnaldo Carvalho de Melo if (prevnd == NULL) 199af427bf5SArnaldo Carvalho de Melo return; 200af427bf5SArnaldo Carvalho de Melo 201af427bf5SArnaldo Carvalho de Melo curr = rb_entry(prevnd, struct map, rb_node); 202af427bf5SArnaldo Carvalho de Melo 203af427bf5SArnaldo Carvalho de Melo for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) { 204af427bf5SArnaldo Carvalho de Melo prev = curr; 205af427bf5SArnaldo Carvalho de Melo curr = rb_entry(nd, struct map, rb_node); 206af427bf5SArnaldo Carvalho de Melo prev->end = curr->start - 1; 2072e538c4aSArnaldo Carvalho de Melo } 20890c83218SArnaldo Carvalho de Melo 20990c83218SArnaldo Carvalho de Melo /* 21090c83218SArnaldo Carvalho de Melo * We still haven't the actual symbols, so guess the 21190c83218SArnaldo Carvalho de Melo * last map final address. 21290c83218SArnaldo Carvalho de Melo */ 2139d1faba5SIan Munsie curr->end = ~0ULL; 214af427bf5SArnaldo Carvalho de Melo } 215af427bf5SArnaldo Carvalho de Melo 216e5a1845fSNamhyung Kim struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name) 21786470930SIngo Molnar { 21886470930SIngo Molnar size_t namelen = strlen(name) + 1; 219aeafcbafSArnaldo Carvalho de Melo struct symbol *sym = calloc(1, (symbol_conf.priv_size + 220aeafcbafSArnaldo Carvalho de Melo sizeof(*sym) + namelen)); 221aeafcbafSArnaldo Carvalho de Melo if (sym == NULL) 22286470930SIngo Molnar return NULL; 22386470930SIngo Molnar 22475be6cf4SArnaldo Carvalho de Melo if (symbol_conf.priv_size) 225aeafcbafSArnaldo Carvalho de Melo sym = ((void *)sym) + symbol_conf.priv_size; 22636479484SArnaldo Carvalho de Melo 227aeafcbafSArnaldo Carvalho de Melo sym->start = start; 228aeafcbafSArnaldo Carvalho de Melo sym->end = len ? start + len - 1 : start; 229aeafcbafSArnaldo Carvalho de Melo sym->binding = binding; 230aeafcbafSArnaldo Carvalho de Melo sym->namelen = namelen - 1; 231e4204992SArnaldo Carvalho de Melo 232aeafcbafSArnaldo Carvalho de Melo pr_debug4("%s: %s %#" PRIx64 "-%#" PRIx64 "\n", 233aeafcbafSArnaldo Carvalho de Melo __func__, name, start, sym->end); 234aeafcbafSArnaldo Carvalho de Melo memcpy(sym->name, name, namelen); 235e4204992SArnaldo Carvalho de Melo 236aeafcbafSArnaldo Carvalho de Melo return sym; 23786470930SIngo Molnar } 23886470930SIngo Molnar 239aeafcbafSArnaldo Carvalho de Melo void symbol__delete(struct symbol *sym) 24086470930SIngo Molnar { 241aeafcbafSArnaldo Carvalho de Melo free(((void *)sym) - symbol_conf.priv_size); 24286470930SIngo Molnar } 24386470930SIngo Molnar 244cdd059d7SJiri Olsa size_t symbol__fprintf(struct symbol *sym, FILE *fp) 24586470930SIngo Molnar { 2469486aa38SArnaldo Carvalho de Melo return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %c %s\n", 247aeafcbafSArnaldo Carvalho de Melo sym->start, sym->end, 248aeafcbafSArnaldo Carvalho de Melo sym->binding == STB_GLOBAL ? 'g' : 249aeafcbafSArnaldo Carvalho de Melo sym->binding == STB_LOCAL ? 'l' : 'w', 250aeafcbafSArnaldo Carvalho de Melo sym->name); 25186470930SIngo Molnar } 25286470930SIngo Molnar 253a978f2abSAkihiro Nagai size_t symbol__fprintf_symname_offs(const struct symbol *sym, 254a978f2abSAkihiro Nagai const struct addr_location *al, FILE *fp) 255a978f2abSAkihiro Nagai { 256a978f2abSAkihiro Nagai unsigned long offset; 257a978f2abSAkihiro Nagai size_t length; 258a978f2abSAkihiro Nagai 259a978f2abSAkihiro Nagai if (sym && sym->name) { 260a978f2abSAkihiro Nagai length = fprintf(fp, "%s", sym->name); 261a978f2abSAkihiro Nagai if (al) { 262*0b8c25d9SDavid Ahern if (al->addr < sym->end) 263a978f2abSAkihiro Nagai offset = al->addr - sym->start; 264*0b8c25d9SDavid Ahern else 265*0b8c25d9SDavid Ahern offset = al->addr - al->map->start - sym->start; 266a978f2abSAkihiro Nagai length += fprintf(fp, "+0x%lx", offset); 267a978f2abSAkihiro Nagai } 268a978f2abSAkihiro Nagai return length; 269a978f2abSAkihiro Nagai } else 270a978f2abSAkihiro Nagai return fprintf(fp, "[unknown]"); 271a978f2abSAkihiro Nagai } 272a978f2abSAkihiro Nagai 273547a92e0SAkihiro Nagai size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp) 274547a92e0SAkihiro Nagai { 275a978f2abSAkihiro Nagai return symbol__fprintf_symname_offs(sym, NULL, fp); 276547a92e0SAkihiro Nagai } 277547a92e0SAkihiro Nagai 278cdd059d7SJiri Olsa void symbols__delete(struct rb_root *symbols) 27986470930SIngo Molnar { 28086470930SIngo Molnar struct symbol *pos; 281aeafcbafSArnaldo Carvalho de Melo struct rb_node *next = rb_first(symbols); 28286470930SIngo Molnar 28386470930SIngo Molnar while (next) { 28486470930SIngo Molnar pos = rb_entry(next, struct symbol, rb_node); 28586470930SIngo Molnar next = rb_next(&pos->rb_node); 286aeafcbafSArnaldo Carvalho de Melo rb_erase(&pos->rb_node, symbols); 28700a192b3SArnaldo Carvalho de Melo symbol__delete(pos); 28886470930SIngo Molnar } 28986470930SIngo Molnar } 29086470930SIngo Molnar 291e5a1845fSNamhyung Kim void symbols__insert(struct rb_root *symbols, struct symbol *sym) 29286470930SIngo Molnar { 293aeafcbafSArnaldo Carvalho de Melo struct rb_node **p = &symbols->rb_node; 29486470930SIngo Molnar struct rb_node *parent = NULL; 2959cffa8d5SPaul Mackerras const u64 ip = sym->start; 29686470930SIngo Molnar struct symbol *s; 29786470930SIngo Molnar 29886470930SIngo Molnar while (*p != NULL) { 29986470930SIngo Molnar parent = *p; 30086470930SIngo Molnar s = rb_entry(parent, struct symbol, rb_node); 30186470930SIngo Molnar if (ip < s->start) 30286470930SIngo Molnar p = &(*p)->rb_left; 30386470930SIngo Molnar else 30486470930SIngo Molnar p = &(*p)->rb_right; 30586470930SIngo Molnar } 30686470930SIngo Molnar rb_link_node(&sym->rb_node, parent, p); 307aeafcbafSArnaldo Carvalho de Melo rb_insert_color(&sym->rb_node, symbols); 30886470930SIngo Molnar } 30986470930SIngo Molnar 310aeafcbafSArnaldo Carvalho de Melo static struct symbol *symbols__find(struct rb_root *symbols, u64 ip) 31186470930SIngo Molnar { 31286470930SIngo Molnar struct rb_node *n; 31386470930SIngo Molnar 314aeafcbafSArnaldo Carvalho de Melo if (symbols == NULL) 31586470930SIngo Molnar return NULL; 31686470930SIngo Molnar 317aeafcbafSArnaldo Carvalho de Melo n = symbols->rb_node; 31886470930SIngo Molnar 31986470930SIngo Molnar while (n) { 32086470930SIngo Molnar struct symbol *s = rb_entry(n, struct symbol, rb_node); 32186470930SIngo Molnar 32286470930SIngo Molnar if (ip < s->start) 32386470930SIngo Molnar n = n->rb_left; 32486470930SIngo Molnar else if (ip > s->end) 32586470930SIngo Molnar n = n->rb_right; 32686470930SIngo Molnar else 32786470930SIngo Molnar return s; 32886470930SIngo Molnar } 32986470930SIngo Molnar 33086470930SIngo Molnar return NULL; 33186470930SIngo Molnar } 33286470930SIngo Molnar 3338e0cf965SAdrian Hunter static struct symbol *symbols__first(struct rb_root *symbols) 3348e0cf965SAdrian Hunter { 3358e0cf965SAdrian Hunter struct rb_node *n = rb_first(symbols); 3368e0cf965SAdrian Hunter 3378e0cf965SAdrian Hunter if (n) 3388e0cf965SAdrian Hunter return rb_entry(n, struct symbol, rb_node); 3398e0cf965SAdrian Hunter 3408e0cf965SAdrian Hunter return NULL; 3418e0cf965SAdrian Hunter } 3428e0cf965SAdrian Hunter 34379406cd7SArnaldo Carvalho de Melo struct symbol_name_rb_node { 34479406cd7SArnaldo Carvalho de Melo struct rb_node rb_node; 34579406cd7SArnaldo Carvalho de Melo struct symbol sym; 34679406cd7SArnaldo Carvalho de Melo }; 34779406cd7SArnaldo Carvalho de Melo 348aeafcbafSArnaldo Carvalho de Melo static void symbols__insert_by_name(struct rb_root *symbols, struct symbol *sym) 34979406cd7SArnaldo Carvalho de Melo { 350aeafcbafSArnaldo Carvalho de Melo struct rb_node **p = &symbols->rb_node; 35179406cd7SArnaldo Carvalho de Melo struct rb_node *parent = NULL; 35202a9d037SRabin Vincent struct symbol_name_rb_node *symn, *s; 35302a9d037SRabin Vincent 35402a9d037SRabin Vincent symn = container_of(sym, struct symbol_name_rb_node, sym); 35579406cd7SArnaldo Carvalho de Melo 35679406cd7SArnaldo Carvalho de Melo while (*p != NULL) { 35779406cd7SArnaldo Carvalho de Melo parent = *p; 35879406cd7SArnaldo Carvalho de Melo s = rb_entry(parent, struct symbol_name_rb_node, rb_node); 35979406cd7SArnaldo Carvalho de Melo if (strcmp(sym->name, s->sym.name) < 0) 36079406cd7SArnaldo Carvalho de Melo p = &(*p)->rb_left; 36179406cd7SArnaldo Carvalho de Melo else 36279406cd7SArnaldo Carvalho de Melo p = &(*p)->rb_right; 36379406cd7SArnaldo Carvalho de Melo } 36479406cd7SArnaldo Carvalho de Melo rb_link_node(&symn->rb_node, parent, p); 365aeafcbafSArnaldo Carvalho de Melo rb_insert_color(&symn->rb_node, symbols); 36679406cd7SArnaldo Carvalho de Melo } 36779406cd7SArnaldo Carvalho de Melo 368aeafcbafSArnaldo Carvalho de Melo static void symbols__sort_by_name(struct rb_root *symbols, 369aeafcbafSArnaldo Carvalho de Melo struct rb_root *source) 37079406cd7SArnaldo Carvalho de Melo { 37179406cd7SArnaldo Carvalho de Melo struct rb_node *nd; 37279406cd7SArnaldo Carvalho de Melo 37379406cd7SArnaldo Carvalho de Melo for (nd = rb_first(source); nd; nd = rb_next(nd)) { 37479406cd7SArnaldo Carvalho de Melo struct symbol *pos = rb_entry(nd, struct symbol, rb_node); 375aeafcbafSArnaldo Carvalho de Melo symbols__insert_by_name(symbols, pos); 37679406cd7SArnaldo Carvalho de Melo } 37779406cd7SArnaldo Carvalho de Melo } 37879406cd7SArnaldo Carvalho de Melo 379aeafcbafSArnaldo Carvalho de Melo static struct symbol *symbols__find_by_name(struct rb_root *symbols, 380aeafcbafSArnaldo Carvalho de Melo const char *name) 38179406cd7SArnaldo Carvalho de Melo { 38279406cd7SArnaldo Carvalho de Melo struct rb_node *n; 38379406cd7SArnaldo Carvalho de Melo 384aeafcbafSArnaldo Carvalho de Melo if (symbols == NULL) 38579406cd7SArnaldo Carvalho de Melo return NULL; 38679406cd7SArnaldo Carvalho de Melo 387aeafcbafSArnaldo Carvalho de Melo n = symbols->rb_node; 38879406cd7SArnaldo Carvalho de Melo 38979406cd7SArnaldo Carvalho de Melo while (n) { 39079406cd7SArnaldo Carvalho de Melo struct symbol_name_rb_node *s; 39179406cd7SArnaldo Carvalho de Melo int cmp; 39279406cd7SArnaldo Carvalho de Melo 39379406cd7SArnaldo Carvalho de Melo s = rb_entry(n, struct symbol_name_rb_node, rb_node); 39479406cd7SArnaldo Carvalho de Melo cmp = strcmp(name, s->sym.name); 39579406cd7SArnaldo Carvalho de Melo 39679406cd7SArnaldo Carvalho de Melo if (cmp < 0) 39779406cd7SArnaldo Carvalho de Melo n = n->rb_left; 39879406cd7SArnaldo Carvalho de Melo else if (cmp > 0) 39979406cd7SArnaldo Carvalho de Melo n = n->rb_right; 40079406cd7SArnaldo Carvalho de Melo else 40179406cd7SArnaldo Carvalho de Melo return &s->sym; 40279406cd7SArnaldo Carvalho de Melo } 40379406cd7SArnaldo Carvalho de Melo 40479406cd7SArnaldo Carvalho de Melo return NULL; 40579406cd7SArnaldo Carvalho de Melo } 40679406cd7SArnaldo Carvalho de Melo 407aeafcbafSArnaldo Carvalho de Melo struct symbol *dso__find_symbol(struct dso *dso, 40879406cd7SArnaldo Carvalho de Melo enum map_type type, u64 addr) 409fcf1203aSArnaldo Carvalho de Melo { 410aeafcbafSArnaldo Carvalho de Melo return symbols__find(&dso->symbols[type], addr); 411fcf1203aSArnaldo Carvalho de Melo } 412fcf1203aSArnaldo Carvalho de Melo 4138e0cf965SAdrian Hunter struct symbol *dso__first_symbol(struct dso *dso, enum map_type type) 4148e0cf965SAdrian Hunter { 4158e0cf965SAdrian Hunter return symbols__first(&dso->symbols[type]); 4168e0cf965SAdrian Hunter } 4178e0cf965SAdrian Hunter 418aeafcbafSArnaldo Carvalho de Melo struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type, 41979406cd7SArnaldo Carvalho de Melo const char *name) 42079406cd7SArnaldo Carvalho de Melo { 421aeafcbafSArnaldo Carvalho de Melo return symbols__find_by_name(&dso->symbol_names[type], name); 42279406cd7SArnaldo Carvalho de Melo } 42379406cd7SArnaldo Carvalho de Melo 424aeafcbafSArnaldo Carvalho de Melo void dso__sort_by_name(struct dso *dso, enum map_type type) 42579406cd7SArnaldo Carvalho de Melo { 426aeafcbafSArnaldo Carvalho de Melo dso__set_sorted_by_name(dso, type); 427aeafcbafSArnaldo Carvalho de Melo return symbols__sort_by_name(&dso->symbol_names[type], 428aeafcbafSArnaldo Carvalho de Melo &dso->symbols[type]); 42979406cd7SArnaldo Carvalho de Melo } 43079406cd7SArnaldo Carvalho de Melo 431aeafcbafSArnaldo Carvalho de Melo size_t dso__fprintf_symbols_by_name(struct dso *dso, 432aeafcbafSArnaldo Carvalho de Melo enum map_type type, FILE *fp) 43390f18e63SSrikar Dronamraju { 43490f18e63SSrikar Dronamraju size_t ret = 0; 43590f18e63SSrikar Dronamraju struct rb_node *nd; 43690f18e63SSrikar Dronamraju struct symbol_name_rb_node *pos; 43790f18e63SSrikar Dronamraju 438aeafcbafSArnaldo Carvalho de Melo for (nd = rb_first(&dso->symbol_names[type]); nd; nd = rb_next(nd)) { 43990f18e63SSrikar Dronamraju pos = rb_entry(nd, struct symbol_name_rb_node, rb_node); 44090f18e63SSrikar Dronamraju fprintf(fp, "%s\n", pos->sym.name); 44190f18e63SSrikar Dronamraju } 44290f18e63SSrikar Dronamraju 44390f18e63SSrikar Dronamraju return ret; 44490f18e63SSrikar Dronamraju } 44590f18e63SSrikar Dronamraju 4469e201442SArnaldo Carvalho de Melo int kallsyms__parse(const char *filename, void *arg, 4479e201442SArnaldo Carvalho de Melo int (*process_symbol)(void *arg, const char *name, 44882151520SCody P Schafer char type, u64 start)) 44986470930SIngo Molnar { 45086470930SIngo Molnar char *line = NULL; 45186470930SIngo Molnar size_t n; 4523b01a413SArnaldo Carvalho de Melo int err = -1; 4539e201442SArnaldo Carvalho de Melo FILE *file = fopen(filename, "r"); 45486470930SIngo Molnar 45586470930SIngo Molnar if (file == NULL) 45686470930SIngo Molnar goto out_failure; 45786470930SIngo Molnar 4583b01a413SArnaldo Carvalho de Melo err = 0; 4593b01a413SArnaldo Carvalho de Melo 46086470930SIngo Molnar while (!feof(file)) { 4619cffa8d5SPaul Mackerras u64 start; 46286470930SIngo Molnar int line_len, len; 46386470930SIngo Molnar char symbol_type; 4642e538c4aSArnaldo Carvalho de Melo char *symbol_name; 46586470930SIngo Molnar 46686470930SIngo Molnar line_len = getline(&line, &n, file); 467a1645ce1SZhang, Yanmin if (line_len < 0 || !line) 46886470930SIngo Molnar break; 46986470930SIngo Molnar 47086470930SIngo Molnar line[--line_len] = '\0'; /* \n */ 47186470930SIngo Molnar 47286470930SIngo Molnar len = hex2u64(line, &start); 47386470930SIngo Molnar 47486470930SIngo Molnar len++; 47586470930SIngo Molnar if (len + 2 >= line_len) 47686470930SIngo Molnar continue; 47786470930SIngo Molnar 47831877908SAnton Blanchard symbol_type = line[len]; 4793b01a413SArnaldo Carvalho de Melo len += 2; 4803b01a413SArnaldo Carvalho de Melo symbol_name = line + len; 4813b01a413SArnaldo Carvalho de Melo len = line_len - len; 482682b335aSArnaldo Carvalho de Melo 4833b01a413SArnaldo Carvalho de Melo if (len >= KSYM_NAME_LEN) { 4843b01a413SArnaldo Carvalho de Melo err = -1; 4853b01a413SArnaldo Carvalho de Melo break; 4863b01a413SArnaldo Carvalho de Melo } 4873b01a413SArnaldo Carvalho de Melo 4883f5a4272SAnton Blanchard err = process_symbol(arg, symbol_name, 48982151520SCody P Schafer symbol_type, start); 490682b335aSArnaldo Carvalho de Melo if (err) 491682b335aSArnaldo Carvalho de Melo break; 492682b335aSArnaldo Carvalho de Melo } 493682b335aSArnaldo Carvalho de Melo 494682b335aSArnaldo Carvalho de Melo free(line); 495682b335aSArnaldo Carvalho de Melo fclose(file); 496682b335aSArnaldo Carvalho de Melo return err; 497682b335aSArnaldo Carvalho de Melo 498682b335aSArnaldo Carvalho de Melo out_failure: 499682b335aSArnaldo Carvalho de Melo return -1; 500682b335aSArnaldo Carvalho de Melo } 501682b335aSArnaldo Carvalho de Melo 502682b335aSArnaldo Carvalho de Melo struct process_kallsyms_args { 503682b335aSArnaldo Carvalho de Melo struct map *map; 504682b335aSArnaldo Carvalho de Melo struct dso *dso; 505682b335aSArnaldo Carvalho de Melo }; 506682b335aSArnaldo Carvalho de Melo 507c408fedfSArnaldo Carvalho de Melo static u8 kallsyms2elf_type(char type) 508c408fedfSArnaldo Carvalho de Melo { 509c408fedfSArnaldo Carvalho de Melo if (type == 'W') 510c408fedfSArnaldo Carvalho de Melo return STB_WEAK; 511c408fedfSArnaldo Carvalho de Melo 512c408fedfSArnaldo Carvalho de Melo return isupper(type) ? STB_GLOBAL : STB_LOCAL; 513c408fedfSArnaldo Carvalho de Melo } 514c408fedfSArnaldo Carvalho de Melo 515682b335aSArnaldo Carvalho de Melo static int map__process_kallsym_symbol(void *arg, const char *name, 51682151520SCody P Schafer char type, u64 start) 517682b335aSArnaldo Carvalho de Melo { 518682b335aSArnaldo Carvalho de Melo struct symbol *sym; 519682b335aSArnaldo Carvalho de Melo struct process_kallsyms_args *a = arg; 520682b335aSArnaldo Carvalho de Melo struct rb_root *root = &a->dso->symbols[a->map->type]; 521682b335aSArnaldo Carvalho de Melo 522682b335aSArnaldo Carvalho de Melo if (!symbol_type__is_a(type, a->map->type)) 523682b335aSArnaldo Carvalho de Melo return 0; 524682b335aSArnaldo Carvalho de Melo 52582151520SCody P Schafer /* 52682151520SCody P Schafer * module symbols are not sorted so we add all 52782151520SCody P Schafer * symbols, setting length to 0, and rely on 52882151520SCody P Schafer * symbols__fixup_end() to fix it up. 52982151520SCody P Schafer */ 53082151520SCody P Schafer sym = symbol__new(start, 0, kallsyms2elf_type(type), name); 5312e538c4aSArnaldo Carvalho de Melo if (sym == NULL) 532682b335aSArnaldo Carvalho de Melo return -ENOMEM; 53382164161SArnaldo Carvalho de Melo /* 53482164161SArnaldo Carvalho de Melo * We will pass the symbols to the filter later, in 5354e06255fSArnaldo Carvalho de Melo * map__split_kallsyms, when we have split the maps per module 53682164161SArnaldo Carvalho de Melo */ 5374e06255fSArnaldo Carvalho de Melo symbols__insert(root, sym); 538a1645ce1SZhang, Yanmin 539682b335aSArnaldo Carvalho de Melo return 0; 5402e538c4aSArnaldo Carvalho de Melo } 5412e538c4aSArnaldo Carvalho de Melo 542682b335aSArnaldo Carvalho de Melo /* 543682b335aSArnaldo Carvalho de Melo * Loads the function entries in /proc/kallsyms into kernel_map->dso, 544682b335aSArnaldo Carvalho de Melo * so that we can in the next step set the symbol ->end address and then 545682b335aSArnaldo Carvalho de Melo * call kernel_maps__split_kallsyms. 546682b335aSArnaldo Carvalho de Melo */ 547aeafcbafSArnaldo Carvalho de Melo static int dso__load_all_kallsyms(struct dso *dso, const char *filename, 5489e201442SArnaldo Carvalho de Melo struct map *map) 549682b335aSArnaldo Carvalho de Melo { 550aeafcbafSArnaldo Carvalho de Melo struct process_kallsyms_args args = { .map = map, .dso = dso, }; 5519e201442SArnaldo Carvalho de Melo return kallsyms__parse(filename, &args, map__process_kallsym_symbol); 5522e538c4aSArnaldo Carvalho de Melo } 5532e538c4aSArnaldo Carvalho de Melo 5548e0cf965SAdrian Hunter static int dso__split_kallsyms_for_kcore(struct dso *dso, struct map *map, 5558e0cf965SAdrian Hunter symbol_filter_t filter) 5568e0cf965SAdrian Hunter { 5578e0cf965SAdrian Hunter struct map_groups *kmaps = map__kmap(map)->kmaps; 5588e0cf965SAdrian Hunter struct map *curr_map; 5598e0cf965SAdrian Hunter struct symbol *pos; 5608e0cf965SAdrian Hunter int count = 0, moved = 0; 5618e0cf965SAdrian Hunter struct rb_root *root = &dso->symbols[map->type]; 5628e0cf965SAdrian Hunter struct rb_node *next = rb_first(root); 5638e0cf965SAdrian Hunter 5648e0cf965SAdrian Hunter while (next) { 5658e0cf965SAdrian Hunter char *module; 5668e0cf965SAdrian Hunter 5678e0cf965SAdrian Hunter pos = rb_entry(next, struct symbol, rb_node); 5688e0cf965SAdrian Hunter next = rb_next(&pos->rb_node); 5698e0cf965SAdrian Hunter 5708e0cf965SAdrian Hunter module = strchr(pos->name, '\t'); 5718e0cf965SAdrian Hunter if (module) 5728e0cf965SAdrian Hunter *module = '\0'; 5738e0cf965SAdrian Hunter 5748e0cf965SAdrian Hunter curr_map = map_groups__find(kmaps, map->type, pos->start); 5758e0cf965SAdrian Hunter 5768e0cf965SAdrian Hunter if (!curr_map || (filter && filter(curr_map, pos))) { 5778e0cf965SAdrian Hunter rb_erase(&pos->rb_node, root); 5788e0cf965SAdrian Hunter symbol__delete(pos); 5798e0cf965SAdrian Hunter } else { 5808e0cf965SAdrian Hunter pos->start -= curr_map->start - curr_map->pgoff; 5818e0cf965SAdrian Hunter if (pos->end) 5828e0cf965SAdrian Hunter pos->end -= curr_map->start - curr_map->pgoff; 5838e0cf965SAdrian Hunter if (curr_map != map) { 5848e0cf965SAdrian Hunter rb_erase(&pos->rb_node, root); 5858e0cf965SAdrian Hunter symbols__insert( 5868e0cf965SAdrian Hunter &curr_map->dso->symbols[curr_map->type], 5878e0cf965SAdrian Hunter pos); 5888e0cf965SAdrian Hunter ++moved; 5898e0cf965SAdrian Hunter } else { 5908e0cf965SAdrian Hunter ++count; 5918e0cf965SAdrian Hunter } 5928e0cf965SAdrian Hunter } 5938e0cf965SAdrian Hunter } 5948e0cf965SAdrian Hunter 5958e0cf965SAdrian Hunter /* Symbols have been adjusted */ 5968e0cf965SAdrian Hunter dso->adjust_symbols = 1; 5978e0cf965SAdrian Hunter 5988e0cf965SAdrian Hunter return count + moved; 5998e0cf965SAdrian Hunter } 6008e0cf965SAdrian Hunter 6012e538c4aSArnaldo Carvalho de Melo /* 6022e538c4aSArnaldo Carvalho de Melo * Split the symbols into maps, making sure there are no overlaps, i.e. the 6032e538c4aSArnaldo Carvalho de Melo * kernel range is broken in several maps, named [kernel].N, as we don't have 6042e538c4aSArnaldo Carvalho de Melo * the original ELF section names vmlinux have. 6052e538c4aSArnaldo Carvalho de Melo */ 606aeafcbafSArnaldo Carvalho de Melo static int dso__split_kallsyms(struct dso *dso, struct map *map, 6079de89fe7SArnaldo Carvalho de Melo symbol_filter_t filter) 6082e538c4aSArnaldo Carvalho de Melo { 6099de89fe7SArnaldo Carvalho de Melo struct map_groups *kmaps = map__kmap(map)->kmaps; 61023346f21SArnaldo Carvalho de Melo struct machine *machine = kmaps->machine; 6114e06255fSArnaldo Carvalho de Melo struct map *curr_map = map; 6122e538c4aSArnaldo Carvalho de Melo struct symbol *pos; 6138a953312SArnaldo Carvalho de Melo int count = 0, moved = 0; 614aeafcbafSArnaldo Carvalho de Melo struct rb_root *root = &dso->symbols[map->type]; 6154e06255fSArnaldo Carvalho de Melo struct rb_node *next = rb_first(root); 6162e538c4aSArnaldo Carvalho de Melo int kernel_range = 0; 6172e538c4aSArnaldo Carvalho de Melo 6182e538c4aSArnaldo Carvalho de Melo while (next) { 6192e538c4aSArnaldo Carvalho de Melo char *module; 6202e538c4aSArnaldo Carvalho de Melo 6212e538c4aSArnaldo Carvalho de Melo pos = rb_entry(next, struct symbol, rb_node); 6222e538c4aSArnaldo Carvalho de Melo next = rb_next(&pos->rb_node); 6232e538c4aSArnaldo Carvalho de Melo 6242e538c4aSArnaldo Carvalho de Melo module = strchr(pos->name, '\t'); 6252e538c4aSArnaldo Carvalho de Melo if (module) { 62675be6cf4SArnaldo Carvalho de Melo if (!symbol_conf.use_modules) 6271de8e245SArnaldo Carvalho de Melo goto discard_symbol; 6281de8e245SArnaldo Carvalho de Melo 6292e538c4aSArnaldo Carvalho de Melo *module++ = '\0'; 6302e538c4aSArnaldo Carvalho de Melo 631b7cece76SArnaldo Carvalho de Melo if (strcmp(curr_map->dso->short_name, module)) { 632a1645ce1SZhang, Yanmin if (curr_map != map && 633aeafcbafSArnaldo Carvalho de Melo dso->kernel == DSO_TYPE_GUEST_KERNEL && 63423346f21SArnaldo Carvalho de Melo machine__is_default_guest(machine)) { 635a1645ce1SZhang, Yanmin /* 636a1645ce1SZhang, Yanmin * We assume all symbols of a module are 637a1645ce1SZhang, Yanmin * continuous in * kallsyms, so curr_map 638a1645ce1SZhang, Yanmin * points to a module and all its 639a1645ce1SZhang, Yanmin * symbols are in its kmap. Mark it as 640a1645ce1SZhang, Yanmin * loaded. 641a1645ce1SZhang, Yanmin */ 642a1645ce1SZhang, Yanmin dso__set_loaded(curr_map->dso, 643a1645ce1SZhang, Yanmin curr_map->type); 644af427bf5SArnaldo Carvalho de Melo } 645b7cece76SArnaldo Carvalho de Melo 646a1645ce1SZhang, Yanmin curr_map = map_groups__find_by_name(kmaps, 647a1645ce1SZhang, Yanmin map->type, module); 648a1645ce1SZhang, Yanmin if (curr_map == NULL) { 6492f51903bSArnaldo Carvalho de Melo pr_debug("%s/proc/{kallsyms,modules} " 650a1645ce1SZhang, Yanmin "inconsistency while looking " 651a1645ce1SZhang, Yanmin "for \"%s\" module!\n", 65223346f21SArnaldo Carvalho de Melo machine->root_dir, module); 653a1645ce1SZhang, Yanmin curr_map = map; 654a1645ce1SZhang, Yanmin goto discard_symbol; 655a1645ce1SZhang, Yanmin } 656a1645ce1SZhang, Yanmin 657a1645ce1SZhang, Yanmin if (curr_map->dso->loaded && 65823346f21SArnaldo Carvalho de Melo !machine__is_default_guest(machine)) 659b7cece76SArnaldo Carvalho de Melo goto discard_symbol; 660af427bf5SArnaldo Carvalho de Melo } 66186470930SIngo Molnar /* 6622e538c4aSArnaldo Carvalho de Melo * So that we look just like we get from .ko files, 6632e538c4aSArnaldo Carvalho de Melo * i.e. not prelinked, relative to map->start. 66486470930SIngo Molnar */ 6654e06255fSArnaldo Carvalho de Melo pos->start = curr_map->map_ip(curr_map, pos->start); 6664e06255fSArnaldo Carvalho de Melo pos->end = curr_map->map_ip(curr_map, pos->end); 6674e06255fSArnaldo Carvalho de Melo } else if (curr_map != map) { 6682e538c4aSArnaldo Carvalho de Melo char dso_name[PATH_MAX]; 669aeafcbafSArnaldo Carvalho de Melo struct dso *ndso; 67086470930SIngo Molnar 6718a953312SArnaldo Carvalho de Melo if (count == 0) { 6728a953312SArnaldo Carvalho de Melo curr_map = map; 6738a953312SArnaldo Carvalho de Melo goto filter_symbol; 6748a953312SArnaldo Carvalho de Melo } 6758a953312SArnaldo Carvalho de Melo 676aeafcbafSArnaldo Carvalho de Melo if (dso->kernel == DSO_TYPE_GUEST_KERNEL) 677a1645ce1SZhang, Yanmin snprintf(dso_name, sizeof(dso_name), 678a1645ce1SZhang, Yanmin "[guest.kernel].%d", 679a1645ce1SZhang, Yanmin kernel_range++); 680a1645ce1SZhang, Yanmin else 681a1645ce1SZhang, Yanmin snprintf(dso_name, sizeof(dso_name), 682a1645ce1SZhang, Yanmin "[kernel].%d", 6832e538c4aSArnaldo Carvalho de Melo kernel_range++); 68486470930SIngo Molnar 685aeafcbafSArnaldo Carvalho de Melo ndso = dso__new(dso_name); 686aeafcbafSArnaldo Carvalho de Melo if (ndso == NULL) 6872e538c4aSArnaldo Carvalho de Melo return -1; 6882e538c4aSArnaldo Carvalho de Melo 689aeafcbafSArnaldo Carvalho de Melo ndso->kernel = dso->kernel; 690a1645ce1SZhang, Yanmin 691aeafcbafSArnaldo Carvalho de Melo curr_map = map__new2(pos->start, ndso, map->type); 69237fe5fcbSZhang, Yanmin if (curr_map == NULL) { 693aeafcbafSArnaldo Carvalho de Melo dso__delete(ndso); 6942e538c4aSArnaldo Carvalho de Melo return -1; 6952e538c4aSArnaldo Carvalho de Melo } 6962e538c4aSArnaldo Carvalho de Melo 6974e06255fSArnaldo Carvalho de Melo curr_map->map_ip = curr_map->unmap_ip = identity__map_ip; 6989de89fe7SArnaldo Carvalho de Melo map_groups__insert(kmaps, curr_map); 6992e538c4aSArnaldo Carvalho de Melo ++kernel_range; 7002e538c4aSArnaldo Carvalho de Melo } 7018a953312SArnaldo Carvalho de Melo filter_symbol: 7024e06255fSArnaldo Carvalho de Melo if (filter && filter(curr_map, pos)) { 7031de8e245SArnaldo Carvalho de Melo discard_symbol: rb_erase(&pos->rb_node, root); 70400a192b3SArnaldo Carvalho de Melo symbol__delete(pos); 7052e538c4aSArnaldo Carvalho de Melo } else { 7064e06255fSArnaldo Carvalho de Melo if (curr_map != map) { 7074e06255fSArnaldo Carvalho de Melo rb_erase(&pos->rb_node, root); 7084e06255fSArnaldo Carvalho de Melo symbols__insert(&curr_map->dso->symbols[curr_map->type], pos); 7098a953312SArnaldo Carvalho de Melo ++moved; 7108a953312SArnaldo Carvalho de Melo } else 7118a953312SArnaldo Carvalho de Melo ++count; 7129974f496SMike Galbraith } 71386470930SIngo Molnar } 71486470930SIngo Molnar 715a1645ce1SZhang, Yanmin if (curr_map != map && 716aeafcbafSArnaldo Carvalho de Melo dso->kernel == DSO_TYPE_GUEST_KERNEL && 71723346f21SArnaldo Carvalho de Melo machine__is_default_guest(kmaps->machine)) { 718a1645ce1SZhang, Yanmin dso__set_loaded(curr_map->dso, curr_map->type); 719a1645ce1SZhang, Yanmin } 720a1645ce1SZhang, Yanmin 7218a953312SArnaldo Carvalho de Melo return count + moved; 72286470930SIngo Molnar } 72386470930SIngo Molnar 7243f067dcaSArnaldo Carvalho de Melo bool symbol__restricted_filename(const char *filename, 725ec80fde7SArnaldo Carvalho de Melo const char *restricted_filename) 726ec80fde7SArnaldo Carvalho de Melo { 727ec80fde7SArnaldo Carvalho de Melo bool restricted = false; 728ec80fde7SArnaldo Carvalho de Melo 729ec80fde7SArnaldo Carvalho de Melo if (symbol_conf.kptr_restrict) { 730ec80fde7SArnaldo Carvalho de Melo char *r = realpath(filename, NULL); 731ec80fde7SArnaldo Carvalho de Melo 732ec80fde7SArnaldo Carvalho de Melo if (r != NULL) { 733ec80fde7SArnaldo Carvalho de Melo restricted = strcmp(r, restricted_filename) == 0; 734ec80fde7SArnaldo Carvalho de Melo free(r); 735ec80fde7SArnaldo Carvalho de Melo return restricted; 736ec80fde7SArnaldo Carvalho de Melo } 737ec80fde7SArnaldo Carvalho de Melo } 738ec80fde7SArnaldo Carvalho de Melo 739ec80fde7SArnaldo Carvalho de Melo return restricted; 740ec80fde7SArnaldo Carvalho de Melo } 741ec80fde7SArnaldo Carvalho de Melo 7428e0cf965SAdrian Hunter struct kcore_mapfn_data { 7438e0cf965SAdrian Hunter struct dso *dso; 7448e0cf965SAdrian Hunter enum map_type type; 7458e0cf965SAdrian Hunter struct list_head maps; 7468e0cf965SAdrian Hunter }; 7478e0cf965SAdrian Hunter 7488e0cf965SAdrian Hunter static int kcore_mapfn(u64 start, u64 len, u64 pgoff, void *data) 7498e0cf965SAdrian Hunter { 7508e0cf965SAdrian Hunter struct kcore_mapfn_data *md = data; 7518e0cf965SAdrian Hunter struct map *map; 7528e0cf965SAdrian Hunter 7538e0cf965SAdrian Hunter map = map__new2(start, md->dso, md->type); 7548e0cf965SAdrian Hunter if (map == NULL) 7558e0cf965SAdrian Hunter return -ENOMEM; 7568e0cf965SAdrian Hunter 7578e0cf965SAdrian Hunter map->end = map->start + len; 7588e0cf965SAdrian Hunter map->pgoff = pgoff; 7598e0cf965SAdrian Hunter 7608e0cf965SAdrian Hunter list_add(&map->node, &md->maps); 7618e0cf965SAdrian Hunter 7628e0cf965SAdrian Hunter return 0; 7638e0cf965SAdrian Hunter } 7648e0cf965SAdrian Hunter 7658e0cf965SAdrian Hunter /* 7668e0cf965SAdrian Hunter * If kallsyms is referenced by name then we look for kcore in the same 7678e0cf965SAdrian Hunter * directory. 7688e0cf965SAdrian Hunter */ 7698e0cf965SAdrian Hunter static bool kcore_filename_from_kallsyms_filename(char *kcore_filename, 7708e0cf965SAdrian Hunter const char *kallsyms_filename) 7718e0cf965SAdrian Hunter { 7728e0cf965SAdrian Hunter char *name; 7738e0cf965SAdrian Hunter 7748e0cf965SAdrian Hunter strcpy(kcore_filename, kallsyms_filename); 7758e0cf965SAdrian Hunter name = strrchr(kcore_filename, '/'); 7768e0cf965SAdrian Hunter if (!name) 7778e0cf965SAdrian Hunter return false; 7788e0cf965SAdrian Hunter 7798e0cf965SAdrian Hunter if (!strcmp(name, "/kallsyms")) { 7808e0cf965SAdrian Hunter strcpy(name, "/kcore"); 7818e0cf965SAdrian Hunter return true; 7828e0cf965SAdrian Hunter } 7838e0cf965SAdrian Hunter 7848e0cf965SAdrian Hunter return false; 7858e0cf965SAdrian Hunter } 7868e0cf965SAdrian Hunter 7878e0cf965SAdrian Hunter static int dso__load_kcore(struct dso *dso, struct map *map, 7888e0cf965SAdrian Hunter const char *kallsyms_filename) 7898e0cf965SAdrian Hunter { 7908e0cf965SAdrian Hunter struct map_groups *kmaps = map__kmap(map)->kmaps; 7918e0cf965SAdrian Hunter struct machine *machine = kmaps->machine; 7928e0cf965SAdrian Hunter struct kcore_mapfn_data md; 7938e0cf965SAdrian Hunter struct map *old_map, *new_map, *replacement_map = NULL; 7948e0cf965SAdrian Hunter bool is_64_bit; 7958e0cf965SAdrian Hunter int err, fd; 7968e0cf965SAdrian Hunter char kcore_filename[PATH_MAX]; 7978e0cf965SAdrian Hunter struct symbol *sym; 7988e0cf965SAdrian Hunter 7998e0cf965SAdrian Hunter /* This function requires that the map is the kernel map */ 8008e0cf965SAdrian Hunter if (map != machine->vmlinux_maps[map->type]) 8018e0cf965SAdrian Hunter return -EINVAL; 8028e0cf965SAdrian Hunter 8038e0cf965SAdrian Hunter if (!kcore_filename_from_kallsyms_filename(kcore_filename, 8048e0cf965SAdrian Hunter kallsyms_filename)) 8058e0cf965SAdrian Hunter return -EINVAL; 8068e0cf965SAdrian Hunter 8078e0cf965SAdrian Hunter md.dso = dso; 8088e0cf965SAdrian Hunter md.type = map->type; 8098e0cf965SAdrian Hunter INIT_LIST_HEAD(&md.maps); 8108e0cf965SAdrian Hunter 8118e0cf965SAdrian Hunter fd = open(kcore_filename, O_RDONLY); 8128e0cf965SAdrian Hunter if (fd < 0) 8138e0cf965SAdrian Hunter return -EINVAL; 8148e0cf965SAdrian Hunter 8158e0cf965SAdrian Hunter /* Read new maps into temporary lists */ 8168e0cf965SAdrian Hunter err = file__read_maps(fd, md.type == MAP__FUNCTION, kcore_mapfn, &md, 8178e0cf965SAdrian Hunter &is_64_bit); 8188e0cf965SAdrian Hunter if (err) 8198e0cf965SAdrian Hunter goto out_err; 8208e0cf965SAdrian Hunter 8218e0cf965SAdrian Hunter if (list_empty(&md.maps)) { 8228e0cf965SAdrian Hunter err = -EINVAL; 8238e0cf965SAdrian Hunter goto out_err; 8248e0cf965SAdrian Hunter } 8258e0cf965SAdrian Hunter 8268e0cf965SAdrian Hunter /* Remove old maps */ 8278e0cf965SAdrian Hunter old_map = map_groups__first(kmaps, map->type); 8288e0cf965SAdrian Hunter while (old_map) { 8298e0cf965SAdrian Hunter struct map *next = map_groups__next(old_map); 8308e0cf965SAdrian Hunter 8318e0cf965SAdrian Hunter if (old_map != map) 8328e0cf965SAdrian Hunter map_groups__remove(kmaps, old_map); 8338e0cf965SAdrian Hunter old_map = next; 8348e0cf965SAdrian Hunter } 8358e0cf965SAdrian Hunter 8368e0cf965SAdrian Hunter /* Find the kernel map using the first symbol */ 8378e0cf965SAdrian Hunter sym = dso__first_symbol(dso, map->type); 8388e0cf965SAdrian Hunter list_for_each_entry(new_map, &md.maps, node) { 8398e0cf965SAdrian Hunter if (sym && sym->start >= new_map->start && 8408e0cf965SAdrian Hunter sym->start < new_map->end) { 8418e0cf965SAdrian Hunter replacement_map = new_map; 8428e0cf965SAdrian Hunter break; 8438e0cf965SAdrian Hunter } 8448e0cf965SAdrian Hunter } 8458e0cf965SAdrian Hunter 8468e0cf965SAdrian Hunter if (!replacement_map) 8478e0cf965SAdrian Hunter replacement_map = list_entry(md.maps.next, struct map, node); 8488e0cf965SAdrian Hunter 8498e0cf965SAdrian Hunter /* Add new maps */ 8508e0cf965SAdrian Hunter while (!list_empty(&md.maps)) { 8518e0cf965SAdrian Hunter new_map = list_entry(md.maps.next, struct map, node); 8528e0cf965SAdrian Hunter list_del(&new_map->node); 8538e0cf965SAdrian Hunter if (new_map == replacement_map) { 8548e0cf965SAdrian Hunter map->start = new_map->start; 8558e0cf965SAdrian Hunter map->end = new_map->end; 8568e0cf965SAdrian Hunter map->pgoff = new_map->pgoff; 8578e0cf965SAdrian Hunter map->map_ip = new_map->map_ip; 8588e0cf965SAdrian Hunter map->unmap_ip = new_map->unmap_ip; 8598e0cf965SAdrian Hunter map__delete(new_map); 8608e0cf965SAdrian Hunter /* Ensure maps are correctly ordered */ 8618e0cf965SAdrian Hunter map_groups__remove(kmaps, map); 8628e0cf965SAdrian Hunter map_groups__insert(kmaps, map); 8638e0cf965SAdrian Hunter } else { 8648e0cf965SAdrian Hunter map_groups__insert(kmaps, new_map); 8658e0cf965SAdrian Hunter } 8668e0cf965SAdrian Hunter } 8678e0cf965SAdrian Hunter 8688e0cf965SAdrian Hunter /* 8698e0cf965SAdrian Hunter * Set the data type and long name so that kcore can be read via 8708e0cf965SAdrian Hunter * dso__data_read_addr(). 8718e0cf965SAdrian Hunter */ 8728e0cf965SAdrian Hunter if (dso->kernel == DSO_TYPE_GUEST_KERNEL) 8738e0cf965SAdrian Hunter dso->data_type = DSO_BINARY_TYPE__GUEST_KCORE; 8748e0cf965SAdrian Hunter else 8758e0cf965SAdrian Hunter dso->data_type = DSO_BINARY_TYPE__KCORE; 8768e0cf965SAdrian Hunter dso__set_long_name(dso, strdup(kcore_filename)); 8778e0cf965SAdrian Hunter 8788e0cf965SAdrian Hunter close(fd); 8798e0cf965SAdrian Hunter 8808e0cf965SAdrian Hunter if (map->type == MAP__FUNCTION) 8818e0cf965SAdrian Hunter pr_debug("Using %s for kernel object code\n", kcore_filename); 8828e0cf965SAdrian Hunter else 8838e0cf965SAdrian Hunter pr_debug("Using %s for kernel data\n", kcore_filename); 8848e0cf965SAdrian Hunter 8858e0cf965SAdrian Hunter return 0; 8868e0cf965SAdrian Hunter 8878e0cf965SAdrian Hunter out_err: 8888e0cf965SAdrian Hunter while (!list_empty(&md.maps)) { 8898e0cf965SAdrian Hunter map = list_entry(md.maps.next, struct map, node); 8908e0cf965SAdrian Hunter list_del(&map->node); 8918e0cf965SAdrian Hunter map__delete(map); 8928e0cf965SAdrian Hunter } 8938e0cf965SAdrian Hunter close(fd); 8948e0cf965SAdrian Hunter return -EINVAL; 8958e0cf965SAdrian Hunter } 8968e0cf965SAdrian Hunter 897aeafcbafSArnaldo Carvalho de Melo int dso__load_kallsyms(struct dso *dso, const char *filename, 8989de89fe7SArnaldo Carvalho de Melo struct map *map, symbol_filter_t filter) 8992e538c4aSArnaldo Carvalho de Melo { 900ec80fde7SArnaldo Carvalho de Melo if (symbol__restricted_filename(filename, "/proc/kallsyms")) 901ec80fde7SArnaldo Carvalho de Melo return -1; 902ec80fde7SArnaldo Carvalho de Melo 903aeafcbafSArnaldo Carvalho de Melo if (dso__load_all_kallsyms(dso, filename, map) < 0) 9042e538c4aSArnaldo Carvalho de Melo return -1; 9052e538c4aSArnaldo Carvalho de Melo 906694bf407SAnton Blanchard symbols__fixup_duplicate(&dso->symbols[map->type]); 9073f5a4272SAnton Blanchard symbols__fixup_end(&dso->symbols[map->type]); 9083f5a4272SAnton Blanchard 909aeafcbafSArnaldo Carvalho de Melo if (dso->kernel == DSO_TYPE_GUEST_KERNEL) 91044f24cb3SJiri Olsa dso->symtab_type = DSO_BINARY_TYPE__GUEST_KALLSYMS; 911a1645ce1SZhang, Yanmin else 91244f24cb3SJiri Olsa dso->symtab_type = DSO_BINARY_TYPE__KALLSYMS; 9132e538c4aSArnaldo Carvalho de Melo 9148e0cf965SAdrian Hunter if (!dso__load_kcore(dso, map, filename)) 9158e0cf965SAdrian Hunter return dso__split_kallsyms_for_kcore(dso, map, filter); 9168e0cf965SAdrian Hunter else 917aeafcbafSArnaldo Carvalho de Melo return dso__split_kallsyms(dso, map, filter); 918af427bf5SArnaldo Carvalho de Melo } 919af427bf5SArnaldo Carvalho de Melo 920aeafcbafSArnaldo Carvalho de Melo static int dso__load_perf_map(struct dso *dso, struct map *map, 9216beba7adSArnaldo Carvalho de Melo symbol_filter_t filter) 92280d496beSPekka Enberg { 92380d496beSPekka Enberg char *line = NULL; 92480d496beSPekka Enberg size_t n; 92580d496beSPekka Enberg FILE *file; 92680d496beSPekka Enberg int nr_syms = 0; 92780d496beSPekka Enberg 928aeafcbafSArnaldo Carvalho de Melo file = fopen(dso->long_name, "r"); 92980d496beSPekka Enberg if (file == NULL) 93080d496beSPekka Enberg goto out_failure; 93180d496beSPekka Enberg 93280d496beSPekka Enberg while (!feof(file)) { 9339cffa8d5SPaul Mackerras u64 start, size; 93480d496beSPekka Enberg struct symbol *sym; 93580d496beSPekka Enberg int line_len, len; 93680d496beSPekka Enberg 93780d496beSPekka Enberg line_len = getline(&line, &n, file); 93880d496beSPekka Enberg if (line_len < 0) 93980d496beSPekka Enberg break; 94080d496beSPekka Enberg 94180d496beSPekka Enberg if (!line) 94280d496beSPekka Enberg goto out_failure; 94380d496beSPekka Enberg 94480d496beSPekka Enberg line[--line_len] = '\0'; /* \n */ 94580d496beSPekka Enberg 94680d496beSPekka Enberg len = hex2u64(line, &start); 94780d496beSPekka Enberg 94880d496beSPekka Enberg len++; 94980d496beSPekka Enberg if (len + 2 >= line_len) 95080d496beSPekka Enberg continue; 95180d496beSPekka Enberg 95280d496beSPekka Enberg len += hex2u64(line + len, &size); 95380d496beSPekka Enberg 95480d496beSPekka Enberg len++; 95580d496beSPekka Enberg if (len + 2 >= line_len) 95680d496beSPekka Enberg continue; 95780d496beSPekka Enberg 958c408fedfSArnaldo Carvalho de Melo sym = symbol__new(start, size, STB_GLOBAL, line + len); 95980d496beSPekka Enberg 96080d496beSPekka Enberg if (sym == NULL) 96180d496beSPekka Enberg goto out_delete_line; 96280d496beSPekka Enberg 963439d473bSArnaldo Carvalho de Melo if (filter && filter(map, sym)) 96400a192b3SArnaldo Carvalho de Melo symbol__delete(sym); 96580d496beSPekka Enberg else { 966aeafcbafSArnaldo Carvalho de Melo symbols__insert(&dso->symbols[map->type], sym); 96780d496beSPekka Enberg nr_syms++; 96880d496beSPekka Enberg } 96980d496beSPekka Enberg } 97080d496beSPekka Enberg 97180d496beSPekka Enberg free(line); 97280d496beSPekka Enberg fclose(file); 97380d496beSPekka Enberg 97480d496beSPekka Enberg return nr_syms; 97580d496beSPekka Enberg 97680d496beSPekka Enberg out_delete_line: 97780d496beSPekka Enberg free(line); 97880d496beSPekka Enberg out_failure: 97980d496beSPekka Enberg return -1; 98080d496beSPekka Enberg } 98180d496beSPekka Enberg 982aeafcbafSArnaldo Carvalho de Melo int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter) 98386470930SIngo Molnar { 984c338aee8SArnaldo Carvalho de Melo char *name; 98586470930SIngo Molnar int ret = -1; 98644f24cb3SJiri Olsa u_int i; 98723346f21SArnaldo Carvalho de Melo struct machine *machine; 98844f24cb3SJiri Olsa char *root_dir = (char *) ""; 9893aafe5aeSCody P Schafer int ss_pos = 0; 9903aafe5aeSCody P Schafer struct symsrc ss_[2]; 9913aafe5aeSCody P Schafer struct symsrc *syms_ss = NULL, *runtime_ss = NULL; 99286470930SIngo Molnar 993aeafcbafSArnaldo Carvalho de Melo dso__set_loaded(dso, map->type); 99466bd8424SArnaldo Carvalho de Melo 995aeafcbafSArnaldo Carvalho de Melo if (dso->kernel == DSO_TYPE_KERNEL) 996aeafcbafSArnaldo Carvalho de Melo return dso__load_kernel_sym(dso, map, filter); 997aeafcbafSArnaldo Carvalho de Melo else if (dso->kernel == DSO_TYPE_GUEST_KERNEL) 998aeafcbafSArnaldo Carvalho de Melo return dso__load_guest_kernel_sym(dso, map, filter); 999a1645ce1SZhang, Yanmin 100023346f21SArnaldo Carvalho de Melo if (map->groups && map->groups->machine) 100123346f21SArnaldo Carvalho de Melo machine = map->groups->machine; 1002a1645ce1SZhang, Yanmin else 100323346f21SArnaldo Carvalho de Melo machine = NULL; 1004c338aee8SArnaldo Carvalho de Melo 1005aeafcbafSArnaldo Carvalho de Melo dso->adjust_symbols = 0; 1006f5812a7aSArnaldo Carvalho de Melo 1007aeafcbafSArnaldo Carvalho de Melo if (strncmp(dso->name, "/tmp/perf-", 10) == 0) { 1008981c1252SPekka Enberg struct stat st; 1009981c1252SPekka Enberg 1010e9b52ef2SVasiliy Kulikov if (lstat(dso->name, &st) < 0) 1011981c1252SPekka Enberg return -1; 1012981c1252SPekka Enberg 1013981c1252SPekka Enberg if (st.st_uid && (st.st_uid != geteuid())) { 1014981c1252SPekka Enberg pr_warning("File %s not owned by current user or root, " 1015981c1252SPekka Enberg "ignoring it.\n", dso->name); 1016981c1252SPekka Enberg return -1; 1017981c1252SPekka Enberg } 1018981c1252SPekka Enberg 1019aeafcbafSArnaldo Carvalho de Melo ret = dso__load_perf_map(dso, map, filter); 102044f24cb3SJiri Olsa dso->symtab_type = ret > 0 ? DSO_BINARY_TYPE__JAVA_JIT : 102144f24cb3SJiri Olsa DSO_BINARY_TYPE__NOT_FOUND; 102294cb9e38SArnaldo Carvalho de Melo return ret; 102394cb9e38SArnaldo Carvalho de Melo } 102494cb9e38SArnaldo Carvalho de Melo 102544f24cb3SJiri Olsa if (machine) 102644f24cb3SJiri Olsa root_dir = machine->root_dir; 102744f24cb3SJiri Olsa 1028164c800eSDavid Ahern name = malloc(PATH_MAX); 1029164c800eSDavid Ahern if (!name) 1030164c800eSDavid Ahern return -1; 1031164c800eSDavid Ahern 10326da80ce8SDave Martin /* Iterate over candidate debug images. 10333aafe5aeSCody P Schafer * Keep track of "interesting" ones (those which have a symtab, dynsym, 10343aafe5aeSCody P Schafer * and/or opd section) for processing. 10356da80ce8SDave Martin */ 103644f24cb3SJiri Olsa for (i = 0; i < DSO_BINARY_TYPE__SYMTAB_CNT; i++) { 10373aafe5aeSCody P Schafer struct symsrc *ss = &ss_[ss_pos]; 10383aafe5aeSCody P Schafer bool next_slot = false; 103944f24cb3SJiri Olsa 1040005f9294SCody P Schafer enum dso_binary_type symtab_type = binary_type_symtab[i]; 104144f24cb3SJiri Olsa 1042005f9294SCody P Schafer if (dso__binary_type_file(dso, symtab_type, 104344f24cb3SJiri Olsa root_dir, name, PATH_MAX)) 10446da80ce8SDave Martin continue; 104586470930SIngo Molnar 10466da80ce8SDave Martin /* Name is now the name of the next image to try */ 10473aafe5aeSCody P Schafer if (symsrc__init(ss, dso, name, symtab_type) < 0) 10486da80ce8SDave Martin continue; 10496da80ce8SDave Martin 10503aafe5aeSCody P Schafer if (!syms_ss && symsrc__has_symtab(ss)) { 10513aafe5aeSCody P Schafer syms_ss = ss; 10523aafe5aeSCody P Schafer next_slot = true; 1053d26cd12bSCody P Schafer } 1054d26cd12bSCody P Schafer 10553aafe5aeSCody P Schafer if (!runtime_ss && symsrc__possibly_runtime(ss)) { 10563aafe5aeSCody P Schafer runtime_ss = ss; 10573aafe5aeSCody P Schafer next_slot = true; 1058a44f605bSCody P Schafer } 105986470930SIngo Molnar 10603aafe5aeSCody P Schafer if (next_slot) { 10613aafe5aeSCody P Schafer ss_pos++; 106233ff581eSJiri Olsa 10633aafe5aeSCody P Schafer if (syms_ss && runtime_ss) 10646da80ce8SDave Martin break; 1065a25e46c4SArnaldo Carvalho de Melo } 10663aafe5aeSCody P Schafer 10676da80ce8SDave Martin } 10686da80ce8SDave Martin 10693aafe5aeSCody P Schafer if (!runtime_ss && !syms_ss) 10703aafe5aeSCody P Schafer goto out_free; 10713aafe5aeSCody P Schafer 10723aafe5aeSCody P Schafer if (runtime_ss && !syms_ss) { 10733aafe5aeSCody P Schafer syms_ss = runtime_ss; 107460e4b10cSArnaldo Carvalho de Melo } 107560e4b10cSArnaldo Carvalho de Melo 10763aafe5aeSCody P Schafer /* We'll have to hope for the best */ 10773aafe5aeSCody P Schafer if (!runtime_ss && syms_ss) 10783aafe5aeSCody P Schafer runtime_ss = syms_ss; 10793aafe5aeSCody P Schafer 10800131c4ecSAdrian Hunter if (syms_ss) { 10810131c4ecSAdrian Hunter int km; 10820131c4ecSAdrian Hunter 10830131c4ecSAdrian Hunter km = dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE || 10840131c4ecSAdrian Hunter dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE; 10850131c4ecSAdrian Hunter ret = dso__load_sym(dso, map, syms_ss, runtime_ss, filter, km); 10860131c4ecSAdrian Hunter } else { 10873aafe5aeSCody P Schafer ret = -1; 10880131c4ecSAdrian Hunter } 10893aafe5aeSCody P Schafer 1090f47b58b7SDavid Ahern if (ret > 0) { 10913aafe5aeSCody P Schafer int nr_plt; 10923aafe5aeSCody P Schafer 10933aafe5aeSCody P Schafer nr_plt = dso__synthesize_plt_symbols(dso, runtime_ss, map, filter); 10943aafe5aeSCody P Schafer if (nr_plt > 0) 10953aafe5aeSCody P Schafer ret += nr_plt; 10963aafe5aeSCody P Schafer } 10973aafe5aeSCody P Schafer 10983aafe5aeSCody P Schafer for (; ss_pos > 0; ss_pos--) 10993aafe5aeSCody P Schafer symsrc__destroy(&ss_[ss_pos - 1]); 11003aafe5aeSCody P Schafer out_free: 110186470930SIngo Molnar free(name); 1102aeafcbafSArnaldo Carvalho de Melo if (ret < 0 && strstr(dso->name, " (deleted)") != NULL) 11031340e6bbSArnaldo Carvalho de Melo return 0; 110486470930SIngo Molnar return ret; 110586470930SIngo Molnar } 110686470930SIngo Molnar 1107aeafcbafSArnaldo Carvalho de Melo struct map *map_groups__find_by_name(struct map_groups *mg, 110879406cd7SArnaldo Carvalho de Melo enum map_type type, const char *name) 1109439d473bSArnaldo Carvalho de Melo { 1110439d473bSArnaldo Carvalho de Melo struct rb_node *nd; 1111439d473bSArnaldo Carvalho de Melo 1112aeafcbafSArnaldo Carvalho de Melo for (nd = rb_first(&mg->maps[type]); nd; nd = rb_next(nd)) { 1113439d473bSArnaldo Carvalho de Melo struct map *map = rb_entry(nd, struct map, rb_node); 1114439d473bSArnaldo Carvalho de Melo 1115b7cece76SArnaldo Carvalho de Melo if (map->dso && strcmp(map->dso->short_name, name) == 0) 1116439d473bSArnaldo Carvalho de Melo return map; 1117439d473bSArnaldo Carvalho de Melo } 1118439d473bSArnaldo Carvalho de Melo 1119439d473bSArnaldo Carvalho de Melo return NULL; 1120439d473bSArnaldo Carvalho de Melo } 1121439d473bSArnaldo Carvalho de Melo 1122aeafcbafSArnaldo Carvalho de Melo int dso__load_vmlinux(struct dso *dso, struct map *map, 11236beba7adSArnaldo Carvalho de Melo const char *vmlinux, symbol_filter_t filter) 112486470930SIngo Molnar { 1125b68e2f91SCody P Schafer int err = -1; 1126b68e2f91SCody P Schafer struct symsrc ss; 1127ec5761eaSDavid Ahern char symfs_vmlinux[PATH_MAX]; 1128005f9294SCody P Schafer enum dso_binary_type symtab_type; 112986470930SIngo Molnar 11305698d2c9SNamhyung Kim if (vmlinux[0] == '/') 11315698d2c9SNamhyung Kim snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s", vmlinux); 11325698d2c9SNamhyung Kim else 1133a639dc64SArnaldo Carvalho de Melo snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s%s", 1134ec5761eaSDavid Ahern symbol_conf.symfs, vmlinux); 113586470930SIngo Molnar 113621ea4539SCody P Schafer if (dso->kernel == DSO_TYPE_GUEST_KERNEL) 1137005f9294SCody P Schafer symtab_type = DSO_BINARY_TYPE__GUEST_VMLINUX; 113821ea4539SCody P Schafer else 1139005f9294SCody P Schafer symtab_type = DSO_BINARY_TYPE__VMLINUX; 114021ea4539SCody P Schafer 1141005f9294SCody P Schafer if (symsrc__init(&ss, dso, symfs_vmlinux, symtab_type)) 1142b68e2f91SCody P Schafer return -1; 1143b68e2f91SCody P Schafer 1144261360b6SCody P Schafer err = dso__load_sym(dso, map, &ss, &ss, filter, 0); 1145b68e2f91SCody P Schafer symsrc__destroy(&ss); 114686470930SIngo Molnar 1147515850e4SCody P Schafer if (err > 0) { 114839b12f78SAdrian Hunter if (dso->kernel == DSO_TYPE_GUEST_KERNEL) 114939b12f78SAdrian Hunter dso->data_type = DSO_BINARY_TYPE__GUEST_VMLINUX; 115039b12f78SAdrian Hunter else 115139b12f78SAdrian Hunter dso->data_type = DSO_BINARY_TYPE__VMLINUX; 1152515850e4SCody P Schafer dso__set_long_name(dso, (char *)vmlinux); 1153515850e4SCody P Schafer dso__set_loaded(dso, map->type); 1154ec5761eaSDavid Ahern pr_debug("Using %s for symbols\n", symfs_vmlinux); 1155515850e4SCody P Schafer } 11563846df2eSArnaldo Carvalho de Melo 115786470930SIngo Molnar return err; 115886470930SIngo Molnar } 115986470930SIngo Molnar 1160aeafcbafSArnaldo Carvalho de Melo int dso__load_vmlinux_path(struct dso *dso, struct map *map, 11619de89fe7SArnaldo Carvalho de Melo symbol_filter_t filter) 1162a19afe46SArnaldo Carvalho de Melo { 1163a19afe46SArnaldo Carvalho de Melo int i, err = 0; 11645ad90e4eSArnaldo Carvalho de Melo char *filename; 1165a19afe46SArnaldo Carvalho de Melo 1166a19afe46SArnaldo Carvalho de Melo pr_debug("Looking at the vmlinux_path (%d entries long)\n", 11675ad90e4eSArnaldo Carvalho de Melo vmlinux_path__nr_entries + 1); 11685ad90e4eSArnaldo Carvalho de Melo 1169aeafcbafSArnaldo Carvalho de Melo filename = dso__build_id_filename(dso, NULL, 0); 11705ad90e4eSArnaldo Carvalho de Melo if (filename != NULL) { 1171aeafcbafSArnaldo Carvalho de Melo err = dso__load_vmlinux(dso, map, filename, filter); 1172b7c14a0bSDavid Ahern if (err > 0) { 1173b7c14a0bSDavid Ahern dso->lname_alloc = 1; 11745ad90e4eSArnaldo Carvalho de Melo goto out; 1175b7c14a0bSDavid Ahern } 11765ad90e4eSArnaldo Carvalho de Melo free(filename); 11775ad90e4eSArnaldo Carvalho de Melo } 1178a19afe46SArnaldo Carvalho de Melo 1179a19afe46SArnaldo Carvalho de Melo for (i = 0; i < vmlinux_path__nr_entries; ++i) { 1180aeafcbafSArnaldo Carvalho de Melo err = dso__load_vmlinux(dso, map, vmlinux_path[i], filter); 1181a19afe46SArnaldo Carvalho de Melo if (err > 0) { 1182aeafcbafSArnaldo Carvalho de Melo dso__set_long_name(dso, strdup(vmlinux_path[i])); 1183b7c14a0bSDavid Ahern dso->lname_alloc = 1; 1184a19afe46SArnaldo Carvalho de Melo break; 1185a19afe46SArnaldo Carvalho de Melo } 1186a19afe46SArnaldo Carvalho de Melo } 11875ad90e4eSArnaldo Carvalho de Melo out: 1188a19afe46SArnaldo Carvalho de Melo return err; 1189a19afe46SArnaldo Carvalho de Melo } 1190a19afe46SArnaldo Carvalho de Melo 1191aeafcbafSArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *dso, struct map *map, 11929de89fe7SArnaldo Carvalho de Melo symbol_filter_t filter) 119386470930SIngo Molnar { 1194cc612d81SArnaldo Carvalho de Melo int err; 11959e201442SArnaldo Carvalho de Melo const char *kallsyms_filename = NULL; 11969e201442SArnaldo Carvalho de Melo char *kallsyms_allocated_filename = NULL; 1197dc8d6ab2SArnaldo Carvalho de Melo /* 1198b226a5a7SDavid Ahern * Step 1: if the user specified a kallsyms or vmlinux filename, use 1199b226a5a7SDavid Ahern * it and only it, reporting errors to the user if it cannot be used. 1200dc8d6ab2SArnaldo Carvalho de Melo * 1201dc8d6ab2SArnaldo Carvalho de Melo * For instance, try to analyse an ARM perf.data file _without_ a 1202dc8d6ab2SArnaldo Carvalho de Melo * build-id, or if the user specifies the wrong path to the right 1203dc8d6ab2SArnaldo Carvalho de Melo * vmlinux file, obviously we can't fallback to another vmlinux (a 1204dc8d6ab2SArnaldo Carvalho de Melo * x86_86 one, on the machine where analysis is being performed, say), 1205dc8d6ab2SArnaldo Carvalho de Melo * or worse, /proc/kallsyms. 1206dc8d6ab2SArnaldo Carvalho de Melo * 1207dc8d6ab2SArnaldo Carvalho de Melo * If the specified file _has_ a build-id and there is a build-id 1208dc8d6ab2SArnaldo Carvalho de Melo * section in the perf.data file, we will still do the expected 1209dc8d6ab2SArnaldo Carvalho de Melo * validation in dso__load_vmlinux and will bail out if they don't 1210dc8d6ab2SArnaldo Carvalho de Melo * match. 1211dc8d6ab2SArnaldo Carvalho de Melo */ 1212b226a5a7SDavid Ahern if (symbol_conf.kallsyms_name != NULL) { 1213b226a5a7SDavid Ahern kallsyms_filename = symbol_conf.kallsyms_name; 1214b226a5a7SDavid Ahern goto do_kallsyms; 1215b226a5a7SDavid Ahern } 1216b226a5a7SDavid Ahern 1217dc8d6ab2SArnaldo Carvalho de Melo if (symbol_conf.vmlinux_name != NULL) { 1218aeafcbafSArnaldo Carvalho de Melo err = dso__load_vmlinux(dso, map, 1219dc8d6ab2SArnaldo Carvalho de Melo symbol_conf.vmlinux_name, filter); 1220e7dadc00SArnaldo Carvalho de Melo if (err > 0) { 1221aeafcbafSArnaldo Carvalho de Melo dso__set_long_name(dso, 1222e7dadc00SArnaldo Carvalho de Melo strdup(symbol_conf.vmlinux_name)); 1223b7c14a0bSDavid Ahern dso->lname_alloc = 1; 122439b12f78SAdrian Hunter return err; 1225e7dadc00SArnaldo Carvalho de Melo } 1226e7dadc00SArnaldo Carvalho de Melo return err; 1227dc8d6ab2SArnaldo Carvalho de Melo } 1228439d473bSArnaldo Carvalho de Melo 1229cc612d81SArnaldo Carvalho de Melo if (vmlinux_path != NULL) { 1230aeafcbafSArnaldo Carvalho de Melo err = dso__load_vmlinux_path(dso, map, filter); 1231a19afe46SArnaldo Carvalho de Melo if (err > 0) 123239b12f78SAdrian Hunter return err; 1233cc612d81SArnaldo Carvalho de Melo } 1234cc612d81SArnaldo Carvalho de Melo 1235ec5761eaSDavid Ahern /* do not try local files if a symfs was given */ 1236ec5761eaSDavid Ahern if (symbol_conf.symfs[0] != 0) 1237ec5761eaSDavid Ahern return -1; 1238ec5761eaSDavid Ahern 1239b7cece76SArnaldo Carvalho de Melo /* 1240b7cece76SArnaldo Carvalho de Melo * Say the kernel DSO was created when processing the build-id header table, 1241b7cece76SArnaldo Carvalho de Melo * we have a build-id, so check if it is the same as the running kernel, 1242b7cece76SArnaldo Carvalho de Melo * using it if it is. 1243b7cece76SArnaldo Carvalho de Melo */ 1244aeafcbafSArnaldo Carvalho de Melo if (dso->has_build_id) { 1245b7cece76SArnaldo Carvalho de Melo u8 kallsyms_build_id[BUILD_ID_SIZE]; 12469e201442SArnaldo Carvalho de Melo char sbuild_id[BUILD_ID_SIZE * 2 + 1]; 1247b7cece76SArnaldo Carvalho de Melo 1248b7cece76SArnaldo Carvalho de Melo if (sysfs__read_build_id("/sys/kernel/notes", kallsyms_build_id, 12498d0591f6SArnaldo Carvalho de Melo sizeof(kallsyms_build_id)) == 0) { 1250aeafcbafSArnaldo Carvalho de Melo if (dso__build_id_equal(dso, kallsyms_build_id)) { 12519e201442SArnaldo Carvalho de Melo kallsyms_filename = "/proc/kallsyms"; 1252b7cece76SArnaldo Carvalho de Melo goto do_kallsyms; 12538d0591f6SArnaldo Carvalho de Melo } 12549e201442SArnaldo Carvalho de Melo } 1255dc8d6ab2SArnaldo Carvalho de Melo /* 1256dc8d6ab2SArnaldo Carvalho de Melo * Now look if we have it on the build-id cache in 1257dc8d6ab2SArnaldo Carvalho de Melo * $HOME/.debug/[kernel.kallsyms]. 1258dc8d6ab2SArnaldo Carvalho de Melo */ 1259aeafcbafSArnaldo Carvalho de Melo build_id__sprintf(dso->build_id, sizeof(dso->build_id), 12609e201442SArnaldo Carvalho de Melo sbuild_id); 12619e201442SArnaldo Carvalho de Melo 12629e201442SArnaldo Carvalho de Melo if (asprintf(&kallsyms_allocated_filename, 12639e201442SArnaldo Carvalho de Melo "%s/.debug/[kernel.kallsyms]/%s", 12643846df2eSArnaldo Carvalho de Melo getenv("HOME"), sbuild_id) == -1) { 12653846df2eSArnaldo Carvalho de Melo pr_err("Not enough memory for kallsyms file lookup\n"); 12668d0591f6SArnaldo Carvalho de Melo return -1; 12673846df2eSArnaldo Carvalho de Melo } 12688d0591f6SArnaldo Carvalho de Melo 126919fc2dedSArnaldo Carvalho de Melo kallsyms_filename = kallsyms_allocated_filename; 127019fc2dedSArnaldo Carvalho de Melo 1271dc8d6ab2SArnaldo Carvalho de Melo if (access(kallsyms_filename, F_OK)) { 12723846df2eSArnaldo Carvalho de Melo pr_err("No kallsyms or vmlinux with build-id %s " 12733846df2eSArnaldo Carvalho de Melo "was found\n", sbuild_id); 12749e201442SArnaldo Carvalho de Melo free(kallsyms_allocated_filename); 1275dc8d6ab2SArnaldo Carvalho de Melo return -1; 1276ef6ae724SArnaldo Carvalho de Melo } 1277dc8d6ab2SArnaldo Carvalho de Melo } else { 1278dc8d6ab2SArnaldo Carvalho de Melo /* 1279dc8d6ab2SArnaldo Carvalho de Melo * Last resort, if we don't have a build-id and couldn't find 1280dc8d6ab2SArnaldo Carvalho de Melo * any vmlinux file, try the running kernel kallsyms table. 1281dc8d6ab2SArnaldo Carvalho de Melo */ 1282dc8d6ab2SArnaldo Carvalho de Melo kallsyms_filename = "/proc/kallsyms"; 1283dc8d6ab2SArnaldo Carvalho de Melo } 1284dc8d6ab2SArnaldo Carvalho de Melo 1285dc8d6ab2SArnaldo Carvalho de Melo do_kallsyms: 1286aeafcbafSArnaldo Carvalho de Melo err = dso__load_kallsyms(dso, kallsyms_filename, map, filter); 12873846df2eSArnaldo Carvalho de Melo if (err > 0) 12883846df2eSArnaldo Carvalho de Melo pr_debug("Using %s for symbols\n", kallsyms_filename); 1289dc8d6ab2SArnaldo Carvalho de Melo free(kallsyms_allocated_filename); 1290dc8d6ab2SArnaldo Carvalho de Melo 12918e0cf965SAdrian Hunter if (err > 0 && !dso__is_kcore(dso)) { 1292aeafcbafSArnaldo Carvalho de Melo dso__set_long_name(dso, strdup("[kernel.kallsyms]")); 12936a4694a4SArnaldo Carvalho de Melo map__fixup_start(map); 12946a4694a4SArnaldo Carvalho de Melo map__fixup_end(map); 1295439d473bSArnaldo Carvalho de Melo } 129694cb9e38SArnaldo Carvalho de Melo 129786470930SIngo Molnar return err; 129886470930SIngo Molnar } 129986470930SIngo Molnar 1300aeafcbafSArnaldo Carvalho de Melo static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map, 1301a1645ce1SZhang, Yanmin symbol_filter_t filter) 1302a1645ce1SZhang, Yanmin { 1303a1645ce1SZhang, Yanmin int err; 1304a1645ce1SZhang, Yanmin const char *kallsyms_filename = NULL; 130523346f21SArnaldo Carvalho de Melo struct machine *machine; 1306a1645ce1SZhang, Yanmin char path[PATH_MAX]; 1307a1645ce1SZhang, Yanmin 1308a1645ce1SZhang, Yanmin if (!map->groups) { 1309a1645ce1SZhang, Yanmin pr_debug("Guest kernel map hasn't the point to groups\n"); 1310a1645ce1SZhang, Yanmin return -1; 1311a1645ce1SZhang, Yanmin } 131223346f21SArnaldo Carvalho de Melo machine = map->groups->machine; 1313a1645ce1SZhang, Yanmin 131423346f21SArnaldo Carvalho de Melo if (machine__is_default_guest(machine)) { 1315a1645ce1SZhang, Yanmin /* 1316a1645ce1SZhang, Yanmin * if the user specified a vmlinux filename, use it and only 1317a1645ce1SZhang, Yanmin * it, reporting errors to the user if it cannot be used. 1318a1645ce1SZhang, Yanmin * Or use file guest_kallsyms inputted by user on commandline 1319a1645ce1SZhang, Yanmin */ 1320a1645ce1SZhang, Yanmin if (symbol_conf.default_guest_vmlinux_name != NULL) { 1321aeafcbafSArnaldo Carvalho de Melo err = dso__load_vmlinux(dso, map, 1322a1645ce1SZhang, Yanmin symbol_conf.default_guest_vmlinux_name, filter); 132339b12f78SAdrian Hunter return err; 1324a1645ce1SZhang, Yanmin } 1325a1645ce1SZhang, Yanmin 1326a1645ce1SZhang, Yanmin kallsyms_filename = symbol_conf.default_guest_kallsyms; 1327a1645ce1SZhang, Yanmin if (!kallsyms_filename) 1328a1645ce1SZhang, Yanmin return -1; 1329a1645ce1SZhang, Yanmin } else { 133023346f21SArnaldo Carvalho de Melo sprintf(path, "%s/proc/kallsyms", machine->root_dir); 1331a1645ce1SZhang, Yanmin kallsyms_filename = path; 1332a1645ce1SZhang, Yanmin } 1333a1645ce1SZhang, Yanmin 1334aeafcbafSArnaldo Carvalho de Melo err = dso__load_kallsyms(dso, kallsyms_filename, map, filter); 13358e0cf965SAdrian Hunter if (err > 0) 133639b12f78SAdrian Hunter pr_debug("Using %s for symbols\n", kallsyms_filename); 13378e0cf965SAdrian Hunter if (err > 0 && !dso__is_kcore(dso)) { 133848ea8f54SArnaldo Carvalho de Melo machine__mmap_name(machine, path, sizeof(path)); 1339aeafcbafSArnaldo Carvalho de Melo dso__set_long_name(dso, strdup(path)); 1340a1645ce1SZhang, Yanmin map__fixup_start(map); 1341a1645ce1SZhang, Yanmin map__fixup_end(map); 1342a1645ce1SZhang, Yanmin } 1343a1645ce1SZhang, Yanmin 1344a1645ce1SZhang, Yanmin return err; 1345a1645ce1SZhang, Yanmin } 1346cd84c2acSFrederic Weisbecker 1347cc612d81SArnaldo Carvalho de Melo static void vmlinux_path__exit(void) 13482446042cSArnaldo Carvalho de Melo { 1349cc612d81SArnaldo Carvalho de Melo while (--vmlinux_path__nr_entries >= 0) { 1350cc612d81SArnaldo Carvalho de Melo free(vmlinux_path[vmlinux_path__nr_entries]); 1351cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = NULL; 1352cc612d81SArnaldo Carvalho de Melo } 1353cc612d81SArnaldo Carvalho de Melo 1354cc612d81SArnaldo Carvalho de Melo free(vmlinux_path); 1355cc612d81SArnaldo Carvalho de Melo vmlinux_path = NULL; 1356cc612d81SArnaldo Carvalho de Melo } 1357cc612d81SArnaldo Carvalho de Melo 1358cc612d81SArnaldo Carvalho de Melo static int vmlinux_path__init(void) 1359cc612d81SArnaldo Carvalho de Melo { 1360cc612d81SArnaldo Carvalho de Melo struct utsname uts; 1361cc612d81SArnaldo Carvalho de Melo char bf[PATH_MAX]; 1362cc612d81SArnaldo Carvalho de Melo 1363cc612d81SArnaldo Carvalho de Melo vmlinux_path = malloc(sizeof(char *) * 5); 1364cc612d81SArnaldo Carvalho de Melo if (vmlinux_path == NULL) 1365cc612d81SArnaldo Carvalho de Melo return -1; 1366cc612d81SArnaldo Carvalho de Melo 1367cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup("vmlinux"); 1368cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 1369cc612d81SArnaldo Carvalho de Melo goto out_fail; 1370cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 1371cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup("/boot/vmlinux"); 1372cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 1373cc612d81SArnaldo Carvalho de Melo goto out_fail; 1374cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 1375ec5761eaSDavid Ahern 1376ec5761eaSDavid Ahern /* only try running kernel version if no symfs was given */ 1377ec5761eaSDavid Ahern if (symbol_conf.symfs[0] != 0) 1378ec5761eaSDavid Ahern return 0; 1379ec5761eaSDavid Ahern 1380ec5761eaSDavid Ahern if (uname(&uts) < 0) 1381ec5761eaSDavid Ahern return -1; 1382ec5761eaSDavid Ahern 1383cc612d81SArnaldo Carvalho de Melo snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", uts.release); 1384cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); 1385cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 1386cc612d81SArnaldo Carvalho de Melo goto out_fail; 1387cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 1388cc612d81SArnaldo Carvalho de Melo snprintf(bf, sizeof(bf), "/lib/modules/%s/build/vmlinux", uts.release); 1389cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); 1390cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 1391cc612d81SArnaldo Carvalho de Melo goto out_fail; 1392cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 1393cc612d81SArnaldo Carvalho de Melo snprintf(bf, sizeof(bf), "/usr/lib/debug/lib/modules/%s/vmlinux", 1394cc612d81SArnaldo Carvalho de Melo uts.release); 1395cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); 1396cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 1397cc612d81SArnaldo Carvalho de Melo goto out_fail; 1398cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 1399cc612d81SArnaldo Carvalho de Melo 1400cc612d81SArnaldo Carvalho de Melo return 0; 1401cc612d81SArnaldo Carvalho de Melo 1402cc612d81SArnaldo Carvalho de Melo out_fail: 1403cc612d81SArnaldo Carvalho de Melo vmlinux_path__exit(); 1404cc612d81SArnaldo Carvalho de Melo return -1; 1405cc612d81SArnaldo Carvalho de Melo } 1406cc612d81SArnaldo Carvalho de Melo 1407655000e7SArnaldo Carvalho de Melo static int setup_list(struct strlist **list, const char *list_str, 1408655000e7SArnaldo Carvalho de Melo const char *list_name) 1409655000e7SArnaldo Carvalho de Melo { 1410655000e7SArnaldo Carvalho de Melo if (list_str == NULL) 1411655000e7SArnaldo Carvalho de Melo return 0; 1412655000e7SArnaldo Carvalho de Melo 1413655000e7SArnaldo Carvalho de Melo *list = strlist__new(true, list_str); 1414655000e7SArnaldo Carvalho de Melo if (!*list) { 1415655000e7SArnaldo Carvalho de Melo pr_err("problems parsing %s list\n", list_name); 1416655000e7SArnaldo Carvalho de Melo return -1; 1417655000e7SArnaldo Carvalho de Melo } 1418655000e7SArnaldo Carvalho de Melo return 0; 1419655000e7SArnaldo Carvalho de Melo } 1420655000e7SArnaldo Carvalho de Melo 1421ec80fde7SArnaldo Carvalho de Melo static bool symbol__read_kptr_restrict(void) 1422ec80fde7SArnaldo Carvalho de Melo { 1423ec80fde7SArnaldo Carvalho de Melo bool value = false; 1424ec80fde7SArnaldo Carvalho de Melo 1425ec80fde7SArnaldo Carvalho de Melo if (geteuid() != 0) { 1426ec80fde7SArnaldo Carvalho de Melo FILE *fp = fopen("/proc/sys/kernel/kptr_restrict", "r"); 1427ec80fde7SArnaldo Carvalho de Melo if (fp != NULL) { 1428ec80fde7SArnaldo Carvalho de Melo char line[8]; 1429ec80fde7SArnaldo Carvalho de Melo 1430ec80fde7SArnaldo Carvalho de Melo if (fgets(line, sizeof(line), fp) != NULL) 1431ec80fde7SArnaldo Carvalho de Melo value = atoi(line) != 0; 1432ec80fde7SArnaldo Carvalho de Melo 1433ec80fde7SArnaldo Carvalho de Melo fclose(fp); 1434ec80fde7SArnaldo Carvalho de Melo } 1435ec80fde7SArnaldo Carvalho de Melo } 1436ec80fde7SArnaldo Carvalho de Melo 1437ec80fde7SArnaldo Carvalho de Melo return value; 1438ec80fde7SArnaldo Carvalho de Melo } 1439ec80fde7SArnaldo Carvalho de Melo 144075be6cf4SArnaldo Carvalho de Melo int symbol__init(void) 1441cc612d81SArnaldo Carvalho de Melo { 1442ec5761eaSDavid Ahern const char *symfs; 1443ec5761eaSDavid Ahern 144485e00b55SJovi Zhang if (symbol_conf.initialized) 144585e00b55SJovi Zhang return 0; 144685e00b55SJovi Zhang 14479ac3e487SIrina Tirdea symbol_conf.priv_size = PERF_ALIGN(symbol_conf.priv_size, sizeof(u64)); 14484d439517SDavid S. Miller 1449166ccc9cSNamhyung Kim symbol__elf_init(); 1450166ccc9cSNamhyung Kim 145175be6cf4SArnaldo Carvalho de Melo if (symbol_conf.sort_by_name) 145275be6cf4SArnaldo Carvalho de Melo symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) - 145379406cd7SArnaldo Carvalho de Melo sizeof(struct symbol)); 1454b32d133aSArnaldo Carvalho de Melo 145575be6cf4SArnaldo Carvalho de Melo if (symbol_conf.try_vmlinux_path && vmlinux_path__init() < 0) 1456cc612d81SArnaldo Carvalho de Melo return -1; 1457cc612d81SArnaldo Carvalho de Melo 1458c410a338SArnaldo Carvalho de Melo if (symbol_conf.field_sep && *symbol_conf.field_sep == '.') { 1459c410a338SArnaldo Carvalho de Melo pr_err("'.' is the only non valid --field-separator argument\n"); 1460c410a338SArnaldo Carvalho de Melo return -1; 1461c410a338SArnaldo Carvalho de Melo } 1462c410a338SArnaldo Carvalho de Melo 1463655000e7SArnaldo Carvalho de Melo if (setup_list(&symbol_conf.dso_list, 1464655000e7SArnaldo Carvalho de Melo symbol_conf.dso_list_str, "dso") < 0) 1465655000e7SArnaldo Carvalho de Melo return -1; 1466655000e7SArnaldo Carvalho de Melo 1467655000e7SArnaldo Carvalho de Melo if (setup_list(&symbol_conf.comm_list, 1468655000e7SArnaldo Carvalho de Melo symbol_conf.comm_list_str, "comm") < 0) 1469655000e7SArnaldo Carvalho de Melo goto out_free_dso_list; 1470655000e7SArnaldo Carvalho de Melo 1471655000e7SArnaldo Carvalho de Melo if (setup_list(&symbol_conf.sym_list, 1472655000e7SArnaldo Carvalho de Melo symbol_conf.sym_list_str, "symbol") < 0) 1473655000e7SArnaldo Carvalho de Melo goto out_free_comm_list; 1474655000e7SArnaldo Carvalho de Melo 1475ec5761eaSDavid Ahern /* 1476ec5761eaSDavid Ahern * A path to symbols of "/" is identical to "" 1477ec5761eaSDavid Ahern * reset here for simplicity. 1478ec5761eaSDavid Ahern */ 1479ec5761eaSDavid Ahern symfs = realpath(symbol_conf.symfs, NULL); 1480ec5761eaSDavid Ahern if (symfs == NULL) 1481ec5761eaSDavid Ahern symfs = symbol_conf.symfs; 1482ec5761eaSDavid Ahern if (strcmp(symfs, "/") == 0) 1483ec5761eaSDavid Ahern symbol_conf.symfs = ""; 1484ec5761eaSDavid Ahern if (symfs != symbol_conf.symfs) 1485ec5761eaSDavid Ahern free((void *)symfs); 1486ec5761eaSDavid Ahern 1487ec80fde7SArnaldo Carvalho de Melo symbol_conf.kptr_restrict = symbol__read_kptr_restrict(); 1488ec80fde7SArnaldo Carvalho de Melo 148985e00b55SJovi Zhang symbol_conf.initialized = true; 14904aa65636SArnaldo Carvalho de Melo return 0; 1491655000e7SArnaldo Carvalho de Melo 1492655000e7SArnaldo Carvalho de Melo out_free_comm_list: 1493655000e7SArnaldo Carvalho de Melo strlist__delete(symbol_conf.comm_list); 1494d74c896bSNamhyung Kim out_free_dso_list: 1495d74c896bSNamhyung Kim strlist__delete(symbol_conf.dso_list); 1496655000e7SArnaldo Carvalho de Melo return -1; 1497cc612d81SArnaldo Carvalho de Melo } 1498cc612d81SArnaldo Carvalho de Melo 1499d65a458bSArnaldo Carvalho de Melo void symbol__exit(void) 1500d65a458bSArnaldo Carvalho de Melo { 150185e00b55SJovi Zhang if (!symbol_conf.initialized) 150285e00b55SJovi Zhang return; 1503d65a458bSArnaldo Carvalho de Melo strlist__delete(symbol_conf.sym_list); 1504d65a458bSArnaldo Carvalho de Melo strlist__delete(symbol_conf.dso_list); 1505d65a458bSArnaldo Carvalho de Melo strlist__delete(symbol_conf.comm_list); 1506d65a458bSArnaldo Carvalho de Melo vmlinux_path__exit(); 1507d65a458bSArnaldo Carvalho de Melo symbol_conf.sym_list = symbol_conf.dso_list = symbol_conf.comm_list = NULL; 150885e00b55SJovi Zhang symbol_conf.initialized = false; 1509d65a458bSArnaldo Carvalho de Melo } 1510