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; 29802a9d037SRabin Vincent struct symbol_name_rb_node *symn, *s; 29902a9d037SRabin Vincent 30002a9d037SRabin Vincent symn = container_of(sym, struct symbol_name_rb_node, sym); 30179406cd7SArnaldo Carvalho de Melo 30279406cd7SArnaldo Carvalho de Melo while (*p != NULL) { 30379406cd7SArnaldo Carvalho de Melo parent = *p; 30479406cd7SArnaldo Carvalho de Melo s = rb_entry(parent, struct symbol_name_rb_node, rb_node); 30579406cd7SArnaldo Carvalho de Melo if (strcmp(sym->name, s->sym.name) < 0) 30679406cd7SArnaldo Carvalho de Melo p = &(*p)->rb_left; 30779406cd7SArnaldo Carvalho de Melo else 30879406cd7SArnaldo Carvalho de Melo p = &(*p)->rb_right; 30979406cd7SArnaldo Carvalho de Melo } 31079406cd7SArnaldo Carvalho de Melo rb_link_node(&symn->rb_node, parent, p); 31179406cd7SArnaldo Carvalho de Melo rb_insert_color(&symn->rb_node, self); 31279406cd7SArnaldo Carvalho de Melo } 31379406cd7SArnaldo Carvalho de Melo 31479406cd7SArnaldo Carvalho de Melo static void symbols__sort_by_name(struct rb_root *self, struct rb_root *source) 31579406cd7SArnaldo Carvalho de Melo { 31679406cd7SArnaldo Carvalho de Melo struct rb_node *nd; 31779406cd7SArnaldo Carvalho de Melo 31879406cd7SArnaldo Carvalho de Melo for (nd = rb_first(source); nd; nd = rb_next(nd)) { 31979406cd7SArnaldo Carvalho de Melo struct symbol *pos = rb_entry(nd, struct symbol, rb_node); 32079406cd7SArnaldo Carvalho de Melo symbols__insert_by_name(self, pos); 32179406cd7SArnaldo Carvalho de Melo } 32279406cd7SArnaldo Carvalho de Melo } 32379406cd7SArnaldo Carvalho de Melo 32479406cd7SArnaldo Carvalho de Melo static struct symbol *symbols__find_by_name(struct rb_root *self, const char *name) 32579406cd7SArnaldo Carvalho de Melo { 32679406cd7SArnaldo Carvalho de Melo struct rb_node *n; 32779406cd7SArnaldo Carvalho de Melo 32879406cd7SArnaldo Carvalho de Melo if (self == NULL) 32979406cd7SArnaldo Carvalho de Melo return NULL; 33079406cd7SArnaldo Carvalho de Melo 33179406cd7SArnaldo Carvalho de Melo n = self->rb_node; 33279406cd7SArnaldo Carvalho de Melo 33379406cd7SArnaldo Carvalho de Melo while (n) { 33479406cd7SArnaldo Carvalho de Melo struct symbol_name_rb_node *s; 33579406cd7SArnaldo Carvalho de Melo int cmp; 33679406cd7SArnaldo Carvalho de Melo 33779406cd7SArnaldo Carvalho de Melo s = rb_entry(n, struct symbol_name_rb_node, rb_node); 33879406cd7SArnaldo Carvalho de Melo cmp = strcmp(name, s->sym.name); 33979406cd7SArnaldo Carvalho de Melo 34079406cd7SArnaldo Carvalho de Melo if (cmp < 0) 34179406cd7SArnaldo Carvalho de Melo n = n->rb_left; 34279406cd7SArnaldo Carvalho de Melo else if (cmp > 0) 34379406cd7SArnaldo Carvalho de Melo n = n->rb_right; 34479406cd7SArnaldo Carvalho de Melo else 34579406cd7SArnaldo Carvalho de Melo return &s->sym; 34679406cd7SArnaldo Carvalho de Melo } 34779406cd7SArnaldo Carvalho de Melo 34879406cd7SArnaldo Carvalho de Melo return NULL; 34979406cd7SArnaldo Carvalho de Melo } 35079406cd7SArnaldo Carvalho de Melo 35179406cd7SArnaldo Carvalho de Melo struct symbol *dso__find_symbol(struct dso *self, 35279406cd7SArnaldo Carvalho de Melo enum map_type type, u64 addr) 353fcf1203aSArnaldo Carvalho de Melo { 3546a4694a4SArnaldo Carvalho de Melo return symbols__find(&self->symbols[type], addr); 355fcf1203aSArnaldo Carvalho de Melo } 356fcf1203aSArnaldo Carvalho de Melo 35779406cd7SArnaldo Carvalho de Melo struct symbol *dso__find_symbol_by_name(struct dso *self, enum map_type type, 35879406cd7SArnaldo Carvalho de Melo const char *name) 35979406cd7SArnaldo Carvalho de Melo { 36079406cd7SArnaldo Carvalho de Melo return symbols__find_by_name(&self->symbol_names[type], name); 36179406cd7SArnaldo Carvalho de Melo } 36279406cd7SArnaldo Carvalho de Melo 36379406cd7SArnaldo Carvalho de Melo void dso__sort_by_name(struct dso *self, enum map_type type) 36479406cd7SArnaldo Carvalho de Melo { 36579406cd7SArnaldo Carvalho de Melo dso__set_sorted_by_name(self, type); 36679406cd7SArnaldo Carvalho de Melo return symbols__sort_by_name(&self->symbol_names[type], 36779406cd7SArnaldo Carvalho de Melo &self->symbols[type]); 36879406cd7SArnaldo Carvalho de Melo } 36979406cd7SArnaldo Carvalho de Melo 370ef12a141SArnaldo Carvalho de Melo int build_id__sprintf(const u8 *self, int len, char *bf) 3718d06367fSArnaldo Carvalho de Melo { 3728d06367fSArnaldo Carvalho de Melo char *bid = bf; 373ef12a141SArnaldo Carvalho de Melo const u8 *raw = self; 3748d06367fSArnaldo Carvalho de Melo int i; 3758d06367fSArnaldo Carvalho de Melo 3768d06367fSArnaldo Carvalho de Melo for (i = 0; i < len; ++i) { 3778d06367fSArnaldo Carvalho de Melo sprintf(bid, "%02x", *raw); 3788d06367fSArnaldo Carvalho de Melo ++raw; 3798d06367fSArnaldo Carvalho de Melo bid += 2; 3808d06367fSArnaldo Carvalho de Melo } 3818d06367fSArnaldo Carvalho de Melo 3828d06367fSArnaldo Carvalho de Melo return raw - self; 3838d06367fSArnaldo Carvalho de Melo } 3848d06367fSArnaldo Carvalho de Melo 3859e03eb2dSArnaldo Carvalho de Melo size_t dso__fprintf_buildid(struct dso *self, FILE *fp) 38686470930SIngo Molnar { 3878d06367fSArnaldo Carvalho de Melo char sbuild_id[BUILD_ID_SIZE * 2 + 1]; 3888d06367fSArnaldo Carvalho de Melo 3898d06367fSArnaldo Carvalho de Melo build_id__sprintf(self->build_id, sizeof(self->build_id), sbuild_id); 3909e03eb2dSArnaldo Carvalho de Melo return fprintf(fp, "%s", sbuild_id); 3919e03eb2dSArnaldo Carvalho de Melo } 3929e03eb2dSArnaldo Carvalho de Melo 39390f18e63SSrikar Dronamraju size_t dso__fprintf_symbols_by_name(struct dso *self, enum map_type type, FILE *fp) 39490f18e63SSrikar Dronamraju { 39590f18e63SSrikar Dronamraju size_t ret = 0; 39690f18e63SSrikar Dronamraju struct rb_node *nd; 39790f18e63SSrikar Dronamraju struct symbol_name_rb_node *pos; 39890f18e63SSrikar Dronamraju 39990f18e63SSrikar Dronamraju for (nd = rb_first(&self->symbol_names[type]); nd; nd = rb_next(nd)) { 40090f18e63SSrikar Dronamraju pos = rb_entry(nd, struct symbol_name_rb_node, rb_node); 40190f18e63SSrikar Dronamraju fprintf(fp, "%s\n", pos->sym.name); 40290f18e63SSrikar Dronamraju } 40390f18e63SSrikar Dronamraju 40490f18e63SSrikar Dronamraju return ret; 40590f18e63SSrikar Dronamraju } 40690f18e63SSrikar Dronamraju 40795011c60SArnaldo Carvalho de Melo size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp) 4089e03eb2dSArnaldo Carvalho de Melo { 4099e03eb2dSArnaldo Carvalho de Melo struct rb_node *nd; 4109e03eb2dSArnaldo Carvalho de Melo size_t ret = fprintf(fp, "dso: %s (", self->short_name); 4119e03eb2dSArnaldo Carvalho de Melo 4123846df2eSArnaldo Carvalho de Melo if (self->short_name != self->long_name) 4133846df2eSArnaldo Carvalho de Melo ret += fprintf(fp, "%s, ", self->long_name); 4143846df2eSArnaldo Carvalho de Melo ret += fprintf(fp, "%s, %sloaded, ", map_type__name[type], 4153846df2eSArnaldo Carvalho de Melo self->loaded ? "" : "NOT "); 4169e03eb2dSArnaldo Carvalho de Melo ret += dso__fprintf_buildid(self, fp); 4176a4694a4SArnaldo Carvalho de Melo ret += fprintf(fp, ")\n"); 41895011c60SArnaldo Carvalho de Melo for (nd = rb_first(&self->symbols[type]); nd; nd = rb_next(nd)) { 41986470930SIngo Molnar struct symbol *pos = rb_entry(nd, struct symbol, rb_node); 42086470930SIngo Molnar ret += symbol__fprintf(pos, fp); 42186470930SIngo Molnar } 42286470930SIngo Molnar 42386470930SIngo Molnar return ret; 42486470930SIngo Molnar } 42586470930SIngo Molnar 4269e201442SArnaldo Carvalho de Melo int kallsyms__parse(const char *filename, void *arg, 4279e201442SArnaldo Carvalho de Melo int (*process_symbol)(void *arg, const char *name, 428682b335aSArnaldo Carvalho de Melo char type, u64 start)) 42986470930SIngo Molnar { 43086470930SIngo Molnar char *line = NULL; 43186470930SIngo Molnar size_t n; 432682b335aSArnaldo Carvalho de Melo int err = 0; 4339e201442SArnaldo Carvalho de Melo FILE *file = fopen(filename, "r"); 43486470930SIngo Molnar 43586470930SIngo Molnar if (file == NULL) 43686470930SIngo Molnar goto out_failure; 43786470930SIngo Molnar 43886470930SIngo Molnar while (!feof(file)) { 4399cffa8d5SPaul Mackerras u64 start; 44086470930SIngo Molnar int line_len, len; 44186470930SIngo Molnar char symbol_type; 4422e538c4aSArnaldo Carvalho de Melo char *symbol_name; 44386470930SIngo Molnar 44486470930SIngo Molnar line_len = getline(&line, &n, file); 445a1645ce1SZhang, Yanmin if (line_len < 0 || !line) 44686470930SIngo Molnar break; 44786470930SIngo Molnar 44886470930SIngo Molnar line[--line_len] = '\0'; /* \n */ 44986470930SIngo Molnar 45086470930SIngo Molnar len = hex2u64(line, &start); 45186470930SIngo Molnar 45286470930SIngo Molnar len++; 45386470930SIngo Molnar if (len + 2 >= line_len) 45486470930SIngo Molnar continue; 45586470930SIngo Molnar 45686470930SIngo Molnar symbol_type = toupper(line[len]); 457af427bf5SArnaldo Carvalho de Melo symbol_name = line + len + 2; 458682b335aSArnaldo Carvalho de Melo 459682b335aSArnaldo Carvalho de Melo err = process_symbol(arg, symbol_name, symbol_type, start); 460682b335aSArnaldo Carvalho de Melo if (err) 461682b335aSArnaldo Carvalho de Melo break; 462682b335aSArnaldo Carvalho de Melo } 463682b335aSArnaldo Carvalho de Melo 464682b335aSArnaldo Carvalho de Melo free(line); 465682b335aSArnaldo Carvalho de Melo fclose(file); 466682b335aSArnaldo Carvalho de Melo return err; 467682b335aSArnaldo Carvalho de Melo 468682b335aSArnaldo Carvalho de Melo out_failure: 469682b335aSArnaldo Carvalho de Melo return -1; 470682b335aSArnaldo Carvalho de Melo } 471682b335aSArnaldo Carvalho de Melo 472682b335aSArnaldo Carvalho de Melo struct process_kallsyms_args { 473682b335aSArnaldo Carvalho de Melo struct map *map; 474682b335aSArnaldo Carvalho de Melo struct dso *dso; 475682b335aSArnaldo Carvalho de Melo }; 476682b335aSArnaldo Carvalho de Melo 477c408fedfSArnaldo Carvalho de Melo static u8 kallsyms2elf_type(char type) 478c408fedfSArnaldo Carvalho de Melo { 479c408fedfSArnaldo Carvalho de Melo if (type == 'W') 480c408fedfSArnaldo Carvalho de Melo return STB_WEAK; 481c408fedfSArnaldo Carvalho de Melo 482c408fedfSArnaldo Carvalho de Melo return isupper(type) ? STB_GLOBAL : STB_LOCAL; 483c408fedfSArnaldo Carvalho de Melo } 484c408fedfSArnaldo Carvalho de Melo 485682b335aSArnaldo Carvalho de Melo static int map__process_kallsym_symbol(void *arg, const char *name, 486682b335aSArnaldo Carvalho de Melo char type, u64 start) 487682b335aSArnaldo Carvalho de Melo { 488682b335aSArnaldo Carvalho de Melo struct symbol *sym; 489682b335aSArnaldo Carvalho de Melo struct process_kallsyms_args *a = arg; 490682b335aSArnaldo Carvalho de Melo struct rb_root *root = &a->dso->symbols[a->map->type]; 491682b335aSArnaldo Carvalho de Melo 492682b335aSArnaldo Carvalho de Melo if (!symbol_type__is_a(type, a->map->type)) 493682b335aSArnaldo Carvalho de Melo return 0; 494682b335aSArnaldo Carvalho de Melo 4952e538c4aSArnaldo Carvalho de Melo /* 4962e538c4aSArnaldo Carvalho de Melo * Will fix up the end later, when we have all symbols sorted. 4972e538c4aSArnaldo Carvalho de Melo */ 498c408fedfSArnaldo Carvalho de Melo sym = symbol__new(start, 0, kallsyms2elf_type(type), name); 499af427bf5SArnaldo Carvalho de Melo 5002e538c4aSArnaldo Carvalho de Melo if (sym == NULL) 501682b335aSArnaldo Carvalho de Melo return -ENOMEM; 50282164161SArnaldo Carvalho de Melo /* 50382164161SArnaldo Carvalho de Melo * We will pass the symbols to the filter later, in 5044e06255fSArnaldo Carvalho de Melo * map__split_kallsyms, when we have split the maps per module 50582164161SArnaldo Carvalho de Melo */ 5064e06255fSArnaldo Carvalho de Melo symbols__insert(root, sym); 507a1645ce1SZhang, Yanmin 508682b335aSArnaldo Carvalho de Melo return 0; 5092e538c4aSArnaldo Carvalho de Melo } 5102e538c4aSArnaldo Carvalho de Melo 511682b335aSArnaldo Carvalho de Melo /* 512682b335aSArnaldo Carvalho de Melo * Loads the function entries in /proc/kallsyms into kernel_map->dso, 513682b335aSArnaldo Carvalho de Melo * so that we can in the next step set the symbol ->end address and then 514682b335aSArnaldo Carvalho de Melo * call kernel_maps__split_kallsyms. 515682b335aSArnaldo Carvalho de Melo */ 5169e201442SArnaldo Carvalho de Melo static int dso__load_all_kallsyms(struct dso *self, const char *filename, 5179e201442SArnaldo Carvalho de Melo struct map *map) 518682b335aSArnaldo Carvalho de Melo { 519682b335aSArnaldo Carvalho de Melo struct process_kallsyms_args args = { .map = map, .dso = self, }; 5209e201442SArnaldo Carvalho de Melo return kallsyms__parse(filename, &args, map__process_kallsym_symbol); 5212e538c4aSArnaldo Carvalho de Melo } 5222e538c4aSArnaldo Carvalho de Melo 5232e538c4aSArnaldo Carvalho de Melo /* 5242e538c4aSArnaldo Carvalho de Melo * Split the symbols into maps, making sure there are no overlaps, i.e. the 5252e538c4aSArnaldo Carvalho de Melo * kernel range is broken in several maps, named [kernel].N, as we don't have 5262e538c4aSArnaldo Carvalho de Melo * the original ELF section names vmlinux have. 5272e538c4aSArnaldo Carvalho de Melo */ 5289958e1f0SArnaldo Carvalho de Melo static int dso__split_kallsyms(struct dso *self, struct map *map, 5299de89fe7SArnaldo Carvalho de Melo symbol_filter_t filter) 5302e538c4aSArnaldo Carvalho de Melo { 5319de89fe7SArnaldo Carvalho de Melo struct map_groups *kmaps = map__kmap(map)->kmaps; 53223346f21SArnaldo Carvalho de Melo struct machine *machine = kmaps->machine; 5334e06255fSArnaldo Carvalho de Melo struct map *curr_map = map; 5342e538c4aSArnaldo Carvalho de Melo struct symbol *pos; 5358a953312SArnaldo Carvalho de Melo int count = 0, moved = 0; 5364e06255fSArnaldo Carvalho de Melo struct rb_root *root = &self->symbols[map->type]; 5374e06255fSArnaldo Carvalho de Melo struct rb_node *next = rb_first(root); 5382e538c4aSArnaldo Carvalho de Melo int kernel_range = 0; 5392e538c4aSArnaldo Carvalho de Melo 5402e538c4aSArnaldo Carvalho de Melo while (next) { 5412e538c4aSArnaldo Carvalho de Melo char *module; 5422e538c4aSArnaldo Carvalho de Melo 5432e538c4aSArnaldo Carvalho de Melo pos = rb_entry(next, struct symbol, rb_node); 5442e538c4aSArnaldo Carvalho de Melo next = rb_next(&pos->rb_node); 5452e538c4aSArnaldo Carvalho de Melo 5462e538c4aSArnaldo Carvalho de Melo module = strchr(pos->name, '\t'); 5472e538c4aSArnaldo Carvalho de Melo if (module) { 54875be6cf4SArnaldo Carvalho de Melo if (!symbol_conf.use_modules) 5491de8e245SArnaldo Carvalho de Melo goto discard_symbol; 5501de8e245SArnaldo Carvalho de Melo 5512e538c4aSArnaldo Carvalho de Melo *module++ = '\0'; 5522e538c4aSArnaldo Carvalho de Melo 553b7cece76SArnaldo Carvalho de Melo if (strcmp(curr_map->dso->short_name, module)) { 554a1645ce1SZhang, Yanmin if (curr_map != map && 555a1645ce1SZhang, Yanmin self->kernel == DSO_TYPE_GUEST_KERNEL && 55623346f21SArnaldo Carvalho de Melo machine__is_default_guest(machine)) { 557a1645ce1SZhang, Yanmin /* 558a1645ce1SZhang, Yanmin * We assume all symbols of a module are 559a1645ce1SZhang, Yanmin * continuous in * kallsyms, so curr_map 560a1645ce1SZhang, Yanmin * points to a module and all its 561a1645ce1SZhang, Yanmin * symbols are in its kmap. Mark it as 562a1645ce1SZhang, Yanmin * loaded. 563a1645ce1SZhang, Yanmin */ 564a1645ce1SZhang, Yanmin dso__set_loaded(curr_map->dso, 565a1645ce1SZhang, Yanmin curr_map->type); 566af427bf5SArnaldo Carvalho de Melo } 567b7cece76SArnaldo Carvalho de Melo 568a1645ce1SZhang, Yanmin curr_map = map_groups__find_by_name(kmaps, 569a1645ce1SZhang, Yanmin map->type, module); 570a1645ce1SZhang, Yanmin if (curr_map == NULL) { 5712f51903bSArnaldo Carvalho de Melo pr_debug("%s/proc/{kallsyms,modules} " 572a1645ce1SZhang, Yanmin "inconsistency while looking " 573a1645ce1SZhang, Yanmin "for \"%s\" module!\n", 57423346f21SArnaldo Carvalho de Melo machine->root_dir, module); 575a1645ce1SZhang, Yanmin curr_map = map; 576a1645ce1SZhang, Yanmin goto discard_symbol; 577a1645ce1SZhang, Yanmin } 578a1645ce1SZhang, Yanmin 579a1645ce1SZhang, Yanmin if (curr_map->dso->loaded && 58023346f21SArnaldo Carvalho de Melo !machine__is_default_guest(machine)) 581b7cece76SArnaldo Carvalho de Melo goto discard_symbol; 582af427bf5SArnaldo Carvalho de Melo } 58386470930SIngo Molnar /* 5842e538c4aSArnaldo Carvalho de Melo * So that we look just like we get from .ko files, 5852e538c4aSArnaldo Carvalho de Melo * i.e. not prelinked, relative to map->start. 58686470930SIngo Molnar */ 5874e06255fSArnaldo Carvalho de Melo pos->start = curr_map->map_ip(curr_map, pos->start); 5884e06255fSArnaldo Carvalho de Melo pos->end = curr_map->map_ip(curr_map, pos->end); 5894e06255fSArnaldo Carvalho de Melo } else if (curr_map != map) { 5902e538c4aSArnaldo Carvalho de Melo char dso_name[PATH_MAX]; 5912e538c4aSArnaldo Carvalho de Melo struct dso *dso; 59286470930SIngo Molnar 5938a953312SArnaldo Carvalho de Melo if (count == 0) { 5948a953312SArnaldo Carvalho de Melo curr_map = map; 5958a953312SArnaldo Carvalho de Melo goto filter_symbol; 5968a953312SArnaldo Carvalho de Melo } 5978a953312SArnaldo Carvalho de Melo 598a1645ce1SZhang, Yanmin if (self->kernel == DSO_TYPE_GUEST_KERNEL) 599a1645ce1SZhang, Yanmin snprintf(dso_name, sizeof(dso_name), 600a1645ce1SZhang, Yanmin "[guest.kernel].%d", 601a1645ce1SZhang, Yanmin kernel_range++); 602a1645ce1SZhang, Yanmin else 603a1645ce1SZhang, Yanmin snprintf(dso_name, sizeof(dso_name), 604a1645ce1SZhang, Yanmin "[kernel].%d", 6052e538c4aSArnaldo Carvalho de Melo kernel_range++); 60686470930SIngo Molnar 60700a192b3SArnaldo Carvalho de Melo dso = dso__new(dso_name); 6082e538c4aSArnaldo Carvalho de Melo if (dso == NULL) 6092e538c4aSArnaldo Carvalho de Melo return -1; 6102e538c4aSArnaldo Carvalho de Melo 611a1645ce1SZhang, Yanmin dso->kernel = self->kernel; 612a1645ce1SZhang, Yanmin 6134e06255fSArnaldo Carvalho de Melo curr_map = map__new2(pos->start, dso, map->type); 61437fe5fcbSZhang, Yanmin if (curr_map == NULL) { 6152e538c4aSArnaldo Carvalho de Melo dso__delete(dso); 6162e538c4aSArnaldo Carvalho de Melo return -1; 6172e538c4aSArnaldo Carvalho de Melo } 6182e538c4aSArnaldo Carvalho de Melo 6194e06255fSArnaldo Carvalho de Melo curr_map->map_ip = curr_map->unmap_ip = identity__map_ip; 6209de89fe7SArnaldo Carvalho de Melo map_groups__insert(kmaps, curr_map); 6212e538c4aSArnaldo Carvalho de Melo ++kernel_range; 6222e538c4aSArnaldo Carvalho de Melo } 6238a953312SArnaldo Carvalho de Melo filter_symbol: 6244e06255fSArnaldo Carvalho de Melo if (filter && filter(curr_map, pos)) { 6251de8e245SArnaldo Carvalho de Melo discard_symbol: rb_erase(&pos->rb_node, root); 62600a192b3SArnaldo Carvalho de Melo symbol__delete(pos); 6272e538c4aSArnaldo Carvalho de Melo } else { 6284e06255fSArnaldo Carvalho de Melo if (curr_map != map) { 6294e06255fSArnaldo Carvalho de Melo rb_erase(&pos->rb_node, root); 6304e06255fSArnaldo Carvalho de Melo symbols__insert(&curr_map->dso->symbols[curr_map->type], pos); 6318a953312SArnaldo Carvalho de Melo ++moved; 6328a953312SArnaldo Carvalho de Melo } else 6338a953312SArnaldo Carvalho de Melo ++count; 6349974f496SMike Galbraith } 63586470930SIngo Molnar } 63686470930SIngo Molnar 637a1645ce1SZhang, Yanmin if (curr_map != map && 638a1645ce1SZhang, Yanmin self->kernel == DSO_TYPE_GUEST_KERNEL && 63923346f21SArnaldo Carvalho de Melo machine__is_default_guest(kmaps->machine)) { 640a1645ce1SZhang, Yanmin dso__set_loaded(curr_map->dso, curr_map->type); 641a1645ce1SZhang, Yanmin } 642a1645ce1SZhang, Yanmin 6438a953312SArnaldo Carvalho de Melo return count + moved; 64486470930SIngo Molnar } 64586470930SIngo Molnar 6469de89fe7SArnaldo Carvalho de Melo int dso__load_kallsyms(struct dso *self, const char *filename, 6479de89fe7SArnaldo Carvalho de Melo struct map *map, symbol_filter_t filter) 6482e538c4aSArnaldo Carvalho de Melo { 6499e201442SArnaldo Carvalho de Melo if (dso__load_all_kallsyms(self, filename, map) < 0) 6502e538c4aSArnaldo Carvalho de Melo return -1; 6512e538c4aSArnaldo Carvalho de Melo 6524e06255fSArnaldo Carvalho de Melo symbols__fixup_end(&self->symbols[map->type]); 653a1645ce1SZhang, Yanmin if (self->kernel == DSO_TYPE_GUEST_KERNEL) 654a1645ce1SZhang, Yanmin self->origin = DSO__ORIG_GUEST_KERNEL; 655a1645ce1SZhang, Yanmin else 6564e06255fSArnaldo Carvalho de Melo self->origin = DSO__ORIG_KERNEL; 6572e538c4aSArnaldo Carvalho de Melo 6589de89fe7SArnaldo Carvalho de Melo return dso__split_kallsyms(self, map, filter); 659af427bf5SArnaldo Carvalho de Melo } 660af427bf5SArnaldo Carvalho de Melo 661439d473bSArnaldo Carvalho de Melo static int dso__load_perf_map(struct dso *self, struct map *map, 6626beba7adSArnaldo Carvalho de Melo symbol_filter_t filter) 66380d496beSPekka Enberg { 66480d496beSPekka Enberg char *line = NULL; 66580d496beSPekka Enberg size_t n; 66680d496beSPekka Enberg FILE *file; 66780d496beSPekka Enberg int nr_syms = 0; 66880d496beSPekka Enberg 669439d473bSArnaldo Carvalho de Melo file = fopen(self->long_name, "r"); 67080d496beSPekka Enberg if (file == NULL) 67180d496beSPekka Enberg goto out_failure; 67280d496beSPekka Enberg 67380d496beSPekka Enberg while (!feof(file)) { 6749cffa8d5SPaul Mackerras u64 start, size; 67580d496beSPekka Enberg struct symbol *sym; 67680d496beSPekka Enberg int line_len, len; 67780d496beSPekka Enberg 67880d496beSPekka Enberg line_len = getline(&line, &n, file); 67980d496beSPekka Enberg if (line_len < 0) 68080d496beSPekka Enberg break; 68180d496beSPekka Enberg 68280d496beSPekka Enberg if (!line) 68380d496beSPekka Enberg goto out_failure; 68480d496beSPekka Enberg 68580d496beSPekka Enberg line[--line_len] = '\0'; /* \n */ 68680d496beSPekka Enberg 68780d496beSPekka Enberg len = hex2u64(line, &start); 68880d496beSPekka Enberg 68980d496beSPekka Enberg len++; 69080d496beSPekka Enberg if (len + 2 >= line_len) 69180d496beSPekka Enberg continue; 69280d496beSPekka Enberg 69380d496beSPekka Enberg len += hex2u64(line + len, &size); 69480d496beSPekka Enberg 69580d496beSPekka Enberg len++; 69680d496beSPekka Enberg if (len + 2 >= line_len) 69780d496beSPekka Enberg continue; 69880d496beSPekka Enberg 699c408fedfSArnaldo Carvalho de Melo sym = symbol__new(start, size, STB_GLOBAL, line + len); 70080d496beSPekka Enberg 70180d496beSPekka Enberg if (sym == NULL) 70280d496beSPekka Enberg goto out_delete_line; 70380d496beSPekka Enberg 704439d473bSArnaldo Carvalho de Melo if (filter && filter(map, sym)) 70500a192b3SArnaldo Carvalho de Melo symbol__delete(sym); 70680d496beSPekka Enberg else { 7076a4694a4SArnaldo Carvalho de Melo symbols__insert(&self->symbols[map->type], sym); 70880d496beSPekka Enberg nr_syms++; 70980d496beSPekka Enberg } 71080d496beSPekka Enberg } 71180d496beSPekka Enberg 71280d496beSPekka Enberg free(line); 71380d496beSPekka Enberg fclose(file); 71480d496beSPekka Enberg 71580d496beSPekka Enberg return nr_syms; 71680d496beSPekka Enberg 71780d496beSPekka Enberg out_delete_line: 71880d496beSPekka Enberg free(line); 71980d496beSPekka Enberg out_failure: 72080d496beSPekka Enberg return -1; 72180d496beSPekka Enberg } 72280d496beSPekka Enberg 72386470930SIngo Molnar /** 72486470930SIngo Molnar * elf_symtab__for_each_symbol - iterate thru all the symbols 72586470930SIngo Molnar * 72686470930SIngo Molnar * @self: struct elf_symtab instance to iterate 72783a0944fSIngo Molnar * @idx: uint32_t idx 72886470930SIngo Molnar * @sym: GElf_Sym iterator 72986470930SIngo Molnar */ 73083a0944fSIngo Molnar #define elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) \ 73183a0944fSIngo Molnar for (idx = 0, gelf_getsym(syms, idx, &sym);\ 73283a0944fSIngo Molnar idx < nr_syms; \ 73383a0944fSIngo Molnar idx++, gelf_getsym(syms, idx, &sym)) 73486470930SIngo Molnar 73586470930SIngo Molnar static inline uint8_t elf_sym__type(const GElf_Sym *sym) 73686470930SIngo Molnar { 73786470930SIngo Molnar return GELF_ST_TYPE(sym->st_info); 73886470930SIngo Molnar } 73986470930SIngo Molnar 74086470930SIngo Molnar static inline int elf_sym__is_function(const GElf_Sym *sym) 74186470930SIngo Molnar { 74286470930SIngo Molnar return elf_sym__type(sym) == STT_FUNC && 74386470930SIngo Molnar sym->st_name != 0 && 74481833130SArnaldo Carvalho de Melo sym->st_shndx != SHN_UNDEF; 74586470930SIngo Molnar } 74686470930SIngo Molnar 747f1dfa0b1SArnaldo Carvalho de Melo static inline bool elf_sym__is_object(const GElf_Sym *sym) 748f1dfa0b1SArnaldo Carvalho de Melo { 749f1dfa0b1SArnaldo Carvalho de Melo return elf_sym__type(sym) == STT_OBJECT && 750f1dfa0b1SArnaldo Carvalho de Melo sym->st_name != 0 && 751f1dfa0b1SArnaldo Carvalho de Melo sym->st_shndx != SHN_UNDEF; 752f1dfa0b1SArnaldo Carvalho de Melo } 753f1dfa0b1SArnaldo Carvalho de Melo 7546cfcc53eSMike Galbraith static inline int elf_sym__is_label(const GElf_Sym *sym) 7556cfcc53eSMike Galbraith { 7566cfcc53eSMike Galbraith return elf_sym__type(sym) == STT_NOTYPE && 7576cfcc53eSMike Galbraith sym->st_name != 0 && 7586cfcc53eSMike Galbraith sym->st_shndx != SHN_UNDEF && 7596cfcc53eSMike Galbraith sym->st_shndx != SHN_ABS; 7606cfcc53eSMike Galbraith } 7616cfcc53eSMike Galbraith 7626cfcc53eSMike Galbraith static inline const char *elf_sec__name(const GElf_Shdr *shdr, 7636cfcc53eSMike Galbraith const Elf_Data *secstrs) 7646cfcc53eSMike Galbraith { 7656cfcc53eSMike Galbraith return secstrs->d_buf + shdr->sh_name; 7666cfcc53eSMike Galbraith } 7676cfcc53eSMike Galbraith 7686cfcc53eSMike Galbraith static inline int elf_sec__is_text(const GElf_Shdr *shdr, 7696cfcc53eSMike Galbraith const Elf_Data *secstrs) 7706cfcc53eSMike Galbraith { 7716cfcc53eSMike Galbraith return strstr(elf_sec__name(shdr, secstrs), "text") != NULL; 7726cfcc53eSMike Galbraith } 7736cfcc53eSMike Galbraith 774f1dfa0b1SArnaldo Carvalho de Melo static inline bool elf_sec__is_data(const GElf_Shdr *shdr, 775f1dfa0b1SArnaldo Carvalho de Melo const Elf_Data *secstrs) 776f1dfa0b1SArnaldo Carvalho de Melo { 777f1dfa0b1SArnaldo Carvalho de Melo return strstr(elf_sec__name(shdr, secstrs), "data") != NULL; 778f1dfa0b1SArnaldo Carvalho de Melo } 779f1dfa0b1SArnaldo Carvalho de Melo 78086470930SIngo Molnar static inline const char *elf_sym__name(const GElf_Sym *sym, 78186470930SIngo Molnar const Elf_Data *symstrs) 78286470930SIngo Molnar { 78386470930SIngo Molnar return symstrs->d_buf + sym->st_name; 78486470930SIngo Molnar } 78586470930SIngo Molnar 78686470930SIngo Molnar static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, 78786470930SIngo Molnar GElf_Shdr *shp, const char *name, 78883a0944fSIngo Molnar size_t *idx) 78986470930SIngo Molnar { 79086470930SIngo Molnar Elf_Scn *sec = NULL; 79186470930SIngo Molnar size_t cnt = 1; 79286470930SIngo Molnar 79386470930SIngo Molnar while ((sec = elf_nextscn(elf, sec)) != NULL) { 79486470930SIngo Molnar char *str; 79586470930SIngo Molnar 79686470930SIngo Molnar gelf_getshdr(sec, shp); 79786470930SIngo Molnar str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name); 79886470930SIngo Molnar if (!strcmp(name, str)) { 79983a0944fSIngo Molnar if (idx) 80083a0944fSIngo Molnar *idx = cnt; 80186470930SIngo Molnar break; 80286470930SIngo Molnar } 80386470930SIngo Molnar ++cnt; 80486470930SIngo Molnar } 80586470930SIngo Molnar 80686470930SIngo Molnar return sec; 80786470930SIngo Molnar } 80886470930SIngo Molnar 80986470930SIngo Molnar #define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \ 81086470930SIngo Molnar for (idx = 0, pos = gelf_getrel(reldata, 0, &pos_mem); \ 81186470930SIngo Molnar idx < nr_entries; \ 81286470930SIngo Molnar ++idx, pos = gelf_getrel(reldata, idx, &pos_mem)) 81386470930SIngo Molnar 81486470930SIngo Molnar #define elf_section__for_each_rela(reldata, pos, pos_mem, idx, nr_entries) \ 81586470930SIngo Molnar for (idx = 0, pos = gelf_getrela(reldata, 0, &pos_mem); \ 81686470930SIngo Molnar idx < nr_entries; \ 81786470930SIngo Molnar ++idx, pos = gelf_getrela(reldata, idx, &pos_mem)) 81886470930SIngo Molnar 819a25e46c4SArnaldo Carvalho de Melo /* 820a25e46c4SArnaldo Carvalho de Melo * We need to check if we have a .dynsym, so that we can handle the 821a25e46c4SArnaldo Carvalho de Melo * .plt, synthesizing its symbols, that aren't on the symtabs (be it 822a25e46c4SArnaldo Carvalho de Melo * .dynsym or .symtab). 823a25e46c4SArnaldo Carvalho de Melo * And always look at the original dso, not at debuginfo packages, that 824a25e46c4SArnaldo Carvalho de Melo * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS). 825a25e46c4SArnaldo Carvalho de Melo */ 82682164161SArnaldo Carvalho de Melo static int dso__synthesize_plt_symbols(struct dso *self, struct map *map, 82782164161SArnaldo Carvalho de Melo symbol_filter_t filter) 82886470930SIngo Molnar { 82986470930SIngo Molnar uint32_t nr_rel_entries, idx; 83086470930SIngo Molnar GElf_Sym sym; 8319cffa8d5SPaul Mackerras u64 plt_offset; 83286470930SIngo Molnar GElf_Shdr shdr_plt; 83386470930SIngo Molnar struct symbol *f; 834a25e46c4SArnaldo Carvalho de Melo GElf_Shdr shdr_rel_plt, shdr_dynsym; 83586470930SIngo Molnar Elf_Data *reldata, *syms, *symstrs; 836a25e46c4SArnaldo Carvalho de Melo Elf_Scn *scn_plt_rel, *scn_symstrs, *scn_dynsym; 837a25e46c4SArnaldo Carvalho de Melo size_t dynsym_idx; 838a25e46c4SArnaldo Carvalho de Melo GElf_Ehdr ehdr; 83986470930SIngo Molnar char sympltname[1024]; 840a25e46c4SArnaldo Carvalho de Melo Elf *elf; 841a25e46c4SArnaldo Carvalho de Melo int nr = 0, symidx, fd, err = 0; 84286470930SIngo Molnar 843439d473bSArnaldo Carvalho de Melo fd = open(self->long_name, O_RDONLY); 844a25e46c4SArnaldo Carvalho de Melo if (fd < 0) 845a25e46c4SArnaldo Carvalho de Melo goto out; 846a25e46c4SArnaldo Carvalho de Melo 84784087126SMarti Raudsepp elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 848a25e46c4SArnaldo Carvalho de Melo if (elf == NULL) 849a25e46c4SArnaldo Carvalho de Melo goto out_close; 850a25e46c4SArnaldo Carvalho de Melo 851a25e46c4SArnaldo Carvalho de Melo if (gelf_getehdr(elf, &ehdr) == NULL) 852a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 853a25e46c4SArnaldo Carvalho de Melo 854a25e46c4SArnaldo Carvalho de Melo scn_dynsym = elf_section_by_name(elf, &ehdr, &shdr_dynsym, 855a25e46c4SArnaldo Carvalho de Melo ".dynsym", &dynsym_idx); 856a25e46c4SArnaldo Carvalho de Melo if (scn_dynsym == NULL) 857a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 858a25e46c4SArnaldo Carvalho de Melo 859a25e46c4SArnaldo Carvalho de Melo scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt, 86086470930SIngo Molnar ".rela.plt", NULL); 86186470930SIngo Molnar if (scn_plt_rel == NULL) { 862a25e46c4SArnaldo Carvalho de Melo scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt, 86386470930SIngo Molnar ".rel.plt", NULL); 86486470930SIngo Molnar if (scn_plt_rel == NULL) 865a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 86686470930SIngo Molnar } 86786470930SIngo Molnar 868a25e46c4SArnaldo Carvalho de Melo err = -1; 86986470930SIngo Molnar 870a25e46c4SArnaldo Carvalho de Melo if (shdr_rel_plt.sh_link != dynsym_idx) 871a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 872a25e46c4SArnaldo Carvalho de Melo 873a25e46c4SArnaldo Carvalho de Melo if (elf_section_by_name(elf, &ehdr, &shdr_plt, ".plt", NULL) == NULL) 874a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 87586470930SIngo Molnar 87686470930SIngo Molnar /* 87783a0944fSIngo Molnar * Fetch the relocation section to find the idxes to the GOT 87886470930SIngo Molnar * and the symbols in the .dynsym they refer to. 87986470930SIngo Molnar */ 88086470930SIngo Molnar reldata = elf_getdata(scn_plt_rel, NULL); 88186470930SIngo Molnar if (reldata == NULL) 882a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 88386470930SIngo Molnar 88486470930SIngo Molnar syms = elf_getdata(scn_dynsym, NULL); 88586470930SIngo Molnar if (syms == NULL) 886a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 88786470930SIngo Molnar 888a25e46c4SArnaldo Carvalho de Melo scn_symstrs = elf_getscn(elf, shdr_dynsym.sh_link); 88986470930SIngo Molnar if (scn_symstrs == NULL) 890a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 89186470930SIngo Molnar 89286470930SIngo Molnar symstrs = elf_getdata(scn_symstrs, NULL); 89386470930SIngo Molnar if (symstrs == NULL) 894a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 89586470930SIngo Molnar 89686470930SIngo Molnar nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize; 89786470930SIngo Molnar plt_offset = shdr_plt.sh_offset; 89886470930SIngo Molnar 89986470930SIngo Molnar if (shdr_rel_plt.sh_type == SHT_RELA) { 90086470930SIngo Molnar GElf_Rela pos_mem, *pos; 90186470930SIngo Molnar 90286470930SIngo Molnar elf_section__for_each_rela(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 } 92182164161SArnaldo Carvalho de Melo } 92286470930SIngo Molnar } else if (shdr_rel_plt.sh_type == SHT_REL) { 92386470930SIngo Molnar GElf_Rel pos_mem, *pos; 92486470930SIngo Molnar elf_section__for_each_rel(reldata, pos, pos_mem, idx, 92586470930SIngo Molnar nr_rel_entries) { 92686470930SIngo Molnar symidx = GELF_R_SYM(pos->r_info); 92786470930SIngo Molnar plt_offset += shdr_plt.sh_entsize; 92886470930SIngo Molnar gelf_getsym(syms, symidx, &sym); 92986470930SIngo Molnar snprintf(sympltname, sizeof(sympltname), 93086470930SIngo Molnar "%s@plt", elf_sym__name(&sym, symstrs)); 93186470930SIngo Molnar 93286470930SIngo Molnar f = symbol__new(plt_offset, shdr_plt.sh_entsize, 933c408fedfSArnaldo Carvalho de Melo STB_GLOBAL, sympltname); 93486470930SIngo Molnar if (!f) 935a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 93686470930SIngo Molnar 93782164161SArnaldo Carvalho de Melo if (filter && filter(map, f)) 93882164161SArnaldo Carvalho de Melo symbol__delete(f); 93982164161SArnaldo Carvalho de Melo else { 9406a4694a4SArnaldo Carvalho de Melo symbols__insert(&self->symbols[map->type], f); 94186470930SIngo Molnar ++nr; 94286470930SIngo Molnar } 94386470930SIngo Molnar } 94482164161SArnaldo Carvalho de Melo } 94586470930SIngo Molnar 946a25e46c4SArnaldo Carvalho de Melo err = 0; 947a25e46c4SArnaldo Carvalho de Melo out_elf_end: 948a25e46c4SArnaldo Carvalho de Melo elf_end(elf); 949a25e46c4SArnaldo Carvalho de Melo out_close: 950a25e46c4SArnaldo Carvalho de Melo close(fd); 951a25e46c4SArnaldo Carvalho de Melo 952a25e46c4SArnaldo Carvalho de Melo if (err == 0) 95386470930SIngo Molnar return nr; 954a25e46c4SArnaldo Carvalho de Melo out: 955fe2197b8SArnaldo Carvalho de Melo pr_debug("%s: problems reading %s PLT info.\n", 956439d473bSArnaldo Carvalho de Melo __func__, self->long_name); 957a25e46c4SArnaldo Carvalho de Melo return 0; 95886470930SIngo Molnar } 95986470930SIngo Molnar 960d45868d3SArnaldo Carvalho de Melo static bool elf_sym__is_a(GElf_Sym *self, enum map_type type) 961d45868d3SArnaldo Carvalho de Melo { 962d45868d3SArnaldo Carvalho de Melo switch (type) { 963d45868d3SArnaldo Carvalho de Melo case MAP__FUNCTION: 964d45868d3SArnaldo Carvalho de Melo return elf_sym__is_function(self); 965f1dfa0b1SArnaldo Carvalho de Melo case MAP__VARIABLE: 966f1dfa0b1SArnaldo Carvalho de Melo return elf_sym__is_object(self); 967d45868d3SArnaldo Carvalho de Melo default: 968d45868d3SArnaldo Carvalho de Melo return false; 969d45868d3SArnaldo Carvalho de Melo } 970d45868d3SArnaldo Carvalho de Melo } 971d45868d3SArnaldo Carvalho de Melo 972d45868d3SArnaldo Carvalho de Melo static bool elf_sec__is_a(GElf_Shdr *self, Elf_Data *secstrs, enum map_type type) 973d45868d3SArnaldo Carvalho de Melo { 974d45868d3SArnaldo Carvalho de Melo switch (type) { 975d45868d3SArnaldo Carvalho de Melo case MAP__FUNCTION: 976d45868d3SArnaldo Carvalho de Melo return elf_sec__is_text(self, secstrs); 977f1dfa0b1SArnaldo Carvalho de Melo case MAP__VARIABLE: 978f1dfa0b1SArnaldo Carvalho de Melo return elf_sec__is_data(self, secstrs); 979d45868d3SArnaldo Carvalho de Melo default: 980d45868d3SArnaldo Carvalho de Melo return false; 981d45868d3SArnaldo Carvalho de Melo } 982d45868d3SArnaldo Carvalho de Melo } 983d45868d3SArnaldo Carvalho de Melo 98470c3856bSEric B Munson static size_t elf_addr_to_index(Elf *elf, GElf_Addr addr) 98570c3856bSEric B Munson { 98670c3856bSEric B Munson Elf_Scn *sec = NULL; 98770c3856bSEric B Munson GElf_Shdr shdr; 98870c3856bSEric B Munson size_t cnt = 1; 98970c3856bSEric B Munson 99070c3856bSEric B Munson while ((sec = elf_nextscn(elf, sec)) != NULL) { 99170c3856bSEric B Munson gelf_getshdr(sec, &shdr); 99270c3856bSEric B Munson 99370c3856bSEric B Munson if ((addr >= shdr.sh_addr) && 99470c3856bSEric B Munson (addr < (shdr.sh_addr + shdr.sh_size))) 99570c3856bSEric B Munson return cnt; 99670c3856bSEric B Munson 99770c3856bSEric B Munson ++cnt; 99870c3856bSEric B Munson } 99970c3856bSEric B Munson 100070c3856bSEric B Munson return -1; 100170c3856bSEric B Munson } 100270c3856bSEric B Munson 10039de89fe7SArnaldo Carvalho de Melo static int dso__load_sym(struct dso *self, struct map *map, const char *name, 10046da80ce8SDave Martin int fd, symbol_filter_t filter, int kmodule, 10056da80ce8SDave Martin int want_symtab) 100686470930SIngo Molnar { 10079de89fe7SArnaldo Carvalho de Melo struct kmap *kmap = self->kernel ? map__kmap(map) : NULL; 10082e538c4aSArnaldo Carvalho de Melo struct map *curr_map = map; 10092e538c4aSArnaldo Carvalho de Melo struct dso *curr_dso = self; 10106cfcc53eSMike Galbraith Elf_Data *symstrs, *secstrs; 101186470930SIngo Molnar uint32_t nr_syms; 101286470930SIngo Molnar int err = -1; 101383a0944fSIngo Molnar uint32_t idx; 101486470930SIngo Molnar GElf_Ehdr ehdr; 101570c3856bSEric B Munson GElf_Shdr shdr, opdshdr; 101670c3856bSEric B Munson Elf_Data *syms, *opddata = NULL; 101786470930SIngo Molnar GElf_Sym sym; 101870c3856bSEric B Munson Elf_Scn *sec, *sec_strndx, *opdsec; 101986470930SIngo Molnar Elf *elf; 1020439d473bSArnaldo Carvalho de Melo int nr = 0; 102170c3856bSEric B Munson size_t opdidx = 0; 102286470930SIngo Molnar 102384087126SMarti Raudsepp elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 102486470930SIngo Molnar if (elf == NULL) { 10258b1389efSDave Martin pr_debug("%s: cannot read %s ELF file.\n", __func__, name); 102686470930SIngo Molnar goto out_close; 102786470930SIngo Molnar } 102886470930SIngo Molnar 102986470930SIngo Molnar if (gelf_getehdr(elf, &ehdr) == NULL) { 10308b1389efSDave Martin pr_debug("%s: cannot get elf header.\n", __func__); 103186470930SIngo Molnar goto out_elf_end; 103286470930SIngo Molnar } 103386470930SIngo Molnar 10346da80ce8SDave Martin /* Always reject images with a mismatched build-id: */ 103521916c38SDave Martin if (self->has_build_id) { 103621916c38SDave Martin u8 build_id[BUILD_ID_SIZE]; 103721916c38SDave Martin 103821916c38SDave Martin if (elf_read_build_id(elf, build_id, 103921916c38SDave Martin BUILD_ID_SIZE) != BUILD_ID_SIZE) 104021916c38SDave Martin goto out_elf_end; 104121916c38SDave Martin 104221916c38SDave Martin if (!dso__build_id_equal(self, build_id)) 104321916c38SDave Martin goto out_elf_end; 104421916c38SDave Martin } 104521916c38SDave Martin 104686470930SIngo Molnar sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL); 104786470930SIngo Molnar if (sec == NULL) { 10486da80ce8SDave Martin if (want_symtab) 10496da80ce8SDave Martin goto out_elf_end; 10506da80ce8SDave Martin 1051a25e46c4SArnaldo Carvalho de Melo sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL); 1052a25e46c4SArnaldo Carvalho de Melo if (sec == NULL) 105386470930SIngo Molnar goto out_elf_end; 105486470930SIngo Molnar } 105586470930SIngo Molnar 105670c3856bSEric B Munson opdsec = elf_section_by_name(elf, &ehdr, &opdshdr, ".opd", &opdidx); 105770c3856bSEric B Munson if (opdsec) 105870c3856bSEric B Munson opddata = elf_rawdata(opdsec, NULL); 105970c3856bSEric B Munson 106086470930SIngo Molnar syms = elf_getdata(sec, NULL); 106186470930SIngo Molnar if (syms == NULL) 106286470930SIngo Molnar goto out_elf_end; 106386470930SIngo Molnar 106486470930SIngo Molnar sec = elf_getscn(elf, shdr.sh_link); 106586470930SIngo Molnar if (sec == NULL) 106686470930SIngo Molnar goto out_elf_end; 106786470930SIngo Molnar 106886470930SIngo Molnar symstrs = elf_getdata(sec, NULL); 106986470930SIngo Molnar if (symstrs == NULL) 107086470930SIngo Molnar goto out_elf_end; 107186470930SIngo Molnar 10726cfcc53eSMike Galbraith sec_strndx = elf_getscn(elf, ehdr.e_shstrndx); 10736cfcc53eSMike Galbraith if (sec_strndx == NULL) 10746cfcc53eSMike Galbraith goto out_elf_end; 10756cfcc53eSMike Galbraith 10766cfcc53eSMike Galbraith secstrs = elf_getdata(sec_strndx, NULL); 10779b30a26bSStoyan Gaydarov if (secstrs == NULL) 10786cfcc53eSMike Galbraith goto out_elf_end; 10796cfcc53eSMike Galbraith 108086470930SIngo Molnar nr_syms = shdr.sh_size / shdr.sh_entsize; 108186470930SIngo Molnar 1082e9fbc9dcSArjan van de Ven memset(&sym, 0, sizeof(sym)); 1083a1645ce1SZhang, Yanmin if (self->kernel == DSO_TYPE_USER) { 108430d7a77dSArnaldo Carvalho de Melo self->adjust_symbols = (ehdr.e_type == ET_EXEC || 108530d7a77dSArnaldo Carvalho de Melo elf_section_by_name(elf, &ehdr, &shdr, 1086f5812a7aSArnaldo Carvalho de Melo ".gnu.prelink_undo", 108730d7a77dSArnaldo Carvalho de Melo NULL) != NULL); 1088d20ff6bdSMike Galbraith } else self->adjust_symbols = 0; 1089d20ff6bdSMike Galbraith 109083a0944fSIngo Molnar elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) { 109186470930SIngo Molnar struct symbol *f; 109256b03f3cSArnaldo Carvalho de Melo const char *elf_name = elf_sym__name(&sym, symstrs); 10932e538c4aSArnaldo Carvalho de Melo char *demangled = NULL; 10946cfcc53eSMike Galbraith int is_label = elf_sym__is_label(&sym); 10956cfcc53eSMike Galbraith const char *section_name; 109686470930SIngo Molnar 10979de89fe7SArnaldo Carvalho de Melo if (kmap && kmap->ref_reloc_sym && kmap->ref_reloc_sym->name && 10989de89fe7SArnaldo Carvalho de Melo strcmp(elf_name, kmap->ref_reloc_sym->name) == 0) 10999de89fe7SArnaldo Carvalho de Melo kmap->ref_reloc_sym->unrelocated_addr = sym.st_value; 110056b03f3cSArnaldo Carvalho de Melo 1101d45868d3SArnaldo Carvalho de Melo if (!is_label && !elf_sym__is_a(&sym, map->type)) 110286470930SIngo Molnar continue; 110386470930SIngo Molnar 1104696b97a5SDave Martin /* Reject ARM ELF "mapping symbols": these aren't unique and 1105696b97a5SDave Martin * don't identify functions, so will confuse the profile 1106696b97a5SDave Martin * output: */ 1107696b97a5SDave Martin if (ehdr.e_machine == EM_ARM) { 1108696b97a5SDave Martin if (!strcmp(elf_name, "$a") || 1109696b97a5SDave Martin !strcmp(elf_name, "$d") || 1110696b97a5SDave Martin !strcmp(elf_name, "$t")) 1111696b97a5SDave Martin continue; 1112696b97a5SDave Martin } 1113696b97a5SDave Martin 111470c3856bSEric B Munson if (opdsec && sym.st_shndx == opdidx) { 111570c3856bSEric B Munson u32 offset = sym.st_value - opdshdr.sh_addr; 111670c3856bSEric B Munson u64 *opd = opddata->d_buf + offset; 111770c3856bSEric B Munson sym.st_value = *opd; 111870c3856bSEric B Munson sym.st_shndx = elf_addr_to_index(elf, sym.st_value); 111970c3856bSEric B Munson } 112070c3856bSEric B Munson 112186470930SIngo Molnar sec = elf_getscn(elf, sym.st_shndx); 112286470930SIngo Molnar if (!sec) 112386470930SIngo Molnar goto out_elf_end; 112486470930SIngo Molnar 112586470930SIngo Molnar gelf_getshdr(sec, &shdr); 11266cfcc53eSMike Galbraith 1127d45868d3SArnaldo Carvalho de Melo if (is_label && !elf_sec__is_a(&shdr, secstrs, map->type)) 11286cfcc53eSMike Galbraith continue; 11296cfcc53eSMike Galbraith 11306cfcc53eSMike Galbraith section_name = elf_sec__name(&shdr, secstrs); 113186470930SIngo Molnar 1132a1645ce1SZhang, Yanmin if (self->kernel != DSO_TYPE_USER || kmodule) { 11332e538c4aSArnaldo Carvalho de Melo char dso_name[PATH_MAX]; 11342e538c4aSArnaldo Carvalho de Melo 11352e538c4aSArnaldo Carvalho de Melo if (strcmp(section_name, 1136b63be8d7SArnaldo Carvalho de Melo (curr_dso->short_name + 1137b63be8d7SArnaldo Carvalho de Melo self->short_name_len)) == 0) 11382e538c4aSArnaldo Carvalho de Melo goto new_symbol; 11392e538c4aSArnaldo Carvalho de Melo 11402e538c4aSArnaldo Carvalho de Melo if (strcmp(section_name, ".text") == 0) { 11412e538c4aSArnaldo Carvalho de Melo curr_map = map; 11422e538c4aSArnaldo Carvalho de Melo curr_dso = self; 11432e538c4aSArnaldo Carvalho de Melo goto new_symbol; 1144af427bf5SArnaldo Carvalho de Melo } 1145af427bf5SArnaldo Carvalho de Melo 11462e538c4aSArnaldo Carvalho de Melo snprintf(dso_name, sizeof(dso_name), 11472e538c4aSArnaldo Carvalho de Melo "%s%s", self->short_name, section_name); 11482e538c4aSArnaldo Carvalho de Melo 11499de89fe7SArnaldo Carvalho de Melo curr_map = map_groups__find_by_name(kmap->kmaps, map->type, dso_name); 11502e538c4aSArnaldo Carvalho de Melo if (curr_map == NULL) { 11512e538c4aSArnaldo Carvalho de Melo u64 start = sym.st_value; 11522e538c4aSArnaldo Carvalho de Melo 11532e538c4aSArnaldo Carvalho de Melo if (kmodule) 11542e538c4aSArnaldo Carvalho de Melo start += map->start + shdr.sh_offset; 11552e538c4aSArnaldo Carvalho de Melo 115600a192b3SArnaldo Carvalho de Melo curr_dso = dso__new(dso_name); 11572e538c4aSArnaldo Carvalho de Melo if (curr_dso == NULL) 11582e538c4aSArnaldo Carvalho de Melo goto out_elf_end; 1159a1645ce1SZhang, Yanmin curr_dso->kernel = self->kernel; 11603610583cSArnaldo Carvalho de Melo curr_map = map__new2(start, curr_dso, 11616275ce2dSArnaldo Carvalho de Melo map->type); 11622e538c4aSArnaldo Carvalho de Melo if (curr_map == NULL) { 11632e538c4aSArnaldo Carvalho de Melo dso__delete(curr_dso); 11642e538c4aSArnaldo Carvalho de Melo goto out_elf_end; 11652e538c4aSArnaldo Carvalho de Melo } 1166ed52ce2eSArnaldo Carvalho de Melo curr_map->map_ip = identity__map_ip; 1167ed52ce2eSArnaldo Carvalho de Melo curr_map->unmap_ip = identity__map_ip; 1168b0a9ab62SArnaldo Carvalho de Melo curr_dso->origin = self->origin; 11699de89fe7SArnaldo Carvalho de Melo map_groups__insert(kmap->kmaps, curr_map); 1170a1645ce1SZhang, Yanmin dsos__add(&self->node, curr_dso); 11716275ce2dSArnaldo Carvalho de Melo dso__set_loaded(curr_dso, map->type); 11722e538c4aSArnaldo Carvalho de Melo } else 11732e538c4aSArnaldo Carvalho de Melo curr_dso = curr_map->dso; 11742e538c4aSArnaldo Carvalho de Melo 11752e538c4aSArnaldo Carvalho de Melo goto new_symbol; 11762e538c4aSArnaldo Carvalho de Melo } 11772e538c4aSArnaldo Carvalho de Melo 11782e538c4aSArnaldo Carvalho de Melo if (curr_dso->adjust_symbols) { 117929a9f66dSArnaldo Carvalho de Melo pr_debug4("%s: adjusting symbol: st_value: %#Lx " 118029a9f66dSArnaldo Carvalho de Melo "sh_addr: %#Lx sh_offset: %#Lx\n", __func__, 118129a9f66dSArnaldo Carvalho de Melo (u64)sym.st_value, (u64)shdr.sh_addr, 118229a9f66dSArnaldo Carvalho de Melo (u64)shdr.sh_offset); 118386470930SIngo Molnar sym.st_value -= shdr.sh_addr - shdr.sh_offset; 1184af427bf5SArnaldo Carvalho de Melo } 118528ac909bSArnaldo Carvalho de Melo /* 118628ac909bSArnaldo Carvalho de Melo * We need to figure out if the object was created from C++ sources 118728ac909bSArnaldo Carvalho de Melo * DWARF DW_compile_unit has this, but we don't always have access 118828ac909bSArnaldo Carvalho de Melo * to it... 118928ac909bSArnaldo Carvalho de Melo */ 119083a0944fSIngo Molnar demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI); 119128ac909bSArnaldo Carvalho de Melo if (demangled != NULL) 119283a0944fSIngo Molnar elf_name = demangled; 11932e538c4aSArnaldo Carvalho de Melo new_symbol: 1194c408fedfSArnaldo Carvalho de Melo f = symbol__new(sym.st_value, sym.st_size, 1195c408fedfSArnaldo Carvalho de Melo GELF_ST_BIND(sym.st_info), elf_name); 119628ac909bSArnaldo Carvalho de Melo free(demangled); 119786470930SIngo Molnar if (!f) 119886470930SIngo Molnar goto out_elf_end; 119986470930SIngo Molnar 12002e538c4aSArnaldo Carvalho de Melo if (filter && filter(curr_map, f)) 120100a192b3SArnaldo Carvalho de Melo symbol__delete(f); 120286470930SIngo Molnar else { 12036a4694a4SArnaldo Carvalho de Melo symbols__insert(&curr_dso->symbols[curr_map->type], f); 120486470930SIngo Molnar nr++; 120586470930SIngo Molnar } 120686470930SIngo Molnar } 120786470930SIngo Molnar 12082e538c4aSArnaldo Carvalho de Melo /* 12092e538c4aSArnaldo Carvalho de Melo * For misannotated, zeroed, ASM function sizes. 12102e538c4aSArnaldo Carvalho de Melo */ 12116275ce2dSArnaldo Carvalho de Melo if (nr > 0) { 12126a4694a4SArnaldo Carvalho de Melo symbols__fixup_end(&self->symbols[map->type]); 12136275ce2dSArnaldo Carvalho de Melo if (kmap) { 12146275ce2dSArnaldo Carvalho de Melo /* 12156275ce2dSArnaldo Carvalho de Melo * We need to fixup this here too because we create new 12166275ce2dSArnaldo Carvalho de Melo * maps here, for things like vsyscall sections. 12176275ce2dSArnaldo Carvalho de Melo */ 12186275ce2dSArnaldo Carvalho de Melo __map_groups__fixup_end(kmap->kmaps, map->type); 12196275ce2dSArnaldo Carvalho de Melo } 12206275ce2dSArnaldo Carvalho de Melo } 122186470930SIngo Molnar err = nr; 122286470930SIngo Molnar out_elf_end: 122386470930SIngo Molnar elf_end(elf); 122486470930SIngo Molnar out_close: 122586470930SIngo Molnar return err; 122686470930SIngo Molnar } 122786470930SIngo Molnar 122878075caaSArnaldo Carvalho de Melo static bool dso__build_id_equal(const struct dso *self, u8 *build_id) 122978075caaSArnaldo Carvalho de Melo { 123078075caaSArnaldo Carvalho de Melo return memcmp(self->build_id, build_id, sizeof(self->build_id)) == 0; 123178075caaSArnaldo Carvalho de Melo } 123278075caaSArnaldo Carvalho de Melo 1233a1645ce1SZhang, Yanmin bool __dsos__read_build_ids(struct list_head *head, bool with_hits) 123457f395a7SFrederic Weisbecker { 1235e30a3d12SArnaldo Carvalho de Melo bool have_build_id = false; 123657f395a7SFrederic Weisbecker struct dso *pos; 123757f395a7SFrederic Weisbecker 12386122e4e4SArnaldo Carvalho de Melo list_for_each_entry(pos, head, node) { 12396122e4e4SArnaldo Carvalho de Melo if (with_hits && !pos->hit) 12406122e4e4SArnaldo Carvalho de Melo continue; 1241f6e1467dSArnaldo Carvalho de Melo if (pos->has_build_id) { 1242f6e1467dSArnaldo Carvalho de Melo have_build_id = true; 1243f6e1467dSArnaldo Carvalho de Melo continue; 1244f6e1467dSArnaldo Carvalho de Melo } 1245e30a3d12SArnaldo Carvalho de Melo if (filename__read_build_id(pos->long_name, pos->build_id, 1246e30a3d12SArnaldo Carvalho de Melo sizeof(pos->build_id)) > 0) { 1247e30a3d12SArnaldo Carvalho de Melo have_build_id = true; 1248e30a3d12SArnaldo Carvalho de Melo pos->has_build_id = true; 124957f395a7SFrederic Weisbecker } 12506122e4e4SArnaldo Carvalho de Melo } 125157f395a7SFrederic Weisbecker 1252e30a3d12SArnaldo Carvalho de Melo return have_build_id; 125357f395a7SFrederic Weisbecker } 125457f395a7SFrederic Weisbecker 1255fd7a346eSArnaldo Carvalho de Melo /* 1256fd7a346eSArnaldo Carvalho de Melo * Align offset to 4 bytes as needed for note name and descriptor data. 1257fd7a346eSArnaldo Carvalho de Melo */ 1258fd7a346eSArnaldo Carvalho de Melo #define NOTE_ALIGN(n) (((n) + 3) & -4U) 1259fd7a346eSArnaldo Carvalho de Melo 126021916c38SDave Martin static int elf_read_build_id(Elf *elf, void *bf, size_t size) 12614d1e00a8SArnaldo Carvalho de Melo { 126221916c38SDave Martin int err = -1; 12634d1e00a8SArnaldo Carvalho de Melo GElf_Ehdr ehdr; 12644d1e00a8SArnaldo Carvalho de Melo GElf_Shdr shdr; 1265fd7a346eSArnaldo Carvalho de Melo Elf_Data *data; 12664d1e00a8SArnaldo Carvalho de Melo Elf_Scn *sec; 1267e57cfcdaSPekka Enberg Elf_Kind ek; 1268fd7a346eSArnaldo Carvalho de Melo void *ptr; 12694d1e00a8SArnaldo Carvalho de Melo 12702643ce11SArnaldo Carvalho de Melo if (size < BUILD_ID_SIZE) 12712643ce11SArnaldo Carvalho de Melo goto out; 12722643ce11SArnaldo Carvalho de Melo 1273e57cfcdaSPekka Enberg ek = elf_kind(elf); 1274e57cfcdaSPekka Enberg if (ek != ELF_K_ELF) 127521916c38SDave Martin goto out; 1276e57cfcdaSPekka Enberg 12774d1e00a8SArnaldo Carvalho de Melo if (gelf_getehdr(elf, &ehdr) == NULL) { 12786beba7adSArnaldo Carvalho de Melo pr_err("%s: cannot get elf header.\n", __func__); 127921916c38SDave Martin goto out; 12804d1e00a8SArnaldo Carvalho de Melo } 12814d1e00a8SArnaldo Carvalho de Melo 12822643ce11SArnaldo Carvalho de Melo sec = elf_section_by_name(elf, &ehdr, &shdr, 12832643ce11SArnaldo Carvalho de Melo ".note.gnu.build-id", NULL); 1284fd7a346eSArnaldo Carvalho de Melo if (sec == NULL) { 1285fd7a346eSArnaldo Carvalho de Melo sec = elf_section_by_name(elf, &ehdr, &shdr, 1286fd7a346eSArnaldo Carvalho de Melo ".notes", NULL); 12874d1e00a8SArnaldo Carvalho de Melo if (sec == NULL) 128821916c38SDave Martin goto out; 1289fd7a346eSArnaldo Carvalho de Melo } 12904d1e00a8SArnaldo Carvalho de Melo 1291fd7a346eSArnaldo Carvalho de Melo data = elf_getdata(sec, NULL); 1292fd7a346eSArnaldo Carvalho de Melo if (data == NULL) 129321916c38SDave Martin goto out; 1294fd7a346eSArnaldo Carvalho de Melo 1295fd7a346eSArnaldo Carvalho de Melo ptr = data->d_buf; 1296fd7a346eSArnaldo Carvalho de Melo while (ptr < (data->d_buf + data->d_size)) { 1297fd7a346eSArnaldo Carvalho de Melo GElf_Nhdr *nhdr = ptr; 1298fd7a346eSArnaldo Carvalho de Melo int namesz = NOTE_ALIGN(nhdr->n_namesz), 1299fd7a346eSArnaldo Carvalho de Melo descsz = NOTE_ALIGN(nhdr->n_descsz); 1300fd7a346eSArnaldo Carvalho de Melo const char *name; 1301fd7a346eSArnaldo Carvalho de Melo 1302fd7a346eSArnaldo Carvalho de Melo ptr += sizeof(*nhdr); 1303fd7a346eSArnaldo Carvalho de Melo name = ptr; 1304fd7a346eSArnaldo Carvalho de Melo ptr += namesz; 1305fd7a346eSArnaldo Carvalho de Melo if (nhdr->n_type == NT_GNU_BUILD_ID && 1306fd7a346eSArnaldo Carvalho de Melo nhdr->n_namesz == sizeof("GNU")) { 1307fd7a346eSArnaldo Carvalho de Melo if (memcmp(name, "GNU", sizeof("GNU")) == 0) { 1308fd7a346eSArnaldo Carvalho de Melo memcpy(bf, ptr, BUILD_ID_SIZE); 13092643ce11SArnaldo Carvalho de Melo err = BUILD_ID_SIZE; 1310fd7a346eSArnaldo Carvalho de Melo break; 1311fd7a346eSArnaldo Carvalho de Melo } 1312fd7a346eSArnaldo Carvalho de Melo } 1313fd7a346eSArnaldo Carvalho de Melo ptr += descsz; 1314fd7a346eSArnaldo Carvalho de Melo } 131521916c38SDave Martin 131621916c38SDave Martin out: 131721916c38SDave Martin return err; 131821916c38SDave Martin } 131921916c38SDave Martin 132021916c38SDave Martin int filename__read_build_id(const char *filename, void *bf, size_t size) 132121916c38SDave Martin { 132221916c38SDave Martin int fd, err = -1; 132321916c38SDave Martin Elf *elf; 132421916c38SDave Martin 132521916c38SDave Martin if (size < BUILD_ID_SIZE) 132621916c38SDave Martin goto out; 132721916c38SDave Martin 132821916c38SDave Martin fd = open(filename, O_RDONLY); 132921916c38SDave Martin if (fd < 0) 133021916c38SDave Martin goto out; 133121916c38SDave Martin 133221916c38SDave Martin elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 133321916c38SDave Martin if (elf == NULL) { 133421916c38SDave Martin pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename); 133521916c38SDave Martin goto out_close; 133621916c38SDave Martin } 133721916c38SDave Martin 133821916c38SDave Martin err = elf_read_build_id(elf, bf, size); 133921916c38SDave Martin 13402643ce11SArnaldo Carvalho de Melo elf_end(elf); 13412643ce11SArnaldo Carvalho de Melo out_close: 13422643ce11SArnaldo Carvalho de Melo close(fd); 13432643ce11SArnaldo Carvalho de Melo out: 13442643ce11SArnaldo Carvalho de Melo return err; 13452643ce11SArnaldo Carvalho de Melo } 13462643ce11SArnaldo Carvalho de Melo 1347f1617b40SArnaldo Carvalho de Melo int sysfs__read_build_id(const char *filename, void *build_id, size_t size) 1348f1617b40SArnaldo Carvalho de Melo { 1349f1617b40SArnaldo Carvalho de Melo int fd, err = -1; 1350f1617b40SArnaldo Carvalho de Melo 1351f1617b40SArnaldo Carvalho de Melo if (size < BUILD_ID_SIZE) 1352f1617b40SArnaldo Carvalho de Melo goto out; 1353f1617b40SArnaldo Carvalho de Melo 1354f1617b40SArnaldo Carvalho de Melo fd = open(filename, O_RDONLY); 1355f1617b40SArnaldo Carvalho de Melo if (fd < 0) 1356f1617b40SArnaldo Carvalho de Melo goto out; 1357f1617b40SArnaldo Carvalho de Melo 1358f1617b40SArnaldo Carvalho de Melo while (1) { 1359f1617b40SArnaldo Carvalho de Melo char bf[BUFSIZ]; 1360f1617b40SArnaldo Carvalho de Melo GElf_Nhdr nhdr; 1361f1617b40SArnaldo Carvalho de Melo int namesz, descsz; 1362f1617b40SArnaldo Carvalho de Melo 1363f1617b40SArnaldo Carvalho de Melo if (read(fd, &nhdr, sizeof(nhdr)) != sizeof(nhdr)) 1364f1617b40SArnaldo Carvalho de Melo break; 1365f1617b40SArnaldo Carvalho de Melo 1366fd7a346eSArnaldo Carvalho de Melo namesz = NOTE_ALIGN(nhdr.n_namesz); 1367fd7a346eSArnaldo Carvalho de Melo descsz = NOTE_ALIGN(nhdr.n_descsz); 1368f1617b40SArnaldo Carvalho de Melo if (nhdr.n_type == NT_GNU_BUILD_ID && 1369f1617b40SArnaldo Carvalho de Melo nhdr.n_namesz == sizeof("GNU")) { 1370f1617b40SArnaldo Carvalho de Melo if (read(fd, bf, namesz) != namesz) 1371f1617b40SArnaldo Carvalho de Melo break; 1372f1617b40SArnaldo Carvalho de Melo if (memcmp(bf, "GNU", sizeof("GNU")) == 0) { 1373f1617b40SArnaldo Carvalho de Melo if (read(fd, build_id, 1374f1617b40SArnaldo Carvalho de Melo BUILD_ID_SIZE) == BUILD_ID_SIZE) { 1375f1617b40SArnaldo Carvalho de Melo err = 0; 1376f1617b40SArnaldo Carvalho de Melo break; 1377f1617b40SArnaldo Carvalho de Melo } 1378f1617b40SArnaldo Carvalho de Melo } else if (read(fd, bf, descsz) != descsz) 1379f1617b40SArnaldo Carvalho de Melo break; 1380f1617b40SArnaldo Carvalho de Melo } else { 1381f1617b40SArnaldo Carvalho de Melo int n = namesz + descsz; 1382f1617b40SArnaldo Carvalho de Melo if (read(fd, bf, n) != n) 1383f1617b40SArnaldo Carvalho de Melo break; 1384f1617b40SArnaldo Carvalho de Melo } 1385f1617b40SArnaldo Carvalho de Melo } 1386f1617b40SArnaldo Carvalho de Melo close(fd); 1387f1617b40SArnaldo Carvalho de Melo out: 1388f1617b40SArnaldo Carvalho de Melo return err; 1389f1617b40SArnaldo Carvalho de Melo } 1390f1617b40SArnaldo Carvalho de Melo 139194cb9e38SArnaldo Carvalho de Melo char dso__symtab_origin(const struct dso *self) 139294cb9e38SArnaldo Carvalho de Melo { 139394cb9e38SArnaldo Carvalho de Melo static const char origin[] = { 139494cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_KERNEL] = 'k', 139594cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_JAVA_JIT] = 'j', 13964cf40131SArnaldo Carvalho de Melo [DSO__ORIG_BUILD_ID_CACHE] = 'B', 139794cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_FEDORA] = 'f', 139894cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_UBUNTU] = 'u', 139994cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_BUILDID] = 'b', 140094cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_DSO] = 'd', 1401439d473bSArnaldo Carvalho de Melo [DSO__ORIG_KMODULE] = 'K', 1402a1645ce1SZhang, Yanmin [DSO__ORIG_GUEST_KERNEL] = 'g', 1403a1645ce1SZhang, Yanmin [DSO__ORIG_GUEST_KMODULE] = 'G', 140494cb9e38SArnaldo Carvalho de Melo }; 140594cb9e38SArnaldo Carvalho de Melo 140694cb9e38SArnaldo Carvalho de Melo if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND) 140794cb9e38SArnaldo Carvalho de Melo return '!'; 140894cb9e38SArnaldo Carvalho de Melo return origin[self->origin]; 140994cb9e38SArnaldo Carvalho de Melo } 141094cb9e38SArnaldo Carvalho de Melo 14119de89fe7SArnaldo Carvalho de Melo int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) 141286470930SIngo Molnar { 14134d1e00a8SArnaldo Carvalho de Melo int size = PATH_MAX; 1414c338aee8SArnaldo Carvalho de Melo char *name; 141586470930SIngo Molnar int ret = -1; 141686470930SIngo Molnar int fd; 141723346f21SArnaldo Carvalho de Melo struct machine *machine; 1418a1645ce1SZhang, Yanmin const char *root_dir; 14196da80ce8SDave Martin int want_symtab; 142086470930SIngo Molnar 14213610583cSArnaldo Carvalho de Melo dso__set_loaded(self, map->type); 142266bd8424SArnaldo Carvalho de Melo 1423a1645ce1SZhang, Yanmin if (self->kernel == DSO_TYPE_KERNEL) 14249de89fe7SArnaldo Carvalho de Melo return dso__load_kernel_sym(self, map, filter); 1425a1645ce1SZhang, Yanmin else if (self->kernel == DSO_TYPE_GUEST_KERNEL) 1426a1645ce1SZhang, Yanmin return dso__load_guest_kernel_sym(self, map, filter); 1427a1645ce1SZhang, Yanmin 142823346f21SArnaldo Carvalho de Melo if (map->groups && map->groups->machine) 142923346f21SArnaldo Carvalho de Melo machine = map->groups->machine; 1430a1645ce1SZhang, Yanmin else 143123346f21SArnaldo Carvalho de Melo machine = NULL; 1432c338aee8SArnaldo Carvalho de Melo 1433c338aee8SArnaldo Carvalho de Melo name = malloc(size); 143486470930SIngo Molnar if (!name) 143586470930SIngo Molnar return -1; 143686470930SIngo Molnar 143730d7a77dSArnaldo Carvalho de Melo self->adjust_symbols = 0; 1438f5812a7aSArnaldo Carvalho de Melo 143994cb9e38SArnaldo Carvalho de Melo if (strncmp(self->name, "/tmp/perf-", 10) == 0) { 14406beba7adSArnaldo Carvalho de Melo ret = dso__load_perf_map(self, map, filter); 144194cb9e38SArnaldo Carvalho de Melo self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT : 144294cb9e38SArnaldo Carvalho de Melo DSO__ORIG_NOT_FOUND; 144394cb9e38SArnaldo Carvalho de Melo return ret; 144494cb9e38SArnaldo Carvalho de Melo } 144594cb9e38SArnaldo Carvalho de Melo 14466da80ce8SDave Martin /* Iterate over candidate debug images. 14476da80ce8SDave Martin * On the first pass, only load images if they have a full symtab. 14486da80ce8SDave Martin * Failing that, do a second pass where we accept .dynsym also 14496da80ce8SDave Martin */ 14506da80ce8SDave Martin for (self->origin = DSO__ORIG_BUILD_ID_CACHE, want_symtab = 1; 14516da80ce8SDave Martin self->origin != DSO__ORIG_NOT_FOUND; 14526da80ce8SDave Martin self->origin++) { 145394cb9e38SArnaldo Carvalho de Melo switch (self->origin) { 14546da80ce8SDave Martin case DSO__ORIG_BUILD_ID_CACHE: 14556da80ce8SDave Martin if (dso__build_id_filename(self, name, size) == NULL) 14566da80ce8SDave Martin continue; 14576da80ce8SDave Martin break; 145894cb9e38SArnaldo Carvalho de Melo case DSO__ORIG_FEDORA: 1459439d473bSArnaldo Carvalho de Melo snprintf(name, size, "/usr/lib/debug%s.debug", 1460439d473bSArnaldo Carvalho de Melo self->long_name); 146186470930SIngo Molnar break; 146294cb9e38SArnaldo Carvalho de Melo case DSO__ORIG_UBUNTU: 1463439d473bSArnaldo Carvalho de Melo snprintf(name, size, "/usr/lib/debug%s", 1464439d473bSArnaldo Carvalho de Melo self->long_name); 146586470930SIngo Molnar break; 14666da80ce8SDave Martin case DSO__ORIG_BUILDID: { 1467b36f19d5SArnaldo Carvalho de Melo char build_id_hex[BUILD_ID_SIZE * 2 + 1]; 14686da80ce8SDave Martin 14696da80ce8SDave Martin if (!self->has_build_id) 14706da80ce8SDave Martin continue; 14716da80ce8SDave Martin 147221916c38SDave Martin build_id__sprintf(self->build_id, 147321916c38SDave Martin sizeof(self->build_id), 1474d3379ab9SArnaldo Carvalho de Melo build_id_hex); 14754d1e00a8SArnaldo Carvalho de Melo snprintf(name, size, 14764d1e00a8SArnaldo Carvalho de Melo "/usr/lib/debug/.build-id/%.2s/%s.debug", 1477d3379ab9SArnaldo Carvalho de Melo build_id_hex, build_id_hex + 2); 14784d1e00a8SArnaldo Carvalho de Melo } 14796da80ce8SDave Martin break; 148094cb9e38SArnaldo Carvalho de Melo case DSO__ORIG_DSO: 1481439d473bSArnaldo Carvalho de Melo snprintf(name, size, "%s", self->long_name); 148286470930SIngo Molnar break; 1483a1645ce1SZhang, Yanmin case DSO__ORIG_GUEST_KMODULE: 148423346f21SArnaldo Carvalho de Melo if (map->groups && map->groups->machine) 148523346f21SArnaldo Carvalho de Melo root_dir = map->groups->machine->root_dir; 1486a1645ce1SZhang, Yanmin else 1487a1645ce1SZhang, Yanmin root_dir = ""; 1488a1645ce1SZhang, Yanmin snprintf(name, size, "%s%s", root_dir, self->long_name); 1489a1645ce1SZhang, Yanmin break; 149086470930SIngo Molnar 149186470930SIngo Molnar default: 14926da80ce8SDave Martin /* 14936da80ce8SDave Martin * If we wanted a full symtab but no image had one, 14946da80ce8SDave Martin * relax our requirements and repeat the search. 14956da80ce8SDave Martin */ 14966da80ce8SDave Martin if (want_symtab) { 14976da80ce8SDave Martin want_symtab = 0; 14986da80ce8SDave Martin self->origin = DSO__ORIG_BUILD_ID_CACHE; 14996da80ce8SDave Martin } else 15006da80ce8SDave Martin continue; 150186470930SIngo Molnar } 150286470930SIngo Molnar 15036da80ce8SDave Martin /* Name is now the name of the next image to try */ 15046da80ce8SDave Martin fd = open(name, O_RDONLY); 15056da80ce8SDave Martin if (fd < 0) 15066da80ce8SDave Martin continue; 15076da80ce8SDave Martin 15086da80ce8SDave Martin ret = dso__load_sym(self, map, name, fd, filter, 0, 15096da80ce8SDave Martin want_symtab); 151086470930SIngo Molnar close(fd); 151186470930SIngo Molnar 151286470930SIngo Molnar /* 15136da80ce8SDave Martin * Some people seem to have debuginfo files _WITHOUT_ debug 15146da80ce8SDave Martin * info!?!? 151586470930SIngo Molnar */ 151686470930SIngo Molnar if (!ret) 15176da80ce8SDave Martin continue; 151886470930SIngo Molnar 1519a25e46c4SArnaldo Carvalho de Melo if (ret > 0) { 152082164161SArnaldo Carvalho de Melo int nr_plt = dso__synthesize_plt_symbols(self, map, filter); 1521a25e46c4SArnaldo Carvalho de Melo if (nr_plt > 0) 1522a25e46c4SArnaldo Carvalho de Melo ret += nr_plt; 15236da80ce8SDave Martin break; 1524a25e46c4SArnaldo Carvalho de Melo } 15256da80ce8SDave Martin } 15266da80ce8SDave Martin 152786470930SIngo Molnar free(name); 15281340e6bbSArnaldo Carvalho de Melo if (ret < 0 && strstr(self->name, " (deleted)") != NULL) 15291340e6bbSArnaldo Carvalho de Melo return 0; 153086470930SIngo Molnar return ret; 153186470930SIngo Molnar } 153286470930SIngo Molnar 153379406cd7SArnaldo Carvalho de Melo struct map *map_groups__find_by_name(struct map_groups *self, 153479406cd7SArnaldo Carvalho de Melo enum map_type type, const char *name) 1535439d473bSArnaldo Carvalho de Melo { 1536439d473bSArnaldo Carvalho de Melo struct rb_node *nd; 1537439d473bSArnaldo Carvalho de Melo 153879406cd7SArnaldo Carvalho de Melo for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) { 1539439d473bSArnaldo Carvalho de Melo struct map *map = rb_entry(nd, struct map, rb_node); 1540439d473bSArnaldo Carvalho de Melo 1541b7cece76SArnaldo Carvalho de Melo if (map->dso && strcmp(map->dso->short_name, name) == 0) 1542439d473bSArnaldo Carvalho de Melo return map; 1543439d473bSArnaldo Carvalho de Melo } 1544439d473bSArnaldo Carvalho de Melo 1545439d473bSArnaldo Carvalho de Melo return NULL; 1546439d473bSArnaldo Carvalho de Melo } 1547439d473bSArnaldo Carvalho de Melo 1548a1645ce1SZhang, Yanmin static int dso__kernel_module_get_build_id(struct dso *self, 1549a1645ce1SZhang, Yanmin const char *root_dir) 1550b7cece76SArnaldo Carvalho de Melo { 1551b7cece76SArnaldo Carvalho de Melo char filename[PATH_MAX]; 1552b7cece76SArnaldo Carvalho de Melo /* 1553b7cece76SArnaldo Carvalho de Melo * kernel module short names are of the form "[module]" and 1554b7cece76SArnaldo Carvalho de Melo * we need just "module" here. 1555b7cece76SArnaldo Carvalho de Melo */ 1556b7cece76SArnaldo Carvalho de Melo const char *name = self->short_name + 1; 1557b7cece76SArnaldo Carvalho de Melo 1558b7cece76SArnaldo Carvalho de Melo snprintf(filename, sizeof(filename), 1559a1645ce1SZhang, Yanmin "%s/sys/module/%.*s/notes/.note.gnu.build-id", 1560a1645ce1SZhang, Yanmin root_dir, (int)strlen(name) - 1, name); 1561b7cece76SArnaldo Carvalho de Melo 1562b7cece76SArnaldo Carvalho de Melo if (sysfs__read_build_id(filename, self->build_id, 1563b7cece76SArnaldo Carvalho de Melo sizeof(self->build_id)) == 0) 1564b7cece76SArnaldo Carvalho de Melo self->has_build_id = true; 1565b7cece76SArnaldo Carvalho de Melo 1566b7cece76SArnaldo Carvalho de Melo return 0; 1567b7cece76SArnaldo Carvalho de Melo } 1568b7cece76SArnaldo Carvalho de Melo 1569a1645ce1SZhang, Yanmin static int map_groups__set_modules_path_dir(struct map_groups *self, 1570a1645ce1SZhang, Yanmin const char *dir_name) 15716cfcc53eSMike Galbraith { 1572439d473bSArnaldo Carvalho de Melo struct dirent *dent; 15735aab621bSArnaldo Carvalho de Melo DIR *dir = opendir(dir_name); 157474534341SGui Jianfeng int ret = 0; 15756cfcc53eSMike Galbraith 1576439d473bSArnaldo Carvalho de Melo if (!dir) { 15775aab621bSArnaldo Carvalho de Melo pr_debug("%s: cannot open %s dir\n", __func__, dir_name); 1578439d473bSArnaldo Carvalho de Melo return -1; 1579439d473bSArnaldo Carvalho de Melo } 15806cfcc53eSMike Galbraith 1581439d473bSArnaldo Carvalho de Melo while ((dent = readdir(dir)) != NULL) { 1582439d473bSArnaldo Carvalho de Melo char path[PATH_MAX]; 1583a1645ce1SZhang, Yanmin struct stat st; 1584439d473bSArnaldo Carvalho de Melo 1585a1645ce1SZhang, Yanmin /*sshfs might return bad dent->d_type, so we have to stat*/ 1586a1645ce1SZhang, Yanmin sprintf(path, "%s/%s", dir_name, dent->d_name); 1587a1645ce1SZhang, Yanmin if (stat(path, &st)) 1588a1645ce1SZhang, Yanmin continue; 1589a1645ce1SZhang, Yanmin 1590a1645ce1SZhang, Yanmin if (S_ISDIR(st.st_mode)) { 1591439d473bSArnaldo Carvalho de Melo if (!strcmp(dent->d_name, ".") || 1592439d473bSArnaldo Carvalho de Melo !strcmp(dent->d_name, "..")) 1593439d473bSArnaldo Carvalho de Melo continue; 1594439d473bSArnaldo Carvalho de Melo 1595439d473bSArnaldo Carvalho de Melo snprintf(path, sizeof(path), "%s/%s", 15965aab621bSArnaldo Carvalho de Melo dir_name, dent->d_name); 159774534341SGui Jianfeng ret = map_groups__set_modules_path_dir(self, path); 159874534341SGui Jianfeng if (ret < 0) 159974534341SGui Jianfeng goto out; 1600439d473bSArnaldo Carvalho de Melo } else { 1601439d473bSArnaldo Carvalho de Melo char *dot = strrchr(dent->d_name, '.'), 1602439d473bSArnaldo Carvalho de Melo dso_name[PATH_MAX]; 1603439d473bSArnaldo Carvalho de Melo struct map *map; 1604cfc10d3bSArnaldo Carvalho de Melo char *long_name; 1605439d473bSArnaldo Carvalho de Melo 1606439d473bSArnaldo Carvalho de Melo if (dot == NULL || strcmp(dot, ".ko")) 1607439d473bSArnaldo Carvalho de Melo continue; 1608439d473bSArnaldo Carvalho de Melo snprintf(dso_name, sizeof(dso_name), "[%.*s]", 1609439d473bSArnaldo Carvalho de Melo (int)(dot - dent->d_name), dent->d_name); 1610439d473bSArnaldo Carvalho de Melo 1611a2a99e8eSArnaldo Carvalho de Melo strxfrchar(dso_name, '-', '_'); 16129de89fe7SArnaldo Carvalho de Melo map = map_groups__find_by_name(self, MAP__FUNCTION, dso_name); 1613439d473bSArnaldo Carvalho de Melo if (map == NULL) 1614439d473bSArnaldo Carvalho de Melo continue; 1615439d473bSArnaldo Carvalho de Melo 1616439d473bSArnaldo Carvalho de Melo snprintf(path, sizeof(path), "%s/%s", 16175aab621bSArnaldo Carvalho de Melo dir_name, dent->d_name); 1618439d473bSArnaldo Carvalho de Melo 1619cfc10d3bSArnaldo Carvalho de Melo long_name = strdup(path); 162074534341SGui Jianfeng if (long_name == NULL) { 162174534341SGui Jianfeng ret = -1; 162274534341SGui Jianfeng goto out; 162374534341SGui Jianfeng } 1624cfc10d3bSArnaldo Carvalho de Melo dso__set_long_name(map->dso, long_name); 16256e406257SArnaldo Carvalho de Melo map->dso->lname_alloc = 1; 1626a1645ce1SZhang, Yanmin dso__kernel_module_get_build_id(map->dso, ""); 1627439d473bSArnaldo Carvalho de Melo } 1628439d473bSArnaldo Carvalho de Melo } 1629439d473bSArnaldo Carvalho de Melo 163074534341SGui Jianfeng out: 1631439d473bSArnaldo Carvalho de Melo closedir(dir); 163274534341SGui Jianfeng return ret; 1633439d473bSArnaldo Carvalho de Melo } 1634439d473bSArnaldo Carvalho de Melo 1635a1645ce1SZhang, Yanmin static char *get_kernel_version(const char *root_dir) 1636439d473bSArnaldo Carvalho de Melo { 1637a1645ce1SZhang, Yanmin char version[PATH_MAX]; 1638a1645ce1SZhang, Yanmin FILE *file; 1639a1645ce1SZhang, Yanmin char *name, *tmp; 1640a1645ce1SZhang, Yanmin const char *prefix = "Linux version "; 1641a1645ce1SZhang, Yanmin 1642a1645ce1SZhang, Yanmin sprintf(version, "%s/proc/version", root_dir); 1643a1645ce1SZhang, Yanmin file = fopen(version, "r"); 1644a1645ce1SZhang, Yanmin if (!file) 1645a1645ce1SZhang, Yanmin return NULL; 1646a1645ce1SZhang, Yanmin 1647a1645ce1SZhang, Yanmin version[0] = '\0'; 1648a1645ce1SZhang, Yanmin tmp = fgets(version, sizeof(version), file); 1649a1645ce1SZhang, Yanmin fclose(file); 1650a1645ce1SZhang, Yanmin 1651a1645ce1SZhang, Yanmin name = strstr(version, prefix); 1652a1645ce1SZhang, Yanmin if (!name) 1653a1645ce1SZhang, Yanmin return NULL; 1654a1645ce1SZhang, Yanmin name += strlen(prefix); 1655a1645ce1SZhang, Yanmin tmp = strchr(name, ' '); 1656a1645ce1SZhang, Yanmin if (tmp) 1657a1645ce1SZhang, Yanmin *tmp = '\0'; 1658a1645ce1SZhang, Yanmin 1659a1645ce1SZhang, Yanmin return strdup(name); 1660a1645ce1SZhang, Yanmin } 1661a1645ce1SZhang, Yanmin 1662d28c6223SArnaldo Carvalho de Melo static int machine__set_modules_path(struct machine *self) 1663a1645ce1SZhang, Yanmin { 1664a1645ce1SZhang, Yanmin char *version; 1665439d473bSArnaldo Carvalho de Melo char modules_path[PATH_MAX]; 1666439d473bSArnaldo Carvalho de Melo 1667d28c6223SArnaldo Carvalho de Melo version = get_kernel_version(self->root_dir); 1668a1645ce1SZhang, Yanmin if (!version) 1669439d473bSArnaldo Carvalho de Melo return -1; 1670439d473bSArnaldo Carvalho de Melo 1671a1645ce1SZhang, Yanmin snprintf(modules_path, sizeof(modules_path), "%s/lib/modules/%s/kernel", 1672d28c6223SArnaldo Carvalho de Melo self->root_dir, version); 1673a1645ce1SZhang, Yanmin free(version); 1674439d473bSArnaldo Carvalho de Melo 1675d28c6223SArnaldo Carvalho de Melo return map_groups__set_modules_path_dir(&self->kmaps, modules_path); 1676439d473bSArnaldo Carvalho de Melo } 16776cfcc53eSMike Galbraith 16786cfcc53eSMike Galbraith /* 1679439d473bSArnaldo Carvalho de Melo * Constructor variant for modules (where we know from /proc/modules where 1680439d473bSArnaldo Carvalho de Melo * they are loaded) and for vmlinux, where only after we load all the 1681439d473bSArnaldo Carvalho de Melo * symbols we'll know where it starts and ends. 16826cfcc53eSMike Galbraith */ 16833610583cSArnaldo Carvalho de Melo static struct map *map__new2(u64 start, struct dso *dso, enum map_type type) 1684439d473bSArnaldo Carvalho de Melo { 16855aab621bSArnaldo Carvalho de Melo struct map *self = calloc(1, (sizeof(*self) + 16865aab621bSArnaldo Carvalho de Melo (dso->kernel ? sizeof(struct kmap) : 0))); 1687439d473bSArnaldo Carvalho de Melo if (self != NULL) { 1688439d473bSArnaldo Carvalho de Melo /* 1689afb7b4f0SArnaldo Carvalho de Melo * ->end will be filled after we load all the symbols 1690439d473bSArnaldo Carvalho de Melo */ 16913610583cSArnaldo Carvalho de Melo map__init(self, type, start, 0, 0, dso); 1692439d473bSArnaldo Carvalho de Melo } 1693afb7b4f0SArnaldo Carvalho de Melo 1694439d473bSArnaldo Carvalho de Melo return self; 1695439d473bSArnaldo Carvalho de Melo } 1696439d473bSArnaldo Carvalho de Melo 1697d28c6223SArnaldo Carvalho de Melo struct map *machine__new_module(struct machine *self, u64 start, 1698d28c6223SArnaldo Carvalho de Melo const char *filename) 1699b7cece76SArnaldo Carvalho de Melo { 1700b7cece76SArnaldo Carvalho de Melo struct map *map; 1701d28c6223SArnaldo Carvalho de Melo struct dso *dso = __dsos__findnew(&self->kernel_dsos, filename); 1702b7cece76SArnaldo Carvalho de Melo 1703b7cece76SArnaldo Carvalho de Melo if (dso == NULL) 1704b7cece76SArnaldo Carvalho de Melo return NULL; 1705b7cece76SArnaldo Carvalho de Melo 1706b7cece76SArnaldo Carvalho de Melo map = map__new2(start, dso, MAP__FUNCTION); 1707b7cece76SArnaldo Carvalho de Melo if (map == NULL) 1708b7cece76SArnaldo Carvalho de Melo return NULL; 1709b7cece76SArnaldo Carvalho de Melo 1710d28c6223SArnaldo Carvalho de Melo if (machine__is_host(self)) 1711b7cece76SArnaldo Carvalho de Melo dso->origin = DSO__ORIG_KMODULE; 1712a1645ce1SZhang, Yanmin else 1713a1645ce1SZhang, Yanmin dso->origin = DSO__ORIG_GUEST_KMODULE; 1714d28c6223SArnaldo Carvalho de Melo map_groups__insert(&self->kmaps, map); 1715b7cece76SArnaldo Carvalho de Melo return map; 1716b7cece76SArnaldo Carvalho de Melo } 1717b7cece76SArnaldo Carvalho de Melo 1718d28c6223SArnaldo Carvalho de Melo static int machine__create_modules(struct machine *self) 1719439d473bSArnaldo Carvalho de Melo { 1720439d473bSArnaldo Carvalho de Melo char *line = NULL; 1721439d473bSArnaldo Carvalho de Melo size_t n; 1722a1645ce1SZhang, Yanmin FILE *file; 1723439d473bSArnaldo Carvalho de Melo struct map *map; 1724a1645ce1SZhang, Yanmin const char *modules; 1725a1645ce1SZhang, Yanmin char path[PATH_MAX]; 1726439d473bSArnaldo Carvalho de Melo 1727d28c6223SArnaldo Carvalho de Melo if (machine__is_default_guest(self)) 1728a1645ce1SZhang, Yanmin modules = symbol_conf.default_guest_modules; 1729a1645ce1SZhang, Yanmin else { 1730d28c6223SArnaldo Carvalho de Melo sprintf(path, "%s/proc/modules", self->root_dir); 1731a1645ce1SZhang, Yanmin modules = path; 1732a1645ce1SZhang, Yanmin } 1733a1645ce1SZhang, Yanmin 1734a1645ce1SZhang, Yanmin file = fopen(modules, "r"); 1735439d473bSArnaldo Carvalho de Melo if (file == NULL) 1736439d473bSArnaldo Carvalho de Melo return -1; 1737439d473bSArnaldo Carvalho de Melo 1738439d473bSArnaldo Carvalho de Melo while (!feof(file)) { 1739439d473bSArnaldo Carvalho de Melo char name[PATH_MAX]; 1740439d473bSArnaldo Carvalho de Melo u64 start; 1741439d473bSArnaldo Carvalho de Melo char *sep; 1742439d473bSArnaldo Carvalho de Melo int line_len; 1743439d473bSArnaldo Carvalho de Melo 1744439d473bSArnaldo Carvalho de Melo line_len = getline(&line, &n, file); 1745439d473bSArnaldo Carvalho de Melo if (line_len < 0) 17466cfcc53eSMike Galbraith break; 17476cfcc53eSMike Galbraith 1748439d473bSArnaldo Carvalho de Melo if (!line) 1749439d473bSArnaldo Carvalho de Melo goto out_failure; 1750439d473bSArnaldo Carvalho de Melo 1751439d473bSArnaldo Carvalho de Melo line[--line_len] = '\0'; /* \n */ 1752439d473bSArnaldo Carvalho de Melo 1753439d473bSArnaldo Carvalho de Melo sep = strrchr(line, 'x'); 1754439d473bSArnaldo Carvalho de Melo if (sep == NULL) 1755439d473bSArnaldo Carvalho de Melo continue; 1756439d473bSArnaldo Carvalho de Melo 1757439d473bSArnaldo Carvalho de Melo hex2u64(sep + 1, &start); 1758439d473bSArnaldo Carvalho de Melo 1759439d473bSArnaldo Carvalho de Melo sep = strchr(line, ' '); 1760439d473bSArnaldo Carvalho de Melo if (sep == NULL) 1761439d473bSArnaldo Carvalho de Melo continue; 1762439d473bSArnaldo Carvalho de Melo 1763439d473bSArnaldo Carvalho de Melo *sep = '\0'; 1764439d473bSArnaldo Carvalho de Melo 1765439d473bSArnaldo Carvalho de Melo snprintf(name, sizeof(name), "[%s]", line); 1766d28c6223SArnaldo Carvalho de Melo map = machine__new_module(self, start, name); 1767b7cece76SArnaldo Carvalho de Melo if (map == NULL) 1768439d473bSArnaldo Carvalho de Melo goto out_delete_line; 1769d28c6223SArnaldo Carvalho de Melo dso__kernel_module_get_build_id(map->dso, self->root_dir); 17706cfcc53eSMike Galbraith } 17716cfcc53eSMike Galbraith 1772439d473bSArnaldo Carvalho de Melo free(line); 1773439d473bSArnaldo Carvalho de Melo fclose(file); 1774439d473bSArnaldo Carvalho de Melo 1775d28c6223SArnaldo Carvalho de Melo return machine__set_modules_path(self); 1776439d473bSArnaldo Carvalho de Melo 1777439d473bSArnaldo Carvalho de Melo out_delete_line: 1778439d473bSArnaldo Carvalho de Melo free(line); 1779439d473bSArnaldo Carvalho de Melo out_failure: 1780439d473bSArnaldo Carvalho de Melo return -1; 17816cfcc53eSMike Galbraith } 17826cfcc53eSMike Galbraith 1783*fd930ff9SFranck Bui-Huu int dso__load_vmlinux(struct dso *self, struct map *map, 17846beba7adSArnaldo Carvalho de Melo const char *vmlinux, symbol_filter_t filter) 178586470930SIngo Molnar { 1786fbd733b8SArnaldo Carvalho de Melo int err = -1, fd; 178786470930SIngo Molnar 1788fbd733b8SArnaldo Carvalho de Melo fd = open(vmlinux, O_RDONLY); 178986470930SIngo Molnar if (fd < 0) 179086470930SIngo Molnar return -1; 179186470930SIngo Molnar 17923610583cSArnaldo Carvalho de Melo dso__set_loaded(self, map->type); 17936da80ce8SDave Martin err = dso__load_sym(self, map, vmlinux, fd, filter, 0, 0); 179486470930SIngo Molnar close(fd); 179586470930SIngo Molnar 17963846df2eSArnaldo Carvalho de Melo if (err > 0) 17973846df2eSArnaldo Carvalho de Melo pr_debug("Using %s for symbols\n", vmlinux); 17983846df2eSArnaldo Carvalho de Melo 179986470930SIngo Molnar return err; 180086470930SIngo Molnar } 180186470930SIngo Molnar 1802a19afe46SArnaldo Carvalho de Melo int dso__load_vmlinux_path(struct dso *self, struct map *map, 18039de89fe7SArnaldo Carvalho de Melo symbol_filter_t filter) 1804a19afe46SArnaldo Carvalho de Melo { 1805a19afe46SArnaldo Carvalho de Melo int i, err = 0; 18065ad90e4eSArnaldo Carvalho de Melo char *filename; 1807a19afe46SArnaldo Carvalho de Melo 1808a19afe46SArnaldo Carvalho de Melo pr_debug("Looking at the vmlinux_path (%d entries long)\n", 18095ad90e4eSArnaldo Carvalho de Melo vmlinux_path__nr_entries + 1); 18105ad90e4eSArnaldo Carvalho de Melo 18115ad90e4eSArnaldo Carvalho de Melo filename = dso__build_id_filename(self, NULL, 0); 18125ad90e4eSArnaldo Carvalho de Melo if (filename != NULL) { 18135ad90e4eSArnaldo Carvalho de Melo err = dso__load_vmlinux(self, map, filename, filter); 18145ad90e4eSArnaldo Carvalho de Melo if (err > 0) { 18155ad90e4eSArnaldo Carvalho de Melo dso__set_long_name(self, filename); 18165ad90e4eSArnaldo Carvalho de Melo goto out; 18175ad90e4eSArnaldo Carvalho de Melo } 18185ad90e4eSArnaldo Carvalho de Melo free(filename); 18195ad90e4eSArnaldo Carvalho de Melo } 1820a19afe46SArnaldo Carvalho de Melo 1821a19afe46SArnaldo Carvalho de Melo for (i = 0; i < vmlinux_path__nr_entries; ++i) { 18229de89fe7SArnaldo Carvalho de Melo err = dso__load_vmlinux(self, map, vmlinux_path[i], filter); 1823a19afe46SArnaldo Carvalho de Melo if (err > 0) { 1824a19afe46SArnaldo Carvalho de Melo dso__set_long_name(self, strdup(vmlinux_path[i])); 1825a19afe46SArnaldo Carvalho de Melo break; 1826a19afe46SArnaldo Carvalho de Melo } 1827a19afe46SArnaldo Carvalho de Melo } 18285ad90e4eSArnaldo Carvalho de Melo out: 1829a19afe46SArnaldo Carvalho de Melo return err; 1830a19afe46SArnaldo Carvalho de Melo } 1831a19afe46SArnaldo Carvalho de Melo 1832c338aee8SArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *self, struct map *map, 18339de89fe7SArnaldo Carvalho de Melo symbol_filter_t filter) 183486470930SIngo Molnar { 1835cc612d81SArnaldo Carvalho de Melo int err; 18369e201442SArnaldo Carvalho de Melo const char *kallsyms_filename = NULL; 18379e201442SArnaldo Carvalho de Melo char *kallsyms_allocated_filename = NULL; 1838dc8d6ab2SArnaldo Carvalho de Melo /* 1839dc8d6ab2SArnaldo Carvalho de Melo * Step 1: if the user specified a vmlinux filename, use it and only 1840dc8d6ab2SArnaldo Carvalho de Melo * it, reporting errors to the user if it cannot be used. 1841dc8d6ab2SArnaldo Carvalho de Melo * 1842dc8d6ab2SArnaldo Carvalho de Melo * For instance, try to analyse an ARM perf.data file _without_ a 1843dc8d6ab2SArnaldo Carvalho de Melo * build-id, or if the user specifies the wrong path to the right 1844dc8d6ab2SArnaldo Carvalho de Melo * vmlinux file, obviously we can't fallback to another vmlinux (a 1845dc8d6ab2SArnaldo Carvalho de Melo * x86_86 one, on the machine where analysis is being performed, say), 1846dc8d6ab2SArnaldo Carvalho de Melo * or worse, /proc/kallsyms. 1847dc8d6ab2SArnaldo Carvalho de Melo * 1848dc8d6ab2SArnaldo Carvalho de Melo * If the specified file _has_ a build-id and there is a build-id 1849dc8d6ab2SArnaldo Carvalho de Melo * section in the perf.data file, we will still do the expected 1850dc8d6ab2SArnaldo Carvalho de Melo * validation in dso__load_vmlinux and will bail out if they don't 1851dc8d6ab2SArnaldo Carvalho de Melo * match. 1852dc8d6ab2SArnaldo Carvalho de Melo */ 1853dc8d6ab2SArnaldo Carvalho de Melo if (symbol_conf.vmlinux_name != NULL) { 18549de89fe7SArnaldo Carvalho de Melo err = dso__load_vmlinux(self, map, 1855dc8d6ab2SArnaldo Carvalho de Melo symbol_conf.vmlinux_name, filter); 1856e7dadc00SArnaldo Carvalho de Melo if (err > 0) { 1857e7dadc00SArnaldo Carvalho de Melo dso__set_long_name(self, 1858e7dadc00SArnaldo Carvalho de Melo strdup(symbol_conf.vmlinux_name)); 1859e7dadc00SArnaldo Carvalho de Melo goto out_fixup; 1860e7dadc00SArnaldo Carvalho de Melo } 1861e7dadc00SArnaldo Carvalho de Melo return err; 1862dc8d6ab2SArnaldo Carvalho de Melo } 1863439d473bSArnaldo Carvalho de Melo 1864cc612d81SArnaldo Carvalho de Melo if (vmlinux_path != NULL) { 18659de89fe7SArnaldo Carvalho de Melo err = dso__load_vmlinux_path(self, map, filter); 1866a19afe46SArnaldo Carvalho de Melo if (err > 0) 1867cc612d81SArnaldo Carvalho de Melo goto out_fixup; 1868cc612d81SArnaldo Carvalho de Melo } 1869cc612d81SArnaldo Carvalho de Melo 1870b7cece76SArnaldo Carvalho de Melo /* 1871b7cece76SArnaldo Carvalho de Melo * Say the kernel DSO was created when processing the build-id header table, 1872b7cece76SArnaldo Carvalho de Melo * we have a build-id, so check if it is the same as the running kernel, 1873b7cece76SArnaldo Carvalho de Melo * using it if it is. 1874b7cece76SArnaldo Carvalho de Melo */ 1875b7cece76SArnaldo Carvalho de Melo if (self->has_build_id) { 1876b7cece76SArnaldo Carvalho de Melo u8 kallsyms_build_id[BUILD_ID_SIZE]; 18779e201442SArnaldo Carvalho de Melo char sbuild_id[BUILD_ID_SIZE * 2 + 1]; 1878b7cece76SArnaldo Carvalho de Melo 1879b7cece76SArnaldo Carvalho de Melo if (sysfs__read_build_id("/sys/kernel/notes", kallsyms_build_id, 18808d0591f6SArnaldo Carvalho de Melo sizeof(kallsyms_build_id)) == 0) { 18819e201442SArnaldo Carvalho de Melo if (dso__build_id_equal(self, kallsyms_build_id)) { 18829e201442SArnaldo Carvalho de Melo kallsyms_filename = "/proc/kallsyms"; 1883b7cece76SArnaldo Carvalho de Melo goto do_kallsyms; 18848d0591f6SArnaldo Carvalho de Melo } 18859e201442SArnaldo Carvalho de Melo } 1886dc8d6ab2SArnaldo Carvalho de Melo /* 1887dc8d6ab2SArnaldo Carvalho de Melo * Now look if we have it on the build-id cache in 1888dc8d6ab2SArnaldo Carvalho de Melo * $HOME/.debug/[kernel.kallsyms]. 1889dc8d6ab2SArnaldo Carvalho de Melo */ 18909e201442SArnaldo Carvalho de Melo build_id__sprintf(self->build_id, sizeof(self->build_id), 18919e201442SArnaldo Carvalho de Melo sbuild_id); 18929e201442SArnaldo Carvalho de Melo 18939e201442SArnaldo Carvalho de Melo if (asprintf(&kallsyms_allocated_filename, 18949e201442SArnaldo Carvalho de Melo "%s/.debug/[kernel.kallsyms]/%s", 18953846df2eSArnaldo Carvalho de Melo getenv("HOME"), sbuild_id) == -1) { 18963846df2eSArnaldo Carvalho de Melo pr_err("Not enough memory for kallsyms file lookup\n"); 18978d0591f6SArnaldo Carvalho de Melo return -1; 18983846df2eSArnaldo Carvalho de Melo } 18998d0591f6SArnaldo Carvalho de Melo 190019fc2dedSArnaldo Carvalho de Melo kallsyms_filename = kallsyms_allocated_filename; 190119fc2dedSArnaldo Carvalho de Melo 1902dc8d6ab2SArnaldo Carvalho de Melo if (access(kallsyms_filename, F_OK)) { 19033846df2eSArnaldo Carvalho de Melo pr_err("No kallsyms or vmlinux with build-id %s " 19043846df2eSArnaldo Carvalho de Melo "was found\n", sbuild_id); 19059e201442SArnaldo Carvalho de Melo free(kallsyms_allocated_filename); 1906dc8d6ab2SArnaldo Carvalho de Melo return -1; 1907ef6ae724SArnaldo Carvalho de Melo } 1908dc8d6ab2SArnaldo Carvalho de Melo } else { 1909dc8d6ab2SArnaldo Carvalho de Melo /* 1910dc8d6ab2SArnaldo Carvalho de Melo * Last resort, if we don't have a build-id and couldn't find 1911dc8d6ab2SArnaldo Carvalho de Melo * any vmlinux file, try the running kernel kallsyms table. 1912dc8d6ab2SArnaldo Carvalho de Melo */ 1913dc8d6ab2SArnaldo Carvalho de Melo kallsyms_filename = "/proc/kallsyms"; 1914dc8d6ab2SArnaldo Carvalho de Melo } 1915dc8d6ab2SArnaldo Carvalho de Melo 1916dc8d6ab2SArnaldo Carvalho de Melo do_kallsyms: 19179de89fe7SArnaldo Carvalho de Melo err = dso__load_kallsyms(self, kallsyms_filename, map, filter); 19183846df2eSArnaldo Carvalho de Melo if (err > 0) 19193846df2eSArnaldo Carvalho de Melo pr_debug("Using %s for symbols\n", kallsyms_filename); 1920dc8d6ab2SArnaldo Carvalho de Melo free(kallsyms_allocated_filename); 1921dc8d6ab2SArnaldo Carvalho de Melo 1922439d473bSArnaldo Carvalho de Melo if (err > 0) { 1923cc612d81SArnaldo Carvalho de Melo out_fixup: 1924e1c7c6a4SArnaldo Carvalho de Melo if (kallsyms_filename != NULL) 1925dc8d6ab2SArnaldo Carvalho de Melo dso__set_long_name(self, strdup("[kernel.kallsyms]")); 19266a4694a4SArnaldo Carvalho de Melo map__fixup_start(map); 19276a4694a4SArnaldo Carvalho de Melo map__fixup_end(map); 1928439d473bSArnaldo Carvalho de Melo } 192994cb9e38SArnaldo Carvalho de Melo 193086470930SIngo Molnar return err; 193186470930SIngo Molnar } 193286470930SIngo Molnar 1933a1645ce1SZhang, Yanmin static int dso__load_guest_kernel_sym(struct dso *self, struct map *map, 1934a1645ce1SZhang, Yanmin symbol_filter_t filter) 1935a1645ce1SZhang, Yanmin { 1936a1645ce1SZhang, Yanmin int err; 1937a1645ce1SZhang, Yanmin const char *kallsyms_filename = NULL; 193823346f21SArnaldo Carvalho de Melo struct machine *machine; 1939a1645ce1SZhang, Yanmin char path[PATH_MAX]; 1940a1645ce1SZhang, Yanmin 1941a1645ce1SZhang, Yanmin if (!map->groups) { 1942a1645ce1SZhang, Yanmin pr_debug("Guest kernel map hasn't the point to groups\n"); 1943a1645ce1SZhang, Yanmin return -1; 1944a1645ce1SZhang, Yanmin } 194523346f21SArnaldo Carvalho de Melo machine = map->groups->machine; 1946a1645ce1SZhang, Yanmin 194723346f21SArnaldo Carvalho de Melo if (machine__is_default_guest(machine)) { 1948a1645ce1SZhang, Yanmin /* 1949a1645ce1SZhang, Yanmin * if the user specified a vmlinux filename, use it and only 1950a1645ce1SZhang, Yanmin * it, reporting errors to the user if it cannot be used. 1951a1645ce1SZhang, Yanmin * Or use file guest_kallsyms inputted by user on commandline 1952a1645ce1SZhang, Yanmin */ 1953a1645ce1SZhang, Yanmin if (symbol_conf.default_guest_vmlinux_name != NULL) { 1954a1645ce1SZhang, Yanmin err = dso__load_vmlinux(self, map, 1955a1645ce1SZhang, Yanmin symbol_conf.default_guest_vmlinux_name, filter); 1956a1645ce1SZhang, Yanmin goto out_try_fixup; 1957a1645ce1SZhang, Yanmin } 1958a1645ce1SZhang, Yanmin 1959a1645ce1SZhang, Yanmin kallsyms_filename = symbol_conf.default_guest_kallsyms; 1960a1645ce1SZhang, Yanmin if (!kallsyms_filename) 1961a1645ce1SZhang, Yanmin return -1; 1962a1645ce1SZhang, Yanmin } else { 196323346f21SArnaldo Carvalho de Melo sprintf(path, "%s/proc/kallsyms", machine->root_dir); 1964a1645ce1SZhang, Yanmin kallsyms_filename = path; 1965a1645ce1SZhang, Yanmin } 1966a1645ce1SZhang, Yanmin 1967a1645ce1SZhang, Yanmin err = dso__load_kallsyms(self, kallsyms_filename, map, filter); 1968a1645ce1SZhang, Yanmin if (err > 0) 1969a1645ce1SZhang, Yanmin pr_debug("Using %s for symbols\n", kallsyms_filename); 1970a1645ce1SZhang, Yanmin 1971a1645ce1SZhang, Yanmin out_try_fixup: 1972a1645ce1SZhang, Yanmin if (err > 0) { 1973a1645ce1SZhang, Yanmin if (kallsyms_filename != NULL) { 197448ea8f54SArnaldo Carvalho de Melo machine__mmap_name(machine, path, sizeof(path)); 197523346f21SArnaldo Carvalho de Melo dso__set_long_name(self, strdup(path)); 1976a1645ce1SZhang, Yanmin } 1977a1645ce1SZhang, Yanmin map__fixup_start(map); 1978a1645ce1SZhang, Yanmin map__fixup_end(map); 1979a1645ce1SZhang, Yanmin } 1980a1645ce1SZhang, Yanmin 1981a1645ce1SZhang, Yanmin return err; 1982a1645ce1SZhang, Yanmin } 1983cd84c2acSFrederic Weisbecker 1984b0da954aSArnaldo Carvalho de Melo static void dsos__add(struct list_head *head, struct dso *dso) 1985cd84c2acSFrederic Weisbecker { 1986b0da954aSArnaldo Carvalho de Melo list_add_tail(&dso->node, head); 1987cd84c2acSFrederic Weisbecker } 1988cd84c2acSFrederic Weisbecker 1989b0da954aSArnaldo Carvalho de Melo static struct dso *dsos__find(struct list_head *head, const char *name) 1990cd84c2acSFrederic Weisbecker { 1991cd84c2acSFrederic Weisbecker struct dso *pos; 1992cd84c2acSFrederic Weisbecker 1993b0da954aSArnaldo Carvalho de Melo list_for_each_entry(pos, head, node) 1994cf4e5b08SArnaldo Carvalho de Melo if (strcmp(pos->long_name, name) == 0) 1995cd84c2acSFrederic Weisbecker return pos; 1996cd84c2acSFrederic Weisbecker return NULL; 1997cd84c2acSFrederic Weisbecker } 1998cd84c2acSFrederic Weisbecker 1999a89e5abeSArnaldo Carvalho de Melo struct dso *__dsos__findnew(struct list_head *head, const char *name) 2000cd84c2acSFrederic Weisbecker { 2001a89e5abeSArnaldo Carvalho de Melo struct dso *dso = dsos__find(head, name); 2002cd84c2acSFrederic Weisbecker 2003e4204992SArnaldo Carvalho de Melo if (!dso) { 200400a192b3SArnaldo Carvalho de Melo dso = dso__new(name); 2005cfc10d3bSArnaldo Carvalho de Melo if (dso != NULL) { 2006a89e5abeSArnaldo Carvalho de Melo dsos__add(head, dso); 2007cfc10d3bSArnaldo Carvalho de Melo dso__set_basename(dso); 2008cfc10d3bSArnaldo Carvalho de Melo } 2009e4204992SArnaldo Carvalho de Melo } 2010cd84c2acSFrederic Weisbecker 2011cd84c2acSFrederic Weisbecker return dso; 2012cd84c2acSFrederic Weisbecker } 2013cd84c2acSFrederic Weisbecker 20141f626bc3SArnaldo Carvalho de Melo size_t __dsos__fprintf(struct list_head *head, FILE *fp) 2015cd84c2acSFrederic Weisbecker { 2016cd84c2acSFrederic Weisbecker struct dso *pos; 2017cbf69680SArnaldo Carvalho de Melo size_t ret = 0; 2018cd84c2acSFrederic Weisbecker 201995011c60SArnaldo Carvalho de Melo list_for_each_entry(pos, head, node) { 202095011c60SArnaldo Carvalho de Melo int i; 202195011c60SArnaldo Carvalho de Melo for (i = 0; i < MAP__NR_TYPES; ++i) 2022cbf69680SArnaldo Carvalho de Melo ret += dso__fprintf(pos, i, fp); 2023cd84c2acSFrederic Weisbecker } 2024cd84c2acSFrederic Weisbecker 2025cbf69680SArnaldo Carvalho de Melo return ret; 2026cbf69680SArnaldo Carvalho de Melo } 2027cbf69680SArnaldo Carvalho de Melo 2028cbf69680SArnaldo Carvalho de Melo size_t machines__fprintf_dsos(struct rb_root *self, FILE *fp) 2029b0da954aSArnaldo Carvalho de Melo { 2030a1645ce1SZhang, Yanmin struct rb_node *nd; 2031cbf69680SArnaldo Carvalho de Melo size_t ret = 0; 2032a1645ce1SZhang, Yanmin 2033cbf69680SArnaldo Carvalho de Melo for (nd = rb_first(self); nd; nd = rb_next(nd)) { 203423346f21SArnaldo Carvalho de Melo struct machine *pos = rb_entry(nd, struct machine, rb_node); 2035cbf69680SArnaldo Carvalho de Melo ret += __dsos__fprintf(&pos->kernel_dsos, fp); 2036cbf69680SArnaldo Carvalho de Melo ret += __dsos__fprintf(&pos->user_dsos, fp); 2037a1645ce1SZhang, Yanmin } 2038cbf69680SArnaldo Carvalho de Melo 2039cbf69680SArnaldo Carvalho de Melo return ret; 2040b0da954aSArnaldo Carvalho de Melo } 2041b0da954aSArnaldo Carvalho de Melo 204288d3d9b7SArnaldo Carvalho de Melo static size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp, 204388d3d9b7SArnaldo Carvalho de Melo bool with_hits) 20449e03eb2dSArnaldo Carvalho de Melo { 20459e03eb2dSArnaldo Carvalho de Melo struct dso *pos; 20469e03eb2dSArnaldo Carvalho de Melo size_t ret = 0; 20479e03eb2dSArnaldo Carvalho de Melo 2048b0da954aSArnaldo Carvalho de Melo list_for_each_entry(pos, head, node) { 204988d3d9b7SArnaldo Carvalho de Melo if (with_hits && !pos->hit) 205088d3d9b7SArnaldo Carvalho de Melo continue; 20519e03eb2dSArnaldo Carvalho de Melo ret += dso__fprintf_buildid(pos, fp); 20529e03eb2dSArnaldo Carvalho de Melo ret += fprintf(fp, " %s\n", pos->long_name); 20539e03eb2dSArnaldo Carvalho de Melo } 20549e03eb2dSArnaldo Carvalho de Melo return ret; 20559e03eb2dSArnaldo Carvalho de Melo } 20569e03eb2dSArnaldo Carvalho de Melo 2057f869097eSArnaldo Carvalho de Melo size_t machine__fprintf_dsos_buildid(struct machine *self, FILE *fp, bool with_hits) 2058f869097eSArnaldo Carvalho de Melo { 2059f869097eSArnaldo Carvalho de Melo return __dsos__fprintf_buildid(&self->kernel_dsos, fp, with_hits) + 2060f869097eSArnaldo Carvalho de Melo __dsos__fprintf_buildid(&self->user_dsos, fp, with_hits); 2061f869097eSArnaldo Carvalho de Melo } 2062f869097eSArnaldo Carvalho de Melo 2063cbf69680SArnaldo Carvalho de Melo size_t machines__fprintf_dsos_buildid(struct rb_root *self, FILE *fp, bool with_hits) 2064b0da954aSArnaldo Carvalho de Melo { 2065a1645ce1SZhang, Yanmin struct rb_node *nd; 2066a1645ce1SZhang, Yanmin size_t ret = 0; 2067a1645ce1SZhang, Yanmin 2068cbf69680SArnaldo Carvalho de Melo for (nd = rb_first(self); nd; nd = rb_next(nd)) { 206923346f21SArnaldo Carvalho de Melo struct machine *pos = rb_entry(nd, struct machine, rb_node); 2070f869097eSArnaldo Carvalho de Melo ret += machine__fprintf_dsos_buildid(pos, fp, with_hits); 2071a1645ce1SZhang, Yanmin } 2072a1645ce1SZhang, Yanmin return ret; 2073b0da954aSArnaldo Carvalho de Melo } 2074b0da954aSArnaldo Carvalho de Melo 2075fd1d908cSArnaldo Carvalho de Melo struct dso *dso__new_kernel(const char *name) 2076fd1d908cSArnaldo Carvalho de Melo { 2077fd1d908cSArnaldo Carvalho de Melo struct dso *self = dso__new(name ?: "[kernel.kallsyms]"); 2078fd1d908cSArnaldo Carvalho de Melo 2079fd1d908cSArnaldo Carvalho de Melo if (self != NULL) { 2080b63be8d7SArnaldo Carvalho de Melo dso__set_short_name(self, "[kernel]"); 2081a1645ce1SZhang, Yanmin self->kernel = DSO_TYPE_KERNEL; 2082fd1d908cSArnaldo Carvalho de Melo } 2083fd1d908cSArnaldo Carvalho de Melo 2084fd1d908cSArnaldo Carvalho de Melo return self; 2085fd1d908cSArnaldo Carvalho de Melo } 2086fd1d908cSArnaldo Carvalho de Melo 208723346f21SArnaldo Carvalho de Melo static struct dso *dso__new_guest_kernel(struct machine *machine, 2088a1645ce1SZhang, Yanmin const char *name) 2089fd1d908cSArnaldo Carvalho de Melo { 209048ea8f54SArnaldo Carvalho de Melo char bf[PATH_MAX]; 209148ea8f54SArnaldo Carvalho de Melo struct dso *self = dso__new(name ?: machine__mmap_name(machine, bf, sizeof(bf))); 2092a1645ce1SZhang, Yanmin 2093a1645ce1SZhang, Yanmin if (self != NULL) { 2094a1645ce1SZhang, Yanmin dso__set_short_name(self, "[guest.kernel]"); 2095a1645ce1SZhang, Yanmin self->kernel = DSO_TYPE_GUEST_KERNEL; 2096a1645ce1SZhang, Yanmin } 2097a1645ce1SZhang, Yanmin 2098a1645ce1SZhang, Yanmin return self; 2099a1645ce1SZhang, Yanmin } 2100a1645ce1SZhang, Yanmin 210123346f21SArnaldo Carvalho de Melo void dso__read_running_kernel_build_id(struct dso *self, struct machine *machine) 2102a1645ce1SZhang, Yanmin { 2103a1645ce1SZhang, Yanmin char path[PATH_MAX]; 2104a1645ce1SZhang, Yanmin 210523346f21SArnaldo Carvalho de Melo if (machine__is_default_guest(machine)) 2106a1645ce1SZhang, Yanmin return; 210723346f21SArnaldo Carvalho de Melo sprintf(path, "%s/sys/kernel/notes", machine->root_dir); 2108a1645ce1SZhang, Yanmin if (sysfs__read_build_id(path, self->build_id, 2109fd1d908cSArnaldo Carvalho de Melo sizeof(self->build_id)) == 0) 2110fd1d908cSArnaldo Carvalho de Melo self->has_build_id = true; 2111fd1d908cSArnaldo Carvalho de Melo } 2112fd1d908cSArnaldo Carvalho de Melo 21135c0541d5SArnaldo Carvalho de Melo static struct dso *machine__create_kernel(struct machine *self) 2114cd84c2acSFrederic Weisbecker { 2115a1645ce1SZhang, Yanmin const char *vmlinux_name = NULL; 2116a1645ce1SZhang, Yanmin struct dso *kernel; 2117cd84c2acSFrederic Weisbecker 21185c0541d5SArnaldo Carvalho de Melo if (machine__is_host(self)) { 2119a1645ce1SZhang, Yanmin vmlinux_name = symbol_conf.vmlinux_name; 2120a1645ce1SZhang, Yanmin kernel = dso__new_kernel(vmlinux_name); 2121a1645ce1SZhang, Yanmin } else { 21225c0541d5SArnaldo Carvalho de Melo if (machine__is_default_guest(self)) 2123a1645ce1SZhang, Yanmin vmlinux_name = symbol_conf.default_guest_vmlinux_name; 21245c0541d5SArnaldo Carvalho de Melo kernel = dso__new_guest_kernel(self, vmlinux_name); 21258d92c02aSArnaldo Carvalho de Melo } 2126cd84c2acSFrederic Weisbecker 2127a1645ce1SZhang, Yanmin if (kernel != NULL) { 21285c0541d5SArnaldo Carvalho de Melo dso__read_running_kernel_build_id(kernel, self); 21295c0541d5SArnaldo Carvalho de Melo dsos__add(&self->kernel_dsos, kernel); 2130a1645ce1SZhang, Yanmin } 2131f1dfa0b1SArnaldo Carvalho de Melo return kernel; 2132f1dfa0b1SArnaldo Carvalho de Melo } 2133f1dfa0b1SArnaldo Carvalho de Melo 2134d214afbdSMing Lei struct process_args { 2135d214afbdSMing Lei u64 start; 2136d214afbdSMing Lei }; 2137d214afbdSMing Lei 2138d214afbdSMing Lei static int symbol__in_kernel(void *arg, const char *name, 2139d214afbdSMing Lei char type __used, u64 start) 2140d214afbdSMing Lei { 2141d214afbdSMing Lei struct process_args *args = arg; 2142d214afbdSMing Lei 2143d214afbdSMing Lei if (strchr(name, '[')) 2144d214afbdSMing Lei return 0; 2145d214afbdSMing Lei 2146d214afbdSMing Lei args->start = start; 2147d214afbdSMing Lei return 1; 2148d214afbdSMing Lei } 2149d214afbdSMing Lei 2150d214afbdSMing Lei /* Figure out the start address of kernel map from /proc/kallsyms */ 2151d214afbdSMing Lei static u64 machine__get_kernel_start_addr(struct machine *machine) 2152d214afbdSMing Lei { 2153d214afbdSMing Lei const char *filename; 2154d214afbdSMing Lei char path[PATH_MAX]; 2155d214afbdSMing Lei struct process_args args; 2156d214afbdSMing Lei 2157d214afbdSMing Lei if (machine__is_host(machine)) { 2158d214afbdSMing Lei filename = "/proc/kallsyms"; 2159d214afbdSMing Lei } else { 2160d214afbdSMing Lei if (machine__is_default_guest(machine)) 2161d214afbdSMing Lei filename = (char *)symbol_conf.default_guest_kallsyms; 2162d214afbdSMing Lei else { 2163d214afbdSMing Lei sprintf(path, "%s/proc/kallsyms", machine->root_dir); 2164d214afbdSMing Lei filename = path; 2165d214afbdSMing Lei } 2166d214afbdSMing Lei } 2167d214afbdSMing Lei 2168d214afbdSMing Lei if (kallsyms__parse(filename, &args, symbol__in_kernel) <= 0) 2169d214afbdSMing Lei return 0; 2170d214afbdSMing Lei 2171d214afbdSMing Lei return args.start; 2172d214afbdSMing Lei } 2173d214afbdSMing Lei 2174d28c6223SArnaldo Carvalho de Melo int __machine__create_kernel_maps(struct machine *self, struct dso *kernel) 2175f1dfa0b1SArnaldo Carvalho de Melo { 2176de176489SArnaldo Carvalho de Melo enum map_type type; 2177d214afbdSMing Lei u64 start = machine__get_kernel_start_addr(self); 2178f1dfa0b1SArnaldo Carvalho de Melo 2179de176489SArnaldo Carvalho de Melo for (type = 0; type < MAP__NR_TYPES; ++type) { 21809de89fe7SArnaldo Carvalho de Melo struct kmap *kmap; 21819de89fe7SArnaldo Carvalho de Melo 2182d214afbdSMing Lei self->vmlinux_maps[type] = map__new2(start, kernel, type); 2183d28c6223SArnaldo Carvalho de Melo if (self->vmlinux_maps[type] == NULL) 2184f1dfa0b1SArnaldo Carvalho de Melo return -1; 2185f1dfa0b1SArnaldo Carvalho de Melo 2186d28c6223SArnaldo Carvalho de Melo self->vmlinux_maps[type]->map_ip = 2187d28c6223SArnaldo Carvalho de Melo self->vmlinux_maps[type]->unmap_ip = identity__map_ip; 21889de89fe7SArnaldo Carvalho de Melo 2189d28c6223SArnaldo Carvalho de Melo kmap = map__kmap(self->vmlinux_maps[type]); 2190d28c6223SArnaldo Carvalho de Melo kmap->kmaps = &self->kmaps; 2191d28c6223SArnaldo Carvalho de Melo map_groups__insert(&self->kmaps, self->vmlinux_maps[type]); 2192f1dfa0b1SArnaldo Carvalho de Melo } 2193f1dfa0b1SArnaldo Carvalho de Melo 2194f1dfa0b1SArnaldo Carvalho de Melo return 0; 21952446042cSArnaldo Carvalho de Melo } 21962446042cSArnaldo Carvalho de Melo 2197076c6e45SArnaldo Carvalho de Melo void machine__destroy_kernel_maps(struct machine *self) 2198076c6e45SArnaldo Carvalho de Melo { 2199076c6e45SArnaldo Carvalho de Melo enum map_type type; 2200076c6e45SArnaldo Carvalho de Melo 2201076c6e45SArnaldo Carvalho de Melo for (type = 0; type < MAP__NR_TYPES; ++type) { 2202076c6e45SArnaldo Carvalho de Melo struct kmap *kmap; 2203076c6e45SArnaldo Carvalho de Melo 2204076c6e45SArnaldo Carvalho de Melo if (self->vmlinux_maps[type] == NULL) 2205076c6e45SArnaldo Carvalho de Melo continue; 2206076c6e45SArnaldo Carvalho de Melo 2207076c6e45SArnaldo Carvalho de Melo kmap = map__kmap(self->vmlinux_maps[type]); 2208076c6e45SArnaldo Carvalho de Melo map_groups__remove(&self->kmaps, self->vmlinux_maps[type]); 2209076c6e45SArnaldo Carvalho de Melo if (kmap->ref_reloc_sym) { 2210076c6e45SArnaldo Carvalho de Melo /* 2211076c6e45SArnaldo Carvalho de Melo * ref_reloc_sym is shared among all maps, so free just 2212076c6e45SArnaldo Carvalho de Melo * on one of them. 2213076c6e45SArnaldo Carvalho de Melo */ 2214076c6e45SArnaldo Carvalho de Melo if (type == MAP__FUNCTION) { 2215076c6e45SArnaldo Carvalho de Melo free((char *)kmap->ref_reloc_sym->name); 2216076c6e45SArnaldo Carvalho de Melo kmap->ref_reloc_sym->name = NULL; 2217076c6e45SArnaldo Carvalho de Melo free(kmap->ref_reloc_sym); 2218076c6e45SArnaldo Carvalho de Melo } 2219076c6e45SArnaldo Carvalho de Melo kmap->ref_reloc_sym = NULL; 2220076c6e45SArnaldo Carvalho de Melo } 2221076c6e45SArnaldo Carvalho de Melo 2222076c6e45SArnaldo Carvalho de Melo map__delete(self->vmlinux_maps[type]); 2223076c6e45SArnaldo Carvalho de Melo self->vmlinux_maps[type] = NULL; 2224076c6e45SArnaldo Carvalho de Melo } 2225076c6e45SArnaldo Carvalho de Melo } 2226076c6e45SArnaldo Carvalho de Melo 22275c0541d5SArnaldo Carvalho de Melo int machine__create_kernel_maps(struct machine *self) 22285c0541d5SArnaldo Carvalho de Melo { 22295c0541d5SArnaldo Carvalho de Melo struct dso *kernel = machine__create_kernel(self); 22305c0541d5SArnaldo Carvalho de Melo 22315c0541d5SArnaldo Carvalho de Melo if (kernel == NULL || 22325c0541d5SArnaldo Carvalho de Melo __machine__create_kernel_maps(self, kernel) < 0) 22335c0541d5SArnaldo Carvalho de Melo return -1; 22345c0541d5SArnaldo Carvalho de Melo 22355c0541d5SArnaldo Carvalho de Melo if (symbol_conf.use_modules && machine__create_modules(self) < 0) 22365c0541d5SArnaldo Carvalho de Melo pr_debug("Problems creating module maps, continuing anyway...\n"); 22375c0541d5SArnaldo Carvalho de Melo /* 22385c0541d5SArnaldo Carvalho de Melo * Now that we have all the maps created, just set the ->end of them: 22395c0541d5SArnaldo Carvalho de Melo */ 22405c0541d5SArnaldo Carvalho de Melo map_groups__fixup_end(&self->kmaps); 22415c0541d5SArnaldo Carvalho de Melo return 0; 22425c0541d5SArnaldo Carvalho de Melo } 22435c0541d5SArnaldo Carvalho de Melo 2244cc612d81SArnaldo Carvalho de Melo static void vmlinux_path__exit(void) 22452446042cSArnaldo Carvalho de Melo { 2246cc612d81SArnaldo Carvalho de Melo while (--vmlinux_path__nr_entries >= 0) { 2247cc612d81SArnaldo Carvalho de Melo free(vmlinux_path[vmlinux_path__nr_entries]); 2248cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = NULL; 2249cc612d81SArnaldo Carvalho de Melo } 2250cc612d81SArnaldo Carvalho de Melo 2251cc612d81SArnaldo Carvalho de Melo free(vmlinux_path); 2252cc612d81SArnaldo Carvalho de Melo vmlinux_path = NULL; 2253cc612d81SArnaldo Carvalho de Melo } 2254cc612d81SArnaldo Carvalho de Melo 2255cc612d81SArnaldo Carvalho de Melo static int vmlinux_path__init(void) 2256cc612d81SArnaldo Carvalho de Melo { 2257cc612d81SArnaldo Carvalho de Melo struct utsname uts; 2258cc612d81SArnaldo Carvalho de Melo char bf[PATH_MAX]; 2259cc612d81SArnaldo Carvalho de Melo 2260cc612d81SArnaldo Carvalho de Melo if (uname(&uts) < 0) 22612446042cSArnaldo Carvalho de Melo return -1; 22622446042cSArnaldo Carvalho de Melo 2263cc612d81SArnaldo Carvalho de Melo vmlinux_path = malloc(sizeof(char *) * 5); 2264cc612d81SArnaldo Carvalho de Melo if (vmlinux_path == NULL) 2265cc612d81SArnaldo Carvalho de Melo return -1; 2266cc612d81SArnaldo Carvalho de Melo 2267cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup("vmlinux"); 2268cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 2269cc612d81SArnaldo Carvalho de Melo goto out_fail; 2270cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 2271cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup("/boot/vmlinux"); 2272cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 2273cc612d81SArnaldo Carvalho de Melo goto out_fail; 2274cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 2275cc612d81SArnaldo Carvalho de Melo snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", uts.release); 2276cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); 2277cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 2278cc612d81SArnaldo Carvalho de Melo goto out_fail; 2279cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 2280cc612d81SArnaldo Carvalho de Melo snprintf(bf, sizeof(bf), "/lib/modules/%s/build/vmlinux", uts.release); 2281cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); 2282cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 2283cc612d81SArnaldo Carvalho de Melo goto out_fail; 2284cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 2285cc612d81SArnaldo Carvalho de Melo snprintf(bf, sizeof(bf), "/usr/lib/debug/lib/modules/%s/vmlinux", 2286cc612d81SArnaldo Carvalho de Melo uts.release); 2287cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); 2288cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 2289cc612d81SArnaldo Carvalho de Melo goto out_fail; 2290cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 2291cc612d81SArnaldo Carvalho de Melo 2292cc612d81SArnaldo Carvalho de Melo return 0; 2293cc612d81SArnaldo Carvalho de Melo 2294cc612d81SArnaldo Carvalho de Melo out_fail: 2295cc612d81SArnaldo Carvalho de Melo vmlinux_path__exit(); 2296cc612d81SArnaldo Carvalho de Melo return -1; 2297cc612d81SArnaldo Carvalho de Melo } 2298cc612d81SArnaldo Carvalho de Melo 22995ad90e4eSArnaldo Carvalho de Melo size_t machine__fprintf_vmlinux_path(struct machine *self, FILE *fp) 2300b0a9ab62SArnaldo Carvalho de Melo { 2301b0a9ab62SArnaldo Carvalho de Melo int i; 2302b0a9ab62SArnaldo Carvalho de Melo size_t printed = 0; 23035ad90e4eSArnaldo Carvalho de Melo struct dso *kdso = self->vmlinux_maps[MAP__FUNCTION]->dso; 23045ad90e4eSArnaldo Carvalho de Melo 23055ad90e4eSArnaldo Carvalho de Melo if (kdso->has_build_id) { 23065ad90e4eSArnaldo Carvalho de Melo char filename[PATH_MAX]; 23075ad90e4eSArnaldo Carvalho de Melo if (dso__build_id_filename(kdso, filename, sizeof(filename))) 23085ad90e4eSArnaldo Carvalho de Melo printed += fprintf(fp, "[0] %s\n", filename); 23095ad90e4eSArnaldo Carvalho de Melo } 2310b0a9ab62SArnaldo Carvalho de Melo 2311b0a9ab62SArnaldo Carvalho de Melo for (i = 0; i < vmlinux_path__nr_entries; ++i) 23125ad90e4eSArnaldo Carvalho de Melo printed += fprintf(fp, "[%d] %s\n", 23135ad90e4eSArnaldo Carvalho de Melo i + kdso->has_build_id, vmlinux_path[i]); 2314b0a9ab62SArnaldo Carvalho de Melo 2315b0a9ab62SArnaldo Carvalho de Melo return printed; 2316b0a9ab62SArnaldo Carvalho de Melo } 2317b0a9ab62SArnaldo Carvalho de Melo 2318655000e7SArnaldo Carvalho de Melo static int setup_list(struct strlist **list, const char *list_str, 2319655000e7SArnaldo Carvalho de Melo const char *list_name) 2320655000e7SArnaldo Carvalho de Melo { 2321655000e7SArnaldo Carvalho de Melo if (list_str == NULL) 2322655000e7SArnaldo Carvalho de Melo return 0; 2323655000e7SArnaldo Carvalho de Melo 2324655000e7SArnaldo Carvalho de Melo *list = strlist__new(true, list_str); 2325655000e7SArnaldo Carvalho de Melo if (!*list) { 2326655000e7SArnaldo Carvalho de Melo pr_err("problems parsing %s list\n", list_name); 2327655000e7SArnaldo Carvalho de Melo return -1; 2328655000e7SArnaldo Carvalho de Melo } 2329655000e7SArnaldo Carvalho de Melo return 0; 2330655000e7SArnaldo Carvalho de Melo } 2331655000e7SArnaldo Carvalho de Melo 233275be6cf4SArnaldo Carvalho de Melo int symbol__init(void) 2333cc612d81SArnaldo Carvalho de Melo { 233485e00b55SJovi Zhang if (symbol_conf.initialized) 233585e00b55SJovi Zhang return 0; 233685e00b55SJovi Zhang 233795011c60SArnaldo Carvalho de Melo elf_version(EV_CURRENT); 233875be6cf4SArnaldo Carvalho de Melo if (symbol_conf.sort_by_name) 233975be6cf4SArnaldo Carvalho de Melo symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) - 234079406cd7SArnaldo Carvalho de Melo sizeof(struct symbol)); 2341b32d133aSArnaldo Carvalho de Melo 234275be6cf4SArnaldo Carvalho de Melo if (symbol_conf.try_vmlinux_path && vmlinux_path__init() < 0) 2343cc612d81SArnaldo Carvalho de Melo return -1; 2344cc612d81SArnaldo Carvalho de Melo 2345c410a338SArnaldo Carvalho de Melo if (symbol_conf.field_sep && *symbol_conf.field_sep == '.') { 2346c410a338SArnaldo Carvalho de Melo pr_err("'.' is the only non valid --field-separator argument\n"); 2347c410a338SArnaldo Carvalho de Melo return -1; 2348c410a338SArnaldo Carvalho de Melo } 2349c410a338SArnaldo Carvalho de Melo 2350655000e7SArnaldo Carvalho de Melo if (setup_list(&symbol_conf.dso_list, 2351655000e7SArnaldo Carvalho de Melo symbol_conf.dso_list_str, "dso") < 0) 2352655000e7SArnaldo Carvalho de Melo return -1; 2353655000e7SArnaldo Carvalho de Melo 2354655000e7SArnaldo Carvalho de Melo if (setup_list(&symbol_conf.comm_list, 2355655000e7SArnaldo Carvalho de Melo symbol_conf.comm_list_str, "comm") < 0) 2356655000e7SArnaldo Carvalho de Melo goto out_free_dso_list; 2357655000e7SArnaldo Carvalho de Melo 2358655000e7SArnaldo Carvalho de Melo if (setup_list(&symbol_conf.sym_list, 2359655000e7SArnaldo Carvalho de Melo symbol_conf.sym_list_str, "symbol") < 0) 2360655000e7SArnaldo Carvalho de Melo goto out_free_comm_list; 2361655000e7SArnaldo Carvalho de Melo 236285e00b55SJovi Zhang symbol_conf.initialized = true; 23634aa65636SArnaldo Carvalho de Melo return 0; 2364655000e7SArnaldo Carvalho de Melo 2365655000e7SArnaldo Carvalho de Melo out_free_dso_list: 2366655000e7SArnaldo Carvalho de Melo strlist__delete(symbol_conf.dso_list); 2367655000e7SArnaldo Carvalho de Melo out_free_comm_list: 2368655000e7SArnaldo Carvalho de Melo strlist__delete(symbol_conf.comm_list); 2369655000e7SArnaldo Carvalho de Melo return -1; 2370cc612d81SArnaldo Carvalho de Melo } 2371cc612d81SArnaldo Carvalho de Melo 2372d65a458bSArnaldo Carvalho de Melo void symbol__exit(void) 2373d65a458bSArnaldo Carvalho de Melo { 237485e00b55SJovi Zhang if (!symbol_conf.initialized) 237585e00b55SJovi Zhang return; 2376d65a458bSArnaldo Carvalho de Melo strlist__delete(symbol_conf.sym_list); 2377d65a458bSArnaldo Carvalho de Melo strlist__delete(symbol_conf.dso_list); 2378d65a458bSArnaldo Carvalho de Melo strlist__delete(symbol_conf.comm_list); 2379d65a458bSArnaldo Carvalho de Melo vmlinux_path__exit(); 2380d65a458bSArnaldo Carvalho de Melo symbol_conf.sym_list = symbol_conf.dso_list = symbol_conf.comm_list = NULL; 238185e00b55SJovi Zhang symbol_conf.initialized = false; 2382d65a458bSArnaldo Carvalho de Melo } 2383d65a458bSArnaldo Carvalho de Melo 2384d28c6223SArnaldo Carvalho de Melo int machines__create_kernel_maps(struct rb_root *self, pid_t pid) 23854aa65636SArnaldo Carvalho de Melo { 2386d28c6223SArnaldo Carvalho de Melo struct machine *machine = machines__findnew(self, pid); 23879de89fe7SArnaldo Carvalho de Melo 238823346f21SArnaldo Carvalho de Melo if (machine == NULL) 2389a1645ce1SZhang, Yanmin return -1; 23904aa65636SArnaldo Carvalho de Melo 23915c0541d5SArnaldo Carvalho de Melo return machine__create_kernel_maps(machine); 2392cd84c2acSFrederic Weisbecker } 23935aab621bSArnaldo Carvalho de Melo 23945aab621bSArnaldo Carvalho de Melo static int hex(char ch) 23955aab621bSArnaldo Carvalho de Melo { 23965aab621bSArnaldo Carvalho de Melo if ((ch >= '0') && (ch <= '9')) 23975aab621bSArnaldo Carvalho de Melo return ch - '0'; 23985aab621bSArnaldo Carvalho de Melo if ((ch >= 'a') && (ch <= 'f')) 23995aab621bSArnaldo Carvalho de Melo return ch - 'a' + 10; 24005aab621bSArnaldo Carvalho de Melo if ((ch >= 'A') && (ch <= 'F')) 24015aab621bSArnaldo Carvalho de Melo return ch - 'A' + 10; 24025aab621bSArnaldo Carvalho de Melo return -1; 24035aab621bSArnaldo Carvalho de Melo } 24045aab621bSArnaldo Carvalho de Melo 24055aab621bSArnaldo Carvalho de Melo /* 24065aab621bSArnaldo Carvalho de Melo * While we find nice hex chars, build a long_val. 24075aab621bSArnaldo Carvalho de Melo * Return number of chars processed. 24085aab621bSArnaldo Carvalho de Melo */ 24095aab621bSArnaldo Carvalho de Melo int hex2u64(const char *ptr, u64 *long_val) 24105aab621bSArnaldo Carvalho de Melo { 24115aab621bSArnaldo Carvalho de Melo const char *p = ptr; 24125aab621bSArnaldo Carvalho de Melo *long_val = 0; 24135aab621bSArnaldo Carvalho de Melo 24145aab621bSArnaldo Carvalho de Melo while (*p) { 24155aab621bSArnaldo Carvalho de Melo const int hex_val = hex(*p); 24165aab621bSArnaldo Carvalho de Melo 24175aab621bSArnaldo Carvalho de Melo if (hex_val < 0) 24185aab621bSArnaldo Carvalho de Melo break; 24195aab621bSArnaldo Carvalho de Melo 24205aab621bSArnaldo Carvalho de Melo *long_val = (*long_val << 4) | hex_val; 24215aab621bSArnaldo Carvalho de Melo p++; 24225aab621bSArnaldo Carvalho de Melo } 24235aab621bSArnaldo Carvalho de Melo 24245aab621bSArnaldo Carvalho de Melo return p - ptr; 24255aab621bSArnaldo Carvalho de Melo } 24265aab621bSArnaldo Carvalho de Melo 24275aab621bSArnaldo Carvalho de Melo char *strxfrchar(char *s, char from, char to) 24285aab621bSArnaldo Carvalho de Melo { 24295aab621bSArnaldo Carvalho de Melo char *p = s; 24305aab621bSArnaldo Carvalho de Melo 24315aab621bSArnaldo Carvalho de Melo while ((p = strchr(p, from)) != NULL) 24325aab621bSArnaldo Carvalho de Melo *p++ = to; 24335aab621bSArnaldo Carvalho de Melo 24345aab621bSArnaldo Carvalho de Melo return s; 24355aab621bSArnaldo Carvalho de Melo } 2436a1645ce1SZhang, Yanmin 2437d28c6223SArnaldo Carvalho de Melo int machines__create_guest_kernel_maps(struct rb_root *self) 2438a1645ce1SZhang, Yanmin { 2439a1645ce1SZhang, Yanmin int ret = 0; 2440a1645ce1SZhang, Yanmin struct dirent **namelist = NULL; 2441a1645ce1SZhang, Yanmin int i, items = 0; 2442a1645ce1SZhang, Yanmin char path[PATH_MAX]; 2443a1645ce1SZhang, Yanmin pid_t pid; 2444a1645ce1SZhang, Yanmin 2445a1645ce1SZhang, Yanmin if (symbol_conf.default_guest_vmlinux_name || 2446a1645ce1SZhang, Yanmin symbol_conf.default_guest_modules || 2447a1645ce1SZhang, Yanmin symbol_conf.default_guest_kallsyms) { 2448d28c6223SArnaldo Carvalho de Melo machines__create_kernel_maps(self, DEFAULT_GUEST_KERNEL_ID); 2449a1645ce1SZhang, Yanmin } 2450a1645ce1SZhang, Yanmin 2451a1645ce1SZhang, Yanmin if (symbol_conf.guestmount) { 2452a1645ce1SZhang, Yanmin items = scandir(symbol_conf.guestmount, &namelist, NULL, NULL); 2453a1645ce1SZhang, Yanmin if (items <= 0) 2454a1645ce1SZhang, Yanmin return -ENOENT; 2455a1645ce1SZhang, Yanmin for (i = 0; i < items; i++) { 2456a1645ce1SZhang, Yanmin if (!isdigit(namelist[i]->d_name[0])) { 2457a1645ce1SZhang, Yanmin /* Filter out . and .. */ 2458a1645ce1SZhang, Yanmin continue; 2459a1645ce1SZhang, Yanmin } 2460a1645ce1SZhang, Yanmin pid = atoi(namelist[i]->d_name); 2461a1645ce1SZhang, Yanmin sprintf(path, "%s/%s/proc/kallsyms", 2462a1645ce1SZhang, Yanmin symbol_conf.guestmount, 2463a1645ce1SZhang, Yanmin namelist[i]->d_name); 2464a1645ce1SZhang, Yanmin ret = access(path, R_OK); 2465a1645ce1SZhang, Yanmin if (ret) { 2466a1645ce1SZhang, Yanmin pr_debug("Can't access file %s\n", path); 2467a1645ce1SZhang, Yanmin goto failure; 2468a1645ce1SZhang, Yanmin } 2469d28c6223SArnaldo Carvalho de Melo machines__create_kernel_maps(self, pid); 2470a1645ce1SZhang, Yanmin } 2471a1645ce1SZhang, Yanmin failure: 2472a1645ce1SZhang, Yanmin free(namelist); 2473a1645ce1SZhang, Yanmin } 2474a1645ce1SZhang, Yanmin 2475a1645ce1SZhang, Yanmin return ret; 2476a1645ce1SZhang, Yanmin } 24775c0541d5SArnaldo Carvalho de Melo 2478076c6e45SArnaldo Carvalho de Melo void machines__destroy_guest_kernel_maps(struct rb_root *self) 2479076c6e45SArnaldo Carvalho de Melo { 2480076c6e45SArnaldo Carvalho de Melo struct rb_node *next = rb_first(self); 2481076c6e45SArnaldo Carvalho de Melo 2482076c6e45SArnaldo Carvalho de Melo while (next) { 2483076c6e45SArnaldo Carvalho de Melo struct machine *pos = rb_entry(next, struct machine, rb_node); 2484076c6e45SArnaldo Carvalho de Melo 2485076c6e45SArnaldo Carvalho de Melo next = rb_next(&pos->rb_node); 2486076c6e45SArnaldo Carvalho de Melo rb_erase(&pos->rb_node, self); 2487076c6e45SArnaldo Carvalho de Melo machine__delete(pos); 2488076c6e45SArnaldo Carvalho de Melo } 2489076c6e45SArnaldo Carvalho de Melo } 2490076c6e45SArnaldo Carvalho de Melo 24915c0541d5SArnaldo Carvalho de Melo int machine__load_kallsyms(struct machine *self, const char *filename, 24925c0541d5SArnaldo Carvalho de Melo enum map_type type, symbol_filter_t filter) 24935c0541d5SArnaldo Carvalho de Melo { 24945c0541d5SArnaldo Carvalho de Melo struct map *map = self->vmlinux_maps[type]; 24955c0541d5SArnaldo Carvalho de Melo int ret = dso__load_kallsyms(map->dso, filename, map, filter); 24965c0541d5SArnaldo Carvalho de Melo 24975c0541d5SArnaldo Carvalho de Melo if (ret > 0) { 24985c0541d5SArnaldo Carvalho de Melo dso__set_loaded(map->dso, type); 24995c0541d5SArnaldo Carvalho de Melo /* 25005c0541d5SArnaldo Carvalho de Melo * Since /proc/kallsyms will have multiple sessions for the 25015c0541d5SArnaldo Carvalho de Melo * kernel, with modules between them, fixup the end of all 25025c0541d5SArnaldo Carvalho de Melo * sections. 25035c0541d5SArnaldo Carvalho de Melo */ 25045c0541d5SArnaldo Carvalho de Melo __map_groups__fixup_end(&self->kmaps, type); 25055c0541d5SArnaldo Carvalho de Melo } 25065c0541d5SArnaldo Carvalho de Melo 25075c0541d5SArnaldo Carvalho de Melo return ret; 25085c0541d5SArnaldo Carvalho de Melo } 25095c0541d5SArnaldo Carvalho de Melo 25105c0541d5SArnaldo Carvalho de Melo int machine__load_vmlinux_path(struct machine *self, enum map_type type, 25115c0541d5SArnaldo Carvalho de Melo symbol_filter_t filter) 25125c0541d5SArnaldo Carvalho de Melo { 25135c0541d5SArnaldo Carvalho de Melo struct map *map = self->vmlinux_maps[type]; 25145c0541d5SArnaldo Carvalho de Melo int ret = dso__load_vmlinux_path(map->dso, map, filter); 25155c0541d5SArnaldo Carvalho de Melo 25165c0541d5SArnaldo Carvalho de Melo if (ret > 0) { 25175c0541d5SArnaldo Carvalho de Melo dso__set_loaded(map->dso, type); 25185c0541d5SArnaldo Carvalho de Melo map__reloc_vmlinux(map); 25195c0541d5SArnaldo Carvalho de Melo } 25205c0541d5SArnaldo Carvalho de Melo 25215c0541d5SArnaldo Carvalho de Melo return ret; 25225c0541d5SArnaldo Carvalho de Melo } 2523