1/* Return section index of section header string table.
2   Copyright (C) 2002, 2005, 2009, 2014, 2015 Red Hat, Inc.
3   This file is part of elfutils.
4   Written by Ulrich Drepper <drepper@redhat.com>, 2002.
5
6   This file is free software; you can redistribute it and/or modify
7   it under the terms of either
8
9     * the GNU Lesser General Public License as published by the Free
10       Software Foundation; either version 3 of the License, or (at
11       your option) any later version
12
13   or
14
15     * the GNU General Public License as published by the Free
16       Software Foundation; either version 2 of the License, or (at
17       your option) any later version
18
19   or both in parallel, as here.
20
21   elfutils is distributed in the hope that it will be useful, but
22   WITHOUT ANY WARRANTY; without even the implied warranty of
23   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
24   General Public License for more details.
25
26   You should have received copies of the GNU General Public License and
27   the GNU Lesser General Public License along with this program.  If
28   not, see <http://www.gnu.org/licenses/>.  */
29
30#ifdef HAVE_CONFIG_H
31# include <config.h>
32#endif
33
34#include <assert.h>
35#include <errno.h>
36#include <gelf.h>
37#include <stddef.h>
38#include <unistd.h>
39
40#include <system.h>
41#include "libelfP.h"
42#include "common.h"
43
44
45int
46elf_getshdrstrndx (Elf *elf, size_t *dst)
47{
48  int result = 0;
49
50  if (elf == NULL)
51    return -1;
52
53  if (unlikely (elf->kind != ELF_K_ELF))
54    {
55      __libelf_seterrno (ELF_E_INVALID_HANDLE);
56      return -1;
57    }
58
59  rwlock_rdlock (elf->lock);
60
61  /* We rely here on the fact that the `elf' element is a common prefix
62     of `elf32' and `elf64'.  */
63  assert (offsetof (struct Elf, state.elf.ehdr)
64	  == offsetof (struct Elf, state.elf32.ehdr));
65  assert (sizeof (elf->state.elf.ehdr)
66	  == sizeof (elf->state.elf32.ehdr));
67  assert (offsetof (struct Elf, state.elf.ehdr)
68	  == offsetof (struct Elf, state.elf64.ehdr));
69  assert (sizeof (elf->state.elf.ehdr)
70	  == sizeof (elf->state.elf64.ehdr));
71
72  if (unlikely (elf->state.elf.ehdr == NULL))
73    {
74      __libelf_seterrno (ELF_E_WRONG_ORDER_EHDR);
75      result = -1;
76    }
77  else
78    {
79      Elf32_Word num;
80
81      num = (elf->class == ELFCLASS32
82	     ? elf->state.elf32.ehdr->e_shstrndx
83	     : elf->state.elf64.ehdr->e_shstrndx);
84
85      /* Determine whether the index is too big to fit in the ELF
86	 header.  */
87      if (unlikely (num == SHN_XINDEX))
88	{
89	  /* Yes.  Search the zeroth section header.  */
90	  if (elf->class == ELFCLASS32)
91	    {
92	      size_t offset;
93	      if (unlikely (elf->state.elf32.scns.cnt == 0))
94		{
95		  /* Cannot use SHN_XINDEX without section headers.  */
96		  __libelf_seterrno (ELF_E_INVALID_SECTION_HEADER);
97		  result = -1;
98		  goto out;
99		}
100
101	      if (elf->state.elf32.scns.data[0].shdr.e32 != NULL)
102		{
103		  num = elf->state.elf32.scns.data[0].shdr.e32->sh_link;
104		  goto success;
105		}
106
107	      offset = elf->state.elf32.ehdr->e_shoff;
108
109	      if (elf->map_address != NULL
110		  && elf->state.elf32.ehdr->e_ident[EI_DATA] == MY_ELFDATA
111		  && (ALLOW_UNALIGNED
112		      || (((size_t) ((char *) elf->map_address
113			   + elf->start_offset + offset))
114			  & (__alignof__ (Elf32_Shdr) - 1)) == 0))
115		{
116		  /* First see whether the information in the ELF header is
117		     valid and it does not ask for too much.  */
118		  if (unlikely (elf->maximum_size - offset
119				< sizeof (Elf32_Shdr)))
120		    {
121		      /* Something is wrong.  */
122		      __libelf_seterrno (ELF_E_INVALID_SECTION_HEADER);
123		      result = -1;
124		      goto out;
125		    }
126
127		  /* We can directly access the memory.  */
128		  num = ((Elf32_Shdr *) (elf->map_address + elf->start_offset
129					 + offset))->sh_link;
130		}
131	      else
132		{
133		  /* We avoid reading in all the section headers.  Just read
134		     the first one.  */
135		  Elf32_Shdr shdr_mem;
136
137		  if (unlikely (pread_retry (elf->fildes, &shdr_mem,
138					     sizeof (Elf32_Shdr), offset)
139				!= sizeof (Elf32_Shdr)))
140		    {
141		      /* We must be able to read this ELF section header.  */
142		      __libelf_seterrno (ELF_E_INVALID_FILE);
143		      result = -1;
144		      goto out;
145		    }
146
147		  if (elf->state.elf32.ehdr->e_ident[EI_DATA] != MY_ELFDATA)
148		    CONVERT (shdr_mem.sh_link);
149		  num = shdr_mem.sh_link;
150		}
151	    }
152	  else
153	    {
154	      if (unlikely (elf->state.elf64.scns.cnt == 0))
155		{
156		  /* Cannot use SHN_XINDEX without section headers.  */
157		  __libelf_seterrno (ELF_E_INVALID_SECTION_HEADER);
158		  result = -1;
159		  goto out;
160		}
161
162	      if (elf->state.elf64.scns.data[0].shdr.e64 != NULL)
163		{
164		  num = elf->state.elf64.scns.data[0].shdr.e64->sh_link;
165		  goto success;
166		}
167
168	      size_t offset = elf->state.elf64.ehdr->e_shoff;
169
170	      if (elf->map_address != NULL
171		  && elf->state.elf64.ehdr->e_ident[EI_DATA] == MY_ELFDATA
172		  && (ALLOW_UNALIGNED
173		      || (((size_t) ((char *) elf->map_address
174			   + elf->start_offset + offset))
175			  & (__alignof__ (Elf64_Shdr) - 1)) == 0))
176		{
177		  /* First see whether the information in the ELF header is
178		     valid and it does not ask for too much.  */
179		  if (unlikely (elf->maximum_size - offset
180				< sizeof (Elf64_Shdr)))
181		    {
182		      /* Something is wrong.  */
183		      __libelf_seterrno (ELF_E_INVALID_SECTION_HEADER);
184		      result = -1;
185		      goto out;
186		    }
187
188		  /* We can directly access the memory.  */
189		  num = ((Elf64_Shdr *) (elf->map_address + elf->start_offset
190					 + offset))->sh_link;
191		}
192	      else
193		{
194		  /* We avoid reading in all the section headers.  Just read
195		     the first one.  */
196		  Elf64_Shdr shdr_mem;
197
198		  if (unlikely (pread_retry (elf->fildes, &shdr_mem,
199					     sizeof (Elf64_Shdr), offset)
200				!= sizeof (Elf64_Shdr)))
201		    {
202		      /* We must be able to read this ELF section header.  */
203		      __libelf_seterrno (ELF_E_INVALID_FILE);
204		      result = -1;
205		      goto out;
206		    }
207
208		  if (elf->state.elf64.ehdr->e_ident[EI_DATA] != MY_ELFDATA)
209		    CONVERT (shdr_mem.sh_link);
210		  num = shdr_mem.sh_link;
211		}
212	    }
213	}
214
215      /* Store the result.  */
216    success:
217      *dst = num;
218    }
219
220 out:
221  rwlock_unlock (elf->lock);
222
223  return result;
224}
225INTDEF(elf_getshdrstrndx)
226/* Alias for the deprecated name.  */
227strong_alias (elf_getshdrstrndx, elf_getshstrndx)
228