Skip to content
Merged
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
16 changes: 14 additions & 2 deletions src/coreclr/debug/createdump/threadinfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ ThreadInfo::UnwindNativeFrames(CONTEXT* pContext)
uint64_t previousSp = 0;
uint64_t previousIp = 0;
int ipMatchCount = 0;
bool isSignalFrame = false;
bool crossedSignalTrampoline = 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 @@ -69,10 +71,19 @@ ThreadInfo::UnwindNativeFrames(CONTEXT* pContext)
sp++;
}
#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.
// Allow the SP decrease if the current frame is a signal trampoline (detected by the
// previous unwind call) and we haven't already crossed one (limit to one crossing to
// bound corruption damage).
if (ip == 0 || sp == 0 || (sp <= previousSp && (!isSignalFrame || crossedSignalTrampoline))) {
TRACE_VERBOSE("Unwind: sp not increasing or ip == 0 sp %p ip %p\n", (void*)sp, (void*)ip);
break;
}
if (sp < previousSp)
{
crossedSignalTrampoline = true;
}
// Break out of the endless loop if the IP matches over a 1000 times. This is a fallback
// behavior of libunwind when the module the IP is in doesn't have unwind info and for
// simple stack overflows. The stack memory is added to the dump in GetThreadStack and
Expand Down Expand Up @@ -104,7 +115,8 @@ 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)) {
isSignalFrame = false;
if (!PAL_VirtualUnwindOutOfProc(pContext, &functionStart, baseAddress, ReadMemoryAdapter, &isSignalFrame)) {
TRACE("Unwind: PAL_VirtualUnwindOutOfProc returned false\n");
break;
}
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 @@ -2335,7 +2335,7 @@ typedef BOOL(*UnwindReadMemoryCallback)(PVOID address, PVOID buffer, SIZE_T size

PALIMPORT BOOL PALAPI PAL_VirtualUnwind(CONTEXT *context);

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
18 changes: 16 additions & 2 deletions src/coreclr/pal/src/exception/remote-unwind.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2328,17 +2328,23 @@ static unw_accessors_t unwind_accessors = init_unwind_accessors();
functionStart - the pointer to return the starting address of the function or nullptr
baseAddress - base address of the module to find the unwind info
readMemoryCallback - reads memory from the target
isSignalFrame - output parameter: set to true if the unwound-to frame is a signal trampoline
--*/
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 @@ -2410,6 +2416,14 @@ PAL_VirtualUnwindOutOfProc(CONTEXT *context, PULONG64 functionStart, SIZE_T base
goto exit;
}

// Check if the frame we landed on is a signal trampoline. When a signal handler uses
// SA_ONSTACK, stepping from a signal frame crosses from the alternate signal stack to the
// original thread stack, which can cause the SP to decrease.
if (isSignalFrame && unw_is_signal_frame(&cursor) > 0)
{
*isSignalFrame = true;
}

UnwindContextToContext(&cursor, context);

result = TRUE;
Expand Down Expand Up @@ -2572,7 +2586,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)
{
Comment thread
hoyosjs marked this conversation as resolved.
return FALSE;
}
Expand Down
Loading