Branch data Line data Source code
1 : : /* Return converted data from raw chunk of ELF file.
2 : : Copyright (C) 2007, 2014, 2015 Red Hat, Inc.
3 : : Copyright (C) 2022, 2023 Mark J. Wielaard <mark@klomp.org>
4 : : This file is part of elfutils.
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 <string.h>
37 : :
38 : : #include "libelfP.h"
39 : : #include "common.h"
40 : : #include "eu-search.h"
41 : :
42 : : static int
43 : 8128 : chunk_compare (const void *a, const void *b)
44 : : {
45 : 8128 : Elf_Data_Chunk *da = (Elf_Data_Chunk *)a;
46 : 8128 : Elf_Data_Chunk *db = (Elf_Data_Chunk *)b;
47 : :
48 [ + + ]: 8128 : if (da->offset != db->offset)
49 : 8038 : return da->offset - db->offset;
50 : :
51 [ - + ]: 90 : if (da->data.d.d_size != db->data.d.d_size)
52 : 0 : return da->data.d.d_size - db->data.d.d_size;
53 : :
54 : 90 : return da->data.d.d_type - db->data.d.d_type;
55 : : }
56 : :
57 : : Elf_Data *
58 : 2422 : elf_getdata_rawchunk (Elf *elf, int64_t offset, size_t size, Elf_Type type)
59 : : {
60 [ - + ]: 2422 : if (unlikely (elf == NULL))
61 : : return NULL;
62 : :
63 [ - + ]: 2422 : if (unlikely (elf->kind != ELF_K_ELF))
64 : : {
65 : : /* No valid descriptor. */
66 : 0 : __libelf_seterrno (ELF_E_INVALID_HANDLE);
67 : 0 : return NULL;
68 : : }
69 : :
70 [ + - + + : 2422 : if (unlikely (offset < 0 || (uint64_t) offset > elf->maximum_size
- + ]
71 : : || elf->maximum_size - (uint64_t) offset < size))
72 : :
73 : : {
74 : : /* Invalid request. */
75 : 28 : __libelf_seterrno (ELF_E_INVALID_OP);
76 : 28 : return NULL;
77 : : }
78 : :
79 [ - + ]: 2394 : if (type >= ELF_T_NUM)
80 : : {
81 : 0 : __libelf_seterrno (ELF_E_UNKNOWN_TYPE);
82 : 0 : return NULL;
83 : : }
84 : :
85 : : /* Get the raw bytes from the file. */
86 : 2394 : void *rawchunk;
87 : 2394 : int flags = 0;
88 : 2394 : Elf_Data *result = NULL;
89 : :
90 : 2394 : rwlock_wrlock (elf->lock);
91 : :
92 : : /* Maybe we already got this chunk? */
93 : 2394 : Elf_Data_Chunk key;
94 : 2394 : key.offset = offset;
95 : 2394 : key.data.d.d_size = size;
96 : 2394 : key.data.d.d_type = type;
97 : 2394 : Elf_Data_Chunk **found
98 : 2394 : = eu_tsearch_nolock (&key, &elf->state.elf.rawchunk_tree, &chunk_compare);
99 : :
100 [ - + ]: 2394 : if (found == NULL)
101 : 0 : goto nomem;
102 : :
103 : : /* Existing entry. */
104 [ + + + - ]: 2394 : if (*found != &key && *found != NULL)
105 : : {
106 : 90 : result = &(*found)->data.d;
107 : 90 : goto out;
108 : : }
109 : :
110 : : /* New entry. Note that *found will point to the newly inserted
111 : : (dummy) key. We'll replace it with a real rawchunk when that is
112 : : setup. Make sure to tdelete the dummy key if anything goes
113 : : wrong. */
114 : :
115 : 2304 : size_t align = __libelf_type_align (elf->class, type);
116 [ + + ]: 2304 : if (elf->map_address != NULL)
117 : : {
118 : : /* If the file is mmap'ed we can use it directly, if aligned for type. */
119 : 1796 : char *rawdata = elf->map_address + elf->start_offset + offset;
120 [ + + ]: 1796 : if (((uintptr_t) rawdata & (align - 1)) == 0)
121 : : rawchunk = rawdata;
122 : : else
123 : : {
124 : : /* We allocate the memory and memcpy it to get aligned data. */
125 : 4 : rawchunk = malloc (size);
126 [ - + ]: 4 : if (rawchunk == NULL)
127 : 0 : goto nomem;
128 : 4 : memcpy (rawchunk, rawdata, size);
129 : 4 : flags = ELF_F_MALLOCED;
130 : : }
131 : : }
132 : : else
133 : : {
134 : : /* We allocate the memory and read the data from the file. */
135 : 508 : rawchunk = malloc (size);
136 [ - + ]: 508 : if (rawchunk == NULL)
137 : : {
138 : 0 : nomem:
139 : 0 : eu_tdelete_nolock (&key, &elf->state.elf.rawchunk_tree,
140 : : &chunk_compare);
141 : 0 : __libelf_seterrno (ELF_E_NOMEM);
142 : 0 : goto out;
143 : : }
144 : :
145 : : /* Read the file content. */
146 [ - + ]: 508 : if (unlikely ((size_t) pread_retry (elf->fildes, rawchunk, size,
147 : : elf->start_offset + offset)
148 : : != size))
149 : : {
150 : : /* Something went wrong. */
151 : 0 : eu_tdelete_nolock (&key, &elf->state.elf.rawchunk_tree,
152 : : &chunk_compare);
153 : 0 : free (rawchunk);
154 : 0 : __libelf_seterrno (ELF_E_READ_ERROR);
155 : 0 : goto out;
156 : : }
157 : :
158 : : flags = ELF_F_MALLOCED;
159 : : }
160 : :
161 : : /* Copy and/or convert the data as needed for aligned native-order access. */
162 : 2304 : void *buffer;
163 [ + + ]: 2304 : if (elf->state.elf32.ehdr->e_ident[EI_DATA] == MY_ELFDATA)
164 : : {
165 [ - + ]: 1594 : if (((uintptr_t) rawchunk & (align - 1)) == 0)
166 : : /* No need to copy, we can use the raw data. */
167 : : buffer = rawchunk;
168 : : else
169 : : {
170 : : /* A malloc'd block is always sufficiently aligned. */
171 [ # # ]: 0 : assert (flags == 0);
172 : :
173 : 0 : buffer = malloc (size);
174 [ # # ]: 0 : if (unlikely (buffer == NULL))
175 : 0 : goto nomem;
176 : 0 : flags = ELF_F_MALLOCED;
177 : :
178 : : /* The copy will be appropriately aligned for direct access. */
179 : 0 : memcpy (buffer, rawchunk, size);
180 : :
181 : 0 : free (rawchunk);
182 : : }
183 : : }
184 : : else
185 : : {
186 [ + + ]: 710 : if (flags)
187 : : buffer = rawchunk;
188 : : else
189 : : {
190 : 656 : buffer = malloc (size);
191 [ - + ]: 656 : if (unlikely (buffer == NULL))
192 : 0 : goto nomem;
193 : : flags = ELF_F_MALLOCED;
194 : : }
195 : :
196 : : /* Call the conversion function. */
197 : 710 : (*__elf_xfctstom[elf->class - 1][type])(buffer, rawchunk, size, 0);
198 : :
199 : 710 : if (!flags)
200 : : free (rawchunk);
201 : : }
202 : :
203 : : /* Allocate the dummy container to point at this buffer. */
204 : 2304 : Elf_Data_Chunk *chunk = calloc (1, sizeof *chunk);
205 [ - + ]: 2304 : if (chunk == NULL)
206 : : {
207 [ # # ]: 0 : if (flags)
208 : 0 : free (buffer);
209 : 0 : goto nomem;
210 : : }
211 : :
212 : 2304 : chunk->dummy_scn.elf = elf;
213 : 2304 : chunk->dummy_scn.flags = flags;
214 : 2304 : chunk->data.s = &chunk->dummy_scn;
215 : 2304 : chunk->data.d.d_buf = buffer;
216 : 2304 : chunk->data.d.d_size = size;
217 : 2304 : chunk->data.d.d_type = type;
218 : 2304 : chunk->data.d.d_align = align;
219 : 2304 : chunk->data.d.d_version = EV_CURRENT;
220 : 2304 : chunk->offset = offset;
221 : :
222 : 2304 : *found = chunk;
223 : 2304 : result = &chunk->data.d;
224 : :
225 : : out:
226 : : rwlock_unlock (elf->lock);
227 : : return result;
228 : : }
|