Line data Source code
1 : /* Unaligned memory access functionality.
2 : Copyright (C) 2000-2014, 2018 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 : #ifndef _MEMORY_ACCESS_H
30 : #define _MEMORY_ACCESS_H 1
31 :
32 : #include <byteswap.h>
33 : #include <endian.h>
34 : #include <limits.h>
35 : #include <stdint.h>
36 :
37 :
38 : /* Number decoding macros. See 7.6 Variable Length Data. */
39 :
40 : #define len_leb128(var) ((8 * sizeof (var) + 6) / 7)
41 :
42 : static inline size_t
43 : __libdw_max_len_leb128 (const size_t type_len,
44 : const unsigned char *addr, const unsigned char *end)
45 : {
46 340620 : const size_t pointer_len = likely (addr < end) ? end - addr : 0;
47 340620 : return likely (type_len <= pointer_len) ? type_len : pointer_len;
48 : }
49 :
50 : static inline size_t
51 : __libdw_max_len_uleb128 (const unsigned char *addr, const unsigned char *end)
52 : {
53 156016 : const size_t type_len = len_leb128 (uint64_t);
54 156016 : return __libdw_max_len_leb128 (type_len, addr, end);
55 : }
56 :
57 : static inline size_t
58 : __libdw_max_len_sleb128 (const unsigned char *addr, const unsigned char *end)
59 : {
60 : /* Subtract one step, so we don't shift into sign bit. */
61 184604 : const size_t type_len = len_leb128 (int64_t) - 1;
62 184604 : return __libdw_max_len_leb128 (type_len, addr, end);
63 : }
64 :
65 : #define get_uleb128_step(var, addr, nth) \
66 : do { \
67 : unsigned char __b = *(addr)++; \
68 : (var) |= (typeof (var)) (__b & 0x7f) << ((nth) * 7); \
69 : if (likely ((__b & 0x80) == 0)) \
70 : return (var); \
71 : } while (0)
72 :
73 : static inline uint64_t
74 83204835 : __libdw_get_uleb128 (const unsigned char **addrp, const unsigned char *end)
75 : {
76 83204835 : uint64_t acc = 0;
77 :
78 : /* Unroll the first step to help the compiler optimize
79 : for the common single-byte case. */
80 83204835 : get_uleb128_step (acc, *addrp, 0);
81 :
82 312032 : const size_t max = __libdw_max_len_uleb128 (*addrp - 1, end);
83 193971 : for (size_t i = 1; i < max; ++i)
84 193971 : get_uleb128_step (acc, *addrp, i);
85 : /* Other implementations set VALUE to UINT_MAX in this
86 : case. So we better do this as well. */
87 : return UINT64_MAX;
88 : }
89 :
90 : static inline uint64_t
91 467684746 : __libdw_get_uleb128_unchecked (const unsigned char **addrp)
92 : {
93 467684746 : uint64_t acc = 0;
94 :
95 : /* Unroll the first step to help the compiler optimize
96 : for the common single-byte case. */
97 467684746 : get_uleb128_step (acc, *addrp, 0);
98 :
99 : const size_t max = len_leb128 (uint64_t);
100 0 : for (size_t i = 1; i < max; ++i)
101 4325733 : get_uleb128_step (acc, *addrp, i);
102 : /* Other implementations set VALUE to UINT_MAX in this
103 : case. So we better do this as well. */
104 : return UINT64_MAX;
105 : }
106 :
107 : /* Note, addr needs to me smaller than end. */
108 : #define get_uleb128(var, addr, end) ((var) = __libdw_get_uleb128 (&(addr), end))
109 : #define get_uleb128_unchecked(var, addr) ((var) = __libdw_get_uleb128_unchecked (&(addr)))
110 :
111 : /* The signed case is similar, but we sign-extend the result. */
112 :
113 : #define get_sleb128_step(var, addr, nth) \
114 : do { \
115 : unsigned char __b = *(addr)++; \
116 : if (likely ((__b & 0x80) == 0)) \
117 : { \
118 : struct { signed int i:7; } __s = { .i = __b }; \
119 : (var) |= (typeof (var)) __s.i * ((typeof (var)) 1 << ((nth) * 7)); \
120 : return (var); \
121 : } \
122 : (var) |= (typeof (var)) (__b & 0x7f) << ((nth) * 7); \
123 : } while (0)
124 :
125 : static inline int64_t
126 423544 : __libdw_get_sleb128 (const unsigned char **addrp, const unsigned char *end)
127 : {
128 423544 : int64_t acc = 0;
129 :
130 : /* Unroll the first step to help the compiler optimize
131 : for the common single-byte case. */
132 423544 : get_sleb128_step (acc, *addrp, 0);
133 :
134 369208 : const size_t max = __libdw_max_len_sleb128 (*addrp - 1, end);
135 196320 : for (size_t i = 1; i < max; ++i)
136 196298 : get_sleb128_step (acc, *addrp, i);
137 : /* Other implementations set VALUE to INT_MAX in this
138 : case. So we better do this as well. */
139 : return INT64_MAX;
140 : }
141 :
142 : static inline int64_t
143 1169 : __libdw_get_sleb128_unchecked (const unsigned char **addrp)
144 : {
145 1169 : int64_t acc = 0;
146 :
147 : /* Unroll the first step to help the compiler optimize
148 : for the common single-byte case. */
149 1169 : get_sleb128_step (acc, *addrp, 0);
150 :
151 : /* Subtract one step, so we don't shift into sign bit. */
152 0 : const size_t max = len_leb128 (int64_t) - 1;
153 0 : for (size_t i = 1; i < max; ++i)
154 0 : get_sleb128_step (acc, *addrp, i);
155 : /* Other implementations set VALUE to INT_MAX in this
156 : case. So we better do this as well. */
157 : return INT64_MAX;
158 : }
159 :
160 : #define get_sleb128(var, addr, end) ((var) = __libdw_get_sleb128 (&(addr), end))
161 : #define get_sleb128_unchecked(var, addr) ((var) = __libdw_get_sleb128_unchecked (&(addr)))
162 :
163 :
164 : /* We use simple memory access functions in case the hardware allows it.
165 : The caller has to make sure we don't have alias problems. */
166 : #if ALLOW_UNALIGNED
167 :
168 : # define read_2ubyte_unaligned(Dbg, Addr) \
169 : (unlikely ((Dbg)->other_byte_order) \
170 : ? bswap_16 (*((const uint16_t *) (Addr))) \
171 : : *((const uint16_t *) (Addr)))
172 : # define read_2sbyte_unaligned(Dbg, Addr) \
173 : (unlikely ((Dbg)->other_byte_order) \
174 : ? (int16_t) bswap_16 (*((const int16_t *) (Addr))) \
175 : : *((const int16_t *) (Addr)))
176 :
177 : # define read_4ubyte_unaligned_noncvt(Addr) \
178 : *((const uint32_t *) (Addr))
179 : # define read_4ubyte_unaligned(Dbg, Addr) \
180 : (unlikely ((Dbg)->other_byte_order) \
181 : ? bswap_32 (*((const uint32_t *) (Addr))) \
182 : : *((const uint32_t *) (Addr)))
183 : # define read_4sbyte_unaligned(Dbg, Addr) \
184 : (unlikely ((Dbg)->other_byte_order) \
185 : ? (int32_t) bswap_32 (*((const int32_t *) (Addr))) \
186 : : *((const int32_t *) (Addr)))
187 :
188 : # define read_8ubyte_unaligned_noncvt(Addr) \
189 : *((const uint64_t *) (Addr))
190 : # define read_8ubyte_unaligned(Dbg, Addr) \
191 : (unlikely ((Dbg)->other_byte_order) \
192 : ? bswap_64 (*((const uint64_t *) (Addr))) \
193 : : *((const uint64_t *) (Addr)))
194 : # define read_8sbyte_unaligned(Dbg, Addr) \
195 : (unlikely ((Dbg)->other_byte_order) \
196 : ? (int64_t) bswap_64 (*((const int64_t *) (Addr))) \
197 : : *((const int64_t *) (Addr)))
198 :
199 : #else
200 :
201 : union unaligned
202 : {
203 : void *p;
204 : uint16_t u2;
205 : uint32_t u4;
206 : uint64_t u8;
207 : int16_t s2;
208 : int32_t s4;
209 : int64_t s8;
210 : } attribute_packed;
211 :
212 : # define read_2ubyte_unaligned(Dbg, Addr) \
213 : read_2ubyte_unaligned_1 ((Dbg)->other_byte_order, (Addr))
214 : # define read_2sbyte_unaligned(Dbg, Addr) \
215 : read_2sbyte_unaligned_1 ((Dbg)->other_byte_order, (Addr))
216 : # define read_4ubyte_unaligned(Dbg, Addr) \
217 : read_4ubyte_unaligned_1 ((Dbg)->other_byte_order, (Addr))
218 : # define read_4sbyte_unaligned(Dbg, Addr) \
219 : read_4sbyte_unaligned_1 ((Dbg)->other_byte_order, (Addr))
220 : # define read_8ubyte_unaligned(Dbg, Addr) \
221 : read_8ubyte_unaligned_1 ((Dbg)->other_byte_order, (Addr))
222 : # define read_8sbyte_unaligned(Dbg, Addr) \
223 : read_8sbyte_unaligned_1 ((Dbg)->other_byte_order, (Addr))
224 :
225 : static inline uint16_t
226 : read_2ubyte_unaligned_1 (bool other_byte_order, const void *p)
227 : {
228 : const union unaligned *up = p;
229 : if (unlikely (other_byte_order))
230 : return bswap_16 (up->u2);
231 : return up->u2;
232 : }
233 : static inline int16_t
234 : read_2sbyte_unaligned_1 (bool other_byte_order, const void *p)
235 : {
236 : const union unaligned *up = p;
237 : if (unlikely (other_byte_order))
238 : return (int16_t) bswap_16 (up->u2);
239 : return up->s2;
240 : }
241 :
242 : static inline uint32_t
243 : read_4ubyte_unaligned_noncvt (const void *p)
244 : {
245 : const union unaligned *up = p;
246 : return up->u4;
247 : }
248 : static inline uint32_t
249 : read_4ubyte_unaligned_1 (bool other_byte_order, const void *p)
250 : {
251 : const union unaligned *up = p;
252 : if (unlikely (other_byte_order))
253 : return bswap_32 (up->u4);
254 : return up->u4;
255 : }
256 : static inline int32_t
257 : read_4sbyte_unaligned_1 (bool other_byte_order, const void *p)
258 : {
259 : const union unaligned *up = p;
260 : if (unlikely (other_byte_order))
261 : return (int32_t) bswap_32 (up->u4);
262 : return up->s4;
263 : }
264 :
265 : static inline uint64_t
266 : read_8ubyte_unaligned_noncvt (const void *p)
267 : {
268 : const union unaligned *up = p;
269 : return up->u8;
270 : }
271 : static inline uint64_t
272 : read_8ubyte_unaligned_1 (bool other_byte_order, const void *p)
273 : {
274 : const union unaligned *up = p;
275 : if (unlikely (other_byte_order))
276 : return bswap_64 (up->u8);
277 : return up->u8;
278 : }
279 : static inline int64_t
280 : read_8sbyte_unaligned_1 (bool other_byte_order, const void *p)
281 : {
282 : const union unaligned *up = p;
283 : if (unlikely (other_byte_order))
284 : return (int64_t) bswap_64 (up->u8);
285 : return up->s8;
286 : }
287 :
288 : #endif /* allow unaligned */
289 :
290 :
291 : #define read_2ubyte_unaligned_inc(Dbg, Addr) \
292 : ({ uint16_t t_ = read_2ubyte_unaligned (Dbg, Addr); \
293 : Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 2); \
294 : t_; })
295 : #define read_2sbyte_unaligned_inc(Dbg, Addr) \
296 : ({ int16_t t_ = read_2sbyte_unaligned (Dbg, Addr); \
297 : Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 2); \
298 : t_; })
299 :
300 : #define read_4ubyte_unaligned_inc(Dbg, Addr) \
301 : ({ uint32_t t_ = read_4ubyte_unaligned (Dbg, Addr); \
302 : Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 4); \
303 : t_; })
304 : #define read_4sbyte_unaligned_inc(Dbg, Addr) \
305 : ({ int32_t t_ = read_4sbyte_unaligned (Dbg, Addr); \
306 : Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 4); \
307 : t_; })
308 :
309 : #define read_8ubyte_unaligned_inc(Dbg, Addr) \
310 : ({ uint64_t t_ = read_8ubyte_unaligned (Dbg, Addr); \
311 : Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 8); \
312 : t_; })
313 : #define read_8sbyte_unaligned_inc(Dbg, Addr) \
314 : ({ int64_t t_ = read_8sbyte_unaligned (Dbg, Addr); \
315 : Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 8); \
316 : t_; })
317 :
318 : /* 3ubyte reads are only used for DW_FORM_addrx3 and DW_FORM_strx3.
319 : And are probably very rare. They are not optimized. They are
320 : handled as if reading a 4byte value with the first (for big endian)
321 : or last (for little endian) byte zero. */
322 :
323 : static inline int
324 : file_byte_order (bool other_byte_order)
325 : {
326 : #if __BYTE_ORDER == __LITTLE_ENDIAN
327 0 : return other_byte_order ? __BIG_ENDIAN : __LITTLE_ENDIAN;
328 : #else
329 : return other_byte_order ? __LITTLE_ENDIAN : __BIG_ENDIAN;
330 : #endif
331 : }
332 :
333 : static inline uint32_t
334 : read_3ubyte_unaligned (Dwarf *dbg, const unsigned char *p)
335 : {
336 : union
337 : {
338 : uint32_t u4;
339 : unsigned char c[4];
340 : } d;
341 0 : bool other_byte_order = dbg->other_byte_order;
342 :
343 0 : if (file_byte_order (other_byte_order) == __BIG_ENDIAN)
344 : {
345 0 : d.c[0] = 0x00;
346 0 : d.c[1] = p[0];
347 0 : d.c[2] = p[1];
348 0 : d.c[3] = p[2];
349 : }
350 : else
351 : {
352 0 : d.c[0] = p[0];
353 0 : d.c[1] = p[1];
354 0 : d.c[2] = p[2];
355 0 : d.c[3] = 0x00;
356 : }
357 :
358 0 : if (other_byte_order)
359 0 : return bswap_32 (d.u4);
360 : else
361 0 : return d.u4;
362 : }
363 :
364 :
365 : #define read_addr_unaligned_inc(Nbytes, Dbg, Addr) \
366 : (assert ((Nbytes) == 4 || (Nbytes) == 8), \
367 : ((Nbytes) == 4 ? read_4ubyte_unaligned_inc (Dbg, Addr) \
368 : : read_8ubyte_unaligned_inc (Dbg, Addr)))
369 :
370 : #endif /* memory-access.h */
|