aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--elf.h8
-rw-r--r--linux-user/elfload.c75
2 files changed, 80 insertions, 3 deletions
diff --git a/elf.h b/elf.h
index d87526a7d8..fcd3fecb4a 100644
--- a/elf.h
+++ b/elf.h
@@ -1,5 +1,5 @@
-#ifndef _ELF_H
-#define _ELF_H
+#ifndef _QEMU_ELF_H
+#define _QEMU_ELF_H
#include <inttypes.h>
@@ -996,6 +996,7 @@ typedef struct elf64_note {
#define elf_phdr elf32_phdr
#define elf_note elf32_note
#define elf_shdr elf32_shdr
+#define elf_sym elf32_sym
#ifdef ELF_USES_RELOCA
# define ELF_RELOC Elf32_Rela
@@ -1009,6 +1010,7 @@ typedef struct elf64_note {
#define elf_phdr elf64_phdr
#define elf_note elf64_note
#define elf_shdr elf64_shdr
+#define elf_sym elf64_sym
#ifdef ELF_USES_RELOCA
# define ELF_RELOC Elf64_Rela
@@ -1029,4 +1031,4 @@ typedef struct elf64_note {
#endif
-#endif /* _ELF_H */
+#endif /* _QEMU_ELF_H */
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 2974c01fe0..edb3176bcb 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -11,6 +11,7 @@
#include <string.h>
#include "qemu.h"
+#include "disas.h"
#ifdef TARGET_I386
@@ -195,6 +196,28 @@ static void bswap_phdr(Elf32_Phdr *phdr)
bswap32s(&phdr->p_flags); /* Segment flags */
bswap32s(&phdr->p_align); /* Segment alignment */
}
+
+static void bswap_shdr(Elf32_Shdr *shdr)
+{
+ bswap32s(&shdr->sh_name);
+ bswap32s(&shdr->sh_type);
+ bswap32s(&shdr->sh_flags);
+ bswap32s(&shdr->sh_addr);
+ bswap32s(&shdr->sh_offset);
+ bswap32s(&shdr->sh_size);
+ bswap32s(&shdr->sh_link);
+ bswap32s(&shdr->sh_info);
+ bswap32s(&shdr->sh_addralign);
+ bswap32s(&shdr->sh_entsize);
+}
+
+static void bswap_sym(Elf32_Sym *sym)
+{
+ bswap32s(&sym->st_name);
+ bswap32s(&sym->st_value);
+ bswap32s(&sym->st_size);
+ bswap16s(&sym->st_shndx);
+}
#endif
static void * get_free_page(void)
@@ -656,7 +679,56 @@ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
return ((unsigned long) interp_elf_ex->e_entry) + load_addr;
}
+/* Best attempt to load symbols from this ELF object. */
+static void load_symbols(struct elfhdr *hdr, int fd)
+{
+ unsigned int i;
+ struct elf_shdr sechdr, symtab, strtab;
+ char *strings;
+
+ lseek(fd, hdr->e_shoff, SEEK_SET);
+ for (i = 0; i < hdr->e_shnum; i++) {
+ if (read(fd, &sechdr, sizeof(sechdr)) != sizeof(sechdr))
+ return;
+#ifdef BSWAP_NEEDED
+ bswap_shdr(&sechdr);
+#endif
+ if (sechdr.sh_type == SHT_SYMTAB) {
+ symtab = sechdr;
+ lseek(fd, hdr->e_shoff
+ + sizeof(sechdr) * sechdr.sh_link, SEEK_SET);
+ if (read(fd, &strtab, sizeof(strtab))
+ != sizeof(strtab))
+ return;
+#ifdef BSWAP_NEEDED
+ bswap_shdr(&strtab);
+#endif
+ goto found;
+ }
+ }
+ return; /* Shouldn't happen... */
+
+ found:
+ /* Now know where the strtab and symtab are. Snarf them. */
+ disas_symtab = malloc(symtab.sh_size);
+ disas_strtab = strings = malloc(strtab.sh_size);
+ if (!disas_symtab || !disas_strtab)
+ return;
+
+ lseek(fd, symtab.sh_offset, SEEK_SET);
+ if (read(fd, disas_symtab, symtab.sh_size) != symtab.sh_size)
+ return;
+#ifdef BSWAP_NEEDED
+ for (i = 0; i < symtab.sh_size / sizeof(struct elf_sym); i++)
+ bswap_sym(disas_symtab + sizeof(struct elf_sym)*i);
+#endif
+
+ lseek(fd, strtab.sh_offset, SEEK_SET);
+ if (read(fd, strings, strtab.sh_size) != strtab.sh_size)
+ return;
+ disas_num_syms = symtab.sh_size / sizeof(struct elf_sym);
+}
static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
struct image_info * info)
@@ -989,6 +1061,9 @@ static int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * r
free(elf_phdata);
+ if (loglevel)
+ load_symbols(&elf_ex, bprm->fd);
+
if (interpreter_type != INTERPRETER_AOUT) close(bprm->fd);
info->personality = (ibcs2_interpreter ? PER_SVR4 : PER_LINUX);