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 164cfc10d3bSArnaldo Carvalho de Melo static 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 { 17986470930SIngo Molnar struct dso *self = malloc(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 3488d06367fSArnaldo Carvalho de Melo int build_id__sprintf(u8 *self, int len, char *bf) 3498d06367fSArnaldo Carvalho de Melo { 3508d06367fSArnaldo Carvalho de Melo char *bid = bf; 3518d06367fSArnaldo Carvalho de Melo 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 386682b335aSArnaldo Carvalho de Melo int kallsyms__parse(void *arg, int (*process_symbol)(void *arg, const char *name, 387682b335aSArnaldo Carvalho de Melo char type, u64 start)) 38886470930SIngo Molnar { 38986470930SIngo Molnar char *line = NULL; 39086470930SIngo Molnar size_t n; 391682b335aSArnaldo Carvalho de Melo int err = 0; 39286470930SIngo Molnar FILE *file = fopen("/proc/kallsyms", "r"); 39386470930SIngo Molnar 39486470930SIngo Molnar if (file == NULL) 39586470930SIngo Molnar goto out_failure; 39686470930SIngo Molnar 39786470930SIngo Molnar while (!feof(file)) { 3989cffa8d5SPaul Mackerras u64 start; 39986470930SIngo Molnar int line_len, len; 40086470930SIngo Molnar char symbol_type; 4012e538c4aSArnaldo Carvalho de Melo char *symbol_name; 40286470930SIngo Molnar 40386470930SIngo Molnar line_len = getline(&line, &n, file); 40486470930SIngo Molnar if (line_len < 0) 40586470930SIngo Molnar break; 40686470930SIngo Molnar 40786470930SIngo Molnar if (!line) 40886470930SIngo Molnar goto out_failure; 40986470930SIngo Molnar 41086470930SIngo Molnar line[--line_len] = '\0'; /* \n */ 41186470930SIngo Molnar 41286470930SIngo Molnar len = hex2u64(line, &start); 41386470930SIngo Molnar 41486470930SIngo Molnar len++; 41586470930SIngo Molnar if (len + 2 >= line_len) 41686470930SIngo Molnar continue; 41786470930SIngo Molnar 41886470930SIngo Molnar symbol_type = toupper(line[len]); 419af427bf5SArnaldo Carvalho de Melo symbol_name = line + len + 2; 420682b335aSArnaldo Carvalho de Melo 421682b335aSArnaldo Carvalho de Melo err = process_symbol(arg, symbol_name, symbol_type, start); 422682b335aSArnaldo Carvalho de Melo if (err) 423682b335aSArnaldo Carvalho de Melo break; 424682b335aSArnaldo Carvalho de Melo } 425682b335aSArnaldo Carvalho de Melo 426682b335aSArnaldo Carvalho de Melo free(line); 427682b335aSArnaldo Carvalho de Melo fclose(file); 428682b335aSArnaldo Carvalho de Melo return err; 429682b335aSArnaldo Carvalho de Melo 430682b335aSArnaldo Carvalho de Melo out_failure: 431682b335aSArnaldo Carvalho de Melo return -1; 432682b335aSArnaldo Carvalho de Melo } 433682b335aSArnaldo Carvalho de Melo 434682b335aSArnaldo Carvalho de Melo struct process_kallsyms_args { 435682b335aSArnaldo Carvalho de Melo struct map *map; 436682b335aSArnaldo Carvalho de Melo struct dso *dso; 437682b335aSArnaldo Carvalho de Melo }; 438682b335aSArnaldo Carvalho de Melo 439682b335aSArnaldo Carvalho de Melo static int map__process_kallsym_symbol(void *arg, const char *name, 440682b335aSArnaldo Carvalho de Melo char type, u64 start) 441682b335aSArnaldo Carvalho de Melo { 442682b335aSArnaldo Carvalho de Melo struct symbol *sym; 443682b335aSArnaldo Carvalho de Melo struct process_kallsyms_args *a = arg; 444682b335aSArnaldo Carvalho de Melo struct rb_root *root = &a->dso->symbols[a->map->type]; 445682b335aSArnaldo Carvalho de Melo 446682b335aSArnaldo Carvalho de Melo if (!symbol_type__is_a(type, a->map->type)) 447682b335aSArnaldo Carvalho de Melo return 0; 448682b335aSArnaldo Carvalho de Melo 4492e538c4aSArnaldo Carvalho de Melo /* 4502e538c4aSArnaldo Carvalho de Melo * Will fix up the end later, when we have all symbols sorted. 4512e538c4aSArnaldo Carvalho de Melo */ 452682b335aSArnaldo Carvalho de Melo sym = symbol__new(start, 0, name); 453af427bf5SArnaldo Carvalho de Melo 4542e538c4aSArnaldo Carvalho de Melo if (sym == NULL) 455682b335aSArnaldo Carvalho de Melo return -ENOMEM; 45682164161SArnaldo Carvalho de Melo /* 45782164161SArnaldo Carvalho de Melo * We will pass the symbols to the filter later, in 4584e06255fSArnaldo Carvalho de Melo * map__split_kallsyms, when we have split the maps per module 45982164161SArnaldo Carvalho de Melo */ 4604e06255fSArnaldo Carvalho de Melo symbols__insert(root, sym); 461682b335aSArnaldo Carvalho de Melo return 0; 4622e538c4aSArnaldo Carvalho de Melo } 4632e538c4aSArnaldo Carvalho de Melo 464682b335aSArnaldo Carvalho de Melo /* 465682b335aSArnaldo Carvalho de Melo * Loads the function entries in /proc/kallsyms into kernel_map->dso, 466682b335aSArnaldo Carvalho de Melo * so that we can in the next step set the symbol ->end address and then 467682b335aSArnaldo Carvalho de Melo * call kernel_maps__split_kallsyms. 468682b335aSArnaldo Carvalho de Melo */ 469682b335aSArnaldo Carvalho de Melo static int dso__load_all_kallsyms(struct dso *self, struct map *map) 470682b335aSArnaldo Carvalho de Melo { 471682b335aSArnaldo Carvalho de Melo struct process_kallsyms_args args = { .map = map, .dso = self, }; 472682b335aSArnaldo Carvalho de Melo return kallsyms__parse(&args, map__process_kallsym_symbol); 4732e538c4aSArnaldo Carvalho de Melo } 4742e538c4aSArnaldo Carvalho de Melo 4752e538c4aSArnaldo Carvalho de Melo /* 4762e538c4aSArnaldo Carvalho de Melo * Split the symbols into maps, making sure there are no overlaps, i.e. the 4772e538c4aSArnaldo Carvalho de Melo * kernel range is broken in several maps, named [kernel].N, as we don't have 4782e538c4aSArnaldo Carvalho de Melo * the original ELF section names vmlinux have. 4792e538c4aSArnaldo Carvalho de Melo */ 4809958e1f0SArnaldo Carvalho de Melo static int dso__split_kallsyms(struct dso *self, struct map *map, 4814aa65636SArnaldo Carvalho de Melo struct perf_session *session, symbol_filter_t filter) 4822e538c4aSArnaldo Carvalho de Melo { 4834e06255fSArnaldo Carvalho de Melo struct map *curr_map = map; 4842e538c4aSArnaldo Carvalho de Melo struct symbol *pos; 4852e538c4aSArnaldo Carvalho de Melo int count = 0; 4864e06255fSArnaldo Carvalho de Melo struct rb_root *root = &self->symbols[map->type]; 4874e06255fSArnaldo Carvalho de Melo struct rb_node *next = rb_first(root); 4882e538c4aSArnaldo Carvalho de Melo int kernel_range = 0; 4892e538c4aSArnaldo Carvalho de Melo 4902e538c4aSArnaldo Carvalho de Melo while (next) { 4912e538c4aSArnaldo Carvalho de Melo char *module; 4922e538c4aSArnaldo Carvalho de Melo 4932e538c4aSArnaldo Carvalho de Melo pos = rb_entry(next, struct symbol, rb_node); 4942e538c4aSArnaldo Carvalho de Melo next = rb_next(&pos->rb_node); 4952e538c4aSArnaldo Carvalho de Melo 4962e538c4aSArnaldo Carvalho de Melo module = strchr(pos->name, '\t'); 4972e538c4aSArnaldo Carvalho de Melo if (module) { 49875be6cf4SArnaldo Carvalho de Melo if (!symbol_conf.use_modules) 4991de8e245SArnaldo Carvalho de Melo goto discard_symbol; 5001de8e245SArnaldo Carvalho de Melo 5012e538c4aSArnaldo Carvalho de Melo *module++ = '\0'; 5022e538c4aSArnaldo Carvalho de Melo 5034e06255fSArnaldo Carvalho de Melo if (strcmp(self->name, module)) { 5044aa65636SArnaldo Carvalho de Melo curr_map = map_groups__find_by_name(&session->kmaps, map->type, module); 5054e06255fSArnaldo Carvalho de Melo if (curr_map == NULL) { 50695011c60SArnaldo Carvalho de Melo pr_debug("/proc/{kallsyms,modules} " 5076beba7adSArnaldo Carvalho de Melo "inconsistency!\n"); 508af427bf5SArnaldo Carvalho de Melo return -1; 509af427bf5SArnaldo Carvalho de Melo } 510af427bf5SArnaldo Carvalho de Melo } 51186470930SIngo Molnar /* 5122e538c4aSArnaldo Carvalho de Melo * So that we look just like we get from .ko files, 5132e538c4aSArnaldo Carvalho de Melo * i.e. not prelinked, relative to map->start. 51486470930SIngo Molnar */ 5154e06255fSArnaldo Carvalho de Melo pos->start = curr_map->map_ip(curr_map, pos->start); 5164e06255fSArnaldo Carvalho de Melo pos->end = curr_map->map_ip(curr_map, pos->end); 5174e06255fSArnaldo Carvalho de Melo } else if (curr_map != map) { 5182e538c4aSArnaldo Carvalho de Melo char dso_name[PATH_MAX]; 5192e538c4aSArnaldo Carvalho de Melo struct dso *dso; 52086470930SIngo Molnar 5212e538c4aSArnaldo Carvalho de Melo snprintf(dso_name, sizeof(dso_name), "[kernel].%d", 5222e538c4aSArnaldo Carvalho de Melo kernel_range++); 52386470930SIngo Molnar 52400a192b3SArnaldo Carvalho de Melo dso = dso__new(dso_name); 5252e538c4aSArnaldo Carvalho de Melo if (dso == NULL) 5262e538c4aSArnaldo Carvalho de Melo return -1; 5272e538c4aSArnaldo Carvalho de Melo 5284e06255fSArnaldo Carvalho de Melo curr_map = map__new2(pos->start, dso, map->type); 5292e538c4aSArnaldo Carvalho de Melo if (map == NULL) { 5302e538c4aSArnaldo Carvalho de Melo dso__delete(dso); 5312e538c4aSArnaldo Carvalho de Melo return -1; 5322e538c4aSArnaldo Carvalho de Melo } 5332e538c4aSArnaldo Carvalho de Melo 5344e06255fSArnaldo Carvalho de Melo curr_map->map_ip = curr_map->unmap_ip = identity__map_ip; 5354aa65636SArnaldo Carvalho de Melo map_groups__insert(&session->kmaps, curr_map); 5362e538c4aSArnaldo Carvalho de Melo ++kernel_range; 5372e538c4aSArnaldo Carvalho de Melo } 5382e538c4aSArnaldo Carvalho de Melo 5394e06255fSArnaldo Carvalho de Melo if (filter && filter(curr_map, pos)) { 5401de8e245SArnaldo Carvalho de Melo discard_symbol: rb_erase(&pos->rb_node, root); 54100a192b3SArnaldo Carvalho de Melo symbol__delete(pos); 5422e538c4aSArnaldo Carvalho de Melo } else { 5434e06255fSArnaldo Carvalho de Melo if (curr_map != map) { 5444e06255fSArnaldo Carvalho de Melo rb_erase(&pos->rb_node, root); 5454e06255fSArnaldo Carvalho de Melo symbols__insert(&curr_map->dso->symbols[curr_map->type], pos); 5462e538c4aSArnaldo Carvalho de Melo } 5479974f496SMike Galbraith count++; 5489974f496SMike Galbraith } 54986470930SIngo Molnar } 55086470930SIngo Molnar 5519974f496SMike Galbraith return count; 55286470930SIngo Molnar } 55386470930SIngo Molnar 5542e538c4aSArnaldo Carvalho de Melo 5554e06255fSArnaldo Carvalho de Melo static int dso__load_kallsyms(struct dso *self, struct map *map, 5564aa65636SArnaldo Carvalho de Melo struct perf_session *session, symbol_filter_t filter) 5572e538c4aSArnaldo Carvalho de Melo { 5584e06255fSArnaldo Carvalho de Melo if (dso__load_all_kallsyms(self, map) < 0) 5592e538c4aSArnaldo Carvalho de Melo return -1; 5602e538c4aSArnaldo Carvalho de Melo 5614e06255fSArnaldo Carvalho de Melo symbols__fixup_end(&self->symbols[map->type]); 5624e06255fSArnaldo Carvalho de Melo self->origin = DSO__ORIG_KERNEL; 5632e538c4aSArnaldo Carvalho de Melo 5644aa65636SArnaldo Carvalho de Melo return dso__split_kallsyms(self, map, session, filter); 565af427bf5SArnaldo Carvalho de Melo } 566af427bf5SArnaldo Carvalho de Melo 567439d473bSArnaldo Carvalho de Melo static int dso__load_perf_map(struct dso *self, struct map *map, 5686beba7adSArnaldo Carvalho de Melo symbol_filter_t filter) 56980d496beSPekka Enberg { 57080d496beSPekka Enberg char *line = NULL; 57180d496beSPekka Enberg size_t n; 57280d496beSPekka Enberg FILE *file; 57380d496beSPekka Enberg int nr_syms = 0; 57480d496beSPekka Enberg 575439d473bSArnaldo Carvalho de Melo file = fopen(self->long_name, "r"); 57680d496beSPekka Enberg if (file == NULL) 57780d496beSPekka Enberg goto out_failure; 57880d496beSPekka Enberg 57980d496beSPekka Enberg while (!feof(file)) { 5809cffa8d5SPaul Mackerras u64 start, size; 58180d496beSPekka Enberg struct symbol *sym; 58280d496beSPekka Enberg int line_len, len; 58380d496beSPekka Enberg 58480d496beSPekka Enberg line_len = getline(&line, &n, file); 58580d496beSPekka Enberg if (line_len < 0) 58680d496beSPekka Enberg break; 58780d496beSPekka Enberg 58880d496beSPekka Enberg if (!line) 58980d496beSPekka Enberg goto out_failure; 59080d496beSPekka Enberg 59180d496beSPekka Enberg line[--line_len] = '\0'; /* \n */ 59280d496beSPekka Enberg 59380d496beSPekka Enberg len = hex2u64(line, &start); 59480d496beSPekka Enberg 59580d496beSPekka Enberg len++; 59680d496beSPekka Enberg if (len + 2 >= line_len) 59780d496beSPekka Enberg continue; 59880d496beSPekka Enberg 59980d496beSPekka Enberg len += hex2u64(line + len, &size); 60080d496beSPekka Enberg 60180d496beSPekka Enberg len++; 60280d496beSPekka Enberg if (len + 2 >= line_len) 60380d496beSPekka Enberg continue; 60480d496beSPekka Enberg 60500a192b3SArnaldo Carvalho de Melo sym = symbol__new(start, size, line + len); 60680d496beSPekka Enberg 60780d496beSPekka Enberg if (sym == NULL) 60880d496beSPekka Enberg goto out_delete_line; 60980d496beSPekka Enberg 610439d473bSArnaldo Carvalho de Melo if (filter && filter(map, sym)) 61100a192b3SArnaldo Carvalho de Melo symbol__delete(sym); 61280d496beSPekka Enberg else { 6136a4694a4SArnaldo Carvalho de Melo symbols__insert(&self->symbols[map->type], sym); 61480d496beSPekka Enberg nr_syms++; 61580d496beSPekka Enberg } 61680d496beSPekka Enberg } 61780d496beSPekka Enberg 61880d496beSPekka Enberg free(line); 61980d496beSPekka Enberg fclose(file); 62080d496beSPekka Enberg 62180d496beSPekka Enberg return nr_syms; 62280d496beSPekka Enberg 62380d496beSPekka Enberg out_delete_line: 62480d496beSPekka Enberg free(line); 62580d496beSPekka Enberg out_failure: 62680d496beSPekka Enberg return -1; 62780d496beSPekka Enberg } 62880d496beSPekka Enberg 62986470930SIngo Molnar /** 63086470930SIngo Molnar * elf_symtab__for_each_symbol - iterate thru all the symbols 63186470930SIngo Molnar * 63286470930SIngo Molnar * @self: struct elf_symtab instance to iterate 63383a0944fSIngo Molnar * @idx: uint32_t idx 63486470930SIngo Molnar * @sym: GElf_Sym iterator 63586470930SIngo Molnar */ 63683a0944fSIngo Molnar #define elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) \ 63783a0944fSIngo Molnar for (idx = 0, gelf_getsym(syms, idx, &sym);\ 63883a0944fSIngo Molnar idx < nr_syms; \ 63983a0944fSIngo Molnar idx++, gelf_getsym(syms, idx, &sym)) 64086470930SIngo Molnar 64186470930SIngo Molnar static inline uint8_t elf_sym__type(const GElf_Sym *sym) 64286470930SIngo Molnar { 64386470930SIngo Molnar return GELF_ST_TYPE(sym->st_info); 64486470930SIngo Molnar } 64586470930SIngo Molnar 64686470930SIngo Molnar static inline int elf_sym__is_function(const GElf_Sym *sym) 64786470930SIngo Molnar { 64886470930SIngo Molnar return elf_sym__type(sym) == STT_FUNC && 64986470930SIngo Molnar sym->st_name != 0 && 65081833130SArnaldo Carvalho de Melo sym->st_shndx != SHN_UNDEF; 65186470930SIngo Molnar } 65286470930SIngo Molnar 653f1dfa0b1SArnaldo Carvalho de Melo static inline bool elf_sym__is_object(const GElf_Sym *sym) 654f1dfa0b1SArnaldo Carvalho de Melo { 655f1dfa0b1SArnaldo Carvalho de Melo return elf_sym__type(sym) == STT_OBJECT && 656f1dfa0b1SArnaldo Carvalho de Melo sym->st_name != 0 && 657f1dfa0b1SArnaldo Carvalho de Melo sym->st_shndx != SHN_UNDEF; 658f1dfa0b1SArnaldo Carvalho de Melo } 659f1dfa0b1SArnaldo Carvalho de Melo 6606cfcc53eSMike Galbraith static inline int elf_sym__is_label(const GElf_Sym *sym) 6616cfcc53eSMike Galbraith { 6626cfcc53eSMike Galbraith return elf_sym__type(sym) == STT_NOTYPE && 6636cfcc53eSMike Galbraith sym->st_name != 0 && 6646cfcc53eSMike Galbraith sym->st_shndx != SHN_UNDEF && 6656cfcc53eSMike Galbraith sym->st_shndx != SHN_ABS; 6666cfcc53eSMike Galbraith } 6676cfcc53eSMike Galbraith 6686cfcc53eSMike Galbraith static inline const char *elf_sec__name(const GElf_Shdr *shdr, 6696cfcc53eSMike Galbraith const Elf_Data *secstrs) 6706cfcc53eSMike Galbraith { 6716cfcc53eSMike Galbraith return secstrs->d_buf + shdr->sh_name; 6726cfcc53eSMike Galbraith } 6736cfcc53eSMike Galbraith 6746cfcc53eSMike Galbraith static inline int elf_sec__is_text(const GElf_Shdr *shdr, 6756cfcc53eSMike Galbraith const Elf_Data *secstrs) 6766cfcc53eSMike Galbraith { 6776cfcc53eSMike Galbraith return strstr(elf_sec__name(shdr, secstrs), "text") != NULL; 6786cfcc53eSMike Galbraith } 6796cfcc53eSMike Galbraith 680f1dfa0b1SArnaldo Carvalho de Melo static inline bool elf_sec__is_data(const GElf_Shdr *shdr, 681f1dfa0b1SArnaldo Carvalho de Melo const Elf_Data *secstrs) 682f1dfa0b1SArnaldo Carvalho de Melo { 683f1dfa0b1SArnaldo Carvalho de Melo return strstr(elf_sec__name(shdr, secstrs), "data") != NULL; 684f1dfa0b1SArnaldo Carvalho de Melo } 685f1dfa0b1SArnaldo Carvalho de Melo 68686470930SIngo Molnar static inline const char *elf_sym__name(const GElf_Sym *sym, 68786470930SIngo Molnar const Elf_Data *symstrs) 68886470930SIngo Molnar { 68986470930SIngo Molnar return symstrs->d_buf + sym->st_name; 69086470930SIngo Molnar } 69186470930SIngo Molnar 69286470930SIngo Molnar static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, 69386470930SIngo Molnar GElf_Shdr *shp, const char *name, 69483a0944fSIngo Molnar size_t *idx) 69586470930SIngo Molnar { 69686470930SIngo Molnar Elf_Scn *sec = NULL; 69786470930SIngo Molnar size_t cnt = 1; 69886470930SIngo Molnar 69986470930SIngo Molnar while ((sec = elf_nextscn(elf, sec)) != NULL) { 70086470930SIngo Molnar char *str; 70186470930SIngo Molnar 70286470930SIngo Molnar gelf_getshdr(sec, shp); 70386470930SIngo Molnar str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name); 70486470930SIngo Molnar if (!strcmp(name, str)) { 70583a0944fSIngo Molnar if (idx) 70683a0944fSIngo Molnar *idx = cnt; 70786470930SIngo Molnar break; 70886470930SIngo Molnar } 70986470930SIngo Molnar ++cnt; 71086470930SIngo Molnar } 71186470930SIngo Molnar 71286470930SIngo Molnar return sec; 71386470930SIngo Molnar } 71486470930SIngo Molnar 71586470930SIngo Molnar #define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \ 71686470930SIngo Molnar for (idx = 0, pos = gelf_getrel(reldata, 0, &pos_mem); \ 71786470930SIngo Molnar idx < nr_entries; \ 71886470930SIngo Molnar ++idx, pos = gelf_getrel(reldata, idx, &pos_mem)) 71986470930SIngo Molnar 72086470930SIngo Molnar #define elf_section__for_each_rela(reldata, pos, pos_mem, idx, nr_entries) \ 72186470930SIngo Molnar for (idx = 0, pos = gelf_getrela(reldata, 0, &pos_mem); \ 72286470930SIngo Molnar idx < nr_entries; \ 72386470930SIngo Molnar ++idx, pos = gelf_getrela(reldata, idx, &pos_mem)) 72486470930SIngo Molnar 725a25e46c4SArnaldo Carvalho de Melo /* 726a25e46c4SArnaldo Carvalho de Melo * We need to check if we have a .dynsym, so that we can handle the 727a25e46c4SArnaldo Carvalho de Melo * .plt, synthesizing its symbols, that aren't on the symtabs (be it 728a25e46c4SArnaldo Carvalho de Melo * .dynsym or .symtab). 729a25e46c4SArnaldo Carvalho de Melo * And always look at the original dso, not at debuginfo packages, that 730a25e46c4SArnaldo Carvalho de Melo * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS). 731a25e46c4SArnaldo Carvalho de Melo */ 73282164161SArnaldo Carvalho de Melo static int dso__synthesize_plt_symbols(struct dso *self, struct map *map, 73382164161SArnaldo Carvalho de Melo symbol_filter_t filter) 73486470930SIngo Molnar { 73586470930SIngo Molnar uint32_t nr_rel_entries, idx; 73686470930SIngo Molnar GElf_Sym sym; 7379cffa8d5SPaul Mackerras u64 plt_offset; 73886470930SIngo Molnar GElf_Shdr shdr_plt; 73986470930SIngo Molnar struct symbol *f; 740a25e46c4SArnaldo Carvalho de Melo GElf_Shdr shdr_rel_plt, shdr_dynsym; 74186470930SIngo Molnar Elf_Data *reldata, *syms, *symstrs; 742a25e46c4SArnaldo Carvalho de Melo Elf_Scn *scn_plt_rel, *scn_symstrs, *scn_dynsym; 743a25e46c4SArnaldo Carvalho de Melo size_t dynsym_idx; 744a25e46c4SArnaldo Carvalho de Melo GElf_Ehdr ehdr; 74586470930SIngo Molnar char sympltname[1024]; 746a25e46c4SArnaldo Carvalho de Melo Elf *elf; 747a25e46c4SArnaldo Carvalho de Melo int nr = 0, symidx, fd, err = 0; 74886470930SIngo Molnar 749439d473bSArnaldo Carvalho de Melo fd = open(self->long_name, O_RDONLY); 750a25e46c4SArnaldo Carvalho de Melo if (fd < 0) 751a25e46c4SArnaldo Carvalho de Melo goto out; 752a25e46c4SArnaldo Carvalho de Melo 75384087126SMarti Raudsepp elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 754a25e46c4SArnaldo Carvalho de Melo if (elf == NULL) 755a25e46c4SArnaldo Carvalho de Melo goto out_close; 756a25e46c4SArnaldo Carvalho de Melo 757a25e46c4SArnaldo Carvalho de Melo if (gelf_getehdr(elf, &ehdr) == NULL) 758a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 759a25e46c4SArnaldo Carvalho de Melo 760a25e46c4SArnaldo Carvalho de Melo scn_dynsym = elf_section_by_name(elf, &ehdr, &shdr_dynsym, 761a25e46c4SArnaldo Carvalho de Melo ".dynsym", &dynsym_idx); 762a25e46c4SArnaldo Carvalho de Melo if (scn_dynsym == NULL) 763a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 764a25e46c4SArnaldo Carvalho de Melo 765a25e46c4SArnaldo Carvalho de Melo scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt, 76686470930SIngo Molnar ".rela.plt", NULL); 76786470930SIngo Molnar if (scn_plt_rel == NULL) { 768a25e46c4SArnaldo Carvalho de Melo scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt, 76986470930SIngo Molnar ".rel.plt", NULL); 77086470930SIngo Molnar if (scn_plt_rel == NULL) 771a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 77286470930SIngo Molnar } 77386470930SIngo Molnar 774a25e46c4SArnaldo Carvalho de Melo err = -1; 77586470930SIngo Molnar 776a25e46c4SArnaldo Carvalho de Melo if (shdr_rel_plt.sh_link != dynsym_idx) 777a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 778a25e46c4SArnaldo Carvalho de Melo 779a25e46c4SArnaldo Carvalho de Melo if (elf_section_by_name(elf, &ehdr, &shdr_plt, ".plt", NULL) == NULL) 780a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 78186470930SIngo Molnar 78286470930SIngo Molnar /* 78383a0944fSIngo Molnar * Fetch the relocation section to find the idxes to the GOT 78486470930SIngo Molnar * and the symbols in the .dynsym they refer to. 78586470930SIngo Molnar */ 78686470930SIngo Molnar reldata = elf_getdata(scn_plt_rel, NULL); 78786470930SIngo Molnar if (reldata == NULL) 788a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 78986470930SIngo Molnar 79086470930SIngo Molnar syms = elf_getdata(scn_dynsym, NULL); 79186470930SIngo Molnar if (syms == NULL) 792a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 79386470930SIngo Molnar 794a25e46c4SArnaldo Carvalho de Melo scn_symstrs = elf_getscn(elf, shdr_dynsym.sh_link); 79586470930SIngo Molnar if (scn_symstrs == NULL) 796a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 79786470930SIngo Molnar 79886470930SIngo Molnar symstrs = elf_getdata(scn_symstrs, NULL); 79986470930SIngo Molnar if (symstrs == NULL) 800a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 80186470930SIngo Molnar 80286470930SIngo Molnar nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize; 80386470930SIngo Molnar plt_offset = shdr_plt.sh_offset; 80486470930SIngo Molnar 80586470930SIngo Molnar if (shdr_rel_plt.sh_type == SHT_RELA) { 80686470930SIngo Molnar GElf_Rela pos_mem, *pos; 80786470930SIngo Molnar 80886470930SIngo Molnar elf_section__for_each_rela(reldata, pos, pos_mem, idx, 80986470930SIngo Molnar nr_rel_entries) { 81086470930SIngo Molnar symidx = GELF_R_SYM(pos->r_info); 81186470930SIngo Molnar plt_offset += shdr_plt.sh_entsize; 81286470930SIngo Molnar gelf_getsym(syms, symidx, &sym); 81386470930SIngo Molnar snprintf(sympltname, sizeof(sympltname), 81486470930SIngo Molnar "%s@plt", elf_sym__name(&sym, symstrs)); 81586470930SIngo Molnar 81686470930SIngo Molnar f = symbol__new(plt_offset, shdr_plt.sh_entsize, 81700a192b3SArnaldo Carvalho de Melo sympltname); 81886470930SIngo Molnar if (!f) 819a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 82086470930SIngo Molnar 82182164161SArnaldo Carvalho de Melo if (filter && filter(map, f)) 82282164161SArnaldo Carvalho de Melo symbol__delete(f); 82382164161SArnaldo Carvalho de Melo else { 8246a4694a4SArnaldo Carvalho de Melo symbols__insert(&self->symbols[map->type], f); 82586470930SIngo Molnar ++nr; 82686470930SIngo Molnar } 82782164161SArnaldo Carvalho de Melo } 82886470930SIngo Molnar } else if (shdr_rel_plt.sh_type == SHT_REL) { 82986470930SIngo Molnar GElf_Rel pos_mem, *pos; 83086470930SIngo Molnar elf_section__for_each_rel(reldata, pos, pos_mem, idx, 83186470930SIngo Molnar nr_rel_entries) { 83286470930SIngo Molnar symidx = GELF_R_SYM(pos->r_info); 83386470930SIngo Molnar plt_offset += shdr_plt.sh_entsize; 83486470930SIngo Molnar gelf_getsym(syms, symidx, &sym); 83586470930SIngo Molnar snprintf(sympltname, sizeof(sympltname), 83686470930SIngo Molnar "%s@plt", elf_sym__name(&sym, symstrs)); 83786470930SIngo Molnar 83886470930SIngo Molnar f = symbol__new(plt_offset, shdr_plt.sh_entsize, 83900a192b3SArnaldo Carvalho de Melo sympltname); 84086470930SIngo Molnar if (!f) 841a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 84286470930SIngo Molnar 84382164161SArnaldo Carvalho de Melo if (filter && filter(map, f)) 84482164161SArnaldo Carvalho de Melo symbol__delete(f); 84582164161SArnaldo Carvalho de Melo else { 8466a4694a4SArnaldo Carvalho de Melo symbols__insert(&self->symbols[map->type], f); 84786470930SIngo Molnar ++nr; 84886470930SIngo Molnar } 84986470930SIngo Molnar } 85082164161SArnaldo Carvalho de Melo } 85186470930SIngo Molnar 852a25e46c4SArnaldo Carvalho de Melo err = 0; 853a25e46c4SArnaldo Carvalho de Melo out_elf_end: 854a25e46c4SArnaldo Carvalho de Melo elf_end(elf); 855a25e46c4SArnaldo Carvalho de Melo out_close: 856a25e46c4SArnaldo Carvalho de Melo close(fd); 857a25e46c4SArnaldo Carvalho de Melo 858a25e46c4SArnaldo Carvalho de Melo if (err == 0) 85986470930SIngo Molnar return nr; 860a25e46c4SArnaldo Carvalho de Melo out: 8616beba7adSArnaldo Carvalho de Melo pr_warning("%s: problems reading %s PLT info.\n", 862439d473bSArnaldo Carvalho de Melo __func__, self->long_name); 863a25e46c4SArnaldo Carvalho de Melo return 0; 86486470930SIngo Molnar } 86586470930SIngo Molnar 866d45868d3SArnaldo Carvalho de Melo static bool elf_sym__is_a(GElf_Sym *self, enum map_type type) 867d45868d3SArnaldo Carvalho de Melo { 868d45868d3SArnaldo Carvalho de Melo switch (type) { 869d45868d3SArnaldo Carvalho de Melo case MAP__FUNCTION: 870d45868d3SArnaldo Carvalho de Melo return elf_sym__is_function(self); 871f1dfa0b1SArnaldo Carvalho de Melo case MAP__VARIABLE: 872f1dfa0b1SArnaldo Carvalho de Melo return elf_sym__is_object(self); 873d45868d3SArnaldo Carvalho de Melo default: 874d45868d3SArnaldo Carvalho de Melo return false; 875d45868d3SArnaldo Carvalho de Melo } 876d45868d3SArnaldo Carvalho de Melo } 877d45868d3SArnaldo Carvalho de Melo 878d45868d3SArnaldo Carvalho de Melo static bool elf_sec__is_a(GElf_Shdr *self, Elf_Data *secstrs, enum map_type type) 879d45868d3SArnaldo Carvalho de Melo { 880d45868d3SArnaldo Carvalho de Melo switch (type) { 881d45868d3SArnaldo Carvalho de Melo case MAP__FUNCTION: 882d45868d3SArnaldo Carvalho de Melo return elf_sec__is_text(self, secstrs); 883f1dfa0b1SArnaldo Carvalho de Melo case MAP__VARIABLE: 884f1dfa0b1SArnaldo Carvalho de Melo return elf_sec__is_data(self, secstrs); 885d45868d3SArnaldo Carvalho de Melo default: 886d45868d3SArnaldo Carvalho de Melo return false; 887d45868d3SArnaldo Carvalho de Melo } 888d45868d3SArnaldo Carvalho de Melo } 889d45868d3SArnaldo Carvalho de Melo 89095011c60SArnaldo Carvalho de Melo static int dso__load_sym(struct dso *self, struct map *map, 8914aa65636SArnaldo Carvalho de Melo struct perf_session *session, const char *name, int fd, 89295011c60SArnaldo Carvalho de Melo symbol_filter_t filter, int kernel, int kmodule) 89386470930SIngo Molnar { 8942e538c4aSArnaldo Carvalho de Melo struct map *curr_map = map; 8952e538c4aSArnaldo Carvalho de Melo struct dso *curr_dso = self; 8962e538c4aSArnaldo Carvalho de Melo size_t dso_name_len = strlen(self->short_name); 8976cfcc53eSMike Galbraith Elf_Data *symstrs, *secstrs; 89886470930SIngo Molnar uint32_t nr_syms; 89986470930SIngo Molnar int err = -1; 90083a0944fSIngo Molnar uint32_t idx; 90186470930SIngo Molnar GElf_Ehdr ehdr; 90286470930SIngo Molnar GElf_Shdr shdr; 90386470930SIngo Molnar Elf_Data *syms; 90486470930SIngo Molnar GElf_Sym sym; 905a25e46c4SArnaldo Carvalho de Melo Elf_Scn *sec, *sec_strndx; 90686470930SIngo Molnar Elf *elf; 907439d473bSArnaldo Carvalho de Melo int nr = 0; 90886470930SIngo Molnar 90984087126SMarti Raudsepp elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 91086470930SIngo Molnar if (elf == NULL) { 9116beba7adSArnaldo Carvalho de Melo pr_err("%s: cannot read %s ELF file.\n", __func__, name); 91286470930SIngo Molnar goto out_close; 91386470930SIngo Molnar } 91486470930SIngo Molnar 91586470930SIngo Molnar if (gelf_getehdr(elf, &ehdr) == NULL) { 9166beba7adSArnaldo Carvalho de Melo pr_err("%s: cannot get elf header.\n", __func__); 91786470930SIngo Molnar goto out_elf_end; 91886470930SIngo Molnar } 91986470930SIngo Molnar 92086470930SIngo Molnar sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL); 92186470930SIngo Molnar if (sec == NULL) { 922a25e46c4SArnaldo Carvalho de Melo sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL); 923a25e46c4SArnaldo Carvalho de Melo if (sec == NULL) 92486470930SIngo Molnar goto out_elf_end; 92586470930SIngo Molnar } 92686470930SIngo Molnar 92786470930SIngo Molnar syms = elf_getdata(sec, NULL); 92886470930SIngo Molnar if (syms == NULL) 92986470930SIngo Molnar goto out_elf_end; 93086470930SIngo Molnar 93186470930SIngo Molnar sec = elf_getscn(elf, shdr.sh_link); 93286470930SIngo Molnar if (sec == NULL) 93386470930SIngo Molnar goto out_elf_end; 93486470930SIngo Molnar 93586470930SIngo Molnar symstrs = elf_getdata(sec, NULL); 93686470930SIngo Molnar if (symstrs == NULL) 93786470930SIngo Molnar goto out_elf_end; 93886470930SIngo Molnar 9396cfcc53eSMike Galbraith sec_strndx = elf_getscn(elf, ehdr.e_shstrndx); 9406cfcc53eSMike Galbraith if (sec_strndx == NULL) 9416cfcc53eSMike Galbraith goto out_elf_end; 9426cfcc53eSMike Galbraith 9436cfcc53eSMike Galbraith secstrs = elf_getdata(sec_strndx, NULL); 9449b30a26bSStoyan Gaydarov if (secstrs == NULL) 9456cfcc53eSMike Galbraith goto out_elf_end; 9466cfcc53eSMike Galbraith 94786470930SIngo Molnar nr_syms = shdr.sh_size / shdr.sh_entsize; 94886470930SIngo Molnar 949e9fbc9dcSArjan van de Ven memset(&sym, 0, sizeof(sym)); 950d20ff6bdSMike Galbraith if (!kernel) { 95130d7a77dSArnaldo Carvalho de Melo self->adjust_symbols = (ehdr.e_type == ET_EXEC || 95230d7a77dSArnaldo Carvalho de Melo elf_section_by_name(elf, &ehdr, &shdr, 953f5812a7aSArnaldo Carvalho de Melo ".gnu.prelink_undo", 95430d7a77dSArnaldo Carvalho de Melo NULL) != NULL); 955d20ff6bdSMike Galbraith } else self->adjust_symbols = 0; 956d20ff6bdSMike Galbraith 95783a0944fSIngo Molnar elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) { 95886470930SIngo Molnar struct symbol *f; 95983a0944fSIngo Molnar const char *elf_name; 9602e538c4aSArnaldo Carvalho de Melo char *demangled = NULL; 9616cfcc53eSMike Galbraith int is_label = elf_sym__is_label(&sym); 9626cfcc53eSMike Galbraith const char *section_name; 96386470930SIngo Molnar 964d45868d3SArnaldo Carvalho de Melo if (!is_label && !elf_sym__is_a(&sym, map->type)) 96586470930SIngo Molnar continue; 96686470930SIngo Molnar 96786470930SIngo Molnar sec = elf_getscn(elf, sym.st_shndx); 96886470930SIngo Molnar if (!sec) 96986470930SIngo Molnar goto out_elf_end; 97086470930SIngo Molnar 97186470930SIngo Molnar gelf_getshdr(sec, &shdr); 9726cfcc53eSMike Galbraith 973d45868d3SArnaldo Carvalho de Melo if (is_label && !elf_sec__is_a(&shdr, secstrs, map->type)) 9746cfcc53eSMike Galbraith continue; 9756cfcc53eSMike Galbraith 9762e538c4aSArnaldo Carvalho de Melo elf_name = elf_sym__name(&sym, symstrs); 9776cfcc53eSMike Galbraith section_name = elf_sec__name(&shdr, secstrs); 97886470930SIngo Molnar 9792e538c4aSArnaldo Carvalho de Melo if (kernel || kmodule) { 9802e538c4aSArnaldo Carvalho de Melo char dso_name[PATH_MAX]; 9812e538c4aSArnaldo Carvalho de Melo 9822e538c4aSArnaldo Carvalho de Melo if (strcmp(section_name, 9832e538c4aSArnaldo Carvalho de Melo curr_dso->short_name + dso_name_len) == 0) 9842e538c4aSArnaldo Carvalho de Melo goto new_symbol; 9852e538c4aSArnaldo Carvalho de Melo 9862e538c4aSArnaldo Carvalho de Melo if (strcmp(section_name, ".text") == 0) { 9872e538c4aSArnaldo Carvalho de Melo curr_map = map; 9882e538c4aSArnaldo Carvalho de Melo curr_dso = self; 9892e538c4aSArnaldo Carvalho de Melo goto new_symbol; 990af427bf5SArnaldo Carvalho de Melo } 991af427bf5SArnaldo Carvalho de Melo 9922e538c4aSArnaldo Carvalho de Melo snprintf(dso_name, sizeof(dso_name), 9932e538c4aSArnaldo Carvalho de Melo "%s%s", self->short_name, section_name); 9942e538c4aSArnaldo Carvalho de Melo 9954aa65636SArnaldo Carvalho de Melo curr_map = map_groups__find_by_name(&session->kmaps, map->type, dso_name); 9962e538c4aSArnaldo Carvalho de Melo if (curr_map == NULL) { 9972e538c4aSArnaldo Carvalho de Melo u64 start = sym.st_value; 9982e538c4aSArnaldo Carvalho de Melo 9992e538c4aSArnaldo Carvalho de Melo if (kmodule) 10002e538c4aSArnaldo Carvalho de Melo start += map->start + shdr.sh_offset; 10012e538c4aSArnaldo Carvalho de Melo 100200a192b3SArnaldo Carvalho de Melo curr_dso = dso__new(dso_name); 10032e538c4aSArnaldo Carvalho de Melo if (curr_dso == NULL) 10042e538c4aSArnaldo Carvalho de Melo goto out_elf_end; 10053610583cSArnaldo Carvalho de Melo curr_map = map__new2(start, curr_dso, 10063610583cSArnaldo Carvalho de Melo MAP__FUNCTION); 10072e538c4aSArnaldo Carvalho de Melo if (curr_map == NULL) { 10082e538c4aSArnaldo Carvalho de Melo dso__delete(curr_dso); 10092e538c4aSArnaldo Carvalho de Melo goto out_elf_end; 10102e538c4aSArnaldo Carvalho de Melo } 1011ed52ce2eSArnaldo Carvalho de Melo curr_map->map_ip = identity__map_ip; 1012ed52ce2eSArnaldo Carvalho de Melo curr_map->unmap_ip = identity__map_ip; 10132e538c4aSArnaldo Carvalho de Melo curr_dso->origin = DSO__ORIG_KERNEL; 10144aa65636SArnaldo Carvalho de Melo map_groups__insert(&session->kmaps, curr_map); 1015b0da954aSArnaldo Carvalho de Melo dsos__add(&dsos__kernel, curr_dso); 10162e538c4aSArnaldo Carvalho de Melo } else 10172e538c4aSArnaldo Carvalho de Melo curr_dso = curr_map->dso; 10182e538c4aSArnaldo Carvalho de Melo 10192e538c4aSArnaldo Carvalho de Melo goto new_symbol; 10202e538c4aSArnaldo Carvalho de Melo } 10212e538c4aSArnaldo Carvalho de Melo 10222e538c4aSArnaldo Carvalho de Melo if (curr_dso->adjust_symbols) { 10236beba7adSArnaldo Carvalho de Melo pr_debug2("adjusting symbol: st_value: %Lx sh_addr: " 10246beba7adSArnaldo Carvalho de Melo "%Lx sh_offset: %Lx\n", (u64)sym.st_value, 10256beba7adSArnaldo Carvalho de Melo (u64)shdr.sh_addr, (u64)shdr.sh_offset); 102686470930SIngo Molnar sym.st_value -= shdr.sh_addr - shdr.sh_offset; 1027af427bf5SArnaldo Carvalho de Melo } 102828ac909bSArnaldo Carvalho de Melo /* 102928ac909bSArnaldo Carvalho de Melo * We need to figure out if the object was created from C++ sources 103028ac909bSArnaldo Carvalho de Melo * DWARF DW_compile_unit has this, but we don't always have access 103128ac909bSArnaldo Carvalho de Melo * to it... 103228ac909bSArnaldo Carvalho de Melo */ 103383a0944fSIngo Molnar demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI); 103428ac909bSArnaldo Carvalho de Melo if (demangled != NULL) 103583a0944fSIngo Molnar elf_name = demangled; 10362e538c4aSArnaldo Carvalho de Melo new_symbol: 103700a192b3SArnaldo Carvalho de Melo f = symbol__new(sym.st_value, sym.st_size, elf_name); 103828ac909bSArnaldo Carvalho de Melo free(demangled); 103986470930SIngo Molnar if (!f) 104086470930SIngo Molnar goto out_elf_end; 104186470930SIngo Molnar 10422e538c4aSArnaldo Carvalho de Melo if (filter && filter(curr_map, f)) 104300a192b3SArnaldo Carvalho de Melo symbol__delete(f); 104486470930SIngo Molnar else { 10456a4694a4SArnaldo Carvalho de Melo symbols__insert(&curr_dso->symbols[curr_map->type], f); 104686470930SIngo Molnar nr++; 104786470930SIngo Molnar } 104886470930SIngo Molnar } 104986470930SIngo Molnar 10502e538c4aSArnaldo Carvalho de Melo /* 10512e538c4aSArnaldo Carvalho de Melo * For misannotated, zeroed, ASM function sizes. 10522e538c4aSArnaldo Carvalho de Melo */ 10532e538c4aSArnaldo Carvalho de Melo if (nr > 0) 10546a4694a4SArnaldo Carvalho de Melo symbols__fixup_end(&self->symbols[map->type]); 105586470930SIngo Molnar err = nr; 105686470930SIngo Molnar out_elf_end: 105786470930SIngo Molnar elf_end(elf); 105886470930SIngo Molnar out_close: 105986470930SIngo Molnar return err; 106086470930SIngo Molnar } 106186470930SIngo Molnar 106278075caaSArnaldo Carvalho de Melo static bool dso__build_id_equal(const struct dso *self, u8 *build_id) 106378075caaSArnaldo Carvalho de Melo { 106478075caaSArnaldo Carvalho de Melo return memcmp(self->build_id, build_id, sizeof(self->build_id)) == 0; 106578075caaSArnaldo Carvalho de Melo } 106678075caaSArnaldo Carvalho de Melo 1067b0da954aSArnaldo Carvalho de Melo static bool __dsos__read_build_ids(struct list_head *head) 106857f395a7SFrederic Weisbecker { 1069e30a3d12SArnaldo Carvalho de Melo bool have_build_id = false; 107057f395a7SFrederic Weisbecker struct dso *pos; 107157f395a7SFrederic Weisbecker 1072b0da954aSArnaldo Carvalho de Melo list_for_each_entry(pos, head, node) 1073e30a3d12SArnaldo Carvalho de Melo if (filename__read_build_id(pos->long_name, pos->build_id, 1074e30a3d12SArnaldo Carvalho de Melo sizeof(pos->build_id)) > 0) { 1075e30a3d12SArnaldo Carvalho de Melo have_build_id = true; 1076e30a3d12SArnaldo Carvalho de Melo pos->has_build_id = true; 107757f395a7SFrederic Weisbecker } 107857f395a7SFrederic Weisbecker 1079e30a3d12SArnaldo Carvalho de Melo return have_build_id; 108057f395a7SFrederic Weisbecker } 108157f395a7SFrederic Weisbecker 1082b0da954aSArnaldo Carvalho de Melo bool dsos__read_build_ids(void) 1083b0da954aSArnaldo Carvalho de Melo { 10848b4825bfSArnaldo Carvalho de Melo bool kbuildids = __dsos__read_build_ids(&dsos__kernel), 10858b4825bfSArnaldo Carvalho de Melo ubuildids = __dsos__read_build_ids(&dsos__user); 10868b4825bfSArnaldo Carvalho de Melo return kbuildids || ubuildids; 1087b0da954aSArnaldo Carvalho de Melo } 1088b0da954aSArnaldo Carvalho de Melo 1089fd7a346eSArnaldo Carvalho de Melo /* 1090fd7a346eSArnaldo Carvalho de Melo * Align offset to 4 bytes as needed for note name and descriptor data. 1091fd7a346eSArnaldo Carvalho de Melo */ 1092fd7a346eSArnaldo Carvalho de Melo #define NOTE_ALIGN(n) (((n) + 3) & -4U) 1093fd7a346eSArnaldo Carvalho de Melo 10942643ce11SArnaldo Carvalho de Melo int filename__read_build_id(const char *filename, void *bf, size_t size) 10954d1e00a8SArnaldo Carvalho de Melo { 10962643ce11SArnaldo Carvalho de Melo int fd, err = -1; 10974d1e00a8SArnaldo Carvalho de Melo GElf_Ehdr ehdr; 10984d1e00a8SArnaldo Carvalho de Melo GElf_Shdr shdr; 1099fd7a346eSArnaldo Carvalho de Melo Elf_Data *data; 11004d1e00a8SArnaldo Carvalho de Melo Elf_Scn *sec; 1101e57cfcdaSPekka Enberg Elf_Kind ek; 1102fd7a346eSArnaldo Carvalho de Melo void *ptr; 11034d1e00a8SArnaldo Carvalho de Melo Elf *elf; 11044d1e00a8SArnaldo Carvalho de Melo 11052643ce11SArnaldo Carvalho de Melo if (size < BUILD_ID_SIZE) 11062643ce11SArnaldo Carvalho de Melo goto out; 11072643ce11SArnaldo Carvalho de Melo 11082643ce11SArnaldo Carvalho de Melo fd = open(filename, O_RDONLY); 11094d1e00a8SArnaldo Carvalho de Melo if (fd < 0) 11104d1e00a8SArnaldo Carvalho de Melo goto out; 11114d1e00a8SArnaldo Carvalho de Melo 111284087126SMarti Raudsepp elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 11134d1e00a8SArnaldo Carvalho de Melo if (elf == NULL) { 11148d06367fSArnaldo Carvalho de Melo pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename); 11154d1e00a8SArnaldo Carvalho de Melo goto out_close; 11164d1e00a8SArnaldo Carvalho de Melo } 11174d1e00a8SArnaldo Carvalho de Melo 1118e57cfcdaSPekka Enberg ek = elf_kind(elf); 1119e57cfcdaSPekka Enberg if (ek != ELF_K_ELF) 1120e57cfcdaSPekka Enberg goto out_elf_end; 1121e57cfcdaSPekka Enberg 11224d1e00a8SArnaldo Carvalho de Melo if (gelf_getehdr(elf, &ehdr) == NULL) { 11236beba7adSArnaldo Carvalho de Melo pr_err("%s: cannot get elf header.\n", __func__); 11244d1e00a8SArnaldo Carvalho de Melo goto out_elf_end; 11254d1e00a8SArnaldo Carvalho de Melo } 11264d1e00a8SArnaldo Carvalho de Melo 11272643ce11SArnaldo Carvalho de Melo sec = elf_section_by_name(elf, &ehdr, &shdr, 11282643ce11SArnaldo Carvalho de Melo ".note.gnu.build-id", NULL); 1129fd7a346eSArnaldo Carvalho de Melo if (sec == NULL) { 1130fd7a346eSArnaldo Carvalho de Melo sec = elf_section_by_name(elf, &ehdr, &shdr, 1131fd7a346eSArnaldo Carvalho de Melo ".notes", NULL); 11324d1e00a8SArnaldo Carvalho de Melo if (sec == NULL) 11334d1e00a8SArnaldo Carvalho de Melo goto out_elf_end; 1134fd7a346eSArnaldo Carvalho de Melo } 11354d1e00a8SArnaldo Carvalho de Melo 1136fd7a346eSArnaldo Carvalho de Melo data = elf_getdata(sec, NULL); 1137fd7a346eSArnaldo Carvalho de Melo if (data == NULL) 11384d1e00a8SArnaldo Carvalho de Melo goto out_elf_end; 1139fd7a346eSArnaldo Carvalho de Melo 1140fd7a346eSArnaldo Carvalho de Melo ptr = data->d_buf; 1141fd7a346eSArnaldo Carvalho de Melo while (ptr < (data->d_buf + data->d_size)) { 1142fd7a346eSArnaldo Carvalho de Melo GElf_Nhdr *nhdr = ptr; 1143fd7a346eSArnaldo Carvalho de Melo int namesz = NOTE_ALIGN(nhdr->n_namesz), 1144fd7a346eSArnaldo Carvalho de Melo descsz = NOTE_ALIGN(nhdr->n_descsz); 1145fd7a346eSArnaldo Carvalho de Melo const char *name; 1146fd7a346eSArnaldo Carvalho de Melo 1147fd7a346eSArnaldo Carvalho de Melo ptr += sizeof(*nhdr); 1148fd7a346eSArnaldo Carvalho de Melo name = ptr; 1149fd7a346eSArnaldo Carvalho de Melo ptr += namesz; 1150fd7a346eSArnaldo Carvalho de Melo if (nhdr->n_type == NT_GNU_BUILD_ID && 1151fd7a346eSArnaldo Carvalho de Melo nhdr->n_namesz == sizeof("GNU")) { 1152fd7a346eSArnaldo Carvalho de Melo if (memcmp(name, "GNU", sizeof("GNU")) == 0) { 1153fd7a346eSArnaldo Carvalho de Melo memcpy(bf, ptr, BUILD_ID_SIZE); 11542643ce11SArnaldo Carvalho de Melo err = BUILD_ID_SIZE; 1155fd7a346eSArnaldo Carvalho de Melo break; 1156fd7a346eSArnaldo Carvalho de Melo } 1157fd7a346eSArnaldo Carvalho de Melo } 1158fd7a346eSArnaldo Carvalho de Melo ptr += descsz; 1159fd7a346eSArnaldo Carvalho de Melo } 11602643ce11SArnaldo Carvalho de Melo out_elf_end: 11612643ce11SArnaldo Carvalho de Melo elf_end(elf); 11622643ce11SArnaldo Carvalho de Melo out_close: 11632643ce11SArnaldo Carvalho de Melo close(fd); 11642643ce11SArnaldo Carvalho de Melo out: 11652643ce11SArnaldo Carvalho de Melo return err; 11662643ce11SArnaldo Carvalho de Melo } 11672643ce11SArnaldo Carvalho de Melo 1168f1617b40SArnaldo Carvalho de Melo int sysfs__read_build_id(const char *filename, void *build_id, size_t size) 1169f1617b40SArnaldo Carvalho de Melo { 1170f1617b40SArnaldo Carvalho de Melo int fd, err = -1; 1171f1617b40SArnaldo Carvalho de Melo 1172f1617b40SArnaldo Carvalho de Melo if (size < BUILD_ID_SIZE) 1173f1617b40SArnaldo Carvalho de Melo goto out; 1174f1617b40SArnaldo Carvalho de Melo 1175f1617b40SArnaldo Carvalho de Melo fd = open(filename, O_RDONLY); 1176f1617b40SArnaldo Carvalho de Melo if (fd < 0) 1177f1617b40SArnaldo Carvalho de Melo goto out; 1178f1617b40SArnaldo Carvalho de Melo 1179f1617b40SArnaldo Carvalho de Melo while (1) { 1180f1617b40SArnaldo Carvalho de Melo char bf[BUFSIZ]; 1181f1617b40SArnaldo Carvalho de Melo GElf_Nhdr nhdr; 1182f1617b40SArnaldo Carvalho de Melo int namesz, descsz; 1183f1617b40SArnaldo Carvalho de Melo 1184f1617b40SArnaldo Carvalho de Melo if (read(fd, &nhdr, sizeof(nhdr)) != sizeof(nhdr)) 1185f1617b40SArnaldo Carvalho de Melo break; 1186f1617b40SArnaldo Carvalho de Melo 1187fd7a346eSArnaldo Carvalho de Melo namesz = NOTE_ALIGN(nhdr.n_namesz); 1188fd7a346eSArnaldo Carvalho de Melo descsz = NOTE_ALIGN(nhdr.n_descsz); 1189f1617b40SArnaldo Carvalho de Melo if (nhdr.n_type == NT_GNU_BUILD_ID && 1190f1617b40SArnaldo Carvalho de Melo nhdr.n_namesz == sizeof("GNU")) { 1191f1617b40SArnaldo Carvalho de Melo if (read(fd, bf, namesz) != namesz) 1192f1617b40SArnaldo Carvalho de Melo break; 1193f1617b40SArnaldo Carvalho de Melo if (memcmp(bf, "GNU", sizeof("GNU")) == 0) { 1194f1617b40SArnaldo Carvalho de Melo if (read(fd, build_id, 1195f1617b40SArnaldo Carvalho de Melo BUILD_ID_SIZE) == BUILD_ID_SIZE) { 1196f1617b40SArnaldo Carvalho de Melo err = 0; 1197f1617b40SArnaldo Carvalho de Melo break; 1198f1617b40SArnaldo Carvalho de Melo } 1199f1617b40SArnaldo Carvalho de Melo } else if (read(fd, bf, descsz) != descsz) 1200f1617b40SArnaldo Carvalho de Melo break; 1201f1617b40SArnaldo Carvalho de Melo } else { 1202f1617b40SArnaldo Carvalho de Melo int n = namesz + descsz; 1203f1617b40SArnaldo Carvalho de Melo if (read(fd, bf, n) != n) 1204f1617b40SArnaldo Carvalho de Melo break; 1205f1617b40SArnaldo Carvalho de Melo } 1206f1617b40SArnaldo Carvalho de Melo } 1207f1617b40SArnaldo Carvalho de Melo close(fd); 1208f1617b40SArnaldo Carvalho de Melo out: 1209f1617b40SArnaldo Carvalho de Melo return err; 1210f1617b40SArnaldo Carvalho de Melo } 1211f1617b40SArnaldo Carvalho de Melo 121294cb9e38SArnaldo Carvalho de Melo char dso__symtab_origin(const struct dso *self) 121394cb9e38SArnaldo Carvalho de Melo { 121494cb9e38SArnaldo Carvalho de Melo static const char origin[] = { 121594cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_KERNEL] = 'k', 121694cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_JAVA_JIT] = 'j', 12174cf40131SArnaldo Carvalho de Melo [DSO__ORIG_BUILD_ID_CACHE] = 'B', 121894cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_FEDORA] = 'f', 121994cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_UBUNTU] = 'u', 122094cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_BUILDID] = 'b', 122194cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_DSO] = 'd', 1222439d473bSArnaldo Carvalho de Melo [DSO__ORIG_KMODULE] = 'K', 122394cb9e38SArnaldo Carvalho de Melo }; 122494cb9e38SArnaldo Carvalho de Melo 122594cb9e38SArnaldo Carvalho de Melo if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND) 122694cb9e38SArnaldo Carvalho de Melo return '!'; 122794cb9e38SArnaldo Carvalho de Melo return origin[self->origin]; 122894cb9e38SArnaldo Carvalho de Melo } 122994cb9e38SArnaldo Carvalho de Melo 12304aa65636SArnaldo Carvalho de Melo int dso__load(struct dso *self, struct map *map, struct perf_session *session, 12314aa65636SArnaldo Carvalho de Melo symbol_filter_t filter) 123286470930SIngo Molnar { 12334d1e00a8SArnaldo Carvalho de Melo int size = PATH_MAX; 1234c338aee8SArnaldo Carvalho de Melo char *name; 1235d3379ab9SArnaldo Carvalho de Melo u8 build_id[BUILD_ID_SIZE]; 12364cf40131SArnaldo Carvalho de Melo char build_id_hex[BUILD_ID_SIZE * 2 + 1]; 123786470930SIngo Molnar int ret = -1; 123886470930SIngo Molnar int fd; 123986470930SIngo Molnar 12403610583cSArnaldo Carvalho de Melo dso__set_loaded(self, map->type); 124166bd8424SArnaldo Carvalho de Melo 1242c338aee8SArnaldo Carvalho de Melo if (self->kernel) 12434aa65636SArnaldo Carvalho de Melo return dso__load_kernel_sym(self, map, session, filter); 1244c338aee8SArnaldo Carvalho de Melo 1245c338aee8SArnaldo Carvalho de Melo name = malloc(size); 124686470930SIngo Molnar if (!name) 124786470930SIngo Molnar return -1; 124886470930SIngo Molnar 124930d7a77dSArnaldo Carvalho de Melo self->adjust_symbols = 0; 1250f5812a7aSArnaldo Carvalho de Melo 125194cb9e38SArnaldo Carvalho de Melo if (strncmp(self->name, "/tmp/perf-", 10) == 0) { 12526beba7adSArnaldo Carvalho de Melo ret = dso__load_perf_map(self, map, filter); 125394cb9e38SArnaldo Carvalho de Melo self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT : 125494cb9e38SArnaldo Carvalho de Melo DSO__ORIG_NOT_FOUND; 125594cb9e38SArnaldo Carvalho de Melo return ret; 125694cb9e38SArnaldo Carvalho de Melo } 125794cb9e38SArnaldo Carvalho de Melo 12584cf40131SArnaldo Carvalho de Melo self->origin = DSO__ORIG_BUILD_ID_CACHE; 125980d496beSPekka Enberg 12604cf40131SArnaldo Carvalho de Melo if (self->has_build_id) { 12614cf40131SArnaldo Carvalho de Melo build_id__sprintf(self->build_id, sizeof(self->build_id), 12624cf40131SArnaldo Carvalho de Melo build_id_hex); 12634cf40131SArnaldo Carvalho de Melo snprintf(name, size, "%s/%s/.build-id/%.2s/%s", 12644cf40131SArnaldo Carvalho de Melo getenv("HOME"), DEBUG_CACHE_DIR, 12654cf40131SArnaldo Carvalho de Melo build_id_hex, build_id_hex + 2); 12664cf40131SArnaldo Carvalho de Melo goto open_file; 12674cf40131SArnaldo Carvalho de Melo } 126886470930SIngo Molnar more: 126986470930SIngo Molnar do { 127094cb9e38SArnaldo Carvalho de Melo self->origin++; 127194cb9e38SArnaldo Carvalho de Melo switch (self->origin) { 127294cb9e38SArnaldo Carvalho de Melo case DSO__ORIG_FEDORA: 1273439d473bSArnaldo Carvalho de Melo snprintf(name, size, "/usr/lib/debug%s.debug", 1274439d473bSArnaldo Carvalho de Melo self->long_name); 127586470930SIngo Molnar break; 127694cb9e38SArnaldo Carvalho de Melo case DSO__ORIG_UBUNTU: 1277439d473bSArnaldo Carvalho de Melo snprintf(name, size, "/usr/lib/debug%s", 1278439d473bSArnaldo Carvalho de Melo self->long_name); 127986470930SIngo Molnar break; 128094cb9e38SArnaldo Carvalho de Melo case DSO__ORIG_BUILDID: 1281d3379ab9SArnaldo Carvalho de Melo if (filename__read_build_id(self->long_name, build_id, 1282d3379ab9SArnaldo Carvalho de Melo sizeof(build_id))) { 1283d3379ab9SArnaldo Carvalho de Melo build_id__sprintf(build_id, sizeof(build_id), 1284d3379ab9SArnaldo Carvalho de Melo build_id_hex); 12854d1e00a8SArnaldo Carvalho de Melo snprintf(name, size, 12864d1e00a8SArnaldo Carvalho de Melo "/usr/lib/debug/.build-id/%.2s/%s.debug", 1287d3379ab9SArnaldo Carvalho de Melo build_id_hex, build_id_hex + 2); 1288d3379ab9SArnaldo Carvalho de Melo if (self->has_build_id) 12898d06367fSArnaldo Carvalho de Melo goto compare_build_id; 1290d3379ab9SArnaldo Carvalho de Melo break; 12914d1e00a8SArnaldo Carvalho de Melo } 129294cb9e38SArnaldo Carvalho de Melo self->origin++; 12934d1e00a8SArnaldo Carvalho de Melo /* Fall thru */ 129494cb9e38SArnaldo Carvalho de Melo case DSO__ORIG_DSO: 1295439d473bSArnaldo Carvalho de Melo snprintf(name, size, "%s", self->long_name); 129686470930SIngo Molnar break; 129786470930SIngo Molnar 129886470930SIngo Molnar default: 129986470930SIngo Molnar goto out; 130086470930SIngo Molnar } 130186470930SIngo Molnar 13028d06367fSArnaldo Carvalho de Melo if (self->has_build_id) { 1303d3379ab9SArnaldo Carvalho de Melo if (filename__read_build_id(name, build_id, 1304d3379ab9SArnaldo Carvalho de Melo sizeof(build_id)) < 0) 13058d06367fSArnaldo Carvalho de Melo goto more; 13068d06367fSArnaldo Carvalho de Melo compare_build_id: 130778075caaSArnaldo Carvalho de Melo if (!dso__build_id_equal(self, build_id)) 13088d06367fSArnaldo Carvalho de Melo goto more; 13098d06367fSArnaldo Carvalho de Melo } 13104cf40131SArnaldo Carvalho de Melo open_file: 131186470930SIngo Molnar fd = open(name, O_RDONLY); 131286470930SIngo Molnar } while (fd < 0); 131386470930SIngo Molnar 131495011c60SArnaldo Carvalho de Melo ret = dso__load_sym(self, map, NULL, name, fd, filter, 0, 0); 131586470930SIngo Molnar close(fd); 131686470930SIngo Molnar 131786470930SIngo Molnar /* 131886470930SIngo Molnar * Some people seem to have debuginfo files _WITHOUT_ debug info!?!? 131986470930SIngo Molnar */ 132086470930SIngo Molnar if (!ret) 132186470930SIngo Molnar goto more; 132286470930SIngo Molnar 1323a25e46c4SArnaldo Carvalho de Melo if (ret > 0) { 132482164161SArnaldo Carvalho de Melo int nr_plt = dso__synthesize_plt_symbols(self, map, filter); 1325a25e46c4SArnaldo Carvalho de Melo if (nr_plt > 0) 1326a25e46c4SArnaldo Carvalho de Melo ret += nr_plt; 1327a25e46c4SArnaldo Carvalho de Melo } 132886470930SIngo Molnar out: 132986470930SIngo Molnar free(name); 13301340e6bbSArnaldo Carvalho de Melo if (ret < 0 && strstr(self->name, " (deleted)") != NULL) 13311340e6bbSArnaldo Carvalho de Melo return 0; 133286470930SIngo Molnar return ret; 133386470930SIngo Molnar } 133486470930SIngo Molnar 133579406cd7SArnaldo Carvalho de Melo struct map *map_groups__find_by_name(struct map_groups *self, 133679406cd7SArnaldo Carvalho de Melo enum map_type type, const char *name) 1337439d473bSArnaldo Carvalho de Melo { 1338439d473bSArnaldo Carvalho de Melo struct rb_node *nd; 1339439d473bSArnaldo Carvalho de Melo 134079406cd7SArnaldo Carvalho de Melo for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) { 1341439d473bSArnaldo Carvalho de Melo struct map *map = rb_entry(nd, struct map, rb_node); 1342439d473bSArnaldo Carvalho de Melo 1343439d473bSArnaldo Carvalho de Melo if (map->dso && strcmp(map->dso->name, name) == 0) 1344439d473bSArnaldo Carvalho de Melo return map; 1345439d473bSArnaldo Carvalho de Melo } 1346439d473bSArnaldo Carvalho de Melo 1347439d473bSArnaldo Carvalho de Melo return NULL; 1348439d473bSArnaldo Carvalho de Melo } 1349439d473bSArnaldo Carvalho de Melo 13504aa65636SArnaldo Carvalho de Melo static int perf_session__set_modules_path_dir(struct perf_session *self, char *dirname) 13516cfcc53eSMike Galbraith { 1352439d473bSArnaldo Carvalho de Melo struct dirent *dent; 1353439d473bSArnaldo Carvalho de Melo DIR *dir = opendir(dirname); 13546cfcc53eSMike Galbraith 1355439d473bSArnaldo Carvalho de Melo if (!dir) { 135687f8ea4cSArnaldo Carvalho de Melo pr_debug("%s: cannot open %s dir\n", __func__, dirname); 1357439d473bSArnaldo Carvalho de Melo return -1; 1358439d473bSArnaldo Carvalho de Melo } 13596cfcc53eSMike Galbraith 1360439d473bSArnaldo Carvalho de Melo while ((dent = readdir(dir)) != NULL) { 1361439d473bSArnaldo Carvalho de Melo char path[PATH_MAX]; 1362439d473bSArnaldo Carvalho de Melo 1363439d473bSArnaldo Carvalho de Melo if (dent->d_type == DT_DIR) { 1364439d473bSArnaldo Carvalho de Melo if (!strcmp(dent->d_name, ".") || 1365439d473bSArnaldo Carvalho de Melo !strcmp(dent->d_name, "..")) 1366439d473bSArnaldo Carvalho de Melo continue; 1367439d473bSArnaldo Carvalho de Melo 1368439d473bSArnaldo Carvalho de Melo snprintf(path, sizeof(path), "%s/%s", 1369439d473bSArnaldo Carvalho de Melo dirname, dent->d_name); 13704aa65636SArnaldo Carvalho de Melo if (perf_session__set_modules_path_dir(self, path) < 0) 1371439d473bSArnaldo Carvalho de Melo goto failure; 1372439d473bSArnaldo Carvalho de Melo } else { 1373439d473bSArnaldo Carvalho de Melo char *dot = strrchr(dent->d_name, '.'), 1374439d473bSArnaldo Carvalho de Melo dso_name[PATH_MAX]; 1375439d473bSArnaldo Carvalho de Melo struct map *map; 1376cfc10d3bSArnaldo Carvalho de Melo char *long_name; 1377439d473bSArnaldo Carvalho de Melo 1378439d473bSArnaldo Carvalho de Melo if (dot == NULL || strcmp(dot, ".ko")) 1379439d473bSArnaldo Carvalho de Melo continue; 1380439d473bSArnaldo Carvalho de Melo snprintf(dso_name, sizeof(dso_name), "[%.*s]", 1381439d473bSArnaldo Carvalho de Melo (int)(dot - dent->d_name), dent->d_name); 1382439d473bSArnaldo Carvalho de Melo 1383a2a99e8eSArnaldo Carvalho de Melo strxfrchar(dso_name, '-', '_'); 13844aa65636SArnaldo Carvalho de Melo map = map_groups__find_by_name(&self->kmaps, MAP__FUNCTION, dso_name); 1385439d473bSArnaldo Carvalho de Melo if (map == NULL) 1386439d473bSArnaldo Carvalho de Melo continue; 1387439d473bSArnaldo Carvalho de Melo 1388439d473bSArnaldo Carvalho de Melo snprintf(path, sizeof(path), "%s/%s", 1389439d473bSArnaldo Carvalho de Melo dirname, dent->d_name); 1390439d473bSArnaldo Carvalho de Melo 1391cfc10d3bSArnaldo Carvalho de Melo long_name = strdup(path); 1392cfc10d3bSArnaldo Carvalho de Melo if (long_name == NULL) 1393439d473bSArnaldo Carvalho de Melo goto failure; 1394cfc10d3bSArnaldo Carvalho de Melo dso__set_long_name(map->dso, long_name); 1395439d473bSArnaldo Carvalho de Melo } 1396439d473bSArnaldo Carvalho de Melo } 1397439d473bSArnaldo Carvalho de Melo 1398c338aee8SArnaldo Carvalho de Melo return 0; 1399439d473bSArnaldo Carvalho de Melo failure: 1400439d473bSArnaldo Carvalho de Melo closedir(dir); 1401439d473bSArnaldo Carvalho de Melo return -1; 1402439d473bSArnaldo Carvalho de Melo } 1403439d473bSArnaldo Carvalho de Melo 14044aa65636SArnaldo Carvalho de Melo static int perf_session__set_modules_path(struct perf_session *self) 1405439d473bSArnaldo Carvalho de Melo { 1406439d473bSArnaldo Carvalho de Melo struct utsname uts; 1407439d473bSArnaldo Carvalho de Melo char modules_path[PATH_MAX]; 1408439d473bSArnaldo Carvalho de Melo 1409439d473bSArnaldo Carvalho de Melo if (uname(&uts) < 0) 1410439d473bSArnaldo Carvalho de Melo return -1; 1411439d473bSArnaldo Carvalho de Melo 1412439d473bSArnaldo Carvalho de Melo snprintf(modules_path, sizeof(modules_path), "/lib/modules/%s/kernel", 1413439d473bSArnaldo Carvalho de Melo uts.release); 1414439d473bSArnaldo Carvalho de Melo 14154aa65636SArnaldo Carvalho de Melo return perf_session__set_modules_path_dir(self, modules_path); 1416439d473bSArnaldo Carvalho de Melo } 14176cfcc53eSMike Galbraith 14186cfcc53eSMike Galbraith /* 1419439d473bSArnaldo Carvalho de Melo * Constructor variant for modules (where we know from /proc/modules where 1420439d473bSArnaldo Carvalho de Melo * they are loaded) and for vmlinux, where only after we load all the 1421439d473bSArnaldo Carvalho de Melo * symbols we'll know where it starts and ends. 14226cfcc53eSMike Galbraith */ 14233610583cSArnaldo Carvalho de Melo static struct map *map__new2(u64 start, struct dso *dso, enum map_type type) 1424439d473bSArnaldo Carvalho de Melo { 1425439d473bSArnaldo Carvalho de Melo struct map *self = malloc(sizeof(*self)); 14266cfcc53eSMike Galbraith 1427439d473bSArnaldo Carvalho de Melo if (self != NULL) { 1428439d473bSArnaldo Carvalho de Melo /* 1429afb7b4f0SArnaldo Carvalho de Melo * ->end will be filled after we load all the symbols 1430439d473bSArnaldo Carvalho de Melo */ 14313610583cSArnaldo Carvalho de Melo map__init(self, type, start, 0, 0, dso); 1432439d473bSArnaldo Carvalho de Melo } 1433afb7b4f0SArnaldo Carvalho de Melo 1434439d473bSArnaldo Carvalho de Melo return self; 1435439d473bSArnaldo Carvalho de Melo } 1436439d473bSArnaldo Carvalho de Melo 14374aa65636SArnaldo Carvalho de Melo static int perf_session__create_module_maps(struct perf_session *self) 1438439d473bSArnaldo Carvalho de Melo { 1439439d473bSArnaldo Carvalho de Melo char *line = NULL; 1440439d473bSArnaldo Carvalho de Melo size_t n; 1441439d473bSArnaldo Carvalho de Melo FILE *file = fopen("/proc/modules", "r"); 1442439d473bSArnaldo Carvalho de Melo struct map *map; 1443439d473bSArnaldo Carvalho de Melo 1444439d473bSArnaldo Carvalho de Melo if (file == NULL) 1445439d473bSArnaldo Carvalho de Melo return -1; 1446439d473bSArnaldo Carvalho de Melo 1447439d473bSArnaldo Carvalho de Melo while (!feof(file)) { 1448439d473bSArnaldo Carvalho de Melo char name[PATH_MAX]; 1449439d473bSArnaldo Carvalho de Melo u64 start; 1450439d473bSArnaldo Carvalho de Melo struct dso *dso; 1451439d473bSArnaldo Carvalho de Melo char *sep; 1452439d473bSArnaldo Carvalho de Melo int line_len; 1453439d473bSArnaldo Carvalho de Melo 1454439d473bSArnaldo Carvalho de Melo line_len = getline(&line, &n, file); 1455439d473bSArnaldo Carvalho de Melo if (line_len < 0) 14566cfcc53eSMike Galbraith break; 14576cfcc53eSMike Galbraith 1458439d473bSArnaldo Carvalho de Melo if (!line) 1459439d473bSArnaldo Carvalho de Melo goto out_failure; 1460439d473bSArnaldo Carvalho de Melo 1461439d473bSArnaldo Carvalho de Melo line[--line_len] = '\0'; /* \n */ 1462439d473bSArnaldo Carvalho de Melo 1463439d473bSArnaldo Carvalho de Melo sep = strrchr(line, 'x'); 1464439d473bSArnaldo Carvalho de Melo if (sep == NULL) 1465439d473bSArnaldo Carvalho de Melo continue; 1466439d473bSArnaldo Carvalho de Melo 1467439d473bSArnaldo Carvalho de Melo hex2u64(sep + 1, &start); 1468439d473bSArnaldo Carvalho de Melo 1469439d473bSArnaldo Carvalho de Melo sep = strchr(line, ' '); 1470439d473bSArnaldo Carvalho de Melo if (sep == NULL) 1471439d473bSArnaldo Carvalho de Melo continue; 1472439d473bSArnaldo Carvalho de Melo 1473439d473bSArnaldo Carvalho de Melo *sep = '\0'; 1474439d473bSArnaldo Carvalho de Melo 1475439d473bSArnaldo Carvalho de Melo snprintf(name, sizeof(name), "[%s]", line); 147600a192b3SArnaldo Carvalho de Melo dso = dso__new(name); 1477439d473bSArnaldo Carvalho de Melo 1478439d473bSArnaldo Carvalho de Melo if (dso == NULL) 1479439d473bSArnaldo Carvalho de Melo goto out_delete_line; 1480439d473bSArnaldo Carvalho de Melo 14813610583cSArnaldo Carvalho de Melo map = map__new2(start, dso, MAP__FUNCTION); 1482439d473bSArnaldo Carvalho de Melo if (map == NULL) { 1483439d473bSArnaldo Carvalho de Melo dso__delete(dso); 1484439d473bSArnaldo Carvalho de Melo goto out_delete_line; 14856cfcc53eSMike Galbraith } 14866cfcc53eSMike Galbraith 1487f1617b40SArnaldo Carvalho de Melo snprintf(name, sizeof(name), 1488f1617b40SArnaldo Carvalho de Melo "/sys/module/%s/notes/.note.gnu.build-id", line); 1489f1617b40SArnaldo Carvalho de Melo if (sysfs__read_build_id(name, dso->build_id, 1490f1617b40SArnaldo Carvalho de Melo sizeof(dso->build_id)) == 0) 1491f1617b40SArnaldo Carvalho de Melo dso->has_build_id = true; 1492f1617b40SArnaldo Carvalho de Melo 1493439d473bSArnaldo Carvalho de Melo dso->origin = DSO__ORIG_KMODULE; 14944aa65636SArnaldo Carvalho de Melo map_groups__insert(&self->kmaps, map); 1495b0da954aSArnaldo Carvalho de Melo dsos__add(&dsos__kernel, dso); 14966cfcc53eSMike Galbraith } 14976cfcc53eSMike Galbraith 1498439d473bSArnaldo Carvalho de Melo free(line); 1499439d473bSArnaldo Carvalho de Melo fclose(file); 1500439d473bSArnaldo Carvalho de Melo 15014aa65636SArnaldo Carvalho de Melo return perf_session__set_modules_path(self); 1502439d473bSArnaldo Carvalho de Melo 1503439d473bSArnaldo Carvalho de Melo out_delete_line: 1504439d473bSArnaldo Carvalho de Melo free(line); 1505439d473bSArnaldo Carvalho de Melo out_failure: 1506439d473bSArnaldo Carvalho de Melo return -1; 15076cfcc53eSMike Galbraith } 15086cfcc53eSMike Galbraith 15099958e1f0SArnaldo Carvalho de Melo static int dso__load_vmlinux(struct dso *self, struct map *map, 15104aa65636SArnaldo Carvalho de Melo struct perf_session *session, 15116beba7adSArnaldo Carvalho de Melo const char *vmlinux, symbol_filter_t filter) 151286470930SIngo Molnar { 1513fbd733b8SArnaldo Carvalho de Melo int err = -1, fd; 151486470930SIngo Molnar 1515fbd733b8SArnaldo Carvalho de Melo if (self->has_build_id) { 1516fbd733b8SArnaldo Carvalho de Melo u8 build_id[BUILD_ID_SIZE]; 151766bd8424SArnaldo Carvalho de Melo 1518fbd733b8SArnaldo Carvalho de Melo if (filename__read_build_id(vmlinux, build_id, 1519fbd733b8SArnaldo Carvalho de Melo sizeof(build_id)) < 0) { 1520fbd733b8SArnaldo Carvalho de Melo pr_debug("No build_id in %s, ignoring it\n", vmlinux); 1521fbd733b8SArnaldo Carvalho de Melo return -1; 1522fbd733b8SArnaldo Carvalho de Melo } 1523fbd733b8SArnaldo Carvalho de Melo if (!dso__build_id_equal(self, build_id)) { 1524fbd733b8SArnaldo Carvalho de Melo char expected_build_id[BUILD_ID_SIZE * 2 + 1], 1525fbd733b8SArnaldo Carvalho de Melo vmlinux_build_id[BUILD_ID_SIZE * 2 + 1]; 1526fbd733b8SArnaldo Carvalho de Melo 1527fbd733b8SArnaldo Carvalho de Melo build_id__sprintf(self->build_id, 1528fbd733b8SArnaldo Carvalho de Melo sizeof(self->build_id), 1529fbd733b8SArnaldo Carvalho de Melo expected_build_id); 1530fbd733b8SArnaldo Carvalho de Melo build_id__sprintf(build_id, sizeof(build_id), 1531fbd733b8SArnaldo Carvalho de Melo vmlinux_build_id); 1532fbd733b8SArnaldo Carvalho de Melo pr_debug("build_id in %s is %s while expected is %s, " 1533fbd733b8SArnaldo Carvalho de Melo "ignoring it\n", vmlinux, vmlinux_build_id, 1534fbd733b8SArnaldo Carvalho de Melo expected_build_id); 1535fbd733b8SArnaldo Carvalho de Melo return -1; 1536fbd733b8SArnaldo Carvalho de Melo } 1537fbd733b8SArnaldo Carvalho de Melo } 1538fbd733b8SArnaldo Carvalho de Melo 1539fbd733b8SArnaldo Carvalho de Melo fd = open(vmlinux, O_RDONLY); 154086470930SIngo Molnar if (fd < 0) 154186470930SIngo Molnar return -1; 154286470930SIngo Molnar 15433610583cSArnaldo Carvalho de Melo dso__set_loaded(self, map->type); 15444aa65636SArnaldo Carvalho de Melo err = dso__load_sym(self, map, session, self->long_name, fd, filter, 1, 0); 154586470930SIngo Molnar close(fd); 154686470930SIngo Molnar 154786470930SIngo Molnar return err; 154886470930SIngo Molnar } 154986470930SIngo Molnar 1550c338aee8SArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *self, struct map *map, 15514aa65636SArnaldo Carvalho de Melo struct perf_session *session, symbol_filter_t filter) 155286470930SIngo Molnar { 1553cc612d81SArnaldo Carvalho de Melo int err; 1554cc612d81SArnaldo Carvalho de Melo bool is_kallsyms; 1555439d473bSArnaldo Carvalho de Melo 1556cc612d81SArnaldo Carvalho de Melo if (vmlinux_path != NULL) { 1557cc612d81SArnaldo Carvalho de Melo int i; 1558cc612d81SArnaldo Carvalho de Melo pr_debug("Looking at the vmlinux_path (%d entries long)\n", 1559cc612d81SArnaldo Carvalho de Melo vmlinux_path__nr_entries); 1560cc612d81SArnaldo Carvalho de Melo for (i = 0; i < vmlinux_path__nr_entries; ++i) { 15614aa65636SArnaldo Carvalho de Melo err = dso__load_vmlinux(self, map, session, 156295011c60SArnaldo Carvalho de Melo vmlinux_path[i], filter); 1563cc612d81SArnaldo Carvalho de Melo if (err > 0) { 1564cc612d81SArnaldo Carvalho de Melo pr_debug("Using %s for symbols\n", 1565cc612d81SArnaldo Carvalho de Melo vmlinux_path[i]); 1566cc612d81SArnaldo Carvalho de Melo dso__set_long_name(self, 1567cc612d81SArnaldo Carvalho de Melo strdup(vmlinux_path[i])); 1568cc612d81SArnaldo Carvalho de Melo goto out_fixup; 1569cc612d81SArnaldo Carvalho de Melo } 1570cc612d81SArnaldo Carvalho de Melo } 1571cc612d81SArnaldo Carvalho de Melo } 1572cc612d81SArnaldo Carvalho de Melo 1573cc612d81SArnaldo Carvalho de Melo is_kallsyms = self->long_name[0] == '['; 1574cc612d81SArnaldo Carvalho de Melo if (is_kallsyms) 1575cc612d81SArnaldo Carvalho de Melo goto do_kallsyms; 1576cc612d81SArnaldo Carvalho de Melo 15774aa65636SArnaldo Carvalho de Melo err = dso__load_vmlinux(self, map, session, self->long_name, filter); 1578ef6ae724SArnaldo Carvalho de Melo if (err <= 0) { 1579cc612d81SArnaldo Carvalho de Melo pr_info("The file %s cannot be used, " 1580cc612d81SArnaldo Carvalho de Melo "trying to use /proc/kallsyms...", self->long_name); 1581cc612d81SArnaldo Carvalho de Melo do_kallsyms: 15824aa65636SArnaldo Carvalho de Melo err = dso__load_kallsyms(self, map, session, filter); 1583cc612d81SArnaldo Carvalho de Melo if (err > 0 && !is_kallsyms) 1584ef6ae724SArnaldo Carvalho de Melo dso__set_long_name(self, strdup("[kernel.kallsyms]")); 1585ef6ae724SArnaldo Carvalho de Melo } 158686470930SIngo Molnar 1587439d473bSArnaldo Carvalho de Melo if (err > 0) { 1588cc612d81SArnaldo Carvalho de Melo out_fixup: 15896a4694a4SArnaldo Carvalho de Melo map__fixup_start(map); 15906a4694a4SArnaldo Carvalho de Melo map__fixup_end(map); 1591439d473bSArnaldo Carvalho de Melo } 159294cb9e38SArnaldo Carvalho de Melo 159386470930SIngo Molnar return err; 159486470930SIngo Molnar } 159586470930SIngo Molnar 1596b0da954aSArnaldo Carvalho de Melo LIST_HEAD(dsos__user); 1597b0da954aSArnaldo Carvalho de Melo LIST_HEAD(dsos__kernel); 1598cd84c2acSFrederic Weisbecker struct dso *vdso; 1599cd84c2acSFrederic Weisbecker 1600b0da954aSArnaldo Carvalho de Melo static void dsos__add(struct list_head *head, struct dso *dso) 1601cd84c2acSFrederic Weisbecker { 1602b0da954aSArnaldo Carvalho de Melo list_add_tail(&dso->node, head); 1603cd84c2acSFrederic Weisbecker } 1604cd84c2acSFrederic Weisbecker 1605b0da954aSArnaldo Carvalho de Melo static struct dso *dsos__find(struct list_head *head, const char *name) 1606cd84c2acSFrederic Weisbecker { 1607cd84c2acSFrederic Weisbecker struct dso *pos; 1608cd84c2acSFrederic Weisbecker 1609b0da954aSArnaldo Carvalho de Melo list_for_each_entry(pos, head, node) 1610cd84c2acSFrederic Weisbecker if (strcmp(pos->name, name) == 0) 1611cd84c2acSFrederic Weisbecker return pos; 1612cd84c2acSFrederic Weisbecker return NULL; 1613cd84c2acSFrederic Weisbecker } 1614cd84c2acSFrederic Weisbecker 161500a192b3SArnaldo Carvalho de Melo struct dso *dsos__findnew(const char *name) 1616cd84c2acSFrederic Weisbecker { 1617b0da954aSArnaldo Carvalho de Melo struct dso *dso = dsos__find(&dsos__user, name); 1618cd84c2acSFrederic Weisbecker 1619e4204992SArnaldo Carvalho de Melo if (!dso) { 162000a192b3SArnaldo Carvalho de Melo dso = dso__new(name); 1621cfc10d3bSArnaldo Carvalho de Melo if (dso != NULL) { 1622b0da954aSArnaldo Carvalho de Melo dsos__add(&dsos__user, dso); 1623cfc10d3bSArnaldo Carvalho de Melo dso__set_basename(dso); 1624cfc10d3bSArnaldo Carvalho de Melo } 1625e4204992SArnaldo Carvalho de Melo } 1626cd84c2acSFrederic Weisbecker 1627cd84c2acSFrederic Weisbecker return dso; 1628cd84c2acSFrederic Weisbecker } 1629cd84c2acSFrederic Weisbecker 1630b0da954aSArnaldo Carvalho de Melo static void __dsos__fprintf(struct list_head *head, FILE *fp) 1631cd84c2acSFrederic Weisbecker { 1632cd84c2acSFrederic Weisbecker struct dso *pos; 1633cd84c2acSFrederic Weisbecker 163495011c60SArnaldo Carvalho de Melo list_for_each_entry(pos, head, node) { 163595011c60SArnaldo Carvalho de Melo int i; 163695011c60SArnaldo Carvalho de Melo for (i = 0; i < MAP__NR_TYPES; ++i) 163795011c60SArnaldo Carvalho de Melo dso__fprintf(pos, i, fp); 163895011c60SArnaldo Carvalho de Melo } 1639cd84c2acSFrederic Weisbecker } 1640cd84c2acSFrederic Weisbecker 1641b0da954aSArnaldo Carvalho de Melo void dsos__fprintf(FILE *fp) 1642b0da954aSArnaldo Carvalho de Melo { 1643b0da954aSArnaldo Carvalho de Melo __dsos__fprintf(&dsos__kernel, fp); 1644b0da954aSArnaldo Carvalho de Melo __dsos__fprintf(&dsos__user, fp); 1645b0da954aSArnaldo Carvalho de Melo } 1646b0da954aSArnaldo Carvalho de Melo 1647b0da954aSArnaldo Carvalho de Melo static size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp) 16489e03eb2dSArnaldo Carvalho de Melo { 16499e03eb2dSArnaldo Carvalho de Melo struct dso *pos; 16509e03eb2dSArnaldo Carvalho de Melo size_t ret = 0; 16519e03eb2dSArnaldo Carvalho de Melo 1652b0da954aSArnaldo Carvalho de Melo list_for_each_entry(pos, head, node) { 16539e03eb2dSArnaldo Carvalho de Melo ret += dso__fprintf_buildid(pos, fp); 16549e03eb2dSArnaldo Carvalho de Melo ret += fprintf(fp, " %s\n", pos->long_name); 16559e03eb2dSArnaldo Carvalho de Melo } 16569e03eb2dSArnaldo Carvalho de Melo return ret; 16579e03eb2dSArnaldo Carvalho de Melo } 16589e03eb2dSArnaldo Carvalho de Melo 1659b0da954aSArnaldo Carvalho de Melo size_t dsos__fprintf_buildid(FILE *fp) 1660b0da954aSArnaldo Carvalho de Melo { 1661b0da954aSArnaldo Carvalho de Melo return (__dsos__fprintf_buildid(&dsos__kernel, fp) + 1662b0da954aSArnaldo Carvalho de Melo __dsos__fprintf_buildid(&dsos__user, fp)); 1663b0da954aSArnaldo Carvalho de Melo } 1664b0da954aSArnaldo Carvalho de Melo 1665f1dfa0b1SArnaldo Carvalho de Melo static struct dso *dsos__create_kernel(const char *vmlinux) 1666cd84c2acSFrederic Weisbecker { 166795011c60SArnaldo Carvalho de Melo struct dso *kernel = dso__new(vmlinux ?: "[kernel.kallsyms]"); 1668cd84c2acSFrederic Weisbecker 16692446042cSArnaldo Carvalho de Melo if (kernel == NULL) 1670f1dfa0b1SArnaldo Carvalho de Melo return NULL; 1671c338aee8SArnaldo Carvalho de Melo 16722446042cSArnaldo Carvalho de Melo kernel->short_name = "[kernel]"; 1673c338aee8SArnaldo Carvalho de Melo kernel->kernel = 1; 1674cc612d81SArnaldo Carvalho de Melo 167500a192b3SArnaldo Carvalho de Melo vdso = dso__new("[vdso]"); 1676c338aee8SArnaldo Carvalho de Melo if (vdso == NULL) 1677f1dfa0b1SArnaldo Carvalho de Melo goto out_delete_kernel_dso; 16783610583cSArnaldo Carvalho de Melo dso__set_loaded(vdso, MAP__FUNCTION); 1679cd84c2acSFrederic Weisbecker 16802446042cSArnaldo Carvalho de Melo if (sysfs__read_build_id("/sys/kernel/notes", kernel->build_id, 16812446042cSArnaldo Carvalho de Melo sizeof(kernel->build_id)) == 0) 16822446042cSArnaldo Carvalho de Melo kernel->has_build_id = true; 16832446042cSArnaldo Carvalho de Melo 1684b0da954aSArnaldo Carvalho de Melo dsos__add(&dsos__kernel, kernel); 1685b0da954aSArnaldo Carvalho de Melo dsos__add(&dsos__user, vdso); 1686cd84c2acSFrederic Weisbecker 1687f1dfa0b1SArnaldo Carvalho de Melo return kernel; 1688c338aee8SArnaldo Carvalho de Melo 1689c338aee8SArnaldo Carvalho de Melo out_delete_kernel_dso: 1690c338aee8SArnaldo Carvalho de Melo dso__delete(kernel); 1691f1dfa0b1SArnaldo Carvalho de Melo return NULL; 1692f1dfa0b1SArnaldo Carvalho de Melo } 1693f1dfa0b1SArnaldo Carvalho de Melo 1694*de176489SArnaldo Carvalho de Melo static int map_groups__create_kernel_maps(struct map_groups *self, 1695*de176489SArnaldo Carvalho de Melo struct map *vmlinux_maps[MAP__NR_TYPES], 1696*de176489SArnaldo Carvalho de Melo const char *vmlinux) 1697f1dfa0b1SArnaldo Carvalho de Melo { 1698f1dfa0b1SArnaldo Carvalho de Melo struct dso *kernel = dsos__create_kernel(vmlinux); 1699*de176489SArnaldo Carvalho de Melo enum map_type type; 1700f1dfa0b1SArnaldo Carvalho de Melo 1701f1dfa0b1SArnaldo Carvalho de Melo if (kernel == NULL) 1702c338aee8SArnaldo Carvalho de Melo return -1; 1703f1dfa0b1SArnaldo Carvalho de Melo 1704*de176489SArnaldo Carvalho de Melo for (type = 0; type < MAP__NR_TYPES; ++type) { 1705*de176489SArnaldo Carvalho de Melo vmlinux_maps[type] = map__new2(0, kernel, type); 1706*de176489SArnaldo Carvalho de Melo if (vmlinux_maps[type] == NULL) 1707f1dfa0b1SArnaldo Carvalho de Melo return -1; 1708f1dfa0b1SArnaldo Carvalho de Melo 1709*de176489SArnaldo Carvalho de Melo vmlinux_maps[type]->map_ip = 1710*de176489SArnaldo Carvalho de Melo vmlinux_maps[type]->unmap_ip = identity__map_ip; 1711*de176489SArnaldo Carvalho de Melo map_groups__insert(self, vmlinux_maps[type]); 1712f1dfa0b1SArnaldo Carvalho de Melo } 1713f1dfa0b1SArnaldo Carvalho de Melo 1714f1dfa0b1SArnaldo Carvalho de Melo return 0; 17152446042cSArnaldo Carvalho de Melo } 17162446042cSArnaldo Carvalho de Melo 1717cc612d81SArnaldo Carvalho de Melo static void vmlinux_path__exit(void) 17182446042cSArnaldo Carvalho de Melo { 1719cc612d81SArnaldo Carvalho de Melo while (--vmlinux_path__nr_entries >= 0) { 1720cc612d81SArnaldo Carvalho de Melo free(vmlinux_path[vmlinux_path__nr_entries]); 1721cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = NULL; 1722cc612d81SArnaldo Carvalho de Melo } 1723cc612d81SArnaldo Carvalho de Melo 1724cc612d81SArnaldo Carvalho de Melo free(vmlinux_path); 1725cc612d81SArnaldo Carvalho de Melo vmlinux_path = NULL; 1726cc612d81SArnaldo Carvalho de Melo } 1727cc612d81SArnaldo Carvalho de Melo 1728cc612d81SArnaldo Carvalho de Melo static int vmlinux_path__init(void) 1729cc612d81SArnaldo Carvalho de Melo { 1730cc612d81SArnaldo Carvalho de Melo struct utsname uts; 1731cc612d81SArnaldo Carvalho de Melo char bf[PATH_MAX]; 1732cc612d81SArnaldo Carvalho de Melo 1733cc612d81SArnaldo Carvalho de Melo if (uname(&uts) < 0) 17342446042cSArnaldo Carvalho de Melo return -1; 17352446042cSArnaldo Carvalho de Melo 1736cc612d81SArnaldo Carvalho de Melo vmlinux_path = malloc(sizeof(char *) * 5); 1737cc612d81SArnaldo Carvalho de Melo if (vmlinux_path == NULL) 1738cc612d81SArnaldo Carvalho de Melo return -1; 1739cc612d81SArnaldo Carvalho de Melo 1740cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup("vmlinux"); 1741cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 1742cc612d81SArnaldo Carvalho de Melo goto out_fail; 1743cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 1744cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup("/boot/vmlinux"); 1745cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 1746cc612d81SArnaldo Carvalho de Melo goto out_fail; 1747cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 1748cc612d81SArnaldo Carvalho de Melo snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", uts.release); 1749cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); 1750cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 1751cc612d81SArnaldo Carvalho de Melo goto out_fail; 1752cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 1753cc612d81SArnaldo Carvalho de Melo snprintf(bf, sizeof(bf), "/lib/modules/%s/build/vmlinux", uts.release); 1754cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); 1755cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 1756cc612d81SArnaldo Carvalho de Melo goto out_fail; 1757cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 1758cc612d81SArnaldo Carvalho de Melo snprintf(bf, sizeof(bf), "/usr/lib/debug/lib/modules/%s/vmlinux", 1759cc612d81SArnaldo Carvalho de Melo uts.release); 1760cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); 1761cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 1762cc612d81SArnaldo Carvalho de Melo goto out_fail; 1763cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 1764cc612d81SArnaldo Carvalho de Melo 1765cc612d81SArnaldo Carvalho de Melo return 0; 1766cc612d81SArnaldo Carvalho de Melo 1767cc612d81SArnaldo Carvalho de Melo out_fail: 1768cc612d81SArnaldo Carvalho de Melo vmlinux_path__exit(); 1769cc612d81SArnaldo Carvalho de Melo return -1; 1770cc612d81SArnaldo Carvalho de Melo } 1771cc612d81SArnaldo Carvalho de Melo 1772655000e7SArnaldo Carvalho de Melo static int setup_list(struct strlist **list, const char *list_str, 1773655000e7SArnaldo Carvalho de Melo const char *list_name) 1774655000e7SArnaldo Carvalho de Melo { 1775655000e7SArnaldo Carvalho de Melo if (list_str == NULL) 1776655000e7SArnaldo Carvalho de Melo return 0; 1777655000e7SArnaldo Carvalho de Melo 1778655000e7SArnaldo Carvalho de Melo *list = strlist__new(true, list_str); 1779655000e7SArnaldo Carvalho de Melo if (!*list) { 1780655000e7SArnaldo Carvalho de Melo pr_err("problems parsing %s list\n", list_name); 1781655000e7SArnaldo Carvalho de Melo return -1; 1782655000e7SArnaldo Carvalho de Melo } 1783655000e7SArnaldo Carvalho de Melo return 0; 1784655000e7SArnaldo Carvalho de Melo } 1785655000e7SArnaldo Carvalho de Melo 178675be6cf4SArnaldo Carvalho de Melo int symbol__init(void) 1787cc612d81SArnaldo Carvalho de Melo { 178895011c60SArnaldo Carvalho de Melo elf_version(EV_CURRENT); 178975be6cf4SArnaldo Carvalho de Melo if (symbol_conf.sort_by_name) 179075be6cf4SArnaldo Carvalho de Melo symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) - 179179406cd7SArnaldo Carvalho de Melo sizeof(struct symbol)); 1792b32d133aSArnaldo Carvalho de Melo 179375be6cf4SArnaldo Carvalho de Melo if (symbol_conf.try_vmlinux_path && vmlinux_path__init() < 0) 1794cc612d81SArnaldo Carvalho de Melo return -1; 1795cc612d81SArnaldo Carvalho de Melo 1796c410a338SArnaldo Carvalho de Melo if (symbol_conf.field_sep && *symbol_conf.field_sep == '.') { 1797c410a338SArnaldo Carvalho de Melo pr_err("'.' is the only non valid --field-separator argument\n"); 1798c410a338SArnaldo Carvalho de Melo return -1; 1799c410a338SArnaldo Carvalho de Melo } 1800c410a338SArnaldo Carvalho de Melo 1801655000e7SArnaldo Carvalho de Melo if (setup_list(&symbol_conf.dso_list, 1802655000e7SArnaldo Carvalho de Melo symbol_conf.dso_list_str, "dso") < 0) 1803655000e7SArnaldo Carvalho de Melo return -1; 1804655000e7SArnaldo Carvalho de Melo 1805655000e7SArnaldo Carvalho de Melo if (setup_list(&symbol_conf.comm_list, 1806655000e7SArnaldo Carvalho de Melo symbol_conf.comm_list_str, "comm") < 0) 1807655000e7SArnaldo Carvalho de Melo goto out_free_dso_list; 1808655000e7SArnaldo Carvalho de Melo 1809655000e7SArnaldo Carvalho de Melo if (setup_list(&symbol_conf.sym_list, 1810655000e7SArnaldo Carvalho de Melo symbol_conf.sym_list_str, "symbol") < 0) 1811655000e7SArnaldo Carvalho de Melo goto out_free_comm_list; 1812655000e7SArnaldo Carvalho de Melo 18134aa65636SArnaldo Carvalho de Melo return 0; 1814655000e7SArnaldo Carvalho de Melo 1815655000e7SArnaldo Carvalho de Melo out_free_dso_list: 1816655000e7SArnaldo Carvalho de Melo strlist__delete(symbol_conf.dso_list); 1817655000e7SArnaldo Carvalho de Melo out_free_comm_list: 1818655000e7SArnaldo Carvalho de Melo strlist__delete(symbol_conf.comm_list); 1819655000e7SArnaldo Carvalho de Melo return -1; 1820cc612d81SArnaldo Carvalho de Melo } 1821cc612d81SArnaldo Carvalho de Melo 182275be6cf4SArnaldo Carvalho de Melo int perf_session__create_kernel_maps(struct perf_session *self) 18234aa65636SArnaldo Carvalho de Melo { 1824*de176489SArnaldo Carvalho de Melo if (map_groups__create_kernel_maps(&self->kmaps, self->vmlinux_maps, 182575be6cf4SArnaldo Carvalho de Melo symbol_conf.vmlinux_name) < 0) 18264aa65636SArnaldo Carvalho de Melo return -1; 18274aa65636SArnaldo Carvalho de Melo 182875be6cf4SArnaldo Carvalho de Melo if (symbol_conf.use_modules && 182975be6cf4SArnaldo Carvalho de Melo perf_session__create_module_maps(self) < 0) 18304aa65636SArnaldo Carvalho de Melo pr_debug("Failed to load list of modules for session %s, " 18314aa65636SArnaldo Carvalho de Melo "continuing...\n", self->filename); 183290c83218SArnaldo Carvalho de Melo /* 183390c83218SArnaldo Carvalho de Melo * Now that we have all the maps created, just set the ->end of them: 183490c83218SArnaldo Carvalho de Melo */ 18354aa65636SArnaldo Carvalho de Melo map_groups__fixup_end(&self->kmaps); 18366671cb16SArnaldo Carvalho de Melo return 0; 1837cd84c2acSFrederic Weisbecker } 1838