]> git.ipfire.org Git - thirdparty/elfutils.git/blame - libelf/elf_getdata_rawchunk.c
funcretval-struct
[thirdparty/elfutils.git] / libelf / elf_getdata_rawchunk.c
CommitLineData
59ea7f33 1/* Return converted data from raw chunk of ELF file.
1ccdfb68 2 Copyright (C) 2007, 2014, 2015 Red Hat, Inc.
35e059b6 3 Copyright (C) 2022, 2023 Mark J. Wielaard <mark@klomp.org>
de2ed97f 4 This file is part of elfutils.
b08d5a8f 5
de2ed97f
MW
6 This file is free software; you can redistribute it and/or modify
7 it under the terms of either
b08d5a8f 8
de2ed97f
MW
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
361df7da
UD
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.
b08d5a8f 25
de2ed97f
MW
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/>. */
b08d5a8f
UD
29
30#ifdef HAVE_CONFIG_H
31# include <config.h>
32#endif
33
59ea7f33 34#include <assert.h>
fbe998a0 35#include <errno.h>
35e059b6 36#include <search.h>
b08d5a8f 37#include <stdlib.h>
59ea7f33 38#include <string.h>
b08d5a8f
UD
39
40#include "libelfP.h"
59ea7f33 41#include "common.h"
b08d5a8f 42
35e059b6
MW
43static int
44chunk_compare (const void *a, const void *b)
45{
46 Elf_Data_Chunk *da = (Elf_Data_Chunk *)a;
47 Elf_Data_Chunk *db = (Elf_Data_Chunk *)b;
48
49 if (da->offset != db->offset)
50 return da->offset - db->offset;
51
52 if (da->data.d.d_size != db->data.d.d_size)
53 return da->data.d.d_size - db->data.d.d_size;
54
55 return da->data.d.d_type - db->data.d.d_type;
56}
57
59ea7f33 58Elf_Data *
a46200f6 59elf_getdata_rawchunk (Elf *elf, int64_t offset, size_t size, Elf_Type type)
b08d5a8f 60{
59ea7f33
RM
61 if (unlikely (elf == NULL))
62 return NULL;
63
64 if (unlikely (elf->kind != ELF_K_ELF))
b08d5a8f
UD
65 {
66 /* No valid descriptor. */
67 __libelf_seterrno (ELF_E_INVALID_HANDLE);
68 return NULL;
69 }
70
f62658f7
MW
71 if (unlikely (offset < 0 || (uint64_t) offset > elf->maximum_size
72 || elf->maximum_size - (uint64_t) offset < size))
73
b08d5a8f
UD
74 {
75 /* Invalid request. */
76 __libelf_seterrno (ELF_E_INVALID_OP);
77 return NULL;
78 }
79
59ea7f33
RM
80 if (type >= ELF_T_NUM)
81 {
82 __libelf_seterrno (ELF_E_UNKNOWN_TYPE);
83 return NULL;
84 }
85
86 /* Get the raw bytes from the file. */
87 void *rawchunk;
88 int flags = 0;
02f66452
UD
89 Elf_Data *result = NULL;
90
91 rwlock_rdlock (elf->lock);
59ea7f33 92
8db84997 93 /* Maybe we already got this chunk? */
35e059b6
MW
94 Elf_Data_Chunk key;
95 key.offset = offset;
96 key.data.d.d_size = size;
97 key.data.d.d_type = type;
98 Elf_Data_Chunk **found = tsearch (&key, &elf->state.elf.rawchunks,
99 &chunk_compare);
100 if (found == NULL)
101 goto nomem;
102
103 /* Existing entry. */
104 if (*found != &key && *found != NULL)
8db84997 105 {
35e059b6
MW
106 result = &(*found)->data.d;
107 goto out;
8db84997
MW
108 }
109
d0525deb
MW
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. */
35e059b6 114
ede1d9d8 115 size_t align = __libelf_type_align (elf->class, type);
b08d5a8f 116 if (elf->map_address != NULL)
ede1d9d8
MW
117 {
118 /* If the file is mmap'ed we can use it directly, if aligned for type. */
119 char *rawdata = elf->map_address + elf->start_offset + offset;
dd813335 120 if (((uintptr_t) rawdata & (align - 1)) == 0)
ede1d9d8
MW
121 rawchunk = rawdata;
122 else
123 {
124 /* We allocate the memory and memcpy it to get aligned data. */
125 rawchunk = malloc (size);
126 if (rawchunk == NULL)
127 goto nomem;
128 memcpy (rawchunk, rawdata, size);
129 flags = ELF_F_MALLOCED;
130 }
131 }
59ea7f33
RM
132 else
133 {
134 /* We allocate the memory and read the data from the file. */
135 rawchunk = malloc (size);
136 if (rawchunk == NULL)
137 {
138 nomem:
d0525deb 139 tdelete (&key, &elf->state.elf.rawchunks, &chunk_compare);
59ea7f33 140 __libelf_seterrno (ELF_E_NOMEM);
02f66452 141 goto out;
59ea7f33
RM
142 }
143
144 /* Read the file content. */
145 if (unlikely ((size_t) pread_retry (elf->fildes, rawchunk, size,
146 elf->start_offset + offset)
147 != size))
148 {
149 /* Something went wrong. */
d0525deb 150 tdelete (&key, &elf->state.elf.rawchunks, &chunk_compare);
59ea7f33
RM
151 free (rawchunk);
152 __libelf_seterrno (ELF_E_READ_ERROR);
02f66452 153 goto out;
59ea7f33 154 }
b08d5a8f 155
59ea7f33
RM
156 flags = ELF_F_MALLOCED;
157 }
158
159 /* Copy and/or convert the data as needed for aligned native-order access. */
59ea7f33
RM
160 void *buffer;
161 if (elf->state.elf32.ehdr->e_ident[EI_DATA] == MY_ELFDATA)
162 {
163 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 assert (flags == 0);
170
171 buffer = malloc (size);
172 if (unlikely (buffer == NULL))
173 goto nomem;
174 flags = ELF_F_MALLOCED;
175
176 /* The copy will be appropriately aligned for direct access. */
177 memcpy (buffer, rawchunk, size);
b21b4dfc
MW
178
179 free (rawchunk);
59ea7f33
RM
180 }
181 }
b08d5a8f 182 else
59ea7f33
RM
183 {
184 if (flags)
185 buffer = rawchunk;
186 else
187 {
188 buffer = malloc (size);
189 if (unlikely (buffer == NULL))
190 goto nomem;
191 flags = ELF_F_MALLOCED;
192 }
193
194 /* Call the conversion function. */
b9d16789 195 (*__elf_xfctstom[elf->class - 1][type])(buffer, rawchunk, size, 0);
b21b4dfc
MW
196
197 if (!flags)
198 free (rawchunk);
59ea7f33
RM
199 }
200
201 /* Allocate the dummy container to point at this buffer. */
202 Elf_Data_Chunk *chunk = calloc (1, sizeof *chunk);
203 if (chunk == NULL)
204 {
205 if (flags)
206 free (buffer);
207 goto nomem;
208 }
209
210 chunk->dummy_scn.elf = elf;
211 chunk->dummy_scn.flags = flags;
212 chunk->data.s = &chunk->dummy_scn;
213 chunk->data.d.d_buf = buffer;
214 chunk->data.d.d_size = size;
215 chunk->data.d.d_type = type;
216 chunk->data.d.d_align = align;
b9d16789 217 chunk->data.d.d_version = EV_CURRENT;
8db84997 218 chunk->offset = offset;
59ea7f33 219
02f66452
UD
220 rwlock_unlock (elf->lock);
221 rwlock_wrlock (elf->lock);
222
35e059b6 223 *found = chunk;
02f66452 224 result = &chunk->data.d;
59ea7f33 225
02f66452
UD
226 out:
227 rwlock_unlock (elf->lock);
228 return result;
b08d5a8f 229}