1 /* Unaligned memory access functionality.
2 Copyright (C) 2000, 2001, 2002, 2003, 2004 Red Hat, Inc.
3 Written by Ulrich Drepper <drepper@redhat.com>, 2001.
4
5 This program is Open Source software; you can redistribute it and/or
6 modify it under the terms of the Open Software License version 1.0 as
7 published by the Open Source Initiative.
8
9 You should have received a copy of the Open Software License along
10 with this program; if not, you may obtain a copy of the Open Software
11 License version 1.0 from http://www.opensource.org/licenses/osl.php or
12 by writing the Open Source Initiative c/o Lawrence Rosen, Esq.,
13 3001 King Ranch Road, Ukiah, CA 95482. */
14
15 #ifndef _MEMORY_ACCESS_H
16 #define _MEMORY_ACCESS_H 1
17
18 #include <byteswap.h>
19 #include <limits.h>
20 #include <stdint.h>
21
22
23 /* Number decoding macros. See 7.6 Variable Length Data. */
24 #define get_uleb128(var, addr) \
25 do { \
26 unsigned char __b = *((const unsigned char *) addr); \
27 addr = (__typeof (addr)) (((uintptr_t) (addr)) + 1); \
28 var = __b & 0x7f; \
29 if (__b & 0x80) \
30 { \
31 __b = *((const unsigned char *) addr); \
32 addr = (__typeof (addr)) (((uintptr_t) (addr)) + 1); \
33 var |= (__b & 0x7f) << 7; \
34 if (__b & 0x80) \
35 { \
36 __b = *((const unsigned char *) addr); \
37 addr = (__typeof (addr)) (((uintptr_t) (addr)) + 1); \
38 var |= (__b & 0x7f) << 14; \
39 if (__b & 0x80) \
40 { \
41 __b = *((const unsigned char *) addr); \
42 addr = (__typeof (addr)) (((uintptr_t) (addr)) + 1); \
43 var |= (__b & 0x7f) << 21; \
44 if (__b & 0x80) \
45 /* Other implementation set VALUE to UINT_MAX in this \
46 case. So we better do this as well. */ \
47 var = UINT_MAX; \
48 } \
49 } \
50 } \
51 } while (0)
52
53 /* The signed case is a big more complicated. */
54 #define get_sleb128(var, addr) \
55 do { \
56 unsigned char __b = *((const unsigned char *) addr); \
57 addr = (__typeof (addr)) (((uintptr_t) (addr)) + 1); \
58 int32_t __res = __b & 0x7f; \
59 if ((__b & 0x80) == 0) \
60 { \
61 if (__b & 0x40) \
62 __res |= 0xffffff80; \
63 } \
64 else \
65 { \
66 __b = *((const unsigned char *) addr); \
67 addr = (__typeof (addr)) (((uintptr_t) (addr)) + 1); \
68 __res |= (__b & 0x7f) << 7; \
69 if ((__b & 0x80) == 0) \
70 { \
71 if (__b & 0x40) \
72 __res |= 0xffffc000; \
73 } \
74 else \
75 { \
76 __b = *((const unsigned char *) addr); \
77 addr = (__typeof (addr)) (((uintptr_t) (addr)) + 1); \
78 __res |= (__b & 0x7f) << 14; \
79 if ((__b & 0x80) == 0) \
80 { \
81 if (__b & 0x40) \
82 __res |= 0xffe00000; \
83 } \
84 else \
85 { \
86 __b = *((const unsigned char *) addr); \
87 addr = (__typeof (addr)) (((uintptr_t) (addr)) + 1); \
88 __res |= (__b & 0x7f) << 21; \
89 if ((__b & 0x80) == 0) \
90 { \
91 if (__b & 0x40) \
92 __res |= 0xf0000000; \
93 } \
94 else \
95 /* Other implementation set VALUE to INT_MAX in this \
96 case. So we better do this as well. */ \
97 __res = INT_MAX; \
98 } \
99 } \
100 } \
101 var = __res; \
102 } while (0)
103
104
105 /* We use simple memory access functions in case the hardware allows it.
106 The caller has to make sure we don't have alias problems. */
107 #if ALLOW_UNALIGNED
108
109 # define read_2ubyte_unaligned(Dbg, Addr) \
110 (unlikely ((Dbg)->other_byte_order) \
111 ? bswap_16 (*((const uint16_t *) (Addr))) \
112 : *((const uint16_t *) (Addr)))
113 # define read_2sbyte_unaligned(Dbg, Addr) \
114 (unlikely ((Dbg)->other_byte_order) \
115 ? (int16_t) bswap_16 (*((const int16_t *) (Addr))) \
116 : *((const int16_t *) (Addr)))
117
118 # define read_4ubyte_unaligned_noncvt(Addr) \
119 *((const uint32_t *) (Addr))
120 # define read_4ubyte_unaligned(Dbg, Addr) \
121 (unlikely ((Dbg)->other_byte_order) \
122 ? bswap_32 (*((const uint32_t *) (Addr))) \
123 : *((const uint32_t *) (Addr)))
124 # define read_4sbyte_unaligned(Dbg, Addr) \
125 (unlikely ((Dbg)->other_byte_order) \
126 ? (int32_t) bswap_32 (*((const int32_t *) (Addr))) \
127 : *((const int32_t *) (Addr)))
128
129 # define read_8ubyte_unaligned(Dbg, Addr) \
130 (unlikely ((Dbg)->other_byte_order) \
131 ? bswap_64 (*((const uint64_t *) (Addr))) \
132 : *((const uint64_t *) (Addr)))
133 # define read_8sbyte_unaligned(Dbg, Addr) \
134 (unlikely ((Dbg)->other_byte_order) \
135 ? (int64_t) bswap_64 (*((const int64_t *) (Addr))) \
136 : *((const int64_t *) (Addr)))
137
138 #else
139
140 union unaligned
141 {
142 void *p;
143 uint16_t u2;
144 uint32_t u4;
145 uint64_t u8;
146 int16_t s2;
147 int32_t s4;
148 int64_t s8;
149 } __attribute__ ((packed));
150
151 static inline uint16_t
read_2ubyte_unaligned(Dwarf * dbg,const void * p)152 read_2ubyte_unaligned (Dwarf *dbg, const void *p)
153 {
154 const union unaligned *up = p;
155 if (dbg->other_byte_order)
156 return bswap_16 (up->u2);
157 return up->u2;
158 }
159 static inline int16_t
read_2sbyte_unaligned(Dwarf * dbg,const void * p)160 read_2sbyte_unaligned (Dwarf *dbg, const void *p)
161 {
162 const union unaligned *up = p;
163 if (dbg->other_byte_order)
164 return (int16_t) bswap_16 (up->u2);
165 return up->s2;
166 }
167
168 static inline uint32_t
read_4ubyte_unaligned_noncvt(const void * p)169 read_4ubyte_unaligned_noncvt (const void *p)
170 {
171 const union unaligned *up = p;
172 return up->u4;
173 }
174 static inline uint32_t
read_4ubyte_unaligned(Dwarf * dbg,const void * p)175 read_4ubyte_unaligned (Dwarf *dbg, const void *p)
176 {
177 const union unaligned *up = p;
178 if (dbg->other_byte_order)
179 return bswap_32 (up->u4);
180 return up->u4;
181 }
182 static inline int32_t
read_4sbyte_unaligned(Dwarf * dbg,const void * p)183 read_4sbyte_unaligned (Dwarf *dbg, const void *p)
184 {
185 const union unaligned *up = p;
186 if (dbg->other_byte_order)
187 return (int32_t) bswap_32 (up->u4);
188 return up->s4;
189 }
190
191 static inline uint64_t
read_8ubyte_unaligned(Dwarf * dbg,const void * p)192 read_8ubyte_unaligned (Dwarf *dbg, const void *p)
193 {
194 const union unaligned *up = p;
195 if (dbg->other_byte_order)
196 return bswap_64 (up->u8);
197 return up->u8;
198 }
199 static inline int64_t
read_8sbyte_unaligned(Dwarf * dbg,const void * p)200 read_8sbyte_unaligned (Dwarf *dbg, const void *p)
201 {
202 const union unaligned *up = p;
203 if (dbg->other_byte_order)
204 return (int64_t) bswap_64 (up->u8);
205 return up->s8;
206 }
207
208 #endif /* allow unaligned */
209
210
211 #define read_2ubyte_unaligned_inc(Dbg, Addr) \
212 ({ uint16_t t_ = read_2ubyte_unaligned (Dbg, Addr); \
213 Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 2); \
214 t_; })
215 #define read_2sbyte_unaligned_inc(Dbg, Addr) \
216 ({ int16_t t_ = read_2sbyte_unaligned (Dbg, Addr); \
217 Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 2); \
218 t_; })
219
220 #define read_4ubyte_unaligned_inc(Dbg, Addr) \
221 ({ uint32_t t_ = read_4ubyte_unaligned (Dbg, Addr); \
222 Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 4); \
223 t_; })
224 #define read_4sbyte_unaligned_inc(Dbg, Addr) \
225 ({ int32_t t_ = read_4sbyte_unaligned (Dbg, Addr); \
226 Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 4); \
227 t_; })
228
229 #define read_8ubyte_unaligned_inc(Dbg, Addr) \
230 ({ uint64_t t_ = read_8ubyte_unaligned (Dbg, Addr); \
231 Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 8); \
232 t_; })
233 #define read_8sbyte_unaligned_inc(Dbg, Addr) \
234 ({ int64_t t_ = read_8sbyte_unaligned (Dbg, Addr); \
235 Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 8); \
236 t_; })
237
238 #endif /* memory-access.h */
239