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 1594cb9e38SArnaldo Carvalho de Melo enum dso_origin { 1694cb9e38SArnaldo Carvalho de Melo DSO__ORIG_KERNEL = 0, 1794cb9e38SArnaldo Carvalho de Melo DSO__ORIG_JAVA_JIT, 1894cb9e38SArnaldo Carvalho de Melo DSO__ORIG_FEDORA, 1994cb9e38SArnaldo Carvalho de Melo DSO__ORIG_UBUNTU, 2094cb9e38SArnaldo Carvalho de Melo DSO__ORIG_BUILDID, 2194cb9e38SArnaldo Carvalho de Melo DSO__ORIG_DSO, 22439d473bSArnaldo Carvalho de Melo DSO__ORIG_KMODULE, 2394cb9e38SArnaldo Carvalho de Melo DSO__ORIG_NOT_FOUND, 2494cb9e38SArnaldo Carvalho de Melo }; 2594cb9e38SArnaldo Carvalho de Melo 26439d473bSArnaldo Carvalho de Melo static void dsos__add(struct dso *dso); 27439d473bSArnaldo Carvalho de Melo static struct dso *dsos__find(const char *name); 282e538c4aSArnaldo Carvalho de Melo static struct map *map__new2(u64 start, struct dso *dso); 292e538c4aSArnaldo Carvalho de Melo static void kernel_maps__insert(struct map *map); 3000a192b3SArnaldo Carvalho de Melo unsigned int symbol__priv_size; 31439d473bSArnaldo Carvalho de Melo 32af427bf5SArnaldo Carvalho de Melo static struct rb_root kernel_maps; 33af427bf5SArnaldo Carvalho de Melo 342e538c4aSArnaldo Carvalho de Melo static void dso__fixup_sym_end(struct dso *self) 35af427bf5SArnaldo Carvalho de Melo { 36af427bf5SArnaldo Carvalho de Melo struct rb_node *nd, *prevnd = rb_first(&self->syms); 372e538c4aSArnaldo Carvalho de Melo struct symbol *curr, *prev; 38af427bf5SArnaldo Carvalho de Melo 39af427bf5SArnaldo Carvalho de Melo if (prevnd == NULL) 40af427bf5SArnaldo Carvalho de Melo return; 41af427bf5SArnaldo Carvalho de Melo 422e538c4aSArnaldo Carvalho de Melo curr = rb_entry(prevnd, struct symbol, rb_node); 432e538c4aSArnaldo Carvalho de Melo 44af427bf5SArnaldo Carvalho de Melo for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) { 452e538c4aSArnaldo Carvalho de Melo prev = curr; 462e538c4aSArnaldo Carvalho de Melo curr = rb_entry(nd, struct symbol, rb_node); 47af427bf5SArnaldo Carvalho de Melo 48af427bf5SArnaldo Carvalho de Melo if (prev->end == prev->start) 49af427bf5SArnaldo Carvalho de Melo prev->end = curr->start - 1; 50af427bf5SArnaldo Carvalho de Melo } 51af427bf5SArnaldo Carvalho de Melo 522e538c4aSArnaldo Carvalho de Melo /* Last entry */ 532e538c4aSArnaldo Carvalho de Melo if (curr->end == curr->start) 542e538c4aSArnaldo Carvalho de Melo curr->end = roundup(curr->start, 4096); 552e538c4aSArnaldo Carvalho de Melo } 562e538c4aSArnaldo Carvalho de Melo 572e538c4aSArnaldo Carvalho de Melo static void kernel_maps__fixup_end(void) 58af427bf5SArnaldo Carvalho de Melo { 59af427bf5SArnaldo Carvalho de Melo struct map *prev, *curr; 60af427bf5SArnaldo Carvalho de Melo struct rb_node *nd, *prevnd = rb_first(&kernel_maps); 61af427bf5SArnaldo Carvalho de Melo 62af427bf5SArnaldo Carvalho de Melo if (prevnd == NULL) 63af427bf5SArnaldo Carvalho de Melo return; 64af427bf5SArnaldo Carvalho de Melo 65af427bf5SArnaldo Carvalho de Melo curr = rb_entry(prevnd, struct map, rb_node); 66af427bf5SArnaldo Carvalho de Melo 67af427bf5SArnaldo Carvalho de Melo for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) { 68af427bf5SArnaldo Carvalho de Melo prev = curr; 69af427bf5SArnaldo Carvalho de Melo curr = rb_entry(nd, struct map, rb_node); 70af427bf5SArnaldo Carvalho de Melo prev->end = curr->start - 1; 712e538c4aSArnaldo Carvalho de Melo } 722e538c4aSArnaldo Carvalho de Melo 732e538c4aSArnaldo Carvalho de Melo nd = rb_last(&curr->dso->syms); 742e538c4aSArnaldo Carvalho de Melo if (nd) { 752e538c4aSArnaldo Carvalho de Melo struct symbol *sym = rb_entry(nd, struct symbol, rb_node); 762e538c4aSArnaldo Carvalho de Melo curr->end = sym->end; 77af427bf5SArnaldo Carvalho de Melo } 78af427bf5SArnaldo Carvalho de Melo } 79af427bf5SArnaldo Carvalho de Melo 8000a192b3SArnaldo Carvalho de Melo static struct symbol *symbol__new(u64 start, u64 len, const char *name) 8186470930SIngo Molnar { 8286470930SIngo Molnar size_t namelen = strlen(name) + 1; 8300a192b3SArnaldo Carvalho de Melo struct symbol *self = calloc(1, (symbol__priv_size + 8400a192b3SArnaldo Carvalho de Melo sizeof(*self) + namelen)); 8586470930SIngo Molnar if (!self) 8686470930SIngo Molnar return NULL; 8786470930SIngo Molnar 8800a192b3SArnaldo Carvalho de Melo if (symbol__priv_size) { 8900a192b3SArnaldo Carvalho de Melo memset(self, 0, symbol__priv_size); 9000a192b3SArnaldo Carvalho de Melo self = ((void *)self) + symbol__priv_size; 9186470930SIngo Molnar } 9286470930SIngo Molnar self->start = start; 936cfcc53eSMike Galbraith self->end = len ? start + len - 1 : start; 94e4204992SArnaldo Carvalho de Melo 956beba7adSArnaldo Carvalho de Melo pr_debug3("%s: %s %#Lx-%#Lx\n", __func__, name, start, self->end); 96e4204992SArnaldo Carvalho de Melo 9786470930SIngo Molnar memcpy(self->name, name, namelen); 9886470930SIngo Molnar 9986470930SIngo Molnar return self; 10086470930SIngo Molnar } 10186470930SIngo Molnar 10200a192b3SArnaldo Carvalho de Melo static void symbol__delete(struct symbol *self) 10386470930SIngo Molnar { 10400a192b3SArnaldo Carvalho de Melo free(((void *)self) - symbol__priv_size); 10586470930SIngo Molnar } 10686470930SIngo Molnar 10786470930SIngo Molnar static size_t symbol__fprintf(struct symbol *self, FILE *fp) 10886470930SIngo Molnar { 10986470930SIngo Molnar return fprintf(fp, " %llx-%llx %s\n", 11086470930SIngo Molnar self->start, self->end, self->name); 11186470930SIngo Molnar } 11286470930SIngo Molnar 113cfc10d3bSArnaldo Carvalho de Melo static void dso__set_long_name(struct dso *self, char *name) 114cfc10d3bSArnaldo Carvalho de Melo { 115cfc10d3bSArnaldo Carvalho de Melo self->long_name = name; 116cfc10d3bSArnaldo Carvalho de Melo self->long_name_len = strlen(name); 117cfc10d3bSArnaldo Carvalho de Melo } 118cfc10d3bSArnaldo Carvalho de Melo 119cfc10d3bSArnaldo Carvalho de Melo static void dso__set_basename(struct dso *self) 120cfc10d3bSArnaldo Carvalho de Melo { 121cfc10d3bSArnaldo Carvalho de Melo self->short_name = basename(self->long_name); 122cfc10d3bSArnaldo Carvalho de Melo } 123cfc10d3bSArnaldo Carvalho de Melo 12400a192b3SArnaldo Carvalho de Melo struct dso *dso__new(const char *name) 12586470930SIngo Molnar { 12686470930SIngo Molnar struct dso *self = malloc(sizeof(*self) + strlen(name) + 1); 12786470930SIngo Molnar 12886470930SIngo Molnar if (self != NULL) { 12986470930SIngo Molnar strcpy(self->name, name); 130cfc10d3bSArnaldo Carvalho de Melo dso__set_long_name(self, self->name); 131439d473bSArnaldo Carvalho de Melo self->short_name = self->name; 13286470930SIngo Molnar self->syms = RB_ROOT; 13386470930SIngo Molnar self->find_symbol = dso__find_symbol; 13452d422deSArnaldo Carvalho de Melo self->slen_calculated = 0; 13594cb9e38SArnaldo Carvalho de Melo self->origin = DSO__ORIG_NOT_FOUND; 1368d06367fSArnaldo Carvalho de Melo self->loaded = 0; 1378d06367fSArnaldo Carvalho de Melo self->has_build_id = 0; 13886470930SIngo Molnar } 13986470930SIngo Molnar 14086470930SIngo Molnar return self; 14186470930SIngo Molnar } 14286470930SIngo Molnar 14386470930SIngo Molnar static void dso__delete_symbols(struct dso *self) 14486470930SIngo Molnar { 14586470930SIngo Molnar struct symbol *pos; 14686470930SIngo Molnar struct rb_node *next = rb_first(&self->syms); 14786470930SIngo Molnar 14886470930SIngo Molnar while (next) { 14986470930SIngo Molnar pos = rb_entry(next, struct symbol, rb_node); 15086470930SIngo Molnar next = rb_next(&pos->rb_node); 15186470930SIngo Molnar rb_erase(&pos->rb_node, &self->syms); 15200a192b3SArnaldo Carvalho de Melo symbol__delete(pos); 15386470930SIngo Molnar } 15486470930SIngo Molnar } 15586470930SIngo Molnar 15686470930SIngo Molnar void dso__delete(struct dso *self) 15786470930SIngo Molnar { 15886470930SIngo Molnar dso__delete_symbols(self); 159439d473bSArnaldo Carvalho de Melo if (self->long_name != self->name) 160439d473bSArnaldo Carvalho de Melo free(self->long_name); 16186470930SIngo Molnar free(self); 16286470930SIngo Molnar } 16386470930SIngo Molnar 1648d06367fSArnaldo Carvalho de Melo void dso__set_build_id(struct dso *self, void *build_id) 1658d06367fSArnaldo Carvalho de Melo { 1668d06367fSArnaldo Carvalho de Melo memcpy(self->build_id, build_id, sizeof(self->build_id)); 1678d06367fSArnaldo Carvalho de Melo self->has_build_id = 1; 1688d06367fSArnaldo Carvalho de Melo } 1698d06367fSArnaldo Carvalho de Melo 17086470930SIngo Molnar static void dso__insert_symbol(struct dso *self, struct symbol *sym) 17186470930SIngo Molnar { 17286470930SIngo Molnar struct rb_node **p = &self->syms.rb_node; 17386470930SIngo Molnar struct rb_node *parent = NULL; 1749cffa8d5SPaul Mackerras const u64 ip = sym->start; 17586470930SIngo Molnar struct symbol *s; 17686470930SIngo Molnar 17786470930SIngo Molnar while (*p != NULL) { 17886470930SIngo Molnar parent = *p; 17986470930SIngo Molnar s = rb_entry(parent, struct symbol, rb_node); 18086470930SIngo Molnar if (ip < s->start) 18186470930SIngo Molnar p = &(*p)->rb_left; 18286470930SIngo Molnar else 18386470930SIngo Molnar p = &(*p)->rb_right; 18486470930SIngo Molnar } 18586470930SIngo Molnar rb_link_node(&sym->rb_node, parent, p); 18686470930SIngo Molnar rb_insert_color(&sym->rb_node, &self->syms); 18786470930SIngo Molnar } 18886470930SIngo Molnar 1899cffa8d5SPaul Mackerras struct symbol *dso__find_symbol(struct dso *self, u64 ip) 19086470930SIngo Molnar { 19186470930SIngo Molnar struct rb_node *n; 19286470930SIngo Molnar 19386470930SIngo Molnar if (self == NULL) 19486470930SIngo Molnar return NULL; 19586470930SIngo Molnar 19686470930SIngo Molnar n = self->syms.rb_node; 19786470930SIngo Molnar 19886470930SIngo Molnar while (n) { 19986470930SIngo Molnar struct symbol *s = rb_entry(n, struct symbol, rb_node); 20086470930SIngo Molnar 20186470930SIngo Molnar if (ip < s->start) 20286470930SIngo Molnar n = n->rb_left; 20386470930SIngo Molnar else if (ip > s->end) 20486470930SIngo Molnar n = n->rb_right; 20586470930SIngo Molnar else 20686470930SIngo Molnar return s; 20786470930SIngo Molnar } 20886470930SIngo Molnar 20986470930SIngo Molnar return NULL; 21086470930SIngo Molnar } 21186470930SIngo Molnar 2128d06367fSArnaldo Carvalho de Melo int build_id__sprintf(u8 *self, int len, char *bf) 2138d06367fSArnaldo Carvalho de Melo { 2148d06367fSArnaldo Carvalho de Melo char *bid = bf; 2158d06367fSArnaldo Carvalho de Melo u8 *raw = self; 2168d06367fSArnaldo Carvalho de Melo int i; 2178d06367fSArnaldo Carvalho de Melo 2188d06367fSArnaldo Carvalho de Melo for (i = 0; i < len; ++i) { 2198d06367fSArnaldo Carvalho de Melo sprintf(bid, "%02x", *raw); 2208d06367fSArnaldo Carvalho de Melo ++raw; 2218d06367fSArnaldo Carvalho de Melo bid += 2; 2228d06367fSArnaldo Carvalho de Melo } 2238d06367fSArnaldo Carvalho de Melo 2248d06367fSArnaldo Carvalho de Melo return raw - self; 2258d06367fSArnaldo Carvalho de Melo } 2268d06367fSArnaldo Carvalho de Melo 2279e03eb2dSArnaldo Carvalho de Melo size_t dso__fprintf_buildid(struct dso *self, FILE *fp) 22886470930SIngo Molnar { 2298d06367fSArnaldo Carvalho de Melo char sbuild_id[BUILD_ID_SIZE * 2 + 1]; 2308d06367fSArnaldo Carvalho de Melo 2318d06367fSArnaldo Carvalho de Melo build_id__sprintf(self->build_id, sizeof(self->build_id), sbuild_id); 2329e03eb2dSArnaldo Carvalho de Melo return fprintf(fp, "%s", sbuild_id); 2339e03eb2dSArnaldo Carvalho de Melo } 2349e03eb2dSArnaldo Carvalho de Melo 2359e03eb2dSArnaldo Carvalho de Melo size_t dso__fprintf(struct dso *self, FILE *fp) 2369e03eb2dSArnaldo Carvalho de Melo { 2379e03eb2dSArnaldo Carvalho de Melo struct rb_node *nd; 2389e03eb2dSArnaldo Carvalho de Melo size_t ret = fprintf(fp, "dso: %s (", self->short_name); 2399e03eb2dSArnaldo Carvalho de Melo 2409e03eb2dSArnaldo Carvalho de Melo ret += dso__fprintf_buildid(self, fp); 2419e03eb2dSArnaldo Carvalho de Melo ret += fprintf(fp, ")\n"); 2428d06367fSArnaldo Carvalho de Melo 24386470930SIngo Molnar for (nd = rb_first(&self->syms); nd; nd = rb_next(nd)) { 24486470930SIngo Molnar struct symbol *pos = rb_entry(nd, struct symbol, rb_node); 24586470930SIngo Molnar ret += symbol__fprintf(pos, fp); 24686470930SIngo Molnar } 24786470930SIngo Molnar 24886470930SIngo Molnar return ret; 24986470930SIngo Molnar } 25086470930SIngo Molnar 2512e538c4aSArnaldo Carvalho de Melo /* 2522e538c4aSArnaldo Carvalho de Melo * Loads the function entries in /proc/kallsyms into kernel_map->dso, 2532e538c4aSArnaldo Carvalho de Melo * so that we can in the next step set the symbol ->end address and then 2542e538c4aSArnaldo Carvalho de Melo * call kernel_maps__split_kallsyms. 2552e538c4aSArnaldo Carvalho de Melo */ 2566beba7adSArnaldo Carvalho de Melo static int kernel_maps__load_all_kallsyms(void) 25786470930SIngo Molnar { 25886470930SIngo Molnar char *line = NULL; 25986470930SIngo Molnar size_t n; 26086470930SIngo Molnar FILE *file = fopen("/proc/kallsyms", "r"); 26186470930SIngo Molnar 26286470930SIngo Molnar if (file == NULL) 26386470930SIngo Molnar goto out_failure; 26486470930SIngo Molnar 26586470930SIngo Molnar while (!feof(file)) { 2669cffa8d5SPaul Mackerras u64 start; 26786470930SIngo Molnar struct symbol *sym; 26886470930SIngo Molnar int line_len, len; 26986470930SIngo Molnar char symbol_type; 2702e538c4aSArnaldo Carvalho de Melo char *symbol_name; 27186470930SIngo Molnar 27286470930SIngo Molnar line_len = getline(&line, &n, file); 27386470930SIngo Molnar if (line_len < 0) 27486470930SIngo Molnar break; 27586470930SIngo Molnar 27686470930SIngo Molnar if (!line) 27786470930SIngo Molnar goto out_failure; 27886470930SIngo Molnar 27986470930SIngo Molnar line[--line_len] = '\0'; /* \n */ 28086470930SIngo Molnar 28186470930SIngo Molnar len = hex2u64(line, &start); 28286470930SIngo Molnar 28386470930SIngo Molnar len++; 28486470930SIngo Molnar if (len + 2 >= line_len) 28586470930SIngo Molnar continue; 28686470930SIngo Molnar 28786470930SIngo Molnar symbol_type = toupper(line[len]); 28886470930SIngo Molnar /* 28986470930SIngo Molnar * We're interested only in code ('T'ext) 29086470930SIngo Molnar */ 29186470930SIngo Molnar if (symbol_type != 'T' && symbol_type != 'W') 29286470930SIngo Molnar continue; 293af427bf5SArnaldo Carvalho de Melo 294af427bf5SArnaldo Carvalho de Melo symbol_name = line + len + 2; 2952e538c4aSArnaldo Carvalho de Melo /* 2962e538c4aSArnaldo Carvalho de Melo * Will fix up the end later, when we have all symbols sorted. 2972e538c4aSArnaldo Carvalho de Melo */ 29800a192b3SArnaldo Carvalho de Melo sym = symbol__new(start, 0, symbol_name); 299af427bf5SArnaldo Carvalho de Melo 3002e538c4aSArnaldo Carvalho de Melo if (sym == NULL) 3012e538c4aSArnaldo Carvalho de Melo goto out_delete_line; 3022e538c4aSArnaldo Carvalho de Melo 30382164161SArnaldo Carvalho de Melo /* 30482164161SArnaldo Carvalho de Melo * We will pass the symbols to the filter later, in 30582164161SArnaldo Carvalho de Melo * kernel_maps__split_kallsyms, when we have split the 30682164161SArnaldo Carvalho de Melo * maps per module 30782164161SArnaldo Carvalho de Melo */ 3082e538c4aSArnaldo Carvalho de Melo dso__insert_symbol(kernel_map->dso, sym); 3092e538c4aSArnaldo Carvalho de Melo } 3102e538c4aSArnaldo Carvalho de Melo 3112e538c4aSArnaldo Carvalho de Melo free(line); 3122e538c4aSArnaldo Carvalho de Melo fclose(file); 3132e538c4aSArnaldo Carvalho de Melo 3142e538c4aSArnaldo Carvalho de Melo return 0; 3152e538c4aSArnaldo Carvalho de Melo 3162e538c4aSArnaldo Carvalho de Melo out_delete_line: 3172e538c4aSArnaldo Carvalho de Melo free(line); 3182e538c4aSArnaldo Carvalho de Melo out_failure: 3192e538c4aSArnaldo Carvalho de Melo return -1; 3202e538c4aSArnaldo Carvalho de Melo } 3212e538c4aSArnaldo Carvalho de Melo 3222e538c4aSArnaldo Carvalho de Melo /* 3232e538c4aSArnaldo Carvalho de Melo * Split the symbols into maps, making sure there are no overlaps, i.e. the 3242e538c4aSArnaldo Carvalho de Melo * kernel range is broken in several maps, named [kernel].N, as we don't have 3252e538c4aSArnaldo Carvalho de Melo * the original ELF section names vmlinux have. 3262e538c4aSArnaldo Carvalho de Melo */ 3272e538c4aSArnaldo Carvalho de Melo static int kernel_maps__split_kallsyms(symbol_filter_t filter, int use_modules) 3282e538c4aSArnaldo Carvalho de Melo { 3292e538c4aSArnaldo Carvalho de Melo struct map *map = kernel_map; 3302e538c4aSArnaldo Carvalho de Melo struct symbol *pos; 3312e538c4aSArnaldo Carvalho de Melo int count = 0; 3322e538c4aSArnaldo Carvalho de Melo struct rb_node *next = rb_first(&kernel_map->dso->syms); 3332e538c4aSArnaldo Carvalho de Melo int kernel_range = 0; 3342e538c4aSArnaldo Carvalho de Melo 3352e538c4aSArnaldo Carvalho de Melo while (next) { 3362e538c4aSArnaldo Carvalho de Melo char *module; 3372e538c4aSArnaldo Carvalho de Melo 3382e538c4aSArnaldo Carvalho de Melo pos = rb_entry(next, struct symbol, rb_node); 3392e538c4aSArnaldo Carvalho de Melo next = rb_next(&pos->rb_node); 3402e538c4aSArnaldo Carvalho de Melo 3412e538c4aSArnaldo Carvalho de Melo module = strchr(pos->name, '\t'); 3422e538c4aSArnaldo Carvalho de Melo if (module) { 343af427bf5SArnaldo Carvalho de Melo if (!use_modules) 3442e538c4aSArnaldo Carvalho de Melo goto delete_symbol; 3452e538c4aSArnaldo Carvalho de Melo 3462e538c4aSArnaldo Carvalho de Melo *module++ = '\0'; 3472e538c4aSArnaldo Carvalho de Melo 348af427bf5SArnaldo Carvalho de Melo if (strcmp(map->dso->name, module)) { 349af427bf5SArnaldo Carvalho de Melo map = kernel_maps__find_by_dso_name(module); 350af427bf5SArnaldo Carvalho de Melo if (!map) { 3516beba7adSArnaldo Carvalho de Melo pr_err("/proc/{kallsyms,modules} " 3526beba7adSArnaldo Carvalho de Melo "inconsistency!\n"); 353af427bf5SArnaldo Carvalho de Melo return -1; 354af427bf5SArnaldo Carvalho de Melo } 355af427bf5SArnaldo Carvalho de Melo } 35686470930SIngo Molnar /* 3572e538c4aSArnaldo Carvalho de Melo * So that we look just like we get from .ko files, 3582e538c4aSArnaldo Carvalho de Melo * i.e. not prelinked, relative to map->start. 35986470930SIngo Molnar */ 3602e538c4aSArnaldo Carvalho de Melo pos->start = map->map_ip(map, pos->start); 3612e538c4aSArnaldo Carvalho de Melo pos->end = map->map_ip(map, pos->end); 3622e538c4aSArnaldo Carvalho de Melo } else if (map != kernel_map) { 3632e538c4aSArnaldo Carvalho de Melo char dso_name[PATH_MAX]; 3642e538c4aSArnaldo Carvalho de Melo struct dso *dso; 36586470930SIngo Molnar 3662e538c4aSArnaldo Carvalho de Melo snprintf(dso_name, sizeof(dso_name), "[kernel].%d", 3672e538c4aSArnaldo Carvalho de Melo kernel_range++); 36886470930SIngo Molnar 36900a192b3SArnaldo Carvalho de Melo dso = dso__new(dso_name); 3702e538c4aSArnaldo Carvalho de Melo if (dso == NULL) 3712e538c4aSArnaldo Carvalho de Melo return -1; 3722e538c4aSArnaldo Carvalho de Melo 3732e538c4aSArnaldo Carvalho de Melo map = map__new2(pos->start, dso); 3742e538c4aSArnaldo Carvalho de Melo if (map == NULL) { 3752e538c4aSArnaldo Carvalho de Melo dso__delete(dso); 3762e538c4aSArnaldo Carvalho de Melo return -1; 3772e538c4aSArnaldo Carvalho de Melo } 3782e538c4aSArnaldo Carvalho de Melo 379ed52ce2eSArnaldo Carvalho de Melo map->map_ip = map->unmap_ip = identity__map_ip; 3802e538c4aSArnaldo Carvalho de Melo kernel_maps__insert(map); 3812e538c4aSArnaldo Carvalho de Melo ++kernel_range; 3822e538c4aSArnaldo Carvalho de Melo } 3832e538c4aSArnaldo Carvalho de Melo 3842e538c4aSArnaldo Carvalho de Melo if (filter && filter(map, pos)) { 3852e538c4aSArnaldo Carvalho de Melo delete_symbol: 3862e538c4aSArnaldo Carvalho de Melo rb_erase(&pos->rb_node, &kernel_map->dso->syms); 38700a192b3SArnaldo Carvalho de Melo symbol__delete(pos); 3882e538c4aSArnaldo Carvalho de Melo } else { 3892e538c4aSArnaldo Carvalho de Melo if (map != kernel_map) { 3902e538c4aSArnaldo Carvalho de Melo rb_erase(&pos->rb_node, &kernel_map->dso->syms); 3912e538c4aSArnaldo Carvalho de Melo dso__insert_symbol(map->dso, pos); 3922e538c4aSArnaldo Carvalho de Melo } 3939974f496SMike Galbraith count++; 3949974f496SMike Galbraith } 39586470930SIngo Molnar } 39686470930SIngo Molnar 3979974f496SMike Galbraith return count; 39886470930SIngo Molnar } 39986470930SIngo Molnar 4002e538c4aSArnaldo Carvalho de Melo 4016beba7adSArnaldo Carvalho de Melo static int kernel_maps__load_kallsyms(symbol_filter_t filter, int use_modules) 4022e538c4aSArnaldo Carvalho de Melo { 4036beba7adSArnaldo Carvalho de Melo if (kernel_maps__load_all_kallsyms()) 4042e538c4aSArnaldo Carvalho de Melo return -1; 4052e538c4aSArnaldo Carvalho de Melo 4062e538c4aSArnaldo Carvalho de Melo dso__fixup_sym_end(kernel_map->dso); 4072e538c4aSArnaldo Carvalho de Melo 4082e538c4aSArnaldo Carvalho de Melo return kernel_maps__split_kallsyms(filter, use_modules); 4092e538c4aSArnaldo Carvalho de Melo } 4102e538c4aSArnaldo Carvalho de Melo 4116beba7adSArnaldo Carvalho de Melo static size_t kernel_maps__fprintf(FILE *fp) 412af427bf5SArnaldo Carvalho de Melo { 4136beba7adSArnaldo Carvalho de Melo size_t printed = fprintf(fp, "Kernel maps:\n"); 414af427bf5SArnaldo Carvalho de Melo struct rb_node *nd; 415af427bf5SArnaldo Carvalho de Melo 416af427bf5SArnaldo Carvalho de Melo for (nd = rb_first(&kernel_maps); nd; nd = rb_next(nd)) { 417af427bf5SArnaldo Carvalho de Melo struct map *pos = rb_entry(nd, struct map, rb_node); 418af427bf5SArnaldo Carvalho de Melo 4192e538c4aSArnaldo Carvalho de Melo printed += fprintf(fp, "Map:"); 420af427bf5SArnaldo Carvalho de Melo printed += map__fprintf(pos, fp); 4216beba7adSArnaldo Carvalho de Melo if (verbose > 1) { 422af427bf5SArnaldo Carvalho de Melo printed += dso__fprintf(pos->dso, fp); 4232e538c4aSArnaldo Carvalho de Melo printed += fprintf(fp, "--\n"); 4242e538c4aSArnaldo Carvalho de Melo } 425af427bf5SArnaldo Carvalho de Melo } 426af427bf5SArnaldo Carvalho de Melo 4276beba7adSArnaldo Carvalho de Melo return printed + fprintf(fp, "END kernel maps\n"); 428af427bf5SArnaldo Carvalho de Melo } 429af427bf5SArnaldo Carvalho de Melo 430439d473bSArnaldo Carvalho de Melo static int dso__load_perf_map(struct dso *self, struct map *map, 4316beba7adSArnaldo Carvalho de Melo symbol_filter_t filter) 43280d496beSPekka Enberg { 43380d496beSPekka Enberg char *line = NULL; 43480d496beSPekka Enberg size_t n; 43580d496beSPekka Enberg FILE *file; 43680d496beSPekka Enberg int nr_syms = 0; 43780d496beSPekka Enberg 438439d473bSArnaldo Carvalho de Melo file = fopen(self->long_name, "r"); 43980d496beSPekka Enberg if (file == NULL) 44080d496beSPekka Enberg goto out_failure; 44180d496beSPekka Enberg 44280d496beSPekka Enberg while (!feof(file)) { 4439cffa8d5SPaul Mackerras u64 start, size; 44480d496beSPekka Enberg struct symbol *sym; 44580d496beSPekka Enberg int line_len, len; 44680d496beSPekka Enberg 44780d496beSPekka Enberg line_len = getline(&line, &n, file); 44880d496beSPekka Enberg if (line_len < 0) 44980d496beSPekka Enberg break; 45080d496beSPekka Enberg 45180d496beSPekka Enberg if (!line) 45280d496beSPekka Enberg goto out_failure; 45380d496beSPekka Enberg 45480d496beSPekka Enberg line[--line_len] = '\0'; /* \n */ 45580d496beSPekka Enberg 45680d496beSPekka Enberg len = hex2u64(line, &start); 45780d496beSPekka Enberg 45880d496beSPekka Enberg len++; 45980d496beSPekka Enberg if (len + 2 >= line_len) 46080d496beSPekka Enberg continue; 46180d496beSPekka Enberg 46280d496beSPekka Enberg len += hex2u64(line + len, &size); 46380d496beSPekka Enberg 46480d496beSPekka Enberg len++; 46580d496beSPekka Enberg if (len + 2 >= line_len) 46680d496beSPekka Enberg continue; 46780d496beSPekka Enberg 46800a192b3SArnaldo Carvalho de Melo sym = symbol__new(start, size, line + len); 46980d496beSPekka Enberg 47080d496beSPekka Enberg if (sym == NULL) 47180d496beSPekka Enberg goto out_delete_line; 47280d496beSPekka Enberg 473439d473bSArnaldo Carvalho de Melo if (filter && filter(map, sym)) 47400a192b3SArnaldo Carvalho de Melo symbol__delete(sym); 47580d496beSPekka Enberg else { 47680d496beSPekka Enberg dso__insert_symbol(self, sym); 47780d496beSPekka Enberg nr_syms++; 47880d496beSPekka Enberg } 47980d496beSPekka Enberg } 48080d496beSPekka Enberg 48180d496beSPekka Enberg free(line); 48280d496beSPekka Enberg fclose(file); 48380d496beSPekka Enberg 48480d496beSPekka Enberg return nr_syms; 48580d496beSPekka Enberg 48680d496beSPekka Enberg out_delete_line: 48780d496beSPekka Enberg free(line); 48880d496beSPekka Enberg out_failure: 48980d496beSPekka Enberg return -1; 49080d496beSPekka Enberg } 49180d496beSPekka Enberg 49286470930SIngo Molnar /** 49386470930SIngo Molnar * elf_symtab__for_each_symbol - iterate thru all the symbols 49486470930SIngo Molnar * 49586470930SIngo Molnar * @self: struct elf_symtab instance to iterate 49683a0944fSIngo Molnar * @idx: uint32_t idx 49786470930SIngo Molnar * @sym: GElf_Sym iterator 49886470930SIngo Molnar */ 49983a0944fSIngo Molnar #define elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) \ 50083a0944fSIngo Molnar for (idx = 0, gelf_getsym(syms, idx, &sym);\ 50183a0944fSIngo Molnar idx < nr_syms; \ 50283a0944fSIngo Molnar idx++, gelf_getsym(syms, idx, &sym)) 50386470930SIngo Molnar 50486470930SIngo Molnar static inline uint8_t elf_sym__type(const GElf_Sym *sym) 50586470930SIngo Molnar { 50686470930SIngo Molnar return GELF_ST_TYPE(sym->st_info); 50786470930SIngo Molnar } 50886470930SIngo Molnar 50986470930SIngo Molnar static inline int elf_sym__is_function(const GElf_Sym *sym) 51086470930SIngo Molnar { 51186470930SIngo Molnar return elf_sym__type(sym) == STT_FUNC && 51286470930SIngo Molnar sym->st_name != 0 && 51381833130SArnaldo Carvalho de Melo sym->st_shndx != SHN_UNDEF; 51486470930SIngo Molnar } 51586470930SIngo Molnar 5166cfcc53eSMike Galbraith static inline int elf_sym__is_label(const GElf_Sym *sym) 5176cfcc53eSMike Galbraith { 5186cfcc53eSMike Galbraith return elf_sym__type(sym) == STT_NOTYPE && 5196cfcc53eSMike Galbraith sym->st_name != 0 && 5206cfcc53eSMike Galbraith sym->st_shndx != SHN_UNDEF && 5216cfcc53eSMike Galbraith sym->st_shndx != SHN_ABS; 5226cfcc53eSMike Galbraith } 5236cfcc53eSMike Galbraith 5246cfcc53eSMike Galbraith static inline const char *elf_sec__name(const GElf_Shdr *shdr, 5256cfcc53eSMike Galbraith const Elf_Data *secstrs) 5266cfcc53eSMike Galbraith { 5276cfcc53eSMike Galbraith return secstrs->d_buf + shdr->sh_name; 5286cfcc53eSMike Galbraith } 5296cfcc53eSMike Galbraith 5306cfcc53eSMike Galbraith static inline int elf_sec__is_text(const GElf_Shdr *shdr, 5316cfcc53eSMike Galbraith const Elf_Data *secstrs) 5326cfcc53eSMike Galbraith { 5336cfcc53eSMike Galbraith return strstr(elf_sec__name(shdr, secstrs), "text") != NULL; 5346cfcc53eSMike Galbraith } 5356cfcc53eSMike Galbraith 53686470930SIngo Molnar static inline const char *elf_sym__name(const GElf_Sym *sym, 53786470930SIngo Molnar const Elf_Data *symstrs) 53886470930SIngo Molnar { 53986470930SIngo Molnar return symstrs->d_buf + sym->st_name; 54086470930SIngo Molnar } 54186470930SIngo Molnar 54286470930SIngo Molnar static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, 54386470930SIngo Molnar GElf_Shdr *shp, const char *name, 54483a0944fSIngo Molnar size_t *idx) 54586470930SIngo Molnar { 54686470930SIngo Molnar Elf_Scn *sec = NULL; 54786470930SIngo Molnar size_t cnt = 1; 54886470930SIngo Molnar 54986470930SIngo Molnar while ((sec = elf_nextscn(elf, sec)) != NULL) { 55086470930SIngo Molnar char *str; 55186470930SIngo Molnar 55286470930SIngo Molnar gelf_getshdr(sec, shp); 55386470930SIngo Molnar str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name); 55486470930SIngo Molnar if (!strcmp(name, str)) { 55583a0944fSIngo Molnar if (idx) 55683a0944fSIngo Molnar *idx = cnt; 55786470930SIngo Molnar break; 55886470930SIngo Molnar } 55986470930SIngo Molnar ++cnt; 56086470930SIngo Molnar } 56186470930SIngo Molnar 56286470930SIngo Molnar return sec; 56386470930SIngo Molnar } 56486470930SIngo Molnar 56586470930SIngo Molnar #define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \ 56686470930SIngo Molnar for (idx = 0, pos = gelf_getrel(reldata, 0, &pos_mem); \ 56786470930SIngo Molnar idx < nr_entries; \ 56886470930SIngo Molnar ++idx, pos = gelf_getrel(reldata, idx, &pos_mem)) 56986470930SIngo Molnar 57086470930SIngo Molnar #define elf_section__for_each_rela(reldata, pos, pos_mem, idx, nr_entries) \ 57186470930SIngo Molnar for (idx = 0, pos = gelf_getrela(reldata, 0, &pos_mem); \ 57286470930SIngo Molnar idx < nr_entries; \ 57386470930SIngo Molnar ++idx, pos = gelf_getrela(reldata, idx, &pos_mem)) 57486470930SIngo Molnar 575a25e46c4SArnaldo Carvalho de Melo /* 576a25e46c4SArnaldo Carvalho de Melo * We need to check if we have a .dynsym, so that we can handle the 577a25e46c4SArnaldo Carvalho de Melo * .plt, synthesizing its symbols, that aren't on the symtabs (be it 578a25e46c4SArnaldo Carvalho de Melo * .dynsym or .symtab). 579a25e46c4SArnaldo Carvalho de Melo * And always look at the original dso, not at debuginfo packages, that 580a25e46c4SArnaldo Carvalho de Melo * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS). 581a25e46c4SArnaldo Carvalho de Melo */ 58282164161SArnaldo Carvalho de Melo static int dso__synthesize_plt_symbols(struct dso *self, struct map *map, 58382164161SArnaldo Carvalho de Melo symbol_filter_t filter) 58486470930SIngo Molnar { 58586470930SIngo Molnar uint32_t nr_rel_entries, idx; 58686470930SIngo Molnar GElf_Sym sym; 5879cffa8d5SPaul Mackerras u64 plt_offset; 58886470930SIngo Molnar GElf_Shdr shdr_plt; 58986470930SIngo Molnar struct symbol *f; 590a25e46c4SArnaldo Carvalho de Melo GElf_Shdr shdr_rel_plt, shdr_dynsym; 59186470930SIngo Molnar Elf_Data *reldata, *syms, *symstrs; 592a25e46c4SArnaldo Carvalho de Melo Elf_Scn *scn_plt_rel, *scn_symstrs, *scn_dynsym; 593a25e46c4SArnaldo Carvalho de Melo size_t dynsym_idx; 594a25e46c4SArnaldo Carvalho de Melo GElf_Ehdr ehdr; 59586470930SIngo Molnar char sympltname[1024]; 596a25e46c4SArnaldo Carvalho de Melo Elf *elf; 597a25e46c4SArnaldo Carvalho de Melo int nr = 0, symidx, fd, err = 0; 59886470930SIngo Molnar 599439d473bSArnaldo Carvalho de Melo fd = open(self->long_name, O_RDONLY); 600a25e46c4SArnaldo Carvalho de Melo if (fd < 0) 601a25e46c4SArnaldo Carvalho de Melo goto out; 602a25e46c4SArnaldo Carvalho de Melo 60384087126SMarti Raudsepp elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 604a25e46c4SArnaldo Carvalho de Melo if (elf == NULL) 605a25e46c4SArnaldo Carvalho de Melo goto out_close; 606a25e46c4SArnaldo Carvalho de Melo 607a25e46c4SArnaldo Carvalho de Melo if (gelf_getehdr(elf, &ehdr) == NULL) 608a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 609a25e46c4SArnaldo Carvalho de Melo 610a25e46c4SArnaldo Carvalho de Melo scn_dynsym = elf_section_by_name(elf, &ehdr, &shdr_dynsym, 611a25e46c4SArnaldo Carvalho de Melo ".dynsym", &dynsym_idx); 612a25e46c4SArnaldo Carvalho de Melo if (scn_dynsym == NULL) 613a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 614a25e46c4SArnaldo Carvalho de Melo 615a25e46c4SArnaldo Carvalho de Melo scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt, 61686470930SIngo Molnar ".rela.plt", NULL); 61786470930SIngo Molnar if (scn_plt_rel == NULL) { 618a25e46c4SArnaldo Carvalho de Melo scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt, 61986470930SIngo Molnar ".rel.plt", NULL); 62086470930SIngo Molnar if (scn_plt_rel == NULL) 621a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 62286470930SIngo Molnar } 62386470930SIngo Molnar 624a25e46c4SArnaldo Carvalho de Melo err = -1; 62586470930SIngo Molnar 626a25e46c4SArnaldo Carvalho de Melo if (shdr_rel_plt.sh_link != dynsym_idx) 627a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 628a25e46c4SArnaldo Carvalho de Melo 629a25e46c4SArnaldo Carvalho de Melo if (elf_section_by_name(elf, &ehdr, &shdr_plt, ".plt", NULL) == NULL) 630a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 63186470930SIngo Molnar 63286470930SIngo Molnar /* 63383a0944fSIngo Molnar * Fetch the relocation section to find the idxes to the GOT 63486470930SIngo Molnar * and the symbols in the .dynsym they refer to. 63586470930SIngo Molnar */ 63686470930SIngo Molnar reldata = elf_getdata(scn_plt_rel, NULL); 63786470930SIngo Molnar if (reldata == NULL) 638a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 63986470930SIngo Molnar 64086470930SIngo Molnar syms = elf_getdata(scn_dynsym, NULL); 64186470930SIngo Molnar if (syms == NULL) 642a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 64386470930SIngo Molnar 644a25e46c4SArnaldo Carvalho de Melo scn_symstrs = elf_getscn(elf, shdr_dynsym.sh_link); 64586470930SIngo Molnar if (scn_symstrs == NULL) 646a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 64786470930SIngo Molnar 64886470930SIngo Molnar symstrs = elf_getdata(scn_symstrs, NULL); 64986470930SIngo Molnar if (symstrs == NULL) 650a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 65186470930SIngo Molnar 65286470930SIngo Molnar nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize; 65386470930SIngo Molnar plt_offset = shdr_plt.sh_offset; 65486470930SIngo Molnar 65586470930SIngo Molnar if (shdr_rel_plt.sh_type == SHT_RELA) { 65686470930SIngo Molnar GElf_Rela pos_mem, *pos; 65786470930SIngo Molnar 65886470930SIngo Molnar elf_section__for_each_rela(reldata, pos, pos_mem, idx, 65986470930SIngo Molnar nr_rel_entries) { 66086470930SIngo Molnar symidx = GELF_R_SYM(pos->r_info); 66186470930SIngo Molnar plt_offset += shdr_plt.sh_entsize; 66286470930SIngo Molnar gelf_getsym(syms, symidx, &sym); 66386470930SIngo Molnar snprintf(sympltname, sizeof(sympltname), 66486470930SIngo Molnar "%s@plt", elf_sym__name(&sym, symstrs)); 66586470930SIngo Molnar 66686470930SIngo Molnar f = symbol__new(plt_offset, shdr_plt.sh_entsize, 66700a192b3SArnaldo Carvalho de Melo sympltname); 66886470930SIngo Molnar if (!f) 669a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 67086470930SIngo Molnar 67182164161SArnaldo Carvalho de Melo if (filter && filter(map, f)) 67282164161SArnaldo Carvalho de Melo symbol__delete(f); 67382164161SArnaldo Carvalho de Melo else { 67486470930SIngo Molnar dso__insert_symbol(self, f); 67586470930SIngo Molnar ++nr; 67686470930SIngo Molnar } 67782164161SArnaldo Carvalho de Melo } 67886470930SIngo Molnar } else if (shdr_rel_plt.sh_type == SHT_REL) { 67986470930SIngo Molnar GElf_Rel pos_mem, *pos; 68086470930SIngo Molnar elf_section__for_each_rel(reldata, pos, pos_mem, idx, 68186470930SIngo Molnar nr_rel_entries) { 68286470930SIngo Molnar symidx = GELF_R_SYM(pos->r_info); 68386470930SIngo Molnar plt_offset += shdr_plt.sh_entsize; 68486470930SIngo Molnar gelf_getsym(syms, symidx, &sym); 68586470930SIngo Molnar snprintf(sympltname, sizeof(sympltname), 68686470930SIngo Molnar "%s@plt", elf_sym__name(&sym, symstrs)); 68786470930SIngo Molnar 68886470930SIngo Molnar f = symbol__new(plt_offset, shdr_plt.sh_entsize, 68900a192b3SArnaldo Carvalho de Melo sympltname); 69086470930SIngo Molnar if (!f) 691a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 69286470930SIngo Molnar 69382164161SArnaldo Carvalho de Melo if (filter && filter(map, f)) 69482164161SArnaldo Carvalho de Melo symbol__delete(f); 69582164161SArnaldo Carvalho de Melo else { 69686470930SIngo Molnar dso__insert_symbol(self, f); 69786470930SIngo Molnar ++nr; 69886470930SIngo Molnar } 69986470930SIngo Molnar } 70082164161SArnaldo Carvalho de Melo } 70186470930SIngo Molnar 702a25e46c4SArnaldo Carvalho de Melo err = 0; 703a25e46c4SArnaldo Carvalho de Melo out_elf_end: 704a25e46c4SArnaldo Carvalho de Melo elf_end(elf); 705a25e46c4SArnaldo Carvalho de Melo out_close: 706a25e46c4SArnaldo Carvalho de Melo close(fd); 707a25e46c4SArnaldo Carvalho de Melo 708a25e46c4SArnaldo Carvalho de Melo if (err == 0) 70986470930SIngo Molnar return nr; 710a25e46c4SArnaldo Carvalho de Melo out: 7116beba7adSArnaldo Carvalho de Melo pr_warning("%s: problems reading %s PLT info.\n", 712439d473bSArnaldo Carvalho de Melo __func__, self->long_name); 713a25e46c4SArnaldo Carvalho de Melo return 0; 71486470930SIngo Molnar } 71586470930SIngo Molnar 716439d473bSArnaldo Carvalho de Melo static int dso__load_sym(struct dso *self, struct map *map, const char *name, 717439d473bSArnaldo Carvalho de Melo int fd, symbol_filter_t filter, int kernel, 7186beba7adSArnaldo Carvalho de Melo int kmodule) 71986470930SIngo Molnar { 7202e538c4aSArnaldo Carvalho de Melo struct map *curr_map = map; 7212e538c4aSArnaldo Carvalho de Melo struct dso *curr_dso = self; 7222e538c4aSArnaldo Carvalho de Melo size_t dso_name_len = strlen(self->short_name); 7236cfcc53eSMike Galbraith Elf_Data *symstrs, *secstrs; 72486470930SIngo Molnar uint32_t nr_syms; 72586470930SIngo Molnar int err = -1; 72683a0944fSIngo Molnar uint32_t idx; 72786470930SIngo Molnar GElf_Ehdr ehdr; 72886470930SIngo Molnar GElf_Shdr shdr; 72986470930SIngo Molnar Elf_Data *syms; 73086470930SIngo Molnar GElf_Sym sym; 731a25e46c4SArnaldo Carvalho de Melo Elf_Scn *sec, *sec_strndx; 73286470930SIngo Molnar Elf *elf; 733439d473bSArnaldo Carvalho de Melo int nr = 0; 73486470930SIngo Molnar 73584087126SMarti Raudsepp elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 73686470930SIngo Molnar if (elf == NULL) { 7376beba7adSArnaldo Carvalho de Melo pr_err("%s: cannot read %s ELF file.\n", __func__, name); 73886470930SIngo Molnar goto out_close; 73986470930SIngo Molnar } 74086470930SIngo Molnar 74186470930SIngo Molnar if (gelf_getehdr(elf, &ehdr) == NULL) { 7426beba7adSArnaldo Carvalho de Melo pr_err("%s: cannot get elf header.\n", __func__); 74386470930SIngo Molnar goto out_elf_end; 74486470930SIngo Molnar } 74586470930SIngo Molnar 74686470930SIngo Molnar sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL); 74786470930SIngo Molnar if (sec == NULL) { 748a25e46c4SArnaldo Carvalho de Melo sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL); 749a25e46c4SArnaldo Carvalho de Melo if (sec == NULL) 75086470930SIngo Molnar goto out_elf_end; 75186470930SIngo Molnar } 75286470930SIngo Molnar 75386470930SIngo Molnar syms = elf_getdata(sec, NULL); 75486470930SIngo Molnar if (syms == NULL) 75586470930SIngo Molnar goto out_elf_end; 75686470930SIngo Molnar 75786470930SIngo Molnar sec = elf_getscn(elf, shdr.sh_link); 75886470930SIngo Molnar if (sec == NULL) 75986470930SIngo Molnar goto out_elf_end; 76086470930SIngo Molnar 76186470930SIngo Molnar symstrs = elf_getdata(sec, NULL); 76286470930SIngo Molnar if (symstrs == NULL) 76386470930SIngo Molnar goto out_elf_end; 76486470930SIngo Molnar 7656cfcc53eSMike Galbraith sec_strndx = elf_getscn(elf, ehdr.e_shstrndx); 7666cfcc53eSMike Galbraith if (sec_strndx == NULL) 7676cfcc53eSMike Galbraith goto out_elf_end; 7686cfcc53eSMike Galbraith 7696cfcc53eSMike Galbraith secstrs = elf_getdata(sec_strndx, NULL); 7709b30a26bSStoyan Gaydarov if (secstrs == NULL) 7716cfcc53eSMike Galbraith goto out_elf_end; 7726cfcc53eSMike Galbraith 77386470930SIngo Molnar nr_syms = shdr.sh_size / shdr.sh_entsize; 77486470930SIngo Molnar 775e9fbc9dcSArjan van de Ven memset(&sym, 0, sizeof(sym)); 776d20ff6bdSMike Galbraith if (!kernel) { 77730d7a77dSArnaldo Carvalho de Melo self->adjust_symbols = (ehdr.e_type == ET_EXEC || 77830d7a77dSArnaldo Carvalho de Melo elf_section_by_name(elf, &ehdr, &shdr, 779f5812a7aSArnaldo Carvalho de Melo ".gnu.prelink_undo", 78030d7a77dSArnaldo Carvalho de Melo NULL) != NULL); 781d20ff6bdSMike Galbraith } else self->adjust_symbols = 0; 782d20ff6bdSMike Galbraith 78383a0944fSIngo Molnar elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) { 78486470930SIngo Molnar struct symbol *f; 78583a0944fSIngo Molnar const char *elf_name; 7862e538c4aSArnaldo Carvalho de Melo char *demangled = NULL; 7876cfcc53eSMike Galbraith int is_label = elf_sym__is_label(&sym); 7886cfcc53eSMike Galbraith const char *section_name; 78986470930SIngo Molnar 7906cfcc53eSMike Galbraith if (!is_label && !elf_sym__is_function(&sym)) 79186470930SIngo Molnar continue; 79286470930SIngo Molnar 79386470930SIngo Molnar sec = elf_getscn(elf, sym.st_shndx); 79486470930SIngo Molnar if (!sec) 79586470930SIngo Molnar goto out_elf_end; 79686470930SIngo Molnar 79786470930SIngo Molnar gelf_getshdr(sec, &shdr); 7986cfcc53eSMike Galbraith 7996cfcc53eSMike Galbraith if (is_label && !elf_sec__is_text(&shdr, secstrs)) 8006cfcc53eSMike Galbraith continue; 8016cfcc53eSMike Galbraith 8022e538c4aSArnaldo Carvalho de Melo elf_name = elf_sym__name(&sym, symstrs); 8036cfcc53eSMike Galbraith section_name = elf_sec__name(&shdr, secstrs); 80486470930SIngo Molnar 8052e538c4aSArnaldo Carvalho de Melo if (kernel || kmodule) { 8062e538c4aSArnaldo Carvalho de Melo char dso_name[PATH_MAX]; 8072e538c4aSArnaldo Carvalho de Melo 8082e538c4aSArnaldo Carvalho de Melo if (strcmp(section_name, 8092e538c4aSArnaldo Carvalho de Melo curr_dso->short_name + dso_name_len) == 0) 8102e538c4aSArnaldo Carvalho de Melo goto new_symbol; 8112e538c4aSArnaldo Carvalho de Melo 8122e538c4aSArnaldo Carvalho de Melo if (strcmp(section_name, ".text") == 0) { 8132e538c4aSArnaldo Carvalho de Melo curr_map = map; 8142e538c4aSArnaldo Carvalho de Melo curr_dso = self; 8152e538c4aSArnaldo Carvalho de Melo goto new_symbol; 816af427bf5SArnaldo Carvalho de Melo } 817af427bf5SArnaldo Carvalho de Melo 8182e538c4aSArnaldo Carvalho de Melo snprintf(dso_name, sizeof(dso_name), 8192e538c4aSArnaldo Carvalho de Melo "%s%s", self->short_name, section_name); 8202e538c4aSArnaldo Carvalho de Melo 8212e538c4aSArnaldo Carvalho de Melo curr_map = kernel_maps__find_by_dso_name(dso_name); 8222e538c4aSArnaldo Carvalho de Melo if (curr_map == NULL) { 8232e538c4aSArnaldo Carvalho de Melo u64 start = sym.st_value; 8242e538c4aSArnaldo Carvalho de Melo 8252e538c4aSArnaldo Carvalho de Melo if (kmodule) 8262e538c4aSArnaldo Carvalho de Melo start += map->start + shdr.sh_offset; 8272e538c4aSArnaldo Carvalho de Melo 82800a192b3SArnaldo Carvalho de Melo curr_dso = dso__new(dso_name); 8292e538c4aSArnaldo Carvalho de Melo if (curr_dso == NULL) 8302e538c4aSArnaldo Carvalho de Melo goto out_elf_end; 8312e538c4aSArnaldo Carvalho de Melo curr_map = map__new2(start, curr_dso); 8322e538c4aSArnaldo Carvalho de Melo if (curr_map == NULL) { 8332e538c4aSArnaldo Carvalho de Melo dso__delete(curr_dso); 8342e538c4aSArnaldo Carvalho de Melo goto out_elf_end; 8352e538c4aSArnaldo Carvalho de Melo } 836ed52ce2eSArnaldo Carvalho de Melo curr_map->map_ip = identity__map_ip; 837ed52ce2eSArnaldo Carvalho de Melo curr_map->unmap_ip = identity__map_ip; 8382e538c4aSArnaldo Carvalho de Melo curr_dso->origin = DSO__ORIG_KERNEL; 8392e538c4aSArnaldo Carvalho de Melo kernel_maps__insert(curr_map); 8402e538c4aSArnaldo Carvalho de Melo dsos__add(curr_dso); 8412e538c4aSArnaldo Carvalho de Melo } else 8422e538c4aSArnaldo Carvalho de Melo curr_dso = curr_map->dso; 8432e538c4aSArnaldo Carvalho de Melo 8442e538c4aSArnaldo Carvalho de Melo goto new_symbol; 8452e538c4aSArnaldo Carvalho de Melo } 8462e538c4aSArnaldo Carvalho de Melo 8472e538c4aSArnaldo Carvalho de Melo if (curr_dso->adjust_symbols) { 8486beba7adSArnaldo Carvalho de Melo pr_debug2("adjusting symbol: st_value: %Lx sh_addr: " 8496beba7adSArnaldo Carvalho de Melo "%Lx sh_offset: %Lx\n", (u64)sym.st_value, 8506beba7adSArnaldo Carvalho de Melo (u64)shdr.sh_addr, (u64)shdr.sh_offset); 85186470930SIngo Molnar sym.st_value -= shdr.sh_addr - shdr.sh_offset; 852af427bf5SArnaldo Carvalho de Melo } 85328ac909bSArnaldo Carvalho de Melo /* 85428ac909bSArnaldo Carvalho de Melo * We need to figure out if the object was created from C++ sources 85528ac909bSArnaldo Carvalho de Melo * DWARF DW_compile_unit has this, but we don't always have access 85628ac909bSArnaldo Carvalho de Melo * to it... 85728ac909bSArnaldo Carvalho de Melo */ 85883a0944fSIngo Molnar demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI); 85928ac909bSArnaldo Carvalho de Melo if (demangled != NULL) 86083a0944fSIngo Molnar elf_name = demangled; 8612e538c4aSArnaldo Carvalho de Melo new_symbol: 86200a192b3SArnaldo Carvalho de Melo f = symbol__new(sym.st_value, sym.st_size, elf_name); 86328ac909bSArnaldo Carvalho de Melo free(demangled); 86486470930SIngo Molnar if (!f) 86586470930SIngo Molnar goto out_elf_end; 86686470930SIngo Molnar 8672e538c4aSArnaldo Carvalho de Melo if (filter && filter(curr_map, f)) 86800a192b3SArnaldo Carvalho de Melo symbol__delete(f); 86986470930SIngo Molnar else { 8702e538c4aSArnaldo Carvalho de Melo dso__insert_symbol(curr_dso, f); 87186470930SIngo Molnar nr++; 87286470930SIngo Molnar } 87386470930SIngo Molnar } 87486470930SIngo Molnar 8752e538c4aSArnaldo Carvalho de Melo /* 8762e538c4aSArnaldo Carvalho de Melo * For misannotated, zeroed, ASM function sizes. 8772e538c4aSArnaldo Carvalho de Melo */ 8782e538c4aSArnaldo Carvalho de Melo if (nr > 0) 8792e538c4aSArnaldo Carvalho de Melo dso__fixup_sym_end(self); 88086470930SIngo Molnar err = nr; 88186470930SIngo Molnar out_elf_end: 88286470930SIngo Molnar elf_end(elf); 88386470930SIngo Molnar out_close: 88486470930SIngo Molnar return err; 88586470930SIngo Molnar } 88686470930SIngo Molnar 887e30a3d12SArnaldo Carvalho de Melo bool dsos__read_build_ids(void) 88857f395a7SFrederic Weisbecker { 889e30a3d12SArnaldo Carvalho de Melo bool have_build_id = false; 89057f395a7SFrederic Weisbecker struct dso *pos; 89157f395a7SFrederic Weisbecker 892e30a3d12SArnaldo Carvalho de Melo list_for_each_entry(pos, &dsos, node) 893e30a3d12SArnaldo Carvalho de Melo if (filename__read_build_id(pos->long_name, pos->build_id, 894e30a3d12SArnaldo Carvalho de Melo sizeof(pos->build_id)) > 0) { 895e30a3d12SArnaldo Carvalho de Melo have_build_id = true; 896e30a3d12SArnaldo Carvalho de Melo pos->has_build_id = true; 89757f395a7SFrederic Weisbecker } 89857f395a7SFrederic Weisbecker 899e30a3d12SArnaldo Carvalho de Melo return have_build_id; 90057f395a7SFrederic Weisbecker } 90157f395a7SFrederic Weisbecker 902*fd7a346eSArnaldo Carvalho de Melo /* 903*fd7a346eSArnaldo Carvalho de Melo * Align offset to 4 bytes as needed for note name and descriptor data. 904*fd7a346eSArnaldo Carvalho de Melo */ 905*fd7a346eSArnaldo Carvalho de Melo #define NOTE_ALIGN(n) (((n) + 3) & -4U) 906*fd7a346eSArnaldo Carvalho de Melo 9072643ce11SArnaldo Carvalho de Melo int filename__read_build_id(const char *filename, void *bf, size_t size) 9084d1e00a8SArnaldo Carvalho de Melo { 9092643ce11SArnaldo Carvalho de Melo int fd, err = -1; 9104d1e00a8SArnaldo Carvalho de Melo GElf_Ehdr ehdr; 9114d1e00a8SArnaldo Carvalho de Melo GElf_Shdr shdr; 912*fd7a346eSArnaldo Carvalho de Melo Elf_Data *data; 9134d1e00a8SArnaldo Carvalho de Melo Elf_Scn *sec; 914*fd7a346eSArnaldo Carvalho de Melo void *ptr; 9154d1e00a8SArnaldo Carvalho de Melo Elf *elf; 9164d1e00a8SArnaldo Carvalho de Melo 9172643ce11SArnaldo Carvalho de Melo if (size < BUILD_ID_SIZE) 9182643ce11SArnaldo Carvalho de Melo goto out; 9192643ce11SArnaldo Carvalho de Melo 9202643ce11SArnaldo Carvalho de Melo fd = open(filename, O_RDONLY); 9214d1e00a8SArnaldo Carvalho de Melo if (fd < 0) 9224d1e00a8SArnaldo Carvalho de Melo goto out; 9234d1e00a8SArnaldo Carvalho de Melo 92484087126SMarti Raudsepp elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 9254d1e00a8SArnaldo Carvalho de Melo if (elf == NULL) { 9268d06367fSArnaldo Carvalho de Melo pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename); 9274d1e00a8SArnaldo Carvalho de Melo goto out_close; 9284d1e00a8SArnaldo Carvalho de Melo } 9294d1e00a8SArnaldo Carvalho de Melo 9304d1e00a8SArnaldo Carvalho de Melo if (gelf_getehdr(elf, &ehdr) == NULL) { 9316beba7adSArnaldo Carvalho de Melo pr_err("%s: cannot get elf header.\n", __func__); 9324d1e00a8SArnaldo Carvalho de Melo goto out_elf_end; 9334d1e00a8SArnaldo Carvalho de Melo } 9344d1e00a8SArnaldo Carvalho de Melo 9352643ce11SArnaldo Carvalho de Melo sec = elf_section_by_name(elf, &ehdr, &shdr, 9362643ce11SArnaldo Carvalho de Melo ".note.gnu.build-id", NULL); 937*fd7a346eSArnaldo Carvalho de Melo if (sec == NULL) { 938*fd7a346eSArnaldo Carvalho de Melo sec = elf_section_by_name(elf, &ehdr, &shdr, 939*fd7a346eSArnaldo Carvalho de Melo ".notes", NULL); 9404d1e00a8SArnaldo Carvalho de Melo if (sec == NULL) 9414d1e00a8SArnaldo Carvalho de Melo goto out_elf_end; 942*fd7a346eSArnaldo Carvalho de Melo } 9434d1e00a8SArnaldo Carvalho de Melo 944*fd7a346eSArnaldo Carvalho de Melo data = elf_getdata(sec, NULL); 945*fd7a346eSArnaldo Carvalho de Melo if (data == NULL) 9464d1e00a8SArnaldo Carvalho de Melo goto out_elf_end; 947*fd7a346eSArnaldo Carvalho de Melo 948*fd7a346eSArnaldo Carvalho de Melo ptr = data->d_buf; 949*fd7a346eSArnaldo Carvalho de Melo while (ptr < (data->d_buf + data->d_size)) { 950*fd7a346eSArnaldo Carvalho de Melo GElf_Nhdr *nhdr = ptr; 951*fd7a346eSArnaldo Carvalho de Melo int namesz = NOTE_ALIGN(nhdr->n_namesz), 952*fd7a346eSArnaldo Carvalho de Melo descsz = NOTE_ALIGN(nhdr->n_descsz); 953*fd7a346eSArnaldo Carvalho de Melo const char *name; 954*fd7a346eSArnaldo Carvalho de Melo 955*fd7a346eSArnaldo Carvalho de Melo ptr += sizeof(*nhdr); 956*fd7a346eSArnaldo Carvalho de Melo name = ptr; 957*fd7a346eSArnaldo Carvalho de Melo ptr += namesz; 958*fd7a346eSArnaldo Carvalho de Melo if (nhdr->n_type == NT_GNU_BUILD_ID && 959*fd7a346eSArnaldo Carvalho de Melo nhdr->n_namesz == sizeof("GNU")) { 960*fd7a346eSArnaldo Carvalho de Melo if (memcmp(name, "GNU", sizeof("GNU")) == 0) { 961*fd7a346eSArnaldo Carvalho de Melo memcpy(bf, ptr, BUILD_ID_SIZE); 9622643ce11SArnaldo Carvalho de Melo err = BUILD_ID_SIZE; 963*fd7a346eSArnaldo Carvalho de Melo break; 964*fd7a346eSArnaldo Carvalho de Melo } 965*fd7a346eSArnaldo Carvalho de Melo } 966*fd7a346eSArnaldo Carvalho de Melo ptr += descsz; 967*fd7a346eSArnaldo Carvalho de Melo } 9682643ce11SArnaldo Carvalho de Melo out_elf_end: 9692643ce11SArnaldo Carvalho de Melo elf_end(elf); 9702643ce11SArnaldo Carvalho de Melo out_close: 9712643ce11SArnaldo Carvalho de Melo close(fd); 9722643ce11SArnaldo Carvalho de Melo out: 9732643ce11SArnaldo Carvalho de Melo return err; 9742643ce11SArnaldo Carvalho de Melo } 9752643ce11SArnaldo Carvalho de Melo 976f1617b40SArnaldo Carvalho de Melo int sysfs__read_build_id(const char *filename, void *build_id, size_t size) 977f1617b40SArnaldo Carvalho de Melo { 978f1617b40SArnaldo Carvalho de Melo int fd, err = -1; 979f1617b40SArnaldo Carvalho de Melo 980f1617b40SArnaldo Carvalho de Melo if (size < BUILD_ID_SIZE) 981f1617b40SArnaldo Carvalho de Melo goto out; 982f1617b40SArnaldo Carvalho de Melo 983f1617b40SArnaldo Carvalho de Melo fd = open(filename, O_RDONLY); 984f1617b40SArnaldo Carvalho de Melo if (fd < 0) 985f1617b40SArnaldo Carvalho de Melo goto out; 986f1617b40SArnaldo Carvalho de Melo 987f1617b40SArnaldo Carvalho de Melo while (1) { 988f1617b40SArnaldo Carvalho de Melo char bf[BUFSIZ]; 989f1617b40SArnaldo Carvalho de Melo GElf_Nhdr nhdr; 990f1617b40SArnaldo Carvalho de Melo int namesz, descsz; 991f1617b40SArnaldo Carvalho de Melo 992f1617b40SArnaldo Carvalho de Melo if (read(fd, &nhdr, sizeof(nhdr)) != sizeof(nhdr)) 993f1617b40SArnaldo Carvalho de Melo break; 994f1617b40SArnaldo Carvalho de Melo 995*fd7a346eSArnaldo Carvalho de Melo namesz = NOTE_ALIGN(nhdr.n_namesz); 996*fd7a346eSArnaldo Carvalho de Melo descsz = NOTE_ALIGN(nhdr.n_descsz); 997f1617b40SArnaldo Carvalho de Melo if (nhdr.n_type == NT_GNU_BUILD_ID && 998f1617b40SArnaldo Carvalho de Melo nhdr.n_namesz == sizeof("GNU")) { 999f1617b40SArnaldo Carvalho de Melo if (read(fd, bf, namesz) != namesz) 1000f1617b40SArnaldo Carvalho de Melo break; 1001f1617b40SArnaldo Carvalho de Melo if (memcmp(bf, "GNU", sizeof("GNU")) == 0) { 1002f1617b40SArnaldo Carvalho de Melo if (read(fd, build_id, 1003f1617b40SArnaldo Carvalho de Melo BUILD_ID_SIZE) == BUILD_ID_SIZE) { 1004f1617b40SArnaldo Carvalho de Melo err = 0; 1005f1617b40SArnaldo Carvalho de Melo break; 1006f1617b40SArnaldo Carvalho de Melo } 1007f1617b40SArnaldo Carvalho de Melo } else if (read(fd, bf, descsz) != descsz) 1008f1617b40SArnaldo Carvalho de Melo break; 1009f1617b40SArnaldo Carvalho de Melo } else { 1010f1617b40SArnaldo Carvalho de Melo int n = namesz + descsz; 1011f1617b40SArnaldo Carvalho de Melo if (read(fd, bf, n) != n) 1012f1617b40SArnaldo Carvalho de Melo break; 1013f1617b40SArnaldo Carvalho de Melo } 1014f1617b40SArnaldo Carvalho de Melo } 1015f1617b40SArnaldo Carvalho de Melo close(fd); 1016f1617b40SArnaldo Carvalho de Melo out: 1017f1617b40SArnaldo Carvalho de Melo return err; 1018f1617b40SArnaldo Carvalho de Melo } 1019f1617b40SArnaldo Carvalho de Melo 102094cb9e38SArnaldo Carvalho de Melo char dso__symtab_origin(const struct dso *self) 102194cb9e38SArnaldo Carvalho de Melo { 102294cb9e38SArnaldo Carvalho de Melo static const char origin[] = { 102394cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_KERNEL] = 'k', 102494cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_JAVA_JIT] = 'j', 102594cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_FEDORA] = 'f', 102694cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_UBUNTU] = 'u', 102794cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_BUILDID] = 'b', 102894cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_DSO] = 'd', 1029439d473bSArnaldo Carvalho de Melo [DSO__ORIG_KMODULE] = 'K', 103094cb9e38SArnaldo Carvalho de Melo }; 103194cb9e38SArnaldo Carvalho de Melo 103294cb9e38SArnaldo Carvalho de Melo if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND) 103394cb9e38SArnaldo Carvalho de Melo return '!'; 103494cb9e38SArnaldo Carvalho de Melo return origin[self->origin]; 103594cb9e38SArnaldo Carvalho de Melo } 103694cb9e38SArnaldo Carvalho de Melo 10376beba7adSArnaldo Carvalho de Melo int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) 103886470930SIngo Molnar { 10394d1e00a8SArnaldo Carvalho de Melo int size = PATH_MAX; 1040d3379ab9SArnaldo Carvalho de Melo char *name = malloc(size); 1041d3379ab9SArnaldo Carvalho de Melo u8 build_id[BUILD_ID_SIZE]; 104286470930SIngo Molnar int ret = -1; 104386470930SIngo Molnar int fd; 104486470930SIngo Molnar 10458d06367fSArnaldo Carvalho de Melo self->loaded = 1; 104666bd8424SArnaldo Carvalho de Melo 104786470930SIngo Molnar if (!name) 104886470930SIngo Molnar return -1; 104986470930SIngo Molnar 105030d7a77dSArnaldo Carvalho de Melo self->adjust_symbols = 0; 1051f5812a7aSArnaldo Carvalho de Melo 105294cb9e38SArnaldo Carvalho de Melo if (strncmp(self->name, "/tmp/perf-", 10) == 0) { 10536beba7adSArnaldo Carvalho de Melo ret = dso__load_perf_map(self, map, filter); 105494cb9e38SArnaldo Carvalho de Melo self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT : 105594cb9e38SArnaldo Carvalho de Melo DSO__ORIG_NOT_FOUND; 105694cb9e38SArnaldo Carvalho de Melo return ret; 105794cb9e38SArnaldo Carvalho de Melo } 105894cb9e38SArnaldo Carvalho de Melo 105994cb9e38SArnaldo Carvalho de Melo self->origin = DSO__ORIG_FEDORA - 1; 106080d496beSPekka Enberg 106186470930SIngo Molnar more: 106286470930SIngo Molnar do { 106394cb9e38SArnaldo Carvalho de Melo self->origin++; 106494cb9e38SArnaldo Carvalho de Melo switch (self->origin) { 106594cb9e38SArnaldo Carvalho de Melo case DSO__ORIG_FEDORA: 1066439d473bSArnaldo Carvalho de Melo snprintf(name, size, "/usr/lib/debug%s.debug", 1067439d473bSArnaldo Carvalho de Melo self->long_name); 106886470930SIngo Molnar break; 106994cb9e38SArnaldo Carvalho de Melo case DSO__ORIG_UBUNTU: 1070439d473bSArnaldo Carvalho de Melo snprintf(name, size, "/usr/lib/debug%s", 1071439d473bSArnaldo Carvalho de Melo self->long_name); 107286470930SIngo Molnar break; 107394cb9e38SArnaldo Carvalho de Melo case DSO__ORIG_BUILDID: 1074d3379ab9SArnaldo Carvalho de Melo if (filename__read_build_id(self->long_name, build_id, 1075d3379ab9SArnaldo Carvalho de Melo sizeof(build_id))) { 1076d3379ab9SArnaldo Carvalho de Melo char build_id_hex[BUILD_ID_SIZE * 2 + 1]; 1077d3379ab9SArnaldo Carvalho de Melo 1078d3379ab9SArnaldo Carvalho de Melo build_id__sprintf(build_id, sizeof(build_id), 1079d3379ab9SArnaldo Carvalho de Melo build_id_hex); 10804d1e00a8SArnaldo Carvalho de Melo snprintf(name, size, 10814d1e00a8SArnaldo Carvalho de Melo "/usr/lib/debug/.build-id/%.2s/%s.debug", 1082d3379ab9SArnaldo Carvalho de Melo build_id_hex, build_id_hex + 2); 1083d3379ab9SArnaldo Carvalho de Melo if (self->has_build_id) 10848d06367fSArnaldo Carvalho de Melo goto compare_build_id; 1085d3379ab9SArnaldo Carvalho de Melo break; 10864d1e00a8SArnaldo Carvalho de Melo } 108794cb9e38SArnaldo Carvalho de Melo self->origin++; 10884d1e00a8SArnaldo Carvalho de Melo /* Fall thru */ 108994cb9e38SArnaldo Carvalho de Melo case DSO__ORIG_DSO: 1090439d473bSArnaldo Carvalho de Melo snprintf(name, size, "%s", self->long_name); 109186470930SIngo Molnar break; 109286470930SIngo Molnar 109386470930SIngo Molnar default: 109486470930SIngo Molnar goto out; 109586470930SIngo Molnar } 109686470930SIngo Molnar 10978d06367fSArnaldo Carvalho de Melo if (self->has_build_id) { 1098d3379ab9SArnaldo Carvalho de Melo if (filename__read_build_id(name, build_id, 1099d3379ab9SArnaldo Carvalho de Melo sizeof(build_id)) < 0) 11008d06367fSArnaldo Carvalho de Melo goto more; 11018d06367fSArnaldo Carvalho de Melo compare_build_id: 1102d3379ab9SArnaldo Carvalho de Melo if (memcmp(build_id, self->build_id, 1103d3379ab9SArnaldo Carvalho de Melo sizeof(self->build_id)) != 0) 11048d06367fSArnaldo Carvalho de Melo goto more; 11058d06367fSArnaldo Carvalho de Melo } 11068d06367fSArnaldo Carvalho de Melo 110786470930SIngo Molnar fd = open(name, O_RDONLY); 110886470930SIngo Molnar } while (fd < 0); 110986470930SIngo Molnar 11106beba7adSArnaldo Carvalho de Melo ret = dso__load_sym(self, map, name, fd, filter, 0, 0); 111186470930SIngo Molnar close(fd); 111286470930SIngo Molnar 111386470930SIngo Molnar /* 111486470930SIngo Molnar * Some people seem to have debuginfo files _WITHOUT_ debug info!?!? 111586470930SIngo Molnar */ 111686470930SIngo Molnar if (!ret) 111786470930SIngo Molnar goto more; 111886470930SIngo Molnar 1119a25e46c4SArnaldo Carvalho de Melo if (ret > 0) { 112082164161SArnaldo Carvalho de Melo int nr_plt = dso__synthesize_plt_symbols(self, map, filter); 1121a25e46c4SArnaldo Carvalho de Melo if (nr_plt > 0) 1122a25e46c4SArnaldo Carvalho de Melo ret += nr_plt; 1123a25e46c4SArnaldo Carvalho de Melo } 112486470930SIngo Molnar out: 112586470930SIngo Molnar free(name); 11261340e6bbSArnaldo Carvalho de Melo if (ret < 0 && strstr(self->name, " (deleted)") != NULL) 11271340e6bbSArnaldo Carvalho de Melo return 0; 112886470930SIngo Molnar return ret; 112986470930SIngo Molnar } 113086470930SIngo Molnar 1131439d473bSArnaldo Carvalho de Melo struct map *kernel_map; 1132439d473bSArnaldo Carvalho de Melo 1133439d473bSArnaldo Carvalho de Melo static void kernel_maps__insert(struct map *map) 1134439d473bSArnaldo Carvalho de Melo { 1135439d473bSArnaldo Carvalho de Melo maps__insert(&kernel_maps, map); 1136439d473bSArnaldo Carvalho de Melo } 1137439d473bSArnaldo Carvalho de Melo 1138439d473bSArnaldo Carvalho de Melo struct symbol *kernel_maps__find_symbol(u64 ip, struct map **mapp) 1139439d473bSArnaldo Carvalho de Melo { 1140439d473bSArnaldo Carvalho de Melo struct map *map = maps__find(&kernel_maps, ip); 1141439d473bSArnaldo Carvalho de Melo 1142439d473bSArnaldo Carvalho de Melo if (mapp) 1143439d473bSArnaldo Carvalho de Melo *mapp = map; 1144439d473bSArnaldo Carvalho de Melo 11452e538c4aSArnaldo Carvalho de Melo if (map) { 11462e538c4aSArnaldo Carvalho de Melo ip = map->map_ip(map, ip); 11472e538c4aSArnaldo Carvalho de Melo return map->dso->find_symbol(map->dso, ip); 11482e538c4aSArnaldo Carvalho de Melo } 11492e538c4aSArnaldo Carvalho de Melo 11502e538c4aSArnaldo Carvalho de Melo return NULL; 1151439d473bSArnaldo Carvalho de Melo } 1152439d473bSArnaldo Carvalho de Melo 1153439d473bSArnaldo Carvalho de Melo struct map *kernel_maps__find_by_dso_name(const char *name) 1154439d473bSArnaldo Carvalho de Melo { 1155439d473bSArnaldo Carvalho de Melo struct rb_node *nd; 1156439d473bSArnaldo Carvalho de Melo 1157439d473bSArnaldo Carvalho de Melo for (nd = rb_first(&kernel_maps); nd; nd = rb_next(nd)) { 1158439d473bSArnaldo Carvalho de Melo struct map *map = rb_entry(nd, struct map, rb_node); 1159439d473bSArnaldo Carvalho de Melo 1160439d473bSArnaldo Carvalho de Melo if (map->dso && strcmp(map->dso->name, name) == 0) 1161439d473bSArnaldo Carvalho de Melo return map; 1162439d473bSArnaldo Carvalho de Melo } 1163439d473bSArnaldo Carvalho de Melo 1164439d473bSArnaldo Carvalho de Melo return NULL; 1165439d473bSArnaldo Carvalho de Melo } 1166439d473bSArnaldo Carvalho de Melo 1167439d473bSArnaldo Carvalho de Melo static int dso__load_module_sym(struct dso *self, struct map *map, 11686beba7adSArnaldo Carvalho de Melo symbol_filter_t filter) 11696cfcc53eSMike Galbraith { 1170439d473bSArnaldo Carvalho de Melo int err = 0, fd = open(self->long_name, O_RDONLY); 11716cfcc53eSMike Galbraith 11728d06367fSArnaldo Carvalho de Melo self->loaded = 1; 117366bd8424SArnaldo Carvalho de Melo 1174439d473bSArnaldo Carvalho de Melo if (fd < 0) { 11756beba7adSArnaldo Carvalho de Melo pr_err("%s: cannot open %s\n", __func__, self->long_name); 11766cfcc53eSMike Galbraith return err; 1177439d473bSArnaldo Carvalho de Melo } 11786cfcc53eSMike Galbraith 11796beba7adSArnaldo Carvalho de Melo err = dso__load_sym(self, map, self->long_name, fd, filter, 0, 1); 11806cfcc53eSMike Galbraith close(fd); 11816cfcc53eSMike Galbraith 11826cfcc53eSMike Galbraith return err; 11836cfcc53eSMike Galbraith } 11846cfcc53eSMike Galbraith 11856beba7adSArnaldo Carvalho de Melo static int dsos__load_modules_sym_dir(char *dirname, symbol_filter_t filter) 11866cfcc53eSMike Galbraith { 1187439d473bSArnaldo Carvalho de Melo struct dirent *dent; 1188439d473bSArnaldo Carvalho de Melo int nr_symbols = 0, err; 1189439d473bSArnaldo Carvalho de Melo DIR *dir = opendir(dirname); 11906cfcc53eSMike Galbraith 1191439d473bSArnaldo Carvalho de Melo if (!dir) { 11926beba7adSArnaldo Carvalho de Melo pr_err("%s: cannot open %s dir\n", __func__, dirname); 1193439d473bSArnaldo Carvalho de Melo return -1; 1194439d473bSArnaldo Carvalho de Melo } 11956cfcc53eSMike Galbraith 1196439d473bSArnaldo Carvalho de Melo while ((dent = readdir(dir)) != NULL) { 1197439d473bSArnaldo Carvalho de Melo char path[PATH_MAX]; 1198439d473bSArnaldo Carvalho de Melo 1199439d473bSArnaldo Carvalho de Melo if (dent->d_type == DT_DIR) { 1200439d473bSArnaldo Carvalho de Melo if (!strcmp(dent->d_name, ".") || 1201439d473bSArnaldo Carvalho de Melo !strcmp(dent->d_name, "..")) 1202439d473bSArnaldo Carvalho de Melo continue; 1203439d473bSArnaldo Carvalho de Melo 1204439d473bSArnaldo Carvalho de Melo snprintf(path, sizeof(path), "%s/%s", 1205439d473bSArnaldo Carvalho de Melo dirname, dent->d_name); 12066beba7adSArnaldo Carvalho de Melo err = dsos__load_modules_sym_dir(path, filter); 1207439d473bSArnaldo Carvalho de Melo if (err < 0) 1208439d473bSArnaldo Carvalho de Melo goto failure; 1209439d473bSArnaldo Carvalho de Melo } else { 1210439d473bSArnaldo Carvalho de Melo char *dot = strrchr(dent->d_name, '.'), 1211439d473bSArnaldo Carvalho de Melo dso_name[PATH_MAX]; 1212439d473bSArnaldo Carvalho de Melo struct map *map; 1213439d473bSArnaldo Carvalho de Melo struct rb_node *last; 1214cfc10d3bSArnaldo Carvalho de Melo char *long_name; 1215439d473bSArnaldo Carvalho de Melo 1216439d473bSArnaldo Carvalho de Melo if (dot == NULL || strcmp(dot, ".ko")) 1217439d473bSArnaldo Carvalho de Melo continue; 1218439d473bSArnaldo Carvalho de Melo snprintf(dso_name, sizeof(dso_name), "[%.*s]", 1219439d473bSArnaldo Carvalho de Melo (int)(dot - dent->d_name), dent->d_name); 1220439d473bSArnaldo Carvalho de Melo 1221a2a99e8eSArnaldo Carvalho de Melo strxfrchar(dso_name, '-', '_'); 1222439d473bSArnaldo Carvalho de Melo map = kernel_maps__find_by_dso_name(dso_name); 1223439d473bSArnaldo Carvalho de Melo if (map == NULL) 1224439d473bSArnaldo Carvalho de Melo continue; 1225439d473bSArnaldo Carvalho de Melo 1226439d473bSArnaldo Carvalho de Melo snprintf(path, sizeof(path), "%s/%s", 1227439d473bSArnaldo Carvalho de Melo dirname, dent->d_name); 1228439d473bSArnaldo Carvalho de Melo 1229cfc10d3bSArnaldo Carvalho de Melo long_name = strdup(path); 1230cfc10d3bSArnaldo Carvalho de Melo if (long_name == NULL) 1231439d473bSArnaldo Carvalho de Melo goto failure; 1232cfc10d3bSArnaldo Carvalho de Melo dso__set_long_name(map->dso, long_name); 1233cfc10d3bSArnaldo Carvalho de Melo dso__set_basename(map->dso); 1234439d473bSArnaldo Carvalho de Melo 12356beba7adSArnaldo Carvalho de Melo err = dso__load_module_sym(map->dso, map, filter); 1236439d473bSArnaldo Carvalho de Melo if (err < 0) 1237439d473bSArnaldo Carvalho de Melo goto failure; 1238439d473bSArnaldo Carvalho de Melo last = rb_last(&map->dso->syms); 1239439d473bSArnaldo Carvalho de Melo if (last) { 1240439d473bSArnaldo Carvalho de Melo struct symbol *sym; 12412e538c4aSArnaldo Carvalho de Melo /* 12422e538c4aSArnaldo Carvalho de Melo * We do this here as well, even having the 12432e538c4aSArnaldo Carvalho de Melo * symbol size found in the symtab because 12442e538c4aSArnaldo Carvalho de Melo * misannotated ASM symbols may have the size 12452e538c4aSArnaldo Carvalho de Melo * set to zero. 12462e538c4aSArnaldo Carvalho de Melo */ 12472e538c4aSArnaldo Carvalho de Melo dso__fixup_sym_end(map->dso); 12482e538c4aSArnaldo Carvalho de Melo 1249439d473bSArnaldo Carvalho de Melo sym = rb_entry(last, struct symbol, rb_node); 1250439d473bSArnaldo Carvalho de Melo map->end = map->start + sym->end; 1251439d473bSArnaldo Carvalho de Melo } 1252439d473bSArnaldo Carvalho de Melo } 1253439d473bSArnaldo Carvalho de Melo nr_symbols += err; 1254439d473bSArnaldo Carvalho de Melo } 1255439d473bSArnaldo Carvalho de Melo 1256439d473bSArnaldo Carvalho de Melo return nr_symbols; 1257439d473bSArnaldo Carvalho de Melo failure: 1258439d473bSArnaldo Carvalho de Melo closedir(dir); 1259439d473bSArnaldo Carvalho de Melo return -1; 1260439d473bSArnaldo Carvalho de Melo } 1261439d473bSArnaldo Carvalho de Melo 12626671cb16SArnaldo Carvalho de Melo int dsos__load_modules_sym(symbol_filter_t filter) 1263439d473bSArnaldo Carvalho de Melo { 1264439d473bSArnaldo Carvalho de Melo struct utsname uts; 1265439d473bSArnaldo Carvalho de Melo char modules_path[PATH_MAX]; 1266439d473bSArnaldo Carvalho de Melo 1267439d473bSArnaldo Carvalho de Melo if (uname(&uts) < 0) 1268439d473bSArnaldo Carvalho de Melo return -1; 1269439d473bSArnaldo Carvalho de Melo 1270439d473bSArnaldo Carvalho de Melo snprintf(modules_path, sizeof(modules_path), "/lib/modules/%s/kernel", 1271439d473bSArnaldo Carvalho de Melo uts.release); 1272439d473bSArnaldo Carvalho de Melo 12736beba7adSArnaldo Carvalho de Melo return dsos__load_modules_sym_dir(modules_path, filter); 1274439d473bSArnaldo Carvalho de Melo } 12756cfcc53eSMike Galbraith 12766cfcc53eSMike Galbraith /* 1277439d473bSArnaldo Carvalho de Melo * Constructor variant for modules (where we know from /proc/modules where 1278439d473bSArnaldo Carvalho de Melo * they are loaded) and for vmlinux, where only after we load all the 1279439d473bSArnaldo Carvalho de Melo * symbols we'll know where it starts and ends. 12806cfcc53eSMike Galbraith */ 1281439d473bSArnaldo Carvalho de Melo static struct map *map__new2(u64 start, struct dso *dso) 1282439d473bSArnaldo Carvalho de Melo { 1283439d473bSArnaldo Carvalho de Melo struct map *self = malloc(sizeof(*self)); 12846cfcc53eSMike Galbraith 1285439d473bSArnaldo Carvalho de Melo if (self != NULL) { 1286439d473bSArnaldo Carvalho de Melo /* 1287afb7b4f0SArnaldo Carvalho de Melo * ->end will be filled after we load all the symbols 1288439d473bSArnaldo Carvalho de Melo */ 1289afb7b4f0SArnaldo Carvalho de Melo map__init(self, start, 0, 0, dso); 1290439d473bSArnaldo Carvalho de Melo } 1291afb7b4f0SArnaldo Carvalho de Melo 1292439d473bSArnaldo Carvalho de Melo return self; 1293439d473bSArnaldo Carvalho de Melo } 1294439d473bSArnaldo Carvalho de Melo 1295f1617b40SArnaldo Carvalho de Melo int dsos__load_modules(void) 1296439d473bSArnaldo Carvalho de Melo { 1297439d473bSArnaldo Carvalho de Melo char *line = NULL; 1298439d473bSArnaldo Carvalho de Melo size_t n; 1299439d473bSArnaldo Carvalho de Melo FILE *file = fopen("/proc/modules", "r"); 1300439d473bSArnaldo Carvalho de Melo struct map *map; 1301439d473bSArnaldo Carvalho de Melo 1302439d473bSArnaldo Carvalho de Melo if (file == NULL) 1303439d473bSArnaldo Carvalho de Melo return -1; 1304439d473bSArnaldo Carvalho de Melo 1305439d473bSArnaldo Carvalho de Melo while (!feof(file)) { 1306439d473bSArnaldo Carvalho de Melo char name[PATH_MAX]; 1307439d473bSArnaldo Carvalho de Melo u64 start; 1308439d473bSArnaldo Carvalho de Melo struct dso *dso; 1309439d473bSArnaldo Carvalho de Melo char *sep; 1310439d473bSArnaldo Carvalho de Melo int line_len; 1311439d473bSArnaldo Carvalho de Melo 1312439d473bSArnaldo Carvalho de Melo line_len = getline(&line, &n, file); 1313439d473bSArnaldo Carvalho de Melo if (line_len < 0) 13146cfcc53eSMike Galbraith break; 13156cfcc53eSMike Galbraith 1316439d473bSArnaldo Carvalho de Melo if (!line) 1317439d473bSArnaldo Carvalho de Melo goto out_failure; 1318439d473bSArnaldo Carvalho de Melo 1319439d473bSArnaldo Carvalho de Melo line[--line_len] = '\0'; /* \n */ 1320439d473bSArnaldo Carvalho de Melo 1321439d473bSArnaldo Carvalho de Melo sep = strrchr(line, 'x'); 1322439d473bSArnaldo Carvalho de Melo if (sep == NULL) 1323439d473bSArnaldo Carvalho de Melo continue; 1324439d473bSArnaldo Carvalho de Melo 1325439d473bSArnaldo Carvalho de Melo hex2u64(sep + 1, &start); 1326439d473bSArnaldo Carvalho de Melo 1327439d473bSArnaldo Carvalho de Melo sep = strchr(line, ' '); 1328439d473bSArnaldo Carvalho de Melo if (sep == NULL) 1329439d473bSArnaldo Carvalho de Melo continue; 1330439d473bSArnaldo Carvalho de Melo 1331439d473bSArnaldo Carvalho de Melo *sep = '\0'; 1332439d473bSArnaldo Carvalho de Melo 1333439d473bSArnaldo Carvalho de Melo snprintf(name, sizeof(name), "[%s]", line); 133400a192b3SArnaldo Carvalho de Melo dso = dso__new(name); 1335439d473bSArnaldo Carvalho de Melo 1336439d473bSArnaldo Carvalho de Melo if (dso == NULL) 1337439d473bSArnaldo Carvalho de Melo goto out_delete_line; 1338439d473bSArnaldo Carvalho de Melo 1339439d473bSArnaldo Carvalho de Melo map = map__new2(start, dso); 1340439d473bSArnaldo Carvalho de Melo if (map == NULL) { 1341439d473bSArnaldo Carvalho de Melo dso__delete(dso); 1342439d473bSArnaldo Carvalho de Melo goto out_delete_line; 13436cfcc53eSMike Galbraith } 13446cfcc53eSMike Galbraith 1345f1617b40SArnaldo Carvalho de Melo snprintf(name, sizeof(name), 1346f1617b40SArnaldo Carvalho de Melo "/sys/module/%s/notes/.note.gnu.build-id", line); 1347f1617b40SArnaldo Carvalho de Melo if (sysfs__read_build_id(name, dso->build_id, 1348f1617b40SArnaldo Carvalho de Melo sizeof(dso->build_id)) == 0) 1349f1617b40SArnaldo Carvalho de Melo dso->has_build_id = true; 1350f1617b40SArnaldo Carvalho de Melo 1351439d473bSArnaldo Carvalho de Melo dso->origin = DSO__ORIG_KMODULE; 1352439d473bSArnaldo Carvalho de Melo kernel_maps__insert(map); 1353439d473bSArnaldo Carvalho de Melo dsos__add(dso); 13546cfcc53eSMike Galbraith } 13556cfcc53eSMike Galbraith 1356439d473bSArnaldo Carvalho de Melo free(line); 1357439d473bSArnaldo Carvalho de Melo fclose(file); 1358439d473bSArnaldo Carvalho de Melo 1359af427bf5SArnaldo Carvalho de Melo return 0; 1360439d473bSArnaldo Carvalho de Melo 1361439d473bSArnaldo Carvalho de Melo out_delete_line: 1362439d473bSArnaldo Carvalho de Melo free(line); 1363439d473bSArnaldo Carvalho de Melo out_failure: 1364439d473bSArnaldo Carvalho de Melo return -1; 13656cfcc53eSMike Galbraith } 13666cfcc53eSMike Galbraith 1367439d473bSArnaldo Carvalho de Melo static int dso__load_vmlinux(struct dso *self, struct map *map, 13686beba7adSArnaldo Carvalho de Melo const char *vmlinux, symbol_filter_t filter) 136986470930SIngo Molnar { 137086470930SIngo Molnar int err, fd = open(vmlinux, O_RDONLY); 137186470930SIngo Molnar 13728d06367fSArnaldo Carvalho de Melo self->loaded = 1; 137366bd8424SArnaldo Carvalho de Melo 137486470930SIngo Molnar if (fd < 0) 137586470930SIngo Molnar return -1; 137686470930SIngo Molnar 13776beba7adSArnaldo Carvalho de Melo err = dso__load_sym(self, map, self->long_name, fd, filter, 1, 0); 13786cfcc53eSMike Galbraith 137986470930SIngo Molnar close(fd); 138086470930SIngo Molnar 138186470930SIngo Molnar return err; 138286470930SIngo Molnar } 138386470930SIngo Molnar 13846671cb16SArnaldo Carvalho de Melo int dso__load_kernel_sym(struct dso *self, symbol_filter_t filter, 13856671cb16SArnaldo Carvalho de Melo int use_modules) 138686470930SIngo Molnar { 13876671cb16SArnaldo Carvalho de Melo int err; 1388439d473bSArnaldo Carvalho de Melo 13892446042cSArnaldo Carvalho de Melo kernel_map = map__new2(0, self); 1390439d473bSArnaldo Carvalho de Melo if (kernel_map == NULL) 13916671cb16SArnaldo Carvalho de Melo return -1; 1392439d473bSArnaldo Carvalho de Melo 1393ed52ce2eSArnaldo Carvalho de Melo kernel_map->map_ip = kernel_map->unmap_ip = identity__map_ip; 139486470930SIngo Molnar 13952446042cSArnaldo Carvalho de Melo err = dso__load_vmlinux(self, kernel_map, self->name, filter); 13969974f496SMike Galbraith if (err <= 0) 13976beba7adSArnaldo Carvalho de Melo err = kernel_maps__load_kallsyms(filter, use_modules); 139886470930SIngo Molnar 1399439d473bSArnaldo Carvalho de Melo if (err > 0) { 14002446042cSArnaldo Carvalho de Melo struct rb_node *node = rb_first(&self->syms); 1401439d473bSArnaldo Carvalho de Melo struct symbol *sym = rb_entry(node, struct symbol, rb_node); 1402439d473bSArnaldo Carvalho de Melo 1403439d473bSArnaldo Carvalho de Melo kernel_map->start = sym->start; 14042446042cSArnaldo Carvalho de Melo node = rb_last(&self->syms); 1405439d473bSArnaldo Carvalho de Melo sym = rb_entry(node, struct symbol, rb_node); 1406439d473bSArnaldo Carvalho de Melo kernel_map->end = sym->end; 1407439d473bSArnaldo Carvalho de Melo 14082446042cSArnaldo Carvalho de Melo self->origin = DSO__ORIG_KERNEL; 14092e538c4aSArnaldo Carvalho de Melo kernel_maps__insert(kernel_map); 1410439d473bSArnaldo Carvalho de Melo /* 14112e538c4aSArnaldo Carvalho de Melo * Now that we have all sorted out, just set the ->end of all 14122e538c4aSArnaldo Carvalho de Melo * maps: 1413439d473bSArnaldo Carvalho de Melo */ 14142e538c4aSArnaldo Carvalho de Melo kernel_maps__fixup_end(); 1415af427bf5SArnaldo Carvalho de Melo 14166beba7adSArnaldo Carvalho de Melo if (verbose) 14176beba7adSArnaldo Carvalho de Melo kernel_maps__fprintf(stderr); 1418439d473bSArnaldo Carvalho de Melo } 141994cb9e38SArnaldo Carvalho de Melo 142086470930SIngo Molnar return err; 142186470930SIngo Molnar } 142286470930SIngo Molnar 1423cd84c2acSFrederic Weisbecker LIST_HEAD(dsos); 1424cd84c2acSFrederic Weisbecker struct dso *vdso; 1425cd84c2acSFrederic Weisbecker 142683a0944fSIngo Molnar const char *vmlinux_name = "vmlinux"; 1427cd84c2acSFrederic Weisbecker 1428cd84c2acSFrederic Weisbecker static void dsos__add(struct dso *dso) 1429cd84c2acSFrederic Weisbecker { 1430cd84c2acSFrederic Weisbecker list_add_tail(&dso->node, &dsos); 1431cd84c2acSFrederic Weisbecker } 1432cd84c2acSFrederic Weisbecker 1433cd84c2acSFrederic Weisbecker static struct dso *dsos__find(const char *name) 1434cd84c2acSFrederic Weisbecker { 1435cd84c2acSFrederic Weisbecker struct dso *pos; 1436cd84c2acSFrederic Weisbecker 1437cd84c2acSFrederic Weisbecker list_for_each_entry(pos, &dsos, node) 1438cd84c2acSFrederic Weisbecker if (strcmp(pos->name, name) == 0) 1439cd84c2acSFrederic Weisbecker return pos; 1440cd84c2acSFrederic Weisbecker return NULL; 1441cd84c2acSFrederic Weisbecker } 1442cd84c2acSFrederic Weisbecker 144300a192b3SArnaldo Carvalho de Melo struct dso *dsos__findnew(const char *name) 1444cd84c2acSFrederic Weisbecker { 1445cd84c2acSFrederic Weisbecker struct dso *dso = dsos__find(name); 1446cd84c2acSFrederic Weisbecker 1447e4204992SArnaldo Carvalho de Melo if (!dso) { 144800a192b3SArnaldo Carvalho de Melo dso = dso__new(name); 1449cfc10d3bSArnaldo Carvalho de Melo if (dso != NULL) { 1450cd84c2acSFrederic Weisbecker dsos__add(dso); 1451cfc10d3bSArnaldo Carvalho de Melo dso__set_basename(dso); 1452cfc10d3bSArnaldo Carvalho de Melo } 1453e4204992SArnaldo Carvalho de Melo } 1454cd84c2acSFrederic Weisbecker 1455cd84c2acSFrederic Weisbecker return dso; 1456cd84c2acSFrederic Weisbecker } 1457cd84c2acSFrederic Weisbecker 1458cd84c2acSFrederic Weisbecker void dsos__fprintf(FILE *fp) 1459cd84c2acSFrederic Weisbecker { 1460cd84c2acSFrederic Weisbecker struct dso *pos; 1461cd84c2acSFrederic Weisbecker 1462cd84c2acSFrederic Weisbecker list_for_each_entry(pos, &dsos, node) 1463cd84c2acSFrederic Weisbecker dso__fprintf(pos, fp); 1464cd84c2acSFrederic Weisbecker } 1465cd84c2acSFrederic Weisbecker 14669e03eb2dSArnaldo Carvalho de Melo size_t dsos__fprintf_buildid(FILE *fp) 14679e03eb2dSArnaldo Carvalho de Melo { 14689e03eb2dSArnaldo Carvalho de Melo struct dso *pos; 14699e03eb2dSArnaldo Carvalho de Melo size_t ret = 0; 14709e03eb2dSArnaldo Carvalho de Melo 14719e03eb2dSArnaldo Carvalho de Melo list_for_each_entry(pos, &dsos, node) { 14729e03eb2dSArnaldo Carvalho de Melo ret += dso__fprintf_buildid(pos, fp); 14739e03eb2dSArnaldo Carvalho de Melo ret += fprintf(fp, " %s\n", pos->long_name); 14749e03eb2dSArnaldo Carvalho de Melo } 14759e03eb2dSArnaldo Carvalho de Melo return ret; 14769e03eb2dSArnaldo Carvalho de Melo } 14779e03eb2dSArnaldo Carvalho de Melo 14782446042cSArnaldo Carvalho de Melo struct dso *dsos__load_kernel(void) 1479cd84c2acSFrederic Weisbecker { 14802446042cSArnaldo Carvalho de Melo struct dso *kernel = dso__new(vmlinux_name); 1481cd84c2acSFrederic Weisbecker 14822446042cSArnaldo Carvalho de Melo if (kernel == NULL) 14832446042cSArnaldo Carvalho de Melo return NULL; 14842446042cSArnaldo Carvalho de Melo 14852446042cSArnaldo Carvalho de Melo kernel->short_name = "[kernel]"; 148600a192b3SArnaldo Carvalho de Melo vdso = dso__new("[vdso]"); 1487cd84c2acSFrederic Weisbecker if (!vdso) 14882446042cSArnaldo Carvalho de Melo return NULL; 1489cd84c2acSFrederic Weisbecker 14902446042cSArnaldo Carvalho de Melo if (sysfs__read_build_id("/sys/kernel/notes", kernel->build_id, 14912446042cSArnaldo Carvalho de Melo sizeof(kernel->build_id)) == 0) 14922446042cSArnaldo Carvalho de Melo kernel->has_build_id = true; 14932446042cSArnaldo Carvalho de Melo 14942446042cSArnaldo Carvalho de Melo dsos__add(kernel); 1495cd84c2acSFrederic Weisbecker dsos__add(vdso); 1496cd84c2acSFrederic Weisbecker 14972446042cSArnaldo Carvalho de Melo return kernel; 14982446042cSArnaldo Carvalho de Melo } 14992446042cSArnaldo Carvalho de Melo 15006671cb16SArnaldo Carvalho de Melo int load_kernel(symbol_filter_t filter, bool use_modules) 15012446042cSArnaldo Carvalho de Melo { 15022446042cSArnaldo Carvalho de Melo struct dso *kernel = dsos__load_kernel(); 15032446042cSArnaldo Carvalho de Melo 15042446042cSArnaldo Carvalho de Melo if (kernel == NULL) 15052446042cSArnaldo Carvalho de Melo return -1; 15062446042cSArnaldo Carvalho de Melo 15076671cb16SArnaldo Carvalho de Melo if (use_modules) { 15086671cb16SArnaldo Carvalho de Melo if (dsos__load_modules() < 0) 15096671cb16SArnaldo Carvalho de Melo pr_warning("Failed to load list of modules in use, " 15106671cb16SArnaldo Carvalho de Melo "continuing...\n"); 15116671cb16SArnaldo Carvalho de Melo else if (dsos__load_modules_sym(filter) < 0) 15126671cb16SArnaldo Carvalho de Melo pr_warning("Failed to read module symbols, " 15136671cb16SArnaldo Carvalho de Melo "continuing...\n"); 15146671cb16SArnaldo Carvalho de Melo } 15156671cb16SArnaldo Carvalho de Melo 15166671cb16SArnaldo Carvalho de Melo if (dso__load_kernel_sym(kernel, filter, use_modules) < 0) 15176671cb16SArnaldo Carvalho de Melo pr_warning("Failed to read kernel symbols, continuing...\n"); 15186671cb16SArnaldo Carvalho de Melo 15196671cb16SArnaldo Carvalho de Melo return 0; 1520cd84c2acSFrederic Weisbecker } 1521cd84c2acSFrederic Weisbecker 152200a192b3SArnaldo Carvalho de Melo void symbol__init(unsigned int priv_size) 152386470930SIngo Molnar { 152486470930SIngo Molnar elf_version(EV_CURRENT); 152500a192b3SArnaldo Carvalho de Melo symbol__priv_size = priv_size; 152686470930SIngo Molnar } 1527