1b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper/* Reconstruct an ELF file by reading the segments out of remote memory.
29202fe132caea838cc7e2c7864e0ee702e62f155Mark Wielaard   Copyright (C) 2005-2011, 2014, 2015 Red Hat, Inc.
3de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard   This file is part of elfutils.
4b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper
5de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard   This file is free software; you can redistribute it and/or modify
6de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard   it under the terms of either
7b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper
8de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard     * the GNU Lesser General Public License as published by the Free
9de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard       Software Foundation; either version 3 of the License, or (at
10de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard       your option) any later version
11de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard
12de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard   or
13de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard
14de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard     * the GNU General Public License as published by the Free
15de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard       Software Foundation; either version 2 of the License, or (at
16de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard       your option) any later version
17de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard
18de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard   or both in parallel, as here.
19de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard
20de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard   elfutils is distributed in the hope that it will be useful, but
21361df7da6dfecd817b27e62b91752ac316d7cdd4Ulrich Drepper   WITHOUT ANY WARRANTY; without even the implied warranty of
22361df7da6dfecd817b27e62b91752ac316d7cdd4Ulrich Drepper   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
23361df7da6dfecd817b27e62b91752ac316d7cdd4Ulrich Drepper   General Public License for more details.
24361df7da6dfecd817b27e62b91752ac316d7cdd4Ulrich Drepper
25de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard   You should have received copies of the GNU General Public License and
26de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard   the GNU Lesser General Public License along with this program.  If
27de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard   not, see <http://www.gnu.org/licenses/>.  */
28b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper
29b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper#include <config.h>
30b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper#include "../libelf/libelfP.h"
31b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper#undef _
32b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper
33b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper#include "libdwflP.h"
34b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper
35b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper#include <gelf.h>
36b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper#include <sys/types.h>
37b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper#include <stdbool.h>
38b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper#include <stdlib.h>
39b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper#include <string.h>
40b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper
41b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper/* Reconstruct an ELF file by reading the segments out of remote memory
42b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper   based on the ELF file header at EHDR_VMA and the ELF program headers it
43b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper   points to.  If not null, *LOADBASEP is filled in with the difference
44b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper   between the addresses from which the segments were read, and the
45b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper   addresses the file headers put them at.
46b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper
47b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper   The function READ_MEMORY is called to copy at least MINREAD and at most
48b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper   MAXREAD bytes from the remote memory at target address ADDRESS into the
49b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper   local buffer at DATA; it should return -1 for errors (with code in
50b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper   `errno'), 0 if it failed to read at least MINREAD bytes due to EOF, or
51f15bcda4137446d4773bb54cb99cc18497e9822cMark Wielaard   the number of bytes read if >= MINREAD.  ARG is passed through.
52f15bcda4137446d4773bb54cb99cc18497e9822cMark Wielaard
53f15bcda4137446d4773bb54cb99cc18497e9822cMark Wielaard   PAGESIZE is the minimum page size and alignment used for the PT_LOAD
54f15bcda4137446d4773bb54cb99cc18497e9822cMark Wielaard   segments.  */
55b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper
56b08d5a8fb42f4586d756068065186b5af7e48daUlrich DrepperElf *
57b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepperelf_from_remote_memory (GElf_Addr ehdr_vma,
58f15bcda4137446d4773bb54cb99cc18497e9822cMark Wielaard			GElf_Xword pagesize,
59b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper			GElf_Addr *loadbasep,
60b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper			ssize_t (*read_memory) (void *arg, void *data,
61b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper						GElf_Addr address,
62b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper						size_t minread,
63b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper						size_t maxread),
64b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper			void *arg)
65b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper{
669202fe132caea838cc7e2c7864e0ee702e62f155Mark Wielaard  /* We might have to reserve some memory for the phdrs.  Set to NULL
679202fe132caea838cc7e2c7864e0ee702e62f155Mark Wielaard     here so we can always safely free it.  */
689202fe132caea838cc7e2c7864e0ee702e62f155Mark Wielaard  void *phdrsp = NULL;
699202fe132caea838cc7e2c7864e0ee702e62f155Mark Wielaard
70b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper  /* First read in the file header and check its sanity.  */
71b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper
72b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper  const size_t initial_bufsize = 256;
73b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper  unsigned char *buffer = malloc (initial_bufsize);
749202fe132caea838cc7e2c7864e0ee702e62f155Mark Wielaard  if (unlikely (buffer == NULL))
75b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper    {
76b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper    no_memory:
77b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper      __libdwfl_seterrno (DWFL_E_NOMEM);
78b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper      return NULL;
79b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper    }
80b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper
81b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper  ssize_t nread = (*read_memory) (arg, buffer, ehdr_vma,
82b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper				  sizeof (Elf32_Ehdr), initial_bufsize);
83b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper  if (nread <= 0)
84b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper    {
85b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper    read_error:
86b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper      free (buffer);
879202fe132caea838cc7e2c7864e0ee702e62f155Mark Wielaard      free (phdrsp);
88b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper      __libdwfl_seterrno (nread < 0 ? DWFL_E_ERRNO : DWFL_E_TRUNCATED);
89b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper      return NULL;
90b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper    }
91b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper
92b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper  if (memcmp (buffer, ELFMAG, SELFMAG) != 0)
93b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper    {
94b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper    bad_elf:
95f15bcda4137446d4773bb54cb99cc18497e9822cMark Wielaard      free (buffer);
969202fe132caea838cc7e2c7864e0ee702e62f155Mark Wielaard      free (phdrsp);
97b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper      __libdwfl_seterrno (DWFL_E_BADELF);
98b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper      return NULL;
99b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper    }
100b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper
101b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper  /* Extract the information we need from the file header.  */
102b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper
103b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper  union
104b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper  {
105b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper    Elf32_Ehdr e32;
106b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper    Elf64_Ehdr e64;
107b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper  } ehdr;
108b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper  Elf_Data xlatefrom =
109b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper    {
110b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper      .d_type = ELF_T_EHDR,
111b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper      .d_buf = buffer,
112b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper      .d_version = EV_CURRENT,
113b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper    };
114b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper  Elf_Data xlateto =
115b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper    {
116b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper      .d_type = ELF_T_EHDR,
117b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper      .d_buf = &ehdr,
118b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper      .d_size = sizeof ehdr,
119b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper      .d_version = EV_CURRENT,
120b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper    };
121b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper
122b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper  GElf_Off phoff;
123b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper  uint_fast16_t phnum;
124b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper  uint_fast16_t phentsize;
125b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper  GElf_Off shdrs_end;
126b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper
127b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper  switch (buffer[EI_CLASS])
128b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper    {
129b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper    case ELFCLASS32:
130b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper      xlatefrom.d_size = sizeof (Elf32_Ehdr);
131b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper      if (elf32_xlatetom (&xlateto, &xlatefrom, buffer[EI_DATA]) == NULL)
132b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper	{
133b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper	libelf_error:
134b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper	  __libdwfl_seterrno (DWFL_E_LIBELF);
135b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper	  return NULL;
136b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper	}
137b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper      phoff = ehdr.e32.e_phoff;
138b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper      phnum = ehdr.e32.e_phnum;
139b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper      phentsize = ehdr.e32.e_phentsize;
140b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper      if (phentsize != sizeof (Elf32_Phdr) || phnum == 0)
141b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper	goto bad_elf;
142b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper      shdrs_end = ehdr.e32.e_shoff + ehdr.e32.e_shnum * ehdr.e32.e_shentsize;
143b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper      break;
144b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper
145b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper    case ELFCLASS64:
146b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper      xlatefrom.d_size = sizeof (Elf64_Ehdr);
1476258e7486eb3eed6e50005946795c5fbf73aa106Ulrich Drepper      if (elf64_xlatetom (&xlateto, &xlatefrom, buffer[EI_DATA]) == NULL)
148b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper	goto libelf_error;
149b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper      phoff = ehdr.e64.e_phoff;
150b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper      phnum = ehdr.e64.e_phnum;
151b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper      phentsize = ehdr.e64.e_phentsize;
152b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper      if (phentsize != sizeof (Elf64_Phdr) || phnum == 0)
153b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper	goto bad_elf;
154b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper      shdrs_end = ehdr.e64.e_shoff + ehdr.e64.e_shnum * ehdr.e64.e_shentsize;
155b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper      break;
156b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper
157b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper    default:
158b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper      goto bad_elf;
159b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper    }
160b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper
161b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper
162b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper  /* The file header tells where to find the program headers.
163b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper     These are what we use to actually choose what to read.  */
164b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper
165b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper  xlatefrom.d_type = xlateto.d_type = ELF_T_PHDR;
166b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper  xlatefrom.d_size = phnum * phentsize;
167b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper
168b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper  if ((size_t) nread >= phoff + phnum * phentsize)
169b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper    /* We already have all the phdrs from the initial read.  */
170b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper    xlatefrom.d_buf = buffer + phoff;
171b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper  else
172b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper    {
173b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper      /* Read in the program headers.  */
174b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper
175b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper      if (initial_bufsize < phnum * phentsize)
176b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper	{
177b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper	  unsigned char *newbuf = realloc (buffer, phnum * phentsize);
178b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper	  if (newbuf == NULL)
179b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper	    {
180b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper	      free (buffer);
1819202fe132caea838cc7e2c7864e0ee702e62f155Mark Wielaard	      free (phdrsp);
182b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper	      goto no_memory;
183b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper	    }
184b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper	  buffer = newbuf;
185b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper	}
186b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper      nread = (*read_memory) (arg, buffer, ehdr_vma + phoff,
187b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper			      phnum * phentsize, phnum * phentsize);
188b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper      if (nread <= 0)
189b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper	goto read_error;
190b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper
191b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper      xlatefrom.d_buf = buffer;
192b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper    }
193b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper
19486ed7f7f53179d7a893329e6b9851dbb75aba405Mark Wielaard  bool class32 = ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32;
19586ed7f7f53179d7a893329e6b9851dbb75aba405Mark Wielaard  size_t phdr_size = class32 ? sizeof (Elf32_Phdr) : sizeof (Elf64_Phdr);
19686ed7f7f53179d7a893329e6b9851dbb75aba405Mark Wielaard  if (unlikely (phnum > SIZE_MAX / phdr_size))
1977eff36d5daa6ebca5e6399638a7643af105ae5b0Chih-Hung Hsieh    {
1987eff36d5daa6ebca5e6399638a7643af105ae5b0Chih-Hung Hsieh      free (buffer);
1997eff36d5daa6ebca5e6399638a7643af105ae5b0Chih-Hung Hsieh      goto no_memory;
2007eff36d5daa6ebca5e6399638a7643af105ae5b0Chih-Hung Hsieh    }
20186ed7f7f53179d7a893329e6b9851dbb75aba405Mark Wielaard  const size_t phdrsp_bytes = phnum * phdr_size;
2027eff36d5daa6ebca5e6399638a7643af105ae5b0Chih-Hung Hsieh  phdrsp = malloc (phdrsp_bytes);
2039202fe132caea838cc7e2c7864e0ee702e62f155Mark Wielaard  if (unlikely (phdrsp == NULL))
2049202fe132caea838cc7e2c7864e0ee702e62f155Mark Wielaard    {
2059202fe132caea838cc7e2c7864e0ee702e62f155Mark Wielaard      free (buffer);
2069202fe132caea838cc7e2c7864e0ee702e62f155Mark Wielaard      goto no_memory;
2079202fe132caea838cc7e2c7864e0ee702e62f155Mark Wielaard    }
208b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper
2097eff36d5daa6ebca5e6399638a7643af105ae5b0Chih-Hung Hsieh  xlateto.d_buf = phdrsp;
2107eff36d5daa6ebca5e6399638a7643af105ae5b0Chih-Hung Hsieh  xlateto.d_size = phdrsp_bytes;
211b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper
212b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper  /* Scan for PT_LOAD segments to find the total size of the file image.  */
213b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper  size_t contents_size = 0;
214b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper  GElf_Off segments_end = 0;
215dd64d4a9268b822b035f8c59c2b8f55a65f80819Mark Wielaard  GElf_Off segments_end_mem = 0;
216b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper  GElf_Addr loadbase = ehdr_vma;
217099dd52727f2ce1a2c73cde82af8cd5e06368aecRoland McGrath  bool found_base = false;
21886ed7f7f53179d7a893329e6b9851dbb75aba405Mark Wielaard  Elf32_Phdr (*p32)[phnum] = phdrsp;
21986ed7f7f53179d7a893329e6b9851dbb75aba405Mark Wielaard  Elf64_Phdr (*p64)[phnum] = phdrsp;
220b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper  switch (ehdr.e32.e_ident[EI_CLASS])
221b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper    {
222f15bcda4137446d4773bb54cb99cc18497e9822cMark Wielaard      /* Sanity checks segments and calculates segment_end,
223f15bcda4137446d4773bb54cb99cc18497e9822cMark Wielaard	 segments_end, segments_end_mem and loadbase (if not
224f15bcda4137446d4773bb54cb99cc18497e9822cMark Wielaard	 found_base yet).  Returns true if sanity checking failed,
225f15bcda4137446d4773bb54cb99cc18497e9822cMark Wielaard	 false otherwise.  */
226f15bcda4137446d4773bb54cb99cc18497e9822cMark Wielaard      inline bool handle_segment (GElf_Addr vaddr, GElf_Off offset,
22732b6c6aa608d64529e863684d3d7ec3f49afe7faMark Wielaard				  GElf_Xword filesz, GElf_Xword memsz)
228b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper	{
22932b6c6aa608d64529e863684d3d7ec3f49afe7faMark Wielaard	  /* Sanity check the segment load aligns with the pagesize.  */
23032b6c6aa608d64529e863684d3d7ec3f49afe7faMark Wielaard	  if (((vaddr - offset) & (pagesize - 1)) != 0)
231f15bcda4137446d4773bb54cb99cc18497e9822cMark Wielaard	    return true;
232f15bcda4137446d4773bb54cb99cc18497e9822cMark Wielaard
233f15bcda4137446d4773bb54cb99cc18497e9822cMark Wielaard	  GElf_Off segment_end = ((offset + filesz + pagesize - 1)
234f15bcda4137446d4773bb54cb99cc18497e9822cMark Wielaard				  & -pagesize);
235b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper
236b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper	  if (segment_end > (GElf_Off) contents_size)
237b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper	    contents_size = segment_end;
238b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper
239f15bcda4137446d4773bb54cb99cc18497e9822cMark Wielaard	  if (!found_base && (offset & -pagesize) == 0)
240099dd52727f2ce1a2c73cde82af8cd5e06368aecRoland McGrath	    {
241f15bcda4137446d4773bb54cb99cc18497e9822cMark Wielaard	      loadbase = ehdr_vma - (vaddr & -pagesize);
242099dd52727f2ce1a2c73cde82af8cd5e06368aecRoland McGrath	      found_base = true;
243099dd52727f2ce1a2c73cde82af8cd5e06368aecRoland McGrath	    }
244b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper
245b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper	  segments_end = offset + filesz;
246dd64d4a9268b822b035f8c59c2b8f55a65f80819Mark Wielaard	  segments_end_mem = offset + memsz;
247f15bcda4137446d4773bb54cb99cc18497e9822cMark Wielaard	  return false;
248b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper	}
249b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper
250b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper    case ELFCLASS32:
251b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper      if (elf32_xlatetom (&xlateto, &xlatefrom,
252b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper			  ehdr.e32.e_ident[EI_DATA]) == NULL)
253b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper	goto libelf_error;
254b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper      for (uint_fast16_t i = 0; i < phnum; ++i)
2557eff36d5daa6ebca5e6399638a7643af105ae5b0Chih-Hung Hsieh	if ((*p32)[i].p_type == PT_LOAD)
2567eff36d5daa6ebca5e6399638a7643af105ae5b0Chih-Hung Hsieh	  if (handle_segment ((*p32)[i].p_vaddr, (*p32)[i].p_offset,
2577eff36d5daa6ebca5e6399638a7643af105ae5b0Chih-Hung Hsieh			      (*p32)[i].p_filesz, (*p32)[i].p_memsz))
258f15bcda4137446d4773bb54cb99cc18497e9822cMark Wielaard	    goto bad_elf;
259b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper      break;
260b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper
261b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper    case ELFCLASS64:
26201fef9d502eb1e21ac7b7e8ec9451dc96c72f7edRoland McGrath      if (elf64_xlatetom (&xlateto, &xlatefrom,
26301fef9d502eb1e21ac7b7e8ec9451dc96c72f7edRoland McGrath			  ehdr.e64.e_ident[EI_DATA]) == NULL)
264b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper	goto libelf_error;
265b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper      for (uint_fast16_t i = 0; i < phnum; ++i)
2667eff36d5daa6ebca5e6399638a7643af105ae5b0Chih-Hung Hsieh	if ((*p64)[i].p_type == PT_LOAD)
2677eff36d5daa6ebca5e6399638a7643af105ae5b0Chih-Hung Hsieh	  if (handle_segment ((*p64)[i].p_vaddr, (*p64)[i].p_offset,
2687eff36d5daa6ebca5e6399638a7643af105ae5b0Chih-Hung Hsieh			      (*p64)[i].p_filesz, (*p64)[i].p_memsz))
269f15bcda4137446d4773bb54cb99cc18497e9822cMark Wielaard	    goto bad_elf;
270b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper      break;
271b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper
272b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper    default:
273b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper      abort ();
274b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper      break;
275b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper    }
276b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper
277b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper  /* Trim the last segment so we don't bother with zeros in the last page
278b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper     that are off the end of the file.  However, if the extra bit in that
279dd64d4a9268b822b035f8c59c2b8f55a65f80819Mark Wielaard     page includes the section headers and the memory isn't extended (which
280dd64d4a9268b822b035f8c59c2b8f55a65f80819Mark Wielaard     might indicate it will have been reused otherwise), keep them.  */
281b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper  if ((GElf_Off) contents_size > segments_end
282dd64d4a9268b822b035f8c59c2b8f55a65f80819Mark Wielaard      && (GElf_Off) contents_size >= shdrs_end
283dd64d4a9268b822b035f8c59c2b8f55a65f80819Mark Wielaard      && segments_end == segments_end_mem)
284b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper    {
285b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper      contents_size = segments_end;
286b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper      if ((GElf_Off) contents_size < shdrs_end)
287b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper	contents_size = shdrs_end;
288b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper    }
289b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper  else
290b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper    contents_size = segments_end;
291b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper
292b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper  free (buffer);
293b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper
294b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper  /* Now we know the size of the whole image we want read in.  */
295b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper  buffer = calloc (1, contents_size);
296b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper  if (buffer == NULL)
2979202fe132caea838cc7e2c7864e0ee702e62f155Mark Wielaard    {
2989202fe132caea838cc7e2c7864e0ee702e62f155Mark Wielaard      free (phdrsp);
2999202fe132caea838cc7e2c7864e0ee702e62f155Mark Wielaard      goto no_memory;
3009202fe132caea838cc7e2c7864e0ee702e62f155Mark Wielaard    }
301b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper
302b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper  switch (ehdr.e32.e_ident[EI_CLASS])
303b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper    {
304f15bcda4137446d4773bb54cb99cc18497e9822cMark Wielaard      /* Reads the given segment.  Returns true if reading fails,
305f15bcda4137446d4773bb54cb99cc18497e9822cMark Wielaard	 false otherwise.  */
306b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper      inline bool handle_segment (GElf_Addr vaddr, GElf_Off offset,
307f15bcda4137446d4773bb54cb99cc18497e9822cMark Wielaard				  GElf_Xword filesz)
308b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper	{
309f15bcda4137446d4773bb54cb99cc18497e9822cMark Wielaard	  GElf_Off start = offset & -pagesize;
310f15bcda4137446d4773bb54cb99cc18497e9822cMark Wielaard	  GElf_Off end = (offset + filesz + pagesize - 1) & -pagesize;
311b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper	  if (end > (GElf_Off) contents_size)
312b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper	    end = contents_size;
313b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper	  nread = (*read_memory) (arg, buffer + start,
314f15bcda4137446d4773bb54cb99cc18497e9822cMark Wielaard				  (loadbase + vaddr) & -pagesize,
315b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper				  end - start, end - start);
316b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper	  return nread <= 0;
317b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper	}
318b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper
319b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper    case ELFCLASS32:
320b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper      for (uint_fast16_t i = 0; i < phnum; ++i)
3217eff36d5daa6ebca5e6399638a7643af105ae5b0Chih-Hung Hsieh	if ((*p32)[i].p_type == PT_LOAD)
3227eff36d5daa6ebca5e6399638a7643af105ae5b0Chih-Hung Hsieh	  if (handle_segment ((*p32)[i].p_vaddr, (*p32)[i].p_offset,
3237eff36d5daa6ebca5e6399638a7643af105ae5b0Chih-Hung Hsieh			      (*p32)[i].p_filesz))
324b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper	    goto read_error;
325b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper
326b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper      /* If the segments visible in memory didn't include the section
327b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper	 headers, then clear them from the file header.  */
328b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper      if (contents_size < shdrs_end)
329b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper	{
330b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper	  ehdr.e32.e_shoff = 0;
331b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper	  ehdr.e32.e_shnum = 0;
332b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper	  ehdr.e32.e_shstrndx = 0;
333b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper	}
334b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper
335b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper      /* This will normally have been in the first PT_LOAD segment.  But it
336b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper	 conceivably could be missing, and we might have just changed it.  */
337b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper      xlatefrom.d_type = xlateto.d_type = ELF_T_EHDR;
338b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper      xlatefrom.d_size = xlateto.d_size = sizeof ehdr.e32;
339b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper      xlatefrom.d_buf = &ehdr.e32;
340b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper      xlateto.d_buf = buffer;
341b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper      if (elf32_xlatetof (&xlateto, &xlatefrom,
342b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper			  ehdr.e32.e_ident[EI_DATA]) == NULL)
343b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper	goto libelf_error;
344b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper      break;
345b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper
346b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper    case ELFCLASS64:
347b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper      for (uint_fast16_t i = 0; i < phnum; ++i)
3487eff36d5daa6ebca5e6399638a7643af105ae5b0Chih-Hung Hsieh	if ((*p64)[i].p_type == PT_LOAD)
3497eff36d5daa6ebca5e6399638a7643af105ae5b0Chih-Hung Hsieh	  if (handle_segment ((*p64)[i].p_vaddr, (*p64)[i].p_offset,
3507eff36d5daa6ebca5e6399638a7643af105ae5b0Chih-Hung Hsieh			      (*p64)[i].p_filesz))
351b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper	    goto read_error;
352b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper
353b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper      /* If the segments visible in memory didn't include the section
354b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper	 headers, then clear them from the file header.  */
355b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper      if (contents_size < shdrs_end)
356b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper	{
357b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper	  ehdr.e64.e_shoff = 0;
358b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper	  ehdr.e64.e_shnum = 0;
359b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper	  ehdr.e64.e_shstrndx = 0;
360b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper	}
361b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper
362b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper      /* This will normally have been in the first PT_LOAD segment.  But it
363b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper	 conceivably could be missing, and we might have just changed it.  */
364b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper      xlatefrom.d_type = xlateto.d_type = ELF_T_EHDR;
365b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper      xlatefrom.d_size = xlateto.d_size = sizeof ehdr.e64;
366b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper      xlatefrom.d_buf = &ehdr.e64;
367b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper      xlateto.d_buf = buffer;
368d5a7519085f35bf48c9b33b8698835b24caa2da1Ulrich Drepper      if (elf64_xlatetof (&xlateto, &xlatefrom,
369b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper			  ehdr.e64.e_ident[EI_DATA]) == NULL)
370b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper	goto libelf_error;
371b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper      break;
372b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper
373b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper    default:
374b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper      abort ();
375b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper      break;
376b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper    }
377b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper
3789202fe132caea838cc7e2c7864e0ee702e62f155Mark Wielaard  free (phdrsp);
3797eff36d5daa6ebca5e6399638a7643af105ae5b0Chih-Hung Hsieh  phdrsp = NULL;
3809202fe132caea838cc7e2c7864e0ee702e62f155Mark Wielaard
381b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper  /* Now we have the image.  Open libelf on it.  */
382b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper
383b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper  Elf *elf = elf_memory ((char *) buffer, contents_size);
384b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper  if (elf == NULL)
385b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper    {
386b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper      free (buffer);
387d5a7519085f35bf48c9b33b8698835b24caa2da1Ulrich Drepper      goto libelf_error;
388b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper    }
389b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper
390b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper  elf->flags |= ELF_F_MALLOCED;
391b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper  if (loadbasep != NULL)
392b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper    *loadbasep = loadbase;
393b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper  return elf;
394b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper}
395