125b3c049e70834cf33790a28643ab058b507b35cBen Cheng/* Reconstruct an ELF file by reading the segments out of remote memory.
225b3c049e70834cf33790a28643ab058b507b35cBen Cheng   Copyright (C) 2005-2011 Red Hat, Inc.
325b3c049e70834cf33790a28643ab058b507b35cBen Cheng   This file is part of Red Hat elfutils.
425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
525b3c049e70834cf33790a28643ab058b507b35cBen Cheng   Red Hat elfutils is free software; you can redistribute it and/or modify
625b3c049e70834cf33790a28643ab058b507b35cBen Cheng   it under the terms of the GNU General Public License as published by the
725b3c049e70834cf33790a28643ab058b507b35cBen Cheng   Free Software Foundation; version 2 of the License.
825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
925b3c049e70834cf33790a28643ab058b507b35cBen Cheng   Red Hat elfutils is distributed in the hope that it will be useful, but
1025b3c049e70834cf33790a28643ab058b507b35cBen Cheng   WITHOUT ANY WARRANTY; without even the implied warranty of
1125b3c049e70834cf33790a28643ab058b507b35cBen Cheng   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1225b3c049e70834cf33790a28643ab058b507b35cBen Cheng   General Public License for more details.
1325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
1425b3c049e70834cf33790a28643ab058b507b35cBen Cheng   You should have received a copy of the GNU General Public License along
1525b3c049e70834cf33790a28643ab058b507b35cBen Cheng   with Red Hat elfutils; if not, write to the Free Software Foundation,
1625b3c049e70834cf33790a28643ab058b507b35cBen Cheng   Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
1725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
1825b3c049e70834cf33790a28643ab058b507b35cBen Cheng   In addition, as a special exception, Red Hat, Inc. gives You the
1925b3c049e70834cf33790a28643ab058b507b35cBen Cheng   additional right to link the code of Red Hat elfutils with code licensed
2025b3c049e70834cf33790a28643ab058b507b35cBen Cheng   under any Open Source Initiative certified open source license
2125b3c049e70834cf33790a28643ab058b507b35cBen Cheng   (http://www.opensource.org/licenses/index.php) which requires the
2225b3c049e70834cf33790a28643ab058b507b35cBen Cheng   distribution of source code with any binary distribution and to
2325b3c049e70834cf33790a28643ab058b507b35cBen Cheng   distribute linked combinations of the two.  Non-GPL Code permitted under
2425b3c049e70834cf33790a28643ab058b507b35cBen Cheng   this exception must only link to the code of Red Hat elfutils through
2525b3c049e70834cf33790a28643ab058b507b35cBen Cheng   those well defined interfaces identified in the file named EXCEPTION
2625b3c049e70834cf33790a28643ab058b507b35cBen Cheng   found in the source code files (the "Approved Interfaces").  The files
2725b3c049e70834cf33790a28643ab058b507b35cBen Cheng   of Non-GPL Code may instantiate templates or use macros or inline
2825b3c049e70834cf33790a28643ab058b507b35cBen Cheng   functions from the Approved Interfaces without causing the resulting
2925b3c049e70834cf33790a28643ab058b507b35cBen Cheng   work to be covered by the GNU General Public License.  Only Red Hat,
3025b3c049e70834cf33790a28643ab058b507b35cBen Cheng   Inc. may make changes or additions to the list of Approved Interfaces.
3125b3c049e70834cf33790a28643ab058b507b35cBen Cheng   Red Hat's grant of this exception is conditioned upon your not adding
3225b3c049e70834cf33790a28643ab058b507b35cBen Cheng   any new exceptions.  If you wish to add a new Approved Interface or
3325b3c049e70834cf33790a28643ab058b507b35cBen Cheng   exception, please contact Red Hat.  You must obey the GNU General Public
3425b3c049e70834cf33790a28643ab058b507b35cBen Cheng   License in all respects for all of the Red Hat elfutils code and other
3525b3c049e70834cf33790a28643ab058b507b35cBen Cheng   code used in conjunction with Red Hat elfutils except the Non-GPL Code
3625b3c049e70834cf33790a28643ab058b507b35cBen Cheng   covered by this exception.  If you modify this file, you may extend this
3725b3c049e70834cf33790a28643ab058b507b35cBen Cheng   exception to your version of the file, but you are not obligated to do
3825b3c049e70834cf33790a28643ab058b507b35cBen Cheng   so.  If you do not wish to provide this exception without modification,
3925b3c049e70834cf33790a28643ab058b507b35cBen Cheng   you must delete this exception statement from your version and license
4025b3c049e70834cf33790a28643ab058b507b35cBen Cheng   this file solely under the GPL without exception.
4125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
4225b3c049e70834cf33790a28643ab058b507b35cBen Cheng   Red Hat elfutils is an included package of the Open Invention Network.
4325b3c049e70834cf33790a28643ab058b507b35cBen Cheng   An included package of the Open Invention Network is a package for which
4425b3c049e70834cf33790a28643ab058b507b35cBen Cheng   Open Invention Network licensees cross-license their patents.  No patent
4525b3c049e70834cf33790a28643ab058b507b35cBen Cheng   license is granted, either expressly or impliedly, by designation as an
4625b3c049e70834cf33790a28643ab058b507b35cBen Cheng   included package.  Should you wish to participate in the Open Invention
4725b3c049e70834cf33790a28643ab058b507b35cBen Cheng   Network licensing program, please visit www.openinventionnetwork.com
4825b3c049e70834cf33790a28643ab058b507b35cBen Cheng   <http://www.openinventionnetwork.com>.  */
4925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
5025b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include <config.h>
5125b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include "../libelf/libelfP.h"
5225b3c049e70834cf33790a28643ab058b507b35cBen Cheng#undef _
5325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
5425b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include "libdwflP.h"
5525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
5625b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include <gelf.h>
5725b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include <sys/types.h>
5825b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include <stdbool.h>
5925b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include <stdlib.h>
6025b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include <string.h>
6125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
6225b3c049e70834cf33790a28643ab058b507b35cBen Cheng/* Reconstruct an ELF file by reading the segments out of remote memory
6325b3c049e70834cf33790a28643ab058b507b35cBen Cheng   based on the ELF file header at EHDR_VMA and the ELF program headers it
6425b3c049e70834cf33790a28643ab058b507b35cBen Cheng   points to.  If not null, *LOADBASEP is filled in with the difference
6525b3c049e70834cf33790a28643ab058b507b35cBen Cheng   between the addresses from which the segments were read, and the
6625b3c049e70834cf33790a28643ab058b507b35cBen Cheng   addresses the file headers put them at.
6725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
6825b3c049e70834cf33790a28643ab058b507b35cBen Cheng   The function READ_MEMORY is called to copy at least MINREAD and at most
6925b3c049e70834cf33790a28643ab058b507b35cBen Cheng   MAXREAD bytes from the remote memory at target address ADDRESS into the
7025b3c049e70834cf33790a28643ab058b507b35cBen Cheng   local buffer at DATA; it should return -1 for errors (with code in
7125b3c049e70834cf33790a28643ab058b507b35cBen Cheng   `errno'), 0 if it failed to read at least MINREAD bytes due to EOF, or
7225b3c049e70834cf33790a28643ab058b507b35cBen Cheng   the number of bytes read if >= MINREAD.  ARG is passed through.  */
7325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
7425b3c049e70834cf33790a28643ab058b507b35cBen ChengElf *
7525b3c049e70834cf33790a28643ab058b507b35cBen Chengelf_from_remote_memory (GElf_Addr ehdr_vma,
7625b3c049e70834cf33790a28643ab058b507b35cBen Cheng			GElf_Addr *loadbasep,
7725b3c049e70834cf33790a28643ab058b507b35cBen Cheng			ssize_t (*read_memory) (void *arg, void *data,
7825b3c049e70834cf33790a28643ab058b507b35cBen Cheng						GElf_Addr address,
7925b3c049e70834cf33790a28643ab058b507b35cBen Cheng						size_t minread,
8025b3c049e70834cf33790a28643ab058b507b35cBen Cheng						size_t maxread),
8125b3c049e70834cf33790a28643ab058b507b35cBen Cheng			void *arg)
8225b3c049e70834cf33790a28643ab058b507b35cBen Cheng{
8325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* First read in the file header and check its sanity.  */
8425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
8525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  const size_t initial_bufsize = 256;
8625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  unsigned char *buffer = malloc (initial_bufsize);
8725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (buffer == NULL)
8825b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
8925b3c049e70834cf33790a28643ab058b507b35cBen Cheng    no_memory:
9025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      __libdwfl_seterrno (DWFL_E_NOMEM);
9125b3c049e70834cf33790a28643ab058b507b35cBen Cheng      return NULL;
9225b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
9325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
9425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  ssize_t nread = (*read_memory) (arg, buffer, ehdr_vma,
9525b3c049e70834cf33790a28643ab058b507b35cBen Cheng				  sizeof (Elf32_Ehdr), initial_bufsize);
9625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (nread <= 0)
9725b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
9825b3c049e70834cf33790a28643ab058b507b35cBen Cheng    read_error:
9925b3c049e70834cf33790a28643ab058b507b35cBen Cheng      free (buffer);
10025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      __libdwfl_seterrno (nread < 0 ? DWFL_E_ERRNO : DWFL_E_TRUNCATED);
10125b3c049e70834cf33790a28643ab058b507b35cBen Cheng      return NULL;
10225b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
10325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
10425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (memcmp (buffer, ELFMAG, SELFMAG) != 0)
10525b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
10625b3c049e70834cf33790a28643ab058b507b35cBen Cheng    bad_elf:
10725b3c049e70834cf33790a28643ab058b507b35cBen Cheng      __libdwfl_seterrno (DWFL_E_BADELF);
10825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      return NULL;
10925b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
11025b3c049e70834cf33790a28643ab058b507b35cBen Cheng
11125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* Extract the information we need from the file header.  */
11225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
11325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  union
11425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  {
11525b3c049e70834cf33790a28643ab058b507b35cBen Cheng    Elf32_Ehdr e32;
11625b3c049e70834cf33790a28643ab058b507b35cBen Cheng    Elf64_Ehdr e64;
11725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  } ehdr;
11825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Elf_Data xlatefrom =
11925b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
12025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      .d_type = ELF_T_EHDR,
12125b3c049e70834cf33790a28643ab058b507b35cBen Cheng      .d_buf = buffer,
12225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      .d_version = EV_CURRENT,
12325b3c049e70834cf33790a28643ab058b507b35cBen Cheng    };
12425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Elf_Data xlateto =
12525b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
12625b3c049e70834cf33790a28643ab058b507b35cBen Cheng      .d_type = ELF_T_EHDR,
12725b3c049e70834cf33790a28643ab058b507b35cBen Cheng      .d_buf = &ehdr,
12825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      .d_size = sizeof ehdr,
12925b3c049e70834cf33790a28643ab058b507b35cBen Cheng      .d_version = EV_CURRENT,
13025b3c049e70834cf33790a28643ab058b507b35cBen Cheng    };
13125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
13225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Off phoff;
13325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  uint_fast16_t phnum;
13425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  uint_fast16_t phentsize;
13525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Off shdrs_end;
13625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
13725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  switch (buffer[EI_CLASS])
13825b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
13925b3c049e70834cf33790a28643ab058b507b35cBen Cheng    case ELFCLASS32:
14025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      xlatefrom.d_size = sizeof (Elf32_Ehdr);
14125b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (elf32_xlatetom (&xlateto, &xlatefrom, buffer[EI_DATA]) == NULL)
14225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
14325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	libelf_error:
14425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  __libdwfl_seterrno (DWFL_E_LIBELF);
14525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  return NULL;
14625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
14725b3c049e70834cf33790a28643ab058b507b35cBen Cheng      phoff = ehdr.e32.e_phoff;
14825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      phnum = ehdr.e32.e_phnum;
14925b3c049e70834cf33790a28643ab058b507b35cBen Cheng      phentsize = ehdr.e32.e_phentsize;
15025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (phentsize != sizeof (Elf32_Phdr) || phnum == 0)
15125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	goto bad_elf;
15225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      shdrs_end = ehdr.e32.e_shoff + ehdr.e32.e_shnum * ehdr.e32.e_shentsize;
15325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      break;
15425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
15525b3c049e70834cf33790a28643ab058b507b35cBen Cheng    case ELFCLASS64:
15625b3c049e70834cf33790a28643ab058b507b35cBen Cheng      xlatefrom.d_size = sizeof (Elf64_Ehdr);
15725b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (elf64_xlatetom (&xlateto, &xlatefrom, buffer[EI_DATA]) == NULL)
15825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	goto libelf_error;
15925b3c049e70834cf33790a28643ab058b507b35cBen Cheng      phoff = ehdr.e64.e_phoff;
16025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      phnum = ehdr.e64.e_phnum;
16125b3c049e70834cf33790a28643ab058b507b35cBen Cheng      phentsize = ehdr.e64.e_phentsize;
16225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (phentsize != sizeof (Elf64_Phdr) || phnum == 0)
16325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	goto bad_elf;
16425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      shdrs_end = ehdr.e64.e_shoff + ehdr.e64.e_shnum * ehdr.e64.e_shentsize;
16525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      break;
16625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
16725b3c049e70834cf33790a28643ab058b507b35cBen Cheng    default:
16825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      goto bad_elf;
16925b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
17025b3c049e70834cf33790a28643ab058b507b35cBen Cheng
17125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
17225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* The file header tells where to find the program headers.
17325b3c049e70834cf33790a28643ab058b507b35cBen Cheng     These are what we use to actually choose what to read.  */
17425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
17525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  xlatefrom.d_type = xlateto.d_type = ELF_T_PHDR;
17625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  xlatefrom.d_size = phnum * phentsize;
17725b3c049e70834cf33790a28643ab058b507b35cBen Cheng
17825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if ((size_t) nread >= phoff + phnum * phentsize)
17925b3c049e70834cf33790a28643ab058b507b35cBen Cheng    /* We already have all the phdrs from the initial read.  */
18025b3c049e70834cf33790a28643ab058b507b35cBen Cheng    xlatefrom.d_buf = buffer + phoff;
18125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  else
18225b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
18325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      /* Read in the program headers.  */
18425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
18525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (initial_bufsize < phnum * phentsize)
18625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
18725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  unsigned char *newbuf = realloc (buffer, phnum * phentsize);
18825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (newbuf == NULL)
18925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    {
19025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      free (buffer);
19125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      goto no_memory;
19225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    }
19325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  buffer = newbuf;
19425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
19525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      nread = (*read_memory) (arg, buffer, ehdr_vma + phoff,
19625b3c049e70834cf33790a28643ab058b507b35cBen Cheng			      phnum * phentsize, phnum * phentsize);
19725b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (nread <= 0)
19825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	goto read_error;
19925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
20025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      xlatefrom.d_buf = buffer;
20125b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
20225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
20325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  union
20425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  {
20525b3c049e70834cf33790a28643ab058b507b35cBen Cheng    Elf32_Phdr p32[phnum];
20625b3c049e70834cf33790a28643ab058b507b35cBen Cheng    Elf64_Phdr p64[phnum];
20725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  } phdrs;
20825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
20925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  xlateto.d_buf = &phdrs;
21025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  xlateto.d_size = sizeof phdrs;
21125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
21225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* Scan for PT_LOAD segments to find the total size of the file image.  */
21325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  size_t contents_size = 0;
21425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Off segments_end = 0;
21525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  GElf_Addr loadbase = ehdr_vma;
21625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  bool found_base = false;
21725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  switch (ehdr.e32.e_ident[EI_CLASS])
21825b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
21925b3c049e70834cf33790a28643ab058b507b35cBen Cheng      inline void handle_segment (GElf_Addr vaddr, GElf_Off offset,
22025b3c049e70834cf33790a28643ab058b507b35cBen Cheng				  GElf_Xword filesz, GElf_Xword align)
22125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
22225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  GElf_Off segment_end = ((offset + filesz + align - 1) & -align);
22325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
22425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (segment_end > (GElf_Off) contents_size)
22525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    contents_size = segment_end;
22625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
22725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (!found_base && (offset & -align) == 0)
22825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    {
22925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      loadbase = ehdr_vma - (vaddr & -align);
23025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	      found_base = true;
23125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    }
23225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
23325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  segments_end = offset + filesz;
23425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
23525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
23625b3c049e70834cf33790a28643ab058b507b35cBen Cheng    case ELFCLASS32:
23725b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (elf32_xlatetom (&xlateto, &xlatefrom,
23825b3c049e70834cf33790a28643ab058b507b35cBen Cheng			  ehdr.e32.e_ident[EI_DATA]) == NULL)
23925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	goto libelf_error;
24025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      for (uint_fast16_t i = 0; i < phnum; ++i)
24125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	if (phdrs.p32[i].p_type == PT_LOAD)
24225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  handle_segment (phdrs.p32[i].p_vaddr, phdrs.p32[i].p_offset,
24325b3c049e70834cf33790a28643ab058b507b35cBen Cheng			  phdrs.p32[i].p_filesz, phdrs.p32[i].p_align);
24425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      break;
24525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
24625b3c049e70834cf33790a28643ab058b507b35cBen Cheng    case ELFCLASS64:
24725b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (elf64_xlatetom (&xlateto, &xlatefrom,
24825b3c049e70834cf33790a28643ab058b507b35cBen Cheng			  ehdr.e64.e_ident[EI_DATA]) == NULL)
24925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	goto libelf_error;
25025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      for (uint_fast16_t i = 0; i < phnum; ++i)
25125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	if (phdrs.p64[i].p_type == PT_LOAD)
25225b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  handle_segment (phdrs.p64[i].p_vaddr, phdrs.p64[i].p_offset,
25325b3c049e70834cf33790a28643ab058b507b35cBen Cheng			  phdrs.p64[i].p_filesz, phdrs.p64[i].p_align);
25425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      break;
25525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
25625b3c049e70834cf33790a28643ab058b507b35cBen Cheng    default:
25725b3c049e70834cf33790a28643ab058b507b35cBen Cheng      abort ();
25825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      break;
25925b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
26025b3c049e70834cf33790a28643ab058b507b35cBen Cheng
26125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* Trim the last segment so we don't bother with zeros in the last page
26225b3c049e70834cf33790a28643ab058b507b35cBen Cheng     that are off the end of the file.  However, if the extra bit in that
26325b3c049e70834cf33790a28643ab058b507b35cBen Cheng     page includes the section headers, keep them.  */
26425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if ((GElf_Off) contents_size > segments_end
26525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      && (GElf_Off) contents_size >= shdrs_end)
26625b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
26725b3c049e70834cf33790a28643ab058b507b35cBen Cheng      contents_size = segments_end;
26825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if ((GElf_Off) contents_size < shdrs_end)
26925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	contents_size = shdrs_end;
27025b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
27125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  else
27225b3c049e70834cf33790a28643ab058b507b35cBen Cheng    contents_size = segments_end;
27325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
27425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  free (buffer);
27525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
27625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* Now we know the size of the whole image we want read in.  */
27725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  buffer = calloc (1, contents_size);
27825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (buffer == NULL)
27925b3c049e70834cf33790a28643ab058b507b35cBen Cheng    goto no_memory;
28025b3c049e70834cf33790a28643ab058b507b35cBen Cheng
28125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  switch (ehdr.e32.e_ident[EI_CLASS])
28225b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
28325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      inline bool handle_segment (GElf_Addr vaddr, GElf_Off offset,
28425b3c049e70834cf33790a28643ab058b507b35cBen Cheng				  GElf_Xword filesz, GElf_Xword align)
28525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
28625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  GElf_Off start = offset & -align;
28725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  GElf_Off end = (offset + filesz + align - 1) & -align;
28825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (end > (GElf_Off) contents_size)
28925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    end = contents_size;
29025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  nread = (*read_memory) (arg, buffer + start,
29125b3c049e70834cf33790a28643ab058b507b35cBen Cheng				  (loadbase + vaddr) & -align,
29225b3c049e70834cf33790a28643ab058b507b35cBen Cheng				  end - start, end - start);
29325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  return nread <= 0;
29425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
29525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
29625b3c049e70834cf33790a28643ab058b507b35cBen Cheng    case ELFCLASS32:
29725b3c049e70834cf33790a28643ab058b507b35cBen Cheng      for (uint_fast16_t i = 0; i < phnum; ++i)
29825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	if (phdrs.p32[i].p_type == PT_LOAD)
29925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (handle_segment (phdrs.p32[i].p_vaddr, phdrs.p32[i].p_offset,
30025b3c049e70834cf33790a28643ab058b507b35cBen Cheng			      phdrs.p32[i].p_filesz, phdrs.p32[i].p_align))
30125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    goto read_error;
30225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
30325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      /* If the segments visible in memory didn't include the section
30425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	 headers, then clear them from the file header.  */
30525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (contents_size < shdrs_end)
30625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
30725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  ehdr.e32.e_shoff = 0;
30825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  ehdr.e32.e_shnum = 0;
30925b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  ehdr.e32.e_shstrndx = 0;
31025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
31125b3c049e70834cf33790a28643ab058b507b35cBen Cheng
31225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      /* This will normally have been in the first PT_LOAD segment.  But it
31325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	 conceivably could be missing, and we might have just changed it.  */
31425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      xlatefrom.d_type = xlateto.d_type = ELF_T_EHDR;
31525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      xlatefrom.d_size = xlateto.d_size = sizeof ehdr.e32;
31625b3c049e70834cf33790a28643ab058b507b35cBen Cheng      xlatefrom.d_buf = &ehdr.e32;
31725b3c049e70834cf33790a28643ab058b507b35cBen Cheng      xlateto.d_buf = buffer;
31825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (elf32_xlatetof (&xlateto, &xlatefrom,
31925b3c049e70834cf33790a28643ab058b507b35cBen Cheng			  ehdr.e32.e_ident[EI_DATA]) == NULL)
32025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	goto libelf_error;
32125b3c049e70834cf33790a28643ab058b507b35cBen Cheng      break;
32225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
32325b3c049e70834cf33790a28643ab058b507b35cBen Cheng    case ELFCLASS64:
32425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      for (uint_fast16_t i = 0; i < phnum; ++i)
32525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	if (phdrs.p32[i].p_type == PT_LOAD)
32625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  if (handle_segment (phdrs.p64[i].p_vaddr, phdrs.p64[i].p_offset,
32725b3c049e70834cf33790a28643ab058b507b35cBen Cheng			      phdrs.p64[i].p_filesz, phdrs.p64[i].p_align))
32825b3c049e70834cf33790a28643ab058b507b35cBen Cheng	    goto read_error;
32925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
33025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      /* If the segments visible in memory didn't include the section
33125b3c049e70834cf33790a28643ab058b507b35cBen Cheng	 headers, then clear them from the file header.  */
33225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (contents_size < shdrs_end)
33325b3c049e70834cf33790a28643ab058b507b35cBen Cheng	{
33425b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  ehdr.e64.e_shoff = 0;
33525b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  ehdr.e64.e_shnum = 0;
33625b3c049e70834cf33790a28643ab058b507b35cBen Cheng	  ehdr.e64.e_shstrndx = 0;
33725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	}
33825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
33925b3c049e70834cf33790a28643ab058b507b35cBen Cheng      /* This will normally have been in the first PT_LOAD segment.  But it
34025b3c049e70834cf33790a28643ab058b507b35cBen Cheng	 conceivably could be missing, and we might have just changed it.  */
34125b3c049e70834cf33790a28643ab058b507b35cBen Cheng      xlatefrom.d_type = xlateto.d_type = ELF_T_EHDR;
34225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      xlatefrom.d_size = xlateto.d_size = sizeof ehdr.e64;
34325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      xlatefrom.d_buf = &ehdr.e64;
34425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      xlateto.d_buf = buffer;
34525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      if (elf64_xlatetof (&xlateto, &xlatefrom,
34625b3c049e70834cf33790a28643ab058b507b35cBen Cheng			  ehdr.e64.e_ident[EI_DATA]) == NULL)
34725b3c049e70834cf33790a28643ab058b507b35cBen Cheng	goto libelf_error;
34825b3c049e70834cf33790a28643ab058b507b35cBen Cheng      break;
34925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
35025b3c049e70834cf33790a28643ab058b507b35cBen Cheng    default:
35125b3c049e70834cf33790a28643ab058b507b35cBen Cheng      abort ();
35225b3c049e70834cf33790a28643ab058b507b35cBen Cheng      break;
35325b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
35425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
35525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  /* Now we have the image.  Open libelf on it.  */
35625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
35725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  Elf *elf = elf_memory ((char *) buffer, contents_size);
35825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (elf == NULL)
35925b3c049e70834cf33790a28643ab058b507b35cBen Cheng    {
36025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      free (buffer);
36125b3c049e70834cf33790a28643ab058b507b35cBen Cheng      goto libelf_error;
36225b3c049e70834cf33790a28643ab058b507b35cBen Cheng    }
36325b3c049e70834cf33790a28643ab058b507b35cBen Cheng
36425b3c049e70834cf33790a28643ab058b507b35cBen Cheng  elf->flags |= ELF_F_MALLOCED;
36525b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (loadbasep != NULL)
36625b3c049e70834cf33790a28643ab058b507b35cBen Cheng    *loadbasep = loadbase;
36725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  return elf;
36825b3c049e70834cf33790a28643ab058b507b35cBen Cheng}
369