Imported Upstream version 0.155
[platform/upstream/elfutils.git] / libdw / memory-access.h
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   get_uleb128_rest_return (acc, i, addrp);
114 }
115 static inline int64_t
116 __attribute__ ((unused))
117 __libdw_get_sleb128 (int64_t acc, unsigned int i, const unsigned char **addrp)
118 {
119   unsigned char __b;
120   int64_t _v = acc;
121   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 */