|
@@ -2,12 +2,14 @@
|
|
|
#include "../perf.h"
|
|
|
#include "string.h"
|
|
|
#include "symbol.h"
|
|
|
+#include "thread.h"
|
|
|
|
|
|
#include "debug.h"
|
|
|
|
|
|
#include <libelf.h>
|
|
|
#include <gelf.h>
|
|
|
#include <elf.h>
|
|
|
+#include <sys/utsname.h>
|
|
|
|
|
|
const char *sym_hist_filter;
|
|
|
|
|
@@ -18,12 +20,15 @@ enum dso_origin {
|
|
|
DSO__ORIG_UBUNTU,
|
|
|
DSO__ORIG_BUILDID,
|
|
|
DSO__ORIG_DSO,
|
|
|
+ DSO__ORIG_KMODULE,
|
|
|
DSO__ORIG_NOT_FOUND,
|
|
|
};
|
|
|
|
|
|
-static struct symbol *symbol__new(u64 start, u64 len,
|
|
|
- const char *name, unsigned int priv_size,
|
|
|
- u64 obj_start, int v)
|
|
|
+static void dsos__add(struct dso *dso);
|
|
|
+static struct dso *dsos__find(const char *name);
|
|
|
+
|
|
|
+static struct symbol *symbol__new(u64 start, u64 len, const char *name,
|
|
|
+ unsigned int priv_size, int v)
|
|
|
{
|
|
|
size_t namelen = strlen(name) + 1;
|
|
|
struct symbol *self = calloc(1, priv_size + sizeof(*self) + namelen);
|
|
@@ -32,10 +37,9 @@ static struct symbol *symbol__new(u64 start, u64 len,
|
|
|
return NULL;
|
|
|
|
|
|
if (v >= 2)
|
|
|
- printf("new symbol: %016Lx [%08lx]: %s, hist: %p, obj_start: %p\n",
|
|
|
- (u64)start, (unsigned long)len, name, self->hist, (void *)(unsigned long)obj_start);
|
|
|
+ printf("new symbol: %016Lx [%08lx]: %s, hist: %p\n",
|
|
|
+ start, (unsigned long)len, name, self->hist);
|
|
|
|
|
|
- self->obj_start= obj_start;
|
|
|
self->hist = NULL;
|
|
|
self->hist_sum = 0;
|
|
|
|
|
@@ -60,12 +64,8 @@ static void symbol__delete(struct symbol *self, unsigned int priv_size)
|
|
|
|
|
|
static size_t symbol__fprintf(struct symbol *self, FILE *fp)
|
|
|
{
|
|
|
- if (!self->module)
|
|
|
- return fprintf(fp, " %llx-%llx %s\n",
|
|
|
+ return fprintf(fp, " %llx-%llx %s\n",
|
|
|
self->start, self->end, self->name);
|
|
|
- else
|
|
|
- return fprintf(fp, " %llx-%llx %s \t[%s]\n",
|
|
|
- self->start, self->end, self->name, self->module->name);
|
|
|
}
|
|
|
|
|
|
struct dso *dso__new(const char *name, unsigned int sym_priv_size)
|
|
@@ -74,6 +74,8 @@ struct dso *dso__new(const char *name, unsigned int sym_priv_size)
|
|
|
|
|
|
if (self != NULL) {
|
|
|
strcpy(self->name, name);
|
|
|
+ self->long_name = self->name;
|
|
|
+ self->short_name = self->name;
|
|
|
self->syms = RB_ROOT;
|
|
|
self->sym_priv_size = sym_priv_size;
|
|
|
self->find_symbol = dso__find_symbol;
|
|
@@ -100,6 +102,8 @@ static void dso__delete_symbols(struct dso *self)
|
|
|
void dso__delete(struct dso *self)
|
|
|
{
|
|
|
dso__delete_symbols(self);
|
|
|
+ if (self->long_name != self->name)
|
|
|
+ free(self->long_name);
|
|
|
free(self);
|
|
|
}
|
|
|
|
|
@@ -147,7 +151,7 @@ struct symbol *dso__find_symbol(struct dso *self, u64 ip)
|
|
|
|
|
|
size_t dso__fprintf(struct dso *self, FILE *fp)
|
|
|
{
|
|
|
- size_t ret = fprintf(fp, "dso: %s\n", self->name);
|
|
|
+ size_t ret = fprintf(fp, "dso: %s\n", self->long_name);
|
|
|
|
|
|
struct rb_node *nd;
|
|
|
for (nd = rb_first(&self->syms); nd; nd = rb_next(nd)) {
|
|
@@ -158,7 +162,8 @@ size_t dso__fprintf(struct dso *self, FILE *fp)
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
-static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int v)
|
|
|
+static int dso__load_kallsyms(struct dso *self, struct map *map,
|
|
|
+ symbol_filter_t filter, int v)
|
|
|
{
|
|
|
struct rb_node *nd, *prevnd;
|
|
|
char *line = NULL;
|
|
@@ -200,12 +205,12 @@ static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int v)
|
|
|
* Well fix up the end later, when we have all sorted.
|
|
|
*/
|
|
|
sym = symbol__new(start, 0xdead, line + len + 2,
|
|
|
- self->sym_priv_size, 0, v);
|
|
|
+ self->sym_priv_size, v);
|
|
|
|
|
|
if (sym == NULL)
|
|
|
goto out_delete_line;
|
|
|
|
|
|
- if (filter && filter(self, sym))
|
|
|
+ if (filter && filter(map, sym))
|
|
|
symbol__delete(sym, self->sym_priv_size);
|
|
|
else {
|
|
|
dso__insert_symbol(self, sym);
|
|
@@ -241,14 +246,15 @@ out_failure:
|
|
|
return -1;
|
|
|
}
|
|
|
|
|
|
-static int dso__load_perf_map(struct dso *self, symbol_filter_t filter, int v)
|
|
|
+static int dso__load_perf_map(struct dso *self, struct map *map,
|
|
|
+ symbol_filter_t filter, int v)
|
|
|
{
|
|
|
char *line = NULL;
|
|
|
size_t n;
|
|
|
FILE *file;
|
|
|
int nr_syms = 0;
|
|
|
|
|
|
- file = fopen(self->name, "r");
|
|
|
+ file = fopen(self->long_name, "r");
|
|
|
if (file == NULL)
|
|
|
goto out_failure;
|
|
|
|
|
@@ -279,12 +285,12 @@ static int dso__load_perf_map(struct dso *self, symbol_filter_t filter, int v)
|
|
|
continue;
|
|
|
|
|
|
sym = symbol__new(start, size, line + len,
|
|
|
- self->sym_priv_size, start, v);
|
|
|
+ self->sym_priv_size, v);
|
|
|
|
|
|
if (sym == NULL)
|
|
|
goto out_delete_line;
|
|
|
|
|
|
- if (filter && filter(self, sym))
|
|
|
+ if (filter && filter(map, sym))
|
|
|
symbol__delete(sym, self->sym_priv_size);
|
|
|
else {
|
|
|
dso__insert_symbol(self, sym);
|
|
@@ -410,7 +416,7 @@ static int dso__synthesize_plt_symbols(struct dso *self, int v)
|
|
|
Elf *elf;
|
|
|
int nr = 0, symidx, fd, err = 0;
|
|
|
|
|
|
- fd = open(self->name, O_RDONLY);
|
|
|
+ fd = open(self->long_name, O_RDONLY);
|
|
|
if (fd < 0)
|
|
|
goto out;
|
|
|
|
|
@@ -478,7 +484,7 @@ static int dso__synthesize_plt_symbols(struct dso *self, int v)
|
|
|
"%s@plt", elf_sym__name(&sym, symstrs));
|
|
|
|
|
|
f = symbol__new(plt_offset, shdr_plt.sh_entsize,
|
|
|
- sympltname, self->sym_priv_size, 0, v);
|
|
|
+ sympltname, self->sym_priv_size, v);
|
|
|
if (!f)
|
|
|
goto out_elf_end;
|
|
|
|
|
@@ -496,7 +502,7 @@ static int dso__synthesize_plt_symbols(struct dso *self, int v)
|
|
|
"%s@plt", elf_sym__name(&sym, symstrs));
|
|
|
|
|
|
f = symbol__new(plt_offset, shdr_plt.sh_entsize,
|
|
|
- sympltname, self->sym_priv_size, 0, v);
|
|
|
+ sympltname, self->sym_priv_size, v);
|
|
|
if (!f)
|
|
|
goto out_elf_end;
|
|
|
|
|
@@ -515,12 +521,13 @@ out_close:
|
|
|
return nr;
|
|
|
out:
|
|
|
fprintf(stderr, "%s: problems reading %s PLT info.\n",
|
|
|
- __func__, self->name);
|
|
|
+ __func__, self->long_name);
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static int dso__load_sym(struct dso *self, int fd, const char *name,
|
|
|
- symbol_filter_t filter, int v, struct module *mod)
|
|
|
+static int dso__load_sym(struct dso *self, struct map *map, const char *name,
|
|
|
+ int fd, symbol_filter_t filter, int kernel,
|
|
|
+ int kmodule, int v)
|
|
|
{
|
|
|
Elf_Data *symstrs, *secstrs;
|
|
|
uint32_t nr_syms;
|
|
@@ -532,7 +539,7 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
|
|
|
GElf_Sym sym;
|
|
|
Elf_Scn *sec, *sec_strndx;
|
|
|
Elf *elf;
|
|
|
- int nr = 0, kernel = !strcmp("[kernel]", self->name);
|
|
|
+ int nr = 0;
|
|
|
|
|
|
elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
|
|
|
if (elf == NULL) {
|
|
@@ -589,8 +596,6 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
|
|
|
struct symbol *f;
|
|
|
const char *elf_name;
|
|
|
char *demangled;
|
|
|
- u64 obj_start;
|
|
|
- struct section *section = NULL;
|
|
|
int is_label = elf_sym__is_label(&sym);
|
|
|
const char *section_name;
|
|
|
|
|
@@ -607,7 +612,6 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
|
|
|
continue;
|
|
|
|
|
|
section_name = elf_sec__name(&shdr, secstrs);
|
|
|
- obj_start = sym.st_value;
|
|
|
|
|
|
if (self->adjust_symbols) {
|
|
|
if (v >= 2)
|
|
@@ -615,18 +619,8 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
|
|
|
(u64)sym.st_value, (u64)shdr.sh_addr, (u64)shdr.sh_offset);
|
|
|
|
|
|
sym.st_value -= shdr.sh_addr - shdr.sh_offset;
|
|
|
- }
|
|
|
-
|
|
|
- if (mod) {
|
|
|
- section = mod->sections->find_section(mod->sections, section_name);
|
|
|
- if (section)
|
|
|
- sym.st_value += section->vma;
|
|
|
- else {
|
|
|
- fprintf(stderr, "dso__load_sym() module %s lookup of %s failed\n",
|
|
|
- mod->name, section_name);
|
|
|
- goto out_elf_end;
|
|
|
- }
|
|
|
- }
|
|
|
+ } else if (kmodule)
|
|
|
+ sym.st_value += shdr.sh_offset;
|
|
|
/*
|
|
|
* We need to figure out if the object was created from C++ sources
|
|
|
* DWARF DW_compile_unit has this, but we don't always have access
|
|
@@ -638,15 +632,14 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
|
|
|
elf_name = demangled;
|
|
|
|
|
|
f = symbol__new(sym.st_value, sym.st_size, elf_name,
|
|
|
- self->sym_priv_size, obj_start, v);
|
|
|
+ self->sym_priv_size, v);
|
|
|
free(demangled);
|
|
|
if (!f)
|
|
|
goto out_elf_end;
|
|
|
|
|
|
- if (filter && filter(self, f))
|
|
|
+ if (filter && filter(map, f))
|
|
|
symbol__delete(f, self->sym_priv_size);
|
|
|
else {
|
|
|
- f->module = mod;
|
|
|
dso__insert_symbol(self, f);
|
|
|
nr++;
|
|
|
}
|
|
@@ -671,7 +664,7 @@ static char *dso__read_build_id(struct dso *self, int v)
|
|
|
char *build_id = NULL, *bid;
|
|
|
unsigned char *raw;
|
|
|
Elf *elf;
|
|
|
- int fd = open(self->name, O_RDONLY);
|
|
|
+ int fd = open(self->long_name, O_RDONLY);
|
|
|
|
|
|
if (fd < 0)
|
|
|
goto out;
|
|
@@ -680,7 +673,7 @@ static char *dso__read_build_id(struct dso *self, int v)
|
|
|
if (elf == NULL) {
|
|
|
if (v)
|
|
|
fprintf(stderr, "%s: cannot read %s ELF file.\n",
|
|
|
- __func__, self->name);
|
|
|
+ __func__, self->long_name);
|
|
|
goto out_close;
|
|
|
}
|
|
|
|
|
@@ -709,7 +702,7 @@ static char *dso__read_build_id(struct dso *self, int v)
|
|
|
bid += 2;
|
|
|
}
|
|
|
if (v >= 2)
|
|
|
- printf("%s(%s): %s\n", __func__, self->name, build_id);
|
|
|
+ printf("%s(%s): %s\n", __func__, self->long_name, build_id);
|
|
|
out_elf_end:
|
|
|
elf_end(elf);
|
|
|
out_close:
|
|
@@ -727,6 +720,7 @@ char dso__symtab_origin(const struct dso *self)
|
|
|
[DSO__ORIG_UBUNTU] = 'u',
|
|
|
[DSO__ORIG_BUILDID] = 'b',
|
|
|
[DSO__ORIG_DSO] = 'd',
|
|
|
+ [DSO__ORIG_KMODULE] = 'K',
|
|
|
};
|
|
|
|
|
|
if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND)
|
|
@@ -734,7 +728,7 @@ char dso__symtab_origin(const struct dso *self)
|
|
|
return origin[self->origin];
|
|
|
}
|
|
|
|
|
|
-int dso__load(struct dso *self, symbol_filter_t filter, int v)
|
|
|
+int dso__load(struct dso *self, struct map *map, symbol_filter_t filter, int v)
|
|
|
{
|
|
|
int size = PATH_MAX;
|
|
|
char *name = malloc(size), *build_id = NULL;
|
|
@@ -747,7 +741,7 @@ int dso__load(struct dso *self, symbol_filter_t filter, int v)
|
|
|
self->adjust_symbols = 0;
|
|
|
|
|
|
if (strncmp(self->name, "/tmp/perf-", 10) == 0) {
|
|
|
- ret = dso__load_perf_map(self, filter, v);
|
|
|
+ ret = dso__load_perf_map(self, map, filter, v);
|
|
|
self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT :
|
|
|
DSO__ORIG_NOT_FOUND;
|
|
|
return ret;
|
|
@@ -760,10 +754,12 @@ more:
|
|
|
self->origin++;
|
|
|
switch (self->origin) {
|
|
|
case DSO__ORIG_FEDORA:
|
|
|
- snprintf(name, size, "/usr/lib/debug%s.debug", self->name);
|
|
|
+ snprintf(name, size, "/usr/lib/debug%s.debug",
|
|
|
+ self->long_name);
|
|
|
break;
|
|
|
case DSO__ORIG_UBUNTU:
|
|
|
- snprintf(name, size, "/usr/lib/debug%s", self->name);
|
|
|
+ snprintf(name, size, "/usr/lib/debug%s",
|
|
|
+ self->long_name);
|
|
|
break;
|
|
|
case DSO__ORIG_BUILDID:
|
|
|
build_id = dso__read_build_id(self, v);
|
|
@@ -777,7 +773,7 @@ more:
|
|
|
self->origin++;
|
|
|
/* Fall thru */
|
|
|
case DSO__ORIG_DSO:
|
|
|
- snprintf(name, size, "%s", self->name);
|
|
|
+ snprintf(name, size, "%s", self->long_name);
|
|
|
break;
|
|
|
|
|
|
default:
|
|
@@ -787,7 +783,7 @@ more:
|
|
|
fd = open(name, O_RDONLY);
|
|
|
} while (fd < 0);
|
|
|
|
|
|
- ret = dso__load_sym(self, fd, name, filter, v, NULL);
|
|
|
+ ret = dso__load_sym(self, map, name, fd, filter, 0, 0, v);
|
|
|
close(fd);
|
|
|
|
|
|
/*
|
|
@@ -808,89 +804,247 @@ out:
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
-static int dso__load_module(struct dso *self, struct mod_dso *mods, const char *name,
|
|
|
- symbol_filter_t filter, int v)
|
|
|
+static struct rb_root kernel_maps;
|
|
|
+struct map *kernel_map;
|
|
|
+
|
|
|
+static void kernel_maps__insert(struct map *map)
|
|
|
{
|
|
|
- struct module *mod = mod_dso__find_module(mods, name);
|
|
|
- int err = 0, fd;
|
|
|
+ maps__insert(&kernel_maps, map);
|
|
|
+}
|
|
|
|
|
|
- if (mod == NULL || !mod->active)
|
|
|
- return err;
|
|
|
+struct symbol *kernel_maps__find_symbol(u64 ip, struct map **mapp)
|
|
|
+{
|
|
|
+ /*
|
|
|
+ * We can't have kernel_map in kernel_maps because it spans an address
|
|
|
+ * space that includes the modules. The right way to fix this is to
|
|
|
+ * create several maps, so that we don't have overlapping ranges with
|
|
|
+ * modules. For now lets look first on the kernel dso.
|
|
|
+ */
|
|
|
+ struct map *map = maps__find(&kernel_maps, ip);
|
|
|
+ struct symbol *sym;
|
|
|
+
|
|
|
+ if (map) {
|
|
|
+ ip = map->map_ip(map, ip);
|
|
|
+ sym = map->dso->find_symbol(map->dso, ip);
|
|
|
+ } else {
|
|
|
+ map = kernel_map;
|
|
|
+ sym = map->dso->find_symbol(map->dso, ip);
|
|
|
+ }
|
|
|
|
|
|
- fd = open(mod->path, O_RDONLY);
|
|
|
+ if (mapp)
|
|
|
+ *mapp = map;
|
|
|
|
|
|
- if (fd < 0)
|
|
|
+ return sym;
|
|
|
+}
|
|
|
+
|
|
|
+struct map *kernel_maps__find_by_dso_name(const char *name)
|
|
|
+{
|
|
|
+ struct rb_node *nd;
|
|
|
+
|
|
|
+ for (nd = rb_first(&kernel_maps); nd; nd = rb_next(nd)) {
|
|
|
+ struct map *map = rb_entry(nd, struct map, rb_node);
|
|
|
+
|
|
|
+ if (map->dso && strcmp(map->dso->name, name) == 0)
|
|
|
+ return map;
|
|
|
+ }
|
|
|
+
|
|
|
+ return NULL;
|
|
|
+}
|
|
|
+
|
|
|
+static int dso__load_module_sym(struct dso *self, struct map *map,
|
|
|
+ symbol_filter_t filter, int v)
|
|
|
+{
|
|
|
+ int err = 0, fd = open(self->long_name, O_RDONLY);
|
|
|
+
|
|
|
+ if (fd < 0) {
|
|
|
+ if (v)
|
|
|
+ fprintf(stderr, "%s: cannot open %s\n",
|
|
|
+ __func__, self->long_name);
|
|
|
return err;
|
|
|
+ }
|
|
|
|
|
|
- err = dso__load_sym(self, fd, name, filter, v, mod);
|
|
|
+ err = dso__load_sym(self, map, self->long_name, fd, filter, 0, 1, v);
|
|
|
close(fd);
|
|
|
|
|
|
return err;
|
|
|
}
|
|
|
|
|
|
-int dso__load_modules(struct dso *self, symbol_filter_t filter, int v)
|
|
|
+static int dsos__load_modules_sym_dir(char *dirname,
|
|
|
+ symbol_filter_t filter, int v)
|
|
|
{
|
|
|
- struct mod_dso *mods = mod_dso__new_dso("modules");
|
|
|
- struct module *pos;
|
|
|
- struct rb_node *next;
|
|
|
- int err, count = 0;
|
|
|
+ struct dirent *dent;
|
|
|
+ int nr_symbols = 0, err;
|
|
|
+ DIR *dir = opendir(dirname);
|
|
|
|
|
|
- err = mod_dso__load_modules(mods);
|
|
|
+ if (!dir) {
|
|
|
+ if (v)
|
|
|
+ fprintf(stderr, "%s: cannot open %s dir\n", __func__,
|
|
|
+ dirname);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
|
|
|
- if (err <= 0)
|
|
|
- return err;
|
|
|
+ while ((dent = readdir(dir)) != NULL) {
|
|
|
+ char path[PATH_MAX];
|
|
|
+
|
|
|
+ if (dent->d_type == DT_DIR) {
|
|
|
+ if (!strcmp(dent->d_name, ".") ||
|
|
|
+ !strcmp(dent->d_name, ".."))
|
|
|
+ continue;
|
|
|
+
|
|
|
+ snprintf(path, sizeof(path), "%s/%s",
|
|
|
+ dirname, dent->d_name);
|
|
|
+ err = dsos__load_modules_sym_dir(path, filter, v);
|
|
|
+ if (err < 0)
|
|
|
+ goto failure;
|
|
|
+ } else {
|
|
|
+ char *dot = strrchr(dent->d_name, '.'),
|
|
|
+ dso_name[PATH_MAX];
|
|
|
+ struct map *map;
|
|
|
+ struct rb_node *last;
|
|
|
+
|
|
|
+ if (dot == NULL || strcmp(dot, ".ko"))
|
|
|
+ continue;
|
|
|
+ snprintf(dso_name, sizeof(dso_name), "[%.*s]",
|
|
|
+ (int)(dot - dent->d_name), dent->d_name);
|
|
|
+
|
|
|
+ map = kernel_maps__find_by_dso_name(dso_name);
|
|
|
+ if (map == NULL)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ snprintf(path, sizeof(path), "%s/%s",
|
|
|
+ dirname, dent->d_name);
|
|
|
+
|
|
|
+ map->dso->long_name = strdup(path);
|
|
|
+ if (map->dso->long_name == NULL)
|
|
|
+ goto failure;
|
|
|
+
|
|
|
+ err = dso__load_module_sym(map->dso, map, filter, v);
|
|
|
+ if (err < 0)
|
|
|
+ goto failure;
|
|
|
+ last = rb_last(&map->dso->syms);
|
|
|
+ if (last) {
|
|
|
+ struct symbol *sym;
|
|
|
+ sym = rb_entry(last, struct symbol, rb_node);
|
|
|
+ map->end = map->start + sym->end;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ nr_symbols += err;
|
|
|
+ }
|
|
|
|
|
|
- /*
|
|
|
- * Iterate over modules, and load active symbols.
|
|
|
- */
|
|
|
- next = rb_first(&mods->mods);
|
|
|
- while (next) {
|
|
|
- pos = rb_entry(next, struct module, rb_node);
|
|
|
- err = dso__load_module(self, mods, pos->name, filter, v);
|
|
|
+ return nr_symbols;
|
|
|
+failure:
|
|
|
+ closedir(dir);
|
|
|
+ return -1;
|
|
|
+}
|
|
|
|
|
|
- if (err < 0)
|
|
|
- break;
|
|
|
+static int dsos__load_modules_sym(symbol_filter_t filter, int v)
|
|
|
+{
|
|
|
+ struct utsname uts;
|
|
|
+ char modules_path[PATH_MAX];
|
|
|
|
|
|
- next = rb_next(&pos->rb_node);
|
|
|
- count += err;
|
|
|
- }
|
|
|
+ if (uname(&uts) < 0)
|
|
|
+ return -1;
|
|
|
|
|
|
- if (err < 0) {
|
|
|
- mod_dso__delete_modules(mods);
|
|
|
- mod_dso__delete_self(mods);
|
|
|
- return err;
|
|
|
- }
|
|
|
+ snprintf(modules_path, sizeof(modules_path), "/lib/modules/%s/kernel",
|
|
|
+ uts.release);
|
|
|
|
|
|
- return count;
|
|
|
+ return dsos__load_modules_sym_dir(modules_path, filter, v);
|
|
|
}
|
|
|
|
|
|
-static inline void dso__fill_symbol_holes(struct dso *self)
|
|
|
+/*
|
|
|
+ * Constructor variant for modules (where we know from /proc/modules where
|
|
|
+ * they are loaded) and for vmlinux, where only after we load all the
|
|
|
+ * symbols we'll know where it starts and ends.
|
|
|
+ */
|
|
|
+static struct map *map__new2(u64 start, struct dso *dso)
|
|
|
{
|
|
|
- struct symbol *prev = NULL;
|
|
|
- struct rb_node *nd;
|
|
|
+ struct map *self = malloc(sizeof(*self));
|
|
|
|
|
|
- for (nd = rb_last(&self->syms); nd; nd = rb_prev(nd)) {
|
|
|
- struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
|
|
|
+ if (self != NULL) {
|
|
|
+ self->start = start;
|
|
|
+ /*
|
|
|
+ * Will be filled after we load all the symbols
|
|
|
+ */
|
|
|
+ self->end = 0;
|
|
|
+
|
|
|
+ self->pgoff = 0;
|
|
|
+ self->dso = dso;
|
|
|
+ self->map_ip = map__map_ip;
|
|
|
+ RB_CLEAR_NODE(&self->rb_node);
|
|
|
+ }
|
|
|
+ return self;
|
|
|
+}
|
|
|
+
|
|
|
+int dsos__load_modules(unsigned int sym_priv_size,
|
|
|
+ symbol_filter_t filter, int v)
|
|
|
+{
|
|
|
+ char *line = NULL;
|
|
|
+ size_t n;
|
|
|
+ FILE *file = fopen("/proc/modules", "r");
|
|
|
+ struct map *map;
|
|
|
|
|
|
- if (prev) {
|
|
|
- u64 hole = 0;
|
|
|
- int alias = pos->start == prev->start;
|
|
|
+ if (file == NULL)
|
|
|
+ return -1;
|
|
|
|
|
|
- if (!alias)
|
|
|
- hole = prev->start - pos->end - 1;
|
|
|
+ while (!feof(file)) {
|
|
|
+ char name[PATH_MAX];
|
|
|
+ u64 start;
|
|
|
+ struct dso *dso;
|
|
|
+ char *sep;
|
|
|
+ int line_len;
|
|
|
|
|
|
- if (hole || alias) {
|
|
|
- if (alias)
|
|
|
- pos->end = prev->end;
|
|
|
- else if (hole)
|
|
|
- pos->end = prev->start - 1;
|
|
|
- }
|
|
|
+ line_len = getline(&line, &n, file);
|
|
|
+ if (line_len < 0)
|
|
|
+ break;
|
|
|
+
|
|
|
+ if (!line)
|
|
|
+ goto out_failure;
|
|
|
+
|
|
|
+ line[--line_len] = '\0'; /* \n */
|
|
|
+
|
|
|
+ sep = strrchr(line, 'x');
|
|
|
+ if (sep == NULL)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ hex2u64(sep + 1, &start);
|
|
|
+
|
|
|
+ sep = strchr(line, ' ');
|
|
|
+ if (sep == NULL)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ *sep = '\0';
|
|
|
+
|
|
|
+ snprintf(name, sizeof(name), "[%s]", line);
|
|
|
+ dso = dso__new(name, sym_priv_size);
|
|
|
+
|
|
|
+ if (dso == NULL)
|
|
|
+ goto out_delete_line;
|
|
|
+
|
|
|
+ map = map__new2(start, dso);
|
|
|
+ if (map == NULL) {
|
|
|
+ dso__delete(dso);
|
|
|
+ goto out_delete_line;
|
|
|
}
|
|
|
- prev = pos;
|
|
|
+
|
|
|
+ dso->origin = DSO__ORIG_KMODULE;
|
|
|
+ kernel_maps__insert(map);
|
|
|
+ dsos__add(dso);
|
|
|
}
|
|
|
+
|
|
|
+ free(line);
|
|
|
+ fclose(file);
|
|
|
+
|
|
|
+ v = 1;
|
|
|
+ return dsos__load_modules_sym(filter, v);
|
|
|
+
|
|
|
+out_delete_line:
|
|
|
+ free(line);
|
|
|
+out_failure:
|
|
|
+ return -1;
|
|
|
}
|
|
|
|
|
|
-static int dso__load_vmlinux(struct dso *self, const char *vmlinux,
|
|
|
+static int dso__load_vmlinux(struct dso *self, struct map *map,
|
|
|
+ const char *vmlinux,
|
|
|
symbol_filter_t filter, int v)
|
|
|
{
|
|
|
int err, fd = open(vmlinux, O_RDONLY);
|
|
@@ -898,28 +1052,36 @@ static int dso__load_vmlinux(struct dso *self, const char *vmlinux,
|
|
|
if (fd < 0)
|
|
|
return -1;
|
|
|
|
|
|
- err = dso__load_sym(self, fd, vmlinux, filter, v, NULL);
|
|
|
-
|
|
|
- if (err > 0)
|
|
|
- dso__fill_symbol_holes(self);
|
|
|
+ err = dso__load_sym(self, map, self->long_name, fd, filter, 1, 0, v);
|
|
|
|
|
|
close(fd);
|
|
|
|
|
|
return err;
|
|
|
}
|
|
|
|
|
|
-int dso__load_kernel(struct dso *self, const char *vmlinux,
|
|
|
- symbol_filter_t filter, int v, int use_modules)
|
|
|
+int dsos__load_kernel(const char *vmlinux, unsigned int sym_priv_size,
|
|
|
+ symbol_filter_t filter, int v, int use_modules)
|
|
|
{
|
|
|
int err = -1;
|
|
|
+ struct dso *dso = dso__new(vmlinux, sym_priv_size);
|
|
|
+
|
|
|
+ if (dso == NULL)
|
|
|
+ return -1;
|
|
|
+
|
|
|
+ dso->short_name = "[kernel]";
|
|
|
+ kernel_map = map__new2(0, dso);
|
|
|
+ if (kernel_map == NULL)
|
|
|
+ goto out_delete_dso;
|
|
|
+
|
|
|
+ kernel_map->map_ip = vdso__map_ip;
|
|
|
|
|
|
if (vmlinux) {
|
|
|
- err = dso__load_vmlinux(self, vmlinux, filter, v);
|
|
|
+ err = dso__load_vmlinux(dso, kernel_map, vmlinux, filter, v);
|
|
|
if (err > 0 && use_modules) {
|
|
|
- int syms = dso__load_modules(self, filter, v);
|
|
|
+ int syms = dsos__load_modules(sym_priv_size, filter, v);
|
|
|
|
|
|
if (syms < 0) {
|
|
|
- fprintf(stderr, "dso__load_modules failed!\n");
|
|
|
+ fprintf(stderr, "dsos__load_modules failed!\n");
|
|
|
return syms;
|
|
|
}
|
|
|
err += syms;
|
|
@@ -927,18 +1089,34 @@ int dso__load_kernel(struct dso *self, const char *vmlinux,
|
|
|
}
|
|
|
|
|
|
if (err <= 0)
|
|
|
- err = dso__load_kallsyms(self, filter, v);
|
|
|
+ err = dso__load_kallsyms(dso, kernel_map, filter, v);
|
|
|
+
|
|
|
+ if (err > 0) {
|
|
|
+ struct rb_node *node = rb_first(&dso->syms);
|
|
|
+ struct symbol *sym = rb_entry(node, struct symbol, rb_node);
|
|
|
|
|
|
- if (err > 0)
|
|
|
- self->origin = DSO__ORIG_KERNEL;
|
|
|
+ kernel_map->start = sym->start;
|
|
|
+ node = rb_last(&dso->syms);
|
|
|
+ sym = rb_entry(node, struct symbol, rb_node);
|
|
|
+ kernel_map->end = sym->end;
|
|
|
+
|
|
|
+ dso->origin = DSO__ORIG_KERNEL;
|
|
|
+ /*
|
|
|
+ * XXX See kernel_maps__find_symbol comment
|
|
|
+ * kernel_maps__insert(kernel_map)
|
|
|
+ */
|
|
|
+ dsos__add(dso);
|
|
|
+ }
|
|
|
|
|
|
return err;
|
|
|
+
|
|
|
+out_delete_dso:
|
|
|
+ dso__delete(dso);
|
|
|
+ return -1;
|
|
|
}
|
|
|
|
|
|
LIST_HEAD(dsos);
|
|
|
-struct dso *kernel_dso;
|
|
|
struct dso *vdso;
|
|
|
-struct dso *hypervisor_dso;
|
|
|
|
|
|
const char *vmlinux_name = "vmlinux";
|
|
|
int modules;
|
|
@@ -970,7 +1148,7 @@ struct dso *dsos__findnew(const char *name)
|
|
|
if (!dso)
|
|
|
goto out_delete_dso;
|
|
|
|
|
|
- nr = dso__load(dso, NULL, verbose);
|
|
|
+ nr = dso__load(dso, NULL, NULL, verbose);
|
|
|
if (nr < 0) {
|
|
|
eprintf("Failed to open: %s\n", name);
|
|
|
goto out_delete_dso;
|
|
@@ -995,43 +1173,20 @@ void dsos__fprintf(FILE *fp)
|
|
|
dso__fprintf(pos, fp);
|
|
|
}
|
|
|
|
|
|
-static struct symbol *vdso__find_symbol(struct dso *dso, u64 ip)
|
|
|
-{
|
|
|
- return dso__find_symbol(dso, ip);
|
|
|
-}
|
|
|
-
|
|
|
int load_kernel(void)
|
|
|
{
|
|
|
- int err;
|
|
|
-
|
|
|
- kernel_dso = dso__new("[kernel]", 0);
|
|
|
- if (!kernel_dso)
|
|
|
+ if (dsos__load_kernel(vmlinux_name, 0, NULL, verbose, modules) <= 0)
|
|
|
return -1;
|
|
|
|
|
|
- err = dso__load_kernel(kernel_dso, vmlinux_name, NULL, verbose, modules);
|
|
|
- if (err <= 0) {
|
|
|
- dso__delete(kernel_dso);
|
|
|
- kernel_dso = NULL;
|
|
|
- } else
|
|
|
- dsos__add(kernel_dso);
|
|
|
-
|
|
|
vdso = dso__new("[vdso]", 0);
|
|
|
if (!vdso)
|
|
|
return -1;
|
|
|
|
|
|
- vdso->find_symbol = vdso__find_symbol;
|
|
|
-
|
|
|
dsos__add(vdso);
|
|
|
|
|
|
- hypervisor_dso = dso__new("[hypervisor]", 0);
|
|
|
- if (!hypervisor_dso)
|
|
|
- return -1;
|
|
|
- dsos__add(hypervisor_dso);
|
|
|
-
|
|
|
- return err;
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
-
|
|
|
void symbol__init(void)
|
|
|
{
|
|
|
elf_version(EV_CURRENT);
|