blob: 8efd899373f5386fa4fb0e0f89afc576504c4089 [file] [log] [blame]
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001/* Unaligned memory access functionality.
2 Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005 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
25#define get_uleb128_step(var, addr, nth, break) \
26 __b = *(addr)++; \
27 var |= (uintmax_t) (__b & 0x7f) << (nth * 7); \
28 if (likely ((__b & 0x80) == 0)) \
29 break
30
31#define get_uleb128(var, addr) \
32 do { \
33 unsigned char __b; \
34 var = 0; \
35 get_uleb128_step (var, addr, 0, break); \
36 var = __libdw_get_uleb128 (var, 1, &(addr)); \
37 } while (0)
38
39#define get_uleb128_rest_return(var, i, addrp) \
40 do { \
41 for (; i < 10; ++i) \
42 { \
43 get_uleb128_step (var, *addrp, i, return var); \
44 } \
45 /* Other implementations set VALUE to UINT_MAX in this \
46 case. So we better do this as well. */ \
47 return UINT64_MAX; \
48 } while (0)
49
50/* The signed case is similar, but we sign-extend the result. */
51
52#define get_sleb128_step(var, addr, nth, break) \
53 __b = *(addr)++; \
54 _v |= (uint64_t) (__b & 0x7f) << (nth * 7); \
55 if (likely ((__b & 0x80) == 0)) \
56 { \
57 var = (_v << (64 - (nth * 7) - 7) >> (64 - (nth * 7) - 7)); \
58 break; \
59 } \
60 else do {} while (0)
61
62#define get_sleb128(var, addr) \
63 do { \
64 unsigned char __b; \
65 int64_t _v = 0; \
66 get_sleb128_step (var, addr, 0, break); \
67 var = __libdw_get_sleb128 (_v, 1, &(addr)); \
68 } while (0)
69
70#define get_sleb128_rest_return(var, i, addrp) \
71 do { \
72 for (; i < 9; ++i) \
73 { \
74 get_sleb128_step (var, *addrp, i, return var); \
75 } \
76 /* Other implementations set VALUE to INT_MAX in this \
77 case. So we better do this as well. */ \
78 return INT64_MAX; \
79 } while (0)
80
81#ifdef IS_LIBDW
82extern uint64_t __libdw_get_uleb128 (uint64_t acc, unsigned int i,
83 const unsigned char **addrp)
84 internal_function attribute_hidden;
85extern int64_t __libdw_get_sleb128 (int64_t acc, unsigned int i,
86 const unsigned char **addrp)
87 internal_function attribute_hidden;
88#else
89static uint64_t
90__attribute__ ((unused))
91__libdw_get_uleb128 (uint64_t acc, unsigned int i, const unsigned char **addrp)
92{
93 unsigned char __b;
94 get_uleb128_rest_return (acc, i, addrp);
95}
96static int64_t
97__attribute__ ((unused))
98__libdw_get_sleb128 (int64_t acc, unsigned int i, const unsigned char **addrp)
99{
100 unsigned char __b;
101 int64_t _v = acc;
102 get_sleb128_rest_return (acc, i, addrp);
103}
104#endif
105
106
107/* We use simple memory access functions in case the hardware allows it.
108 The caller has to make sure we don't have alias problems. */
109#if ALLOW_UNALIGNED
110
111# define read_2ubyte_unaligned(Dbg, Addr) \
112 (unlikely ((Dbg)->other_byte_order) \
113 ? bswap_16 (*((const uint16_t *) (Addr))) \
114 : *((const uint16_t *) (Addr)))
115# define read_2sbyte_unaligned(Dbg, Addr) \
116 (unlikely ((Dbg)->other_byte_order) \
117 ? (int16_t) bswap_16 (*((const int16_t *) (Addr))) \
118 : *((const int16_t *) (Addr)))
119
120# define read_4ubyte_unaligned_noncvt(Addr) \
121 *((const uint32_t *) (Addr))
122# define read_4ubyte_unaligned(Dbg, Addr) \
123 (unlikely ((Dbg)->other_byte_order) \
124 ? bswap_32 (*((const uint32_t *) (Addr))) \
125 : *((const uint32_t *) (Addr)))
126# define read_4sbyte_unaligned(Dbg, Addr) \
127 (unlikely ((Dbg)->other_byte_order) \
128 ? (int32_t) bswap_32 (*((const int32_t *) (Addr))) \
129 : *((const int32_t *) (Addr)))
130
131# define read_8ubyte_unaligned(Dbg, Addr) \
132 (unlikely ((Dbg)->other_byte_order) \
133 ? bswap_64 (*((const uint64_t *) (Addr))) \
134 : *((const uint64_t *) (Addr)))
135# define read_8sbyte_unaligned(Dbg, Addr) \
136 (unlikely ((Dbg)->other_byte_order) \
137 ? (int64_t) bswap_64 (*((const int64_t *) (Addr))) \
138 : *((const int64_t *) (Addr)))
139
140#else
141
142union unaligned
143 {
144 void *p;
145 uint16_t u2;
146 uint32_t u4;
147 uint64_t u8;
148 int16_t s2;
149 int32_t s4;
150 int64_t s8;
151 } __attribute__ ((packed));
152
153static inline uint16_t
154read_2ubyte_unaligned (Dwarf *dbg, const void *p)
155{
156 const union unaligned *up = p;
157 if (dbg->other_byte_order)
158 return bswap_16 (up->u2);
159 return up->u2;
160}
161static inline int16_t
162read_2sbyte_unaligned (Dwarf *dbg, const void *p)
163{
164 const union unaligned *up = p;
165 if (dbg->other_byte_order)
166 return (int16_t) bswap_16 (up->u2);
167 return up->s2;
168}
169
170static inline uint32_t
171read_4ubyte_unaligned_noncvt (const void *p)
172{
173 const union unaligned *up = p;
174 return up->u4;
175}
176static inline uint32_t
177read_4ubyte_unaligned (Dwarf *dbg, const void *p)
178{
179 const union unaligned *up = p;
180 if (dbg->other_byte_order)
181 return bswap_32 (up->u4);
182 return up->u4;
183}
184static inline int32_t
185read_4sbyte_unaligned (Dwarf *dbg, const void *p)
186{
187 const union unaligned *up = p;
188 if (dbg->other_byte_order)
189 return (int32_t) bswap_32 (up->u4);
190 return up->s4;
191}
192
193static inline uint64_t
194read_8ubyte_unaligned (Dwarf *dbg, const void *p)
195{
196 const union unaligned *up = p;
197 if (dbg->other_byte_order)
198 return bswap_64 (up->u8);
199 return up->u8;
200}
201static inline int64_t
202read_8sbyte_unaligned (Dwarf *dbg, const void *p)
203{
204 const union unaligned *up = p;
205 if (dbg->other_byte_order)
206 return (int64_t) bswap_64 (up->u8);
207 return up->s8;
208}
209
210#endif /* allow unaligned */
211
212
213#define read_2ubyte_unaligned_inc(Dbg, Addr) \
214 ({ uint16_t t_ = read_2ubyte_unaligned (Dbg, Addr); \
215 Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 2); \
216 t_; })
217#define read_2sbyte_unaligned_inc(Dbg, Addr) \
218 ({ int16_t t_ = read_2sbyte_unaligned (Dbg, Addr); \
219 Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 2); \
220 t_; })
221
222#define read_4ubyte_unaligned_inc(Dbg, Addr) \
223 ({ uint32_t t_ = read_4ubyte_unaligned (Dbg, Addr); \
224 Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 4); \
225 t_; })
226#define read_4sbyte_unaligned_inc(Dbg, Addr) \
227 ({ int32_t t_ = read_4sbyte_unaligned (Dbg, Addr); \
228 Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 4); \
229 t_; })
230
231#define read_8ubyte_unaligned_inc(Dbg, Addr) \
232 ({ uint64_t t_ = read_8ubyte_unaligned (Dbg, Addr); \
233 Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 8); \
234 t_; })
235#define read_8sbyte_unaligned_inc(Dbg, Addr) \
236 ({ int64_t t_ = read_8sbyte_unaligned (Dbg, Addr); \
237 Addr = (__typeof (Addr)) (((uintptr_t) (Addr)) + 8); \
238 t_; })
239
240#endif /* memory-access.h */