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

Update stepping through ExternalMethodFixup under the Debugger #108942

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
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
93 changes: 92 additions & 1 deletion src/coreclr/debug/ee/controller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -944,7 +944,8 @@ DebuggerController::DebuggerController(Thread * pThread, AppDomain * pAppDomain)
m_eventQueuedCount(0),
m_deleted(false),
m_fEnableMethodEnter(false),
m_multicastDelegateHelper(false)
m_multicastDelegateHelper(false),
m_externalMethodFixup(false)
{
CONTRACTL
{
Expand Down Expand Up @@ -1136,6 +1137,8 @@ void DebuggerController::DisableAll()
DisableMethodEnter();
if (m_multicastDelegateHelper)
DisableMultiCastDelegate();
if (m_externalMethodFixup)
DisableExternalMethodFixup();
}
}

Expand Down Expand Up @@ -2397,6 +2400,10 @@ bool DebuggerController::PatchTrace(TraceDestination *trace,
EnableMultiCastDelegate();
return true;

case TRACE_EXTERNAL_METHOD_FIXUP:
EnableExternalMethodFixup();
return true;

case TRACE_OTHER:
LOG((LF_CORDB, LL_INFO10000,
"Can't set a trace patch for TRACE_OTHER...\n"));
Expand Down Expand Up @@ -3975,6 +3982,74 @@ void DebuggerController::DispatchMulticastDelegate(DELEGATEREF pbDel, INT32 coun
p = p->m_next;
}
}

void DebuggerController::EnableExternalMethodFixup()
{
CONTRACTL
{
NOTHROW;
GC_NOTRIGGER;
}
CONTRACTL_END;

ControllerLockHolder chController;
if (!m_externalMethodFixup)
{
LOG((LF_CORDB, LL_INFO1000000, "DC::EnableExternalMethodFixup, this=%p, previously disabled\n", this));
m_externalMethodFixup = true;
g_externalMethodFixupTraceActiveCount += 1;
}
else
{
LOG((LF_CORDB, LL_INFO1000000, "DC::EnableExternalMethodFixup, this=%p, already set\n", this));
}
}

void DebuggerController::DisableExternalMethodFixup()
{
CONTRACTL
{
NOTHROW;
GC_NOTRIGGER;
}
CONTRACTL_END;

ControllerLockHolder chController;
if (m_externalMethodFixup)
{
LOG((LF_CORDB, LL_INFO10000, "DC::DisableExternalMethodFixup, this=%p, previously set\n", this));
m_externalMethodFixup = false;
g_externalMethodFixupTraceActiveCount -= 1;
}
else
{
LOG((LF_CORDB, LL_INFO10000, "DC::DisableExternalMethodFixup, this=%p, already disabled\n", this));
}
}

// Loop through controllers and dispatch TriggerExternalMethodFixup
void DebuggerController::DispatchExternalMethodFixup(PCODE addr)
{
LOG((LF_CORDB, LL_INFO10000, "DC::DispatchExternalMethodFixup\n"));

Thread * pThread = g_pEEInterface->GetThread();
_ASSERTE(pThread != NULL);

ControllerLockHolder lockController;

DebuggerController *p = g_controllers;
while (p != NULL)
{
if (p->m_externalMethodFixup)
{
if ((p->GetThread() == NULL) || (p->GetThread() == pThread))
{
p->TriggerExternalMethodFixup(addr);
}
}
p = p->m_next;
}
}
//
// AddProtection adds page protection to (at least) the given range of
// addresses
Expand Down Expand Up @@ -4123,6 +4198,10 @@ void DebuggerController::TriggerMulticastDelegate(DELEGATEREF pDel, INT32 delega
{
_ASSERTE(!"This code should be unreachable. If your controller enables MulticastDelegateHelper events,it should also override this callback to do something useful when the event arrives.");
}
void DebuggerController::TriggerExternalMethodFixup(PCODE target)
{
_ASSERTE(!"This code should be unreachable. If your controller enables ExternalMethodFixup events,it should also override this callback to do something useful when the event arrives.");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: the same missing space is in the message above too

Suggested change
_ASSERTE(!"This code should be unreachable. If your controller enables ExternalMethodFixup events,it should also override this callback to do something useful when the event arrives.");
_ASSERTE(!"This code should be unreachable. If your controller enables ExternalMethodFixup events, it should also override this callback to do something useful when the event arrives.");

}


#ifdef _DEBUG
Expand Down Expand Up @@ -7701,6 +7780,18 @@ void DebuggerStepper::TriggerMulticastDelegate(DELEGATEREF pDel, INT32 delegateC
this->DisableMultiCastDelegate();
}

void DebuggerStepper::TriggerExternalMethodFixup(PCODE target)
{
TraceDestination trace;
FramePointer fp = LEAF_MOST_FRAME;

trace.InitForStub(target);
g_pEEInterface->FollowTrace(&trace);
//fStopInUnmanaged only matters for TRACE_UNMANAGED
PatchTrace(&trace, fp, /*fStopInUnmanaged*/false);
this->DisableExternalMethodFixup();
}

// Prepare for sending an event.
// This is called 1:1 w/ SendEvent, but this method can be called in a GC_TRIGGERABLE context
// whereas SendEvent is pretty strict.
Expand Down
8 changes: 8 additions & 0 deletions src/coreclr/debug/ee/controller.h
Original file line number Diff line number Diff line change
Expand Up @@ -1095,6 +1095,7 @@ class DebuggerController
// fp is the frame pointer for that method.
static void DispatchMethodEnter(void * pIP, FramePointer fp);
static void DispatchMulticastDelegate(DELEGATEREF pbDel, INT32 countDel);
static void DispatchExternalMethodFixup(PCODE addr);


// Delete any patches that exist for a specific module and optionally a specific AppDomain.
Expand Down Expand Up @@ -1318,6 +1319,9 @@ class DebuggerController
void EnableMultiCastDelegate();
void DisableMultiCastDelegate();

void EnableExternalMethodFixup();
void DisableExternalMethodFixup();

void DisableAll();

virtual DEBUGGER_CONTROLLER_TYPE GetDCType( void )
Expand Down Expand Up @@ -1419,6 +1423,8 @@ class DebuggerController

virtual void TriggerMulticastDelegate(DELEGATEREF pDel, INT32 delegateCount);

virtual void TriggerExternalMethodFixup(PCODE target);

// Send the managed debug event.
// This is called after TriggerPatch/TriggerSingleStep actually trigger.
// Note this can have a strange interaction with SetIp. Specifically this thread:
Expand Down Expand Up @@ -1458,6 +1464,7 @@ class DebuggerController
bool m_deleted;
bool m_fEnableMethodEnter;
bool m_multicastDelegateHelper;
bool m_externalMethodFixup;

#endif // !DACCESS_COMPILE
};
Expand Down Expand Up @@ -1696,6 +1703,7 @@ class DebuggerStepper : public DebuggerController

virtual void TriggerMethodEnter(Thread * thread, DebuggerJitInfo * dji, const BYTE * ip, FramePointer fp);
void TriggerMulticastDelegate(DELEGATEREF pDel, INT32 delegateCount);
void TriggerExternalMethodFixup(PCODE target);

void ResetRange();

Expand Down
4 changes: 4 additions & 0 deletions src/coreclr/debug/ee/debugger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16793,6 +16793,10 @@ void Debugger::MulticastTraceNextStep(DELEGATEREF pbDel, INT32 count)
{
DebuggerController::DispatchMulticastDelegate(pbDel, count);
}
void Debugger::ExternalMethodFixupNextStep(PCODE address)
{
DebuggerController::DispatchExternalMethodFixup(address);
}
#endif //DACCESS_COMPILE

#endif //DEBUGGING_SUPPORTED
1 change: 1 addition & 0 deletions src/coreclr/debug/ee/debugger.h
Original file line number Diff line number Diff line change
Expand Up @@ -2613,6 +2613,7 @@ class Debugger : public DebugInterface
HRESULT ReDaclEvents(PSECURITY_DESCRIPTOR securityDescriptor);
#ifndef DACCESS_COMPILE
void MulticastTraceNextStep(DELEGATEREF pbDel, INT32 count);
void ExternalMethodFixupNextStep(PCODE address);
#endif

#ifdef DACCESS_COMPILE
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/vm/dbginterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,7 @@ class DebugInterface
virtual HRESULT DeoptimizeMethod(Module* pModule, mdMethodDef methodDef) = 0;
virtual HRESULT IsMethodDeoptimized(Module *pModule, mdMethodDef methodDef, BOOL *pResult) = 0;
virtual void MulticastTraceNextStep(DELEGATEREF pbDel, INT32 count) = 0;
virtual void ExternalMethodFixupNextStep(PCODE address) = 0;
#endif //DACCESS_COMPILE
};

Expand Down
5 changes: 5 additions & 0 deletions src/coreclr/vm/prestub.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "array.h"
#include "ecall.h"
#include "virtualcallstub.h"
#include "../debug/ee/debugger.h"

