0fb5f8a375d77e84b37d76938058b8762bfc9351
[platform/upstream/elfutils.git] / libdwfl / elf-from-memory.c
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
74 Elf *
75 elf_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 }