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 (((uintptr_t) rawdata & (align - 1)) == 0)
84 rawchunk = rawdata;
85 else
86 {
87 /* We allocate the memory and memcpy it to get aligned data. */
88 rawchunk = malloc (size);
89 if (rawchunk == NULL)
90 goto nomem;
91 memcpy (rawchunk, rawdata, size);
92 flags = ELF_F_MALLOCED;
93 }
94 }
95 else
96 {
97 /* We allocate the memory and read the data from the file. */
98 rawchunk = malloc (size);
99 if (rawchunk == NULL)
100 {
101 nomem:
102 __libelf_seterrno (ELF_E_NOMEM);
103 goto out;
104 }
105
106 /* Read the file content. */
107 if (unlikely ((size_t) pread_retry (elf->fildes, rawchunk, size,
108 elf->start_offset + offset)
109 != size))
110 {
111 /* Something went wrong. */
112 free (rawchunk);
113 __libelf_seterrno (ELF_E_READ_ERROR);
114 goto out;
115 }
116
117 flags = ELF_F_MALLOCED;
118 }
119
120 /* Copy and/or convert the data as needed for aligned native-order access. */
121 void *buffer;
122 if (elf->state.elf32.ehdr->e_ident[EI_DATA] == MY_ELFDATA)
123 {
124 if (((uintptr_t) rawchunk & (align - 1)) == 0)
125 /* No need to copy, we can use the raw data. */
126 buffer = rawchunk;
127 else
128 {
129 /* A malloc'd block is always sufficiently aligned. */
130 assert (flags == 0);
131
132 buffer = malloc (size);
133 if (unlikely (buffer == NULL))
134 goto nomem;
135 flags = ELF_F_MALLOCED;
136
137 /* The copy will be appropriately aligned for direct access. */
138 memcpy (buffer, rawchunk, size);
139 }
140 }
141 else
142 {
143 if (flags)
144 buffer = rawchunk;
145 else
146 {
147 buffer = malloc (size);
148 if (unlikely (buffer == NULL))
149 goto nomem;
150 flags = ELF_F_MALLOCED;
151 }
152
153 /* Call the conversion function. */
154 (*__elf_xfctstom[elf->class - 1][type])(buffer, rawchunk, size, 0);
155 }
156
157 /* Allocate the dummy container to point at this buffer. */
158 Elf_Data_Chunk *chunk = calloc (1, sizeof *chunk);
159 if (chunk == NULL)
160 {
161 if (flags)
162 free (buffer);
163 goto nomem;
164 }
165
166 chunk->dummy_scn.elf = elf;
167 chunk->dummy_scn.flags = flags;
168 chunk->data.s = &chunk->dummy_scn;
169 chunk->data.d.d_buf = buffer;
170 chunk->data.d.d_size = size;
171 chunk->data.d.d_type = type;
172 chunk->data.d.d_align = align;
173 chunk->data.d.d_version = EV_CURRENT;
174
175 rwlock_unlock (elf->lock);
176 rwlock_wrlock (elf->lock);
177
178 chunk->next = elf->state.elf.rawchunks;
179 elf->state.elf.rawchunks = chunk;
180 result = &chunk->data.d;
181
182 out:
183 rwlock_unlock (elf->lock);
184 return result;
185 }
186