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