elf-from-memory.c revision d8dcc9c17a866f18b342b3b0594c15d007b8b73b
1/* Reconstruct an ELF file by reading the segments out of remote memory.
2   Copyright (C) 2005, 2006 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 (elf32_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  switch (ehdr.e32.e_ident[EI_CLASS])
217    {
218      inline void handle_segment (GElf_Addr vaddr, GElf_Off offset,
219				  GElf_Xword filesz, GElf_Xword align)
220	{
221	  GElf_Off segment_end = ((offset + filesz + align - 1) & -align);
222
223	  if (segment_end > (GElf_Off) contents_size)
224	    contents_size = segment_end;
225
226	  if ((offset & -align) == 0 && loadbase == ehdr_vma)
227	    loadbase = ehdr_vma - (vaddr & -align);
228
229	  segments_end = offset + filesz;
230	}
231
232    case ELFCLASS32:
233      if (elf32_xlatetom (&xlateto, &xlatefrom,
234			  ehdr.e32.e_ident[EI_DATA]) == NULL)
235	goto libelf_error;
236      for (uint_fast16_t i = 0; i < phnum; ++i)
237	if (phdrs.p32[i].p_type == PT_LOAD)
238	  handle_segment (phdrs.p32[i].p_vaddr, phdrs.p32[i].p_offset,
239			  phdrs.p32[i].p_filesz, phdrs.p32[i].p_align);
240      break;
241
242    case ELFCLASS64:
243      if (elf32_xlatetom (&xlateto, &xlatefrom,
244			  ehdr.e32.e_ident[EI_DATA]) == NULL)
245	goto libelf_error;
246      for (uint_fast16_t i = 0; i < phnum; ++i)
247	if (phdrs.p32[i].p_type == PT_LOAD)
248	  handle_segment (phdrs.p64[i].p_vaddr, phdrs.p64[i].p_offset,
249			  phdrs.p64[i].p_filesz, phdrs.p64[i].p_align);
250      break;
251
252    default:
253      abort ();
254      break;
255    }
256
257  /* Trim the last segment so we don't bother with zeros in the last page
258     that are off the end of the file.  However, if the extra bit in that
259     page includes the section headers, keep them.  */
260  if ((GElf_Off) contents_size > segments_end
261      && (GElf_Off) contents_size >= shdrs_end)
262    {
263      contents_size = segments_end;
264      if ((GElf_Off) contents_size < shdrs_end)
265	contents_size = shdrs_end;
266    }
267  else
268    contents_size = segments_end;
269
270  free (buffer);
271
272  /* Now we know the size of the whole image we want read in.  */
273  buffer = calloc (1, contents_size);
274  if (buffer == NULL)
275    goto no_memory;
276
277  switch (ehdr.e32.e_ident[EI_CLASS])
278    {
279      inline bool handle_segment (GElf_Addr vaddr, GElf_Off offset,
280				  GElf_Xword filesz, GElf_Xword align)
281	{
282	  GElf_Off start = offset & -align;
283	  GElf_Off end = (offset + filesz + align - 1) & -align;
284	  if (end > (GElf_Off) contents_size)
285	    end = contents_size;
286	  nread = (*read_memory) (arg, buffer + start,
287				  (loadbase + vaddr) & -align,
288				  end - start, end - start);
289	  return nread <= 0;
290	}
291
292    case ELFCLASS32:
293      for (uint_fast16_t i = 0; i < phnum; ++i)
294	if (phdrs.p32[i].p_type == PT_LOAD)
295	  if (handle_segment (phdrs.p32[i].p_vaddr, phdrs.p32[i].p_offset,
296			      phdrs.p32[i].p_filesz, phdrs.p32[i].p_align))
297	    goto read_error;
298
299      /* If the segments visible in memory didn't include the section
300	 headers, then clear them from the file header.  */
301      if (contents_size < shdrs_end)
302	{
303	  ehdr.e32.e_shoff = 0;
304	  ehdr.e32.e_shnum = 0;
305	  ehdr.e32.e_shstrndx = 0;
306	}
307
308      /* This will normally have been in the first PT_LOAD segment.  But it
309	 conceivably could be missing, and we might have just changed it.  */
310      xlatefrom.d_type = xlateto.d_type = ELF_T_EHDR;
311      xlatefrom.d_size = xlateto.d_size = sizeof ehdr.e32;
312      xlatefrom.d_buf = &ehdr.e32;
313      xlateto.d_buf = buffer;
314      if (elf32_xlatetof (&xlateto, &xlatefrom,
315			  ehdr.e32.e_ident[EI_DATA]) == NULL)
316	goto libelf_error;
317      break;
318
319    case ELFCLASS64:
320      for (uint_fast16_t i = 0; i < phnum; ++i)
321	if (phdrs.p32[i].p_type == PT_LOAD)
322	  if (handle_segment (phdrs.p64[i].p_vaddr, phdrs.p64[i].p_offset,
323			      phdrs.p64[i].p_filesz, phdrs.p64[i].p_align))
324	    goto read_error;
325
326      /* If the segments visible in memory didn't include the section
327	 headers, then clear them from the file header.  */
328      if (contents_size < shdrs_end)
329	{
330	  ehdr.e64.e_shoff = 0;
331	  ehdr.e64.e_shnum = 0;
332	  ehdr.e64.e_shstrndx = 0;
333	}
334
335      /* This will normally have been in the first PT_LOAD segment.  But it
336	 conceivably could be missing, and we might have just changed it.  */
337      xlatefrom.d_type = xlateto.d_type = ELF_T_EHDR;
338      xlatefrom.d_size = xlateto.d_size = sizeof ehdr.e64;
339      xlatefrom.d_buf = &ehdr.e64;
340      xlateto.d_buf = buffer;
341      if (elf64_xlatetof (&xlateto, &xlatefrom,
342			  ehdr.e64.e_ident[EI_DATA]) == NULL)
343	goto libelf_error;
344      break;
345
346    default:
347      abort ();
348      break;
349    }
350
351  /* Now we have the image.  Open libelf on it.  */
352
353  Elf *elf = elf_memory ((char *) buffer, contents_size);
354  if (elf == NULL)
355    {
356      free (buffer);
357      goto libelf_error;
358    }
359
360  elf->flags |= ELF_F_MALLOCED;
361  if (loadbasep != NULL)
362    *loadbasep = loadbase;
363  return elf;
364}
365