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 986470930SIngo Molnar #include <libelf.h> 1086470930SIngo Molnar #include <gelf.h> 1186470930SIngo Molnar #include <elf.h> 12f1617b40SArnaldo Carvalho de Melo #include <limits.h> 13439d473bSArnaldo Carvalho de Melo #include <sys/utsname.h> 142cdbc46dSPeter Zijlstra 15*c12e15e7SArnaldo Carvalho de Melo #ifndef NT_GNU_BUILD_ID 16*c12e15e7SArnaldo Carvalho de Melo #define NT_GNU_BUILD_ID 3 17*c12e15e7SArnaldo Carvalho de Melo #endif 18*c12e15e7SArnaldo Carvalho de Melo 1994cb9e38SArnaldo Carvalho de Melo enum dso_origin { 2094cb9e38SArnaldo Carvalho de Melo DSO__ORIG_KERNEL = 0, 2194cb9e38SArnaldo Carvalho de Melo DSO__ORIG_JAVA_JIT, 2294cb9e38SArnaldo Carvalho de Melo DSO__ORIG_FEDORA, 2394cb9e38SArnaldo Carvalho de Melo DSO__ORIG_UBUNTU, 2494cb9e38SArnaldo Carvalho de Melo DSO__ORIG_BUILDID, 2594cb9e38SArnaldo Carvalho de Melo DSO__ORIG_DSO, 26439d473bSArnaldo Carvalho de Melo DSO__ORIG_KMODULE, 2794cb9e38SArnaldo Carvalho de Melo DSO__ORIG_NOT_FOUND, 2894cb9e38SArnaldo Carvalho de Melo }; 2994cb9e38SArnaldo Carvalho de Melo 30439d473bSArnaldo Carvalho de Melo static void dsos__add(struct dso *dso); 31439d473bSArnaldo Carvalho de Melo static struct dso *dsos__find(const char *name); 322e538c4aSArnaldo Carvalho de Melo static struct map *map__new2(u64 start, struct dso *dso); 332e538c4aSArnaldo Carvalho de Melo static void kernel_maps__insert(struct map *map); 34c338aee8SArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *self, struct map *map, 35c338aee8SArnaldo Carvalho de Melo symbol_filter_t filter); 3600a192b3SArnaldo Carvalho de Melo unsigned int symbol__priv_size; 37439d473bSArnaldo Carvalho de Melo 38af427bf5SArnaldo Carvalho de Melo static struct rb_root kernel_maps; 39af427bf5SArnaldo Carvalho de Melo 402e538c4aSArnaldo Carvalho de Melo static void dso__fixup_sym_end(struct dso *self) 41af427bf5SArnaldo Carvalho de Melo { 42af427bf5SArnaldo Carvalho de Melo struct rb_node *nd, *prevnd = rb_first(&self->syms); 432e538c4aSArnaldo Carvalho de Melo struct symbol *curr, *prev; 44af427bf5SArnaldo Carvalho de Melo 45af427bf5SArnaldo Carvalho de Melo if (prevnd == NULL) 46af427bf5SArnaldo Carvalho de Melo return; 47af427bf5SArnaldo Carvalho de Melo 482e538c4aSArnaldo Carvalho de Melo curr = rb_entry(prevnd, struct symbol, rb_node); 492e538c4aSArnaldo Carvalho de Melo 50af427bf5SArnaldo Carvalho de Melo for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) { 512e538c4aSArnaldo Carvalho de Melo prev = curr; 522e538c4aSArnaldo Carvalho de Melo curr = rb_entry(nd, struct symbol, rb_node); 53af427bf5SArnaldo Carvalho de Melo 54af427bf5SArnaldo Carvalho de Melo if (prev->end == prev->start) 55af427bf5SArnaldo Carvalho de Melo prev->end = curr->start - 1; 56af427bf5SArnaldo Carvalho de Melo } 57af427bf5SArnaldo Carvalho de Melo 582e538c4aSArnaldo Carvalho de Melo /* Last entry */ 592e538c4aSArnaldo Carvalho de Melo if (curr->end == curr->start) 602e538c4aSArnaldo Carvalho de Melo curr->end = roundup(curr->start, 4096); 612e538c4aSArnaldo Carvalho de Melo } 622e538c4aSArnaldo Carvalho de Melo 632e538c4aSArnaldo Carvalho de Melo static void kernel_maps__fixup_end(void) 64af427bf5SArnaldo Carvalho de Melo { 65af427bf5SArnaldo Carvalho de Melo struct map *prev, *curr; 66af427bf5SArnaldo Carvalho de Melo struct rb_node *nd, *prevnd = rb_first(&kernel_maps); 67af427bf5SArnaldo Carvalho de Melo 68af427bf5SArnaldo Carvalho de Melo if (prevnd == NULL) 69af427bf5SArnaldo Carvalho de Melo return; 70af427bf5SArnaldo Carvalho de Melo 71af427bf5SArnaldo Carvalho de Melo curr = rb_entry(prevnd, struct map, rb_node); 72af427bf5SArnaldo Carvalho de Melo 73af427bf5SArnaldo Carvalho de Melo for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) { 74af427bf5SArnaldo Carvalho de Melo prev = curr; 75af427bf5SArnaldo Carvalho de Melo curr = rb_entry(nd, struct map, rb_node); 76af427bf5SArnaldo Carvalho de Melo prev->end = curr->start - 1; 772e538c4aSArnaldo Carvalho de Melo } 7890c83218SArnaldo Carvalho de Melo 7990c83218SArnaldo Carvalho de Melo /* 8090c83218SArnaldo Carvalho de Melo * We still haven't the actual symbols, so guess the 8190c83218SArnaldo Carvalho de Melo * last map final address. 8290c83218SArnaldo Carvalho de Melo */ 8390c83218SArnaldo Carvalho de Melo curr->end = ~0UL; 84af427bf5SArnaldo Carvalho de Melo } 85af427bf5SArnaldo Carvalho de Melo 8600a192b3SArnaldo Carvalho de Melo static struct symbol *symbol__new(u64 start, u64 len, const char *name) 8786470930SIngo Molnar { 8886470930SIngo Molnar size_t namelen = strlen(name) + 1; 8900a192b3SArnaldo Carvalho de Melo struct symbol *self = calloc(1, (symbol__priv_size + 9000a192b3SArnaldo Carvalho de Melo sizeof(*self) + namelen)); 9186470930SIngo Molnar if (!self) 9286470930SIngo Molnar return NULL; 9386470930SIngo Molnar 9400a192b3SArnaldo Carvalho de Melo if (symbol__priv_size) { 9500a192b3SArnaldo Carvalho de Melo memset(self, 0, symbol__priv_size); 9600a192b3SArnaldo Carvalho de Melo self = ((void *)self) + symbol__priv_size; 9786470930SIngo Molnar } 9886470930SIngo Molnar self->start = start; 996cfcc53eSMike Galbraith self->end = len ? start + len - 1 : start; 100e4204992SArnaldo Carvalho de Melo 1016beba7adSArnaldo Carvalho de Melo pr_debug3("%s: %s %#Lx-%#Lx\n", __func__, name, start, self->end); 102e4204992SArnaldo Carvalho de Melo 10386470930SIngo Molnar memcpy(self->name, name, namelen); 10486470930SIngo Molnar 10586470930SIngo Molnar return self; 10686470930SIngo Molnar } 10786470930SIngo Molnar 10800a192b3SArnaldo Carvalho de Melo static void symbol__delete(struct symbol *self) 10986470930SIngo Molnar { 11000a192b3SArnaldo Carvalho de Melo free(((void *)self) - symbol__priv_size); 11186470930SIngo Molnar } 11286470930SIngo Molnar 11386470930SIngo Molnar static size_t symbol__fprintf(struct symbol *self, FILE *fp) 11486470930SIngo Molnar { 11586470930SIngo Molnar return fprintf(fp, " %llx-%llx %s\n", 11686470930SIngo Molnar self->start, self->end, self->name); 11786470930SIngo Molnar } 11886470930SIngo Molnar 119cfc10d3bSArnaldo Carvalho de Melo static void dso__set_long_name(struct dso *self, char *name) 120cfc10d3bSArnaldo Carvalho de Melo { 121ef6ae724SArnaldo Carvalho de Melo if (name == NULL) 122ef6ae724SArnaldo Carvalho de Melo return; 123cfc10d3bSArnaldo Carvalho de Melo self->long_name = name; 124cfc10d3bSArnaldo Carvalho de Melo self->long_name_len = strlen(name); 125cfc10d3bSArnaldo Carvalho de Melo } 126cfc10d3bSArnaldo Carvalho de Melo 127cfc10d3bSArnaldo Carvalho de Melo static void dso__set_basename(struct dso *self) 128cfc10d3bSArnaldo Carvalho de Melo { 129cfc10d3bSArnaldo Carvalho de Melo self->short_name = basename(self->long_name); 130cfc10d3bSArnaldo Carvalho de Melo } 131cfc10d3bSArnaldo Carvalho de Melo 13200a192b3SArnaldo Carvalho de Melo struct dso *dso__new(const char *name) 13386470930SIngo Molnar { 13486470930SIngo Molnar struct dso *self = malloc(sizeof(*self) + strlen(name) + 1); 13586470930SIngo Molnar 13686470930SIngo Molnar if (self != NULL) { 13786470930SIngo Molnar strcpy(self->name, name); 138cfc10d3bSArnaldo Carvalho de Melo dso__set_long_name(self, self->name); 139439d473bSArnaldo Carvalho de Melo self->short_name = self->name; 14086470930SIngo Molnar self->syms = RB_ROOT; 14186470930SIngo Molnar self->find_symbol = dso__find_symbol; 14252d422deSArnaldo Carvalho de Melo self->slen_calculated = 0; 14394cb9e38SArnaldo Carvalho de Melo self->origin = DSO__ORIG_NOT_FOUND; 1448d06367fSArnaldo Carvalho de Melo self->loaded = 0; 1458d06367fSArnaldo Carvalho de Melo self->has_build_id = 0; 14686470930SIngo Molnar } 14786470930SIngo Molnar 14886470930SIngo Molnar return self; 14986470930SIngo Molnar } 15086470930SIngo Molnar 15186470930SIngo Molnar static void dso__delete_symbols(struct dso *self) 15286470930SIngo Molnar { 15386470930SIngo Molnar struct symbol *pos; 15486470930SIngo Molnar struct rb_node *next = rb_first(&self->syms); 15586470930SIngo Molnar 15686470930SIngo Molnar while (next) { 15786470930SIngo Molnar pos = rb_entry(next, struct symbol, rb_node); 15886470930SIngo Molnar next = rb_next(&pos->rb_node); 15986470930SIngo Molnar rb_erase(&pos->rb_node, &self->syms); 16000a192b3SArnaldo Carvalho de Melo symbol__delete(pos); 16186470930SIngo Molnar } 16286470930SIngo Molnar } 16386470930SIngo Molnar 16486470930SIngo Molnar void dso__delete(struct dso *self) 16586470930SIngo Molnar { 16686470930SIngo Molnar dso__delete_symbols(self); 167439d473bSArnaldo Carvalho de Melo if (self->long_name != self->name) 168439d473bSArnaldo Carvalho de Melo free(self->long_name); 16986470930SIngo Molnar free(self); 17086470930SIngo Molnar } 17186470930SIngo Molnar 1728d06367fSArnaldo Carvalho de Melo void dso__set_build_id(struct dso *self, void *build_id) 1738d06367fSArnaldo Carvalho de Melo { 1748d06367fSArnaldo Carvalho de Melo memcpy(self->build_id, build_id, sizeof(self->build_id)); 1758d06367fSArnaldo Carvalho de Melo self->has_build_id = 1; 1768d06367fSArnaldo Carvalho de Melo } 1778d06367fSArnaldo Carvalho de Melo 17886470930SIngo Molnar static void dso__insert_symbol(struct dso *self, struct symbol *sym) 17986470930SIngo Molnar { 18086470930SIngo Molnar struct rb_node **p = &self->syms.rb_node; 18186470930SIngo Molnar struct rb_node *parent = NULL; 1829cffa8d5SPaul Mackerras const u64 ip = sym->start; 18386470930SIngo Molnar struct symbol *s; 18486470930SIngo Molnar 18586470930SIngo Molnar while (*p != NULL) { 18686470930SIngo Molnar parent = *p; 18786470930SIngo Molnar s = rb_entry(parent, struct symbol, rb_node); 18886470930SIngo Molnar if (ip < s->start) 18986470930SIngo Molnar p = &(*p)->rb_left; 19086470930SIngo Molnar else 19186470930SIngo Molnar p = &(*p)->rb_right; 19286470930SIngo Molnar } 19386470930SIngo Molnar rb_link_node(&sym->rb_node, parent, p); 19486470930SIngo Molnar rb_insert_color(&sym->rb_node, &self->syms); 19586470930SIngo Molnar } 19686470930SIngo Molnar 1979cffa8d5SPaul Mackerras struct symbol *dso__find_symbol(struct dso *self, u64 ip) 19886470930SIngo Molnar { 19986470930SIngo Molnar struct rb_node *n; 20086470930SIngo Molnar 20186470930SIngo Molnar if (self == NULL) 20286470930SIngo Molnar return NULL; 20386470930SIngo Molnar 20486470930SIngo Molnar n = self->syms.rb_node; 20586470930SIngo Molnar 20686470930SIngo Molnar while (n) { 20786470930SIngo Molnar struct symbol *s = rb_entry(n, struct symbol, rb_node); 20886470930SIngo Molnar 20986470930SIngo Molnar if (ip < s->start) 21086470930SIngo Molnar n = n->rb_left; 21186470930SIngo Molnar else if (ip > s->end) 21286470930SIngo Molnar n = n->rb_right; 21386470930SIngo Molnar else 21486470930SIngo Molnar return s; 21586470930SIngo Molnar } 21686470930SIngo Molnar 21786470930SIngo Molnar return NULL; 21886470930SIngo Molnar } 21986470930SIngo Molnar 2208d06367fSArnaldo Carvalho de Melo int build_id__sprintf(u8 *self, int len, char *bf) 2218d06367fSArnaldo Carvalho de Melo { 2228d06367fSArnaldo Carvalho de Melo char *bid = bf; 2238d06367fSArnaldo Carvalho de Melo u8 *raw = self; 2248d06367fSArnaldo Carvalho de Melo int i; 2258d06367fSArnaldo Carvalho de Melo 2268d06367fSArnaldo Carvalho de Melo for (i = 0; i < len; ++i) { 2278d06367fSArnaldo Carvalho de Melo sprintf(bid, "%02x", *raw); 2288d06367fSArnaldo Carvalho de Melo ++raw; 2298d06367fSArnaldo Carvalho de Melo bid += 2; 2308d06367fSArnaldo Carvalho de Melo } 2318d06367fSArnaldo Carvalho de Melo 2328d06367fSArnaldo Carvalho de Melo return raw - self; 2338d06367fSArnaldo Carvalho de Melo } 2348d06367fSArnaldo Carvalho de Melo 2359e03eb2dSArnaldo Carvalho de Melo size_t dso__fprintf_buildid(struct dso *self, FILE *fp) 23686470930SIngo Molnar { 2378d06367fSArnaldo Carvalho de Melo char sbuild_id[BUILD_ID_SIZE * 2 + 1]; 2388d06367fSArnaldo Carvalho de Melo 2398d06367fSArnaldo Carvalho de Melo build_id__sprintf(self->build_id, sizeof(self->build_id), sbuild_id); 2409e03eb2dSArnaldo Carvalho de Melo return fprintf(fp, "%s", sbuild_id); 2419e03eb2dSArnaldo Carvalho de Melo } 2429e03eb2dSArnaldo Carvalho de Melo 2439e03eb2dSArnaldo Carvalho de Melo size_t dso__fprintf(struct dso *self, FILE *fp) 2449e03eb2dSArnaldo Carvalho de Melo { 2459e03eb2dSArnaldo Carvalho de Melo struct rb_node *nd; 2469e03eb2dSArnaldo Carvalho de Melo size_t ret = fprintf(fp, "dso: %s (", self->short_name); 2479e03eb2dSArnaldo Carvalho de Melo 2489e03eb2dSArnaldo Carvalho de Melo ret += dso__fprintf_buildid(self, fp); 2499e03eb2dSArnaldo Carvalho de Melo ret += fprintf(fp, ")\n"); 2508d06367fSArnaldo Carvalho de Melo 25186470930SIngo Molnar for (nd = rb_first(&self->syms); nd; nd = rb_next(nd)) { 25286470930SIngo Molnar struct symbol *pos = rb_entry(nd, struct symbol, rb_node); 25386470930SIngo Molnar ret += symbol__fprintf(pos, fp); 25486470930SIngo Molnar } 25586470930SIngo Molnar 25686470930SIngo Molnar return ret; 25786470930SIngo Molnar } 25886470930SIngo Molnar 2592e538c4aSArnaldo Carvalho de Melo /* 2602e538c4aSArnaldo Carvalho de Melo * Loads the function entries in /proc/kallsyms into kernel_map->dso, 2612e538c4aSArnaldo Carvalho de Melo * so that we can in the next step set the symbol ->end address and then 2622e538c4aSArnaldo Carvalho de Melo * call kernel_maps__split_kallsyms. 2632e538c4aSArnaldo Carvalho de Melo */ 2646beba7adSArnaldo Carvalho de Melo static int kernel_maps__load_all_kallsyms(void) 26586470930SIngo Molnar { 26686470930SIngo Molnar char *line = NULL; 26786470930SIngo Molnar size_t n; 26886470930SIngo Molnar FILE *file = fopen("/proc/kallsyms", "r"); 26986470930SIngo Molnar 27086470930SIngo Molnar if (file == NULL) 27186470930SIngo Molnar goto out_failure; 27286470930SIngo Molnar 27386470930SIngo Molnar while (!feof(file)) { 2749cffa8d5SPaul Mackerras u64 start; 27586470930SIngo Molnar struct symbol *sym; 27686470930SIngo Molnar int line_len, len; 27786470930SIngo Molnar char symbol_type; 2782e538c4aSArnaldo Carvalho de Melo char *symbol_name; 27986470930SIngo Molnar 28086470930SIngo Molnar line_len = getline(&line, &n, file); 28186470930SIngo Molnar if (line_len < 0) 28286470930SIngo Molnar break; 28386470930SIngo Molnar 28486470930SIngo Molnar if (!line) 28586470930SIngo Molnar goto out_failure; 28686470930SIngo Molnar 28786470930SIngo Molnar line[--line_len] = '\0'; /* \n */ 28886470930SIngo Molnar 28986470930SIngo Molnar len = hex2u64(line, &start); 29086470930SIngo Molnar 29186470930SIngo Molnar len++; 29286470930SIngo Molnar if (len + 2 >= line_len) 29386470930SIngo Molnar continue; 29486470930SIngo Molnar 29586470930SIngo Molnar symbol_type = toupper(line[len]); 29686470930SIngo Molnar /* 29786470930SIngo Molnar * We're interested only in code ('T'ext) 29886470930SIngo Molnar */ 29986470930SIngo Molnar if (symbol_type != 'T' && symbol_type != 'W') 30086470930SIngo Molnar continue; 301af427bf5SArnaldo Carvalho de Melo 302af427bf5SArnaldo Carvalho de Melo symbol_name = line + len + 2; 3032e538c4aSArnaldo Carvalho de Melo /* 3042e538c4aSArnaldo Carvalho de Melo * Will fix up the end later, when we have all symbols sorted. 3052e538c4aSArnaldo Carvalho de Melo */ 30600a192b3SArnaldo Carvalho de Melo sym = symbol__new(start, 0, symbol_name); 307af427bf5SArnaldo Carvalho de Melo 3082e538c4aSArnaldo Carvalho de Melo if (sym == NULL) 3092e538c4aSArnaldo Carvalho de Melo goto out_delete_line; 3102e538c4aSArnaldo Carvalho de Melo 31182164161SArnaldo Carvalho de Melo /* 31282164161SArnaldo Carvalho de Melo * We will pass the symbols to the filter later, in 31382164161SArnaldo Carvalho de Melo * kernel_maps__split_kallsyms, when we have split the 31482164161SArnaldo Carvalho de Melo * maps per module 31582164161SArnaldo Carvalho de Melo */ 3162e538c4aSArnaldo Carvalho de Melo dso__insert_symbol(kernel_map->dso, sym); 3172e538c4aSArnaldo Carvalho de Melo } 3182e538c4aSArnaldo Carvalho de Melo 3192e538c4aSArnaldo Carvalho de Melo free(line); 3202e538c4aSArnaldo Carvalho de Melo fclose(file); 3212e538c4aSArnaldo Carvalho de Melo 3222e538c4aSArnaldo Carvalho de Melo return 0; 3232e538c4aSArnaldo Carvalho de Melo 3242e538c4aSArnaldo Carvalho de Melo out_delete_line: 3252e538c4aSArnaldo Carvalho de Melo free(line); 3262e538c4aSArnaldo Carvalho de Melo out_failure: 3272e538c4aSArnaldo Carvalho de Melo return -1; 3282e538c4aSArnaldo Carvalho de Melo } 3292e538c4aSArnaldo Carvalho de Melo 3302e538c4aSArnaldo Carvalho de Melo /* 3312e538c4aSArnaldo Carvalho de Melo * Split the symbols into maps, making sure there are no overlaps, i.e. the 3322e538c4aSArnaldo Carvalho de Melo * kernel range is broken in several maps, named [kernel].N, as we don't have 3332e538c4aSArnaldo Carvalho de Melo * the original ELF section names vmlinux have. 3342e538c4aSArnaldo Carvalho de Melo */ 335c338aee8SArnaldo Carvalho de Melo static int kernel_maps__split_kallsyms(symbol_filter_t filter) 3362e538c4aSArnaldo Carvalho de Melo { 3372e538c4aSArnaldo Carvalho de Melo struct map *map = kernel_map; 3382e538c4aSArnaldo Carvalho de Melo struct symbol *pos; 3392e538c4aSArnaldo Carvalho de Melo int count = 0; 3402e538c4aSArnaldo Carvalho de Melo struct rb_node *next = rb_first(&kernel_map->dso->syms); 3412e538c4aSArnaldo Carvalho de Melo int kernel_range = 0; 3422e538c4aSArnaldo Carvalho de Melo 3432e538c4aSArnaldo Carvalho de Melo while (next) { 3442e538c4aSArnaldo Carvalho de Melo char *module; 3452e538c4aSArnaldo Carvalho de Melo 3462e538c4aSArnaldo Carvalho de Melo pos = rb_entry(next, struct symbol, rb_node); 3472e538c4aSArnaldo Carvalho de Melo next = rb_next(&pos->rb_node); 3482e538c4aSArnaldo Carvalho de Melo 3492e538c4aSArnaldo Carvalho de Melo module = strchr(pos->name, '\t'); 3502e538c4aSArnaldo Carvalho de Melo if (module) { 3512e538c4aSArnaldo Carvalho de Melo *module++ = '\0'; 3522e538c4aSArnaldo Carvalho de Melo 353af427bf5SArnaldo Carvalho de Melo if (strcmp(map->dso->name, module)) { 354af427bf5SArnaldo Carvalho de Melo map = kernel_maps__find_by_dso_name(module); 355af427bf5SArnaldo Carvalho de Melo if (!map) { 3566beba7adSArnaldo Carvalho de Melo pr_err("/proc/{kallsyms,modules} " 3576beba7adSArnaldo Carvalho de Melo "inconsistency!\n"); 358af427bf5SArnaldo Carvalho de Melo return -1; 359af427bf5SArnaldo Carvalho de Melo } 360af427bf5SArnaldo Carvalho de Melo } 36186470930SIngo Molnar /* 3622e538c4aSArnaldo Carvalho de Melo * So that we look just like we get from .ko files, 3632e538c4aSArnaldo Carvalho de Melo * i.e. not prelinked, relative to map->start. 36486470930SIngo Molnar */ 3652e538c4aSArnaldo Carvalho de Melo pos->start = map->map_ip(map, pos->start); 3662e538c4aSArnaldo Carvalho de Melo pos->end = map->map_ip(map, pos->end); 3672e538c4aSArnaldo Carvalho de Melo } else if (map != kernel_map) { 3682e538c4aSArnaldo Carvalho de Melo char dso_name[PATH_MAX]; 3692e538c4aSArnaldo Carvalho de Melo struct dso *dso; 37086470930SIngo Molnar 3712e538c4aSArnaldo Carvalho de Melo snprintf(dso_name, sizeof(dso_name), "[kernel].%d", 3722e538c4aSArnaldo Carvalho de Melo kernel_range++); 37386470930SIngo Molnar 37400a192b3SArnaldo Carvalho de Melo dso = dso__new(dso_name); 3752e538c4aSArnaldo Carvalho de Melo if (dso == NULL) 3762e538c4aSArnaldo Carvalho de Melo return -1; 3772e538c4aSArnaldo Carvalho de Melo 3782e538c4aSArnaldo Carvalho de Melo map = map__new2(pos->start, dso); 3792e538c4aSArnaldo Carvalho de Melo if (map == NULL) { 3802e538c4aSArnaldo Carvalho de Melo dso__delete(dso); 3812e538c4aSArnaldo Carvalho de Melo return -1; 3822e538c4aSArnaldo Carvalho de Melo } 3832e538c4aSArnaldo Carvalho de Melo 384ed52ce2eSArnaldo Carvalho de Melo map->map_ip = map->unmap_ip = identity__map_ip; 3852e538c4aSArnaldo Carvalho de Melo kernel_maps__insert(map); 3862e538c4aSArnaldo Carvalho de Melo ++kernel_range; 3872e538c4aSArnaldo Carvalho de Melo } 3882e538c4aSArnaldo Carvalho de Melo 3892e538c4aSArnaldo Carvalho de Melo if (filter && filter(map, pos)) { 3902e538c4aSArnaldo Carvalho de Melo rb_erase(&pos->rb_node, &kernel_map->dso->syms); 39100a192b3SArnaldo Carvalho de Melo symbol__delete(pos); 3922e538c4aSArnaldo Carvalho de Melo } else { 3932e538c4aSArnaldo Carvalho de Melo if (map != kernel_map) { 3942e538c4aSArnaldo Carvalho de Melo rb_erase(&pos->rb_node, &kernel_map->dso->syms); 3952e538c4aSArnaldo Carvalho de Melo dso__insert_symbol(map->dso, pos); 3962e538c4aSArnaldo Carvalho de Melo } 3979974f496SMike Galbraith count++; 3989974f496SMike Galbraith } 39986470930SIngo Molnar } 40086470930SIngo Molnar 4019974f496SMike Galbraith return count; 40286470930SIngo Molnar } 40386470930SIngo Molnar 4042e538c4aSArnaldo Carvalho de Melo 405c338aee8SArnaldo Carvalho de Melo static int kernel_maps__load_kallsyms(symbol_filter_t filter) 4062e538c4aSArnaldo Carvalho de Melo { 4076beba7adSArnaldo Carvalho de Melo if (kernel_maps__load_all_kallsyms()) 4082e538c4aSArnaldo Carvalho de Melo return -1; 4092e538c4aSArnaldo Carvalho de Melo 4102e538c4aSArnaldo Carvalho de Melo dso__fixup_sym_end(kernel_map->dso); 411c338aee8SArnaldo Carvalho de Melo kernel_map->dso->origin = DSO__ORIG_KERNEL; 4122e538c4aSArnaldo Carvalho de Melo 413c338aee8SArnaldo Carvalho de Melo return kernel_maps__split_kallsyms(filter); 4142e538c4aSArnaldo Carvalho de Melo } 4152e538c4aSArnaldo Carvalho de Melo 416c338aee8SArnaldo Carvalho de Melo size_t kernel_maps__fprintf(FILE *fp) 417af427bf5SArnaldo Carvalho de Melo { 4186beba7adSArnaldo Carvalho de Melo size_t printed = fprintf(fp, "Kernel maps:\n"); 419af427bf5SArnaldo Carvalho de Melo struct rb_node *nd; 420af427bf5SArnaldo Carvalho de Melo 421af427bf5SArnaldo Carvalho de Melo for (nd = rb_first(&kernel_maps); nd; nd = rb_next(nd)) { 422af427bf5SArnaldo Carvalho de Melo struct map *pos = rb_entry(nd, struct map, rb_node); 423af427bf5SArnaldo Carvalho de Melo 4242e538c4aSArnaldo Carvalho de Melo printed += fprintf(fp, "Map:"); 425af427bf5SArnaldo Carvalho de Melo printed += map__fprintf(pos, fp); 4266beba7adSArnaldo Carvalho de Melo if (verbose > 1) { 427af427bf5SArnaldo Carvalho de Melo printed += dso__fprintf(pos->dso, fp); 4282e538c4aSArnaldo Carvalho de Melo printed += fprintf(fp, "--\n"); 4292e538c4aSArnaldo Carvalho de Melo } 430af427bf5SArnaldo Carvalho de Melo } 431af427bf5SArnaldo Carvalho de Melo 4326beba7adSArnaldo Carvalho de Melo return printed + fprintf(fp, "END kernel maps\n"); 433af427bf5SArnaldo Carvalho de Melo } 434af427bf5SArnaldo Carvalho de Melo 435439d473bSArnaldo Carvalho de Melo static int dso__load_perf_map(struct dso *self, struct map *map, 4366beba7adSArnaldo Carvalho de Melo symbol_filter_t filter) 43780d496beSPekka Enberg { 43880d496beSPekka Enberg char *line = NULL; 43980d496beSPekka Enberg size_t n; 44080d496beSPekka Enberg FILE *file; 44180d496beSPekka Enberg int nr_syms = 0; 44280d496beSPekka Enberg 443439d473bSArnaldo Carvalho de Melo file = fopen(self->long_name, "r"); 44480d496beSPekka Enberg if (file == NULL) 44580d496beSPekka Enberg goto out_failure; 44680d496beSPekka Enberg 44780d496beSPekka Enberg while (!feof(file)) { 4489cffa8d5SPaul Mackerras u64 start, size; 44980d496beSPekka Enberg struct symbol *sym; 45080d496beSPekka Enberg int line_len, len; 45180d496beSPekka Enberg 45280d496beSPekka Enberg line_len = getline(&line, &n, file); 45380d496beSPekka Enberg if (line_len < 0) 45480d496beSPekka Enberg break; 45580d496beSPekka Enberg 45680d496beSPekka Enberg if (!line) 45780d496beSPekka Enberg goto out_failure; 45880d496beSPekka Enberg 45980d496beSPekka Enberg line[--line_len] = '\0'; /* \n */ 46080d496beSPekka Enberg 46180d496beSPekka Enberg len = hex2u64(line, &start); 46280d496beSPekka Enberg 46380d496beSPekka Enberg len++; 46480d496beSPekka Enberg if (len + 2 >= line_len) 46580d496beSPekka Enberg continue; 46680d496beSPekka Enberg 46780d496beSPekka Enberg len += hex2u64(line + len, &size); 46880d496beSPekka Enberg 46980d496beSPekka Enberg len++; 47080d496beSPekka Enberg if (len + 2 >= line_len) 47180d496beSPekka Enberg continue; 47280d496beSPekka Enberg 47300a192b3SArnaldo Carvalho de Melo sym = symbol__new(start, size, line + len); 47480d496beSPekka Enberg 47580d496beSPekka Enberg if (sym == NULL) 47680d496beSPekka Enberg goto out_delete_line; 47780d496beSPekka Enberg 478439d473bSArnaldo Carvalho de Melo if (filter && filter(map, sym)) 47900a192b3SArnaldo Carvalho de Melo symbol__delete(sym); 48080d496beSPekka Enberg else { 48180d496beSPekka Enberg dso__insert_symbol(self, sym); 48280d496beSPekka Enberg nr_syms++; 48380d496beSPekka Enberg } 48480d496beSPekka Enberg } 48580d496beSPekka Enberg 48680d496beSPekka Enberg free(line); 48780d496beSPekka Enberg fclose(file); 48880d496beSPekka Enberg 48980d496beSPekka Enberg return nr_syms; 49080d496beSPekka Enberg 49180d496beSPekka Enberg out_delete_line: 49280d496beSPekka Enberg free(line); 49380d496beSPekka Enberg out_failure: 49480d496beSPekka Enberg return -1; 49580d496beSPekka Enberg } 49680d496beSPekka Enberg 49786470930SIngo Molnar /** 49886470930SIngo Molnar * elf_symtab__for_each_symbol - iterate thru all the symbols 49986470930SIngo Molnar * 50086470930SIngo Molnar * @self: struct elf_symtab instance to iterate 50183a0944fSIngo Molnar * @idx: uint32_t idx 50286470930SIngo Molnar * @sym: GElf_Sym iterator 50386470930SIngo Molnar */ 50483a0944fSIngo Molnar #define elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) \ 50583a0944fSIngo Molnar for (idx = 0, gelf_getsym(syms, idx, &sym);\ 50683a0944fSIngo Molnar idx < nr_syms; \ 50783a0944fSIngo Molnar idx++, gelf_getsym(syms, idx, &sym)) 50886470930SIngo Molnar 50986470930SIngo Molnar static inline uint8_t elf_sym__type(const GElf_Sym *sym) 51086470930SIngo Molnar { 51186470930SIngo Molnar return GELF_ST_TYPE(sym->st_info); 51286470930SIngo Molnar } 51386470930SIngo Molnar 51486470930SIngo Molnar static inline int elf_sym__is_function(const GElf_Sym *sym) 51586470930SIngo Molnar { 51686470930SIngo Molnar return elf_sym__type(sym) == STT_FUNC && 51786470930SIngo Molnar sym->st_name != 0 && 51881833130SArnaldo Carvalho de Melo sym->st_shndx != SHN_UNDEF; 51986470930SIngo Molnar } 52086470930SIngo Molnar 5216cfcc53eSMike Galbraith static inline int elf_sym__is_label(const GElf_Sym *sym) 5226cfcc53eSMike Galbraith { 5236cfcc53eSMike Galbraith return elf_sym__type(sym) == STT_NOTYPE && 5246cfcc53eSMike Galbraith sym->st_name != 0 && 5256cfcc53eSMike Galbraith sym->st_shndx != SHN_UNDEF && 5266cfcc53eSMike Galbraith sym->st_shndx != SHN_ABS; 5276cfcc53eSMike Galbraith } 5286cfcc53eSMike Galbraith 5296cfcc53eSMike Galbraith static inline const char *elf_sec__name(const GElf_Shdr *shdr, 5306cfcc53eSMike Galbraith const Elf_Data *secstrs) 5316cfcc53eSMike Galbraith { 5326cfcc53eSMike Galbraith return secstrs->d_buf + shdr->sh_name; 5336cfcc53eSMike Galbraith } 5346cfcc53eSMike Galbraith 5356cfcc53eSMike Galbraith static inline int elf_sec__is_text(const GElf_Shdr *shdr, 5366cfcc53eSMike Galbraith const Elf_Data *secstrs) 5376cfcc53eSMike Galbraith { 5386cfcc53eSMike Galbraith return strstr(elf_sec__name(shdr, secstrs), "text") != NULL; 5396cfcc53eSMike Galbraith } 5406cfcc53eSMike Galbraith 54186470930SIngo Molnar static inline const char *elf_sym__name(const GElf_Sym *sym, 54286470930SIngo Molnar const Elf_Data *symstrs) 54386470930SIngo Molnar { 54486470930SIngo Molnar return symstrs->d_buf + sym->st_name; 54586470930SIngo Molnar } 54686470930SIngo Molnar 54786470930SIngo Molnar static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, 54886470930SIngo Molnar GElf_Shdr *shp, const char *name, 54983a0944fSIngo Molnar size_t *idx) 55086470930SIngo Molnar { 55186470930SIngo Molnar Elf_Scn *sec = NULL; 55286470930SIngo Molnar size_t cnt = 1; 55386470930SIngo Molnar 55486470930SIngo Molnar while ((sec = elf_nextscn(elf, sec)) != NULL) { 55586470930SIngo Molnar char *str; 55686470930SIngo Molnar 55786470930SIngo Molnar gelf_getshdr(sec, shp); 55886470930SIngo Molnar str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name); 55986470930SIngo Molnar if (!strcmp(name, str)) { 56083a0944fSIngo Molnar if (idx) 56183a0944fSIngo Molnar *idx = cnt; 56286470930SIngo Molnar break; 56386470930SIngo Molnar } 56486470930SIngo Molnar ++cnt; 56586470930SIngo Molnar } 56686470930SIngo Molnar 56786470930SIngo Molnar return sec; 56886470930SIngo Molnar } 56986470930SIngo Molnar 57086470930SIngo Molnar #define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \ 57186470930SIngo Molnar for (idx = 0, pos = gelf_getrel(reldata, 0, &pos_mem); \ 57286470930SIngo Molnar idx < nr_entries; \ 57386470930SIngo Molnar ++idx, pos = gelf_getrel(reldata, idx, &pos_mem)) 57486470930SIngo Molnar 57586470930SIngo Molnar #define elf_section__for_each_rela(reldata, pos, pos_mem, idx, nr_entries) \ 57686470930SIngo Molnar for (idx = 0, pos = gelf_getrela(reldata, 0, &pos_mem); \ 57786470930SIngo Molnar idx < nr_entries; \ 57886470930SIngo Molnar ++idx, pos = gelf_getrela(reldata, idx, &pos_mem)) 57986470930SIngo Molnar 580a25e46c4SArnaldo Carvalho de Melo /* 581a25e46c4SArnaldo Carvalho de Melo * We need to check if we have a .dynsym, so that we can handle the 582a25e46c4SArnaldo Carvalho de Melo * .plt, synthesizing its symbols, that aren't on the symtabs (be it 583a25e46c4SArnaldo Carvalho de Melo * .dynsym or .symtab). 584a25e46c4SArnaldo Carvalho de Melo * And always look at the original dso, not at debuginfo packages, that 585a25e46c4SArnaldo Carvalho de Melo * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS). 586a25e46c4SArnaldo Carvalho de Melo */ 58782164161SArnaldo Carvalho de Melo static int dso__synthesize_plt_symbols(struct dso *self, struct map *map, 58882164161SArnaldo Carvalho de Melo symbol_filter_t filter) 58986470930SIngo Molnar { 59086470930SIngo Molnar uint32_t nr_rel_entries, idx; 59186470930SIngo Molnar GElf_Sym sym; 5929cffa8d5SPaul Mackerras u64 plt_offset; 59386470930SIngo Molnar GElf_Shdr shdr_plt; 59486470930SIngo Molnar struct symbol *f; 595a25e46c4SArnaldo Carvalho de Melo GElf_Shdr shdr_rel_plt, shdr_dynsym; 59686470930SIngo Molnar Elf_Data *reldata, *syms, *symstrs; 597a25e46c4SArnaldo Carvalho de Melo Elf_Scn *scn_plt_rel, *scn_symstrs, *scn_dynsym; 598a25e46c4SArnaldo Carvalho de Melo size_t dynsym_idx; 599a25e46c4SArnaldo Carvalho de Melo GElf_Ehdr ehdr; 60086470930SIngo Molnar char sympltname[1024]; 601a25e46c4SArnaldo Carvalho de Melo Elf *elf; 602a25e46c4SArnaldo Carvalho de Melo int nr = 0, symidx, fd, err = 0; 60386470930SIngo Molnar 604439d473bSArnaldo Carvalho de Melo fd = open(self->long_name, O_RDONLY); 605a25e46c4SArnaldo Carvalho de Melo if (fd < 0) 606a25e46c4SArnaldo Carvalho de Melo goto out; 607a25e46c4SArnaldo Carvalho de Melo 60884087126SMarti Raudsepp elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 609a25e46c4SArnaldo Carvalho de Melo if (elf == NULL) 610a25e46c4SArnaldo Carvalho de Melo goto out_close; 611a25e46c4SArnaldo Carvalho de Melo 612a25e46c4SArnaldo Carvalho de Melo if (gelf_getehdr(elf, &ehdr) == NULL) 613a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 614a25e46c4SArnaldo Carvalho de Melo 615a25e46c4SArnaldo Carvalho de Melo scn_dynsym = elf_section_by_name(elf, &ehdr, &shdr_dynsym, 616a25e46c4SArnaldo Carvalho de Melo ".dynsym", &dynsym_idx); 617a25e46c4SArnaldo Carvalho de Melo if (scn_dynsym == NULL) 618a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 619a25e46c4SArnaldo Carvalho de Melo 620a25e46c4SArnaldo Carvalho de Melo scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt, 62186470930SIngo Molnar ".rela.plt", NULL); 62286470930SIngo Molnar if (scn_plt_rel == NULL) { 623a25e46c4SArnaldo Carvalho de Melo scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt, 62486470930SIngo Molnar ".rel.plt", NULL); 62586470930SIngo Molnar if (scn_plt_rel == NULL) 626a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 62786470930SIngo Molnar } 62886470930SIngo Molnar 629a25e46c4SArnaldo Carvalho de Melo err = -1; 63086470930SIngo Molnar 631a25e46c4SArnaldo Carvalho de Melo if (shdr_rel_plt.sh_link != dynsym_idx) 632a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 633a25e46c4SArnaldo Carvalho de Melo 634a25e46c4SArnaldo Carvalho de Melo if (elf_section_by_name(elf, &ehdr, &shdr_plt, ".plt", NULL) == NULL) 635a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 63686470930SIngo Molnar 63786470930SIngo Molnar /* 63883a0944fSIngo Molnar * Fetch the relocation section to find the idxes to the GOT 63986470930SIngo Molnar * and the symbols in the .dynsym they refer to. 64086470930SIngo Molnar */ 64186470930SIngo Molnar reldata = elf_getdata(scn_plt_rel, NULL); 64286470930SIngo Molnar if (reldata == NULL) 643a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 64486470930SIngo Molnar 64586470930SIngo Molnar syms = elf_getdata(scn_dynsym, NULL); 64686470930SIngo Molnar if (syms == NULL) 647a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 64886470930SIngo Molnar 649a25e46c4SArnaldo Carvalho de Melo scn_symstrs = elf_getscn(elf, shdr_dynsym.sh_link); 65086470930SIngo Molnar if (scn_symstrs == NULL) 651a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 65286470930SIngo Molnar 65386470930SIngo Molnar symstrs = elf_getdata(scn_symstrs, NULL); 65486470930SIngo Molnar if (symstrs == NULL) 655a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 65686470930SIngo Molnar 65786470930SIngo Molnar nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize; 65886470930SIngo Molnar plt_offset = shdr_plt.sh_offset; 65986470930SIngo Molnar 66086470930SIngo Molnar if (shdr_rel_plt.sh_type == SHT_RELA) { 66186470930SIngo Molnar GElf_Rela pos_mem, *pos; 66286470930SIngo Molnar 66386470930SIngo Molnar elf_section__for_each_rela(reldata, pos, pos_mem, idx, 66486470930SIngo Molnar nr_rel_entries) { 66586470930SIngo Molnar symidx = GELF_R_SYM(pos->r_info); 66686470930SIngo Molnar plt_offset += shdr_plt.sh_entsize; 66786470930SIngo Molnar gelf_getsym(syms, symidx, &sym); 66886470930SIngo Molnar snprintf(sympltname, sizeof(sympltname), 66986470930SIngo Molnar "%s@plt", elf_sym__name(&sym, symstrs)); 67086470930SIngo Molnar 67186470930SIngo Molnar f = symbol__new(plt_offset, shdr_plt.sh_entsize, 67200a192b3SArnaldo Carvalho de Melo sympltname); 67386470930SIngo Molnar if (!f) 674a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 67586470930SIngo Molnar 67682164161SArnaldo Carvalho de Melo if (filter && filter(map, f)) 67782164161SArnaldo Carvalho de Melo symbol__delete(f); 67882164161SArnaldo Carvalho de Melo else { 67986470930SIngo Molnar dso__insert_symbol(self, f); 68086470930SIngo Molnar ++nr; 68186470930SIngo Molnar } 68282164161SArnaldo Carvalho de Melo } 68386470930SIngo Molnar } else if (shdr_rel_plt.sh_type == SHT_REL) { 68486470930SIngo Molnar GElf_Rel pos_mem, *pos; 68586470930SIngo Molnar elf_section__for_each_rel(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 { 70186470930SIngo Molnar dso__insert_symbol(self, f); 70286470930SIngo Molnar ++nr; 70386470930SIngo Molnar } 70486470930SIngo Molnar } 70582164161SArnaldo Carvalho de Melo } 70686470930SIngo Molnar 707a25e46c4SArnaldo Carvalho de Melo err = 0; 708a25e46c4SArnaldo Carvalho de Melo out_elf_end: 709a25e46c4SArnaldo Carvalho de Melo elf_end(elf); 710a25e46c4SArnaldo Carvalho de Melo out_close: 711a25e46c4SArnaldo Carvalho de Melo close(fd); 712a25e46c4SArnaldo Carvalho de Melo 713a25e46c4SArnaldo Carvalho de Melo if (err == 0) 71486470930SIngo Molnar return nr; 715a25e46c4SArnaldo Carvalho de Melo out: 7166beba7adSArnaldo Carvalho de Melo pr_warning("%s: problems reading %s PLT info.\n", 717439d473bSArnaldo Carvalho de Melo __func__, self->long_name); 718a25e46c4SArnaldo Carvalho de Melo return 0; 71986470930SIngo Molnar } 72086470930SIngo Molnar 721439d473bSArnaldo Carvalho de Melo static int dso__load_sym(struct dso *self, struct map *map, const char *name, 722439d473bSArnaldo Carvalho de Melo int fd, symbol_filter_t filter, int kernel, 7236beba7adSArnaldo Carvalho de Melo int kmodule) 72486470930SIngo Molnar { 7252e538c4aSArnaldo Carvalho de Melo struct map *curr_map = map; 7262e538c4aSArnaldo Carvalho de Melo struct dso *curr_dso = self; 7272e538c4aSArnaldo Carvalho de Melo size_t dso_name_len = strlen(self->short_name); 7286cfcc53eSMike Galbraith Elf_Data *symstrs, *secstrs; 72986470930SIngo Molnar uint32_t nr_syms; 73086470930SIngo Molnar int err = -1; 73183a0944fSIngo Molnar uint32_t idx; 73286470930SIngo Molnar GElf_Ehdr ehdr; 73386470930SIngo Molnar GElf_Shdr shdr; 73486470930SIngo Molnar Elf_Data *syms; 73586470930SIngo Molnar GElf_Sym sym; 736a25e46c4SArnaldo Carvalho de Melo Elf_Scn *sec, *sec_strndx; 73786470930SIngo Molnar Elf *elf; 738439d473bSArnaldo Carvalho de Melo int nr = 0; 73986470930SIngo Molnar 74084087126SMarti Raudsepp elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 74186470930SIngo Molnar if (elf == NULL) { 7426beba7adSArnaldo Carvalho de Melo pr_err("%s: cannot read %s ELF file.\n", __func__, name); 74386470930SIngo Molnar goto out_close; 74486470930SIngo Molnar } 74586470930SIngo Molnar 74686470930SIngo Molnar if (gelf_getehdr(elf, &ehdr) == NULL) { 7476beba7adSArnaldo Carvalho de Melo pr_err("%s: cannot get elf header.\n", __func__); 74886470930SIngo Molnar goto out_elf_end; 74986470930SIngo Molnar } 75086470930SIngo Molnar 75186470930SIngo Molnar sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL); 75286470930SIngo Molnar if (sec == NULL) { 753a25e46c4SArnaldo Carvalho de Melo sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL); 754a25e46c4SArnaldo Carvalho de Melo if (sec == NULL) 75586470930SIngo Molnar goto out_elf_end; 75686470930SIngo Molnar } 75786470930SIngo Molnar 75886470930SIngo Molnar syms = elf_getdata(sec, NULL); 75986470930SIngo Molnar if (syms == NULL) 76086470930SIngo Molnar goto out_elf_end; 76186470930SIngo Molnar 76286470930SIngo Molnar sec = elf_getscn(elf, shdr.sh_link); 76386470930SIngo Molnar if (sec == NULL) 76486470930SIngo Molnar goto out_elf_end; 76586470930SIngo Molnar 76686470930SIngo Molnar symstrs = elf_getdata(sec, NULL); 76786470930SIngo Molnar if (symstrs == NULL) 76886470930SIngo Molnar goto out_elf_end; 76986470930SIngo Molnar 7706cfcc53eSMike Galbraith sec_strndx = elf_getscn(elf, ehdr.e_shstrndx); 7716cfcc53eSMike Galbraith if (sec_strndx == NULL) 7726cfcc53eSMike Galbraith goto out_elf_end; 7736cfcc53eSMike Galbraith 7746cfcc53eSMike Galbraith secstrs = elf_getdata(sec_strndx, NULL); 7759b30a26bSStoyan Gaydarov if (secstrs == NULL) 7766cfcc53eSMike Galbraith goto out_elf_end; 7776cfcc53eSMike Galbraith 77886470930SIngo Molnar nr_syms = shdr.sh_size / shdr.sh_entsize; 77986470930SIngo Molnar 780e9fbc9dcSArjan van de Ven memset(&sym, 0, sizeof(sym)); 781d20ff6bdSMike Galbraith if (!kernel) { 78230d7a77dSArnaldo Carvalho de Melo self->adjust_symbols = (ehdr.e_type == ET_EXEC || 78330d7a77dSArnaldo Carvalho de Melo elf_section_by_name(elf, &ehdr, &shdr, 784f5812a7aSArnaldo Carvalho de Melo ".gnu.prelink_undo", 78530d7a77dSArnaldo Carvalho de Melo NULL) != NULL); 786d20ff6bdSMike Galbraith } else self->adjust_symbols = 0; 787d20ff6bdSMike Galbraith 78883a0944fSIngo Molnar elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) { 78986470930SIngo Molnar struct symbol *f; 79083a0944fSIngo Molnar const char *elf_name; 7912e538c4aSArnaldo Carvalho de Melo char *demangled = NULL; 7926cfcc53eSMike Galbraith int is_label = elf_sym__is_label(&sym); 7936cfcc53eSMike Galbraith const char *section_name; 79486470930SIngo Molnar 7956cfcc53eSMike Galbraith if (!is_label && !elf_sym__is_function(&sym)) 79686470930SIngo Molnar continue; 79786470930SIngo Molnar 79886470930SIngo Molnar sec = elf_getscn(elf, sym.st_shndx); 79986470930SIngo Molnar if (!sec) 80086470930SIngo Molnar goto out_elf_end; 80186470930SIngo Molnar 80286470930SIngo Molnar gelf_getshdr(sec, &shdr); 8036cfcc53eSMike Galbraith 8046cfcc53eSMike Galbraith if (is_label && !elf_sec__is_text(&shdr, secstrs)) 8056cfcc53eSMike Galbraith continue; 8066cfcc53eSMike Galbraith 8072e538c4aSArnaldo Carvalho de Melo elf_name = elf_sym__name(&sym, symstrs); 8086cfcc53eSMike Galbraith section_name = elf_sec__name(&shdr, secstrs); 80986470930SIngo Molnar 8102e538c4aSArnaldo Carvalho de Melo if (kernel || kmodule) { 8112e538c4aSArnaldo Carvalho de Melo char dso_name[PATH_MAX]; 8122e538c4aSArnaldo Carvalho de Melo 8132e538c4aSArnaldo Carvalho de Melo if (strcmp(section_name, 8142e538c4aSArnaldo Carvalho de Melo curr_dso->short_name + dso_name_len) == 0) 8152e538c4aSArnaldo Carvalho de Melo goto new_symbol; 8162e538c4aSArnaldo Carvalho de Melo 8172e538c4aSArnaldo Carvalho de Melo if (strcmp(section_name, ".text") == 0) { 8182e538c4aSArnaldo Carvalho de Melo curr_map = map; 8192e538c4aSArnaldo Carvalho de Melo curr_dso = self; 8202e538c4aSArnaldo Carvalho de Melo goto new_symbol; 821af427bf5SArnaldo Carvalho de Melo } 822af427bf5SArnaldo Carvalho de Melo 8232e538c4aSArnaldo Carvalho de Melo snprintf(dso_name, sizeof(dso_name), 8242e538c4aSArnaldo Carvalho de Melo "%s%s", self->short_name, section_name); 8252e538c4aSArnaldo Carvalho de Melo 8262e538c4aSArnaldo Carvalho de Melo curr_map = kernel_maps__find_by_dso_name(dso_name); 8272e538c4aSArnaldo Carvalho de Melo if (curr_map == NULL) { 8282e538c4aSArnaldo Carvalho de Melo u64 start = sym.st_value; 8292e538c4aSArnaldo Carvalho de Melo 8302e538c4aSArnaldo Carvalho de Melo if (kmodule) 8312e538c4aSArnaldo Carvalho de Melo start += map->start + shdr.sh_offset; 8322e538c4aSArnaldo Carvalho de Melo 83300a192b3SArnaldo Carvalho de Melo curr_dso = dso__new(dso_name); 8342e538c4aSArnaldo Carvalho de Melo if (curr_dso == NULL) 8352e538c4aSArnaldo Carvalho de Melo goto out_elf_end; 8362e538c4aSArnaldo Carvalho de Melo curr_map = map__new2(start, curr_dso); 8372e538c4aSArnaldo Carvalho de Melo if (curr_map == NULL) { 8382e538c4aSArnaldo Carvalho de Melo dso__delete(curr_dso); 8392e538c4aSArnaldo Carvalho de Melo goto out_elf_end; 8402e538c4aSArnaldo Carvalho de Melo } 841ed52ce2eSArnaldo Carvalho de Melo curr_map->map_ip = identity__map_ip; 842ed52ce2eSArnaldo Carvalho de Melo curr_map->unmap_ip = identity__map_ip; 8432e538c4aSArnaldo Carvalho de Melo curr_dso->origin = DSO__ORIG_KERNEL; 8442e538c4aSArnaldo Carvalho de Melo kernel_maps__insert(curr_map); 8452e538c4aSArnaldo Carvalho de Melo dsos__add(curr_dso); 8462e538c4aSArnaldo Carvalho de Melo } else 8472e538c4aSArnaldo Carvalho de Melo curr_dso = curr_map->dso; 8482e538c4aSArnaldo Carvalho de Melo 8492e538c4aSArnaldo Carvalho de Melo goto new_symbol; 8502e538c4aSArnaldo Carvalho de Melo } 8512e538c4aSArnaldo Carvalho de Melo 8522e538c4aSArnaldo Carvalho de Melo if (curr_dso->adjust_symbols) { 8536beba7adSArnaldo Carvalho de Melo pr_debug2("adjusting symbol: st_value: %Lx sh_addr: " 8546beba7adSArnaldo Carvalho de Melo "%Lx sh_offset: %Lx\n", (u64)sym.st_value, 8556beba7adSArnaldo Carvalho de Melo (u64)shdr.sh_addr, (u64)shdr.sh_offset); 85686470930SIngo Molnar sym.st_value -= shdr.sh_addr - shdr.sh_offset; 857af427bf5SArnaldo Carvalho de Melo } 85828ac909bSArnaldo Carvalho de Melo /* 85928ac909bSArnaldo Carvalho de Melo * We need to figure out if the object was created from C++ sources 86028ac909bSArnaldo Carvalho de Melo * DWARF DW_compile_unit has this, but we don't always have access 86128ac909bSArnaldo Carvalho de Melo * to it... 86228ac909bSArnaldo Carvalho de Melo */ 86383a0944fSIngo Molnar demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI); 86428ac909bSArnaldo Carvalho de Melo if (demangled != NULL) 86583a0944fSIngo Molnar elf_name = demangled; 8662e538c4aSArnaldo Carvalho de Melo new_symbol: 86700a192b3SArnaldo Carvalho de Melo f = symbol__new(sym.st_value, sym.st_size, elf_name); 86828ac909bSArnaldo Carvalho de Melo free(demangled); 86986470930SIngo Molnar if (!f) 87086470930SIngo Molnar goto out_elf_end; 87186470930SIngo Molnar 8722e538c4aSArnaldo Carvalho de Melo if (filter && filter(curr_map, f)) 87300a192b3SArnaldo Carvalho de Melo symbol__delete(f); 87486470930SIngo Molnar else { 8752e538c4aSArnaldo Carvalho de Melo dso__insert_symbol(curr_dso, f); 87686470930SIngo Molnar nr++; 87786470930SIngo Molnar } 87886470930SIngo Molnar } 87986470930SIngo Molnar 8802e538c4aSArnaldo Carvalho de Melo /* 8812e538c4aSArnaldo Carvalho de Melo * For misannotated, zeroed, ASM function sizes. 8822e538c4aSArnaldo Carvalho de Melo */ 8832e538c4aSArnaldo Carvalho de Melo if (nr > 0) 8842e538c4aSArnaldo Carvalho de Melo dso__fixup_sym_end(self); 88586470930SIngo Molnar err = nr; 88686470930SIngo Molnar out_elf_end: 88786470930SIngo Molnar elf_end(elf); 88886470930SIngo Molnar out_close: 88986470930SIngo Molnar return err; 89086470930SIngo Molnar } 89186470930SIngo Molnar 89278075caaSArnaldo Carvalho de Melo static bool dso__build_id_equal(const struct dso *self, u8 *build_id) 89378075caaSArnaldo Carvalho de Melo { 89478075caaSArnaldo Carvalho de Melo return memcmp(self->build_id, build_id, sizeof(self->build_id)) == 0; 89578075caaSArnaldo Carvalho de Melo } 89678075caaSArnaldo Carvalho de Melo 897e30a3d12SArnaldo Carvalho de Melo bool dsos__read_build_ids(void) 89857f395a7SFrederic Weisbecker { 899e30a3d12SArnaldo Carvalho de Melo bool have_build_id = false; 90057f395a7SFrederic Weisbecker struct dso *pos; 90157f395a7SFrederic Weisbecker 902e30a3d12SArnaldo Carvalho de Melo list_for_each_entry(pos, &dsos, node) 903e30a3d12SArnaldo Carvalho de Melo if (filename__read_build_id(pos->long_name, pos->build_id, 904e30a3d12SArnaldo Carvalho de Melo sizeof(pos->build_id)) > 0) { 905e30a3d12SArnaldo Carvalho de Melo have_build_id = true; 906e30a3d12SArnaldo Carvalho de Melo pos->has_build_id = true; 90757f395a7SFrederic Weisbecker } 90857f395a7SFrederic Weisbecker 909e30a3d12SArnaldo Carvalho de Melo return have_build_id; 91057f395a7SFrederic Weisbecker } 91157f395a7SFrederic Weisbecker 912fd7a346eSArnaldo Carvalho de Melo /* 913fd7a346eSArnaldo Carvalho de Melo * Align offset to 4 bytes as needed for note name and descriptor data. 914fd7a346eSArnaldo Carvalho de Melo */ 915fd7a346eSArnaldo Carvalho de Melo #define NOTE_ALIGN(n) (((n) + 3) & -4U) 916fd7a346eSArnaldo Carvalho de Melo 9172643ce11SArnaldo Carvalho de Melo int filename__read_build_id(const char *filename, void *bf, size_t size) 9184d1e00a8SArnaldo Carvalho de Melo { 9192643ce11SArnaldo Carvalho de Melo int fd, err = -1; 9204d1e00a8SArnaldo Carvalho de Melo GElf_Ehdr ehdr; 9214d1e00a8SArnaldo Carvalho de Melo GElf_Shdr shdr; 922fd7a346eSArnaldo Carvalho de Melo Elf_Data *data; 9234d1e00a8SArnaldo Carvalho de Melo Elf_Scn *sec; 924fd7a346eSArnaldo Carvalho de Melo void *ptr; 9254d1e00a8SArnaldo Carvalho de Melo Elf *elf; 9264d1e00a8SArnaldo Carvalho de Melo 9272643ce11SArnaldo Carvalho de Melo if (size < BUILD_ID_SIZE) 9282643ce11SArnaldo Carvalho de Melo goto out; 9292643ce11SArnaldo Carvalho de Melo 9302643ce11SArnaldo Carvalho de Melo fd = open(filename, O_RDONLY); 9314d1e00a8SArnaldo Carvalho de Melo if (fd < 0) 9324d1e00a8SArnaldo Carvalho de Melo goto out; 9334d1e00a8SArnaldo Carvalho de Melo 93484087126SMarti Raudsepp elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 9354d1e00a8SArnaldo Carvalho de Melo if (elf == NULL) { 9368d06367fSArnaldo Carvalho de Melo pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename); 9374d1e00a8SArnaldo Carvalho de Melo goto out_close; 9384d1e00a8SArnaldo Carvalho de Melo } 9394d1e00a8SArnaldo Carvalho de Melo 9404d1e00a8SArnaldo Carvalho de Melo if (gelf_getehdr(elf, &ehdr) == NULL) { 9416beba7adSArnaldo Carvalho de Melo pr_err("%s: cannot get elf header.\n", __func__); 9424d1e00a8SArnaldo Carvalho de Melo goto out_elf_end; 9434d1e00a8SArnaldo Carvalho de Melo } 9444d1e00a8SArnaldo Carvalho de Melo 9452643ce11SArnaldo Carvalho de Melo sec = elf_section_by_name(elf, &ehdr, &shdr, 9462643ce11SArnaldo Carvalho de Melo ".note.gnu.build-id", NULL); 947fd7a346eSArnaldo Carvalho de Melo if (sec == NULL) { 948fd7a346eSArnaldo Carvalho de Melo sec = elf_section_by_name(elf, &ehdr, &shdr, 949fd7a346eSArnaldo Carvalho de Melo ".notes", NULL); 9504d1e00a8SArnaldo Carvalho de Melo if (sec == NULL) 9514d1e00a8SArnaldo Carvalho de Melo goto out_elf_end; 952fd7a346eSArnaldo Carvalho de Melo } 9534d1e00a8SArnaldo Carvalho de Melo 954fd7a346eSArnaldo Carvalho de Melo data = elf_getdata(sec, NULL); 955fd7a346eSArnaldo Carvalho de Melo if (data == NULL) 9564d1e00a8SArnaldo Carvalho de Melo goto out_elf_end; 957fd7a346eSArnaldo Carvalho de Melo 958fd7a346eSArnaldo Carvalho de Melo ptr = data->d_buf; 959fd7a346eSArnaldo Carvalho de Melo while (ptr < (data->d_buf + data->d_size)) { 960fd7a346eSArnaldo Carvalho de Melo GElf_Nhdr *nhdr = ptr; 961fd7a346eSArnaldo Carvalho de Melo int namesz = NOTE_ALIGN(nhdr->n_namesz), 962fd7a346eSArnaldo Carvalho de Melo descsz = NOTE_ALIGN(nhdr->n_descsz); 963fd7a346eSArnaldo Carvalho de Melo const char *name; 964fd7a346eSArnaldo Carvalho de Melo 965fd7a346eSArnaldo Carvalho de Melo ptr += sizeof(*nhdr); 966fd7a346eSArnaldo Carvalho de Melo name = ptr; 967fd7a346eSArnaldo Carvalho de Melo ptr += namesz; 968fd7a346eSArnaldo Carvalho de Melo if (nhdr->n_type == NT_GNU_BUILD_ID && 969fd7a346eSArnaldo Carvalho de Melo nhdr->n_namesz == sizeof("GNU")) { 970fd7a346eSArnaldo Carvalho de Melo if (memcmp(name, "GNU", sizeof("GNU")) == 0) { 971fd7a346eSArnaldo Carvalho de Melo memcpy(bf, ptr, BUILD_ID_SIZE); 9722643ce11SArnaldo Carvalho de Melo err = BUILD_ID_SIZE; 973fd7a346eSArnaldo Carvalho de Melo break; 974fd7a346eSArnaldo Carvalho de Melo } 975fd7a346eSArnaldo Carvalho de Melo } 976fd7a346eSArnaldo Carvalho de Melo ptr += descsz; 977fd7a346eSArnaldo Carvalho de Melo } 9782643ce11SArnaldo Carvalho de Melo out_elf_end: 9792643ce11SArnaldo Carvalho de Melo elf_end(elf); 9802643ce11SArnaldo Carvalho de Melo out_close: 9812643ce11SArnaldo Carvalho de Melo close(fd); 9822643ce11SArnaldo Carvalho de Melo out: 9832643ce11SArnaldo Carvalho de Melo return err; 9842643ce11SArnaldo Carvalho de Melo } 9852643ce11SArnaldo Carvalho de Melo 986f1617b40SArnaldo Carvalho de Melo int sysfs__read_build_id(const char *filename, void *build_id, size_t size) 987f1617b40SArnaldo Carvalho de Melo { 988f1617b40SArnaldo Carvalho de Melo int fd, err = -1; 989f1617b40SArnaldo Carvalho de Melo 990f1617b40SArnaldo Carvalho de Melo if (size < BUILD_ID_SIZE) 991f1617b40SArnaldo Carvalho de Melo goto out; 992f1617b40SArnaldo Carvalho de Melo 993f1617b40SArnaldo Carvalho de Melo fd = open(filename, O_RDONLY); 994f1617b40SArnaldo Carvalho de Melo if (fd < 0) 995f1617b40SArnaldo Carvalho de Melo goto out; 996f1617b40SArnaldo Carvalho de Melo 997f1617b40SArnaldo Carvalho de Melo while (1) { 998f1617b40SArnaldo Carvalho de Melo char bf[BUFSIZ]; 999f1617b40SArnaldo Carvalho de Melo GElf_Nhdr nhdr; 1000f1617b40SArnaldo Carvalho de Melo int namesz, descsz; 1001f1617b40SArnaldo Carvalho de Melo 1002f1617b40SArnaldo Carvalho de Melo if (read(fd, &nhdr, sizeof(nhdr)) != sizeof(nhdr)) 1003f1617b40SArnaldo Carvalho de Melo break; 1004f1617b40SArnaldo Carvalho de Melo 1005fd7a346eSArnaldo Carvalho de Melo namesz = NOTE_ALIGN(nhdr.n_namesz); 1006fd7a346eSArnaldo Carvalho de Melo descsz = NOTE_ALIGN(nhdr.n_descsz); 1007f1617b40SArnaldo Carvalho de Melo if (nhdr.n_type == NT_GNU_BUILD_ID && 1008f1617b40SArnaldo Carvalho de Melo nhdr.n_namesz == sizeof("GNU")) { 1009f1617b40SArnaldo Carvalho de Melo if (read(fd, bf, namesz) != namesz) 1010f1617b40SArnaldo Carvalho de Melo break; 1011f1617b40SArnaldo Carvalho de Melo if (memcmp(bf, "GNU", sizeof("GNU")) == 0) { 1012f1617b40SArnaldo Carvalho de Melo if (read(fd, build_id, 1013f1617b40SArnaldo Carvalho de Melo BUILD_ID_SIZE) == BUILD_ID_SIZE) { 1014f1617b40SArnaldo Carvalho de Melo err = 0; 1015f1617b40SArnaldo Carvalho de Melo break; 1016f1617b40SArnaldo Carvalho de Melo } 1017f1617b40SArnaldo Carvalho de Melo } else if (read(fd, bf, descsz) != descsz) 1018f1617b40SArnaldo Carvalho de Melo break; 1019f1617b40SArnaldo Carvalho de Melo } else { 1020f1617b40SArnaldo Carvalho de Melo int n = namesz + descsz; 1021f1617b40SArnaldo Carvalho de Melo if (read(fd, bf, n) != n) 1022f1617b40SArnaldo Carvalho de Melo break; 1023f1617b40SArnaldo Carvalho de Melo } 1024f1617b40SArnaldo Carvalho de Melo } 1025f1617b40SArnaldo Carvalho de Melo close(fd); 1026f1617b40SArnaldo Carvalho de Melo out: 1027f1617b40SArnaldo Carvalho de Melo return err; 1028f1617b40SArnaldo Carvalho de Melo } 1029f1617b40SArnaldo Carvalho de Melo 103094cb9e38SArnaldo Carvalho de Melo char dso__symtab_origin(const struct dso *self) 103194cb9e38SArnaldo Carvalho de Melo { 103294cb9e38SArnaldo Carvalho de Melo static const char origin[] = { 103394cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_KERNEL] = 'k', 103494cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_JAVA_JIT] = 'j', 103594cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_FEDORA] = 'f', 103694cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_UBUNTU] = 'u', 103794cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_BUILDID] = 'b', 103894cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_DSO] = 'd', 1039439d473bSArnaldo Carvalho de Melo [DSO__ORIG_KMODULE] = 'K', 104094cb9e38SArnaldo Carvalho de Melo }; 104194cb9e38SArnaldo Carvalho de Melo 104294cb9e38SArnaldo Carvalho de Melo if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND) 104394cb9e38SArnaldo Carvalho de Melo return '!'; 104494cb9e38SArnaldo Carvalho de Melo return origin[self->origin]; 104594cb9e38SArnaldo Carvalho de Melo } 104694cb9e38SArnaldo Carvalho de Melo 10476beba7adSArnaldo Carvalho de Melo int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) 104886470930SIngo Molnar { 10494d1e00a8SArnaldo Carvalho de Melo int size = PATH_MAX; 1050c338aee8SArnaldo Carvalho de Melo char *name; 1051d3379ab9SArnaldo Carvalho de Melo u8 build_id[BUILD_ID_SIZE]; 105286470930SIngo Molnar int ret = -1; 105386470930SIngo Molnar int fd; 105486470930SIngo Molnar 10558d06367fSArnaldo Carvalho de Melo self->loaded = 1; 105666bd8424SArnaldo Carvalho de Melo 1057c338aee8SArnaldo Carvalho de Melo if (self->kernel) 1058c338aee8SArnaldo Carvalho de Melo return dso__load_kernel_sym(self, map, filter); 1059c338aee8SArnaldo Carvalho de Melo 1060c338aee8SArnaldo Carvalho de Melo name = malloc(size); 106186470930SIngo Molnar if (!name) 106286470930SIngo Molnar return -1; 106386470930SIngo Molnar 106430d7a77dSArnaldo Carvalho de Melo self->adjust_symbols = 0; 1065f5812a7aSArnaldo Carvalho de Melo 106694cb9e38SArnaldo Carvalho de Melo if (strncmp(self->name, "/tmp/perf-", 10) == 0) { 10676beba7adSArnaldo Carvalho de Melo ret = dso__load_perf_map(self, map, filter); 106894cb9e38SArnaldo Carvalho de Melo self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT : 106994cb9e38SArnaldo Carvalho de Melo DSO__ORIG_NOT_FOUND; 107094cb9e38SArnaldo Carvalho de Melo return ret; 107194cb9e38SArnaldo Carvalho de Melo } 107294cb9e38SArnaldo Carvalho de Melo 107394cb9e38SArnaldo Carvalho de Melo self->origin = DSO__ORIG_FEDORA - 1; 107480d496beSPekka Enberg 107586470930SIngo Molnar more: 107686470930SIngo Molnar do { 107794cb9e38SArnaldo Carvalho de Melo self->origin++; 107894cb9e38SArnaldo Carvalho de Melo switch (self->origin) { 107994cb9e38SArnaldo Carvalho de Melo case DSO__ORIG_FEDORA: 1080439d473bSArnaldo Carvalho de Melo snprintf(name, size, "/usr/lib/debug%s.debug", 1081439d473bSArnaldo Carvalho de Melo self->long_name); 108286470930SIngo Molnar break; 108394cb9e38SArnaldo Carvalho de Melo case DSO__ORIG_UBUNTU: 1084439d473bSArnaldo Carvalho de Melo snprintf(name, size, "/usr/lib/debug%s", 1085439d473bSArnaldo Carvalho de Melo self->long_name); 108686470930SIngo Molnar break; 108794cb9e38SArnaldo Carvalho de Melo case DSO__ORIG_BUILDID: 1088d3379ab9SArnaldo Carvalho de Melo if (filename__read_build_id(self->long_name, build_id, 1089d3379ab9SArnaldo Carvalho de Melo sizeof(build_id))) { 1090d3379ab9SArnaldo Carvalho de Melo char build_id_hex[BUILD_ID_SIZE * 2 + 1]; 1091d3379ab9SArnaldo Carvalho de Melo 1092d3379ab9SArnaldo Carvalho de Melo build_id__sprintf(build_id, sizeof(build_id), 1093d3379ab9SArnaldo Carvalho de Melo build_id_hex); 10944d1e00a8SArnaldo Carvalho de Melo snprintf(name, size, 10954d1e00a8SArnaldo Carvalho de Melo "/usr/lib/debug/.build-id/%.2s/%s.debug", 1096d3379ab9SArnaldo Carvalho de Melo build_id_hex, build_id_hex + 2); 1097d3379ab9SArnaldo Carvalho de Melo if (self->has_build_id) 10988d06367fSArnaldo Carvalho de Melo goto compare_build_id; 1099d3379ab9SArnaldo Carvalho de Melo break; 11004d1e00a8SArnaldo Carvalho de Melo } 110194cb9e38SArnaldo Carvalho de Melo self->origin++; 11024d1e00a8SArnaldo Carvalho de Melo /* Fall thru */ 110394cb9e38SArnaldo Carvalho de Melo case DSO__ORIG_DSO: 1104439d473bSArnaldo Carvalho de Melo snprintf(name, size, "%s", self->long_name); 110586470930SIngo Molnar break; 110686470930SIngo Molnar 110786470930SIngo Molnar default: 110886470930SIngo Molnar goto out; 110986470930SIngo Molnar } 111086470930SIngo Molnar 11118d06367fSArnaldo Carvalho de Melo if (self->has_build_id) { 1112d3379ab9SArnaldo Carvalho de Melo if (filename__read_build_id(name, build_id, 1113d3379ab9SArnaldo Carvalho de Melo sizeof(build_id)) < 0) 11148d06367fSArnaldo Carvalho de Melo goto more; 11158d06367fSArnaldo Carvalho de Melo compare_build_id: 111678075caaSArnaldo Carvalho de Melo if (!dso__build_id_equal(self, build_id)) 11178d06367fSArnaldo Carvalho de Melo goto more; 11188d06367fSArnaldo Carvalho de Melo } 11198d06367fSArnaldo Carvalho de Melo 112086470930SIngo Molnar fd = open(name, O_RDONLY); 112186470930SIngo Molnar } while (fd < 0); 112286470930SIngo Molnar 11236beba7adSArnaldo Carvalho de Melo ret = dso__load_sym(self, map, name, fd, filter, 0, 0); 112486470930SIngo Molnar close(fd); 112586470930SIngo Molnar 112686470930SIngo Molnar /* 112786470930SIngo Molnar * Some people seem to have debuginfo files _WITHOUT_ debug info!?!? 112886470930SIngo Molnar */ 112986470930SIngo Molnar if (!ret) 113086470930SIngo Molnar goto more; 113186470930SIngo Molnar 1132a25e46c4SArnaldo Carvalho de Melo if (ret > 0) { 113382164161SArnaldo Carvalho de Melo int nr_plt = dso__synthesize_plt_symbols(self, map, filter); 1134a25e46c4SArnaldo Carvalho de Melo if (nr_plt > 0) 1135a25e46c4SArnaldo Carvalho de Melo ret += nr_plt; 1136a25e46c4SArnaldo Carvalho de Melo } 113786470930SIngo Molnar out: 113886470930SIngo Molnar free(name); 11391340e6bbSArnaldo Carvalho de Melo if (ret < 0 && strstr(self->name, " (deleted)") != NULL) 11401340e6bbSArnaldo Carvalho de Melo return 0; 114186470930SIngo Molnar return ret; 114286470930SIngo Molnar } 114386470930SIngo Molnar 1144439d473bSArnaldo Carvalho de Melo struct map *kernel_map; 1145439d473bSArnaldo Carvalho de Melo 1146439d473bSArnaldo Carvalho de Melo static void kernel_maps__insert(struct map *map) 1147439d473bSArnaldo Carvalho de Melo { 1148439d473bSArnaldo Carvalho de Melo maps__insert(&kernel_maps, map); 1149439d473bSArnaldo Carvalho de Melo } 1150439d473bSArnaldo Carvalho de Melo 1151c338aee8SArnaldo Carvalho de Melo struct symbol *kernel_maps__find_symbol(u64 ip, struct map **mapp, 1152c338aee8SArnaldo Carvalho de Melo symbol_filter_t filter) 1153439d473bSArnaldo Carvalho de Melo { 1154439d473bSArnaldo Carvalho de Melo struct map *map = maps__find(&kernel_maps, ip); 1155439d473bSArnaldo Carvalho de Melo 1156439d473bSArnaldo Carvalho de Melo if (mapp) 1157439d473bSArnaldo Carvalho de Melo *mapp = map; 1158439d473bSArnaldo Carvalho de Melo 11592e538c4aSArnaldo Carvalho de Melo if (map) { 11602e538c4aSArnaldo Carvalho de Melo ip = map->map_ip(map, ip); 1161c338aee8SArnaldo Carvalho de Melo return map__find_symbol(map, ip, filter); 11622e538c4aSArnaldo Carvalho de Melo } 11632e538c4aSArnaldo Carvalho de Melo 11642e538c4aSArnaldo Carvalho de Melo return NULL; 1165439d473bSArnaldo Carvalho de Melo } 1166439d473bSArnaldo Carvalho de Melo 1167439d473bSArnaldo Carvalho de Melo struct map *kernel_maps__find_by_dso_name(const char *name) 1168439d473bSArnaldo Carvalho de Melo { 1169439d473bSArnaldo Carvalho de Melo struct rb_node *nd; 1170439d473bSArnaldo Carvalho de Melo 1171439d473bSArnaldo Carvalho de Melo for (nd = rb_first(&kernel_maps); nd; nd = rb_next(nd)) { 1172439d473bSArnaldo Carvalho de Melo struct map *map = rb_entry(nd, struct map, rb_node); 1173439d473bSArnaldo Carvalho de Melo 1174439d473bSArnaldo Carvalho de Melo if (map->dso && strcmp(map->dso->name, name) == 0) 1175439d473bSArnaldo Carvalho de Melo return map; 1176439d473bSArnaldo Carvalho de Melo } 1177439d473bSArnaldo Carvalho de Melo 1178439d473bSArnaldo Carvalho de Melo return NULL; 1179439d473bSArnaldo Carvalho de Melo } 1180439d473bSArnaldo Carvalho de Melo 1181c338aee8SArnaldo Carvalho de Melo static int dsos__set_modules_path_dir(char *dirname) 11826cfcc53eSMike Galbraith { 1183439d473bSArnaldo Carvalho de Melo struct dirent *dent; 1184439d473bSArnaldo Carvalho de Melo DIR *dir = opendir(dirname); 11856cfcc53eSMike Galbraith 1186439d473bSArnaldo Carvalho de Melo if (!dir) { 11876beba7adSArnaldo Carvalho de Melo pr_err("%s: cannot open %s dir\n", __func__, dirname); 1188439d473bSArnaldo Carvalho de Melo return -1; 1189439d473bSArnaldo Carvalho de Melo } 11906cfcc53eSMike Galbraith 1191439d473bSArnaldo Carvalho de Melo while ((dent = readdir(dir)) != NULL) { 1192439d473bSArnaldo Carvalho de Melo char path[PATH_MAX]; 1193439d473bSArnaldo Carvalho de Melo 1194439d473bSArnaldo Carvalho de Melo if (dent->d_type == DT_DIR) { 1195439d473bSArnaldo Carvalho de Melo if (!strcmp(dent->d_name, ".") || 1196439d473bSArnaldo Carvalho de Melo !strcmp(dent->d_name, "..")) 1197439d473bSArnaldo Carvalho de Melo continue; 1198439d473bSArnaldo Carvalho de Melo 1199439d473bSArnaldo Carvalho de Melo snprintf(path, sizeof(path), "%s/%s", 1200439d473bSArnaldo Carvalho de Melo dirname, dent->d_name); 1201c338aee8SArnaldo Carvalho de Melo if (dsos__set_modules_path_dir(path) < 0) 1202439d473bSArnaldo Carvalho de Melo goto failure; 1203439d473bSArnaldo Carvalho de Melo } else { 1204439d473bSArnaldo Carvalho de Melo char *dot = strrchr(dent->d_name, '.'), 1205439d473bSArnaldo Carvalho de Melo dso_name[PATH_MAX]; 1206439d473bSArnaldo Carvalho de Melo struct map *map; 1207cfc10d3bSArnaldo Carvalho de Melo char *long_name; 1208439d473bSArnaldo Carvalho de Melo 1209439d473bSArnaldo Carvalho de Melo if (dot == NULL || strcmp(dot, ".ko")) 1210439d473bSArnaldo Carvalho de Melo continue; 1211439d473bSArnaldo Carvalho de Melo snprintf(dso_name, sizeof(dso_name), "[%.*s]", 1212439d473bSArnaldo Carvalho de Melo (int)(dot - dent->d_name), dent->d_name); 1213439d473bSArnaldo Carvalho de Melo 1214a2a99e8eSArnaldo Carvalho de Melo strxfrchar(dso_name, '-', '_'); 1215439d473bSArnaldo Carvalho de Melo map = kernel_maps__find_by_dso_name(dso_name); 1216439d473bSArnaldo Carvalho de Melo if (map == NULL) 1217439d473bSArnaldo Carvalho de Melo continue; 1218439d473bSArnaldo Carvalho de Melo 1219439d473bSArnaldo Carvalho de Melo snprintf(path, sizeof(path), "%s/%s", 1220439d473bSArnaldo Carvalho de Melo dirname, dent->d_name); 1221439d473bSArnaldo Carvalho de Melo 1222cfc10d3bSArnaldo Carvalho de Melo long_name = strdup(path); 1223cfc10d3bSArnaldo Carvalho de Melo if (long_name == NULL) 1224439d473bSArnaldo Carvalho de Melo goto failure; 1225cfc10d3bSArnaldo Carvalho de Melo dso__set_long_name(map->dso, long_name); 1226439d473bSArnaldo Carvalho de Melo } 1227439d473bSArnaldo Carvalho de Melo } 1228439d473bSArnaldo Carvalho de Melo 1229c338aee8SArnaldo Carvalho de Melo return 0; 1230439d473bSArnaldo Carvalho de Melo failure: 1231439d473bSArnaldo Carvalho de Melo closedir(dir); 1232439d473bSArnaldo Carvalho de Melo return -1; 1233439d473bSArnaldo Carvalho de Melo } 1234439d473bSArnaldo Carvalho de Melo 1235c338aee8SArnaldo Carvalho de Melo static int dsos__set_modules_path(void) 1236439d473bSArnaldo Carvalho de Melo { 1237439d473bSArnaldo Carvalho de Melo struct utsname uts; 1238439d473bSArnaldo Carvalho de Melo char modules_path[PATH_MAX]; 1239439d473bSArnaldo Carvalho de Melo 1240439d473bSArnaldo Carvalho de Melo if (uname(&uts) < 0) 1241439d473bSArnaldo Carvalho de Melo return -1; 1242439d473bSArnaldo Carvalho de Melo 1243439d473bSArnaldo Carvalho de Melo snprintf(modules_path, sizeof(modules_path), "/lib/modules/%s/kernel", 1244439d473bSArnaldo Carvalho de Melo uts.release); 1245439d473bSArnaldo Carvalho de Melo 1246c338aee8SArnaldo Carvalho de Melo return dsos__set_modules_path_dir(modules_path); 1247439d473bSArnaldo Carvalho de Melo } 12486cfcc53eSMike Galbraith 12496cfcc53eSMike Galbraith /* 1250439d473bSArnaldo Carvalho de Melo * Constructor variant for modules (where we know from /proc/modules where 1251439d473bSArnaldo Carvalho de Melo * they are loaded) and for vmlinux, where only after we load all the 1252439d473bSArnaldo Carvalho de Melo * symbols we'll know where it starts and ends. 12536cfcc53eSMike Galbraith */ 1254439d473bSArnaldo Carvalho de Melo static struct map *map__new2(u64 start, struct dso *dso) 1255439d473bSArnaldo Carvalho de Melo { 1256439d473bSArnaldo Carvalho de Melo struct map *self = malloc(sizeof(*self)); 12576cfcc53eSMike Galbraith 1258439d473bSArnaldo Carvalho de Melo if (self != NULL) { 1259439d473bSArnaldo Carvalho de Melo /* 1260afb7b4f0SArnaldo Carvalho de Melo * ->end will be filled after we load all the symbols 1261439d473bSArnaldo Carvalho de Melo */ 1262afb7b4f0SArnaldo Carvalho de Melo map__init(self, start, 0, 0, dso); 1263439d473bSArnaldo Carvalho de Melo } 1264afb7b4f0SArnaldo Carvalho de Melo 1265439d473bSArnaldo Carvalho de Melo return self; 1266439d473bSArnaldo Carvalho de Melo } 1267439d473bSArnaldo Carvalho de Melo 1268c338aee8SArnaldo Carvalho de Melo static int kernel_maps__create_module_maps(void) 1269439d473bSArnaldo Carvalho de Melo { 1270439d473bSArnaldo Carvalho de Melo char *line = NULL; 1271439d473bSArnaldo Carvalho de Melo size_t n; 1272439d473bSArnaldo Carvalho de Melo FILE *file = fopen("/proc/modules", "r"); 1273439d473bSArnaldo Carvalho de Melo struct map *map; 1274439d473bSArnaldo Carvalho de Melo 1275439d473bSArnaldo Carvalho de Melo if (file == NULL) 1276439d473bSArnaldo Carvalho de Melo return -1; 1277439d473bSArnaldo Carvalho de Melo 1278439d473bSArnaldo Carvalho de Melo while (!feof(file)) { 1279439d473bSArnaldo Carvalho de Melo char name[PATH_MAX]; 1280439d473bSArnaldo Carvalho de Melo u64 start; 1281439d473bSArnaldo Carvalho de Melo struct dso *dso; 1282439d473bSArnaldo Carvalho de Melo char *sep; 1283439d473bSArnaldo Carvalho de Melo int line_len; 1284439d473bSArnaldo Carvalho de Melo 1285439d473bSArnaldo Carvalho de Melo line_len = getline(&line, &n, file); 1286439d473bSArnaldo Carvalho de Melo if (line_len < 0) 12876cfcc53eSMike Galbraith break; 12886cfcc53eSMike Galbraith 1289439d473bSArnaldo Carvalho de Melo if (!line) 1290439d473bSArnaldo Carvalho de Melo goto out_failure; 1291439d473bSArnaldo Carvalho de Melo 1292439d473bSArnaldo Carvalho de Melo line[--line_len] = '\0'; /* \n */ 1293439d473bSArnaldo Carvalho de Melo 1294439d473bSArnaldo Carvalho de Melo sep = strrchr(line, 'x'); 1295439d473bSArnaldo Carvalho de Melo if (sep == NULL) 1296439d473bSArnaldo Carvalho de Melo continue; 1297439d473bSArnaldo Carvalho de Melo 1298439d473bSArnaldo Carvalho de Melo hex2u64(sep + 1, &start); 1299439d473bSArnaldo Carvalho de Melo 1300439d473bSArnaldo Carvalho de Melo sep = strchr(line, ' '); 1301439d473bSArnaldo Carvalho de Melo if (sep == NULL) 1302439d473bSArnaldo Carvalho de Melo continue; 1303439d473bSArnaldo Carvalho de Melo 1304439d473bSArnaldo Carvalho de Melo *sep = '\0'; 1305439d473bSArnaldo Carvalho de Melo 1306439d473bSArnaldo Carvalho de Melo snprintf(name, sizeof(name), "[%s]", line); 130700a192b3SArnaldo Carvalho de Melo dso = dso__new(name); 1308439d473bSArnaldo Carvalho de Melo 1309439d473bSArnaldo Carvalho de Melo if (dso == NULL) 1310439d473bSArnaldo Carvalho de Melo goto out_delete_line; 1311439d473bSArnaldo Carvalho de Melo 1312439d473bSArnaldo Carvalho de Melo map = map__new2(start, dso); 1313439d473bSArnaldo Carvalho de Melo if (map == NULL) { 1314439d473bSArnaldo Carvalho de Melo dso__delete(dso); 1315439d473bSArnaldo Carvalho de Melo goto out_delete_line; 13166cfcc53eSMike Galbraith } 13176cfcc53eSMike Galbraith 1318f1617b40SArnaldo Carvalho de Melo snprintf(name, sizeof(name), 1319f1617b40SArnaldo Carvalho de Melo "/sys/module/%s/notes/.note.gnu.build-id", line); 1320f1617b40SArnaldo Carvalho de Melo if (sysfs__read_build_id(name, dso->build_id, 1321f1617b40SArnaldo Carvalho de Melo sizeof(dso->build_id)) == 0) 1322f1617b40SArnaldo Carvalho de Melo dso->has_build_id = true; 1323f1617b40SArnaldo Carvalho de Melo 1324439d473bSArnaldo Carvalho de Melo dso->origin = DSO__ORIG_KMODULE; 1325439d473bSArnaldo Carvalho de Melo kernel_maps__insert(map); 1326439d473bSArnaldo Carvalho de Melo dsos__add(dso); 13276cfcc53eSMike Galbraith } 13286cfcc53eSMike Galbraith 1329439d473bSArnaldo Carvalho de Melo free(line); 1330439d473bSArnaldo Carvalho de Melo fclose(file); 1331439d473bSArnaldo Carvalho de Melo 1332c338aee8SArnaldo Carvalho de Melo return dsos__set_modules_path(); 1333439d473bSArnaldo Carvalho de Melo 1334439d473bSArnaldo Carvalho de Melo out_delete_line: 1335439d473bSArnaldo Carvalho de Melo free(line); 1336439d473bSArnaldo Carvalho de Melo out_failure: 1337439d473bSArnaldo Carvalho de Melo return -1; 13386cfcc53eSMike Galbraith } 13396cfcc53eSMike Galbraith 1340439d473bSArnaldo Carvalho de Melo static int dso__load_vmlinux(struct dso *self, struct map *map, 13416beba7adSArnaldo Carvalho de Melo const char *vmlinux, symbol_filter_t filter) 134286470930SIngo Molnar { 1343fbd733b8SArnaldo Carvalho de Melo int err = -1, fd; 134486470930SIngo Molnar 1345fbd733b8SArnaldo Carvalho de Melo if (self->has_build_id) { 1346fbd733b8SArnaldo Carvalho de Melo u8 build_id[BUILD_ID_SIZE]; 134766bd8424SArnaldo Carvalho de Melo 1348fbd733b8SArnaldo Carvalho de Melo if (filename__read_build_id(vmlinux, build_id, 1349fbd733b8SArnaldo Carvalho de Melo sizeof(build_id)) < 0) { 1350fbd733b8SArnaldo Carvalho de Melo pr_debug("No build_id in %s, ignoring it\n", vmlinux); 1351fbd733b8SArnaldo Carvalho de Melo return -1; 1352fbd733b8SArnaldo Carvalho de Melo } 1353fbd733b8SArnaldo Carvalho de Melo if (!dso__build_id_equal(self, build_id)) { 1354fbd733b8SArnaldo Carvalho de Melo char expected_build_id[BUILD_ID_SIZE * 2 + 1], 1355fbd733b8SArnaldo Carvalho de Melo vmlinux_build_id[BUILD_ID_SIZE * 2 + 1]; 1356fbd733b8SArnaldo Carvalho de Melo 1357fbd733b8SArnaldo Carvalho de Melo build_id__sprintf(self->build_id, 1358fbd733b8SArnaldo Carvalho de Melo sizeof(self->build_id), 1359fbd733b8SArnaldo Carvalho de Melo expected_build_id); 1360fbd733b8SArnaldo Carvalho de Melo build_id__sprintf(build_id, sizeof(build_id), 1361fbd733b8SArnaldo Carvalho de Melo vmlinux_build_id); 1362fbd733b8SArnaldo Carvalho de Melo pr_debug("build_id in %s is %s while expected is %s, " 1363fbd733b8SArnaldo Carvalho de Melo "ignoring it\n", vmlinux, vmlinux_build_id, 1364fbd733b8SArnaldo Carvalho de Melo expected_build_id); 1365fbd733b8SArnaldo Carvalho de Melo return -1; 1366fbd733b8SArnaldo Carvalho de Melo } 1367fbd733b8SArnaldo Carvalho de Melo } 1368fbd733b8SArnaldo Carvalho de Melo 1369fbd733b8SArnaldo Carvalho de Melo fd = open(vmlinux, O_RDONLY); 137086470930SIngo Molnar if (fd < 0) 137186470930SIngo Molnar return -1; 137286470930SIngo Molnar 1373fbd733b8SArnaldo Carvalho de Melo self->loaded = 1; 13746beba7adSArnaldo Carvalho de Melo err = dso__load_sym(self, map, self->long_name, fd, filter, 1, 0); 13756cfcc53eSMike Galbraith 137686470930SIngo Molnar close(fd); 137786470930SIngo Molnar 137886470930SIngo Molnar return err; 137986470930SIngo Molnar } 138086470930SIngo Molnar 1381c338aee8SArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *self, struct map *map, 1382c338aee8SArnaldo Carvalho de Melo symbol_filter_t filter) 138386470930SIngo Molnar { 1384c338aee8SArnaldo Carvalho de Melo int err = dso__load_vmlinux(self, map, self->name, filter); 1385439d473bSArnaldo Carvalho de Melo 1386ef6ae724SArnaldo Carvalho de Melo if (err <= 0) { 1387c338aee8SArnaldo Carvalho de Melo err = kernel_maps__load_kallsyms(filter); 1388ef6ae724SArnaldo Carvalho de Melo if (err > 0) 1389ef6ae724SArnaldo Carvalho de Melo dso__set_long_name(self, strdup("[kernel.kallsyms]")); 1390ef6ae724SArnaldo Carvalho de Melo } 139186470930SIngo Molnar 1392439d473bSArnaldo Carvalho de Melo if (err > 0) { 1393c338aee8SArnaldo Carvalho de Melo map__fixup_start(map); 1394c338aee8SArnaldo Carvalho de Melo map__fixup_end(map); 1395439d473bSArnaldo Carvalho de Melo } 139694cb9e38SArnaldo Carvalho de Melo 139786470930SIngo Molnar return err; 139886470930SIngo Molnar } 139986470930SIngo Molnar 1400cd84c2acSFrederic Weisbecker LIST_HEAD(dsos); 1401cd84c2acSFrederic Weisbecker struct dso *vdso; 1402cd84c2acSFrederic Weisbecker 140383a0944fSIngo Molnar const char *vmlinux_name = "vmlinux"; 1404cd84c2acSFrederic Weisbecker 1405cd84c2acSFrederic Weisbecker static void dsos__add(struct dso *dso) 1406cd84c2acSFrederic Weisbecker { 1407cd84c2acSFrederic Weisbecker list_add_tail(&dso->node, &dsos); 1408cd84c2acSFrederic Weisbecker } 1409cd84c2acSFrederic Weisbecker 1410cd84c2acSFrederic Weisbecker static struct dso *dsos__find(const char *name) 1411cd84c2acSFrederic Weisbecker { 1412cd84c2acSFrederic Weisbecker struct dso *pos; 1413cd84c2acSFrederic Weisbecker 1414cd84c2acSFrederic Weisbecker list_for_each_entry(pos, &dsos, node) 1415cd84c2acSFrederic Weisbecker if (strcmp(pos->name, name) == 0) 1416cd84c2acSFrederic Weisbecker return pos; 1417cd84c2acSFrederic Weisbecker return NULL; 1418cd84c2acSFrederic Weisbecker } 1419cd84c2acSFrederic Weisbecker 142000a192b3SArnaldo Carvalho de Melo struct dso *dsos__findnew(const char *name) 1421cd84c2acSFrederic Weisbecker { 1422cd84c2acSFrederic Weisbecker struct dso *dso = dsos__find(name); 1423cd84c2acSFrederic Weisbecker 1424e4204992SArnaldo Carvalho de Melo if (!dso) { 142500a192b3SArnaldo Carvalho de Melo dso = dso__new(name); 1426cfc10d3bSArnaldo Carvalho de Melo if (dso != NULL) { 1427cd84c2acSFrederic Weisbecker dsos__add(dso); 1428cfc10d3bSArnaldo Carvalho de Melo dso__set_basename(dso); 1429cfc10d3bSArnaldo Carvalho de Melo } 1430e4204992SArnaldo Carvalho de Melo } 1431cd84c2acSFrederic Weisbecker 1432cd84c2acSFrederic Weisbecker return dso; 1433cd84c2acSFrederic Weisbecker } 1434cd84c2acSFrederic Weisbecker 1435cd84c2acSFrederic Weisbecker void dsos__fprintf(FILE *fp) 1436cd84c2acSFrederic Weisbecker { 1437cd84c2acSFrederic Weisbecker struct dso *pos; 1438cd84c2acSFrederic Weisbecker 1439cd84c2acSFrederic Weisbecker list_for_each_entry(pos, &dsos, node) 1440cd84c2acSFrederic Weisbecker dso__fprintf(pos, fp); 1441cd84c2acSFrederic Weisbecker } 1442cd84c2acSFrederic Weisbecker 14439e03eb2dSArnaldo Carvalho de Melo size_t dsos__fprintf_buildid(FILE *fp) 14449e03eb2dSArnaldo Carvalho de Melo { 14459e03eb2dSArnaldo Carvalho de Melo struct dso *pos; 14469e03eb2dSArnaldo Carvalho de Melo size_t ret = 0; 14479e03eb2dSArnaldo Carvalho de Melo 14489e03eb2dSArnaldo Carvalho de Melo list_for_each_entry(pos, &dsos, node) { 14499e03eb2dSArnaldo Carvalho de Melo ret += dso__fprintf_buildid(pos, fp); 14509e03eb2dSArnaldo Carvalho de Melo ret += fprintf(fp, " %s\n", pos->long_name); 14519e03eb2dSArnaldo Carvalho de Melo } 14529e03eb2dSArnaldo Carvalho de Melo return ret; 14539e03eb2dSArnaldo Carvalho de Melo } 14549e03eb2dSArnaldo Carvalho de Melo 1455c338aee8SArnaldo Carvalho de Melo static int kernel_maps__create_kernel_map(void) 1456cd84c2acSFrederic Weisbecker { 14572446042cSArnaldo Carvalho de Melo struct dso *kernel = dso__new(vmlinux_name); 1458cd84c2acSFrederic Weisbecker 14592446042cSArnaldo Carvalho de Melo if (kernel == NULL) 1460c338aee8SArnaldo Carvalho de Melo return -1; 1461c338aee8SArnaldo Carvalho de Melo 1462c338aee8SArnaldo Carvalho de Melo kernel_map = map__new2(0, kernel); 1463c338aee8SArnaldo Carvalho de Melo if (kernel_map == NULL) 1464c338aee8SArnaldo Carvalho de Melo goto out_delete_kernel_dso; 1465c338aee8SArnaldo Carvalho de Melo 1466c338aee8SArnaldo Carvalho de Melo kernel_map->map_ip = kernel_map->unmap_ip = identity__map_ip; 14672446042cSArnaldo Carvalho de Melo 14682446042cSArnaldo Carvalho de Melo kernel->short_name = "[kernel]"; 1469c338aee8SArnaldo Carvalho de Melo kernel->kernel = 1; 147000a192b3SArnaldo Carvalho de Melo vdso = dso__new("[vdso]"); 1471c338aee8SArnaldo Carvalho de Melo if (vdso == NULL) 1472c338aee8SArnaldo Carvalho de Melo goto out_delete_kernel_map; 1473cd84c2acSFrederic Weisbecker 14742446042cSArnaldo Carvalho de Melo if (sysfs__read_build_id("/sys/kernel/notes", kernel->build_id, 14752446042cSArnaldo Carvalho de Melo sizeof(kernel->build_id)) == 0) 14762446042cSArnaldo Carvalho de Melo kernel->has_build_id = true; 14772446042cSArnaldo Carvalho de Melo 1478c338aee8SArnaldo Carvalho de Melo kernel_maps__insert(kernel_map); 14792446042cSArnaldo Carvalho de Melo dsos__add(kernel); 1480cd84c2acSFrederic Weisbecker dsos__add(vdso); 1481cd84c2acSFrederic Weisbecker 1482c338aee8SArnaldo Carvalho de Melo return 0; 1483c338aee8SArnaldo Carvalho de Melo 1484c338aee8SArnaldo Carvalho de Melo out_delete_kernel_map: 1485c338aee8SArnaldo Carvalho de Melo map__delete(kernel_map); 1486c338aee8SArnaldo Carvalho de Melo kernel_map = NULL; 1487c338aee8SArnaldo Carvalho de Melo out_delete_kernel_dso: 1488c338aee8SArnaldo Carvalho de Melo dso__delete(kernel); 1489c338aee8SArnaldo Carvalho de Melo return -1; 14902446042cSArnaldo Carvalho de Melo } 14912446042cSArnaldo Carvalho de Melo 1492c338aee8SArnaldo Carvalho de Melo int kernel_maps__init(bool use_modules) 14932446042cSArnaldo Carvalho de Melo { 1494c338aee8SArnaldo Carvalho de Melo if (kernel_maps__create_kernel_map() < 0) 14952446042cSArnaldo Carvalho de Melo return -1; 14962446042cSArnaldo Carvalho de Melo 1497c338aee8SArnaldo Carvalho de Melo if (use_modules && kernel_maps__create_module_maps() < 0) 14986671cb16SArnaldo Carvalho de Melo pr_warning("Failed to load list of modules in use, " 14996671cb16SArnaldo Carvalho de Melo "continuing...\n"); 150090c83218SArnaldo Carvalho de Melo /* 150190c83218SArnaldo Carvalho de Melo * Now that we have all the maps created, just set the ->end of them: 150290c83218SArnaldo Carvalho de Melo */ 150390c83218SArnaldo Carvalho de Melo kernel_maps__fixup_end(); 15046671cb16SArnaldo Carvalho de Melo return 0; 1505cd84c2acSFrederic Weisbecker } 1506cd84c2acSFrederic Weisbecker 150700a192b3SArnaldo Carvalho de Melo void symbol__init(unsigned int priv_size) 150886470930SIngo Molnar { 150986470930SIngo Molnar elf_version(EV_CURRENT); 151000a192b3SArnaldo Carvalho de Melo symbol__priv_size = priv_size; 151186470930SIngo Molnar } 1512