1da0c48c4Sopenharmony_ci/* Return section header.
2da0c48c4Sopenharmony_ci   Copyright (C) 1998-2002, 2005, 2007, 2009, 2012, 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 <assert.h>
35da0c48c4Sopenharmony_ci#include <errno.h>
36da0c48c4Sopenharmony_ci#include <stdbool.h>
37da0c48c4Sopenharmony_ci
38da0c48c4Sopenharmony_ci#include "libelfP.h"
39da0c48c4Sopenharmony_ci#include "common.h"
40da0c48c4Sopenharmony_ci
41da0c48c4Sopenharmony_ci#ifndef LIBELFBITS
42da0c48c4Sopenharmony_ci# define LIBELFBITS 32
43da0c48c4Sopenharmony_ci#endif
44da0c48c4Sopenharmony_ci
45da0c48c4Sopenharmony_ci
46da0c48c4Sopenharmony_cistatic ElfW2(LIBELFBITS,Shdr) *
47da0c48c4Sopenharmony_ciload_shdr_wrlock (Elf_Scn *scn)
48da0c48c4Sopenharmony_ci{
49da0c48c4Sopenharmony_ci  ElfW2(LIBELFBITS,Shdr) *result;
50da0c48c4Sopenharmony_ci
51da0c48c4Sopenharmony_ci  /* Read the section header table.  */
52da0c48c4Sopenharmony_ci  Elf *elf = scn->elf;
53da0c48c4Sopenharmony_ci  ElfW2(LIBELFBITS,Ehdr) *ehdr = elf->state.ELFW(elf,LIBELFBITS).ehdr;
54da0c48c4Sopenharmony_ci
55da0c48c4Sopenharmony_ci  /* Try again, maybe the data is there now.  */
56da0c48c4Sopenharmony_ci  result = scn->shdr.ELFW(e,LIBELFBITS);
57da0c48c4Sopenharmony_ci  if (result != NULL)
58da0c48c4Sopenharmony_ci    goto out;
59da0c48c4Sopenharmony_ci
60da0c48c4Sopenharmony_ci  size_t shnum;
61da0c48c4Sopenharmony_ci  if (__elf_getshdrnum_rdlock (elf, &shnum) != 0
62da0c48c4Sopenharmony_ci      || shnum > SIZE_MAX / sizeof (ElfW2(LIBELFBITS,Shdr)))
63da0c48c4Sopenharmony_ci    goto out;
64da0c48c4Sopenharmony_ci  size_t size = shnum * sizeof (ElfW2(LIBELFBITS,Shdr));
65da0c48c4Sopenharmony_ci
66da0c48c4Sopenharmony_ci  /* Allocate memory for the section headers.  We know the number
67da0c48c4Sopenharmony_ci     of entries from the ELF header.  */
68da0c48c4Sopenharmony_ci  ElfW2(LIBELFBITS,Shdr) *shdr = elf->state.ELFW(elf,LIBELFBITS).shdr =
69da0c48c4Sopenharmony_ci    (ElfW2(LIBELFBITS,Shdr) *) malloc (size);
70da0c48c4Sopenharmony_ci  if (elf->state.ELFW(elf,LIBELFBITS).shdr == NULL)
71da0c48c4Sopenharmony_ci    {
72da0c48c4Sopenharmony_ci      __libelf_seterrno (ELF_E_NOMEM);
73da0c48c4Sopenharmony_ci      goto out;
74da0c48c4Sopenharmony_ci    }
75da0c48c4Sopenharmony_ci  elf->state.ELFW(elf,LIBELFBITS).shdr_malloced = 1;
76da0c48c4Sopenharmony_ci
77da0c48c4Sopenharmony_ci  if (elf->map_address != NULL)
78da0c48c4Sopenharmony_ci    {
79da0c48c4Sopenharmony_ci      /* First see whether the information in the ELF header is
80da0c48c4Sopenharmony_ci	 valid and it does not ask for too much.  */
81da0c48c4Sopenharmony_ci      if (unlikely (ehdr->e_shoff >= elf->maximum_size)
82da0c48c4Sopenharmony_ci	  || unlikely (elf->maximum_size - ehdr->e_shoff < size))
83da0c48c4Sopenharmony_ci	{
84da0c48c4Sopenharmony_ci	  /* Something is wrong.  */
85da0c48c4Sopenharmony_ci	  __libelf_seterrno (ELF_E_INVALID_SECTION_HEADER);
86da0c48c4Sopenharmony_ci	  goto free_and_out;
87da0c48c4Sopenharmony_ci	}
88da0c48c4Sopenharmony_ci
89da0c48c4Sopenharmony_ci      ElfW2(LIBELFBITS,Shdr) *notcvt;
90da0c48c4Sopenharmony_ci
91da0c48c4Sopenharmony_ci      /* All the data is already mapped.  If we could use it
92da0c48c4Sopenharmony_ci	 directly this would already have happened.  Unless
93da0c48c4Sopenharmony_ci	 we allocated the memory ourselves and the ELF_F_MALLOCED
94da0c48c4Sopenharmony_ci	 flag is set.  */
95da0c48c4Sopenharmony_ci      void *file_shdr = ((char *) elf->map_address
96da0c48c4Sopenharmony_ci			 + elf->start_offset + ehdr->e_shoff);
97da0c48c4Sopenharmony_ci
98da0c48c4Sopenharmony_ci      assert ((elf->flags & ELF_F_MALLOCED)
99da0c48c4Sopenharmony_ci	      || ehdr->e_ident[EI_DATA] != MY_ELFDATA
100da0c48c4Sopenharmony_ci	      || elf->cmd == ELF_C_READ_MMAP
101da0c48c4Sopenharmony_ci	      || (! ALLOW_UNALIGNED
102da0c48c4Sopenharmony_ci		  && ((uintptr_t) file_shdr
103da0c48c4Sopenharmony_ci		      & (__alignof__ (ElfW2(LIBELFBITS,Shdr)) - 1)) != 0));
104da0c48c4Sopenharmony_ci
105da0c48c4Sopenharmony_ci      /* Now copy the data and at the same time convert the byte order.  */
106da0c48c4Sopenharmony_ci      if (ehdr->e_ident[EI_DATA] == MY_ELFDATA)
107da0c48c4Sopenharmony_ci	{
108da0c48c4Sopenharmony_ci	  assert ((elf->flags & ELF_F_MALLOCED)
109da0c48c4Sopenharmony_ci		  || elf->cmd == ELF_C_READ_MMAP
110da0c48c4Sopenharmony_ci		  || ! ALLOW_UNALIGNED);
111da0c48c4Sopenharmony_ci	  memcpy (shdr, file_shdr, size);
112da0c48c4Sopenharmony_ci	}
113da0c48c4Sopenharmony_ci      else
114da0c48c4Sopenharmony_ci	{
115da0c48c4Sopenharmony_ci	  bool copy = ! (ALLOW_UNALIGNED
116da0c48c4Sopenharmony_ci			 || ((uintptr_t) file_shdr
117da0c48c4Sopenharmony_ci			     & (__alignof__ (ElfW2(LIBELFBITS,Shdr)) - 1))
118da0c48c4Sopenharmony_ci			     == 0);
119da0c48c4Sopenharmony_ci	  if (! copy)
120da0c48c4Sopenharmony_ci	    notcvt = (ElfW2(LIBELFBITS,Shdr) *)
121da0c48c4Sopenharmony_ci	      ((char *) elf->map_address
122da0c48c4Sopenharmony_ci	       + elf->start_offset + ehdr->e_shoff);
123da0c48c4Sopenharmony_ci	  else
124da0c48c4Sopenharmony_ci	    {
125da0c48c4Sopenharmony_ci	      notcvt = (ElfW2(LIBELFBITS,Shdr) *) malloc (size);
126da0c48c4Sopenharmony_ci	      if (unlikely (notcvt == NULL))
127da0c48c4Sopenharmony_ci		{
128da0c48c4Sopenharmony_ci		  __libelf_seterrno (ELF_E_NOMEM);
129da0c48c4Sopenharmony_ci		  goto out;
130da0c48c4Sopenharmony_ci		}
131da0c48c4Sopenharmony_ci	      memcpy (notcvt, ((char *) elf->map_address
132da0c48c4Sopenharmony_ci			       + elf->start_offset + ehdr->e_shoff),
133da0c48c4Sopenharmony_ci		      size);
134da0c48c4Sopenharmony_ci	    }
135da0c48c4Sopenharmony_ci
136da0c48c4Sopenharmony_ci	  for (size_t cnt = 0; cnt < shnum; ++cnt)
137da0c48c4Sopenharmony_ci	    {
138da0c48c4Sopenharmony_ci	      CONVERT_TO (shdr[cnt].sh_name, notcvt[cnt].sh_name);
139da0c48c4Sopenharmony_ci	      CONVERT_TO (shdr[cnt].sh_type, notcvt[cnt].sh_type);
140da0c48c4Sopenharmony_ci	      CONVERT_TO (shdr[cnt].sh_flags, notcvt[cnt].sh_flags);
141da0c48c4Sopenharmony_ci	      CONVERT_TO (shdr[cnt].sh_addr, notcvt[cnt].sh_addr);
142da0c48c4Sopenharmony_ci	      CONVERT_TO (shdr[cnt].sh_offset, notcvt[cnt].sh_offset);
143da0c48c4Sopenharmony_ci	      CONVERT_TO (shdr[cnt].sh_size, notcvt[cnt].sh_size);
144da0c48c4Sopenharmony_ci	      CONVERT_TO (shdr[cnt].sh_link, notcvt[cnt].sh_link);
145da0c48c4Sopenharmony_ci	      CONVERT_TO (shdr[cnt].sh_info, notcvt[cnt].sh_info);
146da0c48c4Sopenharmony_ci	      CONVERT_TO (shdr[cnt].sh_addralign,
147da0c48c4Sopenharmony_ci			  notcvt[cnt].sh_addralign);
148da0c48c4Sopenharmony_ci	      CONVERT_TO (shdr[cnt].sh_entsize, notcvt[cnt].sh_entsize);
149da0c48c4Sopenharmony_ci
150da0c48c4Sopenharmony_ci	      /* If this is a section with an extended index add a
151da0c48c4Sopenharmony_ci		 reference in the section which uses the extended
152da0c48c4Sopenharmony_ci		 index.  */
153da0c48c4Sopenharmony_ci	      if (shdr[cnt].sh_type == SHT_SYMTAB_SHNDX
154da0c48c4Sopenharmony_ci		  && shdr[cnt].sh_link < shnum)
155da0c48c4Sopenharmony_ci		elf->state.ELFW(elf,LIBELFBITS).scns.data[shdr[cnt].sh_link].shndx_index
156da0c48c4Sopenharmony_ci		  = cnt;
157da0c48c4Sopenharmony_ci
158da0c48c4Sopenharmony_ci	      /* Set the own shndx_index field in case it has not yet
159da0c48c4Sopenharmony_ci		 been set.  */
160da0c48c4Sopenharmony_ci	      if (elf->state.ELFW(elf,LIBELFBITS).scns.data[cnt].shndx_index == 0)
161da0c48c4Sopenharmony_ci		elf->state.ELFW(elf,LIBELFBITS).scns.data[cnt].shndx_index
162da0c48c4Sopenharmony_ci		  = -1;
163da0c48c4Sopenharmony_ci	    }
164da0c48c4Sopenharmony_ci
165da0c48c4Sopenharmony_ci	  if (copy)
166da0c48c4Sopenharmony_ci	    free (notcvt);
167da0c48c4Sopenharmony_ci	}
168da0c48c4Sopenharmony_ci    }
169da0c48c4Sopenharmony_ci  else if (likely (elf->fildes != -1))
170da0c48c4Sopenharmony_ci    {
171da0c48c4Sopenharmony_ci      /* Read the header.  */
172da0c48c4Sopenharmony_ci      ssize_t n = pread_retry (elf->fildes,
173da0c48c4Sopenharmony_ci			       elf->state.ELFW(elf,LIBELFBITS).shdr, size,
174da0c48c4Sopenharmony_ci			       elf->start_offset + ehdr->e_shoff);
175da0c48c4Sopenharmony_ci      if (unlikely ((size_t) n != size))
176da0c48c4Sopenharmony_ci	{
177da0c48c4Sopenharmony_ci	  /* Severe problems.  We cannot read the data.  */
178da0c48c4Sopenharmony_ci	  __libelf_seterrno (ELF_E_READ_ERROR);
179da0c48c4Sopenharmony_ci	  goto free_and_out;
180da0c48c4Sopenharmony_ci	}
181da0c48c4Sopenharmony_ci
182da0c48c4Sopenharmony_ci      /* If the byte order of the file is not the same as the one
183da0c48c4Sopenharmony_ci	 of the host convert the data now.  */
184da0c48c4Sopenharmony_ci      if (ehdr->e_ident[EI_DATA] != MY_ELFDATA)
185da0c48c4Sopenharmony_ci	for (size_t cnt = 0; cnt < shnum; ++cnt)
186da0c48c4Sopenharmony_ci	  {
187da0c48c4Sopenharmony_ci	    CONVERT (shdr[cnt].sh_name);
188da0c48c4Sopenharmony_ci	    CONVERT (shdr[cnt].sh_type);
189da0c48c4Sopenharmony_ci	    CONVERT (shdr[cnt].sh_flags);
190da0c48c4Sopenharmony_ci	    CONVERT (shdr[cnt].sh_addr);
191da0c48c4Sopenharmony_ci	    CONVERT (shdr[cnt].sh_offset);
192da0c48c4Sopenharmony_ci	    CONVERT (shdr[cnt].sh_size);
193da0c48c4Sopenharmony_ci	    CONVERT (shdr[cnt].sh_link);
194da0c48c4Sopenharmony_ci	    CONVERT (shdr[cnt].sh_info);
195da0c48c4Sopenharmony_ci	    CONVERT (shdr[cnt].sh_addralign);
196da0c48c4Sopenharmony_ci	    CONVERT (shdr[cnt].sh_entsize);
197da0c48c4Sopenharmony_ci	  }
198da0c48c4Sopenharmony_ci    }
199da0c48c4Sopenharmony_ci  else
200da0c48c4Sopenharmony_ci    {
201da0c48c4Sopenharmony_ci      /* The file descriptor was already enabled and not all data was
202da0c48c4Sopenharmony_ci	 read.  Undo the allocation.  */
203da0c48c4Sopenharmony_ci      __libelf_seterrno (ELF_E_FD_DISABLED);
204da0c48c4Sopenharmony_ci
205da0c48c4Sopenharmony_ci    free_and_out:
206da0c48c4Sopenharmony_ci      free (shdr);
207da0c48c4Sopenharmony_ci      elf->state.ELFW(elf,LIBELFBITS).shdr = NULL;
208da0c48c4Sopenharmony_ci      elf->state.ELFW(elf,LIBELFBITS).shdr_malloced = 0;
209da0c48c4Sopenharmony_ci
210da0c48c4Sopenharmony_ci      goto out;
211da0c48c4Sopenharmony_ci    }
212da0c48c4Sopenharmony_ci
213da0c48c4Sopenharmony_ci  /* Set the pointers in the `scn's.  */
214da0c48c4Sopenharmony_ci  for (size_t cnt = 0; cnt < shnum; ++cnt)
215da0c48c4Sopenharmony_ci    elf->state.ELFW(elf,LIBELFBITS).scns.data[cnt].shdr.ELFW(e,LIBELFBITS)
216da0c48c4Sopenharmony_ci      = &elf->state.ELFW(elf,LIBELFBITS).shdr[cnt];
217da0c48c4Sopenharmony_ci
218da0c48c4Sopenharmony_ci  result = scn->shdr.ELFW(e,LIBELFBITS);
219da0c48c4Sopenharmony_ci  assert (result != NULL);
220da0c48c4Sopenharmony_ci
221da0c48c4Sopenharmony_ciout:
222da0c48c4Sopenharmony_ci  return result;
223da0c48c4Sopenharmony_ci}
224da0c48c4Sopenharmony_ci
225da0c48c4Sopenharmony_cistatic bool
226da0c48c4Sopenharmony_ciscn_valid (Elf_Scn *scn)
227da0c48c4Sopenharmony_ci{
228da0c48c4Sopenharmony_ci  if (scn == NULL)
229da0c48c4Sopenharmony_ci    return false;
230da0c48c4Sopenharmony_ci
231da0c48c4Sopenharmony_ci  if (unlikely (scn->elf->state.elf.ehdr == NULL))
232da0c48c4Sopenharmony_ci    {
233da0c48c4Sopenharmony_ci      __libelf_seterrno (ELF_E_WRONG_ORDER_EHDR);
234da0c48c4Sopenharmony_ci      return false;
235da0c48c4Sopenharmony_ci    }
236da0c48c4Sopenharmony_ci
237da0c48c4Sopenharmony_ci  if (unlikely (scn->elf->class != ELFW(ELFCLASS,LIBELFBITS)))
238da0c48c4Sopenharmony_ci    {
239da0c48c4Sopenharmony_ci      __libelf_seterrno (ELF_E_INVALID_CLASS);
240da0c48c4Sopenharmony_ci      return false;
241da0c48c4Sopenharmony_ci    }
242da0c48c4Sopenharmony_ci
243da0c48c4Sopenharmony_ci  return true;
244da0c48c4Sopenharmony_ci}
245da0c48c4Sopenharmony_ci
246da0c48c4Sopenharmony_ciElfW2(LIBELFBITS,Shdr) *
247da0c48c4Sopenharmony_ciinternal_function
248da0c48c4Sopenharmony_ci__elfw2(LIBELFBITS,getshdr_rdlock) (Elf_Scn *scn)
249da0c48c4Sopenharmony_ci{
250da0c48c4Sopenharmony_ci  ElfW2(LIBELFBITS,Shdr) *result;
251da0c48c4Sopenharmony_ci
252da0c48c4Sopenharmony_ci  if (!scn_valid (scn))
253da0c48c4Sopenharmony_ci    return NULL;
254da0c48c4Sopenharmony_ci
255da0c48c4Sopenharmony_ci  result = scn->shdr.ELFW(e,LIBELFBITS);
256da0c48c4Sopenharmony_ci  if (result == NULL)
257da0c48c4Sopenharmony_ci    {
258da0c48c4Sopenharmony_ci      rwlock_unlock (scn->elf->lock);
259da0c48c4Sopenharmony_ci      rwlock_wrlock (scn->elf->lock);
260da0c48c4Sopenharmony_ci      result = scn->shdr.ELFW(e,LIBELFBITS);
261da0c48c4Sopenharmony_ci      if (result == NULL)
262da0c48c4Sopenharmony_ci	result = load_shdr_wrlock (scn);
263da0c48c4Sopenharmony_ci    }
264da0c48c4Sopenharmony_ci
265da0c48c4Sopenharmony_ci  return result;
266da0c48c4Sopenharmony_ci}
267da0c48c4Sopenharmony_ci
268da0c48c4Sopenharmony_ciElfW2(LIBELFBITS,Shdr) *
269da0c48c4Sopenharmony_ciinternal_function
270da0c48c4Sopenharmony_ci__elfw2(LIBELFBITS,getshdr_wrlock) (Elf_Scn *scn)
271da0c48c4Sopenharmony_ci{
272da0c48c4Sopenharmony_ci  ElfW2(LIBELFBITS,Shdr) *result;
273da0c48c4Sopenharmony_ci
274da0c48c4Sopenharmony_ci  if (!scn_valid (scn))
275da0c48c4Sopenharmony_ci    return NULL;
276da0c48c4Sopenharmony_ci
277da0c48c4Sopenharmony_ci  result = scn->shdr.ELFW(e,LIBELFBITS);
278da0c48c4Sopenharmony_ci  if (result == NULL)
279da0c48c4Sopenharmony_ci    result = load_shdr_wrlock (scn);
280da0c48c4Sopenharmony_ci
281da0c48c4Sopenharmony_ci  return result;
282da0c48c4Sopenharmony_ci}
283da0c48c4Sopenharmony_ci
284da0c48c4Sopenharmony_ciElfW2(LIBELFBITS,Shdr) *
285da0c48c4Sopenharmony_cielfw2(LIBELFBITS,getshdr) (Elf_Scn *scn)
286da0c48c4Sopenharmony_ci{
287da0c48c4Sopenharmony_ci  ElfW2(LIBELFBITS,Shdr) *result;
288da0c48c4Sopenharmony_ci
289da0c48c4Sopenharmony_ci  if (!scn_valid (scn))
290da0c48c4Sopenharmony_ci    return NULL;
291da0c48c4Sopenharmony_ci
292da0c48c4Sopenharmony_ci  rwlock_rdlock (scn->elf->lock);
293da0c48c4Sopenharmony_ci  result = __elfw2(LIBELFBITS,getshdr_rdlock) (scn);
294da0c48c4Sopenharmony_ci  rwlock_unlock (scn->elf->lock);
295da0c48c4Sopenharmony_ci
296da0c48c4Sopenharmony_ci  return result;
297da0c48c4Sopenharmony_ci}
298