Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions src/coreclr/debug/createdump/createdumppal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ typedef BOOL (*PFN_PAL_VirtualUnwindOutOfProc)(
CONTEXT *context,
PULONG64 functionStart,
SIZE_T baseAddress,
UnwindReadMemoryCallback readMemoryCallback);
UnwindReadMemoryCallback readMemoryCallback,
BOOL *isSignalFrame);

typedef BOOL (*PFN_PAL_GetUnwindInfoSize)(
SIZE_T baseAddress,
Expand Down Expand Up @@ -129,13 +130,14 @@ PAL_VirtualUnwindOutOfProc(
CONTEXT *context,
PULONG64 functionStart,
SIZE_T baseAddress,
UnwindReadMemoryCallback readMemoryCallback)
UnwindReadMemoryCallback readMemoryCallback,
BOOL *isSignalFrame)
{
if (!InitializePAL() || g_PAL_VirtualUnwindOutOfProc == nullptr)
{
return FALSE;
}
return g_PAL_VirtualUnwindOutOfProc(context, functionStart, baseAddress, readMemoryCallback);
return g_PAL_VirtualUnwindOutOfProc(context, functionStart, baseAddress, readMemoryCallback, isSignalFrame);
}

BOOL
Expand Down
17 changes: 16 additions & 1 deletion src/coreclr/debug/createdump/threadinfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ ThreadInfo::UnwindNativeFrames(CONTEXT* pContext)
uint64_t previousSp = 0;
uint64_t previousIp = 0;
int ipMatchCount = 0;
bool previousFrameWasSignal = false;

// For each native frame, add a page around the IP and any unwind info not already
// added in VisitProgramHeader (Linux) and VisitSection (MacOS) to the dump.
Expand All @@ -70,6 +71,18 @@ ThreadInfo::UnwindNativeFrames(CONTEXT* pContext)
}
#endif
if (ip == 0 || sp <= previousSp) {
// When a signal handler uses SA_ONSTACK (alternate signal stack), the SP can legitimately
// decrease when unwinding crosses the signal trampoline back to the original thread stack.
// This commonly happens on secondary threads where both the thread stack and alt stack are
// mmap'd, with the alt stack at a higher address. Allow one SP decrease if the previous
// frame was a signal trampoline.
if (ip != 0 && sp != 0 && sp < previousSp && previousFrameWasSignal) {
TRACE("Unwind: signal trampoline crossing detected sp %p -> %p\n", (void*)previousSp, (void*)sp);
previousSp = sp - 1;
previousIp = ip;
previousFrameWasSignal = false;
continue;
}
TRACE_VERBOSE("Unwind: sp not increasing or ip == 0 sp %p ip %p\n", (void*)sp, (void*)ip);
break;
}
Expand Down Expand Up @@ -104,10 +117,12 @@ ThreadInfo::UnwindNativeFrames(CONTEXT* pContext)

// Unwind the native frame adding all the memory accessed to the core dump via the read memory adapter.
ULONG64 functionStart;
if (!PAL_VirtualUnwindOutOfProc(pContext, &functionStart, baseAddress, ReadMemoryAdapter)) {
BOOL isSignalFrame = FALSE;
if (!PAL_VirtualUnwindOutOfProc(pContext, &functionStart, baseAddress, ReadMemoryAdapter, &isSignalFrame)) {
TRACE("Unwind: PAL_VirtualUnwindOutOfProc returned false\n");
break;
}
previousFrameWasSignal = (isSignalFrame != FALSE);

if (m_crashInfo.GatherFrames())
{
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/pal/inc/pal.h
Original file line number Diff line number Diff line change
Expand Up @@ -2494,7 +2494,7 @@ typedef BOOL(*UnwindReadMemoryCallback)(PVOID address, PVOID buffer, SIZE_T size

PALIMPORT BOOL PALAPI PAL_VirtualUnwind(CONTEXT *context, KNONVOLATILE_CONTEXT_POINTERS *contextPointers);

PALIMPORT BOOL PALAPI PAL_VirtualUnwindOutOfProc(CONTEXT *context, PULONG64 functionStart, SIZE_T baseAddress, UnwindReadMemoryCallback readMemoryCallback);
PALIMPORT BOOL PALAPI PAL_VirtualUnwindOutOfProc(CONTEXT *context, PULONG64 functionStart, SIZE_T baseAddress, UnwindReadMemoryCallback readMemoryCallback, BOOL *isSignalFrame);

PALIMPORT BOOL PALAPI PAL_GetUnwindInfoSize(SIZE_T baseAddress, ULONG64 ehFrameHdrAddr, UnwindReadMemoryCallback readMemoryCallback, PULONG64 ehFrameStart, PULONG64 ehFrameSize);

Expand Down
23 changes: 21 additions & 2 deletions src/coreclr/pal/src/exception/remote-unwind.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2337,14 +2337,19 @@ static unw_accessors_t unwind_accessors = init_unwind_accessors();
--*/
BOOL
PALAPI
PAL_VirtualUnwindOutOfProc(CONTEXT *context, PULONG64 functionStart, SIZE_T baseAddress, UnwindReadMemoryCallback readMemoryCallback)
PAL_VirtualUnwindOutOfProc(CONTEXT *context, PULONG64 functionStart, SIZE_T baseAddress, UnwindReadMemoryCallback readMemoryCallback, BOOL *isSignalFrame)
{
unw_addr_space_t addrSpace = 0;
unw_cursor_t cursor;
libunwindInfo info;
BOOL result = FALSE;
int st;

if (isSignalFrame)
{
*isSignalFrame = FALSE;
}

info.BaseAddress = baseAddress;
info.Context = context;
info.FunctionStart = 0;
Expand Down Expand Up @@ -2409,6 +2414,20 @@ PAL_VirtualUnwindOutOfProc(CONTEXT *context, PULONG64 functionStart, SIZE_T base
goto exit;
}

// Check if the current frame is a signal trampoline before stepping. When the signal handler
// uses SA_ONSTACK, stepping past a signal frame crosses from the alternate signal stack to the
// original thread stack, which can cause the SP to decrease.
// Note: unw_is_signal_frame requires the cursor's proc_info to be populated. unw_init_remote
// does not call find_proc_info, so we force it via unw_get_proc_info first.
if (isSignalFrame)
{
unw_proc_info_t procInfo;
if (unw_get_proc_info(&cursor, &procInfo) == 0 && unw_is_signal_frame(&cursor) > 0)
{
*isSignalFrame = TRUE;
}
}

st = unw_step(&cursor);
if (st < 0)
{
Expand Down Expand Up @@ -2578,7 +2597,7 @@ PAL_GetUnwindInfoSize(SIZE_T baseAddress, ULONG64 ehFrameHdrAddr, UnwindReadMemo

BOOL
PALAPI
PAL_VirtualUnwindOutOfProc(CONTEXT *context, PULONG64 functionStart, SIZE_T baseAddress, UnwindReadMemoryCallback readMemoryCallback)
PAL_VirtualUnwindOutOfProc(CONTEXT *context, PULONG64 functionStart, SIZE_T baseAddress, UnwindReadMemoryCallback readMemoryCallback, BOOL *isSignalFrame)
{
return FALSE;
}
Expand Down
Loading