15aab621bSArnaldo Carvalho de Melo #define _GNU_SOURCE 25aab621bSArnaldo Carvalho de Melo #include <ctype.h> 35aab621bSArnaldo Carvalho de Melo #include <dirent.h> 45aab621bSArnaldo Carvalho de Melo #include <errno.h> 55aab621bSArnaldo Carvalho de Melo #include <libgen.h> 65aab621bSArnaldo Carvalho de Melo #include <stdlib.h> 75aab621bSArnaldo Carvalho de Melo #include <stdio.h> 85aab621bSArnaldo Carvalho de Melo #include <string.h> 95aab621bSArnaldo Carvalho de Melo #include <sys/types.h> 105aab621bSArnaldo Carvalho de Melo #include <sys/stat.h> 115aab621bSArnaldo Carvalho de Melo #include <sys/param.h> 125aab621bSArnaldo Carvalho de Melo #include <fcntl.h> 135aab621bSArnaldo Carvalho de Melo #include <unistd.h> 149486aa38SArnaldo Carvalho de Melo #include <inttypes.h> 15b36f19d5SArnaldo Carvalho de Melo #include "build-id.h" 168a6c5b26SArnaldo Carvalho de Melo #include "debug.h" 1786470930SIngo Molnar #include "symbol.h" 185aab621bSArnaldo Carvalho de Melo #include "strlist.h" 1986470930SIngo Molnar 2086470930SIngo Molnar #include <libelf.h> 2186470930SIngo Molnar #include <gelf.h> 2286470930SIngo Molnar #include <elf.h> 23f1617b40SArnaldo Carvalho de Melo #include <limits.h> 24439d473bSArnaldo Carvalho de Melo #include <sys/utsname.h> 252cdbc46dSPeter Zijlstra 263b01a413SArnaldo Carvalho de Melo #ifndef KSYM_NAME_LEN 273b01a413SArnaldo Carvalho de Melo #define KSYM_NAME_LEN 128 283b01a413SArnaldo Carvalho de Melo #endif 293b01a413SArnaldo Carvalho de Melo 30c12e15e7SArnaldo Carvalho de Melo #ifndef NT_GNU_BUILD_ID 31c12e15e7SArnaldo Carvalho de Melo #define NT_GNU_BUILD_ID 3 32c12e15e7SArnaldo Carvalho de Melo #endif 33c12e15e7SArnaldo Carvalho de Melo 34aeafcbafSArnaldo Carvalho de Melo static bool dso__build_id_equal(const struct dso *dso, u8 *build_id); 3521916c38SDave Martin static int elf_read_build_id(Elf *elf, void *bf, size_t size); 36b0da954aSArnaldo Carvalho de Melo static void dsos__add(struct list_head *head, struct dso *dso); 373610583cSArnaldo Carvalho de Melo static struct map *map__new2(u64 start, struct dso *dso, enum map_type type); 38aeafcbafSArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *dso, struct map *map, 399de89fe7SArnaldo Carvalho de Melo symbol_filter_t filter); 40aeafcbafSArnaldo Carvalho de Melo static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map, 41a1645ce1SZhang, Yanmin symbol_filter_t filter); 42cc612d81SArnaldo Carvalho de Melo static int vmlinux_path__nr_entries; 43cc612d81SArnaldo Carvalho de Melo static char **vmlinux_path; 44439d473bSArnaldo Carvalho de Melo 4575be6cf4SArnaldo Carvalho de Melo struct symbol_conf symbol_conf = { 46d599db3fSArnaldo Carvalho de Melo .exclude_other = true, 47b32d133aSArnaldo Carvalho de Melo .use_modules = true, 48b32d133aSArnaldo Carvalho de Melo .try_vmlinux_path = true, 49ec5761eaSDavid Ahern .symfs = "", 50b32d133aSArnaldo Carvalho de Melo }; 51b32d133aSArnaldo Carvalho de Melo 52aeafcbafSArnaldo Carvalho de Melo int dso__name_len(const struct dso *dso) 538a6c5b26SArnaldo Carvalho de Melo { 548a6c5b26SArnaldo Carvalho de Melo if (verbose) 55aeafcbafSArnaldo Carvalho de Melo return dso->long_name_len; 568a6c5b26SArnaldo Carvalho de Melo 57aeafcbafSArnaldo Carvalho de Melo return dso->short_name_len; 588a6c5b26SArnaldo Carvalho de Melo } 598a6c5b26SArnaldo Carvalho de Melo 60aeafcbafSArnaldo Carvalho de Melo bool dso__loaded(const struct dso *dso, enum map_type type) 613610583cSArnaldo Carvalho de Melo { 62aeafcbafSArnaldo Carvalho de Melo return dso->loaded & (1 << type); 633610583cSArnaldo Carvalho de Melo } 643610583cSArnaldo Carvalho de Melo 65aeafcbafSArnaldo Carvalho de Melo bool dso__sorted_by_name(const struct dso *dso, enum map_type type) 6679406cd7SArnaldo Carvalho de Melo { 67aeafcbafSArnaldo Carvalho de Melo return dso->sorted_by_name & (1 << type); 6879406cd7SArnaldo Carvalho de Melo } 6979406cd7SArnaldo Carvalho de Melo 70aeafcbafSArnaldo Carvalho de Melo static void dso__set_sorted_by_name(struct dso *dso, enum map_type type) 7179406cd7SArnaldo Carvalho de Melo { 72aeafcbafSArnaldo Carvalho de Melo dso->sorted_by_name |= (1 << type); 7379406cd7SArnaldo Carvalho de Melo } 7479406cd7SArnaldo Carvalho de Melo 7536a3e646SArnaldo Carvalho de Melo bool symbol_type__is_a(char symbol_type, enum map_type map_type) 766893d4eeSArnaldo Carvalho de Melo { 776893d4eeSArnaldo Carvalho de Melo switch (map_type) { 786893d4eeSArnaldo Carvalho de Melo case MAP__FUNCTION: 796893d4eeSArnaldo Carvalho de Melo return symbol_type == 'T' || symbol_type == 'W'; 80f1dfa0b1SArnaldo Carvalho de Melo case MAP__VARIABLE: 81f1dfa0b1SArnaldo Carvalho de Melo return symbol_type == 'D' || symbol_type == 'd'; 826893d4eeSArnaldo Carvalho de Melo default: 836893d4eeSArnaldo Carvalho de Melo return false; 846893d4eeSArnaldo Carvalho de Melo } 856893d4eeSArnaldo Carvalho de Melo } 866893d4eeSArnaldo Carvalho de Melo 87aeafcbafSArnaldo Carvalho de Melo static void symbols__fixup_end(struct rb_root *symbols) 88af427bf5SArnaldo Carvalho de Melo { 89aeafcbafSArnaldo Carvalho de Melo struct rb_node *nd, *prevnd = rb_first(symbols); 902e538c4aSArnaldo Carvalho de Melo struct symbol *curr, *prev; 91af427bf5SArnaldo Carvalho de Melo 92af427bf5SArnaldo Carvalho de Melo if (prevnd == NULL) 93af427bf5SArnaldo Carvalho de Melo return; 94af427bf5SArnaldo Carvalho de Melo 952e538c4aSArnaldo Carvalho de Melo curr = rb_entry(prevnd, struct symbol, rb_node); 962e538c4aSArnaldo Carvalho de Melo 97af427bf5SArnaldo Carvalho de Melo for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) { 982e538c4aSArnaldo Carvalho de Melo prev = curr; 992e538c4aSArnaldo Carvalho de Melo curr = rb_entry(nd, struct symbol, rb_node); 100af427bf5SArnaldo Carvalho de Melo 1013b01a413SArnaldo Carvalho de Melo if (prev->end == prev->start && prev->end != curr->start) 102af427bf5SArnaldo Carvalho de Melo prev->end = curr->start - 1; 103af427bf5SArnaldo Carvalho de Melo } 104af427bf5SArnaldo Carvalho de Melo 1052e538c4aSArnaldo Carvalho de Melo /* Last entry */ 1062e538c4aSArnaldo Carvalho de Melo if (curr->end == curr->start) 1072e538c4aSArnaldo Carvalho de Melo curr->end = roundup(curr->start, 4096); 1082e538c4aSArnaldo Carvalho de Melo } 1092e538c4aSArnaldo Carvalho de Melo 110aeafcbafSArnaldo Carvalho de Melo static void __map_groups__fixup_end(struct map_groups *mg, enum map_type type) 111af427bf5SArnaldo Carvalho de Melo { 112af427bf5SArnaldo Carvalho de Melo struct map *prev, *curr; 113aeafcbafSArnaldo Carvalho de Melo struct rb_node *nd, *prevnd = rb_first(&mg->maps[type]); 114af427bf5SArnaldo Carvalho de Melo 115af427bf5SArnaldo Carvalho de Melo if (prevnd == NULL) 116af427bf5SArnaldo Carvalho de Melo return; 117af427bf5SArnaldo Carvalho de Melo 118af427bf5SArnaldo Carvalho de Melo curr = rb_entry(prevnd, struct map, rb_node); 119af427bf5SArnaldo Carvalho de Melo 120af427bf5SArnaldo Carvalho de Melo for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) { 121af427bf5SArnaldo Carvalho de Melo prev = curr; 122af427bf5SArnaldo Carvalho de Melo curr = rb_entry(nd, struct map, rb_node); 123af427bf5SArnaldo Carvalho de Melo prev->end = curr->start - 1; 1242e538c4aSArnaldo Carvalho de Melo } 12590c83218SArnaldo Carvalho de Melo 12690c83218SArnaldo Carvalho de Melo /* 12790c83218SArnaldo Carvalho de Melo * We still haven't the actual symbols, so guess the 12890c83218SArnaldo Carvalho de Melo * last map final address. 12990c83218SArnaldo Carvalho de Melo */ 1309d1faba5SIan Munsie curr->end = ~0ULL; 131af427bf5SArnaldo Carvalho de Melo } 132af427bf5SArnaldo Carvalho de Melo 133aeafcbafSArnaldo Carvalho de Melo static void map_groups__fixup_end(struct map_groups *mg) 13423ea4a3fSArnaldo Carvalho de Melo { 13523ea4a3fSArnaldo Carvalho de Melo int i; 13623ea4a3fSArnaldo Carvalho de Melo for (i = 0; i < MAP__NR_TYPES; ++i) 137aeafcbafSArnaldo Carvalho de Melo __map_groups__fixup_end(mg, i); 13823ea4a3fSArnaldo Carvalho de Melo } 13923ea4a3fSArnaldo Carvalho de Melo 140c408fedfSArnaldo Carvalho de Melo static struct symbol *symbol__new(u64 start, u64 len, u8 binding, 141c408fedfSArnaldo Carvalho de Melo const char *name) 14286470930SIngo Molnar { 14386470930SIngo Molnar size_t namelen = strlen(name) + 1; 144aeafcbafSArnaldo Carvalho de Melo struct symbol *sym = calloc(1, (symbol_conf.priv_size + 145aeafcbafSArnaldo Carvalho de Melo sizeof(*sym) + namelen)); 146aeafcbafSArnaldo Carvalho de Melo if (sym == NULL) 14786470930SIngo Molnar return NULL; 14886470930SIngo Molnar 14975be6cf4SArnaldo Carvalho de Melo if (symbol_conf.priv_size) 150aeafcbafSArnaldo Carvalho de Melo sym = ((void *)sym) + symbol_conf.priv_size; 15136479484SArnaldo Carvalho de Melo 152aeafcbafSArnaldo Carvalho de Melo sym->start = start; 153aeafcbafSArnaldo Carvalho de Melo sym->end = len ? start + len - 1 : start; 154aeafcbafSArnaldo Carvalho de Melo sym->binding = binding; 155aeafcbafSArnaldo Carvalho de Melo sym->namelen = namelen - 1; 156e4204992SArnaldo Carvalho de Melo 157aeafcbafSArnaldo Carvalho de Melo pr_debug4("%s: %s %#" PRIx64 "-%#" PRIx64 "\n", 158aeafcbafSArnaldo Carvalho de Melo __func__, name, start, sym->end); 159aeafcbafSArnaldo Carvalho de Melo memcpy(sym->name, name, namelen); 160e4204992SArnaldo Carvalho de Melo 161aeafcbafSArnaldo Carvalho de Melo return sym; 16286470930SIngo Molnar } 16386470930SIngo Molnar 164aeafcbafSArnaldo Carvalho de Melo void symbol__delete(struct symbol *sym) 16586470930SIngo Molnar { 166aeafcbafSArnaldo Carvalho de Melo free(((void *)sym) - symbol_conf.priv_size); 16786470930SIngo Molnar } 16886470930SIngo Molnar 169aeafcbafSArnaldo Carvalho de Melo static size_t symbol__fprintf(struct symbol *sym, FILE *fp) 17086470930SIngo Molnar { 1719486aa38SArnaldo Carvalho de Melo return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %c %s\n", 172aeafcbafSArnaldo Carvalho de Melo sym->start, sym->end, 173aeafcbafSArnaldo Carvalho de Melo sym->binding == STB_GLOBAL ? 'g' : 174aeafcbafSArnaldo Carvalho de Melo sym->binding == STB_LOCAL ? 'l' : 'w', 175aeafcbafSArnaldo Carvalho de Melo sym->name); 17686470930SIngo Molnar } 17786470930SIngo Molnar 178aeafcbafSArnaldo Carvalho de Melo void dso__set_long_name(struct dso *dso, char *name) 179cfc10d3bSArnaldo Carvalho de Melo { 180ef6ae724SArnaldo Carvalho de Melo if (name == NULL) 181ef6ae724SArnaldo Carvalho de Melo return; 182aeafcbafSArnaldo Carvalho de Melo dso->long_name = name; 183aeafcbafSArnaldo Carvalho de Melo dso->long_name_len = strlen(name); 184cfc10d3bSArnaldo Carvalho de Melo } 185cfc10d3bSArnaldo Carvalho de Melo 186aeafcbafSArnaldo Carvalho de Melo static void dso__set_short_name(struct dso *dso, const char *name) 187b63be8d7SArnaldo Carvalho de Melo { 188b63be8d7SArnaldo Carvalho de Melo if (name == NULL) 189b63be8d7SArnaldo Carvalho de Melo return; 190aeafcbafSArnaldo Carvalho de Melo dso->short_name = name; 191aeafcbafSArnaldo Carvalho de Melo dso->short_name_len = strlen(name); 192b63be8d7SArnaldo Carvalho de Melo } 193b63be8d7SArnaldo Carvalho de Melo 194aeafcbafSArnaldo Carvalho de Melo static void dso__set_basename(struct dso *dso) 195cfc10d3bSArnaldo Carvalho de Melo { 196aeafcbafSArnaldo Carvalho de Melo dso__set_short_name(dso, basename(dso->long_name)); 197cfc10d3bSArnaldo Carvalho de Melo } 198cfc10d3bSArnaldo Carvalho de Melo 19900a192b3SArnaldo Carvalho de Melo struct dso *dso__new(const char *name) 20086470930SIngo Molnar { 201aeafcbafSArnaldo Carvalho de Melo struct dso *dso = calloc(1, sizeof(*dso) + strlen(name) + 1); 20286470930SIngo Molnar 203aeafcbafSArnaldo Carvalho de Melo if (dso != NULL) { 2046a4694a4SArnaldo Carvalho de Melo int i; 205aeafcbafSArnaldo Carvalho de Melo strcpy(dso->name, name); 206aeafcbafSArnaldo Carvalho de Melo dso__set_long_name(dso, dso->name); 207aeafcbafSArnaldo Carvalho de Melo dso__set_short_name(dso, dso->name); 2086a4694a4SArnaldo Carvalho de Melo for (i = 0; i < MAP__NR_TYPES; ++i) 209aeafcbafSArnaldo Carvalho de Melo dso->symbols[i] = dso->symbol_names[i] = RB_ROOT; 210aeafcbafSArnaldo Carvalho de Melo dso->symtab_type = SYMTAB__NOT_FOUND; 211aeafcbafSArnaldo Carvalho de Melo dso->loaded = 0; 212aeafcbafSArnaldo Carvalho de Melo dso->sorted_by_name = 0; 213aeafcbafSArnaldo Carvalho de Melo dso->has_build_id = 0; 214aeafcbafSArnaldo Carvalho de Melo dso->kernel = DSO_TYPE_USER; 215aeafcbafSArnaldo Carvalho de Melo INIT_LIST_HEAD(&dso->node); 21686470930SIngo Molnar } 21786470930SIngo Molnar 218aeafcbafSArnaldo Carvalho de Melo return dso; 21986470930SIngo Molnar } 22086470930SIngo Molnar 221aeafcbafSArnaldo Carvalho de Melo static void symbols__delete(struct rb_root *symbols) 22286470930SIngo Molnar { 22386470930SIngo Molnar struct symbol *pos; 224aeafcbafSArnaldo Carvalho de Melo struct rb_node *next = rb_first(symbols); 22586470930SIngo Molnar 22686470930SIngo Molnar while (next) { 22786470930SIngo Molnar pos = rb_entry(next, struct symbol, rb_node); 22886470930SIngo Molnar next = rb_next(&pos->rb_node); 229aeafcbafSArnaldo Carvalho de Melo rb_erase(&pos->rb_node, symbols); 23000a192b3SArnaldo Carvalho de Melo symbol__delete(pos); 23186470930SIngo Molnar } 23286470930SIngo Molnar } 23386470930SIngo Molnar 234aeafcbafSArnaldo Carvalho de Melo void dso__delete(struct dso *dso) 23586470930SIngo Molnar { 2366a4694a4SArnaldo Carvalho de Melo int i; 2376a4694a4SArnaldo Carvalho de Melo for (i = 0; i < MAP__NR_TYPES; ++i) 238aeafcbafSArnaldo Carvalho de Melo symbols__delete(&dso->symbols[i]); 239aeafcbafSArnaldo Carvalho de Melo if (dso->sname_alloc) 240aeafcbafSArnaldo Carvalho de Melo free((char *)dso->short_name); 241aeafcbafSArnaldo Carvalho de Melo if (dso->lname_alloc) 242aeafcbafSArnaldo Carvalho de Melo free(dso->long_name); 243aeafcbafSArnaldo Carvalho de Melo free(dso); 24486470930SIngo Molnar } 24586470930SIngo Molnar 246aeafcbafSArnaldo Carvalho de Melo void dso__set_build_id(struct dso *dso, void *build_id) 2478d06367fSArnaldo Carvalho de Melo { 248aeafcbafSArnaldo Carvalho de Melo memcpy(dso->build_id, build_id, sizeof(dso->build_id)); 249aeafcbafSArnaldo Carvalho de Melo dso->has_build_id = 1; 2508d06367fSArnaldo Carvalho de Melo } 2518d06367fSArnaldo Carvalho de Melo 252aeafcbafSArnaldo Carvalho de Melo static void symbols__insert(struct rb_root *symbols, struct symbol *sym) 25386470930SIngo Molnar { 254aeafcbafSArnaldo Carvalho de Melo struct rb_node **p = &symbols->rb_node; 25586470930SIngo Molnar struct rb_node *parent = NULL; 2569cffa8d5SPaul Mackerras const u64 ip = sym->start; 25786470930SIngo Molnar struct symbol *s; 25886470930SIngo Molnar 25986470930SIngo Molnar while (*p != NULL) { 26086470930SIngo Molnar parent = *p; 26186470930SIngo Molnar s = rb_entry(parent, struct symbol, rb_node); 26286470930SIngo Molnar if (ip < s->start) 26386470930SIngo Molnar p = &(*p)->rb_left; 26486470930SIngo Molnar else 26586470930SIngo Molnar p = &(*p)->rb_right; 26686470930SIngo Molnar } 26786470930SIngo Molnar rb_link_node(&sym->rb_node, parent, p); 268aeafcbafSArnaldo Carvalho de Melo rb_insert_color(&sym->rb_node, symbols); 26986470930SIngo Molnar } 27086470930SIngo Molnar 271aeafcbafSArnaldo Carvalho de Melo static struct symbol *symbols__find(struct rb_root *symbols, u64 ip) 27286470930SIngo Molnar { 27386470930SIngo Molnar struct rb_node *n; 27486470930SIngo Molnar 275aeafcbafSArnaldo Carvalho de Melo if (symbols == NULL) 27686470930SIngo Molnar return NULL; 27786470930SIngo Molnar 278aeafcbafSArnaldo Carvalho de Melo n = symbols->rb_node; 27986470930SIngo Molnar 28086470930SIngo Molnar while (n) { 28186470930SIngo Molnar struct symbol *s = rb_entry(n, struct symbol, rb_node); 28286470930SIngo Molnar 28386470930SIngo Molnar if (ip < s->start) 28486470930SIngo Molnar n = n->rb_left; 28586470930SIngo Molnar else if (ip > s->end) 28686470930SIngo Molnar n = n->rb_right; 28786470930SIngo Molnar else 28886470930SIngo Molnar return s; 28986470930SIngo Molnar } 29086470930SIngo Molnar 29186470930SIngo Molnar return NULL; 29286470930SIngo Molnar } 29386470930SIngo Molnar 29479406cd7SArnaldo Carvalho de Melo struct symbol_name_rb_node { 29579406cd7SArnaldo Carvalho de Melo struct rb_node rb_node; 29679406cd7SArnaldo Carvalho de Melo struct symbol sym; 29779406cd7SArnaldo Carvalho de Melo }; 29879406cd7SArnaldo Carvalho de Melo 299aeafcbafSArnaldo Carvalho de Melo static void symbols__insert_by_name(struct rb_root *symbols, struct symbol *sym) 30079406cd7SArnaldo Carvalho de Melo { 301aeafcbafSArnaldo Carvalho de Melo struct rb_node **p = &symbols->rb_node; 30279406cd7SArnaldo Carvalho de Melo struct rb_node *parent = NULL; 30302a9d037SRabin Vincent struct symbol_name_rb_node *symn, *s; 30402a9d037SRabin Vincent 30502a9d037SRabin Vincent symn = container_of(sym, struct symbol_name_rb_node, sym); 30679406cd7SArnaldo Carvalho de Melo 30779406cd7SArnaldo Carvalho de Melo while (*p != NULL) { 30879406cd7SArnaldo Carvalho de Melo parent = *p; 30979406cd7SArnaldo Carvalho de Melo s = rb_entry(parent, struct symbol_name_rb_node, rb_node); 31079406cd7SArnaldo Carvalho de Melo if (strcmp(sym->name, s->sym.name) < 0) 31179406cd7SArnaldo Carvalho de Melo p = &(*p)->rb_left; 31279406cd7SArnaldo Carvalho de Melo else 31379406cd7SArnaldo Carvalho de Melo p = &(*p)->rb_right; 31479406cd7SArnaldo Carvalho de Melo } 31579406cd7SArnaldo Carvalho de Melo rb_link_node(&symn->rb_node, parent, p); 316aeafcbafSArnaldo Carvalho de Melo rb_insert_color(&symn->rb_node, symbols); 31779406cd7SArnaldo Carvalho de Melo } 31879406cd7SArnaldo Carvalho de Melo 319aeafcbafSArnaldo Carvalho de Melo static void symbols__sort_by_name(struct rb_root *symbols, 320aeafcbafSArnaldo Carvalho de Melo struct rb_root *source) 32179406cd7SArnaldo Carvalho de Melo { 32279406cd7SArnaldo Carvalho de Melo struct rb_node *nd; 32379406cd7SArnaldo Carvalho de Melo 32479406cd7SArnaldo Carvalho de Melo for (nd = rb_first(source); nd; nd = rb_next(nd)) { 32579406cd7SArnaldo Carvalho de Melo struct symbol *pos = rb_entry(nd, struct symbol, rb_node); 326aeafcbafSArnaldo Carvalho de Melo symbols__insert_by_name(symbols, pos); 32779406cd7SArnaldo Carvalho de Melo } 32879406cd7SArnaldo Carvalho de Melo } 32979406cd7SArnaldo Carvalho de Melo 330aeafcbafSArnaldo Carvalho de Melo static struct symbol *symbols__find_by_name(struct rb_root *symbols, 331aeafcbafSArnaldo Carvalho de Melo const char *name) 33279406cd7SArnaldo Carvalho de Melo { 33379406cd7SArnaldo Carvalho de Melo struct rb_node *n; 33479406cd7SArnaldo Carvalho de Melo 335aeafcbafSArnaldo Carvalho de Melo if (symbols == NULL) 33679406cd7SArnaldo Carvalho de Melo return NULL; 33779406cd7SArnaldo Carvalho de Melo 338aeafcbafSArnaldo Carvalho de Melo n = symbols->rb_node; 33979406cd7SArnaldo Carvalho de Melo 34079406cd7SArnaldo Carvalho de Melo while (n) { 34179406cd7SArnaldo Carvalho de Melo struct symbol_name_rb_node *s; 34279406cd7SArnaldo Carvalho de Melo int cmp; 34379406cd7SArnaldo Carvalho de Melo 34479406cd7SArnaldo Carvalho de Melo s = rb_entry(n, struct symbol_name_rb_node, rb_node); 34579406cd7SArnaldo Carvalho de Melo cmp = strcmp(name, s->sym.name); 34679406cd7SArnaldo Carvalho de Melo 34779406cd7SArnaldo Carvalho de Melo if (cmp < 0) 34879406cd7SArnaldo Carvalho de Melo n = n->rb_left; 34979406cd7SArnaldo Carvalho de Melo else if (cmp > 0) 35079406cd7SArnaldo Carvalho de Melo n = n->rb_right; 35179406cd7SArnaldo Carvalho de Melo else 35279406cd7SArnaldo Carvalho de Melo return &s->sym; 35379406cd7SArnaldo Carvalho de Melo } 35479406cd7SArnaldo Carvalho de Melo 35579406cd7SArnaldo Carvalho de Melo return NULL; 35679406cd7SArnaldo Carvalho de Melo } 35779406cd7SArnaldo Carvalho de Melo 358aeafcbafSArnaldo Carvalho de Melo struct symbol *dso__find_symbol(struct dso *dso, 35979406cd7SArnaldo Carvalho de Melo enum map_type type, u64 addr) 360fcf1203aSArnaldo Carvalho de Melo { 361aeafcbafSArnaldo Carvalho de Melo return symbols__find(&dso->symbols[type], addr); 362fcf1203aSArnaldo Carvalho de Melo } 363fcf1203aSArnaldo Carvalho de Melo 364aeafcbafSArnaldo Carvalho de Melo struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type, 36579406cd7SArnaldo Carvalho de Melo const char *name) 36679406cd7SArnaldo Carvalho de Melo { 367aeafcbafSArnaldo Carvalho de Melo return symbols__find_by_name(&dso->symbol_names[type], name); 36879406cd7SArnaldo Carvalho de Melo } 36979406cd7SArnaldo Carvalho de Melo 370aeafcbafSArnaldo Carvalho de Melo void dso__sort_by_name(struct dso *dso, enum map_type type) 37179406cd7SArnaldo Carvalho de Melo { 372aeafcbafSArnaldo Carvalho de Melo dso__set_sorted_by_name(dso, type); 373aeafcbafSArnaldo Carvalho de Melo return symbols__sort_by_name(&dso->symbol_names[type], 374aeafcbafSArnaldo Carvalho de Melo &dso->symbols[type]); 37579406cd7SArnaldo Carvalho de Melo } 37679406cd7SArnaldo Carvalho de Melo 377aeafcbafSArnaldo Carvalho de Melo int build_id__sprintf(const u8 *build_id, int len, char *bf) 3788d06367fSArnaldo Carvalho de Melo { 3798d06367fSArnaldo Carvalho de Melo char *bid = bf; 380aeafcbafSArnaldo Carvalho de Melo const u8 *raw = build_id; 3818d06367fSArnaldo Carvalho de Melo int i; 3828d06367fSArnaldo Carvalho de Melo 3838d06367fSArnaldo Carvalho de Melo for (i = 0; i < len; ++i) { 3848d06367fSArnaldo Carvalho de Melo sprintf(bid, "%02x", *raw); 3858d06367fSArnaldo Carvalho de Melo ++raw; 3868d06367fSArnaldo Carvalho de Melo bid += 2; 3878d06367fSArnaldo Carvalho de Melo } 3888d06367fSArnaldo Carvalho de Melo 389aeafcbafSArnaldo Carvalho de Melo return raw - build_id; 3908d06367fSArnaldo Carvalho de Melo } 3918d06367fSArnaldo Carvalho de Melo 392aeafcbafSArnaldo Carvalho de Melo size_t dso__fprintf_buildid(struct dso *dso, FILE *fp) 39386470930SIngo Molnar { 3948d06367fSArnaldo Carvalho de Melo char sbuild_id[BUILD_ID_SIZE * 2 + 1]; 3958d06367fSArnaldo Carvalho de Melo 396aeafcbafSArnaldo Carvalho de Melo build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id); 3979e03eb2dSArnaldo Carvalho de Melo return fprintf(fp, "%s", sbuild_id); 3989e03eb2dSArnaldo Carvalho de Melo } 3999e03eb2dSArnaldo Carvalho de Melo 400aeafcbafSArnaldo Carvalho de Melo size_t dso__fprintf_symbols_by_name(struct dso *dso, 401aeafcbafSArnaldo Carvalho de Melo enum map_type type, FILE *fp) 40290f18e63SSrikar Dronamraju { 40390f18e63SSrikar Dronamraju size_t ret = 0; 40490f18e63SSrikar Dronamraju struct rb_node *nd; 40590f18e63SSrikar Dronamraju struct symbol_name_rb_node *pos; 40690f18e63SSrikar Dronamraju 407aeafcbafSArnaldo Carvalho de Melo for (nd = rb_first(&dso->symbol_names[type]); nd; nd = rb_next(nd)) { 40890f18e63SSrikar Dronamraju pos = rb_entry(nd, struct symbol_name_rb_node, rb_node); 40990f18e63SSrikar Dronamraju fprintf(fp, "%s\n", pos->sym.name); 41090f18e63SSrikar Dronamraju } 41190f18e63SSrikar Dronamraju 41290f18e63SSrikar Dronamraju return ret; 41390f18e63SSrikar Dronamraju } 41490f18e63SSrikar Dronamraju 415aeafcbafSArnaldo Carvalho de Melo size_t dso__fprintf(struct dso *dso, enum map_type type, FILE *fp) 4169e03eb2dSArnaldo Carvalho de Melo { 4179e03eb2dSArnaldo Carvalho de Melo struct rb_node *nd; 418aeafcbafSArnaldo Carvalho de Melo size_t ret = fprintf(fp, "dso: %s (", dso->short_name); 4199e03eb2dSArnaldo Carvalho de Melo 420aeafcbafSArnaldo Carvalho de Melo if (dso->short_name != dso->long_name) 421aeafcbafSArnaldo Carvalho de Melo ret += fprintf(fp, "%s, ", dso->long_name); 4223846df2eSArnaldo Carvalho de Melo ret += fprintf(fp, "%s, %sloaded, ", map_type__name[type], 423aeafcbafSArnaldo Carvalho de Melo dso->loaded ? "" : "NOT "); 424aeafcbafSArnaldo Carvalho de Melo ret += dso__fprintf_buildid(dso, fp); 4256a4694a4SArnaldo Carvalho de Melo ret += fprintf(fp, ")\n"); 426aeafcbafSArnaldo Carvalho de Melo for (nd = rb_first(&dso->symbols[type]); nd; nd = rb_next(nd)) { 42786470930SIngo Molnar struct symbol *pos = rb_entry(nd, struct symbol, rb_node); 42886470930SIngo Molnar ret += symbol__fprintf(pos, fp); 42986470930SIngo Molnar } 43086470930SIngo Molnar 43186470930SIngo Molnar return ret; 43286470930SIngo Molnar } 43386470930SIngo Molnar 4349e201442SArnaldo Carvalho de Melo int kallsyms__parse(const char *filename, void *arg, 4359e201442SArnaldo Carvalho de Melo int (*process_symbol)(void *arg, const char *name, 4363b01a413SArnaldo Carvalho de Melo char type, u64 start, u64 end)) 43786470930SIngo Molnar { 43886470930SIngo Molnar char *line = NULL; 43986470930SIngo Molnar size_t n; 4403b01a413SArnaldo Carvalho de Melo int err = -1; 4413b01a413SArnaldo Carvalho de Melo u64 prev_start = 0; 4423b01a413SArnaldo Carvalho de Melo char prev_symbol_type = 0; 4433b01a413SArnaldo Carvalho de Melo char *prev_symbol_name; 4449e201442SArnaldo Carvalho de Melo FILE *file = fopen(filename, "r"); 44586470930SIngo Molnar 44686470930SIngo Molnar if (file == NULL) 44786470930SIngo Molnar goto out_failure; 44886470930SIngo Molnar 4493b01a413SArnaldo Carvalho de Melo prev_symbol_name = malloc(KSYM_NAME_LEN); 4503b01a413SArnaldo Carvalho de Melo if (prev_symbol_name == NULL) 4513b01a413SArnaldo Carvalho de Melo goto out_close; 4523b01a413SArnaldo Carvalho de Melo 4533b01a413SArnaldo Carvalho de Melo err = 0; 4543b01a413SArnaldo Carvalho de Melo 45586470930SIngo Molnar while (!feof(file)) { 4569cffa8d5SPaul Mackerras u64 start; 45786470930SIngo Molnar int line_len, len; 45886470930SIngo Molnar char symbol_type; 4592e538c4aSArnaldo Carvalho de Melo char *symbol_name; 46086470930SIngo Molnar 46186470930SIngo Molnar line_len = getline(&line, &n, file); 462a1645ce1SZhang, Yanmin if (line_len < 0 || !line) 46386470930SIngo Molnar break; 46486470930SIngo Molnar 46586470930SIngo Molnar line[--line_len] = '\0'; /* \n */ 46686470930SIngo Molnar 46786470930SIngo Molnar len = hex2u64(line, &start); 46886470930SIngo Molnar 46986470930SIngo Molnar len++; 47086470930SIngo Molnar if (len + 2 >= line_len) 47186470930SIngo Molnar continue; 47286470930SIngo Molnar 47386470930SIngo Molnar symbol_type = toupper(line[len]); 4743b01a413SArnaldo Carvalho de Melo len += 2; 4753b01a413SArnaldo Carvalho de Melo symbol_name = line + len; 4763b01a413SArnaldo Carvalho de Melo len = line_len - len; 477682b335aSArnaldo Carvalho de Melo 4783b01a413SArnaldo Carvalho de Melo if (len >= KSYM_NAME_LEN) { 4793b01a413SArnaldo Carvalho de Melo err = -1; 4803b01a413SArnaldo Carvalho de Melo break; 4813b01a413SArnaldo Carvalho de Melo } 4823b01a413SArnaldo Carvalho de Melo 4833b01a413SArnaldo Carvalho de Melo if (prev_symbol_type) { 4843b01a413SArnaldo Carvalho de Melo u64 end = start; 4853b01a413SArnaldo Carvalho de Melo if (end != prev_start) 4863b01a413SArnaldo Carvalho de Melo --end; 4873b01a413SArnaldo Carvalho de Melo err = process_symbol(arg, prev_symbol_name, 4883b01a413SArnaldo Carvalho de Melo prev_symbol_type, prev_start, end); 489682b335aSArnaldo Carvalho de Melo if (err) 490682b335aSArnaldo Carvalho de Melo break; 491682b335aSArnaldo Carvalho de Melo } 492682b335aSArnaldo Carvalho de Melo 4933b01a413SArnaldo Carvalho de Melo memcpy(prev_symbol_name, symbol_name, len + 1); 4943b01a413SArnaldo Carvalho de Melo prev_symbol_type = symbol_type; 4953b01a413SArnaldo Carvalho de Melo prev_start = start; 4963b01a413SArnaldo Carvalho de Melo } 4973b01a413SArnaldo Carvalho de Melo 4983b01a413SArnaldo Carvalho de Melo free(prev_symbol_name); 499682b335aSArnaldo Carvalho de Melo free(line); 5003b01a413SArnaldo Carvalho de Melo out_close: 501682b335aSArnaldo Carvalho de Melo fclose(file); 502682b335aSArnaldo Carvalho de Melo return err; 503682b335aSArnaldo Carvalho de Melo 504682b335aSArnaldo Carvalho de Melo out_failure: 505682b335aSArnaldo Carvalho de Melo return -1; 506682b335aSArnaldo Carvalho de Melo } 507682b335aSArnaldo Carvalho de Melo 508682b335aSArnaldo Carvalho de Melo struct process_kallsyms_args { 509682b335aSArnaldo Carvalho de Melo struct map *map; 510682b335aSArnaldo Carvalho de Melo struct dso *dso; 511682b335aSArnaldo Carvalho de Melo }; 512682b335aSArnaldo Carvalho de Melo 513c408fedfSArnaldo Carvalho de Melo static u8 kallsyms2elf_type(char type) 514c408fedfSArnaldo Carvalho de Melo { 515c408fedfSArnaldo Carvalho de Melo if (type == 'W') 516c408fedfSArnaldo Carvalho de Melo return STB_WEAK; 517c408fedfSArnaldo Carvalho de Melo 518c408fedfSArnaldo Carvalho de Melo return isupper(type) ? STB_GLOBAL : STB_LOCAL; 519c408fedfSArnaldo Carvalho de Melo } 520c408fedfSArnaldo Carvalho de Melo 521682b335aSArnaldo Carvalho de Melo static int map__process_kallsym_symbol(void *arg, const char *name, 5223b01a413SArnaldo Carvalho de Melo char type, u64 start, u64 end) 523682b335aSArnaldo Carvalho de Melo { 524682b335aSArnaldo Carvalho de Melo struct symbol *sym; 525682b335aSArnaldo Carvalho de Melo struct process_kallsyms_args *a = arg; 526682b335aSArnaldo Carvalho de Melo struct rb_root *root = &a->dso->symbols[a->map->type]; 527682b335aSArnaldo Carvalho de Melo 528682b335aSArnaldo Carvalho de Melo if (!symbol_type__is_a(type, a->map->type)) 529682b335aSArnaldo Carvalho de Melo return 0; 530682b335aSArnaldo Carvalho de Melo 5313b01a413SArnaldo Carvalho de Melo sym = symbol__new(start, end - start + 1, 5323b01a413SArnaldo Carvalho de Melo kallsyms2elf_type(type), name); 5332e538c4aSArnaldo Carvalho de Melo if (sym == NULL) 534682b335aSArnaldo Carvalho de Melo return -ENOMEM; 53582164161SArnaldo Carvalho de Melo /* 53682164161SArnaldo Carvalho de Melo * We will pass the symbols to the filter later, in 5374e06255fSArnaldo Carvalho de Melo * map__split_kallsyms, when we have split the maps per module 53882164161SArnaldo Carvalho de Melo */ 5394e06255fSArnaldo Carvalho de Melo symbols__insert(root, sym); 540a1645ce1SZhang, Yanmin 541682b335aSArnaldo Carvalho de Melo return 0; 5422e538c4aSArnaldo Carvalho de Melo } 5432e538c4aSArnaldo Carvalho de Melo 544682b335aSArnaldo Carvalho de Melo /* 545682b335aSArnaldo Carvalho de Melo * Loads the function entries in /proc/kallsyms into kernel_map->dso, 546682b335aSArnaldo Carvalho de Melo * so that we can in the next step set the symbol ->end address and then 547682b335aSArnaldo Carvalho de Melo * call kernel_maps__split_kallsyms. 548682b335aSArnaldo Carvalho de Melo */ 549aeafcbafSArnaldo Carvalho de Melo static int dso__load_all_kallsyms(struct dso *dso, const char *filename, 5509e201442SArnaldo Carvalho de Melo struct map *map) 551682b335aSArnaldo Carvalho de Melo { 552aeafcbafSArnaldo Carvalho de Melo struct process_kallsyms_args args = { .map = map, .dso = dso, }; 5539e201442SArnaldo Carvalho de Melo return kallsyms__parse(filename, &args, map__process_kallsym_symbol); 5542e538c4aSArnaldo Carvalho de Melo } 5552e538c4aSArnaldo Carvalho de Melo 5562e538c4aSArnaldo Carvalho de Melo /* 5572e538c4aSArnaldo Carvalho de Melo * Split the symbols into maps, making sure there are no overlaps, i.e. the 5582e538c4aSArnaldo Carvalho de Melo * kernel range is broken in several maps, named [kernel].N, as we don't have 5592e538c4aSArnaldo Carvalho de Melo * the original ELF section names vmlinux have. 5602e538c4aSArnaldo Carvalho de Melo */ 561aeafcbafSArnaldo Carvalho de Melo static int dso__split_kallsyms(struct dso *dso, struct map *map, 5629de89fe7SArnaldo Carvalho de Melo symbol_filter_t filter) 5632e538c4aSArnaldo Carvalho de Melo { 5649de89fe7SArnaldo Carvalho de Melo struct map_groups *kmaps = map__kmap(map)->kmaps; 56523346f21SArnaldo Carvalho de Melo struct machine *machine = kmaps->machine; 5664e06255fSArnaldo Carvalho de Melo struct map *curr_map = map; 5672e538c4aSArnaldo Carvalho de Melo struct symbol *pos; 5688a953312SArnaldo Carvalho de Melo int count = 0, moved = 0; 569aeafcbafSArnaldo Carvalho de Melo struct rb_root *root = &dso->symbols[map->type]; 5704e06255fSArnaldo Carvalho de Melo struct rb_node *next = rb_first(root); 5712e538c4aSArnaldo Carvalho de Melo int kernel_range = 0; 5722e538c4aSArnaldo Carvalho de Melo 5732e538c4aSArnaldo Carvalho de Melo while (next) { 5742e538c4aSArnaldo Carvalho de Melo char *module; 5752e538c4aSArnaldo Carvalho de Melo 5762e538c4aSArnaldo Carvalho de Melo pos = rb_entry(next, struct symbol, rb_node); 5772e538c4aSArnaldo Carvalho de Melo next = rb_next(&pos->rb_node); 5782e538c4aSArnaldo Carvalho de Melo 5792e538c4aSArnaldo Carvalho de Melo module = strchr(pos->name, '\t'); 5802e538c4aSArnaldo Carvalho de Melo if (module) { 58175be6cf4SArnaldo Carvalho de Melo if (!symbol_conf.use_modules) 5821de8e245SArnaldo Carvalho de Melo goto discard_symbol; 5831de8e245SArnaldo Carvalho de Melo 5842e538c4aSArnaldo Carvalho de Melo *module++ = '\0'; 5852e538c4aSArnaldo Carvalho de Melo 586b7cece76SArnaldo Carvalho de Melo if (strcmp(curr_map->dso->short_name, module)) { 587a1645ce1SZhang, Yanmin if (curr_map != map && 588aeafcbafSArnaldo Carvalho de Melo dso->kernel == DSO_TYPE_GUEST_KERNEL && 58923346f21SArnaldo Carvalho de Melo machine__is_default_guest(machine)) { 590a1645ce1SZhang, Yanmin /* 591a1645ce1SZhang, Yanmin * We assume all symbols of a module are 592a1645ce1SZhang, Yanmin * continuous in * kallsyms, so curr_map 593a1645ce1SZhang, Yanmin * points to a module and all its 594a1645ce1SZhang, Yanmin * symbols are in its kmap. Mark it as 595a1645ce1SZhang, Yanmin * loaded. 596a1645ce1SZhang, Yanmin */ 597a1645ce1SZhang, Yanmin dso__set_loaded(curr_map->dso, 598a1645ce1SZhang, Yanmin curr_map->type); 599af427bf5SArnaldo Carvalho de Melo } 600b7cece76SArnaldo Carvalho de Melo 601a1645ce1SZhang, Yanmin curr_map = map_groups__find_by_name(kmaps, 602a1645ce1SZhang, Yanmin map->type, module); 603a1645ce1SZhang, Yanmin if (curr_map == NULL) { 6042f51903bSArnaldo Carvalho de Melo pr_debug("%s/proc/{kallsyms,modules} " 605a1645ce1SZhang, Yanmin "inconsistency while looking " 606a1645ce1SZhang, Yanmin "for \"%s\" module!\n", 60723346f21SArnaldo Carvalho de Melo machine->root_dir, module); 608a1645ce1SZhang, Yanmin curr_map = map; 609a1645ce1SZhang, Yanmin goto discard_symbol; 610a1645ce1SZhang, Yanmin } 611a1645ce1SZhang, Yanmin 612a1645ce1SZhang, Yanmin if (curr_map->dso->loaded && 61323346f21SArnaldo Carvalho de Melo !machine__is_default_guest(machine)) 614b7cece76SArnaldo Carvalho de Melo goto discard_symbol; 615af427bf5SArnaldo Carvalho de Melo } 61686470930SIngo Molnar /* 6172e538c4aSArnaldo Carvalho de Melo * So that we look just like we get from .ko files, 6182e538c4aSArnaldo Carvalho de Melo * i.e. not prelinked, relative to map->start. 61986470930SIngo Molnar */ 6204e06255fSArnaldo Carvalho de Melo pos->start = curr_map->map_ip(curr_map, pos->start); 6214e06255fSArnaldo Carvalho de Melo pos->end = curr_map->map_ip(curr_map, pos->end); 6224e06255fSArnaldo Carvalho de Melo } else if (curr_map != map) { 6232e538c4aSArnaldo Carvalho de Melo char dso_name[PATH_MAX]; 624aeafcbafSArnaldo Carvalho de Melo struct dso *ndso; 62586470930SIngo Molnar 6268a953312SArnaldo Carvalho de Melo if (count == 0) { 6278a953312SArnaldo Carvalho de Melo curr_map = map; 6288a953312SArnaldo Carvalho de Melo goto filter_symbol; 6298a953312SArnaldo Carvalho de Melo } 6308a953312SArnaldo Carvalho de Melo 631aeafcbafSArnaldo Carvalho de Melo if (dso->kernel == DSO_TYPE_GUEST_KERNEL) 632a1645ce1SZhang, Yanmin snprintf(dso_name, sizeof(dso_name), 633a1645ce1SZhang, Yanmin "[guest.kernel].%d", 634a1645ce1SZhang, Yanmin kernel_range++); 635a1645ce1SZhang, Yanmin else 636a1645ce1SZhang, Yanmin snprintf(dso_name, sizeof(dso_name), 637a1645ce1SZhang, Yanmin "[kernel].%d", 6382e538c4aSArnaldo Carvalho de Melo kernel_range++); 63986470930SIngo Molnar 640aeafcbafSArnaldo Carvalho de Melo ndso = dso__new(dso_name); 641aeafcbafSArnaldo Carvalho de Melo if (ndso == NULL) 6422e538c4aSArnaldo Carvalho de Melo return -1; 6432e538c4aSArnaldo Carvalho de Melo 644aeafcbafSArnaldo Carvalho de Melo ndso->kernel = dso->kernel; 645a1645ce1SZhang, Yanmin 646aeafcbafSArnaldo Carvalho de Melo curr_map = map__new2(pos->start, ndso, map->type); 64737fe5fcbSZhang, Yanmin if (curr_map == NULL) { 648aeafcbafSArnaldo Carvalho de Melo dso__delete(ndso); 6492e538c4aSArnaldo Carvalho de Melo return -1; 6502e538c4aSArnaldo Carvalho de Melo } 6512e538c4aSArnaldo Carvalho de Melo 6524e06255fSArnaldo Carvalho de Melo curr_map->map_ip = curr_map->unmap_ip = identity__map_ip; 6539de89fe7SArnaldo Carvalho de Melo map_groups__insert(kmaps, curr_map); 6542e538c4aSArnaldo Carvalho de Melo ++kernel_range; 6552e538c4aSArnaldo Carvalho de Melo } 6568a953312SArnaldo Carvalho de Melo filter_symbol: 6574e06255fSArnaldo Carvalho de Melo if (filter && filter(curr_map, pos)) { 6581de8e245SArnaldo Carvalho de Melo discard_symbol: rb_erase(&pos->rb_node, root); 65900a192b3SArnaldo Carvalho de Melo symbol__delete(pos); 6602e538c4aSArnaldo Carvalho de Melo } else { 6614e06255fSArnaldo Carvalho de Melo if (curr_map != map) { 6624e06255fSArnaldo Carvalho de Melo rb_erase(&pos->rb_node, root); 6634e06255fSArnaldo Carvalho de Melo symbols__insert(&curr_map->dso->symbols[curr_map->type], pos); 6648a953312SArnaldo Carvalho de Melo ++moved; 6658a953312SArnaldo Carvalho de Melo } else 6668a953312SArnaldo Carvalho de Melo ++count; 6679974f496SMike Galbraith } 66886470930SIngo Molnar } 66986470930SIngo Molnar 670a1645ce1SZhang, Yanmin if (curr_map != map && 671aeafcbafSArnaldo Carvalho de Melo dso->kernel == DSO_TYPE_GUEST_KERNEL && 67223346f21SArnaldo Carvalho de Melo machine__is_default_guest(kmaps->machine)) { 673a1645ce1SZhang, Yanmin dso__set_loaded(curr_map->dso, curr_map->type); 674a1645ce1SZhang, Yanmin } 675a1645ce1SZhang, Yanmin 6768a953312SArnaldo Carvalho de Melo return count + moved; 67786470930SIngo Molnar } 67886470930SIngo Molnar 679ec80fde7SArnaldo Carvalho de Melo static bool symbol__restricted_filename(const char *filename, 680ec80fde7SArnaldo Carvalho de Melo const char *restricted_filename) 681ec80fde7SArnaldo Carvalho de Melo { 682ec80fde7SArnaldo Carvalho de Melo bool restricted = false; 683ec80fde7SArnaldo Carvalho de Melo 684ec80fde7SArnaldo Carvalho de Melo if (symbol_conf.kptr_restrict) { 685ec80fde7SArnaldo Carvalho de Melo char *r = realpath(filename, NULL); 686ec80fde7SArnaldo Carvalho de Melo 687ec80fde7SArnaldo Carvalho de Melo if (r != NULL) { 688ec80fde7SArnaldo Carvalho de Melo restricted = strcmp(r, restricted_filename) == 0; 689ec80fde7SArnaldo Carvalho de Melo free(r); 690ec80fde7SArnaldo Carvalho de Melo return restricted; 691ec80fde7SArnaldo Carvalho de Melo } 692ec80fde7SArnaldo Carvalho de Melo } 693ec80fde7SArnaldo Carvalho de Melo 694ec80fde7SArnaldo Carvalho de Melo return restricted; 695ec80fde7SArnaldo Carvalho de Melo } 696ec80fde7SArnaldo Carvalho de Melo 697aeafcbafSArnaldo Carvalho de Melo int dso__load_kallsyms(struct dso *dso, const char *filename, 6989de89fe7SArnaldo Carvalho de Melo struct map *map, symbol_filter_t filter) 6992e538c4aSArnaldo Carvalho de Melo { 700ec80fde7SArnaldo Carvalho de Melo if (symbol__restricted_filename(filename, "/proc/kallsyms")) 701ec80fde7SArnaldo Carvalho de Melo return -1; 702ec80fde7SArnaldo Carvalho de Melo 703aeafcbafSArnaldo Carvalho de Melo if (dso__load_all_kallsyms(dso, filename, map) < 0) 7042e538c4aSArnaldo Carvalho de Melo return -1; 7052e538c4aSArnaldo Carvalho de Melo 706aeafcbafSArnaldo Carvalho de Melo if (dso->kernel == DSO_TYPE_GUEST_KERNEL) 707aeafcbafSArnaldo Carvalho de Melo dso->symtab_type = SYMTAB__GUEST_KALLSYMS; 708a1645ce1SZhang, Yanmin else 709aeafcbafSArnaldo Carvalho de Melo dso->symtab_type = SYMTAB__KALLSYMS; 7102e538c4aSArnaldo Carvalho de Melo 711aeafcbafSArnaldo Carvalho de Melo return dso__split_kallsyms(dso, map, filter); 712af427bf5SArnaldo Carvalho de Melo } 713af427bf5SArnaldo Carvalho de Melo 714aeafcbafSArnaldo Carvalho de Melo static int dso__load_perf_map(struct dso *dso, struct map *map, 7156beba7adSArnaldo Carvalho de Melo symbol_filter_t filter) 71680d496beSPekka Enberg { 71780d496beSPekka Enberg char *line = NULL; 71880d496beSPekka Enberg size_t n; 71980d496beSPekka Enberg FILE *file; 72080d496beSPekka Enberg int nr_syms = 0; 72180d496beSPekka Enberg 722aeafcbafSArnaldo Carvalho de Melo file = fopen(dso->long_name, "r"); 72380d496beSPekka Enberg if (file == NULL) 72480d496beSPekka Enberg goto out_failure; 72580d496beSPekka Enberg 72680d496beSPekka Enberg while (!feof(file)) { 7279cffa8d5SPaul Mackerras u64 start, size; 72880d496beSPekka Enberg struct symbol *sym; 72980d496beSPekka Enberg int line_len, len; 73080d496beSPekka Enberg 73180d496beSPekka Enberg line_len = getline(&line, &n, file); 73280d496beSPekka Enberg if (line_len < 0) 73380d496beSPekka Enberg break; 73480d496beSPekka Enberg 73580d496beSPekka Enberg if (!line) 73680d496beSPekka Enberg goto out_failure; 73780d496beSPekka Enberg 73880d496beSPekka Enberg line[--line_len] = '\0'; /* \n */ 73980d496beSPekka Enberg 74080d496beSPekka Enberg len = hex2u64(line, &start); 74180d496beSPekka Enberg 74280d496beSPekka Enberg len++; 74380d496beSPekka Enberg if (len + 2 >= line_len) 74480d496beSPekka Enberg continue; 74580d496beSPekka Enberg 74680d496beSPekka Enberg len += hex2u64(line + len, &size); 74780d496beSPekka Enberg 74880d496beSPekka Enberg len++; 74980d496beSPekka Enberg if (len + 2 >= line_len) 75080d496beSPekka Enberg continue; 75180d496beSPekka Enberg 752c408fedfSArnaldo Carvalho de Melo sym = symbol__new(start, size, STB_GLOBAL, line + len); 75380d496beSPekka Enberg 75480d496beSPekka Enberg if (sym == NULL) 75580d496beSPekka Enberg goto out_delete_line; 75680d496beSPekka Enberg 757439d473bSArnaldo Carvalho de Melo if (filter && filter(map, sym)) 75800a192b3SArnaldo Carvalho de Melo symbol__delete(sym); 75980d496beSPekka Enberg else { 760aeafcbafSArnaldo Carvalho de Melo symbols__insert(&dso->symbols[map->type], sym); 76180d496beSPekka Enberg nr_syms++; 76280d496beSPekka Enberg } 76380d496beSPekka Enberg } 76480d496beSPekka Enberg 76580d496beSPekka Enberg free(line); 76680d496beSPekka Enberg fclose(file); 76780d496beSPekka Enberg 76880d496beSPekka Enberg return nr_syms; 76980d496beSPekka Enberg 77080d496beSPekka Enberg out_delete_line: 77180d496beSPekka Enberg free(line); 77280d496beSPekka Enberg out_failure: 77380d496beSPekka Enberg return -1; 77480d496beSPekka Enberg } 77580d496beSPekka Enberg 77686470930SIngo Molnar /** 77786470930SIngo Molnar * elf_symtab__for_each_symbol - iterate thru all the symbols 77886470930SIngo Molnar * 779aeafcbafSArnaldo Carvalho de Melo * @syms: struct elf_symtab instance to iterate 78083a0944fSIngo Molnar * @idx: uint32_t idx 78186470930SIngo Molnar * @sym: GElf_Sym iterator 78286470930SIngo Molnar */ 78383a0944fSIngo Molnar #define elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) \ 78483a0944fSIngo Molnar for (idx = 0, gelf_getsym(syms, idx, &sym);\ 78583a0944fSIngo Molnar idx < nr_syms; \ 78683a0944fSIngo Molnar idx++, gelf_getsym(syms, idx, &sym)) 78786470930SIngo Molnar 78886470930SIngo Molnar static inline uint8_t elf_sym__type(const GElf_Sym *sym) 78986470930SIngo Molnar { 79086470930SIngo Molnar return GELF_ST_TYPE(sym->st_info); 79186470930SIngo Molnar } 79286470930SIngo Molnar 79386470930SIngo Molnar static inline int elf_sym__is_function(const GElf_Sym *sym) 79486470930SIngo Molnar { 79586470930SIngo Molnar return elf_sym__type(sym) == STT_FUNC && 79686470930SIngo Molnar sym->st_name != 0 && 79781833130SArnaldo Carvalho de Melo sym->st_shndx != SHN_UNDEF; 79886470930SIngo Molnar } 79986470930SIngo Molnar 800f1dfa0b1SArnaldo Carvalho de Melo static inline bool elf_sym__is_object(const GElf_Sym *sym) 801f1dfa0b1SArnaldo Carvalho de Melo { 802f1dfa0b1SArnaldo Carvalho de Melo return elf_sym__type(sym) == STT_OBJECT && 803f1dfa0b1SArnaldo Carvalho de Melo sym->st_name != 0 && 804f1dfa0b1SArnaldo Carvalho de Melo sym->st_shndx != SHN_UNDEF; 805f1dfa0b1SArnaldo Carvalho de Melo } 806f1dfa0b1SArnaldo Carvalho de Melo 8076cfcc53eSMike Galbraith static inline int elf_sym__is_label(const GElf_Sym *sym) 8086cfcc53eSMike Galbraith { 8096cfcc53eSMike Galbraith return elf_sym__type(sym) == STT_NOTYPE && 8106cfcc53eSMike Galbraith sym->st_name != 0 && 8116cfcc53eSMike Galbraith sym->st_shndx != SHN_UNDEF && 8126cfcc53eSMike Galbraith sym->st_shndx != SHN_ABS; 8136cfcc53eSMike Galbraith } 8146cfcc53eSMike Galbraith 8156cfcc53eSMike Galbraith static inline const char *elf_sec__name(const GElf_Shdr *shdr, 8166cfcc53eSMike Galbraith const Elf_Data *secstrs) 8176cfcc53eSMike Galbraith { 8186cfcc53eSMike Galbraith return secstrs->d_buf + shdr->sh_name; 8196cfcc53eSMike Galbraith } 8206cfcc53eSMike Galbraith 8216cfcc53eSMike Galbraith static inline int elf_sec__is_text(const GElf_Shdr *shdr, 8226cfcc53eSMike Galbraith const Elf_Data *secstrs) 8236cfcc53eSMike Galbraith { 8246cfcc53eSMike Galbraith return strstr(elf_sec__name(shdr, secstrs), "text") != NULL; 8256cfcc53eSMike Galbraith } 8266cfcc53eSMike Galbraith 827f1dfa0b1SArnaldo Carvalho de Melo static inline bool elf_sec__is_data(const GElf_Shdr *shdr, 828f1dfa0b1SArnaldo Carvalho de Melo const Elf_Data *secstrs) 829f1dfa0b1SArnaldo Carvalho de Melo { 830f1dfa0b1SArnaldo Carvalho de Melo return strstr(elf_sec__name(shdr, secstrs), "data") != NULL; 831f1dfa0b1SArnaldo Carvalho de Melo } 832f1dfa0b1SArnaldo Carvalho de Melo 83386470930SIngo Molnar static inline const char *elf_sym__name(const GElf_Sym *sym, 83486470930SIngo Molnar const Elf_Data *symstrs) 83586470930SIngo Molnar { 83686470930SIngo Molnar return symstrs->d_buf + sym->st_name; 83786470930SIngo Molnar } 83886470930SIngo Molnar 83986470930SIngo Molnar static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, 84086470930SIngo Molnar GElf_Shdr *shp, const char *name, 84183a0944fSIngo Molnar size_t *idx) 84286470930SIngo Molnar { 84386470930SIngo Molnar Elf_Scn *sec = NULL; 84486470930SIngo Molnar size_t cnt = 1; 84586470930SIngo Molnar 84686470930SIngo Molnar while ((sec = elf_nextscn(elf, sec)) != NULL) { 84786470930SIngo Molnar char *str; 84886470930SIngo Molnar 84986470930SIngo Molnar gelf_getshdr(sec, shp); 85086470930SIngo Molnar str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name); 85186470930SIngo Molnar if (!strcmp(name, str)) { 85283a0944fSIngo Molnar if (idx) 85383a0944fSIngo Molnar *idx = cnt; 85486470930SIngo Molnar break; 85586470930SIngo Molnar } 85686470930SIngo Molnar ++cnt; 85786470930SIngo Molnar } 85886470930SIngo Molnar 85986470930SIngo Molnar return sec; 86086470930SIngo Molnar } 86186470930SIngo Molnar 86286470930SIngo Molnar #define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \ 86386470930SIngo Molnar for (idx = 0, pos = gelf_getrel(reldata, 0, &pos_mem); \ 86486470930SIngo Molnar idx < nr_entries; \ 86586470930SIngo Molnar ++idx, pos = gelf_getrel(reldata, idx, &pos_mem)) 86686470930SIngo Molnar 86786470930SIngo Molnar #define elf_section__for_each_rela(reldata, pos, pos_mem, idx, nr_entries) \ 86886470930SIngo Molnar for (idx = 0, pos = gelf_getrela(reldata, 0, &pos_mem); \ 86986470930SIngo Molnar idx < nr_entries; \ 87086470930SIngo Molnar ++idx, pos = gelf_getrela(reldata, idx, &pos_mem)) 87186470930SIngo Molnar 872a25e46c4SArnaldo Carvalho de Melo /* 873a25e46c4SArnaldo Carvalho de Melo * We need to check if we have a .dynsym, so that we can handle the 874a25e46c4SArnaldo Carvalho de Melo * .plt, synthesizing its symbols, that aren't on the symtabs (be it 875a25e46c4SArnaldo Carvalho de Melo * .dynsym or .symtab). 876a25e46c4SArnaldo Carvalho de Melo * And always look at the original dso, not at debuginfo packages, that 877a25e46c4SArnaldo Carvalho de Melo * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS). 878a25e46c4SArnaldo Carvalho de Melo */ 879aeafcbafSArnaldo Carvalho de Melo static int dso__synthesize_plt_symbols(struct dso *dso, struct map *map, 88082164161SArnaldo Carvalho de Melo symbol_filter_t filter) 88186470930SIngo Molnar { 88286470930SIngo Molnar uint32_t nr_rel_entries, idx; 88386470930SIngo Molnar GElf_Sym sym; 8849cffa8d5SPaul Mackerras u64 plt_offset; 88586470930SIngo Molnar GElf_Shdr shdr_plt; 88686470930SIngo Molnar struct symbol *f; 887a25e46c4SArnaldo Carvalho de Melo GElf_Shdr shdr_rel_plt, shdr_dynsym; 88886470930SIngo Molnar Elf_Data *reldata, *syms, *symstrs; 889a25e46c4SArnaldo Carvalho de Melo Elf_Scn *scn_plt_rel, *scn_symstrs, *scn_dynsym; 890a25e46c4SArnaldo Carvalho de Melo size_t dynsym_idx; 891a25e46c4SArnaldo Carvalho de Melo GElf_Ehdr ehdr; 89286470930SIngo Molnar char sympltname[1024]; 893a25e46c4SArnaldo Carvalho de Melo Elf *elf; 894a25e46c4SArnaldo Carvalho de Melo int nr = 0, symidx, fd, err = 0; 895ec5761eaSDavid Ahern char name[PATH_MAX]; 89686470930SIngo Molnar 897ec5761eaSDavid Ahern snprintf(name, sizeof(name), "%s%s", 898aeafcbafSArnaldo Carvalho de Melo symbol_conf.symfs, dso->long_name); 899ec5761eaSDavid Ahern fd = open(name, O_RDONLY); 900a25e46c4SArnaldo Carvalho de Melo if (fd < 0) 901a25e46c4SArnaldo Carvalho de Melo goto out; 902a25e46c4SArnaldo Carvalho de Melo 90384087126SMarti Raudsepp elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 904a25e46c4SArnaldo Carvalho de Melo if (elf == NULL) 905a25e46c4SArnaldo Carvalho de Melo goto out_close; 906a25e46c4SArnaldo Carvalho de Melo 907a25e46c4SArnaldo Carvalho de Melo if (gelf_getehdr(elf, &ehdr) == NULL) 908a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 909a25e46c4SArnaldo Carvalho de Melo 910a25e46c4SArnaldo Carvalho de Melo scn_dynsym = elf_section_by_name(elf, &ehdr, &shdr_dynsym, 911a25e46c4SArnaldo Carvalho de Melo ".dynsym", &dynsym_idx); 912a25e46c4SArnaldo Carvalho de Melo if (scn_dynsym == NULL) 913a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 914a25e46c4SArnaldo Carvalho de Melo 915a25e46c4SArnaldo Carvalho de Melo scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt, 91686470930SIngo Molnar ".rela.plt", NULL); 91786470930SIngo Molnar if (scn_plt_rel == NULL) { 918a25e46c4SArnaldo Carvalho de Melo scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt, 91986470930SIngo Molnar ".rel.plt", NULL); 92086470930SIngo Molnar if (scn_plt_rel == NULL) 921a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 92286470930SIngo Molnar } 92386470930SIngo Molnar 924a25e46c4SArnaldo Carvalho de Melo err = -1; 92586470930SIngo Molnar 926a25e46c4SArnaldo Carvalho de Melo if (shdr_rel_plt.sh_link != dynsym_idx) 927a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 928a25e46c4SArnaldo Carvalho de Melo 929a25e46c4SArnaldo Carvalho de Melo if (elf_section_by_name(elf, &ehdr, &shdr_plt, ".plt", NULL) == NULL) 930a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 93186470930SIngo Molnar 93286470930SIngo Molnar /* 93383a0944fSIngo Molnar * Fetch the relocation section to find the idxes to the GOT 93486470930SIngo Molnar * and the symbols in the .dynsym they refer to. 93586470930SIngo Molnar */ 93686470930SIngo Molnar reldata = elf_getdata(scn_plt_rel, NULL); 93786470930SIngo Molnar if (reldata == NULL) 938a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 93986470930SIngo Molnar 94086470930SIngo Molnar syms = elf_getdata(scn_dynsym, NULL); 94186470930SIngo Molnar if (syms == NULL) 942a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 94386470930SIngo Molnar 944a25e46c4SArnaldo Carvalho de Melo scn_symstrs = elf_getscn(elf, shdr_dynsym.sh_link); 94586470930SIngo Molnar if (scn_symstrs == NULL) 946a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 94786470930SIngo Molnar 94886470930SIngo Molnar symstrs = elf_getdata(scn_symstrs, NULL); 94986470930SIngo Molnar if (symstrs == NULL) 950a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 95186470930SIngo Molnar 95286470930SIngo Molnar nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize; 95386470930SIngo Molnar plt_offset = shdr_plt.sh_offset; 95486470930SIngo Molnar 95586470930SIngo Molnar if (shdr_rel_plt.sh_type == SHT_RELA) { 95686470930SIngo Molnar GElf_Rela pos_mem, *pos; 95786470930SIngo Molnar 95886470930SIngo Molnar elf_section__for_each_rela(reldata, pos, pos_mem, idx, 95986470930SIngo Molnar nr_rel_entries) { 96086470930SIngo Molnar symidx = GELF_R_SYM(pos->r_info); 96186470930SIngo Molnar plt_offset += shdr_plt.sh_entsize; 96286470930SIngo Molnar gelf_getsym(syms, symidx, &sym); 96386470930SIngo Molnar snprintf(sympltname, sizeof(sympltname), 96486470930SIngo Molnar "%s@plt", elf_sym__name(&sym, symstrs)); 96586470930SIngo Molnar 96686470930SIngo Molnar f = symbol__new(plt_offset, shdr_plt.sh_entsize, 967c408fedfSArnaldo Carvalho de Melo STB_GLOBAL, sympltname); 96886470930SIngo Molnar if (!f) 969a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 97086470930SIngo Molnar 97182164161SArnaldo Carvalho de Melo if (filter && filter(map, f)) 97282164161SArnaldo Carvalho de Melo symbol__delete(f); 97382164161SArnaldo Carvalho de Melo else { 974aeafcbafSArnaldo Carvalho de Melo symbols__insert(&dso->symbols[map->type], f); 97586470930SIngo Molnar ++nr; 97686470930SIngo Molnar } 97782164161SArnaldo Carvalho de Melo } 97886470930SIngo Molnar } else if (shdr_rel_plt.sh_type == SHT_REL) { 97986470930SIngo Molnar GElf_Rel pos_mem, *pos; 98086470930SIngo Molnar elf_section__for_each_rel(reldata, pos, pos_mem, idx, 98186470930SIngo Molnar nr_rel_entries) { 98286470930SIngo Molnar symidx = GELF_R_SYM(pos->r_info); 98386470930SIngo Molnar plt_offset += shdr_plt.sh_entsize; 98486470930SIngo Molnar gelf_getsym(syms, symidx, &sym); 98586470930SIngo Molnar snprintf(sympltname, sizeof(sympltname), 98686470930SIngo Molnar "%s@plt", elf_sym__name(&sym, symstrs)); 98786470930SIngo Molnar 98886470930SIngo Molnar f = symbol__new(plt_offset, shdr_plt.sh_entsize, 989c408fedfSArnaldo Carvalho de Melo STB_GLOBAL, sympltname); 99086470930SIngo Molnar if (!f) 991a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 99286470930SIngo Molnar 99382164161SArnaldo Carvalho de Melo if (filter && filter(map, f)) 99482164161SArnaldo Carvalho de Melo symbol__delete(f); 99582164161SArnaldo Carvalho de Melo else { 996aeafcbafSArnaldo Carvalho de Melo symbols__insert(&dso->symbols[map->type], f); 99786470930SIngo Molnar ++nr; 99886470930SIngo Molnar } 99986470930SIngo Molnar } 100082164161SArnaldo Carvalho de Melo } 100186470930SIngo Molnar 1002a25e46c4SArnaldo Carvalho de Melo err = 0; 1003a25e46c4SArnaldo Carvalho de Melo out_elf_end: 1004a25e46c4SArnaldo Carvalho de Melo elf_end(elf); 1005a25e46c4SArnaldo Carvalho de Melo out_close: 1006a25e46c4SArnaldo Carvalho de Melo close(fd); 1007a25e46c4SArnaldo Carvalho de Melo 1008a25e46c4SArnaldo Carvalho de Melo if (err == 0) 100986470930SIngo Molnar return nr; 1010a25e46c4SArnaldo Carvalho de Melo out: 1011fe2197b8SArnaldo Carvalho de Melo pr_debug("%s: problems reading %s PLT info.\n", 1012aeafcbafSArnaldo Carvalho de Melo __func__, dso->long_name); 1013a25e46c4SArnaldo Carvalho de Melo return 0; 101486470930SIngo Molnar } 101586470930SIngo Molnar 1016aeafcbafSArnaldo Carvalho de Melo static bool elf_sym__is_a(GElf_Sym *sym, enum map_type type) 1017d45868d3SArnaldo Carvalho de Melo { 1018d45868d3SArnaldo Carvalho de Melo switch (type) { 1019d45868d3SArnaldo Carvalho de Melo case MAP__FUNCTION: 1020aeafcbafSArnaldo Carvalho de Melo return elf_sym__is_function(sym); 1021f1dfa0b1SArnaldo Carvalho de Melo case MAP__VARIABLE: 1022aeafcbafSArnaldo Carvalho de Melo return elf_sym__is_object(sym); 1023d45868d3SArnaldo Carvalho de Melo default: 1024d45868d3SArnaldo Carvalho de Melo return false; 1025d45868d3SArnaldo Carvalho de Melo } 1026d45868d3SArnaldo Carvalho de Melo } 1027d45868d3SArnaldo Carvalho de Melo 1028aeafcbafSArnaldo Carvalho de Melo static bool elf_sec__is_a(GElf_Shdr *shdr, Elf_Data *secstrs, 1029aeafcbafSArnaldo Carvalho de Melo enum map_type type) 1030d45868d3SArnaldo Carvalho de Melo { 1031d45868d3SArnaldo Carvalho de Melo switch (type) { 1032d45868d3SArnaldo Carvalho de Melo case MAP__FUNCTION: 1033aeafcbafSArnaldo Carvalho de Melo return elf_sec__is_text(shdr, secstrs); 1034f1dfa0b1SArnaldo Carvalho de Melo case MAP__VARIABLE: 1035aeafcbafSArnaldo Carvalho de Melo return elf_sec__is_data(shdr, secstrs); 1036d45868d3SArnaldo Carvalho de Melo default: 1037d45868d3SArnaldo Carvalho de Melo return false; 1038d45868d3SArnaldo Carvalho de Melo } 1039d45868d3SArnaldo Carvalho de Melo } 1040d45868d3SArnaldo Carvalho de Melo 104170c3856bSEric B Munson static size_t elf_addr_to_index(Elf *elf, GElf_Addr addr) 104270c3856bSEric B Munson { 104370c3856bSEric B Munson Elf_Scn *sec = NULL; 104470c3856bSEric B Munson GElf_Shdr shdr; 104570c3856bSEric B Munson size_t cnt = 1; 104670c3856bSEric B Munson 104770c3856bSEric B Munson while ((sec = elf_nextscn(elf, sec)) != NULL) { 104870c3856bSEric B Munson gelf_getshdr(sec, &shdr); 104970c3856bSEric B Munson 105070c3856bSEric B Munson if ((addr >= shdr.sh_addr) && 105170c3856bSEric B Munson (addr < (shdr.sh_addr + shdr.sh_size))) 105270c3856bSEric B Munson return cnt; 105370c3856bSEric B Munson 105470c3856bSEric B Munson ++cnt; 105570c3856bSEric B Munson } 105670c3856bSEric B Munson 105770c3856bSEric B Munson return -1; 105870c3856bSEric B Munson } 105970c3856bSEric B Munson 1060aeafcbafSArnaldo Carvalho de Melo static int dso__load_sym(struct dso *dso, struct map *map, const char *name, 10616da80ce8SDave Martin int fd, symbol_filter_t filter, int kmodule, 10626da80ce8SDave Martin int want_symtab) 106386470930SIngo Molnar { 1064aeafcbafSArnaldo Carvalho de Melo struct kmap *kmap = dso->kernel ? map__kmap(map) : NULL; 10652e538c4aSArnaldo Carvalho de Melo struct map *curr_map = map; 1066aeafcbafSArnaldo Carvalho de Melo struct dso *curr_dso = dso; 10676cfcc53eSMike Galbraith Elf_Data *symstrs, *secstrs; 106886470930SIngo Molnar uint32_t nr_syms; 106986470930SIngo Molnar int err = -1; 107083a0944fSIngo Molnar uint32_t idx; 107186470930SIngo Molnar GElf_Ehdr ehdr; 107270c3856bSEric B Munson GElf_Shdr shdr, opdshdr; 107370c3856bSEric B Munson Elf_Data *syms, *opddata = NULL; 107486470930SIngo Molnar GElf_Sym sym; 107570c3856bSEric B Munson Elf_Scn *sec, *sec_strndx, *opdsec; 107686470930SIngo Molnar Elf *elf; 1077439d473bSArnaldo Carvalho de Melo int nr = 0; 107870c3856bSEric B Munson size_t opdidx = 0; 107986470930SIngo Molnar 108084087126SMarti Raudsepp elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 108186470930SIngo Molnar if (elf == NULL) { 10828b1389efSDave Martin pr_debug("%s: cannot read %s ELF file.\n", __func__, name); 108386470930SIngo Molnar goto out_close; 108486470930SIngo Molnar } 108586470930SIngo Molnar 108686470930SIngo Molnar if (gelf_getehdr(elf, &ehdr) == NULL) { 10878b1389efSDave Martin pr_debug("%s: cannot get elf header.\n", __func__); 108886470930SIngo Molnar goto out_elf_end; 108986470930SIngo Molnar } 109086470930SIngo Molnar 10916da80ce8SDave Martin /* Always reject images with a mismatched build-id: */ 1092aeafcbafSArnaldo Carvalho de Melo if (dso->has_build_id) { 109321916c38SDave Martin u8 build_id[BUILD_ID_SIZE]; 109421916c38SDave Martin 109521916c38SDave Martin if (elf_read_build_id(elf, build_id, 109621916c38SDave Martin BUILD_ID_SIZE) != BUILD_ID_SIZE) 109721916c38SDave Martin goto out_elf_end; 109821916c38SDave Martin 1099aeafcbafSArnaldo Carvalho de Melo if (!dso__build_id_equal(dso, build_id)) 110021916c38SDave Martin goto out_elf_end; 110121916c38SDave Martin } 110221916c38SDave Martin 110386470930SIngo Molnar sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL); 110486470930SIngo Molnar if (sec == NULL) { 11056da80ce8SDave Martin if (want_symtab) 11066da80ce8SDave Martin goto out_elf_end; 11076da80ce8SDave Martin 1108a25e46c4SArnaldo Carvalho de Melo sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL); 1109a25e46c4SArnaldo Carvalho de Melo if (sec == NULL) 111086470930SIngo Molnar goto out_elf_end; 111186470930SIngo Molnar } 111286470930SIngo Molnar 111370c3856bSEric B Munson opdsec = elf_section_by_name(elf, &ehdr, &opdshdr, ".opd", &opdidx); 111470c3856bSEric B Munson if (opdsec) 111570c3856bSEric B Munson opddata = elf_rawdata(opdsec, NULL); 111670c3856bSEric B Munson 111786470930SIngo Molnar syms = elf_getdata(sec, NULL); 111886470930SIngo Molnar if (syms == NULL) 111986470930SIngo Molnar goto out_elf_end; 112086470930SIngo Molnar 112186470930SIngo Molnar sec = elf_getscn(elf, shdr.sh_link); 112286470930SIngo Molnar if (sec == NULL) 112386470930SIngo Molnar goto out_elf_end; 112486470930SIngo Molnar 112586470930SIngo Molnar symstrs = elf_getdata(sec, NULL); 112686470930SIngo Molnar if (symstrs == NULL) 112786470930SIngo Molnar goto out_elf_end; 112886470930SIngo Molnar 11296cfcc53eSMike Galbraith sec_strndx = elf_getscn(elf, ehdr.e_shstrndx); 11306cfcc53eSMike Galbraith if (sec_strndx == NULL) 11316cfcc53eSMike Galbraith goto out_elf_end; 11326cfcc53eSMike Galbraith 11336cfcc53eSMike Galbraith secstrs = elf_getdata(sec_strndx, NULL); 11349b30a26bSStoyan Gaydarov if (secstrs == NULL) 11356cfcc53eSMike Galbraith goto out_elf_end; 11366cfcc53eSMike Galbraith 113786470930SIngo Molnar nr_syms = shdr.sh_size / shdr.sh_entsize; 113886470930SIngo Molnar 1139e9fbc9dcSArjan van de Ven memset(&sym, 0, sizeof(sym)); 1140aeafcbafSArnaldo Carvalho de Melo if (dso->kernel == DSO_TYPE_USER) { 1141aeafcbafSArnaldo Carvalho de Melo dso->adjust_symbols = (ehdr.e_type == ET_EXEC || 114230d7a77dSArnaldo Carvalho de Melo elf_section_by_name(elf, &ehdr, &shdr, 1143f5812a7aSArnaldo Carvalho de Melo ".gnu.prelink_undo", 114430d7a77dSArnaldo Carvalho de Melo NULL) != NULL); 1145aeafcbafSArnaldo Carvalho de Melo } else { 1146aeafcbafSArnaldo Carvalho de Melo dso->adjust_symbols = 0; 1147aeafcbafSArnaldo Carvalho de Melo } 114883a0944fSIngo Molnar elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) { 114986470930SIngo Molnar struct symbol *f; 115056b03f3cSArnaldo Carvalho de Melo const char *elf_name = elf_sym__name(&sym, symstrs); 11512e538c4aSArnaldo Carvalho de Melo char *demangled = NULL; 11526cfcc53eSMike Galbraith int is_label = elf_sym__is_label(&sym); 11536cfcc53eSMike Galbraith const char *section_name; 115486470930SIngo Molnar 11559de89fe7SArnaldo Carvalho de Melo if (kmap && kmap->ref_reloc_sym && kmap->ref_reloc_sym->name && 11569de89fe7SArnaldo Carvalho de Melo strcmp(elf_name, kmap->ref_reloc_sym->name) == 0) 11579de89fe7SArnaldo Carvalho de Melo kmap->ref_reloc_sym->unrelocated_addr = sym.st_value; 115856b03f3cSArnaldo Carvalho de Melo 1159d45868d3SArnaldo Carvalho de Melo if (!is_label && !elf_sym__is_a(&sym, map->type)) 116086470930SIngo Molnar continue; 116186470930SIngo Molnar 1162696b97a5SDave Martin /* Reject ARM ELF "mapping symbols": these aren't unique and 1163696b97a5SDave Martin * don't identify functions, so will confuse the profile 1164696b97a5SDave Martin * output: */ 1165696b97a5SDave Martin if (ehdr.e_machine == EM_ARM) { 1166696b97a5SDave Martin if (!strcmp(elf_name, "$a") || 1167696b97a5SDave Martin !strcmp(elf_name, "$d") || 1168696b97a5SDave Martin !strcmp(elf_name, "$t")) 1169696b97a5SDave Martin continue; 1170696b97a5SDave Martin } 1171696b97a5SDave Martin 117270c3856bSEric B Munson if (opdsec && sym.st_shndx == opdidx) { 117370c3856bSEric B Munson u32 offset = sym.st_value - opdshdr.sh_addr; 117470c3856bSEric B Munson u64 *opd = opddata->d_buf + offset; 117570c3856bSEric B Munson sym.st_value = *opd; 117670c3856bSEric B Munson sym.st_shndx = elf_addr_to_index(elf, sym.st_value); 117770c3856bSEric B Munson } 117870c3856bSEric B Munson 117986470930SIngo Molnar sec = elf_getscn(elf, sym.st_shndx); 118086470930SIngo Molnar if (!sec) 118186470930SIngo Molnar goto out_elf_end; 118286470930SIngo Molnar 118386470930SIngo Molnar gelf_getshdr(sec, &shdr); 11846cfcc53eSMike Galbraith 1185d45868d3SArnaldo Carvalho de Melo if (is_label && !elf_sec__is_a(&shdr, secstrs, map->type)) 11866cfcc53eSMike Galbraith continue; 11876cfcc53eSMike Galbraith 11886cfcc53eSMike Galbraith section_name = elf_sec__name(&shdr, secstrs); 118986470930SIngo Molnar 1190b2f8fb23SDr. David Alan Gilbert /* On ARM, symbols for thumb functions have 1 added to 1191b2f8fb23SDr. David Alan Gilbert * the symbol address as a flag - remove it */ 1192b2f8fb23SDr. David Alan Gilbert if ((ehdr.e_machine == EM_ARM) && 1193b2f8fb23SDr. David Alan Gilbert (map->type == MAP__FUNCTION) && 1194b2f8fb23SDr. David Alan Gilbert (sym.st_value & 1)) 1195b2f8fb23SDr. David Alan Gilbert --sym.st_value; 1196b2f8fb23SDr. David Alan Gilbert 1197aeafcbafSArnaldo Carvalho de Melo if (dso->kernel != DSO_TYPE_USER || kmodule) { 11982e538c4aSArnaldo Carvalho de Melo char dso_name[PATH_MAX]; 11992e538c4aSArnaldo Carvalho de Melo 12002e538c4aSArnaldo Carvalho de Melo if (strcmp(section_name, 1201b63be8d7SArnaldo Carvalho de Melo (curr_dso->short_name + 1202aeafcbafSArnaldo Carvalho de Melo dso->short_name_len)) == 0) 12032e538c4aSArnaldo Carvalho de Melo goto new_symbol; 12042e538c4aSArnaldo Carvalho de Melo 12052e538c4aSArnaldo Carvalho de Melo if (strcmp(section_name, ".text") == 0) { 12062e538c4aSArnaldo Carvalho de Melo curr_map = map; 1207aeafcbafSArnaldo Carvalho de Melo curr_dso = dso; 12082e538c4aSArnaldo Carvalho de Melo goto new_symbol; 1209af427bf5SArnaldo Carvalho de Melo } 1210af427bf5SArnaldo Carvalho de Melo 12112e538c4aSArnaldo Carvalho de Melo snprintf(dso_name, sizeof(dso_name), 1212aeafcbafSArnaldo Carvalho de Melo "%s%s", dso->short_name, section_name); 12132e538c4aSArnaldo Carvalho de Melo 12149de89fe7SArnaldo Carvalho de Melo curr_map = map_groups__find_by_name(kmap->kmaps, map->type, dso_name); 12152e538c4aSArnaldo Carvalho de Melo if (curr_map == NULL) { 12162e538c4aSArnaldo Carvalho de Melo u64 start = sym.st_value; 12172e538c4aSArnaldo Carvalho de Melo 12182e538c4aSArnaldo Carvalho de Melo if (kmodule) 12192e538c4aSArnaldo Carvalho de Melo start += map->start + shdr.sh_offset; 12202e538c4aSArnaldo Carvalho de Melo 122100a192b3SArnaldo Carvalho de Melo curr_dso = dso__new(dso_name); 12222e538c4aSArnaldo Carvalho de Melo if (curr_dso == NULL) 12232e538c4aSArnaldo Carvalho de Melo goto out_elf_end; 1224aeafcbafSArnaldo Carvalho de Melo curr_dso->kernel = dso->kernel; 1225aeafcbafSArnaldo Carvalho de Melo curr_dso->long_name = dso->long_name; 1226aeafcbafSArnaldo Carvalho de Melo curr_dso->long_name_len = dso->long_name_len; 12273610583cSArnaldo Carvalho de Melo curr_map = map__new2(start, curr_dso, 12286275ce2dSArnaldo Carvalho de Melo map->type); 12292e538c4aSArnaldo Carvalho de Melo if (curr_map == NULL) { 12302e538c4aSArnaldo Carvalho de Melo dso__delete(curr_dso); 12312e538c4aSArnaldo Carvalho de Melo goto out_elf_end; 12322e538c4aSArnaldo Carvalho de Melo } 1233ed52ce2eSArnaldo Carvalho de Melo curr_map->map_ip = identity__map_ip; 1234ed52ce2eSArnaldo Carvalho de Melo curr_map->unmap_ip = identity__map_ip; 1235aeafcbafSArnaldo Carvalho de Melo curr_dso->symtab_type = dso->symtab_type; 12369de89fe7SArnaldo Carvalho de Melo map_groups__insert(kmap->kmaps, curr_map); 1237aeafcbafSArnaldo Carvalho de Melo dsos__add(&dso->node, curr_dso); 12386275ce2dSArnaldo Carvalho de Melo dso__set_loaded(curr_dso, map->type); 12392e538c4aSArnaldo Carvalho de Melo } else 12402e538c4aSArnaldo Carvalho de Melo curr_dso = curr_map->dso; 12412e538c4aSArnaldo Carvalho de Melo 12422e538c4aSArnaldo Carvalho de Melo goto new_symbol; 12432e538c4aSArnaldo Carvalho de Melo } 12442e538c4aSArnaldo Carvalho de Melo 12452e538c4aSArnaldo Carvalho de Melo if (curr_dso->adjust_symbols) { 12469486aa38SArnaldo Carvalho de Melo pr_debug4("%s: adjusting symbol: st_value: %#" PRIx64 " " 12479486aa38SArnaldo Carvalho de Melo "sh_addr: %#" PRIx64 " sh_offset: %#" PRIx64 "\n", __func__, 124829a9f66dSArnaldo Carvalho de Melo (u64)sym.st_value, (u64)shdr.sh_addr, 124929a9f66dSArnaldo Carvalho de Melo (u64)shdr.sh_offset); 125086470930SIngo Molnar sym.st_value -= shdr.sh_addr - shdr.sh_offset; 1251af427bf5SArnaldo Carvalho de Melo } 125228ac909bSArnaldo Carvalho de Melo /* 125328ac909bSArnaldo Carvalho de Melo * We need to figure out if the object was created from C++ sources 125428ac909bSArnaldo Carvalho de Melo * DWARF DW_compile_unit has this, but we don't always have access 125528ac909bSArnaldo Carvalho de Melo * to it... 125628ac909bSArnaldo Carvalho de Melo */ 125783a0944fSIngo Molnar demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI); 125828ac909bSArnaldo Carvalho de Melo if (demangled != NULL) 125983a0944fSIngo Molnar elf_name = demangled; 12602e538c4aSArnaldo Carvalho de Melo new_symbol: 1261c408fedfSArnaldo Carvalho de Melo f = symbol__new(sym.st_value, sym.st_size, 1262c408fedfSArnaldo Carvalho de Melo GELF_ST_BIND(sym.st_info), elf_name); 126328ac909bSArnaldo Carvalho de Melo free(demangled); 126486470930SIngo Molnar if (!f) 126586470930SIngo Molnar goto out_elf_end; 126686470930SIngo Molnar 12672e538c4aSArnaldo Carvalho de Melo if (filter && filter(curr_map, f)) 126800a192b3SArnaldo Carvalho de Melo symbol__delete(f); 126986470930SIngo Molnar else { 12706a4694a4SArnaldo Carvalho de Melo symbols__insert(&curr_dso->symbols[curr_map->type], f); 127186470930SIngo Molnar nr++; 127286470930SIngo Molnar } 127386470930SIngo Molnar } 127486470930SIngo Molnar 12752e538c4aSArnaldo Carvalho de Melo /* 12762e538c4aSArnaldo Carvalho de Melo * For misannotated, zeroed, ASM function sizes. 12772e538c4aSArnaldo Carvalho de Melo */ 12786275ce2dSArnaldo Carvalho de Melo if (nr > 0) { 1279aeafcbafSArnaldo Carvalho de Melo symbols__fixup_end(&dso->symbols[map->type]); 12806275ce2dSArnaldo Carvalho de Melo if (kmap) { 12816275ce2dSArnaldo Carvalho de Melo /* 12826275ce2dSArnaldo Carvalho de Melo * We need to fixup this here too because we create new 12836275ce2dSArnaldo Carvalho de Melo * maps here, for things like vsyscall sections. 12846275ce2dSArnaldo Carvalho de Melo */ 12856275ce2dSArnaldo Carvalho de Melo __map_groups__fixup_end(kmap->kmaps, map->type); 12866275ce2dSArnaldo Carvalho de Melo } 12876275ce2dSArnaldo Carvalho de Melo } 128886470930SIngo Molnar err = nr; 128986470930SIngo Molnar out_elf_end: 129086470930SIngo Molnar elf_end(elf); 129186470930SIngo Molnar out_close: 129286470930SIngo Molnar return err; 129386470930SIngo Molnar } 129486470930SIngo Molnar 1295aeafcbafSArnaldo Carvalho de Melo static bool dso__build_id_equal(const struct dso *dso, u8 *build_id) 129678075caaSArnaldo Carvalho de Melo { 1297aeafcbafSArnaldo Carvalho de Melo return memcmp(dso->build_id, build_id, sizeof(dso->build_id)) == 0; 129878075caaSArnaldo Carvalho de Melo } 129978075caaSArnaldo Carvalho de Melo 1300a1645ce1SZhang, Yanmin bool __dsos__read_build_ids(struct list_head *head, bool with_hits) 130157f395a7SFrederic Weisbecker { 1302e30a3d12SArnaldo Carvalho de Melo bool have_build_id = false; 130357f395a7SFrederic Weisbecker struct dso *pos; 130457f395a7SFrederic Weisbecker 13056122e4e4SArnaldo Carvalho de Melo list_for_each_entry(pos, head, node) { 13066122e4e4SArnaldo Carvalho de Melo if (with_hits && !pos->hit) 13076122e4e4SArnaldo Carvalho de Melo continue; 1308f6e1467dSArnaldo Carvalho de Melo if (pos->has_build_id) { 1309f6e1467dSArnaldo Carvalho de Melo have_build_id = true; 1310f6e1467dSArnaldo Carvalho de Melo continue; 1311f6e1467dSArnaldo Carvalho de Melo } 1312e30a3d12SArnaldo Carvalho de Melo if (filename__read_build_id(pos->long_name, pos->build_id, 1313e30a3d12SArnaldo Carvalho de Melo sizeof(pos->build_id)) > 0) { 1314e30a3d12SArnaldo Carvalho de Melo have_build_id = true; 1315e30a3d12SArnaldo Carvalho de Melo pos->has_build_id = true; 131657f395a7SFrederic Weisbecker } 13176122e4e4SArnaldo Carvalho de Melo } 131857f395a7SFrederic Weisbecker 1319e30a3d12SArnaldo Carvalho de Melo return have_build_id; 132057f395a7SFrederic Weisbecker } 132157f395a7SFrederic Weisbecker 1322fd7a346eSArnaldo Carvalho de Melo /* 1323fd7a346eSArnaldo Carvalho de Melo * Align offset to 4 bytes as needed for note name and descriptor data. 1324fd7a346eSArnaldo Carvalho de Melo */ 1325fd7a346eSArnaldo Carvalho de Melo #define NOTE_ALIGN(n) (((n) + 3) & -4U) 1326fd7a346eSArnaldo Carvalho de Melo 132721916c38SDave Martin static int elf_read_build_id(Elf *elf, void *bf, size_t size) 13284d1e00a8SArnaldo Carvalho de Melo { 132921916c38SDave Martin int err = -1; 13304d1e00a8SArnaldo Carvalho de Melo GElf_Ehdr ehdr; 13314d1e00a8SArnaldo Carvalho de Melo GElf_Shdr shdr; 1332fd7a346eSArnaldo Carvalho de Melo Elf_Data *data; 13334d1e00a8SArnaldo Carvalho de Melo Elf_Scn *sec; 1334e57cfcdaSPekka Enberg Elf_Kind ek; 1335fd7a346eSArnaldo Carvalho de Melo void *ptr; 13364d1e00a8SArnaldo Carvalho de Melo 13372643ce11SArnaldo Carvalho de Melo if (size < BUILD_ID_SIZE) 13382643ce11SArnaldo Carvalho de Melo goto out; 13392643ce11SArnaldo Carvalho de Melo 1340e57cfcdaSPekka Enberg ek = elf_kind(elf); 1341e57cfcdaSPekka Enberg if (ek != ELF_K_ELF) 134221916c38SDave Martin goto out; 1343e57cfcdaSPekka Enberg 13444d1e00a8SArnaldo Carvalho de Melo if (gelf_getehdr(elf, &ehdr) == NULL) { 13456beba7adSArnaldo Carvalho de Melo pr_err("%s: cannot get elf header.\n", __func__); 134621916c38SDave Martin goto out; 13474d1e00a8SArnaldo Carvalho de Melo } 13484d1e00a8SArnaldo Carvalho de Melo 13492643ce11SArnaldo Carvalho de Melo sec = elf_section_by_name(elf, &ehdr, &shdr, 13502643ce11SArnaldo Carvalho de Melo ".note.gnu.build-id", NULL); 1351fd7a346eSArnaldo Carvalho de Melo if (sec == NULL) { 1352fd7a346eSArnaldo Carvalho de Melo sec = elf_section_by_name(elf, &ehdr, &shdr, 1353fd7a346eSArnaldo Carvalho de Melo ".notes", NULL); 13544d1e00a8SArnaldo Carvalho de Melo if (sec == NULL) 135521916c38SDave Martin goto out; 1356fd7a346eSArnaldo Carvalho de Melo } 13574d1e00a8SArnaldo Carvalho de Melo 1358fd7a346eSArnaldo Carvalho de Melo data = elf_getdata(sec, NULL); 1359fd7a346eSArnaldo Carvalho de Melo if (data == NULL) 136021916c38SDave Martin goto out; 1361fd7a346eSArnaldo Carvalho de Melo 1362fd7a346eSArnaldo Carvalho de Melo ptr = data->d_buf; 1363fd7a346eSArnaldo Carvalho de Melo while (ptr < (data->d_buf + data->d_size)) { 1364fd7a346eSArnaldo Carvalho de Melo GElf_Nhdr *nhdr = ptr; 1365fd7a346eSArnaldo Carvalho de Melo int namesz = NOTE_ALIGN(nhdr->n_namesz), 1366fd7a346eSArnaldo Carvalho de Melo descsz = NOTE_ALIGN(nhdr->n_descsz); 1367fd7a346eSArnaldo Carvalho de Melo const char *name; 1368fd7a346eSArnaldo Carvalho de Melo 1369fd7a346eSArnaldo Carvalho de Melo ptr += sizeof(*nhdr); 1370fd7a346eSArnaldo Carvalho de Melo name = ptr; 1371fd7a346eSArnaldo Carvalho de Melo ptr += namesz; 1372fd7a346eSArnaldo Carvalho de Melo if (nhdr->n_type == NT_GNU_BUILD_ID && 1373fd7a346eSArnaldo Carvalho de Melo nhdr->n_namesz == sizeof("GNU")) { 1374fd7a346eSArnaldo Carvalho de Melo if (memcmp(name, "GNU", sizeof("GNU")) == 0) { 1375fd7a346eSArnaldo Carvalho de Melo memcpy(bf, ptr, BUILD_ID_SIZE); 13762643ce11SArnaldo Carvalho de Melo err = BUILD_ID_SIZE; 1377fd7a346eSArnaldo Carvalho de Melo break; 1378fd7a346eSArnaldo Carvalho de Melo } 1379fd7a346eSArnaldo Carvalho de Melo } 1380fd7a346eSArnaldo Carvalho de Melo ptr += descsz; 1381fd7a346eSArnaldo Carvalho de Melo } 138221916c38SDave Martin 138321916c38SDave Martin out: 138421916c38SDave Martin return err; 138521916c38SDave Martin } 138621916c38SDave Martin 138721916c38SDave Martin int filename__read_build_id(const char *filename, void *bf, size_t size) 138821916c38SDave Martin { 138921916c38SDave Martin int fd, err = -1; 139021916c38SDave Martin Elf *elf; 139121916c38SDave Martin 139221916c38SDave Martin if (size < BUILD_ID_SIZE) 139321916c38SDave Martin goto out; 139421916c38SDave Martin 139521916c38SDave Martin fd = open(filename, O_RDONLY); 139621916c38SDave Martin if (fd < 0) 139721916c38SDave Martin goto out; 139821916c38SDave Martin 139921916c38SDave Martin elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 140021916c38SDave Martin if (elf == NULL) { 140121916c38SDave Martin pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename); 140221916c38SDave Martin goto out_close; 140321916c38SDave Martin } 140421916c38SDave Martin 140521916c38SDave Martin err = elf_read_build_id(elf, bf, size); 140621916c38SDave Martin 14072643ce11SArnaldo Carvalho de Melo elf_end(elf); 14082643ce11SArnaldo Carvalho de Melo out_close: 14092643ce11SArnaldo Carvalho de Melo close(fd); 14102643ce11SArnaldo Carvalho de Melo out: 14112643ce11SArnaldo Carvalho de Melo return err; 14122643ce11SArnaldo Carvalho de Melo } 14132643ce11SArnaldo Carvalho de Melo 1414f1617b40SArnaldo Carvalho de Melo int sysfs__read_build_id(const char *filename, void *build_id, size_t size) 1415f1617b40SArnaldo Carvalho de Melo { 1416f1617b40SArnaldo Carvalho de Melo int fd, err = -1; 1417f1617b40SArnaldo Carvalho de Melo 1418f1617b40SArnaldo Carvalho de Melo if (size < BUILD_ID_SIZE) 1419f1617b40SArnaldo Carvalho de Melo goto out; 1420f1617b40SArnaldo Carvalho de Melo 1421f1617b40SArnaldo Carvalho de Melo fd = open(filename, O_RDONLY); 1422f1617b40SArnaldo Carvalho de Melo if (fd < 0) 1423f1617b40SArnaldo Carvalho de Melo goto out; 1424f1617b40SArnaldo Carvalho de Melo 1425f1617b40SArnaldo Carvalho de Melo while (1) { 1426f1617b40SArnaldo Carvalho de Melo char bf[BUFSIZ]; 1427f1617b40SArnaldo Carvalho de Melo GElf_Nhdr nhdr; 1428f1617b40SArnaldo Carvalho de Melo int namesz, descsz; 1429f1617b40SArnaldo Carvalho de Melo 1430f1617b40SArnaldo Carvalho de Melo if (read(fd, &nhdr, sizeof(nhdr)) != sizeof(nhdr)) 1431f1617b40SArnaldo Carvalho de Melo break; 1432f1617b40SArnaldo Carvalho de Melo 1433fd7a346eSArnaldo Carvalho de Melo namesz = NOTE_ALIGN(nhdr.n_namesz); 1434fd7a346eSArnaldo Carvalho de Melo descsz = NOTE_ALIGN(nhdr.n_descsz); 1435f1617b40SArnaldo Carvalho de Melo if (nhdr.n_type == NT_GNU_BUILD_ID && 1436f1617b40SArnaldo Carvalho de Melo nhdr.n_namesz == sizeof("GNU")) { 1437f1617b40SArnaldo Carvalho de Melo if (read(fd, bf, namesz) != namesz) 1438f1617b40SArnaldo Carvalho de Melo break; 1439f1617b40SArnaldo Carvalho de Melo if (memcmp(bf, "GNU", sizeof("GNU")) == 0) { 1440f1617b40SArnaldo Carvalho de Melo if (read(fd, build_id, 1441f1617b40SArnaldo Carvalho de Melo BUILD_ID_SIZE) == BUILD_ID_SIZE) { 1442f1617b40SArnaldo Carvalho de Melo err = 0; 1443f1617b40SArnaldo Carvalho de Melo break; 1444f1617b40SArnaldo Carvalho de Melo } 1445f1617b40SArnaldo Carvalho de Melo } else if (read(fd, bf, descsz) != descsz) 1446f1617b40SArnaldo Carvalho de Melo break; 1447f1617b40SArnaldo Carvalho de Melo } else { 1448f1617b40SArnaldo Carvalho de Melo int n = namesz + descsz; 1449f1617b40SArnaldo Carvalho de Melo if (read(fd, bf, n) != n) 1450f1617b40SArnaldo Carvalho de Melo break; 1451f1617b40SArnaldo Carvalho de Melo } 1452f1617b40SArnaldo Carvalho de Melo } 1453f1617b40SArnaldo Carvalho de Melo close(fd); 1454f1617b40SArnaldo Carvalho de Melo out: 1455f1617b40SArnaldo Carvalho de Melo return err; 1456f1617b40SArnaldo Carvalho de Melo } 1457f1617b40SArnaldo Carvalho de Melo 1458aeafcbafSArnaldo Carvalho de Melo char dso__symtab_origin(const struct dso *dso) 145994cb9e38SArnaldo Carvalho de Melo { 146094cb9e38SArnaldo Carvalho de Melo static const char origin[] = { 1461878b439dSArnaldo Carvalho de Melo [SYMTAB__KALLSYMS] = 'k', 1462878b439dSArnaldo Carvalho de Melo [SYMTAB__JAVA_JIT] = 'j', 1463878b439dSArnaldo Carvalho de Melo [SYMTAB__BUILD_ID_CACHE] = 'B', 1464878b439dSArnaldo Carvalho de Melo [SYMTAB__FEDORA_DEBUGINFO] = 'f', 1465878b439dSArnaldo Carvalho de Melo [SYMTAB__UBUNTU_DEBUGINFO] = 'u', 1466878b439dSArnaldo Carvalho de Melo [SYMTAB__BUILDID_DEBUGINFO] = 'b', 1467878b439dSArnaldo Carvalho de Melo [SYMTAB__SYSTEM_PATH_DSO] = 'd', 1468878b439dSArnaldo Carvalho de Melo [SYMTAB__SYSTEM_PATH_KMODULE] = 'K', 1469878b439dSArnaldo Carvalho de Melo [SYMTAB__GUEST_KALLSYMS] = 'g', 1470878b439dSArnaldo Carvalho de Melo [SYMTAB__GUEST_KMODULE] = 'G', 147194cb9e38SArnaldo Carvalho de Melo }; 147294cb9e38SArnaldo Carvalho de Melo 1473aeafcbafSArnaldo Carvalho de Melo if (dso == NULL || dso->symtab_type == SYMTAB__NOT_FOUND) 147494cb9e38SArnaldo Carvalho de Melo return '!'; 1475aeafcbafSArnaldo Carvalho de Melo return origin[dso->symtab_type]; 147694cb9e38SArnaldo Carvalho de Melo } 147794cb9e38SArnaldo Carvalho de Melo 1478aeafcbafSArnaldo Carvalho de Melo int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter) 147986470930SIngo Molnar { 14804d1e00a8SArnaldo Carvalho de Melo int size = PATH_MAX; 1481c338aee8SArnaldo Carvalho de Melo char *name; 148286470930SIngo Molnar int ret = -1; 148386470930SIngo Molnar int fd; 148423346f21SArnaldo Carvalho de Melo struct machine *machine; 1485a1645ce1SZhang, Yanmin const char *root_dir; 14866da80ce8SDave Martin int want_symtab; 148786470930SIngo Molnar 1488aeafcbafSArnaldo Carvalho de Melo dso__set_loaded(dso, map->type); 148966bd8424SArnaldo Carvalho de Melo 1490aeafcbafSArnaldo Carvalho de Melo if (dso->kernel == DSO_TYPE_KERNEL) 1491aeafcbafSArnaldo Carvalho de Melo return dso__load_kernel_sym(dso, map, filter); 1492aeafcbafSArnaldo Carvalho de Melo else if (dso->kernel == DSO_TYPE_GUEST_KERNEL) 1493aeafcbafSArnaldo Carvalho de Melo return dso__load_guest_kernel_sym(dso, map, filter); 1494a1645ce1SZhang, Yanmin 149523346f21SArnaldo Carvalho de Melo if (map->groups && map->groups->machine) 149623346f21SArnaldo Carvalho de Melo machine = map->groups->machine; 1497a1645ce1SZhang, Yanmin else 149823346f21SArnaldo Carvalho de Melo machine = NULL; 1499c338aee8SArnaldo Carvalho de Melo 1500c338aee8SArnaldo Carvalho de Melo name = malloc(size); 150186470930SIngo Molnar if (!name) 150286470930SIngo Molnar return -1; 150386470930SIngo Molnar 1504aeafcbafSArnaldo Carvalho de Melo dso->adjust_symbols = 0; 1505f5812a7aSArnaldo Carvalho de Melo 1506aeafcbafSArnaldo Carvalho de Melo if (strncmp(dso->name, "/tmp/perf-", 10) == 0) { 1507981c1252SPekka Enberg struct stat st; 1508981c1252SPekka Enberg 1509*e9b52ef2SVasiliy Kulikov if (lstat(dso->name, &st) < 0) 1510981c1252SPekka Enberg return -1; 1511981c1252SPekka Enberg 1512981c1252SPekka Enberg if (st.st_uid && (st.st_uid != geteuid())) { 1513981c1252SPekka Enberg pr_warning("File %s not owned by current user or root, " 1514981c1252SPekka Enberg "ignoring it.\n", dso->name); 1515981c1252SPekka Enberg return -1; 1516981c1252SPekka Enberg } 1517981c1252SPekka Enberg 1518aeafcbafSArnaldo Carvalho de Melo ret = dso__load_perf_map(dso, map, filter); 1519aeafcbafSArnaldo Carvalho de Melo dso->symtab_type = ret > 0 ? SYMTAB__JAVA_JIT : 1520878b439dSArnaldo Carvalho de Melo SYMTAB__NOT_FOUND; 152194cb9e38SArnaldo Carvalho de Melo return ret; 152294cb9e38SArnaldo Carvalho de Melo } 152394cb9e38SArnaldo Carvalho de Melo 15246da80ce8SDave Martin /* Iterate over candidate debug images. 15256da80ce8SDave Martin * On the first pass, only load images if they have a full symtab. 15266da80ce8SDave Martin * Failing that, do a second pass where we accept .dynsym also 15276da80ce8SDave Martin */ 152860e4b10cSArnaldo Carvalho de Melo want_symtab = 1; 152960e4b10cSArnaldo Carvalho de Melo restart: 1530aeafcbafSArnaldo Carvalho de Melo for (dso->symtab_type = SYMTAB__BUILD_ID_CACHE; 1531aeafcbafSArnaldo Carvalho de Melo dso->symtab_type != SYMTAB__NOT_FOUND; 1532aeafcbafSArnaldo Carvalho de Melo dso->symtab_type++) { 1533aeafcbafSArnaldo Carvalho de Melo switch (dso->symtab_type) { 1534878b439dSArnaldo Carvalho de Melo case SYMTAB__BUILD_ID_CACHE: 1535ec5761eaSDavid Ahern /* skip the locally configured cache if a symfs is given */ 1536ec5761eaSDavid Ahern if (symbol_conf.symfs[0] || 1537aeafcbafSArnaldo Carvalho de Melo (dso__build_id_filename(dso, name, size) == NULL)) { 15386da80ce8SDave Martin continue; 1539ec5761eaSDavid Ahern } 15406da80ce8SDave Martin break; 1541878b439dSArnaldo Carvalho de Melo case SYMTAB__FEDORA_DEBUGINFO: 1542ec5761eaSDavid Ahern snprintf(name, size, "%s/usr/lib/debug%s.debug", 1543aeafcbafSArnaldo Carvalho de Melo symbol_conf.symfs, dso->long_name); 154486470930SIngo Molnar break; 1545878b439dSArnaldo Carvalho de Melo case SYMTAB__UBUNTU_DEBUGINFO: 1546ec5761eaSDavid Ahern snprintf(name, size, "%s/usr/lib/debug%s", 1547aeafcbafSArnaldo Carvalho de Melo symbol_conf.symfs, dso->long_name); 154886470930SIngo Molnar break; 1549878b439dSArnaldo Carvalho de Melo case SYMTAB__BUILDID_DEBUGINFO: { 1550b36f19d5SArnaldo Carvalho de Melo char build_id_hex[BUILD_ID_SIZE * 2 + 1]; 15516da80ce8SDave Martin 1552aeafcbafSArnaldo Carvalho de Melo if (!dso->has_build_id) 15536da80ce8SDave Martin continue; 15546da80ce8SDave Martin 1555aeafcbafSArnaldo Carvalho de Melo build_id__sprintf(dso->build_id, 1556aeafcbafSArnaldo Carvalho de Melo sizeof(dso->build_id), 1557d3379ab9SArnaldo Carvalho de Melo build_id_hex); 15584d1e00a8SArnaldo Carvalho de Melo snprintf(name, size, 1559ec5761eaSDavid Ahern "%s/usr/lib/debug/.build-id/%.2s/%s.debug", 1560ec5761eaSDavid Ahern symbol_conf.symfs, build_id_hex, build_id_hex + 2); 15614d1e00a8SArnaldo Carvalho de Melo } 15626da80ce8SDave Martin break; 1563878b439dSArnaldo Carvalho de Melo case SYMTAB__SYSTEM_PATH_DSO: 1564ec5761eaSDavid Ahern snprintf(name, size, "%s%s", 1565aeafcbafSArnaldo Carvalho de Melo symbol_conf.symfs, dso->long_name); 156686470930SIngo Molnar break; 1567878b439dSArnaldo Carvalho de Melo case SYMTAB__GUEST_KMODULE: 1568fb7d0b3cSKyle McMartin if (map->groups && machine) 1569fb7d0b3cSKyle McMartin root_dir = machine->root_dir; 1570a1645ce1SZhang, Yanmin else 1571a1645ce1SZhang, Yanmin root_dir = ""; 1572ec5761eaSDavid Ahern snprintf(name, size, "%s%s%s", symbol_conf.symfs, 1573aeafcbafSArnaldo Carvalho de Melo root_dir, dso->long_name); 1574ec5761eaSDavid Ahern break; 1575ec5761eaSDavid Ahern 1576878b439dSArnaldo Carvalho de Melo case SYMTAB__SYSTEM_PATH_KMODULE: 1577ec5761eaSDavid Ahern snprintf(name, size, "%s%s", symbol_conf.symfs, 1578aeafcbafSArnaldo Carvalho de Melo dso->long_name); 1579a1645ce1SZhang, Yanmin break; 158060e4b10cSArnaldo Carvalho de Melo default:; 158186470930SIngo Molnar } 158286470930SIngo Molnar 15836da80ce8SDave Martin /* Name is now the name of the next image to try */ 15846da80ce8SDave Martin fd = open(name, O_RDONLY); 15856da80ce8SDave Martin if (fd < 0) 15866da80ce8SDave Martin continue; 15876da80ce8SDave Martin 1588aeafcbafSArnaldo Carvalho de Melo ret = dso__load_sym(dso, map, name, fd, filter, 0, 15896da80ce8SDave Martin want_symtab); 159086470930SIngo Molnar close(fd); 159186470930SIngo Molnar 159286470930SIngo Molnar /* 15936da80ce8SDave Martin * Some people seem to have debuginfo files _WITHOUT_ debug 15946da80ce8SDave Martin * info!?!? 159586470930SIngo Molnar */ 159686470930SIngo Molnar if (!ret) 15976da80ce8SDave Martin continue; 159886470930SIngo Molnar 1599a25e46c4SArnaldo Carvalho de Melo if (ret > 0) { 1600aeafcbafSArnaldo Carvalho de Melo int nr_plt = dso__synthesize_plt_symbols(dso, map, 1601aeafcbafSArnaldo Carvalho de Melo filter); 1602a25e46c4SArnaldo Carvalho de Melo if (nr_plt > 0) 1603a25e46c4SArnaldo Carvalho de Melo ret += nr_plt; 16046da80ce8SDave Martin break; 1605a25e46c4SArnaldo Carvalho de Melo } 16066da80ce8SDave Martin } 16076da80ce8SDave Martin 160860e4b10cSArnaldo Carvalho de Melo /* 160960e4b10cSArnaldo Carvalho de Melo * If we wanted a full symtab but no image had one, 161060e4b10cSArnaldo Carvalho de Melo * relax our requirements and repeat the search. 161160e4b10cSArnaldo Carvalho de Melo */ 161260e4b10cSArnaldo Carvalho de Melo if (ret <= 0 && want_symtab) { 161360e4b10cSArnaldo Carvalho de Melo want_symtab = 0; 161460e4b10cSArnaldo Carvalho de Melo goto restart; 161560e4b10cSArnaldo Carvalho de Melo } 161660e4b10cSArnaldo Carvalho de Melo 161786470930SIngo Molnar free(name); 1618aeafcbafSArnaldo Carvalho de Melo if (ret < 0 && strstr(dso->name, " (deleted)") != NULL) 16191340e6bbSArnaldo Carvalho de Melo return 0; 162086470930SIngo Molnar return ret; 162186470930SIngo Molnar } 162286470930SIngo Molnar 1623aeafcbafSArnaldo Carvalho de Melo struct map *map_groups__find_by_name(struct map_groups *mg, 162479406cd7SArnaldo Carvalho de Melo enum map_type type, const char *name) 1625439d473bSArnaldo Carvalho de Melo { 1626439d473bSArnaldo Carvalho de Melo struct rb_node *nd; 1627439d473bSArnaldo Carvalho de Melo 1628aeafcbafSArnaldo Carvalho de Melo for (nd = rb_first(&mg->maps[type]); nd; nd = rb_next(nd)) { 1629439d473bSArnaldo Carvalho de Melo struct map *map = rb_entry(nd, struct map, rb_node); 1630439d473bSArnaldo Carvalho de Melo 1631b7cece76SArnaldo Carvalho de Melo if (map->dso && strcmp(map->dso->short_name, name) == 0) 1632439d473bSArnaldo Carvalho de Melo return map; 1633439d473bSArnaldo Carvalho de Melo } 1634439d473bSArnaldo Carvalho de Melo 1635439d473bSArnaldo Carvalho de Melo return NULL; 1636439d473bSArnaldo Carvalho de Melo } 1637439d473bSArnaldo Carvalho de Melo 1638aeafcbafSArnaldo Carvalho de Melo static int dso__kernel_module_get_build_id(struct dso *dso, 1639a1645ce1SZhang, Yanmin const char *root_dir) 1640b7cece76SArnaldo Carvalho de Melo { 1641b7cece76SArnaldo Carvalho de Melo char filename[PATH_MAX]; 1642b7cece76SArnaldo Carvalho de Melo /* 1643b7cece76SArnaldo Carvalho de Melo * kernel module short names are of the form "[module]" and 1644b7cece76SArnaldo Carvalho de Melo * we need just "module" here. 1645b7cece76SArnaldo Carvalho de Melo */ 1646aeafcbafSArnaldo Carvalho de Melo const char *name = dso->short_name + 1; 1647b7cece76SArnaldo Carvalho de Melo 1648b7cece76SArnaldo Carvalho de Melo snprintf(filename, sizeof(filename), 1649a1645ce1SZhang, Yanmin "%s/sys/module/%.*s/notes/.note.gnu.build-id", 1650a1645ce1SZhang, Yanmin root_dir, (int)strlen(name) - 1, name); 1651b7cece76SArnaldo Carvalho de Melo 1652aeafcbafSArnaldo Carvalho de Melo if (sysfs__read_build_id(filename, dso->build_id, 1653aeafcbafSArnaldo Carvalho de Melo sizeof(dso->build_id)) == 0) 1654aeafcbafSArnaldo Carvalho de Melo dso->has_build_id = true; 1655b7cece76SArnaldo Carvalho de Melo 1656b7cece76SArnaldo Carvalho de Melo return 0; 1657b7cece76SArnaldo Carvalho de Melo } 1658b7cece76SArnaldo Carvalho de Melo 1659aeafcbafSArnaldo Carvalho de Melo static int map_groups__set_modules_path_dir(struct map_groups *mg, 1660a1645ce1SZhang, Yanmin const char *dir_name) 16616cfcc53eSMike Galbraith { 1662439d473bSArnaldo Carvalho de Melo struct dirent *dent; 16635aab621bSArnaldo Carvalho de Melo DIR *dir = opendir(dir_name); 166474534341SGui Jianfeng int ret = 0; 16656cfcc53eSMike Galbraith 1666439d473bSArnaldo Carvalho de Melo if (!dir) { 16675aab621bSArnaldo Carvalho de Melo pr_debug("%s: cannot open %s dir\n", __func__, dir_name); 1668439d473bSArnaldo Carvalho de Melo return -1; 1669439d473bSArnaldo Carvalho de Melo } 16706cfcc53eSMike Galbraith 1671439d473bSArnaldo Carvalho de Melo while ((dent = readdir(dir)) != NULL) { 1672439d473bSArnaldo Carvalho de Melo char path[PATH_MAX]; 1673a1645ce1SZhang, Yanmin struct stat st; 1674439d473bSArnaldo Carvalho de Melo 1675a1645ce1SZhang, Yanmin /*sshfs might return bad dent->d_type, so we have to stat*/ 1676a1645ce1SZhang, Yanmin sprintf(path, "%s/%s", dir_name, dent->d_name); 1677a1645ce1SZhang, Yanmin if (stat(path, &st)) 1678a1645ce1SZhang, Yanmin continue; 1679a1645ce1SZhang, Yanmin 1680a1645ce1SZhang, Yanmin if (S_ISDIR(st.st_mode)) { 1681439d473bSArnaldo Carvalho de Melo if (!strcmp(dent->d_name, ".") || 1682439d473bSArnaldo Carvalho de Melo !strcmp(dent->d_name, "..")) 1683439d473bSArnaldo Carvalho de Melo continue; 1684439d473bSArnaldo Carvalho de Melo 1685439d473bSArnaldo Carvalho de Melo snprintf(path, sizeof(path), "%s/%s", 16865aab621bSArnaldo Carvalho de Melo dir_name, dent->d_name); 1687aeafcbafSArnaldo Carvalho de Melo ret = map_groups__set_modules_path_dir(mg, path); 168874534341SGui Jianfeng if (ret < 0) 168974534341SGui Jianfeng goto out; 1690439d473bSArnaldo Carvalho de Melo } else { 1691439d473bSArnaldo Carvalho de Melo char *dot = strrchr(dent->d_name, '.'), 1692439d473bSArnaldo Carvalho de Melo dso_name[PATH_MAX]; 1693439d473bSArnaldo Carvalho de Melo struct map *map; 1694cfc10d3bSArnaldo Carvalho de Melo char *long_name; 1695439d473bSArnaldo Carvalho de Melo 1696439d473bSArnaldo Carvalho de Melo if (dot == NULL || strcmp(dot, ".ko")) 1697439d473bSArnaldo Carvalho de Melo continue; 1698439d473bSArnaldo Carvalho de Melo snprintf(dso_name, sizeof(dso_name), "[%.*s]", 1699439d473bSArnaldo Carvalho de Melo (int)(dot - dent->d_name), dent->d_name); 1700439d473bSArnaldo Carvalho de Melo 1701a2a99e8eSArnaldo Carvalho de Melo strxfrchar(dso_name, '-', '_'); 1702aeafcbafSArnaldo Carvalho de Melo map = map_groups__find_by_name(mg, MAP__FUNCTION, 1703aeafcbafSArnaldo Carvalho de Melo dso_name); 1704439d473bSArnaldo Carvalho de Melo if (map == NULL) 1705439d473bSArnaldo Carvalho de Melo continue; 1706439d473bSArnaldo Carvalho de Melo 1707439d473bSArnaldo Carvalho de Melo snprintf(path, sizeof(path), "%s/%s", 17085aab621bSArnaldo Carvalho de Melo dir_name, dent->d_name); 1709439d473bSArnaldo Carvalho de Melo 1710cfc10d3bSArnaldo Carvalho de Melo long_name = strdup(path); 171174534341SGui Jianfeng if (long_name == NULL) { 171274534341SGui Jianfeng ret = -1; 171374534341SGui Jianfeng goto out; 171474534341SGui Jianfeng } 1715cfc10d3bSArnaldo Carvalho de Melo dso__set_long_name(map->dso, long_name); 17166e406257SArnaldo Carvalho de Melo map->dso->lname_alloc = 1; 1717a1645ce1SZhang, Yanmin dso__kernel_module_get_build_id(map->dso, ""); 1718439d473bSArnaldo Carvalho de Melo } 1719439d473bSArnaldo Carvalho de Melo } 1720439d473bSArnaldo Carvalho de Melo 172174534341SGui Jianfeng out: 1722439d473bSArnaldo Carvalho de Melo closedir(dir); 172374534341SGui Jianfeng return ret; 1724439d473bSArnaldo Carvalho de Melo } 1725439d473bSArnaldo Carvalho de Melo 1726a1645ce1SZhang, Yanmin static char *get_kernel_version(const char *root_dir) 1727439d473bSArnaldo Carvalho de Melo { 1728a1645ce1SZhang, Yanmin char version[PATH_MAX]; 1729a1645ce1SZhang, Yanmin FILE *file; 1730a1645ce1SZhang, Yanmin char *name, *tmp; 1731a1645ce1SZhang, Yanmin const char *prefix = "Linux version "; 1732a1645ce1SZhang, Yanmin 1733a1645ce1SZhang, Yanmin sprintf(version, "%s/proc/version", root_dir); 1734a1645ce1SZhang, Yanmin file = fopen(version, "r"); 1735a1645ce1SZhang, Yanmin if (!file) 1736a1645ce1SZhang, Yanmin return NULL; 1737a1645ce1SZhang, Yanmin 1738a1645ce1SZhang, Yanmin version[0] = '\0'; 1739a1645ce1SZhang, Yanmin tmp = fgets(version, sizeof(version), file); 1740a1645ce1SZhang, Yanmin fclose(file); 1741a1645ce1SZhang, Yanmin 1742a1645ce1SZhang, Yanmin name = strstr(version, prefix); 1743a1645ce1SZhang, Yanmin if (!name) 1744a1645ce1SZhang, Yanmin return NULL; 1745a1645ce1SZhang, Yanmin name += strlen(prefix); 1746a1645ce1SZhang, Yanmin tmp = strchr(name, ' '); 1747a1645ce1SZhang, Yanmin if (tmp) 1748a1645ce1SZhang, Yanmin *tmp = '\0'; 1749a1645ce1SZhang, Yanmin 1750a1645ce1SZhang, Yanmin return strdup(name); 1751a1645ce1SZhang, Yanmin } 1752a1645ce1SZhang, Yanmin 1753aeafcbafSArnaldo Carvalho de Melo static int machine__set_modules_path(struct machine *machine) 1754a1645ce1SZhang, Yanmin { 1755a1645ce1SZhang, Yanmin char *version; 1756439d473bSArnaldo Carvalho de Melo char modules_path[PATH_MAX]; 1757439d473bSArnaldo Carvalho de Melo 1758aeafcbafSArnaldo Carvalho de Melo version = get_kernel_version(machine->root_dir); 1759a1645ce1SZhang, Yanmin if (!version) 1760439d473bSArnaldo Carvalho de Melo return -1; 1761439d473bSArnaldo Carvalho de Melo 1762a1645ce1SZhang, Yanmin snprintf(modules_path, sizeof(modules_path), "%s/lib/modules/%s/kernel", 1763aeafcbafSArnaldo Carvalho de Melo machine->root_dir, version); 1764a1645ce1SZhang, Yanmin free(version); 1765439d473bSArnaldo Carvalho de Melo 1766aeafcbafSArnaldo Carvalho de Melo return map_groups__set_modules_path_dir(&machine->kmaps, modules_path); 1767439d473bSArnaldo Carvalho de Melo } 17686cfcc53eSMike Galbraith 17696cfcc53eSMike Galbraith /* 1770439d473bSArnaldo Carvalho de Melo * Constructor variant for modules (where we know from /proc/modules where 1771439d473bSArnaldo Carvalho de Melo * they are loaded) and for vmlinux, where only after we load all the 1772439d473bSArnaldo Carvalho de Melo * symbols we'll know where it starts and ends. 17736cfcc53eSMike Galbraith */ 17743610583cSArnaldo Carvalho de Melo static struct map *map__new2(u64 start, struct dso *dso, enum map_type type) 1775439d473bSArnaldo Carvalho de Melo { 1776aeafcbafSArnaldo Carvalho de Melo struct map *map = calloc(1, (sizeof(*map) + 17775aab621bSArnaldo Carvalho de Melo (dso->kernel ? sizeof(struct kmap) : 0))); 1778aeafcbafSArnaldo Carvalho de Melo if (map != NULL) { 1779439d473bSArnaldo Carvalho de Melo /* 1780afb7b4f0SArnaldo Carvalho de Melo * ->end will be filled after we load all the symbols 1781439d473bSArnaldo Carvalho de Melo */ 1782aeafcbafSArnaldo Carvalho de Melo map__init(map, type, start, 0, 0, dso); 1783439d473bSArnaldo Carvalho de Melo } 1784afb7b4f0SArnaldo Carvalho de Melo 1785aeafcbafSArnaldo Carvalho de Melo return map; 1786439d473bSArnaldo Carvalho de Melo } 1787439d473bSArnaldo Carvalho de Melo 1788aeafcbafSArnaldo Carvalho de Melo struct map *machine__new_module(struct machine *machine, u64 start, 1789d28c6223SArnaldo Carvalho de Melo const char *filename) 1790b7cece76SArnaldo Carvalho de Melo { 1791b7cece76SArnaldo Carvalho de Melo struct map *map; 1792aeafcbafSArnaldo Carvalho de Melo struct dso *dso = __dsos__findnew(&machine->kernel_dsos, filename); 1793b7cece76SArnaldo Carvalho de Melo 1794b7cece76SArnaldo Carvalho de Melo if (dso == NULL) 1795b7cece76SArnaldo Carvalho de Melo return NULL; 1796b7cece76SArnaldo Carvalho de Melo 1797b7cece76SArnaldo Carvalho de Melo map = map__new2(start, dso, MAP__FUNCTION); 1798b7cece76SArnaldo Carvalho de Melo if (map == NULL) 1799b7cece76SArnaldo Carvalho de Melo return NULL; 1800b7cece76SArnaldo Carvalho de Melo 1801aeafcbafSArnaldo Carvalho de Melo if (machine__is_host(machine)) 1802878b439dSArnaldo Carvalho de Melo dso->symtab_type = SYMTAB__SYSTEM_PATH_KMODULE; 1803a1645ce1SZhang, Yanmin else 1804878b439dSArnaldo Carvalho de Melo dso->symtab_type = SYMTAB__GUEST_KMODULE; 1805aeafcbafSArnaldo Carvalho de Melo map_groups__insert(&machine->kmaps, map); 1806b7cece76SArnaldo Carvalho de Melo return map; 1807b7cece76SArnaldo Carvalho de Melo } 1808b7cece76SArnaldo Carvalho de Melo 1809aeafcbafSArnaldo Carvalho de Melo static int machine__create_modules(struct machine *machine) 1810439d473bSArnaldo Carvalho de Melo { 1811439d473bSArnaldo Carvalho de Melo char *line = NULL; 1812439d473bSArnaldo Carvalho de Melo size_t n; 1813a1645ce1SZhang, Yanmin FILE *file; 1814439d473bSArnaldo Carvalho de Melo struct map *map; 1815a1645ce1SZhang, Yanmin const char *modules; 1816a1645ce1SZhang, Yanmin char path[PATH_MAX]; 1817439d473bSArnaldo Carvalho de Melo 1818aeafcbafSArnaldo Carvalho de Melo if (machine__is_default_guest(machine)) 1819a1645ce1SZhang, Yanmin modules = symbol_conf.default_guest_modules; 1820a1645ce1SZhang, Yanmin else { 1821aeafcbafSArnaldo Carvalho de Melo sprintf(path, "%s/proc/modules", machine->root_dir); 1822a1645ce1SZhang, Yanmin modules = path; 1823a1645ce1SZhang, Yanmin } 1824a1645ce1SZhang, Yanmin 1825ec80fde7SArnaldo Carvalho de Melo if (symbol__restricted_filename(path, "/proc/modules")) 1826ec80fde7SArnaldo Carvalho de Melo return -1; 1827ec80fde7SArnaldo Carvalho de Melo 1828a1645ce1SZhang, Yanmin file = fopen(modules, "r"); 1829439d473bSArnaldo Carvalho de Melo if (file == NULL) 1830439d473bSArnaldo Carvalho de Melo return -1; 1831439d473bSArnaldo Carvalho de Melo 1832439d473bSArnaldo Carvalho de Melo while (!feof(file)) { 1833439d473bSArnaldo Carvalho de Melo char name[PATH_MAX]; 1834439d473bSArnaldo Carvalho de Melo u64 start; 1835439d473bSArnaldo Carvalho de Melo char *sep; 1836439d473bSArnaldo Carvalho de Melo int line_len; 1837439d473bSArnaldo Carvalho de Melo 1838439d473bSArnaldo Carvalho de Melo line_len = getline(&line, &n, file); 1839439d473bSArnaldo Carvalho de Melo if (line_len < 0) 18406cfcc53eSMike Galbraith break; 18416cfcc53eSMike Galbraith 1842439d473bSArnaldo Carvalho de Melo if (!line) 1843439d473bSArnaldo Carvalho de Melo goto out_failure; 1844439d473bSArnaldo Carvalho de Melo 1845439d473bSArnaldo Carvalho de Melo line[--line_len] = '\0'; /* \n */ 1846439d473bSArnaldo Carvalho de Melo 1847439d473bSArnaldo Carvalho de Melo sep = strrchr(line, 'x'); 1848439d473bSArnaldo Carvalho de Melo if (sep == NULL) 1849439d473bSArnaldo Carvalho de Melo continue; 1850439d473bSArnaldo Carvalho de Melo 1851439d473bSArnaldo Carvalho de Melo hex2u64(sep + 1, &start); 1852439d473bSArnaldo Carvalho de Melo 1853439d473bSArnaldo Carvalho de Melo sep = strchr(line, ' '); 1854439d473bSArnaldo Carvalho de Melo if (sep == NULL) 1855439d473bSArnaldo Carvalho de Melo continue; 1856439d473bSArnaldo Carvalho de Melo 1857439d473bSArnaldo Carvalho de Melo *sep = '\0'; 1858439d473bSArnaldo Carvalho de Melo 1859439d473bSArnaldo Carvalho de Melo snprintf(name, sizeof(name), "[%s]", line); 1860aeafcbafSArnaldo Carvalho de Melo map = machine__new_module(machine, start, name); 1861b7cece76SArnaldo Carvalho de Melo if (map == NULL) 1862439d473bSArnaldo Carvalho de Melo goto out_delete_line; 1863aeafcbafSArnaldo Carvalho de Melo dso__kernel_module_get_build_id(map->dso, machine->root_dir); 18646cfcc53eSMike Galbraith } 18656cfcc53eSMike Galbraith 1866439d473bSArnaldo Carvalho de Melo free(line); 1867439d473bSArnaldo Carvalho de Melo fclose(file); 1868439d473bSArnaldo Carvalho de Melo 1869aeafcbafSArnaldo Carvalho de Melo return machine__set_modules_path(machine); 1870439d473bSArnaldo Carvalho de Melo 1871439d473bSArnaldo Carvalho de Melo out_delete_line: 1872439d473bSArnaldo Carvalho de Melo free(line); 1873439d473bSArnaldo Carvalho de Melo out_failure: 1874439d473bSArnaldo Carvalho de Melo return -1; 18756cfcc53eSMike Galbraith } 18766cfcc53eSMike Galbraith 1877aeafcbafSArnaldo Carvalho de Melo int dso__load_vmlinux(struct dso *dso, struct map *map, 18786beba7adSArnaldo Carvalho de Melo const char *vmlinux, symbol_filter_t filter) 187986470930SIngo Molnar { 1880fbd733b8SArnaldo Carvalho de Melo int err = -1, fd; 1881ec5761eaSDavid Ahern char symfs_vmlinux[PATH_MAX]; 188286470930SIngo Molnar 1883a639dc64SArnaldo Carvalho de Melo snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s%s", 1884ec5761eaSDavid Ahern symbol_conf.symfs, vmlinux); 1885ec5761eaSDavid Ahern fd = open(symfs_vmlinux, O_RDONLY); 188686470930SIngo Molnar if (fd < 0) 188786470930SIngo Molnar return -1; 188886470930SIngo Molnar 1889aeafcbafSArnaldo Carvalho de Melo dso__set_long_name(dso, (char *)vmlinux); 1890aeafcbafSArnaldo Carvalho de Melo dso__set_loaded(dso, map->type); 1891aeafcbafSArnaldo Carvalho de Melo err = dso__load_sym(dso, map, symfs_vmlinux, fd, filter, 0, 0); 189286470930SIngo Molnar close(fd); 189386470930SIngo Molnar 18943846df2eSArnaldo Carvalho de Melo if (err > 0) 1895ec5761eaSDavid Ahern pr_debug("Using %s for symbols\n", symfs_vmlinux); 18963846df2eSArnaldo Carvalho de Melo 189786470930SIngo Molnar return err; 189886470930SIngo Molnar } 189986470930SIngo Molnar 1900aeafcbafSArnaldo Carvalho de Melo int dso__load_vmlinux_path(struct dso *dso, struct map *map, 19019de89fe7SArnaldo Carvalho de Melo symbol_filter_t filter) 1902a19afe46SArnaldo Carvalho de Melo { 1903a19afe46SArnaldo Carvalho de Melo int i, err = 0; 19045ad90e4eSArnaldo Carvalho de Melo char *filename; 1905a19afe46SArnaldo Carvalho de Melo 1906a19afe46SArnaldo Carvalho de Melo pr_debug("Looking at the vmlinux_path (%d entries long)\n", 19075ad90e4eSArnaldo Carvalho de Melo vmlinux_path__nr_entries + 1); 19085ad90e4eSArnaldo Carvalho de Melo 1909aeafcbafSArnaldo Carvalho de Melo filename = dso__build_id_filename(dso, NULL, 0); 19105ad90e4eSArnaldo Carvalho de Melo if (filename != NULL) { 1911aeafcbafSArnaldo Carvalho de Melo err = dso__load_vmlinux(dso, map, filename, filter); 19125ad90e4eSArnaldo Carvalho de Melo if (err > 0) { 1913aeafcbafSArnaldo Carvalho de Melo dso__set_long_name(dso, filename); 19145ad90e4eSArnaldo Carvalho de Melo goto out; 19155ad90e4eSArnaldo Carvalho de Melo } 19165ad90e4eSArnaldo Carvalho de Melo free(filename); 19175ad90e4eSArnaldo Carvalho de Melo } 1918a19afe46SArnaldo Carvalho de Melo 1919a19afe46SArnaldo Carvalho de Melo for (i = 0; i < vmlinux_path__nr_entries; ++i) { 1920aeafcbafSArnaldo Carvalho de Melo err = dso__load_vmlinux(dso, map, vmlinux_path[i], filter); 1921a19afe46SArnaldo Carvalho de Melo if (err > 0) { 1922aeafcbafSArnaldo Carvalho de Melo dso__set_long_name(dso, strdup(vmlinux_path[i])); 1923a19afe46SArnaldo Carvalho de Melo break; 1924a19afe46SArnaldo Carvalho de Melo } 1925a19afe46SArnaldo Carvalho de Melo } 19265ad90e4eSArnaldo Carvalho de Melo out: 1927a19afe46SArnaldo Carvalho de Melo return err; 1928a19afe46SArnaldo Carvalho de Melo } 1929a19afe46SArnaldo Carvalho de Melo 1930aeafcbafSArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *dso, struct map *map, 19319de89fe7SArnaldo Carvalho de Melo symbol_filter_t filter) 193286470930SIngo Molnar { 1933cc612d81SArnaldo Carvalho de Melo int err; 19349e201442SArnaldo Carvalho de Melo const char *kallsyms_filename = NULL; 19359e201442SArnaldo Carvalho de Melo char *kallsyms_allocated_filename = NULL; 1936dc8d6ab2SArnaldo Carvalho de Melo /* 1937b226a5a7SDavid Ahern * Step 1: if the user specified a kallsyms or vmlinux filename, use 1938b226a5a7SDavid Ahern * it and only it, reporting errors to the user if it cannot be used. 1939dc8d6ab2SArnaldo Carvalho de Melo * 1940dc8d6ab2SArnaldo Carvalho de Melo * For instance, try to analyse an ARM perf.data file _without_ a 1941dc8d6ab2SArnaldo Carvalho de Melo * build-id, or if the user specifies the wrong path to the right 1942dc8d6ab2SArnaldo Carvalho de Melo * vmlinux file, obviously we can't fallback to another vmlinux (a 1943dc8d6ab2SArnaldo Carvalho de Melo * x86_86 one, on the machine where analysis is being performed, say), 1944dc8d6ab2SArnaldo Carvalho de Melo * or worse, /proc/kallsyms. 1945dc8d6ab2SArnaldo Carvalho de Melo * 1946dc8d6ab2SArnaldo Carvalho de Melo * If the specified file _has_ a build-id and there is a build-id 1947dc8d6ab2SArnaldo Carvalho de Melo * section in the perf.data file, we will still do the expected 1948dc8d6ab2SArnaldo Carvalho de Melo * validation in dso__load_vmlinux and will bail out if they don't 1949dc8d6ab2SArnaldo Carvalho de Melo * match. 1950dc8d6ab2SArnaldo Carvalho de Melo */ 1951b226a5a7SDavid Ahern if (symbol_conf.kallsyms_name != NULL) { 1952b226a5a7SDavid Ahern kallsyms_filename = symbol_conf.kallsyms_name; 1953b226a5a7SDavid Ahern goto do_kallsyms; 1954b226a5a7SDavid Ahern } 1955b226a5a7SDavid Ahern 1956dc8d6ab2SArnaldo Carvalho de Melo if (symbol_conf.vmlinux_name != NULL) { 1957aeafcbafSArnaldo Carvalho de Melo err = dso__load_vmlinux(dso, map, 1958dc8d6ab2SArnaldo Carvalho de Melo symbol_conf.vmlinux_name, filter); 1959e7dadc00SArnaldo Carvalho de Melo if (err > 0) { 1960aeafcbafSArnaldo Carvalho de Melo dso__set_long_name(dso, 1961e7dadc00SArnaldo Carvalho de Melo strdup(symbol_conf.vmlinux_name)); 1962e7dadc00SArnaldo Carvalho de Melo goto out_fixup; 1963e7dadc00SArnaldo Carvalho de Melo } 1964e7dadc00SArnaldo Carvalho de Melo return err; 1965dc8d6ab2SArnaldo Carvalho de Melo } 1966439d473bSArnaldo Carvalho de Melo 1967cc612d81SArnaldo Carvalho de Melo if (vmlinux_path != NULL) { 1968aeafcbafSArnaldo Carvalho de Melo err = dso__load_vmlinux_path(dso, map, filter); 1969a19afe46SArnaldo Carvalho de Melo if (err > 0) 1970cc612d81SArnaldo Carvalho de Melo goto out_fixup; 1971cc612d81SArnaldo Carvalho de Melo } 1972cc612d81SArnaldo Carvalho de Melo 1973ec5761eaSDavid Ahern /* do not try local files if a symfs was given */ 1974ec5761eaSDavid Ahern if (symbol_conf.symfs[0] != 0) 1975ec5761eaSDavid Ahern return -1; 1976ec5761eaSDavid Ahern 1977b7cece76SArnaldo Carvalho de Melo /* 1978b7cece76SArnaldo Carvalho de Melo * Say the kernel DSO was created when processing the build-id header table, 1979b7cece76SArnaldo Carvalho de Melo * we have a build-id, so check if it is the same as the running kernel, 1980b7cece76SArnaldo Carvalho de Melo * using it if it is. 1981b7cece76SArnaldo Carvalho de Melo */ 1982aeafcbafSArnaldo Carvalho de Melo if (dso->has_build_id) { 1983b7cece76SArnaldo Carvalho de Melo u8 kallsyms_build_id[BUILD_ID_SIZE]; 19849e201442SArnaldo Carvalho de Melo char sbuild_id[BUILD_ID_SIZE * 2 + 1]; 1985b7cece76SArnaldo Carvalho de Melo 1986b7cece76SArnaldo Carvalho de Melo if (sysfs__read_build_id("/sys/kernel/notes", kallsyms_build_id, 19878d0591f6SArnaldo Carvalho de Melo sizeof(kallsyms_build_id)) == 0) { 1988aeafcbafSArnaldo Carvalho de Melo if (dso__build_id_equal(dso, kallsyms_build_id)) { 19899e201442SArnaldo Carvalho de Melo kallsyms_filename = "/proc/kallsyms"; 1990b7cece76SArnaldo Carvalho de Melo goto do_kallsyms; 19918d0591f6SArnaldo Carvalho de Melo } 19929e201442SArnaldo Carvalho de Melo } 1993dc8d6ab2SArnaldo Carvalho de Melo /* 1994dc8d6ab2SArnaldo Carvalho de Melo * Now look if we have it on the build-id cache in 1995dc8d6ab2SArnaldo Carvalho de Melo * $HOME/.debug/[kernel.kallsyms]. 1996dc8d6ab2SArnaldo Carvalho de Melo */ 1997aeafcbafSArnaldo Carvalho de Melo build_id__sprintf(dso->build_id, sizeof(dso->build_id), 19989e201442SArnaldo Carvalho de Melo sbuild_id); 19999e201442SArnaldo Carvalho de Melo 20009e201442SArnaldo Carvalho de Melo if (asprintf(&kallsyms_allocated_filename, 20019e201442SArnaldo Carvalho de Melo "%s/.debug/[kernel.kallsyms]/%s", 20023846df2eSArnaldo Carvalho de Melo getenv("HOME"), sbuild_id) == -1) { 20033846df2eSArnaldo Carvalho de Melo pr_err("Not enough memory for kallsyms file lookup\n"); 20048d0591f6SArnaldo Carvalho de Melo return -1; 20053846df2eSArnaldo Carvalho de Melo } 20068d0591f6SArnaldo Carvalho de Melo 200719fc2dedSArnaldo Carvalho de Melo kallsyms_filename = kallsyms_allocated_filename; 200819fc2dedSArnaldo Carvalho de Melo 2009dc8d6ab2SArnaldo Carvalho de Melo if (access(kallsyms_filename, F_OK)) { 20103846df2eSArnaldo Carvalho de Melo pr_err("No kallsyms or vmlinux with build-id %s " 20113846df2eSArnaldo Carvalho de Melo "was found\n", sbuild_id); 20129e201442SArnaldo Carvalho de Melo free(kallsyms_allocated_filename); 2013dc8d6ab2SArnaldo Carvalho de Melo return -1; 2014ef6ae724SArnaldo Carvalho de Melo } 2015dc8d6ab2SArnaldo Carvalho de Melo } else { 2016dc8d6ab2SArnaldo Carvalho de Melo /* 2017dc8d6ab2SArnaldo Carvalho de Melo * Last resort, if we don't have a build-id and couldn't find 2018dc8d6ab2SArnaldo Carvalho de Melo * any vmlinux file, try the running kernel kallsyms table. 2019dc8d6ab2SArnaldo Carvalho de Melo */ 2020dc8d6ab2SArnaldo Carvalho de Melo kallsyms_filename = "/proc/kallsyms"; 2021dc8d6ab2SArnaldo Carvalho de Melo } 2022dc8d6ab2SArnaldo Carvalho de Melo 2023dc8d6ab2SArnaldo Carvalho de Melo do_kallsyms: 2024aeafcbafSArnaldo Carvalho de Melo err = dso__load_kallsyms(dso, kallsyms_filename, map, filter); 20253846df2eSArnaldo Carvalho de Melo if (err > 0) 20263846df2eSArnaldo Carvalho de Melo pr_debug("Using %s for symbols\n", kallsyms_filename); 2027dc8d6ab2SArnaldo Carvalho de Melo free(kallsyms_allocated_filename); 2028dc8d6ab2SArnaldo Carvalho de Melo 2029439d473bSArnaldo Carvalho de Melo if (err > 0) { 2030cc612d81SArnaldo Carvalho de Melo out_fixup: 2031e1c7c6a4SArnaldo Carvalho de Melo if (kallsyms_filename != NULL) 2032aeafcbafSArnaldo Carvalho de Melo dso__set_long_name(dso, strdup("[kernel.kallsyms]")); 20336a4694a4SArnaldo Carvalho de Melo map__fixup_start(map); 20346a4694a4SArnaldo Carvalho de Melo map__fixup_end(map); 2035439d473bSArnaldo Carvalho de Melo } 203694cb9e38SArnaldo Carvalho de Melo 203786470930SIngo Molnar return err; 203886470930SIngo Molnar } 203986470930SIngo Molnar 2040aeafcbafSArnaldo Carvalho de Melo static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map, 2041a1645ce1SZhang, Yanmin symbol_filter_t filter) 2042a1645ce1SZhang, Yanmin { 2043a1645ce1SZhang, Yanmin int err; 2044a1645ce1SZhang, Yanmin const char *kallsyms_filename = NULL; 204523346f21SArnaldo Carvalho de Melo struct machine *machine; 2046a1645ce1SZhang, Yanmin char path[PATH_MAX]; 2047a1645ce1SZhang, Yanmin 2048a1645ce1SZhang, Yanmin if (!map->groups) { 2049a1645ce1SZhang, Yanmin pr_debug("Guest kernel map hasn't the point to groups\n"); 2050a1645ce1SZhang, Yanmin return -1; 2051a1645ce1SZhang, Yanmin } 205223346f21SArnaldo Carvalho de Melo machine = map->groups->machine; 2053a1645ce1SZhang, Yanmin 205423346f21SArnaldo Carvalho de Melo if (machine__is_default_guest(machine)) { 2055a1645ce1SZhang, Yanmin /* 2056a1645ce1SZhang, Yanmin * if the user specified a vmlinux filename, use it and only 2057a1645ce1SZhang, Yanmin * it, reporting errors to the user if it cannot be used. 2058a1645ce1SZhang, Yanmin * Or use file guest_kallsyms inputted by user on commandline 2059a1645ce1SZhang, Yanmin */ 2060a1645ce1SZhang, Yanmin if (symbol_conf.default_guest_vmlinux_name != NULL) { 2061aeafcbafSArnaldo Carvalho de Melo err = dso__load_vmlinux(dso, map, 2062a1645ce1SZhang, Yanmin symbol_conf.default_guest_vmlinux_name, filter); 2063a1645ce1SZhang, Yanmin goto out_try_fixup; 2064a1645ce1SZhang, Yanmin } 2065a1645ce1SZhang, Yanmin 2066a1645ce1SZhang, Yanmin kallsyms_filename = symbol_conf.default_guest_kallsyms; 2067a1645ce1SZhang, Yanmin if (!kallsyms_filename) 2068a1645ce1SZhang, Yanmin return -1; 2069a1645ce1SZhang, Yanmin } else { 207023346f21SArnaldo Carvalho de Melo sprintf(path, "%s/proc/kallsyms", machine->root_dir); 2071a1645ce1SZhang, Yanmin kallsyms_filename = path; 2072a1645ce1SZhang, Yanmin } 2073a1645ce1SZhang, Yanmin 2074aeafcbafSArnaldo Carvalho de Melo err = dso__load_kallsyms(dso, kallsyms_filename, map, filter); 2075a1645ce1SZhang, Yanmin if (err > 0) 2076a1645ce1SZhang, Yanmin pr_debug("Using %s for symbols\n", kallsyms_filename); 2077a1645ce1SZhang, Yanmin 2078a1645ce1SZhang, Yanmin out_try_fixup: 2079a1645ce1SZhang, Yanmin if (err > 0) { 2080a1645ce1SZhang, Yanmin if (kallsyms_filename != NULL) { 208148ea8f54SArnaldo Carvalho de Melo machine__mmap_name(machine, path, sizeof(path)); 2082aeafcbafSArnaldo Carvalho de Melo dso__set_long_name(dso, strdup(path)); 2083a1645ce1SZhang, Yanmin } 2084a1645ce1SZhang, Yanmin map__fixup_start(map); 2085a1645ce1SZhang, Yanmin map__fixup_end(map); 2086a1645ce1SZhang, Yanmin } 2087a1645ce1SZhang, Yanmin 2088a1645ce1SZhang, Yanmin return err; 2089a1645ce1SZhang, Yanmin } 2090cd84c2acSFrederic Weisbecker 2091b0da954aSArnaldo Carvalho de Melo static void dsos__add(struct list_head *head, struct dso *dso) 2092cd84c2acSFrederic Weisbecker { 2093b0da954aSArnaldo Carvalho de Melo list_add_tail(&dso->node, head); 2094cd84c2acSFrederic Weisbecker } 2095cd84c2acSFrederic Weisbecker 2096b0da954aSArnaldo Carvalho de Melo static struct dso *dsos__find(struct list_head *head, const char *name) 2097cd84c2acSFrederic Weisbecker { 2098cd84c2acSFrederic Weisbecker struct dso *pos; 2099cd84c2acSFrederic Weisbecker 2100b0da954aSArnaldo Carvalho de Melo list_for_each_entry(pos, head, node) 2101cf4e5b08SArnaldo Carvalho de Melo if (strcmp(pos->long_name, name) == 0) 2102cd84c2acSFrederic Weisbecker return pos; 2103cd84c2acSFrederic Weisbecker return NULL; 2104cd84c2acSFrederic Weisbecker } 2105cd84c2acSFrederic Weisbecker 2106a89e5abeSArnaldo Carvalho de Melo struct dso *__dsos__findnew(struct list_head *head, const char *name) 2107cd84c2acSFrederic Weisbecker { 2108a89e5abeSArnaldo Carvalho de Melo struct dso *dso = dsos__find(head, name); 2109cd84c2acSFrederic Weisbecker 2110e4204992SArnaldo Carvalho de Melo if (!dso) { 211100a192b3SArnaldo Carvalho de Melo dso = dso__new(name); 2112cfc10d3bSArnaldo Carvalho de Melo if (dso != NULL) { 2113a89e5abeSArnaldo Carvalho de Melo dsos__add(head, dso); 2114cfc10d3bSArnaldo Carvalho de Melo dso__set_basename(dso); 2115cfc10d3bSArnaldo Carvalho de Melo } 2116e4204992SArnaldo Carvalho de Melo } 2117cd84c2acSFrederic Weisbecker 2118cd84c2acSFrederic Weisbecker return dso; 2119cd84c2acSFrederic Weisbecker } 2120cd84c2acSFrederic Weisbecker 21211f626bc3SArnaldo Carvalho de Melo size_t __dsos__fprintf(struct list_head *head, FILE *fp) 2122cd84c2acSFrederic Weisbecker { 2123cd84c2acSFrederic Weisbecker struct dso *pos; 2124cbf69680SArnaldo Carvalho de Melo size_t ret = 0; 2125cd84c2acSFrederic Weisbecker 212695011c60SArnaldo Carvalho de Melo list_for_each_entry(pos, head, node) { 212795011c60SArnaldo Carvalho de Melo int i; 212895011c60SArnaldo Carvalho de Melo for (i = 0; i < MAP__NR_TYPES; ++i) 2129cbf69680SArnaldo Carvalho de Melo ret += dso__fprintf(pos, i, fp); 2130cd84c2acSFrederic Weisbecker } 2131cd84c2acSFrederic Weisbecker 2132cbf69680SArnaldo Carvalho de Melo return ret; 2133cbf69680SArnaldo Carvalho de Melo } 2134cbf69680SArnaldo Carvalho de Melo 2135aeafcbafSArnaldo Carvalho de Melo size_t machines__fprintf_dsos(struct rb_root *machines, FILE *fp) 2136b0da954aSArnaldo Carvalho de Melo { 2137a1645ce1SZhang, Yanmin struct rb_node *nd; 2138cbf69680SArnaldo Carvalho de Melo size_t ret = 0; 2139a1645ce1SZhang, Yanmin 2140aeafcbafSArnaldo Carvalho de Melo for (nd = rb_first(machines); nd; nd = rb_next(nd)) { 214123346f21SArnaldo Carvalho de Melo struct machine *pos = rb_entry(nd, struct machine, rb_node); 2142cbf69680SArnaldo Carvalho de Melo ret += __dsos__fprintf(&pos->kernel_dsos, fp); 2143cbf69680SArnaldo Carvalho de Melo ret += __dsos__fprintf(&pos->user_dsos, fp); 2144a1645ce1SZhang, Yanmin } 2145cbf69680SArnaldo Carvalho de Melo 2146cbf69680SArnaldo Carvalho de Melo return ret; 2147b0da954aSArnaldo Carvalho de Melo } 2148b0da954aSArnaldo Carvalho de Melo 214988d3d9b7SArnaldo Carvalho de Melo static size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp, 215088d3d9b7SArnaldo Carvalho de Melo bool with_hits) 21519e03eb2dSArnaldo Carvalho de Melo { 21529e03eb2dSArnaldo Carvalho de Melo struct dso *pos; 21539e03eb2dSArnaldo Carvalho de Melo size_t ret = 0; 21549e03eb2dSArnaldo Carvalho de Melo 2155b0da954aSArnaldo Carvalho de Melo list_for_each_entry(pos, head, node) { 215688d3d9b7SArnaldo Carvalho de Melo if (with_hits && !pos->hit) 215788d3d9b7SArnaldo Carvalho de Melo continue; 21589e03eb2dSArnaldo Carvalho de Melo ret += dso__fprintf_buildid(pos, fp); 21599e03eb2dSArnaldo Carvalho de Melo ret += fprintf(fp, " %s\n", pos->long_name); 21609e03eb2dSArnaldo Carvalho de Melo } 21619e03eb2dSArnaldo Carvalho de Melo return ret; 21629e03eb2dSArnaldo Carvalho de Melo } 21639e03eb2dSArnaldo Carvalho de Melo 2164aeafcbafSArnaldo Carvalho de Melo size_t machine__fprintf_dsos_buildid(struct machine *machine, FILE *fp, 2165aeafcbafSArnaldo Carvalho de Melo bool with_hits) 2166f869097eSArnaldo Carvalho de Melo { 2167aeafcbafSArnaldo Carvalho de Melo return __dsos__fprintf_buildid(&machine->kernel_dsos, fp, with_hits) + 2168aeafcbafSArnaldo Carvalho de Melo __dsos__fprintf_buildid(&machine->user_dsos, fp, with_hits); 2169f869097eSArnaldo Carvalho de Melo } 2170f869097eSArnaldo Carvalho de Melo 2171aeafcbafSArnaldo Carvalho de Melo size_t machines__fprintf_dsos_buildid(struct rb_root *machines, 2172aeafcbafSArnaldo Carvalho de Melo FILE *fp, bool with_hits) 2173b0da954aSArnaldo Carvalho de Melo { 2174a1645ce1SZhang, Yanmin struct rb_node *nd; 2175a1645ce1SZhang, Yanmin size_t ret = 0; 2176a1645ce1SZhang, Yanmin 2177aeafcbafSArnaldo Carvalho de Melo for (nd = rb_first(machines); nd; nd = rb_next(nd)) { 217823346f21SArnaldo Carvalho de Melo struct machine *pos = rb_entry(nd, struct machine, rb_node); 2179f869097eSArnaldo Carvalho de Melo ret += machine__fprintf_dsos_buildid(pos, fp, with_hits); 2180a1645ce1SZhang, Yanmin } 2181a1645ce1SZhang, Yanmin return ret; 2182b0da954aSArnaldo Carvalho de Melo } 2183b0da954aSArnaldo Carvalho de Melo 2184f57b05edSJiri Olsa static struct dso* 2185f57b05edSJiri Olsa dso__kernel_findnew(struct machine *machine, const char *name, 2186f57b05edSJiri Olsa const char *short_name, int dso_type) 2187fd1d908cSArnaldo Carvalho de Melo { 2188f57b05edSJiri Olsa /* 2189f57b05edSJiri Olsa * The kernel dso could be created by build_id processing. 2190f57b05edSJiri Olsa */ 2191f57b05edSJiri Olsa struct dso *dso = __dsos__findnew(&machine->kernel_dsos, name); 2192fd1d908cSArnaldo Carvalho de Melo 2193f57b05edSJiri Olsa /* 2194f57b05edSJiri Olsa * We need to run this in all cases, since during the build_id 2195f57b05edSJiri Olsa * processing we had no idea this was the kernel dso. 2196f57b05edSJiri Olsa */ 2197aeafcbafSArnaldo Carvalho de Melo if (dso != NULL) { 2198f57b05edSJiri Olsa dso__set_short_name(dso, short_name); 2199f57b05edSJiri Olsa dso->kernel = dso_type; 2200a1645ce1SZhang, Yanmin } 2201a1645ce1SZhang, Yanmin 2202aeafcbafSArnaldo Carvalho de Melo return dso; 2203a1645ce1SZhang, Yanmin } 2204a1645ce1SZhang, Yanmin 2205aeafcbafSArnaldo Carvalho de Melo void dso__read_running_kernel_build_id(struct dso *dso, struct machine *machine) 2206a1645ce1SZhang, Yanmin { 2207a1645ce1SZhang, Yanmin char path[PATH_MAX]; 2208a1645ce1SZhang, Yanmin 220923346f21SArnaldo Carvalho de Melo if (machine__is_default_guest(machine)) 2210a1645ce1SZhang, Yanmin return; 221123346f21SArnaldo Carvalho de Melo sprintf(path, "%s/sys/kernel/notes", machine->root_dir); 2212aeafcbafSArnaldo Carvalho de Melo if (sysfs__read_build_id(path, dso->build_id, 2213aeafcbafSArnaldo Carvalho de Melo sizeof(dso->build_id)) == 0) 2214aeafcbafSArnaldo Carvalho de Melo dso->has_build_id = true; 2215fd1d908cSArnaldo Carvalho de Melo } 2216fd1d908cSArnaldo Carvalho de Melo 2217f57b05edSJiri Olsa static struct dso *machine__get_kernel(struct machine *machine) 2218cd84c2acSFrederic Weisbecker { 2219a1645ce1SZhang, Yanmin const char *vmlinux_name = NULL; 2220a1645ce1SZhang, Yanmin struct dso *kernel; 2221cd84c2acSFrederic Weisbecker 2222aeafcbafSArnaldo Carvalho de Melo if (machine__is_host(machine)) { 2223a1645ce1SZhang, Yanmin vmlinux_name = symbol_conf.vmlinux_name; 2224f57b05edSJiri Olsa if (!vmlinux_name) 2225f57b05edSJiri Olsa vmlinux_name = "[kernel.kallsyms]"; 2226f57b05edSJiri Olsa 2227f57b05edSJiri Olsa kernel = dso__kernel_findnew(machine, vmlinux_name, 2228f57b05edSJiri Olsa "[kernel]", 2229f57b05edSJiri Olsa DSO_TYPE_KERNEL); 2230a1645ce1SZhang, Yanmin } else { 2231f57b05edSJiri Olsa char bf[PATH_MAX]; 2232f57b05edSJiri Olsa 2233aeafcbafSArnaldo Carvalho de Melo if (machine__is_default_guest(machine)) 2234a1645ce1SZhang, Yanmin vmlinux_name = symbol_conf.default_guest_vmlinux_name; 2235f57b05edSJiri Olsa if (!vmlinux_name) 2236f57b05edSJiri Olsa vmlinux_name = machine__mmap_name(machine, bf, 2237f57b05edSJiri Olsa sizeof(bf)); 2238f57b05edSJiri Olsa 2239f57b05edSJiri Olsa kernel = dso__kernel_findnew(machine, vmlinux_name, 2240f57b05edSJiri Olsa "[guest.kernel]", 2241f57b05edSJiri Olsa DSO_TYPE_GUEST_KERNEL); 22428d92c02aSArnaldo Carvalho de Melo } 2243cd84c2acSFrederic Weisbecker 2244f57b05edSJiri Olsa if (kernel != NULL && (!kernel->has_build_id)) 2245aeafcbafSArnaldo Carvalho de Melo dso__read_running_kernel_build_id(kernel, machine); 2246f57b05edSJiri Olsa 2247f1dfa0b1SArnaldo Carvalho de Melo return kernel; 2248f1dfa0b1SArnaldo Carvalho de Melo } 2249f1dfa0b1SArnaldo Carvalho de Melo 2250d214afbdSMing Lei struct process_args { 2251d214afbdSMing Lei u64 start; 2252d214afbdSMing Lei }; 2253d214afbdSMing Lei 2254d214afbdSMing Lei static int symbol__in_kernel(void *arg, const char *name, 22553b01a413SArnaldo Carvalho de Melo char type __used, u64 start, u64 end __used) 2256d214afbdSMing Lei { 2257d214afbdSMing Lei struct process_args *args = arg; 2258d214afbdSMing Lei 2259d214afbdSMing Lei if (strchr(name, '[')) 2260d214afbdSMing Lei return 0; 2261d214afbdSMing Lei 2262d214afbdSMing Lei args->start = start; 2263d214afbdSMing Lei return 1; 2264d214afbdSMing Lei } 2265d214afbdSMing Lei 2266d214afbdSMing Lei /* Figure out the start address of kernel map from /proc/kallsyms */ 2267d214afbdSMing Lei static u64 machine__get_kernel_start_addr(struct machine *machine) 2268d214afbdSMing Lei { 2269d214afbdSMing Lei const char *filename; 2270d214afbdSMing Lei char path[PATH_MAX]; 2271d214afbdSMing Lei struct process_args args; 2272d214afbdSMing Lei 2273d214afbdSMing Lei if (machine__is_host(machine)) { 2274d214afbdSMing Lei filename = "/proc/kallsyms"; 2275d214afbdSMing Lei } else { 2276d214afbdSMing Lei if (machine__is_default_guest(machine)) 2277d214afbdSMing Lei filename = (char *)symbol_conf.default_guest_kallsyms; 2278d214afbdSMing Lei else { 2279d214afbdSMing Lei sprintf(path, "%s/proc/kallsyms", machine->root_dir); 2280d214afbdSMing Lei filename = path; 2281d214afbdSMing Lei } 2282d214afbdSMing Lei } 2283d214afbdSMing Lei 2284ec80fde7SArnaldo Carvalho de Melo if (symbol__restricted_filename(filename, "/proc/kallsyms")) 2285ec80fde7SArnaldo Carvalho de Melo return 0; 2286ec80fde7SArnaldo Carvalho de Melo 2287d214afbdSMing Lei if (kallsyms__parse(filename, &args, symbol__in_kernel) <= 0) 2288d214afbdSMing Lei return 0; 2289d214afbdSMing Lei 2290d214afbdSMing Lei return args.start; 2291d214afbdSMing Lei } 2292d214afbdSMing Lei 2293aeafcbafSArnaldo Carvalho de Melo int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel) 2294f1dfa0b1SArnaldo Carvalho de Melo { 2295de176489SArnaldo Carvalho de Melo enum map_type type; 2296aeafcbafSArnaldo Carvalho de Melo u64 start = machine__get_kernel_start_addr(machine); 2297f1dfa0b1SArnaldo Carvalho de Melo 2298de176489SArnaldo Carvalho de Melo for (type = 0; type < MAP__NR_TYPES; ++type) { 22999de89fe7SArnaldo Carvalho de Melo struct kmap *kmap; 23009de89fe7SArnaldo Carvalho de Melo 2301aeafcbafSArnaldo Carvalho de Melo machine->vmlinux_maps[type] = map__new2(start, kernel, type); 2302aeafcbafSArnaldo Carvalho de Melo if (machine->vmlinux_maps[type] == NULL) 2303f1dfa0b1SArnaldo Carvalho de Melo return -1; 2304f1dfa0b1SArnaldo Carvalho de Melo 2305aeafcbafSArnaldo Carvalho de Melo machine->vmlinux_maps[type]->map_ip = 2306aeafcbafSArnaldo Carvalho de Melo machine->vmlinux_maps[type]->unmap_ip = 2307aeafcbafSArnaldo Carvalho de Melo identity__map_ip; 2308aeafcbafSArnaldo Carvalho de Melo kmap = map__kmap(machine->vmlinux_maps[type]); 2309aeafcbafSArnaldo Carvalho de Melo kmap->kmaps = &machine->kmaps; 2310aeafcbafSArnaldo Carvalho de Melo map_groups__insert(&machine->kmaps, 2311aeafcbafSArnaldo Carvalho de Melo machine->vmlinux_maps[type]); 2312f1dfa0b1SArnaldo Carvalho de Melo } 2313f1dfa0b1SArnaldo Carvalho de Melo 2314f1dfa0b1SArnaldo Carvalho de Melo return 0; 23152446042cSArnaldo Carvalho de Melo } 23162446042cSArnaldo Carvalho de Melo 2317aeafcbafSArnaldo Carvalho de Melo void machine__destroy_kernel_maps(struct machine *machine) 2318076c6e45SArnaldo Carvalho de Melo { 2319076c6e45SArnaldo Carvalho de Melo enum map_type type; 2320076c6e45SArnaldo Carvalho de Melo 2321076c6e45SArnaldo Carvalho de Melo for (type = 0; type < MAP__NR_TYPES; ++type) { 2322076c6e45SArnaldo Carvalho de Melo struct kmap *kmap; 2323076c6e45SArnaldo Carvalho de Melo 2324aeafcbafSArnaldo Carvalho de Melo if (machine->vmlinux_maps[type] == NULL) 2325076c6e45SArnaldo Carvalho de Melo continue; 2326076c6e45SArnaldo Carvalho de Melo 2327aeafcbafSArnaldo Carvalho de Melo kmap = map__kmap(machine->vmlinux_maps[type]); 2328aeafcbafSArnaldo Carvalho de Melo map_groups__remove(&machine->kmaps, 2329aeafcbafSArnaldo Carvalho de Melo machine->vmlinux_maps[type]); 2330076c6e45SArnaldo Carvalho de Melo if (kmap->ref_reloc_sym) { 2331076c6e45SArnaldo Carvalho de Melo /* 2332076c6e45SArnaldo Carvalho de Melo * ref_reloc_sym is shared among all maps, so free just 2333076c6e45SArnaldo Carvalho de Melo * on one of them. 2334076c6e45SArnaldo Carvalho de Melo */ 2335076c6e45SArnaldo Carvalho de Melo if (type == MAP__FUNCTION) { 2336076c6e45SArnaldo Carvalho de Melo free((char *)kmap->ref_reloc_sym->name); 2337076c6e45SArnaldo Carvalho de Melo kmap->ref_reloc_sym->name = NULL; 2338076c6e45SArnaldo Carvalho de Melo free(kmap->ref_reloc_sym); 2339076c6e45SArnaldo Carvalho de Melo } 2340076c6e45SArnaldo Carvalho de Melo kmap->ref_reloc_sym = NULL; 2341076c6e45SArnaldo Carvalho de Melo } 2342076c6e45SArnaldo Carvalho de Melo 2343aeafcbafSArnaldo Carvalho de Melo map__delete(machine->vmlinux_maps[type]); 2344aeafcbafSArnaldo Carvalho de Melo machine->vmlinux_maps[type] = NULL; 2345076c6e45SArnaldo Carvalho de Melo } 2346076c6e45SArnaldo Carvalho de Melo } 2347076c6e45SArnaldo Carvalho de Melo 2348aeafcbafSArnaldo Carvalho de Melo int machine__create_kernel_maps(struct machine *machine) 23495c0541d5SArnaldo Carvalho de Melo { 2350f57b05edSJiri Olsa struct dso *kernel = machine__get_kernel(machine); 23515c0541d5SArnaldo Carvalho de Melo 23525c0541d5SArnaldo Carvalho de Melo if (kernel == NULL || 2353aeafcbafSArnaldo Carvalho de Melo __machine__create_kernel_maps(machine, kernel) < 0) 23545c0541d5SArnaldo Carvalho de Melo return -1; 23555c0541d5SArnaldo Carvalho de Melo 2356aeafcbafSArnaldo Carvalho de Melo if (symbol_conf.use_modules && machine__create_modules(machine) < 0) 23575c0541d5SArnaldo Carvalho de Melo pr_debug("Problems creating module maps, continuing anyway...\n"); 23585c0541d5SArnaldo Carvalho de Melo /* 23595c0541d5SArnaldo Carvalho de Melo * Now that we have all the maps created, just set the ->end of them: 23605c0541d5SArnaldo Carvalho de Melo */ 2361aeafcbafSArnaldo Carvalho de Melo map_groups__fixup_end(&machine->kmaps); 23625c0541d5SArnaldo Carvalho de Melo return 0; 23635c0541d5SArnaldo Carvalho de Melo } 23645c0541d5SArnaldo Carvalho de Melo 2365cc612d81SArnaldo Carvalho de Melo static void vmlinux_path__exit(void) 23662446042cSArnaldo Carvalho de Melo { 2367cc612d81SArnaldo Carvalho de Melo while (--vmlinux_path__nr_entries >= 0) { 2368cc612d81SArnaldo Carvalho de Melo free(vmlinux_path[vmlinux_path__nr_entries]); 2369cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = NULL; 2370cc612d81SArnaldo Carvalho de Melo } 2371cc612d81SArnaldo Carvalho de Melo 2372cc612d81SArnaldo Carvalho de Melo free(vmlinux_path); 2373cc612d81SArnaldo Carvalho de Melo vmlinux_path = NULL; 2374cc612d81SArnaldo Carvalho de Melo } 2375cc612d81SArnaldo Carvalho de Melo 2376cc612d81SArnaldo Carvalho de Melo static int vmlinux_path__init(void) 2377cc612d81SArnaldo Carvalho de Melo { 2378cc612d81SArnaldo Carvalho de Melo struct utsname uts; 2379cc612d81SArnaldo Carvalho de Melo char bf[PATH_MAX]; 2380cc612d81SArnaldo Carvalho de Melo 2381cc612d81SArnaldo Carvalho de Melo vmlinux_path = malloc(sizeof(char *) * 5); 2382cc612d81SArnaldo Carvalho de Melo if (vmlinux_path == NULL) 2383cc612d81SArnaldo Carvalho de Melo return -1; 2384cc612d81SArnaldo Carvalho de Melo 2385cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup("vmlinux"); 2386cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 2387cc612d81SArnaldo Carvalho de Melo goto out_fail; 2388cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 2389cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup("/boot/vmlinux"); 2390cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 2391cc612d81SArnaldo Carvalho de Melo goto out_fail; 2392cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 2393ec5761eaSDavid Ahern 2394ec5761eaSDavid Ahern /* only try running kernel version if no symfs was given */ 2395ec5761eaSDavid Ahern if (symbol_conf.symfs[0] != 0) 2396ec5761eaSDavid Ahern return 0; 2397ec5761eaSDavid Ahern 2398ec5761eaSDavid Ahern if (uname(&uts) < 0) 2399ec5761eaSDavid Ahern return -1; 2400ec5761eaSDavid Ahern 2401cc612d81SArnaldo Carvalho de Melo snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", uts.release); 2402cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); 2403cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 2404cc612d81SArnaldo Carvalho de Melo goto out_fail; 2405cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 2406cc612d81SArnaldo Carvalho de Melo snprintf(bf, sizeof(bf), "/lib/modules/%s/build/vmlinux", uts.release); 2407cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); 2408cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 2409cc612d81SArnaldo Carvalho de Melo goto out_fail; 2410cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 2411cc612d81SArnaldo Carvalho de Melo snprintf(bf, sizeof(bf), "/usr/lib/debug/lib/modules/%s/vmlinux", 2412cc612d81SArnaldo Carvalho de Melo uts.release); 2413cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); 2414cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 2415cc612d81SArnaldo Carvalho de Melo goto out_fail; 2416cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 2417cc612d81SArnaldo Carvalho de Melo 2418cc612d81SArnaldo Carvalho de Melo return 0; 2419cc612d81SArnaldo Carvalho de Melo 2420cc612d81SArnaldo Carvalho de Melo out_fail: 2421cc612d81SArnaldo Carvalho de Melo vmlinux_path__exit(); 2422cc612d81SArnaldo Carvalho de Melo return -1; 2423cc612d81SArnaldo Carvalho de Melo } 2424cc612d81SArnaldo Carvalho de Melo 2425aeafcbafSArnaldo Carvalho de Melo size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp) 2426b0a9ab62SArnaldo Carvalho de Melo { 2427b0a9ab62SArnaldo Carvalho de Melo int i; 2428b0a9ab62SArnaldo Carvalho de Melo size_t printed = 0; 2429aeafcbafSArnaldo Carvalho de Melo struct dso *kdso = machine->vmlinux_maps[MAP__FUNCTION]->dso; 24305ad90e4eSArnaldo Carvalho de Melo 24315ad90e4eSArnaldo Carvalho de Melo if (kdso->has_build_id) { 24325ad90e4eSArnaldo Carvalho de Melo char filename[PATH_MAX]; 24335ad90e4eSArnaldo Carvalho de Melo if (dso__build_id_filename(kdso, filename, sizeof(filename))) 24345ad90e4eSArnaldo Carvalho de Melo printed += fprintf(fp, "[0] %s\n", filename); 24355ad90e4eSArnaldo Carvalho de Melo } 2436b0a9ab62SArnaldo Carvalho de Melo 2437b0a9ab62SArnaldo Carvalho de Melo for (i = 0; i < vmlinux_path__nr_entries; ++i) 24385ad90e4eSArnaldo Carvalho de Melo printed += fprintf(fp, "[%d] %s\n", 24395ad90e4eSArnaldo Carvalho de Melo i + kdso->has_build_id, vmlinux_path[i]); 2440b0a9ab62SArnaldo Carvalho de Melo 2441b0a9ab62SArnaldo Carvalho de Melo return printed; 2442b0a9ab62SArnaldo Carvalho de Melo } 2443b0a9ab62SArnaldo Carvalho de Melo 2444655000e7SArnaldo Carvalho de Melo static int setup_list(struct strlist **list, const char *list_str, 2445655000e7SArnaldo Carvalho de Melo const char *list_name) 2446655000e7SArnaldo Carvalho de Melo { 2447655000e7SArnaldo Carvalho de Melo if (list_str == NULL) 2448655000e7SArnaldo Carvalho de Melo return 0; 2449655000e7SArnaldo Carvalho de Melo 2450655000e7SArnaldo Carvalho de Melo *list = strlist__new(true, list_str); 2451655000e7SArnaldo Carvalho de Melo if (!*list) { 2452655000e7SArnaldo Carvalho de Melo pr_err("problems parsing %s list\n", list_name); 2453655000e7SArnaldo Carvalho de Melo return -1; 2454655000e7SArnaldo Carvalho de Melo } 2455655000e7SArnaldo Carvalho de Melo return 0; 2456655000e7SArnaldo Carvalho de Melo } 2457655000e7SArnaldo Carvalho de Melo 2458ec80fde7SArnaldo Carvalho de Melo static bool symbol__read_kptr_restrict(void) 2459ec80fde7SArnaldo Carvalho de Melo { 2460ec80fde7SArnaldo Carvalho de Melo bool value = false; 2461ec80fde7SArnaldo Carvalho de Melo 2462ec80fde7SArnaldo Carvalho de Melo if (geteuid() != 0) { 2463ec80fde7SArnaldo Carvalho de Melo FILE *fp = fopen("/proc/sys/kernel/kptr_restrict", "r"); 2464ec80fde7SArnaldo Carvalho de Melo if (fp != NULL) { 2465ec80fde7SArnaldo Carvalho de Melo char line[8]; 2466ec80fde7SArnaldo Carvalho de Melo 2467ec80fde7SArnaldo Carvalho de Melo if (fgets(line, sizeof(line), fp) != NULL) 2468ec80fde7SArnaldo Carvalho de Melo value = atoi(line) != 0; 2469ec80fde7SArnaldo Carvalho de Melo 2470ec80fde7SArnaldo Carvalho de Melo fclose(fp); 2471ec80fde7SArnaldo Carvalho de Melo } 2472ec80fde7SArnaldo Carvalho de Melo } 2473ec80fde7SArnaldo Carvalho de Melo 2474ec80fde7SArnaldo Carvalho de Melo return value; 2475ec80fde7SArnaldo Carvalho de Melo } 2476ec80fde7SArnaldo Carvalho de Melo 247775be6cf4SArnaldo Carvalho de Melo int symbol__init(void) 2478cc612d81SArnaldo Carvalho de Melo { 2479ec5761eaSDavid Ahern const char *symfs; 2480ec5761eaSDavid Ahern 248185e00b55SJovi Zhang if (symbol_conf.initialized) 248285e00b55SJovi Zhang return 0; 248385e00b55SJovi Zhang 24844d439517SDavid S. Miller symbol_conf.priv_size = ALIGN(symbol_conf.priv_size, sizeof(u64)); 24854d439517SDavid S. Miller 248695011c60SArnaldo Carvalho de Melo elf_version(EV_CURRENT); 248775be6cf4SArnaldo Carvalho de Melo if (symbol_conf.sort_by_name) 248875be6cf4SArnaldo Carvalho de Melo symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) - 248979406cd7SArnaldo Carvalho de Melo sizeof(struct symbol)); 2490b32d133aSArnaldo Carvalho de Melo 249175be6cf4SArnaldo Carvalho de Melo if (symbol_conf.try_vmlinux_path && vmlinux_path__init() < 0) 2492cc612d81SArnaldo Carvalho de Melo return -1; 2493cc612d81SArnaldo Carvalho de Melo 2494c410a338SArnaldo Carvalho de Melo if (symbol_conf.field_sep && *symbol_conf.field_sep == '.') { 2495c410a338SArnaldo Carvalho de Melo pr_err("'.' is the only non valid --field-separator argument\n"); 2496c410a338SArnaldo Carvalho de Melo return -1; 2497c410a338SArnaldo Carvalho de Melo } 2498c410a338SArnaldo Carvalho de Melo 2499655000e7SArnaldo Carvalho de Melo if (setup_list(&symbol_conf.dso_list, 2500655000e7SArnaldo Carvalho de Melo symbol_conf.dso_list_str, "dso") < 0) 2501655000e7SArnaldo Carvalho de Melo return -1; 2502655000e7SArnaldo Carvalho de Melo 2503655000e7SArnaldo Carvalho de Melo if (setup_list(&symbol_conf.comm_list, 2504655000e7SArnaldo Carvalho de Melo symbol_conf.comm_list_str, "comm") < 0) 2505655000e7SArnaldo Carvalho de Melo goto out_free_dso_list; 2506655000e7SArnaldo Carvalho de Melo 2507655000e7SArnaldo Carvalho de Melo if (setup_list(&symbol_conf.sym_list, 2508655000e7SArnaldo Carvalho de Melo symbol_conf.sym_list_str, "symbol") < 0) 2509655000e7SArnaldo Carvalho de Melo goto out_free_comm_list; 2510655000e7SArnaldo Carvalho de Melo 2511ec5761eaSDavid Ahern /* 2512ec5761eaSDavid Ahern * A path to symbols of "/" is identical to "" 2513ec5761eaSDavid Ahern * reset here for simplicity. 2514ec5761eaSDavid Ahern */ 2515ec5761eaSDavid Ahern symfs = realpath(symbol_conf.symfs, NULL); 2516ec5761eaSDavid Ahern if (symfs == NULL) 2517ec5761eaSDavid Ahern symfs = symbol_conf.symfs; 2518ec5761eaSDavid Ahern if (strcmp(symfs, "/") == 0) 2519ec5761eaSDavid Ahern symbol_conf.symfs = ""; 2520ec5761eaSDavid Ahern if (symfs != symbol_conf.symfs) 2521ec5761eaSDavid Ahern free((void *)symfs); 2522ec5761eaSDavid Ahern 2523ec80fde7SArnaldo Carvalho de Melo symbol_conf.kptr_restrict = symbol__read_kptr_restrict(); 2524ec80fde7SArnaldo Carvalho de Melo 252585e00b55SJovi Zhang symbol_conf.initialized = true; 25264aa65636SArnaldo Carvalho de Melo return 0; 2527655000e7SArnaldo Carvalho de Melo 2528655000e7SArnaldo Carvalho de Melo out_free_dso_list: 2529655000e7SArnaldo Carvalho de Melo strlist__delete(symbol_conf.dso_list); 2530655000e7SArnaldo Carvalho de Melo out_free_comm_list: 2531655000e7SArnaldo Carvalho de Melo strlist__delete(symbol_conf.comm_list); 2532655000e7SArnaldo Carvalho de Melo return -1; 2533cc612d81SArnaldo Carvalho de Melo } 2534cc612d81SArnaldo Carvalho de Melo 2535d65a458bSArnaldo Carvalho de Melo void symbol__exit(void) 2536d65a458bSArnaldo Carvalho de Melo { 253785e00b55SJovi Zhang if (!symbol_conf.initialized) 253885e00b55SJovi Zhang return; 2539d65a458bSArnaldo Carvalho de Melo strlist__delete(symbol_conf.sym_list); 2540d65a458bSArnaldo Carvalho de Melo strlist__delete(symbol_conf.dso_list); 2541d65a458bSArnaldo Carvalho de Melo strlist__delete(symbol_conf.comm_list); 2542d65a458bSArnaldo Carvalho de Melo vmlinux_path__exit(); 2543d65a458bSArnaldo Carvalho de Melo symbol_conf.sym_list = symbol_conf.dso_list = symbol_conf.comm_list = NULL; 254485e00b55SJovi Zhang symbol_conf.initialized = false; 2545d65a458bSArnaldo Carvalho de Melo } 2546d65a458bSArnaldo Carvalho de Melo 2547aeafcbafSArnaldo Carvalho de Melo int machines__create_kernel_maps(struct rb_root *machines, pid_t pid) 25484aa65636SArnaldo Carvalho de Melo { 2549aeafcbafSArnaldo Carvalho de Melo struct machine *machine = machines__findnew(machines, pid); 25509de89fe7SArnaldo Carvalho de Melo 255123346f21SArnaldo Carvalho de Melo if (machine == NULL) 2552a1645ce1SZhang, Yanmin return -1; 25534aa65636SArnaldo Carvalho de Melo 25545c0541d5SArnaldo Carvalho de Melo return machine__create_kernel_maps(machine); 2555cd84c2acSFrederic Weisbecker } 25565aab621bSArnaldo Carvalho de Melo 25575aab621bSArnaldo Carvalho de Melo static int hex(char ch) 25585aab621bSArnaldo Carvalho de Melo { 25595aab621bSArnaldo Carvalho de Melo if ((ch >= '0') && (ch <= '9')) 25605aab621bSArnaldo Carvalho de Melo return ch - '0'; 25615aab621bSArnaldo Carvalho de Melo if ((ch >= 'a') && (ch <= 'f')) 25625aab621bSArnaldo Carvalho de Melo return ch - 'a' + 10; 25635aab621bSArnaldo Carvalho de Melo if ((ch >= 'A') && (ch <= 'F')) 25645aab621bSArnaldo Carvalho de Melo return ch - 'A' + 10; 25655aab621bSArnaldo Carvalho de Melo return -1; 25665aab621bSArnaldo Carvalho de Melo } 25675aab621bSArnaldo Carvalho de Melo 25685aab621bSArnaldo Carvalho de Melo /* 25695aab621bSArnaldo Carvalho de Melo * While we find nice hex chars, build a long_val. 25705aab621bSArnaldo Carvalho de Melo * Return number of chars processed. 25715aab621bSArnaldo Carvalho de Melo */ 25725aab621bSArnaldo Carvalho de Melo int hex2u64(const char *ptr, u64 *long_val) 25735aab621bSArnaldo Carvalho de Melo { 25745aab621bSArnaldo Carvalho de Melo const char *p = ptr; 25755aab621bSArnaldo Carvalho de Melo *long_val = 0; 25765aab621bSArnaldo Carvalho de Melo 25775aab621bSArnaldo Carvalho de Melo while (*p) { 25785aab621bSArnaldo Carvalho de Melo const int hex_val = hex(*p); 25795aab621bSArnaldo Carvalho de Melo 25805aab621bSArnaldo Carvalho de Melo if (hex_val < 0) 25815aab621bSArnaldo Carvalho de Melo break; 25825aab621bSArnaldo Carvalho de Melo 25835aab621bSArnaldo Carvalho de Melo *long_val = (*long_val << 4) | hex_val; 25845aab621bSArnaldo Carvalho de Melo p++; 25855aab621bSArnaldo Carvalho de Melo } 25865aab621bSArnaldo Carvalho de Melo 25875aab621bSArnaldo Carvalho de Melo return p - ptr; 25885aab621bSArnaldo Carvalho de Melo } 25895aab621bSArnaldo Carvalho de Melo 25905aab621bSArnaldo Carvalho de Melo char *strxfrchar(char *s, char from, char to) 25915aab621bSArnaldo Carvalho de Melo { 25925aab621bSArnaldo Carvalho de Melo char *p = s; 25935aab621bSArnaldo Carvalho de Melo 25945aab621bSArnaldo Carvalho de Melo while ((p = strchr(p, from)) != NULL) 25955aab621bSArnaldo Carvalho de Melo *p++ = to; 25965aab621bSArnaldo Carvalho de Melo 25975aab621bSArnaldo Carvalho de Melo return s; 25985aab621bSArnaldo Carvalho de Melo } 2599a1645ce1SZhang, Yanmin 2600aeafcbafSArnaldo Carvalho de Melo int machines__create_guest_kernel_maps(struct rb_root *machines) 2601a1645ce1SZhang, Yanmin { 2602a1645ce1SZhang, Yanmin int ret = 0; 2603a1645ce1SZhang, Yanmin struct dirent **namelist = NULL; 2604a1645ce1SZhang, Yanmin int i, items = 0; 2605a1645ce1SZhang, Yanmin char path[PATH_MAX]; 2606a1645ce1SZhang, Yanmin pid_t pid; 2607a1645ce1SZhang, Yanmin 2608a1645ce1SZhang, Yanmin if (symbol_conf.default_guest_vmlinux_name || 2609a1645ce1SZhang, Yanmin symbol_conf.default_guest_modules || 2610a1645ce1SZhang, Yanmin symbol_conf.default_guest_kallsyms) { 2611aeafcbafSArnaldo Carvalho de Melo machines__create_kernel_maps(machines, DEFAULT_GUEST_KERNEL_ID); 2612a1645ce1SZhang, Yanmin } 2613a1645ce1SZhang, Yanmin 2614a1645ce1SZhang, Yanmin if (symbol_conf.guestmount) { 2615a1645ce1SZhang, Yanmin items = scandir(symbol_conf.guestmount, &namelist, NULL, NULL); 2616a1645ce1SZhang, Yanmin if (items <= 0) 2617a1645ce1SZhang, Yanmin return -ENOENT; 2618a1645ce1SZhang, Yanmin for (i = 0; i < items; i++) { 2619a1645ce1SZhang, Yanmin if (!isdigit(namelist[i]->d_name[0])) { 2620a1645ce1SZhang, Yanmin /* Filter out . and .. */ 2621a1645ce1SZhang, Yanmin continue; 2622a1645ce1SZhang, Yanmin } 2623a1645ce1SZhang, Yanmin pid = atoi(namelist[i]->d_name); 2624a1645ce1SZhang, Yanmin sprintf(path, "%s/%s/proc/kallsyms", 2625a1645ce1SZhang, Yanmin symbol_conf.guestmount, 2626a1645ce1SZhang, Yanmin namelist[i]->d_name); 2627a1645ce1SZhang, Yanmin ret = access(path, R_OK); 2628a1645ce1SZhang, Yanmin if (ret) { 2629a1645ce1SZhang, Yanmin pr_debug("Can't access file %s\n", path); 2630a1645ce1SZhang, Yanmin goto failure; 2631a1645ce1SZhang, Yanmin } 2632aeafcbafSArnaldo Carvalho de Melo machines__create_kernel_maps(machines, pid); 2633a1645ce1SZhang, Yanmin } 2634a1645ce1SZhang, Yanmin failure: 2635a1645ce1SZhang, Yanmin free(namelist); 2636a1645ce1SZhang, Yanmin } 2637a1645ce1SZhang, Yanmin 2638a1645ce1SZhang, Yanmin return ret; 2639a1645ce1SZhang, Yanmin } 26405c0541d5SArnaldo Carvalho de Melo 2641aeafcbafSArnaldo Carvalho de Melo void machines__destroy_guest_kernel_maps(struct rb_root *machines) 2642076c6e45SArnaldo Carvalho de Melo { 2643aeafcbafSArnaldo Carvalho de Melo struct rb_node *next = rb_first(machines); 2644076c6e45SArnaldo Carvalho de Melo 2645076c6e45SArnaldo Carvalho de Melo while (next) { 2646076c6e45SArnaldo Carvalho de Melo struct machine *pos = rb_entry(next, struct machine, rb_node); 2647076c6e45SArnaldo Carvalho de Melo 2648076c6e45SArnaldo Carvalho de Melo next = rb_next(&pos->rb_node); 2649aeafcbafSArnaldo Carvalho de Melo rb_erase(&pos->rb_node, machines); 2650076c6e45SArnaldo Carvalho de Melo machine__delete(pos); 2651076c6e45SArnaldo Carvalho de Melo } 2652076c6e45SArnaldo Carvalho de Melo } 2653076c6e45SArnaldo Carvalho de Melo 2654aeafcbafSArnaldo Carvalho de Melo int machine__load_kallsyms(struct machine *machine, const char *filename, 26555c0541d5SArnaldo Carvalho de Melo enum map_type type, symbol_filter_t filter) 26565c0541d5SArnaldo Carvalho de Melo { 2657aeafcbafSArnaldo Carvalho de Melo struct map *map = machine->vmlinux_maps[type]; 26585c0541d5SArnaldo Carvalho de Melo int ret = dso__load_kallsyms(map->dso, filename, map, filter); 26595c0541d5SArnaldo Carvalho de Melo 26605c0541d5SArnaldo Carvalho de Melo if (ret > 0) { 26615c0541d5SArnaldo Carvalho de Melo dso__set_loaded(map->dso, type); 26625c0541d5SArnaldo Carvalho de Melo /* 26635c0541d5SArnaldo Carvalho de Melo * Since /proc/kallsyms will have multiple sessions for the 26645c0541d5SArnaldo Carvalho de Melo * kernel, with modules between them, fixup the end of all 26655c0541d5SArnaldo Carvalho de Melo * sections. 26665c0541d5SArnaldo Carvalho de Melo */ 2667aeafcbafSArnaldo Carvalho de Melo __map_groups__fixup_end(&machine->kmaps, type); 26685c0541d5SArnaldo Carvalho de Melo } 26695c0541d5SArnaldo Carvalho de Melo 26705c0541d5SArnaldo Carvalho de Melo return ret; 26715c0541d5SArnaldo Carvalho de Melo } 26725c0541d5SArnaldo Carvalho de Melo 2673aeafcbafSArnaldo Carvalho de Melo int machine__load_vmlinux_path(struct machine *machine, enum map_type type, 26745c0541d5SArnaldo Carvalho de Melo symbol_filter_t filter) 26755c0541d5SArnaldo Carvalho de Melo { 2676aeafcbafSArnaldo Carvalho de Melo struct map *map = machine->vmlinux_maps[type]; 26775c0541d5SArnaldo Carvalho de Melo int ret = dso__load_vmlinux_path(map->dso, map, filter); 26785c0541d5SArnaldo Carvalho de Melo 26795c0541d5SArnaldo Carvalho de Melo if (ret > 0) { 26805c0541d5SArnaldo Carvalho de Melo dso__set_loaded(map->dso, type); 26815c0541d5SArnaldo Carvalho de Melo map__reloc_vmlinux(map); 26825c0541d5SArnaldo Carvalho de Melo } 26835c0541d5SArnaldo Carvalho de Melo 26845c0541d5SArnaldo Carvalho de Melo return ret; 26855c0541d5SArnaldo Carvalho de Melo } 2686