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