1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 25aab621bSArnaldo Carvalho de Melo #include <dirent.h> 35aab621bSArnaldo Carvalho de Melo #include <errno.h> 45aab621bSArnaldo Carvalho de Melo #include <stdlib.h> 55aab621bSArnaldo Carvalho de Melo #include <stdio.h> 65aab621bSArnaldo Carvalho de Melo #include <string.h> 7877a7a11SArnaldo Carvalho de Melo #include <linux/kernel.h> 8e9814df8SArnaldo Carvalho de Melo #include <linux/mman.h> 95aab621bSArnaldo Carvalho de Melo #include <sys/types.h> 105aab621bSArnaldo Carvalho de Melo #include <sys/stat.h> 115aab621bSArnaldo Carvalho de Melo #include <sys/param.h> 125aab621bSArnaldo Carvalho de Melo #include <fcntl.h> 135aab621bSArnaldo Carvalho de Melo #include <unistd.h> 149486aa38SArnaldo Carvalho de Melo #include <inttypes.h> 15b01141f4SArnaldo Carvalho de Melo #include "annotate.h" 16b36f19d5SArnaldo Carvalho de Melo #include "build-id.h" 17e334c726SNamhyung Kim #include "util.h" 188a6c5b26SArnaldo Carvalho de Melo #include "debug.h" 1969d2591aSArnaldo Carvalho de Melo #include "machine.h" 201101f69aSArnaldo Carvalho de Melo #include "map.h" 2186470930SIngo Molnar #include "symbol.h" 225aab621bSArnaldo Carvalho de Melo #include "strlist.h" 23e03eaa40SDavid Ahern #include "intlist.h" 24843ff37bSKrister Johansen #include "namespaces.h" 250a7e6d1bSNamhyung Kim #include "header.h" 269a3993d4SArnaldo Carvalho de Melo #include "path.h" 273d689ed6SArnaldo Carvalho de Melo #include "sane_ctype.h" 2886470930SIngo Molnar 2986470930SIngo Molnar #include <elf.h> 30f1617b40SArnaldo Carvalho de Melo #include <limits.h> 31c506c96bSArnaldo Carvalho de Melo #include <symbol/kallsyms.h> 32439d473bSArnaldo Carvalho de Melo #include <sys/utsname.h> 332cdbc46dSPeter Zijlstra 34be39db9fSArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *dso, struct map *map); 35be39db9fSArnaldo Carvalho de Melo static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map); 36608c34deSArnaldo Carvalho de Melo static bool symbol__is_idle(const char *name); 37608c34deSArnaldo Carvalho de Melo 383f067dcaSArnaldo Carvalho de Melo int vmlinux_path__nr_entries; 393f067dcaSArnaldo Carvalho de Melo char **vmlinux_path; 40439d473bSArnaldo Carvalho de Melo 4175be6cf4SArnaldo Carvalho de Melo struct symbol_conf symbol_conf = { 42b32d133aSArnaldo Carvalho de Melo .use_modules = true, 43b32d133aSArnaldo Carvalho de Melo .try_vmlinux_path = true, 44328ccdacSNamhyung Kim .demangle = true, 45763122adSAvi Kivity .demangle_kernel = false, 46e511db5eSNamhyung Kim .cumulate_callchain = true, 47c8302367SJiri Olsa .show_hist_headers = true, 48ec5761eaSDavid Ahern .symfs = "", 491e9abf8bSNamhyung Kim .event_group = true, 50d8a88dd2SMilian Wolff .inline_name = true, 51b32d133aSArnaldo Carvalho de Melo }; 52b32d133aSArnaldo Carvalho de Melo 5344f24cb3SJiri Olsa static enum dso_binary_type binary_type_symtab[] = { 5444f24cb3SJiri Olsa DSO_BINARY_TYPE__KALLSYMS, 5544f24cb3SJiri Olsa DSO_BINARY_TYPE__GUEST_KALLSYMS, 5644f24cb3SJiri Olsa DSO_BINARY_TYPE__JAVA_JIT, 5744f24cb3SJiri Olsa DSO_BINARY_TYPE__DEBUGLINK, 5844f24cb3SJiri Olsa DSO_BINARY_TYPE__BUILD_ID_CACHE, 59d2396999SKrister Johansen DSO_BINARY_TYPE__BUILD_ID_CACHE_DEBUGINFO, 6044f24cb3SJiri Olsa DSO_BINARY_TYPE__FEDORA_DEBUGINFO, 6144f24cb3SJiri Olsa DSO_BINARY_TYPE__UBUNTU_DEBUGINFO, 6244f24cb3SJiri Olsa DSO_BINARY_TYPE__BUILDID_DEBUGINFO, 6344f24cb3SJiri Olsa DSO_BINARY_TYPE__SYSTEM_PATH_DSO, 6444f24cb3SJiri Olsa DSO_BINARY_TYPE__GUEST_KMODULE, 65c00c48fcSNamhyung Kim DSO_BINARY_TYPE__GUEST_KMODULE_COMP, 6644f24cb3SJiri Olsa DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE, 67c00c48fcSNamhyung Kim DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP, 689cd00941SRicardo Ribalda Delgado DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO, 6944f24cb3SJiri Olsa DSO_BINARY_TYPE__NOT_FOUND, 7044f24cb3SJiri Olsa }; 7144f24cb3SJiri Olsa 72028df767SJiri Olsa #define DSO_BINARY_TYPE__SYMTAB_CNT ARRAY_SIZE(binary_type_symtab) 7344f24cb3SJiri Olsa 743183f8caSArnaldo Carvalho de Melo static bool symbol_type__filter(char symbol_type) 756893d4eeSArnaldo Carvalho de Melo { 7631877908SAnton Blanchard symbol_type = toupper(symbol_type); 772be732c0SArnaldo Carvalho de Melo return symbol_type == 'T' || symbol_type == 'W' || symbol_type == 'D' || symbol_type == 'B'; 786893d4eeSArnaldo Carvalho de Melo } 796893d4eeSArnaldo Carvalho de Melo 80694bf407SAnton Blanchard static int prefix_underscores_count(const char *str) 81694bf407SAnton Blanchard { 82694bf407SAnton Blanchard const char *tail = str; 83694bf407SAnton Blanchard 84694bf407SAnton Blanchard while (*tail == '_') 85694bf407SAnton Blanchard tail++; 86694bf407SAnton Blanchard 87694bf407SAnton Blanchard return tail - str; 88694bf407SAnton Blanchard } 89694bf407SAnton Blanchard 904b3a2716SMasami Hiramatsu const char * __weak arch__normalize_symbol_name(const char *name) 914b3a2716SMasami Hiramatsu { 924b3a2716SMasami Hiramatsu return name; 934b3a2716SMasami Hiramatsu } 944b3a2716SMasami Hiramatsu 95d8040645SPaul Clarke int __weak arch__compare_symbol_names(const char *namea, const char *nameb) 96d8040645SPaul Clarke { 97d8040645SPaul Clarke return strcmp(namea, nameb); 98d8040645SPaul Clarke } 99d8040645SPaul Clarke 100d8040645SPaul Clarke int __weak arch__compare_symbol_names_n(const char *namea, const char *nameb, 101d8040645SPaul Clarke unsigned int n) 102d8040645SPaul Clarke { 103d8040645SPaul Clarke return strncmp(namea, nameb, n); 104d8040645SPaul Clarke } 105d8040645SPaul Clarke 106fb6d5942SNaveen N. Rao int __weak arch__choose_best_symbol(struct symbol *syma, 107fb6d5942SNaveen N. Rao struct symbol *symb __maybe_unused) 108fb6d5942SNaveen N. Rao { 109fb6d5942SNaveen N. Rao /* Avoid "SyS" kernel syscall aliases */ 110fb6d5942SNaveen N. Rao if (strlen(syma->name) >= 3 && !strncmp(syma->name, "SyS", 3)) 111fb6d5942SNaveen N. Rao return SYMBOL_B; 112fb6d5942SNaveen N. Rao if (strlen(syma->name) >= 10 && !strncmp(syma->name, "compat_SyS", 10)) 113fb6d5942SNaveen N. Rao return SYMBOL_B; 114fb6d5942SNaveen N. Rao 115fb6d5942SNaveen N. Rao return SYMBOL_A; 116fb6d5942SNaveen N. Rao } 117694bf407SAnton Blanchard 118694bf407SAnton Blanchard static int choose_best_symbol(struct symbol *syma, struct symbol *symb) 119694bf407SAnton Blanchard { 120694bf407SAnton Blanchard s64 a; 121694bf407SAnton Blanchard s64 b; 1223445432bSAdrian Hunter size_t na, nb; 123694bf407SAnton Blanchard 124694bf407SAnton Blanchard /* Prefer a symbol with non zero length */ 125694bf407SAnton Blanchard a = syma->end - syma->start; 126694bf407SAnton Blanchard b = symb->end - symb->start; 127694bf407SAnton Blanchard if ((b == 0) && (a > 0)) 128694bf407SAnton Blanchard return SYMBOL_A; 129694bf407SAnton Blanchard else if ((a == 0) && (b > 0)) 130694bf407SAnton Blanchard return SYMBOL_B; 131694bf407SAnton Blanchard 132694bf407SAnton Blanchard /* Prefer a non weak symbol over a weak one */ 133694bf407SAnton Blanchard a = syma->binding == STB_WEAK; 134694bf407SAnton Blanchard b = symb->binding == STB_WEAK; 135694bf407SAnton Blanchard if (b && !a) 136694bf407SAnton Blanchard return SYMBOL_A; 137694bf407SAnton Blanchard if (a && !b) 138694bf407SAnton Blanchard return SYMBOL_B; 139694bf407SAnton Blanchard 140694bf407SAnton Blanchard /* Prefer a global symbol over a non global one */ 141694bf407SAnton Blanchard a = syma->binding == STB_GLOBAL; 142694bf407SAnton Blanchard b = symb->binding == STB_GLOBAL; 143694bf407SAnton Blanchard if (a && !b) 144694bf407SAnton Blanchard return SYMBOL_A; 145694bf407SAnton Blanchard if (b && !a) 146694bf407SAnton Blanchard return SYMBOL_B; 147694bf407SAnton Blanchard 148694bf407SAnton Blanchard /* Prefer a symbol with less underscores */ 149694bf407SAnton Blanchard a = prefix_underscores_count(syma->name); 150694bf407SAnton Blanchard b = prefix_underscores_count(symb->name); 151694bf407SAnton Blanchard if (b > a) 152694bf407SAnton Blanchard return SYMBOL_A; 153694bf407SAnton Blanchard else if (a > b) 154694bf407SAnton Blanchard return SYMBOL_B; 155694bf407SAnton Blanchard 1563445432bSAdrian Hunter /* Choose the symbol with the longest name */ 1573445432bSAdrian Hunter na = strlen(syma->name); 1583445432bSAdrian Hunter nb = strlen(symb->name); 1593445432bSAdrian Hunter if (na > nb) 160694bf407SAnton Blanchard return SYMBOL_A; 1613445432bSAdrian Hunter else if (na < nb) 162694bf407SAnton Blanchard return SYMBOL_B; 1633445432bSAdrian Hunter 164fb6d5942SNaveen N. Rao return arch__choose_best_symbol(syma, symb); 165694bf407SAnton Blanchard } 166694bf407SAnton Blanchard 1677137ff50SDavidlohr Bueso void symbols__fixup_duplicate(struct rb_root_cached *symbols) 168694bf407SAnton Blanchard { 169694bf407SAnton Blanchard struct rb_node *nd; 170694bf407SAnton Blanchard struct symbol *curr, *next; 171694bf407SAnton Blanchard 172c97b40e4SArnaldo Carvalho de Melo if (symbol_conf.allow_aliases) 173c97b40e4SArnaldo Carvalho de Melo return; 174c97b40e4SArnaldo Carvalho de Melo 1757137ff50SDavidlohr Bueso nd = rb_first_cached(symbols); 176694bf407SAnton Blanchard 177694bf407SAnton Blanchard while (nd) { 178694bf407SAnton Blanchard curr = rb_entry(nd, struct symbol, rb_node); 179694bf407SAnton Blanchard again: 180694bf407SAnton Blanchard nd = rb_next(&curr->rb_node); 181694bf407SAnton Blanchard next = rb_entry(nd, struct symbol, rb_node); 182694bf407SAnton Blanchard 183694bf407SAnton Blanchard if (!nd) 184694bf407SAnton Blanchard break; 185694bf407SAnton Blanchard 186694bf407SAnton Blanchard if (curr->start != next->start) 187694bf407SAnton Blanchard continue; 188694bf407SAnton Blanchard 189694bf407SAnton Blanchard if (choose_best_symbol(curr, next) == SYMBOL_A) { 1907137ff50SDavidlohr Bueso rb_erase_cached(&next->rb_node, symbols); 191d4f74eb8SChenggang Qin symbol__delete(next); 192694bf407SAnton Blanchard goto again; 193694bf407SAnton Blanchard } else { 194694bf407SAnton Blanchard nd = rb_next(&curr->rb_node); 1957137ff50SDavidlohr Bueso rb_erase_cached(&curr->rb_node, symbols); 196d4f74eb8SChenggang Qin symbol__delete(curr); 197694bf407SAnton Blanchard } 198694bf407SAnton Blanchard } 199694bf407SAnton Blanchard } 200694bf407SAnton Blanchard 2017137ff50SDavidlohr Bueso void symbols__fixup_end(struct rb_root_cached *symbols) 202af427bf5SArnaldo Carvalho de Melo { 2037137ff50SDavidlohr Bueso struct rb_node *nd, *prevnd = rb_first_cached(symbols); 2042e538c4aSArnaldo Carvalho de Melo struct symbol *curr, *prev; 205af427bf5SArnaldo Carvalho de Melo 206af427bf5SArnaldo Carvalho de Melo if (prevnd == NULL) 207af427bf5SArnaldo Carvalho de Melo return; 208af427bf5SArnaldo Carvalho de Melo 2092e538c4aSArnaldo Carvalho de Melo curr = rb_entry(prevnd, struct symbol, rb_node); 2102e538c4aSArnaldo Carvalho de Melo 211af427bf5SArnaldo Carvalho de Melo for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) { 2122e538c4aSArnaldo Carvalho de Melo prev = curr; 2132e538c4aSArnaldo Carvalho de Melo curr = rb_entry(nd, struct symbol, rb_node); 214af427bf5SArnaldo Carvalho de Melo 2153b01a413SArnaldo Carvalho de Melo if (prev->end == prev->start && prev->end != curr->start) 2162c241bd3SArnaldo Carvalho de Melo prev->end = curr->start; 217af427bf5SArnaldo Carvalho de Melo } 218af427bf5SArnaldo Carvalho de Melo 2192e538c4aSArnaldo Carvalho de Melo /* Last entry */ 2202e538c4aSArnaldo Carvalho de Melo if (curr->end == curr->start) 221e7ede72aSDaniel Borkmann curr->end = roundup(curr->start, 4096) + 4096; 2222e538c4aSArnaldo Carvalho de Melo } 2232e538c4aSArnaldo Carvalho de Melo 2243183f8caSArnaldo Carvalho de Melo void map_groups__fixup_end(struct map_groups *mg) 225af427bf5SArnaldo Carvalho de Melo { 2263183f8caSArnaldo Carvalho de Melo struct maps *maps = &mg->maps; 2274bb7123dSArnaldo Carvalho de Melo struct map *next, *curr; 228af427bf5SArnaldo Carvalho de Melo 2290a7c74eaSArnaldo Carvalho de Melo down_write(&maps->lock); 2306a2ffcddSArnaldo Carvalho de Melo 2314bb7123dSArnaldo Carvalho de Melo curr = maps__first(maps); 2324bb7123dSArnaldo Carvalho de Melo if (curr == NULL) 2336a2ffcddSArnaldo Carvalho de Melo goto out_unlock; 234af427bf5SArnaldo Carvalho de Melo 2354bb7123dSArnaldo Carvalho de Melo for (next = map__next(curr); next; next = map__next(curr)) { 2369ad4652bSThomas Richter if (!curr->end) 2374bb7123dSArnaldo Carvalho de Melo curr->end = next->start; 2384bb7123dSArnaldo Carvalho de Melo curr = next; 2392e538c4aSArnaldo Carvalho de Melo } 24090c83218SArnaldo Carvalho de Melo 24190c83218SArnaldo Carvalho de Melo /* 24290c83218SArnaldo Carvalho de Melo * We still haven't the actual symbols, so guess the 24390c83218SArnaldo Carvalho de Melo * last map final address. 24490c83218SArnaldo Carvalho de Melo */ 2459ad4652bSThomas Richter if (!curr->end) 2469d1faba5SIan Munsie curr->end = ~0ULL; 2476a2ffcddSArnaldo Carvalho de Melo 2486a2ffcddSArnaldo Carvalho de Melo out_unlock: 2490a7c74eaSArnaldo Carvalho de Melo up_write(&maps->lock); 250af427bf5SArnaldo Carvalho de Melo } 251af427bf5SArnaldo Carvalho de Melo 252af30bffaSArnaldo Carvalho de Melo struct symbol *symbol__new(u64 start, u64 len, u8 binding, u8 type, const char *name) 25386470930SIngo Molnar { 25486470930SIngo Molnar size_t namelen = strlen(name) + 1; 255aeafcbafSArnaldo Carvalho de Melo struct symbol *sym = calloc(1, (symbol_conf.priv_size + 256aeafcbafSArnaldo Carvalho de Melo sizeof(*sym) + namelen)); 257aeafcbafSArnaldo Carvalho de Melo if (sym == NULL) 25886470930SIngo Molnar return NULL; 25986470930SIngo Molnar 260b01141f4SArnaldo Carvalho de Melo if (symbol_conf.priv_size) { 261b01141f4SArnaldo Carvalho de Melo if (symbol_conf.init_annotation) { 262b01141f4SArnaldo Carvalho de Melo struct annotation *notes = (void *)sym; 263b01141f4SArnaldo Carvalho de Melo pthread_mutex_init(¬es->lock, NULL); 264b01141f4SArnaldo Carvalho de Melo } 265aeafcbafSArnaldo Carvalho de Melo sym = ((void *)sym) + symbol_conf.priv_size; 266b01141f4SArnaldo Carvalho de Melo } 26736479484SArnaldo Carvalho de Melo 268aeafcbafSArnaldo Carvalho de Melo sym->start = start; 2692c241bd3SArnaldo Carvalho de Melo sym->end = len ? start + len : start; 270af30bffaSArnaldo Carvalho de Melo sym->type = type; 271aeafcbafSArnaldo Carvalho de Melo sym->binding = binding; 272aeafcbafSArnaldo Carvalho de Melo sym->namelen = namelen - 1; 273e4204992SArnaldo Carvalho de Melo 274aeafcbafSArnaldo Carvalho de Melo pr_debug4("%s: %s %#" PRIx64 "-%#" PRIx64 "\n", 275aeafcbafSArnaldo Carvalho de Melo __func__, name, start, sym->end); 276aeafcbafSArnaldo Carvalho de Melo memcpy(sym->name, name, namelen); 277e4204992SArnaldo Carvalho de Melo 278aeafcbafSArnaldo Carvalho de Melo return sym; 27986470930SIngo Molnar } 28086470930SIngo Molnar 281aeafcbafSArnaldo Carvalho de Melo void symbol__delete(struct symbol *sym) 28286470930SIngo Molnar { 283aeafcbafSArnaldo Carvalho de Melo free(((void *)sym) - symbol_conf.priv_size); 28486470930SIngo Molnar } 28586470930SIngo Molnar 2867137ff50SDavidlohr Bueso void symbols__delete(struct rb_root_cached *symbols) 28786470930SIngo Molnar { 28886470930SIngo Molnar struct symbol *pos; 2897137ff50SDavidlohr Bueso struct rb_node *next = rb_first_cached(symbols); 29086470930SIngo Molnar 29186470930SIngo Molnar while (next) { 29286470930SIngo Molnar pos = rb_entry(next, struct symbol, rb_node); 29386470930SIngo Molnar next = rb_next(&pos->rb_node); 2947137ff50SDavidlohr Bueso rb_erase_cached(&pos->rb_node, symbols); 29500a192b3SArnaldo Carvalho de Melo symbol__delete(pos); 29686470930SIngo Molnar } 29786470930SIngo Molnar } 29886470930SIngo Molnar 2997137ff50SDavidlohr Bueso void __symbols__insert(struct rb_root_cached *symbols, 3007137ff50SDavidlohr Bueso struct symbol *sym, bool kernel) 30186470930SIngo Molnar { 3027137ff50SDavidlohr Bueso struct rb_node **p = &symbols->rb_root.rb_node; 30386470930SIngo Molnar struct rb_node *parent = NULL; 3049cffa8d5SPaul Mackerras const u64 ip = sym->start; 30586470930SIngo Molnar struct symbol *s; 3067137ff50SDavidlohr Bueso bool leftmost = true; 30786470930SIngo Molnar 308608c34deSArnaldo Carvalho de Melo if (kernel) { 309608c34deSArnaldo Carvalho de Melo const char *name = sym->name; 310608c34deSArnaldo Carvalho de Melo /* 311608c34deSArnaldo Carvalho de Melo * ppc64 uses function descriptors and appends a '.' to the 312608c34deSArnaldo Carvalho de Melo * start of every instruction address. Remove it. 313608c34deSArnaldo Carvalho de Melo */ 314608c34deSArnaldo Carvalho de Melo if (name[0] == '.') 315608c34deSArnaldo Carvalho de Melo name++; 316608c34deSArnaldo Carvalho de Melo sym->idle = symbol__is_idle(name); 317608c34deSArnaldo Carvalho de Melo } 318608c34deSArnaldo Carvalho de Melo 31986470930SIngo Molnar while (*p != NULL) { 32086470930SIngo Molnar parent = *p; 32186470930SIngo Molnar s = rb_entry(parent, struct symbol, rb_node); 32286470930SIngo Molnar if (ip < s->start) 32386470930SIngo Molnar p = &(*p)->rb_left; 3247137ff50SDavidlohr Bueso else { 32586470930SIngo Molnar p = &(*p)->rb_right; 3267137ff50SDavidlohr Bueso leftmost = false; 3277137ff50SDavidlohr Bueso } 32886470930SIngo Molnar } 32986470930SIngo Molnar rb_link_node(&sym->rb_node, parent, p); 3307137ff50SDavidlohr Bueso rb_insert_color_cached(&sym->rb_node, symbols, leftmost); 33186470930SIngo Molnar } 33286470930SIngo Molnar 3337137ff50SDavidlohr Bueso void symbols__insert(struct rb_root_cached *symbols, struct symbol *sym) 334608c34deSArnaldo Carvalho de Melo { 335608c34deSArnaldo Carvalho de Melo __symbols__insert(symbols, sym, false); 336608c34deSArnaldo Carvalho de Melo } 337608c34deSArnaldo Carvalho de Melo 3387137ff50SDavidlohr Bueso static struct symbol *symbols__find(struct rb_root_cached *symbols, u64 ip) 33986470930SIngo Molnar { 34086470930SIngo Molnar struct rb_node *n; 34186470930SIngo Molnar 342aeafcbafSArnaldo Carvalho de Melo if (symbols == NULL) 34386470930SIngo Molnar return NULL; 34486470930SIngo Molnar 3457137ff50SDavidlohr Bueso n = symbols->rb_root.rb_node; 34686470930SIngo Molnar 34786470930SIngo Molnar while (n) { 34886470930SIngo Molnar struct symbol *s = rb_entry(n, struct symbol, rb_node); 34986470930SIngo Molnar 35086470930SIngo Molnar if (ip < s->start) 35186470930SIngo Molnar n = n->rb_left; 3529c7b37cdSChris Phlipot else if (ip > s->end || (ip == s->end && ip != s->start)) 35386470930SIngo Molnar n = n->rb_right; 35486470930SIngo Molnar else 35586470930SIngo Molnar return s; 35686470930SIngo Molnar } 35786470930SIngo Molnar 35886470930SIngo Molnar return NULL; 35986470930SIngo Molnar } 36086470930SIngo Molnar 3617137ff50SDavidlohr Bueso static struct symbol *symbols__first(struct rb_root_cached *symbols) 3628e0cf965SAdrian Hunter { 3637137ff50SDavidlohr Bueso struct rb_node *n = rb_first_cached(symbols); 3648e0cf965SAdrian Hunter 3658e0cf965SAdrian Hunter if (n) 3668e0cf965SAdrian Hunter return rb_entry(n, struct symbol, rb_node); 3678e0cf965SAdrian Hunter 3688e0cf965SAdrian Hunter return NULL; 3698e0cf965SAdrian Hunter } 3708e0cf965SAdrian Hunter 3717137ff50SDavidlohr Bueso static struct symbol *symbols__last(struct rb_root_cached *symbols) 372cd67f99fSAdrian Hunter { 3737137ff50SDavidlohr Bueso struct rb_node *n = rb_last(&symbols->rb_root); 374cd67f99fSAdrian Hunter 375cd67f99fSAdrian Hunter if (n) 376cd67f99fSAdrian Hunter return rb_entry(n, struct symbol, rb_node); 377cd67f99fSAdrian Hunter 378cd67f99fSAdrian Hunter return NULL; 379cd67f99fSAdrian Hunter } 380cd67f99fSAdrian Hunter 3819c00a81bSAdrian Hunter static struct symbol *symbols__next(struct symbol *sym) 3829c00a81bSAdrian Hunter { 3839c00a81bSAdrian Hunter struct rb_node *n = rb_next(&sym->rb_node); 3849c00a81bSAdrian Hunter 3859c00a81bSAdrian Hunter if (n) 3869c00a81bSAdrian Hunter return rb_entry(n, struct symbol, rb_node); 3879c00a81bSAdrian Hunter 3889c00a81bSAdrian Hunter return NULL; 3899c00a81bSAdrian Hunter } 3909c00a81bSAdrian Hunter 3917137ff50SDavidlohr Bueso static void symbols__insert_by_name(struct rb_root_cached *symbols, struct symbol *sym) 39279406cd7SArnaldo Carvalho de Melo { 3937137ff50SDavidlohr Bueso struct rb_node **p = &symbols->rb_root.rb_node; 39479406cd7SArnaldo Carvalho de Melo struct rb_node *parent = NULL; 39502a9d037SRabin Vincent struct symbol_name_rb_node *symn, *s; 3967137ff50SDavidlohr Bueso bool leftmost = true; 39702a9d037SRabin Vincent 39802a9d037SRabin Vincent symn = container_of(sym, struct symbol_name_rb_node, sym); 39979406cd7SArnaldo Carvalho de Melo 40079406cd7SArnaldo Carvalho de Melo while (*p != NULL) { 40179406cd7SArnaldo Carvalho de Melo parent = *p; 40279406cd7SArnaldo Carvalho de Melo s = rb_entry(parent, struct symbol_name_rb_node, rb_node); 40379406cd7SArnaldo Carvalho de Melo if (strcmp(sym->name, s->sym.name) < 0) 40479406cd7SArnaldo Carvalho de Melo p = &(*p)->rb_left; 4057137ff50SDavidlohr Bueso else { 40679406cd7SArnaldo Carvalho de Melo p = &(*p)->rb_right; 4077137ff50SDavidlohr Bueso leftmost = false; 4087137ff50SDavidlohr Bueso } 40979406cd7SArnaldo Carvalho de Melo } 41079406cd7SArnaldo Carvalho de Melo rb_link_node(&symn->rb_node, parent, p); 4117137ff50SDavidlohr Bueso rb_insert_color_cached(&symn->rb_node, symbols, leftmost); 41279406cd7SArnaldo Carvalho de Melo } 41379406cd7SArnaldo Carvalho de Melo 4147137ff50SDavidlohr Bueso static void symbols__sort_by_name(struct rb_root_cached *symbols, 4157137ff50SDavidlohr Bueso struct rb_root_cached *source) 41679406cd7SArnaldo Carvalho de Melo { 41779406cd7SArnaldo Carvalho de Melo struct rb_node *nd; 41879406cd7SArnaldo Carvalho de Melo 4197137ff50SDavidlohr Bueso for (nd = rb_first_cached(source); nd; nd = rb_next(nd)) { 42079406cd7SArnaldo Carvalho de Melo struct symbol *pos = rb_entry(nd, struct symbol, rb_node); 421aeafcbafSArnaldo Carvalho de Melo symbols__insert_by_name(symbols, pos); 42279406cd7SArnaldo Carvalho de Melo } 42379406cd7SArnaldo Carvalho de Melo } 42479406cd7SArnaldo Carvalho de Melo 425d8040645SPaul Clarke int symbol__match_symbol_name(const char *name, const char *str, 426d8040645SPaul Clarke enum symbol_tag_include includes) 427d8040645SPaul Clarke { 428d8040645SPaul Clarke const char *versioning; 429d8040645SPaul Clarke 430d8040645SPaul Clarke if (includes == SYMBOL_TAG_INCLUDE__DEFAULT_ONLY && 431d8040645SPaul Clarke (versioning = strstr(name, "@@"))) { 432d8040645SPaul Clarke int len = strlen(str); 433d8040645SPaul Clarke 434d8040645SPaul Clarke if (len < versioning - name) 435d8040645SPaul Clarke len = versioning - name; 436d8040645SPaul Clarke 437d8040645SPaul Clarke return arch__compare_symbol_names_n(name, str, len); 438d8040645SPaul Clarke } else 439d8040645SPaul Clarke return arch__compare_symbol_names(name, str); 440d8040645SPaul Clarke } 441d8040645SPaul Clarke 4427137ff50SDavidlohr Bueso static struct symbol *symbols__find_by_name(struct rb_root_cached *symbols, 443d8040645SPaul Clarke const char *name, 444d8040645SPaul Clarke enum symbol_tag_include includes) 44579406cd7SArnaldo Carvalho de Melo { 44679406cd7SArnaldo Carvalho de Melo struct rb_node *n; 4475bcaaca3SMartin Liška struct symbol_name_rb_node *s = NULL; 44879406cd7SArnaldo Carvalho de Melo 449aeafcbafSArnaldo Carvalho de Melo if (symbols == NULL) 45079406cd7SArnaldo Carvalho de Melo return NULL; 45179406cd7SArnaldo Carvalho de Melo 4527137ff50SDavidlohr Bueso n = symbols->rb_root.rb_node; 45379406cd7SArnaldo Carvalho de Melo 45479406cd7SArnaldo Carvalho de Melo while (n) { 45579406cd7SArnaldo Carvalho de Melo int cmp; 45679406cd7SArnaldo Carvalho de Melo 45779406cd7SArnaldo Carvalho de Melo s = rb_entry(n, struct symbol_name_rb_node, rb_node); 458d8040645SPaul Clarke cmp = symbol__match_symbol_name(s->sym.name, name, includes); 45979406cd7SArnaldo Carvalho de Melo 460d8040645SPaul Clarke if (cmp > 0) 46179406cd7SArnaldo Carvalho de Melo n = n->rb_left; 462d8040645SPaul Clarke else if (cmp < 0) 46379406cd7SArnaldo Carvalho de Melo n = n->rb_right; 46479406cd7SArnaldo Carvalho de Melo else 465de480999SNamhyung Kim break; 46679406cd7SArnaldo Carvalho de Melo } 46779406cd7SArnaldo Carvalho de Melo 468de480999SNamhyung Kim if (n == NULL) 46979406cd7SArnaldo Carvalho de Melo return NULL; 470de480999SNamhyung Kim 471d8040645SPaul Clarke if (includes != SYMBOL_TAG_INCLUDE__DEFAULT_ONLY) 472de480999SNamhyung Kim /* return first symbol that has same name (if any) */ 473de480999SNamhyung Kim for (n = rb_prev(n); n; n = rb_prev(n)) { 474de480999SNamhyung Kim struct symbol_name_rb_node *tmp; 475de480999SNamhyung Kim 476de480999SNamhyung Kim tmp = rb_entry(n, struct symbol_name_rb_node, rb_node); 477031b84c4SNaveen N. Rao if (arch__compare_symbol_names(tmp->sym.name, s->sym.name)) 478de480999SNamhyung Kim break; 479de480999SNamhyung Kim 480de480999SNamhyung Kim s = tmp; 481de480999SNamhyung Kim } 482de480999SNamhyung Kim 483de480999SNamhyung Kim return &s->sym; 48479406cd7SArnaldo Carvalho de Melo } 48579406cd7SArnaldo Carvalho de Melo 486c0b4dffbSArnaldo Carvalho de Melo void dso__reset_find_symbol_cache(struct dso *dso) 487c0b4dffbSArnaldo Carvalho de Melo { 4883183f8caSArnaldo Carvalho de Melo dso->last_find_result.addr = 0; 4893183f8caSArnaldo Carvalho de Melo dso->last_find_result.symbol = NULL; 490c0b4dffbSArnaldo Carvalho de Melo } 491c0b4dffbSArnaldo Carvalho de Melo 4923183f8caSArnaldo Carvalho de Melo void dso__insert_symbol(struct dso *dso, struct symbol *sym) 493ae93a6c7SChris Phlipot { 4943183f8caSArnaldo Carvalho de Melo __symbols__insert(&dso->symbols, sym, dso->kernel); 495ae93a6c7SChris Phlipot 496ae93a6c7SChris Phlipot /* update the symbol cache if necessary */ 4973183f8caSArnaldo Carvalho de Melo if (dso->last_find_result.addr >= sym->start && 4983183f8caSArnaldo Carvalho de Melo (dso->last_find_result.addr < sym->end || 499ae93a6c7SChris Phlipot sym->start == sym->end)) { 5003183f8caSArnaldo Carvalho de Melo dso->last_find_result.symbol = sym; 501ae93a6c7SChris Phlipot } 502ae93a6c7SChris Phlipot } 503ae93a6c7SChris Phlipot 5043183f8caSArnaldo Carvalho de Melo struct symbol *dso__find_symbol(struct dso *dso, u64 addr) 505fcf1203aSArnaldo Carvalho de Melo { 5063183f8caSArnaldo Carvalho de Melo if (dso->last_find_result.addr != addr || dso->last_find_result.symbol == NULL) { 5073183f8caSArnaldo Carvalho de Melo dso->last_find_result.addr = addr; 5083183f8caSArnaldo Carvalho de Melo dso->last_find_result.symbol = symbols__find(&dso->symbols, addr); 509b685ac22SArnaldo Carvalho de Melo } 510b685ac22SArnaldo Carvalho de Melo 5113183f8caSArnaldo Carvalho de Melo return dso->last_find_result.symbol; 5128e0cf965SAdrian Hunter } 5138e0cf965SAdrian Hunter 5145cf88a63SArnaldo Carvalho de Melo struct symbol *dso__first_symbol(struct dso *dso) 5155cf88a63SArnaldo Carvalho de Melo { 5163183f8caSArnaldo Carvalho de Melo return symbols__first(&dso->symbols); 517cd67f99fSAdrian Hunter } 518cd67f99fSAdrian Hunter 5195cf88a63SArnaldo Carvalho de Melo struct symbol *dso__last_symbol(struct dso *dso) 5205cf88a63SArnaldo Carvalho de Melo { 5213183f8caSArnaldo Carvalho de Melo return symbols__last(&dso->symbols); 5225cf88a63SArnaldo Carvalho de Melo } 5235cf88a63SArnaldo Carvalho de Melo 5249c00a81bSAdrian Hunter struct symbol *dso__next_symbol(struct symbol *sym) 5259c00a81bSAdrian Hunter { 5269c00a81bSAdrian Hunter return symbols__next(sym); 5279c00a81bSAdrian Hunter } 5289c00a81bSAdrian Hunter 52918bd7264SArnaldo Carvalho de Melo struct symbol *symbol__next_by_name(struct symbol *sym) 53018bd7264SArnaldo Carvalho de Melo { 53118bd7264SArnaldo Carvalho de Melo struct symbol_name_rb_node *s = container_of(sym, struct symbol_name_rb_node, sym); 53218bd7264SArnaldo Carvalho de Melo struct rb_node *n = rb_next(&s->rb_node); 53318bd7264SArnaldo Carvalho de Melo 53418bd7264SArnaldo Carvalho de Melo return n ? &rb_entry(n, struct symbol_name_rb_node, rb_node)->sym : NULL; 53518bd7264SArnaldo Carvalho de Melo } 53618bd7264SArnaldo Carvalho de Melo 53718bd7264SArnaldo Carvalho de Melo /* 538af07eeb0SArnaldo Carvalho de Melo * Returns first symbol that matched with @name. 53918bd7264SArnaldo Carvalho de Melo */ 5403183f8caSArnaldo Carvalho de Melo struct symbol *dso__find_symbol_by_name(struct dso *dso, const char *name) 54179406cd7SArnaldo Carvalho de Melo { 5423183f8caSArnaldo Carvalho de Melo struct symbol *s = symbols__find_by_name(&dso->symbol_names, name, 543d8040645SPaul Clarke SYMBOL_TAG_INCLUDE__NONE); 544d8040645SPaul Clarke if (!s) 5453183f8caSArnaldo Carvalho de Melo s = symbols__find_by_name(&dso->symbol_names, name, 546d8040645SPaul Clarke SYMBOL_TAG_INCLUDE__DEFAULT_ONLY); 547d8040645SPaul Clarke return s; 54879406cd7SArnaldo Carvalho de Melo } 54979406cd7SArnaldo Carvalho de Melo 5503183f8caSArnaldo Carvalho de Melo void dso__sort_by_name(struct dso *dso) 55179406cd7SArnaldo Carvalho de Melo { 5523183f8caSArnaldo Carvalho de Melo dso__set_sorted_by_name(dso); 5533183f8caSArnaldo Carvalho de Melo return symbols__sort_by_name(&dso->symbol_names, &dso->symbols); 55479406cd7SArnaldo Carvalho de Melo } 55579406cd7SArnaldo Carvalho de Melo 556316d70d6SAdrian Hunter int modules__parse(const char *filename, void *arg, 557316d70d6SAdrian Hunter int (*process_module)(void *arg, const char *name, 5589ad4652bSThomas Richter u64 start, u64 size)) 559316d70d6SAdrian Hunter { 560316d70d6SAdrian Hunter char *line = NULL; 561316d70d6SAdrian Hunter size_t n; 562316d70d6SAdrian Hunter FILE *file; 563316d70d6SAdrian Hunter int err = 0; 564316d70d6SAdrian Hunter 565316d70d6SAdrian Hunter file = fopen(filename, "r"); 566316d70d6SAdrian Hunter if (file == NULL) 567316d70d6SAdrian Hunter return -1; 568316d70d6SAdrian Hunter 569316d70d6SAdrian Hunter while (1) { 570316d70d6SAdrian Hunter char name[PATH_MAX]; 5719ad4652bSThomas Richter u64 start, size; 5729ad4652bSThomas Richter char *sep, *endptr; 573316d70d6SAdrian Hunter ssize_t line_len; 574316d70d6SAdrian Hunter 575316d70d6SAdrian Hunter line_len = getline(&line, &n, file); 576316d70d6SAdrian Hunter if (line_len < 0) { 577316d70d6SAdrian Hunter if (feof(file)) 578316d70d6SAdrian Hunter break; 579316d70d6SAdrian Hunter err = -1; 580316d70d6SAdrian Hunter goto out; 581316d70d6SAdrian Hunter } 582316d70d6SAdrian Hunter 583316d70d6SAdrian Hunter if (!line) { 584316d70d6SAdrian Hunter err = -1; 585316d70d6SAdrian Hunter goto out; 586316d70d6SAdrian Hunter } 587316d70d6SAdrian Hunter 588316d70d6SAdrian Hunter line[--line_len] = '\0'; /* \n */ 589316d70d6SAdrian Hunter 590316d70d6SAdrian Hunter sep = strrchr(line, 'x'); 591316d70d6SAdrian Hunter if (sep == NULL) 592316d70d6SAdrian Hunter continue; 593316d70d6SAdrian Hunter 594316d70d6SAdrian Hunter hex2u64(sep + 1, &start); 595316d70d6SAdrian Hunter 596316d70d6SAdrian Hunter sep = strchr(line, ' '); 597316d70d6SAdrian Hunter if (sep == NULL) 598316d70d6SAdrian Hunter continue; 599316d70d6SAdrian Hunter 600316d70d6SAdrian Hunter *sep = '\0'; 601316d70d6SAdrian Hunter 602316d70d6SAdrian Hunter scnprintf(name, sizeof(name), "[%s]", line); 603316d70d6SAdrian Hunter 6049ad4652bSThomas Richter size = strtoul(sep + 1, &endptr, 0); 6059ad4652bSThomas Richter if (*endptr != ' ' && *endptr != '\t') 6069ad4652bSThomas Richter continue; 6079ad4652bSThomas Richter 6089ad4652bSThomas Richter err = process_module(arg, name, start, size); 609316d70d6SAdrian Hunter if (err) 610316d70d6SAdrian Hunter break; 611316d70d6SAdrian Hunter } 612316d70d6SAdrian Hunter out: 613316d70d6SAdrian Hunter free(line); 614316d70d6SAdrian Hunter fclose(file); 615316d70d6SAdrian Hunter return err; 616316d70d6SAdrian Hunter } 617316d70d6SAdrian Hunter 618e7110b9fSArnaldo Carvalho de Melo /* 619e7110b9fSArnaldo Carvalho de Melo * These are symbols in the kernel image, so make sure that 620e7110b9fSArnaldo Carvalho de Melo * sym is from a kernel DSO. 621e7110b9fSArnaldo Carvalho de Melo */ 622608c34deSArnaldo Carvalho de Melo static bool symbol__is_idle(const char *name) 62382d1deb0SDavid Ahern { 62482d1deb0SDavid Ahern const char * const idle_symbols[] = { 625549aff77SArnaldo Carvalho de Melo "arch_cpu_idle", 62682d1deb0SDavid Ahern "cpu_idle", 627e0336ed6SArnaldo Carvalho de Melo "cpu_startup_entry", 62882d1deb0SDavid Ahern "intel_idle", 62982d1deb0SDavid Ahern "default_idle", 63082d1deb0SDavid Ahern "native_safe_halt", 63182d1deb0SDavid Ahern "enter_idle", 63282d1deb0SDavid Ahern "exit_idle", 63382d1deb0SDavid Ahern "mwait_idle", 63482d1deb0SDavid Ahern "mwait_idle_with_hints", 63582d1deb0SDavid Ahern "poll_idle", 63682d1deb0SDavid Ahern "ppc64_runlatch_off", 63782d1deb0SDavid Ahern "pseries_dedicated_idle_sleep", 63882d1deb0SDavid Ahern NULL 63982d1deb0SDavid Ahern }; 64082d1deb0SDavid Ahern int i; 64182d1deb0SDavid Ahern 64282d1deb0SDavid Ahern for (i = 0; idle_symbols[i]; i++) { 643608c34deSArnaldo Carvalho de Melo if (!strcmp(idle_symbols[i], name)) 64482d1deb0SDavid Ahern return true; 64582d1deb0SDavid Ahern } 64682d1deb0SDavid Ahern 64782d1deb0SDavid Ahern return false; 64882d1deb0SDavid Ahern } 64982d1deb0SDavid Ahern 650682b335aSArnaldo Carvalho de Melo static int map__process_kallsym_symbol(void *arg, const char *name, 65182151520SCody P Schafer char type, u64 start) 652682b335aSArnaldo Carvalho de Melo { 653682b335aSArnaldo Carvalho de Melo struct symbol *sym; 654333cc76cSArnaldo Carvalho de Melo struct dso *dso = arg; 6557137ff50SDavidlohr Bueso struct rb_root_cached *root = &dso->symbols; 656682b335aSArnaldo Carvalho de Melo 6573183f8caSArnaldo Carvalho de Melo if (!symbol_type__filter(type)) 658682b335aSArnaldo Carvalho de Melo return 0; 659682b335aSArnaldo Carvalho de Melo 66082151520SCody P Schafer /* 66182151520SCody P Schafer * module symbols are not sorted so we add all 66282151520SCody P Schafer * symbols, setting length to 0, and rely on 66382151520SCody P Schafer * symbols__fixup_end() to fix it up. 66482151520SCody P Schafer */ 665af30bffaSArnaldo Carvalho de Melo sym = symbol__new(start, 0, kallsyms2elf_binding(type), kallsyms2elf_type(type), name); 6662e538c4aSArnaldo Carvalho de Melo if (sym == NULL) 667682b335aSArnaldo Carvalho de Melo return -ENOMEM; 66882164161SArnaldo Carvalho de Melo /* 66982164161SArnaldo Carvalho de Melo * We will pass the symbols to the filter later, in 6704e06255fSArnaldo Carvalho de Melo * map__split_kallsyms, when we have split the maps per module 67182164161SArnaldo Carvalho de Melo */ 672608c34deSArnaldo Carvalho de Melo __symbols__insert(root, sym, !strchr(name, '[')); 673a1645ce1SZhang, Yanmin 674682b335aSArnaldo Carvalho de Melo return 0; 6752e538c4aSArnaldo Carvalho de Melo } 6762e538c4aSArnaldo Carvalho de Melo 677682b335aSArnaldo Carvalho de Melo /* 678682b335aSArnaldo Carvalho de Melo * Loads the function entries in /proc/kallsyms into kernel_map->dso, 679682b335aSArnaldo Carvalho de Melo * so that we can in the next step set the symbol ->end address and then 680682b335aSArnaldo Carvalho de Melo * call kernel_maps__split_kallsyms. 681682b335aSArnaldo Carvalho de Melo */ 682333cc76cSArnaldo Carvalho de Melo static int dso__load_all_kallsyms(struct dso *dso, const char *filename) 683682b335aSArnaldo Carvalho de Melo { 684333cc76cSArnaldo Carvalho de Melo return kallsyms__parse(filename, dso, map__process_kallsym_symbol); 6852e538c4aSArnaldo Carvalho de Melo } 6862e538c4aSArnaldo Carvalho de Melo 68715e0e2d4SArnaldo Carvalho de Melo static int map_groups__split_kallsyms_for_kcore(struct map_groups *kmaps, struct dso *dso) 6888e0cf965SAdrian Hunter { 6898e0cf965SAdrian Hunter struct map *curr_map; 6908e0cf965SAdrian Hunter struct symbol *pos; 691866548ddSAdrian Hunter int count = 0; 6927137ff50SDavidlohr Bueso struct rb_root_cached old_root = dso->symbols; 6937137ff50SDavidlohr Bueso struct rb_root_cached *root = &dso->symbols; 6947137ff50SDavidlohr Bueso struct rb_node *next = rb_first_cached(root); 6958e0cf965SAdrian Hunter 696ba92732eSWang Nan if (!kmaps) 697ba92732eSWang Nan return -1; 698ba92732eSWang Nan 6997137ff50SDavidlohr Bueso *root = RB_ROOT_CACHED; 700866548ddSAdrian Hunter 7018e0cf965SAdrian Hunter while (next) { 7028e0cf965SAdrian Hunter char *module; 7038e0cf965SAdrian Hunter 7048e0cf965SAdrian Hunter pos = rb_entry(next, struct symbol, rb_node); 7058e0cf965SAdrian Hunter next = rb_next(&pos->rb_node); 7068e0cf965SAdrian Hunter 7077137ff50SDavidlohr Bueso rb_erase_cached(&pos->rb_node, &old_root); 7087137ff50SDavidlohr Bueso RB_CLEAR_NODE(&pos->rb_node); 7098e0cf965SAdrian Hunter module = strchr(pos->name, '\t'); 7108e0cf965SAdrian Hunter if (module) 7118e0cf965SAdrian Hunter *module = '\0'; 7128e0cf965SAdrian Hunter 7133183f8caSArnaldo Carvalho de Melo curr_map = map_groups__find(kmaps, pos->start); 7148e0cf965SAdrian Hunter 715be39db9fSArnaldo Carvalho de Melo if (!curr_map) { 7168e0cf965SAdrian Hunter symbol__delete(pos); 717866548ddSAdrian Hunter continue; 718866548ddSAdrian Hunter } 719866548ddSAdrian Hunter 7208e0cf965SAdrian Hunter pos->start -= curr_map->start - curr_map->pgoff; 721*d6d45745SAdrian Hunter if (pos->end > curr_map->end) 722*d6d45745SAdrian Hunter pos->end = curr_map->end; 7238e0cf965SAdrian Hunter if (pos->end) 7248e0cf965SAdrian Hunter pos->end -= curr_map->start - curr_map->pgoff; 7253183f8caSArnaldo Carvalho de Melo symbols__insert(&curr_map->dso->symbols, pos); 7268e0cf965SAdrian Hunter ++count; 7278e0cf965SAdrian Hunter } 7288e0cf965SAdrian Hunter 7298e0cf965SAdrian Hunter /* Symbols have been adjusted */ 7308e0cf965SAdrian Hunter dso->adjust_symbols = 1; 7318e0cf965SAdrian Hunter 732866548ddSAdrian Hunter return count; 7338e0cf965SAdrian Hunter } 7348e0cf965SAdrian Hunter 7352e538c4aSArnaldo Carvalho de Melo /* 7362e538c4aSArnaldo Carvalho de Melo * Split the symbols into maps, making sure there are no overlaps, i.e. the 7372e538c4aSArnaldo Carvalho de Melo * kernel range is broken in several maps, named [kernel].N, as we don't have 7382e538c4aSArnaldo Carvalho de Melo * the original ELF section names vmlinux have. 7392e538c4aSArnaldo Carvalho de Melo */ 74015e0e2d4SArnaldo Carvalho de Melo static int map_groups__split_kallsyms(struct map_groups *kmaps, struct dso *dso, u64 delta, 74115e0e2d4SArnaldo Carvalho de Melo struct map *initial_map) 7422e538c4aSArnaldo Carvalho de Melo { 743ba92732eSWang Nan struct machine *machine; 74415e0e2d4SArnaldo Carvalho de Melo struct map *curr_map = initial_map; 7452e538c4aSArnaldo Carvalho de Melo struct symbol *pos; 7468a953312SArnaldo Carvalho de Melo int count = 0, moved = 0; 7477137ff50SDavidlohr Bueso struct rb_root_cached *root = &dso->symbols; 7487137ff50SDavidlohr Bueso struct rb_node *next = rb_first_cached(root); 7492e538c4aSArnaldo Carvalho de Melo int kernel_range = 0; 7504d004365SAdrian Hunter bool x86_64; 7512e538c4aSArnaldo Carvalho de Melo 752ba92732eSWang Nan if (!kmaps) 753ba92732eSWang Nan return -1; 754ba92732eSWang Nan 755ba92732eSWang Nan machine = kmaps->machine; 756ba92732eSWang Nan 7574d004365SAdrian Hunter x86_64 = machine__is(machine, "x86_64"); 7584d004365SAdrian Hunter 7592e538c4aSArnaldo Carvalho de Melo while (next) { 7602e538c4aSArnaldo Carvalho de Melo char *module; 7612e538c4aSArnaldo Carvalho de Melo 7622e538c4aSArnaldo Carvalho de Melo pos = rb_entry(next, struct symbol, rb_node); 7632e538c4aSArnaldo Carvalho de Melo next = rb_next(&pos->rb_node); 7642e538c4aSArnaldo Carvalho de Melo 7652e538c4aSArnaldo Carvalho de Melo module = strchr(pos->name, '\t'); 7662e538c4aSArnaldo Carvalho de Melo if (module) { 76775be6cf4SArnaldo Carvalho de Melo if (!symbol_conf.use_modules) 7681de8e245SArnaldo Carvalho de Melo goto discard_symbol; 7691de8e245SArnaldo Carvalho de Melo 7702e538c4aSArnaldo Carvalho de Melo *module++ = '\0'; 7712e538c4aSArnaldo Carvalho de Melo 772b7cece76SArnaldo Carvalho de Melo if (strcmp(curr_map->dso->short_name, module)) { 77315e0e2d4SArnaldo Carvalho de Melo if (curr_map != initial_map && 774aeafcbafSArnaldo Carvalho de Melo dso->kernel == DSO_TYPE_GUEST_KERNEL && 77523346f21SArnaldo Carvalho de Melo machine__is_default_guest(machine)) { 776a1645ce1SZhang, Yanmin /* 777a1645ce1SZhang, Yanmin * We assume all symbols of a module are 778a1645ce1SZhang, Yanmin * continuous in * kallsyms, so curr_map 779a1645ce1SZhang, Yanmin * points to a module and all its 780a1645ce1SZhang, Yanmin * symbols are in its kmap. Mark it as 781a1645ce1SZhang, Yanmin * loaded. 782a1645ce1SZhang, Yanmin */ 7833183f8caSArnaldo Carvalho de Melo dso__set_loaded(curr_map->dso); 784af427bf5SArnaldo Carvalho de Melo } 785b7cece76SArnaldo Carvalho de Melo 7863183f8caSArnaldo Carvalho de Melo curr_map = map_groups__find_by_name(kmaps, module); 787a1645ce1SZhang, Yanmin if (curr_map == NULL) { 7882f51903bSArnaldo Carvalho de Melo pr_debug("%s/proc/{kallsyms,modules} " 789a1645ce1SZhang, Yanmin "inconsistency while looking " 790a1645ce1SZhang, Yanmin "for \"%s\" module!\n", 79123346f21SArnaldo Carvalho de Melo machine->root_dir, module); 79215e0e2d4SArnaldo Carvalho de Melo curr_map = initial_map; 793a1645ce1SZhang, Yanmin goto discard_symbol; 794a1645ce1SZhang, Yanmin } 795a1645ce1SZhang, Yanmin 796a1645ce1SZhang, Yanmin if (curr_map->dso->loaded && 79723346f21SArnaldo Carvalho de Melo !machine__is_default_guest(machine)) 798b7cece76SArnaldo Carvalho de Melo goto discard_symbol; 799af427bf5SArnaldo Carvalho de Melo } 80086470930SIngo Molnar /* 8012e538c4aSArnaldo Carvalho de Melo * So that we look just like we get from .ko files, 80215e0e2d4SArnaldo Carvalho de Melo * i.e. not prelinked, relative to initial_map->start. 80386470930SIngo Molnar */ 8044e06255fSArnaldo Carvalho de Melo pos->start = curr_map->map_ip(curr_map, pos->start); 8054e06255fSArnaldo Carvalho de Melo pos->end = curr_map->map_ip(curr_map, pos->end); 8064d004365SAdrian Hunter } else if (x86_64 && is_entry_trampoline(pos->name)) { 8074d004365SAdrian Hunter /* 8084d004365SAdrian Hunter * These symbols are not needed anymore since the 8094d004365SAdrian Hunter * trampoline maps refer to the text section and it's 8104d004365SAdrian Hunter * symbols instead. Avoid having to deal with 8114d004365SAdrian Hunter * relocations, and the assumption that the first symbol 8124d004365SAdrian Hunter * is the start of kernel text, by simply removing the 8134d004365SAdrian Hunter * symbols at this point. 8144d004365SAdrian Hunter */ 8154d004365SAdrian Hunter goto discard_symbol; 81615e0e2d4SArnaldo Carvalho de Melo } else if (curr_map != initial_map) { 8172e538c4aSArnaldo Carvalho de Melo char dso_name[PATH_MAX]; 818aeafcbafSArnaldo Carvalho de Melo struct dso *ndso; 81986470930SIngo Molnar 820d9b62abaSAdrian Hunter if (delta) { 821d9b62abaSAdrian Hunter /* Kernel was relocated at boot time */ 822d9b62abaSAdrian Hunter pos->start -= delta; 823d9b62abaSAdrian Hunter pos->end -= delta; 824d9b62abaSAdrian Hunter } 825d9b62abaSAdrian Hunter 8268a953312SArnaldo Carvalho de Melo if (count == 0) { 82715e0e2d4SArnaldo Carvalho de Melo curr_map = initial_map; 828be39db9fSArnaldo Carvalho de Melo goto add_symbol; 8298a953312SArnaldo Carvalho de Melo } 8308a953312SArnaldo Carvalho de Melo 831aeafcbafSArnaldo Carvalho de Melo if (dso->kernel == DSO_TYPE_GUEST_KERNEL) 832a1645ce1SZhang, Yanmin snprintf(dso_name, sizeof(dso_name), 833a1645ce1SZhang, Yanmin "[guest.kernel].%d", 834a1645ce1SZhang, Yanmin kernel_range++); 835a1645ce1SZhang, Yanmin else 836a1645ce1SZhang, Yanmin snprintf(dso_name, sizeof(dso_name), 837a1645ce1SZhang, Yanmin "[kernel].%d", 8382e538c4aSArnaldo Carvalho de Melo kernel_range++); 83986470930SIngo Molnar 840aeafcbafSArnaldo Carvalho de Melo ndso = dso__new(dso_name); 841aeafcbafSArnaldo Carvalho de Melo if (ndso == NULL) 8422e538c4aSArnaldo Carvalho de Melo return -1; 8432e538c4aSArnaldo Carvalho de Melo 844aeafcbafSArnaldo Carvalho de Melo ndso->kernel = dso->kernel; 845a1645ce1SZhang, Yanmin 8463183f8caSArnaldo Carvalho de Melo curr_map = map__new2(pos->start, ndso); 84737fe5fcbSZhang, Yanmin if (curr_map == NULL) { 848d3a7c489SArnaldo Carvalho de Melo dso__put(ndso); 8492e538c4aSArnaldo Carvalho de Melo return -1; 8502e538c4aSArnaldo Carvalho de Melo } 8512e538c4aSArnaldo Carvalho de Melo 8524e06255fSArnaldo Carvalho de Melo curr_map->map_ip = curr_map->unmap_ip = identity__map_ip; 8539de89fe7SArnaldo Carvalho de Melo map_groups__insert(kmaps, curr_map); 8542e538c4aSArnaldo Carvalho de Melo ++kernel_range; 855d9b62abaSAdrian Hunter } else if (delta) { 856d9b62abaSAdrian Hunter /* Kernel was relocated at boot time */ 857d9b62abaSAdrian Hunter pos->start -= delta; 858d9b62abaSAdrian Hunter pos->end -= delta; 8592e538c4aSArnaldo Carvalho de Melo } 860be39db9fSArnaldo Carvalho de Melo add_symbol: 86115e0e2d4SArnaldo Carvalho de Melo if (curr_map != initial_map) { 8627137ff50SDavidlohr Bueso rb_erase_cached(&pos->rb_node, root); 8633183f8caSArnaldo Carvalho de Melo symbols__insert(&curr_map->dso->symbols, pos); 8648a953312SArnaldo Carvalho de Melo ++moved; 8658a953312SArnaldo Carvalho de Melo } else 8668a953312SArnaldo Carvalho de Melo ++count; 867be39db9fSArnaldo Carvalho de Melo 868be39db9fSArnaldo Carvalho de Melo continue; 869be39db9fSArnaldo Carvalho de Melo discard_symbol: 8707137ff50SDavidlohr Bueso rb_erase_cached(&pos->rb_node, root); 871be39db9fSArnaldo Carvalho de Melo symbol__delete(pos); 87286470930SIngo Molnar } 87386470930SIngo Molnar 87415e0e2d4SArnaldo Carvalho de Melo if (curr_map != initial_map && 875aeafcbafSArnaldo Carvalho de Melo dso->kernel == DSO_TYPE_GUEST_KERNEL && 87623346f21SArnaldo Carvalho de Melo machine__is_default_guest(kmaps->machine)) { 8773183f8caSArnaldo Carvalho de Melo dso__set_loaded(curr_map->dso); 878a1645ce1SZhang, Yanmin } 879a1645ce1SZhang, Yanmin 8808a953312SArnaldo Carvalho de Melo return count + moved; 88186470930SIngo Molnar } 88286470930SIngo Molnar 8833f067dcaSArnaldo Carvalho de Melo bool symbol__restricted_filename(const char *filename, 884ec80fde7SArnaldo Carvalho de Melo const char *restricted_filename) 885ec80fde7SArnaldo Carvalho de Melo { 886ec80fde7SArnaldo Carvalho de Melo bool restricted = false; 887ec80fde7SArnaldo Carvalho de Melo 888ec80fde7SArnaldo Carvalho de Melo if (symbol_conf.kptr_restrict) { 889ec80fde7SArnaldo Carvalho de Melo char *r = realpath(filename, NULL); 890ec80fde7SArnaldo Carvalho de Melo 891ec80fde7SArnaldo Carvalho de Melo if (r != NULL) { 892ec80fde7SArnaldo Carvalho de Melo restricted = strcmp(r, restricted_filename) == 0; 893ec80fde7SArnaldo Carvalho de Melo free(r); 894ec80fde7SArnaldo Carvalho de Melo return restricted; 895ec80fde7SArnaldo Carvalho de Melo } 896ec80fde7SArnaldo Carvalho de Melo } 897ec80fde7SArnaldo Carvalho de Melo 898ec80fde7SArnaldo Carvalho de Melo return restricted; 899ec80fde7SArnaldo Carvalho de Melo } 900ec80fde7SArnaldo Carvalho de Melo 90152afdaf9SAdrian Hunter struct module_info { 90252afdaf9SAdrian Hunter struct rb_node rb_node; 90352afdaf9SAdrian Hunter char *name; 90452afdaf9SAdrian Hunter u64 start; 90552afdaf9SAdrian Hunter }; 90652afdaf9SAdrian Hunter 90752afdaf9SAdrian Hunter static void add_module(struct module_info *mi, struct rb_root *modules) 90852afdaf9SAdrian Hunter { 90952afdaf9SAdrian Hunter struct rb_node **p = &modules->rb_node; 91052afdaf9SAdrian Hunter struct rb_node *parent = NULL; 91152afdaf9SAdrian Hunter struct module_info *m; 91252afdaf9SAdrian Hunter 91352afdaf9SAdrian Hunter while (*p != NULL) { 91452afdaf9SAdrian Hunter parent = *p; 91552afdaf9SAdrian Hunter m = rb_entry(parent, struct module_info, rb_node); 91652afdaf9SAdrian Hunter if (strcmp(mi->name, m->name) < 0) 91752afdaf9SAdrian Hunter p = &(*p)->rb_left; 91852afdaf9SAdrian Hunter else 91952afdaf9SAdrian Hunter p = &(*p)->rb_right; 92052afdaf9SAdrian Hunter } 92152afdaf9SAdrian Hunter rb_link_node(&mi->rb_node, parent, p); 92252afdaf9SAdrian Hunter rb_insert_color(&mi->rb_node, modules); 92352afdaf9SAdrian Hunter } 92452afdaf9SAdrian Hunter 92552afdaf9SAdrian Hunter static void delete_modules(struct rb_root *modules) 92652afdaf9SAdrian Hunter { 92752afdaf9SAdrian Hunter struct module_info *mi; 92852afdaf9SAdrian Hunter struct rb_node *next = rb_first(modules); 92952afdaf9SAdrian Hunter 93052afdaf9SAdrian Hunter while (next) { 93152afdaf9SAdrian Hunter mi = rb_entry(next, struct module_info, rb_node); 93252afdaf9SAdrian Hunter next = rb_next(&mi->rb_node); 93352afdaf9SAdrian Hunter rb_erase(&mi->rb_node, modules); 93474cf249dSArnaldo Carvalho de Melo zfree(&mi->name); 93552afdaf9SAdrian Hunter free(mi); 93652afdaf9SAdrian Hunter } 93752afdaf9SAdrian Hunter } 93852afdaf9SAdrian Hunter 93952afdaf9SAdrian Hunter static struct module_info *find_module(const char *name, 94052afdaf9SAdrian Hunter struct rb_root *modules) 94152afdaf9SAdrian Hunter { 94252afdaf9SAdrian Hunter struct rb_node *n = modules->rb_node; 94352afdaf9SAdrian Hunter 94452afdaf9SAdrian Hunter while (n) { 94552afdaf9SAdrian Hunter struct module_info *m; 94652afdaf9SAdrian Hunter int cmp; 94752afdaf9SAdrian Hunter 94852afdaf9SAdrian Hunter m = rb_entry(n, struct module_info, rb_node); 94952afdaf9SAdrian Hunter cmp = strcmp(name, m->name); 95052afdaf9SAdrian Hunter if (cmp < 0) 95152afdaf9SAdrian Hunter n = n->rb_left; 95252afdaf9SAdrian Hunter else if (cmp > 0) 95352afdaf9SAdrian Hunter n = n->rb_right; 95452afdaf9SAdrian Hunter else 95552afdaf9SAdrian Hunter return m; 95652afdaf9SAdrian Hunter } 95752afdaf9SAdrian Hunter 95852afdaf9SAdrian Hunter return NULL; 95952afdaf9SAdrian Hunter } 96052afdaf9SAdrian Hunter 9619ad4652bSThomas Richter static int __read_proc_modules(void *arg, const char *name, u64 start, 9629ad4652bSThomas Richter u64 size __maybe_unused) 96352afdaf9SAdrian Hunter { 96452afdaf9SAdrian Hunter struct rb_root *modules = arg; 96552afdaf9SAdrian Hunter struct module_info *mi; 96652afdaf9SAdrian Hunter 96752afdaf9SAdrian Hunter mi = zalloc(sizeof(struct module_info)); 96852afdaf9SAdrian Hunter if (!mi) 96952afdaf9SAdrian Hunter return -ENOMEM; 97052afdaf9SAdrian Hunter 97152afdaf9SAdrian Hunter mi->name = strdup(name); 97252afdaf9SAdrian Hunter mi->start = start; 97352afdaf9SAdrian Hunter 97452afdaf9SAdrian Hunter if (!mi->name) { 97552afdaf9SAdrian Hunter free(mi); 97652afdaf9SAdrian Hunter return -ENOMEM; 97752afdaf9SAdrian Hunter } 97852afdaf9SAdrian Hunter 97952afdaf9SAdrian Hunter add_module(mi, modules); 98052afdaf9SAdrian Hunter 98152afdaf9SAdrian Hunter return 0; 98252afdaf9SAdrian Hunter } 98352afdaf9SAdrian Hunter 98452afdaf9SAdrian Hunter static int read_proc_modules(const char *filename, struct rb_root *modules) 98552afdaf9SAdrian Hunter { 98652afdaf9SAdrian Hunter if (symbol__restricted_filename(filename, "/proc/modules")) 98752afdaf9SAdrian Hunter return -1; 98852afdaf9SAdrian Hunter 98952afdaf9SAdrian Hunter if (modules__parse(filename, modules, __read_proc_modules)) { 99052afdaf9SAdrian Hunter delete_modules(modules); 99152afdaf9SAdrian Hunter return -1; 99252afdaf9SAdrian Hunter } 99352afdaf9SAdrian Hunter 99452afdaf9SAdrian Hunter return 0; 99552afdaf9SAdrian Hunter } 99652afdaf9SAdrian Hunter 997fc1b691dSAdrian Hunter int compare_proc_modules(const char *from, const char *to) 998fc1b691dSAdrian Hunter { 999fc1b691dSAdrian Hunter struct rb_root from_modules = RB_ROOT; 1000fc1b691dSAdrian Hunter struct rb_root to_modules = RB_ROOT; 1001fc1b691dSAdrian Hunter struct rb_node *from_node, *to_node; 1002fc1b691dSAdrian Hunter struct module_info *from_m, *to_m; 1003fc1b691dSAdrian Hunter int ret = -1; 1004fc1b691dSAdrian Hunter 1005fc1b691dSAdrian Hunter if (read_proc_modules(from, &from_modules)) 1006fc1b691dSAdrian Hunter return -1; 1007fc1b691dSAdrian Hunter 1008fc1b691dSAdrian Hunter if (read_proc_modules(to, &to_modules)) 1009fc1b691dSAdrian Hunter goto out_delete_from; 1010fc1b691dSAdrian Hunter 1011fc1b691dSAdrian Hunter from_node = rb_first(&from_modules); 1012fc1b691dSAdrian Hunter to_node = rb_first(&to_modules); 1013fc1b691dSAdrian Hunter while (from_node) { 1014fc1b691dSAdrian Hunter if (!to_node) 1015fc1b691dSAdrian Hunter break; 1016fc1b691dSAdrian Hunter 1017fc1b691dSAdrian Hunter from_m = rb_entry(from_node, struct module_info, rb_node); 1018fc1b691dSAdrian Hunter to_m = rb_entry(to_node, struct module_info, rb_node); 1019fc1b691dSAdrian Hunter 1020fc1b691dSAdrian Hunter if (from_m->start != to_m->start || 1021fc1b691dSAdrian Hunter strcmp(from_m->name, to_m->name)) 1022fc1b691dSAdrian Hunter break; 1023fc1b691dSAdrian Hunter 1024fc1b691dSAdrian Hunter from_node = rb_next(from_node); 1025fc1b691dSAdrian Hunter to_node = rb_next(to_node); 1026fc1b691dSAdrian Hunter } 1027fc1b691dSAdrian Hunter 1028fc1b691dSAdrian Hunter if (!from_node && !to_node) 1029fc1b691dSAdrian Hunter ret = 0; 1030fc1b691dSAdrian Hunter 1031fc1b691dSAdrian Hunter delete_modules(&to_modules); 1032fc1b691dSAdrian Hunter out_delete_from: 1033fc1b691dSAdrian Hunter delete_modules(&from_modules); 1034fc1b691dSAdrian Hunter 1035fc1b691dSAdrian Hunter return ret; 1036fc1b691dSAdrian Hunter } 1037fc1b691dSAdrian Hunter 1038dce0478bSArnaldo Carvalho de Melo struct map *map_groups__first(struct map_groups *mg) 1039dce0478bSArnaldo Carvalho de Melo { 10403183f8caSArnaldo Carvalho de Melo return maps__first(&mg->maps); 1041dce0478bSArnaldo Carvalho de Melo } 1042dce0478bSArnaldo Carvalho de Melo 10435759a682SAdrian Hunter static int do_validate_kcore_modules(const char *filename, 104452afdaf9SAdrian Hunter struct map_groups *kmaps) 104552afdaf9SAdrian Hunter { 104652afdaf9SAdrian Hunter struct rb_root modules = RB_ROOT; 104752afdaf9SAdrian Hunter struct map *old_map; 104852afdaf9SAdrian Hunter int err; 104952afdaf9SAdrian Hunter 105052afdaf9SAdrian Hunter err = read_proc_modules(filename, &modules); 105152afdaf9SAdrian Hunter if (err) 105252afdaf9SAdrian Hunter return err; 105352afdaf9SAdrian Hunter 10543183f8caSArnaldo Carvalho de Melo old_map = map_groups__first(kmaps); 105552afdaf9SAdrian Hunter while (old_map) { 105652afdaf9SAdrian Hunter struct map *next = map_groups__next(old_map); 105752afdaf9SAdrian Hunter struct module_info *mi; 105852afdaf9SAdrian Hunter 10595759a682SAdrian Hunter if (!__map__is_kmodule(old_map)) { 106052afdaf9SAdrian Hunter old_map = next; 106152afdaf9SAdrian Hunter continue; 106252afdaf9SAdrian Hunter } 106352afdaf9SAdrian Hunter 106452afdaf9SAdrian Hunter /* Module must be in memory at the same address */ 106552afdaf9SAdrian Hunter mi = find_module(old_map->dso->short_name, &modules); 106652afdaf9SAdrian Hunter if (!mi || mi->start != old_map->start) { 106752afdaf9SAdrian Hunter err = -EINVAL; 106852afdaf9SAdrian Hunter goto out; 106952afdaf9SAdrian Hunter } 107052afdaf9SAdrian Hunter 107152afdaf9SAdrian Hunter old_map = next; 107252afdaf9SAdrian Hunter } 107352afdaf9SAdrian Hunter out: 107452afdaf9SAdrian Hunter delete_modules(&modules); 107552afdaf9SAdrian Hunter return err; 107652afdaf9SAdrian Hunter } 107752afdaf9SAdrian Hunter 107852afdaf9SAdrian Hunter /* 107952afdaf9SAdrian Hunter * If kallsyms is referenced by name then we look for filename in the same 108052afdaf9SAdrian Hunter * directory. 108152afdaf9SAdrian Hunter */ 108252afdaf9SAdrian Hunter static bool filename_from_kallsyms_filename(char *filename, 108352afdaf9SAdrian Hunter const char *base_name, 108452afdaf9SAdrian Hunter const char *kallsyms_filename) 108552afdaf9SAdrian Hunter { 108652afdaf9SAdrian Hunter char *name; 108752afdaf9SAdrian Hunter 108852afdaf9SAdrian Hunter strcpy(filename, kallsyms_filename); 108952afdaf9SAdrian Hunter name = strrchr(filename, '/'); 109052afdaf9SAdrian Hunter if (!name) 109152afdaf9SAdrian Hunter return false; 109252afdaf9SAdrian Hunter 109352afdaf9SAdrian Hunter name += 1; 109452afdaf9SAdrian Hunter 109552afdaf9SAdrian Hunter if (!strcmp(name, "kallsyms")) { 109652afdaf9SAdrian Hunter strcpy(name, base_name); 109752afdaf9SAdrian Hunter return true; 109852afdaf9SAdrian Hunter } 109952afdaf9SAdrian Hunter 110052afdaf9SAdrian Hunter return false; 110152afdaf9SAdrian Hunter } 110252afdaf9SAdrian Hunter 110352afdaf9SAdrian Hunter static int validate_kcore_modules(const char *kallsyms_filename, 110452afdaf9SAdrian Hunter struct map *map) 110552afdaf9SAdrian Hunter { 1106ba92732eSWang Nan struct map_groups *kmaps = map__kmaps(map); 110752afdaf9SAdrian Hunter char modules_filename[PATH_MAX]; 110852afdaf9SAdrian Hunter 1109ba92732eSWang Nan if (!kmaps) 1110ba92732eSWang Nan return -EINVAL; 1111ba92732eSWang Nan 111252afdaf9SAdrian Hunter if (!filename_from_kallsyms_filename(modules_filename, "modules", 111352afdaf9SAdrian Hunter kallsyms_filename)) 111452afdaf9SAdrian Hunter return -EINVAL; 111552afdaf9SAdrian Hunter 11165759a682SAdrian Hunter if (do_validate_kcore_modules(modules_filename, kmaps)) 111752afdaf9SAdrian Hunter return -EINVAL; 111852afdaf9SAdrian Hunter 111952afdaf9SAdrian Hunter return 0; 112052afdaf9SAdrian Hunter } 112152afdaf9SAdrian Hunter 1122a00d28cbSAdrian Hunter static int validate_kcore_addresses(const char *kallsyms_filename, 1123a00d28cbSAdrian Hunter struct map *map) 1124a00d28cbSAdrian Hunter { 1125a00d28cbSAdrian Hunter struct kmap *kmap = map__kmap(map); 1126a00d28cbSAdrian Hunter 1127ba92732eSWang Nan if (!kmap) 1128ba92732eSWang Nan return -EINVAL; 1129ba92732eSWang Nan 1130a00d28cbSAdrian Hunter if (kmap->ref_reloc_sym && kmap->ref_reloc_sym->name) { 1131a00d28cbSAdrian Hunter u64 start; 1132a00d28cbSAdrian Hunter 1133b843f62aSArnaldo Carvalho de Melo if (kallsyms__get_function_start(kallsyms_filename, 1134b843f62aSArnaldo Carvalho de Melo kmap->ref_reloc_sym->name, &start)) 1135b843f62aSArnaldo Carvalho de Melo return -ENOENT; 1136a00d28cbSAdrian Hunter if (start != kmap->ref_reloc_sym->addr) 1137a00d28cbSAdrian Hunter return -EINVAL; 1138a00d28cbSAdrian Hunter } 1139a00d28cbSAdrian Hunter 1140a00d28cbSAdrian Hunter return validate_kcore_modules(kallsyms_filename, map); 1141a00d28cbSAdrian Hunter } 1142a00d28cbSAdrian Hunter 11438e0cf965SAdrian Hunter struct kcore_mapfn_data { 11448e0cf965SAdrian Hunter struct dso *dso; 11458e0cf965SAdrian Hunter struct list_head maps; 11468e0cf965SAdrian Hunter }; 11478e0cf965SAdrian Hunter 11488e0cf965SAdrian Hunter static int kcore_mapfn(u64 start, u64 len, u64 pgoff, void *data) 11498e0cf965SAdrian Hunter { 11508e0cf965SAdrian Hunter struct kcore_mapfn_data *md = data; 11518e0cf965SAdrian Hunter struct map *map; 11528e0cf965SAdrian Hunter 11533183f8caSArnaldo Carvalho de Melo map = map__new2(start, md->dso); 11548e0cf965SAdrian Hunter if (map == NULL) 11558e0cf965SAdrian Hunter return -ENOMEM; 11568e0cf965SAdrian Hunter 11578e0cf965SAdrian Hunter map->end = map->start + len; 11588e0cf965SAdrian Hunter map->pgoff = pgoff; 11598e0cf965SAdrian Hunter 11608e0cf965SAdrian Hunter list_add(&map->node, &md->maps); 11618e0cf965SAdrian Hunter 11628e0cf965SAdrian Hunter return 0; 11638e0cf965SAdrian Hunter } 11648e0cf965SAdrian Hunter 11658e0cf965SAdrian Hunter static int dso__load_kcore(struct dso *dso, struct map *map, 11668e0cf965SAdrian Hunter const char *kallsyms_filename) 11678e0cf965SAdrian Hunter { 1168ba92732eSWang Nan struct map_groups *kmaps = map__kmaps(map); 11698e0cf965SAdrian Hunter struct kcore_mapfn_data md; 11708e0cf965SAdrian Hunter struct map *old_map, *new_map, *replacement_map = NULL; 11711c5aae77SAdrian Hunter struct machine *machine; 11728e0cf965SAdrian Hunter bool is_64_bit; 11738e0cf965SAdrian Hunter int err, fd; 11748e0cf965SAdrian Hunter char kcore_filename[PATH_MAX]; 117556549978SAdrian Hunter u64 stext; 11768e0cf965SAdrian Hunter 1177ba92732eSWang Nan if (!kmaps) 1178ba92732eSWang Nan return -EINVAL; 1179ba92732eSWang Nan 11801c5aae77SAdrian Hunter machine = kmaps->machine; 11811c5aae77SAdrian Hunter 11828e0cf965SAdrian Hunter /* This function requires that the map is the kernel map */ 1183efdd5c6bSArnaldo Carvalho de Melo if (!__map__is_kernel(map)) 11848e0cf965SAdrian Hunter return -EINVAL; 11858e0cf965SAdrian Hunter 118652afdaf9SAdrian Hunter if (!filename_from_kallsyms_filename(kcore_filename, "kcore", 11878e0cf965SAdrian Hunter kallsyms_filename)) 11888e0cf965SAdrian Hunter return -EINVAL; 11898e0cf965SAdrian Hunter 1190a00d28cbSAdrian Hunter /* Modules and kernel must be present at their original addresses */ 1191a00d28cbSAdrian Hunter if (validate_kcore_addresses(kallsyms_filename, map)) 119252afdaf9SAdrian Hunter return -EINVAL; 119352afdaf9SAdrian Hunter 11948e0cf965SAdrian Hunter md.dso = dso; 11958e0cf965SAdrian Hunter INIT_LIST_HEAD(&md.maps); 11968e0cf965SAdrian Hunter 11978e0cf965SAdrian Hunter fd = open(kcore_filename, O_RDONLY); 119836c8bb56SLi Zhang if (fd < 0) { 1199133de940SAdrian Hunter pr_debug("Failed to open %s. Note /proc/kcore requires CAP_SYS_RAWIO capability to access.\n", 120036c8bb56SLi Zhang kcore_filename); 12018e0cf965SAdrian Hunter return -EINVAL; 120236c8bb56SLi Zhang } 12038e0cf965SAdrian Hunter 12048e0cf965SAdrian Hunter /* Read new maps into temporary lists */ 1205e9814df8SArnaldo Carvalho de Melo err = file__read_maps(fd, map->prot & PROT_EXEC, kcore_mapfn, &md, 12068e0cf965SAdrian Hunter &is_64_bit); 12078e0cf965SAdrian Hunter if (err) 12088e0cf965SAdrian Hunter goto out_err; 1209c6d8f2a4SAdrian Hunter dso->is_64_bit = is_64_bit; 12108e0cf965SAdrian Hunter 12118e0cf965SAdrian Hunter if (list_empty(&md.maps)) { 12128e0cf965SAdrian Hunter err = -EINVAL; 12138e0cf965SAdrian Hunter goto out_err; 12148e0cf965SAdrian Hunter } 12158e0cf965SAdrian Hunter 12168e0cf965SAdrian Hunter /* Remove old maps */ 12173183f8caSArnaldo Carvalho de Melo old_map = map_groups__first(kmaps); 12188e0cf965SAdrian Hunter while (old_map) { 12198e0cf965SAdrian Hunter struct map *next = map_groups__next(old_map); 12208e0cf965SAdrian Hunter 12218e0cf965SAdrian Hunter if (old_map != map) 12228e0cf965SAdrian Hunter map_groups__remove(kmaps, old_map); 12238e0cf965SAdrian Hunter old_map = next; 12248e0cf965SAdrian Hunter } 12251c5aae77SAdrian Hunter machine->trampolines_mapped = false; 12268e0cf965SAdrian Hunter 122756549978SAdrian Hunter /* Find the kernel map using the '_stext' symbol */ 122856549978SAdrian Hunter if (!kallsyms__get_function_start(kallsyms_filename, "_stext", &stext)) { 12298e0cf965SAdrian Hunter list_for_each_entry(new_map, &md.maps, node) { 123056549978SAdrian Hunter if (stext >= new_map->start && stext < new_map->end) { 12318e0cf965SAdrian Hunter replacement_map = new_map; 12328e0cf965SAdrian Hunter break; 12338e0cf965SAdrian Hunter } 12348e0cf965SAdrian Hunter } 123556549978SAdrian Hunter } 12368e0cf965SAdrian Hunter 12378e0cf965SAdrian Hunter if (!replacement_map) 12388e0cf965SAdrian Hunter replacement_map = list_entry(md.maps.next, struct map, node); 12398e0cf965SAdrian Hunter 12408e0cf965SAdrian Hunter /* Add new maps */ 12418e0cf965SAdrian Hunter while (!list_empty(&md.maps)) { 12428e0cf965SAdrian Hunter new_map = list_entry(md.maps.next, struct map, node); 1243facf3f06SArnaldo Carvalho de Melo list_del_init(&new_map->node); 12448e0cf965SAdrian Hunter if (new_map == replacement_map) { 12458e0cf965SAdrian Hunter map->start = new_map->start; 12468e0cf965SAdrian Hunter map->end = new_map->end; 12478e0cf965SAdrian Hunter map->pgoff = new_map->pgoff; 12488e0cf965SAdrian Hunter map->map_ip = new_map->map_ip; 12498e0cf965SAdrian Hunter map->unmap_ip = new_map->unmap_ip; 12508e0cf965SAdrian Hunter /* Ensure maps are correctly ordered */ 125184c2cafaSArnaldo Carvalho de Melo map__get(map); 12528e0cf965SAdrian Hunter map_groups__remove(kmaps, map); 12538e0cf965SAdrian Hunter map_groups__insert(kmaps, map); 125484c2cafaSArnaldo Carvalho de Melo map__put(map); 12558e0cf965SAdrian Hunter } else { 12568e0cf965SAdrian Hunter map_groups__insert(kmaps, new_map); 12578e0cf965SAdrian Hunter } 125884c2cafaSArnaldo Carvalho de Melo 125984c2cafaSArnaldo Carvalho de Melo map__put(new_map); 12608e0cf965SAdrian Hunter } 12618e0cf965SAdrian Hunter 12621c5aae77SAdrian Hunter if (machine__is(machine, "x86_64")) { 12631c5aae77SAdrian Hunter u64 addr; 12641c5aae77SAdrian Hunter 12651c5aae77SAdrian Hunter /* 12661c5aae77SAdrian Hunter * If one of the corresponding symbols is there, assume the 12671c5aae77SAdrian Hunter * entry trampoline maps are too. 12681c5aae77SAdrian Hunter */ 12691c5aae77SAdrian Hunter if (!kallsyms__get_function_start(kallsyms_filename, 12701c5aae77SAdrian Hunter ENTRY_TRAMPOLINE_NAME, 12711c5aae77SAdrian Hunter &addr)) 12721c5aae77SAdrian Hunter machine->trampolines_mapped = true; 12731c5aae77SAdrian Hunter } 12741c5aae77SAdrian Hunter 12758e0cf965SAdrian Hunter /* 12768e0cf965SAdrian Hunter * Set the data type and long name so that kcore can be read via 12778e0cf965SAdrian Hunter * dso__data_read_addr(). 12788e0cf965SAdrian Hunter */ 12798e0cf965SAdrian Hunter if (dso->kernel == DSO_TYPE_GUEST_KERNEL) 12805f70619dSArnaldo Carvalho de Melo dso->binary_type = DSO_BINARY_TYPE__GUEST_KCORE; 12818e0cf965SAdrian Hunter else 12825f70619dSArnaldo Carvalho de Melo dso->binary_type = DSO_BINARY_TYPE__KCORE; 12837e155d4dSArnaldo Carvalho de Melo dso__set_long_name(dso, strdup(kcore_filename), true); 12848e0cf965SAdrian Hunter 12858e0cf965SAdrian Hunter close(fd); 12868e0cf965SAdrian Hunter 1287e9814df8SArnaldo Carvalho de Melo if (map->prot & PROT_EXEC) 12888e0cf965SAdrian Hunter pr_debug("Using %s for kernel object code\n", kcore_filename); 12898e0cf965SAdrian Hunter else 12908e0cf965SAdrian Hunter pr_debug("Using %s for kernel data\n", kcore_filename); 12918e0cf965SAdrian Hunter 12928e0cf965SAdrian Hunter return 0; 12938e0cf965SAdrian Hunter 12948e0cf965SAdrian Hunter out_err: 12958e0cf965SAdrian Hunter while (!list_empty(&md.maps)) { 12968e0cf965SAdrian Hunter map = list_entry(md.maps.next, struct map, node); 1297facf3f06SArnaldo Carvalho de Melo list_del_init(&map->node); 129884c2cafaSArnaldo Carvalho de Melo map__put(map); 12998e0cf965SAdrian Hunter } 13008e0cf965SAdrian Hunter close(fd); 13018e0cf965SAdrian Hunter return -EINVAL; 13028e0cf965SAdrian Hunter } 13038e0cf965SAdrian Hunter 1304d9b62abaSAdrian Hunter /* 1305d9b62abaSAdrian Hunter * If the kernel is relocated at boot time, kallsyms won't match. Compute the 1306d9b62abaSAdrian Hunter * delta based on the relocation reference symbol. 1307d9b62abaSAdrian Hunter */ 1308019c6820SArnaldo Carvalho de Melo static int kallsyms__delta(struct kmap *kmap, const char *filename, u64 *delta) 1309d9b62abaSAdrian Hunter { 1310d9b62abaSAdrian Hunter u64 addr; 1311d9b62abaSAdrian Hunter 1312d9b62abaSAdrian Hunter if (!kmap->ref_reloc_sym || !kmap->ref_reloc_sym->name) 1313d9b62abaSAdrian Hunter return 0; 1314d9b62abaSAdrian Hunter 1315b843f62aSArnaldo Carvalho de Melo if (kallsyms__get_function_start(filename, kmap->ref_reloc_sym->name, &addr)) 1316d9b62abaSAdrian Hunter return -1; 1317d9b62abaSAdrian Hunter 1318d9b62abaSAdrian Hunter *delta = addr - kmap->ref_reloc_sym->addr; 1319d9b62abaSAdrian Hunter return 0; 1320d9b62abaSAdrian Hunter } 1321d9b62abaSAdrian Hunter 1322e02092b9SArnaldo Carvalho de Melo int __dso__load_kallsyms(struct dso *dso, const char *filename, 1323be39db9fSArnaldo Carvalho de Melo struct map *map, bool no_kcore) 13242e538c4aSArnaldo Carvalho de Melo { 1325019c6820SArnaldo Carvalho de Melo struct kmap *kmap = map__kmap(map); 1326d9b62abaSAdrian Hunter u64 delta = 0; 1327d9b62abaSAdrian Hunter 1328ec80fde7SArnaldo Carvalho de Melo if (symbol__restricted_filename(filename, "/proc/kallsyms")) 1329ec80fde7SArnaldo Carvalho de Melo return -1; 1330ec80fde7SArnaldo Carvalho de Melo 1331019c6820SArnaldo Carvalho de Melo if (!kmap || !kmap->kmaps) 1332019c6820SArnaldo Carvalho de Melo return -1; 1333019c6820SArnaldo Carvalho de Melo 1334333cc76cSArnaldo Carvalho de Melo if (dso__load_all_kallsyms(dso, filename) < 0) 13352e538c4aSArnaldo Carvalho de Melo return -1; 13362e538c4aSArnaldo Carvalho de Melo 1337019c6820SArnaldo Carvalho de Melo if (kallsyms__delta(kmap, filename, &delta)) 1338d9b62abaSAdrian Hunter return -1; 1339d9b62abaSAdrian Hunter 13403183f8caSArnaldo Carvalho de Melo symbols__fixup_end(&dso->symbols); 13413183f8caSArnaldo Carvalho de Melo symbols__fixup_duplicate(&dso->symbols); 13423f5a4272SAnton Blanchard 1343aeafcbafSArnaldo Carvalho de Melo if (dso->kernel == DSO_TYPE_GUEST_KERNEL) 134444f24cb3SJiri Olsa dso->symtab_type = DSO_BINARY_TYPE__GUEST_KALLSYMS; 1345a1645ce1SZhang, Yanmin else 134644f24cb3SJiri Olsa dso->symtab_type = DSO_BINARY_TYPE__KALLSYMS; 13472e538c4aSArnaldo Carvalho de Melo 1348e02092b9SArnaldo Carvalho de Melo if (!no_kcore && !dso__load_kcore(dso, map, filename)) 134915e0e2d4SArnaldo Carvalho de Melo return map_groups__split_kallsyms_for_kcore(kmap->kmaps, dso); 13508e0cf965SAdrian Hunter else 135115e0e2d4SArnaldo Carvalho de Melo return map_groups__split_kallsyms(kmap->kmaps, dso, delta, map); 1352af427bf5SArnaldo Carvalho de Melo } 1353af427bf5SArnaldo Carvalho de Melo 1354e02092b9SArnaldo Carvalho de Melo int dso__load_kallsyms(struct dso *dso, const char *filename, 1355be39db9fSArnaldo Carvalho de Melo struct map *map) 1356e02092b9SArnaldo Carvalho de Melo { 1357be39db9fSArnaldo Carvalho de Melo return __dso__load_kallsyms(dso, filename, map, false); 1358e02092b9SArnaldo Carvalho de Melo } 1359e02092b9SArnaldo Carvalho de Melo 13603183f8caSArnaldo Carvalho de Melo static int dso__load_perf_map(const char *map_path, struct dso *dso) 136180d496beSPekka Enberg { 136280d496beSPekka Enberg char *line = NULL; 136380d496beSPekka Enberg size_t n; 136480d496beSPekka Enberg FILE *file; 136580d496beSPekka Enberg int nr_syms = 0; 136680d496beSPekka Enberg 1367bf2e710bSKrister Johansen file = fopen(map_path, "r"); 136880d496beSPekka Enberg if (file == NULL) 136980d496beSPekka Enberg goto out_failure; 137080d496beSPekka Enberg 137180d496beSPekka Enberg while (!feof(file)) { 13729cffa8d5SPaul Mackerras u64 start, size; 137380d496beSPekka Enberg struct symbol *sym; 137480d496beSPekka Enberg int line_len, len; 137580d496beSPekka Enberg 137680d496beSPekka Enberg line_len = getline(&line, &n, file); 137780d496beSPekka Enberg if (line_len < 0) 137880d496beSPekka Enberg break; 137980d496beSPekka Enberg 138080d496beSPekka Enberg if (!line) 138180d496beSPekka Enberg goto out_failure; 138280d496beSPekka Enberg 138380d496beSPekka Enberg line[--line_len] = '\0'; /* \n */ 138480d496beSPekka Enberg 138580d496beSPekka Enberg len = hex2u64(line, &start); 138680d496beSPekka Enberg 138780d496beSPekka Enberg len++; 138880d496beSPekka Enberg if (len + 2 >= line_len) 138980d496beSPekka Enberg continue; 139080d496beSPekka Enberg 139180d496beSPekka Enberg len += hex2u64(line + len, &size); 139280d496beSPekka Enberg 139380d496beSPekka Enberg len++; 139480d496beSPekka Enberg if (len + 2 >= line_len) 139580d496beSPekka Enberg continue; 139680d496beSPekka Enberg 1397af30bffaSArnaldo Carvalho de Melo sym = symbol__new(start, size, STB_GLOBAL, STT_FUNC, line + len); 139880d496beSPekka Enberg 139980d496beSPekka Enberg if (sym == NULL) 140080d496beSPekka Enberg goto out_delete_line; 140180d496beSPekka Enberg 14023183f8caSArnaldo Carvalho de Melo symbols__insert(&dso->symbols, sym); 140380d496beSPekka Enberg nr_syms++; 140480d496beSPekka Enberg } 140580d496beSPekka Enberg 140680d496beSPekka Enberg free(line); 140780d496beSPekka Enberg fclose(file); 140880d496beSPekka Enberg 140980d496beSPekka Enberg return nr_syms; 141080d496beSPekka Enberg 141180d496beSPekka Enberg out_delete_line: 141280d496beSPekka Enberg free(line); 141380d496beSPekka Enberg out_failure: 141480d496beSPekka Enberg return -1; 141580d496beSPekka Enberg } 141680d496beSPekka Enberg 14171029f9feSNamhyung Kim static bool dso__is_compatible_symtab_type(struct dso *dso, bool kmod, 14181029f9feSNamhyung Kim enum dso_binary_type type) 14191029f9feSNamhyung Kim { 14201029f9feSNamhyung Kim switch (type) { 14211029f9feSNamhyung Kim case DSO_BINARY_TYPE__JAVA_JIT: 14221029f9feSNamhyung Kim case DSO_BINARY_TYPE__DEBUGLINK: 14231029f9feSNamhyung Kim case DSO_BINARY_TYPE__SYSTEM_PATH_DSO: 14241029f9feSNamhyung Kim case DSO_BINARY_TYPE__FEDORA_DEBUGINFO: 14251029f9feSNamhyung Kim case DSO_BINARY_TYPE__UBUNTU_DEBUGINFO: 14261029f9feSNamhyung Kim case DSO_BINARY_TYPE__BUILDID_DEBUGINFO: 14271029f9feSNamhyung Kim case DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO: 14281029f9feSNamhyung Kim return !kmod && dso->kernel == DSO_TYPE_USER; 14291029f9feSNamhyung Kim 14301029f9feSNamhyung Kim case DSO_BINARY_TYPE__KALLSYMS: 14311029f9feSNamhyung Kim case DSO_BINARY_TYPE__VMLINUX: 14321029f9feSNamhyung Kim case DSO_BINARY_TYPE__KCORE: 14331029f9feSNamhyung Kim return dso->kernel == DSO_TYPE_KERNEL; 14341029f9feSNamhyung Kim 14351029f9feSNamhyung Kim case DSO_BINARY_TYPE__GUEST_KALLSYMS: 14361029f9feSNamhyung Kim case DSO_BINARY_TYPE__GUEST_VMLINUX: 14371029f9feSNamhyung Kim case DSO_BINARY_TYPE__GUEST_KCORE: 14381029f9feSNamhyung Kim return dso->kernel == DSO_TYPE_GUEST_KERNEL; 14391029f9feSNamhyung Kim 14401029f9feSNamhyung Kim case DSO_BINARY_TYPE__GUEST_KMODULE: 1441c00c48fcSNamhyung Kim case DSO_BINARY_TYPE__GUEST_KMODULE_COMP: 14421029f9feSNamhyung Kim case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE: 1443c00c48fcSNamhyung Kim case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP: 14441029f9feSNamhyung Kim /* 14451029f9feSNamhyung Kim * kernel modules know their symtab type - it's set when 14469f2de315SArnaldo Carvalho de Melo * creating a module dso in machine__findnew_module_map(). 14471029f9feSNamhyung Kim */ 14481029f9feSNamhyung Kim return kmod && dso->symtab_type == type; 14491029f9feSNamhyung Kim 14501029f9feSNamhyung Kim case DSO_BINARY_TYPE__BUILD_ID_CACHE: 1451d2396999SKrister Johansen case DSO_BINARY_TYPE__BUILD_ID_CACHE_DEBUGINFO: 14521029f9feSNamhyung Kim return true; 14531029f9feSNamhyung Kim 14541029f9feSNamhyung Kim case DSO_BINARY_TYPE__NOT_FOUND: 14551029f9feSNamhyung Kim default: 14561029f9feSNamhyung Kim return false; 14571029f9feSNamhyung Kim } 14581029f9feSNamhyung Kim } 14591029f9feSNamhyung Kim 1460bf2e710bSKrister Johansen /* Checks for the existence of the perf-<pid>.map file in two different 1461bf2e710bSKrister Johansen * locations. First, if the process is a separate mount namespace, check in 1462bf2e710bSKrister Johansen * that namespace using the pid of the innermost pid namespace. If's not in a 1463bf2e710bSKrister Johansen * namespace, or the file can't be found there, try in the mount namespace of 1464bf2e710bSKrister Johansen * the tracing process using our view of its pid. 1465bf2e710bSKrister Johansen */ 1466bf2e710bSKrister Johansen static int dso__find_perf_map(char *filebuf, size_t bufsz, 1467bf2e710bSKrister Johansen struct nsinfo **nsip) 1468bf2e710bSKrister Johansen { 1469bf2e710bSKrister Johansen struct nscookie nsc; 1470bf2e710bSKrister Johansen struct nsinfo *nsi; 1471bf2e710bSKrister Johansen struct nsinfo *nnsi; 1472bf2e710bSKrister Johansen int rc = -1; 1473bf2e710bSKrister Johansen 1474bf2e710bSKrister Johansen nsi = *nsip; 1475bf2e710bSKrister Johansen 1476bf2e710bSKrister Johansen if (nsi->need_setns) { 1477bf2e710bSKrister Johansen snprintf(filebuf, bufsz, "/tmp/perf-%d.map", nsi->nstgid); 1478bf2e710bSKrister Johansen nsinfo__mountns_enter(nsi, &nsc); 1479bf2e710bSKrister Johansen rc = access(filebuf, R_OK); 1480bf2e710bSKrister Johansen nsinfo__mountns_exit(&nsc); 1481bf2e710bSKrister Johansen if (rc == 0) 1482bf2e710bSKrister Johansen return rc; 1483bf2e710bSKrister Johansen } 1484bf2e710bSKrister Johansen 1485bf2e710bSKrister Johansen nnsi = nsinfo__copy(nsi); 1486bf2e710bSKrister Johansen if (nnsi) { 1487bf2e710bSKrister Johansen nsinfo__put(nsi); 1488bf2e710bSKrister Johansen 1489bf2e710bSKrister Johansen nnsi->need_setns = false; 1490bf2e710bSKrister Johansen snprintf(filebuf, bufsz, "/tmp/perf-%d.map", nnsi->tgid); 1491bf2e710bSKrister Johansen *nsip = nnsi; 1492bf2e710bSKrister Johansen rc = 0; 1493bf2e710bSKrister Johansen } 1494bf2e710bSKrister Johansen 1495bf2e710bSKrister Johansen return rc; 1496bf2e710bSKrister Johansen } 1497bf2e710bSKrister Johansen 1498be39db9fSArnaldo Carvalho de Melo int dso__load(struct dso *dso, struct map *map) 149986470930SIngo Molnar { 1500c338aee8SArnaldo Carvalho de Melo char *name; 150186470930SIngo Molnar int ret = -1; 150244f24cb3SJiri Olsa u_int i; 150323346f21SArnaldo Carvalho de Melo struct machine *machine; 150444f24cb3SJiri Olsa char *root_dir = (char *) ""; 15053aafe5aeSCody P Schafer int ss_pos = 0; 15063aafe5aeSCody P Schafer struct symsrc ss_[2]; 15073aafe5aeSCody P Schafer struct symsrc *syms_ss = NULL, *runtime_ss = NULL; 15081029f9feSNamhyung Kim bool kmod; 1509bf2e710bSKrister Johansen bool perfmap; 15105baecbcdSDima Kogan unsigned char build_id[BUILD_ID_SIZE]; 1511843ff37bSKrister Johansen struct nscookie nsc; 1512bf2e710bSKrister Johansen char newmapname[PATH_MAX]; 1513bf2e710bSKrister Johansen const char *map_path = dso->long_name; 1514bf2e710bSKrister Johansen 1515bf2e710bSKrister Johansen perfmap = strncmp(dso->name, "/tmp/perf-", 10) == 0; 1516bf2e710bSKrister Johansen if (perfmap) { 1517bf2e710bSKrister Johansen if (dso->nsinfo && (dso__find_perf_map(newmapname, 1518bf2e710bSKrister Johansen sizeof(newmapname), &dso->nsinfo) == 0)) { 1519bf2e710bSKrister Johansen map_path = newmapname; 1520bf2e710bSKrister Johansen } 1521bf2e710bSKrister Johansen } 152286470930SIngo Molnar 1523843ff37bSKrister Johansen nsinfo__mountns_enter(dso->nsinfo, &nsc); 15244a936edcSNamhyung Kim pthread_mutex_lock(&dso->lock); 152566bd8424SArnaldo Carvalho de Melo 15264a936edcSNamhyung Kim /* check again under the dso->lock */ 15273183f8caSArnaldo Carvalho de Melo if (dso__loaded(dso)) { 15284a936edcSNamhyung Kim ret = 1; 15294a936edcSNamhyung Kim goto out; 15304a936edcSNamhyung Kim } 15314a936edcSNamhyung Kim 15324d99e413SAdrian Hunter if (map->groups && map->groups->machine) 15334d99e413SAdrian Hunter machine = map->groups->machine; 15344d99e413SAdrian Hunter else 15354d99e413SAdrian Hunter machine = NULL; 15364d99e413SAdrian Hunter 15374a936edcSNamhyung Kim if (dso->kernel) { 1538aeafcbafSArnaldo Carvalho de Melo if (dso->kernel == DSO_TYPE_KERNEL) 1539be39db9fSArnaldo Carvalho de Melo ret = dso__load_kernel_sym(dso, map); 1540aeafcbafSArnaldo Carvalho de Melo else if (dso->kernel == DSO_TYPE_GUEST_KERNEL) 1541be39db9fSArnaldo Carvalho de Melo ret = dso__load_guest_kernel_sym(dso, map); 15424a936edcSNamhyung Kim 15434d99e413SAdrian Hunter if (machine__is(machine, "x86_64")) 15444d99e413SAdrian Hunter machine__map_x86_64_entry_trampolines(machine, dso); 15454a936edcSNamhyung Kim goto out; 15464a936edcSNamhyung Kim } 1547a1645ce1SZhang, Yanmin 1548aeafcbafSArnaldo Carvalho de Melo dso->adjust_symbols = 0; 1549f5812a7aSArnaldo Carvalho de Melo 1550bf2e710bSKrister Johansen if (perfmap) { 15513183f8caSArnaldo Carvalho de Melo ret = dso__load_perf_map(map_path, dso); 155244f24cb3SJiri Olsa dso->symtab_type = ret > 0 ? DSO_BINARY_TYPE__JAVA_JIT : 155344f24cb3SJiri Olsa DSO_BINARY_TYPE__NOT_FOUND; 15544a936edcSNamhyung Kim goto out; 155594cb9e38SArnaldo Carvalho de Melo } 155694cb9e38SArnaldo Carvalho de Melo 155744f24cb3SJiri Olsa if (machine) 155844f24cb3SJiri Olsa root_dir = machine->root_dir; 155944f24cb3SJiri Olsa 1560164c800eSDavid Ahern name = malloc(PATH_MAX); 1561164c800eSDavid Ahern if (!name) 15624a936edcSNamhyung Kim goto out; 1563164c800eSDavid Ahern 15641029f9feSNamhyung Kim kmod = dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE || 1565c00c48fcSNamhyung Kim dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP || 1566c00c48fcSNamhyung Kim dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE || 1567c00c48fcSNamhyung Kim dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE_COMP; 15681029f9feSNamhyung Kim 15695baecbcdSDima Kogan 15705baecbcdSDima Kogan /* 15715baecbcdSDima Kogan * Read the build id if possible. This is required for 15725baecbcdSDima Kogan * DSO_BINARY_TYPE__BUILDID_DEBUGINFO to work 15735baecbcdSDima Kogan */ 1574ed6c166cSKan Liang if (!dso->has_build_id && 15759b200653SVictor Kamensky is_regular_file(dso->long_name)) { 15769b200653SVictor Kamensky __symbol__join_symfs(name, PATH_MAX, dso->long_name); 15779b200653SVictor Kamensky if (filename__read_build_id(name, build_id, BUILD_ID_SIZE) > 0) 15785baecbcdSDima Kogan dso__set_build_id(dso, build_id); 15799b200653SVictor Kamensky } 15805baecbcdSDima Kogan 15811029f9feSNamhyung Kim /* 15821029f9feSNamhyung Kim * Iterate over candidate debug images. 15833aafe5aeSCody P Schafer * Keep track of "interesting" ones (those which have a symtab, dynsym, 15843aafe5aeSCody P Schafer * and/or opd section) for processing. 15856da80ce8SDave Martin */ 158644f24cb3SJiri Olsa for (i = 0; i < DSO_BINARY_TYPE__SYMTAB_CNT; i++) { 15873aafe5aeSCody P Schafer struct symsrc *ss = &ss_[ss_pos]; 15883aafe5aeSCody P Schafer bool next_slot = false; 1589f045b8c4SKrister Johansen bool is_reg; 1590d2396999SKrister Johansen bool nsexit; 1591c3962961SJiri Olsa int sirc = -1; 159244f24cb3SJiri Olsa 1593005f9294SCody P Schafer enum dso_binary_type symtab_type = binary_type_symtab[i]; 159444f24cb3SJiri Olsa 1595d2396999SKrister Johansen nsexit = (symtab_type == DSO_BINARY_TYPE__BUILD_ID_CACHE || 1596d2396999SKrister Johansen symtab_type == DSO_BINARY_TYPE__BUILD_ID_CACHE_DEBUGINFO); 1597d2396999SKrister Johansen 15981029f9feSNamhyung Kim if (!dso__is_compatible_symtab_type(dso, kmod, symtab_type)) 15991029f9feSNamhyung Kim continue; 16001029f9feSNamhyung Kim 1601ee4e9625SArnaldo Carvalho de Melo if (dso__read_binary_type_filename(dso, symtab_type, 160244f24cb3SJiri Olsa root_dir, name, PATH_MAX)) 16036da80ce8SDave Martin continue; 160486470930SIngo Molnar 1605d2396999SKrister Johansen if (nsexit) 1606f045b8c4SKrister Johansen nsinfo__mountns_exit(&nsc); 160740356721SJiri Olsa 1608f045b8c4SKrister Johansen is_reg = is_regular_file(name); 1609c3962961SJiri Olsa if (is_reg) 1610f045b8c4SKrister Johansen sirc = symsrc__init(ss, dso, name, symtab_type); 1611f045b8c4SKrister Johansen 1612d2396999SKrister Johansen if (nsexit) 1613f045b8c4SKrister Johansen nsinfo__mountns_enter(dso->nsinfo, &nsc); 1614f045b8c4SKrister Johansen 1615c3962961SJiri Olsa if (!is_reg || sirc < 0) 16166da80ce8SDave Martin continue; 16176da80ce8SDave Martin 16183aafe5aeSCody P Schafer if (!syms_ss && symsrc__has_symtab(ss)) { 16193aafe5aeSCody P Schafer syms_ss = ss; 16203aafe5aeSCody P Schafer next_slot = true; 16210058aef6SAdrian Hunter if (!dso->symsrc_filename) 16220058aef6SAdrian Hunter dso->symsrc_filename = strdup(name); 1623d26cd12bSCody P Schafer } 1624d26cd12bSCody P Schafer 16253aafe5aeSCody P Schafer if (!runtime_ss && symsrc__possibly_runtime(ss)) { 16263aafe5aeSCody P Schafer runtime_ss = ss; 16273aafe5aeSCody P Schafer next_slot = true; 1628a44f605bSCody P Schafer } 162986470930SIngo Molnar 16303aafe5aeSCody P Schafer if (next_slot) { 16313aafe5aeSCody P Schafer ss_pos++; 163233ff581eSJiri Olsa 16333aafe5aeSCody P Schafer if (syms_ss && runtime_ss) 16346da80ce8SDave Martin break; 163598e9f03bSNamhyung Kim } else { 163698e9f03bSNamhyung Kim symsrc__destroy(ss); 1637a25e46c4SArnaldo Carvalho de Melo } 16383aafe5aeSCody P Schafer 16396da80ce8SDave Martin } 16406da80ce8SDave Martin 16413aafe5aeSCody P Schafer if (!runtime_ss && !syms_ss) 16423aafe5aeSCody P Schafer goto out_free; 16433aafe5aeSCody P Schafer 16443aafe5aeSCody P Schafer if (runtime_ss && !syms_ss) { 16453aafe5aeSCody P Schafer syms_ss = runtime_ss; 164660e4b10cSArnaldo Carvalho de Melo } 164760e4b10cSArnaldo Carvalho de Melo 16483aafe5aeSCody P Schafer /* We'll have to hope for the best */ 16493aafe5aeSCody P Schafer if (!runtime_ss && syms_ss) 16503aafe5aeSCody P Schafer runtime_ss = syms_ss; 16513aafe5aeSCody P Schafer 16521029f9feSNamhyung Kim if (syms_ss) 1653be39db9fSArnaldo Carvalho de Melo ret = dso__load_sym(dso, map, syms_ss, runtime_ss, kmod); 16541029f9feSNamhyung Kim else 16553aafe5aeSCody P Schafer ret = -1; 16563aafe5aeSCody P Schafer 1657f47b58b7SDavid Ahern if (ret > 0) { 16583aafe5aeSCody P Schafer int nr_plt; 16593aafe5aeSCody P Schafer 16603183f8caSArnaldo Carvalho de Melo nr_plt = dso__synthesize_plt_symbols(dso, runtime_ss); 16613aafe5aeSCody P Schafer if (nr_plt > 0) 16623aafe5aeSCody P Schafer ret += nr_plt; 16633aafe5aeSCody P Schafer } 16643aafe5aeSCody P Schafer 16653aafe5aeSCody P Schafer for (; ss_pos > 0; ss_pos--) 16663aafe5aeSCody P Schafer symsrc__destroy(&ss_[ss_pos - 1]); 16673aafe5aeSCody P Schafer out_free: 166886470930SIngo Molnar free(name); 1669aeafcbafSArnaldo Carvalho de Melo if (ret < 0 && strstr(dso->name, " (deleted)") != NULL) 16704a936edcSNamhyung Kim ret = 0; 16714a936edcSNamhyung Kim out: 16723183f8caSArnaldo Carvalho de Melo dso__set_loaded(dso); 16734a936edcSNamhyung Kim pthread_mutex_unlock(&dso->lock); 1674843ff37bSKrister Johansen nsinfo__mountns_exit(&nsc); 16754a936edcSNamhyung Kim 167686470930SIngo Molnar return ret; 167786470930SIngo Molnar } 167886470930SIngo Molnar 16793183f8caSArnaldo Carvalho de Melo struct map *map_groups__find_by_name(struct map_groups *mg, const char *name) 1680439d473bSArnaldo Carvalho de Melo { 16813183f8caSArnaldo Carvalho de Melo struct maps *maps = &mg->maps; 16824bb7123dSArnaldo Carvalho de Melo struct map *map; 16831e628569SEric Saint-Etienne struct rb_node *node; 1684439d473bSArnaldo Carvalho de Melo 16850a7c74eaSArnaldo Carvalho de Melo down_read(&maps->lock); 16866a2ffcddSArnaldo Carvalho de Melo 16871e628569SEric Saint-Etienne for (node = maps->names.rb_node; node; ) { 16881e628569SEric Saint-Etienne int rc; 16891e628569SEric Saint-Etienne 16901e628569SEric Saint-Etienne map = rb_entry(node, struct map, rb_node_name); 16911e628569SEric Saint-Etienne 16921e628569SEric Saint-Etienne rc = strcmp(map->dso->short_name, name); 16931e628569SEric Saint-Etienne if (rc < 0) 16941e628569SEric Saint-Etienne node = node->rb_left; 16951e628569SEric Saint-Etienne else if (rc > 0) 16961e628569SEric Saint-Etienne node = node->rb_right; 16971e628569SEric Saint-Etienne else 16981e628569SEric Saint-Etienne 16996a2ffcddSArnaldo Carvalho de Melo goto out_unlock; 1700439d473bSArnaldo Carvalho de Melo } 1701439d473bSArnaldo Carvalho de Melo 17026a2ffcddSArnaldo Carvalho de Melo map = NULL; 17036a2ffcddSArnaldo Carvalho de Melo 17046a2ffcddSArnaldo Carvalho de Melo out_unlock: 17050a7c74eaSArnaldo Carvalho de Melo up_read(&maps->lock); 17066a2ffcddSArnaldo Carvalho de Melo return map; 1707439d473bSArnaldo Carvalho de Melo } 1708439d473bSArnaldo Carvalho de Melo 1709aeafcbafSArnaldo Carvalho de Melo int dso__load_vmlinux(struct dso *dso, struct map *map, 1710be39db9fSArnaldo Carvalho de Melo const char *vmlinux, bool vmlinux_allocated) 171186470930SIngo Molnar { 1712b68e2f91SCody P Schafer int err = -1; 1713b68e2f91SCody P Schafer struct symsrc ss; 1714ec5761eaSDavid Ahern char symfs_vmlinux[PATH_MAX]; 1715005f9294SCody P Schafer enum dso_binary_type symtab_type; 171686470930SIngo Molnar 17175698d2c9SNamhyung Kim if (vmlinux[0] == '/') 17185698d2c9SNamhyung Kim snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s", vmlinux); 17195698d2c9SNamhyung Kim else 1720972f393bSArnaldo Carvalho de Melo symbol__join_symfs(symfs_vmlinux, vmlinux); 172186470930SIngo Molnar 172221ea4539SCody P Schafer if (dso->kernel == DSO_TYPE_GUEST_KERNEL) 1723005f9294SCody P Schafer symtab_type = DSO_BINARY_TYPE__GUEST_VMLINUX; 172421ea4539SCody P Schafer else 1725005f9294SCody P Schafer symtab_type = DSO_BINARY_TYPE__VMLINUX; 172621ea4539SCody P Schafer 1727005f9294SCody P Schafer if (symsrc__init(&ss, dso, symfs_vmlinux, symtab_type)) 1728b68e2f91SCody P Schafer return -1; 1729b68e2f91SCody P Schafer 1730be39db9fSArnaldo Carvalho de Melo err = dso__load_sym(dso, map, &ss, &ss, 0); 1731b68e2f91SCody P Schafer symsrc__destroy(&ss); 173286470930SIngo Molnar 1733515850e4SCody P Schafer if (err > 0) { 173439b12f78SAdrian Hunter if (dso->kernel == DSO_TYPE_GUEST_KERNEL) 17355f70619dSArnaldo Carvalho de Melo dso->binary_type = DSO_BINARY_TYPE__GUEST_VMLINUX; 173639b12f78SAdrian Hunter else 17375f70619dSArnaldo Carvalho de Melo dso->binary_type = DSO_BINARY_TYPE__VMLINUX; 1738bf4414aeSArnaldo Carvalho de Melo dso__set_long_name(dso, vmlinux, vmlinux_allocated); 17393183f8caSArnaldo Carvalho de Melo dso__set_loaded(dso); 1740ec5761eaSDavid Ahern pr_debug("Using %s for symbols\n", symfs_vmlinux); 1741515850e4SCody P Schafer } 17423846df2eSArnaldo Carvalho de Melo 174386470930SIngo Molnar return err; 174486470930SIngo Molnar } 174586470930SIngo Molnar 1746be39db9fSArnaldo Carvalho de Melo int dso__load_vmlinux_path(struct dso *dso, struct map *map) 1747a19afe46SArnaldo Carvalho de Melo { 1748a19afe46SArnaldo Carvalho de Melo int i, err = 0; 174900dc8657SNamhyung Kim char *filename = NULL; 1750a19afe46SArnaldo Carvalho de Melo 1751dc38218eSArnaldo Carvalho de Melo pr_debug("Looking at the vmlinux_path (%d entries long)\n", 1752dc38218eSArnaldo Carvalho de Melo vmlinux_path__nr_entries + 1); 1753dc38218eSArnaldo Carvalho de Melo 1754dc38218eSArnaldo Carvalho de Melo for (i = 0; i < vmlinux_path__nr_entries; ++i) { 1755be39db9fSArnaldo Carvalho de Melo err = dso__load_vmlinux(dso, map, vmlinux_path[i], false); 1756dc38218eSArnaldo Carvalho de Melo if (err > 0) 1757dc38218eSArnaldo Carvalho de Melo goto out; 1758dc38218eSArnaldo Carvalho de Melo } 1759dc38218eSArnaldo Carvalho de Melo 176000dc8657SNamhyung Kim if (!symbol_conf.ignore_vmlinux_buildid) 1761d2396999SKrister Johansen filename = dso__build_id_filename(dso, NULL, 0, false); 17625ad90e4eSArnaldo Carvalho de Melo if (filename != NULL) { 1763be39db9fSArnaldo Carvalho de Melo err = dso__load_vmlinux(dso, map, filename, true); 17645230fb7dSArnaldo Carvalho de Melo if (err > 0) 17655ad90e4eSArnaldo Carvalho de Melo goto out; 17665ad90e4eSArnaldo Carvalho de Melo free(filename); 17675ad90e4eSArnaldo Carvalho de Melo } 17685ad90e4eSArnaldo Carvalho de Melo out: 1769a19afe46SArnaldo Carvalho de Melo return err; 1770a19afe46SArnaldo Carvalho de Melo } 1771a19afe46SArnaldo Carvalho de Melo 1772c48903b8SMasami Hiramatsu static bool visible_dir_filter(const char *name, struct dirent *d) 1773c48903b8SMasami Hiramatsu { 1774c48903b8SMasami Hiramatsu if (d->d_type != DT_DIR) 1775c48903b8SMasami Hiramatsu return false; 1776c48903b8SMasami Hiramatsu return lsdir_no_dot_filter(name, d); 1777c48903b8SMasami Hiramatsu } 1778c48903b8SMasami Hiramatsu 17790544d422SAdrian Hunter static int find_matching_kcore(struct map *map, char *dir, size_t dir_sz) 17800544d422SAdrian Hunter { 17810544d422SAdrian Hunter char kallsyms_filename[PATH_MAX]; 17820544d422SAdrian Hunter int ret = -1; 1783c48903b8SMasami Hiramatsu struct strlist *dirs; 1784c48903b8SMasami Hiramatsu struct str_node *nd; 17850544d422SAdrian Hunter 1786c48903b8SMasami Hiramatsu dirs = lsdir(dir, visible_dir_filter); 1787c48903b8SMasami Hiramatsu if (!dirs) 17880544d422SAdrian Hunter return -1; 17890544d422SAdrian Hunter 1790602a1f4dSArnaldo Carvalho de Melo strlist__for_each_entry(nd, dirs) { 17910544d422SAdrian Hunter scnprintf(kallsyms_filename, sizeof(kallsyms_filename), 1792c48903b8SMasami Hiramatsu "%s/%s/kallsyms", dir, nd->s); 1793a00d28cbSAdrian Hunter if (!validate_kcore_addresses(kallsyms_filename, map)) { 17940544d422SAdrian Hunter strlcpy(dir, kallsyms_filename, dir_sz); 17950544d422SAdrian Hunter ret = 0; 17960544d422SAdrian Hunter break; 17970544d422SAdrian Hunter } 17980544d422SAdrian Hunter } 17990544d422SAdrian Hunter 1800c48903b8SMasami Hiramatsu strlist__delete(dirs); 18010544d422SAdrian Hunter 18020544d422SAdrian Hunter return ret; 18030544d422SAdrian Hunter } 18040544d422SAdrian Hunter 180511870d71SMasami Hiramatsu /* 180611870d71SMasami Hiramatsu * Use open(O_RDONLY) to check readability directly instead of access(R_OK) 180711870d71SMasami Hiramatsu * since access(R_OK) only checks with real UID/GID but open() use effective 180811870d71SMasami Hiramatsu * UID/GID and actual capabilities (e.g. /proc/kcore requires CAP_SYS_RAWIO). 180911870d71SMasami Hiramatsu */ 181011870d71SMasami Hiramatsu static bool filename__readable(const char *file) 181111870d71SMasami Hiramatsu { 181211870d71SMasami Hiramatsu int fd = open(file, O_RDONLY); 181311870d71SMasami Hiramatsu if (fd < 0) 181411870d71SMasami Hiramatsu return false; 181511870d71SMasami Hiramatsu close(fd); 181611870d71SMasami Hiramatsu return true; 181711870d71SMasami Hiramatsu } 181811870d71SMasami Hiramatsu 18190544d422SAdrian Hunter static char *dso__find_kallsyms(struct dso *dso, struct map *map) 18200544d422SAdrian Hunter { 18210544d422SAdrian Hunter u8 host_build_id[BUILD_ID_SIZE]; 1822b5d8bbe8SMasami Hiramatsu char sbuild_id[SBUILD_ID_SIZE]; 18230544d422SAdrian Hunter bool is_host = false; 18240544d422SAdrian Hunter char path[PATH_MAX]; 18250544d422SAdrian Hunter 18260544d422SAdrian Hunter if (!dso->has_build_id) { 18270544d422SAdrian Hunter /* 18280544d422SAdrian Hunter * Last resort, if we don't have a build-id and couldn't find 18290544d422SAdrian Hunter * any vmlinux file, try the running kernel kallsyms table. 18300544d422SAdrian Hunter */ 18310544d422SAdrian Hunter goto proc_kallsyms; 18320544d422SAdrian Hunter } 18330544d422SAdrian Hunter 18340544d422SAdrian Hunter if (sysfs__read_build_id("/sys/kernel/notes", host_build_id, 18350544d422SAdrian Hunter sizeof(host_build_id)) == 0) 18360544d422SAdrian Hunter is_host = dso__build_id_equal(dso, host_build_id); 18370544d422SAdrian Hunter 18384e4b6c06SMasami Hiramatsu /* Try a fast path for /proc/kallsyms if possible */ 18390544d422SAdrian Hunter if (is_host) { 18400544d422SAdrian Hunter /* 184111870d71SMasami Hiramatsu * Do not check the build-id cache, unless we know we cannot use 184211870d71SMasami Hiramatsu * /proc/kcore or module maps don't match to /proc/kallsyms. 184311870d71SMasami Hiramatsu * To check readability of /proc/kcore, do not use access(R_OK) 184411870d71SMasami Hiramatsu * since /proc/kcore requires CAP_SYS_RAWIO to read and access 184511870d71SMasami Hiramatsu * can't check it. 18460544d422SAdrian Hunter */ 184711870d71SMasami Hiramatsu if (filename__readable("/proc/kcore") && 184811870d71SMasami Hiramatsu !validate_kcore_addresses("/proc/kallsyms", map)) 18490544d422SAdrian Hunter goto proc_kallsyms; 18500544d422SAdrian Hunter } 18510544d422SAdrian Hunter 18524e4b6c06SMasami Hiramatsu build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id); 18534e4b6c06SMasami Hiramatsu 1854449867e3SAdrian Hunter /* Find kallsyms in build-id cache with kcore */ 18554e4b6c06SMasami Hiramatsu scnprintf(path, sizeof(path), "%s/%s/%s", 18564e4b6c06SMasami Hiramatsu buildid_dir, DSO__NAME_KCORE, sbuild_id); 18574e4b6c06SMasami Hiramatsu 1858449867e3SAdrian Hunter if (!find_matching_kcore(map, path, sizeof(path))) 1859449867e3SAdrian Hunter return strdup(path); 1860449867e3SAdrian Hunter 18614e4b6c06SMasami Hiramatsu /* Use current /proc/kallsyms if possible */ 18624e4b6c06SMasami Hiramatsu if (is_host) { 18634e4b6c06SMasami Hiramatsu proc_kallsyms: 18644e4b6c06SMasami Hiramatsu return strdup("/proc/kallsyms"); 18654e4b6c06SMasami Hiramatsu } 18664e4b6c06SMasami Hiramatsu 18674e4b6c06SMasami Hiramatsu /* Finally, find a cache of kallsyms */ 186801412261SMasami Hiramatsu if (!build_id_cache__kallsyms_path(sbuild_id, path, sizeof(path))) { 18690544d422SAdrian Hunter pr_err("No kallsyms or vmlinux with build-id %s was found\n", 18700544d422SAdrian Hunter sbuild_id); 18710544d422SAdrian Hunter return NULL; 18720544d422SAdrian Hunter } 18730544d422SAdrian Hunter 18740544d422SAdrian Hunter return strdup(path); 18750544d422SAdrian Hunter } 18760544d422SAdrian Hunter 1877be39db9fSArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *dso, struct map *map) 187886470930SIngo Molnar { 1879cc612d81SArnaldo Carvalho de Melo int err; 18809e201442SArnaldo Carvalho de Melo const char *kallsyms_filename = NULL; 18819e201442SArnaldo Carvalho de Melo char *kallsyms_allocated_filename = NULL; 1882dc8d6ab2SArnaldo Carvalho de Melo /* 1883b226a5a7SDavid Ahern * Step 1: if the user specified a kallsyms or vmlinux filename, use 1884b226a5a7SDavid Ahern * it and only it, reporting errors to the user if it cannot be used. 1885dc8d6ab2SArnaldo Carvalho de Melo * 1886dc8d6ab2SArnaldo Carvalho de Melo * For instance, try to analyse an ARM perf.data file _without_ a 1887dc8d6ab2SArnaldo Carvalho de Melo * build-id, or if the user specifies the wrong path to the right 1888dc8d6ab2SArnaldo Carvalho de Melo * vmlinux file, obviously we can't fallback to another vmlinux (a 1889dc8d6ab2SArnaldo Carvalho de Melo * x86_86 one, on the machine where analysis is being performed, say), 1890dc8d6ab2SArnaldo Carvalho de Melo * or worse, /proc/kallsyms. 1891dc8d6ab2SArnaldo Carvalho de Melo * 1892dc8d6ab2SArnaldo Carvalho de Melo * If the specified file _has_ a build-id and there is a build-id 1893dc8d6ab2SArnaldo Carvalho de Melo * section in the perf.data file, we will still do the expected 1894dc8d6ab2SArnaldo Carvalho de Melo * validation in dso__load_vmlinux and will bail out if they don't 1895dc8d6ab2SArnaldo Carvalho de Melo * match. 1896dc8d6ab2SArnaldo Carvalho de Melo */ 1897b226a5a7SDavid Ahern if (symbol_conf.kallsyms_name != NULL) { 1898b226a5a7SDavid Ahern kallsyms_filename = symbol_conf.kallsyms_name; 1899b226a5a7SDavid Ahern goto do_kallsyms; 1900b226a5a7SDavid Ahern } 1901b226a5a7SDavid Ahern 1902fc2be696SWilly Tarreau if (!symbol_conf.ignore_vmlinux && symbol_conf.vmlinux_name != NULL) { 1903be39db9fSArnaldo Carvalho de Melo return dso__load_vmlinux(dso, map, symbol_conf.vmlinux_name, false); 1904dc8d6ab2SArnaldo Carvalho de Melo } 1905439d473bSArnaldo Carvalho de Melo 1906fc2be696SWilly Tarreau if (!symbol_conf.ignore_vmlinux && vmlinux_path != NULL) { 1907be39db9fSArnaldo Carvalho de Melo err = dso__load_vmlinux_path(dso, map); 1908a19afe46SArnaldo Carvalho de Melo if (err > 0) 190939b12f78SAdrian Hunter return err; 1910cc612d81SArnaldo Carvalho de Melo } 1911cc612d81SArnaldo Carvalho de Melo 1912ec5761eaSDavid Ahern /* do not try local files if a symfs was given */ 1913ec5761eaSDavid Ahern if (symbol_conf.symfs[0] != 0) 1914ec5761eaSDavid Ahern return -1; 1915ec5761eaSDavid Ahern 19160544d422SAdrian Hunter kallsyms_allocated_filename = dso__find_kallsyms(dso, map); 19170544d422SAdrian Hunter if (!kallsyms_allocated_filename) 19188d0591f6SArnaldo Carvalho de Melo return -1; 19198d0591f6SArnaldo Carvalho de Melo 192019fc2dedSArnaldo Carvalho de Melo kallsyms_filename = kallsyms_allocated_filename; 192119fc2dedSArnaldo Carvalho de Melo 1922dc8d6ab2SArnaldo Carvalho de Melo do_kallsyms: 1923be39db9fSArnaldo Carvalho de Melo err = dso__load_kallsyms(dso, kallsyms_filename, map); 19243846df2eSArnaldo Carvalho de Melo if (err > 0) 19253846df2eSArnaldo Carvalho de Melo pr_debug("Using %s for symbols\n", kallsyms_filename); 1926dc8d6ab2SArnaldo Carvalho de Melo free(kallsyms_allocated_filename); 1927dc8d6ab2SArnaldo Carvalho de Melo 19288e0cf965SAdrian Hunter if (err > 0 && !dso__is_kcore(dso)) { 1929bdac0bcfSAdrian Hunter dso->binary_type = DSO_BINARY_TYPE__KALLSYMS; 19300a77582fSMasami Hiramatsu dso__set_long_name(dso, DSO__NAME_KALLSYMS, false); 19316a4694a4SArnaldo Carvalho de Melo map__fixup_start(map); 19326a4694a4SArnaldo Carvalho de Melo map__fixup_end(map); 1933439d473bSArnaldo Carvalho de Melo } 193494cb9e38SArnaldo Carvalho de Melo 193586470930SIngo Molnar return err; 193686470930SIngo Molnar } 193786470930SIngo Molnar 1938be39db9fSArnaldo Carvalho de Melo static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map) 1939a1645ce1SZhang, Yanmin { 1940a1645ce1SZhang, Yanmin int err; 1941a1645ce1SZhang, Yanmin const char *kallsyms_filename = NULL; 194223346f21SArnaldo Carvalho de Melo struct machine *machine; 1943a1645ce1SZhang, Yanmin char path[PATH_MAX]; 1944a1645ce1SZhang, Yanmin 1945a1645ce1SZhang, Yanmin if (!map->groups) { 1946a1645ce1SZhang, Yanmin pr_debug("Guest kernel map hasn't the point to groups\n"); 1947a1645ce1SZhang, Yanmin return -1; 1948a1645ce1SZhang, Yanmin } 194923346f21SArnaldo Carvalho de Melo machine = map->groups->machine; 1950a1645ce1SZhang, Yanmin 195123346f21SArnaldo Carvalho de Melo if (machine__is_default_guest(machine)) { 1952a1645ce1SZhang, Yanmin /* 1953a1645ce1SZhang, Yanmin * if the user specified a vmlinux filename, use it and only 1954a1645ce1SZhang, Yanmin * it, reporting errors to the user if it cannot be used. 1955a1645ce1SZhang, Yanmin * Or use file guest_kallsyms inputted by user on commandline 1956a1645ce1SZhang, Yanmin */ 1957a1645ce1SZhang, Yanmin if (symbol_conf.default_guest_vmlinux_name != NULL) { 1958aeafcbafSArnaldo Carvalho de Melo err = dso__load_vmlinux(dso, map, 19595230fb7dSArnaldo Carvalho de Melo symbol_conf.default_guest_vmlinux_name, 1960be39db9fSArnaldo Carvalho de Melo false); 196139b12f78SAdrian Hunter return err; 1962a1645ce1SZhang, Yanmin } 1963a1645ce1SZhang, Yanmin 1964a1645ce1SZhang, Yanmin kallsyms_filename = symbol_conf.default_guest_kallsyms; 1965a1645ce1SZhang, Yanmin if (!kallsyms_filename) 1966a1645ce1SZhang, Yanmin return -1; 1967a1645ce1SZhang, Yanmin } else { 196823346f21SArnaldo Carvalho de Melo sprintf(path, "%s/proc/kallsyms", machine->root_dir); 1969a1645ce1SZhang, Yanmin kallsyms_filename = path; 1970a1645ce1SZhang, Yanmin } 1971a1645ce1SZhang, Yanmin 1972be39db9fSArnaldo Carvalho de Melo err = dso__load_kallsyms(dso, kallsyms_filename, map); 19738e0cf965SAdrian Hunter if (err > 0) 197439b12f78SAdrian Hunter pr_debug("Using %s for symbols\n", kallsyms_filename); 19758e0cf965SAdrian Hunter if (err > 0 && !dso__is_kcore(dso)) { 1976bdac0bcfSAdrian Hunter dso->binary_type = DSO_BINARY_TYPE__GUEST_KALLSYMS; 19778c7f1bb3SJiri Olsa dso__set_long_name(dso, machine->mmap_name, false); 1978a1645ce1SZhang, Yanmin map__fixup_start(map); 1979a1645ce1SZhang, Yanmin map__fixup_end(map); 1980a1645ce1SZhang, Yanmin } 1981a1645ce1SZhang, Yanmin 1982a1645ce1SZhang, Yanmin return err; 1983a1645ce1SZhang, Yanmin } 1984cd84c2acSFrederic Weisbecker 1985cc612d81SArnaldo Carvalho de Melo static void vmlinux_path__exit(void) 19862446042cSArnaldo Carvalho de Melo { 198704662523SArnaldo Carvalho de Melo while (--vmlinux_path__nr_entries >= 0) 198804662523SArnaldo Carvalho de Melo zfree(&vmlinux_path[vmlinux_path__nr_entries]); 1989c4f03547SWang Nan vmlinux_path__nr_entries = 0; 1990cc612d81SArnaldo Carvalho de Melo 199104662523SArnaldo Carvalho de Melo zfree(&vmlinux_path); 1992cc612d81SArnaldo Carvalho de Melo } 1993cc612d81SArnaldo Carvalho de Melo 1994aac48647SEkaterina Tumanova static const char * const vmlinux_paths[] = { 1995aac48647SEkaterina Tumanova "vmlinux", 1996aac48647SEkaterina Tumanova "/boot/vmlinux" 1997aac48647SEkaterina Tumanova }; 1998aac48647SEkaterina Tumanova 1999aac48647SEkaterina Tumanova static const char * const vmlinux_paths_upd[] = { 2000aac48647SEkaterina Tumanova "/boot/vmlinux-%s", 2001aac48647SEkaterina Tumanova "/usr/lib/debug/boot/vmlinux-%s", 2002aac48647SEkaterina Tumanova "/lib/modules/%s/build/vmlinux", 2003f55ae954SEkaterina Tumanova "/usr/lib/debug/lib/modules/%s/vmlinux", 2004f55ae954SEkaterina Tumanova "/usr/lib/debug/boot/vmlinux-%s.debug" 2005aac48647SEkaterina Tumanova }; 2006aac48647SEkaterina Tumanova 2007aac48647SEkaterina Tumanova static int vmlinux_path__add(const char *new_entry) 2008aac48647SEkaterina Tumanova { 2009aac48647SEkaterina Tumanova vmlinux_path[vmlinux_path__nr_entries] = strdup(new_entry); 2010aac48647SEkaterina Tumanova if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 2011aac48647SEkaterina Tumanova return -1; 2012aac48647SEkaterina Tumanova ++vmlinux_path__nr_entries; 2013aac48647SEkaterina Tumanova 2014aac48647SEkaterina Tumanova return 0; 2015aac48647SEkaterina Tumanova } 2016aac48647SEkaterina Tumanova 2017ce80d3beSKan Liang static int vmlinux_path__init(struct perf_env *env) 2018cc612d81SArnaldo Carvalho de Melo { 2019cc612d81SArnaldo Carvalho de Melo struct utsname uts; 2020cc612d81SArnaldo Carvalho de Melo char bf[PATH_MAX]; 20210a7e6d1bSNamhyung Kim char *kernel_version; 2022aac48647SEkaterina Tumanova unsigned int i; 2023cc612d81SArnaldo Carvalho de Melo 2024aac48647SEkaterina Tumanova vmlinux_path = malloc(sizeof(char *) * (ARRAY_SIZE(vmlinux_paths) + 2025aac48647SEkaterina Tumanova ARRAY_SIZE(vmlinux_paths_upd))); 2026cc612d81SArnaldo Carvalho de Melo if (vmlinux_path == NULL) 2027cc612d81SArnaldo Carvalho de Melo return -1; 2028cc612d81SArnaldo Carvalho de Melo 2029aac48647SEkaterina Tumanova for (i = 0; i < ARRAY_SIZE(vmlinux_paths); i++) 2030aac48647SEkaterina Tumanova if (vmlinux_path__add(vmlinux_paths[i]) < 0) 2031cc612d81SArnaldo Carvalho de Melo goto out_fail; 2032ec5761eaSDavid Ahern 20330a7e6d1bSNamhyung Kim /* only try kernel version if no symfs was given */ 2034ec5761eaSDavid Ahern if (symbol_conf.symfs[0] != 0) 2035ec5761eaSDavid Ahern return 0; 2036ec5761eaSDavid Ahern 20370a7e6d1bSNamhyung Kim if (env) { 20380a7e6d1bSNamhyung Kim kernel_version = env->os_release; 20390a7e6d1bSNamhyung Kim } else { 2040ec5761eaSDavid Ahern if (uname(&uts) < 0) 2041e96c674fSNamhyung Kim goto out_fail; 2042ec5761eaSDavid Ahern 20430a7e6d1bSNamhyung Kim kernel_version = uts.release; 20440a7e6d1bSNamhyung Kim } 20450a7e6d1bSNamhyung Kim 2046aac48647SEkaterina Tumanova for (i = 0; i < ARRAY_SIZE(vmlinux_paths_upd); i++) { 2047aac48647SEkaterina Tumanova snprintf(bf, sizeof(bf), vmlinux_paths_upd[i], kernel_version); 2048aac48647SEkaterina Tumanova if (vmlinux_path__add(bf) < 0) 2049cc612d81SArnaldo Carvalho de Melo goto out_fail; 2050aac48647SEkaterina Tumanova } 2051cc612d81SArnaldo Carvalho de Melo 2052cc612d81SArnaldo Carvalho de Melo return 0; 2053cc612d81SArnaldo Carvalho de Melo 2054cc612d81SArnaldo Carvalho de Melo out_fail: 2055cc612d81SArnaldo Carvalho de Melo vmlinux_path__exit(); 2056cc612d81SArnaldo Carvalho de Melo return -1; 2057cc612d81SArnaldo Carvalho de Melo } 2058cc612d81SArnaldo Carvalho de Melo 20593bfe5f81SDavid Ahern int setup_list(struct strlist **list, const char *list_str, 2060655000e7SArnaldo Carvalho de Melo const char *list_name) 2061655000e7SArnaldo Carvalho de Melo { 2062655000e7SArnaldo Carvalho de Melo if (list_str == NULL) 2063655000e7SArnaldo Carvalho de Melo return 0; 2064655000e7SArnaldo Carvalho de Melo 20654a77e218SArnaldo Carvalho de Melo *list = strlist__new(list_str, NULL); 2066655000e7SArnaldo Carvalho de Melo if (!*list) { 2067655000e7SArnaldo Carvalho de Melo pr_err("problems parsing %s list\n", list_name); 2068655000e7SArnaldo Carvalho de Melo return -1; 2069655000e7SArnaldo Carvalho de Melo } 20700bc2f2f7SArnaldo Carvalho de Melo 20710bc2f2f7SArnaldo Carvalho de Melo symbol_conf.has_filter = true; 2072655000e7SArnaldo Carvalho de Melo return 0; 2073655000e7SArnaldo Carvalho de Melo } 2074655000e7SArnaldo Carvalho de Melo 2075e03eaa40SDavid Ahern int setup_intlist(struct intlist **list, const char *list_str, 2076e03eaa40SDavid Ahern const char *list_name) 2077e03eaa40SDavid Ahern { 2078e03eaa40SDavid Ahern if (list_str == NULL) 2079e03eaa40SDavid Ahern return 0; 2080e03eaa40SDavid Ahern 2081e03eaa40SDavid Ahern *list = intlist__new(list_str); 2082e03eaa40SDavid Ahern if (!*list) { 2083e03eaa40SDavid Ahern pr_err("problems parsing %s list\n", list_name); 2084e03eaa40SDavid Ahern return -1; 2085e03eaa40SDavid Ahern } 2086e03eaa40SDavid Ahern return 0; 2087e03eaa40SDavid Ahern } 2088e03eaa40SDavid Ahern 2089ec80fde7SArnaldo Carvalho de Melo static bool symbol__read_kptr_restrict(void) 2090ec80fde7SArnaldo Carvalho de Melo { 2091ec80fde7SArnaldo Carvalho de Melo bool value = false; 2092ec80fde7SArnaldo Carvalho de Melo FILE *fp = fopen("/proc/sys/kernel/kptr_restrict", "r"); 209338272dc4SWang Nan 2094ec80fde7SArnaldo Carvalho de Melo if (fp != NULL) { 2095ec80fde7SArnaldo Carvalho de Melo char line[8]; 2096ec80fde7SArnaldo Carvalho de Melo 2097ec80fde7SArnaldo Carvalho de Melo if (fgets(line, sizeof(line), fp) != NULL) 20983dbe46c5SWang Nan value = ((geteuid() != 0) || (getuid() != 0)) ? 209938272dc4SWang Nan (atoi(line) != 0) : 210038272dc4SWang Nan (atoi(line) == 2); 2101ec80fde7SArnaldo Carvalho de Melo 2102ec80fde7SArnaldo Carvalho de Melo fclose(fp); 2103ec80fde7SArnaldo Carvalho de Melo } 2104ec80fde7SArnaldo Carvalho de Melo 2105ec80fde7SArnaldo Carvalho de Melo return value; 2106ec80fde7SArnaldo Carvalho de Melo } 2107ec80fde7SArnaldo Carvalho de Melo 2108b01141f4SArnaldo Carvalho de Melo int symbol__annotation_init(void) 2109b01141f4SArnaldo Carvalho de Melo { 21107b366142SArnaldo Carvalho de Melo if (symbol_conf.init_annotation) 21117b366142SArnaldo Carvalho de Melo return 0; 21127b366142SArnaldo Carvalho de Melo 2113b01141f4SArnaldo Carvalho de Melo if (symbol_conf.initialized) { 2114b01141f4SArnaldo Carvalho de Melo pr_err("Annotation needs to be init before symbol__init()\n"); 2115b01141f4SArnaldo Carvalho de Melo return -1; 2116b01141f4SArnaldo Carvalho de Melo } 2117b01141f4SArnaldo Carvalho de Melo 2118b01141f4SArnaldo Carvalho de Melo symbol_conf.priv_size += sizeof(struct annotation); 2119b01141f4SArnaldo Carvalho de Melo symbol_conf.init_annotation = true; 2120b01141f4SArnaldo Carvalho de Melo return 0; 2121b01141f4SArnaldo Carvalho de Melo } 2122b01141f4SArnaldo Carvalho de Melo 2123ce80d3beSKan Liang int symbol__init(struct perf_env *env) 2124cc612d81SArnaldo Carvalho de Melo { 2125ec5761eaSDavid Ahern const char *symfs; 2126ec5761eaSDavid Ahern 212785e00b55SJovi Zhang if (symbol_conf.initialized) 212885e00b55SJovi Zhang return 0; 212985e00b55SJovi Zhang 21309ac3e487SIrina Tirdea symbol_conf.priv_size = PERF_ALIGN(symbol_conf.priv_size, sizeof(u64)); 21314d439517SDavid S. Miller 2132166ccc9cSNamhyung Kim symbol__elf_init(); 2133166ccc9cSNamhyung Kim 213475be6cf4SArnaldo Carvalho de Melo if (symbol_conf.sort_by_name) 213575be6cf4SArnaldo Carvalho de Melo symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) - 213679406cd7SArnaldo Carvalho de Melo sizeof(struct symbol)); 2137b32d133aSArnaldo Carvalho de Melo 21380a7e6d1bSNamhyung Kim if (symbol_conf.try_vmlinux_path && vmlinux_path__init(env) < 0) 2139cc612d81SArnaldo Carvalho de Melo return -1; 2140cc612d81SArnaldo Carvalho de Melo 2141c410a338SArnaldo Carvalho de Melo if (symbol_conf.field_sep && *symbol_conf.field_sep == '.') { 2142c410a338SArnaldo Carvalho de Melo pr_err("'.' is the only non valid --field-separator argument\n"); 2143c410a338SArnaldo Carvalho de Melo return -1; 2144c410a338SArnaldo Carvalho de Melo } 2145c410a338SArnaldo Carvalho de Melo 2146655000e7SArnaldo Carvalho de Melo if (setup_list(&symbol_conf.dso_list, 2147655000e7SArnaldo Carvalho de Melo symbol_conf.dso_list_str, "dso") < 0) 2148655000e7SArnaldo Carvalho de Melo return -1; 2149655000e7SArnaldo Carvalho de Melo 2150655000e7SArnaldo Carvalho de Melo if (setup_list(&symbol_conf.comm_list, 2151655000e7SArnaldo Carvalho de Melo symbol_conf.comm_list_str, "comm") < 0) 2152655000e7SArnaldo Carvalho de Melo goto out_free_dso_list; 2153655000e7SArnaldo Carvalho de Melo 2154e03eaa40SDavid Ahern if (setup_intlist(&symbol_conf.pid_list, 2155e03eaa40SDavid Ahern symbol_conf.pid_list_str, "pid") < 0) 2156e03eaa40SDavid Ahern goto out_free_comm_list; 2157e03eaa40SDavid Ahern 2158e03eaa40SDavid Ahern if (setup_intlist(&symbol_conf.tid_list, 2159e03eaa40SDavid Ahern symbol_conf.tid_list_str, "tid") < 0) 2160e03eaa40SDavid Ahern goto out_free_pid_list; 2161e03eaa40SDavid Ahern 2162655000e7SArnaldo Carvalho de Melo if (setup_list(&symbol_conf.sym_list, 2163655000e7SArnaldo Carvalho de Melo symbol_conf.sym_list_str, "symbol") < 0) 2164e03eaa40SDavid Ahern goto out_free_tid_list; 2165655000e7SArnaldo Carvalho de Melo 216664eff7d9SDavid Ahern if (setup_list(&symbol_conf.bt_stop_list, 216764eff7d9SDavid Ahern symbol_conf.bt_stop_list_str, "symbol") < 0) 216864eff7d9SDavid Ahern goto out_free_sym_list; 216964eff7d9SDavid Ahern 2170ec5761eaSDavid Ahern /* 2171ec5761eaSDavid Ahern * A path to symbols of "/" is identical to "" 2172ec5761eaSDavid Ahern * reset here for simplicity. 2173ec5761eaSDavid Ahern */ 2174ec5761eaSDavid Ahern symfs = realpath(symbol_conf.symfs, NULL); 2175ec5761eaSDavid Ahern if (symfs == NULL) 2176ec5761eaSDavid Ahern symfs = symbol_conf.symfs; 2177ec5761eaSDavid Ahern if (strcmp(symfs, "/") == 0) 2178ec5761eaSDavid Ahern symbol_conf.symfs = ""; 2179ec5761eaSDavid Ahern if (symfs != symbol_conf.symfs) 2180ec5761eaSDavid Ahern free((void *)symfs); 2181ec5761eaSDavid Ahern 2182ec80fde7SArnaldo Carvalho de Melo symbol_conf.kptr_restrict = symbol__read_kptr_restrict(); 2183ec80fde7SArnaldo Carvalho de Melo 218485e00b55SJovi Zhang symbol_conf.initialized = true; 21854aa65636SArnaldo Carvalho de Melo return 0; 2186655000e7SArnaldo Carvalho de Melo 218764eff7d9SDavid Ahern out_free_sym_list: 218864eff7d9SDavid Ahern strlist__delete(symbol_conf.sym_list); 2189e03eaa40SDavid Ahern out_free_tid_list: 2190e03eaa40SDavid Ahern intlist__delete(symbol_conf.tid_list); 2191e03eaa40SDavid Ahern out_free_pid_list: 2192e03eaa40SDavid Ahern intlist__delete(symbol_conf.pid_list); 2193655000e7SArnaldo Carvalho de Melo out_free_comm_list: 2194655000e7SArnaldo Carvalho de Melo strlist__delete(symbol_conf.comm_list); 2195d74c896bSNamhyung Kim out_free_dso_list: 2196d74c896bSNamhyung Kim strlist__delete(symbol_conf.dso_list); 2197655000e7SArnaldo Carvalho de Melo return -1; 2198cc612d81SArnaldo Carvalho de Melo } 2199cc612d81SArnaldo Carvalho de Melo 2200d65a458bSArnaldo Carvalho de Melo void symbol__exit(void) 2201d65a458bSArnaldo Carvalho de Melo { 220285e00b55SJovi Zhang if (!symbol_conf.initialized) 220385e00b55SJovi Zhang return; 220464eff7d9SDavid Ahern strlist__delete(symbol_conf.bt_stop_list); 2205d65a458bSArnaldo Carvalho de Melo strlist__delete(symbol_conf.sym_list); 2206d65a458bSArnaldo Carvalho de Melo strlist__delete(symbol_conf.dso_list); 2207d65a458bSArnaldo Carvalho de Melo strlist__delete(symbol_conf.comm_list); 2208e03eaa40SDavid Ahern intlist__delete(symbol_conf.tid_list); 2209e03eaa40SDavid Ahern intlist__delete(symbol_conf.pid_list); 2210d65a458bSArnaldo Carvalho de Melo vmlinux_path__exit(); 2211d65a458bSArnaldo Carvalho de Melo symbol_conf.sym_list = symbol_conf.dso_list = symbol_conf.comm_list = NULL; 221264eff7d9SDavid Ahern symbol_conf.bt_stop_list = NULL; 221385e00b55SJovi Zhang symbol_conf.initialized = false; 2214d65a458bSArnaldo Carvalho de Melo } 2215a7066709SHe Kuang 2216a7066709SHe Kuang int symbol__config_symfs(const struct option *opt __maybe_unused, 2217a7066709SHe Kuang const char *dir, int unset __maybe_unused) 2218a7066709SHe Kuang { 2219a7066709SHe Kuang char *bf = NULL; 2220a7066709SHe Kuang int ret; 2221a7066709SHe Kuang 2222a7066709SHe Kuang symbol_conf.symfs = strdup(dir); 2223a7066709SHe Kuang if (symbol_conf.symfs == NULL) 2224a7066709SHe Kuang return -ENOMEM; 2225a7066709SHe Kuang 2226a7066709SHe Kuang /* skip the locally configured cache if a symfs is given, and 2227a7066709SHe Kuang * config buildid dir to symfs/.debug 2228a7066709SHe Kuang */ 2229a7066709SHe Kuang ret = asprintf(&bf, "%s/%s", dir, ".debug"); 2230a7066709SHe Kuang if (ret < 0) 2231a7066709SHe Kuang return -ENOMEM; 2232a7066709SHe Kuang 2233a7066709SHe Kuang set_buildid_dir(bf); 2234a7066709SHe Kuang 2235a7066709SHe Kuang free(bf); 2236a7066709SHe Kuang return 0; 2237a7066709SHe Kuang } 22389f87498fSJiri Olsa 22399f87498fSJiri Olsa struct mem_info *mem_info__get(struct mem_info *mi) 22409f87498fSJiri Olsa { 22419f87498fSJiri Olsa if (mi) 22429f87498fSJiri Olsa refcount_inc(&mi->refcnt); 22439f87498fSJiri Olsa return mi; 22449f87498fSJiri Olsa } 22459f87498fSJiri Olsa 22469f87498fSJiri Olsa void mem_info__put(struct mem_info *mi) 22479f87498fSJiri Olsa { 22489f87498fSJiri Olsa if (mi && refcount_dec_and_test(&mi->refcnt)) 22499f87498fSJiri Olsa free(mi); 22509f87498fSJiri Olsa } 22519f87498fSJiri Olsa 22529f87498fSJiri Olsa struct mem_info *mem_info__new(void) 22539f87498fSJiri Olsa { 22549f87498fSJiri Olsa struct mem_info *mi = zalloc(sizeof(*mi)); 22559f87498fSJiri Olsa 22569f87498fSJiri Olsa if (mi) 22579f87498fSJiri Olsa refcount_set(&mi->refcnt, 1); 22589f87498fSJiri Olsa return mi; 22599f87498fSJiri Olsa } 2260