186470930SIngo Molnar #include "util.h" 286470930SIngo Molnar #include "../perf.h" 386470930SIngo Molnar #include "string.h" 486470930SIngo Molnar #include "symbol.h" 5439d473bSArnaldo Carvalho de Melo #include "thread.h" 686470930SIngo Molnar 78f28827aSFrederic Weisbecker #include "debug.h" 88f28827aSFrederic Weisbecker 9b32d133aSArnaldo Carvalho de Melo #include <asm/bug.h> 1086470930SIngo Molnar #include <libelf.h> 1186470930SIngo Molnar #include <gelf.h> 1286470930SIngo Molnar #include <elf.h> 13f1617b40SArnaldo Carvalho de Melo #include <limits.h> 14439d473bSArnaldo Carvalho de Melo #include <sys/utsname.h> 152cdbc46dSPeter Zijlstra 16c12e15e7SArnaldo Carvalho de Melo #ifndef NT_GNU_BUILD_ID 17c12e15e7SArnaldo Carvalho de Melo #define NT_GNU_BUILD_ID 3 18c12e15e7SArnaldo Carvalho de Melo #endif 19c12e15e7SArnaldo Carvalho de Melo 2094cb9e38SArnaldo Carvalho de Melo enum dso_origin { 2194cb9e38SArnaldo Carvalho de Melo DSO__ORIG_KERNEL = 0, 2294cb9e38SArnaldo Carvalho de Melo DSO__ORIG_JAVA_JIT, 2394cb9e38SArnaldo Carvalho de Melo DSO__ORIG_FEDORA, 2494cb9e38SArnaldo Carvalho de Melo DSO__ORIG_UBUNTU, 2594cb9e38SArnaldo Carvalho de Melo DSO__ORIG_BUILDID, 2694cb9e38SArnaldo Carvalho de Melo DSO__ORIG_DSO, 27439d473bSArnaldo Carvalho de Melo DSO__ORIG_KMODULE, 2894cb9e38SArnaldo Carvalho de Melo DSO__ORIG_NOT_FOUND, 2994cb9e38SArnaldo Carvalho de Melo }; 3094cb9e38SArnaldo Carvalho de Melo 31b0da954aSArnaldo Carvalho de Melo static void dsos__add(struct list_head *head, struct dso *dso); 329958e1f0SArnaldo Carvalho de Melo static struct map *map_groups__find_by_name(struct map_groups *self, char *name); 333610583cSArnaldo Carvalho de Melo static struct map *map__new2(u64 start, struct dso *dso, enum map_type type); 346a4694a4SArnaldo Carvalho de Melo struct symbol *dso__find_symbol(struct dso *self, enum map_type type, u64 addr); 35c338aee8SArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *self, struct map *map, 369958e1f0SArnaldo Carvalho de Melo struct map_groups *mg, symbol_filter_t filter); 3700a192b3SArnaldo Carvalho de Melo unsigned int symbol__priv_size; 38cc612d81SArnaldo Carvalho de Melo static int vmlinux_path__nr_entries; 39cc612d81SArnaldo Carvalho de Melo static char **vmlinux_path; 40439d473bSArnaldo Carvalho de Melo 41b32d133aSArnaldo Carvalho de Melo static struct symbol_conf symbol_conf__defaults = { 42b32d133aSArnaldo Carvalho de Melo .use_modules = true, 43b32d133aSArnaldo Carvalho de Melo .try_vmlinux_path = true, 44b32d133aSArnaldo Carvalho de Melo }; 45b32d133aSArnaldo Carvalho de Melo 469958e1f0SArnaldo Carvalho de Melo static struct map_groups kmaps_mem; 479958e1f0SArnaldo Carvalho de Melo struct map_groups *kmaps = &kmaps_mem; 48af427bf5SArnaldo Carvalho de Melo 493610583cSArnaldo Carvalho de Melo bool dso__loaded(const struct dso *self, enum map_type type) 503610583cSArnaldo Carvalho de Melo { 513610583cSArnaldo Carvalho de Melo return self->loaded & (1 << type); 523610583cSArnaldo Carvalho de Melo } 533610583cSArnaldo Carvalho de Melo 543610583cSArnaldo Carvalho de Melo static void dso__set_loaded(struct dso *self, enum map_type type) 553610583cSArnaldo Carvalho de Melo { 563610583cSArnaldo Carvalho de Melo self->loaded |= (1 << type); 573610583cSArnaldo Carvalho de Melo } 583610583cSArnaldo Carvalho de Melo 59*6893d4eeSArnaldo Carvalho de Melo static bool symbol_type__is_a(char symbol_type, enum map_type map_type) 60*6893d4eeSArnaldo Carvalho de Melo { 61*6893d4eeSArnaldo Carvalho de Melo switch (map_type) { 62*6893d4eeSArnaldo Carvalho de Melo case MAP__FUNCTION: 63*6893d4eeSArnaldo Carvalho de Melo return symbol_type == 'T' || symbol_type == 'W'; 64*6893d4eeSArnaldo Carvalho de Melo default: 65*6893d4eeSArnaldo Carvalho de Melo return false; 66*6893d4eeSArnaldo Carvalho de Melo } 67*6893d4eeSArnaldo Carvalho de Melo } 68*6893d4eeSArnaldo Carvalho de Melo 69fcf1203aSArnaldo Carvalho de Melo static void symbols__fixup_end(struct rb_root *self) 70af427bf5SArnaldo Carvalho de Melo { 71fcf1203aSArnaldo Carvalho de Melo struct rb_node *nd, *prevnd = rb_first(self); 722e538c4aSArnaldo Carvalho de Melo struct symbol *curr, *prev; 73af427bf5SArnaldo Carvalho de Melo 74af427bf5SArnaldo Carvalho de Melo if (prevnd == NULL) 75af427bf5SArnaldo Carvalho de Melo return; 76af427bf5SArnaldo Carvalho de Melo 772e538c4aSArnaldo Carvalho de Melo curr = rb_entry(prevnd, struct symbol, rb_node); 782e538c4aSArnaldo Carvalho de Melo 79af427bf5SArnaldo Carvalho de Melo for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) { 802e538c4aSArnaldo Carvalho de Melo prev = curr; 812e538c4aSArnaldo Carvalho de Melo curr = rb_entry(nd, struct symbol, rb_node); 82af427bf5SArnaldo Carvalho de Melo 83af427bf5SArnaldo Carvalho de Melo if (prev->end == prev->start) 84af427bf5SArnaldo Carvalho de Melo prev->end = curr->start - 1; 85af427bf5SArnaldo Carvalho de Melo } 86af427bf5SArnaldo Carvalho de Melo 872e538c4aSArnaldo Carvalho de Melo /* Last entry */ 882e538c4aSArnaldo Carvalho de Melo if (curr->end == curr->start) 892e538c4aSArnaldo Carvalho de Melo curr->end = roundup(curr->start, 4096); 902e538c4aSArnaldo Carvalho de Melo } 912e538c4aSArnaldo Carvalho de Melo 929958e1f0SArnaldo Carvalho de Melo static void __map_groups__fixup_end(struct map_groups *self, enum map_type type) 93af427bf5SArnaldo Carvalho de Melo { 94af427bf5SArnaldo Carvalho de Melo struct map *prev, *curr; 9595011c60SArnaldo Carvalho de Melo struct rb_node *nd, *prevnd = rb_first(&self->maps[type]); 96af427bf5SArnaldo Carvalho de Melo 97af427bf5SArnaldo Carvalho de Melo if (prevnd == NULL) 98af427bf5SArnaldo Carvalho de Melo return; 99af427bf5SArnaldo Carvalho de Melo 100af427bf5SArnaldo Carvalho de Melo curr = rb_entry(prevnd, struct map, rb_node); 101af427bf5SArnaldo Carvalho de Melo 102af427bf5SArnaldo Carvalho de Melo for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) { 103af427bf5SArnaldo Carvalho de Melo prev = curr; 104af427bf5SArnaldo Carvalho de Melo curr = rb_entry(nd, struct map, rb_node); 105af427bf5SArnaldo Carvalho de Melo prev->end = curr->start - 1; 1062e538c4aSArnaldo Carvalho de Melo } 10790c83218SArnaldo Carvalho de Melo 10890c83218SArnaldo Carvalho de Melo /* 10990c83218SArnaldo Carvalho de Melo * We still haven't the actual symbols, so guess the 11090c83218SArnaldo Carvalho de Melo * last map final address. 11190c83218SArnaldo Carvalho de Melo */ 11290c83218SArnaldo Carvalho de Melo curr->end = ~0UL; 113af427bf5SArnaldo Carvalho de Melo } 114af427bf5SArnaldo Carvalho de Melo 1159958e1f0SArnaldo Carvalho de Melo static void map_groups__fixup_end(struct map_groups *self) 11623ea4a3fSArnaldo Carvalho de Melo { 11723ea4a3fSArnaldo Carvalho de Melo int i; 11823ea4a3fSArnaldo Carvalho de Melo for (i = 0; i < MAP__NR_TYPES; ++i) 1199958e1f0SArnaldo Carvalho de Melo __map_groups__fixup_end(self, i); 12023ea4a3fSArnaldo Carvalho de Melo } 12123ea4a3fSArnaldo Carvalho de Melo 12200a192b3SArnaldo Carvalho de Melo static struct symbol *symbol__new(u64 start, u64 len, const char *name) 12386470930SIngo Molnar { 12486470930SIngo Molnar size_t namelen = strlen(name) + 1; 12536479484SArnaldo Carvalho de Melo struct symbol *self = zalloc(symbol__priv_size + 12636479484SArnaldo Carvalho de Melo sizeof(*self) + namelen); 12736479484SArnaldo Carvalho de Melo if (self == NULL) 12886470930SIngo Molnar return NULL; 12986470930SIngo Molnar 13036479484SArnaldo Carvalho de Melo if (symbol__priv_size) 13100a192b3SArnaldo Carvalho de Melo self = ((void *)self) + symbol__priv_size; 13236479484SArnaldo Carvalho de Melo 13386470930SIngo Molnar self->start = start; 1346cfcc53eSMike Galbraith self->end = len ? start + len - 1 : start; 135e4204992SArnaldo Carvalho de Melo 1366beba7adSArnaldo Carvalho de Melo pr_debug3("%s: %s %#Lx-%#Lx\n", __func__, name, start, self->end); 137e4204992SArnaldo Carvalho de Melo 13886470930SIngo Molnar memcpy(self->name, name, namelen); 13986470930SIngo Molnar 14086470930SIngo Molnar return self; 14186470930SIngo Molnar } 14286470930SIngo Molnar 14300a192b3SArnaldo Carvalho de Melo static void symbol__delete(struct symbol *self) 14486470930SIngo Molnar { 14500a192b3SArnaldo Carvalho de Melo free(((void *)self) - symbol__priv_size); 14686470930SIngo Molnar } 14786470930SIngo Molnar 14886470930SIngo Molnar static size_t symbol__fprintf(struct symbol *self, FILE *fp) 14986470930SIngo Molnar { 15086470930SIngo Molnar return fprintf(fp, " %llx-%llx %s\n", 15186470930SIngo Molnar self->start, self->end, self->name); 15286470930SIngo Molnar } 15386470930SIngo Molnar 154cfc10d3bSArnaldo Carvalho de Melo static void dso__set_long_name(struct dso *self, char *name) 155cfc10d3bSArnaldo Carvalho de Melo { 156ef6ae724SArnaldo Carvalho de Melo if (name == NULL) 157ef6ae724SArnaldo Carvalho de Melo return; 158cfc10d3bSArnaldo Carvalho de Melo self->long_name = name; 159cfc10d3bSArnaldo Carvalho de Melo self->long_name_len = strlen(name); 160cfc10d3bSArnaldo Carvalho de Melo } 161cfc10d3bSArnaldo Carvalho de Melo 162cfc10d3bSArnaldo Carvalho de Melo static void dso__set_basename(struct dso *self) 163cfc10d3bSArnaldo Carvalho de Melo { 164cfc10d3bSArnaldo Carvalho de Melo self->short_name = basename(self->long_name); 165cfc10d3bSArnaldo Carvalho de Melo } 166cfc10d3bSArnaldo Carvalho de Melo 16700a192b3SArnaldo Carvalho de Melo struct dso *dso__new(const char *name) 16886470930SIngo Molnar { 16986470930SIngo Molnar struct dso *self = malloc(sizeof(*self) + strlen(name) + 1); 17086470930SIngo Molnar 17186470930SIngo Molnar if (self != NULL) { 1726a4694a4SArnaldo Carvalho de Melo int i; 17386470930SIngo Molnar strcpy(self->name, name); 174cfc10d3bSArnaldo Carvalho de Melo dso__set_long_name(self, self->name); 175439d473bSArnaldo Carvalho de Melo self->short_name = self->name; 1766a4694a4SArnaldo Carvalho de Melo for (i = 0; i < MAP__NR_TYPES; ++i) 1776a4694a4SArnaldo Carvalho de Melo self->symbols[i] = RB_ROOT; 1786a4694a4SArnaldo Carvalho de Melo self->find_symbol = dso__find_symbol; 17952d422deSArnaldo Carvalho de Melo self->slen_calculated = 0; 18094cb9e38SArnaldo Carvalho de Melo self->origin = DSO__ORIG_NOT_FOUND; 1818d06367fSArnaldo Carvalho de Melo self->loaded = 0; 1828d06367fSArnaldo Carvalho de Melo self->has_build_id = 0; 18386470930SIngo Molnar } 18486470930SIngo Molnar 18586470930SIngo Molnar return self; 18686470930SIngo Molnar } 18786470930SIngo Molnar 188fcf1203aSArnaldo Carvalho de Melo static void symbols__delete(struct rb_root *self) 18986470930SIngo Molnar { 19086470930SIngo Molnar struct symbol *pos; 191fcf1203aSArnaldo Carvalho de Melo struct rb_node *next = rb_first(self); 19286470930SIngo Molnar 19386470930SIngo Molnar while (next) { 19486470930SIngo Molnar pos = rb_entry(next, struct symbol, rb_node); 19586470930SIngo Molnar next = rb_next(&pos->rb_node); 196fcf1203aSArnaldo Carvalho de Melo rb_erase(&pos->rb_node, self); 19700a192b3SArnaldo Carvalho de Melo symbol__delete(pos); 19886470930SIngo Molnar } 19986470930SIngo Molnar } 20086470930SIngo Molnar 20186470930SIngo Molnar void dso__delete(struct dso *self) 20286470930SIngo Molnar { 2036a4694a4SArnaldo Carvalho de Melo int i; 2046a4694a4SArnaldo Carvalho de Melo for (i = 0; i < MAP__NR_TYPES; ++i) 2056a4694a4SArnaldo Carvalho de Melo symbols__delete(&self->symbols[i]); 206439d473bSArnaldo Carvalho de Melo if (self->long_name != self->name) 207439d473bSArnaldo Carvalho de Melo free(self->long_name); 20886470930SIngo Molnar free(self); 20986470930SIngo Molnar } 21086470930SIngo Molnar 2118d06367fSArnaldo Carvalho de Melo void dso__set_build_id(struct dso *self, void *build_id) 2128d06367fSArnaldo Carvalho de Melo { 2138d06367fSArnaldo Carvalho de Melo memcpy(self->build_id, build_id, sizeof(self->build_id)); 2148d06367fSArnaldo Carvalho de Melo self->has_build_id = 1; 2158d06367fSArnaldo Carvalho de Melo } 2168d06367fSArnaldo Carvalho de Melo 217fcf1203aSArnaldo Carvalho de Melo static void symbols__insert(struct rb_root *self, struct symbol *sym) 21886470930SIngo Molnar { 219fcf1203aSArnaldo Carvalho de Melo struct rb_node **p = &self->rb_node; 22086470930SIngo Molnar struct rb_node *parent = NULL; 2219cffa8d5SPaul Mackerras const u64 ip = sym->start; 22286470930SIngo Molnar struct symbol *s; 22386470930SIngo Molnar 22486470930SIngo Molnar while (*p != NULL) { 22586470930SIngo Molnar parent = *p; 22686470930SIngo Molnar s = rb_entry(parent, struct symbol, rb_node); 22786470930SIngo Molnar if (ip < s->start) 22886470930SIngo Molnar p = &(*p)->rb_left; 22986470930SIngo Molnar else 23086470930SIngo Molnar p = &(*p)->rb_right; 23186470930SIngo Molnar } 23286470930SIngo Molnar rb_link_node(&sym->rb_node, parent, p); 233fcf1203aSArnaldo Carvalho de Melo rb_insert_color(&sym->rb_node, self); 23486470930SIngo Molnar } 23586470930SIngo Molnar 236fcf1203aSArnaldo Carvalho de Melo static struct symbol *symbols__find(struct rb_root *self, u64 ip) 23786470930SIngo Molnar { 23886470930SIngo Molnar struct rb_node *n; 23986470930SIngo Molnar 24086470930SIngo Molnar if (self == NULL) 24186470930SIngo Molnar return NULL; 24286470930SIngo Molnar 243fcf1203aSArnaldo Carvalho de Melo n = self->rb_node; 24486470930SIngo Molnar 24586470930SIngo Molnar while (n) { 24686470930SIngo Molnar struct symbol *s = rb_entry(n, struct symbol, rb_node); 24786470930SIngo Molnar 24886470930SIngo Molnar if (ip < s->start) 24986470930SIngo Molnar n = n->rb_left; 25086470930SIngo Molnar else if (ip > s->end) 25186470930SIngo Molnar n = n->rb_right; 25286470930SIngo Molnar else 25386470930SIngo Molnar return s; 25486470930SIngo Molnar } 25586470930SIngo Molnar 25686470930SIngo Molnar return NULL; 25786470930SIngo Molnar } 25886470930SIngo Molnar 2596a4694a4SArnaldo Carvalho de Melo struct symbol *dso__find_symbol(struct dso *self, enum map_type type, u64 addr) 260fcf1203aSArnaldo Carvalho de Melo { 2616a4694a4SArnaldo Carvalho de Melo return symbols__find(&self->symbols[type], addr); 262fcf1203aSArnaldo Carvalho de Melo } 263fcf1203aSArnaldo Carvalho de Melo 2648d06367fSArnaldo Carvalho de Melo int build_id__sprintf(u8 *self, int len, char *bf) 2658d06367fSArnaldo Carvalho de Melo { 2668d06367fSArnaldo Carvalho de Melo char *bid = bf; 2678d06367fSArnaldo Carvalho de Melo u8 *raw = self; 2688d06367fSArnaldo Carvalho de Melo int i; 2698d06367fSArnaldo Carvalho de Melo 2708d06367fSArnaldo Carvalho de Melo for (i = 0; i < len; ++i) { 2718d06367fSArnaldo Carvalho de Melo sprintf(bid, "%02x", *raw); 2728d06367fSArnaldo Carvalho de Melo ++raw; 2738d06367fSArnaldo Carvalho de Melo bid += 2; 2748d06367fSArnaldo Carvalho de Melo } 2758d06367fSArnaldo Carvalho de Melo 2768d06367fSArnaldo Carvalho de Melo return raw - self; 2778d06367fSArnaldo Carvalho de Melo } 2788d06367fSArnaldo Carvalho de Melo 2799e03eb2dSArnaldo Carvalho de Melo size_t dso__fprintf_buildid(struct dso *self, FILE *fp) 28086470930SIngo Molnar { 2818d06367fSArnaldo Carvalho de Melo char sbuild_id[BUILD_ID_SIZE * 2 + 1]; 2828d06367fSArnaldo Carvalho de Melo 2838d06367fSArnaldo Carvalho de Melo build_id__sprintf(self->build_id, sizeof(self->build_id), sbuild_id); 2849e03eb2dSArnaldo Carvalho de Melo return fprintf(fp, "%s", sbuild_id); 2859e03eb2dSArnaldo Carvalho de Melo } 2869e03eb2dSArnaldo Carvalho de Melo 28795011c60SArnaldo Carvalho de Melo size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp) 2889e03eb2dSArnaldo Carvalho de Melo { 2899e03eb2dSArnaldo Carvalho de Melo struct rb_node *nd; 2909e03eb2dSArnaldo Carvalho de Melo size_t ret = fprintf(fp, "dso: %s (", self->short_name); 2919e03eb2dSArnaldo Carvalho de Melo 2929e03eb2dSArnaldo Carvalho de Melo ret += dso__fprintf_buildid(self, fp); 2936a4694a4SArnaldo Carvalho de Melo ret += fprintf(fp, ")\n"); 29495011c60SArnaldo Carvalho de Melo for (nd = rb_first(&self->symbols[type]); nd; nd = rb_next(nd)) { 29586470930SIngo Molnar struct symbol *pos = rb_entry(nd, struct symbol, rb_node); 29686470930SIngo Molnar ret += symbol__fprintf(pos, fp); 29786470930SIngo Molnar } 29886470930SIngo Molnar 29986470930SIngo Molnar return ret; 30086470930SIngo Molnar } 30186470930SIngo Molnar 3022e538c4aSArnaldo Carvalho de Melo /* 3032e538c4aSArnaldo Carvalho de Melo * Loads the function entries in /proc/kallsyms into kernel_map->dso, 3042e538c4aSArnaldo Carvalho de Melo * so that we can in the next step set the symbol ->end address and then 3052e538c4aSArnaldo Carvalho de Melo * call kernel_maps__split_kallsyms. 3062e538c4aSArnaldo Carvalho de Melo */ 3074e06255fSArnaldo Carvalho de Melo static int dso__load_all_kallsyms(struct dso *self, struct map *map) 30886470930SIngo Molnar { 30986470930SIngo Molnar char *line = NULL; 31086470930SIngo Molnar size_t n; 3114e06255fSArnaldo Carvalho de Melo struct rb_root *root = &self->symbols[map->type]; 31286470930SIngo Molnar FILE *file = fopen("/proc/kallsyms", "r"); 31386470930SIngo Molnar 31486470930SIngo Molnar if (file == NULL) 31586470930SIngo Molnar goto out_failure; 31686470930SIngo Molnar 31786470930SIngo Molnar while (!feof(file)) { 3189cffa8d5SPaul Mackerras u64 start; 31986470930SIngo Molnar struct symbol *sym; 32086470930SIngo Molnar int line_len, len; 32186470930SIngo Molnar char symbol_type; 3222e538c4aSArnaldo Carvalho de Melo char *symbol_name; 32386470930SIngo Molnar 32486470930SIngo Molnar line_len = getline(&line, &n, file); 32586470930SIngo Molnar if (line_len < 0) 32686470930SIngo Molnar break; 32786470930SIngo Molnar 32886470930SIngo Molnar if (!line) 32986470930SIngo Molnar goto out_failure; 33086470930SIngo Molnar 33186470930SIngo Molnar line[--line_len] = '\0'; /* \n */ 33286470930SIngo Molnar 33386470930SIngo Molnar len = hex2u64(line, &start); 33486470930SIngo Molnar 33586470930SIngo Molnar len++; 33686470930SIngo Molnar if (len + 2 >= line_len) 33786470930SIngo Molnar continue; 33886470930SIngo Molnar 33986470930SIngo Molnar symbol_type = toupper(line[len]); 340*6893d4eeSArnaldo Carvalho de Melo if (!symbol_type__is_a(symbol_type, map->type)) 34186470930SIngo Molnar continue; 342af427bf5SArnaldo Carvalho de Melo 343af427bf5SArnaldo Carvalho de Melo symbol_name = line + len + 2; 3442e538c4aSArnaldo Carvalho de Melo /* 3452e538c4aSArnaldo Carvalho de Melo * Will fix up the end later, when we have all symbols sorted. 3462e538c4aSArnaldo Carvalho de Melo */ 34700a192b3SArnaldo Carvalho de Melo sym = symbol__new(start, 0, symbol_name); 348af427bf5SArnaldo Carvalho de Melo 3492e538c4aSArnaldo Carvalho de Melo if (sym == NULL) 3502e538c4aSArnaldo Carvalho de Melo goto out_delete_line; 35182164161SArnaldo Carvalho de Melo /* 35282164161SArnaldo Carvalho de Melo * We will pass the symbols to the filter later, in 3534e06255fSArnaldo Carvalho de Melo * map__split_kallsyms, when we have split the maps per module 35482164161SArnaldo Carvalho de Melo */ 3554e06255fSArnaldo Carvalho de Melo symbols__insert(root, sym); 3562e538c4aSArnaldo Carvalho de Melo } 3572e538c4aSArnaldo Carvalho de Melo 3582e538c4aSArnaldo Carvalho de Melo free(line); 3592e538c4aSArnaldo Carvalho de Melo fclose(file); 3602e538c4aSArnaldo Carvalho de Melo 3612e538c4aSArnaldo Carvalho de Melo return 0; 3622e538c4aSArnaldo Carvalho de Melo 3632e538c4aSArnaldo Carvalho de Melo out_delete_line: 3642e538c4aSArnaldo Carvalho de Melo free(line); 3652e538c4aSArnaldo Carvalho de Melo out_failure: 3662e538c4aSArnaldo Carvalho de Melo return -1; 3672e538c4aSArnaldo Carvalho de Melo } 3682e538c4aSArnaldo Carvalho de Melo 3692e538c4aSArnaldo Carvalho de Melo /* 3702e538c4aSArnaldo Carvalho de Melo * Split the symbols into maps, making sure there are no overlaps, i.e. the 3712e538c4aSArnaldo Carvalho de Melo * kernel range is broken in several maps, named [kernel].N, as we don't have 3722e538c4aSArnaldo Carvalho de Melo * the original ELF section names vmlinux have. 3732e538c4aSArnaldo Carvalho de Melo */ 3749958e1f0SArnaldo Carvalho de Melo static int dso__split_kallsyms(struct dso *self, struct map *map, 3759958e1f0SArnaldo Carvalho de Melo struct map_groups *mg, symbol_filter_t filter) 3762e538c4aSArnaldo Carvalho de Melo { 3774e06255fSArnaldo Carvalho de Melo struct map *curr_map = map; 3782e538c4aSArnaldo Carvalho de Melo struct symbol *pos; 3792e538c4aSArnaldo Carvalho de Melo int count = 0; 3804e06255fSArnaldo Carvalho de Melo struct rb_root *root = &self->symbols[map->type]; 3814e06255fSArnaldo Carvalho de Melo struct rb_node *next = rb_first(root); 3822e538c4aSArnaldo Carvalho de Melo int kernel_range = 0; 3832e538c4aSArnaldo Carvalho de Melo 3842e538c4aSArnaldo Carvalho de Melo while (next) { 3852e538c4aSArnaldo Carvalho de Melo char *module; 3862e538c4aSArnaldo Carvalho de Melo 3872e538c4aSArnaldo Carvalho de Melo pos = rb_entry(next, struct symbol, rb_node); 3882e538c4aSArnaldo Carvalho de Melo next = rb_next(&pos->rb_node); 3892e538c4aSArnaldo Carvalho de Melo 3902e538c4aSArnaldo Carvalho de Melo module = strchr(pos->name, '\t'); 3912e538c4aSArnaldo Carvalho de Melo if (module) { 3929958e1f0SArnaldo Carvalho de Melo if (!mg->use_modules) 3931de8e245SArnaldo Carvalho de Melo goto discard_symbol; 3941de8e245SArnaldo Carvalho de Melo 3952e538c4aSArnaldo Carvalho de Melo *module++ = '\0'; 3962e538c4aSArnaldo Carvalho de Melo 3974e06255fSArnaldo Carvalho de Melo if (strcmp(self->name, module)) { 3989958e1f0SArnaldo Carvalho de Melo curr_map = map_groups__find_by_name(mg, module); 3994e06255fSArnaldo Carvalho de Melo if (curr_map == NULL) { 40095011c60SArnaldo Carvalho de Melo pr_debug("/proc/{kallsyms,modules} " 4016beba7adSArnaldo Carvalho de Melo "inconsistency!\n"); 402af427bf5SArnaldo Carvalho de Melo return -1; 403af427bf5SArnaldo Carvalho de Melo } 404af427bf5SArnaldo Carvalho de Melo } 40586470930SIngo Molnar /* 4062e538c4aSArnaldo Carvalho de Melo * So that we look just like we get from .ko files, 4072e538c4aSArnaldo Carvalho de Melo * i.e. not prelinked, relative to map->start. 40886470930SIngo Molnar */ 4094e06255fSArnaldo Carvalho de Melo pos->start = curr_map->map_ip(curr_map, pos->start); 4104e06255fSArnaldo Carvalho de Melo pos->end = curr_map->map_ip(curr_map, pos->end); 4114e06255fSArnaldo Carvalho de Melo } else if (curr_map != map) { 4122e538c4aSArnaldo Carvalho de Melo char dso_name[PATH_MAX]; 4132e538c4aSArnaldo Carvalho de Melo struct dso *dso; 41486470930SIngo Molnar 4152e538c4aSArnaldo Carvalho de Melo snprintf(dso_name, sizeof(dso_name), "[kernel].%d", 4162e538c4aSArnaldo Carvalho de Melo kernel_range++); 41786470930SIngo Molnar 41800a192b3SArnaldo Carvalho de Melo dso = dso__new(dso_name); 4192e538c4aSArnaldo Carvalho de Melo if (dso == NULL) 4202e538c4aSArnaldo Carvalho de Melo return -1; 4212e538c4aSArnaldo Carvalho de Melo 4224e06255fSArnaldo Carvalho de Melo curr_map = map__new2(pos->start, dso, map->type); 4232e538c4aSArnaldo Carvalho de Melo if (map == NULL) { 4242e538c4aSArnaldo Carvalho de Melo dso__delete(dso); 4252e538c4aSArnaldo Carvalho de Melo return -1; 4262e538c4aSArnaldo Carvalho de Melo } 4272e538c4aSArnaldo Carvalho de Melo 4284e06255fSArnaldo Carvalho de Melo curr_map->map_ip = curr_map->unmap_ip = identity__map_ip; 4299958e1f0SArnaldo Carvalho de Melo map_groups__insert(mg, curr_map); 4302e538c4aSArnaldo Carvalho de Melo ++kernel_range; 4312e538c4aSArnaldo Carvalho de Melo } 4322e538c4aSArnaldo Carvalho de Melo 4334e06255fSArnaldo Carvalho de Melo if (filter && filter(curr_map, pos)) { 4341de8e245SArnaldo Carvalho de Melo discard_symbol: rb_erase(&pos->rb_node, root); 43500a192b3SArnaldo Carvalho de Melo symbol__delete(pos); 4362e538c4aSArnaldo Carvalho de Melo } else { 4374e06255fSArnaldo Carvalho de Melo if (curr_map != map) { 4384e06255fSArnaldo Carvalho de Melo rb_erase(&pos->rb_node, root); 4394e06255fSArnaldo Carvalho de Melo symbols__insert(&curr_map->dso->symbols[curr_map->type], pos); 4402e538c4aSArnaldo Carvalho de Melo } 4419974f496SMike Galbraith count++; 4429974f496SMike Galbraith } 44386470930SIngo Molnar } 44486470930SIngo Molnar 4459974f496SMike Galbraith return count; 44686470930SIngo Molnar } 44786470930SIngo Molnar 4482e538c4aSArnaldo Carvalho de Melo 4494e06255fSArnaldo Carvalho de Melo static int dso__load_kallsyms(struct dso *self, struct map *map, 4509958e1f0SArnaldo Carvalho de Melo struct map_groups *mg, symbol_filter_t filter) 4512e538c4aSArnaldo Carvalho de Melo { 4524e06255fSArnaldo Carvalho de Melo if (dso__load_all_kallsyms(self, map) < 0) 4532e538c4aSArnaldo Carvalho de Melo return -1; 4542e538c4aSArnaldo Carvalho de Melo 4554e06255fSArnaldo Carvalho de Melo symbols__fixup_end(&self->symbols[map->type]); 4564e06255fSArnaldo Carvalho de Melo self->origin = DSO__ORIG_KERNEL; 4572e538c4aSArnaldo Carvalho de Melo 4589958e1f0SArnaldo Carvalho de Melo return dso__split_kallsyms(self, map, mg, filter); 45923ea4a3fSArnaldo Carvalho de Melo } 46023ea4a3fSArnaldo Carvalho de Melo 46123ea4a3fSArnaldo Carvalho de Melo size_t kernel_maps__fprintf(FILE *fp) 46223ea4a3fSArnaldo Carvalho de Melo { 46323ea4a3fSArnaldo Carvalho de Melo size_t printed = fprintf(fp, "Kernel maps:\n"); 4649958e1f0SArnaldo Carvalho de Melo printed += map_groups__fprintf_maps(kmaps, fp); 4656beba7adSArnaldo Carvalho de Melo return printed + fprintf(fp, "END kernel maps\n"); 466af427bf5SArnaldo Carvalho de Melo } 467af427bf5SArnaldo Carvalho de Melo 468439d473bSArnaldo Carvalho de Melo static int dso__load_perf_map(struct dso *self, struct map *map, 4696beba7adSArnaldo Carvalho de Melo symbol_filter_t filter) 47080d496beSPekka Enberg { 47180d496beSPekka Enberg char *line = NULL; 47280d496beSPekka Enberg size_t n; 47380d496beSPekka Enberg FILE *file; 47480d496beSPekka Enberg int nr_syms = 0; 47580d496beSPekka Enberg 476439d473bSArnaldo Carvalho de Melo file = fopen(self->long_name, "r"); 47780d496beSPekka Enberg if (file == NULL) 47880d496beSPekka Enberg goto out_failure; 47980d496beSPekka Enberg 48080d496beSPekka Enberg while (!feof(file)) { 4819cffa8d5SPaul Mackerras u64 start, size; 48280d496beSPekka Enberg struct symbol *sym; 48380d496beSPekka Enberg int line_len, len; 48480d496beSPekka Enberg 48580d496beSPekka Enberg line_len = getline(&line, &n, file); 48680d496beSPekka Enberg if (line_len < 0) 48780d496beSPekka Enberg break; 48880d496beSPekka Enberg 48980d496beSPekka Enberg if (!line) 49080d496beSPekka Enberg goto out_failure; 49180d496beSPekka Enberg 49280d496beSPekka Enberg line[--line_len] = '\0'; /* \n */ 49380d496beSPekka Enberg 49480d496beSPekka Enberg len = hex2u64(line, &start); 49580d496beSPekka Enberg 49680d496beSPekka Enberg len++; 49780d496beSPekka Enberg if (len + 2 >= line_len) 49880d496beSPekka Enberg continue; 49980d496beSPekka Enberg 50080d496beSPekka Enberg len += hex2u64(line + len, &size); 50180d496beSPekka Enberg 50280d496beSPekka Enberg len++; 50380d496beSPekka Enberg if (len + 2 >= line_len) 50480d496beSPekka Enberg continue; 50580d496beSPekka Enberg 50600a192b3SArnaldo Carvalho de Melo sym = symbol__new(start, size, line + len); 50780d496beSPekka Enberg 50880d496beSPekka Enberg if (sym == NULL) 50980d496beSPekka Enberg goto out_delete_line; 51080d496beSPekka Enberg 511439d473bSArnaldo Carvalho de Melo if (filter && filter(map, sym)) 51200a192b3SArnaldo Carvalho de Melo symbol__delete(sym); 51380d496beSPekka Enberg else { 5146a4694a4SArnaldo Carvalho de Melo symbols__insert(&self->symbols[map->type], sym); 51580d496beSPekka Enberg nr_syms++; 51680d496beSPekka Enberg } 51780d496beSPekka Enberg } 51880d496beSPekka Enberg 51980d496beSPekka Enberg free(line); 52080d496beSPekka Enberg fclose(file); 52180d496beSPekka Enberg 52280d496beSPekka Enberg return nr_syms; 52380d496beSPekka Enberg 52480d496beSPekka Enberg out_delete_line: 52580d496beSPekka Enberg free(line); 52680d496beSPekka Enberg out_failure: 52780d496beSPekka Enberg return -1; 52880d496beSPekka Enberg } 52980d496beSPekka Enberg 53086470930SIngo Molnar /** 53186470930SIngo Molnar * elf_symtab__for_each_symbol - iterate thru all the symbols 53286470930SIngo Molnar * 53386470930SIngo Molnar * @self: struct elf_symtab instance to iterate 53483a0944fSIngo Molnar * @idx: uint32_t idx 53586470930SIngo Molnar * @sym: GElf_Sym iterator 53686470930SIngo Molnar */ 53783a0944fSIngo Molnar #define elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) \ 53883a0944fSIngo Molnar for (idx = 0, gelf_getsym(syms, idx, &sym);\ 53983a0944fSIngo Molnar idx < nr_syms; \ 54083a0944fSIngo Molnar idx++, gelf_getsym(syms, idx, &sym)) 54186470930SIngo Molnar 54286470930SIngo Molnar static inline uint8_t elf_sym__type(const GElf_Sym *sym) 54386470930SIngo Molnar { 54486470930SIngo Molnar return GELF_ST_TYPE(sym->st_info); 54586470930SIngo Molnar } 54686470930SIngo Molnar 54786470930SIngo Molnar static inline int elf_sym__is_function(const GElf_Sym *sym) 54886470930SIngo Molnar { 54986470930SIngo Molnar return elf_sym__type(sym) == STT_FUNC && 55086470930SIngo Molnar sym->st_name != 0 && 55181833130SArnaldo Carvalho de Melo sym->st_shndx != SHN_UNDEF; 55286470930SIngo Molnar } 55386470930SIngo Molnar 5546cfcc53eSMike Galbraith static inline int elf_sym__is_label(const GElf_Sym *sym) 5556cfcc53eSMike Galbraith { 5566cfcc53eSMike Galbraith return elf_sym__type(sym) == STT_NOTYPE && 5576cfcc53eSMike Galbraith sym->st_name != 0 && 5586cfcc53eSMike Galbraith sym->st_shndx != SHN_UNDEF && 5596cfcc53eSMike Galbraith sym->st_shndx != SHN_ABS; 5606cfcc53eSMike Galbraith } 5616cfcc53eSMike Galbraith 5626cfcc53eSMike Galbraith static inline const char *elf_sec__name(const GElf_Shdr *shdr, 5636cfcc53eSMike Galbraith const Elf_Data *secstrs) 5646cfcc53eSMike Galbraith { 5656cfcc53eSMike Galbraith return secstrs->d_buf + shdr->sh_name; 5666cfcc53eSMike Galbraith } 5676cfcc53eSMike Galbraith 5686cfcc53eSMike Galbraith static inline int elf_sec__is_text(const GElf_Shdr *shdr, 5696cfcc53eSMike Galbraith const Elf_Data *secstrs) 5706cfcc53eSMike Galbraith { 5716cfcc53eSMike Galbraith return strstr(elf_sec__name(shdr, secstrs), "text") != NULL; 5726cfcc53eSMike Galbraith } 5736cfcc53eSMike Galbraith 57486470930SIngo Molnar static inline const char *elf_sym__name(const GElf_Sym *sym, 57586470930SIngo Molnar const Elf_Data *symstrs) 57686470930SIngo Molnar { 57786470930SIngo Molnar return symstrs->d_buf + sym->st_name; 57886470930SIngo Molnar } 57986470930SIngo Molnar 58086470930SIngo Molnar static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, 58186470930SIngo Molnar GElf_Shdr *shp, const char *name, 58283a0944fSIngo Molnar size_t *idx) 58386470930SIngo Molnar { 58486470930SIngo Molnar Elf_Scn *sec = NULL; 58586470930SIngo Molnar size_t cnt = 1; 58686470930SIngo Molnar 58786470930SIngo Molnar while ((sec = elf_nextscn(elf, sec)) != NULL) { 58886470930SIngo Molnar char *str; 58986470930SIngo Molnar 59086470930SIngo Molnar gelf_getshdr(sec, shp); 59186470930SIngo Molnar str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name); 59286470930SIngo Molnar if (!strcmp(name, str)) { 59383a0944fSIngo Molnar if (idx) 59483a0944fSIngo Molnar *idx = cnt; 59586470930SIngo Molnar break; 59686470930SIngo Molnar } 59786470930SIngo Molnar ++cnt; 59886470930SIngo Molnar } 59986470930SIngo Molnar 60086470930SIngo Molnar return sec; 60186470930SIngo Molnar } 60286470930SIngo Molnar 60386470930SIngo Molnar #define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \ 60486470930SIngo Molnar for (idx = 0, pos = gelf_getrel(reldata, 0, &pos_mem); \ 60586470930SIngo Molnar idx < nr_entries; \ 60686470930SIngo Molnar ++idx, pos = gelf_getrel(reldata, idx, &pos_mem)) 60786470930SIngo Molnar 60886470930SIngo Molnar #define elf_section__for_each_rela(reldata, pos, pos_mem, idx, nr_entries) \ 60986470930SIngo Molnar for (idx = 0, pos = gelf_getrela(reldata, 0, &pos_mem); \ 61086470930SIngo Molnar idx < nr_entries; \ 61186470930SIngo Molnar ++idx, pos = gelf_getrela(reldata, idx, &pos_mem)) 61286470930SIngo Molnar 613a25e46c4SArnaldo Carvalho de Melo /* 614a25e46c4SArnaldo Carvalho de Melo * We need to check if we have a .dynsym, so that we can handle the 615a25e46c4SArnaldo Carvalho de Melo * .plt, synthesizing its symbols, that aren't on the symtabs (be it 616a25e46c4SArnaldo Carvalho de Melo * .dynsym or .symtab). 617a25e46c4SArnaldo Carvalho de Melo * And always look at the original dso, not at debuginfo packages, that 618a25e46c4SArnaldo Carvalho de Melo * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS). 619a25e46c4SArnaldo Carvalho de Melo */ 62082164161SArnaldo Carvalho de Melo static int dso__synthesize_plt_symbols(struct dso *self, struct map *map, 62182164161SArnaldo Carvalho de Melo symbol_filter_t filter) 62286470930SIngo Molnar { 62386470930SIngo Molnar uint32_t nr_rel_entries, idx; 62486470930SIngo Molnar GElf_Sym sym; 6259cffa8d5SPaul Mackerras u64 plt_offset; 62686470930SIngo Molnar GElf_Shdr shdr_plt; 62786470930SIngo Molnar struct symbol *f; 628a25e46c4SArnaldo Carvalho de Melo GElf_Shdr shdr_rel_plt, shdr_dynsym; 62986470930SIngo Molnar Elf_Data *reldata, *syms, *symstrs; 630a25e46c4SArnaldo Carvalho de Melo Elf_Scn *scn_plt_rel, *scn_symstrs, *scn_dynsym; 631a25e46c4SArnaldo Carvalho de Melo size_t dynsym_idx; 632a25e46c4SArnaldo Carvalho de Melo GElf_Ehdr ehdr; 63386470930SIngo Molnar char sympltname[1024]; 634a25e46c4SArnaldo Carvalho de Melo Elf *elf; 635a25e46c4SArnaldo Carvalho de Melo int nr = 0, symidx, fd, err = 0; 63686470930SIngo Molnar 637439d473bSArnaldo Carvalho de Melo fd = open(self->long_name, O_RDONLY); 638a25e46c4SArnaldo Carvalho de Melo if (fd < 0) 639a25e46c4SArnaldo Carvalho de Melo goto out; 640a25e46c4SArnaldo Carvalho de Melo 64184087126SMarti Raudsepp elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 642a25e46c4SArnaldo Carvalho de Melo if (elf == NULL) 643a25e46c4SArnaldo Carvalho de Melo goto out_close; 644a25e46c4SArnaldo Carvalho de Melo 645a25e46c4SArnaldo Carvalho de Melo if (gelf_getehdr(elf, &ehdr) == NULL) 646a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 647a25e46c4SArnaldo Carvalho de Melo 648a25e46c4SArnaldo Carvalho de Melo scn_dynsym = elf_section_by_name(elf, &ehdr, &shdr_dynsym, 649a25e46c4SArnaldo Carvalho de Melo ".dynsym", &dynsym_idx); 650a25e46c4SArnaldo Carvalho de Melo if (scn_dynsym == NULL) 651a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 652a25e46c4SArnaldo Carvalho de Melo 653a25e46c4SArnaldo Carvalho de Melo scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt, 65486470930SIngo Molnar ".rela.plt", NULL); 65586470930SIngo Molnar if (scn_plt_rel == NULL) { 656a25e46c4SArnaldo Carvalho de Melo scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt, 65786470930SIngo Molnar ".rel.plt", NULL); 65886470930SIngo Molnar if (scn_plt_rel == NULL) 659a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 66086470930SIngo Molnar } 66186470930SIngo Molnar 662a25e46c4SArnaldo Carvalho de Melo err = -1; 66386470930SIngo Molnar 664a25e46c4SArnaldo Carvalho de Melo if (shdr_rel_plt.sh_link != dynsym_idx) 665a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 666a25e46c4SArnaldo Carvalho de Melo 667a25e46c4SArnaldo Carvalho de Melo if (elf_section_by_name(elf, &ehdr, &shdr_plt, ".plt", NULL) == NULL) 668a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 66986470930SIngo Molnar 67086470930SIngo Molnar /* 67183a0944fSIngo Molnar * Fetch the relocation section to find the idxes to the GOT 67286470930SIngo Molnar * and the symbols in the .dynsym they refer to. 67386470930SIngo Molnar */ 67486470930SIngo Molnar reldata = elf_getdata(scn_plt_rel, NULL); 67586470930SIngo Molnar if (reldata == NULL) 676a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 67786470930SIngo Molnar 67886470930SIngo Molnar syms = elf_getdata(scn_dynsym, NULL); 67986470930SIngo Molnar if (syms == NULL) 680a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 68186470930SIngo Molnar 682a25e46c4SArnaldo Carvalho de Melo scn_symstrs = elf_getscn(elf, shdr_dynsym.sh_link); 68386470930SIngo Molnar if (scn_symstrs == NULL) 684a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 68586470930SIngo Molnar 68686470930SIngo Molnar symstrs = elf_getdata(scn_symstrs, NULL); 68786470930SIngo Molnar if (symstrs == NULL) 688a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 68986470930SIngo Molnar 69086470930SIngo Molnar nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize; 69186470930SIngo Molnar plt_offset = shdr_plt.sh_offset; 69286470930SIngo Molnar 69386470930SIngo Molnar if (shdr_rel_plt.sh_type == SHT_RELA) { 69486470930SIngo Molnar GElf_Rela pos_mem, *pos; 69586470930SIngo Molnar 69686470930SIngo Molnar elf_section__for_each_rela(reldata, pos, pos_mem, idx, 69786470930SIngo Molnar nr_rel_entries) { 69886470930SIngo Molnar symidx = GELF_R_SYM(pos->r_info); 69986470930SIngo Molnar plt_offset += shdr_plt.sh_entsize; 70086470930SIngo Molnar gelf_getsym(syms, symidx, &sym); 70186470930SIngo Molnar snprintf(sympltname, sizeof(sympltname), 70286470930SIngo Molnar "%s@plt", elf_sym__name(&sym, symstrs)); 70386470930SIngo Molnar 70486470930SIngo Molnar f = symbol__new(plt_offset, shdr_plt.sh_entsize, 70500a192b3SArnaldo Carvalho de Melo sympltname); 70686470930SIngo Molnar if (!f) 707a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 70886470930SIngo Molnar 70982164161SArnaldo Carvalho de Melo if (filter && filter(map, f)) 71082164161SArnaldo Carvalho de Melo symbol__delete(f); 71182164161SArnaldo Carvalho de Melo else { 7126a4694a4SArnaldo Carvalho de Melo symbols__insert(&self->symbols[map->type], f); 71386470930SIngo Molnar ++nr; 71486470930SIngo Molnar } 71582164161SArnaldo Carvalho de Melo } 71686470930SIngo Molnar } else if (shdr_rel_plt.sh_type == SHT_REL) { 71786470930SIngo Molnar GElf_Rel pos_mem, *pos; 71886470930SIngo Molnar elf_section__for_each_rel(reldata, pos, pos_mem, idx, 71986470930SIngo Molnar nr_rel_entries) { 72086470930SIngo Molnar symidx = GELF_R_SYM(pos->r_info); 72186470930SIngo Molnar plt_offset += shdr_plt.sh_entsize; 72286470930SIngo Molnar gelf_getsym(syms, symidx, &sym); 72386470930SIngo Molnar snprintf(sympltname, sizeof(sympltname), 72486470930SIngo Molnar "%s@plt", elf_sym__name(&sym, symstrs)); 72586470930SIngo Molnar 72686470930SIngo Molnar f = symbol__new(plt_offset, shdr_plt.sh_entsize, 72700a192b3SArnaldo Carvalho de Melo sympltname); 72886470930SIngo Molnar if (!f) 729a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 73086470930SIngo Molnar 73182164161SArnaldo Carvalho de Melo if (filter && filter(map, f)) 73282164161SArnaldo Carvalho de Melo symbol__delete(f); 73382164161SArnaldo Carvalho de Melo else { 7346a4694a4SArnaldo Carvalho de Melo symbols__insert(&self->symbols[map->type], f); 73586470930SIngo Molnar ++nr; 73686470930SIngo Molnar } 73786470930SIngo Molnar } 73882164161SArnaldo Carvalho de Melo } 73986470930SIngo Molnar 740a25e46c4SArnaldo Carvalho de Melo err = 0; 741a25e46c4SArnaldo Carvalho de Melo out_elf_end: 742a25e46c4SArnaldo Carvalho de Melo elf_end(elf); 743a25e46c4SArnaldo Carvalho de Melo out_close: 744a25e46c4SArnaldo Carvalho de Melo close(fd); 745a25e46c4SArnaldo Carvalho de Melo 746a25e46c4SArnaldo Carvalho de Melo if (err == 0) 74786470930SIngo Molnar return nr; 748a25e46c4SArnaldo Carvalho de Melo out: 7496beba7adSArnaldo Carvalho de Melo pr_warning("%s: problems reading %s PLT info.\n", 750439d473bSArnaldo Carvalho de Melo __func__, self->long_name); 751a25e46c4SArnaldo Carvalho de Melo return 0; 75286470930SIngo Molnar } 75386470930SIngo Molnar 75495011c60SArnaldo Carvalho de Melo static int dso__load_sym(struct dso *self, struct map *map, 7559958e1f0SArnaldo Carvalho de Melo struct map_groups *mg, const char *name, int fd, 75695011c60SArnaldo Carvalho de Melo symbol_filter_t filter, int kernel, int kmodule) 75786470930SIngo Molnar { 7582e538c4aSArnaldo Carvalho de Melo struct map *curr_map = map; 7592e538c4aSArnaldo Carvalho de Melo struct dso *curr_dso = self; 7602e538c4aSArnaldo Carvalho de Melo size_t dso_name_len = strlen(self->short_name); 7616cfcc53eSMike Galbraith Elf_Data *symstrs, *secstrs; 76286470930SIngo Molnar uint32_t nr_syms; 76386470930SIngo Molnar int err = -1; 76483a0944fSIngo Molnar uint32_t idx; 76586470930SIngo Molnar GElf_Ehdr ehdr; 76686470930SIngo Molnar GElf_Shdr shdr; 76786470930SIngo Molnar Elf_Data *syms; 76886470930SIngo Molnar GElf_Sym sym; 769a25e46c4SArnaldo Carvalho de Melo Elf_Scn *sec, *sec_strndx; 77086470930SIngo Molnar Elf *elf; 771439d473bSArnaldo Carvalho de Melo int nr = 0; 77286470930SIngo Molnar 77384087126SMarti Raudsepp elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 77486470930SIngo Molnar if (elf == NULL) { 7756beba7adSArnaldo Carvalho de Melo pr_err("%s: cannot read %s ELF file.\n", __func__, name); 77686470930SIngo Molnar goto out_close; 77786470930SIngo Molnar } 77886470930SIngo Molnar 77986470930SIngo Molnar if (gelf_getehdr(elf, &ehdr) == NULL) { 7806beba7adSArnaldo Carvalho de Melo pr_err("%s: cannot get elf header.\n", __func__); 78186470930SIngo Molnar goto out_elf_end; 78286470930SIngo Molnar } 78386470930SIngo Molnar 78486470930SIngo Molnar sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL); 78586470930SIngo Molnar if (sec == NULL) { 786a25e46c4SArnaldo Carvalho de Melo sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL); 787a25e46c4SArnaldo Carvalho de Melo if (sec == NULL) 78886470930SIngo Molnar goto out_elf_end; 78986470930SIngo Molnar } 79086470930SIngo Molnar 79186470930SIngo Molnar syms = elf_getdata(sec, NULL); 79286470930SIngo Molnar if (syms == NULL) 79386470930SIngo Molnar goto out_elf_end; 79486470930SIngo Molnar 79586470930SIngo Molnar sec = elf_getscn(elf, shdr.sh_link); 79686470930SIngo Molnar if (sec == NULL) 79786470930SIngo Molnar goto out_elf_end; 79886470930SIngo Molnar 79986470930SIngo Molnar symstrs = elf_getdata(sec, NULL); 80086470930SIngo Molnar if (symstrs == NULL) 80186470930SIngo Molnar goto out_elf_end; 80286470930SIngo Molnar 8036cfcc53eSMike Galbraith sec_strndx = elf_getscn(elf, ehdr.e_shstrndx); 8046cfcc53eSMike Galbraith if (sec_strndx == NULL) 8056cfcc53eSMike Galbraith goto out_elf_end; 8066cfcc53eSMike Galbraith 8076cfcc53eSMike Galbraith secstrs = elf_getdata(sec_strndx, NULL); 8089b30a26bSStoyan Gaydarov if (secstrs == NULL) 8096cfcc53eSMike Galbraith goto out_elf_end; 8106cfcc53eSMike Galbraith 81186470930SIngo Molnar nr_syms = shdr.sh_size / shdr.sh_entsize; 81286470930SIngo Molnar 813e9fbc9dcSArjan van de Ven memset(&sym, 0, sizeof(sym)); 814d20ff6bdSMike Galbraith if (!kernel) { 81530d7a77dSArnaldo Carvalho de Melo self->adjust_symbols = (ehdr.e_type == ET_EXEC || 81630d7a77dSArnaldo Carvalho de Melo elf_section_by_name(elf, &ehdr, &shdr, 817f5812a7aSArnaldo Carvalho de Melo ".gnu.prelink_undo", 81830d7a77dSArnaldo Carvalho de Melo NULL) != NULL); 819d20ff6bdSMike Galbraith } else self->adjust_symbols = 0; 820d20ff6bdSMike Galbraith 82183a0944fSIngo Molnar elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) { 82286470930SIngo Molnar struct symbol *f; 82383a0944fSIngo Molnar const char *elf_name; 8242e538c4aSArnaldo Carvalho de Melo char *demangled = NULL; 8256cfcc53eSMike Galbraith int is_label = elf_sym__is_label(&sym); 8266cfcc53eSMike Galbraith const char *section_name; 82786470930SIngo Molnar 8286cfcc53eSMike Galbraith if (!is_label && !elf_sym__is_function(&sym)) 82986470930SIngo Molnar continue; 83086470930SIngo Molnar 83186470930SIngo Molnar sec = elf_getscn(elf, sym.st_shndx); 83286470930SIngo Molnar if (!sec) 83386470930SIngo Molnar goto out_elf_end; 83486470930SIngo Molnar 83586470930SIngo Molnar gelf_getshdr(sec, &shdr); 8366cfcc53eSMike Galbraith 8376cfcc53eSMike Galbraith if (is_label && !elf_sec__is_text(&shdr, secstrs)) 8386cfcc53eSMike Galbraith continue; 8396cfcc53eSMike Galbraith 8402e538c4aSArnaldo Carvalho de Melo elf_name = elf_sym__name(&sym, symstrs); 8416cfcc53eSMike Galbraith section_name = elf_sec__name(&shdr, secstrs); 84286470930SIngo Molnar 8432e538c4aSArnaldo Carvalho de Melo if (kernel || kmodule) { 8442e538c4aSArnaldo Carvalho de Melo char dso_name[PATH_MAX]; 8452e538c4aSArnaldo Carvalho de Melo 8462e538c4aSArnaldo Carvalho de Melo if (strcmp(section_name, 8472e538c4aSArnaldo Carvalho de Melo curr_dso->short_name + dso_name_len) == 0) 8482e538c4aSArnaldo Carvalho de Melo goto new_symbol; 8492e538c4aSArnaldo Carvalho de Melo 8502e538c4aSArnaldo Carvalho de Melo if (strcmp(section_name, ".text") == 0) { 8512e538c4aSArnaldo Carvalho de Melo curr_map = map; 8522e538c4aSArnaldo Carvalho de Melo curr_dso = self; 8532e538c4aSArnaldo Carvalho de Melo goto new_symbol; 854af427bf5SArnaldo Carvalho de Melo } 855af427bf5SArnaldo Carvalho de Melo 8562e538c4aSArnaldo Carvalho de Melo snprintf(dso_name, sizeof(dso_name), 8572e538c4aSArnaldo Carvalho de Melo "%s%s", self->short_name, section_name); 8582e538c4aSArnaldo Carvalho de Melo 8599958e1f0SArnaldo Carvalho de Melo curr_map = map_groups__find_by_name(mg, dso_name); 8602e538c4aSArnaldo Carvalho de Melo if (curr_map == NULL) { 8612e538c4aSArnaldo Carvalho de Melo u64 start = sym.st_value; 8622e538c4aSArnaldo Carvalho de Melo 8632e538c4aSArnaldo Carvalho de Melo if (kmodule) 8642e538c4aSArnaldo Carvalho de Melo start += map->start + shdr.sh_offset; 8652e538c4aSArnaldo Carvalho de Melo 86600a192b3SArnaldo Carvalho de Melo curr_dso = dso__new(dso_name); 8672e538c4aSArnaldo Carvalho de Melo if (curr_dso == NULL) 8682e538c4aSArnaldo Carvalho de Melo goto out_elf_end; 8693610583cSArnaldo Carvalho de Melo curr_map = map__new2(start, curr_dso, 8703610583cSArnaldo Carvalho de Melo MAP__FUNCTION); 8712e538c4aSArnaldo Carvalho de Melo if (curr_map == NULL) { 8722e538c4aSArnaldo Carvalho de Melo dso__delete(curr_dso); 8732e538c4aSArnaldo Carvalho de Melo goto out_elf_end; 8742e538c4aSArnaldo Carvalho de Melo } 875ed52ce2eSArnaldo Carvalho de Melo curr_map->map_ip = identity__map_ip; 876ed52ce2eSArnaldo Carvalho de Melo curr_map->unmap_ip = identity__map_ip; 8772e538c4aSArnaldo Carvalho de Melo curr_dso->origin = DSO__ORIG_KERNEL; 8789958e1f0SArnaldo Carvalho de Melo map_groups__insert(kmaps, curr_map); 879b0da954aSArnaldo Carvalho de Melo dsos__add(&dsos__kernel, curr_dso); 8802e538c4aSArnaldo Carvalho de Melo } else 8812e538c4aSArnaldo Carvalho de Melo curr_dso = curr_map->dso; 8822e538c4aSArnaldo Carvalho de Melo 8832e538c4aSArnaldo Carvalho de Melo goto new_symbol; 8842e538c4aSArnaldo Carvalho de Melo } 8852e538c4aSArnaldo Carvalho de Melo 8862e538c4aSArnaldo Carvalho de Melo if (curr_dso->adjust_symbols) { 8876beba7adSArnaldo Carvalho de Melo pr_debug2("adjusting symbol: st_value: %Lx sh_addr: " 8886beba7adSArnaldo Carvalho de Melo "%Lx sh_offset: %Lx\n", (u64)sym.st_value, 8896beba7adSArnaldo Carvalho de Melo (u64)shdr.sh_addr, (u64)shdr.sh_offset); 89086470930SIngo Molnar sym.st_value -= shdr.sh_addr - shdr.sh_offset; 891af427bf5SArnaldo Carvalho de Melo } 89228ac909bSArnaldo Carvalho de Melo /* 89328ac909bSArnaldo Carvalho de Melo * We need to figure out if the object was created from C++ sources 89428ac909bSArnaldo Carvalho de Melo * DWARF DW_compile_unit has this, but we don't always have access 89528ac909bSArnaldo Carvalho de Melo * to it... 89628ac909bSArnaldo Carvalho de Melo */ 89783a0944fSIngo Molnar demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI); 89828ac909bSArnaldo Carvalho de Melo if (demangled != NULL) 89983a0944fSIngo Molnar elf_name = demangled; 9002e538c4aSArnaldo Carvalho de Melo new_symbol: 90100a192b3SArnaldo Carvalho de Melo f = symbol__new(sym.st_value, sym.st_size, elf_name); 90228ac909bSArnaldo Carvalho de Melo free(demangled); 90386470930SIngo Molnar if (!f) 90486470930SIngo Molnar goto out_elf_end; 90586470930SIngo Molnar 9062e538c4aSArnaldo Carvalho de Melo if (filter && filter(curr_map, f)) 90700a192b3SArnaldo Carvalho de Melo symbol__delete(f); 90886470930SIngo Molnar else { 9096a4694a4SArnaldo Carvalho de Melo symbols__insert(&curr_dso->symbols[curr_map->type], f); 91086470930SIngo Molnar nr++; 91186470930SIngo Molnar } 91286470930SIngo Molnar } 91386470930SIngo Molnar 9142e538c4aSArnaldo Carvalho de Melo /* 9152e538c4aSArnaldo Carvalho de Melo * For misannotated, zeroed, ASM function sizes. 9162e538c4aSArnaldo Carvalho de Melo */ 9172e538c4aSArnaldo Carvalho de Melo if (nr > 0) 9186a4694a4SArnaldo Carvalho de Melo symbols__fixup_end(&self->symbols[map->type]); 91986470930SIngo Molnar err = nr; 92086470930SIngo Molnar out_elf_end: 92186470930SIngo Molnar elf_end(elf); 92286470930SIngo Molnar out_close: 92386470930SIngo Molnar return err; 92486470930SIngo Molnar } 92586470930SIngo Molnar 92678075caaSArnaldo Carvalho de Melo static bool dso__build_id_equal(const struct dso *self, u8 *build_id) 92778075caaSArnaldo Carvalho de Melo { 92878075caaSArnaldo Carvalho de Melo return memcmp(self->build_id, build_id, sizeof(self->build_id)) == 0; 92978075caaSArnaldo Carvalho de Melo } 93078075caaSArnaldo Carvalho de Melo 931b0da954aSArnaldo Carvalho de Melo static bool __dsos__read_build_ids(struct list_head *head) 93257f395a7SFrederic Weisbecker { 933e30a3d12SArnaldo Carvalho de Melo bool have_build_id = false; 93457f395a7SFrederic Weisbecker struct dso *pos; 93557f395a7SFrederic Weisbecker 936b0da954aSArnaldo Carvalho de Melo list_for_each_entry(pos, head, node) 937e30a3d12SArnaldo Carvalho de Melo if (filename__read_build_id(pos->long_name, pos->build_id, 938e30a3d12SArnaldo Carvalho de Melo sizeof(pos->build_id)) > 0) { 939e30a3d12SArnaldo Carvalho de Melo have_build_id = true; 940e30a3d12SArnaldo Carvalho de Melo pos->has_build_id = true; 94157f395a7SFrederic Weisbecker } 94257f395a7SFrederic Weisbecker 943e30a3d12SArnaldo Carvalho de Melo return have_build_id; 94457f395a7SFrederic Weisbecker } 94557f395a7SFrederic Weisbecker 946b0da954aSArnaldo Carvalho de Melo bool dsos__read_build_ids(void) 947b0da954aSArnaldo Carvalho de Melo { 9488b4825bfSArnaldo Carvalho de Melo bool kbuildids = __dsos__read_build_ids(&dsos__kernel), 9498b4825bfSArnaldo Carvalho de Melo ubuildids = __dsos__read_build_ids(&dsos__user); 9508b4825bfSArnaldo Carvalho de Melo return kbuildids || ubuildids; 951b0da954aSArnaldo Carvalho de Melo } 952b0da954aSArnaldo Carvalho de Melo 953fd7a346eSArnaldo Carvalho de Melo /* 954fd7a346eSArnaldo Carvalho de Melo * Align offset to 4 bytes as needed for note name and descriptor data. 955fd7a346eSArnaldo Carvalho de Melo */ 956fd7a346eSArnaldo Carvalho de Melo #define NOTE_ALIGN(n) (((n) + 3) & -4U) 957fd7a346eSArnaldo Carvalho de Melo 9582643ce11SArnaldo Carvalho de Melo int filename__read_build_id(const char *filename, void *bf, size_t size) 9594d1e00a8SArnaldo Carvalho de Melo { 9602643ce11SArnaldo Carvalho de Melo int fd, err = -1; 9614d1e00a8SArnaldo Carvalho de Melo GElf_Ehdr ehdr; 9624d1e00a8SArnaldo Carvalho de Melo GElf_Shdr shdr; 963fd7a346eSArnaldo Carvalho de Melo Elf_Data *data; 9644d1e00a8SArnaldo Carvalho de Melo Elf_Scn *sec; 965e57cfcdaSPekka Enberg Elf_Kind ek; 966fd7a346eSArnaldo Carvalho de Melo void *ptr; 9674d1e00a8SArnaldo Carvalho de Melo Elf *elf; 9684d1e00a8SArnaldo Carvalho de Melo 9692643ce11SArnaldo Carvalho de Melo if (size < BUILD_ID_SIZE) 9702643ce11SArnaldo Carvalho de Melo goto out; 9712643ce11SArnaldo Carvalho de Melo 9722643ce11SArnaldo Carvalho de Melo fd = open(filename, O_RDONLY); 9734d1e00a8SArnaldo Carvalho de Melo if (fd < 0) 9744d1e00a8SArnaldo Carvalho de Melo goto out; 9754d1e00a8SArnaldo Carvalho de Melo 97684087126SMarti Raudsepp elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 9774d1e00a8SArnaldo Carvalho de Melo if (elf == NULL) { 9788d06367fSArnaldo Carvalho de Melo pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename); 9794d1e00a8SArnaldo Carvalho de Melo goto out_close; 9804d1e00a8SArnaldo Carvalho de Melo } 9814d1e00a8SArnaldo Carvalho de Melo 982e57cfcdaSPekka Enberg ek = elf_kind(elf); 983e57cfcdaSPekka Enberg if (ek != ELF_K_ELF) 984e57cfcdaSPekka Enberg goto out_elf_end; 985e57cfcdaSPekka Enberg 9864d1e00a8SArnaldo Carvalho de Melo if (gelf_getehdr(elf, &ehdr) == NULL) { 9876beba7adSArnaldo Carvalho de Melo pr_err("%s: cannot get elf header.\n", __func__); 9884d1e00a8SArnaldo Carvalho de Melo goto out_elf_end; 9894d1e00a8SArnaldo Carvalho de Melo } 9904d1e00a8SArnaldo Carvalho de Melo 9912643ce11SArnaldo Carvalho de Melo sec = elf_section_by_name(elf, &ehdr, &shdr, 9922643ce11SArnaldo Carvalho de Melo ".note.gnu.build-id", NULL); 993fd7a346eSArnaldo Carvalho de Melo if (sec == NULL) { 994fd7a346eSArnaldo Carvalho de Melo sec = elf_section_by_name(elf, &ehdr, &shdr, 995fd7a346eSArnaldo Carvalho de Melo ".notes", NULL); 9964d1e00a8SArnaldo Carvalho de Melo if (sec == NULL) 9974d1e00a8SArnaldo Carvalho de Melo goto out_elf_end; 998fd7a346eSArnaldo Carvalho de Melo } 9994d1e00a8SArnaldo Carvalho de Melo 1000fd7a346eSArnaldo Carvalho de Melo data = elf_getdata(sec, NULL); 1001fd7a346eSArnaldo Carvalho de Melo if (data == NULL) 10024d1e00a8SArnaldo Carvalho de Melo goto out_elf_end; 1003fd7a346eSArnaldo Carvalho de Melo 1004fd7a346eSArnaldo Carvalho de Melo ptr = data->d_buf; 1005fd7a346eSArnaldo Carvalho de Melo while (ptr < (data->d_buf + data->d_size)) { 1006fd7a346eSArnaldo Carvalho de Melo GElf_Nhdr *nhdr = ptr; 1007fd7a346eSArnaldo Carvalho de Melo int namesz = NOTE_ALIGN(nhdr->n_namesz), 1008fd7a346eSArnaldo Carvalho de Melo descsz = NOTE_ALIGN(nhdr->n_descsz); 1009fd7a346eSArnaldo Carvalho de Melo const char *name; 1010fd7a346eSArnaldo Carvalho de Melo 1011fd7a346eSArnaldo Carvalho de Melo ptr += sizeof(*nhdr); 1012fd7a346eSArnaldo Carvalho de Melo name = ptr; 1013fd7a346eSArnaldo Carvalho de Melo ptr += namesz; 1014fd7a346eSArnaldo Carvalho de Melo if (nhdr->n_type == NT_GNU_BUILD_ID && 1015fd7a346eSArnaldo Carvalho de Melo nhdr->n_namesz == sizeof("GNU")) { 1016fd7a346eSArnaldo Carvalho de Melo if (memcmp(name, "GNU", sizeof("GNU")) == 0) { 1017fd7a346eSArnaldo Carvalho de Melo memcpy(bf, ptr, BUILD_ID_SIZE); 10182643ce11SArnaldo Carvalho de Melo err = BUILD_ID_SIZE; 1019fd7a346eSArnaldo Carvalho de Melo break; 1020fd7a346eSArnaldo Carvalho de Melo } 1021fd7a346eSArnaldo Carvalho de Melo } 1022fd7a346eSArnaldo Carvalho de Melo ptr += descsz; 1023fd7a346eSArnaldo Carvalho de Melo } 10242643ce11SArnaldo Carvalho de Melo out_elf_end: 10252643ce11SArnaldo Carvalho de Melo elf_end(elf); 10262643ce11SArnaldo Carvalho de Melo out_close: 10272643ce11SArnaldo Carvalho de Melo close(fd); 10282643ce11SArnaldo Carvalho de Melo out: 10292643ce11SArnaldo Carvalho de Melo return err; 10302643ce11SArnaldo Carvalho de Melo } 10312643ce11SArnaldo Carvalho de Melo 1032f1617b40SArnaldo Carvalho de Melo int sysfs__read_build_id(const char *filename, void *build_id, size_t size) 1033f1617b40SArnaldo Carvalho de Melo { 1034f1617b40SArnaldo Carvalho de Melo int fd, err = -1; 1035f1617b40SArnaldo Carvalho de Melo 1036f1617b40SArnaldo Carvalho de Melo if (size < BUILD_ID_SIZE) 1037f1617b40SArnaldo Carvalho de Melo goto out; 1038f1617b40SArnaldo Carvalho de Melo 1039f1617b40SArnaldo Carvalho de Melo fd = open(filename, O_RDONLY); 1040f1617b40SArnaldo Carvalho de Melo if (fd < 0) 1041f1617b40SArnaldo Carvalho de Melo goto out; 1042f1617b40SArnaldo Carvalho de Melo 1043f1617b40SArnaldo Carvalho de Melo while (1) { 1044f1617b40SArnaldo Carvalho de Melo char bf[BUFSIZ]; 1045f1617b40SArnaldo Carvalho de Melo GElf_Nhdr nhdr; 1046f1617b40SArnaldo Carvalho de Melo int namesz, descsz; 1047f1617b40SArnaldo Carvalho de Melo 1048f1617b40SArnaldo Carvalho de Melo if (read(fd, &nhdr, sizeof(nhdr)) != sizeof(nhdr)) 1049f1617b40SArnaldo Carvalho de Melo break; 1050f1617b40SArnaldo Carvalho de Melo 1051fd7a346eSArnaldo Carvalho de Melo namesz = NOTE_ALIGN(nhdr.n_namesz); 1052fd7a346eSArnaldo Carvalho de Melo descsz = NOTE_ALIGN(nhdr.n_descsz); 1053f1617b40SArnaldo Carvalho de Melo if (nhdr.n_type == NT_GNU_BUILD_ID && 1054f1617b40SArnaldo Carvalho de Melo nhdr.n_namesz == sizeof("GNU")) { 1055f1617b40SArnaldo Carvalho de Melo if (read(fd, bf, namesz) != namesz) 1056f1617b40SArnaldo Carvalho de Melo break; 1057f1617b40SArnaldo Carvalho de Melo if (memcmp(bf, "GNU", sizeof("GNU")) == 0) { 1058f1617b40SArnaldo Carvalho de Melo if (read(fd, build_id, 1059f1617b40SArnaldo Carvalho de Melo BUILD_ID_SIZE) == BUILD_ID_SIZE) { 1060f1617b40SArnaldo Carvalho de Melo err = 0; 1061f1617b40SArnaldo Carvalho de Melo break; 1062f1617b40SArnaldo Carvalho de Melo } 1063f1617b40SArnaldo Carvalho de Melo } else if (read(fd, bf, descsz) != descsz) 1064f1617b40SArnaldo Carvalho de Melo break; 1065f1617b40SArnaldo Carvalho de Melo } else { 1066f1617b40SArnaldo Carvalho de Melo int n = namesz + descsz; 1067f1617b40SArnaldo Carvalho de Melo if (read(fd, bf, n) != n) 1068f1617b40SArnaldo Carvalho de Melo break; 1069f1617b40SArnaldo Carvalho de Melo } 1070f1617b40SArnaldo Carvalho de Melo } 1071f1617b40SArnaldo Carvalho de Melo close(fd); 1072f1617b40SArnaldo Carvalho de Melo out: 1073f1617b40SArnaldo Carvalho de Melo return err; 1074f1617b40SArnaldo Carvalho de Melo } 1075f1617b40SArnaldo Carvalho de Melo 107694cb9e38SArnaldo Carvalho de Melo char dso__symtab_origin(const struct dso *self) 107794cb9e38SArnaldo Carvalho de Melo { 107894cb9e38SArnaldo Carvalho de Melo static const char origin[] = { 107994cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_KERNEL] = 'k', 108094cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_JAVA_JIT] = 'j', 108194cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_FEDORA] = 'f', 108294cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_UBUNTU] = 'u', 108394cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_BUILDID] = 'b', 108494cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_DSO] = 'd', 1085439d473bSArnaldo Carvalho de Melo [DSO__ORIG_KMODULE] = 'K', 108694cb9e38SArnaldo Carvalho de Melo }; 108794cb9e38SArnaldo Carvalho de Melo 108894cb9e38SArnaldo Carvalho de Melo if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND) 108994cb9e38SArnaldo Carvalho de Melo return '!'; 109094cb9e38SArnaldo Carvalho de Melo return origin[self->origin]; 109194cb9e38SArnaldo Carvalho de Melo } 109294cb9e38SArnaldo Carvalho de Melo 10936beba7adSArnaldo Carvalho de Melo int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) 109486470930SIngo Molnar { 10954d1e00a8SArnaldo Carvalho de Melo int size = PATH_MAX; 1096c338aee8SArnaldo Carvalho de Melo char *name; 1097d3379ab9SArnaldo Carvalho de Melo u8 build_id[BUILD_ID_SIZE]; 109886470930SIngo Molnar int ret = -1; 109986470930SIngo Molnar int fd; 110086470930SIngo Molnar 11013610583cSArnaldo Carvalho de Melo dso__set_loaded(self, map->type); 110266bd8424SArnaldo Carvalho de Melo 1103c338aee8SArnaldo Carvalho de Melo if (self->kernel) 11049958e1f0SArnaldo Carvalho de Melo return dso__load_kernel_sym(self, map, kmaps, filter); 1105c338aee8SArnaldo Carvalho de Melo 1106c338aee8SArnaldo Carvalho de Melo name = malloc(size); 110786470930SIngo Molnar if (!name) 110886470930SIngo Molnar return -1; 110986470930SIngo Molnar 111030d7a77dSArnaldo Carvalho de Melo self->adjust_symbols = 0; 1111f5812a7aSArnaldo Carvalho de Melo 111294cb9e38SArnaldo Carvalho de Melo if (strncmp(self->name, "/tmp/perf-", 10) == 0) { 11136beba7adSArnaldo Carvalho de Melo ret = dso__load_perf_map(self, map, filter); 111494cb9e38SArnaldo Carvalho de Melo self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT : 111594cb9e38SArnaldo Carvalho de Melo DSO__ORIG_NOT_FOUND; 111694cb9e38SArnaldo Carvalho de Melo return ret; 111794cb9e38SArnaldo Carvalho de Melo } 111894cb9e38SArnaldo Carvalho de Melo 111994cb9e38SArnaldo Carvalho de Melo self->origin = DSO__ORIG_FEDORA - 1; 112080d496beSPekka Enberg 112186470930SIngo Molnar more: 112286470930SIngo Molnar do { 112394cb9e38SArnaldo Carvalho de Melo self->origin++; 112494cb9e38SArnaldo Carvalho de Melo switch (self->origin) { 112594cb9e38SArnaldo Carvalho de Melo case DSO__ORIG_FEDORA: 1126439d473bSArnaldo Carvalho de Melo snprintf(name, size, "/usr/lib/debug%s.debug", 1127439d473bSArnaldo Carvalho de Melo self->long_name); 112886470930SIngo Molnar break; 112994cb9e38SArnaldo Carvalho de Melo case DSO__ORIG_UBUNTU: 1130439d473bSArnaldo Carvalho de Melo snprintf(name, size, "/usr/lib/debug%s", 1131439d473bSArnaldo Carvalho de Melo self->long_name); 113286470930SIngo Molnar break; 113394cb9e38SArnaldo Carvalho de Melo case DSO__ORIG_BUILDID: 1134d3379ab9SArnaldo Carvalho de Melo if (filename__read_build_id(self->long_name, build_id, 1135d3379ab9SArnaldo Carvalho de Melo sizeof(build_id))) { 1136d3379ab9SArnaldo Carvalho de Melo char build_id_hex[BUILD_ID_SIZE * 2 + 1]; 1137d3379ab9SArnaldo Carvalho de Melo 1138d3379ab9SArnaldo Carvalho de Melo build_id__sprintf(build_id, sizeof(build_id), 1139d3379ab9SArnaldo Carvalho de Melo build_id_hex); 11404d1e00a8SArnaldo Carvalho de Melo snprintf(name, size, 11414d1e00a8SArnaldo Carvalho de Melo "/usr/lib/debug/.build-id/%.2s/%s.debug", 1142d3379ab9SArnaldo Carvalho de Melo build_id_hex, build_id_hex + 2); 1143d3379ab9SArnaldo Carvalho de Melo if (self->has_build_id) 11448d06367fSArnaldo Carvalho de Melo goto compare_build_id; 1145d3379ab9SArnaldo Carvalho de Melo break; 11464d1e00a8SArnaldo Carvalho de Melo } 114794cb9e38SArnaldo Carvalho de Melo self->origin++; 11484d1e00a8SArnaldo Carvalho de Melo /* Fall thru */ 114994cb9e38SArnaldo Carvalho de Melo case DSO__ORIG_DSO: 1150439d473bSArnaldo Carvalho de Melo snprintf(name, size, "%s", self->long_name); 115186470930SIngo Molnar break; 115286470930SIngo Molnar 115386470930SIngo Molnar default: 115486470930SIngo Molnar goto out; 115586470930SIngo Molnar } 115686470930SIngo Molnar 11578d06367fSArnaldo Carvalho de Melo if (self->has_build_id) { 1158d3379ab9SArnaldo Carvalho de Melo if (filename__read_build_id(name, build_id, 1159d3379ab9SArnaldo Carvalho de Melo sizeof(build_id)) < 0) 11608d06367fSArnaldo Carvalho de Melo goto more; 11618d06367fSArnaldo Carvalho de Melo compare_build_id: 116278075caaSArnaldo Carvalho de Melo if (!dso__build_id_equal(self, build_id)) 11638d06367fSArnaldo Carvalho de Melo goto more; 11648d06367fSArnaldo Carvalho de Melo } 11658d06367fSArnaldo Carvalho de Melo 116686470930SIngo Molnar fd = open(name, O_RDONLY); 116786470930SIngo Molnar } while (fd < 0); 116886470930SIngo Molnar 116995011c60SArnaldo Carvalho de Melo ret = dso__load_sym(self, map, NULL, name, fd, filter, 0, 0); 117086470930SIngo Molnar close(fd); 117186470930SIngo Molnar 117286470930SIngo Molnar /* 117386470930SIngo Molnar * Some people seem to have debuginfo files _WITHOUT_ debug info!?!? 117486470930SIngo Molnar */ 117586470930SIngo Molnar if (!ret) 117686470930SIngo Molnar goto more; 117786470930SIngo Molnar 1178a25e46c4SArnaldo Carvalho de Melo if (ret > 0) { 117982164161SArnaldo Carvalho de Melo int nr_plt = dso__synthesize_plt_symbols(self, map, filter); 1180a25e46c4SArnaldo Carvalho de Melo if (nr_plt > 0) 1181a25e46c4SArnaldo Carvalho de Melo ret += nr_plt; 1182a25e46c4SArnaldo Carvalho de Melo } 118386470930SIngo Molnar out: 118486470930SIngo Molnar free(name); 11851340e6bbSArnaldo Carvalho de Melo if (ret < 0 && strstr(self->name, " (deleted)") != NULL) 11861340e6bbSArnaldo Carvalho de Melo return 0; 118786470930SIngo Molnar return ret; 118886470930SIngo Molnar } 118986470930SIngo Molnar 11909958e1f0SArnaldo Carvalho de Melo static struct map *map_groups__find_by_name(struct map_groups *self, char *name) 1191439d473bSArnaldo Carvalho de Melo { 1192439d473bSArnaldo Carvalho de Melo struct rb_node *nd; 1193439d473bSArnaldo Carvalho de Melo 119495011c60SArnaldo Carvalho de Melo for (nd = rb_first(&self->maps[MAP__FUNCTION]); nd; nd = rb_next(nd)) { 1195439d473bSArnaldo Carvalho de Melo struct map *map = rb_entry(nd, struct map, rb_node); 1196439d473bSArnaldo Carvalho de Melo 1197439d473bSArnaldo Carvalho de Melo if (map->dso && strcmp(map->dso->name, name) == 0) 1198439d473bSArnaldo Carvalho de Melo return map; 1199439d473bSArnaldo Carvalho de Melo } 1200439d473bSArnaldo Carvalho de Melo 1201439d473bSArnaldo Carvalho de Melo return NULL; 1202439d473bSArnaldo Carvalho de Melo } 1203439d473bSArnaldo Carvalho de Melo 1204c338aee8SArnaldo Carvalho de Melo static int dsos__set_modules_path_dir(char *dirname) 12056cfcc53eSMike Galbraith { 1206439d473bSArnaldo Carvalho de Melo struct dirent *dent; 1207439d473bSArnaldo Carvalho de Melo DIR *dir = opendir(dirname); 12086cfcc53eSMike Galbraith 1209439d473bSArnaldo Carvalho de Melo if (!dir) { 121087f8ea4cSArnaldo Carvalho de Melo pr_debug("%s: cannot open %s dir\n", __func__, dirname); 1211439d473bSArnaldo Carvalho de Melo return -1; 1212439d473bSArnaldo Carvalho de Melo } 12136cfcc53eSMike Galbraith 1214439d473bSArnaldo Carvalho de Melo while ((dent = readdir(dir)) != NULL) { 1215439d473bSArnaldo Carvalho de Melo char path[PATH_MAX]; 1216439d473bSArnaldo Carvalho de Melo 1217439d473bSArnaldo Carvalho de Melo if (dent->d_type == DT_DIR) { 1218439d473bSArnaldo Carvalho de Melo if (!strcmp(dent->d_name, ".") || 1219439d473bSArnaldo Carvalho de Melo !strcmp(dent->d_name, "..")) 1220439d473bSArnaldo Carvalho de Melo continue; 1221439d473bSArnaldo Carvalho de Melo 1222439d473bSArnaldo Carvalho de Melo snprintf(path, sizeof(path), "%s/%s", 1223439d473bSArnaldo Carvalho de Melo dirname, dent->d_name); 1224c338aee8SArnaldo Carvalho de Melo if (dsos__set_modules_path_dir(path) < 0) 1225439d473bSArnaldo Carvalho de Melo goto failure; 1226439d473bSArnaldo Carvalho de Melo } else { 1227439d473bSArnaldo Carvalho de Melo char *dot = strrchr(dent->d_name, '.'), 1228439d473bSArnaldo Carvalho de Melo dso_name[PATH_MAX]; 1229439d473bSArnaldo Carvalho de Melo struct map *map; 1230cfc10d3bSArnaldo Carvalho de Melo char *long_name; 1231439d473bSArnaldo Carvalho de Melo 1232439d473bSArnaldo Carvalho de Melo if (dot == NULL || strcmp(dot, ".ko")) 1233439d473bSArnaldo Carvalho de Melo continue; 1234439d473bSArnaldo Carvalho de Melo snprintf(dso_name, sizeof(dso_name), "[%.*s]", 1235439d473bSArnaldo Carvalho de Melo (int)(dot - dent->d_name), dent->d_name); 1236439d473bSArnaldo Carvalho de Melo 1237a2a99e8eSArnaldo Carvalho de Melo strxfrchar(dso_name, '-', '_'); 12389958e1f0SArnaldo Carvalho de Melo map = map_groups__find_by_name(kmaps, dso_name); 1239439d473bSArnaldo Carvalho de Melo if (map == NULL) 1240439d473bSArnaldo Carvalho de Melo continue; 1241439d473bSArnaldo Carvalho de Melo 1242439d473bSArnaldo Carvalho de Melo snprintf(path, sizeof(path), "%s/%s", 1243439d473bSArnaldo Carvalho de Melo dirname, dent->d_name); 1244439d473bSArnaldo Carvalho de Melo 1245cfc10d3bSArnaldo Carvalho de Melo long_name = strdup(path); 1246cfc10d3bSArnaldo Carvalho de Melo if (long_name == NULL) 1247439d473bSArnaldo Carvalho de Melo goto failure; 1248cfc10d3bSArnaldo Carvalho de Melo dso__set_long_name(map->dso, long_name); 1249439d473bSArnaldo Carvalho de Melo } 1250439d473bSArnaldo Carvalho de Melo } 1251439d473bSArnaldo Carvalho de Melo 1252c338aee8SArnaldo Carvalho de Melo return 0; 1253439d473bSArnaldo Carvalho de Melo failure: 1254439d473bSArnaldo Carvalho de Melo closedir(dir); 1255439d473bSArnaldo Carvalho de Melo return -1; 1256439d473bSArnaldo Carvalho de Melo } 1257439d473bSArnaldo Carvalho de Melo 1258c338aee8SArnaldo Carvalho de Melo static int dsos__set_modules_path(void) 1259439d473bSArnaldo Carvalho de Melo { 1260439d473bSArnaldo Carvalho de Melo struct utsname uts; 1261439d473bSArnaldo Carvalho de Melo char modules_path[PATH_MAX]; 1262439d473bSArnaldo Carvalho de Melo 1263439d473bSArnaldo Carvalho de Melo if (uname(&uts) < 0) 1264439d473bSArnaldo Carvalho de Melo return -1; 1265439d473bSArnaldo Carvalho de Melo 1266439d473bSArnaldo Carvalho de Melo snprintf(modules_path, sizeof(modules_path), "/lib/modules/%s/kernel", 1267439d473bSArnaldo Carvalho de Melo uts.release); 1268439d473bSArnaldo Carvalho de Melo 1269c338aee8SArnaldo Carvalho de Melo return dsos__set_modules_path_dir(modules_path); 1270439d473bSArnaldo Carvalho de Melo } 12716cfcc53eSMike Galbraith 12726cfcc53eSMike Galbraith /* 1273439d473bSArnaldo Carvalho de Melo * Constructor variant for modules (where we know from /proc/modules where 1274439d473bSArnaldo Carvalho de Melo * they are loaded) and for vmlinux, where only after we load all the 1275439d473bSArnaldo Carvalho de Melo * symbols we'll know where it starts and ends. 12766cfcc53eSMike Galbraith */ 12773610583cSArnaldo Carvalho de Melo static struct map *map__new2(u64 start, struct dso *dso, enum map_type type) 1278439d473bSArnaldo Carvalho de Melo { 1279439d473bSArnaldo Carvalho de Melo struct map *self = malloc(sizeof(*self)); 12806cfcc53eSMike Galbraith 1281439d473bSArnaldo Carvalho de Melo if (self != NULL) { 1282439d473bSArnaldo Carvalho de Melo /* 1283afb7b4f0SArnaldo Carvalho de Melo * ->end will be filled after we load all the symbols 1284439d473bSArnaldo Carvalho de Melo */ 12853610583cSArnaldo Carvalho de Melo map__init(self, type, start, 0, 0, dso); 1286439d473bSArnaldo Carvalho de Melo } 1287afb7b4f0SArnaldo Carvalho de Melo 1288439d473bSArnaldo Carvalho de Melo return self; 1289439d473bSArnaldo Carvalho de Melo } 1290439d473bSArnaldo Carvalho de Melo 12919958e1f0SArnaldo Carvalho de Melo static int map_groups__create_module_maps(struct map_groups *self) 1292439d473bSArnaldo Carvalho de Melo { 1293439d473bSArnaldo Carvalho de Melo char *line = NULL; 1294439d473bSArnaldo Carvalho de Melo size_t n; 1295439d473bSArnaldo Carvalho de Melo FILE *file = fopen("/proc/modules", "r"); 1296439d473bSArnaldo Carvalho de Melo struct map *map; 1297439d473bSArnaldo Carvalho de Melo 1298439d473bSArnaldo Carvalho de Melo if (file == NULL) 1299439d473bSArnaldo Carvalho de Melo return -1; 1300439d473bSArnaldo Carvalho de Melo 1301439d473bSArnaldo Carvalho de Melo while (!feof(file)) { 1302439d473bSArnaldo Carvalho de Melo char name[PATH_MAX]; 1303439d473bSArnaldo Carvalho de Melo u64 start; 1304439d473bSArnaldo Carvalho de Melo struct dso *dso; 1305439d473bSArnaldo Carvalho de Melo char *sep; 1306439d473bSArnaldo Carvalho de Melo int line_len; 1307439d473bSArnaldo Carvalho de Melo 1308439d473bSArnaldo Carvalho de Melo line_len = getline(&line, &n, file); 1309439d473bSArnaldo Carvalho de Melo if (line_len < 0) 13106cfcc53eSMike Galbraith break; 13116cfcc53eSMike Galbraith 1312439d473bSArnaldo Carvalho de Melo if (!line) 1313439d473bSArnaldo Carvalho de Melo goto out_failure; 1314439d473bSArnaldo Carvalho de Melo 1315439d473bSArnaldo Carvalho de Melo line[--line_len] = '\0'; /* \n */ 1316439d473bSArnaldo Carvalho de Melo 1317439d473bSArnaldo Carvalho de Melo sep = strrchr(line, 'x'); 1318439d473bSArnaldo Carvalho de Melo if (sep == NULL) 1319439d473bSArnaldo Carvalho de Melo continue; 1320439d473bSArnaldo Carvalho de Melo 1321439d473bSArnaldo Carvalho de Melo hex2u64(sep + 1, &start); 1322439d473bSArnaldo Carvalho de Melo 1323439d473bSArnaldo Carvalho de Melo sep = strchr(line, ' '); 1324439d473bSArnaldo Carvalho de Melo if (sep == NULL) 1325439d473bSArnaldo Carvalho de Melo continue; 1326439d473bSArnaldo Carvalho de Melo 1327439d473bSArnaldo Carvalho de Melo *sep = '\0'; 1328439d473bSArnaldo Carvalho de Melo 1329439d473bSArnaldo Carvalho de Melo snprintf(name, sizeof(name), "[%s]", line); 133000a192b3SArnaldo Carvalho de Melo dso = dso__new(name); 1331439d473bSArnaldo Carvalho de Melo 1332439d473bSArnaldo Carvalho de Melo if (dso == NULL) 1333439d473bSArnaldo Carvalho de Melo goto out_delete_line; 1334439d473bSArnaldo Carvalho de Melo 13353610583cSArnaldo Carvalho de Melo map = map__new2(start, dso, MAP__FUNCTION); 1336439d473bSArnaldo Carvalho de Melo if (map == NULL) { 1337439d473bSArnaldo Carvalho de Melo dso__delete(dso); 1338439d473bSArnaldo Carvalho de Melo goto out_delete_line; 13396cfcc53eSMike Galbraith } 13406cfcc53eSMike Galbraith 1341f1617b40SArnaldo Carvalho de Melo snprintf(name, sizeof(name), 1342f1617b40SArnaldo Carvalho de Melo "/sys/module/%s/notes/.note.gnu.build-id", line); 1343f1617b40SArnaldo Carvalho de Melo if (sysfs__read_build_id(name, dso->build_id, 1344f1617b40SArnaldo Carvalho de Melo sizeof(dso->build_id)) == 0) 1345f1617b40SArnaldo Carvalho de Melo dso->has_build_id = true; 1346f1617b40SArnaldo Carvalho de Melo 1347439d473bSArnaldo Carvalho de Melo dso->origin = DSO__ORIG_KMODULE; 13489958e1f0SArnaldo Carvalho de Melo map_groups__insert(self, map); 1349b0da954aSArnaldo Carvalho de Melo dsos__add(&dsos__kernel, dso); 13506cfcc53eSMike Galbraith } 13516cfcc53eSMike Galbraith 1352439d473bSArnaldo Carvalho de Melo free(line); 1353439d473bSArnaldo Carvalho de Melo fclose(file); 1354439d473bSArnaldo Carvalho de Melo 1355c338aee8SArnaldo Carvalho de Melo return dsos__set_modules_path(); 1356439d473bSArnaldo Carvalho de Melo 1357439d473bSArnaldo Carvalho de Melo out_delete_line: 1358439d473bSArnaldo Carvalho de Melo free(line); 1359439d473bSArnaldo Carvalho de Melo out_failure: 1360439d473bSArnaldo Carvalho de Melo return -1; 13616cfcc53eSMike Galbraith } 13626cfcc53eSMike Galbraith 13639958e1f0SArnaldo Carvalho de Melo static int dso__load_vmlinux(struct dso *self, struct map *map, 13649958e1f0SArnaldo Carvalho de Melo struct map_groups *mg, 13656beba7adSArnaldo Carvalho de Melo const char *vmlinux, symbol_filter_t filter) 136686470930SIngo Molnar { 1367fbd733b8SArnaldo Carvalho de Melo int err = -1, fd; 136886470930SIngo Molnar 1369fbd733b8SArnaldo Carvalho de Melo if (self->has_build_id) { 1370fbd733b8SArnaldo Carvalho de Melo u8 build_id[BUILD_ID_SIZE]; 137166bd8424SArnaldo Carvalho de Melo 1372fbd733b8SArnaldo Carvalho de Melo if (filename__read_build_id(vmlinux, build_id, 1373fbd733b8SArnaldo Carvalho de Melo sizeof(build_id)) < 0) { 1374fbd733b8SArnaldo Carvalho de Melo pr_debug("No build_id in %s, ignoring it\n", vmlinux); 1375fbd733b8SArnaldo Carvalho de Melo return -1; 1376fbd733b8SArnaldo Carvalho de Melo } 1377fbd733b8SArnaldo Carvalho de Melo if (!dso__build_id_equal(self, build_id)) { 1378fbd733b8SArnaldo Carvalho de Melo char expected_build_id[BUILD_ID_SIZE * 2 + 1], 1379fbd733b8SArnaldo Carvalho de Melo vmlinux_build_id[BUILD_ID_SIZE * 2 + 1]; 1380fbd733b8SArnaldo Carvalho de Melo 1381fbd733b8SArnaldo Carvalho de Melo build_id__sprintf(self->build_id, 1382fbd733b8SArnaldo Carvalho de Melo sizeof(self->build_id), 1383fbd733b8SArnaldo Carvalho de Melo expected_build_id); 1384fbd733b8SArnaldo Carvalho de Melo build_id__sprintf(build_id, sizeof(build_id), 1385fbd733b8SArnaldo Carvalho de Melo vmlinux_build_id); 1386fbd733b8SArnaldo Carvalho de Melo pr_debug("build_id in %s is %s while expected is %s, " 1387fbd733b8SArnaldo Carvalho de Melo "ignoring it\n", vmlinux, vmlinux_build_id, 1388fbd733b8SArnaldo Carvalho de Melo expected_build_id); 1389fbd733b8SArnaldo Carvalho de Melo return -1; 1390fbd733b8SArnaldo Carvalho de Melo } 1391fbd733b8SArnaldo Carvalho de Melo } 1392fbd733b8SArnaldo Carvalho de Melo 1393fbd733b8SArnaldo Carvalho de Melo fd = open(vmlinux, O_RDONLY); 139486470930SIngo Molnar if (fd < 0) 139586470930SIngo Molnar return -1; 139686470930SIngo Molnar 13973610583cSArnaldo Carvalho de Melo dso__set_loaded(self, map->type); 13989958e1f0SArnaldo Carvalho de Melo err = dso__load_sym(self, map, mg, self->long_name, fd, filter, 1, 0); 139986470930SIngo Molnar close(fd); 140086470930SIngo Molnar 140186470930SIngo Molnar return err; 140286470930SIngo Molnar } 140386470930SIngo Molnar 1404c338aee8SArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *self, struct map *map, 14059958e1f0SArnaldo Carvalho de Melo struct map_groups *mg, symbol_filter_t filter) 140686470930SIngo Molnar { 1407cc612d81SArnaldo Carvalho de Melo int err; 1408cc612d81SArnaldo Carvalho de Melo bool is_kallsyms; 1409439d473bSArnaldo Carvalho de Melo 1410cc612d81SArnaldo Carvalho de Melo if (vmlinux_path != NULL) { 1411cc612d81SArnaldo Carvalho de Melo int i; 1412cc612d81SArnaldo Carvalho de Melo pr_debug("Looking at the vmlinux_path (%d entries long)\n", 1413cc612d81SArnaldo Carvalho de Melo vmlinux_path__nr_entries); 1414cc612d81SArnaldo Carvalho de Melo for (i = 0; i < vmlinux_path__nr_entries; ++i) { 14159958e1f0SArnaldo Carvalho de Melo err = dso__load_vmlinux(self, map, mg, 141695011c60SArnaldo Carvalho de Melo vmlinux_path[i], filter); 1417cc612d81SArnaldo Carvalho de Melo if (err > 0) { 1418cc612d81SArnaldo Carvalho de Melo pr_debug("Using %s for symbols\n", 1419cc612d81SArnaldo Carvalho de Melo vmlinux_path[i]); 1420cc612d81SArnaldo Carvalho de Melo dso__set_long_name(self, 1421cc612d81SArnaldo Carvalho de Melo strdup(vmlinux_path[i])); 1422cc612d81SArnaldo Carvalho de Melo goto out_fixup; 1423cc612d81SArnaldo Carvalho de Melo } 1424cc612d81SArnaldo Carvalho de Melo } 1425cc612d81SArnaldo Carvalho de Melo } 1426cc612d81SArnaldo Carvalho de Melo 1427cc612d81SArnaldo Carvalho de Melo is_kallsyms = self->long_name[0] == '['; 1428cc612d81SArnaldo Carvalho de Melo if (is_kallsyms) 1429cc612d81SArnaldo Carvalho de Melo goto do_kallsyms; 1430cc612d81SArnaldo Carvalho de Melo 14319958e1f0SArnaldo Carvalho de Melo err = dso__load_vmlinux(self, map, mg, self->long_name, filter); 1432ef6ae724SArnaldo Carvalho de Melo if (err <= 0) { 1433cc612d81SArnaldo Carvalho de Melo pr_info("The file %s cannot be used, " 1434cc612d81SArnaldo Carvalho de Melo "trying to use /proc/kallsyms...", self->long_name); 1435cc612d81SArnaldo Carvalho de Melo do_kallsyms: 14369958e1f0SArnaldo Carvalho de Melo err = dso__load_kallsyms(self, map, mg, filter); 1437cc612d81SArnaldo Carvalho de Melo if (err > 0 && !is_kallsyms) 1438ef6ae724SArnaldo Carvalho de Melo dso__set_long_name(self, strdup("[kernel.kallsyms]")); 1439ef6ae724SArnaldo Carvalho de Melo } 144086470930SIngo Molnar 1441439d473bSArnaldo Carvalho de Melo if (err > 0) { 1442cc612d81SArnaldo Carvalho de Melo out_fixup: 14436a4694a4SArnaldo Carvalho de Melo map__fixup_start(map); 14446a4694a4SArnaldo Carvalho de Melo map__fixup_end(map); 1445439d473bSArnaldo Carvalho de Melo } 144694cb9e38SArnaldo Carvalho de Melo 144786470930SIngo Molnar return err; 144886470930SIngo Molnar } 144986470930SIngo Molnar 1450b0da954aSArnaldo Carvalho de Melo LIST_HEAD(dsos__user); 1451b0da954aSArnaldo Carvalho de Melo LIST_HEAD(dsos__kernel); 1452cd84c2acSFrederic Weisbecker struct dso *vdso; 1453cd84c2acSFrederic Weisbecker 1454b0da954aSArnaldo Carvalho de Melo static void dsos__add(struct list_head *head, struct dso *dso) 1455cd84c2acSFrederic Weisbecker { 1456b0da954aSArnaldo Carvalho de Melo list_add_tail(&dso->node, head); 1457cd84c2acSFrederic Weisbecker } 1458cd84c2acSFrederic Weisbecker 1459b0da954aSArnaldo Carvalho de Melo static struct dso *dsos__find(struct list_head *head, const char *name) 1460cd84c2acSFrederic Weisbecker { 1461cd84c2acSFrederic Weisbecker struct dso *pos; 1462cd84c2acSFrederic Weisbecker 1463b0da954aSArnaldo Carvalho de Melo list_for_each_entry(pos, head, node) 1464cd84c2acSFrederic Weisbecker if (strcmp(pos->name, name) == 0) 1465cd84c2acSFrederic Weisbecker return pos; 1466cd84c2acSFrederic Weisbecker return NULL; 1467cd84c2acSFrederic Weisbecker } 1468cd84c2acSFrederic Weisbecker 146900a192b3SArnaldo Carvalho de Melo struct dso *dsos__findnew(const char *name) 1470cd84c2acSFrederic Weisbecker { 1471b0da954aSArnaldo Carvalho de Melo struct dso *dso = dsos__find(&dsos__user, name); 1472cd84c2acSFrederic Weisbecker 1473e4204992SArnaldo Carvalho de Melo if (!dso) { 147400a192b3SArnaldo Carvalho de Melo dso = dso__new(name); 1475cfc10d3bSArnaldo Carvalho de Melo if (dso != NULL) { 1476b0da954aSArnaldo Carvalho de Melo dsos__add(&dsos__user, dso); 1477cfc10d3bSArnaldo Carvalho de Melo dso__set_basename(dso); 1478cfc10d3bSArnaldo Carvalho de Melo } 1479e4204992SArnaldo Carvalho de Melo } 1480cd84c2acSFrederic Weisbecker 1481cd84c2acSFrederic Weisbecker return dso; 1482cd84c2acSFrederic Weisbecker } 1483cd84c2acSFrederic Weisbecker 1484b0da954aSArnaldo Carvalho de Melo static void __dsos__fprintf(struct list_head *head, FILE *fp) 1485cd84c2acSFrederic Weisbecker { 1486cd84c2acSFrederic Weisbecker struct dso *pos; 1487cd84c2acSFrederic Weisbecker 148895011c60SArnaldo Carvalho de Melo list_for_each_entry(pos, head, node) { 148995011c60SArnaldo Carvalho de Melo int i; 149095011c60SArnaldo Carvalho de Melo for (i = 0; i < MAP__NR_TYPES; ++i) 149195011c60SArnaldo Carvalho de Melo dso__fprintf(pos, i, fp); 149295011c60SArnaldo Carvalho de Melo } 1493cd84c2acSFrederic Weisbecker } 1494cd84c2acSFrederic Weisbecker 1495b0da954aSArnaldo Carvalho de Melo void dsos__fprintf(FILE *fp) 1496b0da954aSArnaldo Carvalho de Melo { 1497b0da954aSArnaldo Carvalho de Melo __dsos__fprintf(&dsos__kernel, fp); 1498b0da954aSArnaldo Carvalho de Melo __dsos__fprintf(&dsos__user, fp); 1499b0da954aSArnaldo Carvalho de Melo } 1500b0da954aSArnaldo Carvalho de Melo 1501b0da954aSArnaldo Carvalho de Melo static size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp) 15029e03eb2dSArnaldo Carvalho de Melo { 15039e03eb2dSArnaldo Carvalho de Melo struct dso *pos; 15049e03eb2dSArnaldo Carvalho de Melo size_t ret = 0; 15059e03eb2dSArnaldo Carvalho de Melo 1506b0da954aSArnaldo Carvalho de Melo list_for_each_entry(pos, head, node) { 15079e03eb2dSArnaldo Carvalho de Melo ret += dso__fprintf_buildid(pos, fp); 15089e03eb2dSArnaldo Carvalho de Melo ret += fprintf(fp, " %s\n", pos->long_name); 15099e03eb2dSArnaldo Carvalho de Melo } 15109e03eb2dSArnaldo Carvalho de Melo return ret; 15119e03eb2dSArnaldo Carvalho de Melo } 15129e03eb2dSArnaldo Carvalho de Melo 1513b0da954aSArnaldo Carvalho de Melo size_t dsos__fprintf_buildid(FILE *fp) 1514b0da954aSArnaldo Carvalho de Melo { 1515b0da954aSArnaldo Carvalho de Melo return (__dsos__fprintf_buildid(&dsos__kernel, fp) + 1516b0da954aSArnaldo Carvalho de Melo __dsos__fprintf_buildid(&dsos__user, fp)); 1517b0da954aSArnaldo Carvalho de Melo } 1518b0da954aSArnaldo Carvalho de Melo 15199958e1f0SArnaldo Carvalho de Melo static int map_groups__create_kernel_map(struct map_groups *self, const char *vmlinux) 1520cd84c2acSFrederic Weisbecker { 15214e06255fSArnaldo Carvalho de Melo struct map *kmap; 152295011c60SArnaldo Carvalho de Melo struct dso *kernel = dso__new(vmlinux ?: "[kernel.kallsyms]"); 1523cd84c2acSFrederic Weisbecker 15242446042cSArnaldo Carvalho de Melo if (kernel == NULL) 1525c338aee8SArnaldo Carvalho de Melo return -1; 1526c338aee8SArnaldo Carvalho de Melo 15274e06255fSArnaldo Carvalho de Melo kmap = map__new2(0, kernel, MAP__FUNCTION); 15284e06255fSArnaldo Carvalho de Melo if (kmap == NULL) 1529c338aee8SArnaldo Carvalho de Melo goto out_delete_kernel_dso; 1530c338aee8SArnaldo Carvalho de Melo 15314e06255fSArnaldo Carvalho de Melo kmap->map_ip = kmap->unmap_ip = identity__map_ip; 15322446042cSArnaldo Carvalho de Melo kernel->short_name = "[kernel]"; 1533c338aee8SArnaldo Carvalho de Melo kernel->kernel = 1; 1534cc612d81SArnaldo Carvalho de Melo 153500a192b3SArnaldo Carvalho de Melo vdso = dso__new("[vdso]"); 1536c338aee8SArnaldo Carvalho de Melo if (vdso == NULL) 1537c338aee8SArnaldo Carvalho de Melo goto out_delete_kernel_map; 15383610583cSArnaldo Carvalho de Melo dso__set_loaded(vdso, MAP__FUNCTION); 1539cd84c2acSFrederic Weisbecker 15402446042cSArnaldo Carvalho de Melo if (sysfs__read_build_id("/sys/kernel/notes", kernel->build_id, 15412446042cSArnaldo Carvalho de Melo sizeof(kernel->build_id)) == 0) 15422446042cSArnaldo Carvalho de Melo kernel->has_build_id = true; 15432446042cSArnaldo Carvalho de Melo 15449958e1f0SArnaldo Carvalho de Melo map_groups__insert(self, kmap); 1545b0da954aSArnaldo Carvalho de Melo dsos__add(&dsos__kernel, kernel); 1546b0da954aSArnaldo Carvalho de Melo dsos__add(&dsos__user, vdso); 1547cd84c2acSFrederic Weisbecker 1548c338aee8SArnaldo Carvalho de Melo return 0; 1549c338aee8SArnaldo Carvalho de Melo 1550c338aee8SArnaldo Carvalho de Melo out_delete_kernel_map: 15514e06255fSArnaldo Carvalho de Melo map__delete(kmap); 1552c338aee8SArnaldo Carvalho de Melo out_delete_kernel_dso: 1553c338aee8SArnaldo Carvalho de Melo dso__delete(kernel); 1554c338aee8SArnaldo Carvalho de Melo return -1; 15552446042cSArnaldo Carvalho de Melo } 15562446042cSArnaldo Carvalho de Melo 1557cc612d81SArnaldo Carvalho de Melo static void vmlinux_path__exit(void) 15582446042cSArnaldo Carvalho de Melo { 1559cc612d81SArnaldo Carvalho de Melo while (--vmlinux_path__nr_entries >= 0) { 1560cc612d81SArnaldo Carvalho de Melo free(vmlinux_path[vmlinux_path__nr_entries]); 1561cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = NULL; 1562cc612d81SArnaldo Carvalho de Melo } 1563cc612d81SArnaldo Carvalho de Melo 1564cc612d81SArnaldo Carvalho de Melo free(vmlinux_path); 1565cc612d81SArnaldo Carvalho de Melo vmlinux_path = NULL; 1566cc612d81SArnaldo Carvalho de Melo } 1567cc612d81SArnaldo Carvalho de Melo 1568cc612d81SArnaldo Carvalho de Melo static int vmlinux_path__init(void) 1569cc612d81SArnaldo Carvalho de Melo { 1570cc612d81SArnaldo Carvalho de Melo struct utsname uts; 1571cc612d81SArnaldo Carvalho de Melo char bf[PATH_MAX]; 1572cc612d81SArnaldo Carvalho de Melo 1573cc612d81SArnaldo Carvalho de Melo if (uname(&uts) < 0) 15742446042cSArnaldo Carvalho de Melo return -1; 15752446042cSArnaldo Carvalho de Melo 1576cc612d81SArnaldo Carvalho de Melo vmlinux_path = malloc(sizeof(char *) * 5); 1577cc612d81SArnaldo Carvalho de Melo if (vmlinux_path == NULL) 1578cc612d81SArnaldo Carvalho de Melo return -1; 1579cc612d81SArnaldo Carvalho de Melo 1580cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup("vmlinux"); 1581cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 1582cc612d81SArnaldo Carvalho de Melo goto out_fail; 1583cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 1584cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup("/boot/vmlinux"); 1585cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 1586cc612d81SArnaldo Carvalho de Melo goto out_fail; 1587cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 1588cc612d81SArnaldo Carvalho de Melo snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", uts.release); 1589cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); 1590cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 1591cc612d81SArnaldo Carvalho de Melo goto out_fail; 1592cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 1593cc612d81SArnaldo Carvalho de Melo snprintf(bf, sizeof(bf), "/lib/modules/%s/build/vmlinux", uts.release); 1594cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); 1595cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 1596cc612d81SArnaldo Carvalho de Melo goto out_fail; 1597cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 1598cc612d81SArnaldo Carvalho de Melo snprintf(bf, sizeof(bf), "/usr/lib/debug/lib/modules/%s/vmlinux", 1599cc612d81SArnaldo Carvalho de Melo uts.release); 1600cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); 1601cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 1602cc612d81SArnaldo Carvalho de Melo goto out_fail; 1603cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 1604cc612d81SArnaldo Carvalho de Melo 1605cc612d81SArnaldo Carvalho de Melo return 0; 1606cc612d81SArnaldo Carvalho de Melo 1607cc612d81SArnaldo Carvalho de Melo out_fail: 1608cc612d81SArnaldo Carvalho de Melo vmlinux_path__exit(); 1609cc612d81SArnaldo Carvalho de Melo return -1; 1610cc612d81SArnaldo Carvalho de Melo } 1611cc612d81SArnaldo Carvalho de Melo 161295011c60SArnaldo Carvalho de Melo int symbol__init(struct symbol_conf *conf) 1613cc612d81SArnaldo Carvalho de Melo { 1614b32d133aSArnaldo Carvalho de Melo const struct symbol_conf *pconf = conf ?: &symbol_conf__defaults; 1615b32d133aSArnaldo Carvalho de Melo 161695011c60SArnaldo Carvalho de Melo elf_version(EV_CURRENT); 1617b32d133aSArnaldo Carvalho de Melo symbol__priv_size = pconf->priv_size; 16189958e1f0SArnaldo Carvalho de Melo map_groups__init(kmaps); 1619b32d133aSArnaldo Carvalho de Melo 1620b32d133aSArnaldo Carvalho de Melo if (pconf->try_vmlinux_path && vmlinux_path__init() < 0) 1621cc612d81SArnaldo Carvalho de Melo return -1; 1622cc612d81SArnaldo Carvalho de Melo 16239958e1f0SArnaldo Carvalho de Melo if (map_groups__create_kernel_map(kmaps, pconf->vmlinux_name) < 0) { 1624cc612d81SArnaldo Carvalho de Melo vmlinux_path__exit(); 1625cc612d81SArnaldo Carvalho de Melo return -1; 1626cc612d81SArnaldo Carvalho de Melo } 1627cc612d81SArnaldo Carvalho de Melo 16289958e1f0SArnaldo Carvalho de Melo kmaps->use_modules = pconf->use_modules; 16299958e1f0SArnaldo Carvalho de Melo if (pconf->use_modules && map_groups__create_module_maps(kmaps) < 0) 163087f8ea4cSArnaldo Carvalho de Melo pr_debug("Failed to load list of modules in use, " 16316671cb16SArnaldo Carvalho de Melo "continuing...\n"); 163290c83218SArnaldo Carvalho de Melo /* 163390c83218SArnaldo Carvalho de Melo * Now that we have all the maps created, just set the ->end of them: 163490c83218SArnaldo Carvalho de Melo */ 16359958e1f0SArnaldo Carvalho de Melo map_groups__fixup_end(kmaps); 16366671cb16SArnaldo Carvalho de Melo return 0; 1637cd84c2acSFrederic Weisbecker } 1638