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
140union 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
151static inline uint16_t
152read_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}
159static inline int16_t
160read_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
168static inline uint32_t
169read_4ubyte_unaligned_noncvt (const void *p)
170{
171  const union unaligned *up = p;
172  return up->u4;
173}
174static inline uint32_t
175read_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}
182static inline int32_t
183read_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
191static inline uint64_t
192read_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}
199static inline int64_t
200read_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