15aab621bSArnaldo Carvalho de Melo #include <dirent.h> 25aab621bSArnaldo Carvalho de Melo #include <errno.h> 35aab621bSArnaldo Carvalho de Melo #include <stdlib.h> 45aab621bSArnaldo Carvalho de Melo #include <stdio.h> 55aab621bSArnaldo Carvalho de Melo #include <string.h> 65aab621bSArnaldo Carvalho de Melo #include <sys/types.h> 75aab621bSArnaldo Carvalho de Melo #include <sys/stat.h> 85aab621bSArnaldo Carvalho de Melo #include <sys/param.h> 95aab621bSArnaldo Carvalho de Melo #include <fcntl.h> 105aab621bSArnaldo Carvalho de Melo #include <unistd.h> 119486aa38SArnaldo Carvalho de Melo #include <inttypes.h> 12b36f19d5SArnaldo Carvalho de Melo #include "build-id.h" 13e334c726SNamhyung Kim #include "util.h" 148a6c5b26SArnaldo Carvalho de Melo #include "debug.h" 1586470930SIngo Molnar #include "symbol.h" 165aab621bSArnaldo Carvalho de Melo #include "strlist.h" 1786470930SIngo Molnar 1886470930SIngo Molnar #include <elf.h> 19f1617b40SArnaldo Carvalho de Melo #include <limits.h> 20439d473bSArnaldo Carvalho de Melo #include <sys/utsname.h> 212cdbc46dSPeter Zijlstra 223b01a413SArnaldo Carvalho de Melo #ifndef KSYM_NAME_LEN 23c752d040SRicardo Ribalda Delgado #define KSYM_NAME_LEN 256 243b01a413SArnaldo Carvalho de Melo #endif 253b01a413SArnaldo Carvalho de Melo 264dff624aSJiri Olsa static void dso_cache__free(struct rb_root *root); 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); 31cc612d81SArnaldo Carvalho de Melo static int vmlinux_path__nr_entries; 32cc612d81SArnaldo Carvalho de Melo static char **vmlinux_path; 33439d473bSArnaldo Carvalho de Melo 3475be6cf4SArnaldo Carvalho de Melo struct symbol_conf symbol_conf = { 35d599db3fSArnaldo Carvalho de Melo .exclude_other = true, 36b32d133aSArnaldo Carvalho de Melo .use_modules = true, 37b32d133aSArnaldo Carvalho de Melo .try_vmlinux_path = true, 383e6a2a7fSStephane Eranian .annotate_src = true, 39ec5761eaSDavid Ahern .symfs = "", 40b32d133aSArnaldo Carvalho de Melo }; 41b32d133aSArnaldo Carvalho de Melo 4244f24cb3SJiri Olsa static enum dso_binary_type binary_type_symtab[] = { 4344f24cb3SJiri Olsa DSO_BINARY_TYPE__KALLSYMS, 4444f24cb3SJiri Olsa DSO_BINARY_TYPE__GUEST_KALLSYMS, 4544f24cb3SJiri Olsa DSO_BINARY_TYPE__JAVA_JIT, 4644f24cb3SJiri Olsa DSO_BINARY_TYPE__DEBUGLINK, 4744f24cb3SJiri Olsa DSO_BINARY_TYPE__BUILD_ID_CACHE, 4844f24cb3SJiri Olsa DSO_BINARY_TYPE__FEDORA_DEBUGINFO, 4944f24cb3SJiri Olsa DSO_BINARY_TYPE__UBUNTU_DEBUGINFO, 5044f24cb3SJiri Olsa DSO_BINARY_TYPE__BUILDID_DEBUGINFO, 5144f24cb3SJiri Olsa DSO_BINARY_TYPE__SYSTEM_PATH_DSO, 5244f24cb3SJiri Olsa DSO_BINARY_TYPE__GUEST_KMODULE, 5344f24cb3SJiri Olsa DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE, 5444f24cb3SJiri Olsa DSO_BINARY_TYPE__NOT_FOUND, 5544f24cb3SJiri Olsa }; 5644f24cb3SJiri Olsa 57028df767SJiri Olsa #define DSO_BINARY_TYPE__SYMTAB_CNT ARRAY_SIZE(binary_type_symtab) 5844f24cb3SJiri Olsa 59949d160bSJiri Olsa static enum dso_binary_type binary_type_data[] = { 60949d160bSJiri Olsa DSO_BINARY_TYPE__BUILD_ID_CACHE, 61949d160bSJiri Olsa DSO_BINARY_TYPE__SYSTEM_PATH_DSO, 62949d160bSJiri Olsa DSO_BINARY_TYPE__NOT_FOUND, 63949d160bSJiri Olsa }; 64949d160bSJiri Olsa 65028df767SJiri Olsa #define DSO_BINARY_TYPE__DATA_CNT ARRAY_SIZE(binary_type_data) 66949d160bSJiri Olsa 67aeafcbafSArnaldo Carvalho de Melo int dso__name_len(const struct dso *dso) 688a6c5b26SArnaldo Carvalho de Melo { 691e2dd2f7SDavid Miller if (!dso) 701e2dd2f7SDavid Miller return strlen("[unknown]"); 718a6c5b26SArnaldo Carvalho de Melo if (verbose) 72aeafcbafSArnaldo Carvalho de Melo return dso->long_name_len; 738a6c5b26SArnaldo Carvalho de Melo 74aeafcbafSArnaldo Carvalho de Melo return dso->short_name_len; 758a6c5b26SArnaldo Carvalho de Melo } 768a6c5b26SArnaldo Carvalho de Melo 77aeafcbafSArnaldo Carvalho de Melo bool dso__loaded(const struct dso *dso, enum map_type type) 783610583cSArnaldo Carvalho de Melo { 79aeafcbafSArnaldo Carvalho de Melo return dso->loaded & (1 << type); 803610583cSArnaldo Carvalho de Melo } 813610583cSArnaldo Carvalho de Melo 82aeafcbafSArnaldo Carvalho de Melo bool dso__sorted_by_name(const struct dso *dso, enum map_type type) 8379406cd7SArnaldo Carvalho de Melo { 84aeafcbafSArnaldo Carvalho de Melo return dso->sorted_by_name & (1 << type); 8579406cd7SArnaldo Carvalho de Melo } 8679406cd7SArnaldo Carvalho de Melo 87aeafcbafSArnaldo Carvalho de Melo static void dso__set_sorted_by_name(struct dso *dso, enum map_type type) 8879406cd7SArnaldo Carvalho de Melo { 89aeafcbafSArnaldo Carvalho de Melo dso->sorted_by_name |= (1 << type); 9079406cd7SArnaldo Carvalho de Melo } 9179406cd7SArnaldo Carvalho de Melo 9236a3e646SArnaldo Carvalho de Melo bool symbol_type__is_a(char symbol_type, enum map_type map_type) 936893d4eeSArnaldo Carvalho de Melo { 9431877908SAnton Blanchard symbol_type = toupper(symbol_type); 9531877908SAnton Blanchard 966893d4eeSArnaldo Carvalho de Melo switch (map_type) { 976893d4eeSArnaldo Carvalho de Melo case MAP__FUNCTION: 986893d4eeSArnaldo Carvalho de Melo return symbol_type == 'T' || symbol_type == 'W'; 99f1dfa0b1SArnaldo Carvalho de Melo case MAP__VARIABLE: 10031877908SAnton Blanchard return symbol_type == 'D'; 1016893d4eeSArnaldo Carvalho de Melo default: 1026893d4eeSArnaldo Carvalho de Melo return false; 1036893d4eeSArnaldo Carvalho de Melo } 1046893d4eeSArnaldo Carvalho de Melo } 1056893d4eeSArnaldo Carvalho de Melo 106694bf407SAnton Blanchard static int prefix_underscores_count(const char *str) 107694bf407SAnton Blanchard { 108694bf407SAnton Blanchard const char *tail = str; 109694bf407SAnton Blanchard 110694bf407SAnton Blanchard while (*tail == '_') 111694bf407SAnton Blanchard tail++; 112694bf407SAnton Blanchard 113694bf407SAnton Blanchard return tail - str; 114694bf407SAnton Blanchard } 115694bf407SAnton Blanchard 116694bf407SAnton Blanchard #define SYMBOL_A 0 117694bf407SAnton Blanchard #define SYMBOL_B 1 118694bf407SAnton Blanchard 119694bf407SAnton Blanchard static int choose_best_symbol(struct symbol *syma, struct symbol *symb) 120694bf407SAnton Blanchard { 121694bf407SAnton Blanchard s64 a; 122694bf407SAnton Blanchard s64 b; 123694bf407SAnton Blanchard 124694bf407SAnton Blanchard /* Prefer a symbol with non zero length */ 125694bf407SAnton Blanchard a = syma->end - syma->start; 126694bf407SAnton Blanchard b = symb->end - symb->start; 127694bf407SAnton Blanchard if ((b == 0) && (a > 0)) 128694bf407SAnton Blanchard return SYMBOL_A; 129694bf407SAnton Blanchard else if ((a == 0) && (b > 0)) 130694bf407SAnton Blanchard return SYMBOL_B; 131694bf407SAnton Blanchard 132694bf407SAnton Blanchard /* Prefer a non weak symbol over a weak one */ 133694bf407SAnton Blanchard a = syma->binding == STB_WEAK; 134694bf407SAnton Blanchard b = symb->binding == STB_WEAK; 135694bf407SAnton Blanchard if (b && !a) 136694bf407SAnton Blanchard return SYMBOL_A; 137694bf407SAnton Blanchard if (a && !b) 138694bf407SAnton Blanchard return SYMBOL_B; 139694bf407SAnton Blanchard 140694bf407SAnton Blanchard /* Prefer a global symbol over a non global one */ 141694bf407SAnton Blanchard a = syma->binding == STB_GLOBAL; 142694bf407SAnton Blanchard b = symb->binding == STB_GLOBAL; 143694bf407SAnton Blanchard if (a && !b) 144694bf407SAnton Blanchard return SYMBOL_A; 145694bf407SAnton Blanchard if (b && !a) 146694bf407SAnton Blanchard return SYMBOL_B; 147694bf407SAnton Blanchard 148694bf407SAnton Blanchard /* Prefer a symbol with less underscores */ 149694bf407SAnton Blanchard a = prefix_underscores_count(syma->name); 150694bf407SAnton Blanchard b = prefix_underscores_count(symb->name); 151694bf407SAnton Blanchard if (b > a) 152694bf407SAnton Blanchard return SYMBOL_A; 153694bf407SAnton Blanchard else if (a > b) 154694bf407SAnton Blanchard return SYMBOL_B; 155694bf407SAnton Blanchard 156694bf407SAnton Blanchard /* If all else fails, choose the symbol with the longest name */ 157694bf407SAnton Blanchard if (strlen(syma->name) >= strlen(symb->name)) 158694bf407SAnton Blanchard return SYMBOL_A; 159694bf407SAnton Blanchard else 160694bf407SAnton Blanchard return SYMBOL_B; 161694bf407SAnton Blanchard } 162694bf407SAnton Blanchard 163e5a1845fSNamhyung Kim void symbols__fixup_duplicate(struct rb_root *symbols) 164694bf407SAnton Blanchard { 165694bf407SAnton Blanchard struct rb_node *nd; 166694bf407SAnton Blanchard struct symbol *curr, *next; 167694bf407SAnton Blanchard 168694bf407SAnton Blanchard nd = rb_first(symbols); 169694bf407SAnton Blanchard 170694bf407SAnton Blanchard while (nd) { 171694bf407SAnton Blanchard curr = rb_entry(nd, struct symbol, rb_node); 172694bf407SAnton Blanchard again: 173694bf407SAnton Blanchard nd = rb_next(&curr->rb_node); 174694bf407SAnton Blanchard next = rb_entry(nd, struct symbol, rb_node); 175694bf407SAnton Blanchard 176694bf407SAnton Blanchard if (!nd) 177694bf407SAnton Blanchard break; 178694bf407SAnton Blanchard 179694bf407SAnton Blanchard if (curr->start != next->start) 180694bf407SAnton Blanchard continue; 181694bf407SAnton Blanchard 182694bf407SAnton Blanchard if (choose_best_symbol(curr, next) == SYMBOL_A) { 183694bf407SAnton Blanchard rb_erase(&next->rb_node, symbols); 184694bf407SAnton Blanchard goto again; 185694bf407SAnton Blanchard } else { 186694bf407SAnton Blanchard nd = rb_next(&curr->rb_node); 187694bf407SAnton Blanchard rb_erase(&curr->rb_node, symbols); 188694bf407SAnton Blanchard } 189694bf407SAnton Blanchard } 190694bf407SAnton Blanchard } 191694bf407SAnton Blanchard 192e5a1845fSNamhyung Kim void symbols__fixup_end(struct rb_root *symbols) 193af427bf5SArnaldo Carvalho de Melo { 194aeafcbafSArnaldo Carvalho de Melo struct rb_node *nd, *prevnd = rb_first(symbols); 1952e538c4aSArnaldo Carvalho de Melo struct symbol *curr, *prev; 196af427bf5SArnaldo Carvalho de Melo 197af427bf5SArnaldo Carvalho de Melo if (prevnd == NULL) 198af427bf5SArnaldo Carvalho de Melo return; 199af427bf5SArnaldo Carvalho de Melo 2002e538c4aSArnaldo Carvalho de Melo curr = rb_entry(prevnd, struct symbol, rb_node); 2012e538c4aSArnaldo Carvalho de Melo 202af427bf5SArnaldo Carvalho de Melo for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) { 2032e538c4aSArnaldo Carvalho de Melo prev = curr; 2042e538c4aSArnaldo Carvalho de Melo curr = rb_entry(nd, struct symbol, rb_node); 205af427bf5SArnaldo Carvalho de Melo 2063b01a413SArnaldo Carvalho de Melo if (prev->end == prev->start && prev->end != curr->start) 207af427bf5SArnaldo Carvalho de Melo prev->end = curr->start - 1; 208af427bf5SArnaldo Carvalho de Melo } 209af427bf5SArnaldo Carvalho de Melo 2102e538c4aSArnaldo Carvalho de Melo /* Last entry */ 2112e538c4aSArnaldo Carvalho de Melo if (curr->end == curr->start) 2122e538c4aSArnaldo Carvalho de Melo curr->end = roundup(curr->start, 4096); 2132e538c4aSArnaldo Carvalho de Melo } 2142e538c4aSArnaldo Carvalho de Melo 215e5a1845fSNamhyung Kim void __map_groups__fixup_end(struct map_groups *mg, enum map_type type) 216af427bf5SArnaldo Carvalho de Melo { 217af427bf5SArnaldo Carvalho de Melo struct map *prev, *curr; 218aeafcbafSArnaldo Carvalho de Melo struct rb_node *nd, *prevnd = rb_first(&mg->maps[type]); 219af427bf5SArnaldo Carvalho de Melo 220af427bf5SArnaldo Carvalho de Melo if (prevnd == NULL) 221af427bf5SArnaldo Carvalho de Melo return; 222af427bf5SArnaldo Carvalho de Melo 223af427bf5SArnaldo Carvalho de Melo curr = rb_entry(prevnd, struct map, rb_node); 224af427bf5SArnaldo Carvalho de Melo 225af427bf5SArnaldo Carvalho de Melo for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) { 226af427bf5SArnaldo Carvalho de Melo prev = curr; 227af427bf5SArnaldo Carvalho de Melo curr = rb_entry(nd, struct map, rb_node); 228af427bf5SArnaldo Carvalho de Melo prev->end = curr->start - 1; 2292e538c4aSArnaldo Carvalho de Melo } 23090c83218SArnaldo Carvalho de Melo 23190c83218SArnaldo Carvalho de Melo /* 23290c83218SArnaldo Carvalho de Melo * We still haven't the actual symbols, so guess the 23390c83218SArnaldo Carvalho de Melo * last map final address. 23490c83218SArnaldo Carvalho de Melo */ 2359d1faba5SIan Munsie curr->end = ~0ULL; 236af427bf5SArnaldo Carvalho de Melo } 237af427bf5SArnaldo Carvalho de Melo 238aeafcbafSArnaldo Carvalho de Melo static void map_groups__fixup_end(struct map_groups *mg) 23923ea4a3fSArnaldo Carvalho de Melo { 24023ea4a3fSArnaldo Carvalho de Melo int i; 24123ea4a3fSArnaldo Carvalho de Melo for (i = 0; i < MAP__NR_TYPES; ++i) 242aeafcbafSArnaldo Carvalho de Melo __map_groups__fixup_end(mg, i); 24323ea4a3fSArnaldo Carvalho de Melo } 24423ea4a3fSArnaldo Carvalho de Melo 245e5a1845fSNamhyung Kim struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name) 24686470930SIngo Molnar { 24786470930SIngo Molnar size_t namelen = strlen(name) + 1; 248aeafcbafSArnaldo Carvalho de Melo struct symbol *sym = calloc(1, (symbol_conf.priv_size + 249aeafcbafSArnaldo Carvalho de Melo sizeof(*sym) + namelen)); 250aeafcbafSArnaldo Carvalho de Melo if (sym == NULL) 25186470930SIngo Molnar return NULL; 25286470930SIngo Molnar 25375be6cf4SArnaldo Carvalho de Melo if (symbol_conf.priv_size) 254aeafcbafSArnaldo Carvalho de Melo sym = ((void *)sym) + symbol_conf.priv_size; 25536479484SArnaldo Carvalho de Melo 256aeafcbafSArnaldo Carvalho de Melo sym->start = start; 257aeafcbafSArnaldo Carvalho de Melo sym->end = len ? start + len - 1 : start; 258aeafcbafSArnaldo Carvalho de Melo sym->binding = binding; 259aeafcbafSArnaldo Carvalho de Melo sym->namelen = namelen - 1; 260e4204992SArnaldo Carvalho de Melo 261aeafcbafSArnaldo Carvalho de Melo pr_debug4("%s: %s %#" PRIx64 "-%#" PRIx64 "\n", 262aeafcbafSArnaldo Carvalho de Melo __func__, name, start, sym->end); 263aeafcbafSArnaldo Carvalho de Melo memcpy(sym->name, name, namelen); 264e4204992SArnaldo Carvalho de Melo 265aeafcbafSArnaldo Carvalho de Melo return sym; 26686470930SIngo Molnar } 26786470930SIngo Molnar 268aeafcbafSArnaldo Carvalho de Melo void symbol__delete(struct symbol *sym) 26986470930SIngo Molnar { 270aeafcbafSArnaldo Carvalho de Melo free(((void *)sym) - symbol_conf.priv_size); 27186470930SIngo Molnar } 27286470930SIngo Molnar 273aeafcbafSArnaldo Carvalho de Melo static size_t symbol__fprintf(struct symbol *sym, FILE *fp) 27486470930SIngo Molnar { 2759486aa38SArnaldo Carvalho de Melo return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %c %s\n", 276aeafcbafSArnaldo Carvalho de Melo sym->start, sym->end, 277aeafcbafSArnaldo Carvalho de Melo sym->binding == STB_GLOBAL ? 'g' : 278aeafcbafSArnaldo Carvalho de Melo sym->binding == STB_LOCAL ? 'l' : 'w', 279aeafcbafSArnaldo Carvalho de Melo sym->name); 28086470930SIngo Molnar } 28186470930SIngo Molnar 282a978f2abSAkihiro Nagai size_t symbol__fprintf_symname_offs(const struct symbol *sym, 283a978f2abSAkihiro Nagai const struct addr_location *al, FILE *fp) 284a978f2abSAkihiro Nagai { 285a978f2abSAkihiro Nagai unsigned long offset; 286a978f2abSAkihiro Nagai size_t length; 287a978f2abSAkihiro Nagai 288a978f2abSAkihiro Nagai if (sym && sym->name) { 289a978f2abSAkihiro Nagai length = fprintf(fp, "%s", sym->name); 290a978f2abSAkihiro Nagai if (al) { 291a978f2abSAkihiro Nagai offset = al->addr - sym->start; 292a978f2abSAkihiro Nagai length += fprintf(fp, "+0x%lx", offset); 293a978f2abSAkihiro Nagai } 294a978f2abSAkihiro Nagai return length; 295a978f2abSAkihiro Nagai } else 296a978f2abSAkihiro Nagai return fprintf(fp, "[unknown]"); 297a978f2abSAkihiro Nagai } 298a978f2abSAkihiro Nagai 299547a92e0SAkihiro Nagai size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp) 300547a92e0SAkihiro Nagai { 301a978f2abSAkihiro Nagai return symbol__fprintf_symname_offs(sym, NULL, fp); 302547a92e0SAkihiro Nagai } 303547a92e0SAkihiro Nagai 304aeafcbafSArnaldo Carvalho de Melo void dso__set_long_name(struct dso *dso, char *name) 305cfc10d3bSArnaldo Carvalho de Melo { 306ef6ae724SArnaldo Carvalho de Melo if (name == NULL) 307ef6ae724SArnaldo Carvalho de Melo return; 308aeafcbafSArnaldo Carvalho de Melo dso->long_name = name; 309aeafcbafSArnaldo Carvalho de Melo dso->long_name_len = strlen(name); 310cfc10d3bSArnaldo Carvalho de Melo } 311cfc10d3bSArnaldo Carvalho de Melo 312aeafcbafSArnaldo Carvalho de Melo static void dso__set_short_name(struct dso *dso, const char *name) 313b63be8d7SArnaldo Carvalho de Melo { 314b63be8d7SArnaldo Carvalho de Melo if (name == NULL) 315b63be8d7SArnaldo Carvalho de Melo return; 316aeafcbafSArnaldo Carvalho de Melo dso->short_name = name; 317aeafcbafSArnaldo Carvalho de Melo dso->short_name_len = strlen(name); 318b63be8d7SArnaldo Carvalho de Melo } 319b63be8d7SArnaldo Carvalho de Melo 320aeafcbafSArnaldo Carvalho de Melo static void dso__set_basename(struct dso *dso) 321cfc10d3bSArnaldo Carvalho de Melo { 322aeafcbafSArnaldo Carvalho de Melo dso__set_short_name(dso, basename(dso->long_name)); 323cfc10d3bSArnaldo Carvalho de Melo } 324cfc10d3bSArnaldo Carvalho de Melo 32500a192b3SArnaldo Carvalho de Melo struct dso *dso__new(const char *name) 32686470930SIngo Molnar { 327aeafcbafSArnaldo Carvalho de Melo struct dso *dso = calloc(1, sizeof(*dso) + strlen(name) + 1); 32886470930SIngo Molnar 329aeafcbafSArnaldo Carvalho de Melo if (dso != NULL) { 3306a4694a4SArnaldo Carvalho de Melo int i; 331aeafcbafSArnaldo Carvalho de Melo strcpy(dso->name, name); 332aeafcbafSArnaldo Carvalho de Melo dso__set_long_name(dso, dso->name); 333aeafcbafSArnaldo Carvalho de Melo dso__set_short_name(dso, dso->name); 3346a4694a4SArnaldo Carvalho de Melo for (i = 0; i < MAP__NR_TYPES; ++i) 335aeafcbafSArnaldo Carvalho de Melo dso->symbols[i] = dso->symbol_names[i] = RB_ROOT; 3364dff624aSJiri Olsa dso->cache = RB_ROOT; 33744f24cb3SJiri Olsa dso->symtab_type = DSO_BINARY_TYPE__NOT_FOUND; 338949d160bSJiri Olsa dso->data_type = DSO_BINARY_TYPE__NOT_FOUND; 339aeafcbafSArnaldo Carvalho de Melo dso->loaded = 0; 340aeafcbafSArnaldo Carvalho de Melo dso->sorted_by_name = 0; 341aeafcbafSArnaldo Carvalho de Melo dso->has_build_id = 0; 342aeafcbafSArnaldo Carvalho de Melo dso->kernel = DSO_TYPE_USER; 3438db4841fSJiri Olsa dso->needs_swap = DSO_SWAP__UNSET; 344aeafcbafSArnaldo Carvalho de Melo INIT_LIST_HEAD(&dso->node); 34586470930SIngo Molnar } 34686470930SIngo Molnar 347aeafcbafSArnaldo Carvalho de Melo return dso; 34886470930SIngo Molnar } 34986470930SIngo Molnar 350aeafcbafSArnaldo Carvalho de Melo static void symbols__delete(struct rb_root *symbols) 35186470930SIngo Molnar { 35286470930SIngo Molnar struct symbol *pos; 353aeafcbafSArnaldo Carvalho de Melo struct rb_node *next = rb_first(symbols); 35486470930SIngo Molnar 35586470930SIngo Molnar while (next) { 35686470930SIngo Molnar pos = rb_entry(next, struct symbol, rb_node); 35786470930SIngo Molnar next = rb_next(&pos->rb_node); 358aeafcbafSArnaldo Carvalho de Melo rb_erase(&pos->rb_node, symbols); 35900a192b3SArnaldo Carvalho de Melo symbol__delete(pos); 36086470930SIngo Molnar } 36186470930SIngo Molnar } 36286470930SIngo Molnar 363aeafcbafSArnaldo Carvalho de Melo void dso__delete(struct dso *dso) 36486470930SIngo Molnar { 3656a4694a4SArnaldo Carvalho de Melo int i; 3666a4694a4SArnaldo Carvalho de Melo for (i = 0; i < MAP__NR_TYPES; ++i) 367aeafcbafSArnaldo Carvalho de Melo symbols__delete(&dso->symbols[i]); 368aeafcbafSArnaldo Carvalho de Melo if (dso->sname_alloc) 369aeafcbafSArnaldo Carvalho de Melo free((char *)dso->short_name); 370aeafcbafSArnaldo Carvalho de Melo if (dso->lname_alloc) 371aeafcbafSArnaldo Carvalho de Melo free(dso->long_name); 3724dff624aSJiri Olsa dso_cache__free(&dso->cache); 373aeafcbafSArnaldo Carvalho de Melo free(dso); 37486470930SIngo Molnar } 37586470930SIngo Molnar 376aeafcbafSArnaldo Carvalho de Melo void dso__set_build_id(struct dso *dso, void *build_id) 3778d06367fSArnaldo Carvalho de Melo { 378aeafcbafSArnaldo Carvalho de Melo memcpy(dso->build_id, build_id, sizeof(dso->build_id)); 379aeafcbafSArnaldo Carvalho de Melo dso->has_build_id = 1; 3808d06367fSArnaldo Carvalho de Melo } 3818d06367fSArnaldo Carvalho de Melo 382e5a1845fSNamhyung Kim void symbols__insert(struct rb_root *symbols, struct symbol *sym) 38386470930SIngo Molnar { 384aeafcbafSArnaldo Carvalho de Melo struct rb_node **p = &symbols->rb_node; 38586470930SIngo Molnar struct rb_node *parent = NULL; 3869cffa8d5SPaul Mackerras const u64 ip = sym->start; 38786470930SIngo Molnar struct symbol *s; 38886470930SIngo Molnar 38986470930SIngo Molnar while (*p != NULL) { 39086470930SIngo Molnar parent = *p; 39186470930SIngo Molnar s = rb_entry(parent, struct symbol, rb_node); 39286470930SIngo Molnar if (ip < s->start) 39386470930SIngo Molnar p = &(*p)->rb_left; 39486470930SIngo Molnar else 39586470930SIngo Molnar p = &(*p)->rb_right; 39686470930SIngo Molnar } 39786470930SIngo Molnar rb_link_node(&sym->rb_node, parent, p); 398aeafcbafSArnaldo Carvalho de Melo rb_insert_color(&sym->rb_node, symbols); 39986470930SIngo Molnar } 40086470930SIngo Molnar 401aeafcbafSArnaldo Carvalho de Melo static struct symbol *symbols__find(struct rb_root *symbols, u64 ip) 40286470930SIngo Molnar { 40386470930SIngo Molnar struct rb_node *n; 40486470930SIngo Molnar 405aeafcbafSArnaldo Carvalho de Melo if (symbols == NULL) 40686470930SIngo Molnar return NULL; 40786470930SIngo Molnar 408aeafcbafSArnaldo Carvalho de Melo n = symbols->rb_node; 40986470930SIngo Molnar 41086470930SIngo Molnar while (n) { 41186470930SIngo Molnar struct symbol *s = rb_entry(n, struct symbol, rb_node); 41286470930SIngo Molnar 41386470930SIngo Molnar if (ip < s->start) 41486470930SIngo Molnar n = n->rb_left; 41586470930SIngo Molnar else if (ip > s->end) 41686470930SIngo Molnar n = n->rb_right; 41786470930SIngo Molnar else 41886470930SIngo Molnar return s; 41986470930SIngo Molnar } 42086470930SIngo Molnar 42186470930SIngo Molnar return NULL; 42286470930SIngo Molnar } 42386470930SIngo Molnar 42479406cd7SArnaldo Carvalho de Melo struct symbol_name_rb_node { 42579406cd7SArnaldo Carvalho de Melo struct rb_node rb_node; 42679406cd7SArnaldo Carvalho de Melo struct symbol sym; 42779406cd7SArnaldo Carvalho de Melo }; 42879406cd7SArnaldo Carvalho de Melo 429aeafcbafSArnaldo Carvalho de Melo static void symbols__insert_by_name(struct rb_root *symbols, struct symbol *sym) 43079406cd7SArnaldo Carvalho de Melo { 431aeafcbafSArnaldo Carvalho de Melo struct rb_node **p = &symbols->rb_node; 43279406cd7SArnaldo Carvalho de Melo struct rb_node *parent = NULL; 43302a9d037SRabin Vincent struct symbol_name_rb_node *symn, *s; 43402a9d037SRabin Vincent 43502a9d037SRabin Vincent symn = container_of(sym, struct symbol_name_rb_node, sym); 43679406cd7SArnaldo Carvalho de Melo 43779406cd7SArnaldo Carvalho de Melo while (*p != NULL) { 43879406cd7SArnaldo Carvalho de Melo parent = *p; 43979406cd7SArnaldo Carvalho de Melo s = rb_entry(parent, struct symbol_name_rb_node, rb_node); 44079406cd7SArnaldo Carvalho de Melo if (strcmp(sym->name, s->sym.name) < 0) 44179406cd7SArnaldo Carvalho de Melo p = &(*p)->rb_left; 44279406cd7SArnaldo Carvalho de Melo else 44379406cd7SArnaldo Carvalho de Melo p = &(*p)->rb_right; 44479406cd7SArnaldo Carvalho de Melo } 44579406cd7SArnaldo Carvalho de Melo rb_link_node(&symn->rb_node, parent, p); 446aeafcbafSArnaldo Carvalho de Melo rb_insert_color(&symn->rb_node, symbols); 44779406cd7SArnaldo Carvalho de Melo } 44879406cd7SArnaldo Carvalho de Melo 449aeafcbafSArnaldo Carvalho de Melo static void symbols__sort_by_name(struct rb_root *symbols, 450aeafcbafSArnaldo Carvalho de Melo struct rb_root *source) 45179406cd7SArnaldo Carvalho de Melo { 45279406cd7SArnaldo Carvalho de Melo struct rb_node *nd; 45379406cd7SArnaldo Carvalho de Melo 45479406cd7SArnaldo Carvalho de Melo for (nd = rb_first(source); nd; nd = rb_next(nd)) { 45579406cd7SArnaldo Carvalho de Melo struct symbol *pos = rb_entry(nd, struct symbol, rb_node); 456aeafcbafSArnaldo Carvalho de Melo symbols__insert_by_name(symbols, pos); 45779406cd7SArnaldo Carvalho de Melo } 45879406cd7SArnaldo Carvalho de Melo } 45979406cd7SArnaldo Carvalho de Melo 460aeafcbafSArnaldo Carvalho de Melo static struct symbol *symbols__find_by_name(struct rb_root *symbols, 461aeafcbafSArnaldo Carvalho de Melo const char *name) 46279406cd7SArnaldo Carvalho de Melo { 46379406cd7SArnaldo Carvalho de Melo struct rb_node *n; 46479406cd7SArnaldo Carvalho de Melo 465aeafcbafSArnaldo Carvalho de Melo if (symbols == NULL) 46679406cd7SArnaldo Carvalho de Melo return NULL; 46779406cd7SArnaldo Carvalho de Melo 468aeafcbafSArnaldo Carvalho de Melo n = symbols->rb_node; 46979406cd7SArnaldo Carvalho de Melo 47079406cd7SArnaldo Carvalho de Melo while (n) { 47179406cd7SArnaldo Carvalho de Melo struct symbol_name_rb_node *s; 47279406cd7SArnaldo Carvalho de Melo int cmp; 47379406cd7SArnaldo Carvalho de Melo 47479406cd7SArnaldo Carvalho de Melo s = rb_entry(n, struct symbol_name_rb_node, rb_node); 47579406cd7SArnaldo Carvalho de Melo cmp = strcmp(name, s->sym.name); 47679406cd7SArnaldo Carvalho de Melo 47779406cd7SArnaldo Carvalho de Melo if (cmp < 0) 47879406cd7SArnaldo Carvalho de Melo n = n->rb_left; 47979406cd7SArnaldo Carvalho de Melo else if (cmp > 0) 48079406cd7SArnaldo Carvalho de Melo n = n->rb_right; 48179406cd7SArnaldo Carvalho de Melo else 48279406cd7SArnaldo Carvalho de Melo return &s->sym; 48379406cd7SArnaldo Carvalho de Melo } 48479406cd7SArnaldo Carvalho de Melo 48579406cd7SArnaldo Carvalho de Melo return NULL; 48679406cd7SArnaldo Carvalho de Melo } 48779406cd7SArnaldo Carvalho de Melo 488aeafcbafSArnaldo Carvalho de Melo struct symbol *dso__find_symbol(struct dso *dso, 48979406cd7SArnaldo Carvalho de Melo enum map_type type, u64 addr) 490fcf1203aSArnaldo Carvalho de Melo { 491aeafcbafSArnaldo Carvalho de Melo return symbols__find(&dso->symbols[type], addr); 492fcf1203aSArnaldo Carvalho de Melo } 493fcf1203aSArnaldo Carvalho de Melo 494aeafcbafSArnaldo Carvalho de Melo struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type, 49579406cd7SArnaldo Carvalho de Melo const char *name) 49679406cd7SArnaldo Carvalho de Melo { 497aeafcbafSArnaldo Carvalho de Melo return symbols__find_by_name(&dso->symbol_names[type], name); 49879406cd7SArnaldo Carvalho de Melo } 49979406cd7SArnaldo Carvalho de Melo 500aeafcbafSArnaldo Carvalho de Melo void dso__sort_by_name(struct dso *dso, enum map_type type) 50179406cd7SArnaldo Carvalho de Melo { 502aeafcbafSArnaldo Carvalho de Melo dso__set_sorted_by_name(dso, type); 503aeafcbafSArnaldo Carvalho de Melo return symbols__sort_by_name(&dso->symbol_names[type], 504aeafcbafSArnaldo Carvalho de Melo &dso->symbols[type]); 50579406cd7SArnaldo Carvalho de Melo } 50679406cd7SArnaldo Carvalho de Melo 507aeafcbafSArnaldo Carvalho de Melo int build_id__sprintf(const u8 *build_id, int len, char *bf) 5088d06367fSArnaldo Carvalho de Melo { 5098d06367fSArnaldo Carvalho de Melo char *bid = bf; 510aeafcbafSArnaldo Carvalho de Melo const u8 *raw = build_id; 5118d06367fSArnaldo Carvalho de Melo int i; 5128d06367fSArnaldo Carvalho de Melo 5138d06367fSArnaldo Carvalho de Melo for (i = 0; i < len; ++i) { 5148d06367fSArnaldo Carvalho de Melo sprintf(bid, "%02x", *raw); 5158d06367fSArnaldo Carvalho de Melo ++raw; 5168d06367fSArnaldo Carvalho de Melo bid += 2; 5178d06367fSArnaldo Carvalho de Melo } 5188d06367fSArnaldo Carvalho de Melo 519aeafcbafSArnaldo Carvalho de Melo return raw - build_id; 5208d06367fSArnaldo Carvalho de Melo } 5218d06367fSArnaldo Carvalho de Melo 522aeafcbafSArnaldo Carvalho de Melo size_t dso__fprintf_buildid(struct dso *dso, FILE *fp) 52386470930SIngo Molnar { 5248d06367fSArnaldo Carvalho de Melo char sbuild_id[BUILD_ID_SIZE * 2 + 1]; 5258d06367fSArnaldo Carvalho de Melo 526aeafcbafSArnaldo Carvalho de Melo build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id); 5279e03eb2dSArnaldo Carvalho de Melo return fprintf(fp, "%s", sbuild_id); 5289e03eb2dSArnaldo Carvalho de Melo } 5299e03eb2dSArnaldo Carvalho de Melo 530aeafcbafSArnaldo Carvalho de Melo size_t dso__fprintf_symbols_by_name(struct dso *dso, 531aeafcbafSArnaldo Carvalho de Melo enum map_type type, FILE *fp) 53290f18e63SSrikar Dronamraju { 53390f18e63SSrikar Dronamraju size_t ret = 0; 53490f18e63SSrikar Dronamraju struct rb_node *nd; 53590f18e63SSrikar Dronamraju struct symbol_name_rb_node *pos; 53690f18e63SSrikar Dronamraju 537aeafcbafSArnaldo Carvalho de Melo for (nd = rb_first(&dso->symbol_names[type]); nd; nd = rb_next(nd)) { 53890f18e63SSrikar Dronamraju pos = rb_entry(nd, struct symbol_name_rb_node, rb_node); 53990f18e63SSrikar Dronamraju fprintf(fp, "%s\n", pos->sym.name); 54090f18e63SSrikar Dronamraju } 54190f18e63SSrikar Dronamraju 54290f18e63SSrikar Dronamraju return ret; 54390f18e63SSrikar Dronamraju } 54490f18e63SSrikar Dronamraju 545aeafcbafSArnaldo Carvalho de Melo size_t dso__fprintf(struct dso *dso, enum map_type type, FILE *fp) 5469e03eb2dSArnaldo Carvalho de Melo { 5479e03eb2dSArnaldo Carvalho de Melo struct rb_node *nd; 548aeafcbafSArnaldo Carvalho de Melo size_t ret = fprintf(fp, "dso: %s (", dso->short_name); 5499e03eb2dSArnaldo Carvalho de Melo 550aeafcbafSArnaldo Carvalho de Melo if (dso->short_name != dso->long_name) 551aeafcbafSArnaldo Carvalho de Melo ret += fprintf(fp, "%s, ", dso->long_name); 5523846df2eSArnaldo Carvalho de Melo ret += fprintf(fp, "%s, %sloaded, ", map_type__name[type], 553aeafcbafSArnaldo Carvalho de Melo dso->loaded ? "" : "NOT "); 554aeafcbafSArnaldo Carvalho de Melo ret += dso__fprintf_buildid(dso, fp); 5556a4694a4SArnaldo Carvalho de Melo ret += fprintf(fp, ")\n"); 556aeafcbafSArnaldo Carvalho de Melo for (nd = rb_first(&dso->symbols[type]); nd; nd = rb_next(nd)) { 55786470930SIngo Molnar struct symbol *pos = rb_entry(nd, struct symbol, rb_node); 55886470930SIngo Molnar ret += symbol__fprintf(pos, fp); 55986470930SIngo Molnar } 56086470930SIngo Molnar 56186470930SIngo Molnar return ret; 56286470930SIngo Molnar } 56386470930SIngo Molnar 5649e201442SArnaldo Carvalho de Melo int kallsyms__parse(const char *filename, void *arg, 5659e201442SArnaldo Carvalho de Melo int (*process_symbol)(void *arg, const char *name, 56682151520SCody P Schafer char type, u64 start)) 56786470930SIngo Molnar { 56886470930SIngo Molnar char *line = NULL; 56986470930SIngo Molnar size_t n; 5703b01a413SArnaldo Carvalho de Melo int err = -1; 5719e201442SArnaldo Carvalho de Melo FILE *file = fopen(filename, "r"); 57286470930SIngo Molnar 57386470930SIngo Molnar if (file == NULL) 57486470930SIngo Molnar goto out_failure; 57586470930SIngo Molnar 5763b01a413SArnaldo Carvalho de Melo err = 0; 5773b01a413SArnaldo Carvalho de Melo 57886470930SIngo Molnar while (!feof(file)) { 5799cffa8d5SPaul Mackerras u64 start; 58086470930SIngo Molnar int line_len, len; 58186470930SIngo Molnar char symbol_type; 5822e538c4aSArnaldo Carvalho de Melo char *symbol_name; 58386470930SIngo Molnar 58486470930SIngo Molnar line_len = getline(&line, &n, file); 585a1645ce1SZhang, Yanmin if (line_len < 0 || !line) 58686470930SIngo Molnar break; 58786470930SIngo Molnar 58886470930SIngo Molnar line[--line_len] = '\0'; /* \n */ 58986470930SIngo Molnar 59086470930SIngo Molnar len = hex2u64(line, &start); 59186470930SIngo Molnar 59286470930SIngo Molnar len++; 59386470930SIngo Molnar if (len + 2 >= line_len) 59486470930SIngo Molnar continue; 59586470930SIngo Molnar 59631877908SAnton Blanchard symbol_type = line[len]; 5973b01a413SArnaldo Carvalho de Melo len += 2; 5983b01a413SArnaldo Carvalho de Melo symbol_name = line + len; 5993b01a413SArnaldo Carvalho de Melo len = line_len - len; 600682b335aSArnaldo Carvalho de Melo 6013b01a413SArnaldo Carvalho de Melo if (len >= KSYM_NAME_LEN) { 6023b01a413SArnaldo Carvalho de Melo err = -1; 6033b01a413SArnaldo Carvalho de Melo break; 6043b01a413SArnaldo Carvalho de Melo } 6053b01a413SArnaldo Carvalho de Melo 6063f5a4272SAnton Blanchard err = process_symbol(arg, symbol_name, 60782151520SCody P Schafer symbol_type, start); 608682b335aSArnaldo Carvalho de Melo if (err) 609682b335aSArnaldo Carvalho de Melo break; 610682b335aSArnaldo Carvalho de Melo } 611682b335aSArnaldo Carvalho de Melo 612682b335aSArnaldo Carvalho de Melo free(line); 613682b335aSArnaldo Carvalho de Melo fclose(file); 614682b335aSArnaldo Carvalho de Melo return err; 615682b335aSArnaldo Carvalho de Melo 616682b335aSArnaldo Carvalho de Melo out_failure: 617682b335aSArnaldo Carvalho de Melo return -1; 618682b335aSArnaldo Carvalho de Melo } 619682b335aSArnaldo Carvalho de Melo 620682b335aSArnaldo Carvalho de Melo struct process_kallsyms_args { 621682b335aSArnaldo Carvalho de Melo struct map *map; 622682b335aSArnaldo Carvalho de Melo struct dso *dso; 623682b335aSArnaldo Carvalho de Melo }; 624682b335aSArnaldo Carvalho de Melo 625c408fedfSArnaldo Carvalho de Melo static u8 kallsyms2elf_type(char type) 626c408fedfSArnaldo Carvalho de Melo { 627c408fedfSArnaldo Carvalho de Melo if (type == 'W') 628c408fedfSArnaldo Carvalho de Melo return STB_WEAK; 629c408fedfSArnaldo Carvalho de Melo 630c408fedfSArnaldo Carvalho de Melo return isupper(type) ? STB_GLOBAL : STB_LOCAL; 631c408fedfSArnaldo Carvalho de Melo } 632c408fedfSArnaldo Carvalho de Melo 633682b335aSArnaldo Carvalho de Melo static int map__process_kallsym_symbol(void *arg, const char *name, 63482151520SCody P Schafer char type, u64 start) 635682b335aSArnaldo Carvalho de Melo { 636682b335aSArnaldo Carvalho de Melo struct symbol *sym; 637682b335aSArnaldo Carvalho de Melo struct process_kallsyms_args *a = arg; 638682b335aSArnaldo Carvalho de Melo struct rb_root *root = &a->dso->symbols[a->map->type]; 639682b335aSArnaldo Carvalho de Melo 640682b335aSArnaldo Carvalho de Melo if (!symbol_type__is_a(type, a->map->type)) 641682b335aSArnaldo Carvalho de Melo return 0; 642682b335aSArnaldo Carvalho de Melo 64382151520SCody P Schafer /* 64482151520SCody P Schafer * module symbols are not sorted so we add all 64582151520SCody P Schafer * symbols, setting length to 0, and rely on 64682151520SCody P Schafer * symbols__fixup_end() to fix it up. 64782151520SCody P Schafer */ 64882151520SCody P Schafer sym = symbol__new(start, 0, kallsyms2elf_type(type), name); 6492e538c4aSArnaldo Carvalho de Melo if (sym == NULL) 650682b335aSArnaldo Carvalho de Melo return -ENOMEM; 65182164161SArnaldo Carvalho de Melo /* 65282164161SArnaldo Carvalho de Melo * We will pass the symbols to the filter later, in 6534e06255fSArnaldo Carvalho de Melo * map__split_kallsyms, when we have split the maps per module 65482164161SArnaldo Carvalho de Melo */ 6554e06255fSArnaldo Carvalho de Melo symbols__insert(root, sym); 656a1645ce1SZhang, Yanmin 657682b335aSArnaldo Carvalho de Melo return 0; 6582e538c4aSArnaldo Carvalho de Melo } 6592e538c4aSArnaldo Carvalho de Melo 660682b335aSArnaldo Carvalho de Melo /* 661682b335aSArnaldo Carvalho de Melo * Loads the function entries in /proc/kallsyms into kernel_map->dso, 662682b335aSArnaldo Carvalho de Melo * so that we can in the next step set the symbol ->end address and then 663682b335aSArnaldo Carvalho de Melo * call kernel_maps__split_kallsyms. 664682b335aSArnaldo Carvalho de Melo */ 665aeafcbafSArnaldo Carvalho de Melo static int dso__load_all_kallsyms(struct dso *dso, const char *filename, 6669e201442SArnaldo Carvalho de Melo struct map *map) 667682b335aSArnaldo Carvalho de Melo { 668aeafcbafSArnaldo Carvalho de Melo struct process_kallsyms_args args = { .map = map, .dso = dso, }; 6699e201442SArnaldo Carvalho de Melo return kallsyms__parse(filename, &args, map__process_kallsym_symbol); 6702e538c4aSArnaldo Carvalho de Melo } 6712e538c4aSArnaldo Carvalho de Melo 6722e538c4aSArnaldo Carvalho de Melo /* 6732e538c4aSArnaldo Carvalho de Melo * Split the symbols into maps, making sure there are no overlaps, i.e. the 6742e538c4aSArnaldo Carvalho de Melo * kernel range is broken in several maps, named [kernel].N, as we don't have 6752e538c4aSArnaldo Carvalho de Melo * the original ELF section names vmlinux have. 6762e538c4aSArnaldo Carvalho de Melo */ 677aeafcbafSArnaldo Carvalho de Melo static int dso__split_kallsyms(struct dso *dso, struct map *map, 6789de89fe7SArnaldo Carvalho de Melo symbol_filter_t filter) 6792e538c4aSArnaldo Carvalho de Melo { 6809de89fe7SArnaldo Carvalho de Melo struct map_groups *kmaps = map__kmap(map)->kmaps; 68123346f21SArnaldo Carvalho de Melo struct machine *machine = kmaps->machine; 6824e06255fSArnaldo Carvalho de Melo struct map *curr_map = map; 6832e538c4aSArnaldo Carvalho de Melo struct symbol *pos; 6848a953312SArnaldo Carvalho de Melo int count = 0, moved = 0; 685aeafcbafSArnaldo Carvalho de Melo struct rb_root *root = &dso->symbols[map->type]; 6864e06255fSArnaldo Carvalho de Melo struct rb_node *next = rb_first(root); 6872e538c4aSArnaldo Carvalho de Melo int kernel_range = 0; 6882e538c4aSArnaldo Carvalho de Melo 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 7428a953312SArnaldo Carvalho de Melo if (count == 0) { 7438a953312SArnaldo Carvalho de Melo curr_map = map; 7448a953312SArnaldo Carvalho de Melo goto filter_symbol; 7458a953312SArnaldo Carvalho de Melo } 7468a953312SArnaldo Carvalho de Melo 747aeafcbafSArnaldo Carvalho de Melo if (dso->kernel == DSO_TYPE_GUEST_KERNEL) 748a1645ce1SZhang, Yanmin snprintf(dso_name, sizeof(dso_name), 749a1645ce1SZhang, Yanmin "[guest.kernel].%d", 750a1645ce1SZhang, Yanmin kernel_range++); 751a1645ce1SZhang, Yanmin else 752a1645ce1SZhang, Yanmin snprintf(dso_name, sizeof(dso_name), 753a1645ce1SZhang, Yanmin "[kernel].%d", 7542e538c4aSArnaldo Carvalho de Melo kernel_range++); 75586470930SIngo Molnar 756aeafcbafSArnaldo Carvalho de Melo ndso = dso__new(dso_name); 757aeafcbafSArnaldo Carvalho de Melo if (ndso == NULL) 7582e538c4aSArnaldo Carvalho de Melo return -1; 7592e538c4aSArnaldo Carvalho de Melo 760aeafcbafSArnaldo Carvalho de Melo ndso->kernel = dso->kernel; 761a1645ce1SZhang, Yanmin 762aeafcbafSArnaldo Carvalho de Melo curr_map = map__new2(pos->start, ndso, map->type); 76337fe5fcbSZhang, Yanmin if (curr_map == NULL) { 764aeafcbafSArnaldo Carvalho de Melo dso__delete(ndso); 7652e538c4aSArnaldo Carvalho de Melo return -1; 7662e538c4aSArnaldo Carvalho de Melo } 7672e538c4aSArnaldo Carvalho de Melo 7684e06255fSArnaldo Carvalho de Melo curr_map->map_ip = curr_map->unmap_ip = identity__map_ip; 7699de89fe7SArnaldo Carvalho de Melo map_groups__insert(kmaps, curr_map); 7702e538c4aSArnaldo Carvalho de Melo ++kernel_range; 7712e538c4aSArnaldo Carvalho de Melo } 7728a953312SArnaldo Carvalho de Melo filter_symbol: 7734e06255fSArnaldo Carvalho de Melo if (filter && filter(curr_map, pos)) { 7741de8e245SArnaldo Carvalho de Melo discard_symbol: rb_erase(&pos->rb_node, root); 77500a192b3SArnaldo Carvalho de Melo symbol__delete(pos); 7762e538c4aSArnaldo Carvalho de Melo } else { 7774e06255fSArnaldo Carvalho de Melo if (curr_map != map) { 7784e06255fSArnaldo Carvalho de Melo rb_erase(&pos->rb_node, root); 7794e06255fSArnaldo Carvalho de Melo symbols__insert(&curr_map->dso->symbols[curr_map->type], pos); 7808a953312SArnaldo Carvalho de Melo ++moved; 7818a953312SArnaldo Carvalho de Melo } else 7828a953312SArnaldo Carvalho de Melo ++count; 7839974f496SMike Galbraith } 78486470930SIngo Molnar } 78586470930SIngo Molnar 786a1645ce1SZhang, Yanmin if (curr_map != map && 787aeafcbafSArnaldo Carvalho de Melo dso->kernel == DSO_TYPE_GUEST_KERNEL && 78823346f21SArnaldo Carvalho de Melo machine__is_default_guest(kmaps->machine)) { 789a1645ce1SZhang, Yanmin dso__set_loaded(curr_map->dso, curr_map->type); 790a1645ce1SZhang, Yanmin } 791a1645ce1SZhang, Yanmin 7928a953312SArnaldo Carvalho de Melo return count + moved; 79386470930SIngo Molnar } 79486470930SIngo Molnar 795ec80fde7SArnaldo Carvalho de Melo static bool symbol__restricted_filename(const char *filename, 796ec80fde7SArnaldo Carvalho de Melo const char *restricted_filename) 797ec80fde7SArnaldo Carvalho de Melo { 798ec80fde7SArnaldo Carvalho de Melo bool restricted = false; 799ec80fde7SArnaldo Carvalho de Melo 800ec80fde7SArnaldo Carvalho de Melo if (symbol_conf.kptr_restrict) { 801ec80fde7SArnaldo Carvalho de Melo char *r = realpath(filename, NULL); 802ec80fde7SArnaldo Carvalho de Melo 803ec80fde7SArnaldo Carvalho de Melo if (r != NULL) { 804ec80fde7SArnaldo Carvalho de Melo restricted = strcmp(r, restricted_filename) == 0; 805ec80fde7SArnaldo Carvalho de Melo free(r); 806ec80fde7SArnaldo Carvalho de Melo return restricted; 807ec80fde7SArnaldo Carvalho de Melo } 808ec80fde7SArnaldo Carvalho de Melo } 809ec80fde7SArnaldo Carvalho de Melo 810ec80fde7SArnaldo Carvalho de Melo return restricted; 811ec80fde7SArnaldo Carvalho de Melo } 812ec80fde7SArnaldo Carvalho de Melo 813aeafcbafSArnaldo Carvalho de Melo int dso__load_kallsyms(struct dso *dso, const char *filename, 8149de89fe7SArnaldo Carvalho de Melo struct map *map, symbol_filter_t filter) 8152e538c4aSArnaldo Carvalho de Melo { 816ec80fde7SArnaldo Carvalho de Melo if (symbol__restricted_filename(filename, "/proc/kallsyms")) 817ec80fde7SArnaldo Carvalho de Melo return -1; 818ec80fde7SArnaldo Carvalho de Melo 819aeafcbafSArnaldo Carvalho de Melo if (dso__load_all_kallsyms(dso, filename, map) < 0) 8202e538c4aSArnaldo Carvalho de Melo return -1; 8212e538c4aSArnaldo Carvalho de Melo 822694bf407SAnton Blanchard symbols__fixup_duplicate(&dso->symbols[map->type]); 8233f5a4272SAnton Blanchard symbols__fixup_end(&dso->symbols[map->type]); 8243f5a4272SAnton Blanchard 825aeafcbafSArnaldo Carvalho de Melo if (dso->kernel == DSO_TYPE_GUEST_KERNEL) 82644f24cb3SJiri Olsa dso->symtab_type = DSO_BINARY_TYPE__GUEST_KALLSYMS; 827a1645ce1SZhang, Yanmin else 82844f24cb3SJiri Olsa dso->symtab_type = DSO_BINARY_TYPE__KALLSYMS; 8292e538c4aSArnaldo Carvalho de Melo 830aeafcbafSArnaldo Carvalho de Melo return dso__split_kallsyms(dso, map, filter); 831af427bf5SArnaldo Carvalho de Melo } 832af427bf5SArnaldo Carvalho de Melo 833aeafcbafSArnaldo Carvalho de Melo static int dso__load_perf_map(struct dso *dso, struct map *map, 8346beba7adSArnaldo Carvalho de Melo symbol_filter_t filter) 83580d496beSPekka Enberg { 83680d496beSPekka Enberg char *line = NULL; 83780d496beSPekka Enberg size_t n; 83880d496beSPekka Enberg FILE *file; 83980d496beSPekka Enberg int nr_syms = 0; 84080d496beSPekka Enberg 841aeafcbafSArnaldo Carvalho de Melo file = fopen(dso->long_name, "r"); 84280d496beSPekka Enberg if (file == NULL) 84380d496beSPekka Enberg goto out_failure; 84480d496beSPekka Enberg 84580d496beSPekka Enberg while (!feof(file)) { 8469cffa8d5SPaul Mackerras u64 start, size; 84780d496beSPekka Enberg struct symbol *sym; 84880d496beSPekka Enberg int line_len, len; 84980d496beSPekka Enberg 85080d496beSPekka Enberg line_len = getline(&line, &n, file); 85180d496beSPekka Enberg if (line_len < 0) 85280d496beSPekka Enberg break; 85380d496beSPekka Enberg 85480d496beSPekka Enberg if (!line) 85580d496beSPekka Enberg goto out_failure; 85680d496beSPekka Enberg 85780d496beSPekka Enberg line[--line_len] = '\0'; /* \n */ 85880d496beSPekka Enberg 85980d496beSPekka Enberg len = hex2u64(line, &start); 86080d496beSPekka Enberg 86180d496beSPekka Enberg len++; 86280d496beSPekka Enberg if (len + 2 >= line_len) 86380d496beSPekka Enberg continue; 86480d496beSPekka Enberg 86580d496beSPekka Enberg len += hex2u64(line + len, &size); 86680d496beSPekka Enberg 86780d496beSPekka Enberg len++; 86880d496beSPekka Enberg if (len + 2 >= line_len) 86980d496beSPekka Enberg continue; 87080d496beSPekka Enberg 871c408fedfSArnaldo Carvalho de Melo sym = symbol__new(start, size, STB_GLOBAL, line + len); 87280d496beSPekka Enberg 87380d496beSPekka Enberg if (sym == NULL) 87480d496beSPekka Enberg goto out_delete_line; 87580d496beSPekka Enberg 876439d473bSArnaldo Carvalho de Melo if (filter && filter(map, sym)) 87700a192b3SArnaldo Carvalho de Melo symbol__delete(sym); 87880d496beSPekka Enberg else { 879aeafcbafSArnaldo Carvalho de Melo symbols__insert(&dso->symbols[map->type], sym); 88080d496beSPekka Enberg nr_syms++; 88180d496beSPekka Enberg } 88280d496beSPekka Enberg } 88380d496beSPekka Enberg 88480d496beSPekka Enberg free(line); 88580d496beSPekka Enberg fclose(file); 88680d496beSPekka Enberg 88780d496beSPekka Enberg return nr_syms; 88880d496beSPekka Enberg 88980d496beSPekka Enberg out_delete_line: 89080d496beSPekka Enberg free(line); 89180d496beSPekka Enberg out_failure: 89280d496beSPekka Enberg return -1; 89380d496beSPekka Enberg } 89480d496beSPekka Enberg 895e5a1845fSNamhyung Kim bool dso__build_id_equal(const struct dso *dso, u8 *build_id) 89678075caaSArnaldo Carvalho de Melo { 897aeafcbafSArnaldo Carvalho de Melo return memcmp(dso->build_id, build_id, sizeof(dso->build_id)) == 0; 89878075caaSArnaldo Carvalho de Melo } 89978075caaSArnaldo Carvalho de Melo 900a1645ce1SZhang, Yanmin bool __dsos__read_build_ids(struct list_head *head, bool with_hits) 90157f395a7SFrederic Weisbecker { 902e30a3d12SArnaldo Carvalho de Melo bool have_build_id = false; 90357f395a7SFrederic Weisbecker struct dso *pos; 90457f395a7SFrederic Weisbecker 9056122e4e4SArnaldo Carvalho de Melo list_for_each_entry(pos, head, node) { 9066122e4e4SArnaldo Carvalho de Melo if (with_hits && !pos->hit) 9076122e4e4SArnaldo Carvalho de Melo continue; 908f6e1467dSArnaldo Carvalho de Melo if (pos->has_build_id) { 909f6e1467dSArnaldo Carvalho de Melo have_build_id = true; 910f6e1467dSArnaldo Carvalho de Melo continue; 911f6e1467dSArnaldo Carvalho de Melo } 912e30a3d12SArnaldo Carvalho de Melo if (filename__read_build_id(pos->long_name, pos->build_id, 913e30a3d12SArnaldo Carvalho de Melo sizeof(pos->build_id)) > 0) { 914e30a3d12SArnaldo Carvalho de Melo have_build_id = true; 915e30a3d12SArnaldo Carvalho de Melo pos->has_build_id = true; 91657f395a7SFrederic Weisbecker } 9176122e4e4SArnaldo Carvalho de Melo } 91857f395a7SFrederic Weisbecker 919e30a3d12SArnaldo Carvalho de Melo return have_build_id; 92057f395a7SFrederic Weisbecker } 92157f395a7SFrederic Weisbecker 922aeafcbafSArnaldo Carvalho de Melo char dso__symtab_origin(const struct dso *dso) 92394cb9e38SArnaldo Carvalho de Melo { 92494cb9e38SArnaldo Carvalho de Melo static const char origin[] = { 92544f24cb3SJiri Olsa [DSO_BINARY_TYPE__KALLSYMS] = 'k', 92621ea4539SCody P Schafer [DSO_BINARY_TYPE__VMLINUX] = 'v', 92744f24cb3SJiri Olsa [DSO_BINARY_TYPE__JAVA_JIT] = 'j', 92844f24cb3SJiri Olsa [DSO_BINARY_TYPE__DEBUGLINK] = 'l', 92944f24cb3SJiri Olsa [DSO_BINARY_TYPE__BUILD_ID_CACHE] = 'B', 93044f24cb3SJiri Olsa [DSO_BINARY_TYPE__FEDORA_DEBUGINFO] = 'f', 93144f24cb3SJiri Olsa [DSO_BINARY_TYPE__UBUNTU_DEBUGINFO] = 'u', 93244f24cb3SJiri Olsa [DSO_BINARY_TYPE__BUILDID_DEBUGINFO] = 'b', 93344f24cb3SJiri Olsa [DSO_BINARY_TYPE__SYSTEM_PATH_DSO] = 'd', 93444f24cb3SJiri Olsa [DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE] = 'K', 93544f24cb3SJiri Olsa [DSO_BINARY_TYPE__GUEST_KALLSYMS] = 'g', 93644f24cb3SJiri Olsa [DSO_BINARY_TYPE__GUEST_KMODULE] = 'G', 93721ea4539SCody P Schafer [DSO_BINARY_TYPE__GUEST_VMLINUX] = 'V', 93894cb9e38SArnaldo Carvalho de Melo }; 93994cb9e38SArnaldo Carvalho de Melo 94044f24cb3SJiri Olsa if (dso == NULL || dso->symtab_type == DSO_BINARY_TYPE__NOT_FOUND) 94194cb9e38SArnaldo Carvalho de Melo return '!'; 942aeafcbafSArnaldo Carvalho de Melo return origin[dso->symtab_type]; 94394cb9e38SArnaldo Carvalho de Melo } 94494cb9e38SArnaldo Carvalho de Melo 94544f24cb3SJiri Olsa int dso__binary_type_file(struct dso *dso, enum dso_binary_type type, 94644f24cb3SJiri Olsa char *root_dir, char *file, size_t size) 94744f24cb3SJiri Olsa { 94844f24cb3SJiri Olsa char build_id_hex[BUILD_ID_SIZE * 2 + 1]; 94944f24cb3SJiri Olsa int ret = 0; 95044f24cb3SJiri Olsa 95144f24cb3SJiri Olsa switch (type) { 95244f24cb3SJiri Olsa case DSO_BINARY_TYPE__DEBUGLINK: { 95344f24cb3SJiri Olsa char *debuglink; 95444f24cb3SJiri Olsa 95544f24cb3SJiri Olsa strncpy(file, dso->long_name, size); 95644f24cb3SJiri Olsa debuglink = file + dso->long_name_len; 95744f24cb3SJiri Olsa while (debuglink != file && *debuglink != '/') 95844f24cb3SJiri Olsa debuglink--; 95944f24cb3SJiri Olsa if (*debuglink == '/') 96044f24cb3SJiri Olsa debuglink++; 96144f24cb3SJiri Olsa filename__read_debuglink(dso->long_name, debuglink, 96244f24cb3SJiri Olsa size - (debuglink - file)); 96344f24cb3SJiri Olsa } 96444f24cb3SJiri Olsa break; 96544f24cb3SJiri Olsa case DSO_BINARY_TYPE__BUILD_ID_CACHE: 96644f24cb3SJiri Olsa /* skip the locally configured cache if a symfs is given */ 96744f24cb3SJiri Olsa if (symbol_conf.symfs[0] || 96844f24cb3SJiri Olsa (dso__build_id_filename(dso, file, size) == NULL)) 96944f24cb3SJiri Olsa ret = -1; 97044f24cb3SJiri Olsa break; 97144f24cb3SJiri Olsa 97244f24cb3SJiri Olsa case DSO_BINARY_TYPE__FEDORA_DEBUGINFO: 97344f24cb3SJiri Olsa snprintf(file, size, "%s/usr/lib/debug%s.debug", 97444f24cb3SJiri Olsa symbol_conf.symfs, dso->long_name); 97544f24cb3SJiri Olsa break; 97644f24cb3SJiri Olsa 97744f24cb3SJiri Olsa case DSO_BINARY_TYPE__UBUNTU_DEBUGINFO: 97844f24cb3SJiri Olsa snprintf(file, size, "%s/usr/lib/debug%s", 97944f24cb3SJiri Olsa symbol_conf.symfs, dso->long_name); 98044f24cb3SJiri Olsa break; 98144f24cb3SJiri Olsa 98244f24cb3SJiri Olsa case DSO_BINARY_TYPE__BUILDID_DEBUGINFO: 98344f24cb3SJiri Olsa if (!dso->has_build_id) { 98444f24cb3SJiri Olsa ret = -1; 98544f24cb3SJiri Olsa break; 98644f24cb3SJiri Olsa } 98744f24cb3SJiri Olsa 98844f24cb3SJiri Olsa build_id__sprintf(dso->build_id, 98944f24cb3SJiri Olsa sizeof(dso->build_id), 99044f24cb3SJiri Olsa build_id_hex); 99144f24cb3SJiri Olsa snprintf(file, size, 99244f24cb3SJiri Olsa "%s/usr/lib/debug/.build-id/%.2s/%s.debug", 99344f24cb3SJiri Olsa symbol_conf.symfs, build_id_hex, build_id_hex + 2); 99444f24cb3SJiri Olsa break; 99544f24cb3SJiri Olsa 99644f24cb3SJiri Olsa case DSO_BINARY_TYPE__SYSTEM_PATH_DSO: 99744f24cb3SJiri Olsa snprintf(file, size, "%s%s", 99844f24cb3SJiri Olsa symbol_conf.symfs, dso->long_name); 99944f24cb3SJiri Olsa break; 100044f24cb3SJiri Olsa 100144f24cb3SJiri Olsa case DSO_BINARY_TYPE__GUEST_KMODULE: 100244f24cb3SJiri Olsa snprintf(file, size, "%s%s%s", symbol_conf.symfs, 100344f24cb3SJiri Olsa root_dir, dso->long_name); 100444f24cb3SJiri Olsa break; 100544f24cb3SJiri Olsa 100644f24cb3SJiri Olsa case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE: 100744f24cb3SJiri Olsa snprintf(file, size, "%s%s", symbol_conf.symfs, 100844f24cb3SJiri Olsa dso->long_name); 100944f24cb3SJiri Olsa break; 101044f24cb3SJiri Olsa 101144f24cb3SJiri Olsa default: 101244f24cb3SJiri Olsa case DSO_BINARY_TYPE__KALLSYMS: 101321ea4539SCody P Schafer case DSO_BINARY_TYPE__VMLINUX: 101444f24cb3SJiri Olsa case DSO_BINARY_TYPE__GUEST_KALLSYMS: 101521ea4539SCody P Schafer case DSO_BINARY_TYPE__GUEST_VMLINUX: 101644f24cb3SJiri Olsa case DSO_BINARY_TYPE__JAVA_JIT: 101744f24cb3SJiri Olsa case DSO_BINARY_TYPE__NOT_FOUND: 101844f24cb3SJiri Olsa ret = -1; 101944f24cb3SJiri Olsa break; 102044f24cb3SJiri Olsa } 102144f24cb3SJiri Olsa 102244f24cb3SJiri Olsa return ret; 102344f24cb3SJiri Olsa } 102444f24cb3SJiri Olsa 1025aeafcbafSArnaldo Carvalho de Melo int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter) 102686470930SIngo Molnar { 1027c338aee8SArnaldo Carvalho de Melo char *name; 102886470930SIngo Molnar int ret = -1; 102944f24cb3SJiri Olsa u_int i; 103023346f21SArnaldo Carvalho de Melo struct machine *machine; 103144f24cb3SJiri Olsa char *root_dir = (char *) ""; 10323aafe5aeSCody P Schafer int ss_pos = 0; 10333aafe5aeSCody P Schafer struct symsrc ss_[2]; 10343aafe5aeSCody P Schafer struct symsrc *syms_ss = NULL, *runtime_ss = NULL; 103586470930SIngo Molnar 1036aeafcbafSArnaldo Carvalho de Melo dso__set_loaded(dso, map->type); 103766bd8424SArnaldo Carvalho de Melo 1038aeafcbafSArnaldo Carvalho de Melo if (dso->kernel == DSO_TYPE_KERNEL) 1039aeafcbafSArnaldo Carvalho de Melo return dso__load_kernel_sym(dso, map, filter); 1040aeafcbafSArnaldo Carvalho de Melo else if (dso->kernel == DSO_TYPE_GUEST_KERNEL) 1041aeafcbafSArnaldo Carvalho de Melo return dso__load_guest_kernel_sym(dso, map, filter); 1042a1645ce1SZhang, Yanmin 104323346f21SArnaldo Carvalho de Melo if (map->groups && map->groups->machine) 104423346f21SArnaldo Carvalho de Melo machine = map->groups->machine; 1045a1645ce1SZhang, Yanmin else 104623346f21SArnaldo Carvalho de Melo machine = NULL; 1047c338aee8SArnaldo Carvalho de Melo 104844f24cb3SJiri Olsa name = malloc(PATH_MAX); 104986470930SIngo Molnar if (!name) 105086470930SIngo Molnar return -1; 105186470930SIngo Molnar 1052aeafcbafSArnaldo Carvalho de Melo dso->adjust_symbols = 0; 1053f5812a7aSArnaldo Carvalho de Melo 1054aeafcbafSArnaldo Carvalho de Melo if (strncmp(dso->name, "/tmp/perf-", 10) == 0) { 1055981c1252SPekka Enberg struct stat st; 1056981c1252SPekka Enberg 1057e9b52ef2SVasiliy Kulikov if (lstat(dso->name, &st) < 0) 1058981c1252SPekka Enberg return -1; 1059981c1252SPekka Enberg 1060981c1252SPekka Enberg if (st.st_uid && (st.st_uid != geteuid())) { 1061981c1252SPekka Enberg pr_warning("File %s not owned by current user or root, " 1062981c1252SPekka Enberg "ignoring it.\n", dso->name); 1063981c1252SPekka Enberg return -1; 1064981c1252SPekka Enberg } 1065981c1252SPekka Enberg 1066aeafcbafSArnaldo Carvalho de Melo ret = dso__load_perf_map(dso, map, filter); 106744f24cb3SJiri Olsa dso->symtab_type = ret > 0 ? DSO_BINARY_TYPE__JAVA_JIT : 106844f24cb3SJiri Olsa DSO_BINARY_TYPE__NOT_FOUND; 106994cb9e38SArnaldo Carvalho de Melo return ret; 107094cb9e38SArnaldo Carvalho de Melo } 107194cb9e38SArnaldo Carvalho de Melo 107244f24cb3SJiri Olsa if (machine) 107344f24cb3SJiri Olsa root_dir = machine->root_dir; 107444f24cb3SJiri Olsa 10756da80ce8SDave Martin /* Iterate over candidate debug images. 10763aafe5aeSCody P Schafer * Keep track of "interesting" ones (those which have a symtab, dynsym, 10773aafe5aeSCody P Schafer * and/or opd section) for processing. 10786da80ce8SDave Martin */ 107944f24cb3SJiri Olsa for (i = 0; i < DSO_BINARY_TYPE__SYMTAB_CNT; i++) { 10803aafe5aeSCody P Schafer struct symsrc *ss = &ss_[ss_pos]; 10813aafe5aeSCody P Schafer bool next_slot = false; 108244f24cb3SJiri Olsa 1083005f9294SCody P Schafer enum dso_binary_type symtab_type = binary_type_symtab[i]; 108444f24cb3SJiri Olsa 1085005f9294SCody P Schafer if (dso__binary_type_file(dso, symtab_type, 108644f24cb3SJiri Olsa root_dir, name, PATH_MAX)) 10876da80ce8SDave Martin continue; 108886470930SIngo Molnar 10896da80ce8SDave Martin /* Name is now the name of the next image to try */ 10903aafe5aeSCody P Schafer if (symsrc__init(ss, dso, name, symtab_type) < 0) 10916da80ce8SDave Martin continue; 10926da80ce8SDave Martin 10933aafe5aeSCody P Schafer if (!syms_ss && symsrc__has_symtab(ss)) { 10943aafe5aeSCody P Schafer syms_ss = ss; 10953aafe5aeSCody P Schafer next_slot = true; 1096d26cd12bSCody P Schafer } 1097d26cd12bSCody P Schafer 10983aafe5aeSCody P Schafer if (!runtime_ss && symsrc__possibly_runtime(ss)) { 10993aafe5aeSCody P Schafer runtime_ss = ss; 11003aafe5aeSCody P Schafer next_slot = true; 1101a44f605bSCody P Schafer } 110286470930SIngo Molnar 11033aafe5aeSCody P Schafer if (next_slot) { 11043aafe5aeSCody P Schafer ss_pos++; 110533ff581eSJiri Olsa 11063aafe5aeSCody P Schafer if (syms_ss && runtime_ss) 11076da80ce8SDave Martin break; 1108a25e46c4SArnaldo Carvalho de Melo } 11093aafe5aeSCody P Schafer 11106da80ce8SDave Martin } 11116da80ce8SDave Martin 11123aafe5aeSCody P Schafer if (!runtime_ss && !syms_ss) 11133aafe5aeSCody P Schafer goto out_free; 11143aafe5aeSCody P Schafer 11153aafe5aeSCody P Schafer if (runtime_ss && !syms_ss) { 11163aafe5aeSCody P Schafer syms_ss = runtime_ss; 111760e4b10cSArnaldo Carvalho de Melo } 111860e4b10cSArnaldo Carvalho de Melo 11193aafe5aeSCody P Schafer /* We'll have to hope for the best */ 11203aafe5aeSCody P Schafer if (!runtime_ss && syms_ss) 11213aafe5aeSCody P Schafer runtime_ss = syms_ss; 11223aafe5aeSCody P Schafer 11233aafe5aeSCody P Schafer if (syms_ss) 11243aafe5aeSCody P Schafer ret = dso__load_sym(dso, map, syms_ss, runtime_ss, filter, 0); 11253aafe5aeSCody P Schafer else 11263aafe5aeSCody P Schafer ret = -1; 11273aafe5aeSCody P Schafer 1128f47b58b7SDavid Ahern if (ret > 0) { 11293aafe5aeSCody P Schafer int nr_plt; 11303aafe5aeSCody P Schafer 11313aafe5aeSCody P Schafer nr_plt = dso__synthesize_plt_symbols(dso, runtime_ss, map, filter); 11323aafe5aeSCody P Schafer if (nr_plt > 0) 11333aafe5aeSCody P Schafer ret += nr_plt; 11343aafe5aeSCody P Schafer } 11353aafe5aeSCody P Schafer 11363aafe5aeSCody P Schafer for (; ss_pos > 0; ss_pos--) 11373aafe5aeSCody P Schafer symsrc__destroy(&ss_[ss_pos - 1]); 11383aafe5aeSCody P Schafer out_free: 113986470930SIngo Molnar free(name); 1140aeafcbafSArnaldo Carvalho de Melo if (ret < 0 && strstr(dso->name, " (deleted)") != NULL) 11411340e6bbSArnaldo Carvalho de Melo return 0; 114286470930SIngo Molnar return ret; 114386470930SIngo Molnar } 114486470930SIngo Molnar 1145aeafcbafSArnaldo Carvalho de Melo struct map *map_groups__find_by_name(struct map_groups *mg, 114679406cd7SArnaldo Carvalho de Melo enum map_type type, const char *name) 1147439d473bSArnaldo Carvalho de Melo { 1148439d473bSArnaldo Carvalho de Melo struct rb_node *nd; 1149439d473bSArnaldo Carvalho de Melo 1150aeafcbafSArnaldo Carvalho de Melo for (nd = rb_first(&mg->maps[type]); nd; nd = rb_next(nd)) { 1151439d473bSArnaldo Carvalho de Melo struct map *map = rb_entry(nd, struct map, rb_node); 1152439d473bSArnaldo Carvalho de Melo 1153b7cece76SArnaldo Carvalho de Melo if (map->dso && strcmp(map->dso->short_name, name) == 0) 1154439d473bSArnaldo Carvalho de Melo return map; 1155439d473bSArnaldo Carvalho de Melo } 1156439d473bSArnaldo Carvalho de Melo 1157439d473bSArnaldo Carvalho de Melo return NULL; 1158439d473bSArnaldo Carvalho de Melo } 1159439d473bSArnaldo Carvalho de Melo 1160aeafcbafSArnaldo Carvalho de Melo static int dso__kernel_module_get_build_id(struct dso *dso, 1161a1645ce1SZhang, Yanmin const char *root_dir) 1162b7cece76SArnaldo Carvalho de Melo { 1163b7cece76SArnaldo Carvalho de Melo char filename[PATH_MAX]; 1164b7cece76SArnaldo Carvalho de Melo /* 1165b7cece76SArnaldo Carvalho de Melo * kernel module short names are of the form "[module]" and 1166b7cece76SArnaldo Carvalho de Melo * we need just "module" here. 1167b7cece76SArnaldo Carvalho de Melo */ 1168aeafcbafSArnaldo Carvalho de Melo const char *name = dso->short_name + 1; 1169b7cece76SArnaldo Carvalho de Melo 1170b7cece76SArnaldo Carvalho de Melo snprintf(filename, sizeof(filename), 1171a1645ce1SZhang, Yanmin "%s/sys/module/%.*s/notes/.note.gnu.build-id", 1172a1645ce1SZhang, Yanmin root_dir, (int)strlen(name) - 1, name); 1173b7cece76SArnaldo Carvalho de Melo 1174aeafcbafSArnaldo Carvalho de Melo if (sysfs__read_build_id(filename, dso->build_id, 1175aeafcbafSArnaldo Carvalho de Melo sizeof(dso->build_id)) == 0) 1176aeafcbafSArnaldo Carvalho de Melo dso->has_build_id = true; 1177b7cece76SArnaldo Carvalho de Melo 1178b7cece76SArnaldo Carvalho de Melo return 0; 1179b7cece76SArnaldo Carvalho de Melo } 1180b7cece76SArnaldo Carvalho de Melo 1181aeafcbafSArnaldo Carvalho de Melo static int map_groups__set_modules_path_dir(struct map_groups *mg, 1182a1645ce1SZhang, Yanmin const char *dir_name) 11836cfcc53eSMike Galbraith { 1184439d473bSArnaldo Carvalho de Melo struct dirent *dent; 11855aab621bSArnaldo Carvalho de Melo DIR *dir = opendir(dir_name); 118674534341SGui Jianfeng int ret = 0; 11876cfcc53eSMike Galbraith 1188439d473bSArnaldo Carvalho de Melo if (!dir) { 11895aab621bSArnaldo Carvalho de Melo pr_debug("%s: cannot open %s dir\n", __func__, dir_name); 1190439d473bSArnaldo Carvalho de Melo return -1; 1191439d473bSArnaldo Carvalho de Melo } 11926cfcc53eSMike Galbraith 1193439d473bSArnaldo Carvalho de Melo while ((dent = readdir(dir)) != NULL) { 1194439d473bSArnaldo Carvalho de Melo char path[PATH_MAX]; 1195a1645ce1SZhang, Yanmin struct stat st; 1196439d473bSArnaldo Carvalho de Melo 1197a1645ce1SZhang, Yanmin /*sshfs might return bad dent->d_type, so we have to stat*/ 11982b600f95SNamhyung Kim snprintf(path, sizeof(path), "%s/%s", dir_name, dent->d_name); 1199a1645ce1SZhang, Yanmin if (stat(path, &st)) 1200a1645ce1SZhang, Yanmin continue; 1201a1645ce1SZhang, Yanmin 1202a1645ce1SZhang, Yanmin if (S_ISDIR(st.st_mode)) { 1203439d473bSArnaldo Carvalho de Melo if (!strcmp(dent->d_name, ".") || 1204439d473bSArnaldo Carvalho de Melo !strcmp(dent->d_name, "..")) 1205439d473bSArnaldo Carvalho de Melo continue; 1206439d473bSArnaldo Carvalho de Melo 1207aeafcbafSArnaldo Carvalho de Melo ret = map_groups__set_modules_path_dir(mg, path); 120874534341SGui Jianfeng if (ret < 0) 120974534341SGui Jianfeng goto out; 1210439d473bSArnaldo Carvalho de Melo } else { 1211439d473bSArnaldo Carvalho de Melo char *dot = strrchr(dent->d_name, '.'), 1212439d473bSArnaldo Carvalho de Melo dso_name[PATH_MAX]; 1213439d473bSArnaldo Carvalho de Melo struct map *map; 1214cfc10d3bSArnaldo Carvalho de Melo char *long_name; 1215439d473bSArnaldo Carvalho de Melo 1216439d473bSArnaldo Carvalho de Melo if (dot == NULL || strcmp(dot, ".ko")) 1217439d473bSArnaldo Carvalho de Melo continue; 1218439d473bSArnaldo Carvalho de Melo snprintf(dso_name, sizeof(dso_name), "[%.*s]", 1219439d473bSArnaldo Carvalho de Melo (int)(dot - dent->d_name), dent->d_name); 1220439d473bSArnaldo Carvalho de Melo 1221a2a99e8eSArnaldo Carvalho de Melo strxfrchar(dso_name, '-', '_'); 1222aeafcbafSArnaldo Carvalho de Melo map = map_groups__find_by_name(mg, MAP__FUNCTION, 1223aeafcbafSArnaldo Carvalho de Melo dso_name); 1224439d473bSArnaldo Carvalho de Melo if (map == NULL) 1225439d473bSArnaldo Carvalho de Melo continue; 1226439d473bSArnaldo Carvalho de Melo 1227cfc10d3bSArnaldo Carvalho de Melo long_name = strdup(path); 122874534341SGui Jianfeng if (long_name == NULL) { 122974534341SGui Jianfeng ret = -1; 123074534341SGui Jianfeng goto out; 123174534341SGui Jianfeng } 1232cfc10d3bSArnaldo Carvalho de Melo dso__set_long_name(map->dso, long_name); 12336e406257SArnaldo Carvalho de Melo map->dso->lname_alloc = 1; 1234a1645ce1SZhang, Yanmin dso__kernel_module_get_build_id(map->dso, ""); 1235439d473bSArnaldo Carvalho de Melo } 1236439d473bSArnaldo Carvalho de Melo } 1237439d473bSArnaldo Carvalho de Melo 123874534341SGui Jianfeng out: 1239439d473bSArnaldo Carvalho de Melo closedir(dir); 124074534341SGui Jianfeng return ret; 1241439d473bSArnaldo Carvalho de Melo } 1242439d473bSArnaldo Carvalho de Melo 1243a1645ce1SZhang, Yanmin static char *get_kernel_version(const char *root_dir) 1244439d473bSArnaldo Carvalho de Melo { 1245a1645ce1SZhang, Yanmin char version[PATH_MAX]; 1246a1645ce1SZhang, Yanmin FILE *file; 1247a1645ce1SZhang, Yanmin char *name, *tmp; 1248a1645ce1SZhang, Yanmin const char *prefix = "Linux version "; 1249a1645ce1SZhang, Yanmin 1250a1645ce1SZhang, Yanmin sprintf(version, "%s/proc/version", root_dir); 1251a1645ce1SZhang, Yanmin file = fopen(version, "r"); 1252a1645ce1SZhang, Yanmin if (!file) 1253a1645ce1SZhang, Yanmin return NULL; 1254a1645ce1SZhang, Yanmin 1255a1645ce1SZhang, Yanmin version[0] = '\0'; 1256a1645ce1SZhang, Yanmin tmp = fgets(version, sizeof(version), file); 1257a1645ce1SZhang, Yanmin fclose(file); 1258a1645ce1SZhang, Yanmin 1259a1645ce1SZhang, Yanmin name = strstr(version, prefix); 1260a1645ce1SZhang, Yanmin if (!name) 1261a1645ce1SZhang, Yanmin return NULL; 1262a1645ce1SZhang, Yanmin name += strlen(prefix); 1263a1645ce1SZhang, Yanmin tmp = strchr(name, ' '); 1264a1645ce1SZhang, Yanmin if (tmp) 1265a1645ce1SZhang, Yanmin *tmp = '\0'; 1266a1645ce1SZhang, Yanmin 1267a1645ce1SZhang, Yanmin return strdup(name); 1268a1645ce1SZhang, Yanmin } 1269a1645ce1SZhang, Yanmin 1270aeafcbafSArnaldo Carvalho de Melo static int machine__set_modules_path(struct machine *machine) 1271a1645ce1SZhang, Yanmin { 1272a1645ce1SZhang, Yanmin char *version; 1273439d473bSArnaldo Carvalho de Melo char modules_path[PATH_MAX]; 1274439d473bSArnaldo Carvalho de Melo 1275aeafcbafSArnaldo Carvalho de Melo version = get_kernel_version(machine->root_dir); 1276a1645ce1SZhang, Yanmin if (!version) 1277439d473bSArnaldo Carvalho de Melo return -1; 1278439d473bSArnaldo Carvalho de Melo 1279a1645ce1SZhang, Yanmin snprintf(modules_path, sizeof(modules_path), "%s/lib/modules/%s/kernel", 1280aeafcbafSArnaldo Carvalho de Melo machine->root_dir, version); 1281a1645ce1SZhang, Yanmin free(version); 1282439d473bSArnaldo Carvalho de Melo 1283aeafcbafSArnaldo Carvalho de Melo return map_groups__set_modules_path_dir(&machine->kmaps, modules_path); 1284439d473bSArnaldo Carvalho de Melo } 12856cfcc53eSMike Galbraith 1286aeafcbafSArnaldo Carvalho de Melo struct map *machine__new_module(struct machine *machine, u64 start, 1287d28c6223SArnaldo Carvalho de Melo const char *filename) 1288b7cece76SArnaldo Carvalho de Melo { 1289b7cece76SArnaldo Carvalho de Melo struct map *map; 1290aeafcbafSArnaldo Carvalho de Melo struct dso *dso = __dsos__findnew(&machine->kernel_dsos, filename); 1291b7cece76SArnaldo Carvalho de Melo 1292b7cece76SArnaldo Carvalho de Melo if (dso == NULL) 1293b7cece76SArnaldo Carvalho de Melo return NULL; 1294b7cece76SArnaldo Carvalho de Melo 1295b7cece76SArnaldo Carvalho de Melo map = map__new2(start, dso, MAP__FUNCTION); 1296b7cece76SArnaldo Carvalho de Melo if (map == NULL) 1297b7cece76SArnaldo Carvalho de Melo return NULL; 1298b7cece76SArnaldo Carvalho de Melo 1299aeafcbafSArnaldo Carvalho de Melo if (machine__is_host(machine)) 130044f24cb3SJiri Olsa dso->symtab_type = DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE; 1301a1645ce1SZhang, Yanmin else 130244f24cb3SJiri Olsa dso->symtab_type = DSO_BINARY_TYPE__GUEST_KMODULE; 1303aeafcbafSArnaldo Carvalho de Melo map_groups__insert(&machine->kmaps, map); 1304b7cece76SArnaldo Carvalho de Melo return map; 1305b7cece76SArnaldo Carvalho de Melo } 1306b7cece76SArnaldo Carvalho de Melo 1307aeafcbafSArnaldo Carvalho de Melo static int machine__create_modules(struct machine *machine) 1308439d473bSArnaldo Carvalho de Melo { 1309439d473bSArnaldo Carvalho de Melo char *line = NULL; 1310439d473bSArnaldo Carvalho de Melo size_t n; 1311a1645ce1SZhang, Yanmin FILE *file; 1312439d473bSArnaldo Carvalho de Melo struct map *map; 1313a1645ce1SZhang, Yanmin const char *modules; 1314a1645ce1SZhang, Yanmin char path[PATH_MAX]; 1315439d473bSArnaldo Carvalho de Melo 1316aeafcbafSArnaldo Carvalho de Melo if (machine__is_default_guest(machine)) 1317a1645ce1SZhang, Yanmin modules = symbol_conf.default_guest_modules; 1318a1645ce1SZhang, Yanmin else { 1319aeafcbafSArnaldo Carvalho de Melo sprintf(path, "%s/proc/modules", machine->root_dir); 1320a1645ce1SZhang, Yanmin modules = path; 1321a1645ce1SZhang, Yanmin } 1322a1645ce1SZhang, Yanmin 1323ec80fde7SArnaldo Carvalho de Melo if (symbol__restricted_filename(path, "/proc/modules")) 1324ec80fde7SArnaldo Carvalho de Melo return -1; 1325ec80fde7SArnaldo Carvalho de Melo 1326a1645ce1SZhang, Yanmin file = fopen(modules, "r"); 1327439d473bSArnaldo Carvalho de Melo if (file == NULL) 1328439d473bSArnaldo Carvalho de Melo return -1; 1329439d473bSArnaldo Carvalho de Melo 1330439d473bSArnaldo Carvalho de Melo while (!feof(file)) { 1331439d473bSArnaldo Carvalho de Melo char name[PATH_MAX]; 1332439d473bSArnaldo Carvalho de Melo u64 start; 1333439d473bSArnaldo Carvalho de Melo char *sep; 1334439d473bSArnaldo Carvalho de Melo int line_len; 1335439d473bSArnaldo Carvalho de Melo 1336439d473bSArnaldo Carvalho de Melo line_len = getline(&line, &n, file); 1337439d473bSArnaldo Carvalho de Melo if (line_len < 0) 13386cfcc53eSMike Galbraith break; 13396cfcc53eSMike Galbraith 1340439d473bSArnaldo Carvalho de Melo if (!line) 1341439d473bSArnaldo Carvalho de Melo goto out_failure; 1342439d473bSArnaldo Carvalho de Melo 1343439d473bSArnaldo Carvalho de Melo line[--line_len] = '\0'; /* \n */ 1344439d473bSArnaldo Carvalho de Melo 1345439d473bSArnaldo Carvalho de Melo sep = strrchr(line, 'x'); 1346439d473bSArnaldo Carvalho de Melo if (sep == NULL) 1347439d473bSArnaldo Carvalho de Melo continue; 1348439d473bSArnaldo Carvalho de Melo 1349439d473bSArnaldo Carvalho de Melo hex2u64(sep + 1, &start); 1350439d473bSArnaldo Carvalho de Melo 1351439d473bSArnaldo Carvalho de Melo sep = strchr(line, ' '); 1352439d473bSArnaldo Carvalho de Melo if (sep == NULL) 1353439d473bSArnaldo Carvalho de Melo continue; 1354439d473bSArnaldo Carvalho de Melo 1355439d473bSArnaldo Carvalho de Melo *sep = '\0'; 1356439d473bSArnaldo Carvalho de Melo 1357439d473bSArnaldo Carvalho de Melo snprintf(name, sizeof(name), "[%s]", line); 1358aeafcbafSArnaldo Carvalho de Melo map = machine__new_module(machine, start, name); 1359b7cece76SArnaldo Carvalho de Melo if (map == NULL) 1360439d473bSArnaldo Carvalho de Melo goto out_delete_line; 1361aeafcbafSArnaldo Carvalho de Melo dso__kernel_module_get_build_id(map->dso, machine->root_dir); 13626cfcc53eSMike Galbraith } 13636cfcc53eSMike Galbraith 1364439d473bSArnaldo Carvalho de Melo free(line); 1365439d473bSArnaldo Carvalho de Melo fclose(file); 1366439d473bSArnaldo Carvalho de Melo 1367aeafcbafSArnaldo Carvalho de Melo return machine__set_modules_path(machine); 1368439d473bSArnaldo Carvalho de Melo 1369439d473bSArnaldo Carvalho de Melo out_delete_line: 1370439d473bSArnaldo Carvalho de Melo free(line); 1371439d473bSArnaldo Carvalho de Melo out_failure: 1372439d473bSArnaldo Carvalho de Melo return -1; 13736cfcc53eSMike Galbraith } 13746cfcc53eSMike Galbraith 1375aeafcbafSArnaldo Carvalho de Melo int dso__load_vmlinux(struct dso *dso, struct map *map, 13766beba7adSArnaldo Carvalho de Melo const char *vmlinux, symbol_filter_t filter) 137786470930SIngo Molnar { 1378b68e2f91SCody P Schafer int err = -1; 1379b68e2f91SCody P Schafer struct symsrc ss; 1380ec5761eaSDavid Ahern char symfs_vmlinux[PATH_MAX]; 1381005f9294SCody P Schafer enum dso_binary_type symtab_type; 138286470930SIngo Molnar 1383a639dc64SArnaldo Carvalho de Melo snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s%s", 1384ec5761eaSDavid Ahern symbol_conf.symfs, vmlinux); 138586470930SIngo Molnar 138621ea4539SCody P Schafer if (dso->kernel == DSO_TYPE_GUEST_KERNEL) 1387005f9294SCody P Schafer symtab_type = DSO_BINARY_TYPE__GUEST_VMLINUX; 138821ea4539SCody P Schafer else 1389005f9294SCody P Schafer symtab_type = DSO_BINARY_TYPE__VMLINUX; 139021ea4539SCody P Schafer 1391005f9294SCody P Schafer if (symsrc__init(&ss, dso, symfs_vmlinux, symtab_type)) 1392b68e2f91SCody P Schafer return -1; 1393b68e2f91SCody P Schafer 1394261360b6SCody P Schafer err = dso__load_sym(dso, map, &ss, &ss, filter, 0); 1395b68e2f91SCody P Schafer symsrc__destroy(&ss); 139686470930SIngo Molnar 1397515850e4SCody P Schafer if (err > 0) { 1398515850e4SCody P Schafer dso__set_long_name(dso, (char *)vmlinux); 1399515850e4SCody P Schafer dso__set_loaded(dso, map->type); 1400ec5761eaSDavid Ahern pr_debug("Using %s for symbols\n", symfs_vmlinux); 1401515850e4SCody P Schafer } 14023846df2eSArnaldo Carvalho de Melo 140386470930SIngo Molnar return err; 140486470930SIngo Molnar } 140586470930SIngo Molnar 1406aeafcbafSArnaldo Carvalho de Melo int dso__load_vmlinux_path(struct dso *dso, struct map *map, 14079de89fe7SArnaldo Carvalho de Melo symbol_filter_t filter) 1408a19afe46SArnaldo Carvalho de Melo { 1409a19afe46SArnaldo Carvalho de Melo int i, err = 0; 14105ad90e4eSArnaldo Carvalho de Melo char *filename; 1411a19afe46SArnaldo Carvalho de Melo 1412a19afe46SArnaldo Carvalho de Melo pr_debug("Looking at the vmlinux_path (%d entries long)\n", 14135ad90e4eSArnaldo Carvalho de Melo vmlinux_path__nr_entries + 1); 14145ad90e4eSArnaldo Carvalho de Melo 1415aeafcbafSArnaldo Carvalho de Melo filename = dso__build_id_filename(dso, NULL, 0); 14165ad90e4eSArnaldo Carvalho de Melo if (filename != NULL) { 1417aeafcbafSArnaldo Carvalho de Melo err = dso__load_vmlinux(dso, map, filename, filter); 1418261ee821SCody P Schafer if (err > 0) 14195ad90e4eSArnaldo Carvalho de Melo goto out; 14205ad90e4eSArnaldo Carvalho de Melo free(filename); 14215ad90e4eSArnaldo Carvalho de Melo } 1422a19afe46SArnaldo Carvalho de Melo 1423a19afe46SArnaldo Carvalho de Melo for (i = 0; i < vmlinux_path__nr_entries; ++i) { 1424aeafcbafSArnaldo Carvalho de Melo err = dso__load_vmlinux(dso, map, vmlinux_path[i], filter); 1425a19afe46SArnaldo Carvalho de Melo if (err > 0) { 1426aeafcbafSArnaldo Carvalho de Melo dso__set_long_name(dso, strdup(vmlinux_path[i])); 1427a19afe46SArnaldo Carvalho de Melo break; 1428a19afe46SArnaldo Carvalho de Melo } 1429a19afe46SArnaldo Carvalho de Melo } 14305ad90e4eSArnaldo Carvalho de Melo out: 1431a19afe46SArnaldo Carvalho de Melo return err; 1432a19afe46SArnaldo Carvalho de Melo } 1433a19afe46SArnaldo Carvalho de Melo 1434aeafcbafSArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *dso, struct map *map, 14359de89fe7SArnaldo Carvalho de Melo symbol_filter_t filter) 143686470930SIngo Molnar { 1437cc612d81SArnaldo Carvalho de Melo int err; 14389e201442SArnaldo Carvalho de Melo const char *kallsyms_filename = NULL; 14399e201442SArnaldo Carvalho de Melo char *kallsyms_allocated_filename = NULL; 1440dc8d6ab2SArnaldo Carvalho de Melo /* 1441b226a5a7SDavid Ahern * Step 1: if the user specified a kallsyms or vmlinux filename, use 1442b226a5a7SDavid Ahern * it and only it, reporting errors to the user if it cannot be used. 1443dc8d6ab2SArnaldo Carvalho de Melo * 1444dc8d6ab2SArnaldo Carvalho de Melo * For instance, try to analyse an ARM perf.data file _without_ a 1445dc8d6ab2SArnaldo Carvalho de Melo * build-id, or if the user specifies the wrong path to the right 1446dc8d6ab2SArnaldo Carvalho de Melo * vmlinux file, obviously we can't fallback to another vmlinux (a 1447dc8d6ab2SArnaldo Carvalho de Melo * x86_86 one, on the machine where analysis is being performed, say), 1448dc8d6ab2SArnaldo Carvalho de Melo * or worse, /proc/kallsyms. 1449dc8d6ab2SArnaldo Carvalho de Melo * 1450dc8d6ab2SArnaldo Carvalho de Melo * If the specified file _has_ a build-id and there is a build-id 1451dc8d6ab2SArnaldo Carvalho de Melo * section in the perf.data file, we will still do the expected 1452dc8d6ab2SArnaldo Carvalho de Melo * validation in dso__load_vmlinux and will bail out if they don't 1453dc8d6ab2SArnaldo Carvalho de Melo * match. 1454dc8d6ab2SArnaldo Carvalho de Melo */ 1455b226a5a7SDavid Ahern if (symbol_conf.kallsyms_name != NULL) { 1456b226a5a7SDavid Ahern kallsyms_filename = symbol_conf.kallsyms_name; 1457b226a5a7SDavid Ahern goto do_kallsyms; 1458b226a5a7SDavid Ahern } 1459b226a5a7SDavid Ahern 1460dc8d6ab2SArnaldo Carvalho de Melo if (symbol_conf.vmlinux_name != NULL) { 1461aeafcbafSArnaldo Carvalho de Melo err = dso__load_vmlinux(dso, map, 1462dc8d6ab2SArnaldo Carvalho de Melo symbol_conf.vmlinux_name, filter); 1463e7dadc00SArnaldo Carvalho de Melo if (err > 0) { 1464aeafcbafSArnaldo Carvalho de Melo dso__set_long_name(dso, 1465e7dadc00SArnaldo Carvalho de Melo strdup(symbol_conf.vmlinux_name)); 1466e7dadc00SArnaldo Carvalho de Melo goto out_fixup; 1467e7dadc00SArnaldo Carvalho de Melo } 1468e7dadc00SArnaldo Carvalho de Melo return err; 1469dc8d6ab2SArnaldo Carvalho de Melo } 1470439d473bSArnaldo Carvalho de Melo 1471cc612d81SArnaldo Carvalho de Melo if (vmlinux_path != NULL) { 1472aeafcbafSArnaldo Carvalho de Melo err = dso__load_vmlinux_path(dso, map, filter); 1473a19afe46SArnaldo Carvalho de Melo if (err > 0) 1474cc612d81SArnaldo Carvalho de Melo goto out_fixup; 1475cc612d81SArnaldo Carvalho de Melo } 1476cc612d81SArnaldo Carvalho de Melo 1477ec5761eaSDavid Ahern /* do not try local files if a symfs was given */ 1478ec5761eaSDavid Ahern if (symbol_conf.symfs[0] != 0) 1479ec5761eaSDavid Ahern return -1; 1480ec5761eaSDavid Ahern 1481b7cece76SArnaldo Carvalho de Melo /* 1482b7cece76SArnaldo Carvalho de Melo * Say the kernel DSO was created when processing the build-id header table, 1483b7cece76SArnaldo Carvalho de Melo * we have a build-id, so check if it is the same as the running kernel, 1484b7cece76SArnaldo Carvalho de Melo * using it if it is. 1485b7cece76SArnaldo Carvalho de Melo */ 1486aeafcbafSArnaldo Carvalho de Melo if (dso->has_build_id) { 1487b7cece76SArnaldo Carvalho de Melo u8 kallsyms_build_id[BUILD_ID_SIZE]; 14889e201442SArnaldo Carvalho de Melo char sbuild_id[BUILD_ID_SIZE * 2 + 1]; 1489b7cece76SArnaldo Carvalho de Melo 1490b7cece76SArnaldo Carvalho de Melo if (sysfs__read_build_id("/sys/kernel/notes", kallsyms_build_id, 14918d0591f6SArnaldo Carvalho de Melo sizeof(kallsyms_build_id)) == 0) { 1492aeafcbafSArnaldo Carvalho de Melo if (dso__build_id_equal(dso, kallsyms_build_id)) { 14939e201442SArnaldo Carvalho de Melo kallsyms_filename = "/proc/kallsyms"; 1494b7cece76SArnaldo Carvalho de Melo goto do_kallsyms; 14958d0591f6SArnaldo Carvalho de Melo } 14969e201442SArnaldo Carvalho de Melo } 1497dc8d6ab2SArnaldo Carvalho de Melo /* 1498dc8d6ab2SArnaldo Carvalho de Melo * Now look if we have it on the build-id cache in 1499dc8d6ab2SArnaldo Carvalho de Melo * $HOME/.debug/[kernel.kallsyms]. 1500dc8d6ab2SArnaldo Carvalho de Melo */ 1501aeafcbafSArnaldo Carvalho de Melo build_id__sprintf(dso->build_id, sizeof(dso->build_id), 15029e201442SArnaldo Carvalho de Melo sbuild_id); 15039e201442SArnaldo Carvalho de Melo 15049e201442SArnaldo Carvalho de Melo if (asprintf(&kallsyms_allocated_filename, 15059e201442SArnaldo Carvalho de Melo "%s/.debug/[kernel.kallsyms]/%s", 15063846df2eSArnaldo Carvalho de Melo getenv("HOME"), sbuild_id) == -1) { 15073846df2eSArnaldo Carvalho de Melo pr_err("Not enough memory for kallsyms file lookup\n"); 15088d0591f6SArnaldo Carvalho de Melo return -1; 15093846df2eSArnaldo Carvalho de Melo } 15108d0591f6SArnaldo Carvalho de Melo 151119fc2dedSArnaldo Carvalho de Melo kallsyms_filename = kallsyms_allocated_filename; 151219fc2dedSArnaldo Carvalho de Melo 1513dc8d6ab2SArnaldo Carvalho de Melo if (access(kallsyms_filename, F_OK)) { 15143846df2eSArnaldo Carvalho de Melo pr_err("No kallsyms or vmlinux with build-id %s " 15153846df2eSArnaldo Carvalho de Melo "was found\n", sbuild_id); 15169e201442SArnaldo Carvalho de Melo free(kallsyms_allocated_filename); 1517dc8d6ab2SArnaldo Carvalho de Melo return -1; 1518ef6ae724SArnaldo Carvalho de Melo } 1519dc8d6ab2SArnaldo Carvalho de Melo } else { 1520dc8d6ab2SArnaldo Carvalho de Melo /* 1521dc8d6ab2SArnaldo Carvalho de Melo * Last resort, if we don't have a build-id and couldn't find 1522dc8d6ab2SArnaldo Carvalho de Melo * any vmlinux file, try the running kernel kallsyms table. 1523dc8d6ab2SArnaldo Carvalho de Melo */ 1524dc8d6ab2SArnaldo Carvalho de Melo kallsyms_filename = "/proc/kallsyms"; 1525dc8d6ab2SArnaldo Carvalho de Melo } 1526dc8d6ab2SArnaldo Carvalho de Melo 1527dc8d6ab2SArnaldo Carvalho de Melo do_kallsyms: 1528aeafcbafSArnaldo Carvalho de Melo err = dso__load_kallsyms(dso, kallsyms_filename, map, filter); 15293846df2eSArnaldo Carvalho de Melo if (err > 0) 15303846df2eSArnaldo Carvalho de Melo pr_debug("Using %s for symbols\n", kallsyms_filename); 1531dc8d6ab2SArnaldo Carvalho de Melo free(kallsyms_allocated_filename); 1532dc8d6ab2SArnaldo Carvalho de Melo 1533439d473bSArnaldo Carvalho de Melo if (err > 0) { 1534aeafcbafSArnaldo Carvalho de Melo dso__set_long_name(dso, strdup("[kernel.kallsyms]")); 15350a0317b4SCody P Schafer out_fixup: 15366a4694a4SArnaldo Carvalho de Melo map__fixup_start(map); 15376a4694a4SArnaldo Carvalho de Melo map__fixup_end(map); 1538439d473bSArnaldo Carvalho de Melo } 153994cb9e38SArnaldo Carvalho de Melo 154086470930SIngo Molnar return err; 154186470930SIngo Molnar } 154286470930SIngo Molnar 1543aeafcbafSArnaldo Carvalho de Melo static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map, 1544a1645ce1SZhang, Yanmin symbol_filter_t filter) 1545a1645ce1SZhang, Yanmin { 1546a1645ce1SZhang, Yanmin int err; 1547a1645ce1SZhang, Yanmin const char *kallsyms_filename = NULL; 154823346f21SArnaldo Carvalho de Melo struct machine *machine; 1549a1645ce1SZhang, Yanmin char path[PATH_MAX]; 1550a1645ce1SZhang, Yanmin 1551a1645ce1SZhang, Yanmin if (!map->groups) { 1552a1645ce1SZhang, Yanmin pr_debug("Guest kernel map hasn't the point to groups\n"); 1553a1645ce1SZhang, Yanmin return -1; 1554a1645ce1SZhang, Yanmin } 155523346f21SArnaldo Carvalho de Melo machine = map->groups->machine; 1556a1645ce1SZhang, Yanmin 155723346f21SArnaldo Carvalho de Melo if (machine__is_default_guest(machine)) { 1558a1645ce1SZhang, Yanmin /* 1559a1645ce1SZhang, Yanmin * if the user specified a vmlinux filename, use it and only 1560a1645ce1SZhang, Yanmin * it, reporting errors to the user if it cannot be used. 1561a1645ce1SZhang, Yanmin * Or use file guest_kallsyms inputted by user on commandline 1562a1645ce1SZhang, Yanmin */ 1563a1645ce1SZhang, Yanmin if (symbol_conf.default_guest_vmlinux_name != NULL) { 1564aeafcbafSArnaldo Carvalho de Melo err = dso__load_vmlinux(dso, map, 1565a1645ce1SZhang, Yanmin symbol_conf.default_guest_vmlinux_name, filter); 1566a1645ce1SZhang, Yanmin goto out_try_fixup; 1567a1645ce1SZhang, Yanmin } 1568a1645ce1SZhang, Yanmin 1569a1645ce1SZhang, Yanmin kallsyms_filename = symbol_conf.default_guest_kallsyms; 1570a1645ce1SZhang, Yanmin if (!kallsyms_filename) 1571a1645ce1SZhang, Yanmin return -1; 1572a1645ce1SZhang, Yanmin } else { 157323346f21SArnaldo Carvalho de Melo sprintf(path, "%s/proc/kallsyms", machine->root_dir); 1574a1645ce1SZhang, Yanmin kallsyms_filename = path; 1575a1645ce1SZhang, Yanmin } 1576a1645ce1SZhang, Yanmin 1577aeafcbafSArnaldo Carvalho de Melo err = dso__load_kallsyms(dso, kallsyms_filename, map, filter); 1578a1645ce1SZhang, Yanmin if (err > 0) 1579a1645ce1SZhang, Yanmin pr_debug("Using %s for symbols\n", kallsyms_filename); 1580a1645ce1SZhang, Yanmin 1581a1645ce1SZhang, Yanmin out_try_fixup: 1582a1645ce1SZhang, Yanmin if (err > 0) { 1583a1645ce1SZhang, Yanmin if (kallsyms_filename != NULL) { 158448ea8f54SArnaldo Carvalho de Melo machine__mmap_name(machine, path, sizeof(path)); 1585aeafcbafSArnaldo Carvalho de Melo dso__set_long_name(dso, strdup(path)); 1586a1645ce1SZhang, Yanmin } 1587a1645ce1SZhang, Yanmin map__fixup_start(map); 1588a1645ce1SZhang, Yanmin map__fixup_end(map); 1589a1645ce1SZhang, Yanmin } 1590a1645ce1SZhang, Yanmin 1591a1645ce1SZhang, Yanmin return err; 1592a1645ce1SZhang, Yanmin } 1593cd84c2acSFrederic Weisbecker 1594e5a1845fSNamhyung Kim void dsos__add(struct list_head *head, struct dso *dso) 1595cd84c2acSFrederic Weisbecker { 1596b0da954aSArnaldo Carvalho de Melo list_add_tail(&dso->node, head); 1597cd84c2acSFrederic Weisbecker } 1598cd84c2acSFrederic Weisbecker 15991c4be9ffSJiri Olsa struct dso *dsos__find(struct list_head *head, const char *name) 1600cd84c2acSFrederic Weisbecker { 1601cd84c2acSFrederic Weisbecker struct dso *pos; 1602cd84c2acSFrederic Weisbecker 1603b0da954aSArnaldo Carvalho de Melo list_for_each_entry(pos, head, node) 1604cf4e5b08SArnaldo Carvalho de Melo if (strcmp(pos->long_name, name) == 0) 1605cd84c2acSFrederic Weisbecker return pos; 1606cd84c2acSFrederic Weisbecker return NULL; 1607cd84c2acSFrederic Weisbecker } 1608cd84c2acSFrederic Weisbecker 1609a89e5abeSArnaldo Carvalho de Melo struct dso *__dsos__findnew(struct list_head *head, const char *name) 1610cd84c2acSFrederic Weisbecker { 1611a89e5abeSArnaldo Carvalho de Melo struct dso *dso = dsos__find(head, name); 1612cd84c2acSFrederic Weisbecker 1613e4204992SArnaldo Carvalho de Melo if (!dso) { 161400a192b3SArnaldo Carvalho de Melo dso = dso__new(name); 1615cfc10d3bSArnaldo Carvalho de Melo if (dso != NULL) { 1616a89e5abeSArnaldo Carvalho de Melo dsos__add(head, dso); 1617cfc10d3bSArnaldo Carvalho de Melo dso__set_basename(dso); 1618cfc10d3bSArnaldo Carvalho de Melo } 1619e4204992SArnaldo Carvalho de Melo } 1620cd84c2acSFrederic Weisbecker 1621cd84c2acSFrederic Weisbecker return dso; 1622cd84c2acSFrederic Weisbecker } 1623cd84c2acSFrederic Weisbecker 16241f626bc3SArnaldo Carvalho de Melo size_t __dsos__fprintf(struct list_head *head, FILE *fp) 1625cd84c2acSFrederic Weisbecker { 1626cd84c2acSFrederic Weisbecker struct dso *pos; 1627cbf69680SArnaldo Carvalho de Melo size_t ret = 0; 1628cd84c2acSFrederic Weisbecker 162995011c60SArnaldo Carvalho de Melo list_for_each_entry(pos, head, node) { 163095011c60SArnaldo Carvalho de Melo int i; 163195011c60SArnaldo Carvalho de Melo for (i = 0; i < MAP__NR_TYPES; ++i) 1632cbf69680SArnaldo Carvalho de Melo ret += dso__fprintf(pos, i, fp); 1633cd84c2acSFrederic Weisbecker } 1634cd84c2acSFrederic Weisbecker 1635cbf69680SArnaldo Carvalho de Melo return ret; 1636cbf69680SArnaldo Carvalho de Melo } 1637cbf69680SArnaldo Carvalho de Melo 1638aeafcbafSArnaldo Carvalho de Melo size_t machines__fprintf_dsos(struct rb_root *machines, FILE *fp) 1639b0da954aSArnaldo Carvalho de Melo { 1640a1645ce1SZhang, Yanmin struct rb_node *nd; 1641cbf69680SArnaldo Carvalho de Melo size_t ret = 0; 1642a1645ce1SZhang, Yanmin 1643aeafcbafSArnaldo Carvalho de Melo for (nd = rb_first(machines); nd; nd = rb_next(nd)) { 164423346f21SArnaldo Carvalho de Melo struct machine *pos = rb_entry(nd, struct machine, rb_node); 1645cbf69680SArnaldo Carvalho de Melo ret += __dsos__fprintf(&pos->kernel_dsos, fp); 1646cbf69680SArnaldo Carvalho de Melo ret += __dsos__fprintf(&pos->user_dsos, fp); 1647a1645ce1SZhang, Yanmin } 1648cbf69680SArnaldo Carvalho de Melo 1649cbf69680SArnaldo Carvalho de Melo return ret; 1650b0da954aSArnaldo Carvalho de Melo } 1651b0da954aSArnaldo Carvalho de Melo 165288d3d9b7SArnaldo Carvalho de Melo static size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp, 165388d3d9b7SArnaldo Carvalho de Melo bool with_hits) 16549e03eb2dSArnaldo Carvalho de Melo { 16559e03eb2dSArnaldo Carvalho de Melo struct dso *pos; 16569e03eb2dSArnaldo Carvalho de Melo size_t ret = 0; 16579e03eb2dSArnaldo Carvalho de Melo 1658b0da954aSArnaldo Carvalho de Melo list_for_each_entry(pos, head, node) { 165988d3d9b7SArnaldo Carvalho de Melo if (with_hits && !pos->hit) 166088d3d9b7SArnaldo Carvalho de Melo continue; 16619e03eb2dSArnaldo Carvalho de Melo ret += dso__fprintf_buildid(pos, fp); 16629e03eb2dSArnaldo Carvalho de Melo ret += fprintf(fp, " %s\n", pos->long_name); 16639e03eb2dSArnaldo Carvalho de Melo } 16649e03eb2dSArnaldo Carvalho de Melo return ret; 16659e03eb2dSArnaldo Carvalho de Melo } 16669e03eb2dSArnaldo Carvalho de Melo 1667aeafcbafSArnaldo Carvalho de Melo size_t machine__fprintf_dsos_buildid(struct machine *machine, FILE *fp, 1668aeafcbafSArnaldo Carvalho de Melo bool with_hits) 1669f869097eSArnaldo Carvalho de Melo { 1670aeafcbafSArnaldo Carvalho de Melo return __dsos__fprintf_buildid(&machine->kernel_dsos, fp, with_hits) + 1671aeafcbafSArnaldo Carvalho de Melo __dsos__fprintf_buildid(&machine->user_dsos, fp, with_hits); 1672f869097eSArnaldo Carvalho de Melo } 1673f869097eSArnaldo Carvalho de Melo 1674aeafcbafSArnaldo Carvalho de Melo size_t machines__fprintf_dsos_buildid(struct rb_root *machines, 1675aeafcbafSArnaldo Carvalho de Melo FILE *fp, bool with_hits) 1676b0da954aSArnaldo Carvalho de Melo { 1677a1645ce1SZhang, Yanmin struct rb_node *nd; 1678a1645ce1SZhang, Yanmin size_t ret = 0; 1679a1645ce1SZhang, Yanmin 1680aeafcbafSArnaldo Carvalho de Melo for (nd = rb_first(machines); nd; nd = rb_next(nd)) { 168123346f21SArnaldo Carvalho de Melo struct machine *pos = rb_entry(nd, struct machine, rb_node); 1682f869097eSArnaldo Carvalho de Melo ret += machine__fprintf_dsos_buildid(pos, fp, with_hits); 1683a1645ce1SZhang, Yanmin } 1684a1645ce1SZhang, Yanmin return ret; 1685b0da954aSArnaldo Carvalho de Melo } 1686b0da954aSArnaldo Carvalho de Melo 1687f57b05edSJiri Olsa static struct dso* 1688f57b05edSJiri Olsa dso__kernel_findnew(struct machine *machine, const char *name, 1689f57b05edSJiri Olsa const char *short_name, int dso_type) 1690fd1d908cSArnaldo Carvalho de Melo { 1691f57b05edSJiri Olsa /* 1692f57b05edSJiri Olsa * The kernel dso could be created by build_id processing. 1693f57b05edSJiri Olsa */ 1694f57b05edSJiri Olsa struct dso *dso = __dsos__findnew(&machine->kernel_dsos, name); 1695fd1d908cSArnaldo Carvalho de Melo 1696f57b05edSJiri Olsa /* 1697f57b05edSJiri Olsa * We need to run this in all cases, since during the build_id 1698f57b05edSJiri Olsa * processing we had no idea this was the kernel dso. 1699f57b05edSJiri Olsa */ 1700aeafcbafSArnaldo Carvalho de Melo if (dso != NULL) { 1701f57b05edSJiri Olsa dso__set_short_name(dso, short_name); 1702f57b05edSJiri Olsa dso->kernel = dso_type; 1703a1645ce1SZhang, Yanmin } 1704a1645ce1SZhang, Yanmin 1705aeafcbafSArnaldo Carvalho de Melo return dso; 1706a1645ce1SZhang, Yanmin } 1707a1645ce1SZhang, Yanmin 1708aeafcbafSArnaldo Carvalho de Melo void dso__read_running_kernel_build_id(struct dso *dso, struct machine *machine) 1709a1645ce1SZhang, Yanmin { 1710a1645ce1SZhang, Yanmin char path[PATH_MAX]; 1711a1645ce1SZhang, Yanmin 171223346f21SArnaldo Carvalho de Melo if (machine__is_default_guest(machine)) 1713a1645ce1SZhang, Yanmin return; 171423346f21SArnaldo Carvalho de Melo sprintf(path, "%s/sys/kernel/notes", machine->root_dir); 1715aeafcbafSArnaldo Carvalho de Melo if (sysfs__read_build_id(path, dso->build_id, 1716aeafcbafSArnaldo Carvalho de Melo sizeof(dso->build_id)) == 0) 1717aeafcbafSArnaldo Carvalho de Melo dso->has_build_id = true; 1718fd1d908cSArnaldo Carvalho de Melo } 1719fd1d908cSArnaldo Carvalho de Melo 1720f57b05edSJiri Olsa static struct dso *machine__get_kernel(struct machine *machine) 1721cd84c2acSFrederic Weisbecker { 1722a1645ce1SZhang, Yanmin const char *vmlinux_name = NULL; 1723a1645ce1SZhang, Yanmin struct dso *kernel; 1724cd84c2acSFrederic Weisbecker 1725aeafcbafSArnaldo Carvalho de Melo if (machine__is_host(machine)) { 1726a1645ce1SZhang, Yanmin vmlinux_name = symbol_conf.vmlinux_name; 1727f57b05edSJiri Olsa if (!vmlinux_name) 1728f57b05edSJiri Olsa vmlinux_name = "[kernel.kallsyms]"; 1729f57b05edSJiri Olsa 1730f57b05edSJiri Olsa kernel = dso__kernel_findnew(machine, vmlinux_name, 1731f57b05edSJiri Olsa "[kernel]", 1732f57b05edSJiri Olsa DSO_TYPE_KERNEL); 1733a1645ce1SZhang, Yanmin } else { 1734f57b05edSJiri Olsa char bf[PATH_MAX]; 1735f57b05edSJiri Olsa 1736aeafcbafSArnaldo Carvalho de Melo if (machine__is_default_guest(machine)) 1737a1645ce1SZhang, Yanmin vmlinux_name = symbol_conf.default_guest_vmlinux_name; 1738f57b05edSJiri Olsa if (!vmlinux_name) 1739f57b05edSJiri Olsa vmlinux_name = machine__mmap_name(machine, bf, 1740f57b05edSJiri Olsa sizeof(bf)); 1741f57b05edSJiri Olsa 1742f57b05edSJiri Olsa kernel = dso__kernel_findnew(machine, vmlinux_name, 1743f57b05edSJiri Olsa "[guest.kernel]", 1744f57b05edSJiri Olsa DSO_TYPE_GUEST_KERNEL); 17458d92c02aSArnaldo Carvalho de Melo } 1746cd84c2acSFrederic Weisbecker 1747f57b05edSJiri Olsa if (kernel != NULL && (!kernel->has_build_id)) 1748aeafcbafSArnaldo Carvalho de Melo dso__read_running_kernel_build_id(kernel, machine); 1749f57b05edSJiri Olsa 1750f1dfa0b1SArnaldo Carvalho de Melo return kernel; 1751f1dfa0b1SArnaldo Carvalho de Melo } 1752f1dfa0b1SArnaldo Carvalho de Melo 1753d214afbdSMing Lei struct process_args { 1754d214afbdSMing Lei u64 start; 1755d214afbdSMing Lei }; 1756d214afbdSMing Lei 1757d214afbdSMing Lei static int symbol__in_kernel(void *arg, const char *name, 1758*1d037ca1SIrina Tirdea char type __maybe_unused, u64 start) 1759d214afbdSMing Lei { 1760d214afbdSMing Lei struct process_args *args = arg; 1761d214afbdSMing Lei 1762d214afbdSMing Lei if (strchr(name, '[')) 1763d214afbdSMing Lei return 0; 1764d214afbdSMing Lei 1765d214afbdSMing Lei args->start = start; 1766d214afbdSMing Lei return 1; 1767d214afbdSMing Lei } 1768d214afbdSMing Lei 1769d214afbdSMing Lei /* Figure out the start address of kernel map from /proc/kallsyms */ 1770d214afbdSMing Lei static u64 machine__get_kernel_start_addr(struct machine *machine) 1771d214afbdSMing Lei { 1772d214afbdSMing Lei const char *filename; 1773d214afbdSMing Lei char path[PATH_MAX]; 1774d214afbdSMing Lei struct process_args args; 1775d214afbdSMing Lei 1776d214afbdSMing Lei if (machine__is_host(machine)) { 1777d214afbdSMing Lei filename = "/proc/kallsyms"; 1778d214afbdSMing Lei } else { 1779d214afbdSMing Lei if (machine__is_default_guest(machine)) 1780d214afbdSMing Lei filename = (char *)symbol_conf.default_guest_kallsyms; 1781d214afbdSMing Lei else { 1782d214afbdSMing Lei sprintf(path, "%s/proc/kallsyms", machine->root_dir); 1783d214afbdSMing Lei filename = path; 1784d214afbdSMing Lei } 1785d214afbdSMing Lei } 1786d214afbdSMing Lei 1787ec80fde7SArnaldo Carvalho de Melo if (symbol__restricted_filename(filename, "/proc/kallsyms")) 1788ec80fde7SArnaldo Carvalho de Melo return 0; 1789ec80fde7SArnaldo Carvalho de Melo 1790d214afbdSMing Lei if (kallsyms__parse(filename, &args, symbol__in_kernel) <= 0) 1791d214afbdSMing Lei return 0; 1792d214afbdSMing Lei 1793d214afbdSMing Lei return args.start; 1794d214afbdSMing Lei } 1795d214afbdSMing Lei 1796aeafcbafSArnaldo Carvalho de Melo int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel) 1797f1dfa0b1SArnaldo Carvalho de Melo { 1798de176489SArnaldo Carvalho de Melo enum map_type type; 1799aeafcbafSArnaldo Carvalho de Melo u64 start = machine__get_kernel_start_addr(machine); 1800f1dfa0b1SArnaldo Carvalho de Melo 1801de176489SArnaldo Carvalho de Melo for (type = 0; type < MAP__NR_TYPES; ++type) { 18029de89fe7SArnaldo Carvalho de Melo struct kmap *kmap; 18039de89fe7SArnaldo Carvalho de Melo 1804aeafcbafSArnaldo Carvalho de Melo machine->vmlinux_maps[type] = map__new2(start, kernel, type); 1805aeafcbafSArnaldo Carvalho de Melo if (machine->vmlinux_maps[type] == NULL) 1806f1dfa0b1SArnaldo Carvalho de Melo return -1; 1807f1dfa0b1SArnaldo Carvalho de Melo 1808aeafcbafSArnaldo Carvalho de Melo machine->vmlinux_maps[type]->map_ip = 1809aeafcbafSArnaldo Carvalho de Melo machine->vmlinux_maps[type]->unmap_ip = 1810aeafcbafSArnaldo Carvalho de Melo identity__map_ip; 1811aeafcbafSArnaldo Carvalho de Melo kmap = map__kmap(machine->vmlinux_maps[type]); 1812aeafcbafSArnaldo Carvalho de Melo kmap->kmaps = &machine->kmaps; 1813aeafcbafSArnaldo Carvalho de Melo map_groups__insert(&machine->kmaps, 1814aeafcbafSArnaldo Carvalho de Melo machine->vmlinux_maps[type]); 1815f1dfa0b1SArnaldo Carvalho de Melo } 1816f1dfa0b1SArnaldo Carvalho de Melo 1817f1dfa0b1SArnaldo Carvalho de Melo return 0; 18182446042cSArnaldo Carvalho de Melo } 18192446042cSArnaldo Carvalho de Melo 1820aeafcbafSArnaldo Carvalho de Melo void machine__destroy_kernel_maps(struct machine *machine) 1821076c6e45SArnaldo Carvalho de Melo { 1822076c6e45SArnaldo Carvalho de Melo enum map_type type; 1823076c6e45SArnaldo Carvalho de Melo 1824076c6e45SArnaldo Carvalho de Melo for (type = 0; type < MAP__NR_TYPES; ++type) { 1825076c6e45SArnaldo Carvalho de Melo struct kmap *kmap; 1826076c6e45SArnaldo Carvalho de Melo 1827aeafcbafSArnaldo Carvalho de Melo if (machine->vmlinux_maps[type] == NULL) 1828076c6e45SArnaldo Carvalho de Melo continue; 1829076c6e45SArnaldo Carvalho de Melo 1830aeafcbafSArnaldo Carvalho de Melo kmap = map__kmap(machine->vmlinux_maps[type]); 1831aeafcbafSArnaldo Carvalho de Melo map_groups__remove(&machine->kmaps, 1832aeafcbafSArnaldo Carvalho de Melo machine->vmlinux_maps[type]); 1833076c6e45SArnaldo Carvalho de Melo if (kmap->ref_reloc_sym) { 1834076c6e45SArnaldo Carvalho de Melo /* 1835076c6e45SArnaldo Carvalho de Melo * ref_reloc_sym is shared among all maps, so free just 1836076c6e45SArnaldo Carvalho de Melo * on one of them. 1837076c6e45SArnaldo Carvalho de Melo */ 1838076c6e45SArnaldo Carvalho de Melo if (type == MAP__FUNCTION) { 1839076c6e45SArnaldo Carvalho de Melo free((char *)kmap->ref_reloc_sym->name); 1840076c6e45SArnaldo Carvalho de Melo kmap->ref_reloc_sym->name = NULL; 1841076c6e45SArnaldo Carvalho de Melo free(kmap->ref_reloc_sym); 1842076c6e45SArnaldo Carvalho de Melo } 1843076c6e45SArnaldo Carvalho de Melo kmap->ref_reloc_sym = NULL; 1844076c6e45SArnaldo Carvalho de Melo } 1845076c6e45SArnaldo Carvalho de Melo 1846aeafcbafSArnaldo Carvalho de Melo map__delete(machine->vmlinux_maps[type]); 1847aeafcbafSArnaldo Carvalho de Melo machine->vmlinux_maps[type] = NULL; 1848076c6e45SArnaldo Carvalho de Melo } 1849076c6e45SArnaldo Carvalho de Melo } 1850076c6e45SArnaldo Carvalho de Melo 1851aeafcbafSArnaldo Carvalho de Melo int machine__create_kernel_maps(struct machine *machine) 18525c0541d5SArnaldo Carvalho de Melo { 1853f57b05edSJiri Olsa struct dso *kernel = machine__get_kernel(machine); 18545c0541d5SArnaldo Carvalho de Melo 18555c0541d5SArnaldo Carvalho de Melo if (kernel == NULL || 1856aeafcbafSArnaldo Carvalho de Melo __machine__create_kernel_maps(machine, kernel) < 0) 18575c0541d5SArnaldo Carvalho de Melo return -1; 18585c0541d5SArnaldo Carvalho de Melo 1859f51304d3SDavid Ahern if (symbol_conf.use_modules && machine__create_modules(machine) < 0) { 1860f51304d3SDavid Ahern if (machine__is_host(machine)) 1861f51304d3SDavid Ahern pr_debug("Problems creating module maps, " 1862f51304d3SDavid Ahern "continuing anyway...\n"); 1863f51304d3SDavid Ahern else 1864f51304d3SDavid Ahern pr_debug("Problems creating module maps for guest %d, " 1865f51304d3SDavid Ahern "continuing anyway...\n", machine->pid); 1866f51304d3SDavid Ahern } 1867f51304d3SDavid Ahern 18685c0541d5SArnaldo Carvalho de Melo /* 18695c0541d5SArnaldo Carvalho de Melo * Now that we have all the maps created, just set the ->end of them: 18705c0541d5SArnaldo Carvalho de Melo */ 1871aeafcbafSArnaldo Carvalho de Melo map_groups__fixup_end(&machine->kmaps); 18725c0541d5SArnaldo Carvalho de Melo return 0; 18735c0541d5SArnaldo Carvalho de Melo } 18745c0541d5SArnaldo Carvalho de Melo 1875cc612d81SArnaldo Carvalho de Melo static void vmlinux_path__exit(void) 18762446042cSArnaldo Carvalho de Melo { 1877cc612d81SArnaldo Carvalho de Melo while (--vmlinux_path__nr_entries >= 0) { 1878cc612d81SArnaldo Carvalho de Melo free(vmlinux_path[vmlinux_path__nr_entries]); 1879cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = NULL; 1880cc612d81SArnaldo Carvalho de Melo } 1881cc612d81SArnaldo Carvalho de Melo 1882cc612d81SArnaldo Carvalho de Melo free(vmlinux_path); 1883cc612d81SArnaldo Carvalho de Melo vmlinux_path = NULL; 1884cc612d81SArnaldo Carvalho de Melo } 1885cc612d81SArnaldo Carvalho de Melo 1886cc612d81SArnaldo Carvalho de Melo static int vmlinux_path__init(void) 1887cc612d81SArnaldo Carvalho de Melo { 1888cc612d81SArnaldo Carvalho de Melo struct utsname uts; 1889cc612d81SArnaldo Carvalho de Melo char bf[PATH_MAX]; 1890cc612d81SArnaldo Carvalho de Melo 1891cc612d81SArnaldo Carvalho de Melo vmlinux_path = malloc(sizeof(char *) * 5); 1892cc612d81SArnaldo Carvalho de Melo if (vmlinux_path == NULL) 1893cc612d81SArnaldo Carvalho de Melo return -1; 1894cc612d81SArnaldo Carvalho de Melo 1895cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup("vmlinux"); 1896cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 1897cc612d81SArnaldo Carvalho de Melo goto out_fail; 1898cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 1899cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup("/boot/vmlinux"); 1900cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 1901cc612d81SArnaldo Carvalho de Melo goto out_fail; 1902cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 1903ec5761eaSDavid Ahern 1904ec5761eaSDavid Ahern /* only try running kernel version if no symfs was given */ 1905ec5761eaSDavid Ahern if (symbol_conf.symfs[0] != 0) 1906ec5761eaSDavid Ahern return 0; 1907ec5761eaSDavid Ahern 1908ec5761eaSDavid Ahern if (uname(&uts) < 0) 1909ec5761eaSDavid Ahern return -1; 1910ec5761eaSDavid Ahern 1911cc612d81SArnaldo Carvalho de Melo snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", uts.release); 1912cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); 1913cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 1914cc612d81SArnaldo Carvalho de Melo goto out_fail; 1915cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 1916cc612d81SArnaldo Carvalho de Melo snprintf(bf, sizeof(bf), "/lib/modules/%s/build/vmlinux", uts.release); 1917cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); 1918cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 1919cc612d81SArnaldo Carvalho de Melo goto out_fail; 1920cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 1921cc612d81SArnaldo Carvalho de Melo snprintf(bf, sizeof(bf), "/usr/lib/debug/lib/modules/%s/vmlinux", 1922cc612d81SArnaldo Carvalho de Melo uts.release); 1923cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); 1924cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 1925cc612d81SArnaldo Carvalho de Melo goto out_fail; 1926cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 1927cc612d81SArnaldo Carvalho de Melo 1928cc612d81SArnaldo Carvalho de Melo return 0; 1929cc612d81SArnaldo Carvalho de Melo 1930cc612d81SArnaldo Carvalho de Melo out_fail: 1931cc612d81SArnaldo Carvalho de Melo vmlinux_path__exit(); 1932cc612d81SArnaldo Carvalho de Melo return -1; 1933cc612d81SArnaldo Carvalho de Melo } 1934cc612d81SArnaldo Carvalho de Melo 1935aeafcbafSArnaldo Carvalho de Melo size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp) 1936b0a9ab62SArnaldo Carvalho de Melo { 1937b0a9ab62SArnaldo Carvalho de Melo int i; 1938b0a9ab62SArnaldo Carvalho de Melo size_t printed = 0; 1939aeafcbafSArnaldo Carvalho de Melo struct dso *kdso = machine->vmlinux_maps[MAP__FUNCTION]->dso; 19405ad90e4eSArnaldo Carvalho de Melo 19415ad90e4eSArnaldo Carvalho de Melo if (kdso->has_build_id) { 19425ad90e4eSArnaldo Carvalho de Melo char filename[PATH_MAX]; 19435ad90e4eSArnaldo Carvalho de Melo if (dso__build_id_filename(kdso, filename, sizeof(filename))) 19445ad90e4eSArnaldo Carvalho de Melo printed += fprintf(fp, "[0] %s\n", filename); 19455ad90e4eSArnaldo Carvalho de Melo } 1946b0a9ab62SArnaldo Carvalho de Melo 1947b0a9ab62SArnaldo Carvalho de Melo for (i = 0; i < vmlinux_path__nr_entries; ++i) 19485ad90e4eSArnaldo Carvalho de Melo printed += fprintf(fp, "[%d] %s\n", 19495ad90e4eSArnaldo Carvalho de Melo i + kdso->has_build_id, vmlinux_path[i]); 1950b0a9ab62SArnaldo Carvalho de Melo 1951b0a9ab62SArnaldo Carvalho de Melo return printed; 1952b0a9ab62SArnaldo Carvalho de Melo } 1953b0a9ab62SArnaldo Carvalho de Melo 1954655000e7SArnaldo Carvalho de Melo static int setup_list(struct strlist **list, const char *list_str, 1955655000e7SArnaldo Carvalho de Melo const char *list_name) 1956655000e7SArnaldo Carvalho de Melo { 1957655000e7SArnaldo Carvalho de Melo if (list_str == NULL) 1958655000e7SArnaldo Carvalho de Melo return 0; 1959655000e7SArnaldo Carvalho de Melo 1960655000e7SArnaldo Carvalho de Melo *list = strlist__new(true, list_str); 1961655000e7SArnaldo Carvalho de Melo if (!*list) { 1962655000e7SArnaldo Carvalho de Melo pr_err("problems parsing %s list\n", list_name); 1963655000e7SArnaldo Carvalho de Melo return -1; 1964655000e7SArnaldo Carvalho de Melo } 1965655000e7SArnaldo Carvalho de Melo return 0; 1966655000e7SArnaldo Carvalho de Melo } 1967655000e7SArnaldo Carvalho de Melo 1968ec80fde7SArnaldo Carvalho de Melo static bool symbol__read_kptr_restrict(void) 1969ec80fde7SArnaldo Carvalho de Melo { 1970ec80fde7SArnaldo Carvalho de Melo bool value = false; 1971ec80fde7SArnaldo Carvalho de Melo 1972ec80fde7SArnaldo Carvalho de Melo if (geteuid() != 0) { 1973ec80fde7SArnaldo Carvalho de Melo FILE *fp = fopen("/proc/sys/kernel/kptr_restrict", "r"); 1974ec80fde7SArnaldo Carvalho de Melo if (fp != NULL) { 1975ec80fde7SArnaldo Carvalho de Melo char line[8]; 1976ec80fde7SArnaldo Carvalho de Melo 1977ec80fde7SArnaldo Carvalho de Melo if (fgets(line, sizeof(line), fp) != NULL) 1978ec80fde7SArnaldo Carvalho de Melo value = atoi(line) != 0; 1979ec80fde7SArnaldo Carvalho de Melo 1980ec80fde7SArnaldo Carvalho de Melo fclose(fp); 1981ec80fde7SArnaldo Carvalho de Melo } 1982ec80fde7SArnaldo Carvalho de Melo } 1983ec80fde7SArnaldo Carvalho de Melo 1984ec80fde7SArnaldo Carvalho de Melo return value; 1985ec80fde7SArnaldo Carvalho de Melo } 1986ec80fde7SArnaldo Carvalho de Melo 198775be6cf4SArnaldo Carvalho de Melo int symbol__init(void) 1988cc612d81SArnaldo Carvalho de Melo { 1989ec5761eaSDavid Ahern const char *symfs; 1990ec5761eaSDavid Ahern 199185e00b55SJovi Zhang if (symbol_conf.initialized) 199285e00b55SJovi Zhang return 0; 199385e00b55SJovi Zhang 19949ac3e487SIrina Tirdea symbol_conf.priv_size = PERF_ALIGN(symbol_conf.priv_size, sizeof(u64)); 19954d439517SDavid S. Miller 1996166ccc9cSNamhyung Kim symbol__elf_init(); 1997166ccc9cSNamhyung Kim 199875be6cf4SArnaldo Carvalho de Melo if (symbol_conf.sort_by_name) 199975be6cf4SArnaldo Carvalho de Melo symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) - 200079406cd7SArnaldo Carvalho de Melo sizeof(struct symbol)); 2001b32d133aSArnaldo Carvalho de Melo 200275be6cf4SArnaldo Carvalho de Melo if (symbol_conf.try_vmlinux_path && vmlinux_path__init() < 0) 2003cc612d81SArnaldo Carvalho de Melo return -1; 2004cc612d81SArnaldo Carvalho de Melo 2005c410a338SArnaldo Carvalho de Melo if (symbol_conf.field_sep && *symbol_conf.field_sep == '.') { 2006c410a338SArnaldo Carvalho de Melo pr_err("'.' is the only non valid --field-separator argument\n"); 2007c410a338SArnaldo Carvalho de Melo return -1; 2008c410a338SArnaldo Carvalho de Melo } 2009c410a338SArnaldo Carvalho de Melo 2010655000e7SArnaldo Carvalho de Melo if (setup_list(&symbol_conf.dso_list, 2011655000e7SArnaldo Carvalho de Melo symbol_conf.dso_list_str, "dso") < 0) 2012655000e7SArnaldo Carvalho de Melo return -1; 2013655000e7SArnaldo Carvalho de Melo 2014655000e7SArnaldo Carvalho de Melo if (setup_list(&symbol_conf.comm_list, 2015655000e7SArnaldo Carvalho de Melo symbol_conf.comm_list_str, "comm") < 0) 2016655000e7SArnaldo Carvalho de Melo goto out_free_dso_list; 2017655000e7SArnaldo Carvalho de Melo 2018655000e7SArnaldo Carvalho de Melo if (setup_list(&symbol_conf.sym_list, 2019655000e7SArnaldo Carvalho de Melo symbol_conf.sym_list_str, "symbol") < 0) 2020655000e7SArnaldo Carvalho de Melo goto out_free_comm_list; 2021655000e7SArnaldo Carvalho de Melo 2022ec5761eaSDavid Ahern /* 2023ec5761eaSDavid Ahern * A path to symbols of "/" is identical to "" 2024ec5761eaSDavid Ahern * reset here for simplicity. 2025ec5761eaSDavid Ahern */ 2026ec5761eaSDavid Ahern symfs = realpath(symbol_conf.symfs, NULL); 2027ec5761eaSDavid Ahern if (symfs == NULL) 2028ec5761eaSDavid Ahern symfs = symbol_conf.symfs; 2029ec5761eaSDavid Ahern if (strcmp(symfs, "/") == 0) 2030ec5761eaSDavid Ahern symbol_conf.symfs = ""; 2031ec5761eaSDavid Ahern if (symfs != symbol_conf.symfs) 2032ec5761eaSDavid Ahern free((void *)symfs); 2033ec5761eaSDavid Ahern 2034ec80fde7SArnaldo Carvalho de Melo symbol_conf.kptr_restrict = symbol__read_kptr_restrict(); 2035ec80fde7SArnaldo Carvalho de Melo 203685e00b55SJovi Zhang symbol_conf.initialized = true; 20374aa65636SArnaldo Carvalho de Melo return 0; 2038655000e7SArnaldo Carvalho de Melo 2039655000e7SArnaldo Carvalho de Melo out_free_comm_list: 2040655000e7SArnaldo Carvalho de Melo strlist__delete(symbol_conf.comm_list); 2041d74c896bSNamhyung Kim out_free_dso_list: 2042d74c896bSNamhyung Kim strlist__delete(symbol_conf.dso_list); 2043655000e7SArnaldo Carvalho de Melo return -1; 2044cc612d81SArnaldo Carvalho de Melo } 2045cc612d81SArnaldo Carvalho de Melo 2046d65a458bSArnaldo Carvalho de Melo void symbol__exit(void) 2047d65a458bSArnaldo Carvalho de Melo { 204885e00b55SJovi Zhang if (!symbol_conf.initialized) 204985e00b55SJovi Zhang return; 2050d65a458bSArnaldo Carvalho de Melo strlist__delete(symbol_conf.sym_list); 2051d65a458bSArnaldo Carvalho de Melo strlist__delete(symbol_conf.dso_list); 2052d65a458bSArnaldo Carvalho de Melo strlist__delete(symbol_conf.comm_list); 2053d65a458bSArnaldo Carvalho de Melo vmlinux_path__exit(); 2054d65a458bSArnaldo Carvalho de Melo symbol_conf.sym_list = symbol_conf.dso_list = symbol_conf.comm_list = NULL; 205585e00b55SJovi Zhang symbol_conf.initialized = false; 2056d65a458bSArnaldo Carvalho de Melo } 2057d65a458bSArnaldo Carvalho de Melo 2058aeafcbafSArnaldo Carvalho de Melo int machines__create_kernel_maps(struct rb_root *machines, pid_t pid) 20594aa65636SArnaldo Carvalho de Melo { 2060aeafcbafSArnaldo Carvalho de Melo struct machine *machine = machines__findnew(machines, pid); 20619de89fe7SArnaldo Carvalho de Melo 206223346f21SArnaldo Carvalho de Melo if (machine == NULL) 2063a1645ce1SZhang, Yanmin return -1; 20644aa65636SArnaldo Carvalho de Melo 20655c0541d5SArnaldo Carvalho de Melo return machine__create_kernel_maps(machine); 2066cd84c2acSFrederic Weisbecker } 20675aab621bSArnaldo Carvalho de Melo 20685aab621bSArnaldo Carvalho de Melo static int hex(char ch) 20695aab621bSArnaldo Carvalho de Melo { 20705aab621bSArnaldo Carvalho de Melo if ((ch >= '0') && (ch <= '9')) 20715aab621bSArnaldo Carvalho de Melo return ch - '0'; 20725aab621bSArnaldo Carvalho de Melo if ((ch >= 'a') && (ch <= 'f')) 20735aab621bSArnaldo Carvalho de Melo return ch - 'a' + 10; 20745aab621bSArnaldo Carvalho de Melo if ((ch >= 'A') && (ch <= 'F')) 20755aab621bSArnaldo Carvalho de Melo return ch - 'A' + 10; 20765aab621bSArnaldo Carvalho de Melo return -1; 20775aab621bSArnaldo Carvalho de Melo } 20785aab621bSArnaldo Carvalho de Melo 20795aab621bSArnaldo Carvalho de Melo /* 20805aab621bSArnaldo Carvalho de Melo * While we find nice hex chars, build a long_val. 20815aab621bSArnaldo Carvalho de Melo * Return number of chars processed. 20825aab621bSArnaldo Carvalho de Melo */ 20835aab621bSArnaldo Carvalho de Melo int hex2u64(const char *ptr, u64 *long_val) 20845aab621bSArnaldo Carvalho de Melo { 20855aab621bSArnaldo Carvalho de Melo const char *p = ptr; 20865aab621bSArnaldo Carvalho de Melo *long_val = 0; 20875aab621bSArnaldo Carvalho de Melo 20885aab621bSArnaldo Carvalho de Melo while (*p) { 20895aab621bSArnaldo Carvalho de Melo const int hex_val = hex(*p); 20905aab621bSArnaldo Carvalho de Melo 20915aab621bSArnaldo Carvalho de Melo if (hex_val < 0) 20925aab621bSArnaldo Carvalho de Melo break; 20935aab621bSArnaldo Carvalho de Melo 20945aab621bSArnaldo Carvalho de Melo *long_val = (*long_val << 4) | hex_val; 20955aab621bSArnaldo Carvalho de Melo p++; 20965aab621bSArnaldo Carvalho de Melo } 20975aab621bSArnaldo Carvalho de Melo 20985aab621bSArnaldo Carvalho de Melo return p - ptr; 20995aab621bSArnaldo Carvalho de Melo } 21005aab621bSArnaldo Carvalho de Melo 21015aab621bSArnaldo Carvalho de Melo char *strxfrchar(char *s, char from, char to) 21025aab621bSArnaldo Carvalho de Melo { 21035aab621bSArnaldo Carvalho de Melo char *p = s; 21045aab621bSArnaldo Carvalho de Melo 21055aab621bSArnaldo Carvalho de Melo while ((p = strchr(p, from)) != NULL) 21065aab621bSArnaldo Carvalho de Melo *p++ = to; 21075aab621bSArnaldo Carvalho de Melo 21085aab621bSArnaldo Carvalho de Melo return s; 21095aab621bSArnaldo Carvalho de Melo } 2110a1645ce1SZhang, Yanmin 2111aeafcbafSArnaldo Carvalho de Melo int machines__create_guest_kernel_maps(struct rb_root *machines) 2112a1645ce1SZhang, Yanmin { 2113a1645ce1SZhang, Yanmin int ret = 0; 2114a1645ce1SZhang, Yanmin struct dirent **namelist = NULL; 2115a1645ce1SZhang, Yanmin int i, items = 0; 2116a1645ce1SZhang, Yanmin char path[PATH_MAX]; 2117a1645ce1SZhang, Yanmin pid_t pid; 2118347ed990SDavid Ahern char *endp; 2119a1645ce1SZhang, Yanmin 2120a1645ce1SZhang, Yanmin if (symbol_conf.default_guest_vmlinux_name || 2121a1645ce1SZhang, Yanmin symbol_conf.default_guest_modules || 2122a1645ce1SZhang, Yanmin symbol_conf.default_guest_kallsyms) { 2123aeafcbafSArnaldo Carvalho de Melo machines__create_kernel_maps(machines, DEFAULT_GUEST_KERNEL_ID); 2124a1645ce1SZhang, Yanmin } 2125a1645ce1SZhang, Yanmin 2126a1645ce1SZhang, Yanmin if (symbol_conf.guestmount) { 2127a1645ce1SZhang, Yanmin items = scandir(symbol_conf.guestmount, &namelist, NULL, NULL); 2128a1645ce1SZhang, Yanmin if (items <= 0) 2129a1645ce1SZhang, Yanmin return -ENOENT; 2130a1645ce1SZhang, Yanmin for (i = 0; i < items; i++) { 2131a1645ce1SZhang, Yanmin if (!isdigit(namelist[i]->d_name[0])) { 2132a1645ce1SZhang, Yanmin /* Filter out . and .. */ 2133a1645ce1SZhang, Yanmin continue; 2134a1645ce1SZhang, Yanmin } 2135347ed990SDavid Ahern pid = (pid_t)strtol(namelist[i]->d_name, &endp, 10); 2136347ed990SDavid Ahern if ((*endp != '\0') || 2137347ed990SDavid Ahern (endp == namelist[i]->d_name) || 2138347ed990SDavid Ahern (errno == ERANGE)) { 2139347ed990SDavid Ahern pr_debug("invalid directory (%s). Skipping.\n", 2140347ed990SDavid Ahern namelist[i]->d_name); 2141347ed990SDavid Ahern continue; 2142347ed990SDavid Ahern } 2143a1645ce1SZhang, Yanmin sprintf(path, "%s/%s/proc/kallsyms", 2144a1645ce1SZhang, Yanmin symbol_conf.guestmount, 2145a1645ce1SZhang, Yanmin namelist[i]->d_name); 2146a1645ce1SZhang, Yanmin ret = access(path, R_OK); 2147a1645ce1SZhang, Yanmin if (ret) { 2148a1645ce1SZhang, Yanmin pr_debug("Can't access file %s\n", path); 2149a1645ce1SZhang, Yanmin goto failure; 2150a1645ce1SZhang, Yanmin } 2151aeafcbafSArnaldo Carvalho de Melo machines__create_kernel_maps(machines, pid); 2152a1645ce1SZhang, Yanmin } 2153a1645ce1SZhang, Yanmin failure: 2154a1645ce1SZhang, Yanmin free(namelist); 2155a1645ce1SZhang, Yanmin } 2156a1645ce1SZhang, Yanmin 2157a1645ce1SZhang, Yanmin return ret; 2158a1645ce1SZhang, Yanmin } 21595c0541d5SArnaldo Carvalho de Melo 2160aeafcbafSArnaldo Carvalho de Melo void machines__destroy_guest_kernel_maps(struct rb_root *machines) 2161076c6e45SArnaldo Carvalho de Melo { 2162aeafcbafSArnaldo Carvalho de Melo struct rb_node *next = rb_first(machines); 2163076c6e45SArnaldo Carvalho de Melo 2164076c6e45SArnaldo Carvalho de Melo while (next) { 2165076c6e45SArnaldo Carvalho de Melo struct machine *pos = rb_entry(next, struct machine, rb_node); 2166076c6e45SArnaldo Carvalho de Melo 2167076c6e45SArnaldo Carvalho de Melo next = rb_next(&pos->rb_node); 2168aeafcbafSArnaldo Carvalho de Melo rb_erase(&pos->rb_node, machines); 2169076c6e45SArnaldo Carvalho de Melo machine__delete(pos); 2170076c6e45SArnaldo Carvalho de Melo } 2171076c6e45SArnaldo Carvalho de Melo } 2172076c6e45SArnaldo Carvalho de Melo 2173aeafcbafSArnaldo Carvalho de Melo int machine__load_kallsyms(struct machine *machine, const char *filename, 21745c0541d5SArnaldo Carvalho de Melo enum map_type type, symbol_filter_t filter) 21755c0541d5SArnaldo Carvalho de Melo { 2176aeafcbafSArnaldo Carvalho de Melo struct map *map = machine->vmlinux_maps[type]; 21775c0541d5SArnaldo Carvalho de Melo int ret = dso__load_kallsyms(map->dso, filename, map, filter); 21785c0541d5SArnaldo Carvalho de Melo 21795c0541d5SArnaldo Carvalho de Melo if (ret > 0) { 21805c0541d5SArnaldo Carvalho de Melo dso__set_loaded(map->dso, type); 21815c0541d5SArnaldo Carvalho de Melo /* 21825c0541d5SArnaldo Carvalho de Melo * Since /proc/kallsyms will have multiple sessions for the 21835c0541d5SArnaldo Carvalho de Melo * kernel, with modules between them, fixup the end of all 21845c0541d5SArnaldo Carvalho de Melo * sections. 21855c0541d5SArnaldo Carvalho de Melo */ 2186aeafcbafSArnaldo Carvalho de Melo __map_groups__fixup_end(&machine->kmaps, type); 21875c0541d5SArnaldo Carvalho de Melo } 21885c0541d5SArnaldo Carvalho de Melo 21895c0541d5SArnaldo Carvalho de Melo return ret; 21905c0541d5SArnaldo Carvalho de Melo } 21915c0541d5SArnaldo Carvalho de Melo 2192aeafcbafSArnaldo Carvalho de Melo int machine__load_vmlinux_path(struct machine *machine, enum map_type type, 21935c0541d5SArnaldo Carvalho de Melo symbol_filter_t filter) 21945c0541d5SArnaldo Carvalho de Melo { 2195aeafcbafSArnaldo Carvalho de Melo struct map *map = machine->vmlinux_maps[type]; 21965c0541d5SArnaldo Carvalho de Melo int ret = dso__load_vmlinux_path(map->dso, map, filter); 21975c0541d5SArnaldo Carvalho de Melo 21985c0541d5SArnaldo Carvalho de Melo if (ret > 0) { 21995c0541d5SArnaldo Carvalho de Melo dso__set_loaded(map->dso, type); 22005c0541d5SArnaldo Carvalho de Melo map__reloc_vmlinux(map); 22015c0541d5SArnaldo Carvalho de Melo } 22025c0541d5SArnaldo Carvalho de Melo 22035c0541d5SArnaldo Carvalho de Melo return ret; 22045c0541d5SArnaldo Carvalho de Melo } 2205225466f1SSrikar Dronamraju 2206225466f1SSrikar Dronamraju struct map *dso__new_map(const char *name) 2207225466f1SSrikar Dronamraju { 2208378474e4SSrikar Dronamraju struct map *map = NULL; 2209225466f1SSrikar Dronamraju struct dso *dso = dso__new(name); 2210378474e4SSrikar Dronamraju 2211378474e4SSrikar Dronamraju if (dso) 2212378474e4SSrikar Dronamraju map = map__new2(0, dso, MAP__FUNCTION); 2213225466f1SSrikar Dronamraju 2214225466f1SSrikar Dronamraju return map; 2215225466f1SSrikar Dronamraju } 2216949d160bSJiri Olsa 2217949d160bSJiri Olsa static int open_dso(struct dso *dso, struct machine *machine) 2218949d160bSJiri Olsa { 2219949d160bSJiri Olsa char *root_dir = (char *) ""; 2220949d160bSJiri Olsa char *name; 2221949d160bSJiri Olsa int fd; 2222949d160bSJiri Olsa 2223949d160bSJiri Olsa name = malloc(PATH_MAX); 2224949d160bSJiri Olsa if (!name) 2225949d160bSJiri Olsa return -ENOMEM; 2226949d160bSJiri Olsa 2227949d160bSJiri Olsa if (machine) 2228949d160bSJiri Olsa root_dir = machine->root_dir; 2229949d160bSJiri Olsa 2230949d160bSJiri Olsa if (dso__binary_type_file(dso, dso->data_type, 2231949d160bSJiri Olsa root_dir, name, PATH_MAX)) { 2232949d160bSJiri Olsa free(name); 2233949d160bSJiri Olsa return -EINVAL; 2234949d160bSJiri Olsa } 2235949d160bSJiri Olsa 2236949d160bSJiri Olsa fd = open(name, O_RDONLY); 2237949d160bSJiri Olsa free(name); 2238949d160bSJiri Olsa return fd; 2239949d160bSJiri Olsa } 2240949d160bSJiri Olsa 2241949d160bSJiri Olsa int dso__data_fd(struct dso *dso, struct machine *machine) 2242949d160bSJiri Olsa { 2243949d160bSJiri Olsa int i = 0; 2244949d160bSJiri Olsa 2245949d160bSJiri Olsa if (dso->data_type != DSO_BINARY_TYPE__NOT_FOUND) 2246949d160bSJiri Olsa return open_dso(dso, machine); 2247949d160bSJiri Olsa 2248949d160bSJiri Olsa do { 2249949d160bSJiri Olsa int fd; 2250949d160bSJiri Olsa 2251949d160bSJiri Olsa dso->data_type = binary_type_data[i++]; 2252949d160bSJiri Olsa 2253949d160bSJiri Olsa fd = open_dso(dso, machine); 2254949d160bSJiri Olsa if (fd >= 0) 2255949d160bSJiri Olsa return fd; 2256949d160bSJiri Olsa 2257949d160bSJiri Olsa } while (dso->data_type != DSO_BINARY_TYPE__NOT_FOUND); 2258949d160bSJiri Olsa 2259949d160bSJiri Olsa return -EINVAL; 2260949d160bSJiri Olsa } 2261949d160bSJiri Olsa 22624dff624aSJiri Olsa static void 22634dff624aSJiri Olsa dso_cache__free(struct rb_root *root) 2264949d160bSJiri Olsa { 22654dff624aSJiri Olsa struct rb_node *next = rb_first(root); 22664dff624aSJiri Olsa 22674dff624aSJiri Olsa while (next) { 22684dff624aSJiri Olsa struct dso_cache *cache; 22694dff624aSJiri Olsa 22704dff624aSJiri Olsa cache = rb_entry(next, struct dso_cache, rb_node); 22714dff624aSJiri Olsa next = rb_next(&cache->rb_node); 22724dff624aSJiri Olsa rb_erase(&cache->rb_node, root); 22734dff624aSJiri Olsa free(cache); 22744dff624aSJiri Olsa } 2275949d160bSJiri Olsa } 2276949d160bSJiri Olsa 22774dff624aSJiri Olsa static struct dso_cache* 22784dff624aSJiri Olsa dso_cache__find(struct rb_root *root, u64 offset) 2279949d160bSJiri Olsa { 22804dff624aSJiri Olsa struct rb_node **p = &root->rb_node; 22814dff624aSJiri Olsa struct rb_node *parent = NULL; 22824dff624aSJiri Olsa struct dso_cache *cache; 22834dff624aSJiri Olsa 22844dff624aSJiri Olsa while (*p != NULL) { 22854dff624aSJiri Olsa u64 end; 22864dff624aSJiri Olsa 22874dff624aSJiri Olsa parent = *p; 22884dff624aSJiri Olsa cache = rb_entry(parent, struct dso_cache, rb_node); 22894dff624aSJiri Olsa end = cache->offset + DSO__DATA_CACHE_SIZE; 22904dff624aSJiri Olsa 22914dff624aSJiri Olsa if (offset < cache->offset) 22924dff624aSJiri Olsa p = &(*p)->rb_left; 22934dff624aSJiri Olsa else if (offset >= end) 22944dff624aSJiri Olsa p = &(*p)->rb_right; 22954dff624aSJiri Olsa else 22964dff624aSJiri Olsa return cache; 22974dff624aSJiri Olsa } 22984dff624aSJiri Olsa return NULL; 2299949d160bSJiri Olsa } 2300949d160bSJiri Olsa 23014dff624aSJiri Olsa static void 23024dff624aSJiri Olsa dso_cache__insert(struct rb_root *root, struct dso_cache *new) 23034dff624aSJiri Olsa { 23044dff624aSJiri Olsa struct rb_node **p = &root->rb_node; 23054dff624aSJiri Olsa struct rb_node *parent = NULL; 23064dff624aSJiri Olsa struct dso_cache *cache; 23074dff624aSJiri Olsa u64 offset = new->offset; 23084dff624aSJiri Olsa 23094dff624aSJiri Olsa while (*p != NULL) { 23104dff624aSJiri Olsa u64 end; 23114dff624aSJiri Olsa 23124dff624aSJiri Olsa parent = *p; 23134dff624aSJiri Olsa cache = rb_entry(parent, struct dso_cache, rb_node); 23144dff624aSJiri Olsa end = cache->offset + DSO__DATA_CACHE_SIZE; 23154dff624aSJiri Olsa 23164dff624aSJiri Olsa if (offset < cache->offset) 23174dff624aSJiri Olsa p = &(*p)->rb_left; 23184dff624aSJiri Olsa else if (offset >= end) 23194dff624aSJiri Olsa p = &(*p)->rb_right; 23204dff624aSJiri Olsa } 23214dff624aSJiri Olsa 23224dff624aSJiri Olsa rb_link_node(&new->rb_node, parent, p); 23234dff624aSJiri Olsa rb_insert_color(&new->rb_node, root); 23244dff624aSJiri Olsa } 23254dff624aSJiri Olsa 23264dff624aSJiri Olsa static ssize_t 23274dff624aSJiri Olsa dso_cache__memcpy(struct dso_cache *cache, u64 offset, 23284dff624aSJiri Olsa u8 *data, u64 size) 23294dff624aSJiri Olsa { 23304dff624aSJiri Olsa u64 cache_offset = offset - cache->offset; 23314dff624aSJiri Olsa u64 cache_size = min(cache->size - cache_offset, size); 23324dff624aSJiri Olsa 23334dff624aSJiri Olsa memcpy(data, cache->data + cache_offset, cache_size); 23344dff624aSJiri Olsa return cache_size; 23354dff624aSJiri Olsa } 23364dff624aSJiri Olsa 23374dff624aSJiri Olsa static ssize_t 23384dff624aSJiri Olsa dso_cache__read(struct dso *dso, struct machine *machine, 2339949d160bSJiri Olsa u64 offset, u8 *data, ssize_t size) 2340949d160bSJiri Olsa { 23414dff624aSJiri Olsa struct dso_cache *cache; 23424dff624aSJiri Olsa ssize_t ret; 2343949d160bSJiri Olsa int fd; 2344949d160bSJiri Olsa 2345949d160bSJiri Olsa fd = dso__data_fd(dso, machine); 2346949d160bSJiri Olsa if (fd < 0) 2347949d160bSJiri Olsa return -1; 2348949d160bSJiri Olsa 2349949d160bSJiri Olsa do { 23504dff624aSJiri Olsa u64 cache_offset; 23514dff624aSJiri Olsa 23524dff624aSJiri Olsa ret = -ENOMEM; 23534dff624aSJiri Olsa 23544dff624aSJiri Olsa cache = zalloc(sizeof(*cache) + DSO__DATA_CACHE_SIZE); 23554dff624aSJiri Olsa if (!cache) 2356949d160bSJiri Olsa break; 2357949d160bSJiri Olsa 23584dff624aSJiri Olsa cache_offset = offset & DSO__DATA_CACHE_MASK; 23594dff624aSJiri Olsa ret = -EINVAL; 23604dff624aSJiri Olsa 23614dff624aSJiri Olsa if (-1 == lseek(fd, cache_offset, SEEK_SET)) 2362949d160bSJiri Olsa break; 2363949d160bSJiri Olsa 23644dff624aSJiri Olsa ret = read(fd, cache->data, DSO__DATA_CACHE_SIZE); 23654dff624aSJiri Olsa if (ret <= 0) 23664dff624aSJiri Olsa break; 23674dff624aSJiri Olsa 23684dff624aSJiri Olsa cache->offset = cache_offset; 23694dff624aSJiri Olsa cache->size = ret; 23704dff624aSJiri Olsa dso_cache__insert(&dso->cache, cache); 23714dff624aSJiri Olsa 23724dff624aSJiri Olsa ret = dso_cache__memcpy(cache, offset, data, size); 2373949d160bSJiri Olsa 2374949d160bSJiri Olsa } while (0); 2375949d160bSJiri Olsa 23764dff624aSJiri Olsa if (ret <= 0) 23774dff624aSJiri Olsa free(cache); 23784dff624aSJiri Olsa 2379949d160bSJiri Olsa close(fd); 23804dff624aSJiri Olsa return ret; 23814dff624aSJiri Olsa } 23824dff624aSJiri Olsa 23834dff624aSJiri Olsa static ssize_t dso_cache_read(struct dso *dso, struct machine *machine, 23844dff624aSJiri Olsa u64 offset, u8 *data, ssize_t size) 23854dff624aSJiri Olsa { 23864dff624aSJiri Olsa struct dso_cache *cache; 23874dff624aSJiri Olsa 23884dff624aSJiri Olsa cache = dso_cache__find(&dso->cache, offset); 23894dff624aSJiri Olsa if (cache) 23904dff624aSJiri Olsa return dso_cache__memcpy(cache, offset, data, size); 23914dff624aSJiri Olsa else 23924dff624aSJiri Olsa return dso_cache__read(dso, machine, offset, data, size); 2393949d160bSJiri Olsa } 2394949d160bSJiri Olsa 2395949d160bSJiri Olsa ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine, 2396949d160bSJiri Olsa u64 offset, u8 *data, ssize_t size) 2397949d160bSJiri Olsa { 23984dff624aSJiri Olsa ssize_t r = 0; 23994dff624aSJiri Olsa u8 *p = data; 24004dff624aSJiri Olsa 24014dff624aSJiri Olsa do { 24024dff624aSJiri Olsa ssize_t ret; 24034dff624aSJiri Olsa 24044dff624aSJiri Olsa ret = dso_cache_read(dso, machine, offset, p, size); 24054dff624aSJiri Olsa if (ret < 0) 24064dff624aSJiri Olsa return ret; 24074dff624aSJiri Olsa 24084dff624aSJiri Olsa /* Reached EOF, return what we have. */ 24094dff624aSJiri Olsa if (!ret) 24104dff624aSJiri Olsa break; 24114dff624aSJiri Olsa 24124dff624aSJiri Olsa BUG_ON(ret > size); 24134dff624aSJiri Olsa 24144dff624aSJiri Olsa r += ret; 24154dff624aSJiri Olsa p += ret; 24164dff624aSJiri Olsa offset += ret; 24174dff624aSJiri Olsa size -= ret; 24184dff624aSJiri Olsa 24194dff624aSJiri Olsa } while (size); 24204dff624aSJiri Olsa 24214dff624aSJiri Olsa return r; 2422949d160bSJiri Olsa } 2423949d160bSJiri Olsa 2424949d160bSJiri Olsa ssize_t dso__data_read_addr(struct dso *dso, struct map *map, 2425949d160bSJiri Olsa struct machine *machine, u64 addr, 2426949d160bSJiri Olsa u8 *data, ssize_t size) 2427949d160bSJiri Olsa { 2428949d160bSJiri Olsa u64 offset = map->map_ip(map, addr); 2429949d160bSJiri Olsa return dso__data_read_offset(dso, machine, offset, data, size); 2430949d160bSJiri Olsa } 2431