10b57cec5SDimitry Andric //===-- gcc_personality_v0.c - Implement __gcc_personality_v0 -------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric 90b57cec5SDimitry Andric #include "int_lib.h" 10fe6060f1SDimitry Andric #include <stddef.h> 110b57cec5SDimitry Andric 120b57cec5SDimitry Andric #include <unwind.h> 130b57cec5SDimitry Andric /* 140b57cec5SDimitry Andric * XXX On FreeBSD, this file is compiled into three libraries: 150b57cec5SDimitry Andric * - libcompiler_rt 160b57cec5SDimitry Andric * - libgcc_eh 170b57cec5SDimitry Andric * - libgcc_s 180b57cec5SDimitry Andric * 190b57cec5SDimitry Andric * In the former, the include path points to the contrib/libcxxrt/unwind-arm.h 200b57cec5SDimitry Andric * copy of unwind.h. In the latter, the include path points to the 210b57cec5SDimitry Andric * contrib/libunwind/include/unwind.h header (LLVM libunwind). 220b57cec5SDimitry Andric * 230b57cec5SDimitry Andric * Neither (seemingly redundant) variant of unwind.h needs the redefinitions 240b57cec5SDimitry Andric * provided in the "helpful" header below, and libcxxrt's unwind-arm.h provides 250b57cec5SDimitry Andric * *no* useful distinguishing macros, so just forcibly disable the helper 260b57cec5SDimitry Andric * header on FreeBSD. 270b57cec5SDimitry Andric */ 280b57cec5SDimitry Andric #if defined(__arm__) && !defined(__ARM_DWARF_EH__) && \ 290b57cec5SDimitry Andric !defined(__USING_SJLJ_EXCEPTIONS__) && !defined(__FreeBSD__) 300b57cec5SDimitry Andric // When building with older compilers (e.g. clang <3.9), it is possible that we 310b57cec5SDimitry Andric // have a version of unwind.h which does not provide the EHABI declarations 320b57cec5SDimitry Andric // which are quired for the C personality to conform to the specification. In 330b57cec5SDimitry Andric // order to provide forward compatibility for such compilers, we re-declare the 340b57cec5SDimitry Andric // necessary interfaces in the helper to permit a standalone compilation of the 350b57cec5SDimitry Andric // builtins (which contains the C unwinding personality for historical reasons). 360b57cec5SDimitry Andric #include "unwind-ehabi-helpers.h" 370b57cec5SDimitry Andric #endif 380b57cec5SDimitry Andric 39fe6060f1SDimitry Andric #if defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__) 40fe6060f1SDimitry Andric #include <windows.h> 41fe6060f1SDimitry Andric #include <winnt.h> 42fe6060f1SDimitry Andric 43fe6060f1SDimitry Andric EXCEPTION_DISPOSITION _GCC_specific_handler(PEXCEPTION_RECORD, void *, PCONTEXT, 44fe6060f1SDimitry Andric PDISPATCHER_CONTEXT, 45fe6060f1SDimitry Andric _Unwind_Personality_Fn); 46fe6060f1SDimitry Andric #endif 47fe6060f1SDimitry Andric 480b57cec5SDimitry Andric // Pointer encodings documented at: 490b57cec5SDimitry Andric // http://refspecs.freestandards.org/LSB_1.3.0/gLSB/gLSB/ehframehdr.html 500b57cec5SDimitry Andric 510b57cec5SDimitry Andric #define DW_EH_PE_omit 0xff // no data follows 520b57cec5SDimitry Andric 530b57cec5SDimitry Andric #define DW_EH_PE_absptr 0x00 540b57cec5SDimitry Andric #define DW_EH_PE_uleb128 0x01 550b57cec5SDimitry Andric #define DW_EH_PE_udata2 0x02 560b57cec5SDimitry Andric #define DW_EH_PE_udata4 0x03 570b57cec5SDimitry Andric #define DW_EH_PE_udata8 0x04 580b57cec5SDimitry Andric #define DW_EH_PE_sleb128 0x09 590b57cec5SDimitry Andric #define DW_EH_PE_sdata2 0x0A 600b57cec5SDimitry Andric #define DW_EH_PE_sdata4 0x0B 610b57cec5SDimitry Andric #define DW_EH_PE_sdata8 0x0C 620b57cec5SDimitry Andric 630b57cec5SDimitry Andric #define DW_EH_PE_pcrel 0x10 640b57cec5SDimitry Andric #define DW_EH_PE_textrel 0x20 650b57cec5SDimitry Andric #define DW_EH_PE_datarel 0x30 660b57cec5SDimitry Andric #define DW_EH_PE_funcrel 0x40 670b57cec5SDimitry Andric #define DW_EH_PE_aligned 0x50 680b57cec5SDimitry Andric #define DW_EH_PE_indirect 0x80 // gcc extension 690b57cec5SDimitry Andric 700b57cec5SDimitry Andric // read a uleb128 encoded value and advance pointer 71fe6060f1SDimitry Andric static size_t readULEB128(const uint8_t **data) { 72fe6060f1SDimitry Andric size_t result = 0; 73fe6060f1SDimitry Andric size_t shift = 0; 740b57cec5SDimitry Andric unsigned char byte; 750b57cec5SDimitry Andric const uint8_t *p = *data; 760b57cec5SDimitry Andric do { 770b57cec5SDimitry Andric byte = *p++; 780b57cec5SDimitry Andric result |= (byte & 0x7f) << shift; 790b57cec5SDimitry Andric shift += 7; 800b57cec5SDimitry Andric } while (byte & 0x80); 810b57cec5SDimitry Andric *data = p; 820b57cec5SDimitry Andric return result; 830b57cec5SDimitry Andric } 840b57cec5SDimitry Andric 850b57cec5SDimitry Andric // read a pointer encoded value and advance pointer 860b57cec5SDimitry Andric static uintptr_t readEncodedPointer(const uint8_t **data, uint8_t encoding) { 870b57cec5SDimitry Andric const uint8_t *p = *data; 880b57cec5SDimitry Andric uintptr_t result = 0; 890b57cec5SDimitry Andric 900b57cec5SDimitry Andric if (encoding == DW_EH_PE_omit) 910b57cec5SDimitry Andric return 0; 920b57cec5SDimitry Andric 930b57cec5SDimitry Andric // first get value 940b57cec5SDimitry Andric switch (encoding & 0x0F) { 950b57cec5SDimitry Andric case DW_EH_PE_absptr: 960b57cec5SDimitry Andric result = *((const uintptr_t *)p); 970b57cec5SDimitry Andric p += sizeof(uintptr_t); 980b57cec5SDimitry Andric break; 990b57cec5SDimitry Andric case DW_EH_PE_uleb128: 1000b57cec5SDimitry Andric result = readULEB128(&p); 1010b57cec5SDimitry Andric break; 1020b57cec5SDimitry Andric case DW_EH_PE_udata2: 1030b57cec5SDimitry Andric result = *((const uint16_t *)p); 1040b57cec5SDimitry Andric p += sizeof(uint16_t); 1050b57cec5SDimitry Andric break; 1060b57cec5SDimitry Andric case DW_EH_PE_udata4: 1070b57cec5SDimitry Andric result = *((const uint32_t *)p); 1080b57cec5SDimitry Andric p += sizeof(uint32_t); 1090b57cec5SDimitry Andric break; 1100b57cec5SDimitry Andric case DW_EH_PE_udata8: 1110b57cec5SDimitry Andric result = *((const uint64_t *)p); 1120b57cec5SDimitry Andric p += sizeof(uint64_t); 1130b57cec5SDimitry Andric break; 1140b57cec5SDimitry Andric case DW_EH_PE_sdata2: 1150b57cec5SDimitry Andric result = *((const int16_t *)p); 1160b57cec5SDimitry Andric p += sizeof(int16_t); 1170b57cec5SDimitry Andric break; 1180b57cec5SDimitry Andric case DW_EH_PE_sdata4: 1190b57cec5SDimitry Andric result = *((const int32_t *)p); 1200b57cec5SDimitry Andric p += sizeof(int32_t); 1210b57cec5SDimitry Andric break; 1220b57cec5SDimitry Andric case DW_EH_PE_sdata8: 1230b57cec5SDimitry Andric result = *((const int64_t *)p); 1240b57cec5SDimitry Andric p += sizeof(int64_t); 1250b57cec5SDimitry Andric break; 1260b57cec5SDimitry Andric case DW_EH_PE_sleb128: 1270b57cec5SDimitry Andric default: 1280b57cec5SDimitry Andric // not supported 1290b57cec5SDimitry Andric compilerrt_abort(); 1300b57cec5SDimitry Andric break; 1310b57cec5SDimitry Andric } 1320b57cec5SDimitry Andric 1330b57cec5SDimitry Andric // then add relative offset 1340b57cec5SDimitry Andric switch (encoding & 0x70) { 1350b57cec5SDimitry Andric case DW_EH_PE_absptr: 1360b57cec5SDimitry Andric // do nothing 1370b57cec5SDimitry Andric break; 1380b57cec5SDimitry Andric case DW_EH_PE_pcrel: 1390b57cec5SDimitry Andric result += (uintptr_t)(*data); 1400b57cec5SDimitry Andric break; 1410b57cec5SDimitry Andric case DW_EH_PE_textrel: 1420b57cec5SDimitry Andric case DW_EH_PE_datarel: 1430b57cec5SDimitry Andric case DW_EH_PE_funcrel: 1440b57cec5SDimitry Andric case DW_EH_PE_aligned: 1450b57cec5SDimitry Andric default: 1460b57cec5SDimitry Andric // not supported 1470b57cec5SDimitry Andric compilerrt_abort(); 1480b57cec5SDimitry Andric break; 1490b57cec5SDimitry Andric } 1500b57cec5SDimitry Andric 1510b57cec5SDimitry Andric // then apply indirection 1520b57cec5SDimitry Andric if (encoding & DW_EH_PE_indirect) { 1530b57cec5SDimitry Andric result = *((const uintptr_t *)result); 1540b57cec5SDimitry Andric } 1550b57cec5SDimitry Andric 1560b57cec5SDimitry Andric *data = p; 1570b57cec5SDimitry Andric return result; 1580b57cec5SDimitry Andric } 1590b57cec5SDimitry Andric 1600b57cec5SDimitry Andric #if defined(__arm__) && !defined(__USING_SJLJ_EXCEPTIONS__) && \ 1610b57cec5SDimitry Andric !defined(__ARM_DWARF_EH__) 1620b57cec5SDimitry Andric #define USING_ARM_EHABI 1 1630b57cec5SDimitry Andric _Unwind_Reason_Code __gnu_unwind_frame(struct _Unwind_Exception *, 1640b57cec5SDimitry Andric struct _Unwind_Context *); 1650b57cec5SDimitry Andric #endif 1660b57cec5SDimitry Andric 1670b57cec5SDimitry Andric static inline _Unwind_Reason_Code 1680b57cec5SDimitry Andric continueUnwind(struct _Unwind_Exception *exceptionObject, 1690b57cec5SDimitry Andric struct _Unwind_Context *context) { 1700b57cec5SDimitry Andric #if USING_ARM_EHABI 1710b57cec5SDimitry Andric // On ARM EHABI the personality routine is responsible for actually 1720b57cec5SDimitry Andric // unwinding a single stack frame before returning (ARM EHABI Sec. 6.1). 1730b57cec5SDimitry Andric if (__gnu_unwind_frame(exceptionObject, context) != _URC_OK) 1740b57cec5SDimitry Andric return _URC_FAILURE; 1750b57cec5SDimitry Andric #endif 1760b57cec5SDimitry Andric return _URC_CONTINUE_UNWIND; 1770b57cec5SDimitry Andric } 1780b57cec5SDimitry Andric 1790b57cec5SDimitry Andric // The C compiler makes references to __gcc_personality_v0 in 1800b57cec5SDimitry Andric // the dwarf unwind information for translation units that use 1810b57cec5SDimitry Andric // __attribute__((cleanup(xx))) on local variables. 1820b57cec5SDimitry Andric // This personality routine is called by the system unwinder 1830b57cec5SDimitry Andric // on each frame as the stack is unwound during a C++ exception 1840b57cec5SDimitry Andric // throw through a C function compiled with -fexceptions. 1850b57cec5SDimitry Andric #if __USING_SJLJ_EXCEPTIONS__ 1860b57cec5SDimitry Andric // the setjump-longjump based exceptions personality routine has a 1870b57cec5SDimitry Andric // different name 1880b57cec5SDimitry Andric COMPILER_RT_ABI _Unwind_Reason_Code __gcc_personality_sj0( 1890b57cec5SDimitry Andric int version, _Unwind_Action actions, uint64_t exceptionClass, 1900b57cec5SDimitry Andric struct _Unwind_Exception *exceptionObject, struct _Unwind_Context *context) 1910b57cec5SDimitry Andric #elif USING_ARM_EHABI 1920b57cec5SDimitry Andric // The ARM EHABI personality routine has a different signature. 1930b57cec5SDimitry Andric COMPILER_RT_ABI _Unwind_Reason_Code __gcc_personality_v0( 1940b57cec5SDimitry Andric _Unwind_State state, struct _Unwind_Exception *exceptionObject, 1950b57cec5SDimitry Andric struct _Unwind_Context *context) 196fe6060f1SDimitry Andric #elif defined(__SEH__) 197fe6060f1SDimitry Andric static _Unwind_Reason_Code __gcc_personality_imp( 198fe6060f1SDimitry Andric int version, _Unwind_Action actions, uint64_t exceptionClass, 199fe6060f1SDimitry Andric struct _Unwind_Exception *exceptionObject, struct _Unwind_Context *context) 2000b57cec5SDimitry Andric #else 2010b57cec5SDimitry Andric COMPILER_RT_ABI _Unwind_Reason_Code __gcc_personality_v0( 2020b57cec5SDimitry Andric int version, _Unwind_Action actions, uint64_t exceptionClass, 2030b57cec5SDimitry Andric struct _Unwind_Exception *exceptionObject, struct _Unwind_Context *context) 2040b57cec5SDimitry Andric #endif 2050b57cec5SDimitry Andric { 2060b57cec5SDimitry Andric // Since C does not have catch clauses, there is nothing to do during 2070b57cec5SDimitry Andric // phase 1 (the search phase). 2080b57cec5SDimitry Andric #if USING_ARM_EHABI 2090b57cec5SDimitry Andric // After resuming from a cleanup we should also continue on to the next 2100b57cec5SDimitry Andric // frame straight away. 2110b57cec5SDimitry Andric if ((state & _US_ACTION_MASK) != _US_UNWIND_FRAME_STARTING) 2120b57cec5SDimitry Andric #else 2130b57cec5SDimitry Andric if (actions & _UA_SEARCH_PHASE) 2140b57cec5SDimitry Andric #endif 2150b57cec5SDimitry Andric return continueUnwind(exceptionObject, context); 2160b57cec5SDimitry Andric 2170b57cec5SDimitry Andric // There is nothing to do if there is no LSDA for this frame. 2180b57cec5SDimitry Andric const uint8_t *lsda = (uint8_t *)_Unwind_GetLanguageSpecificData(context); 2190b57cec5SDimitry Andric if (lsda == (uint8_t *)0) 2200b57cec5SDimitry Andric return continueUnwind(exceptionObject, context); 2210b57cec5SDimitry Andric 2220b57cec5SDimitry Andric uintptr_t pc = (uintptr_t)_Unwind_GetIP(context) - 1; 2230b57cec5SDimitry Andric uintptr_t funcStart = (uintptr_t)_Unwind_GetRegionStart(context); 2240b57cec5SDimitry Andric uintptr_t pcOffset = pc - funcStart; 2250b57cec5SDimitry Andric 2260b57cec5SDimitry Andric // Parse LSDA header. 2270b57cec5SDimitry Andric uint8_t lpStartEncoding = *lsda++; 2280b57cec5SDimitry Andric if (lpStartEncoding != DW_EH_PE_omit) { 2290b57cec5SDimitry Andric readEncodedPointer(&lsda, lpStartEncoding); 2300b57cec5SDimitry Andric } 2310b57cec5SDimitry Andric uint8_t ttypeEncoding = *lsda++; 2320b57cec5SDimitry Andric if (ttypeEncoding != DW_EH_PE_omit) { 2330b57cec5SDimitry Andric readULEB128(&lsda); 2340b57cec5SDimitry Andric } 2350b57cec5SDimitry Andric // Walk call-site table looking for range that includes current PC. 2360b57cec5SDimitry Andric uint8_t callSiteEncoding = *lsda++; 2370b57cec5SDimitry Andric uint32_t callSiteTableLength = readULEB128(&lsda); 2380b57cec5SDimitry Andric const uint8_t *callSiteTableStart = lsda; 2390b57cec5SDimitry Andric const uint8_t *callSiteTableEnd = callSiteTableStart + callSiteTableLength; 2400b57cec5SDimitry Andric const uint8_t *p = callSiteTableStart; 2410b57cec5SDimitry Andric while (p < callSiteTableEnd) { 2420b57cec5SDimitry Andric uintptr_t start = readEncodedPointer(&p, callSiteEncoding); 243fe6060f1SDimitry Andric size_t length = readEncodedPointer(&p, callSiteEncoding); 244fe6060f1SDimitry Andric size_t landingPad = readEncodedPointer(&p, callSiteEncoding); 2450b57cec5SDimitry Andric readULEB128(&p); // action value not used for C code 2460b57cec5SDimitry Andric if (landingPad == 0) 2470b57cec5SDimitry Andric continue; // no landing pad for this entry 2480b57cec5SDimitry Andric if ((start <= pcOffset) && (pcOffset < (start + length))) { 2490b57cec5SDimitry Andric // Found landing pad for the PC. 2500b57cec5SDimitry Andric // Set Instruction Pointer to so we re-enter function 2510b57cec5SDimitry Andric // at landing pad. The landing pad is created by the compiler 2520b57cec5SDimitry Andric // to take two parameters in registers. 2530b57cec5SDimitry Andric _Unwind_SetGR(context, __builtin_eh_return_data_regno(0), 2540b57cec5SDimitry Andric (uintptr_t)exceptionObject); 2550b57cec5SDimitry Andric _Unwind_SetGR(context, __builtin_eh_return_data_regno(1), 0); 2560b57cec5SDimitry Andric _Unwind_SetIP(context, (funcStart + landingPad)); 2570b57cec5SDimitry Andric return _URC_INSTALL_CONTEXT; 2580b57cec5SDimitry Andric } 2590b57cec5SDimitry Andric } 2600b57cec5SDimitry Andric 2610b57cec5SDimitry Andric // No landing pad found, continue unwinding. 2620b57cec5SDimitry Andric return continueUnwind(exceptionObject, context); 2630b57cec5SDimitry Andric } 264fe6060f1SDimitry Andric 265fe6060f1SDimitry Andric #if defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__) 266fe6060f1SDimitry Andric COMPILER_RT_ABI EXCEPTION_DISPOSITION 267fe6060f1SDimitry Andric __gcc_personality_seh0(PEXCEPTION_RECORD ms_exc, void *this_frame, 268fe6060f1SDimitry Andric PCONTEXT ms_orig_context, PDISPATCHER_CONTEXT ms_disp) { 269fe6060f1SDimitry Andric return _GCC_specific_handler(ms_exc, this_frame, ms_orig_context, ms_disp, 270fe6060f1SDimitry Andric __gcc_personality_imp); 271fe6060f1SDimitry Andric } 272fe6060f1SDimitry Andric #endif 273