Branch data Line data Source code
1 : : /* Unaligned memory access functionality.
2 : : Copyright (C) 2000-2010 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 [ # # ][ # # ]: 1751 : get_uleb128_rest_return (acc, i, addrp);
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ - + ][ + - ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ + + ][ + - ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ - + ][ + - ]
[ # # ][ # # ]
[ - + ][ + - ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ + + ][ + - ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
114 : : }
115 : : static inline int64_t
116 : : __attribute__ ((unused))
117 : 36920 : __libdw_get_sleb128 (int64_t acc, unsigned int i, const unsigned char **addrp)
118 : : {
119 : : unsigned char __b;
120 : 36920 : int64_t _v = acc;
121 [ + + ][ + + ]: 38858 : 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(Dbg, Addr) \
151 : : (unlikely ((Dbg)->other_byte_order) \
152 : : ? bswap_64 (*((const uint64_t *) (Addr))) \
153 : : : *((const uint64_t *) (Addr)))
154 : : # define read_8sbyte_unaligned(Dbg, Addr) \
155 : : (unlikely ((Dbg)->other_byte_order) \
156 : : ? (int64_t) bswap_64 (*((const int64_t *) (Addr))) \
157 : : : *((const int64_t *) (Addr)))
158 : :
159 : : #else
160 : :
161 : : union unaligned
162 : : {
163 : : void *p;
164 : : uint16_t u2;
165 : : uint32_t u4;
166 : : uint64_t u8;
167 : : int16_t s2;
168 : : int32_t s4;
169 : : int64_t s8;
170 : : } __attribute__ ((packed));
171 : :
172 : : # define read_2ubyte_unaligned(Dbg, Addr) \
173 : : read_2ubyte_unaligned_1 ((Dbg)->other_byte_order, (Addr))
174 : : # define read_2sbyte_unaligned(Dbg, Addr) \
175 : : read_2sbyte_unaligned_1 ((Dbg)->other_byte_order, (Addr))
176 : : # define read_4ubyte_unaligned(Dbg, Addr) \
177 : : read_4ubyte_unaligned_1 ((Dbg)->other_byte_order, (Addr))
178 : : # define read_4sbyte_unaligned(Dbg, Addr) \
179 : : read_4sbyte_unaligned_1 ((Dbg)->other_byte_order, (Addr))
180 : : # define read_8ubyte_unaligned(Dbg, Addr) \
181 : : read_8ubyte_unaligned_1 ((Dbg)->other_byte_order, (Addr))
182 : : # define read_8sbyte_unaligned(Dbg, Addr) \
183 : : read_8sbyte_unaligned_1 ((Dbg)->other_byte_order, (Addr))
184 : :
185 : : static inline uint16_t
186 : : read_2ubyte_unaligned_1 (bool other_byte_order, const void *p)
187 : : {
188 : : const union unaligned *up = p;
189 : : if (unlikely (other_byte_order))
190 : : return bswap_16 (up->u2);
191 : : return up->u2;
192 : : }
193 : : static inline int16_t
194 : : read_2sbyte_unaligned_1 (bool other_byte_order, const void *p)
195 : : {
196 : : const union unaligned *up = p;
197 : : if (unlikely (other_byte_order))
198 : : return (int16_t) bswap_16 (up->u2);
199 : : return up->s2;
200 : : }
201 : :
202 : : static inline uint32_t
203 : : read_4ubyte_unaligned_noncvt (const void *p)
204 : : {
205 : : const union unaligned *up = p;
206 : : return up->u4;
207 : : }
208 : : static inline uint32_t
209 : : read_4ubyte_unaligned_1 (bool other_byte_order, const void *p)
210 : : {
211 : : const union unaligned *up = p;
212 : : if (unlikely (other_byte_order))
213 : : return bswap_32 (up->u4);
214 : : return up->u4;
215 : : }
216 : : static inline int32_t
217 : : read_4sbyte_unaligned_1 (bool other_byte_order, const void *p)
218 : : {
219 : : const union unaligned *up = p;
220 : : if (unlikely (other_byte_order))
221 : : return (int32_t) bswap_32 (up->u4);
222 : : return up->s4;
223 : : }
224 : :
225 : : static inline uint64_t
226 : : read_8ubyte_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_64 (up->u8);
231 : : return up->u8;
232 : : }
233 : : static inline int64_t
234 : : read_8sbyte_unaligned_1 (bool other_byte_order, const void *p)
235 : : {
236 : : const union unaligned *up = p;
237 : : if (unlikely (other_byte_order))
238 : : return (int64_t) bswap_64 (up->u8);
239 : : return up->s8;
240 : : }
241 : :
242 : : #endif /* allow unaligned */
243 : :
244 : :
245 : : #define read_ubyte_unaligned(Nbytes, Dbg, Addr) \
246 : : ((Nbytes) == 2 ? read_2ubyte_unaligned (Dbg, Addr) \
247 : : : (Nbytes) == 4 ? read_4ubyte_unaligned (Dbg, Addr) \
248 : : : read_8ubyte_unaligned (Dbg, Addr))
249 : :
250 : : #define read_sbyte_unaligned(Nbytes, Dbg, Addr) \
251 : : ((Nbytes) == 2 ? read_2sbyte_unaligned (Dbg, Addr) \
252 : : : (Nbytes) == 4 ? read_4sbyte_unaligned (Dbg, Addr) \
253 : : : read_8sbyte_unaligned (Dbg, Addr))
254 : :
255 : :
256 : : #define read_2ubyte_unaligned_inc(Dbg, Addr) \
257 : : ({ uint16_t t_ = read_2ubyte_unaligned (Dbg, Addr); \
258 : : Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 2); \
259 : : t_; })
260 : : #define read_2sbyte_unaligned_inc(Dbg, Addr) \
261 : : ({ int16_t t_ = read_2sbyte_unaligned (Dbg, Addr); \
262 : : Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 2); \
263 : : t_; })
264 : :
265 : : #define read_4ubyte_unaligned_inc(Dbg, Addr) \
266 : : ({ uint32_t t_ = read_4ubyte_unaligned (Dbg, Addr); \
267 : : Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 4); \
268 : : t_; })
269 : : #define read_4sbyte_unaligned_inc(Dbg, Addr) \
270 : : ({ int32_t t_ = read_4sbyte_unaligned (Dbg, Addr); \
271 : : Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 4); \
272 : : t_; })
273 : :
274 : : #define read_8ubyte_unaligned_inc(Dbg, Addr) \
275 : : ({ uint64_t t_ = read_8ubyte_unaligned (Dbg, Addr); \
276 : : Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 8); \
277 : : t_; })
278 : : #define read_8sbyte_unaligned_inc(Dbg, Addr) \
279 : : ({ int64_t t_ = read_8sbyte_unaligned (Dbg, Addr); \
280 : : Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 8); \
281 : : t_; })
282 : :
283 : :
284 : : #define read_ubyte_unaligned_inc(Nbytes, Dbg, Addr) \
285 : : ((Nbytes) == 2 ? read_2ubyte_unaligned_inc (Dbg, Addr) \
286 : : : (Nbytes) == 4 ? read_4ubyte_unaligned_inc (Dbg, Addr) \
287 : : : read_8ubyte_unaligned_inc (Dbg, Addr))
288 : :
289 : : #define read_sbyte_unaligned_inc(Nbytes, Dbg, Addr) \
290 : : ((Nbytes) == 2 ? read_2sbyte_unaligned_inc (Dbg, Addr) \
291 : : : (Nbytes) == 4 ? read_4sbyte_unaligned_inc (Dbg, Addr) \
292 : : : read_8sbyte_unaligned_inc (Dbg, Addr))
293 : :
294 : : #endif /* memory-access.h */
|