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