1da0c48c4Sopenharmony_ci/* Get ELF program header table.
2da0c48c4Sopenharmony_ci   Copyright (C) 1998-2010, 2014, 2015 Red Hat, Inc.
3da0c48c4Sopenharmony_ci   This file is part of elfutils.
4da0c48c4Sopenharmony_ci   Written by Ulrich Drepper <drepper@redhat.com>, 1998.
5da0c48c4Sopenharmony_ci
6da0c48c4Sopenharmony_ci   This file is free software; you can redistribute it and/or modify
7da0c48c4Sopenharmony_ci   it under the terms of either
8da0c48c4Sopenharmony_ci
9da0c48c4Sopenharmony_ci     * the GNU Lesser General Public License as published by the Free
10da0c48c4Sopenharmony_ci       Software Foundation; either version 3 of the License, or (at
11da0c48c4Sopenharmony_ci       your option) any later version
12da0c48c4Sopenharmony_ci
13da0c48c4Sopenharmony_ci   or
14da0c48c4Sopenharmony_ci
15da0c48c4Sopenharmony_ci     * the GNU General Public License as published by the Free
16da0c48c4Sopenharmony_ci       Software Foundation; either version 2 of the License, or (at
17da0c48c4Sopenharmony_ci       your option) any later version
18da0c48c4Sopenharmony_ci
19da0c48c4Sopenharmony_ci   or both in parallel, as here.
20da0c48c4Sopenharmony_ci
21da0c48c4Sopenharmony_ci   elfutils is distributed in the hope that it will be useful, but
22da0c48c4Sopenharmony_ci   WITHOUT ANY WARRANTY; without even the implied warranty of
23da0c48c4Sopenharmony_ci   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
24da0c48c4Sopenharmony_ci   General Public License for more details.
25da0c48c4Sopenharmony_ci
26da0c48c4Sopenharmony_ci   You should have received copies of the GNU General Public License and
27da0c48c4Sopenharmony_ci   the GNU Lesser General Public License along with this program.  If
28da0c48c4Sopenharmony_ci   not, see <http://www.gnu.org/licenses/>.  */
29da0c48c4Sopenharmony_ci
30da0c48c4Sopenharmony_ci#ifdef HAVE_CONFIG_H
31da0c48c4Sopenharmony_ci# include <config.h>
32da0c48c4Sopenharmony_ci#endif
33da0c48c4Sopenharmony_ci
34da0c48c4Sopenharmony_ci#include <errno.h>
35da0c48c4Sopenharmony_ci#include <stdbool.h>
36da0c48c4Sopenharmony_ci#include <stdlib.h>
37da0c48c4Sopenharmony_ci#include <assert.h>
38da0c48c4Sopenharmony_ci
39da0c48c4Sopenharmony_ci#include "libelfP.h"
40da0c48c4Sopenharmony_ci#include "common.h"
41da0c48c4Sopenharmony_ci
42da0c48c4Sopenharmony_ci#ifndef LIBELFBITS
43da0c48c4Sopenharmony_ci# define LIBELFBITS 32
44da0c48c4Sopenharmony_ci#endif
45da0c48c4Sopenharmony_ci
46da0c48c4Sopenharmony_ciElfW2(LIBELFBITS,Phdr) *
47da0c48c4Sopenharmony_ci__elfw2(LIBELFBITS,getphdr_wrlock) (Elf *elf)
48da0c48c4Sopenharmony_ci{
49da0c48c4Sopenharmony_ci  ElfW2(LIBELFBITS,Phdr) *result;
50da0c48c4Sopenharmony_ci
51da0c48c4Sopenharmony_ci  /* If the program header entry has already been filled in the code
52da0c48c4Sopenharmony_ci     below must already have been run.  So the class is set, too.  No
53da0c48c4Sopenharmony_ci     need to waste any more time here.  */
54da0c48c4Sopenharmony_ci  result = elf->state.ELFW(elf,LIBELFBITS).phdr;
55da0c48c4Sopenharmony_ci  if (likely (result != NULL))
56da0c48c4Sopenharmony_ci    return result;
57da0c48c4Sopenharmony_ci
58da0c48c4Sopenharmony_ci  if (elf->class == 0)
59da0c48c4Sopenharmony_ci    elf->class = ELFW(ELFCLASS,LIBELFBITS);
60da0c48c4Sopenharmony_ci  else if (elf->class != ELFW(ELFCLASS,LIBELFBITS))
61da0c48c4Sopenharmony_ci    {
62da0c48c4Sopenharmony_ci      __libelf_seterrno (ELF_E_INVALID_CLASS);
63da0c48c4Sopenharmony_ci      result = NULL;
64da0c48c4Sopenharmony_ci      goto out;
65da0c48c4Sopenharmony_ci    }
66da0c48c4Sopenharmony_ci
67da0c48c4Sopenharmony_ci  if (likely (result == NULL))
68da0c48c4Sopenharmony_ci    {
69da0c48c4Sopenharmony_ci      /* Read the section header table.  */
70da0c48c4Sopenharmony_ci      ElfW2(LIBELFBITS,Ehdr) *ehdr = elf->state.ELFW(elf,LIBELFBITS).ehdr;
71da0c48c4Sopenharmony_ci
72da0c48c4Sopenharmony_ci      /* If no program header exists return NULL.  */
73da0c48c4Sopenharmony_ci      size_t phnum;
74da0c48c4Sopenharmony_ci      if (__elf_getphdrnum_rdlock (elf, &phnum) != 0)
75da0c48c4Sopenharmony_ci	goto out;
76da0c48c4Sopenharmony_ci      if (phnum == 0 || ehdr->e_phoff == 0)
77da0c48c4Sopenharmony_ci	{
78da0c48c4Sopenharmony_ci	  __libelf_seterrno (ELF_E_NO_PHDR);
79da0c48c4Sopenharmony_ci	  goto out;
80da0c48c4Sopenharmony_ci	}
81da0c48c4Sopenharmony_ci
82da0c48c4Sopenharmony_ci      /* Check this doesn't overflow.  */
83da0c48c4Sopenharmony_ci      size_t size = phnum * sizeof (ElfW2(LIBELFBITS,Phdr));
84da0c48c4Sopenharmony_ci
85da0c48c4Sopenharmony_ci      if (phnum > SIZE_MAX / sizeof (ElfW2(LIBELFBITS,Phdr))
86da0c48c4Sopenharmony_ci	  || ehdr->e_phoff > elf->maximum_size
87da0c48c4Sopenharmony_ci	  || elf->maximum_size - ehdr->e_phoff < size)
88da0c48c4Sopenharmony_ci	{
89da0c48c4Sopenharmony_ci	  __libelf_seterrno (ELF_E_INVALID_DATA);
90da0c48c4Sopenharmony_ci	  goto out;
91da0c48c4Sopenharmony_ci	}
92da0c48c4Sopenharmony_ci
93da0c48c4Sopenharmony_ci      if (elf->map_address != NULL)
94da0c48c4Sopenharmony_ci	{
95da0c48c4Sopenharmony_ci	  /* First see whether the information in the ELF header is
96da0c48c4Sopenharmony_ci	     valid and it does not ask for too much.  */
97da0c48c4Sopenharmony_ci	  if (unlikely (ehdr->e_phoff >= elf->maximum_size)
98da0c48c4Sopenharmony_ci	      || unlikely (elf->maximum_size - ehdr->e_phoff < size))
99da0c48c4Sopenharmony_ci	    {
100da0c48c4Sopenharmony_ci	      /* Something is wrong.  */
101da0c48c4Sopenharmony_ci	      __libelf_seterrno (ELF_E_INVALID_PHDR);
102da0c48c4Sopenharmony_ci	      goto out;
103da0c48c4Sopenharmony_ci	    }
104da0c48c4Sopenharmony_ci
105da0c48c4Sopenharmony_ci	  /* All the data is already mapped.  Use it.  */
106da0c48c4Sopenharmony_ci	  void *file_phdr = ((char *) elf->map_address
107da0c48c4Sopenharmony_ci			     + elf->start_offset + ehdr->e_phoff);
108da0c48c4Sopenharmony_ci	  if (ehdr->e_ident[EI_DATA] == MY_ELFDATA
109da0c48c4Sopenharmony_ci	      && (ALLOW_UNALIGNED
110da0c48c4Sopenharmony_ci		  || ((uintptr_t) file_phdr
111da0c48c4Sopenharmony_ci		      & (__alignof__ (ElfW2(LIBELFBITS,Phdr)) - 1)) == 0))
112da0c48c4Sopenharmony_ci	    /* Simply use the mapped data.  */
113da0c48c4Sopenharmony_ci	    elf->state.ELFW(elf,LIBELFBITS).phdr = file_phdr;
114da0c48c4Sopenharmony_ci	  else
115da0c48c4Sopenharmony_ci	    {
116da0c48c4Sopenharmony_ci	      ElfW2(LIBELFBITS,Phdr) *notcvt;
117da0c48c4Sopenharmony_ci	      ElfW2(LIBELFBITS,Phdr) *phdr;
118da0c48c4Sopenharmony_ci
119da0c48c4Sopenharmony_ci	      /* Allocate memory for the program headers.  We know the number
120da0c48c4Sopenharmony_ci		 of entries from the ELF header.  */
121da0c48c4Sopenharmony_ci	      phdr = elf->state.ELFW(elf,LIBELFBITS).phdr =
122da0c48c4Sopenharmony_ci		(ElfW2(LIBELFBITS,Phdr) *) malloc (size);
123da0c48c4Sopenharmony_ci	      if (elf->state.ELFW(elf,LIBELFBITS).phdr == NULL)
124da0c48c4Sopenharmony_ci		{
125da0c48c4Sopenharmony_ci		  __libelf_seterrno (ELF_E_NOMEM);
126da0c48c4Sopenharmony_ci		  goto out;
127da0c48c4Sopenharmony_ci		}
128da0c48c4Sopenharmony_ci	      elf->state.ELFW(elf,LIBELFBITS).phdr_flags |=
129da0c48c4Sopenharmony_ci		ELF_F_MALLOCED | ELF_F_DIRTY;
130da0c48c4Sopenharmony_ci
131da0c48c4Sopenharmony_ci	      /* Now copy the data and at the same time convert the
132da0c48c4Sopenharmony_ci		 byte order.  */
133da0c48c4Sopenharmony_ci
134da0c48c4Sopenharmony_ci	      if (ehdr->e_ident[EI_DATA] == MY_ELFDATA)
135da0c48c4Sopenharmony_ci		{
136da0c48c4Sopenharmony_ci		  assert (! ALLOW_UNALIGNED);
137da0c48c4Sopenharmony_ci		  memcpy (phdr, file_phdr, size);
138da0c48c4Sopenharmony_ci		}
139da0c48c4Sopenharmony_ci	      else
140da0c48c4Sopenharmony_ci		{
141da0c48c4Sopenharmony_ci		  bool copy = ! (ALLOW_UNALIGNED
142da0c48c4Sopenharmony_ci				 || ((uintptr_t) file_phdr
143da0c48c4Sopenharmony_ci				     & (__alignof__ (ElfW2(LIBELFBITS,Phdr))
144da0c48c4Sopenharmony_ci					- 1)) == 0);
145da0c48c4Sopenharmony_ci		  if (! copy)
146da0c48c4Sopenharmony_ci		    notcvt = file_phdr;
147da0c48c4Sopenharmony_ci		  else
148da0c48c4Sopenharmony_ci		    {
149da0c48c4Sopenharmony_ci		      notcvt = (ElfW2(LIBELFBITS,Phdr) *) malloc (size);
150da0c48c4Sopenharmony_ci		      if (unlikely (notcvt == NULL))
151da0c48c4Sopenharmony_ci			{
152da0c48c4Sopenharmony_ci			  __libelf_seterrno (ELF_E_NOMEM);
153da0c48c4Sopenharmony_ci			  goto out;
154da0c48c4Sopenharmony_ci			}
155da0c48c4Sopenharmony_ci		      memcpy (notcvt, file_phdr, size);
156da0c48c4Sopenharmony_ci		    }
157da0c48c4Sopenharmony_ci
158da0c48c4Sopenharmony_ci		  for (size_t cnt = 0; cnt < phnum; ++cnt)
159da0c48c4Sopenharmony_ci		    {
160da0c48c4Sopenharmony_ci		      CONVERT_TO (phdr[cnt].p_type, notcvt[cnt].p_type);
161da0c48c4Sopenharmony_ci		      CONVERT_TO (phdr[cnt].p_offset, notcvt[cnt].p_offset);
162da0c48c4Sopenharmony_ci		      CONVERT_TO (phdr[cnt].p_vaddr, notcvt[cnt].p_vaddr);
163da0c48c4Sopenharmony_ci		      CONVERT_TO (phdr[cnt].p_paddr, notcvt[cnt].p_paddr);
164da0c48c4Sopenharmony_ci		      CONVERT_TO (phdr[cnt].p_filesz, notcvt[cnt].p_filesz);
165da0c48c4Sopenharmony_ci		      CONVERT_TO (phdr[cnt].p_memsz, notcvt[cnt].p_memsz);
166da0c48c4Sopenharmony_ci		      CONVERT_TO (phdr[cnt].p_flags, notcvt[cnt].p_flags);
167da0c48c4Sopenharmony_ci		      CONVERT_TO (phdr[cnt].p_align, notcvt[cnt].p_align);
168da0c48c4Sopenharmony_ci		    }
169da0c48c4Sopenharmony_ci
170da0c48c4Sopenharmony_ci		  if (copy)
171da0c48c4Sopenharmony_ci		    free (notcvt);
172da0c48c4Sopenharmony_ci		}
173da0c48c4Sopenharmony_ci	    }
174da0c48c4Sopenharmony_ci	}
175da0c48c4Sopenharmony_ci      else if (likely (elf->fildes != -1))
176da0c48c4Sopenharmony_ci	{
177da0c48c4Sopenharmony_ci	  /* Allocate memory for the program headers.  We know the number
178da0c48c4Sopenharmony_ci	     of entries from the ELF header.  */
179da0c48c4Sopenharmony_ci	  elf->state.ELFW(elf,LIBELFBITS).phdr =
180da0c48c4Sopenharmony_ci	    (ElfW2(LIBELFBITS,Phdr) *) malloc (size);
181da0c48c4Sopenharmony_ci	  if (elf->state.ELFW(elf,LIBELFBITS).phdr == NULL)
182da0c48c4Sopenharmony_ci	    {
183da0c48c4Sopenharmony_ci	      __libelf_seterrno (ELF_E_NOMEM);
184da0c48c4Sopenharmony_ci	      goto out;
185da0c48c4Sopenharmony_ci	    }
186da0c48c4Sopenharmony_ci	  elf->state.ELFW(elf,LIBELFBITS).phdr_flags |= ELF_F_MALLOCED;
187da0c48c4Sopenharmony_ci
188da0c48c4Sopenharmony_ci	  /* Read the header.  */
189da0c48c4Sopenharmony_ci	  ssize_t n = pread_retry (elf->fildes,
190da0c48c4Sopenharmony_ci				   elf->state.ELFW(elf,LIBELFBITS).phdr, size,
191da0c48c4Sopenharmony_ci				   elf->start_offset + ehdr->e_phoff);
192da0c48c4Sopenharmony_ci	  if (unlikely ((size_t) n != size))
193da0c48c4Sopenharmony_ci	    {
194da0c48c4Sopenharmony_ci	      /* Severe problems.  We cannot read the data.  */
195da0c48c4Sopenharmony_ci	      __libelf_seterrno (ELF_E_READ_ERROR);
196da0c48c4Sopenharmony_ci	      free (elf->state.ELFW(elf,LIBELFBITS).phdr);
197da0c48c4Sopenharmony_ci	      elf->state.ELFW(elf,LIBELFBITS).phdr = NULL;
198da0c48c4Sopenharmony_ci	      goto out;
199da0c48c4Sopenharmony_ci	    }
200da0c48c4Sopenharmony_ci
201da0c48c4Sopenharmony_ci	  /* If the byte order of the file is not the same as the one
202da0c48c4Sopenharmony_ci	     of the host convert the data now.  */
203da0c48c4Sopenharmony_ci	  if (ehdr->e_ident[EI_DATA] != MY_ELFDATA)
204da0c48c4Sopenharmony_ci	    {
205da0c48c4Sopenharmony_ci	      ElfW2(LIBELFBITS,Phdr) *phdr
206da0c48c4Sopenharmony_ci		= elf->state.ELFW(elf,LIBELFBITS).phdr;
207da0c48c4Sopenharmony_ci
208da0c48c4Sopenharmony_ci	      for (size_t cnt = 0; cnt < phnum; ++cnt)
209da0c48c4Sopenharmony_ci		{
210da0c48c4Sopenharmony_ci		  CONVERT (phdr[cnt].p_type);
211da0c48c4Sopenharmony_ci		  CONVERT (phdr[cnt].p_offset);
212da0c48c4Sopenharmony_ci		  CONVERT (phdr[cnt].p_vaddr);
213da0c48c4Sopenharmony_ci		  CONVERT (phdr[cnt].p_paddr);
214da0c48c4Sopenharmony_ci		  CONVERT (phdr[cnt].p_filesz);
215da0c48c4Sopenharmony_ci		  CONVERT (phdr[cnt].p_memsz);
216da0c48c4Sopenharmony_ci		  CONVERT (phdr[cnt].p_flags);
217da0c48c4Sopenharmony_ci		  CONVERT (phdr[cnt].p_align);
218da0c48c4Sopenharmony_ci		}
219da0c48c4Sopenharmony_ci	    }
220da0c48c4Sopenharmony_ci	}
221da0c48c4Sopenharmony_ci      else
222da0c48c4Sopenharmony_ci	{
223da0c48c4Sopenharmony_ci	  /* The file descriptor was already enabled and not all data was
224da0c48c4Sopenharmony_ci	     read.  */
225da0c48c4Sopenharmony_ci	  __libelf_seterrno (ELF_E_FD_DISABLED);
226da0c48c4Sopenharmony_ci	  goto out;
227da0c48c4Sopenharmony_ci	}
228da0c48c4Sopenharmony_ci
229da0c48c4Sopenharmony_ci      result = elf->state.ELFW(elf,LIBELFBITS).phdr;
230da0c48c4Sopenharmony_ci    }
231da0c48c4Sopenharmony_ci
232da0c48c4Sopenharmony_ci out:
233da0c48c4Sopenharmony_ci  return result;
234da0c48c4Sopenharmony_ci}
235da0c48c4Sopenharmony_ci
236da0c48c4Sopenharmony_ciElfW2(LIBELFBITS,Phdr) *
237da0c48c4Sopenharmony_cielfw2(LIBELFBITS,getphdr) (Elf *elf)
238da0c48c4Sopenharmony_ci{
239da0c48c4Sopenharmony_ci  ElfW2(LIBELFBITS,Phdr) *result;
240da0c48c4Sopenharmony_ci
241da0c48c4Sopenharmony_ci  if (elf == NULL)
242da0c48c4Sopenharmony_ci    return NULL;
243da0c48c4Sopenharmony_ci
244da0c48c4Sopenharmony_ci  if (unlikely (elf->kind != ELF_K_ELF))
245da0c48c4Sopenharmony_ci    {
246da0c48c4Sopenharmony_ci      __libelf_seterrno (ELF_E_INVALID_HANDLE);
247da0c48c4Sopenharmony_ci      return NULL;
248da0c48c4Sopenharmony_ci    }
249da0c48c4Sopenharmony_ci
250da0c48c4Sopenharmony_ci  /* If the program header entry has already been filled in the code
251da0c48c4Sopenharmony_ci   * in getphdr_wrlock must already have been run.  So the class is
252da0c48c4Sopenharmony_ci   * set, too.  No need to waste any more time here.  */
253da0c48c4Sopenharmony_ci  result = elf->state.ELFW(elf,LIBELFBITS).phdr;
254da0c48c4Sopenharmony_ci  if (likely (result != NULL))
255da0c48c4Sopenharmony_ci    return result;
256da0c48c4Sopenharmony_ci
257da0c48c4Sopenharmony_ci  rwlock_wrlock (elf->lock);
258da0c48c4Sopenharmony_ci  result = __elfw2(LIBELFBITS,getphdr_wrlock) (elf);
259da0c48c4Sopenharmony_ci  rwlock_unlock (elf->lock);
260da0c48c4Sopenharmony_ci
261da0c48c4Sopenharmony_ci  return result;
262da0c48c4Sopenharmony_ci}
263da0c48c4Sopenharmony_ciINTDEF(elfw2(LIBELFBITS,getphdr))
264