From c94716b6d0977cad1a42c84b55be4628a20076dc Mon Sep 17 00:00:00 2001 From: Geoff Norton Date: Wed, 18 Mar 2015 20:58:12 -0700 Subject: [PATCH] Fix unwinding past main on OSX When reaching the bottom of the real stack, OSX does not change the $pc to 0x0, like llvm libunwind. It returns 0 from unw_step, and leaves the $pc unchanged, so we will track cur and prev pc and guard for this as well Fixes Localloc codegen test, and also verified a simple throw from main works as expected. --- src/pal/src/exception/seh-unwind.cpp | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/pal/src/exception/seh-unwind.cpp b/src/pal/src/exception/seh-unwind.cpp index 6a547979b1fc..8d9a06b144eb 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) {