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