Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[release/9.0-staging] [debugger] Support step into a tail call #110438

Merged
Merged
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
25 changes: 21 additions & 4 deletions src/coreclr/debug/ee/controller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ const char *GetTType( TraceType tt);

#define IsSingleStep(exception) ((exception) == EXCEPTION_SINGLE_STEP)

typedef enum __TailCallFunctionType {
TailCallThatReturns = 1,
StoreTailCallArgs = 2
} TailCallFunctionType;

// -------------------------------------------------------------------------
// DebuggerController routines
// -------------------------------------------------------------------------
Expand Down Expand Up @@ -5631,10 +5636,10 @@ static bool IsTailCallJitHelper(const BYTE * ip)
// control flow will be a little peculiar in that the function will return
// immediately, so we need special handling in the debugger for it. This
// function detects that case to be used for those scenarios.
static bool IsTailCallThatReturns(const BYTE * ip, ControllerStackInfo* info)
static bool IsTailCall(const BYTE * ip, ControllerStackInfo* info, TailCallFunctionType type)
{
MethodDesc* pTailCallDispatcherMD = TailCallHelp::GetTailCallDispatcherMD();
if (pTailCallDispatcherMD == NULL)
if (pTailCallDispatcherMD == NULL && type == TailCallFunctionType::TailCallThatReturns)
{
return false;
}
Expand All @@ -5650,6 +5655,11 @@ static bool IsTailCallThatReturns(const BYTE * ip, ControllerStackInfo* info)
? trace.GetMethodDesc()
: g_pEEInterface->GetNativeCodeMethodDesc(trace.GetAddress());

if (type == TailCallFunctionType::StoreTailCallArgs)
{
return (pTargetMD->IsDynamicMethod() && pTargetMD->AsDynamicMethodDesc()->GetILStubType() == DynamicMethodDesc::StubTailCallStoreArgs);
}

if (pTargetMD != pTailCallDispatcherMD)
{
return false;
Expand Down Expand Up @@ -5881,6 +5891,13 @@ bool DebuggerStepper::TrapStep(ControllerStackInfo *info, bool in)
fCallingIntoFunclet = IsAddrWithinMethodIncludingFunclet(ji, info->m_activeFrame.md, walker.GetNextIP()) &&
((CORDB_ADDRESS)(SIZE_T)walker.GetNextIP() != ji->m_addrOfCode);
#endif
// If we are stepping into a tail call that uses the StoreTailCallArgs
// we need to enable the method enter, otherwise it will behave like a resume
if (in && IsTailCall(walker.GetNextIP(), info, TailCallFunctionType::StoreTailCallArgs))
{
EnableMethodEnter();
return true;
}
// At this point, we know that the call/branch target is not
// in the current method. The possible cases is that this is
// a jump or a tailcall-via-helper. There are two separate
Expand All @@ -5892,7 +5909,7 @@ bool DebuggerStepper::TrapStep(ControllerStackInfo *info, bool in)
// is done by stepping out to the previous user function
// (non IL stub).
if ((fIsJump && !fCallingIntoFunclet) || IsTailCallJitHelper(walker.GetNextIP()) ||
IsTailCallThatReturns(walker.GetNextIP(), info))
IsTailCall(walker.GetNextIP(), info, TailCallFunctionType::TailCallThatReturns))
{
// A step-over becomes a step-out for a tail call.
if (!in)
Expand Down Expand Up @@ -6038,7 +6055,7 @@ bool DebuggerStepper::TrapStep(ControllerStackInfo *info, bool in)
return true;
}

if (IsTailCallJitHelper(walker.GetNextIP()) || IsTailCallThatReturns(walker.GetNextIP(), info))
if (IsTailCallJitHelper(walker.GetNextIP()) || IsTailCall(walker.GetNextIP(), info, TailCallFunctionType::TailCallThatReturns))
{
if (!in)
{
Expand Down
Loading