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 32aeafcbafSArnaldo Carvalho de Melo static bool dso__build_id_equal(const struct dso *dso, u8 *build_id); 3321916c38SDave Martin static int elf_read_build_id(Elf *elf, void *bf, size_t size); 34b0da954aSArnaldo Carvalho de Melo static void dsos__add(struct list_head *head, struct dso *dso); 353610583cSArnaldo Carvalho de Melo static struct map *map__new2(u64 start, struct dso *dso, enum map_type type); 36aeafcbafSArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *dso, struct map *map, 379de89fe7SArnaldo Carvalho de Melo symbol_filter_t filter); 38aeafcbafSArnaldo Carvalho de Melo static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map, 39a1645ce1SZhang, Yanmin symbol_filter_t filter); 40cc612d81SArnaldo Carvalho de Melo static int vmlinux_path__nr_entries; 41cc612d81SArnaldo Carvalho de Melo static char **vmlinux_path; 42439d473bSArnaldo Carvalho de Melo 4375be6cf4SArnaldo Carvalho de Melo struct symbol_conf symbol_conf = { 44d599db3fSArnaldo Carvalho de Melo .exclude_other = true, 45b32d133aSArnaldo Carvalho de Melo .use_modules = true, 46b32d133aSArnaldo Carvalho de Melo .try_vmlinux_path = true, 473e6a2a7fSStephane Eranian .annotate_src = true, 48ec5761eaSDavid Ahern .symfs = "", 49b32d133aSArnaldo Carvalho de Melo }; 50b32d133aSArnaldo Carvalho de Melo 51aeafcbafSArnaldo Carvalho de Melo int dso__name_len(const struct dso *dso) 528a6c5b26SArnaldo Carvalho de Melo { 531e2dd2f7SDavid Miller if (!dso) 541e2dd2f7SDavid Miller return strlen("[unknown]"); 558a6c5b26SArnaldo Carvalho de Melo if (verbose) 56aeafcbafSArnaldo Carvalho de Melo return dso->long_name_len; 578a6c5b26SArnaldo Carvalho de Melo 58aeafcbafSArnaldo Carvalho de Melo return dso->short_name_len; 598a6c5b26SArnaldo Carvalho de Melo } 608a6c5b26SArnaldo Carvalho de Melo 61aeafcbafSArnaldo Carvalho de Melo bool dso__loaded(const struct dso *dso, enum map_type type) 623610583cSArnaldo Carvalho de Melo { 63aeafcbafSArnaldo Carvalho de Melo return dso->loaded & (1 << type); 643610583cSArnaldo Carvalho de Melo } 653610583cSArnaldo Carvalho de Melo 66aeafcbafSArnaldo Carvalho de Melo bool dso__sorted_by_name(const struct dso *dso, enum map_type type) 6779406cd7SArnaldo Carvalho de Melo { 68aeafcbafSArnaldo Carvalho de Melo return dso->sorted_by_name & (1 << type); 6979406cd7SArnaldo Carvalho de Melo } 7079406cd7SArnaldo Carvalho de Melo 71aeafcbafSArnaldo Carvalho de Melo static void dso__set_sorted_by_name(struct dso *dso, enum map_type type) 7279406cd7SArnaldo Carvalho de Melo { 73aeafcbafSArnaldo Carvalho de Melo dso->sorted_by_name |= (1 << type); 7479406cd7SArnaldo Carvalho de Melo } 7579406cd7SArnaldo Carvalho de Melo 7636a3e646SArnaldo Carvalho de Melo bool symbol_type__is_a(char symbol_type, enum map_type map_type) 776893d4eeSArnaldo Carvalho de Melo { 7831877908SAnton Blanchard symbol_type = toupper(symbol_type); 7931877908SAnton Blanchard 806893d4eeSArnaldo Carvalho de Melo switch (map_type) { 816893d4eeSArnaldo Carvalho de Melo case MAP__FUNCTION: 826893d4eeSArnaldo Carvalho de Melo return symbol_type == 'T' || symbol_type == 'W'; 83f1dfa0b1SArnaldo Carvalho de Melo case MAP__VARIABLE: 8431877908SAnton Blanchard return symbol_type == 'D'; 856893d4eeSArnaldo Carvalho de Melo default: 866893d4eeSArnaldo Carvalho de Melo return false; 876893d4eeSArnaldo Carvalho de Melo } 886893d4eeSArnaldo Carvalho de Melo } 896893d4eeSArnaldo Carvalho de Melo 90694bf407SAnton Blanchard static int prefix_underscores_count(const char *str) 91694bf407SAnton Blanchard { 92694bf407SAnton Blanchard const char *tail = str; 93694bf407SAnton Blanchard 94694bf407SAnton Blanchard while (*tail == '_') 95694bf407SAnton Blanchard tail++; 96694bf407SAnton Blanchard 97694bf407SAnton Blanchard return tail - str; 98694bf407SAnton Blanchard } 99694bf407SAnton Blanchard 100694bf407SAnton Blanchard #define SYMBOL_A 0 101694bf407SAnton Blanchard #define SYMBOL_B 1 102694bf407SAnton Blanchard 103694bf407SAnton Blanchard static int choose_best_symbol(struct symbol *syma, struct symbol *symb) 104694bf407SAnton Blanchard { 105694bf407SAnton Blanchard s64 a; 106694bf407SAnton Blanchard s64 b; 107694bf407SAnton Blanchard 108694bf407SAnton Blanchard /* Prefer a symbol with non zero length */ 109694bf407SAnton Blanchard a = syma->end - syma->start; 110694bf407SAnton Blanchard b = symb->end - symb->start; 111694bf407SAnton Blanchard if ((b == 0) && (a > 0)) 112694bf407SAnton Blanchard return SYMBOL_A; 113694bf407SAnton Blanchard else if ((a == 0) && (b > 0)) 114694bf407SAnton Blanchard return SYMBOL_B; 115694bf407SAnton Blanchard 116694bf407SAnton Blanchard /* Prefer a non weak symbol over a weak one */ 117694bf407SAnton Blanchard a = syma->binding == STB_WEAK; 118694bf407SAnton Blanchard b = symb->binding == STB_WEAK; 119694bf407SAnton Blanchard if (b && !a) 120694bf407SAnton Blanchard return SYMBOL_A; 121694bf407SAnton Blanchard if (a && !b) 122694bf407SAnton Blanchard return SYMBOL_B; 123694bf407SAnton Blanchard 124694bf407SAnton Blanchard /* Prefer a global symbol over a non global one */ 125694bf407SAnton Blanchard a = syma->binding == STB_GLOBAL; 126694bf407SAnton Blanchard b = symb->binding == STB_GLOBAL; 127694bf407SAnton Blanchard if (a && !b) 128694bf407SAnton Blanchard return SYMBOL_A; 129694bf407SAnton Blanchard if (b && !a) 130694bf407SAnton Blanchard return SYMBOL_B; 131694bf407SAnton Blanchard 132694bf407SAnton Blanchard /* Prefer a symbol with less underscores */ 133694bf407SAnton Blanchard a = prefix_underscores_count(syma->name); 134694bf407SAnton Blanchard b = prefix_underscores_count(symb->name); 135694bf407SAnton Blanchard if (b > a) 136694bf407SAnton Blanchard return SYMBOL_A; 137694bf407SAnton Blanchard else if (a > b) 138694bf407SAnton Blanchard return SYMBOL_B; 139694bf407SAnton Blanchard 140694bf407SAnton Blanchard /* If all else fails, choose the symbol with the longest name */ 141694bf407SAnton Blanchard if (strlen(syma->name) >= strlen(symb->name)) 142694bf407SAnton Blanchard return SYMBOL_A; 143694bf407SAnton Blanchard else 144694bf407SAnton Blanchard return SYMBOL_B; 145694bf407SAnton Blanchard } 146694bf407SAnton Blanchard 147694bf407SAnton Blanchard static void symbols__fixup_duplicate(struct rb_root *symbols) 148694bf407SAnton Blanchard { 149694bf407SAnton Blanchard struct rb_node *nd; 150694bf407SAnton Blanchard struct symbol *curr, *next; 151694bf407SAnton Blanchard 152694bf407SAnton Blanchard nd = rb_first(symbols); 153694bf407SAnton Blanchard 154694bf407SAnton Blanchard while (nd) { 155694bf407SAnton Blanchard curr = rb_entry(nd, struct symbol, rb_node); 156694bf407SAnton Blanchard again: 157694bf407SAnton Blanchard nd = rb_next(&curr->rb_node); 158694bf407SAnton Blanchard next = rb_entry(nd, struct symbol, rb_node); 159694bf407SAnton Blanchard 160694bf407SAnton Blanchard if (!nd) 161694bf407SAnton Blanchard break; 162694bf407SAnton Blanchard 163694bf407SAnton Blanchard if (curr->start != next->start) 164694bf407SAnton Blanchard continue; 165694bf407SAnton Blanchard 166694bf407SAnton Blanchard if (choose_best_symbol(curr, next) == SYMBOL_A) { 167694bf407SAnton Blanchard rb_erase(&next->rb_node, symbols); 168694bf407SAnton Blanchard goto again; 169694bf407SAnton Blanchard } else { 170694bf407SAnton Blanchard nd = rb_next(&curr->rb_node); 171694bf407SAnton Blanchard rb_erase(&curr->rb_node, symbols); 172694bf407SAnton Blanchard } 173694bf407SAnton Blanchard } 174694bf407SAnton Blanchard } 175694bf407SAnton Blanchard 176aeafcbafSArnaldo Carvalho de Melo static void symbols__fixup_end(struct rb_root *symbols) 177af427bf5SArnaldo Carvalho de Melo { 178aeafcbafSArnaldo Carvalho de Melo struct rb_node *nd, *prevnd = rb_first(symbols); 1792e538c4aSArnaldo Carvalho de Melo struct symbol *curr, *prev; 180af427bf5SArnaldo Carvalho de Melo 181af427bf5SArnaldo Carvalho de Melo if (prevnd == NULL) 182af427bf5SArnaldo Carvalho de Melo return; 183af427bf5SArnaldo Carvalho de Melo 1842e538c4aSArnaldo Carvalho de Melo curr = rb_entry(prevnd, struct symbol, rb_node); 1852e538c4aSArnaldo Carvalho de Melo 186af427bf5SArnaldo Carvalho de Melo for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) { 1872e538c4aSArnaldo Carvalho de Melo prev = curr; 1882e538c4aSArnaldo Carvalho de Melo curr = rb_entry(nd, struct symbol, rb_node); 189af427bf5SArnaldo Carvalho de Melo 1903b01a413SArnaldo Carvalho de Melo if (prev->end == prev->start && prev->end != curr->start) 191af427bf5SArnaldo Carvalho de Melo prev->end = curr->start - 1; 192af427bf5SArnaldo Carvalho de Melo } 193af427bf5SArnaldo Carvalho de Melo 1942e538c4aSArnaldo Carvalho de Melo /* Last entry */ 1952e538c4aSArnaldo Carvalho de Melo if (curr->end == curr->start) 1962e538c4aSArnaldo Carvalho de Melo curr->end = roundup(curr->start, 4096); 1972e538c4aSArnaldo Carvalho de Melo } 1982e538c4aSArnaldo Carvalho de Melo 199aeafcbafSArnaldo Carvalho de Melo static void __map_groups__fixup_end(struct map_groups *mg, enum map_type type) 200af427bf5SArnaldo Carvalho de Melo { 201af427bf5SArnaldo Carvalho de Melo struct map *prev, *curr; 202aeafcbafSArnaldo Carvalho de Melo struct rb_node *nd, *prevnd = rb_first(&mg->maps[type]); 203af427bf5SArnaldo Carvalho de Melo 204af427bf5SArnaldo Carvalho de Melo if (prevnd == NULL) 205af427bf5SArnaldo Carvalho de Melo return; 206af427bf5SArnaldo Carvalho de Melo 207af427bf5SArnaldo Carvalho de Melo curr = rb_entry(prevnd, struct map, rb_node); 208af427bf5SArnaldo Carvalho de Melo 209af427bf5SArnaldo Carvalho de Melo for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) { 210af427bf5SArnaldo Carvalho de Melo prev = curr; 211af427bf5SArnaldo Carvalho de Melo curr = rb_entry(nd, struct map, rb_node); 212af427bf5SArnaldo Carvalho de Melo prev->end = curr->start - 1; 2132e538c4aSArnaldo Carvalho de Melo } 21490c83218SArnaldo Carvalho de Melo 21590c83218SArnaldo Carvalho de Melo /* 21690c83218SArnaldo Carvalho de Melo * We still haven't the actual symbols, so guess the 21790c83218SArnaldo Carvalho de Melo * last map final address. 21890c83218SArnaldo Carvalho de Melo */ 2199d1faba5SIan Munsie curr->end = ~0ULL; 220af427bf5SArnaldo Carvalho de Melo } 221af427bf5SArnaldo Carvalho de Melo 222aeafcbafSArnaldo Carvalho de Melo static void map_groups__fixup_end(struct map_groups *mg) 22323ea4a3fSArnaldo Carvalho de Melo { 22423ea4a3fSArnaldo Carvalho de Melo int i; 22523ea4a3fSArnaldo Carvalho de Melo for (i = 0; i < MAP__NR_TYPES; ++i) 226aeafcbafSArnaldo Carvalho de Melo __map_groups__fixup_end(mg, i); 22723ea4a3fSArnaldo Carvalho de Melo } 22823ea4a3fSArnaldo Carvalho de Melo 229c408fedfSArnaldo Carvalho de Melo static struct symbol *symbol__new(u64 start, u64 len, u8 binding, 230c408fedfSArnaldo Carvalho de Melo const char *name) 23186470930SIngo Molnar { 23286470930SIngo Molnar size_t namelen = strlen(name) + 1; 233aeafcbafSArnaldo Carvalho de Melo struct symbol *sym = calloc(1, (symbol_conf.priv_size + 234aeafcbafSArnaldo Carvalho de Melo sizeof(*sym) + namelen)); 235aeafcbafSArnaldo Carvalho de Melo if (sym == NULL) 23686470930SIngo Molnar return NULL; 23786470930SIngo Molnar 23875be6cf4SArnaldo Carvalho de Melo if (symbol_conf.priv_size) 239aeafcbafSArnaldo Carvalho de Melo sym = ((void *)sym) + symbol_conf.priv_size; 24036479484SArnaldo Carvalho de Melo 241aeafcbafSArnaldo Carvalho de Melo sym->start = start; 242aeafcbafSArnaldo Carvalho de Melo sym->end = len ? start + len - 1 : start; 243aeafcbafSArnaldo Carvalho de Melo sym->binding = binding; 244aeafcbafSArnaldo Carvalho de Melo sym->namelen = namelen - 1; 245e4204992SArnaldo Carvalho de Melo 246aeafcbafSArnaldo Carvalho de Melo pr_debug4("%s: %s %#" PRIx64 "-%#" PRIx64 "\n", 247aeafcbafSArnaldo Carvalho de Melo __func__, name, start, sym->end); 248aeafcbafSArnaldo Carvalho de Melo memcpy(sym->name, name, namelen); 249e4204992SArnaldo Carvalho de Melo 250aeafcbafSArnaldo Carvalho de Melo return sym; 25186470930SIngo Molnar } 25286470930SIngo Molnar 253aeafcbafSArnaldo Carvalho de Melo void symbol__delete(struct symbol *sym) 25486470930SIngo Molnar { 255aeafcbafSArnaldo Carvalho de Melo free(((void *)sym) - symbol_conf.priv_size); 25686470930SIngo Molnar } 25786470930SIngo Molnar 258aeafcbafSArnaldo Carvalho de Melo static size_t symbol__fprintf(struct symbol *sym, FILE *fp) 25986470930SIngo Molnar { 2609486aa38SArnaldo Carvalho de Melo return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %c %s\n", 261aeafcbafSArnaldo Carvalho de Melo sym->start, sym->end, 262aeafcbafSArnaldo Carvalho de Melo sym->binding == STB_GLOBAL ? 'g' : 263aeafcbafSArnaldo Carvalho de Melo sym->binding == STB_LOCAL ? 'l' : 'w', 264aeafcbafSArnaldo Carvalho de Melo sym->name); 26586470930SIngo Molnar } 26686470930SIngo Molnar 267a978f2abSAkihiro Nagai size_t symbol__fprintf_symname_offs(const struct symbol *sym, 268a978f2abSAkihiro Nagai const struct addr_location *al, FILE *fp) 269a978f2abSAkihiro Nagai { 270a978f2abSAkihiro Nagai unsigned long offset; 271a978f2abSAkihiro Nagai size_t length; 272a978f2abSAkihiro Nagai 273a978f2abSAkihiro Nagai if (sym && sym->name) { 274a978f2abSAkihiro Nagai length = fprintf(fp, "%s", sym->name); 275a978f2abSAkihiro Nagai if (al) { 276a978f2abSAkihiro Nagai offset = al->addr - sym->start; 277a978f2abSAkihiro Nagai length += fprintf(fp, "+0x%lx", offset); 278a978f2abSAkihiro Nagai } 279a978f2abSAkihiro Nagai return length; 280a978f2abSAkihiro Nagai } else 281a978f2abSAkihiro Nagai return fprintf(fp, "[unknown]"); 282a978f2abSAkihiro Nagai } 283a978f2abSAkihiro Nagai 284547a92e0SAkihiro Nagai size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp) 285547a92e0SAkihiro Nagai { 286a978f2abSAkihiro Nagai return symbol__fprintf_symname_offs(sym, NULL, fp); 287547a92e0SAkihiro Nagai } 288547a92e0SAkihiro Nagai 289aeafcbafSArnaldo Carvalho de Melo void dso__set_long_name(struct dso *dso, char *name) 290cfc10d3bSArnaldo Carvalho de Melo { 291ef6ae724SArnaldo Carvalho de Melo if (name == NULL) 292ef6ae724SArnaldo Carvalho de Melo return; 293aeafcbafSArnaldo Carvalho de Melo dso->long_name = name; 294aeafcbafSArnaldo Carvalho de Melo dso->long_name_len = strlen(name); 295cfc10d3bSArnaldo Carvalho de Melo } 296cfc10d3bSArnaldo Carvalho de Melo 297aeafcbafSArnaldo Carvalho de Melo static void dso__set_short_name(struct dso *dso, const char *name) 298b63be8d7SArnaldo Carvalho de Melo { 299b63be8d7SArnaldo Carvalho de Melo if (name == NULL) 300b63be8d7SArnaldo Carvalho de Melo return; 301aeafcbafSArnaldo Carvalho de Melo dso->short_name = name; 302aeafcbafSArnaldo Carvalho de Melo dso->short_name_len = strlen(name); 303b63be8d7SArnaldo Carvalho de Melo } 304b63be8d7SArnaldo Carvalho de Melo 305aeafcbafSArnaldo Carvalho de Melo static void dso__set_basename(struct dso *dso) 306cfc10d3bSArnaldo Carvalho de Melo { 307aeafcbafSArnaldo Carvalho de Melo dso__set_short_name(dso, basename(dso->long_name)); 308cfc10d3bSArnaldo Carvalho de Melo } 309cfc10d3bSArnaldo Carvalho de Melo 31000a192b3SArnaldo Carvalho de Melo struct dso *dso__new(const char *name) 31186470930SIngo Molnar { 312aeafcbafSArnaldo Carvalho de Melo struct dso *dso = calloc(1, sizeof(*dso) + strlen(name) + 1); 31386470930SIngo Molnar 314aeafcbafSArnaldo Carvalho de Melo if (dso != NULL) { 3156a4694a4SArnaldo Carvalho de Melo int i; 316aeafcbafSArnaldo Carvalho de Melo strcpy(dso->name, name); 317aeafcbafSArnaldo Carvalho de Melo dso__set_long_name(dso, dso->name); 318aeafcbafSArnaldo Carvalho de Melo dso__set_short_name(dso, dso->name); 3196a4694a4SArnaldo Carvalho de Melo for (i = 0; i < MAP__NR_TYPES; ++i) 320aeafcbafSArnaldo Carvalho de Melo dso->symbols[i] = dso->symbol_names[i] = RB_ROOT; 321aeafcbafSArnaldo Carvalho de Melo dso->symtab_type = SYMTAB__NOT_FOUND; 322aeafcbafSArnaldo Carvalho de Melo dso->loaded = 0; 323aeafcbafSArnaldo Carvalho de Melo dso->sorted_by_name = 0; 324aeafcbafSArnaldo Carvalho de Melo dso->has_build_id = 0; 325aeafcbafSArnaldo Carvalho de Melo dso->kernel = DSO_TYPE_USER; 3268db4841fSJiri Olsa dso->needs_swap = DSO_SWAP__UNSET; 327aeafcbafSArnaldo Carvalho de Melo INIT_LIST_HEAD(&dso->node); 32886470930SIngo Molnar } 32986470930SIngo Molnar 330aeafcbafSArnaldo Carvalho de Melo return dso; 33186470930SIngo Molnar } 33286470930SIngo Molnar 333aeafcbafSArnaldo Carvalho de Melo static void symbols__delete(struct rb_root *symbols) 33486470930SIngo Molnar { 33586470930SIngo Molnar struct symbol *pos; 336aeafcbafSArnaldo Carvalho de Melo struct rb_node *next = rb_first(symbols); 33786470930SIngo Molnar 33886470930SIngo Molnar while (next) { 33986470930SIngo Molnar pos = rb_entry(next, struct symbol, rb_node); 34086470930SIngo Molnar next = rb_next(&pos->rb_node); 341aeafcbafSArnaldo Carvalho de Melo rb_erase(&pos->rb_node, symbols); 34200a192b3SArnaldo Carvalho de Melo symbol__delete(pos); 34386470930SIngo Molnar } 34486470930SIngo Molnar } 34586470930SIngo Molnar 346aeafcbafSArnaldo Carvalho de Melo void dso__delete(struct dso *dso) 34786470930SIngo Molnar { 3486a4694a4SArnaldo Carvalho de Melo int i; 3496a4694a4SArnaldo Carvalho de Melo for (i = 0; i < MAP__NR_TYPES; ++i) 350aeafcbafSArnaldo Carvalho de Melo symbols__delete(&dso->symbols[i]); 351aeafcbafSArnaldo Carvalho de Melo if (dso->sname_alloc) 352aeafcbafSArnaldo Carvalho de Melo free((char *)dso->short_name); 353aeafcbafSArnaldo Carvalho de Melo if (dso->lname_alloc) 354aeafcbafSArnaldo Carvalho de Melo free(dso->long_name); 355aeafcbafSArnaldo Carvalho de Melo free(dso); 35686470930SIngo Molnar } 35786470930SIngo Molnar 358aeafcbafSArnaldo Carvalho de Melo void dso__set_build_id(struct dso *dso, void *build_id) 3598d06367fSArnaldo Carvalho de Melo { 360aeafcbafSArnaldo Carvalho de Melo memcpy(dso->build_id, build_id, sizeof(dso->build_id)); 361aeafcbafSArnaldo Carvalho de Melo dso->has_build_id = 1; 3628d06367fSArnaldo Carvalho de Melo } 3638d06367fSArnaldo Carvalho de Melo 364aeafcbafSArnaldo Carvalho de Melo static void symbols__insert(struct rb_root *symbols, struct symbol *sym) 36586470930SIngo Molnar { 366aeafcbafSArnaldo Carvalho de Melo struct rb_node **p = &symbols->rb_node; 36786470930SIngo Molnar struct rb_node *parent = NULL; 3689cffa8d5SPaul Mackerras const u64 ip = sym->start; 36986470930SIngo Molnar struct symbol *s; 37086470930SIngo Molnar 37186470930SIngo Molnar while (*p != NULL) { 37286470930SIngo Molnar parent = *p; 37386470930SIngo Molnar s = rb_entry(parent, struct symbol, rb_node); 37486470930SIngo Molnar if (ip < s->start) 37586470930SIngo Molnar p = &(*p)->rb_left; 37686470930SIngo Molnar else 37786470930SIngo Molnar p = &(*p)->rb_right; 37886470930SIngo Molnar } 37986470930SIngo Molnar rb_link_node(&sym->rb_node, parent, p); 380aeafcbafSArnaldo Carvalho de Melo rb_insert_color(&sym->rb_node, symbols); 38186470930SIngo Molnar } 38286470930SIngo Molnar 383aeafcbafSArnaldo Carvalho de Melo static struct symbol *symbols__find(struct rb_root *symbols, u64 ip) 38486470930SIngo Molnar { 38586470930SIngo Molnar struct rb_node *n; 38686470930SIngo Molnar 387aeafcbafSArnaldo Carvalho de Melo if (symbols == NULL) 38886470930SIngo Molnar return NULL; 38986470930SIngo Molnar 390aeafcbafSArnaldo Carvalho de Melo n = symbols->rb_node; 39186470930SIngo Molnar 39286470930SIngo Molnar while (n) { 39386470930SIngo Molnar struct symbol *s = rb_entry(n, struct symbol, rb_node); 39486470930SIngo Molnar 39586470930SIngo Molnar if (ip < s->start) 39686470930SIngo Molnar n = n->rb_left; 39786470930SIngo Molnar else if (ip > s->end) 39886470930SIngo Molnar n = n->rb_right; 39986470930SIngo Molnar else 40086470930SIngo Molnar return s; 40186470930SIngo Molnar } 40286470930SIngo Molnar 40386470930SIngo Molnar return NULL; 40486470930SIngo Molnar } 40586470930SIngo Molnar 40679406cd7SArnaldo Carvalho de Melo struct symbol_name_rb_node { 40779406cd7SArnaldo Carvalho de Melo struct rb_node rb_node; 40879406cd7SArnaldo Carvalho de Melo struct symbol sym; 40979406cd7SArnaldo Carvalho de Melo }; 41079406cd7SArnaldo Carvalho de Melo 411aeafcbafSArnaldo Carvalho de Melo static void symbols__insert_by_name(struct rb_root *symbols, struct symbol *sym) 41279406cd7SArnaldo Carvalho de Melo { 413aeafcbafSArnaldo Carvalho de Melo struct rb_node **p = &symbols->rb_node; 41479406cd7SArnaldo Carvalho de Melo struct rb_node *parent = NULL; 41502a9d037SRabin Vincent struct symbol_name_rb_node *symn, *s; 41602a9d037SRabin Vincent 41702a9d037SRabin Vincent symn = container_of(sym, struct symbol_name_rb_node, sym); 41879406cd7SArnaldo Carvalho de Melo 41979406cd7SArnaldo Carvalho de Melo while (*p != NULL) { 42079406cd7SArnaldo Carvalho de Melo parent = *p; 42179406cd7SArnaldo Carvalho de Melo s = rb_entry(parent, struct symbol_name_rb_node, rb_node); 42279406cd7SArnaldo Carvalho de Melo if (strcmp(sym->name, s->sym.name) < 0) 42379406cd7SArnaldo Carvalho de Melo p = &(*p)->rb_left; 42479406cd7SArnaldo Carvalho de Melo else 42579406cd7SArnaldo Carvalho de Melo p = &(*p)->rb_right; 42679406cd7SArnaldo Carvalho de Melo } 42779406cd7SArnaldo Carvalho de Melo rb_link_node(&symn->rb_node, parent, p); 428aeafcbafSArnaldo Carvalho de Melo rb_insert_color(&symn->rb_node, symbols); 42979406cd7SArnaldo Carvalho de Melo } 43079406cd7SArnaldo Carvalho de Melo 431aeafcbafSArnaldo Carvalho de Melo static void symbols__sort_by_name(struct rb_root *symbols, 432aeafcbafSArnaldo Carvalho de Melo struct rb_root *source) 43379406cd7SArnaldo Carvalho de Melo { 43479406cd7SArnaldo Carvalho de Melo struct rb_node *nd; 43579406cd7SArnaldo Carvalho de Melo 43679406cd7SArnaldo Carvalho de Melo for (nd = rb_first(source); nd; nd = rb_next(nd)) { 43779406cd7SArnaldo Carvalho de Melo struct symbol *pos = rb_entry(nd, struct symbol, rb_node); 438aeafcbafSArnaldo Carvalho de Melo symbols__insert_by_name(symbols, pos); 43979406cd7SArnaldo Carvalho de Melo } 44079406cd7SArnaldo Carvalho de Melo } 44179406cd7SArnaldo Carvalho de Melo 442aeafcbafSArnaldo Carvalho de Melo static struct symbol *symbols__find_by_name(struct rb_root *symbols, 443aeafcbafSArnaldo Carvalho de Melo const char *name) 44479406cd7SArnaldo Carvalho de Melo { 44579406cd7SArnaldo Carvalho de Melo struct rb_node *n; 44679406cd7SArnaldo Carvalho de Melo 447aeafcbafSArnaldo Carvalho de Melo if (symbols == NULL) 44879406cd7SArnaldo Carvalho de Melo return NULL; 44979406cd7SArnaldo Carvalho de Melo 450aeafcbafSArnaldo Carvalho de Melo n = symbols->rb_node; 45179406cd7SArnaldo Carvalho de Melo 45279406cd7SArnaldo Carvalho de Melo while (n) { 45379406cd7SArnaldo Carvalho de Melo struct symbol_name_rb_node *s; 45479406cd7SArnaldo Carvalho de Melo int cmp; 45579406cd7SArnaldo Carvalho de Melo 45679406cd7SArnaldo Carvalho de Melo s = rb_entry(n, struct symbol_name_rb_node, rb_node); 45779406cd7SArnaldo Carvalho de Melo cmp = strcmp(name, s->sym.name); 45879406cd7SArnaldo Carvalho de Melo 45979406cd7SArnaldo Carvalho de Melo if (cmp < 0) 46079406cd7SArnaldo Carvalho de Melo n = n->rb_left; 46179406cd7SArnaldo Carvalho de Melo else if (cmp > 0) 46279406cd7SArnaldo Carvalho de Melo n = n->rb_right; 46379406cd7SArnaldo Carvalho de Melo else 46479406cd7SArnaldo Carvalho de Melo return &s->sym; 46579406cd7SArnaldo Carvalho de Melo } 46679406cd7SArnaldo Carvalho de Melo 46779406cd7SArnaldo Carvalho de Melo return NULL; 46879406cd7SArnaldo Carvalho de Melo } 46979406cd7SArnaldo Carvalho de Melo 470aeafcbafSArnaldo Carvalho de Melo struct symbol *dso__find_symbol(struct dso *dso, 47179406cd7SArnaldo Carvalho de Melo enum map_type type, u64 addr) 472fcf1203aSArnaldo Carvalho de Melo { 473aeafcbafSArnaldo Carvalho de Melo return symbols__find(&dso->symbols[type], addr); 474fcf1203aSArnaldo Carvalho de Melo } 475fcf1203aSArnaldo Carvalho de Melo 476aeafcbafSArnaldo Carvalho de Melo struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type, 47779406cd7SArnaldo Carvalho de Melo const char *name) 47879406cd7SArnaldo Carvalho de Melo { 479aeafcbafSArnaldo Carvalho de Melo return symbols__find_by_name(&dso->symbol_names[type], name); 48079406cd7SArnaldo Carvalho de Melo } 48179406cd7SArnaldo Carvalho de Melo 482aeafcbafSArnaldo Carvalho de Melo void dso__sort_by_name(struct dso *dso, enum map_type type) 48379406cd7SArnaldo Carvalho de Melo { 484aeafcbafSArnaldo Carvalho de Melo dso__set_sorted_by_name(dso, type); 485aeafcbafSArnaldo Carvalho de Melo return symbols__sort_by_name(&dso->symbol_names[type], 486aeafcbafSArnaldo Carvalho de Melo &dso->symbols[type]); 48779406cd7SArnaldo Carvalho de Melo } 48879406cd7SArnaldo Carvalho de Melo 489aeafcbafSArnaldo Carvalho de Melo int build_id__sprintf(const u8 *build_id, int len, char *bf) 4908d06367fSArnaldo Carvalho de Melo { 4918d06367fSArnaldo Carvalho de Melo char *bid = bf; 492aeafcbafSArnaldo Carvalho de Melo const u8 *raw = build_id; 4938d06367fSArnaldo Carvalho de Melo int i; 4948d06367fSArnaldo Carvalho de Melo 4958d06367fSArnaldo Carvalho de Melo for (i = 0; i < len; ++i) { 4968d06367fSArnaldo Carvalho de Melo sprintf(bid, "%02x", *raw); 4978d06367fSArnaldo Carvalho de Melo ++raw; 4988d06367fSArnaldo Carvalho de Melo bid += 2; 4998d06367fSArnaldo Carvalho de Melo } 5008d06367fSArnaldo Carvalho de Melo 501aeafcbafSArnaldo Carvalho de Melo return raw - build_id; 5028d06367fSArnaldo Carvalho de Melo } 5038d06367fSArnaldo Carvalho de Melo 504aeafcbafSArnaldo Carvalho de Melo size_t dso__fprintf_buildid(struct dso *dso, FILE *fp) 50586470930SIngo Molnar { 5068d06367fSArnaldo Carvalho de Melo char sbuild_id[BUILD_ID_SIZE * 2 + 1]; 5078d06367fSArnaldo Carvalho de Melo 508aeafcbafSArnaldo Carvalho de Melo build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id); 5099e03eb2dSArnaldo Carvalho de Melo return fprintf(fp, "%s", sbuild_id); 5109e03eb2dSArnaldo Carvalho de Melo } 5119e03eb2dSArnaldo Carvalho de Melo 512aeafcbafSArnaldo Carvalho de Melo size_t dso__fprintf_symbols_by_name(struct dso *dso, 513aeafcbafSArnaldo Carvalho de Melo enum map_type type, FILE *fp) 51490f18e63SSrikar Dronamraju { 51590f18e63SSrikar Dronamraju size_t ret = 0; 51690f18e63SSrikar Dronamraju struct rb_node *nd; 51790f18e63SSrikar Dronamraju struct symbol_name_rb_node *pos; 51890f18e63SSrikar Dronamraju 519aeafcbafSArnaldo Carvalho de Melo for (nd = rb_first(&dso->symbol_names[type]); nd; nd = rb_next(nd)) { 52090f18e63SSrikar Dronamraju pos = rb_entry(nd, struct symbol_name_rb_node, rb_node); 52190f18e63SSrikar Dronamraju fprintf(fp, "%s\n", pos->sym.name); 52290f18e63SSrikar Dronamraju } 52390f18e63SSrikar Dronamraju 52490f18e63SSrikar Dronamraju return ret; 52590f18e63SSrikar Dronamraju } 52690f18e63SSrikar Dronamraju 527aeafcbafSArnaldo Carvalho de Melo size_t dso__fprintf(struct dso *dso, enum map_type type, FILE *fp) 5289e03eb2dSArnaldo Carvalho de Melo { 5299e03eb2dSArnaldo Carvalho de Melo struct rb_node *nd; 530aeafcbafSArnaldo Carvalho de Melo size_t ret = fprintf(fp, "dso: %s (", dso->short_name); 5319e03eb2dSArnaldo Carvalho de Melo 532aeafcbafSArnaldo Carvalho de Melo if (dso->short_name != dso->long_name) 533aeafcbafSArnaldo Carvalho de Melo ret += fprintf(fp, "%s, ", dso->long_name); 5343846df2eSArnaldo Carvalho de Melo ret += fprintf(fp, "%s, %sloaded, ", map_type__name[type], 535aeafcbafSArnaldo Carvalho de Melo dso->loaded ? "" : "NOT "); 536aeafcbafSArnaldo Carvalho de Melo ret += dso__fprintf_buildid(dso, fp); 5376a4694a4SArnaldo Carvalho de Melo ret += fprintf(fp, ")\n"); 538aeafcbafSArnaldo Carvalho de Melo for (nd = rb_first(&dso->symbols[type]); nd; nd = rb_next(nd)) { 53986470930SIngo Molnar struct symbol *pos = rb_entry(nd, struct symbol, rb_node); 54086470930SIngo Molnar ret += symbol__fprintf(pos, fp); 54186470930SIngo Molnar } 54286470930SIngo Molnar 54386470930SIngo Molnar return ret; 54486470930SIngo Molnar } 54586470930SIngo Molnar 5469e201442SArnaldo Carvalho de Melo int kallsyms__parse(const char *filename, void *arg, 5479e201442SArnaldo Carvalho de Melo int (*process_symbol)(void *arg, const char *name, 5483b01a413SArnaldo Carvalho de Melo char type, u64 start, u64 end)) 54986470930SIngo Molnar { 55086470930SIngo Molnar char *line = NULL; 55186470930SIngo Molnar size_t n; 5523b01a413SArnaldo Carvalho de Melo int err = -1; 5539e201442SArnaldo Carvalho de Melo FILE *file = fopen(filename, "r"); 55486470930SIngo Molnar 55586470930SIngo Molnar if (file == NULL) 55686470930SIngo Molnar goto out_failure; 55786470930SIngo Molnar 5583b01a413SArnaldo Carvalho de Melo err = 0; 5593b01a413SArnaldo Carvalho de Melo 56086470930SIngo Molnar while (!feof(file)) { 5619cffa8d5SPaul Mackerras u64 start; 56286470930SIngo Molnar int line_len, len; 56386470930SIngo Molnar char symbol_type; 5642e538c4aSArnaldo Carvalho de Melo char *symbol_name; 56586470930SIngo Molnar 56686470930SIngo Molnar line_len = getline(&line, &n, file); 567a1645ce1SZhang, Yanmin if (line_len < 0 || !line) 56886470930SIngo Molnar break; 56986470930SIngo Molnar 57086470930SIngo Molnar line[--line_len] = '\0'; /* \n */ 57186470930SIngo Molnar 57286470930SIngo Molnar len = hex2u64(line, &start); 57386470930SIngo Molnar 57486470930SIngo Molnar len++; 57586470930SIngo Molnar if (len + 2 >= line_len) 57686470930SIngo Molnar continue; 57786470930SIngo Molnar 57831877908SAnton Blanchard symbol_type = line[len]; 5793b01a413SArnaldo Carvalho de Melo len += 2; 5803b01a413SArnaldo Carvalho de Melo symbol_name = line + len; 5813b01a413SArnaldo Carvalho de Melo len = line_len - len; 582682b335aSArnaldo Carvalho de Melo 5833b01a413SArnaldo Carvalho de Melo if (len >= KSYM_NAME_LEN) { 5843b01a413SArnaldo Carvalho de Melo err = -1; 5853b01a413SArnaldo Carvalho de Melo break; 5863b01a413SArnaldo Carvalho de Melo } 5873b01a413SArnaldo Carvalho de Melo 5883f5a4272SAnton Blanchard /* 5893f5a4272SAnton Blanchard * module symbols are not sorted so we add all 5903f5a4272SAnton Blanchard * symbols with zero length and rely on 5913f5a4272SAnton Blanchard * symbols__fixup_end() to fix it up. 5923f5a4272SAnton Blanchard */ 5933f5a4272SAnton Blanchard err = process_symbol(arg, symbol_name, 5943f5a4272SAnton Blanchard symbol_type, start, start); 595682b335aSArnaldo Carvalho de Melo if (err) 596682b335aSArnaldo Carvalho de Melo break; 597682b335aSArnaldo Carvalho de Melo } 598682b335aSArnaldo Carvalho de Melo 599682b335aSArnaldo Carvalho de Melo free(line); 600682b335aSArnaldo Carvalho de Melo fclose(file); 601682b335aSArnaldo Carvalho de Melo return err; 602682b335aSArnaldo Carvalho de Melo 603682b335aSArnaldo Carvalho de Melo out_failure: 604682b335aSArnaldo Carvalho de Melo return -1; 605682b335aSArnaldo Carvalho de Melo } 606682b335aSArnaldo Carvalho de Melo 607682b335aSArnaldo Carvalho de Melo struct process_kallsyms_args { 608682b335aSArnaldo Carvalho de Melo struct map *map; 609682b335aSArnaldo Carvalho de Melo struct dso *dso; 610682b335aSArnaldo Carvalho de Melo }; 611682b335aSArnaldo Carvalho de Melo 612c408fedfSArnaldo Carvalho de Melo static u8 kallsyms2elf_type(char type) 613c408fedfSArnaldo Carvalho de Melo { 614c408fedfSArnaldo Carvalho de Melo if (type == 'W') 615c408fedfSArnaldo Carvalho de Melo return STB_WEAK; 616c408fedfSArnaldo Carvalho de Melo 617c408fedfSArnaldo Carvalho de Melo return isupper(type) ? STB_GLOBAL : STB_LOCAL; 618c408fedfSArnaldo Carvalho de Melo } 619c408fedfSArnaldo Carvalho de Melo 620682b335aSArnaldo Carvalho de Melo static int map__process_kallsym_symbol(void *arg, const char *name, 6213b01a413SArnaldo Carvalho de Melo char type, u64 start, u64 end) 622682b335aSArnaldo Carvalho de Melo { 623682b335aSArnaldo Carvalho de Melo struct symbol *sym; 624682b335aSArnaldo Carvalho de Melo struct process_kallsyms_args *a = arg; 625682b335aSArnaldo Carvalho de Melo struct rb_root *root = &a->dso->symbols[a->map->type]; 626682b335aSArnaldo Carvalho de Melo 627682b335aSArnaldo Carvalho de Melo if (!symbol_type__is_a(type, a->map->type)) 628682b335aSArnaldo Carvalho de Melo return 0; 629682b335aSArnaldo Carvalho de Melo 6303b01a413SArnaldo Carvalho de Melo sym = symbol__new(start, end - start + 1, 6313b01a413SArnaldo Carvalho de Melo kallsyms2elf_type(type), name); 6322e538c4aSArnaldo Carvalho de Melo if (sym == NULL) 633682b335aSArnaldo Carvalho de Melo return -ENOMEM; 63482164161SArnaldo Carvalho de Melo /* 63582164161SArnaldo Carvalho de Melo * We will pass the symbols to the filter later, in 6364e06255fSArnaldo Carvalho de Melo * map__split_kallsyms, when we have split the maps per module 63782164161SArnaldo Carvalho de Melo */ 6384e06255fSArnaldo Carvalho de Melo symbols__insert(root, sym); 639a1645ce1SZhang, Yanmin 640682b335aSArnaldo Carvalho de Melo return 0; 6412e538c4aSArnaldo Carvalho de Melo } 6422e538c4aSArnaldo Carvalho de Melo 643682b335aSArnaldo Carvalho de Melo /* 644682b335aSArnaldo Carvalho de Melo * Loads the function entries in /proc/kallsyms into kernel_map->dso, 645682b335aSArnaldo Carvalho de Melo * so that we can in the next step set the symbol ->end address and then 646682b335aSArnaldo Carvalho de Melo * call kernel_maps__split_kallsyms. 647682b335aSArnaldo Carvalho de Melo */ 648aeafcbafSArnaldo Carvalho de Melo static int dso__load_all_kallsyms(struct dso *dso, const char *filename, 6499e201442SArnaldo Carvalho de Melo struct map *map) 650682b335aSArnaldo Carvalho de Melo { 651aeafcbafSArnaldo Carvalho de Melo struct process_kallsyms_args args = { .map = map, .dso = dso, }; 6529e201442SArnaldo Carvalho de Melo return kallsyms__parse(filename, &args, map__process_kallsym_symbol); 6532e538c4aSArnaldo Carvalho de Melo } 6542e538c4aSArnaldo Carvalho de Melo 6552e538c4aSArnaldo Carvalho de Melo /* 6562e538c4aSArnaldo Carvalho de Melo * Split the symbols into maps, making sure there are no overlaps, i.e. the 6572e538c4aSArnaldo Carvalho de Melo * kernel range is broken in several maps, named [kernel].N, as we don't have 6582e538c4aSArnaldo Carvalho de Melo * the original ELF section names vmlinux have. 6592e538c4aSArnaldo Carvalho de Melo */ 660aeafcbafSArnaldo Carvalho de Melo static int dso__split_kallsyms(struct dso *dso, struct map *map, 6619de89fe7SArnaldo Carvalho de Melo symbol_filter_t filter) 6622e538c4aSArnaldo Carvalho de Melo { 6639de89fe7SArnaldo Carvalho de Melo struct map_groups *kmaps = map__kmap(map)->kmaps; 66423346f21SArnaldo Carvalho de Melo struct machine *machine = kmaps->machine; 6654e06255fSArnaldo Carvalho de Melo struct map *curr_map = map; 6662e538c4aSArnaldo Carvalho de Melo struct symbol *pos; 6678a953312SArnaldo Carvalho de Melo int count = 0, moved = 0; 668aeafcbafSArnaldo Carvalho de Melo struct rb_root *root = &dso->symbols[map->type]; 6694e06255fSArnaldo Carvalho de Melo struct rb_node *next = rb_first(root); 6702e538c4aSArnaldo Carvalho de Melo int kernel_range = 0; 6712e538c4aSArnaldo Carvalho de Melo 6722e538c4aSArnaldo Carvalho de Melo while (next) { 6732e538c4aSArnaldo Carvalho de Melo char *module; 6742e538c4aSArnaldo Carvalho de Melo 6752e538c4aSArnaldo Carvalho de Melo pos = rb_entry(next, struct symbol, rb_node); 6762e538c4aSArnaldo Carvalho de Melo next = rb_next(&pos->rb_node); 6772e538c4aSArnaldo Carvalho de Melo 6782e538c4aSArnaldo Carvalho de Melo module = strchr(pos->name, '\t'); 6792e538c4aSArnaldo Carvalho de Melo if (module) { 68075be6cf4SArnaldo Carvalho de Melo if (!symbol_conf.use_modules) 6811de8e245SArnaldo Carvalho de Melo goto discard_symbol; 6821de8e245SArnaldo Carvalho de Melo 6832e538c4aSArnaldo Carvalho de Melo *module++ = '\0'; 6842e538c4aSArnaldo Carvalho de Melo 685b7cece76SArnaldo Carvalho de Melo if (strcmp(curr_map->dso->short_name, module)) { 686a1645ce1SZhang, Yanmin if (curr_map != map && 687aeafcbafSArnaldo Carvalho de Melo dso->kernel == DSO_TYPE_GUEST_KERNEL && 68823346f21SArnaldo Carvalho de Melo machine__is_default_guest(machine)) { 689a1645ce1SZhang, Yanmin /* 690a1645ce1SZhang, Yanmin * We assume all symbols of a module are 691a1645ce1SZhang, Yanmin * continuous in * kallsyms, so curr_map 692a1645ce1SZhang, Yanmin * points to a module and all its 693a1645ce1SZhang, Yanmin * symbols are in its kmap. Mark it as 694a1645ce1SZhang, Yanmin * loaded. 695a1645ce1SZhang, Yanmin */ 696a1645ce1SZhang, Yanmin dso__set_loaded(curr_map->dso, 697a1645ce1SZhang, Yanmin curr_map->type); 698af427bf5SArnaldo Carvalho de Melo } 699b7cece76SArnaldo Carvalho de Melo 700a1645ce1SZhang, Yanmin curr_map = map_groups__find_by_name(kmaps, 701a1645ce1SZhang, Yanmin map->type, module); 702a1645ce1SZhang, Yanmin if (curr_map == NULL) { 7032f51903bSArnaldo Carvalho de Melo pr_debug("%s/proc/{kallsyms,modules} " 704a1645ce1SZhang, Yanmin "inconsistency while looking " 705a1645ce1SZhang, Yanmin "for \"%s\" module!\n", 70623346f21SArnaldo Carvalho de Melo machine->root_dir, module); 707a1645ce1SZhang, Yanmin curr_map = map; 708a1645ce1SZhang, Yanmin goto discard_symbol; 709a1645ce1SZhang, Yanmin } 710a1645ce1SZhang, Yanmin 711a1645ce1SZhang, Yanmin if (curr_map->dso->loaded && 71223346f21SArnaldo Carvalho de Melo !machine__is_default_guest(machine)) 713b7cece76SArnaldo Carvalho de Melo goto discard_symbol; 714af427bf5SArnaldo Carvalho de Melo } 71586470930SIngo Molnar /* 7162e538c4aSArnaldo Carvalho de Melo * So that we look just like we get from .ko files, 7172e538c4aSArnaldo Carvalho de Melo * i.e. not prelinked, relative to map->start. 71886470930SIngo Molnar */ 7194e06255fSArnaldo Carvalho de Melo pos->start = curr_map->map_ip(curr_map, pos->start); 7204e06255fSArnaldo Carvalho de Melo pos->end = curr_map->map_ip(curr_map, pos->end); 7214e06255fSArnaldo Carvalho de Melo } else if (curr_map != map) { 7222e538c4aSArnaldo Carvalho de Melo char dso_name[PATH_MAX]; 723aeafcbafSArnaldo Carvalho de Melo struct dso *ndso; 72486470930SIngo Molnar 7258a953312SArnaldo Carvalho de Melo if (count == 0) { 7268a953312SArnaldo Carvalho de Melo curr_map = map; 7278a953312SArnaldo Carvalho de Melo goto filter_symbol; 7288a953312SArnaldo Carvalho de Melo } 7298a953312SArnaldo Carvalho de Melo 730aeafcbafSArnaldo Carvalho de Melo if (dso->kernel == DSO_TYPE_GUEST_KERNEL) 731a1645ce1SZhang, Yanmin snprintf(dso_name, sizeof(dso_name), 732a1645ce1SZhang, Yanmin "[guest.kernel].%d", 733a1645ce1SZhang, Yanmin kernel_range++); 734a1645ce1SZhang, Yanmin else 735a1645ce1SZhang, Yanmin snprintf(dso_name, sizeof(dso_name), 736a1645ce1SZhang, Yanmin "[kernel].%d", 7372e538c4aSArnaldo Carvalho de Melo kernel_range++); 73886470930SIngo Molnar 739aeafcbafSArnaldo Carvalho de Melo ndso = dso__new(dso_name); 740aeafcbafSArnaldo Carvalho de Melo if (ndso == NULL) 7412e538c4aSArnaldo Carvalho de Melo return -1; 7422e538c4aSArnaldo Carvalho de Melo 743aeafcbafSArnaldo Carvalho de Melo ndso->kernel = dso->kernel; 744a1645ce1SZhang, Yanmin 745aeafcbafSArnaldo Carvalho de Melo curr_map = map__new2(pos->start, ndso, map->type); 74637fe5fcbSZhang, Yanmin if (curr_map == NULL) { 747aeafcbafSArnaldo Carvalho de Melo dso__delete(ndso); 7482e538c4aSArnaldo Carvalho de Melo return -1; 7492e538c4aSArnaldo Carvalho de Melo } 7502e538c4aSArnaldo Carvalho de Melo 7514e06255fSArnaldo Carvalho de Melo curr_map->map_ip = curr_map->unmap_ip = identity__map_ip; 7529de89fe7SArnaldo Carvalho de Melo map_groups__insert(kmaps, curr_map); 7532e538c4aSArnaldo Carvalho de Melo ++kernel_range; 7542e538c4aSArnaldo Carvalho de Melo } 7558a953312SArnaldo Carvalho de Melo filter_symbol: 7564e06255fSArnaldo Carvalho de Melo if (filter && filter(curr_map, pos)) { 7571de8e245SArnaldo Carvalho de Melo discard_symbol: rb_erase(&pos->rb_node, root); 75800a192b3SArnaldo Carvalho de Melo symbol__delete(pos); 7592e538c4aSArnaldo Carvalho de Melo } else { 7604e06255fSArnaldo Carvalho de Melo if (curr_map != map) { 7614e06255fSArnaldo Carvalho de Melo rb_erase(&pos->rb_node, root); 7624e06255fSArnaldo Carvalho de Melo symbols__insert(&curr_map->dso->symbols[curr_map->type], pos); 7638a953312SArnaldo Carvalho de Melo ++moved; 7648a953312SArnaldo Carvalho de Melo } else 7658a953312SArnaldo Carvalho de Melo ++count; 7669974f496SMike Galbraith } 76786470930SIngo Molnar } 76886470930SIngo Molnar 769a1645ce1SZhang, Yanmin if (curr_map != map && 770aeafcbafSArnaldo Carvalho de Melo dso->kernel == DSO_TYPE_GUEST_KERNEL && 77123346f21SArnaldo Carvalho de Melo machine__is_default_guest(kmaps->machine)) { 772a1645ce1SZhang, Yanmin dso__set_loaded(curr_map->dso, curr_map->type); 773a1645ce1SZhang, Yanmin } 774a1645ce1SZhang, Yanmin 7758a953312SArnaldo Carvalho de Melo return count + moved; 77686470930SIngo Molnar } 77786470930SIngo Molnar 778ec80fde7SArnaldo Carvalho de Melo static bool symbol__restricted_filename(const char *filename, 779ec80fde7SArnaldo Carvalho de Melo const char *restricted_filename) 780ec80fde7SArnaldo Carvalho de Melo { 781ec80fde7SArnaldo Carvalho de Melo bool restricted = false; 782ec80fde7SArnaldo Carvalho de Melo 783ec80fde7SArnaldo Carvalho de Melo if (symbol_conf.kptr_restrict) { 784ec80fde7SArnaldo Carvalho de Melo char *r = realpath(filename, NULL); 785ec80fde7SArnaldo Carvalho de Melo 786ec80fde7SArnaldo Carvalho de Melo if (r != NULL) { 787ec80fde7SArnaldo Carvalho de Melo restricted = strcmp(r, restricted_filename) == 0; 788ec80fde7SArnaldo Carvalho de Melo free(r); 789ec80fde7SArnaldo Carvalho de Melo return restricted; 790ec80fde7SArnaldo Carvalho de Melo } 791ec80fde7SArnaldo Carvalho de Melo } 792ec80fde7SArnaldo Carvalho de Melo 793ec80fde7SArnaldo Carvalho de Melo return restricted; 794ec80fde7SArnaldo Carvalho de Melo } 795ec80fde7SArnaldo Carvalho de Melo 796aeafcbafSArnaldo Carvalho de Melo int dso__load_kallsyms(struct dso *dso, const char *filename, 7979de89fe7SArnaldo Carvalho de Melo struct map *map, symbol_filter_t filter) 7982e538c4aSArnaldo Carvalho de Melo { 799ec80fde7SArnaldo Carvalho de Melo if (symbol__restricted_filename(filename, "/proc/kallsyms")) 800ec80fde7SArnaldo Carvalho de Melo return -1; 801ec80fde7SArnaldo Carvalho de Melo 802aeafcbafSArnaldo Carvalho de Melo if (dso__load_all_kallsyms(dso, filename, map) < 0) 8032e538c4aSArnaldo Carvalho de Melo return -1; 8042e538c4aSArnaldo Carvalho de Melo 805694bf407SAnton Blanchard symbols__fixup_duplicate(&dso->symbols[map->type]); 8063f5a4272SAnton Blanchard symbols__fixup_end(&dso->symbols[map->type]); 8073f5a4272SAnton Blanchard 808aeafcbafSArnaldo Carvalho de Melo if (dso->kernel == DSO_TYPE_GUEST_KERNEL) 809aeafcbafSArnaldo Carvalho de Melo dso->symtab_type = SYMTAB__GUEST_KALLSYMS; 810a1645ce1SZhang, Yanmin else 811aeafcbafSArnaldo Carvalho de Melo dso->symtab_type = SYMTAB__KALLSYMS; 8122e538c4aSArnaldo Carvalho de Melo 813aeafcbafSArnaldo Carvalho de Melo return dso__split_kallsyms(dso, map, filter); 814af427bf5SArnaldo Carvalho de Melo } 815af427bf5SArnaldo Carvalho de Melo 816aeafcbafSArnaldo Carvalho de Melo static int dso__load_perf_map(struct dso *dso, struct map *map, 8176beba7adSArnaldo Carvalho de Melo symbol_filter_t filter) 81880d496beSPekka Enberg { 81980d496beSPekka Enberg char *line = NULL; 82080d496beSPekka Enberg size_t n; 82180d496beSPekka Enberg FILE *file; 82280d496beSPekka Enberg int nr_syms = 0; 82380d496beSPekka Enberg 824aeafcbafSArnaldo Carvalho de Melo file = fopen(dso->long_name, "r"); 82580d496beSPekka Enberg if (file == NULL) 82680d496beSPekka Enberg goto out_failure; 82780d496beSPekka Enberg 82880d496beSPekka Enberg while (!feof(file)) { 8299cffa8d5SPaul Mackerras u64 start, size; 83080d496beSPekka Enberg struct symbol *sym; 83180d496beSPekka Enberg int line_len, len; 83280d496beSPekka Enberg 83380d496beSPekka Enberg line_len = getline(&line, &n, file); 83480d496beSPekka Enberg if (line_len < 0) 83580d496beSPekka Enberg break; 83680d496beSPekka Enberg 83780d496beSPekka Enberg if (!line) 83880d496beSPekka Enberg goto out_failure; 83980d496beSPekka Enberg 84080d496beSPekka Enberg line[--line_len] = '\0'; /* \n */ 84180d496beSPekka Enberg 84280d496beSPekka Enberg len = hex2u64(line, &start); 84380d496beSPekka Enberg 84480d496beSPekka Enberg len++; 84580d496beSPekka Enberg if (len + 2 >= line_len) 84680d496beSPekka Enberg continue; 84780d496beSPekka Enberg 84880d496beSPekka Enberg len += hex2u64(line + len, &size); 84980d496beSPekka Enberg 85080d496beSPekka Enberg len++; 85180d496beSPekka Enberg if (len + 2 >= line_len) 85280d496beSPekka Enberg continue; 85380d496beSPekka Enberg 854c408fedfSArnaldo Carvalho de Melo sym = symbol__new(start, size, STB_GLOBAL, line + len); 85580d496beSPekka Enberg 85680d496beSPekka Enberg if (sym == NULL) 85780d496beSPekka Enberg goto out_delete_line; 85880d496beSPekka Enberg 859439d473bSArnaldo Carvalho de Melo if (filter && filter(map, sym)) 86000a192b3SArnaldo Carvalho de Melo symbol__delete(sym); 86180d496beSPekka Enberg else { 862aeafcbafSArnaldo Carvalho de Melo symbols__insert(&dso->symbols[map->type], sym); 86380d496beSPekka Enberg nr_syms++; 86480d496beSPekka Enberg } 86580d496beSPekka Enberg } 86680d496beSPekka Enberg 86780d496beSPekka Enberg free(line); 86880d496beSPekka Enberg fclose(file); 86980d496beSPekka Enberg 87080d496beSPekka Enberg return nr_syms; 87180d496beSPekka Enberg 87280d496beSPekka Enberg out_delete_line: 87380d496beSPekka Enberg free(line); 87480d496beSPekka Enberg out_failure: 87580d496beSPekka Enberg return -1; 87680d496beSPekka Enberg } 87780d496beSPekka Enberg 87886470930SIngo Molnar /** 87986470930SIngo Molnar * elf_symtab__for_each_symbol - iterate thru all the symbols 88086470930SIngo Molnar * 881aeafcbafSArnaldo Carvalho de Melo * @syms: struct elf_symtab instance to iterate 88283a0944fSIngo Molnar * @idx: uint32_t idx 88386470930SIngo Molnar * @sym: GElf_Sym iterator 88486470930SIngo Molnar */ 88583a0944fSIngo Molnar #define elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) \ 88683a0944fSIngo Molnar for (idx = 0, gelf_getsym(syms, idx, &sym);\ 88783a0944fSIngo Molnar idx < nr_syms; \ 88883a0944fSIngo Molnar idx++, gelf_getsym(syms, idx, &sym)) 88986470930SIngo Molnar 89086470930SIngo Molnar static inline uint8_t elf_sym__type(const GElf_Sym *sym) 89186470930SIngo Molnar { 89286470930SIngo Molnar return GELF_ST_TYPE(sym->st_info); 89386470930SIngo Molnar } 89486470930SIngo Molnar 89586470930SIngo Molnar static inline int elf_sym__is_function(const GElf_Sym *sym) 89686470930SIngo Molnar { 89786470930SIngo Molnar return elf_sym__type(sym) == STT_FUNC && 89886470930SIngo Molnar sym->st_name != 0 && 89981833130SArnaldo Carvalho de Melo sym->st_shndx != SHN_UNDEF; 90086470930SIngo Molnar } 90186470930SIngo Molnar 902f1dfa0b1SArnaldo Carvalho de Melo static inline bool elf_sym__is_object(const GElf_Sym *sym) 903f1dfa0b1SArnaldo Carvalho de Melo { 904f1dfa0b1SArnaldo Carvalho de Melo return elf_sym__type(sym) == STT_OBJECT && 905f1dfa0b1SArnaldo Carvalho de Melo sym->st_name != 0 && 906f1dfa0b1SArnaldo Carvalho de Melo sym->st_shndx != SHN_UNDEF; 907f1dfa0b1SArnaldo Carvalho de Melo } 908f1dfa0b1SArnaldo Carvalho de Melo 9096cfcc53eSMike Galbraith static inline int elf_sym__is_label(const GElf_Sym *sym) 9106cfcc53eSMike Galbraith { 9116cfcc53eSMike Galbraith return elf_sym__type(sym) == STT_NOTYPE && 9126cfcc53eSMike Galbraith sym->st_name != 0 && 9136cfcc53eSMike Galbraith sym->st_shndx != SHN_UNDEF && 9146cfcc53eSMike Galbraith sym->st_shndx != SHN_ABS; 9156cfcc53eSMike Galbraith } 9166cfcc53eSMike Galbraith 9176cfcc53eSMike Galbraith static inline const char *elf_sec__name(const GElf_Shdr *shdr, 9186cfcc53eSMike Galbraith const Elf_Data *secstrs) 9196cfcc53eSMike Galbraith { 9206cfcc53eSMike Galbraith return secstrs->d_buf + shdr->sh_name; 9216cfcc53eSMike Galbraith } 9226cfcc53eSMike Galbraith 9236cfcc53eSMike Galbraith static inline int elf_sec__is_text(const GElf_Shdr *shdr, 9246cfcc53eSMike Galbraith const Elf_Data *secstrs) 9256cfcc53eSMike Galbraith { 9266cfcc53eSMike Galbraith return strstr(elf_sec__name(shdr, secstrs), "text") != NULL; 9276cfcc53eSMike Galbraith } 9286cfcc53eSMike Galbraith 929f1dfa0b1SArnaldo Carvalho de Melo static inline bool elf_sec__is_data(const GElf_Shdr *shdr, 930f1dfa0b1SArnaldo Carvalho de Melo const Elf_Data *secstrs) 931f1dfa0b1SArnaldo Carvalho de Melo { 932f1dfa0b1SArnaldo Carvalho de Melo return strstr(elf_sec__name(shdr, secstrs), "data") != NULL; 933f1dfa0b1SArnaldo Carvalho de Melo } 934f1dfa0b1SArnaldo Carvalho de Melo 93586470930SIngo Molnar static inline const char *elf_sym__name(const GElf_Sym *sym, 93686470930SIngo Molnar const Elf_Data *symstrs) 93786470930SIngo Molnar { 93886470930SIngo Molnar return symstrs->d_buf + sym->st_name; 93986470930SIngo Molnar } 94086470930SIngo Molnar 94186470930SIngo Molnar static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, 94286470930SIngo Molnar GElf_Shdr *shp, const char *name, 94383a0944fSIngo Molnar size_t *idx) 94486470930SIngo Molnar { 94586470930SIngo Molnar Elf_Scn *sec = NULL; 94686470930SIngo Molnar size_t cnt = 1; 94786470930SIngo Molnar 94886470930SIngo Molnar while ((sec = elf_nextscn(elf, sec)) != NULL) { 94986470930SIngo Molnar char *str; 95086470930SIngo Molnar 95186470930SIngo Molnar gelf_getshdr(sec, shp); 95286470930SIngo Molnar str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name); 95386470930SIngo Molnar if (!strcmp(name, str)) { 95483a0944fSIngo Molnar if (idx) 95583a0944fSIngo Molnar *idx = cnt; 95686470930SIngo Molnar break; 95786470930SIngo Molnar } 95886470930SIngo Molnar ++cnt; 95986470930SIngo Molnar } 96086470930SIngo Molnar 96186470930SIngo Molnar return sec; 96286470930SIngo Molnar } 96386470930SIngo Molnar 96486470930SIngo Molnar #define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \ 96586470930SIngo Molnar for (idx = 0, pos = gelf_getrel(reldata, 0, &pos_mem); \ 96686470930SIngo Molnar idx < nr_entries; \ 96786470930SIngo Molnar ++idx, pos = gelf_getrel(reldata, idx, &pos_mem)) 96886470930SIngo Molnar 96986470930SIngo Molnar #define elf_section__for_each_rela(reldata, pos, pos_mem, idx, nr_entries) \ 97086470930SIngo Molnar for (idx = 0, pos = gelf_getrela(reldata, 0, &pos_mem); \ 97186470930SIngo Molnar idx < nr_entries; \ 97286470930SIngo Molnar ++idx, pos = gelf_getrela(reldata, idx, &pos_mem)) 97386470930SIngo Molnar 974a25e46c4SArnaldo Carvalho de Melo /* 975a25e46c4SArnaldo Carvalho de Melo * We need to check if we have a .dynsym, so that we can handle the 976a25e46c4SArnaldo Carvalho de Melo * .plt, synthesizing its symbols, that aren't on the symtabs (be it 977a25e46c4SArnaldo Carvalho de Melo * .dynsym or .symtab). 978a25e46c4SArnaldo Carvalho de Melo * And always look at the original dso, not at debuginfo packages, that 979a25e46c4SArnaldo Carvalho de Melo * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS). 980a25e46c4SArnaldo Carvalho de Melo */ 98133ff581eSJiri Olsa static int 98233ff581eSJiri Olsa dso__synthesize_plt_symbols(struct dso *dso, char *name, struct map *map, 98382164161SArnaldo Carvalho de Melo symbol_filter_t filter) 98486470930SIngo Molnar { 98586470930SIngo Molnar uint32_t nr_rel_entries, idx; 98686470930SIngo Molnar GElf_Sym sym; 9879cffa8d5SPaul Mackerras u64 plt_offset; 98886470930SIngo Molnar GElf_Shdr shdr_plt; 98986470930SIngo Molnar struct symbol *f; 990a25e46c4SArnaldo Carvalho de Melo GElf_Shdr shdr_rel_plt, shdr_dynsym; 99186470930SIngo Molnar Elf_Data *reldata, *syms, *symstrs; 992a25e46c4SArnaldo Carvalho de Melo Elf_Scn *scn_plt_rel, *scn_symstrs, *scn_dynsym; 993a25e46c4SArnaldo Carvalho de Melo size_t dynsym_idx; 994a25e46c4SArnaldo Carvalho de Melo GElf_Ehdr ehdr; 99586470930SIngo Molnar char sympltname[1024]; 996a25e46c4SArnaldo Carvalho de Melo Elf *elf; 997a25e46c4SArnaldo Carvalho de Melo int nr = 0, symidx, fd, err = 0; 99886470930SIngo Molnar 999ec5761eaSDavid Ahern fd = open(name, O_RDONLY); 1000a25e46c4SArnaldo Carvalho de Melo if (fd < 0) 1001a25e46c4SArnaldo Carvalho de Melo goto out; 1002a25e46c4SArnaldo Carvalho de Melo 100384087126SMarti Raudsepp elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 1004a25e46c4SArnaldo Carvalho de Melo if (elf == NULL) 1005a25e46c4SArnaldo Carvalho de Melo goto out_close; 1006a25e46c4SArnaldo Carvalho de Melo 1007a25e46c4SArnaldo Carvalho de Melo if (gelf_getehdr(elf, &ehdr) == NULL) 1008a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 1009a25e46c4SArnaldo Carvalho de Melo 1010a25e46c4SArnaldo Carvalho de Melo scn_dynsym = elf_section_by_name(elf, &ehdr, &shdr_dynsym, 1011a25e46c4SArnaldo Carvalho de Melo ".dynsym", &dynsym_idx); 1012a25e46c4SArnaldo Carvalho de Melo if (scn_dynsym == NULL) 1013a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 1014a25e46c4SArnaldo Carvalho de Melo 1015a25e46c4SArnaldo Carvalho de Melo scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt, 101686470930SIngo Molnar ".rela.plt", NULL); 101786470930SIngo Molnar if (scn_plt_rel == NULL) { 1018a25e46c4SArnaldo Carvalho de Melo scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt, 101986470930SIngo Molnar ".rel.plt", NULL); 102086470930SIngo Molnar if (scn_plt_rel == NULL) 1021a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 102286470930SIngo Molnar } 102386470930SIngo Molnar 1024a25e46c4SArnaldo Carvalho de Melo err = -1; 102586470930SIngo Molnar 1026a25e46c4SArnaldo Carvalho de Melo if (shdr_rel_plt.sh_link != dynsym_idx) 1027a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 1028a25e46c4SArnaldo Carvalho de Melo 1029a25e46c4SArnaldo Carvalho de Melo if (elf_section_by_name(elf, &ehdr, &shdr_plt, ".plt", NULL) == NULL) 1030a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 103186470930SIngo Molnar 103286470930SIngo Molnar /* 103383a0944fSIngo Molnar * Fetch the relocation section to find the idxes to the GOT 103486470930SIngo Molnar * and the symbols in the .dynsym they refer to. 103586470930SIngo Molnar */ 103686470930SIngo Molnar reldata = elf_getdata(scn_plt_rel, NULL); 103786470930SIngo Molnar if (reldata == NULL) 1038a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 103986470930SIngo Molnar 104086470930SIngo Molnar syms = elf_getdata(scn_dynsym, NULL); 104186470930SIngo Molnar if (syms == NULL) 1042a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 104386470930SIngo Molnar 1044a25e46c4SArnaldo Carvalho de Melo scn_symstrs = elf_getscn(elf, shdr_dynsym.sh_link); 104586470930SIngo Molnar if (scn_symstrs == NULL) 1046a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 104786470930SIngo Molnar 104886470930SIngo Molnar symstrs = elf_getdata(scn_symstrs, NULL); 104986470930SIngo Molnar if (symstrs == NULL) 1050a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 105186470930SIngo Molnar 105286470930SIngo Molnar nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize; 105386470930SIngo Molnar plt_offset = shdr_plt.sh_offset; 105486470930SIngo Molnar 105586470930SIngo Molnar if (shdr_rel_plt.sh_type == SHT_RELA) { 105686470930SIngo Molnar GElf_Rela pos_mem, *pos; 105786470930SIngo Molnar 105886470930SIngo Molnar elf_section__for_each_rela(reldata, pos, pos_mem, idx, 105986470930SIngo Molnar nr_rel_entries) { 106086470930SIngo Molnar symidx = GELF_R_SYM(pos->r_info); 106186470930SIngo Molnar plt_offset += shdr_plt.sh_entsize; 106286470930SIngo Molnar gelf_getsym(syms, symidx, &sym); 106386470930SIngo Molnar snprintf(sympltname, sizeof(sympltname), 106486470930SIngo Molnar "%s@plt", elf_sym__name(&sym, symstrs)); 106586470930SIngo Molnar 106686470930SIngo Molnar f = symbol__new(plt_offset, shdr_plt.sh_entsize, 1067c408fedfSArnaldo Carvalho de Melo STB_GLOBAL, sympltname); 106886470930SIngo Molnar if (!f) 1069a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 107086470930SIngo Molnar 107182164161SArnaldo Carvalho de Melo if (filter && filter(map, f)) 107282164161SArnaldo Carvalho de Melo symbol__delete(f); 107382164161SArnaldo Carvalho de Melo else { 1074aeafcbafSArnaldo Carvalho de Melo symbols__insert(&dso->symbols[map->type], f); 107586470930SIngo Molnar ++nr; 107686470930SIngo Molnar } 107782164161SArnaldo Carvalho de Melo } 107886470930SIngo Molnar } else if (shdr_rel_plt.sh_type == SHT_REL) { 107986470930SIngo Molnar GElf_Rel pos_mem, *pos; 108086470930SIngo Molnar elf_section__for_each_rel(reldata, pos, pos_mem, idx, 108186470930SIngo Molnar nr_rel_entries) { 108286470930SIngo Molnar symidx = GELF_R_SYM(pos->r_info); 108386470930SIngo Molnar plt_offset += shdr_plt.sh_entsize; 108486470930SIngo Molnar gelf_getsym(syms, symidx, &sym); 108586470930SIngo Molnar snprintf(sympltname, sizeof(sympltname), 108686470930SIngo Molnar "%s@plt", elf_sym__name(&sym, symstrs)); 108786470930SIngo Molnar 108886470930SIngo Molnar f = symbol__new(plt_offset, shdr_plt.sh_entsize, 1089c408fedfSArnaldo Carvalho de Melo STB_GLOBAL, sympltname); 109086470930SIngo Molnar if (!f) 1091a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 109286470930SIngo Molnar 109382164161SArnaldo Carvalho de Melo if (filter && filter(map, f)) 109482164161SArnaldo Carvalho de Melo symbol__delete(f); 109582164161SArnaldo Carvalho de Melo else { 1096aeafcbafSArnaldo Carvalho de Melo symbols__insert(&dso->symbols[map->type], f); 109786470930SIngo Molnar ++nr; 109886470930SIngo Molnar } 109986470930SIngo Molnar } 110082164161SArnaldo Carvalho de Melo } 110186470930SIngo Molnar 1102a25e46c4SArnaldo Carvalho de Melo err = 0; 1103a25e46c4SArnaldo Carvalho de Melo out_elf_end: 1104a25e46c4SArnaldo Carvalho de Melo elf_end(elf); 1105a25e46c4SArnaldo Carvalho de Melo out_close: 1106a25e46c4SArnaldo Carvalho de Melo close(fd); 1107a25e46c4SArnaldo Carvalho de Melo 1108a25e46c4SArnaldo Carvalho de Melo if (err == 0) 110986470930SIngo Molnar return nr; 1110a25e46c4SArnaldo Carvalho de Melo out: 1111fe2197b8SArnaldo Carvalho de Melo pr_debug("%s: problems reading %s PLT info.\n", 1112aeafcbafSArnaldo Carvalho de Melo __func__, dso->long_name); 1113a25e46c4SArnaldo Carvalho de Melo return 0; 111486470930SIngo Molnar } 111586470930SIngo Molnar 1116aeafcbafSArnaldo Carvalho de Melo static bool elf_sym__is_a(GElf_Sym *sym, enum map_type type) 1117d45868d3SArnaldo Carvalho de Melo { 1118d45868d3SArnaldo Carvalho de Melo switch (type) { 1119d45868d3SArnaldo Carvalho de Melo case MAP__FUNCTION: 1120aeafcbafSArnaldo Carvalho de Melo return elf_sym__is_function(sym); 1121f1dfa0b1SArnaldo Carvalho de Melo case MAP__VARIABLE: 1122aeafcbafSArnaldo Carvalho de Melo return elf_sym__is_object(sym); 1123d45868d3SArnaldo Carvalho de Melo default: 1124d45868d3SArnaldo Carvalho de Melo return false; 1125d45868d3SArnaldo Carvalho de Melo } 1126d45868d3SArnaldo Carvalho de Melo } 1127d45868d3SArnaldo Carvalho de Melo 1128aeafcbafSArnaldo Carvalho de Melo static bool elf_sec__is_a(GElf_Shdr *shdr, Elf_Data *secstrs, 1129aeafcbafSArnaldo Carvalho de Melo enum map_type type) 1130d45868d3SArnaldo Carvalho de Melo { 1131d45868d3SArnaldo Carvalho de Melo switch (type) { 1132d45868d3SArnaldo Carvalho de Melo case MAP__FUNCTION: 1133aeafcbafSArnaldo Carvalho de Melo return elf_sec__is_text(shdr, secstrs); 1134f1dfa0b1SArnaldo Carvalho de Melo case MAP__VARIABLE: 1135aeafcbafSArnaldo Carvalho de Melo return elf_sec__is_data(shdr, secstrs); 1136d45868d3SArnaldo Carvalho de Melo default: 1137d45868d3SArnaldo Carvalho de Melo return false; 1138d45868d3SArnaldo Carvalho de Melo } 1139d45868d3SArnaldo Carvalho de Melo } 1140d45868d3SArnaldo Carvalho de Melo 114170c3856bSEric B Munson static size_t elf_addr_to_index(Elf *elf, GElf_Addr addr) 114270c3856bSEric B Munson { 114370c3856bSEric B Munson Elf_Scn *sec = NULL; 114470c3856bSEric B Munson GElf_Shdr shdr; 114570c3856bSEric B Munson size_t cnt = 1; 114670c3856bSEric B Munson 114770c3856bSEric B Munson while ((sec = elf_nextscn(elf, sec)) != NULL) { 114870c3856bSEric B Munson gelf_getshdr(sec, &shdr); 114970c3856bSEric B Munson 115070c3856bSEric B Munson if ((addr >= shdr.sh_addr) && 115170c3856bSEric B Munson (addr < (shdr.sh_addr + shdr.sh_size))) 115270c3856bSEric B Munson return cnt; 115370c3856bSEric B Munson 115470c3856bSEric B Munson ++cnt; 115570c3856bSEric B Munson } 115670c3856bSEric B Munson 115770c3856bSEric B Munson return -1; 115870c3856bSEric B Munson } 115970c3856bSEric B Munson 11608db4841fSJiri Olsa static int dso__swap_init(struct dso *dso, unsigned char eidata) 11618db4841fSJiri Olsa { 11628db4841fSJiri Olsa static unsigned int const endian = 1; 11638db4841fSJiri Olsa 11648db4841fSJiri Olsa dso->needs_swap = DSO_SWAP__NO; 11658db4841fSJiri Olsa 11668db4841fSJiri Olsa switch (eidata) { 11678db4841fSJiri Olsa case ELFDATA2LSB: 11688db4841fSJiri Olsa /* We are big endian, DSO is little endian. */ 11698db4841fSJiri Olsa if (*(unsigned char const *)&endian != 1) 11708db4841fSJiri Olsa dso->needs_swap = DSO_SWAP__YES; 11718db4841fSJiri Olsa break; 11728db4841fSJiri Olsa 11738db4841fSJiri Olsa case ELFDATA2MSB: 11748db4841fSJiri Olsa /* We are little endian, DSO is big endian. */ 11758db4841fSJiri Olsa if (*(unsigned char const *)&endian != 0) 11768db4841fSJiri Olsa dso->needs_swap = DSO_SWAP__YES; 11778db4841fSJiri Olsa break; 11788db4841fSJiri Olsa 11798db4841fSJiri Olsa default: 11808db4841fSJiri Olsa pr_err("unrecognized DSO data encoding %d\n", eidata); 11818db4841fSJiri Olsa return -EINVAL; 11828db4841fSJiri Olsa } 11838db4841fSJiri Olsa 11848db4841fSJiri Olsa return 0; 11858db4841fSJiri Olsa } 11868db4841fSJiri Olsa 1187aeafcbafSArnaldo Carvalho de Melo static int dso__load_sym(struct dso *dso, struct map *map, const char *name, 11886da80ce8SDave Martin int fd, symbol_filter_t filter, int kmodule, 11896da80ce8SDave Martin int want_symtab) 119086470930SIngo Molnar { 1191aeafcbafSArnaldo Carvalho de Melo struct kmap *kmap = dso->kernel ? map__kmap(map) : NULL; 11922e538c4aSArnaldo Carvalho de Melo struct map *curr_map = map; 1193aeafcbafSArnaldo Carvalho de Melo struct dso *curr_dso = dso; 11946cfcc53eSMike Galbraith Elf_Data *symstrs, *secstrs; 119586470930SIngo Molnar uint32_t nr_syms; 119686470930SIngo Molnar int err = -1; 119783a0944fSIngo Molnar uint32_t idx; 119886470930SIngo Molnar GElf_Ehdr ehdr; 119970c3856bSEric B Munson GElf_Shdr shdr, opdshdr; 120070c3856bSEric B Munson Elf_Data *syms, *opddata = NULL; 120186470930SIngo Molnar GElf_Sym sym; 120270c3856bSEric B Munson Elf_Scn *sec, *sec_strndx, *opdsec; 120386470930SIngo Molnar Elf *elf; 1204439d473bSArnaldo Carvalho de Melo int nr = 0; 120570c3856bSEric B Munson size_t opdidx = 0; 120686470930SIngo Molnar 120784087126SMarti Raudsepp elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 120886470930SIngo Molnar if (elf == NULL) { 12098b1389efSDave Martin pr_debug("%s: cannot read %s ELF file.\n", __func__, name); 121086470930SIngo Molnar goto out_close; 121186470930SIngo Molnar } 121286470930SIngo Molnar 121386470930SIngo Molnar if (gelf_getehdr(elf, &ehdr) == NULL) { 12148b1389efSDave Martin pr_debug("%s: cannot get elf header.\n", __func__); 121586470930SIngo Molnar goto out_elf_end; 121686470930SIngo Molnar } 121786470930SIngo Molnar 12188db4841fSJiri Olsa if (dso__swap_init(dso, ehdr.e_ident[EI_DATA])) 12198db4841fSJiri Olsa goto out_elf_end; 12208db4841fSJiri Olsa 12216da80ce8SDave Martin /* Always reject images with a mismatched build-id: */ 1222aeafcbafSArnaldo Carvalho de Melo if (dso->has_build_id) { 122321916c38SDave Martin u8 build_id[BUILD_ID_SIZE]; 122421916c38SDave Martin 1225be96ea8fSStephane Eranian if (elf_read_build_id(elf, build_id, BUILD_ID_SIZE) < 0) 122621916c38SDave Martin goto out_elf_end; 122721916c38SDave Martin 1228aeafcbafSArnaldo Carvalho de Melo if (!dso__build_id_equal(dso, build_id)) 122921916c38SDave Martin goto out_elf_end; 123021916c38SDave Martin } 123121916c38SDave Martin 123286470930SIngo Molnar sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL); 123386470930SIngo Molnar if (sec == NULL) { 12346da80ce8SDave Martin if (want_symtab) 12356da80ce8SDave Martin goto out_elf_end; 12366da80ce8SDave Martin 1237a25e46c4SArnaldo Carvalho de Melo sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL); 1238a25e46c4SArnaldo Carvalho de Melo if (sec == NULL) 123986470930SIngo Molnar goto out_elf_end; 124086470930SIngo Molnar } 124186470930SIngo Molnar 124270c3856bSEric B Munson opdsec = elf_section_by_name(elf, &ehdr, &opdshdr, ".opd", &opdidx); 1243adb09184SAnton Blanchard if (opdshdr.sh_type != SHT_PROGBITS) 1244adb09184SAnton Blanchard opdsec = NULL; 124570c3856bSEric B Munson if (opdsec) 124670c3856bSEric B Munson opddata = elf_rawdata(opdsec, NULL); 124770c3856bSEric B Munson 124886470930SIngo Molnar syms = elf_getdata(sec, NULL); 124986470930SIngo Molnar if (syms == NULL) 125086470930SIngo Molnar goto out_elf_end; 125186470930SIngo Molnar 125286470930SIngo Molnar sec = elf_getscn(elf, shdr.sh_link); 125386470930SIngo Molnar if (sec == NULL) 125486470930SIngo Molnar goto out_elf_end; 125586470930SIngo Molnar 125686470930SIngo Molnar symstrs = elf_getdata(sec, NULL); 125786470930SIngo Molnar if (symstrs == NULL) 125886470930SIngo Molnar goto out_elf_end; 125986470930SIngo Molnar 12606cfcc53eSMike Galbraith sec_strndx = elf_getscn(elf, ehdr.e_shstrndx); 12616cfcc53eSMike Galbraith if (sec_strndx == NULL) 12626cfcc53eSMike Galbraith goto out_elf_end; 12636cfcc53eSMike Galbraith 12646cfcc53eSMike Galbraith secstrs = elf_getdata(sec_strndx, NULL); 12659b30a26bSStoyan Gaydarov if (secstrs == NULL) 12666cfcc53eSMike Galbraith goto out_elf_end; 12676cfcc53eSMike Galbraith 126886470930SIngo Molnar nr_syms = shdr.sh_size / shdr.sh_entsize; 126986470930SIngo Molnar 1270e9fbc9dcSArjan van de Ven memset(&sym, 0, sizeof(sym)); 1271aeafcbafSArnaldo Carvalho de Melo if (dso->kernel == DSO_TYPE_USER) { 1272aeafcbafSArnaldo Carvalho de Melo dso->adjust_symbols = (ehdr.e_type == ET_EXEC || 127330d7a77dSArnaldo Carvalho de Melo elf_section_by_name(elf, &ehdr, &shdr, 1274f5812a7aSArnaldo Carvalho de Melo ".gnu.prelink_undo", 127530d7a77dSArnaldo Carvalho de Melo NULL) != NULL); 1276aeafcbafSArnaldo Carvalho de Melo } else { 1277aeafcbafSArnaldo Carvalho de Melo dso->adjust_symbols = 0; 1278aeafcbafSArnaldo Carvalho de Melo } 127983a0944fSIngo Molnar elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) { 128086470930SIngo Molnar struct symbol *f; 128156b03f3cSArnaldo Carvalho de Melo const char *elf_name = elf_sym__name(&sym, symstrs); 12822e538c4aSArnaldo Carvalho de Melo char *demangled = NULL; 12836cfcc53eSMike Galbraith int is_label = elf_sym__is_label(&sym); 12846cfcc53eSMike Galbraith const char *section_name; 128586470930SIngo Molnar 12869de89fe7SArnaldo Carvalho de Melo if (kmap && kmap->ref_reloc_sym && kmap->ref_reloc_sym->name && 12879de89fe7SArnaldo Carvalho de Melo strcmp(elf_name, kmap->ref_reloc_sym->name) == 0) 12889de89fe7SArnaldo Carvalho de Melo kmap->ref_reloc_sym->unrelocated_addr = sym.st_value; 128956b03f3cSArnaldo Carvalho de Melo 1290d45868d3SArnaldo Carvalho de Melo if (!is_label && !elf_sym__is_a(&sym, map->type)) 129186470930SIngo Molnar continue; 129286470930SIngo Molnar 1293696b97a5SDave Martin /* Reject ARM ELF "mapping symbols": these aren't unique and 1294696b97a5SDave Martin * don't identify functions, so will confuse the profile 1295696b97a5SDave Martin * output: */ 1296696b97a5SDave Martin if (ehdr.e_machine == EM_ARM) { 1297696b97a5SDave Martin if (!strcmp(elf_name, "$a") || 1298696b97a5SDave Martin !strcmp(elf_name, "$d") || 1299696b97a5SDave Martin !strcmp(elf_name, "$t")) 1300696b97a5SDave Martin continue; 1301696b97a5SDave Martin } 1302696b97a5SDave Martin 130370c3856bSEric B Munson if (opdsec && sym.st_shndx == opdidx) { 130470c3856bSEric B Munson u32 offset = sym.st_value - opdshdr.sh_addr; 130570c3856bSEric B Munson u64 *opd = opddata->d_buf + offset; 13068db4841fSJiri Olsa sym.st_value = DSO__SWAP(dso, u64, *opd); 130770c3856bSEric B Munson sym.st_shndx = elf_addr_to_index(elf, sym.st_value); 130870c3856bSEric B Munson } 130970c3856bSEric B Munson 131086470930SIngo Molnar sec = elf_getscn(elf, sym.st_shndx); 131186470930SIngo Molnar if (!sec) 131286470930SIngo Molnar goto out_elf_end; 131386470930SIngo Molnar 131486470930SIngo Molnar gelf_getshdr(sec, &shdr); 13156cfcc53eSMike Galbraith 1316d45868d3SArnaldo Carvalho de Melo if (is_label && !elf_sec__is_a(&shdr, secstrs, map->type)) 13176cfcc53eSMike Galbraith continue; 13186cfcc53eSMike Galbraith 13196cfcc53eSMike Galbraith section_name = elf_sec__name(&shdr, secstrs); 132086470930SIngo Molnar 1321b2f8fb23SDr. David Alan Gilbert /* On ARM, symbols for thumb functions have 1 added to 1322b2f8fb23SDr. David Alan Gilbert * the symbol address as a flag - remove it */ 1323b2f8fb23SDr. David Alan Gilbert if ((ehdr.e_machine == EM_ARM) && 1324b2f8fb23SDr. David Alan Gilbert (map->type == MAP__FUNCTION) && 1325b2f8fb23SDr. David Alan Gilbert (sym.st_value & 1)) 1326b2f8fb23SDr. David Alan Gilbert --sym.st_value; 1327b2f8fb23SDr. David Alan Gilbert 1328aeafcbafSArnaldo Carvalho de Melo if (dso->kernel != DSO_TYPE_USER || kmodule) { 13292e538c4aSArnaldo Carvalho de Melo char dso_name[PATH_MAX]; 13302e538c4aSArnaldo Carvalho de Melo 13312e538c4aSArnaldo Carvalho de Melo if (strcmp(section_name, 1332b63be8d7SArnaldo Carvalho de Melo (curr_dso->short_name + 1333aeafcbafSArnaldo Carvalho de Melo dso->short_name_len)) == 0) 13342e538c4aSArnaldo Carvalho de Melo goto new_symbol; 13352e538c4aSArnaldo Carvalho de Melo 13362e538c4aSArnaldo Carvalho de Melo if (strcmp(section_name, ".text") == 0) { 13372e538c4aSArnaldo Carvalho de Melo curr_map = map; 1338aeafcbafSArnaldo Carvalho de Melo curr_dso = dso; 13392e538c4aSArnaldo Carvalho de Melo goto new_symbol; 1340af427bf5SArnaldo Carvalho de Melo } 1341af427bf5SArnaldo Carvalho de Melo 13422e538c4aSArnaldo Carvalho de Melo snprintf(dso_name, sizeof(dso_name), 1343aeafcbafSArnaldo Carvalho de Melo "%s%s", dso->short_name, section_name); 13442e538c4aSArnaldo Carvalho de Melo 13459de89fe7SArnaldo Carvalho de Melo curr_map = map_groups__find_by_name(kmap->kmaps, map->type, dso_name); 13462e538c4aSArnaldo Carvalho de Melo if (curr_map == NULL) { 13472e538c4aSArnaldo Carvalho de Melo u64 start = sym.st_value; 13482e538c4aSArnaldo Carvalho de Melo 13492e538c4aSArnaldo Carvalho de Melo if (kmodule) 13502e538c4aSArnaldo Carvalho de Melo start += map->start + shdr.sh_offset; 13512e538c4aSArnaldo Carvalho de Melo 135200a192b3SArnaldo Carvalho de Melo curr_dso = dso__new(dso_name); 13532e538c4aSArnaldo Carvalho de Melo if (curr_dso == NULL) 13542e538c4aSArnaldo Carvalho de Melo goto out_elf_end; 1355aeafcbafSArnaldo Carvalho de Melo curr_dso->kernel = dso->kernel; 1356aeafcbafSArnaldo Carvalho de Melo curr_dso->long_name = dso->long_name; 1357aeafcbafSArnaldo Carvalho de Melo curr_dso->long_name_len = dso->long_name_len; 13583610583cSArnaldo Carvalho de Melo curr_map = map__new2(start, curr_dso, 13596275ce2dSArnaldo Carvalho de Melo map->type); 13602e538c4aSArnaldo Carvalho de Melo if (curr_map == NULL) { 13612e538c4aSArnaldo Carvalho de Melo dso__delete(curr_dso); 13622e538c4aSArnaldo Carvalho de Melo goto out_elf_end; 13632e538c4aSArnaldo Carvalho de Melo } 1364ed52ce2eSArnaldo Carvalho de Melo curr_map->map_ip = identity__map_ip; 1365ed52ce2eSArnaldo Carvalho de Melo curr_map->unmap_ip = identity__map_ip; 1366aeafcbafSArnaldo Carvalho de Melo curr_dso->symtab_type = dso->symtab_type; 13679de89fe7SArnaldo Carvalho de Melo map_groups__insert(kmap->kmaps, curr_map); 1368aeafcbafSArnaldo Carvalho de Melo dsos__add(&dso->node, curr_dso); 13696275ce2dSArnaldo Carvalho de Melo dso__set_loaded(curr_dso, map->type); 13702e538c4aSArnaldo Carvalho de Melo } else 13712e538c4aSArnaldo Carvalho de Melo curr_dso = curr_map->dso; 13722e538c4aSArnaldo Carvalho de Melo 13732e538c4aSArnaldo Carvalho de Melo goto new_symbol; 13742e538c4aSArnaldo Carvalho de Melo } 13752e538c4aSArnaldo Carvalho de Melo 13762e538c4aSArnaldo Carvalho de Melo if (curr_dso->adjust_symbols) { 13779486aa38SArnaldo Carvalho de Melo pr_debug4("%s: adjusting symbol: st_value: %#" PRIx64 " " 13789486aa38SArnaldo Carvalho de Melo "sh_addr: %#" PRIx64 " sh_offset: %#" PRIx64 "\n", __func__, 137929a9f66dSArnaldo Carvalho de Melo (u64)sym.st_value, (u64)shdr.sh_addr, 138029a9f66dSArnaldo Carvalho de Melo (u64)shdr.sh_offset); 138186470930SIngo Molnar sym.st_value -= shdr.sh_addr - shdr.sh_offset; 1382af427bf5SArnaldo Carvalho de Melo } 138328ac909bSArnaldo Carvalho de Melo /* 138428ac909bSArnaldo Carvalho de Melo * We need to figure out if the object was created from C++ sources 138528ac909bSArnaldo Carvalho de Melo * DWARF DW_compile_unit has this, but we don't always have access 138628ac909bSArnaldo Carvalho de Melo * to it... 138728ac909bSArnaldo Carvalho de Melo */ 138883a0944fSIngo Molnar demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI); 138928ac909bSArnaldo Carvalho de Melo if (demangled != NULL) 139083a0944fSIngo Molnar elf_name = demangled; 13912e538c4aSArnaldo Carvalho de Melo new_symbol: 1392c408fedfSArnaldo Carvalho de Melo f = symbol__new(sym.st_value, sym.st_size, 1393c408fedfSArnaldo Carvalho de Melo GELF_ST_BIND(sym.st_info), elf_name); 139428ac909bSArnaldo Carvalho de Melo free(demangled); 139586470930SIngo Molnar if (!f) 139686470930SIngo Molnar goto out_elf_end; 139786470930SIngo Molnar 13982e538c4aSArnaldo Carvalho de Melo if (filter && filter(curr_map, f)) 139900a192b3SArnaldo Carvalho de Melo symbol__delete(f); 140086470930SIngo Molnar else { 14016a4694a4SArnaldo Carvalho de Melo symbols__insert(&curr_dso->symbols[curr_map->type], f); 140286470930SIngo Molnar nr++; 140386470930SIngo Molnar } 140486470930SIngo Molnar } 140586470930SIngo Molnar 14062e538c4aSArnaldo Carvalho de Melo /* 14072e538c4aSArnaldo Carvalho de Melo * For misannotated, zeroed, ASM function sizes. 14082e538c4aSArnaldo Carvalho de Melo */ 14096275ce2dSArnaldo Carvalho de Melo if (nr > 0) { 1410694bf407SAnton Blanchard symbols__fixup_duplicate(&dso->symbols[map->type]); 1411aeafcbafSArnaldo Carvalho de Melo symbols__fixup_end(&dso->symbols[map->type]); 14126275ce2dSArnaldo Carvalho de Melo if (kmap) { 14136275ce2dSArnaldo Carvalho de Melo /* 14146275ce2dSArnaldo Carvalho de Melo * We need to fixup this here too because we create new 14156275ce2dSArnaldo Carvalho de Melo * maps here, for things like vsyscall sections. 14166275ce2dSArnaldo Carvalho de Melo */ 14176275ce2dSArnaldo Carvalho de Melo __map_groups__fixup_end(kmap->kmaps, map->type); 14186275ce2dSArnaldo Carvalho de Melo } 14196275ce2dSArnaldo Carvalho de Melo } 142086470930SIngo Molnar err = nr; 142186470930SIngo Molnar out_elf_end: 142286470930SIngo Molnar elf_end(elf); 142386470930SIngo Molnar out_close: 142486470930SIngo Molnar return err; 142586470930SIngo Molnar } 142686470930SIngo Molnar 1427aeafcbafSArnaldo Carvalho de Melo static bool dso__build_id_equal(const struct dso *dso, u8 *build_id) 142878075caaSArnaldo Carvalho de Melo { 1429aeafcbafSArnaldo Carvalho de Melo return memcmp(dso->build_id, build_id, sizeof(dso->build_id)) == 0; 143078075caaSArnaldo Carvalho de Melo } 143178075caaSArnaldo Carvalho de Melo 1432a1645ce1SZhang, Yanmin bool __dsos__read_build_ids(struct list_head *head, bool with_hits) 143357f395a7SFrederic Weisbecker { 1434e30a3d12SArnaldo Carvalho de Melo bool have_build_id = false; 143557f395a7SFrederic Weisbecker struct dso *pos; 143657f395a7SFrederic Weisbecker 14376122e4e4SArnaldo Carvalho de Melo list_for_each_entry(pos, head, node) { 14386122e4e4SArnaldo Carvalho de Melo if (with_hits && !pos->hit) 14396122e4e4SArnaldo Carvalho de Melo continue; 1440f6e1467dSArnaldo Carvalho de Melo if (pos->has_build_id) { 1441f6e1467dSArnaldo Carvalho de Melo have_build_id = true; 1442f6e1467dSArnaldo Carvalho de Melo continue; 1443f6e1467dSArnaldo Carvalho de Melo } 1444e30a3d12SArnaldo Carvalho de Melo if (filename__read_build_id(pos->long_name, pos->build_id, 1445e30a3d12SArnaldo Carvalho de Melo sizeof(pos->build_id)) > 0) { 1446e30a3d12SArnaldo Carvalho de Melo have_build_id = true; 1447e30a3d12SArnaldo Carvalho de Melo pos->has_build_id = true; 144857f395a7SFrederic Weisbecker } 14496122e4e4SArnaldo Carvalho de Melo } 145057f395a7SFrederic Weisbecker 1451e30a3d12SArnaldo Carvalho de Melo return have_build_id; 145257f395a7SFrederic Weisbecker } 145357f395a7SFrederic Weisbecker 1454fd7a346eSArnaldo Carvalho de Melo /* 1455fd7a346eSArnaldo Carvalho de Melo * Align offset to 4 bytes as needed for note name and descriptor data. 1456fd7a346eSArnaldo Carvalho de Melo */ 1457fd7a346eSArnaldo Carvalho de Melo #define NOTE_ALIGN(n) (((n) + 3) & -4U) 1458fd7a346eSArnaldo Carvalho de Melo 145921916c38SDave Martin static int elf_read_build_id(Elf *elf, void *bf, size_t size) 14604d1e00a8SArnaldo Carvalho de Melo { 146121916c38SDave Martin int err = -1; 14624d1e00a8SArnaldo Carvalho de Melo GElf_Ehdr ehdr; 14634d1e00a8SArnaldo Carvalho de Melo GElf_Shdr shdr; 1464fd7a346eSArnaldo Carvalho de Melo Elf_Data *data; 14654d1e00a8SArnaldo Carvalho de Melo Elf_Scn *sec; 1466e57cfcdaSPekka Enberg Elf_Kind ek; 1467fd7a346eSArnaldo Carvalho de Melo void *ptr; 14684d1e00a8SArnaldo Carvalho de Melo 14692643ce11SArnaldo Carvalho de Melo if (size < BUILD_ID_SIZE) 14702643ce11SArnaldo Carvalho de Melo goto out; 14712643ce11SArnaldo Carvalho de Melo 1472e57cfcdaSPekka Enberg ek = elf_kind(elf); 1473e57cfcdaSPekka Enberg if (ek != ELF_K_ELF) 147421916c38SDave Martin goto out; 1475e57cfcdaSPekka Enberg 14764d1e00a8SArnaldo Carvalho de Melo if (gelf_getehdr(elf, &ehdr) == NULL) { 14776beba7adSArnaldo Carvalho de Melo pr_err("%s: cannot get elf header.\n", __func__); 147821916c38SDave Martin goto out; 14794d1e00a8SArnaldo Carvalho de Melo } 14804d1e00a8SArnaldo Carvalho de Melo 14811388d715SJiri Olsa /* 14821388d715SJiri Olsa * Check following sections for notes: 14831388d715SJiri Olsa * '.note.gnu.build-id' 14841388d715SJiri Olsa * '.notes' 14851388d715SJiri Olsa * '.note' (VDSO specific) 14861388d715SJiri Olsa */ 14871388d715SJiri Olsa do { 14882643ce11SArnaldo Carvalho de Melo sec = elf_section_by_name(elf, &ehdr, &shdr, 14892643ce11SArnaldo Carvalho de Melo ".note.gnu.build-id", NULL); 14901388d715SJiri Olsa if (sec) 14911388d715SJiri Olsa break; 14921388d715SJiri Olsa 1493fd7a346eSArnaldo Carvalho de Melo sec = elf_section_by_name(elf, &ehdr, &shdr, 1494fd7a346eSArnaldo Carvalho de Melo ".notes", NULL); 14951388d715SJiri Olsa if (sec) 14961388d715SJiri Olsa break; 14971388d715SJiri Olsa 14981388d715SJiri Olsa sec = elf_section_by_name(elf, &ehdr, &shdr, 14991388d715SJiri Olsa ".note", NULL); 15001388d715SJiri Olsa if (sec) 15011388d715SJiri Olsa break; 15021388d715SJiri Olsa 15031388d715SJiri Olsa return err; 15041388d715SJiri Olsa 15051388d715SJiri Olsa } while (0); 15064d1e00a8SArnaldo Carvalho de Melo 1507fd7a346eSArnaldo Carvalho de Melo data = elf_getdata(sec, NULL); 1508fd7a346eSArnaldo Carvalho de Melo if (data == NULL) 150921916c38SDave Martin goto out; 1510fd7a346eSArnaldo Carvalho de Melo 1511fd7a346eSArnaldo Carvalho de Melo ptr = data->d_buf; 1512fd7a346eSArnaldo Carvalho de Melo while (ptr < (data->d_buf + data->d_size)) { 1513fd7a346eSArnaldo Carvalho de Melo GElf_Nhdr *nhdr = ptr; 1514be96ea8fSStephane Eranian size_t namesz = NOTE_ALIGN(nhdr->n_namesz), 1515fd7a346eSArnaldo Carvalho de Melo descsz = NOTE_ALIGN(nhdr->n_descsz); 1516fd7a346eSArnaldo Carvalho de Melo const char *name; 1517fd7a346eSArnaldo Carvalho de Melo 1518fd7a346eSArnaldo Carvalho de Melo ptr += sizeof(*nhdr); 1519fd7a346eSArnaldo Carvalho de Melo name = ptr; 1520fd7a346eSArnaldo Carvalho de Melo ptr += namesz; 1521fd7a346eSArnaldo Carvalho de Melo if (nhdr->n_type == NT_GNU_BUILD_ID && 1522fd7a346eSArnaldo Carvalho de Melo nhdr->n_namesz == sizeof("GNU")) { 1523fd7a346eSArnaldo Carvalho de Melo if (memcmp(name, "GNU", sizeof("GNU")) == 0) { 1524be96ea8fSStephane Eranian size_t sz = min(size, descsz); 1525be96ea8fSStephane Eranian memcpy(bf, ptr, sz); 1526be96ea8fSStephane Eranian memset(bf + sz, 0, size - sz); 1527be96ea8fSStephane Eranian err = descsz; 1528fd7a346eSArnaldo Carvalho de Melo break; 1529fd7a346eSArnaldo Carvalho de Melo } 1530fd7a346eSArnaldo Carvalho de Melo } 1531fd7a346eSArnaldo Carvalho de Melo ptr += descsz; 1532fd7a346eSArnaldo Carvalho de Melo } 153321916c38SDave Martin 153421916c38SDave Martin out: 153521916c38SDave Martin return err; 153621916c38SDave Martin } 153721916c38SDave Martin 153821916c38SDave Martin int filename__read_build_id(const char *filename, void *bf, size_t size) 153921916c38SDave Martin { 154021916c38SDave Martin int fd, err = -1; 154121916c38SDave Martin Elf *elf; 154221916c38SDave Martin 154321916c38SDave Martin if (size < BUILD_ID_SIZE) 154421916c38SDave Martin goto out; 154521916c38SDave Martin 154621916c38SDave Martin fd = open(filename, O_RDONLY); 154721916c38SDave Martin if (fd < 0) 154821916c38SDave Martin goto out; 154921916c38SDave Martin 155021916c38SDave Martin elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 155121916c38SDave Martin if (elf == NULL) { 155221916c38SDave Martin pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename); 155321916c38SDave Martin goto out_close; 155421916c38SDave Martin } 155521916c38SDave Martin 155621916c38SDave Martin err = elf_read_build_id(elf, bf, size); 155721916c38SDave Martin 15582643ce11SArnaldo Carvalho de Melo elf_end(elf); 15592643ce11SArnaldo Carvalho de Melo out_close: 15602643ce11SArnaldo Carvalho de Melo close(fd); 15612643ce11SArnaldo Carvalho de Melo out: 15622643ce11SArnaldo Carvalho de Melo return err; 15632643ce11SArnaldo Carvalho de Melo } 15642643ce11SArnaldo Carvalho de Melo 1565f1617b40SArnaldo Carvalho de Melo int sysfs__read_build_id(const char *filename, void *build_id, size_t size) 1566f1617b40SArnaldo Carvalho de Melo { 1567f1617b40SArnaldo Carvalho de Melo int fd, err = -1; 1568f1617b40SArnaldo Carvalho de Melo 1569f1617b40SArnaldo Carvalho de Melo if (size < BUILD_ID_SIZE) 1570f1617b40SArnaldo Carvalho de Melo goto out; 1571f1617b40SArnaldo Carvalho de Melo 1572f1617b40SArnaldo Carvalho de Melo fd = open(filename, O_RDONLY); 1573f1617b40SArnaldo Carvalho de Melo if (fd < 0) 1574f1617b40SArnaldo Carvalho de Melo goto out; 1575f1617b40SArnaldo Carvalho de Melo 1576f1617b40SArnaldo Carvalho de Melo while (1) { 1577f1617b40SArnaldo Carvalho de Melo char bf[BUFSIZ]; 1578f1617b40SArnaldo Carvalho de Melo GElf_Nhdr nhdr; 1579be96ea8fSStephane Eranian size_t namesz, descsz; 1580f1617b40SArnaldo Carvalho de Melo 1581f1617b40SArnaldo Carvalho de Melo if (read(fd, &nhdr, sizeof(nhdr)) != sizeof(nhdr)) 1582f1617b40SArnaldo Carvalho de Melo break; 1583f1617b40SArnaldo Carvalho de Melo 1584fd7a346eSArnaldo Carvalho de Melo namesz = NOTE_ALIGN(nhdr.n_namesz); 1585fd7a346eSArnaldo Carvalho de Melo descsz = NOTE_ALIGN(nhdr.n_descsz); 1586f1617b40SArnaldo Carvalho de Melo if (nhdr.n_type == NT_GNU_BUILD_ID && 1587f1617b40SArnaldo Carvalho de Melo nhdr.n_namesz == sizeof("GNU")) { 1588be96ea8fSStephane Eranian if (read(fd, bf, namesz) != (ssize_t)namesz) 1589f1617b40SArnaldo Carvalho de Melo break; 1590f1617b40SArnaldo Carvalho de Melo if (memcmp(bf, "GNU", sizeof("GNU")) == 0) { 1591be96ea8fSStephane Eranian size_t sz = min(descsz, size); 1592be96ea8fSStephane Eranian if (read(fd, build_id, sz) == (ssize_t)sz) { 1593be96ea8fSStephane Eranian memset(build_id + sz, 0, size - sz); 1594f1617b40SArnaldo Carvalho de Melo err = 0; 1595f1617b40SArnaldo Carvalho de Melo break; 1596f1617b40SArnaldo Carvalho de Melo } 1597be96ea8fSStephane Eranian } else if (read(fd, bf, descsz) != (ssize_t)descsz) 1598f1617b40SArnaldo Carvalho de Melo break; 1599f1617b40SArnaldo Carvalho de Melo } else { 1600f1617b40SArnaldo Carvalho de Melo int n = namesz + descsz; 1601f1617b40SArnaldo Carvalho de Melo if (read(fd, bf, n) != n) 1602f1617b40SArnaldo Carvalho de Melo break; 1603f1617b40SArnaldo Carvalho de Melo } 1604f1617b40SArnaldo Carvalho de Melo } 1605f1617b40SArnaldo Carvalho de Melo close(fd); 1606f1617b40SArnaldo Carvalho de Melo out: 1607f1617b40SArnaldo Carvalho de Melo return err; 1608f1617b40SArnaldo Carvalho de Melo } 1609f1617b40SArnaldo Carvalho de Melo 1610209bd9e3SPierre-Loup A. Griffais static int filename__read_debuglink(const char *filename, 1611209bd9e3SPierre-Loup A. Griffais char *debuglink, size_t size) 1612209bd9e3SPierre-Loup A. Griffais { 1613209bd9e3SPierre-Loup A. Griffais int fd, err = -1; 1614209bd9e3SPierre-Loup A. Griffais Elf *elf; 1615209bd9e3SPierre-Loup A. Griffais GElf_Ehdr ehdr; 1616209bd9e3SPierre-Loup A. Griffais GElf_Shdr shdr; 1617209bd9e3SPierre-Loup A. Griffais Elf_Data *data; 1618209bd9e3SPierre-Loup A. Griffais Elf_Scn *sec; 1619209bd9e3SPierre-Loup A. Griffais Elf_Kind ek; 1620209bd9e3SPierre-Loup A. Griffais 1621209bd9e3SPierre-Loup A. Griffais fd = open(filename, O_RDONLY); 1622209bd9e3SPierre-Loup A. Griffais if (fd < 0) 1623209bd9e3SPierre-Loup A. Griffais goto out; 1624209bd9e3SPierre-Loup A. Griffais 1625209bd9e3SPierre-Loup A. Griffais elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 1626209bd9e3SPierre-Loup A. Griffais if (elf == NULL) { 1627209bd9e3SPierre-Loup A. Griffais pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename); 1628209bd9e3SPierre-Loup A. Griffais goto out_close; 1629209bd9e3SPierre-Loup A. Griffais } 1630209bd9e3SPierre-Loup A. Griffais 1631209bd9e3SPierre-Loup A. Griffais ek = elf_kind(elf); 1632209bd9e3SPierre-Loup A. Griffais if (ek != ELF_K_ELF) 1633209bd9e3SPierre-Loup A. Griffais goto out_close; 1634209bd9e3SPierre-Loup A. Griffais 1635209bd9e3SPierre-Loup A. Griffais if (gelf_getehdr(elf, &ehdr) == NULL) { 1636209bd9e3SPierre-Loup A. Griffais pr_err("%s: cannot get elf header.\n", __func__); 1637209bd9e3SPierre-Loup A. Griffais goto out_close; 1638209bd9e3SPierre-Loup A. Griffais } 1639209bd9e3SPierre-Loup A. Griffais 1640209bd9e3SPierre-Loup A. Griffais sec = elf_section_by_name(elf, &ehdr, &shdr, 1641209bd9e3SPierre-Loup A. Griffais ".gnu_debuglink", NULL); 1642209bd9e3SPierre-Loup A. Griffais if (sec == NULL) 1643209bd9e3SPierre-Loup A. Griffais goto out_close; 1644209bd9e3SPierre-Loup A. Griffais 1645209bd9e3SPierre-Loup A. Griffais data = elf_getdata(sec, NULL); 1646209bd9e3SPierre-Loup A. Griffais if (data == NULL) 1647209bd9e3SPierre-Loup A. Griffais goto out_close; 1648209bd9e3SPierre-Loup A. Griffais 1649209bd9e3SPierre-Loup A. Griffais /* the start of this section is a zero-terminated string */ 1650209bd9e3SPierre-Loup A. Griffais strncpy(debuglink, data->d_buf, size); 1651209bd9e3SPierre-Loup A. Griffais 1652209bd9e3SPierre-Loup A. Griffais elf_end(elf); 1653209bd9e3SPierre-Loup A. Griffais 1654209bd9e3SPierre-Loup A. Griffais out_close: 1655209bd9e3SPierre-Loup A. Griffais close(fd); 1656209bd9e3SPierre-Loup A. Griffais out: 1657209bd9e3SPierre-Loup A. Griffais return err; 1658209bd9e3SPierre-Loup A. Griffais } 1659209bd9e3SPierre-Loup A. Griffais 1660aeafcbafSArnaldo Carvalho de Melo char dso__symtab_origin(const struct dso *dso) 166194cb9e38SArnaldo Carvalho de Melo { 166294cb9e38SArnaldo Carvalho de Melo static const char origin[] = { 1663878b439dSArnaldo Carvalho de Melo [SYMTAB__KALLSYMS] = 'k', 1664878b439dSArnaldo Carvalho de Melo [SYMTAB__JAVA_JIT] = 'j', 1665209bd9e3SPierre-Loup A. Griffais [SYMTAB__DEBUGLINK] = 'l', 1666878b439dSArnaldo Carvalho de Melo [SYMTAB__BUILD_ID_CACHE] = 'B', 1667878b439dSArnaldo Carvalho de Melo [SYMTAB__FEDORA_DEBUGINFO] = 'f', 1668878b439dSArnaldo Carvalho de Melo [SYMTAB__UBUNTU_DEBUGINFO] = 'u', 1669878b439dSArnaldo Carvalho de Melo [SYMTAB__BUILDID_DEBUGINFO] = 'b', 1670878b439dSArnaldo Carvalho de Melo [SYMTAB__SYSTEM_PATH_DSO] = 'd', 1671878b439dSArnaldo Carvalho de Melo [SYMTAB__SYSTEM_PATH_KMODULE] = 'K', 1672878b439dSArnaldo Carvalho de Melo [SYMTAB__GUEST_KALLSYMS] = 'g', 1673878b439dSArnaldo Carvalho de Melo [SYMTAB__GUEST_KMODULE] = 'G', 167494cb9e38SArnaldo Carvalho de Melo }; 167594cb9e38SArnaldo Carvalho de Melo 1676aeafcbafSArnaldo Carvalho de Melo if (dso == NULL || dso->symtab_type == SYMTAB__NOT_FOUND) 167794cb9e38SArnaldo Carvalho de Melo return '!'; 1678aeafcbafSArnaldo Carvalho de Melo return origin[dso->symtab_type]; 167994cb9e38SArnaldo Carvalho de Melo } 168094cb9e38SArnaldo Carvalho de Melo 1681aeafcbafSArnaldo Carvalho de Melo int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter) 168286470930SIngo Molnar { 16834d1e00a8SArnaldo Carvalho de Melo int size = PATH_MAX; 1684c338aee8SArnaldo Carvalho de Melo char *name; 168586470930SIngo Molnar int ret = -1; 168686470930SIngo Molnar int fd; 168723346f21SArnaldo Carvalho de Melo struct machine *machine; 1688a1645ce1SZhang, Yanmin const char *root_dir; 16896da80ce8SDave Martin int want_symtab; 169086470930SIngo Molnar 1691aeafcbafSArnaldo Carvalho de Melo dso__set_loaded(dso, map->type); 169266bd8424SArnaldo Carvalho de Melo 1693aeafcbafSArnaldo Carvalho de Melo if (dso->kernel == DSO_TYPE_KERNEL) 1694aeafcbafSArnaldo Carvalho de Melo return dso__load_kernel_sym(dso, map, filter); 1695aeafcbafSArnaldo Carvalho de Melo else if (dso->kernel == DSO_TYPE_GUEST_KERNEL) 1696aeafcbafSArnaldo Carvalho de Melo return dso__load_guest_kernel_sym(dso, map, filter); 1697a1645ce1SZhang, Yanmin 169823346f21SArnaldo Carvalho de Melo if (map->groups && map->groups->machine) 169923346f21SArnaldo Carvalho de Melo machine = map->groups->machine; 1700a1645ce1SZhang, Yanmin else 170123346f21SArnaldo Carvalho de Melo machine = NULL; 1702c338aee8SArnaldo Carvalho de Melo 1703c338aee8SArnaldo Carvalho de Melo name = malloc(size); 170486470930SIngo Molnar if (!name) 170586470930SIngo Molnar return -1; 170686470930SIngo Molnar 1707aeafcbafSArnaldo Carvalho de Melo dso->adjust_symbols = 0; 1708f5812a7aSArnaldo Carvalho de Melo 1709aeafcbafSArnaldo Carvalho de Melo if (strncmp(dso->name, "/tmp/perf-", 10) == 0) { 1710981c1252SPekka Enberg struct stat st; 1711981c1252SPekka Enberg 1712e9b52ef2SVasiliy Kulikov if (lstat(dso->name, &st) < 0) 1713981c1252SPekka Enberg return -1; 1714981c1252SPekka Enberg 1715981c1252SPekka Enberg if (st.st_uid && (st.st_uid != geteuid())) { 1716981c1252SPekka Enberg pr_warning("File %s not owned by current user or root, " 1717981c1252SPekka Enberg "ignoring it.\n", dso->name); 1718981c1252SPekka Enberg return -1; 1719981c1252SPekka Enberg } 1720981c1252SPekka Enberg 1721aeafcbafSArnaldo Carvalho de Melo ret = dso__load_perf_map(dso, map, filter); 1722aeafcbafSArnaldo Carvalho de Melo dso->symtab_type = ret > 0 ? SYMTAB__JAVA_JIT : 1723878b439dSArnaldo Carvalho de Melo SYMTAB__NOT_FOUND; 172494cb9e38SArnaldo Carvalho de Melo return ret; 172594cb9e38SArnaldo Carvalho de Melo } 172694cb9e38SArnaldo Carvalho de Melo 17276da80ce8SDave Martin /* Iterate over candidate debug images. 17286da80ce8SDave Martin * On the first pass, only load images if they have a full symtab. 17296da80ce8SDave Martin * Failing that, do a second pass where we accept .dynsym also 17306da80ce8SDave Martin */ 173160e4b10cSArnaldo Carvalho de Melo want_symtab = 1; 173260e4b10cSArnaldo Carvalho de Melo restart: 1733209bd9e3SPierre-Loup A. Griffais for (dso->symtab_type = SYMTAB__DEBUGLINK; 1734aeafcbafSArnaldo Carvalho de Melo dso->symtab_type != SYMTAB__NOT_FOUND; 1735aeafcbafSArnaldo Carvalho de Melo dso->symtab_type++) { 1736aeafcbafSArnaldo Carvalho de Melo switch (dso->symtab_type) { 1737209bd9e3SPierre-Loup A. Griffais case SYMTAB__DEBUGLINK: { 1738209bd9e3SPierre-Loup A. Griffais char *debuglink; 1739209bd9e3SPierre-Loup A. Griffais strncpy(name, dso->long_name, size); 1740209bd9e3SPierre-Loup A. Griffais debuglink = name + dso->long_name_len; 1741209bd9e3SPierre-Loup A. Griffais while (debuglink != name && *debuglink != '/') 1742209bd9e3SPierre-Loup A. Griffais debuglink--; 1743209bd9e3SPierre-Loup A. Griffais if (*debuglink == '/') 1744209bd9e3SPierre-Loup A. Griffais debuglink++; 1745209bd9e3SPierre-Loup A. Griffais filename__read_debuglink(dso->long_name, debuglink, 1746209bd9e3SPierre-Loup A. Griffais size - (debuglink - name)); 1747209bd9e3SPierre-Loup A. Griffais } 1748209bd9e3SPierre-Loup A. Griffais break; 1749878b439dSArnaldo Carvalho de Melo case SYMTAB__BUILD_ID_CACHE: 1750ec5761eaSDavid Ahern /* skip the locally configured cache if a symfs is given */ 1751ec5761eaSDavid Ahern if (symbol_conf.symfs[0] || 1752aeafcbafSArnaldo Carvalho de Melo (dso__build_id_filename(dso, name, size) == NULL)) { 17536da80ce8SDave Martin continue; 1754ec5761eaSDavid Ahern } 17556da80ce8SDave Martin break; 1756878b439dSArnaldo Carvalho de Melo case SYMTAB__FEDORA_DEBUGINFO: 1757ec5761eaSDavid Ahern snprintf(name, size, "%s/usr/lib/debug%s.debug", 1758aeafcbafSArnaldo Carvalho de Melo symbol_conf.symfs, dso->long_name); 175986470930SIngo Molnar break; 1760878b439dSArnaldo Carvalho de Melo case SYMTAB__UBUNTU_DEBUGINFO: 1761ec5761eaSDavid Ahern snprintf(name, size, "%s/usr/lib/debug%s", 1762aeafcbafSArnaldo Carvalho de Melo symbol_conf.symfs, dso->long_name); 176386470930SIngo Molnar break; 1764878b439dSArnaldo Carvalho de Melo case SYMTAB__BUILDID_DEBUGINFO: { 1765b36f19d5SArnaldo Carvalho de Melo char build_id_hex[BUILD_ID_SIZE * 2 + 1]; 17666da80ce8SDave Martin 1767aeafcbafSArnaldo Carvalho de Melo if (!dso->has_build_id) 17686da80ce8SDave Martin continue; 17696da80ce8SDave Martin 1770aeafcbafSArnaldo Carvalho de Melo build_id__sprintf(dso->build_id, 1771aeafcbafSArnaldo Carvalho de Melo sizeof(dso->build_id), 1772d3379ab9SArnaldo Carvalho de Melo build_id_hex); 17734d1e00a8SArnaldo Carvalho de Melo snprintf(name, size, 1774ec5761eaSDavid Ahern "%s/usr/lib/debug/.build-id/%.2s/%s.debug", 1775ec5761eaSDavid Ahern symbol_conf.symfs, build_id_hex, build_id_hex + 2); 17764d1e00a8SArnaldo Carvalho de Melo } 17776da80ce8SDave Martin break; 1778878b439dSArnaldo Carvalho de Melo case SYMTAB__SYSTEM_PATH_DSO: 1779ec5761eaSDavid Ahern snprintf(name, size, "%s%s", 1780aeafcbafSArnaldo Carvalho de Melo symbol_conf.symfs, dso->long_name); 178186470930SIngo Molnar break; 1782878b439dSArnaldo Carvalho de Melo case SYMTAB__GUEST_KMODULE: 1783fb7d0b3cSKyle McMartin if (map->groups && machine) 1784fb7d0b3cSKyle McMartin root_dir = machine->root_dir; 1785a1645ce1SZhang, Yanmin else 1786a1645ce1SZhang, Yanmin root_dir = ""; 1787ec5761eaSDavid Ahern snprintf(name, size, "%s%s%s", symbol_conf.symfs, 1788aeafcbafSArnaldo Carvalho de Melo root_dir, dso->long_name); 1789ec5761eaSDavid Ahern break; 1790ec5761eaSDavid Ahern 1791878b439dSArnaldo Carvalho de Melo case SYMTAB__SYSTEM_PATH_KMODULE: 1792ec5761eaSDavid Ahern snprintf(name, size, "%s%s", symbol_conf.symfs, 1793aeafcbafSArnaldo Carvalho de Melo dso->long_name); 1794a1645ce1SZhang, Yanmin break; 179560e4b10cSArnaldo Carvalho de Melo default:; 179686470930SIngo Molnar } 179786470930SIngo Molnar 17986da80ce8SDave Martin /* Name is now the name of the next image to try */ 17996da80ce8SDave Martin fd = open(name, O_RDONLY); 18006da80ce8SDave Martin if (fd < 0) 18016da80ce8SDave Martin continue; 18026da80ce8SDave Martin 1803aeafcbafSArnaldo Carvalho de Melo ret = dso__load_sym(dso, map, name, fd, filter, 0, 18046da80ce8SDave Martin want_symtab); 180586470930SIngo Molnar close(fd); 180686470930SIngo Molnar 180786470930SIngo Molnar /* 18086da80ce8SDave Martin * Some people seem to have debuginfo files _WITHOUT_ debug 18096da80ce8SDave Martin * info!?!? 181086470930SIngo Molnar */ 181186470930SIngo Molnar if (!ret) 18126da80ce8SDave Martin continue; 181386470930SIngo Molnar 1814a25e46c4SArnaldo Carvalho de Melo if (ret > 0) { 181533ff581eSJiri Olsa int nr_plt; 181633ff581eSJiri Olsa 181733ff581eSJiri Olsa nr_plt = dso__synthesize_plt_symbols(dso, name, map, filter); 1818a25e46c4SArnaldo Carvalho de Melo if (nr_plt > 0) 1819a25e46c4SArnaldo Carvalho de Melo ret += nr_plt; 18206da80ce8SDave Martin break; 1821a25e46c4SArnaldo Carvalho de Melo } 18226da80ce8SDave Martin } 18236da80ce8SDave Martin 182460e4b10cSArnaldo Carvalho de Melo /* 182560e4b10cSArnaldo Carvalho de Melo * If we wanted a full symtab but no image had one, 182660e4b10cSArnaldo Carvalho de Melo * relax our requirements and repeat the search. 182760e4b10cSArnaldo Carvalho de Melo */ 182860e4b10cSArnaldo Carvalho de Melo if (ret <= 0 && want_symtab) { 182960e4b10cSArnaldo Carvalho de Melo want_symtab = 0; 183060e4b10cSArnaldo Carvalho de Melo goto restart; 183160e4b10cSArnaldo Carvalho de Melo } 183260e4b10cSArnaldo Carvalho de Melo 183386470930SIngo Molnar free(name); 1834aeafcbafSArnaldo Carvalho de Melo if (ret < 0 && strstr(dso->name, " (deleted)") != NULL) 18351340e6bbSArnaldo Carvalho de Melo return 0; 183686470930SIngo Molnar return ret; 183786470930SIngo Molnar } 183886470930SIngo Molnar 1839aeafcbafSArnaldo Carvalho de Melo struct map *map_groups__find_by_name(struct map_groups *mg, 184079406cd7SArnaldo Carvalho de Melo enum map_type type, const char *name) 1841439d473bSArnaldo Carvalho de Melo { 1842439d473bSArnaldo Carvalho de Melo struct rb_node *nd; 1843439d473bSArnaldo Carvalho de Melo 1844aeafcbafSArnaldo Carvalho de Melo for (nd = rb_first(&mg->maps[type]); nd; nd = rb_next(nd)) { 1845439d473bSArnaldo Carvalho de Melo struct map *map = rb_entry(nd, struct map, rb_node); 1846439d473bSArnaldo Carvalho de Melo 1847b7cece76SArnaldo Carvalho de Melo if (map->dso && strcmp(map->dso->short_name, name) == 0) 1848439d473bSArnaldo Carvalho de Melo return map; 1849439d473bSArnaldo Carvalho de Melo } 1850439d473bSArnaldo Carvalho de Melo 1851439d473bSArnaldo Carvalho de Melo return NULL; 1852439d473bSArnaldo Carvalho de Melo } 1853439d473bSArnaldo Carvalho de Melo 1854aeafcbafSArnaldo Carvalho de Melo static int dso__kernel_module_get_build_id(struct dso *dso, 1855a1645ce1SZhang, Yanmin const char *root_dir) 1856b7cece76SArnaldo Carvalho de Melo { 1857b7cece76SArnaldo Carvalho de Melo char filename[PATH_MAX]; 1858b7cece76SArnaldo Carvalho de Melo /* 1859b7cece76SArnaldo Carvalho de Melo * kernel module short names are of the form "[module]" and 1860b7cece76SArnaldo Carvalho de Melo * we need just "module" here. 1861b7cece76SArnaldo Carvalho de Melo */ 1862aeafcbafSArnaldo Carvalho de Melo const char *name = dso->short_name + 1; 1863b7cece76SArnaldo Carvalho de Melo 1864b7cece76SArnaldo Carvalho de Melo snprintf(filename, sizeof(filename), 1865a1645ce1SZhang, Yanmin "%s/sys/module/%.*s/notes/.note.gnu.build-id", 1866a1645ce1SZhang, Yanmin root_dir, (int)strlen(name) - 1, name); 1867b7cece76SArnaldo Carvalho de Melo 1868aeafcbafSArnaldo Carvalho de Melo if (sysfs__read_build_id(filename, dso->build_id, 1869aeafcbafSArnaldo Carvalho de Melo sizeof(dso->build_id)) == 0) 1870aeafcbafSArnaldo Carvalho de Melo dso->has_build_id = true; 1871b7cece76SArnaldo Carvalho de Melo 1872b7cece76SArnaldo Carvalho de Melo return 0; 1873b7cece76SArnaldo Carvalho de Melo } 1874b7cece76SArnaldo Carvalho de Melo 1875aeafcbafSArnaldo Carvalho de Melo static int map_groups__set_modules_path_dir(struct map_groups *mg, 1876a1645ce1SZhang, Yanmin const char *dir_name) 18776cfcc53eSMike Galbraith { 1878439d473bSArnaldo Carvalho de Melo struct dirent *dent; 18795aab621bSArnaldo Carvalho de Melo DIR *dir = opendir(dir_name); 188074534341SGui Jianfeng int ret = 0; 18816cfcc53eSMike Galbraith 1882439d473bSArnaldo Carvalho de Melo if (!dir) { 18835aab621bSArnaldo Carvalho de Melo pr_debug("%s: cannot open %s dir\n", __func__, dir_name); 1884439d473bSArnaldo Carvalho de Melo return -1; 1885439d473bSArnaldo Carvalho de Melo } 18866cfcc53eSMike Galbraith 1887439d473bSArnaldo Carvalho de Melo while ((dent = readdir(dir)) != NULL) { 1888439d473bSArnaldo Carvalho de Melo char path[PATH_MAX]; 1889a1645ce1SZhang, Yanmin struct stat st; 1890439d473bSArnaldo Carvalho de Melo 1891a1645ce1SZhang, Yanmin /*sshfs might return bad dent->d_type, so we have to stat*/ 18922b600f95SNamhyung Kim snprintf(path, sizeof(path), "%s/%s", dir_name, dent->d_name); 1893a1645ce1SZhang, Yanmin if (stat(path, &st)) 1894a1645ce1SZhang, Yanmin continue; 1895a1645ce1SZhang, Yanmin 1896a1645ce1SZhang, Yanmin if (S_ISDIR(st.st_mode)) { 1897439d473bSArnaldo Carvalho de Melo if (!strcmp(dent->d_name, ".") || 1898439d473bSArnaldo Carvalho de Melo !strcmp(dent->d_name, "..")) 1899439d473bSArnaldo Carvalho de Melo continue; 1900439d473bSArnaldo Carvalho de Melo 1901aeafcbafSArnaldo Carvalho de Melo ret = map_groups__set_modules_path_dir(mg, path); 190274534341SGui Jianfeng if (ret < 0) 190374534341SGui Jianfeng goto out; 1904439d473bSArnaldo Carvalho de Melo } else { 1905439d473bSArnaldo Carvalho de Melo char *dot = strrchr(dent->d_name, '.'), 1906439d473bSArnaldo Carvalho de Melo dso_name[PATH_MAX]; 1907439d473bSArnaldo Carvalho de Melo struct map *map; 1908cfc10d3bSArnaldo Carvalho de Melo char *long_name; 1909439d473bSArnaldo Carvalho de Melo 1910439d473bSArnaldo Carvalho de Melo if (dot == NULL || strcmp(dot, ".ko")) 1911439d473bSArnaldo Carvalho de Melo continue; 1912439d473bSArnaldo Carvalho de Melo snprintf(dso_name, sizeof(dso_name), "[%.*s]", 1913439d473bSArnaldo Carvalho de Melo (int)(dot - dent->d_name), dent->d_name); 1914439d473bSArnaldo Carvalho de Melo 1915a2a99e8eSArnaldo Carvalho de Melo strxfrchar(dso_name, '-', '_'); 1916aeafcbafSArnaldo Carvalho de Melo map = map_groups__find_by_name(mg, MAP__FUNCTION, 1917aeafcbafSArnaldo Carvalho de Melo dso_name); 1918439d473bSArnaldo Carvalho de Melo if (map == NULL) 1919439d473bSArnaldo Carvalho de Melo continue; 1920439d473bSArnaldo Carvalho de Melo 1921cfc10d3bSArnaldo Carvalho de Melo long_name = strdup(path); 192274534341SGui Jianfeng if (long_name == NULL) { 192374534341SGui Jianfeng ret = -1; 192474534341SGui Jianfeng goto out; 192574534341SGui Jianfeng } 1926cfc10d3bSArnaldo Carvalho de Melo dso__set_long_name(map->dso, long_name); 19276e406257SArnaldo Carvalho de Melo map->dso->lname_alloc = 1; 1928a1645ce1SZhang, Yanmin dso__kernel_module_get_build_id(map->dso, ""); 1929439d473bSArnaldo Carvalho de Melo } 1930439d473bSArnaldo Carvalho de Melo } 1931439d473bSArnaldo Carvalho de Melo 193274534341SGui Jianfeng out: 1933439d473bSArnaldo Carvalho de Melo closedir(dir); 193474534341SGui Jianfeng return ret; 1935439d473bSArnaldo Carvalho de Melo } 1936439d473bSArnaldo Carvalho de Melo 1937a1645ce1SZhang, Yanmin static char *get_kernel_version(const char *root_dir) 1938439d473bSArnaldo Carvalho de Melo { 1939a1645ce1SZhang, Yanmin char version[PATH_MAX]; 1940a1645ce1SZhang, Yanmin FILE *file; 1941a1645ce1SZhang, Yanmin char *name, *tmp; 1942a1645ce1SZhang, Yanmin const char *prefix = "Linux version "; 1943a1645ce1SZhang, Yanmin 1944a1645ce1SZhang, Yanmin sprintf(version, "%s/proc/version", root_dir); 1945a1645ce1SZhang, Yanmin file = fopen(version, "r"); 1946a1645ce1SZhang, Yanmin if (!file) 1947a1645ce1SZhang, Yanmin return NULL; 1948a1645ce1SZhang, Yanmin 1949a1645ce1SZhang, Yanmin version[0] = '\0'; 1950a1645ce1SZhang, Yanmin tmp = fgets(version, sizeof(version), file); 1951a1645ce1SZhang, Yanmin fclose(file); 1952a1645ce1SZhang, Yanmin 1953a1645ce1SZhang, Yanmin name = strstr(version, prefix); 1954a1645ce1SZhang, Yanmin if (!name) 1955a1645ce1SZhang, Yanmin return NULL; 1956a1645ce1SZhang, Yanmin name += strlen(prefix); 1957a1645ce1SZhang, Yanmin tmp = strchr(name, ' '); 1958a1645ce1SZhang, Yanmin if (tmp) 1959a1645ce1SZhang, Yanmin *tmp = '\0'; 1960a1645ce1SZhang, Yanmin 1961a1645ce1SZhang, Yanmin return strdup(name); 1962a1645ce1SZhang, Yanmin } 1963a1645ce1SZhang, Yanmin 1964aeafcbafSArnaldo Carvalho de Melo static int machine__set_modules_path(struct machine *machine) 1965a1645ce1SZhang, Yanmin { 1966a1645ce1SZhang, Yanmin char *version; 1967439d473bSArnaldo Carvalho de Melo char modules_path[PATH_MAX]; 1968439d473bSArnaldo Carvalho de Melo 1969aeafcbafSArnaldo Carvalho de Melo version = get_kernel_version(machine->root_dir); 1970a1645ce1SZhang, Yanmin if (!version) 1971439d473bSArnaldo Carvalho de Melo return -1; 1972439d473bSArnaldo Carvalho de Melo 1973a1645ce1SZhang, Yanmin snprintf(modules_path, sizeof(modules_path), "%s/lib/modules/%s/kernel", 1974aeafcbafSArnaldo Carvalho de Melo machine->root_dir, version); 1975a1645ce1SZhang, Yanmin free(version); 1976439d473bSArnaldo Carvalho de Melo 1977aeafcbafSArnaldo Carvalho de Melo return map_groups__set_modules_path_dir(&machine->kmaps, modules_path); 1978439d473bSArnaldo Carvalho de Melo } 19796cfcc53eSMike Galbraith 19806cfcc53eSMike Galbraith /* 1981439d473bSArnaldo Carvalho de Melo * Constructor variant for modules (where we know from /proc/modules where 1982439d473bSArnaldo Carvalho de Melo * they are loaded) and for vmlinux, where only after we load all the 1983439d473bSArnaldo Carvalho de Melo * symbols we'll know where it starts and ends. 19846cfcc53eSMike Galbraith */ 19853610583cSArnaldo Carvalho de Melo static struct map *map__new2(u64 start, struct dso *dso, enum map_type type) 1986439d473bSArnaldo Carvalho de Melo { 1987aeafcbafSArnaldo Carvalho de Melo struct map *map = calloc(1, (sizeof(*map) + 19885aab621bSArnaldo Carvalho de Melo (dso->kernel ? sizeof(struct kmap) : 0))); 1989aeafcbafSArnaldo Carvalho de Melo if (map != NULL) { 1990439d473bSArnaldo Carvalho de Melo /* 1991afb7b4f0SArnaldo Carvalho de Melo * ->end will be filled after we load all the symbols 1992439d473bSArnaldo Carvalho de Melo */ 1993aeafcbafSArnaldo Carvalho de Melo map__init(map, type, start, 0, 0, dso); 1994439d473bSArnaldo Carvalho de Melo } 1995afb7b4f0SArnaldo Carvalho de Melo 1996aeafcbafSArnaldo Carvalho de Melo return map; 1997439d473bSArnaldo Carvalho de Melo } 1998439d473bSArnaldo Carvalho de Melo 1999aeafcbafSArnaldo Carvalho de Melo struct map *machine__new_module(struct machine *machine, u64 start, 2000d28c6223SArnaldo Carvalho de Melo const char *filename) 2001b7cece76SArnaldo Carvalho de Melo { 2002b7cece76SArnaldo Carvalho de Melo struct map *map; 2003aeafcbafSArnaldo Carvalho de Melo struct dso *dso = __dsos__findnew(&machine->kernel_dsos, filename); 2004b7cece76SArnaldo Carvalho de Melo 2005b7cece76SArnaldo Carvalho de Melo if (dso == NULL) 2006b7cece76SArnaldo Carvalho de Melo return NULL; 2007b7cece76SArnaldo Carvalho de Melo 2008b7cece76SArnaldo Carvalho de Melo map = map__new2(start, dso, MAP__FUNCTION); 2009b7cece76SArnaldo Carvalho de Melo if (map == NULL) 2010b7cece76SArnaldo Carvalho de Melo return NULL; 2011b7cece76SArnaldo Carvalho de Melo 2012aeafcbafSArnaldo Carvalho de Melo if (machine__is_host(machine)) 2013878b439dSArnaldo Carvalho de Melo dso->symtab_type = SYMTAB__SYSTEM_PATH_KMODULE; 2014a1645ce1SZhang, Yanmin else 2015878b439dSArnaldo Carvalho de Melo dso->symtab_type = SYMTAB__GUEST_KMODULE; 2016aeafcbafSArnaldo Carvalho de Melo map_groups__insert(&machine->kmaps, map); 2017b7cece76SArnaldo Carvalho de Melo return map; 2018b7cece76SArnaldo Carvalho de Melo } 2019b7cece76SArnaldo Carvalho de Melo 2020aeafcbafSArnaldo Carvalho de Melo static int machine__create_modules(struct machine *machine) 2021439d473bSArnaldo Carvalho de Melo { 2022439d473bSArnaldo Carvalho de Melo char *line = NULL; 2023439d473bSArnaldo Carvalho de Melo size_t n; 2024a1645ce1SZhang, Yanmin FILE *file; 2025439d473bSArnaldo Carvalho de Melo struct map *map; 2026a1645ce1SZhang, Yanmin const char *modules; 2027a1645ce1SZhang, Yanmin char path[PATH_MAX]; 2028439d473bSArnaldo Carvalho de Melo 2029aeafcbafSArnaldo Carvalho de Melo if (machine__is_default_guest(machine)) 2030a1645ce1SZhang, Yanmin modules = symbol_conf.default_guest_modules; 2031a1645ce1SZhang, Yanmin else { 2032aeafcbafSArnaldo Carvalho de Melo sprintf(path, "%s/proc/modules", machine->root_dir); 2033a1645ce1SZhang, Yanmin modules = path; 2034a1645ce1SZhang, Yanmin } 2035a1645ce1SZhang, Yanmin 2036ec80fde7SArnaldo Carvalho de Melo if (symbol__restricted_filename(path, "/proc/modules")) 2037ec80fde7SArnaldo Carvalho de Melo return -1; 2038ec80fde7SArnaldo Carvalho de Melo 2039a1645ce1SZhang, Yanmin file = fopen(modules, "r"); 2040439d473bSArnaldo Carvalho de Melo if (file == NULL) 2041439d473bSArnaldo Carvalho de Melo return -1; 2042439d473bSArnaldo Carvalho de Melo 2043439d473bSArnaldo Carvalho de Melo while (!feof(file)) { 2044439d473bSArnaldo Carvalho de Melo char name[PATH_MAX]; 2045439d473bSArnaldo Carvalho de Melo u64 start; 2046439d473bSArnaldo Carvalho de Melo char *sep; 2047439d473bSArnaldo Carvalho de Melo int line_len; 2048439d473bSArnaldo Carvalho de Melo 2049439d473bSArnaldo Carvalho de Melo line_len = getline(&line, &n, file); 2050439d473bSArnaldo Carvalho de Melo if (line_len < 0) 20516cfcc53eSMike Galbraith break; 20526cfcc53eSMike Galbraith 2053439d473bSArnaldo Carvalho de Melo if (!line) 2054439d473bSArnaldo Carvalho de Melo goto out_failure; 2055439d473bSArnaldo Carvalho de Melo 2056439d473bSArnaldo Carvalho de Melo line[--line_len] = '\0'; /* \n */ 2057439d473bSArnaldo Carvalho de Melo 2058439d473bSArnaldo Carvalho de Melo sep = strrchr(line, 'x'); 2059439d473bSArnaldo Carvalho de Melo if (sep == NULL) 2060439d473bSArnaldo Carvalho de Melo continue; 2061439d473bSArnaldo Carvalho de Melo 2062439d473bSArnaldo Carvalho de Melo hex2u64(sep + 1, &start); 2063439d473bSArnaldo Carvalho de Melo 2064439d473bSArnaldo Carvalho de Melo sep = strchr(line, ' '); 2065439d473bSArnaldo Carvalho de Melo if (sep == NULL) 2066439d473bSArnaldo Carvalho de Melo continue; 2067439d473bSArnaldo Carvalho de Melo 2068439d473bSArnaldo Carvalho de Melo *sep = '\0'; 2069439d473bSArnaldo Carvalho de Melo 2070439d473bSArnaldo Carvalho de Melo snprintf(name, sizeof(name), "[%s]", line); 2071aeafcbafSArnaldo Carvalho de Melo map = machine__new_module(machine, start, name); 2072b7cece76SArnaldo Carvalho de Melo if (map == NULL) 2073439d473bSArnaldo Carvalho de Melo goto out_delete_line; 2074aeafcbafSArnaldo Carvalho de Melo dso__kernel_module_get_build_id(map->dso, machine->root_dir); 20756cfcc53eSMike Galbraith } 20766cfcc53eSMike Galbraith 2077439d473bSArnaldo Carvalho de Melo free(line); 2078439d473bSArnaldo Carvalho de Melo fclose(file); 2079439d473bSArnaldo Carvalho de Melo 2080aeafcbafSArnaldo Carvalho de Melo return machine__set_modules_path(machine); 2081439d473bSArnaldo Carvalho de Melo 2082439d473bSArnaldo Carvalho de Melo out_delete_line: 2083439d473bSArnaldo Carvalho de Melo free(line); 2084439d473bSArnaldo Carvalho de Melo out_failure: 2085439d473bSArnaldo Carvalho de Melo return -1; 20866cfcc53eSMike Galbraith } 20876cfcc53eSMike Galbraith 2088aeafcbafSArnaldo Carvalho de Melo int dso__load_vmlinux(struct dso *dso, struct map *map, 20896beba7adSArnaldo Carvalho de Melo const char *vmlinux, symbol_filter_t filter) 209086470930SIngo Molnar { 2091fbd733b8SArnaldo Carvalho de Melo int err = -1, fd; 2092ec5761eaSDavid Ahern char symfs_vmlinux[PATH_MAX]; 209386470930SIngo Molnar 2094a639dc64SArnaldo Carvalho de Melo snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s%s", 2095ec5761eaSDavid Ahern symbol_conf.symfs, vmlinux); 2096ec5761eaSDavid Ahern fd = open(symfs_vmlinux, O_RDONLY); 209786470930SIngo Molnar if (fd < 0) 209886470930SIngo Molnar return -1; 209986470930SIngo Molnar 2100aeafcbafSArnaldo Carvalho de Melo dso__set_long_name(dso, (char *)vmlinux); 2101aeafcbafSArnaldo Carvalho de Melo dso__set_loaded(dso, map->type); 2102aeafcbafSArnaldo Carvalho de Melo err = dso__load_sym(dso, map, symfs_vmlinux, fd, filter, 0, 0); 210386470930SIngo Molnar close(fd); 210486470930SIngo Molnar 21053846df2eSArnaldo Carvalho de Melo if (err > 0) 2106ec5761eaSDavid Ahern pr_debug("Using %s for symbols\n", symfs_vmlinux); 21073846df2eSArnaldo Carvalho de Melo 210886470930SIngo Molnar return err; 210986470930SIngo Molnar } 211086470930SIngo Molnar 2111aeafcbafSArnaldo Carvalho de Melo int dso__load_vmlinux_path(struct dso *dso, struct map *map, 21129de89fe7SArnaldo Carvalho de Melo symbol_filter_t filter) 2113a19afe46SArnaldo Carvalho de Melo { 2114a19afe46SArnaldo Carvalho de Melo int i, err = 0; 21155ad90e4eSArnaldo Carvalho de Melo char *filename; 2116a19afe46SArnaldo Carvalho de Melo 2117a19afe46SArnaldo Carvalho de Melo pr_debug("Looking at the vmlinux_path (%d entries long)\n", 21185ad90e4eSArnaldo Carvalho de Melo vmlinux_path__nr_entries + 1); 21195ad90e4eSArnaldo Carvalho de Melo 2120aeafcbafSArnaldo Carvalho de Melo filename = dso__build_id_filename(dso, NULL, 0); 21215ad90e4eSArnaldo Carvalho de Melo if (filename != NULL) { 2122aeafcbafSArnaldo Carvalho de Melo err = dso__load_vmlinux(dso, map, filename, filter); 21235ad90e4eSArnaldo Carvalho de Melo if (err > 0) { 2124aeafcbafSArnaldo Carvalho de Melo dso__set_long_name(dso, filename); 21255ad90e4eSArnaldo Carvalho de Melo goto out; 21265ad90e4eSArnaldo Carvalho de Melo } 21275ad90e4eSArnaldo Carvalho de Melo free(filename); 21285ad90e4eSArnaldo Carvalho de Melo } 2129a19afe46SArnaldo Carvalho de Melo 2130a19afe46SArnaldo Carvalho de Melo for (i = 0; i < vmlinux_path__nr_entries; ++i) { 2131aeafcbafSArnaldo Carvalho de Melo err = dso__load_vmlinux(dso, map, vmlinux_path[i], filter); 2132a19afe46SArnaldo Carvalho de Melo if (err > 0) { 2133aeafcbafSArnaldo Carvalho de Melo dso__set_long_name(dso, strdup(vmlinux_path[i])); 2134a19afe46SArnaldo Carvalho de Melo break; 2135a19afe46SArnaldo Carvalho de Melo } 2136a19afe46SArnaldo Carvalho de Melo } 21375ad90e4eSArnaldo Carvalho de Melo out: 2138a19afe46SArnaldo Carvalho de Melo return err; 2139a19afe46SArnaldo Carvalho de Melo } 2140a19afe46SArnaldo Carvalho de Melo 2141aeafcbafSArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *dso, struct map *map, 21429de89fe7SArnaldo Carvalho de Melo symbol_filter_t filter) 214386470930SIngo Molnar { 2144cc612d81SArnaldo Carvalho de Melo int err; 21459e201442SArnaldo Carvalho de Melo const char *kallsyms_filename = NULL; 21469e201442SArnaldo Carvalho de Melo char *kallsyms_allocated_filename = NULL; 2147dc8d6ab2SArnaldo Carvalho de Melo /* 2148b226a5a7SDavid Ahern * Step 1: if the user specified a kallsyms or vmlinux filename, use 2149b226a5a7SDavid Ahern * it and only it, reporting errors to the user if it cannot be used. 2150dc8d6ab2SArnaldo Carvalho de Melo * 2151dc8d6ab2SArnaldo Carvalho de Melo * For instance, try to analyse an ARM perf.data file _without_ a 2152dc8d6ab2SArnaldo Carvalho de Melo * build-id, or if the user specifies the wrong path to the right 2153dc8d6ab2SArnaldo Carvalho de Melo * vmlinux file, obviously we can't fallback to another vmlinux (a 2154dc8d6ab2SArnaldo Carvalho de Melo * x86_86 one, on the machine where analysis is being performed, say), 2155dc8d6ab2SArnaldo Carvalho de Melo * or worse, /proc/kallsyms. 2156dc8d6ab2SArnaldo Carvalho de Melo * 2157dc8d6ab2SArnaldo Carvalho de Melo * If the specified file _has_ a build-id and there is a build-id 2158dc8d6ab2SArnaldo Carvalho de Melo * section in the perf.data file, we will still do the expected 2159dc8d6ab2SArnaldo Carvalho de Melo * validation in dso__load_vmlinux and will bail out if they don't 2160dc8d6ab2SArnaldo Carvalho de Melo * match. 2161dc8d6ab2SArnaldo Carvalho de Melo */ 2162b226a5a7SDavid Ahern if (symbol_conf.kallsyms_name != NULL) { 2163b226a5a7SDavid Ahern kallsyms_filename = symbol_conf.kallsyms_name; 2164b226a5a7SDavid Ahern goto do_kallsyms; 2165b226a5a7SDavid Ahern } 2166b226a5a7SDavid Ahern 2167dc8d6ab2SArnaldo Carvalho de Melo if (symbol_conf.vmlinux_name != NULL) { 2168aeafcbafSArnaldo Carvalho de Melo err = dso__load_vmlinux(dso, map, 2169dc8d6ab2SArnaldo Carvalho de Melo symbol_conf.vmlinux_name, filter); 2170e7dadc00SArnaldo Carvalho de Melo if (err > 0) { 2171aeafcbafSArnaldo Carvalho de Melo dso__set_long_name(dso, 2172e7dadc00SArnaldo Carvalho de Melo strdup(symbol_conf.vmlinux_name)); 2173e7dadc00SArnaldo Carvalho de Melo goto out_fixup; 2174e7dadc00SArnaldo Carvalho de Melo } 2175e7dadc00SArnaldo Carvalho de Melo return err; 2176dc8d6ab2SArnaldo Carvalho de Melo } 2177439d473bSArnaldo Carvalho de Melo 2178cc612d81SArnaldo Carvalho de Melo if (vmlinux_path != NULL) { 2179aeafcbafSArnaldo Carvalho de Melo err = dso__load_vmlinux_path(dso, map, filter); 2180a19afe46SArnaldo Carvalho de Melo if (err > 0) 2181cc612d81SArnaldo Carvalho de Melo goto out_fixup; 2182cc612d81SArnaldo Carvalho de Melo } 2183cc612d81SArnaldo Carvalho de Melo 2184ec5761eaSDavid Ahern /* do not try local files if a symfs was given */ 2185ec5761eaSDavid Ahern if (symbol_conf.symfs[0] != 0) 2186ec5761eaSDavid Ahern return -1; 2187ec5761eaSDavid Ahern 2188b7cece76SArnaldo Carvalho de Melo /* 2189b7cece76SArnaldo Carvalho de Melo * Say the kernel DSO was created when processing the build-id header table, 2190b7cece76SArnaldo Carvalho de Melo * we have a build-id, so check if it is the same as the running kernel, 2191b7cece76SArnaldo Carvalho de Melo * using it if it is. 2192b7cece76SArnaldo Carvalho de Melo */ 2193aeafcbafSArnaldo Carvalho de Melo if (dso->has_build_id) { 2194b7cece76SArnaldo Carvalho de Melo u8 kallsyms_build_id[BUILD_ID_SIZE]; 21959e201442SArnaldo Carvalho de Melo char sbuild_id[BUILD_ID_SIZE * 2 + 1]; 2196b7cece76SArnaldo Carvalho de Melo 2197b7cece76SArnaldo Carvalho de Melo if (sysfs__read_build_id("/sys/kernel/notes", kallsyms_build_id, 21988d0591f6SArnaldo Carvalho de Melo sizeof(kallsyms_build_id)) == 0) { 2199aeafcbafSArnaldo Carvalho de Melo if (dso__build_id_equal(dso, kallsyms_build_id)) { 22009e201442SArnaldo Carvalho de Melo kallsyms_filename = "/proc/kallsyms"; 2201b7cece76SArnaldo Carvalho de Melo goto do_kallsyms; 22028d0591f6SArnaldo Carvalho de Melo } 22039e201442SArnaldo Carvalho de Melo } 2204dc8d6ab2SArnaldo Carvalho de Melo /* 2205dc8d6ab2SArnaldo Carvalho de Melo * Now look if we have it on the build-id cache in 2206dc8d6ab2SArnaldo Carvalho de Melo * $HOME/.debug/[kernel.kallsyms]. 2207dc8d6ab2SArnaldo Carvalho de Melo */ 2208aeafcbafSArnaldo Carvalho de Melo build_id__sprintf(dso->build_id, sizeof(dso->build_id), 22099e201442SArnaldo Carvalho de Melo sbuild_id); 22109e201442SArnaldo Carvalho de Melo 22119e201442SArnaldo Carvalho de Melo if (asprintf(&kallsyms_allocated_filename, 22129e201442SArnaldo Carvalho de Melo "%s/.debug/[kernel.kallsyms]/%s", 22133846df2eSArnaldo Carvalho de Melo getenv("HOME"), sbuild_id) == -1) { 22143846df2eSArnaldo Carvalho de Melo pr_err("Not enough memory for kallsyms file lookup\n"); 22158d0591f6SArnaldo Carvalho de Melo return -1; 22163846df2eSArnaldo Carvalho de Melo } 22178d0591f6SArnaldo Carvalho de Melo 221819fc2dedSArnaldo Carvalho de Melo kallsyms_filename = kallsyms_allocated_filename; 221919fc2dedSArnaldo Carvalho de Melo 2220dc8d6ab2SArnaldo Carvalho de Melo if (access(kallsyms_filename, F_OK)) { 22213846df2eSArnaldo Carvalho de Melo pr_err("No kallsyms or vmlinux with build-id %s " 22223846df2eSArnaldo Carvalho de Melo "was found\n", sbuild_id); 22239e201442SArnaldo Carvalho de Melo free(kallsyms_allocated_filename); 2224dc8d6ab2SArnaldo Carvalho de Melo return -1; 2225ef6ae724SArnaldo Carvalho de Melo } 2226dc8d6ab2SArnaldo Carvalho de Melo } else { 2227dc8d6ab2SArnaldo Carvalho de Melo /* 2228dc8d6ab2SArnaldo Carvalho de Melo * Last resort, if we don't have a build-id and couldn't find 2229dc8d6ab2SArnaldo Carvalho de Melo * any vmlinux file, try the running kernel kallsyms table. 2230dc8d6ab2SArnaldo Carvalho de Melo */ 2231dc8d6ab2SArnaldo Carvalho de Melo kallsyms_filename = "/proc/kallsyms"; 2232dc8d6ab2SArnaldo Carvalho de Melo } 2233dc8d6ab2SArnaldo Carvalho de Melo 2234dc8d6ab2SArnaldo Carvalho de Melo do_kallsyms: 2235aeafcbafSArnaldo Carvalho de Melo err = dso__load_kallsyms(dso, kallsyms_filename, map, filter); 22363846df2eSArnaldo Carvalho de Melo if (err > 0) 22373846df2eSArnaldo Carvalho de Melo pr_debug("Using %s for symbols\n", kallsyms_filename); 2238dc8d6ab2SArnaldo Carvalho de Melo free(kallsyms_allocated_filename); 2239dc8d6ab2SArnaldo Carvalho de Melo 2240439d473bSArnaldo Carvalho de Melo if (err > 0) { 2241cc612d81SArnaldo Carvalho de Melo out_fixup: 2242e1c7c6a4SArnaldo Carvalho de Melo if (kallsyms_filename != NULL) 2243aeafcbafSArnaldo Carvalho de Melo dso__set_long_name(dso, strdup("[kernel.kallsyms]")); 22446a4694a4SArnaldo Carvalho de Melo map__fixup_start(map); 22456a4694a4SArnaldo Carvalho de Melo map__fixup_end(map); 2246439d473bSArnaldo Carvalho de Melo } 224794cb9e38SArnaldo Carvalho de Melo 224886470930SIngo Molnar return err; 224986470930SIngo Molnar } 225086470930SIngo Molnar 2251aeafcbafSArnaldo Carvalho de Melo static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map, 2252a1645ce1SZhang, Yanmin symbol_filter_t filter) 2253a1645ce1SZhang, Yanmin { 2254a1645ce1SZhang, Yanmin int err; 2255a1645ce1SZhang, Yanmin const char *kallsyms_filename = NULL; 225623346f21SArnaldo Carvalho de Melo struct machine *machine; 2257a1645ce1SZhang, Yanmin char path[PATH_MAX]; 2258a1645ce1SZhang, Yanmin 2259a1645ce1SZhang, Yanmin if (!map->groups) { 2260a1645ce1SZhang, Yanmin pr_debug("Guest kernel map hasn't the point to groups\n"); 2261a1645ce1SZhang, Yanmin return -1; 2262a1645ce1SZhang, Yanmin } 226323346f21SArnaldo Carvalho de Melo machine = map->groups->machine; 2264a1645ce1SZhang, Yanmin 226523346f21SArnaldo Carvalho de Melo if (machine__is_default_guest(machine)) { 2266a1645ce1SZhang, Yanmin /* 2267a1645ce1SZhang, Yanmin * if the user specified a vmlinux filename, use it and only 2268a1645ce1SZhang, Yanmin * it, reporting errors to the user if it cannot be used. 2269a1645ce1SZhang, Yanmin * Or use file guest_kallsyms inputted by user on commandline 2270a1645ce1SZhang, Yanmin */ 2271a1645ce1SZhang, Yanmin if (symbol_conf.default_guest_vmlinux_name != NULL) { 2272aeafcbafSArnaldo Carvalho de Melo err = dso__load_vmlinux(dso, map, 2273a1645ce1SZhang, Yanmin symbol_conf.default_guest_vmlinux_name, filter); 2274a1645ce1SZhang, Yanmin goto out_try_fixup; 2275a1645ce1SZhang, Yanmin } 2276a1645ce1SZhang, Yanmin 2277a1645ce1SZhang, Yanmin kallsyms_filename = symbol_conf.default_guest_kallsyms; 2278a1645ce1SZhang, Yanmin if (!kallsyms_filename) 2279a1645ce1SZhang, Yanmin return -1; 2280a1645ce1SZhang, Yanmin } else { 228123346f21SArnaldo Carvalho de Melo sprintf(path, "%s/proc/kallsyms", machine->root_dir); 2282a1645ce1SZhang, Yanmin kallsyms_filename = path; 2283a1645ce1SZhang, Yanmin } 2284a1645ce1SZhang, Yanmin 2285aeafcbafSArnaldo Carvalho de Melo err = dso__load_kallsyms(dso, kallsyms_filename, map, filter); 2286a1645ce1SZhang, Yanmin if (err > 0) 2287a1645ce1SZhang, Yanmin pr_debug("Using %s for symbols\n", kallsyms_filename); 2288a1645ce1SZhang, Yanmin 2289a1645ce1SZhang, Yanmin out_try_fixup: 2290a1645ce1SZhang, Yanmin if (err > 0) { 2291a1645ce1SZhang, Yanmin if (kallsyms_filename != NULL) { 229248ea8f54SArnaldo Carvalho de Melo machine__mmap_name(machine, path, sizeof(path)); 2293aeafcbafSArnaldo Carvalho de Melo dso__set_long_name(dso, strdup(path)); 2294a1645ce1SZhang, Yanmin } 2295a1645ce1SZhang, Yanmin map__fixup_start(map); 2296a1645ce1SZhang, Yanmin map__fixup_end(map); 2297a1645ce1SZhang, Yanmin } 2298a1645ce1SZhang, Yanmin 2299a1645ce1SZhang, Yanmin return err; 2300a1645ce1SZhang, Yanmin } 2301cd84c2acSFrederic Weisbecker 2302b0da954aSArnaldo Carvalho de Melo static void dsos__add(struct list_head *head, struct dso *dso) 2303cd84c2acSFrederic Weisbecker { 2304b0da954aSArnaldo Carvalho de Melo list_add_tail(&dso->node, head); 2305cd84c2acSFrederic Weisbecker } 2306cd84c2acSFrederic Weisbecker 2307b0da954aSArnaldo Carvalho de Melo static struct dso *dsos__find(struct list_head *head, const char *name) 2308cd84c2acSFrederic Weisbecker { 2309cd84c2acSFrederic Weisbecker struct dso *pos; 2310cd84c2acSFrederic Weisbecker 2311b0da954aSArnaldo Carvalho de Melo list_for_each_entry(pos, head, node) 2312cf4e5b08SArnaldo Carvalho de Melo if (strcmp(pos->long_name, name) == 0) 2313cd84c2acSFrederic Weisbecker return pos; 2314cd84c2acSFrederic Weisbecker return NULL; 2315cd84c2acSFrederic Weisbecker } 2316cd84c2acSFrederic Weisbecker 2317a89e5abeSArnaldo Carvalho de Melo struct dso *__dsos__findnew(struct list_head *head, const char *name) 2318cd84c2acSFrederic Weisbecker { 2319a89e5abeSArnaldo Carvalho de Melo struct dso *dso = dsos__find(head, name); 2320cd84c2acSFrederic Weisbecker 2321e4204992SArnaldo Carvalho de Melo if (!dso) { 232200a192b3SArnaldo Carvalho de Melo dso = dso__new(name); 2323cfc10d3bSArnaldo Carvalho de Melo if (dso != NULL) { 2324a89e5abeSArnaldo Carvalho de Melo dsos__add(head, dso); 2325cfc10d3bSArnaldo Carvalho de Melo dso__set_basename(dso); 2326cfc10d3bSArnaldo Carvalho de Melo } 2327e4204992SArnaldo Carvalho de Melo } 2328cd84c2acSFrederic Weisbecker 2329cd84c2acSFrederic Weisbecker return dso; 2330cd84c2acSFrederic Weisbecker } 2331cd84c2acSFrederic Weisbecker 23321f626bc3SArnaldo Carvalho de Melo size_t __dsos__fprintf(struct list_head *head, FILE *fp) 2333cd84c2acSFrederic Weisbecker { 2334cd84c2acSFrederic Weisbecker struct dso *pos; 2335cbf69680SArnaldo Carvalho de Melo size_t ret = 0; 2336cd84c2acSFrederic Weisbecker 233795011c60SArnaldo Carvalho de Melo list_for_each_entry(pos, head, node) { 233895011c60SArnaldo Carvalho de Melo int i; 233995011c60SArnaldo Carvalho de Melo for (i = 0; i < MAP__NR_TYPES; ++i) 2340cbf69680SArnaldo Carvalho de Melo ret += dso__fprintf(pos, i, fp); 2341cd84c2acSFrederic Weisbecker } 2342cd84c2acSFrederic Weisbecker 2343cbf69680SArnaldo Carvalho de Melo return ret; 2344cbf69680SArnaldo Carvalho de Melo } 2345cbf69680SArnaldo Carvalho de Melo 2346aeafcbafSArnaldo Carvalho de Melo size_t machines__fprintf_dsos(struct rb_root *machines, FILE *fp) 2347b0da954aSArnaldo Carvalho de Melo { 2348a1645ce1SZhang, Yanmin struct rb_node *nd; 2349cbf69680SArnaldo Carvalho de Melo size_t ret = 0; 2350a1645ce1SZhang, Yanmin 2351aeafcbafSArnaldo Carvalho de Melo for (nd = rb_first(machines); nd; nd = rb_next(nd)) { 235223346f21SArnaldo Carvalho de Melo struct machine *pos = rb_entry(nd, struct machine, rb_node); 2353cbf69680SArnaldo Carvalho de Melo ret += __dsos__fprintf(&pos->kernel_dsos, fp); 2354cbf69680SArnaldo Carvalho de Melo ret += __dsos__fprintf(&pos->user_dsos, fp); 2355a1645ce1SZhang, Yanmin } 2356cbf69680SArnaldo Carvalho de Melo 2357cbf69680SArnaldo Carvalho de Melo return ret; 2358b0da954aSArnaldo Carvalho de Melo } 2359b0da954aSArnaldo Carvalho de Melo 236088d3d9b7SArnaldo Carvalho de Melo static size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp, 236188d3d9b7SArnaldo Carvalho de Melo bool with_hits) 23629e03eb2dSArnaldo Carvalho de Melo { 23639e03eb2dSArnaldo Carvalho de Melo struct dso *pos; 23649e03eb2dSArnaldo Carvalho de Melo size_t ret = 0; 23659e03eb2dSArnaldo Carvalho de Melo 2366b0da954aSArnaldo Carvalho de Melo list_for_each_entry(pos, head, node) { 236788d3d9b7SArnaldo Carvalho de Melo if (with_hits && !pos->hit) 236888d3d9b7SArnaldo Carvalho de Melo continue; 23699e03eb2dSArnaldo Carvalho de Melo ret += dso__fprintf_buildid(pos, fp); 23709e03eb2dSArnaldo Carvalho de Melo ret += fprintf(fp, " %s\n", pos->long_name); 23719e03eb2dSArnaldo Carvalho de Melo } 23729e03eb2dSArnaldo Carvalho de Melo return ret; 23739e03eb2dSArnaldo Carvalho de Melo } 23749e03eb2dSArnaldo Carvalho de Melo 2375aeafcbafSArnaldo Carvalho de Melo size_t machine__fprintf_dsos_buildid(struct machine *machine, FILE *fp, 2376aeafcbafSArnaldo Carvalho de Melo bool with_hits) 2377f869097eSArnaldo Carvalho de Melo { 2378aeafcbafSArnaldo Carvalho de Melo return __dsos__fprintf_buildid(&machine->kernel_dsos, fp, with_hits) + 2379aeafcbafSArnaldo Carvalho de Melo __dsos__fprintf_buildid(&machine->user_dsos, fp, with_hits); 2380f869097eSArnaldo Carvalho de Melo } 2381f869097eSArnaldo Carvalho de Melo 2382aeafcbafSArnaldo Carvalho de Melo size_t machines__fprintf_dsos_buildid(struct rb_root *machines, 2383aeafcbafSArnaldo Carvalho de Melo FILE *fp, bool with_hits) 2384b0da954aSArnaldo Carvalho de Melo { 2385a1645ce1SZhang, Yanmin struct rb_node *nd; 2386a1645ce1SZhang, Yanmin size_t ret = 0; 2387a1645ce1SZhang, Yanmin 2388aeafcbafSArnaldo Carvalho de Melo for (nd = rb_first(machines); nd; nd = rb_next(nd)) { 238923346f21SArnaldo Carvalho de Melo struct machine *pos = rb_entry(nd, struct machine, rb_node); 2390f869097eSArnaldo Carvalho de Melo ret += machine__fprintf_dsos_buildid(pos, fp, with_hits); 2391a1645ce1SZhang, Yanmin } 2392a1645ce1SZhang, Yanmin return ret; 2393b0da954aSArnaldo Carvalho de Melo } 2394b0da954aSArnaldo Carvalho de Melo 2395f57b05edSJiri Olsa static struct dso* 2396f57b05edSJiri Olsa dso__kernel_findnew(struct machine *machine, const char *name, 2397f57b05edSJiri Olsa const char *short_name, int dso_type) 2398fd1d908cSArnaldo Carvalho de Melo { 2399f57b05edSJiri Olsa /* 2400f57b05edSJiri Olsa * The kernel dso could be created by build_id processing. 2401f57b05edSJiri Olsa */ 2402f57b05edSJiri Olsa struct dso *dso = __dsos__findnew(&machine->kernel_dsos, name); 2403fd1d908cSArnaldo Carvalho de Melo 2404f57b05edSJiri Olsa /* 2405f57b05edSJiri Olsa * We need to run this in all cases, since during the build_id 2406f57b05edSJiri Olsa * processing we had no idea this was the kernel dso. 2407f57b05edSJiri Olsa */ 2408aeafcbafSArnaldo Carvalho de Melo if (dso != NULL) { 2409f57b05edSJiri Olsa dso__set_short_name(dso, short_name); 2410f57b05edSJiri Olsa dso->kernel = dso_type; 2411a1645ce1SZhang, Yanmin } 2412a1645ce1SZhang, Yanmin 2413aeafcbafSArnaldo Carvalho de Melo return dso; 2414a1645ce1SZhang, Yanmin } 2415a1645ce1SZhang, Yanmin 2416aeafcbafSArnaldo Carvalho de Melo void dso__read_running_kernel_build_id(struct dso *dso, struct machine *machine) 2417a1645ce1SZhang, Yanmin { 2418a1645ce1SZhang, Yanmin char path[PATH_MAX]; 2419a1645ce1SZhang, Yanmin 242023346f21SArnaldo Carvalho de Melo if (machine__is_default_guest(machine)) 2421a1645ce1SZhang, Yanmin return; 242223346f21SArnaldo Carvalho de Melo sprintf(path, "%s/sys/kernel/notes", machine->root_dir); 2423aeafcbafSArnaldo Carvalho de Melo if (sysfs__read_build_id(path, dso->build_id, 2424aeafcbafSArnaldo Carvalho de Melo sizeof(dso->build_id)) == 0) 2425aeafcbafSArnaldo Carvalho de Melo dso->has_build_id = true; 2426fd1d908cSArnaldo Carvalho de Melo } 2427fd1d908cSArnaldo Carvalho de Melo 2428f57b05edSJiri Olsa static struct dso *machine__get_kernel(struct machine *machine) 2429cd84c2acSFrederic Weisbecker { 2430a1645ce1SZhang, Yanmin const char *vmlinux_name = NULL; 2431a1645ce1SZhang, Yanmin struct dso *kernel; 2432cd84c2acSFrederic Weisbecker 2433aeafcbafSArnaldo Carvalho de Melo if (machine__is_host(machine)) { 2434a1645ce1SZhang, Yanmin vmlinux_name = symbol_conf.vmlinux_name; 2435f57b05edSJiri Olsa if (!vmlinux_name) 2436f57b05edSJiri Olsa vmlinux_name = "[kernel.kallsyms]"; 2437f57b05edSJiri Olsa 2438f57b05edSJiri Olsa kernel = dso__kernel_findnew(machine, vmlinux_name, 2439f57b05edSJiri Olsa "[kernel]", 2440f57b05edSJiri Olsa DSO_TYPE_KERNEL); 2441a1645ce1SZhang, Yanmin } else { 2442f57b05edSJiri Olsa char bf[PATH_MAX]; 2443f57b05edSJiri Olsa 2444aeafcbafSArnaldo Carvalho de Melo if (machine__is_default_guest(machine)) 2445a1645ce1SZhang, Yanmin vmlinux_name = symbol_conf.default_guest_vmlinux_name; 2446f57b05edSJiri Olsa if (!vmlinux_name) 2447f57b05edSJiri Olsa vmlinux_name = machine__mmap_name(machine, bf, 2448f57b05edSJiri Olsa sizeof(bf)); 2449f57b05edSJiri Olsa 2450f57b05edSJiri Olsa kernel = dso__kernel_findnew(machine, vmlinux_name, 2451f57b05edSJiri Olsa "[guest.kernel]", 2452f57b05edSJiri Olsa DSO_TYPE_GUEST_KERNEL); 24538d92c02aSArnaldo Carvalho de Melo } 2454cd84c2acSFrederic Weisbecker 2455f57b05edSJiri Olsa if (kernel != NULL && (!kernel->has_build_id)) 2456aeafcbafSArnaldo Carvalho de Melo dso__read_running_kernel_build_id(kernel, machine); 2457f57b05edSJiri Olsa 2458f1dfa0b1SArnaldo Carvalho de Melo return kernel; 2459f1dfa0b1SArnaldo Carvalho de Melo } 2460f1dfa0b1SArnaldo Carvalho de Melo 2461d214afbdSMing Lei struct process_args { 2462d214afbdSMing Lei u64 start; 2463d214afbdSMing Lei }; 2464d214afbdSMing Lei 2465d214afbdSMing Lei static int symbol__in_kernel(void *arg, const char *name, 24663b01a413SArnaldo Carvalho de Melo char type __used, u64 start, u64 end __used) 2467d214afbdSMing Lei { 2468d214afbdSMing Lei struct process_args *args = arg; 2469d214afbdSMing Lei 2470d214afbdSMing Lei if (strchr(name, '[')) 2471d214afbdSMing Lei return 0; 2472d214afbdSMing Lei 2473d214afbdSMing Lei args->start = start; 2474d214afbdSMing Lei return 1; 2475d214afbdSMing Lei } 2476d214afbdSMing Lei 2477d214afbdSMing Lei /* Figure out the start address of kernel map from /proc/kallsyms */ 2478d214afbdSMing Lei static u64 machine__get_kernel_start_addr(struct machine *machine) 2479d214afbdSMing Lei { 2480d214afbdSMing Lei const char *filename; 2481d214afbdSMing Lei char path[PATH_MAX]; 2482d214afbdSMing Lei struct process_args args; 2483d214afbdSMing Lei 2484d214afbdSMing Lei if (machine__is_host(machine)) { 2485d214afbdSMing Lei filename = "/proc/kallsyms"; 2486d214afbdSMing Lei } else { 2487d214afbdSMing Lei if (machine__is_default_guest(machine)) 2488d214afbdSMing Lei filename = (char *)symbol_conf.default_guest_kallsyms; 2489d214afbdSMing Lei else { 2490d214afbdSMing Lei sprintf(path, "%s/proc/kallsyms", machine->root_dir); 2491d214afbdSMing Lei filename = path; 2492d214afbdSMing Lei } 2493d214afbdSMing Lei } 2494d214afbdSMing Lei 2495ec80fde7SArnaldo Carvalho de Melo if (symbol__restricted_filename(filename, "/proc/kallsyms")) 2496ec80fde7SArnaldo Carvalho de Melo return 0; 2497ec80fde7SArnaldo Carvalho de Melo 2498d214afbdSMing Lei if (kallsyms__parse(filename, &args, symbol__in_kernel) <= 0) 2499d214afbdSMing Lei return 0; 2500d214afbdSMing Lei 2501d214afbdSMing Lei return args.start; 2502d214afbdSMing Lei } 2503d214afbdSMing Lei 2504aeafcbafSArnaldo Carvalho de Melo int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel) 2505f1dfa0b1SArnaldo Carvalho de Melo { 2506de176489SArnaldo Carvalho de Melo enum map_type type; 2507aeafcbafSArnaldo Carvalho de Melo u64 start = machine__get_kernel_start_addr(machine); 2508f1dfa0b1SArnaldo Carvalho de Melo 2509de176489SArnaldo Carvalho de Melo for (type = 0; type < MAP__NR_TYPES; ++type) { 25109de89fe7SArnaldo Carvalho de Melo struct kmap *kmap; 25119de89fe7SArnaldo Carvalho de Melo 2512aeafcbafSArnaldo Carvalho de Melo machine->vmlinux_maps[type] = map__new2(start, kernel, type); 2513aeafcbafSArnaldo Carvalho de Melo if (machine->vmlinux_maps[type] == NULL) 2514f1dfa0b1SArnaldo Carvalho de Melo return -1; 2515f1dfa0b1SArnaldo Carvalho de Melo 2516aeafcbafSArnaldo Carvalho de Melo machine->vmlinux_maps[type]->map_ip = 2517aeafcbafSArnaldo Carvalho de Melo machine->vmlinux_maps[type]->unmap_ip = 2518aeafcbafSArnaldo Carvalho de Melo identity__map_ip; 2519aeafcbafSArnaldo Carvalho de Melo kmap = map__kmap(machine->vmlinux_maps[type]); 2520aeafcbafSArnaldo Carvalho de Melo kmap->kmaps = &machine->kmaps; 2521aeafcbafSArnaldo Carvalho de Melo map_groups__insert(&machine->kmaps, 2522aeafcbafSArnaldo Carvalho de Melo machine->vmlinux_maps[type]); 2523f1dfa0b1SArnaldo Carvalho de Melo } 2524f1dfa0b1SArnaldo Carvalho de Melo 2525f1dfa0b1SArnaldo Carvalho de Melo return 0; 25262446042cSArnaldo Carvalho de Melo } 25272446042cSArnaldo Carvalho de Melo 2528aeafcbafSArnaldo Carvalho de Melo void machine__destroy_kernel_maps(struct machine *machine) 2529076c6e45SArnaldo Carvalho de Melo { 2530076c6e45SArnaldo Carvalho de Melo enum map_type type; 2531076c6e45SArnaldo Carvalho de Melo 2532076c6e45SArnaldo Carvalho de Melo for (type = 0; type < MAP__NR_TYPES; ++type) { 2533076c6e45SArnaldo Carvalho de Melo struct kmap *kmap; 2534076c6e45SArnaldo Carvalho de Melo 2535aeafcbafSArnaldo Carvalho de Melo if (machine->vmlinux_maps[type] == NULL) 2536076c6e45SArnaldo Carvalho de Melo continue; 2537076c6e45SArnaldo Carvalho de Melo 2538aeafcbafSArnaldo Carvalho de Melo kmap = map__kmap(machine->vmlinux_maps[type]); 2539aeafcbafSArnaldo Carvalho de Melo map_groups__remove(&machine->kmaps, 2540aeafcbafSArnaldo Carvalho de Melo machine->vmlinux_maps[type]); 2541076c6e45SArnaldo Carvalho de Melo if (kmap->ref_reloc_sym) { 2542076c6e45SArnaldo Carvalho de Melo /* 2543076c6e45SArnaldo Carvalho de Melo * ref_reloc_sym is shared among all maps, so free just 2544076c6e45SArnaldo Carvalho de Melo * on one of them. 2545076c6e45SArnaldo Carvalho de Melo */ 2546076c6e45SArnaldo Carvalho de Melo if (type == MAP__FUNCTION) { 2547076c6e45SArnaldo Carvalho de Melo free((char *)kmap->ref_reloc_sym->name); 2548076c6e45SArnaldo Carvalho de Melo kmap->ref_reloc_sym->name = NULL; 2549076c6e45SArnaldo Carvalho de Melo free(kmap->ref_reloc_sym); 2550076c6e45SArnaldo Carvalho de Melo } 2551076c6e45SArnaldo Carvalho de Melo kmap->ref_reloc_sym = NULL; 2552076c6e45SArnaldo Carvalho de Melo } 2553076c6e45SArnaldo Carvalho de Melo 2554aeafcbafSArnaldo Carvalho de Melo map__delete(machine->vmlinux_maps[type]); 2555aeafcbafSArnaldo Carvalho de Melo machine->vmlinux_maps[type] = NULL; 2556076c6e45SArnaldo Carvalho de Melo } 2557076c6e45SArnaldo Carvalho de Melo } 2558076c6e45SArnaldo Carvalho de Melo 2559aeafcbafSArnaldo Carvalho de Melo int machine__create_kernel_maps(struct machine *machine) 25605c0541d5SArnaldo Carvalho de Melo { 2561f57b05edSJiri Olsa struct dso *kernel = machine__get_kernel(machine); 25625c0541d5SArnaldo Carvalho de Melo 25635c0541d5SArnaldo Carvalho de Melo if (kernel == NULL || 2564aeafcbafSArnaldo Carvalho de Melo __machine__create_kernel_maps(machine, kernel) < 0) 25655c0541d5SArnaldo Carvalho de Melo return -1; 25665c0541d5SArnaldo Carvalho de Melo 2567*f51304d3SDavid Ahern if (symbol_conf.use_modules && machine__create_modules(machine) < 0) { 2568*f51304d3SDavid Ahern if (machine__is_host(machine)) 2569*f51304d3SDavid Ahern pr_debug("Problems creating module maps, " 2570*f51304d3SDavid Ahern "continuing anyway...\n"); 2571*f51304d3SDavid Ahern else 2572*f51304d3SDavid Ahern pr_debug("Problems creating module maps for guest %d, " 2573*f51304d3SDavid Ahern "continuing anyway...\n", machine->pid); 2574*f51304d3SDavid Ahern } 2575*f51304d3SDavid Ahern 25765c0541d5SArnaldo Carvalho de Melo /* 25775c0541d5SArnaldo Carvalho de Melo * Now that we have all the maps created, just set the ->end of them: 25785c0541d5SArnaldo Carvalho de Melo */ 2579aeafcbafSArnaldo Carvalho de Melo map_groups__fixup_end(&machine->kmaps); 25805c0541d5SArnaldo Carvalho de Melo return 0; 25815c0541d5SArnaldo Carvalho de Melo } 25825c0541d5SArnaldo Carvalho de Melo 2583cc612d81SArnaldo Carvalho de Melo static void vmlinux_path__exit(void) 25842446042cSArnaldo Carvalho de Melo { 2585cc612d81SArnaldo Carvalho de Melo while (--vmlinux_path__nr_entries >= 0) { 2586cc612d81SArnaldo Carvalho de Melo free(vmlinux_path[vmlinux_path__nr_entries]); 2587cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = NULL; 2588cc612d81SArnaldo Carvalho de Melo } 2589cc612d81SArnaldo Carvalho de Melo 2590cc612d81SArnaldo Carvalho de Melo free(vmlinux_path); 2591cc612d81SArnaldo Carvalho de Melo vmlinux_path = NULL; 2592cc612d81SArnaldo Carvalho de Melo } 2593cc612d81SArnaldo Carvalho de Melo 2594cc612d81SArnaldo Carvalho de Melo static int vmlinux_path__init(void) 2595cc612d81SArnaldo Carvalho de Melo { 2596cc612d81SArnaldo Carvalho de Melo struct utsname uts; 2597cc612d81SArnaldo Carvalho de Melo char bf[PATH_MAX]; 2598cc612d81SArnaldo Carvalho de Melo 2599cc612d81SArnaldo Carvalho de Melo vmlinux_path = malloc(sizeof(char *) * 5); 2600cc612d81SArnaldo Carvalho de Melo if (vmlinux_path == NULL) 2601cc612d81SArnaldo Carvalho de Melo return -1; 2602cc612d81SArnaldo Carvalho de Melo 2603cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup("vmlinux"); 2604cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 2605cc612d81SArnaldo Carvalho de Melo goto out_fail; 2606cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 2607cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup("/boot/vmlinux"); 2608cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 2609cc612d81SArnaldo Carvalho de Melo goto out_fail; 2610cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 2611ec5761eaSDavid Ahern 2612ec5761eaSDavid Ahern /* only try running kernel version if no symfs was given */ 2613ec5761eaSDavid Ahern if (symbol_conf.symfs[0] != 0) 2614ec5761eaSDavid Ahern return 0; 2615ec5761eaSDavid Ahern 2616ec5761eaSDavid Ahern if (uname(&uts) < 0) 2617ec5761eaSDavid Ahern return -1; 2618ec5761eaSDavid Ahern 2619cc612d81SArnaldo Carvalho de Melo snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", uts.release); 2620cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); 2621cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 2622cc612d81SArnaldo Carvalho de Melo goto out_fail; 2623cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 2624cc612d81SArnaldo Carvalho de Melo snprintf(bf, sizeof(bf), "/lib/modules/%s/build/vmlinux", uts.release); 2625cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); 2626cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 2627cc612d81SArnaldo Carvalho de Melo goto out_fail; 2628cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 2629cc612d81SArnaldo Carvalho de Melo snprintf(bf, sizeof(bf), "/usr/lib/debug/lib/modules/%s/vmlinux", 2630cc612d81SArnaldo Carvalho de Melo uts.release); 2631cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); 2632cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 2633cc612d81SArnaldo Carvalho de Melo goto out_fail; 2634cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 2635cc612d81SArnaldo Carvalho de Melo 2636cc612d81SArnaldo Carvalho de Melo return 0; 2637cc612d81SArnaldo Carvalho de Melo 2638cc612d81SArnaldo Carvalho de Melo out_fail: 2639cc612d81SArnaldo Carvalho de Melo vmlinux_path__exit(); 2640cc612d81SArnaldo Carvalho de Melo return -1; 2641cc612d81SArnaldo Carvalho de Melo } 2642cc612d81SArnaldo Carvalho de Melo 2643aeafcbafSArnaldo Carvalho de Melo size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp) 2644b0a9ab62SArnaldo Carvalho de Melo { 2645b0a9ab62SArnaldo Carvalho de Melo int i; 2646b0a9ab62SArnaldo Carvalho de Melo size_t printed = 0; 2647aeafcbafSArnaldo Carvalho de Melo struct dso *kdso = machine->vmlinux_maps[MAP__FUNCTION]->dso; 26485ad90e4eSArnaldo Carvalho de Melo 26495ad90e4eSArnaldo Carvalho de Melo if (kdso->has_build_id) { 26505ad90e4eSArnaldo Carvalho de Melo char filename[PATH_MAX]; 26515ad90e4eSArnaldo Carvalho de Melo if (dso__build_id_filename(kdso, filename, sizeof(filename))) 26525ad90e4eSArnaldo Carvalho de Melo printed += fprintf(fp, "[0] %s\n", filename); 26535ad90e4eSArnaldo Carvalho de Melo } 2654b0a9ab62SArnaldo Carvalho de Melo 2655b0a9ab62SArnaldo Carvalho de Melo for (i = 0; i < vmlinux_path__nr_entries; ++i) 26565ad90e4eSArnaldo Carvalho de Melo printed += fprintf(fp, "[%d] %s\n", 26575ad90e4eSArnaldo Carvalho de Melo i + kdso->has_build_id, vmlinux_path[i]); 2658b0a9ab62SArnaldo Carvalho de Melo 2659b0a9ab62SArnaldo Carvalho de Melo return printed; 2660b0a9ab62SArnaldo Carvalho de Melo } 2661b0a9ab62SArnaldo Carvalho de Melo 2662655000e7SArnaldo Carvalho de Melo static int setup_list(struct strlist **list, const char *list_str, 2663655000e7SArnaldo Carvalho de Melo const char *list_name) 2664655000e7SArnaldo Carvalho de Melo { 2665655000e7SArnaldo Carvalho de Melo if (list_str == NULL) 2666655000e7SArnaldo Carvalho de Melo return 0; 2667655000e7SArnaldo Carvalho de Melo 2668655000e7SArnaldo Carvalho de Melo *list = strlist__new(true, list_str); 2669655000e7SArnaldo Carvalho de Melo if (!*list) { 2670655000e7SArnaldo Carvalho de Melo pr_err("problems parsing %s list\n", list_name); 2671655000e7SArnaldo Carvalho de Melo return -1; 2672655000e7SArnaldo Carvalho de Melo } 2673655000e7SArnaldo Carvalho de Melo return 0; 2674655000e7SArnaldo Carvalho de Melo } 2675655000e7SArnaldo Carvalho de Melo 2676ec80fde7SArnaldo Carvalho de Melo static bool symbol__read_kptr_restrict(void) 2677ec80fde7SArnaldo Carvalho de Melo { 2678ec80fde7SArnaldo Carvalho de Melo bool value = false; 2679ec80fde7SArnaldo Carvalho de Melo 2680ec80fde7SArnaldo Carvalho de Melo if (geteuid() != 0) { 2681ec80fde7SArnaldo Carvalho de Melo FILE *fp = fopen("/proc/sys/kernel/kptr_restrict", "r"); 2682ec80fde7SArnaldo Carvalho de Melo if (fp != NULL) { 2683ec80fde7SArnaldo Carvalho de Melo char line[8]; 2684ec80fde7SArnaldo Carvalho de Melo 2685ec80fde7SArnaldo Carvalho de Melo if (fgets(line, sizeof(line), fp) != NULL) 2686ec80fde7SArnaldo Carvalho de Melo value = atoi(line) != 0; 2687ec80fde7SArnaldo Carvalho de Melo 2688ec80fde7SArnaldo Carvalho de Melo fclose(fp); 2689ec80fde7SArnaldo Carvalho de Melo } 2690ec80fde7SArnaldo Carvalho de Melo } 2691ec80fde7SArnaldo Carvalho de Melo 2692ec80fde7SArnaldo Carvalho de Melo return value; 2693ec80fde7SArnaldo Carvalho de Melo } 2694ec80fde7SArnaldo Carvalho de Melo 269575be6cf4SArnaldo Carvalho de Melo int symbol__init(void) 2696cc612d81SArnaldo Carvalho de Melo { 2697ec5761eaSDavid Ahern const char *symfs; 2698ec5761eaSDavid Ahern 269985e00b55SJovi Zhang if (symbol_conf.initialized) 270085e00b55SJovi Zhang return 0; 270185e00b55SJovi Zhang 27024d439517SDavid S. Miller symbol_conf.priv_size = ALIGN(symbol_conf.priv_size, sizeof(u64)); 27034d439517SDavid S. Miller 270495011c60SArnaldo Carvalho de Melo elf_version(EV_CURRENT); 270575be6cf4SArnaldo Carvalho de Melo if (symbol_conf.sort_by_name) 270675be6cf4SArnaldo Carvalho de Melo symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) - 270779406cd7SArnaldo Carvalho de Melo sizeof(struct symbol)); 2708b32d133aSArnaldo Carvalho de Melo 270975be6cf4SArnaldo Carvalho de Melo if (symbol_conf.try_vmlinux_path && vmlinux_path__init() < 0) 2710cc612d81SArnaldo Carvalho de Melo return -1; 2711cc612d81SArnaldo Carvalho de Melo 2712c410a338SArnaldo Carvalho de Melo if (symbol_conf.field_sep && *symbol_conf.field_sep == '.') { 2713c410a338SArnaldo Carvalho de Melo pr_err("'.' is the only non valid --field-separator argument\n"); 2714c410a338SArnaldo Carvalho de Melo return -1; 2715c410a338SArnaldo Carvalho de Melo } 2716c410a338SArnaldo Carvalho de Melo 2717655000e7SArnaldo Carvalho de Melo if (setup_list(&symbol_conf.dso_list, 2718655000e7SArnaldo Carvalho de Melo symbol_conf.dso_list_str, "dso") < 0) 2719655000e7SArnaldo Carvalho de Melo return -1; 2720655000e7SArnaldo Carvalho de Melo 2721655000e7SArnaldo Carvalho de Melo if (setup_list(&symbol_conf.comm_list, 2722655000e7SArnaldo Carvalho de Melo symbol_conf.comm_list_str, "comm") < 0) 2723655000e7SArnaldo Carvalho de Melo goto out_free_dso_list; 2724655000e7SArnaldo Carvalho de Melo 2725655000e7SArnaldo Carvalho de Melo if (setup_list(&symbol_conf.sym_list, 2726655000e7SArnaldo Carvalho de Melo symbol_conf.sym_list_str, "symbol") < 0) 2727655000e7SArnaldo Carvalho de Melo goto out_free_comm_list; 2728655000e7SArnaldo Carvalho de Melo 2729ec5761eaSDavid Ahern /* 2730ec5761eaSDavid Ahern * A path to symbols of "/" is identical to "" 2731ec5761eaSDavid Ahern * reset here for simplicity. 2732ec5761eaSDavid Ahern */ 2733ec5761eaSDavid Ahern symfs = realpath(symbol_conf.symfs, NULL); 2734ec5761eaSDavid Ahern if (symfs == NULL) 2735ec5761eaSDavid Ahern symfs = symbol_conf.symfs; 2736ec5761eaSDavid Ahern if (strcmp(symfs, "/") == 0) 2737ec5761eaSDavid Ahern symbol_conf.symfs = ""; 2738ec5761eaSDavid Ahern if (symfs != symbol_conf.symfs) 2739ec5761eaSDavid Ahern free((void *)symfs); 2740ec5761eaSDavid Ahern 2741ec80fde7SArnaldo Carvalho de Melo symbol_conf.kptr_restrict = symbol__read_kptr_restrict(); 2742ec80fde7SArnaldo Carvalho de Melo 274385e00b55SJovi Zhang symbol_conf.initialized = true; 27444aa65636SArnaldo Carvalho de Melo return 0; 2745655000e7SArnaldo Carvalho de Melo 2746655000e7SArnaldo Carvalho de Melo out_free_comm_list: 2747655000e7SArnaldo Carvalho de Melo strlist__delete(symbol_conf.comm_list); 2748d74c896bSNamhyung Kim out_free_dso_list: 2749d74c896bSNamhyung Kim strlist__delete(symbol_conf.dso_list); 2750655000e7SArnaldo Carvalho de Melo return -1; 2751cc612d81SArnaldo Carvalho de Melo } 2752cc612d81SArnaldo Carvalho de Melo 2753d65a458bSArnaldo Carvalho de Melo void symbol__exit(void) 2754d65a458bSArnaldo Carvalho de Melo { 275585e00b55SJovi Zhang if (!symbol_conf.initialized) 275685e00b55SJovi Zhang return; 2757d65a458bSArnaldo Carvalho de Melo strlist__delete(symbol_conf.sym_list); 2758d65a458bSArnaldo Carvalho de Melo strlist__delete(symbol_conf.dso_list); 2759d65a458bSArnaldo Carvalho de Melo strlist__delete(symbol_conf.comm_list); 2760d65a458bSArnaldo Carvalho de Melo vmlinux_path__exit(); 2761d65a458bSArnaldo Carvalho de Melo symbol_conf.sym_list = symbol_conf.dso_list = symbol_conf.comm_list = NULL; 276285e00b55SJovi Zhang symbol_conf.initialized = false; 2763d65a458bSArnaldo Carvalho de Melo } 2764d65a458bSArnaldo Carvalho de Melo 2765aeafcbafSArnaldo Carvalho de Melo int machines__create_kernel_maps(struct rb_root *machines, pid_t pid) 27664aa65636SArnaldo Carvalho de Melo { 2767aeafcbafSArnaldo Carvalho de Melo struct machine *machine = machines__findnew(machines, pid); 27689de89fe7SArnaldo Carvalho de Melo 276923346f21SArnaldo Carvalho de Melo if (machine == NULL) 2770a1645ce1SZhang, Yanmin return -1; 27714aa65636SArnaldo Carvalho de Melo 27725c0541d5SArnaldo Carvalho de Melo return machine__create_kernel_maps(machine); 2773cd84c2acSFrederic Weisbecker } 27745aab621bSArnaldo Carvalho de Melo 27755aab621bSArnaldo Carvalho de Melo static int hex(char ch) 27765aab621bSArnaldo Carvalho de Melo { 27775aab621bSArnaldo Carvalho de Melo if ((ch >= '0') && (ch <= '9')) 27785aab621bSArnaldo Carvalho de Melo return ch - '0'; 27795aab621bSArnaldo Carvalho de Melo if ((ch >= 'a') && (ch <= 'f')) 27805aab621bSArnaldo Carvalho de Melo return ch - 'a' + 10; 27815aab621bSArnaldo Carvalho de Melo if ((ch >= 'A') && (ch <= 'F')) 27825aab621bSArnaldo Carvalho de Melo return ch - 'A' + 10; 27835aab621bSArnaldo Carvalho de Melo return -1; 27845aab621bSArnaldo Carvalho de Melo } 27855aab621bSArnaldo Carvalho de Melo 27865aab621bSArnaldo Carvalho de Melo /* 27875aab621bSArnaldo Carvalho de Melo * While we find nice hex chars, build a long_val. 27885aab621bSArnaldo Carvalho de Melo * Return number of chars processed. 27895aab621bSArnaldo Carvalho de Melo */ 27905aab621bSArnaldo Carvalho de Melo int hex2u64(const char *ptr, u64 *long_val) 27915aab621bSArnaldo Carvalho de Melo { 27925aab621bSArnaldo Carvalho de Melo const char *p = ptr; 27935aab621bSArnaldo Carvalho de Melo *long_val = 0; 27945aab621bSArnaldo Carvalho de Melo 27955aab621bSArnaldo Carvalho de Melo while (*p) { 27965aab621bSArnaldo Carvalho de Melo const int hex_val = hex(*p); 27975aab621bSArnaldo Carvalho de Melo 27985aab621bSArnaldo Carvalho de Melo if (hex_val < 0) 27995aab621bSArnaldo Carvalho de Melo break; 28005aab621bSArnaldo Carvalho de Melo 28015aab621bSArnaldo Carvalho de Melo *long_val = (*long_val << 4) | hex_val; 28025aab621bSArnaldo Carvalho de Melo p++; 28035aab621bSArnaldo Carvalho de Melo } 28045aab621bSArnaldo Carvalho de Melo 28055aab621bSArnaldo Carvalho de Melo return p - ptr; 28065aab621bSArnaldo Carvalho de Melo } 28075aab621bSArnaldo Carvalho de Melo 28085aab621bSArnaldo Carvalho de Melo char *strxfrchar(char *s, char from, char to) 28095aab621bSArnaldo Carvalho de Melo { 28105aab621bSArnaldo Carvalho de Melo char *p = s; 28115aab621bSArnaldo Carvalho de Melo 28125aab621bSArnaldo Carvalho de Melo while ((p = strchr(p, from)) != NULL) 28135aab621bSArnaldo Carvalho de Melo *p++ = to; 28145aab621bSArnaldo Carvalho de Melo 28155aab621bSArnaldo Carvalho de Melo return s; 28165aab621bSArnaldo Carvalho de Melo } 2817a1645ce1SZhang, Yanmin 2818aeafcbafSArnaldo Carvalho de Melo int machines__create_guest_kernel_maps(struct rb_root *machines) 2819a1645ce1SZhang, Yanmin { 2820a1645ce1SZhang, Yanmin int ret = 0; 2821a1645ce1SZhang, Yanmin struct dirent **namelist = NULL; 2822a1645ce1SZhang, Yanmin int i, items = 0; 2823a1645ce1SZhang, Yanmin char path[PATH_MAX]; 2824a1645ce1SZhang, Yanmin pid_t pid; 2825a1645ce1SZhang, Yanmin 2826a1645ce1SZhang, Yanmin if (symbol_conf.default_guest_vmlinux_name || 2827a1645ce1SZhang, Yanmin symbol_conf.default_guest_modules || 2828a1645ce1SZhang, Yanmin symbol_conf.default_guest_kallsyms) { 2829aeafcbafSArnaldo Carvalho de Melo machines__create_kernel_maps(machines, DEFAULT_GUEST_KERNEL_ID); 2830a1645ce1SZhang, Yanmin } 2831a1645ce1SZhang, Yanmin 2832a1645ce1SZhang, Yanmin if (symbol_conf.guestmount) { 2833a1645ce1SZhang, Yanmin items = scandir(symbol_conf.guestmount, &namelist, NULL, NULL); 2834a1645ce1SZhang, Yanmin if (items <= 0) 2835a1645ce1SZhang, Yanmin return -ENOENT; 2836a1645ce1SZhang, Yanmin for (i = 0; i < items; i++) { 2837a1645ce1SZhang, Yanmin if (!isdigit(namelist[i]->d_name[0])) { 2838a1645ce1SZhang, Yanmin /* Filter out . and .. */ 2839a1645ce1SZhang, Yanmin continue; 2840a1645ce1SZhang, Yanmin } 2841a1645ce1SZhang, Yanmin pid = atoi(namelist[i]->d_name); 2842a1645ce1SZhang, Yanmin sprintf(path, "%s/%s/proc/kallsyms", 2843a1645ce1SZhang, Yanmin symbol_conf.guestmount, 2844a1645ce1SZhang, Yanmin namelist[i]->d_name); 2845a1645ce1SZhang, Yanmin ret = access(path, R_OK); 2846a1645ce1SZhang, Yanmin if (ret) { 2847a1645ce1SZhang, Yanmin pr_debug("Can't access file %s\n", path); 2848a1645ce1SZhang, Yanmin goto failure; 2849a1645ce1SZhang, Yanmin } 2850aeafcbafSArnaldo Carvalho de Melo machines__create_kernel_maps(machines, pid); 2851a1645ce1SZhang, Yanmin } 2852a1645ce1SZhang, Yanmin failure: 2853a1645ce1SZhang, Yanmin free(namelist); 2854a1645ce1SZhang, Yanmin } 2855a1645ce1SZhang, Yanmin 2856a1645ce1SZhang, Yanmin return ret; 2857a1645ce1SZhang, Yanmin } 28585c0541d5SArnaldo Carvalho de Melo 2859aeafcbafSArnaldo Carvalho de Melo void machines__destroy_guest_kernel_maps(struct rb_root *machines) 2860076c6e45SArnaldo Carvalho de Melo { 2861aeafcbafSArnaldo Carvalho de Melo struct rb_node *next = rb_first(machines); 2862076c6e45SArnaldo Carvalho de Melo 2863076c6e45SArnaldo Carvalho de Melo while (next) { 2864076c6e45SArnaldo Carvalho de Melo struct machine *pos = rb_entry(next, struct machine, rb_node); 2865076c6e45SArnaldo Carvalho de Melo 2866076c6e45SArnaldo Carvalho de Melo next = rb_next(&pos->rb_node); 2867aeafcbafSArnaldo Carvalho de Melo rb_erase(&pos->rb_node, machines); 2868076c6e45SArnaldo Carvalho de Melo machine__delete(pos); 2869076c6e45SArnaldo Carvalho de Melo } 2870076c6e45SArnaldo Carvalho de Melo } 2871076c6e45SArnaldo Carvalho de Melo 2872aeafcbafSArnaldo Carvalho de Melo int machine__load_kallsyms(struct machine *machine, const char *filename, 28735c0541d5SArnaldo Carvalho de Melo enum map_type type, symbol_filter_t filter) 28745c0541d5SArnaldo Carvalho de Melo { 2875aeafcbafSArnaldo Carvalho de Melo struct map *map = machine->vmlinux_maps[type]; 28765c0541d5SArnaldo Carvalho de Melo int ret = dso__load_kallsyms(map->dso, filename, map, filter); 28775c0541d5SArnaldo Carvalho de Melo 28785c0541d5SArnaldo Carvalho de Melo if (ret > 0) { 28795c0541d5SArnaldo Carvalho de Melo dso__set_loaded(map->dso, type); 28805c0541d5SArnaldo Carvalho de Melo /* 28815c0541d5SArnaldo Carvalho de Melo * Since /proc/kallsyms will have multiple sessions for the 28825c0541d5SArnaldo Carvalho de Melo * kernel, with modules between them, fixup the end of all 28835c0541d5SArnaldo Carvalho de Melo * sections. 28845c0541d5SArnaldo Carvalho de Melo */ 2885aeafcbafSArnaldo Carvalho de Melo __map_groups__fixup_end(&machine->kmaps, type); 28865c0541d5SArnaldo Carvalho de Melo } 28875c0541d5SArnaldo Carvalho de Melo 28885c0541d5SArnaldo Carvalho de Melo return ret; 28895c0541d5SArnaldo Carvalho de Melo } 28905c0541d5SArnaldo Carvalho de Melo 2891aeafcbafSArnaldo Carvalho de Melo int machine__load_vmlinux_path(struct machine *machine, enum map_type type, 28925c0541d5SArnaldo Carvalho de Melo symbol_filter_t filter) 28935c0541d5SArnaldo Carvalho de Melo { 2894aeafcbafSArnaldo Carvalho de Melo struct map *map = machine->vmlinux_maps[type]; 28955c0541d5SArnaldo Carvalho de Melo int ret = dso__load_vmlinux_path(map->dso, map, filter); 28965c0541d5SArnaldo Carvalho de Melo 28975c0541d5SArnaldo Carvalho de Melo if (ret > 0) { 28985c0541d5SArnaldo Carvalho de Melo dso__set_loaded(map->dso, type); 28995c0541d5SArnaldo Carvalho de Melo map__reloc_vmlinux(map); 29005c0541d5SArnaldo Carvalho de Melo } 29015c0541d5SArnaldo Carvalho de Melo 29025c0541d5SArnaldo Carvalho de Melo return ret; 29035c0541d5SArnaldo Carvalho de Melo } 2904225466f1SSrikar Dronamraju 2905225466f1SSrikar Dronamraju struct map *dso__new_map(const char *name) 2906225466f1SSrikar Dronamraju { 2907378474e4SSrikar Dronamraju struct map *map = NULL; 2908225466f1SSrikar Dronamraju struct dso *dso = dso__new(name); 2909378474e4SSrikar Dronamraju 2910378474e4SSrikar Dronamraju if (dso) 2911378474e4SSrikar Dronamraju map = map__new2(0, dso, MAP__FUNCTION); 2912225466f1SSrikar Dronamraju 2913225466f1SSrikar Dronamraju return map; 2914225466f1SSrikar Dronamraju } 2915