1 //===--------------------------- Unwind-seh.cpp ---------------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is dual licensed under the MIT and the University of Illinois Open 6 // Source Licenses. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // Implements SEH-based Itanium C++ exceptions. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "config.h" 15 16 #if defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) 17 18 #include <unwind.h> 19 20 #include <stdint.h> 21 #include <stdbool.h> 22 #include <stdlib.h> 23 24 #include <windef.h> 25 #include <excpt.h> 26 #include <winnt.h> 27 #include <ntstatus.h> 28 29 #include "libunwind_ext.h" 30 #include "UnwindCursor.hpp" 31 32 using namespace libunwind; 33 34 #define STATUS_USER_DEFINED (1u << 29) 35 36 #define STATUS_GCC_MAGIC (('G' << 16) | ('C' << 8) | 'C') 37 38 #define MAKE_CUSTOM_STATUS(s, c) \ 39 ((NTSTATUS)(((s) << 30) | STATUS_USER_DEFINED | (c))) 40 #define MAKE_GCC_EXCEPTION(c) \ 41 MAKE_CUSTOM_STATUS(STATUS_SEVERITY_SUCCESS, STATUS_GCC_MAGIC | ((c) << 24)) 42 43 /// SEH exception raised by libunwind when the program calls 44 /// \c _Unwind_RaiseException. 45 #define STATUS_GCC_THROW MAKE_GCC_EXCEPTION(0) // 0x20474343 46 /// SEH exception raised by libunwind to initiate phase 2 of exception 47 /// handling. 48 #define STATUS_GCC_UNWIND MAKE_GCC_EXCEPTION(1) // 0x21474343 49 50 /// Class of foreign exceptions based on unrecognized SEH exceptions. 51 static const uint64_t kSEHExceptionClass = 0x434C4E4753454800; // CLNGSEH\0 52 53 /// Exception cleanup routine used by \c _GCC_specific_handler to 54 /// free foreign exceptions. 55 static void seh_exc_cleanup(_Unwind_Reason_Code urc, _Unwind_Exception *exc) { 56 if (exc->exception_class != kSEHExceptionClass) 57 _LIBUNWIND_ABORT("SEH cleanup called on non-SEH exception"); 58 free(exc); 59 } 60 61 static int _unw_init_seh(unw_cursor_t *cursor, CONTEXT *ctx); 62 static DISPATCHER_CONTEXT *_unw_seh_get_disp_ctx(unw_cursor_t *cursor); 63 static void _unw_seh_set_disp_ctx(unw_cursor_t *cursor, DISPATCHER_CONTEXT *disp); 64 65 /// Common implementation of SEH-style handler functions used by Itanium- 66 /// style frames. Depending on how and why it was called, it may do one of: 67 /// a) Delegate to the given Itanium-style personality function; or 68 /// b) Initiate a collided unwind to halt unwinding. 69 _LIBUNWIND_EXPORT EXCEPTION_DISPOSITION 70 _GCC_specific_handler(PEXCEPTION_RECORD ms_exc, PVOID frame, PCONTEXT ms_ctx, 71 DISPATCHER_CONTEXT *disp, __personality_routine pers) { 72 unw_context_t uc; 73 unw_cursor_t cursor; 74 _Unwind_Exception *exc; 75 _Unwind_Action action; 76 struct _Unwind_Context *ctx = nullptr; 77 _Unwind_Reason_Code urc; 78 uintptr_t retval, target; 79 bool ours = false; 80 81 _LIBUNWIND_TRACE_UNWINDING("_GCC_specific_handler(%#010x(%x), %p)", ms_exc->ExceptionCode, ms_exc->ExceptionFlags, frame); 82 if (ms_exc->ExceptionCode == STATUS_GCC_UNWIND) { 83 if (IS_TARGET_UNWIND(ms_exc->ExceptionFlags)) { 84 // Set up the upper return value (the lower one and the target PC 85 // were set in the call to RtlUnwindEx()) for the landing pad. 86 #ifdef __x86_64__ 87 disp->ContextRecord->Rdx = ms_exc->ExceptionInformation[3]; 88 #elif defined(__arm__) 89 disp->ContextRecord->R1 = ms_exc->ExceptionInformation[3]; 90 #elif defined(__aarch64__) 91 disp->ContextRecord->X1 = ms_exc->ExceptionInformation[3]; 92 #endif 93 } 94 // This is the collided unwind to the landing pad. Nothing to do. 95 return ExceptionContinueSearch; 96 } 97 98 if (ms_exc->ExceptionCode == STATUS_GCC_THROW) { 99 // This is (probably) a libunwind-controlled exception/unwind. Recover the 100 // parameters which we set below, and pass them to the personality function. 101 ours = true; 102 exc = (_Unwind_Exception *)ms_exc->ExceptionInformation[0]; 103 if (!IS_UNWINDING(ms_exc->ExceptionFlags) && ms_exc->NumberParameters > 1) { 104 ctx = (struct _Unwind_Context *)ms_exc->ExceptionInformation[1]; 105 action = (_Unwind_Action)ms_exc->ExceptionInformation[2]; 106 } 107 } else { 108 // Foreign exception. 109 exc = (_Unwind_Exception *)malloc(sizeof(_Unwind_Exception)); 110 exc->exception_class = kSEHExceptionClass; 111 exc->exception_cleanup = seh_exc_cleanup; 112 memset(exc->private_, 0, sizeof(exc->private_)); 113 } 114 if (!ctx) { 115 _unw_init_seh(&cursor, disp->ContextRecord); 116 _unw_seh_set_disp_ctx(&cursor, disp); 117 unw_set_reg(&cursor, UNW_REG_IP, disp->ControlPc-1); 118 ctx = (struct _Unwind_Context *)&cursor; 119 120 if (!IS_UNWINDING(ms_exc->ExceptionFlags)) { 121 if (ours && ms_exc->NumberParameters > 1) 122 action = (_Unwind_Action)(_UA_CLEANUP_PHASE | _UA_FORCE_UNWIND); 123 else 124 action = _UA_SEARCH_PHASE; 125 } else { 126 if (ours && ms_exc->ExceptionInformation[1] == (ULONG_PTR)frame) 127 action = (_Unwind_Action)(_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME); 128 else 129 action = _UA_CLEANUP_PHASE; 130 } 131 } 132 133 _LIBUNWIND_TRACE_UNWINDING("_GCC_specific_handler() calling personality function %p(1, %d, %llx, %p, %p)", pers, action, exc->exception_class, exc, ctx); 134 urc = pers(1, action, exc->exception_class, exc, ctx); 135 _LIBUNWIND_TRACE_UNWINDING("_GCC_specific_handler() personality returned %d", urc); 136 switch (urc) { 137 case _URC_CONTINUE_UNWIND: 138 // If we're in phase 2, and the personality routine said to continue 139 // at the target frame, we're in real trouble. 140 if (action & _UA_HANDLER_FRAME) 141 _LIBUNWIND_ABORT("Personality continued unwind at the target frame!"); 142 return ExceptionContinueSearch; 143 case _URC_HANDLER_FOUND: 144 // If we were called by __libunwind_seh_personality(), indicate that 145 // a handler was found; otherwise, initiate phase 2 by unwinding. 146 if (ours && ms_exc->NumberParameters > 1) 147 return 4 /* ExecptionExecuteHandler in mingw */; 148 // This should never happen in phase 2. 149 if (IS_UNWINDING(ms_exc->ExceptionFlags)) 150 _LIBUNWIND_ABORT("Personality indicated exception handler in phase 2!"); 151 exc->private_[1] = (ULONG_PTR)frame; 152 if (ours) { 153 ms_exc->NumberParameters = 4; 154 ms_exc->ExceptionInformation[1] = (ULONG_PTR)frame; 155 } 156 // FIXME: Indicate target frame in foreign case! 157 // phase 2: the clean up phase 158 RtlUnwindEx(frame, (PVOID)disp->ControlPc, ms_exc, exc, ms_ctx, disp->HistoryTable); 159 _LIBUNWIND_ABORT("RtlUnwindEx() failed"); 160 case _URC_INSTALL_CONTEXT: { 161 // If we were called by __libunwind_seh_personality(), indicate that 162 // a handler was found; otherwise, it's time to initiate a collided 163 // unwind to the target. 164 if (ours && !IS_UNWINDING(ms_exc->ExceptionFlags) && ms_exc->NumberParameters > 1) 165 return 4 /* ExecptionExecuteHandler in mingw */; 166 // This should never happen in phase 1. 167 if (!IS_UNWINDING(ms_exc->ExceptionFlags)) 168 _LIBUNWIND_ABORT("Personality installed context during phase 1!"); 169 #ifdef __x86_64__ 170 exc->private_[2] = disp->TargetIp; 171 unw_get_reg(&cursor, UNW_X86_64_RAX, &retval); 172 unw_get_reg(&cursor, UNW_X86_64_RDX, &exc->private_[3]); 173 #elif defined(__arm__) 174 exc->private_[2] = disp->TargetPc; 175 unw_get_reg(&cursor, UNW_ARM_R0, &retval); 176 unw_get_reg(&cursor, UNW_ARM_R1, &exc->private_[3]); 177 #elif defined(__aarch64__) 178 exc->private_[2] = disp->TargetPc; 179 unw_get_reg(&cursor, UNW_ARM64_X0, &retval); 180 unw_get_reg(&cursor, UNW_ARM64_X1, &exc->private_[3]); 181 #endif 182 unw_get_reg(&cursor, UNW_REG_IP, &target); 183 ms_exc->ExceptionCode = STATUS_GCC_UNWIND; 184 #ifdef __x86_64__ 185 ms_exc->ExceptionInformation[2] = disp->TargetIp; 186 #elif defined(__arm__) || defined(__aarch64__) 187 ms_exc->ExceptionInformation[2] = disp->TargetPc; 188 #endif 189 ms_exc->ExceptionInformation[3] = exc->private_[3]; 190 // Give NTRTL some scratch space to keep track of the collided unwind. 191 // Don't use the one that was passed in; we don't want to overwrite the 192 // context in the DISPATCHER_CONTEXT. 193 CONTEXT new_ctx; 194 RtlUnwindEx(frame, (PVOID)target, ms_exc, (PVOID)retval, &new_ctx, disp->HistoryTable); 195 _LIBUNWIND_ABORT("RtlUnwindEx() failed"); 196 } 197 // Anything else indicates a serious problem. 198 default: return ExceptionContinueExecution; 199 } 200 } 201 202 /// Personality function returned by \c unw_get_proc_info() in SEH contexts. 203 /// This is a wrapper that calls the real SEH handler function, which in 204 /// turn (at least, for Itanium-style frames) calls the real Itanium 205 /// personality function (see \c _GCC_specific_handler()). 206 extern "C" _Unwind_Reason_Code 207 __libunwind_seh_personality(int version, _Unwind_Action state, 208 uint64_t klass, _Unwind_Exception *exc, 209 struct _Unwind_Context *context) { 210 EXCEPTION_RECORD ms_exc; 211 bool phase2 = (state & (_UA_SEARCH_PHASE|_UA_CLEANUP_PHASE)) == _UA_CLEANUP_PHASE; 212 ms_exc.ExceptionCode = STATUS_GCC_THROW; 213 ms_exc.ExceptionFlags = 0; 214 ms_exc.NumberParameters = 3; 215 ms_exc.ExceptionInformation[0] = (ULONG_PTR)exc; 216 ms_exc.ExceptionInformation[1] = (ULONG_PTR)context; 217 ms_exc.ExceptionInformation[2] = state; 218 DISPATCHER_CONTEXT *disp_ctx = _unw_seh_get_disp_ctx((unw_cursor_t *)context); 219 EXCEPTION_DISPOSITION ms_act = disp_ctx->LanguageHandler(&ms_exc, 220 (PVOID)disp_ctx->EstablisherFrame, 221 disp_ctx->ContextRecord, 222 disp_ctx); 223 switch (ms_act) { 224 case ExceptionContinueSearch: return _URC_CONTINUE_UNWIND; 225 case 4 /*ExceptionExecuteHandler*/: 226 return phase2 ? _URC_INSTALL_CONTEXT : _URC_HANDLER_FOUND; 227 default: 228 return phase2 ? _URC_FATAL_PHASE2_ERROR : _URC_FATAL_PHASE1_ERROR; 229 } 230 } 231 232 static _Unwind_Reason_Code 233 unwind_phase2_forced(unw_context_t *uc, 234 _Unwind_Exception *exception_object, 235 _Unwind_Stop_Fn stop, void *stop_parameter) { 236 unw_cursor_t cursor2; 237 unw_init_local(&cursor2, uc); 238 239 // Walk each frame until we reach where search phase said to stop 240 while (unw_step(&cursor2) > 0) { 241 242 // Update info about this frame. 243 unw_proc_info_t frameInfo; 244 if (unw_get_proc_info(&cursor2, &frameInfo) != UNW_ESUCCESS) { 245 _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): unw_step " 246 "failed => _URC_END_OF_STACK", 247 (void *)exception_object); 248 return _URC_FATAL_PHASE2_ERROR; 249 } 250 251 // When tracing, print state information. 252 if (_LIBUNWIND_TRACING_UNWINDING) { 253 char functionBuf[512]; 254 const char *functionName = functionBuf; 255 unw_word_t offset; 256 if ((unw_get_proc_name(&cursor2, functionBuf, sizeof(functionBuf), 257 &offset) != UNW_ESUCCESS) || 258 (frameInfo.start_ip + offset > frameInfo.end_ip)) 259 functionName = ".anonymous."; 260 _LIBUNWIND_TRACE_UNWINDING( 261 "unwind_phase2_forced(ex_ojb=%p): start_ip=0x%" PRIx64 262 ", func=%s, lsda=0x%" PRIx64 ", personality=0x%" PRIx64, 263 (void *)exception_object, frameInfo.start_ip, functionName, 264 frameInfo.lsda, frameInfo.handler); 265 } 266 267 // Call stop function at each frame. 268 _Unwind_Action action = 269 (_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE); 270 _Unwind_Reason_Code stopResult = 271 (*stop)(1, action, exception_object->exception_class, exception_object, 272 (struct _Unwind_Context *)(&cursor2), stop_parameter); 273 _LIBUNWIND_TRACE_UNWINDING( 274 "unwind_phase2_forced(ex_ojb=%p): stop function returned %d", 275 (void *)exception_object, stopResult); 276 if (stopResult != _URC_NO_REASON) { 277 _LIBUNWIND_TRACE_UNWINDING( 278 "unwind_phase2_forced(ex_ojb=%p): stopped by stop function", 279 (void *)exception_object); 280 return _URC_FATAL_PHASE2_ERROR; 281 } 282 283 // If there is a personality routine, tell it we are unwinding. 284 if (frameInfo.handler != 0) { 285 __personality_routine p = 286 (__personality_routine)(intptr_t)(frameInfo.handler); 287 _LIBUNWIND_TRACE_UNWINDING( 288 "unwind_phase2_forced(ex_ojb=%p): calling personality function %p", 289 (void *)exception_object, (void *)(uintptr_t)p); 290 _Unwind_Reason_Code personalityResult = 291 (*p)(1, action, exception_object->exception_class, exception_object, 292 (struct _Unwind_Context *)(&cursor2)); 293 switch (personalityResult) { 294 case _URC_CONTINUE_UNWIND: 295 _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " 296 "personality returned " 297 "_URC_CONTINUE_UNWIND", 298 (void *)exception_object); 299 // Destructors called, continue unwinding 300 break; 301 case _URC_INSTALL_CONTEXT: 302 _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " 303 "personality returned " 304 "_URC_INSTALL_CONTEXT", 305 (void *)exception_object); 306 // We may get control back if landing pad calls _Unwind_Resume(). 307 unw_resume(&cursor2); 308 break; 309 default: 310 // Personality routine returned an unknown result code. 311 _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " 312 "personality returned %d, " 313 "_URC_FATAL_PHASE2_ERROR", 314 (void *)exception_object, personalityResult); 315 return _URC_FATAL_PHASE2_ERROR; 316 } 317 } 318 } 319 320 // Call stop function one last time and tell it we've reached the end 321 // of the stack. 322 _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): calling stop " 323 "function with _UA_END_OF_STACK", 324 (void *)exception_object); 325 _Unwind_Action lastAction = 326 (_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE | _UA_END_OF_STACK); 327 (*stop)(1, lastAction, exception_object->exception_class, exception_object, 328 (struct _Unwind_Context *)(&cursor2), stop_parameter); 329 330 // Clean up phase did not resume at the frame that the search phase said it 331 // would. 332 return _URC_FATAL_PHASE2_ERROR; 333 } 334 335 /// Called by \c __cxa_throw(). Only returns if there is a fatal error. 336 _LIBUNWIND_EXPORT _Unwind_Reason_Code 337 _Unwind_RaiseException(_Unwind_Exception *exception_object) { 338 _LIBUNWIND_TRACE_API("_Unwind_RaiseException(ex_obj=%p)", 339 (void *)exception_object); 340 341 // Mark that this is a non-forced unwind, so _Unwind_Resume() 342 // can do the right thing. 343 memset(exception_object->private_, 0, sizeof(exception_object->private_)); 344 345 // phase 1: the search phase 346 // We'll let the system do that for us. 347 RaiseException(STATUS_GCC_THROW, 0, 1, (ULONG_PTR *)&exception_object); 348 349 // If we get here, either something went horribly wrong or we reached the 350 // top of the stack. Either way, let libc++abi call std::terminate(). 351 return _URC_END_OF_STACK; 352 } 353 354 /// When \c _Unwind_RaiseException() is in phase2, it hands control 355 /// to the personality function at each frame. The personality 356 /// may force a jump to a landing pad in that function; the landing 357 /// pad code may then call \c _Unwind_Resume() to continue with the 358 /// unwinding. Note: the call to \c _Unwind_Resume() is from compiler 359 /// geneated user code. All other \c _Unwind_* routines are called 360 /// by the C++ runtime \c __cxa_* routines. 361 /// 362 /// Note: re-throwing an exception (as opposed to continuing the unwind) 363 /// is implemented by having the code call \c __cxa_rethrow() which 364 /// in turn calls \c _Unwind_Resume_or_Rethrow(). 365 _LIBUNWIND_EXPORT void 366 _Unwind_Resume(_Unwind_Exception *exception_object) { 367 _LIBUNWIND_TRACE_API("_Unwind_Resume(ex_obj=%p)", (void *)exception_object); 368 369 if (exception_object->private_[0] != 0) { 370 unw_context_t uc; 371 372 unw_getcontext(&uc); 373 unwind_phase2_forced(&uc, exception_object, 374 (_Unwind_Stop_Fn) exception_object->private_[0], 375 (void *)exception_object->private_[4]); 376 } else { 377 // Recover the parameters for the unwind from the exception object 378 // so we can start unwinding again. 379 EXCEPTION_RECORD ms_exc; 380 CONTEXT ms_ctx; 381 UNWIND_HISTORY_TABLE hist; 382 383 memset(&ms_exc, 0, sizeof(ms_exc)); 384 memset(&hist, 0, sizeof(hist)); 385 ms_exc.ExceptionCode = STATUS_GCC_THROW; 386 ms_exc.ExceptionFlags = EXCEPTION_NONCONTINUABLE; 387 ms_exc.NumberParameters = 4; 388 ms_exc.ExceptionInformation[0] = (ULONG_PTR)exception_object; 389 ms_exc.ExceptionInformation[1] = exception_object->private_[1]; 390 ms_exc.ExceptionInformation[2] = exception_object->private_[2]; 391 ms_exc.ExceptionInformation[3] = exception_object->private_[3]; 392 RtlUnwindEx((PVOID)exception_object->private_[1], 393 (PVOID)exception_object->private_[2], &ms_exc, 394 exception_object, &ms_ctx, &hist); 395 } 396 397 // Clients assume _Unwind_Resume() does not return, so all we can do is abort. 398 _LIBUNWIND_ABORT("_Unwind_Resume() can't return"); 399 } 400 401 /// Not used by C++. 402 /// Unwinds stack, calling "stop" function at each frame. 403 /// Could be used to implement \c longjmp(). 404 _LIBUNWIND_EXPORT _Unwind_Reason_Code 405 _Unwind_ForcedUnwind(_Unwind_Exception *exception_object, 406 _Unwind_Stop_Fn stop, void *stop_parameter) { 407 _LIBUNWIND_TRACE_API("_Unwind_ForcedUnwind(ex_obj=%p, stop=%p)", 408 (void *)exception_object, (void *)(uintptr_t)stop); 409 unw_context_t uc; 410 unw_getcontext(&uc); 411 412 // Mark that this is a forced unwind, so _Unwind_Resume() can do 413 // the right thing. 414 exception_object->private_[0] = (uintptr_t) stop; 415 exception_object->private_[4] = (uintptr_t) stop_parameter; 416 417 // do it 418 return unwind_phase2_forced(&uc, exception_object, stop, stop_parameter); 419 } 420 421 /// Called by personality handler during phase 2 to get LSDA for current frame. 422 _LIBUNWIND_EXPORT uintptr_t 423 _Unwind_GetLanguageSpecificData(struct _Unwind_Context *context) { 424 uintptr_t result = (uintptr_t)_unw_seh_get_disp_ctx((unw_cursor_t *)context)->HandlerData; 425 _LIBUNWIND_TRACE_API( 426 "_Unwind_GetLanguageSpecificData(context=%p) => 0x%" PRIxPTR, 427 (void *)context, result); 428 return result; 429 } 430 431 /// Called by personality handler during phase 2 to find the start of the 432 /// function. 433 _LIBUNWIND_EXPORT uintptr_t 434 _Unwind_GetRegionStart(struct _Unwind_Context *context) { 435 DISPATCHER_CONTEXT *disp = _unw_seh_get_disp_ctx((unw_cursor_t *)context); 436 uintptr_t result = (uintptr_t)disp->FunctionEntry->BeginAddress + disp->ImageBase; 437 _LIBUNWIND_TRACE_API("_Unwind_GetRegionStart(context=%p) => 0x%" PRIxPTR, 438 (void *)context, result); 439 return result; 440 } 441 442 static int 443 _unw_init_seh(unw_cursor_t *cursor, CONTEXT *context) { 444 #ifdef _LIBUNWIND_TARGET_X86_64 445 new ((void *)cursor) UnwindCursor<LocalAddressSpace, Registers_x86_64>( 446 context, LocalAddressSpace::sThisAddressSpace); 447 auto *co = reinterpret_cast<AbstractUnwindCursor *>(cursor); 448 co->setInfoBasedOnIPRegister(); 449 return UNW_ESUCCESS; 450 #elif defined(_LIBUNWIND_TARGET_ARM) 451 new ((void *)cursor) UnwindCursor<LocalAddressSpace, Registers_arm>( 452 context, LocalAddressSpace::sThisAddressSpace); 453 auto *co = reinterpret_cast<AbstractUnwindCursor *>(cursor); 454 co->setInfoBasedOnIPRegister(); 455 return UNW_ESUCCESS; 456 #elif defined(_LIBUNWIND_TARGET_AARCH64) 457 new ((void *)cursor) UnwindCursor<LocalAddressSpace, Registers_arm64>( 458 context, LocalAddressSpace::sThisAddressSpace); 459 auto *co = reinterpret_cast<AbstractUnwindCursor *>(cursor); 460 co->setInfoBasedOnIPRegister(); 461 return UNW_ESUCCESS; 462 #else 463 return UNW_EINVAL; 464 #endif 465 } 466 467 static DISPATCHER_CONTEXT * 468 _unw_seh_get_disp_ctx(unw_cursor_t *cursor) { 469 #ifdef _LIBUNWIND_TARGET_X86_64 470 return reinterpret_cast<UnwindCursor<LocalAddressSpace, Registers_x86_64> *>(cursor)->getDispatcherContext(); 471 #elif defined(_LIBUNWIND_TARGET_ARM) 472 return reinterpret_cast<UnwindCursor<LocalAddressSpace, Registers_arm> *>(cursor)->getDispatcherContext(); 473 #elif defined(_LIBUNWIND_TARGET_AARCH64) 474 return reinterpret_cast<UnwindCursor<LocalAddressSpace, Registers_arm64> *>(cursor)->getDispatcherContext(); 475 #else 476 return nullptr; 477 #endif 478 } 479 480 static void 481 _unw_seh_set_disp_ctx(unw_cursor_t *cursor, DISPATCHER_CONTEXT *disp) { 482 #ifdef _LIBUNWIND_TARGET_X86_64 483 reinterpret_cast<UnwindCursor<LocalAddressSpace, Registers_x86_64> *>(cursor)->setDispatcherContext(disp); 484 #elif defined(_LIBUNWIND_TARGET_ARM) 485 reinterpret_cast<UnwindCursor<LocalAddressSpace, Registers_arm> *>(cursor)->setDispatcherContext(disp); 486 #elif defined(_LIBUNWIND_TARGET_AARCH64) 487 reinterpret_cast<UnwindCursor<LocalAddressSpace, Registers_arm64> *>(cursor)->setDispatcherContext(disp); 488 #endif 489 } 490 491 #endif // defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) 492