1cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng/* Reconstruct an ELF file by reading the segments out of remote memory.
2cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   Copyright (C) 2005, 2006, 2007 Red Hat, Inc.
3cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   This file is part of Red Hat elfutils.
4cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
5cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   Red Hat elfutils is free software; you can redistribute it and/or modify
6cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   it under the terms of the GNU General Public License as published by the
7cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   Free Software Foundation; version 2 of the License.
8cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
9cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   Red Hat elfutils is distributed in the hope that it will be useful, but
10cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   WITHOUT ANY WARRANTY; without even the implied warranty of
11cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   General Public License for more details.
13cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
14cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   You should have received a copy of the GNU General Public License along
15cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   with Red Hat elfutils; if not, write to the Free Software Foundation,
16cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
17cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
18cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   In addition, as a special exception, Red Hat, Inc. gives You the
19cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   additional right to link the code of Red Hat elfutils with code licensed
20cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   under any Open Source Initiative certified open source license
21cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   (http://www.opensource.org/licenses/index.php) which requires the
22cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   distribution of source code with any binary distribution and to
23cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   distribute linked combinations of the two.  Non-GPL Code permitted under
24cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   this exception must only link to the code of Red Hat elfutils through
25cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   those well defined interfaces identified in the file named EXCEPTION
26cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   found in the source code files (the "Approved Interfaces").  The files
27cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   of Non-GPL Code may instantiate templates or use macros or inline
28cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   functions from the Approved Interfaces without causing the resulting
29cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   work to be covered by the GNU General Public License.  Only Red Hat,
30cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   Inc. may make changes or additions to the list of Approved Interfaces.
31cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   Red Hat's grant of this exception is conditioned upon your not adding
32cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   any new exceptions.  If you wish to add a new Approved Interface or
33cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   exception, please contact Red Hat.  You must obey the GNU General Public
34cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   License in all respects for all of the Red Hat elfutils code and other
35cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   code used in conjunction with Red Hat elfutils except the Non-GPL Code
36cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   covered by this exception.  If you modify this file, you may extend this
37cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   exception to your version of the file, but you are not obligated to do
38cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   so.  If you do not wish to provide this exception without modification,
39cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   you must delete this exception statement from your version and license
40cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   this file solely under the GPL without exception.
41cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
42cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   Red Hat elfutils is an included package of the Open Invention Network.
43cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   An included package of the Open Invention Network is a package for which
44cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   Open Invention Network licensees cross-license their patents.  No patent
45cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   license is granted, either expressly or impliedly, by designation as an
46cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   included package.  Should you wish to participate in the Open Invention
47cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   Network licensing program, please visit www.openinventionnetwork.com
48cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   <http://www.openinventionnetwork.com>.  */
49cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
50cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#include <config.h>
51cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#include "../libelf/libelfP.h"
52cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#undef _
53cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
54cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#include "libdwflP.h"
55cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
56cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#include <gelf.h>
57cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#include <sys/types.h>
58cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#include <stdbool.h>
59cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#include <stdlib.h>
60cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#include <string.h>
61cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
62cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng/* Reconstruct an ELF file by reading the segments out of remote memory
63cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   based on the ELF file header at EHDR_VMA and the ELF program headers it
64cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   points to.  If not null, *LOADBASEP is filled in with the difference
65cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   between the addresses from which the segments were read, and the
66cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   addresses the file headers put them at.
67cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
68cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   The function READ_MEMORY is called to copy at least MINREAD and at most
69cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   MAXREAD bytes from the remote memory at target address ADDRESS into the
70cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   local buffer at DATA; it should return -1 for errors (with code in
71cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   `errno'), 0 if it failed to read at least MINREAD bytes due to EOF, or
72cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   the number of bytes read if >= MINREAD.  ARG is passed through.  */
73cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
74cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben ChengElf *
75cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengelf_from_remote_memory (GElf_Addr ehdr_vma,
76cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			GElf_Addr *loadbasep,
77cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			ssize_t (*read_memory) (void *arg, void *data,
78cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng						GElf_Addr address,
79cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng						size_t minread,
80cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng						size_t maxread),
81cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			void *arg)
82cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng{
83cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  /* First read in the file header and check its sanity.  */
84cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
85cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  const size_t initial_bufsize = 256;
86cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  unsigned char *buffer = malloc (initial_bufsize);
87cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (buffer == NULL)
88cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
89cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    no_memory:
90cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      __libdwfl_seterrno (DWFL_E_NOMEM);
91cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      return NULL;
92cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
93cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
94cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  ssize_t nread = (*read_memory) (arg, buffer, ehdr_vma,
95cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				  sizeof (Elf32_Ehdr), initial_bufsize);
96cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (nread <= 0)
97cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
98cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    read_error:
99cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      free (buffer);
100cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      __libdwfl_seterrno (nread < 0 ? DWFL_E_ERRNO : DWFL_E_TRUNCATED);
101cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      return NULL;
102cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
103cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
104cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (memcmp (buffer, ELFMAG, SELFMAG) != 0)
105cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
106cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    bad_elf:
107cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      __libdwfl_seterrno (DWFL_E_BADELF);
108cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      return NULL;
109cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
110cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
111cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  /* Extract the information we need from the file header.  */
112cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
113cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  union
114cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  {
115cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    Elf32_Ehdr e32;
116cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    Elf64_Ehdr e64;
117cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  } ehdr;
118cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Elf_Data xlatefrom =
119cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
120cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      .d_type = ELF_T_EHDR,
121cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      .d_buf = buffer,
122cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      .d_version = EV_CURRENT,
123cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    };
124cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Elf_Data xlateto =
125cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
126cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      .d_type = ELF_T_EHDR,
127cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      .d_buf = &ehdr,
128cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      .d_size = sizeof ehdr,
129cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      .d_version = EV_CURRENT,
130cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    };
131cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
132cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  GElf_Off phoff;
133cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  uint_fast16_t phnum;
134cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  uint_fast16_t phentsize;
135cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  GElf_Off shdrs_end;
136cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
137cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  switch (buffer[EI_CLASS])
138cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
139cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    case ELFCLASS32:
140cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      xlatefrom.d_size = sizeof (Elf32_Ehdr);
141cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (elf32_xlatetom (&xlateto, &xlatefrom, buffer[EI_DATA]) == NULL)
142cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
143cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	libelf_error:
144cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  __libdwfl_seterrno (DWFL_E_LIBELF);
145cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  return NULL;
146cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}
147cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      phoff = ehdr.e32.e_phoff;
148cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      phnum = ehdr.e32.e_phnum;
149cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      phentsize = ehdr.e32.e_phentsize;
150cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (phentsize != sizeof (Elf32_Phdr) || phnum == 0)
151cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	goto bad_elf;
152cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      shdrs_end = ehdr.e32.e_shoff + ehdr.e32.e_shnum * ehdr.e32.e_shentsize;
153cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      break;
154cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
155cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    case ELFCLASS64:
156cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      xlatefrom.d_size = sizeof (Elf64_Ehdr);
157cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (elf64_xlatetom (&xlateto, &xlatefrom, buffer[EI_DATA]) == NULL)
158cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	goto libelf_error;
159cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      phoff = ehdr.e64.e_phoff;
160cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      phnum = ehdr.e64.e_phnum;
161cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      phentsize = ehdr.e64.e_phentsize;
162cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (phentsize != sizeof (Elf64_Phdr) || phnum == 0)
163cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	goto bad_elf;
164cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      shdrs_end = ehdr.e64.e_shoff + ehdr.e64.e_shnum * ehdr.e64.e_shentsize;
165cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      break;
166cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
167cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    default:
168cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      goto bad_elf;
169cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
170cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
171cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
172cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  /* The file header tells where to find the program headers.
173cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng     These are what we use to actually choose what to read.  */
174cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
175cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  xlatefrom.d_type = xlateto.d_type = ELF_T_PHDR;
176cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  xlatefrom.d_size = phnum * phentsize;
177cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
178cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if ((size_t) nread >= phoff + phnum * phentsize)
179cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    /* We already have all the phdrs from the initial read.  */
180cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    xlatefrom.d_buf = buffer + phoff;
181cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  else
182cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
183cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      /* Read in the program headers.  */
184cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
185cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (initial_bufsize < phnum * phentsize)
186cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
187cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  unsigned char *newbuf = realloc (buffer, phnum * phentsize);
188cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if (newbuf == NULL)
189cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    {
190cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      free (buffer);
191cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      goto no_memory;
192cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    }
193cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  buffer = newbuf;
194cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}
195cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      nread = (*read_memory) (arg, buffer, ehdr_vma + phoff,
196cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			      phnum * phentsize, phnum * phentsize);
197cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (nread <= 0)
198cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	goto read_error;
199cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
200cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      xlatefrom.d_buf = buffer;
201cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
202cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
203cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  union
204cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  {
205cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    Elf32_Phdr p32[phnum];
206cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    Elf64_Phdr p64[phnum];
207cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  } phdrs;
208cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
209cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  xlateto.d_buf = &phdrs;
210cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  xlateto.d_size = sizeof phdrs;
211cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
212cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  /* Scan for PT_LOAD segments to find the total size of the file image.  */
213cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  size_t contents_size = 0;
214cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  GElf_Off segments_end = 0;
215cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  GElf_Addr loadbase = ehdr_vma;
216cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  bool found_base = false;
217cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  switch (ehdr.e32.e_ident[EI_CLASS])
218cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
219cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      inline void handle_segment (GElf_Addr vaddr, GElf_Off offset,
220cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				  GElf_Xword filesz, GElf_Xword align)
221cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
222cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  GElf_Off segment_end = ((offset + filesz + align - 1) & -align);
223cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
224cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if (segment_end > (GElf_Off) contents_size)
225cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    contents_size = segment_end;
226cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
227cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if (!found_base && (offset & -align) == 0)
228cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    {
229cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      loadbase = ehdr_vma - (vaddr & -align);
230cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      found_base = true;
231cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    }
232cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
233cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  segments_end = offset + filesz;
234cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}
235cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
236cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    case ELFCLASS32:
237cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (elf32_xlatetom (&xlateto, &xlatefrom,
238cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			  ehdr.e32.e_ident[EI_DATA]) == NULL)
239cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	goto libelf_error;
240cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      for (uint_fast16_t i = 0; i < phnum; ++i)
241cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	if (phdrs.p32[i].p_type == PT_LOAD)
242cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  handle_segment (phdrs.p32[i].p_vaddr, phdrs.p32[i].p_offset,
243cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			  phdrs.p32[i].p_filesz, phdrs.p32[i].p_align);
244cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      break;
245cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
246cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    case ELFCLASS64:
247cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (elf32_xlatetom (&xlateto, &xlatefrom,
248cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			  ehdr.e32.e_ident[EI_DATA]) == NULL)
249cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	goto libelf_error;
250cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      for (uint_fast16_t i = 0; i < phnum; ++i)
251cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	if (phdrs.p32[i].p_type == PT_LOAD)
252cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  handle_segment (phdrs.p64[i].p_vaddr, phdrs.p64[i].p_offset,
253cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			  phdrs.p64[i].p_filesz, phdrs.p64[i].p_align);
254cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      break;
255cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
256cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    default:
257cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      abort ();
258cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      break;
259cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
260cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
261cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  /* Trim the last segment so we don't bother with zeros in the last page
262cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng     that are off the end of the file.  However, if the extra bit in that
263cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng     page includes the section headers, keep them.  */
264cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if ((GElf_Off) contents_size > segments_end
265cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      && (GElf_Off) contents_size >= shdrs_end)
266cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
267cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      contents_size = segments_end;
268cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if ((GElf_Off) contents_size < shdrs_end)
269cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	contents_size = shdrs_end;
270cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
271cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  else
272cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    contents_size = segments_end;
273cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
274cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  free (buffer);
275cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
276cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  /* Now we know the size of the whole image we want read in.  */
277cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  buffer = calloc (1, contents_size);
278cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (buffer == NULL)
279cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    goto no_memory;
280cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
281cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  switch (ehdr.e32.e_ident[EI_CLASS])
282cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
283cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      inline bool handle_segment (GElf_Addr vaddr, GElf_Off offset,
284cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				  GElf_Xword filesz, GElf_Xword align)
285cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
286cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  GElf_Off start = offset & -align;
287cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  GElf_Off end = (offset + filesz + align - 1) & -align;
288cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if (end > (GElf_Off) contents_size)
289cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    end = contents_size;
290cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  nread = (*read_memory) (arg, buffer + start,
291cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				  (loadbase + vaddr) & -align,
292cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				  end - start, end - start);
293cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  return nread <= 0;
294cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}
295cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
296cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    case ELFCLASS32:
297cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      for (uint_fast16_t i = 0; i < phnum; ++i)
298cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	if (phdrs.p32[i].p_type == PT_LOAD)
299cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if (handle_segment (phdrs.p32[i].p_vaddr, phdrs.p32[i].p_offset,
300cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			      phdrs.p32[i].p_filesz, phdrs.p32[i].p_align))
301cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    goto read_error;
302cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
303cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      /* If the segments visible in memory didn't include the section
304cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	 headers, then clear them from the file header.  */
305cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (contents_size < shdrs_end)
306cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
307cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  ehdr.e32.e_shoff = 0;
308cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  ehdr.e32.e_shnum = 0;
309cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  ehdr.e32.e_shstrndx = 0;
310cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}
311cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
312cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      /* This will normally have been in the first PT_LOAD segment.  But it
313cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	 conceivably could be missing, and we might have just changed it.  */
314cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      xlatefrom.d_type = xlateto.d_type = ELF_T_EHDR;
315cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      xlatefrom.d_size = xlateto.d_size = sizeof ehdr.e32;
316cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      xlatefrom.d_buf = &ehdr.e32;
317cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      xlateto.d_buf = buffer;
318cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (elf32_xlatetof (&xlateto, &xlatefrom,
319cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			  ehdr.e32.e_ident[EI_DATA]) == NULL)
320cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	goto libelf_error;
321cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      break;
322cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
323cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    case ELFCLASS64:
324cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      for (uint_fast16_t i = 0; i < phnum; ++i)
325cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	if (phdrs.p32[i].p_type == PT_LOAD)
326cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if (handle_segment (phdrs.p64[i].p_vaddr, phdrs.p64[i].p_offset,
327cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			      phdrs.p64[i].p_filesz, phdrs.p64[i].p_align))
328cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    goto read_error;
329cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
330cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      /* If the segments visible in memory didn't include the section
331cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	 headers, then clear them from the file header.  */
332cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (contents_size < shdrs_end)
333cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
334cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  ehdr.e64.e_shoff = 0;
335cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  ehdr.e64.e_shnum = 0;
336cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  ehdr.e64.e_shstrndx = 0;
337cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}
338cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
339cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      /* This will normally have been in the first PT_LOAD segment.  But it
340cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	 conceivably could be missing, and we might have just changed it.  */
341cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      xlatefrom.d_type = xlateto.d_type = ELF_T_EHDR;
342cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      xlatefrom.d_size = xlateto.d_size = sizeof ehdr.e64;
343cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      xlatefrom.d_buf = &ehdr.e64;
344cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      xlateto.d_buf = buffer;
345cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (elf64_xlatetof (&xlateto, &xlatefrom,
346cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			  ehdr.e64.e_ident[EI_DATA]) == NULL)
347cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	goto libelf_error;
348cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      break;
349cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
350cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    default:
351cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      abort ();
352cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      break;
353cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
354cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
355cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  /* Now we have the image.  Open libelf on it.  */
356cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
357cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Elf *elf = elf_memory ((char *) buffer, contents_size);
358cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (elf == NULL)
359cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
360cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      free (buffer);
361cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      goto libelf_error;
362cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
363cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
364cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  elf->flags |= ELF_F_MALLOCED;
365cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (loadbasep != NULL)
366cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    *loadbasep = loadbase;
367cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  return elf;
368cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng}
369