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