1441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project/* Create descriptor for processing file.
2cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   Copyright (C) 1998-2005, 2006, 2007, 2008 Red Hat, Inc.
3cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   This file is part of Red Hat elfutils.
4441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project   Written by Ulrich Drepper <drepper@redhat.com>, 1998.
5441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
6cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   Red Hat elfutils is free software; you can redistribute it and/or modify
7cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   it under the terms of the GNU General Public License as published by the
8cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   Free Software Foundation; version 2 of the License.
9cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
10cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   Red Hat elfutils is distributed in the hope that it will be useful, but
11cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   WITHOUT ANY WARRANTY; without even the implied warranty of
12cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   General Public License for more details.
14cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
15cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   You should have received a copy of the GNU General Public License along
16cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   with Red Hat elfutils; if not, write to the Free Software Foundation,
17cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
18cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
19cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   In addition, as a special exception, Red Hat, Inc. gives You the
20cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   additional right to link the code of Red Hat elfutils with code licensed
21cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   under any Open Source Initiative certified open source license
22cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   (http://www.opensource.org/licenses/index.php) which requires the
23cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   distribution of source code with any binary distribution and to
24cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   distribute linked combinations of the two.  Non-GPL Code permitted under
25cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   this exception must only link to the code of Red Hat elfutils through
26cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   those well defined interfaces identified in the file named EXCEPTION
27cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   found in the source code files (the "Approved Interfaces").  The files
28cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   of Non-GPL Code may instantiate templates or use macros or inline
29cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   functions from the Approved Interfaces without causing the resulting
30cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   work to be covered by the GNU General Public License.  Only Red Hat,
31cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   Inc. may make changes or additions to the list of Approved Interfaces.
32cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   Red Hat's grant of this exception is conditioned upon your not adding
33cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   any new exceptions.  If you wish to add a new Approved Interface or
34cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   exception, please contact Red Hat.  You must obey the GNU General Public
35cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   License in all respects for all of the Red Hat elfutils code and other
36cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   code used in conjunction with Red Hat elfutils except the Non-GPL Code
37cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   covered by this exception.  If you modify this file, you may extend this
38cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   exception to your version of the file, but you are not obligated to do
39cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   so.  If you do not wish to provide this exception without modification,
40cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   you must delete this exception statement from your version and license
41cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   this file solely under the GPL without exception.
42cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
43cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   Red Hat elfutils is an included package of the Open Invention Network.
44cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   An included package of the Open Invention Network is a package for which
45cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   Open Invention Network licensees cross-license their patents.  No patent
46cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   license is granted, either expressly or impliedly, by designation as an
47cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   included package.  Should you wish to participate in the Open Invention
48cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   Network licensing program, please visit www.openinventionnetwork.com
49cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng   <http://www.openinventionnetwork.com>.  */
50441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
51441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project#ifdef HAVE_CONFIG_H
52441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project# include <config.h>
53441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project#endif
54441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
55441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project#include <assert.h>
56441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project#include <ctype.h>
57441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project#include <errno.h>
58441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project#include <fcntl.h>
59441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project#include <stdbool.h>
60441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project#include <stddef.h>
61441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project#include <string.h>
62441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project#include <unistd.h>
63441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project#include <sys/mman.h>
64441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project#include <sys/param.h>
65441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project#include <sys/stat.h>
66441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
67cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#include <system.h>
68441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project#include "libelfP.h"
69441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project#include "common.h"
70441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
71441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project/* Create descriptor for archive in memory.  */
72441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectstatic inline Elf *
73441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectfile_read_ar (int fildes, void *map_address, off_t offset, size_t maxsize,
74441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      Elf_Cmd cmd, Elf *parent)
75441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project{
76441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  Elf *elf;
77441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
78441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  /* Create a descriptor.  */
79441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  elf = allocate_elf (fildes, map_address, offset, maxsize, cmd, parent,
80441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project                      ELF_K_AR, 0);
81441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  if (elf != NULL)
82441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    {
83441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      /* We don't read all the symbol tables in advance.  All this will
84441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	 happen on demand.  */
85441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      elf->state.ar.offset = offset + SARMAG;
86441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
87441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      elf->state.ar.elf_ar_hdr.ar_rawname = elf->state.ar.raw_name;
88441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    }
89441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
90441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  return elf;
91441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project}
92441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
93441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
94441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectstatic size_t
95441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectget_shnum (void *map_address, unsigned char *e_ident, int fildes, off_t offset,
96441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	   size_t maxsize)
97441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project{
98441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  size_t result;
99441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  union
100441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  {
101441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    Elf32_Ehdr *e32;
102441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    Elf64_Ehdr *e64;
103441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    void *p;
104441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  } ehdr;
105cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  union
106cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  {
107cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    Elf32_Ehdr e32;
108cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    Elf64_Ehdr e64;
109cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  } ehdr_mem;
110441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  bool is32 = e_ident[EI_CLASS] == ELFCLASS32;
111441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
112441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  /* Make the ELF header available.  */
113cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (e_ident[EI_DATA] == MY_ELFDATA
114441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      && (ALLOW_UNALIGNED
115cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  || (((size_t) e_ident
116cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       & ((is32 ? __alignof__ (Elf32_Ehdr) : __alignof__ (Elf64_Ehdr))
117cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  - 1)) == 0)))
118cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    ehdr.p = e_ident;
119441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  else
120441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    {
121cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      /* We already read the ELF header.  We have to copy the header
122cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	 since we possibly modify the data here and the caller
123cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	 expects the memory it passes in to be preserved.  */
124cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      ehdr.p = &ehdr_mem;
125441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
126cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (is32)
127cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
128cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if (ALLOW_UNALIGNED)
129cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    {
130cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      ehdr_mem.e32.e_shnum = ((Elf32_Ehdr *) e_ident)->e_shnum;
131cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      ehdr_mem.e32.e_shoff = ((Elf32_Ehdr *) e_ident)->e_shoff;
132cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    }
133cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  else
134cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    memcpy (&ehdr_mem, e_ident, sizeof (Elf32_Ehdr));
135441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
136cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if (e_ident[EI_DATA] != MY_ELFDATA)
137cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    {
138cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      CONVERT (ehdr_mem.e32.e_shnum);
139cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      CONVERT (ehdr_mem.e32.e_shoff);
140cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    }
141cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}
142cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      else
143441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	{
144cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if (ALLOW_UNALIGNED)
145441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    {
146cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      ehdr_mem.e64.e_shnum = ((Elf64_Ehdr *) e_ident)->e_shnum;
147cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      ehdr_mem.e64.e_shoff = ((Elf64_Ehdr *) e_ident)->e_shoff;
148441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    }
149441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  else
150cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    memcpy (&ehdr_mem, e_ident, sizeof (Elf64_Ehdr));
151cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
152cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if (e_ident[EI_DATA] != MY_ELFDATA)
153441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    {
154cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      CONVERT (ehdr_mem.e64.e_shnum);
155cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      CONVERT (ehdr_mem.e64.e_shoff);
156441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    }
157441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	}
158441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    }
159441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
160441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  if (is32)
161441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    {
162441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      /* Get the number of sections from the ELF header.  */
163441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      result = ehdr.e32->e_shnum;
164441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
165441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      if (unlikely (result == 0) && ehdr.e32->e_shoff != 0)
166441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	{
167cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if (ehdr.e32->e_shoff + sizeof (Elf32_Shdr) > maxsize)
168441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    /* Cannot read the first section header.  */
169cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    return 0;
170441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
171441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  if (likely (map_address != NULL) && e_ident[EI_DATA] == MY_ELFDATA
172441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      && (ALLOW_UNALIGNED
173441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		  || (((size_t) ((char *) map_address + offset))
174441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		      & (__alignof__ (Elf32_Ehdr) - 1)) == 0))
175441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    /* We can directly access the memory.  */
176cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    result = ((Elf32_Shdr *) ((char *) map_address + ehdr.e32->e_shoff
177441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project				      + offset))->sh_size;
178441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  else
179441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    {
180441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      Elf32_Word size;
181441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
182cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      if (likely (map_address != NULL))
183cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		/* gcc will optimize the memcpy to a simple memory
184cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		   access while taking care of alignment issues.  */
185cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		memcpy (&size, &((Elf32_Shdr *) ((char *) map_address
186cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng						 + ehdr.e32->e_shoff
187cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng						 + offset))->sh_size,
188cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			sizeof (Elf32_Word));
189cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      else
190cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		if (unlikely (pread_retry (fildes, &size, sizeof (Elf32_Word),
191cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng					   offset + ehdr.e32->e_shoff
192cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng					   + offsetof (Elf32_Shdr, sh_size))
193cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			      != sizeof (Elf32_Word)))
194cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  return (size_t) -1l;
195441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
196441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      if (e_ident[EI_DATA] != MY_ELFDATA)
197441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		CONVERT (size);
198441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
199441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      result = size;
200441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    }
201441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	}
202cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
203cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      /* If the section headers were truncated, pretend none were there.  */
204cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (ehdr.e32->e_shoff > maxsize
205cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  || maxsize - ehdr.e32->e_shoff < sizeof (Elf32_Shdr) * result)
206cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	result = 0;
207441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    }
208441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  else
209441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    {
210441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      /* Get the number of sections from the ELF header.  */
211441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      result = ehdr.e64->e_shnum;
212441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
213441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      if (unlikely (result == 0) && ehdr.e64->e_shoff != 0)
214441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	{
215cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if (ehdr.e64->e_shoff + sizeof (Elf64_Shdr) > maxsize)
216441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    /* Cannot read the first section header.  */
217cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    return 0;
218441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
219cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  Elf64_Xword size;
220441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  if (likely (map_address != NULL) && e_ident[EI_DATA] == MY_ELFDATA
221441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      && (ALLOW_UNALIGNED
222441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		  || (((size_t) ((char *) map_address + offset))
223441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		      & (__alignof__ (Elf64_Ehdr) - 1)) == 0))
224441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    /* We can directly access the memory.  */
225cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    size = ((Elf64_Shdr *) ((char *) map_address + ehdr.e64->e_shoff
226cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				    + offset))->sh_size;
227441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  else
228441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    {
229cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      if (likely (map_address != NULL))
230cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		/* gcc will optimize the memcpy to a simple memory
231cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		   access while taking care of alignment issues.  */
232cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		memcpy (&size, &((Elf64_Shdr *) ((char *) map_address
233cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng						 + ehdr.e64->e_shoff
234cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng						 + offset))->sh_size,
235cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			sizeof (Elf64_Xword));
236cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      else
237cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		if (unlikely (pread_retry (fildes, &size, sizeof (Elf64_Word),
238cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng					   offset + ehdr.e64->e_shoff
239cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng					   + offsetof (Elf64_Shdr, sh_size))
240cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			      != sizeof (Elf64_Xword)))
241cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  return (size_t) -1l;
242441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
243441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      if (e_ident[EI_DATA] != MY_ELFDATA)
244441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		CONVERT (size);
245441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    }
246cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
247cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if (size > ~((GElf_Word) 0))
248cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    /* Invalid value, it is too large.  */
249cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    return (size_t) -1l;
250cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
251cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  result = size;
252441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	}
253cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
254cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      /* If the section headers were truncated, pretend none were there.  */
255cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (ehdr.e64->e_shoff > maxsize
256cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  || maxsize - ehdr.e64->e_shoff < sizeof (Elf64_Shdr) * result)
257cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	result = 0;
258441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    }
259441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
260441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  return result;
261441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project}
262441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
263441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
264441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project/* Create descriptor for ELF file in memory.  */
265441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectstatic Elf *
266cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengfile_read_elf (int fildes, void *map_address, unsigned char *e_ident,
267cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	       off_t offset, size_t maxsize, Elf_Cmd cmd, Elf *parent)
268441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project{
269441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  /* Verify the binary is of the class we can handle.  */
270cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (unlikely ((e_ident[EI_CLASS] != ELFCLASS32
271cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		 && e_ident[EI_CLASS] != ELFCLASS64)
272cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		/* We also can only handle two encodings.  */
273cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		|| (e_ident[EI_DATA] != ELFDATA2LSB
274cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		    && e_ident[EI_DATA] != ELFDATA2MSB)))
275441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    {
276441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      /* Cannot handle this.  */
277441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      __libelf_seterrno (ELF_E_INVALID_FILE);
278441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      return NULL;
279441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    }
280441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
281441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  /* Determine the number of sections.  */
282cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  size_t scncnt = get_shnum (map_address, e_ident, fildes, offset, maxsize);
283441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  if (scncnt == (size_t) -1l)
284441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    /* Could not determine the number of sections.  */
285441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    return NULL;
286441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
287441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  /* We can now allocate the memory.  */
288cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Elf *elf = allocate_elf (fildes, map_address, offset, maxsize, cmd, parent,
289cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			   ELF_K_ELF, scncnt * sizeof (Elf_Scn));
290441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  if (elf == NULL)
291441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    /* Not enough memory.  */
292441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    return NULL;
293441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
294441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  /* Some more or less arbitrary value.  */
295441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  elf->state.elf.scnincr = 10;
296441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
297cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  /* Make the class easily available.  */
298cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  elf->class = e_ident[EI_CLASS];
299cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
300441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  if (e_ident[EI_CLASS] == ELFCLASS32)
301441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    {
302441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      /* This pointer might not be directly usable if the alignment is
303441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	 not sufficient for the architecture.  */
304441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      Elf32_Ehdr *ehdr = (Elf32_Ehdr *) ((char *) map_address + offset);
305441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
306441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      assert ((unsigned int) scncnt == scncnt);
307441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      elf->state.elf32.scns.cnt = elf->state.elf32.scns.max = scncnt;
308441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
309441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      /* This is a 32-bit binary.  */
310441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      if (map_address != NULL && e_ident[EI_DATA] == MY_ELFDATA
311441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  && (ALLOW_UNALIGNED
312441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      || ((((uintptr_t) ehdr) & (__alignof__ (Elf32_Ehdr) - 1)) == 0
313441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		  && ((uintptr_t) ((char *) ehdr + ehdr->e_shoff)
314441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		      & (__alignof__ (Elf32_Shdr) - 1)) == 0
315441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		  && ((uintptr_t) ((char *) ehdr + ehdr->e_phoff)
316441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		      & (__alignof__ (Elf32_Phdr) - 1)) == 0)))
317441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	{
318441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  /* We can use the mmapped memory.  */
319cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  elf->state.elf32.ehdr = ehdr;
320cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  elf->state.elf32.shdr
321cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    = (Elf32_Shdr *) ((char *) ehdr + ehdr->e_shoff);
322cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if (ehdr->e_phnum > 0)
323441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    /* Assign a value only if there really is a program
324441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	       header.  Otherwise the value remains NULL.  */
325441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    elf->state.elf32.phdr
326cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      = (Elf32_Phdr *) ((char *) ehdr + ehdr->e_phoff);
327441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
328cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  for (size_t cnt = 0; cnt < scncnt; ++cnt)
329441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    {
330441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      elf->state.elf32.scns.data[cnt].index = cnt;
331441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      elf->state.elf32.scns.data[cnt].elf = elf;
332441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      elf->state.elf32.scns.data[cnt].shdr.e32 =
333441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		&elf->state.elf32.shdr[cnt];
334441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      elf->state.elf32.scns.data[cnt].rawdata_base =
335441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		elf->state.elf32.scns.data[cnt].data_base =
336441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		((char *) map_address + offset
337441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		 + elf->state.elf32.shdr[cnt].sh_offset);
338441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      elf->state.elf32.scns.data[cnt].list = &elf->state.elf32.scns;
339cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
340cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      /* If this is a section with an extended index add a
341cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		 reference in the section which uses the extended
342cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		 index.  */
343cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      if (elf->state.elf32.shdr[cnt].sh_type == SHT_SYMTAB_SHNDX
344cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  && elf->state.elf32.shdr[cnt].sh_link < scncnt)
345cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		elf->state.elf32.scns.data[elf->state.elf32.shdr[cnt].sh_link].shndx_index
346cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  = cnt;
347cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
348cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      /* Set the own shndx_index field in case it has not yet
349cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		 been set.  */
350cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      if (elf->state.elf32.scns.data[cnt].shndx_index == 0)
351cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		elf->state.elf32.scns.data[cnt].shndx_index = -1;
352441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    }
353441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	}
354441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      else
355441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	{
356cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  /* Copy the ELF header.  */
357cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  elf->state.elf32.ehdr = memcpy (&elf->state.elf32.ehdr_mem, e_ident,
358cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng					  sizeof (Elf32_Ehdr));
359441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
360441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  if (e_ident[EI_DATA] != MY_ELFDATA)
361441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    {
362441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      CONVERT (elf->state.elf32.ehdr_mem.e_type);
363441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      CONVERT (elf->state.elf32.ehdr_mem.e_machine);
364441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      CONVERT (elf->state.elf32.ehdr_mem.e_version);
365441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      CONVERT (elf->state.elf32.ehdr_mem.e_entry);
366441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      CONVERT (elf->state.elf32.ehdr_mem.e_phoff);
367441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      CONVERT (elf->state.elf32.ehdr_mem.e_shoff);
368441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      CONVERT (elf->state.elf32.ehdr_mem.e_flags);
369441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      CONVERT (elf->state.elf32.ehdr_mem.e_ehsize);
370441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      CONVERT (elf->state.elf32.ehdr_mem.e_phentsize);
371441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      CONVERT (elf->state.elf32.ehdr_mem.e_phnum);
372441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      CONVERT (elf->state.elf32.ehdr_mem.e_shentsize);
373441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      CONVERT (elf->state.elf32.ehdr_mem.e_shnum);
374441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      CONVERT (elf->state.elf32.ehdr_mem.e_shstrndx);
375441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    }
376441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
377cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  for (size_t cnt = 0; cnt < scncnt; ++cnt)
378441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    {
379441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      elf->state.elf32.scns.data[cnt].index = cnt;
380441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      elf->state.elf32.scns.data[cnt].elf = elf;
381441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      elf->state.elf32.scns.data[cnt].list = &elf->state.elf32.scns;
382441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    }
383441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	}
384441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
385441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      /* So far only one block with sections.  */
386441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      elf->state.elf32.scns_last = &elf->state.elf32.scns;
387441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    }
388441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  else
389441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    {
390441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      /* This pointer might not be directly usable if the alignment is
391441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	 not sufficient for the architecture.  */
392441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      Elf64_Ehdr *ehdr = (Elf64_Ehdr *) ((char *) map_address + offset);
393441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
394441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      assert ((unsigned int) scncnt == scncnt);
395441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      elf->state.elf64.scns.cnt = elf->state.elf64.scns.max = scncnt;
396441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
397441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      /* This is a 64-bit binary.  */
398441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      if (map_address != NULL && e_ident[EI_DATA] == MY_ELFDATA
399441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  && (ALLOW_UNALIGNED
400441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      || ((((uintptr_t) ehdr) & (__alignof__ (Elf64_Ehdr) - 1)) == 0
401441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		  && ((uintptr_t) ((char *) ehdr + ehdr->e_shoff)
402441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		      & (__alignof__ (Elf64_Shdr) - 1)) == 0
403441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		  && ((uintptr_t) ((char *) ehdr + ehdr->e_phoff)
404441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		      & (__alignof__ (Elf64_Phdr) - 1)) == 0)))
405441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	{
406441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  /* We can use the mmapped memory.  */
407cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  elf->state.elf64.ehdr = ehdr;
408cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  elf->state.elf64.shdr
409cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    = (Elf64_Shdr *) ((char *) ehdr + ehdr->e_shoff);
410cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if (ehdr->e_phnum > 0)
411441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    /* Assign a value only if there really is a program
412441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	       header.  Otherwise the value remains NULL.  */
413441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    elf->state.elf64.phdr
414cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      = (Elf64_Phdr *) ((char *) ehdr + ehdr->e_phoff);
415441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
416cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  for (size_t cnt = 0; cnt < scncnt; ++cnt)
417441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    {
418441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      elf->state.elf64.scns.data[cnt].index = cnt;
419441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      elf->state.elf64.scns.data[cnt].elf = elf;
420441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      elf->state.elf64.scns.data[cnt].shdr.e64 =
421441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		&elf->state.elf64.shdr[cnt];
422441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      elf->state.elf64.scns.data[cnt].rawdata_base =
423441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		elf->state.elf64.scns.data[cnt].data_base =
424441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		((char *) map_address + offset
425441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		 + elf->state.elf64.shdr[cnt].sh_offset);
426441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      elf->state.elf64.scns.data[cnt].list = &elf->state.elf64.scns;
427cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
428cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      /* If this is a section with an extended index add a
429cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		 reference in the section which uses the extended
430cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		 index.  */
431cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      if (elf->state.elf64.shdr[cnt].sh_type == SHT_SYMTAB_SHNDX
432cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  && elf->state.elf64.shdr[cnt].sh_link < scncnt)
433cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		elf->state.elf64.scns.data[elf->state.elf64.shdr[cnt].sh_link].shndx_index
434cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		  = cnt;
435cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
436cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      /* Set the own shndx_index field in case it has not yet
437cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		 been set.  */
438cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	      if (elf->state.elf64.scns.data[cnt].shndx_index == 0)
439cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		elf->state.elf64.scns.data[cnt].shndx_index = -1;
440441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    }
441441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	}
442441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      else
443441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	{
444cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  /* Copy the ELF header.  */
445cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  elf->state.elf64.ehdr = memcpy (&elf->state.elf64.ehdr_mem, e_ident,
446cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng					  sizeof (Elf64_Ehdr));
447441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
448441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  if (e_ident[EI_DATA] != MY_ELFDATA)
449441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    {
450441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      CONVERT (elf->state.elf64.ehdr_mem.e_type);
451441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      CONVERT (elf->state.elf64.ehdr_mem.e_machine);
452441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      CONVERT (elf->state.elf64.ehdr_mem.e_version);
453441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      CONVERT (elf->state.elf64.ehdr_mem.e_entry);
454441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      CONVERT (elf->state.elf64.ehdr_mem.e_phoff);
455441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      CONVERT (elf->state.elf64.ehdr_mem.e_shoff);
456441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      CONVERT (elf->state.elf64.ehdr_mem.e_flags);
457441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      CONVERT (elf->state.elf64.ehdr_mem.e_ehsize);
458441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      CONVERT (elf->state.elf64.ehdr_mem.e_phentsize);
459441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      CONVERT (elf->state.elf64.ehdr_mem.e_phnum);
460441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      CONVERT (elf->state.elf64.ehdr_mem.e_shentsize);
461441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      CONVERT (elf->state.elf64.ehdr_mem.e_shnum);
462441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      CONVERT (elf->state.elf64.ehdr_mem.e_shstrndx);
463441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    }
464441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
465cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  for (size_t cnt = 0; cnt < scncnt; ++cnt)
466441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    {
467441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      elf->state.elf64.scns.data[cnt].index = cnt;
468441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      elf->state.elf64.scns.data[cnt].elf = elf;
469441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      elf->state.elf64.scns.data[cnt].list = &elf->state.elf64.scns;
470441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    }
471441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	}
472441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
473441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      /* So far only one block with sections.  */
474441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      elf->state.elf64.scns_last = &elf->state.elf64.scns;
475441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    }
476441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
477441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  return elf;
478441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project}
479441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
480441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
481441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source ProjectElf *
482cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chenginternal_function
483441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project__libelf_read_mmaped_file (int fildes, void *map_address,  off_t offset,
484441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project			   size_t maxsize, Elf_Cmd cmd, Elf *parent)
485441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project{
486441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  /* We have to find out what kind of file this is.  We handle ELF
487441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project     files and archives.  To find out what we have we must look at the
488441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project     header.  The header for an ELF file is EI_NIDENT bytes in size,
489441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project     the header for an archive file SARMAG bytes long.  */
490cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  unsigned char *e_ident = (unsigned char *) map_address + offset;
491441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
492441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  /* See what kind of object we have here.  */
493cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Elf_Kind kind = determine_kind (e_ident, maxsize);
494441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
495441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  switch (kind)
496441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    {
497441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    case ELF_K_ELF:
498cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      return file_read_elf (fildes, map_address, e_ident, offset, maxsize,
499cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			    cmd, parent);
500441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
501441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    case ELF_K_AR:
502441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      return file_read_ar (fildes, map_address, offset, maxsize, cmd, parent);
503441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
504441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    default:
505441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      break;
506441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    }
507441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
508441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  /* This case is easy.  Since we cannot do anything with this file
509441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project     create a dummy descriptor.  */
510441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  return allocate_elf (fildes, map_address, offset, maxsize, cmd, parent,
511441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		       ELF_K_NONE, 0);
512441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project}
513441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
514441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
515441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectstatic Elf *
516441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectread_unmmaped_file (int fildes, off_t offset, size_t maxsize, Elf_Cmd cmd,
517441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		    Elf *parent)
518441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project{
519441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  /* We have to find out what kind of file this is.  We handle ELF
520441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project     files and archives.  To find out what we have we must read the
521cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng     header.  The identification header for an ELF file is EI_NIDENT
522cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng     bytes in size, but we read the whole ELF header since we will
523cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng     need it anyway later.  For archives the header in SARMAG bytes
524cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng     long.  Read the maximum of these numbers.
525441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
526cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng     XXX We have to change this for the extended `ar' format some day.
527cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
528cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng     Use a union to ensure alignment.  We might later access the
529cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng     memory as a ElfXX_Ehdr.  */
530cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  union
531cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  {
532cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    Elf64_Ehdr ehdr;
533cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    unsigned char header[MAX (sizeof (Elf64_Ehdr), SARMAG)];
534cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  } mem;
535441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
536441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  /* Read the head of the file.  */
537cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  ssize_t nread = pread_retry (fildes, mem.header,
538cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			       MIN (MAX (sizeof (Elf64_Ehdr), SARMAG),
539cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				    maxsize),
540cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			       offset);
541cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (unlikely (nread == -1))
542441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    /* We cannot even read the head of the file.  Maybe FILDES is associated
543441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project       with an unseekable device.  This is nothing we can handle.  */
544441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    return NULL;
545441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
546441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  /* See what kind of object we have here.  */
547cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Elf_Kind kind = determine_kind (mem.header, nread);
548441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
549441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  switch (kind)
550441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    {
551441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    case ELF_K_AR:
552441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      return file_read_ar (fildes, NULL, offset, maxsize, cmd, parent);
553441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
554441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    case ELF_K_ELF:
555441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      /* Make sure at least the ELF header is contained in the file.  */
556cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if ((size_t) nread >= (mem.header[EI_CLASS] == ELFCLASS32
557cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			     ? sizeof (Elf32_Ehdr) : sizeof (Elf64_Ehdr)))
558cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	return file_read_elf (fildes, NULL, mem.header, offset, maxsize, cmd,
559cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			      parent);
560441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      /* FALLTHROUGH */
561441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
562441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    default:
563441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      break;
564441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    }
565441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
566441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  /* This case is easy.  Since we cannot do anything with this file
567441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project     create a dummy descriptor.  */
568441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  return allocate_elf (fildes, NULL, offset, maxsize, cmd, parent,
569441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		       ELF_K_NONE, 0);
570441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project}
571441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
572441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
573441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project/* Open a file for reading.  If possible we will try to mmap() the file.  */
574441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectstatic struct Elf *
575441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectread_file (int fildes, off_t offset, size_t maxsize,
576441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	   Elf_Cmd cmd, Elf *parent)
577441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project{
578441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  void *map_address = NULL;
579441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  int use_mmap = (cmd == ELF_C_READ_MMAP || cmd == ELF_C_RDWR_MMAP
580441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		  || cmd == ELF_C_WRITE_MMAP
581441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		  || cmd == ELF_C_READ_MMAP_PRIVATE);
582441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
583cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#if _MUDFLAP
584cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  /* Mudflap doesn't grok that our mmap'd data is ok.  */
585cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  use_mmap = 0;
586cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#endif
587cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
588441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  if (use_mmap)
589441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    {
590441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      if (parent == NULL)
591441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	{
592441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  if (maxsize == ~((size_t) 0))
593441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    {
594441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      /* We don't know in the moment how large the file is.
595441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		 Determine it now.  */
596441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      struct stat st;
597441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
598441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      if (fstat (fildes, &st) == 0
599441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		  && (sizeof (size_t) >= sizeof (st.st_size)
600441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		      || st.st_size <= ~((size_t) 0)))
601441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		maxsize = (size_t) st.st_size;
602441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    }
603441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
604441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  /* We try to map the file ourself.  */
605441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  map_address = mmap (NULL, maxsize, (cmd == ELF_C_READ_MMAP
606441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project					      ? PROT_READ
607441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project					      : PROT_READ|PROT_WRITE),
608441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project			      cmd == ELF_C_READ_MMAP_PRIVATE
609cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			      || cmd == ELF_C_READ_MMAP
610441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project			      ? MAP_PRIVATE : MAP_SHARED,
611441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project			      fildes, offset);
612441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
613441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  if (map_address == MAP_FAILED)
614441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    map_address = NULL;
615441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	}
616441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      else
617441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	{
618441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  /* The parent is already loaded.  Use it.  */
619441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  assert (maxsize != ~((size_t) 0));
620441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
621441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  map_address = parent->map_address;
622441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	}
623441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    }
624441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
625441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  /* If we have the file in memory optimize the access.  */
626441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  if (map_address != NULL)
627441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    {
628cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      assert (map_address != MAP_FAILED);
629441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
630cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      struct Elf *result = __libelf_read_mmaped_file (fildes, map_address,
631cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng						      offset, maxsize, cmd,
632cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng						      parent);
633441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
634441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      /* If something went wrong during the initialization unmap the
635441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	 memory if we mmaped here.  */
636441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      if (result == NULL
637441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  && (parent == NULL
638441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      || parent->map_address != map_address))
639441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	munmap (map_address, maxsize);
640441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      else if (parent == NULL)
641441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	/* Remember that we mmap()ed the memory.  */
642441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	result->flags |= ELF_F_MMAPPED;
643441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
644441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      return result;
645441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    }
646441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
647441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  /* Otherwise we have to do it the hard way.  We read as much as necessary
648441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project     from the file whenever we need information which is not available.  */
649441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  return read_unmmaped_file (fildes, offset, maxsize, cmd, parent);
650441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project}
651441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
652441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
653441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project/* Find the entry with the long names for the content of this archive.  */
654441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectstatic const char *
655441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectread_long_names (Elf *elf)
656441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project{
657441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  off_t offset = SARMAG;	/* This is the first entry.  */
658441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  struct ar_hdr hdrm;
659441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  struct ar_hdr *hdr;
660441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  char *newp;
661441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  size_t len;
662441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
663441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  while (1)
664441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    {
665441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      if (elf->map_address != NULL)
666441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	{
667441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  if (offset + sizeof (struct ar_hdr) > elf->maximum_size)
668441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    return NULL;
669441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
670441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  /* The data is mapped.  */
671441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  hdr = (struct ar_hdr *) (elf->map_address + offset);
672441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	}
673441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      else
674441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	{
675441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  /* Read the header from the file.  */
676cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if (unlikely (pread_retry (elf->fildes, &hdrm, sizeof (hdrm),
677cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				     elf->start_offset + offset)
678cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			!= sizeof (hdrm)))
679441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    return NULL;
680441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
681441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  hdr = &hdrm;
682441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	}
683441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
684441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      len = atol (hdr->ar_size);
685441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
686441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      if (memcmp (hdr->ar_name, "//              ", 16) == 0)
687441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	break;
688441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
689441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      offset += sizeof (struct ar_hdr) + ((len + 1) & ~1l);
690441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    }
691441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
692441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  /* Due to the stupid format of the long name table entry (which are not
693441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project     NUL terminted) we have to provide an appropriate representation anyhow.
694441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project     Therefore we always make a copy which has the appropriate form.  */
695441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  newp = (char *) malloc (len);
696441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  if (newp != NULL)
697441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    {
698441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      char *runp;
699441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
700441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      if (elf->map_address != NULL)
701441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	/* Simply copy it over.  */
702441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	elf->state.ar.long_names = (char *) memcpy (newp,
703441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project						    elf->map_address + offset
704441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project						    + sizeof (struct ar_hdr),
705441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project						    len);
706441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      else
707441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	{
708cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if (unlikely ((size_t) pread_retry (elf->fildes, newp, len,
709cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng					      elf->start_offset + offset
710cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng					      + sizeof (struct ar_hdr))
711cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			!= len))
712441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    {
713441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      /* We were not able to read all data.  */
714441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      free (newp);
715441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      elf->state.ar.long_names = NULL;
716441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      return NULL;
717441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    }
718441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  elf->state.ar.long_names = newp;
719441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	}
720441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
721441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      elf->state.ar.long_names_len = len;
722441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
723441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      /* Now NUL-terminate the strings.  */
724441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      runp = newp;
725441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      while (1)
726441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project        {
727441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  runp = (char *) memchr (runp, '/', newp + len - runp);
728441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  if (runp == NULL)
729441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    /* This was the last entry.  */
730441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    break;
731441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
732441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  /* NUL-terminate the string.  */
733441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  *runp = '\0';
734441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
735cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  /* Skip the NUL byte and the \012.  */
736441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  runp += 2;
737441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
738441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  /* A sanity check.  Somebody might have generated invalid
739441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	     archive.  */
740441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  if (runp >= newp + len)
741441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    break;
742441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	}
743441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    }
744441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
745441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  return newp;
746441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project}
747441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
748441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
749441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project/* Read the next archive header.  */
750441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectint
751cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chenginternal_function
752cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng__libelf_next_arhdr_wrlock (elf)
753441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project     Elf *elf;
754441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project{
755441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  struct ar_hdr *ar_hdr;
756441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  Elf_Arhdr *elf_ar_hdr;
757441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
758441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  if (elf->map_address != NULL)
759441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    {
760441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      /* See whether this entry is in the file.  */
761cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (unlikely (elf->state.ar.offset + sizeof (struct ar_hdr)
762cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		    > elf->start_offset + elf->maximum_size))
763441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	{
764441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  /* This record is not anymore in the file.  */
765441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  __libelf_seterrno (ELF_E_RANGE);
766441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  return -1;
767441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	}
768441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      ar_hdr = (struct ar_hdr *) (elf->map_address + elf->state.ar.offset);
769441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    }
770441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  else
771441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    {
772441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      ar_hdr = &elf->state.ar.ar_hdr;
773441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
774cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (unlikely (pread_retry (elf->fildes, ar_hdr, sizeof (struct ar_hdr),
775cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng				 elf->state.ar.offset)
776cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		    != sizeof (struct ar_hdr)))
777441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	{
778441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  /* Something went wrong while reading the file.  */
779441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  __libelf_seterrno (ELF_E_RANGE);
780441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  return -1;
781441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	}
782441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    }
783441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
784441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  /* One little consistency check.  */
785cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (unlikely (memcmp (ar_hdr->ar_fmag, ARFMAG, 2) != 0))
786441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    {
787441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      /* This is no valid archive.  */
788441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      __libelf_seterrno (ELF_E_ARCHIVE_FMAG);
789441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      return -1;
790441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    }
791441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
792441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  /* Copy the raw name over to a NUL terminated buffer.  */
793441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  *((char *) __mempcpy (elf->state.ar.raw_name, ar_hdr->ar_name, 16)) = '\0';
794441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
795441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  elf_ar_hdr = &elf->state.ar.elf_ar_hdr;
796441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
797441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  /* Now convert the `struct ar_hdr' into `Elf_Arhdr'.
798441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project     Determine whether this is a special entry.  */
799441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  if (ar_hdr->ar_name[0] == '/')
800441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    {
801441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      if (ar_hdr->ar_name[1] == ' '
802441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  && memcmp (ar_hdr->ar_name, "/               ", 16) == 0)
803441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	/* This is the index.  */
804441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	elf_ar_hdr->ar_name = memcpy (elf->state.ar.ar_name, "/", 2);
805441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      else if (ar_hdr->ar_name[1] == '/'
806441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	       && memcmp (ar_hdr->ar_name, "//              ", 16) == 0)
807441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	/* This is the array with the long names.  */
808441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	elf_ar_hdr->ar_name = memcpy (elf->state.ar.ar_name, "//", 3);
809cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      else if (likely  (isdigit (ar_hdr->ar_name[1])))
810441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	{
811441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  size_t offset;
812441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
813441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  /* This is a long name.  First we have to read the long name
814441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	     table, if this hasn't happened already.  */
815cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if (unlikely (elf->state.ar.long_names == NULL
816cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			&& read_long_names (elf) == NULL))
817441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    {
818441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      /* No long name table although it is reference.  The archive is
819441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		 broken.  */
820441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      __libelf_seterrno (ELF_E_INVALID_ARCHIVE);
821441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      return -1;
822441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    }
823441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
824441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  offset = atol (ar_hdr->ar_name + 1);
825cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if (unlikely (offset >= elf->state.ar.long_names_len))
826441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    {
827441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      /* The index in the long name table is larger than the table.  */
828441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      __libelf_seterrno (ELF_E_INVALID_ARCHIVE);
829441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      return -1;
830441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    }
831441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  elf_ar_hdr->ar_name = elf->state.ar.long_names + offset;
832441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	}
833441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      else
834441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	{
835441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  /* This is none of the known special entries.  */
836441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  __libelf_seterrno (ELF_E_INVALID_ARCHIVE);
837441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  return -1;
838441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	}
839441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    }
840441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  else
841441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    {
842441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      char *endp;
843441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
844441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      /* It is a normal entry.  Copy over the name.  */
845441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      endp = (char *) memccpy (elf->state.ar.ar_name, ar_hdr->ar_name,
846441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project			       '/', 16);
847441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      if (endp != NULL)
848441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	endp[-1] = '\0';
849441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      else
850cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{
851cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  /* In the old BSD style of archive, there is no / terminator.
852cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	     Instead, there is space padding at the end of the name.  */
853cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  size_t i = 15;
854cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  do
855cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    elf->state.ar.ar_name[i] = '\0';
856cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  while (i > 0 && elf->state.ar.ar_name[--i] == ' ');
857cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}
858441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
859441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      elf_ar_hdr->ar_name = elf->state.ar.ar_name;
860441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    }
861441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
862cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (unlikely (ar_hdr->ar_size[0] == ' '))
863cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    /* Something is really wrong.  We cannot live without a size for
864cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng       the member since it will not be possible to find the next
865cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng       archive member.  */
866cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {
867cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      __libelf_seterrno (ELF_E_INVALID_ARCHIVE);
868cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      return -1;
869cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }
870cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
871441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  /* Since there are no specialized functions to convert ASCII to
872441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project     time_t, uid_t, gid_t, mode_t, and off_t we use either atol or
873441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project     atoll depending on the size of the types.  We are also prepared
874441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project     for the case where the whole field in the `struct ar_hdr' is
875441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project     filled in which case we cannot simply use atol/l but instead have
876441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project     to create a temporary copy.  */
877441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
878cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#define INT_FIELD(FIELD)						      \
879cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  do									      \
880cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    {									      \
881cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      char buf[sizeof (ar_hdr->FIELD) + 1];				      \
882cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      const char *string = ar_hdr->FIELD;				      \
883cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (ar_hdr->FIELD[sizeof (ar_hdr->FIELD) - 1] != ' ')		      \
884cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	{								      \
885cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  *((char *) __mempcpy (buf, ar_hdr->FIELD, sizeof (ar_hdr->FIELD)))  \
886cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    = '\0';							      \
887cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  string = buf;							      \
888cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	}								      \
889cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (sizeof (elf_ar_hdr->FIELD) <= sizeof (long int))		      \
890cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	elf_ar_hdr->FIELD = (__typeof (elf_ar_hdr->FIELD)) atol (string);     \
891cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      else								      \
892cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	elf_ar_hdr->FIELD = (__typeof (elf_ar_hdr->FIELD)) atoll (string);    \
893cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    }									      \
894cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  while (0)
895cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
896cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  INT_FIELD (ar_date);
897cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  INT_FIELD (ar_uid);
898cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  INT_FIELD (ar_gid);
899cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  INT_FIELD (ar_mode);
900cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  INT_FIELD (ar_size);
901441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
902441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  return 0;
903441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project}
904441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
905441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
906441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project/* We were asked to return a clone of an existing descriptor.  This
907441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project   function must be called with the lock on the parent descriptor
908441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project   being held. */
909441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectstatic Elf *
910441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectdup_elf (int fildes, Elf_Cmd cmd, Elf *ref)
911441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project{
912441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  struct Elf *result;
913441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
914441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  if (fildes == -1)
915441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    /* Allow the user to pass -1 as the file descriptor for the new file.  */
916441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    fildes = ref->fildes;
917441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  /* The file descriptor better should be the same.  If it was disconnected
918441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project     already (using `elf_cntl') we do not test it.  */
919cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  else if (unlikely (ref->fildes != -1 && fildes != ref->fildes))
920441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    {
921441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      __libelf_seterrno (ELF_E_FD_MISMATCH);
922441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      return NULL;
923441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    }
924441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
925441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  /* The mode must allow reading.  I.e., a descriptor creating with a
926441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project     command different then ELF_C_READ, ELF_C_WRITE and ELF_C_RDWR is
927441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project     not allowed.  */
928cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (unlikely (ref->cmd != ELF_C_READ && ref->cmd != ELF_C_READ_MMAP
929cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		&& ref->cmd != ELF_C_WRITE && ref->cmd != ELF_C_WRITE_MMAP
930cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		&& ref->cmd != ELF_C_RDWR && ref->cmd != ELF_C_RDWR_MMAP
931cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng		&& ref->cmd != ELF_C_READ_MMAP_PRIVATE))
932441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    {
933441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      __libelf_seterrno (ELF_E_INVALID_OP);
934441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      return NULL;
935441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    }
936441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
937441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  /* Now it is time to distinguish between reading normal files and
938441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project     archives.  Normal files can easily be handled be incrementing the
939441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project     reference counter and return the same descriptor.  */
940441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  if (ref->kind != ELF_K_AR)
941441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    {
942441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      ++ref->ref_count;
943441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      return ref;
944441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    }
945441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
946441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  /* This is an archive.  We must create a descriptor for the archive
947441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project     member the internal pointer of the archive file desriptor is
948441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project     pointing to.  First read the header of the next member if this
949441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project     has not happened already.  */
950441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  if (ref->state.ar.elf_ar_hdr.ar_name == NULL
951cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      && __libelf_next_arhdr_wrlock (ref) != 0)
952441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    /* Something went wrong.  Maybe there is no member left.  */
953441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    return NULL;
954441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
955441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  /* We have all the information we need about the next archive member.
956441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project     Now create a descriptor for it.  */
957441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  result = read_file (fildes, ref->state.ar.offset + sizeof (struct ar_hdr),
958441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project		      ref->state.ar.elf_ar_hdr.ar_size, cmd, ref);
959441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
960441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  /* Enlist this new descriptor in the list of children.  */
961441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  if (result != NULL)
962441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    {
963441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      result->next = ref->state.ar.children;
964441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      ref->state.ar.children = result;
965441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    }
966441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
967441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  return result;
968441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project}
969441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
970441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
971441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project/* Return desriptor for empty file ready for writing.  */
972441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectstatic struct Elf *
973441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectwrite_file (int fd, Elf_Cmd cmd)
974441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project{
975441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  /* We simply create an empty `Elf' structure.  */
976441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project#define NSCNSALLOC	10
977441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  Elf *result = allocate_elf (fd, NULL, 0, 0, cmd, NULL, ELF_K_ELF,
978441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project			      NSCNSALLOC * sizeof (Elf_Scn));
979441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
980441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  if (result != NULL)
981441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    {
982441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      /* We have to write to the file in any case.  */
983441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      result->flags = ELF_F_DIRTY;
984441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
985441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      /* Some more or less arbitrary value.  */
986441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      result->state.elf.scnincr = NSCNSALLOC;
987441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
988441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      /* We have allocated room for some sections.  */
989441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      assert (offsetof (struct Elf, state.elf32.scns)
990441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      == offsetof (struct Elf, state.elf64.scns));
991441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      result->state.elf.scns_last = &result->state.elf32.scns;
992441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      result->state.elf32.scns.max = NSCNSALLOC;
993441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    }
994441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
995441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  return result;
996441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project}
997441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
998441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
999441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project/* Return a descriptor for the file belonging to FILDES.  */
1000441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source ProjectElf *
1001441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Projectelf_begin (fildes, cmd, ref)
1002441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project     int fildes;
1003441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project     Elf_Cmd cmd;
1004441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project     Elf *ref;
1005441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project{
1006441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  Elf *retval;
1007441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1008cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  if (unlikely (! __libelf_version_initialized))
1009441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    {
1010441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      /* Version wasn't set so far.  */
1011441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      __libelf_seterrno (ELF_E_NO_VERSION);
1012441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      return NULL;
1013441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    }
1014441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1015441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  if (ref != NULL)
1016441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    /* Make sure the descriptor is not suddenly going away.  */
1017441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    rwlock_rdlock (ref->lock);
1018cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  else if (unlikely (fcntl (fildes, F_GETFL) == -1 && errno == EBADF))
1019441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    {
1020441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      /* We cannot do anything productive without a file descriptor.  */
1021441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      __libelf_seterrno (ELF_E_INVALID_FILE);
1022441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      return NULL;
1023441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    }
1024441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1025cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  Elf *lock_dup_elf ()
1026cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  {
1027cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    /* We need wrlock to dup an archive.  */
1028cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    if (ref->kind == ELF_K_AR)
1029cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      {
1030cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	rwlock_unlock (ref->lock);
1031cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	rwlock_wrlock (ref->lock);
1032cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      }
1033cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1034cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    /* Duplicate the descriptor.  */
1035cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng    return dup_elf (fildes, cmd, ref);
1036cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng  }
1037cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng
1038441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  switch (cmd)
1039441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    {
1040441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    case ELF_C_NULL:
1041441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      /* We simply return a NULL pointer.  */
1042441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      retval = NULL;
1043441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      break;
1044441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1045441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    case ELF_C_READ_MMAP_PRIVATE:
1046441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      /* If we have a reference it must also be opened this way.  */
1047cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng      if (unlikely (ref != NULL && ref->cmd != ELF_C_READ_MMAP_PRIVATE))
1048441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	{
1049441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  __libelf_seterrno (ELF_E_INVALID_CMD);
1050441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  retval = NULL;
1051441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  break;
1052441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	}
1053441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      /* FALLTHROUGH */
1054441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1055441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    case ELF_C_READ:
1056441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    case ELF_C_READ_MMAP:
1057441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      if (ref != NULL)
1058cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	retval = lock_dup_elf ();
1059441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      else
1060441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	/* Create descriptor for existing file.  */
1061441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	retval = read_file (fildes, 0, ~((size_t) 0), cmd, NULL);
1062441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      break;
1063441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1064441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    case ELF_C_RDWR:
1065441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    case ELF_C_RDWR_MMAP:
1066441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      /* If we have a REF object it must also be opened using this
1067441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	 command.  */
1068441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      if (ref != NULL)
1069441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	{
1070cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	  if (unlikely (ref->cmd != ELF_C_RDWR && ref->cmd != ELF_C_RDWR_MMAP
1071cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			&& ref->cmd != ELF_C_WRITE
1072cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng			&& ref->cmd != ELF_C_WRITE_MMAP))
1073441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    {
1074441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      /* This is not ok.  REF must also be opened for writing.  */
1075441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      __libelf_seterrno (ELF_E_INVALID_CMD);
1076441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	      retval = NULL;
1077441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	    }
1078441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	  else
1079cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng	    retval = lock_dup_elf ();
1080441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	}
1081441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      else
1082441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	/* Create descriptor for existing file.  */
1083441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project	retval = read_file (fildes, 0, ~((size_t) 0), cmd, NULL);
1084441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      break;
1085441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1086441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    case ELF_C_WRITE:
1087441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    case ELF_C_WRITE_MMAP:
1088441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      /* We ignore REF and prepare a descriptor to write a new file.  */
1089441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      retval = write_file (fildes, cmd);
1090441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      break;
1091441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1092441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    default:
1093441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      __libelf_seterrno (ELF_E_INVALID_CMD);
1094441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      retval = NULL;
1095441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project      break;
1096441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    }
1097441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1098441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  /* Release the lock.  */
1099441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  if (ref != NULL)
1100441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project    rwlock_unlock (ref->lock);
1101441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project
1102441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project  return retval;
1103441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source Project}
1104441f72d43a9b550baa779fc82f70816da5f74f0eThe Android Open Source ProjectINTDEF(elf_begin)
1105