15aab621bSArnaldo Carvalho de Melo #define _GNU_SOURCE 25aab621bSArnaldo Carvalho de Melo #include <ctype.h> 35aab621bSArnaldo Carvalho de Melo #include <dirent.h> 45aab621bSArnaldo Carvalho de Melo #include <errno.h> 55aab621bSArnaldo Carvalho de Melo #include <libgen.h> 65aab621bSArnaldo Carvalho de Melo #include <stdlib.h> 75aab621bSArnaldo Carvalho de Melo #include <stdio.h> 85aab621bSArnaldo Carvalho de Melo #include <string.h> 95aab621bSArnaldo Carvalho de Melo #include <sys/types.h> 105aab621bSArnaldo Carvalho de Melo #include <sys/stat.h> 115aab621bSArnaldo Carvalho de Melo #include <sys/param.h> 125aab621bSArnaldo Carvalho de Melo #include <fcntl.h> 135aab621bSArnaldo Carvalho de Melo #include <unistd.h> 1486470930SIngo Molnar #include "symbol.h" 155aab621bSArnaldo Carvalho de Melo #include "strlist.h" 1686470930SIngo Molnar 1786470930SIngo Molnar #include <libelf.h> 1886470930SIngo Molnar #include <gelf.h> 1986470930SIngo Molnar #include <elf.h> 20f1617b40SArnaldo Carvalho de Melo #include <limits.h> 21439d473bSArnaldo Carvalho de Melo #include <sys/utsname.h> 222cdbc46dSPeter Zijlstra 23c12e15e7SArnaldo Carvalho de Melo #ifndef NT_GNU_BUILD_ID 24c12e15e7SArnaldo Carvalho de Melo #define NT_GNU_BUILD_ID 3 25c12e15e7SArnaldo Carvalho de Melo #endif 26c12e15e7SArnaldo Carvalho de Melo 27b0da954aSArnaldo Carvalho de Melo static void dsos__add(struct list_head *head, struct dso *dso); 283610583cSArnaldo Carvalho de Melo static struct map *map__new2(u64 start, struct dso *dso, enum map_type type); 29c338aee8SArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *self, struct map *map, 309de89fe7SArnaldo Carvalho de Melo symbol_filter_t filter); 31a1645ce1SZhang, Yanmin static int dso__load_guest_kernel_sym(struct dso *self, struct map *map, 32a1645ce1SZhang, Yanmin symbol_filter_t filter); 33cc612d81SArnaldo Carvalho de Melo static int vmlinux_path__nr_entries; 34cc612d81SArnaldo Carvalho de Melo static char **vmlinux_path; 35439d473bSArnaldo Carvalho de Melo 3675be6cf4SArnaldo Carvalho de Melo struct symbol_conf symbol_conf = { 37d599db3fSArnaldo Carvalho de Melo .exclude_other = true, 38b32d133aSArnaldo Carvalho de Melo .use_modules = true, 39b32d133aSArnaldo Carvalho de Melo .try_vmlinux_path = true, 40b32d133aSArnaldo Carvalho de Melo }; 41b32d133aSArnaldo Carvalho de Melo 423610583cSArnaldo Carvalho de Melo bool dso__loaded(const struct dso *self, enum map_type type) 433610583cSArnaldo Carvalho de Melo { 443610583cSArnaldo Carvalho de Melo return self->loaded & (1 << type); 453610583cSArnaldo Carvalho de Melo } 463610583cSArnaldo Carvalho de Melo 4779406cd7SArnaldo Carvalho de Melo bool dso__sorted_by_name(const struct dso *self, enum map_type type) 4879406cd7SArnaldo Carvalho de Melo { 4979406cd7SArnaldo Carvalho de Melo return self->sorted_by_name & (1 << type); 5079406cd7SArnaldo Carvalho de Melo } 5179406cd7SArnaldo Carvalho de Melo 5279406cd7SArnaldo Carvalho de Melo static void dso__set_sorted_by_name(struct dso *self, enum map_type type) 5379406cd7SArnaldo Carvalho de Melo { 5479406cd7SArnaldo Carvalho de Melo self->sorted_by_name |= (1 << type); 5579406cd7SArnaldo Carvalho de Melo } 5679406cd7SArnaldo Carvalho de Melo 5736a3e646SArnaldo Carvalho de Melo bool symbol_type__is_a(char symbol_type, enum map_type map_type) 586893d4eeSArnaldo Carvalho de Melo { 596893d4eeSArnaldo Carvalho de Melo switch (map_type) { 606893d4eeSArnaldo Carvalho de Melo case MAP__FUNCTION: 616893d4eeSArnaldo Carvalho de Melo return symbol_type == 'T' || symbol_type == 'W'; 62f1dfa0b1SArnaldo Carvalho de Melo case MAP__VARIABLE: 63f1dfa0b1SArnaldo Carvalho de Melo return symbol_type == 'D' || symbol_type == 'd'; 646893d4eeSArnaldo Carvalho de Melo default: 656893d4eeSArnaldo Carvalho de Melo return false; 666893d4eeSArnaldo Carvalho de Melo } 676893d4eeSArnaldo Carvalho de Melo } 686893d4eeSArnaldo Carvalho de Melo 69fcf1203aSArnaldo Carvalho de Melo static void symbols__fixup_end(struct rb_root *self) 70af427bf5SArnaldo Carvalho de Melo { 71fcf1203aSArnaldo Carvalho de Melo struct rb_node *nd, *prevnd = rb_first(self); 722e538c4aSArnaldo Carvalho de Melo struct symbol *curr, *prev; 73af427bf5SArnaldo Carvalho de Melo 74af427bf5SArnaldo Carvalho de Melo if (prevnd == NULL) 75af427bf5SArnaldo Carvalho de Melo return; 76af427bf5SArnaldo Carvalho de Melo 772e538c4aSArnaldo Carvalho de Melo curr = rb_entry(prevnd, struct symbol, rb_node); 782e538c4aSArnaldo Carvalho de Melo 79af427bf5SArnaldo Carvalho de Melo for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) { 802e538c4aSArnaldo Carvalho de Melo prev = curr; 812e538c4aSArnaldo Carvalho de Melo curr = rb_entry(nd, struct symbol, rb_node); 82af427bf5SArnaldo Carvalho de Melo 83af427bf5SArnaldo Carvalho de Melo if (prev->end == prev->start) 84af427bf5SArnaldo Carvalho de Melo prev->end = curr->start - 1; 85af427bf5SArnaldo Carvalho de Melo } 86af427bf5SArnaldo Carvalho de Melo 872e538c4aSArnaldo Carvalho de Melo /* Last entry */ 882e538c4aSArnaldo Carvalho de Melo if (curr->end == curr->start) 892e538c4aSArnaldo Carvalho de Melo curr->end = roundup(curr->start, 4096); 902e538c4aSArnaldo Carvalho de Melo } 912e538c4aSArnaldo Carvalho de Melo 929958e1f0SArnaldo Carvalho de Melo static void __map_groups__fixup_end(struct map_groups *self, enum map_type type) 93af427bf5SArnaldo Carvalho de Melo { 94af427bf5SArnaldo Carvalho de Melo struct map *prev, *curr; 9595011c60SArnaldo Carvalho de Melo struct rb_node *nd, *prevnd = rb_first(&self->maps[type]); 96af427bf5SArnaldo Carvalho de Melo 97af427bf5SArnaldo Carvalho de Melo if (prevnd == NULL) 98af427bf5SArnaldo Carvalho de Melo return; 99af427bf5SArnaldo Carvalho de Melo 100af427bf5SArnaldo Carvalho de Melo curr = rb_entry(prevnd, struct map, rb_node); 101af427bf5SArnaldo Carvalho de Melo 102af427bf5SArnaldo Carvalho de Melo for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) { 103af427bf5SArnaldo Carvalho de Melo prev = curr; 104af427bf5SArnaldo Carvalho de Melo curr = rb_entry(nd, struct map, rb_node); 105af427bf5SArnaldo Carvalho de Melo prev->end = curr->start - 1; 1062e538c4aSArnaldo Carvalho de Melo } 10790c83218SArnaldo Carvalho de Melo 10890c83218SArnaldo Carvalho de Melo /* 10990c83218SArnaldo Carvalho de Melo * We still haven't the actual symbols, so guess the 11090c83218SArnaldo Carvalho de Melo * last map final address. 11190c83218SArnaldo Carvalho de Melo */ 11290c83218SArnaldo Carvalho de Melo curr->end = ~0UL; 113af427bf5SArnaldo Carvalho de Melo } 114af427bf5SArnaldo Carvalho de Melo 1159958e1f0SArnaldo Carvalho de Melo static void map_groups__fixup_end(struct map_groups *self) 11623ea4a3fSArnaldo Carvalho de Melo { 11723ea4a3fSArnaldo Carvalho de Melo int i; 11823ea4a3fSArnaldo Carvalho de Melo for (i = 0; i < MAP__NR_TYPES; ++i) 1199958e1f0SArnaldo Carvalho de Melo __map_groups__fixup_end(self, i); 12023ea4a3fSArnaldo Carvalho de Melo } 12123ea4a3fSArnaldo Carvalho de Melo 12200a192b3SArnaldo Carvalho de Melo static struct symbol *symbol__new(u64 start, u64 len, const char *name) 12386470930SIngo Molnar { 12486470930SIngo Molnar size_t namelen = strlen(name) + 1; 1255aab621bSArnaldo Carvalho de Melo struct symbol *self = calloc(1, (symbol_conf.priv_size + 1265aab621bSArnaldo Carvalho de Melo sizeof(*self) + namelen)); 12736479484SArnaldo Carvalho de Melo if (self == NULL) 12886470930SIngo Molnar return NULL; 12986470930SIngo Molnar 13075be6cf4SArnaldo Carvalho de Melo if (symbol_conf.priv_size) 13175be6cf4SArnaldo Carvalho de Melo self = ((void *)self) + symbol_conf.priv_size; 13236479484SArnaldo Carvalho de Melo 13386470930SIngo Molnar self->start = start; 1346cfcc53eSMike Galbraith self->end = len ? start + len - 1 : start; 135e4204992SArnaldo Carvalho de Melo 13629a9f66dSArnaldo Carvalho de Melo pr_debug4("%s: %s %#Lx-%#Lx\n", __func__, name, start, self->end); 137e4204992SArnaldo Carvalho de Melo 13886470930SIngo Molnar memcpy(self->name, name, namelen); 13986470930SIngo Molnar 14086470930SIngo Molnar return self; 14186470930SIngo Molnar } 14286470930SIngo Molnar 143628ada0cSArnaldo Carvalho de Melo void symbol__delete(struct symbol *self) 14486470930SIngo Molnar { 14575be6cf4SArnaldo Carvalho de Melo free(((void *)self) - symbol_conf.priv_size); 14686470930SIngo Molnar } 14786470930SIngo Molnar 14886470930SIngo Molnar static size_t symbol__fprintf(struct symbol *self, FILE *fp) 14986470930SIngo Molnar { 15086470930SIngo Molnar return fprintf(fp, " %llx-%llx %s\n", 15186470930SIngo Molnar self->start, self->end, self->name); 15286470930SIngo Molnar } 15386470930SIngo Molnar 154b7cece76SArnaldo Carvalho de Melo void dso__set_long_name(struct dso *self, char *name) 155cfc10d3bSArnaldo Carvalho de Melo { 156ef6ae724SArnaldo Carvalho de Melo if (name == NULL) 157ef6ae724SArnaldo Carvalho de Melo return; 158cfc10d3bSArnaldo Carvalho de Melo self->long_name = name; 159cfc10d3bSArnaldo Carvalho de Melo self->long_name_len = strlen(name); 160cfc10d3bSArnaldo Carvalho de Melo } 161cfc10d3bSArnaldo Carvalho de Melo 162b63be8d7SArnaldo Carvalho de Melo static void dso__set_short_name(struct dso *self, const char *name) 163b63be8d7SArnaldo Carvalho de Melo { 164b63be8d7SArnaldo Carvalho de Melo if (name == NULL) 165b63be8d7SArnaldo Carvalho de Melo return; 166b63be8d7SArnaldo Carvalho de Melo self->short_name = name; 167b63be8d7SArnaldo Carvalho de Melo self->short_name_len = strlen(name); 168b63be8d7SArnaldo Carvalho de Melo } 169b63be8d7SArnaldo Carvalho de Melo 170cfc10d3bSArnaldo Carvalho de Melo static void dso__set_basename(struct dso *self) 171cfc10d3bSArnaldo Carvalho de Melo { 172b63be8d7SArnaldo Carvalho de Melo dso__set_short_name(self, basename(self->long_name)); 173cfc10d3bSArnaldo Carvalho de Melo } 174cfc10d3bSArnaldo Carvalho de Melo 17500a192b3SArnaldo Carvalho de Melo struct dso *dso__new(const char *name) 17686470930SIngo Molnar { 1775aab621bSArnaldo Carvalho de Melo struct dso *self = calloc(1, sizeof(*self) + strlen(name) + 1); 17886470930SIngo Molnar 17986470930SIngo Molnar if (self != NULL) { 1806a4694a4SArnaldo Carvalho de Melo int i; 18186470930SIngo Molnar strcpy(self->name, name); 182cfc10d3bSArnaldo Carvalho de Melo dso__set_long_name(self, self->name); 183b63be8d7SArnaldo Carvalho de Melo dso__set_short_name(self, self->name); 1846a4694a4SArnaldo Carvalho de Melo for (i = 0; i < MAP__NR_TYPES; ++i) 18579406cd7SArnaldo Carvalho de Melo self->symbols[i] = self->symbol_names[i] = RB_ROOT; 18652d422deSArnaldo Carvalho de Melo self->slen_calculated = 0; 18794cb9e38SArnaldo Carvalho de Melo self->origin = DSO__ORIG_NOT_FOUND; 1888d06367fSArnaldo Carvalho de Melo self->loaded = 0; 18979406cd7SArnaldo Carvalho de Melo self->sorted_by_name = 0; 1908d06367fSArnaldo Carvalho de Melo self->has_build_id = 0; 191a1645ce1SZhang, Yanmin self->kernel = DSO_TYPE_USER; 192*0ab061cdSMasami Hiramatsu INIT_LIST_HEAD(&self->node); 19386470930SIngo Molnar } 19486470930SIngo Molnar 19586470930SIngo Molnar return self; 19686470930SIngo Molnar } 19786470930SIngo Molnar 198fcf1203aSArnaldo Carvalho de Melo static void symbols__delete(struct rb_root *self) 19986470930SIngo Molnar { 20086470930SIngo Molnar struct symbol *pos; 201fcf1203aSArnaldo Carvalho de Melo struct rb_node *next = rb_first(self); 20286470930SIngo Molnar 20386470930SIngo Molnar while (next) { 20486470930SIngo Molnar pos = rb_entry(next, struct symbol, rb_node); 20586470930SIngo Molnar next = rb_next(&pos->rb_node); 206fcf1203aSArnaldo Carvalho de Melo rb_erase(&pos->rb_node, self); 20700a192b3SArnaldo Carvalho de Melo symbol__delete(pos); 20886470930SIngo Molnar } 20986470930SIngo Molnar } 21086470930SIngo Molnar 21186470930SIngo Molnar void dso__delete(struct dso *self) 21286470930SIngo Molnar { 2136a4694a4SArnaldo Carvalho de Melo int i; 2146a4694a4SArnaldo Carvalho de Melo for (i = 0; i < MAP__NR_TYPES; ++i) 2156a4694a4SArnaldo Carvalho de Melo symbols__delete(&self->symbols[i]); 216439d473bSArnaldo Carvalho de Melo if (self->long_name != self->name) 217439d473bSArnaldo Carvalho de Melo free(self->long_name); 21886470930SIngo Molnar free(self); 21986470930SIngo Molnar } 22086470930SIngo Molnar 2218d06367fSArnaldo Carvalho de Melo void dso__set_build_id(struct dso *self, void *build_id) 2228d06367fSArnaldo Carvalho de Melo { 2238d06367fSArnaldo Carvalho de Melo memcpy(self->build_id, build_id, sizeof(self->build_id)); 2248d06367fSArnaldo Carvalho de Melo self->has_build_id = 1; 2258d06367fSArnaldo Carvalho de Melo } 2268d06367fSArnaldo Carvalho de Melo 227fcf1203aSArnaldo Carvalho de Melo static void symbols__insert(struct rb_root *self, struct symbol *sym) 22886470930SIngo Molnar { 229fcf1203aSArnaldo Carvalho de Melo struct rb_node **p = &self->rb_node; 23086470930SIngo Molnar struct rb_node *parent = NULL; 2319cffa8d5SPaul Mackerras const u64 ip = sym->start; 23286470930SIngo Molnar struct symbol *s; 23386470930SIngo Molnar 23486470930SIngo Molnar while (*p != NULL) { 23586470930SIngo Molnar parent = *p; 23686470930SIngo Molnar s = rb_entry(parent, struct symbol, rb_node); 23786470930SIngo Molnar if (ip < s->start) 23886470930SIngo Molnar p = &(*p)->rb_left; 23986470930SIngo Molnar else 24086470930SIngo Molnar p = &(*p)->rb_right; 24186470930SIngo Molnar } 24286470930SIngo Molnar rb_link_node(&sym->rb_node, parent, p); 243fcf1203aSArnaldo Carvalho de Melo rb_insert_color(&sym->rb_node, self); 24486470930SIngo Molnar } 24586470930SIngo Molnar 246fcf1203aSArnaldo Carvalho de Melo static struct symbol *symbols__find(struct rb_root *self, u64 ip) 24786470930SIngo Molnar { 24886470930SIngo Molnar struct rb_node *n; 24986470930SIngo Molnar 25086470930SIngo Molnar if (self == NULL) 25186470930SIngo Molnar return NULL; 25286470930SIngo Molnar 253fcf1203aSArnaldo Carvalho de Melo n = self->rb_node; 25486470930SIngo Molnar 25586470930SIngo Molnar while (n) { 25686470930SIngo Molnar struct symbol *s = rb_entry(n, struct symbol, rb_node); 25786470930SIngo Molnar 25886470930SIngo Molnar if (ip < s->start) 25986470930SIngo Molnar n = n->rb_left; 26086470930SIngo Molnar else if (ip > s->end) 26186470930SIngo Molnar n = n->rb_right; 26286470930SIngo Molnar else 26386470930SIngo Molnar return s; 26486470930SIngo Molnar } 26586470930SIngo Molnar 26686470930SIngo Molnar return NULL; 26786470930SIngo Molnar } 26886470930SIngo Molnar 26979406cd7SArnaldo Carvalho de Melo struct symbol_name_rb_node { 27079406cd7SArnaldo Carvalho de Melo struct rb_node rb_node; 27179406cd7SArnaldo Carvalho de Melo struct symbol sym; 27279406cd7SArnaldo Carvalho de Melo }; 27379406cd7SArnaldo Carvalho de Melo 27479406cd7SArnaldo Carvalho de Melo static void symbols__insert_by_name(struct rb_root *self, struct symbol *sym) 27579406cd7SArnaldo Carvalho de Melo { 27679406cd7SArnaldo Carvalho de Melo struct rb_node **p = &self->rb_node; 27779406cd7SArnaldo Carvalho de Melo struct rb_node *parent = NULL; 27879406cd7SArnaldo Carvalho de Melo struct symbol_name_rb_node *symn = ((void *)sym) - sizeof(*parent), *s; 27979406cd7SArnaldo Carvalho de Melo 28079406cd7SArnaldo Carvalho de Melo while (*p != NULL) { 28179406cd7SArnaldo Carvalho de Melo parent = *p; 28279406cd7SArnaldo Carvalho de Melo s = rb_entry(parent, struct symbol_name_rb_node, rb_node); 28379406cd7SArnaldo Carvalho de Melo if (strcmp(sym->name, s->sym.name) < 0) 28479406cd7SArnaldo Carvalho de Melo p = &(*p)->rb_left; 28579406cd7SArnaldo Carvalho de Melo else 28679406cd7SArnaldo Carvalho de Melo p = &(*p)->rb_right; 28779406cd7SArnaldo Carvalho de Melo } 28879406cd7SArnaldo Carvalho de Melo rb_link_node(&symn->rb_node, parent, p); 28979406cd7SArnaldo Carvalho de Melo rb_insert_color(&symn->rb_node, self); 29079406cd7SArnaldo Carvalho de Melo } 29179406cd7SArnaldo Carvalho de Melo 29279406cd7SArnaldo Carvalho de Melo static void symbols__sort_by_name(struct rb_root *self, struct rb_root *source) 29379406cd7SArnaldo Carvalho de Melo { 29479406cd7SArnaldo Carvalho de Melo struct rb_node *nd; 29579406cd7SArnaldo Carvalho de Melo 29679406cd7SArnaldo Carvalho de Melo for (nd = rb_first(source); nd; nd = rb_next(nd)) { 29779406cd7SArnaldo Carvalho de Melo struct symbol *pos = rb_entry(nd, struct symbol, rb_node); 29879406cd7SArnaldo Carvalho de Melo symbols__insert_by_name(self, pos); 29979406cd7SArnaldo Carvalho de Melo } 30079406cd7SArnaldo Carvalho de Melo } 30179406cd7SArnaldo Carvalho de Melo 30279406cd7SArnaldo Carvalho de Melo static struct symbol *symbols__find_by_name(struct rb_root *self, const char *name) 30379406cd7SArnaldo Carvalho de Melo { 30479406cd7SArnaldo Carvalho de Melo struct rb_node *n; 30579406cd7SArnaldo Carvalho de Melo 30679406cd7SArnaldo Carvalho de Melo if (self == NULL) 30779406cd7SArnaldo Carvalho de Melo return NULL; 30879406cd7SArnaldo Carvalho de Melo 30979406cd7SArnaldo Carvalho de Melo n = self->rb_node; 31079406cd7SArnaldo Carvalho de Melo 31179406cd7SArnaldo Carvalho de Melo while (n) { 31279406cd7SArnaldo Carvalho de Melo struct symbol_name_rb_node *s; 31379406cd7SArnaldo Carvalho de Melo int cmp; 31479406cd7SArnaldo Carvalho de Melo 31579406cd7SArnaldo Carvalho de Melo s = rb_entry(n, struct symbol_name_rb_node, rb_node); 31679406cd7SArnaldo Carvalho de Melo cmp = strcmp(name, s->sym.name); 31779406cd7SArnaldo Carvalho de Melo 31879406cd7SArnaldo Carvalho de Melo if (cmp < 0) 31979406cd7SArnaldo Carvalho de Melo n = n->rb_left; 32079406cd7SArnaldo Carvalho de Melo else if (cmp > 0) 32179406cd7SArnaldo Carvalho de Melo n = n->rb_right; 32279406cd7SArnaldo Carvalho de Melo else 32379406cd7SArnaldo Carvalho de Melo return &s->sym; 32479406cd7SArnaldo Carvalho de Melo } 32579406cd7SArnaldo Carvalho de Melo 32679406cd7SArnaldo Carvalho de Melo return NULL; 32779406cd7SArnaldo Carvalho de Melo } 32879406cd7SArnaldo Carvalho de Melo 32979406cd7SArnaldo Carvalho de Melo struct symbol *dso__find_symbol(struct dso *self, 33079406cd7SArnaldo Carvalho de Melo enum map_type type, u64 addr) 331fcf1203aSArnaldo Carvalho de Melo { 3326a4694a4SArnaldo Carvalho de Melo return symbols__find(&self->symbols[type], addr); 333fcf1203aSArnaldo Carvalho de Melo } 334fcf1203aSArnaldo Carvalho de Melo 33579406cd7SArnaldo Carvalho de Melo struct symbol *dso__find_symbol_by_name(struct dso *self, enum map_type type, 33679406cd7SArnaldo Carvalho de Melo const char *name) 33779406cd7SArnaldo Carvalho de Melo { 33879406cd7SArnaldo Carvalho de Melo return symbols__find_by_name(&self->symbol_names[type], name); 33979406cd7SArnaldo Carvalho de Melo } 34079406cd7SArnaldo Carvalho de Melo 34179406cd7SArnaldo Carvalho de Melo void dso__sort_by_name(struct dso *self, enum map_type type) 34279406cd7SArnaldo Carvalho de Melo { 34379406cd7SArnaldo Carvalho de Melo dso__set_sorted_by_name(self, type); 34479406cd7SArnaldo Carvalho de Melo return symbols__sort_by_name(&self->symbol_names[type], 34579406cd7SArnaldo Carvalho de Melo &self->symbols[type]); 34679406cd7SArnaldo Carvalho de Melo } 34779406cd7SArnaldo Carvalho de Melo 348ef12a141SArnaldo Carvalho de Melo int build_id__sprintf(const u8 *self, int len, char *bf) 3498d06367fSArnaldo Carvalho de Melo { 3508d06367fSArnaldo Carvalho de Melo char *bid = bf; 351ef12a141SArnaldo Carvalho de Melo const u8 *raw = self; 3528d06367fSArnaldo Carvalho de Melo int i; 3538d06367fSArnaldo Carvalho de Melo 3548d06367fSArnaldo Carvalho de Melo for (i = 0; i < len; ++i) { 3558d06367fSArnaldo Carvalho de Melo sprintf(bid, "%02x", *raw); 3568d06367fSArnaldo Carvalho de Melo ++raw; 3578d06367fSArnaldo Carvalho de Melo bid += 2; 3588d06367fSArnaldo Carvalho de Melo } 3598d06367fSArnaldo Carvalho de Melo 3608d06367fSArnaldo Carvalho de Melo return raw - self; 3618d06367fSArnaldo Carvalho de Melo } 3628d06367fSArnaldo Carvalho de Melo 3639e03eb2dSArnaldo Carvalho de Melo size_t dso__fprintf_buildid(struct dso *self, FILE *fp) 36486470930SIngo Molnar { 3658d06367fSArnaldo Carvalho de Melo char sbuild_id[BUILD_ID_SIZE * 2 + 1]; 3668d06367fSArnaldo Carvalho de Melo 3678d06367fSArnaldo Carvalho de Melo build_id__sprintf(self->build_id, sizeof(self->build_id), sbuild_id); 3689e03eb2dSArnaldo Carvalho de Melo return fprintf(fp, "%s", sbuild_id); 3699e03eb2dSArnaldo Carvalho de Melo } 3709e03eb2dSArnaldo Carvalho de Melo 37195011c60SArnaldo Carvalho de Melo size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp) 3729e03eb2dSArnaldo Carvalho de Melo { 3739e03eb2dSArnaldo Carvalho de Melo struct rb_node *nd; 3749e03eb2dSArnaldo Carvalho de Melo size_t ret = fprintf(fp, "dso: %s (", self->short_name); 3759e03eb2dSArnaldo Carvalho de Melo 3763846df2eSArnaldo Carvalho de Melo if (self->short_name != self->long_name) 3773846df2eSArnaldo Carvalho de Melo ret += fprintf(fp, "%s, ", self->long_name); 3783846df2eSArnaldo Carvalho de Melo ret += fprintf(fp, "%s, %sloaded, ", map_type__name[type], 3793846df2eSArnaldo Carvalho de Melo self->loaded ? "" : "NOT "); 3809e03eb2dSArnaldo Carvalho de Melo ret += dso__fprintf_buildid(self, fp); 3816a4694a4SArnaldo Carvalho de Melo ret += fprintf(fp, ")\n"); 38295011c60SArnaldo Carvalho de Melo for (nd = rb_first(&self->symbols[type]); nd; nd = rb_next(nd)) { 38386470930SIngo Molnar struct symbol *pos = rb_entry(nd, struct symbol, rb_node); 38486470930SIngo Molnar ret += symbol__fprintf(pos, fp); 38586470930SIngo Molnar } 38686470930SIngo Molnar 38786470930SIngo Molnar return ret; 38886470930SIngo Molnar } 38986470930SIngo Molnar 3909e201442SArnaldo Carvalho de Melo int kallsyms__parse(const char *filename, void *arg, 3919e201442SArnaldo Carvalho de Melo int (*process_symbol)(void *arg, const char *name, 392682b335aSArnaldo Carvalho de Melo char type, u64 start)) 39386470930SIngo Molnar { 39486470930SIngo Molnar char *line = NULL; 39586470930SIngo Molnar size_t n; 396682b335aSArnaldo Carvalho de Melo int err = 0; 3979e201442SArnaldo Carvalho de Melo FILE *file = fopen(filename, "r"); 39886470930SIngo Molnar 39986470930SIngo Molnar if (file == NULL) 40086470930SIngo Molnar goto out_failure; 40186470930SIngo Molnar 40286470930SIngo Molnar while (!feof(file)) { 4039cffa8d5SPaul Mackerras u64 start; 40486470930SIngo Molnar int line_len, len; 40586470930SIngo Molnar char symbol_type; 4062e538c4aSArnaldo Carvalho de Melo char *symbol_name; 40786470930SIngo Molnar 40886470930SIngo Molnar line_len = getline(&line, &n, file); 409a1645ce1SZhang, Yanmin if (line_len < 0 || !line) 41086470930SIngo Molnar break; 41186470930SIngo Molnar 41286470930SIngo Molnar line[--line_len] = '\0'; /* \n */ 41386470930SIngo Molnar 41486470930SIngo Molnar len = hex2u64(line, &start); 41586470930SIngo Molnar 41686470930SIngo Molnar len++; 41786470930SIngo Molnar if (len + 2 >= line_len) 41886470930SIngo Molnar continue; 41986470930SIngo Molnar 42086470930SIngo Molnar symbol_type = toupper(line[len]); 421af427bf5SArnaldo Carvalho de Melo symbol_name = line + len + 2; 422682b335aSArnaldo Carvalho de Melo 423682b335aSArnaldo Carvalho de Melo err = process_symbol(arg, symbol_name, symbol_type, start); 424682b335aSArnaldo Carvalho de Melo if (err) 425682b335aSArnaldo Carvalho de Melo break; 426682b335aSArnaldo Carvalho de Melo } 427682b335aSArnaldo Carvalho de Melo 428682b335aSArnaldo Carvalho de Melo free(line); 429682b335aSArnaldo Carvalho de Melo fclose(file); 430682b335aSArnaldo Carvalho de Melo return err; 431682b335aSArnaldo Carvalho de Melo 432682b335aSArnaldo Carvalho de Melo out_failure: 433682b335aSArnaldo Carvalho de Melo return -1; 434682b335aSArnaldo Carvalho de Melo } 435682b335aSArnaldo Carvalho de Melo 436682b335aSArnaldo Carvalho de Melo struct process_kallsyms_args { 437682b335aSArnaldo Carvalho de Melo struct map *map; 438682b335aSArnaldo Carvalho de Melo struct dso *dso; 439682b335aSArnaldo Carvalho de Melo }; 440682b335aSArnaldo Carvalho de Melo 441682b335aSArnaldo Carvalho de Melo static int map__process_kallsym_symbol(void *arg, const char *name, 442682b335aSArnaldo Carvalho de Melo char type, u64 start) 443682b335aSArnaldo Carvalho de Melo { 444682b335aSArnaldo Carvalho de Melo struct symbol *sym; 445682b335aSArnaldo Carvalho de Melo struct process_kallsyms_args *a = arg; 446682b335aSArnaldo Carvalho de Melo struct rb_root *root = &a->dso->symbols[a->map->type]; 447682b335aSArnaldo Carvalho de Melo 448682b335aSArnaldo Carvalho de Melo if (!symbol_type__is_a(type, a->map->type)) 449682b335aSArnaldo Carvalho de Melo return 0; 450682b335aSArnaldo Carvalho de Melo 4512e538c4aSArnaldo Carvalho de Melo /* 4522e538c4aSArnaldo Carvalho de Melo * Will fix up the end later, when we have all symbols sorted. 4532e538c4aSArnaldo Carvalho de Melo */ 454682b335aSArnaldo Carvalho de Melo sym = symbol__new(start, 0, name); 455af427bf5SArnaldo Carvalho de Melo 4562e538c4aSArnaldo Carvalho de Melo if (sym == NULL) 457682b335aSArnaldo Carvalho de Melo return -ENOMEM; 45882164161SArnaldo Carvalho de Melo /* 45982164161SArnaldo Carvalho de Melo * We will pass the symbols to the filter later, in 4604e06255fSArnaldo Carvalho de Melo * map__split_kallsyms, when we have split the maps per module 46182164161SArnaldo Carvalho de Melo */ 4624e06255fSArnaldo Carvalho de Melo symbols__insert(root, sym); 463a1645ce1SZhang, Yanmin 464682b335aSArnaldo Carvalho de Melo return 0; 4652e538c4aSArnaldo Carvalho de Melo } 4662e538c4aSArnaldo Carvalho de Melo 467682b335aSArnaldo Carvalho de Melo /* 468682b335aSArnaldo Carvalho de Melo * Loads the function entries in /proc/kallsyms into kernel_map->dso, 469682b335aSArnaldo Carvalho de Melo * so that we can in the next step set the symbol ->end address and then 470682b335aSArnaldo Carvalho de Melo * call kernel_maps__split_kallsyms. 471682b335aSArnaldo Carvalho de Melo */ 4729e201442SArnaldo Carvalho de Melo static int dso__load_all_kallsyms(struct dso *self, const char *filename, 4739e201442SArnaldo Carvalho de Melo struct map *map) 474682b335aSArnaldo Carvalho de Melo { 475682b335aSArnaldo Carvalho de Melo struct process_kallsyms_args args = { .map = map, .dso = self, }; 4769e201442SArnaldo Carvalho de Melo return kallsyms__parse(filename, &args, map__process_kallsym_symbol); 4772e538c4aSArnaldo Carvalho de Melo } 4782e538c4aSArnaldo Carvalho de Melo 4792e538c4aSArnaldo Carvalho de Melo /* 4802e538c4aSArnaldo Carvalho de Melo * Split the symbols into maps, making sure there are no overlaps, i.e. the 4812e538c4aSArnaldo Carvalho de Melo * kernel range is broken in several maps, named [kernel].N, as we don't have 4822e538c4aSArnaldo Carvalho de Melo * the original ELF section names vmlinux have. 4832e538c4aSArnaldo Carvalho de Melo */ 4849958e1f0SArnaldo Carvalho de Melo static int dso__split_kallsyms(struct dso *self, struct map *map, 4859de89fe7SArnaldo Carvalho de Melo symbol_filter_t filter) 4862e538c4aSArnaldo Carvalho de Melo { 4879de89fe7SArnaldo Carvalho de Melo struct map_groups *kmaps = map__kmap(map)->kmaps; 488a1645ce1SZhang, Yanmin struct kernel_info *kerninfo = kmaps->this_kerninfo; 4894e06255fSArnaldo Carvalho de Melo struct map *curr_map = map; 4902e538c4aSArnaldo Carvalho de Melo struct symbol *pos; 4912e538c4aSArnaldo Carvalho de Melo int count = 0; 4924e06255fSArnaldo Carvalho de Melo struct rb_root *root = &self->symbols[map->type]; 4934e06255fSArnaldo Carvalho de Melo struct rb_node *next = rb_first(root); 4942e538c4aSArnaldo Carvalho de Melo int kernel_range = 0; 4952e538c4aSArnaldo Carvalho de Melo 4962e538c4aSArnaldo Carvalho de Melo while (next) { 4972e538c4aSArnaldo Carvalho de Melo char *module; 4982e538c4aSArnaldo Carvalho de Melo 4992e538c4aSArnaldo Carvalho de Melo pos = rb_entry(next, struct symbol, rb_node); 5002e538c4aSArnaldo Carvalho de Melo next = rb_next(&pos->rb_node); 5012e538c4aSArnaldo Carvalho de Melo 5022e538c4aSArnaldo Carvalho de Melo module = strchr(pos->name, '\t'); 5032e538c4aSArnaldo Carvalho de Melo if (module) { 50475be6cf4SArnaldo Carvalho de Melo if (!symbol_conf.use_modules) 5051de8e245SArnaldo Carvalho de Melo goto discard_symbol; 5061de8e245SArnaldo Carvalho de Melo 5072e538c4aSArnaldo Carvalho de Melo *module++ = '\0'; 5082e538c4aSArnaldo Carvalho de Melo 509b7cece76SArnaldo Carvalho de Melo if (strcmp(curr_map->dso->short_name, module)) { 510a1645ce1SZhang, Yanmin if (curr_map != map && 511a1645ce1SZhang, Yanmin self->kernel == DSO_TYPE_GUEST_KERNEL && 512a1645ce1SZhang, Yanmin is_default_guest(kerninfo)) { 513a1645ce1SZhang, Yanmin /* 514a1645ce1SZhang, Yanmin * We assume all symbols of a module are 515a1645ce1SZhang, Yanmin * continuous in * kallsyms, so curr_map 516a1645ce1SZhang, Yanmin * points to a module and all its 517a1645ce1SZhang, Yanmin * symbols are in its kmap. Mark it as 518a1645ce1SZhang, Yanmin * loaded. 519a1645ce1SZhang, Yanmin */ 520a1645ce1SZhang, Yanmin dso__set_loaded(curr_map->dso, 521a1645ce1SZhang, Yanmin curr_map->type); 522af427bf5SArnaldo Carvalho de Melo } 523b7cece76SArnaldo Carvalho de Melo 524a1645ce1SZhang, Yanmin curr_map = map_groups__find_by_name(kmaps, 525a1645ce1SZhang, Yanmin map->type, module); 526a1645ce1SZhang, Yanmin if (curr_map == NULL) { 527a1645ce1SZhang, Yanmin pr_err("%s/proc/{kallsyms,modules} " 528a1645ce1SZhang, Yanmin "inconsistency while looking " 529a1645ce1SZhang, Yanmin "for \"%s\" module!\n", 530a1645ce1SZhang, Yanmin kerninfo->root_dir, module); 531a1645ce1SZhang, Yanmin curr_map = map; 532a1645ce1SZhang, Yanmin goto discard_symbol; 533a1645ce1SZhang, Yanmin } 534a1645ce1SZhang, Yanmin 535a1645ce1SZhang, Yanmin if (curr_map->dso->loaded && 536a1645ce1SZhang, Yanmin !is_default_guest(kmaps->this_kerninfo)) 537b7cece76SArnaldo Carvalho de Melo goto discard_symbol; 538af427bf5SArnaldo Carvalho de Melo } 53986470930SIngo Molnar /* 5402e538c4aSArnaldo Carvalho de Melo * So that we look just like we get from .ko files, 5412e538c4aSArnaldo Carvalho de Melo * i.e. not prelinked, relative to map->start. 54286470930SIngo Molnar */ 5434e06255fSArnaldo Carvalho de Melo pos->start = curr_map->map_ip(curr_map, pos->start); 5444e06255fSArnaldo Carvalho de Melo pos->end = curr_map->map_ip(curr_map, pos->end); 5454e06255fSArnaldo Carvalho de Melo } else if (curr_map != map) { 5462e538c4aSArnaldo Carvalho de Melo char dso_name[PATH_MAX]; 5472e538c4aSArnaldo Carvalho de Melo struct dso *dso; 54886470930SIngo Molnar 549a1645ce1SZhang, Yanmin if (self->kernel == DSO_TYPE_GUEST_KERNEL) 550a1645ce1SZhang, Yanmin snprintf(dso_name, sizeof(dso_name), 551a1645ce1SZhang, Yanmin "[guest.kernel].%d", 552a1645ce1SZhang, Yanmin kernel_range++); 553a1645ce1SZhang, Yanmin else 554a1645ce1SZhang, Yanmin snprintf(dso_name, sizeof(dso_name), 555a1645ce1SZhang, Yanmin "[kernel].%d", 5562e538c4aSArnaldo Carvalho de Melo kernel_range++); 55786470930SIngo Molnar 55800a192b3SArnaldo Carvalho de Melo dso = dso__new(dso_name); 5592e538c4aSArnaldo Carvalho de Melo if (dso == NULL) 5602e538c4aSArnaldo Carvalho de Melo return -1; 5612e538c4aSArnaldo Carvalho de Melo 562a1645ce1SZhang, Yanmin dso->kernel = self->kernel; 563a1645ce1SZhang, Yanmin 5644e06255fSArnaldo Carvalho de Melo curr_map = map__new2(pos->start, dso, map->type); 56537fe5fcbSZhang, Yanmin if (curr_map == NULL) { 5662e538c4aSArnaldo Carvalho de Melo dso__delete(dso); 5672e538c4aSArnaldo Carvalho de Melo return -1; 5682e538c4aSArnaldo Carvalho de Melo } 5692e538c4aSArnaldo Carvalho de Melo 5704e06255fSArnaldo Carvalho de Melo curr_map->map_ip = curr_map->unmap_ip = identity__map_ip; 5719de89fe7SArnaldo Carvalho de Melo map_groups__insert(kmaps, curr_map); 5722e538c4aSArnaldo Carvalho de Melo ++kernel_range; 5732e538c4aSArnaldo Carvalho de Melo } 5742e538c4aSArnaldo Carvalho de Melo 5754e06255fSArnaldo Carvalho de Melo if (filter && filter(curr_map, pos)) { 5761de8e245SArnaldo Carvalho de Melo discard_symbol: rb_erase(&pos->rb_node, root); 57700a192b3SArnaldo Carvalho de Melo symbol__delete(pos); 5782e538c4aSArnaldo Carvalho de Melo } else { 5794e06255fSArnaldo Carvalho de Melo if (curr_map != map) { 5804e06255fSArnaldo Carvalho de Melo rb_erase(&pos->rb_node, root); 5814e06255fSArnaldo Carvalho de Melo symbols__insert(&curr_map->dso->symbols[curr_map->type], pos); 5822e538c4aSArnaldo Carvalho de Melo } 5839974f496SMike Galbraith count++; 5849974f496SMike Galbraith } 58586470930SIngo Molnar } 58686470930SIngo Molnar 587a1645ce1SZhang, Yanmin if (curr_map != map && 588a1645ce1SZhang, Yanmin self->kernel == DSO_TYPE_GUEST_KERNEL && 589a1645ce1SZhang, Yanmin is_default_guest(kmaps->this_kerninfo)) { 590a1645ce1SZhang, Yanmin dso__set_loaded(curr_map->dso, curr_map->type); 591a1645ce1SZhang, Yanmin } 592a1645ce1SZhang, Yanmin 5939974f496SMike Galbraith return count; 59486470930SIngo Molnar } 59586470930SIngo Molnar 5969de89fe7SArnaldo Carvalho de Melo int dso__load_kallsyms(struct dso *self, const char *filename, 5979de89fe7SArnaldo Carvalho de Melo struct map *map, symbol_filter_t filter) 5982e538c4aSArnaldo Carvalho de Melo { 5999e201442SArnaldo Carvalho de Melo if (dso__load_all_kallsyms(self, filename, map) < 0) 6002e538c4aSArnaldo Carvalho de Melo return -1; 6012e538c4aSArnaldo Carvalho de Melo 6024e06255fSArnaldo Carvalho de Melo symbols__fixup_end(&self->symbols[map->type]); 603a1645ce1SZhang, Yanmin if (self->kernel == DSO_TYPE_GUEST_KERNEL) 604a1645ce1SZhang, Yanmin self->origin = DSO__ORIG_GUEST_KERNEL; 605a1645ce1SZhang, Yanmin else 6064e06255fSArnaldo Carvalho de Melo self->origin = DSO__ORIG_KERNEL; 6072e538c4aSArnaldo Carvalho de Melo 6089de89fe7SArnaldo Carvalho de Melo return dso__split_kallsyms(self, map, filter); 609af427bf5SArnaldo Carvalho de Melo } 610af427bf5SArnaldo Carvalho de Melo 611439d473bSArnaldo Carvalho de Melo static int dso__load_perf_map(struct dso *self, struct map *map, 6126beba7adSArnaldo Carvalho de Melo symbol_filter_t filter) 61380d496beSPekka Enberg { 61480d496beSPekka Enberg char *line = NULL; 61580d496beSPekka Enberg size_t n; 61680d496beSPekka Enberg FILE *file; 61780d496beSPekka Enberg int nr_syms = 0; 61880d496beSPekka Enberg 619439d473bSArnaldo Carvalho de Melo file = fopen(self->long_name, "r"); 62080d496beSPekka Enberg if (file == NULL) 62180d496beSPekka Enberg goto out_failure; 62280d496beSPekka Enberg 62380d496beSPekka Enberg while (!feof(file)) { 6249cffa8d5SPaul Mackerras u64 start, size; 62580d496beSPekka Enberg struct symbol *sym; 62680d496beSPekka Enberg int line_len, len; 62780d496beSPekka Enberg 62880d496beSPekka Enberg line_len = getline(&line, &n, file); 62980d496beSPekka Enberg if (line_len < 0) 63080d496beSPekka Enberg break; 63180d496beSPekka Enberg 63280d496beSPekka Enberg if (!line) 63380d496beSPekka Enberg goto out_failure; 63480d496beSPekka Enberg 63580d496beSPekka Enberg line[--line_len] = '\0'; /* \n */ 63680d496beSPekka Enberg 63780d496beSPekka Enberg len = hex2u64(line, &start); 63880d496beSPekka Enberg 63980d496beSPekka Enberg len++; 64080d496beSPekka Enberg if (len + 2 >= line_len) 64180d496beSPekka Enberg continue; 64280d496beSPekka Enberg 64380d496beSPekka Enberg len += hex2u64(line + len, &size); 64480d496beSPekka Enberg 64580d496beSPekka Enberg len++; 64680d496beSPekka Enberg if (len + 2 >= line_len) 64780d496beSPekka Enberg continue; 64880d496beSPekka Enberg 64900a192b3SArnaldo Carvalho de Melo sym = symbol__new(start, size, line + len); 65080d496beSPekka Enberg 65180d496beSPekka Enberg if (sym == NULL) 65280d496beSPekka Enberg goto out_delete_line; 65380d496beSPekka Enberg 654439d473bSArnaldo Carvalho de Melo if (filter && filter(map, sym)) 65500a192b3SArnaldo Carvalho de Melo symbol__delete(sym); 65680d496beSPekka Enberg else { 6576a4694a4SArnaldo Carvalho de Melo symbols__insert(&self->symbols[map->type], sym); 65880d496beSPekka Enberg nr_syms++; 65980d496beSPekka Enberg } 66080d496beSPekka Enberg } 66180d496beSPekka Enberg 66280d496beSPekka Enberg free(line); 66380d496beSPekka Enberg fclose(file); 66480d496beSPekka Enberg 66580d496beSPekka Enberg return nr_syms; 66680d496beSPekka Enberg 66780d496beSPekka Enberg out_delete_line: 66880d496beSPekka Enberg free(line); 66980d496beSPekka Enberg out_failure: 67080d496beSPekka Enberg return -1; 67180d496beSPekka Enberg } 67280d496beSPekka Enberg 67386470930SIngo Molnar /** 67486470930SIngo Molnar * elf_symtab__for_each_symbol - iterate thru all the symbols 67586470930SIngo Molnar * 67686470930SIngo Molnar * @self: struct elf_symtab instance to iterate 67783a0944fSIngo Molnar * @idx: uint32_t idx 67886470930SIngo Molnar * @sym: GElf_Sym iterator 67986470930SIngo Molnar */ 68083a0944fSIngo Molnar #define elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) \ 68183a0944fSIngo Molnar for (idx = 0, gelf_getsym(syms, idx, &sym);\ 68283a0944fSIngo Molnar idx < nr_syms; \ 68383a0944fSIngo Molnar idx++, gelf_getsym(syms, idx, &sym)) 68486470930SIngo Molnar 68586470930SIngo Molnar static inline uint8_t elf_sym__type(const GElf_Sym *sym) 68686470930SIngo Molnar { 68786470930SIngo Molnar return GELF_ST_TYPE(sym->st_info); 68886470930SIngo Molnar } 68986470930SIngo Molnar 69086470930SIngo Molnar static inline int elf_sym__is_function(const GElf_Sym *sym) 69186470930SIngo Molnar { 69286470930SIngo Molnar return elf_sym__type(sym) == STT_FUNC && 69386470930SIngo Molnar sym->st_name != 0 && 69481833130SArnaldo Carvalho de Melo sym->st_shndx != SHN_UNDEF; 69586470930SIngo Molnar } 69686470930SIngo Molnar 697f1dfa0b1SArnaldo Carvalho de Melo static inline bool elf_sym__is_object(const GElf_Sym *sym) 698f1dfa0b1SArnaldo Carvalho de Melo { 699f1dfa0b1SArnaldo Carvalho de Melo return elf_sym__type(sym) == STT_OBJECT && 700f1dfa0b1SArnaldo Carvalho de Melo sym->st_name != 0 && 701f1dfa0b1SArnaldo Carvalho de Melo sym->st_shndx != SHN_UNDEF; 702f1dfa0b1SArnaldo Carvalho de Melo } 703f1dfa0b1SArnaldo Carvalho de Melo 7046cfcc53eSMike Galbraith static inline int elf_sym__is_label(const GElf_Sym *sym) 7056cfcc53eSMike Galbraith { 7066cfcc53eSMike Galbraith return elf_sym__type(sym) == STT_NOTYPE && 7076cfcc53eSMike Galbraith sym->st_name != 0 && 7086cfcc53eSMike Galbraith sym->st_shndx != SHN_UNDEF && 7096cfcc53eSMike Galbraith sym->st_shndx != SHN_ABS; 7106cfcc53eSMike Galbraith } 7116cfcc53eSMike Galbraith 7126cfcc53eSMike Galbraith static inline const char *elf_sec__name(const GElf_Shdr *shdr, 7136cfcc53eSMike Galbraith const Elf_Data *secstrs) 7146cfcc53eSMike Galbraith { 7156cfcc53eSMike Galbraith return secstrs->d_buf + shdr->sh_name; 7166cfcc53eSMike Galbraith } 7176cfcc53eSMike Galbraith 7186cfcc53eSMike Galbraith static inline int elf_sec__is_text(const GElf_Shdr *shdr, 7196cfcc53eSMike Galbraith const Elf_Data *secstrs) 7206cfcc53eSMike Galbraith { 7216cfcc53eSMike Galbraith return strstr(elf_sec__name(shdr, secstrs), "text") != NULL; 7226cfcc53eSMike Galbraith } 7236cfcc53eSMike Galbraith 724f1dfa0b1SArnaldo Carvalho de Melo static inline bool elf_sec__is_data(const GElf_Shdr *shdr, 725f1dfa0b1SArnaldo Carvalho de Melo const Elf_Data *secstrs) 726f1dfa0b1SArnaldo Carvalho de Melo { 727f1dfa0b1SArnaldo Carvalho de Melo return strstr(elf_sec__name(shdr, secstrs), "data") != NULL; 728f1dfa0b1SArnaldo Carvalho de Melo } 729f1dfa0b1SArnaldo Carvalho de Melo 73086470930SIngo Molnar static inline const char *elf_sym__name(const GElf_Sym *sym, 73186470930SIngo Molnar const Elf_Data *symstrs) 73286470930SIngo Molnar { 73386470930SIngo Molnar return symstrs->d_buf + sym->st_name; 73486470930SIngo Molnar } 73586470930SIngo Molnar 73686470930SIngo Molnar static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, 73786470930SIngo Molnar GElf_Shdr *shp, const char *name, 73883a0944fSIngo Molnar size_t *idx) 73986470930SIngo Molnar { 74086470930SIngo Molnar Elf_Scn *sec = NULL; 74186470930SIngo Molnar size_t cnt = 1; 74286470930SIngo Molnar 74386470930SIngo Molnar while ((sec = elf_nextscn(elf, sec)) != NULL) { 74486470930SIngo Molnar char *str; 74586470930SIngo Molnar 74686470930SIngo Molnar gelf_getshdr(sec, shp); 74786470930SIngo Molnar str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name); 74886470930SIngo Molnar if (!strcmp(name, str)) { 74983a0944fSIngo Molnar if (idx) 75083a0944fSIngo Molnar *idx = cnt; 75186470930SIngo Molnar break; 75286470930SIngo Molnar } 75386470930SIngo Molnar ++cnt; 75486470930SIngo Molnar } 75586470930SIngo Molnar 75686470930SIngo Molnar return sec; 75786470930SIngo Molnar } 75886470930SIngo Molnar 75986470930SIngo Molnar #define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \ 76086470930SIngo Molnar for (idx = 0, pos = gelf_getrel(reldata, 0, &pos_mem); \ 76186470930SIngo Molnar idx < nr_entries; \ 76286470930SIngo Molnar ++idx, pos = gelf_getrel(reldata, idx, &pos_mem)) 76386470930SIngo Molnar 76486470930SIngo Molnar #define elf_section__for_each_rela(reldata, pos, pos_mem, idx, nr_entries) \ 76586470930SIngo Molnar for (idx = 0, pos = gelf_getrela(reldata, 0, &pos_mem); \ 76686470930SIngo Molnar idx < nr_entries; \ 76786470930SIngo Molnar ++idx, pos = gelf_getrela(reldata, idx, &pos_mem)) 76886470930SIngo Molnar 769a25e46c4SArnaldo Carvalho de Melo /* 770a25e46c4SArnaldo Carvalho de Melo * We need to check if we have a .dynsym, so that we can handle the 771a25e46c4SArnaldo Carvalho de Melo * .plt, synthesizing its symbols, that aren't on the symtabs (be it 772a25e46c4SArnaldo Carvalho de Melo * .dynsym or .symtab). 773a25e46c4SArnaldo Carvalho de Melo * And always look at the original dso, not at debuginfo packages, that 774a25e46c4SArnaldo Carvalho de Melo * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS). 775a25e46c4SArnaldo Carvalho de Melo */ 77682164161SArnaldo Carvalho de Melo static int dso__synthesize_plt_symbols(struct dso *self, struct map *map, 77782164161SArnaldo Carvalho de Melo symbol_filter_t filter) 77886470930SIngo Molnar { 77986470930SIngo Molnar uint32_t nr_rel_entries, idx; 78086470930SIngo Molnar GElf_Sym sym; 7819cffa8d5SPaul Mackerras u64 plt_offset; 78286470930SIngo Molnar GElf_Shdr shdr_plt; 78386470930SIngo Molnar struct symbol *f; 784a25e46c4SArnaldo Carvalho de Melo GElf_Shdr shdr_rel_plt, shdr_dynsym; 78586470930SIngo Molnar Elf_Data *reldata, *syms, *symstrs; 786a25e46c4SArnaldo Carvalho de Melo Elf_Scn *scn_plt_rel, *scn_symstrs, *scn_dynsym; 787a25e46c4SArnaldo Carvalho de Melo size_t dynsym_idx; 788a25e46c4SArnaldo Carvalho de Melo GElf_Ehdr ehdr; 78986470930SIngo Molnar char sympltname[1024]; 790a25e46c4SArnaldo Carvalho de Melo Elf *elf; 791a25e46c4SArnaldo Carvalho de Melo int nr = 0, symidx, fd, err = 0; 79286470930SIngo Molnar 793439d473bSArnaldo Carvalho de Melo fd = open(self->long_name, O_RDONLY); 794a25e46c4SArnaldo Carvalho de Melo if (fd < 0) 795a25e46c4SArnaldo Carvalho de Melo goto out; 796a25e46c4SArnaldo Carvalho de Melo 79784087126SMarti Raudsepp elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 798a25e46c4SArnaldo Carvalho de Melo if (elf == NULL) 799a25e46c4SArnaldo Carvalho de Melo goto out_close; 800a25e46c4SArnaldo Carvalho de Melo 801a25e46c4SArnaldo Carvalho de Melo if (gelf_getehdr(elf, &ehdr) == NULL) 802a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 803a25e46c4SArnaldo Carvalho de Melo 804a25e46c4SArnaldo Carvalho de Melo scn_dynsym = elf_section_by_name(elf, &ehdr, &shdr_dynsym, 805a25e46c4SArnaldo Carvalho de Melo ".dynsym", &dynsym_idx); 806a25e46c4SArnaldo Carvalho de Melo if (scn_dynsym == NULL) 807a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 808a25e46c4SArnaldo Carvalho de Melo 809a25e46c4SArnaldo Carvalho de Melo scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt, 81086470930SIngo Molnar ".rela.plt", NULL); 81186470930SIngo Molnar if (scn_plt_rel == NULL) { 812a25e46c4SArnaldo Carvalho de Melo scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt, 81386470930SIngo Molnar ".rel.plt", NULL); 81486470930SIngo Molnar if (scn_plt_rel == NULL) 815a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 81686470930SIngo Molnar } 81786470930SIngo Molnar 818a25e46c4SArnaldo Carvalho de Melo err = -1; 81986470930SIngo Molnar 820a25e46c4SArnaldo Carvalho de Melo if (shdr_rel_plt.sh_link != dynsym_idx) 821a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 822a25e46c4SArnaldo Carvalho de Melo 823a25e46c4SArnaldo Carvalho de Melo if (elf_section_by_name(elf, &ehdr, &shdr_plt, ".plt", NULL) == NULL) 824a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 82586470930SIngo Molnar 82686470930SIngo Molnar /* 82783a0944fSIngo Molnar * Fetch the relocation section to find the idxes to the GOT 82886470930SIngo Molnar * and the symbols in the .dynsym they refer to. 82986470930SIngo Molnar */ 83086470930SIngo Molnar reldata = elf_getdata(scn_plt_rel, NULL); 83186470930SIngo Molnar if (reldata == NULL) 832a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 83386470930SIngo Molnar 83486470930SIngo Molnar syms = elf_getdata(scn_dynsym, NULL); 83586470930SIngo Molnar if (syms == NULL) 836a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 83786470930SIngo Molnar 838a25e46c4SArnaldo Carvalho de Melo scn_symstrs = elf_getscn(elf, shdr_dynsym.sh_link); 83986470930SIngo Molnar if (scn_symstrs == NULL) 840a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 84186470930SIngo Molnar 84286470930SIngo Molnar symstrs = elf_getdata(scn_symstrs, NULL); 84386470930SIngo Molnar if (symstrs == NULL) 844a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 84586470930SIngo Molnar 84686470930SIngo Molnar nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize; 84786470930SIngo Molnar plt_offset = shdr_plt.sh_offset; 84886470930SIngo Molnar 84986470930SIngo Molnar if (shdr_rel_plt.sh_type == SHT_RELA) { 85086470930SIngo Molnar GElf_Rela pos_mem, *pos; 85186470930SIngo Molnar 85286470930SIngo Molnar elf_section__for_each_rela(reldata, pos, pos_mem, idx, 85386470930SIngo Molnar nr_rel_entries) { 85486470930SIngo Molnar symidx = GELF_R_SYM(pos->r_info); 85586470930SIngo Molnar plt_offset += shdr_plt.sh_entsize; 85686470930SIngo Molnar gelf_getsym(syms, symidx, &sym); 85786470930SIngo Molnar snprintf(sympltname, sizeof(sympltname), 85886470930SIngo Molnar "%s@plt", elf_sym__name(&sym, symstrs)); 85986470930SIngo Molnar 86086470930SIngo Molnar f = symbol__new(plt_offset, shdr_plt.sh_entsize, 86100a192b3SArnaldo Carvalho de Melo sympltname); 86286470930SIngo Molnar if (!f) 863a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 86486470930SIngo Molnar 86582164161SArnaldo Carvalho de Melo if (filter && filter(map, f)) 86682164161SArnaldo Carvalho de Melo symbol__delete(f); 86782164161SArnaldo Carvalho de Melo else { 8686a4694a4SArnaldo Carvalho de Melo symbols__insert(&self->symbols[map->type], f); 86986470930SIngo Molnar ++nr; 87086470930SIngo Molnar } 87182164161SArnaldo Carvalho de Melo } 87286470930SIngo Molnar } else if (shdr_rel_plt.sh_type == SHT_REL) { 87386470930SIngo Molnar GElf_Rel pos_mem, *pos; 87486470930SIngo Molnar elf_section__for_each_rel(reldata, pos, pos_mem, idx, 87586470930SIngo Molnar nr_rel_entries) { 87686470930SIngo Molnar symidx = GELF_R_SYM(pos->r_info); 87786470930SIngo Molnar plt_offset += shdr_plt.sh_entsize; 87886470930SIngo Molnar gelf_getsym(syms, symidx, &sym); 87986470930SIngo Molnar snprintf(sympltname, sizeof(sympltname), 88086470930SIngo Molnar "%s@plt", elf_sym__name(&sym, symstrs)); 88186470930SIngo Molnar 88286470930SIngo Molnar f = symbol__new(plt_offset, shdr_plt.sh_entsize, 88300a192b3SArnaldo Carvalho de Melo sympltname); 88486470930SIngo Molnar if (!f) 885a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 88686470930SIngo Molnar 88782164161SArnaldo Carvalho de Melo if (filter && filter(map, f)) 88882164161SArnaldo Carvalho de Melo symbol__delete(f); 88982164161SArnaldo Carvalho de Melo else { 8906a4694a4SArnaldo Carvalho de Melo symbols__insert(&self->symbols[map->type], f); 89186470930SIngo Molnar ++nr; 89286470930SIngo Molnar } 89386470930SIngo Molnar } 89482164161SArnaldo Carvalho de Melo } 89586470930SIngo Molnar 896a25e46c4SArnaldo Carvalho de Melo err = 0; 897a25e46c4SArnaldo Carvalho de Melo out_elf_end: 898a25e46c4SArnaldo Carvalho de Melo elf_end(elf); 899a25e46c4SArnaldo Carvalho de Melo out_close: 900a25e46c4SArnaldo Carvalho de Melo close(fd); 901a25e46c4SArnaldo Carvalho de Melo 902a25e46c4SArnaldo Carvalho de Melo if (err == 0) 90386470930SIngo Molnar return nr; 904a25e46c4SArnaldo Carvalho de Melo out: 905fe2197b8SArnaldo Carvalho de Melo pr_debug("%s: problems reading %s PLT info.\n", 906439d473bSArnaldo Carvalho de Melo __func__, self->long_name); 907a25e46c4SArnaldo Carvalho de Melo return 0; 90886470930SIngo Molnar } 90986470930SIngo Molnar 910d45868d3SArnaldo Carvalho de Melo static bool elf_sym__is_a(GElf_Sym *self, enum map_type type) 911d45868d3SArnaldo Carvalho de Melo { 912d45868d3SArnaldo Carvalho de Melo switch (type) { 913d45868d3SArnaldo Carvalho de Melo case MAP__FUNCTION: 914d45868d3SArnaldo Carvalho de Melo return elf_sym__is_function(self); 915f1dfa0b1SArnaldo Carvalho de Melo case MAP__VARIABLE: 916f1dfa0b1SArnaldo Carvalho de Melo return elf_sym__is_object(self); 917d45868d3SArnaldo Carvalho de Melo default: 918d45868d3SArnaldo Carvalho de Melo return false; 919d45868d3SArnaldo Carvalho de Melo } 920d45868d3SArnaldo Carvalho de Melo } 921d45868d3SArnaldo Carvalho de Melo 922d45868d3SArnaldo Carvalho de Melo static bool elf_sec__is_a(GElf_Shdr *self, Elf_Data *secstrs, enum map_type type) 923d45868d3SArnaldo Carvalho de Melo { 924d45868d3SArnaldo Carvalho de Melo switch (type) { 925d45868d3SArnaldo Carvalho de Melo case MAP__FUNCTION: 926d45868d3SArnaldo Carvalho de Melo return elf_sec__is_text(self, secstrs); 927f1dfa0b1SArnaldo Carvalho de Melo case MAP__VARIABLE: 928f1dfa0b1SArnaldo Carvalho de Melo return elf_sec__is_data(self, secstrs); 929d45868d3SArnaldo Carvalho de Melo default: 930d45868d3SArnaldo Carvalho de Melo return false; 931d45868d3SArnaldo Carvalho de Melo } 932d45868d3SArnaldo Carvalho de Melo } 933d45868d3SArnaldo Carvalho de Melo 9349de89fe7SArnaldo Carvalho de Melo static int dso__load_sym(struct dso *self, struct map *map, const char *name, 9359de89fe7SArnaldo Carvalho de Melo int fd, symbol_filter_t filter, int kmodule) 93686470930SIngo Molnar { 9379de89fe7SArnaldo Carvalho de Melo struct kmap *kmap = self->kernel ? map__kmap(map) : NULL; 9382e538c4aSArnaldo Carvalho de Melo struct map *curr_map = map; 9392e538c4aSArnaldo Carvalho de Melo struct dso *curr_dso = self; 9406cfcc53eSMike Galbraith Elf_Data *symstrs, *secstrs; 94186470930SIngo Molnar uint32_t nr_syms; 94286470930SIngo Molnar int err = -1; 94383a0944fSIngo Molnar uint32_t idx; 94486470930SIngo Molnar GElf_Ehdr ehdr; 94586470930SIngo Molnar GElf_Shdr shdr; 94686470930SIngo Molnar Elf_Data *syms; 94786470930SIngo Molnar GElf_Sym sym; 948a25e46c4SArnaldo Carvalho de Melo Elf_Scn *sec, *sec_strndx; 94986470930SIngo Molnar Elf *elf; 950439d473bSArnaldo Carvalho de Melo int nr = 0; 95186470930SIngo Molnar 95284087126SMarti Raudsepp elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 95386470930SIngo Molnar if (elf == NULL) { 9546beba7adSArnaldo Carvalho de Melo pr_err("%s: cannot read %s ELF file.\n", __func__, name); 95586470930SIngo Molnar goto out_close; 95686470930SIngo Molnar } 95786470930SIngo Molnar 95886470930SIngo Molnar if (gelf_getehdr(elf, &ehdr) == NULL) { 9596beba7adSArnaldo Carvalho de Melo pr_err("%s: cannot get elf header.\n", __func__); 96086470930SIngo Molnar goto out_elf_end; 96186470930SIngo Molnar } 96286470930SIngo Molnar 96386470930SIngo Molnar sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL); 96486470930SIngo Molnar if (sec == NULL) { 965a25e46c4SArnaldo Carvalho de Melo sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL); 966a25e46c4SArnaldo Carvalho de Melo if (sec == NULL) 96786470930SIngo Molnar goto out_elf_end; 96886470930SIngo Molnar } 96986470930SIngo Molnar 97086470930SIngo Molnar syms = elf_getdata(sec, NULL); 97186470930SIngo Molnar if (syms == NULL) 97286470930SIngo Molnar goto out_elf_end; 97386470930SIngo Molnar 97486470930SIngo Molnar sec = elf_getscn(elf, shdr.sh_link); 97586470930SIngo Molnar if (sec == NULL) 97686470930SIngo Molnar goto out_elf_end; 97786470930SIngo Molnar 97886470930SIngo Molnar symstrs = elf_getdata(sec, NULL); 97986470930SIngo Molnar if (symstrs == NULL) 98086470930SIngo Molnar goto out_elf_end; 98186470930SIngo Molnar 9826cfcc53eSMike Galbraith sec_strndx = elf_getscn(elf, ehdr.e_shstrndx); 9836cfcc53eSMike Galbraith if (sec_strndx == NULL) 9846cfcc53eSMike Galbraith goto out_elf_end; 9856cfcc53eSMike Galbraith 9866cfcc53eSMike Galbraith secstrs = elf_getdata(sec_strndx, NULL); 9879b30a26bSStoyan Gaydarov if (secstrs == NULL) 9886cfcc53eSMike Galbraith goto out_elf_end; 9896cfcc53eSMike Galbraith 99086470930SIngo Molnar nr_syms = shdr.sh_size / shdr.sh_entsize; 99186470930SIngo Molnar 992e9fbc9dcSArjan van de Ven memset(&sym, 0, sizeof(sym)); 993a1645ce1SZhang, Yanmin if (self->kernel == DSO_TYPE_USER) { 99430d7a77dSArnaldo Carvalho de Melo self->adjust_symbols = (ehdr.e_type == ET_EXEC || 99530d7a77dSArnaldo Carvalho de Melo elf_section_by_name(elf, &ehdr, &shdr, 996f5812a7aSArnaldo Carvalho de Melo ".gnu.prelink_undo", 99730d7a77dSArnaldo Carvalho de Melo NULL) != NULL); 998d20ff6bdSMike Galbraith } else self->adjust_symbols = 0; 999d20ff6bdSMike Galbraith 100083a0944fSIngo Molnar elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) { 100186470930SIngo Molnar struct symbol *f; 100256b03f3cSArnaldo Carvalho de Melo const char *elf_name = elf_sym__name(&sym, symstrs); 10032e538c4aSArnaldo Carvalho de Melo char *demangled = NULL; 10046cfcc53eSMike Galbraith int is_label = elf_sym__is_label(&sym); 10056cfcc53eSMike Galbraith const char *section_name; 100686470930SIngo Molnar 10079de89fe7SArnaldo Carvalho de Melo if (kmap && kmap->ref_reloc_sym && kmap->ref_reloc_sym->name && 10089de89fe7SArnaldo Carvalho de Melo strcmp(elf_name, kmap->ref_reloc_sym->name) == 0) 10099de89fe7SArnaldo Carvalho de Melo kmap->ref_reloc_sym->unrelocated_addr = sym.st_value; 101056b03f3cSArnaldo Carvalho de Melo 1011d45868d3SArnaldo Carvalho de Melo if (!is_label && !elf_sym__is_a(&sym, map->type)) 101286470930SIngo Molnar continue; 101386470930SIngo Molnar 101486470930SIngo Molnar sec = elf_getscn(elf, sym.st_shndx); 101586470930SIngo Molnar if (!sec) 101686470930SIngo Molnar goto out_elf_end; 101786470930SIngo Molnar 101886470930SIngo Molnar gelf_getshdr(sec, &shdr); 10196cfcc53eSMike Galbraith 1020d45868d3SArnaldo Carvalho de Melo if (is_label && !elf_sec__is_a(&shdr, secstrs, map->type)) 10216cfcc53eSMike Galbraith continue; 10226cfcc53eSMike Galbraith 10236cfcc53eSMike Galbraith section_name = elf_sec__name(&shdr, secstrs); 102486470930SIngo Molnar 1025a1645ce1SZhang, Yanmin if (self->kernel != DSO_TYPE_USER || kmodule) { 10262e538c4aSArnaldo Carvalho de Melo char dso_name[PATH_MAX]; 10272e538c4aSArnaldo Carvalho de Melo 10282e538c4aSArnaldo Carvalho de Melo if (strcmp(section_name, 1029b63be8d7SArnaldo Carvalho de Melo (curr_dso->short_name + 1030b63be8d7SArnaldo Carvalho de Melo self->short_name_len)) == 0) 10312e538c4aSArnaldo Carvalho de Melo goto new_symbol; 10322e538c4aSArnaldo Carvalho de Melo 10332e538c4aSArnaldo Carvalho de Melo if (strcmp(section_name, ".text") == 0) { 10342e538c4aSArnaldo Carvalho de Melo curr_map = map; 10352e538c4aSArnaldo Carvalho de Melo curr_dso = self; 10362e538c4aSArnaldo Carvalho de Melo goto new_symbol; 1037af427bf5SArnaldo Carvalho de Melo } 1038af427bf5SArnaldo Carvalho de Melo 10392e538c4aSArnaldo Carvalho de Melo snprintf(dso_name, sizeof(dso_name), 10402e538c4aSArnaldo Carvalho de Melo "%s%s", self->short_name, section_name); 10412e538c4aSArnaldo Carvalho de Melo 10429de89fe7SArnaldo Carvalho de Melo curr_map = map_groups__find_by_name(kmap->kmaps, map->type, dso_name); 10432e538c4aSArnaldo Carvalho de Melo if (curr_map == NULL) { 10442e538c4aSArnaldo Carvalho de Melo u64 start = sym.st_value; 10452e538c4aSArnaldo Carvalho de Melo 10462e538c4aSArnaldo Carvalho de Melo if (kmodule) 10472e538c4aSArnaldo Carvalho de Melo start += map->start + shdr.sh_offset; 10482e538c4aSArnaldo Carvalho de Melo 104900a192b3SArnaldo Carvalho de Melo curr_dso = dso__new(dso_name); 10502e538c4aSArnaldo Carvalho de Melo if (curr_dso == NULL) 10512e538c4aSArnaldo Carvalho de Melo goto out_elf_end; 1052a1645ce1SZhang, Yanmin curr_dso->kernel = self->kernel; 10533610583cSArnaldo Carvalho de Melo curr_map = map__new2(start, curr_dso, 10546275ce2dSArnaldo Carvalho de Melo map->type); 10552e538c4aSArnaldo Carvalho de Melo if (curr_map == NULL) { 10562e538c4aSArnaldo Carvalho de Melo dso__delete(curr_dso); 10572e538c4aSArnaldo Carvalho de Melo goto out_elf_end; 10582e538c4aSArnaldo Carvalho de Melo } 1059ed52ce2eSArnaldo Carvalho de Melo curr_map->map_ip = identity__map_ip; 1060ed52ce2eSArnaldo Carvalho de Melo curr_map->unmap_ip = identity__map_ip; 1061b0a9ab62SArnaldo Carvalho de Melo curr_dso->origin = self->origin; 10629de89fe7SArnaldo Carvalho de Melo map_groups__insert(kmap->kmaps, curr_map); 1063a1645ce1SZhang, Yanmin dsos__add(&self->node, curr_dso); 10646275ce2dSArnaldo Carvalho de Melo dso__set_loaded(curr_dso, map->type); 10652e538c4aSArnaldo Carvalho de Melo } else 10662e538c4aSArnaldo Carvalho de Melo curr_dso = curr_map->dso; 10672e538c4aSArnaldo Carvalho de Melo 10682e538c4aSArnaldo Carvalho de Melo goto new_symbol; 10692e538c4aSArnaldo Carvalho de Melo } 10702e538c4aSArnaldo Carvalho de Melo 10712e538c4aSArnaldo Carvalho de Melo if (curr_dso->adjust_symbols) { 107229a9f66dSArnaldo Carvalho de Melo pr_debug4("%s: adjusting symbol: st_value: %#Lx " 107329a9f66dSArnaldo Carvalho de Melo "sh_addr: %#Lx sh_offset: %#Lx\n", __func__, 107429a9f66dSArnaldo Carvalho de Melo (u64)sym.st_value, (u64)shdr.sh_addr, 107529a9f66dSArnaldo Carvalho de Melo (u64)shdr.sh_offset); 107686470930SIngo Molnar sym.st_value -= shdr.sh_addr - shdr.sh_offset; 1077af427bf5SArnaldo Carvalho de Melo } 107828ac909bSArnaldo Carvalho de Melo /* 107928ac909bSArnaldo Carvalho de Melo * We need to figure out if the object was created from C++ sources 108028ac909bSArnaldo Carvalho de Melo * DWARF DW_compile_unit has this, but we don't always have access 108128ac909bSArnaldo Carvalho de Melo * to it... 108228ac909bSArnaldo Carvalho de Melo */ 108383a0944fSIngo Molnar demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI); 108428ac909bSArnaldo Carvalho de Melo if (demangled != NULL) 108583a0944fSIngo Molnar elf_name = demangled; 10862e538c4aSArnaldo Carvalho de Melo new_symbol: 108700a192b3SArnaldo Carvalho de Melo f = symbol__new(sym.st_value, sym.st_size, elf_name); 108828ac909bSArnaldo Carvalho de Melo free(demangled); 108986470930SIngo Molnar if (!f) 109086470930SIngo Molnar goto out_elf_end; 109186470930SIngo Molnar 10922e538c4aSArnaldo Carvalho de Melo if (filter && filter(curr_map, f)) 109300a192b3SArnaldo Carvalho de Melo symbol__delete(f); 109486470930SIngo Molnar else { 10956a4694a4SArnaldo Carvalho de Melo symbols__insert(&curr_dso->symbols[curr_map->type], f); 109686470930SIngo Molnar nr++; 109786470930SIngo Molnar } 109886470930SIngo Molnar } 109986470930SIngo Molnar 11002e538c4aSArnaldo Carvalho de Melo /* 11012e538c4aSArnaldo Carvalho de Melo * For misannotated, zeroed, ASM function sizes. 11022e538c4aSArnaldo Carvalho de Melo */ 11036275ce2dSArnaldo Carvalho de Melo if (nr > 0) { 11046a4694a4SArnaldo Carvalho de Melo symbols__fixup_end(&self->symbols[map->type]); 11056275ce2dSArnaldo Carvalho de Melo if (kmap) { 11066275ce2dSArnaldo Carvalho de Melo /* 11076275ce2dSArnaldo Carvalho de Melo * We need to fixup this here too because we create new 11086275ce2dSArnaldo Carvalho de Melo * maps here, for things like vsyscall sections. 11096275ce2dSArnaldo Carvalho de Melo */ 11106275ce2dSArnaldo Carvalho de Melo __map_groups__fixup_end(kmap->kmaps, map->type); 11116275ce2dSArnaldo Carvalho de Melo } 11126275ce2dSArnaldo Carvalho de Melo } 111386470930SIngo Molnar err = nr; 111486470930SIngo Molnar out_elf_end: 111586470930SIngo Molnar elf_end(elf); 111686470930SIngo Molnar out_close: 111786470930SIngo Molnar return err; 111886470930SIngo Molnar } 111986470930SIngo Molnar 112078075caaSArnaldo Carvalho de Melo static bool dso__build_id_equal(const struct dso *self, u8 *build_id) 112178075caaSArnaldo Carvalho de Melo { 112278075caaSArnaldo Carvalho de Melo return memcmp(self->build_id, build_id, sizeof(self->build_id)) == 0; 112378075caaSArnaldo Carvalho de Melo } 112478075caaSArnaldo Carvalho de Melo 1125a1645ce1SZhang, Yanmin bool __dsos__read_build_ids(struct list_head *head, bool with_hits) 112657f395a7SFrederic Weisbecker { 1127e30a3d12SArnaldo Carvalho de Melo bool have_build_id = false; 112857f395a7SFrederic Weisbecker struct dso *pos; 112957f395a7SFrederic Weisbecker 11306122e4e4SArnaldo Carvalho de Melo list_for_each_entry(pos, head, node) { 11316122e4e4SArnaldo Carvalho de Melo if (with_hits && !pos->hit) 11326122e4e4SArnaldo Carvalho de Melo continue; 1133e30a3d12SArnaldo Carvalho de Melo if (filename__read_build_id(pos->long_name, pos->build_id, 1134e30a3d12SArnaldo Carvalho de Melo sizeof(pos->build_id)) > 0) { 1135e30a3d12SArnaldo Carvalho de Melo have_build_id = true; 1136e30a3d12SArnaldo Carvalho de Melo pos->has_build_id = true; 113757f395a7SFrederic Weisbecker } 11386122e4e4SArnaldo Carvalho de Melo } 113957f395a7SFrederic Weisbecker 1140e30a3d12SArnaldo Carvalho de Melo return have_build_id; 114157f395a7SFrederic Weisbecker } 114257f395a7SFrederic Weisbecker 1143fd7a346eSArnaldo Carvalho de Melo /* 1144fd7a346eSArnaldo Carvalho de Melo * Align offset to 4 bytes as needed for note name and descriptor data. 1145fd7a346eSArnaldo Carvalho de Melo */ 1146fd7a346eSArnaldo Carvalho de Melo #define NOTE_ALIGN(n) (((n) + 3) & -4U) 1147fd7a346eSArnaldo Carvalho de Melo 11482643ce11SArnaldo Carvalho de Melo int filename__read_build_id(const char *filename, void *bf, size_t size) 11494d1e00a8SArnaldo Carvalho de Melo { 11502643ce11SArnaldo Carvalho de Melo int fd, err = -1; 11514d1e00a8SArnaldo Carvalho de Melo GElf_Ehdr ehdr; 11524d1e00a8SArnaldo Carvalho de Melo GElf_Shdr shdr; 1153fd7a346eSArnaldo Carvalho de Melo Elf_Data *data; 11544d1e00a8SArnaldo Carvalho de Melo Elf_Scn *sec; 1155e57cfcdaSPekka Enberg Elf_Kind ek; 1156fd7a346eSArnaldo Carvalho de Melo void *ptr; 11574d1e00a8SArnaldo Carvalho de Melo Elf *elf; 11584d1e00a8SArnaldo Carvalho de Melo 11592643ce11SArnaldo Carvalho de Melo if (size < BUILD_ID_SIZE) 11602643ce11SArnaldo Carvalho de Melo goto out; 11612643ce11SArnaldo Carvalho de Melo 11622643ce11SArnaldo Carvalho de Melo fd = open(filename, O_RDONLY); 11634d1e00a8SArnaldo Carvalho de Melo if (fd < 0) 11644d1e00a8SArnaldo Carvalho de Melo goto out; 11654d1e00a8SArnaldo Carvalho de Melo 116684087126SMarti Raudsepp elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 11674d1e00a8SArnaldo Carvalho de Melo if (elf == NULL) { 11688d06367fSArnaldo Carvalho de Melo pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename); 11694d1e00a8SArnaldo Carvalho de Melo goto out_close; 11704d1e00a8SArnaldo Carvalho de Melo } 11714d1e00a8SArnaldo Carvalho de Melo 1172e57cfcdaSPekka Enberg ek = elf_kind(elf); 1173e57cfcdaSPekka Enberg if (ek != ELF_K_ELF) 1174e57cfcdaSPekka Enberg goto out_elf_end; 1175e57cfcdaSPekka Enberg 11764d1e00a8SArnaldo Carvalho de Melo if (gelf_getehdr(elf, &ehdr) == NULL) { 11776beba7adSArnaldo Carvalho de Melo pr_err("%s: cannot get elf header.\n", __func__); 11784d1e00a8SArnaldo Carvalho de Melo goto out_elf_end; 11794d1e00a8SArnaldo Carvalho de Melo } 11804d1e00a8SArnaldo Carvalho de Melo 11812643ce11SArnaldo Carvalho de Melo sec = elf_section_by_name(elf, &ehdr, &shdr, 11822643ce11SArnaldo Carvalho de Melo ".note.gnu.build-id", NULL); 1183fd7a346eSArnaldo Carvalho de Melo if (sec == NULL) { 1184fd7a346eSArnaldo Carvalho de Melo sec = elf_section_by_name(elf, &ehdr, &shdr, 1185fd7a346eSArnaldo Carvalho de Melo ".notes", NULL); 11864d1e00a8SArnaldo Carvalho de Melo if (sec == NULL) 11874d1e00a8SArnaldo Carvalho de Melo goto out_elf_end; 1188fd7a346eSArnaldo Carvalho de Melo } 11894d1e00a8SArnaldo Carvalho de Melo 1190fd7a346eSArnaldo Carvalho de Melo data = elf_getdata(sec, NULL); 1191fd7a346eSArnaldo Carvalho de Melo if (data == NULL) 11924d1e00a8SArnaldo Carvalho de Melo goto out_elf_end; 1193fd7a346eSArnaldo Carvalho de Melo 1194fd7a346eSArnaldo Carvalho de Melo ptr = data->d_buf; 1195fd7a346eSArnaldo Carvalho de Melo while (ptr < (data->d_buf + data->d_size)) { 1196fd7a346eSArnaldo Carvalho de Melo GElf_Nhdr *nhdr = ptr; 1197fd7a346eSArnaldo Carvalho de Melo int namesz = NOTE_ALIGN(nhdr->n_namesz), 1198fd7a346eSArnaldo Carvalho de Melo descsz = NOTE_ALIGN(nhdr->n_descsz); 1199fd7a346eSArnaldo Carvalho de Melo const char *name; 1200fd7a346eSArnaldo Carvalho de Melo 1201fd7a346eSArnaldo Carvalho de Melo ptr += sizeof(*nhdr); 1202fd7a346eSArnaldo Carvalho de Melo name = ptr; 1203fd7a346eSArnaldo Carvalho de Melo ptr += namesz; 1204fd7a346eSArnaldo Carvalho de Melo if (nhdr->n_type == NT_GNU_BUILD_ID && 1205fd7a346eSArnaldo Carvalho de Melo nhdr->n_namesz == sizeof("GNU")) { 1206fd7a346eSArnaldo Carvalho de Melo if (memcmp(name, "GNU", sizeof("GNU")) == 0) { 1207fd7a346eSArnaldo Carvalho de Melo memcpy(bf, ptr, BUILD_ID_SIZE); 12082643ce11SArnaldo Carvalho de Melo err = BUILD_ID_SIZE; 1209fd7a346eSArnaldo Carvalho de Melo break; 1210fd7a346eSArnaldo Carvalho de Melo } 1211fd7a346eSArnaldo Carvalho de Melo } 1212fd7a346eSArnaldo Carvalho de Melo ptr += descsz; 1213fd7a346eSArnaldo Carvalho de Melo } 12142643ce11SArnaldo Carvalho de Melo out_elf_end: 12152643ce11SArnaldo Carvalho de Melo elf_end(elf); 12162643ce11SArnaldo Carvalho de Melo out_close: 12172643ce11SArnaldo Carvalho de Melo close(fd); 12182643ce11SArnaldo Carvalho de Melo out: 12192643ce11SArnaldo Carvalho de Melo return err; 12202643ce11SArnaldo Carvalho de Melo } 12212643ce11SArnaldo Carvalho de Melo 1222f1617b40SArnaldo Carvalho de Melo int sysfs__read_build_id(const char *filename, void *build_id, size_t size) 1223f1617b40SArnaldo Carvalho de Melo { 1224f1617b40SArnaldo Carvalho de Melo int fd, err = -1; 1225f1617b40SArnaldo Carvalho de Melo 1226f1617b40SArnaldo Carvalho de Melo if (size < BUILD_ID_SIZE) 1227f1617b40SArnaldo Carvalho de Melo goto out; 1228f1617b40SArnaldo Carvalho de Melo 1229f1617b40SArnaldo Carvalho de Melo fd = open(filename, O_RDONLY); 1230f1617b40SArnaldo Carvalho de Melo if (fd < 0) 1231f1617b40SArnaldo Carvalho de Melo goto out; 1232f1617b40SArnaldo Carvalho de Melo 1233f1617b40SArnaldo Carvalho de Melo while (1) { 1234f1617b40SArnaldo Carvalho de Melo char bf[BUFSIZ]; 1235f1617b40SArnaldo Carvalho de Melo GElf_Nhdr nhdr; 1236f1617b40SArnaldo Carvalho de Melo int namesz, descsz; 1237f1617b40SArnaldo Carvalho de Melo 1238f1617b40SArnaldo Carvalho de Melo if (read(fd, &nhdr, sizeof(nhdr)) != sizeof(nhdr)) 1239f1617b40SArnaldo Carvalho de Melo break; 1240f1617b40SArnaldo Carvalho de Melo 1241fd7a346eSArnaldo Carvalho de Melo namesz = NOTE_ALIGN(nhdr.n_namesz); 1242fd7a346eSArnaldo Carvalho de Melo descsz = NOTE_ALIGN(nhdr.n_descsz); 1243f1617b40SArnaldo Carvalho de Melo if (nhdr.n_type == NT_GNU_BUILD_ID && 1244f1617b40SArnaldo Carvalho de Melo nhdr.n_namesz == sizeof("GNU")) { 1245f1617b40SArnaldo Carvalho de Melo if (read(fd, bf, namesz) != namesz) 1246f1617b40SArnaldo Carvalho de Melo break; 1247f1617b40SArnaldo Carvalho de Melo if (memcmp(bf, "GNU", sizeof("GNU")) == 0) { 1248f1617b40SArnaldo Carvalho de Melo if (read(fd, build_id, 1249f1617b40SArnaldo Carvalho de Melo BUILD_ID_SIZE) == BUILD_ID_SIZE) { 1250f1617b40SArnaldo Carvalho de Melo err = 0; 1251f1617b40SArnaldo Carvalho de Melo break; 1252f1617b40SArnaldo Carvalho de Melo } 1253f1617b40SArnaldo Carvalho de Melo } else if (read(fd, bf, descsz) != descsz) 1254f1617b40SArnaldo Carvalho de Melo break; 1255f1617b40SArnaldo Carvalho de Melo } else { 1256f1617b40SArnaldo Carvalho de Melo int n = namesz + descsz; 1257f1617b40SArnaldo Carvalho de Melo if (read(fd, bf, n) != n) 1258f1617b40SArnaldo Carvalho de Melo break; 1259f1617b40SArnaldo Carvalho de Melo } 1260f1617b40SArnaldo Carvalho de Melo } 1261f1617b40SArnaldo Carvalho de Melo close(fd); 1262f1617b40SArnaldo Carvalho de Melo out: 1263f1617b40SArnaldo Carvalho de Melo return err; 1264f1617b40SArnaldo Carvalho de Melo } 1265f1617b40SArnaldo Carvalho de Melo 126694cb9e38SArnaldo Carvalho de Melo char dso__symtab_origin(const struct dso *self) 126794cb9e38SArnaldo Carvalho de Melo { 126894cb9e38SArnaldo Carvalho de Melo static const char origin[] = { 126994cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_KERNEL] = 'k', 127094cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_JAVA_JIT] = 'j', 12714cf40131SArnaldo Carvalho de Melo [DSO__ORIG_BUILD_ID_CACHE] = 'B', 127294cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_FEDORA] = 'f', 127394cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_UBUNTU] = 'u', 127494cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_BUILDID] = 'b', 127594cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_DSO] = 'd', 1276439d473bSArnaldo Carvalho de Melo [DSO__ORIG_KMODULE] = 'K', 1277a1645ce1SZhang, Yanmin [DSO__ORIG_GUEST_KERNEL] = 'g', 1278a1645ce1SZhang, Yanmin [DSO__ORIG_GUEST_KMODULE] = 'G', 127994cb9e38SArnaldo Carvalho de Melo }; 128094cb9e38SArnaldo Carvalho de Melo 128194cb9e38SArnaldo Carvalho de Melo if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND) 128294cb9e38SArnaldo Carvalho de Melo return '!'; 128394cb9e38SArnaldo Carvalho de Melo return origin[self->origin]; 128494cb9e38SArnaldo Carvalho de Melo } 128594cb9e38SArnaldo Carvalho de Melo 12869de89fe7SArnaldo Carvalho de Melo int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) 128786470930SIngo Molnar { 12884d1e00a8SArnaldo Carvalho de Melo int size = PATH_MAX; 1289c338aee8SArnaldo Carvalho de Melo char *name; 1290d3379ab9SArnaldo Carvalho de Melo u8 build_id[BUILD_ID_SIZE]; 12914cf40131SArnaldo Carvalho de Melo char build_id_hex[BUILD_ID_SIZE * 2 + 1]; 129286470930SIngo Molnar int ret = -1; 129386470930SIngo Molnar int fd; 1294a1645ce1SZhang, Yanmin struct kernel_info *kerninfo; 1295a1645ce1SZhang, Yanmin const char *root_dir; 129686470930SIngo Molnar 12973610583cSArnaldo Carvalho de Melo dso__set_loaded(self, map->type); 129866bd8424SArnaldo Carvalho de Melo 1299a1645ce1SZhang, Yanmin if (self->kernel == DSO_TYPE_KERNEL) 13009de89fe7SArnaldo Carvalho de Melo return dso__load_kernel_sym(self, map, filter); 1301a1645ce1SZhang, Yanmin else if (self->kernel == DSO_TYPE_GUEST_KERNEL) 1302a1645ce1SZhang, Yanmin return dso__load_guest_kernel_sym(self, map, filter); 1303a1645ce1SZhang, Yanmin 1304a1645ce1SZhang, Yanmin if (map->groups && map->groups->this_kerninfo) 1305a1645ce1SZhang, Yanmin kerninfo = map->groups->this_kerninfo; 1306a1645ce1SZhang, Yanmin else 1307a1645ce1SZhang, Yanmin kerninfo = NULL; 1308c338aee8SArnaldo Carvalho de Melo 1309c338aee8SArnaldo Carvalho de Melo name = malloc(size); 131086470930SIngo Molnar if (!name) 131186470930SIngo Molnar return -1; 131286470930SIngo Molnar 131330d7a77dSArnaldo Carvalho de Melo self->adjust_symbols = 0; 1314f5812a7aSArnaldo Carvalho de Melo 131594cb9e38SArnaldo Carvalho de Melo if (strncmp(self->name, "/tmp/perf-", 10) == 0) { 13166beba7adSArnaldo Carvalho de Melo ret = dso__load_perf_map(self, map, filter); 131794cb9e38SArnaldo Carvalho de Melo self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT : 131894cb9e38SArnaldo Carvalho de Melo DSO__ORIG_NOT_FOUND; 131994cb9e38SArnaldo Carvalho de Melo return ret; 132094cb9e38SArnaldo Carvalho de Melo } 132194cb9e38SArnaldo Carvalho de Melo 13224cf40131SArnaldo Carvalho de Melo self->origin = DSO__ORIG_BUILD_ID_CACHE; 132380d496beSPekka Enberg 13244cf40131SArnaldo Carvalho de Melo if (self->has_build_id) { 13254cf40131SArnaldo Carvalho de Melo build_id__sprintf(self->build_id, sizeof(self->build_id), 13264cf40131SArnaldo Carvalho de Melo build_id_hex); 13274cf40131SArnaldo Carvalho de Melo snprintf(name, size, "%s/%s/.build-id/%.2s/%s", 13284cf40131SArnaldo Carvalho de Melo getenv("HOME"), DEBUG_CACHE_DIR, 13294cf40131SArnaldo Carvalho de Melo build_id_hex, build_id_hex + 2); 13304cf40131SArnaldo Carvalho de Melo goto open_file; 13314cf40131SArnaldo Carvalho de Melo } 133286470930SIngo Molnar more: 133386470930SIngo Molnar do { 133494cb9e38SArnaldo Carvalho de Melo self->origin++; 133594cb9e38SArnaldo Carvalho de Melo switch (self->origin) { 133694cb9e38SArnaldo Carvalho de Melo case DSO__ORIG_FEDORA: 1337439d473bSArnaldo Carvalho de Melo snprintf(name, size, "/usr/lib/debug%s.debug", 1338439d473bSArnaldo Carvalho de Melo self->long_name); 133986470930SIngo Molnar break; 134094cb9e38SArnaldo Carvalho de Melo case DSO__ORIG_UBUNTU: 1341439d473bSArnaldo Carvalho de Melo snprintf(name, size, "/usr/lib/debug%s", 1342439d473bSArnaldo Carvalho de Melo self->long_name); 134386470930SIngo Molnar break; 134494cb9e38SArnaldo Carvalho de Melo case DSO__ORIG_BUILDID: 1345d3379ab9SArnaldo Carvalho de Melo if (filename__read_build_id(self->long_name, build_id, 1346d3379ab9SArnaldo Carvalho de Melo sizeof(build_id))) { 1347d3379ab9SArnaldo Carvalho de Melo build_id__sprintf(build_id, sizeof(build_id), 1348d3379ab9SArnaldo Carvalho de Melo build_id_hex); 13494d1e00a8SArnaldo Carvalho de Melo snprintf(name, size, 13504d1e00a8SArnaldo Carvalho de Melo "/usr/lib/debug/.build-id/%.2s/%s.debug", 1351d3379ab9SArnaldo Carvalho de Melo build_id_hex, build_id_hex + 2); 1352d3379ab9SArnaldo Carvalho de Melo if (self->has_build_id) 13538d06367fSArnaldo Carvalho de Melo goto compare_build_id; 1354d3379ab9SArnaldo Carvalho de Melo break; 13554d1e00a8SArnaldo Carvalho de Melo } 135694cb9e38SArnaldo Carvalho de Melo self->origin++; 13574d1e00a8SArnaldo Carvalho de Melo /* Fall thru */ 135894cb9e38SArnaldo Carvalho de Melo case DSO__ORIG_DSO: 1359439d473bSArnaldo Carvalho de Melo snprintf(name, size, "%s", self->long_name); 136086470930SIngo Molnar break; 1361a1645ce1SZhang, Yanmin case DSO__ORIG_GUEST_KMODULE: 1362a1645ce1SZhang, Yanmin if (map->groups && map->groups->this_kerninfo) 1363a1645ce1SZhang, Yanmin root_dir = map->groups->this_kerninfo->root_dir; 1364a1645ce1SZhang, Yanmin else 1365a1645ce1SZhang, Yanmin root_dir = ""; 1366a1645ce1SZhang, Yanmin snprintf(name, size, "%s%s", root_dir, self->long_name); 1367a1645ce1SZhang, Yanmin break; 136886470930SIngo Molnar 136986470930SIngo Molnar default: 137086470930SIngo Molnar goto out; 137186470930SIngo Molnar } 137286470930SIngo Molnar 13738d06367fSArnaldo Carvalho de Melo if (self->has_build_id) { 1374d3379ab9SArnaldo Carvalho de Melo if (filename__read_build_id(name, build_id, 1375d3379ab9SArnaldo Carvalho de Melo sizeof(build_id)) < 0) 13768d06367fSArnaldo Carvalho de Melo goto more; 13778d06367fSArnaldo Carvalho de Melo compare_build_id: 137878075caaSArnaldo Carvalho de Melo if (!dso__build_id_equal(self, build_id)) 13798d06367fSArnaldo Carvalho de Melo goto more; 13808d06367fSArnaldo Carvalho de Melo } 13814cf40131SArnaldo Carvalho de Melo open_file: 138286470930SIngo Molnar fd = open(name, O_RDONLY); 138386470930SIngo Molnar } while (fd < 0); 138486470930SIngo Molnar 13859de89fe7SArnaldo Carvalho de Melo ret = dso__load_sym(self, map, name, fd, filter, 0); 138686470930SIngo Molnar close(fd); 138786470930SIngo Molnar 138886470930SIngo Molnar /* 138986470930SIngo Molnar * Some people seem to have debuginfo files _WITHOUT_ debug info!?!? 139086470930SIngo Molnar */ 139186470930SIngo Molnar if (!ret) 139286470930SIngo Molnar goto more; 139386470930SIngo Molnar 1394a25e46c4SArnaldo Carvalho de Melo if (ret > 0) { 139582164161SArnaldo Carvalho de Melo int nr_plt = dso__synthesize_plt_symbols(self, map, filter); 1396a25e46c4SArnaldo Carvalho de Melo if (nr_plt > 0) 1397a25e46c4SArnaldo Carvalho de Melo ret += nr_plt; 1398a25e46c4SArnaldo Carvalho de Melo } 139986470930SIngo Molnar out: 140086470930SIngo Molnar free(name); 14011340e6bbSArnaldo Carvalho de Melo if (ret < 0 && strstr(self->name, " (deleted)") != NULL) 14021340e6bbSArnaldo Carvalho de Melo return 0; 140386470930SIngo Molnar return ret; 140486470930SIngo Molnar } 140586470930SIngo Molnar 140679406cd7SArnaldo Carvalho de Melo struct map *map_groups__find_by_name(struct map_groups *self, 140779406cd7SArnaldo Carvalho de Melo enum map_type type, const char *name) 1408439d473bSArnaldo Carvalho de Melo { 1409439d473bSArnaldo Carvalho de Melo struct rb_node *nd; 1410439d473bSArnaldo Carvalho de Melo 141179406cd7SArnaldo Carvalho de Melo for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) { 1412439d473bSArnaldo Carvalho de Melo struct map *map = rb_entry(nd, struct map, rb_node); 1413439d473bSArnaldo Carvalho de Melo 1414b7cece76SArnaldo Carvalho de Melo if (map->dso && strcmp(map->dso->short_name, name) == 0) 1415439d473bSArnaldo Carvalho de Melo return map; 1416439d473bSArnaldo Carvalho de Melo } 1417439d473bSArnaldo Carvalho de Melo 1418439d473bSArnaldo Carvalho de Melo return NULL; 1419439d473bSArnaldo Carvalho de Melo } 1420439d473bSArnaldo Carvalho de Melo 1421a1645ce1SZhang, Yanmin static int dso__kernel_module_get_build_id(struct dso *self, 1422a1645ce1SZhang, Yanmin const char *root_dir) 1423b7cece76SArnaldo Carvalho de Melo { 1424b7cece76SArnaldo Carvalho de Melo char filename[PATH_MAX]; 1425b7cece76SArnaldo Carvalho de Melo /* 1426b7cece76SArnaldo Carvalho de Melo * kernel module short names are of the form "[module]" and 1427b7cece76SArnaldo Carvalho de Melo * we need just "module" here. 1428b7cece76SArnaldo Carvalho de Melo */ 1429b7cece76SArnaldo Carvalho de Melo const char *name = self->short_name + 1; 1430b7cece76SArnaldo Carvalho de Melo 1431b7cece76SArnaldo Carvalho de Melo snprintf(filename, sizeof(filename), 1432a1645ce1SZhang, Yanmin "%s/sys/module/%.*s/notes/.note.gnu.build-id", 1433a1645ce1SZhang, Yanmin root_dir, (int)strlen(name) - 1, name); 1434b7cece76SArnaldo Carvalho de Melo 1435b7cece76SArnaldo Carvalho de Melo if (sysfs__read_build_id(filename, self->build_id, 1436b7cece76SArnaldo Carvalho de Melo sizeof(self->build_id)) == 0) 1437b7cece76SArnaldo Carvalho de Melo self->has_build_id = true; 1438b7cece76SArnaldo Carvalho de Melo 1439b7cece76SArnaldo Carvalho de Melo return 0; 1440b7cece76SArnaldo Carvalho de Melo } 1441b7cece76SArnaldo Carvalho de Melo 1442a1645ce1SZhang, Yanmin static int map_groups__set_modules_path_dir(struct map_groups *self, 1443a1645ce1SZhang, Yanmin const char *dir_name) 14446cfcc53eSMike Galbraith { 1445439d473bSArnaldo Carvalho de Melo struct dirent *dent; 14465aab621bSArnaldo Carvalho de Melo DIR *dir = opendir(dir_name); 14476cfcc53eSMike Galbraith 1448439d473bSArnaldo Carvalho de Melo if (!dir) { 14495aab621bSArnaldo Carvalho de Melo pr_debug("%s: cannot open %s dir\n", __func__, dir_name); 1450439d473bSArnaldo Carvalho de Melo return -1; 1451439d473bSArnaldo Carvalho de Melo } 14526cfcc53eSMike Galbraith 1453439d473bSArnaldo Carvalho de Melo while ((dent = readdir(dir)) != NULL) { 1454439d473bSArnaldo Carvalho de Melo char path[PATH_MAX]; 1455a1645ce1SZhang, Yanmin struct stat st; 1456439d473bSArnaldo Carvalho de Melo 1457a1645ce1SZhang, Yanmin /*sshfs might return bad dent->d_type, so we have to stat*/ 1458a1645ce1SZhang, Yanmin sprintf(path, "%s/%s", dir_name, dent->d_name); 1459a1645ce1SZhang, Yanmin if (stat(path, &st)) 1460a1645ce1SZhang, Yanmin continue; 1461a1645ce1SZhang, Yanmin 1462a1645ce1SZhang, Yanmin if (S_ISDIR(st.st_mode)) { 1463439d473bSArnaldo Carvalho de Melo if (!strcmp(dent->d_name, ".") || 1464439d473bSArnaldo Carvalho de Melo !strcmp(dent->d_name, "..")) 1465439d473bSArnaldo Carvalho de Melo continue; 1466439d473bSArnaldo Carvalho de Melo 1467439d473bSArnaldo Carvalho de Melo snprintf(path, sizeof(path), "%s/%s", 14685aab621bSArnaldo Carvalho de Melo dir_name, dent->d_name); 14699de89fe7SArnaldo Carvalho de Melo if (map_groups__set_modules_path_dir(self, path) < 0) 1470439d473bSArnaldo Carvalho de Melo goto failure; 1471439d473bSArnaldo Carvalho de Melo } else { 1472439d473bSArnaldo Carvalho de Melo char *dot = strrchr(dent->d_name, '.'), 1473439d473bSArnaldo Carvalho de Melo dso_name[PATH_MAX]; 1474439d473bSArnaldo Carvalho de Melo struct map *map; 1475cfc10d3bSArnaldo Carvalho de Melo char *long_name; 1476439d473bSArnaldo Carvalho de Melo 1477439d473bSArnaldo Carvalho de Melo if (dot == NULL || strcmp(dot, ".ko")) 1478439d473bSArnaldo Carvalho de Melo continue; 1479439d473bSArnaldo Carvalho de Melo snprintf(dso_name, sizeof(dso_name), "[%.*s]", 1480439d473bSArnaldo Carvalho de Melo (int)(dot - dent->d_name), dent->d_name); 1481439d473bSArnaldo Carvalho de Melo 1482a2a99e8eSArnaldo Carvalho de Melo strxfrchar(dso_name, '-', '_'); 14839de89fe7SArnaldo Carvalho de Melo map = map_groups__find_by_name(self, MAP__FUNCTION, dso_name); 1484439d473bSArnaldo Carvalho de Melo if (map == NULL) 1485439d473bSArnaldo Carvalho de Melo continue; 1486439d473bSArnaldo Carvalho de Melo 1487439d473bSArnaldo Carvalho de Melo snprintf(path, sizeof(path), "%s/%s", 14885aab621bSArnaldo Carvalho de Melo dir_name, dent->d_name); 1489439d473bSArnaldo Carvalho de Melo 1490cfc10d3bSArnaldo Carvalho de Melo long_name = strdup(path); 1491cfc10d3bSArnaldo Carvalho de Melo if (long_name == NULL) 1492439d473bSArnaldo Carvalho de Melo goto failure; 1493cfc10d3bSArnaldo Carvalho de Melo dso__set_long_name(map->dso, long_name); 1494a1645ce1SZhang, Yanmin dso__kernel_module_get_build_id(map->dso, ""); 1495439d473bSArnaldo Carvalho de Melo } 1496439d473bSArnaldo Carvalho de Melo } 1497439d473bSArnaldo Carvalho de Melo 1498c338aee8SArnaldo Carvalho de Melo return 0; 1499439d473bSArnaldo Carvalho de Melo failure: 1500439d473bSArnaldo Carvalho de Melo closedir(dir); 1501439d473bSArnaldo Carvalho de Melo return -1; 1502439d473bSArnaldo Carvalho de Melo } 1503439d473bSArnaldo Carvalho de Melo 1504a1645ce1SZhang, Yanmin static char *get_kernel_version(const char *root_dir) 1505439d473bSArnaldo Carvalho de Melo { 1506a1645ce1SZhang, Yanmin char version[PATH_MAX]; 1507a1645ce1SZhang, Yanmin FILE *file; 1508a1645ce1SZhang, Yanmin char *name, *tmp; 1509a1645ce1SZhang, Yanmin const char *prefix = "Linux version "; 1510a1645ce1SZhang, Yanmin 1511a1645ce1SZhang, Yanmin sprintf(version, "%s/proc/version", root_dir); 1512a1645ce1SZhang, Yanmin file = fopen(version, "r"); 1513a1645ce1SZhang, Yanmin if (!file) 1514a1645ce1SZhang, Yanmin return NULL; 1515a1645ce1SZhang, Yanmin 1516a1645ce1SZhang, Yanmin version[0] = '\0'; 1517a1645ce1SZhang, Yanmin tmp = fgets(version, sizeof(version), file); 1518a1645ce1SZhang, Yanmin fclose(file); 1519a1645ce1SZhang, Yanmin 1520a1645ce1SZhang, Yanmin name = strstr(version, prefix); 1521a1645ce1SZhang, Yanmin if (!name) 1522a1645ce1SZhang, Yanmin return NULL; 1523a1645ce1SZhang, Yanmin name += strlen(prefix); 1524a1645ce1SZhang, Yanmin tmp = strchr(name, ' '); 1525a1645ce1SZhang, Yanmin if (tmp) 1526a1645ce1SZhang, Yanmin *tmp = '\0'; 1527a1645ce1SZhang, Yanmin 1528a1645ce1SZhang, Yanmin return strdup(name); 1529a1645ce1SZhang, Yanmin } 1530a1645ce1SZhang, Yanmin 1531a1645ce1SZhang, Yanmin static int map_groups__set_modules_path(struct map_groups *self, 1532a1645ce1SZhang, Yanmin const char *root_dir) 1533a1645ce1SZhang, Yanmin { 1534a1645ce1SZhang, Yanmin char *version; 1535439d473bSArnaldo Carvalho de Melo char modules_path[PATH_MAX]; 1536439d473bSArnaldo Carvalho de Melo 1537a1645ce1SZhang, Yanmin version = get_kernel_version(root_dir); 1538a1645ce1SZhang, Yanmin if (!version) 1539439d473bSArnaldo Carvalho de Melo return -1; 1540439d473bSArnaldo Carvalho de Melo 1541a1645ce1SZhang, Yanmin snprintf(modules_path, sizeof(modules_path), "%s/lib/modules/%s/kernel", 1542a1645ce1SZhang, Yanmin root_dir, version); 1543a1645ce1SZhang, Yanmin free(version); 1544439d473bSArnaldo Carvalho de Melo 15459de89fe7SArnaldo Carvalho de Melo return map_groups__set_modules_path_dir(self, modules_path); 1546439d473bSArnaldo Carvalho de Melo } 15476cfcc53eSMike Galbraith 15486cfcc53eSMike Galbraith /* 1549439d473bSArnaldo Carvalho de Melo * Constructor variant for modules (where we know from /proc/modules where 1550439d473bSArnaldo Carvalho de Melo * they are loaded) and for vmlinux, where only after we load all the 1551439d473bSArnaldo Carvalho de Melo * symbols we'll know where it starts and ends. 15526cfcc53eSMike Galbraith */ 15533610583cSArnaldo Carvalho de Melo static struct map *map__new2(u64 start, struct dso *dso, enum map_type type) 1554439d473bSArnaldo Carvalho de Melo { 15555aab621bSArnaldo Carvalho de Melo struct map *self = calloc(1, (sizeof(*self) + 15565aab621bSArnaldo Carvalho de Melo (dso->kernel ? sizeof(struct kmap) : 0))); 1557439d473bSArnaldo Carvalho de Melo if (self != NULL) { 1558439d473bSArnaldo Carvalho de Melo /* 1559afb7b4f0SArnaldo Carvalho de Melo * ->end will be filled after we load all the symbols 1560439d473bSArnaldo Carvalho de Melo */ 15613610583cSArnaldo Carvalho de Melo map__init(self, type, start, 0, 0, dso); 1562439d473bSArnaldo Carvalho de Melo } 1563afb7b4f0SArnaldo Carvalho de Melo 1564439d473bSArnaldo Carvalho de Melo return self; 1565439d473bSArnaldo Carvalho de Melo } 1566439d473bSArnaldo Carvalho de Melo 15679de89fe7SArnaldo Carvalho de Melo struct map *map_groups__new_module(struct map_groups *self, u64 start, 1568a1645ce1SZhang, Yanmin const char *filename, 1569a1645ce1SZhang, Yanmin struct kernel_info *kerninfo) 1570b7cece76SArnaldo Carvalho de Melo { 1571b7cece76SArnaldo Carvalho de Melo struct map *map; 1572a1645ce1SZhang, Yanmin struct dso *dso; 1573b7cece76SArnaldo Carvalho de Melo 1574a1645ce1SZhang, Yanmin dso = __dsos__findnew(&kerninfo->dsos__kernel, filename); 1575b7cece76SArnaldo Carvalho de Melo if (dso == NULL) 1576b7cece76SArnaldo Carvalho de Melo return NULL; 1577b7cece76SArnaldo Carvalho de Melo 1578b7cece76SArnaldo Carvalho de Melo map = map__new2(start, dso, MAP__FUNCTION); 1579b7cece76SArnaldo Carvalho de Melo if (map == NULL) 1580b7cece76SArnaldo Carvalho de Melo return NULL; 1581b7cece76SArnaldo Carvalho de Melo 1582a1645ce1SZhang, Yanmin if (is_host_kernel(kerninfo)) 1583b7cece76SArnaldo Carvalho de Melo dso->origin = DSO__ORIG_KMODULE; 1584a1645ce1SZhang, Yanmin else 1585a1645ce1SZhang, Yanmin dso->origin = DSO__ORIG_GUEST_KMODULE; 15869de89fe7SArnaldo Carvalho de Melo map_groups__insert(self, map); 1587b7cece76SArnaldo Carvalho de Melo return map; 1588b7cece76SArnaldo Carvalho de Melo } 1589b7cece76SArnaldo Carvalho de Melo 1590a1645ce1SZhang, Yanmin static int map_groups__create_modules(struct kernel_info *kerninfo) 1591439d473bSArnaldo Carvalho de Melo { 1592439d473bSArnaldo Carvalho de Melo char *line = NULL; 1593439d473bSArnaldo Carvalho de Melo size_t n; 1594a1645ce1SZhang, Yanmin FILE *file; 1595439d473bSArnaldo Carvalho de Melo struct map *map; 1596a1645ce1SZhang, Yanmin const char *root_dir; 1597a1645ce1SZhang, Yanmin const char *modules; 1598a1645ce1SZhang, Yanmin char path[PATH_MAX]; 1599439d473bSArnaldo Carvalho de Melo 1600a1645ce1SZhang, Yanmin if (is_default_guest(kerninfo)) 1601a1645ce1SZhang, Yanmin modules = symbol_conf.default_guest_modules; 1602a1645ce1SZhang, Yanmin else { 1603a1645ce1SZhang, Yanmin sprintf(path, "%s/proc/modules", kerninfo->root_dir); 1604a1645ce1SZhang, Yanmin modules = path; 1605a1645ce1SZhang, Yanmin } 1606a1645ce1SZhang, Yanmin 1607a1645ce1SZhang, Yanmin file = fopen(modules, "r"); 1608439d473bSArnaldo Carvalho de Melo if (file == NULL) 1609439d473bSArnaldo Carvalho de Melo return -1; 1610439d473bSArnaldo Carvalho de Melo 1611a1645ce1SZhang, Yanmin root_dir = kerninfo->root_dir; 1612a1645ce1SZhang, Yanmin 1613439d473bSArnaldo Carvalho de Melo while (!feof(file)) { 1614439d473bSArnaldo Carvalho de Melo char name[PATH_MAX]; 1615439d473bSArnaldo Carvalho de Melo u64 start; 1616439d473bSArnaldo Carvalho de Melo char *sep; 1617439d473bSArnaldo Carvalho de Melo int line_len; 1618439d473bSArnaldo Carvalho de Melo 1619439d473bSArnaldo Carvalho de Melo line_len = getline(&line, &n, file); 1620439d473bSArnaldo Carvalho de Melo if (line_len < 0) 16216cfcc53eSMike Galbraith break; 16226cfcc53eSMike Galbraith 1623439d473bSArnaldo Carvalho de Melo if (!line) 1624439d473bSArnaldo Carvalho de Melo goto out_failure; 1625439d473bSArnaldo Carvalho de Melo 1626439d473bSArnaldo Carvalho de Melo line[--line_len] = '\0'; /* \n */ 1627439d473bSArnaldo Carvalho de Melo 1628439d473bSArnaldo Carvalho de Melo sep = strrchr(line, 'x'); 1629439d473bSArnaldo Carvalho de Melo if (sep == NULL) 1630439d473bSArnaldo Carvalho de Melo continue; 1631439d473bSArnaldo Carvalho de Melo 1632439d473bSArnaldo Carvalho de Melo hex2u64(sep + 1, &start); 1633439d473bSArnaldo Carvalho de Melo 1634439d473bSArnaldo Carvalho de Melo sep = strchr(line, ' '); 1635439d473bSArnaldo Carvalho de Melo if (sep == NULL) 1636439d473bSArnaldo Carvalho de Melo continue; 1637439d473bSArnaldo Carvalho de Melo 1638439d473bSArnaldo Carvalho de Melo *sep = '\0'; 1639439d473bSArnaldo Carvalho de Melo 1640439d473bSArnaldo Carvalho de Melo snprintf(name, sizeof(name), "[%s]", line); 1641a1645ce1SZhang, Yanmin map = map_groups__new_module(&kerninfo->kmaps, 1642a1645ce1SZhang, Yanmin start, name, kerninfo); 1643b7cece76SArnaldo Carvalho de Melo if (map == NULL) 1644439d473bSArnaldo Carvalho de Melo goto out_delete_line; 1645a1645ce1SZhang, Yanmin dso__kernel_module_get_build_id(map->dso, root_dir); 16466cfcc53eSMike Galbraith } 16476cfcc53eSMike Galbraith 1648439d473bSArnaldo Carvalho de Melo free(line); 1649439d473bSArnaldo Carvalho de Melo fclose(file); 1650439d473bSArnaldo Carvalho de Melo 1651a1645ce1SZhang, Yanmin return map_groups__set_modules_path(&kerninfo->kmaps, root_dir); 1652439d473bSArnaldo Carvalho de Melo 1653439d473bSArnaldo Carvalho de Melo out_delete_line: 1654439d473bSArnaldo Carvalho de Melo free(line); 1655439d473bSArnaldo Carvalho de Melo out_failure: 1656439d473bSArnaldo Carvalho de Melo return -1; 16576cfcc53eSMike Galbraith } 16586cfcc53eSMike Galbraith 16599958e1f0SArnaldo Carvalho de Melo static int dso__load_vmlinux(struct dso *self, struct map *map, 16606beba7adSArnaldo Carvalho de Melo const char *vmlinux, symbol_filter_t filter) 166186470930SIngo Molnar { 1662fbd733b8SArnaldo Carvalho de Melo int err = -1, fd; 166386470930SIngo Molnar 1664fbd733b8SArnaldo Carvalho de Melo if (self->has_build_id) { 1665fbd733b8SArnaldo Carvalho de Melo u8 build_id[BUILD_ID_SIZE]; 166666bd8424SArnaldo Carvalho de Melo 1667fbd733b8SArnaldo Carvalho de Melo if (filename__read_build_id(vmlinux, build_id, 1668fbd733b8SArnaldo Carvalho de Melo sizeof(build_id)) < 0) { 1669fbd733b8SArnaldo Carvalho de Melo pr_debug("No build_id in %s, ignoring it\n", vmlinux); 1670fbd733b8SArnaldo Carvalho de Melo return -1; 1671fbd733b8SArnaldo Carvalho de Melo } 1672fbd733b8SArnaldo Carvalho de Melo if (!dso__build_id_equal(self, build_id)) { 1673fbd733b8SArnaldo Carvalho de Melo char expected_build_id[BUILD_ID_SIZE * 2 + 1], 1674fbd733b8SArnaldo Carvalho de Melo vmlinux_build_id[BUILD_ID_SIZE * 2 + 1]; 1675fbd733b8SArnaldo Carvalho de Melo 1676fbd733b8SArnaldo Carvalho de Melo build_id__sprintf(self->build_id, 1677fbd733b8SArnaldo Carvalho de Melo sizeof(self->build_id), 1678fbd733b8SArnaldo Carvalho de Melo expected_build_id); 1679fbd733b8SArnaldo Carvalho de Melo build_id__sprintf(build_id, sizeof(build_id), 1680fbd733b8SArnaldo Carvalho de Melo vmlinux_build_id); 1681fbd733b8SArnaldo Carvalho de Melo pr_debug("build_id in %s is %s while expected is %s, " 1682fbd733b8SArnaldo Carvalho de Melo "ignoring it\n", vmlinux, vmlinux_build_id, 1683fbd733b8SArnaldo Carvalho de Melo expected_build_id); 1684fbd733b8SArnaldo Carvalho de Melo return -1; 1685fbd733b8SArnaldo Carvalho de Melo } 1686fbd733b8SArnaldo Carvalho de Melo } 1687fbd733b8SArnaldo Carvalho de Melo 1688fbd733b8SArnaldo Carvalho de Melo fd = open(vmlinux, O_RDONLY); 168986470930SIngo Molnar if (fd < 0) 169086470930SIngo Molnar return -1; 169186470930SIngo Molnar 16923610583cSArnaldo Carvalho de Melo dso__set_loaded(self, map->type); 16939de89fe7SArnaldo Carvalho de Melo err = dso__load_sym(self, map, vmlinux, fd, filter, 0); 169486470930SIngo Molnar close(fd); 169586470930SIngo Molnar 16963846df2eSArnaldo Carvalho de Melo if (err > 0) 16973846df2eSArnaldo Carvalho de Melo pr_debug("Using %s for symbols\n", vmlinux); 16983846df2eSArnaldo Carvalho de Melo 169986470930SIngo Molnar return err; 170086470930SIngo Molnar } 170186470930SIngo Molnar 1702a19afe46SArnaldo Carvalho de Melo int dso__load_vmlinux_path(struct dso *self, struct map *map, 17039de89fe7SArnaldo Carvalho de Melo symbol_filter_t filter) 1704a19afe46SArnaldo Carvalho de Melo { 1705a19afe46SArnaldo Carvalho de Melo int i, err = 0; 1706a19afe46SArnaldo Carvalho de Melo 1707a19afe46SArnaldo Carvalho de Melo pr_debug("Looking at the vmlinux_path (%d entries long)\n", 1708a19afe46SArnaldo Carvalho de Melo vmlinux_path__nr_entries); 1709a19afe46SArnaldo Carvalho de Melo 1710a19afe46SArnaldo Carvalho de Melo for (i = 0; i < vmlinux_path__nr_entries; ++i) { 17119de89fe7SArnaldo Carvalho de Melo err = dso__load_vmlinux(self, map, vmlinux_path[i], filter); 1712a19afe46SArnaldo Carvalho de Melo if (err > 0) { 1713a19afe46SArnaldo Carvalho de Melo dso__set_long_name(self, strdup(vmlinux_path[i])); 1714a19afe46SArnaldo Carvalho de Melo break; 1715a19afe46SArnaldo Carvalho de Melo } 1716a19afe46SArnaldo Carvalho de Melo } 1717a19afe46SArnaldo Carvalho de Melo 1718a19afe46SArnaldo Carvalho de Melo return err; 1719a19afe46SArnaldo Carvalho de Melo } 1720a19afe46SArnaldo Carvalho de Melo 1721c338aee8SArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *self, struct map *map, 17229de89fe7SArnaldo Carvalho de Melo symbol_filter_t filter) 172386470930SIngo Molnar { 1724cc612d81SArnaldo Carvalho de Melo int err; 17259e201442SArnaldo Carvalho de Melo const char *kallsyms_filename = NULL; 17269e201442SArnaldo Carvalho de Melo char *kallsyms_allocated_filename = NULL; 1727dc8d6ab2SArnaldo Carvalho de Melo /* 1728dc8d6ab2SArnaldo Carvalho de Melo * Step 1: if the user specified a vmlinux filename, use it and only 1729dc8d6ab2SArnaldo Carvalho de Melo * it, reporting errors to the user if it cannot be used. 1730dc8d6ab2SArnaldo Carvalho de Melo * 1731dc8d6ab2SArnaldo Carvalho de Melo * For instance, try to analyse an ARM perf.data file _without_ a 1732dc8d6ab2SArnaldo Carvalho de Melo * build-id, or if the user specifies the wrong path to the right 1733dc8d6ab2SArnaldo Carvalho de Melo * vmlinux file, obviously we can't fallback to another vmlinux (a 1734dc8d6ab2SArnaldo Carvalho de Melo * x86_86 one, on the machine where analysis is being performed, say), 1735dc8d6ab2SArnaldo Carvalho de Melo * or worse, /proc/kallsyms. 1736dc8d6ab2SArnaldo Carvalho de Melo * 1737dc8d6ab2SArnaldo Carvalho de Melo * If the specified file _has_ a build-id and there is a build-id 1738dc8d6ab2SArnaldo Carvalho de Melo * section in the perf.data file, we will still do the expected 1739dc8d6ab2SArnaldo Carvalho de Melo * validation in dso__load_vmlinux and will bail out if they don't 1740dc8d6ab2SArnaldo Carvalho de Melo * match. 1741dc8d6ab2SArnaldo Carvalho de Melo */ 1742dc8d6ab2SArnaldo Carvalho de Melo if (symbol_conf.vmlinux_name != NULL) { 17439de89fe7SArnaldo Carvalho de Melo err = dso__load_vmlinux(self, map, 1744dc8d6ab2SArnaldo Carvalho de Melo symbol_conf.vmlinux_name, filter); 1745dc8d6ab2SArnaldo Carvalho de Melo goto out_try_fixup; 1746dc8d6ab2SArnaldo Carvalho de Melo } 1747439d473bSArnaldo Carvalho de Melo 1748cc612d81SArnaldo Carvalho de Melo if (vmlinux_path != NULL) { 17499de89fe7SArnaldo Carvalho de Melo err = dso__load_vmlinux_path(self, map, filter); 1750a19afe46SArnaldo Carvalho de Melo if (err > 0) 1751cc612d81SArnaldo Carvalho de Melo goto out_fixup; 1752cc612d81SArnaldo Carvalho de Melo } 1753cc612d81SArnaldo Carvalho de Melo 1754b7cece76SArnaldo Carvalho de Melo /* 1755b7cece76SArnaldo Carvalho de Melo * Say the kernel DSO was created when processing the build-id header table, 1756b7cece76SArnaldo Carvalho de Melo * we have a build-id, so check if it is the same as the running kernel, 1757b7cece76SArnaldo Carvalho de Melo * using it if it is. 1758b7cece76SArnaldo Carvalho de Melo */ 1759b7cece76SArnaldo Carvalho de Melo if (self->has_build_id) { 1760b7cece76SArnaldo Carvalho de Melo u8 kallsyms_build_id[BUILD_ID_SIZE]; 17619e201442SArnaldo Carvalho de Melo char sbuild_id[BUILD_ID_SIZE * 2 + 1]; 1762b7cece76SArnaldo Carvalho de Melo 1763b7cece76SArnaldo Carvalho de Melo if (sysfs__read_build_id("/sys/kernel/notes", kallsyms_build_id, 17648d0591f6SArnaldo Carvalho de Melo sizeof(kallsyms_build_id)) == 0) { 17659e201442SArnaldo Carvalho de Melo if (dso__build_id_equal(self, kallsyms_build_id)) { 17669e201442SArnaldo Carvalho de Melo kallsyms_filename = "/proc/kallsyms"; 1767b7cece76SArnaldo Carvalho de Melo goto do_kallsyms; 17688d0591f6SArnaldo Carvalho de Melo } 17699e201442SArnaldo Carvalho de Melo } 1770dc8d6ab2SArnaldo Carvalho de Melo /* 1771dc8d6ab2SArnaldo Carvalho de Melo * Now look if we have it on the build-id cache in 1772dc8d6ab2SArnaldo Carvalho de Melo * $HOME/.debug/[kernel.kallsyms]. 1773dc8d6ab2SArnaldo Carvalho de Melo */ 17749e201442SArnaldo Carvalho de Melo build_id__sprintf(self->build_id, sizeof(self->build_id), 17759e201442SArnaldo Carvalho de Melo sbuild_id); 17769e201442SArnaldo Carvalho de Melo 17779e201442SArnaldo Carvalho de Melo if (asprintf(&kallsyms_allocated_filename, 17789e201442SArnaldo Carvalho de Melo "%s/.debug/[kernel.kallsyms]/%s", 17793846df2eSArnaldo Carvalho de Melo getenv("HOME"), sbuild_id) == -1) { 17803846df2eSArnaldo Carvalho de Melo pr_err("Not enough memory for kallsyms file lookup\n"); 17818d0591f6SArnaldo Carvalho de Melo return -1; 17823846df2eSArnaldo Carvalho de Melo } 17838d0591f6SArnaldo Carvalho de Melo 178419fc2dedSArnaldo Carvalho de Melo kallsyms_filename = kallsyms_allocated_filename; 178519fc2dedSArnaldo Carvalho de Melo 1786dc8d6ab2SArnaldo Carvalho de Melo if (access(kallsyms_filename, F_OK)) { 17873846df2eSArnaldo Carvalho de Melo pr_err("No kallsyms or vmlinux with build-id %s " 17883846df2eSArnaldo Carvalho de Melo "was found\n", sbuild_id); 17899e201442SArnaldo Carvalho de Melo free(kallsyms_allocated_filename); 1790dc8d6ab2SArnaldo Carvalho de Melo return -1; 1791ef6ae724SArnaldo Carvalho de Melo } 1792dc8d6ab2SArnaldo Carvalho de Melo } else { 1793dc8d6ab2SArnaldo Carvalho de Melo /* 1794dc8d6ab2SArnaldo Carvalho de Melo * Last resort, if we don't have a build-id and couldn't find 1795dc8d6ab2SArnaldo Carvalho de Melo * any vmlinux file, try the running kernel kallsyms table. 1796dc8d6ab2SArnaldo Carvalho de Melo */ 1797dc8d6ab2SArnaldo Carvalho de Melo kallsyms_filename = "/proc/kallsyms"; 1798dc8d6ab2SArnaldo Carvalho de Melo } 1799dc8d6ab2SArnaldo Carvalho de Melo 1800dc8d6ab2SArnaldo Carvalho de Melo do_kallsyms: 18019de89fe7SArnaldo Carvalho de Melo err = dso__load_kallsyms(self, kallsyms_filename, map, filter); 18023846df2eSArnaldo Carvalho de Melo if (err > 0) 18033846df2eSArnaldo Carvalho de Melo pr_debug("Using %s for symbols\n", kallsyms_filename); 1804dc8d6ab2SArnaldo Carvalho de Melo free(kallsyms_allocated_filename); 1805dc8d6ab2SArnaldo Carvalho de Melo 1806dc8d6ab2SArnaldo Carvalho de Melo out_try_fixup: 1807439d473bSArnaldo Carvalho de Melo if (err > 0) { 1808cc612d81SArnaldo Carvalho de Melo out_fixup: 1809e1c7c6a4SArnaldo Carvalho de Melo if (kallsyms_filename != NULL) 1810dc8d6ab2SArnaldo Carvalho de Melo dso__set_long_name(self, strdup("[kernel.kallsyms]")); 18116a4694a4SArnaldo Carvalho de Melo map__fixup_start(map); 18126a4694a4SArnaldo Carvalho de Melo map__fixup_end(map); 1813439d473bSArnaldo Carvalho de Melo } 181494cb9e38SArnaldo Carvalho de Melo 181586470930SIngo Molnar return err; 181686470930SIngo Molnar } 181786470930SIngo Molnar 1818a1645ce1SZhang, Yanmin static int dso__load_guest_kernel_sym(struct dso *self, struct map *map, 1819a1645ce1SZhang, Yanmin symbol_filter_t filter) 1820a1645ce1SZhang, Yanmin { 1821a1645ce1SZhang, Yanmin int err; 1822a1645ce1SZhang, Yanmin const char *kallsyms_filename = NULL; 1823a1645ce1SZhang, Yanmin struct kernel_info *kerninfo; 1824a1645ce1SZhang, Yanmin char path[PATH_MAX]; 1825a1645ce1SZhang, Yanmin 1826a1645ce1SZhang, Yanmin if (!map->groups) { 1827a1645ce1SZhang, Yanmin pr_debug("Guest kernel map hasn't the point to groups\n"); 1828a1645ce1SZhang, Yanmin return -1; 1829a1645ce1SZhang, Yanmin } 1830a1645ce1SZhang, Yanmin kerninfo = map->groups->this_kerninfo; 1831a1645ce1SZhang, Yanmin 1832a1645ce1SZhang, Yanmin if (is_default_guest(kerninfo)) { 1833a1645ce1SZhang, Yanmin /* 1834a1645ce1SZhang, Yanmin * if the user specified a vmlinux filename, use it and only 1835a1645ce1SZhang, Yanmin * it, reporting errors to the user if it cannot be used. 1836a1645ce1SZhang, Yanmin * Or use file guest_kallsyms inputted by user on commandline 1837a1645ce1SZhang, Yanmin */ 1838a1645ce1SZhang, Yanmin if (symbol_conf.default_guest_vmlinux_name != NULL) { 1839a1645ce1SZhang, Yanmin err = dso__load_vmlinux(self, map, 1840a1645ce1SZhang, Yanmin symbol_conf.default_guest_vmlinux_name, filter); 1841a1645ce1SZhang, Yanmin goto out_try_fixup; 1842a1645ce1SZhang, Yanmin } 1843a1645ce1SZhang, Yanmin 1844a1645ce1SZhang, Yanmin kallsyms_filename = symbol_conf.default_guest_kallsyms; 1845a1645ce1SZhang, Yanmin if (!kallsyms_filename) 1846a1645ce1SZhang, Yanmin return -1; 1847a1645ce1SZhang, Yanmin } else { 1848a1645ce1SZhang, Yanmin sprintf(path, "%s/proc/kallsyms", kerninfo->root_dir); 1849a1645ce1SZhang, Yanmin kallsyms_filename = path; 1850a1645ce1SZhang, Yanmin } 1851a1645ce1SZhang, Yanmin 1852a1645ce1SZhang, Yanmin err = dso__load_kallsyms(self, kallsyms_filename, map, filter); 1853a1645ce1SZhang, Yanmin if (err > 0) 1854a1645ce1SZhang, Yanmin pr_debug("Using %s for symbols\n", kallsyms_filename); 1855a1645ce1SZhang, Yanmin 1856a1645ce1SZhang, Yanmin out_try_fixup: 1857a1645ce1SZhang, Yanmin if (err > 0) { 1858a1645ce1SZhang, Yanmin if (kallsyms_filename != NULL) { 1859a1645ce1SZhang, Yanmin kern_mmap_name(kerninfo, path); 1860a1645ce1SZhang, Yanmin dso__set_long_name(self, 1861a1645ce1SZhang, Yanmin strdup(path)); 1862a1645ce1SZhang, Yanmin } 1863a1645ce1SZhang, Yanmin map__fixup_start(map); 1864a1645ce1SZhang, Yanmin map__fixup_end(map); 1865a1645ce1SZhang, Yanmin } 1866a1645ce1SZhang, Yanmin 1867a1645ce1SZhang, Yanmin return err; 1868a1645ce1SZhang, Yanmin } 1869cd84c2acSFrederic Weisbecker 1870b0da954aSArnaldo Carvalho de Melo static void dsos__add(struct list_head *head, struct dso *dso) 1871cd84c2acSFrederic Weisbecker { 1872b0da954aSArnaldo Carvalho de Melo list_add_tail(&dso->node, head); 1873cd84c2acSFrederic Weisbecker } 1874cd84c2acSFrederic Weisbecker 1875b0da954aSArnaldo Carvalho de Melo static struct dso *dsos__find(struct list_head *head, const char *name) 1876cd84c2acSFrederic Weisbecker { 1877cd84c2acSFrederic Weisbecker struct dso *pos; 1878cd84c2acSFrederic Weisbecker 1879b0da954aSArnaldo Carvalho de Melo list_for_each_entry(pos, head, node) 1880cf4e5b08SArnaldo Carvalho de Melo if (strcmp(pos->long_name, name) == 0) 1881cd84c2acSFrederic Weisbecker return pos; 1882cd84c2acSFrederic Weisbecker return NULL; 1883cd84c2acSFrederic Weisbecker } 1884cd84c2acSFrederic Weisbecker 1885a89e5abeSArnaldo Carvalho de Melo struct dso *__dsos__findnew(struct list_head *head, const char *name) 1886cd84c2acSFrederic Weisbecker { 1887a89e5abeSArnaldo Carvalho de Melo struct dso *dso = dsos__find(head, name); 1888cd84c2acSFrederic Weisbecker 1889e4204992SArnaldo Carvalho de Melo if (!dso) { 189000a192b3SArnaldo Carvalho de Melo dso = dso__new(name); 1891cfc10d3bSArnaldo Carvalho de Melo if (dso != NULL) { 1892a89e5abeSArnaldo Carvalho de Melo dsos__add(head, dso); 1893cfc10d3bSArnaldo Carvalho de Melo dso__set_basename(dso); 1894cfc10d3bSArnaldo Carvalho de Melo } 1895e4204992SArnaldo Carvalho de Melo } 1896cd84c2acSFrederic Weisbecker 1897cd84c2acSFrederic Weisbecker return dso; 1898cd84c2acSFrederic Weisbecker } 1899cd84c2acSFrederic Weisbecker 1900b0da954aSArnaldo Carvalho de Melo static void __dsos__fprintf(struct list_head *head, FILE *fp) 1901cd84c2acSFrederic Weisbecker { 1902cd84c2acSFrederic Weisbecker struct dso *pos; 1903cd84c2acSFrederic Weisbecker 190495011c60SArnaldo Carvalho de Melo list_for_each_entry(pos, head, node) { 190595011c60SArnaldo Carvalho de Melo int i; 190695011c60SArnaldo Carvalho de Melo for (i = 0; i < MAP__NR_TYPES; ++i) 190795011c60SArnaldo Carvalho de Melo dso__fprintf(pos, i, fp); 190895011c60SArnaldo Carvalho de Melo } 1909cd84c2acSFrederic Weisbecker } 1910cd84c2acSFrederic Weisbecker 1911a1645ce1SZhang, Yanmin void dsos__fprintf(struct rb_root *kerninfo_root, FILE *fp) 1912b0da954aSArnaldo Carvalho de Melo { 1913a1645ce1SZhang, Yanmin struct rb_node *nd; 1914a1645ce1SZhang, Yanmin 1915a1645ce1SZhang, Yanmin for (nd = rb_first(kerninfo_root); nd; nd = rb_next(nd)) { 1916a1645ce1SZhang, Yanmin struct kernel_info *pos = rb_entry(nd, struct kernel_info, 1917a1645ce1SZhang, Yanmin rb_node); 1918a1645ce1SZhang, Yanmin __dsos__fprintf(&pos->dsos__kernel, fp); 1919a1645ce1SZhang, Yanmin __dsos__fprintf(&pos->dsos__user, fp); 1920a1645ce1SZhang, Yanmin } 1921b0da954aSArnaldo Carvalho de Melo } 1922b0da954aSArnaldo Carvalho de Melo 192388d3d9b7SArnaldo Carvalho de Melo static size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp, 192488d3d9b7SArnaldo Carvalho de Melo bool with_hits) 19259e03eb2dSArnaldo Carvalho de Melo { 19269e03eb2dSArnaldo Carvalho de Melo struct dso *pos; 19279e03eb2dSArnaldo Carvalho de Melo size_t ret = 0; 19289e03eb2dSArnaldo Carvalho de Melo 1929b0da954aSArnaldo Carvalho de Melo list_for_each_entry(pos, head, node) { 193088d3d9b7SArnaldo Carvalho de Melo if (with_hits && !pos->hit) 193188d3d9b7SArnaldo Carvalho de Melo continue; 19329e03eb2dSArnaldo Carvalho de Melo ret += dso__fprintf_buildid(pos, fp); 19339e03eb2dSArnaldo Carvalho de Melo ret += fprintf(fp, " %s\n", pos->long_name); 19349e03eb2dSArnaldo Carvalho de Melo } 19359e03eb2dSArnaldo Carvalho de Melo return ret; 19369e03eb2dSArnaldo Carvalho de Melo } 19379e03eb2dSArnaldo Carvalho de Melo 1938a1645ce1SZhang, Yanmin size_t dsos__fprintf_buildid(struct rb_root *kerninfo_root, 1939a1645ce1SZhang, Yanmin FILE *fp, bool with_hits) 1940b0da954aSArnaldo Carvalho de Melo { 1941a1645ce1SZhang, Yanmin struct rb_node *nd; 1942a1645ce1SZhang, Yanmin size_t ret = 0; 1943a1645ce1SZhang, Yanmin 1944a1645ce1SZhang, Yanmin for (nd = rb_first(kerninfo_root); nd; nd = rb_next(nd)) { 1945a1645ce1SZhang, Yanmin struct kernel_info *pos = rb_entry(nd, struct kernel_info, 1946a1645ce1SZhang, Yanmin rb_node); 1947a1645ce1SZhang, Yanmin ret += __dsos__fprintf_buildid(&pos->dsos__kernel, 1948a1645ce1SZhang, Yanmin fp, with_hits); 1949a1645ce1SZhang, Yanmin ret += __dsos__fprintf_buildid(&pos->dsos__user, 1950a1645ce1SZhang, Yanmin fp, with_hits); 1951a1645ce1SZhang, Yanmin } 1952a1645ce1SZhang, Yanmin return ret; 1953b0da954aSArnaldo Carvalho de Melo } 1954b0da954aSArnaldo Carvalho de Melo 1955fd1d908cSArnaldo Carvalho de Melo struct dso *dso__new_kernel(const char *name) 1956fd1d908cSArnaldo Carvalho de Melo { 1957fd1d908cSArnaldo Carvalho de Melo struct dso *self = dso__new(name ?: "[kernel.kallsyms]"); 1958fd1d908cSArnaldo Carvalho de Melo 1959fd1d908cSArnaldo Carvalho de Melo if (self != NULL) { 1960b63be8d7SArnaldo Carvalho de Melo dso__set_short_name(self, "[kernel]"); 1961a1645ce1SZhang, Yanmin self->kernel = DSO_TYPE_KERNEL; 1962fd1d908cSArnaldo Carvalho de Melo } 1963fd1d908cSArnaldo Carvalho de Melo 1964fd1d908cSArnaldo Carvalho de Melo return self; 1965fd1d908cSArnaldo Carvalho de Melo } 1966fd1d908cSArnaldo Carvalho de Melo 1967a1645ce1SZhang, Yanmin static struct dso *dso__new_guest_kernel(struct kernel_info *kerninfo, 1968a1645ce1SZhang, Yanmin const char *name) 1969fd1d908cSArnaldo Carvalho de Melo { 1970a1645ce1SZhang, Yanmin char buff[PATH_MAX]; 1971a1645ce1SZhang, Yanmin struct dso *self; 1972a1645ce1SZhang, Yanmin 1973a1645ce1SZhang, Yanmin kern_mmap_name(kerninfo, buff); 1974a1645ce1SZhang, Yanmin self = dso__new(name ?: buff); 1975a1645ce1SZhang, Yanmin if (self != NULL) { 1976a1645ce1SZhang, Yanmin dso__set_short_name(self, "[guest.kernel]"); 1977a1645ce1SZhang, Yanmin self->kernel = DSO_TYPE_GUEST_KERNEL; 1978a1645ce1SZhang, Yanmin } 1979a1645ce1SZhang, Yanmin 1980a1645ce1SZhang, Yanmin return self; 1981a1645ce1SZhang, Yanmin } 1982a1645ce1SZhang, Yanmin 1983a1645ce1SZhang, Yanmin void dso__read_running_kernel_build_id(struct dso *self, 1984a1645ce1SZhang, Yanmin struct kernel_info *kerninfo) 1985a1645ce1SZhang, Yanmin { 1986a1645ce1SZhang, Yanmin char path[PATH_MAX]; 1987a1645ce1SZhang, Yanmin 1988a1645ce1SZhang, Yanmin if (is_default_guest(kerninfo)) 1989a1645ce1SZhang, Yanmin return; 1990a1645ce1SZhang, Yanmin sprintf(path, "%s/sys/kernel/notes", kerninfo->root_dir); 1991a1645ce1SZhang, Yanmin if (sysfs__read_build_id(path, self->build_id, 1992fd1d908cSArnaldo Carvalho de Melo sizeof(self->build_id)) == 0) 1993fd1d908cSArnaldo Carvalho de Melo self->has_build_id = true; 1994fd1d908cSArnaldo Carvalho de Melo } 1995fd1d908cSArnaldo Carvalho de Melo 1996a1645ce1SZhang, Yanmin static struct dso *dsos__create_kernel(struct kernel_info *kerninfo) 1997cd84c2acSFrederic Weisbecker { 1998a1645ce1SZhang, Yanmin const char *vmlinux_name = NULL; 1999a1645ce1SZhang, Yanmin struct dso *kernel; 2000cd84c2acSFrederic Weisbecker 2001a1645ce1SZhang, Yanmin if (is_host_kernel(kerninfo)) { 2002a1645ce1SZhang, Yanmin vmlinux_name = symbol_conf.vmlinux_name; 2003a1645ce1SZhang, Yanmin kernel = dso__new_kernel(vmlinux_name); 2004a1645ce1SZhang, Yanmin } else { 2005a1645ce1SZhang, Yanmin if (is_default_guest(kerninfo)) 2006a1645ce1SZhang, Yanmin vmlinux_name = symbol_conf.default_guest_vmlinux_name; 2007a1645ce1SZhang, Yanmin kernel = dso__new_guest_kernel(kerninfo, vmlinux_name); 20088d92c02aSArnaldo Carvalho de Melo } 2009cd84c2acSFrederic Weisbecker 2010a1645ce1SZhang, Yanmin if (kernel != NULL) { 2011a1645ce1SZhang, Yanmin dso__read_running_kernel_build_id(kernel, kerninfo); 2012a1645ce1SZhang, Yanmin dsos__add(&kerninfo->dsos__kernel, kernel); 2013a1645ce1SZhang, Yanmin } 2014f1dfa0b1SArnaldo Carvalho de Melo return kernel; 2015f1dfa0b1SArnaldo Carvalho de Melo } 2016f1dfa0b1SArnaldo Carvalho de Melo 2017b7cece76SArnaldo Carvalho de Melo int __map_groups__create_kernel_maps(struct map_groups *self, 2018de176489SArnaldo Carvalho de Melo struct map *vmlinux_maps[MAP__NR_TYPES], 2019b7cece76SArnaldo Carvalho de Melo struct dso *kernel) 2020f1dfa0b1SArnaldo Carvalho de Melo { 2021de176489SArnaldo Carvalho de Melo enum map_type type; 2022f1dfa0b1SArnaldo Carvalho de Melo 2023de176489SArnaldo Carvalho de Melo for (type = 0; type < MAP__NR_TYPES; ++type) { 20249de89fe7SArnaldo Carvalho de Melo struct kmap *kmap; 20259de89fe7SArnaldo Carvalho de Melo 2026de176489SArnaldo Carvalho de Melo vmlinux_maps[type] = map__new2(0, kernel, type); 2027de176489SArnaldo Carvalho de Melo if (vmlinux_maps[type] == NULL) 2028f1dfa0b1SArnaldo Carvalho de Melo return -1; 2029f1dfa0b1SArnaldo Carvalho de Melo 2030de176489SArnaldo Carvalho de Melo vmlinux_maps[type]->map_ip = 2031de176489SArnaldo Carvalho de Melo vmlinux_maps[type]->unmap_ip = identity__map_ip; 20329de89fe7SArnaldo Carvalho de Melo 20339de89fe7SArnaldo Carvalho de Melo kmap = map__kmap(vmlinux_maps[type]); 20349de89fe7SArnaldo Carvalho de Melo kmap->kmaps = self; 2035de176489SArnaldo Carvalho de Melo map_groups__insert(self, vmlinux_maps[type]); 2036f1dfa0b1SArnaldo Carvalho de Melo } 2037f1dfa0b1SArnaldo Carvalho de Melo 2038f1dfa0b1SArnaldo Carvalho de Melo return 0; 20392446042cSArnaldo Carvalho de Melo } 20402446042cSArnaldo Carvalho de Melo 2041cc612d81SArnaldo Carvalho de Melo static void vmlinux_path__exit(void) 20422446042cSArnaldo Carvalho de Melo { 2043cc612d81SArnaldo Carvalho de Melo while (--vmlinux_path__nr_entries >= 0) { 2044cc612d81SArnaldo Carvalho de Melo free(vmlinux_path[vmlinux_path__nr_entries]); 2045cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = NULL; 2046cc612d81SArnaldo Carvalho de Melo } 2047cc612d81SArnaldo Carvalho de Melo 2048cc612d81SArnaldo Carvalho de Melo free(vmlinux_path); 2049cc612d81SArnaldo Carvalho de Melo vmlinux_path = NULL; 2050cc612d81SArnaldo Carvalho de Melo } 2051cc612d81SArnaldo Carvalho de Melo 2052cc612d81SArnaldo Carvalho de Melo static int vmlinux_path__init(void) 2053cc612d81SArnaldo Carvalho de Melo { 2054cc612d81SArnaldo Carvalho de Melo struct utsname uts; 2055cc612d81SArnaldo Carvalho de Melo char bf[PATH_MAX]; 2056cc612d81SArnaldo Carvalho de Melo 2057cc612d81SArnaldo Carvalho de Melo if (uname(&uts) < 0) 20582446042cSArnaldo Carvalho de Melo return -1; 20592446042cSArnaldo Carvalho de Melo 2060cc612d81SArnaldo Carvalho de Melo vmlinux_path = malloc(sizeof(char *) * 5); 2061cc612d81SArnaldo Carvalho de Melo if (vmlinux_path == NULL) 2062cc612d81SArnaldo Carvalho de Melo return -1; 2063cc612d81SArnaldo Carvalho de Melo 2064cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup("vmlinux"); 2065cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 2066cc612d81SArnaldo Carvalho de Melo goto out_fail; 2067cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 2068cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup("/boot/vmlinux"); 2069cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 2070cc612d81SArnaldo Carvalho de Melo goto out_fail; 2071cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 2072cc612d81SArnaldo Carvalho de Melo snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", uts.release); 2073cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); 2074cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 2075cc612d81SArnaldo Carvalho de Melo goto out_fail; 2076cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 2077cc612d81SArnaldo Carvalho de Melo snprintf(bf, sizeof(bf), "/lib/modules/%s/build/vmlinux", uts.release); 2078cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); 2079cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 2080cc612d81SArnaldo Carvalho de Melo goto out_fail; 2081cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 2082cc612d81SArnaldo Carvalho de Melo snprintf(bf, sizeof(bf), "/usr/lib/debug/lib/modules/%s/vmlinux", 2083cc612d81SArnaldo Carvalho de Melo uts.release); 2084cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); 2085cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 2086cc612d81SArnaldo Carvalho de Melo goto out_fail; 2087cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 2088cc612d81SArnaldo Carvalho de Melo 2089cc612d81SArnaldo Carvalho de Melo return 0; 2090cc612d81SArnaldo Carvalho de Melo 2091cc612d81SArnaldo Carvalho de Melo out_fail: 2092cc612d81SArnaldo Carvalho de Melo vmlinux_path__exit(); 2093cc612d81SArnaldo Carvalho de Melo return -1; 2094cc612d81SArnaldo Carvalho de Melo } 2095cc612d81SArnaldo Carvalho de Melo 2096b0a9ab62SArnaldo Carvalho de Melo size_t vmlinux_path__fprintf(FILE *fp) 2097b0a9ab62SArnaldo Carvalho de Melo { 2098b0a9ab62SArnaldo Carvalho de Melo int i; 2099b0a9ab62SArnaldo Carvalho de Melo size_t printed = 0; 2100b0a9ab62SArnaldo Carvalho de Melo 2101b0a9ab62SArnaldo Carvalho de Melo for (i = 0; i < vmlinux_path__nr_entries; ++i) 2102b0a9ab62SArnaldo Carvalho de Melo printed += fprintf(fp, "[%d] %s\n", i, vmlinux_path[i]); 2103b0a9ab62SArnaldo Carvalho de Melo 2104b0a9ab62SArnaldo Carvalho de Melo return printed; 2105b0a9ab62SArnaldo Carvalho de Melo } 2106b0a9ab62SArnaldo Carvalho de Melo 2107655000e7SArnaldo Carvalho de Melo static int setup_list(struct strlist **list, const char *list_str, 2108655000e7SArnaldo Carvalho de Melo const char *list_name) 2109655000e7SArnaldo Carvalho de Melo { 2110655000e7SArnaldo Carvalho de Melo if (list_str == NULL) 2111655000e7SArnaldo Carvalho de Melo return 0; 2112655000e7SArnaldo Carvalho de Melo 2113655000e7SArnaldo Carvalho de Melo *list = strlist__new(true, list_str); 2114655000e7SArnaldo Carvalho de Melo if (!*list) { 2115655000e7SArnaldo Carvalho de Melo pr_err("problems parsing %s list\n", list_name); 2116655000e7SArnaldo Carvalho de Melo return -1; 2117655000e7SArnaldo Carvalho de Melo } 2118655000e7SArnaldo Carvalho de Melo return 0; 2119655000e7SArnaldo Carvalho de Melo } 2120655000e7SArnaldo Carvalho de Melo 212175be6cf4SArnaldo Carvalho de Melo int symbol__init(void) 2122cc612d81SArnaldo Carvalho de Melo { 212395011c60SArnaldo Carvalho de Melo elf_version(EV_CURRENT); 212475be6cf4SArnaldo Carvalho de Melo if (symbol_conf.sort_by_name) 212575be6cf4SArnaldo Carvalho de Melo symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) - 212679406cd7SArnaldo Carvalho de Melo sizeof(struct symbol)); 2127b32d133aSArnaldo Carvalho de Melo 212875be6cf4SArnaldo Carvalho de Melo if (symbol_conf.try_vmlinux_path && vmlinux_path__init() < 0) 2129cc612d81SArnaldo Carvalho de Melo return -1; 2130cc612d81SArnaldo Carvalho de Melo 2131c410a338SArnaldo Carvalho de Melo if (symbol_conf.field_sep && *symbol_conf.field_sep == '.') { 2132c410a338SArnaldo Carvalho de Melo pr_err("'.' is the only non valid --field-separator argument\n"); 2133c410a338SArnaldo Carvalho de Melo return -1; 2134c410a338SArnaldo Carvalho de Melo } 2135c410a338SArnaldo Carvalho de Melo 2136655000e7SArnaldo Carvalho de Melo if (setup_list(&symbol_conf.dso_list, 2137655000e7SArnaldo Carvalho de Melo symbol_conf.dso_list_str, "dso") < 0) 2138655000e7SArnaldo Carvalho de Melo return -1; 2139655000e7SArnaldo Carvalho de Melo 2140655000e7SArnaldo Carvalho de Melo if (setup_list(&symbol_conf.comm_list, 2141655000e7SArnaldo Carvalho de Melo symbol_conf.comm_list_str, "comm") < 0) 2142655000e7SArnaldo Carvalho de Melo goto out_free_dso_list; 2143655000e7SArnaldo Carvalho de Melo 2144655000e7SArnaldo Carvalho de Melo if (setup_list(&symbol_conf.sym_list, 2145655000e7SArnaldo Carvalho de Melo symbol_conf.sym_list_str, "symbol") < 0) 2146655000e7SArnaldo Carvalho de Melo goto out_free_comm_list; 2147655000e7SArnaldo Carvalho de Melo 21484aa65636SArnaldo Carvalho de Melo return 0; 2149655000e7SArnaldo Carvalho de Melo 2150655000e7SArnaldo Carvalho de Melo out_free_dso_list: 2151655000e7SArnaldo Carvalho de Melo strlist__delete(symbol_conf.dso_list); 2152655000e7SArnaldo Carvalho de Melo out_free_comm_list: 2153655000e7SArnaldo Carvalho de Melo strlist__delete(symbol_conf.comm_list); 2154655000e7SArnaldo Carvalho de Melo return -1; 2155cc612d81SArnaldo Carvalho de Melo } 2156cc612d81SArnaldo Carvalho de Melo 2157a1645ce1SZhang, Yanmin int map_groups__create_kernel_maps(struct rb_root *kerninfo_root, pid_t pid) 21584aa65636SArnaldo Carvalho de Melo { 2159a1645ce1SZhang, Yanmin struct kernel_info *kerninfo; 2160a1645ce1SZhang, Yanmin struct dso *kernel; 21619de89fe7SArnaldo Carvalho de Melo 2162a1645ce1SZhang, Yanmin kerninfo = kerninfo__findnew(kerninfo_root, pid); 2163a1645ce1SZhang, Yanmin if (kerninfo == NULL) 2164a1645ce1SZhang, Yanmin return -1; 2165a1645ce1SZhang, Yanmin kernel = dsos__create_kernel(kerninfo); 21669de89fe7SArnaldo Carvalho de Melo if (kernel == NULL) 21674aa65636SArnaldo Carvalho de Melo return -1; 21684aa65636SArnaldo Carvalho de Melo 2169a1645ce1SZhang, Yanmin if (__map_groups__create_kernel_maps(&kerninfo->kmaps, 2170a1645ce1SZhang, Yanmin kerninfo->vmlinux_maps, kernel) < 0) 21719de89fe7SArnaldo Carvalho de Melo return -1; 21729de89fe7SArnaldo Carvalho de Melo 2173a1645ce1SZhang, Yanmin if (symbol_conf.use_modules && 2174a1645ce1SZhang, Yanmin map_groups__create_modules(kerninfo) < 0) 217510fe12efSArnaldo Carvalho de Melo pr_debug("Problems creating module maps, continuing anyway...\n"); 217690c83218SArnaldo Carvalho de Melo /* 217790c83218SArnaldo Carvalho de Melo * Now that we have all the maps created, just set the ->end of them: 217890c83218SArnaldo Carvalho de Melo */ 2179a1645ce1SZhang, Yanmin map_groups__fixup_end(&kerninfo->kmaps); 21806671cb16SArnaldo Carvalho de Melo return 0; 2181cd84c2acSFrederic Weisbecker } 21825aab621bSArnaldo Carvalho de Melo 21835aab621bSArnaldo Carvalho de Melo static int hex(char ch) 21845aab621bSArnaldo Carvalho de Melo { 21855aab621bSArnaldo Carvalho de Melo if ((ch >= '0') && (ch <= '9')) 21865aab621bSArnaldo Carvalho de Melo return ch - '0'; 21875aab621bSArnaldo Carvalho de Melo if ((ch >= 'a') && (ch <= 'f')) 21885aab621bSArnaldo Carvalho de Melo return ch - 'a' + 10; 21895aab621bSArnaldo Carvalho de Melo if ((ch >= 'A') && (ch <= 'F')) 21905aab621bSArnaldo Carvalho de Melo return ch - 'A' + 10; 21915aab621bSArnaldo Carvalho de Melo return -1; 21925aab621bSArnaldo Carvalho de Melo } 21935aab621bSArnaldo Carvalho de Melo 21945aab621bSArnaldo Carvalho de Melo /* 21955aab621bSArnaldo Carvalho de Melo * While we find nice hex chars, build a long_val. 21965aab621bSArnaldo Carvalho de Melo * Return number of chars processed. 21975aab621bSArnaldo Carvalho de Melo */ 21985aab621bSArnaldo Carvalho de Melo int hex2u64(const char *ptr, u64 *long_val) 21995aab621bSArnaldo Carvalho de Melo { 22005aab621bSArnaldo Carvalho de Melo const char *p = ptr; 22015aab621bSArnaldo Carvalho de Melo *long_val = 0; 22025aab621bSArnaldo Carvalho de Melo 22035aab621bSArnaldo Carvalho de Melo while (*p) { 22045aab621bSArnaldo Carvalho de Melo const int hex_val = hex(*p); 22055aab621bSArnaldo Carvalho de Melo 22065aab621bSArnaldo Carvalho de Melo if (hex_val < 0) 22075aab621bSArnaldo Carvalho de Melo break; 22085aab621bSArnaldo Carvalho de Melo 22095aab621bSArnaldo Carvalho de Melo *long_val = (*long_val << 4) | hex_val; 22105aab621bSArnaldo Carvalho de Melo p++; 22115aab621bSArnaldo Carvalho de Melo } 22125aab621bSArnaldo Carvalho de Melo 22135aab621bSArnaldo Carvalho de Melo return p - ptr; 22145aab621bSArnaldo Carvalho de Melo } 22155aab621bSArnaldo Carvalho de Melo 22165aab621bSArnaldo Carvalho de Melo char *strxfrchar(char *s, char from, char to) 22175aab621bSArnaldo Carvalho de Melo { 22185aab621bSArnaldo Carvalho de Melo char *p = s; 22195aab621bSArnaldo Carvalho de Melo 22205aab621bSArnaldo Carvalho de Melo while ((p = strchr(p, from)) != NULL) 22215aab621bSArnaldo Carvalho de Melo *p++ = to; 22225aab621bSArnaldo Carvalho de Melo 22235aab621bSArnaldo Carvalho de Melo return s; 22245aab621bSArnaldo Carvalho de Melo } 2225a1645ce1SZhang, Yanmin 2226a1645ce1SZhang, Yanmin int map_groups__create_guest_kernel_maps(struct rb_root *kerninfo_root) 2227a1645ce1SZhang, Yanmin { 2228a1645ce1SZhang, Yanmin int ret = 0; 2229a1645ce1SZhang, Yanmin struct dirent **namelist = NULL; 2230a1645ce1SZhang, Yanmin int i, items = 0; 2231a1645ce1SZhang, Yanmin char path[PATH_MAX]; 2232a1645ce1SZhang, Yanmin pid_t pid; 2233a1645ce1SZhang, Yanmin 2234a1645ce1SZhang, Yanmin if (symbol_conf.default_guest_vmlinux_name || 2235a1645ce1SZhang, Yanmin symbol_conf.default_guest_modules || 2236a1645ce1SZhang, Yanmin symbol_conf.default_guest_kallsyms) { 2237a1645ce1SZhang, Yanmin map_groups__create_kernel_maps(kerninfo_root, 2238a1645ce1SZhang, Yanmin DEFAULT_GUEST_KERNEL_ID); 2239a1645ce1SZhang, Yanmin } 2240a1645ce1SZhang, Yanmin 2241a1645ce1SZhang, Yanmin if (symbol_conf.guestmount) { 2242a1645ce1SZhang, Yanmin items = scandir(symbol_conf.guestmount, &namelist, NULL, NULL); 2243a1645ce1SZhang, Yanmin if (items <= 0) 2244a1645ce1SZhang, Yanmin return -ENOENT; 2245a1645ce1SZhang, Yanmin for (i = 0; i < items; i++) { 2246a1645ce1SZhang, Yanmin if (!isdigit(namelist[i]->d_name[0])) { 2247a1645ce1SZhang, Yanmin /* Filter out . and .. */ 2248a1645ce1SZhang, Yanmin continue; 2249a1645ce1SZhang, Yanmin } 2250a1645ce1SZhang, Yanmin pid = atoi(namelist[i]->d_name); 2251a1645ce1SZhang, Yanmin sprintf(path, "%s/%s/proc/kallsyms", 2252a1645ce1SZhang, Yanmin symbol_conf.guestmount, 2253a1645ce1SZhang, Yanmin namelist[i]->d_name); 2254a1645ce1SZhang, Yanmin ret = access(path, R_OK); 2255a1645ce1SZhang, Yanmin if (ret) { 2256a1645ce1SZhang, Yanmin pr_debug("Can't access file %s\n", path); 2257a1645ce1SZhang, Yanmin goto failure; 2258a1645ce1SZhang, Yanmin } 2259a1645ce1SZhang, Yanmin map_groups__create_kernel_maps(kerninfo_root, 2260a1645ce1SZhang, Yanmin pid); 2261a1645ce1SZhang, Yanmin } 2262a1645ce1SZhang, Yanmin failure: 2263a1645ce1SZhang, Yanmin free(namelist); 2264a1645ce1SZhang, Yanmin } 2265a1645ce1SZhang, Yanmin 2266a1645ce1SZhang, Yanmin return ret; 2267a1645ce1SZhang, Yanmin } 2268