blob: e3436ff43c396f603a3b4cc44e2a38f51189444c [file] [log] [blame]
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001/* Reconstruct an ELF file by reading the segments out of remote memory.
2 Copyright (C) 2005 Red Hat, Inc.
Ulrich Drepper361df7d2006-04-04 21:38:57 +00003 This file is part of Red Hat elfutils.
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00004
Ulrich Drepper361df7d2006-04-04 21:38:57 +00005 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.
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00008
Ulrich Drepper361df7d2006-04-04 21:38:57 +00009 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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>. */
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000049
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 (elf32_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 return NULL;
358 }
359
360 elf->flags |= ELF_F_MALLOCED;
361 if (loadbasep != NULL)
362 *loadbasep = loadbase;
363 return elf;
364}