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> 12439d473bSArnaldo Carvalho de Melo #include <sys/utsname.h> 132cdbc46dSPeter Zijlstra 1494cb9e38SArnaldo Carvalho de Melo enum dso_origin { 1594cb9e38SArnaldo Carvalho de Melo DSO__ORIG_KERNEL = 0, 1694cb9e38SArnaldo Carvalho de Melo DSO__ORIG_JAVA_JIT, 1794cb9e38SArnaldo Carvalho de Melo DSO__ORIG_FEDORA, 1894cb9e38SArnaldo Carvalho de Melo DSO__ORIG_UBUNTU, 1994cb9e38SArnaldo Carvalho de Melo DSO__ORIG_BUILDID, 2094cb9e38SArnaldo Carvalho de Melo DSO__ORIG_DSO, 21439d473bSArnaldo Carvalho de Melo DSO__ORIG_KMODULE, 2294cb9e38SArnaldo Carvalho de Melo DSO__ORIG_NOT_FOUND, 2394cb9e38SArnaldo Carvalho de Melo }; 2494cb9e38SArnaldo Carvalho de Melo 25439d473bSArnaldo Carvalho de Melo static void dsos__add(struct dso *dso); 26439d473bSArnaldo Carvalho de Melo static struct dso *dsos__find(const char *name); 272e538c4aSArnaldo Carvalho de Melo static struct map *map__new2(u64 start, struct dso *dso); 282e538c4aSArnaldo Carvalho de Melo static void kernel_maps__insert(struct map *map); 2900a192b3SArnaldo Carvalho de Melo unsigned int symbol__priv_size; 30439d473bSArnaldo Carvalho de Melo 31af427bf5SArnaldo Carvalho de Melo static struct rb_root kernel_maps; 32af427bf5SArnaldo Carvalho de Melo 332e538c4aSArnaldo Carvalho de Melo static void dso__fixup_sym_end(struct dso *self) 34af427bf5SArnaldo Carvalho de Melo { 35af427bf5SArnaldo Carvalho de Melo struct rb_node *nd, *prevnd = rb_first(&self->syms); 362e538c4aSArnaldo Carvalho de Melo struct symbol *curr, *prev; 37af427bf5SArnaldo Carvalho de Melo 38af427bf5SArnaldo Carvalho de Melo if (prevnd == NULL) 39af427bf5SArnaldo Carvalho de Melo return; 40af427bf5SArnaldo Carvalho de Melo 412e538c4aSArnaldo Carvalho de Melo curr = rb_entry(prevnd, struct symbol, rb_node); 422e538c4aSArnaldo Carvalho de Melo 43af427bf5SArnaldo Carvalho de Melo for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) { 442e538c4aSArnaldo Carvalho de Melo prev = curr; 452e538c4aSArnaldo Carvalho de Melo curr = rb_entry(nd, struct symbol, rb_node); 46af427bf5SArnaldo Carvalho de Melo 47af427bf5SArnaldo Carvalho de Melo if (prev->end == prev->start) 48af427bf5SArnaldo Carvalho de Melo prev->end = curr->start - 1; 49af427bf5SArnaldo Carvalho de Melo } 50af427bf5SArnaldo Carvalho de Melo 512e538c4aSArnaldo Carvalho de Melo /* Last entry */ 522e538c4aSArnaldo Carvalho de Melo if (curr->end == curr->start) 532e538c4aSArnaldo Carvalho de Melo curr->end = roundup(curr->start, 4096); 542e538c4aSArnaldo Carvalho de Melo } 552e538c4aSArnaldo Carvalho de Melo 562e538c4aSArnaldo Carvalho de Melo static void kernel_maps__fixup_end(void) 57af427bf5SArnaldo Carvalho de Melo { 58af427bf5SArnaldo Carvalho de Melo struct map *prev, *curr; 59af427bf5SArnaldo Carvalho de Melo struct rb_node *nd, *prevnd = rb_first(&kernel_maps); 60af427bf5SArnaldo Carvalho de Melo 61af427bf5SArnaldo Carvalho de Melo if (prevnd == NULL) 62af427bf5SArnaldo Carvalho de Melo return; 63af427bf5SArnaldo Carvalho de Melo 64af427bf5SArnaldo Carvalho de Melo curr = rb_entry(prevnd, struct map, rb_node); 65af427bf5SArnaldo Carvalho de Melo 66af427bf5SArnaldo Carvalho de Melo for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) { 67af427bf5SArnaldo Carvalho de Melo prev = curr; 68af427bf5SArnaldo Carvalho de Melo curr = rb_entry(nd, struct map, rb_node); 69af427bf5SArnaldo Carvalho de Melo prev->end = curr->start - 1; 702e538c4aSArnaldo Carvalho de Melo } 712e538c4aSArnaldo Carvalho de Melo 722e538c4aSArnaldo Carvalho de Melo nd = rb_last(&curr->dso->syms); 732e538c4aSArnaldo Carvalho de Melo if (nd) { 742e538c4aSArnaldo Carvalho de Melo struct symbol *sym = rb_entry(nd, struct symbol, rb_node); 752e538c4aSArnaldo Carvalho de Melo curr->end = sym->end; 76af427bf5SArnaldo Carvalho de Melo } 77af427bf5SArnaldo Carvalho de Melo } 78af427bf5SArnaldo Carvalho de Melo 7900a192b3SArnaldo Carvalho de Melo static struct symbol *symbol__new(u64 start, u64 len, const char *name) 8086470930SIngo Molnar { 8186470930SIngo Molnar size_t namelen = strlen(name) + 1; 8200a192b3SArnaldo Carvalho de Melo struct symbol *self = calloc(1, (symbol__priv_size + 8300a192b3SArnaldo Carvalho de Melo sizeof(*self) + namelen)); 8486470930SIngo Molnar if (!self) 8586470930SIngo Molnar return NULL; 8686470930SIngo Molnar 8700a192b3SArnaldo Carvalho de Melo if (symbol__priv_size) { 8800a192b3SArnaldo Carvalho de Melo memset(self, 0, symbol__priv_size); 8900a192b3SArnaldo Carvalho de Melo self = ((void *)self) + symbol__priv_size; 9086470930SIngo Molnar } 9186470930SIngo Molnar self->start = start; 926cfcc53eSMike Galbraith self->end = len ? start + len - 1 : start; 93e4204992SArnaldo Carvalho de Melo 946beba7adSArnaldo Carvalho de Melo pr_debug3("%s: %s %#Lx-%#Lx\n", __func__, name, start, self->end); 95e4204992SArnaldo Carvalho de Melo 9686470930SIngo Molnar memcpy(self->name, name, namelen); 9786470930SIngo Molnar 9886470930SIngo Molnar return self; 9986470930SIngo Molnar } 10086470930SIngo Molnar 10100a192b3SArnaldo Carvalho de Melo static void symbol__delete(struct symbol *self) 10286470930SIngo Molnar { 10300a192b3SArnaldo Carvalho de Melo free(((void *)self) - symbol__priv_size); 10486470930SIngo Molnar } 10586470930SIngo Molnar 10686470930SIngo Molnar static size_t symbol__fprintf(struct symbol *self, FILE *fp) 10786470930SIngo Molnar { 10886470930SIngo Molnar return fprintf(fp, " %llx-%llx %s\n", 10986470930SIngo Molnar self->start, self->end, self->name); 11086470930SIngo Molnar } 11186470930SIngo Molnar 11200a192b3SArnaldo Carvalho de Melo struct dso *dso__new(const char *name) 11386470930SIngo Molnar { 11486470930SIngo Molnar struct dso *self = malloc(sizeof(*self) + strlen(name) + 1); 11586470930SIngo Molnar 11686470930SIngo Molnar if (self != NULL) { 11786470930SIngo Molnar strcpy(self->name, name); 118439d473bSArnaldo Carvalho de Melo self->long_name = self->name; 119439d473bSArnaldo Carvalho de Melo self->short_name = self->name; 12086470930SIngo Molnar self->syms = RB_ROOT; 12186470930SIngo Molnar self->find_symbol = dso__find_symbol; 12252d422deSArnaldo Carvalho de Melo self->slen_calculated = 0; 12394cb9e38SArnaldo Carvalho de Melo self->origin = DSO__ORIG_NOT_FOUND; 124*8d06367fSArnaldo Carvalho de Melo self->loaded = 0; 125*8d06367fSArnaldo Carvalho de Melo self->has_build_id = 0; 12686470930SIngo Molnar } 12786470930SIngo Molnar 12886470930SIngo Molnar return self; 12986470930SIngo Molnar } 13086470930SIngo Molnar 13186470930SIngo Molnar static void dso__delete_symbols(struct dso *self) 13286470930SIngo Molnar { 13386470930SIngo Molnar struct symbol *pos; 13486470930SIngo Molnar struct rb_node *next = rb_first(&self->syms); 13586470930SIngo Molnar 13686470930SIngo Molnar while (next) { 13786470930SIngo Molnar pos = rb_entry(next, struct symbol, rb_node); 13886470930SIngo Molnar next = rb_next(&pos->rb_node); 13986470930SIngo Molnar rb_erase(&pos->rb_node, &self->syms); 14000a192b3SArnaldo Carvalho de Melo symbol__delete(pos); 14186470930SIngo Molnar } 14286470930SIngo Molnar } 14386470930SIngo Molnar 14486470930SIngo Molnar void dso__delete(struct dso *self) 14586470930SIngo Molnar { 14686470930SIngo Molnar dso__delete_symbols(self); 147439d473bSArnaldo Carvalho de Melo if (self->long_name != self->name) 148439d473bSArnaldo Carvalho de Melo free(self->long_name); 14986470930SIngo Molnar free(self); 15086470930SIngo Molnar } 15186470930SIngo Molnar 152*8d06367fSArnaldo Carvalho de Melo void dso__set_build_id(struct dso *self, void *build_id) 153*8d06367fSArnaldo Carvalho de Melo { 154*8d06367fSArnaldo Carvalho de Melo memcpy(self->build_id, build_id, sizeof(self->build_id)); 155*8d06367fSArnaldo Carvalho de Melo self->has_build_id = 1; 156*8d06367fSArnaldo Carvalho de Melo } 157*8d06367fSArnaldo Carvalho de Melo 15886470930SIngo Molnar static void dso__insert_symbol(struct dso *self, struct symbol *sym) 15986470930SIngo Molnar { 16086470930SIngo Molnar struct rb_node **p = &self->syms.rb_node; 16186470930SIngo Molnar struct rb_node *parent = NULL; 1629cffa8d5SPaul Mackerras const u64 ip = sym->start; 16386470930SIngo Molnar struct symbol *s; 16486470930SIngo Molnar 16586470930SIngo Molnar while (*p != NULL) { 16686470930SIngo Molnar parent = *p; 16786470930SIngo Molnar s = rb_entry(parent, struct symbol, rb_node); 16886470930SIngo Molnar if (ip < s->start) 16986470930SIngo Molnar p = &(*p)->rb_left; 17086470930SIngo Molnar else 17186470930SIngo Molnar p = &(*p)->rb_right; 17286470930SIngo Molnar } 17386470930SIngo Molnar rb_link_node(&sym->rb_node, parent, p); 17486470930SIngo Molnar rb_insert_color(&sym->rb_node, &self->syms); 17586470930SIngo Molnar } 17686470930SIngo Molnar 1779cffa8d5SPaul Mackerras struct symbol *dso__find_symbol(struct dso *self, u64 ip) 17886470930SIngo Molnar { 17986470930SIngo Molnar struct rb_node *n; 18086470930SIngo Molnar 18186470930SIngo Molnar if (self == NULL) 18286470930SIngo Molnar return NULL; 18386470930SIngo Molnar 18486470930SIngo Molnar n = self->syms.rb_node; 18586470930SIngo Molnar 18686470930SIngo Molnar while (n) { 18786470930SIngo Molnar struct symbol *s = rb_entry(n, struct symbol, rb_node); 18886470930SIngo Molnar 18986470930SIngo Molnar if (ip < s->start) 19086470930SIngo Molnar n = n->rb_left; 19186470930SIngo Molnar else if (ip > s->end) 19286470930SIngo Molnar n = n->rb_right; 19386470930SIngo Molnar else 19486470930SIngo Molnar return s; 19586470930SIngo Molnar } 19686470930SIngo Molnar 19786470930SIngo Molnar return NULL; 19886470930SIngo Molnar } 19986470930SIngo Molnar 200*8d06367fSArnaldo Carvalho de Melo int build_id__sprintf(u8 *self, int len, char *bf) 201*8d06367fSArnaldo Carvalho de Melo { 202*8d06367fSArnaldo Carvalho de Melo char *bid = bf; 203*8d06367fSArnaldo Carvalho de Melo u8 *raw = self; 204*8d06367fSArnaldo Carvalho de Melo int i; 205*8d06367fSArnaldo Carvalho de Melo 206*8d06367fSArnaldo Carvalho de Melo for (i = 0; i < len; ++i) { 207*8d06367fSArnaldo Carvalho de Melo sprintf(bid, "%02x", *raw); 208*8d06367fSArnaldo Carvalho de Melo ++raw; 209*8d06367fSArnaldo Carvalho de Melo bid += 2; 210*8d06367fSArnaldo Carvalho de Melo } 211*8d06367fSArnaldo Carvalho de Melo 212*8d06367fSArnaldo Carvalho de Melo return raw - self; 213*8d06367fSArnaldo Carvalho de Melo } 214*8d06367fSArnaldo Carvalho de Melo 21586470930SIngo Molnar size_t dso__fprintf(struct dso *self, FILE *fp) 21686470930SIngo Molnar { 217*8d06367fSArnaldo Carvalho de Melo char sbuild_id[BUILD_ID_SIZE * 2 + 1]; 21886470930SIngo Molnar struct rb_node *nd; 219*8d06367fSArnaldo Carvalho de Melo size_t ret; 220*8d06367fSArnaldo Carvalho de Melo 221*8d06367fSArnaldo Carvalho de Melo build_id__sprintf(self->build_id, sizeof(self->build_id), sbuild_id); 222*8d06367fSArnaldo Carvalho de Melo ret = fprintf(fp, "dso: %s (%s)\n", self->short_name, sbuild_id); 223*8d06367fSArnaldo Carvalho de Melo 22486470930SIngo Molnar for (nd = rb_first(&self->syms); nd; nd = rb_next(nd)) { 22586470930SIngo Molnar struct symbol *pos = rb_entry(nd, struct symbol, rb_node); 22686470930SIngo Molnar ret += symbol__fprintf(pos, fp); 22786470930SIngo Molnar } 22886470930SIngo Molnar 22986470930SIngo Molnar return ret; 23086470930SIngo Molnar } 23186470930SIngo Molnar 2322e538c4aSArnaldo Carvalho de Melo /* 2332e538c4aSArnaldo Carvalho de Melo * Loads the function entries in /proc/kallsyms into kernel_map->dso, 2342e538c4aSArnaldo Carvalho de Melo * so that we can in the next step set the symbol ->end address and then 2352e538c4aSArnaldo Carvalho de Melo * call kernel_maps__split_kallsyms. 2362e538c4aSArnaldo Carvalho de Melo */ 2376beba7adSArnaldo Carvalho de Melo static int kernel_maps__load_all_kallsyms(void) 23886470930SIngo Molnar { 23986470930SIngo Molnar char *line = NULL; 24086470930SIngo Molnar size_t n; 24186470930SIngo Molnar FILE *file = fopen("/proc/kallsyms", "r"); 24286470930SIngo Molnar 24386470930SIngo Molnar if (file == NULL) 24486470930SIngo Molnar goto out_failure; 24586470930SIngo Molnar 24686470930SIngo Molnar while (!feof(file)) { 2479cffa8d5SPaul Mackerras u64 start; 24886470930SIngo Molnar struct symbol *sym; 24986470930SIngo Molnar int line_len, len; 25086470930SIngo Molnar char symbol_type; 2512e538c4aSArnaldo Carvalho de Melo char *symbol_name; 25286470930SIngo Molnar 25386470930SIngo Molnar line_len = getline(&line, &n, file); 25486470930SIngo Molnar if (line_len < 0) 25586470930SIngo Molnar break; 25686470930SIngo Molnar 25786470930SIngo Molnar if (!line) 25886470930SIngo Molnar goto out_failure; 25986470930SIngo Molnar 26086470930SIngo Molnar line[--line_len] = '\0'; /* \n */ 26186470930SIngo Molnar 26286470930SIngo Molnar len = hex2u64(line, &start); 26386470930SIngo Molnar 26486470930SIngo Molnar len++; 26586470930SIngo Molnar if (len + 2 >= line_len) 26686470930SIngo Molnar continue; 26786470930SIngo Molnar 26886470930SIngo Molnar symbol_type = toupper(line[len]); 26986470930SIngo Molnar /* 27086470930SIngo Molnar * We're interested only in code ('T'ext) 27186470930SIngo Molnar */ 27286470930SIngo Molnar if (symbol_type != 'T' && symbol_type != 'W') 27386470930SIngo Molnar continue; 274af427bf5SArnaldo Carvalho de Melo 275af427bf5SArnaldo Carvalho de Melo symbol_name = line + len + 2; 2762e538c4aSArnaldo Carvalho de Melo /* 2772e538c4aSArnaldo Carvalho de Melo * Will fix up the end later, when we have all symbols sorted. 2782e538c4aSArnaldo Carvalho de Melo */ 27900a192b3SArnaldo Carvalho de Melo sym = symbol__new(start, 0, symbol_name); 280af427bf5SArnaldo Carvalho de Melo 2812e538c4aSArnaldo Carvalho de Melo if (sym == NULL) 2822e538c4aSArnaldo Carvalho de Melo goto out_delete_line; 2832e538c4aSArnaldo Carvalho de Melo 2842e538c4aSArnaldo Carvalho de Melo dso__insert_symbol(kernel_map->dso, sym); 2852e538c4aSArnaldo Carvalho de Melo } 2862e538c4aSArnaldo Carvalho de Melo 2872e538c4aSArnaldo Carvalho de Melo free(line); 2882e538c4aSArnaldo Carvalho de Melo fclose(file); 2892e538c4aSArnaldo Carvalho de Melo 2902e538c4aSArnaldo Carvalho de Melo return 0; 2912e538c4aSArnaldo Carvalho de Melo 2922e538c4aSArnaldo Carvalho de Melo out_delete_line: 2932e538c4aSArnaldo Carvalho de Melo free(line); 2942e538c4aSArnaldo Carvalho de Melo out_failure: 2952e538c4aSArnaldo Carvalho de Melo return -1; 2962e538c4aSArnaldo Carvalho de Melo } 2972e538c4aSArnaldo Carvalho de Melo 2982e538c4aSArnaldo Carvalho de Melo /* 2992e538c4aSArnaldo Carvalho de Melo * Split the symbols into maps, making sure there are no overlaps, i.e. the 3002e538c4aSArnaldo Carvalho de Melo * kernel range is broken in several maps, named [kernel].N, as we don't have 3012e538c4aSArnaldo Carvalho de Melo * the original ELF section names vmlinux have. 3022e538c4aSArnaldo Carvalho de Melo */ 3032e538c4aSArnaldo Carvalho de Melo static int kernel_maps__split_kallsyms(symbol_filter_t filter, int use_modules) 3042e538c4aSArnaldo Carvalho de Melo { 3052e538c4aSArnaldo Carvalho de Melo struct map *map = kernel_map; 3062e538c4aSArnaldo Carvalho de Melo struct symbol *pos; 3072e538c4aSArnaldo Carvalho de Melo int count = 0; 3082e538c4aSArnaldo Carvalho de Melo struct rb_node *next = rb_first(&kernel_map->dso->syms); 3092e538c4aSArnaldo Carvalho de Melo int kernel_range = 0; 3102e538c4aSArnaldo Carvalho de Melo 3112e538c4aSArnaldo Carvalho de Melo while (next) { 3122e538c4aSArnaldo Carvalho de Melo char *module; 3132e538c4aSArnaldo Carvalho de Melo 3142e538c4aSArnaldo Carvalho de Melo pos = rb_entry(next, struct symbol, rb_node); 3152e538c4aSArnaldo Carvalho de Melo next = rb_next(&pos->rb_node); 3162e538c4aSArnaldo Carvalho de Melo 3172e538c4aSArnaldo Carvalho de Melo module = strchr(pos->name, '\t'); 3182e538c4aSArnaldo Carvalho de Melo if (module) { 319af427bf5SArnaldo Carvalho de Melo if (!use_modules) 3202e538c4aSArnaldo Carvalho de Melo goto delete_symbol; 3212e538c4aSArnaldo Carvalho de Melo 3222e538c4aSArnaldo Carvalho de Melo *module++ = '\0'; 3232e538c4aSArnaldo Carvalho de Melo 324af427bf5SArnaldo Carvalho de Melo if (strcmp(map->dso->name, module)) { 325af427bf5SArnaldo Carvalho de Melo map = kernel_maps__find_by_dso_name(module); 326af427bf5SArnaldo Carvalho de Melo if (!map) { 3276beba7adSArnaldo Carvalho de Melo pr_err("/proc/{kallsyms,modules} " 3286beba7adSArnaldo Carvalho de Melo "inconsistency!\n"); 329af427bf5SArnaldo Carvalho de Melo return -1; 330af427bf5SArnaldo Carvalho de Melo } 331af427bf5SArnaldo Carvalho de Melo } 33286470930SIngo Molnar /* 3332e538c4aSArnaldo Carvalho de Melo * So that we look just like we get from .ko files, 3342e538c4aSArnaldo Carvalho de Melo * i.e. not prelinked, relative to map->start. 33586470930SIngo Molnar */ 3362e538c4aSArnaldo Carvalho de Melo pos->start = map->map_ip(map, pos->start); 3372e538c4aSArnaldo Carvalho de Melo pos->end = map->map_ip(map, pos->end); 3382e538c4aSArnaldo Carvalho de Melo } else if (map != kernel_map) { 3392e538c4aSArnaldo Carvalho de Melo char dso_name[PATH_MAX]; 3402e538c4aSArnaldo Carvalho de Melo struct dso *dso; 34186470930SIngo Molnar 3422e538c4aSArnaldo Carvalho de Melo snprintf(dso_name, sizeof(dso_name), "[kernel].%d", 3432e538c4aSArnaldo Carvalho de Melo kernel_range++); 34486470930SIngo Molnar 34500a192b3SArnaldo Carvalho de Melo dso = dso__new(dso_name); 3462e538c4aSArnaldo Carvalho de Melo if (dso == NULL) 3472e538c4aSArnaldo Carvalho de Melo return -1; 3482e538c4aSArnaldo Carvalho de Melo 3492e538c4aSArnaldo Carvalho de Melo map = map__new2(pos->start, dso); 3502e538c4aSArnaldo Carvalho de Melo if (map == NULL) { 3512e538c4aSArnaldo Carvalho de Melo dso__delete(dso); 3522e538c4aSArnaldo Carvalho de Melo return -1; 3532e538c4aSArnaldo Carvalho de Melo } 3542e538c4aSArnaldo Carvalho de Melo 355ed52ce2eSArnaldo Carvalho de Melo map->map_ip = map->unmap_ip = identity__map_ip; 3562e538c4aSArnaldo Carvalho de Melo kernel_maps__insert(map); 3572e538c4aSArnaldo Carvalho de Melo ++kernel_range; 3582e538c4aSArnaldo Carvalho de Melo } 3592e538c4aSArnaldo Carvalho de Melo 3602e538c4aSArnaldo Carvalho de Melo if (filter && filter(map, pos)) { 3612e538c4aSArnaldo Carvalho de Melo delete_symbol: 3622e538c4aSArnaldo Carvalho de Melo rb_erase(&pos->rb_node, &kernel_map->dso->syms); 36300a192b3SArnaldo Carvalho de Melo symbol__delete(pos); 3642e538c4aSArnaldo Carvalho de Melo } else { 3652e538c4aSArnaldo Carvalho de Melo if (map != kernel_map) { 3662e538c4aSArnaldo Carvalho de Melo rb_erase(&pos->rb_node, &kernel_map->dso->syms); 3672e538c4aSArnaldo Carvalho de Melo dso__insert_symbol(map->dso, pos); 3682e538c4aSArnaldo Carvalho de Melo } 3699974f496SMike Galbraith count++; 3709974f496SMike Galbraith } 37186470930SIngo Molnar } 37286470930SIngo Molnar 3739974f496SMike Galbraith return count; 37486470930SIngo Molnar } 37586470930SIngo Molnar 3762e538c4aSArnaldo Carvalho de Melo 3776beba7adSArnaldo Carvalho de Melo static int kernel_maps__load_kallsyms(symbol_filter_t filter, int use_modules) 3782e538c4aSArnaldo Carvalho de Melo { 3796beba7adSArnaldo Carvalho de Melo if (kernel_maps__load_all_kallsyms()) 3802e538c4aSArnaldo Carvalho de Melo return -1; 3812e538c4aSArnaldo Carvalho de Melo 3822e538c4aSArnaldo Carvalho de Melo dso__fixup_sym_end(kernel_map->dso); 3832e538c4aSArnaldo Carvalho de Melo 3842e538c4aSArnaldo Carvalho de Melo return kernel_maps__split_kallsyms(filter, use_modules); 3852e538c4aSArnaldo Carvalho de Melo } 3862e538c4aSArnaldo Carvalho de Melo 3876beba7adSArnaldo Carvalho de Melo static size_t kernel_maps__fprintf(FILE *fp) 388af427bf5SArnaldo Carvalho de Melo { 3896beba7adSArnaldo Carvalho de Melo size_t printed = fprintf(fp, "Kernel maps:\n"); 390af427bf5SArnaldo Carvalho de Melo struct rb_node *nd; 391af427bf5SArnaldo Carvalho de Melo 392af427bf5SArnaldo Carvalho de Melo for (nd = rb_first(&kernel_maps); nd; nd = rb_next(nd)) { 393af427bf5SArnaldo Carvalho de Melo struct map *pos = rb_entry(nd, struct map, rb_node); 394af427bf5SArnaldo Carvalho de Melo 3952e538c4aSArnaldo Carvalho de Melo printed += fprintf(fp, "Map:"); 396af427bf5SArnaldo Carvalho de Melo printed += map__fprintf(pos, fp); 3976beba7adSArnaldo Carvalho de Melo if (verbose > 1) { 398af427bf5SArnaldo Carvalho de Melo printed += dso__fprintf(pos->dso, fp); 3992e538c4aSArnaldo Carvalho de Melo printed += fprintf(fp, "--\n"); 4002e538c4aSArnaldo Carvalho de Melo } 401af427bf5SArnaldo Carvalho de Melo } 402af427bf5SArnaldo Carvalho de Melo 4036beba7adSArnaldo Carvalho de Melo return printed + fprintf(fp, "END kernel maps\n"); 404af427bf5SArnaldo Carvalho de Melo } 405af427bf5SArnaldo Carvalho de Melo 406439d473bSArnaldo Carvalho de Melo static int dso__load_perf_map(struct dso *self, struct map *map, 4076beba7adSArnaldo Carvalho de Melo symbol_filter_t filter) 40880d496beSPekka Enberg { 40980d496beSPekka Enberg char *line = NULL; 41080d496beSPekka Enberg size_t n; 41180d496beSPekka Enberg FILE *file; 41280d496beSPekka Enberg int nr_syms = 0; 41380d496beSPekka Enberg 414439d473bSArnaldo Carvalho de Melo file = fopen(self->long_name, "r"); 41580d496beSPekka Enberg if (file == NULL) 41680d496beSPekka Enberg goto out_failure; 41780d496beSPekka Enberg 41880d496beSPekka Enberg while (!feof(file)) { 4199cffa8d5SPaul Mackerras u64 start, size; 42080d496beSPekka Enberg struct symbol *sym; 42180d496beSPekka Enberg int line_len, len; 42280d496beSPekka Enberg 42380d496beSPekka Enberg line_len = getline(&line, &n, file); 42480d496beSPekka Enberg if (line_len < 0) 42580d496beSPekka Enberg break; 42680d496beSPekka Enberg 42780d496beSPekka Enberg if (!line) 42880d496beSPekka Enberg goto out_failure; 42980d496beSPekka Enberg 43080d496beSPekka Enberg line[--line_len] = '\0'; /* \n */ 43180d496beSPekka Enberg 43280d496beSPekka Enberg len = hex2u64(line, &start); 43380d496beSPekka Enberg 43480d496beSPekka Enberg len++; 43580d496beSPekka Enberg if (len + 2 >= line_len) 43680d496beSPekka Enberg continue; 43780d496beSPekka Enberg 43880d496beSPekka Enberg len += hex2u64(line + len, &size); 43980d496beSPekka Enberg 44080d496beSPekka Enberg len++; 44180d496beSPekka Enberg if (len + 2 >= line_len) 44280d496beSPekka Enberg continue; 44380d496beSPekka Enberg 44400a192b3SArnaldo Carvalho de Melo sym = symbol__new(start, size, line + len); 44580d496beSPekka Enberg 44680d496beSPekka Enberg if (sym == NULL) 44780d496beSPekka Enberg goto out_delete_line; 44880d496beSPekka Enberg 449439d473bSArnaldo Carvalho de Melo if (filter && filter(map, sym)) 45000a192b3SArnaldo Carvalho de Melo symbol__delete(sym); 45180d496beSPekka Enberg else { 45280d496beSPekka Enberg dso__insert_symbol(self, sym); 45380d496beSPekka Enberg nr_syms++; 45480d496beSPekka Enberg } 45580d496beSPekka Enberg } 45680d496beSPekka Enberg 45780d496beSPekka Enberg free(line); 45880d496beSPekka Enberg fclose(file); 45980d496beSPekka Enberg 46080d496beSPekka Enberg return nr_syms; 46180d496beSPekka Enberg 46280d496beSPekka Enberg out_delete_line: 46380d496beSPekka Enberg free(line); 46480d496beSPekka Enberg out_failure: 46580d496beSPekka Enberg return -1; 46680d496beSPekka Enberg } 46780d496beSPekka Enberg 46886470930SIngo Molnar /** 46986470930SIngo Molnar * elf_symtab__for_each_symbol - iterate thru all the symbols 47086470930SIngo Molnar * 47186470930SIngo Molnar * @self: struct elf_symtab instance to iterate 47283a0944fSIngo Molnar * @idx: uint32_t idx 47386470930SIngo Molnar * @sym: GElf_Sym iterator 47486470930SIngo Molnar */ 47583a0944fSIngo Molnar #define elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) \ 47683a0944fSIngo Molnar for (idx = 0, gelf_getsym(syms, idx, &sym);\ 47783a0944fSIngo Molnar idx < nr_syms; \ 47883a0944fSIngo Molnar idx++, gelf_getsym(syms, idx, &sym)) 47986470930SIngo Molnar 48086470930SIngo Molnar static inline uint8_t elf_sym__type(const GElf_Sym *sym) 48186470930SIngo Molnar { 48286470930SIngo Molnar return GELF_ST_TYPE(sym->st_info); 48386470930SIngo Molnar } 48486470930SIngo Molnar 48586470930SIngo Molnar static inline int elf_sym__is_function(const GElf_Sym *sym) 48686470930SIngo Molnar { 48786470930SIngo Molnar return elf_sym__type(sym) == STT_FUNC && 48886470930SIngo Molnar sym->st_name != 0 && 48981833130SArnaldo Carvalho de Melo sym->st_shndx != SHN_UNDEF; 49086470930SIngo Molnar } 49186470930SIngo Molnar 4926cfcc53eSMike Galbraith static inline int elf_sym__is_label(const GElf_Sym *sym) 4936cfcc53eSMike Galbraith { 4946cfcc53eSMike Galbraith return elf_sym__type(sym) == STT_NOTYPE && 4956cfcc53eSMike Galbraith sym->st_name != 0 && 4966cfcc53eSMike Galbraith sym->st_shndx != SHN_UNDEF && 4976cfcc53eSMike Galbraith sym->st_shndx != SHN_ABS; 4986cfcc53eSMike Galbraith } 4996cfcc53eSMike Galbraith 5006cfcc53eSMike Galbraith static inline const char *elf_sec__name(const GElf_Shdr *shdr, 5016cfcc53eSMike Galbraith const Elf_Data *secstrs) 5026cfcc53eSMike Galbraith { 5036cfcc53eSMike Galbraith return secstrs->d_buf + shdr->sh_name; 5046cfcc53eSMike Galbraith } 5056cfcc53eSMike Galbraith 5066cfcc53eSMike Galbraith static inline int elf_sec__is_text(const GElf_Shdr *shdr, 5076cfcc53eSMike Galbraith const Elf_Data *secstrs) 5086cfcc53eSMike Galbraith { 5096cfcc53eSMike Galbraith return strstr(elf_sec__name(shdr, secstrs), "text") != NULL; 5106cfcc53eSMike Galbraith } 5116cfcc53eSMike Galbraith 51286470930SIngo Molnar static inline const char *elf_sym__name(const GElf_Sym *sym, 51386470930SIngo Molnar const Elf_Data *symstrs) 51486470930SIngo Molnar { 51586470930SIngo Molnar return symstrs->d_buf + sym->st_name; 51686470930SIngo Molnar } 51786470930SIngo Molnar 51886470930SIngo Molnar static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, 51986470930SIngo Molnar GElf_Shdr *shp, const char *name, 52083a0944fSIngo Molnar size_t *idx) 52186470930SIngo Molnar { 52286470930SIngo Molnar Elf_Scn *sec = NULL; 52386470930SIngo Molnar size_t cnt = 1; 52486470930SIngo Molnar 52586470930SIngo Molnar while ((sec = elf_nextscn(elf, sec)) != NULL) { 52686470930SIngo Molnar char *str; 52786470930SIngo Molnar 52886470930SIngo Molnar gelf_getshdr(sec, shp); 52986470930SIngo Molnar str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name); 53086470930SIngo Molnar if (!strcmp(name, str)) { 53183a0944fSIngo Molnar if (idx) 53283a0944fSIngo Molnar *idx = cnt; 53386470930SIngo Molnar break; 53486470930SIngo Molnar } 53586470930SIngo Molnar ++cnt; 53686470930SIngo Molnar } 53786470930SIngo Molnar 53886470930SIngo Molnar return sec; 53986470930SIngo Molnar } 54086470930SIngo Molnar 54186470930SIngo Molnar #define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \ 54286470930SIngo Molnar for (idx = 0, pos = gelf_getrel(reldata, 0, &pos_mem); \ 54386470930SIngo Molnar idx < nr_entries; \ 54486470930SIngo Molnar ++idx, pos = gelf_getrel(reldata, idx, &pos_mem)) 54586470930SIngo Molnar 54686470930SIngo Molnar #define elf_section__for_each_rela(reldata, pos, pos_mem, idx, nr_entries) \ 54786470930SIngo Molnar for (idx = 0, pos = gelf_getrela(reldata, 0, &pos_mem); \ 54886470930SIngo Molnar idx < nr_entries; \ 54986470930SIngo Molnar ++idx, pos = gelf_getrela(reldata, idx, &pos_mem)) 55086470930SIngo Molnar 551a25e46c4SArnaldo Carvalho de Melo /* 552a25e46c4SArnaldo Carvalho de Melo * We need to check if we have a .dynsym, so that we can handle the 553a25e46c4SArnaldo Carvalho de Melo * .plt, synthesizing its symbols, that aren't on the symtabs (be it 554a25e46c4SArnaldo Carvalho de Melo * .dynsym or .symtab). 555a25e46c4SArnaldo Carvalho de Melo * And always look at the original dso, not at debuginfo packages, that 556a25e46c4SArnaldo Carvalho de Melo * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS). 557a25e46c4SArnaldo Carvalho de Melo */ 5586beba7adSArnaldo Carvalho de Melo static int dso__synthesize_plt_symbols(struct dso *self) 55986470930SIngo Molnar { 56086470930SIngo Molnar uint32_t nr_rel_entries, idx; 56186470930SIngo Molnar GElf_Sym sym; 5629cffa8d5SPaul Mackerras u64 plt_offset; 56386470930SIngo Molnar GElf_Shdr shdr_plt; 56486470930SIngo Molnar struct symbol *f; 565a25e46c4SArnaldo Carvalho de Melo GElf_Shdr shdr_rel_plt, shdr_dynsym; 56686470930SIngo Molnar Elf_Data *reldata, *syms, *symstrs; 567a25e46c4SArnaldo Carvalho de Melo Elf_Scn *scn_plt_rel, *scn_symstrs, *scn_dynsym; 568a25e46c4SArnaldo Carvalho de Melo size_t dynsym_idx; 569a25e46c4SArnaldo Carvalho de Melo GElf_Ehdr ehdr; 57086470930SIngo Molnar char sympltname[1024]; 571a25e46c4SArnaldo Carvalho de Melo Elf *elf; 572a25e46c4SArnaldo Carvalho de Melo int nr = 0, symidx, fd, err = 0; 57386470930SIngo Molnar 574439d473bSArnaldo Carvalho de Melo fd = open(self->long_name, O_RDONLY); 575a25e46c4SArnaldo Carvalho de Melo if (fd < 0) 576a25e46c4SArnaldo Carvalho de Melo goto out; 577a25e46c4SArnaldo Carvalho de Melo 57884087126SMarti Raudsepp elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 579a25e46c4SArnaldo Carvalho de Melo if (elf == NULL) 580a25e46c4SArnaldo Carvalho de Melo goto out_close; 581a25e46c4SArnaldo Carvalho de Melo 582a25e46c4SArnaldo Carvalho de Melo if (gelf_getehdr(elf, &ehdr) == NULL) 583a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 584a25e46c4SArnaldo Carvalho de Melo 585a25e46c4SArnaldo Carvalho de Melo scn_dynsym = elf_section_by_name(elf, &ehdr, &shdr_dynsym, 586a25e46c4SArnaldo Carvalho de Melo ".dynsym", &dynsym_idx); 587a25e46c4SArnaldo Carvalho de Melo if (scn_dynsym == NULL) 588a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 589a25e46c4SArnaldo Carvalho de Melo 590a25e46c4SArnaldo Carvalho de Melo scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt, 59186470930SIngo Molnar ".rela.plt", NULL); 59286470930SIngo Molnar if (scn_plt_rel == NULL) { 593a25e46c4SArnaldo Carvalho de Melo scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt, 59486470930SIngo Molnar ".rel.plt", NULL); 59586470930SIngo Molnar if (scn_plt_rel == NULL) 596a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 59786470930SIngo Molnar } 59886470930SIngo Molnar 599a25e46c4SArnaldo Carvalho de Melo err = -1; 60086470930SIngo Molnar 601a25e46c4SArnaldo Carvalho de Melo if (shdr_rel_plt.sh_link != dynsym_idx) 602a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 603a25e46c4SArnaldo Carvalho de Melo 604a25e46c4SArnaldo Carvalho de Melo if (elf_section_by_name(elf, &ehdr, &shdr_plt, ".plt", NULL) == NULL) 605a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 60686470930SIngo Molnar 60786470930SIngo Molnar /* 60883a0944fSIngo Molnar * Fetch the relocation section to find the idxes to the GOT 60986470930SIngo Molnar * and the symbols in the .dynsym they refer to. 61086470930SIngo Molnar */ 61186470930SIngo Molnar reldata = elf_getdata(scn_plt_rel, NULL); 61286470930SIngo Molnar if (reldata == NULL) 613a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 61486470930SIngo Molnar 61586470930SIngo Molnar syms = elf_getdata(scn_dynsym, NULL); 61686470930SIngo Molnar if (syms == NULL) 617a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 61886470930SIngo Molnar 619a25e46c4SArnaldo Carvalho de Melo scn_symstrs = elf_getscn(elf, shdr_dynsym.sh_link); 62086470930SIngo Molnar if (scn_symstrs == NULL) 621a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 62286470930SIngo Molnar 62386470930SIngo Molnar symstrs = elf_getdata(scn_symstrs, NULL); 62486470930SIngo Molnar if (symstrs == NULL) 625a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 62686470930SIngo Molnar 62786470930SIngo Molnar nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize; 62886470930SIngo Molnar plt_offset = shdr_plt.sh_offset; 62986470930SIngo Molnar 63086470930SIngo Molnar if (shdr_rel_plt.sh_type == SHT_RELA) { 63186470930SIngo Molnar GElf_Rela pos_mem, *pos; 63286470930SIngo Molnar 63386470930SIngo Molnar elf_section__for_each_rela(reldata, pos, pos_mem, idx, 63486470930SIngo Molnar nr_rel_entries) { 63586470930SIngo Molnar symidx = GELF_R_SYM(pos->r_info); 63686470930SIngo Molnar plt_offset += shdr_plt.sh_entsize; 63786470930SIngo Molnar gelf_getsym(syms, symidx, &sym); 63886470930SIngo Molnar snprintf(sympltname, sizeof(sympltname), 63986470930SIngo Molnar "%s@plt", elf_sym__name(&sym, symstrs)); 64086470930SIngo Molnar 64186470930SIngo Molnar f = symbol__new(plt_offset, shdr_plt.sh_entsize, 64200a192b3SArnaldo Carvalho de Melo sympltname); 64386470930SIngo Molnar if (!f) 644a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 64586470930SIngo Molnar 64686470930SIngo Molnar dso__insert_symbol(self, f); 64786470930SIngo Molnar ++nr; 64886470930SIngo Molnar } 64986470930SIngo Molnar } else if (shdr_rel_plt.sh_type == SHT_REL) { 65086470930SIngo Molnar GElf_Rel pos_mem, *pos; 65186470930SIngo Molnar elf_section__for_each_rel(reldata, pos, pos_mem, idx, 65286470930SIngo Molnar nr_rel_entries) { 65386470930SIngo Molnar symidx = GELF_R_SYM(pos->r_info); 65486470930SIngo Molnar plt_offset += shdr_plt.sh_entsize; 65586470930SIngo Molnar gelf_getsym(syms, symidx, &sym); 65686470930SIngo Molnar snprintf(sympltname, sizeof(sympltname), 65786470930SIngo Molnar "%s@plt", elf_sym__name(&sym, symstrs)); 65886470930SIngo Molnar 65986470930SIngo Molnar f = symbol__new(plt_offset, shdr_plt.sh_entsize, 66000a192b3SArnaldo Carvalho de Melo sympltname); 66186470930SIngo Molnar if (!f) 662a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 66386470930SIngo Molnar 66486470930SIngo Molnar dso__insert_symbol(self, f); 66586470930SIngo Molnar ++nr; 66686470930SIngo Molnar } 66786470930SIngo Molnar } 66886470930SIngo Molnar 669a25e46c4SArnaldo Carvalho de Melo err = 0; 670a25e46c4SArnaldo Carvalho de Melo out_elf_end: 671a25e46c4SArnaldo Carvalho de Melo elf_end(elf); 672a25e46c4SArnaldo Carvalho de Melo out_close: 673a25e46c4SArnaldo Carvalho de Melo close(fd); 674a25e46c4SArnaldo Carvalho de Melo 675a25e46c4SArnaldo Carvalho de Melo if (err == 0) 67686470930SIngo Molnar return nr; 677a25e46c4SArnaldo Carvalho de Melo out: 6786beba7adSArnaldo Carvalho de Melo pr_warning("%s: problems reading %s PLT info.\n", 679439d473bSArnaldo Carvalho de Melo __func__, self->long_name); 680a25e46c4SArnaldo Carvalho de Melo return 0; 68186470930SIngo Molnar } 68286470930SIngo Molnar 683439d473bSArnaldo Carvalho de Melo static int dso__load_sym(struct dso *self, struct map *map, const char *name, 684439d473bSArnaldo Carvalho de Melo int fd, symbol_filter_t filter, int kernel, 6856beba7adSArnaldo Carvalho de Melo int kmodule) 68686470930SIngo Molnar { 6872e538c4aSArnaldo Carvalho de Melo struct map *curr_map = map; 6882e538c4aSArnaldo Carvalho de Melo struct dso *curr_dso = self; 6892e538c4aSArnaldo Carvalho de Melo size_t dso_name_len = strlen(self->short_name); 6906cfcc53eSMike Galbraith Elf_Data *symstrs, *secstrs; 69186470930SIngo Molnar uint32_t nr_syms; 69286470930SIngo Molnar int err = -1; 69383a0944fSIngo Molnar uint32_t idx; 69486470930SIngo Molnar GElf_Ehdr ehdr; 69586470930SIngo Molnar GElf_Shdr shdr; 69686470930SIngo Molnar Elf_Data *syms; 69786470930SIngo Molnar GElf_Sym sym; 698a25e46c4SArnaldo Carvalho de Melo Elf_Scn *sec, *sec_strndx; 69986470930SIngo Molnar Elf *elf; 700439d473bSArnaldo Carvalho de Melo int nr = 0; 70186470930SIngo Molnar 70284087126SMarti Raudsepp elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 70386470930SIngo Molnar if (elf == NULL) { 7046beba7adSArnaldo Carvalho de Melo pr_err("%s: cannot read %s ELF file.\n", __func__, name); 70586470930SIngo Molnar goto out_close; 70686470930SIngo Molnar } 70786470930SIngo Molnar 70886470930SIngo Molnar if (gelf_getehdr(elf, &ehdr) == NULL) { 7096beba7adSArnaldo Carvalho de Melo pr_err("%s: cannot get elf header.\n", __func__); 71086470930SIngo Molnar goto out_elf_end; 71186470930SIngo Molnar } 71286470930SIngo Molnar 71386470930SIngo Molnar sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL); 71486470930SIngo Molnar if (sec == NULL) { 715a25e46c4SArnaldo Carvalho de Melo sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL); 716a25e46c4SArnaldo Carvalho de Melo if (sec == NULL) 71786470930SIngo Molnar goto out_elf_end; 71886470930SIngo Molnar } 71986470930SIngo Molnar 72086470930SIngo Molnar syms = elf_getdata(sec, NULL); 72186470930SIngo Molnar if (syms == NULL) 72286470930SIngo Molnar goto out_elf_end; 72386470930SIngo Molnar 72486470930SIngo Molnar sec = elf_getscn(elf, shdr.sh_link); 72586470930SIngo Molnar if (sec == NULL) 72686470930SIngo Molnar goto out_elf_end; 72786470930SIngo Molnar 72886470930SIngo Molnar symstrs = elf_getdata(sec, NULL); 72986470930SIngo Molnar if (symstrs == NULL) 73086470930SIngo Molnar goto out_elf_end; 73186470930SIngo Molnar 7326cfcc53eSMike Galbraith sec_strndx = elf_getscn(elf, ehdr.e_shstrndx); 7336cfcc53eSMike Galbraith if (sec_strndx == NULL) 7346cfcc53eSMike Galbraith goto out_elf_end; 7356cfcc53eSMike Galbraith 7366cfcc53eSMike Galbraith secstrs = elf_getdata(sec_strndx, NULL); 7379b30a26bSStoyan Gaydarov if (secstrs == NULL) 7386cfcc53eSMike Galbraith goto out_elf_end; 7396cfcc53eSMike Galbraith 74086470930SIngo Molnar nr_syms = shdr.sh_size / shdr.sh_entsize; 74186470930SIngo Molnar 742e9fbc9dcSArjan van de Ven memset(&sym, 0, sizeof(sym)); 743d20ff6bdSMike Galbraith if (!kernel) { 74430d7a77dSArnaldo Carvalho de Melo self->adjust_symbols = (ehdr.e_type == ET_EXEC || 74530d7a77dSArnaldo Carvalho de Melo elf_section_by_name(elf, &ehdr, &shdr, 746f5812a7aSArnaldo Carvalho de Melo ".gnu.prelink_undo", 74730d7a77dSArnaldo Carvalho de Melo NULL) != NULL); 748d20ff6bdSMike Galbraith } else self->adjust_symbols = 0; 749d20ff6bdSMike Galbraith 75083a0944fSIngo Molnar elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) { 75186470930SIngo Molnar struct symbol *f; 75283a0944fSIngo Molnar const char *elf_name; 7532e538c4aSArnaldo Carvalho de Melo char *demangled = NULL; 7546cfcc53eSMike Galbraith int is_label = elf_sym__is_label(&sym); 7556cfcc53eSMike Galbraith const char *section_name; 75686470930SIngo Molnar 7576cfcc53eSMike Galbraith if (!is_label && !elf_sym__is_function(&sym)) 75886470930SIngo Molnar continue; 75986470930SIngo Molnar 76086470930SIngo Molnar sec = elf_getscn(elf, sym.st_shndx); 76186470930SIngo Molnar if (!sec) 76286470930SIngo Molnar goto out_elf_end; 76386470930SIngo Molnar 76486470930SIngo Molnar gelf_getshdr(sec, &shdr); 7656cfcc53eSMike Galbraith 7666cfcc53eSMike Galbraith if (is_label && !elf_sec__is_text(&shdr, secstrs)) 7676cfcc53eSMike Galbraith continue; 7686cfcc53eSMike Galbraith 7692e538c4aSArnaldo Carvalho de Melo elf_name = elf_sym__name(&sym, symstrs); 7706cfcc53eSMike Galbraith section_name = elf_sec__name(&shdr, secstrs); 77186470930SIngo Molnar 7722e538c4aSArnaldo Carvalho de Melo if (kernel || kmodule) { 7732e538c4aSArnaldo Carvalho de Melo char dso_name[PATH_MAX]; 7742e538c4aSArnaldo Carvalho de Melo 7752e538c4aSArnaldo Carvalho de Melo if (strcmp(section_name, 7762e538c4aSArnaldo Carvalho de Melo curr_dso->short_name + dso_name_len) == 0) 7772e538c4aSArnaldo Carvalho de Melo goto new_symbol; 7782e538c4aSArnaldo Carvalho de Melo 7792e538c4aSArnaldo Carvalho de Melo if (strcmp(section_name, ".text") == 0) { 7802e538c4aSArnaldo Carvalho de Melo curr_map = map; 7812e538c4aSArnaldo Carvalho de Melo curr_dso = self; 7822e538c4aSArnaldo Carvalho de Melo goto new_symbol; 783af427bf5SArnaldo Carvalho de Melo } 784af427bf5SArnaldo Carvalho de Melo 7852e538c4aSArnaldo Carvalho de Melo snprintf(dso_name, sizeof(dso_name), 7862e538c4aSArnaldo Carvalho de Melo "%s%s", self->short_name, section_name); 7872e538c4aSArnaldo Carvalho de Melo 7882e538c4aSArnaldo Carvalho de Melo curr_map = kernel_maps__find_by_dso_name(dso_name); 7892e538c4aSArnaldo Carvalho de Melo if (curr_map == NULL) { 7902e538c4aSArnaldo Carvalho de Melo u64 start = sym.st_value; 7912e538c4aSArnaldo Carvalho de Melo 7922e538c4aSArnaldo Carvalho de Melo if (kmodule) 7932e538c4aSArnaldo Carvalho de Melo start += map->start + shdr.sh_offset; 7942e538c4aSArnaldo Carvalho de Melo 79500a192b3SArnaldo Carvalho de Melo curr_dso = dso__new(dso_name); 7962e538c4aSArnaldo Carvalho de Melo if (curr_dso == NULL) 7972e538c4aSArnaldo Carvalho de Melo goto out_elf_end; 7982e538c4aSArnaldo Carvalho de Melo curr_map = map__new2(start, curr_dso); 7992e538c4aSArnaldo Carvalho de Melo if (curr_map == NULL) { 8002e538c4aSArnaldo Carvalho de Melo dso__delete(curr_dso); 8012e538c4aSArnaldo Carvalho de Melo goto out_elf_end; 8022e538c4aSArnaldo Carvalho de Melo } 803ed52ce2eSArnaldo Carvalho de Melo curr_map->map_ip = identity__map_ip; 804ed52ce2eSArnaldo Carvalho de Melo curr_map->unmap_ip = identity__map_ip; 8052e538c4aSArnaldo Carvalho de Melo curr_dso->origin = DSO__ORIG_KERNEL; 8062e538c4aSArnaldo Carvalho de Melo kernel_maps__insert(curr_map); 8072e538c4aSArnaldo Carvalho de Melo dsos__add(curr_dso); 8082e538c4aSArnaldo Carvalho de Melo } else 8092e538c4aSArnaldo Carvalho de Melo curr_dso = curr_map->dso; 8102e538c4aSArnaldo Carvalho de Melo 8112e538c4aSArnaldo Carvalho de Melo goto new_symbol; 8122e538c4aSArnaldo Carvalho de Melo } 8132e538c4aSArnaldo Carvalho de Melo 8142e538c4aSArnaldo Carvalho de Melo if (curr_dso->adjust_symbols) { 8156beba7adSArnaldo Carvalho de Melo pr_debug2("adjusting symbol: st_value: %Lx sh_addr: " 8166beba7adSArnaldo Carvalho de Melo "%Lx sh_offset: %Lx\n", (u64)sym.st_value, 8176beba7adSArnaldo Carvalho de Melo (u64)shdr.sh_addr, (u64)shdr.sh_offset); 81886470930SIngo Molnar sym.st_value -= shdr.sh_addr - shdr.sh_offset; 819af427bf5SArnaldo Carvalho de Melo } 82028ac909bSArnaldo Carvalho de Melo /* 82128ac909bSArnaldo Carvalho de Melo * We need to figure out if the object was created from C++ sources 82228ac909bSArnaldo Carvalho de Melo * DWARF DW_compile_unit has this, but we don't always have access 82328ac909bSArnaldo Carvalho de Melo * to it... 82428ac909bSArnaldo Carvalho de Melo */ 82583a0944fSIngo Molnar demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI); 82628ac909bSArnaldo Carvalho de Melo if (demangled != NULL) 82783a0944fSIngo Molnar elf_name = demangled; 8282e538c4aSArnaldo Carvalho de Melo new_symbol: 82900a192b3SArnaldo Carvalho de Melo f = symbol__new(sym.st_value, sym.st_size, elf_name); 83028ac909bSArnaldo Carvalho de Melo free(demangled); 83186470930SIngo Molnar if (!f) 83286470930SIngo Molnar goto out_elf_end; 83386470930SIngo Molnar 8342e538c4aSArnaldo Carvalho de Melo if (filter && filter(curr_map, f)) 83500a192b3SArnaldo Carvalho de Melo symbol__delete(f); 83686470930SIngo Molnar else { 8372e538c4aSArnaldo Carvalho de Melo dso__insert_symbol(curr_dso, f); 83886470930SIngo Molnar nr++; 83986470930SIngo Molnar } 84086470930SIngo Molnar } 84186470930SIngo Molnar 8422e538c4aSArnaldo Carvalho de Melo /* 8432e538c4aSArnaldo Carvalho de Melo * For misannotated, zeroed, ASM function sizes. 8442e538c4aSArnaldo Carvalho de Melo */ 8452e538c4aSArnaldo Carvalho de Melo if (nr > 0) 8462e538c4aSArnaldo Carvalho de Melo dso__fixup_sym_end(self); 84786470930SIngo Molnar err = nr; 84886470930SIngo Molnar out_elf_end: 84986470930SIngo Molnar elf_end(elf); 85086470930SIngo Molnar out_close: 85186470930SIngo Molnar return err; 85286470930SIngo Molnar } 85386470930SIngo Molnar 8542643ce11SArnaldo Carvalho de Melo int filename__read_build_id(const char *filename, void *bf, size_t size) 8554d1e00a8SArnaldo Carvalho de Melo { 8562643ce11SArnaldo Carvalho de Melo int fd, err = -1; 8574d1e00a8SArnaldo Carvalho de Melo GElf_Ehdr ehdr; 8584d1e00a8SArnaldo Carvalho de Melo GElf_Shdr shdr; 8594d1e00a8SArnaldo Carvalho de Melo Elf_Data *build_id_data; 8604d1e00a8SArnaldo Carvalho de Melo Elf_Scn *sec; 8614d1e00a8SArnaldo Carvalho de Melo Elf *elf; 8624d1e00a8SArnaldo Carvalho de Melo 8632643ce11SArnaldo Carvalho de Melo if (size < BUILD_ID_SIZE) 8642643ce11SArnaldo Carvalho de Melo goto out; 8652643ce11SArnaldo Carvalho de Melo 8662643ce11SArnaldo Carvalho de Melo fd = open(filename, O_RDONLY); 8674d1e00a8SArnaldo Carvalho de Melo if (fd < 0) 8684d1e00a8SArnaldo Carvalho de Melo goto out; 8694d1e00a8SArnaldo Carvalho de Melo 87084087126SMarti Raudsepp elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 8714d1e00a8SArnaldo Carvalho de Melo if (elf == NULL) { 872*8d06367fSArnaldo Carvalho de Melo pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename); 8734d1e00a8SArnaldo Carvalho de Melo goto out_close; 8744d1e00a8SArnaldo Carvalho de Melo } 8754d1e00a8SArnaldo Carvalho de Melo 8764d1e00a8SArnaldo Carvalho de Melo if (gelf_getehdr(elf, &ehdr) == NULL) { 8776beba7adSArnaldo Carvalho de Melo pr_err("%s: cannot get elf header.\n", __func__); 8784d1e00a8SArnaldo Carvalho de Melo goto out_elf_end; 8794d1e00a8SArnaldo Carvalho de Melo } 8804d1e00a8SArnaldo Carvalho de Melo 8812643ce11SArnaldo Carvalho de Melo sec = elf_section_by_name(elf, &ehdr, &shdr, 8822643ce11SArnaldo Carvalho de Melo ".note.gnu.build-id", NULL); 8834d1e00a8SArnaldo Carvalho de Melo if (sec == NULL) 8844d1e00a8SArnaldo Carvalho de Melo goto out_elf_end; 8854d1e00a8SArnaldo Carvalho de Melo 8864d1e00a8SArnaldo Carvalho de Melo build_id_data = elf_getdata(sec, NULL); 8874d1e00a8SArnaldo Carvalho de Melo if (build_id_data == NULL) 8884d1e00a8SArnaldo Carvalho de Melo goto out_elf_end; 8892643ce11SArnaldo Carvalho de Melo memcpy(bf, build_id_data->d_buf + 16, BUILD_ID_SIZE); 8902643ce11SArnaldo Carvalho de Melo err = BUILD_ID_SIZE; 8912643ce11SArnaldo Carvalho de Melo out_elf_end: 8922643ce11SArnaldo Carvalho de Melo elf_end(elf); 8932643ce11SArnaldo Carvalho de Melo out_close: 8942643ce11SArnaldo Carvalho de Melo close(fd); 8952643ce11SArnaldo Carvalho de Melo out: 8962643ce11SArnaldo Carvalho de Melo return err; 8972643ce11SArnaldo Carvalho de Melo } 8982643ce11SArnaldo Carvalho de Melo 8992643ce11SArnaldo Carvalho de Melo static char *dso__read_build_id(struct dso *self) 9002643ce11SArnaldo Carvalho de Melo { 901*8d06367fSArnaldo Carvalho de Melo int len; 902*8d06367fSArnaldo Carvalho de Melo char *build_id = NULL; 903*8d06367fSArnaldo Carvalho de Melo unsigned char rawbf[BUILD_ID_SIZE]; 9042643ce11SArnaldo Carvalho de Melo 9052643ce11SArnaldo Carvalho de Melo len = filename__read_build_id(self->long_name, rawbf, sizeof(rawbf)); 9062643ce11SArnaldo Carvalho de Melo if (len < 0) 9072643ce11SArnaldo Carvalho de Melo goto out; 9082643ce11SArnaldo Carvalho de Melo 9092643ce11SArnaldo Carvalho de Melo build_id = malloc(len * 2 + 1); 9104d1e00a8SArnaldo Carvalho de Melo if (build_id == NULL) 9112643ce11SArnaldo Carvalho de Melo goto out; 9124d1e00a8SArnaldo Carvalho de Melo 913*8d06367fSArnaldo Carvalho de Melo build_id__sprintf(rawbf, len, build_id); 9144d1e00a8SArnaldo Carvalho de Melo out: 9154d1e00a8SArnaldo Carvalho de Melo return build_id; 9164d1e00a8SArnaldo Carvalho de Melo } 9174d1e00a8SArnaldo Carvalho de Melo 91894cb9e38SArnaldo Carvalho de Melo char dso__symtab_origin(const struct dso *self) 91994cb9e38SArnaldo Carvalho de Melo { 92094cb9e38SArnaldo Carvalho de Melo static const char origin[] = { 92194cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_KERNEL] = 'k', 92294cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_JAVA_JIT] = 'j', 92394cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_FEDORA] = 'f', 92494cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_UBUNTU] = 'u', 92594cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_BUILDID] = 'b', 92694cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_DSO] = 'd', 927439d473bSArnaldo Carvalho de Melo [DSO__ORIG_KMODULE] = 'K', 92894cb9e38SArnaldo Carvalho de Melo }; 92994cb9e38SArnaldo Carvalho de Melo 93094cb9e38SArnaldo Carvalho de Melo if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND) 93194cb9e38SArnaldo Carvalho de Melo return '!'; 93294cb9e38SArnaldo Carvalho de Melo return origin[self->origin]; 93394cb9e38SArnaldo Carvalho de Melo } 93494cb9e38SArnaldo Carvalho de Melo 9356beba7adSArnaldo Carvalho de Melo int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) 93686470930SIngo Molnar { 9374d1e00a8SArnaldo Carvalho de Melo int size = PATH_MAX; 9384d1e00a8SArnaldo Carvalho de Melo char *name = malloc(size), *build_id = NULL; 93986470930SIngo Molnar int ret = -1; 94086470930SIngo Molnar int fd; 94186470930SIngo Molnar 942*8d06367fSArnaldo Carvalho de Melo self->loaded = 1; 94366bd8424SArnaldo Carvalho de Melo 94486470930SIngo Molnar if (!name) 94586470930SIngo Molnar return -1; 94686470930SIngo Molnar 94730d7a77dSArnaldo Carvalho de Melo self->adjust_symbols = 0; 948f5812a7aSArnaldo Carvalho de Melo 94994cb9e38SArnaldo Carvalho de Melo if (strncmp(self->name, "/tmp/perf-", 10) == 0) { 9506beba7adSArnaldo Carvalho de Melo ret = dso__load_perf_map(self, map, filter); 95194cb9e38SArnaldo Carvalho de Melo self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT : 95294cb9e38SArnaldo Carvalho de Melo DSO__ORIG_NOT_FOUND; 95394cb9e38SArnaldo Carvalho de Melo return ret; 95494cb9e38SArnaldo Carvalho de Melo } 95594cb9e38SArnaldo Carvalho de Melo 95694cb9e38SArnaldo Carvalho de Melo self->origin = DSO__ORIG_FEDORA - 1; 95780d496beSPekka Enberg 95886470930SIngo Molnar more: 95986470930SIngo Molnar do { 960*8d06367fSArnaldo Carvalho de Melo int berr = 0; 961*8d06367fSArnaldo Carvalho de Melo 96294cb9e38SArnaldo Carvalho de Melo self->origin++; 96394cb9e38SArnaldo Carvalho de Melo switch (self->origin) { 96494cb9e38SArnaldo Carvalho de Melo case DSO__ORIG_FEDORA: 965439d473bSArnaldo Carvalho de Melo snprintf(name, size, "/usr/lib/debug%s.debug", 966439d473bSArnaldo Carvalho de Melo self->long_name); 96786470930SIngo Molnar break; 96894cb9e38SArnaldo Carvalho de Melo case DSO__ORIG_UBUNTU: 969439d473bSArnaldo Carvalho de Melo snprintf(name, size, "/usr/lib/debug%s", 970439d473bSArnaldo Carvalho de Melo self->long_name); 97186470930SIngo Molnar break; 97294cb9e38SArnaldo Carvalho de Melo case DSO__ORIG_BUILDID: 9736beba7adSArnaldo Carvalho de Melo build_id = dso__read_build_id(self); 9744d1e00a8SArnaldo Carvalho de Melo if (build_id != NULL) { 9754d1e00a8SArnaldo Carvalho de Melo snprintf(name, size, 9764d1e00a8SArnaldo Carvalho de Melo "/usr/lib/debug/.build-id/%.2s/%s.debug", 9774d1e00a8SArnaldo Carvalho de Melo build_id, build_id + 2); 978*8d06367fSArnaldo Carvalho de Melo goto compare_build_id; 9794d1e00a8SArnaldo Carvalho de Melo } 98094cb9e38SArnaldo Carvalho de Melo self->origin++; 9814d1e00a8SArnaldo Carvalho de Melo /* Fall thru */ 98294cb9e38SArnaldo Carvalho de Melo case DSO__ORIG_DSO: 983439d473bSArnaldo Carvalho de Melo snprintf(name, size, "%s", self->long_name); 98486470930SIngo Molnar break; 98586470930SIngo Molnar 98686470930SIngo Molnar default: 98786470930SIngo Molnar goto out; 98886470930SIngo Molnar } 98986470930SIngo Molnar 990*8d06367fSArnaldo Carvalho de Melo if (self->has_build_id) { 991*8d06367fSArnaldo Carvalho de Melo bool match; 992*8d06367fSArnaldo Carvalho de Melo build_id = malloc(BUILD_ID_SIZE); 993*8d06367fSArnaldo Carvalho de Melo if (build_id == NULL) 994*8d06367fSArnaldo Carvalho de Melo goto more; 995*8d06367fSArnaldo Carvalho de Melo berr = filename__read_build_id(name, build_id, 996*8d06367fSArnaldo Carvalho de Melo BUILD_ID_SIZE); 997*8d06367fSArnaldo Carvalho de Melo compare_build_id: 998*8d06367fSArnaldo Carvalho de Melo match = berr > 0 && memcmp(build_id, self->build_id, 999*8d06367fSArnaldo Carvalho de Melo sizeof(self->build_id)) == 0; 1000*8d06367fSArnaldo Carvalho de Melo free(build_id); 1001*8d06367fSArnaldo Carvalho de Melo build_id = NULL; 1002*8d06367fSArnaldo Carvalho de Melo if (!match) 1003*8d06367fSArnaldo Carvalho de Melo goto more; 1004*8d06367fSArnaldo Carvalho de Melo } 1005*8d06367fSArnaldo Carvalho de Melo 100686470930SIngo Molnar fd = open(name, O_RDONLY); 100786470930SIngo Molnar } while (fd < 0); 100886470930SIngo Molnar 10096beba7adSArnaldo Carvalho de Melo ret = dso__load_sym(self, map, name, fd, filter, 0, 0); 101086470930SIngo Molnar close(fd); 101186470930SIngo Molnar 101286470930SIngo Molnar /* 101386470930SIngo Molnar * Some people seem to have debuginfo files _WITHOUT_ debug info!?!? 101486470930SIngo Molnar */ 101586470930SIngo Molnar if (!ret) 101686470930SIngo Molnar goto more; 101786470930SIngo Molnar 1018a25e46c4SArnaldo Carvalho de Melo if (ret > 0) { 10196beba7adSArnaldo Carvalho de Melo int nr_plt = dso__synthesize_plt_symbols(self); 1020a25e46c4SArnaldo Carvalho de Melo if (nr_plt > 0) 1021a25e46c4SArnaldo Carvalho de Melo ret += nr_plt; 1022a25e46c4SArnaldo Carvalho de Melo } 102386470930SIngo Molnar out: 102486470930SIngo Molnar free(name); 10251340e6bbSArnaldo Carvalho de Melo if (ret < 0 && strstr(self->name, " (deleted)") != NULL) 10261340e6bbSArnaldo Carvalho de Melo return 0; 102786470930SIngo Molnar return ret; 102886470930SIngo Molnar } 102986470930SIngo Molnar 1030439d473bSArnaldo Carvalho de Melo struct map *kernel_map; 1031439d473bSArnaldo Carvalho de Melo 1032439d473bSArnaldo Carvalho de Melo static void kernel_maps__insert(struct map *map) 1033439d473bSArnaldo Carvalho de Melo { 1034439d473bSArnaldo Carvalho de Melo maps__insert(&kernel_maps, map); 1035439d473bSArnaldo Carvalho de Melo } 1036439d473bSArnaldo Carvalho de Melo 1037439d473bSArnaldo Carvalho de Melo struct symbol *kernel_maps__find_symbol(u64 ip, struct map **mapp) 1038439d473bSArnaldo Carvalho de Melo { 1039439d473bSArnaldo Carvalho de Melo struct map *map = maps__find(&kernel_maps, ip); 1040439d473bSArnaldo Carvalho de Melo 1041439d473bSArnaldo Carvalho de Melo if (mapp) 1042439d473bSArnaldo Carvalho de Melo *mapp = map; 1043439d473bSArnaldo Carvalho de Melo 10442e538c4aSArnaldo Carvalho de Melo if (map) { 10452e538c4aSArnaldo Carvalho de Melo ip = map->map_ip(map, ip); 10462e538c4aSArnaldo Carvalho de Melo return map->dso->find_symbol(map->dso, ip); 10472e538c4aSArnaldo Carvalho de Melo } 10482e538c4aSArnaldo Carvalho de Melo 10492e538c4aSArnaldo Carvalho de Melo return NULL; 1050439d473bSArnaldo Carvalho de Melo } 1051439d473bSArnaldo Carvalho de Melo 1052439d473bSArnaldo Carvalho de Melo struct map *kernel_maps__find_by_dso_name(const char *name) 1053439d473bSArnaldo Carvalho de Melo { 1054439d473bSArnaldo Carvalho de Melo struct rb_node *nd; 1055439d473bSArnaldo Carvalho de Melo 1056439d473bSArnaldo Carvalho de Melo for (nd = rb_first(&kernel_maps); nd; nd = rb_next(nd)) { 1057439d473bSArnaldo Carvalho de Melo struct map *map = rb_entry(nd, struct map, rb_node); 1058439d473bSArnaldo Carvalho de Melo 1059439d473bSArnaldo Carvalho de Melo if (map->dso && strcmp(map->dso->name, name) == 0) 1060439d473bSArnaldo Carvalho de Melo return map; 1061439d473bSArnaldo Carvalho de Melo } 1062439d473bSArnaldo Carvalho de Melo 1063439d473bSArnaldo Carvalho de Melo return NULL; 1064439d473bSArnaldo Carvalho de Melo } 1065439d473bSArnaldo Carvalho de Melo 1066439d473bSArnaldo Carvalho de Melo static int dso__load_module_sym(struct dso *self, struct map *map, 10676beba7adSArnaldo Carvalho de Melo symbol_filter_t filter) 10686cfcc53eSMike Galbraith { 1069439d473bSArnaldo Carvalho de Melo int err = 0, fd = open(self->long_name, O_RDONLY); 10706cfcc53eSMike Galbraith 1071*8d06367fSArnaldo Carvalho de Melo self->loaded = 1; 107266bd8424SArnaldo Carvalho de Melo 1073439d473bSArnaldo Carvalho de Melo if (fd < 0) { 10746beba7adSArnaldo Carvalho de Melo pr_err("%s: cannot open %s\n", __func__, self->long_name); 10756cfcc53eSMike Galbraith return err; 1076439d473bSArnaldo Carvalho de Melo } 10776cfcc53eSMike Galbraith 10786beba7adSArnaldo Carvalho de Melo err = dso__load_sym(self, map, self->long_name, fd, filter, 0, 1); 10796cfcc53eSMike Galbraith close(fd); 10806cfcc53eSMike Galbraith 10816cfcc53eSMike Galbraith return err; 10826cfcc53eSMike Galbraith } 10836cfcc53eSMike Galbraith 10846beba7adSArnaldo Carvalho de Melo static int dsos__load_modules_sym_dir(char *dirname, symbol_filter_t filter) 10856cfcc53eSMike Galbraith { 1086439d473bSArnaldo Carvalho de Melo struct dirent *dent; 1087439d473bSArnaldo Carvalho de Melo int nr_symbols = 0, err; 1088439d473bSArnaldo Carvalho de Melo DIR *dir = opendir(dirname); 10896cfcc53eSMike Galbraith 1090439d473bSArnaldo Carvalho de Melo if (!dir) { 10916beba7adSArnaldo Carvalho de Melo pr_err("%s: cannot open %s dir\n", __func__, dirname); 1092439d473bSArnaldo Carvalho de Melo return -1; 1093439d473bSArnaldo Carvalho de Melo } 10946cfcc53eSMike Galbraith 1095439d473bSArnaldo Carvalho de Melo while ((dent = readdir(dir)) != NULL) { 1096439d473bSArnaldo Carvalho de Melo char path[PATH_MAX]; 1097439d473bSArnaldo Carvalho de Melo 1098439d473bSArnaldo Carvalho de Melo if (dent->d_type == DT_DIR) { 1099439d473bSArnaldo Carvalho de Melo if (!strcmp(dent->d_name, ".") || 1100439d473bSArnaldo Carvalho de Melo !strcmp(dent->d_name, "..")) 1101439d473bSArnaldo Carvalho de Melo continue; 1102439d473bSArnaldo Carvalho de Melo 1103439d473bSArnaldo Carvalho de Melo snprintf(path, sizeof(path), "%s/%s", 1104439d473bSArnaldo Carvalho de Melo dirname, dent->d_name); 11056beba7adSArnaldo Carvalho de Melo err = dsos__load_modules_sym_dir(path, filter); 1106439d473bSArnaldo Carvalho de Melo if (err < 0) 1107439d473bSArnaldo Carvalho de Melo goto failure; 1108439d473bSArnaldo Carvalho de Melo } else { 1109439d473bSArnaldo Carvalho de Melo char *dot = strrchr(dent->d_name, '.'), 1110439d473bSArnaldo Carvalho de Melo dso_name[PATH_MAX]; 1111439d473bSArnaldo Carvalho de Melo struct map *map; 1112439d473bSArnaldo Carvalho de Melo struct rb_node *last; 1113439d473bSArnaldo Carvalho de Melo 1114439d473bSArnaldo Carvalho de Melo if (dot == NULL || strcmp(dot, ".ko")) 1115439d473bSArnaldo Carvalho de Melo continue; 1116439d473bSArnaldo Carvalho de Melo snprintf(dso_name, sizeof(dso_name), "[%.*s]", 1117439d473bSArnaldo Carvalho de Melo (int)(dot - dent->d_name), dent->d_name); 1118439d473bSArnaldo Carvalho de Melo 1119a2a99e8eSArnaldo Carvalho de Melo strxfrchar(dso_name, '-', '_'); 1120439d473bSArnaldo Carvalho de Melo map = kernel_maps__find_by_dso_name(dso_name); 1121439d473bSArnaldo Carvalho de Melo if (map == NULL) 1122439d473bSArnaldo Carvalho de Melo continue; 1123439d473bSArnaldo Carvalho de Melo 1124439d473bSArnaldo Carvalho de Melo snprintf(path, sizeof(path), "%s/%s", 1125439d473bSArnaldo Carvalho de Melo dirname, dent->d_name); 1126439d473bSArnaldo Carvalho de Melo 1127439d473bSArnaldo Carvalho de Melo map->dso->long_name = strdup(path); 1128439d473bSArnaldo Carvalho de Melo if (map->dso->long_name == NULL) 1129439d473bSArnaldo Carvalho de Melo goto failure; 1130439d473bSArnaldo Carvalho de Melo 11316beba7adSArnaldo Carvalho de Melo err = dso__load_module_sym(map->dso, map, filter); 1132439d473bSArnaldo Carvalho de Melo if (err < 0) 1133439d473bSArnaldo Carvalho de Melo goto failure; 1134439d473bSArnaldo Carvalho de Melo last = rb_last(&map->dso->syms); 1135439d473bSArnaldo Carvalho de Melo if (last) { 1136439d473bSArnaldo Carvalho de Melo struct symbol *sym; 11372e538c4aSArnaldo Carvalho de Melo /* 11382e538c4aSArnaldo Carvalho de Melo * We do this here as well, even having the 11392e538c4aSArnaldo Carvalho de Melo * symbol size found in the symtab because 11402e538c4aSArnaldo Carvalho de Melo * misannotated ASM symbols may have the size 11412e538c4aSArnaldo Carvalho de Melo * set to zero. 11422e538c4aSArnaldo Carvalho de Melo */ 11432e538c4aSArnaldo Carvalho de Melo dso__fixup_sym_end(map->dso); 11442e538c4aSArnaldo Carvalho de Melo 1145439d473bSArnaldo Carvalho de Melo sym = rb_entry(last, struct symbol, rb_node); 1146439d473bSArnaldo Carvalho de Melo map->end = map->start + sym->end; 1147439d473bSArnaldo Carvalho de Melo } 1148439d473bSArnaldo Carvalho de Melo } 1149439d473bSArnaldo Carvalho de Melo nr_symbols += err; 1150439d473bSArnaldo Carvalho de Melo } 1151439d473bSArnaldo Carvalho de Melo 1152439d473bSArnaldo Carvalho de Melo return nr_symbols; 1153439d473bSArnaldo Carvalho de Melo failure: 1154439d473bSArnaldo Carvalho de Melo closedir(dir); 1155439d473bSArnaldo Carvalho de Melo return -1; 1156439d473bSArnaldo Carvalho de Melo } 1157439d473bSArnaldo Carvalho de Melo 11586beba7adSArnaldo Carvalho de Melo static int dsos__load_modules_sym(symbol_filter_t filter) 1159439d473bSArnaldo Carvalho de Melo { 1160439d473bSArnaldo Carvalho de Melo struct utsname uts; 1161439d473bSArnaldo Carvalho de Melo char modules_path[PATH_MAX]; 1162439d473bSArnaldo Carvalho de Melo 1163439d473bSArnaldo Carvalho de Melo if (uname(&uts) < 0) 1164439d473bSArnaldo Carvalho de Melo return -1; 1165439d473bSArnaldo Carvalho de Melo 1166439d473bSArnaldo Carvalho de Melo snprintf(modules_path, sizeof(modules_path), "/lib/modules/%s/kernel", 1167439d473bSArnaldo Carvalho de Melo uts.release); 1168439d473bSArnaldo Carvalho de Melo 11696beba7adSArnaldo Carvalho de Melo return dsos__load_modules_sym_dir(modules_path, filter); 1170439d473bSArnaldo Carvalho de Melo } 11716cfcc53eSMike Galbraith 11726cfcc53eSMike Galbraith /* 1173439d473bSArnaldo Carvalho de Melo * Constructor variant for modules (where we know from /proc/modules where 1174439d473bSArnaldo Carvalho de Melo * they are loaded) and for vmlinux, where only after we load all the 1175439d473bSArnaldo Carvalho de Melo * symbols we'll know where it starts and ends. 11766cfcc53eSMike Galbraith */ 1177439d473bSArnaldo Carvalho de Melo static struct map *map__new2(u64 start, struct dso *dso) 1178439d473bSArnaldo Carvalho de Melo { 1179439d473bSArnaldo Carvalho de Melo struct map *self = malloc(sizeof(*self)); 11806cfcc53eSMike Galbraith 1181439d473bSArnaldo Carvalho de Melo if (self != NULL) { 1182439d473bSArnaldo Carvalho de Melo /* 1183afb7b4f0SArnaldo Carvalho de Melo * ->end will be filled after we load all the symbols 1184439d473bSArnaldo Carvalho de Melo */ 1185afb7b4f0SArnaldo Carvalho de Melo map__init(self, start, 0, 0, dso); 1186439d473bSArnaldo Carvalho de Melo } 1187afb7b4f0SArnaldo Carvalho de Melo 1188439d473bSArnaldo Carvalho de Melo return self; 1189439d473bSArnaldo Carvalho de Melo } 1190439d473bSArnaldo Carvalho de Melo 119100a192b3SArnaldo Carvalho de Melo static int dsos__load_modules(void) 1192439d473bSArnaldo Carvalho de Melo { 1193439d473bSArnaldo Carvalho de Melo char *line = NULL; 1194439d473bSArnaldo Carvalho de Melo size_t n; 1195439d473bSArnaldo Carvalho de Melo FILE *file = fopen("/proc/modules", "r"); 1196439d473bSArnaldo Carvalho de Melo struct map *map; 1197439d473bSArnaldo Carvalho de Melo 1198439d473bSArnaldo Carvalho de Melo if (file == NULL) 1199439d473bSArnaldo Carvalho de Melo return -1; 1200439d473bSArnaldo Carvalho de Melo 1201439d473bSArnaldo Carvalho de Melo while (!feof(file)) { 1202439d473bSArnaldo Carvalho de Melo char name[PATH_MAX]; 1203439d473bSArnaldo Carvalho de Melo u64 start; 1204439d473bSArnaldo Carvalho de Melo struct dso *dso; 1205439d473bSArnaldo Carvalho de Melo char *sep; 1206439d473bSArnaldo Carvalho de Melo int line_len; 1207439d473bSArnaldo Carvalho de Melo 1208439d473bSArnaldo Carvalho de Melo line_len = getline(&line, &n, file); 1209439d473bSArnaldo Carvalho de Melo if (line_len < 0) 12106cfcc53eSMike Galbraith break; 12116cfcc53eSMike Galbraith 1212439d473bSArnaldo Carvalho de Melo if (!line) 1213439d473bSArnaldo Carvalho de Melo goto out_failure; 1214439d473bSArnaldo Carvalho de Melo 1215439d473bSArnaldo Carvalho de Melo line[--line_len] = '\0'; /* \n */ 1216439d473bSArnaldo Carvalho de Melo 1217439d473bSArnaldo Carvalho de Melo sep = strrchr(line, 'x'); 1218439d473bSArnaldo Carvalho de Melo if (sep == NULL) 1219439d473bSArnaldo Carvalho de Melo continue; 1220439d473bSArnaldo Carvalho de Melo 1221439d473bSArnaldo Carvalho de Melo hex2u64(sep + 1, &start); 1222439d473bSArnaldo Carvalho de Melo 1223439d473bSArnaldo Carvalho de Melo sep = strchr(line, ' '); 1224439d473bSArnaldo Carvalho de Melo if (sep == NULL) 1225439d473bSArnaldo Carvalho de Melo continue; 1226439d473bSArnaldo Carvalho de Melo 1227439d473bSArnaldo Carvalho de Melo *sep = '\0'; 1228439d473bSArnaldo Carvalho de Melo 1229439d473bSArnaldo Carvalho de Melo snprintf(name, sizeof(name), "[%s]", line); 123000a192b3SArnaldo Carvalho de Melo dso = dso__new(name); 1231439d473bSArnaldo Carvalho de Melo 1232439d473bSArnaldo Carvalho de Melo if (dso == NULL) 1233439d473bSArnaldo Carvalho de Melo goto out_delete_line; 1234439d473bSArnaldo Carvalho de Melo 1235439d473bSArnaldo Carvalho de Melo map = map__new2(start, dso); 1236439d473bSArnaldo Carvalho de Melo if (map == NULL) { 1237439d473bSArnaldo Carvalho de Melo dso__delete(dso); 1238439d473bSArnaldo Carvalho de Melo goto out_delete_line; 12396cfcc53eSMike Galbraith } 12406cfcc53eSMike Galbraith 1241439d473bSArnaldo Carvalho de Melo dso->origin = DSO__ORIG_KMODULE; 1242439d473bSArnaldo Carvalho de Melo kernel_maps__insert(map); 1243439d473bSArnaldo Carvalho de Melo dsos__add(dso); 12446cfcc53eSMike Galbraith } 12456cfcc53eSMike Galbraith 1246439d473bSArnaldo Carvalho de Melo free(line); 1247439d473bSArnaldo Carvalho de Melo fclose(file); 1248439d473bSArnaldo Carvalho de Melo 1249af427bf5SArnaldo Carvalho de Melo return 0; 1250439d473bSArnaldo Carvalho de Melo 1251439d473bSArnaldo Carvalho de Melo out_delete_line: 1252439d473bSArnaldo Carvalho de Melo free(line); 1253439d473bSArnaldo Carvalho de Melo out_failure: 1254439d473bSArnaldo Carvalho de Melo return -1; 12556cfcc53eSMike Galbraith } 12566cfcc53eSMike Galbraith 1257439d473bSArnaldo Carvalho de Melo static int dso__load_vmlinux(struct dso *self, struct map *map, 12586beba7adSArnaldo Carvalho de Melo const char *vmlinux, symbol_filter_t filter) 125986470930SIngo Molnar { 126086470930SIngo Molnar int err, fd = open(vmlinux, O_RDONLY); 126186470930SIngo Molnar 1262*8d06367fSArnaldo Carvalho de Melo self->loaded = 1; 126366bd8424SArnaldo Carvalho de Melo 126486470930SIngo Molnar if (fd < 0) 126586470930SIngo Molnar return -1; 126686470930SIngo Molnar 12676beba7adSArnaldo Carvalho de Melo err = dso__load_sym(self, map, self->long_name, fd, filter, 1, 0); 12686cfcc53eSMike Galbraith 126986470930SIngo Molnar close(fd); 127086470930SIngo Molnar 127186470930SIngo Molnar return err; 127286470930SIngo Molnar } 127386470930SIngo Molnar 127400a192b3SArnaldo Carvalho de Melo int dsos__load_kernel(const char *vmlinux, symbol_filter_t filter, 127500a192b3SArnaldo Carvalho de Melo int use_modules) 127686470930SIngo Molnar { 127786470930SIngo Molnar int err = -1; 127800a192b3SArnaldo Carvalho de Melo struct dso *dso = dso__new(vmlinux); 1279439d473bSArnaldo Carvalho de Melo 1280439d473bSArnaldo Carvalho de Melo if (dso == NULL) 1281439d473bSArnaldo Carvalho de Melo return -1; 1282439d473bSArnaldo Carvalho de Melo 1283439d473bSArnaldo Carvalho de Melo dso->short_name = "[kernel]"; 1284439d473bSArnaldo Carvalho de Melo kernel_map = map__new2(0, dso); 1285439d473bSArnaldo Carvalho de Melo if (kernel_map == NULL) 1286439d473bSArnaldo Carvalho de Melo goto out_delete_dso; 1287439d473bSArnaldo Carvalho de Melo 1288ed52ce2eSArnaldo Carvalho de Melo kernel_map->map_ip = kernel_map->unmap_ip = identity__map_ip; 128986470930SIngo Molnar 129000a192b3SArnaldo Carvalho de Melo if (use_modules && dsos__load_modules() < 0) { 12916beba7adSArnaldo Carvalho de Melo pr_warning("Failed to load list of modules in use! " 1292af427bf5SArnaldo Carvalho de Melo "Continuing...\n"); 1293af427bf5SArnaldo Carvalho de Melo use_modules = 0; 1294af427bf5SArnaldo Carvalho de Melo } 1295af427bf5SArnaldo Carvalho de Melo 12966cfcc53eSMike Galbraith if (vmlinux) { 12976beba7adSArnaldo Carvalho de Melo err = dso__load_vmlinux(dso, kernel_map, vmlinux, filter); 1298508c4d08SMike Galbraith if (err > 0 && use_modules) { 12996beba7adSArnaldo Carvalho de Melo int syms = dsos__load_modules_sym(filter); 1300508c4d08SMike Galbraith 1301af427bf5SArnaldo Carvalho de Melo if (syms < 0) 13026beba7adSArnaldo Carvalho de Melo pr_warning("Failed to read module symbols!" 1303af427bf5SArnaldo Carvalho de Melo " Continuing...\n"); 1304af427bf5SArnaldo Carvalho de Melo else 1305508c4d08SMike Galbraith err += syms; 1306508c4d08SMike Galbraith } 13076cfcc53eSMike Galbraith } 130886470930SIngo Molnar 13099974f496SMike Galbraith if (err <= 0) 13106beba7adSArnaldo Carvalho de Melo err = kernel_maps__load_kallsyms(filter, use_modules); 131186470930SIngo Molnar 1312439d473bSArnaldo Carvalho de Melo if (err > 0) { 1313439d473bSArnaldo Carvalho de Melo struct rb_node *node = rb_first(&dso->syms); 1314439d473bSArnaldo Carvalho de Melo struct symbol *sym = rb_entry(node, struct symbol, rb_node); 1315439d473bSArnaldo Carvalho de Melo 1316439d473bSArnaldo Carvalho de Melo kernel_map->start = sym->start; 1317439d473bSArnaldo Carvalho de Melo node = rb_last(&dso->syms); 1318439d473bSArnaldo Carvalho de Melo sym = rb_entry(node, struct symbol, rb_node); 1319439d473bSArnaldo Carvalho de Melo kernel_map->end = sym->end; 1320439d473bSArnaldo Carvalho de Melo 1321439d473bSArnaldo Carvalho de Melo dso->origin = DSO__ORIG_KERNEL; 13222e538c4aSArnaldo Carvalho de Melo kernel_maps__insert(kernel_map); 1323439d473bSArnaldo Carvalho de Melo /* 13242e538c4aSArnaldo Carvalho de Melo * Now that we have all sorted out, just set the ->end of all 13252e538c4aSArnaldo Carvalho de Melo * maps: 1326439d473bSArnaldo Carvalho de Melo */ 13272e538c4aSArnaldo Carvalho de Melo kernel_maps__fixup_end(); 1328439d473bSArnaldo Carvalho de Melo dsos__add(dso); 1329af427bf5SArnaldo Carvalho de Melo 13306beba7adSArnaldo Carvalho de Melo if (verbose) 13316beba7adSArnaldo Carvalho de Melo kernel_maps__fprintf(stderr); 1332439d473bSArnaldo Carvalho de Melo } 133394cb9e38SArnaldo Carvalho de Melo 133486470930SIngo Molnar return err; 1335439d473bSArnaldo Carvalho de Melo 1336439d473bSArnaldo Carvalho de Melo out_delete_dso: 1337439d473bSArnaldo Carvalho de Melo dso__delete(dso); 1338439d473bSArnaldo Carvalho de Melo return -1; 133986470930SIngo Molnar } 134086470930SIngo Molnar 1341cd84c2acSFrederic Weisbecker LIST_HEAD(dsos); 1342cd84c2acSFrederic Weisbecker struct dso *vdso; 1343cd84c2acSFrederic Weisbecker 134483a0944fSIngo Molnar const char *vmlinux_name = "vmlinux"; 1345cd84c2acSFrederic Weisbecker int modules; 1346cd84c2acSFrederic Weisbecker 1347cd84c2acSFrederic Weisbecker static void dsos__add(struct dso *dso) 1348cd84c2acSFrederic Weisbecker { 1349cd84c2acSFrederic Weisbecker list_add_tail(&dso->node, &dsos); 1350cd84c2acSFrederic Weisbecker } 1351cd84c2acSFrederic Weisbecker 1352cd84c2acSFrederic Weisbecker static struct dso *dsos__find(const char *name) 1353cd84c2acSFrederic Weisbecker { 1354cd84c2acSFrederic Weisbecker struct dso *pos; 1355cd84c2acSFrederic Weisbecker 1356cd84c2acSFrederic Weisbecker list_for_each_entry(pos, &dsos, node) 1357cd84c2acSFrederic Weisbecker if (strcmp(pos->name, name) == 0) 1358cd84c2acSFrederic Weisbecker return pos; 1359cd84c2acSFrederic Weisbecker return NULL; 1360cd84c2acSFrederic Weisbecker } 1361cd84c2acSFrederic Weisbecker 136200a192b3SArnaldo Carvalho de Melo struct dso *dsos__findnew(const char *name) 1363cd84c2acSFrederic Weisbecker { 1364cd84c2acSFrederic Weisbecker struct dso *dso = dsos__find(name); 1365cd84c2acSFrederic Weisbecker 1366e4204992SArnaldo Carvalho de Melo if (!dso) { 136700a192b3SArnaldo Carvalho de Melo dso = dso__new(name); 136866bd8424SArnaldo Carvalho de Melo if (dso != NULL) 1369cd84c2acSFrederic Weisbecker dsos__add(dso); 1370e4204992SArnaldo Carvalho de Melo } 1371cd84c2acSFrederic Weisbecker 1372cd84c2acSFrederic Weisbecker return dso; 1373cd84c2acSFrederic Weisbecker } 1374cd84c2acSFrederic Weisbecker 1375cd84c2acSFrederic Weisbecker void dsos__fprintf(FILE *fp) 1376cd84c2acSFrederic Weisbecker { 1377cd84c2acSFrederic Weisbecker struct dso *pos; 1378cd84c2acSFrederic Weisbecker 1379cd84c2acSFrederic Weisbecker list_for_each_entry(pos, &dsos, node) 1380cd84c2acSFrederic Weisbecker dso__fprintf(pos, fp); 1381cd84c2acSFrederic Weisbecker } 1382cd84c2acSFrederic Weisbecker 138300a192b3SArnaldo Carvalho de Melo int load_kernel(symbol_filter_t filter) 1384cd84c2acSFrederic Weisbecker { 138500a192b3SArnaldo Carvalho de Melo if (dsos__load_kernel(vmlinux_name, filter, modules) <= 0) 1386cd84c2acSFrederic Weisbecker return -1; 1387cd84c2acSFrederic Weisbecker 138800a192b3SArnaldo Carvalho de Melo vdso = dso__new("[vdso]"); 1389cd84c2acSFrederic Weisbecker if (!vdso) 1390cd84c2acSFrederic Weisbecker return -1; 1391cd84c2acSFrederic Weisbecker 1392cd84c2acSFrederic Weisbecker dsos__add(vdso); 1393cd84c2acSFrederic Weisbecker 1394439d473bSArnaldo Carvalho de Melo return 0; 1395cd84c2acSFrederic Weisbecker } 1396cd84c2acSFrederic Weisbecker 139700a192b3SArnaldo Carvalho de Melo void symbol__init(unsigned int priv_size) 139886470930SIngo Molnar { 139986470930SIngo Molnar elf_version(EV_CURRENT); 140000a192b3SArnaldo Carvalho de Melo symbol__priv_size = priv_size; 140186470930SIngo Molnar } 1402