186470930SIngo Molnar #include "util.h" 286470930SIngo Molnar #include "../perf.h" 3655000e7SArnaldo Carvalho de Melo #include "sort.h" 486470930SIngo Molnar #include "string.h" 586470930SIngo Molnar #include "symbol.h" 6439d473bSArnaldo Carvalho de Melo #include "thread.h" 786470930SIngo Molnar 88f28827aSFrederic Weisbecker #include "debug.h" 98f28827aSFrederic Weisbecker 10b32d133aSArnaldo Carvalho de Melo #include <asm/bug.h> 1186470930SIngo Molnar #include <libelf.h> 1286470930SIngo Molnar #include <gelf.h> 1386470930SIngo Molnar #include <elf.h> 14f1617b40SArnaldo Carvalho de Melo #include <limits.h> 15439d473bSArnaldo Carvalho de Melo #include <sys/utsname.h> 162cdbc46dSPeter Zijlstra 17c12e15e7SArnaldo Carvalho de Melo #ifndef NT_GNU_BUILD_ID 18c12e15e7SArnaldo Carvalho de Melo #define NT_GNU_BUILD_ID 3 19c12e15e7SArnaldo Carvalho de Melo #endif 20c12e15e7SArnaldo Carvalho de Melo 2194cb9e38SArnaldo Carvalho de Melo enum dso_origin { 2294cb9e38SArnaldo Carvalho de Melo DSO__ORIG_KERNEL = 0, 2394cb9e38SArnaldo Carvalho de Melo DSO__ORIG_JAVA_JIT, 244cf40131SArnaldo Carvalho de Melo DSO__ORIG_BUILD_ID_CACHE, 2594cb9e38SArnaldo Carvalho de Melo DSO__ORIG_FEDORA, 2694cb9e38SArnaldo Carvalho de Melo DSO__ORIG_UBUNTU, 2794cb9e38SArnaldo Carvalho de Melo DSO__ORIG_BUILDID, 2894cb9e38SArnaldo Carvalho de Melo DSO__ORIG_DSO, 29439d473bSArnaldo Carvalho de Melo DSO__ORIG_KMODULE, 3094cb9e38SArnaldo Carvalho de Melo DSO__ORIG_NOT_FOUND, 3194cb9e38SArnaldo Carvalho de Melo }; 3294cb9e38SArnaldo Carvalho de Melo 33b0da954aSArnaldo Carvalho de Melo static void dsos__add(struct list_head *head, struct dso *dso); 343610583cSArnaldo Carvalho de Melo static struct map *map__new2(u64 start, struct dso *dso, enum map_type type); 35c338aee8SArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *self, struct map *map, 369de89fe7SArnaldo Carvalho de Melo symbol_filter_t filter); 37cc612d81SArnaldo Carvalho de Melo static int vmlinux_path__nr_entries; 38cc612d81SArnaldo Carvalho de Melo static char **vmlinux_path; 39439d473bSArnaldo Carvalho de Melo 4075be6cf4SArnaldo Carvalho de Melo struct symbol_conf symbol_conf = { 41d599db3fSArnaldo Carvalho de Melo .exclude_other = true, 42b32d133aSArnaldo Carvalho de Melo .use_modules = true, 43b32d133aSArnaldo Carvalho de Melo .try_vmlinux_path = true, 44b32d133aSArnaldo Carvalho de Melo }; 45b32d133aSArnaldo Carvalho de Melo 463610583cSArnaldo Carvalho de Melo bool dso__loaded(const struct dso *self, enum map_type type) 473610583cSArnaldo Carvalho de Melo { 483610583cSArnaldo Carvalho de Melo return self->loaded & (1 << type); 493610583cSArnaldo Carvalho de Melo } 503610583cSArnaldo Carvalho de Melo 5179406cd7SArnaldo Carvalho de Melo bool dso__sorted_by_name(const struct dso *self, enum map_type type) 5279406cd7SArnaldo Carvalho de Melo { 5379406cd7SArnaldo Carvalho de Melo return self->sorted_by_name & (1 << type); 5479406cd7SArnaldo Carvalho de Melo } 5579406cd7SArnaldo Carvalho de Melo 5679406cd7SArnaldo Carvalho de Melo static void dso__set_sorted_by_name(struct dso *self, enum map_type type) 5779406cd7SArnaldo Carvalho de Melo { 5879406cd7SArnaldo Carvalho de Melo self->sorted_by_name |= (1 << type); 5979406cd7SArnaldo Carvalho de Melo } 6079406cd7SArnaldo Carvalho de Melo 6136a3e646SArnaldo Carvalho de Melo bool symbol_type__is_a(char symbol_type, enum map_type map_type) 626893d4eeSArnaldo Carvalho de Melo { 636893d4eeSArnaldo Carvalho de Melo switch (map_type) { 646893d4eeSArnaldo Carvalho de Melo case MAP__FUNCTION: 656893d4eeSArnaldo Carvalho de Melo return symbol_type == 'T' || symbol_type == 'W'; 66f1dfa0b1SArnaldo Carvalho de Melo case MAP__VARIABLE: 67f1dfa0b1SArnaldo Carvalho de Melo return symbol_type == 'D' || symbol_type == 'd'; 686893d4eeSArnaldo Carvalho de Melo default: 696893d4eeSArnaldo Carvalho de Melo return false; 706893d4eeSArnaldo Carvalho de Melo } 716893d4eeSArnaldo Carvalho de Melo } 726893d4eeSArnaldo Carvalho de Melo 73fcf1203aSArnaldo Carvalho de Melo static void symbols__fixup_end(struct rb_root *self) 74af427bf5SArnaldo Carvalho de Melo { 75fcf1203aSArnaldo Carvalho de Melo struct rb_node *nd, *prevnd = rb_first(self); 762e538c4aSArnaldo Carvalho de Melo struct symbol *curr, *prev; 77af427bf5SArnaldo Carvalho de Melo 78af427bf5SArnaldo Carvalho de Melo if (prevnd == NULL) 79af427bf5SArnaldo Carvalho de Melo return; 80af427bf5SArnaldo Carvalho de Melo 812e538c4aSArnaldo Carvalho de Melo curr = rb_entry(prevnd, struct symbol, rb_node); 822e538c4aSArnaldo Carvalho de Melo 83af427bf5SArnaldo Carvalho de Melo for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) { 842e538c4aSArnaldo Carvalho de Melo prev = curr; 852e538c4aSArnaldo Carvalho de Melo curr = rb_entry(nd, struct symbol, rb_node); 86af427bf5SArnaldo Carvalho de Melo 87af427bf5SArnaldo Carvalho de Melo if (prev->end == prev->start) 88af427bf5SArnaldo Carvalho de Melo prev->end = curr->start - 1; 89af427bf5SArnaldo Carvalho de Melo } 90af427bf5SArnaldo Carvalho de Melo 912e538c4aSArnaldo Carvalho de Melo /* Last entry */ 922e538c4aSArnaldo Carvalho de Melo if (curr->end == curr->start) 932e538c4aSArnaldo Carvalho de Melo curr->end = roundup(curr->start, 4096); 942e538c4aSArnaldo Carvalho de Melo } 952e538c4aSArnaldo Carvalho de Melo 969958e1f0SArnaldo Carvalho de Melo static void __map_groups__fixup_end(struct map_groups *self, enum map_type type) 97af427bf5SArnaldo Carvalho de Melo { 98af427bf5SArnaldo Carvalho de Melo struct map *prev, *curr; 9995011c60SArnaldo Carvalho de Melo struct rb_node *nd, *prevnd = rb_first(&self->maps[type]); 100af427bf5SArnaldo Carvalho de Melo 101af427bf5SArnaldo Carvalho de Melo if (prevnd == NULL) 102af427bf5SArnaldo Carvalho de Melo return; 103af427bf5SArnaldo Carvalho de Melo 104af427bf5SArnaldo Carvalho de Melo curr = rb_entry(prevnd, struct map, rb_node); 105af427bf5SArnaldo Carvalho de Melo 106af427bf5SArnaldo Carvalho de Melo for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) { 107af427bf5SArnaldo Carvalho de Melo prev = curr; 108af427bf5SArnaldo Carvalho de Melo curr = rb_entry(nd, struct map, rb_node); 109af427bf5SArnaldo Carvalho de Melo prev->end = curr->start - 1; 1102e538c4aSArnaldo Carvalho de Melo } 11190c83218SArnaldo Carvalho de Melo 11290c83218SArnaldo Carvalho de Melo /* 11390c83218SArnaldo Carvalho de Melo * We still haven't the actual symbols, so guess the 11490c83218SArnaldo Carvalho de Melo * last map final address. 11590c83218SArnaldo Carvalho de Melo */ 11690c83218SArnaldo Carvalho de Melo curr->end = ~0UL; 117af427bf5SArnaldo Carvalho de Melo } 118af427bf5SArnaldo Carvalho de Melo 1199958e1f0SArnaldo Carvalho de Melo static void map_groups__fixup_end(struct map_groups *self) 12023ea4a3fSArnaldo Carvalho de Melo { 12123ea4a3fSArnaldo Carvalho de Melo int i; 12223ea4a3fSArnaldo Carvalho de Melo for (i = 0; i < MAP__NR_TYPES; ++i) 1239958e1f0SArnaldo Carvalho de Melo __map_groups__fixup_end(self, i); 12423ea4a3fSArnaldo Carvalho de Melo } 12523ea4a3fSArnaldo Carvalho de Melo 12600a192b3SArnaldo Carvalho de Melo static struct symbol *symbol__new(u64 start, u64 len, const char *name) 12786470930SIngo Molnar { 12886470930SIngo Molnar size_t namelen = strlen(name) + 1; 12975be6cf4SArnaldo Carvalho de Melo struct symbol *self = zalloc(symbol_conf.priv_size + 13036479484SArnaldo Carvalho de Melo sizeof(*self) + namelen); 13136479484SArnaldo Carvalho de Melo if (self == NULL) 13286470930SIngo Molnar return NULL; 13386470930SIngo Molnar 13475be6cf4SArnaldo Carvalho de Melo if (symbol_conf.priv_size) 13575be6cf4SArnaldo Carvalho de Melo self = ((void *)self) + symbol_conf.priv_size; 13636479484SArnaldo Carvalho de Melo 13786470930SIngo Molnar self->start = start; 1386cfcc53eSMike Galbraith self->end = len ? start + len - 1 : start; 139e4204992SArnaldo Carvalho de Melo 14029a9f66dSArnaldo Carvalho de Melo pr_debug4("%s: %s %#Lx-%#Lx\n", __func__, name, start, self->end); 141e4204992SArnaldo Carvalho de Melo 14286470930SIngo Molnar memcpy(self->name, name, namelen); 14386470930SIngo Molnar 14486470930SIngo Molnar return self; 14586470930SIngo Molnar } 14686470930SIngo Molnar 147*628ada0cSArnaldo Carvalho de Melo void symbol__delete(struct symbol *self) 14886470930SIngo Molnar { 14975be6cf4SArnaldo Carvalho de Melo free(((void *)self) - symbol_conf.priv_size); 15086470930SIngo Molnar } 15186470930SIngo Molnar 15286470930SIngo Molnar static size_t symbol__fprintf(struct symbol *self, FILE *fp) 15386470930SIngo Molnar { 15486470930SIngo Molnar return fprintf(fp, " %llx-%llx %s\n", 15586470930SIngo Molnar self->start, self->end, self->name); 15686470930SIngo Molnar } 15786470930SIngo Molnar 158b7cece76SArnaldo Carvalho de Melo void dso__set_long_name(struct dso *self, char *name) 159cfc10d3bSArnaldo Carvalho de Melo { 160ef6ae724SArnaldo Carvalho de Melo if (name == NULL) 161ef6ae724SArnaldo Carvalho de Melo return; 162cfc10d3bSArnaldo Carvalho de Melo self->long_name = name; 163cfc10d3bSArnaldo Carvalho de Melo self->long_name_len = strlen(name); 164cfc10d3bSArnaldo Carvalho de Melo } 165cfc10d3bSArnaldo Carvalho de Melo 166cfc10d3bSArnaldo Carvalho de Melo static void dso__set_basename(struct dso *self) 167cfc10d3bSArnaldo Carvalho de Melo { 168cfc10d3bSArnaldo Carvalho de Melo self->short_name = basename(self->long_name); 169cfc10d3bSArnaldo Carvalho de Melo } 170cfc10d3bSArnaldo Carvalho de Melo 17100a192b3SArnaldo Carvalho de Melo struct dso *dso__new(const char *name) 17286470930SIngo Molnar { 173b7cece76SArnaldo Carvalho de Melo struct dso *self = zalloc(sizeof(*self) + strlen(name) + 1); 17486470930SIngo Molnar 17586470930SIngo Molnar if (self != NULL) { 1766a4694a4SArnaldo Carvalho de Melo int i; 17786470930SIngo Molnar strcpy(self->name, name); 178cfc10d3bSArnaldo Carvalho de Melo dso__set_long_name(self, self->name); 179439d473bSArnaldo Carvalho de Melo self->short_name = self->name; 1806a4694a4SArnaldo Carvalho de Melo for (i = 0; i < MAP__NR_TYPES; ++i) 18179406cd7SArnaldo Carvalho de Melo self->symbols[i] = self->symbol_names[i] = RB_ROOT; 18252d422deSArnaldo Carvalho de Melo self->slen_calculated = 0; 18394cb9e38SArnaldo Carvalho de Melo self->origin = DSO__ORIG_NOT_FOUND; 1848d06367fSArnaldo Carvalho de Melo self->loaded = 0; 18579406cd7SArnaldo Carvalho de Melo self->sorted_by_name = 0; 1868d06367fSArnaldo Carvalho de Melo self->has_build_id = 0; 18786470930SIngo Molnar } 18886470930SIngo Molnar 18986470930SIngo Molnar return self; 19086470930SIngo Molnar } 19186470930SIngo Molnar 192fcf1203aSArnaldo Carvalho de Melo static void symbols__delete(struct rb_root *self) 19386470930SIngo Molnar { 19486470930SIngo Molnar struct symbol *pos; 195fcf1203aSArnaldo Carvalho de Melo struct rb_node *next = rb_first(self); 19686470930SIngo Molnar 19786470930SIngo Molnar while (next) { 19886470930SIngo Molnar pos = rb_entry(next, struct symbol, rb_node); 19986470930SIngo Molnar next = rb_next(&pos->rb_node); 200fcf1203aSArnaldo Carvalho de Melo rb_erase(&pos->rb_node, self); 20100a192b3SArnaldo Carvalho de Melo symbol__delete(pos); 20286470930SIngo Molnar } 20386470930SIngo Molnar } 20486470930SIngo Molnar 20586470930SIngo Molnar void dso__delete(struct dso *self) 20686470930SIngo Molnar { 2076a4694a4SArnaldo Carvalho de Melo int i; 2086a4694a4SArnaldo Carvalho de Melo for (i = 0; i < MAP__NR_TYPES; ++i) 2096a4694a4SArnaldo Carvalho de Melo symbols__delete(&self->symbols[i]); 210439d473bSArnaldo Carvalho de Melo if (self->long_name != self->name) 211439d473bSArnaldo Carvalho de Melo free(self->long_name); 21286470930SIngo Molnar free(self); 21386470930SIngo Molnar } 21486470930SIngo Molnar 2158d06367fSArnaldo Carvalho de Melo void dso__set_build_id(struct dso *self, void *build_id) 2168d06367fSArnaldo Carvalho de Melo { 2178d06367fSArnaldo Carvalho de Melo memcpy(self->build_id, build_id, sizeof(self->build_id)); 2188d06367fSArnaldo Carvalho de Melo self->has_build_id = 1; 2198d06367fSArnaldo Carvalho de Melo } 2208d06367fSArnaldo Carvalho de Melo 221fcf1203aSArnaldo Carvalho de Melo static void symbols__insert(struct rb_root *self, struct symbol *sym) 22286470930SIngo Molnar { 223fcf1203aSArnaldo Carvalho de Melo struct rb_node **p = &self->rb_node; 22486470930SIngo Molnar struct rb_node *parent = NULL; 2259cffa8d5SPaul Mackerras const u64 ip = sym->start; 22686470930SIngo Molnar struct symbol *s; 22786470930SIngo Molnar 22886470930SIngo Molnar while (*p != NULL) { 22986470930SIngo Molnar parent = *p; 23086470930SIngo Molnar s = rb_entry(parent, struct symbol, rb_node); 23186470930SIngo Molnar if (ip < s->start) 23286470930SIngo Molnar p = &(*p)->rb_left; 23386470930SIngo Molnar else 23486470930SIngo Molnar p = &(*p)->rb_right; 23586470930SIngo Molnar } 23686470930SIngo Molnar rb_link_node(&sym->rb_node, parent, p); 237fcf1203aSArnaldo Carvalho de Melo rb_insert_color(&sym->rb_node, self); 23886470930SIngo Molnar } 23986470930SIngo Molnar 240fcf1203aSArnaldo Carvalho de Melo static struct symbol *symbols__find(struct rb_root *self, u64 ip) 24186470930SIngo Molnar { 24286470930SIngo Molnar struct rb_node *n; 24386470930SIngo Molnar 24486470930SIngo Molnar if (self == NULL) 24586470930SIngo Molnar return NULL; 24686470930SIngo Molnar 247fcf1203aSArnaldo Carvalho de Melo n = self->rb_node; 24886470930SIngo Molnar 24986470930SIngo Molnar while (n) { 25086470930SIngo Molnar struct symbol *s = rb_entry(n, struct symbol, rb_node); 25186470930SIngo Molnar 25286470930SIngo Molnar if (ip < s->start) 25386470930SIngo Molnar n = n->rb_left; 25486470930SIngo Molnar else if (ip > s->end) 25586470930SIngo Molnar n = n->rb_right; 25686470930SIngo Molnar else 25786470930SIngo Molnar return s; 25886470930SIngo Molnar } 25986470930SIngo Molnar 26086470930SIngo Molnar return NULL; 26186470930SIngo Molnar } 26286470930SIngo Molnar 26379406cd7SArnaldo Carvalho de Melo struct symbol_name_rb_node { 26479406cd7SArnaldo Carvalho de Melo struct rb_node rb_node; 26579406cd7SArnaldo Carvalho de Melo struct symbol sym; 26679406cd7SArnaldo Carvalho de Melo }; 26779406cd7SArnaldo Carvalho de Melo 26879406cd7SArnaldo Carvalho de Melo static void symbols__insert_by_name(struct rb_root *self, struct symbol *sym) 26979406cd7SArnaldo Carvalho de Melo { 27079406cd7SArnaldo Carvalho de Melo struct rb_node **p = &self->rb_node; 27179406cd7SArnaldo Carvalho de Melo struct rb_node *parent = NULL; 27279406cd7SArnaldo Carvalho de Melo struct symbol_name_rb_node *symn = ((void *)sym) - sizeof(*parent), *s; 27379406cd7SArnaldo Carvalho de Melo 27479406cd7SArnaldo Carvalho de Melo while (*p != NULL) { 27579406cd7SArnaldo Carvalho de Melo parent = *p; 27679406cd7SArnaldo Carvalho de Melo s = rb_entry(parent, struct symbol_name_rb_node, rb_node); 27779406cd7SArnaldo Carvalho de Melo if (strcmp(sym->name, s->sym.name) < 0) 27879406cd7SArnaldo Carvalho de Melo p = &(*p)->rb_left; 27979406cd7SArnaldo Carvalho de Melo else 28079406cd7SArnaldo Carvalho de Melo p = &(*p)->rb_right; 28179406cd7SArnaldo Carvalho de Melo } 28279406cd7SArnaldo Carvalho de Melo rb_link_node(&symn->rb_node, parent, p); 28379406cd7SArnaldo Carvalho de Melo rb_insert_color(&symn->rb_node, self); 28479406cd7SArnaldo Carvalho de Melo } 28579406cd7SArnaldo Carvalho de Melo 28679406cd7SArnaldo Carvalho de Melo static void symbols__sort_by_name(struct rb_root *self, struct rb_root *source) 28779406cd7SArnaldo Carvalho de Melo { 28879406cd7SArnaldo Carvalho de Melo struct rb_node *nd; 28979406cd7SArnaldo Carvalho de Melo 29079406cd7SArnaldo Carvalho de Melo for (nd = rb_first(source); nd; nd = rb_next(nd)) { 29179406cd7SArnaldo Carvalho de Melo struct symbol *pos = rb_entry(nd, struct symbol, rb_node); 29279406cd7SArnaldo Carvalho de Melo symbols__insert_by_name(self, pos); 29379406cd7SArnaldo Carvalho de Melo } 29479406cd7SArnaldo Carvalho de Melo } 29579406cd7SArnaldo Carvalho de Melo 29679406cd7SArnaldo Carvalho de Melo static struct symbol *symbols__find_by_name(struct rb_root *self, const char *name) 29779406cd7SArnaldo Carvalho de Melo { 29879406cd7SArnaldo Carvalho de Melo struct rb_node *n; 29979406cd7SArnaldo Carvalho de Melo 30079406cd7SArnaldo Carvalho de Melo if (self == NULL) 30179406cd7SArnaldo Carvalho de Melo return NULL; 30279406cd7SArnaldo Carvalho de Melo 30379406cd7SArnaldo Carvalho de Melo n = self->rb_node; 30479406cd7SArnaldo Carvalho de Melo 30579406cd7SArnaldo Carvalho de Melo while (n) { 30679406cd7SArnaldo Carvalho de Melo struct symbol_name_rb_node *s; 30779406cd7SArnaldo Carvalho de Melo int cmp; 30879406cd7SArnaldo Carvalho de Melo 30979406cd7SArnaldo Carvalho de Melo s = rb_entry(n, struct symbol_name_rb_node, rb_node); 31079406cd7SArnaldo Carvalho de Melo cmp = strcmp(name, s->sym.name); 31179406cd7SArnaldo Carvalho de Melo 31279406cd7SArnaldo Carvalho de Melo if (cmp < 0) 31379406cd7SArnaldo Carvalho de Melo n = n->rb_left; 31479406cd7SArnaldo Carvalho de Melo else if (cmp > 0) 31579406cd7SArnaldo Carvalho de Melo n = n->rb_right; 31679406cd7SArnaldo Carvalho de Melo else 31779406cd7SArnaldo Carvalho de Melo return &s->sym; 31879406cd7SArnaldo Carvalho de Melo } 31979406cd7SArnaldo Carvalho de Melo 32079406cd7SArnaldo Carvalho de Melo return NULL; 32179406cd7SArnaldo Carvalho de Melo } 32279406cd7SArnaldo Carvalho de Melo 32379406cd7SArnaldo Carvalho de Melo struct symbol *dso__find_symbol(struct dso *self, 32479406cd7SArnaldo Carvalho de Melo enum map_type type, u64 addr) 325fcf1203aSArnaldo Carvalho de Melo { 3266a4694a4SArnaldo Carvalho de Melo return symbols__find(&self->symbols[type], addr); 327fcf1203aSArnaldo Carvalho de Melo } 328fcf1203aSArnaldo Carvalho de Melo 32979406cd7SArnaldo Carvalho de Melo struct symbol *dso__find_symbol_by_name(struct dso *self, enum map_type type, 33079406cd7SArnaldo Carvalho de Melo const char *name) 33179406cd7SArnaldo Carvalho de Melo { 33279406cd7SArnaldo Carvalho de Melo return symbols__find_by_name(&self->symbol_names[type], name); 33379406cd7SArnaldo Carvalho de Melo } 33479406cd7SArnaldo Carvalho de Melo 33579406cd7SArnaldo Carvalho de Melo void dso__sort_by_name(struct dso *self, enum map_type type) 33679406cd7SArnaldo Carvalho de Melo { 33779406cd7SArnaldo Carvalho de Melo dso__set_sorted_by_name(self, type); 33879406cd7SArnaldo Carvalho de Melo return symbols__sort_by_name(&self->symbol_names[type], 33979406cd7SArnaldo Carvalho de Melo &self->symbols[type]); 34079406cd7SArnaldo Carvalho de Melo } 34179406cd7SArnaldo Carvalho de Melo 342ef12a141SArnaldo Carvalho de Melo int build_id__sprintf(const u8 *self, int len, char *bf) 3438d06367fSArnaldo Carvalho de Melo { 3448d06367fSArnaldo Carvalho de Melo char *bid = bf; 345ef12a141SArnaldo Carvalho de Melo const u8 *raw = self; 3468d06367fSArnaldo Carvalho de Melo int i; 3478d06367fSArnaldo Carvalho de Melo 3488d06367fSArnaldo Carvalho de Melo for (i = 0; i < len; ++i) { 3498d06367fSArnaldo Carvalho de Melo sprintf(bid, "%02x", *raw); 3508d06367fSArnaldo Carvalho de Melo ++raw; 3518d06367fSArnaldo Carvalho de Melo bid += 2; 3528d06367fSArnaldo Carvalho de Melo } 3538d06367fSArnaldo Carvalho de Melo 3548d06367fSArnaldo Carvalho de Melo return raw - self; 3558d06367fSArnaldo Carvalho de Melo } 3568d06367fSArnaldo Carvalho de Melo 3579e03eb2dSArnaldo Carvalho de Melo size_t dso__fprintf_buildid(struct dso *self, FILE *fp) 35886470930SIngo Molnar { 3598d06367fSArnaldo Carvalho de Melo char sbuild_id[BUILD_ID_SIZE * 2 + 1]; 3608d06367fSArnaldo Carvalho de Melo 3618d06367fSArnaldo Carvalho de Melo build_id__sprintf(self->build_id, sizeof(self->build_id), sbuild_id); 3629e03eb2dSArnaldo Carvalho de Melo return fprintf(fp, "%s", sbuild_id); 3639e03eb2dSArnaldo Carvalho de Melo } 3649e03eb2dSArnaldo Carvalho de Melo 36595011c60SArnaldo Carvalho de Melo size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp) 3669e03eb2dSArnaldo Carvalho de Melo { 3679e03eb2dSArnaldo Carvalho de Melo struct rb_node *nd; 3689e03eb2dSArnaldo Carvalho de Melo size_t ret = fprintf(fp, "dso: %s (", self->short_name); 3699e03eb2dSArnaldo Carvalho de Melo 3703846df2eSArnaldo Carvalho de Melo if (self->short_name != self->long_name) 3713846df2eSArnaldo Carvalho de Melo ret += fprintf(fp, "%s, ", self->long_name); 3723846df2eSArnaldo Carvalho de Melo ret += fprintf(fp, "%s, %sloaded, ", map_type__name[type], 3733846df2eSArnaldo Carvalho de Melo self->loaded ? "" : "NOT "); 3749e03eb2dSArnaldo Carvalho de Melo ret += dso__fprintf_buildid(self, fp); 3756a4694a4SArnaldo Carvalho de Melo ret += fprintf(fp, ")\n"); 37695011c60SArnaldo Carvalho de Melo for (nd = rb_first(&self->symbols[type]); nd; nd = rb_next(nd)) { 37786470930SIngo Molnar struct symbol *pos = rb_entry(nd, struct symbol, rb_node); 37886470930SIngo Molnar ret += symbol__fprintf(pos, fp); 37986470930SIngo Molnar } 38086470930SIngo Molnar 38186470930SIngo Molnar return ret; 38286470930SIngo Molnar } 38386470930SIngo Molnar 3849e201442SArnaldo Carvalho de Melo int kallsyms__parse(const char *filename, void *arg, 3859e201442SArnaldo Carvalho de Melo int (*process_symbol)(void *arg, const char *name, 386682b335aSArnaldo Carvalho de Melo char type, u64 start)) 38786470930SIngo Molnar { 38886470930SIngo Molnar char *line = NULL; 38986470930SIngo Molnar size_t n; 390682b335aSArnaldo Carvalho de Melo int err = 0; 3919e201442SArnaldo Carvalho de Melo FILE *file = fopen(filename, "r"); 39286470930SIngo Molnar 39386470930SIngo Molnar if (file == NULL) 39486470930SIngo Molnar goto out_failure; 39586470930SIngo Molnar 39686470930SIngo Molnar while (!feof(file)) { 3979cffa8d5SPaul Mackerras u64 start; 39886470930SIngo Molnar int line_len, len; 39986470930SIngo Molnar char symbol_type; 4002e538c4aSArnaldo Carvalho de Melo char *symbol_name; 40186470930SIngo Molnar 40286470930SIngo Molnar line_len = getline(&line, &n, file); 40386470930SIngo Molnar if (line_len < 0) 40486470930SIngo Molnar break; 40586470930SIngo Molnar 40686470930SIngo Molnar if (!line) 40786470930SIngo Molnar goto out_failure; 40886470930SIngo Molnar 40986470930SIngo Molnar line[--line_len] = '\0'; /* \n */ 41086470930SIngo Molnar 41186470930SIngo Molnar len = hex2u64(line, &start); 41286470930SIngo Molnar 41386470930SIngo Molnar len++; 41486470930SIngo Molnar if (len + 2 >= line_len) 41586470930SIngo Molnar continue; 41686470930SIngo Molnar 41786470930SIngo Molnar symbol_type = toupper(line[len]); 418af427bf5SArnaldo Carvalho de Melo symbol_name = line + len + 2; 419682b335aSArnaldo Carvalho de Melo 420682b335aSArnaldo Carvalho de Melo err = process_symbol(arg, symbol_name, symbol_type, start); 421682b335aSArnaldo Carvalho de Melo if (err) 422682b335aSArnaldo Carvalho de Melo break; 423682b335aSArnaldo Carvalho de Melo } 424682b335aSArnaldo Carvalho de Melo 425682b335aSArnaldo Carvalho de Melo free(line); 426682b335aSArnaldo Carvalho de Melo fclose(file); 427682b335aSArnaldo Carvalho de Melo return err; 428682b335aSArnaldo Carvalho de Melo 429682b335aSArnaldo Carvalho de Melo out_failure: 430682b335aSArnaldo Carvalho de Melo return -1; 431682b335aSArnaldo Carvalho de Melo } 432682b335aSArnaldo Carvalho de Melo 433682b335aSArnaldo Carvalho de Melo struct process_kallsyms_args { 434682b335aSArnaldo Carvalho de Melo struct map *map; 435682b335aSArnaldo Carvalho de Melo struct dso *dso; 436682b335aSArnaldo Carvalho de Melo }; 437682b335aSArnaldo Carvalho de Melo 438682b335aSArnaldo Carvalho de Melo static int map__process_kallsym_symbol(void *arg, const char *name, 439682b335aSArnaldo Carvalho de Melo char type, u64 start) 440682b335aSArnaldo Carvalho de Melo { 441682b335aSArnaldo Carvalho de Melo struct symbol *sym; 442682b335aSArnaldo Carvalho de Melo struct process_kallsyms_args *a = arg; 443682b335aSArnaldo Carvalho de Melo struct rb_root *root = &a->dso->symbols[a->map->type]; 444682b335aSArnaldo Carvalho de Melo 445682b335aSArnaldo Carvalho de Melo if (!symbol_type__is_a(type, a->map->type)) 446682b335aSArnaldo Carvalho de Melo return 0; 447682b335aSArnaldo Carvalho de Melo 4482e538c4aSArnaldo Carvalho de Melo /* 4492e538c4aSArnaldo Carvalho de Melo * Will fix up the end later, when we have all symbols sorted. 4502e538c4aSArnaldo Carvalho de Melo */ 451682b335aSArnaldo Carvalho de Melo sym = symbol__new(start, 0, name); 452af427bf5SArnaldo Carvalho de Melo 4532e538c4aSArnaldo Carvalho de Melo if (sym == NULL) 454682b335aSArnaldo Carvalho de Melo return -ENOMEM; 45582164161SArnaldo Carvalho de Melo /* 45682164161SArnaldo Carvalho de Melo * We will pass the symbols to the filter later, in 4574e06255fSArnaldo Carvalho de Melo * map__split_kallsyms, when we have split the maps per module 45882164161SArnaldo Carvalho de Melo */ 4594e06255fSArnaldo Carvalho de Melo symbols__insert(root, sym); 460682b335aSArnaldo Carvalho de Melo return 0; 4612e538c4aSArnaldo Carvalho de Melo } 4622e538c4aSArnaldo Carvalho de Melo 463682b335aSArnaldo Carvalho de Melo /* 464682b335aSArnaldo Carvalho de Melo * Loads the function entries in /proc/kallsyms into kernel_map->dso, 465682b335aSArnaldo Carvalho de Melo * so that we can in the next step set the symbol ->end address and then 466682b335aSArnaldo Carvalho de Melo * call kernel_maps__split_kallsyms. 467682b335aSArnaldo Carvalho de Melo */ 4689e201442SArnaldo Carvalho de Melo static int dso__load_all_kallsyms(struct dso *self, const char *filename, 4699e201442SArnaldo Carvalho de Melo struct map *map) 470682b335aSArnaldo Carvalho de Melo { 471682b335aSArnaldo Carvalho de Melo struct process_kallsyms_args args = { .map = map, .dso = self, }; 4729e201442SArnaldo Carvalho de Melo return kallsyms__parse(filename, &args, map__process_kallsym_symbol); 4732e538c4aSArnaldo Carvalho de Melo } 4742e538c4aSArnaldo Carvalho de Melo 4752e538c4aSArnaldo Carvalho de Melo /* 4762e538c4aSArnaldo Carvalho de Melo * Split the symbols into maps, making sure there are no overlaps, i.e. the 4772e538c4aSArnaldo Carvalho de Melo * kernel range is broken in several maps, named [kernel].N, as we don't have 4782e538c4aSArnaldo Carvalho de Melo * the original ELF section names vmlinux have. 4792e538c4aSArnaldo Carvalho de Melo */ 4809958e1f0SArnaldo Carvalho de Melo static int dso__split_kallsyms(struct dso *self, struct map *map, 4819de89fe7SArnaldo Carvalho de Melo symbol_filter_t filter) 4822e538c4aSArnaldo Carvalho de Melo { 4839de89fe7SArnaldo Carvalho de Melo struct map_groups *kmaps = map__kmap(map)->kmaps; 4844e06255fSArnaldo Carvalho de Melo struct map *curr_map = map; 4852e538c4aSArnaldo Carvalho de Melo struct symbol *pos; 4862e538c4aSArnaldo Carvalho de Melo int count = 0; 4874e06255fSArnaldo Carvalho de Melo struct rb_root *root = &self->symbols[map->type]; 4884e06255fSArnaldo Carvalho de Melo struct rb_node *next = rb_first(root); 4892e538c4aSArnaldo Carvalho de Melo int kernel_range = 0; 4902e538c4aSArnaldo Carvalho de Melo 4912e538c4aSArnaldo Carvalho de Melo while (next) { 4922e538c4aSArnaldo Carvalho de Melo char *module; 4932e538c4aSArnaldo Carvalho de Melo 4942e538c4aSArnaldo Carvalho de Melo pos = rb_entry(next, struct symbol, rb_node); 4952e538c4aSArnaldo Carvalho de Melo next = rb_next(&pos->rb_node); 4962e538c4aSArnaldo Carvalho de Melo 4972e538c4aSArnaldo Carvalho de Melo module = strchr(pos->name, '\t'); 4982e538c4aSArnaldo Carvalho de Melo if (module) { 49975be6cf4SArnaldo Carvalho de Melo if (!symbol_conf.use_modules) 5001de8e245SArnaldo Carvalho de Melo goto discard_symbol; 5011de8e245SArnaldo Carvalho de Melo 5022e538c4aSArnaldo Carvalho de Melo *module++ = '\0'; 5032e538c4aSArnaldo Carvalho de Melo 504b7cece76SArnaldo Carvalho de Melo if (strcmp(curr_map->dso->short_name, module)) { 5059de89fe7SArnaldo Carvalho de Melo curr_map = map_groups__find_by_name(kmaps, map->type, module); 5064e06255fSArnaldo Carvalho de Melo if (curr_map == NULL) { 50795011c60SArnaldo Carvalho de Melo pr_debug("/proc/{kallsyms,modules} " 508b7cece76SArnaldo Carvalho de Melo "inconsistency while looking " 509b7cece76SArnaldo Carvalho de Melo "for \"%s\" module!\n", module); 510af427bf5SArnaldo Carvalho de Melo return -1; 511af427bf5SArnaldo Carvalho de Melo } 512b7cece76SArnaldo Carvalho de Melo 513b7cece76SArnaldo Carvalho de Melo if (curr_map->dso->loaded) 514b7cece76SArnaldo Carvalho de Melo goto discard_symbol; 515af427bf5SArnaldo Carvalho de Melo } 51686470930SIngo Molnar /* 5172e538c4aSArnaldo Carvalho de Melo * So that we look just like we get from .ko files, 5182e538c4aSArnaldo Carvalho de Melo * i.e. not prelinked, relative to map->start. 51986470930SIngo Molnar */ 5204e06255fSArnaldo Carvalho de Melo pos->start = curr_map->map_ip(curr_map, pos->start); 5214e06255fSArnaldo Carvalho de Melo pos->end = curr_map->map_ip(curr_map, pos->end); 5224e06255fSArnaldo Carvalho de Melo } else if (curr_map != map) { 5232e538c4aSArnaldo Carvalho de Melo char dso_name[PATH_MAX]; 5242e538c4aSArnaldo Carvalho de Melo struct dso *dso; 52586470930SIngo Molnar 5262e538c4aSArnaldo Carvalho de Melo snprintf(dso_name, sizeof(dso_name), "[kernel].%d", 5272e538c4aSArnaldo Carvalho de Melo kernel_range++); 52886470930SIngo Molnar 52900a192b3SArnaldo Carvalho de Melo dso = dso__new(dso_name); 5302e538c4aSArnaldo Carvalho de Melo if (dso == NULL) 5312e538c4aSArnaldo Carvalho de Melo return -1; 5322e538c4aSArnaldo Carvalho de Melo 5334e06255fSArnaldo Carvalho de Melo curr_map = map__new2(pos->start, dso, map->type); 53437fe5fcbSZhang, Yanmin if (curr_map == NULL) { 5352e538c4aSArnaldo Carvalho de Melo dso__delete(dso); 5362e538c4aSArnaldo Carvalho de Melo return -1; 5372e538c4aSArnaldo Carvalho de Melo } 5382e538c4aSArnaldo Carvalho de Melo 5394e06255fSArnaldo Carvalho de Melo curr_map->map_ip = curr_map->unmap_ip = identity__map_ip; 5409de89fe7SArnaldo Carvalho de Melo map_groups__insert(kmaps, curr_map); 5412e538c4aSArnaldo Carvalho de Melo ++kernel_range; 5422e538c4aSArnaldo Carvalho de Melo } 5432e538c4aSArnaldo Carvalho de Melo 5444e06255fSArnaldo Carvalho de Melo if (filter && filter(curr_map, pos)) { 5451de8e245SArnaldo Carvalho de Melo discard_symbol: rb_erase(&pos->rb_node, root); 54600a192b3SArnaldo Carvalho de Melo symbol__delete(pos); 5472e538c4aSArnaldo Carvalho de Melo } else { 5484e06255fSArnaldo Carvalho de Melo if (curr_map != map) { 5494e06255fSArnaldo Carvalho de Melo rb_erase(&pos->rb_node, root); 5504e06255fSArnaldo Carvalho de Melo symbols__insert(&curr_map->dso->symbols[curr_map->type], pos); 5512e538c4aSArnaldo Carvalho de Melo } 5529974f496SMike Galbraith count++; 5539974f496SMike Galbraith } 55486470930SIngo Molnar } 55586470930SIngo Molnar 5569974f496SMike Galbraith return count; 55786470930SIngo Molnar } 55886470930SIngo Molnar 5599de89fe7SArnaldo Carvalho de Melo int dso__load_kallsyms(struct dso *self, const char *filename, 5609de89fe7SArnaldo Carvalho de Melo struct map *map, symbol_filter_t filter) 5612e538c4aSArnaldo Carvalho de Melo { 5629e201442SArnaldo Carvalho de Melo if (dso__load_all_kallsyms(self, filename, map) < 0) 5632e538c4aSArnaldo Carvalho de Melo return -1; 5642e538c4aSArnaldo Carvalho de Melo 5654e06255fSArnaldo Carvalho de Melo symbols__fixup_end(&self->symbols[map->type]); 5664e06255fSArnaldo Carvalho de Melo self->origin = DSO__ORIG_KERNEL; 5672e538c4aSArnaldo Carvalho de Melo 5689de89fe7SArnaldo Carvalho de Melo return dso__split_kallsyms(self, map, filter); 569af427bf5SArnaldo Carvalho de Melo } 570af427bf5SArnaldo Carvalho de Melo 571439d473bSArnaldo Carvalho de Melo static int dso__load_perf_map(struct dso *self, struct map *map, 5726beba7adSArnaldo Carvalho de Melo symbol_filter_t filter) 57380d496beSPekka Enberg { 57480d496beSPekka Enberg char *line = NULL; 57580d496beSPekka Enberg size_t n; 57680d496beSPekka Enberg FILE *file; 57780d496beSPekka Enberg int nr_syms = 0; 57880d496beSPekka Enberg 579439d473bSArnaldo Carvalho de Melo file = fopen(self->long_name, "r"); 58080d496beSPekka Enberg if (file == NULL) 58180d496beSPekka Enberg goto out_failure; 58280d496beSPekka Enberg 58380d496beSPekka Enberg while (!feof(file)) { 5849cffa8d5SPaul Mackerras u64 start, size; 58580d496beSPekka Enberg struct symbol *sym; 58680d496beSPekka Enberg int line_len, len; 58780d496beSPekka Enberg 58880d496beSPekka Enberg line_len = getline(&line, &n, file); 58980d496beSPekka Enberg if (line_len < 0) 59080d496beSPekka Enberg break; 59180d496beSPekka Enberg 59280d496beSPekka Enberg if (!line) 59380d496beSPekka Enberg goto out_failure; 59480d496beSPekka Enberg 59580d496beSPekka Enberg line[--line_len] = '\0'; /* \n */ 59680d496beSPekka Enberg 59780d496beSPekka Enberg len = hex2u64(line, &start); 59880d496beSPekka Enberg 59980d496beSPekka Enberg len++; 60080d496beSPekka Enberg if (len + 2 >= line_len) 60180d496beSPekka Enberg continue; 60280d496beSPekka Enberg 60380d496beSPekka Enberg len += hex2u64(line + len, &size); 60480d496beSPekka Enberg 60580d496beSPekka Enberg len++; 60680d496beSPekka Enberg if (len + 2 >= line_len) 60780d496beSPekka Enberg continue; 60880d496beSPekka Enberg 60900a192b3SArnaldo Carvalho de Melo sym = symbol__new(start, size, line + len); 61080d496beSPekka Enberg 61180d496beSPekka Enberg if (sym == NULL) 61280d496beSPekka Enberg goto out_delete_line; 61380d496beSPekka Enberg 614439d473bSArnaldo Carvalho de Melo if (filter && filter(map, sym)) 61500a192b3SArnaldo Carvalho de Melo symbol__delete(sym); 61680d496beSPekka Enberg else { 6176a4694a4SArnaldo Carvalho de Melo symbols__insert(&self->symbols[map->type], sym); 61880d496beSPekka Enberg nr_syms++; 61980d496beSPekka Enberg } 62080d496beSPekka Enberg } 62180d496beSPekka Enberg 62280d496beSPekka Enberg free(line); 62380d496beSPekka Enberg fclose(file); 62480d496beSPekka Enberg 62580d496beSPekka Enberg return nr_syms; 62680d496beSPekka Enberg 62780d496beSPekka Enberg out_delete_line: 62880d496beSPekka Enberg free(line); 62980d496beSPekka Enberg out_failure: 63080d496beSPekka Enberg return -1; 63180d496beSPekka Enberg } 63280d496beSPekka Enberg 63386470930SIngo Molnar /** 63486470930SIngo Molnar * elf_symtab__for_each_symbol - iterate thru all the symbols 63586470930SIngo Molnar * 63686470930SIngo Molnar * @self: struct elf_symtab instance to iterate 63783a0944fSIngo Molnar * @idx: uint32_t idx 63886470930SIngo Molnar * @sym: GElf_Sym iterator 63986470930SIngo Molnar */ 64083a0944fSIngo Molnar #define elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) \ 64183a0944fSIngo Molnar for (idx = 0, gelf_getsym(syms, idx, &sym);\ 64283a0944fSIngo Molnar idx < nr_syms; \ 64383a0944fSIngo Molnar idx++, gelf_getsym(syms, idx, &sym)) 64486470930SIngo Molnar 64586470930SIngo Molnar static inline uint8_t elf_sym__type(const GElf_Sym *sym) 64686470930SIngo Molnar { 64786470930SIngo Molnar return GELF_ST_TYPE(sym->st_info); 64886470930SIngo Molnar } 64986470930SIngo Molnar 65086470930SIngo Molnar static inline int elf_sym__is_function(const GElf_Sym *sym) 65186470930SIngo Molnar { 65286470930SIngo Molnar return elf_sym__type(sym) == STT_FUNC && 65386470930SIngo Molnar sym->st_name != 0 && 65481833130SArnaldo Carvalho de Melo sym->st_shndx != SHN_UNDEF; 65586470930SIngo Molnar } 65686470930SIngo Molnar 657f1dfa0b1SArnaldo Carvalho de Melo static inline bool elf_sym__is_object(const GElf_Sym *sym) 658f1dfa0b1SArnaldo Carvalho de Melo { 659f1dfa0b1SArnaldo Carvalho de Melo return elf_sym__type(sym) == STT_OBJECT && 660f1dfa0b1SArnaldo Carvalho de Melo sym->st_name != 0 && 661f1dfa0b1SArnaldo Carvalho de Melo sym->st_shndx != SHN_UNDEF; 662f1dfa0b1SArnaldo Carvalho de Melo } 663f1dfa0b1SArnaldo Carvalho de Melo 6646cfcc53eSMike Galbraith static inline int elf_sym__is_label(const GElf_Sym *sym) 6656cfcc53eSMike Galbraith { 6666cfcc53eSMike Galbraith return elf_sym__type(sym) == STT_NOTYPE && 6676cfcc53eSMike Galbraith sym->st_name != 0 && 6686cfcc53eSMike Galbraith sym->st_shndx != SHN_UNDEF && 6696cfcc53eSMike Galbraith sym->st_shndx != SHN_ABS; 6706cfcc53eSMike Galbraith } 6716cfcc53eSMike Galbraith 6726cfcc53eSMike Galbraith static inline const char *elf_sec__name(const GElf_Shdr *shdr, 6736cfcc53eSMike Galbraith const Elf_Data *secstrs) 6746cfcc53eSMike Galbraith { 6756cfcc53eSMike Galbraith return secstrs->d_buf + shdr->sh_name; 6766cfcc53eSMike Galbraith } 6776cfcc53eSMike Galbraith 6786cfcc53eSMike Galbraith static inline int elf_sec__is_text(const GElf_Shdr *shdr, 6796cfcc53eSMike Galbraith const Elf_Data *secstrs) 6806cfcc53eSMike Galbraith { 6816cfcc53eSMike Galbraith return strstr(elf_sec__name(shdr, secstrs), "text") != NULL; 6826cfcc53eSMike Galbraith } 6836cfcc53eSMike Galbraith 684f1dfa0b1SArnaldo Carvalho de Melo static inline bool elf_sec__is_data(const GElf_Shdr *shdr, 685f1dfa0b1SArnaldo Carvalho de Melo const Elf_Data *secstrs) 686f1dfa0b1SArnaldo Carvalho de Melo { 687f1dfa0b1SArnaldo Carvalho de Melo return strstr(elf_sec__name(shdr, secstrs), "data") != NULL; 688f1dfa0b1SArnaldo Carvalho de Melo } 689f1dfa0b1SArnaldo Carvalho de Melo 69086470930SIngo Molnar static inline const char *elf_sym__name(const GElf_Sym *sym, 69186470930SIngo Molnar const Elf_Data *symstrs) 69286470930SIngo Molnar { 69386470930SIngo Molnar return symstrs->d_buf + sym->st_name; 69486470930SIngo Molnar } 69586470930SIngo Molnar 69686470930SIngo Molnar static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, 69786470930SIngo Molnar GElf_Shdr *shp, const char *name, 69883a0944fSIngo Molnar size_t *idx) 69986470930SIngo Molnar { 70086470930SIngo Molnar Elf_Scn *sec = NULL; 70186470930SIngo Molnar size_t cnt = 1; 70286470930SIngo Molnar 70386470930SIngo Molnar while ((sec = elf_nextscn(elf, sec)) != NULL) { 70486470930SIngo Molnar char *str; 70586470930SIngo Molnar 70686470930SIngo Molnar gelf_getshdr(sec, shp); 70786470930SIngo Molnar str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name); 70886470930SIngo Molnar if (!strcmp(name, str)) { 70983a0944fSIngo Molnar if (idx) 71083a0944fSIngo Molnar *idx = cnt; 71186470930SIngo Molnar break; 71286470930SIngo Molnar } 71386470930SIngo Molnar ++cnt; 71486470930SIngo Molnar } 71586470930SIngo Molnar 71686470930SIngo Molnar return sec; 71786470930SIngo Molnar } 71886470930SIngo Molnar 71986470930SIngo Molnar #define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \ 72086470930SIngo Molnar for (idx = 0, pos = gelf_getrel(reldata, 0, &pos_mem); \ 72186470930SIngo Molnar idx < nr_entries; \ 72286470930SIngo Molnar ++idx, pos = gelf_getrel(reldata, idx, &pos_mem)) 72386470930SIngo Molnar 72486470930SIngo Molnar #define elf_section__for_each_rela(reldata, pos, pos_mem, idx, nr_entries) \ 72586470930SIngo Molnar for (idx = 0, pos = gelf_getrela(reldata, 0, &pos_mem); \ 72686470930SIngo Molnar idx < nr_entries; \ 72786470930SIngo Molnar ++idx, pos = gelf_getrela(reldata, idx, &pos_mem)) 72886470930SIngo Molnar 729a25e46c4SArnaldo Carvalho de Melo /* 730a25e46c4SArnaldo Carvalho de Melo * We need to check if we have a .dynsym, so that we can handle the 731a25e46c4SArnaldo Carvalho de Melo * .plt, synthesizing its symbols, that aren't on the symtabs (be it 732a25e46c4SArnaldo Carvalho de Melo * .dynsym or .symtab). 733a25e46c4SArnaldo Carvalho de Melo * And always look at the original dso, not at debuginfo packages, that 734a25e46c4SArnaldo Carvalho de Melo * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS). 735a25e46c4SArnaldo Carvalho de Melo */ 73682164161SArnaldo Carvalho de Melo static int dso__synthesize_plt_symbols(struct dso *self, struct map *map, 73782164161SArnaldo Carvalho de Melo symbol_filter_t filter) 73886470930SIngo Molnar { 73986470930SIngo Molnar uint32_t nr_rel_entries, idx; 74086470930SIngo Molnar GElf_Sym sym; 7419cffa8d5SPaul Mackerras u64 plt_offset; 74286470930SIngo Molnar GElf_Shdr shdr_plt; 74386470930SIngo Molnar struct symbol *f; 744a25e46c4SArnaldo Carvalho de Melo GElf_Shdr shdr_rel_plt, shdr_dynsym; 74586470930SIngo Molnar Elf_Data *reldata, *syms, *symstrs; 746a25e46c4SArnaldo Carvalho de Melo Elf_Scn *scn_plt_rel, *scn_symstrs, *scn_dynsym; 747a25e46c4SArnaldo Carvalho de Melo size_t dynsym_idx; 748a25e46c4SArnaldo Carvalho de Melo GElf_Ehdr ehdr; 74986470930SIngo Molnar char sympltname[1024]; 750a25e46c4SArnaldo Carvalho de Melo Elf *elf; 751a25e46c4SArnaldo Carvalho de Melo int nr = 0, symidx, fd, err = 0; 75286470930SIngo Molnar 753439d473bSArnaldo Carvalho de Melo fd = open(self->long_name, O_RDONLY); 754a25e46c4SArnaldo Carvalho de Melo if (fd < 0) 755a25e46c4SArnaldo Carvalho de Melo goto out; 756a25e46c4SArnaldo Carvalho de Melo 75784087126SMarti Raudsepp elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 758a25e46c4SArnaldo Carvalho de Melo if (elf == NULL) 759a25e46c4SArnaldo Carvalho de Melo goto out_close; 760a25e46c4SArnaldo Carvalho de Melo 761a25e46c4SArnaldo Carvalho de Melo if (gelf_getehdr(elf, &ehdr) == NULL) 762a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 763a25e46c4SArnaldo Carvalho de Melo 764a25e46c4SArnaldo Carvalho de Melo scn_dynsym = elf_section_by_name(elf, &ehdr, &shdr_dynsym, 765a25e46c4SArnaldo Carvalho de Melo ".dynsym", &dynsym_idx); 766a25e46c4SArnaldo Carvalho de Melo if (scn_dynsym == NULL) 767a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 768a25e46c4SArnaldo Carvalho de Melo 769a25e46c4SArnaldo Carvalho de Melo scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt, 77086470930SIngo Molnar ".rela.plt", NULL); 77186470930SIngo Molnar if (scn_plt_rel == NULL) { 772a25e46c4SArnaldo Carvalho de Melo scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt, 77386470930SIngo Molnar ".rel.plt", NULL); 77486470930SIngo Molnar if (scn_plt_rel == NULL) 775a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 77686470930SIngo Molnar } 77786470930SIngo Molnar 778a25e46c4SArnaldo Carvalho de Melo err = -1; 77986470930SIngo Molnar 780a25e46c4SArnaldo Carvalho de Melo if (shdr_rel_plt.sh_link != dynsym_idx) 781a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 782a25e46c4SArnaldo Carvalho de Melo 783a25e46c4SArnaldo Carvalho de Melo if (elf_section_by_name(elf, &ehdr, &shdr_plt, ".plt", NULL) == NULL) 784a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 78586470930SIngo Molnar 78686470930SIngo Molnar /* 78783a0944fSIngo Molnar * Fetch the relocation section to find the idxes to the GOT 78886470930SIngo Molnar * and the symbols in the .dynsym they refer to. 78986470930SIngo Molnar */ 79086470930SIngo Molnar reldata = elf_getdata(scn_plt_rel, NULL); 79186470930SIngo Molnar if (reldata == NULL) 792a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 79386470930SIngo Molnar 79486470930SIngo Molnar syms = elf_getdata(scn_dynsym, NULL); 79586470930SIngo Molnar if (syms == NULL) 796a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 79786470930SIngo Molnar 798a25e46c4SArnaldo Carvalho de Melo scn_symstrs = elf_getscn(elf, shdr_dynsym.sh_link); 79986470930SIngo Molnar if (scn_symstrs == NULL) 800a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 80186470930SIngo Molnar 80286470930SIngo Molnar symstrs = elf_getdata(scn_symstrs, NULL); 80386470930SIngo Molnar if (symstrs == NULL) 804a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 80586470930SIngo Molnar 80686470930SIngo Molnar nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize; 80786470930SIngo Molnar plt_offset = shdr_plt.sh_offset; 80886470930SIngo Molnar 80986470930SIngo Molnar if (shdr_rel_plt.sh_type == SHT_RELA) { 81086470930SIngo Molnar GElf_Rela pos_mem, *pos; 81186470930SIngo Molnar 81286470930SIngo Molnar elf_section__for_each_rela(reldata, pos, pos_mem, idx, 81386470930SIngo Molnar nr_rel_entries) { 81486470930SIngo Molnar symidx = GELF_R_SYM(pos->r_info); 81586470930SIngo Molnar plt_offset += shdr_plt.sh_entsize; 81686470930SIngo Molnar gelf_getsym(syms, symidx, &sym); 81786470930SIngo Molnar snprintf(sympltname, sizeof(sympltname), 81886470930SIngo Molnar "%s@plt", elf_sym__name(&sym, symstrs)); 81986470930SIngo Molnar 82086470930SIngo Molnar f = symbol__new(plt_offset, shdr_plt.sh_entsize, 82100a192b3SArnaldo Carvalho de Melo sympltname); 82286470930SIngo Molnar if (!f) 823a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 82486470930SIngo Molnar 82582164161SArnaldo Carvalho de Melo if (filter && filter(map, f)) 82682164161SArnaldo Carvalho de Melo symbol__delete(f); 82782164161SArnaldo Carvalho de Melo else { 8286a4694a4SArnaldo Carvalho de Melo symbols__insert(&self->symbols[map->type], f); 82986470930SIngo Molnar ++nr; 83086470930SIngo Molnar } 83182164161SArnaldo Carvalho de Melo } 83286470930SIngo Molnar } else if (shdr_rel_plt.sh_type == SHT_REL) { 83386470930SIngo Molnar GElf_Rel pos_mem, *pos; 83486470930SIngo Molnar elf_section__for_each_rel(reldata, pos, pos_mem, idx, 83586470930SIngo Molnar nr_rel_entries) { 83686470930SIngo Molnar symidx = GELF_R_SYM(pos->r_info); 83786470930SIngo Molnar plt_offset += shdr_plt.sh_entsize; 83886470930SIngo Molnar gelf_getsym(syms, symidx, &sym); 83986470930SIngo Molnar snprintf(sympltname, sizeof(sympltname), 84086470930SIngo Molnar "%s@plt", elf_sym__name(&sym, symstrs)); 84186470930SIngo Molnar 84286470930SIngo Molnar f = symbol__new(plt_offset, shdr_plt.sh_entsize, 84300a192b3SArnaldo Carvalho de Melo sympltname); 84486470930SIngo Molnar if (!f) 845a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 84686470930SIngo Molnar 84782164161SArnaldo Carvalho de Melo if (filter && filter(map, f)) 84882164161SArnaldo Carvalho de Melo symbol__delete(f); 84982164161SArnaldo Carvalho de Melo else { 8506a4694a4SArnaldo Carvalho de Melo symbols__insert(&self->symbols[map->type], f); 85186470930SIngo Molnar ++nr; 85286470930SIngo Molnar } 85386470930SIngo Molnar } 85482164161SArnaldo Carvalho de Melo } 85586470930SIngo Molnar 856a25e46c4SArnaldo Carvalho de Melo err = 0; 857a25e46c4SArnaldo Carvalho de Melo out_elf_end: 858a25e46c4SArnaldo Carvalho de Melo elf_end(elf); 859a25e46c4SArnaldo Carvalho de Melo out_close: 860a25e46c4SArnaldo Carvalho de Melo close(fd); 861a25e46c4SArnaldo Carvalho de Melo 862a25e46c4SArnaldo Carvalho de Melo if (err == 0) 86386470930SIngo Molnar return nr; 864a25e46c4SArnaldo Carvalho de Melo out: 8656beba7adSArnaldo Carvalho de Melo pr_warning("%s: problems reading %s PLT info.\n", 866439d473bSArnaldo Carvalho de Melo __func__, self->long_name); 867a25e46c4SArnaldo Carvalho de Melo return 0; 86886470930SIngo Molnar } 86986470930SIngo Molnar 870d45868d3SArnaldo Carvalho de Melo static bool elf_sym__is_a(GElf_Sym *self, enum map_type type) 871d45868d3SArnaldo Carvalho de Melo { 872d45868d3SArnaldo Carvalho de Melo switch (type) { 873d45868d3SArnaldo Carvalho de Melo case MAP__FUNCTION: 874d45868d3SArnaldo Carvalho de Melo return elf_sym__is_function(self); 875f1dfa0b1SArnaldo Carvalho de Melo case MAP__VARIABLE: 876f1dfa0b1SArnaldo Carvalho de Melo return elf_sym__is_object(self); 877d45868d3SArnaldo Carvalho de Melo default: 878d45868d3SArnaldo Carvalho de Melo return false; 879d45868d3SArnaldo Carvalho de Melo } 880d45868d3SArnaldo Carvalho de Melo } 881d45868d3SArnaldo Carvalho de Melo 882d45868d3SArnaldo Carvalho de Melo static bool elf_sec__is_a(GElf_Shdr *self, Elf_Data *secstrs, enum map_type type) 883d45868d3SArnaldo Carvalho de Melo { 884d45868d3SArnaldo Carvalho de Melo switch (type) { 885d45868d3SArnaldo Carvalho de Melo case MAP__FUNCTION: 886d45868d3SArnaldo Carvalho de Melo return elf_sec__is_text(self, secstrs); 887f1dfa0b1SArnaldo Carvalho de Melo case MAP__VARIABLE: 888f1dfa0b1SArnaldo Carvalho de Melo return elf_sec__is_data(self, secstrs); 889d45868d3SArnaldo Carvalho de Melo default: 890d45868d3SArnaldo Carvalho de Melo return false; 891d45868d3SArnaldo Carvalho de Melo } 892d45868d3SArnaldo Carvalho de Melo } 893d45868d3SArnaldo Carvalho de Melo 8949de89fe7SArnaldo Carvalho de Melo static int dso__load_sym(struct dso *self, struct map *map, const char *name, 8959de89fe7SArnaldo Carvalho de Melo int fd, symbol_filter_t filter, int kmodule) 89686470930SIngo Molnar { 8979de89fe7SArnaldo Carvalho de Melo struct kmap *kmap = self->kernel ? map__kmap(map) : NULL; 8982e538c4aSArnaldo Carvalho de Melo struct map *curr_map = map; 8992e538c4aSArnaldo Carvalho de Melo struct dso *curr_dso = self; 9002e538c4aSArnaldo Carvalho de Melo size_t dso_name_len = strlen(self->short_name); 9016cfcc53eSMike Galbraith Elf_Data *symstrs, *secstrs; 90286470930SIngo Molnar uint32_t nr_syms; 90386470930SIngo Molnar int err = -1; 90483a0944fSIngo Molnar uint32_t idx; 90586470930SIngo Molnar GElf_Ehdr ehdr; 90686470930SIngo Molnar GElf_Shdr shdr; 90786470930SIngo Molnar Elf_Data *syms; 90886470930SIngo Molnar GElf_Sym sym; 909a25e46c4SArnaldo Carvalho de Melo Elf_Scn *sec, *sec_strndx; 91086470930SIngo Molnar Elf *elf; 911439d473bSArnaldo Carvalho de Melo int nr = 0; 91286470930SIngo Molnar 91384087126SMarti Raudsepp elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 91486470930SIngo Molnar if (elf == NULL) { 9156beba7adSArnaldo Carvalho de Melo pr_err("%s: cannot read %s ELF file.\n", __func__, name); 91686470930SIngo Molnar goto out_close; 91786470930SIngo Molnar } 91886470930SIngo Molnar 91986470930SIngo Molnar if (gelf_getehdr(elf, &ehdr) == NULL) { 9206beba7adSArnaldo Carvalho de Melo pr_err("%s: cannot get elf header.\n", __func__); 92186470930SIngo Molnar goto out_elf_end; 92286470930SIngo Molnar } 92386470930SIngo Molnar 92486470930SIngo Molnar sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL); 92586470930SIngo Molnar if (sec == NULL) { 926a25e46c4SArnaldo Carvalho de Melo sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL); 927a25e46c4SArnaldo Carvalho de Melo if (sec == NULL) 92886470930SIngo Molnar goto out_elf_end; 92986470930SIngo Molnar } 93086470930SIngo Molnar 93186470930SIngo Molnar syms = elf_getdata(sec, NULL); 93286470930SIngo Molnar if (syms == NULL) 93386470930SIngo Molnar goto out_elf_end; 93486470930SIngo Molnar 93586470930SIngo Molnar sec = elf_getscn(elf, shdr.sh_link); 93686470930SIngo Molnar if (sec == NULL) 93786470930SIngo Molnar goto out_elf_end; 93886470930SIngo Molnar 93986470930SIngo Molnar symstrs = elf_getdata(sec, NULL); 94086470930SIngo Molnar if (symstrs == NULL) 94186470930SIngo Molnar goto out_elf_end; 94286470930SIngo Molnar 9436cfcc53eSMike Galbraith sec_strndx = elf_getscn(elf, ehdr.e_shstrndx); 9446cfcc53eSMike Galbraith if (sec_strndx == NULL) 9456cfcc53eSMike Galbraith goto out_elf_end; 9466cfcc53eSMike Galbraith 9476cfcc53eSMike Galbraith secstrs = elf_getdata(sec_strndx, NULL); 9489b30a26bSStoyan Gaydarov if (secstrs == NULL) 9496cfcc53eSMike Galbraith goto out_elf_end; 9506cfcc53eSMike Galbraith 95186470930SIngo Molnar nr_syms = shdr.sh_size / shdr.sh_entsize; 95286470930SIngo Molnar 953e9fbc9dcSArjan van de Ven memset(&sym, 0, sizeof(sym)); 9549de89fe7SArnaldo Carvalho de Melo if (!self->kernel) { 95530d7a77dSArnaldo Carvalho de Melo self->adjust_symbols = (ehdr.e_type == ET_EXEC || 95630d7a77dSArnaldo Carvalho de Melo elf_section_by_name(elf, &ehdr, &shdr, 957f5812a7aSArnaldo Carvalho de Melo ".gnu.prelink_undo", 95830d7a77dSArnaldo Carvalho de Melo NULL) != NULL); 959d20ff6bdSMike Galbraith } else self->adjust_symbols = 0; 960d20ff6bdSMike Galbraith 96183a0944fSIngo Molnar elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) { 96286470930SIngo Molnar struct symbol *f; 96356b03f3cSArnaldo Carvalho de Melo const char *elf_name = elf_sym__name(&sym, symstrs); 9642e538c4aSArnaldo Carvalho de Melo char *demangled = NULL; 9656cfcc53eSMike Galbraith int is_label = elf_sym__is_label(&sym); 9666cfcc53eSMike Galbraith const char *section_name; 96786470930SIngo Molnar 9689de89fe7SArnaldo Carvalho de Melo if (kmap && kmap->ref_reloc_sym && kmap->ref_reloc_sym->name && 9699de89fe7SArnaldo Carvalho de Melo strcmp(elf_name, kmap->ref_reloc_sym->name) == 0) 9709de89fe7SArnaldo Carvalho de Melo kmap->ref_reloc_sym->unrelocated_addr = sym.st_value; 97156b03f3cSArnaldo Carvalho de Melo 972d45868d3SArnaldo Carvalho de Melo if (!is_label && !elf_sym__is_a(&sym, map->type)) 97386470930SIngo Molnar continue; 97486470930SIngo Molnar 97586470930SIngo Molnar sec = elf_getscn(elf, sym.st_shndx); 97686470930SIngo Molnar if (!sec) 97786470930SIngo Molnar goto out_elf_end; 97886470930SIngo Molnar 97986470930SIngo Molnar gelf_getshdr(sec, &shdr); 9806cfcc53eSMike Galbraith 981d45868d3SArnaldo Carvalho de Melo if (is_label && !elf_sec__is_a(&shdr, secstrs, map->type)) 9826cfcc53eSMike Galbraith continue; 9836cfcc53eSMike Galbraith 9846cfcc53eSMike Galbraith section_name = elf_sec__name(&shdr, secstrs); 98586470930SIngo Molnar 9869de89fe7SArnaldo Carvalho de Melo if (self->kernel || kmodule) { 9872e538c4aSArnaldo Carvalho de Melo char dso_name[PATH_MAX]; 9882e538c4aSArnaldo Carvalho de Melo 9892e538c4aSArnaldo Carvalho de Melo if (strcmp(section_name, 9902e538c4aSArnaldo Carvalho de Melo curr_dso->short_name + dso_name_len) == 0) 9912e538c4aSArnaldo Carvalho de Melo goto new_symbol; 9922e538c4aSArnaldo Carvalho de Melo 9932e538c4aSArnaldo Carvalho de Melo if (strcmp(section_name, ".text") == 0) { 9942e538c4aSArnaldo Carvalho de Melo curr_map = map; 9952e538c4aSArnaldo Carvalho de Melo curr_dso = self; 9962e538c4aSArnaldo Carvalho de Melo goto new_symbol; 997af427bf5SArnaldo Carvalho de Melo } 998af427bf5SArnaldo Carvalho de Melo 9992e538c4aSArnaldo Carvalho de Melo snprintf(dso_name, sizeof(dso_name), 10002e538c4aSArnaldo Carvalho de Melo "%s%s", self->short_name, section_name); 10012e538c4aSArnaldo Carvalho de Melo 10029de89fe7SArnaldo Carvalho de Melo curr_map = map_groups__find_by_name(kmap->kmaps, map->type, dso_name); 10032e538c4aSArnaldo Carvalho de Melo if (curr_map == NULL) { 10042e538c4aSArnaldo Carvalho de Melo u64 start = sym.st_value; 10052e538c4aSArnaldo Carvalho de Melo 10062e538c4aSArnaldo Carvalho de Melo if (kmodule) 10072e538c4aSArnaldo Carvalho de Melo start += map->start + shdr.sh_offset; 10082e538c4aSArnaldo Carvalho de Melo 100900a192b3SArnaldo Carvalho de Melo curr_dso = dso__new(dso_name); 10102e538c4aSArnaldo Carvalho de Melo if (curr_dso == NULL) 10112e538c4aSArnaldo Carvalho de Melo goto out_elf_end; 10123610583cSArnaldo Carvalho de Melo curr_map = map__new2(start, curr_dso, 10136275ce2dSArnaldo Carvalho de Melo map->type); 10142e538c4aSArnaldo Carvalho de Melo if (curr_map == NULL) { 10152e538c4aSArnaldo Carvalho de Melo dso__delete(curr_dso); 10162e538c4aSArnaldo Carvalho de Melo goto out_elf_end; 10172e538c4aSArnaldo Carvalho de Melo } 1018ed52ce2eSArnaldo Carvalho de Melo curr_map->map_ip = identity__map_ip; 1019ed52ce2eSArnaldo Carvalho de Melo curr_map->unmap_ip = identity__map_ip; 10202e538c4aSArnaldo Carvalho de Melo curr_dso->origin = DSO__ORIG_KERNEL; 10219de89fe7SArnaldo Carvalho de Melo map_groups__insert(kmap->kmaps, curr_map); 1022b0da954aSArnaldo Carvalho de Melo dsos__add(&dsos__kernel, curr_dso); 10236275ce2dSArnaldo Carvalho de Melo dso__set_loaded(curr_dso, map->type); 10242e538c4aSArnaldo Carvalho de Melo } else 10252e538c4aSArnaldo Carvalho de Melo curr_dso = curr_map->dso; 10262e538c4aSArnaldo Carvalho de Melo 10272e538c4aSArnaldo Carvalho de Melo goto new_symbol; 10282e538c4aSArnaldo Carvalho de Melo } 10292e538c4aSArnaldo Carvalho de Melo 10302e538c4aSArnaldo Carvalho de Melo if (curr_dso->adjust_symbols) { 103129a9f66dSArnaldo Carvalho de Melo pr_debug4("%s: adjusting symbol: st_value: %#Lx " 103229a9f66dSArnaldo Carvalho de Melo "sh_addr: %#Lx sh_offset: %#Lx\n", __func__, 103329a9f66dSArnaldo Carvalho de Melo (u64)sym.st_value, (u64)shdr.sh_addr, 103429a9f66dSArnaldo Carvalho de Melo (u64)shdr.sh_offset); 103586470930SIngo Molnar sym.st_value -= shdr.sh_addr - shdr.sh_offset; 1036af427bf5SArnaldo Carvalho de Melo } 103728ac909bSArnaldo Carvalho de Melo /* 103828ac909bSArnaldo Carvalho de Melo * We need to figure out if the object was created from C++ sources 103928ac909bSArnaldo Carvalho de Melo * DWARF DW_compile_unit has this, but we don't always have access 104028ac909bSArnaldo Carvalho de Melo * to it... 104128ac909bSArnaldo Carvalho de Melo */ 104283a0944fSIngo Molnar demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI); 104328ac909bSArnaldo Carvalho de Melo if (demangled != NULL) 104483a0944fSIngo Molnar elf_name = demangled; 10452e538c4aSArnaldo Carvalho de Melo new_symbol: 104600a192b3SArnaldo Carvalho de Melo f = symbol__new(sym.st_value, sym.st_size, elf_name); 104728ac909bSArnaldo Carvalho de Melo free(demangled); 104886470930SIngo Molnar if (!f) 104986470930SIngo Molnar goto out_elf_end; 105086470930SIngo Molnar 10512e538c4aSArnaldo Carvalho de Melo if (filter && filter(curr_map, f)) 105200a192b3SArnaldo Carvalho de Melo symbol__delete(f); 105386470930SIngo Molnar else { 10546a4694a4SArnaldo Carvalho de Melo symbols__insert(&curr_dso->symbols[curr_map->type], f); 105586470930SIngo Molnar nr++; 105686470930SIngo Molnar } 105786470930SIngo Molnar } 105886470930SIngo Molnar 10592e538c4aSArnaldo Carvalho de Melo /* 10602e538c4aSArnaldo Carvalho de Melo * For misannotated, zeroed, ASM function sizes. 10612e538c4aSArnaldo Carvalho de Melo */ 10626275ce2dSArnaldo Carvalho de Melo if (nr > 0) { 10636a4694a4SArnaldo Carvalho de Melo symbols__fixup_end(&self->symbols[map->type]); 10646275ce2dSArnaldo Carvalho de Melo if (kmap) { 10656275ce2dSArnaldo Carvalho de Melo /* 10666275ce2dSArnaldo Carvalho de Melo * We need to fixup this here too because we create new 10676275ce2dSArnaldo Carvalho de Melo * maps here, for things like vsyscall sections. 10686275ce2dSArnaldo Carvalho de Melo */ 10696275ce2dSArnaldo Carvalho de Melo __map_groups__fixup_end(kmap->kmaps, map->type); 10706275ce2dSArnaldo Carvalho de Melo } 10716275ce2dSArnaldo Carvalho de Melo } 107286470930SIngo Molnar err = nr; 107386470930SIngo Molnar out_elf_end: 107486470930SIngo Molnar elf_end(elf); 107586470930SIngo Molnar out_close: 107686470930SIngo Molnar return err; 107786470930SIngo Molnar } 107886470930SIngo Molnar 107978075caaSArnaldo Carvalho de Melo static bool dso__build_id_equal(const struct dso *self, u8 *build_id) 108078075caaSArnaldo Carvalho de Melo { 108178075caaSArnaldo Carvalho de Melo return memcmp(self->build_id, build_id, sizeof(self->build_id)) == 0; 108278075caaSArnaldo Carvalho de Melo } 108378075caaSArnaldo Carvalho de Melo 10846122e4e4SArnaldo Carvalho de Melo static bool __dsos__read_build_ids(struct list_head *head, bool with_hits) 108557f395a7SFrederic Weisbecker { 1086e30a3d12SArnaldo Carvalho de Melo bool have_build_id = false; 108757f395a7SFrederic Weisbecker struct dso *pos; 108857f395a7SFrederic Weisbecker 10896122e4e4SArnaldo Carvalho de Melo list_for_each_entry(pos, head, node) { 10906122e4e4SArnaldo Carvalho de Melo if (with_hits && !pos->hit) 10916122e4e4SArnaldo Carvalho de Melo continue; 1092e30a3d12SArnaldo Carvalho de Melo if (filename__read_build_id(pos->long_name, pos->build_id, 1093e30a3d12SArnaldo Carvalho de Melo sizeof(pos->build_id)) > 0) { 1094e30a3d12SArnaldo Carvalho de Melo have_build_id = true; 1095e30a3d12SArnaldo Carvalho de Melo pos->has_build_id = true; 109657f395a7SFrederic Weisbecker } 10976122e4e4SArnaldo Carvalho de Melo } 109857f395a7SFrederic Weisbecker 1099e30a3d12SArnaldo Carvalho de Melo return have_build_id; 110057f395a7SFrederic Weisbecker } 110157f395a7SFrederic Weisbecker 11026122e4e4SArnaldo Carvalho de Melo bool dsos__read_build_ids(bool with_hits) 1103b0da954aSArnaldo Carvalho de Melo { 11046122e4e4SArnaldo Carvalho de Melo bool kbuildids = __dsos__read_build_ids(&dsos__kernel, with_hits), 11056122e4e4SArnaldo Carvalho de Melo ubuildids = __dsos__read_build_ids(&dsos__user, with_hits); 11068b4825bfSArnaldo Carvalho de Melo return kbuildids || ubuildids; 1107b0da954aSArnaldo Carvalho de Melo } 1108b0da954aSArnaldo Carvalho de Melo 1109fd7a346eSArnaldo Carvalho de Melo /* 1110fd7a346eSArnaldo Carvalho de Melo * Align offset to 4 bytes as needed for note name and descriptor data. 1111fd7a346eSArnaldo Carvalho de Melo */ 1112fd7a346eSArnaldo Carvalho de Melo #define NOTE_ALIGN(n) (((n) + 3) & -4U) 1113fd7a346eSArnaldo Carvalho de Melo 11142643ce11SArnaldo Carvalho de Melo int filename__read_build_id(const char *filename, void *bf, size_t size) 11154d1e00a8SArnaldo Carvalho de Melo { 11162643ce11SArnaldo Carvalho de Melo int fd, err = -1; 11174d1e00a8SArnaldo Carvalho de Melo GElf_Ehdr ehdr; 11184d1e00a8SArnaldo Carvalho de Melo GElf_Shdr shdr; 1119fd7a346eSArnaldo Carvalho de Melo Elf_Data *data; 11204d1e00a8SArnaldo Carvalho de Melo Elf_Scn *sec; 1121e57cfcdaSPekka Enberg Elf_Kind ek; 1122fd7a346eSArnaldo Carvalho de Melo void *ptr; 11234d1e00a8SArnaldo Carvalho de Melo Elf *elf; 11244d1e00a8SArnaldo Carvalho de Melo 11252643ce11SArnaldo Carvalho de Melo if (size < BUILD_ID_SIZE) 11262643ce11SArnaldo Carvalho de Melo goto out; 11272643ce11SArnaldo Carvalho de Melo 11282643ce11SArnaldo Carvalho de Melo fd = open(filename, O_RDONLY); 11294d1e00a8SArnaldo Carvalho de Melo if (fd < 0) 11304d1e00a8SArnaldo Carvalho de Melo goto out; 11314d1e00a8SArnaldo Carvalho de Melo 113284087126SMarti Raudsepp elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 11334d1e00a8SArnaldo Carvalho de Melo if (elf == NULL) { 11348d06367fSArnaldo Carvalho de Melo pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename); 11354d1e00a8SArnaldo Carvalho de Melo goto out_close; 11364d1e00a8SArnaldo Carvalho de Melo } 11374d1e00a8SArnaldo Carvalho de Melo 1138e57cfcdaSPekka Enberg ek = elf_kind(elf); 1139e57cfcdaSPekka Enberg if (ek != ELF_K_ELF) 1140e57cfcdaSPekka Enberg goto out_elf_end; 1141e57cfcdaSPekka Enberg 11424d1e00a8SArnaldo Carvalho de Melo if (gelf_getehdr(elf, &ehdr) == NULL) { 11436beba7adSArnaldo Carvalho de Melo pr_err("%s: cannot get elf header.\n", __func__); 11444d1e00a8SArnaldo Carvalho de Melo goto out_elf_end; 11454d1e00a8SArnaldo Carvalho de Melo } 11464d1e00a8SArnaldo Carvalho de Melo 11472643ce11SArnaldo Carvalho de Melo sec = elf_section_by_name(elf, &ehdr, &shdr, 11482643ce11SArnaldo Carvalho de Melo ".note.gnu.build-id", NULL); 1149fd7a346eSArnaldo Carvalho de Melo if (sec == NULL) { 1150fd7a346eSArnaldo Carvalho de Melo sec = elf_section_by_name(elf, &ehdr, &shdr, 1151fd7a346eSArnaldo Carvalho de Melo ".notes", NULL); 11524d1e00a8SArnaldo Carvalho de Melo if (sec == NULL) 11534d1e00a8SArnaldo Carvalho de Melo goto out_elf_end; 1154fd7a346eSArnaldo Carvalho de Melo } 11554d1e00a8SArnaldo Carvalho de Melo 1156fd7a346eSArnaldo Carvalho de Melo data = elf_getdata(sec, NULL); 1157fd7a346eSArnaldo Carvalho de Melo if (data == NULL) 11584d1e00a8SArnaldo Carvalho de Melo goto out_elf_end; 1159fd7a346eSArnaldo Carvalho de Melo 1160fd7a346eSArnaldo Carvalho de Melo ptr = data->d_buf; 1161fd7a346eSArnaldo Carvalho de Melo while (ptr < (data->d_buf + data->d_size)) { 1162fd7a346eSArnaldo Carvalho de Melo GElf_Nhdr *nhdr = ptr; 1163fd7a346eSArnaldo Carvalho de Melo int namesz = NOTE_ALIGN(nhdr->n_namesz), 1164fd7a346eSArnaldo Carvalho de Melo descsz = NOTE_ALIGN(nhdr->n_descsz); 1165fd7a346eSArnaldo Carvalho de Melo const char *name; 1166fd7a346eSArnaldo Carvalho de Melo 1167fd7a346eSArnaldo Carvalho de Melo ptr += sizeof(*nhdr); 1168fd7a346eSArnaldo Carvalho de Melo name = ptr; 1169fd7a346eSArnaldo Carvalho de Melo ptr += namesz; 1170fd7a346eSArnaldo Carvalho de Melo if (nhdr->n_type == NT_GNU_BUILD_ID && 1171fd7a346eSArnaldo Carvalho de Melo nhdr->n_namesz == sizeof("GNU")) { 1172fd7a346eSArnaldo Carvalho de Melo if (memcmp(name, "GNU", sizeof("GNU")) == 0) { 1173fd7a346eSArnaldo Carvalho de Melo memcpy(bf, ptr, BUILD_ID_SIZE); 11742643ce11SArnaldo Carvalho de Melo err = BUILD_ID_SIZE; 1175fd7a346eSArnaldo Carvalho de Melo break; 1176fd7a346eSArnaldo Carvalho de Melo } 1177fd7a346eSArnaldo Carvalho de Melo } 1178fd7a346eSArnaldo Carvalho de Melo ptr += descsz; 1179fd7a346eSArnaldo Carvalho de Melo } 11802643ce11SArnaldo Carvalho de Melo out_elf_end: 11812643ce11SArnaldo Carvalho de Melo elf_end(elf); 11822643ce11SArnaldo Carvalho de Melo out_close: 11832643ce11SArnaldo Carvalho de Melo close(fd); 11842643ce11SArnaldo Carvalho de Melo out: 11852643ce11SArnaldo Carvalho de Melo return err; 11862643ce11SArnaldo Carvalho de Melo } 11872643ce11SArnaldo Carvalho de Melo 1188f1617b40SArnaldo Carvalho de Melo int sysfs__read_build_id(const char *filename, void *build_id, size_t size) 1189f1617b40SArnaldo Carvalho de Melo { 1190f1617b40SArnaldo Carvalho de Melo int fd, err = -1; 1191f1617b40SArnaldo Carvalho de Melo 1192f1617b40SArnaldo Carvalho de Melo if (size < BUILD_ID_SIZE) 1193f1617b40SArnaldo Carvalho de Melo goto out; 1194f1617b40SArnaldo Carvalho de Melo 1195f1617b40SArnaldo Carvalho de Melo fd = open(filename, O_RDONLY); 1196f1617b40SArnaldo Carvalho de Melo if (fd < 0) 1197f1617b40SArnaldo Carvalho de Melo goto out; 1198f1617b40SArnaldo Carvalho de Melo 1199f1617b40SArnaldo Carvalho de Melo while (1) { 1200f1617b40SArnaldo Carvalho de Melo char bf[BUFSIZ]; 1201f1617b40SArnaldo Carvalho de Melo GElf_Nhdr nhdr; 1202f1617b40SArnaldo Carvalho de Melo int namesz, descsz; 1203f1617b40SArnaldo Carvalho de Melo 1204f1617b40SArnaldo Carvalho de Melo if (read(fd, &nhdr, sizeof(nhdr)) != sizeof(nhdr)) 1205f1617b40SArnaldo Carvalho de Melo break; 1206f1617b40SArnaldo Carvalho de Melo 1207fd7a346eSArnaldo Carvalho de Melo namesz = NOTE_ALIGN(nhdr.n_namesz); 1208fd7a346eSArnaldo Carvalho de Melo descsz = NOTE_ALIGN(nhdr.n_descsz); 1209f1617b40SArnaldo Carvalho de Melo if (nhdr.n_type == NT_GNU_BUILD_ID && 1210f1617b40SArnaldo Carvalho de Melo nhdr.n_namesz == sizeof("GNU")) { 1211f1617b40SArnaldo Carvalho de Melo if (read(fd, bf, namesz) != namesz) 1212f1617b40SArnaldo Carvalho de Melo break; 1213f1617b40SArnaldo Carvalho de Melo if (memcmp(bf, "GNU", sizeof("GNU")) == 0) { 1214f1617b40SArnaldo Carvalho de Melo if (read(fd, build_id, 1215f1617b40SArnaldo Carvalho de Melo BUILD_ID_SIZE) == BUILD_ID_SIZE) { 1216f1617b40SArnaldo Carvalho de Melo err = 0; 1217f1617b40SArnaldo Carvalho de Melo break; 1218f1617b40SArnaldo Carvalho de Melo } 1219f1617b40SArnaldo Carvalho de Melo } else if (read(fd, bf, descsz) != descsz) 1220f1617b40SArnaldo Carvalho de Melo break; 1221f1617b40SArnaldo Carvalho de Melo } else { 1222f1617b40SArnaldo Carvalho de Melo int n = namesz + descsz; 1223f1617b40SArnaldo Carvalho de Melo if (read(fd, bf, n) != n) 1224f1617b40SArnaldo Carvalho de Melo break; 1225f1617b40SArnaldo Carvalho de Melo } 1226f1617b40SArnaldo Carvalho de Melo } 1227f1617b40SArnaldo Carvalho de Melo close(fd); 1228f1617b40SArnaldo Carvalho de Melo out: 1229f1617b40SArnaldo Carvalho de Melo return err; 1230f1617b40SArnaldo Carvalho de Melo } 1231f1617b40SArnaldo Carvalho de Melo 123294cb9e38SArnaldo Carvalho de Melo char dso__symtab_origin(const struct dso *self) 123394cb9e38SArnaldo Carvalho de Melo { 123494cb9e38SArnaldo Carvalho de Melo static const char origin[] = { 123594cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_KERNEL] = 'k', 123694cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_JAVA_JIT] = 'j', 12374cf40131SArnaldo Carvalho de Melo [DSO__ORIG_BUILD_ID_CACHE] = 'B', 123894cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_FEDORA] = 'f', 123994cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_UBUNTU] = 'u', 124094cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_BUILDID] = 'b', 124194cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_DSO] = 'd', 1242439d473bSArnaldo Carvalho de Melo [DSO__ORIG_KMODULE] = 'K', 124394cb9e38SArnaldo Carvalho de Melo }; 124494cb9e38SArnaldo Carvalho de Melo 124594cb9e38SArnaldo Carvalho de Melo if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND) 124694cb9e38SArnaldo Carvalho de Melo return '!'; 124794cb9e38SArnaldo Carvalho de Melo return origin[self->origin]; 124894cb9e38SArnaldo Carvalho de Melo } 124994cb9e38SArnaldo Carvalho de Melo 12509de89fe7SArnaldo Carvalho de Melo int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) 125186470930SIngo Molnar { 12524d1e00a8SArnaldo Carvalho de Melo int size = PATH_MAX; 1253c338aee8SArnaldo Carvalho de Melo char *name; 1254d3379ab9SArnaldo Carvalho de Melo u8 build_id[BUILD_ID_SIZE]; 12554cf40131SArnaldo Carvalho de Melo char build_id_hex[BUILD_ID_SIZE * 2 + 1]; 125686470930SIngo Molnar int ret = -1; 125786470930SIngo Molnar int fd; 125886470930SIngo Molnar 12593610583cSArnaldo Carvalho de Melo dso__set_loaded(self, map->type); 126066bd8424SArnaldo Carvalho de Melo 1261c338aee8SArnaldo Carvalho de Melo if (self->kernel) 12629de89fe7SArnaldo Carvalho de Melo return dso__load_kernel_sym(self, map, filter); 1263c338aee8SArnaldo Carvalho de Melo 1264c338aee8SArnaldo Carvalho de Melo name = malloc(size); 126586470930SIngo Molnar if (!name) 126686470930SIngo Molnar return -1; 126786470930SIngo Molnar 126830d7a77dSArnaldo Carvalho de Melo self->adjust_symbols = 0; 1269f5812a7aSArnaldo Carvalho de Melo 127094cb9e38SArnaldo Carvalho de Melo if (strncmp(self->name, "/tmp/perf-", 10) == 0) { 12716beba7adSArnaldo Carvalho de Melo ret = dso__load_perf_map(self, map, filter); 127294cb9e38SArnaldo Carvalho de Melo self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT : 127394cb9e38SArnaldo Carvalho de Melo DSO__ORIG_NOT_FOUND; 127494cb9e38SArnaldo Carvalho de Melo return ret; 127594cb9e38SArnaldo Carvalho de Melo } 127694cb9e38SArnaldo Carvalho de Melo 12774cf40131SArnaldo Carvalho de Melo self->origin = DSO__ORIG_BUILD_ID_CACHE; 127880d496beSPekka Enberg 12794cf40131SArnaldo Carvalho de Melo if (self->has_build_id) { 12804cf40131SArnaldo Carvalho de Melo build_id__sprintf(self->build_id, sizeof(self->build_id), 12814cf40131SArnaldo Carvalho de Melo build_id_hex); 12824cf40131SArnaldo Carvalho de Melo snprintf(name, size, "%s/%s/.build-id/%.2s/%s", 12834cf40131SArnaldo Carvalho de Melo getenv("HOME"), DEBUG_CACHE_DIR, 12844cf40131SArnaldo Carvalho de Melo build_id_hex, build_id_hex + 2); 12854cf40131SArnaldo Carvalho de Melo goto open_file; 12864cf40131SArnaldo Carvalho de Melo } 128786470930SIngo Molnar more: 128886470930SIngo Molnar do { 128994cb9e38SArnaldo Carvalho de Melo self->origin++; 129094cb9e38SArnaldo Carvalho de Melo switch (self->origin) { 129194cb9e38SArnaldo Carvalho de Melo case DSO__ORIG_FEDORA: 1292439d473bSArnaldo Carvalho de Melo snprintf(name, size, "/usr/lib/debug%s.debug", 1293439d473bSArnaldo Carvalho de Melo self->long_name); 129486470930SIngo Molnar break; 129594cb9e38SArnaldo Carvalho de Melo case DSO__ORIG_UBUNTU: 1296439d473bSArnaldo Carvalho de Melo snprintf(name, size, "/usr/lib/debug%s", 1297439d473bSArnaldo Carvalho de Melo self->long_name); 129886470930SIngo Molnar break; 129994cb9e38SArnaldo Carvalho de Melo case DSO__ORIG_BUILDID: 1300d3379ab9SArnaldo Carvalho de Melo if (filename__read_build_id(self->long_name, build_id, 1301d3379ab9SArnaldo Carvalho de Melo sizeof(build_id))) { 1302d3379ab9SArnaldo Carvalho de Melo build_id__sprintf(build_id, sizeof(build_id), 1303d3379ab9SArnaldo Carvalho de Melo build_id_hex); 13044d1e00a8SArnaldo Carvalho de Melo snprintf(name, size, 13054d1e00a8SArnaldo Carvalho de Melo "/usr/lib/debug/.build-id/%.2s/%s.debug", 1306d3379ab9SArnaldo Carvalho de Melo build_id_hex, build_id_hex + 2); 1307d3379ab9SArnaldo Carvalho de Melo if (self->has_build_id) 13088d06367fSArnaldo Carvalho de Melo goto compare_build_id; 1309d3379ab9SArnaldo Carvalho de Melo break; 13104d1e00a8SArnaldo Carvalho de Melo } 131194cb9e38SArnaldo Carvalho de Melo self->origin++; 13124d1e00a8SArnaldo Carvalho de Melo /* Fall thru */ 131394cb9e38SArnaldo Carvalho de Melo case DSO__ORIG_DSO: 1314439d473bSArnaldo Carvalho de Melo snprintf(name, size, "%s", self->long_name); 131586470930SIngo Molnar break; 131686470930SIngo Molnar 131786470930SIngo Molnar default: 131886470930SIngo Molnar goto out; 131986470930SIngo Molnar } 132086470930SIngo Molnar 13218d06367fSArnaldo Carvalho de Melo if (self->has_build_id) { 1322d3379ab9SArnaldo Carvalho de Melo if (filename__read_build_id(name, build_id, 1323d3379ab9SArnaldo Carvalho de Melo sizeof(build_id)) < 0) 13248d06367fSArnaldo Carvalho de Melo goto more; 13258d06367fSArnaldo Carvalho de Melo compare_build_id: 132678075caaSArnaldo Carvalho de Melo if (!dso__build_id_equal(self, build_id)) 13278d06367fSArnaldo Carvalho de Melo goto more; 13288d06367fSArnaldo Carvalho de Melo } 13294cf40131SArnaldo Carvalho de Melo open_file: 133086470930SIngo Molnar fd = open(name, O_RDONLY); 133186470930SIngo Molnar } while (fd < 0); 133286470930SIngo Molnar 13339de89fe7SArnaldo Carvalho de Melo ret = dso__load_sym(self, map, name, fd, filter, 0); 133486470930SIngo Molnar close(fd); 133586470930SIngo Molnar 133686470930SIngo Molnar /* 133786470930SIngo Molnar * Some people seem to have debuginfo files _WITHOUT_ debug info!?!? 133886470930SIngo Molnar */ 133986470930SIngo Molnar if (!ret) 134086470930SIngo Molnar goto more; 134186470930SIngo Molnar 1342a25e46c4SArnaldo Carvalho de Melo if (ret > 0) { 134382164161SArnaldo Carvalho de Melo int nr_plt = dso__synthesize_plt_symbols(self, map, filter); 1344a25e46c4SArnaldo Carvalho de Melo if (nr_plt > 0) 1345a25e46c4SArnaldo Carvalho de Melo ret += nr_plt; 1346a25e46c4SArnaldo Carvalho de Melo } 134786470930SIngo Molnar out: 134886470930SIngo Molnar free(name); 13491340e6bbSArnaldo Carvalho de Melo if (ret < 0 && strstr(self->name, " (deleted)") != NULL) 13501340e6bbSArnaldo Carvalho de Melo return 0; 135186470930SIngo Molnar return ret; 135286470930SIngo Molnar } 135386470930SIngo Molnar 135479406cd7SArnaldo Carvalho de Melo struct map *map_groups__find_by_name(struct map_groups *self, 135579406cd7SArnaldo Carvalho de Melo enum map_type type, const char *name) 1356439d473bSArnaldo Carvalho de Melo { 1357439d473bSArnaldo Carvalho de Melo struct rb_node *nd; 1358439d473bSArnaldo Carvalho de Melo 135979406cd7SArnaldo Carvalho de Melo for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) { 1360439d473bSArnaldo Carvalho de Melo struct map *map = rb_entry(nd, struct map, rb_node); 1361439d473bSArnaldo Carvalho de Melo 1362b7cece76SArnaldo Carvalho de Melo if (map->dso && strcmp(map->dso->short_name, name) == 0) 1363439d473bSArnaldo Carvalho de Melo return map; 1364439d473bSArnaldo Carvalho de Melo } 1365439d473bSArnaldo Carvalho de Melo 1366439d473bSArnaldo Carvalho de Melo return NULL; 1367439d473bSArnaldo Carvalho de Melo } 1368439d473bSArnaldo Carvalho de Melo 1369b7cece76SArnaldo Carvalho de Melo static int dso__kernel_module_get_build_id(struct dso *self) 1370b7cece76SArnaldo Carvalho de Melo { 1371b7cece76SArnaldo Carvalho de Melo char filename[PATH_MAX]; 1372b7cece76SArnaldo Carvalho de Melo /* 1373b7cece76SArnaldo Carvalho de Melo * kernel module short names are of the form "[module]" and 1374b7cece76SArnaldo Carvalho de Melo * we need just "module" here. 1375b7cece76SArnaldo Carvalho de Melo */ 1376b7cece76SArnaldo Carvalho de Melo const char *name = self->short_name + 1; 1377b7cece76SArnaldo Carvalho de Melo 1378b7cece76SArnaldo Carvalho de Melo snprintf(filename, sizeof(filename), 1379b7cece76SArnaldo Carvalho de Melo "/sys/module/%.*s/notes/.note.gnu.build-id", 1380b7cece76SArnaldo Carvalho de Melo (int)strlen(name - 1), name); 1381b7cece76SArnaldo Carvalho de Melo 1382b7cece76SArnaldo Carvalho de Melo if (sysfs__read_build_id(filename, self->build_id, 1383b7cece76SArnaldo Carvalho de Melo sizeof(self->build_id)) == 0) 1384b7cece76SArnaldo Carvalho de Melo self->has_build_id = true; 1385b7cece76SArnaldo Carvalho de Melo 1386b7cece76SArnaldo Carvalho de Melo return 0; 1387b7cece76SArnaldo Carvalho de Melo } 1388b7cece76SArnaldo Carvalho de Melo 13899de89fe7SArnaldo Carvalho de Melo static int map_groups__set_modules_path_dir(struct map_groups *self, char *dirname) 13906cfcc53eSMike Galbraith { 1391439d473bSArnaldo Carvalho de Melo struct dirent *dent; 1392439d473bSArnaldo Carvalho de Melo DIR *dir = opendir(dirname); 13936cfcc53eSMike Galbraith 1394439d473bSArnaldo Carvalho de Melo if (!dir) { 139587f8ea4cSArnaldo Carvalho de Melo pr_debug("%s: cannot open %s dir\n", __func__, dirname); 1396439d473bSArnaldo Carvalho de Melo return -1; 1397439d473bSArnaldo Carvalho de Melo } 13986cfcc53eSMike Galbraith 1399439d473bSArnaldo Carvalho de Melo while ((dent = readdir(dir)) != NULL) { 1400439d473bSArnaldo Carvalho de Melo char path[PATH_MAX]; 1401439d473bSArnaldo Carvalho de Melo 1402439d473bSArnaldo Carvalho de Melo if (dent->d_type == DT_DIR) { 1403439d473bSArnaldo Carvalho de Melo if (!strcmp(dent->d_name, ".") || 1404439d473bSArnaldo Carvalho de Melo !strcmp(dent->d_name, "..")) 1405439d473bSArnaldo Carvalho de Melo continue; 1406439d473bSArnaldo Carvalho de Melo 1407439d473bSArnaldo Carvalho de Melo snprintf(path, sizeof(path), "%s/%s", 1408439d473bSArnaldo Carvalho de Melo dirname, dent->d_name); 14099de89fe7SArnaldo Carvalho de Melo if (map_groups__set_modules_path_dir(self, path) < 0) 1410439d473bSArnaldo Carvalho de Melo goto failure; 1411439d473bSArnaldo Carvalho de Melo } else { 1412439d473bSArnaldo Carvalho de Melo char *dot = strrchr(dent->d_name, '.'), 1413439d473bSArnaldo Carvalho de Melo dso_name[PATH_MAX]; 1414439d473bSArnaldo Carvalho de Melo struct map *map; 1415cfc10d3bSArnaldo Carvalho de Melo char *long_name; 1416439d473bSArnaldo Carvalho de Melo 1417439d473bSArnaldo Carvalho de Melo if (dot == NULL || strcmp(dot, ".ko")) 1418439d473bSArnaldo Carvalho de Melo continue; 1419439d473bSArnaldo Carvalho de Melo snprintf(dso_name, sizeof(dso_name), "[%.*s]", 1420439d473bSArnaldo Carvalho de Melo (int)(dot - dent->d_name), dent->d_name); 1421439d473bSArnaldo Carvalho de Melo 1422a2a99e8eSArnaldo Carvalho de Melo strxfrchar(dso_name, '-', '_'); 14239de89fe7SArnaldo Carvalho de Melo map = map_groups__find_by_name(self, MAP__FUNCTION, dso_name); 1424439d473bSArnaldo Carvalho de Melo if (map == NULL) 1425439d473bSArnaldo Carvalho de Melo continue; 1426439d473bSArnaldo Carvalho de Melo 1427439d473bSArnaldo Carvalho de Melo snprintf(path, sizeof(path), "%s/%s", 1428439d473bSArnaldo Carvalho de Melo dirname, dent->d_name); 1429439d473bSArnaldo Carvalho de Melo 1430cfc10d3bSArnaldo Carvalho de Melo long_name = strdup(path); 1431cfc10d3bSArnaldo Carvalho de Melo if (long_name == NULL) 1432439d473bSArnaldo Carvalho de Melo goto failure; 1433cfc10d3bSArnaldo Carvalho de Melo dso__set_long_name(map->dso, long_name); 1434b7cece76SArnaldo Carvalho de Melo dso__kernel_module_get_build_id(map->dso); 1435439d473bSArnaldo Carvalho de Melo } 1436439d473bSArnaldo Carvalho de Melo } 1437439d473bSArnaldo Carvalho de Melo 1438c338aee8SArnaldo Carvalho de Melo return 0; 1439439d473bSArnaldo Carvalho de Melo failure: 1440439d473bSArnaldo Carvalho de Melo closedir(dir); 1441439d473bSArnaldo Carvalho de Melo return -1; 1442439d473bSArnaldo Carvalho de Melo } 1443439d473bSArnaldo Carvalho de Melo 14449de89fe7SArnaldo Carvalho de Melo static int map_groups__set_modules_path(struct map_groups *self) 1445439d473bSArnaldo Carvalho de Melo { 1446439d473bSArnaldo Carvalho de Melo struct utsname uts; 1447439d473bSArnaldo Carvalho de Melo char modules_path[PATH_MAX]; 1448439d473bSArnaldo Carvalho de Melo 1449439d473bSArnaldo Carvalho de Melo if (uname(&uts) < 0) 1450439d473bSArnaldo Carvalho de Melo return -1; 1451439d473bSArnaldo Carvalho de Melo 1452439d473bSArnaldo Carvalho de Melo snprintf(modules_path, sizeof(modules_path), "/lib/modules/%s/kernel", 1453439d473bSArnaldo Carvalho de Melo uts.release); 1454439d473bSArnaldo Carvalho de Melo 14559de89fe7SArnaldo Carvalho de Melo return map_groups__set_modules_path_dir(self, modules_path); 1456439d473bSArnaldo Carvalho de Melo } 14576cfcc53eSMike Galbraith 14586cfcc53eSMike Galbraith /* 1459439d473bSArnaldo Carvalho de Melo * Constructor variant for modules (where we know from /proc/modules where 1460439d473bSArnaldo Carvalho de Melo * they are loaded) and for vmlinux, where only after we load all the 1461439d473bSArnaldo Carvalho de Melo * symbols we'll know where it starts and ends. 14626cfcc53eSMike Galbraith */ 14633610583cSArnaldo Carvalho de Melo static struct map *map__new2(u64 start, struct dso *dso, enum map_type type) 1464439d473bSArnaldo Carvalho de Melo { 14659de89fe7SArnaldo Carvalho de Melo struct map *self = zalloc(sizeof(*self) + 14669de89fe7SArnaldo Carvalho de Melo (dso->kernel ? sizeof(struct kmap) : 0)); 1467439d473bSArnaldo Carvalho de Melo if (self != NULL) { 1468439d473bSArnaldo Carvalho de Melo /* 1469afb7b4f0SArnaldo Carvalho de Melo * ->end will be filled after we load all the symbols 1470439d473bSArnaldo Carvalho de Melo */ 14713610583cSArnaldo Carvalho de Melo map__init(self, type, start, 0, 0, dso); 1472439d473bSArnaldo Carvalho de Melo } 1473afb7b4f0SArnaldo Carvalho de Melo 1474439d473bSArnaldo Carvalho de Melo return self; 1475439d473bSArnaldo Carvalho de Melo } 1476439d473bSArnaldo Carvalho de Melo 14779de89fe7SArnaldo Carvalho de Melo struct map *map_groups__new_module(struct map_groups *self, u64 start, 1478b7cece76SArnaldo Carvalho de Melo const char *filename) 1479b7cece76SArnaldo Carvalho de Melo { 1480b7cece76SArnaldo Carvalho de Melo struct map *map; 1481b7cece76SArnaldo Carvalho de Melo struct dso *dso = __dsos__findnew(&dsos__kernel, filename); 1482b7cece76SArnaldo Carvalho de Melo 1483b7cece76SArnaldo Carvalho de Melo if (dso == NULL) 1484b7cece76SArnaldo Carvalho de Melo return NULL; 1485b7cece76SArnaldo Carvalho de Melo 1486b7cece76SArnaldo Carvalho de Melo map = map__new2(start, dso, MAP__FUNCTION); 1487b7cece76SArnaldo Carvalho de Melo if (map == NULL) 1488b7cece76SArnaldo Carvalho de Melo return NULL; 1489b7cece76SArnaldo Carvalho de Melo 1490b7cece76SArnaldo Carvalho de Melo dso->origin = DSO__ORIG_KMODULE; 14919de89fe7SArnaldo Carvalho de Melo map_groups__insert(self, map); 1492b7cece76SArnaldo Carvalho de Melo return map; 1493b7cece76SArnaldo Carvalho de Melo } 1494b7cece76SArnaldo Carvalho de Melo 14959de89fe7SArnaldo Carvalho de Melo static int map_groups__create_modules(struct map_groups *self) 1496439d473bSArnaldo Carvalho de Melo { 1497439d473bSArnaldo Carvalho de Melo char *line = NULL; 1498439d473bSArnaldo Carvalho de Melo size_t n; 1499439d473bSArnaldo Carvalho de Melo FILE *file = fopen("/proc/modules", "r"); 1500439d473bSArnaldo Carvalho de Melo struct map *map; 1501439d473bSArnaldo Carvalho de Melo 1502439d473bSArnaldo Carvalho de Melo if (file == NULL) 1503439d473bSArnaldo Carvalho de Melo return -1; 1504439d473bSArnaldo Carvalho de Melo 1505439d473bSArnaldo Carvalho de Melo while (!feof(file)) { 1506439d473bSArnaldo Carvalho de Melo char name[PATH_MAX]; 1507439d473bSArnaldo Carvalho de Melo u64 start; 1508439d473bSArnaldo Carvalho de Melo char *sep; 1509439d473bSArnaldo Carvalho de Melo int line_len; 1510439d473bSArnaldo Carvalho de Melo 1511439d473bSArnaldo Carvalho de Melo line_len = getline(&line, &n, file); 1512439d473bSArnaldo Carvalho de Melo if (line_len < 0) 15136cfcc53eSMike Galbraith break; 15146cfcc53eSMike Galbraith 1515439d473bSArnaldo Carvalho de Melo if (!line) 1516439d473bSArnaldo Carvalho de Melo goto out_failure; 1517439d473bSArnaldo Carvalho de Melo 1518439d473bSArnaldo Carvalho de Melo line[--line_len] = '\0'; /* \n */ 1519439d473bSArnaldo Carvalho de Melo 1520439d473bSArnaldo Carvalho de Melo sep = strrchr(line, 'x'); 1521439d473bSArnaldo Carvalho de Melo if (sep == NULL) 1522439d473bSArnaldo Carvalho de Melo continue; 1523439d473bSArnaldo Carvalho de Melo 1524439d473bSArnaldo Carvalho de Melo hex2u64(sep + 1, &start); 1525439d473bSArnaldo Carvalho de Melo 1526439d473bSArnaldo Carvalho de Melo sep = strchr(line, ' '); 1527439d473bSArnaldo Carvalho de Melo if (sep == NULL) 1528439d473bSArnaldo Carvalho de Melo continue; 1529439d473bSArnaldo Carvalho de Melo 1530439d473bSArnaldo Carvalho de Melo *sep = '\0'; 1531439d473bSArnaldo Carvalho de Melo 1532439d473bSArnaldo Carvalho de Melo snprintf(name, sizeof(name), "[%s]", line); 15339de89fe7SArnaldo Carvalho de Melo map = map_groups__new_module(self, start, name); 1534b7cece76SArnaldo Carvalho de Melo if (map == NULL) 1535439d473bSArnaldo Carvalho de Melo goto out_delete_line; 1536b7cece76SArnaldo Carvalho de Melo dso__kernel_module_get_build_id(map->dso); 15376cfcc53eSMike Galbraith } 15386cfcc53eSMike Galbraith 1539439d473bSArnaldo Carvalho de Melo free(line); 1540439d473bSArnaldo Carvalho de Melo fclose(file); 1541439d473bSArnaldo Carvalho de Melo 15429de89fe7SArnaldo Carvalho de Melo return map_groups__set_modules_path(self); 1543439d473bSArnaldo Carvalho de Melo 1544439d473bSArnaldo Carvalho de Melo out_delete_line: 1545439d473bSArnaldo Carvalho de Melo free(line); 1546439d473bSArnaldo Carvalho de Melo out_failure: 1547439d473bSArnaldo Carvalho de Melo return -1; 15486cfcc53eSMike Galbraith } 15496cfcc53eSMike Galbraith 15509958e1f0SArnaldo Carvalho de Melo static int dso__load_vmlinux(struct dso *self, struct map *map, 15516beba7adSArnaldo Carvalho de Melo const char *vmlinux, symbol_filter_t filter) 155286470930SIngo Molnar { 1553fbd733b8SArnaldo Carvalho de Melo int err = -1, fd; 155486470930SIngo Molnar 1555fbd733b8SArnaldo Carvalho de Melo if (self->has_build_id) { 1556fbd733b8SArnaldo Carvalho de Melo u8 build_id[BUILD_ID_SIZE]; 155766bd8424SArnaldo Carvalho de Melo 1558fbd733b8SArnaldo Carvalho de Melo if (filename__read_build_id(vmlinux, build_id, 1559fbd733b8SArnaldo Carvalho de Melo sizeof(build_id)) < 0) { 1560fbd733b8SArnaldo Carvalho de Melo pr_debug("No build_id in %s, ignoring it\n", vmlinux); 1561fbd733b8SArnaldo Carvalho de Melo return -1; 1562fbd733b8SArnaldo Carvalho de Melo } 1563fbd733b8SArnaldo Carvalho de Melo if (!dso__build_id_equal(self, build_id)) { 1564fbd733b8SArnaldo Carvalho de Melo char expected_build_id[BUILD_ID_SIZE * 2 + 1], 1565fbd733b8SArnaldo Carvalho de Melo vmlinux_build_id[BUILD_ID_SIZE * 2 + 1]; 1566fbd733b8SArnaldo Carvalho de Melo 1567fbd733b8SArnaldo Carvalho de Melo build_id__sprintf(self->build_id, 1568fbd733b8SArnaldo Carvalho de Melo sizeof(self->build_id), 1569fbd733b8SArnaldo Carvalho de Melo expected_build_id); 1570fbd733b8SArnaldo Carvalho de Melo build_id__sprintf(build_id, sizeof(build_id), 1571fbd733b8SArnaldo Carvalho de Melo vmlinux_build_id); 1572fbd733b8SArnaldo Carvalho de Melo pr_debug("build_id in %s is %s while expected is %s, " 1573fbd733b8SArnaldo Carvalho de Melo "ignoring it\n", vmlinux, vmlinux_build_id, 1574fbd733b8SArnaldo Carvalho de Melo expected_build_id); 1575fbd733b8SArnaldo Carvalho de Melo return -1; 1576fbd733b8SArnaldo Carvalho de Melo } 1577fbd733b8SArnaldo Carvalho de Melo } 1578fbd733b8SArnaldo Carvalho de Melo 1579fbd733b8SArnaldo Carvalho de Melo fd = open(vmlinux, O_RDONLY); 158086470930SIngo Molnar if (fd < 0) 158186470930SIngo Molnar return -1; 158286470930SIngo Molnar 15833610583cSArnaldo Carvalho de Melo dso__set_loaded(self, map->type); 15849de89fe7SArnaldo Carvalho de Melo err = dso__load_sym(self, map, vmlinux, fd, filter, 0); 158586470930SIngo Molnar close(fd); 158686470930SIngo Molnar 15873846df2eSArnaldo Carvalho de Melo if (err > 0) 15883846df2eSArnaldo Carvalho de Melo pr_debug("Using %s for symbols\n", vmlinux); 15893846df2eSArnaldo Carvalho de Melo 159086470930SIngo Molnar return err; 159186470930SIngo Molnar } 159286470930SIngo Molnar 1593a19afe46SArnaldo Carvalho de Melo int dso__load_vmlinux_path(struct dso *self, struct map *map, 15949de89fe7SArnaldo Carvalho de Melo symbol_filter_t filter) 1595a19afe46SArnaldo Carvalho de Melo { 1596a19afe46SArnaldo Carvalho de Melo int i, err = 0; 1597a19afe46SArnaldo Carvalho de Melo 1598a19afe46SArnaldo Carvalho de Melo pr_debug("Looking at the vmlinux_path (%d entries long)\n", 1599a19afe46SArnaldo Carvalho de Melo vmlinux_path__nr_entries); 1600a19afe46SArnaldo Carvalho de Melo 1601a19afe46SArnaldo Carvalho de Melo for (i = 0; i < vmlinux_path__nr_entries; ++i) { 16029de89fe7SArnaldo Carvalho de Melo err = dso__load_vmlinux(self, map, vmlinux_path[i], filter); 1603a19afe46SArnaldo Carvalho de Melo if (err > 0) { 1604a19afe46SArnaldo Carvalho de Melo dso__set_long_name(self, strdup(vmlinux_path[i])); 1605a19afe46SArnaldo Carvalho de Melo break; 1606a19afe46SArnaldo Carvalho de Melo } 1607a19afe46SArnaldo Carvalho de Melo } 1608a19afe46SArnaldo Carvalho de Melo 1609a19afe46SArnaldo Carvalho de Melo return err; 1610a19afe46SArnaldo Carvalho de Melo } 1611a19afe46SArnaldo Carvalho de Melo 1612c338aee8SArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *self, struct map *map, 16139de89fe7SArnaldo Carvalho de Melo symbol_filter_t filter) 161486470930SIngo Molnar { 1615cc612d81SArnaldo Carvalho de Melo int err; 16169e201442SArnaldo Carvalho de Melo const char *kallsyms_filename = NULL; 16179e201442SArnaldo Carvalho de Melo char *kallsyms_allocated_filename = NULL; 1618dc8d6ab2SArnaldo Carvalho de Melo /* 1619dc8d6ab2SArnaldo Carvalho de Melo * Step 1: if the user specified a vmlinux filename, use it and only 1620dc8d6ab2SArnaldo Carvalho de Melo * it, reporting errors to the user if it cannot be used. 1621dc8d6ab2SArnaldo Carvalho de Melo * 1622dc8d6ab2SArnaldo Carvalho de Melo * For instance, try to analyse an ARM perf.data file _without_ a 1623dc8d6ab2SArnaldo Carvalho de Melo * build-id, or if the user specifies the wrong path to the right 1624dc8d6ab2SArnaldo Carvalho de Melo * vmlinux file, obviously we can't fallback to another vmlinux (a 1625dc8d6ab2SArnaldo Carvalho de Melo * x86_86 one, on the machine where analysis is being performed, say), 1626dc8d6ab2SArnaldo Carvalho de Melo * or worse, /proc/kallsyms. 1627dc8d6ab2SArnaldo Carvalho de Melo * 1628dc8d6ab2SArnaldo Carvalho de Melo * If the specified file _has_ a build-id and there is a build-id 1629dc8d6ab2SArnaldo Carvalho de Melo * section in the perf.data file, we will still do the expected 1630dc8d6ab2SArnaldo Carvalho de Melo * validation in dso__load_vmlinux and will bail out if they don't 1631dc8d6ab2SArnaldo Carvalho de Melo * match. 1632dc8d6ab2SArnaldo Carvalho de Melo */ 1633dc8d6ab2SArnaldo Carvalho de Melo if (symbol_conf.vmlinux_name != NULL) { 16349de89fe7SArnaldo Carvalho de Melo err = dso__load_vmlinux(self, map, 1635dc8d6ab2SArnaldo Carvalho de Melo symbol_conf.vmlinux_name, filter); 1636dc8d6ab2SArnaldo Carvalho de Melo goto out_try_fixup; 1637dc8d6ab2SArnaldo Carvalho de Melo } 1638439d473bSArnaldo Carvalho de Melo 1639cc612d81SArnaldo Carvalho de Melo if (vmlinux_path != NULL) { 16409de89fe7SArnaldo Carvalho de Melo err = dso__load_vmlinux_path(self, map, filter); 1641a19afe46SArnaldo Carvalho de Melo if (err > 0) 1642cc612d81SArnaldo Carvalho de Melo goto out_fixup; 1643cc612d81SArnaldo Carvalho de Melo } 1644cc612d81SArnaldo Carvalho de Melo 1645b7cece76SArnaldo Carvalho de Melo /* 1646b7cece76SArnaldo Carvalho de Melo * Say the kernel DSO was created when processing the build-id header table, 1647b7cece76SArnaldo Carvalho de Melo * we have a build-id, so check if it is the same as the running kernel, 1648b7cece76SArnaldo Carvalho de Melo * using it if it is. 1649b7cece76SArnaldo Carvalho de Melo */ 1650b7cece76SArnaldo Carvalho de Melo if (self->has_build_id) { 1651b7cece76SArnaldo Carvalho de Melo u8 kallsyms_build_id[BUILD_ID_SIZE]; 16529e201442SArnaldo Carvalho de Melo char sbuild_id[BUILD_ID_SIZE * 2 + 1]; 1653b7cece76SArnaldo Carvalho de Melo 1654b7cece76SArnaldo Carvalho de Melo if (sysfs__read_build_id("/sys/kernel/notes", kallsyms_build_id, 16558d0591f6SArnaldo Carvalho de Melo sizeof(kallsyms_build_id)) == 0) { 16569e201442SArnaldo Carvalho de Melo if (dso__build_id_equal(self, kallsyms_build_id)) { 16579e201442SArnaldo Carvalho de Melo kallsyms_filename = "/proc/kallsyms"; 1658b7cece76SArnaldo Carvalho de Melo goto do_kallsyms; 16598d0591f6SArnaldo Carvalho de Melo } 16609e201442SArnaldo Carvalho de Melo } 1661dc8d6ab2SArnaldo Carvalho de Melo /* 1662dc8d6ab2SArnaldo Carvalho de Melo * Now look if we have it on the build-id cache in 1663dc8d6ab2SArnaldo Carvalho de Melo * $HOME/.debug/[kernel.kallsyms]. 1664dc8d6ab2SArnaldo Carvalho de Melo */ 16659e201442SArnaldo Carvalho de Melo build_id__sprintf(self->build_id, sizeof(self->build_id), 16669e201442SArnaldo Carvalho de Melo sbuild_id); 16679e201442SArnaldo Carvalho de Melo 16689e201442SArnaldo Carvalho de Melo if (asprintf(&kallsyms_allocated_filename, 16699e201442SArnaldo Carvalho de Melo "%s/.debug/[kernel.kallsyms]/%s", 16703846df2eSArnaldo Carvalho de Melo getenv("HOME"), sbuild_id) == -1) { 16713846df2eSArnaldo Carvalho de Melo pr_err("Not enough memory for kallsyms file lookup\n"); 16728d0591f6SArnaldo Carvalho de Melo return -1; 16733846df2eSArnaldo Carvalho de Melo } 16748d0591f6SArnaldo Carvalho de Melo 167519fc2dedSArnaldo Carvalho de Melo kallsyms_filename = kallsyms_allocated_filename; 167619fc2dedSArnaldo Carvalho de Melo 1677dc8d6ab2SArnaldo Carvalho de Melo if (access(kallsyms_filename, F_OK)) { 16783846df2eSArnaldo Carvalho de Melo pr_err("No kallsyms or vmlinux with build-id %s " 16793846df2eSArnaldo Carvalho de Melo "was found\n", sbuild_id); 16809e201442SArnaldo Carvalho de Melo free(kallsyms_allocated_filename); 1681dc8d6ab2SArnaldo Carvalho de Melo return -1; 1682ef6ae724SArnaldo Carvalho de Melo } 1683dc8d6ab2SArnaldo Carvalho de Melo } else { 1684dc8d6ab2SArnaldo Carvalho de Melo /* 1685dc8d6ab2SArnaldo Carvalho de Melo * Last resort, if we don't have a build-id and couldn't find 1686dc8d6ab2SArnaldo Carvalho de Melo * any vmlinux file, try the running kernel kallsyms table. 1687dc8d6ab2SArnaldo Carvalho de Melo */ 1688dc8d6ab2SArnaldo Carvalho de Melo kallsyms_filename = "/proc/kallsyms"; 1689dc8d6ab2SArnaldo Carvalho de Melo } 1690dc8d6ab2SArnaldo Carvalho de Melo 1691dc8d6ab2SArnaldo Carvalho de Melo do_kallsyms: 16929de89fe7SArnaldo Carvalho de Melo err = dso__load_kallsyms(self, kallsyms_filename, map, filter); 16933846df2eSArnaldo Carvalho de Melo if (err > 0) 16943846df2eSArnaldo Carvalho de Melo pr_debug("Using %s for symbols\n", kallsyms_filename); 1695dc8d6ab2SArnaldo Carvalho de Melo free(kallsyms_allocated_filename); 1696dc8d6ab2SArnaldo Carvalho de Melo 1697dc8d6ab2SArnaldo Carvalho de Melo out_try_fixup: 1698439d473bSArnaldo Carvalho de Melo if (err > 0) { 1699cc612d81SArnaldo Carvalho de Melo out_fixup: 1700e1c7c6a4SArnaldo Carvalho de Melo if (kallsyms_filename != NULL) 1701dc8d6ab2SArnaldo Carvalho de Melo dso__set_long_name(self, strdup("[kernel.kallsyms]")); 17026a4694a4SArnaldo Carvalho de Melo map__fixup_start(map); 17036a4694a4SArnaldo Carvalho de Melo map__fixup_end(map); 1704439d473bSArnaldo Carvalho de Melo } 170594cb9e38SArnaldo Carvalho de Melo 170686470930SIngo Molnar return err; 170786470930SIngo Molnar } 170886470930SIngo Molnar 1709b0da954aSArnaldo Carvalho de Melo LIST_HEAD(dsos__user); 1710b0da954aSArnaldo Carvalho de Melo LIST_HEAD(dsos__kernel); 1711cd84c2acSFrederic Weisbecker 1712b0da954aSArnaldo Carvalho de Melo static void dsos__add(struct list_head *head, struct dso *dso) 1713cd84c2acSFrederic Weisbecker { 1714b0da954aSArnaldo Carvalho de Melo list_add_tail(&dso->node, head); 1715cd84c2acSFrederic Weisbecker } 1716cd84c2acSFrederic Weisbecker 1717b0da954aSArnaldo Carvalho de Melo static struct dso *dsos__find(struct list_head *head, const char *name) 1718cd84c2acSFrederic Weisbecker { 1719cd84c2acSFrederic Weisbecker struct dso *pos; 1720cd84c2acSFrederic Weisbecker 1721b0da954aSArnaldo Carvalho de Melo list_for_each_entry(pos, head, node) 1722cf4e5b08SArnaldo Carvalho de Melo if (strcmp(pos->long_name, name) == 0) 1723cd84c2acSFrederic Weisbecker return pos; 1724cd84c2acSFrederic Weisbecker return NULL; 1725cd84c2acSFrederic Weisbecker } 1726cd84c2acSFrederic Weisbecker 1727a89e5abeSArnaldo Carvalho de Melo struct dso *__dsos__findnew(struct list_head *head, const char *name) 1728cd84c2acSFrederic Weisbecker { 1729a89e5abeSArnaldo Carvalho de Melo struct dso *dso = dsos__find(head, name); 1730cd84c2acSFrederic Weisbecker 1731e4204992SArnaldo Carvalho de Melo if (!dso) { 173200a192b3SArnaldo Carvalho de Melo dso = dso__new(name); 1733cfc10d3bSArnaldo Carvalho de Melo if (dso != NULL) { 1734a89e5abeSArnaldo Carvalho de Melo dsos__add(head, dso); 1735cfc10d3bSArnaldo Carvalho de Melo dso__set_basename(dso); 1736cfc10d3bSArnaldo Carvalho de Melo } 1737e4204992SArnaldo Carvalho de Melo } 1738cd84c2acSFrederic Weisbecker 1739cd84c2acSFrederic Weisbecker return dso; 1740cd84c2acSFrederic Weisbecker } 1741cd84c2acSFrederic Weisbecker 1742b0da954aSArnaldo Carvalho de Melo static void __dsos__fprintf(struct list_head *head, FILE *fp) 1743cd84c2acSFrederic Weisbecker { 1744cd84c2acSFrederic Weisbecker struct dso *pos; 1745cd84c2acSFrederic Weisbecker 174695011c60SArnaldo Carvalho de Melo list_for_each_entry(pos, head, node) { 174795011c60SArnaldo Carvalho de Melo int i; 174895011c60SArnaldo Carvalho de Melo for (i = 0; i < MAP__NR_TYPES; ++i) 174995011c60SArnaldo Carvalho de Melo dso__fprintf(pos, i, fp); 175095011c60SArnaldo Carvalho de Melo } 1751cd84c2acSFrederic Weisbecker } 1752cd84c2acSFrederic Weisbecker 1753b0da954aSArnaldo Carvalho de Melo void dsos__fprintf(FILE *fp) 1754b0da954aSArnaldo Carvalho de Melo { 1755b0da954aSArnaldo Carvalho de Melo __dsos__fprintf(&dsos__kernel, fp); 1756b0da954aSArnaldo Carvalho de Melo __dsos__fprintf(&dsos__user, fp); 1757b0da954aSArnaldo Carvalho de Melo } 1758b0da954aSArnaldo Carvalho de Melo 175988d3d9b7SArnaldo Carvalho de Melo static size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp, 176088d3d9b7SArnaldo Carvalho de Melo bool with_hits) 17619e03eb2dSArnaldo Carvalho de Melo { 17629e03eb2dSArnaldo Carvalho de Melo struct dso *pos; 17639e03eb2dSArnaldo Carvalho de Melo size_t ret = 0; 17649e03eb2dSArnaldo Carvalho de Melo 1765b0da954aSArnaldo Carvalho de Melo list_for_each_entry(pos, head, node) { 176688d3d9b7SArnaldo Carvalho de Melo if (with_hits && !pos->hit) 176788d3d9b7SArnaldo Carvalho de Melo continue; 17689e03eb2dSArnaldo Carvalho de Melo ret += dso__fprintf_buildid(pos, fp); 17699e03eb2dSArnaldo Carvalho de Melo ret += fprintf(fp, " %s\n", pos->long_name); 17709e03eb2dSArnaldo Carvalho de Melo } 17719e03eb2dSArnaldo Carvalho de Melo return ret; 17729e03eb2dSArnaldo Carvalho de Melo } 17739e03eb2dSArnaldo Carvalho de Melo 177488d3d9b7SArnaldo Carvalho de Melo size_t dsos__fprintf_buildid(FILE *fp, bool with_hits) 1775b0da954aSArnaldo Carvalho de Melo { 177688d3d9b7SArnaldo Carvalho de Melo return (__dsos__fprintf_buildid(&dsos__kernel, fp, with_hits) + 177788d3d9b7SArnaldo Carvalho de Melo __dsos__fprintf_buildid(&dsos__user, fp, with_hits)); 1778b0da954aSArnaldo Carvalho de Melo } 1779b0da954aSArnaldo Carvalho de Melo 1780fd1d908cSArnaldo Carvalho de Melo struct dso *dso__new_kernel(const char *name) 1781fd1d908cSArnaldo Carvalho de Melo { 1782fd1d908cSArnaldo Carvalho de Melo struct dso *self = dso__new(name ?: "[kernel.kallsyms]"); 1783fd1d908cSArnaldo Carvalho de Melo 1784fd1d908cSArnaldo Carvalho de Melo if (self != NULL) { 1785fd1d908cSArnaldo Carvalho de Melo self->short_name = "[kernel]"; 1786fd1d908cSArnaldo Carvalho de Melo self->kernel = 1; 1787fd1d908cSArnaldo Carvalho de Melo } 1788fd1d908cSArnaldo Carvalho de Melo 1789fd1d908cSArnaldo Carvalho de Melo return self; 1790fd1d908cSArnaldo Carvalho de Melo } 1791fd1d908cSArnaldo Carvalho de Melo 1792fd1d908cSArnaldo Carvalho de Melo void dso__read_running_kernel_build_id(struct dso *self) 1793fd1d908cSArnaldo Carvalho de Melo { 1794fd1d908cSArnaldo Carvalho de Melo if (sysfs__read_build_id("/sys/kernel/notes", self->build_id, 1795fd1d908cSArnaldo Carvalho de Melo sizeof(self->build_id)) == 0) 1796fd1d908cSArnaldo Carvalho de Melo self->has_build_id = true; 1797fd1d908cSArnaldo Carvalho de Melo } 1798fd1d908cSArnaldo Carvalho de Melo 1799f1dfa0b1SArnaldo Carvalho de Melo static struct dso *dsos__create_kernel(const char *vmlinux) 1800cd84c2acSFrederic Weisbecker { 1801fd1d908cSArnaldo Carvalho de Melo struct dso *kernel = dso__new_kernel(vmlinux); 1802cd84c2acSFrederic Weisbecker 18038d92c02aSArnaldo Carvalho de Melo if (kernel != NULL) { 1804fd1d908cSArnaldo Carvalho de Melo dso__read_running_kernel_build_id(kernel); 1805b0da954aSArnaldo Carvalho de Melo dsos__add(&dsos__kernel, kernel); 18068d92c02aSArnaldo Carvalho de Melo } 1807cd84c2acSFrederic Weisbecker 1808f1dfa0b1SArnaldo Carvalho de Melo return kernel; 1809f1dfa0b1SArnaldo Carvalho de Melo } 1810f1dfa0b1SArnaldo Carvalho de Melo 1811b7cece76SArnaldo Carvalho de Melo int __map_groups__create_kernel_maps(struct map_groups *self, 1812de176489SArnaldo Carvalho de Melo struct map *vmlinux_maps[MAP__NR_TYPES], 1813b7cece76SArnaldo Carvalho de Melo struct dso *kernel) 1814f1dfa0b1SArnaldo Carvalho de Melo { 1815de176489SArnaldo Carvalho de Melo enum map_type type; 1816f1dfa0b1SArnaldo Carvalho de Melo 1817de176489SArnaldo Carvalho de Melo for (type = 0; type < MAP__NR_TYPES; ++type) { 18189de89fe7SArnaldo Carvalho de Melo struct kmap *kmap; 18199de89fe7SArnaldo Carvalho de Melo 1820de176489SArnaldo Carvalho de Melo vmlinux_maps[type] = map__new2(0, kernel, type); 1821de176489SArnaldo Carvalho de Melo if (vmlinux_maps[type] == NULL) 1822f1dfa0b1SArnaldo Carvalho de Melo return -1; 1823f1dfa0b1SArnaldo Carvalho de Melo 1824de176489SArnaldo Carvalho de Melo vmlinux_maps[type]->map_ip = 1825de176489SArnaldo Carvalho de Melo vmlinux_maps[type]->unmap_ip = identity__map_ip; 18269de89fe7SArnaldo Carvalho de Melo 18279de89fe7SArnaldo Carvalho de Melo kmap = map__kmap(vmlinux_maps[type]); 18289de89fe7SArnaldo Carvalho de Melo kmap->kmaps = self; 1829de176489SArnaldo Carvalho de Melo map_groups__insert(self, vmlinux_maps[type]); 1830f1dfa0b1SArnaldo Carvalho de Melo } 1831f1dfa0b1SArnaldo Carvalho de Melo 1832f1dfa0b1SArnaldo Carvalho de Melo return 0; 18332446042cSArnaldo Carvalho de Melo } 18342446042cSArnaldo Carvalho de Melo 1835cc612d81SArnaldo Carvalho de Melo static void vmlinux_path__exit(void) 18362446042cSArnaldo Carvalho de Melo { 1837cc612d81SArnaldo Carvalho de Melo while (--vmlinux_path__nr_entries >= 0) { 1838cc612d81SArnaldo Carvalho de Melo free(vmlinux_path[vmlinux_path__nr_entries]); 1839cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = NULL; 1840cc612d81SArnaldo Carvalho de Melo } 1841cc612d81SArnaldo Carvalho de Melo 1842cc612d81SArnaldo Carvalho de Melo free(vmlinux_path); 1843cc612d81SArnaldo Carvalho de Melo vmlinux_path = NULL; 1844cc612d81SArnaldo Carvalho de Melo } 1845cc612d81SArnaldo Carvalho de Melo 1846cc612d81SArnaldo Carvalho de Melo static int vmlinux_path__init(void) 1847cc612d81SArnaldo Carvalho de Melo { 1848cc612d81SArnaldo Carvalho de Melo struct utsname uts; 1849cc612d81SArnaldo Carvalho de Melo char bf[PATH_MAX]; 1850cc612d81SArnaldo Carvalho de Melo 1851cc612d81SArnaldo Carvalho de Melo if (uname(&uts) < 0) 18522446042cSArnaldo Carvalho de Melo return -1; 18532446042cSArnaldo Carvalho de Melo 1854cc612d81SArnaldo Carvalho de Melo vmlinux_path = malloc(sizeof(char *) * 5); 1855cc612d81SArnaldo Carvalho de Melo if (vmlinux_path == NULL) 1856cc612d81SArnaldo Carvalho de Melo return -1; 1857cc612d81SArnaldo Carvalho de Melo 1858cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup("vmlinux"); 1859cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 1860cc612d81SArnaldo Carvalho de Melo goto out_fail; 1861cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 1862cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup("/boot/vmlinux"); 1863cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 1864cc612d81SArnaldo Carvalho de Melo goto out_fail; 1865cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 1866cc612d81SArnaldo Carvalho de Melo snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", uts.release); 1867cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); 1868cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 1869cc612d81SArnaldo Carvalho de Melo goto out_fail; 1870cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 1871cc612d81SArnaldo Carvalho de Melo snprintf(bf, sizeof(bf), "/lib/modules/%s/build/vmlinux", uts.release); 1872cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); 1873cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 1874cc612d81SArnaldo Carvalho de Melo goto out_fail; 1875cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 1876cc612d81SArnaldo Carvalho de Melo snprintf(bf, sizeof(bf), "/usr/lib/debug/lib/modules/%s/vmlinux", 1877cc612d81SArnaldo Carvalho de Melo uts.release); 1878cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); 1879cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 1880cc612d81SArnaldo Carvalho de Melo goto out_fail; 1881cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 1882cc612d81SArnaldo Carvalho de Melo 1883cc612d81SArnaldo Carvalho de Melo return 0; 1884cc612d81SArnaldo Carvalho de Melo 1885cc612d81SArnaldo Carvalho de Melo out_fail: 1886cc612d81SArnaldo Carvalho de Melo vmlinux_path__exit(); 1887cc612d81SArnaldo Carvalho de Melo return -1; 1888cc612d81SArnaldo Carvalho de Melo } 1889cc612d81SArnaldo Carvalho de Melo 1890655000e7SArnaldo Carvalho de Melo static int setup_list(struct strlist **list, const char *list_str, 1891655000e7SArnaldo Carvalho de Melo const char *list_name) 1892655000e7SArnaldo Carvalho de Melo { 1893655000e7SArnaldo Carvalho de Melo if (list_str == NULL) 1894655000e7SArnaldo Carvalho de Melo return 0; 1895655000e7SArnaldo Carvalho de Melo 1896655000e7SArnaldo Carvalho de Melo *list = strlist__new(true, list_str); 1897655000e7SArnaldo Carvalho de Melo if (!*list) { 1898655000e7SArnaldo Carvalho de Melo pr_err("problems parsing %s list\n", list_name); 1899655000e7SArnaldo Carvalho de Melo return -1; 1900655000e7SArnaldo Carvalho de Melo } 1901655000e7SArnaldo Carvalho de Melo return 0; 1902655000e7SArnaldo Carvalho de Melo } 1903655000e7SArnaldo Carvalho de Melo 190475be6cf4SArnaldo Carvalho de Melo int symbol__init(void) 1905cc612d81SArnaldo Carvalho de Melo { 190695011c60SArnaldo Carvalho de Melo elf_version(EV_CURRENT); 190775be6cf4SArnaldo Carvalho de Melo if (symbol_conf.sort_by_name) 190875be6cf4SArnaldo Carvalho de Melo symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) - 190979406cd7SArnaldo Carvalho de Melo sizeof(struct symbol)); 1910b32d133aSArnaldo Carvalho de Melo 191175be6cf4SArnaldo Carvalho de Melo if (symbol_conf.try_vmlinux_path && vmlinux_path__init() < 0) 1912cc612d81SArnaldo Carvalho de Melo return -1; 1913cc612d81SArnaldo Carvalho de Melo 1914c410a338SArnaldo Carvalho de Melo if (symbol_conf.field_sep && *symbol_conf.field_sep == '.') { 1915c410a338SArnaldo Carvalho de Melo pr_err("'.' is the only non valid --field-separator argument\n"); 1916c410a338SArnaldo Carvalho de Melo return -1; 1917c410a338SArnaldo Carvalho de Melo } 1918c410a338SArnaldo Carvalho de Melo 1919655000e7SArnaldo Carvalho de Melo if (setup_list(&symbol_conf.dso_list, 1920655000e7SArnaldo Carvalho de Melo symbol_conf.dso_list_str, "dso") < 0) 1921655000e7SArnaldo Carvalho de Melo return -1; 1922655000e7SArnaldo Carvalho de Melo 1923655000e7SArnaldo Carvalho de Melo if (setup_list(&symbol_conf.comm_list, 1924655000e7SArnaldo Carvalho de Melo symbol_conf.comm_list_str, "comm") < 0) 1925655000e7SArnaldo Carvalho de Melo goto out_free_dso_list; 1926655000e7SArnaldo Carvalho de Melo 1927655000e7SArnaldo Carvalho de Melo if (setup_list(&symbol_conf.sym_list, 1928655000e7SArnaldo Carvalho de Melo symbol_conf.sym_list_str, "symbol") < 0) 1929655000e7SArnaldo Carvalho de Melo goto out_free_comm_list; 1930655000e7SArnaldo Carvalho de Melo 19314aa65636SArnaldo Carvalho de Melo return 0; 1932655000e7SArnaldo Carvalho de Melo 1933655000e7SArnaldo Carvalho de Melo out_free_dso_list: 1934655000e7SArnaldo Carvalho de Melo strlist__delete(symbol_conf.dso_list); 1935655000e7SArnaldo Carvalho de Melo out_free_comm_list: 1936655000e7SArnaldo Carvalho de Melo strlist__delete(symbol_conf.comm_list); 1937655000e7SArnaldo Carvalho de Melo return -1; 1938cc612d81SArnaldo Carvalho de Melo } 1939cc612d81SArnaldo Carvalho de Melo 19409de89fe7SArnaldo Carvalho de Melo int map_groups__create_kernel_maps(struct map_groups *self, 19419de89fe7SArnaldo Carvalho de Melo struct map *vmlinux_maps[MAP__NR_TYPES]) 19424aa65636SArnaldo Carvalho de Melo { 19439de89fe7SArnaldo Carvalho de Melo struct dso *kernel = dsos__create_kernel(symbol_conf.vmlinux_name); 19449de89fe7SArnaldo Carvalho de Melo 19459de89fe7SArnaldo Carvalho de Melo if (kernel == NULL) 19464aa65636SArnaldo Carvalho de Melo return -1; 19474aa65636SArnaldo Carvalho de Melo 19489de89fe7SArnaldo Carvalho de Melo if (__map_groups__create_kernel_maps(self, vmlinux_maps, kernel) < 0) 19499de89fe7SArnaldo Carvalho de Melo return -1; 19509de89fe7SArnaldo Carvalho de Melo 19519de89fe7SArnaldo Carvalho de Melo if (symbol_conf.use_modules && map_groups__create_modules(self) < 0) 195210fe12efSArnaldo Carvalho de Melo pr_debug("Problems creating module maps, continuing anyway...\n"); 195390c83218SArnaldo Carvalho de Melo /* 195490c83218SArnaldo Carvalho de Melo * Now that we have all the maps created, just set the ->end of them: 195590c83218SArnaldo Carvalho de Melo */ 19569de89fe7SArnaldo Carvalho de Melo map_groups__fixup_end(self); 19576671cb16SArnaldo Carvalho de Melo return 0; 1958cd84c2acSFrederic Weisbecker } 1959