xref: /third_party/elfutils/libelf/elf_begin.c (revision da0c48c4)
1da0c48c4Sopenharmony_ci/* Create descriptor for processing file.
2da0c48c4Sopenharmony_ci   Copyright (C) 1998-2010, 2012, 2014, 2015, 2016 Red Hat, Inc.
3da0c48c4Sopenharmony_ci   Copyright (C) 2021, 2022 Mark J. Wielaard <mark@klomp.org>
4da0c48c4Sopenharmony_ci   This file is part of elfutils.
5da0c48c4Sopenharmony_ci   Written by Ulrich Drepper <drepper@redhat.com>, 1998.
6da0c48c4Sopenharmony_ci
7da0c48c4Sopenharmony_ci   This file is free software; you can redistribute it and/or modify
8da0c48c4Sopenharmony_ci   it under the terms of either
9da0c48c4Sopenharmony_ci
10da0c48c4Sopenharmony_ci     * the GNU Lesser General Public License as published by the Free
11da0c48c4Sopenharmony_ci       Software Foundation; either version 3 of the License, or (at
12da0c48c4Sopenharmony_ci       your option) any later version
13da0c48c4Sopenharmony_ci
14da0c48c4Sopenharmony_ci   or
15da0c48c4Sopenharmony_ci
16da0c48c4Sopenharmony_ci     * the GNU General Public License as published by the Free
17da0c48c4Sopenharmony_ci       Software Foundation; either version 2 of the License, or (at
18da0c48c4Sopenharmony_ci       your option) any later version
19da0c48c4Sopenharmony_ci
20da0c48c4Sopenharmony_ci   or both in parallel, as here.
21da0c48c4Sopenharmony_ci
22da0c48c4Sopenharmony_ci   elfutils is distributed in the hope that it will be useful, but
23da0c48c4Sopenharmony_ci   WITHOUT ANY WARRANTY; without even the implied warranty of
24da0c48c4Sopenharmony_ci   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
25da0c48c4Sopenharmony_ci   General Public License for more details.
26da0c48c4Sopenharmony_ci
27da0c48c4Sopenharmony_ci   You should have received copies of the GNU General Public License and
28da0c48c4Sopenharmony_ci   the GNU Lesser General Public License along with this program.  If
29da0c48c4Sopenharmony_ci   not, see <http://www.gnu.org/licenses/>.  */
30da0c48c4Sopenharmony_ci
31da0c48c4Sopenharmony_ci#ifdef HAVE_CONFIG_H
32da0c48c4Sopenharmony_ci# include <config.h>
33da0c48c4Sopenharmony_ci#endif
34da0c48c4Sopenharmony_ci
35da0c48c4Sopenharmony_ci#include <assert.h>
36da0c48c4Sopenharmony_ci#include <ctype.h>
37da0c48c4Sopenharmony_ci#include <errno.h>
38da0c48c4Sopenharmony_ci#include <fcntl.h>
39da0c48c4Sopenharmony_ci#include <stdbool.h>
40da0c48c4Sopenharmony_ci#include <stddef.h>
41da0c48c4Sopenharmony_ci#include <string.h>
42da0c48c4Sopenharmony_ci#include <sys/stat.h>
43da0c48c4Sopenharmony_ci
44da0c48c4Sopenharmony_ci#include "libelfP.h"
45da0c48c4Sopenharmony_ci#include "common.h"
46da0c48c4Sopenharmony_ci
47da0c48c4Sopenharmony_ci
48da0c48c4Sopenharmony_ci/* Create descriptor for archive in memory.  */
49da0c48c4Sopenharmony_cistatic inline Elf *
50da0c48c4Sopenharmony_cifile_read_ar (int fildes, void *map_address, off_t offset, size_t maxsize,
51da0c48c4Sopenharmony_ci	      Elf_Cmd cmd, Elf *parent)
52da0c48c4Sopenharmony_ci{
53da0c48c4Sopenharmony_ci  Elf *elf;
54da0c48c4Sopenharmony_ci
55da0c48c4Sopenharmony_ci  /* Create a descriptor.  */
56da0c48c4Sopenharmony_ci  elf = allocate_elf (fildes, map_address, offset, maxsize, cmd, parent,
57da0c48c4Sopenharmony_ci                      ELF_K_AR, 0);
58da0c48c4Sopenharmony_ci  if (elf != NULL)
59da0c48c4Sopenharmony_ci    {
60da0c48c4Sopenharmony_ci      /* We don't read all the symbol tables in advance.  All this will
61da0c48c4Sopenharmony_ci	 happen on demand.  */
62da0c48c4Sopenharmony_ci      elf->state.ar.offset = offset + SARMAG;
63da0c48c4Sopenharmony_ci
64da0c48c4Sopenharmony_ci      elf->state.ar.elf_ar_hdr.ar_rawname = elf->state.ar.raw_name;
65da0c48c4Sopenharmony_ci    }
66da0c48c4Sopenharmony_ci
67da0c48c4Sopenharmony_ci  return elf;
68da0c48c4Sopenharmony_ci}
69da0c48c4Sopenharmony_ci
70da0c48c4Sopenharmony_ci
71da0c48c4Sopenharmony_cistatic size_t
72da0c48c4Sopenharmony_ciget_shnum (void *map_address, unsigned char *e_ident, int fildes,
73da0c48c4Sopenharmony_ci	   int64_t offset, size_t maxsize)
74da0c48c4Sopenharmony_ci{
75da0c48c4Sopenharmony_ci  size_t result;
76da0c48c4Sopenharmony_ci  union
77da0c48c4Sopenharmony_ci  {
78da0c48c4Sopenharmony_ci    Elf32_Ehdr *e32;
79da0c48c4Sopenharmony_ci    Elf64_Ehdr *e64;
80da0c48c4Sopenharmony_ci    void *p;
81da0c48c4Sopenharmony_ci  } ehdr;
82da0c48c4Sopenharmony_ci  union
83da0c48c4Sopenharmony_ci  {
84da0c48c4Sopenharmony_ci    Elf32_Ehdr e32;
85da0c48c4Sopenharmony_ci    Elf64_Ehdr e64;
86da0c48c4Sopenharmony_ci  } ehdr_mem;
87da0c48c4Sopenharmony_ci  bool is32 = e_ident[EI_CLASS] == ELFCLASS32;
88da0c48c4Sopenharmony_ci
89da0c48c4Sopenharmony_ci  if ((is32 && maxsize < sizeof (Elf32_Ehdr))
90da0c48c4Sopenharmony_ci      || (!is32 && maxsize < sizeof (Elf64_Ehdr)))
91da0c48c4Sopenharmony_ci    {
92da0c48c4Sopenharmony_ci       __libelf_seterrno (ELF_E_INVALID_ELF);
93da0c48c4Sopenharmony_ci      return (size_t) -1l;
94da0c48c4Sopenharmony_ci    }
95da0c48c4Sopenharmony_ci
96da0c48c4Sopenharmony_ci  /* Make the ELF header available.  */
97da0c48c4Sopenharmony_ci  if (e_ident[EI_DATA] == MY_ELFDATA
98da0c48c4Sopenharmony_ci      && (ALLOW_UNALIGNED
99da0c48c4Sopenharmony_ci	  || (((size_t) e_ident
100da0c48c4Sopenharmony_ci	       & ((is32 ? __alignof__ (Elf32_Ehdr) : __alignof__ (Elf64_Ehdr))
101da0c48c4Sopenharmony_ci		  - 1)) == 0)))
102da0c48c4Sopenharmony_ci    ehdr.p = e_ident;
103da0c48c4Sopenharmony_ci  else
104da0c48c4Sopenharmony_ci    {
105da0c48c4Sopenharmony_ci      /* We already read the ELF header.  We have to copy the header
106da0c48c4Sopenharmony_ci	 since we possibly modify the data here and the caller
107da0c48c4Sopenharmony_ci	 expects the memory it passes in to be preserved.  */
108da0c48c4Sopenharmony_ci      ehdr.p = &ehdr_mem;
109da0c48c4Sopenharmony_ci
110da0c48c4Sopenharmony_ci      if (is32)
111da0c48c4Sopenharmony_ci	{
112da0c48c4Sopenharmony_ci	  if (ALLOW_UNALIGNED)
113da0c48c4Sopenharmony_ci	    {
114da0c48c4Sopenharmony_ci	      ehdr_mem.e32.e_shnum = ((Elf32_Ehdr *) e_ident)->e_shnum;
115da0c48c4Sopenharmony_ci	      ehdr_mem.e32.e_shoff = ((Elf32_Ehdr *) e_ident)->e_shoff;
116da0c48c4Sopenharmony_ci	    }
117da0c48c4Sopenharmony_ci	  else
118da0c48c4Sopenharmony_ci	    memcpy (&ehdr_mem, e_ident, sizeof (Elf32_Ehdr));
119da0c48c4Sopenharmony_ci
120da0c48c4Sopenharmony_ci	  if (e_ident[EI_DATA] != MY_ELFDATA)
121da0c48c4Sopenharmony_ci	    {
122da0c48c4Sopenharmony_ci	      CONVERT (ehdr_mem.e32.e_shnum);
123da0c48c4Sopenharmony_ci	      CONVERT (ehdr_mem.e32.e_shoff);
124da0c48c4Sopenharmony_ci	    }
125da0c48c4Sopenharmony_ci	}
126da0c48c4Sopenharmony_ci      else
127da0c48c4Sopenharmony_ci	{
128da0c48c4Sopenharmony_ci	  if (ALLOW_UNALIGNED)
129da0c48c4Sopenharmony_ci	    {
130da0c48c4Sopenharmony_ci	      ehdr_mem.e64.e_shnum = ((Elf64_Ehdr *) e_ident)->e_shnum;
131da0c48c4Sopenharmony_ci	      ehdr_mem.e64.e_shoff = ((Elf64_Ehdr *) e_ident)->e_shoff;
132da0c48c4Sopenharmony_ci	    }
133da0c48c4Sopenharmony_ci	  else
134da0c48c4Sopenharmony_ci	    memcpy (&ehdr_mem, e_ident, sizeof (Elf64_Ehdr));
135da0c48c4Sopenharmony_ci
136da0c48c4Sopenharmony_ci	  if (e_ident[EI_DATA] != MY_ELFDATA)
137da0c48c4Sopenharmony_ci	    {
138da0c48c4Sopenharmony_ci	      CONVERT (ehdr_mem.e64.e_shnum);
139da0c48c4Sopenharmony_ci	      CONVERT (ehdr_mem.e64.e_shoff);
140da0c48c4Sopenharmony_ci	    }
141da0c48c4Sopenharmony_ci	}
142da0c48c4Sopenharmony_ci    }
143da0c48c4Sopenharmony_ci
144da0c48c4Sopenharmony_ci  if (is32)
145da0c48c4Sopenharmony_ci    {
146da0c48c4Sopenharmony_ci      /* Get the number of sections from the ELF header.  */
147da0c48c4Sopenharmony_ci      result = ehdr.e32->e_shnum;
148da0c48c4Sopenharmony_ci
149da0c48c4Sopenharmony_ci      if (unlikely (result == 0) && ehdr.e32->e_shoff != 0)
150da0c48c4Sopenharmony_ci	{
151da0c48c4Sopenharmony_ci	  if (unlikely (ehdr.e32->e_shoff >= maxsize)
152da0c48c4Sopenharmony_ci	      || unlikely (maxsize - ehdr.e32->e_shoff < sizeof (Elf32_Shdr)))
153da0c48c4Sopenharmony_ci	    /* Cannot read the first section header.  */
154da0c48c4Sopenharmony_ci	    return 0;
155da0c48c4Sopenharmony_ci
156da0c48c4Sopenharmony_ci	  if (likely (map_address != NULL) && e_ident[EI_DATA] == MY_ELFDATA
157da0c48c4Sopenharmony_ci	      && (ALLOW_UNALIGNED
158da0c48c4Sopenharmony_ci		  || (((size_t) ((char *) (map_address + ehdr.e32->e_shoff
159da0c48c4Sopenharmony_ci					   + offset)))
160da0c48c4Sopenharmony_ci		      & (__alignof__ (Elf32_Shdr) - 1)) == 0))
161da0c48c4Sopenharmony_ci	    /* We can directly access the memory.  */
162da0c48c4Sopenharmony_ci	    result = ((Elf32_Shdr *) ((char *) map_address + ehdr.e32->e_shoff
163da0c48c4Sopenharmony_ci				      + offset))->sh_size;
164da0c48c4Sopenharmony_ci	  else
165da0c48c4Sopenharmony_ci	    {
166da0c48c4Sopenharmony_ci	      Elf32_Word size;
167da0c48c4Sopenharmony_ci	      ssize_t r;
168da0c48c4Sopenharmony_ci
169da0c48c4Sopenharmony_ci	      if (likely (map_address != NULL))
170da0c48c4Sopenharmony_ci		/* gcc will optimize the memcpy to a simple memory
171da0c48c4Sopenharmony_ci		   access while taking care of alignment issues.  */
172da0c48c4Sopenharmony_ci		memcpy (&size, ((char *) map_address
173da0c48c4Sopenharmony_ci					 + ehdr.e32->e_shoff
174da0c48c4Sopenharmony_ci					 + offset
175da0c48c4Sopenharmony_ci					 + offsetof (Elf32_Shdr, sh_size)),
176da0c48c4Sopenharmony_ci			sizeof (Elf32_Word));
177da0c48c4Sopenharmony_ci	      else
178da0c48c4Sopenharmony_ci		if (unlikely ((r = pread_retry (fildes, &size,
179da0c48c4Sopenharmony_ci						sizeof (Elf32_Word),
180da0c48c4Sopenharmony_ci						offset + ehdr.e32->e_shoff
181da0c48c4Sopenharmony_ci						+ offsetof (Elf32_Shdr,
182da0c48c4Sopenharmony_ci							    sh_size)))
183da0c48c4Sopenharmony_ci			      != sizeof (Elf32_Word)))
184da0c48c4Sopenharmony_ci		  {
185da0c48c4Sopenharmony_ci		    if (r < 0)
186da0c48c4Sopenharmony_ci		      __libelf_seterrno (ELF_E_INVALID_FILE);
187da0c48c4Sopenharmony_ci		    else
188da0c48c4Sopenharmony_ci		      __libelf_seterrno (ELF_E_INVALID_ELF);
189da0c48c4Sopenharmony_ci		    return (size_t) -1l;
190da0c48c4Sopenharmony_ci		  }
191da0c48c4Sopenharmony_ci
192da0c48c4Sopenharmony_ci	      if (e_ident[EI_DATA] != MY_ELFDATA)
193da0c48c4Sopenharmony_ci		CONVERT (size);
194da0c48c4Sopenharmony_ci
195da0c48c4Sopenharmony_ci	      result = size;
196da0c48c4Sopenharmony_ci	    }
197da0c48c4Sopenharmony_ci	}
198da0c48c4Sopenharmony_ci
199da0c48c4Sopenharmony_ci      /* If the section headers were truncated, pretend none were there.  */
200da0c48c4Sopenharmony_ci      if (ehdr.e32->e_shoff > maxsize
201da0c48c4Sopenharmony_ci	  || maxsize - ehdr.e32->e_shoff < sizeof (Elf32_Shdr) * result)
202da0c48c4Sopenharmony_ci	result = 0;
203da0c48c4Sopenharmony_ci    }
204da0c48c4Sopenharmony_ci  else
205da0c48c4Sopenharmony_ci    {
206da0c48c4Sopenharmony_ci      /* Get the number of sections from the ELF header.  */
207da0c48c4Sopenharmony_ci      result = ehdr.e64->e_shnum;
208da0c48c4Sopenharmony_ci
209da0c48c4Sopenharmony_ci      if (unlikely (result == 0) && ehdr.e64->e_shoff != 0)
210da0c48c4Sopenharmony_ci	{
211da0c48c4Sopenharmony_ci	  if (unlikely (ehdr.e64->e_shoff >= maxsize)
212da0c48c4Sopenharmony_ci	      || unlikely (ehdr.e64->e_shoff + sizeof (Elf64_Shdr) > maxsize))
213da0c48c4Sopenharmony_ci	    /* Cannot read the first section header.  */
214da0c48c4Sopenharmony_ci	    return 0;
215da0c48c4Sopenharmony_ci
216da0c48c4Sopenharmony_ci	  Elf64_Xword size;
217da0c48c4Sopenharmony_ci	  if (likely (map_address != NULL) && e_ident[EI_DATA] == MY_ELFDATA
218da0c48c4Sopenharmony_ci	      && (ALLOW_UNALIGNED
219da0c48c4Sopenharmony_ci		  || (((size_t) ((char *) (map_address + ehdr.e64->e_shoff
220da0c48c4Sopenharmony_ci					   + offset)))
221da0c48c4Sopenharmony_ci		      & (__alignof__ (Elf64_Shdr) - 1)) == 0))
222da0c48c4Sopenharmony_ci	    /* We can directly access the memory.  */
223da0c48c4Sopenharmony_ci	    size = ((Elf64_Shdr *) ((char *) map_address + ehdr.e64->e_shoff
224da0c48c4Sopenharmony_ci				    + offset))->sh_size;
225da0c48c4Sopenharmony_ci	  else
226da0c48c4Sopenharmony_ci	    {
227da0c48c4Sopenharmony_ci	      ssize_t r;
228da0c48c4Sopenharmony_ci	      if (likely (map_address != NULL))
229da0c48c4Sopenharmony_ci		/* gcc will optimize the memcpy to a simple memory
230da0c48c4Sopenharmony_ci		   access while taking care of alignment issues.  */
231da0c48c4Sopenharmony_ci		memcpy (&size, ((char *) map_address
232da0c48c4Sopenharmony_ci					 + ehdr.e64->e_shoff
233da0c48c4Sopenharmony_ci					 + offset
234da0c48c4Sopenharmony_ci					 + offsetof (Elf64_Shdr, sh_size)),
235da0c48c4Sopenharmony_ci			sizeof (Elf64_Xword));
236da0c48c4Sopenharmony_ci	      else
237da0c48c4Sopenharmony_ci		if (unlikely ((r = pread_retry (fildes, &size,
238da0c48c4Sopenharmony_ci						sizeof (Elf64_Xword),
239da0c48c4Sopenharmony_ci						offset + ehdr.e64->e_shoff
240da0c48c4Sopenharmony_ci						+ offsetof (Elf64_Shdr,
241da0c48c4Sopenharmony_ci							    sh_size)))
242da0c48c4Sopenharmony_ci			      != sizeof (Elf64_Xword)))
243da0c48c4Sopenharmony_ci		  {
244da0c48c4Sopenharmony_ci		    if (r < 0)
245da0c48c4Sopenharmony_ci		      __libelf_seterrno (ELF_E_INVALID_FILE);
246da0c48c4Sopenharmony_ci		    else
247da0c48c4Sopenharmony_ci		      __libelf_seterrno (ELF_E_INVALID_ELF);
248da0c48c4Sopenharmony_ci		    return (size_t) -1l;
249da0c48c4Sopenharmony_ci		  }
250da0c48c4Sopenharmony_ci
251da0c48c4Sopenharmony_ci	      if (e_ident[EI_DATA] != MY_ELFDATA)
252da0c48c4Sopenharmony_ci		CONVERT (size);
253da0c48c4Sopenharmony_ci	    }
254da0c48c4Sopenharmony_ci
255da0c48c4Sopenharmony_ci	  /* Although sh_size is an Elf64_Xword and can contain a 64bit
256da0c48c4Sopenharmony_ci	     value, we only expect an 32bit value max.  GElf_Word is
257da0c48c4Sopenharmony_ci	     32bit unsigned.  */
258da0c48c4Sopenharmony_ci	  if (size > ~((GElf_Word) 0))
259da0c48c4Sopenharmony_ci	    {
260da0c48c4Sopenharmony_ci	      /* Invalid value, it is too large.  */
261da0c48c4Sopenharmony_ci	      __libelf_seterrno (ELF_E_INVALID_ELF);
262da0c48c4Sopenharmony_ci	      return (size_t) -1l;
263da0c48c4Sopenharmony_ci	    }
264da0c48c4Sopenharmony_ci
265da0c48c4Sopenharmony_ci	  result = size;
266da0c48c4Sopenharmony_ci	}
267da0c48c4Sopenharmony_ci
268da0c48c4Sopenharmony_ci      /* If the section headers were truncated, pretend none were there.  */
269da0c48c4Sopenharmony_ci      if (ehdr.e64->e_shoff > maxsize
270da0c48c4Sopenharmony_ci	  || maxsize - ehdr.e64->e_shoff < sizeof (Elf64_Shdr) * result)
271da0c48c4Sopenharmony_ci	result = 0;
272da0c48c4Sopenharmony_ci    }
273da0c48c4Sopenharmony_ci
274da0c48c4Sopenharmony_ci  return result;
275da0c48c4Sopenharmony_ci}
276da0c48c4Sopenharmony_ci
277da0c48c4Sopenharmony_ci
278da0c48c4Sopenharmony_ci/* Create descriptor for ELF file in memory.  */
279da0c48c4Sopenharmony_cistatic Elf *
280da0c48c4Sopenharmony_cifile_read_elf (int fildes, void *map_address, unsigned char *e_ident,
281da0c48c4Sopenharmony_ci	       int64_t offset, size_t maxsize, Elf_Cmd cmd, Elf *parent)
282da0c48c4Sopenharmony_ci{
283da0c48c4Sopenharmony_ci  /* Verify the binary is of the class we can handle.  */
284da0c48c4Sopenharmony_ci  if (unlikely ((e_ident[EI_CLASS] != ELFCLASS32
285da0c48c4Sopenharmony_ci		 && e_ident[EI_CLASS] != ELFCLASS64)
286da0c48c4Sopenharmony_ci		/* We also can only handle two encodings.  */
287da0c48c4Sopenharmony_ci		|| (e_ident[EI_DATA] != ELFDATA2LSB
288da0c48c4Sopenharmony_ci		    && e_ident[EI_DATA] != ELFDATA2MSB)))
289da0c48c4Sopenharmony_ci    {
290da0c48c4Sopenharmony_ci      /* Cannot handle this.  */
291da0c48c4Sopenharmony_ci      __libelf_seterrno (ELF_E_INVALID_ELF);
292da0c48c4Sopenharmony_ci      return NULL;
293da0c48c4Sopenharmony_ci    }
294da0c48c4Sopenharmony_ci
295da0c48c4Sopenharmony_ci  /* Determine the number of sections.  Returns -1 and sets libelf errno
296da0c48c4Sopenharmony_ci     if the file handle or elf file is invalid.  Returns zero if there
297da0c48c4Sopenharmony_ci     are no section headers (or they cannot be read).  */
298da0c48c4Sopenharmony_ci  size_t scncnt = get_shnum (map_address, e_ident, fildes, offset, maxsize);
299da0c48c4Sopenharmony_ci  if (scncnt == (size_t) -1l)
300da0c48c4Sopenharmony_ci    /* Could not determine the number of sections.  */
301da0c48c4Sopenharmony_ci    return NULL;
302da0c48c4Sopenharmony_ci
303da0c48c4Sopenharmony_ci  /* Check for too many sections.  */
304da0c48c4Sopenharmony_ci  if (e_ident[EI_CLASS] == ELFCLASS32)
305da0c48c4Sopenharmony_ci    {
306da0c48c4Sopenharmony_ci      if (scncnt > SIZE_MAX / (sizeof (Elf_Scn) + sizeof (Elf32_Shdr)))
307da0c48c4Sopenharmony_ci	{
308da0c48c4Sopenharmony_ci	  __libelf_seterrno (ELF_E_INVALID_ELF);
309da0c48c4Sopenharmony_ci	  return NULL;
310da0c48c4Sopenharmony_ci	}
311da0c48c4Sopenharmony_ci    }
312da0c48c4Sopenharmony_ci  else if (scncnt > SIZE_MAX / (sizeof (Elf_Scn) + sizeof (Elf64_Shdr)))
313da0c48c4Sopenharmony_ci    {
314da0c48c4Sopenharmony_ci      __libelf_seterrno (ELF_E_INVALID_ELF);
315da0c48c4Sopenharmony_ci      return NULL;
316da0c48c4Sopenharmony_ci    }
317da0c48c4Sopenharmony_ci
318da0c48c4Sopenharmony_ci  /* We can now allocate the memory.  Even if there are no section headers,
319da0c48c4Sopenharmony_ci     we allocate space for a zeroth section in case we need it later.  */
320da0c48c4Sopenharmony_ci  const size_t scnmax = (scncnt ?: (cmd == ELF_C_RDWR || cmd == ELF_C_RDWR_MMAP)
321da0c48c4Sopenharmony_ci			 ? 1 : 0);
322da0c48c4Sopenharmony_ci  Elf *elf = allocate_elf (fildes, map_address, offset, maxsize, cmd, parent,
323da0c48c4Sopenharmony_ci			   ELF_K_ELF, scnmax * sizeof (Elf_Scn));
324da0c48c4Sopenharmony_ci  if (elf == NULL)
325da0c48c4Sopenharmony_ci    /* Not enough memory.  allocate_elf will have set libelf errno.  */
326da0c48c4Sopenharmony_ci    return NULL;
327da0c48c4Sopenharmony_ci
328da0c48c4Sopenharmony_ci  assert ((unsigned int) scncnt == scncnt);
329da0c48c4Sopenharmony_ci  assert (offsetof (struct Elf, state.elf32.scns)
330da0c48c4Sopenharmony_ci	  == offsetof (struct Elf, state.elf64.scns));
331da0c48c4Sopenharmony_ci  elf->state.elf32.scns.cnt = scncnt;
332da0c48c4Sopenharmony_ci  elf->state.elf32.scns.max = scnmax;
333da0c48c4Sopenharmony_ci
334da0c48c4Sopenharmony_ci  /* Some more or less arbitrary value.  */
335da0c48c4Sopenharmony_ci  elf->state.elf.scnincr = 10;
336da0c48c4Sopenharmony_ci
337da0c48c4Sopenharmony_ci  /* Make the class easily available.  */
338da0c48c4Sopenharmony_ci  elf->class = e_ident[EI_CLASS];
339da0c48c4Sopenharmony_ci
340da0c48c4Sopenharmony_ci  if (e_ident[EI_CLASS] == ELFCLASS32)
341da0c48c4Sopenharmony_ci    {
342da0c48c4Sopenharmony_ci      /* This pointer might not be directly usable if the alignment is
343da0c48c4Sopenharmony_ci	 not sufficient for the architecture.  */
344da0c48c4Sopenharmony_ci      Elf32_Ehdr *ehdr = (Elf32_Ehdr *) ((char *) map_address + offset);
345da0c48c4Sopenharmony_ci
346da0c48c4Sopenharmony_ci      /* This is a 32-bit binary.  */
347da0c48c4Sopenharmony_ci      if (map_address != NULL && e_ident[EI_DATA] == MY_ELFDATA
348da0c48c4Sopenharmony_ci	  && (ALLOW_UNALIGNED
349da0c48c4Sopenharmony_ci	      || (((uintptr_t) ehdr) & (__alignof__ (Elf32_Ehdr) - 1)) == 0))
350da0c48c4Sopenharmony_ci	{
351da0c48c4Sopenharmony_ci	  /* We can use the mmapped memory.  */
352da0c48c4Sopenharmony_ci	  elf->state.elf32.ehdr = ehdr;
353da0c48c4Sopenharmony_ci	}
354da0c48c4Sopenharmony_ci      else
355da0c48c4Sopenharmony_ci	{
356da0c48c4Sopenharmony_ci	  /* Copy the ELF header.  */
357da0c48c4Sopenharmony_ci	  elf->state.elf32.ehdr = memcpy (&elf->state.elf32.ehdr_mem, e_ident,
358da0c48c4Sopenharmony_ci					  sizeof (Elf32_Ehdr));
359da0c48c4Sopenharmony_ci
360da0c48c4Sopenharmony_ci	  if (e_ident[EI_DATA] != MY_ELFDATA)
361da0c48c4Sopenharmony_ci	    {
362da0c48c4Sopenharmony_ci	      CONVERT (elf->state.elf32.ehdr_mem.e_type);
363da0c48c4Sopenharmony_ci	      CONVERT (elf->state.elf32.ehdr_mem.e_machine);
364da0c48c4Sopenharmony_ci	      CONVERT (elf->state.elf32.ehdr_mem.e_version);
365da0c48c4Sopenharmony_ci	      CONVERT (elf->state.elf32.ehdr_mem.e_entry);
366da0c48c4Sopenharmony_ci	      CONVERT (elf->state.elf32.ehdr_mem.e_phoff);
367da0c48c4Sopenharmony_ci	      CONVERT (elf->state.elf32.ehdr_mem.e_shoff);
368da0c48c4Sopenharmony_ci	      CONVERT (elf->state.elf32.ehdr_mem.e_flags);
369da0c48c4Sopenharmony_ci	      CONVERT (elf->state.elf32.ehdr_mem.e_ehsize);
370da0c48c4Sopenharmony_ci	      CONVERT (elf->state.elf32.ehdr_mem.e_phentsize);
371da0c48c4Sopenharmony_ci	      CONVERT (elf->state.elf32.ehdr_mem.e_phnum);
372da0c48c4Sopenharmony_ci	      CONVERT (elf->state.elf32.ehdr_mem.e_shentsize);
373da0c48c4Sopenharmony_ci	      CONVERT (elf->state.elf32.ehdr_mem.e_shnum);
374da0c48c4Sopenharmony_ci	      CONVERT (elf->state.elf32.ehdr_mem.e_shstrndx);
375da0c48c4Sopenharmony_ci	    }
376da0c48c4Sopenharmony_ci	}
377da0c48c4Sopenharmony_ci
378da0c48c4Sopenharmony_ci      /* Don't precache the phdr pointer here.
379da0c48c4Sopenharmony_ci	 elf32_getphdr will validate it against the size when asked.  */
380da0c48c4Sopenharmony_ci
381da0c48c4Sopenharmony_ci      Elf32_Off e_shoff = elf->state.elf32.ehdr->e_shoff;
382da0c48c4Sopenharmony_ci      if (map_address != NULL && e_ident[EI_DATA] == MY_ELFDATA
383da0c48c4Sopenharmony_ci	  && cmd != ELF_C_READ_MMAP /* We need a copy to be able to write.  */
384da0c48c4Sopenharmony_ci	  && (ALLOW_UNALIGNED
385da0c48c4Sopenharmony_ci	      || ((((uintptr_t) ehdr + e_shoff)
386da0c48c4Sopenharmony_ci		   & (__alignof__ (Elf32_Shdr) - 1)) == 0)))
387da0c48c4Sopenharmony_ci	{
388da0c48c4Sopenharmony_ci	  if (unlikely (scncnt > 0 && e_shoff >= maxsize)
389da0c48c4Sopenharmony_ci	      || unlikely (maxsize - e_shoff
390da0c48c4Sopenharmony_ci			   < scncnt * sizeof (Elf32_Shdr)))
391da0c48c4Sopenharmony_ci	    {
392da0c48c4Sopenharmony_ci	    free_and_out:
393da0c48c4Sopenharmony_ci	      free (elf);
394da0c48c4Sopenharmony_ci	      __libelf_seterrno (ELF_E_INVALID_ELF);
395da0c48c4Sopenharmony_ci	      return NULL;
396da0c48c4Sopenharmony_ci	    }
397da0c48c4Sopenharmony_ci
398da0c48c4Sopenharmony_ci	  if (scncnt > 0)
399da0c48c4Sopenharmony_ci	    elf->state.elf32.shdr
400da0c48c4Sopenharmony_ci	      = (Elf32_Shdr *) ((char *) ehdr + e_shoff);
401da0c48c4Sopenharmony_ci
402da0c48c4Sopenharmony_ci	  for (size_t cnt = 0; cnt < scncnt; ++cnt)
403da0c48c4Sopenharmony_ci	    {
404da0c48c4Sopenharmony_ci	      elf->state.elf32.scns.data[cnt].index = cnt;
405da0c48c4Sopenharmony_ci	      elf->state.elf32.scns.data[cnt].elf = elf;
406da0c48c4Sopenharmony_ci	      elf->state.elf32.scns.data[cnt].shdr.e32 =
407da0c48c4Sopenharmony_ci		&elf->state.elf32.shdr[cnt];
408da0c48c4Sopenharmony_ci	      if (likely (elf->state.elf32.shdr[cnt].sh_offset < maxsize)
409da0c48c4Sopenharmony_ci		  && likely (elf->state.elf32.shdr[cnt].sh_size
410da0c48c4Sopenharmony_ci			     <= maxsize - elf->state.elf32.shdr[cnt].sh_offset))
411da0c48c4Sopenharmony_ci		elf->state.elf32.scns.data[cnt].rawdata_base =
412da0c48c4Sopenharmony_ci		  elf->state.elf32.scns.data[cnt].data_base =
413da0c48c4Sopenharmony_ci		  ((char *) map_address + offset
414da0c48c4Sopenharmony_ci		   + elf->state.elf32.shdr[cnt].sh_offset);
415da0c48c4Sopenharmony_ci	      elf->state.elf32.scns.data[cnt].list = &elf->state.elf32.scns;
416da0c48c4Sopenharmony_ci
417da0c48c4Sopenharmony_ci	      /* If this is a section with an extended index add a
418da0c48c4Sopenharmony_ci		 reference in the section which uses the extended
419da0c48c4Sopenharmony_ci		 index.  */
420da0c48c4Sopenharmony_ci	      if (elf->state.elf32.shdr[cnt].sh_type == SHT_SYMTAB_SHNDX
421da0c48c4Sopenharmony_ci		  && elf->state.elf32.shdr[cnt].sh_link < scncnt)
422da0c48c4Sopenharmony_ci		elf->state.elf32.scns.data[elf->state.elf32.shdr[cnt].sh_link].shndx_index
423da0c48c4Sopenharmony_ci		  = cnt;
424da0c48c4Sopenharmony_ci
425da0c48c4Sopenharmony_ci	      /* Set the own shndx_index field in case it has not yet
426da0c48c4Sopenharmony_ci		 been set.  */
427da0c48c4Sopenharmony_ci	      if (elf->state.elf32.scns.data[cnt].shndx_index == 0)
428da0c48c4Sopenharmony_ci		elf->state.elf32.scns.data[cnt].shndx_index = -1;
429da0c48c4Sopenharmony_ci	    }
430da0c48c4Sopenharmony_ci	}
431da0c48c4Sopenharmony_ci      else
432da0c48c4Sopenharmony_ci	{
433da0c48c4Sopenharmony_ci	  for (size_t cnt = 0; cnt < scncnt; ++cnt)
434da0c48c4Sopenharmony_ci	    {
435da0c48c4Sopenharmony_ci	      elf->state.elf32.scns.data[cnt].index = cnt;
436da0c48c4Sopenharmony_ci	      elf->state.elf32.scns.data[cnt].elf = elf;
437da0c48c4Sopenharmony_ci	      elf->state.elf32.scns.data[cnt].list = &elf->state.elf32.scns;
438da0c48c4Sopenharmony_ci	    }
439da0c48c4Sopenharmony_ci	}
440da0c48c4Sopenharmony_ci
441da0c48c4Sopenharmony_ci      /* So far only one block with sections.  */
442da0c48c4Sopenharmony_ci      elf->state.elf32.scns_last = &elf->state.elf32.scns;
443da0c48c4Sopenharmony_ci    }
444da0c48c4Sopenharmony_ci  else
445da0c48c4Sopenharmony_ci    {
446da0c48c4Sopenharmony_ci      /* This pointer might not be directly usable if the alignment is
447da0c48c4Sopenharmony_ci	 not sufficient for the architecture.  */
448da0c48c4Sopenharmony_ci      Elf64_Ehdr *ehdr = (Elf64_Ehdr *) ((char *) map_address + offset);
449da0c48c4Sopenharmony_ci
450da0c48c4Sopenharmony_ci      /* This is a 64-bit binary.  */
451da0c48c4Sopenharmony_ci      if (map_address != NULL && e_ident[EI_DATA] == MY_ELFDATA
452da0c48c4Sopenharmony_ci	  && (ALLOW_UNALIGNED
453da0c48c4Sopenharmony_ci	      || (((uintptr_t) ehdr) & (__alignof__ (Elf64_Ehdr) - 1)) == 0))
454da0c48c4Sopenharmony_ci	{
455da0c48c4Sopenharmony_ci	  /* We can use the mmapped memory.  */
456da0c48c4Sopenharmony_ci	  elf->state.elf64.ehdr = ehdr;
457da0c48c4Sopenharmony_ci	}
458da0c48c4Sopenharmony_ci      else
459da0c48c4Sopenharmony_ci	{
460da0c48c4Sopenharmony_ci	  /* Copy the ELF header.  */
461da0c48c4Sopenharmony_ci	  elf->state.elf64.ehdr = memcpy (&elf->state.elf64.ehdr_mem, e_ident,
462da0c48c4Sopenharmony_ci					  sizeof (Elf64_Ehdr));
463da0c48c4Sopenharmony_ci
464da0c48c4Sopenharmony_ci	  if (e_ident[EI_DATA] != MY_ELFDATA)
465da0c48c4Sopenharmony_ci	    {
466da0c48c4Sopenharmony_ci	      CONVERT (elf->state.elf64.ehdr_mem.e_type);
467da0c48c4Sopenharmony_ci	      CONVERT (elf->state.elf64.ehdr_mem.e_machine);
468da0c48c4Sopenharmony_ci	      CONVERT (elf->state.elf64.ehdr_mem.e_version);
469da0c48c4Sopenharmony_ci	      CONVERT (elf->state.elf64.ehdr_mem.e_entry);
470da0c48c4Sopenharmony_ci	      CONVERT (elf->state.elf64.ehdr_mem.e_phoff);
471da0c48c4Sopenharmony_ci	      CONVERT (elf->state.elf64.ehdr_mem.e_shoff);
472da0c48c4Sopenharmony_ci	      CONVERT (elf->state.elf64.ehdr_mem.e_flags);
473da0c48c4Sopenharmony_ci	      CONVERT (elf->state.elf64.ehdr_mem.e_ehsize);
474da0c48c4Sopenharmony_ci	      CONVERT (elf->state.elf64.ehdr_mem.e_phentsize);
475da0c48c4Sopenharmony_ci	      CONVERT (elf->state.elf64.ehdr_mem.e_phnum);
476da0c48c4Sopenharmony_ci	      CONVERT (elf->state.elf64.ehdr_mem.e_shentsize);
477da0c48c4Sopenharmony_ci	      CONVERT (elf->state.elf64.ehdr_mem.e_shnum);
478da0c48c4Sopenharmony_ci	      CONVERT (elf->state.elf64.ehdr_mem.e_shstrndx);
479da0c48c4Sopenharmony_ci	    }
480da0c48c4Sopenharmony_ci	}
481da0c48c4Sopenharmony_ci
482da0c48c4Sopenharmony_ci      /* Don't precache the phdr pointer here.
483da0c48c4Sopenharmony_ci	 elf64_getphdr will validate it against the size when asked.  */
484da0c48c4Sopenharmony_ci
485da0c48c4Sopenharmony_ci      Elf64_Off e_shoff = elf->state.elf64.ehdr->e_shoff;
486da0c48c4Sopenharmony_ci      if (map_address != NULL && e_ident[EI_DATA] == MY_ELFDATA
487da0c48c4Sopenharmony_ci	  && cmd != ELF_C_READ_MMAP /* We need a copy to be able to write.  */
488da0c48c4Sopenharmony_ci	  && (ALLOW_UNALIGNED
489da0c48c4Sopenharmony_ci	      || ((((uintptr_t) ehdr + e_shoff)
490da0c48c4Sopenharmony_ci		   & (__alignof__ (Elf64_Shdr) - 1)) == 0)))
491da0c48c4Sopenharmony_ci	{
492da0c48c4Sopenharmony_ci	  if (unlikely (scncnt > 0 && e_shoff >= maxsize)
493da0c48c4Sopenharmony_ci	      || unlikely (maxsize - e_shoff
494da0c48c4Sopenharmony_ci			   < scncnt * sizeof (Elf64_Shdr)))
495da0c48c4Sopenharmony_ci	    goto free_and_out;
496da0c48c4Sopenharmony_ci
497da0c48c4Sopenharmony_ci	  if (scncnt > 0)
498da0c48c4Sopenharmony_ci	    elf->state.elf64.shdr
499da0c48c4Sopenharmony_ci	      = (Elf64_Shdr *) ((char *) ehdr + e_shoff);
500da0c48c4Sopenharmony_ci
501da0c48c4Sopenharmony_ci	  for (size_t cnt = 0; cnt < scncnt; ++cnt)
502da0c48c4Sopenharmony_ci	    {
503da0c48c4Sopenharmony_ci	      elf->state.elf64.scns.data[cnt].index = cnt;
504da0c48c4Sopenharmony_ci	      elf->state.elf64.scns.data[cnt].elf = elf;
505da0c48c4Sopenharmony_ci	      elf->state.elf64.scns.data[cnt].shdr.e64 =
506da0c48c4Sopenharmony_ci		&elf->state.elf64.shdr[cnt];
507da0c48c4Sopenharmony_ci	      if (likely (elf->state.elf64.shdr[cnt].sh_offset < maxsize)
508da0c48c4Sopenharmony_ci		  && likely (elf->state.elf64.shdr[cnt].sh_size
509da0c48c4Sopenharmony_ci			     <= maxsize - elf->state.elf64.shdr[cnt].sh_offset))
510da0c48c4Sopenharmony_ci		elf->state.elf64.scns.data[cnt].rawdata_base =
511da0c48c4Sopenharmony_ci		  elf->state.elf64.scns.data[cnt].data_base =
512da0c48c4Sopenharmony_ci		  ((char *) map_address + offset
513da0c48c4Sopenharmony_ci		   + elf->state.elf64.shdr[cnt].sh_offset);
514da0c48c4Sopenharmony_ci	      elf->state.elf64.scns.data[cnt].list = &elf->state.elf64.scns;
515da0c48c4Sopenharmony_ci
516da0c48c4Sopenharmony_ci	      /* If this is a section with an extended index add a
517da0c48c4Sopenharmony_ci		 reference in the section which uses the extended
518da0c48c4Sopenharmony_ci		 index.  */
519da0c48c4Sopenharmony_ci	      if (elf->state.elf64.shdr[cnt].sh_type == SHT_SYMTAB_SHNDX
520da0c48c4Sopenharmony_ci		  && elf->state.elf64.shdr[cnt].sh_link < scncnt)
521da0c48c4Sopenharmony_ci		elf->state.elf64.scns.data[elf->state.elf64.shdr[cnt].sh_link].shndx_index
522da0c48c4Sopenharmony_ci		  = cnt;
523da0c48c4Sopenharmony_ci
524da0c48c4Sopenharmony_ci	      /* Set the own shndx_index field in case it has not yet
525da0c48c4Sopenharmony_ci		 been set.  */
526da0c48c4Sopenharmony_ci	      if (elf->state.elf64.scns.data[cnt].shndx_index == 0)
527da0c48c4Sopenharmony_ci		elf->state.elf64.scns.data[cnt].shndx_index = -1;
528da0c48c4Sopenharmony_ci	    }
529da0c48c4Sopenharmony_ci	}
530da0c48c4Sopenharmony_ci      else
531da0c48c4Sopenharmony_ci	{
532da0c48c4Sopenharmony_ci	  for (size_t cnt = 0; cnt < scncnt; ++cnt)
533da0c48c4Sopenharmony_ci	    {
534da0c48c4Sopenharmony_ci	      elf->state.elf64.scns.data[cnt].index = cnt;
535da0c48c4Sopenharmony_ci	      elf->state.elf64.scns.data[cnt].elf = elf;
536da0c48c4Sopenharmony_ci	      elf->state.elf64.scns.data[cnt].list = &elf->state.elf64.scns;
537da0c48c4Sopenharmony_ci	    }
538da0c48c4Sopenharmony_ci	}
539da0c48c4Sopenharmony_ci
540da0c48c4Sopenharmony_ci      /* So far only one block with sections.  */
541da0c48c4Sopenharmony_ci      elf->state.elf64.scns_last = &elf->state.elf64.scns;
542da0c48c4Sopenharmony_ci    }
543da0c48c4Sopenharmony_ci
544da0c48c4Sopenharmony_ci  return elf;
545da0c48c4Sopenharmony_ci}
546da0c48c4Sopenharmony_ci
547da0c48c4Sopenharmony_ci
548da0c48c4Sopenharmony_ciElf *
549da0c48c4Sopenharmony_ciinternal_function
550da0c48c4Sopenharmony_ci__libelf_read_mmaped_file (int fildes, void *map_address,  int64_t offset,
551da0c48c4Sopenharmony_ci			   size_t maxsize, Elf_Cmd cmd, Elf *parent)
552da0c48c4Sopenharmony_ci{
553da0c48c4Sopenharmony_ci  /* We have to find out what kind of file this is.  We handle ELF
554da0c48c4Sopenharmony_ci     files and archives.  To find out what we have we must look at the
555da0c48c4Sopenharmony_ci     header.  The header for an ELF file is EI_NIDENT bytes in size,
556da0c48c4Sopenharmony_ci     the header for an archive file SARMAG bytes long.  */
557da0c48c4Sopenharmony_ci  unsigned char *e_ident = (unsigned char *) map_address + offset;
558da0c48c4Sopenharmony_ci
559da0c48c4Sopenharmony_ci  /* See what kind of object we have here.  */
560da0c48c4Sopenharmony_ci  Elf_Kind kind = determine_kind (e_ident, maxsize);
561da0c48c4Sopenharmony_ci
562da0c48c4Sopenharmony_ci  switch (kind)
563da0c48c4Sopenharmony_ci    {
564da0c48c4Sopenharmony_ci    case ELF_K_ELF:
565da0c48c4Sopenharmony_ci      return file_read_elf (fildes, map_address, e_ident, offset, maxsize,
566da0c48c4Sopenharmony_ci			    cmd, parent);
567da0c48c4Sopenharmony_ci
568da0c48c4Sopenharmony_ci    case ELF_K_AR:
569da0c48c4Sopenharmony_ci      return file_read_ar (fildes, map_address, offset, maxsize, cmd, parent);
570da0c48c4Sopenharmony_ci
571da0c48c4Sopenharmony_ci    default:
572da0c48c4Sopenharmony_ci      break;
573da0c48c4Sopenharmony_ci    }
574da0c48c4Sopenharmony_ci
575da0c48c4Sopenharmony_ci  /* This case is easy.  Since we cannot do anything with this file
576da0c48c4Sopenharmony_ci     create a dummy descriptor.  */
577da0c48c4Sopenharmony_ci  return allocate_elf (fildes, map_address, offset, maxsize, cmd, parent,
578da0c48c4Sopenharmony_ci		       ELF_K_NONE, 0);
579da0c48c4Sopenharmony_ci}
580da0c48c4Sopenharmony_ci
581da0c48c4Sopenharmony_ci
582da0c48c4Sopenharmony_cistatic Elf *
583da0c48c4Sopenharmony_ciread_unmmaped_file (int fildes, int64_t offset, size_t maxsize, Elf_Cmd cmd,
584da0c48c4Sopenharmony_ci		    Elf *parent)
585da0c48c4Sopenharmony_ci{
586da0c48c4Sopenharmony_ci  /* We have to find out what kind of file this is.  We handle ELF
587da0c48c4Sopenharmony_ci     files and archives.  To find out what we have we must read the
588da0c48c4Sopenharmony_ci     header.  The identification header for an ELF file is EI_NIDENT
589da0c48c4Sopenharmony_ci     bytes in size, but we read the whole ELF header since we will
590da0c48c4Sopenharmony_ci     need it anyway later.  For archives the header in SARMAG bytes
591da0c48c4Sopenharmony_ci     long.  Read the maximum of these numbers.
592da0c48c4Sopenharmony_ci
593da0c48c4Sopenharmony_ci     XXX We have to change this for the extended `ar' format some day.
594da0c48c4Sopenharmony_ci
595da0c48c4Sopenharmony_ci     Use a union to ensure alignment.  We might later access the
596da0c48c4Sopenharmony_ci     memory as a ElfXX_Ehdr.  */
597da0c48c4Sopenharmony_ci  union
598da0c48c4Sopenharmony_ci  {
599da0c48c4Sopenharmony_ci    Elf64_Ehdr ehdr;
600da0c48c4Sopenharmony_ci    unsigned char header[MAX (sizeof (Elf64_Ehdr), SARMAG)];
601da0c48c4Sopenharmony_ci  } mem;
602da0c48c4Sopenharmony_ci
603da0c48c4Sopenharmony_ci  /* Read the head of the file.  */
604da0c48c4Sopenharmony_ci  ssize_t nread = pread_retry (fildes, mem.header,
605da0c48c4Sopenharmony_ci			       MIN (MAX (sizeof (Elf64_Ehdr), SARMAG),
606da0c48c4Sopenharmony_ci				    maxsize),
607da0c48c4Sopenharmony_ci			       offset);
608da0c48c4Sopenharmony_ci  if (unlikely (nread == -1))
609da0c48c4Sopenharmony_ci    {
610da0c48c4Sopenharmony_ci      /* We cannot even read the head of the file.  Maybe FILDES is associated
611da0c48c4Sopenharmony_ci	 with an unseekable device.  This is nothing we can handle.  */
612da0c48c4Sopenharmony_ci      __libelf_seterrno (ELF_E_INVALID_FILE);
613da0c48c4Sopenharmony_ci      return NULL;
614da0c48c4Sopenharmony_ci    }
615da0c48c4Sopenharmony_ci
616da0c48c4Sopenharmony_ci  /* See what kind of object we have here.  */
617da0c48c4Sopenharmony_ci  Elf_Kind kind = determine_kind (mem.header, nread);
618da0c48c4Sopenharmony_ci
619da0c48c4Sopenharmony_ci  switch (kind)
620da0c48c4Sopenharmony_ci    {
621da0c48c4Sopenharmony_ci    case ELF_K_AR:
622da0c48c4Sopenharmony_ci      return file_read_ar (fildes, NULL, offset, maxsize, cmd, parent);
623da0c48c4Sopenharmony_ci
624da0c48c4Sopenharmony_ci    case ELF_K_ELF:
625da0c48c4Sopenharmony_ci      /* Make sure at least the ELF header is contained in the file.  */
626da0c48c4Sopenharmony_ci      if ((size_t) nread >= (mem.header[EI_CLASS] == ELFCLASS32
627da0c48c4Sopenharmony_ci			     ? sizeof (Elf32_Ehdr) : sizeof (Elf64_Ehdr)))
628da0c48c4Sopenharmony_ci	return file_read_elf (fildes, NULL, mem.header, offset, maxsize, cmd,
629da0c48c4Sopenharmony_ci			      parent);
630da0c48c4Sopenharmony_ci      FALLTHROUGH;
631da0c48c4Sopenharmony_ci
632da0c48c4Sopenharmony_ci    default:
633da0c48c4Sopenharmony_ci      break;
634da0c48c4Sopenharmony_ci    }
635da0c48c4Sopenharmony_ci
636da0c48c4Sopenharmony_ci  /* This case is easy.  Since we cannot do anything with this file
637da0c48c4Sopenharmony_ci     create a dummy descriptor.  */
638da0c48c4Sopenharmony_ci  return allocate_elf (fildes, NULL, offset, maxsize, cmd, parent,
639da0c48c4Sopenharmony_ci		       ELF_K_NONE, 0);
640da0c48c4Sopenharmony_ci}
641da0c48c4Sopenharmony_ci
642da0c48c4Sopenharmony_ci
643da0c48c4Sopenharmony_ci/* Open a file for reading.  If possible we will try to mmap() the file.  */
644da0c48c4Sopenharmony_cistatic struct Elf *
645da0c48c4Sopenharmony_ciread_file (int fildes, int64_t offset, size_t maxsize,
646da0c48c4Sopenharmony_ci	   Elf_Cmd cmd, Elf *parent)
647da0c48c4Sopenharmony_ci{
648da0c48c4Sopenharmony_ci  void *map_address = NULL;
649da0c48c4Sopenharmony_ci  int use_mmap = (cmd == ELF_C_READ_MMAP || cmd == ELF_C_RDWR_MMAP
650da0c48c4Sopenharmony_ci		  || cmd == ELF_C_WRITE_MMAP
651da0c48c4Sopenharmony_ci		  || cmd == ELF_C_READ_MMAP_PRIVATE);
652da0c48c4Sopenharmony_ci
653da0c48c4Sopenharmony_ci  if (parent == NULL)
654da0c48c4Sopenharmony_ci    {
655da0c48c4Sopenharmony_ci      if (maxsize == ~((size_t) 0))
656da0c48c4Sopenharmony_ci	{
657da0c48c4Sopenharmony_ci	  /* We don't know in the moment how large the file is.
658da0c48c4Sopenharmony_ci	     Determine it now.  */
659da0c48c4Sopenharmony_ci	  struct stat st;
660da0c48c4Sopenharmony_ci
661da0c48c4Sopenharmony_ci	  if (fstat (fildes, &st) == 0
662da0c48c4Sopenharmony_ci	      && (sizeof (size_t) >= sizeof (st.st_size)
663da0c48c4Sopenharmony_ci		  || st.st_size <= ~((size_t) 0)))
664da0c48c4Sopenharmony_ci	    maxsize = (size_t) st.st_size;
665da0c48c4Sopenharmony_ci	}
666da0c48c4Sopenharmony_ci    }
667da0c48c4Sopenharmony_ci  else
668da0c48c4Sopenharmony_ci    {
669da0c48c4Sopenharmony_ci      /* The parent is already loaded.  Use it.  */
670da0c48c4Sopenharmony_ci      assert (maxsize != ~((size_t) 0));
671da0c48c4Sopenharmony_ci    }
672da0c48c4Sopenharmony_ci
673da0c48c4Sopenharmony_ci  if (use_mmap)
674da0c48c4Sopenharmony_ci    {
675da0c48c4Sopenharmony_ci      if (parent == NULL)
676da0c48c4Sopenharmony_ci	{
677da0c48c4Sopenharmony_ci	  /* We try to map the file ourself.  */
678da0c48c4Sopenharmony_ci	  map_address = mmap (NULL, maxsize, (cmd == ELF_C_READ_MMAP
679da0c48c4Sopenharmony_ci					      ? PROT_READ
680da0c48c4Sopenharmony_ci					      : PROT_READ|PROT_WRITE),
681da0c48c4Sopenharmony_ci			      cmd == ELF_C_READ_MMAP_PRIVATE
682da0c48c4Sopenharmony_ci			      || cmd == ELF_C_READ_MMAP
683da0c48c4Sopenharmony_ci			      ? MAP_PRIVATE : MAP_SHARED,
684da0c48c4Sopenharmony_ci			      fildes, offset);
685da0c48c4Sopenharmony_ci
686da0c48c4Sopenharmony_ci	  if (map_address == MAP_FAILED)
687da0c48c4Sopenharmony_ci	    map_address = NULL;
688da0c48c4Sopenharmony_ci	}
689da0c48c4Sopenharmony_ci      else
690da0c48c4Sopenharmony_ci	{
691da0c48c4Sopenharmony_ci	  map_address = parent->map_address;
692da0c48c4Sopenharmony_ci	}
693da0c48c4Sopenharmony_ci    }
694da0c48c4Sopenharmony_ci
695da0c48c4Sopenharmony_ci  /* If we have the file in memory optimize the access.  */
696da0c48c4Sopenharmony_ci  if (map_address != NULL)
697da0c48c4Sopenharmony_ci    {
698da0c48c4Sopenharmony_ci      assert (map_address != MAP_FAILED);
699da0c48c4Sopenharmony_ci
700da0c48c4Sopenharmony_ci      struct Elf *result = __libelf_read_mmaped_file (fildes, map_address,
701da0c48c4Sopenharmony_ci						      offset, maxsize, cmd,
702da0c48c4Sopenharmony_ci						      parent);
703da0c48c4Sopenharmony_ci
704da0c48c4Sopenharmony_ci      /* If something went wrong during the initialization unmap the
705da0c48c4Sopenharmony_ci	 memory if we mmaped here.  */
706da0c48c4Sopenharmony_ci      if (result == NULL
707da0c48c4Sopenharmony_ci	  && (parent == NULL
708da0c48c4Sopenharmony_ci	      || parent->map_address != map_address))
709da0c48c4Sopenharmony_ci	munmap (map_address, maxsize);
710da0c48c4Sopenharmony_ci      else if (parent == NULL)
711da0c48c4Sopenharmony_ci	/* Remember that we mmap()ed the memory.  */
712da0c48c4Sopenharmony_ci	result->flags |= ELF_F_MMAPPED;
713da0c48c4Sopenharmony_ci
714da0c48c4Sopenharmony_ci      return result;
715da0c48c4Sopenharmony_ci    }
716da0c48c4Sopenharmony_ci
717da0c48c4Sopenharmony_ci  /* Otherwise we have to do it the hard way.  We read as much as necessary
718da0c48c4Sopenharmony_ci     from the file whenever we need information which is not available.  */
719da0c48c4Sopenharmony_ci  return read_unmmaped_file (fildes, offset, maxsize, cmd, parent);
720da0c48c4Sopenharmony_ci}
721da0c48c4Sopenharmony_ci
722da0c48c4Sopenharmony_ci
723da0c48c4Sopenharmony_ci/* Find the entry with the long names for the content of this archive.  */
724da0c48c4Sopenharmony_cistatic const char *
725da0c48c4Sopenharmony_ciread_long_names (Elf *elf)
726da0c48c4Sopenharmony_ci{
727da0c48c4Sopenharmony_ci  off_t offset = SARMAG;	/* This is the first entry.  */
728da0c48c4Sopenharmony_ci  struct ar_hdr hdrm;
729da0c48c4Sopenharmony_ci  struct ar_hdr *hdr;
730da0c48c4Sopenharmony_ci  char *newp;
731da0c48c4Sopenharmony_ci  size_t len;
732da0c48c4Sopenharmony_ci
733da0c48c4Sopenharmony_ci  while (1)
734da0c48c4Sopenharmony_ci    {
735da0c48c4Sopenharmony_ci      if (elf->map_address != NULL)
736da0c48c4Sopenharmony_ci	{
737da0c48c4Sopenharmony_ci	  if ((size_t) offset > elf->maximum_size
738da0c48c4Sopenharmony_ci	      || elf->maximum_size - offset < sizeof (struct ar_hdr))
739da0c48c4Sopenharmony_ci	    return NULL;
740da0c48c4Sopenharmony_ci
741da0c48c4Sopenharmony_ci	  /* The data is mapped.  */
742da0c48c4Sopenharmony_ci	  hdr = (struct ar_hdr *) (elf->map_address + offset);
743da0c48c4Sopenharmony_ci	}
744da0c48c4Sopenharmony_ci      else
745da0c48c4Sopenharmony_ci	{
746da0c48c4Sopenharmony_ci	  /* Read the header from the file.  */
747da0c48c4Sopenharmony_ci	  if (unlikely (pread_retry (elf->fildes, &hdrm, sizeof (hdrm),
748da0c48c4Sopenharmony_ci				     elf->start_offset + offset)
749da0c48c4Sopenharmony_ci			!= sizeof (hdrm)))
750da0c48c4Sopenharmony_ci	    return NULL;
751da0c48c4Sopenharmony_ci
752da0c48c4Sopenharmony_ci	  hdr = &hdrm;
753da0c48c4Sopenharmony_ci	}
754da0c48c4Sopenharmony_ci
755da0c48c4Sopenharmony_ci      /* The ar_size is given as a fixed size decimal string, right
756da0c48c4Sopenharmony_ci	 padded with spaces.  Make sure we read it properly even if
757da0c48c4Sopenharmony_ci	 there is no terminating space.  */
758da0c48c4Sopenharmony_ci      char buf[sizeof (hdr->ar_size) + 1];
759da0c48c4Sopenharmony_ci      const char *string = hdr->ar_size;
760da0c48c4Sopenharmony_ci      if (hdr->ar_size[sizeof (hdr->ar_size) - 1] != ' ')
761da0c48c4Sopenharmony_ci	{
762da0c48c4Sopenharmony_ci	  *((char *) mempcpy (buf, hdr->ar_size, sizeof (hdr->ar_size))) = '\0';
763da0c48c4Sopenharmony_ci	  string = buf;
764da0c48c4Sopenharmony_ci	}
765da0c48c4Sopenharmony_ci
766da0c48c4Sopenharmony_ci      /* atol expects to see at least one digit.
767da0c48c4Sopenharmony_ci	 It also cannot be negative (-).  */
768da0c48c4Sopenharmony_ci      if (!isdigit(string[0]))
769da0c48c4Sopenharmony_ci	return NULL;
770da0c48c4Sopenharmony_ci      len = atol (string);
771da0c48c4Sopenharmony_ci
772da0c48c4Sopenharmony_ci      if (memcmp (hdr->ar_name, "//              ", 16) == 0)
773da0c48c4Sopenharmony_ci	break;
774da0c48c4Sopenharmony_ci
775da0c48c4Sopenharmony_ci      offset += sizeof (struct ar_hdr) + ((len + 1) & ~1l);
776da0c48c4Sopenharmony_ci    }
777da0c48c4Sopenharmony_ci
778da0c48c4Sopenharmony_ci  /* Sanity check len early if we can.  */
779da0c48c4Sopenharmony_ci  if (elf->map_address != NULL)
780da0c48c4Sopenharmony_ci    {
781da0c48c4Sopenharmony_ci      if (len > elf->maximum_size - offset - sizeof (struct ar_hdr))
782da0c48c4Sopenharmony_ci	return NULL;
783da0c48c4Sopenharmony_ci    }
784da0c48c4Sopenharmony_ci
785da0c48c4Sopenharmony_ci  /* Due to the stupid format of the long name table entry (which are not
786da0c48c4Sopenharmony_ci     NUL terminted) we have to provide an appropriate representation anyhow.
787da0c48c4Sopenharmony_ci     Therefore we always make a copy which has the appropriate form.  */
788da0c48c4Sopenharmony_ci  newp = malloc (len);
789da0c48c4Sopenharmony_ci  if (newp != NULL)
790da0c48c4Sopenharmony_ci    {
791da0c48c4Sopenharmony_ci      char *runp;
792da0c48c4Sopenharmony_ci
793da0c48c4Sopenharmony_ci      if (elf->map_address != NULL)
794da0c48c4Sopenharmony_ci	{
795da0c48c4Sopenharmony_ci	  /* Simply copy it over.  */
796da0c48c4Sopenharmony_ci	  elf->state.ar.long_names = (char *) memcpy (newp,
797da0c48c4Sopenharmony_ci						      elf->map_address + offset
798da0c48c4Sopenharmony_ci						      + sizeof (struct ar_hdr),
799da0c48c4Sopenharmony_ci						      len);
800da0c48c4Sopenharmony_ci	}
801da0c48c4Sopenharmony_ci      else
802da0c48c4Sopenharmony_ci	{
803da0c48c4Sopenharmony_ci	  if (unlikely ((size_t) pread_retry (elf->fildes, newp, len,
804da0c48c4Sopenharmony_ci					      elf->start_offset + offset
805da0c48c4Sopenharmony_ci					      + sizeof (struct ar_hdr))
806da0c48c4Sopenharmony_ci			!= len))
807da0c48c4Sopenharmony_ci	    {
808da0c48c4Sopenharmony_ci	      /* We were not able to read all data.  */
809da0c48c4Sopenharmony_ci	      free (newp);
810da0c48c4Sopenharmony_ci	      elf->state.ar.long_names = NULL;
811da0c48c4Sopenharmony_ci	      return NULL;
812da0c48c4Sopenharmony_ci	    }
813da0c48c4Sopenharmony_ci	  elf->state.ar.long_names = newp;
814da0c48c4Sopenharmony_ci	}
815da0c48c4Sopenharmony_ci
816da0c48c4Sopenharmony_ci      elf->state.ar.long_names_len = len;
817da0c48c4Sopenharmony_ci
818da0c48c4Sopenharmony_ci      /* Now NUL-terminate the strings.  */
819da0c48c4Sopenharmony_ci      runp = newp;
820da0c48c4Sopenharmony_ci      while (1)
821da0c48c4Sopenharmony_ci        {
822da0c48c4Sopenharmony_ci	  char *startp = runp;
823da0c48c4Sopenharmony_ci	  runp = (char *) memchr (runp, '/', newp + len - runp);
824da0c48c4Sopenharmony_ci	  if (runp == NULL)
825da0c48c4Sopenharmony_ci	    {
826da0c48c4Sopenharmony_ci	      /* This was the last entry.  Clear any left overs.  */
827da0c48c4Sopenharmony_ci	      memset (startp, '\0', newp + len - startp);
828da0c48c4Sopenharmony_ci	      break;
829da0c48c4Sopenharmony_ci	    }
830da0c48c4Sopenharmony_ci
831da0c48c4Sopenharmony_ci	  /* NUL-terminate the string.  */
832da0c48c4Sopenharmony_ci	  *runp++ = '\0';
833da0c48c4Sopenharmony_ci
834da0c48c4Sopenharmony_ci	  /* A sanity check.  Somebody might have generated invalid
835da0c48c4Sopenharmony_ci	     archive.  */
836da0c48c4Sopenharmony_ci	  if (runp >= newp + len)
837da0c48c4Sopenharmony_ci	    break;
838da0c48c4Sopenharmony_ci	}
839da0c48c4Sopenharmony_ci    }
840da0c48c4Sopenharmony_ci
841da0c48c4Sopenharmony_ci  return newp;
842da0c48c4Sopenharmony_ci}
843da0c48c4Sopenharmony_ci
844da0c48c4Sopenharmony_ci
845da0c48c4Sopenharmony_ci/* Read the next archive header.  */
846da0c48c4Sopenharmony_ciint
847da0c48c4Sopenharmony_ciinternal_function
848da0c48c4Sopenharmony_ci__libelf_next_arhdr_wrlock (Elf *elf)
849da0c48c4Sopenharmony_ci{
850da0c48c4Sopenharmony_ci  struct ar_hdr *ar_hdr;
851da0c48c4Sopenharmony_ci  Elf_Arhdr *elf_ar_hdr;
852da0c48c4Sopenharmony_ci
853da0c48c4Sopenharmony_ci  if (elf->map_address != NULL)
854da0c48c4Sopenharmony_ci    {
855da0c48c4Sopenharmony_ci      /* See whether this entry is in the file.  */
856da0c48c4Sopenharmony_ci      if (unlikely ((size_t) elf->state.ar.offset
857da0c48c4Sopenharmony_ci		    > elf->start_offset + elf->maximum_size
858da0c48c4Sopenharmony_ci		    || (elf->start_offset + elf->maximum_size
859da0c48c4Sopenharmony_ci			- elf->state.ar.offset) < sizeof (struct ar_hdr)))
860da0c48c4Sopenharmony_ci	{
861da0c48c4Sopenharmony_ci	  /* This record is not anymore in the file.  */
862da0c48c4Sopenharmony_ci	  __libelf_seterrno (ELF_E_RANGE);
863da0c48c4Sopenharmony_ci	  return -1;
864da0c48c4Sopenharmony_ci	}
865da0c48c4Sopenharmony_ci      ar_hdr = (struct ar_hdr *) (elf->map_address + elf->state.ar.offset);
866da0c48c4Sopenharmony_ci    }
867da0c48c4Sopenharmony_ci  else
868da0c48c4Sopenharmony_ci    {
869da0c48c4Sopenharmony_ci      ar_hdr = &elf->state.ar.ar_hdr;
870da0c48c4Sopenharmony_ci
871da0c48c4Sopenharmony_ci      if (unlikely (pread_retry (elf->fildes, ar_hdr, sizeof (struct ar_hdr),
872da0c48c4Sopenharmony_ci				 elf->state.ar.offset)
873da0c48c4Sopenharmony_ci		    != sizeof (struct ar_hdr)))
874da0c48c4Sopenharmony_ci	{
875da0c48c4Sopenharmony_ci	  /* Something went wrong while reading the file.  */
876da0c48c4Sopenharmony_ci	  __libelf_seterrno (ELF_E_RANGE);
877da0c48c4Sopenharmony_ci	  return -1;
878da0c48c4Sopenharmony_ci	}
879da0c48c4Sopenharmony_ci    }
880da0c48c4Sopenharmony_ci
881da0c48c4Sopenharmony_ci  /* One little consistency check.  */
882da0c48c4Sopenharmony_ci  if (unlikely (memcmp (ar_hdr->ar_fmag, ARFMAG, 2) != 0))
883da0c48c4Sopenharmony_ci    {
884da0c48c4Sopenharmony_ci      /* This is no valid archive.  */
885da0c48c4Sopenharmony_ci      __libelf_seterrno (ELF_E_ARCHIVE_FMAG);
886da0c48c4Sopenharmony_ci      return -1;
887da0c48c4Sopenharmony_ci    }
888da0c48c4Sopenharmony_ci
889da0c48c4Sopenharmony_ci  /* Copy the raw name over to a NUL terminated buffer.  */
890da0c48c4Sopenharmony_ci  *((char *) mempcpy (elf->state.ar.raw_name, ar_hdr->ar_name, 16)) = '\0';
891da0c48c4Sopenharmony_ci
892da0c48c4Sopenharmony_ci  elf_ar_hdr = &elf->state.ar.elf_ar_hdr;
893da0c48c4Sopenharmony_ci
894da0c48c4Sopenharmony_ci  /* Now convert the `struct ar_hdr' into `Elf_Arhdr'.
895da0c48c4Sopenharmony_ci     Determine whether this is a special entry.  */
896da0c48c4Sopenharmony_ci  if (ar_hdr->ar_name[0] == '/')
897da0c48c4Sopenharmony_ci    {
898da0c48c4Sopenharmony_ci      if (ar_hdr->ar_name[1] == ' '
899da0c48c4Sopenharmony_ci	  && memcmp (ar_hdr->ar_name, "/               ", 16) == 0)
900da0c48c4Sopenharmony_ci	/* This is the index.  */
901da0c48c4Sopenharmony_ci	elf_ar_hdr->ar_name = memcpy (elf->state.ar.ar_name, "/", 2);
902da0c48c4Sopenharmony_ci      else if (ar_hdr->ar_name[1] == 'S'
903da0c48c4Sopenharmony_ci	       && memcmp (ar_hdr->ar_name, "/SYM64/         ", 16) == 0)
904da0c48c4Sopenharmony_ci	/* 64-bit index.  */
905da0c48c4Sopenharmony_ci	elf_ar_hdr->ar_name = memcpy (elf->state.ar.ar_name, "/SYM64/", 8);
906da0c48c4Sopenharmony_ci      else if (ar_hdr->ar_name[1] == '/'
907da0c48c4Sopenharmony_ci	       && memcmp (ar_hdr->ar_name, "//              ", 16) == 0)
908da0c48c4Sopenharmony_ci	/* This is the array with the long names.  */
909da0c48c4Sopenharmony_ci	elf_ar_hdr->ar_name = memcpy (elf->state.ar.ar_name, "//", 3);
910da0c48c4Sopenharmony_ci      else if (likely  (isdigit (ar_hdr->ar_name[1])))
911da0c48c4Sopenharmony_ci	{
912da0c48c4Sopenharmony_ci	  size_t offset;
913da0c48c4Sopenharmony_ci
914da0c48c4Sopenharmony_ci	  /* This is a long name.  First we have to read the long name
915da0c48c4Sopenharmony_ci	     table, if this hasn't happened already.  */
916da0c48c4Sopenharmony_ci	  if (unlikely (elf->state.ar.long_names == NULL
917da0c48c4Sopenharmony_ci			&& read_long_names (elf) == NULL))
918da0c48c4Sopenharmony_ci	    {
919da0c48c4Sopenharmony_ci	      /* No long name table although it is reference.  The archive is
920da0c48c4Sopenharmony_ci		 broken.  */
921da0c48c4Sopenharmony_ci	      __libelf_seterrno (ELF_E_INVALID_ARCHIVE);
922da0c48c4Sopenharmony_ci	      return -1;
923da0c48c4Sopenharmony_ci	    }
924da0c48c4Sopenharmony_ci
925da0c48c4Sopenharmony_ci	  offset = atol (ar_hdr->ar_name + 1);
926da0c48c4Sopenharmony_ci	  if (unlikely (offset >= elf->state.ar.long_names_len))
927da0c48c4Sopenharmony_ci	    {
928da0c48c4Sopenharmony_ci	      /* The index in the long name table is larger than the table.  */
929da0c48c4Sopenharmony_ci	      __libelf_seterrno (ELF_E_INVALID_ARCHIVE);
930da0c48c4Sopenharmony_ci	      return -1;
931da0c48c4Sopenharmony_ci	    }
932da0c48c4Sopenharmony_ci	  elf_ar_hdr->ar_name = elf->state.ar.long_names + offset;
933da0c48c4Sopenharmony_ci	}
934da0c48c4Sopenharmony_ci      else
935da0c48c4Sopenharmony_ci	{
936da0c48c4Sopenharmony_ci	  /* This is none of the known special entries.  */
937da0c48c4Sopenharmony_ci	  __libelf_seterrno (ELF_E_INVALID_ARCHIVE);
938da0c48c4Sopenharmony_ci	  return -1;
939da0c48c4Sopenharmony_ci	}
940da0c48c4Sopenharmony_ci    }
941da0c48c4Sopenharmony_ci  else
942da0c48c4Sopenharmony_ci    {
943da0c48c4Sopenharmony_ci      char *endp;
944da0c48c4Sopenharmony_ci
945da0c48c4Sopenharmony_ci      /* It is a normal entry.  Copy over the name.  */
946da0c48c4Sopenharmony_ci      endp = (char *) memccpy (elf->state.ar.ar_name, ar_hdr->ar_name,
947da0c48c4Sopenharmony_ci			       '/', 16);
948da0c48c4Sopenharmony_ci      if (endp != NULL)
949da0c48c4Sopenharmony_ci	endp[-1] = '\0';
950da0c48c4Sopenharmony_ci      else
951da0c48c4Sopenharmony_ci	{
952da0c48c4Sopenharmony_ci	  /* In the old BSD style of archive, there is no / terminator.
953da0c48c4Sopenharmony_ci	     Instead, there is space padding at the end of the name.  */
954da0c48c4Sopenharmony_ci	  size_t i = 15;
955da0c48c4Sopenharmony_ci	  do
956da0c48c4Sopenharmony_ci	    elf->state.ar.ar_name[i] = '\0';
957da0c48c4Sopenharmony_ci	  while (i > 0 && elf->state.ar.ar_name[--i] == ' ');
958da0c48c4Sopenharmony_ci	}
959da0c48c4Sopenharmony_ci
960da0c48c4Sopenharmony_ci      elf_ar_hdr->ar_name = elf->state.ar.ar_name;
961da0c48c4Sopenharmony_ci    }
962da0c48c4Sopenharmony_ci
963da0c48c4Sopenharmony_ci  if (unlikely (ar_hdr->ar_size[0] == ' '))
964da0c48c4Sopenharmony_ci    /* Something is really wrong.  We cannot live without a size for
965da0c48c4Sopenharmony_ci       the member since it will not be possible to find the next
966da0c48c4Sopenharmony_ci       archive member.  */
967da0c48c4Sopenharmony_ci    {
968da0c48c4Sopenharmony_ci      __libelf_seterrno (ELF_E_INVALID_ARCHIVE);
969da0c48c4Sopenharmony_ci      return -1;
970da0c48c4Sopenharmony_ci    }
971da0c48c4Sopenharmony_ci
972da0c48c4Sopenharmony_ci  /* Since there are no specialized functions to convert ASCII to
973da0c48c4Sopenharmony_ci     time_t, uid_t, gid_t, mode_t, and off_t we use either atol or
974da0c48c4Sopenharmony_ci     atoll depending on the size of the types.  We are also prepared
975da0c48c4Sopenharmony_ci     for the case where the whole field in the `struct ar_hdr' is
976da0c48c4Sopenharmony_ci     filled in which case we cannot simply use atol/l but instead have
977da0c48c4Sopenharmony_ci     to create a temporary copy.  Note that all fields use decimal
978da0c48c4Sopenharmony_ci     encoding, except ar_mode which uses octal.  */
979da0c48c4Sopenharmony_ci
980da0c48c4Sopenharmony_ci#define INT_FIELD(FIELD)						      \
981da0c48c4Sopenharmony_ci  do									      \
982da0c48c4Sopenharmony_ci    {									      \
983da0c48c4Sopenharmony_ci      char buf[sizeof (ar_hdr->FIELD) + 1];				      \
984da0c48c4Sopenharmony_ci      const char *string = ar_hdr->FIELD;				      \
985da0c48c4Sopenharmony_ci      if (ar_hdr->FIELD[sizeof (ar_hdr->FIELD) - 1] != ' ')		      \
986da0c48c4Sopenharmony_ci	{								      \
987da0c48c4Sopenharmony_ci	  *((char *) mempcpy (buf, ar_hdr->FIELD, sizeof (ar_hdr->FIELD)))  \
988da0c48c4Sopenharmony_ci	    = '\0';							      \
989da0c48c4Sopenharmony_ci	  string = buf;							      \
990da0c48c4Sopenharmony_ci	}								      \
991da0c48c4Sopenharmony_ci      if (sizeof (elf_ar_hdr->FIELD) <= sizeof (long int))		      \
992da0c48c4Sopenharmony_ci	elf_ar_hdr->FIELD = (__typeof (elf_ar_hdr->FIELD)) atol (string);     \
993da0c48c4Sopenharmony_ci      else								      \
994da0c48c4Sopenharmony_ci	elf_ar_hdr->FIELD = (__typeof (elf_ar_hdr->FIELD)) atoll (string);    \
995da0c48c4Sopenharmony_ci    }									      \
996da0c48c4Sopenharmony_ci  while (0)
997da0c48c4Sopenharmony_ci
998da0c48c4Sopenharmony_ci#define OCT_FIELD(FIELD)						      \
999da0c48c4Sopenharmony_ci  do									      \
1000da0c48c4Sopenharmony_ci    {									      \
1001da0c48c4Sopenharmony_ci      char buf[sizeof (ar_hdr->FIELD) + 1];				      \
1002da0c48c4Sopenharmony_ci      const char *string = ar_hdr->FIELD;				      \
1003da0c48c4Sopenharmony_ci      if (ar_hdr->FIELD[sizeof (ar_hdr->FIELD) - 1] != ' ')		      \
1004da0c48c4Sopenharmony_ci	{								      \
1005da0c48c4Sopenharmony_ci	  *((char *) mempcpy (buf, ar_hdr->FIELD, sizeof (ar_hdr->FIELD)))  \
1006da0c48c4Sopenharmony_ci	    = '\0';							      \
1007da0c48c4Sopenharmony_ci	  string = buf;							      \
1008da0c48c4Sopenharmony_ci	}								      \
1009da0c48c4Sopenharmony_ci      if (sizeof (elf_ar_hdr->FIELD) <= sizeof (long int))		      \
1010da0c48c4Sopenharmony_ci	elf_ar_hdr->FIELD						      \
1011da0c48c4Sopenharmony_ci	  = (__typeof (elf_ar_hdr->FIELD)) strtol (string, NULL, 8);	      \
1012da0c48c4Sopenharmony_ci      else								      \
1013da0c48c4Sopenharmony_ci	elf_ar_hdr->FIELD						      \
1014da0c48c4Sopenharmony_ci	  = (__typeof (elf_ar_hdr->FIELD)) strtoll (string, NULL, 8);	      \
1015da0c48c4Sopenharmony_ci    }									      \
1016da0c48c4Sopenharmony_ci  while (0)
1017da0c48c4Sopenharmony_ci
1018da0c48c4Sopenharmony_ci  INT_FIELD (ar_date);
1019da0c48c4Sopenharmony_ci  INT_FIELD (ar_uid);
1020da0c48c4Sopenharmony_ci  INT_FIELD (ar_gid);
1021da0c48c4Sopenharmony_ci  OCT_FIELD (ar_mode);
1022da0c48c4Sopenharmony_ci  INT_FIELD (ar_size);
1023da0c48c4Sopenharmony_ci
1024da0c48c4Sopenharmony_ci  if (elf_ar_hdr->ar_size < 0)
1025da0c48c4Sopenharmony_ci    {
1026da0c48c4Sopenharmony_ci      __libelf_seterrno (ELF_E_INVALID_ARCHIVE);
1027da0c48c4Sopenharmony_ci      return -1;
1028da0c48c4Sopenharmony_ci    }
1029da0c48c4Sopenharmony_ci
1030da0c48c4Sopenharmony_ci  /* Truncated file?  */
1031da0c48c4Sopenharmony_ci  size_t maxsize;
1032da0c48c4Sopenharmony_ci  maxsize = (elf->start_offset + elf->maximum_size
1033da0c48c4Sopenharmony_ci	     - elf->state.ar.offset - sizeof (struct ar_hdr));
1034da0c48c4Sopenharmony_ci  if ((size_t) elf_ar_hdr->ar_size > maxsize)
1035da0c48c4Sopenharmony_ci    elf_ar_hdr->ar_size = maxsize;
1036da0c48c4Sopenharmony_ci
1037da0c48c4Sopenharmony_ci  return 0;
1038da0c48c4Sopenharmony_ci}
1039da0c48c4Sopenharmony_ci
1040da0c48c4Sopenharmony_ci
1041da0c48c4Sopenharmony_ci/* We were asked to return a clone of an existing descriptor.  This
1042da0c48c4Sopenharmony_ci   function must be called with the lock on the parent descriptor
1043da0c48c4Sopenharmony_ci   being held. */
1044da0c48c4Sopenharmony_cistatic Elf *
1045da0c48c4Sopenharmony_cidup_elf (int fildes, Elf_Cmd cmd, Elf *ref)
1046da0c48c4Sopenharmony_ci{
1047da0c48c4Sopenharmony_ci  struct Elf *result;
1048da0c48c4Sopenharmony_ci
1049da0c48c4Sopenharmony_ci  if (fildes == -1)
1050da0c48c4Sopenharmony_ci    /* Allow the user to pass -1 as the file descriptor for the new file.  */
1051da0c48c4Sopenharmony_ci    fildes = ref->fildes;
1052da0c48c4Sopenharmony_ci  /* The file descriptor better should be the same.  If it was disconnected
1053da0c48c4Sopenharmony_ci     already (using `elf_cntl') we do not test it.  */
1054da0c48c4Sopenharmony_ci  else if (unlikely (ref->fildes != -1 && fildes != ref->fildes))
1055da0c48c4Sopenharmony_ci    {
1056da0c48c4Sopenharmony_ci      __libelf_seterrno (ELF_E_FD_MISMATCH);
1057da0c48c4Sopenharmony_ci      return NULL;
1058da0c48c4Sopenharmony_ci    }
1059da0c48c4Sopenharmony_ci
1060da0c48c4Sopenharmony_ci  /* The mode must allow reading.  I.e., a descriptor creating with a
1061da0c48c4Sopenharmony_ci     command different then ELF_C_READ, ELF_C_WRITE and ELF_C_RDWR is
1062da0c48c4Sopenharmony_ci     not allowed.  */
1063da0c48c4Sopenharmony_ci  if (unlikely (ref->cmd != ELF_C_READ && ref->cmd != ELF_C_READ_MMAP
1064da0c48c4Sopenharmony_ci		&& ref->cmd != ELF_C_WRITE && ref->cmd != ELF_C_WRITE_MMAP
1065da0c48c4Sopenharmony_ci		&& ref->cmd != ELF_C_RDWR && ref->cmd != ELF_C_RDWR_MMAP
1066da0c48c4Sopenharmony_ci		&& ref->cmd != ELF_C_READ_MMAP_PRIVATE))
1067da0c48c4Sopenharmony_ci    {
1068da0c48c4Sopenharmony_ci      __libelf_seterrno (ELF_E_INVALID_OP);
1069da0c48c4Sopenharmony_ci      return NULL;
1070da0c48c4Sopenharmony_ci    }
1071da0c48c4Sopenharmony_ci
1072da0c48c4Sopenharmony_ci  /* Now it is time to distinguish between reading normal files and
1073da0c48c4Sopenharmony_ci     archives.  Normal files can easily be handled be incrementing the
1074da0c48c4Sopenharmony_ci     reference counter and return the same descriptor.  */
1075da0c48c4Sopenharmony_ci  if (ref->kind != ELF_K_AR)
1076da0c48c4Sopenharmony_ci    {
1077da0c48c4Sopenharmony_ci      ++ref->ref_count;
1078da0c48c4Sopenharmony_ci      return ref;
1079da0c48c4Sopenharmony_ci    }
1080da0c48c4Sopenharmony_ci
1081da0c48c4Sopenharmony_ci  /* This is an archive.  We must create a descriptor for the archive
1082da0c48c4Sopenharmony_ci     member the internal pointer of the archive file descriptor is
1083da0c48c4Sopenharmony_ci     pointing to.  First read the header of the next member if this
1084da0c48c4Sopenharmony_ci     has not happened already.  */
1085da0c48c4Sopenharmony_ci  if (ref->state.ar.elf_ar_hdr.ar_name == NULL
1086da0c48c4Sopenharmony_ci      && __libelf_next_arhdr_wrlock (ref) != 0)
1087da0c48c4Sopenharmony_ci    /* Something went wrong.  Maybe there is no member left.  */
1088da0c48c4Sopenharmony_ci    return NULL;
1089da0c48c4Sopenharmony_ci
1090da0c48c4Sopenharmony_ci  /* We have all the information we need about the next archive member.
1091da0c48c4Sopenharmony_ci     Now create a descriptor for it.  */
1092da0c48c4Sopenharmony_ci  result = read_file (fildes, ref->state.ar.offset + sizeof (struct ar_hdr),
1093da0c48c4Sopenharmony_ci		      ref->state.ar.elf_ar_hdr.ar_size, cmd, ref);
1094da0c48c4Sopenharmony_ci
1095da0c48c4Sopenharmony_ci  /* Enlist this new descriptor in the list of children.  */
1096da0c48c4Sopenharmony_ci  if (result != NULL)
1097da0c48c4Sopenharmony_ci    {
1098da0c48c4Sopenharmony_ci      result->next = ref->state.ar.children;
1099da0c48c4Sopenharmony_ci      ref->state.ar.children = result;
1100da0c48c4Sopenharmony_ci    }
1101da0c48c4Sopenharmony_ci
1102da0c48c4Sopenharmony_ci  return result;
1103da0c48c4Sopenharmony_ci}
1104da0c48c4Sopenharmony_ci
1105da0c48c4Sopenharmony_ci
1106da0c48c4Sopenharmony_ci/* Return descriptor for empty file ready for writing.  */
1107da0c48c4Sopenharmony_cistatic struct Elf *
1108da0c48c4Sopenharmony_ciwrite_file (int fd, Elf_Cmd cmd)
1109da0c48c4Sopenharmony_ci{
1110da0c48c4Sopenharmony_ci  /* We simply create an empty `Elf' structure.  */
1111da0c48c4Sopenharmony_ci#define NSCNSALLOC	10
1112da0c48c4Sopenharmony_ci  Elf *result = allocate_elf (fd, NULL, 0, 0, cmd, NULL, ELF_K_ELF,
1113da0c48c4Sopenharmony_ci			      NSCNSALLOC * sizeof (Elf_Scn));
1114da0c48c4Sopenharmony_ci
1115da0c48c4Sopenharmony_ci  if (result != NULL)
1116da0c48c4Sopenharmony_ci    {
1117da0c48c4Sopenharmony_ci      /* We have to write to the file in any case.  */
1118da0c48c4Sopenharmony_ci      result->flags = ELF_F_DIRTY;
1119da0c48c4Sopenharmony_ci
1120da0c48c4Sopenharmony_ci      /* Some more or less arbitrary value.  */
1121da0c48c4Sopenharmony_ci      result->state.elf.scnincr = NSCNSALLOC;
1122da0c48c4Sopenharmony_ci
1123da0c48c4Sopenharmony_ci      /* We have allocated room for some sections.  */
1124da0c48c4Sopenharmony_ci      assert (offsetof (struct Elf, state.elf32.scns)
1125da0c48c4Sopenharmony_ci	      == offsetof (struct Elf, state.elf64.scns));
1126da0c48c4Sopenharmony_ci      result->state.elf.scns_last = &result->state.elf32.scns;
1127da0c48c4Sopenharmony_ci      result->state.elf32.scns.max = NSCNSALLOC;
1128da0c48c4Sopenharmony_ci    }
1129da0c48c4Sopenharmony_ci
1130da0c48c4Sopenharmony_ci  return result;
1131da0c48c4Sopenharmony_ci}
1132da0c48c4Sopenharmony_ci
1133da0c48c4Sopenharmony_ci/* Lock if necessary before dup an archive.  */
1134da0c48c4Sopenharmony_cistatic inline Elf *
1135da0c48c4Sopenharmony_cilock_dup_elf (int fildes, Elf_Cmd cmd, Elf *ref)
1136da0c48c4Sopenharmony_ci{
1137da0c48c4Sopenharmony_ci  /* We need wrlock to dup an archive.  */
1138da0c48c4Sopenharmony_ci  if (ref->kind == ELF_K_AR)
1139da0c48c4Sopenharmony_ci    {
1140da0c48c4Sopenharmony_ci      rwlock_unlock (ref->lock);
1141da0c48c4Sopenharmony_ci      rwlock_wrlock (ref->lock);
1142da0c48c4Sopenharmony_ci    }
1143da0c48c4Sopenharmony_ci    /* Duplicate the descriptor.  */
1144da0c48c4Sopenharmony_ci  return dup_elf (fildes, cmd, ref);
1145da0c48c4Sopenharmony_ci}
1146da0c48c4Sopenharmony_ci
1147da0c48c4Sopenharmony_ci/* Return a descriptor for the file belonging to FILDES.  */
1148da0c48c4Sopenharmony_ciElf *
1149da0c48c4Sopenharmony_cielf_begin (int fildes, Elf_Cmd cmd, Elf *ref)
1150da0c48c4Sopenharmony_ci{
1151da0c48c4Sopenharmony_ci  Elf *retval;
1152da0c48c4Sopenharmony_ci
1153da0c48c4Sopenharmony_ci  if (unlikely (__libelf_version != EV_CURRENT))
1154da0c48c4Sopenharmony_ci    {
1155da0c48c4Sopenharmony_ci      /* Version wasn't set so far.  */
1156da0c48c4Sopenharmony_ci      __libelf_seterrno (ELF_E_NO_VERSION);
1157da0c48c4Sopenharmony_ci      return NULL;
1158da0c48c4Sopenharmony_ci    }
1159da0c48c4Sopenharmony_ci
1160da0c48c4Sopenharmony_ci  if (ref != NULL)
1161da0c48c4Sopenharmony_ci    /* Make sure the descriptor is not suddenly going away.  */
1162da0c48c4Sopenharmony_ci    rwlock_rdlock (ref->lock);
1163da0c48c4Sopenharmony_ci  else if (unlikely (fcntl (fildes, F_GETFD) == -1 && errno == EBADF))
1164da0c48c4Sopenharmony_ci    {
1165da0c48c4Sopenharmony_ci      /* We cannot do anything productive without a file descriptor.  */
1166da0c48c4Sopenharmony_ci      __libelf_seterrno (ELF_E_INVALID_FILE);
1167da0c48c4Sopenharmony_ci      return NULL;
1168da0c48c4Sopenharmony_ci    }
1169da0c48c4Sopenharmony_ci
1170da0c48c4Sopenharmony_ci  switch (cmd)
1171da0c48c4Sopenharmony_ci    {
1172da0c48c4Sopenharmony_ci    case ELF_C_NULL:
1173da0c48c4Sopenharmony_ci      /* We simply return a NULL pointer.  */
1174da0c48c4Sopenharmony_ci      retval = NULL;
1175da0c48c4Sopenharmony_ci      break;
1176da0c48c4Sopenharmony_ci
1177da0c48c4Sopenharmony_ci    case ELF_C_READ_MMAP_PRIVATE:
1178da0c48c4Sopenharmony_ci      /* If we have a reference it must also be opened this way.  */
1179da0c48c4Sopenharmony_ci      if (unlikely (ref != NULL && ref->cmd != ELF_C_READ_MMAP_PRIVATE))
1180da0c48c4Sopenharmony_ci	{
1181da0c48c4Sopenharmony_ci	  __libelf_seterrno (ELF_E_INVALID_CMD);
1182da0c48c4Sopenharmony_ci	  retval = NULL;
1183da0c48c4Sopenharmony_ci	  break;
1184da0c48c4Sopenharmony_ci	}
1185da0c48c4Sopenharmony_ci      FALLTHROUGH;
1186da0c48c4Sopenharmony_ci
1187da0c48c4Sopenharmony_ci    case ELF_C_READ:
1188da0c48c4Sopenharmony_ci    case ELF_C_READ_MMAP:
1189da0c48c4Sopenharmony_ci      if (ref != NULL)
1190da0c48c4Sopenharmony_ci	retval = lock_dup_elf (fildes, cmd, ref);
1191da0c48c4Sopenharmony_ci      else
1192da0c48c4Sopenharmony_ci	/* Create descriptor for existing file.  */
1193da0c48c4Sopenharmony_ci	retval = read_file (fildes, 0, ~((size_t) 0), cmd, NULL);
1194da0c48c4Sopenharmony_ci      break;
1195da0c48c4Sopenharmony_ci
1196da0c48c4Sopenharmony_ci    case ELF_C_RDWR:
1197da0c48c4Sopenharmony_ci    case ELF_C_RDWR_MMAP:
1198da0c48c4Sopenharmony_ci      /* If we have a REF object it must also be opened using this
1199da0c48c4Sopenharmony_ci	 command.  */
1200da0c48c4Sopenharmony_ci      if (ref != NULL)
1201da0c48c4Sopenharmony_ci	{
1202da0c48c4Sopenharmony_ci	  if (unlikely (ref->cmd != ELF_C_RDWR && ref->cmd != ELF_C_RDWR_MMAP
1203da0c48c4Sopenharmony_ci			&& ref->cmd != ELF_C_WRITE
1204da0c48c4Sopenharmony_ci			&& ref->cmd != ELF_C_WRITE_MMAP))
1205da0c48c4Sopenharmony_ci	    {
1206da0c48c4Sopenharmony_ci	      /* This is not ok.  REF must also be opened for writing.  */
1207da0c48c4Sopenharmony_ci	      __libelf_seterrno (ELF_E_INVALID_CMD);
1208da0c48c4Sopenharmony_ci	      retval = NULL;
1209da0c48c4Sopenharmony_ci	    }
1210da0c48c4Sopenharmony_ci	  else
1211da0c48c4Sopenharmony_ci	    retval = lock_dup_elf (fildes, cmd, ref);
1212da0c48c4Sopenharmony_ci	}
1213da0c48c4Sopenharmony_ci      else
1214da0c48c4Sopenharmony_ci	/* Create descriptor for existing file.  */
1215da0c48c4Sopenharmony_ci	retval = read_file (fildes, 0, ~((size_t) 0), cmd, NULL);
1216da0c48c4Sopenharmony_ci      break;
1217da0c48c4Sopenharmony_ci
1218da0c48c4Sopenharmony_ci    case ELF_C_WRITE:
1219da0c48c4Sopenharmony_ci    case ELF_C_WRITE_MMAP:
1220da0c48c4Sopenharmony_ci      /* We ignore REF and prepare a descriptor to write a new file.  */
1221da0c48c4Sopenharmony_ci      retval = write_file (fildes, cmd);
1222da0c48c4Sopenharmony_ci      break;
1223da0c48c4Sopenharmony_ci
1224da0c48c4Sopenharmony_ci    default:
1225da0c48c4Sopenharmony_ci      __libelf_seterrno (ELF_E_INVALID_CMD);
1226da0c48c4Sopenharmony_ci      retval = NULL;
1227da0c48c4Sopenharmony_ci      break;
1228da0c48c4Sopenharmony_ci    }
1229da0c48c4Sopenharmony_ci
1230da0c48c4Sopenharmony_ci  /* Release the lock.  */
1231da0c48c4Sopenharmony_ci  if (ref != NULL)
1232da0c48c4Sopenharmony_ci    rwlock_unlock (ref->lock);
1233da0c48c4Sopenharmony_ci
1234da0c48c4Sopenharmony_ci  return retval;
1235da0c48c4Sopenharmony_ci}
1236da0c48c4Sopenharmony_ciINTDEF(elf_begin)
1237