186470930SIngo Molnar #include "util.h" 286470930SIngo Molnar #include "../perf.h" 34aa65636SArnaldo Carvalho de Melo #include "session.h" 4655000e7SArnaldo Carvalho de Melo #include "sort.h" 586470930SIngo Molnar #include "string.h" 686470930SIngo Molnar #include "symbol.h" 7439d473bSArnaldo Carvalho de Melo #include "thread.h" 886470930SIngo Molnar 98f28827aSFrederic Weisbecker #include "debug.h" 108f28827aSFrederic Weisbecker 11b32d133aSArnaldo Carvalho de Melo #include <asm/bug.h> 1286470930SIngo Molnar #include <libelf.h> 1386470930SIngo Molnar #include <gelf.h> 1486470930SIngo Molnar #include <elf.h> 15f1617b40SArnaldo Carvalho de Melo #include <limits.h> 16439d473bSArnaldo Carvalho de Melo #include <sys/utsname.h> 172cdbc46dSPeter Zijlstra 18c12e15e7SArnaldo Carvalho de Melo #ifndef NT_GNU_BUILD_ID 19c12e15e7SArnaldo Carvalho de Melo #define NT_GNU_BUILD_ID 3 20c12e15e7SArnaldo Carvalho de Melo #endif 21c12e15e7SArnaldo Carvalho de Melo 2294cb9e38SArnaldo Carvalho de Melo enum dso_origin { 2394cb9e38SArnaldo Carvalho de Melo DSO__ORIG_KERNEL = 0, 2494cb9e38SArnaldo Carvalho de Melo DSO__ORIG_JAVA_JIT, 254cf40131SArnaldo Carvalho de Melo DSO__ORIG_BUILD_ID_CACHE, 2694cb9e38SArnaldo Carvalho de Melo DSO__ORIG_FEDORA, 2794cb9e38SArnaldo Carvalho de Melo DSO__ORIG_UBUNTU, 2894cb9e38SArnaldo Carvalho de Melo DSO__ORIG_BUILDID, 2994cb9e38SArnaldo Carvalho de Melo DSO__ORIG_DSO, 30439d473bSArnaldo Carvalho de Melo DSO__ORIG_KMODULE, 3194cb9e38SArnaldo Carvalho de Melo DSO__ORIG_NOT_FOUND, 3294cb9e38SArnaldo Carvalho de Melo }; 3394cb9e38SArnaldo Carvalho de Melo 34b0da954aSArnaldo Carvalho de Melo static void dsos__add(struct list_head *head, struct dso *dso); 353610583cSArnaldo Carvalho de Melo static struct map *map__new2(u64 start, struct dso *dso, enum map_type type); 36c338aee8SArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *self, struct map *map, 374aa65636SArnaldo Carvalho de Melo struct perf_session *session, symbol_filter_t filter); 38cc612d81SArnaldo Carvalho de Melo static int vmlinux_path__nr_entries; 39cc612d81SArnaldo Carvalho de Melo static char **vmlinux_path; 40439d473bSArnaldo Carvalho de Melo 4175be6cf4SArnaldo Carvalho de Melo struct symbol_conf symbol_conf = { 42d599db3fSArnaldo Carvalho de Melo .exclude_other = true, 43b32d133aSArnaldo Carvalho de Melo .use_modules = true, 44b32d133aSArnaldo Carvalho de Melo .try_vmlinux_path = true, 45b32d133aSArnaldo Carvalho de Melo }; 46b32d133aSArnaldo Carvalho de Melo 473610583cSArnaldo Carvalho de Melo bool dso__loaded(const struct dso *self, enum map_type type) 483610583cSArnaldo Carvalho de Melo { 493610583cSArnaldo Carvalho de Melo return self->loaded & (1 << type); 503610583cSArnaldo Carvalho de Melo } 513610583cSArnaldo Carvalho de Melo 5279406cd7SArnaldo Carvalho de Melo bool dso__sorted_by_name(const struct dso *self, enum map_type type) 5379406cd7SArnaldo Carvalho de Melo { 5479406cd7SArnaldo Carvalho de Melo return self->sorted_by_name & (1 << type); 5579406cd7SArnaldo Carvalho de Melo } 5679406cd7SArnaldo Carvalho de Melo 573610583cSArnaldo Carvalho de Melo static void dso__set_loaded(struct dso *self, enum map_type type) 583610583cSArnaldo Carvalho de Melo { 593610583cSArnaldo Carvalho de Melo self->loaded |= (1 << type); 603610583cSArnaldo Carvalho de Melo } 613610583cSArnaldo Carvalho de Melo 6279406cd7SArnaldo Carvalho de Melo static void dso__set_sorted_by_name(struct dso *self, enum map_type type) 6379406cd7SArnaldo Carvalho de Melo { 6479406cd7SArnaldo Carvalho de Melo self->sorted_by_name |= (1 << type); 6579406cd7SArnaldo Carvalho de Melo } 6679406cd7SArnaldo Carvalho de Melo 6736a3e646SArnaldo Carvalho de Melo bool symbol_type__is_a(char symbol_type, enum map_type map_type) 686893d4eeSArnaldo Carvalho de Melo { 696893d4eeSArnaldo Carvalho de Melo switch (map_type) { 706893d4eeSArnaldo Carvalho de Melo case MAP__FUNCTION: 716893d4eeSArnaldo Carvalho de Melo return symbol_type == 'T' || symbol_type == 'W'; 72f1dfa0b1SArnaldo Carvalho de Melo case MAP__VARIABLE: 73f1dfa0b1SArnaldo Carvalho de Melo return symbol_type == 'D' || symbol_type == 'd'; 746893d4eeSArnaldo Carvalho de Melo default: 756893d4eeSArnaldo Carvalho de Melo return false; 766893d4eeSArnaldo Carvalho de Melo } 776893d4eeSArnaldo Carvalho de Melo } 786893d4eeSArnaldo Carvalho de Melo 79fcf1203aSArnaldo Carvalho de Melo static void symbols__fixup_end(struct rb_root *self) 80af427bf5SArnaldo Carvalho de Melo { 81fcf1203aSArnaldo Carvalho de Melo struct rb_node *nd, *prevnd = rb_first(self); 822e538c4aSArnaldo Carvalho de Melo struct symbol *curr, *prev; 83af427bf5SArnaldo Carvalho de Melo 84af427bf5SArnaldo Carvalho de Melo if (prevnd == NULL) 85af427bf5SArnaldo Carvalho de Melo return; 86af427bf5SArnaldo Carvalho de Melo 872e538c4aSArnaldo Carvalho de Melo curr = rb_entry(prevnd, struct symbol, rb_node); 882e538c4aSArnaldo Carvalho de Melo 89af427bf5SArnaldo Carvalho de Melo for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) { 902e538c4aSArnaldo Carvalho de Melo prev = curr; 912e538c4aSArnaldo Carvalho de Melo curr = rb_entry(nd, struct symbol, rb_node); 92af427bf5SArnaldo Carvalho de Melo 93af427bf5SArnaldo Carvalho de Melo if (prev->end == prev->start) 94af427bf5SArnaldo Carvalho de Melo prev->end = curr->start - 1; 95af427bf5SArnaldo Carvalho de Melo } 96af427bf5SArnaldo Carvalho de Melo 972e538c4aSArnaldo Carvalho de Melo /* Last entry */ 982e538c4aSArnaldo Carvalho de Melo if (curr->end == curr->start) 992e538c4aSArnaldo Carvalho de Melo curr->end = roundup(curr->start, 4096); 1002e538c4aSArnaldo Carvalho de Melo } 1012e538c4aSArnaldo Carvalho de Melo 1029958e1f0SArnaldo Carvalho de Melo static void __map_groups__fixup_end(struct map_groups *self, enum map_type type) 103af427bf5SArnaldo Carvalho de Melo { 104af427bf5SArnaldo Carvalho de Melo struct map *prev, *curr; 10595011c60SArnaldo Carvalho de Melo struct rb_node *nd, *prevnd = rb_first(&self->maps[type]); 106af427bf5SArnaldo Carvalho de Melo 107af427bf5SArnaldo Carvalho de Melo if (prevnd == NULL) 108af427bf5SArnaldo Carvalho de Melo return; 109af427bf5SArnaldo Carvalho de Melo 110af427bf5SArnaldo Carvalho de Melo curr = rb_entry(prevnd, struct map, rb_node); 111af427bf5SArnaldo Carvalho de Melo 112af427bf5SArnaldo Carvalho de Melo for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) { 113af427bf5SArnaldo Carvalho de Melo prev = curr; 114af427bf5SArnaldo Carvalho de Melo curr = rb_entry(nd, struct map, rb_node); 115af427bf5SArnaldo Carvalho de Melo prev->end = curr->start - 1; 1162e538c4aSArnaldo Carvalho de Melo } 11790c83218SArnaldo Carvalho de Melo 11890c83218SArnaldo Carvalho de Melo /* 11990c83218SArnaldo Carvalho de Melo * We still haven't the actual symbols, so guess the 12090c83218SArnaldo Carvalho de Melo * last map final address. 12190c83218SArnaldo Carvalho de Melo */ 12290c83218SArnaldo Carvalho de Melo curr->end = ~0UL; 123af427bf5SArnaldo Carvalho de Melo } 124af427bf5SArnaldo Carvalho de Melo 1259958e1f0SArnaldo Carvalho de Melo static void map_groups__fixup_end(struct map_groups *self) 12623ea4a3fSArnaldo Carvalho de Melo { 12723ea4a3fSArnaldo Carvalho de Melo int i; 12823ea4a3fSArnaldo Carvalho de Melo for (i = 0; i < MAP__NR_TYPES; ++i) 1299958e1f0SArnaldo Carvalho de Melo __map_groups__fixup_end(self, i); 13023ea4a3fSArnaldo Carvalho de Melo } 13123ea4a3fSArnaldo Carvalho de Melo 13200a192b3SArnaldo Carvalho de Melo static struct symbol *symbol__new(u64 start, u64 len, const char *name) 13386470930SIngo Molnar { 13486470930SIngo Molnar size_t namelen = strlen(name) + 1; 13575be6cf4SArnaldo Carvalho de Melo struct symbol *self = zalloc(symbol_conf.priv_size + 13636479484SArnaldo Carvalho de Melo sizeof(*self) + namelen); 13736479484SArnaldo Carvalho de Melo if (self == NULL) 13886470930SIngo Molnar return NULL; 13986470930SIngo Molnar 14075be6cf4SArnaldo Carvalho de Melo if (symbol_conf.priv_size) 14175be6cf4SArnaldo Carvalho de Melo self = ((void *)self) + symbol_conf.priv_size; 14236479484SArnaldo Carvalho de Melo 14386470930SIngo Molnar self->start = start; 1446cfcc53eSMike Galbraith self->end = len ? start + len - 1 : start; 145e4204992SArnaldo Carvalho de Melo 1466beba7adSArnaldo Carvalho de Melo pr_debug3("%s: %s %#Lx-%#Lx\n", __func__, name, start, self->end); 147e4204992SArnaldo Carvalho de Melo 14886470930SIngo Molnar memcpy(self->name, name, namelen); 14986470930SIngo Molnar 15086470930SIngo Molnar return self; 15186470930SIngo Molnar } 15286470930SIngo Molnar 15300a192b3SArnaldo Carvalho de Melo static void symbol__delete(struct symbol *self) 15486470930SIngo Molnar { 15575be6cf4SArnaldo Carvalho de Melo free(((void *)self) - symbol_conf.priv_size); 15686470930SIngo Molnar } 15786470930SIngo Molnar 15886470930SIngo Molnar static size_t symbol__fprintf(struct symbol *self, FILE *fp) 15986470930SIngo Molnar { 16086470930SIngo Molnar return fprintf(fp, " %llx-%llx %s\n", 16186470930SIngo Molnar self->start, self->end, self->name); 16286470930SIngo Molnar } 16386470930SIngo Molnar 164b7cece76SArnaldo Carvalho de Melo void dso__set_long_name(struct dso *self, char *name) 165cfc10d3bSArnaldo Carvalho de Melo { 166ef6ae724SArnaldo Carvalho de Melo if (name == NULL) 167ef6ae724SArnaldo Carvalho de Melo return; 168cfc10d3bSArnaldo Carvalho de Melo self->long_name = name; 169cfc10d3bSArnaldo Carvalho de Melo self->long_name_len = strlen(name); 170cfc10d3bSArnaldo Carvalho de Melo } 171cfc10d3bSArnaldo Carvalho de Melo 172cfc10d3bSArnaldo Carvalho de Melo static void dso__set_basename(struct dso *self) 173cfc10d3bSArnaldo Carvalho de Melo { 174cfc10d3bSArnaldo Carvalho de Melo self->short_name = basename(self->long_name); 175cfc10d3bSArnaldo Carvalho de Melo } 176cfc10d3bSArnaldo Carvalho de Melo 17700a192b3SArnaldo Carvalho de Melo struct dso *dso__new(const char *name) 17886470930SIngo Molnar { 179b7cece76SArnaldo Carvalho de Melo struct dso *self = zalloc(sizeof(*self) + strlen(name) + 1); 18086470930SIngo Molnar 18186470930SIngo Molnar if (self != NULL) { 1826a4694a4SArnaldo Carvalho de Melo int i; 18386470930SIngo Molnar strcpy(self->name, name); 184cfc10d3bSArnaldo Carvalho de Melo dso__set_long_name(self, self->name); 185439d473bSArnaldo Carvalho de Melo self->short_name = self->name; 1866a4694a4SArnaldo Carvalho de Melo for (i = 0; i < MAP__NR_TYPES; ++i) 18779406cd7SArnaldo Carvalho de Melo self->symbols[i] = self->symbol_names[i] = RB_ROOT; 18852d422deSArnaldo Carvalho de Melo self->slen_calculated = 0; 18994cb9e38SArnaldo Carvalho de Melo self->origin = DSO__ORIG_NOT_FOUND; 1908d06367fSArnaldo Carvalho de Melo self->loaded = 0; 19179406cd7SArnaldo Carvalho de Melo self->sorted_by_name = 0; 1928d06367fSArnaldo Carvalho de Melo self->has_build_id = 0; 19386470930SIngo Molnar } 19486470930SIngo Molnar 19586470930SIngo Molnar return self; 19686470930SIngo Molnar } 19786470930SIngo Molnar 198fcf1203aSArnaldo Carvalho de Melo static void symbols__delete(struct rb_root *self) 19986470930SIngo Molnar { 20086470930SIngo Molnar struct symbol *pos; 201fcf1203aSArnaldo Carvalho de Melo struct rb_node *next = rb_first(self); 20286470930SIngo Molnar 20386470930SIngo Molnar while (next) { 20486470930SIngo Molnar pos = rb_entry(next, struct symbol, rb_node); 20586470930SIngo Molnar next = rb_next(&pos->rb_node); 206fcf1203aSArnaldo Carvalho de Melo rb_erase(&pos->rb_node, self); 20700a192b3SArnaldo Carvalho de Melo symbol__delete(pos); 20886470930SIngo Molnar } 20986470930SIngo Molnar } 21086470930SIngo Molnar 21186470930SIngo Molnar void dso__delete(struct dso *self) 21286470930SIngo Molnar { 2136a4694a4SArnaldo Carvalho de Melo int i; 2146a4694a4SArnaldo Carvalho de Melo for (i = 0; i < MAP__NR_TYPES; ++i) 2156a4694a4SArnaldo Carvalho de Melo symbols__delete(&self->symbols[i]); 216439d473bSArnaldo Carvalho de Melo if (self->long_name != self->name) 217439d473bSArnaldo Carvalho de Melo free(self->long_name); 21886470930SIngo Molnar free(self); 21986470930SIngo Molnar } 22086470930SIngo Molnar 2218d06367fSArnaldo Carvalho de Melo void dso__set_build_id(struct dso *self, void *build_id) 2228d06367fSArnaldo Carvalho de Melo { 2238d06367fSArnaldo Carvalho de Melo memcpy(self->build_id, build_id, sizeof(self->build_id)); 2248d06367fSArnaldo Carvalho de Melo self->has_build_id = 1; 2258d06367fSArnaldo Carvalho de Melo } 2268d06367fSArnaldo Carvalho de Melo 227fcf1203aSArnaldo Carvalho de Melo static void symbols__insert(struct rb_root *self, struct symbol *sym) 22886470930SIngo Molnar { 229fcf1203aSArnaldo Carvalho de Melo struct rb_node **p = &self->rb_node; 23086470930SIngo Molnar struct rb_node *parent = NULL; 2319cffa8d5SPaul Mackerras const u64 ip = sym->start; 23286470930SIngo Molnar struct symbol *s; 23386470930SIngo Molnar 23486470930SIngo Molnar while (*p != NULL) { 23586470930SIngo Molnar parent = *p; 23686470930SIngo Molnar s = rb_entry(parent, struct symbol, rb_node); 23786470930SIngo Molnar if (ip < s->start) 23886470930SIngo Molnar p = &(*p)->rb_left; 23986470930SIngo Molnar else 24086470930SIngo Molnar p = &(*p)->rb_right; 24186470930SIngo Molnar } 24286470930SIngo Molnar rb_link_node(&sym->rb_node, parent, p); 243fcf1203aSArnaldo Carvalho de Melo rb_insert_color(&sym->rb_node, self); 24486470930SIngo Molnar } 24586470930SIngo Molnar 246fcf1203aSArnaldo Carvalho de Melo static struct symbol *symbols__find(struct rb_root *self, u64 ip) 24786470930SIngo Molnar { 24886470930SIngo Molnar struct rb_node *n; 24986470930SIngo Molnar 25086470930SIngo Molnar if (self == NULL) 25186470930SIngo Molnar return NULL; 25286470930SIngo Molnar 253fcf1203aSArnaldo Carvalho de Melo n = self->rb_node; 25486470930SIngo Molnar 25586470930SIngo Molnar while (n) { 25686470930SIngo Molnar struct symbol *s = rb_entry(n, struct symbol, rb_node); 25786470930SIngo Molnar 25886470930SIngo Molnar if (ip < s->start) 25986470930SIngo Molnar n = n->rb_left; 26086470930SIngo Molnar else if (ip > s->end) 26186470930SIngo Molnar n = n->rb_right; 26286470930SIngo Molnar else 26386470930SIngo Molnar return s; 26486470930SIngo Molnar } 26586470930SIngo Molnar 26686470930SIngo Molnar return NULL; 26786470930SIngo Molnar } 26886470930SIngo Molnar 26979406cd7SArnaldo Carvalho de Melo struct symbol_name_rb_node { 27079406cd7SArnaldo Carvalho de Melo struct rb_node rb_node; 27179406cd7SArnaldo Carvalho de Melo struct symbol sym; 27279406cd7SArnaldo Carvalho de Melo }; 27379406cd7SArnaldo Carvalho de Melo 27479406cd7SArnaldo Carvalho de Melo static void symbols__insert_by_name(struct rb_root *self, struct symbol *sym) 27579406cd7SArnaldo Carvalho de Melo { 27679406cd7SArnaldo Carvalho de Melo struct rb_node **p = &self->rb_node; 27779406cd7SArnaldo Carvalho de Melo struct rb_node *parent = NULL; 27879406cd7SArnaldo Carvalho de Melo struct symbol_name_rb_node *symn = ((void *)sym) - sizeof(*parent), *s; 27979406cd7SArnaldo Carvalho de Melo 28079406cd7SArnaldo Carvalho de Melo while (*p != NULL) { 28179406cd7SArnaldo Carvalho de Melo parent = *p; 28279406cd7SArnaldo Carvalho de Melo s = rb_entry(parent, struct symbol_name_rb_node, rb_node); 28379406cd7SArnaldo Carvalho de Melo if (strcmp(sym->name, s->sym.name) < 0) 28479406cd7SArnaldo Carvalho de Melo p = &(*p)->rb_left; 28579406cd7SArnaldo Carvalho de Melo else 28679406cd7SArnaldo Carvalho de Melo p = &(*p)->rb_right; 28779406cd7SArnaldo Carvalho de Melo } 28879406cd7SArnaldo Carvalho de Melo rb_link_node(&symn->rb_node, parent, p); 28979406cd7SArnaldo Carvalho de Melo rb_insert_color(&symn->rb_node, self); 29079406cd7SArnaldo Carvalho de Melo } 29179406cd7SArnaldo Carvalho de Melo 29279406cd7SArnaldo Carvalho de Melo static void symbols__sort_by_name(struct rb_root *self, struct rb_root *source) 29379406cd7SArnaldo Carvalho de Melo { 29479406cd7SArnaldo Carvalho de Melo struct rb_node *nd; 29579406cd7SArnaldo Carvalho de Melo 29679406cd7SArnaldo Carvalho de Melo for (nd = rb_first(source); nd; nd = rb_next(nd)) { 29779406cd7SArnaldo Carvalho de Melo struct symbol *pos = rb_entry(nd, struct symbol, rb_node); 29879406cd7SArnaldo Carvalho de Melo symbols__insert_by_name(self, pos); 29979406cd7SArnaldo Carvalho de Melo } 30079406cd7SArnaldo Carvalho de Melo } 30179406cd7SArnaldo Carvalho de Melo 30279406cd7SArnaldo Carvalho de Melo static struct symbol *symbols__find_by_name(struct rb_root *self, const char *name) 30379406cd7SArnaldo Carvalho de Melo { 30479406cd7SArnaldo Carvalho de Melo struct rb_node *n; 30579406cd7SArnaldo Carvalho de Melo 30679406cd7SArnaldo Carvalho de Melo if (self == NULL) 30779406cd7SArnaldo Carvalho de Melo return NULL; 30879406cd7SArnaldo Carvalho de Melo 30979406cd7SArnaldo Carvalho de Melo n = self->rb_node; 31079406cd7SArnaldo Carvalho de Melo 31179406cd7SArnaldo Carvalho de Melo while (n) { 31279406cd7SArnaldo Carvalho de Melo struct symbol_name_rb_node *s; 31379406cd7SArnaldo Carvalho de Melo int cmp; 31479406cd7SArnaldo Carvalho de Melo 31579406cd7SArnaldo Carvalho de Melo s = rb_entry(n, struct symbol_name_rb_node, rb_node); 31679406cd7SArnaldo Carvalho de Melo cmp = strcmp(name, s->sym.name); 31779406cd7SArnaldo Carvalho de Melo 31879406cd7SArnaldo Carvalho de Melo if (cmp < 0) 31979406cd7SArnaldo Carvalho de Melo n = n->rb_left; 32079406cd7SArnaldo Carvalho de Melo else if (cmp > 0) 32179406cd7SArnaldo Carvalho de Melo n = n->rb_right; 32279406cd7SArnaldo Carvalho de Melo else 32379406cd7SArnaldo Carvalho de Melo return &s->sym; 32479406cd7SArnaldo Carvalho de Melo } 32579406cd7SArnaldo Carvalho de Melo 32679406cd7SArnaldo Carvalho de Melo return NULL; 32779406cd7SArnaldo Carvalho de Melo } 32879406cd7SArnaldo Carvalho de Melo 32979406cd7SArnaldo Carvalho de Melo struct symbol *dso__find_symbol(struct dso *self, 33079406cd7SArnaldo Carvalho de Melo enum map_type type, u64 addr) 331fcf1203aSArnaldo Carvalho de Melo { 3326a4694a4SArnaldo Carvalho de Melo return symbols__find(&self->symbols[type], addr); 333fcf1203aSArnaldo Carvalho de Melo } 334fcf1203aSArnaldo Carvalho de Melo 33579406cd7SArnaldo Carvalho de Melo struct symbol *dso__find_symbol_by_name(struct dso *self, enum map_type type, 33679406cd7SArnaldo Carvalho de Melo const char *name) 33779406cd7SArnaldo Carvalho de Melo { 33879406cd7SArnaldo Carvalho de Melo return symbols__find_by_name(&self->symbol_names[type], name); 33979406cd7SArnaldo Carvalho de Melo } 34079406cd7SArnaldo Carvalho de Melo 34179406cd7SArnaldo Carvalho de Melo void dso__sort_by_name(struct dso *self, enum map_type type) 34279406cd7SArnaldo Carvalho de Melo { 34379406cd7SArnaldo Carvalho de Melo dso__set_sorted_by_name(self, type); 34479406cd7SArnaldo Carvalho de Melo return symbols__sort_by_name(&self->symbol_names[type], 34579406cd7SArnaldo Carvalho de Melo &self->symbols[type]); 34679406cd7SArnaldo Carvalho de Melo } 34779406cd7SArnaldo Carvalho de Melo 348ef12a141SArnaldo Carvalho de Melo int build_id__sprintf(const u8 *self, int len, char *bf) 3498d06367fSArnaldo Carvalho de Melo { 3508d06367fSArnaldo Carvalho de Melo char *bid = bf; 351ef12a141SArnaldo Carvalho de Melo const u8 *raw = self; 3528d06367fSArnaldo Carvalho de Melo int i; 3538d06367fSArnaldo Carvalho de Melo 3548d06367fSArnaldo Carvalho de Melo for (i = 0; i < len; ++i) { 3558d06367fSArnaldo Carvalho de Melo sprintf(bid, "%02x", *raw); 3568d06367fSArnaldo Carvalho de Melo ++raw; 3578d06367fSArnaldo Carvalho de Melo bid += 2; 3588d06367fSArnaldo Carvalho de Melo } 3598d06367fSArnaldo Carvalho de Melo 3608d06367fSArnaldo Carvalho de Melo return raw - self; 3618d06367fSArnaldo Carvalho de Melo } 3628d06367fSArnaldo Carvalho de Melo 3639e03eb2dSArnaldo Carvalho de Melo size_t dso__fprintf_buildid(struct dso *self, FILE *fp) 36486470930SIngo Molnar { 3658d06367fSArnaldo Carvalho de Melo char sbuild_id[BUILD_ID_SIZE * 2 + 1]; 3668d06367fSArnaldo Carvalho de Melo 3678d06367fSArnaldo Carvalho de Melo build_id__sprintf(self->build_id, sizeof(self->build_id), sbuild_id); 3689e03eb2dSArnaldo Carvalho de Melo return fprintf(fp, "%s", sbuild_id); 3699e03eb2dSArnaldo Carvalho de Melo } 3709e03eb2dSArnaldo Carvalho de Melo 37195011c60SArnaldo Carvalho de Melo size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp) 3729e03eb2dSArnaldo Carvalho de Melo { 3739e03eb2dSArnaldo Carvalho de Melo struct rb_node *nd; 3749e03eb2dSArnaldo Carvalho de Melo size_t ret = fprintf(fp, "dso: %s (", self->short_name); 3759e03eb2dSArnaldo Carvalho de Melo 3769e03eb2dSArnaldo Carvalho de Melo ret += dso__fprintf_buildid(self, fp); 3776a4694a4SArnaldo Carvalho de Melo ret += fprintf(fp, ")\n"); 37895011c60SArnaldo Carvalho de Melo for (nd = rb_first(&self->symbols[type]); nd; nd = rb_next(nd)) { 37986470930SIngo Molnar struct symbol *pos = rb_entry(nd, struct symbol, rb_node); 38086470930SIngo Molnar ret += symbol__fprintf(pos, fp); 38186470930SIngo Molnar } 38286470930SIngo Molnar 38386470930SIngo Molnar return ret; 38486470930SIngo Molnar } 38586470930SIngo Molnar 3869e201442SArnaldo Carvalho de Melo int kallsyms__parse(const char *filename, void *arg, 3879e201442SArnaldo Carvalho de Melo int (*process_symbol)(void *arg, const char *name, 388682b335aSArnaldo Carvalho de Melo char type, u64 start)) 38986470930SIngo Molnar { 39086470930SIngo Molnar char *line = NULL; 39186470930SIngo Molnar size_t n; 392682b335aSArnaldo Carvalho de Melo int err = 0; 3939e201442SArnaldo Carvalho de Melo FILE *file = fopen(filename, "r"); 39486470930SIngo Molnar 39586470930SIngo Molnar if (file == NULL) 39686470930SIngo Molnar goto out_failure; 39786470930SIngo Molnar 39886470930SIngo Molnar while (!feof(file)) { 3999cffa8d5SPaul Mackerras u64 start; 40086470930SIngo Molnar int line_len, len; 40186470930SIngo Molnar char symbol_type; 4022e538c4aSArnaldo Carvalho de Melo char *symbol_name; 40386470930SIngo Molnar 40486470930SIngo Molnar line_len = getline(&line, &n, file); 40586470930SIngo Molnar if (line_len < 0) 40686470930SIngo Molnar break; 40786470930SIngo Molnar 40886470930SIngo Molnar if (!line) 40986470930SIngo Molnar goto out_failure; 41086470930SIngo Molnar 41186470930SIngo Molnar line[--line_len] = '\0'; /* \n */ 41286470930SIngo Molnar 41386470930SIngo Molnar len = hex2u64(line, &start); 41486470930SIngo Molnar 41586470930SIngo Molnar len++; 41686470930SIngo Molnar if (len + 2 >= line_len) 41786470930SIngo Molnar continue; 41886470930SIngo Molnar 41986470930SIngo Molnar symbol_type = toupper(line[len]); 420af427bf5SArnaldo Carvalho de Melo symbol_name = line + len + 2; 421682b335aSArnaldo Carvalho de Melo 422682b335aSArnaldo Carvalho de Melo err = process_symbol(arg, symbol_name, symbol_type, start); 423682b335aSArnaldo Carvalho de Melo if (err) 424682b335aSArnaldo Carvalho de Melo break; 425682b335aSArnaldo Carvalho de Melo } 426682b335aSArnaldo Carvalho de Melo 427682b335aSArnaldo Carvalho de Melo free(line); 428682b335aSArnaldo Carvalho de Melo fclose(file); 429682b335aSArnaldo Carvalho de Melo return err; 430682b335aSArnaldo Carvalho de Melo 431682b335aSArnaldo Carvalho de Melo out_failure: 432682b335aSArnaldo Carvalho de Melo return -1; 433682b335aSArnaldo Carvalho de Melo } 434682b335aSArnaldo Carvalho de Melo 435682b335aSArnaldo Carvalho de Melo struct process_kallsyms_args { 436682b335aSArnaldo Carvalho de Melo struct map *map; 437682b335aSArnaldo Carvalho de Melo struct dso *dso; 438682b335aSArnaldo Carvalho de Melo }; 439682b335aSArnaldo Carvalho de Melo 440682b335aSArnaldo Carvalho de Melo static int map__process_kallsym_symbol(void *arg, const char *name, 441682b335aSArnaldo Carvalho de Melo char type, u64 start) 442682b335aSArnaldo Carvalho de Melo { 443682b335aSArnaldo Carvalho de Melo struct symbol *sym; 444682b335aSArnaldo Carvalho de Melo struct process_kallsyms_args *a = arg; 445682b335aSArnaldo Carvalho de Melo struct rb_root *root = &a->dso->symbols[a->map->type]; 446682b335aSArnaldo Carvalho de Melo 447682b335aSArnaldo Carvalho de Melo if (!symbol_type__is_a(type, a->map->type)) 448682b335aSArnaldo Carvalho de Melo return 0; 449682b335aSArnaldo Carvalho de Melo 4502e538c4aSArnaldo Carvalho de Melo /* 4512e538c4aSArnaldo Carvalho de Melo * Will fix up the end later, when we have all symbols sorted. 4522e538c4aSArnaldo Carvalho de Melo */ 453682b335aSArnaldo Carvalho de Melo sym = symbol__new(start, 0, name); 454af427bf5SArnaldo Carvalho de Melo 4552e538c4aSArnaldo Carvalho de Melo if (sym == NULL) 456682b335aSArnaldo Carvalho de Melo return -ENOMEM; 45782164161SArnaldo Carvalho de Melo /* 45882164161SArnaldo Carvalho de Melo * We will pass the symbols to the filter later, in 4594e06255fSArnaldo Carvalho de Melo * map__split_kallsyms, when we have split the maps per module 46082164161SArnaldo Carvalho de Melo */ 4614e06255fSArnaldo Carvalho de Melo symbols__insert(root, sym); 462682b335aSArnaldo Carvalho de Melo return 0; 4632e538c4aSArnaldo Carvalho de Melo } 4642e538c4aSArnaldo Carvalho de Melo 465682b335aSArnaldo Carvalho de Melo /* 466682b335aSArnaldo Carvalho de Melo * Loads the function entries in /proc/kallsyms into kernel_map->dso, 467682b335aSArnaldo Carvalho de Melo * so that we can in the next step set the symbol ->end address and then 468682b335aSArnaldo Carvalho de Melo * call kernel_maps__split_kallsyms. 469682b335aSArnaldo Carvalho de Melo */ 4709e201442SArnaldo Carvalho de Melo static int dso__load_all_kallsyms(struct dso *self, const char *filename, 4719e201442SArnaldo Carvalho de Melo struct map *map) 472682b335aSArnaldo Carvalho de Melo { 473682b335aSArnaldo Carvalho de Melo struct process_kallsyms_args args = { .map = map, .dso = self, }; 4749e201442SArnaldo Carvalho de Melo return kallsyms__parse(filename, &args, map__process_kallsym_symbol); 4752e538c4aSArnaldo Carvalho de Melo } 4762e538c4aSArnaldo Carvalho de Melo 4772e538c4aSArnaldo Carvalho de Melo /* 4782e538c4aSArnaldo Carvalho de Melo * Split the symbols into maps, making sure there are no overlaps, i.e. the 4792e538c4aSArnaldo Carvalho de Melo * kernel range is broken in several maps, named [kernel].N, as we don't have 4802e538c4aSArnaldo Carvalho de Melo * the original ELF section names vmlinux have. 4812e538c4aSArnaldo Carvalho de Melo */ 4829958e1f0SArnaldo Carvalho de Melo static int dso__split_kallsyms(struct dso *self, struct map *map, 4834aa65636SArnaldo Carvalho de Melo struct perf_session *session, symbol_filter_t filter) 4842e538c4aSArnaldo Carvalho de Melo { 4854e06255fSArnaldo Carvalho de Melo struct map *curr_map = map; 4862e538c4aSArnaldo Carvalho de Melo struct symbol *pos; 4872e538c4aSArnaldo Carvalho de Melo int count = 0; 4884e06255fSArnaldo Carvalho de Melo struct rb_root *root = &self->symbols[map->type]; 4894e06255fSArnaldo Carvalho de Melo struct rb_node *next = rb_first(root); 4902e538c4aSArnaldo Carvalho de Melo int kernel_range = 0; 4912e538c4aSArnaldo Carvalho de Melo 4922e538c4aSArnaldo Carvalho de Melo while (next) { 4932e538c4aSArnaldo Carvalho de Melo char *module; 4942e538c4aSArnaldo Carvalho de Melo 4952e538c4aSArnaldo Carvalho de Melo pos = rb_entry(next, struct symbol, rb_node); 4962e538c4aSArnaldo Carvalho de Melo next = rb_next(&pos->rb_node); 4972e538c4aSArnaldo Carvalho de Melo 4982e538c4aSArnaldo Carvalho de Melo module = strchr(pos->name, '\t'); 4992e538c4aSArnaldo Carvalho de Melo if (module) { 50075be6cf4SArnaldo Carvalho de Melo if (!symbol_conf.use_modules) 5011de8e245SArnaldo Carvalho de Melo goto discard_symbol; 5021de8e245SArnaldo Carvalho de Melo 5032e538c4aSArnaldo Carvalho de Melo *module++ = '\0'; 5042e538c4aSArnaldo Carvalho de Melo 505b7cece76SArnaldo Carvalho de Melo if (strcmp(curr_map->dso->short_name, module)) { 5064aa65636SArnaldo Carvalho de Melo curr_map = map_groups__find_by_name(&session->kmaps, map->type, module); 5074e06255fSArnaldo Carvalho de Melo if (curr_map == NULL) { 50895011c60SArnaldo Carvalho de Melo pr_debug("/proc/{kallsyms,modules} " 509b7cece76SArnaldo Carvalho de Melo "inconsistency while looking " 510b7cece76SArnaldo Carvalho de Melo "for \"%s\" module!\n", module); 511af427bf5SArnaldo Carvalho de Melo return -1; 512af427bf5SArnaldo Carvalho de Melo } 513b7cece76SArnaldo Carvalho de Melo 514b7cece76SArnaldo Carvalho de Melo if (curr_map->dso->loaded) 515b7cece76SArnaldo Carvalho de Melo goto discard_symbol; 516af427bf5SArnaldo Carvalho de Melo } 51786470930SIngo Molnar /* 5182e538c4aSArnaldo Carvalho de Melo * So that we look just like we get from .ko files, 5192e538c4aSArnaldo Carvalho de Melo * i.e. not prelinked, relative to map->start. 52086470930SIngo Molnar */ 5214e06255fSArnaldo Carvalho de Melo pos->start = curr_map->map_ip(curr_map, pos->start); 5224e06255fSArnaldo Carvalho de Melo pos->end = curr_map->map_ip(curr_map, pos->end); 5234e06255fSArnaldo Carvalho de Melo } else if (curr_map != map) { 5242e538c4aSArnaldo Carvalho de Melo char dso_name[PATH_MAX]; 5252e538c4aSArnaldo Carvalho de Melo struct dso *dso; 52686470930SIngo Molnar 5272e538c4aSArnaldo Carvalho de Melo snprintf(dso_name, sizeof(dso_name), "[kernel].%d", 5282e538c4aSArnaldo Carvalho de Melo kernel_range++); 52986470930SIngo Molnar 53000a192b3SArnaldo Carvalho de Melo dso = dso__new(dso_name); 5312e538c4aSArnaldo Carvalho de Melo if (dso == NULL) 5322e538c4aSArnaldo Carvalho de Melo return -1; 5332e538c4aSArnaldo Carvalho de Melo 5344e06255fSArnaldo Carvalho de Melo curr_map = map__new2(pos->start, dso, map->type); 5352e538c4aSArnaldo Carvalho de Melo if (map == NULL) { 5362e538c4aSArnaldo Carvalho de Melo dso__delete(dso); 5372e538c4aSArnaldo Carvalho de Melo return -1; 5382e538c4aSArnaldo Carvalho de Melo } 5392e538c4aSArnaldo Carvalho de Melo 5404e06255fSArnaldo Carvalho de Melo curr_map->map_ip = curr_map->unmap_ip = identity__map_ip; 5414aa65636SArnaldo Carvalho de Melo map_groups__insert(&session->kmaps, curr_map); 5422e538c4aSArnaldo Carvalho de Melo ++kernel_range; 5432e538c4aSArnaldo Carvalho de Melo } 5442e538c4aSArnaldo Carvalho de Melo 5454e06255fSArnaldo Carvalho de Melo if (filter && filter(curr_map, pos)) { 5461de8e245SArnaldo Carvalho de Melo discard_symbol: rb_erase(&pos->rb_node, root); 54700a192b3SArnaldo Carvalho de Melo symbol__delete(pos); 5482e538c4aSArnaldo Carvalho de Melo } else { 5494e06255fSArnaldo Carvalho de Melo if (curr_map != map) { 5504e06255fSArnaldo Carvalho de Melo rb_erase(&pos->rb_node, root); 5514e06255fSArnaldo Carvalho de Melo symbols__insert(&curr_map->dso->symbols[curr_map->type], pos); 5522e538c4aSArnaldo Carvalho de Melo } 5539974f496SMike Galbraith count++; 5549974f496SMike Galbraith } 55586470930SIngo Molnar } 55686470930SIngo Molnar 5579974f496SMike Galbraith return count; 55886470930SIngo Molnar } 55986470930SIngo Molnar 5602e538c4aSArnaldo Carvalho de Melo 5619e201442SArnaldo Carvalho de Melo static int dso__load_kallsyms(struct dso *self, const char *filename, struct map *map, 5624aa65636SArnaldo Carvalho de Melo struct perf_session *session, symbol_filter_t filter) 5632e538c4aSArnaldo Carvalho de Melo { 5649e201442SArnaldo Carvalho de Melo if (dso__load_all_kallsyms(self, filename, map) < 0) 5652e538c4aSArnaldo Carvalho de Melo return -1; 5662e538c4aSArnaldo Carvalho de Melo 5674e06255fSArnaldo Carvalho de Melo symbols__fixup_end(&self->symbols[map->type]); 5684e06255fSArnaldo Carvalho de Melo self->origin = DSO__ORIG_KERNEL; 5692e538c4aSArnaldo Carvalho de Melo 5704aa65636SArnaldo Carvalho de Melo return dso__split_kallsyms(self, map, session, filter); 571af427bf5SArnaldo Carvalho de Melo } 572af427bf5SArnaldo Carvalho de Melo 573439d473bSArnaldo Carvalho de Melo static int dso__load_perf_map(struct dso *self, struct map *map, 5746beba7adSArnaldo Carvalho de Melo symbol_filter_t filter) 57580d496beSPekka Enberg { 57680d496beSPekka Enberg char *line = NULL; 57780d496beSPekka Enberg size_t n; 57880d496beSPekka Enberg FILE *file; 57980d496beSPekka Enberg int nr_syms = 0; 58080d496beSPekka Enberg 581439d473bSArnaldo Carvalho de Melo file = fopen(self->long_name, "r"); 58280d496beSPekka Enberg if (file == NULL) 58380d496beSPekka Enberg goto out_failure; 58480d496beSPekka Enberg 58580d496beSPekka Enberg while (!feof(file)) { 5869cffa8d5SPaul Mackerras u64 start, size; 58780d496beSPekka Enberg struct symbol *sym; 58880d496beSPekka Enberg int line_len, len; 58980d496beSPekka Enberg 59080d496beSPekka Enberg line_len = getline(&line, &n, file); 59180d496beSPekka Enberg if (line_len < 0) 59280d496beSPekka Enberg break; 59380d496beSPekka Enberg 59480d496beSPekka Enberg if (!line) 59580d496beSPekka Enberg goto out_failure; 59680d496beSPekka Enberg 59780d496beSPekka Enberg line[--line_len] = '\0'; /* \n */ 59880d496beSPekka Enberg 59980d496beSPekka Enberg len = hex2u64(line, &start); 60080d496beSPekka Enberg 60180d496beSPekka Enberg len++; 60280d496beSPekka Enberg if (len + 2 >= line_len) 60380d496beSPekka Enberg continue; 60480d496beSPekka Enberg 60580d496beSPekka Enberg len += hex2u64(line + len, &size); 60680d496beSPekka Enberg 60780d496beSPekka Enberg len++; 60880d496beSPekka Enberg if (len + 2 >= line_len) 60980d496beSPekka Enberg continue; 61080d496beSPekka Enberg 61100a192b3SArnaldo Carvalho de Melo sym = symbol__new(start, size, line + len); 61280d496beSPekka Enberg 61380d496beSPekka Enberg if (sym == NULL) 61480d496beSPekka Enberg goto out_delete_line; 61580d496beSPekka Enberg 616439d473bSArnaldo Carvalho de Melo if (filter && filter(map, sym)) 61700a192b3SArnaldo Carvalho de Melo symbol__delete(sym); 61880d496beSPekka Enberg else { 6196a4694a4SArnaldo Carvalho de Melo symbols__insert(&self->symbols[map->type], sym); 62080d496beSPekka Enberg nr_syms++; 62180d496beSPekka Enberg } 62280d496beSPekka Enberg } 62380d496beSPekka Enberg 62480d496beSPekka Enberg free(line); 62580d496beSPekka Enberg fclose(file); 62680d496beSPekka Enberg 62780d496beSPekka Enberg return nr_syms; 62880d496beSPekka Enberg 62980d496beSPekka Enberg out_delete_line: 63080d496beSPekka Enberg free(line); 63180d496beSPekka Enberg out_failure: 63280d496beSPekka Enberg return -1; 63380d496beSPekka Enberg } 63480d496beSPekka Enberg 63586470930SIngo Molnar /** 63686470930SIngo Molnar * elf_symtab__for_each_symbol - iterate thru all the symbols 63786470930SIngo Molnar * 63886470930SIngo Molnar * @self: struct elf_symtab instance to iterate 63983a0944fSIngo Molnar * @idx: uint32_t idx 64086470930SIngo Molnar * @sym: GElf_Sym iterator 64186470930SIngo Molnar */ 64283a0944fSIngo Molnar #define elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) \ 64383a0944fSIngo Molnar for (idx = 0, gelf_getsym(syms, idx, &sym);\ 64483a0944fSIngo Molnar idx < nr_syms; \ 64583a0944fSIngo Molnar idx++, gelf_getsym(syms, idx, &sym)) 64686470930SIngo Molnar 64786470930SIngo Molnar static inline uint8_t elf_sym__type(const GElf_Sym *sym) 64886470930SIngo Molnar { 64986470930SIngo Molnar return GELF_ST_TYPE(sym->st_info); 65086470930SIngo Molnar } 65186470930SIngo Molnar 65286470930SIngo Molnar static inline int elf_sym__is_function(const GElf_Sym *sym) 65386470930SIngo Molnar { 65486470930SIngo Molnar return elf_sym__type(sym) == STT_FUNC && 65586470930SIngo Molnar sym->st_name != 0 && 65681833130SArnaldo Carvalho de Melo sym->st_shndx != SHN_UNDEF; 65786470930SIngo Molnar } 65886470930SIngo Molnar 659f1dfa0b1SArnaldo Carvalho de Melo static inline bool elf_sym__is_object(const GElf_Sym *sym) 660f1dfa0b1SArnaldo Carvalho de Melo { 661f1dfa0b1SArnaldo Carvalho de Melo return elf_sym__type(sym) == STT_OBJECT && 662f1dfa0b1SArnaldo Carvalho de Melo sym->st_name != 0 && 663f1dfa0b1SArnaldo Carvalho de Melo sym->st_shndx != SHN_UNDEF; 664f1dfa0b1SArnaldo Carvalho de Melo } 665f1dfa0b1SArnaldo Carvalho de Melo 6666cfcc53eSMike Galbraith static inline int elf_sym__is_label(const GElf_Sym *sym) 6676cfcc53eSMike Galbraith { 6686cfcc53eSMike Galbraith return elf_sym__type(sym) == STT_NOTYPE && 6696cfcc53eSMike Galbraith sym->st_name != 0 && 6706cfcc53eSMike Galbraith sym->st_shndx != SHN_UNDEF && 6716cfcc53eSMike Galbraith sym->st_shndx != SHN_ABS; 6726cfcc53eSMike Galbraith } 6736cfcc53eSMike Galbraith 6746cfcc53eSMike Galbraith static inline const char *elf_sec__name(const GElf_Shdr *shdr, 6756cfcc53eSMike Galbraith const Elf_Data *secstrs) 6766cfcc53eSMike Galbraith { 6776cfcc53eSMike Galbraith return secstrs->d_buf + shdr->sh_name; 6786cfcc53eSMike Galbraith } 6796cfcc53eSMike Galbraith 6806cfcc53eSMike Galbraith static inline int elf_sec__is_text(const GElf_Shdr *shdr, 6816cfcc53eSMike Galbraith const Elf_Data *secstrs) 6826cfcc53eSMike Galbraith { 6836cfcc53eSMike Galbraith return strstr(elf_sec__name(shdr, secstrs), "text") != NULL; 6846cfcc53eSMike Galbraith } 6856cfcc53eSMike Galbraith 686f1dfa0b1SArnaldo Carvalho de Melo static inline bool elf_sec__is_data(const GElf_Shdr *shdr, 687f1dfa0b1SArnaldo Carvalho de Melo const Elf_Data *secstrs) 688f1dfa0b1SArnaldo Carvalho de Melo { 689f1dfa0b1SArnaldo Carvalho de Melo return strstr(elf_sec__name(shdr, secstrs), "data") != NULL; 690f1dfa0b1SArnaldo Carvalho de Melo } 691f1dfa0b1SArnaldo Carvalho de Melo 69286470930SIngo Molnar static inline const char *elf_sym__name(const GElf_Sym *sym, 69386470930SIngo Molnar const Elf_Data *symstrs) 69486470930SIngo Molnar { 69586470930SIngo Molnar return symstrs->d_buf + sym->st_name; 69686470930SIngo Molnar } 69786470930SIngo Molnar 69886470930SIngo Molnar static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, 69986470930SIngo Molnar GElf_Shdr *shp, const char *name, 70083a0944fSIngo Molnar size_t *idx) 70186470930SIngo Molnar { 70286470930SIngo Molnar Elf_Scn *sec = NULL; 70386470930SIngo Molnar size_t cnt = 1; 70486470930SIngo Molnar 70586470930SIngo Molnar while ((sec = elf_nextscn(elf, sec)) != NULL) { 70686470930SIngo Molnar char *str; 70786470930SIngo Molnar 70886470930SIngo Molnar gelf_getshdr(sec, shp); 70986470930SIngo Molnar str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name); 71086470930SIngo Molnar if (!strcmp(name, str)) { 71183a0944fSIngo Molnar if (idx) 71283a0944fSIngo Molnar *idx = cnt; 71386470930SIngo Molnar break; 71486470930SIngo Molnar } 71586470930SIngo Molnar ++cnt; 71686470930SIngo Molnar } 71786470930SIngo Molnar 71886470930SIngo Molnar return sec; 71986470930SIngo Molnar } 72086470930SIngo Molnar 72186470930SIngo Molnar #define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \ 72286470930SIngo Molnar for (idx = 0, pos = gelf_getrel(reldata, 0, &pos_mem); \ 72386470930SIngo Molnar idx < nr_entries; \ 72486470930SIngo Molnar ++idx, pos = gelf_getrel(reldata, idx, &pos_mem)) 72586470930SIngo Molnar 72686470930SIngo Molnar #define elf_section__for_each_rela(reldata, pos, pos_mem, idx, nr_entries) \ 72786470930SIngo Molnar for (idx = 0, pos = gelf_getrela(reldata, 0, &pos_mem); \ 72886470930SIngo Molnar idx < nr_entries; \ 72986470930SIngo Molnar ++idx, pos = gelf_getrela(reldata, idx, &pos_mem)) 73086470930SIngo Molnar 731a25e46c4SArnaldo Carvalho de Melo /* 732a25e46c4SArnaldo Carvalho de Melo * We need to check if we have a .dynsym, so that we can handle the 733a25e46c4SArnaldo Carvalho de Melo * .plt, synthesizing its symbols, that aren't on the symtabs (be it 734a25e46c4SArnaldo Carvalho de Melo * .dynsym or .symtab). 735a25e46c4SArnaldo Carvalho de Melo * And always look at the original dso, not at debuginfo packages, that 736a25e46c4SArnaldo Carvalho de Melo * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS). 737a25e46c4SArnaldo Carvalho de Melo */ 73882164161SArnaldo Carvalho de Melo static int dso__synthesize_plt_symbols(struct dso *self, struct map *map, 73982164161SArnaldo Carvalho de Melo symbol_filter_t filter) 74086470930SIngo Molnar { 74186470930SIngo Molnar uint32_t nr_rel_entries, idx; 74286470930SIngo Molnar GElf_Sym sym; 7439cffa8d5SPaul Mackerras u64 plt_offset; 74486470930SIngo Molnar GElf_Shdr shdr_plt; 74586470930SIngo Molnar struct symbol *f; 746a25e46c4SArnaldo Carvalho de Melo GElf_Shdr shdr_rel_plt, shdr_dynsym; 74786470930SIngo Molnar Elf_Data *reldata, *syms, *symstrs; 748a25e46c4SArnaldo Carvalho de Melo Elf_Scn *scn_plt_rel, *scn_symstrs, *scn_dynsym; 749a25e46c4SArnaldo Carvalho de Melo size_t dynsym_idx; 750a25e46c4SArnaldo Carvalho de Melo GElf_Ehdr ehdr; 75186470930SIngo Molnar char sympltname[1024]; 752a25e46c4SArnaldo Carvalho de Melo Elf *elf; 753a25e46c4SArnaldo Carvalho de Melo int nr = 0, symidx, fd, err = 0; 75486470930SIngo Molnar 755439d473bSArnaldo Carvalho de Melo fd = open(self->long_name, O_RDONLY); 756a25e46c4SArnaldo Carvalho de Melo if (fd < 0) 757a25e46c4SArnaldo Carvalho de Melo goto out; 758a25e46c4SArnaldo Carvalho de Melo 75984087126SMarti Raudsepp elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 760a25e46c4SArnaldo Carvalho de Melo if (elf == NULL) 761a25e46c4SArnaldo Carvalho de Melo goto out_close; 762a25e46c4SArnaldo Carvalho de Melo 763a25e46c4SArnaldo Carvalho de Melo if (gelf_getehdr(elf, &ehdr) == NULL) 764a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 765a25e46c4SArnaldo Carvalho de Melo 766a25e46c4SArnaldo Carvalho de Melo scn_dynsym = elf_section_by_name(elf, &ehdr, &shdr_dynsym, 767a25e46c4SArnaldo Carvalho de Melo ".dynsym", &dynsym_idx); 768a25e46c4SArnaldo Carvalho de Melo if (scn_dynsym == NULL) 769a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 770a25e46c4SArnaldo Carvalho de Melo 771a25e46c4SArnaldo Carvalho de Melo scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt, 77286470930SIngo Molnar ".rela.plt", NULL); 77386470930SIngo Molnar if (scn_plt_rel == NULL) { 774a25e46c4SArnaldo Carvalho de Melo scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt, 77586470930SIngo Molnar ".rel.plt", NULL); 77686470930SIngo Molnar if (scn_plt_rel == NULL) 777a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 77886470930SIngo Molnar } 77986470930SIngo Molnar 780a25e46c4SArnaldo Carvalho de Melo err = -1; 78186470930SIngo Molnar 782a25e46c4SArnaldo Carvalho de Melo if (shdr_rel_plt.sh_link != dynsym_idx) 783a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 784a25e46c4SArnaldo Carvalho de Melo 785a25e46c4SArnaldo Carvalho de Melo if (elf_section_by_name(elf, &ehdr, &shdr_plt, ".plt", NULL) == NULL) 786a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 78786470930SIngo Molnar 78886470930SIngo Molnar /* 78983a0944fSIngo Molnar * Fetch the relocation section to find the idxes to the GOT 79086470930SIngo Molnar * and the symbols in the .dynsym they refer to. 79186470930SIngo Molnar */ 79286470930SIngo Molnar reldata = elf_getdata(scn_plt_rel, NULL); 79386470930SIngo Molnar if (reldata == NULL) 794a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 79586470930SIngo Molnar 79686470930SIngo Molnar syms = elf_getdata(scn_dynsym, NULL); 79786470930SIngo Molnar if (syms == NULL) 798a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 79986470930SIngo Molnar 800a25e46c4SArnaldo Carvalho de Melo scn_symstrs = elf_getscn(elf, shdr_dynsym.sh_link); 80186470930SIngo Molnar if (scn_symstrs == NULL) 802a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 80386470930SIngo Molnar 80486470930SIngo Molnar symstrs = elf_getdata(scn_symstrs, NULL); 80586470930SIngo Molnar if (symstrs == NULL) 806a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 80786470930SIngo Molnar 80886470930SIngo Molnar nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize; 80986470930SIngo Molnar plt_offset = shdr_plt.sh_offset; 81086470930SIngo Molnar 81186470930SIngo Molnar if (shdr_rel_plt.sh_type == SHT_RELA) { 81286470930SIngo Molnar GElf_Rela pos_mem, *pos; 81386470930SIngo Molnar 81486470930SIngo Molnar elf_section__for_each_rela(reldata, pos, pos_mem, idx, 81586470930SIngo Molnar nr_rel_entries) { 81686470930SIngo Molnar symidx = GELF_R_SYM(pos->r_info); 81786470930SIngo Molnar plt_offset += shdr_plt.sh_entsize; 81886470930SIngo Molnar gelf_getsym(syms, symidx, &sym); 81986470930SIngo Molnar snprintf(sympltname, sizeof(sympltname), 82086470930SIngo Molnar "%s@plt", elf_sym__name(&sym, symstrs)); 82186470930SIngo Molnar 82286470930SIngo Molnar f = symbol__new(plt_offset, shdr_plt.sh_entsize, 82300a192b3SArnaldo Carvalho de Melo sympltname); 82486470930SIngo Molnar if (!f) 825a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 82686470930SIngo Molnar 82782164161SArnaldo Carvalho de Melo if (filter && filter(map, f)) 82882164161SArnaldo Carvalho de Melo symbol__delete(f); 82982164161SArnaldo Carvalho de Melo else { 8306a4694a4SArnaldo Carvalho de Melo symbols__insert(&self->symbols[map->type], f); 83186470930SIngo Molnar ++nr; 83286470930SIngo Molnar } 83382164161SArnaldo Carvalho de Melo } 83486470930SIngo Molnar } else if (shdr_rel_plt.sh_type == SHT_REL) { 83586470930SIngo Molnar GElf_Rel pos_mem, *pos; 83686470930SIngo Molnar elf_section__for_each_rel(reldata, pos, pos_mem, idx, 83786470930SIngo Molnar nr_rel_entries) { 83886470930SIngo Molnar symidx = GELF_R_SYM(pos->r_info); 83986470930SIngo Molnar plt_offset += shdr_plt.sh_entsize; 84086470930SIngo Molnar gelf_getsym(syms, symidx, &sym); 84186470930SIngo Molnar snprintf(sympltname, sizeof(sympltname), 84286470930SIngo Molnar "%s@plt", elf_sym__name(&sym, symstrs)); 84386470930SIngo Molnar 84486470930SIngo Molnar f = symbol__new(plt_offset, shdr_plt.sh_entsize, 84500a192b3SArnaldo Carvalho de Melo sympltname); 84686470930SIngo Molnar if (!f) 847a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 84886470930SIngo Molnar 84982164161SArnaldo Carvalho de Melo if (filter && filter(map, f)) 85082164161SArnaldo Carvalho de Melo symbol__delete(f); 85182164161SArnaldo Carvalho de Melo else { 8526a4694a4SArnaldo Carvalho de Melo symbols__insert(&self->symbols[map->type], f); 85386470930SIngo Molnar ++nr; 85486470930SIngo Molnar } 85586470930SIngo Molnar } 85682164161SArnaldo Carvalho de Melo } 85786470930SIngo Molnar 858a25e46c4SArnaldo Carvalho de Melo err = 0; 859a25e46c4SArnaldo Carvalho de Melo out_elf_end: 860a25e46c4SArnaldo Carvalho de Melo elf_end(elf); 861a25e46c4SArnaldo Carvalho de Melo out_close: 862a25e46c4SArnaldo Carvalho de Melo close(fd); 863a25e46c4SArnaldo Carvalho de Melo 864a25e46c4SArnaldo Carvalho de Melo if (err == 0) 86586470930SIngo Molnar return nr; 866a25e46c4SArnaldo Carvalho de Melo out: 8676beba7adSArnaldo Carvalho de Melo pr_warning("%s: problems reading %s PLT info.\n", 868439d473bSArnaldo Carvalho de Melo __func__, self->long_name); 869a25e46c4SArnaldo Carvalho de Melo return 0; 87086470930SIngo Molnar } 87186470930SIngo Molnar 872d45868d3SArnaldo Carvalho de Melo static bool elf_sym__is_a(GElf_Sym *self, enum map_type type) 873d45868d3SArnaldo Carvalho de Melo { 874d45868d3SArnaldo Carvalho de Melo switch (type) { 875d45868d3SArnaldo Carvalho de Melo case MAP__FUNCTION: 876d45868d3SArnaldo Carvalho de Melo return elf_sym__is_function(self); 877f1dfa0b1SArnaldo Carvalho de Melo case MAP__VARIABLE: 878f1dfa0b1SArnaldo Carvalho de Melo return elf_sym__is_object(self); 879d45868d3SArnaldo Carvalho de Melo default: 880d45868d3SArnaldo Carvalho de Melo return false; 881d45868d3SArnaldo Carvalho de Melo } 882d45868d3SArnaldo Carvalho de Melo } 883d45868d3SArnaldo Carvalho de Melo 884d45868d3SArnaldo Carvalho de Melo static bool elf_sec__is_a(GElf_Shdr *self, Elf_Data *secstrs, enum map_type type) 885d45868d3SArnaldo Carvalho de Melo { 886d45868d3SArnaldo Carvalho de Melo switch (type) { 887d45868d3SArnaldo Carvalho de Melo case MAP__FUNCTION: 888d45868d3SArnaldo Carvalho de Melo return elf_sec__is_text(self, secstrs); 889f1dfa0b1SArnaldo Carvalho de Melo case MAP__VARIABLE: 890f1dfa0b1SArnaldo Carvalho de Melo return elf_sec__is_data(self, secstrs); 891d45868d3SArnaldo Carvalho de Melo default: 892d45868d3SArnaldo Carvalho de Melo return false; 893d45868d3SArnaldo Carvalho de Melo } 894d45868d3SArnaldo Carvalho de Melo } 895d45868d3SArnaldo Carvalho de Melo 89695011c60SArnaldo Carvalho de Melo static int dso__load_sym(struct dso *self, struct map *map, 8974aa65636SArnaldo Carvalho de Melo struct perf_session *session, const char *name, int fd, 89895011c60SArnaldo Carvalho de Melo symbol_filter_t filter, int kernel, int kmodule) 89986470930SIngo Molnar { 9002e538c4aSArnaldo Carvalho de Melo struct map *curr_map = map; 9012e538c4aSArnaldo Carvalho de Melo struct dso *curr_dso = self; 9022e538c4aSArnaldo Carvalho de Melo size_t dso_name_len = strlen(self->short_name); 9036cfcc53eSMike Galbraith Elf_Data *symstrs, *secstrs; 90486470930SIngo Molnar uint32_t nr_syms; 90586470930SIngo Molnar int err = -1; 90683a0944fSIngo Molnar uint32_t idx; 90786470930SIngo Molnar GElf_Ehdr ehdr; 90886470930SIngo Molnar GElf_Shdr shdr; 90986470930SIngo Molnar Elf_Data *syms; 91086470930SIngo Molnar GElf_Sym sym; 911a25e46c4SArnaldo Carvalho de Melo Elf_Scn *sec, *sec_strndx; 91286470930SIngo Molnar Elf *elf; 913439d473bSArnaldo Carvalho de Melo int nr = 0; 91486470930SIngo Molnar 91584087126SMarti Raudsepp elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 91686470930SIngo Molnar if (elf == NULL) { 9176beba7adSArnaldo Carvalho de Melo pr_err("%s: cannot read %s ELF file.\n", __func__, name); 91886470930SIngo Molnar goto out_close; 91986470930SIngo Molnar } 92086470930SIngo Molnar 92186470930SIngo Molnar if (gelf_getehdr(elf, &ehdr) == NULL) { 9226beba7adSArnaldo Carvalho de Melo pr_err("%s: cannot get elf header.\n", __func__); 92386470930SIngo Molnar goto out_elf_end; 92486470930SIngo Molnar } 92586470930SIngo Molnar 92686470930SIngo Molnar sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL); 92786470930SIngo Molnar if (sec == NULL) { 928a25e46c4SArnaldo Carvalho de Melo sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL); 929a25e46c4SArnaldo Carvalho de Melo if (sec == NULL) 93086470930SIngo Molnar goto out_elf_end; 93186470930SIngo Molnar } 93286470930SIngo Molnar 93386470930SIngo Molnar syms = elf_getdata(sec, NULL); 93486470930SIngo Molnar if (syms == NULL) 93586470930SIngo Molnar goto out_elf_end; 93686470930SIngo Molnar 93786470930SIngo Molnar sec = elf_getscn(elf, shdr.sh_link); 93886470930SIngo Molnar if (sec == NULL) 93986470930SIngo Molnar goto out_elf_end; 94086470930SIngo Molnar 94186470930SIngo Molnar symstrs = elf_getdata(sec, NULL); 94286470930SIngo Molnar if (symstrs == NULL) 94386470930SIngo Molnar goto out_elf_end; 94486470930SIngo Molnar 9456cfcc53eSMike Galbraith sec_strndx = elf_getscn(elf, ehdr.e_shstrndx); 9466cfcc53eSMike Galbraith if (sec_strndx == NULL) 9476cfcc53eSMike Galbraith goto out_elf_end; 9486cfcc53eSMike Galbraith 9496cfcc53eSMike Galbraith secstrs = elf_getdata(sec_strndx, NULL); 9509b30a26bSStoyan Gaydarov if (secstrs == NULL) 9516cfcc53eSMike Galbraith goto out_elf_end; 9526cfcc53eSMike Galbraith 95386470930SIngo Molnar nr_syms = shdr.sh_size / shdr.sh_entsize; 95486470930SIngo Molnar 955e9fbc9dcSArjan van de Ven memset(&sym, 0, sizeof(sym)); 956d20ff6bdSMike Galbraith if (!kernel) { 95730d7a77dSArnaldo Carvalho de Melo self->adjust_symbols = (ehdr.e_type == ET_EXEC || 95830d7a77dSArnaldo Carvalho de Melo elf_section_by_name(elf, &ehdr, &shdr, 959f5812a7aSArnaldo Carvalho de Melo ".gnu.prelink_undo", 96030d7a77dSArnaldo Carvalho de Melo NULL) != NULL); 961d20ff6bdSMike Galbraith } else self->adjust_symbols = 0; 962d20ff6bdSMike Galbraith 96383a0944fSIngo Molnar elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) { 96486470930SIngo Molnar struct symbol *f; 96556b03f3cSArnaldo Carvalho de Melo const char *elf_name = elf_sym__name(&sym, symstrs); 9662e538c4aSArnaldo Carvalho de Melo char *demangled = NULL; 9676cfcc53eSMike Galbraith int is_label = elf_sym__is_label(&sym); 9686cfcc53eSMike Galbraith const char *section_name; 96986470930SIngo Molnar 97056b03f3cSArnaldo Carvalho de Melo if (kernel && session->ref_reloc_sym.name != NULL && 97156b03f3cSArnaldo Carvalho de Melo strcmp(elf_name, session->ref_reloc_sym.name) == 0) 97256b03f3cSArnaldo Carvalho de Melo perf_session__reloc_vmlinux_maps(session, sym.st_value); 97356b03f3cSArnaldo Carvalho de Melo 974d45868d3SArnaldo Carvalho de Melo if (!is_label && !elf_sym__is_a(&sym, map->type)) 97586470930SIngo Molnar continue; 97686470930SIngo Molnar 97786470930SIngo Molnar sec = elf_getscn(elf, sym.st_shndx); 97886470930SIngo Molnar if (!sec) 97986470930SIngo Molnar goto out_elf_end; 98086470930SIngo Molnar 98186470930SIngo Molnar gelf_getshdr(sec, &shdr); 9826cfcc53eSMike Galbraith 983d45868d3SArnaldo Carvalho de Melo if (is_label && !elf_sec__is_a(&shdr, secstrs, map->type)) 9846cfcc53eSMike Galbraith continue; 9856cfcc53eSMike Galbraith 9866cfcc53eSMike Galbraith section_name = elf_sec__name(&shdr, secstrs); 98786470930SIngo Molnar 9882e538c4aSArnaldo Carvalho de Melo if (kernel || kmodule) { 9892e538c4aSArnaldo Carvalho de Melo char dso_name[PATH_MAX]; 9902e538c4aSArnaldo Carvalho de Melo 9912e538c4aSArnaldo Carvalho de Melo if (strcmp(section_name, 9922e538c4aSArnaldo Carvalho de Melo curr_dso->short_name + dso_name_len) == 0) 9932e538c4aSArnaldo Carvalho de Melo goto new_symbol; 9942e538c4aSArnaldo Carvalho de Melo 9952e538c4aSArnaldo Carvalho de Melo if (strcmp(section_name, ".text") == 0) { 9962e538c4aSArnaldo Carvalho de Melo curr_map = map; 9972e538c4aSArnaldo Carvalho de Melo curr_dso = self; 9982e538c4aSArnaldo Carvalho de Melo goto new_symbol; 999af427bf5SArnaldo Carvalho de Melo } 1000af427bf5SArnaldo Carvalho de Melo 10012e538c4aSArnaldo Carvalho de Melo snprintf(dso_name, sizeof(dso_name), 10022e538c4aSArnaldo Carvalho de Melo "%s%s", self->short_name, section_name); 10032e538c4aSArnaldo Carvalho de Melo 10044aa65636SArnaldo Carvalho de Melo curr_map = map_groups__find_by_name(&session->kmaps, map->type, dso_name); 10052e538c4aSArnaldo Carvalho de Melo if (curr_map == NULL) { 10062e538c4aSArnaldo Carvalho de Melo u64 start = sym.st_value; 10072e538c4aSArnaldo Carvalho de Melo 10082e538c4aSArnaldo Carvalho de Melo if (kmodule) 10092e538c4aSArnaldo Carvalho de Melo start += map->start + shdr.sh_offset; 10102e538c4aSArnaldo Carvalho de Melo 101100a192b3SArnaldo Carvalho de Melo curr_dso = dso__new(dso_name); 10122e538c4aSArnaldo Carvalho de Melo if (curr_dso == NULL) 10132e538c4aSArnaldo Carvalho de Melo goto out_elf_end; 10143610583cSArnaldo Carvalho de Melo curr_map = map__new2(start, curr_dso, 10153610583cSArnaldo Carvalho de Melo MAP__FUNCTION); 10162e538c4aSArnaldo Carvalho de Melo if (curr_map == NULL) { 10172e538c4aSArnaldo Carvalho de Melo dso__delete(curr_dso); 10182e538c4aSArnaldo Carvalho de Melo goto out_elf_end; 10192e538c4aSArnaldo Carvalho de Melo } 1020ed52ce2eSArnaldo Carvalho de Melo curr_map->map_ip = identity__map_ip; 1021ed52ce2eSArnaldo Carvalho de Melo curr_map->unmap_ip = identity__map_ip; 10222e538c4aSArnaldo Carvalho de Melo curr_dso->origin = DSO__ORIG_KERNEL; 10234aa65636SArnaldo Carvalho de Melo map_groups__insert(&session->kmaps, curr_map); 1024b0da954aSArnaldo Carvalho de Melo dsos__add(&dsos__kernel, curr_dso); 10252e538c4aSArnaldo Carvalho de Melo } else 10262e538c4aSArnaldo Carvalho de Melo curr_dso = curr_map->dso; 10272e538c4aSArnaldo Carvalho de Melo 10282e538c4aSArnaldo Carvalho de Melo goto new_symbol; 10292e538c4aSArnaldo Carvalho de Melo } 10302e538c4aSArnaldo Carvalho de Melo 10312e538c4aSArnaldo Carvalho de Melo if (curr_dso->adjust_symbols) { 10326beba7adSArnaldo Carvalho de Melo pr_debug2("adjusting symbol: st_value: %Lx sh_addr: " 10336beba7adSArnaldo Carvalho de Melo "%Lx sh_offset: %Lx\n", (u64)sym.st_value, 10346beba7adSArnaldo Carvalho de Melo (u64)shdr.sh_addr, (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 */ 10622e538c4aSArnaldo Carvalho de Melo if (nr > 0) 10636a4694a4SArnaldo Carvalho de Melo symbols__fixup_end(&self->symbols[map->type]); 106486470930SIngo Molnar err = nr; 106586470930SIngo Molnar out_elf_end: 106686470930SIngo Molnar elf_end(elf); 106786470930SIngo Molnar out_close: 106886470930SIngo Molnar return err; 106986470930SIngo Molnar } 107086470930SIngo Molnar 107178075caaSArnaldo Carvalho de Melo static bool dso__build_id_equal(const struct dso *self, u8 *build_id) 107278075caaSArnaldo Carvalho de Melo { 107378075caaSArnaldo Carvalho de Melo return memcmp(self->build_id, build_id, sizeof(self->build_id)) == 0; 107478075caaSArnaldo Carvalho de Melo } 107578075caaSArnaldo Carvalho de Melo 1076b0da954aSArnaldo Carvalho de Melo static bool __dsos__read_build_ids(struct list_head *head) 107757f395a7SFrederic Weisbecker { 1078e30a3d12SArnaldo Carvalho de Melo bool have_build_id = false; 107957f395a7SFrederic Weisbecker struct dso *pos; 108057f395a7SFrederic Weisbecker 1081b0da954aSArnaldo Carvalho de Melo list_for_each_entry(pos, head, node) 1082e30a3d12SArnaldo Carvalho de Melo if (filename__read_build_id(pos->long_name, pos->build_id, 1083e30a3d12SArnaldo Carvalho de Melo sizeof(pos->build_id)) > 0) { 1084e30a3d12SArnaldo Carvalho de Melo have_build_id = true; 1085e30a3d12SArnaldo Carvalho de Melo pos->has_build_id = true; 108657f395a7SFrederic Weisbecker } 108757f395a7SFrederic Weisbecker 1088e30a3d12SArnaldo Carvalho de Melo return have_build_id; 108957f395a7SFrederic Weisbecker } 109057f395a7SFrederic Weisbecker 1091b0da954aSArnaldo Carvalho de Melo bool dsos__read_build_ids(void) 1092b0da954aSArnaldo Carvalho de Melo { 10938b4825bfSArnaldo Carvalho de Melo bool kbuildids = __dsos__read_build_ids(&dsos__kernel), 10948b4825bfSArnaldo Carvalho de Melo ubuildids = __dsos__read_build_ids(&dsos__user); 10958b4825bfSArnaldo Carvalho de Melo return kbuildids || ubuildids; 1096b0da954aSArnaldo Carvalho de Melo } 1097b0da954aSArnaldo Carvalho de Melo 1098fd7a346eSArnaldo Carvalho de Melo /* 1099fd7a346eSArnaldo Carvalho de Melo * Align offset to 4 bytes as needed for note name and descriptor data. 1100fd7a346eSArnaldo Carvalho de Melo */ 1101fd7a346eSArnaldo Carvalho de Melo #define NOTE_ALIGN(n) (((n) + 3) & -4U) 1102fd7a346eSArnaldo Carvalho de Melo 11032643ce11SArnaldo Carvalho de Melo int filename__read_build_id(const char *filename, void *bf, size_t size) 11044d1e00a8SArnaldo Carvalho de Melo { 11052643ce11SArnaldo Carvalho de Melo int fd, err = -1; 11064d1e00a8SArnaldo Carvalho de Melo GElf_Ehdr ehdr; 11074d1e00a8SArnaldo Carvalho de Melo GElf_Shdr shdr; 1108fd7a346eSArnaldo Carvalho de Melo Elf_Data *data; 11094d1e00a8SArnaldo Carvalho de Melo Elf_Scn *sec; 1110e57cfcdaSPekka Enberg Elf_Kind ek; 1111fd7a346eSArnaldo Carvalho de Melo void *ptr; 11124d1e00a8SArnaldo Carvalho de Melo Elf *elf; 11134d1e00a8SArnaldo Carvalho de Melo 11142643ce11SArnaldo Carvalho de Melo if (size < BUILD_ID_SIZE) 11152643ce11SArnaldo Carvalho de Melo goto out; 11162643ce11SArnaldo Carvalho de Melo 11172643ce11SArnaldo Carvalho de Melo fd = open(filename, O_RDONLY); 11184d1e00a8SArnaldo Carvalho de Melo if (fd < 0) 11194d1e00a8SArnaldo Carvalho de Melo goto out; 11204d1e00a8SArnaldo Carvalho de Melo 112184087126SMarti Raudsepp elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 11224d1e00a8SArnaldo Carvalho de Melo if (elf == NULL) { 11238d06367fSArnaldo Carvalho de Melo pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename); 11244d1e00a8SArnaldo Carvalho de Melo goto out_close; 11254d1e00a8SArnaldo Carvalho de Melo } 11264d1e00a8SArnaldo Carvalho de Melo 1127e57cfcdaSPekka Enberg ek = elf_kind(elf); 1128e57cfcdaSPekka Enberg if (ek != ELF_K_ELF) 1129e57cfcdaSPekka Enberg goto out_elf_end; 1130e57cfcdaSPekka Enberg 11314d1e00a8SArnaldo Carvalho de Melo if (gelf_getehdr(elf, &ehdr) == NULL) { 11326beba7adSArnaldo Carvalho de Melo pr_err("%s: cannot get elf header.\n", __func__); 11334d1e00a8SArnaldo Carvalho de Melo goto out_elf_end; 11344d1e00a8SArnaldo Carvalho de Melo } 11354d1e00a8SArnaldo Carvalho de Melo 11362643ce11SArnaldo Carvalho de Melo sec = elf_section_by_name(elf, &ehdr, &shdr, 11372643ce11SArnaldo Carvalho de Melo ".note.gnu.build-id", NULL); 1138fd7a346eSArnaldo Carvalho de Melo if (sec == NULL) { 1139fd7a346eSArnaldo Carvalho de Melo sec = elf_section_by_name(elf, &ehdr, &shdr, 1140fd7a346eSArnaldo Carvalho de Melo ".notes", NULL); 11414d1e00a8SArnaldo Carvalho de Melo if (sec == NULL) 11424d1e00a8SArnaldo Carvalho de Melo goto out_elf_end; 1143fd7a346eSArnaldo Carvalho de Melo } 11444d1e00a8SArnaldo Carvalho de Melo 1145fd7a346eSArnaldo Carvalho de Melo data = elf_getdata(sec, NULL); 1146fd7a346eSArnaldo Carvalho de Melo if (data == NULL) 11474d1e00a8SArnaldo Carvalho de Melo goto out_elf_end; 1148fd7a346eSArnaldo Carvalho de Melo 1149fd7a346eSArnaldo Carvalho de Melo ptr = data->d_buf; 1150fd7a346eSArnaldo Carvalho de Melo while (ptr < (data->d_buf + data->d_size)) { 1151fd7a346eSArnaldo Carvalho de Melo GElf_Nhdr *nhdr = ptr; 1152fd7a346eSArnaldo Carvalho de Melo int namesz = NOTE_ALIGN(nhdr->n_namesz), 1153fd7a346eSArnaldo Carvalho de Melo descsz = NOTE_ALIGN(nhdr->n_descsz); 1154fd7a346eSArnaldo Carvalho de Melo const char *name; 1155fd7a346eSArnaldo Carvalho de Melo 1156fd7a346eSArnaldo Carvalho de Melo ptr += sizeof(*nhdr); 1157fd7a346eSArnaldo Carvalho de Melo name = ptr; 1158fd7a346eSArnaldo Carvalho de Melo ptr += namesz; 1159fd7a346eSArnaldo Carvalho de Melo if (nhdr->n_type == NT_GNU_BUILD_ID && 1160fd7a346eSArnaldo Carvalho de Melo nhdr->n_namesz == sizeof("GNU")) { 1161fd7a346eSArnaldo Carvalho de Melo if (memcmp(name, "GNU", sizeof("GNU")) == 0) { 1162fd7a346eSArnaldo Carvalho de Melo memcpy(bf, ptr, BUILD_ID_SIZE); 11632643ce11SArnaldo Carvalho de Melo err = BUILD_ID_SIZE; 1164fd7a346eSArnaldo Carvalho de Melo break; 1165fd7a346eSArnaldo Carvalho de Melo } 1166fd7a346eSArnaldo Carvalho de Melo } 1167fd7a346eSArnaldo Carvalho de Melo ptr += descsz; 1168fd7a346eSArnaldo Carvalho de Melo } 11692643ce11SArnaldo Carvalho de Melo out_elf_end: 11702643ce11SArnaldo Carvalho de Melo elf_end(elf); 11712643ce11SArnaldo Carvalho de Melo out_close: 11722643ce11SArnaldo Carvalho de Melo close(fd); 11732643ce11SArnaldo Carvalho de Melo out: 11742643ce11SArnaldo Carvalho de Melo return err; 11752643ce11SArnaldo Carvalho de Melo } 11762643ce11SArnaldo Carvalho de Melo 1177f1617b40SArnaldo Carvalho de Melo int sysfs__read_build_id(const char *filename, void *build_id, size_t size) 1178f1617b40SArnaldo Carvalho de Melo { 1179f1617b40SArnaldo Carvalho de Melo int fd, err = -1; 1180f1617b40SArnaldo Carvalho de Melo 1181f1617b40SArnaldo Carvalho de Melo if (size < BUILD_ID_SIZE) 1182f1617b40SArnaldo Carvalho de Melo goto out; 1183f1617b40SArnaldo Carvalho de Melo 1184f1617b40SArnaldo Carvalho de Melo fd = open(filename, O_RDONLY); 1185f1617b40SArnaldo Carvalho de Melo if (fd < 0) 1186f1617b40SArnaldo Carvalho de Melo goto out; 1187f1617b40SArnaldo Carvalho de Melo 1188f1617b40SArnaldo Carvalho de Melo while (1) { 1189f1617b40SArnaldo Carvalho de Melo char bf[BUFSIZ]; 1190f1617b40SArnaldo Carvalho de Melo GElf_Nhdr nhdr; 1191f1617b40SArnaldo Carvalho de Melo int namesz, descsz; 1192f1617b40SArnaldo Carvalho de Melo 1193f1617b40SArnaldo Carvalho de Melo if (read(fd, &nhdr, sizeof(nhdr)) != sizeof(nhdr)) 1194f1617b40SArnaldo Carvalho de Melo break; 1195f1617b40SArnaldo Carvalho de Melo 1196fd7a346eSArnaldo Carvalho de Melo namesz = NOTE_ALIGN(nhdr.n_namesz); 1197fd7a346eSArnaldo Carvalho de Melo descsz = NOTE_ALIGN(nhdr.n_descsz); 1198f1617b40SArnaldo Carvalho de Melo if (nhdr.n_type == NT_GNU_BUILD_ID && 1199f1617b40SArnaldo Carvalho de Melo nhdr.n_namesz == sizeof("GNU")) { 1200f1617b40SArnaldo Carvalho de Melo if (read(fd, bf, namesz) != namesz) 1201f1617b40SArnaldo Carvalho de Melo break; 1202f1617b40SArnaldo Carvalho de Melo if (memcmp(bf, "GNU", sizeof("GNU")) == 0) { 1203f1617b40SArnaldo Carvalho de Melo if (read(fd, build_id, 1204f1617b40SArnaldo Carvalho de Melo BUILD_ID_SIZE) == BUILD_ID_SIZE) { 1205f1617b40SArnaldo Carvalho de Melo err = 0; 1206f1617b40SArnaldo Carvalho de Melo break; 1207f1617b40SArnaldo Carvalho de Melo } 1208f1617b40SArnaldo Carvalho de Melo } else if (read(fd, bf, descsz) != descsz) 1209f1617b40SArnaldo Carvalho de Melo break; 1210f1617b40SArnaldo Carvalho de Melo } else { 1211f1617b40SArnaldo Carvalho de Melo int n = namesz + descsz; 1212f1617b40SArnaldo Carvalho de Melo if (read(fd, bf, n) != n) 1213f1617b40SArnaldo Carvalho de Melo break; 1214f1617b40SArnaldo Carvalho de Melo } 1215f1617b40SArnaldo Carvalho de Melo } 1216f1617b40SArnaldo Carvalho de Melo close(fd); 1217f1617b40SArnaldo Carvalho de Melo out: 1218f1617b40SArnaldo Carvalho de Melo return err; 1219f1617b40SArnaldo Carvalho de Melo } 1220f1617b40SArnaldo Carvalho de Melo 122194cb9e38SArnaldo Carvalho de Melo char dso__symtab_origin(const struct dso *self) 122294cb9e38SArnaldo Carvalho de Melo { 122394cb9e38SArnaldo Carvalho de Melo static const char origin[] = { 122494cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_KERNEL] = 'k', 122594cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_JAVA_JIT] = 'j', 12264cf40131SArnaldo Carvalho de Melo [DSO__ORIG_BUILD_ID_CACHE] = 'B', 122794cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_FEDORA] = 'f', 122894cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_UBUNTU] = 'u', 122994cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_BUILDID] = 'b', 123094cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_DSO] = 'd', 1231439d473bSArnaldo Carvalho de Melo [DSO__ORIG_KMODULE] = 'K', 123294cb9e38SArnaldo Carvalho de Melo }; 123394cb9e38SArnaldo Carvalho de Melo 123494cb9e38SArnaldo Carvalho de Melo if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND) 123594cb9e38SArnaldo Carvalho de Melo return '!'; 123694cb9e38SArnaldo Carvalho de Melo return origin[self->origin]; 123794cb9e38SArnaldo Carvalho de Melo } 123894cb9e38SArnaldo Carvalho de Melo 12394aa65636SArnaldo Carvalho de Melo int dso__load(struct dso *self, struct map *map, struct perf_session *session, 12404aa65636SArnaldo Carvalho de Melo symbol_filter_t filter) 124186470930SIngo Molnar { 12424d1e00a8SArnaldo Carvalho de Melo int size = PATH_MAX; 1243c338aee8SArnaldo Carvalho de Melo char *name; 1244d3379ab9SArnaldo Carvalho de Melo u8 build_id[BUILD_ID_SIZE]; 12454cf40131SArnaldo Carvalho de Melo char build_id_hex[BUILD_ID_SIZE * 2 + 1]; 124686470930SIngo Molnar int ret = -1; 124786470930SIngo Molnar int fd; 124886470930SIngo Molnar 12493610583cSArnaldo Carvalho de Melo dso__set_loaded(self, map->type); 125066bd8424SArnaldo Carvalho de Melo 1251c338aee8SArnaldo Carvalho de Melo if (self->kernel) 12524aa65636SArnaldo Carvalho de Melo return dso__load_kernel_sym(self, map, session, filter); 1253c338aee8SArnaldo Carvalho de Melo 1254c338aee8SArnaldo Carvalho de Melo name = malloc(size); 125586470930SIngo Molnar if (!name) 125686470930SIngo Molnar return -1; 125786470930SIngo Molnar 125830d7a77dSArnaldo Carvalho de Melo self->adjust_symbols = 0; 1259f5812a7aSArnaldo Carvalho de Melo 126094cb9e38SArnaldo Carvalho de Melo if (strncmp(self->name, "/tmp/perf-", 10) == 0) { 12616beba7adSArnaldo Carvalho de Melo ret = dso__load_perf_map(self, map, filter); 126294cb9e38SArnaldo Carvalho de Melo self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT : 126394cb9e38SArnaldo Carvalho de Melo DSO__ORIG_NOT_FOUND; 126494cb9e38SArnaldo Carvalho de Melo return ret; 126594cb9e38SArnaldo Carvalho de Melo } 126694cb9e38SArnaldo Carvalho de Melo 12674cf40131SArnaldo Carvalho de Melo self->origin = DSO__ORIG_BUILD_ID_CACHE; 126880d496beSPekka Enberg 12694cf40131SArnaldo Carvalho de Melo if (self->has_build_id) { 12704cf40131SArnaldo Carvalho de Melo build_id__sprintf(self->build_id, sizeof(self->build_id), 12714cf40131SArnaldo Carvalho de Melo build_id_hex); 12724cf40131SArnaldo Carvalho de Melo snprintf(name, size, "%s/%s/.build-id/%.2s/%s", 12734cf40131SArnaldo Carvalho de Melo getenv("HOME"), DEBUG_CACHE_DIR, 12744cf40131SArnaldo Carvalho de Melo build_id_hex, build_id_hex + 2); 12754cf40131SArnaldo Carvalho de Melo goto open_file; 12764cf40131SArnaldo Carvalho de Melo } 127786470930SIngo Molnar more: 127886470930SIngo Molnar do { 127994cb9e38SArnaldo Carvalho de Melo self->origin++; 128094cb9e38SArnaldo Carvalho de Melo switch (self->origin) { 128194cb9e38SArnaldo Carvalho de Melo case DSO__ORIG_FEDORA: 1282439d473bSArnaldo Carvalho de Melo snprintf(name, size, "/usr/lib/debug%s.debug", 1283439d473bSArnaldo Carvalho de Melo self->long_name); 128486470930SIngo Molnar break; 128594cb9e38SArnaldo Carvalho de Melo case DSO__ORIG_UBUNTU: 1286439d473bSArnaldo Carvalho de Melo snprintf(name, size, "/usr/lib/debug%s", 1287439d473bSArnaldo Carvalho de Melo self->long_name); 128886470930SIngo Molnar break; 128994cb9e38SArnaldo Carvalho de Melo case DSO__ORIG_BUILDID: 1290d3379ab9SArnaldo Carvalho de Melo if (filename__read_build_id(self->long_name, build_id, 1291d3379ab9SArnaldo Carvalho de Melo sizeof(build_id))) { 1292d3379ab9SArnaldo Carvalho de Melo build_id__sprintf(build_id, sizeof(build_id), 1293d3379ab9SArnaldo Carvalho de Melo build_id_hex); 12944d1e00a8SArnaldo Carvalho de Melo snprintf(name, size, 12954d1e00a8SArnaldo Carvalho de Melo "/usr/lib/debug/.build-id/%.2s/%s.debug", 1296d3379ab9SArnaldo Carvalho de Melo build_id_hex, build_id_hex + 2); 1297d3379ab9SArnaldo Carvalho de Melo if (self->has_build_id) 12988d06367fSArnaldo Carvalho de Melo goto compare_build_id; 1299d3379ab9SArnaldo Carvalho de Melo break; 13004d1e00a8SArnaldo Carvalho de Melo } 130194cb9e38SArnaldo Carvalho de Melo self->origin++; 13024d1e00a8SArnaldo Carvalho de Melo /* Fall thru */ 130394cb9e38SArnaldo Carvalho de Melo case DSO__ORIG_DSO: 1304439d473bSArnaldo Carvalho de Melo snprintf(name, size, "%s", self->long_name); 130586470930SIngo Molnar break; 130686470930SIngo Molnar 130786470930SIngo Molnar default: 130886470930SIngo Molnar goto out; 130986470930SIngo Molnar } 131086470930SIngo Molnar 13118d06367fSArnaldo Carvalho de Melo if (self->has_build_id) { 1312d3379ab9SArnaldo Carvalho de Melo if (filename__read_build_id(name, build_id, 1313d3379ab9SArnaldo Carvalho de Melo sizeof(build_id)) < 0) 13148d06367fSArnaldo Carvalho de Melo goto more; 13158d06367fSArnaldo Carvalho de Melo compare_build_id: 131678075caaSArnaldo Carvalho de Melo if (!dso__build_id_equal(self, build_id)) 13178d06367fSArnaldo Carvalho de Melo goto more; 13188d06367fSArnaldo Carvalho de Melo } 13194cf40131SArnaldo Carvalho de Melo open_file: 132086470930SIngo Molnar fd = open(name, O_RDONLY); 132186470930SIngo Molnar } while (fd < 0); 132286470930SIngo Molnar 132395011c60SArnaldo Carvalho de Melo ret = dso__load_sym(self, map, NULL, name, fd, filter, 0, 0); 132486470930SIngo Molnar close(fd); 132586470930SIngo Molnar 132686470930SIngo Molnar /* 132786470930SIngo Molnar * Some people seem to have debuginfo files _WITHOUT_ debug info!?!? 132886470930SIngo Molnar */ 132986470930SIngo Molnar if (!ret) 133086470930SIngo Molnar goto more; 133186470930SIngo Molnar 1332a25e46c4SArnaldo Carvalho de Melo if (ret > 0) { 133382164161SArnaldo Carvalho de Melo int nr_plt = dso__synthesize_plt_symbols(self, map, filter); 1334a25e46c4SArnaldo Carvalho de Melo if (nr_plt > 0) 1335a25e46c4SArnaldo Carvalho de Melo ret += nr_plt; 1336a25e46c4SArnaldo Carvalho de Melo } 133786470930SIngo Molnar out: 133886470930SIngo Molnar free(name); 13391340e6bbSArnaldo Carvalho de Melo if (ret < 0 && strstr(self->name, " (deleted)") != NULL) 13401340e6bbSArnaldo Carvalho de Melo return 0; 134186470930SIngo Molnar return ret; 134286470930SIngo Molnar } 134386470930SIngo Molnar 134479406cd7SArnaldo Carvalho de Melo struct map *map_groups__find_by_name(struct map_groups *self, 134579406cd7SArnaldo Carvalho de Melo enum map_type type, const char *name) 1346439d473bSArnaldo Carvalho de Melo { 1347439d473bSArnaldo Carvalho de Melo struct rb_node *nd; 1348439d473bSArnaldo Carvalho de Melo 134979406cd7SArnaldo Carvalho de Melo for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) { 1350439d473bSArnaldo Carvalho de Melo struct map *map = rb_entry(nd, struct map, rb_node); 1351439d473bSArnaldo Carvalho de Melo 1352b7cece76SArnaldo Carvalho de Melo if (map->dso && strcmp(map->dso->short_name, name) == 0) 1353439d473bSArnaldo Carvalho de Melo return map; 1354439d473bSArnaldo Carvalho de Melo } 1355439d473bSArnaldo Carvalho de Melo 1356439d473bSArnaldo Carvalho de Melo return NULL; 1357439d473bSArnaldo Carvalho de Melo } 1358439d473bSArnaldo Carvalho de Melo 1359b7cece76SArnaldo Carvalho de Melo static int dso__kernel_module_get_build_id(struct dso *self) 1360b7cece76SArnaldo Carvalho de Melo { 1361b7cece76SArnaldo Carvalho de Melo char filename[PATH_MAX]; 1362b7cece76SArnaldo Carvalho de Melo /* 1363b7cece76SArnaldo Carvalho de Melo * kernel module short names are of the form "[module]" and 1364b7cece76SArnaldo Carvalho de Melo * we need just "module" here. 1365b7cece76SArnaldo Carvalho de Melo */ 1366b7cece76SArnaldo Carvalho de Melo const char *name = self->short_name + 1; 1367b7cece76SArnaldo Carvalho de Melo 1368b7cece76SArnaldo Carvalho de Melo snprintf(filename, sizeof(filename), 1369b7cece76SArnaldo Carvalho de Melo "/sys/module/%.*s/notes/.note.gnu.build-id", 1370b7cece76SArnaldo Carvalho de Melo (int)strlen(name - 1), name); 1371b7cece76SArnaldo Carvalho de Melo 1372b7cece76SArnaldo Carvalho de Melo if (sysfs__read_build_id(filename, self->build_id, 1373b7cece76SArnaldo Carvalho de Melo sizeof(self->build_id)) == 0) 1374b7cece76SArnaldo Carvalho de Melo self->has_build_id = true; 1375b7cece76SArnaldo Carvalho de Melo 1376b7cece76SArnaldo Carvalho de Melo return 0; 1377b7cece76SArnaldo Carvalho de Melo } 1378b7cece76SArnaldo Carvalho de Melo 13794aa65636SArnaldo Carvalho de Melo static int perf_session__set_modules_path_dir(struct perf_session *self, char *dirname) 13806cfcc53eSMike Galbraith { 1381439d473bSArnaldo Carvalho de Melo struct dirent *dent; 1382439d473bSArnaldo Carvalho de Melo DIR *dir = opendir(dirname); 13836cfcc53eSMike Galbraith 1384439d473bSArnaldo Carvalho de Melo if (!dir) { 138587f8ea4cSArnaldo Carvalho de Melo pr_debug("%s: cannot open %s dir\n", __func__, dirname); 1386439d473bSArnaldo Carvalho de Melo return -1; 1387439d473bSArnaldo Carvalho de Melo } 13886cfcc53eSMike Galbraith 1389439d473bSArnaldo Carvalho de Melo while ((dent = readdir(dir)) != NULL) { 1390439d473bSArnaldo Carvalho de Melo char path[PATH_MAX]; 1391439d473bSArnaldo Carvalho de Melo 1392439d473bSArnaldo Carvalho de Melo if (dent->d_type == DT_DIR) { 1393439d473bSArnaldo Carvalho de Melo if (!strcmp(dent->d_name, ".") || 1394439d473bSArnaldo Carvalho de Melo !strcmp(dent->d_name, "..")) 1395439d473bSArnaldo Carvalho de Melo continue; 1396439d473bSArnaldo Carvalho de Melo 1397439d473bSArnaldo Carvalho de Melo snprintf(path, sizeof(path), "%s/%s", 1398439d473bSArnaldo Carvalho de Melo dirname, dent->d_name); 13994aa65636SArnaldo Carvalho de Melo if (perf_session__set_modules_path_dir(self, path) < 0) 1400439d473bSArnaldo Carvalho de Melo goto failure; 1401439d473bSArnaldo Carvalho de Melo } else { 1402439d473bSArnaldo Carvalho de Melo char *dot = strrchr(dent->d_name, '.'), 1403439d473bSArnaldo Carvalho de Melo dso_name[PATH_MAX]; 1404439d473bSArnaldo Carvalho de Melo struct map *map; 1405cfc10d3bSArnaldo Carvalho de Melo char *long_name; 1406439d473bSArnaldo Carvalho de Melo 1407439d473bSArnaldo Carvalho de Melo if (dot == NULL || strcmp(dot, ".ko")) 1408439d473bSArnaldo Carvalho de Melo continue; 1409439d473bSArnaldo Carvalho de Melo snprintf(dso_name, sizeof(dso_name), "[%.*s]", 1410439d473bSArnaldo Carvalho de Melo (int)(dot - dent->d_name), dent->d_name); 1411439d473bSArnaldo Carvalho de Melo 1412a2a99e8eSArnaldo Carvalho de Melo strxfrchar(dso_name, '-', '_'); 14134aa65636SArnaldo Carvalho de Melo map = map_groups__find_by_name(&self->kmaps, MAP__FUNCTION, dso_name); 1414439d473bSArnaldo Carvalho de Melo if (map == NULL) 1415439d473bSArnaldo Carvalho de Melo continue; 1416439d473bSArnaldo Carvalho de Melo 1417439d473bSArnaldo Carvalho de Melo snprintf(path, sizeof(path), "%s/%s", 1418439d473bSArnaldo Carvalho de Melo dirname, dent->d_name); 1419439d473bSArnaldo Carvalho de Melo 1420cfc10d3bSArnaldo Carvalho de Melo long_name = strdup(path); 1421cfc10d3bSArnaldo Carvalho de Melo if (long_name == NULL) 1422439d473bSArnaldo Carvalho de Melo goto failure; 1423cfc10d3bSArnaldo Carvalho de Melo dso__set_long_name(map->dso, long_name); 1424b7cece76SArnaldo Carvalho de Melo dso__kernel_module_get_build_id(map->dso); 1425439d473bSArnaldo Carvalho de Melo } 1426439d473bSArnaldo Carvalho de Melo } 1427439d473bSArnaldo Carvalho de Melo 1428c338aee8SArnaldo Carvalho de Melo return 0; 1429439d473bSArnaldo Carvalho de Melo failure: 1430439d473bSArnaldo Carvalho de Melo closedir(dir); 1431439d473bSArnaldo Carvalho de Melo return -1; 1432439d473bSArnaldo Carvalho de Melo } 1433439d473bSArnaldo Carvalho de Melo 14344aa65636SArnaldo Carvalho de Melo static int perf_session__set_modules_path(struct perf_session *self) 1435439d473bSArnaldo Carvalho de Melo { 1436439d473bSArnaldo Carvalho de Melo struct utsname uts; 1437439d473bSArnaldo Carvalho de Melo char modules_path[PATH_MAX]; 1438439d473bSArnaldo Carvalho de Melo 1439439d473bSArnaldo Carvalho de Melo if (uname(&uts) < 0) 1440439d473bSArnaldo Carvalho de Melo return -1; 1441439d473bSArnaldo Carvalho de Melo 1442439d473bSArnaldo Carvalho de Melo snprintf(modules_path, sizeof(modules_path), "/lib/modules/%s/kernel", 1443439d473bSArnaldo Carvalho de Melo uts.release); 1444439d473bSArnaldo Carvalho de Melo 14454aa65636SArnaldo Carvalho de Melo return perf_session__set_modules_path_dir(self, modules_path); 1446439d473bSArnaldo Carvalho de Melo } 14476cfcc53eSMike Galbraith 14486cfcc53eSMike Galbraith /* 1449439d473bSArnaldo Carvalho de Melo * Constructor variant for modules (where we know from /proc/modules where 1450439d473bSArnaldo Carvalho de Melo * they are loaded) and for vmlinux, where only after we load all the 1451439d473bSArnaldo Carvalho de Melo * symbols we'll know where it starts and ends. 14526cfcc53eSMike Galbraith */ 14533610583cSArnaldo Carvalho de Melo static struct map *map__new2(u64 start, struct dso *dso, enum map_type type) 1454439d473bSArnaldo Carvalho de Melo { 1455439d473bSArnaldo Carvalho de Melo struct map *self = malloc(sizeof(*self)); 14566cfcc53eSMike Galbraith 1457439d473bSArnaldo Carvalho de Melo if (self != NULL) { 1458439d473bSArnaldo Carvalho de Melo /* 1459afb7b4f0SArnaldo Carvalho de Melo * ->end will be filled after we load all the symbols 1460439d473bSArnaldo Carvalho de Melo */ 14613610583cSArnaldo Carvalho de Melo map__init(self, type, start, 0, 0, dso); 1462439d473bSArnaldo Carvalho de Melo } 1463afb7b4f0SArnaldo Carvalho de Melo 1464439d473bSArnaldo Carvalho de Melo return self; 1465439d473bSArnaldo Carvalho de Melo } 1466439d473bSArnaldo Carvalho de Melo 1467b7cece76SArnaldo Carvalho de Melo struct map *perf_session__new_module_map(struct perf_session *self, u64 start, 1468b7cece76SArnaldo Carvalho de Melo const char *filename) 1469b7cece76SArnaldo Carvalho de Melo { 1470b7cece76SArnaldo Carvalho de Melo struct map *map; 1471b7cece76SArnaldo Carvalho de Melo struct dso *dso = __dsos__findnew(&dsos__kernel, filename); 1472b7cece76SArnaldo Carvalho de Melo 1473b7cece76SArnaldo Carvalho de Melo if (dso == NULL) 1474b7cece76SArnaldo Carvalho de Melo return NULL; 1475b7cece76SArnaldo Carvalho de Melo 1476b7cece76SArnaldo Carvalho de Melo map = map__new2(start, dso, MAP__FUNCTION); 1477b7cece76SArnaldo Carvalho de Melo if (map == NULL) 1478b7cece76SArnaldo Carvalho de Melo return NULL; 1479b7cece76SArnaldo Carvalho de Melo 1480b7cece76SArnaldo Carvalho de Melo dso->origin = DSO__ORIG_KMODULE; 1481b7cece76SArnaldo Carvalho de Melo map_groups__insert(&self->kmaps, map); 1482b7cece76SArnaldo Carvalho de Melo return map; 1483b7cece76SArnaldo Carvalho de Melo } 1484b7cece76SArnaldo Carvalho de Melo 14854aa65636SArnaldo Carvalho de Melo static int perf_session__create_module_maps(struct perf_session *self) 1486439d473bSArnaldo Carvalho de Melo { 1487439d473bSArnaldo Carvalho de Melo char *line = NULL; 1488439d473bSArnaldo Carvalho de Melo size_t n; 1489439d473bSArnaldo Carvalho de Melo FILE *file = fopen("/proc/modules", "r"); 1490439d473bSArnaldo Carvalho de Melo struct map *map; 1491439d473bSArnaldo Carvalho de Melo 1492439d473bSArnaldo Carvalho de Melo if (file == NULL) 1493439d473bSArnaldo Carvalho de Melo return -1; 1494439d473bSArnaldo Carvalho de Melo 1495439d473bSArnaldo Carvalho de Melo while (!feof(file)) { 1496439d473bSArnaldo Carvalho de Melo char name[PATH_MAX]; 1497439d473bSArnaldo Carvalho de Melo u64 start; 1498439d473bSArnaldo Carvalho de Melo char *sep; 1499439d473bSArnaldo Carvalho de Melo int line_len; 1500439d473bSArnaldo Carvalho de Melo 1501439d473bSArnaldo Carvalho de Melo line_len = getline(&line, &n, file); 1502439d473bSArnaldo Carvalho de Melo if (line_len < 0) 15036cfcc53eSMike Galbraith break; 15046cfcc53eSMike Galbraith 1505439d473bSArnaldo Carvalho de Melo if (!line) 1506439d473bSArnaldo Carvalho de Melo goto out_failure; 1507439d473bSArnaldo Carvalho de Melo 1508439d473bSArnaldo Carvalho de Melo line[--line_len] = '\0'; /* \n */ 1509439d473bSArnaldo Carvalho de Melo 1510439d473bSArnaldo Carvalho de Melo sep = strrchr(line, 'x'); 1511439d473bSArnaldo Carvalho de Melo if (sep == NULL) 1512439d473bSArnaldo Carvalho de Melo continue; 1513439d473bSArnaldo Carvalho de Melo 1514439d473bSArnaldo Carvalho de Melo hex2u64(sep + 1, &start); 1515439d473bSArnaldo Carvalho de Melo 1516439d473bSArnaldo Carvalho de Melo sep = strchr(line, ' '); 1517439d473bSArnaldo Carvalho de Melo if (sep == NULL) 1518439d473bSArnaldo Carvalho de Melo continue; 1519439d473bSArnaldo Carvalho de Melo 1520439d473bSArnaldo Carvalho de Melo *sep = '\0'; 1521439d473bSArnaldo Carvalho de Melo 1522439d473bSArnaldo Carvalho de Melo snprintf(name, sizeof(name), "[%s]", line); 1523b7cece76SArnaldo Carvalho de Melo map = perf_session__new_module_map(self, start, name); 1524b7cece76SArnaldo Carvalho de Melo if (map == NULL) 1525439d473bSArnaldo Carvalho de Melo goto out_delete_line; 1526b7cece76SArnaldo Carvalho de Melo dso__kernel_module_get_build_id(map->dso); 15276cfcc53eSMike Galbraith } 15286cfcc53eSMike Galbraith 1529439d473bSArnaldo Carvalho de Melo free(line); 1530439d473bSArnaldo Carvalho de Melo fclose(file); 1531439d473bSArnaldo Carvalho de Melo 15324aa65636SArnaldo Carvalho de Melo return perf_session__set_modules_path(self); 1533439d473bSArnaldo Carvalho de Melo 1534439d473bSArnaldo Carvalho de Melo out_delete_line: 1535439d473bSArnaldo Carvalho de Melo free(line); 1536439d473bSArnaldo Carvalho de Melo out_failure: 1537439d473bSArnaldo Carvalho de Melo return -1; 15386cfcc53eSMike Galbraith } 15396cfcc53eSMike Galbraith 15409958e1f0SArnaldo Carvalho de Melo static int dso__load_vmlinux(struct dso *self, struct map *map, 15414aa65636SArnaldo Carvalho de Melo struct perf_session *session, 15426beba7adSArnaldo Carvalho de Melo const char *vmlinux, symbol_filter_t filter) 154386470930SIngo Molnar { 1544fbd733b8SArnaldo Carvalho de Melo int err = -1, fd; 154586470930SIngo Molnar 1546fbd733b8SArnaldo Carvalho de Melo if (self->has_build_id) { 1547fbd733b8SArnaldo Carvalho de Melo u8 build_id[BUILD_ID_SIZE]; 154866bd8424SArnaldo Carvalho de Melo 1549fbd733b8SArnaldo Carvalho de Melo if (filename__read_build_id(vmlinux, build_id, 1550fbd733b8SArnaldo Carvalho de Melo sizeof(build_id)) < 0) { 1551fbd733b8SArnaldo Carvalho de Melo pr_debug("No build_id in %s, ignoring it\n", vmlinux); 1552fbd733b8SArnaldo Carvalho de Melo return -1; 1553fbd733b8SArnaldo Carvalho de Melo } 1554fbd733b8SArnaldo Carvalho de Melo if (!dso__build_id_equal(self, build_id)) { 1555fbd733b8SArnaldo Carvalho de Melo char expected_build_id[BUILD_ID_SIZE * 2 + 1], 1556fbd733b8SArnaldo Carvalho de Melo vmlinux_build_id[BUILD_ID_SIZE * 2 + 1]; 1557fbd733b8SArnaldo Carvalho de Melo 1558fbd733b8SArnaldo Carvalho de Melo build_id__sprintf(self->build_id, 1559fbd733b8SArnaldo Carvalho de Melo sizeof(self->build_id), 1560fbd733b8SArnaldo Carvalho de Melo expected_build_id); 1561fbd733b8SArnaldo Carvalho de Melo build_id__sprintf(build_id, sizeof(build_id), 1562fbd733b8SArnaldo Carvalho de Melo vmlinux_build_id); 1563fbd733b8SArnaldo Carvalho de Melo pr_debug("build_id in %s is %s while expected is %s, " 1564fbd733b8SArnaldo Carvalho de Melo "ignoring it\n", vmlinux, vmlinux_build_id, 1565fbd733b8SArnaldo Carvalho de Melo expected_build_id); 1566fbd733b8SArnaldo Carvalho de Melo return -1; 1567fbd733b8SArnaldo Carvalho de Melo } 1568fbd733b8SArnaldo Carvalho de Melo } 1569fbd733b8SArnaldo Carvalho de Melo 1570fbd733b8SArnaldo Carvalho de Melo fd = open(vmlinux, O_RDONLY); 157186470930SIngo Molnar if (fd < 0) 157286470930SIngo Molnar return -1; 157386470930SIngo Molnar 15743610583cSArnaldo Carvalho de Melo dso__set_loaded(self, map->type); 1575dc8d6ab2SArnaldo Carvalho de Melo err = dso__load_sym(self, map, session, vmlinux, fd, filter, 1, 0); 157686470930SIngo Molnar close(fd); 157786470930SIngo Molnar 157886470930SIngo Molnar return err; 157986470930SIngo Molnar } 158086470930SIngo Molnar 1581c338aee8SArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *self, struct map *map, 15824aa65636SArnaldo Carvalho de Melo struct perf_session *session, symbol_filter_t filter) 158386470930SIngo Molnar { 1584cc612d81SArnaldo Carvalho de Melo int err; 15859e201442SArnaldo Carvalho de Melo const char *kallsyms_filename = NULL; 15869e201442SArnaldo Carvalho de Melo char *kallsyms_allocated_filename = NULL; 1587dc8d6ab2SArnaldo Carvalho de Melo /* 1588dc8d6ab2SArnaldo Carvalho de Melo * Step 1: if the user specified a vmlinux filename, use it and only 1589dc8d6ab2SArnaldo Carvalho de Melo * it, reporting errors to the user if it cannot be used. 1590dc8d6ab2SArnaldo Carvalho de Melo * 1591dc8d6ab2SArnaldo Carvalho de Melo * For instance, try to analyse an ARM perf.data file _without_ a 1592dc8d6ab2SArnaldo Carvalho de Melo * build-id, or if the user specifies the wrong path to the right 1593dc8d6ab2SArnaldo Carvalho de Melo * vmlinux file, obviously we can't fallback to another vmlinux (a 1594dc8d6ab2SArnaldo Carvalho de Melo * x86_86 one, on the machine where analysis is being performed, say), 1595dc8d6ab2SArnaldo Carvalho de Melo * or worse, /proc/kallsyms. 1596dc8d6ab2SArnaldo Carvalho de Melo * 1597dc8d6ab2SArnaldo Carvalho de Melo * If the specified file _has_ a build-id and there is a build-id 1598dc8d6ab2SArnaldo Carvalho de Melo * section in the perf.data file, we will still do the expected 1599dc8d6ab2SArnaldo Carvalho de Melo * validation in dso__load_vmlinux and will bail out if they don't 1600dc8d6ab2SArnaldo Carvalho de Melo * match. 1601dc8d6ab2SArnaldo Carvalho de Melo */ 1602dc8d6ab2SArnaldo Carvalho de Melo if (symbol_conf.vmlinux_name != NULL) { 1603dc8d6ab2SArnaldo Carvalho de Melo err = dso__load_vmlinux(self, map, session, 1604dc8d6ab2SArnaldo Carvalho de Melo symbol_conf.vmlinux_name, filter); 1605dc8d6ab2SArnaldo Carvalho de Melo goto out_try_fixup; 1606dc8d6ab2SArnaldo Carvalho de Melo } 1607439d473bSArnaldo Carvalho de Melo 1608cc612d81SArnaldo Carvalho de Melo if (vmlinux_path != NULL) { 1609cc612d81SArnaldo Carvalho de Melo int i; 1610cc612d81SArnaldo Carvalho de Melo pr_debug("Looking at the vmlinux_path (%d entries long)\n", 1611cc612d81SArnaldo Carvalho de Melo vmlinux_path__nr_entries); 1612cc612d81SArnaldo Carvalho de Melo for (i = 0; i < vmlinux_path__nr_entries; ++i) { 16134aa65636SArnaldo Carvalho de Melo err = dso__load_vmlinux(self, map, session, 161495011c60SArnaldo Carvalho de Melo vmlinux_path[i], filter); 1615cc612d81SArnaldo Carvalho de Melo if (err > 0) { 1616cc612d81SArnaldo Carvalho de Melo pr_debug("Using %s for symbols\n", 1617cc612d81SArnaldo Carvalho de Melo vmlinux_path[i]); 1618cc612d81SArnaldo Carvalho de Melo dso__set_long_name(self, 1619cc612d81SArnaldo Carvalho de Melo strdup(vmlinux_path[i])); 1620cc612d81SArnaldo Carvalho de Melo goto out_fixup; 1621cc612d81SArnaldo Carvalho de Melo } 1622cc612d81SArnaldo Carvalho de Melo } 1623cc612d81SArnaldo Carvalho de Melo } 1624cc612d81SArnaldo Carvalho de Melo 1625b7cece76SArnaldo Carvalho de Melo /* 1626b7cece76SArnaldo Carvalho de Melo * Say the kernel DSO was created when processing the build-id header table, 1627b7cece76SArnaldo Carvalho de Melo * we have a build-id, so check if it is the same as the running kernel, 1628b7cece76SArnaldo Carvalho de Melo * using it if it is. 1629b7cece76SArnaldo Carvalho de Melo */ 1630b7cece76SArnaldo Carvalho de Melo if (self->has_build_id) { 1631b7cece76SArnaldo Carvalho de Melo u8 kallsyms_build_id[BUILD_ID_SIZE]; 16329e201442SArnaldo Carvalho de Melo char sbuild_id[BUILD_ID_SIZE * 2 + 1]; 1633b7cece76SArnaldo Carvalho de Melo 1634b7cece76SArnaldo Carvalho de Melo if (sysfs__read_build_id("/sys/kernel/notes", kallsyms_build_id, 16358d0591f6SArnaldo Carvalho de Melo sizeof(kallsyms_build_id)) == 0) { 16369e201442SArnaldo Carvalho de Melo if (dso__build_id_equal(self, kallsyms_build_id)) { 16379e201442SArnaldo Carvalho de Melo kallsyms_filename = "/proc/kallsyms"; 1638b7cece76SArnaldo Carvalho de Melo goto do_kallsyms; 16398d0591f6SArnaldo Carvalho de Melo } 16409e201442SArnaldo Carvalho de Melo } 1641dc8d6ab2SArnaldo Carvalho de Melo /* 1642dc8d6ab2SArnaldo Carvalho de Melo * Now look if we have it on the build-id cache in 1643dc8d6ab2SArnaldo Carvalho de Melo * $HOME/.debug/[kernel.kallsyms]. 1644dc8d6ab2SArnaldo Carvalho de Melo */ 16459e201442SArnaldo Carvalho de Melo build_id__sprintf(self->build_id, sizeof(self->build_id), 16469e201442SArnaldo Carvalho de Melo sbuild_id); 16479e201442SArnaldo Carvalho de Melo 16489e201442SArnaldo Carvalho de Melo if (asprintf(&kallsyms_allocated_filename, 16499e201442SArnaldo Carvalho de Melo "%s/.debug/[kernel.kallsyms]/%s", 1650dc8d6ab2SArnaldo Carvalho de Melo getenv("HOME"), sbuild_id) == -1) 16518d0591f6SArnaldo Carvalho de Melo return -1; 16528d0591f6SArnaldo Carvalho de Melo 1653dc8d6ab2SArnaldo Carvalho de Melo if (access(kallsyms_filename, F_OK)) { 16549e201442SArnaldo Carvalho de Melo free(kallsyms_allocated_filename); 1655dc8d6ab2SArnaldo Carvalho de Melo return -1; 1656ef6ae724SArnaldo Carvalho de Melo } 165786470930SIngo Molnar 1658dc8d6ab2SArnaldo Carvalho de Melo kallsyms_filename = kallsyms_allocated_filename; 1659dc8d6ab2SArnaldo Carvalho de Melo } else { 1660dc8d6ab2SArnaldo Carvalho de Melo /* 1661dc8d6ab2SArnaldo Carvalho de Melo * Last resort, if we don't have a build-id and couldn't find 1662dc8d6ab2SArnaldo Carvalho de Melo * any vmlinux file, try the running kernel kallsyms table. 1663dc8d6ab2SArnaldo Carvalho de Melo */ 1664dc8d6ab2SArnaldo Carvalho de Melo kallsyms_filename = "/proc/kallsyms"; 1665dc8d6ab2SArnaldo Carvalho de Melo } 1666dc8d6ab2SArnaldo Carvalho de Melo 1667dc8d6ab2SArnaldo Carvalho de Melo do_kallsyms: 1668dc8d6ab2SArnaldo Carvalho de Melo err = dso__load_kallsyms(self, kallsyms_filename, map, session, filter); 1669dc8d6ab2SArnaldo Carvalho de Melo free(kallsyms_allocated_filename); 1670dc8d6ab2SArnaldo Carvalho de Melo 1671dc8d6ab2SArnaldo Carvalho de Melo out_try_fixup: 1672439d473bSArnaldo Carvalho de Melo if (err > 0) { 1673cc612d81SArnaldo Carvalho de Melo out_fixup: 1674*e1c7c6a4SArnaldo Carvalho de Melo if (kallsyms_filename != NULL) 1675dc8d6ab2SArnaldo Carvalho de Melo dso__set_long_name(self, strdup("[kernel.kallsyms]")); 16766a4694a4SArnaldo Carvalho de Melo map__fixup_start(map); 16776a4694a4SArnaldo Carvalho de Melo map__fixup_end(map); 1678439d473bSArnaldo Carvalho de Melo } 167994cb9e38SArnaldo Carvalho de Melo 168086470930SIngo Molnar return err; 168186470930SIngo Molnar } 168286470930SIngo Molnar 1683b0da954aSArnaldo Carvalho de Melo LIST_HEAD(dsos__user); 1684b0da954aSArnaldo Carvalho de Melo LIST_HEAD(dsos__kernel); 1685cd84c2acSFrederic Weisbecker struct dso *vdso; 1686cd84c2acSFrederic Weisbecker 1687b0da954aSArnaldo Carvalho de Melo static void dsos__add(struct list_head *head, struct dso *dso) 1688cd84c2acSFrederic Weisbecker { 1689b0da954aSArnaldo Carvalho de Melo list_add_tail(&dso->node, head); 1690cd84c2acSFrederic Weisbecker } 1691cd84c2acSFrederic Weisbecker 1692b0da954aSArnaldo Carvalho de Melo static struct dso *dsos__find(struct list_head *head, const char *name) 1693cd84c2acSFrederic Weisbecker { 1694cd84c2acSFrederic Weisbecker struct dso *pos; 1695cd84c2acSFrederic Weisbecker 1696b0da954aSArnaldo Carvalho de Melo list_for_each_entry(pos, head, node) 1697cf4e5b08SArnaldo Carvalho de Melo if (strcmp(pos->long_name, name) == 0) 1698cd84c2acSFrederic Weisbecker return pos; 1699cd84c2acSFrederic Weisbecker return NULL; 1700cd84c2acSFrederic Weisbecker } 1701cd84c2acSFrederic Weisbecker 1702a89e5abeSArnaldo Carvalho de Melo struct dso *__dsos__findnew(struct list_head *head, const char *name) 1703cd84c2acSFrederic Weisbecker { 1704a89e5abeSArnaldo Carvalho de Melo struct dso *dso = dsos__find(head, name); 1705cd84c2acSFrederic Weisbecker 1706e4204992SArnaldo Carvalho de Melo if (!dso) { 170700a192b3SArnaldo Carvalho de Melo dso = dso__new(name); 1708cfc10d3bSArnaldo Carvalho de Melo if (dso != NULL) { 1709a89e5abeSArnaldo Carvalho de Melo dsos__add(head, dso); 1710cfc10d3bSArnaldo Carvalho de Melo dso__set_basename(dso); 1711cfc10d3bSArnaldo Carvalho de Melo } 1712e4204992SArnaldo Carvalho de Melo } 1713cd84c2acSFrederic Weisbecker 1714cd84c2acSFrederic Weisbecker return dso; 1715cd84c2acSFrederic Weisbecker } 1716cd84c2acSFrederic Weisbecker 1717b0da954aSArnaldo Carvalho de Melo static void __dsos__fprintf(struct list_head *head, FILE *fp) 1718cd84c2acSFrederic Weisbecker { 1719cd84c2acSFrederic Weisbecker struct dso *pos; 1720cd84c2acSFrederic Weisbecker 172195011c60SArnaldo Carvalho de Melo list_for_each_entry(pos, head, node) { 172295011c60SArnaldo Carvalho de Melo int i; 172395011c60SArnaldo Carvalho de Melo for (i = 0; i < MAP__NR_TYPES; ++i) 172495011c60SArnaldo Carvalho de Melo dso__fprintf(pos, i, fp); 172595011c60SArnaldo Carvalho de Melo } 1726cd84c2acSFrederic Weisbecker } 1727cd84c2acSFrederic Weisbecker 1728b0da954aSArnaldo Carvalho de Melo void dsos__fprintf(FILE *fp) 1729b0da954aSArnaldo Carvalho de Melo { 1730b0da954aSArnaldo Carvalho de Melo __dsos__fprintf(&dsos__kernel, fp); 1731b0da954aSArnaldo Carvalho de Melo __dsos__fprintf(&dsos__user, fp); 1732b0da954aSArnaldo Carvalho de Melo } 1733b0da954aSArnaldo Carvalho de Melo 173488d3d9b7SArnaldo Carvalho de Melo static size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp, 173588d3d9b7SArnaldo Carvalho de Melo bool with_hits) 17369e03eb2dSArnaldo Carvalho de Melo { 17379e03eb2dSArnaldo Carvalho de Melo struct dso *pos; 17389e03eb2dSArnaldo Carvalho de Melo size_t ret = 0; 17399e03eb2dSArnaldo Carvalho de Melo 1740b0da954aSArnaldo Carvalho de Melo list_for_each_entry(pos, head, node) { 174188d3d9b7SArnaldo Carvalho de Melo if (with_hits && !pos->hit) 174288d3d9b7SArnaldo Carvalho de Melo continue; 17439e03eb2dSArnaldo Carvalho de Melo ret += dso__fprintf_buildid(pos, fp); 17449e03eb2dSArnaldo Carvalho de Melo ret += fprintf(fp, " %s\n", pos->long_name); 17459e03eb2dSArnaldo Carvalho de Melo } 17469e03eb2dSArnaldo Carvalho de Melo return ret; 17479e03eb2dSArnaldo Carvalho de Melo } 17489e03eb2dSArnaldo Carvalho de Melo 174988d3d9b7SArnaldo Carvalho de Melo size_t dsos__fprintf_buildid(FILE *fp, bool with_hits) 1750b0da954aSArnaldo Carvalho de Melo { 175188d3d9b7SArnaldo Carvalho de Melo return (__dsos__fprintf_buildid(&dsos__kernel, fp, with_hits) + 175288d3d9b7SArnaldo Carvalho de Melo __dsos__fprintf_buildid(&dsos__user, fp, with_hits)); 1753b0da954aSArnaldo Carvalho de Melo } 1754b0da954aSArnaldo Carvalho de Melo 1755f1dfa0b1SArnaldo Carvalho de Melo static struct dso *dsos__create_kernel(const char *vmlinux) 1756cd84c2acSFrederic Weisbecker { 175795011c60SArnaldo Carvalho de Melo struct dso *kernel = dso__new(vmlinux ?: "[kernel.kallsyms]"); 1758cd84c2acSFrederic Weisbecker 17592446042cSArnaldo Carvalho de Melo if (kernel == NULL) 1760f1dfa0b1SArnaldo Carvalho de Melo return NULL; 1761c338aee8SArnaldo Carvalho de Melo 17622446042cSArnaldo Carvalho de Melo kernel->short_name = "[kernel]"; 1763c338aee8SArnaldo Carvalho de Melo kernel->kernel = 1; 1764cc612d81SArnaldo Carvalho de Melo 176500a192b3SArnaldo Carvalho de Melo vdso = dso__new("[vdso]"); 1766c338aee8SArnaldo Carvalho de Melo if (vdso == NULL) 1767f1dfa0b1SArnaldo Carvalho de Melo goto out_delete_kernel_dso; 17683610583cSArnaldo Carvalho de Melo dso__set_loaded(vdso, MAP__FUNCTION); 1769cd84c2acSFrederic Weisbecker 17702446042cSArnaldo Carvalho de Melo if (sysfs__read_build_id("/sys/kernel/notes", kernel->build_id, 17712446042cSArnaldo Carvalho de Melo sizeof(kernel->build_id)) == 0) 17722446042cSArnaldo Carvalho de Melo kernel->has_build_id = true; 17732446042cSArnaldo Carvalho de Melo 1774b0da954aSArnaldo Carvalho de Melo dsos__add(&dsos__kernel, kernel); 1775b0da954aSArnaldo Carvalho de Melo dsos__add(&dsos__user, vdso); 1776cd84c2acSFrederic Weisbecker 1777f1dfa0b1SArnaldo Carvalho de Melo return kernel; 1778c338aee8SArnaldo Carvalho de Melo 1779c338aee8SArnaldo Carvalho de Melo out_delete_kernel_dso: 1780c338aee8SArnaldo Carvalho de Melo dso__delete(kernel); 1781f1dfa0b1SArnaldo Carvalho de Melo return NULL; 1782f1dfa0b1SArnaldo Carvalho de Melo } 1783f1dfa0b1SArnaldo Carvalho de Melo 1784b7cece76SArnaldo Carvalho de Melo int __map_groups__create_kernel_maps(struct map_groups *self, 1785de176489SArnaldo Carvalho de Melo struct map *vmlinux_maps[MAP__NR_TYPES], 1786b7cece76SArnaldo Carvalho de Melo struct dso *kernel) 1787f1dfa0b1SArnaldo Carvalho de Melo { 1788de176489SArnaldo Carvalho de Melo enum map_type type; 1789f1dfa0b1SArnaldo Carvalho de Melo 1790de176489SArnaldo Carvalho de Melo for (type = 0; type < MAP__NR_TYPES; ++type) { 1791de176489SArnaldo Carvalho de Melo vmlinux_maps[type] = map__new2(0, kernel, type); 1792de176489SArnaldo Carvalho de Melo if (vmlinux_maps[type] == NULL) 1793f1dfa0b1SArnaldo Carvalho de Melo return -1; 1794f1dfa0b1SArnaldo Carvalho de Melo 1795de176489SArnaldo Carvalho de Melo vmlinux_maps[type]->map_ip = 1796de176489SArnaldo Carvalho de Melo vmlinux_maps[type]->unmap_ip = identity__map_ip; 1797de176489SArnaldo Carvalho de Melo map_groups__insert(self, vmlinux_maps[type]); 1798f1dfa0b1SArnaldo Carvalho de Melo } 1799f1dfa0b1SArnaldo Carvalho de Melo 1800f1dfa0b1SArnaldo Carvalho de Melo return 0; 18012446042cSArnaldo Carvalho de Melo } 18022446042cSArnaldo Carvalho de Melo 1803b7cece76SArnaldo Carvalho de Melo static int map_groups__create_kernel_maps(struct map_groups *self, 1804b7cece76SArnaldo Carvalho de Melo struct map *vmlinux_maps[MAP__NR_TYPES], 1805b7cece76SArnaldo Carvalho de Melo const char *vmlinux) 1806b7cece76SArnaldo Carvalho de Melo { 1807b7cece76SArnaldo Carvalho de Melo struct dso *kernel = dsos__create_kernel(vmlinux); 1808b7cece76SArnaldo Carvalho de Melo 1809b7cece76SArnaldo Carvalho de Melo if (kernel == NULL) 1810b7cece76SArnaldo Carvalho de Melo return -1; 1811b7cece76SArnaldo Carvalho de Melo 1812b7cece76SArnaldo Carvalho de Melo return __map_groups__create_kernel_maps(self, vmlinux_maps, kernel); 1813b7cece76SArnaldo Carvalho de Melo } 1814b7cece76SArnaldo Carvalho de Melo 1815cc612d81SArnaldo Carvalho de Melo static void vmlinux_path__exit(void) 18162446042cSArnaldo Carvalho de Melo { 1817cc612d81SArnaldo Carvalho de Melo while (--vmlinux_path__nr_entries >= 0) { 1818cc612d81SArnaldo Carvalho de Melo free(vmlinux_path[vmlinux_path__nr_entries]); 1819cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = NULL; 1820cc612d81SArnaldo Carvalho de Melo } 1821cc612d81SArnaldo Carvalho de Melo 1822cc612d81SArnaldo Carvalho de Melo free(vmlinux_path); 1823cc612d81SArnaldo Carvalho de Melo vmlinux_path = NULL; 1824cc612d81SArnaldo Carvalho de Melo } 1825cc612d81SArnaldo Carvalho de Melo 1826cc612d81SArnaldo Carvalho de Melo static int vmlinux_path__init(void) 1827cc612d81SArnaldo Carvalho de Melo { 1828cc612d81SArnaldo Carvalho de Melo struct utsname uts; 1829cc612d81SArnaldo Carvalho de Melo char bf[PATH_MAX]; 1830cc612d81SArnaldo Carvalho de Melo 1831cc612d81SArnaldo Carvalho de Melo if (uname(&uts) < 0) 18322446042cSArnaldo Carvalho de Melo return -1; 18332446042cSArnaldo Carvalho de Melo 1834cc612d81SArnaldo Carvalho de Melo vmlinux_path = malloc(sizeof(char *) * 5); 1835cc612d81SArnaldo Carvalho de Melo if (vmlinux_path == NULL) 1836cc612d81SArnaldo Carvalho de Melo return -1; 1837cc612d81SArnaldo Carvalho de Melo 1838cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup("vmlinux"); 1839cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 1840cc612d81SArnaldo Carvalho de Melo goto out_fail; 1841cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 1842cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup("/boot/vmlinux"); 1843cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 1844cc612d81SArnaldo Carvalho de Melo goto out_fail; 1845cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 1846cc612d81SArnaldo Carvalho de Melo snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", uts.release); 1847cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); 1848cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 1849cc612d81SArnaldo Carvalho de Melo goto out_fail; 1850cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 1851cc612d81SArnaldo Carvalho de Melo snprintf(bf, sizeof(bf), "/lib/modules/%s/build/vmlinux", uts.release); 1852cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); 1853cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 1854cc612d81SArnaldo Carvalho de Melo goto out_fail; 1855cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 1856cc612d81SArnaldo Carvalho de Melo snprintf(bf, sizeof(bf), "/usr/lib/debug/lib/modules/%s/vmlinux", 1857cc612d81SArnaldo Carvalho de Melo uts.release); 1858cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); 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 1863cc612d81SArnaldo Carvalho de Melo return 0; 1864cc612d81SArnaldo Carvalho de Melo 1865cc612d81SArnaldo Carvalho de Melo out_fail: 1866cc612d81SArnaldo Carvalho de Melo vmlinux_path__exit(); 1867cc612d81SArnaldo Carvalho de Melo return -1; 1868cc612d81SArnaldo Carvalho de Melo } 1869cc612d81SArnaldo Carvalho de Melo 1870655000e7SArnaldo Carvalho de Melo static int setup_list(struct strlist **list, const char *list_str, 1871655000e7SArnaldo Carvalho de Melo const char *list_name) 1872655000e7SArnaldo Carvalho de Melo { 1873655000e7SArnaldo Carvalho de Melo if (list_str == NULL) 1874655000e7SArnaldo Carvalho de Melo return 0; 1875655000e7SArnaldo Carvalho de Melo 1876655000e7SArnaldo Carvalho de Melo *list = strlist__new(true, list_str); 1877655000e7SArnaldo Carvalho de Melo if (!*list) { 1878655000e7SArnaldo Carvalho de Melo pr_err("problems parsing %s list\n", list_name); 1879655000e7SArnaldo Carvalho de Melo return -1; 1880655000e7SArnaldo Carvalho de Melo } 1881655000e7SArnaldo Carvalho de Melo return 0; 1882655000e7SArnaldo Carvalho de Melo } 1883655000e7SArnaldo Carvalho de Melo 188475be6cf4SArnaldo Carvalho de Melo int symbol__init(void) 1885cc612d81SArnaldo Carvalho de Melo { 188695011c60SArnaldo Carvalho de Melo elf_version(EV_CURRENT); 188775be6cf4SArnaldo Carvalho de Melo if (symbol_conf.sort_by_name) 188875be6cf4SArnaldo Carvalho de Melo symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) - 188979406cd7SArnaldo Carvalho de Melo sizeof(struct symbol)); 1890b32d133aSArnaldo Carvalho de Melo 189175be6cf4SArnaldo Carvalho de Melo if (symbol_conf.try_vmlinux_path && vmlinux_path__init() < 0) 1892cc612d81SArnaldo Carvalho de Melo return -1; 1893cc612d81SArnaldo Carvalho de Melo 1894c410a338SArnaldo Carvalho de Melo if (symbol_conf.field_sep && *symbol_conf.field_sep == '.') { 1895c410a338SArnaldo Carvalho de Melo pr_err("'.' is the only non valid --field-separator argument\n"); 1896c410a338SArnaldo Carvalho de Melo return -1; 1897c410a338SArnaldo Carvalho de Melo } 1898c410a338SArnaldo Carvalho de Melo 1899655000e7SArnaldo Carvalho de Melo if (setup_list(&symbol_conf.dso_list, 1900655000e7SArnaldo Carvalho de Melo symbol_conf.dso_list_str, "dso") < 0) 1901655000e7SArnaldo Carvalho de Melo return -1; 1902655000e7SArnaldo Carvalho de Melo 1903655000e7SArnaldo Carvalho de Melo if (setup_list(&symbol_conf.comm_list, 1904655000e7SArnaldo Carvalho de Melo symbol_conf.comm_list_str, "comm") < 0) 1905655000e7SArnaldo Carvalho de Melo goto out_free_dso_list; 1906655000e7SArnaldo Carvalho de Melo 1907655000e7SArnaldo Carvalho de Melo if (setup_list(&symbol_conf.sym_list, 1908655000e7SArnaldo Carvalho de Melo symbol_conf.sym_list_str, "symbol") < 0) 1909655000e7SArnaldo Carvalho de Melo goto out_free_comm_list; 1910655000e7SArnaldo Carvalho de Melo 19114aa65636SArnaldo Carvalho de Melo return 0; 1912655000e7SArnaldo Carvalho de Melo 1913655000e7SArnaldo Carvalho de Melo out_free_dso_list: 1914655000e7SArnaldo Carvalho de Melo strlist__delete(symbol_conf.dso_list); 1915655000e7SArnaldo Carvalho de Melo out_free_comm_list: 1916655000e7SArnaldo Carvalho de Melo strlist__delete(symbol_conf.comm_list); 1917655000e7SArnaldo Carvalho de Melo return -1; 1918cc612d81SArnaldo Carvalho de Melo } 1919cc612d81SArnaldo Carvalho de Melo 192075be6cf4SArnaldo Carvalho de Melo int perf_session__create_kernel_maps(struct perf_session *self) 19214aa65636SArnaldo Carvalho de Melo { 1922de176489SArnaldo Carvalho de Melo if (map_groups__create_kernel_maps(&self->kmaps, self->vmlinux_maps, 192375be6cf4SArnaldo Carvalho de Melo symbol_conf.vmlinux_name) < 0) 19244aa65636SArnaldo Carvalho de Melo return -1; 19254aa65636SArnaldo Carvalho de Melo 192675be6cf4SArnaldo Carvalho de Melo if (symbol_conf.use_modules && 192775be6cf4SArnaldo Carvalho de Melo perf_session__create_module_maps(self) < 0) 19284aa65636SArnaldo Carvalho de Melo pr_debug("Failed to load list of modules for session %s, " 19294aa65636SArnaldo Carvalho de Melo "continuing...\n", self->filename); 193090c83218SArnaldo Carvalho de Melo /* 193190c83218SArnaldo Carvalho de Melo * Now that we have all the maps created, just set the ->end of them: 193290c83218SArnaldo Carvalho de Melo */ 19334aa65636SArnaldo Carvalho de Melo map_groups__fixup_end(&self->kmaps); 19346671cb16SArnaldo Carvalho de Melo return 0; 1935cd84c2acSFrederic Weisbecker } 1936