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> 14b36f19d5SArnaldo Carvalho de Melo #include "build-id.h" 158a6c5b26SArnaldo Carvalho de Melo #include "debug.h" 1686470930SIngo Molnar #include "symbol.h" 175aab621bSArnaldo Carvalho de Melo #include "strlist.h" 1886470930SIngo Molnar 1986470930SIngo Molnar #include <libelf.h> 2086470930SIngo Molnar #include <gelf.h> 2186470930SIngo Molnar #include <elf.h> 22f1617b40SArnaldo Carvalho de Melo #include <limits.h> 23439d473bSArnaldo Carvalho de Melo #include <sys/utsname.h> 242cdbc46dSPeter Zijlstra 25c12e15e7SArnaldo Carvalho de Melo #ifndef NT_GNU_BUILD_ID 26c12e15e7SArnaldo Carvalho de Melo #define NT_GNU_BUILD_ID 3 27c12e15e7SArnaldo Carvalho de Melo #endif 28c12e15e7SArnaldo Carvalho de Melo 2921916c38SDave Martin static bool dso__build_id_equal(const struct dso *self, u8 *build_id); 3021916c38SDave Martin static int elf_read_build_id(Elf *elf, void *bf, size_t size); 31b0da954aSArnaldo Carvalho de Melo static void dsos__add(struct list_head *head, struct dso *dso); 323610583cSArnaldo Carvalho de Melo static struct map *map__new2(u64 start, struct dso *dso, enum map_type type); 33c338aee8SArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *self, struct map *map, 349de89fe7SArnaldo Carvalho de Melo symbol_filter_t filter); 35a1645ce1SZhang, Yanmin static int dso__load_guest_kernel_sym(struct dso *self, struct map *map, 36a1645ce1SZhang, Yanmin symbol_filter_t filter); 37cc612d81SArnaldo Carvalho de Melo static int vmlinux_path__nr_entries; 38cc612d81SArnaldo Carvalho de Melo static char **vmlinux_path; 39439d473bSArnaldo Carvalho de Melo 4075be6cf4SArnaldo Carvalho de Melo struct symbol_conf symbol_conf = { 41d599db3fSArnaldo Carvalho de Melo .exclude_other = true, 42b32d133aSArnaldo Carvalho de Melo .use_modules = true, 43b32d133aSArnaldo Carvalho de Melo .try_vmlinux_path = true, 44*ec5761eaSDavid Ahern .symfs = "", 45b32d133aSArnaldo Carvalho de Melo }; 46b32d133aSArnaldo Carvalho de Melo 478a6c5b26SArnaldo Carvalho de Melo int dso__name_len(const struct dso *self) 488a6c5b26SArnaldo Carvalho de Melo { 498a6c5b26SArnaldo Carvalho de Melo if (verbose) 508a6c5b26SArnaldo Carvalho de Melo return self->long_name_len; 518a6c5b26SArnaldo Carvalho de Melo 528a6c5b26SArnaldo Carvalho de Melo return self->short_name_len; 538a6c5b26SArnaldo Carvalho de Melo } 548a6c5b26SArnaldo Carvalho de Melo 553610583cSArnaldo Carvalho de Melo bool dso__loaded(const struct dso *self, enum map_type type) 563610583cSArnaldo Carvalho de Melo { 573610583cSArnaldo Carvalho de Melo return self->loaded & (1 << type); 583610583cSArnaldo Carvalho de Melo } 593610583cSArnaldo Carvalho de Melo 6079406cd7SArnaldo Carvalho de Melo bool dso__sorted_by_name(const struct dso *self, enum map_type type) 6179406cd7SArnaldo Carvalho de Melo { 6279406cd7SArnaldo Carvalho de Melo return self->sorted_by_name & (1 << type); 6379406cd7SArnaldo Carvalho de Melo } 6479406cd7SArnaldo Carvalho de Melo 6579406cd7SArnaldo Carvalho de Melo static void dso__set_sorted_by_name(struct dso *self, enum map_type type) 6679406cd7SArnaldo Carvalho de Melo { 6779406cd7SArnaldo Carvalho de Melo self->sorted_by_name |= (1 << type); 6879406cd7SArnaldo Carvalho de Melo } 6979406cd7SArnaldo Carvalho de Melo 7036a3e646SArnaldo Carvalho de Melo bool symbol_type__is_a(char symbol_type, enum map_type map_type) 716893d4eeSArnaldo Carvalho de Melo { 726893d4eeSArnaldo Carvalho de Melo switch (map_type) { 736893d4eeSArnaldo Carvalho de Melo case MAP__FUNCTION: 746893d4eeSArnaldo Carvalho de Melo return symbol_type == 'T' || symbol_type == 'W'; 75f1dfa0b1SArnaldo Carvalho de Melo case MAP__VARIABLE: 76f1dfa0b1SArnaldo Carvalho de Melo return symbol_type == 'D' || symbol_type == 'd'; 776893d4eeSArnaldo Carvalho de Melo default: 786893d4eeSArnaldo Carvalho de Melo return false; 796893d4eeSArnaldo Carvalho de Melo } 806893d4eeSArnaldo Carvalho de Melo } 816893d4eeSArnaldo Carvalho de Melo 82fcf1203aSArnaldo Carvalho de Melo static void symbols__fixup_end(struct rb_root *self) 83af427bf5SArnaldo Carvalho de Melo { 84fcf1203aSArnaldo Carvalho de Melo struct rb_node *nd, *prevnd = rb_first(self); 852e538c4aSArnaldo Carvalho de Melo struct symbol *curr, *prev; 86af427bf5SArnaldo Carvalho de Melo 87af427bf5SArnaldo Carvalho de Melo if (prevnd == NULL) 88af427bf5SArnaldo Carvalho de Melo return; 89af427bf5SArnaldo Carvalho de Melo 902e538c4aSArnaldo Carvalho de Melo curr = rb_entry(prevnd, struct symbol, rb_node); 912e538c4aSArnaldo Carvalho de Melo 92af427bf5SArnaldo Carvalho de Melo for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) { 932e538c4aSArnaldo Carvalho de Melo prev = curr; 942e538c4aSArnaldo Carvalho de Melo curr = rb_entry(nd, struct symbol, rb_node); 95af427bf5SArnaldo Carvalho de Melo 96af427bf5SArnaldo Carvalho de Melo if (prev->end == prev->start) 97af427bf5SArnaldo Carvalho de Melo prev->end = curr->start - 1; 98af427bf5SArnaldo Carvalho de Melo } 99af427bf5SArnaldo Carvalho de Melo 1002e538c4aSArnaldo Carvalho de Melo /* Last entry */ 1012e538c4aSArnaldo Carvalho de Melo if (curr->end == curr->start) 1022e538c4aSArnaldo Carvalho de Melo curr->end = roundup(curr->start, 4096); 1032e538c4aSArnaldo Carvalho de Melo } 1042e538c4aSArnaldo Carvalho de Melo 1059958e1f0SArnaldo Carvalho de Melo static void __map_groups__fixup_end(struct map_groups *self, enum map_type type) 106af427bf5SArnaldo Carvalho de Melo { 107af427bf5SArnaldo Carvalho de Melo struct map *prev, *curr; 10895011c60SArnaldo Carvalho de Melo struct rb_node *nd, *prevnd = rb_first(&self->maps[type]); 109af427bf5SArnaldo Carvalho de Melo 110af427bf5SArnaldo Carvalho de Melo if (prevnd == NULL) 111af427bf5SArnaldo Carvalho de Melo return; 112af427bf5SArnaldo Carvalho de Melo 113af427bf5SArnaldo Carvalho de Melo curr = rb_entry(prevnd, struct map, rb_node); 114af427bf5SArnaldo Carvalho de Melo 115af427bf5SArnaldo Carvalho de Melo for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) { 116af427bf5SArnaldo Carvalho de Melo prev = curr; 117af427bf5SArnaldo Carvalho de Melo curr = rb_entry(nd, struct map, rb_node); 118af427bf5SArnaldo Carvalho de Melo prev->end = curr->start - 1; 1192e538c4aSArnaldo Carvalho de Melo } 12090c83218SArnaldo Carvalho de Melo 12190c83218SArnaldo Carvalho de Melo /* 12290c83218SArnaldo Carvalho de Melo * We still haven't the actual symbols, so guess the 12390c83218SArnaldo Carvalho de Melo * last map final address. 12490c83218SArnaldo Carvalho de Melo */ 1259d1faba5SIan Munsie curr->end = ~0ULL; 126af427bf5SArnaldo Carvalho de Melo } 127af427bf5SArnaldo Carvalho de Melo 1289958e1f0SArnaldo Carvalho de Melo static void map_groups__fixup_end(struct map_groups *self) 12923ea4a3fSArnaldo Carvalho de Melo { 13023ea4a3fSArnaldo Carvalho de Melo int i; 13123ea4a3fSArnaldo Carvalho de Melo for (i = 0; i < MAP__NR_TYPES; ++i) 1329958e1f0SArnaldo Carvalho de Melo __map_groups__fixup_end(self, i); 13323ea4a3fSArnaldo Carvalho de Melo } 13423ea4a3fSArnaldo Carvalho de Melo 135c408fedfSArnaldo Carvalho de Melo static struct symbol *symbol__new(u64 start, u64 len, u8 binding, 136c408fedfSArnaldo Carvalho de Melo const char *name) 13786470930SIngo Molnar { 13886470930SIngo Molnar size_t namelen = strlen(name) + 1; 1395aab621bSArnaldo Carvalho de Melo struct symbol *self = calloc(1, (symbol_conf.priv_size + 1405aab621bSArnaldo Carvalho de Melo sizeof(*self) + namelen)); 14136479484SArnaldo Carvalho de Melo if (self == NULL) 14286470930SIngo Molnar return NULL; 14386470930SIngo Molnar 14475be6cf4SArnaldo Carvalho de Melo if (symbol_conf.priv_size) 14575be6cf4SArnaldo Carvalho de Melo self = ((void *)self) + symbol_conf.priv_size; 14636479484SArnaldo Carvalho de Melo 14786470930SIngo Molnar self->start = start; 1486cfcc53eSMike Galbraith self->end = len ? start + len - 1 : start; 149c408fedfSArnaldo Carvalho de Melo self->binding = binding; 150fefb0b94SArnaldo Carvalho de Melo self->namelen = namelen - 1; 151e4204992SArnaldo Carvalho de Melo 15229a9f66dSArnaldo Carvalho de Melo pr_debug4("%s: %s %#Lx-%#Lx\n", __func__, name, start, self->end); 153e4204992SArnaldo Carvalho de Melo 15486470930SIngo Molnar memcpy(self->name, name, namelen); 15586470930SIngo Molnar 15686470930SIngo Molnar return self; 15786470930SIngo Molnar } 15886470930SIngo Molnar 159628ada0cSArnaldo Carvalho de Melo void symbol__delete(struct symbol *self) 16086470930SIngo Molnar { 16175be6cf4SArnaldo Carvalho de Melo free(((void *)self) - symbol_conf.priv_size); 16286470930SIngo Molnar } 16386470930SIngo Molnar 16486470930SIngo Molnar static size_t symbol__fprintf(struct symbol *self, FILE *fp) 16586470930SIngo Molnar { 166c408fedfSArnaldo Carvalho de Melo return fprintf(fp, " %llx-%llx %c %s\n", 167c408fedfSArnaldo Carvalho de Melo self->start, self->end, 168c408fedfSArnaldo Carvalho de Melo self->binding == STB_GLOBAL ? 'g' : 169c408fedfSArnaldo Carvalho de Melo self->binding == STB_LOCAL ? 'l' : 'w', 170c408fedfSArnaldo Carvalho de Melo self->name); 17186470930SIngo Molnar } 17286470930SIngo Molnar 173b7cece76SArnaldo Carvalho de Melo void dso__set_long_name(struct dso *self, char *name) 174cfc10d3bSArnaldo Carvalho de Melo { 175ef6ae724SArnaldo Carvalho de Melo if (name == NULL) 176ef6ae724SArnaldo Carvalho de Melo return; 177cfc10d3bSArnaldo Carvalho de Melo self->long_name = name; 178cfc10d3bSArnaldo Carvalho de Melo self->long_name_len = strlen(name); 179cfc10d3bSArnaldo Carvalho de Melo } 180cfc10d3bSArnaldo Carvalho de Melo 181b63be8d7SArnaldo Carvalho de Melo static void dso__set_short_name(struct dso *self, const char *name) 182b63be8d7SArnaldo Carvalho de Melo { 183b63be8d7SArnaldo Carvalho de Melo if (name == NULL) 184b63be8d7SArnaldo Carvalho de Melo return; 185b63be8d7SArnaldo Carvalho de Melo self->short_name = name; 186b63be8d7SArnaldo Carvalho de Melo self->short_name_len = strlen(name); 187b63be8d7SArnaldo Carvalho de Melo } 188b63be8d7SArnaldo Carvalho de Melo 189cfc10d3bSArnaldo Carvalho de Melo static void dso__set_basename(struct dso *self) 190cfc10d3bSArnaldo Carvalho de Melo { 191b63be8d7SArnaldo Carvalho de Melo dso__set_short_name(self, basename(self->long_name)); 192cfc10d3bSArnaldo Carvalho de Melo } 193cfc10d3bSArnaldo Carvalho de Melo 19400a192b3SArnaldo Carvalho de Melo struct dso *dso__new(const char *name) 19586470930SIngo Molnar { 1965aab621bSArnaldo Carvalho de Melo struct dso *self = calloc(1, sizeof(*self) + strlen(name) + 1); 19786470930SIngo Molnar 19886470930SIngo Molnar if (self != NULL) { 1996a4694a4SArnaldo Carvalho de Melo int i; 20086470930SIngo Molnar strcpy(self->name, name); 201cfc10d3bSArnaldo Carvalho de Melo dso__set_long_name(self, self->name); 202b63be8d7SArnaldo Carvalho de Melo dso__set_short_name(self, self->name); 2036a4694a4SArnaldo Carvalho de Melo for (i = 0; i < MAP__NR_TYPES; ++i) 20479406cd7SArnaldo Carvalho de Melo self->symbols[i] = self->symbol_names[i] = RB_ROOT; 20552d422deSArnaldo Carvalho de Melo self->slen_calculated = 0; 20694cb9e38SArnaldo Carvalho de Melo self->origin = DSO__ORIG_NOT_FOUND; 2078d06367fSArnaldo Carvalho de Melo self->loaded = 0; 20879406cd7SArnaldo Carvalho de Melo self->sorted_by_name = 0; 2098d06367fSArnaldo Carvalho de Melo self->has_build_id = 0; 210a1645ce1SZhang, Yanmin self->kernel = DSO_TYPE_USER; 2110ab061cdSMasami Hiramatsu INIT_LIST_HEAD(&self->node); 21286470930SIngo Molnar } 21386470930SIngo Molnar 21486470930SIngo Molnar return self; 21586470930SIngo Molnar } 21686470930SIngo Molnar 217fcf1203aSArnaldo Carvalho de Melo static void symbols__delete(struct rb_root *self) 21886470930SIngo Molnar { 21986470930SIngo Molnar struct symbol *pos; 220fcf1203aSArnaldo Carvalho de Melo struct rb_node *next = rb_first(self); 22186470930SIngo Molnar 22286470930SIngo Molnar while (next) { 22386470930SIngo Molnar pos = rb_entry(next, struct symbol, rb_node); 22486470930SIngo Molnar next = rb_next(&pos->rb_node); 225fcf1203aSArnaldo Carvalho de Melo rb_erase(&pos->rb_node, self); 22600a192b3SArnaldo Carvalho de Melo symbol__delete(pos); 22786470930SIngo Molnar } 22886470930SIngo Molnar } 22986470930SIngo Molnar 23086470930SIngo Molnar void dso__delete(struct dso *self) 23186470930SIngo Molnar { 2326a4694a4SArnaldo Carvalho de Melo int i; 2336a4694a4SArnaldo Carvalho de Melo for (i = 0; i < MAP__NR_TYPES; ++i) 2346a4694a4SArnaldo Carvalho de Melo symbols__delete(&self->symbols[i]); 2356e406257SArnaldo Carvalho de Melo if (self->sname_alloc) 2366e406257SArnaldo Carvalho de Melo free((char *)self->short_name); 2376e406257SArnaldo Carvalho de Melo if (self->lname_alloc) 238439d473bSArnaldo Carvalho de Melo free(self->long_name); 23986470930SIngo Molnar free(self); 24086470930SIngo Molnar } 24186470930SIngo Molnar 2428d06367fSArnaldo Carvalho de Melo void dso__set_build_id(struct dso *self, void *build_id) 2438d06367fSArnaldo Carvalho de Melo { 2448d06367fSArnaldo Carvalho de Melo memcpy(self->build_id, build_id, sizeof(self->build_id)); 2458d06367fSArnaldo Carvalho de Melo self->has_build_id = 1; 2468d06367fSArnaldo Carvalho de Melo } 2478d06367fSArnaldo Carvalho de Melo 248fcf1203aSArnaldo Carvalho de Melo static void symbols__insert(struct rb_root *self, struct symbol *sym) 24986470930SIngo Molnar { 250fcf1203aSArnaldo Carvalho de Melo struct rb_node **p = &self->rb_node; 25186470930SIngo Molnar struct rb_node *parent = NULL; 2529cffa8d5SPaul Mackerras const u64 ip = sym->start; 25386470930SIngo Molnar struct symbol *s; 25486470930SIngo Molnar 25586470930SIngo Molnar while (*p != NULL) { 25686470930SIngo Molnar parent = *p; 25786470930SIngo Molnar s = rb_entry(parent, struct symbol, rb_node); 25886470930SIngo Molnar if (ip < s->start) 25986470930SIngo Molnar p = &(*p)->rb_left; 26086470930SIngo Molnar else 26186470930SIngo Molnar p = &(*p)->rb_right; 26286470930SIngo Molnar } 26386470930SIngo Molnar rb_link_node(&sym->rb_node, parent, p); 264fcf1203aSArnaldo Carvalho de Melo rb_insert_color(&sym->rb_node, self); 26586470930SIngo Molnar } 26686470930SIngo Molnar 267fcf1203aSArnaldo Carvalho de Melo static struct symbol *symbols__find(struct rb_root *self, u64 ip) 26886470930SIngo Molnar { 26986470930SIngo Molnar struct rb_node *n; 27086470930SIngo Molnar 27186470930SIngo Molnar if (self == NULL) 27286470930SIngo Molnar return NULL; 27386470930SIngo Molnar 274fcf1203aSArnaldo Carvalho de Melo n = self->rb_node; 27586470930SIngo Molnar 27686470930SIngo Molnar while (n) { 27786470930SIngo Molnar struct symbol *s = rb_entry(n, struct symbol, rb_node); 27886470930SIngo Molnar 27986470930SIngo Molnar if (ip < s->start) 28086470930SIngo Molnar n = n->rb_left; 28186470930SIngo Molnar else if (ip > s->end) 28286470930SIngo Molnar n = n->rb_right; 28386470930SIngo Molnar else 28486470930SIngo Molnar return s; 28586470930SIngo Molnar } 28686470930SIngo Molnar 28786470930SIngo Molnar return NULL; 28886470930SIngo Molnar } 28986470930SIngo Molnar 29079406cd7SArnaldo Carvalho de Melo struct symbol_name_rb_node { 29179406cd7SArnaldo Carvalho de Melo struct rb_node rb_node; 29279406cd7SArnaldo Carvalho de Melo struct symbol sym; 29379406cd7SArnaldo Carvalho de Melo }; 29479406cd7SArnaldo Carvalho de Melo 29579406cd7SArnaldo Carvalho de Melo static void symbols__insert_by_name(struct rb_root *self, struct symbol *sym) 29679406cd7SArnaldo Carvalho de Melo { 29779406cd7SArnaldo Carvalho de Melo struct rb_node **p = &self->rb_node; 29879406cd7SArnaldo Carvalho de Melo struct rb_node *parent = NULL; 29902a9d037SRabin Vincent struct symbol_name_rb_node *symn, *s; 30002a9d037SRabin Vincent 30102a9d037SRabin Vincent symn = container_of(sym, struct symbol_name_rb_node, sym); 30279406cd7SArnaldo Carvalho de Melo 30379406cd7SArnaldo Carvalho de Melo while (*p != NULL) { 30479406cd7SArnaldo Carvalho de Melo parent = *p; 30579406cd7SArnaldo Carvalho de Melo s = rb_entry(parent, struct symbol_name_rb_node, rb_node); 30679406cd7SArnaldo Carvalho de Melo if (strcmp(sym->name, s->sym.name) < 0) 30779406cd7SArnaldo Carvalho de Melo p = &(*p)->rb_left; 30879406cd7SArnaldo Carvalho de Melo else 30979406cd7SArnaldo Carvalho de Melo p = &(*p)->rb_right; 31079406cd7SArnaldo Carvalho de Melo } 31179406cd7SArnaldo Carvalho de Melo rb_link_node(&symn->rb_node, parent, p); 31279406cd7SArnaldo Carvalho de Melo rb_insert_color(&symn->rb_node, self); 31379406cd7SArnaldo Carvalho de Melo } 31479406cd7SArnaldo Carvalho de Melo 31579406cd7SArnaldo Carvalho de Melo static void symbols__sort_by_name(struct rb_root *self, struct rb_root *source) 31679406cd7SArnaldo Carvalho de Melo { 31779406cd7SArnaldo Carvalho de Melo struct rb_node *nd; 31879406cd7SArnaldo Carvalho de Melo 31979406cd7SArnaldo Carvalho de Melo for (nd = rb_first(source); nd; nd = rb_next(nd)) { 32079406cd7SArnaldo Carvalho de Melo struct symbol *pos = rb_entry(nd, struct symbol, rb_node); 32179406cd7SArnaldo Carvalho de Melo symbols__insert_by_name(self, pos); 32279406cd7SArnaldo Carvalho de Melo } 32379406cd7SArnaldo Carvalho de Melo } 32479406cd7SArnaldo Carvalho de Melo 32579406cd7SArnaldo Carvalho de Melo static struct symbol *symbols__find_by_name(struct rb_root *self, const char *name) 32679406cd7SArnaldo Carvalho de Melo { 32779406cd7SArnaldo Carvalho de Melo struct rb_node *n; 32879406cd7SArnaldo Carvalho de Melo 32979406cd7SArnaldo Carvalho de Melo if (self == NULL) 33079406cd7SArnaldo Carvalho de Melo return NULL; 33179406cd7SArnaldo Carvalho de Melo 33279406cd7SArnaldo Carvalho de Melo n = self->rb_node; 33379406cd7SArnaldo Carvalho de Melo 33479406cd7SArnaldo Carvalho de Melo while (n) { 33579406cd7SArnaldo Carvalho de Melo struct symbol_name_rb_node *s; 33679406cd7SArnaldo Carvalho de Melo int cmp; 33779406cd7SArnaldo Carvalho de Melo 33879406cd7SArnaldo Carvalho de Melo s = rb_entry(n, struct symbol_name_rb_node, rb_node); 33979406cd7SArnaldo Carvalho de Melo cmp = strcmp(name, s->sym.name); 34079406cd7SArnaldo Carvalho de Melo 34179406cd7SArnaldo Carvalho de Melo if (cmp < 0) 34279406cd7SArnaldo Carvalho de Melo n = n->rb_left; 34379406cd7SArnaldo Carvalho de Melo else if (cmp > 0) 34479406cd7SArnaldo Carvalho de Melo n = n->rb_right; 34579406cd7SArnaldo Carvalho de Melo else 34679406cd7SArnaldo Carvalho de Melo return &s->sym; 34779406cd7SArnaldo Carvalho de Melo } 34879406cd7SArnaldo Carvalho de Melo 34979406cd7SArnaldo Carvalho de Melo return NULL; 35079406cd7SArnaldo Carvalho de Melo } 35179406cd7SArnaldo Carvalho de Melo 35279406cd7SArnaldo Carvalho de Melo struct symbol *dso__find_symbol(struct dso *self, 35379406cd7SArnaldo Carvalho de Melo enum map_type type, u64 addr) 354fcf1203aSArnaldo Carvalho de Melo { 3556a4694a4SArnaldo Carvalho de Melo return symbols__find(&self->symbols[type], addr); 356fcf1203aSArnaldo Carvalho de Melo } 357fcf1203aSArnaldo Carvalho de Melo 35879406cd7SArnaldo Carvalho de Melo struct symbol *dso__find_symbol_by_name(struct dso *self, enum map_type type, 35979406cd7SArnaldo Carvalho de Melo const char *name) 36079406cd7SArnaldo Carvalho de Melo { 36179406cd7SArnaldo Carvalho de Melo return symbols__find_by_name(&self->symbol_names[type], name); 36279406cd7SArnaldo Carvalho de Melo } 36379406cd7SArnaldo Carvalho de Melo 36479406cd7SArnaldo Carvalho de Melo void dso__sort_by_name(struct dso *self, enum map_type type) 36579406cd7SArnaldo Carvalho de Melo { 36679406cd7SArnaldo Carvalho de Melo dso__set_sorted_by_name(self, type); 36779406cd7SArnaldo Carvalho de Melo return symbols__sort_by_name(&self->symbol_names[type], 36879406cd7SArnaldo Carvalho de Melo &self->symbols[type]); 36979406cd7SArnaldo Carvalho de Melo } 37079406cd7SArnaldo Carvalho de Melo 371ef12a141SArnaldo Carvalho de Melo int build_id__sprintf(const u8 *self, int len, char *bf) 3728d06367fSArnaldo Carvalho de Melo { 3738d06367fSArnaldo Carvalho de Melo char *bid = bf; 374ef12a141SArnaldo Carvalho de Melo const u8 *raw = self; 3758d06367fSArnaldo Carvalho de Melo int i; 3768d06367fSArnaldo Carvalho de Melo 3778d06367fSArnaldo Carvalho de Melo for (i = 0; i < len; ++i) { 3788d06367fSArnaldo Carvalho de Melo sprintf(bid, "%02x", *raw); 3798d06367fSArnaldo Carvalho de Melo ++raw; 3808d06367fSArnaldo Carvalho de Melo bid += 2; 3818d06367fSArnaldo Carvalho de Melo } 3828d06367fSArnaldo Carvalho de Melo 3838d06367fSArnaldo Carvalho de Melo return raw - self; 3848d06367fSArnaldo Carvalho de Melo } 3858d06367fSArnaldo Carvalho de Melo 3869e03eb2dSArnaldo Carvalho de Melo size_t dso__fprintf_buildid(struct dso *self, FILE *fp) 38786470930SIngo Molnar { 3888d06367fSArnaldo Carvalho de Melo char sbuild_id[BUILD_ID_SIZE * 2 + 1]; 3898d06367fSArnaldo Carvalho de Melo 3908d06367fSArnaldo Carvalho de Melo build_id__sprintf(self->build_id, sizeof(self->build_id), sbuild_id); 3919e03eb2dSArnaldo Carvalho de Melo return fprintf(fp, "%s", sbuild_id); 3929e03eb2dSArnaldo Carvalho de Melo } 3939e03eb2dSArnaldo Carvalho de Melo 39490f18e63SSrikar Dronamraju size_t dso__fprintf_symbols_by_name(struct dso *self, enum map_type type, FILE *fp) 39590f18e63SSrikar Dronamraju { 39690f18e63SSrikar Dronamraju size_t ret = 0; 39790f18e63SSrikar Dronamraju struct rb_node *nd; 39890f18e63SSrikar Dronamraju struct symbol_name_rb_node *pos; 39990f18e63SSrikar Dronamraju 40090f18e63SSrikar Dronamraju for (nd = rb_first(&self->symbol_names[type]); nd; nd = rb_next(nd)) { 40190f18e63SSrikar Dronamraju pos = rb_entry(nd, struct symbol_name_rb_node, rb_node); 40290f18e63SSrikar Dronamraju fprintf(fp, "%s\n", pos->sym.name); 40390f18e63SSrikar Dronamraju } 40490f18e63SSrikar Dronamraju 40590f18e63SSrikar Dronamraju return ret; 40690f18e63SSrikar Dronamraju } 40790f18e63SSrikar Dronamraju 40895011c60SArnaldo Carvalho de Melo size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp) 4099e03eb2dSArnaldo Carvalho de Melo { 4109e03eb2dSArnaldo Carvalho de Melo struct rb_node *nd; 4119e03eb2dSArnaldo Carvalho de Melo size_t ret = fprintf(fp, "dso: %s (", self->short_name); 4129e03eb2dSArnaldo Carvalho de Melo 4133846df2eSArnaldo Carvalho de Melo if (self->short_name != self->long_name) 4143846df2eSArnaldo Carvalho de Melo ret += fprintf(fp, "%s, ", self->long_name); 4153846df2eSArnaldo Carvalho de Melo ret += fprintf(fp, "%s, %sloaded, ", map_type__name[type], 4163846df2eSArnaldo Carvalho de Melo self->loaded ? "" : "NOT "); 4179e03eb2dSArnaldo Carvalho de Melo ret += dso__fprintf_buildid(self, fp); 4186a4694a4SArnaldo Carvalho de Melo ret += fprintf(fp, ")\n"); 41995011c60SArnaldo Carvalho de Melo for (nd = rb_first(&self->symbols[type]); nd; nd = rb_next(nd)) { 42086470930SIngo Molnar struct symbol *pos = rb_entry(nd, struct symbol, rb_node); 42186470930SIngo Molnar ret += symbol__fprintf(pos, fp); 42286470930SIngo Molnar } 42386470930SIngo Molnar 42486470930SIngo Molnar return ret; 42586470930SIngo Molnar } 42686470930SIngo Molnar 4279e201442SArnaldo Carvalho de Melo int kallsyms__parse(const char *filename, void *arg, 4289e201442SArnaldo Carvalho de Melo int (*process_symbol)(void *arg, const char *name, 429682b335aSArnaldo Carvalho de Melo char type, u64 start)) 43086470930SIngo Molnar { 43186470930SIngo Molnar char *line = NULL; 43286470930SIngo Molnar size_t n; 433682b335aSArnaldo Carvalho de Melo int err = 0; 4349e201442SArnaldo Carvalho de Melo FILE *file = fopen(filename, "r"); 43586470930SIngo Molnar 43686470930SIngo Molnar if (file == NULL) 43786470930SIngo Molnar goto out_failure; 43886470930SIngo Molnar 43986470930SIngo Molnar while (!feof(file)) { 4409cffa8d5SPaul Mackerras u64 start; 44186470930SIngo Molnar int line_len, len; 44286470930SIngo Molnar char symbol_type; 4432e538c4aSArnaldo Carvalho de Melo char *symbol_name; 44486470930SIngo Molnar 44586470930SIngo Molnar line_len = getline(&line, &n, file); 446a1645ce1SZhang, Yanmin if (line_len < 0 || !line) 44786470930SIngo Molnar break; 44886470930SIngo Molnar 44986470930SIngo Molnar line[--line_len] = '\0'; /* \n */ 45086470930SIngo Molnar 45186470930SIngo Molnar len = hex2u64(line, &start); 45286470930SIngo Molnar 45386470930SIngo Molnar len++; 45486470930SIngo Molnar if (len + 2 >= line_len) 45586470930SIngo Molnar continue; 45686470930SIngo Molnar 45786470930SIngo Molnar symbol_type = toupper(line[len]); 458af427bf5SArnaldo Carvalho de Melo symbol_name = line + len + 2; 459682b335aSArnaldo Carvalho de Melo 460682b335aSArnaldo Carvalho de Melo err = process_symbol(arg, symbol_name, symbol_type, start); 461682b335aSArnaldo Carvalho de Melo if (err) 462682b335aSArnaldo Carvalho de Melo break; 463682b335aSArnaldo Carvalho de Melo } 464682b335aSArnaldo Carvalho de Melo 465682b335aSArnaldo Carvalho de Melo free(line); 466682b335aSArnaldo Carvalho de Melo fclose(file); 467682b335aSArnaldo Carvalho de Melo return err; 468682b335aSArnaldo Carvalho de Melo 469682b335aSArnaldo Carvalho de Melo out_failure: 470682b335aSArnaldo Carvalho de Melo return -1; 471682b335aSArnaldo Carvalho de Melo } 472682b335aSArnaldo Carvalho de Melo 473682b335aSArnaldo Carvalho de Melo struct process_kallsyms_args { 474682b335aSArnaldo Carvalho de Melo struct map *map; 475682b335aSArnaldo Carvalho de Melo struct dso *dso; 476682b335aSArnaldo Carvalho de Melo }; 477682b335aSArnaldo Carvalho de Melo 478c408fedfSArnaldo Carvalho de Melo static u8 kallsyms2elf_type(char type) 479c408fedfSArnaldo Carvalho de Melo { 480c408fedfSArnaldo Carvalho de Melo if (type == 'W') 481c408fedfSArnaldo Carvalho de Melo return STB_WEAK; 482c408fedfSArnaldo Carvalho de Melo 483c408fedfSArnaldo Carvalho de Melo return isupper(type) ? STB_GLOBAL : STB_LOCAL; 484c408fedfSArnaldo Carvalho de Melo } 485c408fedfSArnaldo Carvalho de Melo 486682b335aSArnaldo Carvalho de Melo static int map__process_kallsym_symbol(void *arg, const char *name, 487682b335aSArnaldo Carvalho de Melo char type, u64 start) 488682b335aSArnaldo Carvalho de Melo { 489682b335aSArnaldo Carvalho de Melo struct symbol *sym; 490682b335aSArnaldo Carvalho de Melo struct process_kallsyms_args *a = arg; 491682b335aSArnaldo Carvalho de Melo struct rb_root *root = &a->dso->symbols[a->map->type]; 492682b335aSArnaldo Carvalho de Melo 493682b335aSArnaldo Carvalho de Melo if (!symbol_type__is_a(type, a->map->type)) 494682b335aSArnaldo Carvalho de Melo return 0; 495682b335aSArnaldo Carvalho de Melo 4962e538c4aSArnaldo Carvalho de Melo /* 4972e538c4aSArnaldo Carvalho de Melo * Will fix up the end later, when we have all symbols sorted. 4982e538c4aSArnaldo Carvalho de Melo */ 499c408fedfSArnaldo Carvalho de Melo sym = symbol__new(start, 0, kallsyms2elf_type(type), name); 500af427bf5SArnaldo Carvalho de Melo 5012e538c4aSArnaldo Carvalho de Melo if (sym == NULL) 502682b335aSArnaldo Carvalho de Melo return -ENOMEM; 50382164161SArnaldo Carvalho de Melo /* 50482164161SArnaldo Carvalho de Melo * We will pass the symbols to the filter later, in 5054e06255fSArnaldo Carvalho de Melo * map__split_kallsyms, when we have split the maps per module 50682164161SArnaldo Carvalho de Melo */ 5074e06255fSArnaldo Carvalho de Melo symbols__insert(root, sym); 508a1645ce1SZhang, Yanmin 509682b335aSArnaldo Carvalho de Melo return 0; 5102e538c4aSArnaldo Carvalho de Melo } 5112e538c4aSArnaldo Carvalho de Melo 512682b335aSArnaldo Carvalho de Melo /* 513682b335aSArnaldo Carvalho de Melo * Loads the function entries in /proc/kallsyms into kernel_map->dso, 514682b335aSArnaldo Carvalho de Melo * so that we can in the next step set the symbol ->end address and then 515682b335aSArnaldo Carvalho de Melo * call kernel_maps__split_kallsyms. 516682b335aSArnaldo Carvalho de Melo */ 5179e201442SArnaldo Carvalho de Melo static int dso__load_all_kallsyms(struct dso *self, const char *filename, 5189e201442SArnaldo Carvalho de Melo struct map *map) 519682b335aSArnaldo Carvalho de Melo { 520682b335aSArnaldo Carvalho de Melo struct process_kallsyms_args args = { .map = map, .dso = self, }; 5219e201442SArnaldo Carvalho de Melo return kallsyms__parse(filename, &args, map__process_kallsym_symbol); 5222e538c4aSArnaldo Carvalho de Melo } 5232e538c4aSArnaldo Carvalho de Melo 5242e538c4aSArnaldo Carvalho de Melo /* 5252e538c4aSArnaldo Carvalho de Melo * Split the symbols into maps, making sure there are no overlaps, i.e. the 5262e538c4aSArnaldo Carvalho de Melo * kernel range is broken in several maps, named [kernel].N, as we don't have 5272e538c4aSArnaldo Carvalho de Melo * the original ELF section names vmlinux have. 5282e538c4aSArnaldo Carvalho de Melo */ 5299958e1f0SArnaldo Carvalho de Melo static int dso__split_kallsyms(struct dso *self, struct map *map, 5309de89fe7SArnaldo Carvalho de Melo symbol_filter_t filter) 5312e538c4aSArnaldo Carvalho de Melo { 5329de89fe7SArnaldo Carvalho de Melo struct map_groups *kmaps = map__kmap(map)->kmaps; 53323346f21SArnaldo Carvalho de Melo struct machine *machine = kmaps->machine; 5344e06255fSArnaldo Carvalho de Melo struct map *curr_map = map; 5352e538c4aSArnaldo Carvalho de Melo struct symbol *pos; 5368a953312SArnaldo Carvalho de Melo int count = 0, moved = 0; 5374e06255fSArnaldo Carvalho de Melo struct rb_root *root = &self->symbols[map->type]; 5384e06255fSArnaldo Carvalho de Melo struct rb_node *next = rb_first(root); 5392e538c4aSArnaldo Carvalho de Melo int kernel_range = 0; 5402e538c4aSArnaldo Carvalho de Melo 5412e538c4aSArnaldo Carvalho de Melo while (next) { 5422e538c4aSArnaldo Carvalho de Melo char *module; 5432e538c4aSArnaldo Carvalho de Melo 5442e538c4aSArnaldo Carvalho de Melo pos = rb_entry(next, struct symbol, rb_node); 5452e538c4aSArnaldo Carvalho de Melo next = rb_next(&pos->rb_node); 5462e538c4aSArnaldo Carvalho de Melo 5472e538c4aSArnaldo Carvalho de Melo module = strchr(pos->name, '\t'); 5482e538c4aSArnaldo Carvalho de Melo if (module) { 54975be6cf4SArnaldo Carvalho de Melo if (!symbol_conf.use_modules) 5501de8e245SArnaldo Carvalho de Melo goto discard_symbol; 5511de8e245SArnaldo Carvalho de Melo 5522e538c4aSArnaldo Carvalho de Melo *module++ = '\0'; 5532e538c4aSArnaldo Carvalho de Melo 554b7cece76SArnaldo Carvalho de Melo if (strcmp(curr_map->dso->short_name, module)) { 555a1645ce1SZhang, Yanmin if (curr_map != map && 556a1645ce1SZhang, Yanmin self->kernel == DSO_TYPE_GUEST_KERNEL && 55723346f21SArnaldo Carvalho de Melo machine__is_default_guest(machine)) { 558a1645ce1SZhang, Yanmin /* 559a1645ce1SZhang, Yanmin * We assume all symbols of a module are 560a1645ce1SZhang, Yanmin * continuous in * kallsyms, so curr_map 561a1645ce1SZhang, Yanmin * points to a module and all its 562a1645ce1SZhang, Yanmin * symbols are in its kmap. Mark it as 563a1645ce1SZhang, Yanmin * loaded. 564a1645ce1SZhang, Yanmin */ 565a1645ce1SZhang, Yanmin dso__set_loaded(curr_map->dso, 566a1645ce1SZhang, Yanmin curr_map->type); 567af427bf5SArnaldo Carvalho de Melo } 568b7cece76SArnaldo Carvalho de Melo 569a1645ce1SZhang, Yanmin curr_map = map_groups__find_by_name(kmaps, 570a1645ce1SZhang, Yanmin map->type, module); 571a1645ce1SZhang, Yanmin if (curr_map == NULL) { 5722f51903bSArnaldo Carvalho de Melo pr_debug("%s/proc/{kallsyms,modules} " 573a1645ce1SZhang, Yanmin "inconsistency while looking " 574a1645ce1SZhang, Yanmin "for \"%s\" module!\n", 57523346f21SArnaldo Carvalho de Melo machine->root_dir, module); 576a1645ce1SZhang, Yanmin curr_map = map; 577a1645ce1SZhang, Yanmin goto discard_symbol; 578a1645ce1SZhang, Yanmin } 579a1645ce1SZhang, Yanmin 580a1645ce1SZhang, Yanmin if (curr_map->dso->loaded && 58123346f21SArnaldo Carvalho de Melo !machine__is_default_guest(machine)) 582b7cece76SArnaldo Carvalho de Melo goto discard_symbol; 583af427bf5SArnaldo Carvalho de Melo } 58486470930SIngo Molnar /* 5852e538c4aSArnaldo Carvalho de Melo * So that we look just like we get from .ko files, 5862e538c4aSArnaldo Carvalho de Melo * i.e. not prelinked, relative to map->start. 58786470930SIngo Molnar */ 5884e06255fSArnaldo Carvalho de Melo pos->start = curr_map->map_ip(curr_map, pos->start); 5894e06255fSArnaldo Carvalho de Melo pos->end = curr_map->map_ip(curr_map, pos->end); 5904e06255fSArnaldo Carvalho de Melo } else if (curr_map != map) { 5912e538c4aSArnaldo Carvalho de Melo char dso_name[PATH_MAX]; 5922e538c4aSArnaldo Carvalho de Melo struct dso *dso; 59386470930SIngo Molnar 5948a953312SArnaldo Carvalho de Melo if (count == 0) { 5958a953312SArnaldo Carvalho de Melo curr_map = map; 5968a953312SArnaldo Carvalho de Melo goto filter_symbol; 5978a953312SArnaldo Carvalho de Melo } 5988a953312SArnaldo Carvalho de Melo 599a1645ce1SZhang, Yanmin if (self->kernel == DSO_TYPE_GUEST_KERNEL) 600a1645ce1SZhang, Yanmin snprintf(dso_name, sizeof(dso_name), 601a1645ce1SZhang, Yanmin "[guest.kernel].%d", 602a1645ce1SZhang, Yanmin kernel_range++); 603a1645ce1SZhang, Yanmin else 604a1645ce1SZhang, Yanmin snprintf(dso_name, sizeof(dso_name), 605a1645ce1SZhang, Yanmin "[kernel].%d", 6062e538c4aSArnaldo Carvalho de Melo kernel_range++); 60786470930SIngo Molnar 60800a192b3SArnaldo Carvalho de Melo dso = dso__new(dso_name); 6092e538c4aSArnaldo Carvalho de Melo if (dso == NULL) 6102e538c4aSArnaldo Carvalho de Melo return -1; 6112e538c4aSArnaldo Carvalho de Melo 612a1645ce1SZhang, Yanmin dso->kernel = self->kernel; 613a1645ce1SZhang, Yanmin 6144e06255fSArnaldo Carvalho de Melo curr_map = map__new2(pos->start, dso, map->type); 61537fe5fcbSZhang, Yanmin if (curr_map == NULL) { 6162e538c4aSArnaldo Carvalho de Melo dso__delete(dso); 6172e538c4aSArnaldo Carvalho de Melo return -1; 6182e538c4aSArnaldo Carvalho de Melo } 6192e538c4aSArnaldo Carvalho de Melo 6204e06255fSArnaldo Carvalho de Melo curr_map->map_ip = curr_map->unmap_ip = identity__map_ip; 6219de89fe7SArnaldo Carvalho de Melo map_groups__insert(kmaps, curr_map); 6222e538c4aSArnaldo Carvalho de Melo ++kernel_range; 6232e538c4aSArnaldo Carvalho de Melo } 6248a953312SArnaldo Carvalho de Melo filter_symbol: 6254e06255fSArnaldo Carvalho de Melo if (filter && filter(curr_map, pos)) { 6261de8e245SArnaldo Carvalho de Melo discard_symbol: rb_erase(&pos->rb_node, root); 62700a192b3SArnaldo Carvalho de Melo symbol__delete(pos); 6282e538c4aSArnaldo Carvalho de Melo } else { 6294e06255fSArnaldo Carvalho de Melo if (curr_map != map) { 6304e06255fSArnaldo Carvalho de Melo rb_erase(&pos->rb_node, root); 6314e06255fSArnaldo Carvalho de Melo symbols__insert(&curr_map->dso->symbols[curr_map->type], pos); 6328a953312SArnaldo Carvalho de Melo ++moved; 6338a953312SArnaldo Carvalho de Melo } else 6348a953312SArnaldo Carvalho de Melo ++count; 6359974f496SMike Galbraith } 63686470930SIngo Molnar } 63786470930SIngo Molnar 638a1645ce1SZhang, Yanmin if (curr_map != map && 639a1645ce1SZhang, Yanmin self->kernel == DSO_TYPE_GUEST_KERNEL && 64023346f21SArnaldo Carvalho de Melo machine__is_default_guest(kmaps->machine)) { 641a1645ce1SZhang, Yanmin dso__set_loaded(curr_map->dso, curr_map->type); 642a1645ce1SZhang, Yanmin } 643a1645ce1SZhang, Yanmin 6448a953312SArnaldo Carvalho de Melo return count + moved; 64586470930SIngo Molnar } 64686470930SIngo Molnar 6479de89fe7SArnaldo Carvalho de Melo int dso__load_kallsyms(struct dso *self, const char *filename, 6489de89fe7SArnaldo Carvalho de Melo struct map *map, symbol_filter_t filter) 6492e538c4aSArnaldo Carvalho de Melo { 6509e201442SArnaldo Carvalho de Melo if (dso__load_all_kallsyms(self, filename, map) < 0) 6512e538c4aSArnaldo Carvalho de Melo return -1; 6522e538c4aSArnaldo Carvalho de Melo 6534e06255fSArnaldo Carvalho de Melo symbols__fixup_end(&self->symbols[map->type]); 654a1645ce1SZhang, Yanmin if (self->kernel == DSO_TYPE_GUEST_KERNEL) 655a1645ce1SZhang, Yanmin self->origin = DSO__ORIG_GUEST_KERNEL; 656a1645ce1SZhang, Yanmin else 6574e06255fSArnaldo Carvalho de Melo self->origin = DSO__ORIG_KERNEL; 6582e538c4aSArnaldo Carvalho de Melo 6599de89fe7SArnaldo Carvalho de Melo return dso__split_kallsyms(self, map, filter); 660af427bf5SArnaldo Carvalho de Melo } 661af427bf5SArnaldo Carvalho de Melo 662439d473bSArnaldo Carvalho de Melo static int dso__load_perf_map(struct dso *self, struct map *map, 6636beba7adSArnaldo Carvalho de Melo symbol_filter_t filter) 66480d496beSPekka Enberg { 66580d496beSPekka Enberg char *line = NULL; 66680d496beSPekka Enberg size_t n; 66780d496beSPekka Enberg FILE *file; 66880d496beSPekka Enberg int nr_syms = 0; 66980d496beSPekka Enberg 670439d473bSArnaldo Carvalho de Melo file = fopen(self->long_name, "r"); 67180d496beSPekka Enberg if (file == NULL) 67280d496beSPekka Enberg goto out_failure; 67380d496beSPekka Enberg 67480d496beSPekka Enberg while (!feof(file)) { 6759cffa8d5SPaul Mackerras u64 start, size; 67680d496beSPekka Enberg struct symbol *sym; 67780d496beSPekka Enberg int line_len, len; 67880d496beSPekka Enberg 67980d496beSPekka Enberg line_len = getline(&line, &n, file); 68080d496beSPekka Enberg if (line_len < 0) 68180d496beSPekka Enberg break; 68280d496beSPekka Enberg 68380d496beSPekka Enberg if (!line) 68480d496beSPekka Enberg goto out_failure; 68580d496beSPekka Enberg 68680d496beSPekka Enberg line[--line_len] = '\0'; /* \n */ 68780d496beSPekka Enberg 68880d496beSPekka Enberg len = hex2u64(line, &start); 68980d496beSPekka Enberg 69080d496beSPekka Enberg len++; 69180d496beSPekka Enberg if (len + 2 >= line_len) 69280d496beSPekka Enberg continue; 69380d496beSPekka Enberg 69480d496beSPekka Enberg len += hex2u64(line + len, &size); 69580d496beSPekka Enberg 69680d496beSPekka Enberg len++; 69780d496beSPekka Enberg if (len + 2 >= line_len) 69880d496beSPekka Enberg continue; 69980d496beSPekka Enberg 700c408fedfSArnaldo Carvalho de Melo sym = symbol__new(start, size, STB_GLOBAL, line + len); 70180d496beSPekka Enberg 70280d496beSPekka Enberg if (sym == NULL) 70380d496beSPekka Enberg goto out_delete_line; 70480d496beSPekka Enberg 705439d473bSArnaldo Carvalho de Melo if (filter && filter(map, sym)) 70600a192b3SArnaldo Carvalho de Melo symbol__delete(sym); 70780d496beSPekka Enberg else { 7086a4694a4SArnaldo Carvalho de Melo symbols__insert(&self->symbols[map->type], sym); 70980d496beSPekka Enberg nr_syms++; 71080d496beSPekka Enberg } 71180d496beSPekka Enberg } 71280d496beSPekka Enberg 71380d496beSPekka Enberg free(line); 71480d496beSPekka Enberg fclose(file); 71580d496beSPekka Enberg 71680d496beSPekka Enberg return nr_syms; 71780d496beSPekka Enberg 71880d496beSPekka Enberg out_delete_line: 71980d496beSPekka Enberg free(line); 72080d496beSPekka Enberg out_failure: 72180d496beSPekka Enberg return -1; 72280d496beSPekka Enberg } 72380d496beSPekka Enberg 72486470930SIngo Molnar /** 72586470930SIngo Molnar * elf_symtab__for_each_symbol - iterate thru all the symbols 72686470930SIngo Molnar * 72786470930SIngo Molnar * @self: struct elf_symtab instance to iterate 72883a0944fSIngo Molnar * @idx: uint32_t idx 72986470930SIngo Molnar * @sym: GElf_Sym iterator 73086470930SIngo Molnar */ 73183a0944fSIngo Molnar #define elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) \ 73283a0944fSIngo Molnar for (idx = 0, gelf_getsym(syms, idx, &sym);\ 73383a0944fSIngo Molnar idx < nr_syms; \ 73483a0944fSIngo Molnar idx++, gelf_getsym(syms, idx, &sym)) 73586470930SIngo Molnar 73686470930SIngo Molnar static inline uint8_t elf_sym__type(const GElf_Sym *sym) 73786470930SIngo Molnar { 73886470930SIngo Molnar return GELF_ST_TYPE(sym->st_info); 73986470930SIngo Molnar } 74086470930SIngo Molnar 74186470930SIngo Molnar static inline int elf_sym__is_function(const GElf_Sym *sym) 74286470930SIngo Molnar { 74386470930SIngo Molnar return elf_sym__type(sym) == STT_FUNC && 74486470930SIngo Molnar sym->st_name != 0 && 74581833130SArnaldo Carvalho de Melo sym->st_shndx != SHN_UNDEF; 74686470930SIngo Molnar } 74786470930SIngo Molnar 748f1dfa0b1SArnaldo Carvalho de Melo static inline bool elf_sym__is_object(const GElf_Sym *sym) 749f1dfa0b1SArnaldo Carvalho de Melo { 750f1dfa0b1SArnaldo Carvalho de Melo return elf_sym__type(sym) == STT_OBJECT && 751f1dfa0b1SArnaldo Carvalho de Melo sym->st_name != 0 && 752f1dfa0b1SArnaldo Carvalho de Melo sym->st_shndx != SHN_UNDEF; 753f1dfa0b1SArnaldo Carvalho de Melo } 754f1dfa0b1SArnaldo Carvalho de Melo 7556cfcc53eSMike Galbraith static inline int elf_sym__is_label(const GElf_Sym *sym) 7566cfcc53eSMike Galbraith { 7576cfcc53eSMike Galbraith return elf_sym__type(sym) == STT_NOTYPE && 7586cfcc53eSMike Galbraith sym->st_name != 0 && 7596cfcc53eSMike Galbraith sym->st_shndx != SHN_UNDEF && 7606cfcc53eSMike Galbraith sym->st_shndx != SHN_ABS; 7616cfcc53eSMike Galbraith } 7626cfcc53eSMike Galbraith 7636cfcc53eSMike Galbraith static inline const char *elf_sec__name(const GElf_Shdr *shdr, 7646cfcc53eSMike Galbraith const Elf_Data *secstrs) 7656cfcc53eSMike Galbraith { 7666cfcc53eSMike Galbraith return secstrs->d_buf + shdr->sh_name; 7676cfcc53eSMike Galbraith } 7686cfcc53eSMike Galbraith 7696cfcc53eSMike Galbraith static inline int elf_sec__is_text(const GElf_Shdr *shdr, 7706cfcc53eSMike Galbraith const Elf_Data *secstrs) 7716cfcc53eSMike Galbraith { 7726cfcc53eSMike Galbraith return strstr(elf_sec__name(shdr, secstrs), "text") != NULL; 7736cfcc53eSMike Galbraith } 7746cfcc53eSMike Galbraith 775f1dfa0b1SArnaldo Carvalho de Melo static inline bool elf_sec__is_data(const GElf_Shdr *shdr, 776f1dfa0b1SArnaldo Carvalho de Melo const Elf_Data *secstrs) 777f1dfa0b1SArnaldo Carvalho de Melo { 778f1dfa0b1SArnaldo Carvalho de Melo return strstr(elf_sec__name(shdr, secstrs), "data") != NULL; 779f1dfa0b1SArnaldo Carvalho de Melo } 780f1dfa0b1SArnaldo Carvalho de Melo 78186470930SIngo Molnar static inline const char *elf_sym__name(const GElf_Sym *sym, 78286470930SIngo Molnar const Elf_Data *symstrs) 78386470930SIngo Molnar { 78486470930SIngo Molnar return symstrs->d_buf + sym->st_name; 78586470930SIngo Molnar } 78686470930SIngo Molnar 78786470930SIngo Molnar static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, 78886470930SIngo Molnar GElf_Shdr *shp, const char *name, 78983a0944fSIngo Molnar size_t *idx) 79086470930SIngo Molnar { 79186470930SIngo Molnar Elf_Scn *sec = NULL; 79286470930SIngo Molnar size_t cnt = 1; 79386470930SIngo Molnar 79486470930SIngo Molnar while ((sec = elf_nextscn(elf, sec)) != NULL) { 79586470930SIngo Molnar char *str; 79686470930SIngo Molnar 79786470930SIngo Molnar gelf_getshdr(sec, shp); 79886470930SIngo Molnar str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name); 79986470930SIngo Molnar if (!strcmp(name, str)) { 80083a0944fSIngo Molnar if (idx) 80183a0944fSIngo Molnar *idx = cnt; 80286470930SIngo Molnar break; 80386470930SIngo Molnar } 80486470930SIngo Molnar ++cnt; 80586470930SIngo Molnar } 80686470930SIngo Molnar 80786470930SIngo Molnar return sec; 80886470930SIngo Molnar } 80986470930SIngo Molnar 81086470930SIngo Molnar #define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \ 81186470930SIngo Molnar for (idx = 0, pos = gelf_getrel(reldata, 0, &pos_mem); \ 81286470930SIngo Molnar idx < nr_entries; \ 81386470930SIngo Molnar ++idx, pos = gelf_getrel(reldata, idx, &pos_mem)) 81486470930SIngo Molnar 81586470930SIngo Molnar #define elf_section__for_each_rela(reldata, pos, pos_mem, idx, nr_entries) \ 81686470930SIngo Molnar for (idx = 0, pos = gelf_getrela(reldata, 0, &pos_mem); \ 81786470930SIngo Molnar idx < nr_entries; \ 81886470930SIngo Molnar ++idx, pos = gelf_getrela(reldata, idx, &pos_mem)) 81986470930SIngo Molnar 820a25e46c4SArnaldo Carvalho de Melo /* 821a25e46c4SArnaldo Carvalho de Melo * We need to check if we have a .dynsym, so that we can handle the 822a25e46c4SArnaldo Carvalho de Melo * .plt, synthesizing its symbols, that aren't on the symtabs (be it 823a25e46c4SArnaldo Carvalho de Melo * .dynsym or .symtab). 824a25e46c4SArnaldo Carvalho de Melo * And always look at the original dso, not at debuginfo packages, that 825a25e46c4SArnaldo Carvalho de Melo * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS). 826a25e46c4SArnaldo Carvalho de Melo */ 82782164161SArnaldo Carvalho de Melo static int dso__synthesize_plt_symbols(struct dso *self, struct map *map, 82882164161SArnaldo Carvalho de Melo symbol_filter_t filter) 82986470930SIngo Molnar { 83086470930SIngo Molnar uint32_t nr_rel_entries, idx; 83186470930SIngo Molnar GElf_Sym sym; 8329cffa8d5SPaul Mackerras u64 plt_offset; 83386470930SIngo Molnar GElf_Shdr shdr_plt; 83486470930SIngo Molnar struct symbol *f; 835a25e46c4SArnaldo Carvalho de Melo GElf_Shdr shdr_rel_plt, shdr_dynsym; 83686470930SIngo Molnar Elf_Data *reldata, *syms, *symstrs; 837a25e46c4SArnaldo Carvalho de Melo Elf_Scn *scn_plt_rel, *scn_symstrs, *scn_dynsym; 838a25e46c4SArnaldo Carvalho de Melo size_t dynsym_idx; 839a25e46c4SArnaldo Carvalho de Melo GElf_Ehdr ehdr; 84086470930SIngo Molnar char sympltname[1024]; 841a25e46c4SArnaldo Carvalho de Melo Elf *elf; 842a25e46c4SArnaldo Carvalho de Melo int nr = 0, symidx, fd, err = 0; 843*ec5761eaSDavid Ahern char name[PATH_MAX]; 84486470930SIngo Molnar 845*ec5761eaSDavid Ahern snprintf(name, sizeof(name), "%s%s", 846*ec5761eaSDavid Ahern symbol_conf.symfs, self->long_name); 847*ec5761eaSDavid Ahern fd = open(name, O_RDONLY); 848a25e46c4SArnaldo Carvalho de Melo if (fd < 0) 849a25e46c4SArnaldo Carvalho de Melo goto out; 850a25e46c4SArnaldo Carvalho de Melo 85184087126SMarti Raudsepp elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 852a25e46c4SArnaldo Carvalho de Melo if (elf == NULL) 853a25e46c4SArnaldo Carvalho de Melo goto out_close; 854a25e46c4SArnaldo Carvalho de Melo 855a25e46c4SArnaldo Carvalho de Melo if (gelf_getehdr(elf, &ehdr) == NULL) 856a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 857a25e46c4SArnaldo Carvalho de Melo 858a25e46c4SArnaldo Carvalho de Melo scn_dynsym = elf_section_by_name(elf, &ehdr, &shdr_dynsym, 859a25e46c4SArnaldo Carvalho de Melo ".dynsym", &dynsym_idx); 860a25e46c4SArnaldo Carvalho de Melo if (scn_dynsym == NULL) 861a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 862a25e46c4SArnaldo Carvalho de Melo 863a25e46c4SArnaldo Carvalho de Melo scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt, 86486470930SIngo Molnar ".rela.plt", NULL); 86586470930SIngo Molnar if (scn_plt_rel == NULL) { 866a25e46c4SArnaldo Carvalho de Melo scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt, 86786470930SIngo Molnar ".rel.plt", NULL); 86886470930SIngo Molnar if (scn_plt_rel == NULL) 869a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 87086470930SIngo Molnar } 87186470930SIngo Molnar 872a25e46c4SArnaldo Carvalho de Melo err = -1; 87386470930SIngo Molnar 874a25e46c4SArnaldo Carvalho de Melo if (shdr_rel_plt.sh_link != dynsym_idx) 875a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 876a25e46c4SArnaldo Carvalho de Melo 877a25e46c4SArnaldo Carvalho de Melo if (elf_section_by_name(elf, &ehdr, &shdr_plt, ".plt", NULL) == NULL) 878a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 87986470930SIngo Molnar 88086470930SIngo Molnar /* 88183a0944fSIngo Molnar * Fetch the relocation section to find the idxes to the GOT 88286470930SIngo Molnar * and the symbols in the .dynsym they refer to. 88386470930SIngo Molnar */ 88486470930SIngo Molnar reldata = elf_getdata(scn_plt_rel, NULL); 88586470930SIngo Molnar if (reldata == NULL) 886a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 88786470930SIngo Molnar 88886470930SIngo Molnar syms = elf_getdata(scn_dynsym, NULL); 88986470930SIngo Molnar if (syms == NULL) 890a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 89186470930SIngo Molnar 892a25e46c4SArnaldo Carvalho de Melo scn_symstrs = elf_getscn(elf, shdr_dynsym.sh_link); 89386470930SIngo Molnar if (scn_symstrs == NULL) 894a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 89586470930SIngo Molnar 89686470930SIngo Molnar symstrs = elf_getdata(scn_symstrs, NULL); 89786470930SIngo Molnar if (symstrs == NULL) 898a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 89986470930SIngo Molnar 90086470930SIngo Molnar nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize; 90186470930SIngo Molnar plt_offset = shdr_plt.sh_offset; 90286470930SIngo Molnar 90386470930SIngo Molnar if (shdr_rel_plt.sh_type == SHT_RELA) { 90486470930SIngo Molnar GElf_Rela pos_mem, *pos; 90586470930SIngo Molnar 90686470930SIngo Molnar elf_section__for_each_rela(reldata, pos, pos_mem, idx, 90786470930SIngo Molnar nr_rel_entries) { 90886470930SIngo Molnar symidx = GELF_R_SYM(pos->r_info); 90986470930SIngo Molnar plt_offset += shdr_plt.sh_entsize; 91086470930SIngo Molnar gelf_getsym(syms, symidx, &sym); 91186470930SIngo Molnar snprintf(sympltname, sizeof(sympltname), 91286470930SIngo Molnar "%s@plt", elf_sym__name(&sym, symstrs)); 91386470930SIngo Molnar 91486470930SIngo Molnar f = symbol__new(plt_offset, shdr_plt.sh_entsize, 915c408fedfSArnaldo Carvalho de Melo STB_GLOBAL, sympltname); 91686470930SIngo Molnar if (!f) 917a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 91886470930SIngo Molnar 91982164161SArnaldo Carvalho de Melo if (filter && filter(map, f)) 92082164161SArnaldo Carvalho de Melo symbol__delete(f); 92182164161SArnaldo Carvalho de Melo else { 9226a4694a4SArnaldo Carvalho de Melo symbols__insert(&self->symbols[map->type], f); 92386470930SIngo Molnar ++nr; 92486470930SIngo Molnar } 92582164161SArnaldo Carvalho de Melo } 92686470930SIngo Molnar } else if (shdr_rel_plt.sh_type == SHT_REL) { 92786470930SIngo Molnar GElf_Rel pos_mem, *pos; 92886470930SIngo Molnar elf_section__for_each_rel(reldata, pos, pos_mem, idx, 92986470930SIngo Molnar nr_rel_entries) { 93086470930SIngo Molnar symidx = GELF_R_SYM(pos->r_info); 93186470930SIngo Molnar plt_offset += shdr_plt.sh_entsize; 93286470930SIngo Molnar gelf_getsym(syms, symidx, &sym); 93386470930SIngo Molnar snprintf(sympltname, sizeof(sympltname), 93486470930SIngo Molnar "%s@plt", elf_sym__name(&sym, symstrs)); 93586470930SIngo Molnar 93686470930SIngo Molnar f = symbol__new(plt_offset, shdr_plt.sh_entsize, 937c408fedfSArnaldo Carvalho de Melo STB_GLOBAL, sympltname); 93886470930SIngo Molnar if (!f) 939a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 94086470930SIngo Molnar 94182164161SArnaldo Carvalho de Melo if (filter && filter(map, f)) 94282164161SArnaldo Carvalho de Melo symbol__delete(f); 94382164161SArnaldo Carvalho de Melo else { 9446a4694a4SArnaldo Carvalho de Melo symbols__insert(&self->symbols[map->type], f); 94586470930SIngo Molnar ++nr; 94686470930SIngo Molnar } 94786470930SIngo Molnar } 94882164161SArnaldo Carvalho de Melo } 94986470930SIngo Molnar 950a25e46c4SArnaldo Carvalho de Melo err = 0; 951a25e46c4SArnaldo Carvalho de Melo out_elf_end: 952a25e46c4SArnaldo Carvalho de Melo elf_end(elf); 953a25e46c4SArnaldo Carvalho de Melo out_close: 954a25e46c4SArnaldo Carvalho de Melo close(fd); 955a25e46c4SArnaldo Carvalho de Melo 956a25e46c4SArnaldo Carvalho de Melo if (err == 0) 95786470930SIngo Molnar return nr; 958a25e46c4SArnaldo Carvalho de Melo out: 959fe2197b8SArnaldo Carvalho de Melo pr_debug("%s: problems reading %s PLT info.\n", 960439d473bSArnaldo Carvalho de Melo __func__, self->long_name); 961a25e46c4SArnaldo Carvalho de Melo return 0; 96286470930SIngo Molnar } 96386470930SIngo Molnar 964d45868d3SArnaldo Carvalho de Melo static bool elf_sym__is_a(GElf_Sym *self, enum map_type type) 965d45868d3SArnaldo Carvalho de Melo { 966d45868d3SArnaldo Carvalho de Melo switch (type) { 967d45868d3SArnaldo Carvalho de Melo case MAP__FUNCTION: 968d45868d3SArnaldo Carvalho de Melo return elf_sym__is_function(self); 969f1dfa0b1SArnaldo Carvalho de Melo case MAP__VARIABLE: 970f1dfa0b1SArnaldo Carvalho de Melo return elf_sym__is_object(self); 971d45868d3SArnaldo Carvalho de Melo default: 972d45868d3SArnaldo Carvalho de Melo return false; 973d45868d3SArnaldo Carvalho de Melo } 974d45868d3SArnaldo Carvalho de Melo } 975d45868d3SArnaldo Carvalho de Melo 976d45868d3SArnaldo Carvalho de Melo static bool elf_sec__is_a(GElf_Shdr *self, Elf_Data *secstrs, enum map_type type) 977d45868d3SArnaldo Carvalho de Melo { 978d45868d3SArnaldo Carvalho de Melo switch (type) { 979d45868d3SArnaldo Carvalho de Melo case MAP__FUNCTION: 980d45868d3SArnaldo Carvalho de Melo return elf_sec__is_text(self, secstrs); 981f1dfa0b1SArnaldo Carvalho de Melo case MAP__VARIABLE: 982f1dfa0b1SArnaldo Carvalho de Melo return elf_sec__is_data(self, secstrs); 983d45868d3SArnaldo Carvalho de Melo default: 984d45868d3SArnaldo Carvalho de Melo return false; 985d45868d3SArnaldo Carvalho de Melo } 986d45868d3SArnaldo Carvalho de Melo } 987d45868d3SArnaldo Carvalho de Melo 98870c3856bSEric B Munson static size_t elf_addr_to_index(Elf *elf, GElf_Addr addr) 98970c3856bSEric B Munson { 99070c3856bSEric B Munson Elf_Scn *sec = NULL; 99170c3856bSEric B Munson GElf_Shdr shdr; 99270c3856bSEric B Munson size_t cnt = 1; 99370c3856bSEric B Munson 99470c3856bSEric B Munson while ((sec = elf_nextscn(elf, sec)) != NULL) { 99570c3856bSEric B Munson gelf_getshdr(sec, &shdr); 99670c3856bSEric B Munson 99770c3856bSEric B Munson if ((addr >= shdr.sh_addr) && 99870c3856bSEric B Munson (addr < (shdr.sh_addr + shdr.sh_size))) 99970c3856bSEric B Munson return cnt; 100070c3856bSEric B Munson 100170c3856bSEric B Munson ++cnt; 100270c3856bSEric B Munson } 100370c3856bSEric B Munson 100470c3856bSEric B Munson return -1; 100570c3856bSEric B Munson } 100670c3856bSEric B Munson 10079de89fe7SArnaldo Carvalho de Melo static int dso__load_sym(struct dso *self, struct map *map, const char *name, 10086da80ce8SDave Martin int fd, symbol_filter_t filter, int kmodule, 10096da80ce8SDave Martin int want_symtab) 101086470930SIngo Molnar { 10119de89fe7SArnaldo Carvalho de Melo struct kmap *kmap = self->kernel ? map__kmap(map) : NULL; 10122e538c4aSArnaldo Carvalho de Melo struct map *curr_map = map; 10132e538c4aSArnaldo Carvalho de Melo struct dso *curr_dso = self; 10146cfcc53eSMike Galbraith Elf_Data *symstrs, *secstrs; 101586470930SIngo Molnar uint32_t nr_syms; 101686470930SIngo Molnar int err = -1; 101783a0944fSIngo Molnar uint32_t idx; 101886470930SIngo Molnar GElf_Ehdr ehdr; 101970c3856bSEric B Munson GElf_Shdr shdr, opdshdr; 102070c3856bSEric B Munson Elf_Data *syms, *opddata = NULL; 102186470930SIngo Molnar GElf_Sym sym; 102270c3856bSEric B Munson Elf_Scn *sec, *sec_strndx, *opdsec; 102386470930SIngo Molnar Elf *elf; 1024439d473bSArnaldo Carvalho de Melo int nr = 0; 102570c3856bSEric B Munson size_t opdidx = 0; 102686470930SIngo Molnar 102784087126SMarti Raudsepp elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 102886470930SIngo Molnar if (elf == NULL) { 10298b1389efSDave Martin pr_debug("%s: cannot read %s ELF file.\n", __func__, name); 103086470930SIngo Molnar goto out_close; 103186470930SIngo Molnar } 103286470930SIngo Molnar 103386470930SIngo Molnar if (gelf_getehdr(elf, &ehdr) == NULL) { 10348b1389efSDave Martin pr_debug("%s: cannot get elf header.\n", __func__); 103586470930SIngo Molnar goto out_elf_end; 103686470930SIngo Molnar } 103786470930SIngo Molnar 10386da80ce8SDave Martin /* Always reject images with a mismatched build-id: */ 103921916c38SDave Martin if (self->has_build_id) { 104021916c38SDave Martin u8 build_id[BUILD_ID_SIZE]; 104121916c38SDave Martin 104221916c38SDave Martin if (elf_read_build_id(elf, build_id, 104321916c38SDave Martin BUILD_ID_SIZE) != BUILD_ID_SIZE) 104421916c38SDave Martin goto out_elf_end; 104521916c38SDave Martin 104621916c38SDave Martin if (!dso__build_id_equal(self, build_id)) 104721916c38SDave Martin goto out_elf_end; 104821916c38SDave Martin } 104921916c38SDave Martin 105086470930SIngo Molnar sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL); 105186470930SIngo Molnar if (sec == NULL) { 10526da80ce8SDave Martin if (want_symtab) 10536da80ce8SDave Martin goto out_elf_end; 10546da80ce8SDave Martin 1055a25e46c4SArnaldo Carvalho de Melo sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL); 1056a25e46c4SArnaldo Carvalho de Melo if (sec == NULL) 105786470930SIngo Molnar goto out_elf_end; 105886470930SIngo Molnar } 105986470930SIngo Molnar 106070c3856bSEric B Munson opdsec = elf_section_by_name(elf, &ehdr, &opdshdr, ".opd", &opdidx); 106170c3856bSEric B Munson if (opdsec) 106270c3856bSEric B Munson opddata = elf_rawdata(opdsec, NULL); 106370c3856bSEric B Munson 106486470930SIngo Molnar syms = elf_getdata(sec, NULL); 106586470930SIngo Molnar if (syms == NULL) 106686470930SIngo Molnar goto out_elf_end; 106786470930SIngo Molnar 106886470930SIngo Molnar sec = elf_getscn(elf, shdr.sh_link); 106986470930SIngo Molnar if (sec == NULL) 107086470930SIngo Molnar goto out_elf_end; 107186470930SIngo Molnar 107286470930SIngo Molnar symstrs = elf_getdata(sec, NULL); 107386470930SIngo Molnar if (symstrs == NULL) 107486470930SIngo Molnar goto out_elf_end; 107586470930SIngo Molnar 10766cfcc53eSMike Galbraith sec_strndx = elf_getscn(elf, ehdr.e_shstrndx); 10776cfcc53eSMike Galbraith if (sec_strndx == NULL) 10786cfcc53eSMike Galbraith goto out_elf_end; 10796cfcc53eSMike Galbraith 10806cfcc53eSMike Galbraith secstrs = elf_getdata(sec_strndx, NULL); 10819b30a26bSStoyan Gaydarov if (secstrs == NULL) 10826cfcc53eSMike Galbraith goto out_elf_end; 10836cfcc53eSMike Galbraith 108486470930SIngo Molnar nr_syms = shdr.sh_size / shdr.sh_entsize; 108586470930SIngo Molnar 1086e9fbc9dcSArjan van de Ven memset(&sym, 0, sizeof(sym)); 1087a1645ce1SZhang, Yanmin if (self->kernel == DSO_TYPE_USER) { 108830d7a77dSArnaldo Carvalho de Melo self->adjust_symbols = (ehdr.e_type == ET_EXEC || 108930d7a77dSArnaldo Carvalho de Melo elf_section_by_name(elf, &ehdr, &shdr, 1090f5812a7aSArnaldo Carvalho de Melo ".gnu.prelink_undo", 109130d7a77dSArnaldo Carvalho de Melo NULL) != NULL); 1092d20ff6bdSMike Galbraith } else self->adjust_symbols = 0; 1093d20ff6bdSMike Galbraith 109483a0944fSIngo Molnar elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) { 109586470930SIngo Molnar struct symbol *f; 109656b03f3cSArnaldo Carvalho de Melo const char *elf_name = elf_sym__name(&sym, symstrs); 10972e538c4aSArnaldo Carvalho de Melo char *demangled = NULL; 10986cfcc53eSMike Galbraith int is_label = elf_sym__is_label(&sym); 10996cfcc53eSMike Galbraith const char *section_name; 110086470930SIngo Molnar 11019de89fe7SArnaldo Carvalho de Melo if (kmap && kmap->ref_reloc_sym && kmap->ref_reloc_sym->name && 11029de89fe7SArnaldo Carvalho de Melo strcmp(elf_name, kmap->ref_reloc_sym->name) == 0) 11039de89fe7SArnaldo Carvalho de Melo kmap->ref_reloc_sym->unrelocated_addr = sym.st_value; 110456b03f3cSArnaldo Carvalho de Melo 1105d45868d3SArnaldo Carvalho de Melo if (!is_label && !elf_sym__is_a(&sym, map->type)) 110686470930SIngo Molnar continue; 110786470930SIngo Molnar 1108696b97a5SDave Martin /* Reject ARM ELF "mapping symbols": these aren't unique and 1109696b97a5SDave Martin * don't identify functions, so will confuse the profile 1110696b97a5SDave Martin * output: */ 1111696b97a5SDave Martin if (ehdr.e_machine == EM_ARM) { 1112696b97a5SDave Martin if (!strcmp(elf_name, "$a") || 1113696b97a5SDave Martin !strcmp(elf_name, "$d") || 1114696b97a5SDave Martin !strcmp(elf_name, "$t")) 1115696b97a5SDave Martin continue; 1116696b97a5SDave Martin } 1117696b97a5SDave Martin 111870c3856bSEric B Munson if (opdsec && sym.st_shndx == opdidx) { 111970c3856bSEric B Munson u32 offset = sym.st_value - opdshdr.sh_addr; 112070c3856bSEric B Munson u64 *opd = opddata->d_buf + offset; 112170c3856bSEric B Munson sym.st_value = *opd; 112270c3856bSEric B Munson sym.st_shndx = elf_addr_to_index(elf, sym.st_value); 112370c3856bSEric B Munson } 112470c3856bSEric B Munson 112586470930SIngo Molnar sec = elf_getscn(elf, sym.st_shndx); 112686470930SIngo Molnar if (!sec) 112786470930SIngo Molnar goto out_elf_end; 112886470930SIngo Molnar 112986470930SIngo Molnar gelf_getshdr(sec, &shdr); 11306cfcc53eSMike Galbraith 1131d45868d3SArnaldo Carvalho de Melo if (is_label && !elf_sec__is_a(&shdr, secstrs, map->type)) 11326cfcc53eSMike Galbraith continue; 11336cfcc53eSMike Galbraith 11346cfcc53eSMike Galbraith section_name = elf_sec__name(&shdr, secstrs); 113586470930SIngo Molnar 1136a1645ce1SZhang, Yanmin if (self->kernel != DSO_TYPE_USER || kmodule) { 11372e538c4aSArnaldo Carvalho de Melo char dso_name[PATH_MAX]; 11382e538c4aSArnaldo Carvalho de Melo 11392e538c4aSArnaldo Carvalho de Melo if (strcmp(section_name, 1140b63be8d7SArnaldo Carvalho de Melo (curr_dso->short_name + 1141b63be8d7SArnaldo Carvalho de Melo self->short_name_len)) == 0) 11422e538c4aSArnaldo Carvalho de Melo goto new_symbol; 11432e538c4aSArnaldo Carvalho de Melo 11442e538c4aSArnaldo Carvalho de Melo if (strcmp(section_name, ".text") == 0) { 11452e538c4aSArnaldo Carvalho de Melo curr_map = map; 11462e538c4aSArnaldo Carvalho de Melo curr_dso = self; 11472e538c4aSArnaldo Carvalho de Melo goto new_symbol; 1148af427bf5SArnaldo Carvalho de Melo } 1149af427bf5SArnaldo Carvalho de Melo 11502e538c4aSArnaldo Carvalho de Melo snprintf(dso_name, sizeof(dso_name), 11512e538c4aSArnaldo Carvalho de Melo "%s%s", self->short_name, section_name); 11522e538c4aSArnaldo Carvalho de Melo 11539de89fe7SArnaldo Carvalho de Melo curr_map = map_groups__find_by_name(kmap->kmaps, map->type, dso_name); 11542e538c4aSArnaldo Carvalho de Melo if (curr_map == NULL) { 11552e538c4aSArnaldo Carvalho de Melo u64 start = sym.st_value; 11562e538c4aSArnaldo Carvalho de Melo 11572e538c4aSArnaldo Carvalho de Melo if (kmodule) 11582e538c4aSArnaldo Carvalho de Melo start += map->start + shdr.sh_offset; 11592e538c4aSArnaldo Carvalho de Melo 116000a192b3SArnaldo Carvalho de Melo curr_dso = dso__new(dso_name); 11612e538c4aSArnaldo Carvalho de Melo if (curr_dso == NULL) 11622e538c4aSArnaldo Carvalho de Melo goto out_elf_end; 1163a1645ce1SZhang, Yanmin curr_dso->kernel = self->kernel; 11643610583cSArnaldo Carvalho de Melo curr_map = map__new2(start, curr_dso, 11656275ce2dSArnaldo Carvalho de Melo map->type); 11662e538c4aSArnaldo Carvalho de Melo if (curr_map == NULL) { 11672e538c4aSArnaldo Carvalho de Melo dso__delete(curr_dso); 11682e538c4aSArnaldo Carvalho de Melo goto out_elf_end; 11692e538c4aSArnaldo Carvalho de Melo } 1170ed52ce2eSArnaldo Carvalho de Melo curr_map->map_ip = identity__map_ip; 1171ed52ce2eSArnaldo Carvalho de Melo curr_map->unmap_ip = identity__map_ip; 1172b0a9ab62SArnaldo Carvalho de Melo curr_dso->origin = self->origin; 11739de89fe7SArnaldo Carvalho de Melo map_groups__insert(kmap->kmaps, curr_map); 1174a1645ce1SZhang, Yanmin dsos__add(&self->node, curr_dso); 11756275ce2dSArnaldo Carvalho de Melo dso__set_loaded(curr_dso, map->type); 11762e538c4aSArnaldo Carvalho de Melo } else 11772e538c4aSArnaldo Carvalho de Melo curr_dso = curr_map->dso; 11782e538c4aSArnaldo Carvalho de Melo 11792e538c4aSArnaldo Carvalho de Melo goto new_symbol; 11802e538c4aSArnaldo Carvalho de Melo } 11812e538c4aSArnaldo Carvalho de Melo 11822e538c4aSArnaldo Carvalho de Melo if (curr_dso->adjust_symbols) { 118329a9f66dSArnaldo Carvalho de Melo pr_debug4("%s: adjusting symbol: st_value: %#Lx " 118429a9f66dSArnaldo Carvalho de Melo "sh_addr: %#Lx sh_offset: %#Lx\n", __func__, 118529a9f66dSArnaldo Carvalho de Melo (u64)sym.st_value, (u64)shdr.sh_addr, 118629a9f66dSArnaldo Carvalho de Melo (u64)shdr.sh_offset); 118786470930SIngo Molnar sym.st_value -= shdr.sh_addr - shdr.sh_offset; 1188af427bf5SArnaldo Carvalho de Melo } 118928ac909bSArnaldo Carvalho de Melo /* 119028ac909bSArnaldo Carvalho de Melo * We need to figure out if the object was created from C++ sources 119128ac909bSArnaldo Carvalho de Melo * DWARF DW_compile_unit has this, but we don't always have access 119228ac909bSArnaldo Carvalho de Melo * to it... 119328ac909bSArnaldo Carvalho de Melo */ 119483a0944fSIngo Molnar demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI); 119528ac909bSArnaldo Carvalho de Melo if (demangled != NULL) 119683a0944fSIngo Molnar elf_name = demangled; 11972e538c4aSArnaldo Carvalho de Melo new_symbol: 1198c408fedfSArnaldo Carvalho de Melo f = symbol__new(sym.st_value, sym.st_size, 1199c408fedfSArnaldo Carvalho de Melo GELF_ST_BIND(sym.st_info), elf_name); 120028ac909bSArnaldo Carvalho de Melo free(demangled); 120186470930SIngo Molnar if (!f) 120286470930SIngo Molnar goto out_elf_end; 120386470930SIngo Molnar 12042e538c4aSArnaldo Carvalho de Melo if (filter && filter(curr_map, f)) 120500a192b3SArnaldo Carvalho de Melo symbol__delete(f); 120686470930SIngo Molnar else { 12076a4694a4SArnaldo Carvalho de Melo symbols__insert(&curr_dso->symbols[curr_map->type], f); 120886470930SIngo Molnar nr++; 120986470930SIngo Molnar } 121086470930SIngo Molnar } 121186470930SIngo Molnar 12122e538c4aSArnaldo Carvalho de Melo /* 12132e538c4aSArnaldo Carvalho de Melo * For misannotated, zeroed, ASM function sizes. 12142e538c4aSArnaldo Carvalho de Melo */ 12156275ce2dSArnaldo Carvalho de Melo if (nr > 0) { 12166a4694a4SArnaldo Carvalho de Melo symbols__fixup_end(&self->symbols[map->type]); 12176275ce2dSArnaldo Carvalho de Melo if (kmap) { 12186275ce2dSArnaldo Carvalho de Melo /* 12196275ce2dSArnaldo Carvalho de Melo * We need to fixup this here too because we create new 12206275ce2dSArnaldo Carvalho de Melo * maps here, for things like vsyscall sections. 12216275ce2dSArnaldo Carvalho de Melo */ 12226275ce2dSArnaldo Carvalho de Melo __map_groups__fixup_end(kmap->kmaps, map->type); 12236275ce2dSArnaldo Carvalho de Melo } 12246275ce2dSArnaldo Carvalho de Melo } 122586470930SIngo Molnar err = nr; 122686470930SIngo Molnar out_elf_end: 122786470930SIngo Molnar elf_end(elf); 122886470930SIngo Molnar out_close: 122986470930SIngo Molnar return err; 123086470930SIngo Molnar } 123186470930SIngo Molnar 123278075caaSArnaldo Carvalho de Melo static bool dso__build_id_equal(const struct dso *self, u8 *build_id) 123378075caaSArnaldo Carvalho de Melo { 123478075caaSArnaldo Carvalho de Melo return memcmp(self->build_id, build_id, sizeof(self->build_id)) == 0; 123578075caaSArnaldo Carvalho de Melo } 123678075caaSArnaldo Carvalho de Melo 1237a1645ce1SZhang, Yanmin bool __dsos__read_build_ids(struct list_head *head, bool with_hits) 123857f395a7SFrederic Weisbecker { 1239e30a3d12SArnaldo Carvalho de Melo bool have_build_id = false; 124057f395a7SFrederic Weisbecker struct dso *pos; 124157f395a7SFrederic Weisbecker 12426122e4e4SArnaldo Carvalho de Melo list_for_each_entry(pos, head, node) { 12436122e4e4SArnaldo Carvalho de Melo if (with_hits && !pos->hit) 12446122e4e4SArnaldo Carvalho de Melo continue; 1245f6e1467dSArnaldo Carvalho de Melo if (pos->has_build_id) { 1246f6e1467dSArnaldo Carvalho de Melo have_build_id = true; 1247f6e1467dSArnaldo Carvalho de Melo continue; 1248f6e1467dSArnaldo Carvalho de Melo } 1249e30a3d12SArnaldo Carvalho de Melo if (filename__read_build_id(pos->long_name, pos->build_id, 1250e30a3d12SArnaldo Carvalho de Melo sizeof(pos->build_id)) > 0) { 1251e30a3d12SArnaldo Carvalho de Melo have_build_id = true; 1252e30a3d12SArnaldo Carvalho de Melo pos->has_build_id = true; 125357f395a7SFrederic Weisbecker } 12546122e4e4SArnaldo Carvalho de Melo } 125557f395a7SFrederic Weisbecker 1256e30a3d12SArnaldo Carvalho de Melo return have_build_id; 125757f395a7SFrederic Weisbecker } 125857f395a7SFrederic Weisbecker 1259fd7a346eSArnaldo Carvalho de Melo /* 1260fd7a346eSArnaldo Carvalho de Melo * Align offset to 4 bytes as needed for note name and descriptor data. 1261fd7a346eSArnaldo Carvalho de Melo */ 1262fd7a346eSArnaldo Carvalho de Melo #define NOTE_ALIGN(n) (((n) + 3) & -4U) 1263fd7a346eSArnaldo Carvalho de Melo 126421916c38SDave Martin static int elf_read_build_id(Elf *elf, void *bf, size_t size) 12654d1e00a8SArnaldo Carvalho de Melo { 126621916c38SDave Martin int err = -1; 12674d1e00a8SArnaldo Carvalho de Melo GElf_Ehdr ehdr; 12684d1e00a8SArnaldo Carvalho de Melo GElf_Shdr shdr; 1269fd7a346eSArnaldo Carvalho de Melo Elf_Data *data; 12704d1e00a8SArnaldo Carvalho de Melo Elf_Scn *sec; 1271e57cfcdaSPekka Enberg Elf_Kind ek; 1272fd7a346eSArnaldo Carvalho de Melo void *ptr; 12734d1e00a8SArnaldo Carvalho de Melo 12742643ce11SArnaldo Carvalho de Melo if (size < BUILD_ID_SIZE) 12752643ce11SArnaldo Carvalho de Melo goto out; 12762643ce11SArnaldo Carvalho de Melo 1277e57cfcdaSPekka Enberg ek = elf_kind(elf); 1278e57cfcdaSPekka Enberg if (ek != ELF_K_ELF) 127921916c38SDave Martin goto out; 1280e57cfcdaSPekka Enberg 12814d1e00a8SArnaldo Carvalho de Melo if (gelf_getehdr(elf, &ehdr) == NULL) { 12826beba7adSArnaldo Carvalho de Melo pr_err("%s: cannot get elf header.\n", __func__); 128321916c38SDave Martin goto out; 12844d1e00a8SArnaldo Carvalho de Melo } 12854d1e00a8SArnaldo Carvalho de Melo 12862643ce11SArnaldo Carvalho de Melo sec = elf_section_by_name(elf, &ehdr, &shdr, 12872643ce11SArnaldo Carvalho de Melo ".note.gnu.build-id", NULL); 1288fd7a346eSArnaldo Carvalho de Melo if (sec == NULL) { 1289fd7a346eSArnaldo Carvalho de Melo sec = elf_section_by_name(elf, &ehdr, &shdr, 1290fd7a346eSArnaldo Carvalho de Melo ".notes", NULL); 12914d1e00a8SArnaldo Carvalho de Melo if (sec == NULL) 129221916c38SDave Martin goto out; 1293fd7a346eSArnaldo Carvalho de Melo } 12944d1e00a8SArnaldo Carvalho de Melo 1295fd7a346eSArnaldo Carvalho de Melo data = elf_getdata(sec, NULL); 1296fd7a346eSArnaldo Carvalho de Melo if (data == NULL) 129721916c38SDave Martin goto out; 1298fd7a346eSArnaldo Carvalho de Melo 1299fd7a346eSArnaldo Carvalho de Melo ptr = data->d_buf; 1300fd7a346eSArnaldo Carvalho de Melo while (ptr < (data->d_buf + data->d_size)) { 1301fd7a346eSArnaldo Carvalho de Melo GElf_Nhdr *nhdr = ptr; 1302fd7a346eSArnaldo Carvalho de Melo int namesz = NOTE_ALIGN(nhdr->n_namesz), 1303fd7a346eSArnaldo Carvalho de Melo descsz = NOTE_ALIGN(nhdr->n_descsz); 1304fd7a346eSArnaldo Carvalho de Melo const char *name; 1305fd7a346eSArnaldo Carvalho de Melo 1306fd7a346eSArnaldo Carvalho de Melo ptr += sizeof(*nhdr); 1307fd7a346eSArnaldo Carvalho de Melo name = ptr; 1308fd7a346eSArnaldo Carvalho de Melo ptr += namesz; 1309fd7a346eSArnaldo Carvalho de Melo if (nhdr->n_type == NT_GNU_BUILD_ID && 1310fd7a346eSArnaldo Carvalho de Melo nhdr->n_namesz == sizeof("GNU")) { 1311fd7a346eSArnaldo Carvalho de Melo if (memcmp(name, "GNU", sizeof("GNU")) == 0) { 1312fd7a346eSArnaldo Carvalho de Melo memcpy(bf, ptr, BUILD_ID_SIZE); 13132643ce11SArnaldo Carvalho de Melo err = BUILD_ID_SIZE; 1314fd7a346eSArnaldo Carvalho de Melo break; 1315fd7a346eSArnaldo Carvalho de Melo } 1316fd7a346eSArnaldo Carvalho de Melo } 1317fd7a346eSArnaldo Carvalho de Melo ptr += descsz; 1318fd7a346eSArnaldo Carvalho de Melo } 131921916c38SDave Martin 132021916c38SDave Martin out: 132121916c38SDave Martin return err; 132221916c38SDave Martin } 132321916c38SDave Martin 132421916c38SDave Martin int filename__read_build_id(const char *filename, void *bf, size_t size) 132521916c38SDave Martin { 132621916c38SDave Martin int fd, err = -1; 132721916c38SDave Martin Elf *elf; 132821916c38SDave Martin 132921916c38SDave Martin if (size < BUILD_ID_SIZE) 133021916c38SDave Martin goto out; 133121916c38SDave Martin 133221916c38SDave Martin fd = open(filename, O_RDONLY); 133321916c38SDave Martin if (fd < 0) 133421916c38SDave Martin goto out; 133521916c38SDave Martin 133621916c38SDave Martin elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 133721916c38SDave Martin if (elf == NULL) { 133821916c38SDave Martin pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename); 133921916c38SDave Martin goto out_close; 134021916c38SDave Martin } 134121916c38SDave Martin 134221916c38SDave Martin err = elf_read_build_id(elf, bf, size); 134321916c38SDave Martin 13442643ce11SArnaldo Carvalho de Melo elf_end(elf); 13452643ce11SArnaldo Carvalho de Melo out_close: 13462643ce11SArnaldo Carvalho de Melo close(fd); 13472643ce11SArnaldo Carvalho de Melo out: 13482643ce11SArnaldo Carvalho de Melo return err; 13492643ce11SArnaldo Carvalho de Melo } 13502643ce11SArnaldo Carvalho de Melo 1351f1617b40SArnaldo Carvalho de Melo int sysfs__read_build_id(const char *filename, void *build_id, size_t size) 1352f1617b40SArnaldo Carvalho de Melo { 1353f1617b40SArnaldo Carvalho de Melo int fd, err = -1; 1354f1617b40SArnaldo Carvalho de Melo 1355f1617b40SArnaldo Carvalho de Melo if (size < BUILD_ID_SIZE) 1356f1617b40SArnaldo Carvalho de Melo goto out; 1357f1617b40SArnaldo Carvalho de Melo 1358f1617b40SArnaldo Carvalho de Melo fd = open(filename, O_RDONLY); 1359f1617b40SArnaldo Carvalho de Melo if (fd < 0) 1360f1617b40SArnaldo Carvalho de Melo goto out; 1361f1617b40SArnaldo Carvalho de Melo 1362f1617b40SArnaldo Carvalho de Melo while (1) { 1363f1617b40SArnaldo Carvalho de Melo char bf[BUFSIZ]; 1364f1617b40SArnaldo Carvalho de Melo GElf_Nhdr nhdr; 1365f1617b40SArnaldo Carvalho de Melo int namesz, descsz; 1366f1617b40SArnaldo Carvalho de Melo 1367f1617b40SArnaldo Carvalho de Melo if (read(fd, &nhdr, sizeof(nhdr)) != sizeof(nhdr)) 1368f1617b40SArnaldo Carvalho de Melo break; 1369f1617b40SArnaldo Carvalho de Melo 1370fd7a346eSArnaldo Carvalho de Melo namesz = NOTE_ALIGN(nhdr.n_namesz); 1371fd7a346eSArnaldo Carvalho de Melo descsz = NOTE_ALIGN(nhdr.n_descsz); 1372f1617b40SArnaldo Carvalho de Melo if (nhdr.n_type == NT_GNU_BUILD_ID && 1373f1617b40SArnaldo Carvalho de Melo nhdr.n_namesz == sizeof("GNU")) { 1374f1617b40SArnaldo Carvalho de Melo if (read(fd, bf, namesz) != namesz) 1375f1617b40SArnaldo Carvalho de Melo break; 1376f1617b40SArnaldo Carvalho de Melo if (memcmp(bf, "GNU", sizeof("GNU")) == 0) { 1377f1617b40SArnaldo Carvalho de Melo if (read(fd, build_id, 1378f1617b40SArnaldo Carvalho de Melo BUILD_ID_SIZE) == BUILD_ID_SIZE) { 1379f1617b40SArnaldo Carvalho de Melo err = 0; 1380f1617b40SArnaldo Carvalho de Melo break; 1381f1617b40SArnaldo Carvalho de Melo } 1382f1617b40SArnaldo Carvalho de Melo } else if (read(fd, bf, descsz) != descsz) 1383f1617b40SArnaldo Carvalho de Melo break; 1384f1617b40SArnaldo Carvalho de Melo } else { 1385f1617b40SArnaldo Carvalho de Melo int n = namesz + descsz; 1386f1617b40SArnaldo Carvalho de Melo if (read(fd, bf, n) != n) 1387f1617b40SArnaldo Carvalho de Melo break; 1388f1617b40SArnaldo Carvalho de Melo } 1389f1617b40SArnaldo Carvalho de Melo } 1390f1617b40SArnaldo Carvalho de Melo close(fd); 1391f1617b40SArnaldo Carvalho de Melo out: 1392f1617b40SArnaldo Carvalho de Melo return err; 1393f1617b40SArnaldo Carvalho de Melo } 1394f1617b40SArnaldo Carvalho de Melo 139594cb9e38SArnaldo Carvalho de Melo char dso__symtab_origin(const struct dso *self) 139694cb9e38SArnaldo Carvalho de Melo { 139794cb9e38SArnaldo Carvalho de Melo static const char origin[] = { 139894cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_KERNEL] = 'k', 139994cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_JAVA_JIT] = 'j', 14004cf40131SArnaldo Carvalho de Melo [DSO__ORIG_BUILD_ID_CACHE] = 'B', 140194cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_FEDORA] = 'f', 140294cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_UBUNTU] = 'u', 140394cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_BUILDID] = 'b', 140494cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_DSO] = 'd', 1405439d473bSArnaldo Carvalho de Melo [DSO__ORIG_KMODULE] = 'K', 1406a1645ce1SZhang, Yanmin [DSO__ORIG_GUEST_KERNEL] = 'g', 1407a1645ce1SZhang, Yanmin [DSO__ORIG_GUEST_KMODULE] = 'G', 140894cb9e38SArnaldo Carvalho de Melo }; 140994cb9e38SArnaldo Carvalho de Melo 141094cb9e38SArnaldo Carvalho de Melo if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND) 141194cb9e38SArnaldo Carvalho de Melo return '!'; 141294cb9e38SArnaldo Carvalho de Melo return origin[self->origin]; 141394cb9e38SArnaldo Carvalho de Melo } 141494cb9e38SArnaldo Carvalho de Melo 14159de89fe7SArnaldo Carvalho de Melo int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) 141686470930SIngo Molnar { 14174d1e00a8SArnaldo Carvalho de Melo int size = PATH_MAX; 1418c338aee8SArnaldo Carvalho de Melo char *name; 141986470930SIngo Molnar int ret = -1; 142086470930SIngo Molnar int fd; 142123346f21SArnaldo Carvalho de Melo struct machine *machine; 1422a1645ce1SZhang, Yanmin const char *root_dir; 14236da80ce8SDave Martin int want_symtab; 142486470930SIngo Molnar 14253610583cSArnaldo Carvalho de Melo dso__set_loaded(self, map->type); 142666bd8424SArnaldo Carvalho de Melo 1427a1645ce1SZhang, Yanmin if (self->kernel == DSO_TYPE_KERNEL) 14289de89fe7SArnaldo Carvalho de Melo return dso__load_kernel_sym(self, map, filter); 1429a1645ce1SZhang, Yanmin else if (self->kernel == DSO_TYPE_GUEST_KERNEL) 1430a1645ce1SZhang, Yanmin return dso__load_guest_kernel_sym(self, map, filter); 1431a1645ce1SZhang, Yanmin 143223346f21SArnaldo Carvalho de Melo if (map->groups && map->groups->machine) 143323346f21SArnaldo Carvalho de Melo machine = map->groups->machine; 1434a1645ce1SZhang, Yanmin else 143523346f21SArnaldo Carvalho de Melo machine = NULL; 1436c338aee8SArnaldo Carvalho de Melo 1437c338aee8SArnaldo Carvalho de Melo name = malloc(size); 143886470930SIngo Molnar if (!name) 143986470930SIngo Molnar return -1; 144086470930SIngo Molnar 144130d7a77dSArnaldo Carvalho de Melo self->adjust_symbols = 0; 1442f5812a7aSArnaldo Carvalho de Melo 144394cb9e38SArnaldo Carvalho de Melo if (strncmp(self->name, "/tmp/perf-", 10) == 0) { 14446beba7adSArnaldo Carvalho de Melo ret = dso__load_perf_map(self, map, filter); 144594cb9e38SArnaldo Carvalho de Melo self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT : 144694cb9e38SArnaldo Carvalho de Melo DSO__ORIG_NOT_FOUND; 144794cb9e38SArnaldo Carvalho de Melo return ret; 144894cb9e38SArnaldo Carvalho de Melo } 144994cb9e38SArnaldo Carvalho de Melo 14506da80ce8SDave Martin /* Iterate over candidate debug images. 14516da80ce8SDave Martin * On the first pass, only load images if they have a full symtab. 14526da80ce8SDave Martin * Failing that, do a second pass where we accept .dynsym also 14536da80ce8SDave Martin */ 14546da80ce8SDave Martin for (self->origin = DSO__ORIG_BUILD_ID_CACHE, want_symtab = 1; 14556da80ce8SDave Martin self->origin != DSO__ORIG_NOT_FOUND; 14566da80ce8SDave Martin self->origin++) { 145794cb9e38SArnaldo Carvalho de Melo switch (self->origin) { 14586da80ce8SDave Martin case DSO__ORIG_BUILD_ID_CACHE: 1459*ec5761eaSDavid Ahern /* skip the locally configured cache if a symfs is given */ 1460*ec5761eaSDavid Ahern if (symbol_conf.symfs[0] || 1461*ec5761eaSDavid Ahern (dso__build_id_filename(self, name, size) == NULL)) { 14626da80ce8SDave Martin continue; 1463*ec5761eaSDavid Ahern } 14646da80ce8SDave Martin break; 146594cb9e38SArnaldo Carvalho de Melo case DSO__ORIG_FEDORA: 1466*ec5761eaSDavid Ahern snprintf(name, size, "%s/usr/lib/debug%s.debug", 1467*ec5761eaSDavid Ahern symbol_conf.symfs, self->long_name); 146886470930SIngo Molnar break; 146994cb9e38SArnaldo Carvalho de Melo case DSO__ORIG_UBUNTU: 1470*ec5761eaSDavid Ahern snprintf(name, size, "%s/usr/lib/debug%s", 1471*ec5761eaSDavid Ahern symbol_conf.symfs, self->long_name); 147286470930SIngo Molnar break; 14736da80ce8SDave Martin case DSO__ORIG_BUILDID: { 1474b36f19d5SArnaldo Carvalho de Melo char build_id_hex[BUILD_ID_SIZE * 2 + 1]; 14756da80ce8SDave Martin 14766da80ce8SDave Martin if (!self->has_build_id) 14776da80ce8SDave Martin continue; 14786da80ce8SDave Martin 147921916c38SDave Martin build_id__sprintf(self->build_id, 148021916c38SDave Martin sizeof(self->build_id), 1481d3379ab9SArnaldo Carvalho de Melo build_id_hex); 14824d1e00a8SArnaldo Carvalho de Melo snprintf(name, size, 1483*ec5761eaSDavid Ahern "%s/usr/lib/debug/.build-id/%.2s/%s.debug", 1484*ec5761eaSDavid Ahern symbol_conf.symfs, build_id_hex, build_id_hex + 2); 14854d1e00a8SArnaldo Carvalho de Melo } 14866da80ce8SDave Martin break; 148794cb9e38SArnaldo Carvalho de Melo case DSO__ORIG_DSO: 1488*ec5761eaSDavid Ahern snprintf(name, size, "%s%s", 1489*ec5761eaSDavid Ahern symbol_conf.symfs, self->long_name); 149086470930SIngo Molnar break; 1491a1645ce1SZhang, Yanmin case DSO__ORIG_GUEST_KMODULE: 149223346f21SArnaldo Carvalho de Melo if (map->groups && map->groups->machine) 149323346f21SArnaldo Carvalho de Melo root_dir = map->groups->machine->root_dir; 1494a1645ce1SZhang, Yanmin else 1495a1645ce1SZhang, Yanmin root_dir = ""; 1496*ec5761eaSDavid Ahern snprintf(name, size, "%s%s%s", symbol_conf.symfs, 1497*ec5761eaSDavid Ahern root_dir, self->long_name); 1498*ec5761eaSDavid Ahern break; 1499*ec5761eaSDavid Ahern 1500*ec5761eaSDavid Ahern case DSO__ORIG_KMODULE: 1501*ec5761eaSDavid Ahern snprintf(name, size, "%s%s", symbol_conf.symfs, 1502*ec5761eaSDavid Ahern self->long_name); 1503a1645ce1SZhang, Yanmin break; 150486470930SIngo Molnar 150586470930SIngo Molnar default: 15066da80ce8SDave Martin /* 15076da80ce8SDave Martin * If we wanted a full symtab but no image had one, 15086da80ce8SDave Martin * relax our requirements and repeat the search. 15096da80ce8SDave Martin */ 15106da80ce8SDave Martin if (want_symtab) { 15116da80ce8SDave Martin want_symtab = 0; 15126da80ce8SDave Martin self->origin = DSO__ORIG_BUILD_ID_CACHE; 15136da80ce8SDave Martin } else 15146da80ce8SDave Martin continue; 151586470930SIngo Molnar } 151686470930SIngo Molnar 15176da80ce8SDave Martin /* Name is now the name of the next image to try */ 15186da80ce8SDave Martin fd = open(name, O_RDONLY); 15196da80ce8SDave Martin if (fd < 0) 15206da80ce8SDave Martin continue; 15216da80ce8SDave Martin 15226da80ce8SDave Martin ret = dso__load_sym(self, map, name, fd, filter, 0, 15236da80ce8SDave Martin want_symtab); 152486470930SIngo Molnar close(fd); 152586470930SIngo Molnar 152686470930SIngo Molnar /* 15276da80ce8SDave Martin * Some people seem to have debuginfo files _WITHOUT_ debug 15286da80ce8SDave Martin * info!?!? 152986470930SIngo Molnar */ 153086470930SIngo Molnar if (!ret) 15316da80ce8SDave Martin continue; 153286470930SIngo Molnar 1533a25e46c4SArnaldo Carvalho de Melo if (ret > 0) { 153482164161SArnaldo Carvalho de Melo int nr_plt = dso__synthesize_plt_symbols(self, map, filter); 1535a25e46c4SArnaldo Carvalho de Melo if (nr_plt > 0) 1536a25e46c4SArnaldo Carvalho de Melo ret += nr_plt; 15376da80ce8SDave Martin break; 1538a25e46c4SArnaldo Carvalho de Melo } 15396da80ce8SDave Martin } 15406da80ce8SDave Martin 154186470930SIngo Molnar free(name); 15421340e6bbSArnaldo Carvalho de Melo if (ret < 0 && strstr(self->name, " (deleted)") != NULL) 15431340e6bbSArnaldo Carvalho de Melo return 0; 154486470930SIngo Molnar return ret; 154586470930SIngo Molnar } 154686470930SIngo Molnar 154779406cd7SArnaldo Carvalho de Melo struct map *map_groups__find_by_name(struct map_groups *self, 154879406cd7SArnaldo Carvalho de Melo enum map_type type, const char *name) 1549439d473bSArnaldo Carvalho de Melo { 1550439d473bSArnaldo Carvalho de Melo struct rb_node *nd; 1551439d473bSArnaldo Carvalho de Melo 155279406cd7SArnaldo Carvalho de Melo for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) { 1553439d473bSArnaldo Carvalho de Melo struct map *map = rb_entry(nd, struct map, rb_node); 1554439d473bSArnaldo Carvalho de Melo 1555b7cece76SArnaldo Carvalho de Melo if (map->dso && strcmp(map->dso->short_name, name) == 0) 1556439d473bSArnaldo Carvalho de Melo return map; 1557439d473bSArnaldo Carvalho de Melo } 1558439d473bSArnaldo Carvalho de Melo 1559439d473bSArnaldo Carvalho de Melo return NULL; 1560439d473bSArnaldo Carvalho de Melo } 1561439d473bSArnaldo Carvalho de Melo 1562a1645ce1SZhang, Yanmin static int dso__kernel_module_get_build_id(struct dso *self, 1563a1645ce1SZhang, Yanmin const char *root_dir) 1564b7cece76SArnaldo Carvalho de Melo { 1565b7cece76SArnaldo Carvalho de Melo char filename[PATH_MAX]; 1566b7cece76SArnaldo Carvalho de Melo /* 1567b7cece76SArnaldo Carvalho de Melo * kernel module short names are of the form "[module]" and 1568b7cece76SArnaldo Carvalho de Melo * we need just "module" here. 1569b7cece76SArnaldo Carvalho de Melo */ 1570b7cece76SArnaldo Carvalho de Melo const char *name = self->short_name + 1; 1571b7cece76SArnaldo Carvalho de Melo 1572b7cece76SArnaldo Carvalho de Melo snprintf(filename, sizeof(filename), 1573a1645ce1SZhang, Yanmin "%s/sys/module/%.*s/notes/.note.gnu.build-id", 1574a1645ce1SZhang, Yanmin root_dir, (int)strlen(name) - 1, name); 1575b7cece76SArnaldo Carvalho de Melo 1576b7cece76SArnaldo Carvalho de Melo if (sysfs__read_build_id(filename, self->build_id, 1577b7cece76SArnaldo Carvalho de Melo sizeof(self->build_id)) == 0) 1578b7cece76SArnaldo Carvalho de Melo self->has_build_id = true; 1579b7cece76SArnaldo Carvalho de Melo 1580b7cece76SArnaldo Carvalho de Melo return 0; 1581b7cece76SArnaldo Carvalho de Melo } 1582b7cece76SArnaldo Carvalho de Melo 1583a1645ce1SZhang, Yanmin static int map_groups__set_modules_path_dir(struct map_groups *self, 1584a1645ce1SZhang, Yanmin const char *dir_name) 15856cfcc53eSMike Galbraith { 1586439d473bSArnaldo Carvalho de Melo struct dirent *dent; 15875aab621bSArnaldo Carvalho de Melo DIR *dir = opendir(dir_name); 158874534341SGui Jianfeng int ret = 0; 15896cfcc53eSMike Galbraith 1590439d473bSArnaldo Carvalho de Melo if (!dir) { 15915aab621bSArnaldo Carvalho de Melo pr_debug("%s: cannot open %s dir\n", __func__, dir_name); 1592439d473bSArnaldo Carvalho de Melo return -1; 1593439d473bSArnaldo Carvalho de Melo } 15946cfcc53eSMike Galbraith 1595439d473bSArnaldo Carvalho de Melo while ((dent = readdir(dir)) != NULL) { 1596439d473bSArnaldo Carvalho de Melo char path[PATH_MAX]; 1597a1645ce1SZhang, Yanmin struct stat st; 1598439d473bSArnaldo Carvalho de Melo 1599a1645ce1SZhang, Yanmin /*sshfs might return bad dent->d_type, so we have to stat*/ 1600a1645ce1SZhang, Yanmin sprintf(path, "%s/%s", dir_name, dent->d_name); 1601a1645ce1SZhang, Yanmin if (stat(path, &st)) 1602a1645ce1SZhang, Yanmin continue; 1603a1645ce1SZhang, Yanmin 1604a1645ce1SZhang, Yanmin if (S_ISDIR(st.st_mode)) { 1605439d473bSArnaldo Carvalho de Melo if (!strcmp(dent->d_name, ".") || 1606439d473bSArnaldo Carvalho de Melo !strcmp(dent->d_name, "..")) 1607439d473bSArnaldo Carvalho de Melo continue; 1608439d473bSArnaldo Carvalho de Melo 1609439d473bSArnaldo Carvalho de Melo snprintf(path, sizeof(path), "%s/%s", 16105aab621bSArnaldo Carvalho de Melo dir_name, dent->d_name); 161174534341SGui Jianfeng ret = map_groups__set_modules_path_dir(self, path); 161274534341SGui Jianfeng if (ret < 0) 161374534341SGui Jianfeng goto out; 1614439d473bSArnaldo Carvalho de Melo } else { 1615439d473bSArnaldo Carvalho de Melo char *dot = strrchr(dent->d_name, '.'), 1616439d473bSArnaldo Carvalho de Melo dso_name[PATH_MAX]; 1617439d473bSArnaldo Carvalho de Melo struct map *map; 1618cfc10d3bSArnaldo Carvalho de Melo char *long_name; 1619439d473bSArnaldo Carvalho de Melo 1620439d473bSArnaldo Carvalho de Melo if (dot == NULL || strcmp(dot, ".ko")) 1621439d473bSArnaldo Carvalho de Melo continue; 1622439d473bSArnaldo Carvalho de Melo snprintf(dso_name, sizeof(dso_name), "[%.*s]", 1623439d473bSArnaldo Carvalho de Melo (int)(dot - dent->d_name), dent->d_name); 1624439d473bSArnaldo Carvalho de Melo 1625a2a99e8eSArnaldo Carvalho de Melo strxfrchar(dso_name, '-', '_'); 16269de89fe7SArnaldo Carvalho de Melo map = map_groups__find_by_name(self, MAP__FUNCTION, dso_name); 1627439d473bSArnaldo Carvalho de Melo if (map == NULL) 1628439d473bSArnaldo Carvalho de Melo continue; 1629439d473bSArnaldo Carvalho de Melo 1630439d473bSArnaldo Carvalho de Melo snprintf(path, sizeof(path), "%s/%s", 16315aab621bSArnaldo Carvalho de Melo dir_name, dent->d_name); 1632439d473bSArnaldo Carvalho de Melo 1633cfc10d3bSArnaldo Carvalho de Melo long_name = strdup(path); 163474534341SGui Jianfeng if (long_name == NULL) { 163574534341SGui Jianfeng ret = -1; 163674534341SGui Jianfeng goto out; 163774534341SGui Jianfeng } 1638cfc10d3bSArnaldo Carvalho de Melo dso__set_long_name(map->dso, long_name); 16396e406257SArnaldo Carvalho de Melo map->dso->lname_alloc = 1; 1640a1645ce1SZhang, Yanmin dso__kernel_module_get_build_id(map->dso, ""); 1641439d473bSArnaldo Carvalho de Melo } 1642439d473bSArnaldo Carvalho de Melo } 1643439d473bSArnaldo Carvalho de Melo 164474534341SGui Jianfeng out: 1645439d473bSArnaldo Carvalho de Melo closedir(dir); 164674534341SGui Jianfeng return ret; 1647439d473bSArnaldo Carvalho de Melo } 1648439d473bSArnaldo Carvalho de Melo 1649a1645ce1SZhang, Yanmin static char *get_kernel_version(const char *root_dir) 1650439d473bSArnaldo Carvalho de Melo { 1651a1645ce1SZhang, Yanmin char version[PATH_MAX]; 1652a1645ce1SZhang, Yanmin FILE *file; 1653a1645ce1SZhang, Yanmin char *name, *tmp; 1654a1645ce1SZhang, Yanmin const char *prefix = "Linux version "; 1655a1645ce1SZhang, Yanmin 1656a1645ce1SZhang, Yanmin sprintf(version, "%s/proc/version", root_dir); 1657a1645ce1SZhang, Yanmin file = fopen(version, "r"); 1658a1645ce1SZhang, Yanmin if (!file) 1659a1645ce1SZhang, Yanmin return NULL; 1660a1645ce1SZhang, Yanmin 1661a1645ce1SZhang, Yanmin version[0] = '\0'; 1662a1645ce1SZhang, Yanmin tmp = fgets(version, sizeof(version), file); 1663a1645ce1SZhang, Yanmin fclose(file); 1664a1645ce1SZhang, Yanmin 1665a1645ce1SZhang, Yanmin name = strstr(version, prefix); 1666a1645ce1SZhang, Yanmin if (!name) 1667a1645ce1SZhang, Yanmin return NULL; 1668a1645ce1SZhang, Yanmin name += strlen(prefix); 1669a1645ce1SZhang, Yanmin tmp = strchr(name, ' '); 1670a1645ce1SZhang, Yanmin if (tmp) 1671a1645ce1SZhang, Yanmin *tmp = '\0'; 1672a1645ce1SZhang, Yanmin 1673a1645ce1SZhang, Yanmin return strdup(name); 1674a1645ce1SZhang, Yanmin } 1675a1645ce1SZhang, Yanmin 1676d28c6223SArnaldo Carvalho de Melo static int machine__set_modules_path(struct machine *self) 1677a1645ce1SZhang, Yanmin { 1678a1645ce1SZhang, Yanmin char *version; 1679439d473bSArnaldo Carvalho de Melo char modules_path[PATH_MAX]; 1680439d473bSArnaldo Carvalho de Melo 1681d28c6223SArnaldo Carvalho de Melo version = get_kernel_version(self->root_dir); 1682a1645ce1SZhang, Yanmin if (!version) 1683439d473bSArnaldo Carvalho de Melo return -1; 1684439d473bSArnaldo Carvalho de Melo 1685a1645ce1SZhang, Yanmin snprintf(modules_path, sizeof(modules_path), "%s/lib/modules/%s/kernel", 1686d28c6223SArnaldo Carvalho de Melo self->root_dir, version); 1687a1645ce1SZhang, Yanmin free(version); 1688439d473bSArnaldo Carvalho de Melo 1689d28c6223SArnaldo Carvalho de Melo return map_groups__set_modules_path_dir(&self->kmaps, modules_path); 1690439d473bSArnaldo Carvalho de Melo } 16916cfcc53eSMike Galbraith 16926cfcc53eSMike Galbraith /* 1693439d473bSArnaldo Carvalho de Melo * Constructor variant for modules (where we know from /proc/modules where 1694439d473bSArnaldo Carvalho de Melo * they are loaded) and for vmlinux, where only after we load all the 1695439d473bSArnaldo Carvalho de Melo * symbols we'll know where it starts and ends. 16966cfcc53eSMike Galbraith */ 16973610583cSArnaldo Carvalho de Melo static struct map *map__new2(u64 start, struct dso *dso, enum map_type type) 1698439d473bSArnaldo Carvalho de Melo { 16995aab621bSArnaldo Carvalho de Melo struct map *self = calloc(1, (sizeof(*self) + 17005aab621bSArnaldo Carvalho de Melo (dso->kernel ? sizeof(struct kmap) : 0))); 1701439d473bSArnaldo Carvalho de Melo if (self != NULL) { 1702439d473bSArnaldo Carvalho de Melo /* 1703afb7b4f0SArnaldo Carvalho de Melo * ->end will be filled after we load all the symbols 1704439d473bSArnaldo Carvalho de Melo */ 17053610583cSArnaldo Carvalho de Melo map__init(self, type, start, 0, 0, dso); 1706439d473bSArnaldo Carvalho de Melo } 1707afb7b4f0SArnaldo Carvalho de Melo 1708439d473bSArnaldo Carvalho de Melo return self; 1709439d473bSArnaldo Carvalho de Melo } 1710439d473bSArnaldo Carvalho de Melo 1711d28c6223SArnaldo Carvalho de Melo struct map *machine__new_module(struct machine *self, u64 start, 1712d28c6223SArnaldo Carvalho de Melo const char *filename) 1713b7cece76SArnaldo Carvalho de Melo { 1714b7cece76SArnaldo Carvalho de Melo struct map *map; 1715d28c6223SArnaldo Carvalho de Melo struct dso *dso = __dsos__findnew(&self->kernel_dsos, filename); 1716b7cece76SArnaldo Carvalho de Melo 1717b7cece76SArnaldo Carvalho de Melo if (dso == NULL) 1718b7cece76SArnaldo Carvalho de Melo return NULL; 1719b7cece76SArnaldo Carvalho de Melo 1720b7cece76SArnaldo Carvalho de Melo map = map__new2(start, dso, MAP__FUNCTION); 1721b7cece76SArnaldo Carvalho de Melo if (map == NULL) 1722b7cece76SArnaldo Carvalho de Melo return NULL; 1723b7cece76SArnaldo Carvalho de Melo 1724d28c6223SArnaldo Carvalho de Melo if (machine__is_host(self)) 1725b7cece76SArnaldo Carvalho de Melo dso->origin = DSO__ORIG_KMODULE; 1726a1645ce1SZhang, Yanmin else 1727a1645ce1SZhang, Yanmin dso->origin = DSO__ORIG_GUEST_KMODULE; 1728d28c6223SArnaldo Carvalho de Melo map_groups__insert(&self->kmaps, map); 1729b7cece76SArnaldo Carvalho de Melo return map; 1730b7cece76SArnaldo Carvalho de Melo } 1731b7cece76SArnaldo Carvalho de Melo 1732d28c6223SArnaldo Carvalho de Melo static int machine__create_modules(struct machine *self) 1733439d473bSArnaldo Carvalho de Melo { 1734439d473bSArnaldo Carvalho de Melo char *line = NULL; 1735439d473bSArnaldo Carvalho de Melo size_t n; 1736a1645ce1SZhang, Yanmin FILE *file; 1737439d473bSArnaldo Carvalho de Melo struct map *map; 1738a1645ce1SZhang, Yanmin const char *modules; 1739a1645ce1SZhang, Yanmin char path[PATH_MAX]; 1740439d473bSArnaldo Carvalho de Melo 1741d28c6223SArnaldo Carvalho de Melo if (machine__is_default_guest(self)) 1742a1645ce1SZhang, Yanmin modules = symbol_conf.default_guest_modules; 1743a1645ce1SZhang, Yanmin else { 1744d28c6223SArnaldo Carvalho de Melo sprintf(path, "%s/proc/modules", self->root_dir); 1745a1645ce1SZhang, Yanmin modules = path; 1746a1645ce1SZhang, Yanmin } 1747a1645ce1SZhang, Yanmin 1748a1645ce1SZhang, Yanmin file = fopen(modules, "r"); 1749439d473bSArnaldo Carvalho de Melo if (file == NULL) 1750439d473bSArnaldo Carvalho de Melo return -1; 1751439d473bSArnaldo Carvalho de Melo 1752439d473bSArnaldo Carvalho de Melo while (!feof(file)) { 1753439d473bSArnaldo Carvalho de Melo char name[PATH_MAX]; 1754439d473bSArnaldo Carvalho de Melo u64 start; 1755439d473bSArnaldo Carvalho de Melo char *sep; 1756439d473bSArnaldo Carvalho de Melo int line_len; 1757439d473bSArnaldo Carvalho de Melo 1758439d473bSArnaldo Carvalho de Melo line_len = getline(&line, &n, file); 1759439d473bSArnaldo Carvalho de Melo if (line_len < 0) 17606cfcc53eSMike Galbraith break; 17616cfcc53eSMike Galbraith 1762439d473bSArnaldo Carvalho de Melo if (!line) 1763439d473bSArnaldo Carvalho de Melo goto out_failure; 1764439d473bSArnaldo Carvalho de Melo 1765439d473bSArnaldo Carvalho de Melo line[--line_len] = '\0'; /* \n */ 1766439d473bSArnaldo Carvalho de Melo 1767439d473bSArnaldo Carvalho de Melo sep = strrchr(line, 'x'); 1768439d473bSArnaldo Carvalho de Melo if (sep == NULL) 1769439d473bSArnaldo Carvalho de Melo continue; 1770439d473bSArnaldo Carvalho de Melo 1771439d473bSArnaldo Carvalho de Melo hex2u64(sep + 1, &start); 1772439d473bSArnaldo Carvalho de Melo 1773439d473bSArnaldo Carvalho de Melo sep = strchr(line, ' '); 1774439d473bSArnaldo Carvalho de Melo if (sep == NULL) 1775439d473bSArnaldo Carvalho de Melo continue; 1776439d473bSArnaldo Carvalho de Melo 1777439d473bSArnaldo Carvalho de Melo *sep = '\0'; 1778439d473bSArnaldo Carvalho de Melo 1779439d473bSArnaldo Carvalho de Melo snprintf(name, sizeof(name), "[%s]", line); 1780d28c6223SArnaldo Carvalho de Melo map = machine__new_module(self, start, name); 1781b7cece76SArnaldo Carvalho de Melo if (map == NULL) 1782439d473bSArnaldo Carvalho de Melo goto out_delete_line; 1783d28c6223SArnaldo Carvalho de Melo dso__kernel_module_get_build_id(map->dso, self->root_dir); 17846cfcc53eSMike Galbraith } 17856cfcc53eSMike Galbraith 1786439d473bSArnaldo Carvalho de Melo free(line); 1787439d473bSArnaldo Carvalho de Melo fclose(file); 1788439d473bSArnaldo Carvalho de Melo 1789d28c6223SArnaldo Carvalho de Melo return machine__set_modules_path(self); 1790439d473bSArnaldo Carvalho de Melo 1791439d473bSArnaldo Carvalho de Melo out_delete_line: 1792439d473bSArnaldo Carvalho de Melo free(line); 1793439d473bSArnaldo Carvalho de Melo out_failure: 1794439d473bSArnaldo Carvalho de Melo return -1; 17956cfcc53eSMike Galbraith } 17966cfcc53eSMike Galbraith 17979958e1f0SArnaldo Carvalho de Melo static int dso__load_vmlinux(struct dso *self, struct map *map, 17986beba7adSArnaldo Carvalho de Melo const char *vmlinux, symbol_filter_t filter) 179986470930SIngo Molnar { 1800fbd733b8SArnaldo Carvalho de Melo int err = -1, fd; 1801*ec5761eaSDavid Ahern char symfs_vmlinux[PATH_MAX]; 180286470930SIngo Molnar 1803*ec5761eaSDavid Ahern snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s/%s", 1804*ec5761eaSDavid Ahern symbol_conf.symfs, vmlinux); 1805*ec5761eaSDavid Ahern fd = open(symfs_vmlinux, O_RDONLY); 180686470930SIngo Molnar if (fd < 0) 180786470930SIngo Molnar return -1; 180886470930SIngo Molnar 18093610583cSArnaldo Carvalho de Melo dso__set_loaded(self, map->type); 1810*ec5761eaSDavid Ahern err = dso__load_sym(self, map, symfs_vmlinux, fd, filter, 0, 0); 181186470930SIngo Molnar close(fd); 181286470930SIngo Molnar 18133846df2eSArnaldo Carvalho de Melo if (err > 0) 1814*ec5761eaSDavid Ahern pr_debug("Using %s for symbols\n", symfs_vmlinux); 18153846df2eSArnaldo Carvalho de Melo 181686470930SIngo Molnar return err; 181786470930SIngo Molnar } 181886470930SIngo Molnar 1819a19afe46SArnaldo Carvalho de Melo int dso__load_vmlinux_path(struct dso *self, struct map *map, 18209de89fe7SArnaldo Carvalho de Melo symbol_filter_t filter) 1821a19afe46SArnaldo Carvalho de Melo { 1822a19afe46SArnaldo Carvalho de Melo int i, err = 0; 18235ad90e4eSArnaldo Carvalho de Melo char *filename; 1824a19afe46SArnaldo Carvalho de Melo 1825a19afe46SArnaldo Carvalho de Melo pr_debug("Looking at the vmlinux_path (%d entries long)\n", 18265ad90e4eSArnaldo Carvalho de Melo vmlinux_path__nr_entries + 1); 18275ad90e4eSArnaldo Carvalho de Melo 18285ad90e4eSArnaldo Carvalho de Melo filename = dso__build_id_filename(self, NULL, 0); 18295ad90e4eSArnaldo Carvalho de Melo if (filename != NULL) { 18305ad90e4eSArnaldo Carvalho de Melo err = dso__load_vmlinux(self, map, filename, filter); 18315ad90e4eSArnaldo Carvalho de Melo if (err > 0) { 18325ad90e4eSArnaldo Carvalho de Melo dso__set_long_name(self, filename); 18335ad90e4eSArnaldo Carvalho de Melo goto out; 18345ad90e4eSArnaldo Carvalho de Melo } 18355ad90e4eSArnaldo Carvalho de Melo free(filename); 18365ad90e4eSArnaldo Carvalho de Melo } 1837a19afe46SArnaldo Carvalho de Melo 1838a19afe46SArnaldo Carvalho de Melo for (i = 0; i < vmlinux_path__nr_entries; ++i) { 18399de89fe7SArnaldo Carvalho de Melo err = dso__load_vmlinux(self, map, vmlinux_path[i], filter); 1840a19afe46SArnaldo Carvalho de Melo if (err > 0) { 1841a19afe46SArnaldo Carvalho de Melo dso__set_long_name(self, strdup(vmlinux_path[i])); 1842a19afe46SArnaldo Carvalho de Melo break; 1843a19afe46SArnaldo Carvalho de Melo } 1844a19afe46SArnaldo Carvalho de Melo } 18455ad90e4eSArnaldo Carvalho de Melo out: 1846a19afe46SArnaldo Carvalho de Melo return err; 1847a19afe46SArnaldo Carvalho de Melo } 1848a19afe46SArnaldo Carvalho de Melo 1849c338aee8SArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *self, struct map *map, 18509de89fe7SArnaldo Carvalho de Melo symbol_filter_t filter) 185186470930SIngo Molnar { 1852cc612d81SArnaldo Carvalho de Melo int err; 18539e201442SArnaldo Carvalho de Melo const char *kallsyms_filename = NULL; 18549e201442SArnaldo Carvalho de Melo char *kallsyms_allocated_filename = NULL; 1855dc8d6ab2SArnaldo Carvalho de Melo /* 1856b226a5a7SDavid Ahern * Step 1: if the user specified a kallsyms or vmlinux filename, use 1857b226a5a7SDavid Ahern * it and only it, reporting errors to the user if it cannot be used. 1858dc8d6ab2SArnaldo Carvalho de Melo * 1859dc8d6ab2SArnaldo Carvalho de Melo * For instance, try to analyse an ARM perf.data file _without_ a 1860dc8d6ab2SArnaldo Carvalho de Melo * build-id, or if the user specifies the wrong path to the right 1861dc8d6ab2SArnaldo Carvalho de Melo * vmlinux file, obviously we can't fallback to another vmlinux (a 1862dc8d6ab2SArnaldo Carvalho de Melo * x86_86 one, on the machine where analysis is being performed, say), 1863dc8d6ab2SArnaldo Carvalho de Melo * or worse, /proc/kallsyms. 1864dc8d6ab2SArnaldo Carvalho de Melo * 1865dc8d6ab2SArnaldo Carvalho de Melo * If the specified file _has_ a build-id and there is a build-id 1866dc8d6ab2SArnaldo Carvalho de Melo * section in the perf.data file, we will still do the expected 1867dc8d6ab2SArnaldo Carvalho de Melo * validation in dso__load_vmlinux and will bail out if they don't 1868dc8d6ab2SArnaldo Carvalho de Melo * match. 1869dc8d6ab2SArnaldo Carvalho de Melo */ 1870b226a5a7SDavid Ahern if (symbol_conf.kallsyms_name != NULL) { 1871b226a5a7SDavid Ahern kallsyms_filename = symbol_conf.kallsyms_name; 1872b226a5a7SDavid Ahern goto do_kallsyms; 1873b226a5a7SDavid Ahern } 1874b226a5a7SDavid Ahern 1875dc8d6ab2SArnaldo Carvalho de Melo if (symbol_conf.vmlinux_name != NULL) { 18769de89fe7SArnaldo Carvalho de Melo err = dso__load_vmlinux(self, map, 1877dc8d6ab2SArnaldo Carvalho de Melo symbol_conf.vmlinux_name, filter); 1878e7dadc00SArnaldo Carvalho de Melo if (err > 0) { 1879e7dadc00SArnaldo Carvalho de Melo dso__set_long_name(self, 1880e7dadc00SArnaldo Carvalho de Melo strdup(symbol_conf.vmlinux_name)); 1881e7dadc00SArnaldo Carvalho de Melo goto out_fixup; 1882e7dadc00SArnaldo Carvalho de Melo } 1883e7dadc00SArnaldo Carvalho de Melo return err; 1884dc8d6ab2SArnaldo Carvalho de Melo } 1885439d473bSArnaldo Carvalho de Melo 1886cc612d81SArnaldo Carvalho de Melo if (vmlinux_path != NULL) { 18879de89fe7SArnaldo Carvalho de Melo err = dso__load_vmlinux_path(self, map, filter); 1888a19afe46SArnaldo Carvalho de Melo if (err > 0) 1889cc612d81SArnaldo Carvalho de Melo goto out_fixup; 1890cc612d81SArnaldo Carvalho de Melo } 1891cc612d81SArnaldo Carvalho de Melo 1892*ec5761eaSDavid Ahern /* do not try local files if a symfs was given */ 1893*ec5761eaSDavid Ahern if (symbol_conf.symfs[0] != 0) 1894*ec5761eaSDavid Ahern return -1; 1895*ec5761eaSDavid Ahern 1896b7cece76SArnaldo Carvalho de Melo /* 1897b7cece76SArnaldo Carvalho de Melo * Say the kernel DSO was created when processing the build-id header table, 1898b7cece76SArnaldo Carvalho de Melo * we have a build-id, so check if it is the same as the running kernel, 1899b7cece76SArnaldo Carvalho de Melo * using it if it is. 1900b7cece76SArnaldo Carvalho de Melo */ 1901b7cece76SArnaldo Carvalho de Melo if (self->has_build_id) { 1902b7cece76SArnaldo Carvalho de Melo u8 kallsyms_build_id[BUILD_ID_SIZE]; 19039e201442SArnaldo Carvalho de Melo char sbuild_id[BUILD_ID_SIZE * 2 + 1]; 1904b7cece76SArnaldo Carvalho de Melo 1905b7cece76SArnaldo Carvalho de Melo if (sysfs__read_build_id("/sys/kernel/notes", kallsyms_build_id, 19068d0591f6SArnaldo Carvalho de Melo sizeof(kallsyms_build_id)) == 0) { 19079e201442SArnaldo Carvalho de Melo if (dso__build_id_equal(self, kallsyms_build_id)) { 19089e201442SArnaldo Carvalho de Melo kallsyms_filename = "/proc/kallsyms"; 1909b7cece76SArnaldo Carvalho de Melo goto do_kallsyms; 19108d0591f6SArnaldo Carvalho de Melo } 19119e201442SArnaldo Carvalho de Melo } 1912dc8d6ab2SArnaldo Carvalho de Melo /* 1913dc8d6ab2SArnaldo Carvalho de Melo * Now look if we have it on the build-id cache in 1914dc8d6ab2SArnaldo Carvalho de Melo * $HOME/.debug/[kernel.kallsyms]. 1915dc8d6ab2SArnaldo Carvalho de Melo */ 19169e201442SArnaldo Carvalho de Melo build_id__sprintf(self->build_id, sizeof(self->build_id), 19179e201442SArnaldo Carvalho de Melo sbuild_id); 19189e201442SArnaldo Carvalho de Melo 19199e201442SArnaldo Carvalho de Melo if (asprintf(&kallsyms_allocated_filename, 19209e201442SArnaldo Carvalho de Melo "%s/.debug/[kernel.kallsyms]/%s", 19213846df2eSArnaldo Carvalho de Melo getenv("HOME"), sbuild_id) == -1) { 19223846df2eSArnaldo Carvalho de Melo pr_err("Not enough memory for kallsyms file lookup\n"); 19238d0591f6SArnaldo Carvalho de Melo return -1; 19243846df2eSArnaldo Carvalho de Melo } 19258d0591f6SArnaldo Carvalho de Melo 192619fc2dedSArnaldo Carvalho de Melo kallsyms_filename = kallsyms_allocated_filename; 192719fc2dedSArnaldo Carvalho de Melo 1928dc8d6ab2SArnaldo Carvalho de Melo if (access(kallsyms_filename, F_OK)) { 19293846df2eSArnaldo Carvalho de Melo pr_err("No kallsyms or vmlinux with build-id %s " 19303846df2eSArnaldo Carvalho de Melo "was found\n", sbuild_id); 19319e201442SArnaldo Carvalho de Melo free(kallsyms_allocated_filename); 1932dc8d6ab2SArnaldo Carvalho de Melo return -1; 1933ef6ae724SArnaldo Carvalho de Melo } 1934dc8d6ab2SArnaldo Carvalho de Melo } else { 1935dc8d6ab2SArnaldo Carvalho de Melo /* 1936dc8d6ab2SArnaldo Carvalho de Melo * Last resort, if we don't have a build-id and couldn't find 1937dc8d6ab2SArnaldo Carvalho de Melo * any vmlinux file, try the running kernel kallsyms table. 1938dc8d6ab2SArnaldo Carvalho de Melo */ 1939dc8d6ab2SArnaldo Carvalho de Melo kallsyms_filename = "/proc/kallsyms"; 1940dc8d6ab2SArnaldo Carvalho de Melo } 1941dc8d6ab2SArnaldo Carvalho de Melo 1942dc8d6ab2SArnaldo Carvalho de Melo do_kallsyms: 19439de89fe7SArnaldo Carvalho de Melo err = dso__load_kallsyms(self, kallsyms_filename, map, filter); 19443846df2eSArnaldo Carvalho de Melo if (err > 0) 19453846df2eSArnaldo Carvalho de Melo pr_debug("Using %s for symbols\n", kallsyms_filename); 1946dc8d6ab2SArnaldo Carvalho de Melo free(kallsyms_allocated_filename); 1947dc8d6ab2SArnaldo Carvalho de Melo 1948439d473bSArnaldo Carvalho de Melo if (err > 0) { 1949cc612d81SArnaldo Carvalho de Melo out_fixup: 1950e1c7c6a4SArnaldo Carvalho de Melo if (kallsyms_filename != NULL) 1951dc8d6ab2SArnaldo Carvalho de Melo dso__set_long_name(self, strdup("[kernel.kallsyms]")); 19526a4694a4SArnaldo Carvalho de Melo map__fixup_start(map); 19536a4694a4SArnaldo Carvalho de Melo map__fixup_end(map); 1954439d473bSArnaldo Carvalho de Melo } 195594cb9e38SArnaldo Carvalho de Melo 195686470930SIngo Molnar return err; 195786470930SIngo Molnar } 195886470930SIngo Molnar 1959a1645ce1SZhang, Yanmin static int dso__load_guest_kernel_sym(struct dso *self, struct map *map, 1960a1645ce1SZhang, Yanmin symbol_filter_t filter) 1961a1645ce1SZhang, Yanmin { 1962a1645ce1SZhang, Yanmin int err; 1963a1645ce1SZhang, Yanmin const char *kallsyms_filename = NULL; 196423346f21SArnaldo Carvalho de Melo struct machine *machine; 1965a1645ce1SZhang, Yanmin char path[PATH_MAX]; 1966a1645ce1SZhang, Yanmin 1967a1645ce1SZhang, Yanmin if (!map->groups) { 1968a1645ce1SZhang, Yanmin pr_debug("Guest kernel map hasn't the point to groups\n"); 1969a1645ce1SZhang, Yanmin return -1; 1970a1645ce1SZhang, Yanmin } 197123346f21SArnaldo Carvalho de Melo machine = map->groups->machine; 1972a1645ce1SZhang, Yanmin 197323346f21SArnaldo Carvalho de Melo if (machine__is_default_guest(machine)) { 1974a1645ce1SZhang, Yanmin /* 1975a1645ce1SZhang, Yanmin * if the user specified a vmlinux filename, use it and only 1976a1645ce1SZhang, Yanmin * it, reporting errors to the user if it cannot be used. 1977a1645ce1SZhang, Yanmin * Or use file guest_kallsyms inputted by user on commandline 1978a1645ce1SZhang, Yanmin */ 1979a1645ce1SZhang, Yanmin if (symbol_conf.default_guest_vmlinux_name != NULL) { 1980a1645ce1SZhang, Yanmin err = dso__load_vmlinux(self, map, 1981a1645ce1SZhang, Yanmin symbol_conf.default_guest_vmlinux_name, filter); 1982a1645ce1SZhang, Yanmin goto out_try_fixup; 1983a1645ce1SZhang, Yanmin } 1984a1645ce1SZhang, Yanmin 1985a1645ce1SZhang, Yanmin kallsyms_filename = symbol_conf.default_guest_kallsyms; 1986a1645ce1SZhang, Yanmin if (!kallsyms_filename) 1987a1645ce1SZhang, Yanmin return -1; 1988a1645ce1SZhang, Yanmin } else { 198923346f21SArnaldo Carvalho de Melo sprintf(path, "%s/proc/kallsyms", machine->root_dir); 1990a1645ce1SZhang, Yanmin kallsyms_filename = path; 1991a1645ce1SZhang, Yanmin } 1992a1645ce1SZhang, Yanmin 1993a1645ce1SZhang, Yanmin err = dso__load_kallsyms(self, kallsyms_filename, map, filter); 1994a1645ce1SZhang, Yanmin if (err > 0) 1995a1645ce1SZhang, Yanmin pr_debug("Using %s for symbols\n", kallsyms_filename); 1996a1645ce1SZhang, Yanmin 1997a1645ce1SZhang, Yanmin out_try_fixup: 1998a1645ce1SZhang, Yanmin if (err > 0) { 1999a1645ce1SZhang, Yanmin if (kallsyms_filename != NULL) { 200048ea8f54SArnaldo Carvalho de Melo machine__mmap_name(machine, path, sizeof(path)); 200123346f21SArnaldo Carvalho de Melo dso__set_long_name(self, strdup(path)); 2002a1645ce1SZhang, Yanmin } 2003a1645ce1SZhang, Yanmin map__fixup_start(map); 2004a1645ce1SZhang, Yanmin map__fixup_end(map); 2005a1645ce1SZhang, Yanmin } 2006a1645ce1SZhang, Yanmin 2007a1645ce1SZhang, Yanmin return err; 2008a1645ce1SZhang, Yanmin } 2009cd84c2acSFrederic Weisbecker 2010b0da954aSArnaldo Carvalho de Melo static void dsos__add(struct list_head *head, struct dso *dso) 2011cd84c2acSFrederic Weisbecker { 2012b0da954aSArnaldo Carvalho de Melo list_add_tail(&dso->node, head); 2013cd84c2acSFrederic Weisbecker } 2014cd84c2acSFrederic Weisbecker 2015b0da954aSArnaldo Carvalho de Melo static struct dso *dsos__find(struct list_head *head, const char *name) 2016cd84c2acSFrederic Weisbecker { 2017cd84c2acSFrederic Weisbecker struct dso *pos; 2018cd84c2acSFrederic Weisbecker 2019b0da954aSArnaldo Carvalho de Melo list_for_each_entry(pos, head, node) 2020cf4e5b08SArnaldo Carvalho de Melo if (strcmp(pos->long_name, name) == 0) 2021cd84c2acSFrederic Weisbecker return pos; 2022cd84c2acSFrederic Weisbecker return NULL; 2023cd84c2acSFrederic Weisbecker } 2024cd84c2acSFrederic Weisbecker 2025a89e5abeSArnaldo Carvalho de Melo struct dso *__dsos__findnew(struct list_head *head, const char *name) 2026cd84c2acSFrederic Weisbecker { 2027a89e5abeSArnaldo Carvalho de Melo struct dso *dso = dsos__find(head, name); 2028cd84c2acSFrederic Weisbecker 2029e4204992SArnaldo Carvalho de Melo if (!dso) { 203000a192b3SArnaldo Carvalho de Melo dso = dso__new(name); 2031cfc10d3bSArnaldo Carvalho de Melo if (dso != NULL) { 2032a89e5abeSArnaldo Carvalho de Melo dsos__add(head, dso); 2033cfc10d3bSArnaldo Carvalho de Melo dso__set_basename(dso); 2034cfc10d3bSArnaldo Carvalho de Melo } 2035e4204992SArnaldo Carvalho de Melo } 2036cd84c2acSFrederic Weisbecker 2037cd84c2acSFrederic Weisbecker return dso; 2038cd84c2acSFrederic Weisbecker } 2039cd84c2acSFrederic Weisbecker 20401f626bc3SArnaldo Carvalho de Melo size_t __dsos__fprintf(struct list_head *head, FILE *fp) 2041cd84c2acSFrederic Weisbecker { 2042cd84c2acSFrederic Weisbecker struct dso *pos; 2043cbf69680SArnaldo Carvalho de Melo size_t ret = 0; 2044cd84c2acSFrederic Weisbecker 204595011c60SArnaldo Carvalho de Melo list_for_each_entry(pos, head, node) { 204695011c60SArnaldo Carvalho de Melo int i; 204795011c60SArnaldo Carvalho de Melo for (i = 0; i < MAP__NR_TYPES; ++i) 2048cbf69680SArnaldo Carvalho de Melo ret += dso__fprintf(pos, i, fp); 2049cd84c2acSFrederic Weisbecker } 2050cd84c2acSFrederic Weisbecker 2051cbf69680SArnaldo Carvalho de Melo return ret; 2052cbf69680SArnaldo Carvalho de Melo } 2053cbf69680SArnaldo Carvalho de Melo 2054cbf69680SArnaldo Carvalho de Melo size_t machines__fprintf_dsos(struct rb_root *self, FILE *fp) 2055b0da954aSArnaldo Carvalho de Melo { 2056a1645ce1SZhang, Yanmin struct rb_node *nd; 2057cbf69680SArnaldo Carvalho de Melo size_t ret = 0; 2058a1645ce1SZhang, Yanmin 2059cbf69680SArnaldo Carvalho de Melo for (nd = rb_first(self); nd; nd = rb_next(nd)) { 206023346f21SArnaldo Carvalho de Melo struct machine *pos = rb_entry(nd, struct machine, rb_node); 2061cbf69680SArnaldo Carvalho de Melo ret += __dsos__fprintf(&pos->kernel_dsos, fp); 2062cbf69680SArnaldo Carvalho de Melo ret += __dsos__fprintf(&pos->user_dsos, fp); 2063a1645ce1SZhang, Yanmin } 2064cbf69680SArnaldo Carvalho de Melo 2065cbf69680SArnaldo Carvalho de Melo return ret; 2066b0da954aSArnaldo Carvalho de Melo } 2067b0da954aSArnaldo Carvalho de Melo 206888d3d9b7SArnaldo Carvalho de Melo static size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp, 206988d3d9b7SArnaldo Carvalho de Melo bool with_hits) 20709e03eb2dSArnaldo Carvalho de Melo { 20719e03eb2dSArnaldo Carvalho de Melo struct dso *pos; 20729e03eb2dSArnaldo Carvalho de Melo size_t ret = 0; 20739e03eb2dSArnaldo Carvalho de Melo 2074b0da954aSArnaldo Carvalho de Melo list_for_each_entry(pos, head, node) { 207588d3d9b7SArnaldo Carvalho de Melo if (with_hits && !pos->hit) 207688d3d9b7SArnaldo Carvalho de Melo continue; 20779e03eb2dSArnaldo Carvalho de Melo ret += dso__fprintf_buildid(pos, fp); 20789e03eb2dSArnaldo Carvalho de Melo ret += fprintf(fp, " %s\n", pos->long_name); 20799e03eb2dSArnaldo Carvalho de Melo } 20809e03eb2dSArnaldo Carvalho de Melo return ret; 20819e03eb2dSArnaldo Carvalho de Melo } 20829e03eb2dSArnaldo Carvalho de Melo 2083f869097eSArnaldo Carvalho de Melo size_t machine__fprintf_dsos_buildid(struct machine *self, FILE *fp, bool with_hits) 2084f869097eSArnaldo Carvalho de Melo { 2085f869097eSArnaldo Carvalho de Melo return __dsos__fprintf_buildid(&self->kernel_dsos, fp, with_hits) + 2086f869097eSArnaldo Carvalho de Melo __dsos__fprintf_buildid(&self->user_dsos, fp, with_hits); 2087f869097eSArnaldo Carvalho de Melo } 2088f869097eSArnaldo Carvalho de Melo 2089cbf69680SArnaldo Carvalho de Melo size_t machines__fprintf_dsos_buildid(struct rb_root *self, FILE *fp, bool with_hits) 2090b0da954aSArnaldo Carvalho de Melo { 2091a1645ce1SZhang, Yanmin struct rb_node *nd; 2092a1645ce1SZhang, Yanmin size_t ret = 0; 2093a1645ce1SZhang, Yanmin 2094cbf69680SArnaldo Carvalho de Melo for (nd = rb_first(self); nd; nd = rb_next(nd)) { 209523346f21SArnaldo Carvalho de Melo struct machine *pos = rb_entry(nd, struct machine, rb_node); 2096f869097eSArnaldo Carvalho de Melo ret += machine__fprintf_dsos_buildid(pos, fp, with_hits); 2097a1645ce1SZhang, Yanmin } 2098a1645ce1SZhang, Yanmin return ret; 2099b0da954aSArnaldo Carvalho de Melo } 2100b0da954aSArnaldo Carvalho de Melo 2101fd1d908cSArnaldo Carvalho de Melo struct dso *dso__new_kernel(const char *name) 2102fd1d908cSArnaldo Carvalho de Melo { 2103fd1d908cSArnaldo Carvalho de Melo struct dso *self = dso__new(name ?: "[kernel.kallsyms]"); 2104fd1d908cSArnaldo Carvalho de Melo 2105fd1d908cSArnaldo Carvalho de Melo if (self != NULL) { 2106b63be8d7SArnaldo Carvalho de Melo dso__set_short_name(self, "[kernel]"); 2107a1645ce1SZhang, Yanmin self->kernel = DSO_TYPE_KERNEL; 2108fd1d908cSArnaldo Carvalho de Melo } 2109fd1d908cSArnaldo Carvalho de Melo 2110fd1d908cSArnaldo Carvalho de Melo return self; 2111fd1d908cSArnaldo Carvalho de Melo } 2112fd1d908cSArnaldo Carvalho de Melo 211323346f21SArnaldo Carvalho de Melo static struct dso *dso__new_guest_kernel(struct machine *machine, 2114a1645ce1SZhang, Yanmin const char *name) 2115fd1d908cSArnaldo Carvalho de Melo { 211648ea8f54SArnaldo Carvalho de Melo char bf[PATH_MAX]; 211748ea8f54SArnaldo Carvalho de Melo struct dso *self = dso__new(name ?: machine__mmap_name(machine, bf, sizeof(bf))); 2118a1645ce1SZhang, Yanmin 2119a1645ce1SZhang, Yanmin if (self != NULL) { 2120a1645ce1SZhang, Yanmin dso__set_short_name(self, "[guest.kernel]"); 2121a1645ce1SZhang, Yanmin self->kernel = DSO_TYPE_GUEST_KERNEL; 2122a1645ce1SZhang, Yanmin } 2123a1645ce1SZhang, Yanmin 2124a1645ce1SZhang, Yanmin return self; 2125a1645ce1SZhang, Yanmin } 2126a1645ce1SZhang, Yanmin 212723346f21SArnaldo Carvalho de Melo void dso__read_running_kernel_build_id(struct dso *self, struct machine *machine) 2128a1645ce1SZhang, Yanmin { 2129a1645ce1SZhang, Yanmin char path[PATH_MAX]; 2130a1645ce1SZhang, Yanmin 213123346f21SArnaldo Carvalho de Melo if (machine__is_default_guest(machine)) 2132a1645ce1SZhang, Yanmin return; 213323346f21SArnaldo Carvalho de Melo sprintf(path, "%s/sys/kernel/notes", machine->root_dir); 2134a1645ce1SZhang, Yanmin if (sysfs__read_build_id(path, self->build_id, 2135fd1d908cSArnaldo Carvalho de Melo sizeof(self->build_id)) == 0) 2136fd1d908cSArnaldo Carvalho de Melo self->has_build_id = true; 2137fd1d908cSArnaldo Carvalho de Melo } 2138fd1d908cSArnaldo Carvalho de Melo 21395c0541d5SArnaldo Carvalho de Melo static struct dso *machine__create_kernel(struct machine *self) 2140cd84c2acSFrederic Weisbecker { 2141a1645ce1SZhang, Yanmin const char *vmlinux_name = NULL; 2142a1645ce1SZhang, Yanmin struct dso *kernel; 2143cd84c2acSFrederic Weisbecker 21445c0541d5SArnaldo Carvalho de Melo if (machine__is_host(self)) { 2145a1645ce1SZhang, Yanmin vmlinux_name = symbol_conf.vmlinux_name; 2146a1645ce1SZhang, Yanmin kernel = dso__new_kernel(vmlinux_name); 2147a1645ce1SZhang, Yanmin } else { 21485c0541d5SArnaldo Carvalho de Melo if (machine__is_default_guest(self)) 2149a1645ce1SZhang, Yanmin vmlinux_name = symbol_conf.default_guest_vmlinux_name; 21505c0541d5SArnaldo Carvalho de Melo kernel = dso__new_guest_kernel(self, vmlinux_name); 21518d92c02aSArnaldo Carvalho de Melo } 2152cd84c2acSFrederic Weisbecker 2153a1645ce1SZhang, Yanmin if (kernel != NULL) { 21545c0541d5SArnaldo Carvalho de Melo dso__read_running_kernel_build_id(kernel, self); 21555c0541d5SArnaldo Carvalho de Melo dsos__add(&self->kernel_dsos, kernel); 2156a1645ce1SZhang, Yanmin } 2157f1dfa0b1SArnaldo Carvalho de Melo return kernel; 2158f1dfa0b1SArnaldo Carvalho de Melo } 2159f1dfa0b1SArnaldo Carvalho de Melo 2160d214afbdSMing Lei struct process_args { 2161d214afbdSMing Lei u64 start; 2162d214afbdSMing Lei }; 2163d214afbdSMing Lei 2164d214afbdSMing Lei static int symbol__in_kernel(void *arg, const char *name, 2165d214afbdSMing Lei char type __used, u64 start) 2166d214afbdSMing Lei { 2167d214afbdSMing Lei struct process_args *args = arg; 2168d214afbdSMing Lei 2169d214afbdSMing Lei if (strchr(name, '[')) 2170d214afbdSMing Lei return 0; 2171d214afbdSMing Lei 2172d214afbdSMing Lei args->start = start; 2173d214afbdSMing Lei return 1; 2174d214afbdSMing Lei } 2175d214afbdSMing Lei 2176d214afbdSMing Lei /* Figure out the start address of kernel map from /proc/kallsyms */ 2177d214afbdSMing Lei static u64 machine__get_kernel_start_addr(struct machine *machine) 2178d214afbdSMing Lei { 2179d214afbdSMing Lei const char *filename; 2180d214afbdSMing Lei char path[PATH_MAX]; 2181d214afbdSMing Lei struct process_args args; 2182d214afbdSMing Lei 2183d214afbdSMing Lei if (machine__is_host(machine)) { 2184d214afbdSMing Lei filename = "/proc/kallsyms"; 2185d214afbdSMing Lei } else { 2186d214afbdSMing Lei if (machine__is_default_guest(machine)) 2187d214afbdSMing Lei filename = (char *)symbol_conf.default_guest_kallsyms; 2188d214afbdSMing Lei else { 2189d214afbdSMing Lei sprintf(path, "%s/proc/kallsyms", machine->root_dir); 2190d214afbdSMing Lei filename = path; 2191d214afbdSMing Lei } 2192d214afbdSMing Lei } 2193d214afbdSMing Lei 2194d214afbdSMing Lei if (kallsyms__parse(filename, &args, symbol__in_kernel) <= 0) 2195d214afbdSMing Lei return 0; 2196d214afbdSMing Lei 2197d214afbdSMing Lei return args.start; 2198d214afbdSMing Lei } 2199d214afbdSMing Lei 2200d28c6223SArnaldo Carvalho de Melo int __machine__create_kernel_maps(struct machine *self, struct dso *kernel) 2201f1dfa0b1SArnaldo Carvalho de Melo { 2202de176489SArnaldo Carvalho de Melo enum map_type type; 2203d214afbdSMing Lei u64 start = machine__get_kernel_start_addr(self); 2204f1dfa0b1SArnaldo Carvalho de Melo 2205de176489SArnaldo Carvalho de Melo for (type = 0; type < MAP__NR_TYPES; ++type) { 22069de89fe7SArnaldo Carvalho de Melo struct kmap *kmap; 22079de89fe7SArnaldo Carvalho de Melo 2208d214afbdSMing Lei self->vmlinux_maps[type] = map__new2(start, kernel, type); 2209d28c6223SArnaldo Carvalho de Melo if (self->vmlinux_maps[type] == NULL) 2210f1dfa0b1SArnaldo Carvalho de Melo return -1; 2211f1dfa0b1SArnaldo Carvalho de Melo 2212d28c6223SArnaldo Carvalho de Melo self->vmlinux_maps[type]->map_ip = 2213d28c6223SArnaldo Carvalho de Melo self->vmlinux_maps[type]->unmap_ip = identity__map_ip; 22149de89fe7SArnaldo Carvalho de Melo 2215d28c6223SArnaldo Carvalho de Melo kmap = map__kmap(self->vmlinux_maps[type]); 2216d28c6223SArnaldo Carvalho de Melo kmap->kmaps = &self->kmaps; 2217d28c6223SArnaldo Carvalho de Melo map_groups__insert(&self->kmaps, self->vmlinux_maps[type]); 2218f1dfa0b1SArnaldo Carvalho de Melo } 2219f1dfa0b1SArnaldo Carvalho de Melo 2220f1dfa0b1SArnaldo Carvalho de Melo return 0; 22212446042cSArnaldo Carvalho de Melo } 22222446042cSArnaldo Carvalho de Melo 2223076c6e45SArnaldo Carvalho de Melo void machine__destroy_kernel_maps(struct machine *self) 2224076c6e45SArnaldo Carvalho de Melo { 2225076c6e45SArnaldo Carvalho de Melo enum map_type type; 2226076c6e45SArnaldo Carvalho de Melo 2227076c6e45SArnaldo Carvalho de Melo for (type = 0; type < MAP__NR_TYPES; ++type) { 2228076c6e45SArnaldo Carvalho de Melo struct kmap *kmap; 2229076c6e45SArnaldo Carvalho de Melo 2230076c6e45SArnaldo Carvalho de Melo if (self->vmlinux_maps[type] == NULL) 2231076c6e45SArnaldo Carvalho de Melo continue; 2232076c6e45SArnaldo Carvalho de Melo 2233076c6e45SArnaldo Carvalho de Melo kmap = map__kmap(self->vmlinux_maps[type]); 2234076c6e45SArnaldo Carvalho de Melo map_groups__remove(&self->kmaps, self->vmlinux_maps[type]); 2235076c6e45SArnaldo Carvalho de Melo if (kmap->ref_reloc_sym) { 2236076c6e45SArnaldo Carvalho de Melo /* 2237076c6e45SArnaldo Carvalho de Melo * ref_reloc_sym is shared among all maps, so free just 2238076c6e45SArnaldo Carvalho de Melo * on one of them. 2239076c6e45SArnaldo Carvalho de Melo */ 2240076c6e45SArnaldo Carvalho de Melo if (type == MAP__FUNCTION) { 2241076c6e45SArnaldo Carvalho de Melo free((char *)kmap->ref_reloc_sym->name); 2242076c6e45SArnaldo Carvalho de Melo kmap->ref_reloc_sym->name = NULL; 2243076c6e45SArnaldo Carvalho de Melo free(kmap->ref_reloc_sym); 2244076c6e45SArnaldo Carvalho de Melo } 2245076c6e45SArnaldo Carvalho de Melo kmap->ref_reloc_sym = NULL; 2246076c6e45SArnaldo Carvalho de Melo } 2247076c6e45SArnaldo Carvalho de Melo 2248076c6e45SArnaldo Carvalho de Melo map__delete(self->vmlinux_maps[type]); 2249076c6e45SArnaldo Carvalho de Melo self->vmlinux_maps[type] = NULL; 2250076c6e45SArnaldo Carvalho de Melo } 2251076c6e45SArnaldo Carvalho de Melo } 2252076c6e45SArnaldo Carvalho de Melo 22535c0541d5SArnaldo Carvalho de Melo int machine__create_kernel_maps(struct machine *self) 22545c0541d5SArnaldo Carvalho de Melo { 22555c0541d5SArnaldo Carvalho de Melo struct dso *kernel = machine__create_kernel(self); 22565c0541d5SArnaldo Carvalho de Melo 22575c0541d5SArnaldo Carvalho de Melo if (kernel == NULL || 22585c0541d5SArnaldo Carvalho de Melo __machine__create_kernel_maps(self, kernel) < 0) 22595c0541d5SArnaldo Carvalho de Melo return -1; 22605c0541d5SArnaldo Carvalho de Melo 22615c0541d5SArnaldo Carvalho de Melo if (symbol_conf.use_modules && machine__create_modules(self) < 0) 22625c0541d5SArnaldo Carvalho de Melo pr_debug("Problems creating module maps, continuing anyway...\n"); 22635c0541d5SArnaldo Carvalho de Melo /* 22645c0541d5SArnaldo Carvalho de Melo * Now that we have all the maps created, just set the ->end of them: 22655c0541d5SArnaldo Carvalho de Melo */ 22665c0541d5SArnaldo Carvalho de Melo map_groups__fixup_end(&self->kmaps); 22675c0541d5SArnaldo Carvalho de Melo return 0; 22685c0541d5SArnaldo Carvalho de Melo } 22695c0541d5SArnaldo Carvalho de Melo 2270cc612d81SArnaldo Carvalho de Melo static void vmlinux_path__exit(void) 22712446042cSArnaldo Carvalho de Melo { 2272cc612d81SArnaldo Carvalho de Melo while (--vmlinux_path__nr_entries >= 0) { 2273cc612d81SArnaldo Carvalho de Melo free(vmlinux_path[vmlinux_path__nr_entries]); 2274cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = NULL; 2275cc612d81SArnaldo Carvalho de Melo } 2276cc612d81SArnaldo Carvalho de Melo 2277cc612d81SArnaldo Carvalho de Melo free(vmlinux_path); 2278cc612d81SArnaldo Carvalho de Melo vmlinux_path = NULL; 2279cc612d81SArnaldo Carvalho de Melo } 2280cc612d81SArnaldo Carvalho de Melo 2281cc612d81SArnaldo Carvalho de Melo static int vmlinux_path__init(void) 2282cc612d81SArnaldo Carvalho de Melo { 2283cc612d81SArnaldo Carvalho de Melo struct utsname uts; 2284cc612d81SArnaldo Carvalho de Melo char bf[PATH_MAX]; 2285cc612d81SArnaldo Carvalho de Melo 2286cc612d81SArnaldo Carvalho de Melo vmlinux_path = malloc(sizeof(char *) * 5); 2287cc612d81SArnaldo Carvalho de Melo if (vmlinux_path == NULL) 2288cc612d81SArnaldo Carvalho de Melo return -1; 2289cc612d81SArnaldo Carvalho de Melo 2290cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup("vmlinux"); 2291cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 2292cc612d81SArnaldo Carvalho de Melo goto out_fail; 2293cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 2294cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup("/boot/vmlinux"); 2295cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 2296cc612d81SArnaldo Carvalho de Melo goto out_fail; 2297cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 2298*ec5761eaSDavid Ahern 2299*ec5761eaSDavid Ahern /* only try running kernel version if no symfs was given */ 2300*ec5761eaSDavid Ahern if (symbol_conf.symfs[0] != 0) 2301*ec5761eaSDavid Ahern return 0; 2302*ec5761eaSDavid Ahern 2303*ec5761eaSDavid Ahern if (uname(&uts) < 0) 2304*ec5761eaSDavid Ahern return -1; 2305*ec5761eaSDavid Ahern 2306cc612d81SArnaldo Carvalho de Melo snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", uts.release); 2307cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); 2308cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 2309cc612d81SArnaldo Carvalho de Melo goto out_fail; 2310cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 2311cc612d81SArnaldo Carvalho de Melo snprintf(bf, sizeof(bf), "/lib/modules/%s/build/vmlinux", uts.release); 2312cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); 2313cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 2314cc612d81SArnaldo Carvalho de Melo goto out_fail; 2315cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 2316cc612d81SArnaldo Carvalho de Melo snprintf(bf, sizeof(bf), "/usr/lib/debug/lib/modules/%s/vmlinux", 2317cc612d81SArnaldo Carvalho de Melo uts.release); 2318cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); 2319cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 2320cc612d81SArnaldo Carvalho de Melo goto out_fail; 2321cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 2322cc612d81SArnaldo Carvalho de Melo 2323cc612d81SArnaldo Carvalho de Melo return 0; 2324cc612d81SArnaldo Carvalho de Melo 2325cc612d81SArnaldo Carvalho de Melo out_fail: 2326cc612d81SArnaldo Carvalho de Melo vmlinux_path__exit(); 2327cc612d81SArnaldo Carvalho de Melo return -1; 2328cc612d81SArnaldo Carvalho de Melo } 2329cc612d81SArnaldo Carvalho de Melo 23305ad90e4eSArnaldo Carvalho de Melo size_t machine__fprintf_vmlinux_path(struct machine *self, FILE *fp) 2331b0a9ab62SArnaldo Carvalho de Melo { 2332b0a9ab62SArnaldo Carvalho de Melo int i; 2333b0a9ab62SArnaldo Carvalho de Melo size_t printed = 0; 23345ad90e4eSArnaldo Carvalho de Melo struct dso *kdso = self->vmlinux_maps[MAP__FUNCTION]->dso; 23355ad90e4eSArnaldo Carvalho de Melo 23365ad90e4eSArnaldo Carvalho de Melo if (kdso->has_build_id) { 23375ad90e4eSArnaldo Carvalho de Melo char filename[PATH_MAX]; 23385ad90e4eSArnaldo Carvalho de Melo if (dso__build_id_filename(kdso, filename, sizeof(filename))) 23395ad90e4eSArnaldo Carvalho de Melo printed += fprintf(fp, "[0] %s\n", filename); 23405ad90e4eSArnaldo Carvalho de Melo } 2341b0a9ab62SArnaldo Carvalho de Melo 2342b0a9ab62SArnaldo Carvalho de Melo for (i = 0; i < vmlinux_path__nr_entries; ++i) 23435ad90e4eSArnaldo Carvalho de Melo printed += fprintf(fp, "[%d] %s\n", 23445ad90e4eSArnaldo Carvalho de Melo i + kdso->has_build_id, vmlinux_path[i]); 2345b0a9ab62SArnaldo Carvalho de Melo 2346b0a9ab62SArnaldo Carvalho de Melo return printed; 2347b0a9ab62SArnaldo Carvalho de Melo } 2348b0a9ab62SArnaldo Carvalho de Melo 2349655000e7SArnaldo Carvalho de Melo static int setup_list(struct strlist **list, const char *list_str, 2350655000e7SArnaldo Carvalho de Melo const char *list_name) 2351655000e7SArnaldo Carvalho de Melo { 2352655000e7SArnaldo Carvalho de Melo if (list_str == NULL) 2353655000e7SArnaldo Carvalho de Melo return 0; 2354655000e7SArnaldo Carvalho de Melo 2355655000e7SArnaldo Carvalho de Melo *list = strlist__new(true, list_str); 2356655000e7SArnaldo Carvalho de Melo if (!*list) { 2357655000e7SArnaldo Carvalho de Melo pr_err("problems parsing %s list\n", list_name); 2358655000e7SArnaldo Carvalho de Melo return -1; 2359655000e7SArnaldo Carvalho de Melo } 2360655000e7SArnaldo Carvalho de Melo return 0; 2361655000e7SArnaldo Carvalho de Melo } 2362655000e7SArnaldo Carvalho de Melo 236375be6cf4SArnaldo Carvalho de Melo int symbol__init(void) 2364cc612d81SArnaldo Carvalho de Melo { 2365*ec5761eaSDavid Ahern const char *symfs; 2366*ec5761eaSDavid Ahern 236785e00b55SJovi Zhang if (symbol_conf.initialized) 236885e00b55SJovi Zhang return 0; 236985e00b55SJovi Zhang 237095011c60SArnaldo Carvalho de Melo elf_version(EV_CURRENT); 237175be6cf4SArnaldo Carvalho de Melo if (symbol_conf.sort_by_name) 237275be6cf4SArnaldo Carvalho de Melo symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) - 237379406cd7SArnaldo Carvalho de Melo sizeof(struct symbol)); 2374b32d133aSArnaldo Carvalho de Melo 237575be6cf4SArnaldo Carvalho de Melo if (symbol_conf.try_vmlinux_path && vmlinux_path__init() < 0) 2376cc612d81SArnaldo Carvalho de Melo return -1; 2377cc612d81SArnaldo Carvalho de Melo 2378c410a338SArnaldo Carvalho de Melo if (symbol_conf.field_sep && *symbol_conf.field_sep == '.') { 2379c410a338SArnaldo Carvalho de Melo pr_err("'.' is the only non valid --field-separator argument\n"); 2380c410a338SArnaldo Carvalho de Melo return -1; 2381c410a338SArnaldo Carvalho de Melo } 2382c410a338SArnaldo Carvalho de Melo 2383655000e7SArnaldo Carvalho de Melo if (setup_list(&symbol_conf.dso_list, 2384655000e7SArnaldo Carvalho de Melo symbol_conf.dso_list_str, "dso") < 0) 2385655000e7SArnaldo Carvalho de Melo return -1; 2386655000e7SArnaldo Carvalho de Melo 2387655000e7SArnaldo Carvalho de Melo if (setup_list(&symbol_conf.comm_list, 2388655000e7SArnaldo Carvalho de Melo symbol_conf.comm_list_str, "comm") < 0) 2389655000e7SArnaldo Carvalho de Melo goto out_free_dso_list; 2390655000e7SArnaldo Carvalho de Melo 2391655000e7SArnaldo Carvalho de Melo if (setup_list(&symbol_conf.sym_list, 2392655000e7SArnaldo Carvalho de Melo symbol_conf.sym_list_str, "symbol") < 0) 2393655000e7SArnaldo Carvalho de Melo goto out_free_comm_list; 2394655000e7SArnaldo Carvalho de Melo 2395*ec5761eaSDavid Ahern /* 2396*ec5761eaSDavid Ahern * A path to symbols of "/" is identical to "" 2397*ec5761eaSDavid Ahern * reset here for simplicity. 2398*ec5761eaSDavid Ahern */ 2399*ec5761eaSDavid Ahern symfs = realpath(symbol_conf.symfs, NULL); 2400*ec5761eaSDavid Ahern if (symfs == NULL) 2401*ec5761eaSDavid Ahern symfs = symbol_conf.symfs; 2402*ec5761eaSDavid Ahern if (strcmp(symfs, "/") == 0) 2403*ec5761eaSDavid Ahern symbol_conf.symfs = ""; 2404*ec5761eaSDavid Ahern if (symfs != symbol_conf.symfs) 2405*ec5761eaSDavid Ahern free((void *)symfs); 2406*ec5761eaSDavid Ahern 240785e00b55SJovi Zhang symbol_conf.initialized = true; 24084aa65636SArnaldo Carvalho de Melo return 0; 2409655000e7SArnaldo Carvalho de Melo 2410655000e7SArnaldo Carvalho de Melo out_free_dso_list: 2411655000e7SArnaldo Carvalho de Melo strlist__delete(symbol_conf.dso_list); 2412655000e7SArnaldo Carvalho de Melo out_free_comm_list: 2413655000e7SArnaldo Carvalho de Melo strlist__delete(symbol_conf.comm_list); 2414655000e7SArnaldo Carvalho de Melo return -1; 2415cc612d81SArnaldo Carvalho de Melo } 2416cc612d81SArnaldo Carvalho de Melo 2417d65a458bSArnaldo Carvalho de Melo void symbol__exit(void) 2418d65a458bSArnaldo Carvalho de Melo { 241985e00b55SJovi Zhang if (!symbol_conf.initialized) 242085e00b55SJovi Zhang return; 2421d65a458bSArnaldo Carvalho de Melo strlist__delete(symbol_conf.sym_list); 2422d65a458bSArnaldo Carvalho de Melo strlist__delete(symbol_conf.dso_list); 2423d65a458bSArnaldo Carvalho de Melo strlist__delete(symbol_conf.comm_list); 2424d65a458bSArnaldo Carvalho de Melo vmlinux_path__exit(); 2425d65a458bSArnaldo Carvalho de Melo symbol_conf.sym_list = symbol_conf.dso_list = symbol_conf.comm_list = NULL; 242685e00b55SJovi Zhang symbol_conf.initialized = false; 2427d65a458bSArnaldo Carvalho de Melo } 2428d65a458bSArnaldo Carvalho de Melo 2429d28c6223SArnaldo Carvalho de Melo int machines__create_kernel_maps(struct rb_root *self, pid_t pid) 24304aa65636SArnaldo Carvalho de Melo { 2431d28c6223SArnaldo Carvalho de Melo struct machine *machine = machines__findnew(self, pid); 24329de89fe7SArnaldo Carvalho de Melo 243323346f21SArnaldo Carvalho de Melo if (machine == NULL) 2434a1645ce1SZhang, Yanmin return -1; 24354aa65636SArnaldo Carvalho de Melo 24365c0541d5SArnaldo Carvalho de Melo return machine__create_kernel_maps(machine); 2437cd84c2acSFrederic Weisbecker } 24385aab621bSArnaldo Carvalho de Melo 24395aab621bSArnaldo Carvalho de Melo static int hex(char ch) 24405aab621bSArnaldo Carvalho de Melo { 24415aab621bSArnaldo Carvalho de Melo if ((ch >= '0') && (ch <= '9')) 24425aab621bSArnaldo Carvalho de Melo return ch - '0'; 24435aab621bSArnaldo Carvalho de Melo if ((ch >= 'a') && (ch <= 'f')) 24445aab621bSArnaldo Carvalho de Melo return ch - 'a' + 10; 24455aab621bSArnaldo Carvalho de Melo if ((ch >= 'A') && (ch <= 'F')) 24465aab621bSArnaldo Carvalho de Melo return ch - 'A' + 10; 24475aab621bSArnaldo Carvalho de Melo return -1; 24485aab621bSArnaldo Carvalho de Melo } 24495aab621bSArnaldo Carvalho de Melo 24505aab621bSArnaldo Carvalho de Melo /* 24515aab621bSArnaldo Carvalho de Melo * While we find nice hex chars, build a long_val. 24525aab621bSArnaldo Carvalho de Melo * Return number of chars processed. 24535aab621bSArnaldo Carvalho de Melo */ 24545aab621bSArnaldo Carvalho de Melo int hex2u64(const char *ptr, u64 *long_val) 24555aab621bSArnaldo Carvalho de Melo { 24565aab621bSArnaldo Carvalho de Melo const char *p = ptr; 24575aab621bSArnaldo Carvalho de Melo *long_val = 0; 24585aab621bSArnaldo Carvalho de Melo 24595aab621bSArnaldo Carvalho de Melo while (*p) { 24605aab621bSArnaldo Carvalho de Melo const int hex_val = hex(*p); 24615aab621bSArnaldo Carvalho de Melo 24625aab621bSArnaldo Carvalho de Melo if (hex_val < 0) 24635aab621bSArnaldo Carvalho de Melo break; 24645aab621bSArnaldo Carvalho de Melo 24655aab621bSArnaldo Carvalho de Melo *long_val = (*long_val << 4) | hex_val; 24665aab621bSArnaldo Carvalho de Melo p++; 24675aab621bSArnaldo Carvalho de Melo } 24685aab621bSArnaldo Carvalho de Melo 24695aab621bSArnaldo Carvalho de Melo return p - ptr; 24705aab621bSArnaldo Carvalho de Melo } 24715aab621bSArnaldo Carvalho de Melo 24725aab621bSArnaldo Carvalho de Melo char *strxfrchar(char *s, char from, char to) 24735aab621bSArnaldo Carvalho de Melo { 24745aab621bSArnaldo Carvalho de Melo char *p = s; 24755aab621bSArnaldo Carvalho de Melo 24765aab621bSArnaldo Carvalho de Melo while ((p = strchr(p, from)) != NULL) 24775aab621bSArnaldo Carvalho de Melo *p++ = to; 24785aab621bSArnaldo Carvalho de Melo 24795aab621bSArnaldo Carvalho de Melo return s; 24805aab621bSArnaldo Carvalho de Melo } 2481a1645ce1SZhang, Yanmin 2482d28c6223SArnaldo Carvalho de Melo int machines__create_guest_kernel_maps(struct rb_root *self) 2483a1645ce1SZhang, Yanmin { 2484a1645ce1SZhang, Yanmin int ret = 0; 2485a1645ce1SZhang, Yanmin struct dirent **namelist = NULL; 2486a1645ce1SZhang, Yanmin int i, items = 0; 2487a1645ce1SZhang, Yanmin char path[PATH_MAX]; 2488a1645ce1SZhang, Yanmin pid_t pid; 2489a1645ce1SZhang, Yanmin 2490a1645ce1SZhang, Yanmin if (symbol_conf.default_guest_vmlinux_name || 2491a1645ce1SZhang, Yanmin symbol_conf.default_guest_modules || 2492a1645ce1SZhang, Yanmin symbol_conf.default_guest_kallsyms) { 2493d28c6223SArnaldo Carvalho de Melo machines__create_kernel_maps(self, DEFAULT_GUEST_KERNEL_ID); 2494a1645ce1SZhang, Yanmin } 2495a1645ce1SZhang, Yanmin 2496a1645ce1SZhang, Yanmin if (symbol_conf.guestmount) { 2497a1645ce1SZhang, Yanmin items = scandir(symbol_conf.guestmount, &namelist, NULL, NULL); 2498a1645ce1SZhang, Yanmin if (items <= 0) 2499a1645ce1SZhang, Yanmin return -ENOENT; 2500a1645ce1SZhang, Yanmin for (i = 0; i < items; i++) { 2501a1645ce1SZhang, Yanmin if (!isdigit(namelist[i]->d_name[0])) { 2502a1645ce1SZhang, Yanmin /* Filter out . and .. */ 2503a1645ce1SZhang, Yanmin continue; 2504a1645ce1SZhang, Yanmin } 2505a1645ce1SZhang, Yanmin pid = atoi(namelist[i]->d_name); 2506a1645ce1SZhang, Yanmin sprintf(path, "%s/%s/proc/kallsyms", 2507a1645ce1SZhang, Yanmin symbol_conf.guestmount, 2508a1645ce1SZhang, Yanmin namelist[i]->d_name); 2509a1645ce1SZhang, Yanmin ret = access(path, R_OK); 2510a1645ce1SZhang, Yanmin if (ret) { 2511a1645ce1SZhang, Yanmin pr_debug("Can't access file %s\n", path); 2512a1645ce1SZhang, Yanmin goto failure; 2513a1645ce1SZhang, Yanmin } 2514d28c6223SArnaldo Carvalho de Melo machines__create_kernel_maps(self, pid); 2515a1645ce1SZhang, Yanmin } 2516a1645ce1SZhang, Yanmin failure: 2517a1645ce1SZhang, Yanmin free(namelist); 2518a1645ce1SZhang, Yanmin } 2519a1645ce1SZhang, Yanmin 2520a1645ce1SZhang, Yanmin return ret; 2521a1645ce1SZhang, Yanmin } 25225c0541d5SArnaldo Carvalho de Melo 2523076c6e45SArnaldo Carvalho de Melo void machines__destroy_guest_kernel_maps(struct rb_root *self) 2524076c6e45SArnaldo Carvalho de Melo { 2525076c6e45SArnaldo Carvalho de Melo struct rb_node *next = rb_first(self); 2526076c6e45SArnaldo Carvalho de Melo 2527076c6e45SArnaldo Carvalho de Melo while (next) { 2528076c6e45SArnaldo Carvalho de Melo struct machine *pos = rb_entry(next, struct machine, rb_node); 2529076c6e45SArnaldo Carvalho de Melo 2530076c6e45SArnaldo Carvalho de Melo next = rb_next(&pos->rb_node); 2531076c6e45SArnaldo Carvalho de Melo rb_erase(&pos->rb_node, self); 2532076c6e45SArnaldo Carvalho de Melo machine__delete(pos); 2533076c6e45SArnaldo Carvalho de Melo } 2534076c6e45SArnaldo Carvalho de Melo } 2535076c6e45SArnaldo Carvalho de Melo 25365c0541d5SArnaldo Carvalho de Melo int machine__load_kallsyms(struct machine *self, const char *filename, 25375c0541d5SArnaldo Carvalho de Melo enum map_type type, symbol_filter_t filter) 25385c0541d5SArnaldo Carvalho de Melo { 25395c0541d5SArnaldo Carvalho de Melo struct map *map = self->vmlinux_maps[type]; 25405c0541d5SArnaldo Carvalho de Melo int ret = dso__load_kallsyms(map->dso, filename, map, filter); 25415c0541d5SArnaldo Carvalho de Melo 25425c0541d5SArnaldo Carvalho de Melo if (ret > 0) { 25435c0541d5SArnaldo Carvalho de Melo dso__set_loaded(map->dso, type); 25445c0541d5SArnaldo Carvalho de Melo /* 25455c0541d5SArnaldo Carvalho de Melo * Since /proc/kallsyms will have multiple sessions for the 25465c0541d5SArnaldo Carvalho de Melo * kernel, with modules between them, fixup the end of all 25475c0541d5SArnaldo Carvalho de Melo * sections. 25485c0541d5SArnaldo Carvalho de Melo */ 25495c0541d5SArnaldo Carvalho de Melo __map_groups__fixup_end(&self->kmaps, type); 25505c0541d5SArnaldo Carvalho de Melo } 25515c0541d5SArnaldo Carvalho de Melo 25525c0541d5SArnaldo Carvalho de Melo return ret; 25535c0541d5SArnaldo Carvalho de Melo } 25545c0541d5SArnaldo Carvalho de Melo 25555c0541d5SArnaldo Carvalho de Melo int machine__load_vmlinux_path(struct machine *self, enum map_type type, 25565c0541d5SArnaldo Carvalho de Melo symbol_filter_t filter) 25575c0541d5SArnaldo Carvalho de Melo { 25585c0541d5SArnaldo Carvalho de Melo struct map *map = self->vmlinux_maps[type]; 25595c0541d5SArnaldo Carvalho de Melo int ret = dso__load_vmlinux_path(map->dso, map, filter); 25605c0541d5SArnaldo Carvalho de Melo 25615c0541d5SArnaldo Carvalho de Melo if (ret > 0) { 25625c0541d5SArnaldo Carvalho de Melo dso__set_loaded(map->dso, type); 25635c0541d5SArnaldo Carvalho de Melo map__reloc_vmlinux(map); 25645c0541d5SArnaldo Carvalho de Melo } 25655c0541d5SArnaldo Carvalho de Melo 25665c0541d5SArnaldo Carvalho de Melo return ret; 25675c0541d5SArnaldo Carvalho de Melo } 2568