From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 483 invoked by alias); 14 May 2003 01:28:53 -0000 Mailing-List: contact gdb-patches-help@sources.redhat.com; run by ezmlm Precedence: bulk List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sources.redhat.com Received: (qmail 464 invoked from network); 14 May 2003 01:28:52 -0000 Received: from unknown (HELO gateway.sf.frob.com) (64.163.213.212) by sources.redhat.com with SMTP; 14 May 2003 01:28:52 -0000 Received: from magilla.sf.frob.com (magilla.sf.frob.com [198.49.250.228]) by gateway.sf.frob.com (Postfix) with ESMTP id 70442354C; Tue, 13 May 2003 18:28:51 -0700 (PDT) Received: (from roland@localhost) by magilla.sf.frob.com (8.11.6/8.11.6) id h4E1Spw06177; Tue, 13 May 2003 18:28:51 -0700 Date: Wed, 14 May 2003 01:28:00 -0000 Message-Id: <200305140128.h4E1Spw06177@magilla.sf.frob.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit From: Roland McGrath To: binutils@sources.redhat.com, gdb-patches@sources.redhat.com Subject: bfd function to read ELF file image from memory X-SW-Source: 2003-05/txt/msg00208.txt.bz2 This bfd patch adds a function that creates an in-memory BFD by reading from process memory to read ELF headers and from that determine the size of the whole file image to read out of the process. I am using this in gdb to read the Linux vsyscall DSO image from a live process; the details of what that is all about have been discussed on the gdb@sources.redhat.com list. I wrote this as a BFD function that takes a callback function pointer with the same signature as gdb's `target_read_memory'. This function is not really all that generally useful as it is. It assumes that the memory image simply maps the whole file image verbatim. That works great for the vsyscall DSO. But for a normal DSO that has a data segment, that is not how the memory looks. For those, this will create a bfd that has bogus contents for the parts of the file after the end of the text segment; the data segment will be bogus, and so will the section headers because they appear at the end of the file (and perhaps not at all in the memory image). Ultimately a more useful function would be one that only tries to read the contents of the PT_LOAD segments and places their contents appropriately in the bfd's in-memory file image. As things stand in gdb we need the section headers for the vsyscall DSO, but it so happens that its sole PT_LOAD segment when taken with alignment covers the whole file image. So I may rewrite it that way. But all of that is a bit of a digression. I'm posting now because I don't quite know where to put this function even it its implementation were perfect. It was by far easier to write it in elfcode.h than to put it elsewhere. It gets to use the local helper code there, and automagically define 32 and 64 bit flavors, which keeps the code quite simple. It would be a lot more hair to put the code elsewhere, copy the header swapping code, and do the 32/64 versions half as cleanly. The proper way to put it there is to make it yet another bfd target vector function. I don't know what all rigamorole is involved in doing that, and it seems like overkill for something probably only ever used by gdb and only with ELF. For testing purposes, I have added a gdb command that makes use of this. It's code that doesn't need to be target-specific except for by what name to call this function. Right now I just have it kludged to do runtime checks with bfd_get_flavour and bfd_get_arch_size, but that is code that won't build properly if libbfd doesn't have some elf32 and elf64 targets configured in. Can anyone offer advice on where this function ought to live? If it doesn't live in the bfd elf backend, then I'll have to copy or hand-integrate some sanity checking and byte-swapping code for ELF headers. Thanks, Roland --- elfcode.h.~1.41.~ Sat May 10 15:09:29 2003 +++ elfcode.h Tue May 13 17:49:15 2003 @@ -1568,6 +1568,201 @@ elf_symbol_flags (flags) } #endif +/* Create a new BFD as if by bfd_openr. Rather than opening a file, read + an ELF file image out of remote memory based on the ELF file header + found at EHDR_VMA. The function TARGET_READ_MEMORY is called to read + remote memory regions by VMA. TEMPL must be a BFD for a target with the + word size and byte order found in the remote memory. */ + +bfd * +NAME(bfd_elf,bfd_from_memory) + (bfd *templ, bfd_vma ehdr_vma, + int (*target_read_memory) (bfd_vma vma, char *myaddr, int len)) +{ + Elf_External_Ehdr x_ehdr; /* Elf file header, external form */ + Elf_Internal_Ehdr ehdr; /* Elf file header, internal form */ + bfd *nbfd; + struct bfd_in_memory *bim; + int contents_size; + char *contents; + int err; + + /* Read in the ELF header in external format. */ + err = target_read_memory (ehdr_vma, (char *) &x_ehdr, sizeof x_ehdr); + if (err) + { + bfd_set_error (bfd_error_system_call); + errno = err; + return NULL; + } + + /* Now check to see if we have a valid ELF file, and one that BFD can + make use of. The magic number must match, the address size ('class') + and byte-swapping must match our XVEC entry. */ + + if (! elf_file_p (&x_ehdr) + || x_ehdr.e_ident[EI_VERSION] != EV_CURRENT + || x_ehdr.e_ident[EI_CLASS] != ELFCLASS) + { + bfd_set_error (bfd_error_wrong_format); + return NULL; + } + + /* Check that file's byte order matches xvec's */ + switch (x_ehdr.e_ident[EI_DATA]) + { + case ELFDATA2MSB: /* Big-endian */ + if (! bfd_header_big_endian (templ)) + { + bfd_set_error (bfd_error_wrong_format); + return NULL; + } + break; + case ELFDATA2LSB: /* Little-endian */ + if (! bfd_header_little_endian (templ)) + { + bfd_set_error (bfd_error_wrong_format); + return NULL; + } + break; + case ELFDATANONE: /* No data encoding specified */ + default: /* Unknown data encoding specified */ + bfd_set_error (bfd_error_wrong_format); + return NULL; + } + + elf_swap_ehdr_in (templ, &x_ehdr, &ehdr); + + /* The file header tells where to find the phdrs and section headers, + which tells us how big the file is. */ + + contents_size = ehdr.e_ehsize; +#define BUMP(to) if (contents_size < (int) (to)) contents_size = (to) + + BUMP (ehdr.e_phoff + ehdr.e_phnum * ehdr.e_phentsize); + if (ehdr.e_phentsize == sizeof (Elf_External_Phdr)) + { + unsigned int i; + Elf_Internal_Phdr phdr; + Elf_External_Phdr *x_phdrs + = (Elf_External_Phdr *) bfd_malloc (ehdr.e_phnum * sizeof *x_phdrs); + if (x_phdrs == NULL) + { + bfd_set_error (bfd_error_no_memory); + return NULL; + } + err = target_read_memory (ehdr_vma + ehdr.e_phoff, + (char *) x_phdrs, + ehdr.e_phnum * sizeof *x_phdrs); + if (err) + { + free (x_phdrs); + bfd_set_error (bfd_error_system_call); + errno = err; + return NULL; + } + for (i = 0; i < ehdr.e_phnum; ++i) + { + elf_swap_phdr_in (templ, &x_phdrs[i], &phdr); + BUMP (phdr.p_offset + phdr.p_filesz); + } + free (x_phdrs); + } + else if (ehdr.e_phentsize != 0 && ehdr.e_phnum != 0) + { + bfd_set_error (bfd_error_wrong_format); + return NULL; + } + + BUMP (ehdr.e_shoff + ehdr.e_shnum * ehdr.e_shentsize); + if (ehdr.e_shentsize == sizeof (Elf_External_Shdr)) + { + unsigned int i; + Elf_Internal_Shdr shdr; + Elf_External_Shdr *x_shdrs + = (Elf_External_Shdr *) bfd_malloc (ehdr.e_shnum * sizeof *x_shdrs); + if (x_shdrs == NULL) + { + bfd_set_error (bfd_error_no_memory); + return NULL; + } + err = target_read_memory (ehdr_vma + ehdr.e_shoff, + (char *) x_shdrs, + ehdr.e_shnum * sizeof *x_shdrs); + if (err) + { + free (x_shdrs); + bfd_set_error (bfd_error_system_call); + errno = err; + return NULL; + } + for (i = 0; i < ehdr.e_shnum; ++i) + { + elf_swap_shdr_in (templ, &x_shdrs[i], &shdr); + BUMP (shdr.sh_offset + + ((shdr.sh_flags & SHF_ALLOC) ? shdr.sh_size : 0)); + } + free (x_shdrs); + } + else if (ehdr.e_shentsize != 0 && ehdr.e_shnum != 0) + { + bfd_set_error (bfd_error_wrong_format); + return NULL; + } + +#undef BUMP + + /* Now we know the size of the whole image we want read in. */ + + contents = (char *) bfd_malloc ((bfd_size_type) contents_size); + if (contents == NULL) + { + bfd_set_error (bfd_error_no_memory); + return NULL; + } + /* We already read the ELF header, no need to copy it in again. */ + memcpy (contents, &x_ehdr, sizeof x_ehdr); + err = target_read_memory (ehdr_vma + sizeof x_ehdr, contents + sizeof x_ehdr, + contents_size - sizeof x_ehdr); + if (err) + { + free (contents); + bfd_set_error (bfd_error_system_call); + errno = err; + return NULL; + } + + /* Now we have a memory image of the ELF file contents. Make a BFD. */ + bim = ((struct bfd_in_memory *) + bfd_malloc ((bfd_size_type) sizeof (struct bfd_in_memory))); + if (bim == NULL) + { + free (contents); + bfd_set_error (bfd_error_no_memory); + return NULL; + } + nbfd = _bfd_new_bfd (); + if (nbfd == NULL) + { + free (bim); + free (contents); + bfd_set_error (bfd_error_no_memory); + return NULL; + } + nbfd->filename = ""; + if (templ) + nbfd->xvec = templ->xvec; + bim->size = contents_size; + bim->buffer = contents; + nbfd->iostream = (PTR) bim; + nbfd->flags = BFD_IN_MEMORY; + nbfd->direction = read_direction; + nbfd->mtime = time (NULL); + nbfd->mtime_set = TRUE; + + return nbfd; +} + #include "elfcore.h" #include "elflink.h"