1 /* Return section header.
2 Copyright (C) 1998-2002, 2005, 2007, 2009, 2012, 2014 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 || (! ALLOW_UNALIGNED
103 && ((uintptr_t) file_shdr
104 & (__alignof__ (ElfW2(LIBELFBITS,Shdr)) - 1)) != 0));
105
106 /* Now copy the data and at the same time convert the byte order. */
107 if (ehdr->e_ident[EI_DATA] == MY_ELFDATA)
108 {
109 assert ((elf->flags & ELF_F_MALLOCED) || ! ALLOW_UNALIGNED);
110 memcpy (shdr, file_shdr, size);
111 }
112 else
113 {
114 if (ALLOW_UNALIGNED
115 || ((uintptr_t) file_shdr
116 & (__alignof__ (ElfW2(LIBELFBITS,Shdr)) - 1)) == 0)
117 notcvt = (ElfW2(LIBELFBITS,Shdr) *)
118 ((char *) elf->map_address
119 + elf->start_offset + ehdr->e_shoff);
120 else
121 {
122 notcvt = (ElfW2(LIBELFBITS,Shdr) *) alloca (size);
123 memcpy (notcvt, ((char *) elf->map_address
124 + elf->start_offset + ehdr->e_shoff),
125 size);
126 }
127
128 for (size_t cnt = 0; cnt < shnum; ++cnt)
129 {
130 CONVERT_TO (shdr[cnt].sh_name, notcvt[cnt].sh_name);
131 CONVERT_TO (shdr[cnt].sh_type, notcvt[cnt].sh_type);
132 CONVERT_TO (shdr[cnt].sh_flags, notcvt[cnt].sh_flags);
133 CONVERT_TO (shdr[cnt].sh_addr, notcvt[cnt].sh_addr);
134 CONVERT_TO (shdr[cnt].sh_offset, notcvt[cnt].sh_offset);
135 CONVERT_TO (shdr[cnt].sh_size, notcvt[cnt].sh_size);
136 CONVERT_TO (shdr[cnt].sh_link, notcvt[cnt].sh_link);
137 CONVERT_TO (shdr[cnt].sh_info, notcvt[cnt].sh_info);
138 CONVERT_TO (shdr[cnt].sh_addralign,
139 notcvt[cnt].sh_addralign);
140 CONVERT_TO (shdr[cnt].sh_entsize, notcvt[cnt].sh_entsize);
141
142 /* If this is a section with an extended index add a
143 reference in the section which uses the extended
144 index. */
145 if (shdr[cnt].sh_type == SHT_SYMTAB_SHNDX
146 && shdr[cnt].sh_link < shnum)
147 elf->state.ELFW(elf,LIBELFBITS).scns.data[shdr[cnt].sh_link].shndx_index
148 = cnt;
149
150 /* Set the own shndx_index field in case it has not yet
151 been set. */
152 if (elf->state.ELFW(elf,LIBELFBITS).scns.data[cnt].shndx_index == 0)
153 elf->state.ELFW(elf,LIBELFBITS).scns.data[cnt].shndx_index
154 = -1;
155 }
156 }
157 }
158 else if (likely (elf->fildes != -1))
159 {
160 /* Read the header. */
161 ssize_t n = pread_retry (elf->fildes,
162 elf->state.ELFW(elf,LIBELFBITS).shdr, size,
163 elf->start_offset + ehdr->e_shoff);
164 if (unlikely ((size_t) n != size))
165 {
166 /* Severe problems. We cannot read the data. */
167 __libelf_seterrno (ELF_E_READ_ERROR);
168 goto free_and_out;
169 }
170
171 /* If the byte order of the file is not the same as the one
172 of the host convert the data now. */
173 if (ehdr->e_ident[EI_DATA] != MY_ELFDATA)
174 for (size_t cnt = 0; cnt < shnum; ++cnt)
175 {
176 CONVERT (shdr[cnt].sh_name);
177 CONVERT (shdr[cnt].sh_type);
178 CONVERT (shdr[cnt].sh_flags);
179 CONVERT (shdr[cnt].sh_addr);
180 CONVERT (shdr[cnt].sh_offset);
181 CONVERT (shdr[cnt].sh_size);
182 CONVERT (shdr[cnt].sh_link);
183 CONVERT (shdr[cnt].sh_info);
184 CONVERT (shdr[cnt].sh_addralign);
185 CONVERT (shdr[cnt].sh_entsize);
186 }
187 }
188 else
189 {
190 /* The file descriptor was already enabled and not all data was
191 read. Undo the allocation. */
192 __libelf_seterrno (ELF_E_FD_DISABLED);
193
194 free_and_out:
195 free (shdr);
196 elf->state.ELFW(elf,LIBELFBITS).shdr = NULL;
197 elf->state.ELFW(elf,LIBELFBITS).shdr_malloced = 0;
198
199 goto out;
200 }
201
202 /* Set the pointers in the `scn's. */
203 for (size_t cnt = 0; cnt < shnum; ++cnt)
204 elf->state.ELFW(elf,LIBELFBITS).scns.data[cnt].shdr.ELFW(e,LIBELFBITS)
205 = &elf->state.ELFW(elf,LIBELFBITS).shdr[cnt];
206
207 result = scn->shdr.ELFW(e,LIBELFBITS);
208 assert (result != NULL);
209
210 out:
211 return result;
212 }
213
214 static bool
scn_valid(Elf_Scn * scn)215 scn_valid (Elf_Scn *scn)
216 {
217 if (scn == NULL)
218 return false;
219
220 if (unlikely (scn->elf->state.elf.ehdr == NULL))
221 {
222 __libelf_seterrno (ELF_E_WRONG_ORDER_EHDR);
223 return false;
224 }
225
226 if (unlikely (scn->elf->class != ELFW(ELFCLASS,LIBELFBITS)))
227 {
228 __libelf_seterrno (ELF_E_INVALID_CLASS);
229 return false;
230 }
231
232 return true;
233 }
234
235 ElfW2(LIBELFBITS,Shdr) *
236 __elfw2(LIBELFBITS,getshdr_rdlock) (scn)
237 Elf_Scn *scn;
238 {
239 ElfW2(LIBELFBITS,Shdr) *result;
240
241 if (!scn_valid (scn))
242 return NULL;
243
244 result = scn->shdr.ELFW(e,LIBELFBITS);
245 if (result == NULL)
246 {
247 rwlock_unlock (scn->elf->lock);
248 rwlock_wrlock (scn->elf->lock);
249 result = scn->shdr.ELFW(e,LIBELFBITS);
250 if (result == NULL)
251 result = load_shdr_wrlock (scn);
252 }
253
254 return result;
255 }
256
257 ElfW2(LIBELFBITS,Shdr) *
258 __elfw2(LIBELFBITS,getshdr_wrlock) (scn)
259 Elf_Scn *scn;
260 {
261 ElfW2(LIBELFBITS,Shdr) *result;
262
263 if (!scn_valid (scn))
264 return NULL;
265
266 result = scn->shdr.ELFW(e,LIBELFBITS);
267 if (result == NULL)
268 result = load_shdr_wrlock (scn);
269
270 return result;
271 }
272
273 ElfW2(LIBELFBITS,Shdr) *
274 elfw2(LIBELFBITS,getshdr) (scn)
275 Elf_Scn *scn;
276 {
277 ElfW2(LIBELFBITS,Shdr) *result;
278
279 if (!scn_valid (scn))
280 return NULL;
281
282 rwlock_rdlock (scn->elf->lock);
283 result = __elfw2(LIBELFBITS,getshdr_rdlock) (scn);
284 rwlock_unlock (scn->elf->lock);
285
286 return result;
287 }
288