Skip to content

Commit 5a5ea3e

Browse files
authored
Support step into a tail call (dotnet#110334)
1 parent c3e1bc3 commit 5a5ea3e

File tree

1 file changed

+21
-4
lines changed

1 file changed

+21
-4
lines changed

src/coreclr/debug/ee/controller.cpp

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@ const char *GetTType( TraceType tt);
2525

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

28+
typedef enum __TailCallFunctionType {
29+
TailCallThatReturns = 1,
30+
StoreTailCallArgs = 2
31+
} TailCallFunctionType;
32+
2833
// -------------------------------------------------------------------------
2934
// DebuggerController routines
3035
// -------------------------------------------------------------------------
@@ -5789,10 +5794,10 @@ static bool IsTailCallJitHelper(const BYTE * ip)
57895794
// control flow will be a little peculiar in that the function will return
57905795
// immediately, so we need special handling in the debugger for it. This
57915796
// function detects that case to be used for those scenarios.
5792-
static bool IsTailCallThatReturns(const BYTE * ip, ControllerStackInfo* info)
5797+
static bool IsTailCall(const BYTE * ip, ControllerStackInfo* info, TailCallFunctionType type)
57935798
{
57945799
MethodDesc* pTailCallDispatcherMD = TailCallHelp::GetTailCallDispatcherMD();
5795-
if (pTailCallDispatcherMD == NULL)
5800+
if (pTailCallDispatcherMD == NULL && type == TailCallFunctionType::TailCallThatReturns)
57965801
{
57975802
return false;
57985803
}
@@ -5808,6 +5813,11 @@ static bool IsTailCallThatReturns(const BYTE * ip, ControllerStackInfo* info)
58085813
? trace.GetMethodDesc()
58095814
: g_pEEInterface->GetNativeCodeMethodDesc(trace.GetAddress());
58105815

5816+
if (type == TailCallFunctionType::StoreTailCallArgs)
5817+
{
5818+
return (pTargetMD->IsDynamicMethod() && pTargetMD->AsDynamicMethodDesc()->GetILStubType() == DynamicMethodDesc::StubTailCallStoreArgs);
5819+
}
5820+
58115821
if (pTargetMD != pTailCallDispatcherMD)
58125822
{
58135823
return false;
@@ -6039,6 +6049,13 @@ bool DebuggerStepper::TrapStep(ControllerStackInfo *info, bool in)
60396049
fCallingIntoFunclet = IsAddrWithinMethodIncludingFunclet(ji, info->m_activeFrame.md, walker.GetNextIP()) &&
60406050
((CORDB_ADDRESS)(SIZE_T)walker.GetNextIP() != ji->m_addrOfCode);
60416051
#endif
6052+
// If we are stepping into a tail call that uses the StoreTailCallArgs
6053+
// we need to enable the method enter, otherwise it will behave like a resume
6054+
if (in && IsTailCall(walker.GetNextIP(), info, TailCallFunctionType::StoreTailCallArgs))
6055+
{
6056+
EnableMethodEnter();
6057+
return true;
6058+
}
60426059
// At this point, we know that the call/branch target is not
60436060
// in the current method. The possible cases is that this is
60446061
// a jump or a tailcall-via-helper. There are two separate
@@ -6050,7 +6067,7 @@ bool DebuggerStepper::TrapStep(ControllerStackInfo *info, bool in)
60506067
// is done by stepping out to the previous user function
60516068
// (non IL stub).
60526069
if ((fIsJump && !fCallingIntoFunclet) || IsTailCallJitHelper(walker.GetNextIP()) ||
6053-
IsTailCallThatReturns(walker.GetNextIP(), info))
6070+
IsTailCall(walker.GetNextIP(), info, TailCallFunctionType::TailCallThatReturns))
60546071
{
60556072
// A step-over becomes a step-out for a tail call.
60566073
if (!in)
@@ -6196,7 +6213,7 @@ bool DebuggerStepper::TrapStep(ControllerStackInfo *info, bool in)
61966213
return true;
61976214
}
61986215

6199-
if (IsTailCallJitHelper(walker.GetNextIP()) || IsTailCallThatReturns(walker.GetNextIP(), info))
6216+
if (IsTailCallJitHelper(walker.GetNextIP()) || IsTailCall(walker.GetNextIP(), info, TailCallFunctionType::TailCallThatReturns))
62006217
{
62016218
if (!in)
62026219
{

0 commit comments

Comments
 (0)