15aab621bSArnaldo Carvalho de Melo #include <dirent.h> 25aab621bSArnaldo Carvalho de Melo #include <errno.h> 35aab621bSArnaldo Carvalho de Melo #include <stdlib.h> 45aab621bSArnaldo Carvalho de Melo #include <stdio.h> 55aab621bSArnaldo Carvalho de Melo #include <string.h> 65aab621bSArnaldo Carvalho de Melo #include <sys/types.h> 75aab621bSArnaldo Carvalho de Melo #include <sys/stat.h> 85aab621bSArnaldo Carvalho de Melo #include <sys/param.h> 95aab621bSArnaldo Carvalho de Melo #include <fcntl.h> 105aab621bSArnaldo Carvalho de Melo #include <unistd.h> 119486aa38SArnaldo Carvalho de Melo #include <inttypes.h> 12b01141f4SArnaldo Carvalho de Melo #include "annotate.h" 13b36f19d5SArnaldo Carvalho de Melo #include "build-id.h" 14e334c726SNamhyung Kim #include "util.h" 158a6c5b26SArnaldo Carvalho de Melo #include "debug.h" 1669d2591aSArnaldo Carvalho de Melo #include "machine.h" 1786470930SIngo Molnar #include "symbol.h" 185aab621bSArnaldo Carvalho de Melo #include "strlist.h" 19e03eaa40SDavid Ahern #include "intlist.h" 200a7e6d1bSNamhyung Kim #include "header.h" 2186470930SIngo Molnar 2286470930SIngo Molnar #include <elf.h> 23f1617b40SArnaldo Carvalho de Melo #include <limits.h> 24c506c96bSArnaldo Carvalho de Melo #include <symbol/kallsyms.h> 25439d473bSArnaldo Carvalho de Melo #include <sys/utsname.h> 262cdbc46dSPeter Zijlstra 27aeafcbafSArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *dso, struct map *map, 289de89fe7SArnaldo Carvalho de Melo symbol_filter_t filter); 29aeafcbafSArnaldo Carvalho de Melo static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map, 30a1645ce1SZhang, Yanmin symbol_filter_t filter); 313f067dcaSArnaldo Carvalho de Melo int vmlinux_path__nr_entries; 323f067dcaSArnaldo Carvalho de Melo char **vmlinux_path; 33439d473bSArnaldo Carvalho de Melo 3475be6cf4SArnaldo Carvalho de Melo struct symbol_conf symbol_conf = { 35b32d133aSArnaldo Carvalho de Melo .use_modules = true, 36b32d133aSArnaldo Carvalho de Melo .try_vmlinux_path = true, 373e6a2a7fSStephane Eranian .annotate_src = true, 38328ccdacSNamhyung Kim .demangle = true, 39763122adSAvi Kivity .demangle_kernel = false, 40e511db5eSNamhyung Kim .cumulate_callchain = true, 41c8302367SJiri Olsa .show_hist_headers = true, 42ec5761eaSDavid Ahern .symfs = "", 431e9abf8bSNamhyung Kim .event_group = true, 44b32d133aSArnaldo Carvalho de Melo }; 45b32d133aSArnaldo Carvalho de Melo 4644f24cb3SJiri Olsa static enum dso_binary_type binary_type_symtab[] = { 4744f24cb3SJiri Olsa DSO_BINARY_TYPE__KALLSYMS, 4844f24cb3SJiri Olsa DSO_BINARY_TYPE__GUEST_KALLSYMS, 4944f24cb3SJiri Olsa DSO_BINARY_TYPE__JAVA_JIT, 5044f24cb3SJiri Olsa DSO_BINARY_TYPE__DEBUGLINK, 5144f24cb3SJiri Olsa DSO_BINARY_TYPE__BUILD_ID_CACHE, 5244f24cb3SJiri Olsa DSO_BINARY_TYPE__FEDORA_DEBUGINFO, 5344f24cb3SJiri Olsa DSO_BINARY_TYPE__UBUNTU_DEBUGINFO, 5444f24cb3SJiri Olsa DSO_BINARY_TYPE__BUILDID_DEBUGINFO, 5544f24cb3SJiri Olsa DSO_BINARY_TYPE__SYSTEM_PATH_DSO, 5644f24cb3SJiri Olsa DSO_BINARY_TYPE__GUEST_KMODULE, 57c00c48fcSNamhyung Kim DSO_BINARY_TYPE__GUEST_KMODULE_COMP, 5844f24cb3SJiri Olsa DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE, 59c00c48fcSNamhyung Kim DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP, 609cd00941SRicardo Ribalda Delgado DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO, 6144f24cb3SJiri Olsa DSO_BINARY_TYPE__NOT_FOUND, 6244f24cb3SJiri Olsa }; 6344f24cb3SJiri Olsa 64028df767SJiri Olsa #define DSO_BINARY_TYPE__SYMTAB_CNT ARRAY_SIZE(binary_type_symtab) 6544f24cb3SJiri Olsa 6636a3e646SArnaldo Carvalho de Melo bool symbol_type__is_a(char symbol_type, enum map_type map_type) 676893d4eeSArnaldo Carvalho de Melo { 6831877908SAnton Blanchard symbol_type = toupper(symbol_type); 6931877908SAnton Blanchard 706893d4eeSArnaldo Carvalho de Melo switch (map_type) { 716893d4eeSArnaldo Carvalho de Melo case MAP__FUNCTION: 726893d4eeSArnaldo Carvalho de Melo return symbol_type == 'T' || symbol_type == 'W'; 73f1dfa0b1SArnaldo Carvalho de Melo case MAP__VARIABLE: 7431877908SAnton Blanchard return symbol_type == 'D'; 756893d4eeSArnaldo Carvalho de Melo default: 766893d4eeSArnaldo Carvalho de Melo return false; 776893d4eeSArnaldo Carvalho de Melo } 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 90fb6d5942SNaveen N. Rao int __weak arch__choose_best_symbol(struct symbol *syma, 91fb6d5942SNaveen N. Rao struct symbol *symb __maybe_unused) 92fb6d5942SNaveen N. Rao { 93fb6d5942SNaveen N. Rao /* Avoid "SyS" kernel syscall aliases */ 94fb6d5942SNaveen N. Rao if (strlen(syma->name) >= 3 && !strncmp(syma->name, "SyS", 3)) 95fb6d5942SNaveen N. Rao return SYMBOL_B; 96fb6d5942SNaveen N. Rao if (strlen(syma->name) >= 10 && !strncmp(syma->name, "compat_SyS", 10)) 97fb6d5942SNaveen N. Rao return SYMBOL_B; 98fb6d5942SNaveen N. Rao 99fb6d5942SNaveen N. Rao return SYMBOL_A; 100fb6d5942SNaveen N. Rao } 101694bf407SAnton Blanchard 102694bf407SAnton Blanchard static int choose_best_symbol(struct symbol *syma, struct symbol *symb) 103694bf407SAnton Blanchard { 104694bf407SAnton Blanchard s64 a; 105694bf407SAnton Blanchard s64 b; 1063445432bSAdrian Hunter size_t na, nb; 107694bf407SAnton Blanchard 108694bf407SAnton Blanchard /* Prefer a symbol with non zero length */ 109694bf407SAnton Blanchard a = syma->end - syma->start; 110694bf407SAnton Blanchard b = symb->end - symb->start; 111694bf407SAnton Blanchard if ((b == 0) && (a > 0)) 112694bf407SAnton Blanchard return SYMBOL_A; 113694bf407SAnton Blanchard else if ((a == 0) && (b > 0)) 114694bf407SAnton Blanchard return SYMBOL_B; 115694bf407SAnton Blanchard 116694bf407SAnton Blanchard /* Prefer a non weak symbol over a weak one */ 117694bf407SAnton Blanchard a = syma->binding == STB_WEAK; 118694bf407SAnton Blanchard b = symb->binding == STB_WEAK; 119694bf407SAnton Blanchard if (b && !a) 120694bf407SAnton Blanchard return SYMBOL_A; 121694bf407SAnton Blanchard if (a && !b) 122694bf407SAnton Blanchard return SYMBOL_B; 123694bf407SAnton Blanchard 124694bf407SAnton Blanchard /* Prefer a global symbol over a non global one */ 125694bf407SAnton Blanchard a = syma->binding == STB_GLOBAL; 126694bf407SAnton Blanchard b = symb->binding == STB_GLOBAL; 127694bf407SAnton Blanchard if (a && !b) 128694bf407SAnton Blanchard return SYMBOL_A; 129694bf407SAnton Blanchard if (b && !a) 130694bf407SAnton Blanchard return SYMBOL_B; 131694bf407SAnton Blanchard 132694bf407SAnton Blanchard /* Prefer a symbol with less underscores */ 133694bf407SAnton Blanchard a = prefix_underscores_count(syma->name); 134694bf407SAnton Blanchard b = prefix_underscores_count(symb->name); 135694bf407SAnton Blanchard if (b > a) 136694bf407SAnton Blanchard return SYMBOL_A; 137694bf407SAnton Blanchard else if (a > b) 138694bf407SAnton Blanchard return SYMBOL_B; 139694bf407SAnton Blanchard 1403445432bSAdrian Hunter /* Choose the symbol with the longest name */ 1413445432bSAdrian Hunter na = strlen(syma->name); 1423445432bSAdrian Hunter nb = strlen(symb->name); 1433445432bSAdrian Hunter if (na > nb) 144694bf407SAnton Blanchard return SYMBOL_A; 1453445432bSAdrian Hunter else if (na < nb) 146694bf407SAnton Blanchard return SYMBOL_B; 1473445432bSAdrian Hunter 148fb6d5942SNaveen N. Rao return arch__choose_best_symbol(syma, symb); 149694bf407SAnton Blanchard } 150694bf407SAnton Blanchard 151e5a1845fSNamhyung Kim void symbols__fixup_duplicate(struct rb_root *symbols) 152694bf407SAnton Blanchard { 153694bf407SAnton Blanchard struct rb_node *nd; 154694bf407SAnton Blanchard struct symbol *curr, *next; 155694bf407SAnton Blanchard 156c97b40e4SArnaldo Carvalho de Melo if (symbol_conf.allow_aliases) 157c97b40e4SArnaldo Carvalho de Melo return; 158c97b40e4SArnaldo Carvalho de Melo 159694bf407SAnton Blanchard nd = rb_first(symbols); 160694bf407SAnton Blanchard 161694bf407SAnton Blanchard while (nd) { 162694bf407SAnton Blanchard curr = rb_entry(nd, struct symbol, rb_node); 163694bf407SAnton Blanchard again: 164694bf407SAnton Blanchard nd = rb_next(&curr->rb_node); 165694bf407SAnton Blanchard next = rb_entry(nd, struct symbol, rb_node); 166694bf407SAnton Blanchard 167694bf407SAnton Blanchard if (!nd) 168694bf407SAnton Blanchard break; 169694bf407SAnton Blanchard 170694bf407SAnton Blanchard if (curr->start != next->start) 171694bf407SAnton Blanchard continue; 172694bf407SAnton Blanchard 173694bf407SAnton Blanchard if (choose_best_symbol(curr, next) == SYMBOL_A) { 174694bf407SAnton Blanchard rb_erase(&next->rb_node, symbols); 175d4f74eb8SChenggang Qin symbol__delete(next); 176694bf407SAnton Blanchard goto again; 177694bf407SAnton Blanchard } else { 178694bf407SAnton Blanchard nd = rb_next(&curr->rb_node); 179694bf407SAnton Blanchard rb_erase(&curr->rb_node, symbols); 180d4f74eb8SChenggang Qin symbol__delete(curr); 181694bf407SAnton Blanchard } 182694bf407SAnton Blanchard } 183694bf407SAnton Blanchard } 184694bf407SAnton Blanchard 185e5a1845fSNamhyung Kim void symbols__fixup_end(struct rb_root *symbols) 186af427bf5SArnaldo Carvalho de Melo { 187aeafcbafSArnaldo Carvalho de Melo struct rb_node *nd, *prevnd = rb_first(symbols); 1882e538c4aSArnaldo Carvalho de Melo struct symbol *curr, *prev; 189af427bf5SArnaldo Carvalho de Melo 190af427bf5SArnaldo Carvalho de Melo if (prevnd == NULL) 191af427bf5SArnaldo Carvalho de Melo return; 192af427bf5SArnaldo Carvalho de Melo 1932e538c4aSArnaldo Carvalho de Melo curr = rb_entry(prevnd, struct symbol, rb_node); 1942e538c4aSArnaldo Carvalho de Melo 195af427bf5SArnaldo Carvalho de Melo for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) { 1962e538c4aSArnaldo Carvalho de Melo prev = curr; 1972e538c4aSArnaldo Carvalho de Melo curr = rb_entry(nd, struct symbol, rb_node); 198af427bf5SArnaldo Carvalho de Melo 1993b01a413SArnaldo Carvalho de Melo if (prev->end == prev->start && prev->end != curr->start) 2002c241bd3SArnaldo Carvalho de Melo prev->end = curr->start; 201af427bf5SArnaldo Carvalho de Melo } 202af427bf5SArnaldo Carvalho de Melo 2032e538c4aSArnaldo Carvalho de Melo /* Last entry */ 2042e538c4aSArnaldo Carvalho de Melo if (curr->end == curr->start) 2052e538c4aSArnaldo Carvalho de Melo curr->end = roundup(curr->start, 4096); 2062e538c4aSArnaldo Carvalho de Melo } 2072e538c4aSArnaldo Carvalho de Melo 208e5a1845fSNamhyung Kim void __map_groups__fixup_end(struct map_groups *mg, enum map_type type) 209af427bf5SArnaldo Carvalho de Melo { 2101eee78aeSArnaldo Carvalho de Melo struct maps *maps = &mg->maps[type]; 2114bb7123dSArnaldo Carvalho de Melo struct map *next, *curr; 212af427bf5SArnaldo Carvalho de Melo 2136a2ffcddSArnaldo Carvalho de Melo pthread_rwlock_wrlock(&maps->lock); 2146a2ffcddSArnaldo Carvalho de Melo 2154bb7123dSArnaldo Carvalho de Melo curr = maps__first(maps); 2164bb7123dSArnaldo Carvalho de Melo if (curr == NULL) 2176a2ffcddSArnaldo Carvalho de Melo goto out_unlock; 218af427bf5SArnaldo Carvalho de Melo 2194bb7123dSArnaldo Carvalho de Melo for (next = map__next(curr); next; next = map__next(curr)) { 2204bb7123dSArnaldo Carvalho de Melo curr->end = next->start; 2214bb7123dSArnaldo Carvalho de Melo curr = next; 2222e538c4aSArnaldo Carvalho de Melo } 22390c83218SArnaldo Carvalho de Melo 22490c83218SArnaldo Carvalho de Melo /* 22590c83218SArnaldo Carvalho de Melo * We still haven't the actual symbols, so guess the 22690c83218SArnaldo Carvalho de Melo * last map final address. 22790c83218SArnaldo Carvalho de Melo */ 2289d1faba5SIan Munsie curr->end = ~0ULL; 2296a2ffcddSArnaldo Carvalho de Melo 2306a2ffcddSArnaldo Carvalho de Melo out_unlock: 2316a2ffcddSArnaldo Carvalho de Melo pthread_rwlock_unlock(&maps->lock); 232af427bf5SArnaldo Carvalho de Melo } 233af427bf5SArnaldo Carvalho de Melo 234e5a1845fSNamhyung Kim struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name) 23586470930SIngo Molnar { 23686470930SIngo Molnar size_t namelen = strlen(name) + 1; 237aeafcbafSArnaldo Carvalho de Melo struct symbol *sym = calloc(1, (symbol_conf.priv_size + 238aeafcbafSArnaldo Carvalho de Melo sizeof(*sym) + namelen)); 239aeafcbafSArnaldo Carvalho de Melo if (sym == NULL) 24086470930SIngo Molnar return NULL; 24186470930SIngo Molnar 242b01141f4SArnaldo Carvalho de Melo if (symbol_conf.priv_size) { 243b01141f4SArnaldo Carvalho de Melo if (symbol_conf.init_annotation) { 244b01141f4SArnaldo Carvalho de Melo struct annotation *notes = (void *)sym; 245b01141f4SArnaldo Carvalho de Melo pthread_mutex_init(¬es->lock, NULL); 246b01141f4SArnaldo Carvalho de Melo } 247aeafcbafSArnaldo Carvalho de Melo sym = ((void *)sym) + symbol_conf.priv_size; 248b01141f4SArnaldo Carvalho de Melo } 24936479484SArnaldo Carvalho de Melo 250aeafcbafSArnaldo Carvalho de Melo sym->start = start; 2512c241bd3SArnaldo Carvalho de Melo sym->end = len ? start + len : start; 252aeafcbafSArnaldo Carvalho de Melo sym->binding = binding; 253aeafcbafSArnaldo Carvalho de Melo sym->namelen = namelen - 1; 254e4204992SArnaldo Carvalho de Melo 255aeafcbafSArnaldo Carvalho de Melo pr_debug4("%s: %s %#" PRIx64 "-%#" PRIx64 "\n", 256aeafcbafSArnaldo Carvalho de Melo __func__, name, start, sym->end); 257aeafcbafSArnaldo Carvalho de Melo memcpy(sym->name, name, namelen); 258e4204992SArnaldo Carvalho de Melo 259aeafcbafSArnaldo Carvalho de Melo return sym; 26086470930SIngo Molnar } 26186470930SIngo Molnar 262aeafcbafSArnaldo Carvalho de Melo void symbol__delete(struct symbol *sym) 26386470930SIngo Molnar { 264aeafcbafSArnaldo Carvalho de Melo free(((void *)sym) - symbol_conf.priv_size); 26586470930SIngo Molnar } 26686470930SIngo Molnar 267cdd059d7SJiri Olsa void symbols__delete(struct rb_root *symbols) 26886470930SIngo Molnar { 26986470930SIngo Molnar struct symbol *pos; 270aeafcbafSArnaldo Carvalho de Melo struct rb_node *next = rb_first(symbols); 27186470930SIngo Molnar 27286470930SIngo Molnar while (next) { 27386470930SIngo Molnar pos = rb_entry(next, struct symbol, rb_node); 27486470930SIngo Molnar next = rb_next(&pos->rb_node); 275aeafcbafSArnaldo Carvalho de Melo rb_erase(&pos->rb_node, symbols); 27600a192b3SArnaldo Carvalho de Melo symbol__delete(pos); 27786470930SIngo Molnar } 27886470930SIngo Molnar } 27986470930SIngo Molnar 280e5a1845fSNamhyung Kim void symbols__insert(struct rb_root *symbols, struct symbol *sym) 28186470930SIngo Molnar { 282aeafcbafSArnaldo Carvalho de Melo struct rb_node **p = &symbols->rb_node; 28386470930SIngo Molnar struct rb_node *parent = NULL; 2849cffa8d5SPaul Mackerras const u64 ip = sym->start; 28586470930SIngo Molnar struct symbol *s; 28686470930SIngo Molnar 28786470930SIngo Molnar while (*p != NULL) { 28886470930SIngo Molnar parent = *p; 28986470930SIngo Molnar s = rb_entry(parent, struct symbol, rb_node); 29086470930SIngo Molnar if (ip < s->start) 29186470930SIngo Molnar p = &(*p)->rb_left; 29286470930SIngo Molnar else 29386470930SIngo Molnar p = &(*p)->rb_right; 29486470930SIngo Molnar } 29586470930SIngo Molnar rb_link_node(&sym->rb_node, parent, p); 296aeafcbafSArnaldo Carvalho de Melo rb_insert_color(&sym->rb_node, symbols); 29786470930SIngo Molnar } 29886470930SIngo Molnar 299aeafcbafSArnaldo Carvalho de Melo static struct symbol *symbols__find(struct rb_root *symbols, u64 ip) 30086470930SIngo Molnar { 30186470930SIngo Molnar struct rb_node *n; 30286470930SIngo Molnar 303aeafcbafSArnaldo Carvalho de Melo if (symbols == NULL) 30486470930SIngo Molnar return NULL; 30586470930SIngo Molnar 306aeafcbafSArnaldo Carvalho de Melo n = symbols->rb_node; 30786470930SIngo Molnar 30886470930SIngo Molnar while (n) { 30986470930SIngo Molnar struct symbol *s = rb_entry(n, struct symbol, rb_node); 31086470930SIngo Molnar 31186470930SIngo Molnar if (ip < s->start) 31286470930SIngo Molnar n = n->rb_left; 3139c7b37cdSChris Phlipot else if (ip > s->end || (ip == s->end && ip != s->start)) 31486470930SIngo Molnar n = n->rb_right; 31586470930SIngo Molnar else 31686470930SIngo Molnar return s; 31786470930SIngo Molnar } 31886470930SIngo Molnar 31986470930SIngo Molnar return NULL; 32086470930SIngo Molnar } 32186470930SIngo Molnar 3228e0cf965SAdrian Hunter static struct symbol *symbols__first(struct rb_root *symbols) 3238e0cf965SAdrian Hunter { 3248e0cf965SAdrian Hunter struct rb_node *n = rb_first(symbols); 3258e0cf965SAdrian Hunter 3268e0cf965SAdrian Hunter if (n) 3278e0cf965SAdrian Hunter return rb_entry(n, struct symbol, rb_node); 3288e0cf965SAdrian Hunter 3298e0cf965SAdrian Hunter return NULL; 3308e0cf965SAdrian Hunter } 3318e0cf965SAdrian Hunter 3329c00a81bSAdrian Hunter static struct symbol *symbols__next(struct symbol *sym) 3339c00a81bSAdrian Hunter { 3349c00a81bSAdrian Hunter struct rb_node *n = rb_next(&sym->rb_node); 3359c00a81bSAdrian Hunter 3369c00a81bSAdrian Hunter if (n) 3379c00a81bSAdrian Hunter return rb_entry(n, struct symbol, rb_node); 3389c00a81bSAdrian Hunter 3399c00a81bSAdrian Hunter return NULL; 3409c00a81bSAdrian Hunter } 3419c00a81bSAdrian Hunter 342aeafcbafSArnaldo Carvalho de Melo static void symbols__insert_by_name(struct rb_root *symbols, struct symbol *sym) 34379406cd7SArnaldo Carvalho de Melo { 344aeafcbafSArnaldo Carvalho de Melo struct rb_node **p = &symbols->rb_node; 34579406cd7SArnaldo Carvalho de Melo struct rb_node *parent = NULL; 34602a9d037SRabin Vincent struct symbol_name_rb_node *symn, *s; 34702a9d037SRabin Vincent 34802a9d037SRabin Vincent symn = container_of(sym, struct symbol_name_rb_node, sym); 34979406cd7SArnaldo Carvalho de Melo 35079406cd7SArnaldo Carvalho de Melo while (*p != NULL) { 35179406cd7SArnaldo Carvalho de Melo parent = *p; 35279406cd7SArnaldo Carvalho de Melo s = rb_entry(parent, struct symbol_name_rb_node, rb_node); 35379406cd7SArnaldo Carvalho de Melo if (strcmp(sym->name, s->sym.name) < 0) 35479406cd7SArnaldo Carvalho de Melo p = &(*p)->rb_left; 35579406cd7SArnaldo Carvalho de Melo else 35679406cd7SArnaldo Carvalho de Melo p = &(*p)->rb_right; 35779406cd7SArnaldo Carvalho de Melo } 35879406cd7SArnaldo Carvalho de Melo rb_link_node(&symn->rb_node, parent, p); 359aeafcbafSArnaldo Carvalho de Melo rb_insert_color(&symn->rb_node, symbols); 36079406cd7SArnaldo Carvalho de Melo } 36179406cd7SArnaldo Carvalho de Melo 362aeafcbafSArnaldo Carvalho de Melo static void symbols__sort_by_name(struct rb_root *symbols, 363aeafcbafSArnaldo Carvalho de Melo struct rb_root *source) 36479406cd7SArnaldo Carvalho de Melo { 36579406cd7SArnaldo Carvalho de Melo struct rb_node *nd; 36679406cd7SArnaldo Carvalho de Melo 36779406cd7SArnaldo Carvalho de Melo for (nd = rb_first(source); nd; nd = rb_next(nd)) { 36879406cd7SArnaldo Carvalho de Melo struct symbol *pos = rb_entry(nd, struct symbol, rb_node); 369aeafcbafSArnaldo Carvalho de Melo symbols__insert_by_name(symbols, pos); 37079406cd7SArnaldo Carvalho de Melo } 37179406cd7SArnaldo Carvalho de Melo } 37279406cd7SArnaldo Carvalho de Melo 373aeafcbafSArnaldo Carvalho de Melo static struct symbol *symbols__find_by_name(struct rb_root *symbols, 374aeafcbafSArnaldo Carvalho de Melo const char *name) 37579406cd7SArnaldo Carvalho de Melo { 37679406cd7SArnaldo Carvalho de Melo struct rb_node *n; 3775bcaaca3SMartin Liška struct symbol_name_rb_node *s = NULL; 37879406cd7SArnaldo Carvalho de Melo 379aeafcbafSArnaldo Carvalho de Melo if (symbols == NULL) 38079406cd7SArnaldo Carvalho de Melo return NULL; 38179406cd7SArnaldo Carvalho de Melo 382aeafcbafSArnaldo Carvalho de Melo n = symbols->rb_node; 38379406cd7SArnaldo Carvalho de Melo 38479406cd7SArnaldo Carvalho de Melo while (n) { 38579406cd7SArnaldo Carvalho de Melo int cmp; 38679406cd7SArnaldo Carvalho de Melo 38779406cd7SArnaldo Carvalho de Melo s = rb_entry(n, struct symbol_name_rb_node, rb_node); 388031b84c4SNaveen N. Rao cmp = arch__compare_symbol_names(name, s->sym.name); 38979406cd7SArnaldo Carvalho de Melo 39079406cd7SArnaldo Carvalho de Melo if (cmp < 0) 39179406cd7SArnaldo Carvalho de Melo n = n->rb_left; 39279406cd7SArnaldo Carvalho de Melo else if (cmp > 0) 39379406cd7SArnaldo Carvalho de Melo n = n->rb_right; 39479406cd7SArnaldo Carvalho de Melo else 395de480999SNamhyung Kim break; 39679406cd7SArnaldo Carvalho de Melo } 39779406cd7SArnaldo Carvalho de Melo 398de480999SNamhyung Kim if (n == NULL) 39979406cd7SArnaldo Carvalho de Melo return NULL; 400de480999SNamhyung Kim 401de480999SNamhyung Kim /* return first symbol that has same name (if any) */ 402de480999SNamhyung Kim for (n = rb_prev(n); n; n = rb_prev(n)) { 403de480999SNamhyung Kim struct symbol_name_rb_node *tmp; 404de480999SNamhyung Kim 405de480999SNamhyung Kim tmp = rb_entry(n, struct symbol_name_rb_node, rb_node); 406031b84c4SNaveen N. Rao if (arch__compare_symbol_names(tmp->sym.name, s->sym.name)) 407de480999SNamhyung Kim break; 408de480999SNamhyung Kim 409de480999SNamhyung Kim s = tmp; 410de480999SNamhyung Kim } 411de480999SNamhyung Kim 412de480999SNamhyung Kim return &s->sym; 41379406cd7SArnaldo Carvalho de Melo } 41479406cd7SArnaldo Carvalho de Melo 415c0b4dffbSArnaldo Carvalho de Melo void dso__reset_find_symbol_cache(struct dso *dso) 416c0b4dffbSArnaldo Carvalho de Melo { 417c0b4dffbSArnaldo Carvalho de Melo enum map_type type; 418c0b4dffbSArnaldo Carvalho de Melo 419c0b4dffbSArnaldo Carvalho de Melo for (type = MAP__FUNCTION; type <= MAP__VARIABLE; ++type) { 420c0b4dffbSArnaldo Carvalho de Melo dso->last_find_result[type].addr = 0; 421c0b4dffbSArnaldo Carvalho de Melo dso->last_find_result[type].symbol = NULL; 422c0b4dffbSArnaldo Carvalho de Melo } 423c0b4dffbSArnaldo Carvalho de Melo } 424c0b4dffbSArnaldo Carvalho de Melo 425ae93a6c7SChris Phlipot void dso__insert_symbol(struct dso *dso, enum map_type type, struct symbol *sym) 426ae93a6c7SChris Phlipot { 427ae93a6c7SChris Phlipot symbols__insert(&dso->symbols[type], sym); 428ae93a6c7SChris Phlipot 429ae93a6c7SChris Phlipot /* update the symbol cache if necessary */ 430ae93a6c7SChris Phlipot if (dso->last_find_result[type].addr >= sym->start && 431ae93a6c7SChris Phlipot (dso->last_find_result[type].addr < sym->end || 432ae93a6c7SChris Phlipot sym->start == sym->end)) { 433ae93a6c7SChris Phlipot dso->last_find_result[type].symbol = sym; 434ae93a6c7SChris Phlipot } 435ae93a6c7SChris Phlipot } 436ae93a6c7SChris Phlipot 437aeafcbafSArnaldo Carvalho de Melo struct symbol *dso__find_symbol(struct dso *dso, 43879406cd7SArnaldo Carvalho de Melo enum map_type type, u64 addr) 439fcf1203aSArnaldo Carvalho de Melo { 440b685ac22SArnaldo Carvalho de Melo if (dso->last_find_result[type].addr != addr) { 441b685ac22SArnaldo Carvalho de Melo dso->last_find_result[type].addr = addr; 442b685ac22SArnaldo Carvalho de Melo dso->last_find_result[type].symbol = symbols__find(&dso->symbols[type], addr); 443b685ac22SArnaldo Carvalho de Melo } 444b685ac22SArnaldo Carvalho de Melo 445b685ac22SArnaldo Carvalho de Melo return dso->last_find_result[type].symbol; 446fcf1203aSArnaldo Carvalho de Melo } 447fcf1203aSArnaldo Carvalho de Melo 4489c00a81bSAdrian Hunter struct symbol *dso__first_symbol(struct dso *dso, enum map_type type) 4498e0cf965SAdrian Hunter { 4508e0cf965SAdrian Hunter return symbols__first(&dso->symbols[type]); 4518e0cf965SAdrian Hunter } 4528e0cf965SAdrian Hunter 4539c00a81bSAdrian Hunter struct symbol *dso__next_symbol(struct symbol *sym) 4549c00a81bSAdrian Hunter { 4559c00a81bSAdrian Hunter return symbols__next(sym); 4569c00a81bSAdrian Hunter } 4579c00a81bSAdrian Hunter 45818bd7264SArnaldo Carvalho de Melo struct symbol *symbol__next_by_name(struct symbol *sym) 45918bd7264SArnaldo Carvalho de Melo { 46018bd7264SArnaldo Carvalho de Melo struct symbol_name_rb_node *s = container_of(sym, struct symbol_name_rb_node, sym); 46118bd7264SArnaldo Carvalho de Melo struct rb_node *n = rb_next(&s->rb_node); 46218bd7264SArnaldo Carvalho de Melo 46318bd7264SArnaldo Carvalho de Melo return n ? &rb_entry(n, struct symbol_name_rb_node, rb_node)->sym : NULL; 46418bd7264SArnaldo Carvalho de Melo } 46518bd7264SArnaldo Carvalho de Melo 46618bd7264SArnaldo Carvalho de Melo /* 46718bd7264SArnaldo Carvalho de Melo * Teturns first symbol that matched with @name. 46818bd7264SArnaldo Carvalho de Melo */ 469aeafcbafSArnaldo Carvalho de Melo struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type, 47079406cd7SArnaldo Carvalho de Melo const char *name) 47179406cd7SArnaldo Carvalho de Melo { 472aeafcbafSArnaldo Carvalho de Melo return symbols__find_by_name(&dso->symbol_names[type], name); 47379406cd7SArnaldo Carvalho de Melo } 47479406cd7SArnaldo Carvalho de Melo 475aeafcbafSArnaldo Carvalho de Melo void dso__sort_by_name(struct dso *dso, enum map_type type) 47679406cd7SArnaldo Carvalho de Melo { 477aeafcbafSArnaldo Carvalho de Melo dso__set_sorted_by_name(dso, type); 478aeafcbafSArnaldo Carvalho de Melo return symbols__sort_by_name(&dso->symbol_names[type], 479aeafcbafSArnaldo Carvalho de Melo &dso->symbols[type]); 48079406cd7SArnaldo Carvalho de Melo } 48179406cd7SArnaldo Carvalho de Melo 482316d70d6SAdrian Hunter int modules__parse(const char *filename, void *arg, 483316d70d6SAdrian Hunter int (*process_module)(void *arg, const char *name, 484316d70d6SAdrian Hunter u64 start)) 485316d70d6SAdrian Hunter { 486316d70d6SAdrian Hunter char *line = NULL; 487316d70d6SAdrian Hunter size_t n; 488316d70d6SAdrian Hunter FILE *file; 489316d70d6SAdrian Hunter int err = 0; 490316d70d6SAdrian Hunter 491316d70d6SAdrian Hunter file = fopen(filename, "r"); 492316d70d6SAdrian Hunter if (file == NULL) 493316d70d6SAdrian Hunter return -1; 494316d70d6SAdrian Hunter 495316d70d6SAdrian Hunter while (1) { 496316d70d6SAdrian Hunter char name[PATH_MAX]; 497316d70d6SAdrian Hunter u64 start; 498316d70d6SAdrian Hunter char *sep; 499316d70d6SAdrian Hunter ssize_t line_len; 500316d70d6SAdrian Hunter 501316d70d6SAdrian Hunter line_len = getline(&line, &n, file); 502316d70d6SAdrian Hunter if (line_len < 0) { 503316d70d6SAdrian Hunter if (feof(file)) 504316d70d6SAdrian Hunter break; 505316d70d6SAdrian Hunter err = -1; 506316d70d6SAdrian Hunter goto out; 507316d70d6SAdrian Hunter } 508316d70d6SAdrian Hunter 509316d70d6SAdrian Hunter if (!line) { 510316d70d6SAdrian Hunter err = -1; 511316d70d6SAdrian Hunter goto out; 512316d70d6SAdrian Hunter } 513316d70d6SAdrian Hunter 514316d70d6SAdrian Hunter line[--line_len] = '\0'; /* \n */ 515316d70d6SAdrian Hunter 516316d70d6SAdrian Hunter sep = strrchr(line, 'x'); 517316d70d6SAdrian Hunter if (sep == NULL) 518316d70d6SAdrian Hunter continue; 519316d70d6SAdrian Hunter 520316d70d6SAdrian Hunter hex2u64(sep + 1, &start); 521316d70d6SAdrian Hunter 522316d70d6SAdrian Hunter sep = strchr(line, ' '); 523316d70d6SAdrian Hunter if (sep == NULL) 524316d70d6SAdrian Hunter continue; 525316d70d6SAdrian Hunter 526316d70d6SAdrian Hunter *sep = '\0'; 527316d70d6SAdrian Hunter 528316d70d6SAdrian Hunter scnprintf(name, sizeof(name), "[%s]", line); 529316d70d6SAdrian Hunter 530316d70d6SAdrian Hunter err = process_module(arg, name, start); 531316d70d6SAdrian Hunter if (err) 532316d70d6SAdrian Hunter break; 533316d70d6SAdrian Hunter } 534316d70d6SAdrian Hunter out: 535316d70d6SAdrian Hunter free(line); 536316d70d6SAdrian Hunter fclose(file); 537316d70d6SAdrian Hunter return err; 538316d70d6SAdrian Hunter } 539316d70d6SAdrian Hunter 540682b335aSArnaldo Carvalho de Melo struct process_kallsyms_args { 541682b335aSArnaldo Carvalho de Melo struct map *map; 542682b335aSArnaldo Carvalho de Melo struct dso *dso; 543682b335aSArnaldo Carvalho de Melo }; 544682b335aSArnaldo Carvalho de Melo 545e7110b9fSArnaldo Carvalho de Melo /* 546e7110b9fSArnaldo Carvalho de Melo * These are symbols in the kernel image, so make sure that 547e7110b9fSArnaldo Carvalho de Melo * sym is from a kernel DSO. 548e7110b9fSArnaldo Carvalho de Melo */ 54982d1deb0SDavid Ahern bool symbol__is_idle(struct symbol *sym) 55082d1deb0SDavid Ahern { 55182d1deb0SDavid Ahern const char * const idle_symbols[] = { 55282d1deb0SDavid Ahern "cpu_idle", 553e0336ed6SArnaldo Carvalho de Melo "cpu_startup_entry", 55482d1deb0SDavid Ahern "intel_idle", 55582d1deb0SDavid Ahern "default_idle", 55682d1deb0SDavid Ahern "native_safe_halt", 55782d1deb0SDavid Ahern "enter_idle", 55882d1deb0SDavid Ahern "exit_idle", 55982d1deb0SDavid Ahern "mwait_idle", 56082d1deb0SDavid Ahern "mwait_idle_with_hints", 56182d1deb0SDavid Ahern "poll_idle", 56282d1deb0SDavid Ahern "ppc64_runlatch_off", 56382d1deb0SDavid Ahern "pseries_dedicated_idle_sleep", 56482d1deb0SDavid Ahern NULL 56582d1deb0SDavid Ahern }; 56682d1deb0SDavid Ahern 56782d1deb0SDavid Ahern int i; 56882d1deb0SDavid Ahern 56982d1deb0SDavid Ahern if (!sym) 57082d1deb0SDavid Ahern return false; 57182d1deb0SDavid Ahern 57282d1deb0SDavid Ahern for (i = 0; idle_symbols[i]; i++) { 57382d1deb0SDavid Ahern if (!strcmp(idle_symbols[i], sym->name)) 57482d1deb0SDavid Ahern return true; 57582d1deb0SDavid Ahern } 57682d1deb0SDavid Ahern 57782d1deb0SDavid Ahern return false; 57882d1deb0SDavid Ahern } 57982d1deb0SDavid Ahern 580682b335aSArnaldo Carvalho de Melo static int map__process_kallsym_symbol(void *arg, const char *name, 58182151520SCody P Schafer char type, u64 start) 582682b335aSArnaldo Carvalho de Melo { 583682b335aSArnaldo Carvalho de Melo struct symbol *sym; 584682b335aSArnaldo Carvalho de Melo struct process_kallsyms_args *a = arg; 585682b335aSArnaldo Carvalho de Melo struct rb_root *root = &a->dso->symbols[a->map->type]; 586682b335aSArnaldo Carvalho de Melo 587682b335aSArnaldo Carvalho de Melo if (!symbol_type__is_a(type, a->map->type)) 588682b335aSArnaldo Carvalho de Melo return 0; 589682b335aSArnaldo Carvalho de Melo 59082151520SCody P Schafer /* 59182151520SCody P Schafer * module symbols are not sorted so we add all 59282151520SCody P Schafer * symbols, setting length to 0, and rely on 59382151520SCody P Schafer * symbols__fixup_end() to fix it up. 59482151520SCody P Schafer */ 5958e947f1eSArnaldo Carvalho de Melo sym = symbol__new(start, 0, kallsyms2elf_binding(type), name); 5962e538c4aSArnaldo Carvalho de Melo if (sym == NULL) 597682b335aSArnaldo Carvalho de Melo return -ENOMEM; 59882164161SArnaldo Carvalho de Melo /* 59982164161SArnaldo Carvalho de Melo * We will pass the symbols to the filter later, in 6004e06255fSArnaldo Carvalho de Melo * map__split_kallsyms, when we have split the maps per module 60182164161SArnaldo Carvalho de Melo */ 6024e06255fSArnaldo Carvalho de Melo symbols__insert(root, sym); 603a1645ce1SZhang, Yanmin 604682b335aSArnaldo Carvalho de Melo return 0; 6052e538c4aSArnaldo Carvalho de Melo } 6062e538c4aSArnaldo Carvalho de Melo 607682b335aSArnaldo Carvalho de Melo /* 608682b335aSArnaldo Carvalho de Melo * Loads the function entries in /proc/kallsyms into kernel_map->dso, 609682b335aSArnaldo Carvalho de Melo * so that we can in the next step set the symbol ->end address and then 610682b335aSArnaldo Carvalho de Melo * call kernel_maps__split_kallsyms. 611682b335aSArnaldo Carvalho de Melo */ 612aeafcbafSArnaldo Carvalho de Melo static int dso__load_all_kallsyms(struct dso *dso, const char *filename, 6139e201442SArnaldo Carvalho de Melo struct map *map) 614682b335aSArnaldo Carvalho de Melo { 615aeafcbafSArnaldo Carvalho de Melo struct process_kallsyms_args args = { .map = map, .dso = dso, }; 6169e201442SArnaldo Carvalho de Melo return kallsyms__parse(filename, &args, map__process_kallsym_symbol); 6172e538c4aSArnaldo Carvalho de Melo } 6182e538c4aSArnaldo Carvalho de Melo 6198e0cf965SAdrian Hunter static int dso__split_kallsyms_for_kcore(struct dso *dso, struct map *map, 6208e0cf965SAdrian Hunter symbol_filter_t filter) 6218e0cf965SAdrian Hunter { 622ba92732eSWang Nan struct map_groups *kmaps = map__kmaps(map); 6238e0cf965SAdrian Hunter struct map *curr_map; 6248e0cf965SAdrian Hunter struct symbol *pos; 625866548ddSAdrian Hunter int count = 0; 626866548ddSAdrian Hunter struct rb_root old_root = dso->symbols[map->type]; 6278e0cf965SAdrian Hunter struct rb_root *root = &dso->symbols[map->type]; 6288e0cf965SAdrian Hunter struct rb_node *next = rb_first(root); 6298e0cf965SAdrian Hunter 630ba92732eSWang Nan if (!kmaps) 631ba92732eSWang Nan return -1; 632ba92732eSWang Nan 633866548ddSAdrian Hunter *root = RB_ROOT; 634866548ddSAdrian Hunter 6358e0cf965SAdrian Hunter while (next) { 6368e0cf965SAdrian Hunter char *module; 6378e0cf965SAdrian Hunter 6388e0cf965SAdrian Hunter pos = rb_entry(next, struct symbol, rb_node); 6398e0cf965SAdrian Hunter next = rb_next(&pos->rb_node); 6408e0cf965SAdrian Hunter 641866548ddSAdrian Hunter rb_erase_init(&pos->rb_node, &old_root); 642866548ddSAdrian Hunter 6438e0cf965SAdrian Hunter module = strchr(pos->name, '\t'); 6448e0cf965SAdrian Hunter if (module) 6458e0cf965SAdrian Hunter *module = '\0'; 6468e0cf965SAdrian Hunter 6478e0cf965SAdrian Hunter curr_map = map_groups__find(kmaps, map->type, pos->start); 6488e0cf965SAdrian Hunter 6498e0cf965SAdrian Hunter if (!curr_map || (filter && filter(curr_map, pos))) { 6508e0cf965SAdrian Hunter symbol__delete(pos); 651866548ddSAdrian Hunter continue; 652866548ddSAdrian Hunter } 653866548ddSAdrian Hunter 6548e0cf965SAdrian Hunter pos->start -= curr_map->start - curr_map->pgoff; 6558e0cf965SAdrian Hunter if (pos->end) 6568e0cf965SAdrian Hunter pos->end -= curr_map->start - curr_map->pgoff; 657866548ddSAdrian Hunter symbols__insert(&curr_map->dso->symbols[curr_map->type], pos); 6588e0cf965SAdrian Hunter ++count; 6598e0cf965SAdrian Hunter } 6608e0cf965SAdrian Hunter 6618e0cf965SAdrian Hunter /* Symbols have been adjusted */ 6628e0cf965SAdrian Hunter dso->adjust_symbols = 1; 6638e0cf965SAdrian Hunter 664866548ddSAdrian Hunter return count; 6658e0cf965SAdrian Hunter } 6668e0cf965SAdrian Hunter 6672e538c4aSArnaldo Carvalho de Melo /* 6682e538c4aSArnaldo Carvalho de Melo * Split the symbols into maps, making sure there are no overlaps, i.e. the 6692e538c4aSArnaldo Carvalho de Melo * kernel range is broken in several maps, named [kernel].N, as we don't have 6702e538c4aSArnaldo Carvalho de Melo * the original ELF section names vmlinux have. 6712e538c4aSArnaldo Carvalho de Melo */ 672d9b62abaSAdrian Hunter static int dso__split_kallsyms(struct dso *dso, struct map *map, u64 delta, 6739de89fe7SArnaldo Carvalho de Melo symbol_filter_t filter) 6742e538c4aSArnaldo Carvalho de Melo { 675ba92732eSWang Nan struct map_groups *kmaps = map__kmaps(map); 676ba92732eSWang Nan struct machine *machine; 6774e06255fSArnaldo Carvalho de Melo struct map *curr_map = map; 6782e538c4aSArnaldo Carvalho de Melo struct symbol *pos; 6798a953312SArnaldo Carvalho de Melo int count = 0, moved = 0; 680aeafcbafSArnaldo Carvalho de Melo struct rb_root *root = &dso->symbols[map->type]; 6814e06255fSArnaldo Carvalho de Melo struct rb_node *next = rb_first(root); 6822e538c4aSArnaldo Carvalho de Melo int kernel_range = 0; 6832e538c4aSArnaldo Carvalho de Melo 684ba92732eSWang Nan if (!kmaps) 685ba92732eSWang Nan return -1; 686ba92732eSWang Nan 687ba92732eSWang Nan machine = kmaps->machine; 688ba92732eSWang Nan 6892e538c4aSArnaldo Carvalho de Melo while (next) { 6902e538c4aSArnaldo Carvalho de Melo char *module; 6912e538c4aSArnaldo Carvalho de Melo 6922e538c4aSArnaldo Carvalho de Melo pos = rb_entry(next, struct symbol, rb_node); 6932e538c4aSArnaldo Carvalho de Melo next = rb_next(&pos->rb_node); 6942e538c4aSArnaldo Carvalho de Melo 6952e538c4aSArnaldo Carvalho de Melo module = strchr(pos->name, '\t'); 6962e538c4aSArnaldo Carvalho de Melo if (module) { 69775be6cf4SArnaldo Carvalho de Melo if (!symbol_conf.use_modules) 6981de8e245SArnaldo Carvalho de Melo goto discard_symbol; 6991de8e245SArnaldo Carvalho de Melo 7002e538c4aSArnaldo Carvalho de Melo *module++ = '\0'; 7012e538c4aSArnaldo Carvalho de Melo 702b7cece76SArnaldo Carvalho de Melo if (strcmp(curr_map->dso->short_name, module)) { 703a1645ce1SZhang, Yanmin if (curr_map != map && 704aeafcbafSArnaldo Carvalho de Melo dso->kernel == DSO_TYPE_GUEST_KERNEL && 70523346f21SArnaldo Carvalho de Melo machine__is_default_guest(machine)) { 706a1645ce1SZhang, Yanmin /* 707a1645ce1SZhang, Yanmin * We assume all symbols of a module are 708a1645ce1SZhang, Yanmin * continuous in * kallsyms, so curr_map 709a1645ce1SZhang, Yanmin * points to a module and all its 710a1645ce1SZhang, Yanmin * symbols are in its kmap. Mark it as 711a1645ce1SZhang, Yanmin * loaded. 712a1645ce1SZhang, Yanmin */ 713a1645ce1SZhang, Yanmin dso__set_loaded(curr_map->dso, 714a1645ce1SZhang, Yanmin curr_map->type); 715af427bf5SArnaldo Carvalho de Melo } 716b7cece76SArnaldo Carvalho de Melo 717a1645ce1SZhang, Yanmin curr_map = map_groups__find_by_name(kmaps, 718a1645ce1SZhang, Yanmin map->type, module); 719a1645ce1SZhang, Yanmin if (curr_map == NULL) { 7202f51903bSArnaldo Carvalho de Melo pr_debug("%s/proc/{kallsyms,modules} " 721a1645ce1SZhang, Yanmin "inconsistency while looking " 722a1645ce1SZhang, Yanmin "for \"%s\" module!\n", 72323346f21SArnaldo Carvalho de Melo machine->root_dir, module); 724a1645ce1SZhang, Yanmin curr_map = map; 725a1645ce1SZhang, Yanmin goto discard_symbol; 726a1645ce1SZhang, Yanmin } 727a1645ce1SZhang, Yanmin 728a1645ce1SZhang, Yanmin if (curr_map->dso->loaded && 72923346f21SArnaldo Carvalho de Melo !machine__is_default_guest(machine)) 730b7cece76SArnaldo Carvalho de Melo goto discard_symbol; 731af427bf5SArnaldo Carvalho de Melo } 73286470930SIngo Molnar /* 7332e538c4aSArnaldo Carvalho de Melo * So that we look just like we get from .ko files, 7342e538c4aSArnaldo Carvalho de Melo * i.e. not prelinked, relative to map->start. 73586470930SIngo Molnar */ 7364e06255fSArnaldo Carvalho de Melo pos->start = curr_map->map_ip(curr_map, pos->start); 7374e06255fSArnaldo Carvalho de Melo pos->end = curr_map->map_ip(curr_map, pos->end); 7384e06255fSArnaldo Carvalho de Melo } else if (curr_map != map) { 7392e538c4aSArnaldo Carvalho de Melo char dso_name[PATH_MAX]; 740aeafcbafSArnaldo Carvalho de Melo struct dso *ndso; 74186470930SIngo Molnar 742d9b62abaSAdrian Hunter if (delta) { 743d9b62abaSAdrian Hunter /* Kernel was relocated at boot time */ 744d9b62abaSAdrian Hunter pos->start -= delta; 745d9b62abaSAdrian Hunter pos->end -= delta; 746d9b62abaSAdrian Hunter } 747d9b62abaSAdrian Hunter 7488a953312SArnaldo Carvalho de Melo if (count == 0) { 7498a953312SArnaldo Carvalho de Melo curr_map = map; 7508a953312SArnaldo Carvalho de Melo goto filter_symbol; 7518a953312SArnaldo Carvalho de Melo } 7528a953312SArnaldo Carvalho de Melo 753aeafcbafSArnaldo Carvalho de Melo if (dso->kernel == DSO_TYPE_GUEST_KERNEL) 754a1645ce1SZhang, Yanmin snprintf(dso_name, sizeof(dso_name), 755a1645ce1SZhang, Yanmin "[guest.kernel].%d", 756a1645ce1SZhang, Yanmin kernel_range++); 757a1645ce1SZhang, Yanmin else 758a1645ce1SZhang, Yanmin snprintf(dso_name, sizeof(dso_name), 759a1645ce1SZhang, Yanmin "[kernel].%d", 7602e538c4aSArnaldo Carvalho de Melo kernel_range++); 76186470930SIngo Molnar 762aeafcbafSArnaldo Carvalho de Melo ndso = dso__new(dso_name); 763aeafcbafSArnaldo Carvalho de Melo if (ndso == NULL) 7642e538c4aSArnaldo Carvalho de Melo return -1; 7652e538c4aSArnaldo Carvalho de Melo 766aeafcbafSArnaldo Carvalho de Melo ndso->kernel = dso->kernel; 767a1645ce1SZhang, Yanmin 768aeafcbafSArnaldo Carvalho de Melo curr_map = map__new2(pos->start, ndso, map->type); 76937fe5fcbSZhang, Yanmin if (curr_map == NULL) { 770d3a7c489SArnaldo Carvalho de Melo dso__put(ndso); 7712e538c4aSArnaldo Carvalho de Melo return -1; 7722e538c4aSArnaldo Carvalho de Melo } 7732e538c4aSArnaldo Carvalho de Melo 7744e06255fSArnaldo Carvalho de Melo curr_map->map_ip = curr_map->unmap_ip = identity__map_ip; 7759de89fe7SArnaldo Carvalho de Melo map_groups__insert(kmaps, curr_map); 7762e538c4aSArnaldo Carvalho de Melo ++kernel_range; 777d9b62abaSAdrian Hunter } else if (delta) { 778d9b62abaSAdrian Hunter /* Kernel was relocated at boot time */ 779d9b62abaSAdrian Hunter pos->start -= delta; 780d9b62abaSAdrian Hunter pos->end -= delta; 7812e538c4aSArnaldo Carvalho de Melo } 7828a953312SArnaldo Carvalho de Melo filter_symbol: 7834e06255fSArnaldo Carvalho de Melo if (filter && filter(curr_map, pos)) { 7841de8e245SArnaldo Carvalho de Melo discard_symbol: rb_erase(&pos->rb_node, root); 78500a192b3SArnaldo Carvalho de Melo symbol__delete(pos); 7862e538c4aSArnaldo Carvalho de Melo } else { 7874e06255fSArnaldo Carvalho de Melo if (curr_map != map) { 7884e06255fSArnaldo Carvalho de Melo rb_erase(&pos->rb_node, root); 7894e06255fSArnaldo Carvalho de Melo symbols__insert(&curr_map->dso->symbols[curr_map->type], pos); 7908a953312SArnaldo Carvalho de Melo ++moved; 7918a953312SArnaldo Carvalho de Melo } else 7928a953312SArnaldo Carvalho de Melo ++count; 7939974f496SMike Galbraith } 79486470930SIngo Molnar } 79586470930SIngo Molnar 796a1645ce1SZhang, Yanmin if (curr_map != map && 797aeafcbafSArnaldo Carvalho de Melo dso->kernel == DSO_TYPE_GUEST_KERNEL && 79823346f21SArnaldo Carvalho de Melo machine__is_default_guest(kmaps->machine)) { 799a1645ce1SZhang, Yanmin dso__set_loaded(curr_map->dso, curr_map->type); 800a1645ce1SZhang, Yanmin } 801a1645ce1SZhang, Yanmin 8028a953312SArnaldo Carvalho de Melo return count + moved; 80386470930SIngo Molnar } 80486470930SIngo Molnar 8053f067dcaSArnaldo Carvalho de Melo bool symbol__restricted_filename(const char *filename, 806ec80fde7SArnaldo Carvalho de Melo const char *restricted_filename) 807ec80fde7SArnaldo Carvalho de Melo { 808ec80fde7SArnaldo Carvalho de Melo bool restricted = false; 809ec80fde7SArnaldo Carvalho de Melo 810ec80fde7SArnaldo Carvalho de Melo if (symbol_conf.kptr_restrict) { 811ec80fde7SArnaldo Carvalho de Melo char *r = realpath(filename, NULL); 812ec80fde7SArnaldo Carvalho de Melo 813ec80fde7SArnaldo Carvalho de Melo if (r != NULL) { 814ec80fde7SArnaldo Carvalho de Melo restricted = strcmp(r, restricted_filename) == 0; 815ec80fde7SArnaldo Carvalho de Melo free(r); 816ec80fde7SArnaldo Carvalho de Melo return restricted; 817ec80fde7SArnaldo Carvalho de Melo } 818ec80fde7SArnaldo Carvalho de Melo } 819ec80fde7SArnaldo Carvalho de Melo 820ec80fde7SArnaldo Carvalho de Melo return restricted; 821ec80fde7SArnaldo Carvalho de Melo } 822ec80fde7SArnaldo Carvalho de Melo 82352afdaf9SAdrian Hunter struct module_info { 82452afdaf9SAdrian Hunter struct rb_node rb_node; 82552afdaf9SAdrian Hunter char *name; 82652afdaf9SAdrian Hunter u64 start; 82752afdaf9SAdrian Hunter }; 82852afdaf9SAdrian Hunter 82952afdaf9SAdrian Hunter static void add_module(struct module_info *mi, struct rb_root *modules) 83052afdaf9SAdrian Hunter { 83152afdaf9SAdrian Hunter struct rb_node **p = &modules->rb_node; 83252afdaf9SAdrian Hunter struct rb_node *parent = NULL; 83352afdaf9SAdrian Hunter struct module_info *m; 83452afdaf9SAdrian Hunter 83552afdaf9SAdrian Hunter while (*p != NULL) { 83652afdaf9SAdrian Hunter parent = *p; 83752afdaf9SAdrian Hunter m = rb_entry(parent, struct module_info, rb_node); 83852afdaf9SAdrian Hunter if (strcmp(mi->name, m->name) < 0) 83952afdaf9SAdrian Hunter p = &(*p)->rb_left; 84052afdaf9SAdrian Hunter else 84152afdaf9SAdrian Hunter p = &(*p)->rb_right; 84252afdaf9SAdrian Hunter } 84352afdaf9SAdrian Hunter rb_link_node(&mi->rb_node, parent, p); 84452afdaf9SAdrian Hunter rb_insert_color(&mi->rb_node, modules); 84552afdaf9SAdrian Hunter } 84652afdaf9SAdrian Hunter 84752afdaf9SAdrian Hunter static void delete_modules(struct rb_root *modules) 84852afdaf9SAdrian Hunter { 84952afdaf9SAdrian Hunter struct module_info *mi; 85052afdaf9SAdrian Hunter struct rb_node *next = rb_first(modules); 85152afdaf9SAdrian Hunter 85252afdaf9SAdrian Hunter while (next) { 85352afdaf9SAdrian Hunter mi = rb_entry(next, struct module_info, rb_node); 85452afdaf9SAdrian Hunter next = rb_next(&mi->rb_node); 85552afdaf9SAdrian Hunter rb_erase(&mi->rb_node, modules); 85674cf249dSArnaldo Carvalho de Melo zfree(&mi->name); 85752afdaf9SAdrian Hunter free(mi); 85852afdaf9SAdrian Hunter } 85952afdaf9SAdrian Hunter } 86052afdaf9SAdrian Hunter 86152afdaf9SAdrian Hunter static struct module_info *find_module(const char *name, 86252afdaf9SAdrian Hunter struct rb_root *modules) 86352afdaf9SAdrian Hunter { 86452afdaf9SAdrian Hunter struct rb_node *n = modules->rb_node; 86552afdaf9SAdrian Hunter 86652afdaf9SAdrian Hunter while (n) { 86752afdaf9SAdrian Hunter struct module_info *m; 86852afdaf9SAdrian Hunter int cmp; 86952afdaf9SAdrian Hunter 87052afdaf9SAdrian Hunter m = rb_entry(n, struct module_info, rb_node); 87152afdaf9SAdrian Hunter cmp = strcmp(name, m->name); 87252afdaf9SAdrian Hunter if (cmp < 0) 87352afdaf9SAdrian Hunter n = n->rb_left; 87452afdaf9SAdrian Hunter else if (cmp > 0) 87552afdaf9SAdrian Hunter n = n->rb_right; 87652afdaf9SAdrian Hunter else 87752afdaf9SAdrian Hunter return m; 87852afdaf9SAdrian Hunter } 87952afdaf9SAdrian Hunter 88052afdaf9SAdrian Hunter return NULL; 88152afdaf9SAdrian Hunter } 88252afdaf9SAdrian Hunter 88352afdaf9SAdrian Hunter static int __read_proc_modules(void *arg, const char *name, u64 start) 88452afdaf9SAdrian Hunter { 88552afdaf9SAdrian Hunter struct rb_root *modules = arg; 88652afdaf9SAdrian Hunter struct module_info *mi; 88752afdaf9SAdrian Hunter 88852afdaf9SAdrian Hunter mi = zalloc(sizeof(struct module_info)); 88952afdaf9SAdrian Hunter if (!mi) 89052afdaf9SAdrian Hunter return -ENOMEM; 89152afdaf9SAdrian Hunter 89252afdaf9SAdrian Hunter mi->name = strdup(name); 89352afdaf9SAdrian Hunter mi->start = start; 89452afdaf9SAdrian Hunter 89552afdaf9SAdrian Hunter if (!mi->name) { 89652afdaf9SAdrian Hunter free(mi); 89752afdaf9SAdrian Hunter return -ENOMEM; 89852afdaf9SAdrian Hunter } 89952afdaf9SAdrian Hunter 90052afdaf9SAdrian Hunter add_module(mi, modules); 90152afdaf9SAdrian Hunter 90252afdaf9SAdrian Hunter return 0; 90352afdaf9SAdrian Hunter } 90452afdaf9SAdrian Hunter 90552afdaf9SAdrian Hunter static int read_proc_modules(const char *filename, struct rb_root *modules) 90652afdaf9SAdrian Hunter { 90752afdaf9SAdrian Hunter if (symbol__restricted_filename(filename, "/proc/modules")) 90852afdaf9SAdrian Hunter return -1; 90952afdaf9SAdrian Hunter 91052afdaf9SAdrian Hunter if (modules__parse(filename, modules, __read_proc_modules)) { 91152afdaf9SAdrian Hunter delete_modules(modules); 91252afdaf9SAdrian Hunter return -1; 91352afdaf9SAdrian Hunter } 91452afdaf9SAdrian Hunter 91552afdaf9SAdrian Hunter return 0; 91652afdaf9SAdrian Hunter } 91752afdaf9SAdrian Hunter 918fc1b691dSAdrian Hunter int compare_proc_modules(const char *from, const char *to) 919fc1b691dSAdrian Hunter { 920fc1b691dSAdrian Hunter struct rb_root from_modules = RB_ROOT; 921fc1b691dSAdrian Hunter struct rb_root to_modules = RB_ROOT; 922fc1b691dSAdrian Hunter struct rb_node *from_node, *to_node; 923fc1b691dSAdrian Hunter struct module_info *from_m, *to_m; 924fc1b691dSAdrian Hunter int ret = -1; 925fc1b691dSAdrian Hunter 926fc1b691dSAdrian Hunter if (read_proc_modules(from, &from_modules)) 927fc1b691dSAdrian Hunter return -1; 928fc1b691dSAdrian Hunter 929fc1b691dSAdrian Hunter if (read_proc_modules(to, &to_modules)) 930fc1b691dSAdrian Hunter goto out_delete_from; 931fc1b691dSAdrian Hunter 932fc1b691dSAdrian Hunter from_node = rb_first(&from_modules); 933fc1b691dSAdrian Hunter to_node = rb_first(&to_modules); 934fc1b691dSAdrian Hunter while (from_node) { 935fc1b691dSAdrian Hunter if (!to_node) 936fc1b691dSAdrian Hunter break; 937fc1b691dSAdrian Hunter 938fc1b691dSAdrian Hunter from_m = rb_entry(from_node, struct module_info, rb_node); 939fc1b691dSAdrian Hunter to_m = rb_entry(to_node, struct module_info, rb_node); 940fc1b691dSAdrian Hunter 941fc1b691dSAdrian Hunter if (from_m->start != to_m->start || 942fc1b691dSAdrian Hunter strcmp(from_m->name, to_m->name)) 943fc1b691dSAdrian Hunter break; 944fc1b691dSAdrian Hunter 945fc1b691dSAdrian Hunter from_node = rb_next(from_node); 946fc1b691dSAdrian Hunter to_node = rb_next(to_node); 947fc1b691dSAdrian Hunter } 948fc1b691dSAdrian Hunter 949fc1b691dSAdrian Hunter if (!from_node && !to_node) 950fc1b691dSAdrian Hunter ret = 0; 951fc1b691dSAdrian Hunter 952fc1b691dSAdrian Hunter delete_modules(&to_modules); 953fc1b691dSAdrian Hunter out_delete_from: 954fc1b691dSAdrian Hunter delete_modules(&from_modules); 955fc1b691dSAdrian Hunter 956fc1b691dSAdrian Hunter return ret; 957fc1b691dSAdrian Hunter } 958fc1b691dSAdrian Hunter 95952afdaf9SAdrian Hunter static int do_validate_kcore_modules(const char *filename, struct map *map, 96052afdaf9SAdrian Hunter struct map_groups *kmaps) 96152afdaf9SAdrian Hunter { 96252afdaf9SAdrian Hunter struct rb_root modules = RB_ROOT; 96352afdaf9SAdrian Hunter struct map *old_map; 96452afdaf9SAdrian Hunter int err; 96552afdaf9SAdrian Hunter 96652afdaf9SAdrian Hunter err = read_proc_modules(filename, &modules); 96752afdaf9SAdrian Hunter if (err) 96852afdaf9SAdrian Hunter return err; 96952afdaf9SAdrian Hunter 97052afdaf9SAdrian Hunter old_map = map_groups__first(kmaps, map->type); 97152afdaf9SAdrian Hunter while (old_map) { 97252afdaf9SAdrian Hunter struct map *next = map_groups__next(old_map); 97352afdaf9SAdrian Hunter struct module_info *mi; 97452afdaf9SAdrian Hunter 97552afdaf9SAdrian Hunter if (old_map == map || old_map->start == map->start) { 97652afdaf9SAdrian Hunter /* The kernel map */ 97752afdaf9SAdrian Hunter old_map = next; 97852afdaf9SAdrian Hunter continue; 97952afdaf9SAdrian Hunter } 98052afdaf9SAdrian Hunter 98152afdaf9SAdrian Hunter /* Module must be in memory at the same address */ 98252afdaf9SAdrian Hunter mi = find_module(old_map->dso->short_name, &modules); 98352afdaf9SAdrian Hunter if (!mi || mi->start != old_map->start) { 98452afdaf9SAdrian Hunter err = -EINVAL; 98552afdaf9SAdrian Hunter goto out; 98652afdaf9SAdrian Hunter } 98752afdaf9SAdrian Hunter 98852afdaf9SAdrian Hunter old_map = next; 98952afdaf9SAdrian Hunter } 99052afdaf9SAdrian Hunter out: 99152afdaf9SAdrian Hunter delete_modules(&modules); 99252afdaf9SAdrian Hunter return err; 99352afdaf9SAdrian Hunter } 99452afdaf9SAdrian Hunter 99552afdaf9SAdrian Hunter /* 99652afdaf9SAdrian Hunter * If kallsyms is referenced by name then we look for filename in the same 99752afdaf9SAdrian Hunter * directory. 99852afdaf9SAdrian Hunter */ 99952afdaf9SAdrian Hunter static bool filename_from_kallsyms_filename(char *filename, 100052afdaf9SAdrian Hunter const char *base_name, 100152afdaf9SAdrian Hunter const char *kallsyms_filename) 100252afdaf9SAdrian Hunter { 100352afdaf9SAdrian Hunter char *name; 100452afdaf9SAdrian Hunter 100552afdaf9SAdrian Hunter strcpy(filename, kallsyms_filename); 100652afdaf9SAdrian Hunter name = strrchr(filename, '/'); 100752afdaf9SAdrian Hunter if (!name) 100852afdaf9SAdrian Hunter return false; 100952afdaf9SAdrian Hunter 101052afdaf9SAdrian Hunter name += 1; 101152afdaf9SAdrian Hunter 101252afdaf9SAdrian Hunter if (!strcmp(name, "kallsyms")) { 101352afdaf9SAdrian Hunter strcpy(name, base_name); 101452afdaf9SAdrian Hunter return true; 101552afdaf9SAdrian Hunter } 101652afdaf9SAdrian Hunter 101752afdaf9SAdrian Hunter return false; 101852afdaf9SAdrian Hunter } 101952afdaf9SAdrian Hunter 102052afdaf9SAdrian Hunter static int validate_kcore_modules(const char *kallsyms_filename, 102152afdaf9SAdrian Hunter struct map *map) 102252afdaf9SAdrian Hunter { 1023ba92732eSWang Nan struct map_groups *kmaps = map__kmaps(map); 102452afdaf9SAdrian Hunter char modules_filename[PATH_MAX]; 102552afdaf9SAdrian Hunter 1026ba92732eSWang Nan if (!kmaps) 1027ba92732eSWang Nan return -EINVAL; 1028ba92732eSWang Nan 102952afdaf9SAdrian Hunter if (!filename_from_kallsyms_filename(modules_filename, "modules", 103052afdaf9SAdrian Hunter kallsyms_filename)) 103152afdaf9SAdrian Hunter return -EINVAL; 103252afdaf9SAdrian Hunter 103352afdaf9SAdrian Hunter if (do_validate_kcore_modules(modules_filename, map, kmaps)) 103452afdaf9SAdrian Hunter return -EINVAL; 103552afdaf9SAdrian Hunter 103652afdaf9SAdrian Hunter return 0; 103752afdaf9SAdrian Hunter } 103852afdaf9SAdrian Hunter 1039a00d28cbSAdrian Hunter static int validate_kcore_addresses(const char *kallsyms_filename, 1040a00d28cbSAdrian Hunter struct map *map) 1041a00d28cbSAdrian Hunter { 1042a00d28cbSAdrian Hunter struct kmap *kmap = map__kmap(map); 1043a00d28cbSAdrian Hunter 1044ba92732eSWang Nan if (!kmap) 1045ba92732eSWang Nan return -EINVAL; 1046ba92732eSWang Nan 1047a00d28cbSAdrian Hunter if (kmap->ref_reloc_sym && kmap->ref_reloc_sym->name) { 1048a00d28cbSAdrian Hunter u64 start; 1049a00d28cbSAdrian Hunter 1050a00d28cbSAdrian Hunter start = kallsyms__get_function_start(kallsyms_filename, 1051a00d28cbSAdrian Hunter kmap->ref_reloc_sym->name); 1052a00d28cbSAdrian Hunter if (start != kmap->ref_reloc_sym->addr) 1053a00d28cbSAdrian Hunter return -EINVAL; 1054a00d28cbSAdrian Hunter } 1055a00d28cbSAdrian Hunter 1056a00d28cbSAdrian Hunter return validate_kcore_modules(kallsyms_filename, map); 1057a00d28cbSAdrian Hunter } 1058a00d28cbSAdrian Hunter 10598e0cf965SAdrian Hunter struct kcore_mapfn_data { 10608e0cf965SAdrian Hunter struct dso *dso; 10618e0cf965SAdrian Hunter enum map_type type; 10628e0cf965SAdrian Hunter struct list_head maps; 10638e0cf965SAdrian Hunter }; 10648e0cf965SAdrian Hunter 10658e0cf965SAdrian Hunter static int kcore_mapfn(u64 start, u64 len, u64 pgoff, void *data) 10668e0cf965SAdrian Hunter { 10678e0cf965SAdrian Hunter struct kcore_mapfn_data *md = data; 10688e0cf965SAdrian Hunter struct map *map; 10698e0cf965SAdrian Hunter 10708e0cf965SAdrian Hunter map = map__new2(start, md->dso, md->type); 10718e0cf965SAdrian Hunter if (map == NULL) 10728e0cf965SAdrian Hunter return -ENOMEM; 10738e0cf965SAdrian Hunter 10748e0cf965SAdrian Hunter map->end = map->start + len; 10758e0cf965SAdrian Hunter map->pgoff = pgoff; 10768e0cf965SAdrian Hunter 10778e0cf965SAdrian Hunter list_add(&map->node, &md->maps); 10788e0cf965SAdrian Hunter 10798e0cf965SAdrian Hunter return 0; 10808e0cf965SAdrian Hunter } 10818e0cf965SAdrian Hunter 10828e0cf965SAdrian Hunter static int dso__load_kcore(struct dso *dso, struct map *map, 10838e0cf965SAdrian Hunter const char *kallsyms_filename) 10848e0cf965SAdrian Hunter { 1085ba92732eSWang Nan struct map_groups *kmaps = map__kmaps(map); 1086ba92732eSWang Nan struct machine *machine; 10878e0cf965SAdrian Hunter struct kcore_mapfn_data md; 10888e0cf965SAdrian Hunter struct map *old_map, *new_map, *replacement_map = NULL; 10898e0cf965SAdrian Hunter bool is_64_bit; 10908e0cf965SAdrian Hunter int err, fd; 10918e0cf965SAdrian Hunter char kcore_filename[PATH_MAX]; 10928e0cf965SAdrian Hunter struct symbol *sym; 10938e0cf965SAdrian Hunter 1094ba92732eSWang Nan if (!kmaps) 1095ba92732eSWang Nan return -EINVAL; 1096ba92732eSWang Nan 1097ba92732eSWang Nan machine = kmaps->machine; 1098ba92732eSWang Nan 10998e0cf965SAdrian Hunter /* This function requires that the map is the kernel map */ 11008e0cf965SAdrian Hunter if (map != machine->vmlinux_maps[map->type]) 11018e0cf965SAdrian Hunter return -EINVAL; 11028e0cf965SAdrian Hunter 110352afdaf9SAdrian Hunter if (!filename_from_kallsyms_filename(kcore_filename, "kcore", 11048e0cf965SAdrian Hunter kallsyms_filename)) 11058e0cf965SAdrian Hunter return -EINVAL; 11068e0cf965SAdrian Hunter 1107a00d28cbSAdrian Hunter /* Modules and kernel must be present at their original addresses */ 1108a00d28cbSAdrian Hunter if (validate_kcore_addresses(kallsyms_filename, map)) 110952afdaf9SAdrian Hunter return -EINVAL; 111052afdaf9SAdrian Hunter 11118e0cf965SAdrian Hunter md.dso = dso; 11128e0cf965SAdrian Hunter md.type = map->type; 11138e0cf965SAdrian Hunter INIT_LIST_HEAD(&md.maps); 11148e0cf965SAdrian Hunter 11158e0cf965SAdrian Hunter fd = open(kcore_filename, O_RDONLY); 111636c8bb56SLi Zhang if (fd < 0) { 1117133de940SAdrian Hunter pr_debug("Failed to open %s. Note /proc/kcore requires CAP_SYS_RAWIO capability to access.\n", 111836c8bb56SLi Zhang kcore_filename); 11198e0cf965SAdrian Hunter return -EINVAL; 112036c8bb56SLi Zhang } 11218e0cf965SAdrian Hunter 11228e0cf965SAdrian Hunter /* Read new maps into temporary lists */ 11238e0cf965SAdrian Hunter err = file__read_maps(fd, md.type == MAP__FUNCTION, kcore_mapfn, &md, 11248e0cf965SAdrian Hunter &is_64_bit); 11258e0cf965SAdrian Hunter if (err) 11268e0cf965SAdrian Hunter goto out_err; 1127c6d8f2a4SAdrian Hunter dso->is_64_bit = is_64_bit; 11288e0cf965SAdrian Hunter 11298e0cf965SAdrian Hunter if (list_empty(&md.maps)) { 11308e0cf965SAdrian Hunter err = -EINVAL; 11318e0cf965SAdrian Hunter goto out_err; 11328e0cf965SAdrian Hunter } 11338e0cf965SAdrian Hunter 11348e0cf965SAdrian Hunter /* Remove old maps */ 11358e0cf965SAdrian Hunter old_map = map_groups__first(kmaps, map->type); 11368e0cf965SAdrian Hunter while (old_map) { 11378e0cf965SAdrian Hunter struct map *next = map_groups__next(old_map); 11388e0cf965SAdrian Hunter 11398e0cf965SAdrian Hunter if (old_map != map) 11408e0cf965SAdrian Hunter map_groups__remove(kmaps, old_map); 11418e0cf965SAdrian Hunter old_map = next; 11428e0cf965SAdrian Hunter } 11438e0cf965SAdrian Hunter 11448e0cf965SAdrian Hunter /* Find the kernel map using the first symbol */ 11458e0cf965SAdrian Hunter sym = dso__first_symbol(dso, map->type); 11468e0cf965SAdrian Hunter list_for_each_entry(new_map, &md.maps, node) { 11478e0cf965SAdrian Hunter if (sym && sym->start >= new_map->start && 11488e0cf965SAdrian Hunter sym->start < new_map->end) { 11498e0cf965SAdrian Hunter replacement_map = new_map; 11508e0cf965SAdrian Hunter break; 11518e0cf965SAdrian Hunter } 11528e0cf965SAdrian Hunter } 11538e0cf965SAdrian Hunter 11548e0cf965SAdrian Hunter if (!replacement_map) 11558e0cf965SAdrian Hunter replacement_map = list_entry(md.maps.next, struct map, node); 11568e0cf965SAdrian Hunter 11578e0cf965SAdrian Hunter /* Add new maps */ 11588e0cf965SAdrian Hunter while (!list_empty(&md.maps)) { 11598e0cf965SAdrian Hunter new_map = list_entry(md.maps.next, struct map, node); 1160facf3f06SArnaldo Carvalho de Melo list_del_init(&new_map->node); 11618e0cf965SAdrian Hunter if (new_map == replacement_map) { 11628e0cf965SAdrian Hunter map->start = new_map->start; 11638e0cf965SAdrian Hunter map->end = new_map->end; 11648e0cf965SAdrian Hunter map->pgoff = new_map->pgoff; 11658e0cf965SAdrian Hunter map->map_ip = new_map->map_ip; 11668e0cf965SAdrian Hunter map->unmap_ip = new_map->unmap_ip; 11678e0cf965SAdrian Hunter /* Ensure maps are correctly ordered */ 116884c2cafaSArnaldo Carvalho de Melo map__get(map); 11698e0cf965SAdrian Hunter map_groups__remove(kmaps, map); 11708e0cf965SAdrian Hunter map_groups__insert(kmaps, map); 117184c2cafaSArnaldo Carvalho de Melo map__put(map); 11728e0cf965SAdrian Hunter } else { 11738e0cf965SAdrian Hunter map_groups__insert(kmaps, new_map); 11748e0cf965SAdrian Hunter } 117584c2cafaSArnaldo Carvalho de Melo 117684c2cafaSArnaldo Carvalho de Melo map__put(new_map); 11778e0cf965SAdrian Hunter } 11788e0cf965SAdrian Hunter 11798e0cf965SAdrian Hunter /* 11808e0cf965SAdrian Hunter * Set the data type and long name so that kcore can be read via 11818e0cf965SAdrian Hunter * dso__data_read_addr(). 11828e0cf965SAdrian Hunter */ 11838e0cf965SAdrian Hunter if (dso->kernel == DSO_TYPE_GUEST_KERNEL) 11845f70619dSArnaldo Carvalho de Melo dso->binary_type = DSO_BINARY_TYPE__GUEST_KCORE; 11858e0cf965SAdrian Hunter else 11865f70619dSArnaldo Carvalho de Melo dso->binary_type = DSO_BINARY_TYPE__KCORE; 11877e155d4dSArnaldo Carvalho de Melo dso__set_long_name(dso, strdup(kcore_filename), true); 11888e0cf965SAdrian Hunter 11898e0cf965SAdrian Hunter close(fd); 11908e0cf965SAdrian Hunter 11918e0cf965SAdrian Hunter if (map->type == MAP__FUNCTION) 11928e0cf965SAdrian Hunter pr_debug("Using %s for kernel object code\n", kcore_filename); 11938e0cf965SAdrian Hunter else 11948e0cf965SAdrian Hunter pr_debug("Using %s for kernel data\n", kcore_filename); 11958e0cf965SAdrian Hunter 11968e0cf965SAdrian Hunter return 0; 11978e0cf965SAdrian Hunter 11988e0cf965SAdrian Hunter out_err: 11998e0cf965SAdrian Hunter while (!list_empty(&md.maps)) { 12008e0cf965SAdrian Hunter map = list_entry(md.maps.next, struct map, node); 1201facf3f06SArnaldo Carvalho de Melo list_del_init(&map->node); 120284c2cafaSArnaldo Carvalho de Melo map__put(map); 12038e0cf965SAdrian Hunter } 12048e0cf965SAdrian Hunter close(fd); 12058e0cf965SAdrian Hunter return -EINVAL; 12068e0cf965SAdrian Hunter } 12078e0cf965SAdrian Hunter 1208d9b62abaSAdrian Hunter /* 1209d9b62abaSAdrian Hunter * If the kernel is relocated at boot time, kallsyms won't match. Compute the 1210d9b62abaSAdrian Hunter * delta based on the relocation reference symbol. 1211d9b62abaSAdrian Hunter */ 1212d9b62abaSAdrian Hunter static int kallsyms__delta(struct map *map, const char *filename, u64 *delta) 1213d9b62abaSAdrian Hunter { 1214d9b62abaSAdrian Hunter struct kmap *kmap = map__kmap(map); 1215d9b62abaSAdrian Hunter u64 addr; 1216d9b62abaSAdrian Hunter 1217ba92732eSWang Nan if (!kmap) 1218ba92732eSWang Nan return -1; 1219ba92732eSWang Nan 1220d9b62abaSAdrian Hunter if (!kmap->ref_reloc_sym || !kmap->ref_reloc_sym->name) 1221d9b62abaSAdrian Hunter return 0; 1222d9b62abaSAdrian Hunter 1223d9b62abaSAdrian Hunter addr = kallsyms__get_function_start(filename, 1224d9b62abaSAdrian Hunter kmap->ref_reloc_sym->name); 1225d9b62abaSAdrian Hunter if (!addr) 1226d9b62abaSAdrian Hunter return -1; 1227d9b62abaSAdrian Hunter 1228d9b62abaSAdrian Hunter *delta = addr - kmap->ref_reloc_sym->addr; 1229d9b62abaSAdrian Hunter return 0; 1230d9b62abaSAdrian Hunter } 1231d9b62abaSAdrian Hunter 1232e02092b9SArnaldo Carvalho de Melo int __dso__load_kallsyms(struct dso *dso, const char *filename, 1233e02092b9SArnaldo Carvalho de Melo struct map *map, bool no_kcore, symbol_filter_t filter) 12342e538c4aSArnaldo Carvalho de Melo { 1235d9b62abaSAdrian Hunter u64 delta = 0; 1236d9b62abaSAdrian Hunter 1237ec80fde7SArnaldo Carvalho de Melo if (symbol__restricted_filename(filename, "/proc/kallsyms")) 1238ec80fde7SArnaldo Carvalho de Melo return -1; 1239ec80fde7SArnaldo Carvalho de Melo 1240aeafcbafSArnaldo Carvalho de Melo if (dso__load_all_kallsyms(dso, filename, map) < 0) 12412e538c4aSArnaldo Carvalho de Melo return -1; 12422e538c4aSArnaldo Carvalho de Melo 1243d9b62abaSAdrian Hunter if (kallsyms__delta(map, filename, &delta)) 1244d9b62abaSAdrian Hunter return -1; 1245d9b62abaSAdrian Hunter 12463f5a4272SAnton Blanchard symbols__fixup_end(&dso->symbols[map->type]); 1247*432746f8SArnaldo Carvalho de Melo symbols__fixup_duplicate(&dso->symbols[map->type]); 12483f5a4272SAnton Blanchard 1249aeafcbafSArnaldo Carvalho de Melo if (dso->kernel == DSO_TYPE_GUEST_KERNEL) 125044f24cb3SJiri Olsa dso->symtab_type = DSO_BINARY_TYPE__GUEST_KALLSYMS; 1251a1645ce1SZhang, Yanmin else 125244f24cb3SJiri Olsa dso->symtab_type = DSO_BINARY_TYPE__KALLSYMS; 12532e538c4aSArnaldo Carvalho de Melo 1254e02092b9SArnaldo Carvalho de Melo if (!no_kcore && !dso__load_kcore(dso, map, filename)) 12558e0cf965SAdrian Hunter return dso__split_kallsyms_for_kcore(dso, map, filter); 12568e0cf965SAdrian Hunter else 1257d9b62abaSAdrian Hunter return dso__split_kallsyms(dso, map, delta, filter); 1258af427bf5SArnaldo Carvalho de Melo } 1259af427bf5SArnaldo Carvalho de Melo 1260e02092b9SArnaldo Carvalho de Melo int dso__load_kallsyms(struct dso *dso, const char *filename, 1261e02092b9SArnaldo Carvalho de Melo struct map *map, symbol_filter_t filter) 1262e02092b9SArnaldo Carvalho de Melo { 1263e02092b9SArnaldo Carvalho de Melo return __dso__load_kallsyms(dso, filename, map, false, filter); 1264e02092b9SArnaldo Carvalho de Melo } 1265e02092b9SArnaldo Carvalho de Melo 1266aeafcbafSArnaldo Carvalho de Melo static int dso__load_perf_map(struct dso *dso, struct map *map, 12676beba7adSArnaldo Carvalho de Melo symbol_filter_t filter) 126880d496beSPekka Enberg { 126980d496beSPekka Enberg char *line = NULL; 127080d496beSPekka Enberg size_t n; 127180d496beSPekka Enberg FILE *file; 127280d496beSPekka Enberg int nr_syms = 0; 127380d496beSPekka Enberg 1274aeafcbafSArnaldo Carvalho de Melo file = fopen(dso->long_name, "r"); 127580d496beSPekka Enberg if (file == NULL) 127680d496beSPekka Enberg goto out_failure; 127780d496beSPekka Enberg 127880d496beSPekka Enberg while (!feof(file)) { 12799cffa8d5SPaul Mackerras u64 start, size; 128080d496beSPekka Enberg struct symbol *sym; 128180d496beSPekka Enberg int line_len, len; 128280d496beSPekka Enberg 128380d496beSPekka Enberg line_len = getline(&line, &n, file); 128480d496beSPekka Enberg if (line_len < 0) 128580d496beSPekka Enberg break; 128680d496beSPekka Enberg 128780d496beSPekka Enberg if (!line) 128880d496beSPekka Enberg goto out_failure; 128980d496beSPekka Enberg 129080d496beSPekka Enberg line[--line_len] = '\0'; /* \n */ 129180d496beSPekka Enberg 129280d496beSPekka Enberg len = hex2u64(line, &start); 129380d496beSPekka Enberg 129480d496beSPekka Enberg len++; 129580d496beSPekka Enberg if (len + 2 >= line_len) 129680d496beSPekka Enberg continue; 129780d496beSPekka Enberg 129880d496beSPekka Enberg len += hex2u64(line + len, &size); 129980d496beSPekka Enberg 130080d496beSPekka Enberg len++; 130180d496beSPekka Enberg if (len + 2 >= line_len) 130280d496beSPekka Enberg continue; 130380d496beSPekka Enberg 1304c408fedfSArnaldo Carvalho de Melo sym = symbol__new(start, size, STB_GLOBAL, line + len); 130580d496beSPekka Enberg 130680d496beSPekka Enberg if (sym == NULL) 130780d496beSPekka Enberg goto out_delete_line; 130880d496beSPekka Enberg 1309439d473bSArnaldo Carvalho de Melo if (filter && filter(map, sym)) 131000a192b3SArnaldo Carvalho de Melo symbol__delete(sym); 131180d496beSPekka Enberg else { 1312aeafcbafSArnaldo Carvalho de Melo symbols__insert(&dso->symbols[map->type], sym); 131380d496beSPekka Enberg nr_syms++; 131480d496beSPekka Enberg } 131580d496beSPekka Enberg } 131680d496beSPekka Enberg 131780d496beSPekka Enberg free(line); 131880d496beSPekka Enberg fclose(file); 131980d496beSPekka Enberg 132080d496beSPekka Enberg return nr_syms; 132180d496beSPekka Enberg 132280d496beSPekka Enberg out_delete_line: 132380d496beSPekka Enberg free(line); 132480d496beSPekka Enberg out_failure: 132580d496beSPekka Enberg return -1; 132680d496beSPekka Enberg } 132780d496beSPekka Enberg 13281029f9feSNamhyung Kim static bool dso__is_compatible_symtab_type(struct dso *dso, bool kmod, 13291029f9feSNamhyung Kim enum dso_binary_type type) 13301029f9feSNamhyung Kim { 13311029f9feSNamhyung Kim switch (type) { 13321029f9feSNamhyung Kim case DSO_BINARY_TYPE__JAVA_JIT: 13331029f9feSNamhyung Kim case DSO_BINARY_TYPE__DEBUGLINK: 13341029f9feSNamhyung Kim case DSO_BINARY_TYPE__SYSTEM_PATH_DSO: 13351029f9feSNamhyung Kim case DSO_BINARY_TYPE__FEDORA_DEBUGINFO: 13361029f9feSNamhyung Kim case DSO_BINARY_TYPE__UBUNTU_DEBUGINFO: 13371029f9feSNamhyung Kim case DSO_BINARY_TYPE__BUILDID_DEBUGINFO: 13381029f9feSNamhyung Kim case DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO: 13391029f9feSNamhyung Kim return !kmod && dso->kernel == DSO_TYPE_USER; 13401029f9feSNamhyung Kim 13411029f9feSNamhyung Kim case DSO_BINARY_TYPE__KALLSYMS: 13421029f9feSNamhyung Kim case DSO_BINARY_TYPE__VMLINUX: 13431029f9feSNamhyung Kim case DSO_BINARY_TYPE__KCORE: 13441029f9feSNamhyung Kim return dso->kernel == DSO_TYPE_KERNEL; 13451029f9feSNamhyung Kim 13461029f9feSNamhyung Kim case DSO_BINARY_TYPE__GUEST_KALLSYMS: 13471029f9feSNamhyung Kim case DSO_BINARY_TYPE__GUEST_VMLINUX: 13481029f9feSNamhyung Kim case DSO_BINARY_TYPE__GUEST_KCORE: 13491029f9feSNamhyung Kim return dso->kernel == DSO_TYPE_GUEST_KERNEL; 13501029f9feSNamhyung Kim 13511029f9feSNamhyung Kim case DSO_BINARY_TYPE__GUEST_KMODULE: 1352c00c48fcSNamhyung Kim case DSO_BINARY_TYPE__GUEST_KMODULE_COMP: 13531029f9feSNamhyung Kim case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE: 1354c00c48fcSNamhyung Kim case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP: 13551029f9feSNamhyung Kim /* 13561029f9feSNamhyung Kim * kernel modules know their symtab type - it's set when 13579f2de315SArnaldo Carvalho de Melo * creating a module dso in machine__findnew_module_map(). 13581029f9feSNamhyung Kim */ 13591029f9feSNamhyung Kim return kmod && dso->symtab_type == type; 13601029f9feSNamhyung Kim 13611029f9feSNamhyung Kim case DSO_BINARY_TYPE__BUILD_ID_CACHE: 13621029f9feSNamhyung Kim return true; 13631029f9feSNamhyung Kim 13641029f9feSNamhyung Kim case DSO_BINARY_TYPE__NOT_FOUND: 13651029f9feSNamhyung Kim default: 13661029f9feSNamhyung Kim return false; 13671029f9feSNamhyung Kim } 13681029f9feSNamhyung Kim } 13691029f9feSNamhyung Kim 1370aeafcbafSArnaldo Carvalho de Melo int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter) 137186470930SIngo Molnar { 1372c338aee8SArnaldo Carvalho de Melo char *name; 137386470930SIngo Molnar int ret = -1; 137444f24cb3SJiri Olsa u_int i; 137523346f21SArnaldo Carvalho de Melo struct machine *machine; 137644f24cb3SJiri Olsa char *root_dir = (char *) ""; 13773aafe5aeSCody P Schafer int ss_pos = 0; 13783aafe5aeSCody P Schafer struct symsrc ss_[2]; 13793aafe5aeSCody P Schafer struct symsrc *syms_ss = NULL, *runtime_ss = NULL; 13801029f9feSNamhyung Kim bool kmod; 13815baecbcdSDima Kogan unsigned char build_id[BUILD_ID_SIZE]; 138286470930SIngo Molnar 13834a936edcSNamhyung Kim pthread_mutex_lock(&dso->lock); 138466bd8424SArnaldo Carvalho de Melo 13854a936edcSNamhyung Kim /* check again under the dso->lock */ 13864a936edcSNamhyung Kim if (dso__loaded(dso, map->type)) { 13874a936edcSNamhyung Kim ret = 1; 13884a936edcSNamhyung Kim goto out; 13894a936edcSNamhyung Kim } 13904a936edcSNamhyung Kim 13914a936edcSNamhyung Kim if (dso->kernel) { 1392aeafcbafSArnaldo Carvalho de Melo if (dso->kernel == DSO_TYPE_KERNEL) 13934a936edcSNamhyung Kim ret = dso__load_kernel_sym(dso, map, filter); 1394aeafcbafSArnaldo Carvalho de Melo else if (dso->kernel == DSO_TYPE_GUEST_KERNEL) 13954a936edcSNamhyung Kim ret = dso__load_guest_kernel_sym(dso, map, filter); 13964a936edcSNamhyung Kim 13974a936edcSNamhyung Kim goto out; 13984a936edcSNamhyung Kim } 1399a1645ce1SZhang, Yanmin 140023346f21SArnaldo Carvalho de Melo if (map->groups && map->groups->machine) 140123346f21SArnaldo Carvalho de Melo machine = map->groups->machine; 1402a1645ce1SZhang, Yanmin else 140323346f21SArnaldo Carvalho de Melo machine = NULL; 1404c338aee8SArnaldo Carvalho de Melo 1405aeafcbafSArnaldo Carvalho de Melo dso->adjust_symbols = 0; 1406f5812a7aSArnaldo Carvalho de Melo 1407aeafcbafSArnaldo Carvalho de Melo if (strncmp(dso->name, "/tmp/perf-", 10) == 0) { 1408981c1252SPekka Enberg struct stat st; 1409981c1252SPekka Enberg 1410e9b52ef2SVasiliy Kulikov if (lstat(dso->name, &st) < 0) 14114a936edcSNamhyung Kim goto out; 1412981c1252SPekka Enberg 14132059fc7aSArnaldo Carvalho de Melo if (!symbol_conf.force && st.st_uid && (st.st_uid != geteuid())) { 1414981c1252SPekka Enberg pr_warning("File %s not owned by current user or root, " 14152059fc7aSArnaldo Carvalho de Melo "ignoring it (use -f to override).\n", dso->name); 14164a936edcSNamhyung Kim goto out; 1417981c1252SPekka Enberg } 1418981c1252SPekka Enberg 1419aeafcbafSArnaldo Carvalho de Melo ret = dso__load_perf_map(dso, map, filter); 142044f24cb3SJiri Olsa dso->symtab_type = ret > 0 ? DSO_BINARY_TYPE__JAVA_JIT : 142144f24cb3SJiri Olsa DSO_BINARY_TYPE__NOT_FOUND; 14224a936edcSNamhyung Kim goto out; 142394cb9e38SArnaldo Carvalho de Melo } 142494cb9e38SArnaldo Carvalho de Melo 142544f24cb3SJiri Olsa if (machine) 142644f24cb3SJiri Olsa root_dir = machine->root_dir; 142744f24cb3SJiri Olsa 1428164c800eSDavid Ahern name = malloc(PATH_MAX); 1429164c800eSDavid Ahern if (!name) 14304a936edcSNamhyung Kim goto out; 1431164c800eSDavid Ahern 14321029f9feSNamhyung Kim kmod = dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE || 1433c00c48fcSNamhyung Kim dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP || 1434c00c48fcSNamhyung Kim dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE || 1435c00c48fcSNamhyung Kim dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE_COMP; 14361029f9feSNamhyung Kim 14375baecbcdSDima Kogan 14385baecbcdSDima Kogan /* 14395baecbcdSDima Kogan * Read the build id if possible. This is required for 14405baecbcdSDima Kogan * DSO_BINARY_TYPE__BUILDID_DEBUGINFO to work 14415baecbcdSDima Kogan */ 1442ed7b630bSJiri Olsa if (is_regular_file(dso->long_name) && 144340356721SJiri Olsa filename__read_build_id(dso->long_name, build_id, BUILD_ID_SIZE) > 0) 14445baecbcdSDima Kogan dso__set_build_id(dso, build_id); 14455baecbcdSDima Kogan 14461029f9feSNamhyung Kim /* 14471029f9feSNamhyung Kim * Iterate over candidate debug images. 14483aafe5aeSCody P Schafer * Keep track of "interesting" ones (those which have a symtab, dynsym, 14493aafe5aeSCody P Schafer * and/or opd section) for processing. 14506da80ce8SDave Martin */ 145144f24cb3SJiri Olsa for (i = 0; i < DSO_BINARY_TYPE__SYMTAB_CNT; i++) { 14523aafe5aeSCody P Schafer struct symsrc *ss = &ss_[ss_pos]; 14533aafe5aeSCody P Schafer bool next_slot = false; 145444f24cb3SJiri Olsa 1455005f9294SCody P Schafer enum dso_binary_type symtab_type = binary_type_symtab[i]; 145644f24cb3SJiri Olsa 14571029f9feSNamhyung Kim if (!dso__is_compatible_symtab_type(dso, kmod, symtab_type)) 14581029f9feSNamhyung Kim continue; 14591029f9feSNamhyung Kim 1460ee4e9625SArnaldo Carvalho de Melo if (dso__read_binary_type_filename(dso, symtab_type, 146144f24cb3SJiri Olsa root_dir, name, PATH_MAX)) 14626da80ce8SDave Martin continue; 146386470930SIngo Molnar 146440356721SJiri Olsa if (!is_regular_file(name)) 146540356721SJiri Olsa continue; 146640356721SJiri Olsa 14676da80ce8SDave Martin /* Name is now the name of the next image to try */ 14683aafe5aeSCody P Schafer if (symsrc__init(ss, dso, name, symtab_type) < 0) 14696da80ce8SDave Martin continue; 14706da80ce8SDave Martin 14713aafe5aeSCody P Schafer if (!syms_ss && symsrc__has_symtab(ss)) { 14723aafe5aeSCody P Schafer syms_ss = ss; 14733aafe5aeSCody P Schafer next_slot = true; 14740058aef6SAdrian Hunter if (!dso->symsrc_filename) 14750058aef6SAdrian Hunter dso->symsrc_filename = strdup(name); 1476d26cd12bSCody P Schafer } 1477d26cd12bSCody P Schafer 14783aafe5aeSCody P Schafer if (!runtime_ss && symsrc__possibly_runtime(ss)) { 14793aafe5aeSCody P Schafer runtime_ss = ss; 14803aafe5aeSCody P Schafer next_slot = true; 1481a44f605bSCody P Schafer } 148286470930SIngo Molnar 14833aafe5aeSCody P Schafer if (next_slot) { 14843aafe5aeSCody P Schafer ss_pos++; 148533ff581eSJiri Olsa 14863aafe5aeSCody P Schafer if (syms_ss && runtime_ss) 14876da80ce8SDave Martin break; 148898e9f03bSNamhyung Kim } else { 148998e9f03bSNamhyung Kim symsrc__destroy(ss); 1490a25e46c4SArnaldo Carvalho de Melo } 14913aafe5aeSCody P Schafer 14926da80ce8SDave Martin } 14936da80ce8SDave Martin 14943aafe5aeSCody P Schafer if (!runtime_ss && !syms_ss) 14953aafe5aeSCody P Schafer goto out_free; 14963aafe5aeSCody P Schafer 14973aafe5aeSCody P Schafer if (runtime_ss && !syms_ss) { 14983aafe5aeSCody P Schafer syms_ss = runtime_ss; 149960e4b10cSArnaldo Carvalho de Melo } 150060e4b10cSArnaldo Carvalho de Melo 15013aafe5aeSCody P Schafer /* We'll have to hope for the best */ 15023aafe5aeSCody P Schafer if (!runtime_ss && syms_ss) 15033aafe5aeSCody P Schafer runtime_ss = syms_ss; 15043aafe5aeSCody P Schafer 1505e7ee4047SWang Nan if (syms_ss && syms_ss->type == DSO_BINARY_TYPE__BUILD_ID_CACHE) 1506e7ee4047SWang Nan if (dso__build_id_is_kmod(dso, name, PATH_MAX)) 1507e7ee4047SWang Nan kmod = true; 1508e7ee4047SWang Nan 15091029f9feSNamhyung Kim if (syms_ss) 15101029f9feSNamhyung Kim ret = dso__load_sym(dso, map, syms_ss, runtime_ss, filter, kmod); 15111029f9feSNamhyung Kim else 15123aafe5aeSCody P Schafer ret = -1; 15133aafe5aeSCody P Schafer 1514f47b58b7SDavid Ahern if (ret > 0) { 15153aafe5aeSCody P Schafer int nr_plt; 15163aafe5aeSCody P Schafer 15173aafe5aeSCody P Schafer nr_plt = dso__synthesize_plt_symbols(dso, runtime_ss, map, filter); 15183aafe5aeSCody P Schafer if (nr_plt > 0) 15193aafe5aeSCody P Schafer ret += nr_plt; 15203aafe5aeSCody P Schafer } 15213aafe5aeSCody P Schafer 15223aafe5aeSCody P Schafer for (; ss_pos > 0; ss_pos--) 15233aafe5aeSCody P Schafer symsrc__destroy(&ss_[ss_pos - 1]); 15243aafe5aeSCody P Schafer out_free: 152586470930SIngo Molnar free(name); 1526aeafcbafSArnaldo Carvalho de Melo if (ret < 0 && strstr(dso->name, " (deleted)") != NULL) 15274a936edcSNamhyung Kim ret = 0; 15284a936edcSNamhyung Kim out: 15294a936edcSNamhyung Kim dso__set_loaded(dso, map->type); 15304a936edcSNamhyung Kim pthread_mutex_unlock(&dso->lock); 15314a936edcSNamhyung Kim 153286470930SIngo Molnar return ret; 153386470930SIngo Molnar } 153486470930SIngo Molnar 1535aeafcbafSArnaldo Carvalho de Melo struct map *map_groups__find_by_name(struct map_groups *mg, 153679406cd7SArnaldo Carvalho de Melo enum map_type type, const char *name) 1537439d473bSArnaldo Carvalho de Melo { 15381eee78aeSArnaldo Carvalho de Melo struct maps *maps = &mg->maps[type]; 15394bb7123dSArnaldo Carvalho de Melo struct map *map; 1540439d473bSArnaldo Carvalho de Melo 15416a2ffcddSArnaldo Carvalho de Melo pthread_rwlock_rdlock(&maps->lock); 15426a2ffcddSArnaldo Carvalho de Melo 15434bb7123dSArnaldo Carvalho de Melo for (map = maps__first(maps); map; map = map__next(map)) { 1544b7cece76SArnaldo Carvalho de Melo if (map->dso && strcmp(map->dso->short_name, name) == 0) 15456a2ffcddSArnaldo Carvalho de Melo goto out_unlock; 1546439d473bSArnaldo Carvalho de Melo } 1547439d473bSArnaldo Carvalho de Melo 15486a2ffcddSArnaldo Carvalho de Melo map = NULL; 15496a2ffcddSArnaldo Carvalho de Melo 15506a2ffcddSArnaldo Carvalho de Melo out_unlock: 15516a2ffcddSArnaldo Carvalho de Melo pthread_rwlock_unlock(&maps->lock); 15526a2ffcddSArnaldo Carvalho de Melo return map; 1553439d473bSArnaldo Carvalho de Melo } 1554439d473bSArnaldo Carvalho de Melo 1555aeafcbafSArnaldo Carvalho de Melo int dso__load_vmlinux(struct dso *dso, struct map *map, 15565230fb7dSArnaldo Carvalho de Melo const char *vmlinux, bool vmlinux_allocated, 15575230fb7dSArnaldo Carvalho de Melo symbol_filter_t filter) 155886470930SIngo Molnar { 1559b68e2f91SCody P Schafer int err = -1; 1560b68e2f91SCody P Schafer struct symsrc ss; 1561ec5761eaSDavid Ahern char symfs_vmlinux[PATH_MAX]; 1562005f9294SCody P Schafer enum dso_binary_type symtab_type; 156386470930SIngo Molnar 15645698d2c9SNamhyung Kim if (vmlinux[0] == '/') 15655698d2c9SNamhyung Kim snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s", vmlinux); 15665698d2c9SNamhyung Kim else 1567972f393bSArnaldo Carvalho de Melo symbol__join_symfs(symfs_vmlinux, vmlinux); 156886470930SIngo Molnar 156921ea4539SCody P Schafer if (dso->kernel == DSO_TYPE_GUEST_KERNEL) 1570005f9294SCody P Schafer symtab_type = DSO_BINARY_TYPE__GUEST_VMLINUX; 157121ea4539SCody P Schafer else 1572005f9294SCody P Schafer symtab_type = DSO_BINARY_TYPE__VMLINUX; 157321ea4539SCody P Schafer 1574005f9294SCody P Schafer if (symsrc__init(&ss, dso, symfs_vmlinux, symtab_type)) 1575b68e2f91SCody P Schafer return -1; 1576b68e2f91SCody P Schafer 1577261360b6SCody P Schafer err = dso__load_sym(dso, map, &ss, &ss, filter, 0); 1578b68e2f91SCody P Schafer symsrc__destroy(&ss); 157986470930SIngo Molnar 1580515850e4SCody P Schafer if (err > 0) { 158139b12f78SAdrian Hunter if (dso->kernel == DSO_TYPE_GUEST_KERNEL) 15825f70619dSArnaldo Carvalho de Melo dso->binary_type = DSO_BINARY_TYPE__GUEST_VMLINUX; 158339b12f78SAdrian Hunter else 15845f70619dSArnaldo Carvalho de Melo dso->binary_type = DSO_BINARY_TYPE__VMLINUX; 1585bf4414aeSArnaldo Carvalho de Melo dso__set_long_name(dso, vmlinux, vmlinux_allocated); 1586515850e4SCody P Schafer dso__set_loaded(dso, map->type); 1587ec5761eaSDavid Ahern pr_debug("Using %s for symbols\n", symfs_vmlinux); 1588515850e4SCody P Schafer } 15893846df2eSArnaldo Carvalho de Melo 159086470930SIngo Molnar return err; 159186470930SIngo Molnar } 159286470930SIngo Molnar 1593aeafcbafSArnaldo Carvalho de Melo int dso__load_vmlinux_path(struct dso *dso, struct map *map, 15949de89fe7SArnaldo Carvalho de Melo symbol_filter_t filter) 1595a19afe46SArnaldo Carvalho de Melo { 1596a19afe46SArnaldo Carvalho de Melo int i, err = 0; 159700dc8657SNamhyung Kim char *filename = NULL; 1598a19afe46SArnaldo Carvalho de Melo 1599dc38218eSArnaldo Carvalho de Melo pr_debug("Looking at the vmlinux_path (%d entries long)\n", 1600dc38218eSArnaldo Carvalho de Melo vmlinux_path__nr_entries + 1); 1601dc38218eSArnaldo Carvalho de Melo 1602dc38218eSArnaldo Carvalho de Melo for (i = 0; i < vmlinux_path__nr_entries; ++i) { 1603dc38218eSArnaldo Carvalho de Melo err = dso__load_vmlinux(dso, map, vmlinux_path[i], false, filter); 1604dc38218eSArnaldo Carvalho de Melo if (err > 0) 1605dc38218eSArnaldo Carvalho de Melo goto out; 1606dc38218eSArnaldo Carvalho de Melo } 1607dc38218eSArnaldo Carvalho de Melo 160800dc8657SNamhyung Kim if (!symbol_conf.ignore_vmlinux_buildid) 1609aeafcbafSArnaldo Carvalho de Melo filename = dso__build_id_filename(dso, NULL, 0); 16105ad90e4eSArnaldo Carvalho de Melo if (filename != NULL) { 16115230fb7dSArnaldo Carvalho de Melo err = dso__load_vmlinux(dso, map, filename, true, filter); 16125230fb7dSArnaldo Carvalho de Melo if (err > 0) 16135ad90e4eSArnaldo Carvalho de Melo goto out; 16145ad90e4eSArnaldo Carvalho de Melo free(filename); 16155ad90e4eSArnaldo Carvalho de Melo } 16165ad90e4eSArnaldo Carvalho de Melo out: 1617a19afe46SArnaldo Carvalho de Melo return err; 1618a19afe46SArnaldo Carvalho de Melo } 1619a19afe46SArnaldo Carvalho de Melo 1620c48903b8SMasami Hiramatsu static bool visible_dir_filter(const char *name, struct dirent *d) 1621c48903b8SMasami Hiramatsu { 1622c48903b8SMasami Hiramatsu if (d->d_type != DT_DIR) 1623c48903b8SMasami Hiramatsu return false; 1624c48903b8SMasami Hiramatsu return lsdir_no_dot_filter(name, d); 1625c48903b8SMasami Hiramatsu } 1626c48903b8SMasami Hiramatsu 16270544d422SAdrian Hunter static int find_matching_kcore(struct map *map, char *dir, size_t dir_sz) 16280544d422SAdrian Hunter { 16290544d422SAdrian Hunter char kallsyms_filename[PATH_MAX]; 16300544d422SAdrian Hunter int ret = -1; 1631c48903b8SMasami Hiramatsu struct strlist *dirs; 1632c48903b8SMasami Hiramatsu struct str_node *nd; 16330544d422SAdrian Hunter 1634c48903b8SMasami Hiramatsu dirs = lsdir(dir, visible_dir_filter); 1635c48903b8SMasami Hiramatsu if (!dirs) 16360544d422SAdrian Hunter return -1; 16370544d422SAdrian Hunter 1638602a1f4dSArnaldo Carvalho de Melo strlist__for_each_entry(nd, dirs) { 16390544d422SAdrian Hunter scnprintf(kallsyms_filename, sizeof(kallsyms_filename), 1640c48903b8SMasami Hiramatsu "%s/%s/kallsyms", dir, nd->s); 1641a00d28cbSAdrian Hunter if (!validate_kcore_addresses(kallsyms_filename, map)) { 16420544d422SAdrian Hunter strlcpy(dir, kallsyms_filename, dir_sz); 16430544d422SAdrian Hunter ret = 0; 16440544d422SAdrian Hunter break; 16450544d422SAdrian Hunter } 16460544d422SAdrian Hunter } 16470544d422SAdrian Hunter 1648c48903b8SMasami Hiramatsu strlist__delete(dirs); 16490544d422SAdrian Hunter 16500544d422SAdrian Hunter return ret; 16510544d422SAdrian Hunter } 16520544d422SAdrian Hunter 165311870d71SMasami Hiramatsu /* 165411870d71SMasami Hiramatsu * Use open(O_RDONLY) to check readability directly instead of access(R_OK) 165511870d71SMasami Hiramatsu * since access(R_OK) only checks with real UID/GID but open() use effective 165611870d71SMasami Hiramatsu * UID/GID and actual capabilities (e.g. /proc/kcore requires CAP_SYS_RAWIO). 165711870d71SMasami Hiramatsu */ 165811870d71SMasami Hiramatsu static bool filename__readable(const char *file) 165911870d71SMasami Hiramatsu { 166011870d71SMasami Hiramatsu int fd = open(file, O_RDONLY); 166111870d71SMasami Hiramatsu if (fd < 0) 166211870d71SMasami Hiramatsu return false; 166311870d71SMasami Hiramatsu close(fd); 166411870d71SMasami Hiramatsu return true; 166511870d71SMasami Hiramatsu } 166611870d71SMasami Hiramatsu 16670544d422SAdrian Hunter static char *dso__find_kallsyms(struct dso *dso, struct map *map) 16680544d422SAdrian Hunter { 16690544d422SAdrian Hunter u8 host_build_id[BUILD_ID_SIZE]; 1670b5d8bbe8SMasami Hiramatsu char sbuild_id[SBUILD_ID_SIZE]; 16710544d422SAdrian Hunter bool is_host = false; 16720544d422SAdrian Hunter char path[PATH_MAX]; 16730544d422SAdrian Hunter 16740544d422SAdrian Hunter if (!dso->has_build_id) { 16750544d422SAdrian Hunter /* 16760544d422SAdrian Hunter * Last resort, if we don't have a build-id and couldn't find 16770544d422SAdrian Hunter * any vmlinux file, try the running kernel kallsyms table. 16780544d422SAdrian Hunter */ 16790544d422SAdrian Hunter goto proc_kallsyms; 16800544d422SAdrian Hunter } 16810544d422SAdrian Hunter 16820544d422SAdrian Hunter if (sysfs__read_build_id("/sys/kernel/notes", host_build_id, 16830544d422SAdrian Hunter sizeof(host_build_id)) == 0) 16840544d422SAdrian Hunter is_host = dso__build_id_equal(dso, host_build_id); 16850544d422SAdrian Hunter 16864e4b6c06SMasami Hiramatsu /* Try a fast path for /proc/kallsyms if possible */ 16870544d422SAdrian Hunter if (is_host) { 16880544d422SAdrian Hunter /* 168911870d71SMasami Hiramatsu * Do not check the build-id cache, unless we know we cannot use 169011870d71SMasami Hiramatsu * /proc/kcore or module maps don't match to /proc/kallsyms. 169111870d71SMasami Hiramatsu * To check readability of /proc/kcore, do not use access(R_OK) 169211870d71SMasami Hiramatsu * since /proc/kcore requires CAP_SYS_RAWIO to read and access 169311870d71SMasami Hiramatsu * can't check it. 16940544d422SAdrian Hunter */ 169511870d71SMasami Hiramatsu if (filename__readable("/proc/kcore") && 169611870d71SMasami Hiramatsu !validate_kcore_addresses("/proc/kallsyms", map)) 16970544d422SAdrian Hunter goto proc_kallsyms; 16980544d422SAdrian Hunter } 16990544d422SAdrian Hunter 17004e4b6c06SMasami Hiramatsu build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id); 17014e4b6c06SMasami Hiramatsu 1702449867e3SAdrian Hunter /* Find kallsyms in build-id cache with kcore */ 17034e4b6c06SMasami Hiramatsu scnprintf(path, sizeof(path), "%s/%s/%s", 17044e4b6c06SMasami Hiramatsu buildid_dir, DSO__NAME_KCORE, sbuild_id); 17054e4b6c06SMasami Hiramatsu 1706449867e3SAdrian Hunter if (!find_matching_kcore(map, path, sizeof(path))) 1707449867e3SAdrian Hunter return strdup(path); 1708449867e3SAdrian Hunter 17094e4b6c06SMasami Hiramatsu /* Use current /proc/kallsyms if possible */ 17104e4b6c06SMasami Hiramatsu if (is_host) { 17114e4b6c06SMasami Hiramatsu proc_kallsyms: 17124e4b6c06SMasami Hiramatsu return strdup("/proc/kallsyms"); 17134e4b6c06SMasami Hiramatsu } 17144e4b6c06SMasami Hiramatsu 17154e4b6c06SMasami Hiramatsu /* Finally, find a cache of kallsyms */ 171601412261SMasami Hiramatsu if (!build_id_cache__kallsyms_path(sbuild_id, path, sizeof(path))) { 17170544d422SAdrian Hunter pr_err("No kallsyms or vmlinux with build-id %s was found\n", 17180544d422SAdrian Hunter sbuild_id); 17190544d422SAdrian Hunter return NULL; 17200544d422SAdrian Hunter } 17210544d422SAdrian Hunter 17220544d422SAdrian Hunter return strdup(path); 17230544d422SAdrian Hunter } 17240544d422SAdrian Hunter 1725aeafcbafSArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *dso, struct map *map, 17269de89fe7SArnaldo Carvalho de Melo symbol_filter_t filter) 172786470930SIngo Molnar { 1728cc612d81SArnaldo Carvalho de Melo int err; 17299e201442SArnaldo Carvalho de Melo const char *kallsyms_filename = NULL; 17309e201442SArnaldo Carvalho de Melo char *kallsyms_allocated_filename = NULL; 1731dc8d6ab2SArnaldo Carvalho de Melo /* 1732b226a5a7SDavid Ahern * Step 1: if the user specified a kallsyms or vmlinux filename, use 1733b226a5a7SDavid Ahern * it and only it, reporting errors to the user if it cannot be used. 1734dc8d6ab2SArnaldo Carvalho de Melo * 1735dc8d6ab2SArnaldo Carvalho de Melo * For instance, try to analyse an ARM perf.data file _without_ a 1736dc8d6ab2SArnaldo Carvalho de Melo * build-id, or if the user specifies the wrong path to the right 1737dc8d6ab2SArnaldo Carvalho de Melo * vmlinux file, obviously we can't fallback to another vmlinux (a 1738dc8d6ab2SArnaldo Carvalho de Melo * x86_86 one, on the machine where analysis is being performed, say), 1739dc8d6ab2SArnaldo Carvalho de Melo * or worse, /proc/kallsyms. 1740dc8d6ab2SArnaldo Carvalho de Melo * 1741dc8d6ab2SArnaldo Carvalho de Melo * If the specified file _has_ a build-id and there is a build-id 1742dc8d6ab2SArnaldo Carvalho de Melo * section in the perf.data file, we will still do the expected 1743dc8d6ab2SArnaldo Carvalho de Melo * validation in dso__load_vmlinux and will bail out if they don't 1744dc8d6ab2SArnaldo Carvalho de Melo * match. 1745dc8d6ab2SArnaldo Carvalho de Melo */ 1746b226a5a7SDavid Ahern if (symbol_conf.kallsyms_name != NULL) { 1747b226a5a7SDavid Ahern kallsyms_filename = symbol_conf.kallsyms_name; 1748b226a5a7SDavid Ahern goto do_kallsyms; 1749b226a5a7SDavid Ahern } 1750b226a5a7SDavid Ahern 1751fc2be696SWilly Tarreau if (!symbol_conf.ignore_vmlinux && symbol_conf.vmlinux_name != NULL) { 17525230fb7dSArnaldo Carvalho de Melo return dso__load_vmlinux(dso, map, symbol_conf.vmlinux_name, 17535230fb7dSArnaldo Carvalho de Melo false, filter); 1754dc8d6ab2SArnaldo Carvalho de Melo } 1755439d473bSArnaldo Carvalho de Melo 1756fc2be696SWilly Tarreau if (!symbol_conf.ignore_vmlinux && vmlinux_path != NULL) { 1757aeafcbafSArnaldo Carvalho de Melo err = dso__load_vmlinux_path(dso, map, filter); 1758a19afe46SArnaldo Carvalho de Melo if (err > 0) 175939b12f78SAdrian Hunter return err; 1760cc612d81SArnaldo Carvalho de Melo } 1761cc612d81SArnaldo Carvalho de Melo 1762ec5761eaSDavid Ahern /* do not try local files if a symfs was given */ 1763ec5761eaSDavid Ahern if (symbol_conf.symfs[0] != 0) 1764ec5761eaSDavid Ahern return -1; 1765ec5761eaSDavid Ahern 17660544d422SAdrian Hunter kallsyms_allocated_filename = dso__find_kallsyms(dso, map); 17670544d422SAdrian Hunter if (!kallsyms_allocated_filename) 17688d0591f6SArnaldo Carvalho de Melo return -1; 17698d0591f6SArnaldo Carvalho de Melo 177019fc2dedSArnaldo Carvalho de Melo kallsyms_filename = kallsyms_allocated_filename; 177119fc2dedSArnaldo Carvalho de Melo 1772dc8d6ab2SArnaldo Carvalho de Melo do_kallsyms: 1773aeafcbafSArnaldo Carvalho de Melo err = dso__load_kallsyms(dso, kallsyms_filename, map, filter); 17743846df2eSArnaldo Carvalho de Melo if (err > 0) 17753846df2eSArnaldo Carvalho de Melo pr_debug("Using %s for symbols\n", kallsyms_filename); 1776dc8d6ab2SArnaldo Carvalho de Melo free(kallsyms_allocated_filename); 1777dc8d6ab2SArnaldo Carvalho de Melo 17788e0cf965SAdrian Hunter if (err > 0 && !dso__is_kcore(dso)) { 1779bdac0bcfSAdrian Hunter dso->binary_type = DSO_BINARY_TYPE__KALLSYMS; 17800a77582fSMasami Hiramatsu dso__set_long_name(dso, DSO__NAME_KALLSYMS, false); 17816a4694a4SArnaldo Carvalho de Melo map__fixup_start(map); 17826a4694a4SArnaldo Carvalho de Melo map__fixup_end(map); 1783439d473bSArnaldo Carvalho de Melo } 178494cb9e38SArnaldo Carvalho de Melo 178586470930SIngo Molnar return err; 178686470930SIngo Molnar } 178786470930SIngo Molnar 1788aeafcbafSArnaldo Carvalho de Melo static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map, 1789a1645ce1SZhang, Yanmin symbol_filter_t filter) 1790a1645ce1SZhang, Yanmin { 1791a1645ce1SZhang, Yanmin int err; 1792a1645ce1SZhang, Yanmin const char *kallsyms_filename = NULL; 179323346f21SArnaldo Carvalho de Melo struct machine *machine; 1794a1645ce1SZhang, Yanmin char path[PATH_MAX]; 1795a1645ce1SZhang, Yanmin 1796a1645ce1SZhang, Yanmin if (!map->groups) { 1797a1645ce1SZhang, Yanmin pr_debug("Guest kernel map hasn't the point to groups\n"); 1798a1645ce1SZhang, Yanmin return -1; 1799a1645ce1SZhang, Yanmin } 180023346f21SArnaldo Carvalho de Melo machine = map->groups->machine; 1801a1645ce1SZhang, Yanmin 180223346f21SArnaldo Carvalho de Melo if (machine__is_default_guest(machine)) { 1803a1645ce1SZhang, Yanmin /* 1804a1645ce1SZhang, Yanmin * if the user specified a vmlinux filename, use it and only 1805a1645ce1SZhang, Yanmin * it, reporting errors to the user if it cannot be used. 1806a1645ce1SZhang, Yanmin * Or use file guest_kallsyms inputted by user on commandline 1807a1645ce1SZhang, Yanmin */ 1808a1645ce1SZhang, Yanmin if (symbol_conf.default_guest_vmlinux_name != NULL) { 1809aeafcbafSArnaldo Carvalho de Melo err = dso__load_vmlinux(dso, map, 18105230fb7dSArnaldo Carvalho de Melo symbol_conf.default_guest_vmlinux_name, 18115230fb7dSArnaldo Carvalho de Melo false, filter); 181239b12f78SAdrian Hunter return err; 1813a1645ce1SZhang, Yanmin } 1814a1645ce1SZhang, Yanmin 1815a1645ce1SZhang, Yanmin kallsyms_filename = symbol_conf.default_guest_kallsyms; 1816a1645ce1SZhang, Yanmin if (!kallsyms_filename) 1817a1645ce1SZhang, Yanmin return -1; 1818a1645ce1SZhang, Yanmin } else { 181923346f21SArnaldo Carvalho de Melo sprintf(path, "%s/proc/kallsyms", machine->root_dir); 1820a1645ce1SZhang, Yanmin kallsyms_filename = path; 1821a1645ce1SZhang, Yanmin } 1822a1645ce1SZhang, Yanmin 1823aeafcbafSArnaldo Carvalho de Melo err = dso__load_kallsyms(dso, kallsyms_filename, map, filter); 18248e0cf965SAdrian Hunter if (err > 0) 182539b12f78SAdrian Hunter pr_debug("Using %s for symbols\n", kallsyms_filename); 18268e0cf965SAdrian Hunter if (err > 0 && !dso__is_kcore(dso)) { 1827bdac0bcfSAdrian Hunter dso->binary_type = DSO_BINARY_TYPE__GUEST_KALLSYMS; 182848ea8f54SArnaldo Carvalho de Melo machine__mmap_name(machine, path, sizeof(path)); 18297e155d4dSArnaldo Carvalho de Melo dso__set_long_name(dso, strdup(path), true); 1830a1645ce1SZhang, Yanmin map__fixup_start(map); 1831a1645ce1SZhang, Yanmin map__fixup_end(map); 1832a1645ce1SZhang, Yanmin } 1833a1645ce1SZhang, Yanmin 1834a1645ce1SZhang, Yanmin return err; 1835a1645ce1SZhang, Yanmin } 1836cd84c2acSFrederic Weisbecker 1837cc612d81SArnaldo Carvalho de Melo static void vmlinux_path__exit(void) 18382446042cSArnaldo Carvalho de Melo { 183904662523SArnaldo Carvalho de Melo while (--vmlinux_path__nr_entries >= 0) 184004662523SArnaldo Carvalho de Melo zfree(&vmlinux_path[vmlinux_path__nr_entries]); 1841c4f03547SWang Nan vmlinux_path__nr_entries = 0; 1842cc612d81SArnaldo Carvalho de Melo 184304662523SArnaldo Carvalho de Melo zfree(&vmlinux_path); 1844cc612d81SArnaldo Carvalho de Melo } 1845cc612d81SArnaldo Carvalho de Melo 1846aac48647SEkaterina Tumanova static const char * const vmlinux_paths[] = { 1847aac48647SEkaterina Tumanova "vmlinux", 1848aac48647SEkaterina Tumanova "/boot/vmlinux" 1849aac48647SEkaterina Tumanova }; 1850aac48647SEkaterina Tumanova 1851aac48647SEkaterina Tumanova static const char * const vmlinux_paths_upd[] = { 1852aac48647SEkaterina Tumanova "/boot/vmlinux-%s", 1853aac48647SEkaterina Tumanova "/usr/lib/debug/boot/vmlinux-%s", 1854aac48647SEkaterina Tumanova "/lib/modules/%s/build/vmlinux", 1855f55ae954SEkaterina Tumanova "/usr/lib/debug/lib/modules/%s/vmlinux", 1856f55ae954SEkaterina Tumanova "/usr/lib/debug/boot/vmlinux-%s.debug" 1857aac48647SEkaterina Tumanova }; 1858aac48647SEkaterina Tumanova 1859aac48647SEkaterina Tumanova static int vmlinux_path__add(const char *new_entry) 1860aac48647SEkaterina Tumanova { 1861aac48647SEkaterina Tumanova vmlinux_path[vmlinux_path__nr_entries] = strdup(new_entry); 1862aac48647SEkaterina Tumanova if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 1863aac48647SEkaterina Tumanova return -1; 1864aac48647SEkaterina Tumanova ++vmlinux_path__nr_entries; 1865aac48647SEkaterina Tumanova 1866aac48647SEkaterina Tumanova return 0; 1867aac48647SEkaterina Tumanova } 1868aac48647SEkaterina Tumanova 1869ce80d3beSKan Liang static int vmlinux_path__init(struct perf_env *env) 1870cc612d81SArnaldo Carvalho de Melo { 1871cc612d81SArnaldo Carvalho de Melo struct utsname uts; 1872cc612d81SArnaldo Carvalho de Melo char bf[PATH_MAX]; 18730a7e6d1bSNamhyung Kim char *kernel_version; 1874aac48647SEkaterina Tumanova unsigned int i; 1875cc612d81SArnaldo Carvalho de Melo 1876aac48647SEkaterina Tumanova vmlinux_path = malloc(sizeof(char *) * (ARRAY_SIZE(vmlinux_paths) + 1877aac48647SEkaterina Tumanova ARRAY_SIZE(vmlinux_paths_upd))); 1878cc612d81SArnaldo Carvalho de Melo if (vmlinux_path == NULL) 1879cc612d81SArnaldo Carvalho de Melo return -1; 1880cc612d81SArnaldo Carvalho de Melo 1881aac48647SEkaterina Tumanova for (i = 0; i < ARRAY_SIZE(vmlinux_paths); i++) 1882aac48647SEkaterina Tumanova if (vmlinux_path__add(vmlinux_paths[i]) < 0) 1883cc612d81SArnaldo Carvalho de Melo goto out_fail; 1884ec5761eaSDavid Ahern 18850a7e6d1bSNamhyung Kim /* only try kernel version if no symfs was given */ 1886ec5761eaSDavid Ahern if (symbol_conf.symfs[0] != 0) 1887ec5761eaSDavid Ahern return 0; 1888ec5761eaSDavid Ahern 18890a7e6d1bSNamhyung Kim if (env) { 18900a7e6d1bSNamhyung Kim kernel_version = env->os_release; 18910a7e6d1bSNamhyung Kim } else { 1892ec5761eaSDavid Ahern if (uname(&uts) < 0) 1893e96c674fSNamhyung Kim goto out_fail; 1894ec5761eaSDavid Ahern 18950a7e6d1bSNamhyung Kim kernel_version = uts.release; 18960a7e6d1bSNamhyung Kim } 18970a7e6d1bSNamhyung Kim 1898aac48647SEkaterina Tumanova for (i = 0; i < ARRAY_SIZE(vmlinux_paths_upd); i++) { 1899aac48647SEkaterina Tumanova snprintf(bf, sizeof(bf), vmlinux_paths_upd[i], kernel_version); 1900aac48647SEkaterina Tumanova if (vmlinux_path__add(bf) < 0) 1901cc612d81SArnaldo Carvalho de Melo goto out_fail; 1902aac48647SEkaterina Tumanova } 1903cc612d81SArnaldo Carvalho de Melo 1904cc612d81SArnaldo Carvalho de Melo return 0; 1905cc612d81SArnaldo Carvalho de Melo 1906cc612d81SArnaldo Carvalho de Melo out_fail: 1907cc612d81SArnaldo Carvalho de Melo vmlinux_path__exit(); 1908cc612d81SArnaldo Carvalho de Melo return -1; 1909cc612d81SArnaldo Carvalho de Melo } 1910cc612d81SArnaldo Carvalho de Melo 19113bfe5f81SDavid Ahern int setup_list(struct strlist **list, const char *list_str, 1912655000e7SArnaldo Carvalho de Melo const char *list_name) 1913655000e7SArnaldo Carvalho de Melo { 1914655000e7SArnaldo Carvalho de Melo if (list_str == NULL) 1915655000e7SArnaldo Carvalho de Melo return 0; 1916655000e7SArnaldo Carvalho de Melo 19174a77e218SArnaldo Carvalho de Melo *list = strlist__new(list_str, NULL); 1918655000e7SArnaldo Carvalho de Melo if (!*list) { 1919655000e7SArnaldo Carvalho de Melo pr_err("problems parsing %s list\n", list_name); 1920655000e7SArnaldo Carvalho de Melo return -1; 1921655000e7SArnaldo Carvalho de Melo } 19220bc2f2f7SArnaldo Carvalho de Melo 19230bc2f2f7SArnaldo Carvalho de Melo symbol_conf.has_filter = true; 1924655000e7SArnaldo Carvalho de Melo return 0; 1925655000e7SArnaldo Carvalho de Melo } 1926655000e7SArnaldo Carvalho de Melo 1927e03eaa40SDavid Ahern int setup_intlist(struct intlist **list, const char *list_str, 1928e03eaa40SDavid Ahern const char *list_name) 1929e03eaa40SDavid Ahern { 1930e03eaa40SDavid Ahern if (list_str == NULL) 1931e03eaa40SDavid Ahern return 0; 1932e03eaa40SDavid Ahern 1933e03eaa40SDavid Ahern *list = intlist__new(list_str); 1934e03eaa40SDavid Ahern if (!*list) { 1935e03eaa40SDavid Ahern pr_err("problems parsing %s list\n", list_name); 1936e03eaa40SDavid Ahern return -1; 1937e03eaa40SDavid Ahern } 1938e03eaa40SDavid Ahern return 0; 1939e03eaa40SDavid Ahern } 1940e03eaa40SDavid Ahern 1941ec80fde7SArnaldo Carvalho de Melo static bool symbol__read_kptr_restrict(void) 1942ec80fde7SArnaldo Carvalho de Melo { 1943ec80fde7SArnaldo Carvalho de Melo bool value = false; 1944ec80fde7SArnaldo Carvalho de Melo FILE *fp = fopen("/proc/sys/kernel/kptr_restrict", "r"); 194538272dc4SWang Nan 1946ec80fde7SArnaldo Carvalho de Melo if (fp != NULL) { 1947ec80fde7SArnaldo Carvalho de Melo char line[8]; 1948ec80fde7SArnaldo Carvalho de Melo 1949ec80fde7SArnaldo Carvalho de Melo if (fgets(line, sizeof(line), fp) != NULL) 195038272dc4SWang Nan value = (geteuid() != 0) ? 195138272dc4SWang Nan (atoi(line) != 0) : 195238272dc4SWang Nan (atoi(line) == 2); 1953ec80fde7SArnaldo Carvalho de Melo 1954ec80fde7SArnaldo Carvalho de Melo fclose(fp); 1955ec80fde7SArnaldo Carvalho de Melo } 1956ec80fde7SArnaldo Carvalho de Melo 1957ec80fde7SArnaldo Carvalho de Melo return value; 1958ec80fde7SArnaldo Carvalho de Melo } 1959ec80fde7SArnaldo Carvalho de Melo 1960b01141f4SArnaldo Carvalho de Melo int symbol__annotation_init(void) 1961b01141f4SArnaldo Carvalho de Melo { 1962b01141f4SArnaldo Carvalho de Melo if (symbol_conf.initialized) { 1963b01141f4SArnaldo Carvalho de Melo pr_err("Annotation needs to be init before symbol__init()\n"); 1964b01141f4SArnaldo Carvalho de Melo return -1; 1965b01141f4SArnaldo Carvalho de Melo } 1966b01141f4SArnaldo Carvalho de Melo 1967b01141f4SArnaldo Carvalho de Melo if (symbol_conf.init_annotation) { 1968b01141f4SArnaldo Carvalho de Melo pr_warning("Annotation being initialized multiple times\n"); 1969b01141f4SArnaldo Carvalho de Melo return 0; 1970b01141f4SArnaldo Carvalho de Melo } 1971b01141f4SArnaldo Carvalho de Melo 1972b01141f4SArnaldo Carvalho de Melo symbol_conf.priv_size += sizeof(struct annotation); 1973b01141f4SArnaldo Carvalho de Melo symbol_conf.init_annotation = true; 1974b01141f4SArnaldo Carvalho de Melo return 0; 1975b01141f4SArnaldo Carvalho de Melo } 1976b01141f4SArnaldo Carvalho de Melo 1977ce80d3beSKan Liang int symbol__init(struct perf_env *env) 1978cc612d81SArnaldo Carvalho de Melo { 1979ec5761eaSDavid Ahern const char *symfs; 1980ec5761eaSDavid Ahern 198185e00b55SJovi Zhang if (symbol_conf.initialized) 198285e00b55SJovi Zhang return 0; 198385e00b55SJovi Zhang 19849ac3e487SIrina Tirdea symbol_conf.priv_size = PERF_ALIGN(symbol_conf.priv_size, sizeof(u64)); 19854d439517SDavid S. Miller 1986166ccc9cSNamhyung Kim symbol__elf_init(); 1987166ccc9cSNamhyung Kim 198875be6cf4SArnaldo Carvalho de Melo if (symbol_conf.sort_by_name) 198975be6cf4SArnaldo Carvalho de Melo symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) - 199079406cd7SArnaldo Carvalho de Melo sizeof(struct symbol)); 1991b32d133aSArnaldo Carvalho de Melo 19920a7e6d1bSNamhyung Kim if (symbol_conf.try_vmlinux_path && vmlinux_path__init(env) < 0) 1993cc612d81SArnaldo Carvalho de Melo return -1; 1994cc612d81SArnaldo Carvalho de Melo 1995c410a338SArnaldo Carvalho de Melo if (symbol_conf.field_sep && *symbol_conf.field_sep == '.') { 1996c410a338SArnaldo Carvalho de Melo pr_err("'.' is the only non valid --field-separator argument\n"); 1997c410a338SArnaldo Carvalho de Melo return -1; 1998c410a338SArnaldo Carvalho de Melo } 1999c410a338SArnaldo Carvalho de Melo 2000655000e7SArnaldo Carvalho de Melo if (setup_list(&symbol_conf.dso_list, 2001655000e7SArnaldo Carvalho de Melo symbol_conf.dso_list_str, "dso") < 0) 2002655000e7SArnaldo Carvalho de Melo return -1; 2003655000e7SArnaldo Carvalho de Melo 2004655000e7SArnaldo Carvalho de Melo if (setup_list(&symbol_conf.comm_list, 2005655000e7SArnaldo Carvalho de Melo symbol_conf.comm_list_str, "comm") < 0) 2006655000e7SArnaldo Carvalho de Melo goto out_free_dso_list; 2007655000e7SArnaldo Carvalho de Melo 2008e03eaa40SDavid Ahern if (setup_intlist(&symbol_conf.pid_list, 2009e03eaa40SDavid Ahern symbol_conf.pid_list_str, "pid") < 0) 2010e03eaa40SDavid Ahern goto out_free_comm_list; 2011e03eaa40SDavid Ahern 2012e03eaa40SDavid Ahern if (setup_intlist(&symbol_conf.tid_list, 2013e03eaa40SDavid Ahern symbol_conf.tid_list_str, "tid") < 0) 2014e03eaa40SDavid Ahern goto out_free_pid_list; 2015e03eaa40SDavid Ahern 2016655000e7SArnaldo Carvalho de Melo if (setup_list(&symbol_conf.sym_list, 2017655000e7SArnaldo Carvalho de Melo symbol_conf.sym_list_str, "symbol") < 0) 2018e03eaa40SDavid Ahern goto out_free_tid_list; 2019655000e7SArnaldo Carvalho de Melo 2020ec5761eaSDavid Ahern /* 2021ec5761eaSDavid Ahern * A path to symbols of "/" is identical to "" 2022ec5761eaSDavid Ahern * reset here for simplicity. 2023ec5761eaSDavid Ahern */ 2024ec5761eaSDavid Ahern symfs = realpath(symbol_conf.symfs, NULL); 2025ec5761eaSDavid Ahern if (symfs == NULL) 2026ec5761eaSDavid Ahern symfs = symbol_conf.symfs; 2027ec5761eaSDavid Ahern if (strcmp(symfs, "/") == 0) 2028ec5761eaSDavid Ahern symbol_conf.symfs = ""; 2029ec5761eaSDavid Ahern if (symfs != symbol_conf.symfs) 2030ec5761eaSDavid Ahern free((void *)symfs); 2031ec5761eaSDavid Ahern 2032ec80fde7SArnaldo Carvalho de Melo symbol_conf.kptr_restrict = symbol__read_kptr_restrict(); 2033ec80fde7SArnaldo Carvalho de Melo 203485e00b55SJovi Zhang symbol_conf.initialized = true; 20354aa65636SArnaldo Carvalho de Melo return 0; 2036655000e7SArnaldo Carvalho de Melo 2037e03eaa40SDavid Ahern out_free_tid_list: 2038e03eaa40SDavid Ahern intlist__delete(symbol_conf.tid_list); 2039e03eaa40SDavid Ahern out_free_pid_list: 2040e03eaa40SDavid Ahern intlist__delete(symbol_conf.pid_list); 2041655000e7SArnaldo Carvalho de Melo out_free_comm_list: 2042655000e7SArnaldo Carvalho de Melo strlist__delete(symbol_conf.comm_list); 2043d74c896bSNamhyung Kim out_free_dso_list: 2044d74c896bSNamhyung Kim strlist__delete(symbol_conf.dso_list); 2045655000e7SArnaldo Carvalho de Melo return -1; 2046cc612d81SArnaldo Carvalho de Melo } 2047cc612d81SArnaldo Carvalho de Melo 2048d65a458bSArnaldo Carvalho de Melo void symbol__exit(void) 2049d65a458bSArnaldo Carvalho de Melo { 205085e00b55SJovi Zhang if (!symbol_conf.initialized) 205185e00b55SJovi Zhang return; 2052d65a458bSArnaldo Carvalho de Melo strlist__delete(symbol_conf.sym_list); 2053d65a458bSArnaldo Carvalho de Melo strlist__delete(symbol_conf.dso_list); 2054d65a458bSArnaldo Carvalho de Melo strlist__delete(symbol_conf.comm_list); 2055e03eaa40SDavid Ahern intlist__delete(symbol_conf.tid_list); 2056e03eaa40SDavid Ahern intlist__delete(symbol_conf.pid_list); 2057d65a458bSArnaldo Carvalho de Melo vmlinux_path__exit(); 2058d65a458bSArnaldo Carvalho de Melo symbol_conf.sym_list = symbol_conf.dso_list = symbol_conf.comm_list = NULL; 205985e00b55SJovi Zhang symbol_conf.initialized = false; 2060d65a458bSArnaldo Carvalho de Melo } 2061a7066709SHe Kuang 2062a7066709SHe Kuang int symbol__config_symfs(const struct option *opt __maybe_unused, 2063a7066709SHe Kuang const char *dir, int unset __maybe_unused) 2064a7066709SHe Kuang { 2065a7066709SHe Kuang char *bf = NULL; 2066a7066709SHe Kuang int ret; 2067a7066709SHe Kuang 2068a7066709SHe Kuang symbol_conf.symfs = strdup(dir); 2069a7066709SHe Kuang if (symbol_conf.symfs == NULL) 2070a7066709SHe Kuang return -ENOMEM; 2071a7066709SHe Kuang 2072a7066709SHe Kuang /* skip the locally configured cache if a symfs is given, and 2073a7066709SHe Kuang * config buildid dir to symfs/.debug 2074a7066709SHe Kuang */ 2075a7066709SHe Kuang ret = asprintf(&bf, "%s/%s", dir, ".debug"); 2076a7066709SHe Kuang if (ret < 0) 2077a7066709SHe Kuang return -ENOMEM; 2078a7066709SHe Kuang 2079a7066709SHe Kuang set_buildid_dir(bf); 2080a7066709SHe Kuang 2081a7066709SHe Kuang free(bf); 2082a7066709SHe Kuang return 0; 2083a7066709SHe Kuang } 2084