1251881Speter/* Exception handling and frame unwind runtime interface routines.
2251881Speter   Copyright (C) 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
3251881Speter
4251881Speter   This file is part of GCC.
5251881Speter
6251881Speter   GCC is free software; you can redistribute it and/or modify it
7251881Speter   under the terms of the GNU General Public License as published by
8251881Speter   the Free Software Foundation; either version 2, or (at your option)
9251881Speter   any later version.
10251881Speter
11251881Speter   In addition to the permissions in the GNU General Public License, the
12251881Speter   Free Software Foundation gives you unlimited permission to link the
13251881Speter   compiled version of this file into combinations with other programs,
14251881Speter   and to distribute those combinations without any restriction coming
15251881Speter   from the use of this file.  (The General Public License restrictions
16251881Speter   do apply in other respects; for example, they cover modification of
17251881Speter   the file, and distribution when not linked into a combined
18251881Speter   executable.)
19251881Speter
20251881Speter   GCC is distributed in the hope that it will be useful, but WITHOUT
21251881Speter   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
22251881Speter   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
23251881Speter   License for more details.
24251881Speter
25251881Speter   You should have received a copy of the GNU General Public License
26251881Speter   along with GCC; see the file COPYING.  If not, write to the Free
27251881Speter   Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
28251881Speter   02110-1301, USA.  */
29251881Speter
30251881Speter/* @@@ Really this should be out of line, but this also causes link
31251881Speter   compatibility problems with the base ABI.  This is slightly better
32251881Speter   than duplicating code, however.  */
33251881Speter
34251881Speter#ifndef GCC_UNWIND_PE_H
35251881Speter#define GCC_UNWIND_PE_H
36251881Speter
37251881Speter/* If using C++, references to abort have to be qualified with std::.  */
38251881Speter#if __cplusplus
39251881Speter#define __gxx_abort std::abort
40251881Speter#else
41251881Speter#define __gxx_abort abort
42251881Speter#endif
43251881Speter
44251881Speter/* Pointer encodings, from dwarf2.h.  */
45251881Speter#define DW_EH_PE_absptr         0x00
46251881Speter#define DW_EH_PE_omit           0xff
47251881Speter
48251881Speter#define DW_EH_PE_uleb128        0x01
49251881Speter#define DW_EH_PE_udata2         0x02
50251881Speter#define DW_EH_PE_udata4         0x03
51251881Speter#define DW_EH_PE_udata8         0x04
52251881Speter#define DW_EH_PE_sleb128        0x09
53251881Speter#define DW_EH_PE_sdata2         0x0A
54251881Speter#define DW_EH_PE_sdata4         0x0B
55251881Speter#define DW_EH_PE_sdata8         0x0C
56251881Speter#define DW_EH_PE_signed         0x08
57251881Speter
58251881Speter#define DW_EH_PE_pcrel          0x10
59251881Speter#define DW_EH_PE_textrel        0x20
60251881Speter#define DW_EH_PE_datarel        0x30
61251881Speter#define DW_EH_PE_funcrel        0x40
62251881Speter#define DW_EH_PE_aligned        0x50
63251881Speter
64251881Speter#define DW_EH_PE_indirect	0x80
65251881Speter
66251881Speter
67251881Speter#ifndef NO_SIZE_OF_ENCODED_VALUE
68251881Speter
69251881Speter/* Given an encoding, return the number of bytes the format occupies.
70251881Speter   This is only defined for fixed-size encodings, and so does not
71251881Speter   include leb128.  */
72251881Speter
73251881Speterstatic unsigned int
74251881Spetersize_of_encoded_value (unsigned char encoding)
75251881Speter{
76251881Speter  if (encoding == DW_EH_PE_omit)
77251881Speter    return 0;
78251881Speter
79251881Speter  switch (encoding & 0x07)
80251881Speter    {
81251881Speter    case DW_EH_PE_absptr:
82251881Speter      return sizeof (void *);
83251881Speter    case DW_EH_PE_udata2:
84251881Speter      return 2;
85251881Speter    case DW_EH_PE_udata4:
86251881Speter      return 4;
87251881Speter    case DW_EH_PE_udata8:
88251881Speter      return 8;
89251881Speter    }
90251881Speter  __gxx_abort ();
91251881Speter}
92251881Speter
93251881Speter#endif
94251881Speter
95251881Speter#ifndef NO_BASE_OF_ENCODED_VALUE
96251881Speter
97251881Speter/* Given an encoding and an _Unwind_Context, return the base to which
98251881Speter   the encoding is relative.  This base may then be passed to
99251881Speter   read_encoded_value_with_base for use when the _Unwind_Context is
100251881Speter   not available.  */
101251881Speter
102251881Speterstatic _Unwind_Ptr
103251881Speterbase_of_encoded_value (unsigned char encoding, struct _Unwind_Context *context)
104251881Speter{
105251881Speter  if (encoding == DW_EH_PE_omit)
106251881Speter    return 0;
107251881Speter
108251881Speter  switch (encoding & 0x70)
109251881Speter    {
110251881Speter    case DW_EH_PE_absptr:
111251881Speter    case DW_EH_PE_pcrel:
112251881Speter    case DW_EH_PE_aligned:
113251881Speter      return 0;
114251881Speter
115251881Speter    case DW_EH_PE_textrel:
116251881Speter      return _Unwind_GetTextRelBase (context);
117251881Speter    case DW_EH_PE_datarel:
118251881Speter      return _Unwind_GetDataRelBase (context);
119251881Speter    case DW_EH_PE_funcrel:
120251881Speter      return _Unwind_GetRegionStart (context);
121251881Speter    }
122251881Speter  __gxx_abort ();
123251881Speter}
124251881Speter
125251881Speter#endif
126251881Speter
127251881Speter/* Read an unsigned leb128 value from P, store the value in VAL, return
128251881Speter   P incremented past the value.  We assume that a word is large enough to
129251881Speter   hold any value so encoded; if it is smaller than a pointer on some target,
130251881Speter   pointers should not be leb128 encoded on that target.  */
131251881Speter
132251881Speterstatic const unsigned char *
133251881Speterread_uleb128 (const unsigned char *p, _Unwind_Word *val)
134251881Speter{
135251881Speter  unsigned int shift = 0;
136251881Speter  unsigned char byte;
137251881Speter  _Unwind_Word result;
138251881Speter
139251881Speter  result = 0;
140251881Speter  do
141251881Speter    {
142251881Speter      byte = *p++;
143251881Speter      result |= ((_Unwind_Word)byte & 0x7f) << shift;
144251881Speter      shift += 7;
145251881Speter    }
146251881Speter  while (byte & 0x80);
147251881Speter
148251881Speter  *val = result;
149251881Speter  return p;
150251881Speter}
151251881Speter
152251881Speter/* Similar, but read a signed leb128 value.  */
153251881Speter
154251881Speterstatic const unsigned char *
155251881Speterread_sleb128 (const unsigned char *p, _Unwind_Sword *val)
156251881Speter{
157251881Speter  unsigned int shift = 0;
158251881Speter  unsigned char byte;
159251881Speter  _Unwind_Word result;
160251881Speter
161251881Speter  result = 0;
162251881Speter  do
163251881Speter    {
164251881Speter      byte = *p++;
165251881Speter      result |= ((_Unwind_Word)byte & 0x7f) << shift;
166251881Speter      shift += 7;
167251881Speter    }
168251881Speter  while (byte & 0x80);
169251881Speter
170251881Speter  /* Sign-extend a negative value.  */
171251881Speter  if (shift < 8 * sizeof(result) && (byte & 0x40) != 0)
172251881Speter    result |= -(((_Unwind_Word)1L) << shift);
173251881Speter
174251881Speter  *val = (_Unwind_Sword) result;
175251881Speter  return p;
176251881Speter}
177251881Speter
178251881Speter/* Load an encoded value from memory at P.  The value is returned in VAL;
179251881Speter   The function returns P incremented past the value.  BASE is as given
180251881Speter   by base_of_encoded_value for this encoding in the appropriate context.  */
181251881Speter
182251881Speterstatic const unsigned char *
183251881Speterread_encoded_value_with_base (unsigned char encoding, _Unwind_Ptr base,
184251881Speter			      const unsigned char *p, _Unwind_Ptr *val)
185251881Speter{
186251881Speter  union unaligned
187251881Speter    {
188251881Speter      void *ptr;
189251881Speter      unsigned u2 __attribute__ ((mode (HI)));
190251881Speter      unsigned u4 __attribute__ ((mode (SI)));
191251881Speter      unsigned u8 __attribute__ ((mode (DI)));
192251881Speter      signed s2 __attribute__ ((mode (HI)));
193251881Speter      signed s4 __attribute__ ((mode (SI)));
194251881Speter      signed s8 __attribute__ ((mode (DI)));
195251881Speter    } __attribute__((__packed__));
196251881Speter
197251881Speter  const union unaligned *u = (const union unaligned *) p;
198251881Speter  _Unwind_Internal_Ptr result;
199251881Speter
200251881Speter  if (encoding == DW_EH_PE_aligned)
201251881Speter    {
202251881Speter      _Unwind_Internal_Ptr a = (_Unwind_Internal_Ptr) p;
203251881Speter      a = (a + sizeof (void *) - 1) & - sizeof(void *);
204251881Speter      result = *(_Unwind_Internal_Ptr *) a;
205251881Speter      p = (const unsigned char *) (_Unwind_Internal_Ptr) (a + sizeof (void *));
206251881Speter    }
207251881Speter  else
208251881Speter    {
209251881Speter      switch (encoding & 0x0f)
210251881Speter	{
211251881Speter	case DW_EH_PE_absptr:
212251881Speter	  result = (_Unwind_Internal_Ptr) u->ptr;
213251881Speter	  p += sizeof (void *);
214251881Speter	  break;
215251881Speter
216251881Speter	case DW_EH_PE_uleb128:
217251881Speter	  {
218251881Speter	    _Unwind_Word tmp;
219251881Speter	    p = read_uleb128 (p, &tmp);
220251881Speter	    result = (_Unwind_Internal_Ptr) tmp;
221251881Speter	  }
222251881Speter	  break;
223251881Speter
224251881Speter	case DW_EH_PE_sleb128:
225251881Speter	  {
226251881Speter	    _Unwind_Sword tmp;
227251881Speter	    p = read_sleb128 (p, &tmp);
228251881Speter	    result = (_Unwind_Internal_Ptr) tmp;
229251881Speter	  }
230251881Speter	  break;
231251881Speter
232251881Speter	case DW_EH_PE_udata2:
233251881Speter	  result = u->u2;
234251881Speter	  p += 2;
235251881Speter	  break;
236251881Speter	case DW_EH_PE_udata4:
237251881Speter	  result = u->u4;
238251881Speter	  p += 4;
239251881Speter	  break;
240251881Speter	case DW_EH_PE_udata8:
241251881Speter	  result = u->u8;
242251881Speter	  p += 8;
243251881Speter	  break;
244251881Speter
245251881Speter	case DW_EH_PE_sdata2:
246251881Speter	  result = u->s2;
247251881Speter	  p += 2;
248251881Speter	  break;
249251881Speter	case DW_EH_PE_sdata4:
250251881Speter	  result = u->s4;
251251881Speter	  p += 4;
252251881Speter	  break;
253251881Speter	case DW_EH_PE_sdata8:
254251881Speter	  result = u->s8;
255251881Speter	  p += 8;
256251881Speter	  break;
257251881Speter
258251881Speter	default:
259251881Speter	  __gxx_abort ();
260251881Speter	}
261251881Speter
262251881Speter      if (result != 0)
263251881Speter	{
264251881Speter	  result += ((encoding & 0x70) == DW_EH_PE_pcrel
265251881Speter		     ? (_Unwind_Internal_Ptr) u : base);
266251881Speter	  if (encoding & DW_EH_PE_indirect)
267251881Speter	    result = *(_Unwind_Internal_Ptr *) result;
268251881Speter	}
269251881Speter    }
270251881Speter
271251881Speter  *val = result;
272251881Speter  return p;
273251881Speter}
274251881Speter
275251881Speter#ifndef NO_BASE_OF_ENCODED_VALUE
276251881Speter
277251881Speter/* Like read_encoded_value_with_base, but get the base from the context
278251881Speter   rather than providing it directly.  */
279251881Speter
280251881Speterstatic inline const unsigned char *
281251881Speterread_encoded_value (struct _Unwind_Context *context, unsigned char encoding,
282251881Speter		    const unsigned char *p, _Unwind_Ptr *val)
283251881Speter{
284251881Speter  return read_encoded_value_with_base (encoding,
285251881Speter		base_of_encoded_value (encoding, context),
286251881Speter		p, val);
287251881Speter}
288251881Speter
289251881Speter#endif
290251881Speter
291251881Speter#endif /* unwind-pe.h */
292251881Speter