diff options
Diffstat (limited to 'src/libdwfl/elf-from-memory.c')
-rw-r--r-- | src/libdwfl/elf-from-memory.c | 370 |
1 files changed, 0 insertions, 370 deletions
diff --git a/src/libdwfl/elf-from-memory.c b/src/libdwfl/elf-from-memory.c deleted file mode 100644 index b35fac71..00000000 --- a/src/libdwfl/elf-from-memory.c +++ /dev/null @@ -1,370 +0,0 @@ -/* Reconstruct an ELF file by reading the segments out of remote memory. - Copyright (C) 2005-2011, 2014 Red Hat, Inc. - This file is part of elfutils. - - This file is free software; you can redistribute it and/or modify - it under the terms of either - - * the GNU Lesser General Public License as published by the Free - Software Foundation; either version 3 of the License, or (at - your option) any later version - - or - - * the GNU General Public License as published by the Free - Software Foundation; either version 2 of the License, or (at - your option) any later version - - or both in parallel, as here. - - elfutils is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received copies of the GNU General Public License and - the GNU Lesser General Public License along with this program. If - not, see <http://www.gnu.org/licenses/>. */ - -#include <config.h> -#include "../libelf/libelfP.h" -#undef _ - -#include "libdwflP.h" - -#include <gelf.h> -#include <sys/types.h> -#include <stdbool.h> -#include <stdlib.h> -#include <string.h> - -/* Reconstruct an ELF file by reading the segments out of remote memory - based on the ELF file header at EHDR_VMA and the ELF program headers it - points to. If not null, *LOADBASEP is filled in with the difference - between the addresses from which the segments were read, and the - addresses the file headers put them at. - - The function READ_MEMORY is called to copy at least MINREAD and at most - MAXREAD bytes from the remote memory at target address ADDRESS into the - local buffer at DATA; it should return -1 for errors (with code in - `errno'), 0 if it failed to read at least MINREAD bytes due to EOF, or - the number of bytes read if >= MINREAD. ARG is passed through. - - PAGESIZE is the minimum page size and alignment used for the PT_LOAD - segments. */ - -Elf * -elf_from_remote_memory (GElf_Addr ehdr_vma, - GElf_Xword pagesize, - GElf_Addr *loadbasep, - ssize_t (*read_memory) (void *arg, void *data, - GElf_Addr address, - size_t minread, - size_t maxread), - void *arg) -{ - /* First read in the file header and check its sanity. */ - - const size_t initial_bufsize = 256; - unsigned char *buffer = malloc (initial_bufsize); - if (buffer == NULL) - { - no_memory: - __libdwfl_seterrno (DWFL_E_NOMEM); - return NULL; - } - - ssize_t nread = (*read_memory) (arg, buffer, ehdr_vma, - sizeof (Elf32_Ehdr), initial_bufsize); - if (nread <= 0) - { - read_error: - free (buffer); - __libdwfl_seterrno (nread < 0 ? DWFL_E_ERRNO : DWFL_E_TRUNCATED); - return NULL; - } - - if (memcmp (buffer, ELFMAG, SELFMAG) != 0) - { - bad_elf: - free (buffer); - __libdwfl_seterrno (DWFL_E_BADELF); - return NULL; - } - - /* Extract the information we need from the file header. */ - - union - { - Elf32_Ehdr e32; - Elf64_Ehdr e64; - } ehdr; - Elf_Data xlatefrom = - { - .d_type = ELF_T_EHDR, - .d_buf = buffer, - .d_version = EV_CURRENT, - }; - Elf_Data xlateto = - { - .d_type = ELF_T_EHDR, - .d_buf = &ehdr, - .d_size = sizeof ehdr, - .d_version = EV_CURRENT, - }; - - GElf_Off phoff; - uint_fast16_t phnum; - uint_fast16_t phentsize; - GElf_Off shdrs_end; - - switch (buffer[EI_CLASS]) - { - case ELFCLASS32: - xlatefrom.d_size = sizeof (Elf32_Ehdr); - if (elf32_xlatetom (&xlateto, &xlatefrom, buffer[EI_DATA]) == NULL) - { - libelf_error: - __libdwfl_seterrno (DWFL_E_LIBELF); - return NULL; - } - phoff = ehdr.e32.e_phoff; - phnum = ehdr.e32.e_phnum; - phentsize = ehdr.e32.e_phentsize; - if (phentsize != sizeof (Elf32_Phdr) || phnum == 0) - goto bad_elf; - shdrs_end = ehdr.e32.e_shoff + ehdr.e32.e_shnum * ehdr.e32.e_shentsize; - break; - - case ELFCLASS64: - xlatefrom.d_size = sizeof (Elf64_Ehdr); - if (elf64_xlatetom (&xlateto, &xlatefrom, buffer[EI_DATA]) == NULL) - goto libelf_error; - phoff = ehdr.e64.e_phoff; - phnum = ehdr.e64.e_phnum; - phentsize = ehdr.e64.e_phentsize; - if (phentsize != sizeof (Elf64_Phdr) || phnum == 0) - goto bad_elf; - shdrs_end = ehdr.e64.e_shoff + ehdr.e64.e_shnum * ehdr.e64.e_shentsize; - break; - - default: - goto bad_elf; - } - - - /* The file header tells where to find the program headers. - These are what we use to actually choose what to read. */ - - xlatefrom.d_type = xlateto.d_type = ELF_T_PHDR; - xlatefrom.d_size = phnum * phentsize; - - if ((size_t) nread >= phoff + phnum * phentsize) - /* We already have all the phdrs from the initial read. */ - xlatefrom.d_buf = buffer + phoff; - else - { - /* Read in the program headers. */ - - if (initial_bufsize < phnum * phentsize) - { - unsigned char *newbuf = realloc (buffer, phnum * phentsize); - if (newbuf == NULL) - { - free (buffer); - goto no_memory; - } - buffer = newbuf; - } - nread = (*read_memory) (arg, buffer, ehdr_vma + phoff, - phnum * phentsize, phnum * phentsize); - if (nread <= 0) - goto read_error; - - xlatefrom.d_buf = buffer; - } - - union - { - Elf32_Phdr p32[phnum]; - Elf64_Phdr p64[phnum]; - } phdrs; - - xlateto.d_buf = &phdrs; - xlateto.d_size = sizeof phdrs; - - /* Scan for PT_LOAD segments to find the total size of the file image. */ - size_t contents_size = 0; - GElf_Off segments_end = 0; - GElf_Off segments_end_mem = 0; - GElf_Addr loadbase = ehdr_vma; - bool found_base = false; - switch (ehdr.e32.e_ident[EI_CLASS]) - { - /* Sanity checks segments and calculates segment_end, - segments_end, segments_end_mem and loadbase (if not - found_base yet). Returns true if sanity checking failed, - false otherwise. */ - inline bool handle_segment (GElf_Addr vaddr, GElf_Off offset, - GElf_Xword filesz, GElf_Xword memsz) - { - /* Sanity check the segment load aligns with the pagesize. */ - if (((vaddr - offset) & (pagesize - 1)) != 0) - return true; - - GElf_Off segment_end = ((offset + filesz + pagesize - 1) - & -pagesize); - - if (segment_end > (GElf_Off) contents_size) - contents_size = segment_end; - - if (!found_base && (offset & -pagesize) == 0) - { - loadbase = ehdr_vma - (vaddr & -pagesize); - found_base = true; - } - - segments_end = offset + filesz; - segments_end_mem = offset + memsz; - return false; - } - - case ELFCLASS32: - if (elf32_xlatetom (&xlateto, &xlatefrom, - ehdr.e32.e_ident[EI_DATA]) == NULL) - goto libelf_error; - for (uint_fast16_t i = 0; i < phnum; ++i) - if (phdrs.p32[i].p_type == PT_LOAD) - if (handle_segment (phdrs.p32[i].p_vaddr, phdrs.p32[i].p_offset, - phdrs.p32[i].p_filesz, phdrs.p32[i].p_memsz)) - goto bad_elf; - break; - - case ELFCLASS64: - if (elf64_xlatetom (&xlateto, &xlatefrom, - ehdr.e64.e_ident[EI_DATA]) == NULL) - goto libelf_error; - for (uint_fast16_t i = 0; i < phnum; ++i) - if (phdrs.p64[i].p_type == PT_LOAD) - if (handle_segment (phdrs.p64[i].p_vaddr, phdrs.p64[i].p_offset, - phdrs.p64[i].p_filesz, phdrs.p64[i].p_memsz)) - goto bad_elf; - break; - - default: - abort (); - break; - } - - /* Trim the last segment so we don't bother with zeros in the last page - that are off the end of the file. However, if the extra bit in that - page includes the section headers and the memory isn't extended (which - might indicate it will have been reused otherwise), keep them. */ - if ((GElf_Off) contents_size > segments_end - && (GElf_Off) contents_size >= shdrs_end - && segments_end == segments_end_mem) - { - contents_size = segments_end; - if ((GElf_Off) contents_size < shdrs_end) - contents_size = shdrs_end; - } - else - contents_size = segments_end; - - free (buffer); - - /* Now we know the size of the whole image we want read in. */ - buffer = calloc (1, contents_size); - if (buffer == NULL) - goto no_memory; - - switch (ehdr.e32.e_ident[EI_CLASS]) - { - /* Reads the given segment. Returns true if reading fails, - false otherwise. */ - inline bool handle_segment (GElf_Addr vaddr, GElf_Off offset, - GElf_Xword filesz) - { - GElf_Off start = offset & -pagesize; - GElf_Off end = (offset + filesz + pagesize - 1) & -pagesize; - if (end > (GElf_Off) contents_size) - end = contents_size; - nread = (*read_memory) (arg, buffer + start, - (loadbase + vaddr) & -pagesize, - end - start, end - start); - return nread <= 0; - } - - case ELFCLASS32: - for (uint_fast16_t i = 0; i < phnum; ++i) - if (phdrs.p32[i].p_type == PT_LOAD) - if (handle_segment (phdrs.p32[i].p_vaddr, phdrs.p32[i].p_offset, - phdrs.p32[i].p_filesz)) - goto read_error; - - /* If the segments visible in memory didn't include the section - headers, then clear them from the file header. */ - if (contents_size < shdrs_end) - { - ehdr.e32.e_shoff = 0; - ehdr.e32.e_shnum = 0; - ehdr.e32.e_shstrndx = 0; - } - - /* This will normally have been in the first PT_LOAD segment. But it - conceivably could be missing, and we might have just changed it. */ - xlatefrom.d_type = xlateto.d_type = ELF_T_EHDR; - xlatefrom.d_size = xlateto.d_size = sizeof ehdr.e32; - xlatefrom.d_buf = &ehdr.e32; - xlateto.d_buf = buffer; - if (elf32_xlatetof (&xlateto, &xlatefrom, - ehdr.e32.e_ident[EI_DATA]) == NULL) - goto libelf_error; - break; - - case ELFCLASS64: - for (uint_fast16_t i = 0; i < phnum; ++i) - if (phdrs.p64[i].p_type == PT_LOAD) - if (handle_segment (phdrs.p64[i].p_vaddr, phdrs.p64[i].p_offset, - phdrs.p64[i].p_filesz)) - goto read_error; - - /* If the segments visible in memory didn't include the section - headers, then clear them from the file header. */ - if (contents_size < shdrs_end) - { - ehdr.e64.e_shoff = 0; - ehdr.e64.e_shnum = 0; - ehdr.e64.e_shstrndx = 0; - } - - /* This will normally have been in the first PT_LOAD segment. But it - conceivably could be missing, and we might have just changed it. */ - xlatefrom.d_type = xlateto.d_type = ELF_T_EHDR; - xlatefrom.d_size = xlateto.d_size = sizeof ehdr.e64; - xlatefrom.d_buf = &ehdr.e64; - xlateto.d_buf = buffer; - if (elf64_xlatetof (&xlateto, &xlatefrom, - ehdr.e64.e_ident[EI_DATA]) == NULL) - goto libelf_error; - break; - - default: - abort (); - break; - } - - /* Now we have the image. Open libelf on it. */ - - Elf *elf = elf_memory ((char *) buffer, contents_size); - if (elf == NULL) - { - free (buffer); - goto libelf_error; - } - - elf->flags |= ELF_F_MALLOCED; - if (loadbasep != NULL) - *loadbasep = loadbase; - return elf; -} |