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 134c408fedfSArnaldo Carvalho de Melo static struct symbol *symbol__new(u64 start, u64 len, u8 binding, 135c408fedfSArnaldo 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; 148c408fedfSArnaldo 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 { 165c408fedfSArnaldo Carvalho de Melo return fprintf(fp, " %llx-%llx %c %s\n", 166c408fedfSArnaldo Carvalho de Melo self->start, self->end, 167c408fedfSArnaldo Carvalho de Melo self->binding == STB_GLOBAL ? 'g' : 168c408fedfSArnaldo Carvalho de Melo self->binding == STB_LOCAL ? 'l' : 'w', 169c408fedfSArnaldo 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 461c408fedfSArnaldo Carvalho de Melo static u8 kallsyms2elf_type(char type) 462c408fedfSArnaldo Carvalho de Melo { 463c408fedfSArnaldo Carvalho de Melo if (type == 'W') 464c408fedfSArnaldo Carvalho de Melo return STB_WEAK; 465c408fedfSArnaldo Carvalho de Melo 466c408fedfSArnaldo Carvalho de Melo return isupper(type) ? STB_GLOBAL : STB_LOCAL; 467c408fedfSArnaldo Carvalho de Melo } 468c408fedfSArnaldo 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 */ 482c408fedfSArnaldo 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 677c408fedfSArnaldo 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, 889c408fedfSArnaldo 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, 911c408fedfSArnaldo 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 1082*696b97a5SDave Martin /* Reject ARM ELF "mapping symbols": these aren't unique and 1083*696b97a5SDave Martin * don't identify functions, so will confuse the profile 1084*696b97a5SDave Martin * output: */ 1085*696b97a5SDave Martin if (ehdr.e_machine == EM_ARM) { 1086*696b97a5SDave Martin if (!strcmp(elf_name, "$a") || 1087*696b97a5SDave Martin !strcmp(elf_name, "$d") || 1088*696b97a5SDave Martin !strcmp(elf_name, "$t")) 1089*696b97a5SDave Martin continue; 1090*696b97a5SDave Martin } 1091*696b97a5SDave Martin 109270c3856bSEric B Munson if (opdsec && sym.st_shndx == opdidx) { 109370c3856bSEric B Munson u32 offset = sym.st_value - opdshdr.sh_addr; 109470c3856bSEric B Munson u64 *opd = opddata->d_buf + offset; 109570c3856bSEric B Munson sym.st_value = *opd; 109670c3856bSEric B Munson sym.st_shndx = elf_addr_to_index(elf, sym.st_value); 109770c3856bSEric B Munson } 109870c3856bSEric B Munson 109986470930SIngo Molnar sec = elf_getscn(elf, sym.st_shndx); 110086470930SIngo Molnar if (!sec) 110186470930SIngo Molnar goto out_elf_end; 110286470930SIngo Molnar 110386470930SIngo Molnar gelf_getshdr(sec, &shdr); 11046cfcc53eSMike Galbraith 1105d45868d3SArnaldo Carvalho de Melo if (is_label && !elf_sec__is_a(&shdr, secstrs, map->type)) 11066cfcc53eSMike Galbraith continue; 11076cfcc53eSMike Galbraith 11086cfcc53eSMike Galbraith section_name = elf_sec__name(&shdr, secstrs); 110986470930SIngo Molnar 1110a1645ce1SZhang, Yanmin if (self->kernel != DSO_TYPE_USER || kmodule) { 11112e538c4aSArnaldo Carvalho de Melo char dso_name[PATH_MAX]; 11122e538c4aSArnaldo Carvalho de Melo 11132e538c4aSArnaldo Carvalho de Melo if (strcmp(section_name, 1114b63be8d7SArnaldo Carvalho de Melo (curr_dso->short_name + 1115b63be8d7SArnaldo Carvalho de Melo self->short_name_len)) == 0) 11162e538c4aSArnaldo Carvalho de Melo goto new_symbol; 11172e538c4aSArnaldo Carvalho de Melo 11182e538c4aSArnaldo Carvalho de Melo if (strcmp(section_name, ".text") == 0) { 11192e538c4aSArnaldo Carvalho de Melo curr_map = map; 11202e538c4aSArnaldo Carvalho de Melo curr_dso = self; 11212e538c4aSArnaldo Carvalho de Melo goto new_symbol; 1122af427bf5SArnaldo Carvalho de Melo } 1123af427bf5SArnaldo Carvalho de Melo 11242e538c4aSArnaldo Carvalho de Melo snprintf(dso_name, sizeof(dso_name), 11252e538c4aSArnaldo Carvalho de Melo "%s%s", self->short_name, section_name); 11262e538c4aSArnaldo Carvalho de Melo 11279de89fe7SArnaldo Carvalho de Melo curr_map = map_groups__find_by_name(kmap->kmaps, map->type, dso_name); 11282e538c4aSArnaldo Carvalho de Melo if (curr_map == NULL) { 11292e538c4aSArnaldo Carvalho de Melo u64 start = sym.st_value; 11302e538c4aSArnaldo Carvalho de Melo 11312e538c4aSArnaldo Carvalho de Melo if (kmodule) 11322e538c4aSArnaldo Carvalho de Melo start += map->start + shdr.sh_offset; 11332e538c4aSArnaldo Carvalho de Melo 113400a192b3SArnaldo Carvalho de Melo curr_dso = dso__new(dso_name); 11352e538c4aSArnaldo Carvalho de Melo if (curr_dso == NULL) 11362e538c4aSArnaldo Carvalho de Melo goto out_elf_end; 1137a1645ce1SZhang, Yanmin curr_dso->kernel = self->kernel; 11383610583cSArnaldo Carvalho de Melo curr_map = map__new2(start, curr_dso, 11396275ce2dSArnaldo Carvalho de Melo map->type); 11402e538c4aSArnaldo Carvalho de Melo if (curr_map == NULL) { 11412e538c4aSArnaldo Carvalho de Melo dso__delete(curr_dso); 11422e538c4aSArnaldo Carvalho de Melo goto out_elf_end; 11432e538c4aSArnaldo Carvalho de Melo } 1144ed52ce2eSArnaldo Carvalho de Melo curr_map->map_ip = identity__map_ip; 1145ed52ce2eSArnaldo Carvalho de Melo curr_map->unmap_ip = identity__map_ip; 1146b0a9ab62SArnaldo Carvalho de Melo curr_dso->origin = self->origin; 11479de89fe7SArnaldo Carvalho de Melo map_groups__insert(kmap->kmaps, curr_map); 1148a1645ce1SZhang, Yanmin dsos__add(&self->node, curr_dso); 11496275ce2dSArnaldo Carvalho de Melo dso__set_loaded(curr_dso, map->type); 11502e538c4aSArnaldo Carvalho de Melo } else 11512e538c4aSArnaldo Carvalho de Melo curr_dso = curr_map->dso; 11522e538c4aSArnaldo Carvalho de Melo 11532e538c4aSArnaldo Carvalho de Melo goto new_symbol; 11542e538c4aSArnaldo Carvalho de Melo } 11552e538c4aSArnaldo Carvalho de Melo 11562e538c4aSArnaldo Carvalho de Melo if (curr_dso->adjust_symbols) { 115729a9f66dSArnaldo Carvalho de Melo pr_debug4("%s: adjusting symbol: st_value: %#Lx " 115829a9f66dSArnaldo Carvalho de Melo "sh_addr: %#Lx sh_offset: %#Lx\n", __func__, 115929a9f66dSArnaldo Carvalho de Melo (u64)sym.st_value, (u64)shdr.sh_addr, 116029a9f66dSArnaldo Carvalho de Melo (u64)shdr.sh_offset); 116186470930SIngo Molnar sym.st_value -= shdr.sh_addr - shdr.sh_offset; 1162af427bf5SArnaldo Carvalho de Melo } 116328ac909bSArnaldo Carvalho de Melo /* 116428ac909bSArnaldo Carvalho de Melo * We need to figure out if the object was created from C++ sources 116528ac909bSArnaldo Carvalho de Melo * DWARF DW_compile_unit has this, but we don't always have access 116628ac909bSArnaldo Carvalho de Melo * to it... 116728ac909bSArnaldo Carvalho de Melo */ 116883a0944fSIngo Molnar demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI); 116928ac909bSArnaldo Carvalho de Melo if (demangled != NULL) 117083a0944fSIngo Molnar elf_name = demangled; 11712e538c4aSArnaldo Carvalho de Melo new_symbol: 1172c408fedfSArnaldo Carvalho de Melo f = symbol__new(sym.st_value, sym.st_size, 1173c408fedfSArnaldo Carvalho de Melo GELF_ST_BIND(sym.st_info), elf_name); 117428ac909bSArnaldo Carvalho de Melo free(demangled); 117586470930SIngo Molnar if (!f) 117686470930SIngo Molnar goto out_elf_end; 117786470930SIngo Molnar 11782e538c4aSArnaldo Carvalho de Melo if (filter && filter(curr_map, f)) 117900a192b3SArnaldo Carvalho de Melo symbol__delete(f); 118086470930SIngo Molnar else { 11816a4694a4SArnaldo Carvalho de Melo symbols__insert(&curr_dso->symbols[curr_map->type], f); 118286470930SIngo Molnar nr++; 118386470930SIngo Molnar } 118486470930SIngo Molnar } 118586470930SIngo Molnar 11862e538c4aSArnaldo Carvalho de Melo /* 11872e538c4aSArnaldo Carvalho de Melo * For misannotated, zeroed, ASM function sizes. 11882e538c4aSArnaldo Carvalho de Melo */ 11896275ce2dSArnaldo Carvalho de Melo if (nr > 0) { 11906a4694a4SArnaldo Carvalho de Melo symbols__fixup_end(&self->symbols[map->type]); 11916275ce2dSArnaldo Carvalho de Melo if (kmap) { 11926275ce2dSArnaldo Carvalho de Melo /* 11936275ce2dSArnaldo Carvalho de Melo * We need to fixup this here too because we create new 11946275ce2dSArnaldo Carvalho de Melo * maps here, for things like vsyscall sections. 11956275ce2dSArnaldo Carvalho de Melo */ 11966275ce2dSArnaldo Carvalho de Melo __map_groups__fixup_end(kmap->kmaps, map->type); 11976275ce2dSArnaldo Carvalho de Melo } 11986275ce2dSArnaldo Carvalho de Melo } 119986470930SIngo Molnar err = nr; 120086470930SIngo Molnar out_elf_end: 120186470930SIngo Molnar elf_end(elf); 120286470930SIngo Molnar out_close: 120386470930SIngo Molnar return err; 120486470930SIngo Molnar } 120586470930SIngo Molnar 120678075caaSArnaldo Carvalho de Melo static bool dso__build_id_equal(const struct dso *self, u8 *build_id) 120778075caaSArnaldo Carvalho de Melo { 120878075caaSArnaldo Carvalho de Melo return memcmp(self->build_id, build_id, sizeof(self->build_id)) == 0; 120978075caaSArnaldo Carvalho de Melo } 121078075caaSArnaldo Carvalho de Melo 1211a1645ce1SZhang, Yanmin bool __dsos__read_build_ids(struct list_head *head, bool with_hits) 121257f395a7SFrederic Weisbecker { 1213e30a3d12SArnaldo Carvalho de Melo bool have_build_id = false; 121457f395a7SFrederic Weisbecker struct dso *pos; 121557f395a7SFrederic Weisbecker 12166122e4e4SArnaldo Carvalho de Melo list_for_each_entry(pos, head, node) { 12176122e4e4SArnaldo Carvalho de Melo if (with_hits && !pos->hit) 12186122e4e4SArnaldo Carvalho de Melo continue; 1219f6e1467dSArnaldo Carvalho de Melo if (pos->has_build_id) { 1220f6e1467dSArnaldo Carvalho de Melo have_build_id = true; 1221f6e1467dSArnaldo Carvalho de Melo continue; 1222f6e1467dSArnaldo Carvalho de Melo } 1223e30a3d12SArnaldo Carvalho de Melo if (filename__read_build_id(pos->long_name, pos->build_id, 1224e30a3d12SArnaldo Carvalho de Melo sizeof(pos->build_id)) > 0) { 1225e30a3d12SArnaldo Carvalho de Melo have_build_id = true; 1226e30a3d12SArnaldo Carvalho de Melo pos->has_build_id = true; 122757f395a7SFrederic Weisbecker } 12286122e4e4SArnaldo Carvalho de Melo } 122957f395a7SFrederic Weisbecker 1230e30a3d12SArnaldo Carvalho de Melo return have_build_id; 123157f395a7SFrederic Weisbecker } 123257f395a7SFrederic Weisbecker 1233fd7a346eSArnaldo Carvalho de Melo /* 1234fd7a346eSArnaldo Carvalho de Melo * Align offset to 4 bytes as needed for note name and descriptor data. 1235fd7a346eSArnaldo Carvalho de Melo */ 1236fd7a346eSArnaldo Carvalho de Melo #define NOTE_ALIGN(n) (((n) + 3) & -4U) 1237fd7a346eSArnaldo Carvalho de Melo 123821916c38SDave Martin static int elf_read_build_id(Elf *elf, void *bf, size_t size) 12394d1e00a8SArnaldo Carvalho de Melo { 124021916c38SDave Martin int err = -1; 12414d1e00a8SArnaldo Carvalho de Melo GElf_Ehdr ehdr; 12424d1e00a8SArnaldo Carvalho de Melo GElf_Shdr shdr; 1243fd7a346eSArnaldo Carvalho de Melo Elf_Data *data; 12444d1e00a8SArnaldo Carvalho de Melo Elf_Scn *sec; 1245e57cfcdaSPekka Enberg Elf_Kind ek; 1246fd7a346eSArnaldo Carvalho de Melo void *ptr; 12474d1e00a8SArnaldo Carvalho de Melo 12482643ce11SArnaldo Carvalho de Melo if (size < BUILD_ID_SIZE) 12492643ce11SArnaldo Carvalho de Melo goto out; 12502643ce11SArnaldo Carvalho de Melo 1251e57cfcdaSPekka Enberg ek = elf_kind(elf); 1252e57cfcdaSPekka Enberg if (ek != ELF_K_ELF) 125321916c38SDave Martin goto out; 1254e57cfcdaSPekka Enberg 12554d1e00a8SArnaldo Carvalho de Melo if (gelf_getehdr(elf, &ehdr) == NULL) { 12566beba7adSArnaldo Carvalho de Melo pr_err("%s: cannot get elf header.\n", __func__); 125721916c38SDave Martin goto out; 12584d1e00a8SArnaldo Carvalho de Melo } 12594d1e00a8SArnaldo Carvalho de Melo 12602643ce11SArnaldo Carvalho de Melo sec = elf_section_by_name(elf, &ehdr, &shdr, 12612643ce11SArnaldo Carvalho de Melo ".note.gnu.build-id", NULL); 1262fd7a346eSArnaldo Carvalho de Melo if (sec == NULL) { 1263fd7a346eSArnaldo Carvalho de Melo sec = elf_section_by_name(elf, &ehdr, &shdr, 1264fd7a346eSArnaldo Carvalho de Melo ".notes", NULL); 12654d1e00a8SArnaldo Carvalho de Melo if (sec == NULL) 126621916c38SDave Martin goto out; 1267fd7a346eSArnaldo Carvalho de Melo } 12684d1e00a8SArnaldo Carvalho de Melo 1269fd7a346eSArnaldo Carvalho de Melo data = elf_getdata(sec, NULL); 1270fd7a346eSArnaldo Carvalho de Melo if (data == NULL) 127121916c38SDave Martin goto out; 1272fd7a346eSArnaldo Carvalho de Melo 1273fd7a346eSArnaldo Carvalho de Melo ptr = data->d_buf; 1274fd7a346eSArnaldo Carvalho de Melo while (ptr < (data->d_buf + data->d_size)) { 1275fd7a346eSArnaldo Carvalho de Melo GElf_Nhdr *nhdr = ptr; 1276fd7a346eSArnaldo Carvalho de Melo int namesz = NOTE_ALIGN(nhdr->n_namesz), 1277fd7a346eSArnaldo Carvalho de Melo descsz = NOTE_ALIGN(nhdr->n_descsz); 1278fd7a346eSArnaldo Carvalho de Melo const char *name; 1279fd7a346eSArnaldo Carvalho de Melo 1280fd7a346eSArnaldo Carvalho de Melo ptr += sizeof(*nhdr); 1281fd7a346eSArnaldo Carvalho de Melo name = ptr; 1282fd7a346eSArnaldo Carvalho de Melo ptr += namesz; 1283fd7a346eSArnaldo Carvalho de Melo if (nhdr->n_type == NT_GNU_BUILD_ID && 1284fd7a346eSArnaldo Carvalho de Melo nhdr->n_namesz == sizeof("GNU")) { 1285fd7a346eSArnaldo Carvalho de Melo if (memcmp(name, "GNU", sizeof("GNU")) == 0) { 1286fd7a346eSArnaldo Carvalho de Melo memcpy(bf, ptr, BUILD_ID_SIZE); 12872643ce11SArnaldo Carvalho de Melo err = BUILD_ID_SIZE; 1288fd7a346eSArnaldo Carvalho de Melo break; 1289fd7a346eSArnaldo Carvalho de Melo } 1290fd7a346eSArnaldo Carvalho de Melo } 1291fd7a346eSArnaldo Carvalho de Melo ptr += descsz; 1292fd7a346eSArnaldo Carvalho de Melo } 129321916c38SDave Martin 129421916c38SDave Martin out: 129521916c38SDave Martin return err; 129621916c38SDave Martin } 129721916c38SDave Martin 129821916c38SDave Martin int filename__read_build_id(const char *filename, void *bf, size_t size) 129921916c38SDave Martin { 130021916c38SDave Martin int fd, err = -1; 130121916c38SDave Martin Elf *elf; 130221916c38SDave Martin 130321916c38SDave Martin if (size < BUILD_ID_SIZE) 130421916c38SDave Martin goto out; 130521916c38SDave Martin 130621916c38SDave Martin fd = open(filename, O_RDONLY); 130721916c38SDave Martin if (fd < 0) 130821916c38SDave Martin goto out; 130921916c38SDave Martin 131021916c38SDave Martin elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 131121916c38SDave Martin if (elf == NULL) { 131221916c38SDave Martin pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename); 131321916c38SDave Martin goto out_close; 131421916c38SDave Martin } 131521916c38SDave Martin 131621916c38SDave Martin err = elf_read_build_id(elf, bf, size); 131721916c38SDave Martin 13182643ce11SArnaldo Carvalho de Melo elf_end(elf); 13192643ce11SArnaldo Carvalho de Melo out_close: 13202643ce11SArnaldo Carvalho de Melo close(fd); 13212643ce11SArnaldo Carvalho de Melo out: 13222643ce11SArnaldo Carvalho de Melo return err; 13232643ce11SArnaldo Carvalho de Melo } 13242643ce11SArnaldo Carvalho de Melo 1325f1617b40SArnaldo Carvalho de Melo int sysfs__read_build_id(const char *filename, void *build_id, size_t size) 1326f1617b40SArnaldo Carvalho de Melo { 1327f1617b40SArnaldo Carvalho de Melo int fd, err = -1; 1328f1617b40SArnaldo Carvalho de Melo 1329f1617b40SArnaldo Carvalho de Melo if (size < BUILD_ID_SIZE) 1330f1617b40SArnaldo Carvalho de Melo goto out; 1331f1617b40SArnaldo Carvalho de Melo 1332f1617b40SArnaldo Carvalho de Melo fd = open(filename, O_RDONLY); 1333f1617b40SArnaldo Carvalho de Melo if (fd < 0) 1334f1617b40SArnaldo Carvalho de Melo goto out; 1335f1617b40SArnaldo Carvalho de Melo 1336f1617b40SArnaldo Carvalho de Melo while (1) { 1337f1617b40SArnaldo Carvalho de Melo char bf[BUFSIZ]; 1338f1617b40SArnaldo Carvalho de Melo GElf_Nhdr nhdr; 1339f1617b40SArnaldo Carvalho de Melo int namesz, descsz; 1340f1617b40SArnaldo Carvalho de Melo 1341f1617b40SArnaldo Carvalho de Melo if (read(fd, &nhdr, sizeof(nhdr)) != sizeof(nhdr)) 1342f1617b40SArnaldo Carvalho de Melo break; 1343f1617b40SArnaldo Carvalho de Melo 1344fd7a346eSArnaldo Carvalho de Melo namesz = NOTE_ALIGN(nhdr.n_namesz); 1345fd7a346eSArnaldo Carvalho de Melo descsz = NOTE_ALIGN(nhdr.n_descsz); 1346f1617b40SArnaldo Carvalho de Melo if (nhdr.n_type == NT_GNU_BUILD_ID && 1347f1617b40SArnaldo Carvalho de Melo nhdr.n_namesz == sizeof("GNU")) { 1348f1617b40SArnaldo Carvalho de Melo if (read(fd, bf, namesz) != namesz) 1349f1617b40SArnaldo Carvalho de Melo break; 1350f1617b40SArnaldo Carvalho de Melo if (memcmp(bf, "GNU", sizeof("GNU")) == 0) { 1351f1617b40SArnaldo Carvalho de Melo if (read(fd, build_id, 1352f1617b40SArnaldo Carvalho de Melo BUILD_ID_SIZE) == BUILD_ID_SIZE) { 1353f1617b40SArnaldo Carvalho de Melo err = 0; 1354f1617b40SArnaldo Carvalho de Melo break; 1355f1617b40SArnaldo Carvalho de Melo } 1356f1617b40SArnaldo Carvalho de Melo } else if (read(fd, bf, descsz) != descsz) 1357f1617b40SArnaldo Carvalho de Melo break; 1358f1617b40SArnaldo Carvalho de Melo } else { 1359f1617b40SArnaldo Carvalho de Melo int n = namesz + descsz; 1360f1617b40SArnaldo Carvalho de Melo if (read(fd, bf, n) != n) 1361f1617b40SArnaldo Carvalho de Melo break; 1362f1617b40SArnaldo Carvalho de Melo } 1363f1617b40SArnaldo Carvalho de Melo } 1364f1617b40SArnaldo Carvalho de Melo close(fd); 1365f1617b40SArnaldo Carvalho de Melo out: 1366f1617b40SArnaldo Carvalho de Melo return err; 1367f1617b40SArnaldo Carvalho de Melo } 1368f1617b40SArnaldo Carvalho de Melo 136994cb9e38SArnaldo Carvalho de Melo char dso__symtab_origin(const struct dso *self) 137094cb9e38SArnaldo Carvalho de Melo { 137194cb9e38SArnaldo Carvalho de Melo static const char origin[] = { 137294cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_KERNEL] = 'k', 137394cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_JAVA_JIT] = 'j', 13744cf40131SArnaldo Carvalho de Melo [DSO__ORIG_BUILD_ID_CACHE] = 'B', 137594cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_FEDORA] = 'f', 137694cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_UBUNTU] = 'u', 137794cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_BUILDID] = 'b', 137894cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_DSO] = 'd', 1379439d473bSArnaldo Carvalho de Melo [DSO__ORIG_KMODULE] = 'K', 1380a1645ce1SZhang, Yanmin [DSO__ORIG_GUEST_KERNEL] = 'g', 1381a1645ce1SZhang, Yanmin [DSO__ORIG_GUEST_KMODULE] = 'G', 138294cb9e38SArnaldo Carvalho de Melo }; 138394cb9e38SArnaldo Carvalho de Melo 138494cb9e38SArnaldo Carvalho de Melo if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND) 138594cb9e38SArnaldo Carvalho de Melo return '!'; 138694cb9e38SArnaldo Carvalho de Melo return origin[self->origin]; 138794cb9e38SArnaldo Carvalho de Melo } 138894cb9e38SArnaldo Carvalho de Melo 13899de89fe7SArnaldo Carvalho de Melo int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) 139086470930SIngo Molnar { 13914d1e00a8SArnaldo Carvalho de Melo int size = PATH_MAX; 1392c338aee8SArnaldo Carvalho de Melo char *name; 139386470930SIngo Molnar int ret = -1; 139486470930SIngo Molnar int fd; 139523346f21SArnaldo Carvalho de Melo struct machine *machine; 1396a1645ce1SZhang, Yanmin const char *root_dir; 13976da80ce8SDave Martin int want_symtab; 139886470930SIngo Molnar 13993610583cSArnaldo Carvalho de Melo dso__set_loaded(self, map->type); 140066bd8424SArnaldo Carvalho de Melo 1401a1645ce1SZhang, Yanmin if (self->kernel == DSO_TYPE_KERNEL) 14029de89fe7SArnaldo Carvalho de Melo return dso__load_kernel_sym(self, map, filter); 1403a1645ce1SZhang, Yanmin else if (self->kernel == DSO_TYPE_GUEST_KERNEL) 1404a1645ce1SZhang, Yanmin return dso__load_guest_kernel_sym(self, map, filter); 1405a1645ce1SZhang, Yanmin 140623346f21SArnaldo Carvalho de Melo if (map->groups && map->groups->machine) 140723346f21SArnaldo Carvalho de Melo machine = map->groups->machine; 1408a1645ce1SZhang, Yanmin else 140923346f21SArnaldo Carvalho de Melo machine = NULL; 1410c338aee8SArnaldo Carvalho de Melo 1411c338aee8SArnaldo Carvalho de Melo name = malloc(size); 141286470930SIngo Molnar if (!name) 141386470930SIngo Molnar return -1; 141486470930SIngo Molnar 141530d7a77dSArnaldo Carvalho de Melo self->adjust_symbols = 0; 1416f5812a7aSArnaldo Carvalho de Melo 141794cb9e38SArnaldo Carvalho de Melo if (strncmp(self->name, "/tmp/perf-", 10) == 0) { 14186beba7adSArnaldo Carvalho de Melo ret = dso__load_perf_map(self, map, filter); 141994cb9e38SArnaldo Carvalho de Melo self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT : 142094cb9e38SArnaldo Carvalho de Melo DSO__ORIG_NOT_FOUND; 142194cb9e38SArnaldo Carvalho de Melo return ret; 142294cb9e38SArnaldo Carvalho de Melo } 142394cb9e38SArnaldo Carvalho de Melo 14246da80ce8SDave Martin /* Iterate over candidate debug images. 14256da80ce8SDave Martin * On the first pass, only load images if they have a full symtab. 14266da80ce8SDave Martin * Failing that, do a second pass where we accept .dynsym also 14276da80ce8SDave Martin */ 14286da80ce8SDave Martin for (self->origin = DSO__ORIG_BUILD_ID_CACHE, want_symtab = 1; 14296da80ce8SDave Martin self->origin != DSO__ORIG_NOT_FOUND; 14306da80ce8SDave Martin self->origin++) { 143194cb9e38SArnaldo Carvalho de Melo switch (self->origin) { 14326da80ce8SDave Martin case DSO__ORIG_BUILD_ID_CACHE: 14336da80ce8SDave Martin if (dso__build_id_filename(self, name, size) == NULL) 14346da80ce8SDave Martin continue; 14356da80ce8SDave Martin break; 143694cb9e38SArnaldo Carvalho de Melo case DSO__ORIG_FEDORA: 1437439d473bSArnaldo Carvalho de Melo snprintf(name, size, "/usr/lib/debug%s.debug", 1438439d473bSArnaldo Carvalho de Melo self->long_name); 143986470930SIngo Molnar break; 144094cb9e38SArnaldo Carvalho de Melo case DSO__ORIG_UBUNTU: 1441439d473bSArnaldo Carvalho de Melo snprintf(name, size, "/usr/lib/debug%s", 1442439d473bSArnaldo Carvalho de Melo self->long_name); 144386470930SIngo Molnar break; 14446da80ce8SDave Martin case DSO__ORIG_BUILDID: { 1445b36f19d5SArnaldo Carvalho de Melo char build_id_hex[BUILD_ID_SIZE * 2 + 1]; 14466da80ce8SDave Martin 14476da80ce8SDave Martin if (!self->has_build_id) 14486da80ce8SDave Martin continue; 14496da80ce8SDave Martin 145021916c38SDave Martin build_id__sprintf(self->build_id, 145121916c38SDave Martin sizeof(self->build_id), 1452d3379ab9SArnaldo Carvalho de Melo build_id_hex); 14534d1e00a8SArnaldo Carvalho de Melo snprintf(name, size, 14544d1e00a8SArnaldo Carvalho de Melo "/usr/lib/debug/.build-id/%.2s/%s.debug", 1455d3379ab9SArnaldo Carvalho de Melo build_id_hex, build_id_hex + 2); 14564d1e00a8SArnaldo Carvalho de Melo } 14576da80ce8SDave Martin break; 145894cb9e38SArnaldo Carvalho de Melo case DSO__ORIG_DSO: 1459439d473bSArnaldo Carvalho de Melo snprintf(name, size, "%s", self->long_name); 146086470930SIngo Molnar break; 1461a1645ce1SZhang, Yanmin case DSO__ORIG_GUEST_KMODULE: 146223346f21SArnaldo Carvalho de Melo if (map->groups && map->groups->machine) 146323346f21SArnaldo Carvalho de Melo root_dir = map->groups->machine->root_dir; 1464a1645ce1SZhang, Yanmin else 1465a1645ce1SZhang, Yanmin root_dir = ""; 1466a1645ce1SZhang, Yanmin snprintf(name, size, "%s%s", root_dir, self->long_name); 1467a1645ce1SZhang, Yanmin break; 146886470930SIngo Molnar 146986470930SIngo Molnar default: 14706da80ce8SDave Martin /* 14716da80ce8SDave Martin * If we wanted a full symtab but no image had one, 14726da80ce8SDave Martin * relax our requirements and repeat the search. 14736da80ce8SDave Martin */ 14746da80ce8SDave Martin if (want_symtab) { 14756da80ce8SDave Martin want_symtab = 0; 14766da80ce8SDave Martin self->origin = DSO__ORIG_BUILD_ID_CACHE; 14776da80ce8SDave Martin } else 14786da80ce8SDave Martin continue; 147986470930SIngo Molnar } 148086470930SIngo Molnar 14816da80ce8SDave Martin /* Name is now the name of the next image to try */ 14826da80ce8SDave Martin fd = open(name, O_RDONLY); 14836da80ce8SDave Martin if (fd < 0) 14846da80ce8SDave Martin continue; 14856da80ce8SDave Martin 14866da80ce8SDave Martin ret = dso__load_sym(self, map, name, fd, filter, 0, 14876da80ce8SDave Martin want_symtab); 148886470930SIngo Molnar close(fd); 148986470930SIngo Molnar 149086470930SIngo Molnar /* 14916da80ce8SDave Martin * Some people seem to have debuginfo files _WITHOUT_ debug 14926da80ce8SDave Martin * info!?!? 149386470930SIngo Molnar */ 149486470930SIngo Molnar if (!ret) 14956da80ce8SDave Martin continue; 149686470930SIngo Molnar 1497a25e46c4SArnaldo Carvalho de Melo if (ret > 0) { 149882164161SArnaldo Carvalho de Melo int nr_plt = dso__synthesize_plt_symbols(self, map, filter); 1499a25e46c4SArnaldo Carvalho de Melo if (nr_plt > 0) 1500a25e46c4SArnaldo Carvalho de Melo ret += nr_plt; 15016da80ce8SDave Martin break; 1502a25e46c4SArnaldo Carvalho de Melo } 15036da80ce8SDave Martin } 15046da80ce8SDave Martin 150586470930SIngo Molnar free(name); 15061340e6bbSArnaldo Carvalho de Melo if (ret < 0 && strstr(self->name, " (deleted)") != NULL) 15071340e6bbSArnaldo Carvalho de Melo return 0; 150886470930SIngo Molnar return ret; 150986470930SIngo Molnar } 151086470930SIngo Molnar 151179406cd7SArnaldo Carvalho de Melo struct map *map_groups__find_by_name(struct map_groups *self, 151279406cd7SArnaldo Carvalho de Melo enum map_type type, const char *name) 1513439d473bSArnaldo Carvalho de Melo { 1514439d473bSArnaldo Carvalho de Melo struct rb_node *nd; 1515439d473bSArnaldo Carvalho de Melo 151679406cd7SArnaldo Carvalho de Melo for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) { 1517439d473bSArnaldo Carvalho de Melo struct map *map = rb_entry(nd, struct map, rb_node); 1518439d473bSArnaldo Carvalho de Melo 1519b7cece76SArnaldo Carvalho de Melo if (map->dso && strcmp(map->dso->short_name, name) == 0) 1520439d473bSArnaldo Carvalho de Melo return map; 1521439d473bSArnaldo Carvalho de Melo } 1522439d473bSArnaldo Carvalho de Melo 1523439d473bSArnaldo Carvalho de Melo return NULL; 1524439d473bSArnaldo Carvalho de Melo } 1525439d473bSArnaldo Carvalho de Melo 1526a1645ce1SZhang, Yanmin static int dso__kernel_module_get_build_id(struct dso *self, 1527a1645ce1SZhang, Yanmin const char *root_dir) 1528b7cece76SArnaldo Carvalho de Melo { 1529b7cece76SArnaldo Carvalho de Melo char filename[PATH_MAX]; 1530b7cece76SArnaldo Carvalho de Melo /* 1531b7cece76SArnaldo Carvalho de Melo * kernel module short names are of the form "[module]" and 1532b7cece76SArnaldo Carvalho de Melo * we need just "module" here. 1533b7cece76SArnaldo Carvalho de Melo */ 1534b7cece76SArnaldo Carvalho de Melo const char *name = self->short_name + 1; 1535b7cece76SArnaldo Carvalho de Melo 1536b7cece76SArnaldo Carvalho de Melo snprintf(filename, sizeof(filename), 1537a1645ce1SZhang, Yanmin "%s/sys/module/%.*s/notes/.note.gnu.build-id", 1538a1645ce1SZhang, Yanmin root_dir, (int)strlen(name) - 1, name); 1539b7cece76SArnaldo Carvalho de Melo 1540b7cece76SArnaldo Carvalho de Melo if (sysfs__read_build_id(filename, self->build_id, 1541b7cece76SArnaldo Carvalho de Melo sizeof(self->build_id)) == 0) 1542b7cece76SArnaldo Carvalho de Melo self->has_build_id = true; 1543b7cece76SArnaldo Carvalho de Melo 1544b7cece76SArnaldo Carvalho de Melo return 0; 1545b7cece76SArnaldo Carvalho de Melo } 1546b7cece76SArnaldo Carvalho de Melo 1547a1645ce1SZhang, Yanmin static int map_groups__set_modules_path_dir(struct map_groups *self, 1548a1645ce1SZhang, Yanmin const char *dir_name) 15496cfcc53eSMike Galbraith { 1550439d473bSArnaldo Carvalho de Melo struct dirent *dent; 15515aab621bSArnaldo Carvalho de Melo DIR *dir = opendir(dir_name); 155274534341SGui Jianfeng int ret = 0; 15536cfcc53eSMike Galbraith 1554439d473bSArnaldo Carvalho de Melo if (!dir) { 15555aab621bSArnaldo Carvalho de Melo pr_debug("%s: cannot open %s dir\n", __func__, dir_name); 1556439d473bSArnaldo Carvalho de Melo return -1; 1557439d473bSArnaldo Carvalho de Melo } 15586cfcc53eSMike Galbraith 1559439d473bSArnaldo Carvalho de Melo while ((dent = readdir(dir)) != NULL) { 1560439d473bSArnaldo Carvalho de Melo char path[PATH_MAX]; 1561a1645ce1SZhang, Yanmin struct stat st; 1562439d473bSArnaldo Carvalho de Melo 1563a1645ce1SZhang, Yanmin /*sshfs might return bad dent->d_type, so we have to stat*/ 1564a1645ce1SZhang, Yanmin sprintf(path, "%s/%s", dir_name, dent->d_name); 1565a1645ce1SZhang, Yanmin if (stat(path, &st)) 1566a1645ce1SZhang, Yanmin continue; 1567a1645ce1SZhang, Yanmin 1568a1645ce1SZhang, Yanmin if (S_ISDIR(st.st_mode)) { 1569439d473bSArnaldo Carvalho de Melo if (!strcmp(dent->d_name, ".") || 1570439d473bSArnaldo Carvalho de Melo !strcmp(dent->d_name, "..")) 1571439d473bSArnaldo Carvalho de Melo continue; 1572439d473bSArnaldo Carvalho de Melo 1573439d473bSArnaldo Carvalho de Melo snprintf(path, sizeof(path), "%s/%s", 15745aab621bSArnaldo Carvalho de Melo dir_name, dent->d_name); 157574534341SGui Jianfeng ret = map_groups__set_modules_path_dir(self, path); 157674534341SGui Jianfeng if (ret < 0) 157774534341SGui Jianfeng goto out; 1578439d473bSArnaldo Carvalho de Melo } else { 1579439d473bSArnaldo Carvalho de Melo char *dot = strrchr(dent->d_name, '.'), 1580439d473bSArnaldo Carvalho de Melo dso_name[PATH_MAX]; 1581439d473bSArnaldo Carvalho de Melo struct map *map; 1582cfc10d3bSArnaldo Carvalho de Melo char *long_name; 1583439d473bSArnaldo Carvalho de Melo 1584439d473bSArnaldo Carvalho de Melo if (dot == NULL || strcmp(dot, ".ko")) 1585439d473bSArnaldo Carvalho de Melo continue; 1586439d473bSArnaldo Carvalho de Melo snprintf(dso_name, sizeof(dso_name), "[%.*s]", 1587439d473bSArnaldo Carvalho de Melo (int)(dot - dent->d_name), dent->d_name); 1588439d473bSArnaldo Carvalho de Melo 1589a2a99e8eSArnaldo Carvalho de Melo strxfrchar(dso_name, '-', '_'); 15909de89fe7SArnaldo Carvalho de Melo map = map_groups__find_by_name(self, MAP__FUNCTION, dso_name); 1591439d473bSArnaldo Carvalho de Melo if (map == NULL) 1592439d473bSArnaldo Carvalho de Melo continue; 1593439d473bSArnaldo Carvalho de Melo 1594439d473bSArnaldo Carvalho de Melo snprintf(path, sizeof(path), "%s/%s", 15955aab621bSArnaldo Carvalho de Melo dir_name, dent->d_name); 1596439d473bSArnaldo Carvalho de Melo 1597cfc10d3bSArnaldo Carvalho de Melo long_name = strdup(path); 159874534341SGui Jianfeng if (long_name == NULL) { 159974534341SGui Jianfeng ret = -1; 160074534341SGui Jianfeng goto out; 160174534341SGui Jianfeng } 1602cfc10d3bSArnaldo Carvalho de Melo dso__set_long_name(map->dso, long_name); 16036e406257SArnaldo Carvalho de Melo map->dso->lname_alloc = 1; 1604a1645ce1SZhang, Yanmin dso__kernel_module_get_build_id(map->dso, ""); 1605439d473bSArnaldo Carvalho de Melo } 1606439d473bSArnaldo Carvalho de Melo } 1607439d473bSArnaldo Carvalho de Melo 160874534341SGui Jianfeng out: 1609439d473bSArnaldo Carvalho de Melo closedir(dir); 161074534341SGui Jianfeng return ret; 1611439d473bSArnaldo Carvalho de Melo } 1612439d473bSArnaldo Carvalho de Melo 1613a1645ce1SZhang, Yanmin static char *get_kernel_version(const char *root_dir) 1614439d473bSArnaldo Carvalho de Melo { 1615a1645ce1SZhang, Yanmin char version[PATH_MAX]; 1616a1645ce1SZhang, Yanmin FILE *file; 1617a1645ce1SZhang, Yanmin char *name, *tmp; 1618a1645ce1SZhang, Yanmin const char *prefix = "Linux version "; 1619a1645ce1SZhang, Yanmin 1620a1645ce1SZhang, Yanmin sprintf(version, "%s/proc/version", root_dir); 1621a1645ce1SZhang, Yanmin file = fopen(version, "r"); 1622a1645ce1SZhang, Yanmin if (!file) 1623a1645ce1SZhang, Yanmin return NULL; 1624a1645ce1SZhang, Yanmin 1625a1645ce1SZhang, Yanmin version[0] = '\0'; 1626a1645ce1SZhang, Yanmin tmp = fgets(version, sizeof(version), file); 1627a1645ce1SZhang, Yanmin fclose(file); 1628a1645ce1SZhang, Yanmin 1629a1645ce1SZhang, Yanmin name = strstr(version, prefix); 1630a1645ce1SZhang, Yanmin if (!name) 1631a1645ce1SZhang, Yanmin return NULL; 1632a1645ce1SZhang, Yanmin name += strlen(prefix); 1633a1645ce1SZhang, Yanmin tmp = strchr(name, ' '); 1634a1645ce1SZhang, Yanmin if (tmp) 1635a1645ce1SZhang, Yanmin *tmp = '\0'; 1636a1645ce1SZhang, Yanmin 1637a1645ce1SZhang, Yanmin return strdup(name); 1638a1645ce1SZhang, Yanmin } 1639a1645ce1SZhang, Yanmin 1640d28c6223SArnaldo Carvalho de Melo static int machine__set_modules_path(struct machine *self) 1641a1645ce1SZhang, Yanmin { 1642a1645ce1SZhang, Yanmin char *version; 1643439d473bSArnaldo Carvalho de Melo char modules_path[PATH_MAX]; 1644439d473bSArnaldo Carvalho de Melo 1645d28c6223SArnaldo Carvalho de Melo version = get_kernel_version(self->root_dir); 1646a1645ce1SZhang, Yanmin if (!version) 1647439d473bSArnaldo Carvalho de Melo return -1; 1648439d473bSArnaldo Carvalho de Melo 1649a1645ce1SZhang, Yanmin snprintf(modules_path, sizeof(modules_path), "%s/lib/modules/%s/kernel", 1650d28c6223SArnaldo Carvalho de Melo self->root_dir, version); 1651a1645ce1SZhang, Yanmin free(version); 1652439d473bSArnaldo Carvalho de Melo 1653d28c6223SArnaldo Carvalho de Melo return map_groups__set_modules_path_dir(&self->kmaps, modules_path); 1654439d473bSArnaldo Carvalho de Melo } 16556cfcc53eSMike Galbraith 16566cfcc53eSMike Galbraith /* 1657439d473bSArnaldo Carvalho de Melo * Constructor variant for modules (where we know from /proc/modules where 1658439d473bSArnaldo Carvalho de Melo * they are loaded) and for vmlinux, where only after we load all the 1659439d473bSArnaldo Carvalho de Melo * symbols we'll know where it starts and ends. 16606cfcc53eSMike Galbraith */ 16613610583cSArnaldo Carvalho de Melo static struct map *map__new2(u64 start, struct dso *dso, enum map_type type) 1662439d473bSArnaldo Carvalho de Melo { 16635aab621bSArnaldo Carvalho de Melo struct map *self = calloc(1, (sizeof(*self) + 16645aab621bSArnaldo Carvalho de Melo (dso->kernel ? sizeof(struct kmap) : 0))); 1665439d473bSArnaldo Carvalho de Melo if (self != NULL) { 1666439d473bSArnaldo Carvalho de Melo /* 1667afb7b4f0SArnaldo Carvalho de Melo * ->end will be filled after we load all the symbols 1668439d473bSArnaldo Carvalho de Melo */ 16693610583cSArnaldo Carvalho de Melo map__init(self, type, start, 0, 0, dso); 1670439d473bSArnaldo Carvalho de Melo } 1671afb7b4f0SArnaldo Carvalho de Melo 1672439d473bSArnaldo Carvalho de Melo return self; 1673439d473bSArnaldo Carvalho de Melo } 1674439d473bSArnaldo Carvalho de Melo 1675d28c6223SArnaldo Carvalho de Melo struct map *machine__new_module(struct machine *self, u64 start, 1676d28c6223SArnaldo Carvalho de Melo const char *filename) 1677b7cece76SArnaldo Carvalho de Melo { 1678b7cece76SArnaldo Carvalho de Melo struct map *map; 1679d28c6223SArnaldo Carvalho de Melo struct dso *dso = __dsos__findnew(&self->kernel_dsos, filename); 1680b7cece76SArnaldo Carvalho de Melo 1681b7cece76SArnaldo Carvalho de Melo if (dso == NULL) 1682b7cece76SArnaldo Carvalho de Melo return NULL; 1683b7cece76SArnaldo Carvalho de Melo 1684b7cece76SArnaldo Carvalho de Melo map = map__new2(start, dso, MAP__FUNCTION); 1685b7cece76SArnaldo Carvalho de Melo if (map == NULL) 1686b7cece76SArnaldo Carvalho de Melo return NULL; 1687b7cece76SArnaldo Carvalho de Melo 1688d28c6223SArnaldo Carvalho de Melo if (machine__is_host(self)) 1689b7cece76SArnaldo Carvalho de Melo dso->origin = DSO__ORIG_KMODULE; 1690a1645ce1SZhang, Yanmin else 1691a1645ce1SZhang, Yanmin dso->origin = DSO__ORIG_GUEST_KMODULE; 1692d28c6223SArnaldo Carvalho de Melo map_groups__insert(&self->kmaps, map); 1693b7cece76SArnaldo Carvalho de Melo return map; 1694b7cece76SArnaldo Carvalho de Melo } 1695b7cece76SArnaldo Carvalho de Melo 1696d28c6223SArnaldo Carvalho de Melo static int machine__create_modules(struct machine *self) 1697439d473bSArnaldo Carvalho de Melo { 1698439d473bSArnaldo Carvalho de Melo char *line = NULL; 1699439d473bSArnaldo Carvalho de Melo size_t n; 1700a1645ce1SZhang, Yanmin FILE *file; 1701439d473bSArnaldo Carvalho de Melo struct map *map; 1702a1645ce1SZhang, Yanmin const char *modules; 1703a1645ce1SZhang, Yanmin char path[PATH_MAX]; 1704439d473bSArnaldo Carvalho de Melo 1705d28c6223SArnaldo Carvalho de Melo if (machine__is_default_guest(self)) 1706a1645ce1SZhang, Yanmin modules = symbol_conf.default_guest_modules; 1707a1645ce1SZhang, Yanmin else { 1708d28c6223SArnaldo Carvalho de Melo sprintf(path, "%s/proc/modules", self->root_dir); 1709a1645ce1SZhang, Yanmin modules = path; 1710a1645ce1SZhang, Yanmin } 1711a1645ce1SZhang, Yanmin 1712a1645ce1SZhang, Yanmin file = fopen(modules, "r"); 1713439d473bSArnaldo Carvalho de Melo if (file == NULL) 1714439d473bSArnaldo Carvalho de Melo return -1; 1715439d473bSArnaldo Carvalho de Melo 1716439d473bSArnaldo Carvalho de Melo while (!feof(file)) { 1717439d473bSArnaldo Carvalho de Melo char name[PATH_MAX]; 1718439d473bSArnaldo Carvalho de Melo u64 start; 1719439d473bSArnaldo Carvalho de Melo char *sep; 1720439d473bSArnaldo Carvalho de Melo int line_len; 1721439d473bSArnaldo Carvalho de Melo 1722439d473bSArnaldo Carvalho de Melo line_len = getline(&line, &n, file); 1723439d473bSArnaldo Carvalho de Melo if (line_len < 0) 17246cfcc53eSMike Galbraith break; 17256cfcc53eSMike Galbraith 1726439d473bSArnaldo Carvalho de Melo if (!line) 1727439d473bSArnaldo Carvalho de Melo goto out_failure; 1728439d473bSArnaldo Carvalho de Melo 1729439d473bSArnaldo Carvalho de Melo line[--line_len] = '\0'; /* \n */ 1730439d473bSArnaldo Carvalho de Melo 1731439d473bSArnaldo Carvalho de Melo sep = strrchr(line, 'x'); 1732439d473bSArnaldo Carvalho de Melo if (sep == NULL) 1733439d473bSArnaldo Carvalho de Melo continue; 1734439d473bSArnaldo Carvalho de Melo 1735439d473bSArnaldo Carvalho de Melo hex2u64(sep + 1, &start); 1736439d473bSArnaldo Carvalho de Melo 1737439d473bSArnaldo Carvalho de Melo sep = strchr(line, ' '); 1738439d473bSArnaldo Carvalho de Melo if (sep == NULL) 1739439d473bSArnaldo Carvalho de Melo continue; 1740439d473bSArnaldo Carvalho de Melo 1741439d473bSArnaldo Carvalho de Melo *sep = '\0'; 1742439d473bSArnaldo Carvalho de Melo 1743439d473bSArnaldo Carvalho de Melo snprintf(name, sizeof(name), "[%s]", line); 1744d28c6223SArnaldo Carvalho de Melo map = machine__new_module(self, start, name); 1745b7cece76SArnaldo Carvalho de Melo if (map == NULL) 1746439d473bSArnaldo Carvalho de Melo goto out_delete_line; 1747d28c6223SArnaldo Carvalho de Melo dso__kernel_module_get_build_id(map->dso, self->root_dir); 17486cfcc53eSMike Galbraith } 17496cfcc53eSMike Galbraith 1750439d473bSArnaldo Carvalho de Melo free(line); 1751439d473bSArnaldo Carvalho de Melo fclose(file); 1752439d473bSArnaldo Carvalho de Melo 1753d28c6223SArnaldo Carvalho de Melo return machine__set_modules_path(self); 1754439d473bSArnaldo Carvalho de Melo 1755439d473bSArnaldo Carvalho de Melo out_delete_line: 1756439d473bSArnaldo Carvalho de Melo free(line); 1757439d473bSArnaldo Carvalho de Melo out_failure: 1758439d473bSArnaldo Carvalho de Melo return -1; 17596cfcc53eSMike Galbraith } 17606cfcc53eSMike Galbraith 17619958e1f0SArnaldo Carvalho de Melo static int dso__load_vmlinux(struct dso *self, struct map *map, 17626beba7adSArnaldo Carvalho de Melo const char *vmlinux, symbol_filter_t filter) 176386470930SIngo Molnar { 1764fbd733b8SArnaldo Carvalho de Melo int err = -1, fd; 176586470930SIngo Molnar 1766fbd733b8SArnaldo Carvalho de Melo fd = open(vmlinux, O_RDONLY); 176786470930SIngo Molnar if (fd < 0) 176886470930SIngo Molnar return -1; 176986470930SIngo Molnar 17703610583cSArnaldo Carvalho de Melo dso__set_loaded(self, map->type); 17716da80ce8SDave Martin err = dso__load_sym(self, map, vmlinux, fd, filter, 0, 0); 177286470930SIngo Molnar close(fd); 177386470930SIngo Molnar 17743846df2eSArnaldo Carvalho de Melo if (err > 0) 17753846df2eSArnaldo Carvalho de Melo pr_debug("Using %s for symbols\n", vmlinux); 17763846df2eSArnaldo Carvalho de Melo 177786470930SIngo Molnar return err; 177886470930SIngo Molnar } 177986470930SIngo Molnar 1780a19afe46SArnaldo Carvalho de Melo int dso__load_vmlinux_path(struct dso *self, struct map *map, 17819de89fe7SArnaldo Carvalho de Melo symbol_filter_t filter) 1782a19afe46SArnaldo Carvalho de Melo { 1783a19afe46SArnaldo Carvalho de Melo int i, err = 0; 17845ad90e4eSArnaldo Carvalho de Melo char *filename; 1785a19afe46SArnaldo Carvalho de Melo 1786a19afe46SArnaldo Carvalho de Melo pr_debug("Looking at the vmlinux_path (%d entries long)\n", 17875ad90e4eSArnaldo Carvalho de Melo vmlinux_path__nr_entries + 1); 17885ad90e4eSArnaldo Carvalho de Melo 17895ad90e4eSArnaldo Carvalho de Melo filename = dso__build_id_filename(self, NULL, 0); 17905ad90e4eSArnaldo Carvalho de Melo if (filename != NULL) { 17915ad90e4eSArnaldo Carvalho de Melo err = dso__load_vmlinux(self, map, filename, filter); 17925ad90e4eSArnaldo Carvalho de Melo if (err > 0) { 17935ad90e4eSArnaldo Carvalho de Melo dso__set_long_name(self, filename); 17945ad90e4eSArnaldo Carvalho de Melo goto out; 17955ad90e4eSArnaldo Carvalho de Melo } 17965ad90e4eSArnaldo Carvalho de Melo free(filename); 17975ad90e4eSArnaldo Carvalho de Melo } 1798a19afe46SArnaldo Carvalho de Melo 1799a19afe46SArnaldo Carvalho de Melo for (i = 0; i < vmlinux_path__nr_entries; ++i) { 18009de89fe7SArnaldo Carvalho de Melo err = dso__load_vmlinux(self, map, vmlinux_path[i], filter); 1801a19afe46SArnaldo Carvalho de Melo if (err > 0) { 1802a19afe46SArnaldo Carvalho de Melo dso__set_long_name(self, strdup(vmlinux_path[i])); 1803a19afe46SArnaldo Carvalho de Melo break; 1804a19afe46SArnaldo Carvalho de Melo } 1805a19afe46SArnaldo Carvalho de Melo } 18065ad90e4eSArnaldo Carvalho de Melo out: 1807a19afe46SArnaldo Carvalho de Melo return err; 1808a19afe46SArnaldo Carvalho de Melo } 1809a19afe46SArnaldo Carvalho de Melo 1810c338aee8SArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *self, struct map *map, 18119de89fe7SArnaldo Carvalho de Melo symbol_filter_t filter) 181286470930SIngo Molnar { 1813cc612d81SArnaldo Carvalho de Melo int err; 18149e201442SArnaldo Carvalho de Melo const char *kallsyms_filename = NULL; 18159e201442SArnaldo Carvalho de Melo char *kallsyms_allocated_filename = NULL; 1816dc8d6ab2SArnaldo Carvalho de Melo /* 1817dc8d6ab2SArnaldo Carvalho de Melo * Step 1: if the user specified a vmlinux filename, use it and only 1818dc8d6ab2SArnaldo Carvalho de Melo * it, reporting errors to the user if it cannot be used. 1819dc8d6ab2SArnaldo Carvalho de Melo * 1820dc8d6ab2SArnaldo Carvalho de Melo * For instance, try to analyse an ARM perf.data file _without_ a 1821dc8d6ab2SArnaldo Carvalho de Melo * build-id, or if the user specifies the wrong path to the right 1822dc8d6ab2SArnaldo Carvalho de Melo * vmlinux file, obviously we can't fallback to another vmlinux (a 1823dc8d6ab2SArnaldo Carvalho de Melo * x86_86 one, on the machine where analysis is being performed, say), 1824dc8d6ab2SArnaldo Carvalho de Melo * or worse, /proc/kallsyms. 1825dc8d6ab2SArnaldo Carvalho de Melo * 1826dc8d6ab2SArnaldo Carvalho de Melo * If the specified file _has_ a build-id and there is a build-id 1827dc8d6ab2SArnaldo Carvalho de Melo * section in the perf.data file, we will still do the expected 1828dc8d6ab2SArnaldo Carvalho de Melo * validation in dso__load_vmlinux and will bail out if they don't 1829dc8d6ab2SArnaldo Carvalho de Melo * match. 1830dc8d6ab2SArnaldo Carvalho de Melo */ 1831dc8d6ab2SArnaldo Carvalho de Melo if (symbol_conf.vmlinux_name != NULL) { 18329de89fe7SArnaldo Carvalho de Melo err = dso__load_vmlinux(self, map, 1833dc8d6ab2SArnaldo Carvalho de Melo symbol_conf.vmlinux_name, filter); 1834e7dadc00SArnaldo Carvalho de Melo if (err > 0) { 1835e7dadc00SArnaldo Carvalho de Melo dso__set_long_name(self, 1836e7dadc00SArnaldo Carvalho de Melo strdup(symbol_conf.vmlinux_name)); 1837e7dadc00SArnaldo Carvalho de Melo goto out_fixup; 1838e7dadc00SArnaldo Carvalho de Melo } 1839e7dadc00SArnaldo Carvalho de Melo return err; 1840dc8d6ab2SArnaldo Carvalho de Melo } 1841439d473bSArnaldo Carvalho de Melo 1842cc612d81SArnaldo Carvalho de Melo if (vmlinux_path != NULL) { 18439de89fe7SArnaldo Carvalho de Melo err = dso__load_vmlinux_path(self, map, filter); 1844a19afe46SArnaldo Carvalho de Melo if (err > 0) 1845cc612d81SArnaldo Carvalho de Melo goto out_fixup; 1846cc612d81SArnaldo Carvalho de Melo } 1847cc612d81SArnaldo Carvalho de Melo 1848b7cece76SArnaldo Carvalho de Melo /* 1849b7cece76SArnaldo Carvalho de Melo * Say the kernel DSO was created when processing the build-id header table, 1850b7cece76SArnaldo Carvalho de Melo * we have a build-id, so check if it is the same as the running kernel, 1851b7cece76SArnaldo Carvalho de Melo * using it if it is. 1852b7cece76SArnaldo Carvalho de Melo */ 1853b7cece76SArnaldo Carvalho de Melo if (self->has_build_id) { 1854b7cece76SArnaldo Carvalho de Melo u8 kallsyms_build_id[BUILD_ID_SIZE]; 18559e201442SArnaldo Carvalho de Melo char sbuild_id[BUILD_ID_SIZE * 2 + 1]; 1856b7cece76SArnaldo Carvalho de Melo 1857b7cece76SArnaldo Carvalho de Melo if (sysfs__read_build_id("/sys/kernel/notes", kallsyms_build_id, 18588d0591f6SArnaldo Carvalho de Melo sizeof(kallsyms_build_id)) == 0) { 18599e201442SArnaldo Carvalho de Melo if (dso__build_id_equal(self, kallsyms_build_id)) { 18609e201442SArnaldo Carvalho de Melo kallsyms_filename = "/proc/kallsyms"; 1861b7cece76SArnaldo Carvalho de Melo goto do_kallsyms; 18628d0591f6SArnaldo Carvalho de Melo } 18639e201442SArnaldo Carvalho de Melo } 1864dc8d6ab2SArnaldo Carvalho de Melo /* 1865dc8d6ab2SArnaldo Carvalho de Melo * Now look if we have it on the build-id cache in 1866dc8d6ab2SArnaldo Carvalho de Melo * $HOME/.debug/[kernel.kallsyms]. 1867dc8d6ab2SArnaldo Carvalho de Melo */ 18689e201442SArnaldo Carvalho de Melo build_id__sprintf(self->build_id, sizeof(self->build_id), 18699e201442SArnaldo Carvalho de Melo sbuild_id); 18709e201442SArnaldo Carvalho de Melo 18719e201442SArnaldo Carvalho de Melo if (asprintf(&kallsyms_allocated_filename, 18729e201442SArnaldo Carvalho de Melo "%s/.debug/[kernel.kallsyms]/%s", 18733846df2eSArnaldo Carvalho de Melo getenv("HOME"), sbuild_id) == -1) { 18743846df2eSArnaldo Carvalho de Melo pr_err("Not enough memory for kallsyms file lookup\n"); 18758d0591f6SArnaldo Carvalho de Melo return -1; 18763846df2eSArnaldo Carvalho de Melo } 18778d0591f6SArnaldo Carvalho de Melo 187819fc2dedSArnaldo Carvalho de Melo kallsyms_filename = kallsyms_allocated_filename; 187919fc2dedSArnaldo Carvalho de Melo 1880dc8d6ab2SArnaldo Carvalho de Melo if (access(kallsyms_filename, F_OK)) { 18813846df2eSArnaldo Carvalho de Melo pr_err("No kallsyms or vmlinux with build-id %s " 18823846df2eSArnaldo Carvalho de Melo "was found\n", sbuild_id); 18839e201442SArnaldo Carvalho de Melo free(kallsyms_allocated_filename); 1884dc8d6ab2SArnaldo Carvalho de Melo return -1; 1885ef6ae724SArnaldo Carvalho de Melo } 1886dc8d6ab2SArnaldo Carvalho de Melo } else { 1887dc8d6ab2SArnaldo Carvalho de Melo /* 1888dc8d6ab2SArnaldo Carvalho de Melo * Last resort, if we don't have a build-id and couldn't find 1889dc8d6ab2SArnaldo Carvalho de Melo * any vmlinux file, try the running kernel kallsyms table. 1890dc8d6ab2SArnaldo Carvalho de Melo */ 1891dc8d6ab2SArnaldo Carvalho de Melo kallsyms_filename = "/proc/kallsyms"; 1892dc8d6ab2SArnaldo Carvalho de Melo } 1893dc8d6ab2SArnaldo Carvalho de Melo 1894dc8d6ab2SArnaldo Carvalho de Melo do_kallsyms: 18959de89fe7SArnaldo Carvalho de Melo err = dso__load_kallsyms(self, kallsyms_filename, map, filter); 18963846df2eSArnaldo Carvalho de Melo if (err > 0) 18973846df2eSArnaldo Carvalho de Melo pr_debug("Using %s for symbols\n", kallsyms_filename); 1898dc8d6ab2SArnaldo Carvalho de Melo free(kallsyms_allocated_filename); 1899dc8d6ab2SArnaldo Carvalho de Melo 1900439d473bSArnaldo Carvalho de Melo if (err > 0) { 1901cc612d81SArnaldo Carvalho de Melo out_fixup: 1902e1c7c6a4SArnaldo Carvalho de Melo if (kallsyms_filename != NULL) 1903dc8d6ab2SArnaldo Carvalho de Melo dso__set_long_name(self, strdup("[kernel.kallsyms]")); 19046a4694a4SArnaldo Carvalho de Melo map__fixup_start(map); 19056a4694a4SArnaldo Carvalho de Melo map__fixup_end(map); 1906439d473bSArnaldo Carvalho de Melo } 190794cb9e38SArnaldo Carvalho de Melo 190886470930SIngo Molnar return err; 190986470930SIngo Molnar } 191086470930SIngo Molnar 1911a1645ce1SZhang, Yanmin static int dso__load_guest_kernel_sym(struct dso *self, struct map *map, 1912a1645ce1SZhang, Yanmin symbol_filter_t filter) 1913a1645ce1SZhang, Yanmin { 1914a1645ce1SZhang, Yanmin int err; 1915a1645ce1SZhang, Yanmin const char *kallsyms_filename = NULL; 191623346f21SArnaldo Carvalho de Melo struct machine *machine; 1917a1645ce1SZhang, Yanmin char path[PATH_MAX]; 1918a1645ce1SZhang, Yanmin 1919a1645ce1SZhang, Yanmin if (!map->groups) { 1920a1645ce1SZhang, Yanmin pr_debug("Guest kernel map hasn't the point to groups\n"); 1921a1645ce1SZhang, Yanmin return -1; 1922a1645ce1SZhang, Yanmin } 192323346f21SArnaldo Carvalho de Melo machine = map->groups->machine; 1924a1645ce1SZhang, Yanmin 192523346f21SArnaldo Carvalho de Melo if (machine__is_default_guest(machine)) { 1926a1645ce1SZhang, Yanmin /* 1927a1645ce1SZhang, Yanmin * if the user specified a vmlinux filename, use it and only 1928a1645ce1SZhang, Yanmin * it, reporting errors to the user if it cannot be used. 1929a1645ce1SZhang, Yanmin * Or use file guest_kallsyms inputted by user on commandline 1930a1645ce1SZhang, Yanmin */ 1931a1645ce1SZhang, Yanmin if (symbol_conf.default_guest_vmlinux_name != NULL) { 1932a1645ce1SZhang, Yanmin err = dso__load_vmlinux(self, map, 1933a1645ce1SZhang, Yanmin symbol_conf.default_guest_vmlinux_name, filter); 1934a1645ce1SZhang, Yanmin goto out_try_fixup; 1935a1645ce1SZhang, Yanmin } 1936a1645ce1SZhang, Yanmin 1937a1645ce1SZhang, Yanmin kallsyms_filename = symbol_conf.default_guest_kallsyms; 1938a1645ce1SZhang, Yanmin if (!kallsyms_filename) 1939a1645ce1SZhang, Yanmin return -1; 1940a1645ce1SZhang, Yanmin } else { 194123346f21SArnaldo Carvalho de Melo sprintf(path, "%s/proc/kallsyms", machine->root_dir); 1942a1645ce1SZhang, Yanmin kallsyms_filename = path; 1943a1645ce1SZhang, Yanmin } 1944a1645ce1SZhang, Yanmin 1945a1645ce1SZhang, Yanmin err = dso__load_kallsyms(self, kallsyms_filename, map, filter); 1946a1645ce1SZhang, Yanmin if (err > 0) 1947a1645ce1SZhang, Yanmin pr_debug("Using %s for symbols\n", kallsyms_filename); 1948a1645ce1SZhang, Yanmin 1949a1645ce1SZhang, Yanmin out_try_fixup: 1950a1645ce1SZhang, Yanmin if (err > 0) { 1951a1645ce1SZhang, Yanmin if (kallsyms_filename != NULL) { 195248ea8f54SArnaldo Carvalho de Melo machine__mmap_name(machine, path, sizeof(path)); 195323346f21SArnaldo Carvalho de Melo dso__set_long_name(self, strdup(path)); 1954a1645ce1SZhang, Yanmin } 1955a1645ce1SZhang, Yanmin map__fixup_start(map); 1956a1645ce1SZhang, Yanmin map__fixup_end(map); 1957a1645ce1SZhang, Yanmin } 1958a1645ce1SZhang, Yanmin 1959a1645ce1SZhang, Yanmin return err; 1960a1645ce1SZhang, Yanmin } 1961cd84c2acSFrederic Weisbecker 1962b0da954aSArnaldo Carvalho de Melo static void dsos__add(struct list_head *head, struct dso *dso) 1963cd84c2acSFrederic Weisbecker { 1964b0da954aSArnaldo Carvalho de Melo list_add_tail(&dso->node, head); 1965cd84c2acSFrederic Weisbecker } 1966cd84c2acSFrederic Weisbecker 1967b0da954aSArnaldo Carvalho de Melo static struct dso *dsos__find(struct list_head *head, const char *name) 1968cd84c2acSFrederic Weisbecker { 1969cd84c2acSFrederic Weisbecker struct dso *pos; 1970cd84c2acSFrederic Weisbecker 1971b0da954aSArnaldo Carvalho de Melo list_for_each_entry(pos, head, node) 1972cf4e5b08SArnaldo Carvalho de Melo if (strcmp(pos->long_name, name) == 0) 1973cd84c2acSFrederic Weisbecker return pos; 1974cd84c2acSFrederic Weisbecker return NULL; 1975cd84c2acSFrederic Weisbecker } 1976cd84c2acSFrederic Weisbecker 1977a89e5abeSArnaldo Carvalho de Melo struct dso *__dsos__findnew(struct list_head *head, const char *name) 1978cd84c2acSFrederic Weisbecker { 1979a89e5abeSArnaldo Carvalho de Melo struct dso *dso = dsos__find(head, name); 1980cd84c2acSFrederic Weisbecker 1981e4204992SArnaldo Carvalho de Melo if (!dso) { 198200a192b3SArnaldo Carvalho de Melo dso = dso__new(name); 1983cfc10d3bSArnaldo Carvalho de Melo if (dso != NULL) { 1984a89e5abeSArnaldo Carvalho de Melo dsos__add(head, dso); 1985cfc10d3bSArnaldo Carvalho de Melo dso__set_basename(dso); 1986cfc10d3bSArnaldo Carvalho de Melo } 1987e4204992SArnaldo Carvalho de Melo } 1988cd84c2acSFrederic Weisbecker 1989cd84c2acSFrederic Weisbecker return dso; 1990cd84c2acSFrederic Weisbecker } 1991cd84c2acSFrederic Weisbecker 19921f626bc3SArnaldo Carvalho de Melo size_t __dsos__fprintf(struct list_head *head, FILE *fp) 1993cd84c2acSFrederic Weisbecker { 1994cd84c2acSFrederic Weisbecker struct dso *pos; 1995cbf69680SArnaldo Carvalho de Melo size_t ret = 0; 1996cd84c2acSFrederic Weisbecker 199795011c60SArnaldo Carvalho de Melo list_for_each_entry(pos, head, node) { 199895011c60SArnaldo Carvalho de Melo int i; 199995011c60SArnaldo Carvalho de Melo for (i = 0; i < MAP__NR_TYPES; ++i) 2000cbf69680SArnaldo Carvalho de Melo ret += dso__fprintf(pos, i, fp); 2001cd84c2acSFrederic Weisbecker } 2002cd84c2acSFrederic Weisbecker 2003cbf69680SArnaldo Carvalho de Melo return ret; 2004cbf69680SArnaldo Carvalho de Melo } 2005cbf69680SArnaldo Carvalho de Melo 2006cbf69680SArnaldo Carvalho de Melo size_t machines__fprintf_dsos(struct rb_root *self, FILE *fp) 2007b0da954aSArnaldo Carvalho de Melo { 2008a1645ce1SZhang, Yanmin struct rb_node *nd; 2009cbf69680SArnaldo Carvalho de Melo size_t ret = 0; 2010a1645ce1SZhang, Yanmin 2011cbf69680SArnaldo Carvalho de Melo for (nd = rb_first(self); nd; nd = rb_next(nd)) { 201223346f21SArnaldo Carvalho de Melo struct machine *pos = rb_entry(nd, struct machine, rb_node); 2013cbf69680SArnaldo Carvalho de Melo ret += __dsos__fprintf(&pos->kernel_dsos, fp); 2014cbf69680SArnaldo Carvalho de Melo ret += __dsos__fprintf(&pos->user_dsos, fp); 2015a1645ce1SZhang, Yanmin } 2016cbf69680SArnaldo Carvalho de Melo 2017cbf69680SArnaldo Carvalho de Melo return ret; 2018b0da954aSArnaldo Carvalho de Melo } 2019b0da954aSArnaldo Carvalho de Melo 202088d3d9b7SArnaldo Carvalho de Melo static size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp, 202188d3d9b7SArnaldo Carvalho de Melo bool with_hits) 20229e03eb2dSArnaldo Carvalho de Melo { 20239e03eb2dSArnaldo Carvalho de Melo struct dso *pos; 20249e03eb2dSArnaldo Carvalho de Melo size_t ret = 0; 20259e03eb2dSArnaldo Carvalho de Melo 2026b0da954aSArnaldo Carvalho de Melo list_for_each_entry(pos, head, node) { 202788d3d9b7SArnaldo Carvalho de Melo if (with_hits && !pos->hit) 202888d3d9b7SArnaldo Carvalho de Melo continue; 20299e03eb2dSArnaldo Carvalho de Melo ret += dso__fprintf_buildid(pos, fp); 20309e03eb2dSArnaldo Carvalho de Melo ret += fprintf(fp, " %s\n", pos->long_name); 20319e03eb2dSArnaldo Carvalho de Melo } 20329e03eb2dSArnaldo Carvalho de Melo return ret; 20339e03eb2dSArnaldo Carvalho de Melo } 20349e03eb2dSArnaldo Carvalho de Melo 2035f869097eSArnaldo Carvalho de Melo size_t machine__fprintf_dsos_buildid(struct machine *self, FILE *fp, bool with_hits) 2036f869097eSArnaldo Carvalho de Melo { 2037f869097eSArnaldo Carvalho de Melo return __dsos__fprintf_buildid(&self->kernel_dsos, fp, with_hits) + 2038f869097eSArnaldo Carvalho de Melo __dsos__fprintf_buildid(&self->user_dsos, fp, with_hits); 2039f869097eSArnaldo Carvalho de Melo } 2040f869097eSArnaldo Carvalho de Melo 2041cbf69680SArnaldo Carvalho de Melo size_t machines__fprintf_dsos_buildid(struct rb_root *self, FILE *fp, bool with_hits) 2042b0da954aSArnaldo Carvalho de Melo { 2043a1645ce1SZhang, Yanmin struct rb_node *nd; 2044a1645ce1SZhang, Yanmin size_t ret = 0; 2045a1645ce1SZhang, Yanmin 2046cbf69680SArnaldo Carvalho de Melo for (nd = rb_first(self); nd; nd = rb_next(nd)) { 204723346f21SArnaldo Carvalho de Melo struct machine *pos = rb_entry(nd, struct machine, rb_node); 2048f869097eSArnaldo Carvalho de Melo ret += machine__fprintf_dsos_buildid(pos, fp, with_hits); 2049a1645ce1SZhang, Yanmin } 2050a1645ce1SZhang, Yanmin return ret; 2051b0da954aSArnaldo Carvalho de Melo } 2052b0da954aSArnaldo Carvalho de Melo 2053fd1d908cSArnaldo Carvalho de Melo struct dso *dso__new_kernel(const char *name) 2054fd1d908cSArnaldo Carvalho de Melo { 2055fd1d908cSArnaldo Carvalho de Melo struct dso *self = dso__new(name ?: "[kernel.kallsyms]"); 2056fd1d908cSArnaldo Carvalho de Melo 2057fd1d908cSArnaldo Carvalho de Melo if (self != NULL) { 2058b63be8d7SArnaldo Carvalho de Melo dso__set_short_name(self, "[kernel]"); 2059a1645ce1SZhang, Yanmin self->kernel = DSO_TYPE_KERNEL; 2060fd1d908cSArnaldo Carvalho de Melo } 2061fd1d908cSArnaldo Carvalho de Melo 2062fd1d908cSArnaldo Carvalho de Melo return self; 2063fd1d908cSArnaldo Carvalho de Melo } 2064fd1d908cSArnaldo Carvalho de Melo 206523346f21SArnaldo Carvalho de Melo static struct dso *dso__new_guest_kernel(struct machine *machine, 2066a1645ce1SZhang, Yanmin const char *name) 2067fd1d908cSArnaldo Carvalho de Melo { 206848ea8f54SArnaldo Carvalho de Melo char bf[PATH_MAX]; 206948ea8f54SArnaldo Carvalho de Melo struct dso *self = dso__new(name ?: machine__mmap_name(machine, bf, sizeof(bf))); 2070a1645ce1SZhang, Yanmin 2071a1645ce1SZhang, Yanmin if (self != NULL) { 2072a1645ce1SZhang, Yanmin dso__set_short_name(self, "[guest.kernel]"); 2073a1645ce1SZhang, Yanmin self->kernel = DSO_TYPE_GUEST_KERNEL; 2074a1645ce1SZhang, Yanmin } 2075a1645ce1SZhang, Yanmin 2076a1645ce1SZhang, Yanmin return self; 2077a1645ce1SZhang, Yanmin } 2078a1645ce1SZhang, Yanmin 207923346f21SArnaldo Carvalho de Melo void dso__read_running_kernel_build_id(struct dso *self, struct machine *machine) 2080a1645ce1SZhang, Yanmin { 2081a1645ce1SZhang, Yanmin char path[PATH_MAX]; 2082a1645ce1SZhang, Yanmin 208323346f21SArnaldo Carvalho de Melo if (machine__is_default_guest(machine)) 2084a1645ce1SZhang, Yanmin return; 208523346f21SArnaldo Carvalho de Melo sprintf(path, "%s/sys/kernel/notes", machine->root_dir); 2086a1645ce1SZhang, Yanmin if (sysfs__read_build_id(path, self->build_id, 2087fd1d908cSArnaldo Carvalho de Melo sizeof(self->build_id)) == 0) 2088fd1d908cSArnaldo Carvalho de Melo self->has_build_id = true; 2089fd1d908cSArnaldo Carvalho de Melo } 2090fd1d908cSArnaldo Carvalho de Melo 20915c0541d5SArnaldo Carvalho de Melo static struct dso *machine__create_kernel(struct machine *self) 2092cd84c2acSFrederic Weisbecker { 2093a1645ce1SZhang, Yanmin const char *vmlinux_name = NULL; 2094a1645ce1SZhang, Yanmin struct dso *kernel; 2095cd84c2acSFrederic Weisbecker 20965c0541d5SArnaldo Carvalho de Melo if (machine__is_host(self)) { 2097a1645ce1SZhang, Yanmin vmlinux_name = symbol_conf.vmlinux_name; 2098a1645ce1SZhang, Yanmin kernel = dso__new_kernel(vmlinux_name); 2099a1645ce1SZhang, Yanmin } else { 21005c0541d5SArnaldo Carvalho de Melo if (machine__is_default_guest(self)) 2101a1645ce1SZhang, Yanmin vmlinux_name = symbol_conf.default_guest_vmlinux_name; 21025c0541d5SArnaldo Carvalho de Melo kernel = dso__new_guest_kernel(self, vmlinux_name); 21038d92c02aSArnaldo Carvalho de Melo } 2104cd84c2acSFrederic Weisbecker 2105a1645ce1SZhang, Yanmin if (kernel != NULL) { 21065c0541d5SArnaldo Carvalho de Melo dso__read_running_kernel_build_id(kernel, self); 21075c0541d5SArnaldo Carvalho de Melo dsos__add(&self->kernel_dsos, kernel); 2108a1645ce1SZhang, Yanmin } 2109f1dfa0b1SArnaldo Carvalho de Melo return kernel; 2110f1dfa0b1SArnaldo Carvalho de Melo } 2111f1dfa0b1SArnaldo Carvalho de Melo 2112d28c6223SArnaldo Carvalho de Melo int __machine__create_kernel_maps(struct machine *self, struct dso *kernel) 2113f1dfa0b1SArnaldo Carvalho de Melo { 2114de176489SArnaldo Carvalho de Melo enum map_type type; 2115f1dfa0b1SArnaldo Carvalho de Melo 2116de176489SArnaldo Carvalho de Melo for (type = 0; type < MAP__NR_TYPES; ++type) { 21179de89fe7SArnaldo Carvalho de Melo struct kmap *kmap; 21189de89fe7SArnaldo Carvalho de Melo 2119d28c6223SArnaldo Carvalho de Melo self->vmlinux_maps[type] = map__new2(0, kernel, type); 2120d28c6223SArnaldo Carvalho de Melo if (self->vmlinux_maps[type] == NULL) 2121f1dfa0b1SArnaldo Carvalho de Melo return -1; 2122f1dfa0b1SArnaldo Carvalho de Melo 2123d28c6223SArnaldo Carvalho de Melo self->vmlinux_maps[type]->map_ip = 2124d28c6223SArnaldo Carvalho de Melo self->vmlinux_maps[type]->unmap_ip = identity__map_ip; 21259de89fe7SArnaldo Carvalho de Melo 2126d28c6223SArnaldo Carvalho de Melo kmap = map__kmap(self->vmlinux_maps[type]); 2127d28c6223SArnaldo Carvalho de Melo kmap->kmaps = &self->kmaps; 2128d28c6223SArnaldo Carvalho de Melo map_groups__insert(&self->kmaps, self->vmlinux_maps[type]); 2129f1dfa0b1SArnaldo Carvalho de Melo } 2130f1dfa0b1SArnaldo Carvalho de Melo 2131f1dfa0b1SArnaldo Carvalho de Melo return 0; 21322446042cSArnaldo Carvalho de Melo } 21332446042cSArnaldo Carvalho de Melo 2134076c6e45SArnaldo Carvalho de Melo void machine__destroy_kernel_maps(struct machine *self) 2135076c6e45SArnaldo Carvalho de Melo { 2136076c6e45SArnaldo Carvalho de Melo enum map_type type; 2137076c6e45SArnaldo Carvalho de Melo 2138076c6e45SArnaldo Carvalho de Melo for (type = 0; type < MAP__NR_TYPES; ++type) { 2139076c6e45SArnaldo Carvalho de Melo struct kmap *kmap; 2140076c6e45SArnaldo Carvalho de Melo 2141076c6e45SArnaldo Carvalho de Melo if (self->vmlinux_maps[type] == NULL) 2142076c6e45SArnaldo Carvalho de Melo continue; 2143076c6e45SArnaldo Carvalho de Melo 2144076c6e45SArnaldo Carvalho de Melo kmap = map__kmap(self->vmlinux_maps[type]); 2145076c6e45SArnaldo Carvalho de Melo map_groups__remove(&self->kmaps, self->vmlinux_maps[type]); 2146076c6e45SArnaldo Carvalho de Melo if (kmap->ref_reloc_sym) { 2147076c6e45SArnaldo Carvalho de Melo /* 2148076c6e45SArnaldo Carvalho de Melo * ref_reloc_sym is shared among all maps, so free just 2149076c6e45SArnaldo Carvalho de Melo * on one of them. 2150076c6e45SArnaldo Carvalho de Melo */ 2151076c6e45SArnaldo Carvalho de Melo if (type == MAP__FUNCTION) { 2152076c6e45SArnaldo Carvalho de Melo free((char *)kmap->ref_reloc_sym->name); 2153076c6e45SArnaldo Carvalho de Melo kmap->ref_reloc_sym->name = NULL; 2154076c6e45SArnaldo Carvalho de Melo free(kmap->ref_reloc_sym); 2155076c6e45SArnaldo Carvalho de Melo } 2156076c6e45SArnaldo Carvalho de Melo kmap->ref_reloc_sym = NULL; 2157076c6e45SArnaldo Carvalho de Melo } 2158076c6e45SArnaldo Carvalho de Melo 2159076c6e45SArnaldo Carvalho de Melo map__delete(self->vmlinux_maps[type]); 2160076c6e45SArnaldo Carvalho de Melo self->vmlinux_maps[type] = NULL; 2161076c6e45SArnaldo Carvalho de Melo } 2162076c6e45SArnaldo Carvalho de Melo } 2163076c6e45SArnaldo Carvalho de Melo 21645c0541d5SArnaldo Carvalho de Melo int machine__create_kernel_maps(struct machine *self) 21655c0541d5SArnaldo Carvalho de Melo { 21665c0541d5SArnaldo Carvalho de Melo struct dso *kernel = machine__create_kernel(self); 21675c0541d5SArnaldo Carvalho de Melo 21685c0541d5SArnaldo Carvalho de Melo if (kernel == NULL || 21695c0541d5SArnaldo Carvalho de Melo __machine__create_kernel_maps(self, kernel) < 0) 21705c0541d5SArnaldo Carvalho de Melo return -1; 21715c0541d5SArnaldo Carvalho de Melo 21725c0541d5SArnaldo Carvalho de Melo if (symbol_conf.use_modules && machine__create_modules(self) < 0) 21735c0541d5SArnaldo Carvalho de Melo pr_debug("Problems creating module maps, continuing anyway...\n"); 21745c0541d5SArnaldo Carvalho de Melo /* 21755c0541d5SArnaldo Carvalho de Melo * Now that we have all the maps created, just set the ->end of them: 21765c0541d5SArnaldo Carvalho de Melo */ 21775c0541d5SArnaldo Carvalho de Melo map_groups__fixup_end(&self->kmaps); 21785c0541d5SArnaldo Carvalho de Melo return 0; 21795c0541d5SArnaldo Carvalho de Melo } 21805c0541d5SArnaldo Carvalho de Melo 2181cc612d81SArnaldo Carvalho de Melo static void vmlinux_path__exit(void) 21822446042cSArnaldo Carvalho de Melo { 2183cc612d81SArnaldo Carvalho de Melo while (--vmlinux_path__nr_entries >= 0) { 2184cc612d81SArnaldo Carvalho de Melo free(vmlinux_path[vmlinux_path__nr_entries]); 2185cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = NULL; 2186cc612d81SArnaldo Carvalho de Melo } 2187cc612d81SArnaldo Carvalho de Melo 2188cc612d81SArnaldo Carvalho de Melo free(vmlinux_path); 2189cc612d81SArnaldo Carvalho de Melo vmlinux_path = NULL; 2190cc612d81SArnaldo Carvalho de Melo } 2191cc612d81SArnaldo Carvalho de Melo 2192cc612d81SArnaldo Carvalho de Melo static int vmlinux_path__init(void) 2193cc612d81SArnaldo Carvalho de Melo { 2194cc612d81SArnaldo Carvalho de Melo struct utsname uts; 2195cc612d81SArnaldo Carvalho de Melo char bf[PATH_MAX]; 2196cc612d81SArnaldo Carvalho de Melo 2197cc612d81SArnaldo Carvalho de Melo if (uname(&uts) < 0) 21982446042cSArnaldo Carvalho de Melo return -1; 21992446042cSArnaldo Carvalho de Melo 2200cc612d81SArnaldo Carvalho de Melo vmlinux_path = malloc(sizeof(char *) * 5); 2201cc612d81SArnaldo Carvalho de Melo if (vmlinux_path == NULL) 2202cc612d81SArnaldo Carvalho de Melo return -1; 2203cc612d81SArnaldo Carvalho de Melo 2204cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup("vmlinux"); 2205cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 2206cc612d81SArnaldo Carvalho de Melo goto out_fail; 2207cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 2208cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup("/boot/vmlinux"); 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), "/boot/vmlinux-%s", uts.release); 2213cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); 2214cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 2215cc612d81SArnaldo Carvalho de Melo goto out_fail; 2216cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 2217cc612d81SArnaldo Carvalho de Melo snprintf(bf, sizeof(bf), "/lib/modules/%s/build/vmlinux", uts.release); 2218cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); 2219cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 2220cc612d81SArnaldo Carvalho de Melo goto out_fail; 2221cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 2222cc612d81SArnaldo Carvalho de Melo snprintf(bf, sizeof(bf), "/usr/lib/debug/lib/modules/%s/vmlinux", 2223cc612d81SArnaldo Carvalho de Melo uts.release); 2224cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); 2225cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 2226cc612d81SArnaldo Carvalho de Melo goto out_fail; 2227cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 2228cc612d81SArnaldo Carvalho de Melo 2229cc612d81SArnaldo Carvalho de Melo return 0; 2230cc612d81SArnaldo Carvalho de Melo 2231cc612d81SArnaldo Carvalho de Melo out_fail: 2232cc612d81SArnaldo Carvalho de Melo vmlinux_path__exit(); 2233cc612d81SArnaldo Carvalho de Melo return -1; 2234cc612d81SArnaldo Carvalho de Melo } 2235cc612d81SArnaldo Carvalho de Melo 22365ad90e4eSArnaldo Carvalho de Melo size_t machine__fprintf_vmlinux_path(struct machine *self, FILE *fp) 2237b0a9ab62SArnaldo Carvalho de Melo { 2238b0a9ab62SArnaldo Carvalho de Melo int i; 2239b0a9ab62SArnaldo Carvalho de Melo size_t printed = 0; 22405ad90e4eSArnaldo Carvalho de Melo struct dso *kdso = self->vmlinux_maps[MAP__FUNCTION]->dso; 22415ad90e4eSArnaldo Carvalho de Melo 22425ad90e4eSArnaldo Carvalho de Melo if (kdso->has_build_id) { 22435ad90e4eSArnaldo Carvalho de Melo char filename[PATH_MAX]; 22445ad90e4eSArnaldo Carvalho de Melo if (dso__build_id_filename(kdso, filename, sizeof(filename))) 22455ad90e4eSArnaldo Carvalho de Melo printed += fprintf(fp, "[0] %s\n", filename); 22465ad90e4eSArnaldo Carvalho de Melo } 2247b0a9ab62SArnaldo Carvalho de Melo 2248b0a9ab62SArnaldo Carvalho de Melo for (i = 0; i < vmlinux_path__nr_entries; ++i) 22495ad90e4eSArnaldo Carvalho de Melo printed += fprintf(fp, "[%d] %s\n", 22505ad90e4eSArnaldo Carvalho de Melo i + kdso->has_build_id, vmlinux_path[i]); 2251b0a9ab62SArnaldo Carvalho de Melo 2252b0a9ab62SArnaldo Carvalho de Melo return printed; 2253b0a9ab62SArnaldo Carvalho de Melo } 2254b0a9ab62SArnaldo Carvalho de Melo 2255655000e7SArnaldo Carvalho de Melo static int setup_list(struct strlist **list, const char *list_str, 2256655000e7SArnaldo Carvalho de Melo const char *list_name) 2257655000e7SArnaldo Carvalho de Melo { 2258655000e7SArnaldo Carvalho de Melo if (list_str == NULL) 2259655000e7SArnaldo Carvalho de Melo return 0; 2260655000e7SArnaldo Carvalho de Melo 2261655000e7SArnaldo Carvalho de Melo *list = strlist__new(true, list_str); 2262655000e7SArnaldo Carvalho de Melo if (!*list) { 2263655000e7SArnaldo Carvalho de Melo pr_err("problems parsing %s list\n", list_name); 2264655000e7SArnaldo Carvalho de Melo return -1; 2265655000e7SArnaldo Carvalho de Melo } 2266655000e7SArnaldo Carvalho de Melo return 0; 2267655000e7SArnaldo Carvalho de Melo } 2268655000e7SArnaldo Carvalho de Melo 226975be6cf4SArnaldo Carvalho de Melo int symbol__init(void) 2270cc612d81SArnaldo Carvalho de Melo { 227195011c60SArnaldo Carvalho de Melo elf_version(EV_CURRENT); 227275be6cf4SArnaldo Carvalho de Melo if (symbol_conf.sort_by_name) 227375be6cf4SArnaldo Carvalho de Melo symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) - 227479406cd7SArnaldo Carvalho de Melo sizeof(struct symbol)); 2275b32d133aSArnaldo Carvalho de Melo 227675be6cf4SArnaldo Carvalho de Melo if (symbol_conf.try_vmlinux_path && vmlinux_path__init() < 0) 2277cc612d81SArnaldo Carvalho de Melo return -1; 2278cc612d81SArnaldo Carvalho de Melo 2279c410a338SArnaldo Carvalho de Melo if (symbol_conf.field_sep && *symbol_conf.field_sep == '.') { 2280c410a338SArnaldo Carvalho de Melo pr_err("'.' is the only non valid --field-separator argument\n"); 2281c410a338SArnaldo Carvalho de Melo return -1; 2282c410a338SArnaldo Carvalho de Melo } 2283c410a338SArnaldo Carvalho de Melo 2284655000e7SArnaldo Carvalho de Melo if (setup_list(&symbol_conf.dso_list, 2285655000e7SArnaldo Carvalho de Melo symbol_conf.dso_list_str, "dso") < 0) 2286655000e7SArnaldo Carvalho de Melo return -1; 2287655000e7SArnaldo Carvalho de Melo 2288655000e7SArnaldo Carvalho de Melo if (setup_list(&symbol_conf.comm_list, 2289655000e7SArnaldo Carvalho de Melo symbol_conf.comm_list_str, "comm") < 0) 2290655000e7SArnaldo Carvalho de Melo goto out_free_dso_list; 2291655000e7SArnaldo Carvalho de Melo 2292655000e7SArnaldo Carvalho de Melo if (setup_list(&symbol_conf.sym_list, 2293655000e7SArnaldo Carvalho de Melo symbol_conf.sym_list_str, "symbol") < 0) 2294655000e7SArnaldo Carvalho de Melo goto out_free_comm_list; 2295655000e7SArnaldo Carvalho de Melo 22964aa65636SArnaldo Carvalho de Melo return 0; 2297655000e7SArnaldo Carvalho de Melo 2298655000e7SArnaldo Carvalho de Melo out_free_dso_list: 2299655000e7SArnaldo Carvalho de Melo strlist__delete(symbol_conf.dso_list); 2300655000e7SArnaldo Carvalho de Melo out_free_comm_list: 2301655000e7SArnaldo Carvalho de Melo strlist__delete(symbol_conf.comm_list); 2302655000e7SArnaldo Carvalho de Melo return -1; 2303cc612d81SArnaldo Carvalho de Melo } 2304cc612d81SArnaldo Carvalho de Melo 2305d65a458bSArnaldo Carvalho de Melo void symbol__exit(void) 2306d65a458bSArnaldo Carvalho de Melo { 2307d65a458bSArnaldo Carvalho de Melo strlist__delete(symbol_conf.sym_list); 2308d65a458bSArnaldo Carvalho de Melo strlist__delete(symbol_conf.dso_list); 2309d65a458bSArnaldo Carvalho de Melo strlist__delete(symbol_conf.comm_list); 2310d65a458bSArnaldo Carvalho de Melo vmlinux_path__exit(); 2311d65a458bSArnaldo Carvalho de Melo symbol_conf.sym_list = symbol_conf.dso_list = symbol_conf.comm_list = NULL; 2312d65a458bSArnaldo Carvalho de Melo } 2313d65a458bSArnaldo Carvalho de Melo 2314d28c6223SArnaldo Carvalho de Melo int machines__create_kernel_maps(struct rb_root *self, pid_t pid) 23154aa65636SArnaldo Carvalho de Melo { 2316d28c6223SArnaldo Carvalho de Melo struct machine *machine = machines__findnew(self, pid); 23179de89fe7SArnaldo Carvalho de Melo 231823346f21SArnaldo Carvalho de Melo if (machine == NULL) 2319a1645ce1SZhang, Yanmin return -1; 23204aa65636SArnaldo Carvalho de Melo 23215c0541d5SArnaldo Carvalho de Melo return machine__create_kernel_maps(machine); 2322cd84c2acSFrederic Weisbecker } 23235aab621bSArnaldo Carvalho de Melo 23245aab621bSArnaldo Carvalho de Melo static int hex(char ch) 23255aab621bSArnaldo Carvalho de Melo { 23265aab621bSArnaldo Carvalho de Melo if ((ch >= '0') && (ch <= '9')) 23275aab621bSArnaldo Carvalho de Melo return ch - '0'; 23285aab621bSArnaldo Carvalho de Melo if ((ch >= 'a') && (ch <= 'f')) 23295aab621bSArnaldo Carvalho de Melo return ch - 'a' + 10; 23305aab621bSArnaldo Carvalho de Melo if ((ch >= 'A') && (ch <= 'F')) 23315aab621bSArnaldo Carvalho de Melo return ch - 'A' + 10; 23325aab621bSArnaldo Carvalho de Melo return -1; 23335aab621bSArnaldo Carvalho de Melo } 23345aab621bSArnaldo Carvalho de Melo 23355aab621bSArnaldo Carvalho de Melo /* 23365aab621bSArnaldo Carvalho de Melo * While we find nice hex chars, build a long_val. 23375aab621bSArnaldo Carvalho de Melo * Return number of chars processed. 23385aab621bSArnaldo Carvalho de Melo */ 23395aab621bSArnaldo Carvalho de Melo int hex2u64(const char *ptr, u64 *long_val) 23405aab621bSArnaldo Carvalho de Melo { 23415aab621bSArnaldo Carvalho de Melo const char *p = ptr; 23425aab621bSArnaldo Carvalho de Melo *long_val = 0; 23435aab621bSArnaldo Carvalho de Melo 23445aab621bSArnaldo Carvalho de Melo while (*p) { 23455aab621bSArnaldo Carvalho de Melo const int hex_val = hex(*p); 23465aab621bSArnaldo Carvalho de Melo 23475aab621bSArnaldo Carvalho de Melo if (hex_val < 0) 23485aab621bSArnaldo Carvalho de Melo break; 23495aab621bSArnaldo Carvalho de Melo 23505aab621bSArnaldo Carvalho de Melo *long_val = (*long_val << 4) | hex_val; 23515aab621bSArnaldo Carvalho de Melo p++; 23525aab621bSArnaldo Carvalho de Melo } 23535aab621bSArnaldo Carvalho de Melo 23545aab621bSArnaldo Carvalho de Melo return p - ptr; 23555aab621bSArnaldo Carvalho de Melo } 23565aab621bSArnaldo Carvalho de Melo 23575aab621bSArnaldo Carvalho de Melo char *strxfrchar(char *s, char from, char to) 23585aab621bSArnaldo Carvalho de Melo { 23595aab621bSArnaldo Carvalho de Melo char *p = s; 23605aab621bSArnaldo Carvalho de Melo 23615aab621bSArnaldo Carvalho de Melo while ((p = strchr(p, from)) != NULL) 23625aab621bSArnaldo Carvalho de Melo *p++ = to; 23635aab621bSArnaldo Carvalho de Melo 23645aab621bSArnaldo Carvalho de Melo return s; 23655aab621bSArnaldo Carvalho de Melo } 2366a1645ce1SZhang, Yanmin 2367d28c6223SArnaldo Carvalho de Melo int machines__create_guest_kernel_maps(struct rb_root *self) 2368a1645ce1SZhang, Yanmin { 2369a1645ce1SZhang, Yanmin int ret = 0; 2370a1645ce1SZhang, Yanmin struct dirent **namelist = NULL; 2371a1645ce1SZhang, Yanmin int i, items = 0; 2372a1645ce1SZhang, Yanmin char path[PATH_MAX]; 2373a1645ce1SZhang, Yanmin pid_t pid; 2374a1645ce1SZhang, Yanmin 2375a1645ce1SZhang, Yanmin if (symbol_conf.default_guest_vmlinux_name || 2376a1645ce1SZhang, Yanmin symbol_conf.default_guest_modules || 2377a1645ce1SZhang, Yanmin symbol_conf.default_guest_kallsyms) { 2378d28c6223SArnaldo Carvalho de Melo machines__create_kernel_maps(self, DEFAULT_GUEST_KERNEL_ID); 2379a1645ce1SZhang, Yanmin } 2380a1645ce1SZhang, Yanmin 2381a1645ce1SZhang, Yanmin if (symbol_conf.guestmount) { 2382a1645ce1SZhang, Yanmin items = scandir(symbol_conf.guestmount, &namelist, NULL, NULL); 2383a1645ce1SZhang, Yanmin if (items <= 0) 2384a1645ce1SZhang, Yanmin return -ENOENT; 2385a1645ce1SZhang, Yanmin for (i = 0; i < items; i++) { 2386a1645ce1SZhang, Yanmin if (!isdigit(namelist[i]->d_name[0])) { 2387a1645ce1SZhang, Yanmin /* Filter out . and .. */ 2388a1645ce1SZhang, Yanmin continue; 2389a1645ce1SZhang, Yanmin } 2390a1645ce1SZhang, Yanmin pid = atoi(namelist[i]->d_name); 2391a1645ce1SZhang, Yanmin sprintf(path, "%s/%s/proc/kallsyms", 2392a1645ce1SZhang, Yanmin symbol_conf.guestmount, 2393a1645ce1SZhang, Yanmin namelist[i]->d_name); 2394a1645ce1SZhang, Yanmin ret = access(path, R_OK); 2395a1645ce1SZhang, Yanmin if (ret) { 2396a1645ce1SZhang, Yanmin pr_debug("Can't access file %s\n", path); 2397a1645ce1SZhang, Yanmin goto failure; 2398a1645ce1SZhang, Yanmin } 2399d28c6223SArnaldo Carvalho de Melo machines__create_kernel_maps(self, pid); 2400a1645ce1SZhang, Yanmin } 2401a1645ce1SZhang, Yanmin failure: 2402a1645ce1SZhang, Yanmin free(namelist); 2403a1645ce1SZhang, Yanmin } 2404a1645ce1SZhang, Yanmin 2405a1645ce1SZhang, Yanmin return ret; 2406a1645ce1SZhang, Yanmin } 24075c0541d5SArnaldo Carvalho de Melo 2408076c6e45SArnaldo Carvalho de Melo void machines__destroy_guest_kernel_maps(struct rb_root *self) 2409076c6e45SArnaldo Carvalho de Melo { 2410076c6e45SArnaldo Carvalho de Melo struct rb_node *next = rb_first(self); 2411076c6e45SArnaldo Carvalho de Melo 2412076c6e45SArnaldo Carvalho de Melo while (next) { 2413076c6e45SArnaldo Carvalho de Melo struct machine *pos = rb_entry(next, struct machine, rb_node); 2414076c6e45SArnaldo Carvalho de Melo 2415076c6e45SArnaldo Carvalho de Melo next = rb_next(&pos->rb_node); 2416076c6e45SArnaldo Carvalho de Melo rb_erase(&pos->rb_node, self); 2417076c6e45SArnaldo Carvalho de Melo machine__delete(pos); 2418076c6e45SArnaldo Carvalho de Melo } 2419076c6e45SArnaldo Carvalho de Melo } 2420076c6e45SArnaldo Carvalho de Melo 24215c0541d5SArnaldo Carvalho de Melo int machine__load_kallsyms(struct machine *self, const char *filename, 24225c0541d5SArnaldo Carvalho de Melo enum map_type type, symbol_filter_t filter) 24235c0541d5SArnaldo Carvalho de Melo { 24245c0541d5SArnaldo Carvalho de Melo struct map *map = self->vmlinux_maps[type]; 24255c0541d5SArnaldo Carvalho de Melo int ret = dso__load_kallsyms(map->dso, filename, map, filter); 24265c0541d5SArnaldo Carvalho de Melo 24275c0541d5SArnaldo Carvalho de Melo if (ret > 0) { 24285c0541d5SArnaldo Carvalho de Melo dso__set_loaded(map->dso, type); 24295c0541d5SArnaldo Carvalho de Melo /* 24305c0541d5SArnaldo Carvalho de Melo * Since /proc/kallsyms will have multiple sessions for the 24315c0541d5SArnaldo Carvalho de Melo * kernel, with modules between them, fixup the end of all 24325c0541d5SArnaldo Carvalho de Melo * sections. 24335c0541d5SArnaldo Carvalho de Melo */ 24345c0541d5SArnaldo Carvalho de Melo __map_groups__fixup_end(&self->kmaps, type); 24355c0541d5SArnaldo Carvalho de Melo } 24365c0541d5SArnaldo Carvalho de Melo 24375c0541d5SArnaldo Carvalho de Melo return ret; 24385c0541d5SArnaldo Carvalho de Melo } 24395c0541d5SArnaldo Carvalho de Melo 24405c0541d5SArnaldo Carvalho de Melo int machine__load_vmlinux_path(struct machine *self, enum map_type type, 24415c0541d5SArnaldo Carvalho de Melo symbol_filter_t filter) 24425c0541d5SArnaldo Carvalho de Melo { 24435c0541d5SArnaldo Carvalho de Melo struct map *map = self->vmlinux_maps[type]; 24445c0541d5SArnaldo Carvalho de Melo int ret = dso__load_vmlinux_path(map->dso, map, filter); 24455c0541d5SArnaldo Carvalho de Melo 24465c0541d5SArnaldo Carvalho de Melo if (ret > 0) { 24475c0541d5SArnaldo Carvalho de Melo dso__set_loaded(map->dso, type); 24485c0541d5SArnaldo Carvalho de Melo map__reloc_vmlinux(map); 24495c0541d5SArnaldo Carvalho de Melo } 24505c0541d5SArnaldo Carvalho de Melo 24515c0541d5SArnaldo Carvalho de Melo return ret; 24525c0541d5SArnaldo Carvalho de Melo } 2453