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, 44b32d133aSArnaldo Carvalho de Melo }; 45b32d133aSArnaldo Carvalho de Melo 468a6c5b26SArnaldo Carvalho de Melo int dso__name_len(const struct dso *self) 478a6c5b26SArnaldo Carvalho de Melo { 488a6c5b26SArnaldo Carvalho de Melo if (verbose) 498a6c5b26SArnaldo Carvalho de Melo return self->long_name_len; 508a6c5b26SArnaldo Carvalho de Melo 518a6c5b26SArnaldo Carvalho de Melo return self->short_name_len; 528a6c5b26SArnaldo Carvalho de Melo } 538a6c5b26SArnaldo Carvalho de Melo 543610583cSArnaldo Carvalho de Melo bool dso__loaded(const struct dso *self, enum map_type type) 553610583cSArnaldo Carvalho de Melo { 563610583cSArnaldo Carvalho de Melo return self->loaded & (1 << type); 573610583cSArnaldo Carvalho de Melo } 583610583cSArnaldo Carvalho de Melo 5979406cd7SArnaldo Carvalho de Melo bool dso__sorted_by_name(const struct dso *self, enum map_type type) 6079406cd7SArnaldo Carvalho de Melo { 6179406cd7SArnaldo Carvalho de Melo return self->sorted_by_name & (1 << type); 6279406cd7SArnaldo Carvalho de Melo } 6379406cd7SArnaldo Carvalho de Melo 6479406cd7SArnaldo Carvalho de Melo static void dso__set_sorted_by_name(struct dso *self, enum map_type type) 6579406cd7SArnaldo Carvalho de Melo { 6679406cd7SArnaldo Carvalho de Melo self->sorted_by_name |= (1 << type); 6779406cd7SArnaldo Carvalho de Melo } 6879406cd7SArnaldo Carvalho de Melo 6936a3e646SArnaldo Carvalho de Melo bool symbol_type__is_a(char symbol_type, enum map_type map_type) 706893d4eeSArnaldo Carvalho de Melo { 716893d4eeSArnaldo Carvalho de Melo switch (map_type) { 726893d4eeSArnaldo Carvalho de Melo case MAP__FUNCTION: 736893d4eeSArnaldo Carvalho de Melo return symbol_type == 'T' || symbol_type == 'W'; 74f1dfa0b1SArnaldo Carvalho de Melo case MAP__VARIABLE: 75f1dfa0b1SArnaldo Carvalho de Melo return symbol_type == 'D' || symbol_type == 'd'; 766893d4eeSArnaldo Carvalho de Melo default: 776893d4eeSArnaldo Carvalho de Melo return false; 786893d4eeSArnaldo Carvalho de Melo } 796893d4eeSArnaldo Carvalho de Melo } 806893d4eeSArnaldo Carvalho de Melo 81fcf1203aSArnaldo Carvalho de Melo static void symbols__fixup_end(struct rb_root *self) 82af427bf5SArnaldo Carvalho de Melo { 83fcf1203aSArnaldo Carvalho de Melo struct rb_node *nd, *prevnd = rb_first(self); 842e538c4aSArnaldo Carvalho de Melo struct symbol *curr, *prev; 85af427bf5SArnaldo Carvalho de Melo 86af427bf5SArnaldo Carvalho de Melo if (prevnd == NULL) 87af427bf5SArnaldo Carvalho de Melo return; 88af427bf5SArnaldo Carvalho de Melo 892e538c4aSArnaldo Carvalho de Melo curr = rb_entry(prevnd, struct symbol, rb_node); 902e538c4aSArnaldo Carvalho de Melo 91af427bf5SArnaldo Carvalho de Melo for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) { 922e538c4aSArnaldo Carvalho de Melo prev = curr; 932e538c4aSArnaldo Carvalho de Melo curr = rb_entry(nd, struct symbol, rb_node); 94af427bf5SArnaldo Carvalho de Melo 95af427bf5SArnaldo Carvalho de Melo if (prev->end == prev->start) 96af427bf5SArnaldo Carvalho de Melo prev->end = curr->start - 1; 97af427bf5SArnaldo Carvalho de Melo } 98af427bf5SArnaldo Carvalho de Melo 992e538c4aSArnaldo Carvalho de Melo /* Last entry */ 1002e538c4aSArnaldo Carvalho de Melo if (curr->end == curr->start) 1012e538c4aSArnaldo Carvalho de Melo curr->end = roundup(curr->start, 4096); 1022e538c4aSArnaldo Carvalho de Melo } 1032e538c4aSArnaldo Carvalho de Melo 1049958e1f0SArnaldo Carvalho de Melo static void __map_groups__fixup_end(struct map_groups *self, enum map_type type) 105af427bf5SArnaldo Carvalho de Melo { 106af427bf5SArnaldo Carvalho de Melo struct map *prev, *curr; 10795011c60SArnaldo Carvalho de Melo struct rb_node *nd, *prevnd = rb_first(&self->maps[type]); 108af427bf5SArnaldo Carvalho de Melo 109af427bf5SArnaldo Carvalho de Melo if (prevnd == NULL) 110af427bf5SArnaldo Carvalho de Melo return; 111af427bf5SArnaldo Carvalho de Melo 112af427bf5SArnaldo Carvalho de Melo curr = rb_entry(prevnd, struct map, rb_node); 113af427bf5SArnaldo Carvalho de Melo 114af427bf5SArnaldo Carvalho de Melo for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) { 115af427bf5SArnaldo Carvalho de Melo prev = curr; 116af427bf5SArnaldo Carvalho de Melo curr = rb_entry(nd, struct map, rb_node); 117af427bf5SArnaldo Carvalho de Melo prev->end = curr->start - 1; 1182e538c4aSArnaldo Carvalho de Melo } 11990c83218SArnaldo Carvalho de Melo 12090c83218SArnaldo Carvalho de Melo /* 12190c83218SArnaldo Carvalho de Melo * We still haven't the actual symbols, so guess the 12290c83218SArnaldo Carvalho de Melo * last map final address. 12390c83218SArnaldo Carvalho de Melo */ 12490c83218SArnaldo Carvalho de Melo curr->end = ~0UL; 125af427bf5SArnaldo Carvalho de Melo } 126af427bf5SArnaldo Carvalho de Melo 1279958e1f0SArnaldo Carvalho de Melo static void map_groups__fixup_end(struct map_groups *self) 12823ea4a3fSArnaldo Carvalho de Melo { 12923ea4a3fSArnaldo Carvalho de Melo int i; 13023ea4a3fSArnaldo Carvalho de Melo for (i = 0; i < MAP__NR_TYPES; ++i) 1319958e1f0SArnaldo Carvalho de Melo __map_groups__fixup_end(self, i); 13223ea4a3fSArnaldo Carvalho de Melo } 13323ea4a3fSArnaldo Carvalho de Melo 134*c408fedfSArnaldo Carvalho de Melo static struct symbol *symbol__new(u64 start, u64 len, u8 binding, 135*c408fedfSArnaldo Carvalho de Melo const char *name) 13686470930SIngo Molnar { 13786470930SIngo Molnar size_t namelen = strlen(name) + 1; 1385aab621bSArnaldo Carvalho de Melo struct symbol *self = calloc(1, (symbol_conf.priv_size + 1395aab621bSArnaldo Carvalho de Melo sizeof(*self) + namelen)); 14036479484SArnaldo Carvalho de Melo if (self == NULL) 14186470930SIngo Molnar return NULL; 14286470930SIngo Molnar 14375be6cf4SArnaldo Carvalho de Melo if (symbol_conf.priv_size) 14475be6cf4SArnaldo Carvalho de Melo self = ((void *)self) + symbol_conf.priv_size; 14536479484SArnaldo Carvalho de Melo 14686470930SIngo Molnar self->start = start; 1476cfcc53eSMike Galbraith self->end = len ? start + len - 1 : start; 148*c408fedfSArnaldo Carvalho de Melo self->binding = binding; 149fefb0b94SArnaldo Carvalho de Melo self->namelen = namelen - 1; 150e4204992SArnaldo Carvalho de Melo 15129a9f66dSArnaldo Carvalho de Melo pr_debug4("%s: %s %#Lx-%#Lx\n", __func__, name, start, self->end); 152e4204992SArnaldo Carvalho de Melo 15386470930SIngo Molnar memcpy(self->name, name, namelen); 15486470930SIngo Molnar 15586470930SIngo Molnar return self; 15686470930SIngo Molnar } 15786470930SIngo Molnar 158628ada0cSArnaldo Carvalho de Melo void symbol__delete(struct symbol *self) 15986470930SIngo Molnar { 16075be6cf4SArnaldo Carvalho de Melo free(((void *)self) - symbol_conf.priv_size); 16186470930SIngo Molnar } 16286470930SIngo Molnar 16386470930SIngo Molnar static size_t symbol__fprintf(struct symbol *self, FILE *fp) 16486470930SIngo Molnar { 165*c408fedfSArnaldo Carvalho de Melo return fprintf(fp, " %llx-%llx %c %s\n", 166*c408fedfSArnaldo Carvalho de Melo self->start, self->end, 167*c408fedfSArnaldo Carvalho de Melo self->binding == STB_GLOBAL ? 'g' : 168*c408fedfSArnaldo Carvalho de Melo self->binding == STB_LOCAL ? 'l' : 'w', 169*c408fedfSArnaldo Carvalho de Melo self->name); 17086470930SIngo Molnar } 17186470930SIngo Molnar 172b7cece76SArnaldo Carvalho de Melo void dso__set_long_name(struct dso *self, char *name) 173cfc10d3bSArnaldo Carvalho de Melo { 174ef6ae724SArnaldo Carvalho de Melo if (name == NULL) 175ef6ae724SArnaldo Carvalho de Melo return; 176cfc10d3bSArnaldo Carvalho de Melo self->long_name = name; 177cfc10d3bSArnaldo Carvalho de Melo self->long_name_len = strlen(name); 178cfc10d3bSArnaldo Carvalho de Melo } 179cfc10d3bSArnaldo Carvalho de Melo 180b63be8d7SArnaldo Carvalho de Melo static void dso__set_short_name(struct dso *self, const char *name) 181b63be8d7SArnaldo Carvalho de Melo { 182b63be8d7SArnaldo Carvalho de Melo if (name == NULL) 183b63be8d7SArnaldo Carvalho de Melo return; 184b63be8d7SArnaldo Carvalho de Melo self->short_name = name; 185b63be8d7SArnaldo Carvalho de Melo self->short_name_len = strlen(name); 186b63be8d7SArnaldo Carvalho de Melo } 187b63be8d7SArnaldo Carvalho de Melo 188cfc10d3bSArnaldo Carvalho de Melo static void dso__set_basename(struct dso *self) 189cfc10d3bSArnaldo Carvalho de Melo { 190b63be8d7SArnaldo Carvalho de Melo dso__set_short_name(self, basename(self->long_name)); 191cfc10d3bSArnaldo Carvalho de Melo } 192cfc10d3bSArnaldo Carvalho de Melo 19300a192b3SArnaldo Carvalho de Melo struct dso *dso__new(const char *name) 19486470930SIngo Molnar { 1955aab621bSArnaldo Carvalho de Melo struct dso *self = calloc(1, sizeof(*self) + strlen(name) + 1); 19686470930SIngo Molnar 19786470930SIngo Molnar if (self != NULL) { 1986a4694a4SArnaldo Carvalho de Melo int i; 19986470930SIngo Molnar strcpy(self->name, name); 200cfc10d3bSArnaldo Carvalho de Melo dso__set_long_name(self, self->name); 201b63be8d7SArnaldo Carvalho de Melo dso__set_short_name(self, self->name); 2026a4694a4SArnaldo Carvalho de Melo for (i = 0; i < MAP__NR_TYPES; ++i) 20379406cd7SArnaldo Carvalho de Melo self->symbols[i] = self->symbol_names[i] = RB_ROOT; 20452d422deSArnaldo Carvalho de Melo self->slen_calculated = 0; 20594cb9e38SArnaldo Carvalho de Melo self->origin = DSO__ORIG_NOT_FOUND; 2068d06367fSArnaldo Carvalho de Melo self->loaded = 0; 20779406cd7SArnaldo Carvalho de Melo self->sorted_by_name = 0; 2088d06367fSArnaldo Carvalho de Melo self->has_build_id = 0; 209a1645ce1SZhang, Yanmin self->kernel = DSO_TYPE_USER; 2100ab061cdSMasami Hiramatsu INIT_LIST_HEAD(&self->node); 21186470930SIngo Molnar } 21286470930SIngo Molnar 21386470930SIngo Molnar return self; 21486470930SIngo Molnar } 21586470930SIngo Molnar 216fcf1203aSArnaldo Carvalho de Melo static void symbols__delete(struct rb_root *self) 21786470930SIngo Molnar { 21886470930SIngo Molnar struct symbol *pos; 219fcf1203aSArnaldo Carvalho de Melo struct rb_node *next = rb_first(self); 22086470930SIngo Molnar 22186470930SIngo Molnar while (next) { 22286470930SIngo Molnar pos = rb_entry(next, struct symbol, rb_node); 22386470930SIngo Molnar next = rb_next(&pos->rb_node); 224fcf1203aSArnaldo Carvalho de Melo rb_erase(&pos->rb_node, self); 22500a192b3SArnaldo Carvalho de Melo symbol__delete(pos); 22686470930SIngo Molnar } 22786470930SIngo Molnar } 22886470930SIngo Molnar 22986470930SIngo Molnar void dso__delete(struct dso *self) 23086470930SIngo Molnar { 2316a4694a4SArnaldo Carvalho de Melo int i; 2326a4694a4SArnaldo Carvalho de Melo for (i = 0; i < MAP__NR_TYPES; ++i) 2336a4694a4SArnaldo Carvalho de Melo symbols__delete(&self->symbols[i]); 2346e406257SArnaldo Carvalho de Melo if (self->sname_alloc) 2356e406257SArnaldo Carvalho de Melo free((char *)self->short_name); 2366e406257SArnaldo Carvalho de Melo if (self->lname_alloc) 237439d473bSArnaldo Carvalho de Melo free(self->long_name); 23886470930SIngo Molnar free(self); 23986470930SIngo Molnar } 24086470930SIngo Molnar 2418d06367fSArnaldo Carvalho de Melo void dso__set_build_id(struct dso *self, void *build_id) 2428d06367fSArnaldo Carvalho de Melo { 2438d06367fSArnaldo Carvalho de Melo memcpy(self->build_id, build_id, sizeof(self->build_id)); 2448d06367fSArnaldo Carvalho de Melo self->has_build_id = 1; 2458d06367fSArnaldo Carvalho de Melo } 2468d06367fSArnaldo Carvalho de Melo 247fcf1203aSArnaldo Carvalho de Melo static void symbols__insert(struct rb_root *self, struct symbol *sym) 24886470930SIngo Molnar { 249fcf1203aSArnaldo Carvalho de Melo struct rb_node **p = &self->rb_node; 25086470930SIngo Molnar struct rb_node *parent = NULL; 2519cffa8d5SPaul Mackerras const u64 ip = sym->start; 25286470930SIngo Molnar struct symbol *s; 25386470930SIngo Molnar 25486470930SIngo Molnar while (*p != NULL) { 25586470930SIngo Molnar parent = *p; 25686470930SIngo Molnar s = rb_entry(parent, struct symbol, rb_node); 25786470930SIngo Molnar if (ip < s->start) 25886470930SIngo Molnar p = &(*p)->rb_left; 25986470930SIngo Molnar else 26086470930SIngo Molnar p = &(*p)->rb_right; 26186470930SIngo Molnar } 26286470930SIngo Molnar rb_link_node(&sym->rb_node, parent, p); 263fcf1203aSArnaldo Carvalho de Melo rb_insert_color(&sym->rb_node, self); 26486470930SIngo Molnar } 26586470930SIngo Molnar 266fcf1203aSArnaldo Carvalho de Melo static struct symbol *symbols__find(struct rb_root *self, u64 ip) 26786470930SIngo Molnar { 26886470930SIngo Molnar struct rb_node *n; 26986470930SIngo Molnar 27086470930SIngo Molnar if (self == NULL) 27186470930SIngo Molnar return NULL; 27286470930SIngo Molnar 273fcf1203aSArnaldo Carvalho de Melo n = self->rb_node; 27486470930SIngo Molnar 27586470930SIngo Molnar while (n) { 27686470930SIngo Molnar struct symbol *s = rb_entry(n, struct symbol, rb_node); 27786470930SIngo Molnar 27886470930SIngo Molnar if (ip < s->start) 27986470930SIngo Molnar n = n->rb_left; 28086470930SIngo Molnar else if (ip > s->end) 28186470930SIngo Molnar n = n->rb_right; 28286470930SIngo Molnar else 28386470930SIngo Molnar return s; 28486470930SIngo Molnar } 28586470930SIngo Molnar 28686470930SIngo Molnar return NULL; 28786470930SIngo Molnar } 28886470930SIngo Molnar 28979406cd7SArnaldo Carvalho de Melo struct symbol_name_rb_node { 29079406cd7SArnaldo Carvalho de Melo struct rb_node rb_node; 29179406cd7SArnaldo Carvalho de Melo struct symbol sym; 29279406cd7SArnaldo Carvalho de Melo }; 29379406cd7SArnaldo Carvalho de Melo 29479406cd7SArnaldo Carvalho de Melo static void symbols__insert_by_name(struct rb_root *self, struct symbol *sym) 29579406cd7SArnaldo Carvalho de Melo { 29679406cd7SArnaldo Carvalho de Melo struct rb_node **p = &self->rb_node; 29779406cd7SArnaldo Carvalho de Melo struct rb_node *parent = NULL; 29879406cd7SArnaldo Carvalho de Melo struct symbol_name_rb_node *symn = ((void *)sym) - sizeof(*parent), *s; 29979406cd7SArnaldo Carvalho de Melo 30079406cd7SArnaldo Carvalho de Melo while (*p != NULL) { 30179406cd7SArnaldo Carvalho de Melo parent = *p; 30279406cd7SArnaldo Carvalho de Melo s = rb_entry(parent, struct symbol_name_rb_node, rb_node); 30379406cd7SArnaldo Carvalho de Melo if (strcmp(sym->name, s->sym.name) < 0) 30479406cd7SArnaldo Carvalho de Melo p = &(*p)->rb_left; 30579406cd7SArnaldo Carvalho de Melo else 30679406cd7SArnaldo Carvalho de Melo p = &(*p)->rb_right; 30779406cd7SArnaldo Carvalho de Melo } 30879406cd7SArnaldo Carvalho de Melo rb_link_node(&symn->rb_node, parent, p); 30979406cd7SArnaldo Carvalho de Melo rb_insert_color(&symn->rb_node, self); 31079406cd7SArnaldo Carvalho de Melo } 31179406cd7SArnaldo Carvalho de Melo 31279406cd7SArnaldo Carvalho de Melo static void symbols__sort_by_name(struct rb_root *self, struct rb_root *source) 31379406cd7SArnaldo Carvalho de Melo { 31479406cd7SArnaldo Carvalho de Melo struct rb_node *nd; 31579406cd7SArnaldo Carvalho de Melo 31679406cd7SArnaldo Carvalho de Melo for (nd = rb_first(source); nd; nd = rb_next(nd)) { 31779406cd7SArnaldo Carvalho de Melo struct symbol *pos = rb_entry(nd, struct symbol, rb_node); 31879406cd7SArnaldo Carvalho de Melo symbols__insert_by_name(self, pos); 31979406cd7SArnaldo Carvalho de Melo } 32079406cd7SArnaldo Carvalho de Melo } 32179406cd7SArnaldo Carvalho de Melo 32279406cd7SArnaldo Carvalho de Melo static struct symbol *symbols__find_by_name(struct rb_root *self, const char *name) 32379406cd7SArnaldo Carvalho de Melo { 32479406cd7SArnaldo Carvalho de Melo struct rb_node *n; 32579406cd7SArnaldo Carvalho de Melo 32679406cd7SArnaldo Carvalho de Melo if (self == NULL) 32779406cd7SArnaldo Carvalho de Melo return NULL; 32879406cd7SArnaldo Carvalho de Melo 32979406cd7SArnaldo Carvalho de Melo n = self->rb_node; 33079406cd7SArnaldo Carvalho de Melo 33179406cd7SArnaldo Carvalho de Melo while (n) { 33279406cd7SArnaldo Carvalho de Melo struct symbol_name_rb_node *s; 33379406cd7SArnaldo Carvalho de Melo int cmp; 33479406cd7SArnaldo Carvalho de Melo 33579406cd7SArnaldo Carvalho de Melo s = rb_entry(n, struct symbol_name_rb_node, rb_node); 33679406cd7SArnaldo Carvalho de Melo cmp = strcmp(name, s->sym.name); 33779406cd7SArnaldo Carvalho de Melo 33879406cd7SArnaldo Carvalho de Melo if (cmp < 0) 33979406cd7SArnaldo Carvalho de Melo n = n->rb_left; 34079406cd7SArnaldo Carvalho de Melo else if (cmp > 0) 34179406cd7SArnaldo Carvalho de Melo n = n->rb_right; 34279406cd7SArnaldo Carvalho de Melo else 34379406cd7SArnaldo Carvalho de Melo return &s->sym; 34479406cd7SArnaldo Carvalho de Melo } 34579406cd7SArnaldo Carvalho de Melo 34679406cd7SArnaldo Carvalho de Melo return NULL; 34779406cd7SArnaldo Carvalho de Melo } 34879406cd7SArnaldo Carvalho de Melo 34979406cd7SArnaldo Carvalho de Melo struct symbol *dso__find_symbol(struct dso *self, 35079406cd7SArnaldo Carvalho de Melo enum map_type type, u64 addr) 351fcf1203aSArnaldo Carvalho de Melo { 3526a4694a4SArnaldo Carvalho de Melo return symbols__find(&self->symbols[type], addr); 353fcf1203aSArnaldo Carvalho de Melo } 354fcf1203aSArnaldo Carvalho de Melo 35579406cd7SArnaldo Carvalho de Melo struct symbol *dso__find_symbol_by_name(struct dso *self, enum map_type type, 35679406cd7SArnaldo Carvalho de Melo const char *name) 35779406cd7SArnaldo Carvalho de Melo { 35879406cd7SArnaldo Carvalho de Melo return symbols__find_by_name(&self->symbol_names[type], name); 35979406cd7SArnaldo Carvalho de Melo } 36079406cd7SArnaldo Carvalho de Melo 36179406cd7SArnaldo Carvalho de Melo void dso__sort_by_name(struct dso *self, enum map_type type) 36279406cd7SArnaldo Carvalho de Melo { 36379406cd7SArnaldo Carvalho de Melo dso__set_sorted_by_name(self, type); 36479406cd7SArnaldo Carvalho de Melo return symbols__sort_by_name(&self->symbol_names[type], 36579406cd7SArnaldo Carvalho de Melo &self->symbols[type]); 36679406cd7SArnaldo Carvalho de Melo } 36779406cd7SArnaldo Carvalho de Melo 368ef12a141SArnaldo Carvalho de Melo int build_id__sprintf(const u8 *self, int len, char *bf) 3698d06367fSArnaldo Carvalho de Melo { 3708d06367fSArnaldo Carvalho de Melo char *bid = bf; 371ef12a141SArnaldo Carvalho de Melo const u8 *raw = self; 3728d06367fSArnaldo Carvalho de Melo int i; 3738d06367fSArnaldo Carvalho de Melo 3748d06367fSArnaldo Carvalho de Melo for (i = 0; i < len; ++i) { 3758d06367fSArnaldo Carvalho de Melo sprintf(bid, "%02x", *raw); 3768d06367fSArnaldo Carvalho de Melo ++raw; 3778d06367fSArnaldo Carvalho de Melo bid += 2; 3788d06367fSArnaldo Carvalho de Melo } 3798d06367fSArnaldo Carvalho de Melo 3808d06367fSArnaldo Carvalho de Melo return raw - self; 3818d06367fSArnaldo Carvalho de Melo } 3828d06367fSArnaldo Carvalho de Melo 3839e03eb2dSArnaldo Carvalho de Melo size_t dso__fprintf_buildid(struct dso *self, FILE *fp) 38486470930SIngo Molnar { 3858d06367fSArnaldo Carvalho de Melo char sbuild_id[BUILD_ID_SIZE * 2 + 1]; 3868d06367fSArnaldo Carvalho de Melo 3878d06367fSArnaldo Carvalho de Melo build_id__sprintf(self->build_id, sizeof(self->build_id), sbuild_id); 3889e03eb2dSArnaldo Carvalho de Melo return fprintf(fp, "%s", sbuild_id); 3899e03eb2dSArnaldo Carvalho de Melo } 3909e03eb2dSArnaldo Carvalho de Melo 39195011c60SArnaldo Carvalho de Melo size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp) 3929e03eb2dSArnaldo Carvalho de Melo { 3939e03eb2dSArnaldo Carvalho de Melo struct rb_node *nd; 3949e03eb2dSArnaldo Carvalho de Melo size_t ret = fprintf(fp, "dso: %s (", self->short_name); 3959e03eb2dSArnaldo Carvalho de Melo 3963846df2eSArnaldo Carvalho de Melo if (self->short_name != self->long_name) 3973846df2eSArnaldo Carvalho de Melo ret += fprintf(fp, "%s, ", self->long_name); 3983846df2eSArnaldo Carvalho de Melo ret += fprintf(fp, "%s, %sloaded, ", map_type__name[type], 3993846df2eSArnaldo Carvalho de Melo self->loaded ? "" : "NOT "); 4009e03eb2dSArnaldo Carvalho de Melo ret += dso__fprintf_buildid(self, fp); 4016a4694a4SArnaldo Carvalho de Melo ret += fprintf(fp, ")\n"); 40295011c60SArnaldo Carvalho de Melo for (nd = rb_first(&self->symbols[type]); nd; nd = rb_next(nd)) { 40386470930SIngo Molnar struct symbol *pos = rb_entry(nd, struct symbol, rb_node); 40486470930SIngo Molnar ret += symbol__fprintf(pos, fp); 40586470930SIngo Molnar } 40686470930SIngo Molnar 40786470930SIngo Molnar return ret; 40886470930SIngo Molnar } 40986470930SIngo Molnar 4109e201442SArnaldo Carvalho de Melo int kallsyms__parse(const char *filename, void *arg, 4119e201442SArnaldo Carvalho de Melo int (*process_symbol)(void *arg, const char *name, 412682b335aSArnaldo Carvalho de Melo char type, u64 start)) 41386470930SIngo Molnar { 41486470930SIngo Molnar char *line = NULL; 41586470930SIngo Molnar size_t n; 416682b335aSArnaldo Carvalho de Melo int err = 0; 4179e201442SArnaldo Carvalho de Melo FILE *file = fopen(filename, "r"); 41886470930SIngo Molnar 41986470930SIngo Molnar if (file == NULL) 42086470930SIngo Molnar goto out_failure; 42186470930SIngo Molnar 42286470930SIngo Molnar while (!feof(file)) { 4239cffa8d5SPaul Mackerras u64 start; 42486470930SIngo Molnar int line_len, len; 42586470930SIngo Molnar char symbol_type; 4262e538c4aSArnaldo Carvalho de Melo char *symbol_name; 42786470930SIngo Molnar 42886470930SIngo Molnar line_len = getline(&line, &n, file); 429a1645ce1SZhang, Yanmin if (line_len < 0 || !line) 43086470930SIngo Molnar break; 43186470930SIngo Molnar 43286470930SIngo Molnar line[--line_len] = '\0'; /* \n */ 43386470930SIngo Molnar 43486470930SIngo Molnar len = hex2u64(line, &start); 43586470930SIngo Molnar 43686470930SIngo Molnar len++; 43786470930SIngo Molnar if (len + 2 >= line_len) 43886470930SIngo Molnar continue; 43986470930SIngo Molnar 44086470930SIngo Molnar symbol_type = toupper(line[len]); 441af427bf5SArnaldo Carvalho de Melo symbol_name = line + len + 2; 442682b335aSArnaldo Carvalho de Melo 443682b335aSArnaldo Carvalho de Melo err = process_symbol(arg, symbol_name, symbol_type, start); 444682b335aSArnaldo Carvalho de Melo if (err) 445682b335aSArnaldo Carvalho de Melo break; 446682b335aSArnaldo Carvalho de Melo } 447682b335aSArnaldo Carvalho de Melo 448682b335aSArnaldo Carvalho de Melo free(line); 449682b335aSArnaldo Carvalho de Melo fclose(file); 450682b335aSArnaldo Carvalho de Melo return err; 451682b335aSArnaldo Carvalho de Melo 452682b335aSArnaldo Carvalho de Melo out_failure: 453682b335aSArnaldo Carvalho de Melo return -1; 454682b335aSArnaldo Carvalho de Melo } 455682b335aSArnaldo Carvalho de Melo 456682b335aSArnaldo Carvalho de Melo struct process_kallsyms_args { 457682b335aSArnaldo Carvalho de Melo struct map *map; 458682b335aSArnaldo Carvalho de Melo struct dso *dso; 459682b335aSArnaldo Carvalho de Melo }; 460682b335aSArnaldo Carvalho de Melo 461*c408fedfSArnaldo Carvalho de Melo static u8 kallsyms2elf_type(char type) 462*c408fedfSArnaldo Carvalho de Melo { 463*c408fedfSArnaldo Carvalho de Melo if (type == 'W') 464*c408fedfSArnaldo Carvalho de Melo return STB_WEAK; 465*c408fedfSArnaldo Carvalho de Melo 466*c408fedfSArnaldo Carvalho de Melo return isupper(type) ? STB_GLOBAL : STB_LOCAL; 467*c408fedfSArnaldo Carvalho de Melo } 468*c408fedfSArnaldo Carvalho de Melo 469682b335aSArnaldo Carvalho de Melo static int map__process_kallsym_symbol(void *arg, const char *name, 470682b335aSArnaldo Carvalho de Melo char type, u64 start) 471682b335aSArnaldo Carvalho de Melo { 472682b335aSArnaldo Carvalho de Melo struct symbol *sym; 473682b335aSArnaldo Carvalho de Melo struct process_kallsyms_args *a = arg; 474682b335aSArnaldo Carvalho de Melo struct rb_root *root = &a->dso->symbols[a->map->type]; 475682b335aSArnaldo Carvalho de Melo 476682b335aSArnaldo Carvalho de Melo if (!symbol_type__is_a(type, a->map->type)) 477682b335aSArnaldo Carvalho de Melo return 0; 478682b335aSArnaldo Carvalho de Melo 4792e538c4aSArnaldo Carvalho de Melo /* 4802e538c4aSArnaldo Carvalho de Melo * Will fix up the end later, when we have all symbols sorted. 4812e538c4aSArnaldo Carvalho de Melo */ 482*c408fedfSArnaldo Carvalho de Melo sym = symbol__new(start, 0, kallsyms2elf_type(type), name); 483af427bf5SArnaldo Carvalho de Melo 4842e538c4aSArnaldo Carvalho de Melo if (sym == NULL) 485682b335aSArnaldo Carvalho de Melo return -ENOMEM; 48682164161SArnaldo Carvalho de Melo /* 48782164161SArnaldo Carvalho de Melo * We will pass the symbols to the filter later, in 4884e06255fSArnaldo Carvalho de Melo * map__split_kallsyms, when we have split the maps per module 48982164161SArnaldo Carvalho de Melo */ 4904e06255fSArnaldo Carvalho de Melo symbols__insert(root, sym); 491a1645ce1SZhang, Yanmin 492682b335aSArnaldo Carvalho de Melo return 0; 4932e538c4aSArnaldo Carvalho de Melo } 4942e538c4aSArnaldo Carvalho de Melo 495682b335aSArnaldo Carvalho de Melo /* 496682b335aSArnaldo Carvalho de Melo * Loads the function entries in /proc/kallsyms into kernel_map->dso, 497682b335aSArnaldo Carvalho de Melo * so that we can in the next step set the symbol ->end address and then 498682b335aSArnaldo Carvalho de Melo * call kernel_maps__split_kallsyms. 499682b335aSArnaldo Carvalho de Melo */ 5009e201442SArnaldo Carvalho de Melo static int dso__load_all_kallsyms(struct dso *self, const char *filename, 5019e201442SArnaldo Carvalho de Melo struct map *map) 502682b335aSArnaldo Carvalho de Melo { 503682b335aSArnaldo Carvalho de Melo struct process_kallsyms_args args = { .map = map, .dso = self, }; 5049e201442SArnaldo Carvalho de Melo return kallsyms__parse(filename, &args, map__process_kallsym_symbol); 5052e538c4aSArnaldo Carvalho de Melo } 5062e538c4aSArnaldo Carvalho de Melo 5072e538c4aSArnaldo Carvalho de Melo /* 5082e538c4aSArnaldo Carvalho de Melo * Split the symbols into maps, making sure there are no overlaps, i.e. the 5092e538c4aSArnaldo Carvalho de Melo * kernel range is broken in several maps, named [kernel].N, as we don't have 5102e538c4aSArnaldo Carvalho de Melo * the original ELF section names vmlinux have. 5112e538c4aSArnaldo Carvalho de Melo */ 5129958e1f0SArnaldo Carvalho de Melo static int dso__split_kallsyms(struct dso *self, struct map *map, 5139de89fe7SArnaldo Carvalho de Melo symbol_filter_t filter) 5142e538c4aSArnaldo Carvalho de Melo { 5159de89fe7SArnaldo Carvalho de Melo struct map_groups *kmaps = map__kmap(map)->kmaps; 51623346f21SArnaldo Carvalho de Melo struct machine *machine = kmaps->machine; 5174e06255fSArnaldo Carvalho de Melo struct map *curr_map = map; 5182e538c4aSArnaldo Carvalho de Melo struct symbol *pos; 5192e538c4aSArnaldo Carvalho de Melo int count = 0; 5204e06255fSArnaldo Carvalho de Melo struct rb_root *root = &self->symbols[map->type]; 5214e06255fSArnaldo Carvalho de Melo struct rb_node *next = rb_first(root); 5222e538c4aSArnaldo Carvalho de Melo int kernel_range = 0; 5232e538c4aSArnaldo Carvalho de Melo 5242e538c4aSArnaldo Carvalho de Melo while (next) { 5252e538c4aSArnaldo Carvalho de Melo char *module; 5262e538c4aSArnaldo Carvalho de Melo 5272e538c4aSArnaldo Carvalho de Melo pos = rb_entry(next, struct symbol, rb_node); 5282e538c4aSArnaldo Carvalho de Melo next = rb_next(&pos->rb_node); 5292e538c4aSArnaldo Carvalho de Melo 5302e538c4aSArnaldo Carvalho de Melo module = strchr(pos->name, '\t'); 5312e538c4aSArnaldo Carvalho de Melo if (module) { 53275be6cf4SArnaldo Carvalho de Melo if (!symbol_conf.use_modules) 5331de8e245SArnaldo Carvalho de Melo goto discard_symbol; 5341de8e245SArnaldo Carvalho de Melo 5352e538c4aSArnaldo Carvalho de Melo *module++ = '\0'; 5362e538c4aSArnaldo Carvalho de Melo 537b7cece76SArnaldo Carvalho de Melo if (strcmp(curr_map->dso->short_name, module)) { 538a1645ce1SZhang, Yanmin if (curr_map != map && 539a1645ce1SZhang, Yanmin self->kernel == DSO_TYPE_GUEST_KERNEL && 54023346f21SArnaldo Carvalho de Melo machine__is_default_guest(machine)) { 541a1645ce1SZhang, Yanmin /* 542a1645ce1SZhang, Yanmin * We assume all symbols of a module are 543a1645ce1SZhang, Yanmin * continuous in * kallsyms, so curr_map 544a1645ce1SZhang, Yanmin * points to a module and all its 545a1645ce1SZhang, Yanmin * symbols are in its kmap. Mark it as 546a1645ce1SZhang, Yanmin * loaded. 547a1645ce1SZhang, Yanmin */ 548a1645ce1SZhang, Yanmin dso__set_loaded(curr_map->dso, 549a1645ce1SZhang, Yanmin curr_map->type); 550af427bf5SArnaldo Carvalho de Melo } 551b7cece76SArnaldo Carvalho de Melo 552a1645ce1SZhang, Yanmin curr_map = map_groups__find_by_name(kmaps, 553a1645ce1SZhang, Yanmin map->type, module); 554a1645ce1SZhang, Yanmin if (curr_map == NULL) { 5552f51903bSArnaldo Carvalho de Melo pr_debug("%s/proc/{kallsyms,modules} " 556a1645ce1SZhang, Yanmin "inconsistency while looking " 557a1645ce1SZhang, Yanmin "for \"%s\" module!\n", 55823346f21SArnaldo Carvalho de Melo machine->root_dir, module); 559a1645ce1SZhang, Yanmin curr_map = map; 560a1645ce1SZhang, Yanmin goto discard_symbol; 561a1645ce1SZhang, Yanmin } 562a1645ce1SZhang, Yanmin 563a1645ce1SZhang, Yanmin if (curr_map->dso->loaded && 56423346f21SArnaldo Carvalho de Melo !machine__is_default_guest(machine)) 565b7cece76SArnaldo Carvalho de Melo goto discard_symbol; 566af427bf5SArnaldo Carvalho de Melo } 56786470930SIngo Molnar /* 5682e538c4aSArnaldo Carvalho de Melo * So that we look just like we get from .ko files, 5692e538c4aSArnaldo Carvalho de Melo * i.e. not prelinked, relative to map->start. 57086470930SIngo Molnar */ 5714e06255fSArnaldo Carvalho de Melo pos->start = curr_map->map_ip(curr_map, pos->start); 5724e06255fSArnaldo Carvalho de Melo pos->end = curr_map->map_ip(curr_map, pos->end); 5734e06255fSArnaldo Carvalho de Melo } else if (curr_map != map) { 5742e538c4aSArnaldo Carvalho de Melo char dso_name[PATH_MAX]; 5752e538c4aSArnaldo Carvalho de Melo struct dso *dso; 57686470930SIngo Molnar 577a1645ce1SZhang, Yanmin if (self->kernel == DSO_TYPE_GUEST_KERNEL) 578a1645ce1SZhang, Yanmin snprintf(dso_name, sizeof(dso_name), 579a1645ce1SZhang, Yanmin "[guest.kernel].%d", 580a1645ce1SZhang, Yanmin kernel_range++); 581a1645ce1SZhang, Yanmin else 582a1645ce1SZhang, Yanmin snprintf(dso_name, sizeof(dso_name), 583a1645ce1SZhang, Yanmin "[kernel].%d", 5842e538c4aSArnaldo Carvalho de Melo kernel_range++); 58586470930SIngo Molnar 58600a192b3SArnaldo Carvalho de Melo dso = dso__new(dso_name); 5872e538c4aSArnaldo Carvalho de Melo if (dso == NULL) 5882e538c4aSArnaldo Carvalho de Melo return -1; 5892e538c4aSArnaldo Carvalho de Melo 590a1645ce1SZhang, Yanmin dso->kernel = self->kernel; 591a1645ce1SZhang, Yanmin 5924e06255fSArnaldo Carvalho de Melo curr_map = map__new2(pos->start, dso, map->type); 59337fe5fcbSZhang, Yanmin if (curr_map == NULL) { 5942e538c4aSArnaldo Carvalho de Melo dso__delete(dso); 5952e538c4aSArnaldo Carvalho de Melo return -1; 5962e538c4aSArnaldo Carvalho de Melo } 5972e538c4aSArnaldo Carvalho de Melo 5984e06255fSArnaldo Carvalho de Melo curr_map->map_ip = curr_map->unmap_ip = identity__map_ip; 5999de89fe7SArnaldo Carvalho de Melo map_groups__insert(kmaps, curr_map); 6002e538c4aSArnaldo Carvalho de Melo ++kernel_range; 6012e538c4aSArnaldo Carvalho de Melo } 6022e538c4aSArnaldo Carvalho de Melo 6034e06255fSArnaldo Carvalho de Melo if (filter && filter(curr_map, pos)) { 6041de8e245SArnaldo Carvalho de Melo discard_symbol: rb_erase(&pos->rb_node, root); 60500a192b3SArnaldo Carvalho de Melo symbol__delete(pos); 6062e538c4aSArnaldo Carvalho de Melo } else { 6074e06255fSArnaldo Carvalho de Melo if (curr_map != map) { 6084e06255fSArnaldo Carvalho de Melo rb_erase(&pos->rb_node, root); 6094e06255fSArnaldo Carvalho de Melo symbols__insert(&curr_map->dso->symbols[curr_map->type], pos); 6102e538c4aSArnaldo Carvalho de Melo } 6119974f496SMike Galbraith count++; 6129974f496SMike Galbraith } 61386470930SIngo Molnar } 61486470930SIngo Molnar 615a1645ce1SZhang, Yanmin if (curr_map != map && 616a1645ce1SZhang, Yanmin self->kernel == DSO_TYPE_GUEST_KERNEL && 61723346f21SArnaldo Carvalho de Melo machine__is_default_guest(kmaps->machine)) { 618a1645ce1SZhang, Yanmin dso__set_loaded(curr_map->dso, curr_map->type); 619a1645ce1SZhang, Yanmin } 620a1645ce1SZhang, Yanmin 6219974f496SMike Galbraith return count; 62286470930SIngo Molnar } 62386470930SIngo Molnar 6249de89fe7SArnaldo Carvalho de Melo int dso__load_kallsyms(struct dso *self, const char *filename, 6259de89fe7SArnaldo Carvalho de Melo struct map *map, symbol_filter_t filter) 6262e538c4aSArnaldo Carvalho de Melo { 6279e201442SArnaldo Carvalho de Melo if (dso__load_all_kallsyms(self, filename, map) < 0) 6282e538c4aSArnaldo Carvalho de Melo return -1; 6292e538c4aSArnaldo Carvalho de Melo 6304e06255fSArnaldo Carvalho de Melo symbols__fixup_end(&self->symbols[map->type]); 631a1645ce1SZhang, Yanmin if (self->kernel == DSO_TYPE_GUEST_KERNEL) 632a1645ce1SZhang, Yanmin self->origin = DSO__ORIG_GUEST_KERNEL; 633a1645ce1SZhang, Yanmin else 6344e06255fSArnaldo Carvalho de Melo self->origin = DSO__ORIG_KERNEL; 6352e538c4aSArnaldo Carvalho de Melo 6369de89fe7SArnaldo Carvalho de Melo return dso__split_kallsyms(self, map, filter); 637af427bf5SArnaldo Carvalho de Melo } 638af427bf5SArnaldo Carvalho de Melo 639439d473bSArnaldo Carvalho de Melo static int dso__load_perf_map(struct dso *self, struct map *map, 6406beba7adSArnaldo Carvalho de Melo symbol_filter_t filter) 64180d496beSPekka Enberg { 64280d496beSPekka Enberg char *line = NULL; 64380d496beSPekka Enberg size_t n; 64480d496beSPekka Enberg FILE *file; 64580d496beSPekka Enberg int nr_syms = 0; 64680d496beSPekka Enberg 647439d473bSArnaldo Carvalho de Melo file = fopen(self->long_name, "r"); 64880d496beSPekka Enberg if (file == NULL) 64980d496beSPekka Enberg goto out_failure; 65080d496beSPekka Enberg 65180d496beSPekka Enberg while (!feof(file)) { 6529cffa8d5SPaul Mackerras u64 start, size; 65380d496beSPekka Enberg struct symbol *sym; 65480d496beSPekka Enberg int line_len, len; 65580d496beSPekka Enberg 65680d496beSPekka Enberg line_len = getline(&line, &n, file); 65780d496beSPekka Enberg if (line_len < 0) 65880d496beSPekka Enberg break; 65980d496beSPekka Enberg 66080d496beSPekka Enberg if (!line) 66180d496beSPekka Enberg goto out_failure; 66280d496beSPekka Enberg 66380d496beSPekka Enberg line[--line_len] = '\0'; /* \n */ 66480d496beSPekka Enberg 66580d496beSPekka Enberg len = hex2u64(line, &start); 66680d496beSPekka Enberg 66780d496beSPekka Enberg len++; 66880d496beSPekka Enberg if (len + 2 >= line_len) 66980d496beSPekka Enberg continue; 67080d496beSPekka Enberg 67180d496beSPekka Enberg len += hex2u64(line + len, &size); 67280d496beSPekka Enberg 67380d496beSPekka Enberg len++; 67480d496beSPekka Enberg if (len + 2 >= line_len) 67580d496beSPekka Enberg continue; 67680d496beSPekka Enberg 677*c408fedfSArnaldo Carvalho de Melo sym = symbol__new(start, size, STB_GLOBAL, line + len); 67880d496beSPekka Enberg 67980d496beSPekka Enberg if (sym == NULL) 68080d496beSPekka Enberg goto out_delete_line; 68180d496beSPekka Enberg 682439d473bSArnaldo Carvalho de Melo if (filter && filter(map, sym)) 68300a192b3SArnaldo Carvalho de Melo symbol__delete(sym); 68480d496beSPekka Enberg else { 6856a4694a4SArnaldo Carvalho de Melo symbols__insert(&self->symbols[map->type], sym); 68680d496beSPekka Enberg nr_syms++; 68780d496beSPekka Enberg } 68880d496beSPekka Enberg } 68980d496beSPekka Enberg 69080d496beSPekka Enberg free(line); 69180d496beSPekka Enberg fclose(file); 69280d496beSPekka Enberg 69380d496beSPekka Enberg return nr_syms; 69480d496beSPekka Enberg 69580d496beSPekka Enberg out_delete_line: 69680d496beSPekka Enberg free(line); 69780d496beSPekka Enberg out_failure: 69880d496beSPekka Enberg return -1; 69980d496beSPekka Enberg } 70080d496beSPekka Enberg 70186470930SIngo Molnar /** 70286470930SIngo Molnar * elf_symtab__for_each_symbol - iterate thru all the symbols 70386470930SIngo Molnar * 70486470930SIngo Molnar * @self: struct elf_symtab instance to iterate 70583a0944fSIngo Molnar * @idx: uint32_t idx 70686470930SIngo Molnar * @sym: GElf_Sym iterator 70786470930SIngo Molnar */ 70883a0944fSIngo Molnar #define elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) \ 70983a0944fSIngo Molnar for (idx = 0, gelf_getsym(syms, idx, &sym);\ 71083a0944fSIngo Molnar idx < nr_syms; \ 71183a0944fSIngo Molnar idx++, gelf_getsym(syms, idx, &sym)) 71286470930SIngo Molnar 71386470930SIngo Molnar static inline uint8_t elf_sym__type(const GElf_Sym *sym) 71486470930SIngo Molnar { 71586470930SIngo Molnar return GELF_ST_TYPE(sym->st_info); 71686470930SIngo Molnar } 71786470930SIngo Molnar 71886470930SIngo Molnar static inline int elf_sym__is_function(const GElf_Sym *sym) 71986470930SIngo Molnar { 72086470930SIngo Molnar return elf_sym__type(sym) == STT_FUNC && 72186470930SIngo Molnar sym->st_name != 0 && 72281833130SArnaldo Carvalho de Melo sym->st_shndx != SHN_UNDEF; 72386470930SIngo Molnar } 72486470930SIngo Molnar 725f1dfa0b1SArnaldo Carvalho de Melo static inline bool elf_sym__is_object(const GElf_Sym *sym) 726f1dfa0b1SArnaldo Carvalho de Melo { 727f1dfa0b1SArnaldo Carvalho de Melo return elf_sym__type(sym) == STT_OBJECT && 728f1dfa0b1SArnaldo Carvalho de Melo sym->st_name != 0 && 729f1dfa0b1SArnaldo Carvalho de Melo sym->st_shndx != SHN_UNDEF; 730f1dfa0b1SArnaldo Carvalho de Melo } 731f1dfa0b1SArnaldo Carvalho de Melo 7326cfcc53eSMike Galbraith static inline int elf_sym__is_label(const GElf_Sym *sym) 7336cfcc53eSMike Galbraith { 7346cfcc53eSMike Galbraith return elf_sym__type(sym) == STT_NOTYPE && 7356cfcc53eSMike Galbraith sym->st_name != 0 && 7366cfcc53eSMike Galbraith sym->st_shndx != SHN_UNDEF && 7376cfcc53eSMike Galbraith sym->st_shndx != SHN_ABS; 7386cfcc53eSMike Galbraith } 7396cfcc53eSMike Galbraith 7406cfcc53eSMike Galbraith static inline const char *elf_sec__name(const GElf_Shdr *shdr, 7416cfcc53eSMike Galbraith const Elf_Data *secstrs) 7426cfcc53eSMike Galbraith { 7436cfcc53eSMike Galbraith return secstrs->d_buf + shdr->sh_name; 7446cfcc53eSMike Galbraith } 7456cfcc53eSMike Galbraith 7466cfcc53eSMike Galbraith static inline int elf_sec__is_text(const GElf_Shdr *shdr, 7476cfcc53eSMike Galbraith const Elf_Data *secstrs) 7486cfcc53eSMike Galbraith { 7496cfcc53eSMike Galbraith return strstr(elf_sec__name(shdr, secstrs), "text") != NULL; 7506cfcc53eSMike Galbraith } 7516cfcc53eSMike Galbraith 752f1dfa0b1SArnaldo Carvalho de Melo static inline bool elf_sec__is_data(const GElf_Shdr *shdr, 753f1dfa0b1SArnaldo Carvalho de Melo const Elf_Data *secstrs) 754f1dfa0b1SArnaldo Carvalho de Melo { 755f1dfa0b1SArnaldo Carvalho de Melo return strstr(elf_sec__name(shdr, secstrs), "data") != NULL; 756f1dfa0b1SArnaldo Carvalho de Melo } 757f1dfa0b1SArnaldo Carvalho de Melo 75886470930SIngo Molnar static inline const char *elf_sym__name(const GElf_Sym *sym, 75986470930SIngo Molnar const Elf_Data *symstrs) 76086470930SIngo Molnar { 76186470930SIngo Molnar return symstrs->d_buf + sym->st_name; 76286470930SIngo Molnar } 76386470930SIngo Molnar 76486470930SIngo Molnar static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, 76586470930SIngo Molnar GElf_Shdr *shp, const char *name, 76683a0944fSIngo Molnar size_t *idx) 76786470930SIngo Molnar { 76886470930SIngo Molnar Elf_Scn *sec = NULL; 76986470930SIngo Molnar size_t cnt = 1; 77086470930SIngo Molnar 77186470930SIngo Molnar while ((sec = elf_nextscn(elf, sec)) != NULL) { 77286470930SIngo Molnar char *str; 77386470930SIngo Molnar 77486470930SIngo Molnar gelf_getshdr(sec, shp); 77586470930SIngo Molnar str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name); 77686470930SIngo Molnar if (!strcmp(name, str)) { 77783a0944fSIngo Molnar if (idx) 77883a0944fSIngo Molnar *idx = cnt; 77986470930SIngo Molnar break; 78086470930SIngo Molnar } 78186470930SIngo Molnar ++cnt; 78286470930SIngo Molnar } 78386470930SIngo Molnar 78486470930SIngo Molnar return sec; 78586470930SIngo Molnar } 78686470930SIngo Molnar 78786470930SIngo Molnar #define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \ 78886470930SIngo Molnar for (idx = 0, pos = gelf_getrel(reldata, 0, &pos_mem); \ 78986470930SIngo Molnar idx < nr_entries; \ 79086470930SIngo Molnar ++idx, pos = gelf_getrel(reldata, idx, &pos_mem)) 79186470930SIngo Molnar 79286470930SIngo Molnar #define elf_section__for_each_rela(reldata, pos, pos_mem, idx, nr_entries) \ 79386470930SIngo Molnar for (idx = 0, pos = gelf_getrela(reldata, 0, &pos_mem); \ 79486470930SIngo Molnar idx < nr_entries; \ 79586470930SIngo Molnar ++idx, pos = gelf_getrela(reldata, idx, &pos_mem)) 79686470930SIngo Molnar 797a25e46c4SArnaldo Carvalho de Melo /* 798a25e46c4SArnaldo Carvalho de Melo * We need to check if we have a .dynsym, so that we can handle the 799a25e46c4SArnaldo Carvalho de Melo * .plt, synthesizing its symbols, that aren't on the symtabs (be it 800a25e46c4SArnaldo Carvalho de Melo * .dynsym or .symtab). 801a25e46c4SArnaldo Carvalho de Melo * And always look at the original dso, not at debuginfo packages, that 802a25e46c4SArnaldo Carvalho de Melo * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS). 803a25e46c4SArnaldo Carvalho de Melo */ 80482164161SArnaldo Carvalho de Melo static int dso__synthesize_plt_symbols(struct dso *self, struct map *map, 80582164161SArnaldo Carvalho de Melo symbol_filter_t filter) 80686470930SIngo Molnar { 80786470930SIngo Molnar uint32_t nr_rel_entries, idx; 80886470930SIngo Molnar GElf_Sym sym; 8099cffa8d5SPaul Mackerras u64 plt_offset; 81086470930SIngo Molnar GElf_Shdr shdr_plt; 81186470930SIngo Molnar struct symbol *f; 812a25e46c4SArnaldo Carvalho de Melo GElf_Shdr shdr_rel_plt, shdr_dynsym; 81386470930SIngo Molnar Elf_Data *reldata, *syms, *symstrs; 814a25e46c4SArnaldo Carvalho de Melo Elf_Scn *scn_plt_rel, *scn_symstrs, *scn_dynsym; 815a25e46c4SArnaldo Carvalho de Melo size_t dynsym_idx; 816a25e46c4SArnaldo Carvalho de Melo GElf_Ehdr ehdr; 81786470930SIngo Molnar char sympltname[1024]; 818a25e46c4SArnaldo Carvalho de Melo Elf *elf; 819a25e46c4SArnaldo Carvalho de Melo int nr = 0, symidx, fd, err = 0; 82086470930SIngo Molnar 821439d473bSArnaldo Carvalho de Melo fd = open(self->long_name, O_RDONLY); 822a25e46c4SArnaldo Carvalho de Melo if (fd < 0) 823a25e46c4SArnaldo Carvalho de Melo goto out; 824a25e46c4SArnaldo Carvalho de Melo 82584087126SMarti Raudsepp elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 826a25e46c4SArnaldo Carvalho de Melo if (elf == NULL) 827a25e46c4SArnaldo Carvalho de Melo goto out_close; 828a25e46c4SArnaldo Carvalho de Melo 829a25e46c4SArnaldo Carvalho de Melo if (gelf_getehdr(elf, &ehdr) == NULL) 830a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 831a25e46c4SArnaldo Carvalho de Melo 832a25e46c4SArnaldo Carvalho de Melo scn_dynsym = elf_section_by_name(elf, &ehdr, &shdr_dynsym, 833a25e46c4SArnaldo Carvalho de Melo ".dynsym", &dynsym_idx); 834a25e46c4SArnaldo Carvalho de Melo if (scn_dynsym == NULL) 835a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 836a25e46c4SArnaldo Carvalho de Melo 837a25e46c4SArnaldo Carvalho de Melo scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt, 83886470930SIngo Molnar ".rela.plt", NULL); 83986470930SIngo Molnar if (scn_plt_rel == NULL) { 840a25e46c4SArnaldo Carvalho de Melo scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt, 84186470930SIngo Molnar ".rel.plt", NULL); 84286470930SIngo Molnar if (scn_plt_rel == NULL) 843a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 84486470930SIngo Molnar } 84586470930SIngo Molnar 846a25e46c4SArnaldo Carvalho de Melo err = -1; 84786470930SIngo Molnar 848a25e46c4SArnaldo Carvalho de Melo if (shdr_rel_plt.sh_link != dynsym_idx) 849a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 850a25e46c4SArnaldo Carvalho de Melo 851a25e46c4SArnaldo Carvalho de Melo if (elf_section_by_name(elf, &ehdr, &shdr_plt, ".plt", NULL) == NULL) 852a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 85386470930SIngo Molnar 85486470930SIngo Molnar /* 85583a0944fSIngo Molnar * Fetch the relocation section to find the idxes to the GOT 85686470930SIngo Molnar * and the symbols in the .dynsym they refer to. 85786470930SIngo Molnar */ 85886470930SIngo Molnar reldata = elf_getdata(scn_plt_rel, NULL); 85986470930SIngo Molnar if (reldata == NULL) 860a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 86186470930SIngo Molnar 86286470930SIngo Molnar syms = elf_getdata(scn_dynsym, NULL); 86386470930SIngo Molnar if (syms == NULL) 864a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 86586470930SIngo Molnar 866a25e46c4SArnaldo Carvalho de Melo scn_symstrs = elf_getscn(elf, shdr_dynsym.sh_link); 86786470930SIngo Molnar if (scn_symstrs == NULL) 868a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 86986470930SIngo Molnar 87086470930SIngo Molnar symstrs = elf_getdata(scn_symstrs, NULL); 87186470930SIngo Molnar if (symstrs == NULL) 872a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 87386470930SIngo Molnar 87486470930SIngo Molnar nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize; 87586470930SIngo Molnar plt_offset = shdr_plt.sh_offset; 87686470930SIngo Molnar 87786470930SIngo Molnar if (shdr_rel_plt.sh_type == SHT_RELA) { 87886470930SIngo Molnar GElf_Rela pos_mem, *pos; 87986470930SIngo Molnar 88086470930SIngo Molnar elf_section__for_each_rela(reldata, pos, pos_mem, idx, 88186470930SIngo Molnar nr_rel_entries) { 88286470930SIngo Molnar symidx = GELF_R_SYM(pos->r_info); 88386470930SIngo Molnar plt_offset += shdr_plt.sh_entsize; 88486470930SIngo Molnar gelf_getsym(syms, symidx, &sym); 88586470930SIngo Molnar snprintf(sympltname, sizeof(sympltname), 88686470930SIngo Molnar "%s@plt", elf_sym__name(&sym, symstrs)); 88786470930SIngo Molnar 88886470930SIngo Molnar f = symbol__new(plt_offset, shdr_plt.sh_entsize, 889*c408fedfSArnaldo Carvalho de Melo STB_GLOBAL, sympltname); 89086470930SIngo Molnar if (!f) 891a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 89286470930SIngo Molnar 89382164161SArnaldo Carvalho de Melo if (filter && filter(map, f)) 89482164161SArnaldo Carvalho de Melo symbol__delete(f); 89582164161SArnaldo Carvalho de Melo else { 8966a4694a4SArnaldo Carvalho de Melo symbols__insert(&self->symbols[map->type], f); 89786470930SIngo Molnar ++nr; 89886470930SIngo Molnar } 89982164161SArnaldo Carvalho de Melo } 90086470930SIngo Molnar } else if (shdr_rel_plt.sh_type == SHT_REL) { 90186470930SIngo Molnar GElf_Rel pos_mem, *pos; 90286470930SIngo Molnar elf_section__for_each_rel(reldata, pos, pos_mem, idx, 90386470930SIngo Molnar nr_rel_entries) { 90486470930SIngo Molnar symidx = GELF_R_SYM(pos->r_info); 90586470930SIngo Molnar plt_offset += shdr_plt.sh_entsize; 90686470930SIngo Molnar gelf_getsym(syms, symidx, &sym); 90786470930SIngo Molnar snprintf(sympltname, sizeof(sympltname), 90886470930SIngo Molnar "%s@plt", elf_sym__name(&sym, symstrs)); 90986470930SIngo Molnar 91086470930SIngo Molnar f = symbol__new(plt_offset, shdr_plt.sh_entsize, 911*c408fedfSArnaldo Carvalho de Melo STB_GLOBAL, sympltname); 91286470930SIngo Molnar if (!f) 913a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 91486470930SIngo Molnar 91582164161SArnaldo Carvalho de Melo if (filter && filter(map, f)) 91682164161SArnaldo Carvalho de Melo symbol__delete(f); 91782164161SArnaldo Carvalho de Melo else { 9186a4694a4SArnaldo Carvalho de Melo symbols__insert(&self->symbols[map->type], f); 91986470930SIngo Molnar ++nr; 92086470930SIngo Molnar } 92186470930SIngo Molnar } 92282164161SArnaldo Carvalho de Melo } 92386470930SIngo Molnar 924a25e46c4SArnaldo Carvalho de Melo err = 0; 925a25e46c4SArnaldo Carvalho de Melo out_elf_end: 926a25e46c4SArnaldo Carvalho de Melo elf_end(elf); 927a25e46c4SArnaldo Carvalho de Melo out_close: 928a25e46c4SArnaldo Carvalho de Melo close(fd); 929a25e46c4SArnaldo Carvalho de Melo 930a25e46c4SArnaldo Carvalho de Melo if (err == 0) 93186470930SIngo Molnar return nr; 932a25e46c4SArnaldo Carvalho de Melo out: 933fe2197b8SArnaldo Carvalho de Melo pr_debug("%s: problems reading %s PLT info.\n", 934439d473bSArnaldo Carvalho de Melo __func__, self->long_name); 935a25e46c4SArnaldo Carvalho de Melo return 0; 93686470930SIngo Molnar } 93786470930SIngo Molnar 938d45868d3SArnaldo Carvalho de Melo static bool elf_sym__is_a(GElf_Sym *self, enum map_type type) 939d45868d3SArnaldo Carvalho de Melo { 940d45868d3SArnaldo Carvalho de Melo switch (type) { 941d45868d3SArnaldo Carvalho de Melo case MAP__FUNCTION: 942d45868d3SArnaldo Carvalho de Melo return elf_sym__is_function(self); 943f1dfa0b1SArnaldo Carvalho de Melo case MAP__VARIABLE: 944f1dfa0b1SArnaldo Carvalho de Melo return elf_sym__is_object(self); 945d45868d3SArnaldo Carvalho de Melo default: 946d45868d3SArnaldo Carvalho de Melo return false; 947d45868d3SArnaldo Carvalho de Melo } 948d45868d3SArnaldo Carvalho de Melo } 949d45868d3SArnaldo Carvalho de Melo 950d45868d3SArnaldo Carvalho de Melo static bool elf_sec__is_a(GElf_Shdr *self, Elf_Data *secstrs, enum map_type type) 951d45868d3SArnaldo Carvalho de Melo { 952d45868d3SArnaldo Carvalho de Melo switch (type) { 953d45868d3SArnaldo Carvalho de Melo case MAP__FUNCTION: 954d45868d3SArnaldo Carvalho de Melo return elf_sec__is_text(self, secstrs); 955f1dfa0b1SArnaldo Carvalho de Melo case MAP__VARIABLE: 956f1dfa0b1SArnaldo Carvalho de Melo return elf_sec__is_data(self, secstrs); 957d45868d3SArnaldo Carvalho de Melo default: 958d45868d3SArnaldo Carvalho de Melo return false; 959d45868d3SArnaldo Carvalho de Melo } 960d45868d3SArnaldo Carvalho de Melo } 961d45868d3SArnaldo Carvalho de Melo 96270c3856bSEric B Munson static size_t elf_addr_to_index(Elf *elf, GElf_Addr addr) 96370c3856bSEric B Munson { 96470c3856bSEric B Munson Elf_Scn *sec = NULL; 96570c3856bSEric B Munson GElf_Shdr shdr; 96670c3856bSEric B Munson size_t cnt = 1; 96770c3856bSEric B Munson 96870c3856bSEric B Munson while ((sec = elf_nextscn(elf, sec)) != NULL) { 96970c3856bSEric B Munson gelf_getshdr(sec, &shdr); 97070c3856bSEric B Munson 97170c3856bSEric B Munson if ((addr >= shdr.sh_addr) && 97270c3856bSEric B Munson (addr < (shdr.sh_addr + shdr.sh_size))) 97370c3856bSEric B Munson return cnt; 97470c3856bSEric B Munson 97570c3856bSEric B Munson ++cnt; 97670c3856bSEric B Munson } 97770c3856bSEric B Munson 97870c3856bSEric B Munson return -1; 97970c3856bSEric B Munson } 98070c3856bSEric B Munson 9819de89fe7SArnaldo Carvalho de Melo static int dso__load_sym(struct dso *self, struct map *map, const char *name, 9826da80ce8SDave Martin int fd, symbol_filter_t filter, int kmodule, 9836da80ce8SDave Martin int want_symtab) 98486470930SIngo Molnar { 9859de89fe7SArnaldo Carvalho de Melo struct kmap *kmap = self->kernel ? map__kmap(map) : NULL; 9862e538c4aSArnaldo Carvalho de Melo struct map *curr_map = map; 9872e538c4aSArnaldo Carvalho de Melo struct dso *curr_dso = self; 9886cfcc53eSMike Galbraith Elf_Data *symstrs, *secstrs; 98986470930SIngo Molnar uint32_t nr_syms; 99086470930SIngo Molnar int err = -1; 99183a0944fSIngo Molnar uint32_t idx; 99286470930SIngo Molnar GElf_Ehdr ehdr; 99370c3856bSEric B Munson GElf_Shdr shdr, opdshdr; 99470c3856bSEric B Munson Elf_Data *syms, *opddata = NULL; 99586470930SIngo Molnar GElf_Sym sym; 99670c3856bSEric B Munson Elf_Scn *sec, *sec_strndx, *opdsec; 99786470930SIngo Molnar Elf *elf; 998439d473bSArnaldo Carvalho de Melo int nr = 0; 99970c3856bSEric B Munson size_t opdidx = 0; 100086470930SIngo Molnar 100184087126SMarti Raudsepp elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 100286470930SIngo Molnar if (elf == NULL) { 10038b1389efSDave Martin pr_debug("%s: cannot read %s ELF file.\n", __func__, name); 100486470930SIngo Molnar goto out_close; 100586470930SIngo Molnar } 100686470930SIngo Molnar 100786470930SIngo Molnar if (gelf_getehdr(elf, &ehdr) == NULL) { 10088b1389efSDave Martin pr_debug("%s: cannot get elf header.\n", __func__); 100986470930SIngo Molnar goto out_elf_end; 101086470930SIngo Molnar } 101186470930SIngo Molnar 10126da80ce8SDave Martin /* Always reject images with a mismatched build-id: */ 101321916c38SDave Martin if (self->has_build_id) { 101421916c38SDave Martin u8 build_id[BUILD_ID_SIZE]; 101521916c38SDave Martin 101621916c38SDave Martin if (elf_read_build_id(elf, build_id, 101721916c38SDave Martin BUILD_ID_SIZE) != BUILD_ID_SIZE) 101821916c38SDave Martin goto out_elf_end; 101921916c38SDave Martin 102021916c38SDave Martin if (!dso__build_id_equal(self, build_id)) 102121916c38SDave Martin goto out_elf_end; 102221916c38SDave Martin } 102321916c38SDave Martin 102486470930SIngo Molnar sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL); 102586470930SIngo Molnar if (sec == NULL) { 10266da80ce8SDave Martin if (want_symtab) 10276da80ce8SDave Martin goto out_elf_end; 10286da80ce8SDave Martin 1029a25e46c4SArnaldo Carvalho de Melo sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL); 1030a25e46c4SArnaldo Carvalho de Melo if (sec == NULL) 103186470930SIngo Molnar goto out_elf_end; 103286470930SIngo Molnar } 103386470930SIngo Molnar 103470c3856bSEric B Munson opdsec = elf_section_by_name(elf, &ehdr, &opdshdr, ".opd", &opdidx); 103570c3856bSEric B Munson if (opdsec) 103670c3856bSEric B Munson opddata = elf_rawdata(opdsec, NULL); 103770c3856bSEric B Munson 103886470930SIngo Molnar syms = elf_getdata(sec, NULL); 103986470930SIngo Molnar if (syms == NULL) 104086470930SIngo Molnar goto out_elf_end; 104186470930SIngo Molnar 104286470930SIngo Molnar sec = elf_getscn(elf, shdr.sh_link); 104386470930SIngo Molnar if (sec == NULL) 104486470930SIngo Molnar goto out_elf_end; 104586470930SIngo Molnar 104686470930SIngo Molnar symstrs = elf_getdata(sec, NULL); 104786470930SIngo Molnar if (symstrs == NULL) 104886470930SIngo Molnar goto out_elf_end; 104986470930SIngo Molnar 10506cfcc53eSMike Galbraith sec_strndx = elf_getscn(elf, ehdr.e_shstrndx); 10516cfcc53eSMike Galbraith if (sec_strndx == NULL) 10526cfcc53eSMike Galbraith goto out_elf_end; 10536cfcc53eSMike Galbraith 10546cfcc53eSMike Galbraith secstrs = elf_getdata(sec_strndx, NULL); 10559b30a26bSStoyan Gaydarov if (secstrs == NULL) 10566cfcc53eSMike Galbraith goto out_elf_end; 10576cfcc53eSMike Galbraith 105886470930SIngo Molnar nr_syms = shdr.sh_size / shdr.sh_entsize; 105986470930SIngo Molnar 1060e9fbc9dcSArjan van de Ven memset(&sym, 0, sizeof(sym)); 1061a1645ce1SZhang, Yanmin if (self->kernel == DSO_TYPE_USER) { 106230d7a77dSArnaldo Carvalho de Melo self->adjust_symbols = (ehdr.e_type == ET_EXEC || 106330d7a77dSArnaldo Carvalho de Melo elf_section_by_name(elf, &ehdr, &shdr, 1064f5812a7aSArnaldo Carvalho de Melo ".gnu.prelink_undo", 106530d7a77dSArnaldo Carvalho de Melo NULL) != NULL); 1066d20ff6bdSMike Galbraith } else self->adjust_symbols = 0; 1067d20ff6bdSMike Galbraith 106883a0944fSIngo Molnar elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) { 106986470930SIngo Molnar struct symbol *f; 107056b03f3cSArnaldo Carvalho de Melo const char *elf_name = elf_sym__name(&sym, symstrs); 10712e538c4aSArnaldo Carvalho de Melo char *demangled = NULL; 10726cfcc53eSMike Galbraith int is_label = elf_sym__is_label(&sym); 10736cfcc53eSMike Galbraith const char *section_name; 107486470930SIngo Molnar 10759de89fe7SArnaldo Carvalho de Melo if (kmap && kmap->ref_reloc_sym && kmap->ref_reloc_sym->name && 10769de89fe7SArnaldo Carvalho de Melo strcmp(elf_name, kmap->ref_reloc_sym->name) == 0) 10779de89fe7SArnaldo Carvalho de Melo kmap->ref_reloc_sym->unrelocated_addr = sym.st_value; 107856b03f3cSArnaldo Carvalho de Melo 1079d45868d3SArnaldo Carvalho de Melo if (!is_label && !elf_sym__is_a(&sym, map->type)) 108086470930SIngo Molnar continue; 108186470930SIngo Molnar 108270c3856bSEric B Munson if (opdsec && sym.st_shndx == opdidx) { 108370c3856bSEric B Munson u32 offset = sym.st_value - opdshdr.sh_addr; 108470c3856bSEric B Munson u64 *opd = opddata->d_buf + offset; 108570c3856bSEric B Munson sym.st_value = *opd; 108670c3856bSEric B Munson sym.st_shndx = elf_addr_to_index(elf, sym.st_value); 108770c3856bSEric B Munson } 108870c3856bSEric B Munson 108986470930SIngo Molnar sec = elf_getscn(elf, sym.st_shndx); 109086470930SIngo Molnar if (!sec) 109186470930SIngo Molnar goto out_elf_end; 109286470930SIngo Molnar 109386470930SIngo Molnar gelf_getshdr(sec, &shdr); 10946cfcc53eSMike Galbraith 1095d45868d3SArnaldo Carvalho de Melo if (is_label && !elf_sec__is_a(&shdr, secstrs, map->type)) 10966cfcc53eSMike Galbraith continue; 10976cfcc53eSMike Galbraith 10986cfcc53eSMike Galbraith section_name = elf_sec__name(&shdr, secstrs); 109986470930SIngo Molnar 1100a1645ce1SZhang, Yanmin if (self->kernel != DSO_TYPE_USER || kmodule) { 11012e538c4aSArnaldo Carvalho de Melo char dso_name[PATH_MAX]; 11022e538c4aSArnaldo Carvalho de Melo 11032e538c4aSArnaldo Carvalho de Melo if (strcmp(section_name, 1104b63be8d7SArnaldo Carvalho de Melo (curr_dso->short_name + 1105b63be8d7SArnaldo Carvalho de Melo self->short_name_len)) == 0) 11062e538c4aSArnaldo Carvalho de Melo goto new_symbol; 11072e538c4aSArnaldo Carvalho de Melo 11082e538c4aSArnaldo Carvalho de Melo if (strcmp(section_name, ".text") == 0) { 11092e538c4aSArnaldo Carvalho de Melo curr_map = map; 11102e538c4aSArnaldo Carvalho de Melo curr_dso = self; 11112e538c4aSArnaldo Carvalho de Melo goto new_symbol; 1112af427bf5SArnaldo Carvalho de Melo } 1113af427bf5SArnaldo Carvalho de Melo 11142e538c4aSArnaldo Carvalho de Melo snprintf(dso_name, sizeof(dso_name), 11152e538c4aSArnaldo Carvalho de Melo "%s%s", self->short_name, section_name); 11162e538c4aSArnaldo Carvalho de Melo 11179de89fe7SArnaldo Carvalho de Melo curr_map = map_groups__find_by_name(kmap->kmaps, map->type, dso_name); 11182e538c4aSArnaldo Carvalho de Melo if (curr_map == NULL) { 11192e538c4aSArnaldo Carvalho de Melo u64 start = sym.st_value; 11202e538c4aSArnaldo Carvalho de Melo 11212e538c4aSArnaldo Carvalho de Melo if (kmodule) 11222e538c4aSArnaldo Carvalho de Melo start += map->start + shdr.sh_offset; 11232e538c4aSArnaldo Carvalho de Melo 112400a192b3SArnaldo Carvalho de Melo curr_dso = dso__new(dso_name); 11252e538c4aSArnaldo Carvalho de Melo if (curr_dso == NULL) 11262e538c4aSArnaldo Carvalho de Melo goto out_elf_end; 1127a1645ce1SZhang, Yanmin curr_dso->kernel = self->kernel; 11283610583cSArnaldo Carvalho de Melo curr_map = map__new2(start, curr_dso, 11296275ce2dSArnaldo Carvalho de Melo map->type); 11302e538c4aSArnaldo Carvalho de Melo if (curr_map == NULL) { 11312e538c4aSArnaldo Carvalho de Melo dso__delete(curr_dso); 11322e538c4aSArnaldo Carvalho de Melo goto out_elf_end; 11332e538c4aSArnaldo Carvalho de Melo } 1134ed52ce2eSArnaldo Carvalho de Melo curr_map->map_ip = identity__map_ip; 1135ed52ce2eSArnaldo Carvalho de Melo curr_map->unmap_ip = identity__map_ip; 1136b0a9ab62SArnaldo Carvalho de Melo curr_dso->origin = self->origin; 11379de89fe7SArnaldo Carvalho de Melo map_groups__insert(kmap->kmaps, curr_map); 1138a1645ce1SZhang, Yanmin dsos__add(&self->node, curr_dso); 11396275ce2dSArnaldo Carvalho de Melo dso__set_loaded(curr_dso, map->type); 11402e538c4aSArnaldo Carvalho de Melo } else 11412e538c4aSArnaldo Carvalho de Melo curr_dso = curr_map->dso; 11422e538c4aSArnaldo Carvalho de Melo 11432e538c4aSArnaldo Carvalho de Melo goto new_symbol; 11442e538c4aSArnaldo Carvalho de Melo } 11452e538c4aSArnaldo Carvalho de Melo 11462e538c4aSArnaldo Carvalho de Melo if (curr_dso->adjust_symbols) { 114729a9f66dSArnaldo Carvalho de Melo pr_debug4("%s: adjusting symbol: st_value: %#Lx " 114829a9f66dSArnaldo Carvalho de Melo "sh_addr: %#Lx sh_offset: %#Lx\n", __func__, 114929a9f66dSArnaldo Carvalho de Melo (u64)sym.st_value, (u64)shdr.sh_addr, 115029a9f66dSArnaldo Carvalho de Melo (u64)shdr.sh_offset); 115186470930SIngo Molnar sym.st_value -= shdr.sh_addr - shdr.sh_offset; 1152af427bf5SArnaldo Carvalho de Melo } 115328ac909bSArnaldo Carvalho de Melo /* 115428ac909bSArnaldo Carvalho de Melo * We need to figure out if the object was created from C++ sources 115528ac909bSArnaldo Carvalho de Melo * DWARF DW_compile_unit has this, but we don't always have access 115628ac909bSArnaldo Carvalho de Melo * to it... 115728ac909bSArnaldo Carvalho de Melo */ 115883a0944fSIngo Molnar demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI); 115928ac909bSArnaldo Carvalho de Melo if (demangled != NULL) 116083a0944fSIngo Molnar elf_name = demangled; 11612e538c4aSArnaldo Carvalho de Melo new_symbol: 1162*c408fedfSArnaldo Carvalho de Melo f = symbol__new(sym.st_value, sym.st_size, 1163*c408fedfSArnaldo Carvalho de Melo GELF_ST_BIND(sym.st_info), elf_name); 116428ac909bSArnaldo Carvalho de Melo free(demangled); 116586470930SIngo Molnar if (!f) 116686470930SIngo Molnar goto out_elf_end; 116786470930SIngo Molnar 11682e538c4aSArnaldo Carvalho de Melo if (filter && filter(curr_map, f)) 116900a192b3SArnaldo Carvalho de Melo symbol__delete(f); 117086470930SIngo Molnar else { 11716a4694a4SArnaldo Carvalho de Melo symbols__insert(&curr_dso->symbols[curr_map->type], f); 117286470930SIngo Molnar nr++; 117386470930SIngo Molnar } 117486470930SIngo Molnar } 117586470930SIngo Molnar 11762e538c4aSArnaldo Carvalho de Melo /* 11772e538c4aSArnaldo Carvalho de Melo * For misannotated, zeroed, ASM function sizes. 11782e538c4aSArnaldo Carvalho de Melo */ 11796275ce2dSArnaldo Carvalho de Melo if (nr > 0) { 11806a4694a4SArnaldo Carvalho de Melo symbols__fixup_end(&self->symbols[map->type]); 11816275ce2dSArnaldo Carvalho de Melo if (kmap) { 11826275ce2dSArnaldo Carvalho de Melo /* 11836275ce2dSArnaldo Carvalho de Melo * We need to fixup this here too because we create new 11846275ce2dSArnaldo Carvalho de Melo * maps here, for things like vsyscall sections. 11856275ce2dSArnaldo Carvalho de Melo */ 11866275ce2dSArnaldo Carvalho de Melo __map_groups__fixup_end(kmap->kmaps, map->type); 11876275ce2dSArnaldo Carvalho de Melo } 11886275ce2dSArnaldo Carvalho de Melo } 118986470930SIngo Molnar err = nr; 119086470930SIngo Molnar out_elf_end: 119186470930SIngo Molnar elf_end(elf); 119286470930SIngo Molnar out_close: 119386470930SIngo Molnar return err; 119486470930SIngo Molnar } 119586470930SIngo Molnar 119678075caaSArnaldo Carvalho de Melo static bool dso__build_id_equal(const struct dso *self, u8 *build_id) 119778075caaSArnaldo Carvalho de Melo { 119878075caaSArnaldo Carvalho de Melo return memcmp(self->build_id, build_id, sizeof(self->build_id)) == 0; 119978075caaSArnaldo Carvalho de Melo } 120078075caaSArnaldo Carvalho de Melo 1201a1645ce1SZhang, Yanmin bool __dsos__read_build_ids(struct list_head *head, bool with_hits) 120257f395a7SFrederic Weisbecker { 1203e30a3d12SArnaldo Carvalho de Melo bool have_build_id = false; 120457f395a7SFrederic Weisbecker struct dso *pos; 120557f395a7SFrederic Weisbecker 12066122e4e4SArnaldo Carvalho de Melo list_for_each_entry(pos, head, node) { 12076122e4e4SArnaldo Carvalho de Melo if (with_hits && !pos->hit) 12086122e4e4SArnaldo Carvalho de Melo continue; 1209f6e1467dSArnaldo Carvalho de Melo if (pos->has_build_id) { 1210f6e1467dSArnaldo Carvalho de Melo have_build_id = true; 1211f6e1467dSArnaldo Carvalho de Melo continue; 1212f6e1467dSArnaldo Carvalho de Melo } 1213e30a3d12SArnaldo Carvalho de Melo if (filename__read_build_id(pos->long_name, pos->build_id, 1214e30a3d12SArnaldo Carvalho de Melo sizeof(pos->build_id)) > 0) { 1215e30a3d12SArnaldo Carvalho de Melo have_build_id = true; 1216e30a3d12SArnaldo Carvalho de Melo pos->has_build_id = true; 121757f395a7SFrederic Weisbecker } 12186122e4e4SArnaldo Carvalho de Melo } 121957f395a7SFrederic Weisbecker 1220e30a3d12SArnaldo Carvalho de Melo return have_build_id; 122157f395a7SFrederic Weisbecker } 122257f395a7SFrederic Weisbecker 1223fd7a346eSArnaldo Carvalho de Melo /* 1224fd7a346eSArnaldo Carvalho de Melo * Align offset to 4 bytes as needed for note name and descriptor data. 1225fd7a346eSArnaldo Carvalho de Melo */ 1226fd7a346eSArnaldo Carvalho de Melo #define NOTE_ALIGN(n) (((n) + 3) & -4U) 1227fd7a346eSArnaldo Carvalho de Melo 122821916c38SDave Martin static int elf_read_build_id(Elf *elf, void *bf, size_t size) 12294d1e00a8SArnaldo Carvalho de Melo { 123021916c38SDave Martin int err = -1; 12314d1e00a8SArnaldo Carvalho de Melo GElf_Ehdr ehdr; 12324d1e00a8SArnaldo Carvalho de Melo GElf_Shdr shdr; 1233fd7a346eSArnaldo Carvalho de Melo Elf_Data *data; 12344d1e00a8SArnaldo Carvalho de Melo Elf_Scn *sec; 1235e57cfcdaSPekka Enberg Elf_Kind ek; 1236fd7a346eSArnaldo Carvalho de Melo void *ptr; 12374d1e00a8SArnaldo Carvalho de Melo 12382643ce11SArnaldo Carvalho de Melo if (size < BUILD_ID_SIZE) 12392643ce11SArnaldo Carvalho de Melo goto out; 12402643ce11SArnaldo Carvalho de Melo 1241e57cfcdaSPekka Enberg ek = elf_kind(elf); 1242e57cfcdaSPekka Enberg if (ek != ELF_K_ELF) 124321916c38SDave Martin goto out; 1244e57cfcdaSPekka Enberg 12454d1e00a8SArnaldo Carvalho de Melo if (gelf_getehdr(elf, &ehdr) == NULL) { 12466beba7adSArnaldo Carvalho de Melo pr_err("%s: cannot get elf header.\n", __func__); 124721916c38SDave Martin goto out; 12484d1e00a8SArnaldo Carvalho de Melo } 12494d1e00a8SArnaldo Carvalho de Melo 12502643ce11SArnaldo Carvalho de Melo sec = elf_section_by_name(elf, &ehdr, &shdr, 12512643ce11SArnaldo Carvalho de Melo ".note.gnu.build-id", NULL); 1252fd7a346eSArnaldo Carvalho de Melo if (sec == NULL) { 1253fd7a346eSArnaldo Carvalho de Melo sec = elf_section_by_name(elf, &ehdr, &shdr, 1254fd7a346eSArnaldo Carvalho de Melo ".notes", NULL); 12554d1e00a8SArnaldo Carvalho de Melo if (sec == NULL) 125621916c38SDave Martin goto out; 1257fd7a346eSArnaldo Carvalho de Melo } 12584d1e00a8SArnaldo Carvalho de Melo 1259fd7a346eSArnaldo Carvalho de Melo data = elf_getdata(sec, NULL); 1260fd7a346eSArnaldo Carvalho de Melo if (data == NULL) 126121916c38SDave Martin goto out; 1262fd7a346eSArnaldo Carvalho de Melo 1263fd7a346eSArnaldo Carvalho de Melo ptr = data->d_buf; 1264fd7a346eSArnaldo Carvalho de Melo while (ptr < (data->d_buf + data->d_size)) { 1265fd7a346eSArnaldo Carvalho de Melo GElf_Nhdr *nhdr = ptr; 1266fd7a346eSArnaldo Carvalho de Melo int namesz = NOTE_ALIGN(nhdr->n_namesz), 1267fd7a346eSArnaldo Carvalho de Melo descsz = NOTE_ALIGN(nhdr->n_descsz); 1268fd7a346eSArnaldo Carvalho de Melo const char *name; 1269fd7a346eSArnaldo Carvalho de Melo 1270fd7a346eSArnaldo Carvalho de Melo ptr += sizeof(*nhdr); 1271fd7a346eSArnaldo Carvalho de Melo name = ptr; 1272fd7a346eSArnaldo Carvalho de Melo ptr += namesz; 1273fd7a346eSArnaldo Carvalho de Melo if (nhdr->n_type == NT_GNU_BUILD_ID && 1274fd7a346eSArnaldo Carvalho de Melo nhdr->n_namesz == sizeof("GNU")) { 1275fd7a346eSArnaldo Carvalho de Melo if (memcmp(name, "GNU", sizeof("GNU")) == 0) { 1276fd7a346eSArnaldo Carvalho de Melo memcpy(bf, ptr, BUILD_ID_SIZE); 12772643ce11SArnaldo Carvalho de Melo err = BUILD_ID_SIZE; 1278fd7a346eSArnaldo Carvalho de Melo break; 1279fd7a346eSArnaldo Carvalho de Melo } 1280fd7a346eSArnaldo Carvalho de Melo } 1281fd7a346eSArnaldo Carvalho de Melo ptr += descsz; 1282fd7a346eSArnaldo Carvalho de Melo } 128321916c38SDave Martin 128421916c38SDave Martin out: 128521916c38SDave Martin return err; 128621916c38SDave Martin } 128721916c38SDave Martin 128821916c38SDave Martin int filename__read_build_id(const char *filename, void *bf, size_t size) 128921916c38SDave Martin { 129021916c38SDave Martin int fd, err = -1; 129121916c38SDave Martin Elf *elf; 129221916c38SDave Martin 129321916c38SDave Martin if (size < BUILD_ID_SIZE) 129421916c38SDave Martin goto out; 129521916c38SDave Martin 129621916c38SDave Martin fd = open(filename, O_RDONLY); 129721916c38SDave Martin if (fd < 0) 129821916c38SDave Martin goto out; 129921916c38SDave Martin 130021916c38SDave Martin elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 130121916c38SDave Martin if (elf == NULL) { 130221916c38SDave Martin pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename); 130321916c38SDave Martin goto out_close; 130421916c38SDave Martin } 130521916c38SDave Martin 130621916c38SDave Martin err = elf_read_build_id(elf, bf, size); 130721916c38SDave Martin 13082643ce11SArnaldo Carvalho de Melo elf_end(elf); 13092643ce11SArnaldo Carvalho de Melo out_close: 13102643ce11SArnaldo Carvalho de Melo close(fd); 13112643ce11SArnaldo Carvalho de Melo out: 13122643ce11SArnaldo Carvalho de Melo return err; 13132643ce11SArnaldo Carvalho de Melo } 13142643ce11SArnaldo Carvalho de Melo 1315f1617b40SArnaldo Carvalho de Melo int sysfs__read_build_id(const char *filename, void *build_id, size_t size) 1316f1617b40SArnaldo Carvalho de Melo { 1317f1617b40SArnaldo Carvalho de Melo int fd, err = -1; 1318f1617b40SArnaldo Carvalho de Melo 1319f1617b40SArnaldo Carvalho de Melo if (size < BUILD_ID_SIZE) 1320f1617b40SArnaldo Carvalho de Melo goto out; 1321f1617b40SArnaldo Carvalho de Melo 1322f1617b40SArnaldo Carvalho de Melo fd = open(filename, O_RDONLY); 1323f1617b40SArnaldo Carvalho de Melo if (fd < 0) 1324f1617b40SArnaldo Carvalho de Melo goto out; 1325f1617b40SArnaldo Carvalho de Melo 1326f1617b40SArnaldo Carvalho de Melo while (1) { 1327f1617b40SArnaldo Carvalho de Melo char bf[BUFSIZ]; 1328f1617b40SArnaldo Carvalho de Melo GElf_Nhdr nhdr; 1329f1617b40SArnaldo Carvalho de Melo int namesz, descsz; 1330f1617b40SArnaldo Carvalho de Melo 1331f1617b40SArnaldo Carvalho de Melo if (read(fd, &nhdr, sizeof(nhdr)) != sizeof(nhdr)) 1332f1617b40SArnaldo Carvalho de Melo break; 1333f1617b40SArnaldo Carvalho de Melo 1334fd7a346eSArnaldo Carvalho de Melo namesz = NOTE_ALIGN(nhdr.n_namesz); 1335fd7a346eSArnaldo Carvalho de Melo descsz = NOTE_ALIGN(nhdr.n_descsz); 1336f1617b40SArnaldo Carvalho de Melo if (nhdr.n_type == NT_GNU_BUILD_ID && 1337f1617b40SArnaldo Carvalho de Melo nhdr.n_namesz == sizeof("GNU")) { 1338f1617b40SArnaldo Carvalho de Melo if (read(fd, bf, namesz) != namesz) 1339f1617b40SArnaldo Carvalho de Melo break; 1340f1617b40SArnaldo Carvalho de Melo if (memcmp(bf, "GNU", sizeof("GNU")) == 0) { 1341f1617b40SArnaldo Carvalho de Melo if (read(fd, build_id, 1342f1617b40SArnaldo Carvalho de Melo BUILD_ID_SIZE) == BUILD_ID_SIZE) { 1343f1617b40SArnaldo Carvalho de Melo err = 0; 1344f1617b40SArnaldo Carvalho de Melo break; 1345f1617b40SArnaldo Carvalho de Melo } 1346f1617b40SArnaldo Carvalho de Melo } else if (read(fd, bf, descsz) != descsz) 1347f1617b40SArnaldo Carvalho de Melo break; 1348f1617b40SArnaldo Carvalho de Melo } else { 1349f1617b40SArnaldo Carvalho de Melo int n = namesz + descsz; 1350f1617b40SArnaldo Carvalho de Melo if (read(fd, bf, n) != n) 1351f1617b40SArnaldo Carvalho de Melo break; 1352f1617b40SArnaldo Carvalho de Melo } 1353f1617b40SArnaldo Carvalho de Melo } 1354f1617b40SArnaldo Carvalho de Melo close(fd); 1355f1617b40SArnaldo Carvalho de Melo out: 1356f1617b40SArnaldo Carvalho de Melo return err; 1357f1617b40SArnaldo Carvalho de Melo } 1358f1617b40SArnaldo Carvalho de Melo 135994cb9e38SArnaldo Carvalho de Melo char dso__symtab_origin(const struct dso *self) 136094cb9e38SArnaldo Carvalho de Melo { 136194cb9e38SArnaldo Carvalho de Melo static const char origin[] = { 136294cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_KERNEL] = 'k', 136394cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_JAVA_JIT] = 'j', 13644cf40131SArnaldo Carvalho de Melo [DSO__ORIG_BUILD_ID_CACHE] = 'B', 136594cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_FEDORA] = 'f', 136694cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_UBUNTU] = 'u', 136794cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_BUILDID] = 'b', 136894cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_DSO] = 'd', 1369439d473bSArnaldo Carvalho de Melo [DSO__ORIG_KMODULE] = 'K', 1370a1645ce1SZhang, Yanmin [DSO__ORIG_GUEST_KERNEL] = 'g', 1371a1645ce1SZhang, Yanmin [DSO__ORIG_GUEST_KMODULE] = 'G', 137294cb9e38SArnaldo Carvalho de Melo }; 137394cb9e38SArnaldo Carvalho de Melo 137494cb9e38SArnaldo Carvalho de Melo if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND) 137594cb9e38SArnaldo Carvalho de Melo return '!'; 137694cb9e38SArnaldo Carvalho de Melo return origin[self->origin]; 137794cb9e38SArnaldo Carvalho de Melo } 137894cb9e38SArnaldo Carvalho de Melo 13799de89fe7SArnaldo Carvalho de Melo int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) 138086470930SIngo Molnar { 13814d1e00a8SArnaldo Carvalho de Melo int size = PATH_MAX; 1382c338aee8SArnaldo Carvalho de Melo char *name; 138386470930SIngo Molnar int ret = -1; 138486470930SIngo Molnar int fd; 138523346f21SArnaldo Carvalho de Melo struct machine *machine; 1386a1645ce1SZhang, Yanmin const char *root_dir; 13876da80ce8SDave Martin int want_symtab; 138886470930SIngo Molnar 13893610583cSArnaldo Carvalho de Melo dso__set_loaded(self, map->type); 139066bd8424SArnaldo Carvalho de Melo 1391a1645ce1SZhang, Yanmin if (self->kernel == DSO_TYPE_KERNEL) 13929de89fe7SArnaldo Carvalho de Melo return dso__load_kernel_sym(self, map, filter); 1393a1645ce1SZhang, Yanmin else if (self->kernel == DSO_TYPE_GUEST_KERNEL) 1394a1645ce1SZhang, Yanmin return dso__load_guest_kernel_sym(self, map, filter); 1395a1645ce1SZhang, Yanmin 139623346f21SArnaldo Carvalho de Melo if (map->groups && map->groups->machine) 139723346f21SArnaldo Carvalho de Melo machine = map->groups->machine; 1398a1645ce1SZhang, Yanmin else 139923346f21SArnaldo Carvalho de Melo machine = NULL; 1400c338aee8SArnaldo Carvalho de Melo 1401c338aee8SArnaldo Carvalho de Melo name = malloc(size); 140286470930SIngo Molnar if (!name) 140386470930SIngo Molnar return -1; 140486470930SIngo Molnar 140530d7a77dSArnaldo Carvalho de Melo self->adjust_symbols = 0; 1406f5812a7aSArnaldo Carvalho de Melo 140794cb9e38SArnaldo Carvalho de Melo if (strncmp(self->name, "/tmp/perf-", 10) == 0) { 14086beba7adSArnaldo Carvalho de Melo ret = dso__load_perf_map(self, map, filter); 140994cb9e38SArnaldo Carvalho de Melo self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT : 141094cb9e38SArnaldo Carvalho de Melo DSO__ORIG_NOT_FOUND; 141194cb9e38SArnaldo Carvalho de Melo return ret; 141294cb9e38SArnaldo Carvalho de Melo } 141394cb9e38SArnaldo Carvalho de Melo 14146da80ce8SDave Martin /* Iterate over candidate debug images. 14156da80ce8SDave Martin * On the first pass, only load images if they have a full symtab. 14166da80ce8SDave Martin * Failing that, do a second pass where we accept .dynsym also 14176da80ce8SDave Martin */ 14186da80ce8SDave Martin for (self->origin = DSO__ORIG_BUILD_ID_CACHE, want_symtab = 1; 14196da80ce8SDave Martin self->origin != DSO__ORIG_NOT_FOUND; 14206da80ce8SDave Martin self->origin++) { 142194cb9e38SArnaldo Carvalho de Melo switch (self->origin) { 14226da80ce8SDave Martin case DSO__ORIG_BUILD_ID_CACHE: 14236da80ce8SDave Martin if (dso__build_id_filename(self, name, size) == NULL) 14246da80ce8SDave Martin continue; 14256da80ce8SDave Martin break; 142694cb9e38SArnaldo Carvalho de Melo case DSO__ORIG_FEDORA: 1427439d473bSArnaldo Carvalho de Melo snprintf(name, size, "/usr/lib/debug%s.debug", 1428439d473bSArnaldo Carvalho de Melo self->long_name); 142986470930SIngo Molnar break; 143094cb9e38SArnaldo Carvalho de Melo case DSO__ORIG_UBUNTU: 1431439d473bSArnaldo Carvalho de Melo snprintf(name, size, "/usr/lib/debug%s", 1432439d473bSArnaldo Carvalho de Melo self->long_name); 143386470930SIngo Molnar break; 14346da80ce8SDave Martin case DSO__ORIG_BUILDID: { 1435b36f19d5SArnaldo Carvalho de Melo char build_id_hex[BUILD_ID_SIZE * 2 + 1]; 14366da80ce8SDave Martin 14376da80ce8SDave Martin if (!self->has_build_id) 14386da80ce8SDave Martin continue; 14396da80ce8SDave Martin 144021916c38SDave Martin build_id__sprintf(self->build_id, 144121916c38SDave Martin sizeof(self->build_id), 1442d3379ab9SArnaldo Carvalho de Melo build_id_hex); 14434d1e00a8SArnaldo Carvalho de Melo snprintf(name, size, 14444d1e00a8SArnaldo Carvalho de Melo "/usr/lib/debug/.build-id/%.2s/%s.debug", 1445d3379ab9SArnaldo Carvalho de Melo build_id_hex, build_id_hex + 2); 14464d1e00a8SArnaldo Carvalho de Melo } 14476da80ce8SDave Martin break; 144894cb9e38SArnaldo Carvalho de Melo case DSO__ORIG_DSO: 1449439d473bSArnaldo Carvalho de Melo snprintf(name, size, "%s", self->long_name); 145086470930SIngo Molnar break; 1451a1645ce1SZhang, Yanmin case DSO__ORIG_GUEST_KMODULE: 145223346f21SArnaldo Carvalho de Melo if (map->groups && map->groups->machine) 145323346f21SArnaldo Carvalho de Melo root_dir = map->groups->machine->root_dir; 1454a1645ce1SZhang, Yanmin else 1455a1645ce1SZhang, Yanmin root_dir = ""; 1456a1645ce1SZhang, Yanmin snprintf(name, size, "%s%s", root_dir, self->long_name); 1457a1645ce1SZhang, Yanmin break; 145886470930SIngo Molnar 145986470930SIngo Molnar default: 14606da80ce8SDave Martin /* 14616da80ce8SDave Martin * If we wanted a full symtab but no image had one, 14626da80ce8SDave Martin * relax our requirements and repeat the search. 14636da80ce8SDave Martin */ 14646da80ce8SDave Martin if (want_symtab) { 14656da80ce8SDave Martin want_symtab = 0; 14666da80ce8SDave Martin self->origin = DSO__ORIG_BUILD_ID_CACHE; 14676da80ce8SDave Martin } else 14686da80ce8SDave Martin continue; 146986470930SIngo Molnar } 147086470930SIngo Molnar 14716da80ce8SDave Martin /* Name is now the name of the next image to try */ 14726da80ce8SDave Martin fd = open(name, O_RDONLY); 14736da80ce8SDave Martin if (fd < 0) 14746da80ce8SDave Martin continue; 14756da80ce8SDave Martin 14766da80ce8SDave Martin ret = dso__load_sym(self, map, name, fd, filter, 0, 14776da80ce8SDave Martin want_symtab); 147886470930SIngo Molnar close(fd); 147986470930SIngo Molnar 148086470930SIngo Molnar /* 14816da80ce8SDave Martin * Some people seem to have debuginfo files _WITHOUT_ debug 14826da80ce8SDave Martin * info!?!? 148386470930SIngo Molnar */ 148486470930SIngo Molnar if (!ret) 14856da80ce8SDave Martin continue; 148686470930SIngo Molnar 1487a25e46c4SArnaldo Carvalho de Melo if (ret > 0) { 148882164161SArnaldo Carvalho de Melo int nr_plt = dso__synthesize_plt_symbols(self, map, filter); 1489a25e46c4SArnaldo Carvalho de Melo if (nr_plt > 0) 1490a25e46c4SArnaldo Carvalho de Melo ret += nr_plt; 14916da80ce8SDave Martin break; 1492a25e46c4SArnaldo Carvalho de Melo } 14936da80ce8SDave Martin } 14946da80ce8SDave Martin 149586470930SIngo Molnar free(name); 14961340e6bbSArnaldo Carvalho de Melo if (ret < 0 && strstr(self->name, " (deleted)") != NULL) 14971340e6bbSArnaldo Carvalho de Melo return 0; 149886470930SIngo Molnar return ret; 149986470930SIngo Molnar } 150086470930SIngo Molnar 150179406cd7SArnaldo Carvalho de Melo struct map *map_groups__find_by_name(struct map_groups *self, 150279406cd7SArnaldo Carvalho de Melo enum map_type type, const char *name) 1503439d473bSArnaldo Carvalho de Melo { 1504439d473bSArnaldo Carvalho de Melo struct rb_node *nd; 1505439d473bSArnaldo Carvalho de Melo 150679406cd7SArnaldo Carvalho de Melo for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) { 1507439d473bSArnaldo Carvalho de Melo struct map *map = rb_entry(nd, struct map, rb_node); 1508439d473bSArnaldo Carvalho de Melo 1509b7cece76SArnaldo Carvalho de Melo if (map->dso && strcmp(map->dso->short_name, name) == 0) 1510439d473bSArnaldo Carvalho de Melo return map; 1511439d473bSArnaldo Carvalho de Melo } 1512439d473bSArnaldo Carvalho de Melo 1513439d473bSArnaldo Carvalho de Melo return NULL; 1514439d473bSArnaldo Carvalho de Melo } 1515439d473bSArnaldo Carvalho de Melo 1516a1645ce1SZhang, Yanmin static int dso__kernel_module_get_build_id(struct dso *self, 1517a1645ce1SZhang, Yanmin const char *root_dir) 1518b7cece76SArnaldo Carvalho de Melo { 1519b7cece76SArnaldo Carvalho de Melo char filename[PATH_MAX]; 1520b7cece76SArnaldo Carvalho de Melo /* 1521b7cece76SArnaldo Carvalho de Melo * kernel module short names are of the form "[module]" and 1522b7cece76SArnaldo Carvalho de Melo * we need just "module" here. 1523b7cece76SArnaldo Carvalho de Melo */ 1524b7cece76SArnaldo Carvalho de Melo const char *name = self->short_name + 1; 1525b7cece76SArnaldo Carvalho de Melo 1526b7cece76SArnaldo Carvalho de Melo snprintf(filename, sizeof(filename), 1527a1645ce1SZhang, Yanmin "%s/sys/module/%.*s/notes/.note.gnu.build-id", 1528a1645ce1SZhang, Yanmin root_dir, (int)strlen(name) - 1, name); 1529b7cece76SArnaldo Carvalho de Melo 1530b7cece76SArnaldo Carvalho de Melo if (sysfs__read_build_id(filename, self->build_id, 1531b7cece76SArnaldo Carvalho de Melo sizeof(self->build_id)) == 0) 1532b7cece76SArnaldo Carvalho de Melo self->has_build_id = true; 1533b7cece76SArnaldo Carvalho de Melo 1534b7cece76SArnaldo Carvalho de Melo return 0; 1535b7cece76SArnaldo Carvalho de Melo } 1536b7cece76SArnaldo Carvalho de Melo 1537a1645ce1SZhang, Yanmin static int map_groups__set_modules_path_dir(struct map_groups *self, 1538a1645ce1SZhang, Yanmin const char *dir_name) 15396cfcc53eSMike Galbraith { 1540439d473bSArnaldo Carvalho de Melo struct dirent *dent; 15415aab621bSArnaldo Carvalho de Melo DIR *dir = opendir(dir_name); 154274534341SGui Jianfeng int ret = 0; 15436cfcc53eSMike Galbraith 1544439d473bSArnaldo Carvalho de Melo if (!dir) { 15455aab621bSArnaldo Carvalho de Melo pr_debug("%s: cannot open %s dir\n", __func__, dir_name); 1546439d473bSArnaldo Carvalho de Melo return -1; 1547439d473bSArnaldo Carvalho de Melo } 15486cfcc53eSMike Galbraith 1549439d473bSArnaldo Carvalho de Melo while ((dent = readdir(dir)) != NULL) { 1550439d473bSArnaldo Carvalho de Melo char path[PATH_MAX]; 1551a1645ce1SZhang, Yanmin struct stat st; 1552439d473bSArnaldo Carvalho de Melo 1553a1645ce1SZhang, Yanmin /*sshfs might return bad dent->d_type, so we have to stat*/ 1554a1645ce1SZhang, Yanmin sprintf(path, "%s/%s", dir_name, dent->d_name); 1555a1645ce1SZhang, Yanmin if (stat(path, &st)) 1556a1645ce1SZhang, Yanmin continue; 1557a1645ce1SZhang, Yanmin 1558a1645ce1SZhang, Yanmin if (S_ISDIR(st.st_mode)) { 1559439d473bSArnaldo Carvalho de Melo if (!strcmp(dent->d_name, ".") || 1560439d473bSArnaldo Carvalho de Melo !strcmp(dent->d_name, "..")) 1561439d473bSArnaldo Carvalho de Melo continue; 1562439d473bSArnaldo Carvalho de Melo 1563439d473bSArnaldo Carvalho de Melo snprintf(path, sizeof(path), "%s/%s", 15645aab621bSArnaldo Carvalho de Melo dir_name, dent->d_name); 156574534341SGui Jianfeng ret = map_groups__set_modules_path_dir(self, path); 156674534341SGui Jianfeng if (ret < 0) 156774534341SGui Jianfeng goto out; 1568439d473bSArnaldo Carvalho de Melo } else { 1569439d473bSArnaldo Carvalho de Melo char *dot = strrchr(dent->d_name, '.'), 1570439d473bSArnaldo Carvalho de Melo dso_name[PATH_MAX]; 1571439d473bSArnaldo Carvalho de Melo struct map *map; 1572cfc10d3bSArnaldo Carvalho de Melo char *long_name; 1573439d473bSArnaldo Carvalho de Melo 1574439d473bSArnaldo Carvalho de Melo if (dot == NULL || strcmp(dot, ".ko")) 1575439d473bSArnaldo Carvalho de Melo continue; 1576439d473bSArnaldo Carvalho de Melo snprintf(dso_name, sizeof(dso_name), "[%.*s]", 1577439d473bSArnaldo Carvalho de Melo (int)(dot - dent->d_name), dent->d_name); 1578439d473bSArnaldo Carvalho de Melo 1579a2a99e8eSArnaldo Carvalho de Melo strxfrchar(dso_name, '-', '_'); 15809de89fe7SArnaldo Carvalho de Melo map = map_groups__find_by_name(self, MAP__FUNCTION, dso_name); 1581439d473bSArnaldo Carvalho de Melo if (map == NULL) 1582439d473bSArnaldo Carvalho de Melo continue; 1583439d473bSArnaldo Carvalho de Melo 1584439d473bSArnaldo Carvalho de Melo snprintf(path, sizeof(path), "%s/%s", 15855aab621bSArnaldo Carvalho de Melo dir_name, dent->d_name); 1586439d473bSArnaldo Carvalho de Melo 1587cfc10d3bSArnaldo Carvalho de Melo long_name = strdup(path); 158874534341SGui Jianfeng if (long_name == NULL) { 158974534341SGui Jianfeng ret = -1; 159074534341SGui Jianfeng goto out; 159174534341SGui Jianfeng } 1592cfc10d3bSArnaldo Carvalho de Melo dso__set_long_name(map->dso, long_name); 15936e406257SArnaldo Carvalho de Melo map->dso->lname_alloc = 1; 1594a1645ce1SZhang, Yanmin dso__kernel_module_get_build_id(map->dso, ""); 1595439d473bSArnaldo Carvalho de Melo } 1596439d473bSArnaldo Carvalho de Melo } 1597439d473bSArnaldo Carvalho de Melo 159874534341SGui Jianfeng out: 1599439d473bSArnaldo Carvalho de Melo closedir(dir); 160074534341SGui Jianfeng return ret; 1601439d473bSArnaldo Carvalho de Melo } 1602439d473bSArnaldo Carvalho de Melo 1603a1645ce1SZhang, Yanmin static char *get_kernel_version(const char *root_dir) 1604439d473bSArnaldo Carvalho de Melo { 1605a1645ce1SZhang, Yanmin char version[PATH_MAX]; 1606a1645ce1SZhang, Yanmin FILE *file; 1607a1645ce1SZhang, Yanmin char *name, *tmp; 1608a1645ce1SZhang, Yanmin const char *prefix = "Linux version "; 1609a1645ce1SZhang, Yanmin 1610a1645ce1SZhang, Yanmin sprintf(version, "%s/proc/version", root_dir); 1611a1645ce1SZhang, Yanmin file = fopen(version, "r"); 1612a1645ce1SZhang, Yanmin if (!file) 1613a1645ce1SZhang, Yanmin return NULL; 1614a1645ce1SZhang, Yanmin 1615a1645ce1SZhang, Yanmin version[0] = '\0'; 1616a1645ce1SZhang, Yanmin tmp = fgets(version, sizeof(version), file); 1617a1645ce1SZhang, Yanmin fclose(file); 1618a1645ce1SZhang, Yanmin 1619a1645ce1SZhang, Yanmin name = strstr(version, prefix); 1620a1645ce1SZhang, Yanmin if (!name) 1621a1645ce1SZhang, Yanmin return NULL; 1622a1645ce1SZhang, Yanmin name += strlen(prefix); 1623a1645ce1SZhang, Yanmin tmp = strchr(name, ' '); 1624a1645ce1SZhang, Yanmin if (tmp) 1625a1645ce1SZhang, Yanmin *tmp = '\0'; 1626a1645ce1SZhang, Yanmin 1627a1645ce1SZhang, Yanmin return strdup(name); 1628a1645ce1SZhang, Yanmin } 1629a1645ce1SZhang, Yanmin 1630d28c6223SArnaldo Carvalho de Melo static int machine__set_modules_path(struct machine *self) 1631a1645ce1SZhang, Yanmin { 1632a1645ce1SZhang, Yanmin char *version; 1633439d473bSArnaldo Carvalho de Melo char modules_path[PATH_MAX]; 1634439d473bSArnaldo Carvalho de Melo 1635d28c6223SArnaldo Carvalho de Melo version = get_kernel_version(self->root_dir); 1636a1645ce1SZhang, Yanmin if (!version) 1637439d473bSArnaldo Carvalho de Melo return -1; 1638439d473bSArnaldo Carvalho de Melo 1639a1645ce1SZhang, Yanmin snprintf(modules_path, sizeof(modules_path), "%s/lib/modules/%s/kernel", 1640d28c6223SArnaldo Carvalho de Melo self->root_dir, version); 1641a1645ce1SZhang, Yanmin free(version); 1642439d473bSArnaldo Carvalho de Melo 1643d28c6223SArnaldo Carvalho de Melo return map_groups__set_modules_path_dir(&self->kmaps, modules_path); 1644439d473bSArnaldo Carvalho de Melo } 16456cfcc53eSMike Galbraith 16466cfcc53eSMike Galbraith /* 1647439d473bSArnaldo Carvalho de Melo * Constructor variant for modules (where we know from /proc/modules where 1648439d473bSArnaldo Carvalho de Melo * they are loaded) and for vmlinux, where only after we load all the 1649439d473bSArnaldo Carvalho de Melo * symbols we'll know where it starts and ends. 16506cfcc53eSMike Galbraith */ 16513610583cSArnaldo Carvalho de Melo static struct map *map__new2(u64 start, struct dso *dso, enum map_type type) 1652439d473bSArnaldo Carvalho de Melo { 16535aab621bSArnaldo Carvalho de Melo struct map *self = calloc(1, (sizeof(*self) + 16545aab621bSArnaldo Carvalho de Melo (dso->kernel ? sizeof(struct kmap) : 0))); 1655439d473bSArnaldo Carvalho de Melo if (self != NULL) { 1656439d473bSArnaldo Carvalho de Melo /* 1657afb7b4f0SArnaldo Carvalho de Melo * ->end will be filled after we load all the symbols 1658439d473bSArnaldo Carvalho de Melo */ 16593610583cSArnaldo Carvalho de Melo map__init(self, type, start, 0, 0, dso); 1660439d473bSArnaldo Carvalho de Melo } 1661afb7b4f0SArnaldo Carvalho de Melo 1662439d473bSArnaldo Carvalho de Melo return self; 1663439d473bSArnaldo Carvalho de Melo } 1664439d473bSArnaldo Carvalho de Melo 1665d28c6223SArnaldo Carvalho de Melo struct map *machine__new_module(struct machine *self, u64 start, 1666d28c6223SArnaldo Carvalho de Melo const char *filename) 1667b7cece76SArnaldo Carvalho de Melo { 1668b7cece76SArnaldo Carvalho de Melo struct map *map; 1669d28c6223SArnaldo Carvalho de Melo struct dso *dso = __dsos__findnew(&self->kernel_dsos, filename); 1670b7cece76SArnaldo Carvalho de Melo 1671b7cece76SArnaldo Carvalho de Melo if (dso == NULL) 1672b7cece76SArnaldo Carvalho de Melo return NULL; 1673b7cece76SArnaldo Carvalho de Melo 1674b7cece76SArnaldo Carvalho de Melo map = map__new2(start, dso, MAP__FUNCTION); 1675b7cece76SArnaldo Carvalho de Melo if (map == NULL) 1676b7cece76SArnaldo Carvalho de Melo return NULL; 1677b7cece76SArnaldo Carvalho de Melo 1678d28c6223SArnaldo Carvalho de Melo if (machine__is_host(self)) 1679b7cece76SArnaldo Carvalho de Melo dso->origin = DSO__ORIG_KMODULE; 1680a1645ce1SZhang, Yanmin else 1681a1645ce1SZhang, Yanmin dso->origin = DSO__ORIG_GUEST_KMODULE; 1682d28c6223SArnaldo Carvalho de Melo map_groups__insert(&self->kmaps, map); 1683b7cece76SArnaldo Carvalho de Melo return map; 1684b7cece76SArnaldo Carvalho de Melo } 1685b7cece76SArnaldo Carvalho de Melo 1686d28c6223SArnaldo Carvalho de Melo static int machine__create_modules(struct machine *self) 1687439d473bSArnaldo Carvalho de Melo { 1688439d473bSArnaldo Carvalho de Melo char *line = NULL; 1689439d473bSArnaldo Carvalho de Melo size_t n; 1690a1645ce1SZhang, Yanmin FILE *file; 1691439d473bSArnaldo Carvalho de Melo struct map *map; 1692a1645ce1SZhang, Yanmin const char *modules; 1693a1645ce1SZhang, Yanmin char path[PATH_MAX]; 1694439d473bSArnaldo Carvalho de Melo 1695d28c6223SArnaldo Carvalho de Melo if (machine__is_default_guest(self)) 1696a1645ce1SZhang, Yanmin modules = symbol_conf.default_guest_modules; 1697a1645ce1SZhang, Yanmin else { 1698d28c6223SArnaldo Carvalho de Melo sprintf(path, "%s/proc/modules", self->root_dir); 1699a1645ce1SZhang, Yanmin modules = path; 1700a1645ce1SZhang, Yanmin } 1701a1645ce1SZhang, Yanmin 1702a1645ce1SZhang, Yanmin file = fopen(modules, "r"); 1703439d473bSArnaldo Carvalho de Melo if (file == NULL) 1704439d473bSArnaldo Carvalho de Melo return -1; 1705439d473bSArnaldo Carvalho de Melo 1706439d473bSArnaldo Carvalho de Melo while (!feof(file)) { 1707439d473bSArnaldo Carvalho de Melo char name[PATH_MAX]; 1708439d473bSArnaldo Carvalho de Melo u64 start; 1709439d473bSArnaldo Carvalho de Melo char *sep; 1710439d473bSArnaldo Carvalho de Melo int line_len; 1711439d473bSArnaldo Carvalho de Melo 1712439d473bSArnaldo Carvalho de Melo line_len = getline(&line, &n, file); 1713439d473bSArnaldo Carvalho de Melo if (line_len < 0) 17146cfcc53eSMike Galbraith break; 17156cfcc53eSMike Galbraith 1716439d473bSArnaldo Carvalho de Melo if (!line) 1717439d473bSArnaldo Carvalho de Melo goto out_failure; 1718439d473bSArnaldo Carvalho de Melo 1719439d473bSArnaldo Carvalho de Melo line[--line_len] = '\0'; /* \n */ 1720439d473bSArnaldo Carvalho de Melo 1721439d473bSArnaldo Carvalho de Melo sep = strrchr(line, 'x'); 1722439d473bSArnaldo Carvalho de Melo if (sep == NULL) 1723439d473bSArnaldo Carvalho de Melo continue; 1724439d473bSArnaldo Carvalho de Melo 1725439d473bSArnaldo Carvalho de Melo hex2u64(sep + 1, &start); 1726439d473bSArnaldo Carvalho de Melo 1727439d473bSArnaldo Carvalho de Melo sep = strchr(line, ' '); 1728439d473bSArnaldo Carvalho de Melo if (sep == NULL) 1729439d473bSArnaldo Carvalho de Melo continue; 1730439d473bSArnaldo Carvalho de Melo 1731439d473bSArnaldo Carvalho de Melo *sep = '\0'; 1732439d473bSArnaldo Carvalho de Melo 1733439d473bSArnaldo Carvalho de Melo snprintf(name, sizeof(name), "[%s]", line); 1734d28c6223SArnaldo Carvalho de Melo map = machine__new_module(self, start, name); 1735b7cece76SArnaldo Carvalho de Melo if (map == NULL) 1736439d473bSArnaldo Carvalho de Melo goto out_delete_line; 1737d28c6223SArnaldo Carvalho de Melo dso__kernel_module_get_build_id(map->dso, self->root_dir); 17386cfcc53eSMike Galbraith } 17396cfcc53eSMike Galbraith 1740439d473bSArnaldo Carvalho de Melo free(line); 1741439d473bSArnaldo Carvalho de Melo fclose(file); 1742439d473bSArnaldo Carvalho de Melo 1743d28c6223SArnaldo Carvalho de Melo return machine__set_modules_path(self); 1744439d473bSArnaldo Carvalho de Melo 1745439d473bSArnaldo Carvalho de Melo out_delete_line: 1746439d473bSArnaldo Carvalho de Melo free(line); 1747439d473bSArnaldo Carvalho de Melo out_failure: 1748439d473bSArnaldo Carvalho de Melo return -1; 17496cfcc53eSMike Galbraith } 17506cfcc53eSMike Galbraith 17519958e1f0SArnaldo Carvalho de Melo static int dso__load_vmlinux(struct dso *self, struct map *map, 17526beba7adSArnaldo Carvalho de Melo const char *vmlinux, symbol_filter_t filter) 175386470930SIngo Molnar { 1754fbd733b8SArnaldo Carvalho de Melo int err = -1, fd; 175586470930SIngo Molnar 1756fbd733b8SArnaldo Carvalho de Melo fd = open(vmlinux, O_RDONLY); 175786470930SIngo Molnar if (fd < 0) 175886470930SIngo Molnar return -1; 175986470930SIngo Molnar 17603610583cSArnaldo Carvalho de Melo dso__set_loaded(self, map->type); 17616da80ce8SDave Martin err = dso__load_sym(self, map, vmlinux, fd, filter, 0, 0); 176286470930SIngo Molnar close(fd); 176386470930SIngo Molnar 17643846df2eSArnaldo Carvalho de Melo if (err > 0) 17653846df2eSArnaldo Carvalho de Melo pr_debug("Using %s for symbols\n", vmlinux); 17663846df2eSArnaldo Carvalho de Melo 176786470930SIngo Molnar return err; 176886470930SIngo Molnar } 176986470930SIngo Molnar 1770a19afe46SArnaldo Carvalho de Melo int dso__load_vmlinux_path(struct dso *self, struct map *map, 17719de89fe7SArnaldo Carvalho de Melo symbol_filter_t filter) 1772a19afe46SArnaldo Carvalho de Melo { 1773a19afe46SArnaldo Carvalho de Melo int i, err = 0; 17745ad90e4eSArnaldo Carvalho de Melo char *filename; 1775a19afe46SArnaldo Carvalho de Melo 1776a19afe46SArnaldo Carvalho de Melo pr_debug("Looking at the vmlinux_path (%d entries long)\n", 17775ad90e4eSArnaldo Carvalho de Melo vmlinux_path__nr_entries + 1); 17785ad90e4eSArnaldo Carvalho de Melo 17795ad90e4eSArnaldo Carvalho de Melo filename = dso__build_id_filename(self, NULL, 0); 17805ad90e4eSArnaldo Carvalho de Melo if (filename != NULL) { 17815ad90e4eSArnaldo Carvalho de Melo err = dso__load_vmlinux(self, map, filename, filter); 17825ad90e4eSArnaldo Carvalho de Melo if (err > 0) { 17835ad90e4eSArnaldo Carvalho de Melo dso__set_long_name(self, filename); 17845ad90e4eSArnaldo Carvalho de Melo goto out; 17855ad90e4eSArnaldo Carvalho de Melo } 17865ad90e4eSArnaldo Carvalho de Melo free(filename); 17875ad90e4eSArnaldo Carvalho de Melo } 1788a19afe46SArnaldo Carvalho de Melo 1789a19afe46SArnaldo Carvalho de Melo for (i = 0; i < vmlinux_path__nr_entries; ++i) { 17909de89fe7SArnaldo Carvalho de Melo err = dso__load_vmlinux(self, map, vmlinux_path[i], filter); 1791a19afe46SArnaldo Carvalho de Melo if (err > 0) { 1792a19afe46SArnaldo Carvalho de Melo dso__set_long_name(self, strdup(vmlinux_path[i])); 1793a19afe46SArnaldo Carvalho de Melo break; 1794a19afe46SArnaldo Carvalho de Melo } 1795a19afe46SArnaldo Carvalho de Melo } 17965ad90e4eSArnaldo Carvalho de Melo out: 1797a19afe46SArnaldo Carvalho de Melo return err; 1798a19afe46SArnaldo Carvalho de Melo } 1799a19afe46SArnaldo Carvalho de Melo 1800c338aee8SArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *self, struct map *map, 18019de89fe7SArnaldo Carvalho de Melo symbol_filter_t filter) 180286470930SIngo Molnar { 1803cc612d81SArnaldo Carvalho de Melo int err; 18049e201442SArnaldo Carvalho de Melo const char *kallsyms_filename = NULL; 18059e201442SArnaldo Carvalho de Melo char *kallsyms_allocated_filename = NULL; 1806dc8d6ab2SArnaldo Carvalho de Melo /* 1807dc8d6ab2SArnaldo Carvalho de Melo * Step 1: if the user specified a vmlinux filename, use it and only 1808dc8d6ab2SArnaldo Carvalho de Melo * it, reporting errors to the user if it cannot be used. 1809dc8d6ab2SArnaldo Carvalho de Melo * 1810dc8d6ab2SArnaldo Carvalho de Melo * For instance, try to analyse an ARM perf.data file _without_ a 1811dc8d6ab2SArnaldo Carvalho de Melo * build-id, or if the user specifies the wrong path to the right 1812dc8d6ab2SArnaldo Carvalho de Melo * vmlinux file, obviously we can't fallback to another vmlinux (a 1813dc8d6ab2SArnaldo Carvalho de Melo * x86_86 one, on the machine where analysis is being performed, say), 1814dc8d6ab2SArnaldo Carvalho de Melo * or worse, /proc/kallsyms. 1815dc8d6ab2SArnaldo Carvalho de Melo * 1816dc8d6ab2SArnaldo Carvalho de Melo * If the specified file _has_ a build-id and there is a build-id 1817dc8d6ab2SArnaldo Carvalho de Melo * section in the perf.data file, we will still do the expected 1818dc8d6ab2SArnaldo Carvalho de Melo * validation in dso__load_vmlinux and will bail out if they don't 1819dc8d6ab2SArnaldo Carvalho de Melo * match. 1820dc8d6ab2SArnaldo Carvalho de Melo */ 1821dc8d6ab2SArnaldo Carvalho de Melo if (symbol_conf.vmlinux_name != NULL) { 18229de89fe7SArnaldo Carvalho de Melo err = dso__load_vmlinux(self, map, 1823dc8d6ab2SArnaldo Carvalho de Melo symbol_conf.vmlinux_name, filter); 1824e7dadc00SArnaldo Carvalho de Melo if (err > 0) { 1825e7dadc00SArnaldo Carvalho de Melo dso__set_long_name(self, 1826e7dadc00SArnaldo Carvalho de Melo strdup(symbol_conf.vmlinux_name)); 1827e7dadc00SArnaldo Carvalho de Melo goto out_fixup; 1828e7dadc00SArnaldo Carvalho de Melo } 1829e7dadc00SArnaldo Carvalho de Melo return err; 1830dc8d6ab2SArnaldo Carvalho de Melo } 1831439d473bSArnaldo Carvalho de Melo 1832cc612d81SArnaldo Carvalho de Melo if (vmlinux_path != NULL) { 18339de89fe7SArnaldo Carvalho de Melo err = dso__load_vmlinux_path(self, map, filter); 1834a19afe46SArnaldo Carvalho de Melo if (err > 0) 1835cc612d81SArnaldo Carvalho de Melo goto out_fixup; 1836cc612d81SArnaldo Carvalho de Melo } 1837cc612d81SArnaldo Carvalho de Melo 1838b7cece76SArnaldo Carvalho de Melo /* 1839b7cece76SArnaldo Carvalho de Melo * Say the kernel DSO was created when processing the build-id header table, 1840b7cece76SArnaldo Carvalho de Melo * we have a build-id, so check if it is the same as the running kernel, 1841b7cece76SArnaldo Carvalho de Melo * using it if it is. 1842b7cece76SArnaldo Carvalho de Melo */ 1843b7cece76SArnaldo Carvalho de Melo if (self->has_build_id) { 1844b7cece76SArnaldo Carvalho de Melo u8 kallsyms_build_id[BUILD_ID_SIZE]; 18459e201442SArnaldo Carvalho de Melo char sbuild_id[BUILD_ID_SIZE * 2 + 1]; 1846b7cece76SArnaldo Carvalho de Melo 1847b7cece76SArnaldo Carvalho de Melo if (sysfs__read_build_id("/sys/kernel/notes", kallsyms_build_id, 18488d0591f6SArnaldo Carvalho de Melo sizeof(kallsyms_build_id)) == 0) { 18499e201442SArnaldo Carvalho de Melo if (dso__build_id_equal(self, kallsyms_build_id)) { 18509e201442SArnaldo Carvalho de Melo kallsyms_filename = "/proc/kallsyms"; 1851b7cece76SArnaldo Carvalho de Melo goto do_kallsyms; 18528d0591f6SArnaldo Carvalho de Melo } 18539e201442SArnaldo Carvalho de Melo } 1854dc8d6ab2SArnaldo Carvalho de Melo /* 1855dc8d6ab2SArnaldo Carvalho de Melo * Now look if we have it on the build-id cache in 1856dc8d6ab2SArnaldo Carvalho de Melo * $HOME/.debug/[kernel.kallsyms]. 1857dc8d6ab2SArnaldo Carvalho de Melo */ 18589e201442SArnaldo Carvalho de Melo build_id__sprintf(self->build_id, sizeof(self->build_id), 18599e201442SArnaldo Carvalho de Melo sbuild_id); 18609e201442SArnaldo Carvalho de Melo 18619e201442SArnaldo Carvalho de Melo if (asprintf(&kallsyms_allocated_filename, 18629e201442SArnaldo Carvalho de Melo "%s/.debug/[kernel.kallsyms]/%s", 18633846df2eSArnaldo Carvalho de Melo getenv("HOME"), sbuild_id) == -1) { 18643846df2eSArnaldo Carvalho de Melo pr_err("Not enough memory for kallsyms file lookup\n"); 18658d0591f6SArnaldo Carvalho de Melo return -1; 18663846df2eSArnaldo Carvalho de Melo } 18678d0591f6SArnaldo Carvalho de Melo 186819fc2dedSArnaldo Carvalho de Melo kallsyms_filename = kallsyms_allocated_filename; 186919fc2dedSArnaldo Carvalho de Melo 1870dc8d6ab2SArnaldo Carvalho de Melo if (access(kallsyms_filename, F_OK)) { 18713846df2eSArnaldo Carvalho de Melo pr_err("No kallsyms or vmlinux with build-id %s " 18723846df2eSArnaldo Carvalho de Melo "was found\n", sbuild_id); 18739e201442SArnaldo Carvalho de Melo free(kallsyms_allocated_filename); 1874dc8d6ab2SArnaldo Carvalho de Melo return -1; 1875ef6ae724SArnaldo Carvalho de Melo } 1876dc8d6ab2SArnaldo Carvalho de Melo } else { 1877dc8d6ab2SArnaldo Carvalho de Melo /* 1878dc8d6ab2SArnaldo Carvalho de Melo * Last resort, if we don't have a build-id and couldn't find 1879dc8d6ab2SArnaldo Carvalho de Melo * any vmlinux file, try the running kernel kallsyms table. 1880dc8d6ab2SArnaldo Carvalho de Melo */ 1881dc8d6ab2SArnaldo Carvalho de Melo kallsyms_filename = "/proc/kallsyms"; 1882dc8d6ab2SArnaldo Carvalho de Melo } 1883dc8d6ab2SArnaldo Carvalho de Melo 1884dc8d6ab2SArnaldo Carvalho de Melo do_kallsyms: 18859de89fe7SArnaldo Carvalho de Melo err = dso__load_kallsyms(self, kallsyms_filename, map, filter); 18863846df2eSArnaldo Carvalho de Melo if (err > 0) 18873846df2eSArnaldo Carvalho de Melo pr_debug("Using %s for symbols\n", kallsyms_filename); 1888dc8d6ab2SArnaldo Carvalho de Melo free(kallsyms_allocated_filename); 1889dc8d6ab2SArnaldo Carvalho de Melo 1890439d473bSArnaldo Carvalho de Melo if (err > 0) { 1891cc612d81SArnaldo Carvalho de Melo out_fixup: 1892e1c7c6a4SArnaldo Carvalho de Melo if (kallsyms_filename != NULL) 1893dc8d6ab2SArnaldo Carvalho de Melo dso__set_long_name(self, strdup("[kernel.kallsyms]")); 18946a4694a4SArnaldo Carvalho de Melo map__fixup_start(map); 18956a4694a4SArnaldo Carvalho de Melo map__fixup_end(map); 1896439d473bSArnaldo Carvalho de Melo } 189794cb9e38SArnaldo Carvalho de Melo 189886470930SIngo Molnar return err; 189986470930SIngo Molnar } 190086470930SIngo Molnar 1901a1645ce1SZhang, Yanmin static int dso__load_guest_kernel_sym(struct dso *self, struct map *map, 1902a1645ce1SZhang, Yanmin symbol_filter_t filter) 1903a1645ce1SZhang, Yanmin { 1904a1645ce1SZhang, Yanmin int err; 1905a1645ce1SZhang, Yanmin const char *kallsyms_filename = NULL; 190623346f21SArnaldo Carvalho de Melo struct machine *machine; 1907a1645ce1SZhang, Yanmin char path[PATH_MAX]; 1908a1645ce1SZhang, Yanmin 1909a1645ce1SZhang, Yanmin if (!map->groups) { 1910a1645ce1SZhang, Yanmin pr_debug("Guest kernel map hasn't the point to groups\n"); 1911a1645ce1SZhang, Yanmin return -1; 1912a1645ce1SZhang, Yanmin } 191323346f21SArnaldo Carvalho de Melo machine = map->groups->machine; 1914a1645ce1SZhang, Yanmin 191523346f21SArnaldo Carvalho de Melo if (machine__is_default_guest(machine)) { 1916a1645ce1SZhang, Yanmin /* 1917a1645ce1SZhang, Yanmin * if the user specified a vmlinux filename, use it and only 1918a1645ce1SZhang, Yanmin * it, reporting errors to the user if it cannot be used. 1919a1645ce1SZhang, Yanmin * Or use file guest_kallsyms inputted by user on commandline 1920a1645ce1SZhang, Yanmin */ 1921a1645ce1SZhang, Yanmin if (symbol_conf.default_guest_vmlinux_name != NULL) { 1922a1645ce1SZhang, Yanmin err = dso__load_vmlinux(self, map, 1923a1645ce1SZhang, Yanmin symbol_conf.default_guest_vmlinux_name, filter); 1924a1645ce1SZhang, Yanmin goto out_try_fixup; 1925a1645ce1SZhang, Yanmin } 1926a1645ce1SZhang, Yanmin 1927a1645ce1SZhang, Yanmin kallsyms_filename = symbol_conf.default_guest_kallsyms; 1928a1645ce1SZhang, Yanmin if (!kallsyms_filename) 1929a1645ce1SZhang, Yanmin return -1; 1930a1645ce1SZhang, Yanmin } else { 193123346f21SArnaldo Carvalho de Melo sprintf(path, "%s/proc/kallsyms", machine->root_dir); 1932a1645ce1SZhang, Yanmin kallsyms_filename = path; 1933a1645ce1SZhang, Yanmin } 1934a1645ce1SZhang, Yanmin 1935a1645ce1SZhang, Yanmin err = dso__load_kallsyms(self, kallsyms_filename, map, filter); 1936a1645ce1SZhang, Yanmin if (err > 0) 1937a1645ce1SZhang, Yanmin pr_debug("Using %s for symbols\n", kallsyms_filename); 1938a1645ce1SZhang, Yanmin 1939a1645ce1SZhang, Yanmin out_try_fixup: 1940a1645ce1SZhang, Yanmin if (err > 0) { 1941a1645ce1SZhang, Yanmin if (kallsyms_filename != NULL) { 194248ea8f54SArnaldo Carvalho de Melo machine__mmap_name(machine, path, sizeof(path)); 194323346f21SArnaldo Carvalho de Melo dso__set_long_name(self, strdup(path)); 1944a1645ce1SZhang, Yanmin } 1945a1645ce1SZhang, Yanmin map__fixup_start(map); 1946a1645ce1SZhang, Yanmin map__fixup_end(map); 1947a1645ce1SZhang, Yanmin } 1948a1645ce1SZhang, Yanmin 1949a1645ce1SZhang, Yanmin return err; 1950a1645ce1SZhang, Yanmin } 1951cd84c2acSFrederic Weisbecker 1952b0da954aSArnaldo Carvalho de Melo static void dsos__add(struct list_head *head, struct dso *dso) 1953cd84c2acSFrederic Weisbecker { 1954b0da954aSArnaldo Carvalho de Melo list_add_tail(&dso->node, head); 1955cd84c2acSFrederic Weisbecker } 1956cd84c2acSFrederic Weisbecker 1957b0da954aSArnaldo Carvalho de Melo static struct dso *dsos__find(struct list_head *head, const char *name) 1958cd84c2acSFrederic Weisbecker { 1959cd84c2acSFrederic Weisbecker struct dso *pos; 1960cd84c2acSFrederic Weisbecker 1961b0da954aSArnaldo Carvalho de Melo list_for_each_entry(pos, head, node) 1962cf4e5b08SArnaldo Carvalho de Melo if (strcmp(pos->long_name, name) == 0) 1963cd84c2acSFrederic Weisbecker return pos; 1964cd84c2acSFrederic Weisbecker return NULL; 1965cd84c2acSFrederic Weisbecker } 1966cd84c2acSFrederic Weisbecker 1967a89e5abeSArnaldo Carvalho de Melo struct dso *__dsos__findnew(struct list_head *head, const char *name) 1968cd84c2acSFrederic Weisbecker { 1969a89e5abeSArnaldo Carvalho de Melo struct dso *dso = dsos__find(head, name); 1970cd84c2acSFrederic Weisbecker 1971e4204992SArnaldo Carvalho de Melo if (!dso) { 197200a192b3SArnaldo Carvalho de Melo dso = dso__new(name); 1973cfc10d3bSArnaldo Carvalho de Melo if (dso != NULL) { 1974a89e5abeSArnaldo Carvalho de Melo dsos__add(head, dso); 1975cfc10d3bSArnaldo Carvalho de Melo dso__set_basename(dso); 1976cfc10d3bSArnaldo Carvalho de Melo } 1977e4204992SArnaldo Carvalho de Melo } 1978cd84c2acSFrederic Weisbecker 1979cd84c2acSFrederic Weisbecker return dso; 1980cd84c2acSFrederic Weisbecker } 1981cd84c2acSFrederic Weisbecker 19821f626bc3SArnaldo Carvalho de Melo size_t __dsos__fprintf(struct list_head *head, FILE *fp) 1983cd84c2acSFrederic Weisbecker { 1984cd84c2acSFrederic Weisbecker struct dso *pos; 1985cbf69680SArnaldo Carvalho de Melo size_t ret = 0; 1986cd84c2acSFrederic Weisbecker 198795011c60SArnaldo Carvalho de Melo list_for_each_entry(pos, head, node) { 198895011c60SArnaldo Carvalho de Melo int i; 198995011c60SArnaldo Carvalho de Melo for (i = 0; i < MAP__NR_TYPES; ++i) 1990cbf69680SArnaldo Carvalho de Melo ret += dso__fprintf(pos, i, fp); 1991cd84c2acSFrederic Weisbecker } 1992cd84c2acSFrederic Weisbecker 1993cbf69680SArnaldo Carvalho de Melo return ret; 1994cbf69680SArnaldo Carvalho de Melo } 1995cbf69680SArnaldo Carvalho de Melo 1996cbf69680SArnaldo Carvalho de Melo size_t machines__fprintf_dsos(struct rb_root *self, FILE *fp) 1997b0da954aSArnaldo Carvalho de Melo { 1998a1645ce1SZhang, Yanmin struct rb_node *nd; 1999cbf69680SArnaldo Carvalho de Melo size_t ret = 0; 2000a1645ce1SZhang, Yanmin 2001cbf69680SArnaldo Carvalho de Melo for (nd = rb_first(self); nd; nd = rb_next(nd)) { 200223346f21SArnaldo Carvalho de Melo struct machine *pos = rb_entry(nd, struct machine, rb_node); 2003cbf69680SArnaldo Carvalho de Melo ret += __dsos__fprintf(&pos->kernel_dsos, fp); 2004cbf69680SArnaldo Carvalho de Melo ret += __dsos__fprintf(&pos->user_dsos, fp); 2005a1645ce1SZhang, Yanmin } 2006cbf69680SArnaldo Carvalho de Melo 2007cbf69680SArnaldo Carvalho de Melo return ret; 2008b0da954aSArnaldo Carvalho de Melo } 2009b0da954aSArnaldo Carvalho de Melo 201088d3d9b7SArnaldo Carvalho de Melo static size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp, 201188d3d9b7SArnaldo Carvalho de Melo bool with_hits) 20129e03eb2dSArnaldo Carvalho de Melo { 20139e03eb2dSArnaldo Carvalho de Melo struct dso *pos; 20149e03eb2dSArnaldo Carvalho de Melo size_t ret = 0; 20159e03eb2dSArnaldo Carvalho de Melo 2016b0da954aSArnaldo Carvalho de Melo list_for_each_entry(pos, head, node) { 201788d3d9b7SArnaldo Carvalho de Melo if (with_hits && !pos->hit) 201888d3d9b7SArnaldo Carvalho de Melo continue; 20199e03eb2dSArnaldo Carvalho de Melo ret += dso__fprintf_buildid(pos, fp); 20209e03eb2dSArnaldo Carvalho de Melo ret += fprintf(fp, " %s\n", pos->long_name); 20219e03eb2dSArnaldo Carvalho de Melo } 20229e03eb2dSArnaldo Carvalho de Melo return ret; 20239e03eb2dSArnaldo Carvalho de Melo } 20249e03eb2dSArnaldo Carvalho de Melo 2025f869097eSArnaldo Carvalho de Melo size_t machine__fprintf_dsos_buildid(struct machine *self, FILE *fp, bool with_hits) 2026f869097eSArnaldo Carvalho de Melo { 2027f869097eSArnaldo Carvalho de Melo return __dsos__fprintf_buildid(&self->kernel_dsos, fp, with_hits) + 2028f869097eSArnaldo Carvalho de Melo __dsos__fprintf_buildid(&self->user_dsos, fp, with_hits); 2029f869097eSArnaldo Carvalho de Melo } 2030f869097eSArnaldo Carvalho de Melo 2031cbf69680SArnaldo Carvalho de Melo size_t machines__fprintf_dsos_buildid(struct rb_root *self, FILE *fp, bool with_hits) 2032b0da954aSArnaldo Carvalho de Melo { 2033a1645ce1SZhang, Yanmin struct rb_node *nd; 2034a1645ce1SZhang, Yanmin size_t ret = 0; 2035a1645ce1SZhang, Yanmin 2036cbf69680SArnaldo Carvalho de Melo for (nd = rb_first(self); nd; nd = rb_next(nd)) { 203723346f21SArnaldo Carvalho de Melo struct machine *pos = rb_entry(nd, struct machine, rb_node); 2038f869097eSArnaldo Carvalho de Melo ret += machine__fprintf_dsos_buildid(pos, fp, with_hits); 2039a1645ce1SZhang, Yanmin } 2040a1645ce1SZhang, Yanmin return ret; 2041b0da954aSArnaldo Carvalho de Melo } 2042b0da954aSArnaldo Carvalho de Melo 2043fd1d908cSArnaldo Carvalho de Melo struct dso *dso__new_kernel(const char *name) 2044fd1d908cSArnaldo Carvalho de Melo { 2045fd1d908cSArnaldo Carvalho de Melo struct dso *self = dso__new(name ?: "[kernel.kallsyms]"); 2046fd1d908cSArnaldo Carvalho de Melo 2047fd1d908cSArnaldo Carvalho de Melo if (self != NULL) { 2048b63be8d7SArnaldo Carvalho de Melo dso__set_short_name(self, "[kernel]"); 2049a1645ce1SZhang, Yanmin self->kernel = DSO_TYPE_KERNEL; 2050fd1d908cSArnaldo Carvalho de Melo } 2051fd1d908cSArnaldo Carvalho de Melo 2052fd1d908cSArnaldo Carvalho de Melo return self; 2053fd1d908cSArnaldo Carvalho de Melo } 2054fd1d908cSArnaldo Carvalho de Melo 205523346f21SArnaldo Carvalho de Melo static struct dso *dso__new_guest_kernel(struct machine *machine, 2056a1645ce1SZhang, Yanmin const char *name) 2057fd1d908cSArnaldo Carvalho de Melo { 205848ea8f54SArnaldo Carvalho de Melo char bf[PATH_MAX]; 205948ea8f54SArnaldo Carvalho de Melo struct dso *self = dso__new(name ?: machine__mmap_name(machine, bf, sizeof(bf))); 2060a1645ce1SZhang, Yanmin 2061a1645ce1SZhang, Yanmin if (self != NULL) { 2062a1645ce1SZhang, Yanmin dso__set_short_name(self, "[guest.kernel]"); 2063a1645ce1SZhang, Yanmin self->kernel = DSO_TYPE_GUEST_KERNEL; 2064a1645ce1SZhang, Yanmin } 2065a1645ce1SZhang, Yanmin 2066a1645ce1SZhang, Yanmin return self; 2067a1645ce1SZhang, Yanmin } 2068a1645ce1SZhang, Yanmin 206923346f21SArnaldo Carvalho de Melo void dso__read_running_kernel_build_id(struct dso *self, struct machine *machine) 2070a1645ce1SZhang, Yanmin { 2071a1645ce1SZhang, Yanmin char path[PATH_MAX]; 2072a1645ce1SZhang, Yanmin 207323346f21SArnaldo Carvalho de Melo if (machine__is_default_guest(machine)) 2074a1645ce1SZhang, Yanmin return; 207523346f21SArnaldo Carvalho de Melo sprintf(path, "%s/sys/kernel/notes", machine->root_dir); 2076a1645ce1SZhang, Yanmin if (sysfs__read_build_id(path, self->build_id, 2077fd1d908cSArnaldo Carvalho de Melo sizeof(self->build_id)) == 0) 2078fd1d908cSArnaldo Carvalho de Melo self->has_build_id = true; 2079fd1d908cSArnaldo Carvalho de Melo } 2080fd1d908cSArnaldo Carvalho de Melo 20815c0541d5SArnaldo Carvalho de Melo static struct dso *machine__create_kernel(struct machine *self) 2082cd84c2acSFrederic Weisbecker { 2083a1645ce1SZhang, Yanmin const char *vmlinux_name = NULL; 2084a1645ce1SZhang, Yanmin struct dso *kernel; 2085cd84c2acSFrederic Weisbecker 20865c0541d5SArnaldo Carvalho de Melo if (machine__is_host(self)) { 2087a1645ce1SZhang, Yanmin vmlinux_name = symbol_conf.vmlinux_name; 2088a1645ce1SZhang, Yanmin kernel = dso__new_kernel(vmlinux_name); 2089a1645ce1SZhang, Yanmin } else { 20905c0541d5SArnaldo Carvalho de Melo if (machine__is_default_guest(self)) 2091a1645ce1SZhang, Yanmin vmlinux_name = symbol_conf.default_guest_vmlinux_name; 20925c0541d5SArnaldo Carvalho de Melo kernel = dso__new_guest_kernel(self, vmlinux_name); 20938d92c02aSArnaldo Carvalho de Melo } 2094cd84c2acSFrederic Weisbecker 2095a1645ce1SZhang, Yanmin if (kernel != NULL) { 20965c0541d5SArnaldo Carvalho de Melo dso__read_running_kernel_build_id(kernel, self); 20975c0541d5SArnaldo Carvalho de Melo dsos__add(&self->kernel_dsos, kernel); 2098a1645ce1SZhang, Yanmin } 2099f1dfa0b1SArnaldo Carvalho de Melo return kernel; 2100f1dfa0b1SArnaldo Carvalho de Melo } 2101f1dfa0b1SArnaldo Carvalho de Melo 2102d28c6223SArnaldo Carvalho de Melo int __machine__create_kernel_maps(struct machine *self, struct dso *kernel) 2103f1dfa0b1SArnaldo Carvalho de Melo { 2104de176489SArnaldo Carvalho de Melo enum map_type type; 2105f1dfa0b1SArnaldo Carvalho de Melo 2106de176489SArnaldo Carvalho de Melo for (type = 0; type < MAP__NR_TYPES; ++type) { 21079de89fe7SArnaldo Carvalho de Melo struct kmap *kmap; 21089de89fe7SArnaldo Carvalho de Melo 2109d28c6223SArnaldo Carvalho de Melo self->vmlinux_maps[type] = map__new2(0, kernel, type); 2110d28c6223SArnaldo Carvalho de Melo if (self->vmlinux_maps[type] == NULL) 2111f1dfa0b1SArnaldo Carvalho de Melo return -1; 2112f1dfa0b1SArnaldo Carvalho de Melo 2113d28c6223SArnaldo Carvalho de Melo self->vmlinux_maps[type]->map_ip = 2114d28c6223SArnaldo Carvalho de Melo self->vmlinux_maps[type]->unmap_ip = identity__map_ip; 21159de89fe7SArnaldo Carvalho de Melo 2116d28c6223SArnaldo Carvalho de Melo kmap = map__kmap(self->vmlinux_maps[type]); 2117d28c6223SArnaldo Carvalho de Melo kmap->kmaps = &self->kmaps; 2118d28c6223SArnaldo Carvalho de Melo map_groups__insert(&self->kmaps, self->vmlinux_maps[type]); 2119f1dfa0b1SArnaldo Carvalho de Melo } 2120f1dfa0b1SArnaldo Carvalho de Melo 2121f1dfa0b1SArnaldo Carvalho de Melo return 0; 21222446042cSArnaldo Carvalho de Melo } 21232446042cSArnaldo Carvalho de Melo 2124076c6e45SArnaldo Carvalho de Melo void machine__destroy_kernel_maps(struct machine *self) 2125076c6e45SArnaldo Carvalho de Melo { 2126076c6e45SArnaldo Carvalho de Melo enum map_type type; 2127076c6e45SArnaldo Carvalho de Melo 2128076c6e45SArnaldo Carvalho de Melo for (type = 0; type < MAP__NR_TYPES; ++type) { 2129076c6e45SArnaldo Carvalho de Melo struct kmap *kmap; 2130076c6e45SArnaldo Carvalho de Melo 2131076c6e45SArnaldo Carvalho de Melo if (self->vmlinux_maps[type] == NULL) 2132076c6e45SArnaldo Carvalho de Melo continue; 2133076c6e45SArnaldo Carvalho de Melo 2134076c6e45SArnaldo Carvalho de Melo kmap = map__kmap(self->vmlinux_maps[type]); 2135076c6e45SArnaldo Carvalho de Melo map_groups__remove(&self->kmaps, self->vmlinux_maps[type]); 2136076c6e45SArnaldo Carvalho de Melo if (kmap->ref_reloc_sym) { 2137076c6e45SArnaldo Carvalho de Melo /* 2138076c6e45SArnaldo Carvalho de Melo * ref_reloc_sym is shared among all maps, so free just 2139076c6e45SArnaldo Carvalho de Melo * on one of them. 2140076c6e45SArnaldo Carvalho de Melo */ 2141076c6e45SArnaldo Carvalho de Melo if (type == MAP__FUNCTION) { 2142076c6e45SArnaldo Carvalho de Melo free((char *)kmap->ref_reloc_sym->name); 2143076c6e45SArnaldo Carvalho de Melo kmap->ref_reloc_sym->name = NULL; 2144076c6e45SArnaldo Carvalho de Melo free(kmap->ref_reloc_sym); 2145076c6e45SArnaldo Carvalho de Melo } 2146076c6e45SArnaldo Carvalho de Melo kmap->ref_reloc_sym = NULL; 2147076c6e45SArnaldo Carvalho de Melo } 2148076c6e45SArnaldo Carvalho de Melo 2149076c6e45SArnaldo Carvalho de Melo map__delete(self->vmlinux_maps[type]); 2150076c6e45SArnaldo Carvalho de Melo self->vmlinux_maps[type] = NULL; 2151076c6e45SArnaldo Carvalho de Melo } 2152076c6e45SArnaldo Carvalho de Melo } 2153076c6e45SArnaldo Carvalho de Melo 21545c0541d5SArnaldo Carvalho de Melo int machine__create_kernel_maps(struct machine *self) 21555c0541d5SArnaldo Carvalho de Melo { 21565c0541d5SArnaldo Carvalho de Melo struct dso *kernel = machine__create_kernel(self); 21575c0541d5SArnaldo Carvalho de Melo 21585c0541d5SArnaldo Carvalho de Melo if (kernel == NULL || 21595c0541d5SArnaldo Carvalho de Melo __machine__create_kernel_maps(self, kernel) < 0) 21605c0541d5SArnaldo Carvalho de Melo return -1; 21615c0541d5SArnaldo Carvalho de Melo 21625c0541d5SArnaldo Carvalho de Melo if (symbol_conf.use_modules && machine__create_modules(self) < 0) 21635c0541d5SArnaldo Carvalho de Melo pr_debug("Problems creating module maps, continuing anyway...\n"); 21645c0541d5SArnaldo Carvalho de Melo /* 21655c0541d5SArnaldo Carvalho de Melo * Now that we have all the maps created, just set the ->end of them: 21665c0541d5SArnaldo Carvalho de Melo */ 21675c0541d5SArnaldo Carvalho de Melo map_groups__fixup_end(&self->kmaps); 21685c0541d5SArnaldo Carvalho de Melo return 0; 21695c0541d5SArnaldo Carvalho de Melo } 21705c0541d5SArnaldo Carvalho de Melo 2171cc612d81SArnaldo Carvalho de Melo static void vmlinux_path__exit(void) 21722446042cSArnaldo Carvalho de Melo { 2173cc612d81SArnaldo Carvalho de Melo while (--vmlinux_path__nr_entries >= 0) { 2174cc612d81SArnaldo Carvalho de Melo free(vmlinux_path[vmlinux_path__nr_entries]); 2175cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = NULL; 2176cc612d81SArnaldo Carvalho de Melo } 2177cc612d81SArnaldo Carvalho de Melo 2178cc612d81SArnaldo Carvalho de Melo free(vmlinux_path); 2179cc612d81SArnaldo Carvalho de Melo vmlinux_path = NULL; 2180cc612d81SArnaldo Carvalho de Melo } 2181cc612d81SArnaldo Carvalho de Melo 2182cc612d81SArnaldo Carvalho de Melo static int vmlinux_path__init(void) 2183cc612d81SArnaldo Carvalho de Melo { 2184cc612d81SArnaldo Carvalho de Melo struct utsname uts; 2185cc612d81SArnaldo Carvalho de Melo char bf[PATH_MAX]; 2186cc612d81SArnaldo Carvalho de Melo 2187cc612d81SArnaldo Carvalho de Melo if (uname(&uts) < 0) 21882446042cSArnaldo Carvalho de Melo return -1; 21892446042cSArnaldo Carvalho de Melo 2190cc612d81SArnaldo Carvalho de Melo vmlinux_path = malloc(sizeof(char *) * 5); 2191cc612d81SArnaldo Carvalho de Melo if (vmlinux_path == NULL) 2192cc612d81SArnaldo Carvalho de Melo return -1; 2193cc612d81SArnaldo Carvalho de Melo 2194cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup("vmlinux"); 2195cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 2196cc612d81SArnaldo Carvalho de Melo goto out_fail; 2197cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 2198cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup("/boot/vmlinux"); 2199cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 2200cc612d81SArnaldo Carvalho de Melo goto out_fail; 2201cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 2202cc612d81SArnaldo Carvalho de Melo snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", uts.release); 2203cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); 2204cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 2205cc612d81SArnaldo Carvalho de Melo goto out_fail; 2206cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 2207cc612d81SArnaldo Carvalho de Melo snprintf(bf, sizeof(bf), "/lib/modules/%s/build/vmlinux", uts.release); 2208cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); 2209cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 2210cc612d81SArnaldo Carvalho de Melo goto out_fail; 2211cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 2212cc612d81SArnaldo Carvalho de Melo snprintf(bf, sizeof(bf), "/usr/lib/debug/lib/modules/%s/vmlinux", 2213cc612d81SArnaldo Carvalho de Melo uts.release); 2214cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); 2215cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 2216cc612d81SArnaldo Carvalho de Melo goto out_fail; 2217cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 2218cc612d81SArnaldo Carvalho de Melo 2219cc612d81SArnaldo Carvalho de Melo return 0; 2220cc612d81SArnaldo Carvalho de Melo 2221cc612d81SArnaldo Carvalho de Melo out_fail: 2222cc612d81SArnaldo Carvalho de Melo vmlinux_path__exit(); 2223cc612d81SArnaldo Carvalho de Melo return -1; 2224cc612d81SArnaldo Carvalho de Melo } 2225cc612d81SArnaldo Carvalho de Melo 22265ad90e4eSArnaldo Carvalho de Melo size_t machine__fprintf_vmlinux_path(struct machine *self, FILE *fp) 2227b0a9ab62SArnaldo Carvalho de Melo { 2228b0a9ab62SArnaldo Carvalho de Melo int i; 2229b0a9ab62SArnaldo Carvalho de Melo size_t printed = 0; 22305ad90e4eSArnaldo Carvalho de Melo struct dso *kdso = self->vmlinux_maps[MAP__FUNCTION]->dso; 22315ad90e4eSArnaldo Carvalho de Melo 22325ad90e4eSArnaldo Carvalho de Melo if (kdso->has_build_id) { 22335ad90e4eSArnaldo Carvalho de Melo char filename[PATH_MAX]; 22345ad90e4eSArnaldo Carvalho de Melo if (dso__build_id_filename(kdso, filename, sizeof(filename))) 22355ad90e4eSArnaldo Carvalho de Melo printed += fprintf(fp, "[0] %s\n", filename); 22365ad90e4eSArnaldo Carvalho de Melo } 2237b0a9ab62SArnaldo Carvalho de Melo 2238b0a9ab62SArnaldo Carvalho de Melo for (i = 0; i < vmlinux_path__nr_entries; ++i) 22395ad90e4eSArnaldo Carvalho de Melo printed += fprintf(fp, "[%d] %s\n", 22405ad90e4eSArnaldo Carvalho de Melo i + kdso->has_build_id, vmlinux_path[i]); 2241b0a9ab62SArnaldo Carvalho de Melo 2242b0a9ab62SArnaldo Carvalho de Melo return printed; 2243b0a9ab62SArnaldo Carvalho de Melo } 2244b0a9ab62SArnaldo Carvalho de Melo 2245655000e7SArnaldo Carvalho de Melo static int setup_list(struct strlist **list, const char *list_str, 2246655000e7SArnaldo Carvalho de Melo const char *list_name) 2247655000e7SArnaldo Carvalho de Melo { 2248655000e7SArnaldo Carvalho de Melo if (list_str == NULL) 2249655000e7SArnaldo Carvalho de Melo return 0; 2250655000e7SArnaldo Carvalho de Melo 2251655000e7SArnaldo Carvalho de Melo *list = strlist__new(true, list_str); 2252655000e7SArnaldo Carvalho de Melo if (!*list) { 2253655000e7SArnaldo Carvalho de Melo pr_err("problems parsing %s list\n", list_name); 2254655000e7SArnaldo Carvalho de Melo return -1; 2255655000e7SArnaldo Carvalho de Melo } 2256655000e7SArnaldo Carvalho de Melo return 0; 2257655000e7SArnaldo Carvalho de Melo } 2258655000e7SArnaldo Carvalho de Melo 225975be6cf4SArnaldo Carvalho de Melo int symbol__init(void) 2260cc612d81SArnaldo Carvalho de Melo { 226195011c60SArnaldo Carvalho de Melo elf_version(EV_CURRENT); 226275be6cf4SArnaldo Carvalho de Melo if (symbol_conf.sort_by_name) 226375be6cf4SArnaldo Carvalho de Melo symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) - 226479406cd7SArnaldo Carvalho de Melo sizeof(struct symbol)); 2265b32d133aSArnaldo Carvalho de Melo 226675be6cf4SArnaldo Carvalho de Melo if (symbol_conf.try_vmlinux_path && vmlinux_path__init() < 0) 2267cc612d81SArnaldo Carvalho de Melo return -1; 2268cc612d81SArnaldo Carvalho de Melo 2269c410a338SArnaldo Carvalho de Melo if (symbol_conf.field_sep && *symbol_conf.field_sep == '.') { 2270c410a338SArnaldo Carvalho de Melo pr_err("'.' is the only non valid --field-separator argument\n"); 2271c410a338SArnaldo Carvalho de Melo return -1; 2272c410a338SArnaldo Carvalho de Melo } 2273c410a338SArnaldo Carvalho de Melo 2274655000e7SArnaldo Carvalho de Melo if (setup_list(&symbol_conf.dso_list, 2275655000e7SArnaldo Carvalho de Melo symbol_conf.dso_list_str, "dso") < 0) 2276655000e7SArnaldo Carvalho de Melo return -1; 2277655000e7SArnaldo Carvalho de Melo 2278655000e7SArnaldo Carvalho de Melo if (setup_list(&symbol_conf.comm_list, 2279655000e7SArnaldo Carvalho de Melo symbol_conf.comm_list_str, "comm") < 0) 2280655000e7SArnaldo Carvalho de Melo goto out_free_dso_list; 2281655000e7SArnaldo Carvalho de Melo 2282655000e7SArnaldo Carvalho de Melo if (setup_list(&symbol_conf.sym_list, 2283655000e7SArnaldo Carvalho de Melo symbol_conf.sym_list_str, "symbol") < 0) 2284655000e7SArnaldo Carvalho de Melo goto out_free_comm_list; 2285655000e7SArnaldo Carvalho de Melo 22864aa65636SArnaldo Carvalho de Melo return 0; 2287655000e7SArnaldo Carvalho de Melo 2288655000e7SArnaldo Carvalho de Melo out_free_dso_list: 2289655000e7SArnaldo Carvalho de Melo strlist__delete(symbol_conf.dso_list); 2290655000e7SArnaldo Carvalho de Melo out_free_comm_list: 2291655000e7SArnaldo Carvalho de Melo strlist__delete(symbol_conf.comm_list); 2292655000e7SArnaldo Carvalho de Melo return -1; 2293cc612d81SArnaldo Carvalho de Melo } 2294cc612d81SArnaldo Carvalho de Melo 2295d65a458bSArnaldo Carvalho de Melo void symbol__exit(void) 2296d65a458bSArnaldo Carvalho de Melo { 2297d65a458bSArnaldo Carvalho de Melo strlist__delete(symbol_conf.sym_list); 2298d65a458bSArnaldo Carvalho de Melo strlist__delete(symbol_conf.dso_list); 2299d65a458bSArnaldo Carvalho de Melo strlist__delete(symbol_conf.comm_list); 2300d65a458bSArnaldo Carvalho de Melo vmlinux_path__exit(); 2301d65a458bSArnaldo Carvalho de Melo symbol_conf.sym_list = symbol_conf.dso_list = symbol_conf.comm_list = NULL; 2302d65a458bSArnaldo Carvalho de Melo } 2303d65a458bSArnaldo Carvalho de Melo 2304d28c6223SArnaldo Carvalho de Melo int machines__create_kernel_maps(struct rb_root *self, pid_t pid) 23054aa65636SArnaldo Carvalho de Melo { 2306d28c6223SArnaldo Carvalho de Melo struct machine *machine = machines__findnew(self, pid); 23079de89fe7SArnaldo Carvalho de Melo 230823346f21SArnaldo Carvalho de Melo if (machine == NULL) 2309a1645ce1SZhang, Yanmin return -1; 23104aa65636SArnaldo Carvalho de Melo 23115c0541d5SArnaldo Carvalho de Melo return machine__create_kernel_maps(machine); 2312cd84c2acSFrederic Weisbecker } 23135aab621bSArnaldo Carvalho de Melo 23145aab621bSArnaldo Carvalho de Melo static int hex(char ch) 23155aab621bSArnaldo Carvalho de Melo { 23165aab621bSArnaldo Carvalho de Melo if ((ch >= '0') && (ch <= '9')) 23175aab621bSArnaldo Carvalho de Melo return ch - '0'; 23185aab621bSArnaldo Carvalho de Melo if ((ch >= 'a') && (ch <= 'f')) 23195aab621bSArnaldo Carvalho de Melo return ch - 'a' + 10; 23205aab621bSArnaldo Carvalho de Melo if ((ch >= 'A') && (ch <= 'F')) 23215aab621bSArnaldo Carvalho de Melo return ch - 'A' + 10; 23225aab621bSArnaldo Carvalho de Melo return -1; 23235aab621bSArnaldo Carvalho de Melo } 23245aab621bSArnaldo Carvalho de Melo 23255aab621bSArnaldo Carvalho de Melo /* 23265aab621bSArnaldo Carvalho de Melo * While we find nice hex chars, build a long_val. 23275aab621bSArnaldo Carvalho de Melo * Return number of chars processed. 23285aab621bSArnaldo Carvalho de Melo */ 23295aab621bSArnaldo Carvalho de Melo int hex2u64(const char *ptr, u64 *long_val) 23305aab621bSArnaldo Carvalho de Melo { 23315aab621bSArnaldo Carvalho de Melo const char *p = ptr; 23325aab621bSArnaldo Carvalho de Melo *long_val = 0; 23335aab621bSArnaldo Carvalho de Melo 23345aab621bSArnaldo Carvalho de Melo while (*p) { 23355aab621bSArnaldo Carvalho de Melo const int hex_val = hex(*p); 23365aab621bSArnaldo Carvalho de Melo 23375aab621bSArnaldo Carvalho de Melo if (hex_val < 0) 23385aab621bSArnaldo Carvalho de Melo break; 23395aab621bSArnaldo Carvalho de Melo 23405aab621bSArnaldo Carvalho de Melo *long_val = (*long_val << 4) | hex_val; 23415aab621bSArnaldo Carvalho de Melo p++; 23425aab621bSArnaldo Carvalho de Melo } 23435aab621bSArnaldo Carvalho de Melo 23445aab621bSArnaldo Carvalho de Melo return p - ptr; 23455aab621bSArnaldo Carvalho de Melo } 23465aab621bSArnaldo Carvalho de Melo 23475aab621bSArnaldo Carvalho de Melo char *strxfrchar(char *s, char from, char to) 23485aab621bSArnaldo Carvalho de Melo { 23495aab621bSArnaldo Carvalho de Melo char *p = s; 23505aab621bSArnaldo Carvalho de Melo 23515aab621bSArnaldo Carvalho de Melo while ((p = strchr(p, from)) != NULL) 23525aab621bSArnaldo Carvalho de Melo *p++ = to; 23535aab621bSArnaldo Carvalho de Melo 23545aab621bSArnaldo Carvalho de Melo return s; 23555aab621bSArnaldo Carvalho de Melo } 2356a1645ce1SZhang, Yanmin 2357d28c6223SArnaldo Carvalho de Melo int machines__create_guest_kernel_maps(struct rb_root *self) 2358a1645ce1SZhang, Yanmin { 2359a1645ce1SZhang, Yanmin int ret = 0; 2360a1645ce1SZhang, Yanmin struct dirent **namelist = NULL; 2361a1645ce1SZhang, Yanmin int i, items = 0; 2362a1645ce1SZhang, Yanmin char path[PATH_MAX]; 2363a1645ce1SZhang, Yanmin pid_t pid; 2364a1645ce1SZhang, Yanmin 2365a1645ce1SZhang, Yanmin if (symbol_conf.default_guest_vmlinux_name || 2366a1645ce1SZhang, Yanmin symbol_conf.default_guest_modules || 2367a1645ce1SZhang, Yanmin symbol_conf.default_guest_kallsyms) { 2368d28c6223SArnaldo Carvalho de Melo machines__create_kernel_maps(self, DEFAULT_GUEST_KERNEL_ID); 2369a1645ce1SZhang, Yanmin } 2370a1645ce1SZhang, Yanmin 2371a1645ce1SZhang, Yanmin if (symbol_conf.guestmount) { 2372a1645ce1SZhang, Yanmin items = scandir(symbol_conf.guestmount, &namelist, NULL, NULL); 2373a1645ce1SZhang, Yanmin if (items <= 0) 2374a1645ce1SZhang, Yanmin return -ENOENT; 2375a1645ce1SZhang, Yanmin for (i = 0; i < items; i++) { 2376a1645ce1SZhang, Yanmin if (!isdigit(namelist[i]->d_name[0])) { 2377a1645ce1SZhang, Yanmin /* Filter out . and .. */ 2378a1645ce1SZhang, Yanmin continue; 2379a1645ce1SZhang, Yanmin } 2380a1645ce1SZhang, Yanmin pid = atoi(namelist[i]->d_name); 2381a1645ce1SZhang, Yanmin sprintf(path, "%s/%s/proc/kallsyms", 2382a1645ce1SZhang, Yanmin symbol_conf.guestmount, 2383a1645ce1SZhang, Yanmin namelist[i]->d_name); 2384a1645ce1SZhang, Yanmin ret = access(path, R_OK); 2385a1645ce1SZhang, Yanmin if (ret) { 2386a1645ce1SZhang, Yanmin pr_debug("Can't access file %s\n", path); 2387a1645ce1SZhang, Yanmin goto failure; 2388a1645ce1SZhang, Yanmin } 2389d28c6223SArnaldo Carvalho de Melo machines__create_kernel_maps(self, pid); 2390a1645ce1SZhang, Yanmin } 2391a1645ce1SZhang, Yanmin failure: 2392a1645ce1SZhang, Yanmin free(namelist); 2393a1645ce1SZhang, Yanmin } 2394a1645ce1SZhang, Yanmin 2395a1645ce1SZhang, Yanmin return ret; 2396a1645ce1SZhang, Yanmin } 23975c0541d5SArnaldo Carvalho de Melo 2398076c6e45SArnaldo Carvalho de Melo void machines__destroy_guest_kernel_maps(struct rb_root *self) 2399076c6e45SArnaldo Carvalho de Melo { 2400076c6e45SArnaldo Carvalho de Melo struct rb_node *next = rb_first(self); 2401076c6e45SArnaldo Carvalho de Melo 2402076c6e45SArnaldo Carvalho de Melo while (next) { 2403076c6e45SArnaldo Carvalho de Melo struct machine *pos = rb_entry(next, struct machine, rb_node); 2404076c6e45SArnaldo Carvalho de Melo 2405076c6e45SArnaldo Carvalho de Melo next = rb_next(&pos->rb_node); 2406076c6e45SArnaldo Carvalho de Melo rb_erase(&pos->rb_node, self); 2407076c6e45SArnaldo Carvalho de Melo machine__delete(pos); 2408076c6e45SArnaldo Carvalho de Melo } 2409076c6e45SArnaldo Carvalho de Melo } 2410076c6e45SArnaldo Carvalho de Melo 24115c0541d5SArnaldo Carvalho de Melo int machine__load_kallsyms(struct machine *self, const char *filename, 24125c0541d5SArnaldo Carvalho de Melo enum map_type type, symbol_filter_t filter) 24135c0541d5SArnaldo Carvalho de Melo { 24145c0541d5SArnaldo Carvalho de Melo struct map *map = self->vmlinux_maps[type]; 24155c0541d5SArnaldo Carvalho de Melo int ret = dso__load_kallsyms(map->dso, filename, map, filter); 24165c0541d5SArnaldo Carvalho de Melo 24175c0541d5SArnaldo Carvalho de Melo if (ret > 0) { 24185c0541d5SArnaldo Carvalho de Melo dso__set_loaded(map->dso, type); 24195c0541d5SArnaldo Carvalho de Melo /* 24205c0541d5SArnaldo Carvalho de Melo * Since /proc/kallsyms will have multiple sessions for the 24215c0541d5SArnaldo Carvalho de Melo * kernel, with modules between them, fixup the end of all 24225c0541d5SArnaldo Carvalho de Melo * sections. 24235c0541d5SArnaldo Carvalho de Melo */ 24245c0541d5SArnaldo Carvalho de Melo __map_groups__fixup_end(&self->kmaps, type); 24255c0541d5SArnaldo Carvalho de Melo } 24265c0541d5SArnaldo Carvalho de Melo 24275c0541d5SArnaldo Carvalho de Melo return ret; 24285c0541d5SArnaldo Carvalho de Melo } 24295c0541d5SArnaldo Carvalho de Melo 24305c0541d5SArnaldo Carvalho de Melo int machine__load_vmlinux_path(struct machine *self, enum map_type type, 24315c0541d5SArnaldo Carvalho de Melo symbol_filter_t filter) 24325c0541d5SArnaldo Carvalho de Melo { 24335c0541d5SArnaldo Carvalho de Melo struct map *map = self->vmlinux_maps[type]; 24345c0541d5SArnaldo Carvalho de Melo int ret = dso__load_vmlinux_path(map->dso, map, filter); 24355c0541d5SArnaldo Carvalho de Melo 24365c0541d5SArnaldo Carvalho de Melo if (ret > 0) { 24375c0541d5SArnaldo Carvalho de Melo dso__set_loaded(map->dso, type); 24385c0541d5SArnaldo Carvalho de Melo map__reloc_vmlinux(map); 24395c0541d5SArnaldo Carvalho de Melo } 24405c0541d5SArnaldo Carvalho de Melo 24415c0541d5SArnaldo Carvalho de Melo return ret; 24425c0541d5SArnaldo Carvalho de Melo } 2443