1*7c3d14c8STreehugger Robot /* ===-- gcc_personality_v0.c - Implement __gcc_personality_v0 -------------===
2*7c3d14c8STreehugger Robot *
3*7c3d14c8STreehugger Robot * The LLVM Compiler Infrastructure
4*7c3d14c8STreehugger Robot *
5*7c3d14c8STreehugger Robot * This file is dual licensed under the MIT and the University of Illinois Open
6*7c3d14c8STreehugger Robot * Source Licenses. See LICENSE.TXT for details.
7*7c3d14c8STreehugger Robot *
8*7c3d14c8STreehugger Robot * ===----------------------------------------------------------------------===
9*7c3d14c8STreehugger Robot *
10*7c3d14c8STreehugger Robot */
11*7c3d14c8STreehugger Robot
12*7c3d14c8STreehugger Robot #include "int_lib.h"
13*7c3d14c8STreehugger Robot
14*7c3d14c8STreehugger Robot #include <unwind.h>
15*7c3d14c8STreehugger Robot
16*7c3d14c8STreehugger Robot /*
17*7c3d14c8STreehugger Robot * Pointer encodings documented at:
18*7c3d14c8STreehugger Robot * http://refspecs.freestandards.org/LSB_1.3.0/gLSB/gLSB/ehframehdr.html
19*7c3d14c8STreehugger Robot */
20*7c3d14c8STreehugger Robot
21*7c3d14c8STreehugger Robot #define DW_EH_PE_omit 0xff /* no data follows */
22*7c3d14c8STreehugger Robot
23*7c3d14c8STreehugger Robot #define DW_EH_PE_absptr 0x00
24*7c3d14c8STreehugger Robot #define DW_EH_PE_uleb128 0x01
25*7c3d14c8STreehugger Robot #define DW_EH_PE_udata2 0x02
26*7c3d14c8STreehugger Robot #define DW_EH_PE_udata4 0x03
27*7c3d14c8STreehugger Robot #define DW_EH_PE_udata8 0x04
28*7c3d14c8STreehugger Robot #define DW_EH_PE_sleb128 0x09
29*7c3d14c8STreehugger Robot #define DW_EH_PE_sdata2 0x0A
30*7c3d14c8STreehugger Robot #define DW_EH_PE_sdata4 0x0B
31*7c3d14c8STreehugger Robot #define DW_EH_PE_sdata8 0x0C
32*7c3d14c8STreehugger Robot
33*7c3d14c8STreehugger Robot #define DW_EH_PE_pcrel 0x10
34*7c3d14c8STreehugger Robot #define DW_EH_PE_textrel 0x20
35*7c3d14c8STreehugger Robot #define DW_EH_PE_datarel 0x30
36*7c3d14c8STreehugger Robot #define DW_EH_PE_funcrel 0x40
37*7c3d14c8STreehugger Robot #define DW_EH_PE_aligned 0x50
38*7c3d14c8STreehugger Robot #define DW_EH_PE_indirect 0x80 /* gcc extension */
39*7c3d14c8STreehugger Robot
40*7c3d14c8STreehugger Robot
41*7c3d14c8STreehugger Robot
42*7c3d14c8STreehugger Robot /* read a uleb128 encoded value and advance pointer */
readULEB128(const uint8_t ** data)43*7c3d14c8STreehugger Robot static uintptr_t readULEB128(const uint8_t** data)
44*7c3d14c8STreehugger Robot {
45*7c3d14c8STreehugger Robot uintptr_t result = 0;
46*7c3d14c8STreehugger Robot uintptr_t shift = 0;
47*7c3d14c8STreehugger Robot unsigned char byte;
48*7c3d14c8STreehugger Robot const uint8_t* p = *data;
49*7c3d14c8STreehugger Robot do {
50*7c3d14c8STreehugger Robot byte = *p++;
51*7c3d14c8STreehugger Robot result |= (byte & 0x7f) << shift;
52*7c3d14c8STreehugger Robot shift += 7;
53*7c3d14c8STreehugger Robot } while (byte & 0x80);
54*7c3d14c8STreehugger Robot *data = p;
55*7c3d14c8STreehugger Robot return result;
56*7c3d14c8STreehugger Robot }
57*7c3d14c8STreehugger Robot
58*7c3d14c8STreehugger Robot /* read a pointer encoded value and advance pointer */
readEncodedPointer(const uint8_t ** data,uint8_t encoding)59*7c3d14c8STreehugger Robot static uintptr_t readEncodedPointer(const uint8_t** data, uint8_t encoding)
60*7c3d14c8STreehugger Robot {
61*7c3d14c8STreehugger Robot const uint8_t* p = *data;
62*7c3d14c8STreehugger Robot uintptr_t result = 0;
63*7c3d14c8STreehugger Robot
64*7c3d14c8STreehugger Robot if ( encoding == DW_EH_PE_omit )
65*7c3d14c8STreehugger Robot return 0;
66*7c3d14c8STreehugger Robot
67*7c3d14c8STreehugger Robot /* first get value */
68*7c3d14c8STreehugger Robot switch (encoding & 0x0F) {
69*7c3d14c8STreehugger Robot case DW_EH_PE_absptr:
70*7c3d14c8STreehugger Robot result = *((const uintptr_t*)p);
71*7c3d14c8STreehugger Robot p += sizeof(uintptr_t);
72*7c3d14c8STreehugger Robot break;
73*7c3d14c8STreehugger Robot case DW_EH_PE_uleb128:
74*7c3d14c8STreehugger Robot result = readULEB128(&p);
75*7c3d14c8STreehugger Robot break;
76*7c3d14c8STreehugger Robot case DW_EH_PE_udata2:
77*7c3d14c8STreehugger Robot result = *((const uint16_t*)p);
78*7c3d14c8STreehugger Robot p += sizeof(uint16_t);
79*7c3d14c8STreehugger Robot break;
80*7c3d14c8STreehugger Robot case DW_EH_PE_udata4:
81*7c3d14c8STreehugger Robot result = *((const uint32_t*)p);
82*7c3d14c8STreehugger Robot p += sizeof(uint32_t);
83*7c3d14c8STreehugger Robot break;
84*7c3d14c8STreehugger Robot case DW_EH_PE_udata8:
85*7c3d14c8STreehugger Robot result = *((const uint64_t*)p);
86*7c3d14c8STreehugger Robot p += sizeof(uint64_t);
87*7c3d14c8STreehugger Robot break;
88*7c3d14c8STreehugger Robot case DW_EH_PE_sdata2:
89*7c3d14c8STreehugger Robot result = *((const int16_t*)p);
90*7c3d14c8STreehugger Robot p += sizeof(int16_t);
91*7c3d14c8STreehugger Robot break;
92*7c3d14c8STreehugger Robot case DW_EH_PE_sdata4:
93*7c3d14c8STreehugger Robot result = *((const int32_t*)p);
94*7c3d14c8STreehugger Robot p += sizeof(int32_t);
95*7c3d14c8STreehugger Robot break;
96*7c3d14c8STreehugger Robot case DW_EH_PE_sdata8:
97*7c3d14c8STreehugger Robot result = *((const int64_t*)p);
98*7c3d14c8STreehugger Robot p += sizeof(int64_t);
99*7c3d14c8STreehugger Robot break;
100*7c3d14c8STreehugger Robot case DW_EH_PE_sleb128:
101*7c3d14c8STreehugger Robot default:
102*7c3d14c8STreehugger Robot /* not supported */
103*7c3d14c8STreehugger Robot compilerrt_abort();
104*7c3d14c8STreehugger Robot break;
105*7c3d14c8STreehugger Robot }
106*7c3d14c8STreehugger Robot
107*7c3d14c8STreehugger Robot /* then add relative offset */
108*7c3d14c8STreehugger Robot switch ( encoding & 0x70 ) {
109*7c3d14c8STreehugger Robot case DW_EH_PE_absptr:
110*7c3d14c8STreehugger Robot /* do nothing */
111*7c3d14c8STreehugger Robot break;
112*7c3d14c8STreehugger Robot case DW_EH_PE_pcrel:
113*7c3d14c8STreehugger Robot result += (uintptr_t)(*data);
114*7c3d14c8STreehugger Robot break;
115*7c3d14c8STreehugger Robot case DW_EH_PE_textrel:
116*7c3d14c8STreehugger Robot case DW_EH_PE_datarel:
117*7c3d14c8STreehugger Robot case DW_EH_PE_funcrel:
118*7c3d14c8STreehugger Robot case DW_EH_PE_aligned:
119*7c3d14c8STreehugger Robot default:
120*7c3d14c8STreehugger Robot /* not supported */
121*7c3d14c8STreehugger Robot compilerrt_abort();
122*7c3d14c8STreehugger Robot break;
123*7c3d14c8STreehugger Robot }
124*7c3d14c8STreehugger Robot
125*7c3d14c8STreehugger Robot /* then apply indirection */
126*7c3d14c8STreehugger Robot if (encoding & DW_EH_PE_indirect) {
127*7c3d14c8STreehugger Robot result = *((const uintptr_t*)result);
128*7c3d14c8STreehugger Robot }
129*7c3d14c8STreehugger Robot
130*7c3d14c8STreehugger Robot *data = p;
131*7c3d14c8STreehugger Robot return result;
132*7c3d14c8STreehugger Robot }
133*7c3d14c8STreehugger Robot
134*7c3d14c8STreehugger Robot #if defined(__arm__) && !defined(__USING_SJLJ_EXCEPTIONS__) && \
135*7c3d14c8STreehugger Robot !defined(__ARM_DWARF_EH__)
136*7c3d14c8STreehugger Robot #define USING_ARM_EHABI 1
137*7c3d14c8STreehugger Robot _Unwind_Reason_Code __gnu_unwind_frame(struct _Unwind_Exception *,
138*7c3d14c8STreehugger Robot struct _Unwind_Context *);
139*7c3d14c8STreehugger Robot #endif
140*7c3d14c8STreehugger Robot
141*7c3d14c8STreehugger Robot static inline _Unwind_Reason_Code
continueUnwind(struct _Unwind_Exception * exceptionObject,struct _Unwind_Context * context)142*7c3d14c8STreehugger Robot continueUnwind(struct _Unwind_Exception *exceptionObject,
143*7c3d14c8STreehugger Robot struct _Unwind_Context *context) {
144*7c3d14c8STreehugger Robot #if USING_ARM_EHABI
145*7c3d14c8STreehugger Robot /*
146*7c3d14c8STreehugger Robot * On ARM EHABI the personality routine is responsible for actually
147*7c3d14c8STreehugger Robot * unwinding a single stack frame before returning (ARM EHABI Sec. 6.1).
148*7c3d14c8STreehugger Robot */
149*7c3d14c8STreehugger Robot if (__gnu_unwind_frame(exceptionObject, context) != _URC_OK)
150*7c3d14c8STreehugger Robot return _URC_FAILURE;
151*7c3d14c8STreehugger Robot #endif
152*7c3d14c8STreehugger Robot return _URC_CONTINUE_UNWIND;
153*7c3d14c8STreehugger Robot }
154*7c3d14c8STreehugger Robot
155*7c3d14c8STreehugger Robot /*
156*7c3d14c8STreehugger Robot * The C compiler makes references to __gcc_personality_v0 in
157*7c3d14c8STreehugger Robot * the dwarf unwind information for translation units that use
158*7c3d14c8STreehugger Robot * __attribute__((cleanup(xx))) on local variables.
159*7c3d14c8STreehugger Robot * This personality routine is called by the system unwinder
160*7c3d14c8STreehugger Robot * on each frame as the stack is unwound during a C++ exception
161*7c3d14c8STreehugger Robot * throw through a C function compiled with -fexceptions.
162*7c3d14c8STreehugger Robot */
163*7c3d14c8STreehugger Robot #if __USING_SJLJ_EXCEPTIONS__
164*7c3d14c8STreehugger Robot /* the setjump-longjump based exceptions personality routine has a
165*7c3d14c8STreehugger Robot * different name */
166*7c3d14c8STreehugger Robot COMPILER_RT_ABI _Unwind_Reason_Code
__gcc_personality_sj0(int version,_Unwind_Action actions,uint64_t exceptionClass,struct _Unwind_Exception * exceptionObject,struct _Unwind_Context * context)167*7c3d14c8STreehugger Robot __gcc_personality_sj0(int version, _Unwind_Action actions,
168*7c3d14c8STreehugger Robot uint64_t exceptionClass, struct _Unwind_Exception* exceptionObject,
169*7c3d14c8STreehugger Robot struct _Unwind_Context *context)
170*7c3d14c8STreehugger Robot #elif USING_ARM_EHABI
171*7c3d14c8STreehugger Robot /* The ARM EHABI personality routine has a different signature. */
172*7c3d14c8STreehugger Robot COMPILER_RT_ABI _Unwind_Reason_Code __gcc_personality_v0(
173*7c3d14c8STreehugger Robot _Unwind_State state, struct _Unwind_Exception *exceptionObject,
174*7c3d14c8STreehugger Robot struct _Unwind_Context *context)
175*7c3d14c8STreehugger Robot #else
176*7c3d14c8STreehugger Robot COMPILER_RT_ABI _Unwind_Reason_Code
177*7c3d14c8STreehugger Robot __gcc_personality_v0(int version, _Unwind_Action actions,
178*7c3d14c8STreehugger Robot uint64_t exceptionClass, struct _Unwind_Exception* exceptionObject,
179*7c3d14c8STreehugger Robot struct _Unwind_Context *context)
180*7c3d14c8STreehugger Robot #endif
181*7c3d14c8STreehugger Robot {
182*7c3d14c8STreehugger Robot /* Since C does not have catch clauses, there is nothing to do during */
183*7c3d14c8STreehugger Robot /* phase 1 (the search phase). */
184*7c3d14c8STreehugger Robot #if USING_ARM_EHABI
185*7c3d14c8STreehugger Robot /* After resuming from a cleanup we should also continue on to the next
186*7c3d14c8STreehugger Robot * frame straight away. */
187*7c3d14c8STreehugger Robot if ((state & _US_ACTION_MASK) != _US_UNWIND_FRAME_STARTING)
188*7c3d14c8STreehugger Robot #else
189*7c3d14c8STreehugger Robot if ( actions & _UA_SEARCH_PHASE )
190*7c3d14c8STreehugger Robot #endif
191*7c3d14c8STreehugger Robot return continueUnwind(exceptionObject, context);
192*7c3d14c8STreehugger Robot
193*7c3d14c8STreehugger Robot /* There is nothing to do if there is no LSDA for this frame. */
194*7c3d14c8STreehugger Robot const uint8_t* lsda = (uint8_t*)_Unwind_GetLanguageSpecificData(context);
195*7c3d14c8STreehugger Robot if ( lsda == (uint8_t*) 0 )
196*7c3d14c8STreehugger Robot return continueUnwind(exceptionObject, context);
197*7c3d14c8STreehugger Robot
198*7c3d14c8STreehugger Robot uintptr_t pc = _Unwind_GetIP(context)-1;
199*7c3d14c8STreehugger Robot uintptr_t funcStart = _Unwind_GetRegionStart(context);
200*7c3d14c8STreehugger Robot uintptr_t pcOffset = pc - funcStart;
201*7c3d14c8STreehugger Robot
202*7c3d14c8STreehugger Robot /* Parse LSDA header. */
203*7c3d14c8STreehugger Robot uint8_t lpStartEncoding = *lsda++;
204*7c3d14c8STreehugger Robot if (lpStartEncoding != DW_EH_PE_omit) {
205*7c3d14c8STreehugger Robot readEncodedPointer(&lsda, lpStartEncoding);
206*7c3d14c8STreehugger Robot }
207*7c3d14c8STreehugger Robot uint8_t ttypeEncoding = *lsda++;
208*7c3d14c8STreehugger Robot if (ttypeEncoding != DW_EH_PE_omit) {
209*7c3d14c8STreehugger Robot readULEB128(&lsda);
210*7c3d14c8STreehugger Robot }
211*7c3d14c8STreehugger Robot /* Walk call-site table looking for range that includes current PC. */
212*7c3d14c8STreehugger Robot uint8_t callSiteEncoding = *lsda++;
213*7c3d14c8STreehugger Robot uint32_t callSiteTableLength = readULEB128(&lsda);
214*7c3d14c8STreehugger Robot const uint8_t* callSiteTableStart = lsda;
215*7c3d14c8STreehugger Robot const uint8_t* callSiteTableEnd = callSiteTableStart + callSiteTableLength;
216*7c3d14c8STreehugger Robot const uint8_t* p=callSiteTableStart;
217*7c3d14c8STreehugger Robot while (p < callSiteTableEnd) {
218*7c3d14c8STreehugger Robot uintptr_t start = readEncodedPointer(&p, callSiteEncoding);
219*7c3d14c8STreehugger Robot uintptr_t length = readEncodedPointer(&p, callSiteEncoding);
220*7c3d14c8STreehugger Robot uintptr_t landingPad = readEncodedPointer(&p, callSiteEncoding);
221*7c3d14c8STreehugger Robot readULEB128(&p); /* action value not used for C code */
222*7c3d14c8STreehugger Robot if ( landingPad == 0 )
223*7c3d14c8STreehugger Robot continue; /* no landing pad for this entry */
224*7c3d14c8STreehugger Robot if ( (start <= pcOffset) && (pcOffset < (start+length)) ) {
225*7c3d14c8STreehugger Robot /* Found landing pad for the PC.
226*7c3d14c8STreehugger Robot * Set Instruction Pointer to so we re-enter function
227*7c3d14c8STreehugger Robot * at landing pad. The landing pad is created by the compiler
228*7c3d14c8STreehugger Robot * to take two parameters in registers.
229*7c3d14c8STreehugger Robot */
230*7c3d14c8STreehugger Robot _Unwind_SetGR(context, __builtin_eh_return_data_regno(0),
231*7c3d14c8STreehugger Robot (uintptr_t)exceptionObject);
232*7c3d14c8STreehugger Robot _Unwind_SetGR(context, __builtin_eh_return_data_regno(1), 0);
233*7c3d14c8STreehugger Robot _Unwind_SetIP(context, (funcStart + landingPad));
234*7c3d14c8STreehugger Robot return _URC_INSTALL_CONTEXT;
235*7c3d14c8STreehugger Robot }
236*7c3d14c8STreehugger Robot }
237*7c3d14c8STreehugger Robot
238*7c3d14c8STreehugger Robot /* No landing pad found, continue unwinding. */
239*7c3d14c8STreehugger Robot return continueUnwind(exceptionObject, context);
240*7c3d14c8STreehugger Robot }
241*7c3d14c8STreehugger Robot
242