]>
Commit | Line | Data |
---|---|---|
b08d5a8f | 1 | /* Return section header. |
1ccdfb68 | 2 | Copyright (C) 1998-2002, 2005, 2007, 2009, 2012, 2014, 2015 Red Hat, Inc. |
de2ed97f | 3 | This file is part of elfutils. |
b08d5a8f UD |
4 | Written by Ulrich Drepper <drepper@redhat.com>, 1998. |
5 | ||
de2ed97f MW |
6 | This file is free software; you can redistribute it and/or modify |
7 | it under the terms of either | |
b08d5a8f | 8 | |
de2ed97f MW |
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 | |
361df7da UD |
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. | |
b08d5a8f | 25 | |
de2ed97f MW |
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/>. */ | |
b08d5a8f UD |
29 | |
30 | #ifdef HAVE_CONFIG_H | |
31 | # include <config.h> | |
32 | #endif | |
33 | ||
34 | #include <assert.h> | |
fbe998a0 | 35 | #include <errno.h> |
b4d6f0f8 | 36 | #include <stdbool.h> |
b08d5a8f UD |
37 | |
38 | #include "libelfP.h" | |
39 | #include "common.h" | |
40 | ||
41 | #ifndef LIBELFBITS | |
42 | # define LIBELFBITS 32 | |
43 | #endif | |
44 | ||
45 | ||
b4d6f0f8 | 46 | static ElfW2(LIBELFBITS,Shdr) * |
02f66452 | 47 | load_shdr_wrlock (Elf_Scn *scn) |
b08d5a8f UD |
48 | { |
49 | ElfW2(LIBELFBITS,Shdr) *result; | |
50 | ||
b4d6f0f8 RM |
51 | /* Read the section header table. */ |
52 | Elf *elf = scn->elf; | |
53 | ElfW2(LIBELFBITS,Ehdr) *ehdr = elf->state.ELFW(elf,LIBELFBITS).ehdr; | |
b08d5a8f | 54 | |
b4d6f0f8 RM |
55 | /* Try again, maybe the data is there now. */ |
56 | result = scn->shdr.ELFW(e,LIBELFBITS); | |
57 | if (result != NULL) | |
58 | goto out; | |
59 | ||
60 | size_t shnum; | |
720383c5 JJ |
61 | if (__elf_getshdrnum_rdlock (elf, &shnum) != 0 |
62 | || shnum > SIZE_MAX / sizeof (ElfW2(LIBELFBITS,Shdr))) | |
b4d6f0f8 RM |
63 | goto out; |
64 | size_t size = shnum * sizeof (ElfW2(LIBELFBITS,Shdr)); | |
65 | ||
66 | /* Allocate memory for the section headers. We know the number | |
67 | of entries from the ELF header. */ | |
68 | ElfW2(LIBELFBITS,Shdr) *shdr = elf->state.ELFW(elf,LIBELFBITS).shdr = | |
69 | (ElfW2(LIBELFBITS,Shdr) *) malloc (size); | |
70 | if (elf->state.ELFW(elf,LIBELFBITS).shdr == NULL) | |
b08d5a8f | 71 | { |
b4d6f0f8 RM |
72 | __libelf_seterrno (ELF_E_NOMEM); |
73 | goto out; | |
b08d5a8f | 74 | } |
b4d6f0f8 | 75 | elf->state.ELFW(elf,LIBELFBITS).shdr_malloced = 1; |
b08d5a8f | 76 | |
b4d6f0f8 | 77 | if (elf->map_address != NULL) |
b08d5a8f | 78 | { |
720383c5 JJ |
79 | /* First see whether the information in the ELF header is |
80 | valid and it does not ask for too much. */ | |
81 | if (unlikely (ehdr->e_shoff >= elf->maximum_size) | |
82 | || unlikely (elf->maximum_size - ehdr->e_shoff < size)) | |
83 | { | |
84 | /* Something is wrong. */ | |
85 | __libelf_seterrno (ELF_E_INVALID_SECTION_HEADER); | |
86 | goto free_and_out; | |
87 | } | |
88 | ||
b4d6f0f8 | 89 | ElfW2(LIBELFBITS,Shdr) *notcvt; |
b08d5a8f | 90 | |
b4d6f0f8 | 91 | /* All the data is already mapped. If we could use it |
030f626f MW |
92 | directly this would already have happened. Unless |
93 | we allocated the memory ourselves and the ELF_F_MALLOCED | |
94 | flag is set. */ | |
b4d6f0f8 RM |
95 | void *file_shdr = ((char *) elf->map_address |
96 | + elf->start_offset + ehdr->e_shoff); | |
b08d5a8f | 97 | |
030f626f MW |
98 | assert ((elf->flags & ELF_F_MALLOCED) |
99 | || ehdr->e_ident[EI_DATA] != MY_ELFDATA | |
272018bb | 100 | || elf->cmd == ELF_C_READ_MMAP |
b4d6f0f8 RM |
101 | || (! ALLOW_UNALIGNED |
102 | && ((uintptr_t) file_shdr | |
103 | & (__alignof__ (ElfW2(LIBELFBITS,Shdr)) - 1)) != 0)); | |
b08d5a8f | 104 | |
b4d6f0f8 RM |
105 | /* Now copy the data and at the same time convert the byte order. */ |
106 | if (ehdr->e_ident[EI_DATA] == MY_ELFDATA) | |
b08d5a8f | 107 | { |
272018bb MW |
108 | assert ((elf->flags & ELF_F_MALLOCED) |
109 | || elf->cmd == ELF_C_READ_MMAP | |
110 | || ! ALLOW_UNALIGNED); | |
b4d6f0f8 | 111 | memcpy (shdr, file_shdr, size); |
b08d5a8f | 112 | } |
b4d6f0f8 | 113 | else |
b08d5a8f | 114 | { |
96f6c995 MW |
115 | bool copy = ! (ALLOW_UNALIGNED |
116 | || ((uintptr_t) file_shdr | |
117 | & (__alignof__ (ElfW2(LIBELFBITS,Shdr)) - 1)) | |
118 | == 0); | |
119 | if (! copy) | |
b4d6f0f8 RM |
120 | notcvt = (ElfW2(LIBELFBITS,Shdr) *) |
121 | ((char *) elf->map_address | |
122 | + elf->start_offset + ehdr->e_shoff); | |
aa915fd3 | 123 | else |
b08d5a8f | 124 | { |
96f6c995 MW |
125 | notcvt = (ElfW2(LIBELFBITS,Shdr) *) malloc (size); |
126 | if (unlikely (notcvt == NULL)) | |
127 | { | |
128 | __libelf_seterrno (ELF_E_NOMEM); | |
129 | goto out; | |
130 | } | |
b4d6f0f8 RM |
131 | memcpy (notcvt, ((char *) elf->map_address |
132 | + elf->start_offset + ehdr->e_shoff), | |
133 | size); | |
b08d5a8f | 134 | } |
b4d6f0f8 RM |
135 | |
136 | for (size_t cnt = 0; cnt < shnum; ++cnt) | |
b08d5a8f | 137 | { |
b4d6f0f8 RM |
138 | CONVERT_TO (shdr[cnt].sh_name, notcvt[cnt].sh_name); |
139 | CONVERT_TO (shdr[cnt].sh_type, notcvt[cnt].sh_type); | |
140 | CONVERT_TO (shdr[cnt].sh_flags, notcvt[cnt].sh_flags); | |
141 | CONVERT_TO (shdr[cnt].sh_addr, notcvt[cnt].sh_addr); | |
142 | CONVERT_TO (shdr[cnt].sh_offset, notcvt[cnt].sh_offset); | |
143 | CONVERT_TO (shdr[cnt].sh_size, notcvt[cnt].sh_size); | |
144 | CONVERT_TO (shdr[cnt].sh_link, notcvt[cnt].sh_link); | |
145 | CONVERT_TO (shdr[cnt].sh_info, notcvt[cnt].sh_info); | |
146 | CONVERT_TO (shdr[cnt].sh_addralign, | |
147 | notcvt[cnt].sh_addralign); | |
148 | CONVERT_TO (shdr[cnt].sh_entsize, notcvt[cnt].sh_entsize); | |
149 | ||
150 | /* If this is a section with an extended index add a | |
151 | reference in the section which uses the extended | |
152 | index. */ | |
153 | if (shdr[cnt].sh_type == SHT_SYMTAB_SHNDX | |
154 | && shdr[cnt].sh_link < shnum) | |
155 | elf->state.ELFW(elf,LIBELFBITS).scns.data[shdr[cnt].sh_link].shndx_index | |
156 | = cnt; | |
157 | ||
158 | /* Set the own shndx_index field in case it has not yet | |
159 | been set. */ | |
160 | if (elf->state.ELFW(elf,LIBELFBITS).scns.data[cnt].shndx_index == 0) | |
161 | elf->state.ELFW(elf,LIBELFBITS).scns.data[cnt].shndx_index | |
162 | = -1; | |
b08d5a8f | 163 | } |
96f6c995 MW |
164 | |
165 | if (copy) | |
166 | free (notcvt); | |
b08d5a8f | 167 | } |
b4d6f0f8 RM |
168 | } |
169 | else if (likely (elf->fildes != -1)) | |
170 | { | |
171 | /* Read the header. */ | |
172 | ssize_t n = pread_retry (elf->fildes, | |
173 | elf->state.ELFW(elf,LIBELFBITS).shdr, size, | |
174 | elf->start_offset + ehdr->e_shoff); | |
175 | if (unlikely ((size_t) n != size)) | |
b08d5a8f | 176 | { |
b4d6f0f8 RM |
177 | /* Severe problems. We cannot read the data. */ |
178 | __libelf_seterrno (ELF_E_READ_ERROR); | |
179 | goto free_and_out; | |
180 | } | |
b08d5a8f | 181 | |
b4d6f0f8 RM |
182 | /* If the byte order of the file is not the same as the one |
183 | of the host convert the data now. */ | |
184 | if (ehdr->e_ident[EI_DATA] != MY_ELFDATA) | |
185 | for (size_t cnt = 0; cnt < shnum; ++cnt) | |
186 | { | |
187 | CONVERT (shdr[cnt].sh_name); | |
188 | CONVERT (shdr[cnt].sh_type); | |
189 | CONVERT (shdr[cnt].sh_flags); | |
190 | CONVERT (shdr[cnt].sh_addr); | |
191 | CONVERT (shdr[cnt].sh_offset); | |
192 | CONVERT (shdr[cnt].sh_size); | |
193 | CONVERT (shdr[cnt].sh_link); | |
194 | CONVERT (shdr[cnt].sh_info); | |
195 | CONVERT (shdr[cnt].sh_addralign); | |
196 | CONVERT (shdr[cnt].sh_entsize); | |
197 | } | |
198 | } | |
199 | else | |
200 | { | |
201 | /* The file descriptor was already enabled and not all data was | |
202 | read. Undo the allocation. */ | |
203 | __libelf_seterrno (ELF_E_FD_DISABLED); | |
b08d5a8f | 204 | |
b4d6f0f8 RM |
205 | free_and_out: |
206 | free (shdr); | |
207 | elf->state.ELFW(elf,LIBELFBITS).shdr = NULL; | |
208 | elf->state.ELFW(elf,LIBELFBITS).shdr_malloced = 0; | |
b08d5a8f | 209 | |
b4d6f0f8 RM |
210 | goto out; |
211 | } | |
b08d5a8f | 212 | |
b4d6f0f8 RM |
213 | /* Set the pointers in the `scn's. */ |
214 | for (size_t cnt = 0; cnt < shnum; ++cnt) | |
215 | elf->state.ELFW(elf,LIBELFBITS).scns.data[cnt].shdr.ELFW(e,LIBELFBITS) | |
216 | = &elf->state.ELFW(elf,LIBELFBITS).shdr[cnt]; | |
217 | ||
218 | result = scn->shdr.ELFW(e,LIBELFBITS); | |
219 | assert (result != NULL); | |
220 | ||
221 | out: | |
222 | return result; | |
223 | } | |
224 | ||
225 | static bool | |
226 | scn_valid (Elf_Scn *scn) | |
227 | { | |
228 | if (scn == NULL) | |
229 | return false; | |
b08d5a8f | 230 | |
b4d6f0f8 RM |
231 | if (unlikely (scn->elf->state.elf.ehdr == NULL)) |
232 | { | |
233 | __libelf_seterrno (ELF_E_WRONG_ORDER_EHDR); | |
234 | return false; | |
235 | } | |
236 | ||
237 | if (unlikely (scn->elf->class != ELFW(ELFCLASS,LIBELFBITS))) | |
238 | { | |
239 | __libelf_seterrno (ELF_E_INVALID_CLASS); | |
240 | return false; | |
241 | } | |
242 | ||
243 | return true; | |
244 | } | |
245 | ||
246 | ElfW2(LIBELFBITS,Shdr) * | |
d8698e55 | 247 | internal_function |
1ccdfb68 | 248 | __elfw2(LIBELFBITS,getshdr_rdlock) (Elf_Scn *scn) |
b4d6f0f8 | 249 | { |
b4d6f0f8 RM |
250 | ElfW2(LIBELFBITS,Shdr) *result; |
251 | ||
252 | if (!scn_valid (scn)) | |
253 | return NULL; | |
254 | ||
255 | result = scn->shdr.ELFW(e,LIBELFBITS); | |
256 | if (result == NULL) | |
257 | { | |
258 | rwlock_unlock (scn->elf->lock); | |
259 | rwlock_wrlock (scn->elf->lock); | |
260 | result = scn->shdr.ELFW(e,LIBELFBITS); | |
261 | if (result == NULL) | |
02f66452 | 262 | result = load_shdr_wrlock (scn); |
b08d5a8f UD |
263 | } |
264 | ||
265 | return result; | |
266 | } | |
d56e232f | 267 | |
b4d6f0f8 | 268 | ElfW2(LIBELFBITS,Shdr) * |
d8698e55 | 269 | internal_function |
1ccdfb68 | 270 | __elfw2(LIBELFBITS,getshdr_wrlock) (Elf_Scn *scn) |
b4d6f0f8 RM |
271 | { |
272 | ElfW2(LIBELFBITS,Shdr) *result; | |
273 | ||
274 | if (!scn_valid (scn)) | |
275 | return NULL; | |
276 | ||
277 | result = scn->shdr.ELFW(e,LIBELFBITS); | |
278 | if (result == NULL) | |
02f66452 | 279 | result = load_shdr_wrlock (scn); |
b4d6f0f8 RM |
280 | |
281 | return result; | |
282 | } | |
283 | ||
d56e232f | 284 | ElfW2(LIBELFBITS,Shdr) * |
1ccdfb68 | 285 | elfw2(LIBELFBITS,getshdr) (Elf_Scn *scn) |
d56e232f | 286 | { |
b4d6f0f8 RM |
287 | ElfW2(LIBELFBITS,Shdr) *result; |
288 | ||
289 | if (!scn_valid (scn)) | |
290 | return NULL; | |
291 | ||
292 | rwlock_rdlock (scn->elf->lock); | |
293 | result = __elfw2(LIBELFBITS,getshdr_rdlock) (scn); | |
294 | rwlock_unlock (scn->elf->lock); | |
295 | ||
296 | return result; | |
d56e232f | 297 | } |