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