#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;
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 verbose)
+static void dsos__add(struct dso *dso);
+static struct dso *dsos__find(const char *name);
+
+static struct rb_root kernel_maps;
+
+static void dso__set_symbols_end(struct dso *self)
+{
+ struct rb_node *nd, *prevnd = rb_first(&self->syms);
+
+ if (prevnd == NULL)
+ return;
+
+ for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
+ struct symbol *prev = rb_entry(prevnd, struct symbol, rb_node),
+ *curr = rb_entry(nd, struct symbol, rb_node);
+
+ if (prev->end == prev->start)
+ prev->end = curr->start - 1;
+ prevnd = nd;
+ }
+}
+
+static void kernel_maps__fixup_sym_end(void)
+{
+ struct map *prev, *curr;
+ struct rb_node *nd, *prevnd = rb_first(&kernel_maps);
+
+ if (prevnd == NULL)
+ return;
+
+ curr = rb_entry(prevnd, struct map, rb_node);
+ dso__set_symbols_end(curr->dso);
+
+ for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
+ prev = curr;
+ curr = rb_entry(nd, struct map, rb_node);
+ prev->end = curr->start - 1;
+ dso__set_symbols_end(curr->dso);
+ }
+}
+
+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);
if (!self)
return NULL;
- if (verbose >= 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);
+ if (v >= 2)
+ 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;
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)
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;
void dso__delete(struct dso *self)
{
dso__delete_symbols(self);
+ if (self->long_name != self->name)
+ free(self->long_name);
free(self);
}
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->short_name);
struct rb_node *nd;
for (nd = rb_first(&self->syms); nd; nd = rb_next(nd)) {
return ret;
}
-static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int verbose)
+static int maps__load_kallsyms(symbol_filter_t filter, int use_modules, int v)
{
- struct rb_node *nd, *prevnd;
+ struct map *map = kernel_map;
char *line = NULL;
size_t n;
FILE *file = fopen("/proc/kallsyms", "r");
struct symbol *sym;
int line_len, len;
char symbol_type;
+ char *module, *symbol_name;
line_len = getline(&line, &n, file);
if (line_len < 0)
*/
if (symbol_type != 'T' && symbol_type != 'W')
continue;
+
+ symbol_name = line + len + 2;
+ module = strchr(symbol_name, '\t');
+ if (module) {
+ char *module_name_end;
+
+ if (!use_modules)
+ continue;
+ *module = '\0';
+ module = strchr(module + 1, '[');
+ if (!module)
+ continue;
+ module_name_end = strchr(module + 1, ']');
+ if (!module_name_end)
+ continue;
+ *(module_name_end + 1) = '\0';
+ if (strcmp(map->dso->name, module)) {
+ map = kernel_maps__find_by_dso_name(module);
+ if (!map) {
+ fputs("/proc/{kallsyms,modules} "
+ "inconsistency!\n", stderr);
+ return -1;
+ }
+ }
+ start = map->map_ip(map, start);
+ } else
+ map = kernel_map;
/*
* Well fix up the end later, when we have all sorted.
*/
- sym = symbol__new(start, 0xdead, line + len + 2,
- self->sym_priv_size, 0, verbose);
+ sym = symbol__new(start, 0, symbol_name,
+ map->dso->sym_priv_size, v);
if (sym == NULL)
goto out_delete_line;
- if (filter && filter(self, sym))
- symbol__delete(sym, self->sym_priv_size);
+ if (filter && filter(map, sym))
+ symbol__delete(sym, map->dso->sym_priv_size);
else {
- dso__insert_symbol(self, sym);
+ dso__insert_symbol(map->dso, sym);
count++;
}
}
- /*
- * Now that we have all sorted out, just set the ->end of all
- * symbols
- */
- prevnd = rb_first(&self->syms);
-
- if (prevnd == NULL)
- goto out_delete_line;
-
- for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) {
- struct symbol *prev = rb_entry(prevnd, struct symbol, rb_node),
- *curr = rb_entry(nd, struct symbol, rb_node);
-
- prev->end = curr->start - 1;
- prevnd = nd;
- }
-
free(line);
fclose(file);
return -1;
}
-static int dso__load_perf_map(struct dso *self, symbol_filter_t filter, int verbose)
+static size_t kernel_maps__fprintf(FILE *fp)
+{
+ size_t printed = fprintf(stderr, "Kernel maps:\n");
+ struct rb_node *nd;
+
+ printed += map__fprintf(kernel_map, fp);
+ printed += dso__fprintf(kernel_map->dso, fp);
+
+ for (nd = rb_first(&kernel_maps); nd; nd = rb_next(nd)) {
+ struct map *pos = rb_entry(nd, struct map, rb_node);
+
+ printed += map__fprintf(pos, fp);
+ printed += dso__fprintf(pos->dso, fp);
+ }
+
+ return printed + fprintf(stderr, "END kernel maps\n");
+}
+
+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;
continue;
sym = symbol__new(start, size, line + len,
- self->sym_priv_size, start, verbose);
+ 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);
* elf_symtab__for_each_symbol - iterate thru all the symbols
*
* @self: struct elf_symtab instance to iterate
- * @index: uint32_t index
+ * @idx: uint32_t idx
* @sym: GElf_Sym iterator
*/
-#define elf_symtab__for_each_symbol(syms, nr_syms, index, sym) \
- for (index = 0, gelf_getsym(syms, index, &sym);\
- index < nr_syms; \
- index++, gelf_getsym(syms, index, &sym))
+#define elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) \
+ for (idx = 0, gelf_getsym(syms, idx, &sym);\
+ idx < nr_syms; \
+ idx++, gelf_getsym(syms, idx, &sym))
static inline uint8_t elf_sym__type(const GElf_Sym *sym)
{
{
return elf_sym__type(sym) == STT_FUNC &&
sym->st_name != 0 &&
- sym->st_shndx != SHN_UNDEF &&
- sym->st_size != 0;
+ sym->st_shndx != SHN_UNDEF;
}
static inline int elf_sym__is_label(const GElf_Sym *sym)
static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
GElf_Shdr *shp, const char *name,
- size_t *index)
+ size_t *idx)
{
Elf_Scn *sec = NULL;
size_t cnt = 1;
gelf_getshdr(sec, shp);
str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name);
if (!strcmp(name, str)) {
- if (index)
- *index = cnt;
+ if (idx)
+ *idx = cnt;
break;
}
++cnt;
* And always look at the original dso, not at debuginfo packages, that
* have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS).
*/
-static int dso__synthesize_plt_symbols(struct dso *self, int verbose)
+static int dso__synthesize_plt_symbols(struct dso *self, int v)
{
uint32_t nr_rel_entries, idx;
GElf_Sym sym;
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;
goto out_elf_end;
/*
- * Fetch the relocation section to find the indexes to the GOT
+ * Fetch the relocation section to find the idxes to the GOT
* and the symbols in the .dynsym they refer to.
*/
reldata = elf_getdata(scn_plt_rel, NULL);
"%s@plt", elf_sym__name(&sym, symstrs));
f = symbol__new(plt_offset, shdr_plt.sh_entsize,
- sympltname, self->sym_priv_size, 0, verbose);
+ sympltname, self->sym_priv_size, v);
if (!f)
goto out_elf_end;
"%s@plt", elf_sym__name(&sym, symstrs));
f = symbol__new(plt_offset, shdr_plt.sh_entsize,
- sympltname, self->sym_priv_size, 0, verbose);
+ sympltname, self->sym_priv_size, v);
if (!f)
goto out_elf_end;
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 verbose, 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;
int err = -1;
- uint32_t index;
+ uint32_t idx;
GElf_Ehdr ehdr;
GElf_Shdr shdr;
Elf_Data *syms;
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) {
- if (verbose)
+ if (v)
fprintf(stderr, "%s: cannot read %s ELF file.\n",
__func__, name);
goto out_close;
}
if (gelf_getehdr(elf, &ehdr) == NULL) {
- if (verbose)
+ if (v)
fprintf(stderr, "%s: cannot get elf header.\n", __func__);
goto out_elf_end;
}
NULL) != NULL);
} else self->adjust_symbols = 0;
- elf_symtab__for_each_symbol(syms, nr_syms, index, sym) {
+ elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) {
struct symbol *f;
- const char *name;
+ 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;
+ u64 sh_offset = 0;
if (!is_label && !elf_sym__is_function(&sym))
continue;
continue;
section_name = elf_sec__name(&shdr, secstrs);
- obj_start = sym.st_value;
+
+ if ((kernel || kmodule)) {
+ if (strstr(section_name, ".init"))
+ sh_offset = shdr.sh_offset;
+ }
if (self->adjust_symbols) {
- if (verbose >= 2)
+ if (v >= 2)
printf("adjusting symbol: st_value: %Lx sh_addr: %Lx sh_offset: %Lx\n",
(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;
- }
- }
/*
* 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
* to it...
*/
- name = elf_sym__name(&sym, symstrs);
- demangled = bfd_demangle(NULL, name, DMGL_PARAMS | DMGL_ANSI);
+ elf_name = elf_sym__name(&sym, symstrs);
+ demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI);
if (demangled != NULL)
- name = demangled;
+ elf_name = demangled;
- f = symbol__new(sym.st_value, sym.st_size, name,
- self->sym_priv_size, obj_start, verbose);
+ f = symbol__new(sym.st_value + sh_offset, sym.st_size, elf_name,
+ 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++;
}
#define BUILD_ID_SIZE 128
-static char *dso__read_build_id(struct dso *self, int verbose)
+static char *dso__read_build_id(struct dso *self, int v)
{
int i;
GElf_Ehdr ehdr;
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;
elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
if (elf == NULL) {
- if (verbose)
+ if (v)
fprintf(stderr, "%s: cannot read %s ELF file.\n",
- __func__, self->name);
+ __func__, self->long_name);
goto out_close;
}
if (gelf_getehdr(elf, &ehdr) == NULL) {
- if (verbose)
+ if (v)
fprintf(stderr, "%s: cannot get elf header.\n", __func__);
goto out_elf_end;
}
++raw;
bid += 2;
}
- if (verbose >= 2)
- printf("%s(%s): %s\n", __func__, self->name, build_id);
+ if (v >= 2)
+ printf("%s(%s): %s\n", __func__, self->long_name, build_id);
out_elf_end:
elf_end(elf);
out_close:
[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)
return origin[self->origin];
}
-int dso__load(struct dso *self, symbol_filter_t filter, int verbose)
+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;
self->adjust_symbols = 0;
if (strncmp(self->name, "/tmp/perf-", 10) == 0) {
- ret = dso__load_perf_map(self, filter, verbose);
+ ret = dso__load_perf_map(self, map, filter, v);
self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT :
DSO__ORIG_NOT_FOUND;
return ret;
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, verbose);
+ build_id = dso__read_build_id(self, v);
if (build_id != NULL) {
snprintf(name, size,
"/usr/lib/debug/.build-id/%.2s/%s.debug",
self->origin++;
/* Fall thru */
case DSO__ORIG_DSO:
- snprintf(name, size, "%s", self->name);
+ snprintf(name, size, "%s", self->long_name);
break;
default:
fd = open(name, O_RDONLY);
} while (fd < 0);
- ret = dso__load_sym(self, fd, name, filter, verbose, NULL);
+ ret = dso__load_sym(self, map, name, fd, filter, 0, 0, v);
close(fd);
/*
goto more;
if (ret > 0) {
- int nr_plt = dso__synthesize_plt_symbols(self, verbose);
+ int nr_plt = dso__synthesize_plt_symbols(self, v);
if (nr_plt > 0)
ret += nr_plt;
}
return ret;
}
-static int dso__load_module(struct dso *self, struct mod_dso *mods, const char *name,
- symbol_filter_t filter, int verbose)
+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, verbose, 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 verbose)
+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;
+ struct dirent *dent;
+ int nr_symbols = 0, err;
+ DIR *dir = opendir(dirname);
+
+ if (!dir) {
+ if (v)
+ fprintf(stderr, "%s: cannot open %s dir\n", __func__,
+ dirname);
+ return -1;
+ }
- err = mod_dso__load_modules(mods);
+ 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);
+
+ strxfrchar(dso_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;
+ }
- if (err <= 0)
- return err;
+ return nr_symbols;
+failure:
+ closedir(dir);
+ return -1;
+}
- /*
- * 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, verbose);
+static int dsos__load_modules_sym(symbol_filter_t filter, int v)
+{
+ struct utsname uts;
+ char modules_path[PATH_MAX];
- if (err < 0)
- break;
+ if (uname(&uts) < 0)
+ return -1;
- next = rb_next(&pos->rb_node);
- }
+ snprintf(modules_path, sizeof(modules_path), "/lib/modules/%s/kernel",
+ uts.release);
- if (err < 0) {
- mod_dso__delete_modules(mods);
- mod_dso__delete_self(mods);
- }
+ return dsos__load_modules_sym_dir(modules_path, filter, v);
+}
- return err;
+/*
+ * 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 map *self = malloc(sizeof(*self));
+
+ 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;
}
-static inline void dso__fill_symbol_holes(struct dso *self)
+static int dsos__load_modules(unsigned int sym_priv_size)
{
- struct symbol *prev = NULL;
- struct rb_node *nd;
+ char *line = NULL;
+ size_t n;
+ FILE *file = fopen("/proc/modules", "r");
+ struct map *map;
- for (nd = rb_last(&self->syms); nd; nd = rb_prev(nd)) {
- struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
+ if (file == NULL)
+ return -1;
+
+ while (!feof(file)) {
+ char name[PATH_MAX];
+ u64 start;
+ struct dso *dso;
+ char *sep;
+ int line_len;
- if (prev) {
- u64 hole = 0;
- int alias = pos->start == prev->start;
+ line_len = getline(&line, &n, file);
+ if (line_len < 0)
+ break;
- if (!alias)
- hole = prev->start - pos->end - 1;
+ if (!line)
+ goto out_failure;
- if (hole || alias) {
- if (alias)
- pos->end = prev->end;
- else if (hole)
- pos->end = prev->start - 1;
- }
+ 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);
+
+ return 0;
+
+out_delete_line:
+ free(line);
+out_failure:
+ return -1;
}
-static int dso__load_vmlinux(struct dso *self, const char *vmlinux,
- symbol_filter_t filter, int verbose)
+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);
if (fd < 0)
return -1;
- err = dso__load_sym(self, fd, vmlinux, filter, verbose, 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 verbose, int 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 (use_modules && dsos__load_modules(sym_priv_size) < 0) {
+ fprintf(stderr, "Failed to load list of modules in use! "
+ "Continuing...\n");
+ use_modules = 0;
+ }
if (vmlinux) {
- err = dso__load_vmlinux(self, vmlinux, filter, verbose);
- if (err > 0 && modules)
- err = dso__load_modules(self, filter, verbose);
+ err = dso__load_vmlinux(dso, kernel_map, vmlinux, filter, v);
+ if (err > 0 && use_modules) {
+ int syms = dsos__load_modules_sym(filter, v);
+
+ if (syms < 0)
+ fprintf(stderr, "Failed to read module symbols!"
+ " Continuing...\n");
+ else
+ err += syms;
+ }
}
if (err <= 0)
- err = dso__load_kallsyms(self, filter, verbose);
+ err = maps__load_kallsyms(filter, use_modules, v);
- if (err > 0)
- self->origin = DSO__ORIG_KERNEL;
+ if (err > 0) {
+ struct rb_node *node = rb_first(&dso->syms);
+ struct symbol *sym = rb_entry(node, struct symbol, rb_node);
+ /*
+ * Now that we have all sorted out, just set the ->end of all
+ * symbols that still don't have it.
+ */
+ dso__set_symbols_end(dso);
+ kernel_maps__fixup_sym_end();
+
+ 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);
+
+ if (v > 0)
+ kernel_maps__fprintf(stderr);
+ }
return err;
+
+out_delete_dso:
+ dso__delete(dso);
+ return -1;
+}
+
+LIST_HEAD(dsos);
+struct dso *vdso;
+
+const char *vmlinux_name = "vmlinux";
+int modules;
+
+static void dsos__add(struct dso *dso)
+{
+ list_add_tail(&dso->node, &dsos);
+}
+
+static struct dso *dsos__find(const char *name)
+{
+ struct dso *pos;
+
+ list_for_each_entry(pos, &dsos, node)
+ if (strcmp(pos->name, name) == 0)
+ return pos;
+ return NULL;
+}
+
+struct dso *dsos__findnew(const char *name)
+{
+ struct dso *dso = dsos__find(name);
+ int nr;
+
+ if (dso)
+ return dso;
+
+ dso = dso__new(name, 0);
+ if (!dso)
+ goto out_delete_dso;
+
+ nr = dso__load(dso, NULL, NULL, verbose);
+ if (nr < 0) {
+ eprintf("Failed to open: %s\n", name);
+ goto out_delete_dso;
+ }
+ if (!nr)
+ eprintf("No symbols found in: %s, maybe install a debug package?\n", name);
+
+ dsos__add(dso);
+
+ return dso;
+
+out_delete_dso:
+ dso__delete(dso);
+ return NULL;
+}
+
+void dsos__fprintf(FILE *fp)
+{
+ struct dso *pos;
+
+ list_for_each_entry(pos, &dsos, node)
+ dso__fprintf(pos, fp);
+}
+
+int load_kernel(void)
+{
+ if (dsos__load_kernel(vmlinux_name, 0, NULL, verbose, modules) <= 0)
+ return -1;
+
+ vdso = dso__new("[vdso]", 0);
+ if (!vdso)
+ return -1;
+
+ dsos__add(vdso);
+
+ return 0;
}
void symbol__init(void)