1214152Sed/* ===-- gcc_personality_v0.c - Implement __gcc_personality_v0 -------------=== 2214152Sed * 3214152Sed * The LLVM Compiler Infrastructure 4214152Sed * 5222656Sed * This file is dual licensed under the MIT and the University of Illinois Open 6222656Sed * Source Licenses. See LICENSE.TXT for details. 7214152Sed * 8214152Sed * ===----------------------------------------------------------------------=== 9214152Sed * 10214152Sed */ 11214152Sed 12214152Sed#include "int_lib.h" 13214152Sed 14214152Sed/* 15214152Sed * _Unwind_* stuff based on C++ ABI public documentation 16214152Sed * http://refspecs.freestandards.org/abi-eh-1.21.html 17214152Sed */ 18214152Sed 19214152Sedtypedef enum { 20214152Sed _URC_NO_REASON = 0, 21214152Sed _URC_FOREIGN_EXCEPTION_CAUGHT = 1, 22214152Sed _URC_FATAL_PHASE2_ERROR = 2, 23214152Sed _URC_FATAL_PHASE1_ERROR = 3, 24214152Sed _URC_NORMAL_STOP = 4, 25214152Sed _URC_END_OF_STACK = 5, 26214152Sed _URC_HANDLER_FOUND = 6, 27214152Sed _URC_INSTALL_CONTEXT = 7, 28214152Sed _URC_CONTINUE_UNWIND = 8 29214152Sed} _Unwind_Reason_Code; 30214152Sed 31214152Sedtypedef enum { 32214152Sed _UA_SEARCH_PHASE = 1, 33214152Sed _UA_CLEANUP_PHASE = 2, 34214152Sed _UA_HANDLER_FRAME = 4, 35214152Sed _UA_FORCE_UNWIND = 8, 36214152Sed _UA_END_OF_STACK = 16 37214152Sed} _Unwind_Action; 38214152Sed 39214152Sedtypedef struct _Unwind_Context* _Unwind_Context_t; 40214152Sed 41214152Sedstruct _Unwind_Exception { 42214152Sed uint64_t exception_class; 43214152Sed void (*exception_cleanup)(_Unwind_Reason_Code reason, 44214152Sed struct _Unwind_Exception* exc); 45214152Sed uintptr_t private_1; 46214152Sed uintptr_t private_2; 47214152Sed}; 48214152Sed 49214152Sedextern const uint8_t* _Unwind_GetLanguageSpecificData(_Unwind_Context_t c); 50214152Sedextern void _Unwind_SetGR(_Unwind_Context_t c, int i, uintptr_t n); 51214152Sedextern void _Unwind_SetIP(_Unwind_Context_t, uintptr_t new_value); 52214152Sedextern uintptr_t _Unwind_GetIP(_Unwind_Context_t context); 53214152Sedextern uintptr_t _Unwind_GetRegionStart(_Unwind_Context_t context); 54214152Sed 55214152Sed 56214152Sed/* 57214152Sed * Pointer encodings documented at: 58214152Sed * http://refspecs.freestandards.org/LSB_1.3.0/gLSB/gLSB/ehframehdr.html 59214152Sed */ 60214152Sed 61214152Sed#define DW_EH_PE_omit 0xff /* no data follows */ 62214152Sed 63214152Sed#define DW_EH_PE_absptr 0x00 64214152Sed#define DW_EH_PE_uleb128 0x01 65214152Sed#define DW_EH_PE_udata2 0x02 66214152Sed#define DW_EH_PE_udata4 0x03 67214152Sed#define DW_EH_PE_udata8 0x04 68214152Sed#define DW_EH_PE_sleb128 0x09 69214152Sed#define DW_EH_PE_sdata2 0x0A 70214152Sed#define DW_EH_PE_sdata4 0x0B 71214152Sed#define DW_EH_PE_sdata8 0x0C 72214152Sed 73214152Sed#define DW_EH_PE_pcrel 0x10 74214152Sed#define DW_EH_PE_textrel 0x20 75214152Sed#define DW_EH_PE_datarel 0x30 76214152Sed#define DW_EH_PE_funcrel 0x40 77214152Sed#define DW_EH_PE_aligned 0x50 78214152Sed#define DW_EH_PE_indirect 0x80 /* gcc extension */ 79214152Sed 80214152Sed 81214152Sed 82214152Sed/* read a uleb128 encoded value and advance pointer */ 83214152Sedstatic uintptr_t readULEB128(const uint8_t** data) 84214152Sed{ 85214152Sed uintptr_t result = 0; 86214152Sed uintptr_t shift = 0; 87214152Sed unsigned char byte; 88214152Sed const uint8_t* p = *data; 89214152Sed do { 90214152Sed byte = *p++; 91214152Sed result |= (byte & 0x7f) << shift; 92214152Sed shift += 7; 93214152Sed } while (byte & 0x80); 94214152Sed *data = p; 95214152Sed return result; 96214152Sed} 97214152Sed 98214152Sed/* read a pointer encoded value and advance pointer */ 99214152Sedstatic uintptr_t readEncodedPointer(const uint8_t** data, uint8_t encoding) 100214152Sed{ 101214152Sed const uint8_t* p = *data; 102214152Sed uintptr_t result = 0; 103214152Sed 104214152Sed if ( encoding == DW_EH_PE_omit ) 105214152Sed return 0; 106214152Sed 107214152Sed /* first get value */ 108214152Sed switch (encoding & 0x0F) { 109214152Sed case DW_EH_PE_absptr: 110214152Sed result = *((uintptr_t*)p); 111214152Sed p += sizeof(uintptr_t); 112214152Sed break; 113214152Sed case DW_EH_PE_uleb128: 114214152Sed result = readULEB128(&p); 115214152Sed break; 116214152Sed case DW_EH_PE_udata2: 117214152Sed result = *((uint16_t*)p); 118214152Sed p += sizeof(uint16_t); 119214152Sed break; 120214152Sed case DW_EH_PE_udata4: 121214152Sed result = *((uint32_t*)p); 122214152Sed p += sizeof(uint32_t); 123214152Sed break; 124214152Sed case DW_EH_PE_udata8: 125214152Sed result = *((uint64_t*)p); 126214152Sed p += sizeof(uint64_t); 127214152Sed break; 128214152Sed case DW_EH_PE_sdata2: 129214152Sed result = *((int16_t*)p); 130214152Sed p += sizeof(int16_t); 131214152Sed break; 132214152Sed case DW_EH_PE_sdata4: 133214152Sed result = *((int32_t*)p); 134214152Sed p += sizeof(int32_t); 135214152Sed break; 136214152Sed case DW_EH_PE_sdata8: 137214152Sed result = *((int64_t*)p); 138214152Sed p += sizeof(int64_t); 139214152Sed break; 140214152Sed case DW_EH_PE_sleb128: 141214152Sed default: 142214152Sed /* not supported */ 143214152Sed compilerrt_abort(); 144214152Sed break; 145214152Sed } 146214152Sed 147214152Sed /* then add relative offset */ 148214152Sed switch ( encoding & 0x70 ) { 149214152Sed case DW_EH_PE_absptr: 150214152Sed /* do nothing */ 151214152Sed break; 152214152Sed case DW_EH_PE_pcrel: 153214152Sed result += (uintptr_t)(*data); 154214152Sed break; 155214152Sed case DW_EH_PE_textrel: 156214152Sed case DW_EH_PE_datarel: 157214152Sed case DW_EH_PE_funcrel: 158214152Sed case DW_EH_PE_aligned: 159214152Sed default: 160214152Sed /* not supported */ 161214152Sed compilerrt_abort(); 162214152Sed break; 163214152Sed } 164214152Sed 165214152Sed /* then apply indirection */ 166214152Sed if (encoding & DW_EH_PE_indirect) { 167214152Sed result = *((uintptr_t*)result); 168214152Sed } 169214152Sed 170214152Sed *data = p; 171214152Sed return result; 172214152Sed} 173214152Sed 174214152Sed 175214152Sed/* 176214152Sed * The C compiler makes references to __gcc_personality_v0 in 177214152Sed * the dwarf unwind information for translation units that use 178214152Sed * __attribute__((cleanup(xx))) on local variables. 179214152Sed * This personality routine is called by the system unwinder 180214152Sed * on each frame as the stack is unwound during a C++ exception 181214152Sed * throw through a C function compiled with -fexceptions. 182214152Sed */ 183214152Sed#if __arm__ 184214152Sed// the setjump-longjump based exceptions personality routine has a different name 185214152Sed_Unwind_Reason_Code __gcc_personality_sj0(int version, _Unwind_Action actions, 186214152Sed uint64_t exceptionClass, struct _Unwind_Exception* exceptionObject, 187214152Sed _Unwind_Context_t context) 188214152Sed#else 189214152Sed_Unwind_Reason_Code __gcc_personality_v0(int version, _Unwind_Action actions, 190214152Sed uint64_t exceptionClass, struct _Unwind_Exception* exceptionObject, 191214152Sed _Unwind_Context_t context) 192214152Sed#endif 193214152Sed{ 194214152Sed /* Since C does not have catch clauses, there is nothing to do during */ 195214152Sed /* phase 1 (the search phase). */ 196214152Sed if ( actions & _UA_SEARCH_PHASE ) 197214152Sed return _URC_CONTINUE_UNWIND; 198214152Sed 199214152Sed /* There is nothing to do if there is no LSDA for this frame. */ 200214152Sed const uint8_t* lsda = _Unwind_GetLanguageSpecificData(context); 201229135Sed if ( lsda == (uint8_t*) 0 ) 202214152Sed return _URC_CONTINUE_UNWIND; 203214152Sed 204214152Sed uintptr_t pc = _Unwind_GetIP(context)-1; 205214152Sed uintptr_t funcStart = _Unwind_GetRegionStart(context); 206214152Sed uintptr_t pcOffset = pc - funcStart; 207214152Sed 208214152Sed /* Parse LSDA header. */ 209214152Sed uint8_t lpStartEncoding = *lsda++; 210214152Sed if (lpStartEncoding != DW_EH_PE_omit) { 211214152Sed readEncodedPointer(&lsda, lpStartEncoding); 212214152Sed } 213214152Sed uint8_t ttypeEncoding = *lsda++; 214214152Sed if (ttypeEncoding != DW_EH_PE_omit) { 215214152Sed readULEB128(&lsda); 216214152Sed } 217214152Sed /* Walk call-site table looking for range that includes current PC. */ 218214152Sed uint8_t callSiteEncoding = *lsda++; 219214152Sed uint32_t callSiteTableLength = readULEB128(&lsda); 220214152Sed const uint8_t* callSiteTableStart = lsda; 221214152Sed const uint8_t* callSiteTableEnd = callSiteTableStart + callSiteTableLength; 222214152Sed const uint8_t* p=callSiteTableStart; 223214152Sed while (p < callSiteTableEnd) { 224214152Sed uintptr_t start = readEncodedPointer(&p, callSiteEncoding); 225214152Sed uintptr_t length = readEncodedPointer(&p, callSiteEncoding); 226214152Sed uintptr_t landingPad = readEncodedPointer(&p, callSiteEncoding); 227214152Sed readULEB128(&p); /* action value not used for C code */ 228214152Sed if ( landingPad == 0 ) 229214152Sed continue; /* no landing pad for this entry */ 230214152Sed if ( (start <= pcOffset) && (pcOffset < (start+length)) ) { 231214152Sed /* Found landing pad for the PC. 232214152Sed * Set Instruction Pointer to so we re-enter function 233214152Sed * at landing pad. The landing pad is created by the compiler 234214152Sed * to take two parameters in registers. 235214152Sed */ 236214152Sed _Unwind_SetGR(context, __builtin_eh_return_data_regno(0), 237214152Sed (uintptr_t)exceptionObject); 238214152Sed _Unwind_SetGR(context, __builtin_eh_return_data_regno(1), 0); 239214152Sed _Unwind_SetIP(context, funcStart+landingPad); 240214152Sed return _URC_INSTALL_CONTEXT; 241214152Sed } 242214152Sed } 243214152Sed 244214152Sed /* No landing pad found, continue unwinding. */ 245214152Sed return _URC_CONTINUE_UNWIND; 246214152Sed} 247214152Sed 248