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