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.
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.
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.
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.
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.
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>. */
51 #include "../libelf/libelfP.h"
57 #include <sys/types.h>
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.
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. */
75 elf_from_remote_memory (GElf_Addr ehdr_vma,
77 ssize_t (*read_memory) (void *arg, void *data,
83 /* First read in the file header and check its sanity. */
85 const size_t initial_bufsize = 256;
86 unsigned char *buffer = malloc (initial_bufsize);
90 __libdwfl_seterrno (DWFL_E_NOMEM);
94 ssize_t nread = (*read_memory) (arg, buffer, ehdr_vma,
95 sizeof (Elf32_Ehdr), initial_bufsize);
100 __libdwfl_seterrno (nread < 0 ? DWFL_E_ERRNO : DWFL_E_TRUNCATED);
104 if (memcmp (buffer, ELFMAG, SELFMAG) != 0)
107 __libdwfl_seterrno (DWFL_E_BADELF);
111 /* Extract the information we need from the file header. */
120 .d_type = ELF_T_EHDR,
122 .d_version = EV_CURRENT,
126 .d_type = ELF_T_EHDR,
128 .d_size = sizeof ehdr,
129 .d_version = EV_CURRENT,
134 uint_fast16_t phentsize;
137 switch (buffer[EI_CLASS])
140 xlatefrom.d_size = sizeof (Elf32_Ehdr);
141 if (elf32_xlatetom (&xlateto, &xlatefrom, buffer[EI_DATA]) == NULL)
144 __libdwfl_seterrno (DWFL_E_LIBELF);
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)
152 shdrs_end = ehdr.e32.e_shoff + ehdr.e32.e_shnum * ehdr.e32.e_shentsize;
156 xlatefrom.d_size = sizeof (Elf64_Ehdr);
157 if (elf64_xlatetom (&xlateto, &xlatefrom, buffer[EI_DATA]) == NULL)
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)
164 shdrs_end = ehdr.e64.e_shoff + ehdr.e64.e_shnum * ehdr.e64.e_shentsize;
172 /* The file header tells where to find the program headers.
173 These are what we use to actually choose what to read. */
175 xlatefrom.d_type = xlateto.d_type = ELF_T_PHDR;
176 xlatefrom.d_size = phnum * phentsize;
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;
183 /* Read in the program headers. */
185 if (initial_bufsize < phnum * phentsize)
187 unsigned char *newbuf = realloc (buffer, phnum * phentsize);
195 nread = (*read_memory) (arg, buffer, ehdr_vma + phoff,
196 phnum * phentsize, phnum * phentsize);
200 xlatefrom.d_buf = buffer;
205 Elf32_Phdr p32[phnum];
206 Elf64_Phdr p64[phnum];
209 xlateto.d_buf = &phdrs;
210 xlateto.d_size = sizeof phdrs;
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])
219 inline void handle_segment (GElf_Addr vaddr, GElf_Off offset,
220 GElf_Xword filesz, GElf_Xword align)
222 GElf_Off segment_end = ((offset + filesz + align - 1) & -align);
224 if (segment_end > (GElf_Off) contents_size)
225 contents_size = segment_end;
227 if (!found_base && (offset & -align) == 0)
229 loadbase = ehdr_vma - (vaddr & -align);
233 segments_end = offset + filesz;
237 if (elf32_xlatetom (&xlateto, &xlatefrom,
238 ehdr.e32.e_ident[EI_DATA]) == NULL)
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);
247 if (elf64_xlatetom (&xlateto, &xlatefrom,
248 ehdr.e64.e_ident[EI_DATA]) == NULL)
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);
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)
267 contents_size = segments_end;
268 if ((GElf_Off) contents_size < shdrs_end)
269 contents_size = shdrs_end;
272 contents_size = segments_end;
276 /* Now we know the size of the whole image we want read in. */
277 buffer = calloc (1, contents_size);
281 switch (ehdr.e32.e_ident[EI_CLASS])
283 inline bool handle_segment (GElf_Addr vaddr, GElf_Off offset,
284 GElf_Xword filesz, GElf_Xword align)
286 GElf_Off start = offset & -align;
287 GElf_Off end = (offset + filesz + align - 1) & -align;
288 if (end > (GElf_Off) contents_size)
290 nread = (*read_memory) (arg, buffer + start,
291 (loadbase + vaddr) & -align,
292 end - start, end - start);
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))
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)
307 ehdr.e32.e_shoff = 0;
308 ehdr.e32.e_shnum = 0;
309 ehdr.e32.e_shstrndx = 0;
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)
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))
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)
334 ehdr.e64.e_shoff = 0;
335 ehdr.e64.e_shnum = 0;
336 ehdr.e64.e_shstrndx = 0;
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)
355 /* Now we have the image. Open libelf on it. */
357 Elf *elf = elf_memory ((char *) buffer, contents_size);
364 elf->flags |= ELF_F_MALLOCED;
365 if (loadbasep != NULL)
366 *loadbasep = loadbase;