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; 959*56b03f3cSArnaldo Carvalho de Melo const char *elf_name = elf_sym__name(&sym, symstrs); 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 964*56b03f3cSArnaldo Carvalho de Melo if (kernel && session->ref_reloc_sym.name != NULL && 965*56b03f3cSArnaldo Carvalho de Melo strcmp(elf_name, session->ref_reloc_sym.name) == 0) 966*56b03f3cSArnaldo Carvalho de Melo perf_session__reloc_vmlinux_maps(session, sym.st_value); 967*56b03f3cSArnaldo Carvalho de Melo 968d45868d3SArnaldo Carvalho de Melo if (!is_label && !elf_sym__is_a(&sym, map->type)) 96986470930SIngo Molnar continue; 97086470930SIngo Molnar 97186470930SIngo Molnar sec = elf_getscn(elf, sym.st_shndx); 97286470930SIngo Molnar if (!sec) 97386470930SIngo Molnar goto out_elf_end; 97486470930SIngo Molnar 97586470930SIngo Molnar gelf_getshdr(sec, &shdr); 9766cfcc53eSMike Galbraith 977d45868d3SArnaldo Carvalho de Melo if (is_label && !elf_sec__is_a(&shdr, secstrs, map->type)) 9786cfcc53eSMike Galbraith continue; 9796cfcc53eSMike Galbraith 9806cfcc53eSMike Galbraith section_name = elf_sec__name(&shdr, secstrs); 98186470930SIngo Molnar 9822e538c4aSArnaldo Carvalho de Melo if (kernel || kmodule) { 9832e538c4aSArnaldo Carvalho de Melo char dso_name[PATH_MAX]; 9842e538c4aSArnaldo Carvalho de Melo 9852e538c4aSArnaldo Carvalho de Melo if (strcmp(section_name, 9862e538c4aSArnaldo Carvalho de Melo curr_dso->short_name + dso_name_len) == 0) 9872e538c4aSArnaldo Carvalho de Melo goto new_symbol; 9882e538c4aSArnaldo Carvalho de Melo 9892e538c4aSArnaldo Carvalho de Melo if (strcmp(section_name, ".text") == 0) { 9902e538c4aSArnaldo Carvalho de Melo curr_map = map; 9912e538c4aSArnaldo Carvalho de Melo curr_dso = self; 9922e538c4aSArnaldo Carvalho de Melo goto new_symbol; 993af427bf5SArnaldo Carvalho de Melo } 994af427bf5SArnaldo Carvalho de Melo 9952e538c4aSArnaldo Carvalho de Melo snprintf(dso_name, sizeof(dso_name), 9962e538c4aSArnaldo Carvalho de Melo "%s%s", self->short_name, section_name); 9972e538c4aSArnaldo Carvalho de Melo 9984aa65636SArnaldo Carvalho de Melo curr_map = map_groups__find_by_name(&session->kmaps, map->type, dso_name); 9992e538c4aSArnaldo Carvalho de Melo if (curr_map == NULL) { 10002e538c4aSArnaldo Carvalho de Melo u64 start = sym.st_value; 10012e538c4aSArnaldo Carvalho de Melo 10022e538c4aSArnaldo Carvalho de Melo if (kmodule) 10032e538c4aSArnaldo Carvalho de Melo start += map->start + shdr.sh_offset; 10042e538c4aSArnaldo Carvalho de Melo 100500a192b3SArnaldo Carvalho de Melo curr_dso = dso__new(dso_name); 10062e538c4aSArnaldo Carvalho de Melo if (curr_dso == NULL) 10072e538c4aSArnaldo Carvalho de Melo goto out_elf_end; 10083610583cSArnaldo Carvalho de Melo curr_map = map__new2(start, curr_dso, 10093610583cSArnaldo Carvalho de Melo MAP__FUNCTION); 10102e538c4aSArnaldo Carvalho de Melo if (curr_map == NULL) { 10112e538c4aSArnaldo Carvalho de Melo dso__delete(curr_dso); 10122e538c4aSArnaldo Carvalho de Melo goto out_elf_end; 10132e538c4aSArnaldo Carvalho de Melo } 1014ed52ce2eSArnaldo Carvalho de Melo curr_map->map_ip = identity__map_ip; 1015ed52ce2eSArnaldo Carvalho de Melo curr_map->unmap_ip = identity__map_ip; 10162e538c4aSArnaldo Carvalho de Melo curr_dso->origin = DSO__ORIG_KERNEL; 10174aa65636SArnaldo Carvalho de Melo map_groups__insert(&session->kmaps, curr_map); 1018b0da954aSArnaldo Carvalho de Melo dsos__add(&dsos__kernel, curr_dso); 10192e538c4aSArnaldo Carvalho de Melo } else 10202e538c4aSArnaldo Carvalho de Melo curr_dso = curr_map->dso; 10212e538c4aSArnaldo Carvalho de Melo 10222e538c4aSArnaldo Carvalho de Melo goto new_symbol; 10232e538c4aSArnaldo Carvalho de Melo } 10242e538c4aSArnaldo Carvalho de Melo 10252e538c4aSArnaldo Carvalho de Melo if (curr_dso->adjust_symbols) { 10266beba7adSArnaldo Carvalho de Melo pr_debug2("adjusting symbol: st_value: %Lx sh_addr: " 10276beba7adSArnaldo Carvalho de Melo "%Lx sh_offset: %Lx\n", (u64)sym.st_value, 10286beba7adSArnaldo Carvalho de Melo (u64)shdr.sh_addr, (u64)shdr.sh_offset); 102986470930SIngo Molnar sym.st_value -= shdr.sh_addr - shdr.sh_offset; 1030af427bf5SArnaldo Carvalho de Melo } 103128ac909bSArnaldo Carvalho de Melo /* 103228ac909bSArnaldo Carvalho de Melo * We need to figure out if the object was created from C++ sources 103328ac909bSArnaldo Carvalho de Melo * DWARF DW_compile_unit has this, but we don't always have access 103428ac909bSArnaldo Carvalho de Melo * to it... 103528ac909bSArnaldo Carvalho de Melo */ 103683a0944fSIngo Molnar demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI); 103728ac909bSArnaldo Carvalho de Melo if (demangled != NULL) 103883a0944fSIngo Molnar elf_name = demangled; 10392e538c4aSArnaldo Carvalho de Melo new_symbol: 104000a192b3SArnaldo Carvalho de Melo f = symbol__new(sym.st_value, sym.st_size, elf_name); 104128ac909bSArnaldo Carvalho de Melo free(demangled); 104286470930SIngo Molnar if (!f) 104386470930SIngo Molnar goto out_elf_end; 104486470930SIngo Molnar 10452e538c4aSArnaldo Carvalho de Melo if (filter && filter(curr_map, f)) 104600a192b3SArnaldo Carvalho de Melo symbol__delete(f); 104786470930SIngo Molnar else { 10486a4694a4SArnaldo Carvalho de Melo symbols__insert(&curr_dso->symbols[curr_map->type], f); 104986470930SIngo Molnar nr++; 105086470930SIngo Molnar } 105186470930SIngo Molnar } 105286470930SIngo Molnar 10532e538c4aSArnaldo Carvalho de Melo /* 10542e538c4aSArnaldo Carvalho de Melo * For misannotated, zeroed, ASM function sizes. 10552e538c4aSArnaldo Carvalho de Melo */ 10562e538c4aSArnaldo Carvalho de Melo if (nr > 0) 10576a4694a4SArnaldo Carvalho de Melo symbols__fixup_end(&self->symbols[map->type]); 105886470930SIngo Molnar err = nr; 105986470930SIngo Molnar out_elf_end: 106086470930SIngo Molnar elf_end(elf); 106186470930SIngo Molnar out_close: 106286470930SIngo Molnar return err; 106386470930SIngo Molnar } 106486470930SIngo Molnar 106578075caaSArnaldo Carvalho de Melo static bool dso__build_id_equal(const struct dso *self, u8 *build_id) 106678075caaSArnaldo Carvalho de Melo { 106778075caaSArnaldo Carvalho de Melo return memcmp(self->build_id, build_id, sizeof(self->build_id)) == 0; 106878075caaSArnaldo Carvalho de Melo } 106978075caaSArnaldo Carvalho de Melo 1070b0da954aSArnaldo Carvalho de Melo static bool __dsos__read_build_ids(struct list_head *head) 107157f395a7SFrederic Weisbecker { 1072e30a3d12SArnaldo Carvalho de Melo bool have_build_id = false; 107357f395a7SFrederic Weisbecker struct dso *pos; 107457f395a7SFrederic Weisbecker 1075b0da954aSArnaldo Carvalho de Melo list_for_each_entry(pos, head, node) 1076e30a3d12SArnaldo Carvalho de Melo if (filename__read_build_id(pos->long_name, pos->build_id, 1077e30a3d12SArnaldo Carvalho de Melo sizeof(pos->build_id)) > 0) { 1078e30a3d12SArnaldo Carvalho de Melo have_build_id = true; 1079e30a3d12SArnaldo Carvalho de Melo pos->has_build_id = true; 108057f395a7SFrederic Weisbecker } 108157f395a7SFrederic Weisbecker 1082e30a3d12SArnaldo Carvalho de Melo return have_build_id; 108357f395a7SFrederic Weisbecker } 108457f395a7SFrederic Weisbecker 1085b0da954aSArnaldo Carvalho de Melo bool dsos__read_build_ids(void) 1086b0da954aSArnaldo Carvalho de Melo { 10878b4825bfSArnaldo Carvalho de Melo bool kbuildids = __dsos__read_build_ids(&dsos__kernel), 10888b4825bfSArnaldo Carvalho de Melo ubuildids = __dsos__read_build_ids(&dsos__user); 10898b4825bfSArnaldo Carvalho de Melo return kbuildids || ubuildids; 1090b0da954aSArnaldo Carvalho de Melo } 1091b0da954aSArnaldo Carvalho de Melo 1092fd7a346eSArnaldo Carvalho de Melo /* 1093fd7a346eSArnaldo Carvalho de Melo * Align offset to 4 bytes as needed for note name and descriptor data. 1094fd7a346eSArnaldo Carvalho de Melo */ 1095fd7a346eSArnaldo Carvalho de Melo #define NOTE_ALIGN(n) (((n) + 3) & -4U) 1096fd7a346eSArnaldo Carvalho de Melo 10972643ce11SArnaldo Carvalho de Melo int filename__read_build_id(const char *filename, void *bf, size_t size) 10984d1e00a8SArnaldo Carvalho de Melo { 10992643ce11SArnaldo Carvalho de Melo int fd, err = -1; 11004d1e00a8SArnaldo Carvalho de Melo GElf_Ehdr ehdr; 11014d1e00a8SArnaldo Carvalho de Melo GElf_Shdr shdr; 1102fd7a346eSArnaldo Carvalho de Melo Elf_Data *data; 11034d1e00a8SArnaldo Carvalho de Melo Elf_Scn *sec; 1104e57cfcdaSPekka Enberg Elf_Kind ek; 1105fd7a346eSArnaldo Carvalho de Melo void *ptr; 11064d1e00a8SArnaldo Carvalho de Melo Elf *elf; 11074d1e00a8SArnaldo Carvalho de Melo 11082643ce11SArnaldo Carvalho de Melo if (size < BUILD_ID_SIZE) 11092643ce11SArnaldo Carvalho de Melo goto out; 11102643ce11SArnaldo Carvalho de Melo 11112643ce11SArnaldo Carvalho de Melo fd = open(filename, O_RDONLY); 11124d1e00a8SArnaldo Carvalho de Melo if (fd < 0) 11134d1e00a8SArnaldo Carvalho de Melo goto out; 11144d1e00a8SArnaldo Carvalho de Melo 111584087126SMarti Raudsepp elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 11164d1e00a8SArnaldo Carvalho de Melo if (elf == NULL) { 11178d06367fSArnaldo Carvalho de Melo pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename); 11184d1e00a8SArnaldo Carvalho de Melo goto out_close; 11194d1e00a8SArnaldo Carvalho de Melo } 11204d1e00a8SArnaldo Carvalho de Melo 1121e57cfcdaSPekka Enberg ek = elf_kind(elf); 1122e57cfcdaSPekka Enberg if (ek != ELF_K_ELF) 1123e57cfcdaSPekka Enberg goto out_elf_end; 1124e57cfcdaSPekka Enberg 11254d1e00a8SArnaldo Carvalho de Melo if (gelf_getehdr(elf, &ehdr) == NULL) { 11266beba7adSArnaldo Carvalho de Melo pr_err("%s: cannot get elf header.\n", __func__); 11274d1e00a8SArnaldo Carvalho de Melo goto out_elf_end; 11284d1e00a8SArnaldo Carvalho de Melo } 11294d1e00a8SArnaldo Carvalho de Melo 11302643ce11SArnaldo Carvalho de Melo sec = elf_section_by_name(elf, &ehdr, &shdr, 11312643ce11SArnaldo Carvalho de Melo ".note.gnu.build-id", NULL); 1132fd7a346eSArnaldo Carvalho de Melo if (sec == NULL) { 1133fd7a346eSArnaldo Carvalho de Melo sec = elf_section_by_name(elf, &ehdr, &shdr, 1134fd7a346eSArnaldo Carvalho de Melo ".notes", NULL); 11354d1e00a8SArnaldo Carvalho de Melo if (sec == NULL) 11364d1e00a8SArnaldo Carvalho de Melo goto out_elf_end; 1137fd7a346eSArnaldo Carvalho de Melo } 11384d1e00a8SArnaldo Carvalho de Melo 1139fd7a346eSArnaldo Carvalho de Melo data = elf_getdata(sec, NULL); 1140fd7a346eSArnaldo Carvalho de Melo if (data == NULL) 11414d1e00a8SArnaldo Carvalho de Melo goto out_elf_end; 1142fd7a346eSArnaldo Carvalho de Melo 1143fd7a346eSArnaldo Carvalho de Melo ptr = data->d_buf; 1144fd7a346eSArnaldo Carvalho de Melo while (ptr < (data->d_buf + data->d_size)) { 1145fd7a346eSArnaldo Carvalho de Melo GElf_Nhdr *nhdr = ptr; 1146fd7a346eSArnaldo Carvalho de Melo int namesz = NOTE_ALIGN(nhdr->n_namesz), 1147fd7a346eSArnaldo Carvalho de Melo descsz = NOTE_ALIGN(nhdr->n_descsz); 1148fd7a346eSArnaldo Carvalho de Melo const char *name; 1149fd7a346eSArnaldo Carvalho de Melo 1150fd7a346eSArnaldo Carvalho de Melo ptr += sizeof(*nhdr); 1151fd7a346eSArnaldo Carvalho de Melo name = ptr; 1152fd7a346eSArnaldo Carvalho de Melo ptr += namesz; 1153fd7a346eSArnaldo Carvalho de Melo if (nhdr->n_type == NT_GNU_BUILD_ID && 1154fd7a346eSArnaldo Carvalho de Melo nhdr->n_namesz == sizeof("GNU")) { 1155fd7a346eSArnaldo Carvalho de Melo if (memcmp(name, "GNU", sizeof("GNU")) == 0) { 1156fd7a346eSArnaldo Carvalho de Melo memcpy(bf, ptr, BUILD_ID_SIZE); 11572643ce11SArnaldo Carvalho de Melo err = BUILD_ID_SIZE; 1158fd7a346eSArnaldo Carvalho de Melo break; 1159fd7a346eSArnaldo Carvalho de Melo } 1160fd7a346eSArnaldo Carvalho de Melo } 1161fd7a346eSArnaldo Carvalho de Melo ptr += descsz; 1162fd7a346eSArnaldo Carvalho de Melo } 11632643ce11SArnaldo Carvalho de Melo out_elf_end: 11642643ce11SArnaldo Carvalho de Melo elf_end(elf); 11652643ce11SArnaldo Carvalho de Melo out_close: 11662643ce11SArnaldo Carvalho de Melo close(fd); 11672643ce11SArnaldo Carvalho de Melo out: 11682643ce11SArnaldo Carvalho de Melo return err; 11692643ce11SArnaldo Carvalho de Melo } 11702643ce11SArnaldo Carvalho de Melo 1171f1617b40SArnaldo Carvalho de Melo int sysfs__read_build_id(const char *filename, void *build_id, size_t size) 1172f1617b40SArnaldo Carvalho de Melo { 1173f1617b40SArnaldo Carvalho de Melo int fd, err = -1; 1174f1617b40SArnaldo Carvalho de Melo 1175f1617b40SArnaldo Carvalho de Melo if (size < BUILD_ID_SIZE) 1176f1617b40SArnaldo Carvalho de Melo goto out; 1177f1617b40SArnaldo Carvalho de Melo 1178f1617b40SArnaldo Carvalho de Melo fd = open(filename, O_RDONLY); 1179f1617b40SArnaldo Carvalho de Melo if (fd < 0) 1180f1617b40SArnaldo Carvalho de Melo goto out; 1181f1617b40SArnaldo Carvalho de Melo 1182f1617b40SArnaldo Carvalho de Melo while (1) { 1183f1617b40SArnaldo Carvalho de Melo char bf[BUFSIZ]; 1184f1617b40SArnaldo Carvalho de Melo GElf_Nhdr nhdr; 1185f1617b40SArnaldo Carvalho de Melo int namesz, descsz; 1186f1617b40SArnaldo Carvalho de Melo 1187f1617b40SArnaldo Carvalho de Melo if (read(fd, &nhdr, sizeof(nhdr)) != sizeof(nhdr)) 1188f1617b40SArnaldo Carvalho de Melo break; 1189f1617b40SArnaldo Carvalho de Melo 1190fd7a346eSArnaldo Carvalho de Melo namesz = NOTE_ALIGN(nhdr.n_namesz); 1191fd7a346eSArnaldo Carvalho de Melo descsz = NOTE_ALIGN(nhdr.n_descsz); 1192f1617b40SArnaldo Carvalho de Melo if (nhdr.n_type == NT_GNU_BUILD_ID && 1193f1617b40SArnaldo Carvalho de Melo nhdr.n_namesz == sizeof("GNU")) { 1194f1617b40SArnaldo Carvalho de Melo if (read(fd, bf, namesz) != namesz) 1195f1617b40SArnaldo Carvalho de Melo break; 1196f1617b40SArnaldo Carvalho de Melo if (memcmp(bf, "GNU", sizeof("GNU")) == 0) { 1197f1617b40SArnaldo Carvalho de Melo if (read(fd, build_id, 1198f1617b40SArnaldo Carvalho de Melo BUILD_ID_SIZE) == BUILD_ID_SIZE) { 1199f1617b40SArnaldo Carvalho de Melo err = 0; 1200f1617b40SArnaldo Carvalho de Melo break; 1201f1617b40SArnaldo Carvalho de Melo } 1202f1617b40SArnaldo Carvalho de Melo } else if (read(fd, bf, descsz) != descsz) 1203f1617b40SArnaldo Carvalho de Melo break; 1204f1617b40SArnaldo Carvalho de Melo } else { 1205f1617b40SArnaldo Carvalho de Melo int n = namesz + descsz; 1206f1617b40SArnaldo Carvalho de Melo if (read(fd, bf, n) != n) 1207f1617b40SArnaldo Carvalho de Melo break; 1208f1617b40SArnaldo Carvalho de Melo } 1209f1617b40SArnaldo Carvalho de Melo } 1210f1617b40SArnaldo Carvalho de Melo close(fd); 1211f1617b40SArnaldo Carvalho de Melo out: 1212f1617b40SArnaldo Carvalho de Melo return err; 1213f1617b40SArnaldo Carvalho de Melo } 1214f1617b40SArnaldo Carvalho de Melo 121594cb9e38SArnaldo Carvalho de Melo char dso__symtab_origin(const struct dso *self) 121694cb9e38SArnaldo Carvalho de Melo { 121794cb9e38SArnaldo Carvalho de Melo static const char origin[] = { 121894cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_KERNEL] = 'k', 121994cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_JAVA_JIT] = 'j', 12204cf40131SArnaldo Carvalho de Melo [DSO__ORIG_BUILD_ID_CACHE] = 'B', 122194cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_FEDORA] = 'f', 122294cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_UBUNTU] = 'u', 122394cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_BUILDID] = 'b', 122494cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_DSO] = 'd', 1225439d473bSArnaldo Carvalho de Melo [DSO__ORIG_KMODULE] = 'K', 122694cb9e38SArnaldo Carvalho de Melo }; 122794cb9e38SArnaldo Carvalho de Melo 122894cb9e38SArnaldo Carvalho de Melo if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND) 122994cb9e38SArnaldo Carvalho de Melo return '!'; 123094cb9e38SArnaldo Carvalho de Melo return origin[self->origin]; 123194cb9e38SArnaldo Carvalho de Melo } 123294cb9e38SArnaldo Carvalho de Melo 12334aa65636SArnaldo Carvalho de Melo int dso__load(struct dso *self, struct map *map, struct perf_session *session, 12344aa65636SArnaldo Carvalho de Melo symbol_filter_t filter) 123586470930SIngo Molnar { 12364d1e00a8SArnaldo Carvalho de Melo int size = PATH_MAX; 1237c338aee8SArnaldo Carvalho de Melo char *name; 1238d3379ab9SArnaldo Carvalho de Melo u8 build_id[BUILD_ID_SIZE]; 12394cf40131SArnaldo Carvalho de Melo char build_id_hex[BUILD_ID_SIZE * 2 + 1]; 124086470930SIngo Molnar int ret = -1; 124186470930SIngo Molnar int fd; 124286470930SIngo Molnar 12433610583cSArnaldo Carvalho de Melo dso__set_loaded(self, map->type); 124466bd8424SArnaldo Carvalho de Melo 1245c338aee8SArnaldo Carvalho de Melo if (self->kernel) 12464aa65636SArnaldo Carvalho de Melo return dso__load_kernel_sym(self, map, session, filter); 1247c338aee8SArnaldo Carvalho de Melo 1248c338aee8SArnaldo Carvalho de Melo name = malloc(size); 124986470930SIngo Molnar if (!name) 125086470930SIngo Molnar return -1; 125186470930SIngo Molnar 125230d7a77dSArnaldo Carvalho de Melo self->adjust_symbols = 0; 1253f5812a7aSArnaldo Carvalho de Melo 125494cb9e38SArnaldo Carvalho de Melo if (strncmp(self->name, "/tmp/perf-", 10) == 0) { 12556beba7adSArnaldo Carvalho de Melo ret = dso__load_perf_map(self, map, filter); 125694cb9e38SArnaldo Carvalho de Melo self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT : 125794cb9e38SArnaldo Carvalho de Melo DSO__ORIG_NOT_FOUND; 125894cb9e38SArnaldo Carvalho de Melo return ret; 125994cb9e38SArnaldo Carvalho de Melo } 126094cb9e38SArnaldo Carvalho de Melo 12614cf40131SArnaldo Carvalho de Melo self->origin = DSO__ORIG_BUILD_ID_CACHE; 126280d496beSPekka Enberg 12634cf40131SArnaldo Carvalho de Melo if (self->has_build_id) { 12644cf40131SArnaldo Carvalho de Melo build_id__sprintf(self->build_id, sizeof(self->build_id), 12654cf40131SArnaldo Carvalho de Melo build_id_hex); 12664cf40131SArnaldo Carvalho de Melo snprintf(name, size, "%s/%s/.build-id/%.2s/%s", 12674cf40131SArnaldo Carvalho de Melo getenv("HOME"), DEBUG_CACHE_DIR, 12684cf40131SArnaldo Carvalho de Melo build_id_hex, build_id_hex + 2); 12694cf40131SArnaldo Carvalho de Melo goto open_file; 12704cf40131SArnaldo Carvalho de Melo } 127186470930SIngo Molnar more: 127286470930SIngo Molnar do { 127394cb9e38SArnaldo Carvalho de Melo self->origin++; 127494cb9e38SArnaldo Carvalho de Melo switch (self->origin) { 127594cb9e38SArnaldo Carvalho de Melo case DSO__ORIG_FEDORA: 1276439d473bSArnaldo Carvalho de Melo snprintf(name, size, "/usr/lib/debug%s.debug", 1277439d473bSArnaldo Carvalho de Melo self->long_name); 127886470930SIngo Molnar break; 127994cb9e38SArnaldo Carvalho de Melo case DSO__ORIG_UBUNTU: 1280439d473bSArnaldo Carvalho de Melo snprintf(name, size, "/usr/lib/debug%s", 1281439d473bSArnaldo Carvalho de Melo self->long_name); 128286470930SIngo Molnar break; 128394cb9e38SArnaldo Carvalho de Melo case DSO__ORIG_BUILDID: 1284d3379ab9SArnaldo Carvalho de Melo if (filename__read_build_id(self->long_name, build_id, 1285d3379ab9SArnaldo Carvalho de Melo sizeof(build_id))) { 1286d3379ab9SArnaldo Carvalho de Melo build_id__sprintf(build_id, sizeof(build_id), 1287d3379ab9SArnaldo Carvalho de Melo build_id_hex); 12884d1e00a8SArnaldo Carvalho de Melo snprintf(name, size, 12894d1e00a8SArnaldo Carvalho de Melo "/usr/lib/debug/.build-id/%.2s/%s.debug", 1290d3379ab9SArnaldo Carvalho de Melo build_id_hex, build_id_hex + 2); 1291d3379ab9SArnaldo Carvalho de Melo if (self->has_build_id) 12928d06367fSArnaldo Carvalho de Melo goto compare_build_id; 1293d3379ab9SArnaldo Carvalho de Melo break; 12944d1e00a8SArnaldo Carvalho de Melo } 129594cb9e38SArnaldo Carvalho de Melo self->origin++; 12964d1e00a8SArnaldo Carvalho de Melo /* Fall thru */ 129794cb9e38SArnaldo Carvalho de Melo case DSO__ORIG_DSO: 1298439d473bSArnaldo Carvalho de Melo snprintf(name, size, "%s", self->long_name); 129986470930SIngo Molnar break; 130086470930SIngo Molnar 130186470930SIngo Molnar default: 130286470930SIngo Molnar goto out; 130386470930SIngo Molnar } 130486470930SIngo Molnar 13058d06367fSArnaldo Carvalho de Melo if (self->has_build_id) { 1306d3379ab9SArnaldo Carvalho de Melo if (filename__read_build_id(name, build_id, 1307d3379ab9SArnaldo Carvalho de Melo sizeof(build_id)) < 0) 13088d06367fSArnaldo Carvalho de Melo goto more; 13098d06367fSArnaldo Carvalho de Melo compare_build_id: 131078075caaSArnaldo Carvalho de Melo if (!dso__build_id_equal(self, build_id)) 13118d06367fSArnaldo Carvalho de Melo goto more; 13128d06367fSArnaldo Carvalho de Melo } 13134cf40131SArnaldo Carvalho de Melo open_file: 131486470930SIngo Molnar fd = open(name, O_RDONLY); 131586470930SIngo Molnar } while (fd < 0); 131686470930SIngo Molnar 131795011c60SArnaldo Carvalho de Melo ret = dso__load_sym(self, map, NULL, name, fd, filter, 0, 0); 131886470930SIngo Molnar close(fd); 131986470930SIngo Molnar 132086470930SIngo Molnar /* 132186470930SIngo Molnar * Some people seem to have debuginfo files _WITHOUT_ debug info!?!? 132286470930SIngo Molnar */ 132386470930SIngo Molnar if (!ret) 132486470930SIngo Molnar goto more; 132586470930SIngo Molnar 1326a25e46c4SArnaldo Carvalho de Melo if (ret > 0) { 132782164161SArnaldo Carvalho de Melo int nr_plt = dso__synthesize_plt_symbols(self, map, filter); 1328a25e46c4SArnaldo Carvalho de Melo if (nr_plt > 0) 1329a25e46c4SArnaldo Carvalho de Melo ret += nr_plt; 1330a25e46c4SArnaldo Carvalho de Melo } 133186470930SIngo Molnar out: 133286470930SIngo Molnar free(name); 13331340e6bbSArnaldo Carvalho de Melo if (ret < 0 && strstr(self->name, " (deleted)") != NULL) 13341340e6bbSArnaldo Carvalho de Melo return 0; 133586470930SIngo Molnar return ret; 133686470930SIngo Molnar } 133786470930SIngo Molnar 133879406cd7SArnaldo Carvalho de Melo struct map *map_groups__find_by_name(struct map_groups *self, 133979406cd7SArnaldo Carvalho de Melo enum map_type type, const char *name) 1340439d473bSArnaldo Carvalho de Melo { 1341439d473bSArnaldo Carvalho de Melo struct rb_node *nd; 1342439d473bSArnaldo Carvalho de Melo 134379406cd7SArnaldo Carvalho de Melo for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) { 1344439d473bSArnaldo Carvalho de Melo struct map *map = rb_entry(nd, struct map, rb_node); 1345439d473bSArnaldo Carvalho de Melo 1346439d473bSArnaldo Carvalho de Melo if (map->dso && strcmp(map->dso->name, name) == 0) 1347439d473bSArnaldo Carvalho de Melo return map; 1348439d473bSArnaldo Carvalho de Melo } 1349439d473bSArnaldo Carvalho de Melo 1350439d473bSArnaldo Carvalho de Melo return NULL; 1351439d473bSArnaldo Carvalho de Melo } 1352439d473bSArnaldo Carvalho de Melo 13534aa65636SArnaldo Carvalho de Melo static int perf_session__set_modules_path_dir(struct perf_session *self, char *dirname) 13546cfcc53eSMike Galbraith { 1355439d473bSArnaldo Carvalho de Melo struct dirent *dent; 1356439d473bSArnaldo Carvalho de Melo DIR *dir = opendir(dirname); 13576cfcc53eSMike Galbraith 1358439d473bSArnaldo Carvalho de Melo if (!dir) { 135987f8ea4cSArnaldo Carvalho de Melo pr_debug("%s: cannot open %s dir\n", __func__, dirname); 1360439d473bSArnaldo Carvalho de Melo return -1; 1361439d473bSArnaldo Carvalho de Melo } 13626cfcc53eSMike Galbraith 1363439d473bSArnaldo Carvalho de Melo while ((dent = readdir(dir)) != NULL) { 1364439d473bSArnaldo Carvalho de Melo char path[PATH_MAX]; 1365439d473bSArnaldo Carvalho de Melo 1366439d473bSArnaldo Carvalho de Melo if (dent->d_type == DT_DIR) { 1367439d473bSArnaldo Carvalho de Melo if (!strcmp(dent->d_name, ".") || 1368439d473bSArnaldo Carvalho de Melo !strcmp(dent->d_name, "..")) 1369439d473bSArnaldo Carvalho de Melo continue; 1370439d473bSArnaldo Carvalho de Melo 1371439d473bSArnaldo Carvalho de Melo snprintf(path, sizeof(path), "%s/%s", 1372439d473bSArnaldo Carvalho de Melo dirname, dent->d_name); 13734aa65636SArnaldo Carvalho de Melo if (perf_session__set_modules_path_dir(self, path) < 0) 1374439d473bSArnaldo Carvalho de Melo goto failure; 1375439d473bSArnaldo Carvalho de Melo } else { 1376439d473bSArnaldo Carvalho de Melo char *dot = strrchr(dent->d_name, '.'), 1377439d473bSArnaldo Carvalho de Melo dso_name[PATH_MAX]; 1378439d473bSArnaldo Carvalho de Melo struct map *map; 1379cfc10d3bSArnaldo Carvalho de Melo char *long_name; 1380439d473bSArnaldo Carvalho de Melo 1381439d473bSArnaldo Carvalho de Melo if (dot == NULL || strcmp(dot, ".ko")) 1382439d473bSArnaldo Carvalho de Melo continue; 1383439d473bSArnaldo Carvalho de Melo snprintf(dso_name, sizeof(dso_name), "[%.*s]", 1384439d473bSArnaldo Carvalho de Melo (int)(dot - dent->d_name), dent->d_name); 1385439d473bSArnaldo Carvalho de Melo 1386a2a99e8eSArnaldo Carvalho de Melo strxfrchar(dso_name, '-', '_'); 13874aa65636SArnaldo Carvalho de Melo map = map_groups__find_by_name(&self->kmaps, MAP__FUNCTION, dso_name); 1388439d473bSArnaldo Carvalho de Melo if (map == NULL) 1389439d473bSArnaldo Carvalho de Melo continue; 1390439d473bSArnaldo Carvalho de Melo 1391439d473bSArnaldo Carvalho de Melo snprintf(path, sizeof(path), "%s/%s", 1392439d473bSArnaldo Carvalho de Melo dirname, dent->d_name); 1393439d473bSArnaldo Carvalho de Melo 1394cfc10d3bSArnaldo Carvalho de Melo long_name = strdup(path); 1395cfc10d3bSArnaldo Carvalho de Melo if (long_name == NULL) 1396439d473bSArnaldo Carvalho de Melo goto failure; 1397cfc10d3bSArnaldo Carvalho de Melo dso__set_long_name(map->dso, long_name); 1398439d473bSArnaldo Carvalho de Melo } 1399439d473bSArnaldo Carvalho de Melo } 1400439d473bSArnaldo Carvalho de Melo 1401c338aee8SArnaldo Carvalho de Melo return 0; 1402439d473bSArnaldo Carvalho de Melo failure: 1403439d473bSArnaldo Carvalho de Melo closedir(dir); 1404439d473bSArnaldo Carvalho de Melo return -1; 1405439d473bSArnaldo Carvalho de Melo } 1406439d473bSArnaldo Carvalho de Melo 14074aa65636SArnaldo Carvalho de Melo static int perf_session__set_modules_path(struct perf_session *self) 1408439d473bSArnaldo Carvalho de Melo { 1409439d473bSArnaldo Carvalho de Melo struct utsname uts; 1410439d473bSArnaldo Carvalho de Melo char modules_path[PATH_MAX]; 1411439d473bSArnaldo Carvalho de Melo 1412439d473bSArnaldo Carvalho de Melo if (uname(&uts) < 0) 1413439d473bSArnaldo Carvalho de Melo return -1; 1414439d473bSArnaldo Carvalho de Melo 1415439d473bSArnaldo Carvalho de Melo snprintf(modules_path, sizeof(modules_path), "/lib/modules/%s/kernel", 1416439d473bSArnaldo Carvalho de Melo uts.release); 1417439d473bSArnaldo Carvalho de Melo 14184aa65636SArnaldo Carvalho de Melo return perf_session__set_modules_path_dir(self, modules_path); 1419439d473bSArnaldo Carvalho de Melo } 14206cfcc53eSMike Galbraith 14216cfcc53eSMike Galbraith /* 1422439d473bSArnaldo Carvalho de Melo * Constructor variant for modules (where we know from /proc/modules where 1423439d473bSArnaldo Carvalho de Melo * they are loaded) and for vmlinux, where only after we load all the 1424439d473bSArnaldo Carvalho de Melo * symbols we'll know where it starts and ends. 14256cfcc53eSMike Galbraith */ 14263610583cSArnaldo Carvalho de Melo static struct map *map__new2(u64 start, struct dso *dso, enum map_type type) 1427439d473bSArnaldo Carvalho de Melo { 1428439d473bSArnaldo Carvalho de Melo struct map *self = malloc(sizeof(*self)); 14296cfcc53eSMike Galbraith 1430439d473bSArnaldo Carvalho de Melo if (self != NULL) { 1431439d473bSArnaldo Carvalho de Melo /* 1432afb7b4f0SArnaldo Carvalho de Melo * ->end will be filled after we load all the symbols 1433439d473bSArnaldo Carvalho de Melo */ 14343610583cSArnaldo Carvalho de Melo map__init(self, type, start, 0, 0, dso); 1435439d473bSArnaldo Carvalho de Melo } 1436afb7b4f0SArnaldo Carvalho de Melo 1437439d473bSArnaldo Carvalho de Melo return self; 1438439d473bSArnaldo Carvalho de Melo } 1439439d473bSArnaldo Carvalho de Melo 14404aa65636SArnaldo Carvalho de Melo static int perf_session__create_module_maps(struct perf_session *self) 1441439d473bSArnaldo Carvalho de Melo { 1442439d473bSArnaldo Carvalho de Melo char *line = NULL; 1443439d473bSArnaldo Carvalho de Melo size_t n; 1444439d473bSArnaldo Carvalho de Melo FILE *file = fopen("/proc/modules", "r"); 1445439d473bSArnaldo Carvalho de Melo struct map *map; 1446439d473bSArnaldo Carvalho de Melo 1447439d473bSArnaldo Carvalho de Melo if (file == NULL) 1448439d473bSArnaldo Carvalho de Melo return -1; 1449439d473bSArnaldo Carvalho de Melo 1450439d473bSArnaldo Carvalho de Melo while (!feof(file)) { 1451439d473bSArnaldo Carvalho de Melo char name[PATH_MAX]; 1452439d473bSArnaldo Carvalho de Melo u64 start; 1453439d473bSArnaldo Carvalho de Melo struct dso *dso; 1454439d473bSArnaldo Carvalho de Melo char *sep; 1455439d473bSArnaldo Carvalho de Melo int line_len; 1456439d473bSArnaldo Carvalho de Melo 1457439d473bSArnaldo Carvalho de Melo line_len = getline(&line, &n, file); 1458439d473bSArnaldo Carvalho de Melo if (line_len < 0) 14596cfcc53eSMike Galbraith break; 14606cfcc53eSMike Galbraith 1461439d473bSArnaldo Carvalho de Melo if (!line) 1462439d473bSArnaldo Carvalho de Melo goto out_failure; 1463439d473bSArnaldo Carvalho de Melo 1464439d473bSArnaldo Carvalho de Melo line[--line_len] = '\0'; /* \n */ 1465439d473bSArnaldo Carvalho de Melo 1466439d473bSArnaldo Carvalho de Melo sep = strrchr(line, 'x'); 1467439d473bSArnaldo Carvalho de Melo if (sep == NULL) 1468439d473bSArnaldo Carvalho de Melo continue; 1469439d473bSArnaldo Carvalho de Melo 1470439d473bSArnaldo Carvalho de Melo hex2u64(sep + 1, &start); 1471439d473bSArnaldo Carvalho de Melo 1472439d473bSArnaldo Carvalho de Melo sep = strchr(line, ' '); 1473439d473bSArnaldo Carvalho de Melo if (sep == NULL) 1474439d473bSArnaldo Carvalho de Melo continue; 1475439d473bSArnaldo Carvalho de Melo 1476439d473bSArnaldo Carvalho de Melo *sep = '\0'; 1477439d473bSArnaldo Carvalho de Melo 1478439d473bSArnaldo Carvalho de Melo snprintf(name, sizeof(name), "[%s]", line); 147900a192b3SArnaldo Carvalho de Melo dso = dso__new(name); 1480439d473bSArnaldo Carvalho de Melo 1481439d473bSArnaldo Carvalho de Melo if (dso == NULL) 1482439d473bSArnaldo Carvalho de Melo goto out_delete_line; 1483439d473bSArnaldo Carvalho de Melo 14843610583cSArnaldo Carvalho de Melo map = map__new2(start, dso, MAP__FUNCTION); 1485439d473bSArnaldo Carvalho de Melo if (map == NULL) { 1486439d473bSArnaldo Carvalho de Melo dso__delete(dso); 1487439d473bSArnaldo Carvalho de Melo goto out_delete_line; 14886cfcc53eSMike Galbraith } 14896cfcc53eSMike Galbraith 1490f1617b40SArnaldo Carvalho de Melo snprintf(name, sizeof(name), 1491f1617b40SArnaldo Carvalho de Melo "/sys/module/%s/notes/.note.gnu.build-id", line); 1492f1617b40SArnaldo Carvalho de Melo if (sysfs__read_build_id(name, dso->build_id, 1493f1617b40SArnaldo Carvalho de Melo sizeof(dso->build_id)) == 0) 1494f1617b40SArnaldo Carvalho de Melo dso->has_build_id = true; 1495f1617b40SArnaldo Carvalho de Melo 1496439d473bSArnaldo Carvalho de Melo dso->origin = DSO__ORIG_KMODULE; 14974aa65636SArnaldo Carvalho de Melo map_groups__insert(&self->kmaps, map); 1498b0da954aSArnaldo Carvalho de Melo dsos__add(&dsos__kernel, dso); 14996cfcc53eSMike Galbraith } 15006cfcc53eSMike Galbraith 1501439d473bSArnaldo Carvalho de Melo free(line); 1502439d473bSArnaldo Carvalho de Melo fclose(file); 1503439d473bSArnaldo Carvalho de Melo 15044aa65636SArnaldo Carvalho de Melo return perf_session__set_modules_path(self); 1505439d473bSArnaldo Carvalho de Melo 1506439d473bSArnaldo Carvalho de Melo out_delete_line: 1507439d473bSArnaldo Carvalho de Melo free(line); 1508439d473bSArnaldo Carvalho de Melo out_failure: 1509439d473bSArnaldo Carvalho de Melo return -1; 15106cfcc53eSMike Galbraith } 15116cfcc53eSMike Galbraith 15129958e1f0SArnaldo Carvalho de Melo static int dso__load_vmlinux(struct dso *self, struct map *map, 15134aa65636SArnaldo Carvalho de Melo struct perf_session *session, 15146beba7adSArnaldo Carvalho de Melo const char *vmlinux, symbol_filter_t filter) 151586470930SIngo Molnar { 1516fbd733b8SArnaldo Carvalho de Melo int err = -1, fd; 151786470930SIngo Molnar 1518fbd733b8SArnaldo Carvalho de Melo if (self->has_build_id) { 1519fbd733b8SArnaldo Carvalho de Melo u8 build_id[BUILD_ID_SIZE]; 152066bd8424SArnaldo Carvalho de Melo 1521fbd733b8SArnaldo Carvalho de Melo if (filename__read_build_id(vmlinux, build_id, 1522fbd733b8SArnaldo Carvalho de Melo sizeof(build_id)) < 0) { 1523fbd733b8SArnaldo Carvalho de Melo pr_debug("No build_id in %s, ignoring it\n", vmlinux); 1524fbd733b8SArnaldo Carvalho de Melo return -1; 1525fbd733b8SArnaldo Carvalho de Melo } 1526fbd733b8SArnaldo Carvalho de Melo if (!dso__build_id_equal(self, build_id)) { 1527fbd733b8SArnaldo Carvalho de Melo char expected_build_id[BUILD_ID_SIZE * 2 + 1], 1528fbd733b8SArnaldo Carvalho de Melo vmlinux_build_id[BUILD_ID_SIZE * 2 + 1]; 1529fbd733b8SArnaldo Carvalho de Melo 1530fbd733b8SArnaldo Carvalho de Melo build_id__sprintf(self->build_id, 1531fbd733b8SArnaldo Carvalho de Melo sizeof(self->build_id), 1532fbd733b8SArnaldo Carvalho de Melo expected_build_id); 1533fbd733b8SArnaldo Carvalho de Melo build_id__sprintf(build_id, sizeof(build_id), 1534fbd733b8SArnaldo Carvalho de Melo vmlinux_build_id); 1535fbd733b8SArnaldo Carvalho de Melo pr_debug("build_id in %s is %s while expected is %s, " 1536fbd733b8SArnaldo Carvalho de Melo "ignoring it\n", vmlinux, vmlinux_build_id, 1537fbd733b8SArnaldo Carvalho de Melo expected_build_id); 1538fbd733b8SArnaldo Carvalho de Melo return -1; 1539fbd733b8SArnaldo Carvalho de Melo } 1540fbd733b8SArnaldo Carvalho de Melo } 1541fbd733b8SArnaldo Carvalho de Melo 1542fbd733b8SArnaldo Carvalho de Melo fd = open(vmlinux, O_RDONLY); 154386470930SIngo Molnar if (fd < 0) 154486470930SIngo Molnar return -1; 154586470930SIngo Molnar 15463610583cSArnaldo Carvalho de Melo dso__set_loaded(self, map->type); 15474aa65636SArnaldo Carvalho de Melo err = dso__load_sym(self, map, session, self->long_name, fd, filter, 1, 0); 154886470930SIngo Molnar close(fd); 154986470930SIngo Molnar 155086470930SIngo Molnar return err; 155186470930SIngo Molnar } 155286470930SIngo Molnar 1553c338aee8SArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *self, struct map *map, 15544aa65636SArnaldo Carvalho de Melo struct perf_session *session, symbol_filter_t filter) 155586470930SIngo Molnar { 1556cc612d81SArnaldo Carvalho de Melo int err; 1557cc612d81SArnaldo Carvalho de Melo bool is_kallsyms; 1558439d473bSArnaldo Carvalho de Melo 1559cc612d81SArnaldo Carvalho de Melo if (vmlinux_path != NULL) { 1560cc612d81SArnaldo Carvalho de Melo int i; 1561cc612d81SArnaldo Carvalho de Melo pr_debug("Looking at the vmlinux_path (%d entries long)\n", 1562cc612d81SArnaldo Carvalho de Melo vmlinux_path__nr_entries); 1563cc612d81SArnaldo Carvalho de Melo for (i = 0; i < vmlinux_path__nr_entries; ++i) { 15644aa65636SArnaldo Carvalho de Melo err = dso__load_vmlinux(self, map, session, 156595011c60SArnaldo Carvalho de Melo vmlinux_path[i], filter); 1566cc612d81SArnaldo Carvalho de Melo if (err > 0) { 1567cc612d81SArnaldo Carvalho de Melo pr_debug("Using %s for symbols\n", 1568cc612d81SArnaldo Carvalho de Melo vmlinux_path[i]); 1569cc612d81SArnaldo Carvalho de Melo dso__set_long_name(self, 1570cc612d81SArnaldo Carvalho de Melo strdup(vmlinux_path[i])); 1571cc612d81SArnaldo Carvalho de Melo goto out_fixup; 1572cc612d81SArnaldo Carvalho de Melo } 1573cc612d81SArnaldo Carvalho de Melo } 1574cc612d81SArnaldo Carvalho de Melo } 1575cc612d81SArnaldo Carvalho de Melo 1576cc612d81SArnaldo Carvalho de Melo is_kallsyms = self->long_name[0] == '['; 1577cc612d81SArnaldo Carvalho de Melo if (is_kallsyms) 1578cc612d81SArnaldo Carvalho de Melo goto do_kallsyms; 1579cc612d81SArnaldo Carvalho de Melo 15804aa65636SArnaldo Carvalho de Melo err = dso__load_vmlinux(self, map, session, self->long_name, filter); 1581ef6ae724SArnaldo Carvalho de Melo if (err <= 0) { 1582cc612d81SArnaldo Carvalho de Melo pr_info("The file %s cannot be used, " 1583cc612d81SArnaldo Carvalho de Melo "trying to use /proc/kallsyms...", self->long_name); 1584cc612d81SArnaldo Carvalho de Melo do_kallsyms: 15854aa65636SArnaldo Carvalho de Melo err = dso__load_kallsyms(self, map, session, filter); 1586cc612d81SArnaldo Carvalho de Melo if (err > 0 && !is_kallsyms) 1587ef6ae724SArnaldo Carvalho de Melo dso__set_long_name(self, strdup("[kernel.kallsyms]")); 1588ef6ae724SArnaldo Carvalho de Melo } 158986470930SIngo Molnar 1590439d473bSArnaldo Carvalho de Melo if (err > 0) { 1591cc612d81SArnaldo Carvalho de Melo out_fixup: 15926a4694a4SArnaldo Carvalho de Melo map__fixup_start(map); 15936a4694a4SArnaldo Carvalho de Melo map__fixup_end(map); 1594439d473bSArnaldo Carvalho de Melo } 159594cb9e38SArnaldo Carvalho de Melo 159686470930SIngo Molnar return err; 159786470930SIngo Molnar } 159886470930SIngo Molnar 1599b0da954aSArnaldo Carvalho de Melo LIST_HEAD(dsos__user); 1600b0da954aSArnaldo Carvalho de Melo LIST_HEAD(dsos__kernel); 1601cd84c2acSFrederic Weisbecker struct dso *vdso; 1602cd84c2acSFrederic Weisbecker 1603b0da954aSArnaldo Carvalho de Melo static void dsos__add(struct list_head *head, struct dso *dso) 1604cd84c2acSFrederic Weisbecker { 1605b0da954aSArnaldo Carvalho de Melo list_add_tail(&dso->node, head); 1606cd84c2acSFrederic Weisbecker } 1607cd84c2acSFrederic Weisbecker 1608b0da954aSArnaldo Carvalho de Melo static struct dso *dsos__find(struct list_head *head, const char *name) 1609cd84c2acSFrederic Weisbecker { 1610cd84c2acSFrederic Weisbecker struct dso *pos; 1611cd84c2acSFrederic Weisbecker 1612b0da954aSArnaldo Carvalho de Melo list_for_each_entry(pos, head, node) 1613cd84c2acSFrederic Weisbecker if (strcmp(pos->name, name) == 0) 1614cd84c2acSFrederic Weisbecker return pos; 1615cd84c2acSFrederic Weisbecker return NULL; 1616cd84c2acSFrederic Weisbecker } 1617cd84c2acSFrederic Weisbecker 161800a192b3SArnaldo Carvalho de Melo struct dso *dsos__findnew(const char *name) 1619cd84c2acSFrederic Weisbecker { 1620b0da954aSArnaldo Carvalho de Melo struct dso *dso = dsos__find(&dsos__user, name); 1621cd84c2acSFrederic Weisbecker 1622e4204992SArnaldo Carvalho de Melo if (!dso) { 162300a192b3SArnaldo Carvalho de Melo dso = dso__new(name); 1624cfc10d3bSArnaldo Carvalho de Melo if (dso != NULL) { 1625b0da954aSArnaldo Carvalho de Melo dsos__add(&dsos__user, dso); 1626cfc10d3bSArnaldo Carvalho de Melo dso__set_basename(dso); 1627cfc10d3bSArnaldo Carvalho de Melo } 1628e4204992SArnaldo Carvalho de Melo } 1629cd84c2acSFrederic Weisbecker 1630cd84c2acSFrederic Weisbecker return dso; 1631cd84c2acSFrederic Weisbecker } 1632cd84c2acSFrederic Weisbecker 1633b0da954aSArnaldo Carvalho de Melo static void __dsos__fprintf(struct list_head *head, FILE *fp) 1634cd84c2acSFrederic Weisbecker { 1635cd84c2acSFrederic Weisbecker struct dso *pos; 1636cd84c2acSFrederic Weisbecker 163795011c60SArnaldo Carvalho de Melo list_for_each_entry(pos, head, node) { 163895011c60SArnaldo Carvalho de Melo int i; 163995011c60SArnaldo Carvalho de Melo for (i = 0; i < MAP__NR_TYPES; ++i) 164095011c60SArnaldo Carvalho de Melo dso__fprintf(pos, i, fp); 164195011c60SArnaldo Carvalho de Melo } 1642cd84c2acSFrederic Weisbecker } 1643cd84c2acSFrederic Weisbecker 1644b0da954aSArnaldo Carvalho de Melo void dsos__fprintf(FILE *fp) 1645b0da954aSArnaldo Carvalho de Melo { 1646b0da954aSArnaldo Carvalho de Melo __dsos__fprintf(&dsos__kernel, fp); 1647b0da954aSArnaldo Carvalho de Melo __dsos__fprintf(&dsos__user, fp); 1648b0da954aSArnaldo Carvalho de Melo } 1649b0da954aSArnaldo Carvalho de Melo 1650b0da954aSArnaldo Carvalho de Melo static size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp) 16519e03eb2dSArnaldo Carvalho de Melo { 16529e03eb2dSArnaldo Carvalho de Melo struct dso *pos; 16539e03eb2dSArnaldo Carvalho de Melo size_t ret = 0; 16549e03eb2dSArnaldo Carvalho de Melo 1655b0da954aSArnaldo Carvalho de Melo list_for_each_entry(pos, head, node) { 16569e03eb2dSArnaldo Carvalho de Melo ret += dso__fprintf_buildid(pos, fp); 16579e03eb2dSArnaldo Carvalho de Melo ret += fprintf(fp, " %s\n", pos->long_name); 16589e03eb2dSArnaldo Carvalho de Melo } 16599e03eb2dSArnaldo Carvalho de Melo return ret; 16609e03eb2dSArnaldo Carvalho de Melo } 16619e03eb2dSArnaldo Carvalho de Melo 1662b0da954aSArnaldo Carvalho de Melo size_t dsos__fprintf_buildid(FILE *fp) 1663b0da954aSArnaldo Carvalho de Melo { 1664b0da954aSArnaldo Carvalho de Melo return (__dsos__fprintf_buildid(&dsos__kernel, fp) + 1665b0da954aSArnaldo Carvalho de Melo __dsos__fprintf_buildid(&dsos__user, fp)); 1666b0da954aSArnaldo Carvalho de Melo } 1667b0da954aSArnaldo Carvalho de Melo 1668f1dfa0b1SArnaldo Carvalho de Melo static struct dso *dsos__create_kernel(const char *vmlinux) 1669cd84c2acSFrederic Weisbecker { 167095011c60SArnaldo Carvalho de Melo struct dso *kernel = dso__new(vmlinux ?: "[kernel.kallsyms]"); 1671cd84c2acSFrederic Weisbecker 16722446042cSArnaldo Carvalho de Melo if (kernel == NULL) 1673f1dfa0b1SArnaldo Carvalho de Melo return NULL; 1674c338aee8SArnaldo Carvalho de Melo 16752446042cSArnaldo Carvalho de Melo kernel->short_name = "[kernel]"; 1676c338aee8SArnaldo Carvalho de Melo kernel->kernel = 1; 1677cc612d81SArnaldo Carvalho de Melo 167800a192b3SArnaldo Carvalho de Melo vdso = dso__new("[vdso]"); 1679c338aee8SArnaldo Carvalho de Melo if (vdso == NULL) 1680f1dfa0b1SArnaldo Carvalho de Melo goto out_delete_kernel_dso; 16813610583cSArnaldo Carvalho de Melo dso__set_loaded(vdso, MAP__FUNCTION); 1682cd84c2acSFrederic Weisbecker 16832446042cSArnaldo Carvalho de Melo if (sysfs__read_build_id("/sys/kernel/notes", kernel->build_id, 16842446042cSArnaldo Carvalho de Melo sizeof(kernel->build_id)) == 0) 16852446042cSArnaldo Carvalho de Melo kernel->has_build_id = true; 16862446042cSArnaldo Carvalho de Melo 1687b0da954aSArnaldo Carvalho de Melo dsos__add(&dsos__kernel, kernel); 1688b0da954aSArnaldo Carvalho de Melo dsos__add(&dsos__user, vdso); 1689cd84c2acSFrederic Weisbecker 1690f1dfa0b1SArnaldo Carvalho de Melo return kernel; 1691c338aee8SArnaldo Carvalho de Melo 1692c338aee8SArnaldo Carvalho de Melo out_delete_kernel_dso: 1693c338aee8SArnaldo Carvalho de Melo dso__delete(kernel); 1694f1dfa0b1SArnaldo Carvalho de Melo return NULL; 1695f1dfa0b1SArnaldo Carvalho de Melo } 1696f1dfa0b1SArnaldo Carvalho de Melo 1697de176489SArnaldo Carvalho de Melo static int map_groups__create_kernel_maps(struct map_groups *self, 1698de176489SArnaldo Carvalho de Melo struct map *vmlinux_maps[MAP__NR_TYPES], 1699de176489SArnaldo Carvalho de Melo const char *vmlinux) 1700f1dfa0b1SArnaldo Carvalho de Melo { 1701f1dfa0b1SArnaldo Carvalho de Melo struct dso *kernel = dsos__create_kernel(vmlinux); 1702de176489SArnaldo Carvalho de Melo enum map_type type; 1703f1dfa0b1SArnaldo Carvalho de Melo 1704f1dfa0b1SArnaldo Carvalho de Melo if (kernel == NULL) 1705c338aee8SArnaldo Carvalho de Melo return -1; 1706f1dfa0b1SArnaldo Carvalho de Melo 1707de176489SArnaldo Carvalho de Melo for (type = 0; type < MAP__NR_TYPES; ++type) { 1708de176489SArnaldo Carvalho de Melo vmlinux_maps[type] = map__new2(0, kernel, type); 1709de176489SArnaldo Carvalho de Melo if (vmlinux_maps[type] == NULL) 1710f1dfa0b1SArnaldo Carvalho de Melo return -1; 1711f1dfa0b1SArnaldo Carvalho de Melo 1712de176489SArnaldo Carvalho de Melo vmlinux_maps[type]->map_ip = 1713de176489SArnaldo Carvalho de Melo vmlinux_maps[type]->unmap_ip = identity__map_ip; 1714de176489SArnaldo Carvalho de Melo map_groups__insert(self, vmlinux_maps[type]); 1715f1dfa0b1SArnaldo Carvalho de Melo } 1716f1dfa0b1SArnaldo Carvalho de Melo 1717f1dfa0b1SArnaldo Carvalho de Melo return 0; 17182446042cSArnaldo Carvalho de Melo } 17192446042cSArnaldo Carvalho de Melo 1720cc612d81SArnaldo Carvalho de Melo static void vmlinux_path__exit(void) 17212446042cSArnaldo Carvalho de Melo { 1722cc612d81SArnaldo Carvalho de Melo while (--vmlinux_path__nr_entries >= 0) { 1723cc612d81SArnaldo Carvalho de Melo free(vmlinux_path[vmlinux_path__nr_entries]); 1724cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = NULL; 1725cc612d81SArnaldo Carvalho de Melo } 1726cc612d81SArnaldo Carvalho de Melo 1727cc612d81SArnaldo Carvalho de Melo free(vmlinux_path); 1728cc612d81SArnaldo Carvalho de Melo vmlinux_path = NULL; 1729cc612d81SArnaldo Carvalho de Melo } 1730cc612d81SArnaldo Carvalho de Melo 1731cc612d81SArnaldo Carvalho de Melo static int vmlinux_path__init(void) 1732cc612d81SArnaldo Carvalho de Melo { 1733cc612d81SArnaldo Carvalho de Melo struct utsname uts; 1734cc612d81SArnaldo Carvalho de Melo char bf[PATH_MAX]; 1735cc612d81SArnaldo Carvalho de Melo 1736cc612d81SArnaldo Carvalho de Melo if (uname(&uts) < 0) 17372446042cSArnaldo Carvalho de Melo return -1; 17382446042cSArnaldo Carvalho de Melo 1739cc612d81SArnaldo Carvalho de Melo vmlinux_path = malloc(sizeof(char *) * 5); 1740cc612d81SArnaldo Carvalho de Melo if (vmlinux_path == NULL) 1741cc612d81SArnaldo Carvalho de Melo return -1; 1742cc612d81SArnaldo Carvalho de Melo 1743cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup("vmlinux"); 1744cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 1745cc612d81SArnaldo Carvalho de Melo goto out_fail; 1746cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 1747cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup("/boot/vmlinux"); 1748cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 1749cc612d81SArnaldo Carvalho de Melo goto out_fail; 1750cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 1751cc612d81SArnaldo Carvalho de Melo snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", uts.release); 1752cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); 1753cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 1754cc612d81SArnaldo Carvalho de Melo goto out_fail; 1755cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 1756cc612d81SArnaldo Carvalho de Melo snprintf(bf, sizeof(bf), "/lib/modules/%s/build/vmlinux", uts.release); 1757cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); 1758cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 1759cc612d81SArnaldo Carvalho de Melo goto out_fail; 1760cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 1761cc612d81SArnaldo Carvalho de Melo snprintf(bf, sizeof(bf), "/usr/lib/debug/lib/modules/%s/vmlinux", 1762cc612d81SArnaldo Carvalho de Melo uts.release); 1763cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); 1764cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 1765cc612d81SArnaldo Carvalho de Melo goto out_fail; 1766cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 1767cc612d81SArnaldo Carvalho de Melo 1768cc612d81SArnaldo Carvalho de Melo return 0; 1769cc612d81SArnaldo Carvalho de Melo 1770cc612d81SArnaldo Carvalho de Melo out_fail: 1771cc612d81SArnaldo Carvalho de Melo vmlinux_path__exit(); 1772cc612d81SArnaldo Carvalho de Melo return -1; 1773cc612d81SArnaldo Carvalho de Melo } 1774cc612d81SArnaldo Carvalho de Melo 1775655000e7SArnaldo Carvalho de Melo static int setup_list(struct strlist **list, const char *list_str, 1776655000e7SArnaldo Carvalho de Melo const char *list_name) 1777655000e7SArnaldo Carvalho de Melo { 1778655000e7SArnaldo Carvalho de Melo if (list_str == NULL) 1779655000e7SArnaldo Carvalho de Melo return 0; 1780655000e7SArnaldo Carvalho de Melo 1781655000e7SArnaldo Carvalho de Melo *list = strlist__new(true, list_str); 1782655000e7SArnaldo Carvalho de Melo if (!*list) { 1783655000e7SArnaldo Carvalho de Melo pr_err("problems parsing %s list\n", list_name); 1784655000e7SArnaldo Carvalho de Melo return -1; 1785655000e7SArnaldo Carvalho de Melo } 1786655000e7SArnaldo Carvalho de Melo return 0; 1787655000e7SArnaldo Carvalho de Melo } 1788655000e7SArnaldo Carvalho de Melo 178975be6cf4SArnaldo Carvalho de Melo int symbol__init(void) 1790cc612d81SArnaldo Carvalho de Melo { 179195011c60SArnaldo Carvalho de Melo elf_version(EV_CURRENT); 179275be6cf4SArnaldo Carvalho de Melo if (symbol_conf.sort_by_name) 179375be6cf4SArnaldo Carvalho de Melo symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) - 179479406cd7SArnaldo Carvalho de Melo sizeof(struct symbol)); 1795b32d133aSArnaldo Carvalho de Melo 179675be6cf4SArnaldo Carvalho de Melo if (symbol_conf.try_vmlinux_path && vmlinux_path__init() < 0) 1797cc612d81SArnaldo Carvalho de Melo return -1; 1798cc612d81SArnaldo Carvalho de Melo 1799c410a338SArnaldo Carvalho de Melo if (symbol_conf.field_sep && *symbol_conf.field_sep == '.') { 1800c410a338SArnaldo Carvalho de Melo pr_err("'.' is the only non valid --field-separator argument\n"); 1801c410a338SArnaldo Carvalho de Melo return -1; 1802c410a338SArnaldo Carvalho de Melo } 1803c410a338SArnaldo Carvalho de Melo 1804655000e7SArnaldo Carvalho de Melo if (setup_list(&symbol_conf.dso_list, 1805655000e7SArnaldo Carvalho de Melo symbol_conf.dso_list_str, "dso") < 0) 1806655000e7SArnaldo Carvalho de Melo return -1; 1807655000e7SArnaldo Carvalho de Melo 1808655000e7SArnaldo Carvalho de Melo if (setup_list(&symbol_conf.comm_list, 1809655000e7SArnaldo Carvalho de Melo symbol_conf.comm_list_str, "comm") < 0) 1810655000e7SArnaldo Carvalho de Melo goto out_free_dso_list; 1811655000e7SArnaldo Carvalho de Melo 1812655000e7SArnaldo Carvalho de Melo if (setup_list(&symbol_conf.sym_list, 1813655000e7SArnaldo Carvalho de Melo symbol_conf.sym_list_str, "symbol") < 0) 1814655000e7SArnaldo Carvalho de Melo goto out_free_comm_list; 1815655000e7SArnaldo Carvalho de Melo 18164aa65636SArnaldo Carvalho de Melo return 0; 1817655000e7SArnaldo Carvalho de Melo 1818655000e7SArnaldo Carvalho de Melo out_free_dso_list: 1819655000e7SArnaldo Carvalho de Melo strlist__delete(symbol_conf.dso_list); 1820655000e7SArnaldo Carvalho de Melo out_free_comm_list: 1821655000e7SArnaldo Carvalho de Melo strlist__delete(symbol_conf.comm_list); 1822655000e7SArnaldo Carvalho de Melo return -1; 1823cc612d81SArnaldo Carvalho de Melo } 1824cc612d81SArnaldo Carvalho de Melo 182575be6cf4SArnaldo Carvalho de Melo int perf_session__create_kernel_maps(struct perf_session *self) 18264aa65636SArnaldo Carvalho de Melo { 1827de176489SArnaldo Carvalho de Melo if (map_groups__create_kernel_maps(&self->kmaps, self->vmlinux_maps, 182875be6cf4SArnaldo Carvalho de Melo symbol_conf.vmlinux_name) < 0) 18294aa65636SArnaldo Carvalho de Melo return -1; 18304aa65636SArnaldo Carvalho de Melo 183175be6cf4SArnaldo Carvalho de Melo if (symbol_conf.use_modules && 183275be6cf4SArnaldo Carvalho de Melo perf_session__create_module_maps(self) < 0) 18334aa65636SArnaldo Carvalho de Melo pr_debug("Failed to load list of modules for session %s, " 18344aa65636SArnaldo Carvalho de Melo "continuing...\n", self->filename); 183590c83218SArnaldo Carvalho de Melo /* 183690c83218SArnaldo Carvalho de Melo * Now that we have all the maps created, just set the ->end of them: 183790c83218SArnaldo Carvalho de Melo */ 18384aa65636SArnaldo Carvalho de Melo map_groups__fixup_end(&self->kmaps); 18396671cb16SArnaldo Carvalho de Melo return 0; 1840cd84c2acSFrederic Weisbecker } 1841