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 596893d4eeSArnaldo Carvalho de Melo static bool symbol_type__is_a(char symbol_type, enum map_type map_type) 606893d4eeSArnaldo Carvalho de Melo { 616893d4eeSArnaldo Carvalho de Melo switch (map_type) { 626893d4eeSArnaldo Carvalho de Melo case MAP__FUNCTION: 636893d4eeSArnaldo Carvalho de Melo return symbol_type == 'T' || symbol_type == 'W'; 64*f1dfa0b1SArnaldo Carvalho de Melo case MAP__VARIABLE: 65*f1dfa0b1SArnaldo Carvalho de Melo return symbol_type == 'D' || symbol_type == 'd'; 666893d4eeSArnaldo Carvalho de Melo default: 676893d4eeSArnaldo Carvalho de Melo return false; 686893d4eeSArnaldo Carvalho de Melo } 696893d4eeSArnaldo Carvalho de Melo } 706893d4eeSArnaldo Carvalho de Melo 71fcf1203aSArnaldo Carvalho de Melo static void symbols__fixup_end(struct rb_root *self) 72af427bf5SArnaldo Carvalho de Melo { 73fcf1203aSArnaldo Carvalho de Melo struct rb_node *nd, *prevnd = rb_first(self); 742e538c4aSArnaldo Carvalho de Melo struct symbol *curr, *prev; 75af427bf5SArnaldo Carvalho de Melo 76af427bf5SArnaldo Carvalho de Melo if (prevnd == NULL) 77af427bf5SArnaldo Carvalho de Melo return; 78af427bf5SArnaldo Carvalho de Melo 792e538c4aSArnaldo Carvalho de Melo curr = rb_entry(prevnd, struct symbol, rb_node); 802e538c4aSArnaldo Carvalho de Melo 81af427bf5SArnaldo Carvalho de Melo for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) { 822e538c4aSArnaldo Carvalho de Melo prev = curr; 832e538c4aSArnaldo Carvalho de Melo curr = rb_entry(nd, struct symbol, rb_node); 84af427bf5SArnaldo Carvalho de Melo 85af427bf5SArnaldo Carvalho de Melo if (prev->end == prev->start) 86af427bf5SArnaldo Carvalho de Melo prev->end = curr->start - 1; 87af427bf5SArnaldo Carvalho de Melo } 88af427bf5SArnaldo Carvalho de Melo 892e538c4aSArnaldo Carvalho de Melo /* Last entry */ 902e538c4aSArnaldo Carvalho de Melo if (curr->end == curr->start) 912e538c4aSArnaldo Carvalho de Melo curr->end = roundup(curr->start, 4096); 922e538c4aSArnaldo Carvalho de Melo } 932e538c4aSArnaldo Carvalho de Melo 949958e1f0SArnaldo Carvalho de Melo static void __map_groups__fixup_end(struct map_groups *self, enum map_type type) 95af427bf5SArnaldo Carvalho de Melo { 96af427bf5SArnaldo Carvalho de Melo struct map *prev, *curr; 9795011c60SArnaldo Carvalho de Melo struct rb_node *nd, *prevnd = rb_first(&self->maps[type]); 98af427bf5SArnaldo Carvalho de Melo 99af427bf5SArnaldo Carvalho de Melo if (prevnd == NULL) 100af427bf5SArnaldo Carvalho de Melo return; 101af427bf5SArnaldo Carvalho de Melo 102af427bf5SArnaldo Carvalho de Melo curr = rb_entry(prevnd, struct map, rb_node); 103af427bf5SArnaldo Carvalho de Melo 104af427bf5SArnaldo Carvalho de Melo for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) { 105af427bf5SArnaldo Carvalho de Melo prev = curr; 106af427bf5SArnaldo Carvalho de Melo curr = rb_entry(nd, struct map, rb_node); 107af427bf5SArnaldo Carvalho de Melo prev->end = curr->start - 1; 1082e538c4aSArnaldo Carvalho de Melo } 10990c83218SArnaldo Carvalho de Melo 11090c83218SArnaldo Carvalho de Melo /* 11190c83218SArnaldo Carvalho de Melo * We still haven't the actual symbols, so guess the 11290c83218SArnaldo Carvalho de Melo * last map final address. 11390c83218SArnaldo Carvalho de Melo */ 11490c83218SArnaldo Carvalho de Melo curr->end = ~0UL; 115af427bf5SArnaldo Carvalho de Melo } 116af427bf5SArnaldo Carvalho de Melo 1179958e1f0SArnaldo Carvalho de Melo static void map_groups__fixup_end(struct map_groups *self) 11823ea4a3fSArnaldo Carvalho de Melo { 11923ea4a3fSArnaldo Carvalho de Melo int i; 12023ea4a3fSArnaldo Carvalho de Melo for (i = 0; i < MAP__NR_TYPES; ++i) 1219958e1f0SArnaldo Carvalho de Melo __map_groups__fixup_end(self, i); 12223ea4a3fSArnaldo Carvalho de Melo } 12323ea4a3fSArnaldo Carvalho de Melo 12400a192b3SArnaldo Carvalho de Melo static struct symbol *symbol__new(u64 start, u64 len, const char *name) 12586470930SIngo Molnar { 12686470930SIngo Molnar size_t namelen = strlen(name) + 1; 12736479484SArnaldo Carvalho de Melo struct symbol *self = zalloc(symbol__priv_size + 12836479484SArnaldo Carvalho de Melo sizeof(*self) + namelen); 12936479484SArnaldo Carvalho de Melo if (self == NULL) 13086470930SIngo Molnar return NULL; 13186470930SIngo Molnar 13236479484SArnaldo Carvalho de Melo if (symbol__priv_size) 13300a192b3SArnaldo Carvalho de Melo self = ((void *)self) + symbol__priv_size; 13436479484SArnaldo Carvalho de Melo 13586470930SIngo Molnar self->start = start; 1366cfcc53eSMike Galbraith self->end = len ? start + len - 1 : start; 137e4204992SArnaldo Carvalho de Melo 1386beba7adSArnaldo Carvalho de Melo pr_debug3("%s: %s %#Lx-%#Lx\n", __func__, name, start, self->end); 139e4204992SArnaldo Carvalho de Melo 14086470930SIngo Molnar memcpy(self->name, name, namelen); 14186470930SIngo Molnar 14286470930SIngo Molnar return self; 14386470930SIngo Molnar } 14486470930SIngo Molnar 14500a192b3SArnaldo Carvalho de Melo static void symbol__delete(struct symbol *self) 14686470930SIngo Molnar { 14700a192b3SArnaldo Carvalho de Melo free(((void *)self) - symbol__priv_size); 14886470930SIngo Molnar } 14986470930SIngo Molnar 15086470930SIngo Molnar static size_t symbol__fprintf(struct symbol *self, FILE *fp) 15186470930SIngo Molnar { 15286470930SIngo Molnar return fprintf(fp, " %llx-%llx %s\n", 15386470930SIngo Molnar self->start, self->end, self->name); 15486470930SIngo Molnar } 15586470930SIngo Molnar 156cfc10d3bSArnaldo Carvalho de Melo static void dso__set_long_name(struct dso *self, char *name) 157cfc10d3bSArnaldo Carvalho de Melo { 158ef6ae724SArnaldo Carvalho de Melo if (name == NULL) 159ef6ae724SArnaldo Carvalho de Melo return; 160cfc10d3bSArnaldo Carvalho de Melo self->long_name = name; 161cfc10d3bSArnaldo Carvalho de Melo self->long_name_len = strlen(name); 162cfc10d3bSArnaldo Carvalho de Melo } 163cfc10d3bSArnaldo Carvalho de Melo 164cfc10d3bSArnaldo Carvalho de Melo static void dso__set_basename(struct dso *self) 165cfc10d3bSArnaldo Carvalho de Melo { 166cfc10d3bSArnaldo Carvalho de Melo self->short_name = basename(self->long_name); 167cfc10d3bSArnaldo Carvalho de Melo } 168cfc10d3bSArnaldo Carvalho de Melo 16900a192b3SArnaldo Carvalho de Melo struct dso *dso__new(const char *name) 17086470930SIngo Molnar { 17186470930SIngo Molnar struct dso *self = malloc(sizeof(*self) + strlen(name) + 1); 17286470930SIngo Molnar 17386470930SIngo Molnar if (self != NULL) { 1746a4694a4SArnaldo Carvalho de Melo int i; 17586470930SIngo Molnar strcpy(self->name, name); 176cfc10d3bSArnaldo Carvalho de Melo dso__set_long_name(self, self->name); 177439d473bSArnaldo Carvalho de Melo self->short_name = self->name; 1786a4694a4SArnaldo Carvalho de Melo for (i = 0; i < MAP__NR_TYPES; ++i) 1796a4694a4SArnaldo Carvalho de Melo self->symbols[i] = RB_ROOT; 1806a4694a4SArnaldo Carvalho de Melo self->find_symbol = dso__find_symbol; 18152d422deSArnaldo Carvalho de Melo self->slen_calculated = 0; 18294cb9e38SArnaldo Carvalho de Melo self->origin = DSO__ORIG_NOT_FOUND; 1838d06367fSArnaldo Carvalho de Melo self->loaded = 0; 1848d06367fSArnaldo Carvalho de Melo self->has_build_id = 0; 18586470930SIngo Molnar } 18686470930SIngo Molnar 18786470930SIngo Molnar return self; 18886470930SIngo Molnar } 18986470930SIngo Molnar 190fcf1203aSArnaldo Carvalho de Melo static void symbols__delete(struct rb_root *self) 19186470930SIngo Molnar { 19286470930SIngo Molnar struct symbol *pos; 193fcf1203aSArnaldo Carvalho de Melo struct rb_node *next = rb_first(self); 19486470930SIngo Molnar 19586470930SIngo Molnar while (next) { 19686470930SIngo Molnar pos = rb_entry(next, struct symbol, rb_node); 19786470930SIngo Molnar next = rb_next(&pos->rb_node); 198fcf1203aSArnaldo Carvalho de Melo rb_erase(&pos->rb_node, self); 19900a192b3SArnaldo Carvalho de Melo symbol__delete(pos); 20086470930SIngo Molnar } 20186470930SIngo Molnar } 20286470930SIngo Molnar 20386470930SIngo Molnar void dso__delete(struct dso *self) 20486470930SIngo Molnar { 2056a4694a4SArnaldo Carvalho de Melo int i; 2066a4694a4SArnaldo Carvalho de Melo for (i = 0; i < MAP__NR_TYPES; ++i) 2076a4694a4SArnaldo Carvalho de Melo symbols__delete(&self->symbols[i]); 208439d473bSArnaldo Carvalho de Melo if (self->long_name != self->name) 209439d473bSArnaldo Carvalho de Melo free(self->long_name); 21086470930SIngo Molnar free(self); 21186470930SIngo Molnar } 21286470930SIngo Molnar 2138d06367fSArnaldo Carvalho de Melo void dso__set_build_id(struct dso *self, void *build_id) 2148d06367fSArnaldo Carvalho de Melo { 2158d06367fSArnaldo Carvalho de Melo memcpy(self->build_id, build_id, sizeof(self->build_id)); 2168d06367fSArnaldo Carvalho de Melo self->has_build_id = 1; 2178d06367fSArnaldo Carvalho de Melo } 2188d06367fSArnaldo Carvalho de Melo 219fcf1203aSArnaldo Carvalho de Melo static void symbols__insert(struct rb_root *self, struct symbol *sym) 22086470930SIngo Molnar { 221fcf1203aSArnaldo Carvalho de Melo struct rb_node **p = &self->rb_node; 22286470930SIngo Molnar struct rb_node *parent = NULL; 2239cffa8d5SPaul Mackerras const u64 ip = sym->start; 22486470930SIngo Molnar struct symbol *s; 22586470930SIngo Molnar 22686470930SIngo Molnar while (*p != NULL) { 22786470930SIngo Molnar parent = *p; 22886470930SIngo Molnar s = rb_entry(parent, struct symbol, rb_node); 22986470930SIngo Molnar if (ip < s->start) 23086470930SIngo Molnar p = &(*p)->rb_left; 23186470930SIngo Molnar else 23286470930SIngo Molnar p = &(*p)->rb_right; 23386470930SIngo Molnar } 23486470930SIngo Molnar rb_link_node(&sym->rb_node, parent, p); 235fcf1203aSArnaldo Carvalho de Melo rb_insert_color(&sym->rb_node, self); 23686470930SIngo Molnar } 23786470930SIngo Molnar 238fcf1203aSArnaldo Carvalho de Melo static struct symbol *symbols__find(struct rb_root *self, u64 ip) 23986470930SIngo Molnar { 24086470930SIngo Molnar struct rb_node *n; 24186470930SIngo Molnar 24286470930SIngo Molnar if (self == NULL) 24386470930SIngo Molnar return NULL; 24486470930SIngo Molnar 245fcf1203aSArnaldo Carvalho de Melo n = self->rb_node; 24686470930SIngo Molnar 24786470930SIngo Molnar while (n) { 24886470930SIngo Molnar struct symbol *s = rb_entry(n, struct symbol, rb_node); 24986470930SIngo Molnar 25086470930SIngo Molnar if (ip < s->start) 25186470930SIngo Molnar n = n->rb_left; 25286470930SIngo Molnar else if (ip > s->end) 25386470930SIngo Molnar n = n->rb_right; 25486470930SIngo Molnar else 25586470930SIngo Molnar return s; 25686470930SIngo Molnar } 25786470930SIngo Molnar 25886470930SIngo Molnar return NULL; 25986470930SIngo Molnar } 26086470930SIngo Molnar 2616a4694a4SArnaldo Carvalho de Melo struct symbol *dso__find_symbol(struct dso *self, enum map_type type, u64 addr) 262fcf1203aSArnaldo Carvalho de Melo { 2636a4694a4SArnaldo Carvalho de Melo return symbols__find(&self->symbols[type], addr); 264fcf1203aSArnaldo Carvalho de Melo } 265fcf1203aSArnaldo Carvalho de Melo 2668d06367fSArnaldo Carvalho de Melo int build_id__sprintf(u8 *self, int len, char *bf) 2678d06367fSArnaldo Carvalho de Melo { 2688d06367fSArnaldo Carvalho de Melo char *bid = bf; 2698d06367fSArnaldo Carvalho de Melo u8 *raw = self; 2708d06367fSArnaldo Carvalho de Melo int i; 2718d06367fSArnaldo Carvalho de Melo 2728d06367fSArnaldo Carvalho de Melo for (i = 0; i < len; ++i) { 2738d06367fSArnaldo Carvalho de Melo sprintf(bid, "%02x", *raw); 2748d06367fSArnaldo Carvalho de Melo ++raw; 2758d06367fSArnaldo Carvalho de Melo bid += 2; 2768d06367fSArnaldo Carvalho de Melo } 2778d06367fSArnaldo Carvalho de Melo 2788d06367fSArnaldo Carvalho de Melo return raw - self; 2798d06367fSArnaldo Carvalho de Melo } 2808d06367fSArnaldo Carvalho de Melo 2819e03eb2dSArnaldo Carvalho de Melo size_t dso__fprintf_buildid(struct dso *self, FILE *fp) 28286470930SIngo Molnar { 2838d06367fSArnaldo Carvalho de Melo char sbuild_id[BUILD_ID_SIZE * 2 + 1]; 2848d06367fSArnaldo Carvalho de Melo 2858d06367fSArnaldo Carvalho de Melo build_id__sprintf(self->build_id, sizeof(self->build_id), sbuild_id); 2869e03eb2dSArnaldo Carvalho de Melo return fprintf(fp, "%s", sbuild_id); 2879e03eb2dSArnaldo Carvalho de Melo } 2889e03eb2dSArnaldo Carvalho de Melo 28995011c60SArnaldo Carvalho de Melo size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp) 2909e03eb2dSArnaldo Carvalho de Melo { 2919e03eb2dSArnaldo Carvalho de Melo struct rb_node *nd; 2929e03eb2dSArnaldo Carvalho de Melo size_t ret = fprintf(fp, "dso: %s (", self->short_name); 2939e03eb2dSArnaldo Carvalho de Melo 2949e03eb2dSArnaldo Carvalho de Melo ret += dso__fprintf_buildid(self, fp); 2956a4694a4SArnaldo Carvalho de Melo ret += fprintf(fp, ")\n"); 29695011c60SArnaldo Carvalho de Melo for (nd = rb_first(&self->symbols[type]); nd; nd = rb_next(nd)) { 29786470930SIngo Molnar struct symbol *pos = rb_entry(nd, struct symbol, rb_node); 29886470930SIngo Molnar ret += symbol__fprintf(pos, fp); 29986470930SIngo Molnar } 30086470930SIngo Molnar 30186470930SIngo Molnar return ret; 30286470930SIngo Molnar } 30386470930SIngo Molnar 3042e538c4aSArnaldo Carvalho de Melo /* 3052e538c4aSArnaldo Carvalho de Melo * Loads the function entries in /proc/kallsyms into kernel_map->dso, 3062e538c4aSArnaldo Carvalho de Melo * so that we can in the next step set the symbol ->end address and then 3072e538c4aSArnaldo Carvalho de Melo * call kernel_maps__split_kallsyms. 3082e538c4aSArnaldo Carvalho de Melo */ 3094e06255fSArnaldo Carvalho de Melo static int dso__load_all_kallsyms(struct dso *self, struct map *map) 31086470930SIngo Molnar { 31186470930SIngo Molnar char *line = NULL; 31286470930SIngo Molnar size_t n; 3134e06255fSArnaldo Carvalho de Melo struct rb_root *root = &self->symbols[map->type]; 31486470930SIngo Molnar FILE *file = fopen("/proc/kallsyms", "r"); 31586470930SIngo Molnar 31686470930SIngo Molnar if (file == NULL) 31786470930SIngo Molnar goto out_failure; 31886470930SIngo Molnar 31986470930SIngo Molnar while (!feof(file)) { 3209cffa8d5SPaul Mackerras u64 start; 32186470930SIngo Molnar struct symbol *sym; 32286470930SIngo Molnar int line_len, len; 32386470930SIngo Molnar char symbol_type; 3242e538c4aSArnaldo Carvalho de Melo char *symbol_name; 32586470930SIngo Molnar 32686470930SIngo Molnar line_len = getline(&line, &n, file); 32786470930SIngo Molnar if (line_len < 0) 32886470930SIngo Molnar break; 32986470930SIngo Molnar 33086470930SIngo Molnar if (!line) 33186470930SIngo Molnar goto out_failure; 33286470930SIngo Molnar 33386470930SIngo Molnar line[--line_len] = '\0'; /* \n */ 33486470930SIngo Molnar 33586470930SIngo Molnar len = hex2u64(line, &start); 33686470930SIngo Molnar 33786470930SIngo Molnar len++; 33886470930SIngo Molnar if (len + 2 >= line_len) 33986470930SIngo Molnar continue; 34086470930SIngo Molnar 34186470930SIngo Molnar symbol_type = toupper(line[len]); 3426893d4eeSArnaldo Carvalho de Melo if (!symbol_type__is_a(symbol_type, map->type)) 34386470930SIngo Molnar continue; 344af427bf5SArnaldo Carvalho de Melo 345af427bf5SArnaldo Carvalho de Melo symbol_name = line + len + 2; 3462e538c4aSArnaldo Carvalho de Melo /* 3472e538c4aSArnaldo Carvalho de Melo * Will fix up the end later, when we have all symbols sorted. 3482e538c4aSArnaldo Carvalho de Melo */ 34900a192b3SArnaldo Carvalho de Melo sym = symbol__new(start, 0, symbol_name); 350af427bf5SArnaldo Carvalho de Melo 3512e538c4aSArnaldo Carvalho de Melo if (sym == NULL) 3522e538c4aSArnaldo Carvalho de Melo goto out_delete_line; 35382164161SArnaldo Carvalho de Melo /* 35482164161SArnaldo Carvalho de Melo * We will pass the symbols to the filter later, in 3554e06255fSArnaldo Carvalho de Melo * map__split_kallsyms, when we have split the maps per module 35682164161SArnaldo Carvalho de Melo */ 3574e06255fSArnaldo Carvalho de Melo symbols__insert(root, sym); 3582e538c4aSArnaldo Carvalho de Melo } 3592e538c4aSArnaldo Carvalho de Melo 3602e538c4aSArnaldo Carvalho de Melo free(line); 3612e538c4aSArnaldo Carvalho de Melo fclose(file); 3622e538c4aSArnaldo Carvalho de Melo 3632e538c4aSArnaldo Carvalho de Melo return 0; 3642e538c4aSArnaldo Carvalho de Melo 3652e538c4aSArnaldo Carvalho de Melo out_delete_line: 3662e538c4aSArnaldo Carvalho de Melo free(line); 3672e538c4aSArnaldo Carvalho de Melo out_failure: 3682e538c4aSArnaldo Carvalho de Melo return -1; 3692e538c4aSArnaldo Carvalho de Melo } 3702e538c4aSArnaldo Carvalho de Melo 3712e538c4aSArnaldo Carvalho de Melo /* 3722e538c4aSArnaldo Carvalho de Melo * Split the symbols into maps, making sure there are no overlaps, i.e. the 3732e538c4aSArnaldo Carvalho de Melo * kernel range is broken in several maps, named [kernel].N, as we don't have 3742e538c4aSArnaldo Carvalho de Melo * the original ELF section names vmlinux have. 3752e538c4aSArnaldo Carvalho de Melo */ 3769958e1f0SArnaldo Carvalho de Melo static int dso__split_kallsyms(struct dso *self, struct map *map, 3779958e1f0SArnaldo Carvalho de Melo struct map_groups *mg, symbol_filter_t filter) 3782e538c4aSArnaldo Carvalho de Melo { 3794e06255fSArnaldo Carvalho de Melo struct map *curr_map = map; 3802e538c4aSArnaldo Carvalho de Melo struct symbol *pos; 3812e538c4aSArnaldo Carvalho de Melo int count = 0; 3824e06255fSArnaldo Carvalho de Melo struct rb_root *root = &self->symbols[map->type]; 3834e06255fSArnaldo Carvalho de Melo struct rb_node *next = rb_first(root); 3842e538c4aSArnaldo Carvalho de Melo int kernel_range = 0; 3852e538c4aSArnaldo Carvalho de Melo 3862e538c4aSArnaldo Carvalho de Melo while (next) { 3872e538c4aSArnaldo Carvalho de Melo char *module; 3882e538c4aSArnaldo Carvalho de Melo 3892e538c4aSArnaldo Carvalho de Melo pos = rb_entry(next, struct symbol, rb_node); 3902e538c4aSArnaldo Carvalho de Melo next = rb_next(&pos->rb_node); 3912e538c4aSArnaldo Carvalho de Melo 3922e538c4aSArnaldo Carvalho de Melo module = strchr(pos->name, '\t'); 3932e538c4aSArnaldo Carvalho de Melo if (module) { 3949958e1f0SArnaldo Carvalho de Melo if (!mg->use_modules) 3951de8e245SArnaldo Carvalho de Melo goto discard_symbol; 3961de8e245SArnaldo Carvalho de Melo 3972e538c4aSArnaldo Carvalho de Melo *module++ = '\0'; 3982e538c4aSArnaldo Carvalho de Melo 3994e06255fSArnaldo Carvalho de Melo if (strcmp(self->name, module)) { 4009958e1f0SArnaldo Carvalho de Melo curr_map = map_groups__find_by_name(mg, module); 4014e06255fSArnaldo Carvalho de Melo if (curr_map == NULL) { 40295011c60SArnaldo Carvalho de Melo pr_debug("/proc/{kallsyms,modules} " 4036beba7adSArnaldo Carvalho de Melo "inconsistency!\n"); 404af427bf5SArnaldo Carvalho de Melo return -1; 405af427bf5SArnaldo Carvalho de Melo } 406af427bf5SArnaldo Carvalho de Melo } 40786470930SIngo Molnar /* 4082e538c4aSArnaldo Carvalho de Melo * So that we look just like we get from .ko files, 4092e538c4aSArnaldo Carvalho de Melo * i.e. not prelinked, relative to map->start. 41086470930SIngo Molnar */ 4114e06255fSArnaldo Carvalho de Melo pos->start = curr_map->map_ip(curr_map, pos->start); 4124e06255fSArnaldo Carvalho de Melo pos->end = curr_map->map_ip(curr_map, pos->end); 4134e06255fSArnaldo Carvalho de Melo } else if (curr_map != map) { 4142e538c4aSArnaldo Carvalho de Melo char dso_name[PATH_MAX]; 4152e538c4aSArnaldo Carvalho de Melo struct dso *dso; 41686470930SIngo Molnar 4172e538c4aSArnaldo Carvalho de Melo snprintf(dso_name, sizeof(dso_name), "[kernel].%d", 4182e538c4aSArnaldo Carvalho de Melo kernel_range++); 41986470930SIngo Molnar 42000a192b3SArnaldo Carvalho de Melo dso = dso__new(dso_name); 4212e538c4aSArnaldo Carvalho de Melo if (dso == NULL) 4222e538c4aSArnaldo Carvalho de Melo return -1; 4232e538c4aSArnaldo Carvalho de Melo 4244e06255fSArnaldo Carvalho de Melo curr_map = map__new2(pos->start, dso, map->type); 4252e538c4aSArnaldo Carvalho de Melo if (map == NULL) { 4262e538c4aSArnaldo Carvalho de Melo dso__delete(dso); 4272e538c4aSArnaldo Carvalho de Melo return -1; 4282e538c4aSArnaldo Carvalho de Melo } 4292e538c4aSArnaldo Carvalho de Melo 4304e06255fSArnaldo Carvalho de Melo curr_map->map_ip = curr_map->unmap_ip = identity__map_ip; 4319958e1f0SArnaldo Carvalho de Melo map_groups__insert(mg, curr_map); 4322e538c4aSArnaldo Carvalho de Melo ++kernel_range; 4332e538c4aSArnaldo Carvalho de Melo } 4342e538c4aSArnaldo Carvalho de Melo 4354e06255fSArnaldo Carvalho de Melo if (filter && filter(curr_map, pos)) { 4361de8e245SArnaldo Carvalho de Melo discard_symbol: rb_erase(&pos->rb_node, root); 43700a192b3SArnaldo Carvalho de Melo symbol__delete(pos); 4382e538c4aSArnaldo Carvalho de Melo } else { 4394e06255fSArnaldo Carvalho de Melo if (curr_map != map) { 4404e06255fSArnaldo Carvalho de Melo rb_erase(&pos->rb_node, root); 4414e06255fSArnaldo Carvalho de Melo symbols__insert(&curr_map->dso->symbols[curr_map->type], pos); 4422e538c4aSArnaldo Carvalho de Melo } 4439974f496SMike Galbraith count++; 4449974f496SMike Galbraith } 44586470930SIngo Molnar } 44686470930SIngo Molnar 4479974f496SMike Galbraith return count; 44886470930SIngo Molnar } 44986470930SIngo Molnar 4502e538c4aSArnaldo Carvalho de Melo 4514e06255fSArnaldo Carvalho de Melo static int dso__load_kallsyms(struct dso *self, struct map *map, 4529958e1f0SArnaldo Carvalho de Melo struct map_groups *mg, symbol_filter_t filter) 4532e538c4aSArnaldo Carvalho de Melo { 4544e06255fSArnaldo Carvalho de Melo if (dso__load_all_kallsyms(self, map) < 0) 4552e538c4aSArnaldo Carvalho de Melo return -1; 4562e538c4aSArnaldo Carvalho de Melo 4574e06255fSArnaldo Carvalho de Melo symbols__fixup_end(&self->symbols[map->type]); 4584e06255fSArnaldo Carvalho de Melo self->origin = DSO__ORIG_KERNEL; 4592e538c4aSArnaldo Carvalho de Melo 4609958e1f0SArnaldo Carvalho de Melo return dso__split_kallsyms(self, map, mg, filter); 46123ea4a3fSArnaldo Carvalho de Melo } 46223ea4a3fSArnaldo Carvalho de Melo 46323ea4a3fSArnaldo Carvalho de Melo size_t kernel_maps__fprintf(FILE *fp) 46423ea4a3fSArnaldo Carvalho de Melo { 46523ea4a3fSArnaldo Carvalho de Melo size_t printed = fprintf(fp, "Kernel maps:\n"); 4669958e1f0SArnaldo Carvalho de Melo printed += map_groups__fprintf_maps(kmaps, fp); 4676beba7adSArnaldo Carvalho de Melo return printed + fprintf(fp, "END kernel maps\n"); 468af427bf5SArnaldo Carvalho de Melo } 469af427bf5SArnaldo Carvalho de Melo 470439d473bSArnaldo Carvalho de Melo static int dso__load_perf_map(struct dso *self, struct map *map, 4716beba7adSArnaldo Carvalho de Melo symbol_filter_t filter) 47280d496beSPekka Enberg { 47380d496beSPekka Enberg char *line = NULL; 47480d496beSPekka Enberg size_t n; 47580d496beSPekka Enberg FILE *file; 47680d496beSPekka Enberg int nr_syms = 0; 47780d496beSPekka Enberg 478439d473bSArnaldo Carvalho de Melo file = fopen(self->long_name, "r"); 47980d496beSPekka Enberg if (file == NULL) 48080d496beSPekka Enberg goto out_failure; 48180d496beSPekka Enberg 48280d496beSPekka Enberg while (!feof(file)) { 4839cffa8d5SPaul Mackerras u64 start, size; 48480d496beSPekka Enberg struct symbol *sym; 48580d496beSPekka Enberg int line_len, len; 48680d496beSPekka Enberg 48780d496beSPekka Enberg line_len = getline(&line, &n, file); 48880d496beSPekka Enberg if (line_len < 0) 48980d496beSPekka Enberg break; 49080d496beSPekka Enberg 49180d496beSPekka Enberg if (!line) 49280d496beSPekka Enberg goto out_failure; 49380d496beSPekka Enberg 49480d496beSPekka Enberg line[--line_len] = '\0'; /* \n */ 49580d496beSPekka Enberg 49680d496beSPekka Enberg len = hex2u64(line, &start); 49780d496beSPekka Enberg 49880d496beSPekka Enberg len++; 49980d496beSPekka Enberg if (len + 2 >= line_len) 50080d496beSPekka Enberg continue; 50180d496beSPekka Enberg 50280d496beSPekka Enberg len += hex2u64(line + len, &size); 50380d496beSPekka Enberg 50480d496beSPekka Enberg len++; 50580d496beSPekka Enberg if (len + 2 >= line_len) 50680d496beSPekka Enberg continue; 50780d496beSPekka Enberg 50800a192b3SArnaldo Carvalho de Melo sym = symbol__new(start, size, line + len); 50980d496beSPekka Enberg 51080d496beSPekka Enberg if (sym == NULL) 51180d496beSPekka Enberg goto out_delete_line; 51280d496beSPekka Enberg 513439d473bSArnaldo Carvalho de Melo if (filter && filter(map, sym)) 51400a192b3SArnaldo Carvalho de Melo symbol__delete(sym); 51580d496beSPekka Enberg else { 5166a4694a4SArnaldo Carvalho de Melo symbols__insert(&self->symbols[map->type], sym); 51780d496beSPekka Enberg nr_syms++; 51880d496beSPekka Enberg } 51980d496beSPekka Enberg } 52080d496beSPekka Enberg 52180d496beSPekka Enberg free(line); 52280d496beSPekka Enberg fclose(file); 52380d496beSPekka Enberg 52480d496beSPekka Enberg return nr_syms; 52580d496beSPekka Enberg 52680d496beSPekka Enberg out_delete_line: 52780d496beSPekka Enberg free(line); 52880d496beSPekka Enberg out_failure: 52980d496beSPekka Enberg return -1; 53080d496beSPekka Enberg } 53180d496beSPekka Enberg 53286470930SIngo Molnar /** 53386470930SIngo Molnar * elf_symtab__for_each_symbol - iterate thru all the symbols 53486470930SIngo Molnar * 53586470930SIngo Molnar * @self: struct elf_symtab instance to iterate 53683a0944fSIngo Molnar * @idx: uint32_t idx 53786470930SIngo Molnar * @sym: GElf_Sym iterator 53886470930SIngo Molnar */ 53983a0944fSIngo Molnar #define elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) \ 54083a0944fSIngo Molnar for (idx = 0, gelf_getsym(syms, idx, &sym);\ 54183a0944fSIngo Molnar idx < nr_syms; \ 54283a0944fSIngo Molnar idx++, gelf_getsym(syms, idx, &sym)) 54386470930SIngo Molnar 54486470930SIngo Molnar static inline uint8_t elf_sym__type(const GElf_Sym *sym) 54586470930SIngo Molnar { 54686470930SIngo Molnar return GELF_ST_TYPE(sym->st_info); 54786470930SIngo Molnar } 54886470930SIngo Molnar 54986470930SIngo Molnar static inline int elf_sym__is_function(const GElf_Sym *sym) 55086470930SIngo Molnar { 55186470930SIngo Molnar return elf_sym__type(sym) == STT_FUNC && 55286470930SIngo Molnar sym->st_name != 0 && 55381833130SArnaldo Carvalho de Melo sym->st_shndx != SHN_UNDEF; 55486470930SIngo Molnar } 55586470930SIngo Molnar 556*f1dfa0b1SArnaldo Carvalho de Melo static inline bool elf_sym__is_object(const GElf_Sym *sym) 557*f1dfa0b1SArnaldo Carvalho de Melo { 558*f1dfa0b1SArnaldo Carvalho de Melo return elf_sym__type(sym) == STT_OBJECT && 559*f1dfa0b1SArnaldo Carvalho de Melo sym->st_name != 0 && 560*f1dfa0b1SArnaldo Carvalho de Melo sym->st_shndx != SHN_UNDEF; 561*f1dfa0b1SArnaldo Carvalho de Melo } 562*f1dfa0b1SArnaldo Carvalho de Melo 5636cfcc53eSMike Galbraith static inline int elf_sym__is_label(const GElf_Sym *sym) 5646cfcc53eSMike Galbraith { 5656cfcc53eSMike Galbraith return elf_sym__type(sym) == STT_NOTYPE && 5666cfcc53eSMike Galbraith sym->st_name != 0 && 5676cfcc53eSMike Galbraith sym->st_shndx != SHN_UNDEF && 5686cfcc53eSMike Galbraith sym->st_shndx != SHN_ABS; 5696cfcc53eSMike Galbraith } 5706cfcc53eSMike Galbraith 5716cfcc53eSMike Galbraith static inline const char *elf_sec__name(const GElf_Shdr *shdr, 5726cfcc53eSMike Galbraith const Elf_Data *secstrs) 5736cfcc53eSMike Galbraith { 5746cfcc53eSMike Galbraith return secstrs->d_buf + shdr->sh_name; 5756cfcc53eSMike Galbraith } 5766cfcc53eSMike Galbraith 5776cfcc53eSMike Galbraith static inline int elf_sec__is_text(const GElf_Shdr *shdr, 5786cfcc53eSMike Galbraith const Elf_Data *secstrs) 5796cfcc53eSMike Galbraith { 5806cfcc53eSMike Galbraith return strstr(elf_sec__name(shdr, secstrs), "text") != NULL; 5816cfcc53eSMike Galbraith } 5826cfcc53eSMike Galbraith 583*f1dfa0b1SArnaldo Carvalho de Melo static inline bool elf_sec__is_data(const GElf_Shdr *shdr, 584*f1dfa0b1SArnaldo Carvalho de Melo const Elf_Data *secstrs) 585*f1dfa0b1SArnaldo Carvalho de Melo { 586*f1dfa0b1SArnaldo Carvalho de Melo return strstr(elf_sec__name(shdr, secstrs), "data") != NULL; 587*f1dfa0b1SArnaldo Carvalho de Melo } 588*f1dfa0b1SArnaldo Carvalho de Melo 58986470930SIngo Molnar static inline const char *elf_sym__name(const GElf_Sym *sym, 59086470930SIngo Molnar const Elf_Data *symstrs) 59186470930SIngo Molnar { 59286470930SIngo Molnar return symstrs->d_buf + sym->st_name; 59386470930SIngo Molnar } 59486470930SIngo Molnar 59586470930SIngo Molnar static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, 59686470930SIngo Molnar GElf_Shdr *shp, const char *name, 59783a0944fSIngo Molnar size_t *idx) 59886470930SIngo Molnar { 59986470930SIngo Molnar Elf_Scn *sec = NULL; 60086470930SIngo Molnar size_t cnt = 1; 60186470930SIngo Molnar 60286470930SIngo Molnar while ((sec = elf_nextscn(elf, sec)) != NULL) { 60386470930SIngo Molnar char *str; 60486470930SIngo Molnar 60586470930SIngo Molnar gelf_getshdr(sec, shp); 60686470930SIngo Molnar str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name); 60786470930SIngo Molnar if (!strcmp(name, str)) { 60883a0944fSIngo Molnar if (idx) 60983a0944fSIngo Molnar *idx = cnt; 61086470930SIngo Molnar break; 61186470930SIngo Molnar } 61286470930SIngo Molnar ++cnt; 61386470930SIngo Molnar } 61486470930SIngo Molnar 61586470930SIngo Molnar return sec; 61686470930SIngo Molnar } 61786470930SIngo Molnar 61886470930SIngo Molnar #define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \ 61986470930SIngo Molnar for (idx = 0, pos = gelf_getrel(reldata, 0, &pos_mem); \ 62086470930SIngo Molnar idx < nr_entries; \ 62186470930SIngo Molnar ++idx, pos = gelf_getrel(reldata, idx, &pos_mem)) 62286470930SIngo Molnar 62386470930SIngo Molnar #define elf_section__for_each_rela(reldata, pos, pos_mem, idx, nr_entries) \ 62486470930SIngo Molnar for (idx = 0, pos = gelf_getrela(reldata, 0, &pos_mem); \ 62586470930SIngo Molnar idx < nr_entries; \ 62686470930SIngo Molnar ++idx, pos = gelf_getrela(reldata, idx, &pos_mem)) 62786470930SIngo Molnar 628a25e46c4SArnaldo Carvalho de Melo /* 629a25e46c4SArnaldo Carvalho de Melo * We need to check if we have a .dynsym, so that we can handle the 630a25e46c4SArnaldo Carvalho de Melo * .plt, synthesizing its symbols, that aren't on the symtabs (be it 631a25e46c4SArnaldo Carvalho de Melo * .dynsym or .symtab). 632a25e46c4SArnaldo Carvalho de Melo * And always look at the original dso, not at debuginfo packages, that 633a25e46c4SArnaldo Carvalho de Melo * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS). 634a25e46c4SArnaldo Carvalho de Melo */ 63582164161SArnaldo Carvalho de Melo static int dso__synthesize_plt_symbols(struct dso *self, struct map *map, 63682164161SArnaldo Carvalho de Melo symbol_filter_t filter) 63786470930SIngo Molnar { 63886470930SIngo Molnar uint32_t nr_rel_entries, idx; 63986470930SIngo Molnar GElf_Sym sym; 6409cffa8d5SPaul Mackerras u64 plt_offset; 64186470930SIngo Molnar GElf_Shdr shdr_plt; 64286470930SIngo Molnar struct symbol *f; 643a25e46c4SArnaldo Carvalho de Melo GElf_Shdr shdr_rel_plt, shdr_dynsym; 64486470930SIngo Molnar Elf_Data *reldata, *syms, *symstrs; 645a25e46c4SArnaldo Carvalho de Melo Elf_Scn *scn_plt_rel, *scn_symstrs, *scn_dynsym; 646a25e46c4SArnaldo Carvalho de Melo size_t dynsym_idx; 647a25e46c4SArnaldo Carvalho de Melo GElf_Ehdr ehdr; 64886470930SIngo Molnar char sympltname[1024]; 649a25e46c4SArnaldo Carvalho de Melo Elf *elf; 650a25e46c4SArnaldo Carvalho de Melo int nr = 0, symidx, fd, err = 0; 65186470930SIngo Molnar 652439d473bSArnaldo Carvalho de Melo fd = open(self->long_name, O_RDONLY); 653a25e46c4SArnaldo Carvalho de Melo if (fd < 0) 654a25e46c4SArnaldo Carvalho de Melo goto out; 655a25e46c4SArnaldo Carvalho de Melo 65684087126SMarti Raudsepp elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 657a25e46c4SArnaldo Carvalho de Melo if (elf == NULL) 658a25e46c4SArnaldo Carvalho de Melo goto out_close; 659a25e46c4SArnaldo Carvalho de Melo 660a25e46c4SArnaldo Carvalho de Melo if (gelf_getehdr(elf, &ehdr) == NULL) 661a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 662a25e46c4SArnaldo Carvalho de Melo 663a25e46c4SArnaldo Carvalho de Melo scn_dynsym = elf_section_by_name(elf, &ehdr, &shdr_dynsym, 664a25e46c4SArnaldo Carvalho de Melo ".dynsym", &dynsym_idx); 665a25e46c4SArnaldo Carvalho de Melo if (scn_dynsym == NULL) 666a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 667a25e46c4SArnaldo Carvalho de Melo 668a25e46c4SArnaldo Carvalho de Melo scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt, 66986470930SIngo Molnar ".rela.plt", NULL); 67086470930SIngo Molnar if (scn_plt_rel == NULL) { 671a25e46c4SArnaldo Carvalho de Melo scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt, 67286470930SIngo Molnar ".rel.plt", NULL); 67386470930SIngo Molnar if (scn_plt_rel == NULL) 674a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 67586470930SIngo Molnar } 67686470930SIngo Molnar 677a25e46c4SArnaldo Carvalho de Melo err = -1; 67886470930SIngo Molnar 679a25e46c4SArnaldo Carvalho de Melo if (shdr_rel_plt.sh_link != dynsym_idx) 680a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 681a25e46c4SArnaldo Carvalho de Melo 682a25e46c4SArnaldo Carvalho de Melo if (elf_section_by_name(elf, &ehdr, &shdr_plt, ".plt", NULL) == NULL) 683a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 68486470930SIngo Molnar 68586470930SIngo Molnar /* 68683a0944fSIngo Molnar * Fetch the relocation section to find the idxes to the GOT 68786470930SIngo Molnar * and the symbols in the .dynsym they refer to. 68886470930SIngo Molnar */ 68986470930SIngo Molnar reldata = elf_getdata(scn_plt_rel, NULL); 69086470930SIngo Molnar if (reldata == NULL) 691a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 69286470930SIngo Molnar 69386470930SIngo Molnar syms = elf_getdata(scn_dynsym, NULL); 69486470930SIngo Molnar if (syms == NULL) 695a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 69686470930SIngo Molnar 697a25e46c4SArnaldo Carvalho de Melo scn_symstrs = elf_getscn(elf, shdr_dynsym.sh_link); 69886470930SIngo Molnar if (scn_symstrs == NULL) 699a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 70086470930SIngo Molnar 70186470930SIngo Molnar symstrs = elf_getdata(scn_symstrs, NULL); 70286470930SIngo Molnar if (symstrs == NULL) 703a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 70486470930SIngo Molnar 70586470930SIngo Molnar nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize; 70686470930SIngo Molnar plt_offset = shdr_plt.sh_offset; 70786470930SIngo Molnar 70886470930SIngo Molnar if (shdr_rel_plt.sh_type == SHT_RELA) { 70986470930SIngo Molnar GElf_Rela pos_mem, *pos; 71086470930SIngo Molnar 71186470930SIngo Molnar elf_section__for_each_rela(reldata, pos, pos_mem, idx, 71286470930SIngo Molnar nr_rel_entries) { 71386470930SIngo Molnar symidx = GELF_R_SYM(pos->r_info); 71486470930SIngo Molnar plt_offset += shdr_plt.sh_entsize; 71586470930SIngo Molnar gelf_getsym(syms, symidx, &sym); 71686470930SIngo Molnar snprintf(sympltname, sizeof(sympltname), 71786470930SIngo Molnar "%s@plt", elf_sym__name(&sym, symstrs)); 71886470930SIngo Molnar 71986470930SIngo Molnar f = symbol__new(plt_offset, shdr_plt.sh_entsize, 72000a192b3SArnaldo Carvalho de Melo sympltname); 72186470930SIngo Molnar if (!f) 722a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 72386470930SIngo Molnar 72482164161SArnaldo Carvalho de Melo if (filter && filter(map, f)) 72582164161SArnaldo Carvalho de Melo symbol__delete(f); 72682164161SArnaldo Carvalho de Melo else { 7276a4694a4SArnaldo Carvalho de Melo symbols__insert(&self->symbols[map->type], f); 72886470930SIngo Molnar ++nr; 72986470930SIngo Molnar } 73082164161SArnaldo Carvalho de Melo } 73186470930SIngo Molnar } else if (shdr_rel_plt.sh_type == SHT_REL) { 73286470930SIngo Molnar GElf_Rel pos_mem, *pos; 73386470930SIngo Molnar elf_section__for_each_rel(reldata, pos, pos_mem, idx, 73486470930SIngo Molnar nr_rel_entries) { 73586470930SIngo Molnar symidx = GELF_R_SYM(pos->r_info); 73686470930SIngo Molnar plt_offset += shdr_plt.sh_entsize; 73786470930SIngo Molnar gelf_getsym(syms, symidx, &sym); 73886470930SIngo Molnar snprintf(sympltname, sizeof(sympltname), 73986470930SIngo Molnar "%s@plt", elf_sym__name(&sym, symstrs)); 74086470930SIngo Molnar 74186470930SIngo Molnar f = symbol__new(plt_offset, shdr_plt.sh_entsize, 74200a192b3SArnaldo Carvalho de Melo sympltname); 74386470930SIngo Molnar if (!f) 744a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 74586470930SIngo Molnar 74682164161SArnaldo Carvalho de Melo if (filter && filter(map, f)) 74782164161SArnaldo Carvalho de Melo symbol__delete(f); 74882164161SArnaldo Carvalho de Melo else { 7496a4694a4SArnaldo Carvalho de Melo symbols__insert(&self->symbols[map->type], f); 75086470930SIngo Molnar ++nr; 75186470930SIngo Molnar } 75286470930SIngo Molnar } 75382164161SArnaldo Carvalho de Melo } 75486470930SIngo Molnar 755a25e46c4SArnaldo Carvalho de Melo err = 0; 756a25e46c4SArnaldo Carvalho de Melo out_elf_end: 757a25e46c4SArnaldo Carvalho de Melo elf_end(elf); 758a25e46c4SArnaldo Carvalho de Melo out_close: 759a25e46c4SArnaldo Carvalho de Melo close(fd); 760a25e46c4SArnaldo Carvalho de Melo 761a25e46c4SArnaldo Carvalho de Melo if (err == 0) 76286470930SIngo Molnar return nr; 763a25e46c4SArnaldo Carvalho de Melo out: 7646beba7adSArnaldo Carvalho de Melo pr_warning("%s: problems reading %s PLT info.\n", 765439d473bSArnaldo Carvalho de Melo __func__, self->long_name); 766a25e46c4SArnaldo Carvalho de Melo return 0; 76786470930SIngo Molnar } 76886470930SIngo Molnar 769d45868d3SArnaldo Carvalho de Melo static bool elf_sym__is_a(GElf_Sym *self, enum map_type type) 770d45868d3SArnaldo Carvalho de Melo { 771d45868d3SArnaldo Carvalho de Melo switch (type) { 772d45868d3SArnaldo Carvalho de Melo case MAP__FUNCTION: 773d45868d3SArnaldo Carvalho de Melo return elf_sym__is_function(self); 774*f1dfa0b1SArnaldo Carvalho de Melo case MAP__VARIABLE: 775*f1dfa0b1SArnaldo Carvalho de Melo return elf_sym__is_object(self); 776d45868d3SArnaldo Carvalho de Melo default: 777d45868d3SArnaldo Carvalho de Melo return false; 778d45868d3SArnaldo Carvalho de Melo } 779d45868d3SArnaldo Carvalho de Melo } 780d45868d3SArnaldo Carvalho de Melo 781d45868d3SArnaldo Carvalho de Melo static bool elf_sec__is_a(GElf_Shdr *self, Elf_Data *secstrs, enum map_type type) 782d45868d3SArnaldo Carvalho de Melo { 783d45868d3SArnaldo Carvalho de Melo switch (type) { 784d45868d3SArnaldo Carvalho de Melo case MAP__FUNCTION: 785d45868d3SArnaldo Carvalho de Melo return elf_sec__is_text(self, secstrs); 786*f1dfa0b1SArnaldo Carvalho de Melo case MAP__VARIABLE: 787*f1dfa0b1SArnaldo Carvalho de Melo return elf_sec__is_data(self, secstrs); 788d45868d3SArnaldo Carvalho de Melo default: 789d45868d3SArnaldo Carvalho de Melo return false; 790d45868d3SArnaldo Carvalho de Melo } 791d45868d3SArnaldo Carvalho de Melo } 792d45868d3SArnaldo Carvalho de Melo 79395011c60SArnaldo Carvalho de Melo static int dso__load_sym(struct dso *self, struct map *map, 7949958e1f0SArnaldo Carvalho de Melo struct map_groups *mg, const char *name, int fd, 79595011c60SArnaldo Carvalho de Melo symbol_filter_t filter, int kernel, int kmodule) 79686470930SIngo Molnar { 7972e538c4aSArnaldo Carvalho de Melo struct map *curr_map = map; 7982e538c4aSArnaldo Carvalho de Melo struct dso *curr_dso = self; 7992e538c4aSArnaldo Carvalho de Melo size_t dso_name_len = strlen(self->short_name); 8006cfcc53eSMike Galbraith Elf_Data *symstrs, *secstrs; 80186470930SIngo Molnar uint32_t nr_syms; 80286470930SIngo Molnar int err = -1; 80383a0944fSIngo Molnar uint32_t idx; 80486470930SIngo Molnar GElf_Ehdr ehdr; 80586470930SIngo Molnar GElf_Shdr shdr; 80686470930SIngo Molnar Elf_Data *syms; 80786470930SIngo Molnar GElf_Sym sym; 808a25e46c4SArnaldo Carvalho de Melo Elf_Scn *sec, *sec_strndx; 80986470930SIngo Molnar Elf *elf; 810439d473bSArnaldo Carvalho de Melo int nr = 0; 81186470930SIngo Molnar 81284087126SMarti Raudsepp elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 81386470930SIngo Molnar if (elf == NULL) { 8146beba7adSArnaldo Carvalho de Melo pr_err("%s: cannot read %s ELF file.\n", __func__, name); 81586470930SIngo Molnar goto out_close; 81686470930SIngo Molnar } 81786470930SIngo Molnar 81886470930SIngo Molnar if (gelf_getehdr(elf, &ehdr) == NULL) { 8196beba7adSArnaldo Carvalho de Melo pr_err("%s: cannot get elf header.\n", __func__); 82086470930SIngo Molnar goto out_elf_end; 82186470930SIngo Molnar } 82286470930SIngo Molnar 82386470930SIngo Molnar sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL); 82486470930SIngo Molnar if (sec == NULL) { 825a25e46c4SArnaldo Carvalho de Melo sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL); 826a25e46c4SArnaldo Carvalho de Melo if (sec == NULL) 82786470930SIngo Molnar goto out_elf_end; 82886470930SIngo Molnar } 82986470930SIngo Molnar 83086470930SIngo Molnar syms = elf_getdata(sec, NULL); 83186470930SIngo Molnar if (syms == NULL) 83286470930SIngo Molnar goto out_elf_end; 83386470930SIngo Molnar 83486470930SIngo Molnar sec = elf_getscn(elf, shdr.sh_link); 83586470930SIngo Molnar if (sec == NULL) 83686470930SIngo Molnar goto out_elf_end; 83786470930SIngo Molnar 83886470930SIngo Molnar symstrs = elf_getdata(sec, NULL); 83986470930SIngo Molnar if (symstrs == NULL) 84086470930SIngo Molnar goto out_elf_end; 84186470930SIngo Molnar 8426cfcc53eSMike Galbraith sec_strndx = elf_getscn(elf, ehdr.e_shstrndx); 8436cfcc53eSMike Galbraith if (sec_strndx == NULL) 8446cfcc53eSMike Galbraith goto out_elf_end; 8456cfcc53eSMike Galbraith 8466cfcc53eSMike Galbraith secstrs = elf_getdata(sec_strndx, NULL); 8479b30a26bSStoyan Gaydarov if (secstrs == NULL) 8486cfcc53eSMike Galbraith goto out_elf_end; 8496cfcc53eSMike Galbraith 85086470930SIngo Molnar nr_syms = shdr.sh_size / shdr.sh_entsize; 85186470930SIngo Molnar 852e9fbc9dcSArjan van de Ven memset(&sym, 0, sizeof(sym)); 853d20ff6bdSMike Galbraith if (!kernel) { 85430d7a77dSArnaldo Carvalho de Melo self->adjust_symbols = (ehdr.e_type == ET_EXEC || 85530d7a77dSArnaldo Carvalho de Melo elf_section_by_name(elf, &ehdr, &shdr, 856f5812a7aSArnaldo Carvalho de Melo ".gnu.prelink_undo", 85730d7a77dSArnaldo Carvalho de Melo NULL) != NULL); 858d20ff6bdSMike Galbraith } else self->adjust_symbols = 0; 859d20ff6bdSMike Galbraith 86083a0944fSIngo Molnar elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) { 86186470930SIngo Molnar struct symbol *f; 86283a0944fSIngo Molnar const char *elf_name; 8632e538c4aSArnaldo Carvalho de Melo char *demangled = NULL; 8646cfcc53eSMike Galbraith int is_label = elf_sym__is_label(&sym); 8656cfcc53eSMike Galbraith const char *section_name; 86686470930SIngo Molnar 867d45868d3SArnaldo Carvalho de Melo if (!is_label && !elf_sym__is_a(&sym, map->type)) 86886470930SIngo Molnar continue; 86986470930SIngo Molnar 87086470930SIngo Molnar sec = elf_getscn(elf, sym.st_shndx); 87186470930SIngo Molnar if (!sec) 87286470930SIngo Molnar goto out_elf_end; 87386470930SIngo Molnar 87486470930SIngo Molnar gelf_getshdr(sec, &shdr); 8756cfcc53eSMike Galbraith 876d45868d3SArnaldo Carvalho de Melo if (is_label && !elf_sec__is_a(&shdr, secstrs, map->type)) 8776cfcc53eSMike Galbraith continue; 8786cfcc53eSMike Galbraith 8792e538c4aSArnaldo Carvalho de Melo elf_name = elf_sym__name(&sym, symstrs); 8806cfcc53eSMike Galbraith section_name = elf_sec__name(&shdr, secstrs); 88186470930SIngo Molnar 8822e538c4aSArnaldo Carvalho de Melo if (kernel || kmodule) { 8832e538c4aSArnaldo Carvalho de Melo char dso_name[PATH_MAX]; 8842e538c4aSArnaldo Carvalho de Melo 8852e538c4aSArnaldo Carvalho de Melo if (strcmp(section_name, 8862e538c4aSArnaldo Carvalho de Melo curr_dso->short_name + dso_name_len) == 0) 8872e538c4aSArnaldo Carvalho de Melo goto new_symbol; 8882e538c4aSArnaldo Carvalho de Melo 8892e538c4aSArnaldo Carvalho de Melo if (strcmp(section_name, ".text") == 0) { 8902e538c4aSArnaldo Carvalho de Melo curr_map = map; 8912e538c4aSArnaldo Carvalho de Melo curr_dso = self; 8922e538c4aSArnaldo Carvalho de Melo goto new_symbol; 893af427bf5SArnaldo Carvalho de Melo } 894af427bf5SArnaldo Carvalho de Melo 8952e538c4aSArnaldo Carvalho de Melo snprintf(dso_name, sizeof(dso_name), 8962e538c4aSArnaldo Carvalho de Melo "%s%s", self->short_name, section_name); 8972e538c4aSArnaldo Carvalho de Melo 8989958e1f0SArnaldo Carvalho de Melo curr_map = map_groups__find_by_name(mg, dso_name); 8992e538c4aSArnaldo Carvalho de Melo if (curr_map == NULL) { 9002e538c4aSArnaldo Carvalho de Melo u64 start = sym.st_value; 9012e538c4aSArnaldo Carvalho de Melo 9022e538c4aSArnaldo Carvalho de Melo if (kmodule) 9032e538c4aSArnaldo Carvalho de Melo start += map->start + shdr.sh_offset; 9042e538c4aSArnaldo Carvalho de Melo 90500a192b3SArnaldo Carvalho de Melo curr_dso = dso__new(dso_name); 9062e538c4aSArnaldo Carvalho de Melo if (curr_dso == NULL) 9072e538c4aSArnaldo Carvalho de Melo goto out_elf_end; 9083610583cSArnaldo Carvalho de Melo curr_map = map__new2(start, curr_dso, 9093610583cSArnaldo Carvalho de Melo MAP__FUNCTION); 9102e538c4aSArnaldo Carvalho de Melo if (curr_map == NULL) { 9112e538c4aSArnaldo Carvalho de Melo dso__delete(curr_dso); 9122e538c4aSArnaldo Carvalho de Melo goto out_elf_end; 9132e538c4aSArnaldo Carvalho de Melo } 914ed52ce2eSArnaldo Carvalho de Melo curr_map->map_ip = identity__map_ip; 915ed52ce2eSArnaldo Carvalho de Melo curr_map->unmap_ip = identity__map_ip; 9162e538c4aSArnaldo Carvalho de Melo curr_dso->origin = DSO__ORIG_KERNEL; 9179958e1f0SArnaldo Carvalho de Melo map_groups__insert(kmaps, curr_map); 918b0da954aSArnaldo Carvalho de Melo dsos__add(&dsos__kernel, curr_dso); 9192e538c4aSArnaldo Carvalho de Melo } else 9202e538c4aSArnaldo Carvalho de Melo curr_dso = curr_map->dso; 9212e538c4aSArnaldo Carvalho de Melo 9222e538c4aSArnaldo Carvalho de Melo goto new_symbol; 9232e538c4aSArnaldo Carvalho de Melo } 9242e538c4aSArnaldo Carvalho de Melo 9252e538c4aSArnaldo Carvalho de Melo if (curr_dso->adjust_symbols) { 9266beba7adSArnaldo Carvalho de Melo pr_debug2("adjusting symbol: st_value: %Lx sh_addr: " 9276beba7adSArnaldo Carvalho de Melo "%Lx sh_offset: %Lx\n", (u64)sym.st_value, 9286beba7adSArnaldo Carvalho de Melo (u64)shdr.sh_addr, (u64)shdr.sh_offset); 92986470930SIngo Molnar sym.st_value -= shdr.sh_addr - shdr.sh_offset; 930af427bf5SArnaldo Carvalho de Melo } 93128ac909bSArnaldo Carvalho de Melo /* 93228ac909bSArnaldo Carvalho de Melo * We need to figure out if the object was created from C++ sources 93328ac909bSArnaldo Carvalho de Melo * DWARF DW_compile_unit has this, but we don't always have access 93428ac909bSArnaldo Carvalho de Melo * to it... 93528ac909bSArnaldo Carvalho de Melo */ 93683a0944fSIngo Molnar demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI); 93728ac909bSArnaldo Carvalho de Melo if (demangled != NULL) 93883a0944fSIngo Molnar elf_name = demangled; 9392e538c4aSArnaldo Carvalho de Melo new_symbol: 94000a192b3SArnaldo Carvalho de Melo f = symbol__new(sym.st_value, sym.st_size, elf_name); 94128ac909bSArnaldo Carvalho de Melo free(demangled); 94286470930SIngo Molnar if (!f) 94386470930SIngo Molnar goto out_elf_end; 94486470930SIngo Molnar 9452e538c4aSArnaldo Carvalho de Melo if (filter && filter(curr_map, f)) 94600a192b3SArnaldo Carvalho de Melo symbol__delete(f); 94786470930SIngo Molnar else { 9486a4694a4SArnaldo Carvalho de Melo symbols__insert(&curr_dso->symbols[curr_map->type], f); 94986470930SIngo Molnar nr++; 95086470930SIngo Molnar } 95186470930SIngo Molnar } 95286470930SIngo Molnar 9532e538c4aSArnaldo Carvalho de Melo /* 9542e538c4aSArnaldo Carvalho de Melo * For misannotated, zeroed, ASM function sizes. 9552e538c4aSArnaldo Carvalho de Melo */ 9562e538c4aSArnaldo Carvalho de Melo if (nr > 0) 9576a4694a4SArnaldo Carvalho de Melo symbols__fixup_end(&self->symbols[map->type]); 95886470930SIngo Molnar err = nr; 95986470930SIngo Molnar out_elf_end: 96086470930SIngo Molnar elf_end(elf); 96186470930SIngo Molnar out_close: 96286470930SIngo Molnar return err; 96386470930SIngo Molnar } 96486470930SIngo Molnar 96578075caaSArnaldo Carvalho de Melo static bool dso__build_id_equal(const struct dso *self, u8 *build_id) 96678075caaSArnaldo Carvalho de Melo { 96778075caaSArnaldo Carvalho de Melo return memcmp(self->build_id, build_id, sizeof(self->build_id)) == 0; 96878075caaSArnaldo Carvalho de Melo } 96978075caaSArnaldo Carvalho de Melo 970b0da954aSArnaldo Carvalho de Melo static bool __dsos__read_build_ids(struct list_head *head) 97157f395a7SFrederic Weisbecker { 972e30a3d12SArnaldo Carvalho de Melo bool have_build_id = false; 97357f395a7SFrederic Weisbecker struct dso *pos; 97457f395a7SFrederic Weisbecker 975b0da954aSArnaldo Carvalho de Melo list_for_each_entry(pos, head, node) 976e30a3d12SArnaldo Carvalho de Melo if (filename__read_build_id(pos->long_name, pos->build_id, 977e30a3d12SArnaldo Carvalho de Melo sizeof(pos->build_id)) > 0) { 978e30a3d12SArnaldo Carvalho de Melo have_build_id = true; 979e30a3d12SArnaldo Carvalho de Melo pos->has_build_id = true; 98057f395a7SFrederic Weisbecker } 98157f395a7SFrederic Weisbecker 982e30a3d12SArnaldo Carvalho de Melo return have_build_id; 98357f395a7SFrederic Weisbecker } 98457f395a7SFrederic Weisbecker 985b0da954aSArnaldo Carvalho de Melo bool dsos__read_build_ids(void) 986b0da954aSArnaldo Carvalho de Melo { 9878b4825bfSArnaldo Carvalho de Melo bool kbuildids = __dsos__read_build_ids(&dsos__kernel), 9888b4825bfSArnaldo Carvalho de Melo ubuildids = __dsos__read_build_ids(&dsos__user); 9898b4825bfSArnaldo Carvalho de Melo return kbuildids || ubuildids; 990b0da954aSArnaldo Carvalho de Melo } 991b0da954aSArnaldo Carvalho de Melo 992fd7a346eSArnaldo Carvalho de Melo /* 993fd7a346eSArnaldo Carvalho de Melo * Align offset to 4 bytes as needed for note name and descriptor data. 994fd7a346eSArnaldo Carvalho de Melo */ 995fd7a346eSArnaldo Carvalho de Melo #define NOTE_ALIGN(n) (((n) + 3) & -4U) 996fd7a346eSArnaldo Carvalho de Melo 9972643ce11SArnaldo Carvalho de Melo int filename__read_build_id(const char *filename, void *bf, size_t size) 9984d1e00a8SArnaldo Carvalho de Melo { 9992643ce11SArnaldo Carvalho de Melo int fd, err = -1; 10004d1e00a8SArnaldo Carvalho de Melo GElf_Ehdr ehdr; 10014d1e00a8SArnaldo Carvalho de Melo GElf_Shdr shdr; 1002fd7a346eSArnaldo Carvalho de Melo Elf_Data *data; 10034d1e00a8SArnaldo Carvalho de Melo Elf_Scn *sec; 1004e57cfcdaSPekka Enberg Elf_Kind ek; 1005fd7a346eSArnaldo Carvalho de Melo void *ptr; 10064d1e00a8SArnaldo Carvalho de Melo Elf *elf; 10074d1e00a8SArnaldo Carvalho de Melo 10082643ce11SArnaldo Carvalho de Melo if (size < BUILD_ID_SIZE) 10092643ce11SArnaldo Carvalho de Melo goto out; 10102643ce11SArnaldo Carvalho de Melo 10112643ce11SArnaldo Carvalho de Melo fd = open(filename, O_RDONLY); 10124d1e00a8SArnaldo Carvalho de Melo if (fd < 0) 10134d1e00a8SArnaldo Carvalho de Melo goto out; 10144d1e00a8SArnaldo Carvalho de Melo 101584087126SMarti Raudsepp elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 10164d1e00a8SArnaldo Carvalho de Melo if (elf == NULL) { 10178d06367fSArnaldo Carvalho de Melo pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename); 10184d1e00a8SArnaldo Carvalho de Melo goto out_close; 10194d1e00a8SArnaldo Carvalho de Melo } 10204d1e00a8SArnaldo Carvalho de Melo 1021e57cfcdaSPekka Enberg ek = elf_kind(elf); 1022e57cfcdaSPekka Enberg if (ek != ELF_K_ELF) 1023e57cfcdaSPekka Enberg goto out_elf_end; 1024e57cfcdaSPekka Enberg 10254d1e00a8SArnaldo Carvalho de Melo if (gelf_getehdr(elf, &ehdr) == NULL) { 10266beba7adSArnaldo Carvalho de Melo pr_err("%s: cannot get elf header.\n", __func__); 10274d1e00a8SArnaldo Carvalho de Melo goto out_elf_end; 10284d1e00a8SArnaldo Carvalho de Melo } 10294d1e00a8SArnaldo Carvalho de Melo 10302643ce11SArnaldo Carvalho de Melo sec = elf_section_by_name(elf, &ehdr, &shdr, 10312643ce11SArnaldo Carvalho de Melo ".note.gnu.build-id", NULL); 1032fd7a346eSArnaldo Carvalho de Melo if (sec == NULL) { 1033fd7a346eSArnaldo Carvalho de Melo sec = elf_section_by_name(elf, &ehdr, &shdr, 1034fd7a346eSArnaldo Carvalho de Melo ".notes", NULL); 10354d1e00a8SArnaldo Carvalho de Melo if (sec == NULL) 10364d1e00a8SArnaldo Carvalho de Melo goto out_elf_end; 1037fd7a346eSArnaldo Carvalho de Melo } 10384d1e00a8SArnaldo Carvalho de Melo 1039fd7a346eSArnaldo Carvalho de Melo data = elf_getdata(sec, NULL); 1040fd7a346eSArnaldo Carvalho de Melo if (data == NULL) 10414d1e00a8SArnaldo Carvalho de Melo goto out_elf_end; 1042fd7a346eSArnaldo Carvalho de Melo 1043fd7a346eSArnaldo Carvalho de Melo ptr = data->d_buf; 1044fd7a346eSArnaldo Carvalho de Melo while (ptr < (data->d_buf + data->d_size)) { 1045fd7a346eSArnaldo Carvalho de Melo GElf_Nhdr *nhdr = ptr; 1046fd7a346eSArnaldo Carvalho de Melo int namesz = NOTE_ALIGN(nhdr->n_namesz), 1047fd7a346eSArnaldo Carvalho de Melo descsz = NOTE_ALIGN(nhdr->n_descsz); 1048fd7a346eSArnaldo Carvalho de Melo const char *name; 1049fd7a346eSArnaldo Carvalho de Melo 1050fd7a346eSArnaldo Carvalho de Melo ptr += sizeof(*nhdr); 1051fd7a346eSArnaldo Carvalho de Melo name = ptr; 1052fd7a346eSArnaldo Carvalho de Melo ptr += namesz; 1053fd7a346eSArnaldo Carvalho de Melo if (nhdr->n_type == NT_GNU_BUILD_ID && 1054fd7a346eSArnaldo Carvalho de Melo nhdr->n_namesz == sizeof("GNU")) { 1055fd7a346eSArnaldo Carvalho de Melo if (memcmp(name, "GNU", sizeof("GNU")) == 0) { 1056fd7a346eSArnaldo Carvalho de Melo memcpy(bf, ptr, BUILD_ID_SIZE); 10572643ce11SArnaldo Carvalho de Melo err = BUILD_ID_SIZE; 1058fd7a346eSArnaldo Carvalho de Melo break; 1059fd7a346eSArnaldo Carvalho de Melo } 1060fd7a346eSArnaldo Carvalho de Melo } 1061fd7a346eSArnaldo Carvalho de Melo ptr += descsz; 1062fd7a346eSArnaldo Carvalho de Melo } 10632643ce11SArnaldo Carvalho de Melo out_elf_end: 10642643ce11SArnaldo Carvalho de Melo elf_end(elf); 10652643ce11SArnaldo Carvalho de Melo out_close: 10662643ce11SArnaldo Carvalho de Melo close(fd); 10672643ce11SArnaldo Carvalho de Melo out: 10682643ce11SArnaldo Carvalho de Melo return err; 10692643ce11SArnaldo Carvalho de Melo } 10702643ce11SArnaldo Carvalho de Melo 1071f1617b40SArnaldo Carvalho de Melo int sysfs__read_build_id(const char *filename, void *build_id, size_t size) 1072f1617b40SArnaldo Carvalho de Melo { 1073f1617b40SArnaldo Carvalho de Melo int fd, err = -1; 1074f1617b40SArnaldo Carvalho de Melo 1075f1617b40SArnaldo Carvalho de Melo if (size < BUILD_ID_SIZE) 1076f1617b40SArnaldo Carvalho de Melo goto out; 1077f1617b40SArnaldo Carvalho de Melo 1078f1617b40SArnaldo Carvalho de Melo fd = open(filename, O_RDONLY); 1079f1617b40SArnaldo Carvalho de Melo if (fd < 0) 1080f1617b40SArnaldo Carvalho de Melo goto out; 1081f1617b40SArnaldo Carvalho de Melo 1082f1617b40SArnaldo Carvalho de Melo while (1) { 1083f1617b40SArnaldo Carvalho de Melo char bf[BUFSIZ]; 1084f1617b40SArnaldo Carvalho de Melo GElf_Nhdr nhdr; 1085f1617b40SArnaldo Carvalho de Melo int namesz, descsz; 1086f1617b40SArnaldo Carvalho de Melo 1087f1617b40SArnaldo Carvalho de Melo if (read(fd, &nhdr, sizeof(nhdr)) != sizeof(nhdr)) 1088f1617b40SArnaldo Carvalho de Melo break; 1089f1617b40SArnaldo Carvalho de Melo 1090fd7a346eSArnaldo Carvalho de Melo namesz = NOTE_ALIGN(nhdr.n_namesz); 1091fd7a346eSArnaldo Carvalho de Melo descsz = NOTE_ALIGN(nhdr.n_descsz); 1092f1617b40SArnaldo Carvalho de Melo if (nhdr.n_type == NT_GNU_BUILD_ID && 1093f1617b40SArnaldo Carvalho de Melo nhdr.n_namesz == sizeof("GNU")) { 1094f1617b40SArnaldo Carvalho de Melo if (read(fd, bf, namesz) != namesz) 1095f1617b40SArnaldo Carvalho de Melo break; 1096f1617b40SArnaldo Carvalho de Melo if (memcmp(bf, "GNU", sizeof("GNU")) == 0) { 1097f1617b40SArnaldo Carvalho de Melo if (read(fd, build_id, 1098f1617b40SArnaldo Carvalho de Melo BUILD_ID_SIZE) == BUILD_ID_SIZE) { 1099f1617b40SArnaldo Carvalho de Melo err = 0; 1100f1617b40SArnaldo Carvalho de Melo break; 1101f1617b40SArnaldo Carvalho de Melo } 1102f1617b40SArnaldo Carvalho de Melo } else if (read(fd, bf, descsz) != descsz) 1103f1617b40SArnaldo Carvalho de Melo break; 1104f1617b40SArnaldo Carvalho de Melo } else { 1105f1617b40SArnaldo Carvalho de Melo int n = namesz + descsz; 1106f1617b40SArnaldo Carvalho de Melo if (read(fd, bf, n) != n) 1107f1617b40SArnaldo Carvalho de Melo break; 1108f1617b40SArnaldo Carvalho de Melo } 1109f1617b40SArnaldo Carvalho de Melo } 1110f1617b40SArnaldo Carvalho de Melo close(fd); 1111f1617b40SArnaldo Carvalho de Melo out: 1112f1617b40SArnaldo Carvalho de Melo return err; 1113f1617b40SArnaldo Carvalho de Melo } 1114f1617b40SArnaldo Carvalho de Melo 111594cb9e38SArnaldo Carvalho de Melo char dso__symtab_origin(const struct dso *self) 111694cb9e38SArnaldo Carvalho de Melo { 111794cb9e38SArnaldo Carvalho de Melo static const char origin[] = { 111894cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_KERNEL] = 'k', 111994cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_JAVA_JIT] = 'j', 112094cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_FEDORA] = 'f', 112194cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_UBUNTU] = 'u', 112294cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_BUILDID] = 'b', 112394cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_DSO] = 'd', 1124439d473bSArnaldo Carvalho de Melo [DSO__ORIG_KMODULE] = 'K', 112594cb9e38SArnaldo Carvalho de Melo }; 112694cb9e38SArnaldo Carvalho de Melo 112794cb9e38SArnaldo Carvalho de Melo if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND) 112894cb9e38SArnaldo Carvalho de Melo return '!'; 112994cb9e38SArnaldo Carvalho de Melo return origin[self->origin]; 113094cb9e38SArnaldo Carvalho de Melo } 113194cb9e38SArnaldo Carvalho de Melo 11326beba7adSArnaldo Carvalho de Melo int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) 113386470930SIngo Molnar { 11344d1e00a8SArnaldo Carvalho de Melo int size = PATH_MAX; 1135c338aee8SArnaldo Carvalho de Melo char *name; 1136d3379ab9SArnaldo Carvalho de Melo u8 build_id[BUILD_ID_SIZE]; 113786470930SIngo Molnar int ret = -1; 113886470930SIngo Molnar int fd; 113986470930SIngo Molnar 11403610583cSArnaldo Carvalho de Melo dso__set_loaded(self, map->type); 114166bd8424SArnaldo Carvalho de Melo 1142c338aee8SArnaldo Carvalho de Melo if (self->kernel) 11439958e1f0SArnaldo Carvalho de Melo return dso__load_kernel_sym(self, map, kmaps, filter); 1144c338aee8SArnaldo Carvalho de Melo 1145c338aee8SArnaldo Carvalho de Melo name = malloc(size); 114686470930SIngo Molnar if (!name) 114786470930SIngo Molnar return -1; 114886470930SIngo Molnar 114930d7a77dSArnaldo Carvalho de Melo self->adjust_symbols = 0; 1150f5812a7aSArnaldo Carvalho de Melo 115194cb9e38SArnaldo Carvalho de Melo if (strncmp(self->name, "/tmp/perf-", 10) == 0) { 11526beba7adSArnaldo Carvalho de Melo ret = dso__load_perf_map(self, map, filter); 115394cb9e38SArnaldo Carvalho de Melo self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT : 115494cb9e38SArnaldo Carvalho de Melo DSO__ORIG_NOT_FOUND; 115594cb9e38SArnaldo Carvalho de Melo return ret; 115694cb9e38SArnaldo Carvalho de Melo } 115794cb9e38SArnaldo Carvalho de Melo 115894cb9e38SArnaldo Carvalho de Melo self->origin = DSO__ORIG_FEDORA - 1; 115980d496beSPekka Enberg 116086470930SIngo Molnar more: 116186470930SIngo Molnar do { 116294cb9e38SArnaldo Carvalho de Melo self->origin++; 116394cb9e38SArnaldo Carvalho de Melo switch (self->origin) { 116494cb9e38SArnaldo Carvalho de Melo case DSO__ORIG_FEDORA: 1165439d473bSArnaldo Carvalho de Melo snprintf(name, size, "/usr/lib/debug%s.debug", 1166439d473bSArnaldo Carvalho de Melo self->long_name); 116786470930SIngo Molnar break; 116894cb9e38SArnaldo Carvalho de Melo case DSO__ORIG_UBUNTU: 1169439d473bSArnaldo Carvalho de Melo snprintf(name, size, "/usr/lib/debug%s", 1170439d473bSArnaldo Carvalho de Melo self->long_name); 117186470930SIngo Molnar break; 117294cb9e38SArnaldo Carvalho de Melo case DSO__ORIG_BUILDID: 1173d3379ab9SArnaldo Carvalho de Melo if (filename__read_build_id(self->long_name, build_id, 1174d3379ab9SArnaldo Carvalho de Melo sizeof(build_id))) { 1175d3379ab9SArnaldo Carvalho de Melo char build_id_hex[BUILD_ID_SIZE * 2 + 1]; 1176d3379ab9SArnaldo Carvalho de Melo 1177d3379ab9SArnaldo Carvalho de Melo build_id__sprintf(build_id, sizeof(build_id), 1178d3379ab9SArnaldo Carvalho de Melo build_id_hex); 11794d1e00a8SArnaldo Carvalho de Melo snprintf(name, size, 11804d1e00a8SArnaldo Carvalho de Melo "/usr/lib/debug/.build-id/%.2s/%s.debug", 1181d3379ab9SArnaldo Carvalho de Melo build_id_hex, build_id_hex + 2); 1182d3379ab9SArnaldo Carvalho de Melo if (self->has_build_id) 11838d06367fSArnaldo Carvalho de Melo goto compare_build_id; 1184d3379ab9SArnaldo Carvalho de Melo break; 11854d1e00a8SArnaldo Carvalho de Melo } 118694cb9e38SArnaldo Carvalho de Melo self->origin++; 11874d1e00a8SArnaldo Carvalho de Melo /* Fall thru */ 118894cb9e38SArnaldo Carvalho de Melo case DSO__ORIG_DSO: 1189439d473bSArnaldo Carvalho de Melo snprintf(name, size, "%s", self->long_name); 119086470930SIngo Molnar break; 119186470930SIngo Molnar 119286470930SIngo Molnar default: 119386470930SIngo Molnar goto out; 119486470930SIngo Molnar } 119586470930SIngo Molnar 11968d06367fSArnaldo Carvalho de Melo if (self->has_build_id) { 1197d3379ab9SArnaldo Carvalho de Melo if (filename__read_build_id(name, build_id, 1198d3379ab9SArnaldo Carvalho de Melo sizeof(build_id)) < 0) 11998d06367fSArnaldo Carvalho de Melo goto more; 12008d06367fSArnaldo Carvalho de Melo compare_build_id: 120178075caaSArnaldo Carvalho de Melo if (!dso__build_id_equal(self, build_id)) 12028d06367fSArnaldo Carvalho de Melo goto more; 12038d06367fSArnaldo Carvalho de Melo } 12048d06367fSArnaldo Carvalho de Melo 120586470930SIngo Molnar fd = open(name, O_RDONLY); 120686470930SIngo Molnar } while (fd < 0); 120786470930SIngo Molnar 120895011c60SArnaldo Carvalho de Melo ret = dso__load_sym(self, map, NULL, name, fd, filter, 0, 0); 120986470930SIngo Molnar close(fd); 121086470930SIngo Molnar 121186470930SIngo Molnar /* 121286470930SIngo Molnar * Some people seem to have debuginfo files _WITHOUT_ debug info!?!? 121386470930SIngo Molnar */ 121486470930SIngo Molnar if (!ret) 121586470930SIngo Molnar goto more; 121686470930SIngo Molnar 1217a25e46c4SArnaldo Carvalho de Melo if (ret > 0) { 121882164161SArnaldo Carvalho de Melo int nr_plt = dso__synthesize_plt_symbols(self, map, filter); 1219a25e46c4SArnaldo Carvalho de Melo if (nr_plt > 0) 1220a25e46c4SArnaldo Carvalho de Melo ret += nr_plt; 1221a25e46c4SArnaldo Carvalho de Melo } 122286470930SIngo Molnar out: 122386470930SIngo Molnar free(name); 12241340e6bbSArnaldo Carvalho de Melo if (ret < 0 && strstr(self->name, " (deleted)") != NULL) 12251340e6bbSArnaldo Carvalho de Melo return 0; 122686470930SIngo Molnar return ret; 122786470930SIngo Molnar } 122886470930SIngo Molnar 12299958e1f0SArnaldo Carvalho de Melo static struct map *map_groups__find_by_name(struct map_groups *self, char *name) 1230439d473bSArnaldo Carvalho de Melo { 1231439d473bSArnaldo Carvalho de Melo struct rb_node *nd; 1232439d473bSArnaldo Carvalho de Melo 123395011c60SArnaldo Carvalho de Melo for (nd = rb_first(&self->maps[MAP__FUNCTION]); nd; nd = rb_next(nd)) { 1234439d473bSArnaldo Carvalho de Melo struct map *map = rb_entry(nd, struct map, rb_node); 1235439d473bSArnaldo Carvalho de Melo 1236439d473bSArnaldo Carvalho de Melo if (map->dso && strcmp(map->dso->name, name) == 0) 1237439d473bSArnaldo Carvalho de Melo return map; 1238439d473bSArnaldo Carvalho de Melo } 1239439d473bSArnaldo Carvalho de Melo 1240439d473bSArnaldo Carvalho de Melo return NULL; 1241439d473bSArnaldo Carvalho de Melo } 1242439d473bSArnaldo Carvalho de Melo 1243c338aee8SArnaldo Carvalho de Melo static int dsos__set_modules_path_dir(char *dirname) 12446cfcc53eSMike Galbraith { 1245439d473bSArnaldo Carvalho de Melo struct dirent *dent; 1246439d473bSArnaldo Carvalho de Melo DIR *dir = opendir(dirname); 12476cfcc53eSMike Galbraith 1248439d473bSArnaldo Carvalho de Melo if (!dir) { 124987f8ea4cSArnaldo Carvalho de Melo pr_debug("%s: cannot open %s dir\n", __func__, dirname); 1250439d473bSArnaldo Carvalho de Melo return -1; 1251439d473bSArnaldo Carvalho de Melo } 12526cfcc53eSMike Galbraith 1253439d473bSArnaldo Carvalho de Melo while ((dent = readdir(dir)) != NULL) { 1254439d473bSArnaldo Carvalho de Melo char path[PATH_MAX]; 1255439d473bSArnaldo Carvalho de Melo 1256439d473bSArnaldo Carvalho de Melo if (dent->d_type == DT_DIR) { 1257439d473bSArnaldo Carvalho de Melo if (!strcmp(dent->d_name, ".") || 1258439d473bSArnaldo Carvalho de Melo !strcmp(dent->d_name, "..")) 1259439d473bSArnaldo Carvalho de Melo continue; 1260439d473bSArnaldo Carvalho de Melo 1261439d473bSArnaldo Carvalho de Melo snprintf(path, sizeof(path), "%s/%s", 1262439d473bSArnaldo Carvalho de Melo dirname, dent->d_name); 1263c338aee8SArnaldo Carvalho de Melo if (dsos__set_modules_path_dir(path) < 0) 1264439d473bSArnaldo Carvalho de Melo goto failure; 1265439d473bSArnaldo Carvalho de Melo } else { 1266439d473bSArnaldo Carvalho de Melo char *dot = strrchr(dent->d_name, '.'), 1267439d473bSArnaldo Carvalho de Melo dso_name[PATH_MAX]; 1268439d473bSArnaldo Carvalho de Melo struct map *map; 1269cfc10d3bSArnaldo Carvalho de Melo char *long_name; 1270439d473bSArnaldo Carvalho de Melo 1271439d473bSArnaldo Carvalho de Melo if (dot == NULL || strcmp(dot, ".ko")) 1272439d473bSArnaldo Carvalho de Melo continue; 1273439d473bSArnaldo Carvalho de Melo snprintf(dso_name, sizeof(dso_name), "[%.*s]", 1274439d473bSArnaldo Carvalho de Melo (int)(dot - dent->d_name), dent->d_name); 1275439d473bSArnaldo Carvalho de Melo 1276a2a99e8eSArnaldo Carvalho de Melo strxfrchar(dso_name, '-', '_'); 12779958e1f0SArnaldo Carvalho de Melo map = map_groups__find_by_name(kmaps, dso_name); 1278439d473bSArnaldo Carvalho de Melo if (map == NULL) 1279439d473bSArnaldo Carvalho de Melo continue; 1280439d473bSArnaldo Carvalho de Melo 1281439d473bSArnaldo Carvalho de Melo snprintf(path, sizeof(path), "%s/%s", 1282439d473bSArnaldo Carvalho de Melo dirname, dent->d_name); 1283439d473bSArnaldo Carvalho de Melo 1284cfc10d3bSArnaldo Carvalho de Melo long_name = strdup(path); 1285cfc10d3bSArnaldo Carvalho de Melo if (long_name == NULL) 1286439d473bSArnaldo Carvalho de Melo goto failure; 1287cfc10d3bSArnaldo Carvalho de Melo dso__set_long_name(map->dso, long_name); 1288439d473bSArnaldo Carvalho de Melo } 1289439d473bSArnaldo Carvalho de Melo } 1290439d473bSArnaldo Carvalho de Melo 1291c338aee8SArnaldo Carvalho de Melo return 0; 1292439d473bSArnaldo Carvalho de Melo failure: 1293439d473bSArnaldo Carvalho de Melo closedir(dir); 1294439d473bSArnaldo Carvalho de Melo return -1; 1295439d473bSArnaldo Carvalho de Melo } 1296439d473bSArnaldo Carvalho de Melo 1297c338aee8SArnaldo Carvalho de Melo static int dsos__set_modules_path(void) 1298439d473bSArnaldo Carvalho de Melo { 1299439d473bSArnaldo Carvalho de Melo struct utsname uts; 1300439d473bSArnaldo Carvalho de Melo char modules_path[PATH_MAX]; 1301439d473bSArnaldo Carvalho de Melo 1302439d473bSArnaldo Carvalho de Melo if (uname(&uts) < 0) 1303439d473bSArnaldo Carvalho de Melo return -1; 1304439d473bSArnaldo Carvalho de Melo 1305439d473bSArnaldo Carvalho de Melo snprintf(modules_path, sizeof(modules_path), "/lib/modules/%s/kernel", 1306439d473bSArnaldo Carvalho de Melo uts.release); 1307439d473bSArnaldo Carvalho de Melo 1308c338aee8SArnaldo Carvalho de Melo return dsos__set_modules_path_dir(modules_path); 1309439d473bSArnaldo Carvalho de Melo } 13106cfcc53eSMike Galbraith 13116cfcc53eSMike Galbraith /* 1312439d473bSArnaldo Carvalho de Melo * Constructor variant for modules (where we know from /proc/modules where 1313439d473bSArnaldo Carvalho de Melo * they are loaded) and for vmlinux, where only after we load all the 1314439d473bSArnaldo Carvalho de Melo * symbols we'll know where it starts and ends. 13156cfcc53eSMike Galbraith */ 13163610583cSArnaldo Carvalho de Melo static struct map *map__new2(u64 start, struct dso *dso, enum map_type type) 1317439d473bSArnaldo Carvalho de Melo { 1318439d473bSArnaldo Carvalho de Melo struct map *self = malloc(sizeof(*self)); 13196cfcc53eSMike Galbraith 1320439d473bSArnaldo Carvalho de Melo if (self != NULL) { 1321439d473bSArnaldo Carvalho de Melo /* 1322afb7b4f0SArnaldo Carvalho de Melo * ->end will be filled after we load all the symbols 1323439d473bSArnaldo Carvalho de Melo */ 13243610583cSArnaldo Carvalho de Melo map__init(self, type, start, 0, 0, dso); 1325439d473bSArnaldo Carvalho de Melo } 1326afb7b4f0SArnaldo Carvalho de Melo 1327439d473bSArnaldo Carvalho de Melo return self; 1328439d473bSArnaldo Carvalho de Melo } 1329439d473bSArnaldo Carvalho de Melo 13309958e1f0SArnaldo Carvalho de Melo static int map_groups__create_module_maps(struct map_groups *self) 1331439d473bSArnaldo Carvalho de Melo { 1332439d473bSArnaldo Carvalho de Melo char *line = NULL; 1333439d473bSArnaldo Carvalho de Melo size_t n; 1334439d473bSArnaldo Carvalho de Melo FILE *file = fopen("/proc/modules", "r"); 1335439d473bSArnaldo Carvalho de Melo struct map *map; 1336439d473bSArnaldo Carvalho de Melo 1337439d473bSArnaldo Carvalho de Melo if (file == NULL) 1338439d473bSArnaldo Carvalho de Melo return -1; 1339439d473bSArnaldo Carvalho de Melo 1340439d473bSArnaldo Carvalho de Melo while (!feof(file)) { 1341439d473bSArnaldo Carvalho de Melo char name[PATH_MAX]; 1342439d473bSArnaldo Carvalho de Melo u64 start; 1343439d473bSArnaldo Carvalho de Melo struct dso *dso; 1344439d473bSArnaldo Carvalho de Melo char *sep; 1345439d473bSArnaldo Carvalho de Melo int line_len; 1346439d473bSArnaldo Carvalho de Melo 1347439d473bSArnaldo Carvalho de Melo line_len = getline(&line, &n, file); 1348439d473bSArnaldo Carvalho de Melo if (line_len < 0) 13496cfcc53eSMike Galbraith break; 13506cfcc53eSMike Galbraith 1351439d473bSArnaldo Carvalho de Melo if (!line) 1352439d473bSArnaldo Carvalho de Melo goto out_failure; 1353439d473bSArnaldo Carvalho de Melo 1354439d473bSArnaldo Carvalho de Melo line[--line_len] = '\0'; /* \n */ 1355439d473bSArnaldo Carvalho de Melo 1356439d473bSArnaldo Carvalho de Melo sep = strrchr(line, 'x'); 1357439d473bSArnaldo Carvalho de Melo if (sep == NULL) 1358439d473bSArnaldo Carvalho de Melo continue; 1359439d473bSArnaldo Carvalho de Melo 1360439d473bSArnaldo Carvalho de Melo hex2u64(sep + 1, &start); 1361439d473bSArnaldo Carvalho de Melo 1362439d473bSArnaldo Carvalho de Melo sep = strchr(line, ' '); 1363439d473bSArnaldo Carvalho de Melo if (sep == NULL) 1364439d473bSArnaldo Carvalho de Melo continue; 1365439d473bSArnaldo Carvalho de Melo 1366439d473bSArnaldo Carvalho de Melo *sep = '\0'; 1367439d473bSArnaldo Carvalho de Melo 1368439d473bSArnaldo Carvalho de Melo snprintf(name, sizeof(name), "[%s]", line); 136900a192b3SArnaldo Carvalho de Melo dso = dso__new(name); 1370439d473bSArnaldo Carvalho de Melo 1371439d473bSArnaldo Carvalho de Melo if (dso == NULL) 1372439d473bSArnaldo Carvalho de Melo goto out_delete_line; 1373439d473bSArnaldo Carvalho de Melo 13743610583cSArnaldo Carvalho de Melo map = map__new2(start, dso, MAP__FUNCTION); 1375439d473bSArnaldo Carvalho de Melo if (map == NULL) { 1376439d473bSArnaldo Carvalho de Melo dso__delete(dso); 1377439d473bSArnaldo Carvalho de Melo goto out_delete_line; 13786cfcc53eSMike Galbraith } 13796cfcc53eSMike Galbraith 1380f1617b40SArnaldo Carvalho de Melo snprintf(name, sizeof(name), 1381f1617b40SArnaldo Carvalho de Melo "/sys/module/%s/notes/.note.gnu.build-id", line); 1382f1617b40SArnaldo Carvalho de Melo if (sysfs__read_build_id(name, dso->build_id, 1383f1617b40SArnaldo Carvalho de Melo sizeof(dso->build_id)) == 0) 1384f1617b40SArnaldo Carvalho de Melo dso->has_build_id = true; 1385f1617b40SArnaldo Carvalho de Melo 1386439d473bSArnaldo Carvalho de Melo dso->origin = DSO__ORIG_KMODULE; 13879958e1f0SArnaldo Carvalho de Melo map_groups__insert(self, map); 1388b0da954aSArnaldo Carvalho de Melo dsos__add(&dsos__kernel, dso); 13896cfcc53eSMike Galbraith } 13906cfcc53eSMike Galbraith 1391439d473bSArnaldo Carvalho de Melo free(line); 1392439d473bSArnaldo Carvalho de Melo fclose(file); 1393439d473bSArnaldo Carvalho de Melo 1394c338aee8SArnaldo Carvalho de Melo return dsos__set_modules_path(); 1395439d473bSArnaldo Carvalho de Melo 1396439d473bSArnaldo Carvalho de Melo out_delete_line: 1397439d473bSArnaldo Carvalho de Melo free(line); 1398439d473bSArnaldo Carvalho de Melo out_failure: 1399439d473bSArnaldo Carvalho de Melo return -1; 14006cfcc53eSMike Galbraith } 14016cfcc53eSMike Galbraith 14029958e1f0SArnaldo Carvalho de Melo static int dso__load_vmlinux(struct dso *self, struct map *map, 14039958e1f0SArnaldo Carvalho de Melo struct map_groups *mg, 14046beba7adSArnaldo Carvalho de Melo const char *vmlinux, symbol_filter_t filter) 140586470930SIngo Molnar { 1406fbd733b8SArnaldo Carvalho de Melo int err = -1, fd; 140786470930SIngo Molnar 1408fbd733b8SArnaldo Carvalho de Melo if (self->has_build_id) { 1409fbd733b8SArnaldo Carvalho de Melo u8 build_id[BUILD_ID_SIZE]; 141066bd8424SArnaldo Carvalho de Melo 1411fbd733b8SArnaldo Carvalho de Melo if (filename__read_build_id(vmlinux, build_id, 1412fbd733b8SArnaldo Carvalho de Melo sizeof(build_id)) < 0) { 1413fbd733b8SArnaldo Carvalho de Melo pr_debug("No build_id in %s, ignoring it\n", vmlinux); 1414fbd733b8SArnaldo Carvalho de Melo return -1; 1415fbd733b8SArnaldo Carvalho de Melo } 1416fbd733b8SArnaldo Carvalho de Melo if (!dso__build_id_equal(self, build_id)) { 1417fbd733b8SArnaldo Carvalho de Melo char expected_build_id[BUILD_ID_SIZE * 2 + 1], 1418fbd733b8SArnaldo Carvalho de Melo vmlinux_build_id[BUILD_ID_SIZE * 2 + 1]; 1419fbd733b8SArnaldo Carvalho de Melo 1420fbd733b8SArnaldo Carvalho de Melo build_id__sprintf(self->build_id, 1421fbd733b8SArnaldo Carvalho de Melo sizeof(self->build_id), 1422fbd733b8SArnaldo Carvalho de Melo expected_build_id); 1423fbd733b8SArnaldo Carvalho de Melo build_id__sprintf(build_id, sizeof(build_id), 1424fbd733b8SArnaldo Carvalho de Melo vmlinux_build_id); 1425fbd733b8SArnaldo Carvalho de Melo pr_debug("build_id in %s is %s while expected is %s, " 1426fbd733b8SArnaldo Carvalho de Melo "ignoring it\n", vmlinux, vmlinux_build_id, 1427fbd733b8SArnaldo Carvalho de Melo expected_build_id); 1428fbd733b8SArnaldo Carvalho de Melo return -1; 1429fbd733b8SArnaldo Carvalho de Melo } 1430fbd733b8SArnaldo Carvalho de Melo } 1431fbd733b8SArnaldo Carvalho de Melo 1432fbd733b8SArnaldo Carvalho de Melo fd = open(vmlinux, O_RDONLY); 143386470930SIngo Molnar if (fd < 0) 143486470930SIngo Molnar return -1; 143586470930SIngo Molnar 14363610583cSArnaldo Carvalho de Melo dso__set_loaded(self, map->type); 14379958e1f0SArnaldo Carvalho de Melo err = dso__load_sym(self, map, mg, self->long_name, fd, filter, 1, 0); 143886470930SIngo Molnar close(fd); 143986470930SIngo Molnar 144086470930SIngo Molnar return err; 144186470930SIngo Molnar } 144286470930SIngo Molnar 1443c338aee8SArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *self, struct map *map, 14449958e1f0SArnaldo Carvalho de Melo struct map_groups *mg, symbol_filter_t filter) 144586470930SIngo Molnar { 1446cc612d81SArnaldo Carvalho de Melo int err; 1447cc612d81SArnaldo Carvalho de Melo bool is_kallsyms; 1448439d473bSArnaldo Carvalho de Melo 1449cc612d81SArnaldo Carvalho de Melo if (vmlinux_path != NULL) { 1450cc612d81SArnaldo Carvalho de Melo int i; 1451cc612d81SArnaldo Carvalho de Melo pr_debug("Looking at the vmlinux_path (%d entries long)\n", 1452cc612d81SArnaldo Carvalho de Melo vmlinux_path__nr_entries); 1453cc612d81SArnaldo Carvalho de Melo for (i = 0; i < vmlinux_path__nr_entries; ++i) { 14549958e1f0SArnaldo Carvalho de Melo err = dso__load_vmlinux(self, map, mg, 145595011c60SArnaldo Carvalho de Melo vmlinux_path[i], filter); 1456cc612d81SArnaldo Carvalho de Melo if (err > 0) { 1457cc612d81SArnaldo Carvalho de Melo pr_debug("Using %s for symbols\n", 1458cc612d81SArnaldo Carvalho de Melo vmlinux_path[i]); 1459cc612d81SArnaldo Carvalho de Melo dso__set_long_name(self, 1460cc612d81SArnaldo Carvalho de Melo strdup(vmlinux_path[i])); 1461cc612d81SArnaldo Carvalho de Melo goto out_fixup; 1462cc612d81SArnaldo Carvalho de Melo } 1463cc612d81SArnaldo Carvalho de Melo } 1464cc612d81SArnaldo Carvalho de Melo } 1465cc612d81SArnaldo Carvalho de Melo 1466cc612d81SArnaldo Carvalho de Melo is_kallsyms = self->long_name[0] == '['; 1467cc612d81SArnaldo Carvalho de Melo if (is_kallsyms) 1468cc612d81SArnaldo Carvalho de Melo goto do_kallsyms; 1469cc612d81SArnaldo Carvalho de Melo 14709958e1f0SArnaldo Carvalho de Melo err = dso__load_vmlinux(self, map, mg, self->long_name, filter); 1471ef6ae724SArnaldo Carvalho de Melo if (err <= 0) { 1472cc612d81SArnaldo Carvalho de Melo pr_info("The file %s cannot be used, " 1473cc612d81SArnaldo Carvalho de Melo "trying to use /proc/kallsyms...", self->long_name); 1474cc612d81SArnaldo Carvalho de Melo do_kallsyms: 14759958e1f0SArnaldo Carvalho de Melo err = dso__load_kallsyms(self, map, mg, filter); 1476cc612d81SArnaldo Carvalho de Melo if (err > 0 && !is_kallsyms) 1477ef6ae724SArnaldo Carvalho de Melo dso__set_long_name(self, strdup("[kernel.kallsyms]")); 1478ef6ae724SArnaldo Carvalho de Melo } 147986470930SIngo Molnar 1480439d473bSArnaldo Carvalho de Melo if (err > 0) { 1481cc612d81SArnaldo Carvalho de Melo out_fixup: 14826a4694a4SArnaldo Carvalho de Melo map__fixup_start(map); 14836a4694a4SArnaldo Carvalho de Melo map__fixup_end(map); 1484439d473bSArnaldo Carvalho de Melo } 148594cb9e38SArnaldo Carvalho de Melo 148686470930SIngo Molnar return err; 148786470930SIngo Molnar } 148886470930SIngo Molnar 1489b0da954aSArnaldo Carvalho de Melo LIST_HEAD(dsos__user); 1490b0da954aSArnaldo Carvalho de Melo LIST_HEAD(dsos__kernel); 1491cd84c2acSFrederic Weisbecker struct dso *vdso; 1492cd84c2acSFrederic Weisbecker 1493b0da954aSArnaldo Carvalho de Melo static void dsos__add(struct list_head *head, struct dso *dso) 1494cd84c2acSFrederic Weisbecker { 1495b0da954aSArnaldo Carvalho de Melo list_add_tail(&dso->node, head); 1496cd84c2acSFrederic Weisbecker } 1497cd84c2acSFrederic Weisbecker 1498b0da954aSArnaldo Carvalho de Melo static struct dso *dsos__find(struct list_head *head, const char *name) 1499cd84c2acSFrederic Weisbecker { 1500cd84c2acSFrederic Weisbecker struct dso *pos; 1501cd84c2acSFrederic Weisbecker 1502b0da954aSArnaldo Carvalho de Melo list_for_each_entry(pos, head, node) 1503cd84c2acSFrederic Weisbecker if (strcmp(pos->name, name) == 0) 1504cd84c2acSFrederic Weisbecker return pos; 1505cd84c2acSFrederic Weisbecker return NULL; 1506cd84c2acSFrederic Weisbecker } 1507cd84c2acSFrederic Weisbecker 150800a192b3SArnaldo Carvalho de Melo struct dso *dsos__findnew(const char *name) 1509cd84c2acSFrederic Weisbecker { 1510b0da954aSArnaldo Carvalho de Melo struct dso *dso = dsos__find(&dsos__user, name); 1511cd84c2acSFrederic Weisbecker 1512e4204992SArnaldo Carvalho de Melo if (!dso) { 151300a192b3SArnaldo Carvalho de Melo dso = dso__new(name); 1514cfc10d3bSArnaldo Carvalho de Melo if (dso != NULL) { 1515b0da954aSArnaldo Carvalho de Melo dsos__add(&dsos__user, dso); 1516cfc10d3bSArnaldo Carvalho de Melo dso__set_basename(dso); 1517cfc10d3bSArnaldo Carvalho de Melo } 1518e4204992SArnaldo Carvalho de Melo } 1519cd84c2acSFrederic Weisbecker 1520cd84c2acSFrederic Weisbecker return dso; 1521cd84c2acSFrederic Weisbecker } 1522cd84c2acSFrederic Weisbecker 1523b0da954aSArnaldo Carvalho de Melo static void __dsos__fprintf(struct list_head *head, FILE *fp) 1524cd84c2acSFrederic Weisbecker { 1525cd84c2acSFrederic Weisbecker struct dso *pos; 1526cd84c2acSFrederic Weisbecker 152795011c60SArnaldo Carvalho de Melo list_for_each_entry(pos, head, node) { 152895011c60SArnaldo Carvalho de Melo int i; 152995011c60SArnaldo Carvalho de Melo for (i = 0; i < MAP__NR_TYPES; ++i) 153095011c60SArnaldo Carvalho de Melo dso__fprintf(pos, i, fp); 153195011c60SArnaldo Carvalho de Melo } 1532cd84c2acSFrederic Weisbecker } 1533cd84c2acSFrederic Weisbecker 1534b0da954aSArnaldo Carvalho de Melo void dsos__fprintf(FILE *fp) 1535b0da954aSArnaldo Carvalho de Melo { 1536b0da954aSArnaldo Carvalho de Melo __dsos__fprintf(&dsos__kernel, fp); 1537b0da954aSArnaldo Carvalho de Melo __dsos__fprintf(&dsos__user, fp); 1538b0da954aSArnaldo Carvalho de Melo } 1539b0da954aSArnaldo Carvalho de Melo 1540b0da954aSArnaldo Carvalho de Melo static size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp) 15419e03eb2dSArnaldo Carvalho de Melo { 15429e03eb2dSArnaldo Carvalho de Melo struct dso *pos; 15439e03eb2dSArnaldo Carvalho de Melo size_t ret = 0; 15449e03eb2dSArnaldo Carvalho de Melo 1545b0da954aSArnaldo Carvalho de Melo list_for_each_entry(pos, head, node) { 15469e03eb2dSArnaldo Carvalho de Melo ret += dso__fprintf_buildid(pos, fp); 15479e03eb2dSArnaldo Carvalho de Melo ret += fprintf(fp, " %s\n", pos->long_name); 15489e03eb2dSArnaldo Carvalho de Melo } 15499e03eb2dSArnaldo Carvalho de Melo return ret; 15509e03eb2dSArnaldo Carvalho de Melo } 15519e03eb2dSArnaldo Carvalho de Melo 1552b0da954aSArnaldo Carvalho de Melo size_t dsos__fprintf_buildid(FILE *fp) 1553b0da954aSArnaldo Carvalho de Melo { 1554b0da954aSArnaldo Carvalho de Melo return (__dsos__fprintf_buildid(&dsos__kernel, fp) + 1555b0da954aSArnaldo Carvalho de Melo __dsos__fprintf_buildid(&dsos__user, fp)); 1556b0da954aSArnaldo Carvalho de Melo } 1557b0da954aSArnaldo Carvalho de Melo 1558*f1dfa0b1SArnaldo Carvalho de Melo static struct dso *dsos__create_kernel( const char *vmlinux) 1559cd84c2acSFrederic Weisbecker { 156095011c60SArnaldo Carvalho de Melo struct dso *kernel = dso__new(vmlinux ?: "[kernel.kallsyms]"); 1561cd84c2acSFrederic Weisbecker 15622446042cSArnaldo Carvalho de Melo if (kernel == NULL) 1563*f1dfa0b1SArnaldo Carvalho de Melo return NULL; 1564c338aee8SArnaldo Carvalho de Melo 15652446042cSArnaldo Carvalho de Melo kernel->short_name = "[kernel]"; 1566c338aee8SArnaldo Carvalho de Melo kernel->kernel = 1; 1567cc612d81SArnaldo Carvalho de Melo 156800a192b3SArnaldo Carvalho de Melo vdso = dso__new("[vdso]"); 1569c338aee8SArnaldo Carvalho de Melo if (vdso == NULL) 1570*f1dfa0b1SArnaldo Carvalho de Melo goto out_delete_kernel_dso; 15713610583cSArnaldo Carvalho de Melo dso__set_loaded(vdso, MAP__FUNCTION); 1572cd84c2acSFrederic Weisbecker 15732446042cSArnaldo Carvalho de Melo if (sysfs__read_build_id("/sys/kernel/notes", kernel->build_id, 15742446042cSArnaldo Carvalho de Melo sizeof(kernel->build_id)) == 0) 15752446042cSArnaldo Carvalho de Melo kernel->has_build_id = true; 15762446042cSArnaldo Carvalho de Melo 1577b0da954aSArnaldo Carvalho de Melo dsos__add(&dsos__kernel, kernel); 1578b0da954aSArnaldo Carvalho de Melo dsos__add(&dsos__user, vdso); 1579cd84c2acSFrederic Weisbecker 1580*f1dfa0b1SArnaldo Carvalho de Melo return kernel; 1581c338aee8SArnaldo Carvalho de Melo 1582c338aee8SArnaldo Carvalho de Melo out_delete_kernel_dso: 1583c338aee8SArnaldo Carvalho de Melo dso__delete(kernel); 1584*f1dfa0b1SArnaldo Carvalho de Melo return NULL; 1585*f1dfa0b1SArnaldo Carvalho de Melo } 1586*f1dfa0b1SArnaldo Carvalho de Melo 1587*f1dfa0b1SArnaldo Carvalho de Melo static int map_groups__create_kernel_maps(struct map_groups *self, const char *vmlinux) 1588*f1dfa0b1SArnaldo Carvalho de Melo { 1589*f1dfa0b1SArnaldo Carvalho de Melo struct map *functions, *variables; 1590*f1dfa0b1SArnaldo Carvalho de Melo struct dso *kernel = dsos__create_kernel(vmlinux); 1591*f1dfa0b1SArnaldo Carvalho de Melo 1592*f1dfa0b1SArnaldo Carvalho de Melo if (kernel == NULL) 1593c338aee8SArnaldo Carvalho de Melo return -1; 1594*f1dfa0b1SArnaldo Carvalho de Melo 1595*f1dfa0b1SArnaldo Carvalho de Melo functions = map__new2(0, kernel, MAP__FUNCTION); 1596*f1dfa0b1SArnaldo Carvalho de Melo if (functions == NULL) 1597*f1dfa0b1SArnaldo Carvalho de Melo return -1; 1598*f1dfa0b1SArnaldo Carvalho de Melo 1599*f1dfa0b1SArnaldo Carvalho de Melo variables = map__new2(0, kernel, MAP__VARIABLE); 1600*f1dfa0b1SArnaldo Carvalho de Melo if (variables == NULL) { 1601*f1dfa0b1SArnaldo Carvalho de Melo map__delete(functions); 1602*f1dfa0b1SArnaldo Carvalho de Melo return -1; 1603*f1dfa0b1SArnaldo Carvalho de Melo } 1604*f1dfa0b1SArnaldo Carvalho de Melo 1605*f1dfa0b1SArnaldo Carvalho de Melo functions->map_ip = functions->unmap_ip = 1606*f1dfa0b1SArnaldo Carvalho de Melo variables->map_ip = variables->unmap_ip = identity__map_ip; 1607*f1dfa0b1SArnaldo Carvalho de Melo map_groups__insert(self, functions); 1608*f1dfa0b1SArnaldo Carvalho de Melo map_groups__insert(self, variables); 1609*f1dfa0b1SArnaldo Carvalho de Melo 1610*f1dfa0b1SArnaldo Carvalho de Melo return 0; 16112446042cSArnaldo Carvalho de Melo } 16122446042cSArnaldo Carvalho de Melo 1613cc612d81SArnaldo Carvalho de Melo static void vmlinux_path__exit(void) 16142446042cSArnaldo Carvalho de Melo { 1615cc612d81SArnaldo Carvalho de Melo while (--vmlinux_path__nr_entries >= 0) { 1616cc612d81SArnaldo Carvalho de Melo free(vmlinux_path[vmlinux_path__nr_entries]); 1617cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = NULL; 1618cc612d81SArnaldo Carvalho de Melo } 1619cc612d81SArnaldo Carvalho de Melo 1620cc612d81SArnaldo Carvalho de Melo free(vmlinux_path); 1621cc612d81SArnaldo Carvalho de Melo vmlinux_path = NULL; 1622cc612d81SArnaldo Carvalho de Melo } 1623cc612d81SArnaldo Carvalho de Melo 1624cc612d81SArnaldo Carvalho de Melo static int vmlinux_path__init(void) 1625cc612d81SArnaldo Carvalho de Melo { 1626cc612d81SArnaldo Carvalho de Melo struct utsname uts; 1627cc612d81SArnaldo Carvalho de Melo char bf[PATH_MAX]; 1628cc612d81SArnaldo Carvalho de Melo 1629cc612d81SArnaldo Carvalho de Melo if (uname(&uts) < 0) 16302446042cSArnaldo Carvalho de Melo return -1; 16312446042cSArnaldo Carvalho de Melo 1632cc612d81SArnaldo Carvalho de Melo vmlinux_path = malloc(sizeof(char *) * 5); 1633cc612d81SArnaldo Carvalho de Melo if (vmlinux_path == NULL) 1634cc612d81SArnaldo Carvalho de Melo return -1; 1635cc612d81SArnaldo Carvalho de Melo 1636cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup("vmlinux"); 1637cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 1638cc612d81SArnaldo Carvalho de Melo goto out_fail; 1639cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 1640cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup("/boot/vmlinux"); 1641cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 1642cc612d81SArnaldo Carvalho de Melo goto out_fail; 1643cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 1644cc612d81SArnaldo Carvalho de Melo snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", uts.release); 1645cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); 1646cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 1647cc612d81SArnaldo Carvalho de Melo goto out_fail; 1648cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 1649cc612d81SArnaldo Carvalho de Melo snprintf(bf, sizeof(bf), "/lib/modules/%s/build/vmlinux", uts.release); 1650cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); 1651cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 1652cc612d81SArnaldo Carvalho de Melo goto out_fail; 1653cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 1654cc612d81SArnaldo Carvalho de Melo snprintf(bf, sizeof(bf), "/usr/lib/debug/lib/modules/%s/vmlinux", 1655cc612d81SArnaldo Carvalho de Melo uts.release); 1656cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); 1657cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 1658cc612d81SArnaldo Carvalho de Melo goto out_fail; 1659cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 1660cc612d81SArnaldo Carvalho de Melo 1661cc612d81SArnaldo Carvalho de Melo return 0; 1662cc612d81SArnaldo Carvalho de Melo 1663cc612d81SArnaldo Carvalho de Melo out_fail: 1664cc612d81SArnaldo Carvalho de Melo vmlinux_path__exit(); 1665cc612d81SArnaldo Carvalho de Melo return -1; 1666cc612d81SArnaldo Carvalho de Melo } 1667cc612d81SArnaldo Carvalho de Melo 166895011c60SArnaldo Carvalho de Melo int symbol__init(struct symbol_conf *conf) 1669cc612d81SArnaldo Carvalho de Melo { 1670b32d133aSArnaldo Carvalho de Melo const struct symbol_conf *pconf = conf ?: &symbol_conf__defaults; 1671b32d133aSArnaldo Carvalho de Melo 167295011c60SArnaldo Carvalho de Melo elf_version(EV_CURRENT); 1673b32d133aSArnaldo Carvalho de Melo symbol__priv_size = pconf->priv_size; 16749958e1f0SArnaldo Carvalho de Melo map_groups__init(kmaps); 1675b32d133aSArnaldo Carvalho de Melo 1676b32d133aSArnaldo Carvalho de Melo if (pconf->try_vmlinux_path && vmlinux_path__init() < 0) 1677cc612d81SArnaldo Carvalho de Melo return -1; 1678cc612d81SArnaldo Carvalho de Melo 1679*f1dfa0b1SArnaldo Carvalho de Melo if (map_groups__create_kernel_maps(kmaps, pconf->vmlinux_name) < 0) { 1680cc612d81SArnaldo Carvalho de Melo vmlinux_path__exit(); 1681cc612d81SArnaldo Carvalho de Melo return -1; 1682cc612d81SArnaldo Carvalho de Melo } 1683cc612d81SArnaldo Carvalho de Melo 16849958e1f0SArnaldo Carvalho de Melo kmaps->use_modules = pconf->use_modules; 16859958e1f0SArnaldo Carvalho de Melo if (pconf->use_modules && map_groups__create_module_maps(kmaps) < 0) 168687f8ea4cSArnaldo Carvalho de Melo pr_debug("Failed to load list of modules in use, " 16876671cb16SArnaldo Carvalho de Melo "continuing...\n"); 168890c83218SArnaldo Carvalho de Melo /* 168990c83218SArnaldo Carvalho de Melo * Now that we have all the maps created, just set the ->end of them: 169090c83218SArnaldo Carvalho de Melo */ 16919958e1f0SArnaldo Carvalho de Melo map_groups__fixup_end(kmaps); 16926671cb16SArnaldo Carvalho de Melo return 0; 1693cd84c2acSFrederic Weisbecker } 1694