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