Buckets:
| //===----------------------------------------------------------------------===// | |
| // | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| // See https://llvm.org/LICENSE.txt for license information. | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| // | |
| //===----------------------------------------------------------------------===// | |
| // | |
| // Implements SEH-based Itanium C++ exceptions. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| using namespace libunwind; | |
| /// SEH exception raised by libunwind when the program calls | |
| /// \c _Unwind_RaiseException. | |
| /// SEH exception raised by libunwind to initiate phase 2 of exception | |
| /// handling. | |
| static int __unw_init_seh(unw_cursor_t *cursor, CONTEXT *ctx); | |
| static DISPATCHER_CONTEXT *__unw_seh_get_disp_ctx(unw_cursor_t *cursor); | |
| static void __unw_seh_set_disp_ctx(unw_cursor_t *cursor, | |
| DISPATCHER_CONTEXT *disp); | |
| // Local redefinition of this type; mingw-w64 headers lack the | |
| // DISPATCHER_CONTEXT_NONVOLREG_ARM64 type as of May 2025, so locally redefine | |
| // it and use that definition, to avoid needing to test/guess whether the real | |
| // type is available of not. | |
| union LOCAL_DISPATCHER_CONTEXT_NONVOLREG_ARM64 { | |
| BYTE Buffer[11 * sizeof(DWORD64) + 8 * sizeof(double)]; | |
| struct { | |
| DWORD64 GpNvRegs[11]; | |
| double FpNvRegs[8]; | |
| }; | |
| }; | |
| // Custom data type definition; this type is not defined in WinSDK. | |
| union LOCAL_DISPATCHER_CONTEXT_NONVOLREG_ARM { | |
| BYTE Buffer[8 * sizeof(DWORD) + 8 * sizeof(double)]; | |
| struct { | |
| DWORD GpNvRegs[8]; | |
| double FpNvRegs[8]; | |
| }; | |
| }; | |
| /// Common implementation of SEH-style handler functions used by Itanium- | |
| /// style frames. Depending on how and why it was called, it may do one of: | |
| /// a) Delegate to the given Itanium-style personality function; or | |
| /// b) Initiate a collided unwind to halt unwinding. | |
| _LIBUNWIND_EXPORT EXCEPTION_DISPOSITION | |
| _GCC_specific_handler(PEXCEPTION_RECORD ms_exc, PVOID frame, PCONTEXT ms_ctx, | |
| DISPATCHER_CONTEXT *disp, _Unwind_Personality_Fn pers) { | |
| unw_cursor_t cursor; | |
| _Unwind_Exception *exc; | |
| _Unwind_Action action; | |
| struct _Unwind_Context *ctx = nullptr; | |
| _Unwind_Reason_Code urc; | |
| uintptr_t retval, target; | |
| bool ours = false; | |
| _LIBUNWIND_TRACE_UNWINDING("_GCC_specific_handler(%#010lx(%lx), %p)", | |
| ms_exc->ExceptionCode, ms_exc->ExceptionFlags, | |
| (void *)frame); | |
| if (ms_exc->ExceptionCode == STATUS_GCC_UNWIND) { | |
| if (IS_TARGET_UNWIND(ms_exc->ExceptionFlags)) { | |
| // Set up the upper return value (the lower one and the target PC | |
| // were set in the call to RtlUnwindEx()) for the landing pad. | |
| disp->ContextRecord->Rdx = ms_exc->ExceptionInformation[3]; | |
| disp->ContextRecord->R1 = ms_exc->ExceptionInformation[3]; | |
| disp->ContextRecord->X1 = ms_exc->ExceptionInformation[3]; | |
| } | |
| // This is the collided unwind to the landing pad. Nothing to do. | |
| return ExceptionContinueSearch; | |
| } | |
| if (ms_exc->ExceptionCode == STATUS_GCC_THROW) { | |
| // This is (probably) a libunwind-controlled exception/unwind. Recover the | |
| // parameters which we set below, and pass them to the personality function. | |
| ours = true; | |
| exc = (_Unwind_Exception *)ms_exc->ExceptionInformation[0]; | |
| if (!IS_UNWINDING(ms_exc->ExceptionFlags) && ms_exc->NumberParameters > 1) { | |
| ctx = (struct _Unwind_Context *)ms_exc->ExceptionInformation[1]; | |
| action = (_Unwind_Action)ms_exc->ExceptionInformation[2]; | |
| } | |
| } else { | |
| // Foreign exception. | |
| // We can't interact with them (we don't know the original target frame | |
| // that we should pass on to RtlUnwindEx in _Unwind_Resume), so just | |
| // pass without calling our destructors here. | |
| return ExceptionContinueSearch; | |
| } | |
| if (!ctx) { | |
| __unw_init_seh(&cursor, disp->ContextRecord); | |
| __unw_seh_set_disp_ctx(&cursor, disp); | |
| __unw_set_reg(&cursor, UNW_REG_IP, disp->ControlPc); | |
| ctx = (struct _Unwind_Context *)&cursor; | |
| if (!IS_UNWINDING(ms_exc->ExceptionFlags)) { | |
| if (ours && ms_exc->NumberParameters > 1) | |
| action = (_Unwind_Action)(_UA_CLEANUP_PHASE | _UA_FORCE_UNWIND); | |
| else | |
| action = _UA_SEARCH_PHASE; | |
| } else { | |
| if (ours && ms_exc->ExceptionInformation[1] == (ULONG_PTR)frame) | |
| action = (_Unwind_Action)(_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME); | |
| else | |
| action = _UA_CLEANUP_PHASE; | |
| } | |
| } | |
| _LIBUNWIND_TRACE_UNWINDING("_GCC_specific_handler() calling personality " | |
| "function %p(1, %d, %llx, %p, %p)", | |
| (void *)pers, action, exc->exception_class, | |
| (void *)exc, (void *)ctx); | |
| urc = pers(1, action, exc->exception_class, exc, ctx); | |
| _LIBUNWIND_TRACE_UNWINDING("_GCC_specific_handler() personality returned %d", urc); | |
| switch (urc) { | |
| case _URC_CONTINUE_UNWIND: | |
| // If we're in phase 2, and the personality routine said to continue | |
| // at the target frame, we're in real trouble. | |
| if (action & _UA_HANDLER_FRAME) | |
| _LIBUNWIND_ABORT("Personality continued unwind at the target frame!"); | |
| return ExceptionContinueSearch; | |
| case _URC_HANDLER_FOUND: | |
| // If we were called by __libunwind_seh_personality(), indicate that | |
| // a handler was found; otherwise, initiate phase 2 by unwinding. | |
| if (ours && ms_exc->NumberParameters > 1) | |
| return 4 /* ExceptionExecuteHandler in mingw */; | |
| // This should never happen in phase 2. | |
| if (IS_UNWINDING(ms_exc->ExceptionFlags)) | |
| _LIBUNWIND_ABORT("Personality indicated exception handler in phase 2!"); | |
| exc->private_[1] = (ULONG_PTR)frame; | |
| if (ours) { | |
| ms_exc->NumberParameters = 4; | |
| ms_exc->ExceptionInformation[1] = (ULONG_PTR)frame; | |
| } | |
| // FIXME: Indicate target frame in foreign case! | |
| // phase 2: the clean up phase | |
| RtlUnwindEx(frame, (PVOID)disp->ControlPc, ms_exc, exc, disp->ContextRecord, | |
| disp->HistoryTable); | |
| _LIBUNWIND_ABORT("RtlUnwindEx() failed"); | |
| case _URC_INSTALL_CONTEXT: { | |
| // If we were called by __libunwind_seh_personality(), indicate that | |
| // a handler was found; otherwise, it's time to initiate a collided | |
| // unwind to the target. | |
| if (ours && !IS_UNWINDING(ms_exc->ExceptionFlags) && ms_exc->NumberParameters > 1) | |
| return 4 /* ExceptionExecuteHandler in mingw */; | |
| // This should never happen in phase 1. | |
| if (!IS_UNWINDING(ms_exc->ExceptionFlags)) | |
| _LIBUNWIND_ABORT("Personality installed context during phase 1!"); | |
| exc->private_[2] = disp->TargetIp; | |
| __unw_get_reg(&cursor, UNW_X86_64_RAX, &retval); | |
| __unw_get_reg(&cursor, UNW_X86_64_RDX, &exc->private_[3]); | |
| exc->private_[2] = disp->TargetPc; | |
| __unw_get_reg(&cursor, UNW_ARM_R0, &retval); | |
| __unw_get_reg(&cursor, UNW_ARM_R1, &exc->private_[3]); | |
| exc->private_[2] = disp->TargetPc; | |
| __unw_get_reg(&cursor, UNW_AARCH64_X0, &retval); | |
| __unw_get_reg(&cursor, UNW_AARCH64_X1, &exc->private_[3]); | |
| __unw_get_reg(&cursor, UNW_REG_IP, &target); | |
| ms_exc->ExceptionCode = STATUS_GCC_UNWIND; | |
| ms_exc->ExceptionInformation[2] = disp->TargetIp; | |
| ms_exc->ExceptionInformation[2] = disp->TargetPc; | |
| ms_exc->ExceptionInformation[3] = exc->private_[3]; | |
| // Give NTRTL some scratch space to keep track of the collided unwind. | |
| // Don't use the one that was passed in; we don't want to overwrite the | |
| // context in the DISPATCHER_CONTEXT. | |
| CONTEXT new_ctx; | |
| RtlUnwindEx(frame, (PVOID)target, ms_exc, (PVOID)retval, &new_ctx, disp->HistoryTable); | |
| _LIBUNWIND_ABORT("RtlUnwindEx() failed"); | |
| } | |
| // Anything else indicates a serious problem. | |
| default: return ExceptionContinueExecution; | |
| } | |
| } | |
| /// Personality function returned by \c __unw_get_proc_info() in SEH contexts. | |
| /// This is a wrapper that calls the real SEH handler function, which in | |
| /// turn (at least, for Itanium-style frames) calls the real Itanium | |
| /// personality function (see \c _GCC_specific_handler()). | |
| extern "C" _Unwind_Reason_Code | |
| __libunwind_seh_personality(int version, _Unwind_Action state, | |
| uint64_t klass, _Unwind_Exception *exc, | |
| struct _Unwind_Context *context) { | |
| (void)version; | |
| (void)klass; | |
| EXCEPTION_RECORD ms_exc; | |
| bool phase2 = (state & (_UA_SEARCH_PHASE|_UA_CLEANUP_PHASE)) == _UA_CLEANUP_PHASE; | |
| ms_exc.ExceptionCode = STATUS_GCC_THROW; | |
| ms_exc.ExceptionFlags = 0; | |
| ms_exc.NumberParameters = 3; | |
| ms_exc.ExceptionInformation[0] = (ULONG_PTR)exc; | |
| ms_exc.ExceptionInformation[1] = (ULONG_PTR)context; | |
| ms_exc.ExceptionInformation[2] = state; | |
| DISPATCHER_CONTEXT *disp_ctx = | |
| __unw_seh_get_disp_ctx((unw_cursor_t *)context); | |
| LOCAL_DISPATCHER_CONTEXT_NONVOLREG_ARM64 nonvol; | |
| memcpy(&nonvol.GpNvRegs, &disp_ctx->ContextRecord->X19, | |
| sizeof(nonvol.GpNvRegs)); | |
| for (int i = 0; i < 8; i++) | |
| nonvol.FpNvRegs[i] = disp_ctx->ContextRecord->V[i + 8].D[0]; | |
| disp_ctx->NonVolatileRegisters = nonvol.Buffer; | |
| LOCAL_DISPATCHER_CONTEXT_NONVOLREG_ARM nonvol; | |
| memcpy(&nonvol.GpNvRegs, &disp_ctx->ContextRecord->R4, | |
| sizeof(nonvol.GpNvRegs)); | |
| memcpy(&nonvol.FpNvRegs, &disp_ctx->ContextRecord->D[8], | |
| sizeof(nonvol.FpNvRegs)); | |
| disp_ctx->NonVolatileRegisters = nonvol.Buffer; | |
| _LIBUNWIND_TRACE_UNWINDING("__libunwind_seh_personality() calling " | |
| "LanguageHandler %p(%p, %p, %p, %p)", | |
| (void *)disp_ctx->LanguageHandler, (void *)&ms_exc, | |
| (void *)disp_ctx->EstablisherFrame, | |
| (void *)disp_ctx->ContextRecord, (void *)disp_ctx); | |
| EXCEPTION_DISPOSITION ms_act = disp_ctx->LanguageHandler(&ms_exc, | |
| (PVOID)disp_ctx->EstablisherFrame, | |
| disp_ctx->ContextRecord, | |
| disp_ctx); | |
| _LIBUNWIND_TRACE_UNWINDING("__libunwind_seh_personality() LanguageHandler " | |
| "returned %d", | |
| (int)ms_act); | |
| switch (ms_act) { | |
| case ExceptionContinueExecution: return _URC_END_OF_STACK; | |
| case ExceptionContinueSearch: return _URC_CONTINUE_UNWIND; | |
| case 4 /*ExceptionExecuteHandler*/: | |
| return phase2 ? _URC_INSTALL_CONTEXT : _URC_HANDLER_FOUND; | |
| default: | |
| return phase2 ? _URC_FATAL_PHASE2_ERROR : _URC_FATAL_PHASE1_ERROR; | |
| } | |
| } | |
| static _Unwind_Reason_Code | |
| unwind_phase2_forced(unw_context_t *uc, | |
| _Unwind_Exception *exception_object, | |
| _Unwind_Stop_Fn stop, void *stop_parameter) { | |
| unw_cursor_t cursor2; | |
| __unw_init_local(&cursor2, uc); | |
| // Walk each frame until we reach where search phase said to stop | |
| while (__unw_step(&cursor2) > 0) { | |
| // Update info about this frame. | |
| unw_proc_info_t frameInfo; | |
| if (__unw_get_proc_info(&cursor2, &frameInfo) != UNW_ESUCCESS) { | |
| _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): __unw_get_proc_info " | |
| "failed => _URC_END_OF_STACK", | |
| (void *)exception_object); | |
| return _URC_FATAL_PHASE2_ERROR; | |
| } | |
| // When tracing, print state information. | |
| if (_LIBUNWIND_TRACING_UNWINDING) { | |
| char functionBuf[512]; | |
| const char *functionName = functionBuf; | |
| unw_word_t offset; | |
| if ((__unw_get_proc_name(&cursor2, functionBuf, sizeof(functionBuf), | |
| &offset) != UNW_ESUCCESS) || | |
| (frameInfo.start_ip + offset > frameInfo.end_ip)) | |
| functionName = ".anonymous."; | |
| _LIBUNWIND_TRACE_UNWINDING( | |
| "unwind_phase2_forced(ex_ojb=%p): start_ip=0x%" PRIxPTR | |
| ", func=%s, lsda=0x%" PRIxPTR ", personality=0x%" PRIxPTR, | |
| (void *)exception_object, frameInfo.start_ip, functionName, | |
| frameInfo.lsda, frameInfo.handler); | |
| } | |
| // Call stop function at each frame. | |
| _Unwind_Action action = | |
| (_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE); | |
| _Unwind_Reason_Code stopResult = | |
| (*stop)(1, action, exception_object->exception_class, exception_object, | |
| (struct _Unwind_Context *)(&cursor2), stop_parameter); | |
| _LIBUNWIND_TRACE_UNWINDING( | |
| "unwind_phase2_forced(ex_ojb=%p): stop function returned %d", | |
| (void *)exception_object, stopResult); | |
| if (stopResult != _URC_NO_REASON) { | |
| _LIBUNWIND_TRACE_UNWINDING( | |
| "unwind_phase2_forced(ex_ojb=%p): stopped by stop function", | |
| (void *)exception_object); | |
| return _URC_FATAL_PHASE2_ERROR; | |
| } | |
| // If there is a personality routine, tell it we are unwinding. | |
| if (frameInfo.handler != 0) { | |
| _Unwind_Personality_Fn p = | |
| (_Unwind_Personality_Fn)(intptr_t)(frameInfo.handler); | |
| _LIBUNWIND_TRACE_UNWINDING( | |
| "unwind_phase2_forced(ex_ojb=%p): calling personality function %p", | |
| (void *)exception_object, (void *)(uintptr_t)p); | |
| _Unwind_Reason_Code personalityResult = | |
| (*p)(1, action, exception_object->exception_class, exception_object, | |
| (struct _Unwind_Context *)(&cursor2)); | |
| switch (personalityResult) { | |
| case _URC_CONTINUE_UNWIND: | |
| _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " | |
| "personality returned " | |
| "_URC_CONTINUE_UNWIND", | |
| (void *)exception_object); | |
| // Destructors called, continue unwinding | |
| break; | |
| case _URC_INSTALL_CONTEXT: | |
| _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " | |
| "personality returned " | |
| "_URC_INSTALL_CONTEXT", | |
| (void *)exception_object); | |
| // We may get control back if landing pad calls _Unwind_Resume(). | |
| __unw_resume(&cursor2); | |
| break; | |
| case _URC_END_OF_STACK: | |
| _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " | |
| "personality returned " | |
| "_URC_END_OF_STACK", | |
| (void *)exception_object); | |
| break; | |
| default: | |
| // Personality routine returned an unknown result code. | |
| _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " | |
| "personality returned %d, " | |
| "_URC_FATAL_PHASE2_ERROR", | |
| (void *)exception_object, personalityResult); | |
| return _URC_FATAL_PHASE2_ERROR; | |
| } | |
| if (personalityResult == _URC_END_OF_STACK) | |
| break; | |
| } | |
| } | |
| // Call stop function one last time and tell it we've reached the end | |
| // of the stack. | |
| _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): calling stop " | |
| "function with _UA_END_OF_STACK", | |
| (void *)exception_object); | |
| _Unwind_Action lastAction = | |
| (_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE | _UA_END_OF_STACK); | |
| (*stop)(1, lastAction, exception_object->exception_class, exception_object, | |
| (struct _Unwind_Context *)(&cursor2), stop_parameter); | |
| // Clean up phase did not resume at the frame that the search phase said it | |
| // would. | |
| return _URC_FATAL_PHASE2_ERROR; | |
| } | |
| /// Called by \c __cxa_throw(). Only returns if there is a fatal error. | |
| _LIBUNWIND_EXPORT _Unwind_Reason_Code | |
| _Unwind_RaiseException(_Unwind_Exception *exception_object) { | |
| _LIBUNWIND_TRACE_API("_Unwind_RaiseException(ex_obj=%p)", | |
| (void *)exception_object); | |
| // Mark that this is a non-forced unwind, so _Unwind_Resume() | |
| // can do the right thing. | |
| memset(exception_object->private_, 0, sizeof(exception_object->private_)); | |
| // phase 1: the search phase | |
| // We'll let the system do that for us. | |
| RaiseException(STATUS_GCC_THROW, 0, 1, (ULONG_PTR *)&exception_object); | |
| // If we get here, either something went horribly wrong or we reached the | |
| // top of the stack. Either way, let libc++abi call std::terminate(). | |
| return _URC_END_OF_STACK; | |
| } | |
| /// When \c _Unwind_RaiseException() is in phase2, it hands control | |
| /// to the personality function at each frame. The personality | |
| /// may force a jump to a landing pad in that function; the landing | |
| /// pad code may then call \c _Unwind_Resume() to continue with the | |
| /// unwinding. Note: the call to \c _Unwind_Resume() is from compiler | |
| /// generated user code. All other \c _Unwind_* routines are called | |
| /// by the C++ runtime \c __cxa_* routines. | |
| /// | |
| /// Note: re-throwing an exception (as opposed to continuing the unwind) | |
| /// is implemented by having the code call \c __cxa_rethrow() which | |
| /// in turn calls \c _Unwind_Resume_or_Rethrow(). | |
| _LIBUNWIND_EXPORT void | |
| _Unwind_Resume(_Unwind_Exception *exception_object) { | |
| _LIBUNWIND_TRACE_API("_Unwind_Resume(ex_obj=%p)", (void *)exception_object); | |
| if (exception_object->private_[0] != 0) { | |
| unw_context_t uc; | |
| __unw_getcontext(&uc); | |
| unwind_phase2_forced(&uc, exception_object, | |
| (_Unwind_Stop_Fn) exception_object->private_[0], | |
| (void *)exception_object->private_[4]); | |
| } else { | |
| // Recover the parameters for the unwind from the exception object | |
| // so we can start unwinding again. | |
| EXCEPTION_RECORD ms_exc; | |
| CONTEXT ms_ctx; | |
| UNWIND_HISTORY_TABLE hist; | |
| memset(&ms_exc, 0, sizeof(ms_exc)); | |
| memset(&hist, 0, sizeof(hist)); | |
| ms_exc.ExceptionCode = STATUS_GCC_THROW; | |
| ms_exc.ExceptionFlags = EXCEPTION_NONCONTINUABLE; | |
| ms_exc.NumberParameters = 4; | |
| ms_exc.ExceptionInformation[0] = (ULONG_PTR)exception_object; | |
| ms_exc.ExceptionInformation[1] = exception_object->private_[1]; | |
| ms_exc.ExceptionInformation[2] = exception_object->private_[2]; | |
| ms_exc.ExceptionInformation[3] = exception_object->private_[3]; | |
| RtlUnwindEx((PVOID)exception_object->private_[1], | |
| (PVOID)exception_object->private_[2], &ms_exc, | |
| exception_object, &ms_ctx, &hist); | |
| } | |
| // Clients assume _Unwind_Resume() does not return, so all we can do is abort. | |
| _LIBUNWIND_ABORT("_Unwind_Resume() can't return"); | |
| } | |
| /// Not used by C++. | |
| /// Unwinds stack, calling "stop" function at each frame. | |
| /// Could be used to implement \c longjmp(). | |
| _LIBUNWIND_EXPORT _Unwind_Reason_Code | |
| _Unwind_ForcedUnwind(_Unwind_Exception *exception_object, | |
| _Unwind_Stop_Fn stop, void *stop_parameter) { | |
| _LIBUNWIND_TRACE_API("_Unwind_ForcedUnwind(ex_obj=%p, stop=%p)", | |
| (void *)exception_object, (void *)(uintptr_t)stop); | |
| unw_context_t uc; | |
| __unw_getcontext(&uc); | |
| // Mark that this is a forced unwind, so _Unwind_Resume() can do | |
| // the right thing. | |
| exception_object->private_[0] = (uintptr_t) stop; | |
| exception_object->private_[4] = (uintptr_t) stop_parameter; | |
| // do it | |
| return unwind_phase2_forced(&uc, exception_object, stop, stop_parameter); | |
| } | |
| /// Called by personality handler during phase 2 to get LSDA for current frame. | |
| _LIBUNWIND_EXPORT uintptr_t | |
| _Unwind_GetLanguageSpecificData(struct _Unwind_Context *context) { | |
| uintptr_t result = | |
| (uintptr_t)__unw_seh_get_disp_ctx((unw_cursor_t *)context)->HandlerData; | |
| _LIBUNWIND_TRACE_API( | |
| "_Unwind_GetLanguageSpecificData(context=%p) => 0x%" PRIxPTR, | |
| (void *)context, result); | |
| return result; | |
| } | |
| /// Called by personality handler during phase 2 to find the start of the | |
| /// function. | |
| _LIBUNWIND_EXPORT uintptr_t | |
| _Unwind_GetRegionStart(struct _Unwind_Context *context) { | |
| DISPATCHER_CONTEXT *disp = __unw_seh_get_disp_ctx((unw_cursor_t *)context); | |
| uintptr_t result = (uintptr_t)disp->FunctionEntry->BeginAddress + disp->ImageBase; | |
| _LIBUNWIND_TRACE_API("_Unwind_GetRegionStart(context=%p) => 0x%" PRIxPTR, | |
| (void *)context, result); | |
| return result; | |
| } | |
| static int __unw_init_seh(unw_cursor_t *cursor, CONTEXT *context) { | |
| new (reinterpret_cast<UnwindCursor<LocalAddressSpace, Registers_x86_64> *>(cursor)) | |
| UnwindCursor<LocalAddressSpace, Registers_x86_64>( | |
| context, LocalAddressSpace::sThisAddressSpace); | |
| auto *co = reinterpret_cast<AbstractUnwindCursor *>(cursor); | |
| co->setInfoBasedOnIPRegister(); | |
| return UNW_ESUCCESS; | |
| new (reinterpret_cast<UnwindCursor<LocalAddressSpace, Registers_arm> *>(cursor)) | |
| UnwindCursor<LocalAddressSpace, Registers_arm>( | |
| context, LocalAddressSpace::sThisAddressSpace); | |
| auto *co = reinterpret_cast<AbstractUnwindCursor *>(cursor); | |
| co->setInfoBasedOnIPRegister(); | |
| return UNW_ESUCCESS; | |
| new (reinterpret_cast<UnwindCursor<LocalAddressSpace, Registers_arm64> *>(cursor)) | |
| UnwindCursor<LocalAddressSpace, Registers_arm64>( | |
| context, LocalAddressSpace::sThisAddressSpace); | |
| auto *co = reinterpret_cast<AbstractUnwindCursor *>(cursor); | |
| co->setInfoBasedOnIPRegister(); | |
| return UNW_ESUCCESS; | |
| return UNW_EINVAL; | |
| } | |
| static DISPATCHER_CONTEXT *__unw_seh_get_disp_ctx(unw_cursor_t *cursor) { | |
| return reinterpret_cast<UnwindCursor<LocalAddressSpace, Registers_x86_64> *>(cursor)->getDispatcherContext(); | |
| return reinterpret_cast<UnwindCursor<LocalAddressSpace, Registers_arm> *>(cursor)->getDispatcherContext(); | |
| return reinterpret_cast<UnwindCursor<LocalAddressSpace, Registers_arm64> *>(cursor)->getDispatcherContext(); | |
| return nullptr; | |
| } | |
| static void __unw_seh_set_disp_ctx(unw_cursor_t *cursor, | |
| DISPATCHER_CONTEXT *disp) { | |
| reinterpret_cast<UnwindCursor<LocalAddressSpace, Registers_x86_64> *>(cursor)->setDispatcherContext(disp); | |
| reinterpret_cast<UnwindCursor<LocalAddressSpace, Registers_arm> *>(cursor)->setDispatcherContext(disp); | |
| reinterpret_cast<UnwindCursor<LocalAddressSpace, Registers_arm64> *>(cursor)->setDispatcherContext(disp); | |
| } | |
Xet Storage Details
- Size:
- 23.4 kB
- Xet hash:
- ad781d34e241b62bf5cf35a035bffde5d55555a52c36107fa14448d043075730
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.