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_rdlock (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 (&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 (&key, &elf->state.elf.rawchunk_tree, &chunk_compare);
140 : 0 : __libelf_seterrno (ELF_E_NOMEM);
141 : 0 : goto out;
142 : : }
143 : :
144 : : /* Read the file content. */
145 [ - + ]: 508 : if (unlikely ((size_t) pread_retry (elf->fildes, rawchunk, size,
146 : : elf->start_offset + offset)
147 : : != size))
148 : : {
149 : : /* Something went wrong. */
150 : 0 : eu_tdelete (&key, &elf->state.elf.rawchunk_tree, &chunk_compare);
151 : 0 : free (rawchunk);
152 : 0 : __libelf_seterrno (ELF_E_READ_ERROR);
153 : 0 : goto out;
154 : : }
155 : :
156 : : flags = ELF_F_MALLOCED;
157 : : }
158 : :
159 : : /* Copy and/or convert the data as needed for aligned native-order access. */
160 : 2304 : void *buffer;
161 [ + + ]: 2304 : if (elf->state.elf32.ehdr->e_ident[EI_DATA] == MY_ELFDATA)
162 : : {
163 [ - + ]: 1594 : if (((uintptr_t) rawchunk & (align - 1)) == 0)
164 : : /* No need to copy, we can use the raw data. */
165 : : buffer = rawchunk;
166 : : else
167 : : {
168 : : /* A malloc'd block is always sufficiently aligned. */
169 [ # # ]: 0 : assert (flags == 0);
170 : :
171 : 0 : buffer = malloc (size);
172 [ # # ]: 0 : if (unlikely (buffer == NULL))
173 : 0 : goto nomem;
174 : 0 : flags = ELF_F_MALLOCED;
175 : :
176 : : /* The copy will be appropriately aligned for direct access. */
177 : 0 : memcpy (buffer, rawchunk, size);
178 : :
179 : 0 : free (rawchunk);
180 : : }
181 : : }
182 : : else
183 : : {
184 [ + + ]: 710 : if (flags)
185 : : buffer = rawchunk;
186 : : else
187 : : {
188 : 656 : buffer = malloc (size);
189 [ - + ]: 656 : if (unlikely (buffer == NULL))
190 : 0 : goto nomem;
191 : : flags = ELF_F_MALLOCED;
192 : : }
193 : :
194 : : /* Call the conversion function. */
195 : 710 : (*__elf_xfctstom[elf->class - 1][type])(buffer, rawchunk, size, 0);
196 : :
197 : 710 : if (!flags)
198 : : free (rawchunk);
199 : : }
200 : :
201 : : /* Allocate the dummy container to point at this buffer. */
202 : 2304 : Elf_Data_Chunk *chunk = calloc (1, sizeof *chunk);
203 [ - + ]: 2304 : if (chunk == NULL)
204 : : {
205 [ # # ]: 0 : if (flags)
206 : 0 : free (buffer);
207 : 0 : goto nomem;
208 : : }
209 : :
210 : 2304 : chunk->dummy_scn.elf = elf;
211 : 2304 : chunk->dummy_scn.flags = flags;
212 : 2304 : chunk->data.s = &chunk->dummy_scn;
213 : 2304 : chunk->data.d.d_buf = buffer;
214 : 2304 : chunk->data.d.d_size = size;
215 : 2304 : chunk->data.d.d_type = type;
216 : 2304 : chunk->data.d.d_align = align;
217 : 2304 : chunk->data.d.d_version = EV_CURRENT;
218 : 2304 : chunk->offset = offset;
219 : :
220 : 2304 : rwlock_unlock (elf->lock);
221 : 2304 : rwlock_wrlock (elf->lock);
222 : :
223 : 2304 : *found = chunk;
224 : 2304 : result = &chunk->data.d;
225 : :
226 : : out:
227 : : rwlock_unlock (elf->lock);
228 : : return result;
229 : : }
|