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