From patchwork Mon Aug 3 14:45:06 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nathan Froyd X-Patchwork-Id: 30596 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [199.232.76.165]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by bilbo.ozlabs.org (Postfix) with ESMTPS id 0598CB6F34 for ; Tue, 4 Aug 2009 03:03:25 +1000 (EST) Received: from localhost ([127.0.0.1]:49601 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1MY0wS-00087e-NQ for incoming@patchwork.ozlabs.org; Mon, 03 Aug 2009 13:03:20 -0400 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1MXytM-0007Vq-23 for qemu-devel@nongnu.org; Mon, 03 Aug 2009 10:52:00 -0400 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1MXytG-0007Tg-AN for qemu-devel@nongnu.org; Mon, 03 Aug 2009 10:51:59 -0400 Received: from [199.232.76.173] (port=47669 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1MXytG-0007TQ-1K for qemu-devel@nongnu.org; Mon, 03 Aug 2009 10:51:54 -0400 Received: from mx20.gnu.org ([199.232.41.8]:47634) by monty-python.gnu.org with esmtps (TLS-1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.60) (envelope-from ) id 1MXytF-0006Wi-Hg for qemu-devel@nongnu.org; Mon, 03 Aug 2009 10:51:53 -0400 Received: from mail.codesourcery.com ([65.74.133.4]) by mx20.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1MXytE-0001fz-MU for qemu-devel@nongnu.org; Mon, 03 Aug 2009 10:51:53 -0400 Received: (qmail 16842 invoked from network); 3 Aug 2009 14:45:11 -0000 Received: from unknown (HELO localhost) (froydnj@127.0.0.2) by mail.codesourcery.com with ESMTPA; 3 Aug 2009 14:45:11 -0000 From: Nathan Froyd To: qemu-devel@nongnu.org Date: Mon, 3 Aug 2009 07:45:06 -0700 Message-Id: <1249310711-8873-2-git-send-email-froydnj@codesourcery.com> X-Mailer: git-send-email 1.6.3.2 In-Reply-To: <1249310711-8873-1-git-send-email-froydnj@codesourcery.com> References: <1249310711-8873-1-git-send-email-froydnj@codesourcery.com> X-Detected-Operating-System: by mx20.gnu.org: GNU/Linux 2.6, seldom 2.4 (older, 4) X-detected-operating-system: by monty-python.gnu.org: GNU/Linux 2.6, seldom 2.4 (older, 4) Subject: [Qemu-devel] [PATCH 1/6] sysemu: add section_callback argument to ELF loader X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Some targets indicate properties of the program with special sections in the ELF file--MIPS in particular. This infrastructure is useful for grovelling through those sections. Signed-off-by: Nathan Froyd --- elf_ops.h | 34 +++++++++++++++++++++++++++++++--- loader.c | 19 ++++++++++++++----- sysemu.h | 5 +++++ 3 files changed, 50 insertions(+), 8 deletions(-) diff --git a/elf_ops.h b/elf_ops.h index 699651c..0acbcc7 100644 --- a/elf_ops.h +++ b/elf_ops.h @@ -98,7 +98,13 @@ static int glue(symcmp, SZ)(const void *s0, const void *s1) : ((sym0->st_value > sym1->st_value) ? 1 : 0); } -static int glue(load_symbols, SZ)(struct elfhdr *ehdr, int fd, int must_swab) +/* Load function symbols for later groveling. If SECTION_CALLBACK is + non-NULL, it will be called with information about each section in + the binary. This interface enables to the caller to mine the binary + for useful information about the ABI, such as whether the CPU chosen is + compatible with the binary. */ +static int glue(load_symbols, SZ)(struct elfhdr *ehdr, int fd, int must_swab, + section_callback_t section_callback) { struct elf_shdr *symtab, *strtab, *shdr_table = NULL; struct elf_sym *syms = NULL; @@ -117,6 +123,27 @@ static int glue(load_symbols, SZ)(struct elfhdr *ehdr, int fd, int must_swab) } } + /* Permit machines to grovel through the ELF file looking for + interesting bits of information. */ + if (section_callback && ehdr->e_shstrndx != SHN_UNDEF) { + char *shstr = NULL; + struct elf_shdr *shstrtab = &shdr_table[ehdr->e_shstrndx]; + + shstr = load_at(fd, shstrtab->sh_offset, shstrtab->sh_size); + if (!shstr) + goto fail_callback; + + for (i = 0; i < ehdr->e_shnum; i++) { + struct elf_shdr *sh = shdr_table + i; + + section_callback(fd, must_swab, sh->sh_size, sh->sh_offset, + &shstr[sh->sh_name]); + } + + fail_callback: + free (shstr); + } + symtab = glue(find_section, SZ)(shdr_table, ehdr->e_shnum, SHT_SYMTAB); if (!symtab) goto fail; @@ -179,7 +206,8 @@ static int glue(load_symbols, SZ)(struct elfhdr *ehdr, int fd, int must_swab) static int glue(load_elf, SZ)(int fd, int64_t address_offset, int must_swab, uint64_t *pentry, - uint64_t *lowaddr, uint64_t *highaddr) + uint64_t *lowaddr, uint64_t *highaddr, + section_callback_t section_callback) { struct elfhdr ehdr; struct elf_phdr *phdr = NULL, *ph; @@ -213,7 +241,7 @@ static int glue(load_elf, SZ)(int fd, int64_t address_offset, if (pentry) *pentry = (uint64_t)(elf_sword)ehdr.e_entry; - glue(load_symbols, SZ)(&ehdr, fd, must_swab); + glue(load_symbols, SZ)(&ehdr, fd, must_swab, section_callback); size = ehdr.e_phnum * sizeof(phdr[0]); lseek(fd, ehdr.e_phoff, SEEK_SET); diff --git a/loader.c b/loader.c index 0cbcf9c..6f025a9 100644 --- a/loader.c +++ b/loader.c @@ -305,9 +305,10 @@ static void *load_at(int fd, int offset, int size) #define SZ 64 #include "elf_ops.h" -/* return < 0 if error, otherwise the number of bytes loaded in memory */ -int load_elf(const char *filename, int64_t address_offset, - uint64_t *pentry, uint64_t *lowaddr, uint64_t *highaddr) +int load_elf_introspect(const char *filename, int64_t address_offset, + uint64_t *pentry, uint64_t *lowaddr, + uint64_t *highaddr, + section_callback_t section_callback) { int fd, data_order, host_data_order, must_swab, ret; uint8_t e_ident[EI_NIDENT]; @@ -342,10 +343,10 @@ int load_elf(const char *filename, int64_t address_offset, lseek(fd, 0, SEEK_SET); if (e_ident[EI_CLASS] == ELFCLASS64) { ret = load_elf64(fd, address_offset, must_swab, pentry, - lowaddr, highaddr); + lowaddr, highaddr, section_callback); } else { ret = load_elf32(fd, address_offset, must_swab, pentry, - lowaddr, highaddr); + lowaddr, highaddr, section_callback); } close(fd); @@ -356,6 +357,14 @@ int load_elf(const char *filename, int64_t address_offset, return -1; } +/* return < 0 if error, otherwise the number of bytes loaded in memory */ +int load_elf(const char *filename, int64_t address_offset, + uint64_t *pentry, uint64_t *lowaddr, uint64_t *highaddr) +{ + return load_elf_introspect (filename, address_offset, pentry, lowaddr, + highaddr, NULL); +} + static void bswap_uboot_header(uboot_image_header_t *hdr) { #ifndef HOST_WORDS_BIGENDIAN diff --git a/sysemu.h b/sysemu.h index 6af88d8..b26cf40 100644 --- a/sysemu.h +++ b/sysemu.h @@ -241,6 +241,11 @@ int load_image(const char *filename, uint8_t *addr); /* deprecated */ int load_image_targphys(const char *filename, target_phys_addr_t, int max_sz); int load_elf(const char *filename, int64_t address_offset, uint64_t *pentry, uint64_t *lowaddr, uint64_t *highaddr); +typedef void (*section_callback_t)(int fd, int must_swab, + uint64_t size, uint64_t offset, char *name); +int load_elf_introspect(const char *filename, int64_t address_offset, + uint64_t *pentry, uint64_t *lowaddr, + uint64_t *highaddr, section_callback_t callback); int load_aout(const char *filename, target_phys_addr_t addr, int max_sz); int load_uimage(const char *filename, target_ulong *ep, target_ulong *loadaddr, int *is_linux);