Branch data Line data Source code
1 : : /* Return the next data element from the section after possibly converting it.
2 : : Copyright (C) 1998-2005, 2006, 2007 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 <errno.h>
35 : : #include <stddef.h>
36 : : #include <string.h>
37 : : #include <unistd.h>
38 : :
39 : : #include "libelfP.h"
40 : : #include <system.h>
41 : : #include "common.h"
42 : : #include "elf-knowledge.h"
43 : :
44 : :
45 : : #define TYPEIDX(Sh_Type) \
46 : : (Sh_Type >= SHT_NULL && Sh_Type < SHT_NUM \
47 : : ? Sh_Type \
48 : : : (Sh_Type >= SHT_GNU_HASH && Sh_Type <= SHT_HISUNW \
49 : : ? SHT_NUM + Sh_Type - SHT_GNU_HASH \
50 : : : 0))
51 : :
52 : : /* Associate section types with libelf types. */
53 : : static const Elf_Type shtype_map[EV_NUM - 1][TYPEIDX (SHT_HISUNW) + 1] =
54 : : {
55 : : [EV_CURRENT - 1] =
56 : : {
57 : : [SHT_SYMTAB] = ELF_T_SYM,
58 : : [SHT_RELA] = ELF_T_RELA,
59 : : [SHT_HASH] = ELF_T_WORD,
60 : : [SHT_DYNAMIC] = ELF_T_DYN,
61 : : [SHT_REL] = ELF_T_REL,
62 : : [SHT_DYNSYM] = ELF_T_SYM,
63 : : [SHT_INIT_ARRAY] = ELF_T_ADDR,
64 : : [SHT_FINI_ARRAY] = ELF_T_ADDR,
65 : : [SHT_PREINIT_ARRAY] = ELF_T_ADDR,
66 : : [SHT_GROUP] = ELF_T_WORD,
67 : : [SHT_SYMTAB_SHNDX] = ELF_T_WORD,
68 : : [SHT_NOTE] = ELF_T_NHDR,
69 : : [TYPEIDX (SHT_GNU_verdef)] = ELF_T_VDEF,
70 : : [TYPEIDX (SHT_GNU_verneed)] = ELF_T_VNEED,
71 : : [TYPEIDX (SHT_GNU_versym)] = ELF_T_HALF,
72 : : [TYPEIDX (SHT_SUNW_syminfo)] = ELF_T_SYMINFO,
73 : : [TYPEIDX (SHT_SUNW_move)] = ELF_T_MOVE,
74 : : [TYPEIDX (SHT_GNU_LIBLIST)] = ELF_T_LIB,
75 : : [TYPEIDX (SHT_GNU_HASH)] = ELF_T_GNUHASH,
76 : : }
77 : : };
78 : :
79 : : #if !ALLOW_UNALIGNED
80 : : /* Associate libelf types with their internal alignment requirements. */
81 : : const uint_fast8_t __libelf_type_aligns[EV_NUM - 1][ELFCLASSNUM - 1][ELF_T_NUM] =
82 : : {
83 : : # define TYPE_ALIGNS(Bits) \
84 : : { \
85 : : [ELF_T_ADDR] = __alignof__ (ElfW2(Bits,Addr)), \
86 : : [ELF_T_HALF] = __alignof__ (ElfW2(Bits,Half)), \
87 : : [ELF_T_WORD] = __alignof__ (ElfW2(Bits,Word)), \
88 : : [ELF_T_SYM] = __alignof__ (ElfW2(Bits,Sym)), \
89 : : [ELF_T_SYMINFO] = __alignof__ (ElfW2(Bits,Syminfo)), \
90 : : [ELF_T_REL] = __alignof__ (ElfW2(Bits,Rel)), \
91 : : [ELF_T_RELA] = __alignof__ (ElfW2(Bits,Rela)), \
92 : : [ELF_T_DYN] = __alignof__ (ElfW2(Bits,Dyn)), \
93 : : [ELF_T_VDEF] = __alignof__ (ElfW2(Bits,Verdef)), \
94 : : [ELF_T_VDAUX] = __alignof__ (ElfW2(Bits,Verdaux)), \
95 : : [ELF_T_VNEED] = __alignof__ (ElfW2(Bits,Verneed)), \
96 : : [ELF_T_VNAUX] = __alignof__ (ElfW2(Bits,Vernaux)), \
97 : : [ELF_T_MOVE] = __alignof__ (ElfW2(Bits,Move)), \
98 : : [ELF_T_LIB] = __alignof__ (ElfW2(Bits,Lib)), \
99 : : [ELF_T_NHDR] = __alignof__ (ElfW2(Bits,Nhdr)), \
100 : : }
101 : : [EV_CURRENT - 1] =
102 : : {
103 : : [ELFCLASS32 - 1] = TYPE_ALIGNS (32),
104 : : [ELFCLASS64 - 1] = TYPE_ALIGNS (64),
105 : : }
106 : : # undef TYPE_ALIGNS
107 : : };
108 : : #endif
109 : :
110 : :
111 : : /* Convert the data in the current section. */
112 : : static void
113 : 63268 : convert_data (Elf_Scn *scn, int version __attribute__ ((unused)), int eclass,
114 : : int data, size_t size, Elf_Type type)
115 : : {
116 : 63268 : const size_t align = __libelf_type_align (eclass, type);
117 : :
118 [ + + ]: 63268 : if (data == MY_ELFDATA)
119 : : {
120 : : if (((((size_t) (char *) scn->rawdata_base)) & (align - 1)) == 0)
121 : : /* No need to copy, we can use the raw data. */
122 : 62793 : scn->data_base = scn->rawdata_base;
123 : : else
124 : : {
125 : : scn->data_base = (char *) malloc (size);
126 : : if (scn->data_base == NULL)
127 : : {
128 : : __libelf_seterrno (ELF_E_NOMEM);
129 : : return;
130 : : }
131 : :
132 : : /* The copy will be appropriately aligned for direct access. */
133 : : memcpy (scn->data_base, scn->rawdata_base, size);
134 : : }
135 : : }
136 : : else
137 : : {
138 : : xfct_t fp;
139 : :
140 : 475 : scn->data_base = (char *) malloc (size);
141 [ - + ]: 475 : if (scn->data_base == NULL)
142 : : {
143 : 0 : __libelf_seterrno (ELF_E_NOMEM);
144 : : return;
145 : : }
146 : :
147 : : /* Get the conversion function. */
148 : : #if EV_NUM != 2
149 : : fp = __elf_xfctstom[version - 1][__libelf_version - 1][eclass - 1][type];
150 : : #else
151 : 475 : fp = __elf_xfctstom[0][0][eclass - 1][type];
152 : : #endif
153 : :
154 : 475 : fp (scn->data_base, scn->rawdata_base, size, 0);
155 : : }
156 : :
157 : 63268 : scn->data_list.data.d.d_buf = scn->data_base;
158 : 63268 : scn->data_list.data.d.d_size = size;
159 : 63268 : scn->data_list.data.d.d_type = type;
160 : 63268 : scn->data_list.data.d.d_off = scn->rawdata.d.d_off;
161 : 63268 : scn->data_list.data.d.d_align = scn->rawdata.d.d_align;
162 : 63268 : scn->data_list.data.d.d_version = scn->rawdata.d.d_version;
163 : :
164 : 63268 : scn->data_list.data.s = scn;
165 : : }
166 : :
167 : :
168 : : /* Store the information for the raw data in the `rawdata' element. */
169 : : int
170 : : internal_function
171 : 69558 : __libelf_set_rawdata_wrlock (Elf_Scn *scn)
172 : : {
173 : : size_t offset;
174 : : size_t size;
175 : : size_t align;
176 : : int type;
177 : 69558 : Elf *elf = scn->elf;
178 : :
179 [ + + ]: 69558 : if (elf->class == ELFCLASS32)
180 : : {
181 : 23263 : Elf32_Shdr *shdr
182 [ + + ]: 23263 : = scn->shdr.e32 ?: __elf32_getshdr_wrlock (scn);
183 : :
184 [ + - ]: 23263 : if (shdr == NULL)
185 : : /* Something went terribly wrong. */
186 : : return 1;
187 : :
188 : 23263 : offset = shdr->sh_offset;
189 : 23263 : size = shdr->sh_size;
190 : 23263 : type = shdr->sh_type;
191 : 23263 : align = shdr->sh_addralign;
192 : : }
193 : : else
194 : : {
195 : 46295 : Elf64_Shdr *shdr
196 [ + + ]: 46295 : = scn->shdr.e64 ?: __elf64_getshdr_wrlock (scn);
197 : :
198 [ + - ]: 46295 : if (shdr == NULL)
199 : : /* Something went terribly wrong. */
200 : : return 1;
201 : :
202 : 46295 : offset = shdr->sh_offset;
203 : 46295 : size = shdr->sh_size;
204 : 46295 : type = shdr->sh_type;
205 : 46295 : align = shdr->sh_addralign;
206 : : }
207 : :
208 : : /* If the section has no data (for whatever reason), leave the `d_buf'
209 : : pointer NULL. */
210 [ + + ]: 69558 : if (size != 0 && type != SHT_NOBITS)
211 : : {
212 : : /* First a test whether the section is valid at all. */
213 : : size_t entsize;
214 : :
215 [ + + ]: 69290 : if (type == SHT_HASH)
216 : : {
217 : : GElf_Ehdr ehdr_mem;
218 : 35 : GElf_Ehdr *ehdr = __gelf_getehdr_rdlock (elf, &ehdr_mem);
219 [ + + ][ - + ]: 35 : entsize = SH_ENTSIZE_HASH (ehdr);
[ # # ]
220 : : }
221 : : else
222 : : {
223 [ + + ][ + + ]: 69255 : Elf_Type t = shtype_map[LIBELF_EV_IDX][TYPEIDX (type)];
224 [ + + ]: 69255 : if (t == ELF_T_VDEF || t == ELF_T_NHDR
225 [ + + ][ + + ]: 69003 : || (t == ELF_T_GNUHASH && elf->class == ELFCLASS64))
226 : : entsize = 1;
227 : : else
228 : 68948 : entsize = __libelf_type_sizes[LIBELF_EV_IDX][elf->class - 1][t];
229 : : }
230 : :
231 : : /* We assume it is an array of bytes if it is none of the structured
232 : : sections we know of. */
233 [ - + ]: 69290 : if (entsize == 0)
234 : 0 : entsize = 1;
235 : :
236 [ - + ]: 69290 : if (unlikely (size % entsize != 0))
237 : : {
238 : 0 : __libelf_seterrno (ELF_E_INVALID_DATA);
239 : 0 : return 1;
240 : : }
241 : :
242 : : /* We can use the mapped or loaded data if available. */
243 [ + + ]: 69290 : if (elf->map_address != NULL)
244 : : {
245 : : /* First see whether the information in the section header is
246 : : valid and it does not ask for too much. */
247 [ - + ]: 68330 : if (unlikely (offset + size > elf->maximum_size))
248 : : {
249 : : /* Something is wrong. */
250 : 0 : __libelf_seterrno (ELF_E_INVALID_SECTION_HEADER);
251 : 0 : return 1;
252 : : }
253 : :
254 : 68330 : scn->rawdata_base = scn->rawdata.d.d_buf
255 : 68330 : = (char *) elf->map_address + elf->start_offset + offset;
256 : : }
257 [ + - ]: 960 : else if (likely (elf->fildes != -1))
258 : : {
259 : : /* We have to read the data from the file. Allocate the needed
260 : : memory. */
261 : 960 : scn->rawdata_base = scn->rawdata.d.d_buf
262 : 960 : = (char *) malloc (size);
263 [ - + ]: 960 : if (scn->rawdata.d.d_buf == NULL)
264 : : {
265 : 0 : __libelf_seterrno (ELF_E_NOMEM);
266 : 0 : return 1;
267 : : }
268 : :
269 : 960 : ssize_t n = pread_retry (elf->fildes, scn->rawdata.d.d_buf, size,
270 : 960 : elf->start_offset + offset);
271 [ - + ]: 960 : if (unlikely ((size_t) n != size))
272 : : {
273 : : /* Cannot read the data. */
274 : 0 : free (scn->rawdata.d.d_buf);
275 : 0 : scn->rawdata_base = scn->rawdata.d.d_buf = NULL;
276 : 0 : __libelf_seterrno (ELF_E_READ_ERROR);
277 : 0 : return 1;
278 : : }
279 : : }
280 : : else
281 : : {
282 : : /* The file descriptor is already closed, we cannot get the data
283 : : anymore. */
284 : 0 : __libelf_seterrno (ELF_E_FD_DISABLED);
285 : 0 : return 1;
286 : : }
287 : : }
288 : :
289 : 69558 : scn->rawdata.d.d_size = size;
290 : : /* Some broken ELF ABI for 64-bit machines use the wrong hash table
291 : : entry size. See elf-knowledge.h for more information. */
292 [ + + ][ + + ]: 69558 : if (type == SHT_HASH && elf->class == ELFCLASS64)
293 : 20 : {
294 : : GElf_Ehdr ehdr_mem;
295 : 20 : GElf_Ehdr *ehdr = __gelf_getehdr_rdlock (elf, &ehdr_mem);
296 : : scn->rawdata.d.d_type
297 [ + + ][ - + ]: 20 : = (SH_ENTSIZE_HASH (ehdr) == 4 ? ELF_T_WORD : ELF_T_XWORD);
[ # # ]
298 : : }
299 : : else
300 [ + + ][ + + ]: 69538 : scn->rawdata.d.d_type = shtype_map[LIBELF_EV_IDX][TYPEIDX (type)];
301 : 69558 : scn->rawdata.d.d_off = 0;
302 : 69558 : scn->rawdata.d.d_align = align;
303 : : if (elf->class == ELFCLASS32
304 : : || (offsetof (struct Elf, state.elf32.ehdr)
305 : : == offsetof (struct Elf, state.elf64.ehdr)))
306 : 69558 : scn->rawdata.d.d_version =
307 : 69558 : elf->state.elf32.ehdr->e_ident[EI_VERSION];
308 : : else
309 : : scn->rawdata.d.d_version =
310 : : elf->state.elf64.ehdr->e_ident[EI_VERSION];
311 : :
312 : 69558 : scn->rawdata.s = scn;
313 : :
314 : 69558 : scn->data_read = 1;
315 : :
316 : : /* We actually read data from the file. At least we tried. */
317 : 69558 : scn->flags |= ELF_F_FILEDATA;
318 : :
319 : 69558 : return 0;
320 : : }
321 : :
322 : : int
323 : : internal_function
324 : 294 : __libelf_set_rawdata (Elf_Scn *scn)
325 : : {
326 : : int result;
327 : :
328 [ + - ]: 294 : if (scn == NULL)
329 : : return 1;
330 : :
331 : : rwlock_wrlock (scn->elf->lock);
332 : 294 : result = __libelf_set_rawdata_wrlock (scn);
333 : : rwlock_unlock (scn->elf->lock);
334 : :
335 : 294 : return result;
336 : : }
337 : :
338 : : Elf_Data *
339 : : internal_function
340 : 108748 : __elf_getdata_rdlock (scn, data)
341 : : Elf_Scn *scn;
342 : : Elf_Data *data;
343 : : {
344 : 108748 : Elf_Data *result = NULL;
345 : : Elf *elf;
346 : 108748 : int locked = 0;
347 : :
348 [ + - ]: 108748 : if (scn == NULL)
349 : : return NULL;
350 : :
351 [ - + ]: 108748 : if (unlikely (scn->elf->kind != ELF_K_ELF))
352 : : {
353 : 0 : __libelf_seterrno (ELF_E_INVALID_HANDLE);
354 : 0 : return NULL;
355 : : }
356 : :
357 : : /* We will need this multiple times later on. */
358 : 108748 : elf = scn->elf;
359 : :
360 : : /* If `data' is not NULL this means we are not addressing the initial
361 : : data in the file. But this also means this data is already read
362 : : (since otherwise it is not possible to have a valid `data' pointer)
363 : : and all the data structures are initialized as well. In this case
364 : : we can simply walk the list of data records. */
365 [ + + ]: 108748 : if (data != NULL)
366 : : {
367 : : Elf_Data_List *runp;
368 : :
369 : : /* It is not possible that if DATA is not NULL the first entry is
370 : : returned. But this also means that there must be a first data
371 : : entry. */
372 [ + - ]: 38 : if (scn->data_list_rear == NULL
373 : : /* The section the reference data is for must match the section
374 : : parameter. */
375 [ - + ]: 38 : || unlikely (((Elf_Data_Scn *) data)->s != scn))
376 : : {
377 : 0 : __libelf_seterrno (ELF_E_DATA_MISMATCH);
378 : 0 : goto out;
379 : : }
380 : :
381 : : /* We start searching with the first entry. */
382 : 38 : runp = &scn->data_list;
383 : :
384 : : while (1)
385 : : {
386 : : /* If `data' does not match any known record punt. */
387 [ - + ]: 38 : if (runp == NULL)
388 : : {
389 : 0 : __libelf_seterrno (ELF_E_DATA_MISMATCH);
390 : 0 : goto out;
391 : : }
392 : :
393 [ - + ]: 38 : if (&runp->data.d == data)
394 : : /* Found the entry. */
395 : : break;
396 : :
397 : 0 : runp = runp->next;
398 : 0 : }
399 : :
400 : : /* Return the data for the next data record. */
401 [ - + ]: 38 : result = runp->next ? &runp->next->data.d : NULL;
402 : 38 : goto out;
403 : : }
404 : :
405 : : /* If the data for this section was not yet initialized do it now. */
406 [ + + ]: 108710 : if (scn->data_read == 0)
407 : : {
408 : : /* We cannot acquire a write lock while we are holding a read
409 : : lock. Therefore give up the read lock and then get the write
410 : : lock. But this means that the data could meanwhile be
411 : : modified, therefore start the tests again. */
412 : : rwlock_unlock (elf->lock);
413 : : rwlock_wrlock (elf->lock);
414 : 63345 : locked = 1;
415 : :
416 : : /* Read the data from the file. There is always a file (or
417 : : memory region) associated with this descriptor since
418 : : otherwise the `data_read' flag would be set. */
419 [ + - ][ + - ]: 63345 : if (scn->data_read == 0 && __libelf_set_rawdata_wrlock (scn) != 0)
420 : : /* Something went wrong. The error value is already set. */
421 : : goto out;
422 : : }
423 : :
424 : : /* At this point we know the raw data is available. But it might be
425 : : empty in case the section has size zero (for whatever reason).
426 : : Now create the converted data in case this is necessary. */
427 [ + + ]: 108710 : if (scn->data_list_rear == NULL)
428 : : {
429 [ + + ][ + - ]: 63532 : if (scn->rawdata.d.d_buf != NULL && scn->rawdata.d.d_size > 0)
430 : : {
431 [ + + ]: 63268 : if (!locked)
432 : : {
433 : : rwlock_unlock (elf->lock);
434 : : rwlock_wrlock (elf->lock);
435 [ + - ]: 185 : if (scn->data_list_rear != NULL)
436 : : goto pass;
437 : : }
438 : :
439 : : /* Convert according to the version and the type. */
440 : 63268 : convert_data (scn, __libelf_version, elf->class,
441 : : (elf->class == ELFCLASS32
442 : : || (offsetof (struct Elf, state.elf32.ehdr)
443 : : == offsetof (struct Elf, state.elf64.ehdr))
444 : 63268 : ? elf->state.elf32.ehdr->e_ident[EI_DATA]
445 : : : elf->state.elf64.ehdr->e_ident[EI_DATA]),
446 : : scn->rawdata.d.d_size, scn->rawdata.d.d_type);
447 : : }
448 : : else
449 : : {
450 : : /* This is an empty or NOBITS section. There is no buffer but
451 : : the size information etc is important. */
452 : 264 : scn->data_list.data.d = scn->rawdata.d;
453 : 264 : scn->data_list.data.s = scn;
454 : : }
455 : :
456 : 63532 : scn->data_list_rear = &scn->data_list;
457 : : }
458 : :
459 : : /* If no data is present we cannot return any. */
460 [ + - ]: 108710 : if (scn->data_list_rear != NULL)
461 : : pass:
462 : : /* Return the first data element in the list. */
463 : 108710 : result = &scn->data_list.data.d;
464 : :
465 : : out:
466 : 108748 : return result;
467 : : }
468 : :
469 : : Elf_Data *
470 : 109606 : elf_getdata (scn, data)
471 : : Elf_Scn *scn;
472 : : Elf_Data *data;
473 : : {
474 : : Elf_Data *result;
475 : :
476 [ + + ]: 109606 : if (scn == NULL)
477 : : return NULL;
478 : :
479 : : rwlock_rdlock (scn->elf->lock);
480 : 108742 : result = __elf_getdata_rdlock (scn, data);
481 : : rwlock_unlock (scn->elf->lock);
482 : :
483 : 109606 : return result;
484 : : }
485 : : INTDEF(elf_getdata)
|