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 <libelf.h> 1986470930SIngo Molnar #include <gelf.h> 2086470930SIngo Molnar #include <elf.h> 21f1617b40SArnaldo Carvalho de Melo #include <limits.h> 22439d473bSArnaldo Carvalho de Melo #include <sys/utsname.h> 232cdbc46dSPeter Zijlstra 243b01a413SArnaldo Carvalho de Melo #ifndef KSYM_NAME_LEN 25c752d040SRicardo Ribalda Delgado #define KSYM_NAME_LEN 256 263b01a413SArnaldo Carvalho de Melo #endif 273b01a413SArnaldo Carvalho de Melo 28c12e15e7SArnaldo Carvalho de Melo #ifndef NT_GNU_BUILD_ID 29c12e15e7SArnaldo Carvalho de Melo #define NT_GNU_BUILD_ID 3 30c12e15e7SArnaldo Carvalho de Melo #endif 31c12e15e7SArnaldo Carvalho de Melo 324dff624aSJiri Olsa static void dso_cache__free(struct rb_root *root); 33aeafcbafSArnaldo Carvalho de Melo static bool dso__build_id_equal(const struct dso *dso, u8 *build_id); 3421916c38SDave Martin static int elf_read_build_id(Elf *elf, void *bf, size_t size); 35b0da954aSArnaldo Carvalho de Melo static void dsos__add(struct list_head *head, struct dso *dso); 363610583cSArnaldo Carvalho de Melo static struct map *map__new2(u64 start, struct dso *dso, enum map_type type); 37aeafcbafSArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *dso, struct map *map, 389de89fe7SArnaldo Carvalho de Melo symbol_filter_t filter); 39aeafcbafSArnaldo Carvalho de Melo static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map, 40a1645ce1SZhang, Yanmin symbol_filter_t filter); 41cc612d81SArnaldo Carvalho de Melo static int vmlinux_path__nr_entries; 42cc612d81SArnaldo Carvalho de Melo static char **vmlinux_path; 43439d473bSArnaldo Carvalho de Melo 4475be6cf4SArnaldo Carvalho de Melo struct symbol_conf symbol_conf = { 45d599db3fSArnaldo Carvalho de Melo .exclude_other = true, 46b32d133aSArnaldo Carvalho de Melo .use_modules = true, 47b32d133aSArnaldo Carvalho de Melo .try_vmlinux_path = true, 483e6a2a7fSStephane Eranian .annotate_src = true, 49ec5761eaSDavid Ahern .symfs = "", 50b32d133aSArnaldo Carvalho de Melo }; 51b32d133aSArnaldo Carvalho de Melo 5244f24cb3SJiri Olsa static enum dso_binary_type binary_type_symtab[] = { 5344f24cb3SJiri Olsa DSO_BINARY_TYPE__KALLSYMS, 5444f24cb3SJiri Olsa DSO_BINARY_TYPE__GUEST_KALLSYMS, 5544f24cb3SJiri Olsa DSO_BINARY_TYPE__JAVA_JIT, 5644f24cb3SJiri Olsa DSO_BINARY_TYPE__DEBUGLINK, 5744f24cb3SJiri Olsa DSO_BINARY_TYPE__BUILD_ID_CACHE, 5844f24cb3SJiri Olsa DSO_BINARY_TYPE__FEDORA_DEBUGINFO, 5944f24cb3SJiri Olsa DSO_BINARY_TYPE__UBUNTU_DEBUGINFO, 6044f24cb3SJiri Olsa DSO_BINARY_TYPE__BUILDID_DEBUGINFO, 6144f24cb3SJiri Olsa DSO_BINARY_TYPE__SYSTEM_PATH_DSO, 6244f24cb3SJiri Olsa DSO_BINARY_TYPE__GUEST_KMODULE, 6344f24cb3SJiri Olsa DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE, 6444f24cb3SJiri Olsa DSO_BINARY_TYPE__NOT_FOUND, 6544f24cb3SJiri Olsa }; 6644f24cb3SJiri Olsa 67*028df767SJiri Olsa #define DSO_BINARY_TYPE__SYMTAB_CNT ARRAY_SIZE(binary_type_symtab) 6844f24cb3SJiri Olsa 69949d160bSJiri Olsa static enum dso_binary_type binary_type_data[] = { 70949d160bSJiri Olsa DSO_BINARY_TYPE__BUILD_ID_CACHE, 71949d160bSJiri Olsa DSO_BINARY_TYPE__SYSTEM_PATH_DSO, 72949d160bSJiri Olsa DSO_BINARY_TYPE__NOT_FOUND, 73949d160bSJiri Olsa }; 74949d160bSJiri Olsa 75*028df767SJiri Olsa #define DSO_BINARY_TYPE__DATA_CNT ARRAY_SIZE(binary_type_data) 76949d160bSJiri Olsa 77aeafcbafSArnaldo Carvalho de Melo int dso__name_len(const struct dso *dso) 788a6c5b26SArnaldo Carvalho de Melo { 791e2dd2f7SDavid Miller if (!dso) 801e2dd2f7SDavid Miller return strlen("[unknown]"); 818a6c5b26SArnaldo Carvalho de Melo if (verbose) 82aeafcbafSArnaldo Carvalho de Melo return dso->long_name_len; 838a6c5b26SArnaldo Carvalho de Melo 84aeafcbafSArnaldo Carvalho de Melo return dso->short_name_len; 858a6c5b26SArnaldo Carvalho de Melo } 868a6c5b26SArnaldo Carvalho de Melo 87aeafcbafSArnaldo Carvalho de Melo bool dso__loaded(const struct dso *dso, enum map_type type) 883610583cSArnaldo Carvalho de Melo { 89aeafcbafSArnaldo Carvalho de Melo return dso->loaded & (1 << type); 903610583cSArnaldo Carvalho de Melo } 913610583cSArnaldo Carvalho de Melo 92aeafcbafSArnaldo Carvalho de Melo bool dso__sorted_by_name(const struct dso *dso, enum map_type type) 9379406cd7SArnaldo Carvalho de Melo { 94aeafcbafSArnaldo Carvalho de Melo return dso->sorted_by_name & (1 << type); 9579406cd7SArnaldo Carvalho de Melo } 9679406cd7SArnaldo Carvalho de Melo 97aeafcbafSArnaldo Carvalho de Melo static void dso__set_sorted_by_name(struct dso *dso, enum map_type type) 9879406cd7SArnaldo Carvalho de Melo { 99aeafcbafSArnaldo Carvalho de Melo dso->sorted_by_name |= (1 << type); 10079406cd7SArnaldo Carvalho de Melo } 10179406cd7SArnaldo Carvalho de Melo 10236a3e646SArnaldo Carvalho de Melo bool symbol_type__is_a(char symbol_type, enum map_type map_type) 1036893d4eeSArnaldo Carvalho de Melo { 10431877908SAnton Blanchard symbol_type = toupper(symbol_type); 10531877908SAnton Blanchard 1066893d4eeSArnaldo Carvalho de Melo switch (map_type) { 1076893d4eeSArnaldo Carvalho de Melo case MAP__FUNCTION: 1086893d4eeSArnaldo Carvalho de Melo return symbol_type == 'T' || symbol_type == 'W'; 109f1dfa0b1SArnaldo Carvalho de Melo case MAP__VARIABLE: 11031877908SAnton Blanchard return symbol_type == 'D'; 1116893d4eeSArnaldo Carvalho de Melo default: 1126893d4eeSArnaldo Carvalho de Melo return false; 1136893d4eeSArnaldo Carvalho de Melo } 1146893d4eeSArnaldo Carvalho de Melo } 1156893d4eeSArnaldo Carvalho de Melo 116694bf407SAnton Blanchard static int prefix_underscores_count(const char *str) 117694bf407SAnton Blanchard { 118694bf407SAnton Blanchard const char *tail = str; 119694bf407SAnton Blanchard 120694bf407SAnton Blanchard while (*tail == '_') 121694bf407SAnton Blanchard tail++; 122694bf407SAnton Blanchard 123694bf407SAnton Blanchard return tail - str; 124694bf407SAnton Blanchard } 125694bf407SAnton Blanchard 126694bf407SAnton Blanchard #define SYMBOL_A 0 127694bf407SAnton Blanchard #define SYMBOL_B 1 128694bf407SAnton Blanchard 129694bf407SAnton Blanchard static int choose_best_symbol(struct symbol *syma, struct symbol *symb) 130694bf407SAnton Blanchard { 131694bf407SAnton Blanchard s64 a; 132694bf407SAnton Blanchard s64 b; 133694bf407SAnton Blanchard 134694bf407SAnton Blanchard /* Prefer a symbol with non zero length */ 135694bf407SAnton Blanchard a = syma->end - syma->start; 136694bf407SAnton Blanchard b = symb->end - symb->start; 137694bf407SAnton Blanchard if ((b == 0) && (a > 0)) 138694bf407SAnton Blanchard return SYMBOL_A; 139694bf407SAnton Blanchard else if ((a == 0) && (b > 0)) 140694bf407SAnton Blanchard return SYMBOL_B; 141694bf407SAnton Blanchard 142694bf407SAnton Blanchard /* Prefer a non weak symbol over a weak one */ 143694bf407SAnton Blanchard a = syma->binding == STB_WEAK; 144694bf407SAnton Blanchard b = symb->binding == STB_WEAK; 145694bf407SAnton Blanchard if (b && !a) 146694bf407SAnton Blanchard return SYMBOL_A; 147694bf407SAnton Blanchard if (a && !b) 148694bf407SAnton Blanchard return SYMBOL_B; 149694bf407SAnton Blanchard 150694bf407SAnton Blanchard /* Prefer a global symbol over a non global one */ 151694bf407SAnton Blanchard a = syma->binding == STB_GLOBAL; 152694bf407SAnton Blanchard b = symb->binding == STB_GLOBAL; 153694bf407SAnton Blanchard if (a && !b) 154694bf407SAnton Blanchard return SYMBOL_A; 155694bf407SAnton Blanchard if (b && !a) 156694bf407SAnton Blanchard return SYMBOL_B; 157694bf407SAnton Blanchard 158694bf407SAnton Blanchard /* Prefer a symbol with less underscores */ 159694bf407SAnton Blanchard a = prefix_underscores_count(syma->name); 160694bf407SAnton Blanchard b = prefix_underscores_count(symb->name); 161694bf407SAnton Blanchard if (b > a) 162694bf407SAnton Blanchard return SYMBOL_A; 163694bf407SAnton Blanchard else if (a > b) 164694bf407SAnton Blanchard return SYMBOL_B; 165694bf407SAnton Blanchard 166694bf407SAnton Blanchard /* If all else fails, choose the symbol with the longest name */ 167694bf407SAnton Blanchard if (strlen(syma->name) >= strlen(symb->name)) 168694bf407SAnton Blanchard return SYMBOL_A; 169694bf407SAnton Blanchard else 170694bf407SAnton Blanchard return SYMBOL_B; 171694bf407SAnton Blanchard } 172694bf407SAnton Blanchard 173694bf407SAnton Blanchard static void symbols__fixup_duplicate(struct rb_root *symbols) 174694bf407SAnton Blanchard { 175694bf407SAnton Blanchard struct rb_node *nd; 176694bf407SAnton Blanchard struct symbol *curr, *next; 177694bf407SAnton Blanchard 178694bf407SAnton Blanchard nd = rb_first(symbols); 179694bf407SAnton Blanchard 180694bf407SAnton Blanchard while (nd) { 181694bf407SAnton Blanchard curr = rb_entry(nd, struct symbol, rb_node); 182694bf407SAnton Blanchard again: 183694bf407SAnton Blanchard nd = rb_next(&curr->rb_node); 184694bf407SAnton Blanchard next = rb_entry(nd, struct symbol, rb_node); 185694bf407SAnton Blanchard 186694bf407SAnton Blanchard if (!nd) 187694bf407SAnton Blanchard break; 188694bf407SAnton Blanchard 189694bf407SAnton Blanchard if (curr->start != next->start) 190694bf407SAnton Blanchard continue; 191694bf407SAnton Blanchard 192694bf407SAnton Blanchard if (choose_best_symbol(curr, next) == SYMBOL_A) { 193694bf407SAnton Blanchard rb_erase(&next->rb_node, symbols); 194694bf407SAnton Blanchard goto again; 195694bf407SAnton Blanchard } else { 196694bf407SAnton Blanchard nd = rb_next(&curr->rb_node); 197694bf407SAnton Blanchard rb_erase(&curr->rb_node, symbols); 198694bf407SAnton Blanchard } 199694bf407SAnton Blanchard } 200694bf407SAnton Blanchard } 201694bf407SAnton Blanchard 202aeafcbafSArnaldo Carvalho de Melo static void symbols__fixup_end(struct rb_root *symbols) 203af427bf5SArnaldo Carvalho de Melo { 204aeafcbafSArnaldo Carvalho de Melo struct rb_node *nd, *prevnd = rb_first(symbols); 2052e538c4aSArnaldo Carvalho de Melo struct symbol *curr, *prev; 206af427bf5SArnaldo Carvalho de Melo 207af427bf5SArnaldo Carvalho de Melo if (prevnd == NULL) 208af427bf5SArnaldo Carvalho de Melo return; 209af427bf5SArnaldo Carvalho de Melo 2102e538c4aSArnaldo Carvalho de Melo curr = rb_entry(prevnd, struct symbol, rb_node); 2112e538c4aSArnaldo Carvalho de Melo 212af427bf5SArnaldo Carvalho de Melo for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) { 2132e538c4aSArnaldo Carvalho de Melo prev = curr; 2142e538c4aSArnaldo Carvalho de Melo curr = rb_entry(nd, struct symbol, rb_node); 215af427bf5SArnaldo Carvalho de Melo 2163b01a413SArnaldo Carvalho de Melo if (prev->end == prev->start && prev->end != curr->start) 217af427bf5SArnaldo Carvalho de Melo prev->end = curr->start - 1; 218af427bf5SArnaldo Carvalho de Melo } 219af427bf5SArnaldo Carvalho de Melo 2202e538c4aSArnaldo Carvalho de Melo /* Last entry */ 2212e538c4aSArnaldo Carvalho de Melo if (curr->end == curr->start) 2222e538c4aSArnaldo Carvalho de Melo curr->end = roundup(curr->start, 4096); 2232e538c4aSArnaldo Carvalho de Melo } 2242e538c4aSArnaldo Carvalho de Melo 225aeafcbafSArnaldo Carvalho de Melo static void __map_groups__fixup_end(struct map_groups *mg, enum map_type type) 226af427bf5SArnaldo Carvalho de Melo { 227af427bf5SArnaldo Carvalho de Melo struct map *prev, *curr; 228aeafcbafSArnaldo Carvalho de Melo struct rb_node *nd, *prevnd = rb_first(&mg->maps[type]); 229af427bf5SArnaldo Carvalho de Melo 230af427bf5SArnaldo Carvalho de Melo if (prevnd == NULL) 231af427bf5SArnaldo Carvalho de Melo return; 232af427bf5SArnaldo Carvalho de Melo 233af427bf5SArnaldo Carvalho de Melo curr = rb_entry(prevnd, struct map, rb_node); 234af427bf5SArnaldo Carvalho de Melo 235af427bf5SArnaldo Carvalho de Melo for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) { 236af427bf5SArnaldo Carvalho de Melo prev = curr; 237af427bf5SArnaldo Carvalho de Melo curr = rb_entry(nd, struct map, rb_node); 238af427bf5SArnaldo Carvalho de Melo prev->end = curr->start - 1; 2392e538c4aSArnaldo Carvalho de Melo } 24090c83218SArnaldo Carvalho de Melo 24190c83218SArnaldo Carvalho de Melo /* 24290c83218SArnaldo Carvalho de Melo * We still haven't the actual symbols, so guess the 24390c83218SArnaldo Carvalho de Melo * last map final address. 24490c83218SArnaldo Carvalho de Melo */ 2459d1faba5SIan Munsie curr->end = ~0ULL; 246af427bf5SArnaldo Carvalho de Melo } 247af427bf5SArnaldo Carvalho de Melo 248aeafcbafSArnaldo Carvalho de Melo static void map_groups__fixup_end(struct map_groups *mg) 24923ea4a3fSArnaldo Carvalho de Melo { 25023ea4a3fSArnaldo Carvalho de Melo int i; 25123ea4a3fSArnaldo Carvalho de Melo for (i = 0; i < MAP__NR_TYPES; ++i) 252aeafcbafSArnaldo Carvalho de Melo __map_groups__fixup_end(mg, i); 25323ea4a3fSArnaldo Carvalho de Melo } 25423ea4a3fSArnaldo Carvalho de Melo 255c408fedfSArnaldo Carvalho de Melo static struct symbol *symbol__new(u64 start, u64 len, u8 binding, 256c408fedfSArnaldo Carvalho de Melo const char *name) 25786470930SIngo Molnar { 25886470930SIngo Molnar size_t namelen = strlen(name) + 1; 259aeafcbafSArnaldo Carvalho de Melo struct symbol *sym = calloc(1, (symbol_conf.priv_size + 260aeafcbafSArnaldo Carvalho de Melo sizeof(*sym) + namelen)); 261aeafcbafSArnaldo Carvalho de Melo if (sym == NULL) 26286470930SIngo Molnar return NULL; 26386470930SIngo Molnar 26475be6cf4SArnaldo Carvalho de Melo if (symbol_conf.priv_size) 265aeafcbafSArnaldo Carvalho de Melo sym = ((void *)sym) + symbol_conf.priv_size; 26636479484SArnaldo Carvalho de Melo 267aeafcbafSArnaldo Carvalho de Melo sym->start = start; 268aeafcbafSArnaldo Carvalho de Melo sym->end = len ? start + len - 1 : start; 269aeafcbafSArnaldo Carvalho de Melo sym->binding = binding; 270aeafcbafSArnaldo Carvalho de Melo sym->namelen = namelen - 1; 271e4204992SArnaldo Carvalho de Melo 272aeafcbafSArnaldo Carvalho de Melo pr_debug4("%s: %s %#" PRIx64 "-%#" PRIx64 "\n", 273aeafcbafSArnaldo Carvalho de Melo __func__, name, start, sym->end); 274aeafcbafSArnaldo Carvalho de Melo memcpy(sym->name, name, namelen); 275e4204992SArnaldo Carvalho de Melo 276aeafcbafSArnaldo Carvalho de Melo return sym; 27786470930SIngo Molnar } 27886470930SIngo Molnar 279aeafcbafSArnaldo Carvalho de Melo void symbol__delete(struct symbol *sym) 28086470930SIngo Molnar { 281aeafcbafSArnaldo Carvalho de Melo free(((void *)sym) - symbol_conf.priv_size); 28286470930SIngo Molnar } 28386470930SIngo Molnar 284aeafcbafSArnaldo Carvalho de Melo static size_t symbol__fprintf(struct symbol *sym, FILE *fp) 28586470930SIngo Molnar { 2869486aa38SArnaldo Carvalho de Melo return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %c %s\n", 287aeafcbafSArnaldo Carvalho de Melo sym->start, sym->end, 288aeafcbafSArnaldo Carvalho de Melo sym->binding == STB_GLOBAL ? 'g' : 289aeafcbafSArnaldo Carvalho de Melo sym->binding == STB_LOCAL ? 'l' : 'w', 290aeafcbafSArnaldo Carvalho de Melo sym->name); 29186470930SIngo Molnar } 29286470930SIngo Molnar 293a978f2abSAkihiro Nagai size_t symbol__fprintf_symname_offs(const struct symbol *sym, 294a978f2abSAkihiro Nagai const struct addr_location *al, FILE *fp) 295a978f2abSAkihiro Nagai { 296a978f2abSAkihiro Nagai unsigned long offset; 297a978f2abSAkihiro Nagai size_t length; 298a978f2abSAkihiro Nagai 299a978f2abSAkihiro Nagai if (sym && sym->name) { 300a978f2abSAkihiro Nagai length = fprintf(fp, "%s", sym->name); 301a978f2abSAkihiro Nagai if (al) { 302a978f2abSAkihiro Nagai offset = al->addr - sym->start; 303a978f2abSAkihiro Nagai length += fprintf(fp, "+0x%lx", offset); 304a978f2abSAkihiro Nagai } 305a978f2abSAkihiro Nagai return length; 306a978f2abSAkihiro Nagai } else 307a978f2abSAkihiro Nagai return fprintf(fp, "[unknown]"); 308a978f2abSAkihiro Nagai } 309a978f2abSAkihiro Nagai 310547a92e0SAkihiro Nagai size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp) 311547a92e0SAkihiro Nagai { 312a978f2abSAkihiro Nagai return symbol__fprintf_symname_offs(sym, NULL, fp); 313547a92e0SAkihiro Nagai } 314547a92e0SAkihiro Nagai 315aeafcbafSArnaldo Carvalho de Melo void dso__set_long_name(struct dso *dso, char *name) 316cfc10d3bSArnaldo Carvalho de Melo { 317ef6ae724SArnaldo Carvalho de Melo if (name == NULL) 318ef6ae724SArnaldo Carvalho de Melo return; 319aeafcbafSArnaldo Carvalho de Melo dso->long_name = name; 320aeafcbafSArnaldo Carvalho de Melo dso->long_name_len = strlen(name); 321cfc10d3bSArnaldo Carvalho de Melo } 322cfc10d3bSArnaldo Carvalho de Melo 323aeafcbafSArnaldo Carvalho de Melo static void dso__set_short_name(struct dso *dso, const char *name) 324b63be8d7SArnaldo Carvalho de Melo { 325b63be8d7SArnaldo Carvalho de Melo if (name == NULL) 326b63be8d7SArnaldo Carvalho de Melo return; 327aeafcbafSArnaldo Carvalho de Melo dso->short_name = name; 328aeafcbafSArnaldo Carvalho de Melo dso->short_name_len = strlen(name); 329b63be8d7SArnaldo Carvalho de Melo } 330b63be8d7SArnaldo Carvalho de Melo 331aeafcbafSArnaldo Carvalho de Melo static void dso__set_basename(struct dso *dso) 332cfc10d3bSArnaldo Carvalho de Melo { 333aeafcbafSArnaldo Carvalho de Melo dso__set_short_name(dso, basename(dso->long_name)); 334cfc10d3bSArnaldo Carvalho de Melo } 335cfc10d3bSArnaldo Carvalho de Melo 33600a192b3SArnaldo Carvalho de Melo struct dso *dso__new(const char *name) 33786470930SIngo Molnar { 338aeafcbafSArnaldo Carvalho de Melo struct dso *dso = calloc(1, sizeof(*dso) + strlen(name) + 1); 33986470930SIngo Molnar 340aeafcbafSArnaldo Carvalho de Melo if (dso != NULL) { 3416a4694a4SArnaldo Carvalho de Melo int i; 342aeafcbafSArnaldo Carvalho de Melo strcpy(dso->name, name); 343aeafcbafSArnaldo Carvalho de Melo dso__set_long_name(dso, dso->name); 344aeafcbafSArnaldo Carvalho de Melo dso__set_short_name(dso, dso->name); 3456a4694a4SArnaldo Carvalho de Melo for (i = 0; i < MAP__NR_TYPES; ++i) 346aeafcbafSArnaldo Carvalho de Melo dso->symbols[i] = dso->symbol_names[i] = RB_ROOT; 3474dff624aSJiri Olsa dso->cache = RB_ROOT; 34844f24cb3SJiri Olsa dso->symtab_type = DSO_BINARY_TYPE__NOT_FOUND; 349949d160bSJiri Olsa dso->data_type = DSO_BINARY_TYPE__NOT_FOUND; 350aeafcbafSArnaldo Carvalho de Melo dso->loaded = 0; 351aeafcbafSArnaldo Carvalho de Melo dso->sorted_by_name = 0; 352aeafcbafSArnaldo Carvalho de Melo dso->has_build_id = 0; 353aeafcbafSArnaldo Carvalho de Melo dso->kernel = DSO_TYPE_USER; 3548db4841fSJiri Olsa dso->needs_swap = DSO_SWAP__UNSET; 355aeafcbafSArnaldo Carvalho de Melo INIT_LIST_HEAD(&dso->node); 35686470930SIngo Molnar } 35786470930SIngo Molnar 358aeafcbafSArnaldo Carvalho de Melo return dso; 35986470930SIngo Molnar } 36086470930SIngo Molnar 361aeafcbafSArnaldo Carvalho de Melo static void symbols__delete(struct rb_root *symbols) 36286470930SIngo Molnar { 36386470930SIngo Molnar struct symbol *pos; 364aeafcbafSArnaldo Carvalho de Melo struct rb_node *next = rb_first(symbols); 36586470930SIngo Molnar 36686470930SIngo Molnar while (next) { 36786470930SIngo Molnar pos = rb_entry(next, struct symbol, rb_node); 36886470930SIngo Molnar next = rb_next(&pos->rb_node); 369aeafcbafSArnaldo Carvalho de Melo rb_erase(&pos->rb_node, symbols); 37000a192b3SArnaldo Carvalho de Melo symbol__delete(pos); 37186470930SIngo Molnar } 37286470930SIngo Molnar } 37386470930SIngo Molnar 374aeafcbafSArnaldo Carvalho de Melo void dso__delete(struct dso *dso) 37586470930SIngo Molnar { 3766a4694a4SArnaldo Carvalho de Melo int i; 3776a4694a4SArnaldo Carvalho de Melo for (i = 0; i < MAP__NR_TYPES; ++i) 378aeafcbafSArnaldo Carvalho de Melo symbols__delete(&dso->symbols[i]); 379aeafcbafSArnaldo Carvalho de Melo if (dso->sname_alloc) 380aeafcbafSArnaldo Carvalho de Melo free((char *)dso->short_name); 381aeafcbafSArnaldo Carvalho de Melo if (dso->lname_alloc) 382aeafcbafSArnaldo Carvalho de Melo free(dso->long_name); 3834dff624aSJiri Olsa dso_cache__free(&dso->cache); 384aeafcbafSArnaldo Carvalho de Melo free(dso); 38586470930SIngo Molnar } 38686470930SIngo Molnar 387aeafcbafSArnaldo Carvalho de Melo void dso__set_build_id(struct dso *dso, void *build_id) 3888d06367fSArnaldo Carvalho de Melo { 389aeafcbafSArnaldo Carvalho de Melo memcpy(dso->build_id, build_id, sizeof(dso->build_id)); 390aeafcbafSArnaldo Carvalho de Melo dso->has_build_id = 1; 3918d06367fSArnaldo Carvalho de Melo } 3928d06367fSArnaldo Carvalho de Melo 393aeafcbafSArnaldo Carvalho de Melo static void symbols__insert(struct rb_root *symbols, struct symbol *sym) 39486470930SIngo Molnar { 395aeafcbafSArnaldo Carvalho de Melo struct rb_node **p = &symbols->rb_node; 39686470930SIngo Molnar struct rb_node *parent = NULL; 3979cffa8d5SPaul Mackerras const u64 ip = sym->start; 39886470930SIngo Molnar struct symbol *s; 39986470930SIngo Molnar 40086470930SIngo Molnar while (*p != NULL) { 40186470930SIngo Molnar parent = *p; 40286470930SIngo Molnar s = rb_entry(parent, struct symbol, rb_node); 40386470930SIngo Molnar if (ip < s->start) 40486470930SIngo Molnar p = &(*p)->rb_left; 40586470930SIngo Molnar else 40686470930SIngo Molnar p = &(*p)->rb_right; 40786470930SIngo Molnar } 40886470930SIngo Molnar rb_link_node(&sym->rb_node, parent, p); 409aeafcbafSArnaldo Carvalho de Melo rb_insert_color(&sym->rb_node, symbols); 41086470930SIngo Molnar } 41186470930SIngo Molnar 412aeafcbafSArnaldo Carvalho de Melo static struct symbol *symbols__find(struct rb_root *symbols, u64 ip) 41386470930SIngo Molnar { 41486470930SIngo Molnar struct rb_node *n; 41586470930SIngo Molnar 416aeafcbafSArnaldo Carvalho de Melo if (symbols == NULL) 41786470930SIngo Molnar return NULL; 41886470930SIngo Molnar 419aeafcbafSArnaldo Carvalho de Melo n = symbols->rb_node; 42086470930SIngo Molnar 42186470930SIngo Molnar while (n) { 42286470930SIngo Molnar struct symbol *s = rb_entry(n, struct symbol, rb_node); 42386470930SIngo Molnar 42486470930SIngo Molnar if (ip < s->start) 42586470930SIngo Molnar n = n->rb_left; 42686470930SIngo Molnar else if (ip > s->end) 42786470930SIngo Molnar n = n->rb_right; 42886470930SIngo Molnar else 42986470930SIngo Molnar return s; 43086470930SIngo Molnar } 43186470930SIngo Molnar 43286470930SIngo Molnar return NULL; 43386470930SIngo Molnar } 43486470930SIngo Molnar 43579406cd7SArnaldo Carvalho de Melo struct symbol_name_rb_node { 43679406cd7SArnaldo Carvalho de Melo struct rb_node rb_node; 43779406cd7SArnaldo Carvalho de Melo struct symbol sym; 43879406cd7SArnaldo Carvalho de Melo }; 43979406cd7SArnaldo Carvalho de Melo 440aeafcbafSArnaldo Carvalho de Melo static void symbols__insert_by_name(struct rb_root *symbols, struct symbol *sym) 44179406cd7SArnaldo Carvalho de Melo { 442aeafcbafSArnaldo Carvalho de Melo struct rb_node **p = &symbols->rb_node; 44379406cd7SArnaldo Carvalho de Melo struct rb_node *parent = NULL; 44402a9d037SRabin Vincent struct symbol_name_rb_node *symn, *s; 44502a9d037SRabin Vincent 44602a9d037SRabin Vincent symn = container_of(sym, struct symbol_name_rb_node, sym); 44779406cd7SArnaldo Carvalho de Melo 44879406cd7SArnaldo Carvalho de Melo while (*p != NULL) { 44979406cd7SArnaldo Carvalho de Melo parent = *p; 45079406cd7SArnaldo Carvalho de Melo s = rb_entry(parent, struct symbol_name_rb_node, rb_node); 45179406cd7SArnaldo Carvalho de Melo if (strcmp(sym->name, s->sym.name) < 0) 45279406cd7SArnaldo Carvalho de Melo p = &(*p)->rb_left; 45379406cd7SArnaldo Carvalho de Melo else 45479406cd7SArnaldo Carvalho de Melo p = &(*p)->rb_right; 45579406cd7SArnaldo Carvalho de Melo } 45679406cd7SArnaldo Carvalho de Melo rb_link_node(&symn->rb_node, parent, p); 457aeafcbafSArnaldo Carvalho de Melo rb_insert_color(&symn->rb_node, symbols); 45879406cd7SArnaldo Carvalho de Melo } 45979406cd7SArnaldo Carvalho de Melo 460aeafcbafSArnaldo Carvalho de Melo static void symbols__sort_by_name(struct rb_root *symbols, 461aeafcbafSArnaldo Carvalho de Melo struct rb_root *source) 46279406cd7SArnaldo Carvalho de Melo { 46379406cd7SArnaldo Carvalho de Melo struct rb_node *nd; 46479406cd7SArnaldo Carvalho de Melo 46579406cd7SArnaldo Carvalho de Melo for (nd = rb_first(source); nd; nd = rb_next(nd)) { 46679406cd7SArnaldo Carvalho de Melo struct symbol *pos = rb_entry(nd, struct symbol, rb_node); 467aeafcbafSArnaldo Carvalho de Melo symbols__insert_by_name(symbols, pos); 46879406cd7SArnaldo Carvalho de Melo } 46979406cd7SArnaldo Carvalho de Melo } 47079406cd7SArnaldo Carvalho de Melo 471aeafcbafSArnaldo Carvalho de Melo static struct symbol *symbols__find_by_name(struct rb_root *symbols, 472aeafcbafSArnaldo Carvalho de Melo const char *name) 47379406cd7SArnaldo Carvalho de Melo { 47479406cd7SArnaldo Carvalho de Melo struct rb_node *n; 47579406cd7SArnaldo Carvalho de Melo 476aeafcbafSArnaldo Carvalho de Melo if (symbols == NULL) 47779406cd7SArnaldo Carvalho de Melo return NULL; 47879406cd7SArnaldo Carvalho de Melo 479aeafcbafSArnaldo Carvalho de Melo n = symbols->rb_node; 48079406cd7SArnaldo Carvalho de Melo 48179406cd7SArnaldo Carvalho de Melo while (n) { 48279406cd7SArnaldo Carvalho de Melo struct symbol_name_rb_node *s; 48379406cd7SArnaldo Carvalho de Melo int cmp; 48479406cd7SArnaldo Carvalho de Melo 48579406cd7SArnaldo Carvalho de Melo s = rb_entry(n, struct symbol_name_rb_node, rb_node); 48679406cd7SArnaldo Carvalho de Melo cmp = strcmp(name, s->sym.name); 48779406cd7SArnaldo Carvalho de Melo 48879406cd7SArnaldo Carvalho de Melo if (cmp < 0) 48979406cd7SArnaldo Carvalho de Melo n = n->rb_left; 49079406cd7SArnaldo Carvalho de Melo else if (cmp > 0) 49179406cd7SArnaldo Carvalho de Melo n = n->rb_right; 49279406cd7SArnaldo Carvalho de Melo else 49379406cd7SArnaldo Carvalho de Melo return &s->sym; 49479406cd7SArnaldo Carvalho de Melo } 49579406cd7SArnaldo Carvalho de Melo 49679406cd7SArnaldo Carvalho de Melo return NULL; 49779406cd7SArnaldo Carvalho de Melo } 49879406cd7SArnaldo Carvalho de Melo 499aeafcbafSArnaldo Carvalho de Melo struct symbol *dso__find_symbol(struct dso *dso, 50079406cd7SArnaldo Carvalho de Melo enum map_type type, u64 addr) 501fcf1203aSArnaldo Carvalho de Melo { 502aeafcbafSArnaldo Carvalho de Melo return symbols__find(&dso->symbols[type], addr); 503fcf1203aSArnaldo Carvalho de Melo } 504fcf1203aSArnaldo Carvalho de Melo 505aeafcbafSArnaldo Carvalho de Melo struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type, 50679406cd7SArnaldo Carvalho de Melo const char *name) 50779406cd7SArnaldo Carvalho de Melo { 508aeafcbafSArnaldo Carvalho de Melo return symbols__find_by_name(&dso->symbol_names[type], name); 50979406cd7SArnaldo Carvalho de Melo } 51079406cd7SArnaldo Carvalho de Melo 511aeafcbafSArnaldo Carvalho de Melo void dso__sort_by_name(struct dso *dso, enum map_type type) 51279406cd7SArnaldo Carvalho de Melo { 513aeafcbafSArnaldo Carvalho de Melo dso__set_sorted_by_name(dso, type); 514aeafcbafSArnaldo Carvalho de Melo return symbols__sort_by_name(&dso->symbol_names[type], 515aeafcbafSArnaldo Carvalho de Melo &dso->symbols[type]); 51679406cd7SArnaldo Carvalho de Melo } 51779406cd7SArnaldo Carvalho de Melo 518aeafcbafSArnaldo Carvalho de Melo int build_id__sprintf(const u8 *build_id, int len, char *bf) 5198d06367fSArnaldo Carvalho de Melo { 5208d06367fSArnaldo Carvalho de Melo char *bid = bf; 521aeafcbafSArnaldo Carvalho de Melo const u8 *raw = build_id; 5228d06367fSArnaldo Carvalho de Melo int i; 5238d06367fSArnaldo Carvalho de Melo 5248d06367fSArnaldo Carvalho de Melo for (i = 0; i < len; ++i) { 5258d06367fSArnaldo Carvalho de Melo sprintf(bid, "%02x", *raw); 5268d06367fSArnaldo Carvalho de Melo ++raw; 5278d06367fSArnaldo Carvalho de Melo bid += 2; 5288d06367fSArnaldo Carvalho de Melo } 5298d06367fSArnaldo Carvalho de Melo 530aeafcbafSArnaldo Carvalho de Melo return raw - build_id; 5318d06367fSArnaldo Carvalho de Melo } 5328d06367fSArnaldo Carvalho de Melo 533aeafcbafSArnaldo Carvalho de Melo size_t dso__fprintf_buildid(struct dso *dso, FILE *fp) 53486470930SIngo Molnar { 5358d06367fSArnaldo Carvalho de Melo char sbuild_id[BUILD_ID_SIZE * 2 + 1]; 5368d06367fSArnaldo Carvalho de Melo 537aeafcbafSArnaldo Carvalho de Melo build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id); 5389e03eb2dSArnaldo Carvalho de Melo return fprintf(fp, "%s", sbuild_id); 5399e03eb2dSArnaldo Carvalho de Melo } 5409e03eb2dSArnaldo Carvalho de Melo 541aeafcbafSArnaldo Carvalho de Melo size_t dso__fprintf_symbols_by_name(struct dso *dso, 542aeafcbafSArnaldo Carvalho de Melo enum map_type type, FILE *fp) 54390f18e63SSrikar Dronamraju { 54490f18e63SSrikar Dronamraju size_t ret = 0; 54590f18e63SSrikar Dronamraju struct rb_node *nd; 54690f18e63SSrikar Dronamraju struct symbol_name_rb_node *pos; 54790f18e63SSrikar Dronamraju 548aeafcbafSArnaldo Carvalho de Melo for (nd = rb_first(&dso->symbol_names[type]); nd; nd = rb_next(nd)) { 54990f18e63SSrikar Dronamraju pos = rb_entry(nd, struct symbol_name_rb_node, rb_node); 55090f18e63SSrikar Dronamraju fprintf(fp, "%s\n", pos->sym.name); 55190f18e63SSrikar Dronamraju } 55290f18e63SSrikar Dronamraju 55390f18e63SSrikar Dronamraju return ret; 55490f18e63SSrikar Dronamraju } 55590f18e63SSrikar Dronamraju 556aeafcbafSArnaldo Carvalho de Melo size_t dso__fprintf(struct dso *dso, enum map_type type, FILE *fp) 5579e03eb2dSArnaldo Carvalho de Melo { 5589e03eb2dSArnaldo Carvalho de Melo struct rb_node *nd; 559aeafcbafSArnaldo Carvalho de Melo size_t ret = fprintf(fp, "dso: %s (", dso->short_name); 5609e03eb2dSArnaldo Carvalho de Melo 561aeafcbafSArnaldo Carvalho de Melo if (dso->short_name != dso->long_name) 562aeafcbafSArnaldo Carvalho de Melo ret += fprintf(fp, "%s, ", dso->long_name); 5633846df2eSArnaldo Carvalho de Melo ret += fprintf(fp, "%s, %sloaded, ", map_type__name[type], 564aeafcbafSArnaldo Carvalho de Melo dso->loaded ? "" : "NOT "); 565aeafcbafSArnaldo Carvalho de Melo ret += dso__fprintf_buildid(dso, fp); 5666a4694a4SArnaldo Carvalho de Melo ret += fprintf(fp, ")\n"); 567aeafcbafSArnaldo Carvalho de Melo for (nd = rb_first(&dso->symbols[type]); nd; nd = rb_next(nd)) { 56886470930SIngo Molnar struct symbol *pos = rb_entry(nd, struct symbol, rb_node); 56986470930SIngo Molnar ret += symbol__fprintf(pos, fp); 57086470930SIngo Molnar } 57186470930SIngo Molnar 57286470930SIngo Molnar return ret; 57386470930SIngo Molnar } 57486470930SIngo Molnar 5759e201442SArnaldo Carvalho de Melo int kallsyms__parse(const char *filename, void *arg, 5769e201442SArnaldo Carvalho de Melo int (*process_symbol)(void *arg, const char *name, 5773b01a413SArnaldo Carvalho de Melo char type, u64 start, u64 end)) 57886470930SIngo Molnar { 57986470930SIngo Molnar char *line = NULL; 58086470930SIngo Molnar size_t n; 5813b01a413SArnaldo Carvalho de Melo int err = -1; 5829e201442SArnaldo Carvalho de Melo FILE *file = fopen(filename, "r"); 58386470930SIngo Molnar 58486470930SIngo Molnar if (file == NULL) 58586470930SIngo Molnar goto out_failure; 58686470930SIngo Molnar 5873b01a413SArnaldo Carvalho de Melo err = 0; 5883b01a413SArnaldo Carvalho de Melo 58986470930SIngo Molnar while (!feof(file)) { 5909cffa8d5SPaul Mackerras u64 start; 59186470930SIngo Molnar int line_len, len; 59286470930SIngo Molnar char symbol_type; 5932e538c4aSArnaldo Carvalho de Melo char *symbol_name; 59486470930SIngo Molnar 59586470930SIngo Molnar line_len = getline(&line, &n, file); 596a1645ce1SZhang, Yanmin if (line_len < 0 || !line) 59786470930SIngo Molnar break; 59886470930SIngo Molnar 59986470930SIngo Molnar line[--line_len] = '\0'; /* \n */ 60086470930SIngo Molnar 60186470930SIngo Molnar len = hex2u64(line, &start); 60286470930SIngo Molnar 60386470930SIngo Molnar len++; 60486470930SIngo Molnar if (len + 2 >= line_len) 60586470930SIngo Molnar continue; 60686470930SIngo Molnar 60731877908SAnton Blanchard symbol_type = line[len]; 6083b01a413SArnaldo Carvalho de Melo len += 2; 6093b01a413SArnaldo Carvalho de Melo symbol_name = line + len; 6103b01a413SArnaldo Carvalho de Melo len = line_len - len; 611682b335aSArnaldo Carvalho de Melo 6123b01a413SArnaldo Carvalho de Melo if (len >= KSYM_NAME_LEN) { 6133b01a413SArnaldo Carvalho de Melo err = -1; 6143b01a413SArnaldo Carvalho de Melo break; 6153b01a413SArnaldo Carvalho de Melo } 6163b01a413SArnaldo Carvalho de Melo 6173f5a4272SAnton Blanchard /* 6183f5a4272SAnton Blanchard * module symbols are not sorted so we add all 6193f5a4272SAnton Blanchard * symbols with zero length and rely on 6203f5a4272SAnton Blanchard * symbols__fixup_end() to fix it up. 6213f5a4272SAnton Blanchard */ 6223f5a4272SAnton Blanchard err = process_symbol(arg, symbol_name, 6233f5a4272SAnton Blanchard symbol_type, start, start); 624682b335aSArnaldo Carvalho de Melo if (err) 625682b335aSArnaldo Carvalho de Melo break; 626682b335aSArnaldo Carvalho de Melo } 627682b335aSArnaldo Carvalho de Melo 628682b335aSArnaldo Carvalho de Melo free(line); 629682b335aSArnaldo Carvalho de Melo fclose(file); 630682b335aSArnaldo Carvalho de Melo return err; 631682b335aSArnaldo Carvalho de Melo 632682b335aSArnaldo Carvalho de Melo out_failure: 633682b335aSArnaldo Carvalho de Melo return -1; 634682b335aSArnaldo Carvalho de Melo } 635682b335aSArnaldo Carvalho de Melo 636682b335aSArnaldo Carvalho de Melo struct process_kallsyms_args { 637682b335aSArnaldo Carvalho de Melo struct map *map; 638682b335aSArnaldo Carvalho de Melo struct dso *dso; 639682b335aSArnaldo Carvalho de Melo }; 640682b335aSArnaldo Carvalho de Melo 641c408fedfSArnaldo Carvalho de Melo static u8 kallsyms2elf_type(char type) 642c408fedfSArnaldo Carvalho de Melo { 643c408fedfSArnaldo Carvalho de Melo if (type == 'W') 644c408fedfSArnaldo Carvalho de Melo return STB_WEAK; 645c408fedfSArnaldo Carvalho de Melo 646c408fedfSArnaldo Carvalho de Melo return isupper(type) ? STB_GLOBAL : STB_LOCAL; 647c408fedfSArnaldo Carvalho de Melo } 648c408fedfSArnaldo Carvalho de Melo 649682b335aSArnaldo Carvalho de Melo static int map__process_kallsym_symbol(void *arg, const char *name, 6503b01a413SArnaldo Carvalho de Melo char type, u64 start, u64 end) 651682b335aSArnaldo Carvalho de Melo { 652682b335aSArnaldo Carvalho de Melo struct symbol *sym; 653682b335aSArnaldo Carvalho de Melo struct process_kallsyms_args *a = arg; 654682b335aSArnaldo Carvalho de Melo struct rb_root *root = &a->dso->symbols[a->map->type]; 655682b335aSArnaldo Carvalho de Melo 656682b335aSArnaldo Carvalho de Melo if (!symbol_type__is_a(type, a->map->type)) 657682b335aSArnaldo Carvalho de Melo return 0; 658682b335aSArnaldo Carvalho de Melo 6593b01a413SArnaldo Carvalho de Melo sym = symbol__new(start, end - start + 1, 6603b01a413SArnaldo Carvalho de Melo kallsyms2elf_type(type), name); 6612e538c4aSArnaldo Carvalho de Melo if (sym == NULL) 662682b335aSArnaldo Carvalho de Melo return -ENOMEM; 66382164161SArnaldo Carvalho de Melo /* 66482164161SArnaldo Carvalho de Melo * We will pass the symbols to the filter later, in 6654e06255fSArnaldo Carvalho de Melo * map__split_kallsyms, when we have split the maps per module 66682164161SArnaldo Carvalho de Melo */ 6674e06255fSArnaldo Carvalho de Melo symbols__insert(root, sym); 668a1645ce1SZhang, Yanmin 669682b335aSArnaldo Carvalho de Melo return 0; 6702e538c4aSArnaldo Carvalho de Melo } 6712e538c4aSArnaldo Carvalho de Melo 672682b335aSArnaldo Carvalho de Melo /* 673682b335aSArnaldo Carvalho de Melo * Loads the function entries in /proc/kallsyms into kernel_map->dso, 674682b335aSArnaldo Carvalho de Melo * so that we can in the next step set the symbol ->end address and then 675682b335aSArnaldo Carvalho de Melo * call kernel_maps__split_kallsyms. 676682b335aSArnaldo Carvalho de Melo */ 677aeafcbafSArnaldo Carvalho de Melo static int dso__load_all_kallsyms(struct dso *dso, const char *filename, 6789e201442SArnaldo Carvalho de Melo struct map *map) 679682b335aSArnaldo Carvalho de Melo { 680aeafcbafSArnaldo Carvalho de Melo struct process_kallsyms_args args = { .map = map, .dso = dso, }; 6819e201442SArnaldo Carvalho de Melo return kallsyms__parse(filename, &args, map__process_kallsym_symbol); 6822e538c4aSArnaldo Carvalho de Melo } 6832e538c4aSArnaldo Carvalho de Melo 6842e538c4aSArnaldo Carvalho de Melo /* 6852e538c4aSArnaldo Carvalho de Melo * Split the symbols into maps, making sure there are no overlaps, i.e. the 6862e538c4aSArnaldo Carvalho de Melo * kernel range is broken in several maps, named [kernel].N, as we don't have 6872e538c4aSArnaldo Carvalho de Melo * the original ELF section names vmlinux have. 6882e538c4aSArnaldo Carvalho de Melo */ 689aeafcbafSArnaldo Carvalho de Melo static int dso__split_kallsyms(struct dso *dso, struct map *map, 6909de89fe7SArnaldo Carvalho de Melo symbol_filter_t filter) 6912e538c4aSArnaldo Carvalho de Melo { 6929de89fe7SArnaldo Carvalho de Melo struct map_groups *kmaps = map__kmap(map)->kmaps; 69323346f21SArnaldo Carvalho de Melo struct machine *machine = kmaps->machine; 6944e06255fSArnaldo Carvalho de Melo struct map *curr_map = map; 6952e538c4aSArnaldo Carvalho de Melo struct symbol *pos; 6968a953312SArnaldo Carvalho de Melo int count = 0, moved = 0; 697aeafcbafSArnaldo Carvalho de Melo struct rb_root *root = &dso->symbols[map->type]; 6984e06255fSArnaldo Carvalho de Melo struct rb_node *next = rb_first(root); 6992e538c4aSArnaldo Carvalho de Melo int kernel_range = 0; 7002e538c4aSArnaldo Carvalho de Melo 7012e538c4aSArnaldo Carvalho de Melo while (next) { 7022e538c4aSArnaldo Carvalho de Melo char *module; 7032e538c4aSArnaldo Carvalho de Melo 7042e538c4aSArnaldo Carvalho de Melo pos = rb_entry(next, struct symbol, rb_node); 7052e538c4aSArnaldo Carvalho de Melo next = rb_next(&pos->rb_node); 7062e538c4aSArnaldo Carvalho de Melo 7072e538c4aSArnaldo Carvalho de Melo module = strchr(pos->name, '\t'); 7082e538c4aSArnaldo Carvalho de Melo if (module) { 70975be6cf4SArnaldo Carvalho de Melo if (!symbol_conf.use_modules) 7101de8e245SArnaldo Carvalho de Melo goto discard_symbol; 7111de8e245SArnaldo Carvalho de Melo 7122e538c4aSArnaldo Carvalho de Melo *module++ = '\0'; 7132e538c4aSArnaldo Carvalho de Melo 714b7cece76SArnaldo Carvalho de Melo if (strcmp(curr_map->dso->short_name, module)) { 715a1645ce1SZhang, Yanmin if (curr_map != map && 716aeafcbafSArnaldo Carvalho de Melo dso->kernel == DSO_TYPE_GUEST_KERNEL && 71723346f21SArnaldo Carvalho de Melo machine__is_default_guest(machine)) { 718a1645ce1SZhang, Yanmin /* 719a1645ce1SZhang, Yanmin * We assume all symbols of a module are 720a1645ce1SZhang, Yanmin * continuous in * kallsyms, so curr_map 721a1645ce1SZhang, Yanmin * points to a module and all its 722a1645ce1SZhang, Yanmin * symbols are in its kmap. Mark it as 723a1645ce1SZhang, Yanmin * loaded. 724a1645ce1SZhang, Yanmin */ 725a1645ce1SZhang, Yanmin dso__set_loaded(curr_map->dso, 726a1645ce1SZhang, Yanmin curr_map->type); 727af427bf5SArnaldo Carvalho de Melo } 728b7cece76SArnaldo Carvalho de Melo 729a1645ce1SZhang, Yanmin curr_map = map_groups__find_by_name(kmaps, 730a1645ce1SZhang, Yanmin map->type, module); 731a1645ce1SZhang, Yanmin if (curr_map == NULL) { 7322f51903bSArnaldo Carvalho de Melo pr_debug("%s/proc/{kallsyms,modules} " 733a1645ce1SZhang, Yanmin "inconsistency while looking " 734a1645ce1SZhang, Yanmin "for \"%s\" module!\n", 73523346f21SArnaldo Carvalho de Melo machine->root_dir, module); 736a1645ce1SZhang, Yanmin curr_map = map; 737a1645ce1SZhang, Yanmin goto discard_symbol; 738a1645ce1SZhang, Yanmin } 739a1645ce1SZhang, Yanmin 740a1645ce1SZhang, Yanmin if (curr_map->dso->loaded && 74123346f21SArnaldo Carvalho de Melo !machine__is_default_guest(machine)) 742b7cece76SArnaldo Carvalho de Melo goto discard_symbol; 743af427bf5SArnaldo Carvalho de Melo } 74486470930SIngo Molnar /* 7452e538c4aSArnaldo Carvalho de Melo * So that we look just like we get from .ko files, 7462e538c4aSArnaldo Carvalho de Melo * i.e. not prelinked, relative to map->start. 74786470930SIngo Molnar */ 7484e06255fSArnaldo Carvalho de Melo pos->start = curr_map->map_ip(curr_map, pos->start); 7494e06255fSArnaldo Carvalho de Melo pos->end = curr_map->map_ip(curr_map, pos->end); 7504e06255fSArnaldo Carvalho de Melo } else if (curr_map != map) { 7512e538c4aSArnaldo Carvalho de Melo char dso_name[PATH_MAX]; 752aeafcbafSArnaldo Carvalho de Melo struct dso *ndso; 75386470930SIngo Molnar 7548a953312SArnaldo Carvalho de Melo if (count == 0) { 7558a953312SArnaldo Carvalho de Melo curr_map = map; 7568a953312SArnaldo Carvalho de Melo goto filter_symbol; 7578a953312SArnaldo Carvalho de Melo } 7588a953312SArnaldo Carvalho de Melo 759aeafcbafSArnaldo Carvalho de Melo if (dso->kernel == DSO_TYPE_GUEST_KERNEL) 760a1645ce1SZhang, Yanmin snprintf(dso_name, sizeof(dso_name), 761a1645ce1SZhang, Yanmin "[guest.kernel].%d", 762a1645ce1SZhang, Yanmin kernel_range++); 763a1645ce1SZhang, Yanmin else 764a1645ce1SZhang, Yanmin snprintf(dso_name, sizeof(dso_name), 765a1645ce1SZhang, Yanmin "[kernel].%d", 7662e538c4aSArnaldo Carvalho de Melo kernel_range++); 76786470930SIngo Molnar 768aeafcbafSArnaldo Carvalho de Melo ndso = dso__new(dso_name); 769aeafcbafSArnaldo Carvalho de Melo if (ndso == NULL) 7702e538c4aSArnaldo Carvalho de Melo return -1; 7712e538c4aSArnaldo Carvalho de Melo 772aeafcbafSArnaldo Carvalho de Melo ndso->kernel = dso->kernel; 773a1645ce1SZhang, Yanmin 774aeafcbafSArnaldo Carvalho de Melo curr_map = map__new2(pos->start, ndso, map->type); 77537fe5fcbSZhang, Yanmin if (curr_map == NULL) { 776aeafcbafSArnaldo Carvalho de Melo dso__delete(ndso); 7772e538c4aSArnaldo Carvalho de Melo return -1; 7782e538c4aSArnaldo Carvalho de Melo } 7792e538c4aSArnaldo Carvalho de Melo 7804e06255fSArnaldo Carvalho de Melo curr_map->map_ip = curr_map->unmap_ip = identity__map_ip; 7819de89fe7SArnaldo Carvalho de Melo map_groups__insert(kmaps, curr_map); 7822e538c4aSArnaldo Carvalho de Melo ++kernel_range; 7832e538c4aSArnaldo Carvalho de Melo } 7848a953312SArnaldo Carvalho de Melo filter_symbol: 7854e06255fSArnaldo Carvalho de Melo if (filter && filter(curr_map, pos)) { 7861de8e245SArnaldo Carvalho de Melo discard_symbol: rb_erase(&pos->rb_node, root); 78700a192b3SArnaldo Carvalho de Melo symbol__delete(pos); 7882e538c4aSArnaldo Carvalho de Melo } else { 7894e06255fSArnaldo Carvalho de Melo if (curr_map != map) { 7904e06255fSArnaldo Carvalho de Melo rb_erase(&pos->rb_node, root); 7914e06255fSArnaldo Carvalho de Melo symbols__insert(&curr_map->dso->symbols[curr_map->type], pos); 7928a953312SArnaldo Carvalho de Melo ++moved; 7938a953312SArnaldo Carvalho de Melo } else 7948a953312SArnaldo Carvalho de Melo ++count; 7959974f496SMike Galbraith } 79686470930SIngo Molnar } 79786470930SIngo Molnar 798a1645ce1SZhang, Yanmin if (curr_map != map && 799aeafcbafSArnaldo Carvalho de Melo dso->kernel == DSO_TYPE_GUEST_KERNEL && 80023346f21SArnaldo Carvalho de Melo machine__is_default_guest(kmaps->machine)) { 801a1645ce1SZhang, Yanmin dso__set_loaded(curr_map->dso, curr_map->type); 802a1645ce1SZhang, Yanmin } 803a1645ce1SZhang, Yanmin 8048a953312SArnaldo Carvalho de Melo return count + moved; 80586470930SIngo Molnar } 80686470930SIngo Molnar 807ec80fde7SArnaldo Carvalho de Melo static bool symbol__restricted_filename(const char *filename, 808ec80fde7SArnaldo Carvalho de Melo const char *restricted_filename) 809ec80fde7SArnaldo Carvalho de Melo { 810ec80fde7SArnaldo Carvalho de Melo bool restricted = false; 811ec80fde7SArnaldo Carvalho de Melo 812ec80fde7SArnaldo Carvalho de Melo if (symbol_conf.kptr_restrict) { 813ec80fde7SArnaldo Carvalho de Melo char *r = realpath(filename, NULL); 814ec80fde7SArnaldo Carvalho de Melo 815ec80fde7SArnaldo Carvalho de Melo if (r != NULL) { 816ec80fde7SArnaldo Carvalho de Melo restricted = strcmp(r, restricted_filename) == 0; 817ec80fde7SArnaldo Carvalho de Melo free(r); 818ec80fde7SArnaldo Carvalho de Melo return restricted; 819ec80fde7SArnaldo Carvalho de Melo } 820ec80fde7SArnaldo Carvalho de Melo } 821ec80fde7SArnaldo Carvalho de Melo 822ec80fde7SArnaldo Carvalho de Melo return restricted; 823ec80fde7SArnaldo Carvalho de Melo } 824ec80fde7SArnaldo Carvalho de Melo 825aeafcbafSArnaldo Carvalho de Melo int dso__load_kallsyms(struct dso *dso, const char *filename, 8269de89fe7SArnaldo Carvalho de Melo struct map *map, symbol_filter_t filter) 8272e538c4aSArnaldo Carvalho de Melo { 828ec80fde7SArnaldo Carvalho de Melo if (symbol__restricted_filename(filename, "/proc/kallsyms")) 829ec80fde7SArnaldo Carvalho de Melo return -1; 830ec80fde7SArnaldo Carvalho de Melo 831aeafcbafSArnaldo Carvalho de Melo if (dso__load_all_kallsyms(dso, filename, map) < 0) 8322e538c4aSArnaldo Carvalho de Melo return -1; 8332e538c4aSArnaldo Carvalho de Melo 834694bf407SAnton Blanchard symbols__fixup_duplicate(&dso->symbols[map->type]); 8353f5a4272SAnton Blanchard symbols__fixup_end(&dso->symbols[map->type]); 8363f5a4272SAnton Blanchard 837aeafcbafSArnaldo Carvalho de Melo if (dso->kernel == DSO_TYPE_GUEST_KERNEL) 83844f24cb3SJiri Olsa dso->symtab_type = DSO_BINARY_TYPE__GUEST_KALLSYMS; 839a1645ce1SZhang, Yanmin else 84044f24cb3SJiri Olsa dso->symtab_type = DSO_BINARY_TYPE__KALLSYMS; 8412e538c4aSArnaldo Carvalho de Melo 842aeafcbafSArnaldo Carvalho de Melo return dso__split_kallsyms(dso, map, filter); 843af427bf5SArnaldo Carvalho de Melo } 844af427bf5SArnaldo Carvalho de Melo 845aeafcbafSArnaldo Carvalho de Melo static int dso__load_perf_map(struct dso *dso, struct map *map, 8466beba7adSArnaldo Carvalho de Melo symbol_filter_t filter) 84780d496beSPekka Enberg { 84880d496beSPekka Enberg char *line = NULL; 84980d496beSPekka Enberg size_t n; 85080d496beSPekka Enberg FILE *file; 85180d496beSPekka Enberg int nr_syms = 0; 85280d496beSPekka Enberg 853aeafcbafSArnaldo Carvalho de Melo file = fopen(dso->long_name, "r"); 85480d496beSPekka Enberg if (file == NULL) 85580d496beSPekka Enberg goto out_failure; 85680d496beSPekka Enberg 85780d496beSPekka Enberg while (!feof(file)) { 8589cffa8d5SPaul Mackerras u64 start, size; 85980d496beSPekka Enberg struct symbol *sym; 86080d496beSPekka Enberg int line_len, len; 86180d496beSPekka Enberg 86280d496beSPekka Enberg line_len = getline(&line, &n, file); 86380d496beSPekka Enberg if (line_len < 0) 86480d496beSPekka Enberg break; 86580d496beSPekka Enberg 86680d496beSPekka Enberg if (!line) 86780d496beSPekka Enberg goto out_failure; 86880d496beSPekka Enberg 86980d496beSPekka Enberg line[--line_len] = '\0'; /* \n */ 87080d496beSPekka Enberg 87180d496beSPekka Enberg len = hex2u64(line, &start); 87280d496beSPekka Enberg 87380d496beSPekka Enberg len++; 87480d496beSPekka Enberg if (len + 2 >= line_len) 87580d496beSPekka Enberg continue; 87680d496beSPekka Enberg 87780d496beSPekka Enberg len += hex2u64(line + len, &size); 87880d496beSPekka Enberg 87980d496beSPekka Enberg len++; 88080d496beSPekka Enberg if (len + 2 >= line_len) 88180d496beSPekka Enberg continue; 88280d496beSPekka Enberg 883c408fedfSArnaldo Carvalho de Melo sym = symbol__new(start, size, STB_GLOBAL, line + len); 88480d496beSPekka Enberg 88580d496beSPekka Enberg if (sym == NULL) 88680d496beSPekka Enberg goto out_delete_line; 88780d496beSPekka Enberg 888439d473bSArnaldo Carvalho de Melo if (filter && filter(map, sym)) 88900a192b3SArnaldo Carvalho de Melo symbol__delete(sym); 89080d496beSPekka Enberg else { 891aeafcbafSArnaldo Carvalho de Melo symbols__insert(&dso->symbols[map->type], sym); 89280d496beSPekka Enberg nr_syms++; 89380d496beSPekka Enberg } 89480d496beSPekka Enberg } 89580d496beSPekka Enberg 89680d496beSPekka Enberg free(line); 89780d496beSPekka Enberg fclose(file); 89880d496beSPekka Enberg 89980d496beSPekka Enberg return nr_syms; 90080d496beSPekka Enberg 90180d496beSPekka Enberg out_delete_line: 90280d496beSPekka Enberg free(line); 90380d496beSPekka Enberg out_failure: 90480d496beSPekka Enberg return -1; 90580d496beSPekka Enberg } 90680d496beSPekka Enberg 90786470930SIngo Molnar /** 90886470930SIngo Molnar * elf_symtab__for_each_symbol - iterate thru all the symbols 90986470930SIngo Molnar * 910aeafcbafSArnaldo Carvalho de Melo * @syms: struct elf_symtab instance to iterate 91183a0944fSIngo Molnar * @idx: uint32_t idx 91286470930SIngo Molnar * @sym: GElf_Sym iterator 91386470930SIngo Molnar */ 91483a0944fSIngo Molnar #define elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) \ 91583a0944fSIngo Molnar for (idx = 0, gelf_getsym(syms, idx, &sym);\ 91683a0944fSIngo Molnar idx < nr_syms; \ 91783a0944fSIngo Molnar idx++, gelf_getsym(syms, idx, &sym)) 91886470930SIngo Molnar 91986470930SIngo Molnar static inline uint8_t elf_sym__type(const GElf_Sym *sym) 92086470930SIngo Molnar { 92186470930SIngo Molnar return GELF_ST_TYPE(sym->st_info); 92286470930SIngo Molnar } 92386470930SIngo Molnar 92486470930SIngo Molnar static inline int elf_sym__is_function(const GElf_Sym *sym) 92586470930SIngo Molnar { 92686470930SIngo Molnar return elf_sym__type(sym) == STT_FUNC && 92786470930SIngo Molnar sym->st_name != 0 && 92881833130SArnaldo Carvalho de Melo sym->st_shndx != SHN_UNDEF; 92986470930SIngo Molnar } 93086470930SIngo Molnar 931f1dfa0b1SArnaldo Carvalho de Melo static inline bool elf_sym__is_object(const GElf_Sym *sym) 932f1dfa0b1SArnaldo Carvalho de Melo { 933f1dfa0b1SArnaldo Carvalho de Melo return elf_sym__type(sym) == STT_OBJECT && 934f1dfa0b1SArnaldo Carvalho de Melo sym->st_name != 0 && 935f1dfa0b1SArnaldo Carvalho de Melo sym->st_shndx != SHN_UNDEF; 936f1dfa0b1SArnaldo Carvalho de Melo } 937f1dfa0b1SArnaldo Carvalho de Melo 9386cfcc53eSMike Galbraith static inline int elf_sym__is_label(const GElf_Sym *sym) 9396cfcc53eSMike Galbraith { 9406cfcc53eSMike Galbraith return elf_sym__type(sym) == STT_NOTYPE && 9416cfcc53eSMike Galbraith sym->st_name != 0 && 9426cfcc53eSMike Galbraith sym->st_shndx != SHN_UNDEF && 9436cfcc53eSMike Galbraith sym->st_shndx != SHN_ABS; 9446cfcc53eSMike Galbraith } 9456cfcc53eSMike Galbraith 9466cfcc53eSMike Galbraith static inline const char *elf_sec__name(const GElf_Shdr *shdr, 9476cfcc53eSMike Galbraith const Elf_Data *secstrs) 9486cfcc53eSMike Galbraith { 9496cfcc53eSMike Galbraith return secstrs->d_buf + shdr->sh_name; 9506cfcc53eSMike Galbraith } 9516cfcc53eSMike Galbraith 9526cfcc53eSMike Galbraith static inline int elf_sec__is_text(const GElf_Shdr *shdr, 9536cfcc53eSMike Galbraith const Elf_Data *secstrs) 9546cfcc53eSMike Galbraith { 9556cfcc53eSMike Galbraith return strstr(elf_sec__name(shdr, secstrs), "text") != NULL; 9566cfcc53eSMike Galbraith } 9576cfcc53eSMike Galbraith 958f1dfa0b1SArnaldo Carvalho de Melo static inline bool elf_sec__is_data(const GElf_Shdr *shdr, 959f1dfa0b1SArnaldo Carvalho de Melo const Elf_Data *secstrs) 960f1dfa0b1SArnaldo Carvalho de Melo { 961f1dfa0b1SArnaldo Carvalho de Melo return strstr(elf_sec__name(shdr, secstrs), "data") != NULL; 962f1dfa0b1SArnaldo Carvalho de Melo } 963f1dfa0b1SArnaldo Carvalho de Melo 96486470930SIngo Molnar static inline const char *elf_sym__name(const GElf_Sym *sym, 96586470930SIngo Molnar const Elf_Data *symstrs) 96686470930SIngo Molnar { 96786470930SIngo Molnar return symstrs->d_buf + sym->st_name; 96886470930SIngo Molnar } 96986470930SIngo Molnar 97086470930SIngo Molnar static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, 97186470930SIngo Molnar GElf_Shdr *shp, const char *name, 97283a0944fSIngo Molnar size_t *idx) 97386470930SIngo Molnar { 97486470930SIngo Molnar Elf_Scn *sec = NULL; 97586470930SIngo Molnar size_t cnt = 1; 97686470930SIngo Molnar 97786470930SIngo Molnar while ((sec = elf_nextscn(elf, sec)) != NULL) { 97886470930SIngo Molnar char *str; 97986470930SIngo Molnar 98086470930SIngo Molnar gelf_getshdr(sec, shp); 98186470930SIngo Molnar str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name); 98286470930SIngo Molnar if (!strcmp(name, str)) { 98383a0944fSIngo Molnar if (idx) 98483a0944fSIngo Molnar *idx = cnt; 98586470930SIngo Molnar break; 98686470930SIngo Molnar } 98786470930SIngo Molnar ++cnt; 98886470930SIngo Molnar } 98986470930SIngo Molnar 99086470930SIngo Molnar return sec; 99186470930SIngo Molnar } 99286470930SIngo Molnar 99386470930SIngo Molnar #define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \ 99486470930SIngo Molnar for (idx = 0, pos = gelf_getrel(reldata, 0, &pos_mem); \ 99586470930SIngo Molnar idx < nr_entries; \ 99686470930SIngo Molnar ++idx, pos = gelf_getrel(reldata, idx, &pos_mem)) 99786470930SIngo Molnar 99886470930SIngo Molnar #define elf_section__for_each_rela(reldata, pos, pos_mem, idx, nr_entries) \ 99986470930SIngo Molnar for (idx = 0, pos = gelf_getrela(reldata, 0, &pos_mem); \ 100086470930SIngo Molnar idx < nr_entries; \ 100186470930SIngo Molnar ++idx, pos = gelf_getrela(reldata, idx, &pos_mem)) 100286470930SIngo Molnar 1003a25e46c4SArnaldo Carvalho de Melo /* 1004a25e46c4SArnaldo Carvalho de Melo * We need to check if we have a .dynsym, so that we can handle the 1005a25e46c4SArnaldo Carvalho de Melo * .plt, synthesizing its symbols, that aren't on the symtabs (be it 1006a25e46c4SArnaldo Carvalho de Melo * .dynsym or .symtab). 1007a25e46c4SArnaldo Carvalho de Melo * And always look at the original dso, not at debuginfo packages, that 1008a25e46c4SArnaldo Carvalho de Melo * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS). 1009a25e46c4SArnaldo Carvalho de Melo */ 101033ff581eSJiri Olsa static int 101133ff581eSJiri Olsa dso__synthesize_plt_symbols(struct dso *dso, char *name, struct map *map, 101282164161SArnaldo Carvalho de Melo symbol_filter_t filter) 101386470930SIngo Molnar { 101486470930SIngo Molnar uint32_t nr_rel_entries, idx; 101586470930SIngo Molnar GElf_Sym sym; 10169cffa8d5SPaul Mackerras u64 plt_offset; 101786470930SIngo Molnar GElf_Shdr shdr_plt; 101886470930SIngo Molnar struct symbol *f; 1019a25e46c4SArnaldo Carvalho de Melo GElf_Shdr shdr_rel_plt, shdr_dynsym; 102086470930SIngo Molnar Elf_Data *reldata, *syms, *symstrs; 1021a25e46c4SArnaldo Carvalho de Melo Elf_Scn *scn_plt_rel, *scn_symstrs, *scn_dynsym; 1022a25e46c4SArnaldo Carvalho de Melo size_t dynsym_idx; 1023a25e46c4SArnaldo Carvalho de Melo GElf_Ehdr ehdr; 102486470930SIngo Molnar char sympltname[1024]; 1025a25e46c4SArnaldo Carvalho de Melo Elf *elf; 1026a25e46c4SArnaldo Carvalho de Melo int nr = 0, symidx, fd, err = 0; 102786470930SIngo Molnar 1028ec5761eaSDavid Ahern fd = open(name, O_RDONLY); 1029a25e46c4SArnaldo Carvalho de Melo if (fd < 0) 1030a25e46c4SArnaldo Carvalho de Melo goto out; 1031a25e46c4SArnaldo Carvalho de Melo 103284087126SMarti Raudsepp elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 1033a25e46c4SArnaldo Carvalho de Melo if (elf == NULL) 1034a25e46c4SArnaldo Carvalho de Melo goto out_close; 1035a25e46c4SArnaldo Carvalho de Melo 1036a25e46c4SArnaldo Carvalho de Melo if (gelf_getehdr(elf, &ehdr) == NULL) 1037a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 1038a25e46c4SArnaldo Carvalho de Melo 1039a25e46c4SArnaldo Carvalho de Melo scn_dynsym = elf_section_by_name(elf, &ehdr, &shdr_dynsym, 1040a25e46c4SArnaldo Carvalho de Melo ".dynsym", &dynsym_idx); 1041a25e46c4SArnaldo Carvalho de Melo if (scn_dynsym == NULL) 1042a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 1043a25e46c4SArnaldo Carvalho de Melo 1044a25e46c4SArnaldo Carvalho de Melo scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt, 104586470930SIngo Molnar ".rela.plt", NULL); 104686470930SIngo Molnar if (scn_plt_rel == NULL) { 1047a25e46c4SArnaldo Carvalho de Melo scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt, 104886470930SIngo Molnar ".rel.plt", NULL); 104986470930SIngo Molnar if (scn_plt_rel == NULL) 1050a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 105186470930SIngo Molnar } 105286470930SIngo Molnar 1053a25e46c4SArnaldo Carvalho de Melo err = -1; 105486470930SIngo Molnar 1055a25e46c4SArnaldo Carvalho de Melo if (shdr_rel_plt.sh_link != dynsym_idx) 1056a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 1057a25e46c4SArnaldo Carvalho de Melo 1058a25e46c4SArnaldo Carvalho de Melo if (elf_section_by_name(elf, &ehdr, &shdr_plt, ".plt", NULL) == NULL) 1059a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 106086470930SIngo Molnar 106186470930SIngo Molnar /* 106283a0944fSIngo Molnar * Fetch the relocation section to find the idxes to the GOT 106386470930SIngo Molnar * and the symbols in the .dynsym they refer to. 106486470930SIngo Molnar */ 106586470930SIngo Molnar reldata = elf_getdata(scn_plt_rel, NULL); 106686470930SIngo Molnar if (reldata == NULL) 1067a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 106886470930SIngo Molnar 106986470930SIngo Molnar syms = elf_getdata(scn_dynsym, NULL); 107086470930SIngo Molnar if (syms == NULL) 1071a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 107286470930SIngo Molnar 1073a25e46c4SArnaldo Carvalho de Melo scn_symstrs = elf_getscn(elf, shdr_dynsym.sh_link); 107486470930SIngo Molnar if (scn_symstrs == NULL) 1075a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 107686470930SIngo Molnar 107786470930SIngo Molnar symstrs = elf_getdata(scn_symstrs, NULL); 107886470930SIngo Molnar if (symstrs == NULL) 1079a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 108086470930SIngo Molnar 108186470930SIngo Molnar nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize; 108286470930SIngo Molnar plt_offset = shdr_plt.sh_offset; 108386470930SIngo Molnar 108486470930SIngo Molnar if (shdr_rel_plt.sh_type == SHT_RELA) { 108586470930SIngo Molnar GElf_Rela pos_mem, *pos; 108686470930SIngo Molnar 108786470930SIngo Molnar elf_section__for_each_rela(reldata, pos, pos_mem, idx, 108886470930SIngo Molnar nr_rel_entries) { 108986470930SIngo Molnar symidx = GELF_R_SYM(pos->r_info); 109086470930SIngo Molnar plt_offset += shdr_plt.sh_entsize; 109186470930SIngo Molnar gelf_getsym(syms, symidx, &sym); 109286470930SIngo Molnar snprintf(sympltname, sizeof(sympltname), 109386470930SIngo Molnar "%s@plt", elf_sym__name(&sym, symstrs)); 109486470930SIngo Molnar 109586470930SIngo Molnar f = symbol__new(plt_offset, shdr_plt.sh_entsize, 1096c408fedfSArnaldo Carvalho de Melo STB_GLOBAL, sympltname); 109786470930SIngo Molnar if (!f) 1098a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 109986470930SIngo Molnar 110082164161SArnaldo Carvalho de Melo if (filter && filter(map, f)) 110182164161SArnaldo Carvalho de Melo symbol__delete(f); 110282164161SArnaldo Carvalho de Melo else { 1103aeafcbafSArnaldo Carvalho de Melo symbols__insert(&dso->symbols[map->type], f); 110486470930SIngo Molnar ++nr; 110586470930SIngo Molnar } 110682164161SArnaldo Carvalho de Melo } 110786470930SIngo Molnar } else if (shdr_rel_plt.sh_type == SHT_REL) { 110886470930SIngo Molnar GElf_Rel pos_mem, *pos; 110986470930SIngo Molnar elf_section__for_each_rel(reldata, pos, pos_mem, idx, 111086470930SIngo Molnar nr_rel_entries) { 111186470930SIngo Molnar symidx = GELF_R_SYM(pos->r_info); 111286470930SIngo Molnar plt_offset += shdr_plt.sh_entsize; 111386470930SIngo Molnar gelf_getsym(syms, symidx, &sym); 111486470930SIngo Molnar snprintf(sympltname, sizeof(sympltname), 111586470930SIngo Molnar "%s@plt", elf_sym__name(&sym, symstrs)); 111686470930SIngo Molnar 111786470930SIngo Molnar f = symbol__new(plt_offset, shdr_plt.sh_entsize, 1118c408fedfSArnaldo Carvalho de Melo STB_GLOBAL, sympltname); 111986470930SIngo Molnar if (!f) 1120a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 112186470930SIngo Molnar 112282164161SArnaldo Carvalho de Melo if (filter && filter(map, f)) 112382164161SArnaldo Carvalho de Melo symbol__delete(f); 112482164161SArnaldo Carvalho de Melo else { 1125aeafcbafSArnaldo Carvalho de Melo symbols__insert(&dso->symbols[map->type], f); 112686470930SIngo Molnar ++nr; 112786470930SIngo Molnar } 112886470930SIngo Molnar } 112982164161SArnaldo Carvalho de Melo } 113086470930SIngo Molnar 1131a25e46c4SArnaldo Carvalho de Melo err = 0; 1132a25e46c4SArnaldo Carvalho de Melo out_elf_end: 1133a25e46c4SArnaldo Carvalho de Melo elf_end(elf); 1134a25e46c4SArnaldo Carvalho de Melo out_close: 1135a25e46c4SArnaldo Carvalho de Melo close(fd); 1136a25e46c4SArnaldo Carvalho de Melo 1137a25e46c4SArnaldo Carvalho de Melo if (err == 0) 113886470930SIngo Molnar return nr; 1139a25e46c4SArnaldo Carvalho de Melo out: 1140fe2197b8SArnaldo Carvalho de Melo pr_debug("%s: problems reading %s PLT info.\n", 1141aeafcbafSArnaldo Carvalho de Melo __func__, dso->long_name); 1142a25e46c4SArnaldo Carvalho de Melo return 0; 114386470930SIngo Molnar } 114486470930SIngo Molnar 1145aeafcbafSArnaldo Carvalho de Melo static bool elf_sym__is_a(GElf_Sym *sym, enum map_type type) 1146d45868d3SArnaldo Carvalho de Melo { 1147d45868d3SArnaldo Carvalho de Melo switch (type) { 1148d45868d3SArnaldo Carvalho de Melo case MAP__FUNCTION: 1149aeafcbafSArnaldo Carvalho de Melo return elf_sym__is_function(sym); 1150f1dfa0b1SArnaldo Carvalho de Melo case MAP__VARIABLE: 1151aeafcbafSArnaldo Carvalho de Melo return elf_sym__is_object(sym); 1152d45868d3SArnaldo Carvalho de Melo default: 1153d45868d3SArnaldo Carvalho de Melo return false; 1154d45868d3SArnaldo Carvalho de Melo } 1155d45868d3SArnaldo Carvalho de Melo } 1156d45868d3SArnaldo Carvalho de Melo 1157aeafcbafSArnaldo Carvalho de Melo static bool elf_sec__is_a(GElf_Shdr *shdr, Elf_Data *secstrs, 1158aeafcbafSArnaldo Carvalho de Melo enum map_type type) 1159d45868d3SArnaldo Carvalho de Melo { 1160d45868d3SArnaldo Carvalho de Melo switch (type) { 1161d45868d3SArnaldo Carvalho de Melo case MAP__FUNCTION: 1162aeafcbafSArnaldo Carvalho de Melo return elf_sec__is_text(shdr, secstrs); 1163f1dfa0b1SArnaldo Carvalho de Melo case MAP__VARIABLE: 1164aeafcbafSArnaldo Carvalho de Melo return elf_sec__is_data(shdr, secstrs); 1165d45868d3SArnaldo Carvalho de Melo default: 1166d45868d3SArnaldo Carvalho de Melo return false; 1167d45868d3SArnaldo Carvalho de Melo } 1168d45868d3SArnaldo Carvalho de Melo } 1169d45868d3SArnaldo Carvalho de Melo 117070c3856bSEric B Munson static size_t elf_addr_to_index(Elf *elf, GElf_Addr addr) 117170c3856bSEric B Munson { 117270c3856bSEric B Munson Elf_Scn *sec = NULL; 117370c3856bSEric B Munson GElf_Shdr shdr; 117470c3856bSEric B Munson size_t cnt = 1; 117570c3856bSEric B Munson 117670c3856bSEric B Munson while ((sec = elf_nextscn(elf, sec)) != NULL) { 117770c3856bSEric B Munson gelf_getshdr(sec, &shdr); 117870c3856bSEric B Munson 117970c3856bSEric B Munson if ((addr >= shdr.sh_addr) && 118070c3856bSEric B Munson (addr < (shdr.sh_addr + shdr.sh_size))) 118170c3856bSEric B Munson return cnt; 118270c3856bSEric B Munson 118370c3856bSEric B Munson ++cnt; 118470c3856bSEric B Munson } 118570c3856bSEric B Munson 118670c3856bSEric B Munson return -1; 118770c3856bSEric B Munson } 118870c3856bSEric B Munson 11898db4841fSJiri Olsa static int dso__swap_init(struct dso *dso, unsigned char eidata) 11908db4841fSJiri Olsa { 11918db4841fSJiri Olsa static unsigned int const endian = 1; 11928db4841fSJiri Olsa 11938db4841fSJiri Olsa dso->needs_swap = DSO_SWAP__NO; 11948db4841fSJiri Olsa 11958db4841fSJiri Olsa switch (eidata) { 11968db4841fSJiri Olsa case ELFDATA2LSB: 11978db4841fSJiri Olsa /* We are big endian, DSO is little endian. */ 11988db4841fSJiri Olsa if (*(unsigned char const *)&endian != 1) 11998db4841fSJiri Olsa dso->needs_swap = DSO_SWAP__YES; 12008db4841fSJiri Olsa break; 12018db4841fSJiri Olsa 12028db4841fSJiri Olsa case ELFDATA2MSB: 12038db4841fSJiri Olsa /* We are little endian, DSO is big endian. */ 12048db4841fSJiri Olsa if (*(unsigned char const *)&endian != 0) 12058db4841fSJiri Olsa dso->needs_swap = DSO_SWAP__YES; 12068db4841fSJiri Olsa break; 12078db4841fSJiri Olsa 12088db4841fSJiri Olsa default: 12098db4841fSJiri Olsa pr_err("unrecognized DSO data encoding %d\n", eidata); 12108db4841fSJiri Olsa return -EINVAL; 12118db4841fSJiri Olsa } 12128db4841fSJiri Olsa 12138db4841fSJiri Olsa return 0; 12148db4841fSJiri Olsa } 12158db4841fSJiri Olsa 1216aeafcbafSArnaldo Carvalho de Melo static int dso__load_sym(struct dso *dso, struct map *map, const char *name, 12176da80ce8SDave Martin int fd, symbol_filter_t filter, int kmodule, 12186da80ce8SDave Martin int want_symtab) 121986470930SIngo Molnar { 1220aeafcbafSArnaldo Carvalho de Melo struct kmap *kmap = dso->kernel ? map__kmap(map) : NULL; 12212e538c4aSArnaldo Carvalho de Melo struct map *curr_map = map; 1222aeafcbafSArnaldo Carvalho de Melo struct dso *curr_dso = dso; 12236cfcc53eSMike Galbraith Elf_Data *symstrs, *secstrs; 122486470930SIngo Molnar uint32_t nr_syms; 122586470930SIngo Molnar int err = -1; 122683a0944fSIngo Molnar uint32_t idx; 122786470930SIngo Molnar GElf_Ehdr ehdr; 122870c3856bSEric B Munson GElf_Shdr shdr, opdshdr; 122970c3856bSEric B Munson Elf_Data *syms, *opddata = NULL; 123086470930SIngo Molnar GElf_Sym sym; 123170c3856bSEric B Munson Elf_Scn *sec, *sec_strndx, *opdsec; 123286470930SIngo Molnar Elf *elf; 1233439d473bSArnaldo Carvalho de Melo int nr = 0; 123470c3856bSEric B Munson size_t opdidx = 0; 123586470930SIngo Molnar 123684087126SMarti Raudsepp elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 123786470930SIngo Molnar if (elf == NULL) { 12388b1389efSDave Martin pr_debug("%s: cannot read %s ELF file.\n", __func__, name); 123986470930SIngo Molnar goto out_close; 124086470930SIngo Molnar } 124186470930SIngo Molnar 124286470930SIngo Molnar if (gelf_getehdr(elf, &ehdr) == NULL) { 12438b1389efSDave Martin pr_debug("%s: cannot get elf header.\n", __func__); 124486470930SIngo Molnar goto out_elf_end; 124586470930SIngo Molnar } 124686470930SIngo Molnar 12478db4841fSJiri Olsa if (dso__swap_init(dso, ehdr.e_ident[EI_DATA])) 12488db4841fSJiri Olsa goto out_elf_end; 12498db4841fSJiri Olsa 12506da80ce8SDave Martin /* Always reject images with a mismatched build-id: */ 1251aeafcbafSArnaldo Carvalho de Melo if (dso->has_build_id) { 125221916c38SDave Martin u8 build_id[BUILD_ID_SIZE]; 125321916c38SDave Martin 1254be96ea8fSStephane Eranian if (elf_read_build_id(elf, build_id, BUILD_ID_SIZE) < 0) 125521916c38SDave Martin goto out_elf_end; 125621916c38SDave Martin 1257aeafcbafSArnaldo Carvalho de Melo if (!dso__build_id_equal(dso, build_id)) 125821916c38SDave Martin goto out_elf_end; 125921916c38SDave Martin } 126021916c38SDave Martin 126186470930SIngo Molnar sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL); 126286470930SIngo Molnar if (sec == NULL) { 12636da80ce8SDave Martin if (want_symtab) 12646da80ce8SDave Martin goto out_elf_end; 12656da80ce8SDave Martin 1266a25e46c4SArnaldo Carvalho de Melo sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL); 1267a25e46c4SArnaldo Carvalho de Melo if (sec == NULL) 126886470930SIngo Molnar goto out_elf_end; 126986470930SIngo Molnar } 127086470930SIngo Molnar 127170c3856bSEric B Munson opdsec = elf_section_by_name(elf, &ehdr, &opdshdr, ".opd", &opdidx); 1272adb09184SAnton Blanchard if (opdshdr.sh_type != SHT_PROGBITS) 1273adb09184SAnton Blanchard opdsec = NULL; 127470c3856bSEric B Munson if (opdsec) 127570c3856bSEric B Munson opddata = elf_rawdata(opdsec, NULL); 127670c3856bSEric B Munson 127786470930SIngo Molnar syms = elf_getdata(sec, NULL); 127886470930SIngo Molnar if (syms == NULL) 127986470930SIngo Molnar goto out_elf_end; 128086470930SIngo Molnar 128186470930SIngo Molnar sec = elf_getscn(elf, shdr.sh_link); 128286470930SIngo Molnar if (sec == NULL) 128386470930SIngo Molnar goto out_elf_end; 128486470930SIngo Molnar 128586470930SIngo Molnar symstrs = elf_getdata(sec, NULL); 128686470930SIngo Molnar if (symstrs == NULL) 128786470930SIngo Molnar goto out_elf_end; 128886470930SIngo Molnar 12896cfcc53eSMike Galbraith sec_strndx = elf_getscn(elf, ehdr.e_shstrndx); 12906cfcc53eSMike Galbraith if (sec_strndx == NULL) 12916cfcc53eSMike Galbraith goto out_elf_end; 12926cfcc53eSMike Galbraith 12936cfcc53eSMike Galbraith secstrs = elf_getdata(sec_strndx, NULL); 12949b30a26bSStoyan Gaydarov if (secstrs == NULL) 12956cfcc53eSMike Galbraith goto out_elf_end; 12966cfcc53eSMike Galbraith 129786470930SIngo Molnar nr_syms = shdr.sh_size / shdr.sh_entsize; 129886470930SIngo Molnar 1299e9fbc9dcSArjan van de Ven memset(&sym, 0, sizeof(sym)); 1300aeafcbafSArnaldo Carvalho de Melo if (dso->kernel == DSO_TYPE_USER) { 1301aeafcbafSArnaldo Carvalho de Melo dso->adjust_symbols = (ehdr.e_type == ET_EXEC || 130230d7a77dSArnaldo Carvalho de Melo elf_section_by_name(elf, &ehdr, &shdr, 1303f5812a7aSArnaldo Carvalho de Melo ".gnu.prelink_undo", 130430d7a77dSArnaldo Carvalho de Melo NULL) != NULL); 1305aeafcbafSArnaldo Carvalho de Melo } else { 1306aeafcbafSArnaldo Carvalho de Melo dso->adjust_symbols = 0; 1307aeafcbafSArnaldo Carvalho de Melo } 130883a0944fSIngo Molnar elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) { 130986470930SIngo Molnar struct symbol *f; 131056b03f3cSArnaldo Carvalho de Melo const char *elf_name = elf_sym__name(&sym, symstrs); 13112e538c4aSArnaldo Carvalho de Melo char *demangled = NULL; 13126cfcc53eSMike Galbraith int is_label = elf_sym__is_label(&sym); 13136cfcc53eSMike Galbraith const char *section_name; 131486470930SIngo Molnar 13159de89fe7SArnaldo Carvalho de Melo if (kmap && kmap->ref_reloc_sym && kmap->ref_reloc_sym->name && 13169de89fe7SArnaldo Carvalho de Melo strcmp(elf_name, kmap->ref_reloc_sym->name) == 0) 13179de89fe7SArnaldo Carvalho de Melo kmap->ref_reloc_sym->unrelocated_addr = sym.st_value; 131856b03f3cSArnaldo Carvalho de Melo 1319d45868d3SArnaldo Carvalho de Melo if (!is_label && !elf_sym__is_a(&sym, map->type)) 132086470930SIngo Molnar continue; 132186470930SIngo Molnar 1322696b97a5SDave Martin /* Reject ARM ELF "mapping symbols": these aren't unique and 1323696b97a5SDave Martin * don't identify functions, so will confuse the profile 1324696b97a5SDave Martin * output: */ 1325696b97a5SDave Martin if (ehdr.e_machine == EM_ARM) { 1326696b97a5SDave Martin if (!strcmp(elf_name, "$a") || 1327696b97a5SDave Martin !strcmp(elf_name, "$d") || 1328696b97a5SDave Martin !strcmp(elf_name, "$t")) 1329696b97a5SDave Martin continue; 1330696b97a5SDave Martin } 1331696b97a5SDave Martin 133270c3856bSEric B Munson if (opdsec && sym.st_shndx == opdidx) { 133370c3856bSEric B Munson u32 offset = sym.st_value - opdshdr.sh_addr; 133470c3856bSEric B Munson u64 *opd = opddata->d_buf + offset; 13358db4841fSJiri Olsa sym.st_value = DSO__SWAP(dso, u64, *opd); 133670c3856bSEric B Munson sym.st_shndx = elf_addr_to_index(elf, sym.st_value); 133770c3856bSEric B Munson } 133870c3856bSEric B Munson 133986470930SIngo Molnar sec = elf_getscn(elf, sym.st_shndx); 134086470930SIngo Molnar if (!sec) 134186470930SIngo Molnar goto out_elf_end; 134286470930SIngo Molnar 134386470930SIngo Molnar gelf_getshdr(sec, &shdr); 13446cfcc53eSMike Galbraith 1345d45868d3SArnaldo Carvalho de Melo if (is_label && !elf_sec__is_a(&shdr, secstrs, map->type)) 13466cfcc53eSMike Galbraith continue; 13476cfcc53eSMike Galbraith 13486cfcc53eSMike Galbraith section_name = elf_sec__name(&shdr, secstrs); 134986470930SIngo Molnar 1350b2f8fb23SDr. David Alan Gilbert /* On ARM, symbols for thumb functions have 1 added to 1351b2f8fb23SDr. David Alan Gilbert * the symbol address as a flag - remove it */ 1352b2f8fb23SDr. David Alan Gilbert if ((ehdr.e_machine == EM_ARM) && 1353b2f8fb23SDr. David Alan Gilbert (map->type == MAP__FUNCTION) && 1354b2f8fb23SDr. David Alan Gilbert (sym.st_value & 1)) 1355b2f8fb23SDr. David Alan Gilbert --sym.st_value; 1356b2f8fb23SDr. David Alan Gilbert 1357aeafcbafSArnaldo Carvalho de Melo if (dso->kernel != DSO_TYPE_USER || kmodule) { 13582e538c4aSArnaldo Carvalho de Melo char dso_name[PATH_MAX]; 13592e538c4aSArnaldo Carvalho de Melo 13602e538c4aSArnaldo Carvalho de Melo if (strcmp(section_name, 1361b63be8d7SArnaldo Carvalho de Melo (curr_dso->short_name + 1362aeafcbafSArnaldo Carvalho de Melo dso->short_name_len)) == 0) 13632e538c4aSArnaldo Carvalho de Melo goto new_symbol; 13642e538c4aSArnaldo Carvalho de Melo 13652e538c4aSArnaldo Carvalho de Melo if (strcmp(section_name, ".text") == 0) { 13662e538c4aSArnaldo Carvalho de Melo curr_map = map; 1367aeafcbafSArnaldo Carvalho de Melo curr_dso = dso; 13682e538c4aSArnaldo Carvalho de Melo goto new_symbol; 1369af427bf5SArnaldo Carvalho de Melo } 1370af427bf5SArnaldo Carvalho de Melo 13712e538c4aSArnaldo Carvalho de Melo snprintf(dso_name, sizeof(dso_name), 1372aeafcbafSArnaldo Carvalho de Melo "%s%s", dso->short_name, section_name); 13732e538c4aSArnaldo Carvalho de Melo 13749de89fe7SArnaldo Carvalho de Melo curr_map = map_groups__find_by_name(kmap->kmaps, map->type, dso_name); 13752e538c4aSArnaldo Carvalho de Melo if (curr_map == NULL) { 13762e538c4aSArnaldo Carvalho de Melo u64 start = sym.st_value; 13772e538c4aSArnaldo Carvalho de Melo 13782e538c4aSArnaldo Carvalho de Melo if (kmodule) 13792e538c4aSArnaldo Carvalho de Melo start += map->start + shdr.sh_offset; 13802e538c4aSArnaldo Carvalho de Melo 138100a192b3SArnaldo Carvalho de Melo curr_dso = dso__new(dso_name); 13822e538c4aSArnaldo Carvalho de Melo if (curr_dso == NULL) 13832e538c4aSArnaldo Carvalho de Melo goto out_elf_end; 1384aeafcbafSArnaldo Carvalho de Melo curr_dso->kernel = dso->kernel; 1385aeafcbafSArnaldo Carvalho de Melo curr_dso->long_name = dso->long_name; 1386aeafcbafSArnaldo Carvalho de Melo curr_dso->long_name_len = dso->long_name_len; 13873610583cSArnaldo Carvalho de Melo curr_map = map__new2(start, curr_dso, 13886275ce2dSArnaldo Carvalho de Melo map->type); 13892e538c4aSArnaldo Carvalho de Melo if (curr_map == NULL) { 13902e538c4aSArnaldo Carvalho de Melo dso__delete(curr_dso); 13912e538c4aSArnaldo Carvalho de Melo goto out_elf_end; 13922e538c4aSArnaldo Carvalho de Melo } 1393ed52ce2eSArnaldo Carvalho de Melo curr_map->map_ip = identity__map_ip; 1394ed52ce2eSArnaldo Carvalho de Melo curr_map->unmap_ip = identity__map_ip; 1395aeafcbafSArnaldo Carvalho de Melo curr_dso->symtab_type = dso->symtab_type; 13969de89fe7SArnaldo Carvalho de Melo map_groups__insert(kmap->kmaps, curr_map); 1397aeafcbafSArnaldo Carvalho de Melo dsos__add(&dso->node, curr_dso); 13986275ce2dSArnaldo Carvalho de Melo dso__set_loaded(curr_dso, map->type); 13992e538c4aSArnaldo Carvalho de Melo } else 14002e538c4aSArnaldo Carvalho de Melo curr_dso = curr_map->dso; 14012e538c4aSArnaldo Carvalho de Melo 14022e538c4aSArnaldo Carvalho de Melo goto new_symbol; 14032e538c4aSArnaldo Carvalho de Melo } 14042e538c4aSArnaldo Carvalho de Melo 14052e538c4aSArnaldo Carvalho de Melo if (curr_dso->adjust_symbols) { 14069486aa38SArnaldo Carvalho de Melo pr_debug4("%s: adjusting symbol: st_value: %#" PRIx64 " " 14079486aa38SArnaldo Carvalho de Melo "sh_addr: %#" PRIx64 " sh_offset: %#" PRIx64 "\n", __func__, 140829a9f66dSArnaldo Carvalho de Melo (u64)sym.st_value, (u64)shdr.sh_addr, 140929a9f66dSArnaldo Carvalho de Melo (u64)shdr.sh_offset); 141086470930SIngo Molnar sym.st_value -= shdr.sh_addr - shdr.sh_offset; 1411af427bf5SArnaldo Carvalho de Melo } 141228ac909bSArnaldo Carvalho de Melo /* 141328ac909bSArnaldo Carvalho de Melo * We need to figure out if the object was created from C++ sources 141428ac909bSArnaldo Carvalho de Melo * DWARF DW_compile_unit has this, but we don't always have access 141528ac909bSArnaldo Carvalho de Melo * to it... 141628ac909bSArnaldo Carvalho de Melo */ 141783a0944fSIngo Molnar demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI); 141828ac909bSArnaldo Carvalho de Melo if (demangled != NULL) 141983a0944fSIngo Molnar elf_name = demangled; 14202e538c4aSArnaldo Carvalho de Melo new_symbol: 1421c408fedfSArnaldo Carvalho de Melo f = symbol__new(sym.st_value, sym.st_size, 1422c408fedfSArnaldo Carvalho de Melo GELF_ST_BIND(sym.st_info), elf_name); 142328ac909bSArnaldo Carvalho de Melo free(demangled); 142486470930SIngo Molnar if (!f) 142586470930SIngo Molnar goto out_elf_end; 142686470930SIngo Molnar 14272e538c4aSArnaldo Carvalho de Melo if (filter && filter(curr_map, f)) 142800a192b3SArnaldo Carvalho de Melo symbol__delete(f); 142986470930SIngo Molnar else { 14306a4694a4SArnaldo Carvalho de Melo symbols__insert(&curr_dso->symbols[curr_map->type], f); 143186470930SIngo Molnar nr++; 143286470930SIngo Molnar } 143386470930SIngo Molnar } 143486470930SIngo Molnar 14352e538c4aSArnaldo Carvalho de Melo /* 14362e538c4aSArnaldo Carvalho de Melo * For misannotated, zeroed, ASM function sizes. 14372e538c4aSArnaldo Carvalho de Melo */ 14386275ce2dSArnaldo Carvalho de Melo if (nr > 0) { 1439694bf407SAnton Blanchard symbols__fixup_duplicate(&dso->symbols[map->type]); 1440aeafcbafSArnaldo Carvalho de Melo symbols__fixup_end(&dso->symbols[map->type]); 14416275ce2dSArnaldo Carvalho de Melo if (kmap) { 14426275ce2dSArnaldo Carvalho de Melo /* 14436275ce2dSArnaldo Carvalho de Melo * We need to fixup this here too because we create new 14446275ce2dSArnaldo Carvalho de Melo * maps here, for things like vsyscall sections. 14456275ce2dSArnaldo Carvalho de Melo */ 14466275ce2dSArnaldo Carvalho de Melo __map_groups__fixup_end(kmap->kmaps, map->type); 14476275ce2dSArnaldo Carvalho de Melo } 14486275ce2dSArnaldo Carvalho de Melo } 144986470930SIngo Molnar err = nr; 145086470930SIngo Molnar out_elf_end: 145186470930SIngo Molnar elf_end(elf); 145286470930SIngo Molnar out_close: 145386470930SIngo Molnar return err; 145486470930SIngo Molnar } 145586470930SIngo Molnar 1456aeafcbafSArnaldo Carvalho de Melo static bool dso__build_id_equal(const struct dso *dso, u8 *build_id) 145778075caaSArnaldo Carvalho de Melo { 1458aeafcbafSArnaldo Carvalho de Melo return memcmp(dso->build_id, build_id, sizeof(dso->build_id)) == 0; 145978075caaSArnaldo Carvalho de Melo } 146078075caaSArnaldo Carvalho de Melo 1461a1645ce1SZhang, Yanmin bool __dsos__read_build_ids(struct list_head *head, bool with_hits) 146257f395a7SFrederic Weisbecker { 1463e30a3d12SArnaldo Carvalho de Melo bool have_build_id = false; 146457f395a7SFrederic Weisbecker struct dso *pos; 146557f395a7SFrederic Weisbecker 14666122e4e4SArnaldo Carvalho de Melo list_for_each_entry(pos, head, node) { 14676122e4e4SArnaldo Carvalho de Melo if (with_hits && !pos->hit) 14686122e4e4SArnaldo Carvalho de Melo continue; 1469f6e1467dSArnaldo Carvalho de Melo if (pos->has_build_id) { 1470f6e1467dSArnaldo Carvalho de Melo have_build_id = true; 1471f6e1467dSArnaldo Carvalho de Melo continue; 1472f6e1467dSArnaldo Carvalho de Melo } 1473e30a3d12SArnaldo Carvalho de Melo if (filename__read_build_id(pos->long_name, pos->build_id, 1474e30a3d12SArnaldo Carvalho de Melo sizeof(pos->build_id)) > 0) { 1475e30a3d12SArnaldo Carvalho de Melo have_build_id = true; 1476e30a3d12SArnaldo Carvalho de Melo pos->has_build_id = true; 147757f395a7SFrederic Weisbecker } 14786122e4e4SArnaldo Carvalho de Melo } 147957f395a7SFrederic Weisbecker 1480e30a3d12SArnaldo Carvalho de Melo return have_build_id; 148157f395a7SFrederic Weisbecker } 148257f395a7SFrederic Weisbecker 1483fd7a346eSArnaldo Carvalho de Melo /* 1484fd7a346eSArnaldo Carvalho de Melo * Align offset to 4 bytes as needed for note name and descriptor data. 1485fd7a346eSArnaldo Carvalho de Melo */ 1486fd7a346eSArnaldo Carvalho de Melo #define NOTE_ALIGN(n) (((n) + 3) & -4U) 1487fd7a346eSArnaldo Carvalho de Melo 148821916c38SDave Martin static int elf_read_build_id(Elf *elf, void *bf, size_t size) 14894d1e00a8SArnaldo Carvalho de Melo { 149021916c38SDave Martin int err = -1; 14914d1e00a8SArnaldo Carvalho de Melo GElf_Ehdr ehdr; 14924d1e00a8SArnaldo Carvalho de Melo GElf_Shdr shdr; 1493fd7a346eSArnaldo Carvalho de Melo Elf_Data *data; 14944d1e00a8SArnaldo Carvalho de Melo Elf_Scn *sec; 1495e57cfcdaSPekka Enberg Elf_Kind ek; 1496fd7a346eSArnaldo Carvalho de Melo void *ptr; 14974d1e00a8SArnaldo Carvalho de Melo 14982643ce11SArnaldo Carvalho de Melo if (size < BUILD_ID_SIZE) 14992643ce11SArnaldo Carvalho de Melo goto out; 15002643ce11SArnaldo Carvalho de Melo 1501e57cfcdaSPekka Enberg ek = elf_kind(elf); 1502e57cfcdaSPekka Enberg if (ek != ELF_K_ELF) 150321916c38SDave Martin goto out; 1504e57cfcdaSPekka Enberg 15054d1e00a8SArnaldo Carvalho de Melo if (gelf_getehdr(elf, &ehdr) == NULL) { 15066beba7adSArnaldo Carvalho de Melo pr_err("%s: cannot get elf header.\n", __func__); 150721916c38SDave Martin goto out; 15084d1e00a8SArnaldo Carvalho de Melo } 15094d1e00a8SArnaldo Carvalho de Melo 15101388d715SJiri Olsa /* 15111388d715SJiri Olsa * Check following sections for notes: 15121388d715SJiri Olsa * '.note.gnu.build-id' 15131388d715SJiri Olsa * '.notes' 15141388d715SJiri Olsa * '.note' (VDSO specific) 15151388d715SJiri Olsa */ 15161388d715SJiri Olsa do { 15172643ce11SArnaldo Carvalho de Melo sec = elf_section_by_name(elf, &ehdr, &shdr, 15182643ce11SArnaldo Carvalho de Melo ".note.gnu.build-id", NULL); 15191388d715SJiri Olsa if (sec) 15201388d715SJiri Olsa break; 15211388d715SJiri Olsa 1522fd7a346eSArnaldo Carvalho de Melo sec = elf_section_by_name(elf, &ehdr, &shdr, 1523fd7a346eSArnaldo Carvalho de Melo ".notes", NULL); 15241388d715SJiri Olsa if (sec) 15251388d715SJiri Olsa break; 15261388d715SJiri Olsa 15271388d715SJiri Olsa sec = elf_section_by_name(elf, &ehdr, &shdr, 15281388d715SJiri Olsa ".note", NULL); 15291388d715SJiri Olsa if (sec) 15301388d715SJiri Olsa break; 15311388d715SJiri Olsa 15321388d715SJiri Olsa return err; 15331388d715SJiri Olsa 15341388d715SJiri Olsa } while (0); 15354d1e00a8SArnaldo Carvalho de Melo 1536fd7a346eSArnaldo Carvalho de Melo data = elf_getdata(sec, NULL); 1537fd7a346eSArnaldo Carvalho de Melo if (data == NULL) 153821916c38SDave Martin goto out; 1539fd7a346eSArnaldo Carvalho de Melo 1540fd7a346eSArnaldo Carvalho de Melo ptr = data->d_buf; 1541fd7a346eSArnaldo Carvalho de Melo while (ptr < (data->d_buf + data->d_size)) { 1542fd7a346eSArnaldo Carvalho de Melo GElf_Nhdr *nhdr = ptr; 1543be96ea8fSStephane Eranian size_t namesz = NOTE_ALIGN(nhdr->n_namesz), 1544fd7a346eSArnaldo Carvalho de Melo descsz = NOTE_ALIGN(nhdr->n_descsz); 1545fd7a346eSArnaldo Carvalho de Melo const char *name; 1546fd7a346eSArnaldo Carvalho de Melo 1547fd7a346eSArnaldo Carvalho de Melo ptr += sizeof(*nhdr); 1548fd7a346eSArnaldo Carvalho de Melo name = ptr; 1549fd7a346eSArnaldo Carvalho de Melo ptr += namesz; 1550fd7a346eSArnaldo Carvalho de Melo if (nhdr->n_type == NT_GNU_BUILD_ID && 1551fd7a346eSArnaldo Carvalho de Melo nhdr->n_namesz == sizeof("GNU")) { 1552fd7a346eSArnaldo Carvalho de Melo if (memcmp(name, "GNU", sizeof("GNU")) == 0) { 1553be96ea8fSStephane Eranian size_t sz = min(size, descsz); 1554be96ea8fSStephane Eranian memcpy(bf, ptr, sz); 1555be96ea8fSStephane Eranian memset(bf + sz, 0, size - sz); 1556be96ea8fSStephane Eranian err = descsz; 1557fd7a346eSArnaldo Carvalho de Melo break; 1558fd7a346eSArnaldo Carvalho de Melo } 1559fd7a346eSArnaldo Carvalho de Melo } 1560fd7a346eSArnaldo Carvalho de Melo ptr += descsz; 1561fd7a346eSArnaldo Carvalho de Melo } 156221916c38SDave Martin 156321916c38SDave Martin out: 156421916c38SDave Martin return err; 156521916c38SDave Martin } 156621916c38SDave Martin 156721916c38SDave Martin int filename__read_build_id(const char *filename, void *bf, size_t size) 156821916c38SDave Martin { 156921916c38SDave Martin int fd, err = -1; 157021916c38SDave Martin Elf *elf; 157121916c38SDave Martin 157221916c38SDave Martin if (size < BUILD_ID_SIZE) 157321916c38SDave Martin goto out; 157421916c38SDave Martin 157521916c38SDave Martin fd = open(filename, O_RDONLY); 157621916c38SDave Martin if (fd < 0) 157721916c38SDave Martin goto out; 157821916c38SDave Martin 157921916c38SDave Martin elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 158021916c38SDave Martin if (elf == NULL) { 158121916c38SDave Martin pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename); 158221916c38SDave Martin goto out_close; 158321916c38SDave Martin } 158421916c38SDave Martin 158521916c38SDave Martin err = elf_read_build_id(elf, bf, size); 158621916c38SDave Martin 15872643ce11SArnaldo Carvalho de Melo elf_end(elf); 15882643ce11SArnaldo Carvalho de Melo out_close: 15892643ce11SArnaldo Carvalho de Melo close(fd); 15902643ce11SArnaldo Carvalho de Melo out: 15912643ce11SArnaldo Carvalho de Melo return err; 15922643ce11SArnaldo Carvalho de Melo } 15932643ce11SArnaldo Carvalho de Melo 1594f1617b40SArnaldo Carvalho de Melo int sysfs__read_build_id(const char *filename, void *build_id, size_t size) 1595f1617b40SArnaldo Carvalho de Melo { 1596f1617b40SArnaldo Carvalho de Melo int fd, err = -1; 1597f1617b40SArnaldo Carvalho de Melo 1598f1617b40SArnaldo Carvalho de Melo if (size < BUILD_ID_SIZE) 1599f1617b40SArnaldo Carvalho de Melo goto out; 1600f1617b40SArnaldo Carvalho de Melo 1601f1617b40SArnaldo Carvalho de Melo fd = open(filename, O_RDONLY); 1602f1617b40SArnaldo Carvalho de Melo if (fd < 0) 1603f1617b40SArnaldo Carvalho de Melo goto out; 1604f1617b40SArnaldo Carvalho de Melo 1605f1617b40SArnaldo Carvalho de Melo while (1) { 1606f1617b40SArnaldo Carvalho de Melo char bf[BUFSIZ]; 1607f1617b40SArnaldo Carvalho de Melo GElf_Nhdr nhdr; 1608be96ea8fSStephane Eranian size_t namesz, descsz; 1609f1617b40SArnaldo Carvalho de Melo 1610f1617b40SArnaldo Carvalho de Melo if (read(fd, &nhdr, sizeof(nhdr)) != sizeof(nhdr)) 1611f1617b40SArnaldo Carvalho de Melo break; 1612f1617b40SArnaldo Carvalho de Melo 1613fd7a346eSArnaldo Carvalho de Melo namesz = NOTE_ALIGN(nhdr.n_namesz); 1614fd7a346eSArnaldo Carvalho de Melo descsz = NOTE_ALIGN(nhdr.n_descsz); 1615f1617b40SArnaldo Carvalho de Melo if (nhdr.n_type == NT_GNU_BUILD_ID && 1616f1617b40SArnaldo Carvalho de Melo nhdr.n_namesz == sizeof("GNU")) { 1617be96ea8fSStephane Eranian if (read(fd, bf, namesz) != (ssize_t)namesz) 1618f1617b40SArnaldo Carvalho de Melo break; 1619f1617b40SArnaldo Carvalho de Melo if (memcmp(bf, "GNU", sizeof("GNU")) == 0) { 1620be96ea8fSStephane Eranian size_t sz = min(descsz, size); 1621be96ea8fSStephane Eranian if (read(fd, build_id, sz) == (ssize_t)sz) { 1622be96ea8fSStephane Eranian memset(build_id + sz, 0, size - sz); 1623f1617b40SArnaldo Carvalho de Melo err = 0; 1624f1617b40SArnaldo Carvalho de Melo break; 1625f1617b40SArnaldo Carvalho de Melo } 1626be96ea8fSStephane Eranian } else if (read(fd, bf, descsz) != (ssize_t)descsz) 1627f1617b40SArnaldo Carvalho de Melo break; 1628f1617b40SArnaldo Carvalho de Melo } else { 1629f1617b40SArnaldo Carvalho de Melo int n = namesz + descsz; 1630f1617b40SArnaldo Carvalho de Melo if (read(fd, bf, n) != n) 1631f1617b40SArnaldo Carvalho de Melo break; 1632f1617b40SArnaldo Carvalho de Melo } 1633f1617b40SArnaldo Carvalho de Melo } 1634f1617b40SArnaldo Carvalho de Melo close(fd); 1635f1617b40SArnaldo Carvalho de Melo out: 1636f1617b40SArnaldo Carvalho de Melo return err; 1637f1617b40SArnaldo Carvalho de Melo } 1638f1617b40SArnaldo Carvalho de Melo 1639209bd9e3SPierre-Loup A. Griffais static int filename__read_debuglink(const char *filename, 1640209bd9e3SPierre-Loup A. Griffais char *debuglink, size_t size) 1641209bd9e3SPierre-Loup A. Griffais { 1642209bd9e3SPierre-Loup A. Griffais int fd, err = -1; 1643209bd9e3SPierre-Loup A. Griffais Elf *elf; 1644209bd9e3SPierre-Loup A. Griffais GElf_Ehdr ehdr; 1645209bd9e3SPierre-Loup A. Griffais GElf_Shdr shdr; 1646209bd9e3SPierre-Loup A. Griffais Elf_Data *data; 1647209bd9e3SPierre-Loup A. Griffais Elf_Scn *sec; 1648209bd9e3SPierre-Loup A. Griffais Elf_Kind ek; 1649209bd9e3SPierre-Loup A. Griffais 1650209bd9e3SPierre-Loup A. Griffais fd = open(filename, O_RDONLY); 1651209bd9e3SPierre-Loup A. Griffais if (fd < 0) 1652209bd9e3SPierre-Loup A. Griffais goto out; 1653209bd9e3SPierre-Loup A. Griffais 1654209bd9e3SPierre-Loup A. Griffais elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 1655209bd9e3SPierre-Loup A. Griffais if (elf == NULL) { 1656209bd9e3SPierre-Loup A. Griffais pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename); 1657209bd9e3SPierre-Loup A. Griffais goto out_close; 1658209bd9e3SPierre-Loup A. Griffais } 1659209bd9e3SPierre-Loup A. Griffais 1660209bd9e3SPierre-Loup A. Griffais ek = elf_kind(elf); 1661209bd9e3SPierre-Loup A. Griffais if (ek != ELF_K_ELF) 1662209bd9e3SPierre-Loup A. Griffais goto out_close; 1663209bd9e3SPierre-Loup A. Griffais 1664209bd9e3SPierre-Loup A. Griffais if (gelf_getehdr(elf, &ehdr) == NULL) { 1665209bd9e3SPierre-Loup A. Griffais pr_err("%s: cannot get elf header.\n", __func__); 1666209bd9e3SPierre-Loup A. Griffais goto out_close; 1667209bd9e3SPierre-Loup A. Griffais } 1668209bd9e3SPierre-Loup A. Griffais 1669209bd9e3SPierre-Loup A. Griffais sec = elf_section_by_name(elf, &ehdr, &shdr, 1670209bd9e3SPierre-Loup A. Griffais ".gnu_debuglink", NULL); 1671209bd9e3SPierre-Loup A. Griffais if (sec == NULL) 1672209bd9e3SPierre-Loup A. Griffais goto out_close; 1673209bd9e3SPierre-Loup A. Griffais 1674209bd9e3SPierre-Loup A. Griffais data = elf_getdata(sec, NULL); 1675209bd9e3SPierre-Loup A. Griffais if (data == NULL) 1676209bd9e3SPierre-Loup A. Griffais goto out_close; 1677209bd9e3SPierre-Loup A. Griffais 1678209bd9e3SPierre-Loup A. Griffais /* the start of this section is a zero-terminated string */ 1679209bd9e3SPierre-Loup A. Griffais strncpy(debuglink, data->d_buf, size); 1680209bd9e3SPierre-Loup A. Griffais 1681209bd9e3SPierre-Loup A. Griffais elf_end(elf); 1682209bd9e3SPierre-Loup A. Griffais 1683209bd9e3SPierre-Loup A. Griffais out_close: 1684209bd9e3SPierre-Loup A. Griffais close(fd); 1685209bd9e3SPierre-Loup A. Griffais out: 1686209bd9e3SPierre-Loup A. Griffais return err; 1687209bd9e3SPierre-Loup A. Griffais } 1688209bd9e3SPierre-Loup A. Griffais 1689aeafcbafSArnaldo Carvalho de Melo char dso__symtab_origin(const struct dso *dso) 169094cb9e38SArnaldo Carvalho de Melo { 169194cb9e38SArnaldo Carvalho de Melo static const char origin[] = { 169244f24cb3SJiri Olsa [DSO_BINARY_TYPE__KALLSYMS] = 'k', 169344f24cb3SJiri Olsa [DSO_BINARY_TYPE__JAVA_JIT] = 'j', 169444f24cb3SJiri Olsa [DSO_BINARY_TYPE__DEBUGLINK] = 'l', 169544f24cb3SJiri Olsa [DSO_BINARY_TYPE__BUILD_ID_CACHE] = 'B', 169644f24cb3SJiri Olsa [DSO_BINARY_TYPE__FEDORA_DEBUGINFO] = 'f', 169744f24cb3SJiri Olsa [DSO_BINARY_TYPE__UBUNTU_DEBUGINFO] = 'u', 169844f24cb3SJiri Olsa [DSO_BINARY_TYPE__BUILDID_DEBUGINFO] = 'b', 169944f24cb3SJiri Olsa [DSO_BINARY_TYPE__SYSTEM_PATH_DSO] = 'd', 170044f24cb3SJiri Olsa [DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE] = 'K', 170144f24cb3SJiri Olsa [DSO_BINARY_TYPE__GUEST_KALLSYMS] = 'g', 170244f24cb3SJiri Olsa [DSO_BINARY_TYPE__GUEST_KMODULE] = 'G', 170394cb9e38SArnaldo Carvalho de Melo }; 170494cb9e38SArnaldo Carvalho de Melo 170544f24cb3SJiri Olsa if (dso == NULL || dso->symtab_type == DSO_BINARY_TYPE__NOT_FOUND) 170694cb9e38SArnaldo Carvalho de Melo return '!'; 1707aeafcbafSArnaldo Carvalho de Melo return origin[dso->symtab_type]; 170894cb9e38SArnaldo Carvalho de Melo } 170994cb9e38SArnaldo Carvalho de Melo 171044f24cb3SJiri Olsa int dso__binary_type_file(struct dso *dso, enum dso_binary_type type, 171144f24cb3SJiri Olsa char *root_dir, char *file, size_t size) 171244f24cb3SJiri Olsa { 171344f24cb3SJiri Olsa char build_id_hex[BUILD_ID_SIZE * 2 + 1]; 171444f24cb3SJiri Olsa int ret = 0; 171544f24cb3SJiri Olsa 171644f24cb3SJiri Olsa switch (type) { 171744f24cb3SJiri Olsa case DSO_BINARY_TYPE__DEBUGLINK: { 171844f24cb3SJiri Olsa char *debuglink; 171944f24cb3SJiri Olsa 172044f24cb3SJiri Olsa strncpy(file, dso->long_name, size); 172144f24cb3SJiri Olsa debuglink = file + dso->long_name_len; 172244f24cb3SJiri Olsa while (debuglink != file && *debuglink != '/') 172344f24cb3SJiri Olsa debuglink--; 172444f24cb3SJiri Olsa if (*debuglink == '/') 172544f24cb3SJiri Olsa debuglink++; 172644f24cb3SJiri Olsa filename__read_debuglink(dso->long_name, debuglink, 172744f24cb3SJiri Olsa size - (debuglink - file)); 172844f24cb3SJiri Olsa } 172944f24cb3SJiri Olsa break; 173044f24cb3SJiri Olsa case DSO_BINARY_TYPE__BUILD_ID_CACHE: 173144f24cb3SJiri Olsa /* skip the locally configured cache if a symfs is given */ 173244f24cb3SJiri Olsa if (symbol_conf.symfs[0] || 173344f24cb3SJiri Olsa (dso__build_id_filename(dso, file, size) == NULL)) 173444f24cb3SJiri Olsa ret = -1; 173544f24cb3SJiri Olsa break; 173644f24cb3SJiri Olsa 173744f24cb3SJiri Olsa case DSO_BINARY_TYPE__FEDORA_DEBUGINFO: 173844f24cb3SJiri Olsa snprintf(file, size, "%s/usr/lib/debug%s.debug", 173944f24cb3SJiri Olsa symbol_conf.symfs, dso->long_name); 174044f24cb3SJiri Olsa break; 174144f24cb3SJiri Olsa 174244f24cb3SJiri Olsa case DSO_BINARY_TYPE__UBUNTU_DEBUGINFO: 174344f24cb3SJiri Olsa snprintf(file, size, "%s/usr/lib/debug%s", 174444f24cb3SJiri Olsa symbol_conf.symfs, dso->long_name); 174544f24cb3SJiri Olsa break; 174644f24cb3SJiri Olsa 174744f24cb3SJiri Olsa case DSO_BINARY_TYPE__BUILDID_DEBUGINFO: 174844f24cb3SJiri Olsa if (!dso->has_build_id) { 174944f24cb3SJiri Olsa ret = -1; 175044f24cb3SJiri Olsa break; 175144f24cb3SJiri Olsa } 175244f24cb3SJiri Olsa 175344f24cb3SJiri Olsa build_id__sprintf(dso->build_id, 175444f24cb3SJiri Olsa sizeof(dso->build_id), 175544f24cb3SJiri Olsa build_id_hex); 175644f24cb3SJiri Olsa snprintf(file, size, 175744f24cb3SJiri Olsa "%s/usr/lib/debug/.build-id/%.2s/%s.debug", 175844f24cb3SJiri Olsa symbol_conf.symfs, build_id_hex, build_id_hex + 2); 175944f24cb3SJiri Olsa break; 176044f24cb3SJiri Olsa 176144f24cb3SJiri Olsa case DSO_BINARY_TYPE__SYSTEM_PATH_DSO: 176244f24cb3SJiri Olsa snprintf(file, size, "%s%s", 176344f24cb3SJiri Olsa symbol_conf.symfs, dso->long_name); 176444f24cb3SJiri Olsa break; 176544f24cb3SJiri Olsa 176644f24cb3SJiri Olsa case DSO_BINARY_TYPE__GUEST_KMODULE: 176744f24cb3SJiri Olsa snprintf(file, size, "%s%s%s", symbol_conf.symfs, 176844f24cb3SJiri Olsa root_dir, dso->long_name); 176944f24cb3SJiri Olsa break; 177044f24cb3SJiri Olsa 177144f24cb3SJiri Olsa case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE: 177244f24cb3SJiri Olsa snprintf(file, size, "%s%s", symbol_conf.symfs, 177344f24cb3SJiri Olsa dso->long_name); 177444f24cb3SJiri Olsa break; 177544f24cb3SJiri Olsa 177644f24cb3SJiri Olsa default: 177744f24cb3SJiri Olsa case DSO_BINARY_TYPE__KALLSYMS: 177844f24cb3SJiri Olsa case DSO_BINARY_TYPE__GUEST_KALLSYMS: 177944f24cb3SJiri Olsa case DSO_BINARY_TYPE__JAVA_JIT: 178044f24cb3SJiri Olsa case DSO_BINARY_TYPE__NOT_FOUND: 178144f24cb3SJiri Olsa ret = -1; 178244f24cb3SJiri Olsa break; 178344f24cb3SJiri Olsa } 178444f24cb3SJiri Olsa 178544f24cb3SJiri Olsa return ret; 178644f24cb3SJiri Olsa } 178744f24cb3SJiri Olsa 1788aeafcbafSArnaldo Carvalho de Melo int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter) 178986470930SIngo Molnar { 1790c338aee8SArnaldo Carvalho de Melo char *name; 179186470930SIngo Molnar int ret = -1; 179286470930SIngo Molnar int fd; 179344f24cb3SJiri Olsa u_int i; 179423346f21SArnaldo Carvalho de Melo struct machine *machine; 179544f24cb3SJiri Olsa char *root_dir = (char *) ""; 17966da80ce8SDave Martin int want_symtab; 179786470930SIngo Molnar 1798aeafcbafSArnaldo Carvalho de Melo dso__set_loaded(dso, map->type); 179966bd8424SArnaldo Carvalho de Melo 1800aeafcbafSArnaldo Carvalho de Melo if (dso->kernel == DSO_TYPE_KERNEL) 1801aeafcbafSArnaldo Carvalho de Melo return dso__load_kernel_sym(dso, map, filter); 1802aeafcbafSArnaldo Carvalho de Melo else if (dso->kernel == DSO_TYPE_GUEST_KERNEL) 1803aeafcbafSArnaldo Carvalho de Melo return dso__load_guest_kernel_sym(dso, map, filter); 1804a1645ce1SZhang, Yanmin 180523346f21SArnaldo Carvalho de Melo if (map->groups && map->groups->machine) 180623346f21SArnaldo Carvalho de Melo machine = map->groups->machine; 1807a1645ce1SZhang, Yanmin else 180823346f21SArnaldo Carvalho de Melo machine = NULL; 1809c338aee8SArnaldo Carvalho de Melo 181044f24cb3SJiri Olsa name = malloc(PATH_MAX); 181186470930SIngo Molnar if (!name) 181286470930SIngo Molnar return -1; 181386470930SIngo Molnar 1814aeafcbafSArnaldo Carvalho de Melo dso->adjust_symbols = 0; 1815f5812a7aSArnaldo Carvalho de Melo 1816aeafcbafSArnaldo Carvalho de Melo if (strncmp(dso->name, "/tmp/perf-", 10) == 0) { 1817981c1252SPekka Enberg struct stat st; 1818981c1252SPekka Enberg 1819e9b52ef2SVasiliy Kulikov if (lstat(dso->name, &st) < 0) 1820981c1252SPekka Enberg return -1; 1821981c1252SPekka Enberg 1822981c1252SPekka Enberg if (st.st_uid && (st.st_uid != geteuid())) { 1823981c1252SPekka Enberg pr_warning("File %s not owned by current user or root, " 1824981c1252SPekka Enberg "ignoring it.\n", dso->name); 1825981c1252SPekka Enberg return -1; 1826981c1252SPekka Enberg } 1827981c1252SPekka Enberg 1828aeafcbafSArnaldo Carvalho de Melo ret = dso__load_perf_map(dso, map, filter); 182944f24cb3SJiri Olsa dso->symtab_type = ret > 0 ? DSO_BINARY_TYPE__JAVA_JIT : 183044f24cb3SJiri Olsa DSO_BINARY_TYPE__NOT_FOUND; 183194cb9e38SArnaldo Carvalho de Melo return ret; 183294cb9e38SArnaldo Carvalho de Melo } 183394cb9e38SArnaldo Carvalho de Melo 183444f24cb3SJiri Olsa if (machine) 183544f24cb3SJiri Olsa root_dir = machine->root_dir; 183644f24cb3SJiri Olsa 18376da80ce8SDave Martin /* Iterate over candidate debug images. 18386da80ce8SDave Martin * On the first pass, only load images if they have a full symtab. 18396da80ce8SDave Martin * Failing that, do a second pass where we accept .dynsym also 18406da80ce8SDave Martin */ 184160e4b10cSArnaldo Carvalho de Melo want_symtab = 1; 184260e4b10cSArnaldo Carvalho de Melo restart: 184344f24cb3SJiri Olsa for (i = 0; i < DSO_BINARY_TYPE__SYMTAB_CNT; i++) { 184444f24cb3SJiri Olsa 184544f24cb3SJiri Olsa dso->symtab_type = binary_type_symtab[i]; 184644f24cb3SJiri Olsa 184744f24cb3SJiri Olsa if (dso__binary_type_file(dso, dso->symtab_type, 184844f24cb3SJiri Olsa root_dir, name, PATH_MAX)) 18496da80ce8SDave Martin continue; 185086470930SIngo Molnar 18516da80ce8SDave Martin /* Name is now the name of the next image to try */ 18526da80ce8SDave Martin fd = open(name, O_RDONLY); 18536da80ce8SDave Martin if (fd < 0) 18546da80ce8SDave Martin continue; 18556da80ce8SDave Martin 1856aeafcbafSArnaldo Carvalho de Melo ret = dso__load_sym(dso, map, name, fd, filter, 0, 18576da80ce8SDave Martin want_symtab); 185886470930SIngo Molnar close(fd); 185986470930SIngo Molnar 186086470930SIngo Molnar /* 18616da80ce8SDave Martin * Some people seem to have debuginfo files _WITHOUT_ debug 18626da80ce8SDave Martin * info!?!? 186386470930SIngo Molnar */ 186486470930SIngo Molnar if (!ret) 18656da80ce8SDave Martin continue; 186686470930SIngo Molnar 1867a25e46c4SArnaldo Carvalho de Melo if (ret > 0) { 186833ff581eSJiri Olsa int nr_plt; 186933ff581eSJiri Olsa 187033ff581eSJiri Olsa nr_plt = dso__synthesize_plt_symbols(dso, name, map, filter); 1871a25e46c4SArnaldo Carvalho de Melo if (nr_plt > 0) 1872a25e46c4SArnaldo Carvalho de Melo ret += nr_plt; 18736da80ce8SDave Martin break; 1874a25e46c4SArnaldo Carvalho de Melo } 18756da80ce8SDave Martin } 18766da80ce8SDave Martin 187760e4b10cSArnaldo Carvalho de Melo /* 187860e4b10cSArnaldo Carvalho de Melo * If we wanted a full symtab but no image had one, 187960e4b10cSArnaldo Carvalho de Melo * relax our requirements and repeat the search. 188060e4b10cSArnaldo Carvalho de Melo */ 188160e4b10cSArnaldo Carvalho de Melo if (ret <= 0 && want_symtab) { 188260e4b10cSArnaldo Carvalho de Melo want_symtab = 0; 188360e4b10cSArnaldo Carvalho de Melo goto restart; 188460e4b10cSArnaldo Carvalho de Melo } 188560e4b10cSArnaldo Carvalho de Melo 188686470930SIngo Molnar free(name); 1887aeafcbafSArnaldo Carvalho de Melo if (ret < 0 && strstr(dso->name, " (deleted)") != NULL) 18881340e6bbSArnaldo Carvalho de Melo return 0; 188986470930SIngo Molnar return ret; 189086470930SIngo Molnar } 189186470930SIngo Molnar 1892aeafcbafSArnaldo Carvalho de Melo struct map *map_groups__find_by_name(struct map_groups *mg, 189379406cd7SArnaldo Carvalho de Melo enum map_type type, const char *name) 1894439d473bSArnaldo Carvalho de Melo { 1895439d473bSArnaldo Carvalho de Melo struct rb_node *nd; 1896439d473bSArnaldo Carvalho de Melo 1897aeafcbafSArnaldo Carvalho de Melo for (nd = rb_first(&mg->maps[type]); nd; nd = rb_next(nd)) { 1898439d473bSArnaldo Carvalho de Melo struct map *map = rb_entry(nd, struct map, rb_node); 1899439d473bSArnaldo Carvalho de Melo 1900b7cece76SArnaldo Carvalho de Melo if (map->dso && strcmp(map->dso->short_name, name) == 0) 1901439d473bSArnaldo Carvalho de Melo return map; 1902439d473bSArnaldo Carvalho de Melo } 1903439d473bSArnaldo Carvalho de Melo 1904439d473bSArnaldo Carvalho de Melo return NULL; 1905439d473bSArnaldo Carvalho de Melo } 1906439d473bSArnaldo Carvalho de Melo 1907aeafcbafSArnaldo Carvalho de Melo static int dso__kernel_module_get_build_id(struct dso *dso, 1908a1645ce1SZhang, Yanmin const char *root_dir) 1909b7cece76SArnaldo Carvalho de Melo { 1910b7cece76SArnaldo Carvalho de Melo char filename[PATH_MAX]; 1911b7cece76SArnaldo Carvalho de Melo /* 1912b7cece76SArnaldo Carvalho de Melo * kernel module short names are of the form "[module]" and 1913b7cece76SArnaldo Carvalho de Melo * we need just "module" here. 1914b7cece76SArnaldo Carvalho de Melo */ 1915aeafcbafSArnaldo Carvalho de Melo const char *name = dso->short_name + 1; 1916b7cece76SArnaldo Carvalho de Melo 1917b7cece76SArnaldo Carvalho de Melo snprintf(filename, sizeof(filename), 1918a1645ce1SZhang, Yanmin "%s/sys/module/%.*s/notes/.note.gnu.build-id", 1919a1645ce1SZhang, Yanmin root_dir, (int)strlen(name) - 1, name); 1920b7cece76SArnaldo Carvalho de Melo 1921aeafcbafSArnaldo Carvalho de Melo if (sysfs__read_build_id(filename, dso->build_id, 1922aeafcbafSArnaldo Carvalho de Melo sizeof(dso->build_id)) == 0) 1923aeafcbafSArnaldo Carvalho de Melo dso->has_build_id = true; 1924b7cece76SArnaldo Carvalho de Melo 1925b7cece76SArnaldo Carvalho de Melo return 0; 1926b7cece76SArnaldo Carvalho de Melo } 1927b7cece76SArnaldo Carvalho de Melo 1928aeafcbafSArnaldo Carvalho de Melo static int map_groups__set_modules_path_dir(struct map_groups *mg, 1929a1645ce1SZhang, Yanmin const char *dir_name) 19306cfcc53eSMike Galbraith { 1931439d473bSArnaldo Carvalho de Melo struct dirent *dent; 19325aab621bSArnaldo Carvalho de Melo DIR *dir = opendir(dir_name); 193374534341SGui Jianfeng int ret = 0; 19346cfcc53eSMike Galbraith 1935439d473bSArnaldo Carvalho de Melo if (!dir) { 19365aab621bSArnaldo Carvalho de Melo pr_debug("%s: cannot open %s dir\n", __func__, dir_name); 1937439d473bSArnaldo Carvalho de Melo return -1; 1938439d473bSArnaldo Carvalho de Melo } 19396cfcc53eSMike Galbraith 1940439d473bSArnaldo Carvalho de Melo while ((dent = readdir(dir)) != NULL) { 1941439d473bSArnaldo Carvalho de Melo char path[PATH_MAX]; 1942a1645ce1SZhang, Yanmin struct stat st; 1943439d473bSArnaldo Carvalho de Melo 1944a1645ce1SZhang, Yanmin /*sshfs might return bad dent->d_type, so we have to stat*/ 19452b600f95SNamhyung Kim snprintf(path, sizeof(path), "%s/%s", dir_name, dent->d_name); 1946a1645ce1SZhang, Yanmin if (stat(path, &st)) 1947a1645ce1SZhang, Yanmin continue; 1948a1645ce1SZhang, Yanmin 1949a1645ce1SZhang, Yanmin if (S_ISDIR(st.st_mode)) { 1950439d473bSArnaldo Carvalho de Melo if (!strcmp(dent->d_name, ".") || 1951439d473bSArnaldo Carvalho de Melo !strcmp(dent->d_name, "..")) 1952439d473bSArnaldo Carvalho de Melo continue; 1953439d473bSArnaldo Carvalho de Melo 1954aeafcbafSArnaldo Carvalho de Melo ret = map_groups__set_modules_path_dir(mg, path); 195574534341SGui Jianfeng if (ret < 0) 195674534341SGui Jianfeng goto out; 1957439d473bSArnaldo Carvalho de Melo } else { 1958439d473bSArnaldo Carvalho de Melo char *dot = strrchr(dent->d_name, '.'), 1959439d473bSArnaldo Carvalho de Melo dso_name[PATH_MAX]; 1960439d473bSArnaldo Carvalho de Melo struct map *map; 1961cfc10d3bSArnaldo Carvalho de Melo char *long_name; 1962439d473bSArnaldo Carvalho de Melo 1963439d473bSArnaldo Carvalho de Melo if (dot == NULL || strcmp(dot, ".ko")) 1964439d473bSArnaldo Carvalho de Melo continue; 1965439d473bSArnaldo Carvalho de Melo snprintf(dso_name, sizeof(dso_name), "[%.*s]", 1966439d473bSArnaldo Carvalho de Melo (int)(dot - dent->d_name), dent->d_name); 1967439d473bSArnaldo Carvalho de Melo 1968a2a99e8eSArnaldo Carvalho de Melo strxfrchar(dso_name, '-', '_'); 1969aeafcbafSArnaldo Carvalho de Melo map = map_groups__find_by_name(mg, MAP__FUNCTION, 1970aeafcbafSArnaldo Carvalho de Melo dso_name); 1971439d473bSArnaldo Carvalho de Melo if (map == NULL) 1972439d473bSArnaldo Carvalho de Melo continue; 1973439d473bSArnaldo Carvalho de Melo 1974cfc10d3bSArnaldo Carvalho de Melo long_name = strdup(path); 197574534341SGui Jianfeng if (long_name == NULL) { 197674534341SGui Jianfeng ret = -1; 197774534341SGui Jianfeng goto out; 197874534341SGui Jianfeng } 1979cfc10d3bSArnaldo Carvalho de Melo dso__set_long_name(map->dso, long_name); 19806e406257SArnaldo Carvalho de Melo map->dso->lname_alloc = 1; 1981a1645ce1SZhang, Yanmin dso__kernel_module_get_build_id(map->dso, ""); 1982439d473bSArnaldo Carvalho de Melo } 1983439d473bSArnaldo Carvalho de Melo } 1984439d473bSArnaldo Carvalho de Melo 198574534341SGui Jianfeng out: 1986439d473bSArnaldo Carvalho de Melo closedir(dir); 198774534341SGui Jianfeng return ret; 1988439d473bSArnaldo Carvalho de Melo } 1989439d473bSArnaldo Carvalho de Melo 1990a1645ce1SZhang, Yanmin static char *get_kernel_version(const char *root_dir) 1991439d473bSArnaldo Carvalho de Melo { 1992a1645ce1SZhang, Yanmin char version[PATH_MAX]; 1993a1645ce1SZhang, Yanmin FILE *file; 1994a1645ce1SZhang, Yanmin char *name, *tmp; 1995a1645ce1SZhang, Yanmin const char *prefix = "Linux version "; 1996a1645ce1SZhang, Yanmin 1997a1645ce1SZhang, Yanmin sprintf(version, "%s/proc/version", root_dir); 1998a1645ce1SZhang, Yanmin file = fopen(version, "r"); 1999a1645ce1SZhang, Yanmin if (!file) 2000a1645ce1SZhang, Yanmin return NULL; 2001a1645ce1SZhang, Yanmin 2002a1645ce1SZhang, Yanmin version[0] = '\0'; 2003a1645ce1SZhang, Yanmin tmp = fgets(version, sizeof(version), file); 2004a1645ce1SZhang, Yanmin fclose(file); 2005a1645ce1SZhang, Yanmin 2006a1645ce1SZhang, Yanmin name = strstr(version, prefix); 2007a1645ce1SZhang, Yanmin if (!name) 2008a1645ce1SZhang, Yanmin return NULL; 2009a1645ce1SZhang, Yanmin name += strlen(prefix); 2010a1645ce1SZhang, Yanmin tmp = strchr(name, ' '); 2011a1645ce1SZhang, Yanmin if (tmp) 2012a1645ce1SZhang, Yanmin *tmp = '\0'; 2013a1645ce1SZhang, Yanmin 2014a1645ce1SZhang, Yanmin return strdup(name); 2015a1645ce1SZhang, Yanmin } 2016a1645ce1SZhang, Yanmin 2017aeafcbafSArnaldo Carvalho de Melo static int machine__set_modules_path(struct machine *machine) 2018a1645ce1SZhang, Yanmin { 2019a1645ce1SZhang, Yanmin char *version; 2020439d473bSArnaldo Carvalho de Melo char modules_path[PATH_MAX]; 2021439d473bSArnaldo Carvalho de Melo 2022aeafcbafSArnaldo Carvalho de Melo version = get_kernel_version(machine->root_dir); 2023a1645ce1SZhang, Yanmin if (!version) 2024439d473bSArnaldo Carvalho de Melo return -1; 2025439d473bSArnaldo Carvalho de Melo 2026a1645ce1SZhang, Yanmin snprintf(modules_path, sizeof(modules_path), "%s/lib/modules/%s/kernel", 2027aeafcbafSArnaldo Carvalho de Melo machine->root_dir, version); 2028a1645ce1SZhang, Yanmin free(version); 2029439d473bSArnaldo Carvalho de Melo 2030aeafcbafSArnaldo Carvalho de Melo return map_groups__set_modules_path_dir(&machine->kmaps, modules_path); 2031439d473bSArnaldo Carvalho de Melo } 20326cfcc53eSMike Galbraith 20336cfcc53eSMike Galbraith /* 2034439d473bSArnaldo Carvalho de Melo * Constructor variant for modules (where we know from /proc/modules where 2035439d473bSArnaldo Carvalho de Melo * they are loaded) and for vmlinux, where only after we load all the 2036439d473bSArnaldo Carvalho de Melo * symbols we'll know where it starts and ends. 20376cfcc53eSMike Galbraith */ 20383610583cSArnaldo Carvalho de Melo static struct map *map__new2(u64 start, struct dso *dso, enum map_type type) 2039439d473bSArnaldo Carvalho de Melo { 2040aeafcbafSArnaldo Carvalho de Melo struct map *map = calloc(1, (sizeof(*map) + 20415aab621bSArnaldo Carvalho de Melo (dso->kernel ? sizeof(struct kmap) : 0))); 2042aeafcbafSArnaldo Carvalho de Melo if (map != NULL) { 2043439d473bSArnaldo Carvalho de Melo /* 2044afb7b4f0SArnaldo Carvalho de Melo * ->end will be filled after we load all the symbols 2045439d473bSArnaldo Carvalho de Melo */ 2046aeafcbafSArnaldo Carvalho de Melo map__init(map, type, start, 0, 0, dso); 2047439d473bSArnaldo Carvalho de Melo } 2048afb7b4f0SArnaldo Carvalho de Melo 2049aeafcbafSArnaldo Carvalho de Melo return map; 2050439d473bSArnaldo Carvalho de Melo } 2051439d473bSArnaldo Carvalho de Melo 2052aeafcbafSArnaldo Carvalho de Melo struct map *machine__new_module(struct machine *machine, u64 start, 2053d28c6223SArnaldo Carvalho de Melo const char *filename) 2054b7cece76SArnaldo Carvalho de Melo { 2055b7cece76SArnaldo Carvalho de Melo struct map *map; 2056aeafcbafSArnaldo Carvalho de Melo struct dso *dso = __dsos__findnew(&machine->kernel_dsos, filename); 2057b7cece76SArnaldo Carvalho de Melo 2058b7cece76SArnaldo Carvalho de Melo if (dso == NULL) 2059b7cece76SArnaldo Carvalho de Melo return NULL; 2060b7cece76SArnaldo Carvalho de Melo 2061b7cece76SArnaldo Carvalho de Melo map = map__new2(start, dso, MAP__FUNCTION); 2062b7cece76SArnaldo Carvalho de Melo if (map == NULL) 2063b7cece76SArnaldo Carvalho de Melo return NULL; 2064b7cece76SArnaldo Carvalho de Melo 2065aeafcbafSArnaldo Carvalho de Melo if (machine__is_host(machine)) 206644f24cb3SJiri Olsa dso->symtab_type = DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE; 2067a1645ce1SZhang, Yanmin else 206844f24cb3SJiri Olsa dso->symtab_type = DSO_BINARY_TYPE__GUEST_KMODULE; 2069aeafcbafSArnaldo Carvalho de Melo map_groups__insert(&machine->kmaps, map); 2070b7cece76SArnaldo Carvalho de Melo return map; 2071b7cece76SArnaldo Carvalho de Melo } 2072b7cece76SArnaldo Carvalho de Melo 2073aeafcbafSArnaldo Carvalho de Melo static int machine__create_modules(struct machine *machine) 2074439d473bSArnaldo Carvalho de Melo { 2075439d473bSArnaldo Carvalho de Melo char *line = NULL; 2076439d473bSArnaldo Carvalho de Melo size_t n; 2077a1645ce1SZhang, Yanmin FILE *file; 2078439d473bSArnaldo Carvalho de Melo struct map *map; 2079a1645ce1SZhang, Yanmin const char *modules; 2080a1645ce1SZhang, Yanmin char path[PATH_MAX]; 2081439d473bSArnaldo Carvalho de Melo 2082aeafcbafSArnaldo Carvalho de Melo if (machine__is_default_guest(machine)) 2083a1645ce1SZhang, Yanmin modules = symbol_conf.default_guest_modules; 2084a1645ce1SZhang, Yanmin else { 2085aeafcbafSArnaldo Carvalho de Melo sprintf(path, "%s/proc/modules", machine->root_dir); 2086a1645ce1SZhang, Yanmin modules = path; 2087a1645ce1SZhang, Yanmin } 2088a1645ce1SZhang, Yanmin 2089ec80fde7SArnaldo Carvalho de Melo if (symbol__restricted_filename(path, "/proc/modules")) 2090ec80fde7SArnaldo Carvalho de Melo return -1; 2091ec80fde7SArnaldo Carvalho de Melo 2092a1645ce1SZhang, Yanmin file = fopen(modules, "r"); 2093439d473bSArnaldo Carvalho de Melo if (file == NULL) 2094439d473bSArnaldo Carvalho de Melo return -1; 2095439d473bSArnaldo Carvalho de Melo 2096439d473bSArnaldo Carvalho de Melo while (!feof(file)) { 2097439d473bSArnaldo Carvalho de Melo char name[PATH_MAX]; 2098439d473bSArnaldo Carvalho de Melo u64 start; 2099439d473bSArnaldo Carvalho de Melo char *sep; 2100439d473bSArnaldo Carvalho de Melo int line_len; 2101439d473bSArnaldo Carvalho de Melo 2102439d473bSArnaldo Carvalho de Melo line_len = getline(&line, &n, file); 2103439d473bSArnaldo Carvalho de Melo if (line_len < 0) 21046cfcc53eSMike Galbraith break; 21056cfcc53eSMike Galbraith 2106439d473bSArnaldo Carvalho de Melo if (!line) 2107439d473bSArnaldo Carvalho de Melo goto out_failure; 2108439d473bSArnaldo Carvalho de Melo 2109439d473bSArnaldo Carvalho de Melo line[--line_len] = '\0'; /* \n */ 2110439d473bSArnaldo Carvalho de Melo 2111439d473bSArnaldo Carvalho de Melo sep = strrchr(line, 'x'); 2112439d473bSArnaldo Carvalho de Melo if (sep == NULL) 2113439d473bSArnaldo Carvalho de Melo continue; 2114439d473bSArnaldo Carvalho de Melo 2115439d473bSArnaldo Carvalho de Melo hex2u64(sep + 1, &start); 2116439d473bSArnaldo Carvalho de Melo 2117439d473bSArnaldo Carvalho de Melo sep = strchr(line, ' '); 2118439d473bSArnaldo Carvalho de Melo if (sep == NULL) 2119439d473bSArnaldo Carvalho de Melo continue; 2120439d473bSArnaldo Carvalho de Melo 2121439d473bSArnaldo Carvalho de Melo *sep = '\0'; 2122439d473bSArnaldo Carvalho de Melo 2123439d473bSArnaldo Carvalho de Melo snprintf(name, sizeof(name), "[%s]", line); 2124aeafcbafSArnaldo Carvalho de Melo map = machine__new_module(machine, start, name); 2125b7cece76SArnaldo Carvalho de Melo if (map == NULL) 2126439d473bSArnaldo Carvalho de Melo goto out_delete_line; 2127aeafcbafSArnaldo Carvalho de Melo dso__kernel_module_get_build_id(map->dso, machine->root_dir); 21286cfcc53eSMike Galbraith } 21296cfcc53eSMike Galbraith 2130439d473bSArnaldo Carvalho de Melo free(line); 2131439d473bSArnaldo Carvalho de Melo fclose(file); 2132439d473bSArnaldo Carvalho de Melo 2133aeafcbafSArnaldo Carvalho de Melo return machine__set_modules_path(machine); 2134439d473bSArnaldo Carvalho de Melo 2135439d473bSArnaldo Carvalho de Melo out_delete_line: 2136439d473bSArnaldo Carvalho de Melo free(line); 2137439d473bSArnaldo Carvalho de Melo out_failure: 2138439d473bSArnaldo Carvalho de Melo return -1; 21396cfcc53eSMike Galbraith } 21406cfcc53eSMike Galbraith 2141aeafcbafSArnaldo Carvalho de Melo int dso__load_vmlinux(struct dso *dso, struct map *map, 21426beba7adSArnaldo Carvalho de Melo const char *vmlinux, symbol_filter_t filter) 214386470930SIngo Molnar { 2144fbd733b8SArnaldo Carvalho de Melo int err = -1, fd; 2145ec5761eaSDavid Ahern char symfs_vmlinux[PATH_MAX]; 214686470930SIngo Molnar 2147a639dc64SArnaldo Carvalho de Melo snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s%s", 2148ec5761eaSDavid Ahern symbol_conf.symfs, vmlinux); 2149ec5761eaSDavid Ahern fd = open(symfs_vmlinux, O_RDONLY); 215086470930SIngo Molnar if (fd < 0) 215186470930SIngo Molnar return -1; 215286470930SIngo Molnar 2153aeafcbafSArnaldo Carvalho de Melo dso__set_long_name(dso, (char *)vmlinux); 2154aeafcbafSArnaldo Carvalho de Melo dso__set_loaded(dso, map->type); 2155aeafcbafSArnaldo Carvalho de Melo err = dso__load_sym(dso, map, symfs_vmlinux, fd, filter, 0, 0); 215686470930SIngo Molnar close(fd); 215786470930SIngo Molnar 21583846df2eSArnaldo Carvalho de Melo if (err > 0) 2159ec5761eaSDavid Ahern pr_debug("Using %s for symbols\n", symfs_vmlinux); 21603846df2eSArnaldo Carvalho de Melo 216186470930SIngo Molnar return err; 216286470930SIngo Molnar } 216386470930SIngo Molnar 2164aeafcbafSArnaldo Carvalho de Melo int dso__load_vmlinux_path(struct dso *dso, struct map *map, 21659de89fe7SArnaldo Carvalho de Melo symbol_filter_t filter) 2166a19afe46SArnaldo Carvalho de Melo { 2167a19afe46SArnaldo Carvalho de Melo int i, err = 0; 21685ad90e4eSArnaldo Carvalho de Melo char *filename; 2169a19afe46SArnaldo Carvalho de Melo 2170a19afe46SArnaldo Carvalho de Melo pr_debug("Looking at the vmlinux_path (%d entries long)\n", 21715ad90e4eSArnaldo Carvalho de Melo vmlinux_path__nr_entries + 1); 21725ad90e4eSArnaldo Carvalho de Melo 2173aeafcbafSArnaldo Carvalho de Melo filename = dso__build_id_filename(dso, NULL, 0); 21745ad90e4eSArnaldo Carvalho de Melo if (filename != NULL) { 2175aeafcbafSArnaldo Carvalho de Melo err = dso__load_vmlinux(dso, map, filename, filter); 21765ad90e4eSArnaldo Carvalho de Melo if (err > 0) { 2177aeafcbafSArnaldo Carvalho de Melo dso__set_long_name(dso, filename); 21785ad90e4eSArnaldo Carvalho de Melo goto out; 21795ad90e4eSArnaldo Carvalho de Melo } 21805ad90e4eSArnaldo Carvalho de Melo free(filename); 21815ad90e4eSArnaldo Carvalho de Melo } 2182a19afe46SArnaldo Carvalho de Melo 2183a19afe46SArnaldo Carvalho de Melo for (i = 0; i < vmlinux_path__nr_entries; ++i) { 2184aeafcbafSArnaldo Carvalho de Melo err = dso__load_vmlinux(dso, map, vmlinux_path[i], filter); 2185a19afe46SArnaldo Carvalho de Melo if (err > 0) { 2186aeafcbafSArnaldo Carvalho de Melo dso__set_long_name(dso, strdup(vmlinux_path[i])); 2187a19afe46SArnaldo Carvalho de Melo break; 2188a19afe46SArnaldo Carvalho de Melo } 2189a19afe46SArnaldo Carvalho de Melo } 21905ad90e4eSArnaldo Carvalho de Melo out: 2191a19afe46SArnaldo Carvalho de Melo return err; 2192a19afe46SArnaldo Carvalho de Melo } 2193a19afe46SArnaldo Carvalho de Melo 2194aeafcbafSArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *dso, struct map *map, 21959de89fe7SArnaldo Carvalho de Melo symbol_filter_t filter) 219686470930SIngo Molnar { 2197cc612d81SArnaldo Carvalho de Melo int err; 21989e201442SArnaldo Carvalho de Melo const char *kallsyms_filename = NULL; 21999e201442SArnaldo Carvalho de Melo char *kallsyms_allocated_filename = NULL; 2200dc8d6ab2SArnaldo Carvalho de Melo /* 2201b226a5a7SDavid Ahern * Step 1: if the user specified a kallsyms or vmlinux filename, use 2202b226a5a7SDavid Ahern * it and only it, reporting errors to the user if it cannot be used. 2203dc8d6ab2SArnaldo Carvalho de Melo * 2204dc8d6ab2SArnaldo Carvalho de Melo * For instance, try to analyse an ARM perf.data file _without_ a 2205dc8d6ab2SArnaldo Carvalho de Melo * build-id, or if the user specifies the wrong path to the right 2206dc8d6ab2SArnaldo Carvalho de Melo * vmlinux file, obviously we can't fallback to another vmlinux (a 2207dc8d6ab2SArnaldo Carvalho de Melo * x86_86 one, on the machine where analysis is being performed, say), 2208dc8d6ab2SArnaldo Carvalho de Melo * or worse, /proc/kallsyms. 2209dc8d6ab2SArnaldo Carvalho de Melo * 2210dc8d6ab2SArnaldo Carvalho de Melo * If the specified file _has_ a build-id and there is a build-id 2211dc8d6ab2SArnaldo Carvalho de Melo * section in the perf.data file, we will still do the expected 2212dc8d6ab2SArnaldo Carvalho de Melo * validation in dso__load_vmlinux and will bail out if they don't 2213dc8d6ab2SArnaldo Carvalho de Melo * match. 2214dc8d6ab2SArnaldo Carvalho de Melo */ 2215b226a5a7SDavid Ahern if (symbol_conf.kallsyms_name != NULL) { 2216b226a5a7SDavid Ahern kallsyms_filename = symbol_conf.kallsyms_name; 2217b226a5a7SDavid Ahern goto do_kallsyms; 2218b226a5a7SDavid Ahern } 2219b226a5a7SDavid Ahern 2220dc8d6ab2SArnaldo Carvalho de Melo if (symbol_conf.vmlinux_name != NULL) { 2221aeafcbafSArnaldo Carvalho de Melo err = dso__load_vmlinux(dso, map, 2222dc8d6ab2SArnaldo Carvalho de Melo symbol_conf.vmlinux_name, filter); 2223e7dadc00SArnaldo Carvalho de Melo if (err > 0) { 2224aeafcbafSArnaldo Carvalho de Melo dso__set_long_name(dso, 2225e7dadc00SArnaldo Carvalho de Melo strdup(symbol_conf.vmlinux_name)); 2226e7dadc00SArnaldo Carvalho de Melo goto out_fixup; 2227e7dadc00SArnaldo Carvalho de Melo } 2228e7dadc00SArnaldo Carvalho de Melo return err; 2229dc8d6ab2SArnaldo Carvalho de Melo } 2230439d473bSArnaldo Carvalho de Melo 2231cc612d81SArnaldo Carvalho de Melo if (vmlinux_path != NULL) { 2232aeafcbafSArnaldo Carvalho de Melo err = dso__load_vmlinux_path(dso, map, filter); 2233a19afe46SArnaldo Carvalho de Melo if (err > 0) 2234cc612d81SArnaldo Carvalho de Melo goto out_fixup; 2235cc612d81SArnaldo Carvalho de Melo } 2236cc612d81SArnaldo Carvalho de Melo 2237ec5761eaSDavid Ahern /* do not try local files if a symfs was given */ 2238ec5761eaSDavid Ahern if (symbol_conf.symfs[0] != 0) 2239ec5761eaSDavid Ahern return -1; 2240ec5761eaSDavid Ahern 2241b7cece76SArnaldo Carvalho de Melo /* 2242b7cece76SArnaldo Carvalho de Melo * Say the kernel DSO was created when processing the build-id header table, 2243b7cece76SArnaldo Carvalho de Melo * we have a build-id, so check if it is the same as the running kernel, 2244b7cece76SArnaldo Carvalho de Melo * using it if it is. 2245b7cece76SArnaldo Carvalho de Melo */ 2246aeafcbafSArnaldo Carvalho de Melo if (dso->has_build_id) { 2247b7cece76SArnaldo Carvalho de Melo u8 kallsyms_build_id[BUILD_ID_SIZE]; 22489e201442SArnaldo Carvalho de Melo char sbuild_id[BUILD_ID_SIZE * 2 + 1]; 2249b7cece76SArnaldo Carvalho de Melo 2250b7cece76SArnaldo Carvalho de Melo if (sysfs__read_build_id("/sys/kernel/notes", kallsyms_build_id, 22518d0591f6SArnaldo Carvalho de Melo sizeof(kallsyms_build_id)) == 0) { 2252aeafcbafSArnaldo Carvalho de Melo if (dso__build_id_equal(dso, kallsyms_build_id)) { 22539e201442SArnaldo Carvalho de Melo kallsyms_filename = "/proc/kallsyms"; 2254b7cece76SArnaldo Carvalho de Melo goto do_kallsyms; 22558d0591f6SArnaldo Carvalho de Melo } 22569e201442SArnaldo Carvalho de Melo } 2257dc8d6ab2SArnaldo Carvalho de Melo /* 2258dc8d6ab2SArnaldo Carvalho de Melo * Now look if we have it on the build-id cache in 2259dc8d6ab2SArnaldo Carvalho de Melo * $HOME/.debug/[kernel.kallsyms]. 2260dc8d6ab2SArnaldo Carvalho de Melo */ 2261aeafcbafSArnaldo Carvalho de Melo build_id__sprintf(dso->build_id, sizeof(dso->build_id), 22629e201442SArnaldo Carvalho de Melo sbuild_id); 22639e201442SArnaldo Carvalho de Melo 22649e201442SArnaldo Carvalho de Melo if (asprintf(&kallsyms_allocated_filename, 22659e201442SArnaldo Carvalho de Melo "%s/.debug/[kernel.kallsyms]/%s", 22663846df2eSArnaldo Carvalho de Melo getenv("HOME"), sbuild_id) == -1) { 22673846df2eSArnaldo Carvalho de Melo pr_err("Not enough memory for kallsyms file lookup\n"); 22688d0591f6SArnaldo Carvalho de Melo return -1; 22693846df2eSArnaldo Carvalho de Melo } 22708d0591f6SArnaldo Carvalho de Melo 227119fc2dedSArnaldo Carvalho de Melo kallsyms_filename = kallsyms_allocated_filename; 227219fc2dedSArnaldo Carvalho de Melo 2273dc8d6ab2SArnaldo Carvalho de Melo if (access(kallsyms_filename, F_OK)) { 22743846df2eSArnaldo Carvalho de Melo pr_err("No kallsyms or vmlinux with build-id %s " 22753846df2eSArnaldo Carvalho de Melo "was found\n", sbuild_id); 22769e201442SArnaldo Carvalho de Melo free(kallsyms_allocated_filename); 2277dc8d6ab2SArnaldo Carvalho de Melo return -1; 2278ef6ae724SArnaldo Carvalho de Melo } 2279dc8d6ab2SArnaldo Carvalho de Melo } else { 2280dc8d6ab2SArnaldo Carvalho de Melo /* 2281dc8d6ab2SArnaldo Carvalho de Melo * Last resort, if we don't have a build-id and couldn't find 2282dc8d6ab2SArnaldo Carvalho de Melo * any vmlinux file, try the running kernel kallsyms table. 2283dc8d6ab2SArnaldo Carvalho de Melo */ 2284dc8d6ab2SArnaldo Carvalho de Melo kallsyms_filename = "/proc/kallsyms"; 2285dc8d6ab2SArnaldo Carvalho de Melo } 2286dc8d6ab2SArnaldo Carvalho de Melo 2287dc8d6ab2SArnaldo Carvalho de Melo do_kallsyms: 2288aeafcbafSArnaldo Carvalho de Melo err = dso__load_kallsyms(dso, kallsyms_filename, map, filter); 22893846df2eSArnaldo Carvalho de Melo if (err > 0) 22903846df2eSArnaldo Carvalho de Melo pr_debug("Using %s for symbols\n", kallsyms_filename); 2291dc8d6ab2SArnaldo Carvalho de Melo free(kallsyms_allocated_filename); 2292dc8d6ab2SArnaldo Carvalho de Melo 2293439d473bSArnaldo Carvalho de Melo if (err > 0) { 2294cc612d81SArnaldo Carvalho de Melo out_fixup: 2295e1c7c6a4SArnaldo Carvalho de Melo if (kallsyms_filename != NULL) 2296aeafcbafSArnaldo Carvalho de Melo dso__set_long_name(dso, strdup("[kernel.kallsyms]")); 22976a4694a4SArnaldo Carvalho de Melo map__fixup_start(map); 22986a4694a4SArnaldo Carvalho de Melo map__fixup_end(map); 2299439d473bSArnaldo Carvalho de Melo } 230094cb9e38SArnaldo Carvalho de Melo 230186470930SIngo Molnar return err; 230286470930SIngo Molnar } 230386470930SIngo Molnar 2304aeafcbafSArnaldo Carvalho de Melo static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map, 2305a1645ce1SZhang, Yanmin symbol_filter_t filter) 2306a1645ce1SZhang, Yanmin { 2307a1645ce1SZhang, Yanmin int err; 2308a1645ce1SZhang, Yanmin const char *kallsyms_filename = NULL; 230923346f21SArnaldo Carvalho de Melo struct machine *machine; 2310a1645ce1SZhang, Yanmin char path[PATH_MAX]; 2311a1645ce1SZhang, Yanmin 2312a1645ce1SZhang, Yanmin if (!map->groups) { 2313a1645ce1SZhang, Yanmin pr_debug("Guest kernel map hasn't the point to groups\n"); 2314a1645ce1SZhang, Yanmin return -1; 2315a1645ce1SZhang, Yanmin } 231623346f21SArnaldo Carvalho de Melo machine = map->groups->machine; 2317a1645ce1SZhang, Yanmin 231823346f21SArnaldo Carvalho de Melo if (machine__is_default_guest(machine)) { 2319a1645ce1SZhang, Yanmin /* 2320a1645ce1SZhang, Yanmin * if the user specified a vmlinux filename, use it and only 2321a1645ce1SZhang, Yanmin * it, reporting errors to the user if it cannot be used. 2322a1645ce1SZhang, Yanmin * Or use file guest_kallsyms inputted by user on commandline 2323a1645ce1SZhang, Yanmin */ 2324a1645ce1SZhang, Yanmin if (symbol_conf.default_guest_vmlinux_name != NULL) { 2325aeafcbafSArnaldo Carvalho de Melo err = dso__load_vmlinux(dso, map, 2326a1645ce1SZhang, Yanmin symbol_conf.default_guest_vmlinux_name, filter); 2327a1645ce1SZhang, Yanmin goto out_try_fixup; 2328a1645ce1SZhang, Yanmin } 2329a1645ce1SZhang, Yanmin 2330a1645ce1SZhang, Yanmin kallsyms_filename = symbol_conf.default_guest_kallsyms; 2331a1645ce1SZhang, Yanmin if (!kallsyms_filename) 2332a1645ce1SZhang, Yanmin return -1; 2333a1645ce1SZhang, Yanmin } else { 233423346f21SArnaldo Carvalho de Melo sprintf(path, "%s/proc/kallsyms", machine->root_dir); 2335a1645ce1SZhang, Yanmin kallsyms_filename = path; 2336a1645ce1SZhang, Yanmin } 2337a1645ce1SZhang, Yanmin 2338aeafcbafSArnaldo Carvalho de Melo err = dso__load_kallsyms(dso, kallsyms_filename, map, filter); 2339a1645ce1SZhang, Yanmin if (err > 0) 2340a1645ce1SZhang, Yanmin pr_debug("Using %s for symbols\n", kallsyms_filename); 2341a1645ce1SZhang, Yanmin 2342a1645ce1SZhang, Yanmin out_try_fixup: 2343a1645ce1SZhang, Yanmin if (err > 0) { 2344a1645ce1SZhang, Yanmin if (kallsyms_filename != NULL) { 234548ea8f54SArnaldo Carvalho de Melo machine__mmap_name(machine, path, sizeof(path)); 2346aeafcbafSArnaldo Carvalho de Melo dso__set_long_name(dso, strdup(path)); 2347a1645ce1SZhang, Yanmin } 2348a1645ce1SZhang, Yanmin map__fixup_start(map); 2349a1645ce1SZhang, Yanmin map__fixup_end(map); 2350a1645ce1SZhang, Yanmin } 2351a1645ce1SZhang, Yanmin 2352a1645ce1SZhang, Yanmin return err; 2353a1645ce1SZhang, Yanmin } 2354cd84c2acSFrederic Weisbecker 2355b0da954aSArnaldo Carvalho de Melo static void dsos__add(struct list_head *head, struct dso *dso) 2356cd84c2acSFrederic Weisbecker { 2357b0da954aSArnaldo Carvalho de Melo list_add_tail(&dso->node, head); 2358cd84c2acSFrederic Weisbecker } 2359cd84c2acSFrederic Weisbecker 2360b0da954aSArnaldo Carvalho de Melo static struct dso *dsos__find(struct list_head *head, const char *name) 2361cd84c2acSFrederic Weisbecker { 2362cd84c2acSFrederic Weisbecker struct dso *pos; 2363cd84c2acSFrederic Weisbecker 2364b0da954aSArnaldo Carvalho de Melo list_for_each_entry(pos, head, node) 2365cf4e5b08SArnaldo Carvalho de Melo if (strcmp(pos->long_name, name) == 0) 2366cd84c2acSFrederic Weisbecker return pos; 2367cd84c2acSFrederic Weisbecker return NULL; 2368cd84c2acSFrederic Weisbecker } 2369cd84c2acSFrederic Weisbecker 2370a89e5abeSArnaldo Carvalho de Melo struct dso *__dsos__findnew(struct list_head *head, const char *name) 2371cd84c2acSFrederic Weisbecker { 2372a89e5abeSArnaldo Carvalho de Melo struct dso *dso = dsos__find(head, name); 2373cd84c2acSFrederic Weisbecker 2374e4204992SArnaldo Carvalho de Melo if (!dso) { 237500a192b3SArnaldo Carvalho de Melo dso = dso__new(name); 2376cfc10d3bSArnaldo Carvalho de Melo if (dso != NULL) { 2377a89e5abeSArnaldo Carvalho de Melo dsos__add(head, dso); 2378cfc10d3bSArnaldo Carvalho de Melo dso__set_basename(dso); 2379cfc10d3bSArnaldo Carvalho de Melo } 2380e4204992SArnaldo Carvalho de Melo } 2381cd84c2acSFrederic Weisbecker 2382cd84c2acSFrederic Weisbecker return dso; 2383cd84c2acSFrederic Weisbecker } 2384cd84c2acSFrederic Weisbecker 23851f626bc3SArnaldo Carvalho de Melo size_t __dsos__fprintf(struct list_head *head, FILE *fp) 2386cd84c2acSFrederic Weisbecker { 2387cd84c2acSFrederic Weisbecker struct dso *pos; 2388cbf69680SArnaldo Carvalho de Melo size_t ret = 0; 2389cd84c2acSFrederic Weisbecker 239095011c60SArnaldo Carvalho de Melo list_for_each_entry(pos, head, node) { 239195011c60SArnaldo Carvalho de Melo int i; 239295011c60SArnaldo Carvalho de Melo for (i = 0; i < MAP__NR_TYPES; ++i) 2393cbf69680SArnaldo Carvalho de Melo ret += dso__fprintf(pos, i, fp); 2394cd84c2acSFrederic Weisbecker } 2395cd84c2acSFrederic Weisbecker 2396cbf69680SArnaldo Carvalho de Melo return ret; 2397cbf69680SArnaldo Carvalho de Melo } 2398cbf69680SArnaldo Carvalho de Melo 2399aeafcbafSArnaldo Carvalho de Melo size_t machines__fprintf_dsos(struct rb_root *machines, FILE *fp) 2400b0da954aSArnaldo Carvalho de Melo { 2401a1645ce1SZhang, Yanmin struct rb_node *nd; 2402cbf69680SArnaldo Carvalho de Melo size_t ret = 0; 2403a1645ce1SZhang, Yanmin 2404aeafcbafSArnaldo Carvalho de Melo for (nd = rb_first(machines); nd; nd = rb_next(nd)) { 240523346f21SArnaldo Carvalho de Melo struct machine *pos = rb_entry(nd, struct machine, rb_node); 2406cbf69680SArnaldo Carvalho de Melo ret += __dsos__fprintf(&pos->kernel_dsos, fp); 2407cbf69680SArnaldo Carvalho de Melo ret += __dsos__fprintf(&pos->user_dsos, fp); 2408a1645ce1SZhang, Yanmin } 2409cbf69680SArnaldo Carvalho de Melo 2410cbf69680SArnaldo Carvalho de Melo return ret; 2411b0da954aSArnaldo Carvalho de Melo } 2412b0da954aSArnaldo Carvalho de Melo 241388d3d9b7SArnaldo Carvalho de Melo static size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp, 241488d3d9b7SArnaldo Carvalho de Melo bool with_hits) 24159e03eb2dSArnaldo Carvalho de Melo { 24169e03eb2dSArnaldo Carvalho de Melo struct dso *pos; 24179e03eb2dSArnaldo Carvalho de Melo size_t ret = 0; 24189e03eb2dSArnaldo Carvalho de Melo 2419b0da954aSArnaldo Carvalho de Melo list_for_each_entry(pos, head, node) { 242088d3d9b7SArnaldo Carvalho de Melo if (with_hits && !pos->hit) 242188d3d9b7SArnaldo Carvalho de Melo continue; 24229e03eb2dSArnaldo Carvalho de Melo ret += dso__fprintf_buildid(pos, fp); 24239e03eb2dSArnaldo Carvalho de Melo ret += fprintf(fp, " %s\n", pos->long_name); 24249e03eb2dSArnaldo Carvalho de Melo } 24259e03eb2dSArnaldo Carvalho de Melo return ret; 24269e03eb2dSArnaldo Carvalho de Melo } 24279e03eb2dSArnaldo Carvalho de Melo 2428aeafcbafSArnaldo Carvalho de Melo size_t machine__fprintf_dsos_buildid(struct machine *machine, FILE *fp, 2429aeafcbafSArnaldo Carvalho de Melo bool with_hits) 2430f869097eSArnaldo Carvalho de Melo { 2431aeafcbafSArnaldo Carvalho de Melo return __dsos__fprintf_buildid(&machine->kernel_dsos, fp, with_hits) + 2432aeafcbafSArnaldo Carvalho de Melo __dsos__fprintf_buildid(&machine->user_dsos, fp, with_hits); 2433f869097eSArnaldo Carvalho de Melo } 2434f869097eSArnaldo Carvalho de Melo 2435aeafcbafSArnaldo Carvalho de Melo size_t machines__fprintf_dsos_buildid(struct rb_root *machines, 2436aeafcbafSArnaldo Carvalho de Melo FILE *fp, bool with_hits) 2437b0da954aSArnaldo Carvalho de Melo { 2438a1645ce1SZhang, Yanmin struct rb_node *nd; 2439a1645ce1SZhang, Yanmin size_t ret = 0; 2440a1645ce1SZhang, Yanmin 2441aeafcbafSArnaldo Carvalho de Melo for (nd = rb_first(machines); nd; nd = rb_next(nd)) { 244223346f21SArnaldo Carvalho de Melo struct machine *pos = rb_entry(nd, struct machine, rb_node); 2443f869097eSArnaldo Carvalho de Melo ret += machine__fprintf_dsos_buildid(pos, fp, with_hits); 2444a1645ce1SZhang, Yanmin } 2445a1645ce1SZhang, Yanmin return ret; 2446b0da954aSArnaldo Carvalho de Melo } 2447b0da954aSArnaldo Carvalho de Melo 2448f57b05edSJiri Olsa static struct dso* 2449f57b05edSJiri Olsa dso__kernel_findnew(struct machine *machine, const char *name, 2450f57b05edSJiri Olsa const char *short_name, int dso_type) 2451fd1d908cSArnaldo Carvalho de Melo { 2452f57b05edSJiri Olsa /* 2453f57b05edSJiri Olsa * The kernel dso could be created by build_id processing. 2454f57b05edSJiri Olsa */ 2455f57b05edSJiri Olsa struct dso *dso = __dsos__findnew(&machine->kernel_dsos, name); 2456fd1d908cSArnaldo Carvalho de Melo 2457f57b05edSJiri Olsa /* 2458f57b05edSJiri Olsa * We need to run this in all cases, since during the build_id 2459f57b05edSJiri Olsa * processing we had no idea this was the kernel dso. 2460f57b05edSJiri Olsa */ 2461aeafcbafSArnaldo Carvalho de Melo if (dso != NULL) { 2462f57b05edSJiri Olsa dso__set_short_name(dso, short_name); 2463f57b05edSJiri Olsa dso->kernel = dso_type; 2464a1645ce1SZhang, Yanmin } 2465a1645ce1SZhang, Yanmin 2466aeafcbafSArnaldo Carvalho de Melo return dso; 2467a1645ce1SZhang, Yanmin } 2468a1645ce1SZhang, Yanmin 2469aeafcbafSArnaldo Carvalho de Melo void dso__read_running_kernel_build_id(struct dso *dso, struct machine *machine) 2470a1645ce1SZhang, Yanmin { 2471a1645ce1SZhang, Yanmin char path[PATH_MAX]; 2472a1645ce1SZhang, Yanmin 247323346f21SArnaldo Carvalho de Melo if (machine__is_default_guest(machine)) 2474a1645ce1SZhang, Yanmin return; 247523346f21SArnaldo Carvalho de Melo sprintf(path, "%s/sys/kernel/notes", machine->root_dir); 2476aeafcbafSArnaldo Carvalho de Melo if (sysfs__read_build_id(path, dso->build_id, 2477aeafcbafSArnaldo Carvalho de Melo sizeof(dso->build_id)) == 0) 2478aeafcbafSArnaldo Carvalho de Melo dso->has_build_id = true; 2479fd1d908cSArnaldo Carvalho de Melo } 2480fd1d908cSArnaldo Carvalho de Melo 2481f57b05edSJiri Olsa static struct dso *machine__get_kernel(struct machine *machine) 2482cd84c2acSFrederic Weisbecker { 2483a1645ce1SZhang, Yanmin const char *vmlinux_name = NULL; 2484a1645ce1SZhang, Yanmin struct dso *kernel; 2485cd84c2acSFrederic Weisbecker 2486aeafcbafSArnaldo Carvalho de Melo if (machine__is_host(machine)) { 2487a1645ce1SZhang, Yanmin vmlinux_name = symbol_conf.vmlinux_name; 2488f57b05edSJiri Olsa if (!vmlinux_name) 2489f57b05edSJiri Olsa vmlinux_name = "[kernel.kallsyms]"; 2490f57b05edSJiri Olsa 2491f57b05edSJiri Olsa kernel = dso__kernel_findnew(machine, vmlinux_name, 2492f57b05edSJiri Olsa "[kernel]", 2493f57b05edSJiri Olsa DSO_TYPE_KERNEL); 2494a1645ce1SZhang, Yanmin } else { 2495f57b05edSJiri Olsa char bf[PATH_MAX]; 2496f57b05edSJiri Olsa 2497aeafcbafSArnaldo Carvalho de Melo if (machine__is_default_guest(machine)) 2498a1645ce1SZhang, Yanmin vmlinux_name = symbol_conf.default_guest_vmlinux_name; 2499f57b05edSJiri Olsa if (!vmlinux_name) 2500f57b05edSJiri Olsa vmlinux_name = machine__mmap_name(machine, bf, 2501f57b05edSJiri Olsa sizeof(bf)); 2502f57b05edSJiri Olsa 2503f57b05edSJiri Olsa kernel = dso__kernel_findnew(machine, vmlinux_name, 2504f57b05edSJiri Olsa "[guest.kernel]", 2505f57b05edSJiri Olsa DSO_TYPE_GUEST_KERNEL); 25068d92c02aSArnaldo Carvalho de Melo } 2507cd84c2acSFrederic Weisbecker 2508f57b05edSJiri Olsa if (kernel != NULL && (!kernel->has_build_id)) 2509aeafcbafSArnaldo Carvalho de Melo dso__read_running_kernel_build_id(kernel, machine); 2510f57b05edSJiri Olsa 2511f1dfa0b1SArnaldo Carvalho de Melo return kernel; 2512f1dfa0b1SArnaldo Carvalho de Melo } 2513f1dfa0b1SArnaldo Carvalho de Melo 2514d214afbdSMing Lei struct process_args { 2515d214afbdSMing Lei u64 start; 2516d214afbdSMing Lei }; 2517d214afbdSMing Lei 2518d214afbdSMing Lei static int symbol__in_kernel(void *arg, const char *name, 25193b01a413SArnaldo Carvalho de Melo char type __used, u64 start, u64 end __used) 2520d214afbdSMing Lei { 2521d214afbdSMing Lei struct process_args *args = arg; 2522d214afbdSMing Lei 2523d214afbdSMing Lei if (strchr(name, '[')) 2524d214afbdSMing Lei return 0; 2525d214afbdSMing Lei 2526d214afbdSMing Lei args->start = start; 2527d214afbdSMing Lei return 1; 2528d214afbdSMing Lei } 2529d214afbdSMing Lei 2530d214afbdSMing Lei /* Figure out the start address of kernel map from /proc/kallsyms */ 2531d214afbdSMing Lei static u64 machine__get_kernel_start_addr(struct machine *machine) 2532d214afbdSMing Lei { 2533d214afbdSMing Lei const char *filename; 2534d214afbdSMing Lei char path[PATH_MAX]; 2535d214afbdSMing Lei struct process_args args; 2536d214afbdSMing Lei 2537d214afbdSMing Lei if (machine__is_host(machine)) { 2538d214afbdSMing Lei filename = "/proc/kallsyms"; 2539d214afbdSMing Lei } else { 2540d214afbdSMing Lei if (machine__is_default_guest(machine)) 2541d214afbdSMing Lei filename = (char *)symbol_conf.default_guest_kallsyms; 2542d214afbdSMing Lei else { 2543d214afbdSMing Lei sprintf(path, "%s/proc/kallsyms", machine->root_dir); 2544d214afbdSMing Lei filename = path; 2545d214afbdSMing Lei } 2546d214afbdSMing Lei } 2547d214afbdSMing Lei 2548ec80fde7SArnaldo Carvalho de Melo if (symbol__restricted_filename(filename, "/proc/kallsyms")) 2549ec80fde7SArnaldo Carvalho de Melo return 0; 2550ec80fde7SArnaldo Carvalho de Melo 2551d214afbdSMing Lei if (kallsyms__parse(filename, &args, symbol__in_kernel) <= 0) 2552d214afbdSMing Lei return 0; 2553d214afbdSMing Lei 2554d214afbdSMing Lei return args.start; 2555d214afbdSMing Lei } 2556d214afbdSMing Lei 2557aeafcbafSArnaldo Carvalho de Melo int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel) 2558f1dfa0b1SArnaldo Carvalho de Melo { 2559de176489SArnaldo Carvalho de Melo enum map_type type; 2560aeafcbafSArnaldo Carvalho de Melo u64 start = machine__get_kernel_start_addr(machine); 2561f1dfa0b1SArnaldo Carvalho de Melo 2562de176489SArnaldo Carvalho de Melo for (type = 0; type < MAP__NR_TYPES; ++type) { 25639de89fe7SArnaldo Carvalho de Melo struct kmap *kmap; 25649de89fe7SArnaldo Carvalho de Melo 2565aeafcbafSArnaldo Carvalho de Melo machine->vmlinux_maps[type] = map__new2(start, kernel, type); 2566aeafcbafSArnaldo Carvalho de Melo if (machine->vmlinux_maps[type] == NULL) 2567f1dfa0b1SArnaldo Carvalho de Melo return -1; 2568f1dfa0b1SArnaldo Carvalho de Melo 2569aeafcbafSArnaldo Carvalho de Melo machine->vmlinux_maps[type]->map_ip = 2570aeafcbafSArnaldo Carvalho de Melo machine->vmlinux_maps[type]->unmap_ip = 2571aeafcbafSArnaldo Carvalho de Melo identity__map_ip; 2572aeafcbafSArnaldo Carvalho de Melo kmap = map__kmap(machine->vmlinux_maps[type]); 2573aeafcbafSArnaldo Carvalho de Melo kmap->kmaps = &machine->kmaps; 2574aeafcbafSArnaldo Carvalho de Melo map_groups__insert(&machine->kmaps, 2575aeafcbafSArnaldo Carvalho de Melo machine->vmlinux_maps[type]); 2576f1dfa0b1SArnaldo Carvalho de Melo } 2577f1dfa0b1SArnaldo Carvalho de Melo 2578f1dfa0b1SArnaldo Carvalho de Melo return 0; 25792446042cSArnaldo Carvalho de Melo } 25802446042cSArnaldo Carvalho de Melo 2581aeafcbafSArnaldo Carvalho de Melo void machine__destroy_kernel_maps(struct machine *machine) 2582076c6e45SArnaldo Carvalho de Melo { 2583076c6e45SArnaldo Carvalho de Melo enum map_type type; 2584076c6e45SArnaldo Carvalho de Melo 2585076c6e45SArnaldo Carvalho de Melo for (type = 0; type < MAP__NR_TYPES; ++type) { 2586076c6e45SArnaldo Carvalho de Melo struct kmap *kmap; 2587076c6e45SArnaldo Carvalho de Melo 2588aeafcbafSArnaldo Carvalho de Melo if (machine->vmlinux_maps[type] == NULL) 2589076c6e45SArnaldo Carvalho de Melo continue; 2590076c6e45SArnaldo Carvalho de Melo 2591aeafcbafSArnaldo Carvalho de Melo kmap = map__kmap(machine->vmlinux_maps[type]); 2592aeafcbafSArnaldo Carvalho de Melo map_groups__remove(&machine->kmaps, 2593aeafcbafSArnaldo Carvalho de Melo machine->vmlinux_maps[type]); 2594076c6e45SArnaldo Carvalho de Melo if (kmap->ref_reloc_sym) { 2595076c6e45SArnaldo Carvalho de Melo /* 2596076c6e45SArnaldo Carvalho de Melo * ref_reloc_sym is shared among all maps, so free just 2597076c6e45SArnaldo Carvalho de Melo * on one of them. 2598076c6e45SArnaldo Carvalho de Melo */ 2599076c6e45SArnaldo Carvalho de Melo if (type == MAP__FUNCTION) { 2600076c6e45SArnaldo Carvalho de Melo free((char *)kmap->ref_reloc_sym->name); 2601076c6e45SArnaldo Carvalho de Melo kmap->ref_reloc_sym->name = NULL; 2602076c6e45SArnaldo Carvalho de Melo free(kmap->ref_reloc_sym); 2603076c6e45SArnaldo Carvalho de Melo } 2604076c6e45SArnaldo Carvalho de Melo kmap->ref_reloc_sym = NULL; 2605076c6e45SArnaldo Carvalho de Melo } 2606076c6e45SArnaldo Carvalho de Melo 2607aeafcbafSArnaldo Carvalho de Melo map__delete(machine->vmlinux_maps[type]); 2608aeafcbafSArnaldo Carvalho de Melo machine->vmlinux_maps[type] = NULL; 2609076c6e45SArnaldo Carvalho de Melo } 2610076c6e45SArnaldo Carvalho de Melo } 2611076c6e45SArnaldo Carvalho de Melo 2612aeafcbafSArnaldo Carvalho de Melo int machine__create_kernel_maps(struct machine *machine) 26135c0541d5SArnaldo Carvalho de Melo { 2614f57b05edSJiri Olsa struct dso *kernel = machine__get_kernel(machine); 26155c0541d5SArnaldo Carvalho de Melo 26165c0541d5SArnaldo Carvalho de Melo if (kernel == NULL || 2617aeafcbafSArnaldo Carvalho de Melo __machine__create_kernel_maps(machine, kernel) < 0) 26185c0541d5SArnaldo Carvalho de Melo return -1; 26195c0541d5SArnaldo Carvalho de Melo 2620f51304d3SDavid Ahern if (symbol_conf.use_modules && machine__create_modules(machine) < 0) { 2621f51304d3SDavid Ahern if (machine__is_host(machine)) 2622f51304d3SDavid Ahern pr_debug("Problems creating module maps, " 2623f51304d3SDavid Ahern "continuing anyway...\n"); 2624f51304d3SDavid Ahern else 2625f51304d3SDavid Ahern pr_debug("Problems creating module maps for guest %d, " 2626f51304d3SDavid Ahern "continuing anyway...\n", machine->pid); 2627f51304d3SDavid Ahern } 2628f51304d3SDavid Ahern 26295c0541d5SArnaldo Carvalho de Melo /* 26305c0541d5SArnaldo Carvalho de Melo * Now that we have all the maps created, just set the ->end of them: 26315c0541d5SArnaldo Carvalho de Melo */ 2632aeafcbafSArnaldo Carvalho de Melo map_groups__fixup_end(&machine->kmaps); 26335c0541d5SArnaldo Carvalho de Melo return 0; 26345c0541d5SArnaldo Carvalho de Melo } 26355c0541d5SArnaldo Carvalho de Melo 2636cc612d81SArnaldo Carvalho de Melo static void vmlinux_path__exit(void) 26372446042cSArnaldo Carvalho de Melo { 2638cc612d81SArnaldo Carvalho de Melo while (--vmlinux_path__nr_entries >= 0) { 2639cc612d81SArnaldo Carvalho de Melo free(vmlinux_path[vmlinux_path__nr_entries]); 2640cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = NULL; 2641cc612d81SArnaldo Carvalho de Melo } 2642cc612d81SArnaldo Carvalho de Melo 2643cc612d81SArnaldo Carvalho de Melo free(vmlinux_path); 2644cc612d81SArnaldo Carvalho de Melo vmlinux_path = NULL; 2645cc612d81SArnaldo Carvalho de Melo } 2646cc612d81SArnaldo Carvalho de Melo 2647cc612d81SArnaldo Carvalho de Melo static int vmlinux_path__init(void) 2648cc612d81SArnaldo Carvalho de Melo { 2649cc612d81SArnaldo Carvalho de Melo struct utsname uts; 2650cc612d81SArnaldo Carvalho de Melo char bf[PATH_MAX]; 2651cc612d81SArnaldo Carvalho de Melo 2652cc612d81SArnaldo Carvalho de Melo vmlinux_path = malloc(sizeof(char *) * 5); 2653cc612d81SArnaldo Carvalho de Melo if (vmlinux_path == NULL) 2654cc612d81SArnaldo Carvalho de Melo return -1; 2655cc612d81SArnaldo Carvalho de Melo 2656cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup("vmlinux"); 2657cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 2658cc612d81SArnaldo Carvalho de Melo goto out_fail; 2659cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 2660cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup("/boot/vmlinux"); 2661cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 2662cc612d81SArnaldo Carvalho de Melo goto out_fail; 2663cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 2664ec5761eaSDavid Ahern 2665ec5761eaSDavid Ahern /* only try running kernel version if no symfs was given */ 2666ec5761eaSDavid Ahern if (symbol_conf.symfs[0] != 0) 2667ec5761eaSDavid Ahern return 0; 2668ec5761eaSDavid Ahern 2669ec5761eaSDavid Ahern if (uname(&uts) < 0) 2670ec5761eaSDavid Ahern return -1; 2671ec5761eaSDavid Ahern 2672cc612d81SArnaldo Carvalho de Melo snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", uts.release); 2673cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); 2674cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 2675cc612d81SArnaldo Carvalho de Melo goto out_fail; 2676cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 2677cc612d81SArnaldo Carvalho de Melo snprintf(bf, sizeof(bf), "/lib/modules/%s/build/vmlinux", uts.release); 2678cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); 2679cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 2680cc612d81SArnaldo Carvalho de Melo goto out_fail; 2681cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 2682cc612d81SArnaldo Carvalho de Melo snprintf(bf, sizeof(bf), "/usr/lib/debug/lib/modules/%s/vmlinux", 2683cc612d81SArnaldo Carvalho de Melo uts.release); 2684cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); 2685cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 2686cc612d81SArnaldo Carvalho de Melo goto out_fail; 2687cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 2688cc612d81SArnaldo Carvalho de Melo 2689cc612d81SArnaldo Carvalho de Melo return 0; 2690cc612d81SArnaldo Carvalho de Melo 2691cc612d81SArnaldo Carvalho de Melo out_fail: 2692cc612d81SArnaldo Carvalho de Melo vmlinux_path__exit(); 2693cc612d81SArnaldo Carvalho de Melo return -1; 2694cc612d81SArnaldo Carvalho de Melo } 2695cc612d81SArnaldo Carvalho de Melo 2696aeafcbafSArnaldo Carvalho de Melo size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp) 2697b0a9ab62SArnaldo Carvalho de Melo { 2698b0a9ab62SArnaldo Carvalho de Melo int i; 2699b0a9ab62SArnaldo Carvalho de Melo size_t printed = 0; 2700aeafcbafSArnaldo Carvalho de Melo struct dso *kdso = machine->vmlinux_maps[MAP__FUNCTION]->dso; 27015ad90e4eSArnaldo Carvalho de Melo 27025ad90e4eSArnaldo Carvalho de Melo if (kdso->has_build_id) { 27035ad90e4eSArnaldo Carvalho de Melo char filename[PATH_MAX]; 27045ad90e4eSArnaldo Carvalho de Melo if (dso__build_id_filename(kdso, filename, sizeof(filename))) 27055ad90e4eSArnaldo Carvalho de Melo printed += fprintf(fp, "[0] %s\n", filename); 27065ad90e4eSArnaldo Carvalho de Melo } 2707b0a9ab62SArnaldo Carvalho de Melo 2708b0a9ab62SArnaldo Carvalho de Melo for (i = 0; i < vmlinux_path__nr_entries; ++i) 27095ad90e4eSArnaldo Carvalho de Melo printed += fprintf(fp, "[%d] %s\n", 27105ad90e4eSArnaldo Carvalho de Melo i + kdso->has_build_id, vmlinux_path[i]); 2711b0a9ab62SArnaldo Carvalho de Melo 2712b0a9ab62SArnaldo Carvalho de Melo return printed; 2713b0a9ab62SArnaldo Carvalho de Melo } 2714b0a9ab62SArnaldo Carvalho de Melo 2715655000e7SArnaldo Carvalho de Melo static int setup_list(struct strlist **list, const char *list_str, 2716655000e7SArnaldo Carvalho de Melo const char *list_name) 2717655000e7SArnaldo Carvalho de Melo { 2718655000e7SArnaldo Carvalho de Melo if (list_str == NULL) 2719655000e7SArnaldo Carvalho de Melo return 0; 2720655000e7SArnaldo Carvalho de Melo 2721655000e7SArnaldo Carvalho de Melo *list = strlist__new(true, list_str); 2722655000e7SArnaldo Carvalho de Melo if (!*list) { 2723655000e7SArnaldo Carvalho de Melo pr_err("problems parsing %s list\n", list_name); 2724655000e7SArnaldo Carvalho de Melo return -1; 2725655000e7SArnaldo Carvalho de Melo } 2726655000e7SArnaldo Carvalho de Melo return 0; 2727655000e7SArnaldo Carvalho de Melo } 2728655000e7SArnaldo Carvalho de Melo 2729ec80fde7SArnaldo Carvalho de Melo static bool symbol__read_kptr_restrict(void) 2730ec80fde7SArnaldo Carvalho de Melo { 2731ec80fde7SArnaldo Carvalho de Melo bool value = false; 2732ec80fde7SArnaldo Carvalho de Melo 2733ec80fde7SArnaldo Carvalho de Melo if (geteuid() != 0) { 2734ec80fde7SArnaldo Carvalho de Melo FILE *fp = fopen("/proc/sys/kernel/kptr_restrict", "r"); 2735ec80fde7SArnaldo Carvalho de Melo if (fp != NULL) { 2736ec80fde7SArnaldo Carvalho de Melo char line[8]; 2737ec80fde7SArnaldo Carvalho de Melo 2738ec80fde7SArnaldo Carvalho de Melo if (fgets(line, sizeof(line), fp) != NULL) 2739ec80fde7SArnaldo Carvalho de Melo value = atoi(line) != 0; 2740ec80fde7SArnaldo Carvalho de Melo 2741ec80fde7SArnaldo Carvalho de Melo fclose(fp); 2742ec80fde7SArnaldo Carvalho de Melo } 2743ec80fde7SArnaldo Carvalho de Melo } 2744ec80fde7SArnaldo Carvalho de Melo 2745ec80fde7SArnaldo Carvalho de Melo return value; 2746ec80fde7SArnaldo Carvalho de Melo } 2747ec80fde7SArnaldo Carvalho de Melo 274875be6cf4SArnaldo Carvalho de Melo int symbol__init(void) 2749cc612d81SArnaldo Carvalho de Melo { 2750ec5761eaSDavid Ahern const char *symfs; 2751ec5761eaSDavid Ahern 275285e00b55SJovi Zhang if (symbol_conf.initialized) 275385e00b55SJovi Zhang return 0; 275485e00b55SJovi Zhang 27554d439517SDavid S. Miller symbol_conf.priv_size = ALIGN(symbol_conf.priv_size, sizeof(u64)); 27564d439517SDavid S. Miller 275795011c60SArnaldo Carvalho de Melo elf_version(EV_CURRENT); 275875be6cf4SArnaldo Carvalho de Melo if (symbol_conf.sort_by_name) 275975be6cf4SArnaldo Carvalho de Melo symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) - 276079406cd7SArnaldo Carvalho de Melo sizeof(struct symbol)); 2761b32d133aSArnaldo Carvalho de Melo 276275be6cf4SArnaldo Carvalho de Melo if (symbol_conf.try_vmlinux_path && vmlinux_path__init() < 0) 2763cc612d81SArnaldo Carvalho de Melo return -1; 2764cc612d81SArnaldo Carvalho de Melo 2765c410a338SArnaldo Carvalho de Melo if (symbol_conf.field_sep && *symbol_conf.field_sep == '.') { 2766c410a338SArnaldo Carvalho de Melo pr_err("'.' is the only non valid --field-separator argument\n"); 2767c410a338SArnaldo Carvalho de Melo return -1; 2768c410a338SArnaldo Carvalho de Melo } 2769c410a338SArnaldo Carvalho de Melo 2770655000e7SArnaldo Carvalho de Melo if (setup_list(&symbol_conf.dso_list, 2771655000e7SArnaldo Carvalho de Melo symbol_conf.dso_list_str, "dso") < 0) 2772655000e7SArnaldo Carvalho de Melo return -1; 2773655000e7SArnaldo Carvalho de Melo 2774655000e7SArnaldo Carvalho de Melo if (setup_list(&symbol_conf.comm_list, 2775655000e7SArnaldo Carvalho de Melo symbol_conf.comm_list_str, "comm") < 0) 2776655000e7SArnaldo Carvalho de Melo goto out_free_dso_list; 2777655000e7SArnaldo Carvalho de Melo 2778655000e7SArnaldo Carvalho de Melo if (setup_list(&symbol_conf.sym_list, 2779655000e7SArnaldo Carvalho de Melo symbol_conf.sym_list_str, "symbol") < 0) 2780655000e7SArnaldo Carvalho de Melo goto out_free_comm_list; 2781655000e7SArnaldo Carvalho de Melo 2782ec5761eaSDavid Ahern /* 2783ec5761eaSDavid Ahern * A path to symbols of "/" is identical to "" 2784ec5761eaSDavid Ahern * reset here for simplicity. 2785ec5761eaSDavid Ahern */ 2786ec5761eaSDavid Ahern symfs = realpath(symbol_conf.symfs, NULL); 2787ec5761eaSDavid Ahern if (symfs == NULL) 2788ec5761eaSDavid Ahern symfs = symbol_conf.symfs; 2789ec5761eaSDavid Ahern if (strcmp(symfs, "/") == 0) 2790ec5761eaSDavid Ahern symbol_conf.symfs = ""; 2791ec5761eaSDavid Ahern if (symfs != symbol_conf.symfs) 2792ec5761eaSDavid Ahern free((void *)symfs); 2793ec5761eaSDavid Ahern 2794ec80fde7SArnaldo Carvalho de Melo symbol_conf.kptr_restrict = symbol__read_kptr_restrict(); 2795ec80fde7SArnaldo Carvalho de Melo 279685e00b55SJovi Zhang symbol_conf.initialized = true; 27974aa65636SArnaldo Carvalho de Melo return 0; 2798655000e7SArnaldo Carvalho de Melo 2799655000e7SArnaldo Carvalho de Melo out_free_comm_list: 2800655000e7SArnaldo Carvalho de Melo strlist__delete(symbol_conf.comm_list); 2801d74c896bSNamhyung Kim out_free_dso_list: 2802d74c896bSNamhyung Kim strlist__delete(symbol_conf.dso_list); 2803655000e7SArnaldo Carvalho de Melo return -1; 2804cc612d81SArnaldo Carvalho de Melo } 2805cc612d81SArnaldo Carvalho de Melo 2806d65a458bSArnaldo Carvalho de Melo void symbol__exit(void) 2807d65a458bSArnaldo Carvalho de Melo { 280885e00b55SJovi Zhang if (!symbol_conf.initialized) 280985e00b55SJovi Zhang return; 2810d65a458bSArnaldo Carvalho de Melo strlist__delete(symbol_conf.sym_list); 2811d65a458bSArnaldo Carvalho de Melo strlist__delete(symbol_conf.dso_list); 2812d65a458bSArnaldo Carvalho de Melo strlist__delete(symbol_conf.comm_list); 2813d65a458bSArnaldo Carvalho de Melo vmlinux_path__exit(); 2814d65a458bSArnaldo Carvalho de Melo symbol_conf.sym_list = symbol_conf.dso_list = symbol_conf.comm_list = NULL; 281585e00b55SJovi Zhang symbol_conf.initialized = false; 2816d65a458bSArnaldo Carvalho de Melo } 2817d65a458bSArnaldo Carvalho de Melo 2818aeafcbafSArnaldo Carvalho de Melo int machines__create_kernel_maps(struct rb_root *machines, pid_t pid) 28194aa65636SArnaldo Carvalho de Melo { 2820aeafcbafSArnaldo Carvalho de Melo struct machine *machine = machines__findnew(machines, pid); 28219de89fe7SArnaldo Carvalho de Melo 282223346f21SArnaldo Carvalho de Melo if (machine == NULL) 2823a1645ce1SZhang, Yanmin return -1; 28244aa65636SArnaldo Carvalho de Melo 28255c0541d5SArnaldo Carvalho de Melo return machine__create_kernel_maps(machine); 2826cd84c2acSFrederic Weisbecker } 28275aab621bSArnaldo Carvalho de Melo 28285aab621bSArnaldo Carvalho de Melo static int hex(char ch) 28295aab621bSArnaldo Carvalho de Melo { 28305aab621bSArnaldo Carvalho de Melo if ((ch >= '0') && (ch <= '9')) 28315aab621bSArnaldo Carvalho de Melo return ch - '0'; 28325aab621bSArnaldo Carvalho de Melo if ((ch >= 'a') && (ch <= 'f')) 28335aab621bSArnaldo Carvalho de Melo return ch - 'a' + 10; 28345aab621bSArnaldo Carvalho de Melo if ((ch >= 'A') && (ch <= 'F')) 28355aab621bSArnaldo Carvalho de Melo return ch - 'A' + 10; 28365aab621bSArnaldo Carvalho de Melo return -1; 28375aab621bSArnaldo Carvalho de Melo } 28385aab621bSArnaldo Carvalho de Melo 28395aab621bSArnaldo Carvalho de Melo /* 28405aab621bSArnaldo Carvalho de Melo * While we find nice hex chars, build a long_val. 28415aab621bSArnaldo Carvalho de Melo * Return number of chars processed. 28425aab621bSArnaldo Carvalho de Melo */ 28435aab621bSArnaldo Carvalho de Melo int hex2u64(const char *ptr, u64 *long_val) 28445aab621bSArnaldo Carvalho de Melo { 28455aab621bSArnaldo Carvalho de Melo const char *p = ptr; 28465aab621bSArnaldo Carvalho de Melo *long_val = 0; 28475aab621bSArnaldo Carvalho de Melo 28485aab621bSArnaldo Carvalho de Melo while (*p) { 28495aab621bSArnaldo Carvalho de Melo const int hex_val = hex(*p); 28505aab621bSArnaldo Carvalho de Melo 28515aab621bSArnaldo Carvalho de Melo if (hex_val < 0) 28525aab621bSArnaldo Carvalho de Melo break; 28535aab621bSArnaldo Carvalho de Melo 28545aab621bSArnaldo Carvalho de Melo *long_val = (*long_val << 4) | hex_val; 28555aab621bSArnaldo Carvalho de Melo p++; 28565aab621bSArnaldo Carvalho de Melo } 28575aab621bSArnaldo Carvalho de Melo 28585aab621bSArnaldo Carvalho de Melo return p - ptr; 28595aab621bSArnaldo Carvalho de Melo } 28605aab621bSArnaldo Carvalho de Melo 28615aab621bSArnaldo Carvalho de Melo char *strxfrchar(char *s, char from, char to) 28625aab621bSArnaldo Carvalho de Melo { 28635aab621bSArnaldo Carvalho de Melo char *p = s; 28645aab621bSArnaldo Carvalho de Melo 28655aab621bSArnaldo Carvalho de Melo while ((p = strchr(p, from)) != NULL) 28665aab621bSArnaldo Carvalho de Melo *p++ = to; 28675aab621bSArnaldo Carvalho de Melo 28685aab621bSArnaldo Carvalho de Melo return s; 28695aab621bSArnaldo Carvalho de Melo } 2870a1645ce1SZhang, Yanmin 2871aeafcbafSArnaldo Carvalho de Melo int machines__create_guest_kernel_maps(struct rb_root *machines) 2872a1645ce1SZhang, Yanmin { 2873a1645ce1SZhang, Yanmin int ret = 0; 2874a1645ce1SZhang, Yanmin struct dirent **namelist = NULL; 2875a1645ce1SZhang, Yanmin int i, items = 0; 2876a1645ce1SZhang, Yanmin char path[PATH_MAX]; 2877a1645ce1SZhang, Yanmin pid_t pid; 2878a1645ce1SZhang, Yanmin 2879a1645ce1SZhang, Yanmin if (symbol_conf.default_guest_vmlinux_name || 2880a1645ce1SZhang, Yanmin symbol_conf.default_guest_modules || 2881a1645ce1SZhang, Yanmin symbol_conf.default_guest_kallsyms) { 2882aeafcbafSArnaldo Carvalho de Melo machines__create_kernel_maps(machines, DEFAULT_GUEST_KERNEL_ID); 2883a1645ce1SZhang, Yanmin } 2884a1645ce1SZhang, Yanmin 2885a1645ce1SZhang, Yanmin if (symbol_conf.guestmount) { 2886a1645ce1SZhang, Yanmin items = scandir(symbol_conf.guestmount, &namelist, NULL, NULL); 2887a1645ce1SZhang, Yanmin if (items <= 0) 2888a1645ce1SZhang, Yanmin return -ENOENT; 2889a1645ce1SZhang, Yanmin for (i = 0; i < items; i++) { 2890a1645ce1SZhang, Yanmin if (!isdigit(namelist[i]->d_name[0])) { 2891a1645ce1SZhang, Yanmin /* Filter out . and .. */ 2892a1645ce1SZhang, Yanmin continue; 2893a1645ce1SZhang, Yanmin } 2894a1645ce1SZhang, Yanmin pid = atoi(namelist[i]->d_name); 2895a1645ce1SZhang, Yanmin sprintf(path, "%s/%s/proc/kallsyms", 2896a1645ce1SZhang, Yanmin symbol_conf.guestmount, 2897a1645ce1SZhang, Yanmin namelist[i]->d_name); 2898a1645ce1SZhang, Yanmin ret = access(path, R_OK); 2899a1645ce1SZhang, Yanmin if (ret) { 2900a1645ce1SZhang, Yanmin pr_debug("Can't access file %s\n", path); 2901a1645ce1SZhang, Yanmin goto failure; 2902a1645ce1SZhang, Yanmin } 2903aeafcbafSArnaldo Carvalho de Melo machines__create_kernel_maps(machines, pid); 2904a1645ce1SZhang, Yanmin } 2905a1645ce1SZhang, Yanmin failure: 2906a1645ce1SZhang, Yanmin free(namelist); 2907a1645ce1SZhang, Yanmin } 2908a1645ce1SZhang, Yanmin 2909a1645ce1SZhang, Yanmin return ret; 2910a1645ce1SZhang, Yanmin } 29115c0541d5SArnaldo Carvalho de Melo 2912aeafcbafSArnaldo Carvalho de Melo void machines__destroy_guest_kernel_maps(struct rb_root *machines) 2913076c6e45SArnaldo Carvalho de Melo { 2914aeafcbafSArnaldo Carvalho de Melo struct rb_node *next = rb_first(machines); 2915076c6e45SArnaldo Carvalho de Melo 2916076c6e45SArnaldo Carvalho de Melo while (next) { 2917076c6e45SArnaldo Carvalho de Melo struct machine *pos = rb_entry(next, struct machine, rb_node); 2918076c6e45SArnaldo Carvalho de Melo 2919076c6e45SArnaldo Carvalho de Melo next = rb_next(&pos->rb_node); 2920aeafcbafSArnaldo Carvalho de Melo rb_erase(&pos->rb_node, machines); 2921076c6e45SArnaldo Carvalho de Melo machine__delete(pos); 2922076c6e45SArnaldo Carvalho de Melo } 2923076c6e45SArnaldo Carvalho de Melo } 2924076c6e45SArnaldo Carvalho de Melo 2925aeafcbafSArnaldo Carvalho de Melo int machine__load_kallsyms(struct machine *machine, const char *filename, 29265c0541d5SArnaldo Carvalho de Melo enum map_type type, symbol_filter_t filter) 29275c0541d5SArnaldo Carvalho de Melo { 2928aeafcbafSArnaldo Carvalho de Melo struct map *map = machine->vmlinux_maps[type]; 29295c0541d5SArnaldo Carvalho de Melo int ret = dso__load_kallsyms(map->dso, filename, map, filter); 29305c0541d5SArnaldo Carvalho de Melo 29315c0541d5SArnaldo Carvalho de Melo if (ret > 0) { 29325c0541d5SArnaldo Carvalho de Melo dso__set_loaded(map->dso, type); 29335c0541d5SArnaldo Carvalho de Melo /* 29345c0541d5SArnaldo Carvalho de Melo * Since /proc/kallsyms will have multiple sessions for the 29355c0541d5SArnaldo Carvalho de Melo * kernel, with modules between them, fixup the end of all 29365c0541d5SArnaldo Carvalho de Melo * sections. 29375c0541d5SArnaldo Carvalho de Melo */ 2938aeafcbafSArnaldo Carvalho de Melo __map_groups__fixup_end(&machine->kmaps, type); 29395c0541d5SArnaldo Carvalho de Melo } 29405c0541d5SArnaldo Carvalho de Melo 29415c0541d5SArnaldo Carvalho de Melo return ret; 29425c0541d5SArnaldo Carvalho de Melo } 29435c0541d5SArnaldo Carvalho de Melo 2944aeafcbafSArnaldo Carvalho de Melo int machine__load_vmlinux_path(struct machine *machine, enum map_type type, 29455c0541d5SArnaldo Carvalho de Melo symbol_filter_t filter) 29465c0541d5SArnaldo Carvalho de Melo { 2947aeafcbafSArnaldo Carvalho de Melo struct map *map = machine->vmlinux_maps[type]; 29485c0541d5SArnaldo Carvalho de Melo int ret = dso__load_vmlinux_path(map->dso, map, filter); 29495c0541d5SArnaldo Carvalho de Melo 29505c0541d5SArnaldo Carvalho de Melo if (ret > 0) { 29515c0541d5SArnaldo Carvalho de Melo dso__set_loaded(map->dso, type); 29525c0541d5SArnaldo Carvalho de Melo map__reloc_vmlinux(map); 29535c0541d5SArnaldo Carvalho de Melo } 29545c0541d5SArnaldo Carvalho de Melo 29555c0541d5SArnaldo Carvalho de Melo return ret; 29565c0541d5SArnaldo Carvalho de Melo } 2957225466f1SSrikar Dronamraju 2958225466f1SSrikar Dronamraju struct map *dso__new_map(const char *name) 2959225466f1SSrikar Dronamraju { 2960378474e4SSrikar Dronamraju struct map *map = NULL; 2961225466f1SSrikar Dronamraju struct dso *dso = dso__new(name); 2962378474e4SSrikar Dronamraju 2963378474e4SSrikar Dronamraju if (dso) 2964378474e4SSrikar Dronamraju map = map__new2(0, dso, MAP__FUNCTION); 2965225466f1SSrikar Dronamraju 2966225466f1SSrikar Dronamraju return map; 2967225466f1SSrikar Dronamraju } 2968949d160bSJiri Olsa 2969949d160bSJiri Olsa static int open_dso(struct dso *dso, struct machine *machine) 2970949d160bSJiri Olsa { 2971949d160bSJiri Olsa char *root_dir = (char *) ""; 2972949d160bSJiri Olsa char *name; 2973949d160bSJiri Olsa int fd; 2974949d160bSJiri Olsa 2975949d160bSJiri Olsa name = malloc(PATH_MAX); 2976949d160bSJiri Olsa if (!name) 2977949d160bSJiri Olsa return -ENOMEM; 2978949d160bSJiri Olsa 2979949d160bSJiri Olsa if (machine) 2980949d160bSJiri Olsa root_dir = machine->root_dir; 2981949d160bSJiri Olsa 2982949d160bSJiri Olsa if (dso__binary_type_file(dso, dso->data_type, 2983949d160bSJiri Olsa root_dir, name, PATH_MAX)) { 2984949d160bSJiri Olsa free(name); 2985949d160bSJiri Olsa return -EINVAL; 2986949d160bSJiri Olsa } 2987949d160bSJiri Olsa 2988949d160bSJiri Olsa fd = open(name, O_RDONLY); 2989949d160bSJiri Olsa free(name); 2990949d160bSJiri Olsa return fd; 2991949d160bSJiri Olsa } 2992949d160bSJiri Olsa 2993949d160bSJiri Olsa int dso__data_fd(struct dso *dso, struct machine *machine) 2994949d160bSJiri Olsa { 2995949d160bSJiri Olsa int i = 0; 2996949d160bSJiri Olsa 2997949d160bSJiri Olsa if (dso->data_type != DSO_BINARY_TYPE__NOT_FOUND) 2998949d160bSJiri Olsa return open_dso(dso, machine); 2999949d160bSJiri Olsa 3000949d160bSJiri Olsa do { 3001949d160bSJiri Olsa int fd; 3002949d160bSJiri Olsa 3003949d160bSJiri Olsa dso->data_type = binary_type_data[i++]; 3004949d160bSJiri Olsa 3005949d160bSJiri Olsa fd = open_dso(dso, machine); 3006949d160bSJiri Olsa if (fd >= 0) 3007949d160bSJiri Olsa return fd; 3008949d160bSJiri Olsa 3009949d160bSJiri Olsa } while (dso->data_type != DSO_BINARY_TYPE__NOT_FOUND); 3010949d160bSJiri Olsa 3011949d160bSJiri Olsa return -EINVAL; 3012949d160bSJiri Olsa } 3013949d160bSJiri Olsa 30144dff624aSJiri Olsa static void 30154dff624aSJiri Olsa dso_cache__free(struct rb_root *root) 3016949d160bSJiri Olsa { 30174dff624aSJiri Olsa struct rb_node *next = rb_first(root); 30184dff624aSJiri Olsa 30194dff624aSJiri Olsa while (next) { 30204dff624aSJiri Olsa struct dso_cache *cache; 30214dff624aSJiri Olsa 30224dff624aSJiri Olsa cache = rb_entry(next, struct dso_cache, rb_node); 30234dff624aSJiri Olsa next = rb_next(&cache->rb_node); 30244dff624aSJiri Olsa rb_erase(&cache->rb_node, root); 30254dff624aSJiri Olsa free(cache); 30264dff624aSJiri Olsa } 3027949d160bSJiri Olsa } 3028949d160bSJiri Olsa 30294dff624aSJiri Olsa static struct dso_cache* 30304dff624aSJiri Olsa dso_cache__find(struct rb_root *root, u64 offset) 3031949d160bSJiri Olsa { 30324dff624aSJiri Olsa struct rb_node **p = &root->rb_node; 30334dff624aSJiri Olsa struct rb_node *parent = NULL; 30344dff624aSJiri Olsa struct dso_cache *cache; 30354dff624aSJiri Olsa 30364dff624aSJiri Olsa while (*p != NULL) { 30374dff624aSJiri Olsa u64 end; 30384dff624aSJiri Olsa 30394dff624aSJiri Olsa parent = *p; 30404dff624aSJiri Olsa cache = rb_entry(parent, struct dso_cache, rb_node); 30414dff624aSJiri Olsa end = cache->offset + DSO__DATA_CACHE_SIZE; 30424dff624aSJiri Olsa 30434dff624aSJiri Olsa if (offset < cache->offset) 30444dff624aSJiri Olsa p = &(*p)->rb_left; 30454dff624aSJiri Olsa else if (offset >= end) 30464dff624aSJiri Olsa p = &(*p)->rb_right; 30474dff624aSJiri Olsa else 30484dff624aSJiri Olsa return cache; 30494dff624aSJiri Olsa } 30504dff624aSJiri Olsa return NULL; 3051949d160bSJiri Olsa } 3052949d160bSJiri Olsa 30534dff624aSJiri Olsa static void 30544dff624aSJiri Olsa dso_cache__insert(struct rb_root *root, struct dso_cache *new) 30554dff624aSJiri Olsa { 30564dff624aSJiri Olsa struct rb_node **p = &root->rb_node; 30574dff624aSJiri Olsa struct rb_node *parent = NULL; 30584dff624aSJiri Olsa struct dso_cache *cache; 30594dff624aSJiri Olsa u64 offset = new->offset; 30604dff624aSJiri Olsa 30614dff624aSJiri Olsa while (*p != NULL) { 30624dff624aSJiri Olsa u64 end; 30634dff624aSJiri Olsa 30644dff624aSJiri Olsa parent = *p; 30654dff624aSJiri Olsa cache = rb_entry(parent, struct dso_cache, rb_node); 30664dff624aSJiri Olsa end = cache->offset + DSO__DATA_CACHE_SIZE; 30674dff624aSJiri Olsa 30684dff624aSJiri Olsa if (offset < cache->offset) 30694dff624aSJiri Olsa p = &(*p)->rb_left; 30704dff624aSJiri Olsa else if (offset >= end) 30714dff624aSJiri Olsa p = &(*p)->rb_right; 30724dff624aSJiri Olsa } 30734dff624aSJiri Olsa 30744dff624aSJiri Olsa rb_link_node(&new->rb_node, parent, p); 30754dff624aSJiri Olsa rb_insert_color(&new->rb_node, root); 30764dff624aSJiri Olsa } 30774dff624aSJiri Olsa 30784dff624aSJiri Olsa static ssize_t 30794dff624aSJiri Olsa dso_cache__memcpy(struct dso_cache *cache, u64 offset, 30804dff624aSJiri Olsa u8 *data, u64 size) 30814dff624aSJiri Olsa { 30824dff624aSJiri Olsa u64 cache_offset = offset - cache->offset; 30834dff624aSJiri Olsa u64 cache_size = min(cache->size - cache_offset, size); 30844dff624aSJiri Olsa 30854dff624aSJiri Olsa memcpy(data, cache->data + cache_offset, cache_size); 30864dff624aSJiri Olsa return cache_size; 30874dff624aSJiri Olsa } 30884dff624aSJiri Olsa 30894dff624aSJiri Olsa static ssize_t 30904dff624aSJiri Olsa dso_cache__read(struct dso *dso, struct machine *machine, 3091949d160bSJiri Olsa u64 offset, u8 *data, ssize_t size) 3092949d160bSJiri Olsa { 30934dff624aSJiri Olsa struct dso_cache *cache; 30944dff624aSJiri Olsa ssize_t ret; 3095949d160bSJiri Olsa int fd; 3096949d160bSJiri Olsa 3097949d160bSJiri Olsa fd = dso__data_fd(dso, machine); 3098949d160bSJiri Olsa if (fd < 0) 3099949d160bSJiri Olsa return -1; 3100949d160bSJiri Olsa 3101949d160bSJiri Olsa do { 31024dff624aSJiri Olsa u64 cache_offset; 31034dff624aSJiri Olsa 31044dff624aSJiri Olsa ret = -ENOMEM; 31054dff624aSJiri Olsa 31064dff624aSJiri Olsa cache = zalloc(sizeof(*cache) + DSO__DATA_CACHE_SIZE); 31074dff624aSJiri Olsa if (!cache) 3108949d160bSJiri Olsa break; 3109949d160bSJiri Olsa 31104dff624aSJiri Olsa cache_offset = offset & DSO__DATA_CACHE_MASK; 31114dff624aSJiri Olsa ret = -EINVAL; 31124dff624aSJiri Olsa 31134dff624aSJiri Olsa if (-1 == lseek(fd, cache_offset, SEEK_SET)) 3114949d160bSJiri Olsa break; 3115949d160bSJiri Olsa 31164dff624aSJiri Olsa ret = read(fd, cache->data, DSO__DATA_CACHE_SIZE); 31174dff624aSJiri Olsa if (ret <= 0) 31184dff624aSJiri Olsa break; 31194dff624aSJiri Olsa 31204dff624aSJiri Olsa cache->offset = cache_offset; 31214dff624aSJiri Olsa cache->size = ret; 31224dff624aSJiri Olsa dso_cache__insert(&dso->cache, cache); 31234dff624aSJiri Olsa 31244dff624aSJiri Olsa ret = dso_cache__memcpy(cache, offset, data, size); 3125949d160bSJiri Olsa 3126949d160bSJiri Olsa } while (0); 3127949d160bSJiri Olsa 31284dff624aSJiri Olsa if (ret <= 0) 31294dff624aSJiri Olsa free(cache); 31304dff624aSJiri Olsa 3131949d160bSJiri Olsa close(fd); 31324dff624aSJiri Olsa return ret; 31334dff624aSJiri Olsa } 31344dff624aSJiri Olsa 31354dff624aSJiri Olsa static ssize_t dso_cache_read(struct dso *dso, struct machine *machine, 31364dff624aSJiri Olsa u64 offset, u8 *data, ssize_t size) 31374dff624aSJiri Olsa { 31384dff624aSJiri Olsa struct dso_cache *cache; 31394dff624aSJiri Olsa 31404dff624aSJiri Olsa cache = dso_cache__find(&dso->cache, offset); 31414dff624aSJiri Olsa if (cache) 31424dff624aSJiri Olsa return dso_cache__memcpy(cache, offset, data, size); 31434dff624aSJiri Olsa else 31444dff624aSJiri Olsa return dso_cache__read(dso, machine, offset, data, size); 3145949d160bSJiri Olsa } 3146949d160bSJiri Olsa 3147949d160bSJiri Olsa ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine, 3148949d160bSJiri Olsa u64 offset, u8 *data, ssize_t size) 3149949d160bSJiri Olsa { 31504dff624aSJiri Olsa ssize_t r = 0; 31514dff624aSJiri Olsa u8 *p = data; 31524dff624aSJiri Olsa 31534dff624aSJiri Olsa do { 31544dff624aSJiri Olsa ssize_t ret; 31554dff624aSJiri Olsa 31564dff624aSJiri Olsa ret = dso_cache_read(dso, machine, offset, p, size); 31574dff624aSJiri Olsa if (ret < 0) 31584dff624aSJiri Olsa return ret; 31594dff624aSJiri Olsa 31604dff624aSJiri Olsa /* Reached EOF, return what we have. */ 31614dff624aSJiri Olsa if (!ret) 31624dff624aSJiri Olsa break; 31634dff624aSJiri Olsa 31644dff624aSJiri Olsa BUG_ON(ret > size); 31654dff624aSJiri Olsa 31664dff624aSJiri Olsa r += ret; 31674dff624aSJiri Olsa p += ret; 31684dff624aSJiri Olsa offset += ret; 31694dff624aSJiri Olsa size -= ret; 31704dff624aSJiri Olsa 31714dff624aSJiri Olsa } while (size); 31724dff624aSJiri Olsa 31734dff624aSJiri Olsa return r; 3174949d160bSJiri Olsa } 3175949d160bSJiri Olsa 3176949d160bSJiri Olsa ssize_t dso__data_read_addr(struct dso *dso, struct map *map, 3177949d160bSJiri Olsa struct machine *machine, u64 addr, 3178949d160bSJiri Olsa u8 *data, ssize_t size) 3179949d160bSJiri Olsa { 3180949d160bSJiri Olsa u64 offset = map->map_ip(map, addr); 3181949d160bSJiri Olsa return dso__data_read_offset(dso, machine, offset, data, size); 3182949d160bSJiri Olsa } 3183