Commit b68e2f91 authored by Cody P Schafer's avatar Cody P Schafer Committed by Arnaldo Carvalho de Melo

perf symbols: Introduce symsrc structure.

Factors opening of certain sections & tracking certain elf info into an
external structure.

The goal here is to keep multiple elfs (and their looked up
sections/indexes) around during the symbol generation process (in
dso__load()).

We need this to properly resolve symbols on PPC due to the use of
function descriptors & the .opd section (ie: symbols which are functions
don't point to their actual location, they point to their function
descriptor in .opd which contains their actual location.

It would be possible to just keep the (Elf *) around, but then we'd end
up with duplicate code for looking up the same sections and checking for
the existence of an important section wouldn't be as clean (and we need
to keep the Elf stuff confined to symtab-elf.c).

Utilized by the later patch
"perf symbols: Use both runtime and debug images"
Signed-off-by: default avatarCody P Schafer <cody@linux.vnet.ibm.com>
Cc: David Hansen <dave@linux.vnet.ibm.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Matt Hellsley <matthltc@us.ibm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Sukadev Bhattiprolu <sukadev@linux.vnet.ibm.com>
Link: http://lkml.kernel.org/r/1344637382-22789-12-git-send-email-cody@linux.vnet.ibm.comSigned-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 21ea4539
...@@ -536,24 +536,25 @@ static int dso__swap_init(struct dso *dso, unsigned char eidata) ...@@ -536,24 +536,25 @@ static int dso__swap_init(struct dso *dso, unsigned char eidata)
return 0; return 0;
} }
int dso__load_sym(struct dso *dso, struct map *map, const char *name, int fd,
symbol_filter_t filter, int kmodule, int want_symtab) void symsrc__destroy(struct symsrc *ss)
{
free(ss->name);
elf_end(ss->elf);
close(ss->fd);
}
int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name,
enum dso_binary_type type)
{ {
struct kmap *kmap = dso->kernel ? map__kmap(map) : NULL;
struct map *curr_map = map;
struct dso *curr_dso = dso;
Elf_Data *symstrs, *secstrs;
uint32_t nr_syms;
int err = -1; int err = -1;
uint32_t idx;
GElf_Ehdr ehdr; GElf_Ehdr ehdr;
GElf_Shdr shdr, opdshdr;
Elf_Data *syms, *opddata = NULL;
GElf_Sym sym;
Elf_Scn *sec, *sec_strndx, *opdsec;
Elf *elf; Elf *elf;
int nr = 0; int fd;
size_t opdidx = 0;
fd = open(name, O_RDONLY);
if (fd < 0)
return -1;
elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
if (elf == NULL) { if (elf == NULL) {
...@@ -580,19 +581,88 @@ int dso__load_sym(struct dso *dso, struct map *map, const char *name, int fd, ...@@ -580,19 +581,88 @@ int dso__load_sym(struct dso *dso, struct map *map, const char *name, int fd,
goto out_elf_end; goto out_elf_end;
} }
sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL); ss->symtab = elf_section_by_name(elf, &ehdr, &ss->symshdr, ".symtab",
NULL);
if (ss->symshdr.sh_type != SHT_SYMTAB)
ss->symtab = NULL;
ss->dynsym_idx = 0;
ss->dynsym = elf_section_by_name(elf, &ehdr, &ss->dynshdr, ".dynsym",
&ss->dynsym_idx);
if (ss->dynshdr.sh_type != SHT_DYNSYM)
ss->dynsym = NULL;
ss->opdidx = 0;
ss->opdsec = elf_section_by_name(elf, &ehdr, &ss->opdshdr, ".opd",
&ss->opdidx);
if (ss->opdshdr.sh_type != SHT_PROGBITS)
ss->opdsec = NULL;
if (dso->kernel == DSO_TYPE_USER) {
GElf_Shdr shdr;
ss->adjust_symbols = (ehdr.e_type == ET_EXEC ||
elf_section_by_name(elf, &ehdr, &shdr,
".gnu.prelink_undo",
NULL) != NULL);
} else {
ss->adjust_symbols = 0;
}
ss->name = strdup(name);
if (!ss->name)
goto out_elf_end;
ss->elf = elf;
ss->fd = fd;
ss->ehdr = ehdr;
ss->type = type;
return 0;
out_elf_end:
elf_end(elf);
out_close:
close(fd);
return err;
}
int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *ss,
symbol_filter_t filter, int kmodule, int want_symtab)
{
struct kmap *kmap = dso->kernel ? map__kmap(map) : NULL;
struct map *curr_map = map;
struct dso *curr_dso = dso;
Elf_Data *symstrs, *secstrs;
uint32_t nr_syms;
int err = -1;
uint32_t idx;
GElf_Ehdr ehdr;
GElf_Shdr shdr, opdshdr;
Elf_Data *syms, *opddata = NULL;
GElf_Sym sym;
Elf_Scn *sec, *sec_strndx, *opdsec;
Elf *elf;
int nr = 0;
size_t opdidx = 0;
elf = ss->elf;
ehdr = ss->ehdr;
sec = ss->symtab;
shdr = ss->symshdr;
if (sec == NULL) { if (sec == NULL) {
if (want_symtab) if (want_symtab)
goto out_elf_end; goto out_elf_end;
sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL); sec = ss->dynsym;
shdr = ss->dynshdr;
if (sec == NULL) if (sec == NULL)
goto out_elf_end; goto out_elf_end;
} }
opdsec = elf_section_by_name(elf, &ehdr, &opdshdr, ".opd", &opdidx); opdsec = ss->opdsec;
if (opdshdr.sh_type != SHT_PROGBITS) opdshdr = ss->opdshdr;
opdsec = NULL; opdidx = ss->opdidx;
if (opdsec) if (opdsec)
opddata = elf_rawdata(opdsec, NULL); opddata = elf_rawdata(opdsec, NULL);
...@@ -619,14 +689,7 @@ int dso__load_sym(struct dso *dso, struct map *map, const char *name, int fd, ...@@ -619,14 +689,7 @@ int dso__load_sym(struct dso *dso, struct map *map, const char *name, int fd,
nr_syms = shdr.sh_size / shdr.sh_entsize; nr_syms = shdr.sh_size / shdr.sh_entsize;
memset(&sym, 0, sizeof(sym)); memset(&sym, 0, sizeof(sym));
if (dso->kernel == DSO_TYPE_USER) { dso->adjust_symbols = ss->adjust_symbols;
dso->adjust_symbols = (ehdr.e_type == ET_EXEC ||
elf_section_by_name(elf, &ehdr, &shdr,
".gnu.prelink_undo",
NULL) != NULL);
} else {
dso->adjust_symbols = 0;
}
elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) { elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) {
struct symbol *f; struct symbol *f;
const char *elf_name = elf_sym__name(&sym, symstrs); const char *elf_name = elf_sym__name(&sym, symstrs);
...@@ -770,8 +833,6 @@ int dso__load_sym(struct dso *dso, struct map *map, const char *name, int fd, ...@@ -770,8 +833,6 @@ int dso__load_sym(struct dso *dso, struct map *map, const char *name, int fd,
} }
err = nr; err = nr;
out_elf_end: out_elf_end:
elf_end(elf);
out_close:
return err; return err;
} }
......
...@@ -241,6 +241,31 @@ int sysfs__read_build_id(const char *filename, void *build_id, size_t size) ...@@ -241,6 +241,31 @@ int sysfs__read_build_id(const char *filename, void *build_id, size_t size)
return ret; return ret;
} }
int symsrc__init(struct symsrc *ss, struct dso *dso __used, const char *name,
enum dso_binary_type type)
{
int fd = open(name, O_RDONLY);
if (fd < 0)
return -1;
ss->name = strdup(name);
if (!ss->name)
goto out_close;
ss->type = type;
return 0;
out_close:
close(fd);
return -1;
}
void symsrc__destroy(struct symsrc *ss)
{
free(ss->name);
close(ss->fd);
}
int dso__synthesize_plt_symbols(struct dso *dso __used, char *name __used, int dso__synthesize_plt_symbols(struct dso *dso __used, char *name __used,
struct map *map __used, struct map *map __used,
symbol_filter_t filter __used) symbol_filter_t filter __used)
...@@ -248,14 +273,13 @@ int dso__synthesize_plt_symbols(struct dso *dso __used, char *name __used, ...@@ -248,14 +273,13 @@ int dso__synthesize_plt_symbols(struct dso *dso __used, char *name __used,
return 0; return 0;
} }
int dso__load_sym(struct dso *dso, struct map *map __used, int dso__load_sym(struct dso *dso, struct map *map __used, struct symsrc *ss,
const char *name, int fd __used,
symbol_filter_t filter __used, int kmodule __used, symbol_filter_t filter __used, int kmodule __used,
int want_symtab __used) int want_symtab __used)
{ {
unsigned char *build_id[BUILD_ID_SIZE]; unsigned char *build_id[BUILD_ID_SIZE];
if (filename__read_build_id(name, build_id, BUILD_ID_SIZE) > 0) { if (filename__read_build_id(ss->name, build_id, BUILD_ID_SIZE) > 0) {
dso__set_build_id(dso, build_id); dso__set_build_id(dso, build_id);
return 1; return 1;
} }
......
...@@ -1026,7 +1026,7 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter) ...@@ -1026,7 +1026,7 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
{ {
char *name; char *name;
int ret = -1; int ret = -1;
int fd; struct symsrc ss;
u_int i; u_int i;
struct machine *machine; struct machine *machine;
char *root_dir = (char *) ""; char *root_dir = (char *) "";
...@@ -1086,13 +1086,12 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter) ...@@ -1086,13 +1086,12 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
continue; continue;
/* Name is now the name of the next image to try */ /* Name is now the name of the next image to try */
fd = open(name, O_RDONLY); if (symsrc__init(&ss, dso, name, dso->symtab_type) < 0)
if (fd < 0)
continue; continue;
ret = dso__load_sym(dso, map, name, fd, filter, 0, ret = dso__load_sym(dso, map, &ss, filter, 0,
want_symtab); want_symtab);
close(fd); symsrc__destroy(&ss);
/* /*
* Some people seem to have debuginfo files _WITHOUT_ debug * Some people seem to have debuginfo files _WITHOUT_ debug
...@@ -1359,22 +1358,23 @@ static int machine__create_modules(struct machine *machine) ...@@ -1359,22 +1358,23 @@ static int machine__create_modules(struct machine *machine)
int dso__load_vmlinux(struct dso *dso, struct map *map, int dso__load_vmlinux(struct dso *dso, struct map *map,
const char *vmlinux, symbol_filter_t filter) const char *vmlinux, symbol_filter_t filter)
{ {
int err = -1, fd; int err = -1;
struct symsrc ss;
char symfs_vmlinux[PATH_MAX]; char symfs_vmlinux[PATH_MAX];
snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s%s", snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s%s",
symbol_conf.symfs, vmlinux); symbol_conf.symfs, vmlinux);
fd = open(symfs_vmlinux, O_RDONLY);
if (fd < 0)
return -1;
if (dso->kernel == DSO_TYPE_GUEST_KERNEL) if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
dso->symtab_type = DSO_BINARY_TYPE__GUEST_VMLINUX; dso->symtab_type = DSO_BINARY_TYPE__GUEST_VMLINUX;
else else
dso->symtab_type = DSO_BINARY_TYPE__VMLINUX; dso->symtab_type = DSO_BINARY_TYPE__VMLINUX;
err = dso__load_sym(dso, map, symfs_vmlinux, fd, filter, 0, 0); if (symsrc__init(&ss, dso, symfs_vmlinux, dso->symtab_type))
close(fd); return -1;
err = dso__load_sym(dso, map, &ss, filter, 0, 0);
symsrc__destroy(&ss);
if (err > 0) { if (err > 0) {
dso__set_long_name(dso, (char *)vmlinux); dso__set_long_name(dso, (char *)vmlinux);
......
...@@ -11,6 +11,12 @@ ...@@ -11,6 +11,12 @@
#include <stdio.h> #include <stdio.h>
#include <byteswap.h> #include <byteswap.h>
#ifndef NO_LIBELF_SUPPORT
#include <libelf.h>
#include <gelf.h>
#include <elf.h>
#endif
#ifdef HAVE_CPLUS_DEMANGLE #ifdef HAVE_CPLUS_DEMANGLE
extern char *cplus_demangle(const char *, int); extern char *cplus_demangle(const char *, int);
...@@ -219,6 +225,34 @@ struct dso { ...@@ -219,6 +225,34 @@ struct dso {
char name[0]; char name[0];
}; };
struct symsrc {
char *name;
int fd;
enum dso_binary_type type;
#ifndef NO_LIBELF_SUPPORT
Elf *elf;
GElf_Ehdr ehdr;
Elf_Scn *opdsec;
size_t opdidx;
GElf_Shdr opdshdr;
Elf_Scn *symtab;
GElf_Shdr symshdr;
Elf_Scn *dynsym;
size_t dynsym_idx;
GElf_Shdr dynshdr;
bool adjust_symbols;
#endif
};
void symsrc__destroy(struct symsrc *ss);
int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name,
enum dso_binary_type type);
#define DSO__SWAP(dso, type, val) \ #define DSO__SWAP(dso, type, val) \
({ \ ({ \
type ____r = val; \ type ____r = val; \
...@@ -334,7 +368,7 @@ ssize_t dso__data_read_addr(struct dso *dso, struct map *map, ...@@ -334,7 +368,7 @@ ssize_t dso__data_read_addr(struct dso *dso, struct map *map,
struct machine *machine, u64 addr, struct machine *machine, u64 addr,
u8 *data, ssize_t size); u8 *data, ssize_t size);
int dso__test_data(void); int dso__test_data(void);
int dso__load_sym(struct dso *dso, struct map *map, const char *name, int fd, int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *ss,
symbol_filter_t filter, int kmodule, int want_symtab); symbol_filter_t filter, int kmodule, int want_symtab);
int dso__synthesize_plt_symbols(struct dso *dso, char *name, struct map *map, int dso__synthesize_plt_symbols(struct dso *dso, char *name, struct map *map,
symbol_filter_t filter); symbol_filter_t filter);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment