Skip to content

Commit afe9b1d

Browse files
[Arm64] debugging work (dotnet#17993)
* Fix missing implementation of FuncEvalFrame::UpdateRegDisplay for ARM64 - Implementation is missing. Build new one based ARM implementation * Enable just my code on arm64 * Fix logging of addresses for DispatchPatchOrSingleStep * arm64 does not leave the PC at the start of the breakpoint * Enable interop debugging * Tweaks for windows arm64 mixed mode debugging support
1 parent 2bedc57 commit afe9b1d

File tree

10 files changed

+177
-43
lines changed

10 files changed

+177
-43
lines changed

clrdefinitions.cmake

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,9 +149,9 @@ if(NOT CMAKE_SYSTEM_NAME STREQUAL NetBSD)
149149
add_definitions(-DFEATURE_HIJACK)
150150
endif(NOT CMAKE_SYSTEM_NAME STREQUAL NetBSD)
151151
add_definitions(-DFEATURE_ICASTABLE)
152-
if (WIN32 AND (CLR_CMAKE_TARGET_ARCH_AMD64 OR CLR_CMAKE_TARGET_ARCH_I386))
152+
if (WIN32 AND (CLR_CMAKE_TARGET_ARCH_AMD64 OR CLR_CMAKE_TARGET_ARCH_I386 OR CLR_CMAKE_TARGET_ARCH_ARM64))
153153
add_definitions(-DFEATURE_INTEROP_DEBUGGING)
154-
endif (WIN32 AND (CLR_CMAKE_TARGET_ARCH_AMD64 OR CLR_CMAKE_TARGET_ARCH_I386))
154+
endif (WIN32 AND (CLR_CMAKE_TARGET_ARCH_AMD64 OR CLR_CMAKE_TARGET_ARCH_I386 OR CLR_CMAKE_TARGET_ARCH_ARM64))
155155
if(FEATURE_INTERPRETER)
156156
add_definitions(-DFEATURE_INTERPRETER)
157157
endif(FEATURE_INTERPRETER)

src/debug/di/process.cpp

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8963,7 +8963,13 @@ bool CordbProcess::IsBreakOpcodeAtAddress(const void * address)
89638963
{
89648964
// There should have been an int3 there already. Since we already put it in there,
89658965
// we should be able to safely read it out.
8966+
#if defined(DBG_TARGET_ARM) || defined(DBG_TARGET_ARM64)
8967+
PRD_TYPE opcodeTest = 0;
8968+
#elif defined(DBG_TARGET_AMD64) || defined(DBG_TARGET_X86)
89668969
BYTE opcodeTest = 0;
8970+
#else
8971+
PORTABILITY_ASSERT("NYI: Architecture specific opcode type to read");
8972+
#endif
89678973

89688974
HRESULT hr = SafeReadStruct(PTR_TO_CORDB_ADDRESS(address), &opcodeTest);
89698975
SIMPLIFYING_ASSUMPTION_SUCCEEDED(hr);
@@ -9025,6 +9031,14 @@ CordbProcess::SetUnmanagedBreakpointInternal(CORDB_ADDRESS address, ULONG32 bufs
90259031
#if defined(DBG_TARGET_X86) || defined(DBG_TARGET_AMD64)
90269032
const BYTE patch = CORDbg_BREAK_INSTRUCTION;
90279033
BYTE opcode;
9034+
#elif defined(DBG_TARGET_ARM64)
9035+
const PRD_TYPE patch = CORDbg_BREAK_INSTRUCTION;
9036+
PRD_TYPE opcode;
9037+
#else
9038+
PORTABILITY_ASSERT("NYI: CordbProcess::SetUnmanagedBreakpoint, interop debugging NYI on this platform");
9039+
hr = E_NOTIMPL;
9040+
goto ErrExit;
9041+
#endif
90289042

90299043
// Make sure args are good
90309044
if ((buffer == NULL) || (bufsize < sizeof(patch)) || (bufLen == NULL))
@@ -9056,23 +9070,21 @@ CordbProcess::SetUnmanagedBreakpointInternal(CORDB_ADDRESS address, ULONG32 bufs
90569070
goto ErrExit;
90579071

90589072
// It's all successful, so now update our out-params & internal bookkeaping.
9059-
opcode = (BYTE) p->opcode;
9073+
#if defined(DBG_TARGET_X86) || defined(DBG_TARGET_AMD64)
9074+
opcode = (BYTE)p->opcode;
90609075
buffer[0] = opcode;
9076+
#elif defined(DBG_TARGET_ARM64)
9077+
opcode = p->opcode;
9078+
memcpy_s(buffer, bufsize, &opcode, sizeof(opcode));
9079+
#else
9080+
PORTABILITY_ASSERT("NYI: CordbProcess::SetUnmanagedBreakpoint, interop debugging NYI on this platform");
9081+
#endif
90619082
*bufLen = sizeof(opcode);
90629083

90639084
p->pAddress = CORDB_ADDRESS_TO_PTR(address);
90649085
p->opcode = opcode;
90659086

90669087
_ASSERTE(SUCCEEDED(hr));
9067-
#elif defined(DBG_TARGET_WIN64)
9068-
PORTABILITY_ASSERT("NYI: CordbProcess::SetUnmanagedBreakpoint, interop debugging NYI on this platform");
9069-
hr = E_NOTIMPL;
9070-
goto ErrExit;
9071-
#else
9072-
hr = E_NOTIMPL;
9073-
goto ErrExit;
9074-
#endif // DBG_TARGET_X8_
9075-
90769088

90779089
ErrExit:
90789090
// If we failed, then free the patch
@@ -12705,8 +12717,16 @@ void CordbProcess::HandleDebugEventForInteropDebugging(const DEBUG_EVENT * pEven
1270512717
tempDebugContext.ContextFlags = DT_CONTEXT_FULL;
1270612718
DbiGetThreadContext(pUnmanagedThread->m_handle, &tempDebugContext);
1270712719
CordbUnmanagedThread::LogContext(&tempDebugContext);
12720+
#if defined(DBG_TARGET_X86) || defined(DBG_TARGET_AMD64)
12721+
const ULONG_PTR breakpointOpcodeSize = 1;
12722+
#elif defined(DBG_TARGET_ARM64)
12723+
const ULONG_PTR breakpointOpcodeSize = 4;
12724+
#else
12725+
const ULONG_PTR breakpointOpcodeSize = 1;
12726+
PORTABILITY_ASSERT("NYI: Breakpoint size offset for this platform");
12727+
#endif
1270812728
_ASSERTE(CORDbgGetIP(&tempDebugContext) == pEvent->u.Exception.ExceptionRecord.ExceptionAddress ||
12709-
(DWORD)CORDbgGetIP(&tempDebugContext) == ((DWORD)pEvent->u.Exception.ExceptionRecord.ExceptionAddress)+1);
12729+
(DWORD)CORDbgGetIP(&tempDebugContext) == ((DWORD)pEvent->u.Exception.ExceptionRecord.ExceptionAddress)+breakpointOpcodeSize);
1271012730
}
1271112731
#endif
1271212732

src/debug/di/rsthread.cpp

Lines changed: 39 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2836,9 +2836,11 @@ CordbUnmanagedThread::~CordbUnmanagedThread()
28362836
#define WINNT_TLS_OFFSET_X86 0xe10 // TLS[0] at fs:[WINNT_TLS_OFFSET]
28372837
#define WINNT_TLS_OFFSET_AMD64 0x1480
28382838
#define WINNT_TLS_OFFSET_ARM 0xe10
2839+
#define WINNT_TLS_OFFSET_ARM64 0x1480
28392840
#define WINNT5_TLSEXPANSIONPTR_OFFSET_X86 0xf94 // TLS[64] at [fs:[WINNT5_TLSEXPANSIONPTR_OFFSET]]
28402841
#define WINNT5_TLSEXPANSIONPTR_OFFSET_AMD64 0x1780
28412842
#define WINNT5_TLSEXPANSIONPTR_OFFSET_ARM 0xf94
2843+
#define WINNT5_TLSEXPANSIONPTR_OFFSET_ARM64 0x1780
28422844

28432845
HRESULT CordbUnmanagedThread::LoadTLSArrayPtr(void)
28442846
{
@@ -3771,6 +3773,13 @@ VOID CordbUnmanagedThread::LogContext(DT_CONTEXT* pContext)
37713773
DBG_ADDR(pContext->Rip),
37723774
DBG_ADDR(pContext->Rsp),
37733775
pContext->EFlags)); // EFlags is still 32bits on AMD64
3776+
#elif defined(DBG_TARGET_ARM64)
3777+
LOG((LF_CORDB, LL_INFO10000,
3778+
"CUT::LC: Pc=" FMT_ADDR ", Sp=" FMT_ADDR ", Lr=" FMT_ADDR ", Cpsr=" FMT_ADDR "\n",
3779+
DBG_ADDR(pContext->Pc),
3780+
DBG_ADDR(pContext->Sp),
3781+
DBG_ADDR(pContext->Lr),
3782+
DBG_ADDR(pContext->Cpsr)));
37743783
#else // DBG_TARGET_X86
37753784
PORTABILITY_ASSERT("LogContext needs a PC and stack pointer.");
37763785
#endif // DBG_TARGET_X86
@@ -3914,8 +3923,8 @@ HRESULT CordbUnmanagedThread::SetupFirstChanceHijack(EHijackReason::EHijackReaso
39143923
GetProcess()->GetDAC()->Hijack(VMPTR_Thread::NullPtr(),
39153924
GetOSTid(),
39163925
pExceptionRecord,
3917-
(CONTEXT*) GetHijackCtx(),
3918-
sizeof(CONTEXT),
3926+
(T_CONTEXT*) GetHijackCtx(),
3927+
sizeof(T_CONTEXT),
39193928
reason,
39203929
NULL,
39213930
&LSContextAddr);
@@ -3961,7 +3970,7 @@ HRESULT CordbUnmanagedThread::SetupGenericHijack(DWORD eventCode, const EXCEPTIO
39613970
return HRESULT_FROM_WIN32(GetLastError());
39623971
}
39633972

3964-
#if defined(DBG_TARGET_AMD64)
3973+
#if defined(DBG_TARGET_AMD64) || defined(DBG_TARGET_ARM64)
39653974

39663975
// On X86 Debugger::GenericHijackFunc() ensures the stack is walkable
39673976
// by simply using the EBP chain, therefore we can execute the hijack
@@ -3988,8 +3997,8 @@ HRESULT CordbUnmanagedThread::SetupGenericHijack(DWORD eventCode, const EXCEPTIO
39883997
pThread->m_vmThreadToken,
39893998
dwThreadId,
39903999
pRecord,
3991-
(CONTEXT*) GetHijackCtx(),
3992-
sizeof(CONTEXT),
4000+
(T_CONTEXT*) GetHijackCtx(),
4001+
sizeof(T_CONTEXT),
39934002
EHijackReason::kGenericHijack,
39944003
NULL,
39954004
NULL);
@@ -4009,7 +4018,7 @@ HRESULT CordbUnmanagedThread::SetupGenericHijack(DWORD eventCode, const EXCEPTIO
40094018
}
40104019
// else (non-threadstore threads) fallthrough
40114020

4012-
#endif // DBG_TARGET_AMD64
4021+
#endif // DBG_TARGET_AMD64 || defined(DBG_TARGET_ARM64)
40134022

40144023
// Remember that we've hijacked the guy.
40154024
SetState(CUTS_GenericHijacked);
@@ -4379,6 +4388,11 @@ void CordbUnmanagedThread::SaveRaiseExceptionEntryContext()
43794388
m_raiseExceptionExceptionFlags = (DWORD)m_raiseExceptionEntryContext.Rdx;
43804389
m_raiseExceptionNumberParameters = (DWORD)m_raiseExceptionEntryContext.R8;
43814390
pExceptionInformation = (REMOTE_PTR)m_raiseExceptionEntryContext.R9;
4391+
#elif defined(DBG_TARGET_ARM64)
4392+
m_raiseExceptionExceptionCode = (DWORD)m_raiseExceptionEntryContext.X0;
4393+
m_raiseExceptionExceptionFlags = (DWORD)m_raiseExceptionEntryContext.X1;
4394+
m_raiseExceptionNumberParameters = (DWORD)m_raiseExceptionEntryContext.X2;
4395+
pExceptionInformation = (REMOTE_PTR)m_raiseExceptionEntryContext.X3;
43824396
#elif defined(DBG_TARGET_X86)
43834397
hr = m_pProcess->SafeReadStruct(PTR_TO_CORDB_ADDRESS((BYTE*)m_raiseExceptionEntryContext.Esp+4), &m_raiseExceptionExceptionCode);
43844398
if(FAILED(hr))
@@ -4501,11 +4515,14 @@ HRESULT ApplyRemotePatch(CordbProcess * pProcess, const void * pRemoteAddress)
45014515
{
45024516
#if defined(DBG_TARGET_X86) || defined(DBG_TARGET_AMD64)
45034517
const BYTE patch = CORDbg_BREAK_INSTRUCTION;
4504-
HRESULT hr = pProcess->SafeWriteStruct(PTR_TO_CORDB_ADDRESS(pRemoteAddress), &patch);
4505-
SIMPLIFYING_ASSUMPTION_SUCCEEDED(hr);
4518+
#elif defined(DBG_TARGET_ARM64)
4519+
const PRD_TYPE patch = CORDbg_BREAK_INSTRUCTION;
45064520
#else
4521+
const BYTE patch = 0;
45074522
PORTABILITY_ASSERT("NYI: ApplyRemotePatch for this platform");
45084523
#endif
4524+
HRESULT hr = pProcess->SafeWriteStruct(PTR_TO_CORDB_ADDRESS(pRemoteAddress), &patch);
4525+
SIMPLIFYING_ASSUMPTION_SUCCEEDED(hr);
45094526
return S_OK;
45104527
}
45114528

@@ -4516,6 +4533,13 @@ HRESULT ApplyRemotePatch(CordbProcess * pProcess, const void * pRemoteAddress, P
45164533
#if defined(DBG_TARGET_X86) || defined(DBG_TARGET_AMD64)
45174534
// Read out opcode. 1 byte on x86
45184535
BYTE opcode;
4536+
#elif defined(DBG_TARGET_ARM64)
4537+
// Read out opcode. 4 bytes on arm64
4538+
PRD_TYPE opcode;
4539+
#else
4540+
BYTE opcode;
4541+
PORTABILITY_ASSERT("NYI: ApplyRemotePatch for this platform");
4542+
#endif
45194543

45204544
HRESULT hr = pProcess->SafeReadStruct(PTR_TO_CORDB_ADDRESS(pRemoteAddress), &opcode);
45214545
if (FAILED(hr))
@@ -4524,9 +4548,6 @@ HRESULT ApplyRemotePatch(CordbProcess * pProcess, const void * pRemoteAddress, P
45244548
}
45254549

45264550
*pOpcode = (PRD_TYPE) opcode;
4527-
#else
4528-
PORTABILITY_ASSERT("NYI: ApplyRemotePatch for this platform");
4529-
#endif
45304551
ApplyRemotePatch(pProcess, pRemoteAddress);
45314552
return S_OK;
45324553
}
@@ -4539,14 +4560,18 @@ HRESULT RemoveRemotePatch(CordbProcess * pProcess, const void * pRemoteAddress,
45394560
#if defined(DBG_TARGET_X86) || defined(DBG_TARGET_AMD64)
45404561
// Replace the BP w/ the opcode.
45414562
BYTE opcode2 = (BYTE) opcode;
4563+
#elif defined(DBG_TARGET_ARM64)
4564+
// 4 bytes on arm64
4565+
PRD_TYPE opcode2 = opcode;
4566+
#else
4567+
PRD_TYPE opcode2 = opcode;
4568+
PORTABILITY_ASSERT("NYI: RemoveRemotePatch for this platform");
4569+
#endif
45424570

45434571
pProcess->SafeWriteStruct(PTR_TO_CORDB_ADDRESS(pRemoteAddress), &opcode2);
45444572

45454573
// This may fail because the module has been unloaded. In which case, the patch is also
45464574
// gone so it makes sense to return success.
4547-
#else
4548-
PORTABILITY_ASSERT("NYI: RemoveRemotePatch for this platform");
4549-
#endif
45504575
return S_OK;
45514576
}
45524577
#endif // FEATURE_INTEROP_DEBUGGING

src/debug/ee/arm64/dbghelpers.asm

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,54 @@
4949
ExceptionHijackEnd
5050
NESTED_END ExceptionHijack
5151

52+
;
53+
; Flares for interop debugging.
54+
; Flares are exceptions (breakpoints) at well known addresses which the RS
55+
; listens for when interop debugging.
56+
;
57+
58+
LEAF_ENTRY SignalHijackStartedFlare
59+
EMIT_BREAKPOINT
60+
; make sure that the basic block is unique
61+
add x0, x1, x1
62+
ret lr
63+
LEAF_END
64+
65+
LEAF_ENTRY ExceptionForRuntimeHandoffStartFlare
66+
EMIT_BREAKPOINT
67+
; make sure that the basic block is unique
68+
add x0, x2, x2
69+
ret lr
70+
LEAF_END
71+
72+
LEAF_ENTRY ExceptionForRuntimeHandoffCompleteFlare
73+
EMIT_BREAKPOINT
74+
; make sure that the basic block is unique
75+
add x0, x3, x3
76+
ret lr
77+
LEAF_END
78+
79+
LEAF_ENTRY SignalHijackCompleteFlare
80+
EMIT_BREAKPOINT
81+
; make sure that the basic block is unique
82+
add x0, x4, x4
83+
ret lr
84+
LEAF_END
85+
86+
LEAF_ENTRY ExceptionNotForRuntimeFlare
87+
EMIT_BREAKPOINT
88+
; make sure that the basic block is unique
89+
add x0, x5, x5
90+
ret lr
91+
LEAF_END
92+
93+
LEAF_ENTRY NotifyRightSideOfSyncCompleteFlare
94+
EMIT_BREAKPOINT
95+
; make sure that the basic block is unique
96+
add x0, x6, x6
97+
ret lr
98+
LEAF_END
99+
52100
; must be at end of file
53101
END
54102

src/debug/ee/controller.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2867,7 +2867,7 @@ DPOSS_ACTION DebuggerController::DispatchPatchOrSingleStep(Thread *thread, CONTE
28672867

28682868
CONTRACT_VIOLATION(ThrowsViolation);
28692869

2870-
LOG((LF_CORDB|LF_ENC,LL_INFO1000,"DC:DPOSS at 0x%x trigger:0x%x\n", address, which));
2870+
LOG((LF_CORDB|LF_ENC,LL_INFO1000,"DC:DPOSS at 0x%p trigger:0x%x\n", address, which));
28712871

28722872
// We should only have an exception if some managed thread was running.
28732873
// Thus we should never be here when we're stopped.

src/debug/ee/debugger.cpp

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13720,6 +13720,10 @@ LONG Debugger::FirstChanceSuspendHijackWorker(CONTEXT *pContext,
1372013720
SPEW(fprintf(stderr, "0x%x D::FCHF: code=0x%08x, addr=0x%08x, Eip=0x%08x, Esp=0x%08x, EFlags=0x%08x\n",
1372113721
tid, pExceptionRecord->ExceptionCode, pExceptionRecord->ExceptionAddress, pContext->Eip, pContext->Esp,
1372213722
pContext->EFlags));
13723+
#elif defined(_TARGET_ARM64_)
13724+
SPEW(fprintf(stderr, "0x%x D::FCHF: code=0x%08x, addr=0x%08x, Pc=0x%p, Sp=0x%p, EFlags=0x%08x\n",
13725+
tid, pExceptionRecord->ExceptionCode, pExceptionRecord->ExceptionAddress, pContext->Pc, pContext->Sp,
13726+
pContext->EFlags));
1372313727
#endif
1372413728

1372513729
// This memory is used as IPC during the hijack. We will place a pointer to this in
@@ -13829,7 +13833,7 @@ LONG Debugger::FirstChanceSuspendHijackWorker(CONTEXT *pContext,
1382913833
}
1383013834
}
1383113835

13832-
#if defined(_TARGET_X86_) || defined(_TARGET_AMD64_)
13836+
#if defined(_TARGET_X86_) || defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_)
1383313837
void GenericHijackFuncHelper()
1383413838
{
1383513839
#if DOSPEW
@@ -13970,7 +13974,7 @@ void Debugger::SignalHijackStarted(void)
1397013974
{
1397113975
WRAPPER_NO_CONTRACT;
1397213976

13973-
#if defined(_TARGET_X86_) || defined(_TARGET_AMD64_)
13977+
#if defined(FEATURE_INTEROP_DEBUGGING)
1397413978
SignalHijackStartedFlare();
1397513979
#else
1397613980
_ASSERTE(!"@todo - port the flares to the platform your running on.");
@@ -13987,7 +13991,7 @@ void Debugger::ExceptionForRuntimeHandoffStart(void)
1398713991
{
1398813992
WRAPPER_NO_CONTRACT;
1398913993

13990-
#if defined(_TARGET_X86_) || defined(_TARGET_AMD64_)
13994+
#if defined(FEATURE_INTEROP_DEBUGGING)
1399113995
ExceptionForRuntimeHandoffStartFlare();
1399213996
#else
1399313997
_ASSERTE(!"@todo - port the flares to the platform your running on.");
@@ -14005,7 +14009,7 @@ void Debugger::ExceptionForRuntimeHandoffComplete(void)
1400514009
{
1400614010
WRAPPER_NO_CONTRACT;
1400714011

14008-
#if defined(_TARGET_X86_) || defined(_TARGET_AMD64_)
14012+
#if defined(FEATURE_INTEROP_DEBUGGING)
1400914013
ExceptionForRuntimeHandoffCompleteFlare();
1401014014
#else
1401114015
_ASSERTE(!"@todo - port the flares to the platform your running on.");
@@ -14021,7 +14025,7 @@ void Debugger::SignalHijackComplete(void)
1402114025
{
1402214026
WRAPPER_NO_CONTRACT;
1402314027

14024-
#if defined(_TARGET_X86_) || defined(_TARGET_AMD64_)
14028+
#if defined(FEATURE_INTEROP_DEBUGGING)
1402514029
SignalHijackCompleteFlare();
1402614030
#else
1402714031
_ASSERTE(!"@todo - port the flares to the platform your running on.");
@@ -14037,7 +14041,7 @@ void Debugger::ExceptionNotForRuntime(void)
1403714041
{
1403814042
WRAPPER_NO_CONTRACT;
1403914043

14040-
#if defined(_TARGET_X86_) || defined(_TARGET_AMD64_)
14044+
#if defined(FEATURE_INTEROP_DEBUGGING)
1404114045
ExceptionNotForRuntimeFlare();
1404214046
#else
1404314047
_ASSERTE(!"@todo - port the flares to the platform your running on.");
@@ -14053,7 +14057,7 @@ void Debugger::NotifyRightSideOfSyncComplete(void)
1405314057
{
1405414058
WRAPPER_NO_CONTRACT;
1405514059
STRESS_LOG0(LF_CORDB, LL_INFO100000, "D::NRSOSC: Sending flare...\n");
14056-
#if defined(_TARGET_X86_) || defined(_TARGET_AMD64_)
14060+
#if defined(FEATURE_INTEROP_DEBUGGING)
1405714061
NotifyRightSideOfSyncCompleteFlare();
1405814062
#else
1405914063
_ASSERTE(!"@todo - port the flares to the platform your running on.");

0 commit comments

Comments
 (0)