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