1 /* Return converted data from raw chunk of ELF file.
2 Copyright (C) 2007, 2014, 2015 Red Hat, Inc.
3 Copyright (C) 2022 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 <stdlib.h>
37 #include <string.h>
38
39 #include "libelfP.h"
40 #include "common.h"
41
42 Elf_Data *
elf_getdata_rawchunk(Elf * elf,int64_t offset,size_t size,Elf_Type type)43 elf_getdata_rawchunk (Elf *elf, int64_t offset, size_t size, Elf_Type type)
44 {
45 if (unlikely (elf == NULL))
46 return NULL;
47
48 if (unlikely (elf->kind != ELF_K_ELF))
49 {
50 /* No valid descriptor. */
51 __libelf_seterrno (ELF_E_INVALID_HANDLE);
52 return NULL;
53 }
54
55 if (unlikely (offset < 0 || (uint64_t) offset > elf->maximum_size
56 || elf->maximum_size - (uint64_t) offset < size))
57
58 {
59 /* Invalid request. */
60 __libelf_seterrno (ELF_E_INVALID_OP);
61 return NULL;
62 }
63
64 if (type >= ELF_T_NUM)
65 {
66 __libelf_seterrno (ELF_E_UNKNOWN_TYPE);
67 return NULL;
68 }
69
70 /* Get the raw bytes from the file. */
71 void *rawchunk;
72 int flags = 0;
73 Elf_Data *result = NULL;
74
75 rwlock_rdlock (elf->lock);
76
77 /* Maybe we already got this chunk? */
78 Elf_Data_Chunk *rawchunks = elf->state.elf.rawchunks;
79 while (rawchunks != NULL)
80 {
81 if ((rawchunks->offset == offset || size == 0)
82 && rawchunks->data.d.d_size == size
83 && rawchunks->data.d.d_type == type)
84 {
85 result = &rawchunks->data.d;
86 goto out;
87 }
88 rawchunks = rawchunks->next;
89 }
90
91 size_t align = __libelf_type_align (elf->class, type);
92 if (elf->map_address != NULL)
93 {
94 /* If the file is mmap'ed we can use it directly, if aligned for type. */
95 char *rawdata = elf->map_address + elf->start_offset + offset;
96 if (((uintptr_t) rawdata & (align - 1)) == 0)
97 rawchunk = rawdata;
98 else
99 {
100 /* We allocate the memory and memcpy it to get aligned data. */
101 rawchunk = malloc (size);
102 if (rawchunk == NULL)
103 goto nomem;
104 memcpy (rawchunk, rawdata, size);
105 flags = ELF_F_MALLOCED;
106 }
107 }
108 else
109 {
110 /* We allocate the memory and read the data from the file. */
111 rawchunk = malloc (size);
112 if (rawchunk == NULL)
113 {
114 nomem:
115 __libelf_seterrno (ELF_E_NOMEM);
116 goto out;
117 }
118
119 /* Read the file content. */
120 if (unlikely ((size_t) pread_retry (elf->fildes, rawchunk, size,
121 elf->start_offset + offset)
122 != size))
123 {
124 /* Something went wrong. */
125 free (rawchunk);
126 __libelf_seterrno (ELF_E_READ_ERROR);
127 goto out;
128 }
129
130 flags = ELF_F_MALLOCED;
131 }
132
133 /* Copy and/or convert the data as needed for aligned native-order access. */
134 void *buffer;
135 if (elf->state.elf32.ehdr->e_ident[EI_DATA] == MY_ELFDATA)
136 {
137 if (((uintptr_t) rawchunk & (align - 1)) == 0)
138 /* No need to copy, we can use the raw data. */
139 buffer = rawchunk;
140 else
141 {
142 /* A malloc'd block is always sufficiently aligned. */
143 assert (flags == 0);
144
145 buffer = malloc (size);
146 if (unlikely (buffer == NULL))
147 goto nomem;
148 flags = ELF_F_MALLOCED;
149
150 /* The copy will be appropriately aligned for direct access. */
151 memcpy (buffer, rawchunk, size);
152 }
153 }
154 else
155 {
156 if (flags)
157 buffer = rawchunk;
158 else
159 {
160 buffer = malloc (size);
161 if (unlikely (buffer == NULL))
162 goto nomem;
163 flags = ELF_F_MALLOCED;
164 }
165
166 /* Call the conversion function. */
167 (*__elf_xfctstom[elf->class - 1][type])(buffer, rawchunk, size, 0);
168 }
169
170 /* Allocate the dummy container to point at this buffer. */
171 Elf_Data_Chunk *chunk = calloc (1, sizeof *chunk);
172 if (chunk == NULL)
173 {
174 if (flags)
175 free (buffer);
176 goto nomem;
177 }
178
179 chunk->dummy_scn.elf = elf;
180 chunk->dummy_scn.flags = flags;
181 chunk->data.s = &chunk->dummy_scn;
182 chunk->data.d.d_buf = buffer;
183 chunk->data.d.d_size = size;
184 chunk->data.d.d_type = type;
185 chunk->data.d.d_align = align;
186 chunk->data.d.d_version = EV_CURRENT;
187 chunk->offset = offset;
188
189 rwlock_unlock (elf->lock);
190 rwlock_wrlock (elf->lock);
191
192 chunk->next = elf->state.elf.rawchunks;
193 elf->state.elf.rawchunks = chunk;
194 result = &chunk->data.d;
195
196 out:
197 rwlock_unlock (elf->lock);
198 return result;
199 }
200