#ifdef FEATURE_INTERPRETER
#include "interpreter.h"
Expand Down Expand Up @@ -3401,6 +3402,10 @@ EXTERN_C PCODE STDCALL ExternalMethodFixupWorker(TransitionBlock * pTransitionBl
pEMFrame->Pop(CURRENT_THREAD); // Pop the ExternalMethodFrame from the frame stack

END_PRESERVE_LAST_ERROR;
if (g_externalMethodFixupTraceActiveCount > 0)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd suggest moving this code up to 3398. The INSTALL/UNINSTALL_xyz macros are creating try/catch regions to handle exceptions. I don't expect the debugger code to throw exceptions in any normal circumstance, but if there were some error (for example memory is corrupted causing an AV or stack space runs out) then its nice to treat those errors the same way as if they had happened anywhere else in the method body. Also the END_PRESERVE_LAST_ERROR macro is ensuring that the thread local GetLastError() value gets restored before this method returns. Its easier to put our debugger call above that point than to audit ensuring that nothing in the debugger call would ever cause it to change.

{
g_pDebugger->ExternalMethodFixupNextStep(pCode);
}

return pCode;
}
Expand Down
13 changes: 6 additions & 7 deletions src/coreclr/vm/stubmgr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ const char *GetTType( TraceType tt)
case TRACE_OTHER: return "TRACE_OTHER";
case TRACE_UNJITTED_METHOD: return "TRACE_UNJITTED_METHOD";
case TRACE_MULTICAST_DELEGATE_HELPER: return "TRACE_MULTICAST_DELEGATE_HELPER";
case TRACE_EXTERNAL_METHOD_FIXUP: return "TRACE_EXTERNAL_METHOD_FIXUP";
}
return "TRACE_REALLY_WACKED";
}
Expand Down Expand Up @@ -123,6 +124,10 @@ const CHAR * TraceDestination::DbgToString(SString & buffer)
pValue = "TRACE_MULTICAST_DELEGATE_HELPER";
break;

case TRACE_EXTERNAL_METHOD_FIXUP:
pValue = "TRACE_EXTERNAL_METHOD_FIXUP";
break;

case TRACE_OTHER:
pValue = "TRACE_OTHER";
break;
Expand Down Expand Up @@ -1563,13 +1568,7 @@ BOOL RangeSectionStubManager::DoTraceStub(PCODE stubStartAddress, TraceDestinati
#ifdef DACCESS_COMPILE
DacNotImpl();
#else
#if defined(TARGET_ARM64) && defined(__APPLE__)
// On ARM64 Mac, we cannot put a breakpoint inside of ExternalMethodFixupPatchLabel
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Delete all occurrences of ExternalMethodFixupPatchLabel?

LOG((LF_CORDB, LL_INFO10000, "RSM::DoTraceStub: Skipping on arm64-macOS\n"));
return FALSE;
#else
trace->InitForManagerPush(GetEEFuncEntryPoint(ExternalMethodFixupPatchLabel), this);
#endif //defined(TARGET_ARM64) && defined(__APPLE__)
trace->InitForExternalMethodFixup();
#endif
return TRUE;

Expand Down
8 changes: 8 additions & 0 deletions src/coreclr/vm/stubmgr.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ enum TraceType
TRACE_FRAME_PUSH, // Don't know where stub goes, stop at address, and then ask the frame that is on the stack
TRACE_MGR_PUSH, // Don't know where stub goes, stop at address then call TraceManager() below to find out
TRACE_MULTICAST_DELEGATE_HELPER, // Stub goes to a multicast delegate helper
TRACE_EXTERNAL_METHOD_FIXUP, // Stub goes to an external method fixup helper

TRACE_OTHER // We are going somewhere you can't step into (eg. ee helper function)
};
Expand Down Expand Up @@ -156,6 +157,13 @@ class TraceDestination
this->stubManager = NULL;
}

void InitForExternalMethodFixup()
{
this->type = TRACE_EXTERNAL_METHOD_FIXUP;
this->address = (PCODE)NULL;
this->stubManager = NULL;
}

// Nobody recognized the target address. We will not be able to step-in to it.
// This is ok if the target just calls into mscorwks (such as an Fcall) because
// there's no managed code to step in to, and we don't support debugging the CLR
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/vm/vars.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ GPTR_IMPL(EEDbgInterfaceImpl, g_pEEDbgInterfaceImpl);

#ifndef DACCESS_COMPILE
GVAL_IMPL_INIT(DWORD, g_multicastDelegateTraceActiveCount, 0);
GVAL_IMPL_INIT(DWORD, g_externalMethodFixupTraceActiveCount, 0);
#endif // DACCESS_COMPILE

#endif // DEBUGGING_SUPPORTED
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/vm/vars.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,7 @@ GPTR_DECL(EEDbgInterfaceImpl, g_pEEDbgInterfaceImpl);

#ifndef DACCESS_COMPILE
GVAL_DECL(DWORD, g_multicastDelegateTraceActiveCount);
GVAL_DECL(DWORD, g_externalMethodFixupTraceActiveCount);
#endif // DACCESS_COMPILE

#endif // DEBUGGING_SUPPORTED
Expand Down