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
45 int
elf_getshdrstrndx(Elf * elf,size_t * dst)46 elf_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 ssize_t r;
137
138 if (unlikely ((r = pread_retry (elf->fildes, &shdr_mem,
139 sizeof (Elf32_Shdr), offset))
140 != sizeof (Elf32_Shdr)))
141 {
142 /* We must be able to read this ELF section header. */
143 if (r < 0)
144 __libelf_seterrno (ELF_E_INVALID_FILE);
145 else
146 __libelf_seterrno (ELF_E_INVALID_ELF);
147 result = -1;
148 goto out;
149 }
150
151 if (elf->state.elf32.ehdr->e_ident[EI_DATA] != MY_ELFDATA)
152 CONVERT (shdr_mem.sh_link);
153 num = shdr_mem.sh_link;
154 }
155 }
156 else
157 {
158 if (unlikely (elf->state.elf64.scns.cnt == 0))
159 {
160 /* Cannot use SHN_XINDEX without section headers. */
161 __libelf_seterrno (ELF_E_INVALID_SECTION_HEADER);
162 result = -1;
163 goto out;
164 }
165
166 if (elf->state.elf64.scns.data[0].shdr.e64 != NULL)
167 {
168 num = elf->state.elf64.scns.data[0].shdr.e64->sh_link;
169 goto success;
170 }
171
172 size_t offset = elf->state.elf64.ehdr->e_shoff;
173
174 if (elf->map_address != NULL
175 && elf->state.elf64.ehdr->e_ident[EI_DATA] == MY_ELFDATA
176 && (ALLOW_UNALIGNED
177 || (((size_t) ((char *) elf->map_address
178 + elf->start_offset + offset))
179 & (__alignof__ (Elf64_Shdr) - 1)) == 0))
180 {
181 /* First see whether the information in the ELF header is
182 valid and it does not ask for too much. */
183 if (unlikely (elf->maximum_size - offset
184 < sizeof (Elf64_Shdr)))
185 {
186 /* Something is wrong. */
187 __libelf_seterrno (ELF_E_INVALID_SECTION_HEADER);
188 result = -1;
189 goto out;
190 }
191
192 /* We can directly access the memory. */
193 num = ((Elf64_Shdr *) (elf->map_address + elf->start_offset
194 + offset))->sh_link;
195 }
196 else
197 {
198 /* We avoid reading in all the section headers. Just read
199 the first one. */
200 Elf64_Shdr shdr_mem;
201 ssize_t r;
202
203 if (unlikely ((r = pread_retry (elf->fildes, &shdr_mem,
204 sizeof (Elf64_Shdr), offset))
205 != sizeof (Elf64_Shdr)))
206 {
207 /* We must be able to read this ELF section header. */
208 if (r < 0)
209 __libelf_seterrno (ELF_E_INVALID_FILE);
210 else
211 __libelf_seterrno (ELF_E_INVALID_ELF);
212 result = -1;
213 goto out;
214 }
215
216 if (elf->state.elf64.ehdr->e_ident[EI_DATA] != MY_ELFDATA)
217 CONVERT (shdr_mem.sh_link);
218 num = shdr_mem.sh_link;
219 }
220 }
221 }
222
223 /* Store the result. */
224 success:
225 *dst = num;
226 }
227
228 out:
229 rwlock_unlock (elf->lock);
230
231 return result;
232 }
233 INTDEF(elf_getshdrstrndx)
234 /* Alias for the deprecated name. */
235 strong_alias (elf_getshdrstrndx, elf_getshstrndx)
236