1/* Exception handling and frame unwind runtime interface routines.
2   Copyright (C) 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
3
4   This file is part of GCC.
5
6   GCC is free software; you can redistribute it and/or modify it
7   under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 2, or (at your option)
9   any later version.
10
11   In addition to the permissions in the GNU General Public License, the
12   Free Software Foundation gives you unlimited permission to link the
13   compiled version of this file into combinations with other programs,
14   and to distribute those combinations without any restriction coming
15   from the use of this file.  (The General Public License restrictions
16   do apply in other respects; for example, they cover modification of
17   the file, and distribution when not linked into a combined
18   executable.)
19
20   GCC is distributed in the hope that it will be useful, but WITHOUT
21   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
22   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
23   License for more details.
24
25   You should have received a copy of the GNU General Public License
26   along with GCC; see the file COPYING.  If not, write to the Free
27   Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
28   02110-1301, USA.  */
29
30/* @@@ Really this should be out of line, but this also causes link
31   compatibility problems with the base ABI.  This is slightly better
32   than duplicating code, however.  */
33
34#ifndef GCC_UNWIND_PE_H
35#define GCC_UNWIND_PE_H
36
37/* If using C++, references to abort have to be qualified with std::.  */
38#if __cplusplus
39#define __gxx_abort std::abort
40#else
41#define __gxx_abort abort
42#endif
43
44/* Pointer encodings, from dwarf2.h.  */
45#define DW_EH_PE_absptr         0x00
46#define DW_EH_PE_omit           0xff
47
48#define DW_EH_PE_uleb128        0x01
49#define DW_EH_PE_udata2         0x02
50#define DW_EH_PE_udata4         0x03
51#define DW_EH_PE_udata8         0x04
52#define DW_EH_PE_sleb128        0x09
53#define DW_EH_PE_sdata2         0x0A
54#define DW_EH_PE_sdata4         0x0B
55#define DW_EH_PE_sdata8         0x0C
56#define DW_EH_PE_signed         0x08
57
58#define DW_EH_PE_pcrel          0x10
59#define DW_EH_PE_textrel        0x20
60#define DW_EH_PE_datarel        0x30
61#define DW_EH_PE_funcrel        0x40
62#define DW_EH_PE_aligned        0x50
63
64#define DW_EH_PE_indirect	0x80
65
66
67#ifndef NO_SIZE_OF_ENCODED_VALUE
68
69/* Given an encoding, return the number of bytes the format occupies.
70   This is only defined for fixed-size encodings, and so does not
71   include leb128.  */
72
73static unsigned int
74size_of_encoded_value (unsigned char encoding)
75{
76  if (encoding == DW_EH_PE_omit)
77    return 0;
78
79  switch (encoding & 0x07)
80    {
81    case DW_EH_PE_absptr:
82      return sizeof (void *);
83    case DW_EH_PE_udata2:
84      return 2;
85    case DW_EH_PE_udata4:
86      return 4;
87    case DW_EH_PE_udata8:
88      return 8;
89    }
90  __gxx_abort ();
91}
92
93#endif
94
95#ifndef NO_BASE_OF_ENCODED_VALUE
96
97/* Given an encoding and an _Unwind_Context, return the base to which
98   the encoding is relative.  This base may then be passed to
99   read_encoded_value_with_base for use when the _Unwind_Context is
100   not available.  */
101
102static _Unwind_Ptr
103base_of_encoded_value (unsigned char encoding, struct _Unwind_Context *context)
104{
105  if (encoding == DW_EH_PE_omit)
106    return 0;
107
108  switch (encoding & 0x70)
109    {
110    case DW_EH_PE_absptr:
111    case DW_EH_PE_pcrel:
112    case DW_EH_PE_aligned:
113      return 0;
114
115    case DW_EH_PE_textrel:
116      return _Unwind_GetTextRelBase (context);
117    case DW_EH_PE_datarel:
118      return _Unwind_GetDataRelBase (context);
119    case DW_EH_PE_funcrel:
120      return _Unwind_GetRegionStart (context);
121    }
122  __gxx_abort ();
123}
124
125#endif
126
127/* Read an unsigned leb128 value from P, store the value in VAL, return
128   P incremented past the value.  We assume that a word is large enough to
129   hold any value so encoded; if it is smaller than a pointer on some target,
130   pointers should not be leb128 encoded on that target.  */
131
132static const unsigned char *
133read_uleb128 (const unsigned char *p, _Unwind_Word *val)
134{
135  unsigned int shift = 0;
136  unsigned char byte;
137  _Unwind_Word result;
138
139  result = 0;
140  do
141    {
142      byte = *p++;
143      result |= ((_Unwind_Word)byte & 0x7f) << shift;
144      shift += 7;
145    }
146  while (byte & 0x80);
147
148  *val = result;
149  return p;
150}
151
152/* Similar, but read a signed leb128 value.  */
153
154static const unsigned char *
155read_sleb128 (const unsigned char *p, _Unwind_Sword *val)
156{
157  unsigned int shift = 0;
158  unsigned char byte;
159  _Unwind_Word result;
160
161  result = 0;
162  do
163    {
164      byte = *p++;
165      result |= ((_Unwind_Word)byte & 0x7f) << shift;
166      shift += 7;
167    }
168  while (byte & 0x80);
169
170  /* Sign-extend a negative value.  */
171  if (shift < 8 * sizeof(result) && (byte & 0x40) != 0)
172    result |= -(((_Unwind_Word)1L) << shift);
173
174  *val = (_Unwind_Sword) result;
175  return p;
176}
177
178/* Load an encoded value from memory at P.  The value is returned in VAL;
179   The function returns P incremented past the value.  BASE is as given
180   by base_of_encoded_value for this encoding in the appropriate context.  */
181
182static const unsigned char *
183read_encoded_value_with_base (unsigned char encoding, _Unwind_Ptr base,
184			      const unsigned char *p, _Unwind_Ptr *val)
185{
186  union unaligned
187    {
188      void *ptr;
189      unsigned u2 __attribute__ ((mode (HI)));
190      unsigned u4 __attribute__ ((mode (SI)));
191      unsigned u8 __attribute__ ((mode (DI)));
192      signed s2 __attribute__ ((mode (HI)));
193      signed s4 __attribute__ ((mode (SI)));
194      signed s8 __attribute__ ((mode (DI)));
195    } __attribute__((__packed__));
196
197  const union unaligned *u = (const union unaligned *) p;
198  _Unwind_Internal_Ptr result;
199
200  if (encoding == DW_EH_PE_aligned)
201    {
202      _Unwind_Internal_Ptr a = (_Unwind_Internal_Ptr) p;
203      a = (a + sizeof (void *) - 1) & - sizeof(void *);
204      result = *(_Unwind_Internal_Ptr *) a;
205      p = (const unsigned char *) (_Unwind_Internal_Ptr) (a + sizeof (void *));
206    }
207  else
208    {
209      switch (encoding & 0x0f)
210	{
211	case DW_EH_PE_absptr:
212	  result = (_Unwind_Internal_Ptr) u->ptr;
213	  p += sizeof (void *);
214	  break;
215
216	case DW_EH_PE_uleb128:
217	  {
218	    _Unwind_Word tmp;
219	    p = read_uleb128 (p, &tmp);
220	    result = (_Unwind_Internal_Ptr) tmp;
221	  }
222	  break;
223
224	case DW_EH_PE_sleb128:
225	  {
226	    _Unwind_Sword tmp;
227	    p = read_sleb128 (p, &tmp);
228	    result = (_Unwind_Internal_Ptr) tmp;
229	  }
230	  break;
231
232	case DW_EH_PE_udata2:
233	  result = u->u2;
234	  p += 2;
235	  break;
236	case DW_EH_PE_udata4:
237	  result = u->u4;
238	  p += 4;
239	  break;
240	case DW_EH_PE_udata8:
241	  result = u->u8;
242	  p += 8;
243	  break;
244
245	case DW_EH_PE_sdata2:
246	  result = u->s2;
247	  p += 2;
248	  break;
249	case DW_EH_PE_sdata4:
250	  result = u->s4;
251	  p += 4;
252	  break;
253	case DW_EH_PE_sdata8:
254	  result = u->s8;
255	  p += 8;
256	  break;
257
258	default:
259	  __gxx_abort ();
260	}
261
262      if (result != 0)
263	{
264	  result += ((encoding & 0x70) == DW_EH_PE_pcrel
265		     ? (_Unwind_Internal_Ptr) u : base);
266	  if (encoding & DW_EH_PE_indirect)
267	    result = *(_Unwind_Internal_Ptr *) result;
268	}
269    }
270
271  *val = result;
272  return p;
273}
274
275#ifndef NO_BASE_OF_ENCODED_VALUE
276
277/* Like read_encoded_value_with_base, but get the base from the context
278   rather than providing it directly.  */
279
280static inline const unsigned char *
281read_encoded_value (struct _Unwind_Context *context, unsigned char encoding,
282		    const unsigned char *p, _Unwind_Ptr *val)
283{
284  return read_encoded_value_with_base (encoding,
285		base_of_encoded_value (encoding, context),
286		p, val);
287}
288
289#endif
290
291#endif /* unwind-pe.h */
292