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