diff options
-rw-r--r-- | elf.h | 8 | ||||
-rw-r--r-- | linux-user/elfload.c | 75 |
2 files changed, 80 insertions, 3 deletions
@@ -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); |