linux-user: Use ImageSource in load_symbols

Aside from the section headers, we're unlikely to hit the
ImageSource cache on guest executables.  But the interface
for imgsrc_read_* is better.

Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
Richard Henderson 2021-06-16 20:59:49 -07:00
parent 3bd0238638
commit 86cf82dc9f

View file

@ -2201,7 +2201,8 @@ static inline void bswap_mips_abiflags(Mips_elf_abiflags_v0 *abiflags) { }
#ifdef USE_ELF_CORE_DUMP #ifdef USE_ELF_CORE_DUMP
static int elf_core_dump(int, const CPUArchState *); static int elf_core_dump(int, const CPUArchState *);
#endif /* USE_ELF_CORE_DUMP */ #endif /* USE_ELF_CORE_DUMP */
static void load_symbols(struct elfhdr *hdr, int fd, abi_ulong load_bias); static void load_symbols(struct elfhdr *hdr, const ImageSource *src,
abi_ulong load_bias);
/* Verify the portions of EHDR within E_IDENT for the target. /* Verify the portions of EHDR within E_IDENT for the target.
This can be performed before bswapping the entire header. */ This can be performed before bswapping the entire header. */
@ -3473,7 +3474,7 @@ static void load_elf_image(const char *image_name, const ImageSource *src,
} }
if (qemu_log_enabled()) { if (qemu_log_enabled()) {
load_symbols(ehdr, src->fd, load_bias); load_symbols(ehdr, src, load_bias);
} }
debuginfo_report_elf(image_name, src->fd, load_bias); debuginfo_report_elf(image_name, src->fd, load_bias);
@ -3564,19 +3565,20 @@ static int symcmp(const void *s0, const void *s1)
} }
/* Best attempt to load symbols from this ELF object. */ /* Best attempt to load symbols from this ELF object. */
static void load_symbols(struct elfhdr *hdr, int fd, abi_ulong load_bias) static void load_symbols(struct elfhdr *hdr, const ImageSource *src,
abi_ulong load_bias)
{ {
int i, shnum, nsyms, sym_idx = 0, str_idx = 0; int i, shnum, nsyms, sym_idx = 0, str_idx = 0;
uint64_t segsz; g_autofree struct elf_shdr *shdr = NULL;
struct elf_shdr *shdr;
char *strings = NULL; char *strings = NULL;
struct syminfo *s = NULL; struct elf_sym *syms = NULL;
struct elf_sym *new_syms, *syms = NULL; struct elf_sym *new_syms;
uint64_t segsz;
shnum = hdr->e_shnum; shnum = hdr->e_shnum;
i = shnum * sizeof(struct elf_shdr); shdr = imgsrc_read_alloc(hdr->e_shoff, shnum * sizeof(struct elf_shdr),
shdr = (struct elf_shdr *)alloca(i); src, NULL);
if (pread(fd, shdr, i, hdr->e_shoff) != i) { if (shdr == NULL) {
return; return;
} }
@ -3594,31 +3596,33 @@ static void load_symbols(struct elfhdr *hdr, int fd, abi_ulong load_bias)
found: found:
/* Now know where the strtab and symtab are. Snarf them. */ /* Now know where the strtab and symtab are. Snarf them. */
s = g_try_new(struct syminfo, 1);
if (!s) {
goto give_up;
}
segsz = shdr[str_idx].sh_size; segsz = shdr[str_idx].sh_size;
s->disas_strtab = strings = g_try_malloc(segsz); strings = g_try_malloc(segsz);
if (!strings || if (!strings) {
pread(fd, strings, segsz, shdr[str_idx].sh_offset) != segsz) { goto give_up;
}
if (!imgsrc_read(strings, shdr[str_idx].sh_offset, segsz, src, NULL)) {
goto give_up; goto give_up;
} }
segsz = shdr[sym_idx].sh_size; segsz = shdr[sym_idx].sh_size;
syms = g_try_malloc(segsz);
if (!syms || pread(fd, syms, segsz, shdr[sym_idx].sh_offset) != segsz) {
goto give_up;
}
if (segsz / sizeof(struct elf_sym) > INT_MAX) { if (segsz / sizeof(struct elf_sym) > INT_MAX) {
/* Implausibly large symbol table: give up rather than ploughing /*
* on with the number of symbols calculation overflowing * Implausibly large symbol table: give up rather than ploughing
* on with the number of symbols calculation overflowing.
*/ */
goto give_up; goto give_up;
} }
nsyms = segsz / sizeof(struct elf_sym); nsyms = segsz / sizeof(struct elf_sym);
syms = g_try_malloc(segsz);
if (!syms) {
goto give_up;
}
if (!imgsrc_read(syms, shdr[sym_idx].sh_offset, segsz, src, NULL)) {
goto give_up;
}
for (i = 0; i < nsyms; ) { for (i = 0; i < nsyms; ) {
bswap_sym(syms + i); bswap_sym(syms + i);
/* Throw away entries which we do not need. */ /* Throw away entries which we do not need. */
@ -3643,10 +3647,12 @@ static void load_symbols(struct elfhdr *hdr, int fd, abi_ulong load_bias)
goto give_up; goto give_up;
} }
/* Attempt to free the storage associated with the local symbols /*
that we threw away. Whether or not this has any effect on the * Attempt to free the storage associated with the local symbols
memory allocation depends on the malloc implementation and how * that we threw away. Whether or not this has any effect on the
many symbols we managed to discard. */ * memory allocation depends on the malloc implementation and how
* many symbols we managed to discard.
*/
new_syms = g_try_renew(struct elf_sym, syms, nsyms); new_syms = g_try_renew(struct elf_sym, syms, nsyms);
if (new_syms == NULL) { if (new_syms == NULL) {
goto give_up; goto give_up;
@ -3655,6 +3661,10 @@ static void load_symbols(struct elfhdr *hdr, int fd, abi_ulong load_bias)
qsort(syms, nsyms, sizeof(*syms), symcmp); qsort(syms, nsyms, sizeof(*syms), symcmp);
{
struct syminfo *s = g_new(struct syminfo, 1);
s->disas_strtab = strings;
s->disas_num_syms = nsyms; s->disas_num_syms = nsyms;
#if ELF_CLASS == ELFCLASS32 #if ELF_CLASS == ELFCLASS32
s->disas_symtab.elf32 = syms; s->disas_symtab.elf32 = syms;
@ -3664,11 +3674,10 @@ static void load_symbols(struct elfhdr *hdr, int fd, abi_ulong load_bias)
s->lookup_symbol = lookup_symbolxx; s->lookup_symbol = lookup_symbolxx;
s->next = syminfos; s->next = syminfos;
syminfos = s; syminfos = s;
}
return; return;
give_up: give_up:
g_free(s);
g_free(strings); g_free(strings);
g_free(syms); g_free(syms);
} }