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); 32*9958e1f0SArnaldo 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, 36*9958e1f0SArnaldo 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 46*9958e1f0SArnaldo Carvalho de Melo static struct map_groups kmaps_mem; 47*9958e1f0SArnaldo 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 59fcf1203aSArnaldo Carvalho de Melo static void symbols__fixup_end(struct rb_root *self) 60af427bf5SArnaldo Carvalho de Melo { 61fcf1203aSArnaldo Carvalho de Melo struct rb_node *nd, *prevnd = rb_first(self); 622e538c4aSArnaldo Carvalho de Melo struct symbol *curr, *prev; 63af427bf5SArnaldo Carvalho de Melo 64af427bf5SArnaldo Carvalho de Melo if (prevnd == NULL) 65af427bf5SArnaldo Carvalho de Melo return; 66af427bf5SArnaldo Carvalho de Melo 672e538c4aSArnaldo Carvalho de Melo curr = rb_entry(prevnd, struct symbol, rb_node); 682e538c4aSArnaldo Carvalho de Melo 69af427bf5SArnaldo Carvalho de Melo for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) { 702e538c4aSArnaldo Carvalho de Melo prev = curr; 712e538c4aSArnaldo Carvalho de Melo curr = rb_entry(nd, struct symbol, rb_node); 72af427bf5SArnaldo Carvalho de Melo 73af427bf5SArnaldo Carvalho de Melo if (prev->end == prev->start) 74af427bf5SArnaldo Carvalho de Melo prev->end = curr->start - 1; 75af427bf5SArnaldo Carvalho de Melo } 76af427bf5SArnaldo Carvalho de Melo 772e538c4aSArnaldo Carvalho de Melo /* Last entry */ 782e538c4aSArnaldo Carvalho de Melo if (curr->end == curr->start) 792e538c4aSArnaldo Carvalho de Melo curr->end = roundup(curr->start, 4096); 802e538c4aSArnaldo Carvalho de Melo } 812e538c4aSArnaldo Carvalho de Melo 82*9958e1f0SArnaldo Carvalho de Melo static void __map_groups__fixup_end(struct map_groups *self, enum map_type type) 83af427bf5SArnaldo Carvalho de Melo { 84af427bf5SArnaldo Carvalho de Melo struct map *prev, *curr; 8595011c60SArnaldo Carvalho de Melo struct rb_node *nd, *prevnd = rb_first(&self->maps[type]); 86af427bf5SArnaldo Carvalho de Melo 87af427bf5SArnaldo Carvalho de Melo if (prevnd == NULL) 88af427bf5SArnaldo Carvalho de Melo return; 89af427bf5SArnaldo Carvalho de Melo 90af427bf5SArnaldo Carvalho de Melo curr = rb_entry(prevnd, struct map, rb_node); 91af427bf5SArnaldo Carvalho de Melo 92af427bf5SArnaldo Carvalho de Melo for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) { 93af427bf5SArnaldo Carvalho de Melo prev = curr; 94af427bf5SArnaldo Carvalho de Melo curr = rb_entry(nd, struct map, rb_node); 95af427bf5SArnaldo Carvalho de Melo prev->end = curr->start - 1; 962e538c4aSArnaldo Carvalho de Melo } 9790c83218SArnaldo Carvalho de Melo 9890c83218SArnaldo Carvalho de Melo /* 9990c83218SArnaldo Carvalho de Melo * We still haven't the actual symbols, so guess the 10090c83218SArnaldo Carvalho de Melo * last map final address. 10190c83218SArnaldo Carvalho de Melo */ 10290c83218SArnaldo Carvalho de Melo curr->end = ~0UL; 103af427bf5SArnaldo Carvalho de Melo } 104af427bf5SArnaldo Carvalho de Melo 105*9958e1f0SArnaldo Carvalho de Melo static void map_groups__fixup_end(struct map_groups *self) 10623ea4a3fSArnaldo Carvalho de Melo { 10723ea4a3fSArnaldo Carvalho de Melo int i; 10823ea4a3fSArnaldo Carvalho de Melo for (i = 0; i < MAP__NR_TYPES; ++i) 109*9958e1f0SArnaldo Carvalho de Melo __map_groups__fixup_end(self, i); 11023ea4a3fSArnaldo Carvalho de Melo } 11123ea4a3fSArnaldo Carvalho de Melo 11200a192b3SArnaldo Carvalho de Melo static struct symbol *symbol__new(u64 start, u64 len, const char *name) 11386470930SIngo Molnar { 11486470930SIngo Molnar size_t namelen = strlen(name) + 1; 11536479484SArnaldo Carvalho de Melo struct symbol *self = zalloc(symbol__priv_size + 11636479484SArnaldo Carvalho de Melo sizeof(*self) + namelen); 11736479484SArnaldo Carvalho de Melo if (self == NULL) 11886470930SIngo Molnar return NULL; 11986470930SIngo Molnar 12036479484SArnaldo Carvalho de Melo if (symbol__priv_size) 12100a192b3SArnaldo Carvalho de Melo self = ((void *)self) + symbol__priv_size; 12236479484SArnaldo Carvalho de Melo 12386470930SIngo Molnar self->start = start; 1246cfcc53eSMike Galbraith self->end = len ? start + len - 1 : start; 125e4204992SArnaldo Carvalho de Melo 1266beba7adSArnaldo Carvalho de Melo pr_debug3("%s: %s %#Lx-%#Lx\n", __func__, name, start, self->end); 127e4204992SArnaldo Carvalho de Melo 12886470930SIngo Molnar memcpy(self->name, name, namelen); 12986470930SIngo Molnar 13086470930SIngo Molnar return self; 13186470930SIngo Molnar } 13286470930SIngo Molnar 13300a192b3SArnaldo Carvalho de Melo static void symbol__delete(struct symbol *self) 13486470930SIngo Molnar { 13500a192b3SArnaldo Carvalho de Melo free(((void *)self) - symbol__priv_size); 13686470930SIngo Molnar } 13786470930SIngo Molnar 13886470930SIngo Molnar static size_t symbol__fprintf(struct symbol *self, FILE *fp) 13986470930SIngo Molnar { 14086470930SIngo Molnar return fprintf(fp, " %llx-%llx %s\n", 14186470930SIngo Molnar self->start, self->end, self->name); 14286470930SIngo Molnar } 14386470930SIngo Molnar 144cfc10d3bSArnaldo Carvalho de Melo static void dso__set_long_name(struct dso *self, char *name) 145cfc10d3bSArnaldo Carvalho de Melo { 146ef6ae724SArnaldo Carvalho de Melo if (name == NULL) 147ef6ae724SArnaldo Carvalho de Melo return; 148cfc10d3bSArnaldo Carvalho de Melo self->long_name = name; 149cfc10d3bSArnaldo Carvalho de Melo self->long_name_len = strlen(name); 150cfc10d3bSArnaldo Carvalho de Melo } 151cfc10d3bSArnaldo Carvalho de Melo 152cfc10d3bSArnaldo Carvalho de Melo static void dso__set_basename(struct dso *self) 153cfc10d3bSArnaldo Carvalho de Melo { 154cfc10d3bSArnaldo Carvalho de Melo self->short_name = basename(self->long_name); 155cfc10d3bSArnaldo Carvalho de Melo } 156cfc10d3bSArnaldo Carvalho de Melo 15700a192b3SArnaldo Carvalho de Melo struct dso *dso__new(const char *name) 15886470930SIngo Molnar { 15986470930SIngo Molnar struct dso *self = malloc(sizeof(*self) + strlen(name) + 1); 16086470930SIngo Molnar 16186470930SIngo Molnar if (self != NULL) { 1626a4694a4SArnaldo Carvalho de Melo int i; 16386470930SIngo Molnar strcpy(self->name, name); 164cfc10d3bSArnaldo Carvalho de Melo dso__set_long_name(self, self->name); 165439d473bSArnaldo Carvalho de Melo self->short_name = self->name; 1666a4694a4SArnaldo Carvalho de Melo for (i = 0; i < MAP__NR_TYPES; ++i) 1676a4694a4SArnaldo Carvalho de Melo self->symbols[i] = RB_ROOT; 1686a4694a4SArnaldo Carvalho de Melo self->find_symbol = dso__find_symbol; 16952d422deSArnaldo Carvalho de Melo self->slen_calculated = 0; 17094cb9e38SArnaldo Carvalho de Melo self->origin = DSO__ORIG_NOT_FOUND; 1718d06367fSArnaldo Carvalho de Melo self->loaded = 0; 1728d06367fSArnaldo Carvalho de Melo self->has_build_id = 0; 17386470930SIngo Molnar } 17486470930SIngo Molnar 17586470930SIngo Molnar return self; 17686470930SIngo Molnar } 17786470930SIngo Molnar 178fcf1203aSArnaldo Carvalho de Melo static void symbols__delete(struct rb_root *self) 17986470930SIngo Molnar { 18086470930SIngo Molnar struct symbol *pos; 181fcf1203aSArnaldo Carvalho de Melo struct rb_node *next = rb_first(self); 18286470930SIngo Molnar 18386470930SIngo Molnar while (next) { 18486470930SIngo Molnar pos = rb_entry(next, struct symbol, rb_node); 18586470930SIngo Molnar next = rb_next(&pos->rb_node); 186fcf1203aSArnaldo Carvalho de Melo rb_erase(&pos->rb_node, self); 18700a192b3SArnaldo Carvalho de Melo symbol__delete(pos); 18886470930SIngo Molnar } 18986470930SIngo Molnar } 19086470930SIngo Molnar 19186470930SIngo Molnar void dso__delete(struct dso *self) 19286470930SIngo Molnar { 1936a4694a4SArnaldo Carvalho de Melo int i; 1946a4694a4SArnaldo Carvalho de Melo for (i = 0; i < MAP__NR_TYPES; ++i) 1956a4694a4SArnaldo Carvalho de Melo symbols__delete(&self->symbols[i]); 196439d473bSArnaldo Carvalho de Melo if (self->long_name != self->name) 197439d473bSArnaldo Carvalho de Melo free(self->long_name); 19886470930SIngo Molnar free(self); 19986470930SIngo Molnar } 20086470930SIngo Molnar 2018d06367fSArnaldo Carvalho de Melo void dso__set_build_id(struct dso *self, void *build_id) 2028d06367fSArnaldo Carvalho de Melo { 2038d06367fSArnaldo Carvalho de Melo memcpy(self->build_id, build_id, sizeof(self->build_id)); 2048d06367fSArnaldo Carvalho de Melo self->has_build_id = 1; 2058d06367fSArnaldo Carvalho de Melo } 2068d06367fSArnaldo Carvalho de Melo 207fcf1203aSArnaldo Carvalho de Melo static void symbols__insert(struct rb_root *self, struct symbol *sym) 20886470930SIngo Molnar { 209fcf1203aSArnaldo Carvalho de Melo struct rb_node **p = &self->rb_node; 21086470930SIngo Molnar struct rb_node *parent = NULL; 2119cffa8d5SPaul Mackerras const u64 ip = sym->start; 21286470930SIngo Molnar struct symbol *s; 21386470930SIngo Molnar 21486470930SIngo Molnar while (*p != NULL) { 21586470930SIngo Molnar parent = *p; 21686470930SIngo Molnar s = rb_entry(parent, struct symbol, rb_node); 21786470930SIngo Molnar if (ip < s->start) 21886470930SIngo Molnar p = &(*p)->rb_left; 21986470930SIngo Molnar else 22086470930SIngo Molnar p = &(*p)->rb_right; 22186470930SIngo Molnar } 22286470930SIngo Molnar rb_link_node(&sym->rb_node, parent, p); 223fcf1203aSArnaldo Carvalho de Melo rb_insert_color(&sym->rb_node, self); 22486470930SIngo Molnar } 22586470930SIngo Molnar 226fcf1203aSArnaldo Carvalho de Melo static struct symbol *symbols__find(struct rb_root *self, u64 ip) 22786470930SIngo Molnar { 22886470930SIngo Molnar struct rb_node *n; 22986470930SIngo Molnar 23086470930SIngo Molnar if (self == NULL) 23186470930SIngo Molnar return NULL; 23286470930SIngo Molnar 233fcf1203aSArnaldo Carvalho de Melo n = self->rb_node; 23486470930SIngo Molnar 23586470930SIngo Molnar while (n) { 23686470930SIngo Molnar struct symbol *s = rb_entry(n, struct symbol, rb_node); 23786470930SIngo Molnar 23886470930SIngo Molnar if (ip < s->start) 23986470930SIngo Molnar n = n->rb_left; 24086470930SIngo Molnar else if (ip > s->end) 24186470930SIngo Molnar n = n->rb_right; 24286470930SIngo Molnar else 24386470930SIngo Molnar return s; 24486470930SIngo Molnar } 24586470930SIngo Molnar 24686470930SIngo Molnar return NULL; 24786470930SIngo Molnar } 24886470930SIngo Molnar 2496a4694a4SArnaldo Carvalho de Melo struct symbol *dso__find_symbol(struct dso *self, enum map_type type, u64 addr) 250fcf1203aSArnaldo Carvalho de Melo { 2516a4694a4SArnaldo Carvalho de Melo return symbols__find(&self->symbols[type], addr); 252fcf1203aSArnaldo Carvalho de Melo } 253fcf1203aSArnaldo Carvalho de Melo 2548d06367fSArnaldo Carvalho de Melo int build_id__sprintf(u8 *self, int len, char *bf) 2558d06367fSArnaldo Carvalho de Melo { 2568d06367fSArnaldo Carvalho de Melo char *bid = bf; 2578d06367fSArnaldo Carvalho de Melo u8 *raw = self; 2588d06367fSArnaldo Carvalho de Melo int i; 2598d06367fSArnaldo Carvalho de Melo 2608d06367fSArnaldo Carvalho de Melo for (i = 0; i < len; ++i) { 2618d06367fSArnaldo Carvalho de Melo sprintf(bid, "%02x", *raw); 2628d06367fSArnaldo Carvalho de Melo ++raw; 2638d06367fSArnaldo Carvalho de Melo bid += 2; 2648d06367fSArnaldo Carvalho de Melo } 2658d06367fSArnaldo Carvalho de Melo 2668d06367fSArnaldo Carvalho de Melo return raw - self; 2678d06367fSArnaldo Carvalho de Melo } 2688d06367fSArnaldo Carvalho de Melo 2699e03eb2dSArnaldo Carvalho de Melo size_t dso__fprintf_buildid(struct dso *self, FILE *fp) 27086470930SIngo Molnar { 2718d06367fSArnaldo Carvalho de Melo char sbuild_id[BUILD_ID_SIZE * 2 + 1]; 2728d06367fSArnaldo Carvalho de Melo 2738d06367fSArnaldo Carvalho de Melo build_id__sprintf(self->build_id, sizeof(self->build_id), sbuild_id); 2749e03eb2dSArnaldo Carvalho de Melo return fprintf(fp, "%s", sbuild_id); 2759e03eb2dSArnaldo Carvalho de Melo } 2769e03eb2dSArnaldo Carvalho de Melo 27795011c60SArnaldo Carvalho de Melo size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp) 2789e03eb2dSArnaldo Carvalho de Melo { 2799e03eb2dSArnaldo Carvalho de Melo struct rb_node *nd; 2809e03eb2dSArnaldo Carvalho de Melo size_t ret = fprintf(fp, "dso: %s (", self->short_name); 2819e03eb2dSArnaldo Carvalho de Melo 2829e03eb2dSArnaldo Carvalho de Melo ret += dso__fprintf_buildid(self, fp); 2836a4694a4SArnaldo Carvalho de Melo ret += fprintf(fp, ")\n"); 28495011c60SArnaldo Carvalho de Melo for (nd = rb_first(&self->symbols[type]); nd; nd = rb_next(nd)) { 28586470930SIngo Molnar struct symbol *pos = rb_entry(nd, struct symbol, rb_node); 28686470930SIngo Molnar ret += symbol__fprintf(pos, fp); 28786470930SIngo Molnar } 28886470930SIngo Molnar 28986470930SIngo Molnar return ret; 29086470930SIngo Molnar } 29186470930SIngo Molnar 2922e538c4aSArnaldo Carvalho de Melo /* 2932e538c4aSArnaldo Carvalho de Melo * Loads the function entries in /proc/kallsyms into kernel_map->dso, 2942e538c4aSArnaldo Carvalho de Melo * so that we can in the next step set the symbol ->end address and then 2952e538c4aSArnaldo Carvalho de Melo * call kernel_maps__split_kallsyms. 2962e538c4aSArnaldo Carvalho de Melo */ 2974e06255fSArnaldo Carvalho de Melo static int dso__load_all_kallsyms(struct dso *self, struct map *map) 29886470930SIngo Molnar { 29986470930SIngo Molnar char *line = NULL; 30086470930SIngo Molnar size_t n; 3014e06255fSArnaldo Carvalho de Melo struct rb_root *root = &self->symbols[map->type]; 30286470930SIngo Molnar FILE *file = fopen("/proc/kallsyms", "r"); 30386470930SIngo Molnar 30486470930SIngo Molnar if (file == NULL) 30586470930SIngo Molnar goto out_failure; 30686470930SIngo Molnar 30786470930SIngo Molnar while (!feof(file)) { 3089cffa8d5SPaul Mackerras u64 start; 30986470930SIngo Molnar struct symbol *sym; 31086470930SIngo Molnar int line_len, len; 31186470930SIngo Molnar char symbol_type; 3122e538c4aSArnaldo Carvalho de Melo char *symbol_name; 31386470930SIngo Molnar 31486470930SIngo Molnar line_len = getline(&line, &n, file); 31586470930SIngo Molnar if (line_len < 0) 31686470930SIngo Molnar break; 31786470930SIngo Molnar 31886470930SIngo Molnar if (!line) 31986470930SIngo Molnar goto out_failure; 32086470930SIngo Molnar 32186470930SIngo Molnar line[--line_len] = '\0'; /* \n */ 32286470930SIngo Molnar 32386470930SIngo Molnar len = hex2u64(line, &start); 32486470930SIngo Molnar 32586470930SIngo Molnar len++; 32686470930SIngo Molnar if (len + 2 >= line_len) 32786470930SIngo Molnar continue; 32886470930SIngo Molnar 32986470930SIngo Molnar symbol_type = toupper(line[len]); 33086470930SIngo Molnar /* 33186470930SIngo Molnar * We're interested only in code ('T'ext) 33286470930SIngo Molnar */ 33386470930SIngo Molnar if (symbol_type != 'T' && symbol_type != 'W') 33486470930SIngo Molnar continue; 335af427bf5SArnaldo Carvalho de Melo 336af427bf5SArnaldo Carvalho de Melo symbol_name = line + len + 2; 3372e538c4aSArnaldo Carvalho de Melo /* 3382e538c4aSArnaldo Carvalho de Melo * Will fix up the end later, when we have all symbols sorted. 3392e538c4aSArnaldo Carvalho de Melo */ 34000a192b3SArnaldo Carvalho de Melo sym = symbol__new(start, 0, symbol_name); 341af427bf5SArnaldo Carvalho de Melo 3422e538c4aSArnaldo Carvalho de Melo if (sym == NULL) 3432e538c4aSArnaldo Carvalho de Melo goto out_delete_line; 34482164161SArnaldo Carvalho de Melo /* 34582164161SArnaldo Carvalho de Melo * We will pass the symbols to the filter later, in 3464e06255fSArnaldo Carvalho de Melo * map__split_kallsyms, when we have split the maps per module 34782164161SArnaldo Carvalho de Melo */ 3484e06255fSArnaldo Carvalho de Melo symbols__insert(root, sym); 3492e538c4aSArnaldo Carvalho de Melo } 3502e538c4aSArnaldo Carvalho de Melo 3512e538c4aSArnaldo Carvalho de Melo free(line); 3522e538c4aSArnaldo Carvalho de Melo fclose(file); 3532e538c4aSArnaldo Carvalho de Melo 3542e538c4aSArnaldo Carvalho de Melo return 0; 3552e538c4aSArnaldo Carvalho de Melo 3562e538c4aSArnaldo Carvalho de Melo out_delete_line: 3572e538c4aSArnaldo Carvalho de Melo free(line); 3582e538c4aSArnaldo Carvalho de Melo out_failure: 3592e538c4aSArnaldo Carvalho de Melo return -1; 3602e538c4aSArnaldo Carvalho de Melo } 3612e538c4aSArnaldo Carvalho de Melo 3622e538c4aSArnaldo Carvalho de Melo /* 3632e538c4aSArnaldo Carvalho de Melo * Split the symbols into maps, making sure there are no overlaps, i.e. the 3642e538c4aSArnaldo Carvalho de Melo * kernel range is broken in several maps, named [kernel].N, as we don't have 3652e538c4aSArnaldo Carvalho de Melo * the original ELF section names vmlinux have. 3662e538c4aSArnaldo Carvalho de Melo */ 367*9958e1f0SArnaldo Carvalho de Melo static int dso__split_kallsyms(struct dso *self, struct map *map, 368*9958e1f0SArnaldo Carvalho de Melo struct map_groups *mg, symbol_filter_t filter) 3692e538c4aSArnaldo Carvalho de Melo { 3704e06255fSArnaldo Carvalho de Melo struct map *curr_map = map; 3712e538c4aSArnaldo Carvalho de Melo struct symbol *pos; 3722e538c4aSArnaldo Carvalho de Melo int count = 0; 3734e06255fSArnaldo Carvalho de Melo struct rb_root *root = &self->symbols[map->type]; 3744e06255fSArnaldo Carvalho de Melo struct rb_node *next = rb_first(root); 3752e538c4aSArnaldo Carvalho de Melo int kernel_range = 0; 3762e538c4aSArnaldo Carvalho de Melo 3772e538c4aSArnaldo Carvalho de Melo while (next) { 3782e538c4aSArnaldo Carvalho de Melo char *module; 3792e538c4aSArnaldo Carvalho de Melo 3802e538c4aSArnaldo Carvalho de Melo pos = rb_entry(next, struct symbol, rb_node); 3812e538c4aSArnaldo Carvalho de Melo next = rb_next(&pos->rb_node); 3822e538c4aSArnaldo Carvalho de Melo 3832e538c4aSArnaldo Carvalho de Melo module = strchr(pos->name, '\t'); 3842e538c4aSArnaldo Carvalho de Melo if (module) { 385*9958e1f0SArnaldo Carvalho de Melo if (!mg->use_modules) 3861de8e245SArnaldo Carvalho de Melo goto discard_symbol; 3871de8e245SArnaldo Carvalho de Melo 3882e538c4aSArnaldo Carvalho de Melo *module++ = '\0'; 3892e538c4aSArnaldo Carvalho de Melo 3904e06255fSArnaldo Carvalho de Melo if (strcmp(self->name, module)) { 391*9958e1f0SArnaldo Carvalho de Melo curr_map = map_groups__find_by_name(mg, module); 3924e06255fSArnaldo Carvalho de Melo if (curr_map == NULL) { 39395011c60SArnaldo Carvalho de Melo pr_debug("/proc/{kallsyms,modules} " 3946beba7adSArnaldo Carvalho de Melo "inconsistency!\n"); 395af427bf5SArnaldo Carvalho de Melo return -1; 396af427bf5SArnaldo Carvalho de Melo } 397af427bf5SArnaldo Carvalho de Melo } 39886470930SIngo Molnar /* 3992e538c4aSArnaldo Carvalho de Melo * So that we look just like we get from .ko files, 4002e538c4aSArnaldo Carvalho de Melo * i.e. not prelinked, relative to map->start. 40186470930SIngo Molnar */ 4024e06255fSArnaldo Carvalho de Melo pos->start = curr_map->map_ip(curr_map, pos->start); 4034e06255fSArnaldo Carvalho de Melo pos->end = curr_map->map_ip(curr_map, pos->end); 4044e06255fSArnaldo Carvalho de Melo } else if (curr_map != map) { 4052e538c4aSArnaldo Carvalho de Melo char dso_name[PATH_MAX]; 4062e538c4aSArnaldo Carvalho de Melo struct dso *dso; 40786470930SIngo Molnar 4082e538c4aSArnaldo Carvalho de Melo snprintf(dso_name, sizeof(dso_name), "[kernel].%d", 4092e538c4aSArnaldo Carvalho de Melo kernel_range++); 41086470930SIngo Molnar 41100a192b3SArnaldo Carvalho de Melo dso = dso__new(dso_name); 4122e538c4aSArnaldo Carvalho de Melo if (dso == NULL) 4132e538c4aSArnaldo Carvalho de Melo return -1; 4142e538c4aSArnaldo Carvalho de Melo 4154e06255fSArnaldo Carvalho de Melo curr_map = map__new2(pos->start, dso, map->type); 4162e538c4aSArnaldo Carvalho de Melo if (map == NULL) { 4172e538c4aSArnaldo Carvalho de Melo dso__delete(dso); 4182e538c4aSArnaldo Carvalho de Melo return -1; 4192e538c4aSArnaldo Carvalho de Melo } 4202e538c4aSArnaldo Carvalho de Melo 4214e06255fSArnaldo Carvalho de Melo curr_map->map_ip = curr_map->unmap_ip = identity__map_ip; 422*9958e1f0SArnaldo Carvalho de Melo map_groups__insert(mg, curr_map); 4232e538c4aSArnaldo Carvalho de Melo ++kernel_range; 4242e538c4aSArnaldo Carvalho de Melo } 4252e538c4aSArnaldo Carvalho de Melo 4264e06255fSArnaldo Carvalho de Melo if (filter && filter(curr_map, pos)) { 4271de8e245SArnaldo Carvalho de Melo discard_symbol: rb_erase(&pos->rb_node, root); 42800a192b3SArnaldo Carvalho de Melo symbol__delete(pos); 4292e538c4aSArnaldo Carvalho de Melo } else { 4304e06255fSArnaldo Carvalho de Melo if (curr_map != map) { 4314e06255fSArnaldo Carvalho de Melo rb_erase(&pos->rb_node, root); 4324e06255fSArnaldo Carvalho de Melo symbols__insert(&curr_map->dso->symbols[curr_map->type], pos); 4332e538c4aSArnaldo Carvalho de Melo } 4349974f496SMike Galbraith count++; 4359974f496SMike Galbraith } 43686470930SIngo Molnar } 43786470930SIngo Molnar 4389974f496SMike Galbraith return count; 43986470930SIngo Molnar } 44086470930SIngo Molnar 4412e538c4aSArnaldo Carvalho de Melo 4424e06255fSArnaldo Carvalho de Melo static int dso__load_kallsyms(struct dso *self, struct map *map, 443*9958e1f0SArnaldo Carvalho de Melo struct map_groups *mg, symbol_filter_t filter) 4442e538c4aSArnaldo Carvalho de Melo { 4454e06255fSArnaldo Carvalho de Melo if (dso__load_all_kallsyms(self, map) < 0) 4462e538c4aSArnaldo Carvalho de Melo return -1; 4472e538c4aSArnaldo Carvalho de Melo 4484e06255fSArnaldo Carvalho de Melo symbols__fixup_end(&self->symbols[map->type]); 4494e06255fSArnaldo Carvalho de Melo self->origin = DSO__ORIG_KERNEL; 4502e538c4aSArnaldo Carvalho de Melo 451*9958e1f0SArnaldo Carvalho de Melo return dso__split_kallsyms(self, map, mg, filter); 45223ea4a3fSArnaldo Carvalho de Melo } 45323ea4a3fSArnaldo Carvalho de Melo 45423ea4a3fSArnaldo Carvalho de Melo size_t kernel_maps__fprintf(FILE *fp) 45523ea4a3fSArnaldo Carvalho de Melo { 45623ea4a3fSArnaldo Carvalho de Melo size_t printed = fprintf(fp, "Kernel maps:\n"); 457*9958e1f0SArnaldo Carvalho de Melo printed += map_groups__fprintf_maps(kmaps, fp); 4586beba7adSArnaldo Carvalho de Melo return printed + fprintf(fp, "END kernel maps\n"); 459af427bf5SArnaldo Carvalho de Melo } 460af427bf5SArnaldo Carvalho de Melo 461439d473bSArnaldo Carvalho de Melo static int dso__load_perf_map(struct dso *self, struct map *map, 4626beba7adSArnaldo Carvalho de Melo symbol_filter_t filter) 46380d496beSPekka Enberg { 46480d496beSPekka Enberg char *line = NULL; 46580d496beSPekka Enberg size_t n; 46680d496beSPekka Enberg FILE *file; 46780d496beSPekka Enberg int nr_syms = 0; 46880d496beSPekka Enberg 469439d473bSArnaldo Carvalho de Melo file = fopen(self->long_name, "r"); 47080d496beSPekka Enberg if (file == NULL) 47180d496beSPekka Enberg goto out_failure; 47280d496beSPekka Enberg 47380d496beSPekka Enberg while (!feof(file)) { 4749cffa8d5SPaul Mackerras u64 start, size; 47580d496beSPekka Enberg struct symbol *sym; 47680d496beSPekka Enberg int line_len, len; 47780d496beSPekka Enberg 47880d496beSPekka Enberg line_len = getline(&line, &n, file); 47980d496beSPekka Enberg if (line_len < 0) 48080d496beSPekka Enberg break; 48180d496beSPekka Enberg 48280d496beSPekka Enberg if (!line) 48380d496beSPekka Enberg goto out_failure; 48480d496beSPekka Enberg 48580d496beSPekka Enberg line[--line_len] = '\0'; /* \n */ 48680d496beSPekka Enberg 48780d496beSPekka Enberg len = hex2u64(line, &start); 48880d496beSPekka Enberg 48980d496beSPekka Enberg len++; 49080d496beSPekka Enberg if (len + 2 >= line_len) 49180d496beSPekka Enberg continue; 49280d496beSPekka Enberg 49380d496beSPekka Enberg len += hex2u64(line + len, &size); 49480d496beSPekka Enberg 49580d496beSPekka Enberg len++; 49680d496beSPekka Enberg if (len + 2 >= line_len) 49780d496beSPekka Enberg continue; 49880d496beSPekka Enberg 49900a192b3SArnaldo Carvalho de Melo sym = symbol__new(start, size, line + len); 50080d496beSPekka Enberg 50180d496beSPekka Enberg if (sym == NULL) 50280d496beSPekka Enberg goto out_delete_line; 50380d496beSPekka Enberg 504439d473bSArnaldo Carvalho de Melo if (filter && filter(map, sym)) 50500a192b3SArnaldo Carvalho de Melo symbol__delete(sym); 50680d496beSPekka Enberg else { 5076a4694a4SArnaldo Carvalho de Melo symbols__insert(&self->symbols[map->type], sym); 50880d496beSPekka Enberg nr_syms++; 50980d496beSPekka Enberg } 51080d496beSPekka Enberg } 51180d496beSPekka Enberg 51280d496beSPekka Enberg free(line); 51380d496beSPekka Enberg fclose(file); 51480d496beSPekka Enberg 51580d496beSPekka Enberg return nr_syms; 51680d496beSPekka Enberg 51780d496beSPekka Enberg out_delete_line: 51880d496beSPekka Enberg free(line); 51980d496beSPekka Enberg out_failure: 52080d496beSPekka Enberg return -1; 52180d496beSPekka Enberg } 52280d496beSPekka Enberg 52386470930SIngo Molnar /** 52486470930SIngo Molnar * elf_symtab__for_each_symbol - iterate thru all the symbols 52586470930SIngo Molnar * 52686470930SIngo Molnar * @self: struct elf_symtab instance to iterate 52783a0944fSIngo Molnar * @idx: uint32_t idx 52886470930SIngo Molnar * @sym: GElf_Sym iterator 52986470930SIngo Molnar */ 53083a0944fSIngo Molnar #define elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) \ 53183a0944fSIngo Molnar for (idx = 0, gelf_getsym(syms, idx, &sym);\ 53283a0944fSIngo Molnar idx < nr_syms; \ 53383a0944fSIngo Molnar idx++, gelf_getsym(syms, idx, &sym)) 53486470930SIngo Molnar 53586470930SIngo Molnar static inline uint8_t elf_sym__type(const GElf_Sym *sym) 53686470930SIngo Molnar { 53786470930SIngo Molnar return GELF_ST_TYPE(sym->st_info); 53886470930SIngo Molnar } 53986470930SIngo Molnar 54086470930SIngo Molnar static inline int elf_sym__is_function(const GElf_Sym *sym) 54186470930SIngo Molnar { 54286470930SIngo Molnar return elf_sym__type(sym) == STT_FUNC && 54386470930SIngo Molnar sym->st_name != 0 && 54481833130SArnaldo Carvalho de Melo sym->st_shndx != SHN_UNDEF; 54586470930SIngo Molnar } 54686470930SIngo Molnar 5476cfcc53eSMike Galbraith static inline int elf_sym__is_label(const GElf_Sym *sym) 5486cfcc53eSMike Galbraith { 5496cfcc53eSMike Galbraith return elf_sym__type(sym) == STT_NOTYPE && 5506cfcc53eSMike Galbraith sym->st_name != 0 && 5516cfcc53eSMike Galbraith sym->st_shndx != SHN_UNDEF && 5526cfcc53eSMike Galbraith sym->st_shndx != SHN_ABS; 5536cfcc53eSMike Galbraith } 5546cfcc53eSMike Galbraith 5556cfcc53eSMike Galbraith static inline const char *elf_sec__name(const GElf_Shdr *shdr, 5566cfcc53eSMike Galbraith const Elf_Data *secstrs) 5576cfcc53eSMike Galbraith { 5586cfcc53eSMike Galbraith return secstrs->d_buf + shdr->sh_name; 5596cfcc53eSMike Galbraith } 5606cfcc53eSMike Galbraith 5616cfcc53eSMike Galbraith static inline int elf_sec__is_text(const GElf_Shdr *shdr, 5626cfcc53eSMike Galbraith const Elf_Data *secstrs) 5636cfcc53eSMike Galbraith { 5646cfcc53eSMike Galbraith return strstr(elf_sec__name(shdr, secstrs), "text") != NULL; 5656cfcc53eSMike Galbraith } 5666cfcc53eSMike Galbraith 56786470930SIngo Molnar static inline const char *elf_sym__name(const GElf_Sym *sym, 56886470930SIngo Molnar const Elf_Data *symstrs) 56986470930SIngo Molnar { 57086470930SIngo Molnar return symstrs->d_buf + sym->st_name; 57186470930SIngo Molnar } 57286470930SIngo Molnar 57386470930SIngo Molnar static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, 57486470930SIngo Molnar GElf_Shdr *shp, const char *name, 57583a0944fSIngo Molnar size_t *idx) 57686470930SIngo Molnar { 57786470930SIngo Molnar Elf_Scn *sec = NULL; 57886470930SIngo Molnar size_t cnt = 1; 57986470930SIngo Molnar 58086470930SIngo Molnar while ((sec = elf_nextscn(elf, sec)) != NULL) { 58186470930SIngo Molnar char *str; 58286470930SIngo Molnar 58386470930SIngo Molnar gelf_getshdr(sec, shp); 58486470930SIngo Molnar str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name); 58586470930SIngo Molnar if (!strcmp(name, str)) { 58683a0944fSIngo Molnar if (idx) 58783a0944fSIngo Molnar *idx = cnt; 58886470930SIngo Molnar break; 58986470930SIngo Molnar } 59086470930SIngo Molnar ++cnt; 59186470930SIngo Molnar } 59286470930SIngo Molnar 59386470930SIngo Molnar return sec; 59486470930SIngo Molnar } 59586470930SIngo Molnar 59686470930SIngo Molnar #define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \ 59786470930SIngo Molnar for (idx = 0, pos = gelf_getrel(reldata, 0, &pos_mem); \ 59886470930SIngo Molnar idx < nr_entries; \ 59986470930SIngo Molnar ++idx, pos = gelf_getrel(reldata, idx, &pos_mem)) 60086470930SIngo Molnar 60186470930SIngo Molnar #define elf_section__for_each_rela(reldata, pos, pos_mem, idx, nr_entries) \ 60286470930SIngo Molnar for (idx = 0, pos = gelf_getrela(reldata, 0, &pos_mem); \ 60386470930SIngo Molnar idx < nr_entries; \ 60486470930SIngo Molnar ++idx, pos = gelf_getrela(reldata, idx, &pos_mem)) 60586470930SIngo Molnar 606a25e46c4SArnaldo Carvalho de Melo /* 607a25e46c4SArnaldo Carvalho de Melo * We need to check if we have a .dynsym, so that we can handle the 608a25e46c4SArnaldo Carvalho de Melo * .plt, synthesizing its symbols, that aren't on the symtabs (be it 609a25e46c4SArnaldo Carvalho de Melo * .dynsym or .symtab). 610a25e46c4SArnaldo Carvalho de Melo * And always look at the original dso, not at debuginfo packages, that 611a25e46c4SArnaldo Carvalho de Melo * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS). 612a25e46c4SArnaldo Carvalho de Melo */ 61382164161SArnaldo Carvalho de Melo static int dso__synthesize_plt_symbols(struct dso *self, struct map *map, 61482164161SArnaldo Carvalho de Melo symbol_filter_t filter) 61586470930SIngo Molnar { 61686470930SIngo Molnar uint32_t nr_rel_entries, idx; 61786470930SIngo Molnar GElf_Sym sym; 6189cffa8d5SPaul Mackerras u64 plt_offset; 61986470930SIngo Molnar GElf_Shdr shdr_plt; 62086470930SIngo Molnar struct symbol *f; 621a25e46c4SArnaldo Carvalho de Melo GElf_Shdr shdr_rel_plt, shdr_dynsym; 62286470930SIngo Molnar Elf_Data *reldata, *syms, *symstrs; 623a25e46c4SArnaldo Carvalho de Melo Elf_Scn *scn_plt_rel, *scn_symstrs, *scn_dynsym; 624a25e46c4SArnaldo Carvalho de Melo size_t dynsym_idx; 625a25e46c4SArnaldo Carvalho de Melo GElf_Ehdr ehdr; 62686470930SIngo Molnar char sympltname[1024]; 627a25e46c4SArnaldo Carvalho de Melo Elf *elf; 628a25e46c4SArnaldo Carvalho de Melo int nr = 0, symidx, fd, err = 0; 62986470930SIngo Molnar 630439d473bSArnaldo Carvalho de Melo fd = open(self->long_name, O_RDONLY); 631a25e46c4SArnaldo Carvalho de Melo if (fd < 0) 632a25e46c4SArnaldo Carvalho de Melo goto out; 633a25e46c4SArnaldo Carvalho de Melo 63484087126SMarti Raudsepp elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 635a25e46c4SArnaldo Carvalho de Melo if (elf == NULL) 636a25e46c4SArnaldo Carvalho de Melo goto out_close; 637a25e46c4SArnaldo Carvalho de Melo 638a25e46c4SArnaldo Carvalho de Melo if (gelf_getehdr(elf, &ehdr) == NULL) 639a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 640a25e46c4SArnaldo Carvalho de Melo 641a25e46c4SArnaldo Carvalho de Melo scn_dynsym = elf_section_by_name(elf, &ehdr, &shdr_dynsym, 642a25e46c4SArnaldo Carvalho de Melo ".dynsym", &dynsym_idx); 643a25e46c4SArnaldo Carvalho de Melo if (scn_dynsym == NULL) 644a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 645a25e46c4SArnaldo Carvalho de Melo 646a25e46c4SArnaldo Carvalho de Melo scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt, 64786470930SIngo Molnar ".rela.plt", NULL); 64886470930SIngo Molnar if (scn_plt_rel == NULL) { 649a25e46c4SArnaldo Carvalho de Melo scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt, 65086470930SIngo Molnar ".rel.plt", NULL); 65186470930SIngo Molnar if (scn_plt_rel == NULL) 652a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 65386470930SIngo Molnar } 65486470930SIngo Molnar 655a25e46c4SArnaldo Carvalho de Melo err = -1; 65686470930SIngo Molnar 657a25e46c4SArnaldo Carvalho de Melo if (shdr_rel_plt.sh_link != dynsym_idx) 658a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 659a25e46c4SArnaldo Carvalho de Melo 660a25e46c4SArnaldo Carvalho de Melo if (elf_section_by_name(elf, &ehdr, &shdr_plt, ".plt", NULL) == NULL) 661a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 66286470930SIngo Molnar 66386470930SIngo Molnar /* 66483a0944fSIngo Molnar * Fetch the relocation section to find the idxes to the GOT 66586470930SIngo Molnar * and the symbols in the .dynsym they refer to. 66686470930SIngo Molnar */ 66786470930SIngo Molnar reldata = elf_getdata(scn_plt_rel, NULL); 66886470930SIngo Molnar if (reldata == NULL) 669a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 67086470930SIngo Molnar 67186470930SIngo Molnar syms = elf_getdata(scn_dynsym, NULL); 67286470930SIngo Molnar if (syms == NULL) 673a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 67486470930SIngo Molnar 675a25e46c4SArnaldo Carvalho de Melo scn_symstrs = elf_getscn(elf, shdr_dynsym.sh_link); 67686470930SIngo Molnar if (scn_symstrs == NULL) 677a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 67886470930SIngo Molnar 67986470930SIngo Molnar symstrs = elf_getdata(scn_symstrs, NULL); 68086470930SIngo Molnar if (symstrs == NULL) 681a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 68286470930SIngo Molnar 68386470930SIngo Molnar nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize; 68486470930SIngo Molnar plt_offset = shdr_plt.sh_offset; 68586470930SIngo Molnar 68686470930SIngo Molnar if (shdr_rel_plt.sh_type == SHT_RELA) { 68786470930SIngo Molnar GElf_Rela pos_mem, *pos; 68886470930SIngo Molnar 68986470930SIngo Molnar elf_section__for_each_rela(reldata, pos, pos_mem, idx, 69086470930SIngo Molnar nr_rel_entries) { 69186470930SIngo Molnar symidx = GELF_R_SYM(pos->r_info); 69286470930SIngo Molnar plt_offset += shdr_plt.sh_entsize; 69386470930SIngo Molnar gelf_getsym(syms, symidx, &sym); 69486470930SIngo Molnar snprintf(sympltname, sizeof(sympltname), 69586470930SIngo Molnar "%s@plt", elf_sym__name(&sym, symstrs)); 69686470930SIngo Molnar 69786470930SIngo Molnar f = symbol__new(plt_offset, shdr_plt.sh_entsize, 69800a192b3SArnaldo Carvalho de Melo sympltname); 69986470930SIngo Molnar if (!f) 700a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 70186470930SIngo Molnar 70282164161SArnaldo Carvalho de Melo if (filter && filter(map, f)) 70382164161SArnaldo Carvalho de Melo symbol__delete(f); 70482164161SArnaldo Carvalho de Melo else { 7056a4694a4SArnaldo Carvalho de Melo symbols__insert(&self->symbols[map->type], f); 70686470930SIngo Molnar ++nr; 70786470930SIngo Molnar } 70882164161SArnaldo Carvalho de Melo } 70986470930SIngo Molnar } else if (shdr_rel_plt.sh_type == SHT_REL) { 71086470930SIngo Molnar GElf_Rel pos_mem, *pos; 71186470930SIngo Molnar elf_section__for_each_rel(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 } 73086470930SIngo Molnar } 73182164161SArnaldo Carvalho de Melo } 73286470930SIngo Molnar 733a25e46c4SArnaldo Carvalho de Melo err = 0; 734a25e46c4SArnaldo Carvalho de Melo out_elf_end: 735a25e46c4SArnaldo Carvalho de Melo elf_end(elf); 736a25e46c4SArnaldo Carvalho de Melo out_close: 737a25e46c4SArnaldo Carvalho de Melo close(fd); 738a25e46c4SArnaldo Carvalho de Melo 739a25e46c4SArnaldo Carvalho de Melo if (err == 0) 74086470930SIngo Molnar return nr; 741a25e46c4SArnaldo Carvalho de Melo out: 7426beba7adSArnaldo Carvalho de Melo pr_warning("%s: problems reading %s PLT info.\n", 743439d473bSArnaldo Carvalho de Melo __func__, self->long_name); 744a25e46c4SArnaldo Carvalho de Melo return 0; 74586470930SIngo Molnar } 74686470930SIngo Molnar 74795011c60SArnaldo Carvalho de Melo static int dso__load_sym(struct dso *self, struct map *map, 748*9958e1f0SArnaldo Carvalho de Melo struct map_groups *mg, const char *name, int fd, 74995011c60SArnaldo Carvalho de Melo symbol_filter_t filter, int kernel, int kmodule) 75086470930SIngo Molnar { 7512e538c4aSArnaldo Carvalho de Melo struct map *curr_map = map; 7522e538c4aSArnaldo Carvalho de Melo struct dso *curr_dso = self; 7532e538c4aSArnaldo Carvalho de Melo size_t dso_name_len = strlen(self->short_name); 7546cfcc53eSMike Galbraith Elf_Data *symstrs, *secstrs; 75586470930SIngo Molnar uint32_t nr_syms; 75686470930SIngo Molnar int err = -1; 75783a0944fSIngo Molnar uint32_t idx; 75886470930SIngo Molnar GElf_Ehdr ehdr; 75986470930SIngo Molnar GElf_Shdr shdr; 76086470930SIngo Molnar Elf_Data *syms; 76186470930SIngo Molnar GElf_Sym sym; 762a25e46c4SArnaldo Carvalho de Melo Elf_Scn *sec, *sec_strndx; 76386470930SIngo Molnar Elf *elf; 764439d473bSArnaldo Carvalho de Melo int nr = 0; 76586470930SIngo Molnar 76684087126SMarti Raudsepp elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 76786470930SIngo Molnar if (elf == NULL) { 7686beba7adSArnaldo Carvalho de Melo pr_err("%s: cannot read %s ELF file.\n", __func__, name); 76986470930SIngo Molnar goto out_close; 77086470930SIngo Molnar } 77186470930SIngo Molnar 77286470930SIngo Molnar if (gelf_getehdr(elf, &ehdr) == NULL) { 7736beba7adSArnaldo Carvalho de Melo pr_err("%s: cannot get elf header.\n", __func__); 77486470930SIngo Molnar goto out_elf_end; 77586470930SIngo Molnar } 77686470930SIngo Molnar 77786470930SIngo Molnar sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL); 77886470930SIngo Molnar if (sec == NULL) { 779a25e46c4SArnaldo Carvalho de Melo sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL); 780a25e46c4SArnaldo Carvalho de Melo if (sec == NULL) 78186470930SIngo Molnar goto out_elf_end; 78286470930SIngo Molnar } 78386470930SIngo Molnar 78486470930SIngo Molnar syms = elf_getdata(sec, NULL); 78586470930SIngo Molnar if (syms == NULL) 78686470930SIngo Molnar goto out_elf_end; 78786470930SIngo Molnar 78886470930SIngo Molnar sec = elf_getscn(elf, shdr.sh_link); 78986470930SIngo Molnar if (sec == NULL) 79086470930SIngo Molnar goto out_elf_end; 79186470930SIngo Molnar 79286470930SIngo Molnar symstrs = elf_getdata(sec, NULL); 79386470930SIngo Molnar if (symstrs == NULL) 79486470930SIngo Molnar goto out_elf_end; 79586470930SIngo Molnar 7966cfcc53eSMike Galbraith sec_strndx = elf_getscn(elf, ehdr.e_shstrndx); 7976cfcc53eSMike Galbraith if (sec_strndx == NULL) 7986cfcc53eSMike Galbraith goto out_elf_end; 7996cfcc53eSMike Galbraith 8006cfcc53eSMike Galbraith secstrs = elf_getdata(sec_strndx, NULL); 8019b30a26bSStoyan Gaydarov if (secstrs == NULL) 8026cfcc53eSMike Galbraith goto out_elf_end; 8036cfcc53eSMike Galbraith 80486470930SIngo Molnar nr_syms = shdr.sh_size / shdr.sh_entsize; 80586470930SIngo Molnar 806e9fbc9dcSArjan van de Ven memset(&sym, 0, sizeof(sym)); 807d20ff6bdSMike Galbraith if (!kernel) { 80830d7a77dSArnaldo Carvalho de Melo self->adjust_symbols = (ehdr.e_type == ET_EXEC || 80930d7a77dSArnaldo Carvalho de Melo elf_section_by_name(elf, &ehdr, &shdr, 810f5812a7aSArnaldo Carvalho de Melo ".gnu.prelink_undo", 81130d7a77dSArnaldo Carvalho de Melo NULL) != NULL); 812d20ff6bdSMike Galbraith } else self->adjust_symbols = 0; 813d20ff6bdSMike Galbraith 81483a0944fSIngo Molnar elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) { 81586470930SIngo Molnar struct symbol *f; 81683a0944fSIngo Molnar const char *elf_name; 8172e538c4aSArnaldo Carvalho de Melo char *demangled = NULL; 8186cfcc53eSMike Galbraith int is_label = elf_sym__is_label(&sym); 8196cfcc53eSMike Galbraith const char *section_name; 82086470930SIngo Molnar 8216cfcc53eSMike Galbraith if (!is_label && !elf_sym__is_function(&sym)) 82286470930SIngo Molnar continue; 82386470930SIngo Molnar 82486470930SIngo Molnar sec = elf_getscn(elf, sym.st_shndx); 82586470930SIngo Molnar if (!sec) 82686470930SIngo Molnar goto out_elf_end; 82786470930SIngo Molnar 82886470930SIngo Molnar gelf_getshdr(sec, &shdr); 8296cfcc53eSMike Galbraith 8306cfcc53eSMike Galbraith if (is_label && !elf_sec__is_text(&shdr, secstrs)) 8316cfcc53eSMike Galbraith continue; 8326cfcc53eSMike Galbraith 8332e538c4aSArnaldo Carvalho de Melo elf_name = elf_sym__name(&sym, symstrs); 8346cfcc53eSMike Galbraith section_name = elf_sec__name(&shdr, secstrs); 83586470930SIngo Molnar 8362e538c4aSArnaldo Carvalho de Melo if (kernel || kmodule) { 8372e538c4aSArnaldo Carvalho de Melo char dso_name[PATH_MAX]; 8382e538c4aSArnaldo Carvalho de Melo 8392e538c4aSArnaldo Carvalho de Melo if (strcmp(section_name, 8402e538c4aSArnaldo Carvalho de Melo curr_dso->short_name + dso_name_len) == 0) 8412e538c4aSArnaldo Carvalho de Melo goto new_symbol; 8422e538c4aSArnaldo Carvalho de Melo 8432e538c4aSArnaldo Carvalho de Melo if (strcmp(section_name, ".text") == 0) { 8442e538c4aSArnaldo Carvalho de Melo curr_map = map; 8452e538c4aSArnaldo Carvalho de Melo curr_dso = self; 8462e538c4aSArnaldo Carvalho de Melo goto new_symbol; 847af427bf5SArnaldo Carvalho de Melo } 848af427bf5SArnaldo Carvalho de Melo 8492e538c4aSArnaldo Carvalho de Melo snprintf(dso_name, sizeof(dso_name), 8502e538c4aSArnaldo Carvalho de Melo "%s%s", self->short_name, section_name); 8512e538c4aSArnaldo Carvalho de Melo 852*9958e1f0SArnaldo Carvalho de Melo curr_map = map_groups__find_by_name(mg, dso_name); 8532e538c4aSArnaldo Carvalho de Melo if (curr_map == NULL) { 8542e538c4aSArnaldo Carvalho de Melo u64 start = sym.st_value; 8552e538c4aSArnaldo Carvalho de Melo 8562e538c4aSArnaldo Carvalho de Melo if (kmodule) 8572e538c4aSArnaldo Carvalho de Melo start += map->start + shdr.sh_offset; 8582e538c4aSArnaldo Carvalho de Melo 85900a192b3SArnaldo Carvalho de Melo curr_dso = dso__new(dso_name); 8602e538c4aSArnaldo Carvalho de Melo if (curr_dso == NULL) 8612e538c4aSArnaldo Carvalho de Melo goto out_elf_end; 8623610583cSArnaldo Carvalho de Melo curr_map = map__new2(start, curr_dso, 8633610583cSArnaldo Carvalho de Melo MAP__FUNCTION); 8642e538c4aSArnaldo Carvalho de Melo if (curr_map == NULL) { 8652e538c4aSArnaldo Carvalho de Melo dso__delete(curr_dso); 8662e538c4aSArnaldo Carvalho de Melo goto out_elf_end; 8672e538c4aSArnaldo Carvalho de Melo } 868ed52ce2eSArnaldo Carvalho de Melo curr_map->map_ip = identity__map_ip; 869ed52ce2eSArnaldo Carvalho de Melo curr_map->unmap_ip = identity__map_ip; 8702e538c4aSArnaldo Carvalho de Melo curr_dso->origin = DSO__ORIG_KERNEL; 871*9958e1f0SArnaldo Carvalho de Melo map_groups__insert(kmaps, curr_map); 872b0da954aSArnaldo Carvalho de Melo dsos__add(&dsos__kernel, curr_dso); 8732e538c4aSArnaldo Carvalho de Melo } else 8742e538c4aSArnaldo Carvalho de Melo curr_dso = curr_map->dso; 8752e538c4aSArnaldo Carvalho de Melo 8762e538c4aSArnaldo Carvalho de Melo goto new_symbol; 8772e538c4aSArnaldo Carvalho de Melo } 8782e538c4aSArnaldo Carvalho de Melo 8792e538c4aSArnaldo Carvalho de Melo if (curr_dso->adjust_symbols) { 8806beba7adSArnaldo Carvalho de Melo pr_debug2("adjusting symbol: st_value: %Lx sh_addr: " 8816beba7adSArnaldo Carvalho de Melo "%Lx sh_offset: %Lx\n", (u64)sym.st_value, 8826beba7adSArnaldo Carvalho de Melo (u64)shdr.sh_addr, (u64)shdr.sh_offset); 88386470930SIngo Molnar sym.st_value -= shdr.sh_addr - shdr.sh_offset; 884af427bf5SArnaldo Carvalho de Melo } 88528ac909bSArnaldo Carvalho de Melo /* 88628ac909bSArnaldo Carvalho de Melo * We need to figure out if the object was created from C++ sources 88728ac909bSArnaldo Carvalho de Melo * DWARF DW_compile_unit has this, but we don't always have access 88828ac909bSArnaldo Carvalho de Melo * to it... 88928ac909bSArnaldo Carvalho de Melo */ 89083a0944fSIngo Molnar demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI); 89128ac909bSArnaldo Carvalho de Melo if (demangled != NULL) 89283a0944fSIngo Molnar elf_name = demangled; 8932e538c4aSArnaldo Carvalho de Melo new_symbol: 89400a192b3SArnaldo Carvalho de Melo f = symbol__new(sym.st_value, sym.st_size, elf_name); 89528ac909bSArnaldo Carvalho de Melo free(demangled); 89686470930SIngo Molnar if (!f) 89786470930SIngo Molnar goto out_elf_end; 89886470930SIngo Molnar 8992e538c4aSArnaldo Carvalho de Melo if (filter && filter(curr_map, f)) 90000a192b3SArnaldo Carvalho de Melo symbol__delete(f); 90186470930SIngo Molnar else { 9026a4694a4SArnaldo Carvalho de Melo symbols__insert(&curr_dso->symbols[curr_map->type], f); 90386470930SIngo Molnar nr++; 90486470930SIngo Molnar } 90586470930SIngo Molnar } 90686470930SIngo Molnar 9072e538c4aSArnaldo Carvalho de Melo /* 9082e538c4aSArnaldo Carvalho de Melo * For misannotated, zeroed, ASM function sizes. 9092e538c4aSArnaldo Carvalho de Melo */ 9102e538c4aSArnaldo Carvalho de Melo if (nr > 0) 9116a4694a4SArnaldo Carvalho de Melo symbols__fixup_end(&self->symbols[map->type]); 91286470930SIngo Molnar err = nr; 91386470930SIngo Molnar out_elf_end: 91486470930SIngo Molnar elf_end(elf); 91586470930SIngo Molnar out_close: 91686470930SIngo Molnar return err; 91786470930SIngo Molnar } 91886470930SIngo Molnar 91978075caaSArnaldo Carvalho de Melo static bool dso__build_id_equal(const struct dso *self, u8 *build_id) 92078075caaSArnaldo Carvalho de Melo { 92178075caaSArnaldo Carvalho de Melo return memcmp(self->build_id, build_id, sizeof(self->build_id)) == 0; 92278075caaSArnaldo Carvalho de Melo } 92378075caaSArnaldo Carvalho de Melo 924b0da954aSArnaldo Carvalho de Melo static bool __dsos__read_build_ids(struct list_head *head) 92557f395a7SFrederic Weisbecker { 926e30a3d12SArnaldo Carvalho de Melo bool have_build_id = false; 92757f395a7SFrederic Weisbecker struct dso *pos; 92857f395a7SFrederic Weisbecker 929b0da954aSArnaldo Carvalho de Melo list_for_each_entry(pos, head, node) 930e30a3d12SArnaldo Carvalho de Melo if (filename__read_build_id(pos->long_name, pos->build_id, 931e30a3d12SArnaldo Carvalho de Melo sizeof(pos->build_id)) > 0) { 932e30a3d12SArnaldo Carvalho de Melo have_build_id = true; 933e30a3d12SArnaldo Carvalho de Melo pos->has_build_id = true; 93457f395a7SFrederic Weisbecker } 93557f395a7SFrederic Weisbecker 936e30a3d12SArnaldo Carvalho de Melo return have_build_id; 93757f395a7SFrederic Weisbecker } 93857f395a7SFrederic Weisbecker 939b0da954aSArnaldo Carvalho de Melo bool dsos__read_build_ids(void) 940b0da954aSArnaldo Carvalho de Melo { 9418b4825bfSArnaldo Carvalho de Melo bool kbuildids = __dsos__read_build_ids(&dsos__kernel), 9428b4825bfSArnaldo Carvalho de Melo ubuildids = __dsos__read_build_ids(&dsos__user); 9438b4825bfSArnaldo Carvalho de Melo return kbuildids || ubuildids; 944b0da954aSArnaldo Carvalho de Melo } 945b0da954aSArnaldo Carvalho de Melo 946fd7a346eSArnaldo Carvalho de Melo /* 947fd7a346eSArnaldo Carvalho de Melo * Align offset to 4 bytes as needed for note name and descriptor data. 948fd7a346eSArnaldo Carvalho de Melo */ 949fd7a346eSArnaldo Carvalho de Melo #define NOTE_ALIGN(n) (((n) + 3) & -4U) 950fd7a346eSArnaldo Carvalho de Melo 9512643ce11SArnaldo Carvalho de Melo int filename__read_build_id(const char *filename, void *bf, size_t size) 9524d1e00a8SArnaldo Carvalho de Melo { 9532643ce11SArnaldo Carvalho de Melo int fd, err = -1; 9544d1e00a8SArnaldo Carvalho de Melo GElf_Ehdr ehdr; 9554d1e00a8SArnaldo Carvalho de Melo GElf_Shdr shdr; 956fd7a346eSArnaldo Carvalho de Melo Elf_Data *data; 9574d1e00a8SArnaldo Carvalho de Melo Elf_Scn *sec; 958e57cfcdaSPekka Enberg Elf_Kind ek; 959fd7a346eSArnaldo Carvalho de Melo void *ptr; 9604d1e00a8SArnaldo Carvalho de Melo Elf *elf; 9614d1e00a8SArnaldo Carvalho de Melo 9622643ce11SArnaldo Carvalho de Melo if (size < BUILD_ID_SIZE) 9632643ce11SArnaldo Carvalho de Melo goto out; 9642643ce11SArnaldo Carvalho de Melo 9652643ce11SArnaldo Carvalho de Melo fd = open(filename, O_RDONLY); 9664d1e00a8SArnaldo Carvalho de Melo if (fd < 0) 9674d1e00a8SArnaldo Carvalho de Melo goto out; 9684d1e00a8SArnaldo Carvalho de Melo 96984087126SMarti Raudsepp elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 9704d1e00a8SArnaldo Carvalho de Melo if (elf == NULL) { 9718d06367fSArnaldo Carvalho de Melo pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename); 9724d1e00a8SArnaldo Carvalho de Melo goto out_close; 9734d1e00a8SArnaldo Carvalho de Melo } 9744d1e00a8SArnaldo Carvalho de Melo 975e57cfcdaSPekka Enberg ek = elf_kind(elf); 976e57cfcdaSPekka Enberg if (ek != ELF_K_ELF) 977e57cfcdaSPekka Enberg goto out_elf_end; 978e57cfcdaSPekka Enberg 9794d1e00a8SArnaldo Carvalho de Melo if (gelf_getehdr(elf, &ehdr) == NULL) { 9806beba7adSArnaldo Carvalho de Melo pr_err("%s: cannot get elf header.\n", __func__); 9814d1e00a8SArnaldo Carvalho de Melo goto out_elf_end; 9824d1e00a8SArnaldo Carvalho de Melo } 9834d1e00a8SArnaldo Carvalho de Melo 9842643ce11SArnaldo Carvalho de Melo sec = elf_section_by_name(elf, &ehdr, &shdr, 9852643ce11SArnaldo Carvalho de Melo ".note.gnu.build-id", NULL); 986fd7a346eSArnaldo Carvalho de Melo if (sec == NULL) { 987fd7a346eSArnaldo Carvalho de Melo sec = elf_section_by_name(elf, &ehdr, &shdr, 988fd7a346eSArnaldo Carvalho de Melo ".notes", NULL); 9894d1e00a8SArnaldo Carvalho de Melo if (sec == NULL) 9904d1e00a8SArnaldo Carvalho de Melo goto out_elf_end; 991fd7a346eSArnaldo Carvalho de Melo } 9924d1e00a8SArnaldo Carvalho de Melo 993fd7a346eSArnaldo Carvalho de Melo data = elf_getdata(sec, NULL); 994fd7a346eSArnaldo Carvalho de Melo if (data == NULL) 9954d1e00a8SArnaldo Carvalho de Melo goto out_elf_end; 996fd7a346eSArnaldo Carvalho de Melo 997fd7a346eSArnaldo Carvalho de Melo ptr = data->d_buf; 998fd7a346eSArnaldo Carvalho de Melo while (ptr < (data->d_buf + data->d_size)) { 999fd7a346eSArnaldo Carvalho de Melo GElf_Nhdr *nhdr = ptr; 1000fd7a346eSArnaldo Carvalho de Melo int namesz = NOTE_ALIGN(nhdr->n_namesz), 1001fd7a346eSArnaldo Carvalho de Melo descsz = NOTE_ALIGN(nhdr->n_descsz); 1002fd7a346eSArnaldo Carvalho de Melo const char *name; 1003fd7a346eSArnaldo Carvalho de Melo 1004fd7a346eSArnaldo Carvalho de Melo ptr += sizeof(*nhdr); 1005fd7a346eSArnaldo Carvalho de Melo name = ptr; 1006fd7a346eSArnaldo Carvalho de Melo ptr += namesz; 1007fd7a346eSArnaldo Carvalho de Melo if (nhdr->n_type == NT_GNU_BUILD_ID && 1008fd7a346eSArnaldo Carvalho de Melo nhdr->n_namesz == sizeof("GNU")) { 1009fd7a346eSArnaldo Carvalho de Melo if (memcmp(name, "GNU", sizeof("GNU")) == 0) { 1010fd7a346eSArnaldo Carvalho de Melo memcpy(bf, ptr, BUILD_ID_SIZE); 10112643ce11SArnaldo Carvalho de Melo err = BUILD_ID_SIZE; 1012fd7a346eSArnaldo Carvalho de Melo break; 1013fd7a346eSArnaldo Carvalho de Melo } 1014fd7a346eSArnaldo Carvalho de Melo } 1015fd7a346eSArnaldo Carvalho de Melo ptr += descsz; 1016fd7a346eSArnaldo Carvalho de Melo } 10172643ce11SArnaldo Carvalho de Melo out_elf_end: 10182643ce11SArnaldo Carvalho de Melo elf_end(elf); 10192643ce11SArnaldo Carvalho de Melo out_close: 10202643ce11SArnaldo Carvalho de Melo close(fd); 10212643ce11SArnaldo Carvalho de Melo out: 10222643ce11SArnaldo Carvalho de Melo return err; 10232643ce11SArnaldo Carvalho de Melo } 10242643ce11SArnaldo Carvalho de Melo 1025f1617b40SArnaldo Carvalho de Melo int sysfs__read_build_id(const char *filename, void *build_id, size_t size) 1026f1617b40SArnaldo Carvalho de Melo { 1027f1617b40SArnaldo Carvalho de Melo int fd, err = -1; 1028f1617b40SArnaldo Carvalho de Melo 1029f1617b40SArnaldo Carvalho de Melo if (size < BUILD_ID_SIZE) 1030f1617b40SArnaldo Carvalho de Melo goto out; 1031f1617b40SArnaldo Carvalho de Melo 1032f1617b40SArnaldo Carvalho de Melo fd = open(filename, O_RDONLY); 1033f1617b40SArnaldo Carvalho de Melo if (fd < 0) 1034f1617b40SArnaldo Carvalho de Melo goto out; 1035f1617b40SArnaldo Carvalho de Melo 1036f1617b40SArnaldo Carvalho de Melo while (1) { 1037f1617b40SArnaldo Carvalho de Melo char bf[BUFSIZ]; 1038f1617b40SArnaldo Carvalho de Melo GElf_Nhdr nhdr; 1039f1617b40SArnaldo Carvalho de Melo int namesz, descsz; 1040f1617b40SArnaldo Carvalho de Melo 1041f1617b40SArnaldo Carvalho de Melo if (read(fd, &nhdr, sizeof(nhdr)) != sizeof(nhdr)) 1042f1617b40SArnaldo Carvalho de Melo break; 1043f1617b40SArnaldo Carvalho de Melo 1044fd7a346eSArnaldo Carvalho de Melo namesz = NOTE_ALIGN(nhdr.n_namesz); 1045fd7a346eSArnaldo Carvalho de Melo descsz = NOTE_ALIGN(nhdr.n_descsz); 1046f1617b40SArnaldo Carvalho de Melo if (nhdr.n_type == NT_GNU_BUILD_ID && 1047f1617b40SArnaldo Carvalho de Melo nhdr.n_namesz == sizeof("GNU")) { 1048f1617b40SArnaldo Carvalho de Melo if (read(fd, bf, namesz) != namesz) 1049f1617b40SArnaldo Carvalho de Melo break; 1050f1617b40SArnaldo Carvalho de Melo if (memcmp(bf, "GNU", sizeof("GNU")) == 0) { 1051f1617b40SArnaldo Carvalho de Melo if (read(fd, build_id, 1052f1617b40SArnaldo Carvalho de Melo BUILD_ID_SIZE) == BUILD_ID_SIZE) { 1053f1617b40SArnaldo Carvalho de Melo err = 0; 1054f1617b40SArnaldo Carvalho de Melo break; 1055f1617b40SArnaldo Carvalho de Melo } 1056f1617b40SArnaldo Carvalho de Melo } else if (read(fd, bf, descsz) != descsz) 1057f1617b40SArnaldo Carvalho de Melo break; 1058f1617b40SArnaldo Carvalho de Melo } else { 1059f1617b40SArnaldo Carvalho de Melo int n = namesz + descsz; 1060f1617b40SArnaldo Carvalho de Melo if (read(fd, bf, n) != n) 1061f1617b40SArnaldo Carvalho de Melo break; 1062f1617b40SArnaldo Carvalho de Melo } 1063f1617b40SArnaldo Carvalho de Melo } 1064f1617b40SArnaldo Carvalho de Melo close(fd); 1065f1617b40SArnaldo Carvalho de Melo out: 1066f1617b40SArnaldo Carvalho de Melo return err; 1067f1617b40SArnaldo Carvalho de Melo } 1068f1617b40SArnaldo Carvalho de Melo 106994cb9e38SArnaldo Carvalho de Melo char dso__symtab_origin(const struct dso *self) 107094cb9e38SArnaldo Carvalho de Melo { 107194cb9e38SArnaldo Carvalho de Melo static const char origin[] = { 107294cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_KERNEL] = 'k', 107394cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_JAVA_JIT] = 'j', 107494cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_FEDORA] = 'f', 107594cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_UBUNTU] = 'u', 107694cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_BUILDID] = 'b', 107794cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_DSO] = 'd', 1078439d473bSArnaldo Carvalho de Melo [DSO__ORIG_KMODULE] = 'K', 107994cb9e38SArnaldo Carvalho de Melo }; 108094cb9e38SArnaldo Carvalho de Melo 108194cb9e38SArnaldo Carvalho de Melo if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND) 108294cb9e38SArnaldo Carvalho de Melo return '!'; 108394cb9e38SArnaldo Carvalho de Melo return origin[self->origin]; 108494cb9e38SArnaldo Carvalho de Melo } 108594cb9e38SArnaldo Carvalho de Melo 10866beba7adSArnaldo Carvalho de Melo int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) 108786470930SIngo Molnar { 10884d1e00a8SArnaldo Carvalho de Melo int size = PATH_MAX; 1089c338aee8SArnaldo Carvalho de Melo char *name; 1090d3379ab9SArnaldo Carvalho de Melo u8 build_id[BUILD_ID_SIZE]; 109186470930SIngo Molnar int ret = -1; 109286470930SIngo Molnar int fd; 109386470930SIngo Molnar 10943610583cSArnaldo Carvalho de Melo dso__set_loaded(self, map->type); 109566bd8424SArnaldo Carvalho de Melo 1096c338aee8SArnaldo Carvalho de Melo if (self->kernel) 1097*9958e1f0SArnaldo Carvalho de Melo return dso__load_kernel_sym(self, map, kmaps, filter); 1098c338aee8SArnaldo Carvalho de Melo 1099c338aee8SArnaldo Carvalho de Melo name = malloc(size); 110086470930SIngo Molnar if (!name) 110186470930SIngo Molnar return -1; 110286470930SIngo Molnar 110330d7a77dSArnaldo Carvalho de Melo self->adjust_symbols = 0; 1104f5812a7aSArnaldo Carvalho de Melo 110594cb9e38SArnaldo Carvalho de Melo if (strncmp(self->name, "/tmp/perf-", 10) == 0) { 11066beba7adSArnaldo Carvalho de Melo ret = dso__load_perf_map(self, map, filter); 110794cb9e38SArnaldo Carvalho de Melo self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT : 110894cb9e38SArnaldo Carvalho de Melo DSO__ORIG_NOT_FOUND; 110994cb9e38SArnaldo Carvalho de Melo return ret; 111094cb9e38SArnaldo Carvalho de Melo } 111194cb9e38SArnaldo Carvalho de Melo 111294cb9e38SArnaldo Carvalho de Melo self->origin = DSO__ORIG_FEDORA - 1; 111380d496beSPekka Enberg 111486470930SIngo Molnar more: 111586470930SIngo Molnar do { 111694cb9e38SArnaldo Carvalho de Melo self->origin++; 111794cb9e38SArnaldo Carvalho de Melo switch (self->origin) { 111894cb9e38SArnaldo Carvalho de Melo case DSO__ORIG_FEDORA: 1119439d473bSArnaldo Carvalho de Melo snprintf(name, size, "/usr/lib/debug%s.debug", 1120439d473bSArnaldo Carvalho de Melo self->long_name); 112186470930SIngo Molnar break; 112294cb9e38SArnaldo Carvalho de Melo case DSO__ORIG_UBUNTU: 1123439d473bSArnaldo Carvalho de Melo snprintf(name, size, "/usr/lib/debug%s", 1124439d473bSArnaldo Carvalho de Melo self->long_name); 112586470930SIngo Molnar break; 112694cb9e38SArnaldo Carvalho de Melo case DSO__ORIG_BUILDID: 1127d3379ab9SArnaldo Carvalho de Melo if (filename__read_build_id(self->long_name, build_id, 1128d3379ab9SArnaldo Carvalho de Melo sizeof(build_id))) { 1129d3379ab9SArnaldo Carvalho de Melo char build_id_hex[BUILD_ID_SIZE * 2 + 1]; 1130d3379ab9SArnaldo Carvalho de Melo 1131d3379ab9SArnaldo Carvalho de Melo build_id__sprintf(build_id, sizeof(build_id), 1132d3379ab9SArnaldo Carvalho de Melo build_id_hex); 11334d1e00a8SArnaldo Carvalho de Melo snprintf(name, size, 11344d1e00a8SArnaldo Carvalho de Melo "/usr/lib/debug/.build-id/%.2s/%s.debug", 1135d3379ab9SArnaldo Carvalho de Melo build_id_hex, build_id_hex + 2); 1136d3379ab9SArnaldo Carvalho de Melo if (self->has_build_id) 11378d06367fSArnaldo Carvalho de Melo goto compare_build_id; 1138d3379ab9SArnaldo Carvalho de Melo break; 11394d1e00a8SArnaldo Carvalho de Melo } 114094cb9e38SArnaldo Carvalho de Melo self->origin++; 11414d1e00a8SArnaldo Carvalho de Melo /* Fall thru */ 114294cb9e38SArnaldo Carvalho de Melo case DSO__ORIG_DSO: 1143439d473bSArnaldo Carvalho de Melo snprintf(name, size, "%s", self->long_name); 114486470930SIngo Molnar break; 114586470930SIngo Molnar 114686470930SIngo Molnar default: 114786470930SIngo Molnar goto out; 114886470930SIngo Molnar } 114986470930SIngo Molnar 11508d06367fSArnaldo Carvalho de Melo if (self->has_build_id) { 1151d3379ab9SArnaldo Carvalho de Melo if (filename__read_build_id(name, build_id, 1152d3379ab9SArnaldo Carvalho de Melo sizeof(build_id)) < 0) 11538d06367fSArnaldo Carvalho de Melo goto more; 11548d06367fSArnaldo Carvalho de Melo compare_build_id: 115578075caaSArnaldo Carvalho de Melo if (!dso__build_id_equal(self, build_id)) 11568d06367fSArnaldo Carvalho de Melo goto more; 11578d06367fSArnaldo Carvalho de Melo } 11588d06367fSArnaldo Carvalho de Melo 115986470930SIngo Molnar fd = open(name, O_RDONLY); 116086470930SIngo Molnar } while (fd < 0); 116186470930SIngo Molnar 116295011c60SArnaldo Carvalho de Melo ret = dso__load_sym(self, map, NULL, name, fd, filter, 0, 0); 116386470930SIngo Molnar close(fd); 116486470930SIngo Molnar 116586470930SIngo Molnar /* 116686470930SIngo Molnar * Some people seem to have debuginfo files _WITHOUT_ debug info!?!? 116786470930SIngo Molnar */ 116886470930SIngo Molnar if (!ret) 116986470930SIngo Molnar goto more; 117086470930SIngo Molnar 1171a25e46c4SArnaldo Carvalho de Melo if (ret > 0) { 117282164161SArnaldo Carvalho de Melo int nr_plt = dso__synthesize_plt_symbols(self, map, filter); 1173a25e46c4SArnaldo Carvalho de Melo if (nr_plt > 0) 1174a25e46c4SArnaldo Carvalho de Melo ret += nr_plt; 1175a25e46c4SArnaldo Carvalho de Melo } 117686470930SIngo Molnar out: 117786470930SIngo Molnar free(name); 11781340e6bbSArnaldo Carvalho de Melo if (ret < 0 && strstr(self->name, " (deleted)") != NULL) 11791340e6bbSArnaldo Carvalho de Melo return 0; 118086470930SIngo Molnar return ret; 118186470930SIngo Molnar } 118286470930SIngo Molnar 1183*9958e1f0SArnaldo Carvalho de Melo static struct map *map_groups__find_by_name(struct map_groups *self, char *name) 1184439d473bSArnaldo Carvalho de Melo { 1185439d473bSArnaldo Carvalho de Melo struct rb_node *nd; 1186439d473bSArnaldo Carvalho de Melo 118795011c60SArnaldo Carvalho de Melo for (nd = rb_first(&self->maps[MAP__FUNCTION]); nd; nd = rb_next(nd)) { 1188439d473bSArnaldo Carvalho de Melo struct map *map = rb_entry(nd, struct map, rb_node); 1189439d473bSArnaldo Carvalho de Melo 1190439d473bSArnaldo Carvalho de Melo if (map->dso && strcmp(map->dso->name, name) == 0) 1191439d473bSArnaldo Carvalho de Melo return map; 1192439d473bSArnaldo Carvalho de Melo } 1193439d473bSArnaldo Carvalho de Melo 1194439d473bSArnaldo Carvalho de Melo return NULL; 1195439d473bSArnaldo Carvalho de Melo } 1196439d473bSArnaldo Carvalho de Melo 1197c338aee8SArnaldo Carvalho de Melo static int dsos__set_modules_path_dir(char *dirname) 11986cfcc53eSMike Galbraith { 1199439d473bSArnaldo Carvalho de Melo struct dirent *dent; 1200439d473bSArnaldo Carvalho de Melo DIR *dir = opendir(dirname); 12016cfcc53eSMike Galbraith 1202439d473bSArnaldo Carvalho de Melo if (!dir) { 120387f8ea4cSArnaldo Carvalho de Melo pr_debug("%s: cannot open %s dir\n", __func__, dirname); 1204439d473bSArnaldo Carvalho de Melo return -1; 1205439d473bSArnaldo Carvalho de Melo } 12066cfcc53eSMike Galbraith 1207439d473bSArnaldo Carvalho de Melo while ((dent = readdir(dir)) != NULL) { 1208439d473bSArnaldo Carvalho de Melo char path[PATH_MAX]; 1209439d473bSArnaldo Carvalho de Melo 1210439d473bSArnaldo Carvalho de Melo if (dent->d_type == DT_DIR) { 1211439d473bSArnaldo Carvalho de Melo if (!strcmp(dent->d_name, ".") || 1212439d473bSArnaldo Carvalho de Melo !strcmp(dent->d_name, "..")) 1213439d473bSArnaldo Carvalho de Melo continue; 1214439d473bSArnaldo Carvalho de Melo 1215439d473bSArnaldo Carvalho de Melo snprintf(path, sizeof(path), "%s/%s", 1216439d473bSArnaldo Carvalho de Melo dirname, dent->d_name); 1217c338aee8SArnaldo Carvalho de Melo if (dsos__set_modules_path_dir(path) < 0) 1218439d473bSArnaldo Carvalho de Melo goto failure; 1219439d473bSArnaldo Carvalho de Melo } else { 1220439d473bSArnaldo Carvalho de Melo char *dot = strrchr(dent->d_name, '.'), 1221439d473bSArnaldo Carvalho de Melo dso_name[PATH_MAX]; 1222439d473bSArnaldo Carvalho de Melo struct map *map; 1223cfc10d3bSArnaldo Carvalho de Melo char *long_name; 1224439d473bSArnaldo Carvalho de Melo 1225439d473bSArnaldo Carvalho de Melo if (dot == NULL || strcmp(dot, ".ko")) 1226439d473bSArnaldo Carvalho de Melo continue; 1227439d473bSArnaldo Carvalho de Melo snprintf(dso_name, sizeof(dso_name), "[%.*s]", 1228439d473bSArnaldo Carvalho de Melo (int)(dot - dent->d_name), dent->d_name); 1229439d473bSArnaldo Carvalho de Melo 1230a2a99e8eSArnaldo Carvalho de Melo strxfrchar(dso_name, '-', '_'); 1231*9958e1f0SArnaldo Carvalho de Melo map = map_groups__find_by_name(kmaps, dso_name); 1232439d473bSArnaldo Carvalho de Melo if (map == NULL) 1233439d473bSArnaldo Carvalho de Melo continue; 1234439d473bSArnaldo Carvalho de Melo 1235439d473bSArnaldo Carvalho de Melo snprintf(path, sizeof(path), "%s/%s", 1236439d473bSArnaldo Carvalho de Melo dirname, dent->d_name); 1237439d473bSArnaldo Carvalho de Melo 1238cfc10d3bSArnaldo Carvalho de Melo long_name = strdup(path); 1239cfc10d3bSArnaldo Carvalho de Melo if (long_name == NULL) 1240439d473bSArnaldo Carvalho de Melo goto failure; 1241cfc10d3bSArnaldo Carvalho de Melo dso__set_long_name(map->dso, long_name); 1242439d473bSArnaldo Carvalho de Melo } 1243439d473bSArnaldo Carvalho de Melo } 1244439d473bSArnaldo Carvalho de Melo 1245c338aee8SArnaldo Carvalho de Melo return 0; 1246439d473bSArnaldo Carvalho de Melo failure: 1247439d473bSArnaldo Carvalho de Melo closedir(dir); 1248439d473bSArnaldo Carvalho de Melo return -1; 1249439d473bSArnaldo Carvalho de Melo } 1250439d473bSArnaldo Carvalho de Melo 1251c338aee8SArnaldo Carvalho de Melo static int dsos__set_modules_path(void) 1252439d473bSArnaldo Carvalho de Melo { 1253439d473bSArnaldo Carvalho de Melo struct utsname uts; 1254439d473bSArnaldo Carvalho de Melo char modules_path[PATH_MAX]; 1255439d473bSArnaldo Carvalho de Melo 1256439d473bSArnaldo Carvalho de Melo if (uname(&uts) < 0) 1257439d473bSArnaldo Carvalho de Melo return -1; 1258439d473bSArnaldo Carvalho de Melo 1259439d473bSArnaldo Carvalho de Melo snprintf(modules_path, sizeof(modules_path), "/lib/modules/%s/kernel", 1260439d473bSArnaldo Carvalho de Melo uts.release); 1261439d473bSArnaldo Carvalho de Melo 1262c338aee8SArnaldo Carvalho de Melo return dsos__set_modules_path_dir(modules_path); 1263439d473bSArnaldo Carvalho de Melo } 12646cfcc53eSMike Galbraith 12656cfcc53eSMike Galbraith /* 1266439d473bSArnaldo Carvalho de Melo * Constructor variant for modules (where we know from /proc/modules where 1267439d473bSArnaldo Carvalho de Melo * they are loaded) and for vmlinux, where only after we load all the 1268439d473bSArnaldo Carvalho de Melo * symbols we'll know where it starts and ends. 12696cfcc53eSMike Galbraith */ 12703610583cSArnaldo Carvalho de Melo static struct map *map__new2(u64 start, struct dso *dso, enum map_type type) 1271439d473bSArnaldo Carvalho de Melo { 1272439d473bSArnaldo Carvalho de Melo struct map *self = malloc(sizeof(*self)); 12736cfcc53eSMike Galbraith 1274439d473bSArnaldo Carvalho de Melo if (self != NULL) { 1275439d473bSArnaldo Carvalho de Melo /* 1276afb7b4f0SArnaldo Carvalho de Melo * ->end will be filled after we load all the symbols 1277439d473bSArnaldo Carvalho de Melo */ 12783610583cSArnaldo Carvalho de Melo map__init(self, type, start, 0, 0, dso); 1279439d473bSArnaldo Carvalho de Melo } 1280afb7b4f0SArnaldo Carvalho de Melo 1281439d473bSArnaldo Carvalho de Melo return self; 1282439d473bSArnaldo Carvalho de Melo } 1283439d473bSArnaldo Carvalho de Melo 1284*9958e1f0SArnaldo Carvalho de Melo static int map_groups__create_module_maps(struct map_groups *self) 1285439d473bSArnaldo Carvalho de Melo { 1286439d473bSArnaldo Carvalho de Melo char *line = NULL; 1287439d473bSArnaldo Carvalho de Melo size_t n; 1288439d473bSArnaldo Carvalho de Melo FILE *file = fopen("/proc/modules", "r"); 1289439d473bSArnaldo Carvalho de Melo struct map *map; 1290439d473bSArnaldo Carvalho de Melo 1291439d473bSArnaldo Carvalho de Melo if (file == NULL) 1292439d473bSArnaldo Carvalho de Melo return -1; 1293439d473bSArnaldo Carvalho de Melo 1294439d473bSArnaldo Carvalho de Melo while (!feof(file)) { 1295439d473bSArnaldo Carvalho de Melo char name[PATH_MAX]; 1296439d473bSArnaldo Carvalho de Melo u64 start; 1297439d473bSArnaldo Carvalho de Melo struct dso *dso; 1298439d473bSArnaldo Carvalho de Melo char *sep; 1299439d473bSArnaldo Carvalho de Melo int line_len; 1300439d473bSArnaldo Carvalho de Melo 1301439d473bSArnaldo Carvalho de Melo line_len = getline(&line, &n, file); 1302439d473bSArnaldo Carvalho de Melo if (line_len < 0) 13036cfcc53eSMike Galbraith break; 13046cfcc53eSMike Galbraith 1305439d473bSArnaldo Carvalho de Melo if (!line) 1306439d473bSArnaldo Carvalho de Melo goto out_failure; 1307439d473bSArnaldo Carvalho de Melo 1308439d473bSArnaldo Carvalho de Melo line[--line_len] = '\0'; /* \n */ 1309439d473bSArnaldo Carvalho de Melo 1310439d473bSArnaldo Carvalho de Melo sep = strrchr(line, 'x'); 1311439d473bSArnaldo Carvalho de Melo if (sep == NULL) 1312439d473bSArnaldo Carvalho de Melo continue; 1313439d473bSArnaldo Carvalho de Melo 1314439d473bSArnaldo Carvalho de Melo hex2u64(sep + 1, &start); 1315439d473bSArnaldo Carvalho de Melo 1316439d473bSArnaldo Carvalho de Melo sep = strchr(line, ' '); 1317439d473bSArnaldo Carvalho de Melo if (sep == NULL) 1318439d473bSArnaldo Carvalho de Melo continue; 1319439d473bSArnaldo Carvalho de Melo 1320439d473bSArnaldo Carvalho de Melo *sep = '\0'; 1321439d473bSArnaldo Carvalho de Melo 1322439d473bSArnaldo Carvalho de Melo snprintf(name, sizeof(name), "[%s]", line); 132300a192b3SArnaldo Carvalho de Melo dso = dso__new(name); 1324439d473bSArnaldo Carvalho de Melo 1325439d473bSArnaldo Carvalho de Melo if (dso == NULL) 1326439d473bSArnaldo Carvalho de Melo goto out_delete_line; 1327439d473bSArnaldo Carvalho de Melo 13283610583cSArnaldo Carvalho de Melo map = map__new2(start, dso, MAP__FUNCTION); 1329439d473bSArnaldo Carvalho de Melo if (map == NULL) { 1330439d473bSArnaldo Carvalho de Melo dso__delete(dso); 1331439d473bSArnaldo Carvalho de Melo goto out_delete_line; 13326cfcc53eSMike Galbraith } 13336cfcc53eSMike Galbraith 1334f1617b40SArnaldo Carvalho de Melo snprintf(name, sizeof(name), 1335f1617b40SArnaldo Carvalho de Melo "/sys/module/%s/notes/.note.gnu.build-id", line); 1336f1617b40SArnaldo Carvalho de Melo if (sysfs__read_build_id(name, dso->build_id, 1337f1617b40SArnaldo Carvalho de Melo sizeof(dso->build_id)) == 0) 1338f1617b40SArnaldo Carvalho de Melo dso->has_build_id = true; 1339f1617b40SArnaldo Carvalho de Melo 1340439d473bSArnaldo Carvalho de Melo dso->origin = DSO__ORIG_KMODULE; 1341*9958e1f0SArnaldo Carvalho de Melo map_groups__insert(self, map); 1342b0da954aSArnaldo Carvalho de Melo dsos__add(&dsos__kernel, dso); 13436cfcc53eSMike Galbraith } 13446cfcc53eSMike Galbraith 1345439d473bSArnaldo Carvalho de Melo free(line); 1346439d473bSArnaldo Carvalho de Melo fclose(file); 1347439d473bSArnaldo Carvalho de Melo 1348c338aee8SArnaldo Carvalho de Melo return dsos__set_modules_path(); 1349439d473bSArnaldo Carvalho de Melo 1350439d473bSArnaldo Carvalho de Melo out_delete_line: 1351439d473bSArnaldo Carvalho de Melo free(line); 1352439d473bSArnaldo Carvalho de Melo out_failure: 1353439d473bSArnaldo Carvalho de Melo return -1; 13546cfcc53eSMike Galbraith } 13556cfcc53eSMike Galbraith 1356*9958e1f0SArnaldo Carvalho de Melo static int dso__load_vmlinux(struct dso *self, struct map *map, 1357*9958e1f0SArnaldo Carvalho de Melo struct map_groups *mg, 13586beba7adSArnaldo Carvalho de Melo const char *vmlinux, symbol_filter_t filter) 135986470930SIngo Molnar { 1360fbd733b8SArnaldo Carvalho de Melo int err = -1, fd; 136186470930SIngo Molnar 1362fbd733b8SArnaldo Carvalho de Melo if (self->has_build_id) { 1363fbd733b8SArnaldo Carvalho de Melo u8 build_id[BUILD_ID_SIZE]; 136466bd8424SArnaldo Carvalho de Melo 1365fbd733b8SArnaldo Carvalho de Melo if (filename__read_build_id(vmlinux, build_id, 1366fbd733b8SArnaldo Carvalho de Melo sizeof(build_id)) < 0) { 1367fbd733b8SArnaldo Carvalho de Melo pr_debug("No build_id in %s, ignoring it\n", vmlinux); 1368fbd733b8SArnaldo Carvalho de Melo return -1; 1369fbd733b8SArnaldo Carvalho de Melo } 1370fbd733b8SArnaldo Carvalho de Melo if (!dso__build_id_equal(self, build_id)) { 1371fbd733b8SArnaldo Carvalho de Melo char expected_build_id[BUILD_ID_SIZE * 2 + 1], 1372fbd733b8SArnaldo Carvalho de Melo vmlinux_build_id[BUILD_ID_SIZE * 2 + 1]; 1373fbd733b8SArnaldo Carvalho de Melo 1374fbd733b8SArnaldo Carvalho de Melo build_id__sprintf(self->build_id, 1375fbd733b8SArnaldo Carvalho de Melo sizeof(self->build_id), 1376fbd733b8SArnaldo Carvalho de Melo expected_build_id); 1377fbd733b8SArnaldo Carvalho de Melo build_id__sprintf(build_id, sizeof(build_id), 1378fbd733b8SArnaldo Carvalho de Melo vmlinux_build_id); 1379fbd733b8SArnaldo Carvalho de Melo pr_debug("build_id in %s is %s while expected is %s, " 1380fbd733b8SArnaldo Carvalho de Melo "ignoring it\n", vmlinux, vmlinux_build_id, 1381fbd733b8SArnaldo Carvalho de Melo expected_build_id); 1382fbd733b8SArnaldo Carvalho de Melo return -1; 1383fbd733b8SArnaldo Carvalho de Melo } 1384fbd733b8SArnaldo Carvalho de Melo } 1385fbd733b8SArnaldo Carvalho de Melo 1386fbd733b8SArnaldo Carvalho de Melo fd = open(vmlinux, O_RDONLY); 138786470930SIngo Molnar if (fd < 0) 138886470930SIngo Molnar return -1; 138986470930SIngo Molnar 13903610583cSArnaldo Carvalho de Melo dso__set_loaded(self, map->type); 1391*9958e1f0SArnaldo Carvalho de Melo err = dso__load_sym(self, map, mg, self->long_name, fd, filter, 1, 0); 139286470930SIngo Molnar close(fd); 139386470930SIngo Molnar 139486470930SIngo Molnar return err; 139586470930SIngo Molnar } 139686470930SIngo Molnar 1397c338aee8SArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *self, struct map *map, 1398*9958e1f0SArnaldo Carvalho de Melo struct map_groups *mg, symbol_filter_t filter) 139986470930SIngo Molnar { 1400cc612d81SArnaldo Carvalho de Melo int err; 1401cc612d81SArnaldo Carvalho de Melo bool is_kallsyms; 1402439d473bSArnaldo Carvalho de Melo 1403cc612d81SArnaldo Carvalho de Melo if (vmlinux_path != NULL) { 1404cc612d81SArnaldo Carvalho de Melo int i; 1405cc612d81SArnaldo Carvalho de Melo pr_debug("Looking at the vmlinux_path (%d entries long)\n", 1406cc612d81SArnaldo Carvalho de Melo vmlinux_path__nr_entries); 1407cc612d81SArnaldo Carvalho de Melo for (i = 0; i < vmlinux_path__nr_entries; ++i) { 1408*9958e1f0SArnaldo Carvalho de Melo err = dso__load_vmlinux(self, map, mg, 140995011c60SArnaldo Carvalho de Melo vmlinux_path[i], filter); 1410cc612d81SArnaldo Carvalho de Melo if (err > 0) { 1411cc612d81SArnaldo Carvalho de Melo pr_debug("Using %s for symbols\n", 1412cc612d81SArnaldo Carvalho de Melo vmlinux_path[i]); 1413cc612d81SArnaldo Carvalho de Melo dso__set_long_name(self, 1414cc612d81SArnaldo Carvalho de Melo strdup(vmlinux_path[i])); 1415cc612d81SArnaldo Carvalho de Melo goto out_fixup; 1416cc612d81SArnaldo Carvalho de Melo } 1417cc612d81SArnaldo Carvalho de Melo } 1418cc612d81SArnaldo Carvalho de Melo } 1419cc612d81SArnaldo Carvalho de Melo 1420cc612d81SArnaldo Carvalho de Melo is_kallsyms = self->long_name[0] == '['; 1421cc612d81SArnaldo Carvalho de Melo if (is_kallsyms) 1422cc612d81SArnaldo Carvalho de Melo goto do_kallsyms; 1423cc612d81SArnaldo Carvalho de Melo 1424*9958e1f0SArnaldo Carvalho de Melo err = dso__load_vmlinux(self, map, mg, self->long_name, filter); 1425ef6ae724SArnaldo Carvalho de Melo if (err <= 0) { 1426cc612d81SArnaldo Carvalho de Melo pr_info("The file %s cannot be used, " 1427cc612d81SArnaldo Carvalho de Melo "trying to use /proc/kallsyms...", self->long_name); 1428cc612d81SArnaldo Carvalho de Melo do_kallsyms: 1429*9958e1f0SArnaldo Carvalho de Melo err = dso__load_kallsyms(self, map, mg, filter); 1430cc612d81SArnaldo Carvalho de Melo if (err > 0 && !is_kallsyms) 1431ef6ae724SArnaldo Carvalho de Melo dso__set_long_name(self, strdup("[kernel.kallsyms]")); 1432ef6ae724SArnaldo Carvalho de Melo } 143386470930SIngo Molnar 1434439d473bSArnaldo Carvalho de Melo if (err > 0) { 1435cc612d81SArnaldo Carvalho de Melo out_fixup: 14366a4694a4SArnaldo Carvalho de Melo map__fixup_start(map); 14376a4694a4SArnaldo Carvalho de Melo map__fixup_end(map); 1438439d473bSArnaldo Carvalho de Melo } 143994cb9e38SArnaldo Carvalho de Melo 144086470930SIngo Molnar return err; 144186470930SIngo Molnar } 144286470930SIngo Molnar 1443b0da954aSArnaldo Carvalho de Melo LIST_HEAD(dsos__user); 1444b0da954aSArnaldo Carvalho de Melo LIST_HEAD(dsos__kernel); 1445cd84c2acSFrederic Weisbecker struct dso *vdso; 1446cd84c2acSFrederic Weisbecker 1447b0da954aSArnaldo Carvalho de Melo static void dsos__add(struct list_head *head, struct dso *dso) 1448cd84c2acSFrederic Weisbecker { 1449b0da954aSArnaldo Carvalho de Melo list_add_tail(&dso->node, head); 1450cd84c2acSFrederic Weisbecker } 1451cd84c2acSFrederic Weisbecker 1452b0da954aSArnaldo Carvalho de Melo static struct dso *dsos__find(struct list_head *head, const char *name) 1453cd84c2acSFrederic Weisbecker { 1454cd84c2acSFrederic Weisbecker struct dso *pos; 1455cd84c2acSFrederic Weisbecker 1456b0da954aSArnaldo Carvalho de Melo list_for_each_entry(pos, head, node) 1457cd84c2acSFrederic Weisbecker if (strcmp(pos->name, name) == 0) 1458cd84c2acSFrederic Weisbecker return pos; 1459cd84c2acSFrederic Weisbecker return NULL; 1460cd84c2acSFrederic Weisbecker } 1461cd84c2acSFrederic Weisbecker 146200a192b3SArnaldo Carvalho de Melo struct dso *dsos__findnew(const char *name) 1463cd84c2acSFrederic Weisbecker { 1464b0da954aSArnaldo Carvalho de Melo struct dso *dso = dsos__find(&dsos__user, name); 1465cd84c2acSFrederic Weisbecker 1466e4204992SArnaldo Carvalho de Melo if (!dso) { 146700a192b3SArnaldo Carvalho de Melo dso = dso__new(name); 1468cfc10d3bSArnaldo Carvalho de Melo if (dso != NULL) { 1469b0da954aSArnaldo Carvalho de Melo dsos__add(&dsos__user, dso); 1470cfc10d3bSArnaldo Carvalho de Melo dso__set_basename(dso); 1471cfc10d3bSArnaldo Carvalho de Melo } 1472e4204992SArnaldo Carvalho de Melo } 1473cd84c2acSFrederic Weisbecker 1474cd84c2acSFrederic Weisbecker return dso; 1475cd84c2acSFrederic Weisbecker } 1476cd84c2acSFrederic Weisbecker 1477b0da954aSArnaldo Carvalho de Melo static void __dsos__fprintf(struct list_head *head, FILE *fp) 1478cd84c2acSFrederic Weisbecker { 1479cd84c2acSFrederic Weisbecker struct dso *pos; 1480cd84c2acSFrederic Weisbecker 148195011c60SArnaldo Carvalho de Melo list_for_each_entry(pos, head, node) { 148295011c60SArnaldo Carvalho de Melo int i; 148395011c60SArnaldo Carvalho de Melo for (i = 0; i < MAP__NR_TYPES; ++i) 148495011c60SArnaldo Carvalho de Melo dso__fprintf(pos, i, fp); 148595011c60SArnaldo Carvalho de Melo } 1486cd84c2acSFrederic Weisbecker } 1487cd84c2acSFrederic Weisbecker 1488b0da954aSArnaldo Carvalho de Melo void dsos__fprintf(FILE *fp) 1489b0da954aSArnaldo Carvalho de Melo { 1490b0da954aSArnaldo Carvalho de Melo __dsos__fprintf(&dsos__kernel, fp); 1491b0da954aSArnaldo Carvalho de Melo __dsos__fprintf(&dsos__user, fp); 1492b0da954aSArnaldo Carvalho de Melo } 1493b0da954aSArnaldo Carvalho de Melo 1494b0da954aSArnaldo Carvalho de Melo static size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp) 14959e03eb2dSArnaldo Carvalho de Melo { 14969e03eb2dSArnaldo Carvalho de Melo struct dso *pos; 14979e03eb2dSArnaldo Carvalho de Melo size_t ret = 0; 14989e03eb2dSArnaldo Carvalho de Melo 1499b0da954aSArnaldo Carvalho de Melo list_for_each_entry(pos, head, node) { 15009e03eb2dSArnaldo Carvalho de Melo ret += dso__fprintf_buildid(pos, fp); 15019e03eb2dSArnaldo Carvalho de Melo ret += fprintf(fp, " %s\n", pos->long_name); 15029e03eb2dSArnaldo Carvalho de Melo } 15039e03eb2dSArnaldo Carvalho de Melo return ret; 15049e03eb2dSArnaldo Carvalho de Melo } 15059e03eb2dSArnaldo Carvalho de Melo 1506b0da954aSArnaldo Carvalho de Melo size_t dsos__fprintf_buildid(FILE *fp) 1507b0da954aSArnaldo Carvalho de Melo { 1508b0da954aSArnaldo Carvalho de Melo return (__dsos__fprintf_buildid(&dsos__kernel, fp) + 1509b0da954aSArnaldo Carvalho de Melo __dsos__fprintf_buildid(&dsos__user, fp)); 1510b0da954aSArnaldo Carvalho de Melo } 1511b0da954aSArnaldo Carvalho de Melo 1512*9958e1f0SArnaldo Carvalho de Melo static int map_groups__create_kernel_map(struct map_groups *self, const char *vmlinux) 1513cd84c2acSFrederic Weisbecker { 15144e06255fSArnaldo Carvalho de Melo struct map *kmap; 151595011c60SArnaldo Carvalho de Melo struct dso *kernel = dso__new(vmlinux ?: "[kernel.kallsyms]"); 1516cd84c2acSFrederic Weisbecker 15172446042cSArnaldo Carvalho de Melo if (kernel == NULL) 1518c338aee8SArnaldo Carvalho de Melo return -1; 1519c338aee8SArnaldo Carvalho de Melo 15204e06255fSArnaldo Carvalho de Melo kmap = map__new2(0, kernel, MAP__FUNCTION); 15214e06255fSArnaldo Carvalho de Melo if (kmap == NULL) 1522c338aee8SArnaldo Carvalho de Melo goto out_delete_kernel_dso; 1523c338aee8SArnaldo Carvalho de Melo 15244e06255fSArnaldo Carvalho de Melo kmap->map_ip = kmap->unmap_ip = identity__map_ip; 15252446042cSArnaldo Carvalho de Melo kernel->short_name = "[kernel]"; 1526c338aee8SArnaldo Carvalho de Melo kernel->kernel = 1; 1527cc612d81SArnaldo Carvalho de Melo 152800a192b3SArnaldo Carvalho de Melo vdso = dso__new("[vdso]"); 1529c338aee8SArnaldo Carvalho de Melo if (vdso == NULL) 1530c338aee8SArnaldo Carvalho de Melo goto out_delete_kernel_map; 15313610583cSArnaldo Carvalho de Melo dso__set_loaded(vdso, MAP__FUNCTION); 1532cd84c2acSFrederic Weisbecker 15332446042cSArnaldo Carvalho de Melo if (sysfs__read_build_id("/sys/kernel/notes", kernel->build_id, 15342446042cSArnaldo Carvalho de Melo sizeof(kernel->build_id)) == 0) 15352446042cSArnaldo Carvalho de Melo kernel->has_build_id = true; 15362446042cSArnaldo Carvalho de Melo 1537*9958e1f0SArnaldo Carvalho de Melo map_groups__insert(self, kmap); 1538b0da954aSArnaldo Carvalho de Melo dsos__add(&dsos__kernel, kernel); 1539b0da954aSArnaldo Carvalho de Melo dsos__add(&dsos__user, vdso); 1540cd84c2acSFrederic Weisbecker 1541c338aee8SArnaldo Carvalho de Melo return 0; 1542c338aee8SArnaldo Carvalho de Melo 1543c338aee8SArnaldo Carvalho de Melo out_delete_kernel_map: 15444e06255fSArnaldo Carvalho de Melo map__delete(kmap); 1545c338aee8SArnaldo Carvalho de Melo out_delete_kernel_dso: 1546c338aee8SArnaldo Carvalho de Melo dso__delete(kernel); 1547c338aee8SArnaldo Carvalho de Melo return -1; 15482446042cSArnaldo Carvalho de Melo } 15492446042cSArnaldo Carvalho de Melo 1550cc612d81SArnaldo Carvalho de Melo static void vmlinux_path__exit(void) 15512446042cSArnaldo Carvalho de Melo { 1552cc612d81SArnaldo Carvalho de Melo while (--vmlinux_path__nr_entries >= 0) { 1553cc612d81SArnaldo Carvalho de Melo free(vmlinux_path[vmlinux_path__nr_entries]); 1554cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = NULL; 1555cc612d81SArnaldo Carvalho de Melo } 1556cc612d81SArnaldo Carvalho de Melo 1557cc612d81SArnaldo Carvalho de Melo free(vmlinux_path); 1558cc612d81SArnaldo Carvalho de Melo vmlinux_path = NULL; 1559cc612d81SArnaldo Carvalho de Melo } 1560cc612d81SArnaldo Carvalho de Melo 1561cc612d81SArnaldo Carvalho de Melo static int vmlinux_path__init(void) 1562cc612d81SArnaldo Carvalho de Melo { 1563cc612d81SArnaldo Carvalho de Melo struct utsname uts; 1564cc612d81SArnaldo Carvalho de Melo char bf[PATH_MAX]; 1565cc612d81SArnaldo Carvalho de Melo 1566cc612d81SArnaldo Carvalho de Melo if (uname(&uts) < 0) 15672446042cSArnaldo Carvalho de Melo return -1; 15682446042cSArnaldo Carvalho de Melo 1569cc612d81SArnaldo Carvalho de Melo vmlinux_path = malloc(sizeof(char *) * 5); 1570cc612d81SArnaldo Carvalho de Melo if (vmlinux_path == NULL) 1571cc612d81SArnaldo Carvalho de Melo return -1; 1572cc612d81SArnaldo Carvalho de Melo 1573cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup("vmlinux"); 1574cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 1575cc612d81SArnaldo Carvalho de Melo goto out_fail; 1576cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 1577cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup("/boot/vmlinux"); 1578cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 1579cc612d81SArnaldo Carvalho de Melo goto out_fail; 1580cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 1581cc612d81SArnaldo Carvalho de Melo snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", uts.release); 1582cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); 1583cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 1584cc612d81SArnaldo Carvalho de Melo goto out_fail; 1585cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 1586cc612d81SArnaldo Carvalho de Melo snprintf(bf, sizeof(bf), "/lib/modules/%s/build/vmlinux", uts.release); 1587cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); 1588cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 1589cc612d81SArnaldo Carvalho de Melo goto out_fail; 1590cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 1591cc612d81SArnaldo Carvalho de Melo snprintf(bf, sizeof(bf), "/usr/lib/debug/lib/modules/%s/vmlinux", 1592cc612d81SArnaldo Carvalho de Melo uts.release); 1593cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); 1594cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 1595cc612d81SArnaldo Carvalho de Melo goto out_fail; 1596cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 1597cc612d81SArnaldo Carvalho de Melo 1598cc612d81SArnaldo Carvalho de Melo return 0; 1599cc612d81SArnaldo Carvalho de Melo 1600cc612d81SArnaldo Carvalho de Melo out_fail: 1601cc612d81SArnaldo Carvalho de Melo vmlinux_path__exit(); 1602cc612d81SArnaldo Carvalho de Melo return -1; 1603cc612d81SArnaldo Carvalho de Melo } 1604cc612d81SArnaldo Carvalho de Melo 160595011c60SArnaldo Carvalho de Melo int symbol__init(struct symbol_conf *conf) 1606cc612d81SArnaldo Carvalho de Melo { 1607b32d133aSArnaldo Carvalho de Melo const struct symbol_conf *pconf = conf ?: &symbol_conf__defaults; 1608b32d133aSArnaldo Carvalho de Melo 160995011c60SArnaldo Carvalho de Melo elf_version(EV_CURRENT); 1610b32d133aSArnaldo Carvalho de Melo symbol__priv_size = pconf->priv_size; 1611*9958e1f0SArnaldo Carvalho de Melo map_groups__init(kmaps); 1612b32d133aSArnaldo Carvalho de Melo 1613b32d133aSArnaldo Carvalho de Melo if (pconf->try_vmlinux_path && vmlinux_path__init() < 0) 1614cc612d81SArnaldo Carvalho de Melo return -1; 1615cc612d81SArnaldo Carvalho de Melo 1616*9958e1f0SArnaldo Carvalho de Melo if (map_groups__create_kernel_map(kmaps, pconf->vmlinux_name) < 0) { 1617cc612d81SArnaldo Carvalho de Melo vmlinux_path__exit(); 1618cc612d81SArnaldo Carvalho de Melo return -1; 1619cc612d81SArnaldo Carvalho de Melo } 1620cc612d81SArnaldo Carvalho de Melo 1621*9958e1f0SArnaldo Carvalho de Melo kmaps->use_modules = pconf->use_modules; 1622*9958e1f0SArnaldo Carvalho de Melo if (pconf->use_modules && map_groups__create_module_maps(kmaps) < 0) 162387f8ea4cSArnaldo Carvalho de Melo pr_debug("Failed to load list of modules in use, " 16246671cb16SArnaldo Carvalho de Melo "continuing...\n"); 162590c83218SArnaldo Carvalho de Melo /* 162690c83218SArnaldo Carvalho de Melo * Now that we have all the maps created, just set the ->end of them: 162790c83218SArnaldo Carvalho de Melo */ 1628*9958e1f0SArnaldo Carvalho de Melo map_groups__fixup_end(kmaps); 16296671cb16SArnaldo Carvalho de Melo return 0; 1630cd84c2acSFrederic Weisbecker } 1631