summaryrefslogtreecommitdiff
path: root/src/pal/src/exception/seh-unwind.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/pal/src/exception/seh-unwind.cpp')
-rw-r--r--src/pal/src/exception/seh-unwind.cpp22
1 files changed, 22 insertions, 0 deletions
diff --git a/src/pal/src/exception/seh-unwind.cpp b/src/pal/src/exception/seh-unwind.cpp
index 6a547979b1..8d9a06b144 100644
--- a/src/pal/src/exception/seh-unwind.cpp
+++ b/src/pal/src/exception/seh-unwind.cpp
@@ -125,6 +125,9 @@ BOOL PAL_VirtualUnwind(CONTEXT *context, KNONVOLATILE_CONTEXT_POINTERS *contextP
int st;
unw_context_t unwContext;
unw_cursor_t cursor;
+#if defined(__APPLE__)
+ DWORD64 curPc;
+#endif
#if UNWIND_CONTEXT_IS_UCONTEXT_T
WinContextToUnwindContext(context, &unwContext);
@@ -147,6 +150,18 @@ BOOL PAL_VirtualUnwind(CONTEXT *context, KNONVOLATILE_CONTEXT_POINTERS *contextP
WinContextToUnwindCursor(context, &cursor);
#endif
+#if defined(__APPLE__)
+ // OSX appears to do two different things when unwinding
+ // 1: If it reaches where it cannot unwind anymore, say a
+ // managed frame. It wil return 0, but also update the $pc
+ // 2: If it unwinds all the way to _start it will return
+ // 0 from the step, but $pc will stay the same.
+ // The behaviour of libunwind from nongnu.org is to null the PC
+ // So we bank the original PC here, so we can compare it after
+ // the step
+ curPc = context->Rip;
+#endif
+
st = unw_step(&cursor);
if (st < 0)
{
@@ -154,7 +169,14 @@ BOOL PAL_VirtualUnwind(CONTEXT *context, KNONVOLATILE_CONTEXT_POINTERS *contextP
}
// Update the passed in windows context to reflect the unwind
+ //
UnwindContextToWinContext(&cursor, context);
+#if defined(__APPLE__)
+ if (st == 0 && context->Rip == curPc)
+ {
+ context->Rip = 0;
+ }
+#endif
if (contextPointers != NULL)
{