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 253b01a413SArnaldo Carvalho de Melo #ifndef KSYM_NAME_LEN 263b01a413SArnaldo Carvalho de Melo #define KSYM_NAME_LEN 128 273b01a413SArnaldo Carvalho de Melo #endif 283b01a413SArnaldo Carvalho de Melo 29c12e15e7SArnaldo Carvalho de Melo #ifndef NT_GNU_BUILD_ID 30c12e15e7SArnaldo Carvalho de Melo #define NT_GNU_BUILD_ID 3 31c12e15e7SArnaldo Carvalho de Melo #endif 32c12e15e7SArnaldo Carvalho de Melo 3321916c38SDave Martin static bool dso__build_id_equal(const struct dso *self, u8 *build_id); 3421916c38SDave Martin static int elf_read_build_id(Elf *elf, void *bf, size_t size); 35b0da954aSArnaldo Carvalho de Melo static void dsos__add(struct list_head *head, struct dso *dso); 363610583cSArnaldo Carvalho de Melo static struct map *map__new2(u64 start, struct dso *dso, enum map_type type); 37c338aee8SArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *self, struct map *map, 389de89fe7SArnaldo Carvalho de Melo symbol_filter_t filter); 39a1645ce1SZhang, Yanmin static int dso__load_guest_kernel_sym(struct dso *self, struct map *map, 40a1645ce1SZhang, Yanmin symbol_filter_t filter); 41cc612d81SArnaldo Carvalho de Melo static int vmlinux_path__nr_entries; 42cc612d81SArnaldo Carvalho de Melo static char **vmlinux_path; 43439d473bSArnaldo Carvalho de Melo 4475be6cf4SArnaldo Carvalho de Melo struct symbol_conf symbol_conf = { 45d599db3fSArnaldo Carvalho de Melo .exclude_other = true, 46b32d133aSArnaldo Carvalho de Melo .use_modules = true, 47b32d133aSArnaldo Carvalho de Melo .try_vmlinux_path = true, 48ec5761eaSDavid Ahern .symfs = "", 49b32d133aSArnaldo Carvalho de Melo }; 50b32d133aSArnaldo Carvalho de Melo 518a6c5b26SArnaldo Carvalho de Melo int dso__name_len(const struct dso *self) 528a6c5b26SArnaldo Carvalho de Melo { 538a6c5b26SArnaldo Carvalho de Melo if (verbose) 548a6c5b26SArnaldo Carvalho de Melo return self->long_name_len; 558a6c5b26SArnaldo Carvalho de Melo 568a6c5b26SArnaldo Carvalho de Melo return self->short_name_len; 578a6c5b26SArnaldo Carvalho de Melo } 588a6c5b26SArnaldo Carvalho de Melo 593610583cSArnaldo Carvalho de Melo bool dso__loaded(const struct dso *self, enum map_type type) 603610583cSArnaldo Carvalho de Melo { 613610583cSArnaldo Carvalho de Melo return self->loaded & (1 << type); 623610583cSArnaldo Carvalho de Melo } 633610583cSArnaldo Carvalho de Melo 6479406cd7SArnaldo Carvalho de Melo bool dso__sorted_by_name(const struct dso *self, enum map_type type) 6579406cd7SArnaldo Carvalho de Melo { 6679406cd7SArnaldo Carvalho de Melo return self->sorted_by_name & (1 << type); 6779406cd7SArnaldo Carvalho de Melo } 6879406cd7SArnaldo Carvalho de Melo 6979406cd7SArnaldo Carvalho de Melo static void dso__set_sorted_by_name(struct dso *self, enum map_type type) 7079406cd7SArnaldo Carvalho de Melo { 7179406cd7SArnaldo Carvalho de Melo self->sorted_by_name |= (1 << type); 7279406cd7SArnaldo Carvalho de Melo } 7379406cd7SArnaldo Carvalho de Melo 7436a3e646SArnaldo Carvalho de Melo bool symbol_type__is_a(char symbol_type, enum map_type map_type) 756893d4eeSArnaldo Carvalho de Melo { 766893d4eeSArnaldo Carvalho de Melo switch (map_type) { 776893d4eeSArnaldo Carvalho de Melo case MAP__FUNCTION: 786893d4eeSArnaldo Carvalho de Melo return symbol_type == 'T' || symbol_type == 'W'; 79f1dfa0b1SArnaldo Carvalho de Melo case MAP__VARIABLE: 80f1dfa0b1SArnaldo Carvalho de Melo return symbol_type == 'D' || symbol_type == 'd'; 816893d4eeSArnaldo Carvalho de Melo default: 826893d4eeSArnaldo Carvalho de Melo return false; 836893d4eeSArnaldo Carvalho de Melo } 846893d4eeSArnaldo Carvalho de Melo } 856893d4eeSArnaldo Carvalho de Melo 86fcf1203aSArnaldo Carvalho de Melo static void symbols__fixup_end(struct rb_root *self) 87af427bf5SArnaldo Carvalho de Melo { 88fcf1203aSArnaldo Carvalho de Melo struct rb_node *nd, *prevnd = rb_first(self); 892e538c4aSArnaldo Carvalho de Melo struct symbol *curr, *prev; 90af427bf5SArnaldo Carvalho de Melo 91af427bf5SArnaldo Carvalho de Melo if (prevnd == NULL) 92af427bf5SArnaldo Carvalho de Melo return; 93af427bf5SArnaldo Carvalho de Melo 942e538c4aSArnaldo Carvalho de Melo curr = rb_entry(prevnd, struct symbol, rb_node); 952e538c4aSArnaldo Carvalho de Melo 96af427bf5SArnaldo Carvalho de Melo for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) { 972e538c4aSArnaldo Carvalho de Melo prev = curr; 982e538c4aSArnaldo Carvalho de Melo curr = rb_entry(nd, struct symbol, rb_node); 99af427bf5SArnaldo Carvalho de Melo 1003b01a413SArnaldo Carvalho de Melo if (prev->end == prev->start && prev->end != curr->start) 101af427bf5SArnaldo Carvalho de Melo prev->end = curr->start - 1; 102af427bf5SArnaldo Carvalho de Melo } 103af427bf5SArnaldo Carvalho de Melo 1042e538c4aSArnaldo Carvalho de Melo /* Last entry */ 1052e538c4aSArnaldo Carvalho de Melo if (curr->end == curr->start) 1062e538c4aSArnaldo Carvalho de Melo curr->end = roundup(curr->start, 4096); 1072e538c4aSArnaldo Carvalho de Melo } 1082e538c4aSArnaldo Carvalho de Melo 1099958e1f0SArnaldo Carvalho de Melo static void __map_groups__fixup_end(struct map_groups *self, enum map_type type) 110af427bf5SArnaldo Carvalho de Melo { 111af427bf5SArnaldo Carvalho de Melo struct map *prev, *curr; 11295011c60SArnaldo Carvalho de Melo struct rb_node *nd, *prevnd = rb_first(&self->maps[type]); 113af427bf5SArnaldo Carvalho de Melo 114af427bf5SArnaldo Carvalho de Melo if (prevnd == NULL) 115af427bf5SArnaldo Carvalho de Melo return; 116af427bf5SArnaldo Carvalho de Melo 117af427bf5SArnaldo Carvalho de Melo curr = rb_entry(prevnd, struct map, rb_node); 118af427bf5SArnaldo Carvalho de Melo 119af427bf5SArnaldo Carvalho de Melo for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) { 120af427bf5SArnaldo Carvalho de Melo prev = curr; 121af427bf5SArnaldo Carvalho de Melo curr = rb_entry(nd, struct map, rb_node); 122af427bf5SArnaldo Carvalho de Melo prev->end = curr->start - 1; 1232e538c4aSArnaldo Carvalho de Melo } 12490c83218SArnaldo Carvalho de Melo 12590c83218SArnaldo Carvalho de Melo /* 12690c83218SArnaldo Carvalho de Melo * We still haven't the actual symbols, so guess the 12790c83218SArnaldo Carvalho de Melo * last map final address. 12890c83218SArnaldo Carvalho de Melo */ 1299d1faba5SIan Munsie curr->end = ~0ULL; 130af427bf5SArnaldo Carvalho de Melo } 131af427bf5SArnaldo Carvalho de Melo 1329958e1f0SArnaldo Carvalho de Melo static void map_groups__fixup_end(struct map_groups *self) 13323ea4a3fSArnaldo Carvalho de Melo { 13423ea4a3fSArnaldo Carvalho de Melo int i; 13523ea4a3fSArnaldo Carvalho de Melo for (i = 0; i < MAP__NR_TYPES; ++i) 1369958e1f0SArnaldo Carvalho de Melo __map_groups__fixup_end(self, i); 13723ea4a3fSArnaldo Carvalho de Melo } 13823ea4a3fSArnaldo Carvalho de Melo 139c408fedfSArnaldo Carvalho de Melo static struct symbol *symbol__new(u64 start, u64 len, u8 binding, 140c408fedfSArnaldo Carvalho de Melo const char *name) 14186470930SIngo Molnar { 14286470930SIngo Molnar size_t namelen = strlen(name) + 1; 1435aab621bSArnaldo Carvalho de Melo struct symbol *self = calloc(1, (symbol_conf.priv_size + 1445aab621bSArnaldo Carvalho de Melo sizeof(*self) + namelen)); 14536479484SArnaldo Carvalho de Melo if (self == NULL) 14686470930SIngo Molnar return NULL; 14786470930SIngo Molnar 14875be6cf4SArnaldo Carvalho de Melo if (symbol_conf.priv_size) 14975be6cf4SArnaldo Carvalho de Melo self = ((void *)self) + symbol_conf.priv_size; 15036479484SArnaldo Carvalho de Melo 15186470930SIngo Molnar self->start = start; 1526cfcc53eSMike Galbraith self->end = len ? start + len - 1 : start; 153c408fedfSArnaldo Carvalho de Melo self->binding = binding; 154fefb0b94SArnaldo Carvalho de Melo self->namelen = namelen - 1; 155e4204992SArnaldo Carvalho de Melo 15629a9f66dSArnaldo Carvalho de Melo pr_debug4("%s: %s %#Lx-%#Lx\n", __func__, name, start, self->end); 157e4204992SArnaldo Carvalho de Melo 15886470930SIngo Molnar memcpy(self->name, name, namelen); 15986470930SIngo Molnar 16086470930SIngo Molnar return self; 16186470930SIngo Molnar } 16286470930SIngo Molnar 163628ada0cSArnaldo Carvalho de Melo void symbol__delete(struct symbol *self) 16486470930SIngo Molnar { 16575be6cf4SArnaldo Carvalho de Melo free(((void *)self) - symbol_conf.priv_size); 16686470930SIngo Molnar } 16786470930SIngo Molnar 16886470930SIngo Molnar static size_t symbol__fprintf(struct symbol *self, FILE *fp) 16986470930SIngo Molnar { 170c408fedfSArnaldo Carvalho de Melo return fprintf(fp, " %llx-%llx %c %s\n", 171c408fedfSArnaldo Carvalho de Melo self->start, self->end, 172c408fedfSArnaldo Carvalho de Melo self->binding == STB_GLOBAL ? 'g' : 173c408fedfSArnaldo Carvalho de Melo self->binding == STB_LOCAL ? 'l' : 'w', 174c408fedfSArnaldo Carvalho de Melo self->name); 17586470930SIngo Molnar } 17686470930SIngo Molnar 177b7cece76SArnaldo Carvalho de Melo void dso__set_long_name(struct dso *self, char *name) 178cfc10d3bSArnaldo Carvalho de Melo { 179ef6ae724SArnaldo Carvalho de Melo if (name == NULL) 180ef6ae724SArnaldo Carvalho de Melo return; 181cfc10d3bSArnaldo Carvalho de Melo self->long_name = name; 182cfc10d3bSArnaldo Carvalho de Melo self->long_name_len = strlen(name); 183cfc10d3bSArnaldo Carvalho de Melo } 184cfc10d3bSArnaldo Carvalho de Melo 185b63be8d7SArnaldo Carvalho de Melo static void dso__set_short_name(struct dso *self, const char *name) 186b63be8d7SArnaldo Carvalho de Melo { 187b63be8d7SArnaldo Carvalho de Melo if (name == NULL) 188b63be8d7SArnaldo Carvalho de Melo return; 189b63be8d7SArnaldo Carvalho de Melo self->short_name = name; 190b63be8d7SArnaldo Carvalho de Melo self->short_name_len = strlen(name); 191b63be8d7SArnaldo Carvalho de Melo } 192b63be8d7SArnaldo Carvalho de Melo 193cfc10d3bSArnaldo Carvalho de Melo static void dso__set_basename(struct dso *self) 194cfc10d3bSArnaldo Carvalho de Melo { 195b63be8d7SArnaldo Carvalho de Melo dso__set_short_name(self, basename(self->long_name)); 196cfc10d3bSArnaldo Carvalho de Melo } 197cfc10d3bSArnaldo Carvalho de Melo 19800a192b3SArnaldo Carvalho de Melo struct dso *dso__new(const char *name) 19986470930SIngo Molnar { 2005aab621bSArnaldo Carvalho de Melo struct dso *self = calloc(1, sizeof(*self) + strlen(name) + 1); 20186470930SIngo Molnar 20286470930SIngo Molnar if (self != NULL) { 2036a4694a4SArnaldo Carvalho de Melo int i; 20486470930SIngo Molnar strcpy(self->name, name); 205cfc10d3bSArnaldo Carvalho de Melo dso__set_long_name(self, self->name); 206b63be8d7SArnaldo Carvalho de Melo dso__set_short_name(self, self->name); 2076a4694a4SArnaldo Carvalho de Melo for (i = 0; i < MAP__NR_TYPES; ++i) 20879406cd7SArnaldo Carvalho de Melo self->symbols[i] = self->symbol_names[i] = RB_ROOT; 20952d422deSArnaldo Carvalho de Melo self->slen_calculated = 0; 21094cb9e38SArnaldo Carvalho de Melo self->origin = DSO__ORIG_NOT_FOUND; 2118d06367fSArnaldo Carvalho de Melo self->loaded = 0; 21279406cd7SArnaldo Carvalho de Melo self->sorted_by_name = 0; 2138d06367fSArnaldo Carvalho de Melo self->has_build_id = 0; 214a1645ce1SZhang, Yanmin self->kernel = DSO_TYPE_USER; 2150ab061cdSMasami Hiramatsu INIT_LIST_HEAD(&self->node); 21686470930SIngo Molnar } 21786470930SIngo Molnar 21886470930SIngo Molnar return self; 21986470930SIngo Molnar } 22086470930SIngo Molnar 221fcf1203aSArnaldo Carvalho de Melo static void symbols__delete(struct rb_root *self) 22286470930SIngo Molnar { 22386470930SIngo Molnar struct symbol *pos; 224fcf1203aSArnaldo Carvalho de Melo struct rb_node *next = rb_first(self); 22586470930SIngo Molnar 22686470930SIngo Molnar while (next) { 22786470930SIngo Molnar pos = rb_entry(next, struct symbol, rb_node); 22886470930SIngo Molnar next = rb_next(&pos->rb_node); 229fcf1203aSArnaldo Carvalho de Melo rb_erase(&pos->rb_node, self); 23000a192b3SArnaldo Carvalho de Melo symbol__delete(pos); 23186470930SIngo Molnar } 23286470930SIngo Molnar } 23386470930SIngo Molnar 23486470930SIngo Molnar void dso__delete(struct dso *self) 23586470930SIngo Molnar { 2366a4694a4SArnaldo Carvalho de Melo int i; 2376a4694a4SArnaldo Carvalho de Melo for (i = 0; i < MAP__NR_TYPES; ++i) 2386a4694a4SArnaldo Carvalho de Melo symbols__delete(&self->symbols[i]); 2396e406257SArnaldo Carvalho de Melo if (self->sname_alloc) 2406e406257SArnaldo Carvalho de Melo free((char *)self->short_name); 2416e406257SArnaldo Carvalho de Melo if (self->lname_alloc) 242439d473bSArnaldo Carvalho de Melo free(self->long_name); 24386470930SIngo Molnar free(self); 24486470930SIngo Molnar } 24586470930SIngo Molnar 2468d06367fSArnaldo Carvalho de Melo void dso__set_build_id(struct dso *self, void *build_id) 2478d06367fSArnaldo Carvalho de Melo { 2488d06367fSArnaldo Carvalho de Melo memcpy(self->build_id, build_id, sizeof(self->build_id)); 2498d06367fSArnaldo Carvalho de Melo self->has_build_id = 1; 2508d06367fSArnaldo Carvalho de Melo } 2518d06367fSArnaldo Carvalho de Melo 252fcf1203aSArnaldo Carvalho de Melo static void symbols__insert(struct rb_root *self, struct symbol *sym) 25386470930SIngo Molnar { 254fcf1203aSArnaldo Carvalho de Melo struct rb_node **p = &self->rb_node; 25586470930SIngo Molnar struct rb_node *parent = NULL; 2569cffa8d5SPaul Mackerras const u64 ip = sym->start; 25786470930SIngo Molnar struct symbol *s; 25886470930SIngo Molnar 25986470930SIngo Molnar while (*p != NULL) { 26086470930SIngo Molnar parent = *p; 26186470930SIngo Molnar s = rb_entry(parent, struct symbol, rb_node); 26286470930SIngo Molnar if (ip < s->start) 26386470930SIngo Molnar p = &(*p)->rb_left; 26486470930SIngo Molnar else 26586470930SIngo Molnar p = &(*p)->rb_right; 26686470930SIngo Molnar } 26786470930SIngo Molnar rb_link_node(&sym->rb_node, parent, p); 268fcf1203aSArnaldo Carvalho de Melo rb_insert_color(&sym->rb_node, self); 26986470930SIngo Molnar } 27086470930SIngo Molnar 271fcf1203aSArnaldo Carvalho de Melo static struct symbol *symbols__find(struct rb_root *self, u64 ip) 27286470930SIngo Molnar { 27386470930SIngo Molnar struct rb_node *n; 27486470930SIngo Molnar 27586470930SIngo Molnar if (self == NULL) 27686470930SIngo Molnar return NULL; 27786470930SIngo Molnar 278fcf1203aSArnaldo Carvalho de Melo n = self->rb_node; 27986470930SIngo Molnar 28086470930SIngo Molnar while (n) { 28186470930SIngo Molnar struct symbol *s = rb_entry(n, struct symbol, rb_node); 28286470930SIngo Molnar 28386470930SIngo Molnar if (ip < s->start) 28486470930SIngo Molnar n = n->rb_left; 28586470930SIngo Molnar else if (ip > s->end) 28686470930SIngo Molnar n = n->rb_right; 28786470930SIngo Molnar else 28886470930SIngo Molnar return s; 28986470930SIngo Molnar } 29086470930SIngo Molnar 29186470930SIngo Molnar return NULL; 29286470930SIngo Molnar } 29386470930SIngo Molnar 29479406cd7SArnaldo Carvalho de Melo struct symbol_name_rb_node { 29579406cd7SArnaldo Carvalho de Melo struct rb_node rb_node; 29679406cd7SArnaldo Carvalho de Melo struct symbol sym; 29779406cd7SArnaldo Carvalho de Melo }; 29879406cd7SArnaldo Carvalho de Melo 29979406cd7SArnaldo Carvalho de Melo static void symbols__insert_by_name(struct rb_root *self, struct symbol *sym) 30079406cd7SArnaldo Carvalho de Melo { 30179406cd7SArnaldo Carvalho de Melo struct rb_node **p = &self->rb_node; 30279406cd7SArnaldo Carvalho de Melo struct rb_node *parent = NULL; 30302a9d037SRabin Vincent struct symbol_name_rb_node *symn, *s; 30402a9d037SRabin Vincent 30502a9d037SRabin Vincent symn = container_of(sym, struct symbol_name_rb_node, sym); 30679406cd7SArnaldo Carvalho de Melo 30779406cd7SArnaldo Carvalho de Melo while (*p != NULL) { 30879406cd7SArnaldo Carvalho de Melo parent = *p; 30979406cd7SArnaldo Carvalho de Melo s = rb_entry(parent, struct symbol_name_rb_node, rb_node); 31079406cd7SArnaldo Carvalho de Melo if (strcmp(sym->name, s->sym.name) < 0) 31179406cd7SArnaldo Carvalho de Melo p = &(*p)->rb_left; 31279406cd7SArnaldo Carvalho de Melo else 31379406cd7SArnaldo Carvalho de Melo p = &(*p)->rb_right; 31479406cd7SArnaldo Carvalho de Melo } 31579406cd7SArnaldo Carvalho de Melo rb_link_node(&symn->rb_node, parent, p); 31679406cd7SArnaldo Carvalho de Melo rb_insert_color(&symn->rb_node, self); 31779406cd7SArnaldo Carvalho de Melo } 31879406cd7SArnaldo Carvalho de Melo 31979406cd7SArnaldo Carvalho de Melo static void symbols__sort_by_name(struct rb_root *self, struct rb_root *source) 32079406cd7SArnaldo Carvalho de Melo { 32179406cd7SArnaldo Carvalho de Melo struct rb_node *nd; 32279406cd7SArnaldo Carvalho de Melo 32379406cd7SArnaldo Carvalho de Melo for (nd = rb_first(source); nd; nd = rb_next(nd)) { 32479406cd7SArnaldo Carvalho de Melo struct symbol *pos = rb_entry(nd, struct symbol, rb_node); 32579406cd7SArnaldo Carvalho de Melo symbols__insert_by_name(self, pos); 32679406cd7SArnaldo Carvalho de Melo } 32779406cd7SArnaldo Carvalho de Melo } 32879406cd7SArnaldo Carvalho de Melo 32979406cd7SArnaldo Carvalho de Melo static struct symbol *symbols__find_by_name(struct rb_root *self, const char *name) 33079406cd7SArnaldo Carvalho de Melo { 33179406cd7SArnaldo Carvalho de Melo struct rb_node *n; 33279406cd7SArnaldo Carvalho de Melo 33379406cd7SArnaldo Carvalho de Melo if (self == NULL) 33479406cd7SArnaldo Carvalho de Melo return NULL; 33579406cd7SArnaldo Carvalho de Melo 33679406cd7SArnaldo Carvalho de Melo n = self->rb_node; 33779406cd7SArnaldo Carvalho de Melo 33879406cd7SArnaldo Carvalho de Melo while (n) { 33979406cd7SArnaldo Carvalho de Melo struct symbol_name_rb_node *s; 34079406cd7SArnaldo Carvalho de Melo int cmp; 34179406cd7SArnaldo Carvalho de Melo 34279406cd7SArnaldo Carvalho de Melo s = rb_entry(n, struct symbol_name_rb_node, rb_node); 34379406cd7SArnaldo Carvalho de Melo cmp = strcmp(name, s->sym.name); 34479406cd7SArnaldo Carvalho de Melo 34579406cd7SArnaldo Carvalho de Melo if (cmp < 0) 34679406cd7SArnaldo Carvalho de Melo n = n->rb_left; 34779406cd7SArnaldo Carvalho de Melo else if (cmp > 0) 34879406cd7SArnaldo Carvalho de Melo n = n->rb_right; 34979406cd7SArnaldo Carvalho de Melo else 35079406cd7SArnaldo Carvalho de Melo return &s->sym; 35179406cd7SArnaldo Carvalho de Melo } 35279406cd7SArnaldo Carvalho de Melo 35379406cd7SArnaldo Carvalho de Melo return NULL; 35479406cd7SArnaldo Carvalho de Melo } 35579406cd7SArnaldo Carvalho de Melo 35679406cd7SArnaldo Carvalho de Melo struct symbol *dso__find_symbol(struct dso *self, 35779406cd7SArnaldo Carvalho de Melo enum map_type type, u64 addr) 358fcf1203aSArnaldo Carvalho de Melo { 3596a4694a4SArnaldo Carvalho de Melo return symbols__find(&self->symbols[type], addr); 360fcf1203aSArnaldo Carvalho de Melo } 361fcf1203aSArnaldo Carvalho de Melo 36279406cd7SArnaldo Carvalho de Melo struct symbol *dso__find_symbol_by_name(struct dso *self, enum map_type type, 36379406cd7SArnaldo Carvalho de Melo const char *name) 36479406cd7SArnaldo Carvalho de Melo { 36579406cd7SArnaldo Carvalho de Melo return symbols__find_by_name(&self->symbol_names[type], name); 36679406cd7SArnaldo Carvalho de Melo } 36779406cd7SArnaldo Carvalho de Melo 36879406cd7SArnaldo Carvalho de Melo void dso__sort_by_name(struct dso *self, enum map_type type) 36979406cd7SArnaldo Carvalho de Melo { 37079406cd7SArnaldo Carvalho de Melo dso__set_sorted_by_name(self, type); 37179406cd7SArnaldo Carvalho de Melo return symbols__sort_by_name(&self->symbol_names[type], 37279406cd7SArnaldo Carvalho de Melo &self->symbols[type]); 37379406cd7SArnaldo Carvalho de Melo } 37479406cd7SArnaldo Carvalho de Melo 375ef12a141SArnaldo Carvalho de Melo int build_id__sprintf(const u8 *self, int len, char *bf) 3768d06367fSArnaldo Carvalho de Melo { 3778d06367fSArnaldo Carvalho de Melo char *bid = bf; 378ef12a141SArnaldo Carvalho de Melo const u8 *raw = self; 3798d06367fSArnaldo Carvalho de Melo int i; 3808d06367fSArnaldo Carvalho de Melo 3818d06367fSArnaldo Carvalho de Melo for (i = 0; i < len; ++i) { 3828d06367fSArnaldo Carvalho de Melo sprintf(bid, "%02x", *raw); 3838d06367fSArnaldo Carvalho de Melo ++raw; 3848d06367fSArnaldo Carvalho de Melo bid += 2; 3858d06367fSArnaldo Carvalho de Melo } 3868d06367fSArnaldo Carvalho de Melo 3878d06367fSArnaldo Carvalho de Melo return raw - self; 3888d06367fSArnaldo Carvalho de Melo } 3898d06367fSArnaldo Carvalho de Melo 3909e03eb2dSArnaldo Carvalho de Melo size_t dso__fprintf_buildid(struct dso *self, FILE *fp) 39186470930SIngo Molnar { 3928d06367fSArnaldo Carvalho de Melo char sbuild_id[BUILD_ID_SIZE * 2 + 1]; 3938d06367fSArnaldo Carvalho de Melo 3948d06367fSArnaldo Carvalho de Melo build_id__sprintf(self->build_id, sizeof(self->build_id), sbuild_id); 3959e03eb2dSArnaldo Carvalho de Melo return fprintf(fp, "%s", sbuild_id); 3969e03eb2dSArnaldo Carvalho de Melo } 3979e03eb2dSArnaldo Carvalho de Melo 39890f18e63SSrikar Dronamraju size_t dso__fprintf_symbols_by_name(struct dso *self, enum map_type type, FILE *fp) 39990f18e63SSrikar Dronamraju { 40090f18e63SSrikar Dronamraju size_t ret = 0; 40190f18e63SSrikar Dronamraju struct rb_node *nd; 40290f18e63SSrikar Dronamraju struct symbol_name_rb_node *pos; 40390f18e63SSrikar Dronamraju 40490f18e63SSrikar Dronamraju for (nd = rb_first(&self->symbol_names[type]); nd; nd = rb_next(nd)) { 40590f18e63SSrikar Dronamraju pos = rb_entry(nd, struct symbol_name_rb_node, rb_node); 40690f18e63SSrikar Dronamraju fprintf(fp, "%s\n", pos->sym.name); 40790f18e63SSrikar Dronamraju } 40890f18e63SSrikar Dronamraju 40990f18e63SSrikar Dronamraju return ret; 41090f18e63SSrikar Dronamraju } 41190f18e63SSrikar Dronamraju 41295011c60SArnaldo Carvalho de Melo size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp) 4139e03eb2dSArnaldo Carvalho de Melo { 4149e03eb2dSArnaldo Carvalho de Melo struct rb_node *nd; 4159e03eb2dSArnaldo Carvalho de Melo size_t ret = fprintf(fp, "dso: %s (", self->short_name); 4169e03eb2dSArnaldo Carvalho de Melo 4173846df2eSArnaldo Carvalho de Melo if (self->short_name != self->long_name) 4183846df2eSArnaldo Carvalho de Melo ret += fprintf(fp, "%s, ", self->long_name); 4193846df2eSArnaldo Carvalho de Melo ret += fprintf(fp, "%s, %sloaded, ", map_type__name[type], 4203846df2eSArnaldo Carvalho de Melo self->loaded ? "" : "NOT "); 4219e03eb2dSArnaldo Carvalho de Melo ret += dso__fprintf_buildid(self, fp); 4226a4694a4SArnaldo Carvalho de Melo ret += fprintf(fp, ")\n"); 42395011c60SArnaldo Carvalho de Melo for (nd = rb_first(&self->symbols[type]); nd; nd = rb_next(nd)) { 42486470930SIngo Molnar struct symbol *pos = rb_entry(nd, struct symbol, rb_node); 42586470930SIngo Molnar ret += symbol__fprintf(pos, fp); 42686470930SIngo Molnar } 42786470930SIngo Molnar 42886470930SIngo Molnar return ret; 42986470930SIngo Molnar } 43086470930SIngo Molnar 4319e201442SArnaldo Carvalho de Melo int kallsyms__parse(const char *filename, void *arg, 4329e201442SArnaldo Carvalho de Melo int (*process_symbol)(void *arg, const char *name, 4333b01a413SArnaldo Carvalho de Melo char type, u64 start, u64 end)) 43486470930SIngo Molnar { 43586470930SIngo Molnar char *line = NULL; 43686470930SIngo Molnar size_t n; 4373b01a413SArnaldo Carvalho de Melo int err = -1; 4383b01a413SArnaldo Carvalho de Melo u64 prev_start = 0; 4393b01a413SArnaldo Carvalho de Melo char prev_symbol_type = 0; 4403b01a413SArnaldo Carvalho de Melo char *prev_symbol_name; 4419e201442SArnaldo Carvalho de Melo FILE *file = fopen(filename, "r"); 44286470930SIngo Molnar 44386470930SIngo Molnar if (file == NULL) 44486470930SIngo Molnar goto out_failure; 44586470930SIngo Molnar 4463b01a413SArnaldo Carvalho de Melo prev_symbol_name = malloc(KSYM_NAME_LEN); 4473b01a413SArnaldo Carvalho de Melo if (prev_symbol_name == NULL) 4483b01a413SArnaldo Carvalho de Melo goto out_close; 4493b01a413SArnaldo Carvalho de Melo 4503b01a413SArnaldo Carvalho de Melo err = 0; 4513b01a413SArnaldo Carvalho de Melo 45286470930SIngo Molnar while (!feof(file)) { 4539cffa8d5SPaul Mackerras u64 start; 45486470930SIngo Molnar int line_len, len; 45586470930SIngo Molnar char symbol_type; 4562e538c4aSArnaldo Carvalho de Melo char *symbol_name; 45786470930SIngo Molnar 45886470930SIngo Molnar line_len = getline(&line, &n, file); 459a1645ce1SZhang, Yanmin if (line_len < 0 || !line) 46086470930SIngo Molnar break; 46186470930SIngo Molnar 46286470930SIngo Molnar line[--line_len] = '\0'; /* \n */ 46386470930SIngo Molnar 46486470930SIngo Molnar len = hex2u64(line, &start); 46586470930SIngo Molnar 46686470930SIngo Molnar len++; 46786470930SIngo Molnar if (len + 2 >= line_len) 46886470930SIngo Molnar continue; 46986470930SIngo Molnar 47086470930SIngo Molnar symbol_type = toupper(line[len]); 4713b01a413SArnaldo Carvalho de Melo len += 2; 4723b01a413SArnaldo Carvalho de Melo symbol_name = line + len; 4733b01a413SArnaldo Carvalho de Melo len = line_len - len; 474682b335aSArnaldo Carvalho de Melo 4753b01a413SArnaldo Carvalho de Melo if (len >= KSYM_NAME_LEN) { 4763b01a413SArnaldo Carvalho de Melo err = -1; 4773b01a413SArnaldo Carvalho de Melo break; 4783b01a413SArnaldo Carvalho de Melo } 4793b01a413SArnaldo Carvalho de Melo 4803b01a413SArnaldo Carvalho de Melo if (prev_symbol_type) { 4813b01a413SArnaldo Carvalho de Melo u64 end = start; 4823b01a413SArnaldo Carvalho de Melo if (end != prev_start) 4833b01a413SArnaldo Carvalho de Melo --end; 4843b01a413SArnaldo Carvalho de Melo err = process_symbol(arg, prev_symbol_name, 4853b01a413SArnaldo Carvalho de Melo prev_symbol_type, prev_start, end); 486682b335aSArnaldo Carvalho de Melo if (err) 487682b335aSArnaldo Carvalho de Melo break; 488682b335aSArnaldo Carvalho de Melo } 489682b335aSArnaldo Carvalho de Melo 4903b01a413SArnaldo Carvalho de Melo memcpy(prev_symbol_name, symbol_name, len + 1); 4913b01a413SArnaldo Carvalho de Melo prev_symbol_type = symbol_type; 4923b01a413SArnaldo Carvalho de Melo prev_start = start; 4933b01a413SArnaldo Carvalho de Melo } 4943b01a413SArnaldo Carvalho de Melo 4953b01a413SArnaldo Carvalho de Melo free(prev_symbol_name); 496682b335aSArnaldo Carvalho de Melo free(line); 4973b01a413SArnaldo Carvalho de Melo out_close: 498682b335aSArnaldo Carvalho de Melo fclose(file); 499682b335aSArnaldo Carvalho de Melo return err; 500682b335aSArnaldo Carvalho de Melo 501682b335aSArnaldo Carvalho de Melo out_failure: 502682b335aSArnaldo Carvalho de Melo return -1; 503682b335aSArnaldo Carvalho de Melo } 504682b335aSArnaldo Carvalho de Melo 505682b335aSArnaldo Carvalho de Melo struct process_kallsyms_args { 506682b335aSArnaldo Carvalho de Melo struct map *map; 507682b335aSArnaldo Carvalho de Melo struct dso *dso; 508682b335aSArnaldo Carvalho de Melo }; 509682b335aSArnaldo Carvalho de Melo 510c408fedfSArnaldo Carvalho de Melo static u8 kallsyms2elf_type(char type) 511c408fedfSArnaldo Carvalho de Melo { 512c408fedfSArnaldo Carvalho de Melo if (type == 'W') 513c408fedfSArnaldo Carvalho de Melo return STB_WEAK; 514c408fedfSArnaldo Carvalho de Melo 515c408fedfSArnaldo Carvalho de Melo return isupper(type) ? STB_GLOBAL : STB_LOCAL; 516c408fedfSArnaldo Carvalho de Melo } 517c408fedfSArnaldo Carvalho de Melo 518682b335aSArnaldo Carvalho de Melo static int map__process_kallsym_symbol(void *arg, const char *name, 5193b01a413SArnaldo Carvalho de Melo char type, u64 start, u64 end) 520682b335aSArnaldo Carvalho de Melo { 521682b335aSArnaldo Carvalho de Melo struct symbol *sym; 522682b335aSArnaldo Carvalho de Melo struct process_kallsyms_args *a = arg; 523682b335aSArnaldo Carvalho de Melo struct rb_root *root = &a->dso->symbols[a->map->type]; 524682b335aSArnaldo Carvalho de Melo 525682b335aSArnaldo Carvalho de Melo if (!symbol_type__is_a(type, a->map->type)) 526682b335aSArnaldo Carvalho de Melo return 0; 527682b335aSArnaldo Carvalho de Melo 5283b01a413SArnaldo Carvalho de Melo sym = symbol__new(start, end - start + 1, 5293b01a413SArnaldo Carvalho de Melo kallsyms2elf_type(type), name); 5302e538c4aSArnaldo Carvalho de Melo if (sym == NULL) 531682b335aSArnaldo Carvalho de Melo return -ENOMEM; 53282164161SArnaldo Carvalho de Melo /* 53382164161SArnaldo Carvalho de Melo * We will pass the symbols to the filter later, in 5344e06255fSArnaldo Carvalho de Melo * map__split_kallsyms, when we have split the maps per module 53582164161SArnaldo Carvalho de Melo */ 5364e06255fSArnaldo Carvalho de Melo symbols__insert(root, sym); 537a1645ce1SZhang, Yanmin 538682b335aSArnaldo Carvalho de Melo return 0; 5392e538c4aSArnaldo Carvalho de Melo } 5402e538c4aSArnaldo Carvalho de Melo 541682b335aSArnaldo Carvalho de Melo /* 542682b335aSArnaldo Carvalho de Melo * Loads the function entries in /proc/kallsyms into kernel_map->dso, 543682b335aSArnaldo Carvalho de Melo * so that we can in the next step set the symbol ->end address and then 544682b335aSArnaldo Carvalho de Melo * call kernel_maps__split_kallsyms. 545682b335aSArnaldo Carvalho de Melo */ 5469e201442SArnaldo Carvalho de Melo static int dso__load_all_kallsyms(struct dso *self, const char *filename, 5479e201442SArnaldo Carvalho de Melo struct map *map) 548682b335aSArnaldo Carvalho de Melo { 549682b335aSArnaldo Carvalho de Melo struct process_kallsyms_args args = { .map = map, .dso = self, }; 5509e201442SArnaldo Carvalho de Melo return kallsyms__parse(filename, &args, map__process_kallsym_symbol); 5512e538c4aSArnaldo Carvalho de Melo } 5522e538c4aSArnaldo Carvalho de Melo 5532e538c4aSArnaldo Carvalho de Melo /* 5542e538c4aSArnaldo Carvalho de Melo * Split the symbols into maps, making sure there are no overlaps, i.e. the 5552e538c4aSArnaldo Carvalho de Melo * kernel range is broken in several maps, named [kernel].N, as we don't have 5562e538c4aSArnaldo Carvalho de Melo * the original ELF section names vmlinux have. 5572e538c4aSArnaldo Carvalho de Melo */ 5589958e1f0SArnaldo Carvalho de Melo static int dso__split_kallsyms(struct dso *self, struct map *map, 5599de89fe7SArnaldo Carvalho de Melo symbol_filter_t filter) 5602e538c4aSArnaldo Carvalho de Melo { 5619de89fe7SArnaldo Carvalho de Melo struct map_groups *kmaps = map__kmap(map)->kmaps; 56223346f21SArnaldo Carvalho de Melo struct machine *machine = kmaps->machine; 5634e06255fSArnaldo Carvalho de Melo struct map *curr_map = map; 5642e538c4aSArnaldo Carvalho de Melo struct symbol *pos; 5658a953312SArnaldo Carvalho de Melo int count = 0, moved = 0; 5664e06255fSArnaldo Carvalho de Melo struct rb_root *root = &self->symbols[map->type]; 5674e06255fSArnaldo Carvalho de Melo struct rb_node *next = rb_first(root); 5682e538c4aSArnaldo Carvalho de Melo int kernel_range = 0; 5692e538c4aSArnaldo Carvalho de Melo 5702e538c4aSArnaldo Carvalho de Melo while (next) { 5712e538c4aSArnaldo Carvalho de Melo char *module; 5722e538c4aSArnaldo Carvalho de Melo 5732e538c4aSArnaldo Carvalho de Melo pos = rb_entry(next, struct symbol, rb_node); 5742e538c4aSArnaldo Carvalho de Melo next = rb_next(&pos->rb_node); 5752e538c4aSArnaldo Carvalho de Melo 5762e538c4aSArnaldo Carvalho de Melo module = strchr(pos->name, '\t'); 5772e538c4aSArnaldo Carvalho de Melo if (module) { 57875be6cf4SArnaldo Carvalho de Melo if (!symbol_conf.use_modules) 5791de8e245SArnaldo Carvalho de Melo goto discard_symbol; 5801de8e245SArnaldo Carvalho de Melo 5812e538c4aSArnaldo Carvalho de Melo *module++ = '\0'; 5822e538c4aSArnaldo Carvalho de Melo 583b7cece76SArnaldo Carvalho de Melo if (strcmp(curr_map->dso->short_name, module)) { 584a1645ce1SZhang, Yanmin if (curr_map != map && 585a1645ce1SZhang, Yanmin self->kernel == DSO_TYPE_GUEST_KERNEL && 58623346f21SArnaldo Carvalho de Melo machine__is_default_guest(machine)) { 587a1645ce1SZhang, Yanmin /* 588a1645ce1SZhang, Yanmin * We assume all symbols of a module are 589a1645ce1SZhang, Yanmin * continuous in * kallsyms, so curr_map 590a1645ce1SZhang, Yanmin * points to a module and all its 591a1645ce1SZhang, Yanmin * symbols are in its kmap. Mark it as 592a1645ce1SZhang, Yanmin * loaded. 593a1645ce1SZhang, Yanmin */ 594a1645ce1SZhang, Yanmin dso__set_loaded(curr_map->dso, 595a1645ce1SZhang, Yanmin curr_map->type); 596af427bf5SArnaldo Carvalho de Melo } 597b7cece76SArnaldo Carvalho de Melo 598a1645ce1SZhang, Yanmin curr_map = map_groups__find_by_name(kmaps, 599a1645ce1SZhang, Yanmin map->type, module); 600a1645ce1SZhang, Yanmin if (curr_map == NULL) { 6012f51903bSArnaldo Carvalho de Melo pr_debug("%s/proc/{kallsyms,modules} " 602a1645ce1SZhang, Yanmin "inconsistency while looking " 603a1645ce1SZhang, Yanmin "for \"%s\" module!\n", 60423346f21SArnaldo Carvalho de Melo machine->root_dir, module); 605a1645ce1SZhang, Yanmin curr_map = map; 606a1645ce1SZhang, Yanmin goto discard_symbol; 607a1645ce1SZhang, Yanmin } 608a1645ce1SZhang, Yanmin 609a1645ce1SZhang, Yanmin if (curr_map->dso->loaded && 61023346f21SArnaldo Carvalho de Melo !machine__is_default_guest(machine)) 611b7cece76SArnaldo Carvalho de Melo goto discard_symbol; 612af427bf5SArnaldo Carvalho de Melo } 61386470930SIngo Molnar /* 6142e538c4aSArnaldo Carvalho de Melo * So that we look just like we get from .ko files, 6152e538c4aSArnaldo Carvalho de Melo * i.e. not prelinked, relative to map->start. 61686470930SIngo Molnar */ 6174e06255fSArnaldo Carvalho de Melo pos->start = curr_map->map_ip(curr_map, pos->start); 6184e06255fSArnaldo Carvalho de Melo pos->end = curr_map->map_ip(curr_map, pos->end); 6194e06255fSArnaldo Carvalho de Melo } else if (curr_map != map) { 6202e538c4aSArnaldo Carvalho de Melo char dso_name[PATH_MAX]; 6212e538c4aSArnaldo Carvalho de Melo struct dso *dso; 62286470930SIngo Molnar 6238a953312SArnaldo Carvalho de Melo if (count == 0) { 6248a953312SArnaldo Carvalho de Melo curr_map = map; 6258a953312SArnaldo Carvalho de Melo goto filter_symbol; 6268a953312SArnaldo Carvalho de Melo } 6278a953312SArnaldo Carvalho de Melo 628a1645ce1SZhang, Yanmin if (self->kernel == DSO_TYPE_GUEST_KERNEL) 629a1645ce1SZhang, Yanmin snprintf(dso_name, sizeof(dso_name), 630a1645ce1SZhang, Yanmin "[guest.kernel].%d", 631a1645ce1SZhang, Yanmin kernel_range++); 632a1645ce1SZhang, Yanmin else 633a1645ce1SZhang, Yanmin snprintf(dso_name, sizeof(dso_name), 634a1645ce1SZhang, Yanmin "[kernel].%d", 6352e538c4aSArnaldo Carvalho de Melo kernel_range++); 63686470930SIngo Molnar 63700a192b3SArnaldo Carvalho de Melo dso = dso__new(dso_name); 6382e538c4aSArnaldo Carvalho de Melo if (dso == NULL) 6392e538c4aSArnaldo Carvalho de Melo return -1; 6402e538c4aSArnaldo Carvalho de Melo 641a1645ce1SZhang, Yanmin dso->kernel = self->kernel; 642a1645ce1SZhang, Yanmin 6434e06255fSArnaldo Carvalho de Melo curr_map = map__new2(pos->start, dso, map->type); 64437fe5fcbSZhang, Yanmin if (curr_map == NULL) { 6452e538c4aSArnaldo Carvalho de Melo dso__delete(dso); 6462e538c4aSArnaldo Carvalho de Melo return -1; 6472e538c4aSArnaldo Carvalho de Melo } 6482e538c4aSArnaldo Carvalho de Melo 6494e06255fSArnaldo Carvalho de Melo curr_map->map_ip = curr_map->unmap_ip = identity__map_ip; 6509de89fe7SArnaldo Carvalho de Melo map_groups__insert(kmaps, curr_map); 6512e538c4aSArnaldo Carvalho de Melo ++kernel_range; 6522e538c4aSArnaldo Carvalho de Melo } 6538a953312SArnaldo Carvalho de Melo filter_symbol: 6544e06255fSArnaldo Carvalho de Melo if (filter && filter(curr_map, pos)) { 6551de8e245SArnaldo Carvalho de Melo discard_symbol: rb_erase(&pos->rb_node, root); 65600a192b3SArnaldo Carvalho de Melo symbol__delete(pos); 6572e538c4aSArnaldo Carvalho de Melo } else { 6584e06255fSArnaldo Carvalho de Melo if (curr_map != map) { 6594e06255fSArnaldo Carvalho de Melo rb_erase(&pos->rb_node, root); 6604e06255fSArnaldo Carvalho de Melo symbols__insert(&curr_map->dso->symbols[curr_map->type], pos); 6618a953312SArnaldo Carvalho de Melo ++moved; 6628a953312SArnaldo Carvalho de Melo } else 6638a953312SArnaldo Carvalho de Melo ++count; 6649974f496SMike Galbraith } 66586470930SIngo Molnar } 66686470930SIngo Molnar 667a1645ce1SZhang, Yanmin if (curr_map != map && 668a1645ce1SZhang, Yanmin self->kernel == DSO_TYPE_GUEST_KERNEL && 66923346f21SArnaldo Carvalho de Melo machine__is_default_guest(kmaps->machine)) { 670a1645ce1SZhang, Yanmin dso__set_loaded(curr_map->dso, curr_map->type); 671a1645ce1SZhang, Yanmin } 672a1645ce1SZhang, Yanmin 6738a953312SArnaldo Carvalho de Melo return count + moved; 67486470930SIngo Molnar } 67586470930SIngo Molnar 6769de89fe7SArnaldo Carvalho de Melo int dso__load_kallsyms(struct dso *self, const char *filename, 6779de89fe7SArnaldo Carvalho de Melo struct map *map, symbol_filter_t filter) 6782e538c4aSArnaldo Carvalho de Melo { 6799e201442SArnaldo Carvalho de Melo if (dso__load_all_kallsyms(self, filename, map) < 0) 6802e538c4aSArnaldo Carvalho de Melo return -1; 6812e538c4aSArnaldo Carvalho de Melo 682a1645ce1SZhang, Yanmin if (self->kernel == DSO_TYPE_GUEST_KERNEL) 683a1645ce1SZhang, Yanmin self->origin = DSO__ORIG_GUEST_KERNEL; 684a1645ce1SZhang, Yanmin else 6854e06255fSArnaldo Carvalho de Melo self->origin = DSO__ORIG_KERNEL; 6862e538c4aSArnaldo Carvalho de Melo 6879de89fe7SArnaldo Carvalho de Melo return dso__split_kallsyms(self, map, filter); 688af427bf5SArnaldo Carvalho de Melo } 689af427bf5SArnaldo Carvalho de Melo 690439d473bSArnaldo Carvalho de Melo static int dso__load_perf_map(struct dso *self, struct map *map, 6916beba7adSArnaldo Carvalho de Melo symbol_filter_t filter) 69280d496beSPekka Enberg { 69380d496beSPekka Enberg char *line = NULL; 69480d496beSPekka Enberg size_t n; 69580d496beSPekka Enberg FILE *file; 69680d496beSPekka Enberg int nr_syms = 0; 69780d496beSPekka Enberg 698439d473bSArnaldo Carvalho de Melo file = fopen(self->long_name, "r"); 69980d496beSPekka Enberg if (file == NULL) 70080d496beSPekka Enberg goto out_failure; 70180d496beSPekka Enberg 70280d496beSPekka Enberg while (!feof(file)) { 7039cffa8d5SPaul Mackerras u64 start, size; 70480d496beSPekka Enberg struct symbol *sym; 70580d496beSPekka Enberg int line_len, len; 70680d496beSPekka Enberg 70780d496beSPekka Enberg line_len = getline(&line, &n, file); 70880d496beSPekka Enberg if (line_len < 0) 70980d496beSPekka Enberg break; 71080d496beSPekka Enberg 71180d496beSPekka Enberg if (!line) 71280d496beSPekka Enberg goto out_failure; 71380d496beSPekka Enberg 71480d496beSPekka Enberg line[--line_len] = '\0'; /* \n */ 71580d496beSPekka Enberg 71680d496beSPekka Enberg len = hex2u64(line, &start); 71780d496beSPekka Enberg 71880d496beSPekka Enberg len++; 71980d496beSPekka Enberg if (len + 2 >= line_len) 72080d496beSPekka Enberg continue; 72180d496beSPekka Enberg 72280d496beSPekka Enberg len += hex2u64(line + len, &size); 72380d496beSPekka Enberg 72480d496beSPekka Enberg len++; 72580d496beSPekka Enberg if (len + 2 >= line_len) 72680d496beSPekka Enberg continue; 72780d496beSPekka Enberg 728c408fedfSArnaldo Carvalho de Melo sym = symbol__new(start, size, STB_GLOBAL, line + len); 72980d496beSPekka Enberg 73080d496beSPekka Enberg if (sym == NULL) 73180d496beSPekka Enberg goto out_delete_line; 73280d496beSPekka Enberg 733439d473bSArnaldo Carvalho de Melo if (filter && filter(map, sym)) 73400a192b3SArnaldo Carvalho de Melo symbol__delete(sym); 73580d496beSPekka Enberg else { 7366a4694a4SArnaldo Carvalho de Melo symbols__insert(&self->symbols[map->type], sym); 73780d496beSPekka Enberg nr_syms++; 73880d496beSPekka Enberg } 73980d496beSPekka Enberg } 74080d496beSPekka Enberg 74180d496beSPekka Enberg free(line); 74280d496beSPekka Enberg fclose(file); 74380d496beSPekka Enberg 74480d496beSPekka Enberg return nr_syms; 74580d496beSPekka Enberg 74680d496beSPekka Enberg out_delete_line: 74780d496beSPekka Enberg free(line); 74880d496beSPekka Enberg out_failure: 74980d496beSPekka Enberg return -1; 75080d496beSPekka Enberg } 75180d496beSPekka Enberg 75286470930SIngo Molnar /** 75386470930SIngo Molnar * elf_symtab__for_each_symbol - iterate thru all the symbols 75486470930SIngo Molnar * 75586470930SIngo Molnar * @self: struct elf_symtab instance to iterate 75683a0944fSIngo Molnar * @idx: uint32_t idx 75786470930SIngo Molnar * @sym: GElf_Sym iterator 75886470930SIngo Molnar */ 75983a0944fSIngo Molnar #define elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) \ 76083a0944fSIngo Molnar for (idx = 0, gelf_getsym(syms, idx, &sym);\ 76183a0944fSIngo Molnar idx < nr_syms; \ 76283a0944fSIngo Molnar idx++, gelf_getsym(syms, idx, &sym)) 76386470930SIngo Molnar 76486470930SIngo Molnar static inline uint8_t elf_sym__type(const GElf_Sym *sym) 76586470930SIngo Molnar { 76686470930SIngo Molnar return GELF_ST_TYPE(sym->st_info); 76786470930SIngo Molnar } 76886470930SIngo Molnar 76986470930SIngo Molnar static inline int elf_sym__is_function(const GElf_Sym *sym) 77086470930SIngo Molnar { 77186470930SIngo Molnar return elf_sym__type(sym) == STT_FUNC && 77286470930SIngo Molnar sym->st_name != 0 && 77381833130SArnaldo Carvalho de Melo sym->st_shndx != SHN_UNDEF; 77486470930SIngo Molnar } 77586470930SIngo Molnar 776f1dfa0b1SArnaldo Carvalho de Melo static inline bool elf_sym__is_object(const GElf_Sym *sym) 777f1dfa0b1SArnaldo Carvalho de Melo { 778f1dfa0b1SArnaldo Carvalho de Melo return elf_sym__type(sym) == STT_OBJECT && 779f1dfa0b1SArnaldo Carvalho de Melo sym->st_name != 0 && 780f1dfa0b1SArnaldo Carvalho de Melo sym->st_shndx != SHN_UNDEF; 781f1dfa0b1SArnaldo Carvalho de Melo } 782f1dfa0b1SArnaldo Carvalho de Melo 7836cfcc53eSMike Galbraith static inline int elf_sym__is_label(const GElf_Sym *sym) 7846cfcc53eSMike Galbraith { 7856cfcc53eSMike Galbraith return elf_sym__type(sym) == STT_NOTYPE && 7866cfcc53eSMike Galbraith sym->st_name != 0 && 7876cfcc53eSMike Galbraith sym->st_shndx != SHN_UNDEF && 7886cfcc53eSMike Galbraith sym->st_shndx != SHN_ABS; 7896cfcc53eSMike Galbraith } 7906cfcc53eSMike Galbraith 7916cfcc53eSMike Galbraith static inline const char *elf_sec__name(const GElf_Shdr *shdr, 7926cfcc53eSMike Galbraith const Elf_Data *secstrs) 7936cfcc53eSMike Galbraith { 7946cfcc53eSMike Galbraith return secstrs->d_buf + shdr->sh_name; 7956cfcc53eSMike Galbraith } 7966cfcc53eSMike Galbraith 7976cfcc53eSMike Galbraith static inline int elf_sec__is_text(const GElf_Shdr *shdr, 7986cfcc53eSMike Galbraith const Elf_Data *secstrs) 7996cfcc53eSMike Galbraith { 8006cfcc53eSMike Galbraith return strstr(elf_sec__name(shdr, secstrs), "text") != NULL; 8016cfcc53eSMike Galbraith } 8026cfcc53eSMike Galbraith 803f1dfa0b1SArnaldo Carvalho de Melo static inline bool elf_sec__is_data(const GElf_Shdr *shdr, 804f1dfa0b1SArnaldo Carvalho de Melo const Elf_Data *secstrs) 805f1dfa0b1SArnaldo Carvalho de Melo { 806f1dfa0b1SArnaldo Carvalho de Melo return strstr(elf_sec__name(shdr, secstrs), "data") != NULL; 807f1dfa0b1SArnaldo Carvalho de Melo } 808f1dfa0b1SArnaldo Carvalho de Melo 80986470930SIngo Molnar static inline const char *elf_sym__name(const GElf_Sym *sym, 81086470930SIngo Molnar const Elf_Data *symstrs) 81186470930SIngo Molnar { 81286470930SIngo Molnar return symstrs->d_buf + sym->st_name; 81386470930SIngo Molnar } 81486470930SIngo Molnar 81586470930SIngo Molnar static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, 81686470930SIngo Molnar GElf_Shdr *shp, const char *name, 81783a0944fSIngo Molnar size_t *idx) 81886470930SIngo Molnar { 81986470930SIngo Molnar Elf_Scn *sec = NULL; 82086470930SIngo Molnar size_t cnt = 1; 82186470930SIngo Molnar 82286470930SIngo Molnar while ((sec = elf_nextscn(elf, sec)) != NULL) { 82386470930SIngo Molnar char *str; 82486470930SIngo Molnar 82586470930SIngo Molnar gelf_getshdr(sec, shp); 82686470930SIngo Molnar str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name); 82786470930SIngo Molnar if (!strcmp(name, str)) { 82883a0944fSIngo Molnar if (idx) 82983a0944fSIngo Molnar *idx = cnt; 83086470930SIngo Molnar break; 83186470930SIngo Molnar } 83286470930SIngo Molnar ++cnt; 83386470930SIngo Molnar } 83486470930SIngo Molnar 83586470930SIngo Molnar return sec; 83686470930SIngo Molnar } 83786470930SIngo Molnar 83886470930SIngo Molnar #define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \ 83986470930SIngo Molnar for (idx = 0, pos = gelf_getrel(reldata, 0, &pos_mem); \ 84086470930SIngo Molnar idx < nr_entries; \ 84186470930SIngo Molnar ++idx, pos = gelf_getrel(reldata, idx, &pos_mem)) 84286470930SIngo Molnar 84386470930SIngo Molnar #define elf_section__for_each_rela(reldata, pos, pos_mem, idx, nr_entries) \ 84486470930SIngo Molnar for (idx = 0, pos = gelf_getrela(reldata, 0, &pos_mem); \ 84586470930SIngo Molnar idx < nr_entries; \ 84686470930SIngo Molnar ++idx, pos = gelf_getrela(reldata, idx, &pos_mem)) 84786470930SIngo Molnar 848a25e46c4SArnaldo Carvalho de Melo /* 849a25e46c4SArnaldo Carvalho de Melo * We need to check if we have a .dynsym, so that we can handle the 850a25e46c4SArnaldo Carvalho de Melo * .plt, synthesizing its symbols, that aren't on the symtabs (be it 851a25e46c4SArnaldo Carvalho de Melo * .dynsym or .symtab). 852a25e46c4SArnaldo Carvalho de Melo * And always look at the original dso, not at debuginfo packages, that 853a25e46c4SArnaldo Carvalho de Melo * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS). 854a25e46c4SArnaldo Carvalho de Melo */ 85582164161SArnaldo Carvalho de Melo static int dso__synthesize_plt_symbols(struct dso *self, struct map *map, 85682164161SArnaldo Carvalho de Melo symbol_filter_t filter) 85786470930SIngo Molnar { 85886470930SIngo Molnar uint32_t nr_rel_entries, idx; 85986470930SIngo Molnar GElf_Sym sym; 8609cffa8d5SPaul Mackerras u64 plt_offset; 86186470930SIngo Molnar GElf_Shdr shdr_plt; 86286470930SIngo Molnar struct symbol *f; 863a25e46c4SArnaldo Carvalho de Melo GElf_Shdr shdr_rel_plt, shdr_dynsym; 86486470930SIngo Molnar Elf_Data *reldata, *syms, *symstrs; 865a25e46c4SArnaldo Carvalho de Melo Elf_Scn *scn_plt_rel, *scn_symstrs, *scn_dynsym; 866a25e46c4SArnaldo Carvalho de Melo size_t dynsym_idx; 867a25e46c4SArnaldo Carvalho de Melo GElf_Ehdr ehdr; 86886470930SIngo Molnar char sympltname[1024]; 869a25e46c4SArnaldo Carvalho de Melo Elf *elf; 870a25e46c4SArnaldo Carvalho de Melo int nr = 0, symidx, fd, err = 0; 871ec5761eaSDavid Ahern char name[PATH_MAX]; 87286470930SIngo Molnar 873ec5761eaSDavid Ahern snprintf(name, sizeof(name), "%s%s", 874ec5761eaSDavid Ahern symbol_conf.symfs, self->long_name); 875ec5761eaSDavid Ahern fd = open(name, O_RDONLY); 876a25e46c4SArnaldo Carvalho de Melo if (fd < 0) 877a25e46c4SArnaldo Carvalho de Melo goto out; 878a25e46c4SArnaldo Carvalho de Melo 87984087126SMarti Raudsepp elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 880a25e46c4SArnaldo Carvalho de Melo if (elf == NULL) 881a25e46c4SArnaldo Carvalho de Melo goto out_close; 882a25e46c4SArnaldo Carvalho de Melo 883a25e46c4SArnaldo Carvalho de Melo if (gelf_getehdr(elf, &ehdr) == NULL) 884a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 885a25e46c4SArnaldo Carvalho de Melo 886a25e46c4SArnaldo Carvalho de Melo scn_dynsym = elf_section_by_name(elf, &ehdr, &shdr_dynsym, 887a25e46c4SArnaldo Carvalho de Melo ".dynsym", &dynsym_idx); 888a25e46c4SArnaldo Carvalho de Melo if (scn_dynsym == NULL) 889a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 890a25e46c4SArnaldo Carvalho de Melo 891a25e46c4SArnaldo Carvalho de Melo scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt, 89286470930SIngo Molnar ".rela.plt", NULL); 89386470930SIngo Molnar if (scn_plt_rel == NULL) { 894a25e46c4SArnaldo Carvalho de Melo scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt, 89586470930SIngo Molnar ".rel.plt", NULL); 89686470930SIngo Molnar if (scn_plt_rel == NULL) 897a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 89886470930SIngo Molnar } 89986470930SIngo Molnar 900a25e46c4SArnaldo Carvalho de Melo err = -1; 90186470930SIngo Molnar 902a25e46c4SArnaldo Carvalho de Melo if (shdr_rel_plt.sh_link != dynsym_idx) 903a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 904a25e46c4SArnaldo Carvalho de Melo 905a25e46c4SArnaldo Carvalho de Melo if (elf_section_by_name(elf, &ehdr, &shdr_plt, ".plt", NULL) == NULL) 906a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 90786470930SIngo Molnar 90886470930SIngo Molnar /* 90983a0944fSIngo Molnar * Fetch the relocation section to find the idxes to the GOT 91086470930SIngo Molnar * and the symbols in the .dynsym they refer to. 91186470930SIngo Molnar */ 91286470930SIngo Molnar reldata = elf_getdata(scn_plt_rel, NULL); 91386470930SIngo Molnar if (reldata == NULL) 914a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 91586470930SIngo Molnar 91686470930SIngo Molnar syms = elf_getdata(scn_dynsym, NULL); 91786470930SIngo Molnar if (syms == NULL) 918a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 91986470930SIngo Molnar 920a25e46c4SArnaldo Carvalho de Melo scn_symstrs = elf_getscn(elf, shdr_dynsym.sh_link); 92186470930SIngo Molnar if (scn_symstrs == NULL) 922a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 92386470930SIngo Molnar 92486470930SIngo Molnar symstrs = elf_getdata(scn_symstrs, NULL); 92586470930SIngo Molnar if (symstrs == NULL) 926a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 92786470930SIngo Molnar 92886470930SIngo Molnar nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize; 92986470930SIngo Molnar plt_offset = shdr_plt.sh_offset; 93086470930SIngo Molnar 93186470930SIngo Molnar if (shdr_rel_plt.sh_type == SHT_RELA) { 93286470930SIngo Molnar GElf_Rela pos_mem, *pos; 93386470930SIngo Molnar 93486470930SIngo Molnar elf_section__for_each_rela(reldata, pos, pos_mem, idx, 93586470930SIngo Molnar nr_rel_entries) { 93686470930SIngo Molnar symidx = GELF_R_SYM(pos->r_info); 93786470930SIngo Molnar plt_offset += shdr_plt.sh_entsize; 93886470930SIngo Molnar gelf_getsym(syms, symidx, &sym); 93986470930SIngo Molnar snprintf(sympltname, sizeof(sympltname), 94086470930SIngo Molnar "%s@plt", elf_sym__name(&sym, symstrs)); 94186470930SIngo Molnar 94286470930SIngo Molnar f = symbol__new(plt_offset, shdr_plt.sh_entsize, 943c408fedfSArnaldo Carvalho de Melo STB_GLOBAL, sympltname); 94486470930SIngo Molnar if (!f) 945a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 94686470930SIngo Molnar 94782164161SArnaldo Carvalho de Melo if (filter && filter(map, f)) 94882164161SArnaldo Carvalho de Melo symbol__delete(f); 94982164161SArnaldo Carvalho de Melo else { 9506a4694a4SArnaldo Carvalho de Melo symbols__insert(&self->symbols[map->type], f); 95186470930SIngo Molnar ++nr; 95286470930SIngo Molnar } 95382164161SArnaldo Carvalho de Melo } 95486470930SIngo Molnar } else if (shdr_rel_plt.sh_type == SHT_REL) { 95586470930SIngo Molnar GElf_Rel pos_mem, *pos; 95686470930SIngo Molnar elf_section__for_each_rel(reldata, pos, pos_mem, idx, 95786470930SIngo Molnar nr_rel_entries) { 95886470930SIngo Molnar symidx = GELF_R_SYM(pos->r_info); 95986470930SIngo Molnar plt_offset += shdr_plt.sh_entsize; 96086470930SIngo Molnar gelf_getsym(syms, symidx, &sym); 96186470930SIngo Molnar snprintf(sympltname, sizeof(sympltname), 96286470930SIngo Molnar "%s@plt", elf_sym__name(&sym, symstrs)); 96386470930SIngo Molnar 96486470930SIngo Molnar f = symbol__new(plt_offset, shdr_plt.sh_entsize, 965c408fedfSArnaldo Carvalho de Melo STB_GLOBAL, sympltname); 96686470930SIngo Molnar if (!f) 967a25e46c4SArnaldo Carvalho de Melo goto out_elf_end; 96886470930SIngo Molnar 96982164161SArnaldo Carvalho de Melo if (filter && filter(map, f)) 97082164161SArnaldo Carvalho de Melo symbol__delete(f); 97182164161SArnaldo Carvalho de Melo else { 9726a4694a4SArnaldo Carvalho de Melo symbols__insert(&self->symbols[map->type], f); 97386470930SIngo Molnar ++nr; 97486470930SIngo Molnar } 97586470930SIngo Molnar } 97682164161SArnaldo Carvalho de Melo } 97786470930SIngo Molnar 978a25e46c4SArnaldo Carvalho de Melo err = 0; 979a25e46c4SArnaldo Carvalho de Melo out_elf_end: 980a25e46c4SArnaldo Carvalho de Melo elf_end(elf); 981a25e46c4SArnaldo Carvalho de Melo out_close: 982a25e46c4SArnaldo Carvalho de Melo close(fd); 983a25e46c4SArnaldo Carvalho de Melo 984a25e46c4SArnaldo Carvalho de Melo if (err == 0) 98586470930SIngo Molnar return nr; 986a25e46c4SArnaldo Carvalho de Melo out: 987fe2197b8SArnaldo Carvalho de Melo pr_debug("%s: problems reading %s PLT info.\n", 988439d473bSArnaldo Carvalho de Melo __func__, self->long_name); 989a25e46c4SArnaldo Carvalho de Melo return 0; 99086470930SIngo Molnar } 99186470930SIngo Molnar 992d45868d3SArnaldo Carvalho de Melo static bool elf_sym__is_a(GElf_Sym *self, enum map_type type) 993d45868d3SArnaldo Carvalho de Melo { 994d45868d3SArnaldo Carvalho de Melo switch (type) { 995d45868d3SArnaldo Carvalho de Melo case MAP__FUNCTION: 996d45868d3SArnaldo Carvalho de Melo return elf_sym__is_function(self); 997f1dfa0b1SArnaldo Carvalho de Melo case MAP__VARIABLE: 998f1dfa0b1SArnaldo Carvalho de Melo return elf_sym__is_object(self); 999d45868d3SArnaldo Carvalho de Melo default: 1000d45868d3SArnaldo Carvalho de Melo return false; 1001d45868d3SArnaldo Carvalho de Melo } 1002d45868d3SArnaldo Carvalho de Melo } 1003d45868d3SArnaldo Carvalho de Melo 1004d45868d3SArnaldo Carvalho de Melo static bool elf_sec__is_a(GElf_Shdr *self, Elf_Data *secstrs, enum map_type type) 1005d45868d3SArnaldo Carvalho de Melo { 1006d45868d3SArnaldo Carvalho de Melo switch (type) { 1007d45868d3SArnaldo Carvalho de Melo case MAP__FUNCTION: 1008d45868d3SArnaldo Carvalho de Melo return elf_sec__is_text(self, secstrs); 1009f1dfa0b1SArnaldo Carvalho de Melo case MAP__VARIABLE: 1010f1dfa0b1SArnaldo Carvalho de Melo return elf_sec__is_data(self, secstrs); 1011d45868d3SArnaldo Carvalho de Melo default: 1012d45868d3SArnaldo Carvalho de Melo return false; 1013d45868d3SArnaldo Carvalho de Melo } 1014d45868d3SArnaldo Carvalho de Melo } 1015d45868d3SArnaldo Carvalho de Melo 101670c3856bSEric B Munson static size_t elf_addr_to_index(Elf *elf, GElf_Addr addr) 101770c3856bSEric B Munson { 101870c3856bSEric B Munson Elf_Scn *sec = NULL; 101970c3856bSEric B Munson GElf_Shdr shdr; 102070c3856bSEric B Munson size_t cnt = 1; 102170c3856bSEric B Munson 102270c3856bSEric B Munson while ((sec = elf_nextscn(elf, sec)) != NULL) { 102370c3856bSEric B Munson gelf_getshdr(sec, &shdr); 102470c3856bSEric B Munson 102570c3856bSEric B Munson if ((addr >= shdr.sh_addr) && 102670c3856bSEric B Munson (addr < (shdr.sh_addr + shdr.sh_size))) 102770c3856bSEric B Munson return cnt; 102870c3856bSEric B Munson 102970c3856bSEric B Munson ++cnt; 103070c3856bSEric B Munson } 103170c3856bSEric B Munson 103270c3856bSEric B Munson return -1; 103370c3856bSEric B Munson } 103470c3856bSEric B Munson 10359de89fe7SArnaldo Carvalho de Melo static int dso__load_sym(struct dso *self, struct map *map, const char *name, 10366da80ce8SDave Martin int fd, symbol_filter_t filter, int kmodule, 10376da80ce8SDave Martin int want_symtab) 103886470930SIngo Molnar { 10399de89fe7SArnaldo Carvalho de Melo struct kmap *kmap = self->kernel ? map__kmap(map) : NULL; 10402e538c4aSArnaldo Carvalho de Melo struct map *curr_map = map; 10412e538c4aSArnaldo Carvalho de Melo struct dso *curr_dso = self; 10426cfcc53eSMike Galbraith Elf_Data *symstrs, *secstrs; 104386470930SIngo Molnar uint32_t nr_syms; 104486470930SIngo Molnar int err = -1; 104583a0944fSIngo Molnar uint32_t idx; 104686470930SIngo Molnar GElf_Ehdr ehdr; 104770c3856bSEric B Munson GElf_Shdr shdr, opdshdr; 104870c3856bSEric B Munson Elf_Data *syms, *opddata = NULL; 104986470930SIngo Molnar GElf_Sym sym; 105070c3856bSEric B Munson Elf_Scn *sec, *sec_strndx, *opdsec; 105186470930SIngo Molnar Elf *elf; 1052439d473bSArnaldo Carvalho de Melo int nr = 0; 105370c3856bSEric B Munson size_t opdidx = 0; 105486470930SIngo Molnar 105584087126SMarti Raudsepp elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 105686470930SIngo Molnar if (elf == NULL) { 10578b1389efSDave Martin pr_debug("%s: cannot read %s ELF file.\n", __func__, name); 105886470930SIngo Molnar goto out_close; 105986470930SIngo Molnar } 106086470930SIngo Molnar 106186470930SIngo Molnar if (gelf_getehdr(elf, &ehdr) == NULL) { 10628b1389efSDave Martin pr_debug("%s: cannot get elf header.\n", __func__); 106386470930SIngo Molnar goto out_elf_end; 106486470930SIngo Molnar } 106586470930SIngo Molnar 10666da80ce8SDave Martin /* Always reject images with a mismatched build-id: */ 106721916c38SDave Martin if (self->has_build_id) { 106821916c38SDave Martin u8 build_id[BUILD_ID_SIZE]; 106921916c38SDave Martin 107021916c38SDave Martin if (elf_read_build_id(elf, build_id, 107121916c38SDave Martin BUILD_ID_SIZE) != BUILD_ID_SIZE) 107221916c38SDave Martin goto out_elf_end; 107321916c38SDave Martin 107421916c38SDave Martin if (!dso__build_id_equal(self, build_id)) 107521916c38SDave Martin goto out_elf_end; 107621916c38SDave Martin } 107721916c38SDave Martin 107886470930SIngo Molnar sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL); 107986470930SIngo Molnar if (sec == NULL) { 10806da80ce8SDave Martin if (want_symtab) 10816da80ce8SDave Martin goto out_elf_end; 10826da80ce8SDave Martin 1083a25e46c4SArnaldo Carvalho de Melo sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL); 1084a25e46c4SArnaldo Carvalho de Melo if (sec == NULL) 108586470930SIngo Molnar goto out_elf_end; 108686470930SIngo Molnar } 108786470930SIngo Molnar 108870c3856bSEric B Munson opdsec = elf_section_by_name(elf, &ehdr, &opdshdr, ".opd", &opdidx); 108970c3856bSEric B Munson if (opdsec) 109070c3856bSEric B Munson opddata = elf_rawdata(opdsec, NULL); 109170c3856bSEric B Munson 109286470930SIngo Molnar syms = elf_getdata(sec, NULL); 109386470930SIngo Molnar if (syms == NULL) 109486470930SIngo Molnar goto out_elf_end; 109586470930SIngo Molnar 109686470930SIngo Molnar sec = elf_getscn(elf, shdr.sh_link); 109786470930SIngo Molnar if (sec == NULL) 109886470930SIngo Molnar goto out_elf_end; 109986470930SIngo Molnar 110086470930SIngo Molnar symstrs = elf_getdata(sec, NULL); 110186470930SIngo Molnar if (symstrs == NULL) 110286470930SIngo Molnar goto out_elf_end; 110386470930SIngo Molnar 11046cfcc53eSMike Galbraith sec_strndx = elf_getscn(elf, ehdr.e_shstrndx); 11056cfcc53eSMike Galbraith if (sec_strndx == NULL) 11066cfcc53eSMike Galbraith goto out_elf_end; 11076cfcc53eSMike Galbraith 11086cfcc53eSMike Galbraith secstrs = elf_getdata(sec_strndx, NULL); 11099b30a26bSStoyan Gaydarov if (secstrs == NULL) 11106cfcc53eSMike Galbraith goto out_elf_end; 11116cfcc53eSMike Galbraith 111286470930SIngo Molnar nr_syms = shdr.sh_size / shdr.sh_entsize; 111386470930SIngo Molnar 1114e9fbc9dcSArjan van de Ven memset(&sym, 0, sizeof(sym)); 1115a1645ce1SZhang, Yanmin if (self->kernel == DSO_TYPE_USER) { 111630d7a77dSArnaldo Carvalho de Melo self->adjust_symbols = (ehdr.e_type == ET_EXEC || 111730d7a77dSArnaldo Carvalho de Melo elf_section_by_name(elf, &ehdr, &shdr, 1118f5812a7aSArnaldo Carvalho de Melo ".gnu.prelink_undo", 111930d7a77dSArnaldo Carvalho de Melo NULL) != NULL); 1120d20ff6bdSMike Galbraith } else self->adjust_symbols = 0; 1121d20ff6bdSMike Galbraith 112283a0944fSIngo Molnar elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) { 112386470930SIngo Molnar struct symbol *f; 112456b03f3cSArnaldo Carvalho de Melo const char *elf_name = elf_sym__name(&sym, symstrs); 11252e538c4aSArnaldo Carvalho de Melo char *demangled = NULL; 11266cfcc53eSMike Galbraith int is_label = elf_sym__is_label(&sym); 11276cfcc53eSMike Galbraith const char *section_name; 112886470930SIngo Molnar 11299de89fe7SArnaldo Carvalho de Melo if (kmap && kmap->ref_reloc_sym && kmap->ref_reloc_sym->name && 11309de89fe7SArnaldo Carvalho de Melo strcmp(elf_name, kmap->ref_reloc_sym->name) == 0) 11319de89fe7SArnaldo Carvalho de Melo kmap->ref_reloc_sym->unrelocated_addr = sym.st_value; 113256b03f3cSArnaldo Carvalho de Melo 1133d45868d3SArnaldo Carvalho de Melo if (!is_label && !elf_sym__is_a(&sym, map->type)) 113486470930SIngo Molnar continue; 113586470930SIngo Molnar 1136696b97a5SDave Martin /* Reject ARM ELF "mapping symbols": these aren't unique and 1137696b97a5SDave Martin * don't identify functions, so will confuse the profile 1138696b97a5SDave Martin * output: */ 1139696b97a5SDave Martin if (ehdr.e_machine == EM_ARM) { 1140696b97a5SDave Martin if (!strcmp(elf_name, "$a") || 1141696b97a5SDave Martin !strcmp(elf_name, "$d") || 1142696b97a5SDave Martin !strcmp(elf_name, "$t")) 1143696b97a5SDave Martin continue; 1144696b97a5SDave Martin } 1145696b97a5SDave Martin 114670c3856bSEric B Munson if (opdsec && sym.st_shndx == opdidx) { 114770c3856bSEric B Munson u32 offset = sym.st_value - opdshdr.sh_addr; 114870c3856bSEric B Munson u64 *opd = opddata->d_buf + offset; 114970c3856bSEric B Munson sym.st_value = *opd; 115070c3856bSEric B Munson sym.st_shndx = elf_addr_to_index(elf, sym.st_value); 115170c3856bSEric B Munson } 115270c3856bSEric B Munson 115386470930SIngo Molnar sec = elf_getscn(elf, sym.st_shndx); 115486470930SIngo Molnar if (!sec) 115586470930SIngo Molnar goto out_elf_end; 115686470930SIngo Molnar 115786470930SIngo Molnar gelf_getshdr(sec, &shdr); 11586cfcc53eSMike Galbraith 1159d45868d3SArnaldo Carvalho de Melo if (is_label && !elf_sec__is_a(&shdr, secstrs, map->type)) 11606cfcc53eSMike Galbraith continue; 11616cfcc53eSMike Galbraith 11626cfcc53eSMike Galbraith section_name = elf_sec__name(&shdr, secstrs); 116386470930SIngo Molnar 1164*b2f8fb23SDr. David Alan Gilbert /* On ARM, symbols for thumb functions have 1 added to 1165*b2f8fb23SDr. David Alan Gilbert * the symbol address as a flag - remove it */ 1166*b2f8fb23SDr. David Alan Gilbert if ((ehdr.e_machine == EM_ARM) && 1167*b2f8fb23SDr. David Alan Gilbert (map->type == MAP__FUNCTION) && 1168*b2f8fb23SDr. David Alan Gilbert (sym.st_value & 1)) 1169*b2f8fb23SDr. David Alan Gilbert --sym.st_value; 1170*b2f8fb23SDr. David Alan Gilbert 1171a1645ce1SZhang, Yanmin if (self->kernel != DSO_TYPE_USER || kmodule) { 11722e538c4aSArnaldo Carvalho de Melo char dso_name[PATH_MAX]; 11732e538c4aSArnaldo Carvalho de Melo 11742e538c4aSArnaldo Carvalho de Melo if (strcmp(section_name, 1175b63be8d7SArnaldo Carvalho de Melo (curr_dso->short_name + 1176b63be8d7SArnaldo Carvalho de Melo self->short_name_len)) == 0) 11772e538c4aSArnaldo Carvalho de Melo goto new_symbol; 11782e538c4aSArnaldo Carvalho de Melo 11792e538c4aSArnaldo Carvalho de Melo if (strcmp(section_name, ".text") == 0) { 11802e538c4aSArnaldo Carvalho de Melo curr_map = map; 11812e538c4aSArnaldo Carvalho de Melo curr_dso = self; 11822e538c4aSArnaldo Carvalho de Melo goto new_symbol; 1183af427bf5SArnaldo Carvalho de Melo } 1184af427bf5SArnaldo Carvalho de Melo 11852e538c4aSArnaldo Carvalho de Melo snprintf(dso_name, sizeof(dso_name), 11862e538c4aSArnaldo Carvalho de Melo "%s%s", self->short_name, section_name); 11872e538c4aSArnaldo Carvalho de Melo 11889de89fe7SArnaldo Carvalho de Melo curr_map = map_groups__find_by_name(kmap->kmaps, map->type, dso_name); 11892e538c4aSArnaldo Carvalho de Melo if (curr_map == NULL) { 11902e538c4aSArnaldo Carvalho de Melo u64 start = sym.st_value; 11912e538c4aSArnaldo Carvalho de Melo 11922e538c4aSArnaldo Carvalho de Melo if (kmodule) 11932e538c4aSArnaldo Carvalho de Melo start += map->start + shdr.sh_offset; 11942e538c4aSArnaldo Carvalho de Melo 119500a192b3SArnaldo Carvalho de Melo curr_dso = dso__new(dso_name); 11962e538c4aSArnaldo Carvalho de Melo if (curr_dso == NULL) 11972e538c4aSArnaldo Carvalho de Melo goto out_elf_end; 1198a1645ce1SZhang, Yanmin curr_dso->kernel = self->kernel; 11993610583cSArnaldo Carvalho de Melo curr_map = map__new2(start, curr_dso, 12006275ce2dSArnaldo Carvalho de Melo map->type); 12012e538c4aSArnaldo Carvalho de Melo if (curr_map == NULL) { 12022e538c4aSArnaldo Carvalho de Melo dso__delete(curr_dso); 12032e538c4aSArnaldo Carvalho de Melo goto out_elf_end; 12042e538c4aSArnaldo Carvalho de Melo } 1205ed52ce2eSArnaldo Carvalho de Melo curr_map->map_ip = identity__map_ip; 1206ed52ce2eSArnaldo Carvalho de Melo curr_map->unmap_ip = identity__map_ip; 1207b0a9ab62SArnaldo Carvalho de Melo curr_dso->origin = self->origin; 12089de89fe7SArnaldo Carvalho de Melo map_groups__insert(kmap->kmaps, curr_map); 1209a1645ce1SZhang, Yanmin dsos__add(&self->node, curr_dso); 12106275ce2dSArnaldo Carvalho de Melo dso__set_loaded(curr_dso, map->type); 12112e538c4aSArnaldo Carvalho de Melo } else 12122e538c4aSArnaldo Carvalho de Melo curr_dso = curr_map->dso; 12132e538c4aSArnaldo Carvalho de Melo 12142e538c4aSArnaldo Carvalho de Melo goto new_symbol; 12152e538c4aSArnaldo Carvalho de Melo } 12162e538c4aSArnaldo Carvalho de Melo 12172e538c4aSArnaldo Carvalho de Melo if (curr_dso->adjust_symbols) { 121829a9f66dSArnaldo Carvalho de Melo pr_debug4("%s: adjusting symbol: st_value: %#Lx " 121929a9f66dSArnaldo Carvalho de Melo "sh_addr: %#Lx sh_offset: %#Lx\n", __func__, 122029a9f66dSArnaldo Carvalho de Melo (u64)sym.st_value, (u64)shdr.sh_addr, 122129a9f66dSArnaldo Carvalho de Melo (u64)shdr.sh_offset); 122286470930SIngo Molnar sym.st_value -= shdr.sh_addr - shdr.sh_offset; 1223af427bf5SArnaldo Carvalho de Melo } 122428ac909bSArnaldo Carvalho de Melo /* 122528ac909bSArnaldo Carvalho de Melo * We need to figure out if the object was created from C++ sources 122628ac909bSArnaldo Carvalho de Melo * DWARF DW_compile_unit has this, but we don't always have access 122728ac909bSArnaldo Carvalho de Melo * to it... 122828ac909bSArnaldo Carvalho de Melo */ 122983a0944fSIngo Molnar demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI); 123028ac909bSArnaldo Carvalho de Melo if (demangled != NULL) 123183a0944fSIngo Molnar elf_name = demangled; 12322e538c4aSArnaldo Carvalho de Melo new_symbol: 1233c408fedfSArnaldo Carvalho de Melo f = symbol__new(sym.st_value, sym.st_size, 1234c408fedfSArnaldo Carvalho de Melo GELF_ST_BIND(sym.st_info), elf_name); 123528ac909bSArnaldo Carvalho de Melo free(demangled); 123686470930SIngo Molnar if (!f) 123786470930SIngo Molnar goto out_elf_end; 123886470930SIngo Molnar 12392e538c4aSArnaldo Carvalho de Melo if (filter && filter(curr_map, f)) 124000a192b3SArnaldo Carvalho de Melo symbol__delete(f); 124186470930SIngo Molnar else { 12426a4694a4SArnaldo Carvalho de Melo symbols__insert(&curr_dso->symbols[curr_map->type], f); 124386470930SIngo Molnar nr++; 124486470930SIngo Molnar } 124586470930SIngo Molnar } 124686470930SIngo Molnar 12472e538c4aSArnaldo Carvalho de Melo /* 12482e538c4aSArnaldo Carvalho de Melo * For misannotated, zeroed, ASM function sizes. 12492e538c4aSArnaldo Carvalho de Melo */ 12506275ce2dSArnaldo Carvalho de Melo if (nr > 0) { 12516a4694a4SArnaldo Carvalho de Melo symbols__fixup_end(&self->symbols[map->type]); 12526275ce2dSArnaldo Carvalho de Melo if (kmap) { 12536275ce2dSArnaldo Carvalho de Melo /* 12546275ce2dSArnaldo Carvalho de Melo * We need to fixup this here too because we create new 12556275ce2dSArnaldo Carvalho de Melo * maps here, for things like vsyscall sections. 12566275ce2dSArnaldo Carvalho de Melo */ 12576275ce2dSArnaldo Carvalho de Melo __map_groups__fixup_end(kmap->kmaps, map->type); 12586275ce2dSArnaldo Carvalho de Melo } 12596275ce2dSArnaldo Carvalho de Melo } 126086470930SIngo Molnar err = nr; 126186470930SIngo Molnar out_elf_end: 126286470930SIngo Molnar elf_end(elf); 126386470930SIngo Molnar out_close: 126486470930SIngo Molnar return err; 126586470930SIngo Molnar } 126686470930SIngo Molnar 126778075caaSArnaldo Carvalho de Melo static bool dso__build_id_equal(const struct dso *self, u8 *build_id) 126878075caaSArnaldo Carvalho de Melo { 126978075caaSArnaldo Carvalho de Melo return memcmp(self->build_id, build_id, sizeof(self->build_id)) == 0; 127078075caaSArnaldo Carvalho de Melo } 127178075caaSArnaldo Carvalho de Melo 1272a1645ce1SZhang, Yanmin bool __dsos__read_build_ids(struct list_head *head, bool with_hits) 127357f395a7SFrederic Weisbecker { 1274e30a3d12SArnaldo Carvalho de Melo bool have_build_id = false; 127557f395a7SFrederic Weisbecker struct dso *pos; 127657f395a7SFrederic Weisbecker 12776122e4e4SArnaldo Carvalho de Melo list_for_each_entry(pos, head, node) { 12786122e4e4SArnaldo Carvalho de Melo if (with_hits && !pos->hit) 12796122e4e4SArnaldo Carvalho de Melo continue; 1280f6e1467dSArnaldo Carvalho de Melo if (pos->has_build_id) { 1281f6e1467dSArnaldo Carvalho de Melo have_build_id = true; 1282f6e1467dSArnaldo Carvalho de Melo continue; 1283f6e1467dSArnaldo Carvalho de Melo } 1284e30a3d12SArnaldo Carvalho de Melo if (filename__read_build_id(pos->long_name, pos->build_id, 1285e30a3d12SArnaldo Carvalho de Melo sizeof(pos->build_id)) > 0) { 1286e30a3d12SArnaldo Carvalho de Melo have_build_id = true; 1287e30a3d12SArnaldo Carvalho de Melo pos->has_build_id = true; 128857f395a7SFrederic Weisbecker } 12896122e4e4SArnaldo Carvalho de Melo } 129057f395a7SFrederic Weisbecker 1291e30a3d12SArnaldo Carvalho de Melo return have_build_id; 129257f395a7SFrederic Weisbecker } 129357f395a7SFrederic Weisbecker 1294fd7a346eSArnaldo Carvalho de Melo /* 1295fd7a346eSArnaldo Carvalho de Melo * Align offset to 4 bytes as needed for note name and descriptor data. 1296fd7a346eSArnaldo Carvalho de Melo */ 1297fd7a346eSArnaldo Carvalho de Melo #define NOTE_ALIGN(n) (((n) + 3) & -4U) 1298fd7a346eSArnaldo Carvalho de Melo 129921916c38SDave Martin static int elf_read_build_id(Elf *elf, void *bf, size_t size) 13004d1e00a8SArnaldo Carvalho de Melo { 130121916c38SDave Martin int err = -1; 13024d1e00a8SArnaldo Carvalho de Melo GElf_Ehdr ehdr; 13034d1e00a8SArnaldo Carvalho de Melo GElf_Shdr shdr; 1304fd7a346eSArnaldo Carvalho de Melo Elf_Data *data; 13054d1e00a8SArnaldo Carvalho de Melo Elf_Scn *sec; 1306e57cfcdaSPekka Enberg Elf_Kind ek; 1307fd7a346eSArnaldo Carvalho de Melo void *ptr; 13084d1e00a8SArnaldo Carvalho de Melo 13092643ce11SArnaldo Carvalho de Melo if (size < BUILD_ID_SIZE) 13102643ce11SArnaldo Carvalho de Melo goto out; 13112643ce11SArnaldo Carvalho de Melo 1312e57cfcdaSPekka Enberg ek = elf_kind(elf); 1313e57cfcdaSPekka Enberg if (ek != ELF_K_ELF) 131421916c38SDave Martin goto out; 1315e57cfcdaSPekka Enberg 13164d1e00a8SArnaldo Carvalho de Melo if (gelf_getehdr(elf, &ehdr) == NULL) { 13176beba7adSArnaldo Carvalho de Melo pr_err("%s: cannot get elf header.\n", __func__); 131821916c38SDave Martin goto out; 13194d1e00a8SArnaldo Carvalho de Melo } 13204d1e00a8SArnaldo Carvalho de Melo 13212643ce11SArnaldo Carvalho de Melo sec = elf_section_by_name(elf, &ehdr, &shdr, 13222643ce11SArnaldo Carvalho de Melo ".note.gnu.build-id", NULL); 1323fd7a346eSArnaldo Carvalho de Melo if (sec == NULL) { 1324fd7a346eSArnaldo Carvalho de Melo sec = elf_section_by_name(elf, &ehdr, &shdr, 1325fd7a346eSArnaldo Carvalho de Melo ".notes", NULL); 13264d1e00a8SArnaldo Carvalho de Melo if (sec == NULL) 132721916c38SDave Martin goto out; 1328fd7a346eSArnaldo Carvalho de Melo } 13294d1e00a8SArnaldo Carvalho de Melo 1330fd7a346eSArnaldo Carvalho de Melo data = elf_getdata(sec, NULL); 1331fd7a346eSArnaldo Carvalho de Melo if (data == NULL) 133221916c38SDave Martin goto out; 1333fd7a346eSArnaldo Carvalho de Melo 1334fd7a346eSArnaldo Carvalho de Melo ptr = data->d_buf; 1335fd7a346eSArnaldo Carvalho de Melo while (ptr < (data->d_buf + data->d_size)) { 1336fd7a346eSArnaldo Carvalho de Melo GElf_Nhdr *nhdr = ptr; 1337fd7a346eSArnaldo Carvalho de Melo int namesz = NOTE_ALIGN(nhdr->n_namesz), 1338fd7a346eSArnaldo Carvalho de Melo descsz = NOTE_ALIGN(nhdr->n_descsz); 1339fd7a346eSArnaldo Carvalho de Melo const char *name; 1340fd7a346eSArnaldo Carvalho de Melo 1341fd7a346eSArnaldo Carvalho de Melo ptr += sizeof(*nhdr); 1342fd7a346eSArnaldo Carvalho de Melo name = ptr; 1343fd7a346eSArnaldo Carvalho de Melo ptr += namesz; 1344fd7a346eSArnaldo Carvalho de Melo if (nhdr->n_type == NT_GNU_BUILD_ID && 1345fd7a346eSArnaldo Carvalho de Melo nhdr->n_namesz == sizeof("GNU")) { 1346fd7a346eSArnaldo Carvalho de Melo if (memcmp(name, "GNU", sizeof("GNU")) == 0) { 1347fd7a346eSArnaldo Carvalho de Melo memcpy(bf, ptr, BUILD_ID_SIZE); 13482643ce11SArnaldo Carvalho de Melo err = BUILD_ID_SIZE; 1349fd7a346eSArnaldo Carvalho de Melo break; 1350fd7a346eSArnaldo Carvalho de Melo } 1351fd7a346eSArnaldo Carvalho de Melo } 1352fd7a346eSArnaldo Carvalho de Melo ptr += descsz; 1353fd7a346eSArnaldo Carvalho de Melo } 135421916c38SDave Martin 135521916c38SDave Martin out: 135621916c38SDave Martin return err; 135721916c38SDave Martin } 135821916c38SDave Martin 135921916c38SDave Martin int filename__read_build_id(const char *filename, void *bf, size_t size) 136021916c38SDave Martin { 136121916c38SDave Martin int fd, err = -1; 136221916c38SDave Martin Elf *elf; 136321916c38SDave Martin 136421916c38SDave Martin if (size < BUILD_ID_SIZE) 136521916c38SDave Martin goto out; 136621916c38SDave Martin 136721916c38SDave Martin fd = open(filename, O_RDONLY); 136821916c38SDave Martin if (fd < 0) 136921916c38SDave Martin goto out; 137021916c38SDave Martin 137121916c38SDave Martin elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 137221916c38SDave Martin if (elf == NULL) { 137321916c38SDave Martin pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename); 137421916c38SDave Martin goto out_close; 137521916c38SDave Martin } 137621916c38SDave Martin 137721916c38SDave Martin err = elf_read_build_id(elf, bf, size); 137821916c38SDave Martin 13792643ce11SArnaldo Carvalho de Melo elf_end(elf); 13802643ce11SArnaldo Carvalho de Melo out_close: 13812643ce11SArnaldo Carvalho de Melo close(fd); 13822643ce11SArnaldo Carvalho de Melo out: 13832643ce11SArnaldo Carvalho de Melo return err; 13842643ce11SArnaldo Carvalho de Melo } 13852643ce11SArnaldo Carvalho de Melo 1386f1617b40SArnaldo Carvalho de Melo int sysfs__read_build_id(const char *filename, void *build_id, size_t size) 1387f1617b40SArnaldo Carvalho de Melo { 1388f1617b40SArnaldo Carvalho de Melo int fd, err = -1; 1389f1617b40SArnaldo Carvalho de Melo 1390f1617b40SArnaldo Carvalho de Melo if (size < BUILD_ID_SIZE) 1391f1617b40SArnaldo Carvalho de Melo goto out; 1392f1617b40SArnaldo Carvalho de Melo 1393f1617b40SArnaldo Carvalho de Melo fd = open(filename, O_RDONLY); 1394f1617b40SArnaldo Carvalho de Melo if (fd < 0) 1395f1617b40SArnaldo Carvalho de Melo goto out; 1396f1617b40SArnaldo Carvalho de Melo 1397f1617b40SArnaldo Carvalho de Melo while (1) { 1398f1617b40SArnaldo Carvalho de Melo char bf[BUFSIZ]; 1399f1617b40SArnaldo Carvalho de Melo GElf_Nhdr nhdr; 1400f1617b40SArnaldo Carvalho de Melo int namesz, descsz; 1401f1617b40SArnaldo Carvalho de Melo 1402f1617b40SArnaldo Carvalho de Melo if (read(fd, &nhdr, sizeof(nhdr)) != sizeof(nhdr)) 1403f1617b40SArnaldo Carvalho de Melo break; 1404f1617b40SArnaldo Carvalho de Melo 1405fd7a346eSArnaldo Carvalho de Melo namesz = NOTE_ALIGN(nhdr.n_namesz); 1406fd7a346eSArnaldo Carvalho de Melo descsz = NOTE_ALIGN(nhdr.n_descsz); 1407f1617b40SArnaldo Carvalho de Melo if (nhdr.n_type == NT_GNU_BUILD_ID && 1408f1617b40SArnaldo Carvalho de Melo nhdr.n_namesz == sizeof("GNU")) { 1409f1617b40SArnaldo Carvalho de Melo if (read(fd, bf, namesz) != namesz) 1410f1617b40SArnaldo Carvalho de Melo break; 1411f1617b40SArnaldo Carvalho de Melo if (memcmp(bf, "GNU", sizeof("GNU")) == 0) { 1412f1617b40SArnaldo Carvalho de Melo if (read(fd, build_id, 1413f1617b40SArnaldo Carvalho de Melo BUILD_ID_SIZE) == BUILD_ID_SIZE) { 1414f1617b40SArnaldo Carvalho de Melo err = 0; 1415f1617b40SArnaldo Carvalho de Melo break; 1416f1617b40SArnaldo Carvalho de Melo } 1417f1617b40SArnaldo Carvalho de Melo } else if (read(fd, bf, descsz) != descsz) 1418f1617b40SArnaldo Carvalho de Melo break; 1419f1617b40SArnaldo Carvalho de Melo } else { 1420f1617b40SArnaldo Carvalho de Melo int n = namesz + descsz; 1421f1617b40SArnaldo Carvalho de Melo if (read(fd, bf, n) != n) 1422f1617b40SArnaldo Carvalho de Melo break; 1423f1617b40SArnaldo Carvalho de Melo } 1424f1617b40SArnaldo Carvalho de Melo } 1425f1617b40SArnaldo Carvalho de Melo close(fd); 1426f1617b40SArnaldo Carvalho de Melo out: 1427f1617b40SArnaldo Carvalho de Melo return err; 1428f1617b40SArnaldo Carvalho de Melo } 1429f1617b40SArnaldo Carvalho de Melo 143094cb9e38SArnaldo Carvalho de Melo char dso__symtab_origin(const struct dso *self) 143194cb9e38SArnaldo Carvalho de Melo { 143294cb9e38SArnaldo Carvalho de Melo static const char origin[] = { 143394cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_KERNEL] = 'k', 143494cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_JAVA_JIT] = 'j', 14354cf40131SArnaldo Carvalho de Melo [DSO__ORIG_BUILD_ID_CACHE] = 'B', 143694cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_FEDORA] = 'f', 143794cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_UBUNTU] = 'u', 143894cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_BUILDID] = 'b', 143994cb9e38SArnaldo Carvalho de Melo [DSO__ORIG_DSO] = 'd', 1440439d473bSArnaldo Carvalho de Melo [DSO__ORIG_KMODULE] = 'K', 1441a1645ce1SZhang, Yanmin [DSO__ORIG_GUEST_KERNEL] = 'g', 1442a1645ce1SZhang, Yanmin [DSO__ORIG_GUEST_KMODULE] = 'G', 144394cb9e38SArnaldo Carvalho de Melo }; 144494cb9e38SArnaldo Carvalho de Melo 144594cb9e38SArnaldo Carvalho de Melo if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND) 144694cb9e38SArnaldo Carvalho de Melo return '!'; 144794cb9e38SArnaldo Carvalho de Melo return origin[self->origin]; 144894cb9e38SArnaldo Carvalho de Melo } 144994cb9e38SArnaldo Carvalho de Melo 14509de89fe7SArnaldo Carvalho de Melo int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) 145186470930SIngo Molnar { 14524d1e00a8SArnaldo Carvalho de Melo int size = PATH_MAX; 1453c338aee8SArnaldo Carvalho de Melo char *name; 145486470930SIngo Molnar int ret = -1; 145586470930SIngo Molnar int fd; 145623346f21SArnaldo Carvalho de Melo struct machine *machine; 1457a1645ce1SZhang, Yanmin const char *root_dir; 14586da80ce8SDave Martin int want_symtab; 145986470930SIngo Molnar 14603610583cSArnaldo Carvalho de Melo dso__set_loaded(self, map->type); 146166bd8424SArnaldo Carvalho de Melo 1462a1645ce1SZhang, Yanmin if (self->kernel == DSO_TYPE_KERNEL) 14639de89fe7SArnaldo Carvalho de Melo return dso__load_kernel_sym(self, map, filter); 1464a1645ce1SZhang, Yanmin else if (self->kernel == DSO_TYPE_GUEST_KERNEL) 1465a1645ce1SZhang, Yanmin return dso__load_guest_kernel_sym(self, map, filter); 1466a1645ce1SZhang, Yanmin 146723346f21SArnaldo Carvalho de Melo if (map->groups && map->groups->machine) 146823346f21SArnaldo Carvalho de Melo machine = map->groups->machine; 1469a1645ce1SZhang, Yanmin else 147023346f21SArnaldo Carvalho de Melo machine = NULL; 1471c338aee8SArnaldo Carvalho de Melo 1472c338aee8SArnaldo Carvalho de Melo name = malloc(size); 147386470930SIngo Molnar if (!name) 147486470930SIngo Molnar return -1; 147586470930SIngo Molnar 147630d7a77dSArnaldo Carvalho de Melo self->adjust_symbols = 0; 1477f5812a7aSArnaldo Carvalho de Melo 147894cb9e38SArnaldo Carvalho de Melo if (strncmp(self->name, "/tmp/perf-", 10) == 0) { 14796beba7adSArnaldo Carvalho de Melo ret = dso__load_perf_map(self, map, filter); 148094cb9e38SArnaldo Carvalho de Melo self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT : 148194cb9e38SArnaldo Carvalho de Melo DSO__ORIG_NOT_FOUND; 148294cb9e38SArnaldo Carvalho de Melo return ret; 148394cb9e38SArnaldo Carvalho de Melo } 148494cb9e38SArnaldo Carvalho de Melo 14856da80ce8SDave Martin /* Iterate over candidate debug images. 14866da80ce8SDave Martin * On the first pass, only load images if they have a full symtab. 14876da80ce8SDave Martin * Failing that, do a second pass where we accept .dynsym also 14886da80ce8SDave Martin */ 14896da80ce8SDave Martin for (self->origin = DSO__ORIG_BUILD_ID_CACHE, want_symtab = 1; 14906da80ce8SDave Martin self->origin != DSO__ORIG_NOT_FOUND; 14916da80ce8SDave Martin self->origin++) { 149294cb9e38SArnaldo Carvalho de Melo switch (self->origin) { 14936da80ce8SDave Martin case DSO__ORIG_BUILD_ID_CACHE: 1494ec5761eaSDavid Ahern /* skip the locally configured cache if a symfs is given */ 1495ec5761eaSDavid Ahern if (symbol_conf.symfs[0] || 1496ec5761eaSDavid Ahern (dso__build_id_filename(self, name, size) == NULL)) { 14976da80ce8SDave Martin continue; 1498ec5761eaSDavid Ahern } 14996da80ce8SDave Martin break; 150094cb9e38SArnaldo Carvalho de Melo case DSO__ORIG_FEDORA: 1501ec5761eaSDavid Ahern snprintf(name, size, "%s/usr/lib/debug%s.debug", 1502ec5761eaSDavid Ahern symbol_conf.symfs, self->long_name); 150386470930SIngo Molnar break; 150494cb9e38SArnaldo Carvalho de Melo case DSO__ORIG_UBUNTU: 1505ec5761eaSDavid Ahern snprintf(name, size, "%s/usr/lib/debug%s", 1506ec5761eaSDavid Ahern symbol_conf.symfs, self->long_name); 150786470930SIngo Molnar break; 15086da80ce8SDave Martin case DSO__ORIG_BUILDID: { 1509b36f19d5SArnaldo Carvalho de Melo char build_id_hex[BUILD_ID_SIZE * 2 + 1]; 15106da80ce8SDave Martin 15116da80ce8SDave Martin if (!self->has_build_id) 15126da80ce8SDave Martin continue; 15136da80ce8SDave Martin 151421916c38SDave Martin build_id__sprintf(self->build_id, 151521916c38SDave Martin sizeof(self->build_id), 1516d3379ab9SArnaldo Carvalho de Melo build_id_hex); 15174d1e00a8SArnaldo Carvalho de Melo snprintf(name, size, 1518ec5761eaSDavid Ahern "%s/usr/lib/debug/.build-id/%.2s/%s.debug", 1519ec5761eaSDavid Ahern symbol_conf.symfs, build_id_hex, build_id_hex + 2); 15204d1e00a8SArnaldo Carvalho de Melo } 15216da80ce8SDave Martin break; 152294cb9e38SArnaldo Carvalho de Melo case DSO__ORIG_DSO: 1523ec5761eaSDavid Ahern snprintf(name, size, "%s%s", 1524ec5761eaSDavid Ahern symbol_conf.symfs, self->long_name); 152586470930SIngo Molnar break; 1526a1645ce1SZhang, Yanmin case DSO__ORIG_GUEST_KMODULE: 152723346f21SArnaldo Carvalho de Melo if (map->groups && map->groups->machine) 152823346f21SArnaldo Carvalho de Melo root_dir = map->groups->machine->root_dir; 1529a1645ce1SZhang, Yanmin else 1530a1645ce1SZhang, Yanmin root_dir = ""; 1531ec5761eaSDavid Ahern snprintf(name, size, "%s%s%s", symbol_conf.symfs, 1532ec5761eaSDavid Ahern root_dir, self->long_name); 1533ec5761eaSDavid Ahern break; 1534ec5761eaSDavid Ahern 1535ec5761eaSDavid Ahern case DSO__ORIG_KMODULE: 1536ec5761eaSDavid Ahern snprintf(name, size, "%s%s", symbol_conf.symfs, 1537ec5761eaSDavid Ahern self->long_name); 1538a1645ce1SZhang, Yanmin break; 153986470930SIngo Molnar 154086470930SIngo Molnar default: 15416da80ce8SDave Martin /* 15426da80ce8SDave Martin * If we wanted a full symtab but no image had one, 15436da80ce8SDave Martin * relax our requirements and repeat the search. 15446da80ce8SDave Martin */ 15456da80ce8SDave Martin if (want_symtab) { 15466da80ce8SDave Martin want_symtab = 0; 15476da80ce8SDave Martin self->origin = DSO__ORIG_BUILD_ID_CACHE; 15486da80ce8SDave Martin } else 15496da80ce8SDave Martin continue; 155086470930SIngo Molnar } 155186470930SIngo Molnar 15526da80ce8SDave Martin /* Name is now the name of the next image to try */ 15536da80ce8SDave Martin fd = open(name, O_RDONLY); 15546da80ce8SDave Martin if (fd < 0) 15556da80ce8SDave Martin continue; 15566da80ce8SDave Martin 15576da80ce8SDave Martin ret = dso__load_sym(self, map, name, fd, filter, 0, 15586da80ce8SDave Martin want_symtab); 155986470930SIngo Molnar close(fd); 156086470930SIngo Molnar 156186470930SIngo Molnar /* 15626da80ce8SDave Martin * Some people seem to have debuginfo files _WITHOUT_ debug 15636da80ce8SDave Martin * info!?!? 156486470930SIngo Molnar */ 156586470930SIngo Molnar if (!ret) 15666da80ce8SDave Martin continue; 156786470930SIngo Molnar 1568a25e46c4SArnaldo Carvalho de Melo if (ret > 0) { 156982164161SArnaldo Carvalho de Melo int nr_plt = dso__synthesize_plt_symbols(self, map, filter); 1570a25e46c4SArnaldo Carvalho de Melo if (nr_plt > 0) 1571a25e46c4SArnaldo Carvalho de Melo ret += nr_plt; 15726da80ce8SDave Martin break; 1573a25e46c4SArnaldo Carvalho de Melo } 15746da80ce8SDave Martin } 15756da80ce8SDave Martin 157686470930SIngo Molnar free(name); 15771340e6bbSArnaldo Carvalho de Melo if (ret < 0 && strstr(self->name, " (deleted)") != NULL) 15781340e6bbSArnaldo Carvalho de Melo return 0; 157986470930SIngo Molnar return ret; 158086470930SIngo Molnar } 158186470930SIngo Molnar 158279406cd7SArnaldo Carvalho de Melo struct map *map_groups__find_by_name(struct map_groups *self, 158379406cd7SArnaldo Carvalho de Melo enum map_type type, const char *name) 1584439d473bSArnaldo Carvalho de Melo { 1585439d473bSArnaldo Carvalho de Melo struct rb_node *nd; 1586439d473bSArnaldo Carvalho de Melo 158779406cd7SArnaldo Carvalho de Melo for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) { 1588439d473bSArnaldo Carvalho de Melo struct map *map = rb_entry(nd, struct map, rb_node); 1589439d473bSArnaldo Carvalho de Melo 1590b7cece76SArnaldo Carvalho de Melo if (map->dso && strcmp(map->dso->short_name, name) == 0) 1591439d473bSArnaldo Carvalho de Melo return map; 1592439d473bSArnaldo Carvalho de Melo } 1593439d473bSArnaldo Carvalho de Melo 1594439d473bSArnaldo Carvalho de Melo return NULL; 1595439d473bSArnaldo Carvalho de Melo } 1596439d473bSArnaldo Carvalho de Melo 1597a1645ce1SZhang, Yanmin static int dso__kernel_module_get_build_id(struct dso *self, 1598a1645ce1SZhang, Yanmin const char *root_dir) 1599b7cece76SArnaldo Carvalho de Melo { 1600b7cece76SArnaldo Carvalho de Melo char filename[PATH_MAX]; 1601b7cece76SArnaldo Carvalho de Melo /* 1602b7cece76SArnaldo Carvalho de Melo * kernel module short names are of the form "[module]" and 1603b7cece76SArnaldo Carvalho de Melo * we need just "module" here. 1604b7cece76SArnaldo Carvalho de Melo */ 1605b7cece76SArnaldo Carvalho de Melo const char *name = self->short_name + 1; 1606b7cece76SArnaldo Carvalho de Melo 1607b7cece76SArnaldo Carvalho de Melo snprintf(filename, sizeof(filename), 1608a1645ce1SZhang, Yanmin "%s/sys/module/%.*s/notes/.note.gnu.build-id", 1609a1645ce1SZhang, Yanmin root_dir, (int)strlen(name) - 1, name); 1610b7cece76SArnaldo Carvalho de Melo 1611b7cece76SArnaldo Carvalho de Melo if (sysfs__read_build_id(filename, self->build_id, 1612b7cece76SArnaldo Carvalho de Melo sizeof(self->build_id)) == 0) 1613b7cece76SArnaldo Carvalho de Melo self->has_build_id = true; 1614b7cece76SArnaldo Carvalho de Melo 1615b7cece76SArnaldo Carvalho de Melo return 0; 1616b7cece76SArnaldo Carvalho de Melo } 1617b7cece76SArnaldo Carvalho de Melo 1618a1645ce1SZhang, Yanmin static int map_groups__set_modules_path_dir(struct map_groups *self, 1619a1645ce1SZhang, Yanmin const char *dir_name) 16206cfcc53eSMike Galbraith { 1621439d473bSArnaldo Carvalho de Melo struct dirent *dent; 16225aab621bSArnaldo Carvalho de Melo DIR *dir = opendir(dir_name); 162374534341SGui Jianfeng int ret = 0; 16246cfcc53eSMike Galbraith 1625439d473bSArnaldo Carvalho de Melo if (!dir) { 16265aab621bSArnaldo Carvalho de Melo pr_debug("%s: cannot open %s dir\n", __func__, dir_name); 1627439d473bSArnaldo Carvalho de Melo return -1; 1628439d473bSArnaldo Carvalho de Melo } 16296cfcc53eSMike Galbraith 1630439d473bSArnaldo Carvalho de Melo while ((dent = readdir(dir)) != NULL) { 1631439d473bSArnaldo Carvalho de Melo char path[PATH_MAX]; 1632a1645ce1SZhang, Yanmin struct stat st; 1633439d473bSArnaldo Carvalho de Melo 1634a1645ce1SZhang, Yanmin /*sshfs might return bad dent->d_type, so we have to stat*/ 1635a1645ce1SZhang, Yanmin sprintf(path, "%s/%s", dir_name, dent->d_name); 1636a1645ce1SZhang, Yanmin if (stat(path, &st)) 1637a1645ce1SZhang, Yanmin continue; 1638a1645ce1SZhang, Yanmin 1639a1645ce1SZhang, Yanmin if (S_ISDIR(st.st_mode)) { 1640439d473bSArnaldo Carvalho de Melo if (!strcmp(dent->d_name, ".") || 1641439d473bSArnaldo Carvalho de Melo !strcmp(dent->d_name, "..")) 1642439d473bSArnaldo Carvalho de Melo continue; 1643439d473bSArnaldo Carvalho de Melo 1644439d473bSArnaldo Carvalho de Melo snprintf(path, sizeof(path), "%s/%s", 16455aab621bSArnaldo Carvalho de Melo dir_name, dent->d_name); 164674534341SGui Jianfeng ret = map_groups__set_modules_path_dir(self, path); 164774534341SGui Jianfeng if (ret < 0) 164874534341SGui Jianfeng goto out; 1649439d473bSArnaldo Carvalho de Melo } else { 1650439d473bSArnaldo Carvalho de Melo char *dot = strrchr(dent->d_name, '.'), 1651439d473bSArnaldo Carvalho de Melo dso_name[PATH_MAX]; 1652439d473bSArnaldo Carvalho de Melo struct map *map; 1653cfc10d3bSArnaldo Carvalho de Melo char *long_name; 1654439d473bSArnaldo Carvalho de Melo 1655439d473bSArnaldo Carvalho de Melo if (dot == NULL || strcmp(dot, ".ko")) 1656439d473bSArnaldo Carvalho de Melo continue; 1657439d473bSArnaldo Carvalho de Melo snprintf(dso_name, sizeof(dso_name), "[%.*s]", 1658439d473bSArnaldo Carvalho de Melo (int)(dot - dent->d_name), dent->d_name); 1659439d473bSArnaldo Carvalho de Melo 1660a2a99e8eSArnaldo Carvalho de Melo strxfrchar(dso_name, '-', '_'); 16619de89fe7SArnaldo Carvalho de Melo map = map_groups__find_by_name(self, MAP__FUNCTION, dso_name); 1662439d473bSArnaldo Carvalho de Melo if (map == NULL) 1663439d473bSArnaldo Carvalho de Melo continue; 1664439d473bSArnaldo Carvalho de Melo 1665439d473bSArnaldo Carvalho de Melo snprintf(path, sizeof(path), "%s/%s", 16665aab621bSArnaldo Carvalho de Melo dir_name, dent->d_name); 1667439d473bSArnaldo Carvalho de Melo 1668cfc10d3bSArnaldo Carvalho de Melo long_name = strdup(path); 166974534341SGui Jianfeng if (long_name == NULL) { 167074534341SGui Jianfeng ret = -1; 167174534341SGui Jianfeng goto out; 167274534341SGui Jianfeng } 1673cfc10d3bSArnaldo Carvalho de Melo dso__set_long_name(map->dso, long_name); 16746e406257SArnaldo Carvalho de Melo map->dso->lname_alloc = 1; 1675a1645ce1SZhang, Yanmin dso__kernel_module_get_build_id(map->dso, ""); 1676439d473bSArnaldo Carvalho de Melo } 1677439d473bSArnaldo Carvalho de Melo } 1678439d473bSArnaldo Carvalho de Melo 167974534341SGui Jianfeng out: 1680439d473bSArnaldo Carvalho de Melo closedir(dir); 168174534341SGui Jianfeng return ret; 1682439d473bSArnaldo Carvalho de Melo } 1683439d473bSArnaldo Carvalho de Melo 1684a1645ce1SZhang, Yanmin static char *get_kernel_version(const char *root_dir) 1685439d473bSArnaldo Carvalho de Melo { 1686a1645ce1SZhang, Yanmin char version[PATH_MAX]; 1687a1645ce1SZhang, Yanmin FILE *file; 1688a1645ce1SZhang, Yanmin char *name, *tmp; 1689a1645ce1SZhang, Yanmin const char *prefix = "Linux version "; 1690a1645ce1SZhang, Yanmin 1691a1645ce1SZhang, Yanmin sprintf(version, "%s/proc/version", root_dir); 1692a1645ce1SZhang, Yanmin file = fopen(version, "r"); 1693a1645ce1SZhang, Yanmin if (!file) 1694a1645ce1SZhang, Yanmin return NULL; 1695a1645ce1SZhang, Yanmin 1696a1645ce1SZhang, Yanmin version[0] = '\0'; 1697a1645ce1SZhang, Yanmin tmp = fgets(version, sizeof(version), file); 1698a1645ce1SZhang, Yanmin fclose(file); 1699a1645ce1SZhang, Yanmin 1700a1645ce1SZhang, Yanmin name = strstr(version, prefix); 1701a1645ce1SZhang, Yanmin if (!name) 1702a1645ce1SZhang, Yanmin return NULL; 1703a1645ce1SZhang, Yanmin name += strlen(prefix); 1704a1645ce1SZhang, Yanmin tmp = strchr(name, ' '); 1705a1645ce1SZhang, Yanmin if (tmp) 1706a1645ce1SZhang, Yanmin *tmp = '\0'; 1707a1645ce1SZhang, Yanmin 1708a1645ce1SZhang, Yanmin return strdup(name); 1709a1645ce1SZhang, Yanmin } 1710a1645ce1SZhang, Yanmin 1711d28c6223SArnaldo Carvalho de Melo static int machine__set_modules_path(struct machine *self) 1712a1645ce1SZhang, Yanmin { 1713a1645ce1SZhang, Yanmin char *version; 1714439d473bSArnaldo Carvalho de Melo char modules_path[PATH_MAX]; 1715439d473bSArnaldo Carvalho de Melo 1716d28c6223SArnaldo Carvalho de Melo version = get_kernel_version(self->root_dir); 1717a1645ce1SZhang, Yanmin if (!version) 1718439d473bSArnaldo Carvalho de Melo return -1; 1719439d473bSArnaldo Carvalho de Melo 1720a1645ce1SZhang, Yanmin snprintf(modules_path, sizeof(modules_path), "%s/lib/modules/%s/kernel", 1721d28c6223SArnaldo Carvalho de Melo self->root_dir, version); 1722a1645ce1SZhang, Yanmin free(version); 1723439d473bSArnaldo Carvalho de Melo 1724d28c6223SArnaldo Carvalho de Melo return map_groups__set_modules_path_dir(&self->kmaps, modules_path); 1725439d473bSArnaldo Carvalho de Melo } 17266cfcc53eSMike Galbraith 17276cfcc53eSMike Galbraith /* 1728439d473bSArnaldo Carvalho de Melo * Constructor variant for modules (where we know from /proc/modules where 1729439d473bSArnaldo Carvalho de Melo * they are loaded) and for vmlinux, where only after we load all the 1730439d473bSArnaldo Carvalho de Melo * symbols we'll know where it starts and ends. 17316cfcc53eSMike Galbraith */ 17323610583cSArnaldo Carvalho de Melo static struct map *map__new2(u64 start, struct dso *dso, enum map_type type) 1733439d473bSArnaldo Carvalho de Melo { 17345aab621bSArnaldo Carvalho de Melo struct map *self = calloc(1, (sizeof(*self) + 17355aab621bSArnaldo Carvalho de Melo (dso->kernel ? sizeof(struct kmap) : 0))); 1736439d473bSArnaldo Carvalho de Melo if (self != NULL) { 1737439d473bSArnaldo Carvalho de Melo /* 1738afb7b4f0SArnaldo Carvalho de Melo * ->end will be filled after we load all the symbols 1739439d473bSArnaldo Carvalho de Melo */ 17403610583cSArnaldo Carvalho de Melo map__init(self, type, start, 0, 0, dso); 1741439d473bSArnaldo Carvalho de Melo } 1742afb7b4f0SArnaldo Carvalho de Melo 1743439d473bSArnaldo Carvalho de Melo return self; 1744439d473bSArnaldo Carvalho de Melo } 1745439d473bSArnaldo Carvalho de Melo 1746d28c6223SArnaldo Carvalho de Melo struct map *machine__new_module(struct machine *self, u64 start, 1747d28c6223SArnaldo Carvalho de Melo const char *filename) 1748b7cece76SArnaldo Carvalho de Melo { 1749b7cece76SArnaldo Carvalho de Melo struct map *map; 1750d28c6223SArnaldo Carvalho de Melo struct dso *dso = __dsos__findnew(&self->kernel_dsos, filename); 1751b7cece76SArnaldo Carvalho de Melo 1752b7cece76SArnaldo Carvalho de Melo if (dso == NULL) 1753b7cece76SArnaldo Carvalho de Melo return NULL; 1754b7cece76SArnaldo Carvalho de Melo 1755b7cece76SArnaldo Carvalho de Melo map = map__new2(start, dso, MAP__FUNCTION); 1756b7cece76SArnaldo Carvalho de Melo if (map == NULL) 1757b7cece76SArnaldo Carvalho de Melo return NULL; 1758b7cece76SArnaldo Carvalho de Melo 1759d28c6223SArnaldo Carvalho de Melo if (machine__is_host(self)) 1760b7cece76SArnaldo Carvalho de Melo dso->origin = DSO__ORIG_KMODULE; 1761a1645ce1SZhang, Yanmin else 1762a1645ce1SZhang, Yanmin dso->origin = DSO__ORIG_GUEST_KMODULE; 1763d28c6223SArnaldo Carvalho de Melo map_groups__insert(&self->kmaps, map); 1764b7cece76SArnaldo Carvalho de Melo return map; 1765b7cece76SArnaldo Carvalho de Melo } 1766b7cece76SArnaldo Carvalho de Melo 1767d28c6223SArnaldo Carvalho de Melo static int machine__create_modules(struct machine *self) 1768439d473bSArnaldo Carvalho de Melo { 1769439d473bSArnaldo Carvalho de Melo char *line = NULL; 1770439d473bSArnaldo Carvalho de Melo size_t n; 1771a1645ce1SZhang, Yanmin FILE *file; 1772439d473bSArnaldo Carvalho de Melo struct map *map; 1773a1645ce1SZhang, Yanmin const char *modules; 1774a1645ce1SZhang, Yanmin char path[PATH_MAX]; 1775439d473bSArnaldo Carvalho de Melo 1776d28c6223SArnaldo Carvalho de Melo if (machine__is_default_guest(self)) 1777a1645ce1SZhang, Yanmin modules = symbol_conf.default_guest_modules; 1778a1645ce1SZhang, Yanmin else { 1779d28c6223SArnaldo Carvalho de Melo sprintf(path, "%s/proc/modules", self->root_dir); 1780a1645ce1SZhang, Yanmin modules = path; 1781a1645ce1SZhang, Yanmin } 1782a1645ce1SZhang, Yanmin 1783a1645ce1SZhang, Yanmin file = fopen(modules, "r"); 1784439d473bSArnaldo Carvalho de Melo if (file == NULL) 1785439d473bSArnaldo Carvalho de Melo return -1; 1786439d473bSArnaldo Carvalho de Melo 1787439d473bSArnaldo Carvalho de Melo while (!feof(file)) { 1788439d473bSArnaldo Carvalho de Melo char name[PATH_MAX]; 1789439d473bSArnaldo Carvalho de Melo u64 start; 1790439d473bSArnaldo Carvalho de Melo char *sep; 1791439d473bSArnaldo Carvalho de Melo int line_len; 1792439d473bSArnaldo Carvalho de Melo 1793439d473bSArnaldo Carvalho de Melo line_len = getline(&line, &n, file); 1794439d473bSArnaldo Carvalho de Melo if (line_len < 0) 17956cfcc53eSMike Galbraith break; 17966cfcc53eSMike Galbraith 1797439d473bSArnaldo Carvalho de Melo if (!line) 1798439d473bSArnaldo Carvalho de Melo goto out_failure; 1799439d473bSArnaldo Carvalho de Melo 1800439d473bSArnaldo Carvalho de Melo line[--line_len] = '\0'; /* \n */ 1801439d473bSArnaldo Carvalho de Melo 1802439d473bSArnaldo Carvalho de Melo sep = strrchr(line, 'x'); 1803439d473bSArnaldo Carvalho de Melo if (sep == NULL) 1804439d473bSArnaldo Carvalho de Melo continue; 1805439d473bSArnaldo Carvalho de Melo 1806439d473bSArnaldo Carvalho de Melo hex2u64(sep + 1, &start); 1807439d473bSArnaldo Carvalho de Melo 1808439d473bSArnaldo Carvalho de Melo sep = strchr(line, ' '); 1809439d473bSArnaldo Carvalho de Melo if (sep == NULL) 1810439d473bSArnaldo Carvalho de Melo continue; 1811439d473bSArnaldo Carvalho de Melo 1812439d473bSArnaldo Carvalho de Melo *sep = '\0'; 1813439d473bSArnaldo Carvalho de Melo 1814439d473bSArnaldo Carvalho de Melo snprintf(name, sizeof(name), "[%s]", line); 1815d28c6223SArnaldo Carvalho de Melo map = machine__new_module(self, start, name); 1816b7cece76SArnaldo Carvalho de Melo if (map == NULL) 1817439d473bSArnaldo Carvalho de Melo goto out_delete_line; 1818d28c6223SArnaldo Carvalho de Melo dso__kernel_module_get_build_id(map->dso, self->root_dir); 18196cfcc53eSMike Galbraith } 18206cfcc53eSMike Galbraith 1821439d473bSArnaldo Carvalho de Melo free(line); 1822439d473bSArnaldo Carvalho de Melo fclose(file); 1823439d473bSArnaldo Carvalho de Melo 1824d28c6223SArnaldo Carvalho de Melo return machine__set_modules_path(self); 1825439d473bSArnaldo Carvalho de Melo 1826439d473bSArnaldo Carvalho de Melo out_delete_line: 1827439d473bSArnaldo Carvalho de Melo free(line); 1828439d473bSArnaldo Carvalho de Melo out_failure: 1829439d473bSArnaldo Carvalho de Melo return -1; 18306cfcc53eSMike Galbraith } 18316cfcc53eSMike Galbraith 1832fd930ff9SFranck Bui-Huu int dso__load_vmlinux(struct dso *self, struct map *map, 18336beba7adSArnaldo Carvalho de Melo const char *vmlinux, symbol_filter_t filter) 183486470930SIngo Molnar { 1835fbd733b8SArnaldo Carvalho de Melo int err = -1, fd; 1836ec5761eaSDavid Ahern char symfs_vmlinux[PATH_MAX]; 183786470930SIngo Molnar 1838ec5761eaSDavid Ahern snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s/%s", 1839ec5761eaSDavid Ahern symbol_conf.symfs, vmlinux); 1840ec5761eaSDavid Ahern fd = open(symfs_vmlinux, O_RDONLY); 184186470930SIngo Molnar if (fd < 0) 184286470930SIngo Molnar return -1; 184386470930SIngo Molnar 18443610583cSArnaldo Carvalho de Melo dso__set_loaded(self, map->type); 1845ec5761eaSDavid Ahern err = dso__load_sym(self, map, symfs_vmlinux, fd, filter, 0, 0); 184686470930SIngo Molnar close(fd); 184786470930SIngo Molnar 18483846df2eSArnaldo Carvalho de Melo if (err > 0) 1849ec5761eaSDavid Ahern pr_debug("Using %s for symbols\n", symfs_vmlinux); 18503846df2eSArnaldo Carvalho de Melo 185186470930SIngo Molnar return err; 185286470930SIngo Molnar } 185386470930SIngo Molnar 1854a19afe46SArnaldo Carvalho de Melo int dso__load_vmlinux_path(struct dso *self, struct map *map, 18559de89fe7SArnaldo Carvalho de Melo symbol_filter_t filter) 1856a19afe46SArnaldo Carvalho de Melo { 1857a19afe46SArnaldo Carvalho de Melo int i, err = 0; 18585ad90e4eSArnaldo Carvalho de Melo char *filename; 1859a19afe46SArnaldo Carvalho de Melo 1860a19afe46SArnaldo Carvalho de Melo pr_debug("Looking at the vmlinux_path (%d entries long)\n", 18615ad90e4eSArnaldo Carvalho de Melo vmlinux_path__nr_entries + 1); 18625ad90e4eSArnaldo Carvalho de Melo 18635ad90e4eSArnaldo Carvalho de Melo filename = dso__build_id_filename(self, NULL, 0); 18645ad90e4eSArnaldo Carvalho de Melo if (filename != NULL) { 18655ad90e4eSArnaldo Carvalho de Melo err = dso__load_vmlinux(self, map, filename, filter); 18665ad90e4eSArnaldo Carvalho de Melo if (err > 0) { 18675ad90e4eSArnaldo Carvalho de Melo dso__set_long_name(self, filename); 18685ad90e4eSArnaldo Carvalho de Melo goto out; 18695ad90e4eSArnaldo Carvalho de Melo } 18705ad90e4eSArnaldo Carvalho de Melo free(filename); 18715ad90e4eSArnaldo Carvalho de Melo } 1872a19afe46SArnaldo Carvalho de Melo 1873a19afe46SArnaldo Carvalho de Melo for (i = 0; i < vmlinux_path__nr_entries; ++i) { 18749de89fe7SArnaldo Carvalho de Melo err = dso__load_vmlinux(self, map, vmlinux_path[i], filter); 1875a19afe46SArnaldo Carvalho de Melo if (err > 0) { 1876a19afe46SArnaldo Carvalho de Melo dso__set_long_name(self, strdup(vmlinux_path[i])); 1877a19afe46SArnaldo Carvalho de Melo break; 1878a19afe46SArnaldo Carvalho de Melo } 1879a19afe46SArnaldo Carvalho de Melo } 18805ad90e4eSArnaldo Carvalho de Melo out: 1881a19afe46SArnaldo Carvalho de Melo return err; 1882a19afe46SArnaldo Carvalho de Melo } 1883a19afe46SArnaldo Carvalho de Melo 1884c338aee8SArnaldo Carvalho de Melo static int dso__load_kernel_sym(struct dso *self, struct map *map, 18859de89fe7SArnaldo Carvalho de Melo symbol_filter_t filter) 188686470930SIngo Molnar { 1887cc612d81SArnaldo Carvalho de Melo int err; 18889e201442SArnaldo Carvalho de Melo const char *kallsyms_filename = NULL; 18899e201442SArnaldo Carvalho de Melo char *kallsyms_allocated_filename = NULL; 1890dc8d6ab2SArnaldo Carvalho de Melo /* 1891b226a5a7SDavid Ahern * Step 1: if the user specified a kallsyms or vmlinux filename, use 1892b226a5a7SDavid Ahern * it and only it, reporting errors to the user if it cannot be used. 1893dc8d6ab2SArnaldo Carvalho de Melo * 1894dc8d6ab2SArnaldo Carvalho de Melo * For instance, try to analyse an ARM perf.data file _without_ a 1895dc8d6ab2SArnaldo Carvalho de Melo * build-id, or if the user specifies the wrong path to the right 1896dc8d6ab2SArnaldo Carvalho de Melo * vmlinux file, obviously we can't fallback to another vmlinux (a 1897dc8d6ab2SArnaldo Carvalho de Melo * x86_86 one, on the machine where analysis is being performed, say), 1898dc8d6ab2SArnaldo Carvalho de Melo * or worse, /proc/kallsyms. 1899dc8d6ab2SArnaldo Carvalho de Melo * 1900dc8d6ab2SArnaldo Carvalho de Melo * If the specified file _has_ a build-id and there is a build-id 1901dc8d6ab2SArnaldo Carvalho de Melo * section in the perf.data file, we will still do the expected 1902dc8d6ab2SArnaldo Carvalho de Melo * validation in dso__load_vmlinux and will bail out if they don't 1903dc8d6ab2SArnaldo Carvalho de Melo * match. 1904dc8d6ab2SArnaldo Carvalho de Melo */ 1905b226a5a7SDavid Ahern if (symbol_conf.kallsyms_name != NULL) { 1906b226a5a7SDavid Ahern kallsyms_filename = symbol_conf.kallsyms_name; 1907b226a5a7SDavid Ahern goto do_kallsyms; 1908b226a5a7SDavid Ahern } 1909b226a5a7SDavid Ahern 1910dc8d6ab2SArnaldo Carvalho de Melo if (symbol_conf.vmlinux_name != NULL) { 19119de89fe7SArnaldo Carvalho de Melo err = dso__load_vmlinux(self, map, 1912dc8d6ab2SArnaldo Carvalho de Melo symbol_conf.vmlinux_name, filter); 1913e7dadc00SArnaldo Carvalho de Melo if (err > 0) { 1914e7dadc00SArnaldo Carvalho de Melo dso__set_long_name(self, 1915e7dadc00SArnaldo Carvalho de Melo strdup(symbol_conf.vmlinux_name)); 1916e7dadc00SArnaldo Carvalho de Melo goto out_fixup; 1917e7dadc00SArnaldo Carvalho de Melo } 1918e7dadc00SArnaldo Carvalho de Melo return err; 1919dc8d6ab2SArnaldo Carvalho de Melo } 1920439d473bSArnaldo Carvalho de Melo 1921cc612d81SArnaldo Carvalho de Melo if (vmlinux_path != NULL) { 19229de89fe7SArnaldo Carvalho de Melo err = dso__load_vmlinux_path(self, map, filter); 1923a19afe46SArnaldo Carvalho de Melo if (err > 0) 1924cc612d81SArnaldo Carvalho de Melo goto out_fixup; 1925cc612d81SArnaldo Carvalho de Melo } 1926cc612d81SArnaldo Carvalho de Melo 1927ec5761eaSDavid Ahern /* do not try local files if a symfs was given */ 1928ec5761eaSDavid Ahern if (symbol_conf.symfs[0] != 0) 1929ec5761eaSDavid Ahern return -1; 1930ec5761eaSDavid Ahern 1931b7cece76SArnaldo Carvalho de Melo /* 1932b7cece76SArnaldo Carvalho de Melo * Say the kernel DSO was created when processing the build-id header table, 1933b7cece76SArnaldo Carvalho de Melo * we have a build-id, so check if it is the same as the running kernel, 1934b7cece76SArnaldo Carvalho de Melo * using it if it is. 1935b7cece76SArnaldo Carvalho de Melo */ 1936b7cece76SArnaldo Carvalho de Melo if (self->has_build_id) { 1937b7cece76SArnaldo Carvalho de Melo u8 kallsyms_build_id[BUILD_ID_SIZE]; 19389e201442SArnaldo Carvalho de Melo char sbuild_id[BUILD_ID_SIZE * 2 + 1]; 1939b7cece76SArnaldo Carvalho de Melo 1940b7cece76SArnaldo Carvalho de Melo if (sysfs__read_build_id("/sys/kernel/notes", kallsyms_build_id, 19418d0591f6SArnaldo Carvalho de Melo sizeof(kallsyms_build_id)) == 0) { 19429e201442SArnaldo Carvalho de Melo if (dso__build_id_equal(self, kallsyms_build_id)) { 19439e201442SArnaldo Carvalho de Melo kallsyms_filename = "/proc/kallsyms"; 1944b7cece76SArnaldo Carvalho de Melo goto do_kallsyms; 19458d0591f6SArnaldo Carvalho de Melo } 19469e201442SArnaldo Carvalho de Melo } 1947dc8d6ab2SArnaldo Carvalho de Melo /* 1948dc8d6ab2SArnaldo Carvalho de Melo * Now look if we have it on the build-id cache in 1949dc8d6ab2SArnaldo Carvalho de Melo * $HOME/.debug/[kernel.kallsyms]. 1950dc8d6ab2SArnaldo Carvalho de Melo */ 19519e201442SArnaldo Carvalho de Melo build_id__sprintf(self->build_id, sizeof(self->build_id), 19529e201442SArnaldo Carvalho de Melo sbuild_id); 19539e201442SArnaldo Carvalho de Melo 19549e201442SArnaldo Carvalho de Melo if (asprintf(&kallsyms_allocated_filename, 19559e201442SArnaldo Carvalho de Melo "%s/.debug/[kernel.kallsyms]/%s", 19563846df2eSArnaldo Carvalho de Melo getenv("HOME"), sbuild_id) == -1) { 19573846df2eSArnaldo Carvalho de Melo pr_err("Not enough memory for kallsyms file lookup\n"); 19588d0591f6SArnaldo Carvalho de Melo return -1; 19593846df2eSArnaldo Carvalho de Melo } 19608d0591f6SArnaldo Carvalho de Melo 196119fc2dedSArnaldo Carvalho de Melo kallsyms_filename = kallsyms_allocated_filename; 196219fc2dedSArnaldo Carvalho de Melo 1963dc8d6ab2SArnaldo Carvalho de Melo if (access(kallsyms_filename, F_OK)) { 19643846df2eSArnaldo Carvalho de Melo pr_err("No kallsyms or vmlinux with build-id %s " 19653846df2eSArnaldo Carvalho de Melo "was found\n", sbuild_id); 19669e201442SArnaldo Carvalho de Melo free(kallsyms_allocated_filename); 1967dc8d6ab2SArnaldo Carvalho de Melo return -1; 1968ef6ae724SArnaldo Carvalho de Melo } 1969dc8d6ab2SArnaldo Carvalho de Melo } else { 1970dc8d6ab2SArnaldo Carvalho de Melo /* 1971dc8d6ab2SArnaldo Carvalho de Melo * Last resort, if we don't have a build-id and couldn't find 1972dc8d6ab2SArnaldo Carvalho de Melo * any vmlinux file, try the running kernel kallsyms table. 1973dc8d6ab2SArnaldo Carvalho de Melo */ 1974dc8d6ab2SArnaldo Carvalho de Melo kallsyms_filename = "/proc/kallsyms"; 1975dc8d6ab2SArnaldo Carvalho de Melo } 1976dc8d6ab2SArnaldo Carvalho de Melo 1977dc8d6ab2SArnaldo Carvalho de Melo do_kallsyms: 19789de89fe7SArnaldo Carvalho de Melo err = dso__load_kallsyms(self, kallsyms_filename, map, filter); 19793846df2eSArnaldo Carvalho de Melo if (err > 0) 19803846df2eSArnaldo Carvalho de Melo pr_debug("Using %s for symbols\n", kallsyms_filename); 1981dc8d6ab2SArnaldo Carvalho de Melo free(kallsyms_allocated_filename); 1982dc8d6ab2SArnaldo Carvalho de Melo 1983439d473bSArnaldo Carvalho de Melo if (err > 0) { 1984cc612d81SArnaldo Carvalho de Melo out_fixup: 1985e1c7c6a4SArnaldo Carvalho de Melo if (kallsyms_filename != NULL) 1986dc8d6ab2SArnaldo Carvalho de Melo dso__set_long_name(self, strdup("[kernel.kallsyms]")); 19876a4694a4SArnaldo Carvalho de Melo map__fixup_start(map); 19886a4694a4SArnaldo Carvalho de Melo map__fixup_end(map); 1989439d473bSArnaldo Carvalho de Melo } 199094cb9e38SArnaldo Carvalho de Melo 199186470930SIngo Molnar return err; 199286470930SIngo Molnar } 199386470930SIngo Molnar 1994a1645ce1SZhang, Yanmin static int dso__load_guest_kernel_sym(struct dso *self, struct map *map, 1995a1645ce1SZhang, Yanmin symbol_filter_t filter) 1996a1645ce1SZhang, Yanmin { 1997a1645ce1SZhang, Yanmin int err; 1998a1645ce1SZhang, Yanmin const char *kallsyms_filename = NULL; 199923346f21SArnaldo Carvalho de Melo struct machine *machine; 2000a1645ce1SZhang, Yanmin char path[PATH_MAX]; 2001a1645ce1SZhang, Yanmin 2002a1645ce1SZhang, Yanmin if (!map->groups) { 2003a1645ce1SZhang, Yanmin pr_debug("Guest kernel map hasn't the point to groups\n"); 2004a1645ce1SZhang, Yanmin return -1; 2005a1645ce1SZhang, Yanmin } 200623346f21SArnaldo Carvalho de Melo machine = map->groups->machine; 2007a1645ce1SZhang, Yanmin 200823346f21SArnaldo Carvalho de Melo if (machine__is_default_guest(machine)) { 2009a1645ce1SZhang, Yanmin /* 2010a1645ce1SZhang, Yanmin * if the user specified a vmlinux filename, use it and only 2011a1645ce1SZhang, Yanmin * it, reporting errors to the user if it cannot be used. 2012a1645ce1SZhang, Yanmin * Or use file guest_kallsyms inputted by user on commandline 2013a1645ce1SZhang, Yanmin */ 2014a1645ce1SZhang, Yanmin if (symbol_conf.default_guest_vmlinux_name != NULL) { 2015a1645ce1SZhang, Yanmin err = dso__load_vmlinux(self, map, 2016a1645ce1SZhang, Yanmin symbol_conf.default_guest_vmlinux_name, filter); 2017a1645ce1SZhang, Yanmin goto out_try_fixup; 2018a1645ce1SZhang, Yanmin } 2019a1645ce1SZhang, Yanmin 2020a1645ce1SZhang, Yanmin kallsyms_filename = symbol_conf.default_guest_kallsyms; 2021a1645ce1SZhang, Yanmin if (!kallsyms_filename) 2022a1645ce1SZhang, Yanmin return -1; 2023a1645ce1SZhang, Yanmin } else { 202423346f21SArnaldo Carvalho de Melo sprintf(path, "%s/proc/kallsyms", machine->root_dir); 2025a1645ce1SZhang, Yanmin kallsyms_filename = path; 2026a1645ce1SZhang, Yanmin } 2027a1645ce1SZhang, Yanmin 2028a1645ce1SZhang, Yanmin err = dso__load_kallsyms(self, kallsyms_filename, map, filter); 2029a1645ce1SZhang, Yanmin if (err > 0) 2030a1645ce1SZhang, Yanmin pr_debug("Using %s for symbols\n", kallsyms_filename); 2031a1645ce1SZhang, Yanmin 2032a1645ce1SZhang, Yanmin out_try_fixup: 2033a1645ce1SZhang, Yanmin if (err > 0) { 2034a1645ce1SZhang, Yanmin if (kallsyms_filename != NULL) { 203548ea8f54SArnaldo Carvalho de Melo machine__mmap_name(machine, path, sizeof(path)); 203623346f21SArnaldo Carvalho de Melo dso__set_long_name(self, strdup(path)); 2037a1645ce1SZhang, Yanmin } 2038a1645ce1SZhang, Yanmin map__fixup_start(map); 2039a1645ce1SZhang, Yanmin map__fixup_end(map); 2040a1645ce1SZhang, Yanmin } 2041a1645ce1SZhang, Yanmin 2042a1645ce1SZhang, Yanmin return err; 2043a1645ce1SZhang, Yanmin } 2044cd84c2acSFrederic Weisbecker 2045b0da954aSArnaldo Carvalho de Melo static void dsos__add(struct list_head *head, struct dso *dso) 2046cd84c2acSFrederic Weisbecker { 2047b0da954aSArnaldo Carvalho de Melo list_add_tail(&dso->node, head); 2048cd84c2acSFrederic Weisbecker } 2049cd84c2acSFrederic Weisbecker 2050b0da954aSArnaldo Carvalho de Melo static struct dso *dsos__find(struct list_head *head, const char *name) 2051cd84c2acSFrederic Weisbecker { 2052cd84c2acSFrederic Weisbecker struct dso *pos; 2053cd84c2acSFrederic Weisbecker 2054b0da954aSArnaldo Carvalho de Melo list_for_each_entry(pos, head, node) 2055cf4e5b08SArnaldo Carvalho de Melo if (strcmp(pos->long_name, name) == 0) 2056cd84c2acSFrederic Weisbecker return pos; 2057cd84c2acSFrederic Weisbecker return NULL; 2058cd84c2acSFrederic Weisbecker } 2059cd84c2acSFrederic Weisbecker 2060a89e5abeSArnaldo Carvalho de Melo struct dso *__dsos__findnew(struct list_head *head, const char *name) 2061cd84c2acSFrederic Weisbecker { 2062a89e5abeSArnaldo Carvalho de Melo struct dso *dso = dsos__find(head, name); 2063cd84c2acSFrederic Weisbecker 2064e4204992SArnaldo Carvalho de Melo if (!dso) { 206500a192b3SArnaldo Carvalho de Melo dso = dso__new(name); 2066cfc10d3bSArnaldo Carvalho de Melo if (dso != NULL) { 2067a89e5abeSArnaldo Carvalho de Melo dsos__add(head, dso); 2068cfc10d3bSArnaldo Carvalho de Melo dso__set_basename(dso); 2069cfc10d3bSArnaldo Carvalho de Melo } 2070e4204992SArnaldo Carvalho de Melo } 2071cd84c2acSFrederic Weisbecker 2072cd84c2acSFrederic Weisbecker return dso; 2073cd84c2acSFrederic Weisbecker } 2074cd84c2acSFrederic Weisbecker 20751f626bc3SArnaldo Carvalho de Melo size_t __dsos__fprintf(struct list_head *head, FILE *fp) 2076cd84c2acSFrederic Weisbecker { 2077cd84c2acSFrederic Weisbecker struct dso *pos; 2078cbf69680SArnaldo Carvalho de Melo size_t ret = 0; 2079cd84c2acSFrederic Weisbecker 208095011c60SArnaldo Carvalho de Melo list_for_each_entry(pos, head, node) { 208195011c60SArnaldo Carvalho de Melo int i; 208295011c60SArnaldo Carvalho de Melo for (i = 0; i < MAP__NR_TYPES; ++i) 2083cbf69680SArnaldo Carvalho de Melo ret += dso__fprintf(pos, i, fp); 2084cd84c2acSFrederic Weisbecker } 2085cd84c2acSFrederic Weisbecker 2086cbf69680SArnaldo Carvalho de Melo return ret; 2087cbf69680SArnaldo Carvalho de Melo } 2088cbf69680SArnaldo Carvalho de Melo 2089cbf69680SArnaldo Carvalho de Melo size_t machines__fprintf_dsos(struct rb_root *self, FILE *fp) 2090b0da954aSArnaldo Carvalho de Melo { 2091a1645ce1SZhang, Yanmin struct rb_node *nd; 2092cbf69680SArnaldo Carvalho de Melo size_t ret = 0; 2093a1645ce1SZhang, Yanmin 2094cbf69680SArnaldo Carvalho de Melo for (nd = rb_first(self); nd; nd = rb_next(nd)) { 209523346f21SArnaldo Carvalho de Melo struct machine *pos = rb_entry(nd, struct machine, rb_node); 2096cbf69680SArnaldo Carvalho de Melo ret += __dsos__fprintf(&pos->kernel_dsos, fp); 2097cbf69680SArnaldo Carvalho de Melo ret += __dsos__fprintf(&pos->user_dsos, fp); 2098a1645ce1SZhang, Yanmin } 2099cbf69680SArnaldo Carvalho de Melo 2100cbf69680SArnaldo Carvalho de Melo return ret; 2101b0da954aSArnaldo Carvalho de Melo } 2102b0da954aSArnaldo Carvalho de Melo 210388d3d9b7SArnaldo Carvalho de Melo static size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp, 210488d3d9b7SArnaldo Carvalho de Melo bool with_hits) 21059e03eb2dSArnaldo Carvalho de Melo { 21069e03eb2dSArnaldo Carvalho de Melo struct dso *pos; 21079e03eb2dSArnaldo Carvalho de Melo size_t ret = 0; 21089e03eb2dSArnaldo Carvalho de Melo 2109b0da954aSArnaldo Carvalho de Melo list_for_each_entry(pos, head, node) { 211088d3d9b7SArnaldo Carvalho de Melo if (with_hits && !pos->hit) 211188d3d9b7SArnaldo Carvalho de Melo continue; 21129e03eb2dSArnaldo Carvalho de Melo ret += dso__fprintf_buildid(pos, fp); 21139e03eb2dSArnaldo Carvalho de Melo ret += fprintf(fp, " %s\n", pos->long_name); 21149e03eb2dSArnaldo Carvalho de Melo } 21159e03eb2dSArnaldo Carvalho de Melo return ret; 21169e03eb2dSArnaldo Carvalho de Melo } 21179e03eb2dSArnaldo Carvalho de Melo 2118f869097eSArnaldo Carvalho de Melo size_t machine__fprintf_dsos_buildid(struct machine *self, FILE *fp, bool with_hits) 2119f869097eSArnaldo Carvalho de Melo { 2120f869097eSArnaldo Carvalho de Melo return __dsos__fprintf_buildid(&self->kernel_dsos, fp, with_hits) + 2121f869097eSArnaldo Carvalho de Melo __dsos__fprintf_buildid(&self->user_dsos, fp, with_hits); 2122f869097eSArnaldo Carvalho de Melo } 2123f869097eSArnaldo Carvalho de Melo 2124cbf69680SArnaldo Carvalho de Melo size_t machines__fprintf_dsos_buildid(struct rb_root *self, FILE *fp, bool with_hits) 2125b0da954aSArnaldo Carvalho de Melo { 2126a1645ce1SZhang, Yanmin struct rb_node *nd; 2127a1645ce1SZhang, Yanmin size_t ret = 0; 2128a1645ce1SZhang, Yanmin 2129cbf69680SArnaldo Carvalho de Melo for (nd = rb_first(self); nd; nd = rb_next(nd)) { 213023346f21SArnaldo Carvalho de Melo struct machine *pos = rb_entry(nd, struct machine, rb_node); 2131f869097eSArnaldo Carvalho de Melo ret += machine__fprintf_dsos_buildid(pos, fp, with_hits); 2132a1645ce1SZhang, Yanmin } 2133a1645ce1SZhang, Yanmin return ret; 2134b0da954aSArnaldo Carvalho de Melo } 2135b0da954aSArnaldo Carvalho de Melo 2136fd1d908cSArnaldo Carvalho de Melo struct dso *dso__new_kernel(const char *name) 2137fd1d908cSArnaldo Carvalho de Melo { 2138fd1d908cSArnaldo Carvalho de Melo struct dso *self = dso__new(name ?: "[kernel.kallsyms]"); 2139fd1d908cSArnaldo Carvalho de Melo 2140fd1d908cSArnaldo Carvalho de Melo if (self != NULL) { 2141b63be8d7SArnaldo Carvalho de Melo dso__set_short_name(self, "[kernel]"); 2142a1645ce1SZhang, Yanmin self->kernel = DSO_TYPE_KERNEL; 2143fd1d908cSArnaldo Carvalho de Melo } 2144fd1d908cSArnaldo Carvalho de Melo 2145fd1d908cSArnaldo Carvalho de Melo return self; 2146fd1d908cSArnaldo Carvalho de Melo } 2147fd1d908cSArnaldo Carvalho de Melo 214823346f21SArnaldo Carvalho de Melo static struct dso *dso__new_guest_kernel(struct machine *machine, 2149a1645ce1SZhang, Yanmin const char *name) 2150fd1d908cSArnaldo Carvalho de Melo { 215148ea8f54SArnaldo Carvalho de Melo char bf[PATH_MAX]; 215248ea8f54SArnaldo Carvalho de Melo struct dso *self = dso__new(name ?: machine__mmap_name(machine, bf, sizeof(bf))); 2153a1645ce1SZhang, Yanmin 2154a1645ce1SZhang, Yanmin if (self != NULL) { 2155a1645ce1SZhang, Yanmin dso__set_short_name(self, "[guest.kernel]"); 2156a1645ce1SZhang, Yanmin self->kernel = DSO_TYPE_GUEST_KERNEL; 2157a1645ce1SZhang, Yanmin } 2158a1645ce1SZhang, Yanmin 2159a1645ce1SZhang, Yanmin return self; 2160a1645ce1SZhang, Yanmin } 2161a1645ce1SZhang, Yanmin 216223346f21SArnaldo Carvalho de Melo void dso__read_running_kernel_build_id(struct dso *self, struct machine *machine) 2163a1645ce1SZhang, Yanmin { 2164a1645ce1SZhang, Yanmin char path[PATH_MAX]; 2165a1645ce1SZhang, Yanmin 216623346f21SArnaldo Carvalho de Melo if (machine__is_default_guest(machine)) 2167a1645ce1SZhang, Yanmin return; 216823346f21SArnaldo Carvalho de Melo sprintf(path, "%s/sys/kernel/notes", machine->root_dir); 2169a1645ce1SZhang, Yanmin if (sysfs__read_build_id(path, self->build_id, 2170fd1d908cSArnaldo Carvalho de Melo sizeof(self->build_id)) == 0) 2171fd1d908cSArnaldo Carvalho de Melo self->has_build_id = true; 2172fd1d908cSArnaldo Carvalho de Melo } 2173fd1d908cSArnaldo Carvalho de Melo 21745c0541d5SArnaldo Carvalho de Melo static struct dso *machine__create_kernel(struct machine *self) 2175cd84c2acSFrederic Weisbecker { 2176a1645ce1SZhang, Yanmin const char *vmlinux_name = NULL; 2177a1645ce1SZhang, Yanmin struct dso *kernel; 2178cd84c2acSFrederic Weisbecker 21795c0541d5SArnaldo Carvalho de Melo if (machine__is_host(self)) { 2180a1645ce1SZhang, Yanmin vmlinux_name = symbol_conf.vmlinux_name; 2181a1645ce1SZhang, Yanmin kernel = dso__new_kernel(vmlinux_name); 2182a1645ce1SZhang, Yanmin } else { 21835c0541d5SArnaldo Carvalho de Melo if (machine__is_default_guest(self)) 2184a1645ce1SZhang, Yanmin vmlinux_name = symbol_conf.default_guest_vmlinux_name; 21855c0541d5SArnaldo Carvalho de Melo kernel = dso__new_guest_kernel(self, vmlinux_name); 21868d92c02aSArnaldo Carvalho de Melo } 2187cd84c2acSFrederic Weisbecker 2188a1645ce1SZhang, Yanmin if (kernel != NULL) { 21895c0541d5SArnaldo Carvalho de Melo dso__read_running_kernel_build_id(kernel, self); 21905c0541d5SArnaldo Carvalho de Melo dsos__add(&self->kernel_dsos, kernel); 2191a1645ce1SZhang, Yanmin } 2192f1dfa0b1SArnaldo Carvalho de Melo return kernel; 2193f1dfa0b1SArnaldo Carvalho de Melo } 2194f1dfa0b1SArnaldo Carvalho de Melo 2195d214afbdSMing Lei struct process_args { 2196d214afbdSMing Lei u64 start; 2197d214afbdSMing Lei }; 2198d214afbdSMing Lei 2199d214afbdSMing Lei static int symbol__in_kernel(void *arg, const char *name, 22003b01a413SArnaldo Carvalho de Melo char type __used, u64 start, u64 end __used) 2201d214afbdSMing Lei { 2202d214afbdSMing Lei struct process_args *args = arg; 2203d214afbdSMing Lei 2204d214afbdSMing Lei if (strchr(name, '[')) 2205d214afbdSMing Lei return 0; 2206d214afbdSMing Lei 2207d214afbdSMing Lei args->start = start; 2208d214afbdSMing Lei return 1; 2209d214afbdSMing Lei } 2210d214afbdSMing Lei 2211d214afbdSMing Lei /* Figure out the start address of kernel map from /proc/kallsyms */ 2212d214afbdSMing Lei static u64 machine__get_kernel_start_addr(struct machine *machine) 2213d214afbdSMing Lei { 2214d214afbdSMing Lei const char *filename; 2215d214afbdSMing Lei char path[PATH_MAX]; 2216d214afbdSMing Lei struct process_args args; 2217d214afbdSMing Lei 2218d214afbdSMing Lei if (machine__is_host(machine)) { 2219d214afbdSMing Lei filename = "/proc/kallsyms"; 2220d214afbdSMing Lei } else { 2221d214afbdSMing Lei if (machine__is_default_guest(machine)) 2222d214afbdSMing Lei filename = (char *)symbol_conf.default_guest_kallsyms; 2223d214afbdSMing Lei else { 2224d214afbdSMing Lei sprintf(path, "%s/proc/kallsyms", machine->root_dir); 2225d214afbdSMing Lei filename = path; 2226d214afbdSMing Lei } 2227d214afbdSMing Lei } 2228d214afbdSMing Lei 2229d214afbdSMing Lei if (kallsyms__parse(filename, &args, symbol__in_kernel) <= 0) 2230d214afbdSMing Lei return 0; 2231d214afbdSMing Lei 2232d214afbdSMing Lei return args.start; 2233d214afbdSMing Lei } 2234d214afbdSMing Lei 2235d28c6223SArnaldo Carvalho de Melo int __machine__create_kernel_maps(struct machine *self, struct dso *kernel) 2236f1dfa0b1SArnaldo Carvalho de Melo { 2237de176489SArnaldo Carvalho de Melo enum map_type type; 2238d214afbdSMing Lei u64 start = machine__get_kernel_start_addr(self); 2239f1dfa0b1SArnaldo Carvalho de Melo 2240de176489SArnaldo Carvalho de Melo for (type = 0; type < MAP__NR_TYPES; ++type) { 22419de89fe7SArnaldo Carvalho de Melo struct kmap *kmap; 22429de89fe7SArnaldo Carvalho de Melo 2243d214afbdSMing Lei self->vmlinux_maps[type] = map__new2(start, kernel, type); 2244d28c6223SArnaldo Carvalho de Melo if (self->vmlinux_maps[type] == NULL) 2245f1dfa0b1SArnaldo Carvalho de Melo return -1; 2246f1dfa0b1SArnaldo Carvalho de Melo 2247d28c6223SArnaldo Carvalho de Melo self->vmlinux_maps[type]->map_ip = 2248d28c6223SArnaldo Carvalho de Melo self->vmlinux_maps[type]->unmap_ip = identity__map_ip; 22499de89fe7SArnaldo Carvalho de Melo 2250d28c6223SArnaldo Carvalho de Melo kmap = map__kmap(self->vmlinux_maps[type]); 2251d28c6223SArnaldo Carvalho de Melo kmap->kmaps = &self->kmaps; 2252d28c6223SArnaldo Carvalho de Melo map_groups__insert(&self->kmaps, self->vmlinux_maps[type]); 2253f1dfa0b1SArnaldo Carvalho de Melo } 2254f1dfa0b1SArnaldo Carvalho de Melo 2255f1dfa0b1SArnaldo Carvalho de Melo return 0; 22562446042cSArnaldo Carvalho de Melo } 22572446042cSArnaldo Carvalho de Melo 2258076c6e45SArnaldo Carvalho de Melo void machine__destroy_kernel_maps(struct machine *self) 2259076c6e45SArnaldo Carvalho de Melo { 2260076c6e45SArnaldo Carvalho de Melo enum map_type type; 2261076c6e45SArnaldo Carvalho de Melo 2262076c6e45SArnaldo Carvalho de Melo for (type = 0; type < MAP__NR_TYPES; ++type) { 2263076c6e45SArnaldo Carvalho de Melo struct kmap *kmap; 2264076c6e45SArnaldo Carvalho de Melo 2265076c6e45SArnaldo Carvalho de Melo if (self->vmlinux_maps[type] == NULL) 2266076c6e45SArnaldo Carvalho de Melo continue; 2267076c6e45SArnaldo Carvalho de Melo 2268076c6e45SArnaldo Carvalho de Melo kmap = map__kmap(self->vmlinux_maps[type]); 2269076c6e45SArnaldo Carvalho de Melo map_groups__remove(&self->kmaps, self->vmlinux_maps[type]); 2270076c6e45SArnaldo Carvalho de Melo if (kmap->ref_reloc_sym) { 2271076c6e45SArnaldo Carvalho de Melo /* 2272076c6e45SArnaldo Carvalho de Melo * ref_reloc_sym is shared among all maps, so free just 2273076c6e45SArnaldo Carvalho de Melo * on one of them. 2274076c6e45SArnaldo Carvalho de Melo */ 2275076c6e45SArnaldo Carvalho de Melo if (type == MAP__FUNCTION) { 2276076c6e45SArnaldo Carvalho de Melo free((char *)kmap->ref_reloc_sym->name); 2277076c6e45SArnaldo Carvalho de Melo kmap->ref_reloc_sym->name = NULL; 2278076c6e45SArnaldo Carvalho de Melo free(kmap->ref_reloc_sym); 2279076c6e45SArnaldo Carvalho de Melo } 2280076c6e45SArnaldo Carvalho de Melo kmap->ref_reloc_sym = NULL; 2281076c6e45SArnaldo Carvalho de Melo } 2282076c6e45SArnaldo Carvalho de Melo 2283076c6e45SArnaldo Carvalho de Melo map__delete(self->vmlinux_maps[type]); 2284076c6e45SArnaldo Carvalho de Melo self->vmlinux_maps[type] = NULL; 2285076c6e45SArnaldo Carvalho de Melo } 2286076c6e45SArnaldo Carvalho de Melo } 2287076c6e45SArnaldo Carvalho de Melo 22885c0541d5SArnaldo Carvalho de Melo int machine__create_kernel_maps(struct machine *self) 22895c0541d5SArnaldo Carvalho de Melo { 22905c0541d5SArnaldo Carvalho de Melo struct dso *kernel = machine__create_kernel(self); 22915c0541d5SArnaldo Carvalho de Melo 22925c0541d5SArnaldo Carvalho de Melo if (kernel == NULL || 22935c0541d5SArnaldo Carvalho de Melo __machine__create_kernel_maps(self, kernel) < 0) 22945c0541d5SArnaldo Carvalho de Melo return -1; 22955c0541d5SArnaldo Carvalho de Melo 22965c0541d5SArnaldo Carvalho de Melo if (symbol_conf.use_modules && machine__create_modules(self) < 0) 22975c0541d5SArnaldo Carvalho de Melo pr_debug("Problems creating module maps, continuing anyway...\n"); 22985c0541d5SArnaldo Carvalho de Melo /* 22995c0541d5SArnaldo Carvalho de Melo * Now that we have all the maps created, just set the ->end of them: 23005c0541d5SArnaldo Carvalho de Melo */ 23015c0541d5SArnaldo Carvalho de Melo map_groups__fixup_end(&self->kmaps); 23025c0541d5SArnaldo Carvalho de Melo return 0; 23035c0541d5SArnaldo Carvalho de Melo } 23045c0541d5SArnaldo Carvalho de Melo 2305cc612d81SArnaldo Carvalho de Melo static void vmlinux_path__exit(void) 23062446042cSArnaldo Carvalho de Melo { 2307cc612d81SArnaldo Carvalho de Melo while (--vmlinux_path__nr_entries >= 0) { 2308cc612d81SArnaldo Carvalho de Melo free(vmlinux_path[vmlinux_path__nr_entries]); 2309cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = NULL; 2310cc612d81SArnaldo Carvalho de Melo } 2311cc612d81SArnaldo Carvalho de Melo 2312cc612d81SArnaldo Carvalho de Melo free(vmlinux_path); 2313cc612d81SArnaldo Carvalho de Melo vmlinux_path = NULL; 2314cc612d81SArnaldo Carvalho de Melo } 2315cc612d81SArnaldo Carvalho de Melo 2316cc612d81SArnaldo Carvalho de Melo static int vmlinux_path__init(void) 2317cc612d81SArnaldo Carvalho de Melo { 2318cc612d81SArnaldo Carvalho de Melo struct utsname uts; 2319cc612d81SArnaldo Carvalho de Melo char bf[PATH_MAX]; 2320cc612d81SArnaldo Carvalho de Melo 2321cc612d81SArnaldo Carvalho de Melo vmlinux_path = malloc(sizeof(char *) * 5); 2322cc612d81SArnaldo Carvalho de Melo if (vmlinux_path == NULL) 2323cc612d81SArnaldo Carvalho de Melo return -1; 2324cc612d81SArnaldo Carvalho de Melo 2325cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup("vmlinux"); 2326cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 2327cc612d81SArnaldo Carvalho de Melo goto out_fail; 2328cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 2329cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup("/boot/vmlinux"); 2330cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 2331cc612d81SArnaldo Carvalho de Melo goto out_fail; 2332cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 2333ec5761eaSDavid Ahern 2334ec5761eaSDavid Ahern /* only try running kernel version if no symfs was given */ 2335ec5761eaSDavid Ahern if (symbol_conf.symfs[0] != 0) 2336ec5761eaSDavid Ahern return 0; 2337ec5761eaSDavid Ahern 2338ec5761eaSDavid Ahern if (uname(&uts) < 0) 2339ec5761eaSDavid Ahern return -1; 2340ec5761eaSDavid Ahern 2341cc612d81SArnaldo Carvalho de Melo snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", uts.release); 2342cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); 2343cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 2344cc612d81SArnaldo Carvalho de Melo goto out_fail; 2345cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 2346cc612d81SArnaldo Carvalho de Melo snprintf(bf, sizeof(bf), "/lib/modules/%s/build/vmlinux", uts.release); 2347cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); 2348cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 2349cc612d81SArnaldo Carvalho de Melo goto out_fail; 2350cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 2351cc612d81SArnaldo Carvalho de Melo snprintf(bf, sizeof(bf), "/usr/lib/debug/lib/modules/%s/vmlinux", 2352cc612d81SArnaldo Carvalho de Melo uts.release); 2353cc612d81SArnaldo Carvalho de Melo vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); 2354cc612d81SArnaldo Carvalho de Melo if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 2355cc612d81SArnaldo Carvalho de Melo goto out_fail; 2356cc612d81SArnaldo Carvalho de Melo ++vmlinux_path__nr_entries; 2357cc612d81SArnaldo Carvalho de Melo 2358cc612d81SArnaldo Carvalho de Melo return 0; 2359cc612d81SArnaldo Carvalho de Melo 2360cc612d81SArnaldo Carvalho de Melo out_fail: 2361cc612d81SArnaldo Carvalho de Melo vmlinux_path__exit(); 2362cc612d81SArnaldo Carvalho de Melo return -1; 2363cc612d81SArnaldo Carvalho de Melo } 2364cc612d81SArnaldo Carvalho de Melo 23655ad90e4eSArnaldo Carvalho de Melo size_t machine__fprintf_vmlinux_path(struct machine *self, FILE *fp) 2366b0a9ab62SArnaldo Carvalho de Melo { 2367b0a9ab62SArnaldo Carvalho de Melo int i; 2368b0a9ab62SArnaldo Carvalho de Melo size_t printed = 0; 23695ad90e4eSArnaldo Carvalho de Melo struct dso *kdso = self->vmlinux_maps[MAP__FUNCTION]->dso; 23705ad90e4eSArnaldo Carvalho de Melo 23715ad90e4eSArnaldo Carvalho de Melo if (kdso->has_build_id) { 23725ad90e4eSArnaldo Carvalho de Melo char filename[PATH_MAX]; 23735ad90e4eSArnaldo Carvalho de Melo if (dso__build_id_filename(kdso, filename, sizeof(filename))) 23745ad90e4eSArnaldo Carvalho de Melo printed += fprintf(fp, "[0] %s\n", filename); 23755ad90e4eSArnaldo Carvalho de Melo } 2376b0a9ab62SArnaldo Carvalho de Melo 2377b0a9ab62SArnaldo Carvalho de Melo for (i = 0; i < vmlinux_path__nr_entries; ++i) 23785ad90e4eSArnaldo Carvalho de Melo printed += fprintf(fp, "[%d] %s\n", 23795ad90e4eSArnaldo Carvalho de Melo i + kdso->has_build_id, vmlinux_path[i]); 2380b0a9ab62SArnaldo Carvalho de Melo 2381b0a9ab62SArnaldo Carvalho de Melo return printed; 2382b0a9ab62SArnaldo Carvalho de Melo } 2383b0a9ab62SArnaldo Carvalho de Melo 2384655000e7SArnaldo Carvalho de Melo static int setup_list(struct strlist **list, const char *list_str, 2385655000e7SArnaldo Carvalho de Melo const char *list_name) 2386655000e7SArnaldo Carvalho de Melo { 2387655000e7SArnaldo Carvalho de Melo if (list_str == NULL) 2388655000e7SArnaldo Carvalho de Melo return 0; 2389655000e7SArnaldo Carvalho de Melo 2390655000e7SArnaldo Carvalho de Melo *list = strlist__new(true, list_str); 2391655000e7SArnaldo Carvalho de Melo if (!*list) { 2392655000e7SArnaldo Carvalho de Melo pr_err("problems parsing %s list\n", list_name); 2393655000e7SArnaldo Carvalho de Melo return -1; 2394655000e7SArnaldo Carvalho de Melo } 2395655000e7SArnaldo Carvalho de Melo return 0; 2396655000e7SArnaldo Carvalho de Melo } 2397655000e7SArnaldo Carvalho de Melo 239875be6cf4SArnaldo Carvalho de Melo int symbol__init(void) 2399cc612d81SArnaldo Carvalho de Melo { 2400ec5761eaSDavid Ahern const char *symfs; 2401ec5761eaSDavid Ahern 240285e00b55SJovi Zhang if (symbol_conf.initialized) 240385e00b55SJovi Zhang return 0; 240485e00b55SJovi Zhang 240595011c60SArnaldo Carvalho de Melo elf_version(EV_CURRENT); 240675be6cf4SArnaldo Carvalho de Melo if (symbol_conf.sort_by_name) 240775be6cf4SArnaldo Carvalho de Melo symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) - 240879406cd7SArnaldo Carvalho de Melo sizeof(struct symbol)); 2409b32d133aSArnaldo Carvalho de Melo 241075be6cf4SArnaldo Carvalho de Melo if (symbol_conf.try_vmlinux_path && vmlinux_path__init() < 0) 2411cc612d81SArnaldo Carvalho de Melo return -1; 2412cc612d81SArnaldo Carvalho de Melo 2413c410a338SArnaldo Carvalho de Melo if (symbol_conf.field_sep && *symbol_conf.field_sep == '.') { 2414c410a338SArnaldo Carvalho de Melo pr_err("'.' is the only non valid --field-separator argument\n"); 2415c410a338SArnaldo Carvalho de Melo return -1; 2416c410a338SArnaldo Carvalho de Melo } 2417c410a338SArnaldo Carvalho de Melo 2418655000e7SArnaldo Carvalho de Melo if (setup_list(&symbol_conf.dso_list, 2419655000e7SArnaldo Carvalho de Melo symbol_conf.dso_list_str, "dso") < 0) 2420655000e7SArnaldo Carvalho de Melo return -1; 2421655000e7SArnaldo Carvalho de Melo 2422655000e7SArnaldo Carvalho de Melo if (setup_list(&symbol_conf.comm_list, 2423655000e7SArnaldo Carvalho de Melo symbol_conf.comm_list_str, "comm") < 0) 2424655000e7SArnaldo Carvalho de Melo goto out_free_dso_list; 2425655000e7SArnaldo Carvalho de Melo 2426655000e7SArnaldo Carvalho de Melo if (setup_list(&symbol_conf.sym_list, 2427655000e7SArnaldo Carvalho de Melo symbol_conf.sym_list_str, "symbol") < 0) 2428655000e7SArnaldo Carvalho de Melo goto out_free_comm_list; 2429655000e7SArnaldo Carvalho de Melo 2430ec5761eaSDavid Ahern /* 2431ec5761eaSDavid Ahern * A path to symbols of "/" is identical to "" 2432ec5761eaSDavid Ahern * reset here for simplicity. 2433ec5761eaSDavid Ahern */ 2434ec5761eaSDavid Ahern symfs = realpath(symbol_conf.symfs, NULL); 2435ec5761eaSDavid Ahern if (symfs == NULL) 2436ec5761eaSDavid Ahern symfs = symbol_conf.symfs; 2437ec5761eaSDavid Ahern if (strcmp(symfs, "/") == 0) 2438ec5761eaSDavid Ahern symbol_conf.symfs = ""; 2439ec5761eaSDavid Ahern if (symfs != symbol_conf.symfs) 2440ec5761eaSDavid Ahern free((void *)symfs); 2441ec5761eaSDavid Ahern 244285e00b55SJovi Zhang symbol_conf.initialized = true; 24434aa65636SArnaldo Carvalho de Melo return 0; 2444655000e7SArnaldo Carvalho de Melo 2445655000e7SArnaldo Carvalho de Melo out_free_dso_list: 2446655000e7SArnaldo Carvalho de Melo strlist__delete(symbol_conf.dso_list); 2447655000e7SArnaldo Carvalho de Melo out_free_comm_list: 2448655000e7SArnaldo Carvalho de Melo strlist__delete(symbol_conf.comm_list); 2449655000e7SArnaldo Carvalho de Melo return -1; 2450cc612d81SArnaldo Carvalho de Melo } 2451cc612d81SArnaldo Carvalho de Melo 2452d65a458bSArnaldo Carvalho de Melo void symbol__exit(void) 2453d65a458bSArnaldo Carvalho de Melo { 245485e00b55SJovi Zhang if (!symbol_conf.initialized) 245585e00b55SJovi Zhang return; 2456d65a458bSArnaldo Carvalho de Melo strlist__delete(symbol_conf.sym_list); 2457d65a458bSArnaldo Carvalho de Melo strlist__delete(symbol_conf.dso_list); 2458d65a458bSArnaldo Carvalho de Melo strlist__delete(symbol_conf.comm_list); 2459d65a458bSArnaldo Carvalho de Melo vmlinux_path__exit(); 2460d65a458bSArnaldo Carvalho de Melo symbol_conf.sym_list = symbol_conf.dso_list = symbol_conf.comm_list = NULL; 246185e00b55SJovi Zhang symbol_conf.initialized = false; 2462d65a458bSArnaldo Carvalho de Melo } 2463d65a458bSArnaldo Carvalho de Melo 2464d28c6223SArnaldo Carvalho de Melo int machines__create_kernel_maps(struct rb_root *self, pid_t pid) 24654aa65636SArnaldo Carvalho de Melo { 2466d28c6223SArnaldo Carvalho de Melo struct machine *machine = machines__findnew(self, pid); 24679de89fe7SArnaldo Carvalho de Melo 246823346f21SArnaldo Carvalho de Melo if (machine == NULL) 2469a1645ce1SZhang, Yanmin return -1; 24704aa65636SArnaldo Carvalho de Melo 24715c0541d5SArnaldo Carvalho de Melo return machine__create_kernel_maps(machine); 2472cd84c2acSFrederic Weisbecker } 24735aab621bSArnaldo Carvalho de Melo 24745aab621bSArnaldo Carvalho de Melo static int hex(char ch) 24755aab621bSArnaldo Carvalho de Melo { 24765aab621bSArnaldo Carvalho de Melo if ((ch >= '0') && (ch <= '9')) 24775aab621bSArnaldo Carvalho de Melo return ch - '0'; 24785aab621bSArnaldo Carvalho de Melo if ((ch >= 'a') && (ch <= 'f')) 24795aab621bSArnaldo Carvalho de Melo return ch - 'a' + 10; 24805aab621bSArnaldo Carvalho de Melo if ((ch >= 'A') && (ch <= 'F')) 24815aab621bSArnaldo Carvalho de Melo return ch - 'A' + 10; 24825aab621bSArnaldo Carvalho de Melo return -1; 24835aab621bSArnaldo Carvalho de Melo } 24845aab621bSArnaldo Carvalho de Melo 24855aab621bSArnaldo Carvalho de Melo /* 24865aab621bSArnaldo Carvalho de Melo * While we find nice hex chars, build a long_val. 24875aab621bSArnaldo Carvalho de Melo * Return number of chars processed. 24885aab621bSArnaldo Carvalho de Melo */ 24895aab621bSArnaldo Carvalho de Melo int hex2u64(const char *ptr, u64 *long_val) 24905aab621bSArnaldo Carvalho de Melo { 24915aab621bSArnaldo Carvalho de Melo const char *p = ptr; 24925aab621bSArnaldo Carvalho de Melo *long_val = 0; 24935aab621bSArnaldo Carvalho de Melo 24945aab621bSArnaldo Carvalho de Melo while (*p) { 24955aab621bSArnaldo Carvalho de Melo const int hex_val = hex(*p); 24965aab621bSArnaldo Carvalho de Melo 24975aab621bSArnaldo Carvalho de Melo if (hex_val < 0) 24985aab621bSArnaldo Carvalho de Melo break; 24995aab621bSArnaldo Carvalho de Melo 25005aab621bSArnaldo Carvalho de Melo *long_val = (*long_val << 4) | hex_val; 25015aab621bSArnaldo Carvalho de Melo p++; 25025aab621bSArnaldo Carvalho de Melo } 25035aab621bSArnaldo Carvalho de Melo 25045aab621bSArnaldo Carvalho de Melo return p - ptr; 25055aab621bSArnaldo Carvalho de Melo } 25065aab621bSArnaldo Carvalho de Melo 25075aab621bSArnaldo Carvalho de Melo char *strxfrchar(char *s, char from, char to) 25085aab621bSArnaldo Carvalho de Melo { 25095aab621bSArnaldo Carvalho de Melo char *p = s; 25105aab621bSArnaldo Carvalho de Melo 25115aab621bSArnaldo Carvalho de Melo while ((p = strchr(p, from)) != NULL) 25125aab621bSArnaldo Carvalho de Melo *p++ = to; 25135aab621bSArnaldo Carvalho de Melo 25145aab621bSArnaldo Carvalho de Melo return s; 25155aab621bSArnaldo Carvalho de Melo } 2516a1645ce1SZhang, Yanmin 2517d28c6223SArnaldo Carvalho de Melo int machines__create_guest_kernel_maps(struct rb_root *self) 2518a1645ce1SZhang, Yanmin { 2519a1645ce1SZhang, Yanmin int ret = 0; 2520a1645ce1SZhang, Yanmin struct dirent **namelist = NULL; 2521a1645ce1SZhang, Yanmin int i, items = 0; 2522a1645ce1SZhang, Yanmin char path[PATH_MAX]; 2523a1645ce1SZhang, Yanmin pid_t pid; 2524a1645ce1SZhang, Yanmin 2525a1645ce1SZhang, Yanmin if (symbol_conf.default_guest_vmlinux_name || 2526a1645ce1SZhang, Yanmin symbol_conf.default_guest_modules || 2527a1645ce1SZhang, Yanmin symbol_conf.default_guest_kallsyms) { 2528d28c6223SArnaldo Carvalho de Melo machines__create_kernel_maps(self, DEFAULT_GUEST_KERNEL_ID); 2529a1645ce1SZhang, Yanmin } 2530a1645ce1SZhang, Yanmin 2531a1645ce1SZhang, Yanmin if (symbol_conf.guestmount) { 2532a1645ce1SZhang, Yanmin items = scandir(symbol_conf.guestmount, &namelist, NULL, NULL); 2533a1645ce1SZhang, Yanmin if (items <= 0) 2534a1645ce1SZhang, Yanmin return -ENOENT; 2535a1645ce1SZhang, Yanmin for (i = 0; i < items; i++) { 2536a1645ce1SZhang, Yanmin if (!isdigit(namelist[i]->d_name[0])) { 2537a1645ce1SZhang, Yanmin /* Filter out . and .. */ 2538a1645ce1SZhang, Yanmin continue; 2539a1645ce1SZhang, Yanmin } 2540a1645ce1SZhang, Yanmin pid = atoi(namelist[i]->d_name); 2541a1645ce1SZhang, Yanmin sprintf(path, "%s/%s/proc/kallsyms", 2542a1645ce1SZhang, Yanmin symbol_conf.guestmount, 2543a1645ce1SZhang, Yanmin namelist[i]->d_name); 2544a1645ce1SZhang, Yanmin ret = access(path, R_OK); 2545a1645ce1SZhang, Yanmin if (ret) { 2546a1645ce1SZhang, Yanmin pr_debug("Can't access file %s\n", path); 2547a1645ce1SZhang, Yanmin goto failure; 2548a1645ce1SZhang, Yanmin } 2549d28c6223SArnaldo Carvalho de Melo machines__create_kernel_maps(self, pid); 2550a1645ce1SZhang, Yanmin } 2551a1645ce1SZhang, Yanmin failure: 2552a1645ce1SZhang, Yanmin free(namelist); 2553a1645ce1SZhang, Yanmin } 2554a1645ce1SZhang, Yanmin 2555a1645ce1SZhang, Yanmin return ret; 2556a1645ce1SZhang, Yanmin } 25575c0541d5SArnaldo Carvalho de Melo 2558076c6e45SArnaldo Carvalho de Melo void machines__destroy_guest_kernel_maps(struct rb_root *self) 2559076c6e45SArnaldo Carvalho de Melo { 2560076c6e45SArnaldo Carvalho de Melo struct rb_node *next = rb_first(self); 2561076c6e45SArnaldo Carvalho de Melo 2562076c6e45SArnaldo Carvalho de Melo while (next) { 2563076c6e45SArnaldo Carvalho de Melo struct machine *pos = rb_entry(next, struct machine, rb_node); 2564076c6e45SArnaldo Carvalho de Melo 2565076c6e45SArnaldo Carvalho de Melo next = rb_next(&pos->rb_node); 2566076c6e45SArnaldo Carvalho de Melo rb_erase(&pos->rb_node, self); 2567076c6e45SArnaldo Carvalho de Melo machine__delete(pos); 2568076c6e45SArnaldo Carvalho de Melo } 2569076c6e45SArnaldo Carvalho de Melo } 2570076c6e45SArnaldo Carvalho de Melo 25715c0541d5SArnaldo Carvalho de Melo int machine__load_kallsyms(struct machine *self, const char *filename, 25725c0541d5SArnaldo Carvalho de Melo enum map_type type, symbol_filter_t filter) 25735c0541d5SArnaldo Carvalho de Melo { 25745c0541d5SArnaldo Carvalho de Melo struct map *map = self->vmlinux_maps[type]; 25755c0541d5SArnaldo Carvalho de Melo int ret = dso__load_kallsyms(map->dso, filename, map, filter); 25765c0541d5SArnaldo Carvalho de Melo 25775c0541d5SArnaldo Carvalho de Melo if (ret > 0) { 25785c0541d5SArnaldo Carvalho de Melo dso__set_loaded(map->dso, type); 25795c0541d5SArnaldo Carvalho de Melo /* 25805c0541d5SArnaldo Carvalho de Melo * Since /proc/kallsyms will have multiple sessions for the 25815c0541d5SArnaldo Carvalho de Melo * kernel, with modules between them, fixup the end of all 25825c0541d5SArnaldo Carvalho de Melo * sections. 25835c0541d5SArnaldo Carvalho de Melo */ 25845c0541d5SArnaldo Carvalho de Melo __map_groups__fixup_end(&self->kmaps, type); 25855c0541d5SArnaldo Carvalho de Melo } 25865c0541d5SArnaldo Carvalho de Melo 25875c0541d5SArnaldo Carvalho de Melo return ret; 25885c0541d5SArnaldo Carvalho de Melo } 25895c0541d5SArnaldo Carvalho de Melo 25905c0541d5SArnaldo Carvalho de Melo int machine__load_vmlinux_path(struct machine *self, enum map_type type, 25915c0541d5SArnaldo Carvalho de Melo symbol_filter_t filter) 25925c0541d5SArnaldo Carvalho de Melo { 25935c0541d5SArnaldo Carvalho de Melo struct map *map = self->vmlinux_maps[type]; 25945c0541d5SArnaldo Carvalho de Melo int ret = dso__load_vmlinux_path(map->dso, map, filter); 25955c0541d5SArnaldo Carvalho de Melo 25965c0541d5SArnaldo Carvalho de Melo if (ret > 0) { 25975c0541d5SArnaldo Carvalho de Melo dso__set_loaded(map->dso, type); 25985c0541d5SArnaldo Carvalho de Melo map__reloc_vmlinux(map); 25995c0541d5SArnaldo Carvalho de Melo } 26005c0541d5SArnaldo Carvalho de Melo 26015c0541d5SArnaldo Carvalho de Melo return ret; 26025c0541d5SArnaldo Carvalho de Melo } 2603