186470930SIngo Molnar #include "util.h" 286470930SIngo Molnar #include "../perf.h" 386470930SIngo Molnar #include "string.h" 486470930SIngo Molnar #include "symbol.h" 5439d473bSArnaldo Carvalho de Melo #include "thread.h" 686470930SIngo Molnar 78f28827aSFrederic Weisbecker #include "debug.h" 88f28827aSFrederic Weisbecker 9b32d133aSArnaldo Carvalho de Melo #include <asm/bug.h> 1086470930SIngo Molnar #include <libelf.h> 1186470930SIngo Molnar #include <gelf.h> 1286470930SIngo Molnar #include <elf.h> 13f1617b40SArnaldo Carvalho de Melo #include <limits.h> 14439d473bSArnaldo Carvalho de Melo #include <sys/utsname.h> 152cdbc46dSPeter Zijlstra 16c12e15e7SArnaldo Carvalho de Melo #ifndef NT_GNU_BUILD_ID 17c12e15e7SArnaldo Carvalho de Melo #define NT_GNU_BUILD_ID 3 18c12e15e7SArnaldo Carvalho de Melo #endif 19c12e15e7SArnaldo Carvalho de Melo 2094cb9e38SArnaldo Carvalho de Melo enum dso_origin { 2194cb9e38SArnaldo Carvalho de Melo DSO__ORIG_KERNEL = 0, 2294cb9e38SArnaldo Carvalho de Melo DSO__ORIG_JAVA_JIT, 2394cb9e38SArnaldo Carvalho de Melo DSO__ORIG_FEDORA, 2494cb9e38SArnaldo Carvalho de Melo DSO__ORIG_UBUNTU, 2594cb9e38SArnaldo Carvalho de Melo DSO__ORIG_BUILDID, 2694cb9e38SArnaldo Carvalho de Melo DSO__ORIG_DSO, 27439d473bSArnaldo Carvalho de Melo DSO__ORIG_KMODULE, 2894cb9e38SArnaldo Carvalho de Melo DSO__ORIG_NOT_FOUND, 2994cb9e38SArnaldo Carvalho de Melo }; 3094cb9e38SArnaldo Carvalho de Melo 31b0da954aSArnaldo Carvalho de Melo static void dsos__add(struct list_head *head, struct dso *dso); 32*95011c60SArnaldo Carvalho de Melo static struct map *thread__find_map_by_name(struct thread *self, char *name); 333610583cSArnaldo Carvalho de Melo static struct map *map__new2(u64 start, struct dso *dso, enum map_type type); 346a4694a4SArnaldo Carvalho de Melo struct symbol *dso__find_symbol(struct dso *self, enum map_type type, u64 addr); 35c338aee8SArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *self, struct map *map, 36*95011c60SArnaldo Carvalho de Melo struct thread *thread, symbol_filter_t filter); 3700a192b3SArnaldo Carvalho de Melo unsigned int symbol__priv_size; 38cc612d81SArnaldo Carvalho de Melo static int vmlinux_path__nr_entries; 39cc612d81SArnaldo Carvalho de Melo static char **vmlinux_path; 40439d473bSArnaldo Carvalho de Melo 41b32d133aSArnaldo Carvalho de Melo static struct symbol_conf symbol_conf__defaults = { 42b32d133aSArnaldo Carvalho de Melo .use_modules = true, 43b32d133aSArnaldo Carvalho de Melo .try_vmlinux_path = true, 44b32d133aSArnaldo Carvalho de Melo }; 45b32d133aSArnaldo Carvalho de Melo 46*95011c60SArnaldo Carvalho de Melo static struct thread kthread_mem, *kthread = &kthread_mem; 47af427bf5SArnaldo Carvalho de Melo 483610583cSArnaldo Carvalho de Melo bool dso__loaded(const struct dso *self, enum map_type type) 493610583cSArnaldo Carvalho de Melo { 503610583cSArnaldo Carvalho de Melo return self->loaded & (1 << type); 513610583cSArnaldo Carvalho de Melo } 523610583cSArnaldo Carvalho de Melo 533610583cSArnaldo Carvalho de Melo static void dso__set_loaded(struct dso *self, enum map_type type) 543610583cSArnaldo Carvalho de Melo { 553610583cSArnaldo Carvalho de Melo self->loaded |= (1 << type); 563610583cSArnaldo Carvalho de Melo } 573610583cSArnaldo Carvalho de Melo 58fcf1203aSArnaldo Carvalho de Melo static void symbols__fixup_end(struct rb_root *self) 59af427bf5SArnaldo Carvalho de Melo { 60fcf1203aSArnaldo Carvalho de Melo struct rb_node *nd, *prevnd = rb_first(self); 612e538c4aSArnaldo Carvalho de Melo struct symbol *curr, *prev; 62af427bf5SArnaldo Carvalho de Melo 63af427bf5SArnaldo Carvalho de Melo if (prevnd == NULL) 64af427bf5SArnaldo Carvalho de Melo return; 65af427bf5SArnaldo Carvalho de Melo 662e538c4aSArnaldo Carvalho de Melo curr = rb_entry(prevnd, struct symbol, rb_node); 672e538c4aSArnaldo Carvalho de Melo 68af427bf5SArnaldo Carvalho de Melo for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) { 692e538c4aSArnaldo Carvalho de Melo prev = curr; 702e538c4aSArnaldo Carvalho de Melo curr = rb_entry(nd, struct symbol, rb_node); 71af427bf5SArnaldo Carvalho de Melo 72af427bf5SArnaldo Carvalho de Melo if (prev->end == prev->start) 73af427bf5SArnaldo Carvalho de Melo prev->end = curr->start - 1; 74af427bf5SArnaldo Carvalho de Melo } 75af427bf5SArnaldo Carvalho de Melo 762e538c4aSArnaldo Carvalho de Melo /* Last entry */ 772e538c4aSArnaldo Carvalho de Melo if (curr->end == curr->start) 782e538c4aSArnaldo Carvalho de Melo curr->end = roundup(curr->start, 4096); 792e538c4aSArnaldo Carvalho de Melo } 802e538c4aSArnaldo Carvalho de Melo 81*95011c60SArnaldo Carvalho de Melo static void __thread__fixup_maps_end(struct thread *self, enum map_type type) 82af427bf5SArnaldo Carvalho de Melo { 83af427bf5SArnaldo Carvalho de Melo struct map *prev, *curr; 84*95011c60SArnaldo Carvalho de Melo struct rb_node *nd, *prevnd = rb_first(&self->maps[type]); 85af427bf5SArnaldo Carvalho de Melo 86af427bf5SArnaldo Carvalho de Melo if (prevnd == NULL) 87af427bf5SArnaldo Carvalho de Melo return; 88af427bf5SArnaldo Carvalho de Melo 89af427bf5SArnaldo Carvalho de Melo curr = rb_entry(prevnd, struct map, rb_node); 90af427bf5SArnaldo Carvalho de Melo 91af427bf5SArnaldo Carvalho de Melo for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) { 92af427bf5SArnaldo Carvalho de Melo prev = curr; 93af427bf5SArnaldo Carvalho de Melo curr = rb_entry(nd, struct map, rb_node); 94af427bf5SArnaldo Carvalho de Melo prev->end = curr->start - 1; 952e538c4aSArnaldo Carvalho de Melo } 9690c83218SArnaldo Carvalho de Melo 9790c83218SArnaldo Carvalho de Melo /* 9890c83218SArnaldo Carvalho de Melo * We still haven't the actual symbols, so guess the 9990c83218SArnaldo Carvalho de Melo * last map final address. 10090c83218SArnaldo Carvalho de Melo */ 10190c83218SArnaldo Carvalho de Melo curr->end = ~0UL; 102af427bf5SArnaldo Carvalho de Melo } 103af427bf5SArnaldo Carvalho de Melo 104*95011c60SArnaldo Carvalho de Melo static void thread__fixup_maps_end(struct thread *self) 10523ea4a3fSArnaldo Carvalho de Melo { 10623ea4a3fSArnaldo Carvalho de Melo int i; 10723ea4a3fSArnaldo Carvalho de Melo for (i = 0; i < MAP__NR_TYPES; ++i) 108*95011c60SArnaldo Carvalho de Melo __thread__fixup_maps_end(self, i); 10923ea4a3fSArnaldo Carvalho de Melo } 11023ea4a3fSArnaldo Carvalho de Melo 11100a192b3SArnaldo Carvalho de Melo static struct symbol *symbol__new(u64 start, u64 len, const char *name) 11286470930SIngo Molnar { 11386470930SIngo Molnar size_t namelen = strlen(name) + 1; 11436479484SArnaldo Carvalho de Melo struct symbol *self = zalloc(symbol__priv_size + 11536479484SArnaldo Carvalho de Melo sizeof(*self) + namelen); 11636479484SArnaldo Carvalho de Melo if (self == NULL) 11786470930SIngo Molnar return NULL; 11886470930SIngo Molnar 11936479484SArnaldo Carvalho de Melo if (symbol__priv_size) 12000a192b3SArnaldo Carvalho de Melo self = ((void *)self) + symbol__priv_size; 12136479484SArnaldo Carvalho de Melo 12286470930SIngo Molnar self->start = start; 1236cfcc53eSMike Galbraith self->end = len ? start + len - 1 : start; 124e4204992SArnaldo Carvalho de Melo 1256beba7adSArnaldo Carvalho de Melo pr_debug3("%s: %s %#Lx-%#Lx\n", __func__, name, start, self->end); 126e4204992SArnaldo Carvalho de Melo 12786470930SIngo Molnar memcpy(self->name, name, namelen); 12886470930SIngo Molnar 12986470930SIngo Molnar return self; 13086470930SIngo Molnar } 13186470930SIngo Molnar 13200a192b3SArnaldo Carvalho de Melo static void symbol__delete(struct symbol *self) 13386470930SIngo Molnar { 13400a192b3SArnaldo Carvalho de Melo free(((void *)self) - symbol__priv_size); 13586470930SIngo Molnar } 13686470930SIngo Molnar 13786470930SIngo Molnar static size_t symbol__fprintf(struct symbol *self, FILE *fp) 13886470930SIngo Molnar { 13986470930SIngo Molnar return fprintf(fp, " %llx-%llx %s\n", 14086470930SIngo Molnar self->start, self->end, self->name); 14186470930SIngo Molnar } 14286470930SIngo Molnar 143cfc10d3bSArnaldo Carvalho de Melo static void dso__set_long_name(struct dso *self, char *name) 144cfc10d3bSArnaldo Carvalho de Melo { 145ef6ae724SArnaldo Carvalho de Melo if (name == NULL) 146ef6ae724SArnaldo Carvalho de Melo return; 147cfc10d3bSArnaldo Carvalho de Melo self->long_name = name; 148cfc10d3bSArnaldo Carvalho de Melo self->long_name_len = strlen(name); 149cfc10d3bSArnaldo Carvalho de Melo } 150cfc10d3bSArnaldo Carvalho de Melo 151cfc10d3bSArnaldo Carvalho de Melo static void dso__set_basename(struct dso *self) 152cfc10d3bSArnaldo Carvalho de Melo { 153cfc10d3bSArnaldo Carvalho de Melo self->short_name = basename(self->long_name); 154cfc10d3bSArnaldo Carvalho de Melo } 155cfc10d3bSArnaldo Carvalho de Melo 15600a192b3SArnaldo Carvalho de Melo struct dso *dso__new(const char *name) 15786470930SIngo Molnar { 15886470930SIngo Molnar struct dso *self = malloc(sizeof(*self) + strlen(name) + 1); 15986470930SIngo Molnar 16086470930SIngo Molnar if (self != NULL) { 1616a4694a4SArnaldo Carvalho de Melo int i; 16286470930SIngo Molnar strcpy(self->name, name); 163cfc10d3bSArnaldo Carvalho de Melo dso__set_long_name(self, self->name); 164439d473bSArnaldo Carvalho de Melo self->short_name = self->name; 1656a4694a4SArnaldo Carvalho de Melo for (i = 0; i < MAP__NR_TYPES; ++i) 1666a4694a4SArnaldo Carvalho de Melo self->symbols[i] = RB_ROOT; 1676a4694a4SArnaldo Carvalho de Melo self->find_symbol = dso__find_symbol; 16852d422deSArnaldo Carvalho de Melo self->slen_calculated = 0; 16994cb9e38SArnaldo Carvalho de Melo self->origin = DSO__ORIG_NOT_FOUND; 1708d06367fSArnaldo Carvalho de Melo self->loaded = 0; 1718d06367fSArnaldo Carvalho de Melo self->has_build_id = 0; 17286470930SIngo Molnar } 17386470930SIngo Molnar 17486470930SIngo Molnar return self; 17586470930SIngo Molnar } 17686470930SIngo Molnar 177fcf1203aSArnaldo Carvalho de Melo static void symbols__delete(struct rb_root *self) 17886470930SIngo Molnar { 17986470930SIngo Molnar struct symbol *pos; 180fcf1203aSArnaldo Carvalho de Melo struct rb_node *next = rb_first(self); 18186470930SIngo Molnar 18286470930SIngo Molnar while (next) { 18386470930SIngo Molnar pos = rb_entry(next, struct symbol, rb_node); 18486470930SIngo Molnar next = rb_next(&pos->rb_node); 185fcf1203aSArnaldo Carvalho de Melo rb_erase(&pos->rb_node, self); 18600a192b3SArnaldo Carvalho de Melo symbol__delete(pos); 18786470930SIngo Molnar } 18886470930SIngo Molnar } 18986470930SIngo Molnar 19086470930SIngo Molnar void dso__delete(struct dso *self) 19186470930SIngo Molnar { 1926a4694a4SArnaldo Carvalho de Melo int i; 1936a4694a4SArnaldo Carvalho de Melo for (i = 0; i < MAP__NR_TYPES; ++i) 1946a4694a4SArnaldo Carvalho de Melo symbols__delete(&self->symbols[i]); 195439d473bSArnaldo Carvalho de Melo if (self->long_name != self->name) 196439d473bSArnaldo Carvalho de Melo free(self->long_name); 19786470930SIngo Molnar free(self); 19886470930SIngo Molnar } 19986470930SIngo Molnar 2008d06367fSArnaldo Carvalho de Melo void dso__set_build_id(struct dso *self, void *build_id) 2018d06367fSArnaldo Carvalho de Melo { 2028d06367fSArnaldo Carvalho de Melo memcpy(self->build_id, build_id, sizeof(self->build_id)); 2038d06367fSArnaldo Carvalho de Melo self->has_build_id = 1; 2048d06367fSArnaldo Carvalho de Melo } 2058d06367fSArnaldo Carvalho de Melo 206fcf1203aSArnaldo Carvalho de Melo static void symbols__insert(struct rb_root *self, struct symbol *sym) 20786470930SIngo Molnar { 208fcf1203aSArnaldo Carvalho de Melo struct rb_node **p = &self->rb_node; 20986470930SIngo Molnar struct rb_node *parent = NULL; 2109cffa8d5SPaul Mackerras const u64 ip = sym->start; 21186470930SIngo Molnar struct symbol *s; 21286470930SIngo Molnar 21386470930SIngo Molnar while (*p != NULL) { 21486470930SIngo Molnar parent = *p; 21586470930SIngo Molnar s = rb_entry(parent, struct symbol, rb_node); 21686470930SIngo Molnar if (ip < s->start) 21786470930SIngo Molnar p = &(*p)->rb_left; 21886470930SIngo Molnar else 21986470930SIngo Molnar p = &(*p)->rb_right; 22086470930SIngo Molnar } 22186470930SIngo Molnar rb_link_node(&sym->rb_node, parent, p); 222fcf1203aSArnaldo Carvalho de Melo rb_insert_color(&sym->rb_node, self); 22386470930SIngo Molnar } 22486470930SIngo Molnar 225fcf1203aSArnaldo Carvalho de Melo static struct symbol *symbols__find(struct rb_root *self, u64 ip) 22686470930SIngo Molnar { 22786470930SIngo Molnar struct rb_node *n; 22886470930SIngo Molnar 22986470930SIngo Molnar if (self == NULL) 23086470930SIngo Molnar return NULL; 23186470930SIngo Molnar 232fcf1203aSArnaldo Carvalho de Melo n = self->rb_node; 23386470930SIngo Molnar 23486470930SIngo Molnar while (n) { 23586470930SIngo Molnar struct symbol *s = rb_entry(n, struct symbol, rb_node); 23686470930SIngo Molnar 23786470930SIngo Molnar if (ip < s->start) 23886470930SIngo Molnar n = n->rb_left; 23986470930SIngo Molnar else if (ip > s->end) 24086470930SIngo Molnar n = n->rb_right; 24186470930SIngo Molnar else 24286470930SIngo Molnar return s; 24386470930SIngo Molnar } 24486470930SIngo Molnar 24586470930SIngo Molnar return NULL; 24686470930SIngo Molnar } 24786470930SIngo Molnar 2486a4694a4SArnaldo Carvalho de Melo struct symbol *dso__find_symbol(struct dso *self, enum map_type type, u64 addr) 249fcf1203aSArnaldo Carvalho de Melo { 2506a4694a4SArnaldo Carvalho de Melo return symbols__find(&self->symbols[type], addr); 251fcf1203aSArnaldo Carvalho de Melo } 252fcf1203aSArnaldo Carvalho de Melo 2538d06367fSArnaldo Carvalho de Melo int build_id__sprintf(u8 *self, int len, char *bf) 2548d06367fSArnaldo Carvalho de Melo { 2558d06367fSArnaldo Carvalho de Melo char *bid = bf; 2568d06367fSArnaldo Carvalho de Melo u8 *raw = self; 2578d06367fSArnaldo Carvalho de Melo int i; 2588d06367fSArnaldo Carvalho de Melo 2598d06367fSArnaldo Carvalho de Melo for (i = 0; i < len; ++i) { 2608d06367fSArnaldo Carvalho de Melo sprintf(bid, "%02x", *raw); 2618d06367fSArnaldo Carvalho de Melo ++raw; 2628d06367fSArnaldo Carvalho de Melo bid += 2; 2638d06367fSArnaldo Carvalho de Melo } 2648d06367fSArnaldo Carvalho de Melo 2658d06367fSArnaldo Carvalho de Melo return raw - self; 2668d06367fSArnaldo Carvalho de Melo } 2678d06367fSArnaldo Carvalho de Melo 2689e03eb2dSArnaldo Carvalho de Melo size_t dso__fprintf_buildid(struct dso *self, FILE *fp) 26986470930SIngo Molnar { 2708d06367fSArnaldo Carvalho de Melo char sbuild_id[BUILD_ID_SIZE * 2 + 1]; 2718d06367fSArnaldo Carvalho de Melo 2728d06367fSArnaldo Carvalho de Melo build_id__sprintf(self->build_id, sizeof(self->build_id), sbuild_id); 2739e03eb2dSArnaldo Carvalho de Melo return fprintf(fp, "%s", sbuild_id); 2749e03eb2dSArnaldo Carvalho de Melo } 2759e03eb2dSArnaldo Carvalho de Melo 276*95011c60SArnaldo Carvalho de Melo size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp) 2779e03eb2dSArnaldo Carvalho de Melo { 2789e03eb2dSArnaldo Carvalho de Melo struct rb_node *nd; 2799e03eb2dSArnaldo Carvalho de Melo size_t ret = fprintf(fp, "dso: %s (", self->short_name); 2809e03eb2dSArnaldo Carvalho de Melo 2819e03eb2dSArnaldo Carvalho de Melo ret += dso__fprintf_buildid(self, fp); 2826a4694a4SArnaldo Carvalho de Melo ret += fprintf(fp, ")\n"); 283*95011c60SArnaldo Carvalho de Melo for (nd = rb_first(&self->symbols[type]); nd; nd = rb_next(nd)) { 28486470930SIngo Molnar struct symbol *pos = rb_entry(nd, struct symbol, rb_node); 28586470930SIngo Molnar ret += symbol__fprintf(pos, fp); 28686470930SIngo Molnar } 28786470930SIngo Molnar 28886470930SIngo Molnar return ret; 28986470930SIngo Molnar } 29086470930SIngo Molnar 2912e538c4aSArnaldo Carvalho de Melo /* 2922e538c4aSArnaldo Carvalho de Melo * Loads the function entries in /proc/kallsyms into kernel_map->dso, 2932e538c4aSArnaldo Carvalho de Melo * so that we can in the next step set the symbol ->end address and then 2942e538c4aSArnaldo Carvalho de Melo * call kernel_maps__split_kallsyms. 2952e538c4aSArnaldo Carvalho de Melo */ 2964e06255fSArnaldo Carvalho de Melo static int dso__load_all_kallsyms(struct dso *self, struct map *map) 29786470930SIngo Molnar { 29886470930SIngo Molnar char *line = NULL; 29986470930SIngo Molnar size_t n; 3004e06255fSArnaldo Carvalho de Melo struct rb_root *root = &self->symbols[map->type]; 30186470930SIngo Molnar FILE *file = fopen("/proc/kallsyms", "r"); 30286470930SIngo Molnar 30386470930SIngo Molnar if (file == NULL) 30486470930SIngo Molnar goto out_failure; 30586470930SIngo Molnar 30686470930SIngo Molnar while (!feof(file)) { 3079cffa8d5SPaul Mackerras u64 start; 30886470930SIngo Molnar struct symbol *sym; 30986470930SIngo Molnar int line_len, len; 31086470930SIngo Molnar char symbol_type; 3112e538c4aSArnaldo Carvalho de Melo char *symbol_name; 31286470930SIngo Molnar 31386470930SIngo Molnar line_len = getline(&line, &n, file); 31486470930SIngo Molnar if (line_len < 0) 31586470930SIngo Molnar break; 31686470930SIngo Molnar 31786470930SIngo Molnar if (!line) 31886470930SIngo Molnar goto out_failure; 31986470930SIngo Molnar 32086470930SIngo Molnar line[--line_len] = '\0'; /* \n */ 32186470930SIngo Molnar 32286470930SIngo Molnar len = hex2u64(line, &start); 32386470930SIngo Molnar 32486470930SIngo Molnar len++; 32586470930SIngo Molnar if (len + 2 >= line_len) 32686470930SIngo Molnar continue; 32786470930SIngo Molnar 32886470930SIngo Molnar symbol_type = toupper(line[len]); 32986470930SIngo Molnar /* 33086470930SIngo Molnar * We're interested only in code ('T'ext) 33186470930SIngo Molnar */ 33286470930SIngo Molnar if (symbol_type != 'T' && symbol_type != 'W') 33386470930SIngo Molnar continue; 334af427bf5SArnaldo Carvalho de Melo 335af427bf5SArnaldo Carvalho de Melo symbol_name = line + len + 2; 3362e538c4aSArnaldo Carvalho de Melo /* 3372e538c4aSArnaldo Carvalho de Melo * Will fix up the end later, when we have all symbols sorted. 3382e538c4aSArnaldo Carvalho de Melo */ 33900a192b3SArnaldo Carvalho de Melo sym = symbol__new(start, 0, symbol_name); 340af427bf5SArnaldo Carvalho de Melo 3412e538c4aSArnaldo Carvalho de Melo if (sym == NULL) 3422e538c4aSArnaldo Carvalho de Melo goto out_delete_line; 34382164161SArnaldo Carvalho de Melo /* 34482164161SArnaldo Carvalho de Melo * We will pass the symbols to the filter later, in 3454e06255fSArnaldo Carvalho de Melo * map__split_kallsyms, when we have split the maps per module 34682164161SArnaldo Carvalho de Melo */ 3474e06255fSArnaldo Carvalho de Melo symbols__insert(root, sym); 3482e538c4aSArnaldo Carvalho de Melo } 3492e538c4aSArnaldo Carvalho de Melo 3502e538c4aSArnaldo Carvalho de Melo free(line); 3512e538c4aSArnaldo Carvalho de Melo fclose(file); 3522e538c4aSArnaldo Carvalho de Melo 3532e538c4aSArnaldo Carvalho de Melo return 0; 3542e538c4aSArnaldo Carvalho de Melo 3552e538c4aSArnaldo Carvalho de Melo out_delete_line: 3562e538c4aSArnaldo Carvalho de Melo free(line); 3572e538c4aSArnaldo Carvalho de Melo out_failure: 3582e538c4aSArnaldo Carvalho de Melo return -1; 3592e538c4aSArnaldo Carvalho de Melo } 3602e538c4aSArnaldo Carvalho de Melo 3612e538c4aSArnaldo Carvalho de Melo /* 3622e538c4aSArnaldo Carvalho de Melo * Split the symbols into maps, making sure there are no overlaps, i.e. the 3632e538c4aSArnaldo Carvalho de Melo * kernel range is broken in several maps, named [kernel].N, as we don't have 3642e538c4aSArnaldo Carvalho de Melo * the original ELF section names vmlinux have. 3652e538c4aSArnaldo Carvalho de Melo */ 366*95011c60SArnaldo Carvalho de Melo static int dso__split_kallsyms(struct dso *self, struct map *map, struct thread *thread, 3674e06255fSArnaldo Carvalho de Melo symbol_filter_t filter) 3682e538c4aSArnaldo Carvalho de Melo { 3694e06255fSArnaldo Carvalho de Melo struct map *curr_map = map; 3702e538c4aSArnaldo Carvalho de Melo struct symbol *pos; 3712e538c4aSArnaldo Carvalho de Melo int count = 0; 3724e06255fSArnaldo Carvalho de Melo struct rb_root *root = &self->symbols[map->type]; 3734e06255fSArnaldo Carvalho de Melo struct rb_node *next = rb_first(root); 3742e538c4aSArnaldo Carvalho de Melo int kernel_range = 0; 3752e538c4aSArnaldo Carvalho de Melo 3762e538c4aSArnaldo Carvalho de Melo while (next) { 3772e538c4aSArnaldo Carvalho de Melo char *module; 3782e538c4aSArnaldo Carvalho de Melo 3792e538c4aSArnaldo Carvalho de Melo pos = rb_entry(next, struct symbol, rb_node); 3802e538c4aSArnaldo Carvalho de Melo next = rb_next(&pos->rb_node); 3812e538c4aSArnaldo Carvalho de Melo 3822e538c4aSArnaldo Carvalho de Melo module = strchr(pos->name, '\t'); 3832e538c4aSArnaldo Carvalho de Melo if (module) { 3842e538c4aSArnaldo Carvalho de Melo *module++ = '\0'; 3852e538c4aSArnaldo Carvalho de Melo 3864e06255fSArnaldo Carvalho de Melo if (strcmp(self->name, module)) { 387*95011c60SArnaldo Carvalho de Melo curr_map = thread__find_map_by_name(thread, module); 3884e06255fSArnaldo Carvalho de Melo if (curr_map == NULL) { 389*95011c60SArnaldo Carvalho de Melo pr_debug("/proc/{kallsyms,modules} " 3906beba7adSArnaldo Carvalho de Melo "inconsistency!\n"); 391af427bf5SArnaldo Carvalho de Melo return -1; 392af427bf5SArnaldo Carvalho de Melo } 393af427bf5SArnaldo Carvalho de Melo } 39486470930SIngo Molnar /* 3952e538c4aSArnaldo Carvalho de Melo * So that we look just like we get from .ko files, 3962e538c4aSArnaldo Carvalho de Melo * i.e. not prelinked, relative to map->start. 39786470930SIngo Molnar */ 3984e06255fSArnaldo Carvalho de Melo pos->start = curr_map->map_ip(curr_map, pos->start); 3994e06255fSArnaldo Carvalho de Melo pos->end = curr_map->map_ip(curr_map, pos->end); 4004e06255fSArnaldo Carvalho de Melo } else if (curr_map != map) { 4012e538c4aSArnaldo Carvalho de Melo char dso_name[PATH_MAX]; 4022e538c4aSArnaldo Carvalho de Melo struct dso *dso; 40386470930SIngo Molnar 4042e538c4aSArnaldo Carvalho de Melo snprintf(dso_name, sizeof(dso_name), "[kernel].%d", 4052e538c4aSArnaldo Carvalho de Melo kernel_range++); 40686470930SIngo Molnar 40700a192b3SArnaldo Carvalho de Melo dso = dso__new(dso_name); 4082e538c4aSArnaldo Carvalho de Melo if (dso == NULL) 4092e538c4aSArnaldo Carvalho de Melo return -1; 4102e538c4aSArnaldo Carvalho de Melo 4114e06255fSArnaldo Carvalho de Melo curr_map = map__new2(pos->start, dso, map->type); 4122e538c4aSArnaldo Carvalho de Melo if (map == NULL) { 4132e538c4aSArnaldo Carvalho de Melo dso__delete(dso); 4142e538c4aSArnaldo Carvalho de Melo return -1; 4152e538c4aSArnaldo Carvalho de Melo } 4162e538c4aSArnaldo Carvalho de Melo 4174e06255fSArnaldo Carvalho de Melo curr_map->map_ip = curr_map->unmap_ip = identity__map_ip; 418*95011c60SArnaldo Carvalho de Melo __thread__insert_map(thread, curr_map); 4192e538c4aSArnaldo Carvalho de Melo ++kernel_range; 4202e538c4aSArnaldo Carvalho de Melo } 4212e538c4aSArnaldo Carvalho de Melo 4224e06255fSArnaldo Carvalho de Melo if (filter && filter(curr_map, pos)) { 4234e06255fSArnaldo Carvalho de Melo rb_erase(&pos->rb_node, root); 42400a192b3SArnaldo Carvalho de Melo symbol__delete(pos); 4252e538c4aSArnaldo Carvalho de Melo } else { 4264e06255fSArnaldo Carvalho de Melo if (curr_map != map) { 4274e06255fSArnaldo Carvalho de Melo rb_erase(&pos->rb_node, root); 4284e06255fSArnaldo Carvalho de Melo symbols__insert(&curr_map->dso->symbols[curr_map->type], pos); 4292e538c4aSArnaldo Carvalho de Melo } 4309974f496SMike Galbraith count++; 4319974f496SMike Galbraith } 43286470930SIngo Molnar } 43386470930SIngo Molnar 4349974f496SMike Galbraith return count; 43586470930SIngo Molnar } 43686470930SIngo Molnar 4372e538c4aSArnaldo Carvalho de Melo 4384e06255fSArnaldo Carvalho de Melo static int dso__load_kallsyms(struct dso *self, struct map *map, 439*95011c60SArnaldo Carvalho de Melo struct thread *thread, symbol_filter_t filter) 4402e538c4aSArnaldo Carvalho de Melo { 4414e06255fSArnaldo Carvalho de Melo if (dso__load_all_kallsyms(self, map) < 0) 4422e538c4aSArnaldo Carvalho de Melo return -1; 4432e538c4aSArnaldo Carvalho de Melo 4444e06255fSArnaldo Carvalho de Melo symbols__fixup_end(&self->symbols[map->type]); 4454e06255fSArnaldo Carvalho de Melo self->origin = DSO__ORIG_KERNEL; 4462e538c4aSArnaldo Carvalho de Melo 447*95011c60SArnaldo Carvalho de Melo return dso__split_kallsyms(self, map, thread, filter); 44823ea4a3fSArnaldo Carvalho de Melo } 44923ea4a3fSArnaldo Carvalho de Melo 45023ea4a3fSArnaldo Carvalho de Melo size_t kernel_maps__fprintf(FILE *fp) 45123ea4a3fSArnaldo Carvalho de Melo { 45223ea4a3fSArnaldo Carvalho de Melo size_t printed = fprintf(fp, "Kernel maps:\n"); 453*95011c60SArnaldo Carvalho de Melo printed += thread__fprintf_maps(kthread, fp); 4546beba7adSArnaldo Carvalho de Melo return printed + fprintf(fp, "END kernel maps\n"); 455af427bf5SArnaldo Carvalho de Melo } 456af427bf5SArnaldo Carvalho de Melo 457439d473bSArnaldo Carvalho de Melo static int dso__load_perf_map(struct dso *self, struct map *map, 4586beba7adSArnaldo Carvalho de Melo symbol_filter_t filter) 45980d496beSPekka Enberg { 46080d496beSPekka Enberg char *line = NULL; 46180d496beSPekka Enberg size_t n; 46280d496beSPekka Enberg FILE *file; 46380d496beSPekka Enberg int nr_syms = 0; 46480d496beSPekka Enberg 465439d473bSArnaldo Carvalho de Melo file = fopen(self->long_name, "r"); 46680d496beSPekka Enberg if (file == NULL) 46780d496beSPekka Enberg goto out_failure; 46880d496beSPekka Enberg 46980d496beSPekka Enberg while (!feof(file)) { 4709cffa8d5SPaul Mackerras u64 start, size; 47180d496beSPekka Enberg struct symbol *sym; 47280d496beSPekka Enberg int line_len, len; 47380d496beSPekka Enberg 47480d496beSPekka Enberg line_len = getline(&line, &n, file); 47580d496beSPekka Enberg if (line_len < 0) 47680d496beSPekka Enberg break; 47780d496beSPekka Enberg 47880d496beSPekka Enberg if (!line) 47980d496beSPekka Enberg goto out_failure; 48080d496beSPekka Enberg 48180d496beSPekka Enberg line[--line_len] = '\0'; /* \n */ 48280d496beSPekka Enberg 48380d496beSPekka Enberg len = hex2u64(line, &start); 48480d496beSPekka Enberg 48580d496beSPekka Enberg len++; 48680d496beSPekka Enberg if (len + 2 >= line_len) 48780d496beSPekka Enberg continue; 48880d496beSPekka Enberg 48980d496beSPekka Enberg len += hex2u64(line + len, &size); 49080d496beSPekka Enberg 49180d496beSPekka Enberg len++; 49280d496beSPekka Enberg if (len + 2 >= line_len) 49380d496beSPekka Enberg continue; 49480d496beSPekka Enberg 49500a192b3SArnaldo Carvalho de Melo sym = symbol__new(start, size, line + len); 49680d496beSPekka Enberg 49780d496beSPekka Enberg if (sym == NULL) 49880d496beSPekka Enberg goto out_delete_line; 49980d496beSPekka Enberg 500439d473bSArnaldo Carvalho de Melo if (filter && filter(map, sym)) 50100a192b3SArnaldo Carvalho de Melo symbol__delete(sym); 50280d496beSPekka Enberg else { 5036a4694a4SArnaldo Carvalho de Melo symbols__insert(&self->symbols[map->type], sym); 50480d496beSPekka Enberg nr_syms++; 50580d496beSPekka Enberg } 50680d496beSPekka Enberg } 50780d496beSPekka Enberg 50880d496beSPekka Enberg free(line); 50980d496beSPekka Enberg fclose(file); 51080d496beSPekka Enberg 51180d496beSPekka Enberg return nr_syms; 51280d496beSPekka Enberg 51380d496beSPekka Enberg out_delete_line: 51480d496beSPekka Enberg free(line); 51580d496beSPekka Enberg out_failure: 51680d496beSPekka Enberg return -1; 51780d496beSPekka Enberg } 51880d496beSPekka Enberg 51986470930SIngo Molnar /** 52086470930SIngo Molnar * elf_symtab__for_each_symbol - iterate thru all the symbols 52186470930SIngo Molnar * 52286470930SIngo Molnar * @self: struct elf_symtab instance to iterate 52383a0944fSIngo Molnar * @idx: uint32_t idx 52486470930SIngo Molnar * @sym: GElf_Sym iterator 52586470930SIngo Molnar */ 52683a0944fSIngo Molnar #define elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) \ 52783a0944fSIngo Molnar for (idx = 0, gelf_getsym(syms, idx, &sym);\ 52883a0944fSIngo Molnar idx < nr_syms; \ 52983a0944fSIngo Molnar idx++, gelf_getsym(syms, idx, &sym)) 53086470930SIngo Molnar 53186470930SIngo Molnar static inline uint8_t elf_sym__type(const GElf_Sym *sym) 53286470930SIngo Molnar { 53386470930SIngo Molnar return GELF_ST_TYPE(sym->st_info); 53486470930SIngo Molnar } 53586470930SIngo Molnar 53686470930SIngo Molnar static inline int elf_sym__is_function(const GElf_Sym *sym) 53786470930SIngo Molnar { 53886470930SIngo Molnar return elf_sym__type(sym) == STT_FUNC && 53986470930SIngo Molnar sym->st_name != 0 && 54081833130SArnaldo Carvalho de Melo sym->st_shndx != SHN_UNDEF; 54186470930SIngo Molnar } 54286470930SIngo Molnar 5436cfcc53eSMike Galbraith static inline int elf_sym__is_label(const GElf_Sym *sym) 5446cfcc53eSMike Galbraith { 5456cfcc53eSMike Galbraith return elf_sym__type(sym) == STT_NOTYPE && 5466cfcc53eSMike Galbraith sym->st_name != 0 && 5476cfcc53eSMike Galbraith sym->st_shndx != SHN_UNDEF && 5486cfcc53eSMike Galbraith sym->st_shndx != SHN_ABS; 5496cfcc53eSMike Galbraith } 5506cfcc53eSMike Galbraith 5516cfcc53eSMike Galbraith static inline const char *elf_sec__name(const GElf_Shdr *shdr, 5526cfcc53eSMike Galbraith const Elf_Data *secstrs) 5536cfcc53eSMike Galbraith { 5546cfcc53eSMike Galbraith return secstrs->d_buf + shdr->sh_name; 5556cfcc53eSMike Galbraith } 5566cfcc53eSMike Galbraith 5576cfcc53eSMike Galbraith static inline int elf_sec__is_text(const GElf_Shdr *shdr, 5586cfcc53eSMike Galbraith const Elf_Data *secstrs) 5596cfcc53eSMike Galbraith { 5606cfcc53eSMike Galbraith return strstr(elf_sec__name(shdr, secstrs), "text") != NULL; 5616cfcc53eSMike Galbraith } 5626cfcc53eSMike Galbraith 56386470930SIngo Molnar static inline const char *elf_sym__name(const GElf_Sym *sym, 56486470930SIngo Molnar const Elf_Data *symstrs) 56586470930SIngo Molnar { 56686470930SIngo Molnar return symstrs->d_buf + sym->st_name; 56786470930SIngo Molnar } 56886470930SIngo Molnar 56986470930SIngo Molnar static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, 57086470930SIngo Molnar GElf_Shdr *shp, const char *name, 57183a0944fSIngo Molnar size_t *idx) 57286470930SIngo Molnar { 57386470930SIngo Molnar Elf_Scn *sec = NULL; 57486470930SIngo Molnar size_t cnt = 1; 57586470930SIngo Molnar 57686470930SIngo Molnar while ((sec = elf_nextscn(elf, sec)) != NULL) { 57786470930SIngo Molnar char *str; 57886470930SIngo Molnar 57986470930SIngo Molnar gelf_getshdr(sec, shp); 58086470930SIngo Molnar str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name); 58186470930SIngo Molnar if (!strcmp(name, str)) { 58283a0944fSIngo Molnar if (idx) 58383a0944fSIngo Molnar *idx = cnt; 58486470930SIngo Molnar break; 58586470930SIngo Molnar } 58686470930SIngo Molnar ++cnt; 58786470930SIngo Molnar } 58886470930SIngo Molnar 58986470930SIngo Molnar return sec; 59086470930SIngo Molnar } 59186470930SIngo Molnar 59286470930SIngo Molnar #define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \ 59386470930SIngo Molnar for (idx = 0, pos = gelf_getrel(reldata, 0, &pos_mem); \ 59486470930SIngo Molnar idx < nr_entries; \ 59586470930SIngo Molnar ++idx, pos = gelf_getrel(reldata, idx, &pos_mem)) 59686470930SIngo Molnar 59786470930SIngo Molnar #define elf_section__for_each_rela(reldata, pos, pos_mem, idx, nr_entries) \ 59886470930SIngo Molnar for (idx = 0, pos = gelf_getrela(reldata, 0, &pos_mem); \ 59986470930SIngo Molnar idx < nr_entries; \ 60086470930SIngo Molnar ++idx, pos = gelf_getrela(reldata, idx, &pos_mem)) 60186470930SIngo Molnar 602a25e46c4SArnaldo Carvalho de Melo /* 603a25e46c4SArnaldo Carvalho de Melo * We need to check if we have a .dynsym, so that we can handle the 604a25e46c4SArnaldo Carvalho de Melo * .plt, synthesizing its symbols, that aren't on the symtabs (be it 605a25e46c4SArnaldo Carvalho de Melo * .dynsym or .symtab). 606a25e46c4SArnaldo Carvalho de Melo * And always look at the original dso, not at debuginfo packages, that 607a25e46c4SArnaldo Carvalho de Melo * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS). 608a25e46c4SArnaldo Carvalho de Melo */ 60982164161SArnaldo Carvalho de Melo static int dso__synthesize_plt_symbols(struct dso *self, struct map *map, 61082164161SArnaldo Carvalho de Melo symbol_filter_t filter) 61186470930SIngo Molnar { 61286470930SIngo Molnar uint32_t nr_rel_entries, idx; 61386470930SIngo Molnar GElf_Sym sym; 6149cffa8d5SPaul Mackerras u64 plt_offset; 61586470930SIngo Molnar GElf_Shdr shdr_plt; 61686470930SIngo Molnar struct symbol *f; 617a25e46c4SArnaldo Carvalho de Melo GElf_Shdr shdr_rel_plt, shdr_dynsym; 61886470930SIngo Molnar Elf_Data *reldata, *syms, *symstrs; 619a25e46c4SArnaldo Carvalho de Melo Elf_Scn *scn_plt_rel, *scn_symstrs, *scn_dynsym; 620a25e46c4SArnaldo Carvalho de Melo size_t dynsym_idx; 621a25e46c4SArnaldo Carvalho de Melo GElf_Ehdr ehdr; 62286470930SIngo Molnar char sympltname[1024]; 623a25e46c4SArnaldo Carvalho de Melo Elf *elf; 624a25e46c4SArnaldo Carvalho de Melo int nr = 0, symidx, fd, err = 0; 62586470930SIngo Molnar 626439d473bSArnaldo Carvalho de Melo fd = open(self->long_name, O_RDONLY); 627a25e46c4SArnaldo Carvalho de Melo if (fd < 0) 628a25e46c4SArnaldo Carvalho de Melo goto out; 629a25e46c4SArnaldo Carvalho de Melo 63084087126SMarti Raudsepp elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 631a25e46c4SArnaldo Carvalho de Melo if (elf == NULL) 632a25e46c4SArnaldo Carvalho de Melo goto out_close; 633a25e46c4SArnaldo Carvalho de Melo 634a25e46c4SArnaldo Carvalho de Melo if (gelf_getehdr(elf, &ehdr) == NULL) 635a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 636a25e46c4SArnaldo Carvalho de Melo 637a25e46c4SArnaldo Carvalho de Melo scn_dynsym = elf_section_by_name(elf, &ehdr, &shdr_dynsym, 638a25e46c4SArnaldo Carvalho de Melo ".dynsym", &dynsym_idx); 639a25e46c4SArnaldo Carvalho de Melo if (scn_dynsym == NULL) 640a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 641a25e46c4SArnaldo Carvalho de Melo 642a25e46c4SArnaldo Carvalho de Melo scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt, 64386470930SIngo Molnar ".rela.plt", NULL); 64486470930SIngo Molnar if (scn_plt_rel == NULL) { 645a25e46c4SArnaldo Carvalho de Melo scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt, 64686470930SIngo Molnar ".rel.plt", NULL); 64786470930SIngo Molnar if (scn_plt_rel == NULL) 648a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 64986470930SIngo Molnar } 65086470930SIngo Molnar 651a25e46c4SArnaldo Carvalho de Melo err = -1; 65286470930SIngo Molnar 653a25e46c4SArnaldo Carvalho de Melo if (shdr_rel_plt.sh_link != dynsym_idx) 654a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 655a25e46c4SArnaldo Carvalho de Melo 656a25e46c4SArnaldo Carvalho de Melo if (elf_section_by_name(elf, &ehdr, &shdr_plt, ".plt", NULL) == NULL) 657a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 65886470930SIngo Molnar 65986470930SIngo Molnar /* 66083a0944fSIngo Molnar * Fetch the relocation section to find the idxes to the GOT 66186470930SIngo Molnar * and the symbols in the .dynsym they refer to. 66286470930SIngo Molnar */ 66386470930SIngo Molnar reldata = elf_getdata(scn_plt_rel, NULL); 66486470930SIngo Molnar if (reldata == NULL) 665a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 66686470930SIngo Molnar 66786470930SIngo Molnar syms = elf_getdata(scn_dynsym, NULL); 66886470930SIngo Molnar if (syms == NULL) 669a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 67086470930SIngo Molnar 671a25e46c4SArnaldo Carvalho de Melo scn_symstrs = elf_getscn(elf, shdr_dynsym.sh_link); 67286470930SIngo Molnar if (scn_symstrs == NULL) 673a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 67486470930SIngo Molnar 67586470930SIngo Molnar symstrs = elf_getdata(scn_symstrs, NULL); 67686470930SIngo Molnar if (symstrs == NULL) 677a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 67886470930SIngo Molnar 67986470930SIngo Molnar nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize; 68086470930SIngo Molnar plt_offset = shdr_plt.sh_offset; 68186470930SIngo Molnar 68286470930SIngo Molnar if (shdr_rel_plt.sh_type == SHT_RELA) { 68386470930SIngo Molnar GElf_Rela pos_mem, *pos; 68486470930SIngo Molnar 68586470930SIngo Molnar elf_section__for_each_rela(reldata, pos, pos_mem, idx, 68686470930SIngo Molnar nr_rel_entries) { 68786470930SIngo Molnar symidx = GELF_R_SYM(pos->r_info); 68886470930SIngo Molnar plt_offset += shdr_plt.sh_entsize; 68986470930SIngo Molnar gelf_getsym(syms, symidx, &sym); 69086470930SIngo Molnar snprintf(sympltname, sizeof(sympltname), 69186470930SIngo Molnar "%s@plt", elf_sym__name(&sym, symstrs)); 69286470930SIngo Molnar 69386470930SIngo Molnar f = symbol__new(plt_offset, shdr_plt.sh_entsize, 69400a192b3SArnaldo Carvalho de Melo sympltname); 69586470930SIngo Molnar if (!f) 696a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 69786470930SIngo Molnar 69882164161SArnaldo Carvalho de Melo if (filter && filter(map, f)) 69982164161SArnaldo Carvalho de Melo symbol__delete(f); 70082164161SArnaldo Carvalho de Melo else { 7016a4694a4SArnaldo Carvalho de Melo symbols__insert(&self->symbols[map->type], f); 70286470930SIngo Molnar ++nr; 70386470930SIngo Molnar } 70482164161SArnaldo Carvalho de Melo } 70586470930SIngo Molnar } else if (shdr_rel_plt.sh_type == SHT_REL) { 70686470930SIngo Molnar GElf_Rel pos_mem, *pos; 70786470930SIngo Molnar elf_section__for_each_rel(reldata, pos, pos_mem, idx, 70886470930SIngo Molnar nr_rel_entries) { 70986470930SIngo Molnar symidx = GELF_R_SYM(pos->r_info); 71086470930SIngo Molnar plt_offset += shdr_plt.sh_entsize; 71186470930SIngo Molnar gelf_getsym(syms, symidx, &sym); 71286470930SIngo Molnar snprintf(sympltname, sizeof(sympltname), 71386470930SIngo Molnar "%s@plt", elf_sym__name(&sym, symstrs)); 71486470930SIngo Molnar 71586470930SIngo Molnar f = symbol__new(plt_offset, shdr_plt.sh_entsize, 71600a192b3SArnaldo Carvalho de Melo sympltname); 71786470930SIngo Molnar if (!f) 718a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 71986470930SIngo Molnar 72082164161SArnaldo Carvalho de Melo if (filter && filter(map, f)) 72182164161SArnaldo Carvalho de Melo symbol__delete(f); 72282164161SArnaldo Carvalho de Melo else { 7236a4694a4SArnaldo Carvalho de Melo symbols__insert(&self->symbols[map->type], f); 72486470930SIngo Molnar ++nr; 72586470930SIngo Molnar } 72686470930SIngo Molnar } 72782164161SArnaldo Carvalho de Melo } 72886470930SIngo Molnar 729a25e46c4SArnaldo Carvalho de Melo err = 0; 730a25e46c4SArnaldo Carvalho de Melo out_elf_end: 731a25e46c4SArnaldo Carvalho de Melo elf_end(elf); 732a25e46c4SArnaldo Carvalho de Melo out_close: 733a25e46c4SArnaldo Carvalho de Melo close(fd); 734a25e46c4SArnaldo Carvalho de Melo 735a25e46c4SArnaldo Carvalho de Melo if (err == 0) 73686470930SIngo Molnar return nr; 737a25e46c4SArnaldo Carvalho de Melo out: 7386beba7adSArnaldo Carvalho de Melo pr_warning("%s: problems reading %s PLT info.\n", 739439d473bSArnaldo Carvalho de Melo __func__, self->long_name); 740a25e46c4SArnaldo Carvalho de Melo return 0; 74186470930SIngo Molnar } 74286470930SIngo Molnar 743*95011c60SArnaldo Carvalho de Melo static int dso__load_sym(struct dso *self, struct map *map, 744*95011c60SArnaldo Carvalho de Melo struct thread *thread, const char *name, int fd, 745*95011c60SArnaldo Carvalho de Melo symbol_filter_t filter, int kernel, int kmodule) 74686470930SIngo Molnar { 7472e538c4aSArnaldo Carvalho de Melo struct map *curr_map = map; 7482e538c4aSArnaldo Carvalho de Melo struct dso *curr_dso = self; 7492e538c4aSArnaldo Carvalho de Melo size_t dso_name_len = strlen(self->short_name); 7506cfcc53eSMike Galbraith Elf_Data *symstrs, *secstrs; 75186470930SIngo Molnar uint32_t nr_syms; 75286470930SIngo Molnar int err = -1; 75383a0944fSIngo Molnar uint32_t idx; 75486470930SIngo Molnar GElf_Ehdr ehdr; 75586470930SIngo Molnar GElf_Shdr shdr; 75686470930SIngo Molnar Elf_Data *syms; 75786470930SIngo Molnar GElf_Sym sym; 758a25e46c4SArnaldo Carvalho de Melo Elf_Scn *sec, *sec_strndx; 75986470930SIngo Molnar Elf *elf; 760439d473bSArnaldo Carvalho de Melo int nr = 0; 76186470930SIngo Molnar 76284087126SMarti Raudsepp elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 76386470930SIngo Molnar if (elf == NULL) { 7646beba7adSArnaldo Carvalho de Melo pr_err("%s: cannot read %s ELF file.\n", __func__, name); 76586470930SIngo Molnar goto out_close; 76686470930SIngo Molnar } 76786470930SIngo Molnar 76886470930SIngo Molnar if (gelf_getehdr(elf, &ehdr) == NULL) { 7696beba7adSArnaldo Carvalho de Melo pr_err("%s: cannot get elf header.\n", __func__); 77086470930SIngo Molnar goto out_elf_end; 77186470930SIngo Molnar } 77286470930SIngo Molnar 77386470930SIngo Molnar sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL); 77486470930SIngo Molnar if (sec == NULL) { 775a25e46c4SArnaldo Carvalho de Melo sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL); 776a25e46c4SArnaldo Carvalho de Melo if (sec == NULL) 77786470930SIngo Molnar goto out_elf_end; 77886470930SIngo Molnar } 77986470930SIngo Molnar 78086470930SIngo Molnar syms = elf_getdata(sec, NULL); 78186470930SIngo Molnar if (syms == NULL) 78286470930SIngo Molnar goto out_elf_end; 78386470930SIngo Molnar 78486470930SIngo Molnar sec = elf_getscn(elf, shdr.sh_link); 78586470930SIngo Molnar if (sec == NULL) 78686470930SIngo Molnar goto out_elf_end; 78786470930SIngo Molnar 78886470930SIngo Molnar symstrs = elf_getdata(sec, NULL); 78986470930SIngo Molnar if (symstrs == NULL) 79086470930SIngo Molnar goto out_elf_end; 79186470930SIngo Molnar 7926cfcc53eSMike Galbraith sec_strndx = elf_getscn(elf, ehdr.e_shstrndx); 7936cfcc53eSMike Galbraith if (sec_strndx == NULL) 7946cfcc53eSMike Galbraith goto out_elf_end; 7956cfcc53eSMike Galbraith 7966cfcc53eSMike Galbraith secstrs = elf_getdata(sec_strndx, NULL); 7979b30a26bSStoyan Gaydarov if (secstrs == NULL) 7986cfcc53eSMike Galbraith goto out_elf_end; 7996cfcc53eSMike Galbraith 80086470930SIngo Molnar nr_syms = shdr.sh_size / shdr.sh_entsize; 80186470930SIngo Molnar 802e9fbc9dcSArjan van de Ven memset(&sym, 0, sizeof(sym)); 803d20ff6bdSMike Galbraith if (!kernel) { 80430d7a77dSArnaldo Carvalho de Melo self->adjust_symbols = (ehdr.e_type == ET_EXEC || 80530d7a77dSArnaldo Carvalho de Melo elf_section_by_name(elf, &ehdr, &shdr, 806f5812a7aSArnaldo Carvalho de Melo ".gnu.prelink_undo", 80730d7a77dSArnaldo Carvalho de Melo NULL) != NULL); 808d20ff6bdSMike Galbraith } else self->adjust_symbols = 0; 809d20ff6bdSMike Galbraith 81083a0944fSIngo Molnar elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) { 81186470930SIngo Molnar struct symbol *f; 81283a0944fSIngo Molnar const char *elf_name; 8132e538c4aSArnaldo Carvalho de Melo char *demangled = NULL; 8146cfcc53eSMike Galbraith int is_label = elf_sym__is_label(&sym); 8156cfcc53eSMike Galbraith const char *section_name; 81686470930SIngo Molnar 8176cfcc53eSMike Galbraith if (!is_label && !elf_sym__is_function(&sym)) 81886470930SIngo Molnar continue; 81986470930SIngo Molnar 82086470930SIngo Molnar sec = elf_getscn(elf, sym.st_shndx); 82186470930SIngo Molnar if (!sec) 82286470930SIngo Molnar goto out_elf_end; 82386470930SIngo Molnar 82486470930SIngo Molnar gelf_getshdr(sec, &shdr); 8256cfcc53eSMike Galbraith 8266cfcc53eSMike Galbraith if (is_label && !elf_sec__is_text(&shdr, secstrs)) 8276cfcc53eSMike Galbraith continue; 8286cfcc53eSMike Galbraith 8292e538c4aSArnaldo Carvalho de Melo elf_name = elf_sym__name(&sym, symstrs); 8306cfcc53eSMike Galbraith section_name = elf_sec__name(&shdr, secstrs); 83186470930SIngo Molnar 8322e538c4aSArnaldo Carvalho de Melo if (kernel || kmodule) { 8332e538c4aSArnaldo Carvalho de Melo char dso_name[PATH_MAX]; 8342e538c4aSArnaldo Carvalho de Melo 8352e538c4aSArnaldo Carvalho de Melo if (strcmp(section_name, 8362e538c4aSArnaldo Carvalho de Melo curr_dso->short_name + dso_name_len) == 0) 8372e538c4aSArnaldo Carvalho de Melo goto new_symbol; 8382e538c4aSArnaldo Carvalho de Melo 8392e538c4aSArnaldo Carvalho de Melo if (strcmp(section_name, ".text") == 0) { 8402e538c4aSArnaldo Carvalho de Melo curr_map = map; 8412e538c4aSArnaldo Carvalho de Melo curr_dso = self; 8422e538c4aSArnaldo Carvalho de Melo goto new_symbol; 843af427bf5SArnaldo Carvalho de Melo } 844af427bf5SArnaldo Carvalho de Melo 8452e538c4aSArnaldo Carvalho de Melo snprintf(dso_name, sizeof(dso_name), 8462e538c4aSArnaldo Carvalho de Melo "%s%s", self->short_name, section_name); 8472e538c4aSArnaldo Carvalho de Melo 848*95011c60SArnaldo Carvalho de Melo curr_map = thread__find_map_by_name(thread, dso_name); 8492e538c4aSArnaldo Carvalho de Melo if (curr_map == NULL) { 8502e538c4aSArnaldo Carvalho de Melo u64 start = sym.st_value; 8512e538c4aSArnaldo Carvalho de Melo 8522e538c4aSArnaldo Carvalho de Melo if (kmodule) 8532e538c4aSArnaldo Carvalho de Melo start += map->start + shdr.sh_offset; 8542e538c4aSArnaldo Carvalho de Melo 85500a192b3SArnaldo Carvalho de Melo curr_dso = dso__new(dso_name); 8562e538c4aSArnaldo Carvalho de Melo if (curr_dso == NULL) 8572e538c4aSArnaldo Carvalho de Melo goto out_elf_end; 8583610583cSArnaldo Carvalho de Melo curr_map = map__new2(start, curr_dso, 8593610583cSArnaldo Carvalho de Melo MAP__FUNCTION); 8602e538c4aSArnaldo Carvalho de Melo if (curr_map == NULL) { 8612e538c4aSArnaldo Carvalho de Melo dso__delete(curr_dso); 8622e538c4aSArnaldo Carvalho de Melo goto out_elf_end; 8632e538c4aSArnaldo Carvalho de Melo } 864ed52ce2eSArnaldo Carvalho de Melo curr_map->map_ip = identity__map_ip; 865ed52ce2eSArnaldo Carvalho de Melo curr_map->unmap_ip = identity__map_ip; 8662e538c4aSArnaldo Carvalho de Melo curr_dso->origin = DSO__ORIG_KERNEL; 867*95011c60SArnaldo Carvalho de Melo __thread__insert_map(kthread, curr_map); 868b0da954aSArnaldo Carvalho de Melo dsos__add(&dsos__kernel, curr_dso); 8692e538c4aSArnaldo Carvalho de Melo } else 8702e538c4aSArnaldo Carvalho de Melo curr_dso = curr_map->dso; 8712e538c4aSArnaldo Carvalho de Melo 8722e538c4aSArnaldo Carvalho de Melo goto new_symbol; 8732e538c4aSArnaldo Carvalho de Melo } 8742e538c4aSArnaldo Carvalho de Melo 8752e538c4aSArnaldo Carvalho de Melo if (curr_dso->adjust_symbols) { 8766beba7adSArnaldo Carvalho de Melo pr_debug2("adjusting symbol: st_value: %Lx sh_addr: " 8776beba7adSArnaldo Carvalho de Melo "%Lx sh_offset: %Lx\n", (u64)sym.st_value, 8786beba7adSArnaldo Carvalho de Melo (u64)shdr.sh_addr, (u64)shdr.sh_offset); 87986470930SIngo Molnar sym.st_value -= shdr.sh_addr - shdr.sh_offset; 880af427bf5SArnaldo Carvalho de Melo } 88128ac909bSArnaldo Carvalho de Melo /* 88228ac909bSArnaldo Carvalho de Melo * We need to figure out if the object was created from C++ sources 88328ac909bSArnaldo Carvalho de Melo * DWARF DW_compile_unit has this, but we don't always have access 88428ac909bSArnaldo Carvalho de Melo * to it... 88528ac909bSArnaldo Carvalho de Melo */ 88683a0944fSIngo Molnar demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI); 88728ac909bSArnaldo Carvalho de Melo if (demangled != NULL) 88883a0944fSIngo Molnar elf_name = demangled; 8892e538c4aSArnaldo Carvalho de Melo new_symbol: 89000a192b3SArnaldo Carvalho de Melo f = symbol__new(sym.st_value, sym.st_size, elf_name); 89128ac909bSArnaldo Carvalho de Melo free(demangled); 89286470930SIngo Molnar if (!f) 89386470930SIngo Molnar goto out_elf_end; 89486470930SIngo Molnar 8952e538c4aSArnaldo Carvalho de Melo if (filter && filter(curr_map, f)) 89600a192b3SArnaldo Carvalho de Melo symbol__delete(f); 89786470930SIngo Molnar else { 8986a4694a4SArnaldo Carvalho de Melo symbols__insert(&curr_dso->symbols[curr_map->type], f); 89986470930SIngo Molnar nr++; 90086470930SIngo Molnar } 90186470930SIngo Molnar } 90286470930SIngo Molnar 9032e538c4aSArnaldo Carvalho de Melo /* 9042e538c4aSArnaldo Carvalho de Melo * For misannotated, zeroed, ASM function sizes. 9052e538c4aSArnaldo Carvalho de Melo */ 9062e538c4aSArnaldo Carvalho de Melo if (nr > 0) 9076a4694a4SArnaldo Carvalho de Melo symbols__fixup_end(&self->symbols[map->type]); 90886470930SIngo Molnar err = nr; 90986470930SIngo Molnar out_elf_end: 91086470930SIngo Molnar elf_end(elf); 91186470930SIngo Molnar out_close: 91286470930SIngo Molnar return err; 91386470930SIngo Molnar } 91486470930SIngo Molnar 91578075caaSArnaldo Carvalho de Melo static bool dso__build_id_equal(const struct dso *self, u8 *build_id) 91678075caaSArnaldo Carvalho de Melo { 91778075caaSArnaldo Carvalho de Melo return memcmp(self->build_id, build_id, sizeof(self->build_id)) == 0; 91878075caaSArnaldo Carvalho de Melo } 91978075caaSArnaldo Carvalho de Melo 920b0da954aSArnaldo Carvalho de Melo static bool __dsos__read_build_ids(struct list_head *head) 92157f395a7SFrederic Weisbecker { 922e30a3d12SArnaldo Carvalho de Melo bool have_build_id = false; 92357f395a7SFrederic Weisbecker struct dso *pos; 92457f395a7SFrederic Weisbecker 925b0da954aSArnaldo Carvalho de Melo list_for_each_entry(pos, head, node) 926e30a3d12SArnaldo Carvalho de Melo if (filename__read_build_id(pos->long_name, pos->build_id, 927e30a3d12SArnaldo Carvalho de Melo sizeof(pos->build_id)) > 0) { 928e30a3d12SArnaldo Carvalho de Melo have_build_id = true; 929e30a3d12SArnaldo Carvalho de Melo pos->has_build_id = true; 93057f395a7SFrederic Weisbecker } 93157f395a7SFrederic Weisbecker 932e30a3d12SArnaldo Carvalho de Melo return have_build_id; 93357f395a7SFrederic Weisbecker } 93457f395a7SFrederic Weisbecker 935b0da954aSArnaldo Carvalho de Melo bool dsos__read_build_ids(void) 936b0da954aSArnaldo Carvalho de Melo { 937b0da954aSArnaldo Carvalho de Melo return __dsos__read_build_ids(&dsos__kernel) || 938b0da954aSArnaldo Carvalho de Melo __dsos__read_build_ids(&dsos__user); 939b0da954aSArnaldo Carvalho de Melo } 940b0da954aSArnaldo Carvalho de Melo 941fd7a346eSArnaldo Carvalho de Melo /* 942fd7a346eSArnaldo Carvalho de Melo * Align offset to 4 bytes as needed for note name and descriptor data. 943fd7a346eSArnaldo Carvalho de Melo */ 944fd7a346eSArnaldo Carvalho de Melo #define NOTE_ALIGN(n) (((n) + 3) & -4U) 945fd7a346eSArnaldo Carvalho de Melo 9462643ce11SArnaldo Carvalho de Melo int filename__read_build_id(const char *filename, void *bf, size_t size) 9474d1e00a8SArnaldo Carvalho de Melo { 9482643ce11SArnaldo Carvalho de Melo int fd, err = -1; 9494d1e00a8SArnaldo Carvalho de Melo GElf_Ehdr ehdr; 9504d1e00a8SArnaldo Carvalho de Melo GElf_Shdr shdr; 951fd7a346eSArnaldo Carvalho de Melo Elf_Data *data; 9524d1e00a8SArnaldo Carvalho de Melo Elf_Scn *sec; 953e57cfcdaSPekka Enberg Elf_Kind ek; 954fd7a346eSArnaldo Carvalho de Melo void *ptr; 9554d1e00a8SArnaldo Carvalho de Melo Elf *elf; 9564d1e00a8SArnaldo Carvalho de Melo 9572643ce11SArnaldo Carvalho de Melo if (size < BUILD_ID_SIZE) 9582643ce11SArnaldo Carvalho de Melo goto out; 9592643ce11SArnaldo Carvalho de Melo 9602643ce11SArnaldo Carvalho de Melo fd = open(filename, O_RDONLY); 9614d1e00a8SArnaldo Carvalho de Melo if (fd < 0) 9624d1e00a8SArnaldo Carvalho de Melo goto out; 9634d1e00a8SArnaldo Carvalho de Melo 96484087126SMarti Raudsepp elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 9654d1e00a8SArnaldo Carvalho de Melo if (elf == NULL) { 9668d06367fSArnaldo Carvalho de Melo pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename); 9674d1e00a8SArnaldo Carvalho de Melo goto out_close; 9684d1e00a8SArnaldo Carvalho de Melo } 9694d1e00a8SArnaldo Carvalho de Melo 970e57cfcdaSPekka Enberg ek = elf_kind(elf); 971e57cfcdaSPekka Enberg if (ek != ELF_K_ELF) 972e57cfcdaSPekka Enberg goto out_elf_end; 973e57cfcdaSPekka Enberg 9744d1e00a8SArnaldo Carvalho de Melo if (gelf_getehdr(elf, &ehdr) == NULL) { 9756beba7adSArnaldo Carvalho de Melo pr_err("%s: cannot get elf header.\n", __func__); 9764d1e00a8SArnaldo Carvalho de Melo goto out_elf_end; 9774d1e00a8SArnaldo Carvalho de Melo } 9784d1e00a8SArnaldo Carvalho de Melo 9792643ce11SArnaldo Carvalho de Melo sec = elf_section_by_name(elf, &ehdr, &shdr, 9802643ce11SArnaldo Carvalho de Melo ".note.gnu.build-id", NULL); 981fd7a346eSArnaldo Carvalho de Melo if (sec == NULL) { 982fd7a346eSArnaldo Carvalho de Melo sec = elf_section_by_name(elf, &ehdr, &shdr, 983fd7a346eSArnaldo Carvalho de Melo ".notes", NULL); 9844d1e00a8SArnaldo Carvalho de Melo if (sec == NULL) 9854d1e00a8SArnaldo Carvalho de Melo goto out_elf_end; 986fd7a346eSArnaldo Carvalho de Melo } 9874d1e00a8SArnaldo Carvalho de Melo 988fd7a346eSArnaldo Carvalho de Melo data = elf_getdata(sec, NULL); 989fd7a346eSArnaldo Carvalho de Melo if (data == NULL) 9904d1e00a8SArnaldo Carvalho de Melo goto out_elf_end; 991fd7a346eSArnaldo Carvalho de Melo 992fd7a346eSArnaldo Carvalho de Melo ptr = data->d_buf; 993fd7a346eSArnaldo Carvalho de Melo while (ptr < (data->d_buf + data->d_size)) { 994fd7a346eSArnaldo Carvalho de Melo GElf_Nhdr *nhdr = ptr; 995fd7a346eSArnaldo Carvalho de Melo int namesz = NOTE_ALIGN(nhdr->n_namesz), 996fd7a346eSArnaldo Carvalho de Melo descsz = NOTE_ALIGN(nhdr->n_descsz); 997fd7a346eSArnaldo Carvalho de Melo const char *name; 998fd7a346eSArnaldo Carvalho de Melo 999fd7a346eSArnaldo Carvalho de Melo ptr += sizeof(*nhdr); 1000fd7a346eSArnaldo Carvalho de Melo name = ptr; 1001fd7a346eSArnaldo Carvalho de Melo ptr += namesz; 1002fd7a346eSArnaldo Carvalho de Melo if (nhdr->n_type == NT_GNU_BUILD_ID && 1003fd7a346eSArnaldo Carvalho de Melo nhdr->n_namesz == sizeof("GNU")) { 1004fd7a346eSArnaldo Carvalho de Melo if (memcmp(name, "GNU", sizeof("GNU")) == 0) { 1005fd7a346eSArnaldo Carvalho de Melo memcpy(bf, ptr, BUILD_ID_SIZE); 10062643ce11SArnaldo Carvalho de Melo err = BUILD_ID_SIZE; 1007fd7a346eSArnaldo Carvalho de Melo break; 1008fd7a346eSArnaldo Carvalho de Melo } 1009fd7a346eSArnaldo Carvalho de Melo } 1010fd7a346eSArnaldo Carvalho de Melo ptr += descsz; 1011fd7a346eSArnaldo Carvalho de Melo } 10122643ce11SArnaldo Carvalho de Melo out_elf_end: 10132643ce11SArnaldo Carvalho de Melo elf_end(elf); 10142643ce11SArnaldo Carvalho de Melo out_close: 10152643ce11SArnaldo Carvalho de Melo close(fd); 10162643ce11SArnaldo Carvalho de Melo out: 10172643ce11SArnaldo Carvalho de Melo return err; 10182643ce11SArnaldo Carvalho de Melo } 10192643ce11SArnaldo Carvalho de Melo 1020f1617b40SArnaldo Carvalho de Melo int sysfs__read_build_id(const char *filename, void *build_id, size_t size) 1021f1617b40SArnaldo Carvalho de Melo { 1022f1617b40SArnaldo Carvalho de Melo int fd, err = -1; 1023f1617b40SArnaldo Carvalho de Melo 1024f1617b40SArnaldo Carvalho de Melo if (size < BUILD_ID_SIZE) 1025f1617b40SArnaldo Carvalho de Melo goto out; 1026f1617b40SArnaldo Carvalho de Melo 1027f1617b40SArnaldo Carvalho de Melo fd = open(filename, O_RDONLY); 1028f1617b40SArnaldo Carvalho de Melo if (fd < 0) 1029f1617b40SArnaldo Carvalho de Melo goto out; 1030f1617b40SArnaldo Carvalho de Melo 1031f1617b40SArnaldo Carvalho de Melo while (1) { 1032f1617b40SArnaldo Carvalho de Melo char bf[BUFSIZ]; 1033f1617b40SArnaldo Carvalho de Melo GElf_Nhdr nhdr; 1034f1617b40SArnaldo Carvalho de Melo int namesz, descsz; 1035f1617b40SArnaldo Carvalho de Melo 1036f1617b40SArnaldo Carvalho de Melo if (read(fd, &nhdr, sizeof(nhdr)) != sizeof(nhdr)) 1037f1617b40SArnaldo Carvalho de Melo break; 1038f1617b40SArnaldo Carvalho de Melo 1039fd7a346eSArnaldo Carvalho de Melo namesz = NOTE_ALIGN(nhdr.n_namesz); 1040fd7a346eSArnaldo Carvalho de Melo descsz = NOTE_ALIGN(nhdr.n_descsz); 1041f1617b40SArnaldo Carvalho de Melo if (nhdr.n_type == NT_GNU_BUILD_ID && 1042f1617b40SArnaldo Carvalho de Melo nhdr.n_namesz == sizeof("GNU")) { 1043f1617b40SArnaldo Carvalho de Melo if (read(fd, bf, namesz) != namesz) 1044f1617b40SArnaldo Carvalho de Melo break; 1045f1617b40SArnaldo Carvalho de Melo if (memcmp(bf, "GNU", sizeof("GNU")) == 0) { 1046f1617b40SArnaldo Carvalho de Melo if (read(fd, build_id, 1047f1617b40SArnaldo Carvalho de Melo BUILD_ID_SIZE) == BUILD_ID_SIZE) { 1048f1617b40SArnaldo Carvalho de Melo err = 0; 1049f1617b40SArnaldo Carvalho de Melo break; 1050f1617b40SArnaldo Carvalho de Melo } 1051f1617b40SArnaldo Carvalho de Melo } else if (read(fd, bf, descsz) != descsz) 1052f1617b40SArnaldo Carvalho de Melo break; 1053f1617b40SArnaldo Carvalho de Melo } else { 1054f1617b40SArnaldo Carvalho de Melo int n = namesz + descsz; 1055f1617b40SArnaldo Carvalho de Melo if (read(fd, bf, n) != n) 1056f1617b40SArnaldo Carvalho de Melo break; 1057f1617b40SArnaldo Carvalho de Melo } 1058f1617b40SArnaldo Carvalho de Melo } 1059f1617b40SArnaldo Carvalho de Melo close(fd); 1060f1617b40SArnaldo Carvalho de Melo out: 1061f1617b40SArnaldo Carvalho de Melo return err; 1062f1617b40SArnaldo Carvalho de Melo } 1063f1617b40SArnaldo Carvalho de Melo 106494cb9e38SArnaldo Carvalho de Melo char dso__symtab_origin(const struct dso *self) 106594cb9e38SArnaldo Carvalho de Melo { 106694cb9e38SArnaldo Carvalho de Melo static const char origin[] = { 106794cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_KERNEL] = 'k', 106894cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_JAVA_JIT] = 'j', 106994cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_FEDORA] = 'f', 107094cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_UBUNTU] = 'u', 107194cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_BUILDID] = 'b', 107294cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_DSO] = 'd', 1073439d473bSArnaldo Carvalho de Melo [DSO__ORIG_KMODULE] = 'K', 107494cb9e38SArnaldo Carvalho de Melo }; 107594cb9e38SArnaldo Carvalho de Melo 107694cb9e38SArnaldo Carvalho de Melo if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND) 107794cb9e38SArnaldo Carvalho de Melo return '!'; 107894cb9e38SArnaldo Carvalho de Melo return origin[self->origin]; 107994cb9e38SArnaldo Carvalho de Melo } 108094cb9e38SArnaldo Carvalho de Melo 10816beba7adSArnaldo Carvalho de Melo int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) 108286470930SIngo Molnar { 10834d1e00a8SArnaldo Carvalho de Melo int size = PATH_MAX; 1084c338aee8SArnaldo Carvalho de Melo char *name; 1085d3379ab9SArnaldo Carvalho de Melo u8 build_id[BUILD_ID_SIZE]; 108686470930SIngo Molnar int ret = -1; 108786470930SIngo Molnar int fd; 108886470930SIngo Molnar 10893610583cSArnaldo Carvalho de Melo dso__set_loaded(self, map->type); 109066bd8424SArnaldo Carvalho de Melo 1091c338aee8SArnaldo Carvalho de Melo if (self->kernel) 1092*95011c60SArnaldo Carvalho de Melo return dso__load_kernel_sym(self, map, kthread, filter); 1093c338aee8SArnaldo Carvalho de Melo 1094c338aee8SArnaldo Carvalho de Melo name = malloc(size); 109586470930SIngo Molnar if (!name) 109686470930SIngo Molnar return -1; 109786470930SIngo Molnar 109830d7a77dSArnaldo Carvalho de Melo self->adjust_symbols = 0; 1099f5812a7aSArnaldo Carvalho de Melo 110094cb9e38SArnaldo Carvalho de Melo if (strncmp(self->name, "/tmp/perf-", 10) == 0) { 11016beba7adSArnaldo Carvalho de Melo ret = dso__load_perf_map(self, map, filter); 110294cb9e38SArnaldo Carvalho de Melo self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT : 110394cb9e38SArnaldo Carvalho de Melo DSO__ORIG_NOT_FOUND; 110494cb9e38SArnaldo Carvalho de Melo return ret; 110594cb9e38SArnaldo Carvalho de Melo } 110694cb9e38SArnaldo Carvalho de Melo 110794cb9e38SArnaldo Carvalho de Melo self->origin = DSO__ORIG_FEDORA - 1; 110880d496beSPekka Enberg 110986470930SIngo Molnar more: 111086470930SIngo Molnar do { 111194cb9e38SArnaldo Carvalho de Melo self->origin++; 111294cb9e38SArnaldo Carvalho de Melo switch (self->origin) { 111394cb9e38SArnaldo Carvalho de Melo case DSO__ORIG_FEDORA: 1114439d473bSArnaldo Carvalho de Melo snprintf(name, size, "/usr/lib/debug%s.debug", 1115439d473bSArnaldo Carvalho de Melo self->long_name); 111686470930SIngo Molnar break; 111794cb9e38SArnaldo Carvalho de Melo case DSO__ORIG_UBUNTU: 1118439d473bSArnaldo Carvalho de Melo snprintf(name, size, "/usr/lib/debug%s", 1119439d473bSArnaldo Carvalho de Melo self->long_name); 112086470930SIngo Molnar break; 112194cb9e38SArnaldo Carvalho de Melo case DSO__ORIG_BUILDID: 1122d3379ab9SArnaldo Carvalho de Melo if (filename__read_build_id(self->long_name, build_id, 1123d3379ab9SArnaldo Carvalho de Melo sizeof(build_id))) { 1124d3379ab9SArnaldo Carvalho de Melo char build_id_hex[BUILD_ID_SIZE * 2 + 1]; 1125d3379ab9SArnaldo Carvalho de Melo 1126d3379ab9SArnaldo Carvalho de Melo build_id__sprintf(build_id, sizeof(build_id), 1127d3379ab9SArnaldo Carvalho de Melo build_id_hex); 11284d1e00a8SArnaldo Carvalho de Melo snprintf(name, size, 11294d1e00a8SArnaldo Carvalho de Melo "/usr/lib/debug/.build-id/%.2s/%s.debug", 1130d3379ab9SArnaldo Carvalho de Melo build_id_hex, build_id_hex + 2); 1131d3379ab9SArnaldo Carvalho de Melo if (self->has_build_id) 11328d06367fSArnaldo Carvalho de Melo goto compare_build_id; 1133d3379ab9SArnaldo Carvalho de Melo break; 11344d1e00a8SArnaldo Carvalho de Melo } 113594cb9e38SArnaldo Carvalho de Melo self->origin++; 11364d1e00a8SArnaldo Carvalho de Melo /* Fall thru */ 113794cb9e38SArnaldo Carvalho de Melo case DSO__ORIG_DSO: 1138439d473bSArnaldo Carvalho de Melo snprintf(name, size, "%s", self->long_name); 113986470930SIngo Molnar break; 114086470930SIngo Molnar 114186470930SIngo Molnar default: 114286470930SIngo Molnar goto out; 114386470930SIngo Molnar } 114486470930SIngo Molnar 11458d06367fSArnaldo Carvalho de Melo if (self->has_build_id) { 1146d3379ab9SArnaldo Carvalho de Melo if (filename__read_build_id(name, build_id, 1147d3379ab9SArnaldo Carvalho de Melo sizeof(build_id)) < 0) 11488d06367fSArnaldo Carvalho de Melo goto more; 11498d06367fSArnaldo Carvalho de Melo compare_build_id: 115078075caaSArnaldo Carvalho de Melo if (!dso__build_id_equal(self, build_id)) 11518d06367fSArnaldo Carvalho de Melo goto more; 11528d06367fSArnaldo Carvalho de Melo } 11538d06367fSArnaldo Carvalho de Melo 115486470930SIngo Molnar fd = open(name, O_RDONLY); 115586470930SIngo Molnar } while (fd < 0); 115686470930SIngo Molnar 1157*95011c60SArnaldo Carvalho de Melo ret = dso__load_sym(self, map, NULL, name, fd, filter, 0, 0); 115886470930SIngo Molnar close(fd); 115986470930SIngo Molnar 116086470930SIngo Molnar /* 116186470930SIngo Molnar * Some people seem to have debuginfo files _WITHOUT_ debug info!?!? 116286470930SIngo Molnar */ 116386470930SIngo Molnar if (!ret) 116486470930SIngo Molnar goto more; 116586470930SIngo Molnar 1166a25e46c4SArnaldo Carvalho de Melo if (ret > 0) { 116782164161SArnaldo Carvalho de Melo int nr_plt = dso__synthesize_plt_symbols(self, map, filter); 1168a25e46c4SArnaldo Carvalho de Melo if (nr_plt > 0) 1169a25e46c4SArnaldo Carvalho de Melo ret += nr_plt; 1170a25e46c4SArnaldo Carvalho de Melo } 117186470930SIngo Molnar out: 117286470930SIngo Molnar free(name); 11731340e6bbSArnaldo Carvalho de Melo if (ret < 0 && strstr(self->name, " (deleted)") != NULL) 11741340e6bbSArnaldo Carvalho de Melo return 0; 117586470930SIngo Molnar return ret; 117686470930SIngo Molnar } 117786470930SIngo Molnar 1178*95011c60SArnaldo Carvalho de Melo static struct symbol *thread__find_symbol(struct thread *self, u64 ip, 1179*95011c60SArnaldo Carvalho de Melo enum map_type type, struct map **mapp, 1180c338aee8SArnaldo Carvalho de Melo symbol_filter_t filter) 1181439d473bSArnaldo Carvalho de Melo { 1182*95011c60SArnaldo Carvalho de Melo struct map *map = thread__find_map(self, type, ip); 1183439d473bSArnaldo Carvalho de Melo 1184439d473bSArnaldo Carvalho de Melo if (mapp) 1185439d473bSArnaldo Carvalho de Melo *mapp = map; 1186439d473bSArnaldo Carvalho de Melo 11872e538c4aSArnaldo Carvalho de Melo if (map) { 11882e538c4aSArnaldo Carvalho de Melo ip = map->map_ip(map, ip); 11896a4694a4SArnaldo Carvalho de Melo return map__find_symbol(map, ip, filter); 1190*95011c60SArnaldo Carvalho de Melo } 11912e538c4aSArnaldo Carvalho de Melo 11922e538c4aSArnaldo Carvalho de Melo return NULL; 1193439d473bSArnaldo Carvalho de Melo } 1194439d473bSArnaldo Carvalho de Melo 119523ea4a3fSArnaldo Carvalho de Melo struct symbol *kernel_maps__find_function(u64 ip, struct map **mapp, 119623ea4a3fSArnaldo Carvalho de Melo symbol_filter_t filter) 119723ea4a3fSArnaldo Carvalho de Melo { 1198*95011c60SArnaldo Carvalho de Melo return thread__find_symbol(kthread, ip, MAP__FUNCTION, mapp, filter); 119923ea4a3fSArnaldo Carvalho de Melo } 120023ea4a3fSArnaldo Carvalho de Melo 1201*95011c60SArnaldo Carvalho de Melo static struct map *thread__find_map_by_name(struct thread *self, char *name) 1202439d473bSArnaldo Carvalho de Melo { 1203439d473bSArnaldo Carvalho de Melo struct rb_node *nd; 1204439d473bSArnaldo Carvalho de Melo 1205*95011c60SArnaldo Carvalho de Melo for (nd = rb_first(&self->maps[MAP__FUNCTION]); nd; nd = rb_next(nd)) { 1206439d473bSArnaldo Carvalho de Melo struct map *map = rb_entry(nd, struct map, rb_node); 1207439d473bSArnaldo Carvalho de Melo 1208439d473bSArnaldo Carvalho de Melo if (map->dso && strcmp(map->dso->name, name) == 0) 1209439d473bSArnaldo Carvalho de Melo return map; 1210439d473bSArnaldo Carvalho de Melo } 1211439d473bSArnaldo Carvalho de Melo 1212439d473bSArnaldo Carvalho de Melo return NULL; 1213439d473bSArnaldo Carvalho de Melo } 1214439d473bSArnaldo Carvalho de Melo 1215c338aee8SArnaldo Carvalho de Melo static int dsos__set_modules_path_dir(char *dirname) 12166cfcc53eSMike Galbraith { 1217439d473bSArnaldo Carvalho de Melo struct dirent *dent; 1218439d473bSArnaldo Carvalho de Melo DIR *dir = opendir(dirname); 12196cfcc53eSMike Galbraith 1220439d473bSArnaldo Carvalho de Melo if (!dir) { 122187f8ea4cSArnaldo Carvalho de Melo pr_debug("%s: cannot open %s dir\n", __func__, dirname); 1222439d473bSArnaldo Carvalho de Melo return -1; 1223439d473bSArnaldo Carvalho de Melo } 12246cfcc53eSMike Galbraith 1225439d473bSArnaldo Carvalho de Melo while ((dent = readdir(dir)) != NULL) { 1226439d473bSArnaldo Carvalho de Melo char path[PATH_MAX]; 1227439d473bSArnaldo Carvalho de Melo 1228439d473bSArnaldo Carvalho de Melo if (dent->d_type == DT_DIR) { 1229439d473bSArnaldo Carvalho de Melo if (!strcmp(dent->d_name, ".") || 1230439d473bSArnaldo Carvalho de Melo !strcmp(dent->d_name, "..")) 1231439d473bSArnaldo Carvalho de Melo continue; 1232439d473bSArnaldo Carvalho de Melo 1233439d473bSArnaldo Carvalho de Melo snprintf(path, sizeof(path), "%s/%s", 1234439d473bSArnaldo Carvalho de Melo dirname, dent->d_name); 1235c338aee8SArnaldo Carvalho de Melo if (dsos__set_modules_path_dir(path) < 0) 1236439d473bSArnaldo Carvalho de Melo goto failure; 1237439d473bSArnaldo Carvalho de Melo } else { 1238439d473bSArnaldo Carvalho de Melo char *dot = strrchr(dent->d_name, '.'), 1239439d473bSArnaldo Carvalho de Melo dso_name[PATH_MAX]; 1240439d473bSArnaldo Carvalho de Melo struct map *map; 1241cfc10d3bSArnaldo Carvalho de Melo char *long_name; 1242439d473bSArnaldo Carvalho de Melo 1243439d473bSArnaldo Carvalho de Melo if (dot == NULL || strcmp(dot, ".ko")) 1244439d473bSArnaldo Carvalho de Melo continue; 1245439d473bSArnaldo Carvalho de Melo snprintf(dso_name, sizeof(dso_name), "[%.*s]", 1246439d473bSArnaldo Carvalho de Melo (int)(dot - dent->d_name), dent->d_name); 1247439d473bSArnaldo Carvalho de Melo 1248a2a99e8eSArnaldo Carvalho de Melo strxfrchar(dso_name, '-', '_'); 1249*95011c60SArnaldo Carvalho de Melo map = thread__find_map_by_name(kthread, dso_name); 1250439d473bSArnaldo Carvalho de Melo if (map == NULL) 1251439d473bSArnaldo Carvalho de Melo continue; 1252439d473bSArnaldo Carvalho de Melo 1253439d473bSArnaldo Carvalho de Melo snprintf(path, sizeof(path), "%s/%s", 1254439d473bSArnaldo Carvalho de Melo dirname, dent->d_name); 1255439d473bSArnaldo Carvalho de Melo 1256cfc10d3bSArnaldo Carvalho de Melo long_name = strdup(path); 1257cfc10d3bSArnaldo Carvalho de Melo if (long_name == NULL) 1258439d473bSArnaldo Carvalho de Melo goto failure; 1259cfc10d3bSArnaldo Carvalho de Melo dso__set_long_name(map->dso, long_name); 1260439d473bSArnaldo Carvalho de Melo } 1261439d473bSArnaldo Carvalho de Melo } 1262439d473bSArnaldo Carvalho de Melo 1263c338aee8SArnaldo Carvalho de Melo return 0; 1264439d473bSArnaldo Carvalho de Melo failure: 1265439d473bSArnaldo Carvalho de Melo closedir(dir); 1266439d473bSArnaldo Carvalho de Melo return -1; 1267439d473bSArnaldo Carvalho de Melo } 1268439d473bSArnaldo Carvalho de Melo 1269c338aee8SArnaldo Carvalho de Melo static int dsos__set_modules_path(void) 1270439d473bSArnaldo Carvalho de Melo { 1271439d473bSArnaldo Carvalho de Melo struct utsname uts; 1272439d473bSArnaldo Carvalho de Melo char modules_path[PATH_MAX]; 1273439d473bSArnaldo Carvalho de Melo 1274439d473bSArnaldo Carvalho de Melo if (uname(&uts) < 0) 1275439d473bSArnaldo Carvalho de Melo return -1; 1276439d473bSArnaldo Carvalho de Melo 1277439d473bSArnaldo Carvalho de Melo snprintf(modules_path, sizeof(modules_path), "/lib/modules/%s/kernel", 1278439d473bSArnaldo Carvalho de Melo uts.release); 1279439d473bSArnaldo Carvalho de Melo 1280c338aee8SArnaldo Carvalho de Melo return dsos__set_modules_path_dir(modules_path); 1281439d473bSArnaldo Carvalho de Melo } 12826cfcc53eSMike Galbraith 12836cfcc53eSMike Galbraith /* 1284439d473bSArnaldo Carvalho de Melo * Constructor variant for modules (where we know from /proc/modules where 1285439d473bSArnaldo Carvalho de Melo * they are loaded) and for vmlinux, where only after we load all the 1286439d473bSArnaldo Carvalho de Melo * symbols we'll know where it starts and ends. 12876cfcc53eSMike Galbraith */ 12883610583cSArnaldo Carvalho de Melo static struct map *map__new2(u64 start, struct dso *dso, enum map_type type) 1289439d473bSArnaldo Carvalho de Melo { 1290439d473bSArnaldo Carvalho de Melo struct map *self = malloc(sizeof(*self)); 12916cfcc53eSMike Galbraith 1292439d473bSArnaldo Carvalho de Melo if (self != NULL) { 1293439d473bSArnaldo Carvalho de Melo /* 1294afb7b4f0SArnaldo Carvalho de Melo * ->end will be filled after we load all the symbols 1295439d473bSArnaldo Carvalho de Melo */ 12963610583cSArnaldo Carvalho de Melo map__init(self, type, start, 0, 0, dso); 1297439d473bSArnaldo Carvalho de Melo } 1298afb7b4f0SArnaldo Carvalho de Melo 1299439d473bSArnaldo Carvalho de Melo return self; 1300439d473bSArnaldo Carvalho de Melo } 1301439d473bSArnaldo Carvalho de Melo 1302*95011c60SArnaldo Carvalho de Melo static int thread__create_module_maps(struct thread *self) 1303439d473bSArnaldo Carvalho de Melo { 1304439d473bSArnaldo Carvalho de Melo char *line = NULL; 1305439d473bSArnaldo Carvalho de Melo size_t n; 1306439d473bSArnaldo Carvalho de Melo FILE *file = fopen("/proc/modules", "r"); 1307439d473bSArnaldo Carvalho de Melo struct map *map; 1308439d473bSArnaldo Carvalho de Melo 1309439d473bSArnaldo Carvalho de Melo if (file == NULL) 1310439d473bSArnaldo Carvalho de Melo return -1; 1311439d473bSArnaldo Carvalho de Melo 1312439d473bSArnaldo Carvalho de Melo while (!feof(file)) { 1313439d473bSArnaldo Carvalho de Melo char name[PATH_MAX]; 1314439d473bSArnaldo Carvalho de Melo u64 start; 1315439d473bSArnaldo Carvalho de Melo struct dso *dso; 1316439d473bSArnaldo Carvalho de Melo char *sep; 1317439d473bSArnaldo Carvalho de Melo int line_len; 1318439d473bSArnaldo Carvalho de Melo 1319439d473bSArnaldo Carvalho de Melo line_len = getline(&line, &n, file); 1320439d473bSArnaldo Carvalho de Melo if (line_len < 0) 13216cfcc53eSMike Galbraith break; 13226cfcc53eSMike Galbraith 1323439d473bSArnaldo Carvalho de Melo if (!line) 1324439d473bSArnaldo Carvalho de Melo goto out_failure; 1325439d473bSArnaldo Carvalho de Melo 1326439d473bSArnaldo Carvalho de Melo line[--line_len] = '\0'; /* \n */ 1327439d473bSArnaldo Carvalho de Melo 1328439d473bSArnaldo Carvalho de Melo sep = strrchr(line, 'x'); 1329439d473bSArnaldo Carvalho de Melo if (sep == NULL) 1330439d473bSArnaldo Carvalho de Melo continue; 1331439d473bSArnaldo Carvalho de Melo 1332439d473bSArnaldo Carvalho de Melo hex2u64(sep + 1, &start); 1333439d473bSArnaldo Carvalho de Melo 1334439d473bSArnaldo Carvalho de Melo sep = strchr(line, ' '); 1335439d473bSArnaldo Carvalho de Melo if (sep == NULL) 1336439d473bSArnaldo Carvalho de Melo continue; 1337439d473bSArnaldo Carvalho de Melo 1338439d473bSArnaldo Carvalho de Melo *sep = '\0'; 1339439d473bSArnaldo Carvalho de Melo 1340439d473bSArnaldo Carvalho de Melo snprintf(name, sizeof(name), "[%s]", line); 134100a192b3SArnaldo Carvalho de Melo dso = dso__new(name); 1342439d473bSArnaldo Carvalho de Melo 1343439d473bSArnaldo Carvalho de Melo if (dso == NULL) 1344439d473bSArnaldo Carvalho de Melo goto out_delete_line; 1345439d473bSArnaldo Carvalho de Melo 13463610583cSArnaldo Carvalho de Melo map = map__new2(start, dso, MAP__FUNCTION); 1347439d473bSArnaldo Carvalho de Melo if (map == NULL) { 1348439d473bSArnaldo Carvalho de Melo dso__delete(dso); 1349439d473bSArnaldo Carvalho de Melo goto out_delete_line; 13506cfcc53eSMike Galbraith } 13516cfcc53eSMike Galbraith 1352f1617b40SArnaldo Carvalho de Melo snprintf(name, sizeof(name), 1353f1617b40SArnaldo Carvalho de Melo "/sys/module/%s/notes/.note.gnu.build-id", line); 1354f1617b40SArnaldo Carvalho de Melo if (sysfs__read_build_id(name, dso->build_id, 1355f1617b40SArnaldo Carvalho de Melo sizeof(dso->build_id)) == 0) 1356f1617b40SArnaldo Carvalho de Melo dso->has_build_id = true; 1357f1617b40SArnaldo Carvalho de Melo 1358439d473bSArnaldo Carvalho de Melo dso->origin = DSO__ORIG_KMODULE; 1359*95011c60SArnaldo Carvalho de Melo __thread__insert_map(self, map); 1360b0da954aSArnaldo Carvalho de Melo dsos__add(&dsos__kernel, dso); 13616cfcc53eSMike Galbraith } 13626cfcc53eSMike Galbraith 1363439d473bSArnaldo Carvalho de Melo free(line); 1364439d473bSArnaldo Carvalho de Melo fclose(file); 1365439d473bSArnaldo Carvalho de Melo 1366c338aee8SArnaldo Carvalho de Melo return dsos__set_modules_path(); 1367439d473bSArnaldo Carvalho de Melo 1368439d473bSArnaldo Carvalho de Melo out_delete_line: 1369439d473bSArnaldo Carvalho de Melo free(line); 1370439d473bSArnaldo Carvalho de Melo out_failure: 1371439d473bSArnaldo Carvalho de Melo return -1; 13726cfcc53eSMike Galbraith } 13736cfcc53eSMike Galbraith 1374*95011c60SArnaldo Carvalho de Melo static int dso__load_vmlinux(struct dso *self, struct map *map, struct thread *thread, 13756beba7adSArnaldo Carvalho de Melo const char *vmlinux, symbol_filter_t filter) 137686470930SIngo Molnar { 1377fbd733b8SArnaldo Carvalho de Melo int err = -1, fd; 137886470930SIngo Molnar 1379fbd733b8SArnaldo Carvalho de Melo if (self->has_build_id) { 1380fbd733b8SArnaldo Carvalho de Melo u8 build_id[BUILD_ID_SIZE]; 138166bd8424SArnaldo Carvalho de Melo 1382fbd733b8SArnaldo Carvalho de Melo if (filename__read_build_id(vmlinux, build_id, 1383fbd733b8SArnaldo Carvalho de Melo sizeof(build_id)) < 0) { 1384fbd733b8SArnaldo Carvalho de Melo pr_debug("No build_id in %s, ignoring it\n", vmlinux); 1385fbd733b8SArnaldo Carvalho de Melo return -1; 1386fbd733b8SArnaldo Carvalho de Melo } 1387fbd733b8SArnaldo Carvalho de Melo if (!dso__build_id_equal(self, build_id)) { 1388fbd733b8SArnaldo Carvalho de Melo char expected_build_id[BUILD_ID_SIZE * 2 + 1], 1389fbd733b8SArnaldo Carvalho de Melo vmlinux_build_id[BUILD_ID_SIZE * 2 + 1]; 1390fbd733b8SArnaldo Carvalho de Melo 1391fbd733b8SArnaldo Carvalho de Melo build_id__sprintf(self->build_id, 1392fbd733b8SArnaldo Carvalho de Melo sizeof(self->build_id), 1393fbd733b8SArnaldo Carvalho de Melo expected_build_id); 1394fbd733b8SArnaldo Carvalho de Melo build_id__sprintf(build_id, sizeof(build_id), 1395fbd733b8SArnaldo Carvalho de Melo vmlinux_build_id); 1396fbd733b8SArnaldo Carvalho de Melo pr_debug("build_id in %s is %s while expected is %s, " 1397fbd733b8SArnaldo Carvalho de Melo "ignoring it\n", vmlinux, vmlinux_build_id, 1398fbd733b8SArnaldo Carvalho de Melo expected_build_id); 1399fbd733b8SArnaldo Carvalho de Melo return -1; 1400fbd733b8SArnaldo Carvalho de Melo } 1401fbd733b8SArnaldo Carvalho de Melo } 1402fbd733b8SArnaldo Carvalho de Melo 1403fbd733b8SArnaldo Carvalho de Melo fd = open(vmlinux, O_RDONLY); 140486470930SIngo Molnar if (fd < 0) 140586470930SIngo Molnar return -1; 140686470930SIngo Molnar 14073610583cSArnaldo Carvalho de Melo dso__set_loaded(self, map->type); 1408*95011c60SArnaldo Carvalho de Melo err = dso__load_sym(self, map, thread, self->long_name, fd, filter, 1, 0); 140986470930SIngo Molnar close(fd); 141086470930SIngo Molnar 141186470930SIngo Molnar return err; 141286470930SIngo Molnar } 141386470930SIngo Molnar 1414c338aee8SArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *self, struct map *map, 1415*95011c60SArnaldo Carvalho de Melo struct thread *thread, symbol_filter_t filter) 141686470930SIngo Molnar { 1417cc612d81SArnaldo Carvalho de Melo int err; 1418cc612d81SArnaldo Carvalho de Melo bool is_kallsyms; 1419439d473bSArnaldo Carvalho de Melo 1420cc612d81SArnaldo Carvalho de Melo if (vmlinux_path != NULL) { 1421cc612d81SArnaldo Carvalho de Melo int i; 1422cc612d81SArnaldo Carvalho de Melo pr_debug("Looking at the vmlinux_path (%d entries long)\n", 1423cc612d81SArnaldo Carvalho de Melo vmlinux_path__nr_entries); 1424cc612d81SArnaldo Carvalho de Melo for (i = 0; i < vmlinux_path__nr_entries; ++i) { 1425*95011c60SArnaldo Carvalho de Melo err = dso__load_vmlinux(self, map, thread, 1426*95011c60SArnaldo Carvalho de Melo vmlinux_path[i], filter); 1427cc612d81SArnaldo Carvalho de Melo if (err > 0) { 1428cc612d81SArnaldo Carvalho de Melo pr_debug("Using %s for symbols\n", 1429cc612d81SArnaldo Carvalho de Melo vmlinux_path[i]); 1430cc612d81SArnaldo Carvalho de Melo dso__set_long_name(self, 1431cc612d81SArnaldo Carvalho de Melo strdup(vmlinux_path[i])); 1432cc612d81SArnaldo Carvalho de Melo goto out_fixup; 1433cc612d81SArnaldo Carvalho de Melo } 1434cc612d81SArnaldo Carvalho de Melo } 1435cc612d81SArnaldo Carvalho de Melo } 1436cc612d81SArnaldo Carvalho de Melo 1437cc612d81SArnaldo Carvalho de Melo is_kallsyms = self->long_name[0] == '['; 1438cc612d81SArnaldo Carvalho de Melo if (is_kallsyms) 1439cc612d81SArnaldo Carvalho de Melo goto do_kallsyms; 1440cc612d81SArnaldo Carvalho de Melo 1441*95011c60SArnaldo Carvalho de Melo err = dso__load_vmlinux(self, map, thread, self->long_name, filter); 1442ef6ae724SArnaldo Carvalho de Melo if (err <= 0) { 1443cc612d81SArnaldo Carvalho de Melo pr_info("The file %s cannot be used, " 1444cc612d81SArnaldo Carvalho de Melo "trying to use /proc/kallsyms...", self->long_name); 1445cc612d81SArnaldo Carvalho de Melo do_kallsyms: 1446*95011c60SArnaldo Carvalho de Melo err = dso__load_kallsyms(self, map, thread, filter); 1447cc612d81SArnaldo Carvalho de Melo if (err > 0 && !is_kallsyms) 1448ef6ae724SArnaldo Carvalho de Melo dso__set_long_name(self, strdup("[kernel.kallsyms]")); 1449ef6ae724SArnaldo Carvalho de Melo } 145086470930SIngo Molnar 1451439d473bSArnaldo Carvalho de Melo if (err > 0) { 1452cc612d81SArnaldo Carvalho de Melo out_fixup: 14536a4694a4SArnaldo Carvalho de Melo map__fixup_start(map); 14546a4694a4SArnaldo Carvalho de Melo map__fixup_end(map); 1455439d473bSArnaldo Carvalho de Melo } 145694cb9e38SArnaldo Carvalho de Melo 145786470930SIngo Molnar return err; 145886470930SIngo Molnar } 145986470930SIngo Molnar 1460b0da954aSArnaldo Carvalho de Melo LIST_HEAD(dsos__user); 1461b0da954aSArnaldo Carvalho de Melo LIST_HEAD(dsos__kernel); 1462cd84c2acSFrederic Weisbecker struct dso *vdso; 1463cd84c2acSFrederic Weisbecker 1464b0da954aSArnaldo Carvalho de Melo static void dsos__add(struct list_head *head, struct dso *dso) 1465cd84c2acSFrederic Weisbecker { 1466b0da954aSArnaldo Carvalho de Melo list_add_tail(&dso->node, head); 1467cd84c2acSFrederic Weisbecker } 1468cd84c2acSFrederic Weisbecker 1469b0da954aSArnaldo Carvalho de Melo static struct dso *dsos__find(struct list_head *head, const char *name) 1470cd84c2acSFrederic Weisbecker { 1471cd84c2acSFrederic Weisbecker struct dso *pos; 1472cd84c2acSFrederic Weisbecker 1473b0da954aSArnaldo Carvalho de Melo list_for_each_entry(pos, head, node) 1474cd84c2acSFrederic Weisbecker if (strcmp(pos->name, name) == 0) 1475cd84c2acSFrederic Weisbecker return pos; 1476cd84c2acSFrederic Weisbecker return NULL; 1477cd84c2acSFrederic Weisbecker } 1478cd84c2acSFrederic Weisbecker 147900a192b3SArnaldo Carvalho de Melo struct dso *dsos__findnew(const char *name) 1480cd84c2acSFrederic Weisbecker { 1481b0da954aSArnaldo Carvalho de Melo struct dso *dso = dsos__find(&dsos__user, name); 1482cd84c2acSFrederic Weisbecker 1483e4204992SArnaldo Carvalho de Melo if (!dso) { 148400a192b3SArnaldo Carvalho de Melo dso = dso__new(name); 1485cfc10d3bSArnaldo Carvalho de Melo if (dso != NULL) { 1486b0da954aSArnaldo Carvalho de Melo dsos__add(&dsos__user, dso); 1487cfc10d3bSArnaldo Carvalho de Melo dso__set_basename(dso); 1488cfc10d3bSArnaldo Carvalho de Melo } 1489e4204992SArnaldo Carvalho de Melo } 1490cd84c2acSFrederic Weisbecker 1491cd84c2acSFrederic Weisbecker return dso; 1492cd84c2acSFrederic Weisbecker } 1493cd84c2acSFrederic Weisbecker 1494b0da954aSArnaldo Carvalho de Melo static void __dsos__fprintf(struct list_head *head, FILE *fp) 1495cd84c2acSFrederic Weisbecker { 1496cd84c2acSFrederic Weisbecker struct dso *pos; 1497cd84c2acSFrederic Weisbecker 1498*95011c60SArnaldo Carvalho de Melo list_for_each_entry(pos, head, node) { 1499*95011c60SArnaldo Carvalho de Melo int i; 1500*95011c60SArnaldo Carvalho de Melo for (i = 0; i < MAP__NR_TYPES; ++i) 1501*95011c60SArnaldo Carvalho de Melo dso__fprintf(pos, i, fp); 1502*95011c60SArnaldo Carvalho de Melo } 1503cd84c2acSFrederic Weisbecker } 1504cd84c2acSFrederic Weisbecker 1505b0da954aSArnaldo Carvalho de Melo void dsos__fprintf(FILE *fp) 1506b0da954aSArnaldo Carvalho de Melo { 1507b0da954aSArnaldo Carvalho de Melo __dsos__fprintf(&dsos__kernel, fp); 1508b0da954aSArnaldo Carvalho de Melo __dsos__fprintf(&dsos__user, fp); 1509b0da954aSArnaldo Carvalho de Melo } 1510b0da954aSArnaldo Carvalho de Melo 1511b0da954aSArnaldo Carvalho de Melo static size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp) 15129e03eb2dSArnaldo Carvalho de Melo { 15139e03eb2dSArnaldo Carvalho de Melo struct dso *pos; 15149e03eb2dSArnaldo Carvalho de Melo size_t ret = 0; 15159e03eb2dSArnaldo Carvalho de Melo 1516b0da954aSArnaldo Carvalho de Melo list_for_each_entry(pos, head, node) { 15179e03eb2dSArnaldo Carvalho de Melo ret += dso__fprintf_buildid(pos, fp); 15189e03eb2dSArnaldo Carvalho de Melo ret += fprintf(fp, " %s\n", pos->long_name); 15199e03eb2dSArnaldo Carvalho de Melo } 15209e03eb2dSArnaldo Carvalho de Melo return ret; 15219e03eb2dSArnaldo Carvalho de Melo } 15229e03eb2dSArnaldo Carvalho de Melo 1523b0da954aSArnaldo Carvalho de Melo size_t dsos__fprintf_buildid(FILE *fp) 1524b0da954aSArnaldo Carvalho de Melo { 1525b0da954aSArnaldo Carvalho de Melo return (__dsos__fprintf_buildid(&dsos__kernel, fp) + 1526b0da954aSArnaldo Carvalho de Melo __dsos__fprintf_buildid(&dsos__user, fp)); 1527b0da954aSArnaldo Carvalho de Melo } 1528b0da954aSArnaldo Carvalho de Melo 1529*95011c60SArnaldo Carvalho de Melo static int thread__create_kernel_map(struct thread *self, const char *vmlinux) 1530cd84c2acSFrederic Weisbecker { 15314e06255fSArnaldo Carvalho de Melo struct map *kmap; 1532*95011c60SArnaldo Carvalho de Melo struct dso *kernel = dso__new(vmlinux ?: "[kernel.kallsyms]"); 1533cd84c2acSFrederic Weisbecker 15342446042cSArnaldo Carvalho de Melo if (kernel == NULL) 1535c338aee8SArnaldo Carvalho de Melo return -1; 1536c338aee8SArnaldo Carvalho de Melo 15374e06255fSArnaldo Carvalho de Melo kmap = map__new2(0, kernel, MAP__FUNCTION); 15384e06255fSArnaldo Carvalho de Melo if (kmap == NULL) 1539c338aee8SArnaldo Carvalho de Melo goto out_delete_kernel_dso; 1540c338aee8SArnaldo Carvalho de Melo 15414e06255fSArnaldo Carvalho de Melo kmap->map_ip = kmap->unmap_ip = identity__map_ip; 15422446042cSArnaldo Carvalho de Melo kernel->short_name = "[kernel]"; 1543c338aee8SArnaldo Carvalho de Melo kernel->kernel = 1; 1544cc612d81SArnaldo Carvalho de Melo 154500a192b3SArnaldo Carvalho de Melo vdso = dso__new("[vdso]"); 1546c338aee8SArnaldo Carvalho de Melo if (vdso == NULL) 1547c338aee8SArnaldo Carvalho de Melo goto out_delete_kernel_map; 15483610583cSArnaldo Carvalho de Melo dso__set_loaded(vdso, MAP__FUNCTION); 1549cd84c2acSFrederic Weisbecker 15502446042cSArnaldo Carvalho de Melo if (sysfs__read_build_id("/sys/kernel/notes", kernel->build_id, 15512446042cSArnaldo Carvalho de Melo sizeof(kernel->build_id)) == 0) 15522446042cSArnaldo Carvalho de Melo kernel->has_build_id = true; 15532446042cSArnaldo Carvalho de Melo 1554*95011c60SArnaldo Carvalho de Melo __thread__insert_map(self, kmap); 1555b0da954aSArnaldo Carvalho de Melo dsos__add(&dsos__kernel, kernel); 1556b0da954aSArnaldo Carvalho de Melo dsos__add(&dsos__user, vdso); 1557cd84c2acSFrederic Weisbecker 1558c338aee8SArnaldo Carvalho de Melo return 0; 1559c338aee8SArnaldo Carvalho de Melo 1560c338aee8SArnaldo Carvalho de Melo out_delete_kernel_map: 15614e06255fSArnaldo Carvalho de Melo map__delete(kmap); 1562c338aee8SArnaldo Carvalho de Melo out_delete_kernel_dso: 1563c338aee8SArnaldo Carvalho de Melo dso__delete(kernel); 1564c338aee8SArnaldo Carvalho de Melo return -1; 15652446042cSArnaldo Carvalho de Melo } 15662446042cSArnaldo Carvalho de Melo 1567cc612d81SArnaldo Carvalho de Melo static void vmlinux_path__exit(void) 15682446042cSArnaldo Carvalho de Melo { 1569cc612d81SArnaldo Carvalho de Melo while (--vmlinux_path__nr_entries >= 0) { 1570cc612d81SArnaldo Carvalho de Melo free(vmlinux_path[vmlinux_path__nr_entries]); 1571cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = NULL; 1572cc612d81SArnaldo Carvalho de Melo } 1573cc612d81SArnaldo Carvalho de Melo 1574cc612d81SArnaldo Carvalho de Melo free(vmlinux_path); 1575cc612d81SArnaldo Carvalho de Melo vmlinux_path = NULL; 1576cc612d81SArnaldo Carvalho de Melo } 1577cc612d81SArnaldo Carvalho de Melo 1578cc612d81SArnaldo Carvalho de Melo static int vmlinux_path__init(void) 1579cc612d81SArnaldo Carvalho de Melo { 1580cc612d81SArnaldo Carvalho de Melo struct utsname uts; 1581cc612d81SArnaldo Carvalho de Melo char bf[PATH_MAX]; 1582cc612d81SArnaldo Carvalho de Melo 1583cc612d81SArnaldo Carvalho de Melo if (uname(&uts) < 0) 15842446042cSArnaldo Carvalho de Melo return -1; 15852446042cSArnaldo Carvalho de Melo 1586cc612d81SArnaldo Carvalho de Melo vmlinux_path = malloc(sizeof(char *) * 5); 1587cc612d81SArnaldo Carvalho de Melo if (vmlinux_path == NULL) 1588cc612d81SArnaldo Carvalho de Melo return -1; 1589cc612d81SArnaldo Carvalho de Melo 1590cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup("vmlinux"); 1591cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 1592cc612d81SArnaldo Carvalho de Melo goto out_fail; 1593cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 1594cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup("/boot/vmlinux"); 1595cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 1596cc612d81SArnaldo Carvalho de Melo goto out_fail; 1597cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 1598cc612d81SArnaldo Carvalho de Melo snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", uts.release); 1599cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); 1600cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 1601cc612d81SArnaldo Carvalho de Melo goto out_fail; 1602cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 1603cc612d81SArnaldo Carvalho de Melo snprintf(bf, sizeof(bf), "/lib/modules/%s/build/vmlinux", uts.release); 1604cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); 1605cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 1606cc612d81SArnaldo Carvalho de Melo goto out_fail; 1607cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 1608cc612d81SArnaldo Carvalho de Melo snprintf(bf, sizeof(bf), "/usr/lib/debug/lib/modules/%s/vmlinux", 1609cc612d81SArnaldo Carvalho de Melo uts.release); 1610cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); 1611cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 1612cc612d81SArnaldo Carvalho de Melo goto out_fail; 1613cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 1614cc612d81SArnaldo Carvalho de Melo 1615cc612d81SArnaldo Carvalho de Melo return 0; 1616cc612d81SArnaldo Carvalho de Melo 1617cc612d81SArnaldo Carvalho de Melo out_fail: 1618cc612d81SArnaldo Carvalho de Melo vmlinux_path__exit(); 1619cc612d81SArnaldo Carvalho de Melo return -1; 1620cc612d81SArnaldo Carvalho de Melo } 1621cc612d81SArnaldo Carvalho de Melo 1622*95011c60SArnaldo Carvalho de Melo int symbol__init(struct symbol_conf *conf) 1623cc612d81SArnaldo Carvalho de Melo { 1624b32d133aSArnaldo Carvalho de Melo const struct symbol_conf *pconf = conf ?: &symbol_conf__defaults; 1625b32d133aSArnaldo Carvalho de Melo 1626*95011c60SArnaldo Carvalho de Melo elf_version(EV_CURRENT); 1627b32d133aSArnaldo Carvalho de Melo symbol__priv_size = pconf->priv_size; 1628*95011c60SArnaldo Carvalho de Melo thread__init(kthread, 0); 1629b32d133aSArnaldo Carvalho de Melo 1630b32d133aSArnaldo Carvalho de Melo if (pconf->try_vmlinux_path && vmlinux_path__init() < 0) 1631cc612d81SArnaldo Carvalho de Melo return -1; 1632cc612d81SArnaldo Carvalho de Melo 1633*95011c60SArnaldo Carvalho de Melo if (thread__create_kernel_map(kthread, pconf->vmlinux_name) < 0) { 1634cc612d81SArnaldo Carvalho de Melo vmlinux_path__exit(); 1635cc612d81SArnaldo Carvalho de Melo return -1; 1636cc612d81SArnaldo Carvalho de Melo } 1637cc612d81SArnaldo Carvalho de Melo 1638*95011c60SArnaldo Carvalho de Melo if (pconf->use_modules && thread__create_module_maps(kthread) < 0) 163987f8ea4cSArnaldo Carvalho de Melo pr_debug("Failed to load list of modules in use, " 16406671cb16SArnaldo Carvalho de Melo "continuing...\n"); 164190c83218SArnaldo Carvalho de Melo /* 164290c83218SArnaldo Carvalho de Melo * Now that we have all the maps created, just set the ->end of them: 164390c83218SArnaldo Carvalho de Melo */ 1644*95011c60SArnaldo Carvalho de Melo thread__fixup_maps_end(kthread); 16456671cb16SArnaldo Carvalho de Melo return 0; 1646cd84c2acSFrederic Weisbecker } 1647