1*7304104dSAndroid Build Coastguard Worker /* Return converted data from raw chunk of ELF file.
2*7304104dSAndroid Build Coastguard Worker Copyright (C) 2007, 2014, 2015 Red Hat, Inc.
3*7304104dSAndroid Build Coastguard Worker Copyright (C) 2022, 2023 Mark J. Wielaard <[email protected]>
4*7304104dSAndroid Build Coastguard Worker This file is part of elfutils.
5*7304104dSAndroid Build Coastguard Worker
6*7304104dSAndroid Build Coastguard Worker This file is free software; you can redistribute it and/or modify
7*7304104dSAndroid Build Coastguard Worker it under the terms of either
8*7304104dSAndroid Build Coastguard Worker
9*7304104dSAndroid Build Coastguard Worker * the GNU Lesser General Public License as published by the Free
10*7304104dSAndroid Build Coastguard Worker Software Foundation; either version 3 of the License, or (at
11*7304104dSAndroid Build Coastguard Worker your option) any later version
12*7304104dSAndroid Build Coastguard Worker
13*7304104dSAndroid Build Coastguard Worker or
14*7304104dSAndroid Build Coastguard Worker
15*7304104dSAndroid Build Coastguard Worker * the GNU General Public License as published by the Free
16*7304104dSAndroid Build Coastguard Worker Software Foundation; either version 2 of the License, or (at
17*7304104dSAndroid Build Coastguard Worker your option) any later version
18*7304104dSAndroid Build Coastguard Worker
19*7304104dSAndroid Build Coastguard Worker or both in parallel, as here.
20*7304104dSAndroid Build Coastguard Worker
21*7304104dSAndroid Build Coastguard Worker elfutils is distributed in the hope that it will be useful, but
22*7304104dSAndroid Build Coastguard Worker WITHOUT ANY WARRANTY; without even the implied warranty of
23*7304104dSAndroid Build Coastguard Worker MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24*7304104dSAndroid Build Coastguard Worker General Public License for more details.
25*7304104dSAndroid Build Coastguard Worker
26*7304104dSAndroid Build Coastguard Worker You should have received copies of the GNU General Public License and
27*7304104dSAndroid Build Coastguard Worker the GNU Lesser General Public License along with this program. If
28*7304104dSAndroid Build Coastguard Worker not, see <http://www.gnu.org/licenses/>. */
29*7304104dSAndroid Build Coastguard Worker
30*7304104dSAndroid Build Coastguard Worker #ifdef HAVE_CONFIG_H
31*7304104dSAndroid Build Coastguard Worker # include <config.h>
32*7304104dSAndroid Build Coastguard Worker #endif
33*7304104dSAndroid Build Coastguard Worker
34*7304104dSAndroid Build Coastguard Worker #include <assert.h>
35*7304104dSAndroid Build Coastguard Worker #include <errno.h>
36*7304104dSAndroid Build Coastguard Worker #include <search.h>
37*7304104dSAndroid Build Coastguard Worker #include <stdlib.h>
38*7304104dSAndroid Build Coastguard Worker #include <string.h>
39*7304104dSAndroid Build Coastguard Worker
40*7304104dSAndroid Build Coastguard Worker #include "libelfP.h"
41*7304104dSAndroid Build Coastguard Worker #include "common.h"
42*7304104dSAndroid Build Coastguard Worker
43*7304104dSAndroid Build Coastguard Worker static int
chunk_compare(const void * a,const void * b)44*7304104dSAndroid Build Coastguard Worker chunk_compare (const void *a, const void *b)
45*7304104dSAndroid Build Coastguard Worker {
46*7304104dSAndroid Build Coastguard Worker Elf_Data_Chunk *da = (Elf_Data_Chunk *)a;
47*7304104dSAndroid Build Coastguard Worker Elf_Data_Chunk *db = (Elf_Data_Chunk *)b;
48*7304104dSAndroid Build Coastguard Worker
49*7304104dSAndroid Build Coastguard Worker if (da->offset != db->offset)
50*7304104dSAndroid Build Coastguard Worker return da->offset - db->offset;
51*7304104dSAndroid Build Coastguard Worker
52*7304104dSAndroid Build Coastguard Worker if (da->data.d.d_size != db->data.d.d_size)
53*7304104dSAndroid Build Coastguard Worker return da->data.d.d_size - db->data.d.d_size;
54*7304104dSAndroid Build Coastguard Worker
55*7304104dSAndroid Build Coastguard Worker return da->data.d.d_type - db->data.d.d_type;
56*7304104dSAndroid Build Coastguard Worker }
57*7304104dSAndroid Build Coastguard Worker
58*7304104dSAndroid Build Coastguard Worker Elf_Data *
elf_getdata_rawchunk(Elf * elf,int64_t offset,size_t size,Elf_Type type)59*7304104dSAndroid Build Coastguard Worker elf_getdata_rawchunk (Elf *elf, int64_t offset, size_t size, Elf_Type type)
60*7304104dSAndroid Build Coastguard Worker {
61*7304104dSAndroid Build Coastguard Worker if (unlikely (elf == NULL))
62*7304104dSAndroid Build Coastguard Worker return NULL;
63*7304104dSAndroid Build Coastguard Worker
64*7304104dSAndroid Build Coastguard Worker if (unlikely (elf->kind != ELF_K_ELF))
65*7304104dSAndroid Build Coastguard Worker {
66*7304104dSAndroid Build Coastguard Worker /* No valid descriptor. */
67*7304104dSAndroid Build Coastguard Worker __libelf_seterrno (ELF_E_INVALID_HANDLE);
68*7304104dSAndroid Build Coastguard Worker return NULL;
69*7304104dSAndroid Build Coastguard Worker }
70*7304104dSAndroid Build Coastguard Worker
71*7304104dSAndroid Build Coastguard Worker if (unlikely (offset < 0 || (uint64_t) offset > elf->maximum_size
72*7304104dSAndroid Build Coastguard Worker || elf->maximum_size - (uint64_t) offset < size))
73*7304104dSAndroid Build Coastguard Worker
74*7304104dSAndroid Build Coastguard Worker {
75*7304104dSAndroid Build Coastguard Worker /* Invalid request. */
76*7304104dSAndroid Build Coastguard Worker __libelf_seterrno (ELF_E_INVALID_OP);
77*7304104dSAndroid Build Coastguard Worker return NULL;
78*7304104dSAndroid Build Coastguard Worker }
79*7304104dSAndroid Build Coastguard Worker
80*7304104dSAndroid Build Coastguard Worker if (type >= ELF_T_NUM)
81*7304104dSAndroid Build Coastguard Worker {
82*7304104dSAndroid Build Coastguard Worker __libelf_seterrno (ELF_E_UNKNOWN_TYPE);
83*7304104dSAndroid Build Coastguard Worker return NULL;
84*7304104dSAndroid Build Coastguard Worker }
85*7304104dSAndroid Build Coastguard Worker
86*7304104dSAndroid Build Coastguard Worker /* Get the raw bytes from the file. */
87*7304104dSAndroid Build Coastguard Worker void *rawchunk;
88*7304104dSAndroid Build Coastguard Worker int flags = 0;
89*7304104dSAndroid Build Coastguard Worker Elf_Data *result = NULL;
90*7304104dSAndroid Build Coastguard Worker
91*7304104dSAndroid Build Coastguard Worker rwlock_rdlock (elf->lock);
92*7304104dSAndroid Build Coastguard Worker
93*7304104dSAndroid Build Coastguard Worker /* Maybe we already got this chunk? */
94*7304104dSAndroid Build Coastguard Worker Elf_Data_Chunk key;
95*7304104dSAndroid Build Coastguard Worker key.offset = offset;
96*7304104dSAndroid Build Coastguard Worker key.data.d.d_size = size;
97*7304104dSAndroid Build Coastguard Worker key.data.d.d_type = type;
98*7304104dSAndroid Build Coastguard Worker Elf_Data_Chunk **found = tsearch (&key, &elf->state.elf.rawchunks,
99*7304104dSAndroid Build Coastguard Worker &chunk_compare);
100*7304104dSAndroid Build Coastguard Worker if (found == NULL)
101*7304104dSAndroid Build Coastguard Worker goto nomem;
102*7304104dSAndroid Build Coastguard Worker
103*7304104dSAndroid Build Coastguard Worker /* Existing entry. */
104*7304104dSAndroid Build Coastguard Worker if (*found != &key && *found != NULL)
105*7304104dSAndroid Build Coastguard Worker {
106*7304104dSAndroid Build Coastguard Worker result = &(*found)->data.d;
107*7304104dSAndroid Build Coastguard Worker goto out;
108*7304104dSAndroid Build Coastguard Worker }
109*7304104dSAndroid Build Coastguard Worker
110*7304104dSAndroid Build Coastguard Worker /* New entry. Note that *found will point to the newly inserted
111*7304104dSAndroid Build Coastguard Worker (dummy) key. We'll replace it with a real rawchunk when that is
112*7304104dSAndroid Build Coastguard Worker setup. Make sure to tdelete the dummy key if anything goes
113*7304104dSAndroid Build Coastguard Worker wrong. */
114*7304104dSAndroid Build Coastguard Worker
115*7304104dSAndroid Build Coastguard Worker size_t align = __libelf_type_align (elf->class, type);
116*7304104dSAndroid Build Coastguard Worker if (elf->map_address != NULL)
117*7304104dSAndroid Build Coastguard Worker {
118*7304104dSAndroid Build Coastguard Worker /* If the file is mmap'ed we can use it directly, if aligned for type. */
119*7304104dSAndroid Build Coastguard Worker char *rawdata = elf->map_address + elf->start_offset + offset;
120*7304104dSAndroid Build Coastguard Worker if (((uintptr_t) rawdata & (align - 1)) == 0)
121*7304104dSAndroid Build Coastguard Worker rawchunk = rawdata;
122*7304104dSAndroid Build Coastguard Worker else
123*7304104dSAndroid Build Coastguard Worker {
124*7304104dSAndroid Build Coastguard Worker /* We allocate the memory and memcpy it to get aligned data. */
125*7304104dSAndroid Build Coastguard Worker rawchunk = malloc (size);
126*7304104dSAndroid Build Coastguard Worker if (rawchunk == NULL)
127*7304104dSAndroid Build Coastguard Worker goto nomem;
128*7304104dSAndroid Build Coastguard Worker memcpy (rawchunk, rawdata, size);
129*7304104dSAndroid Build Coastguard Worker flags = ELF_F_MALLOCED;
130*7304104dSAndroid Build Coastguard Worker }
131*7304104dSAndroid Build Coastguard Worker }
132*7304104dSAndroid Build Coastguard Worker else
133*7304104dSAndroid Build Coastguard Worker {
134*7304104dSAndroid Build Coastguard Worker /* We allocate the memory and read the data from the file. */
135*7304104dSAndroid Build Coastguard Worker rawchunk = malloc (size);
136*7304104dSAndroid Build Coastguard Worker if (rawchunk == NULL)
137*7304104dSAndroid Build Coastguard Worker {
138*7304104dSAndroid Build Coastguard Worker nomem:
139*7304104dSAndroid Build Coastguard Worker tdelete (&key, &elf->state.elf.rawchunks, &chunk_compare);
140*7304104dSAndroid Build Coastguard Worker __libelf_seterrno (ELF_E_NOMEM);
141*7304104dSAndroid Build Coastguard Worker goto out;
142*7304104dSAndroid Build Coastguard Worker }
143*7304104dSAndroid Build Coastguard Worker
144*7304104dSAndroid Build Coastguard Worker /* Read the file content. */
145*7304104dSAndroid Build Coastguard Worker if (unlikely ((size_t) pread_retry (elf->fildes, rawchunk, size,
146*7304104dSAndroid Build Coastguard Worker elf->start_offset + offset)
147*7304104dSAndroid Build Coastguard Worker != size))
148*7304104dSAndroid Build Coastguard Worker {
149*7304104dSAndroid Build Coastguard Worker /* Something went wrong. */
150*7304104dSAndroid Build Coastguard Worker tdelete (&key, &elf->state.elf.rawchunks, &chunk_compare);
151*7304104dSAndroid Build Coastguard Worker free (rawchunk);
152*7304104dSAndroid Build Coastguard Worker __libelf_seterrno (ELF_E_READ_ERROR);
153*7304104dSAndroid Build Coastguard Worker goto out;
154*7304104dSAndroid Build Coastguard Worker }
155*7304104dSAndroid Build Coastguard Worker
156*7304104dSAndroid Build Coastguard Worker flags = ELF_F_MALLOCED;
157*7304104dSAndroid Build Coastguard Worker }
158*7304104dSAndroid Build Coastguard Worker
159*7304104dSAndroid Build Coastguard Worker /* Copy and/or convert the data as needed for aligned native-order access. */
160*7304104dSAndroid Build Coastguard Worker void *buffer;
161*7304104dSAndroid Build Coastguard Worker if (elf->state.elf32.ehdr->e_ident[EI_DATA] == MY_ELFDATA)
162*7304104dSAndroid Build Coastguard Worker {
163*7304104dSAndroid Build Coastguard Worker if (((uintptr_t) rawchunk & (align - 1)) == 0)
164*7304104dSAndroid Build Coastguard Worker /* No need to copy, we can use the raw data. */
165*7304104dSAndroid Build Coastguard Worker buffer = rawchunk;
166*7304104dSAndroid Build Coastguard Worker else
167*7304104dSAndroid Build Coastguard Worker {
168*7304104dSAndroid Build Coastguard Worker /* A malloc'd block is always sufficiently aligned. */
169*7304104dSAndroid Build Coastguard Worker assert (flags == 0);
170*7304104dSAndroid Build Coastguard Worker
171*7304104dSAndroid Build Coastguard Worker buffer = malloc (size);
172*7304104dSAndroid Build Coastguard Worker if (unlikely (buffer == NULL))
173*7304104dSAndroid Build Coastguard Worker goto nomem;
174*7304104dSAndroid Build Coastguard Worker flags = ELF_F_MALLOCED;
175*7304104dSAndroid Build Coastguard Worker
176*7304104dSAndroid Build Coastguard Worker /* The copy will be appropriately aligned for direct access. */
177*7304104dSAndroid Build Coastguard Worker memcpy (buffer, rawchunk, size);
178*7304104dSAndroid Build Coastguard Worker
179*7304104dSAndroid Build Coastguard Worker free (rawchunk);
180*7304104dSAndroid Build Coastguard Worker }
181*7304104dSAndroid Build Coastguard Worker }
182*7304104dSAndroid Build Coastguard Worker else
183*7304104dSAndroid Build Coastguard Worker {
184*7304104dSAndroid Build Coastguard Worker if (flags)
185*7304104dSAndroid Build Coastguard Worker buffer = rawchunk;
186*7304104dSAndroid Build Coastguard Worker else
187*7304104dSAndroid Build Coastguard Worker {
188*7304104dSAndroid Build Coastguard Worker buffer = malloc (size);
189*7304104dSAndroid Build Coastguard Worker if (unlikely (buffer == NULL))
190*7304104dSAndroid Build Coastguard Worker goto nomem;
191*7304104dSAndroid Build Coastguard Worker flags = ELF_F_MALLOCED;
192*7304104dSAndroid Build Coastguard Worker }
193*7304104dSAndroid Build Coastguard Worker
194*7304104dSAndroid Build Coastguard Worker /* Call the conversion function. */
195*7304104dSAndroid Build Coastguard Worker (*__elf_xfctstom[elf->class - 1][type])(buffer, rawchunk, size, 0);
196*7304104dSAndroid Build Coastguard Worker
197*7304104dSAndroid Build Coastguard Worker if (!flags)
198*7304104dSAndroid Build Coastguard Worker free (rawchunk);
199*7304104dSAndroid Build Coastguard Worker }
200*7304104dSAndroid Build Coastguard Worker
201*7304104dSAndroid Build Coastguard Worker /* Allocate the dummy container to point at this buffer. */
202*7304104dSAndroid Build Coastguard Worker Elf_Data_Chunk *chunk = calloc (1, sizeof *chunk);
203*7304104dSAndroid Build Coastguard Worker if (chunk == NULL)
204*7304104dSAndroid Build Coastguard Worker {
205*7304104dSAndroid Build Coastguard Worker if (flags)
206*7304104dSAndroid Build Coastguard Worker free (buffer);
207*7304104dSAndroid Build Coastguard Worker goto nomem;
208*7304104dSAndroid Build Coastguard Worker }
209*7304104dSAndroid Build Coastguard Worker
210*7304104dSAndroid Build Coastguard Worker chunk->dummy_scn.elf = elf;
211*7304104dSAndroid Build Coastguard Worker chunk->dummy_scn.flags = flags;
212*7304104dSAndroid Build Coastguard Worker chunk->data.s = &chunk->dummy_scn;
213*7304104dSAndroid Build Coastguard Worker chunk->data.d.d_buf = buffer;
214*7304104dSAndroid Build Coastguard Worker chunk->data.d.d_size = size;
215*7304104dSAndroid Build Coastguard Worker chunk->data.d.d_type = type;
216*7304104dSAndroid Build Coastguard Worker chunk->data.d.d_align = align;
217*7304104dSAndroid Build Coastguard Worker chunk->data.d.d_version = EV_CURRENT;
218*7304104dSAndroid Build Coastguard Worker chunk->offset = offset;
219*7304104dSAndroid Build Coastguard Worker
220*7304104dSAndroid Build Coastguard Worker rwlock_unlock (elf->lock);
221*7304104dSAndroid Build Coastguard Worker rwlock_wrlock (elf->lock);
222*7304104dSAndroid Build Coastguard Worker
223*7304104dSAndroid Build Coastguard Worker *found = chunk;
224*7304104dSAndroid Build Coastguard Worker result = &chunk->data.d;
225*7304104dSAndroid Build Coastguard Worker
226*7304104dSAndroid Build Coastguard Worker out:
227*7304104dSAndroid Build Coastguard Worker rwlock_unlock (elf->lock);
228*7304104dSAndroid Build Coastguard Worker return result;
229*7304104dSAndroid Build Coastguard Worker }
230