1/* Return section index of section header string table.
2   Copyright (C) 2002 Red Hat, Inc.
3   Written by Ulrich Drepper <drepper@redhat.com>, 2002.
4
5   This program is free software; you can redistribute it and/or modify
6   it under the terms of the GNU General Public License as published by
7   the Free Software Foundation, version 2.
8
9   This program is distributed in the hope that it will be useful,
10   but WITHOUT ANY WARRANTY; without even the implied warranty of
11   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12   GNU General Public License for more details.
13
14   You should have received a copy of the GNU General Public License
15   along with this program; if not, write to the Free Software Foundation,
16   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
17
18#ifdef HAVE_CONFIG_H
19# include <config.h>
20#endif
21
22#include <assert.h>
23#include <gelf.h>
24#include <stddef.h>
25#include <unistd.h>
26
27#include "libelfP.h"
28#include "common.h"
29
30
31int
32elf_getshstrndx (elf, dst)
33     Elf *elf;
34     size_t *dst;
35{
36  int result = 0;
37
38  if (elf == NULL)
39    return -1;
40
41  if (unlikely (elf->kind != ELF_K_ELF))
42    {
43      __libelf_seterrno (ELF_E_INVALID_HANDLE);
44      return -1;
45    }
46
47  rwlock_rdlock (elf->lock);
48
49  /* We rely here on the fact that the `elf' element is a common prefix
50     of `elf32' and `elf64'.  */
51  assert (offsetof (struct Elf, state.elf.ehdr)
52	  == offsetof (struct Elf, state.elf32.ehdr));
53  assert (sizeof (elf->state.elf.ehdr)
54	  == sizeof (elf->state.elf32.ehdr));
55  assert (offsetof (struct Elf, state.elf.ehdr)
56	  == offsetof (struct Elf, state.elf64.ehdr));
57  assert (sizeof (elf->state.elf.ehdr)
58	  == sizeof (elf->state.elf64.ehdr));
59
60  if (unlikely (elf->state.elf.ehdr == NULL))
61    {
62      __libelf_seterrno (ELF_E_WRONG_ORDER_EHDR);
63      result = -1;
64    }
65  else
66    {
67      Elf32_Word num;
68
69      num = (elf->class == ELFCLASS32
70	     ? elf->state.elf32.ehdr->e_shstrndx
71	     : elf->state.elf64.ehdr->e_shstrndx);
72
73      /* Determine whether the index is too big to fit in the ELF
74	 header.  */
75      if (unlikely (num == SHN_XINDEX))
76	{
77	  /* Yes.  Search the zeroth section header.  */
78	  if (elf->class == ELFCLASS32)
79	    {
80	      size_t offset;
81
82	      if (elf->state.elf32.scns.data[0].shdr.e32 != NULL)
83		{
84		  num = elf->state.elf32.scns.data[0].shdr.e32->sh_link;
85		  goto success;
86		}
87
88	      offset = elf->state.elf32.ehdr->e_shoff;
89
90	      if (elf->map_address != NULL
91		  && elf->state.elf32.ehdr->e_ident[EI_DATA] == MY_ELFDATA
92		  && (ALLOW_UNALIGNED
93		      || (((size_t) ((char *) elf->map_address + offset))
94			  & (__alignof__ (Elf32_Shdr) - 1)) == 0))
95		/* We can directly access the memory.  */
96		num = ((Elf32_Shdr *) (elf->map_address + offset))->sh_link;
97	      else
98		{
99		  /* We avoid reading in all the section headers.  Just read
100		     the first one.  */
101		  Elf32_Shdr shdr_mem;
102
103		  if (pread (elf->fildes, &shdr_mem, sizeof (Elf32_Shdr),
104			     offset) != sizeof (Elf32_Shdr))
105		    {
106		      /* We must be able to read this ELF section header.  */
107		      __libelf_seterrno (ELF_E_INVALID_FILE);
108		      result = -1;
109		      goto out;
110		    }
111
112		  if (elf->state.elf32.ehdr->e_ident[EI_DATA] != MY_ELFDATA)
113		    CONVERT (shdr_mem.sh_link);
114		  num = shdr_mem.sh_link;
115		}
116	    }
117	  else
118	    {
119	      size_t offset;
120
121	      if (elf->state.elf64.scns.data[0].shdr.e64 != NULL)
122		{
123		  num = elf->state.elf64.scns.data[0].shdr.e64->sh_link;
124		  goto success;
125		}
126
127	      offset = elf->state.elf64.ehdr->e_shoff;
128
129	      if (elf->map_address != NULL
130		  && elf->state.elf64.ehdr->e_ident[EI_DATA] == MY_ELFDATA
131		  && (ALLOW_UNALIGNED
132		      || (((size_t) ((char *) elf->map_address + offset))
133			  & (__alignof__ (Elf64_Shdr) - 1)) == 0))
134		/* We can directly access the memory.  */
135		num = ((Elf64_Shdr *) (elf->map_address + offset))->sh_link;
136	      else
137		{
138		  /* We avoid reading in all the section headers.  Just read
139		     the first one.  */
140		  Elf64_Shdr shdr_mem;
141
142		  if (pread (elf->fildes, &shdr_mem, sizeof (Elf64_Shdr),
143			     offset) != sizeof (Elf64_Shdr))
144		    {
145		      /* We must be able to read this ELF section header.  */
146		      __libelf_seterrno (ELF_E_INVALID_FILE);
147		      result = -1;
148		      goto out;
149		    }
150
151		  if (elf->state.elf64.ehdr->e_ident[EI_DATA] != MY_ELFDATA)
152		    CONVERT (shdr_mem.sh_link);
153		  num = shdr_mem.sh_link;
154		}
155	    }
156	}
157
158      /* Store the result.  */
159    success:
160      *dst = num;
161    }
162
163 out:
164  rwlock_unlock (elf->lock);
165
166  return result;
167}
168INTDEF(elf_getshstrndx)
169