Branch data 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 : 988464 : const size_t pointer_len = likely (addr < end) ? end - addr : 0;
47 [ # # ][ + + ]: 494232 : 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 : 196281 : const size_t type_len = len_leb128 (uint64_t);
54 : 392562 : 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 : 297951 : const size_t type_len = len_leb128 (int64_t) - 1;
62 : 595902 : 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 : 55784225 : __libdw_get_uleb128 (const unsigned char **addrp, const unsigned char *end)
75 : : {
76 : 55784225 : uint64_t acc = 0;
77 : :
78 : : /* Unroll the first step to help the compiler optimize
79 : : for the common single-byte case. */
80 [ # # ][ + + ]: 55784225 : get_uleb128_step (acc, *addrp, 0);
81 : :
82 [ # # ][ + - ]: 196281 : const size_t max = __libdw_max_len_uleb128 (*addrp - 1, end);
83 [ # # ][ + - ]: 243042 : for (size_t i = 1; i < max; ++i)
84 [ # # ][ + + ]: 243042 : 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 : 376844878 : __libdw_get_uleb128_unchecked (const unsigned char **addrp)
92 : : {
93 : 376844878 : uint64_t acc = 0;
94 : :
95 : : /* Unroll the first step to help the compiler optimize
96 : : for the common single-byte case. */
97 [ + + ]: 376844878 : get_uleb128_step (acc, *addrp, 0);
98 : :
99 : : const size_t max = len_leb128 (uint64_t);
100 [ # # ][ + - ]: 6128999 : for (size_t i = 1; i < max; ++i)
101 [ # # ][ + - ]: 6128999 : 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 : : (var) |= (typeof (var)) (__b & 0x7f) << ((nth) * 7); \
117 : : if (likely ((__b & 0x80) == 0)) \
118 : : { \
119 : : if ((__b & 0x40) != 0) \
120 : : (var) |= - ((typeof (var)) 1 << (((nth) + 1) * 7)); \
121 : : return (var); \
122 : : } \
123 : : } while (0)
124 : :
125 : : static inline int64_t
126 : 675262 : __libdw_get_sleb128 (const unsigned char **addrp, const unsigned char *end)
127 : : {
128 : : /* Do the work in an unsigned type, but use implementation-defined
129 : : behavior to cast to signed on return. This avoids some undefined
130 : : behavior when shifting. */
131 : 675262 : uint64_t acc = 0;
132 : :
133 : : /* Unroll the first step to help the compiler optimize
134 : : for the common single-byte case. */
135 [ + + ][ + + ]: 675262 : get_sleb128_step (acc, *addrp, 0);
[ # # # # ]
136 : :
137 [ + - ][ # # ]: 297951 : const size_t max = __libdw_max_len_sleb128 (*addrp - 1, end);
138 [ + + ][ # # ]: 306338 : for (size_t i = 1; i < max; ++i)
139 [ + + ][ + + ]: 306320 : get_sleb128_step (acc, *addrp, i);
[ # # # # ]
140 [ # # ][ + - ]: 18 : if (*addrp == end)
141 : : return INT64_MAX;
142 : :
143 : : /* There might be one extra byte. */
144 : 18 : unsigned char b = **addrp;
145 : 18 : ++*addrp;
146 [ # # ][ + - ]: 18 : if (likely ((b & 0x80) == 0))
147 : : {
148 : : /* We only need the low bit of the final byte, and as it is the
149 : : sign bit, we don't need to do anything else here. */
150 : 18 : acc |= ((typeof (acc)) b) << 7 * max;
151 : 18 : return acc;
152 : : }
153 : :
154 : : /* Other implementations set VALUE to INT_MAX in this
155 : : case. So we better do this as well. */
156 : : return INT64_MAX;
157 : : }
158 : :
159 : : static inline int64_t
160 : 1200 : __libdw_get_sleb128_unchecked (const unsigned char **addrp)
161 : : {
162 : : /* Do the work in an unsigned type, but use implementation-defined
163 : : behavior to cast to signed on return. This avoids some undefined
164 : : behavior when shifting. */
165 : 1200 : uint64_t acc = 0;
166 : :
167 : : /* Unroll the first step to help the compiler optimize
168 : : for the common single-byte case. */
169 [ + - ][ + + ]: 1200 : get_sleb128_step (acc, *addrp, 0);
[ # # # # ]
170 : :
171 : : /* Subtract one step, so we don't shift into sign bit. */
172 : : const size_t max = len_leb128 (int64_t) - 1;
173 [ # # ]: 0 : for (size_t i = 1; i < max; ++i)
174 [ # # # # ]: 0 : get_sleb128_step (acc, *addrp, i);
175 : :
176 : : /* There might be one extra byte. */
177 : 0 : unsigned char b = **addrp;
178 : 0 : ++*addrp;
179 [ # # ]: 0 : if (likely ((b & 0x80) == 0))
180 : : {
181 : : /* We only need the low bit of the final byte, and as it is the
182 : : sign bit, we don't need to do anything else here. */
183 : 0 : acc |= ((typeof (acc)) b) << 7 * max;
184 : 0 : return acc;
185 : : }
186 : :
187 : : /* Other implementations set VALUE to INT_MAX in this
188 : : case. So we better do this as well. */
189 : : return INT64_MAX;
190 : : }
191 : :
192 : : #define get_sleb128(var, addr, end) ((var) = __libdw_get_sleb128 (&(addr), end))
193 : : #define get_sleb128_unchecked(var, addr) ((var) = __libdw_get_sleb128_unchecked (&(addr)))
194 : :
195 : :
196 : : /* We use simple memory access functions in case the hardware allows it.
197 : : The caller has to make sure we don't have alias problems. */
198 : : #if ALLOW_UNALIGNED
199 : :
200 : : # define read_2ubyte_unaligned(Dbg, Addr) \
201 : : (unlikely ((Dbg)->other_byte_order) \
202 : : ? bswap_16 (*((const uint16_t *) (Addr))) \
203 : : : *((const uint16_t *) (Addr)))
204 : : # define read_2sbyte_unaligned(Dbg, Addr) \
205 : : (unlikely ((Dbg)->other_byte_order) \
206 : : ? (int16_t) bswap_16 (*((const int16_t *) (Addr))) \
207 : : : *((const int16_t *) (Addr)))
208 : :
209 : : # define read_4ubyte_unaligned_noncvt(Addr) \
210 : : *((const uint32_t *) (Addr))
211 : : # define read_4ubyte_unaligned(Dbg, Addr) \
212 : : (unlikely ((Dbg)->other_byte_order) \
213 : : ? bswap_32 (*((const uint32_t *) (Addr))) \
214 : : : *((const uint32_t *) (Addr)))
215 : : # define read_4sbyte_unaligned(Dbg, Addr) \
216 : : (unlikely ((Dbg)->other_byte_order) \
217 : : ? (int32_t) bswap_32 (*((const int32_t *) (Addr))) \
218 : : : *((const int32_t *) (Addr)))
219 : :
220 : : # define read_8ubyte_unaligned_noncvt(Addr) \
221 : : *((const uint64_t *) (Addr))
222 : : # define read_8ubyte_unaligned(Dbg, Addr) \
223 : : (unlikely ((Dbg)->other_byte_order) \
224 : : ? bswap_64 (*((const uint64_t *) (Addr))) \
225 : : : *((const uint64_t *) (Addr)))
226 : : # define read_8sbyte_unaligned(Dbg, Addr) \
227 : : (unlikely ((Dbg)->other_byte_order) \
228 : : ? (int64_t) bswap_64 (*((const int64_t *) (Addr))) \
229 : : : *((const int64_t *) (Addr)))
230 : :
231 : : #else
232 : :
233 : : union unaligned
234 : : {
235 : : void *p;
236 : : uint16_t u2;
237 : : uint32_t u4;
238 : : uint64_t u8;
239 : : int16_t s2;
240 : : int32_t s4;
241 : : int64_t s8;
242 : : } attribute_packed;
243 : :
244 : : # define read_2ubyte_unaligned(Dbg, Addr) \
245 : : read_2ubyte_unaligned_1 ((Dbg)->other_byte_order, (Addr))
246 : : # define read_2sbyte_unaligned(Dbg, Addr) \
247 : : read_2sbyte_unaligned_1 ((Dbg)->other_byte_order, (Addr))
248 : : # define read_4ubyte_unaligned(Dbg, Addr) \
249 : : read_4ubyte_unaligned_1 ((Dbg)->other_byte_order, (Addr))
250 : : # define read_4sbyte_unaligned(Dbg, Addr) \
251 : : read_4sbyte_unaligned_1 ((Dbg)->other_byte_order, (Addr))
252 : : # define read_8ubyte_unaligned(Dbg, Addr) \
253 : : read_8ubyte_unaligned_1 ((Dbg)->other_byte_order, (Addr))
254 : : # define read_8sbyte_unaligned(Dbg, Addr) \
255 : : read_8sbyte_unaligned_1 ((Dbg)->other_byte_order, (Addr))
256 : :
257 : : static inline uint16_t
258 : : read_2ubyte_unaligned_1 (bool other_byte_order, const void *p)
259 : : {
260 : : const union unaligned *up = p;
261 : : if (unlikely (other_byte_order))
262 : : return bswap_16 (up->u2);
263 : : return up->u2;
264 : : }
265 : : static inline int16_t
266 : : read_2sbyte_unaligned_1 (bool other_byte_order, const void *p)
267 : : {
268 : : const union unaligned *up = p;
269 : : if (unlikely (other_byte_order))
270 : : return (int16_t) bswap_16 (up->u2);
271 : : return up->s2;
272 : : }
273 : :
274 : : static inline uint32_t
275 : : read_4ubyte_unaligned_noncvt (const void *p)
276 : : {
277 : : const union unaligned *up = p;
278 : : return up->u4;
279 : : }
280 : : static inline uint32_t
281 : : read_4ubyte_unaligned_1 (bool other_byte_order, const void *p)
282 : : {
283 : : const union unaligned *up = p;
284 : : if (unlikely (other_byte_order))
285 : : return bswap_32 (up->u4);
286 : : return up->u4;
287 : : }
288 : : static inline int32_t
289 : : read_4sbyte_unaligned_1 (bool other_byte_order, const void *p)
290 : : {
291 : : const union unaligned *up = p;
292 : : if (unlikely (other_byte_order))
293 : : return (int32_t) bswap_32 (up->u4);
294 : : return up->s4;
295 : : }
296 : :
297 : : static inline uint64_t
298 : : read_8ubyte_unaligned_noncvt (const void *p)
299 : : {
300 : : const union unaligned *up = p;
301 : : return up->u8;
302 : : }
303 : : static inline uint64_t
304 : : read_8ubyte_unaligned_1 (bool other_byte_order, const void *p)
305 : : {
306 : : const union unaligned *up = p;
307 : : if (unlikely (other_byte_order))
308 : : return bswap_64 (up->u8);
309 : : return up->u8;
310 : : }
311 : : static inline int64_t
312 : : read_8sbyte_unaligned_1 (bool other_byte_order, const void *p)
313 : : {
314 : : const union unaligned *up = p;
315 : : if (unlikely (other_byte_order))
316 : : return (int64_t) bswap_64 (up->u8);
317 : : return up->s8;
318 : : }
319 : :
320 : : #endif /* allow unaligned */
321 : :
322 : :
323 : : #define read_2ubyte_unaligned_inc(Dbg, Addr) \
324 : : ({ uint16_t t_ = read_2ubyte_unaligned (Dbg, Addr); \
325 : : Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 2); \
326 : : t_; })
327 : : #define read_2sbyte_unaligned_inc(Dbg, Addr) \
328 : : ({ int16_t t_ = read_2sbyte_unaligned (Dbg, Addr); \
329 : : Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 2); \
330 : : t_; })
331 : :
332 : : #define read_4ubyte_unaligned_inc(Dbg, Addr) \
333 : : ({ uint32_t t_ = read_4ubyte_unaligned (Dbg, Addr); \
334 : : Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 4); \
335 : : t_; })
336 : : #define read_4sbyte_unaligned_inc(Dbg, Addr) \
337 : : ({ int32_t t_ = read_4sbyte_unaligned (Dbg, Addr); \
338 : : Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 4); \
339 : : t_; })
340 : :
341 : : #define read_8ubyte_unaligned_inc(Dbg, Addr) \
342 : : ({ uint64_t t_ = read_8ubyte_unaligned (Dbg, Addr); \
343 : : Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 8); \
344 : : t_; })
345 : : #define read_8sbyte_unaligned_inc(Dbg, Addr) \
346 : : ({ int64_t t_ = read_8sbyte_unaligned (Dbg, Addr); \
347 : : Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 8); \
348 : : t_; })
349 : :
350 : : /* 3ubyte reads are only used for DW_FORM_addrx3 and DW_FORM_strx3.
351 : : And are probably very rare. They are not optimized. They are
352 : : handled as if reading a 4byte value with the first (for big endian)
353 : : or last (for little endian) byte zero. */
354 : :
355 : : static inline int
356 : : file_byte_order (bool other_byte_order)
357 : : {
358 : : #if __BYTE_ORDER == __LITTLE_ENDIAN
359 : 0 : return other_byte_order ? __BIG_ENDIAN : __LITTLE_ENDIAN;
360 : : #else
361 : : return other_byte_order ? __LITTLE_ENDIAN : __BIG_ENDIAN;
362 : : #endif
363 : : }
364 : :
365 : : static inline uint32_t
366 : 0 : read_3ubyte_unaligned (Dwarf *dbg, const unsigned char *p)
367 : : {
368 : 0 : union
369 : : {
370 : : uint32_t u4;
371 : : unsigned char c[4];
372 : : } d;
373 : 0 : bool other_byte_order = dbg->other_byte_order;
374 : :
375 [ # # # # ]: 0 : if (file_byte_order (other_byte_order) == __BIG_ENDIAN)
376 : : {
377 : 0 : d.c[0] = 0x00;
378 : 0 : d.c[1] = p[0];
379 : 0 : d.c[2] = p[1];
380 : 0 : d.c[3] = p[2];
381 : : }
382 : : else
383 : : {
384 : 0 : d.c[0] = p[0];
385 : 0 : d.c[1] = p[1];
386 : 0 : d.c[2] = p[2];
387 : 0 : d.c[3] = 0x00;
388 : : }
389 : :
390 [ # # # # ]: 0 : if (other_byte_order)
391 : 0 : return bswap_32 (d.u4);
392 : : else
393 : 0 : return d.u4;
394 : : }
395 : :
396 : :
397 : : #define read_3ubyte_unaligned_inc(Dbg, Addr) \
398 : : ({ uint32_t t_ = read_3ubyte_unaligned (Dbg, Addr); \
399 : : Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 3); \
400 : : t_; })
401 : :
402 : : #define read_addr_unaligned_inc(Nbytes, Dbg, Addr) \
403 : : (assert ((Nbytes) == 4 || (Nbytes) == 8), \
404 : : ((Nbytes) == 4 ? read_4ubyte_unaligned_inc (Dbg, Addr) \
405 : : : read_8ubyte_unaligned_inc (Dbg, Addr)))
406 : :
407 : : #endif /* memory-access.h */
|