Branch data Line data Source code
1 : : /* Unaligned memory access functionality.
2 : : Copyright (C) 2000-2013 Red Hat, Inc.
3 : : This file is part of elfutils.
4 : : Written by Ulrich Drepper <drepper@redhat.com>, 2001.
5 : :
6 : : This file is free software; you can redistribute it and/or modify
7 : : it under the terms of either
8 : :
9 : : * the GNU Lesser General Public License as published by the Free
10 : : Software Foundation; either version 3 of the License, or (at
11 : : your option) any later version
12 : :
13 : : or
14 : :
15 : : * the GNU General Public License as published by the Free
16 : : Software Foundation; either version 2 of the License, or (at
17 : : your option) any later version
18 : :
19 : : or both in parallel, as here.
20 : :
21 : : elfutils is distributed in the hope that it will be useful, but
22 : : WITHOUT ANY WARRANTY; without even the implied warranty of
23 : : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24 : : General Public License for more details.
25 : :
26 : : You should have received copies of the GNU General Public License and
27 : : the GNU Lesser General Public License along with this program. If
28 : : not, see <http://www.gnu.org/licenses/>. */
29 : :
30 : : #ifndef _MEMORY_ACCESS_H
31 : : #define _MEMORY_ACCESS_H 1
32 : :
33 : : #include <byteswap.h>
34 : : #include <limits.h>
35 : : #include <stdint.h>
36 : :
37 : :
38 : : /* Number decoding macros. See 7.6 Variable Length Data. */
39 : :
40 : : #define get_uleb128_step(var, addr, nth, break) \
41 : : __b = *(addr)++; \
42 : : var |= (uintmax_t) (__b & 0x7f) << (nth * 7); \
43 : : if (likely ((__b & 0x80) == 0)) \
44 : : break
45 : :
46 : : #define get_uleb128(var, addr) \
47 : : do { \
48 : : unsigned char __b; \
49 : : var = 0; \
50 : : get_uleb128_step (var, addr, 0, break); \
51 : : var = __libdw_get_uleb128 (var, 1, &(addr)); \
52 : : } while (0)
53 : :
54 : : #define get_uleb128_rest_return(var, i, addrp) \
55 : : do { \
56 : : for (; i < 10; ++i) \
57 : : { \
58 : : get_uleb128_step (var, *addrp, i, return var); \
59 : : } \
60 : : /* Other implementations set VALUE to UINT_MAX in this \
61 : : case. So we better do this as well. */ \
62 : : return UINT64_MAX; \
63 : : } while (0)
64 : :
65 : : /* The signed case is similar, but we sign-extend the result. */
66 : :
67 : : #define get_sleb128_step(var, addr, nth, break) \
68 : : __b = *(addr)++; \
69 : : _v |= (uint64_t) (__b & 0x7f) << (nth * 7); \
70 : : if (likely ((__b & 0x80) == 0)) \
71 : : { \
72 : : var = (_v << (64 - (nth * 7) - 7)) >> (64 - (nth * 7) - 7); \
73 : : break; \
74 : : } \
75 : : else do {} while (0)
76 : :
77 : : #define get_sleb128(var, addr) \
78 : : do { \
79 : : unsigned char __b; \
80 : : int64_t _v = 0; \
81 : : get_sleb128_step (var, addr, 0, break); \
82 : : var = __libdw_get_sleb128 (_v, 1, &(addr)); \
83 : : } while (0)
84 : :
85 : : #define get_sleb128_rest_return(var, i, addrp) \
86 : : do { \
87 : : for (; i < 9; ++i) \
88 : : { \
89 : : get_sleb128_step (var, *addrp, i, return var); \
90 : : } \
91 : : __b = *(*addrp)++; \
92 : : if (likely ((__b & 0x80) == 0)) \
93 : : return var | ((uint64_t) __b << 63); \
94 : : else \
95 : : /* Other implementations set VALUE to INT_MAX in this \
96 : : case. So we better do this as well. */ \
97 : : return INT64_MAX; \
98 : : } while (0)
99 : :
100 : : #ifdef IS_LIBDW
101 : : extern uint64_t __libdw_get_uleb128 (uint64_t acc, unsigned int i,
102 : : const unsigned char **addrp)
103 : : internal_function attribute_hidden;
104 : : extern int64_t __libdw_get_sleb128 (int64_t acc, unsigned int i,
105 : : const unsigned char **addrp)
106 : : internal_function attribute_hidden;
107 : : #else
108 : : static inline uint64_t
109 : : __attribute__ ((unused))
110 : : __libdw_get_uleb128 (uint64_t acc, unsigned int i, const unsigned char **addrp)
111 : : {
112 : : unsigned char __b;
113 [ # # ][ # # ]: 1927 : get_uleb128_rest_return (acc, i, addrp);
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ - + ][ + - ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ + + ][ + - ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ - + ][ + - ]
[ # # ][ # # ]
[ - + ][ + - ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ + + ][ + - ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
114 : : }
115 : : static inline int64_t
116 : : __attribute__ ((unused))
117 : 42084 : __libdw_get_sleb128 (int64_t acc, unsigned int i, const unsigned char **addrp)
118 : : {
119 : : unsigned char __b;
120 : 42084 : int64_t _v = acc;
121 [ + + ][ + + ]: 44067 : get_sleb128_rest_return (acc, i, addrp);
[ + - ]
122 : : }
123 : : #endif
124 : :
125 : :
126 : : /* We use simple memory access functions in case the hardware allows it.
127 : : The caller has to make sure we don't have alias problems. */
128 : : #if ALLOW_UNALIGNED
129 : :
130 : : # define read_2ubyte_unaligned(Dbg, Addr) \
131 : : (unlikely ((Dbg)->other_byte_order) \
132 : : ? bswap_16 (*((const uint16_t *) (Addr))) \
133 : : : *((const uint16_t *) (Addr)))
134 : : # define read_2sbyte_unaligned(Dbg, Addr) \
135 : : (unlikely ((Dbg)->other_byte_order) \
136 : : ? (int16_t) bswap_16 (*((const int16_t *) (Addr))) \
137 : : : *((const int16_t *) (Addr)))
138 : :
139 : : # define read_4ubyte_unaligned_noncvt(Addr) \
140 : : *((const uint32_t *) (Addr))
141 : : # define read_4ubyte_unaligned(Dbg, Addr) \
142 : : (unlikely ((Dbg)->other_byte_order) \
143 : : ? bswap_32 (*((const uint32_t *) (Addr))) \
144 : : : *((const uint32_t *) (Addr)))
145 : : # define read_4sbyte_unaligned(Dbg, Addr) \
146 : : (unlikely ((Dbg)->other_byte_order) \
147 : : ? (int32_t) bswap_32 (*((const int32_t *) (Addr))) \
148 : : : *((const int32_t *) (Addr)))
149 : :
150 : : # define read_8ubyte_unaligned_noncvt(Addr) \
151 : : *((const uint64_t *) (Addr))
152 : : # define read_8ubyte_unaligned(Dbg, Addr) \
153 : : (unlikely ((Dbg)->other_byte_order) \
154 : : ? bswap_64 (*((const uint64_t *) (Addr))) \
155 : : : *((const uint64_t *) (Addr)))
156 : : # define read_8sbyte_unaligned(Dbg, Addr) \
157 : : (unlikely ((Dbg)->other_byte_order) \
158 : : ? (int64_t) bswap_64 (*((const int64_t *) (Addr))) \
159 : : : *((const int64_t *) (Addr)))
160 : :
161 : : #else
162 : :
163 : : union unaligned
164 : : {
165 : : void *p;
166 : : uint16_t u2;
167 : : uint32_t u4;
168 : : uint64_t u8;
169 : : int16_t s2;
170 : : int32_t s4;
171 : : int64_t s8;
172 : : } __attribute__ ((packed));
173 : :
174 : : # define read_2ubyte_unaligned(Dbg, Addr) \
175 : : read_2ubyte_unaligned_1 ((Dbg)->other_byte_order, (Addr))
176 : : # define read_2sbyte_unaligned(Dbg, Addr) \
177 : : read_2sbyte_unaligned_1 ((Dbg)->other_byte_order, (Addr))
178 : : # define read_4ubyte_unaligned(Dbg, Addr) \
179 : : read_4ubyte_unaligned_1 ((Dbg)->other_byte_order, (Addr))
180 : : # define read_4sbyte_unaligned(Dbg, Addr) \
181 : : read_4sbyte_unaligned_1 ((Dbg)->other_byte_order, (Addr))
182 : : # define read_8ubyte_unaligned(Dbg, Addr) \
183 : : read_8ubyte_unaligned_1 ((Dbg)->other_byte_order, (Addr))
184 : : # define read_8sbyte_unaligned(Dbg, Addr) \
185 : : read_8sbyte_unaligned_1 ((Dbg)->other_byte_order, (Addr))
186 : :
187 : : static inline uint16_t
188 : : read_2ubyte_unaligned_1 (bool other_byte_order, const void *p)
189 : : {
190 : : const union unaligned *up = p;
191 : : if (unlikely (other_byte_order))
192 : : return bswap_16 (up->u2);
193 : : return up->u2;
194 : : }
195 : : static inline int16_t
196 : : read_2sbyte_unaligned_1 (bool other_byte_order, const void *p)
197 : : {
198 : : const union unaligned *up = p;
199 : : if (unlikely (other_byte_order))
200 : : return (int16_t) bswap_16 (up->u2);
201 : : return up->s2;
202 : : }
203 : :
204 : : static inline uint32_t
205 : : read_4ubyte_unaligned_noncvt (const void *p)
206 : : {
207 : : const union unaligned *up = p;
208 : : return up->u4;
209 : : }
210 : : static inline uint32_t
211 : : read_4ubyte_unaligned_1 (bool other_byte_order, const void *p)
212 : : {
213 : : const union unaligned *up = p;
214 : : if (unlikely (other_byte_order))
215 : : return bswap_32 (up->u4);
216 : : return up->u4;
217 : : }
218 : : static inline int32_t
219 : : read_4sbyte_unaligned_1 (bool other_byte_order, const void *p)
220 : : {
221 : : const union unaligned *up = p;
222 : : if (unlikely (other_byte_order))
223 : : return (int32_t) bswap_32 (up->u4);
224 : : return up->s4;
225 : : }
226 : :
227 : : static inline uint64_t
228 : : read_8ubyte_unaligned_noncvt (const void *p)
229 : : {
230 : : const union unaligned *up = p;
231 : : return up->u8;
232 : : }
233 : : static inline uint64_t
234 : : read_8ubyte_unaligned_1 (bool other_byte_order, const void *p)
235 : : {
236 : : const union unaligned *up = p;
237 : : if (unlikely (other_byte_order))
238 : : return bswap_64 (up->u8);
239 : : return up->u8;
240 : : }
241 : : static inline int64_t
242 : : read_8sbyte_unaligned_1 (bool other_byte_order, const void *p)
243 : : {
244 : : const union unaligned *up = p;
245 : : if (unlikely (other_byte_order))
246 : : return (int64_t) bswap_64 (up->u8);
247 : : return up->s8;
248 : : }
249 : :
250 : : #endif /* allow unaligned */
251 : :
252 : :
253 : : #define read_ubyte_unaligned(Nbytes, Dbg, Addr) \
254 : : ((Nbytes) == 2 ? read_2ubyte_unaligned (Dbg, Addr) \
255 : : : (Nbytes) == 4 ? read_4ubyte_unaligned (Dbg, Addr) \
256 : : : read_8ubyte_unaligned (Dbg, Addr))
257 : :
258 : : #define read_sbyte_unaligned(Nbytes, Dbg, Addr) \
259 : : ((Nbytes) == 2 ? read_2sbyte_unaligned (Dbg, Addr) \
260 : : : (Nbytes) == 4 ? read_4sbyte_unaligned (Dbg, Addr) \
261 : : : read_8sbyte_unaligned (Dbg, Addr))
262 : :
263 : :
264 : : #define read_2ubyte_unaligned_inc(Dbg, Addr) \
265 : : ({ uint16_t t_ = read_2ubyte_unaligned (Dbg, Addr); \
266 : : Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 2); \
267 : : t_; })
268 : : #define read_2sbyte_unaligned_inc(Dbg, Addr) \
269 : : ({ int16_t t_ = read_2sbyte_unaligned (Dbg, Addr); \
270 : : Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 2); \
271 : : t_; })
272 : :
273 : : #define read_4ubyte_unaligned_inc(Dbg, Addr) \
274 : : ({ uint32_t t_ = read_4ubyte_unaligned (Dbg, Addr); \
275 : : Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 4); \
276 : : t_; })
277 : : #define read_4sbyte_unaligned_inc(Dbg, Addr) \
278 : : ({ int32_t t_ = read_4sbyte_unaligned (Dbg, Addr); \
279 : : Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 4); \
280 : : t_; })
281 : :
282 : : #define read_8ubyte_unaligned_inc(Dbg, Addr) \
283 : : ({ uint64_t t_ = read_8ubyte_unaligned (Dbg, Addr); \
284 : : Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 8); \
285 : : t_; })
286 : : #define read_8sbyte_unaligned_inc(Dbg, Addr) \
287 : : ({ int64_t t_ = read_8sbyte_unaligned (Dbg, Addr); \
288 : : Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 8); \
289 : : t_; })
290 : :
291 : :
292 : : #define read_ubyte_unaligned_inc(Nbytes, Dbg, Addr) \
293 : : ((Nbytes) == 2 ? read_2ubyte_unaligned_inc (Dbg, Addr) \
294 : : : (Nbytes) == 4 ? read_4ubyte_unaligned_inc (Dbg, Addr) \
295 : : : read_8ubyte_unaligned_inc (Dbg, Addr))
296 : :
297 : : #define read_sbyte_unaligned_inc(Nbytes, Dbg, Addr) \
298 : : ((Nbytes) == 2 ? read_2sbyte_unaligned_inc (Dbg, Addr) \
299 : : : (Nbytes) == 4 ? read_4sbyte_unaligned_inc (Dbg, Addr) \
300 : : : read_8sbyte_unaligned_inc (Dbg, Addr))
301 : :
302 : : #endif /* memory-access.h */
|