10b57cec5SDimitry Andric //===--------------------------- Unwind-seh.cpp ---------------------------===// 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 // Implements SEH-based Itanium C++ exceptions. 100b57cec5SDimitry Andric // 110b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 120b57cec5SDimitry Andric 130b57cec5SDimitry Andric #include "config.h" 140b57cec5SDimitry Andric 150b57cec5SDimitry Andric #if defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) 160b57cec5SDimitry Andric 170b57cec5SDimitry Andric #include <unwind.h> 180b57cec5SDimitry Andric 190b57cec5SDimitry Andric #include <stdint.h> 200b57cec5SDimitry Andric #include <stdbool.h> 210b57cec5SDimitry Andric #include <stdlib.h> 220b57cec5SDimitry Andric 230b57cec5SDimitry Andric #include <windef.h> 240b57cec5SDimitry Andric #include <excpt.h> 250b57cec5SDimitry Andric #include <winnt.h> 260b57cec5SDimitry Andric #include <ntstatus.h> 270b57cec5SDimitry Andric 280b57cec5SDimitry Andric #include "libunwind_ext.h" 290b57cec5SDimitry Andric #include "UnwindCursor.hpp" 300b57cec5SDimitry Andric 310b57cec5SDimitry Andric using namespace libunwind; 320b57cec5SDimitry Andric 330b57cec5SDimitry Andric #define STATUS_USER_DEFINED (1u << 29) 340b57cec5SDimitry Andric 350b57cec5SDimitry Andric #define STATUS_GCC_MAGIC (('G' << 16) | ('C' << 8) | 'C') 360b57cec5SDimitry Andric 370b57cec5SDimitry Andric #define MAKE_CUSTOM_STATUS(s, c) \ 380b57cec5SDimitry Andric ((NTSTATUS)(((s) << 30) | STATUS_USER_DEFINED | (c))) 390b57cec5SDimitry Andric #define MAKE_GCC_EXCEPTION(c) \ 400b57cec5SDimitry Andric MAKE_CUSTOM_STATUS(STATUS_SEVERITY_SUCCESS, STATUS_GCC_MAGIC | ((c) << 24)) 410b57cec5SDimitry Andric 420b57cec5SDimitry Andric /// SEH exception raised by libunwind when the program calls 430b57cec5SDimitry Andric /// \c _Unwind_RaiseException. 440b57cec5SDimitry Andric #define STATUS_GCC_THROW MAKE_GCC_EXCEPTION(0) // 0x20474343 450b57cec5SDimitry Andric /// SEH exception raised by libunwind to initiate phase 2 of exception 460b57cec5SDimitry Andric /// handling. 470b57cec5SDimitry Andric #define STATUS_GCC_UNWIND MAKE_GCC_EXCEPTION(1) // 0x21474343 480b57cec5SDimitry Andric 490b57cec5SDimitry Andric static int __unw_init_seh(unw_cursor_t *cursor, CONTEXT *ctx); 500b57cec5SDimitry Andric static DISPATCHER_CONTEXT *__unw_seh_get_disp_ctx(unw_cursor_t *cursor); 510b57cec5SDimitry Andric static void __unw_seh_set_disp_ctx(unw_cursor_t *cursor, 520b57cec5SDimitry Andric DISPATCHER_CONTEXT *disp); 530b57cec5SDimitry Andric 540b57cec5SDimitry Andric /// Common implementation of SEH-style handler functions used by Itanium- 550b57cec5SDimitry Andric /// style frames. Depending on how and why it was called, it may do one of: 560b57cec5SDimitry Andric /// a) Delegate to the given Itanium-style personality function; or 570b57cec5SDimitry Andric /// b) Initiate a collided unwind to halt unwinding. 580b57cec5SDimitry Andric _LIBUNWIND_EXPORT EXCEPTION_DISPOSITION 590b57cec5SDimitry Andric _GCC_specific_handler(PEXCEPTION_RECORD ms_exc, PVOID frame, PCONTEXT ms_ctx, 605ffd83dbSDimitry Andric DISPATCHER_CONTEXT *disp, _Unwind_Personality_Fn pers) { 610b57cec5SDimitry Andric unw_cursor_t cursor; 620b57cec5SDimitry Andric _Unwind_Exception *exc; 630b57cec5SDimitry Andric _Unwind_Action action; 640b57cec5SDimitry Andric struct _Unwind_Context *ctx = nullptr; 650b57cec5SDimitry Andric _Unwind_Reason_Code urc; 660b57cec5SDimitry Andric uintptr_t retval, target; 670b57cec5SDimitry Andric bool ours = false; 680b57cec5SDimitry Andric 690b57cec5SDimitry Andric _LIBUNWIND_TRACE_UNWINDING("_GCC_specific_handler(%#010lx(%lx), %p)", 700b57cec5SDimitry Andric ms_exc->ExceptionCode, ms_exc->ExceptionFlags, 710b57cec5SDimitry Andric (void *)frame); 720b57cec5SDimitry Andric if (ms_exc->ExceptionCode == STATUS_GCC_UNWIND) { 730b57cec5SDimitry Andric if (IS_TARGET_UNWIND(ms_exc->ExceptionFlags)) { 740b57cec5SDimitry Andric // Set up the upper return value (the lower one and the target PC 750b57cec5SDimitry Andric // were set in the call to RtlUnwindEx()) for the landing pad. 760b57cec5SDimitry Andric #ifdef __x86_64__ 770b57cec5SDimitry Andric disp->ContextRecord->Rdx = ms_exc->ExceptionInformation[3]; 780b57cec5SDimitry Andric #elif defined(__arm__) 790b57cec5SDimitry Andric disp->ContextRecord->R1 = ms_exc->ExceptionInformation[3]; 800b57cec5SDimitry Andric #elif defined(__aarch64__) 810b57cec5SDimitry Andric disp->ContextRecord->X1 = ms_exc->ExceptionInformation[3]; 820b57cec5SDimitry Andric #endif 830b57cec5SDimitry Andric } 840b57cec5SDimitry Andric // This is the collided unwind to the landing pad. Nothing to do. 850b57cec5SDimitry Andric return ExceptionContinueSearch; 860b57cec5SDimitry Andric } 870b57cec5SDimitry Andric 880b57cec5SDimitry Andric if (ms_exc->ExceptionCode == STATUS_GCC_THROW) { 890b57cec5SDimitry Andric // This is (probably) a libunwind-controlled exception/unwind. Recover the 900b57cec5SDimitry Andric // parameters which we set below, and pass them to the personality function. 910b57cec5SDimitry Andric ours = true; 920b57cec5SDimitry Andric exc = (_Unwind_Exception *)ms_exc->ExceptionInformation[0]; 930b57cec5SDimitry Andric if (!IS_UNWINDING(ms_exc->ExceptionFlags) && ms_exc->NumberParameters > 1) { 940b57cec5SDimitry Andric ctx = (struct _Unwind_Context *)ms_exc->ExceptionInformation[1]; 950b57cec5SDimitry Andric action = (_Unwind_Action)ms_exc->ExceptionInformation[2]; 960b57cec5SDimitry Andric } 970b57cec5SDimitry Andric } else { 980b57cec5SDimitry Andric // Foreign exception. 99*e8d8bef9SDimitry Andric // We can't interact with them (we don't know the original target frame 100*e8d8bef9SDimitry Andric // that we should pass on to RtlUnwindEx in _Unwind_Resume), so just 101*e8d8bef9SDimitry Andric // pass without calling our destructors here. 102*e8d8bef9SDimitry Andric return ExceptionContinueSearch; 1030b57cec5SDimitry Andric } 1040b57cec5SDimitry Andric if (!ctx) { 1050b57cec5SDimitry Andric __unw_init_seh(&cursor, disp->ContextRecord); 1060b57cec5SDimitry Andric __unw_seh_set_disp_ctx(&cursor, disp); 1070b57cec5SDimitry Andric __unw_set_reg(&cursor, UNW_REG_IP, disp->ControlPc - 1); 1080b57cec5SDimitry Andric ctx = (struct _Unwind_Context *)&cursor; 1090b57cec5SDimitry Andric 1100b57cec5SDimitry Andric if (!IS_UNWINDING(ms_exc->ExceptionFlags)) { 1110b57cec5SDimitry Andric if (ours && ms_exc->NumberParameters > 1) 1120b57cec5SDimitry Andric action = (_Unwind_Action)(_UA_CLEANUP_PHASE | _UA_FORCE_UNWIND); 1130b57cec5SDimitry Andric else 1140b57cec5SDimitry Andric action = _UA_SEARCH_PHASE; 1150b57cec5SDimitry Andric } else { 1160b57cec5SDimitry Andric if (ours && ms_exc->ExceptionInformation[1] == (ULONG_PTR)frame) 1170b57cec5SDimitry Andric action = (_Unwind_Action)(_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME); 1180b57cec5SDimitry Andric else 1190b57cec5SDimitry Andric action = _UA_CLEANUP_PHASE; 1200b57cec5SDimitry Andric } 1210b57cec5SDimitry Andric } 1220b57cec5SDimitry Andric 1230b57cec5SDimitry Andric _LIBUNWIND_TRACE_UNWINDING("_GCC_specific_handler() calling personality " 1240b57cec5SDimitry Andric "function %p(1, %d, %llx, %p, %p)", 1250b57cec5SDimitry Andric (void *)pers, action, exc->exception_class, 1260b57cec5SDimitry Andric (void *)exc, (void *)ctx); 1270b57cec5SDimitry Andric urc = pers(1, action, exc->exception_class, exc, ctx); 1280b57cec5SDimitry Andric _LIBUNWIND_TRACE_UNWINDING("_GCC_specific_handler() personality returned %d", urc); 1290b57cec5SDimitry Andric switch (urc) { 1300b57cec5SDimitry Andric case _URC_CONTINUE_UNWIND: 1310b57cec5SDimitry Andric // If we're in phase 2, and the personality routine said to continue 1320b57cec5SDimitry Andric // at the target frame, we're in real trouble. 1330b57cec5SDimitry Andric if (action & _UA_HANDLER_FRAME) 1340b57cec5SDimitry Andric _LIBUNWIND_ABORT("Personality continued unwind at the target frame!"); 1350b57cec5SDimitry Andric return ExceptionContinueSearch; 1360b57cec5SDimitry Andric case _URC_HANDLER_FOUND: 1370b57cec5SDimitry Andric // If we were called by __libunwind_seh_personality(), indicate that 1380b57cec5SDimitry Andric // a handler was found; otherwise, initiate phase 2 by unwinding. 1390b57cec5SDimitry Andric if (ours && ms_exc->NumberParameters > 1) 1400b57cec5SDimitry Andric return 4 /* ExecptionExecuteHandler in mingw */; 1410b57cec5SDimitry Andric // This should never happen in phase 2. 1420b57cec5SDimitry Andric if (IS_UNWINDING(ms_exc->ExceptionFlags)) 1430b57cec5SDimitry Andric _LIBUNWIND_ABORT("Personality indicated exception handler in phase 2!"); 1440b57cec5SDimitry Andric exc->private_[1] = (ULONG_PTR)frame; 1450b57cec5SDimitry Andric if (ours) { 1460b57cec5SDimitry Andric ms_exc->NumberParameters = 4; 1470b57cec5SDimitry Andric ms_exc->ExceptionInformation[1] = (ULONG_PTR)frame; 1480b57cec5SDimitry Andric } 1490b57cec5SDimitry Andric // FIXME: Indicate target frame in foreign case! 1500b57cec5SDimitry Andric // phase 2: the clean up phase 1510b57cec5SDimitry Andric RtlUnwindEx(frame, (PVOID)disp->ControlPc, ms_exc, exc, ms_ctx, disp->HistoryTable); 1520b57cec5SDimitry Andric _LIBUNWIND_ABORT("RtlUnwindEx() failed"); 1530b57cec5SDimitry Andric case _URC_INSTALL_CONTEXT: { 1540b57cec5SDimitry Andric // If we were called by __libunwind_seh_personality(), indicate that 1550b57cec5SDimitry Andric // a handler was found; otherwise, it's time to initiate a collided 1560b57cec5SDimitry Andric // unwind to the target. 1570b57cec5SDimitry Andric if (ours && !IS_UNWINDING(ms_exc->ExceptionFlags) && ms_exc->NumberParameters > 1) 1580b57cec5SDimitry Andric return 4 /* ExecptionExecuteHandler in mingw */; 1590b57cec5SDimitry Andric // This should never happen in phase 1. 1600b57cec5SDimitry Andric if (!IS_UNWINDING(ms_exc->ExceptionFlags)) 1610b57cec5SDimitry Andric _LIBUNWIND_ABORT("Personality installed context during phase 1!"); 1620b57cec5SDimitry Andric #ifdef __x86_64__ 1630b57cec5SDimitry Andric exc->private_[2] = disp->TargetIp; 1640b57cec5SDimitry Andric __unw_get_reg(&cursor, UNW_X86_64_RAX, &retval); 1650b57cec5SDimitry Andric __unw_get_reg(&cursor, UNW_X86_64_RDX, &exc->private_[3]); 1660b57cec5SDimitry Andric #elif defined(__arm__) 1670b57cec5SDimitry Andric exc->private_[2] = disp->TargetPc; 1680b57cec5SDimitry Andric __unw_get_reg(&cursor, UNW_ARM_R0, &retval); 1690b57cec5SDimitry Andric __unw_get_reg(&cursor, UNW_ARM_R1, &exc->private_[3]); 1700b57cec5SDimitry Andric #elif defined(__aarch64__) 1710b57cec5SDimitry Andric exc->private_[2] = disp->TargetPc; 1720b57cec5SDimitry Andric __unw_get_reg(&cursor, UNW_ARM64_X0, &retval); 1730b57cec5SDimitry Andric __unw_get_reg(&cursor, UNW_ARM64_X1, &exc->private_[3]); 1740b57cec5SDimitry Andric #endif 1750b57cec5SDimitry Andric __unw_get_reg(&cursor, UNW_REG_IP, &target); 1760b57cec5SDimitry Andric ms_exc->ExceptionCode = STATUS_GCC_UNWIND; 1770b57cec5SDimitry Andric #ifdef __x86_64__ 1780b57cec5SDimitry Andric ms_exc->ExceptionInformation[2] = disp->TargetIp; 1790b57cec5SDimitry Andric #elif defined(__arm__) || defined(__aarch64__) 1800b57cec5SDimitry Andric ms_exc->ExceptionInformation[2] = disp->TargetPc; 1810b57cec5SDimitry Andric #endif 1820b57cec5SDimitry Andric ms_exc->ExceptionInformation[3] = exc->private_[3]; 1830b57cec5SDimitry Andric // Give NTRTL some scratch space to keep track of the collided unwind. 1840b57cec5SDimitry Andric // Don't use the one that was passed in; we don't want to overwrite the 1850b57cec5SDimitry Andric // context in the DISPATCHER_CONTEXT. 1860b57cec5SDimitry Andric CONTEXT new_ctx; 1870b57cec5SDimitry Andric RtlUnwindEx(frame, (PVOID)target, ms_exc, (PVOID)retval, &new_ctx, disp->HistoryTable); 1880b57cec5SDimitry Andric _LIBUNWIND_ABORT("RtlUnwindEx() failed"); 1890b57cec5SDimitry Andric } 1900b57cec5SDimitry Andric // Anything else indicates a serious problem. 1910b57cec5SDimitry Andric default: return ExceptionContinueExecution; 1920b57cec5SDimitry Andric } 1930b57cec5SDimitry Andric } 1940b57cec5SDimitry Andric 1950b57cec5SDimitry Andric /// Personality function returned by \c __unw_get_proc_info() in SEH contexts. 1960b57cec5SDimitry Andric /// This is a wrapper that calls the real SEH handler function, which in 1970b57cec5SDimitry Andric /// turn (at least, for Itanium-style frames) calls the real Itanium 1980b57cec5SDimitry Andric /// personality function (see \c _GCC_specific_handler()). 1990b57cec5SDimitry Andric extern "C" _Unwind_Reason_Code 2000b57cec5SDimitry Andric __libunwind_seh_personality(int version, _Unwind_Action state, 2010b57cec5SDimitry Andric uint64_t klass, _Unwind_Exception *exc, 2020b57cec5SDimitry Andric struct _Unwind_Context *context) { 2030b57cec5SDimitry Andric (void)version; 2040b57cec5SDimitry Andric (void)klass; 2050b57cec5SDimitry Andric EXCEPTION_RECORD ms_exc; 2060b57cec5SDimitry Andric bool phase2 = (state & (_UA_SEARCH_PHASE|_UA_CLEANUP_PHASE)) == _UA_CLEANUP_PHASE; 2070b57cec5SDimitry Andric ms_exc.ExceptionCode = STATUS_GCC_THROW; 2080b57cec5SDimitry Andric ms_exc.ExceptionFlags = 0; 2090b57cec5SDimitry Andric ms_exc.NumberParameters = 3; 2100b57cec5SDimitry Andric ms_exc.ExceptionInformation[0] = (ULONG_PTR)exc; 2110b57cec5SDimitry Andric ms_exc.ExceptionInformation[1] = (ULONG_PTR)context; 2120b57cec5SDimitry Andric ms_exc.ExceptionInformation[2] = state; 2130b57cec5SDimitry Andric DISPATCHER_CONTEXT *disp_ctx = 2140b57cec5SDimitry Andric __unw_seh_get_disp_ctx((unw_cursor_t *)context); 2150b57cec5SDimitry Andric EXCEPTION_DISPOSITION ms_act = disp_ctx->LanguageHandler(&ms_exc, 2160b57cec5SDimitry Andric (PVOID)disp_ctx->EstablisherFrame, 2170b57cec5SDimitry Andric disp_ctx->ContextRecord, 2180b57cec5SDimitry Andric disp_ctx); 2190b57cec5SDimitry Andric switch (ms_act) { 2200b57cec5SDimitry Andric case ExceptionContinueSearch: return _URC_CONTINUE_UNWIND; 2210b57cec5SDimitry Andric case 4 /*ExceptionExecuteHandler*/: 2220b57cec5SDimitry Andric return phase2 ? _URC_INSTALL_CONTEXT : _URC_HANDLER_FOUND; 2230b57cec5SDimitry Andric default: 2240b57cec5SDimitry Andric return phase2 ? _URC_FATAL_PHASE2_ERROR : _URC_FATAL_PHASE1_ERROR; 2250b57cec5SDimitry Andric } 2260b57cec5SDimitry Andric } 2270b57cec5SDimitry Andric 2280b57cec5SDimitry Andric static _Unwind_Reason_Code 2290b57cec5SDimitry Andric unwind_phase2_forced(unw_context_t *uc, 2300b57cec5SDimitry Andric _Unwind_Exception *exception_object, 2310b57cec5SDimitry Andric _Unwind_Stop_Fn stop, void *stop_parameter) { 2320b57cec5SDimitry Andric unw_cursor_t cursor2; 2330b57cec5SDimitry Andric __unw_init_local(&cursor2, uc); 2340b57cec5SDimitry Andric 2350b57cec5SDimitry Andric // Walk each frame until we reach where search phase said to stop 2360b57cec5SDimitry Andric while (__unw_step(&cursor2) > 0) { 2370b57cec5SDimitry Andric 2380b57cec5SDimitry Andric // Update info about this frame. 2390b57cec5SDimitry Andric unw_proc_info_t frameInfo; 2400b57cec5SDimitry Andric if (__unw_get_proc_info(&cursor2, &frameInfo) != UNW_ESUCCESS) { 2410b57cec5SDimitry Andric _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): __unw_step " 2420b57cec5SDimitry Andric "failed => _URC_END_OF_STACK", 2430b57cec5SDimitry Andric (void *)exception_object); 2440b57cec5SDimitry Andric return _URC_FATAL_PHASE2_ERROR; 2450b57cec5SDimitry Andric } 2460b57cec5SDimitry Andric 2470b57cec5SDimitry Andric // When tracing, print state information. 2480b57cec5SDimitry Andric if (_LIBUNWIND_TRACING_UNWINDING) { 2490b57cec5SDimitry Andric char functionBuf[512]; 2500b57cec5SDimitry Andric const char *functionName = functionBuf; 2510b57cec5SDimitry Andric unw_word_t offset; 2520b57cec5SDimitry Andric if ((__unw_get_proc_name(&cursor2, functionBuf, sizeof(functionBuf), 2530b57cec5SDimitry Andric &offset) != UNW_ESUCCESS) || 2540b57cec5SDimitry Andric (frameInfo.start_ip + offset > frameInfo.end_ip)) 2550b57cec5SDimitry Andric functionName = ".anonymous."; 2560b57cec5SDimitry Andric _LIBUNWIND_TRACE_UNWINDING( 2570b57cec5SDimitry Andric "unwind_phase2_forced(ex_ojb=%p): start_ip=0x%" PRIx64 2580b57cec5SDimitry Andric ", func=%s, lsda=0x%" PRIx64 ", personality=0x%" PRIx64, 2590b57cec5SDimitry Andric (void *)exception_object, frameInfo.start_ip, functionName, 2600b57cec5SDimitry Andric frameInfo.lsda, frameInfo.handler); 2610b57cec5SDimitry Andric } 2620b57cec5SDimitry Andric 2630b57cec5SDimitry Andric // Call stop function at each frame. 2640b57cec5SDimitry Andric _Unwind_Action action = 2650b57cec5SDimitry Andric (_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE); 2660b57cec5SDimitry Andric _Unwind_Reason_Code stopResult = 2670b57cec5SDimitry Andric (*stop)(1, action, exception_object->exception_class, exception_object, 2680b57cec5SDimitry Andric (struct _Unwind_Context *)(&cursor2), stop_parameter); 2690b57cec5SDimitry Andric _LIBUNWIND_TRACE_UNWINDING( 2700b57cec5SDimitry Andric "unwind_phase2_forced(ex_ojb=%p): stop function returned %d", 2710b57cec5SDimitry Andric (void *)exception_object, stopResult); 2720b57cec5SDimitry Andric if (stopResult != _URC_NO_REASON) { 2730b57cec5SDimitry Andric _LIBUNWIND_TRACE_UNWINDING( 2740b57cec5SDimitry Andric "unwind_phase2_forced(ex_ojb=%p): stopped by stop function", 2750b57cec5SDimitry Andric (void *)exception_object); 2760b57cec5SDimitry Andric return _URC_FATAL_PHASE2_ERROR; 2770b57cec5SDimitry Andric } 2780b57cec5SDimitry Andric 2790b57cec5SDimitry Andric // If there is a personality routine, tell it we are unwinding. 2800b57cec5SDimitry Andric if (frameInfo.handler != 0) { 2815ffd83dbSDimitry Andric _Unwind_Personality_Fn p = 2825ffd83dbSDimitry Andric (_Unwind_Personality_Fn)(intptr_t)(frameInfo.handler); 2830b57cec5SDimitry Andric _LIBUNWIND_TRACE_UNWINDING( 2840b57cec5SDimitry Andric "unwind_phase2_forced(ex_ojb=%p): calling personality function %p", 2850b57cec5SDimitry Andric (void *)exception_object, (void *)(uintptr_t)p); 2860b57cec5SDimitry Andric _Unwind_Reason_Code personalityResult = 2870b57cec5SDimitry Andric (*p)(1, action, exception_object->exception_class, exception_object, 2880b57cec5SDimitry Andric (struct _Unwind_Context *)(&cursor2)); 2890b57cec5SDimitry Andric switch (personalityResult) { 2900b57cec5SDimitry Andric case _URC_CONTINUE_UNWIND: 2910b57cec5SDimitry Andric _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " 2920b57cec5SDimitry Andric "personality returned " 2930b57cec5SDimitry Andric "_URC_CONTINUE_UNWIND", 2940b57cec5SDimitry Andric (void *)exception_object); 2950b57cec5SDimitry Andric // Destructors called, continue unwinding 2960b57cec5SDimitry Andric break; 2970b57cec5SDimitry Andric case _URC_INSTALL_CONTEXT: 2980b57cec5SDimitry Andric _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " 2990b57cec5SDimitry Andric "personality returned " 3000b57cec5SDimitry Andric "_URC_INSTALL_CONTEXT", 3010b57cec5SDimitry Andric (void *)exception_object); 3020b57cec5SDimitry Andric // We may get control back if landing pad calls _Unwind_Resume(). 3030b57cec5SDimitry Andric __unw_resume(&cursor2); 3040b57cec5SDimitry Andric break; 3050b57cec5SDimitry Andric default: 3060b57cec5SDimitry Andric // Personality routine returned an unknown result code. 3070b57cec5SDimitry Andric _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " 3080b57cec5SDimitry Andric "personality returned %d, " 3090b57cec5SDimitry Andric "_URC_FATAL_PHASE2_ERROR", 3100b57cec5SDimitry Andric (void *)exception_object, personalityResult); 3110b57cec5SDimitry Andric return _URC_FATAL_PHASE2_ERROR; 3120b57cec5SDimitry Andric } 3130b57cec5SDimitry Andric } 3140b57cec5SDimitry Andric } 3150b57cec5SDimitry Andric 3160b57cec5SDimitry Andric // Call stop function one last time and tell it we've reached the end 3170b57cec5SDimitry Andric // of the stack. 3180b57cec5SDimitry Andric _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): calling stop " 3190b57cec5SDimitry Andric "function with _UA_END_OF_STACK", 3200b57cec5SDimitry Andric (void *)exception_object); 3210b57cec5SDimitry Andric _Unwind_Action lastAction = 3220b57cec5SDimitry Andric (_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE | _UA_END_OF_STACK); 3230b57cec5SDimitry Andric (*stop)(1, lastAction, exception_object->exception_class, exception_object, 3240b57cec5SDimitry Andric (struct _Unwind_Context *)(&cursor2), stop_parameter); 3250b57cec5SDimitry Andric 3260b57cec5SDimitry Andric // Clean up phase did not resume at the frame that the search phase said it 3270b57cec5SDimitry Andric // would. 3280b57cec5SDimitry Andric return _URC_FATAL_PHASE2_ERROR; 3290b57cec5SDimitry Andric } 3300b57cec5SDimitry Andric 3310b57cec5SDimitry Andric /// Called by \c __cxa_throw(). Only returns if there is a fatal error. 3320b57cec5SDimitry Andric _LIBUNWIND_EXPORT _Unwind_Reason_Code 3330b57cec5SDimitry Andric _Unwind_RaiseException(_Unwind_Exception *exception_object) { 3340b57cec5SDimitry Andric _LIBUNWIND_TRACE_API("_Unwind_RaiseException(ex_obj=%p)", 3350b57cec5SDimitry Andric (void *)exception_object); 3360b57cec5SDimitry Andric 3370b57cec5SDimitry Andric // Mark that this is a non-forced unwind, so _Unwind_Resume() 3380b57cec5SDimitry Andric // can do the right thing. 3390b57cec5SDimitry Andric memset(exception_object->private_, 0, sizeof(exception_object->private_)); 3400b57cec5SDimitry Andric 3410b57cec5SDimitry Andric // phase 1: the search phase 3420b57cec5SDimitry Andric // We'll let the system do that for us. 3430b57cec5SDimitry Andric RaiseException(STATUS_GCC_THROW, 0, 1, (ULONG_PTR *)&exception_object); 3440b57cec5SDimitry Andric 3450b57cec5SDimitry Andric // If we get here, either something went horribly wrong or we reached the 3460b57cec5SDimitry Andric // top of the stack. Either way, let libc++abi call std::terminate(). 3470b57cec5SDimitry Andric return _URC_END_OF_STACK; 3480b57cec5SDimitry Andric } 3490b57cec5SDimitry Andric 3500b57cec5SDimitry Andric /// When \c _Unwind_RaiseException() is in phase2, it hands control 3510b57cec5SDimitry Andric /// to the personality function at each frame. The personality 3520b57cec5SDimitry Andric /// may force a jump to a landing pad in that function; the landing 3530b57cec5SDimitry Andric /// pad code may then call \c _Unwind_Resume() to continue with the 3540b57cec5SDimitry Andric /// unwinding. Note: the call to \c _Unwind_Resume() is from compiler 3550b57cec5SDimitry Andric /// geneated user code. All other \c _Unwind_* routines are called 3560b57cec5SDimitry Andric /// by the C++ runtime \c __cxa_* routines. 3570b57cec5SDimitry Andric /// 3580b57cec5SDimitry Andric /// Note: re-throwing an exception (as opposed to continuing the unwind) 3590b57cec5SDimitry Andric /// is implemented by having the code call \c __cxa_rethrow() which 3600b57cec5SDimitry Andric /// in turn calls \c _Unwind_Resume_or_Rethrow(). 3610b57cec5SDimitry Andric _LIBUNWIND_EXPORT void 3620b57cec5SDimitry Andric _Unwind_Resume(_Unwind_Exception *exception_object) { 3630b57cec5SDimitry Andric _LIBUNWIND_TRACE_API("_Unwind_Resume(ex_obj=%p)", (void *)exception_object); 3640b57cec5SDimitry Andric 3650b57cec5SDimitry Andric if (exception_object->private_[0] != 0) { 3660b57cec5SDimitry Andric unw_context_t uc; 3670b57cec5SDimitry Andric 3680b57cec5SDimitry Andric __unw_getcontext(&uc); 3690b57cec5SDimitry Andric unwind_phase2_forced(&uc, exception_object, 3700b57cec5SDimitry Andric (_Unwind_Stop_Fn) exception_object->private_[0], 3710b57cec5SDimitry Andric (void *)exception_object->private_[4]); 3720b57cec5SDimitry Andric } else { 3730b57cec5SDimitry Andric // Recover the parameters for the unwind from the exception object 3740b57cec5SDimitry Andric // so we can start unwinding again. 3750b57cec5SDimitry Andric EXCEPTION_RECORD ms_exc; 3760b57cec5SDimitry Andric CONTEXT ms_ctx; 3770b57cec5SDimitry Andric UNWIND_HISTORY_TABLE hist; 3780b57cec5SDimitry Andric 3790b57cec5SDimitry Andric memset(&ms_exc, 0, sizeof(ms_exc)); 3800b57cec5SDimitry Andric memset(&hist, 0, sizeof(hist)); 3810b57cec5SDimitry Andric ms_exc.ExceptionCode = STATUS_GCC_THROW; 3820b57cec5SDimitry Andric ms_exc.ExceptionFlags = EXCEPTION_NONCONTINUABLE; 3830b57cec5SDimitry Andric ms_exc.NumberParameters = 4; 3840b57cec5SDimitry Andric ms_exc.ExceptionInformation[0] = (ULONG_PTR)exception_object; 3850b57cec5SDimitry Andric ms_exc.ExceptionInformation[1] = exception_object->private_[1]; 3860b57cec5SDimitry Andric ms_exc.ExceptionInformation[2] = exception_object->private_[2]; 3870b57cec5SDimitry Andric ms_exc.ExceptionInformation[3] = exception_object->private_[3]; 3880b57cec5SDimitry Andric RtlUnwindEx((PVOID)exception_object->private_[1], 3890b57cec5SDimitry Andric (PVOID)exception_object->private_[2], &ms_exc, 3900b57cec5SDimitry Andric exception_object, &ms_ctx, &hist); 3910b57cec5SDimitry Andric } 3920b57cec5SDimitry Andric 3930b57cec5SDimitry Andric // Clients assume _Unwind_Resume() does not return, so all we can do is abort. 3940b57cec5SDimitry Andric _LIBUNWIND_ABORT("_Unwind_Resume() can't return"); 3950b57cec5SDimitry Andric } 3960b57cec5SDimitry Andric 3970b57cec5SDimitry Andric /// Not used by C++. 3980b57cec5SDimitry Andric /// Unwinds stack, calling "stop" function at each frame. 3990b57cec5SDimitry Andric /// Could be used to implement \c longjmp(). 4000b57cec5SDimitry Andric _LIBUNWIND_EXPORT _Unwind_Reason_Code 4010b57cec5SDimitry Andric _Unwind_ForcedUnwind(_Unwind_Exception *exception_object, 4020b57cec5SDimitry Andric _Unwind_Stop_Fn stop, void *stop_parameter) { 4030b57cec5SDimitry Andric _LIBUNWIND_TRACE_API("_Unwind_ForcedUnwind(ex_obj=%p, stop=%p)", 4040b57cec5SDimitry Andric (void *)exception_object, (void *)(uintptr_t)stop); 4050b57cec5SDimitry Andric unw_context_t uc; 4060b57cec5SDimitry Andric __unw_getcontext(&uc); 4070b57cec5SDimitry Andric 4080b57cec5SDimitry Andric // Mark that this is a forced unwind, so _Unwind_Resume() can do 4090b57cec5SDimitry Andric // the right thing. 4100b57cec5SDimitry Andric exception_object->private_[0] = (uintptr_t) stop; 4110b57cec5SDimitry Andric exception_object->private_[4] = (uintptr_t) stop_parameter; 4120b57cec5SDimitry Andric 4130b57cec5SDimitry Andric // do it 4140b57cec5SDimitry Andric return unwind_phase2_forced(&uc, exception_object, stop, stop_parameter); 4150b57cec5SDimitry Andric } 4160b57cec5SDimitry Andric 4170b57cec5SDimitry Andric /// Called by personality handler during phase 2 to get LSDA for current frame. 4180b57cec5SDimitry Andric _LIBUNWIND_EXPORT uintptr_t 4190b57cec5SDimitry Andric _Unwind_GetLanguageSpecificData(struct _Unwind_Context *context) { 4200b57cec5SDimitry Andric uintptr_t result = 4210b57cec5SDimitry Andric (uintptr_t)__unw_seh_get_disp_ctx((unw_cursor_t *)context)->HandlerData; 4220b57cec5SDimitry Andric _LIBUNWIND_TRACE_API( 4230b57cec5SDimitry Andric "_Unwind_GetLanguageSpecificData(context=%p) => 0x%" PRIxPTR, 4240b57cec5SDimitry Andric (void *)context, result); 4250b57cec5SDimitry Andric return result; 4260b57cec5SDimitry Andric } 4270b57cec5SDimitry Andric 4280b57cec5SDimitry Andric /// Called by personality handler during phase 2 to find the start of the 4290b57cec5SDimitry Andric /// function. 4300b57cec5SDimitry Andric _LIBUNWIND_EXPORT uintptr_t 4310b57cec5SDimitry Andric _Unwind_GetRegionStart(struct _Unwind_Context *context) { 4320b57cec5SDimitry Andric DISPATCHER_CONTEXT *disp = __unw_seh_get_disp_ctx((unw_cursor_t *)context); 4330b57cec5SDimitry Andric uintptr_t result = (uintptr_t)disp->FunctionEntry->BeginAddress + disp->ImageBase; 4340b57cec5SDimitry Andric _LIBUNWIND_TRACE_API("_Unwind_GetRegionStart(context=%p) => 0x%" PRIxPTR, 4350b57cec5SDimitry Andric (void *)context, result); 4360b57cec5SDimitry Andric return result; 4370b57cec5SDimitry Andric } 4380b57cec5SDimitry Andric 4390b57cec5SDimitry Andric static int __unw_init_seh(unw_cursor_t *cursor, CONTEXT *context) { 4400b57cec5SDimitry Andric #ifdef _LIBUNWIND_TARGET_X86_64 4410b57cec5SDimitry Andric new (reinterpret_cast<UnwindCursor<LocalAddressSpace, Registers_x86_64> *>(cursor)) 4420b57cec5SDimitry Andric UnwindCursor<LocalAddressSpace, Registers_x86_64>( 4430b57cec5SDimitry Andric context, LocalAddressSpace::sThisAddressSpace); 4440b57cec5SDimitry Andric auto *co = reinterpret_cast<AbstractUnwindCursor *>(cursor); 4450b57cec5SDimitry Andric co->setInfoBasedOnIPRegister(); 4460b57cec5SDimitry Andric return UNW_ESUCCESS; 4470b57cec5SDimitry Andric #elif defined(_LIBUNWIND_TARGET_ARM) 4480b57cec5SDimitry Andric new (reinterpret_cast<UnwindCursor<LocalAddressSpace, Registers_arm> *>(cursor)) 4490b57cec5SDimitry Andric UnwindCursor<LocalAddressSpace, Registers_arm>( 4500b57cec5SDimitry Andric context, LocalAddressSpace::sThisAddressSpace); 4510b57cec5SDimitry Andric auto *co = reinterpret_cast<AbstractUnwindCursor *>(cursor); 4520b57cec5SDimitry Andric co->setInfoBasedOnIPRegister(); 4530b57cec5SDimitry Andric return UNW_ESUCCESS; 4540b57cec5SDimitry Andric #elif defined(_LIBUNWIND_TARGET_AARCH64) 4550b57cec5SDimitry Andric new (reinterpret_cast<UnwindCursor<LocalAddressSpace, Registers_arm64> *>(cursor)) 4560b57cec5SDimitry Andric UnwindCursor<LocalAddressSpace, Registers_arm64>( 4570b57cec5SDimitry Andric context, LocalAddressSpace::sThisAddressSpace); 4580b57cec5SDimitry Andric auto *co = reinterpret_cast<AbstractUnwindCursor *>(cursor); 4590b57cec5SDimitry Andric co->setInfoBasedOnIPRegister(); 4600b57cec5SDimitry Andric return UNW_ESUCCESS; 4610b57cec5SDimitry Andric #else 4620b57cec5SDimitry Andric return UNW_EINVAL; 4630b57cec5SDimitry Andric #endif 4640b57cec5SDimitry Andric } 4650b57cec5SDimitry Andric 4660b57cec5SDimitry Andric static DISPATCHER_CONTEXT *__unw_seh_get_disp_ctx(unw_cursor_t *cursor) { 4670b57cec5SDimitry Andric #ifdef _LIBUNWIND_TARGET_X86_64 4680b57cec5SDimitry Andric return reinterpret_cast<UnwindCursor<LocalAddressSpace, Registers_x86_64> *>(cursor)->getDispatcherContext(); 4690b57cec5SDimitry Andric #elif defined(_LIBUNWIND_TARGET_ARM) 4700b57cec5SDimitry Andric return reinterpret_cast<UnwindCursor<LocalAddressSpace, Registers_arm> *>(cursor)->getDispatcherContext(); 4710b57cec5SDimitry Andric #elif defined(_LIBUNWIND_TARGET_AARCH64) 4720b57cec5SDimitry Andric return reinterpret_cast<UnwindCursor<LocalAddressSpace, Registers_arm64> *>(cursor)->getDispatcherContext(); 4730b57cec5SDimitry Andric #else 4740b57cec5SDimitry Andric return nullptr; 4750b57cec5SDimitry Andric #endif 4760b57cec5SDimitry Andric } 4770b57cec5SDimitry Andric 4780b57cec5SDimitry Andric static void __unw_seh_set_disp_ctx(unw_cursor_t *cursor, 4790b57cec5SDimitry Andric DISPATCHER_CONTEXT *disp) { 4800b57cec5SDimitry Andric #ifdef _LIBUNWIND_TARGET_X86_64 4810b57cec5SDimitry Andric reinterpret_cast<UnwindCursor<LocalAddressSpace, Registers_x86_64> *>(cursor)->setDispatcherContext(disp); 4820b57cec5SDimitry Andric #elif defined(_LIBUNWIND_TARGET_ARM) 4830b57cec5SDimitry Andric reinterpret_cast<UnwindCursor<LocalAddressSpace, Registers_arm> *>(cursor)->setDispatcherContext(disp); 4840b57cec5SDimitry Andric #elif defined(_LIBUNWIND_TARGET_AARCH64) 4850b57cec5SDimitry Andric reinterpret_cast<UnwindCursor<LocalAddressSpace, Registers_arm64> *>(cursor)->setDispatcherContext(disp); 4860b57cec5SDimitry Andric #endif 4870b57cec5SDimitry Andric } 4880b57cec5SDimitry Andric 4890b57cec5SDimitry Andric #endif // defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) 490