1da0c48c4Sopenharmony_ci/* Return section index of section header string table.
2da0c48c4Sopenharmony_ci   Copyright (C) 2002, 2005, 2009, 2014, 2015 Red Hat, Inc.
3da0c48c4Sopenharmony_ci   This file is part of elfutils.
4da0c48c4Sopenharmony_ci   Written by Ulrich Drepper <drepper@redhat.com>, 2002.
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 <gelf.h>
37da0c48c4Sopenharmony_ci#include <stddef.h>
38da0c48c4Sopenharmony_ci
39da0c48c4Sopenharmony_ci#include "libelfP.h"
40da0c48c4Sopenharmony_ci#include "common.h"
41da0c48c4Sopenharmony_ci
42da0c48c4Sopenharmony_ci
43da0c48c4Sopenharmony_ciint
44da0c48c4Sopenharmony_cielf_getshdrstrndx (Elf *elf, size_t *dst)
45da0c48c4Sopenharmony_ci{
46da0c48c4Sopenharmony_ci  int result = 0;
47da0c48c4Sopenharmony_ci
48da0c48c4Sopenharmony_ci  if (elf == NULL)
49da0c48c4Sopenharmony_ci    return -1;
50da0c48c4Sopenharmony_ci
51da0c48c4Sopenharmony_ci  if (unlikely (elf->kind != ELF_K_ELF))
52da0c48c4Sopenharmony_ci    {
53da0c48c4Sopenharmony_ci      __libelf_seterrno (ELF_E_INVALID_HANDLE);
54da0c48c4Sopenharmony_ci      return -1;
55da0c48c4Sopenharmony_ci    }
56da0c48c4Sopenharmony_ci
57da0c48c4Sopenharmony_ci  rwlock_rdlock (elf->lock);
58da0c48c4Sopenharmony_ci
59da0c48c4Sopenharmony_ci  /* We rely here on the fact that the `elf' element is a common prefix
60da0c48c4Sopenharmony_ci     of `elf32' and `elf64'.  */
61da0c48c4Sopenharmony_ci  assert (offsetof (struct Elf, state.elf.ehdr)
62da0c48c4Sopenharmony_ci	  == offsetof (struct Elf, state.elf32.ehdr));
63da0c48c4Sopenharmony_ci  assert (sizeof (elf->state.elf.ehdr)
64da0c48c4Sopenharmony_ci	  == sizeof (elf->state.elf32.ehdr));
65da0c48c4Sopenharmony_ci  assert (offsetof (struct Elf, state.elf.ehdr)
66da0c48c4Sopenharmony_ci	  == offsetof (struct Elf, state.elf64.ehdr));
67da0c48c4Sopenharmony_ci  assert (sizeof (elf->state.elf.ehdr)
68da0c48c4Sopenharmony_ci	  == sizeof (elf->state.elf64.ehdr));
69da0c48c4Sopenharmony_ci
70da0c48c4Sopenharmony_ci  if (unlikely (elf->state.elf.ehdr == NULL))
71da0c48c4Sopenharmony_ci    {
72da0c48c4Sopenharmony_ci      __libelf_seterrno (ELF_E_WRONG_ORDER_EHDR);
73da0c48c4Sopenharmony_ci      result = -1;
74da0c48c4Sopenharmony_ci    }
75da0c48c4Sopenharmony_ci  else
76da0c48c4Sopenharmony_ci    {
77da0c48c4Sopenharmony_ci      Elf32_Word num;
78da0c48c4Sopenharmony_ci
79da0c48c4Sopenharmony_ci      num = (elf->class == ELFCLASS32
80da0c48c4Sopenharmony_ci	     ? elf->state.elf32.ehdr->e_shstrndx
81da0c48c4Sopenharmony_ci	     : elf->state.elf64.ehdr->e_shstrndx);
82da0c48c4Sopenharmony_ci
83da0c48c4Sopenharmony_ci      /* Determine whether the index is too big to fit in the ELF
84da0c48c4Sopenharmony_ci	 header.  */
85da0c48c4Sopenharmony_ci      if (unlikely (num == SHN_XINDEX))
86da0c48c4Sopenharmony_ci	{
87da0c48c4Sopenharmony_ci	  /* Yes.  Search the zeroth section header.  */
88da0c48c4Sopenharmony_ci	  if (elf->class == ELFCLASS32)
89da0c48c4Sopenharmony_ci	    {
90da0c48c4Sopenharmony_ci	      size_t offset;
91da0c48c4Sopenharmony_ci	      if (unlikely (elf->state.elf32.scns.cnt == 0))
92da0c48c4Sopenharmony_ci		{
93da0c48c4Sopenharmony_ci		  /* Cannot use SHN_XINDEX without section headers.  */
94da0c48c4Sopenharmony_ci		  __libelf_seterrno (ELF_E_INVALID_SECTION_HEADER);
95da0c48c4Sopenharmony_ci		  result = -1;
96da0c48c4Sopenharmony_ci		  goto out;
97da0c48c4Sopenharmony_ci		}
98da0c48c4Sopenharmony_ci
99da0c48c4Sopenharmony_ci	      if (elf->state.elf32.scns.data[0].shdr.e32 != NULL)
100da0c48c4Sopenharmony_ci		{
101da0c48c4Sopenharmony_ci		  num = elf->state.elf32.scns.data[0].shdr.e32->sh_link;
102da0c48c4Sopenharmony_ci		  goto success;
103da0c48c4Sopenharmony_ci		}
104da0c48c4Sopenharmony_ci
105da0c48c4Sopenharmony_ci	      offset = elf->state.elf32.ehdr->e_shoff;
106da0c48c4Sopenharmony_ci
107da0c48c4Sopenharmony_ci	      if (elf->map_address != NULL
108da0c48c4Sopenharmony_ci		  && elf->state.elf32.ehdr->e_ident[EI_DATA] == MY_ELFDATA
109da0c48c4Sopenharmony_ci		  && (ALLOW_UNALIGNED
110da0c48c4Sopenharmony_ci		      || (((size_t) ((char *) elf->map_address
111da0c48c4Sopenharmony_ci			   + elf->start_offset + offset))
112da0c48c4Sopenharmony_ci			  & (__alignof__ (Elf32_Shdr) - 1)) == 0))
113da0c48c4Sopenharmony_ci		{
114da0c48c4Sopenharmony_ci		  /* First see whether the information in the ELF header is
115da0c48c4Sopenharmony_ci		     valid and it does not ask for too much.  */
116da0c48c4Sopenharmony_ci		  if (unlikely (elf->maximum_size - offset
117da0c48c4Sopenharmony_ci				< sizeof (Elf32_Shdr)))
118da0c48c4Sopenharmony_ci		    {
119da0c48c4Sopenharmony_ci		      /* Something is wrong.  */
120da0c48c4Sopenharmony_ci		      __libelf_seterrno (ELF_E_INVALID_SECTION_HEADER);
121da0c48c4Sopenharmony_ci		      result = -1;
122da0c48c4Sopenharmony_ci		      goto out;
123da0c48c4Sopenharmony_ci		    }
124da0c48c4Sopenharmony_ci
125da0c48c4Sopenharmony_ci		  /* We can directly access the memory.  */
126da0c48c4Sopenharmony_ci		  num = ((Elf32_Shdr *) (elf->map_address + elf->start_offset
127da0c48c4Sopenharmony_ci					 + offset))->sh_link;
128da0c48c4Sopenharmony_ci		}
129da0c48c4Sopenharmony_ci	      else
130da0c48c4Sopenharmony_ci		{
131da0c48c4Sopenharmony_ci		  /* We avoid reading in all the section headers.  Just read
132da0c48c4Sopenharmony_ci		     the first one.  */
133da0c48c4Sopenharmony_ci		  Elf32_Shdr shdr_mem;
134da0c48c4Sopenharmony_ci		  ssize_t r;
135da0c48c4Sopenharmony_ci
136da0c48c4Sopenharmony_ci		  if (unlikely ((r = pread_retry (elf->fildes, &shdr_mem,
137da0c48c4Sopenharmony_ci						  sizeof (Elf32_Shdr), offset))
138da0c48c4Sopenharmony_ci				!= sizeof (Elf32_Shdr)))
139da0c48c4Sopenharmony_ci		    {
140da0c48c4Sopenharmony_ci		      /* We must be able to read this ELF section header.  */
141da0c48c4Sopenharmony_ci		      if (r < 0)
142da0c48c4Sopenharmony_ci			__libelf_seterrno (ELF_E_INVALID_FILE);
143da0c48c4Sopenharmony_ci		      else
144da0c48c4Sopenharmony_ci			__libelf_seterrno (ELF_E_INVALID_ELF);
145da0c48c4Sopenharmony_ci		      result = -1;
146da0c48c4Sopenharmony_ci		      goto out;
147da0c48c4Sopenharmony_ci		    }
148da0c48c4Sopenharmony_ci
149da0c48c4Sopenharmony_ci		  if (elf->state.elf32.ehdr->e_ident[EI_DATA] != MY_ELFDATA)
150da0c48c4Sopenharmony_ci		    CONVERT (shdr_mem.sh_link);
151da0c48c4Sopenharmony_ci		  num = shdr_mem.sh_link;
152da0c48c4Sopenharmony_ci		}
153da0c48c4Sopenharmony_ci	    }
154da0c48c4Sopenharmony_ci	  else
155da0c48c4Sopenharmony_ci	    {
156da0c48c4Sopenharmony_ci	      if (unlikely (elf->state.elf64.scns.cnt == 0))
157da0c48c4Sopenharmony_ci		{
158da0c48c4Sopenharmony_ci		  /* Cannot use SHN_XINDEX without section headers.  */
159da0c48c4Sopenharmony_ci		  __libelf_seterrno (ELF_E_INVALID_SECTION_HEADER);
160da0c48c4Sopenharmony_ci		  result = -1;
161da0c48c4Sopenharmony_ci		  goto out;
162da0c48c4Sopenharmony_ci		}
163da0c48c4Sopenharmony_ci
164da0c48c4Sopenharmony_ci	      if (elf->state.elf64.scns.data[0].shdr.e64 != NULL)
165da0c48c4Sopenharmony_ci		{
166da0c48c4Sopenharmony_ci		  num = elf->state.elf64.scns.data[0].shdr.e64->sh_link;
167da0c48c4Sopenharmony_ci		  goto success;
168da0c48c4Sopenharmony_ci		}
169da0c48c4Sopenharmony_ci
170da0c48c4Sopenharmony_ci	      size_t offset = elf->state.elf64.ehdr->e_shoff;
171da0c48c4Sopenharmony_ci
172da0c48c4Sopenharmony_ci	      if (elf->map_address != NULL
173da0c48c4Sopenharmony_ci		  && elf->state.elf64.ehdr->e_ident[EI_DATA] == MY_ELFDATA
174da0c48c4Sopenharmony_ci		  && (ALLOW_UNALIGNED
175da0c48c4Sopenharmony_ci		      || (((size_t) ((char *) elf->map_address
176da0c48c4Sopenharmony_ci			   + elf->start_offset + offset))
177da0c48c4Sopenharmony_ci			  & (__alignof__ (Elf64_Shdr) - 1)) == 0))
178da0c48c4Sopenharmony_ci		{
179da0c48c4Sopenharmony_ci		  /* First see whether the information in the ELF header is
180da0c48c4Sopenharmony_ci		     valid and it does not ask for too much.  */
181da0c48c4Sopenharmony_ci		  if (unlikely (elf->maximum_size - offset
182da0c48c4Sopenharmony_ci				< sizeof (Elf64_Shdr)))
183da0c48c4Sopenharmony_ci		    {
184da0c48c4Sopenharmony_ci		      /* Something is wrong.  */
185da0c48c4Sopenharmony_ci		      __libelf_seterrno (ELF_E_INVALID_SECTION_HEADER);
186da0c48c4Sopenharmony_ci		      result = -1;
187da0c48c4Sopenharmony_ci		      goto out;
188da0c48c4Sopenharmony_ci		    }
189da0c48c4Sopenharmony_ci
190da0c48c4Sopenharmony_ci		  /* We can directly access the memory.  */
191da0c48c4Sopenharmony_ci		  num = ((Elf64_Shdr *) (elf->map_address + elf->start_offset
192da0c48c4Sopenharmony_ci					 + offset))->sh_link;
193da0c48c4Sopenharmony_ci		}
194da0c48c4Sopenharmony_ci	      else
195da0c48c4Sopenharmony_ci		{
196da0c48c4Sopenharmony_ci		  /* We avoid reading in all the section headers.  Just read
197da0c48c4Sopenharmony_ci		     the first one.  */
198da0c48c4Sopenharmony_ci		  Elf64_Shdr shdr_mem;
199da0c48c4Sopenharmony_ci		  ssize_t r;
200da0c48c4Sopenharmony_ci
201da0c48c4Sopenharmony_ci		  if (unlikely ((r = pread_retry (elf->fildes, &shdr_mem,
202da0c48c4Sopenharmony_ci						  sizeof (Elf64_Shdr), offset))
203da0c48c4Sopenharmony_ci				!= sizeof (Elf64_Shdr)))
204da0c48c4Sopenharmony_ci		    {
205da0c48c4Sopenharmony_ci		      /* We must be able to read this ELF section header.  */
206da0c48c4Sopenharmony_ci		      if (r < 0)
207da0c48c4Sopenharmony_ci			__libelf_seterrno (ELF_E_INVALID_FILE);
208da0c48c4Sopenharmony_ci		      else
209da0c48c4Sopenharmony_ci			__libelf_seterrno (ELF_E_INVALID_ELF);
210da0c48c4Sopenharmony_ci		      result = -1;
211da0c48c4Sopenharmony_ci		      goto out;
212da0c48c4Sopenharmony_ci		    }
213da0c48c4Sopenharmony_ci
214da0c48c4Sopenharmony_ci		  if (elf->state.elf64.ehdr->e_ident[EI_DATA] != MY_ELFDATA)
215da0c48c4Sopenharmony_ci		    CONVERT (shdr_mem.sh_link);
216da0c48c4Sopenharmony_ci		  num = shdr_mem.sh_link;
217da0c48c4Sopenharmony_ci		}
218da0c48c4Sopenharmony_ci	    }
219da0c48c4Sopenharmony_ci	}
220da0c48c4Sopenharmony_ci
221da0c48c4Sopenharmony_ci      /* Store the result.  */
222da0c48c4Sopenharmony_ci    success:
223da0c48c4Sopenharmony_ci      *dst = num;
224da0c48c4Sopenharmony_ci    }
225da0c48c4Sopenharmony_ci
226da0c48c4Sopenharmony_ci out:
227da0c48c4Sopenharmony_ci  rwlock_unlock (elf->lock);
228da0c48c4Sopenharmony_ci
229da0c48c4Sopenharmony_ci  return result;
230da0c48c4Sopenharmony_ci}
231da0c48c4Sopenharmony_ciINTDEF(elf_getshdrstrndx)
232da0c48c4Sopenharmony_ci/* Alias for the deprecated name.  */
233da0c48c4Sopenharmony_cistrong_alias (elf_getshdrstrndx, elf_getshstrndx)
234