From cf2be048df37d7bc76f9f4b3ace18777b5aa440b Mon Sep 17 00:00:00 2001 From: Thays Grazia Date: Mon, 2 Dec 2024 19:06:13 -0300 Subject: [PATCH] Support step into a tail call Addressing Tom's and Mikelle's comments Removing unrelated change and adding enum Changing the comment. --- src/coreclr/debug/ee/controller.cpp | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/src/coreclr/debug/ee/controller.cpp b/src/coreclr/debug/ee/controller.cpp index fd26e7fe3135dd..9150879ac006a1 100644 --- a/src/coreclr/debug/ee/controller.cpp +++ b/src/coreclr/debug/ee/controller.cpp @@ -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 // ------------------------------------------------------------------------- @@ -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; } @@ -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; @@ -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 @@ -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) @@ -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) {