diff options
author | Rama Krishnan Raghupathy <ramarag@microsoft.com> | 2016-07-18 19:40:05 -0700 |
---|---|---|
committer | Rama Krishnan Raghupathy <ramarag@microsoft.com> | 2016-07-25 18:42:30 -0700 |
commit | 00e3695c1b51248f58f6b7e1f24f83a791a3b79e (patch) | |
tree | 1af2da04bf3816d3a6172b52a84201387a5e2673 /src/debug | |
parent | c358f77a1ddcf31475450c40af64ad115259e622 (diff) | |
download | coreclr-00e3695c1b51248f58f6b7e1f24f83a791a3b79e.tar.gz coreclr-00e3695c1b51248f58f6b7e1f24f83a791a3b79e.tar.bz2 coreclr-00e3695c1b51248f58f6b7e1f24f83a791a3b79e.zip |
Arm64: Debugger
Instruction emulation for Break Points
Debugger::FuncEvalSetup
NativeWalker
ExceptionHijack
Exception intercept
Managed Return Value
Diffstat (limited to 'src/debug')
-rw-r--r-- | src/debug/daccess/dacdbiimpl.cpp | 5 | ||||
-rw-r--r-- | src/debug/di/CMakeLists.txt | 22 | ||||
-rw-r--r-- | src/debug/di/DI.props | 6 | ||||
-rw-r--r-- | src/debug/di/arm64/cordbregisterset.cpp | 4 | ||||
-rw-r--r-- | src/debug/di/arm64/floatconversion.asm | 22 | ||||
-rw-r--r-- | src/debug/di/module.cpp | 4 | ||||
-rw-r--r-- | src/debug/di/rspriv.h | 2 | ||||
-rw-r--r-- | src/debug/di/rsthread.cpp | 34 | ||||
-rw-r--r-- | src/debug/di/shimstackwalk.cpp | 2 | ||||
-rw-r--r-- | src/debug/ee/arm64/arm64walker.cpp | 461 | ||||
-rw-r--r-- | src/debug/ee/arm64/dbghelpers.asm | 54 | ||||
-rw-r--r-- | src/debug/ee/controller.cpp | 60 | ||||
-rw-r--r-- | src/debug/ee/controller.h | 5 | ||||
-rw-r--r-- | src/debug/ee/debugger.cpp | 8 | ||||
-rw-r--r-- | src/debug/ee/frameinfo.cpp | 2 | ||||
-rw-r--r-- | src/debug/ee/funceval.cpp | 6 | ||||
-rw-r--r-- | src/debug/ee/walker.h | 23 | ||||
-rw-r--r-- | src/debug/ee/wks/CMakeLists.txt | 33 | ||||
-rw-r--r-- | src/debug/ee/wks/wks.nativeproj | 1 | ||||
-rw-r--r-- | src/debug/inc/arm64/primitives.h | 14 |
20 files changed, 719 insertions, 49 deletions
diff --git a/src/debug/daccess/dacdbiimpl.cpp b/src/debug/daccess/dacdbiimpl.cpp index 8ff1ecd9da..9b17f4cd46 100644 --- a/src/debug/daccess/dacdbiimpl.cpp +++ b/src/debug/daccess/dacdbiimpl.cpp @@ -5238,6 +5238,11 @@ void DacDbiInterfaceImpl::Hijack( ctx.R1 = (DWORD)espRecord; ctx.R2 = (DWORD)reason; ctx.R3 = (DWORD)pData; +#elif defined(_TARGET_ARM64_) + ctx.X0 = (DWORD64)espContext; + ctx.X1 = (DWORD64)espRecord; + ctx.X2 = (DWORD64)reason; + ctx.X3 = (DWORD64)pData; #else PORTABILITY_ASSERT("CordbThread::HijackForUnhandledException is not implemented on this platform."); #endif diff --git a/src/debug/di/CMakeLists.txt b/src/debug/di/CMakeLists.txt index 8894813e73..abede90d2e 100644 --- a/src/debug/di/CMakeLists.txt +++ b/src/debug/di/CMakeLists.txt @@ -34,11 +34,30 @@ if(WIN32) #use static crt add_definitions(-MT) + if (CLR_CMAKE_TARGET_ARCH_AMD64 OR CLR_CMAKE_TARGET_ARCH_ARM64) + set(CORDBDI_SOURCES_ASM_FILE ${ARCH_SOURCES_DIR}/floatconversion.asm) + endif() if (CLR_CMAKE_TARGET_ARCH_AMD64) set(CORDBDI_SOURCES ${CORDBDI_SOURCES} - ${ARCH_SOURCES_DIR}/floatconversion.asm + ${CORDBDI_SOURCES_ASM_FILE} ) + elseif (CLR_CMAKE_TARGET_ARCH_ARM64 AND NOT DEFINED CLR_CROSS_COMPONENTS_BUILD) + convert_to_absolute_path(CORDBDI_SOURCES_ASM_FILE ${CORDBDI_SOURCES_ASM_FILE}) + get_compile_definitions(ASM_DEFINITIONS) + set(ASM_OPTIONS /c /Zi /W3 /errorReport:prompt) + # asm files require preprocessing using cl.exe on arm64 + get_filename_component(name ${CORDBDI_SOURCES_ASM_FILE} NAME_WE) + set(ASM_PREPROCESSED_FILE ${CMAKE_CURRENT_BINARY_DIR}/${name}.asm) + preprocess_def_file(${CORDBDI_SOURCES_ASM_FILE} ${ASM_PREPROCESSED_FILE}) + set(CORDBDI_SOURCES_WKS_PREPROCESSED_ASM ${ASM_PREPROCESSED_FILE}) + + set_property(SOURCE ${CORDBDI_SOURCES_WKS_PREPROCESSED_ASM} PROPERTY COMPILE_DEFINITIONS ${ASM_DEFINITIONS}) + set_property(SOURCE ${CORDBDI_SOURCES_WKS_PREPROCESSED_ASM} PROPERTY COMPILE_DEFINITIONS ${ASM_OPTIONS}) + set(CORDBDI_SOURCES + ${CORDBDI_SOURCES} + ${CORDBDI_SOURCES_WKS_PREPROCESSED_ASM} + ) endif() elseif(CLR_CMAKE_PLATFORM_UNIX) add_compile_options(-fPIC) @@ -54,4 +73,5 @@ endif(WIN32) add_precompiled_header(stdafx.h stdafx.cpp CORDBDI_SOURCES) + add_library_clr(cordbdi STATIC ${CORDBDI_SOURCES}) diff --git a/src/debug/di/DI.props b/src/debug/di/DI.props index ef787d74da..1d7336dab0 100644 --- a/src/debug/di/DI.props +++ b/src/debug/di/DI.props @@ -76,7 +76,11 @@ <CppCompile Include="@(SourcesPublish)" /> <CppCompile Include="@(SourcesShim)" /> <CppCompile Include="@(SourcesRightside)" /> - <AssembleAmd64 Condition="'$(BuildArchitecture)' == 'amd64'" Include="..\amd64\floatconversion.asm" /> + <AssembleAmd64 Condition="'$(BuildArchitecture)' == 'amd64' and '$(CrossTargetArchitecture)' != 'arm64'" Include="..\amd64\floatconversion.asm" /> + </ItemGroup> + <ItemGroup Condition="'$(BuildArchitecture)' == 'arm64'"> + <PreprocessAssembleArm Include="..\arm64\floatconversion.asm" /> + <AssembleArm64 Include="$(IntermediateOutputDirectory)\floatconversion.i" /> </ItemGroup> <!--Import the targets--> </Project> diff --git a/src/debug/di/arm64/cordbregisterset.cpp b/src/debug/di/arm64/cordbregisterset.cpp index 9a7e1c140f..eab5ba403c 100644 --- a/src/debug/di/arm64/cordbregisterset.cpp +++ b/src/debug/di/arm64/cordbregisterset.cpp @@ -65,8 +65,8 @@ HRESULT CordbRegisterSet::GetRegisters(ULONG64 mask, ULONG32 regCount, // @ARM64TODO: floating point support - for (int i = REGISTER_ARM64_X0; - i <= REGISTER_ARM64_PC && iRegister < regCount; + for (int i = REGISTER_ARM64_PC; + i <= REGISTER_ARM64_LR && iRegister < regCount; i++) { if (mask & SETBITULONG64(i)) diff --git a/src/debug/di/arm64/floatconversion.asm b/src/debug/di/arm64/floatconversion.asm new file mode 100644 index 0000000000..e478fd10fd --- /dev/null +++ b/src/debug/di/arm64/floatconversion.asm @@ -0,0 +1,22 @@ +; Licensed to the .NET Foundation under one or more agreements. +; The .NET Foundation licenses this file to you under the MIT license. +; See the LICENSE file in the project root for more information. + +;; ==++== +;; + +;; +;; ==--== +#include "ksarm64.h" + +;; Arguments +;; input: (in X0) the _NEON128 value to be converted to a double +;; output: the double corresponding to the _NEON128 input value + + LEAF_ENTRY FPFillR8 + LDR Q0, [X0] + ret lr + LEAF_END + +;; Must be at very end of file + END diff --git a/src/debug/di/module.cpp b/src/debug/di/module.cpp index 78c7599455..6717e8575f 100644 --- a/src/debug/di/module.cpp +++ b/src/debug/di/module.cpp @@ -4114,9 +4114,9 @@ HRESULT CordbNativeCode::GetReturnValueLiveOffset(ULONG32 ILoffset, ULONG32 buff int CordbNativeCode::GetCallInstructionLength(BYTE *ip, ULONG32 count) { #if defined(DBG_TARGET_ARM) - return E_NOTIMPL; + return MAX_INSTRUCTION_LENGTH; #elif defined(DBG_TARGET_ARM64) - return E_NOTIMPL; + return MAX_INSTRUCTION_LENGTH; #elif defined(DBG_TARGET_X86) if (count < 2) return -1; diff --git a/src/debug/di/rspriv.h b/src/debug/di/rspriv.h index 2bee31471f..01e65ac9b4 100644 --- a/src/debug/di/rspriv.h +++ b/src/debug/di/rspriv.h @@ -6097,7 +6097,7 @@ public: // Converts the values in the floating point register area of the context to real number values. void Get32bitFPRegisters(CONTEXT * pContext); -#elif defined(DBG_TARGET_AMD64) +#elif defined(DBG_TARGET_AMD64) || defined(DBG_TARGET_ARM64) // Converts the values in the floating point register area of the context to real number values. void Get64bitFPRegisters(FPRegister64 * rgContextFPRegisters, int start, int nRegisters); #endif // DBG_TARGET_X86 diff --git a/src/debug/di/rsthread.cpp b/src/debug/di/rsthread.cpp index 633f68a747..ae9b43cd01 100644 --- a/src/debug/di/rsthread.cpp +++ b/src/debug/di/rsthread.cpp @@ -1432,8 +1432,20 @@ HRESULT CordbThread::FindFrame(ICorDebugFrame ** ppFrame, FramePointer fp) return E_FAIL; } + #if !defined(DBG_TARGET_ARM) // @ARMTODO +#if defined(CROSS_COMPILE) && defined(_TARGET_ARM64_) +extern "C" double FPFillR8(void* pFillSlot) +{ + _ASSERTE(!"nyi for platform"); + return 0; +} +#elif defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_) +extern "C" double FPFillR8(void* pFillSlot); +#endif + + #if defined(_TARGET_X86_) // CordbThread::Get32bitFPRegisters @@ -1496,8 +1508,7 @@ void CordbThread::Get32bitFPRegisters(CONTEXT * pContext) m_floatStackTop = floatStackTop; } // CordbThread::Get32bitFPRegisters -#elif defined(_TARGET_AMD64_) -extern "C" double FPFillR8(void* pFillSlot); +#elif defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_) // CordbThread::Get64bitFPRegisters // Converts the values in the floating point register area of the context to real number values. See @@ -1525,7 +1536,6 @@ void CordbThread::Get64bitFPRegisters(FPRegister64 * rgContextFPRegisters, int s } } // CordbThread::Get64bitFPRegisters - #endif // _TARGET_X86_ // CordbThread::LoadFloatState @@ -1556,6 +1566,10 @@ void CordbThread::LoadFloatState() #elif defined(_TARGET_AMD64_) // we have no fixed-value registers, so we begin with the first one and initialize all 16 Get64bitFPRegisters((FPRegister64*) &(tempContext.Xmm0), 0, 16); +#elif defined(_TARGET_ARM64_) + Get64bitFPRegisters((FPRegister64*) &(tempContext.V), 0, 32); +#else + _ASSERTE(!"nyi for platform"); #endif // !_TARGET_X86_ m_fFloatStateValid = true; @@ -6991,6 +7005,8 @@ HRESULT CordbNativeFrame::GetLocalRegisterValue(CorDebugRegister reg, if ((reg >= REGISTER_X86_FPSTACK_0) && (reg <= REGISTER_X86_FPSTACK_7)) #elif defined(DBG_TARGET_AMD64) if ((reg >= REGISTER_AMD64_XMM0) && (reg <= REGISTER_AMD64_XMM15)) +#elif defined(DBG_TARGET_ARM64) + if ((reg >= REGISTER_ARM64_V0) && (reg <= REGISTER_ARM64_V31)) #endif { return GetLocalFloatingPointValue(reg, pType, ppValue); @@ -7239,6 +7255,11 @@ HRESULT CordbNativeFrame::GetLocalFloatingPointValue(DWORD index, (index <= REGISTER_AMD64_XMM15))) return E_INVALIDARG; index -= REGISTER_AMD64_XMM0; +#elif defined(DBG_TARGET_ARM64) + if (!((index >= REGISTER_ARM64_V0) && + (index <= REGISTER_ARM64_V31))) + return E_INVALIDARG; + index -= REGISTER_ARM64_V0; #else if (!((index >= REGISTER_X86_FPSTACK_0) && (index <= REGISTER_X86_FPSTACK_7))) @@ -8941,20 +8962,25 @@ HRESULT CordbJITILFrame::GetReturnValueForILOffsetImpl(ULONG32 ILoffset, ICorDeb HRESULT CordbJITILFrame::GetReturnValueForType(CordbType *pType, ICorDebugValue **ppReturnValue) { -#if defined(DBG_TARGET_ARM) || defined(DBG_TARGET_ARM64) +#if defined(DBG_TARGET_ARM) return E_NOTIMPL; #else + #if defined(DBG_TARGET_X86) const CorDebugRegister floatRegister = REGISTER_X86_FPSTACK_0; #elif defined(DBG_TARGET_AMD64) const CorDebugRegister floatRegister = REGISTER_AMD64_XMM0; +#elif defined(DBG_TARGET_ARM64) + const CorDebugRegister floatRegister = REGISTER_ARM64_V0; #endif #if defined(DBG_TARGET_X86) const CorDebugRegister ptrRegister = REGISTER_X86_EAX; #elif defined(DBG_TARGET_AMD64) const CorDebugRegister ptrRegister = REGISTER_AMD64_RAX; +#elif defined(DBG_TARGET_ARM64) + const CorDebugRegister ptrRegister = REGISTER_ARM64_X0; #endif CorElementType corReturnType = pType->GetElementType(); diff --git a/src/debug/di/shimstackwalk.cpp b/src/debug/di/shimstackwalk.cpp index f3ea73bc7b..9be1ea1a78 100644 --- a/src/debug/di/shimstackwalk.cpp +++ b/src/debug/di/shimstackwalk.cpp @@ -1097,7 +1097,7 @@ void ShimStackWalk::AppendChain(ChainInfo * pChainInfo, StackWalkInfo * pStackWa // We need to send an extra enter-managed chain. _ASSERTE(pChainInfo->m_fLeafNativeContextIsValid); BYTE * sp = reinterpret_cast<BYTE *>(CORDbgGetSP(&(pChainInfo->m_leafNativeContext))); -#ifndef _TARGET_ARM_ +#if !defined(_TARGET_ARM_) && !defined(_TARGET_ARM64_) // Dev11 324806: on ARM we use the caller's SP for a frame's ending delimiter so we cannot // subtract 4 bytes from the chain's ending delimiter else the frame might never be in range. // TODO: revisit overlapping ranges on ARM, it would be nice to make it consistent with the other architectures. diff --git a/src/debug/ee/arm64/arm64walker.cpp b/src/debug/ee/arm64/arm64walker.cpp index b13f36f3df..7d8089574a 100644 --- a/src/debug/ee/arm64/arm64walker.cpp +++ b/src/debug/ee/arm64/arm64walker.cpp @@ -2,21 +2,474 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. //***************************************************************************** -// File: Amd64walker.cpp +// File: Arm64walker.cpp // // -// AMD64 instruction decoding/stepping logic +// ARM64 instruction decoding/stepping logic // //***************************************************************************** #include "stdafx.h" - #include "walker.h" - #include "frames.h" #include "openum.h" #ifdef _TARGET_ARM64_ +PCODE Expand19bitoffset(PCODE opcode) +{ + opcode = opcode >> 5; + PCODE offset = (opcode & 0x7FFFF) << 2; //imm19:00 -> 21 bits + + //Sign Extension + if ((offset & 0x100000)) //Check for 21'st bit + { + offset = offset | 0xFFFFFFFFFFE00000; + } + return offset; +} + +void NativeWalker::Decode() +{ + + PT_CONTEXT context = NULL; + int RegNum = -1; + PCODE offset = MAX_INSTRUCTION_LENGTH; + + //Reset so that we do not provide bogus info + m_type = WALK_UNKNOWN; + m_skipIP = NULL; + m_nextIP = NULL; + + if (m_registers == NULL) + { + //walker does not use WALK_NEXT + //Without registers decoding will work only for handful of instructions + return; + } + + m_skipIP = m_ip + MAX_INSTRUCTION_LENGTH; + + context = m_registers->pCurrentContext; + // Fetch first word of the current instruction.If the current instruction is a break instruction, we'll + // need to check the patch table to get the correct instruction. + PRD_TYPE opcode = CORDbgGetInstruction(m_ip); + PRD_TYPE unpatchedOpcode; + if (DebuggerController::CheckGetPatchedOpcode(m_ip, &unpatchedOpcode)) + { + opcode = unpatchedOpcode; + } + + LOG((LF_CORDB, LL_INFO100000, "Arm64Walker::Decode instruction at %p, opcode: %x\n", m_ip,opcode)); + + + + if (NativeWalker::DecodeCallInst(opcode, RegNum, m_type)) //Unconditional Branch (register) instructions + { + if (m_type == WALK_RETURN) + { + m_skipIP = NULL; + } + m_nextIP = (BYTE*)GetReg(context, RegNum); + return; + } + + + if (NativeWalker::DecodePCRelativeBranchInst(context, opcode, offset, m_type)) + { + if (m_type == WALK_BRANCH) + { + m_skipIP = NULL; + } + } + + m_nextIP = m_ip + offset; + + + return; +} + + +//When control reaches here m_pSharedPatchBypassBuffer has the original instructions in m_pSharedPatchBypassBuffer->PatchBypass +BYTE* NativeWalker::SetupOrSimulateInstructionForPatchSkip(T_CONTEXT * context, SharedPatchBypassBuffer* m_pSharedPatchBypassBuffer, const BYTE *address, PRD_TYPE opcode) +{ + + BYTE* patchBypass = m_pSharedPatchBypassBuffer->PatchBypass; + PCODE offset = 0; + PCODE ip = 0; + WALK_TYPE walk = WALK_UNKNOWN; + int RegNum =-1; + + + /* + Modify the patchBypass if the opcode is IP-relative, otherwise return it + The following are the instructions that are IP-relative : + • ADR and ADRP. + • The Load register (literal) instruction class. + • Direct branches that use an immediate offset. + • The unconditional branch with link instructions, BL and BLR, that use the PC to create the return link + address. + */ + + _ASSERTE((UINT_PTR)address == context->Pc); + + if ((opcode & 0x1F000000) == 0x10000000) //ADR & ADRP + { + + TADDR immhigh = ((opcode >> 5) & 0x007FFFF) << 2; + TADDR immlow = (opcode & 0x60000000) >> 29; + offset = immhigh | immlow; //ADR + RegNum = (opcode & 0x1F); + + //Sign Extension + if ((offset & 0x100000)) //Check for 21'st bit + { + offset = offset | 0xFFFFFFFFFFE00000; + } + + if ((opcode & 0x80000000) != 0) //ADRP + { + offset = offset << 12; + LOG((LF_CORDB, LL_INFO100000, "Arm64Walker::Simulate opcode: %x to ADRP X%d %p\n", opcode, RegNum, offset)); + } + else + { + LOG((LF_CORDB, LL_INFO100000, "Arm64Walker::Simulate opcode: %x to ADR X%d %p\n", opcode, RegNum, offset)); + } + + + } + + else if ((opcode & 0x3B000000) == 0x18000000) //LDR Literal (General or SIMD) + { + + offset = Expand19bitoffset(opcode); + RegNum = (opcode & 0x1F); + LOG((LF_CORDB, LL_INFO100000, "Arm64Walker::Simulate opcode: %x to LDR[SW] | PRFM X%d %p\n", opcode, RegNum, offset)); + } + else if (NativeWalker::DecodePCRelativeBranchInst(context,opcode, offset, walk)) + { + _ASSERTE(RegNum == -1); + } + else if (NativeWalker::DecodeCallInst(opcode, RegNum, walk)) + { + _ASSERTE(offset == 0); + } + //else Just execute the opcodes as is + //{ + //} + + if (offset != 0) // calculate the next ip from current ip + { + ip = (PCODE)address + offset; + } + else if(RegNum >= 0) + { + ip = GetReg(context, RegNum); + } + + //Do instruction emulation inplace here + + if (walk == WALK_BRANCH || walk == WALK_CALL || walk == WALK_RETURN) + { + CORDbgSetInstruction((CORDB_ADDRESS_TYPE *)patchBypass, 0xd503201f); //Add Nop in buffer + + m_pSharedPatchBypassBuffer->RipTargetFixup = ip; //Control Flow simulation alone is done DebuggerPatchSkip::TriggerExceptionHook + LOG((LF_CORDB, LL_INFO100000, "Arm64Walker::Simulate opcode: %x is a Control Flow instr \n", opcode)); + + if (walk == WALK_CALL) //initialize Lr + { + SetLR(context, (PCODE)address + MAX_INSTRUCTION_LENGTH); + LOG((LF_CORDB, LL_INFO100000, "Arm64Walker::Simulate opcode: %x is a Call instr, setting LR to %p \n", opcode,GetLR(context))); + } + } + else if(RegNum >= 0) + { + CORDbgSetInstruction((CORDB_ADDRESS_TYPE *)patchBypass, 0xd503201f); //Add Nop in buffer + + PCODE RegContents; + if ((opcode & 0x3B000000) == 0x18000000) //LDR Literal + { + RegContents = (PCODE)GetMem(ip); + if ((opcode & 0x4000000)) //LDR literal for SIMD + { + LOG((LF_CORDB, LL_INFO100000, "Arm64Walker::Simulate opcode: %x to LDR V%d %p\n", opcode, RegNum, offset)); + short opc = (opcode >> 30); + switch (opc) + { + case 0: //4byte data into St + RegContents = 0xFFFFFFFF & RegContents; //zero the upper 32bit + SetReg(context, RegNum, RegContents); + case 1: //8byte data into Dt + SetReg(context, RegNum, RegContents); + break; + + case 2: //SIMD 16 byte data + NEON128 SimdRegContents = GetSimdMem(ip); + SetSimdReg(context, RegNum, SimdRegContents); + break; + default: + LOG((LF_CORDB, LL_INFO100000, "Arm64Walker::Simulate Unknown opcode: %x [LDR(litera,SIMD &FP)] \n", opcode)); + _ASSERTE(!("Arm64Walker::Simulated Unknown opcode")); + + } + } + else + { + short opc = (opcode >> 30); + switch (opc) + { + case 0: //4byte data into Wt + LOG((LF_CORDB, LL_INFO100000, "Arm64Walker::Simulate opcode: %x to LDR W%d %p\n", opcode, RegNum, offset)); + RegContents = 0xFFFFFFFF & RegContents; //zero the upper 32bits + SetReg(context, RegNum, RegContents); + break; + + case 1: //8byte data into Xt + LOG((LF_CORDB, LL_INFO100000, "Arm64Walker::Simulate opcode: %x to LDR X%d %p\n", opcode, RegNum, offset)); + SetReg(context, RegNum, RegContents); + break; + + case 2: //LDRSW + LOG((LF_CORDB, LL_INFO100000, "Arm64Walker::Simulate opcode: %x to LDRSW X%d %p\n", opcode, RegNum, offset)); + RegContents = 0xFFFFFFFF & RegContents; + + if (RegContents & 0x80000000) //Sign extend the Word + { + RegContents = 0xFFFFFFFF00000000 | RegContents; + } + SetReg(context, RegNum, RegContents); + break; + case 3: + LOG((LF_CORDB, LL_INFO100000, "Arm64Walker::Simulate opcode: %x as PRFM ,but do nothing \n", opcode)); + + break; + default: + LOG((LF_CORDB, LL_INFO100000, "Arm64Walker::Simulate Unknown opcode: %x [LDR(literal)] \n", opcode)); + _ASSERTE(!("Arm64Walker::Simulated Unknown opcode")); + + } + } + } + else + { + RegContents = ip; + SetReg(context, RegNum, RegContents); + } + + LOG((LF_CORDB, LL_INFO100000, "Arm64Walker::Simulate opcode: %x to update Reg X[V]%d, as %p \n", opcode, RegNum, GetReg(context, RegNum))); + } + //else Just execute the opcodes as IS + //{ + //} + + return patchBypass; +} + +//Decodes PC Relative Branch Instructions +//This code is shared between the NativeWalker and DebuggerPatchSkip. +//So ENSURE THIS FUNCTION DOES NOT CHANGE ANY STATE OF THE DEBUGEE +//This Function Decodes : +// BL offset +// B offset +// B.Cond offset +// CB[N]Z X<r> offset +// TB[N]Z X<r> offset + +//Output of the Function are: +//offset - Offset from current PC to which control will go next +//WALK_TYPE + +BOOL NativeWalker::DecodePCRelativeBranchInst(PT_CONTEXT context, const PRD_TYPE& opcode, PCODE& offset, WALK_TYPE& walk) +{ +#ifdef _DEBUG + PCODE incomingoffset = offset; + WALK_TYPE incomingwalk = walk; +#endif + + if ((opcode & 0x7C000000) == 0x14000000) // Decode B & BL + { + offset = (opcode & 0x03FFFFFF) << 2; + // Sign extension + if ((offset & 0x4000000)) //Check for 26'st bit + { + offset = offset | 0xFFFFFFFFF8000000; + } + + if ((opcode & 0x80000000) != 0) //BL + { + walk = WALK_CALL; + LOG((LF_CORDB, LL_INFO100000, "Arm64Walker::Decoded opcode: %x to BL %p \n", opcode, offset)); + } + else + { + walk = WALK_BRANCH; //B + LOG((LF_CORDB, LL_INFO100000, "Arm64Walker::Decoded opcode: %x to B %p \n", opcode, offset)); + } + return TRUE; + } + + //Conditional Branches + _ASSERTE(context != NULL); + + + if ((opcode & 0xFF000010) == 0x54000000) // B.cond + { + WORD cond = opcode & 0xF; + bool result = false; + switch (cond >> 1) + { + case 0x0: result = (context->Cpsr & NZCV_Z) != 0; // EQ or NE + break; + case 0x1: result = (context->Cpsr & NZCV_C) != 0; // CS or CC + break; + case 0x2: result = (context->Cpsr & NZCV_N) != 0; // MI or PL + break; + case 0x3: result = (context->Cpsr & NZCV_V) != 0; // VS or VC + break; + case 0x4: result = ((context->Cpsr & NZCV_C) != 0) && ((context->Cpsr & NZCV_Z) == 0); // HI or LS + break; + case 0x5: result = ((context->Cpsr & NZCV_N) >> NZCV_N_BIT) == ((context->Cpsr & NZCV_V) >> NZCV_V_BIT); // GE or LT + break; + case 0x6: result = ((context->Cpsr & NZCV_N) >> NZCV_N_BIT) == ((context->Cpsr & NZCV_V) >> NZCV_V_BIT) && ((context->Cpsr & NZCV_Z) == 0); // GT or LE + break; + case 0x7: result = true; // AL + break; + } + + if ((cond & 0x1) && (cond & 0xF) != 0) { result = !result; } + + if (result) + { + walk = WALK_BRANCH; + offset = Expand19bitoffset(opcode); + LOG((LF_CORDB, LL_INFO100000, "Arm64Walker::Decoded opcode: %x to B.cond %p \n", opcode, offset)); + } + else // NOP + { + walk = WALK_UNKNOWN; + LOG((LF_CORDB, LL_INFO100000, "Arm64Walker::Decoded opcode: %x to B.cond but evaluated as NOP \n", opcode)); + offset = MAX_INSTRUCTION_LENGTH; + } + + return TRUE; + + } + + + int RegNum = opcode & 0x1F; + PCODE RegContent = GetReg(context, RegNum); + + if ((opcode & 0xFE000000) == 0x34000000) // CBNZ || CBZ + { + bool result = false; + + if (!(opcode & 0x80000000)) //if sf == '1' the 64 else 32 + { + RegContent = 0xFFFFFFFF & RegContent; //zero the upper 32bit + } + + if (opcode & 0x01000000) //CBNZ + { + result = RegContent != 0; + LOG((LF_CORDB, LL_INFO100000, "Arm64Walker::Decoded opcode: %x to CBNZ X%d \n", opcode, RegNum)); + } + else //CBZ + { + result = RegContent == 0; + LOG((LF_CORDB, LL_INFO100000, "Arm64Walker::Decoded opcode: %x to CBZ X%d \n", opcode, RegNum)); + } + + if (result) + { + walk = WALK_BRANCH; + offset = Expand19bitoffset(opcode); + LOG((LF_CORDB, LL_INFO100000, "Arm64Walker::Decoded opcode: %x to CB[N]Z X%d %p \n", opcode, RegNum, offset)); + } + else // NOP + { + walk = WALK_UNKNOWN; + LOG((LF_CORDB, LL_INFO100000, "Arm64Walker::Decoded opcode: %x to B.cond but evaluated as NOP \n", opcode)); + offset = MAX_INSTRUCTION_LENGTH; + } + + + return TRUE; + } + if ((opcode & 0x7E000000) == 0x36000000) // TBNZ || TBZ + { + bool result = false; + int bit_pos = ((opcode >> 19) & 0x1F); + + if (opcode & 0x80000000) + { + bit_pos = bit_pos + 32; + } + + PCODE bit_val = 1 << bit_pos; + if (opcode & 0x01000000) //TBNZ + { + result = (RegContent & bit_val) != 0; + LOG((LF_CORDB, LL_INFO100000, "Arm64Walker::Decoded opcode: %x to TBNZ X%d \n", opcode, RegNum)); + } + else //TBZ + { + result = (RegContent & bit_val) == 0; + LOG((LF_CORDB, LL_INFO100000, "Arm64Walker::Decoded opcode: %x to CB[N]Z X%d \n", opcode, RegNum)); + } + if (result) + { + walk = WALK_BRANCH; + offset = ((opcode >> 5) & 0x3FFF) << 2; //imm14:00 -> 16 bits + if (offset & 0x8000) //sign extension check for 16'th bit + { + offset = offset | 0xFFFFFFFFFFFF0000; + } + LOG((LF_CORDB, LL_INFO100000, "Arm64Walker::Decoded opcode: %x to TB[N]Z X%d %p \n", opcode, RegNum, offset)); + } + else // NOP + { + walk = WALK_UNKNOWN; + LOG((LF_CORDB, LL_INFO100000, "Arm64Walker::Decoded opcode: %x to B.cond but evaluated as NOP \n", opcode)); + offset = MAX_INSTRUCTION_LENGTH; + } + + return TRUE; + } + + _ASSERTE(offset == incomingoffset); + _ASSERTE(walk == incomingwalk); + return FALSE; +} + +BOOL NativeWalker::DecodeCallInst(const PRD_TYPE& opcode, int& RegNum, WALK_TYPE& walk) +{ + if ((opcode & 0xFF9FFC1F) == 0xD61F0000) // BR, BLR or RET -Unconditional Branch (register) instructions + { + + RegNum = (opcode & 0x3E0) >> 5; + + + short op = (opcode & 0x00600000) >> 21; //Checking for 23 and 22 bits + switch (op) + { + case 0: LOG((LF_CORDB, LL_INFO100000, "Arm64Walker::Decoded opcode: %x to BR X%d\n", opcode, RegNum)); + walk = WALK_BRANCH; + break; + case 1: LOG((LF_CORDB, LL_INFO100000, "Arm64Walker::Decoded opcode: %x to BLR X%d\n", opcode, RegNum)); + walk = WALK_CALL; + break; + case 2: LOG((LF_CORDB, LL_INFO100000, "Arm64Walker::Decoded opcode: %x to Ret X%d\n", opcode, RegNum)); + walk = WALK_RETURN; + break; + default: + LOG((LF_CORDB, LL_INFO100000, "Arm64Walker::Simulate Unknown opcode: %x [Branch] \n", opcode)); + _ASSERTE(!("Arm64Walker::Decoded Unknown opcode")); + } + + return TRUE; + } + return FALSE; +} #endif diff --git a/src/debug/ee/arm64/dbghelpers.asm b/src/debug/ee/arm64/dbghelpers.asm new file mode 100644 index 0000000000..ded1a0d184 --- /dev/null +++ b/src/debug/ee/arm64/dbghelpers.asm @@ -0,0 +1,54 @@ +; Licensed to the .NET Foundation under one or more agreements. +; The .NET Foundation licenses this file to you under the MIT license. +; See the LICENSE file in the project root for more information. + +#include "ksarm64.h" +#include "asmconstants.h" +#include "asmmacros.h" + + IMPORT FuncEvalHijackWorker + IMPORT FuncEvalHijackPersonalityRoutine + IMPORT ExceptionHijackWorker + IMPORT ExceptionHijackPersonalityRoutine + EXPORT ExceptionHijackEnd +; +; hijacking stub used to perform a func-eval, see Debugger::FuncEvalSetup() for use. +; +; on entry: +; x0 : pointer to DebuggerEval object +; + + NESTED_ENTRY FuncEvalHijack,,FuncEvalHijackPersonalityRoutine + + ; NOTE: FuncEvalHijackPersonalityRoutine is dependent on the stack layout so if + ; you change the prolog you will also need to update the personality routine. + + ; push arg to the stack so our personality routine can find it + ; push lr to get good stacktrace in debugger + PROLOG_SAVE_REG_PAIR fp, lr, #-32! + str x0, [sp, #16] + ; FuncEvalHijackWorker returns the address we should jump to. + bl FuncEvalHijackWorker + + EPILOG_STACK_FREE 32 + EPILOG_BRANCH_REG x0 + NESTED_END FuncEvalHijack + + NESTED_ENTRY ExceptionHijack,,ExceptionHijackPersonalityRoutine + + ; make the call + bl ExceptionHijackWorker + + ; effective NOP to terminate unwind + mov x3, x3 + + ; *** should never get here *** + EMIT_BREAKPOINT + +; exported label so the debugger knows where the end of this function is +ExceptionHijackEnd + NESTED_END ExceptionHijack + + ; must be at end of file + END + diff --git a/src/debug/ee/controller.cpp b/src/debug/ee/controller.cpp index de19f7d6ba..7f4d44568d 100644 --- a/src/debug/ee/controller.cpp +++ b/src/debug/ee/controller.cpp @@ -1373,7 +1373,7 @@ bool DebuggerController::ApplyPatch(DebuggerControllerPatch *patch) patch->opcode = CORDbgGetInstruction(patch->address); CORDbgInsertBreakpoint((CORDB_ADDRESS_TYPE *)patch->address); - LOG((LF_CORDB, LL_EVERYTHING, "Breakpoint was inserted\n")); + LOG((LF_CORDB, LL_EVERYTHING, "Breakpoint was inserted at %p for opcode %x\n", patch->address, patch->opcode)); if (!VirtualProtect(baseAddress, CORDbg_BREAK_INSTRUCTION_SIZE, @@ -2531,7 +2531,7 @@ DPOSS_ACTION DebuggerController::ScanForTriggers(CORDB_ADDRESS_TYPE *address, CONTRACT_VIOLATION(ThrowsViolation); - LOG((LF_CORDB, LL_INFO10000, "DC::SFT: starting scan for addr:0x%x" + LOG((LF_CORDB, LL_INFO10000, "DC::SFT: starting scan for addr:0x%p" " thread:0x%x\n", address, thread)); _ASSERTE( pTpr != NULL ); @@ -4069,7 +4069,7 @@ bool DebuggerController::DispatchNativeException(EXCEPTION_RECORD *pException, CONTRACTL_END; LOG((LF_CORDB, LL_EVERYTHING, "DispatchNativeException was called\n")); - LOG((LF_CORDB, LL_INFO10000, "Native exception at 0x%x, code=0x%8x, context=0x%p, er=0x%p\n", + LOG((LF_CORDB, LL_INFO10000, "Native exception at 0x%p, code=0x%8x, context=0x%p, er=0x%p\n", pException->ExceptionAddress, dwCode, pContext, pException)); @@ -4290,7 +4290,7 @@ DebuggerPatchSkip::DebuggerPatchSkip(Thread *thread, m_address(patch->address) { LOG((LF_CORDB, LL_INFO10000, - "DPS::DPS: Patch skip 0x%x\n", patch->address)); + "DPS::DPS: Patch skip 0x%p\n", patch->address)); // On ARM the single-step emulation already utilizes a per-thread execution buffer similar to the scheme // below. As a result we can skip most of the instruction parsing logic that's instead internalized into @@ -4330,14 +4330,15 @@ DebuggerPatchSkip::DebuggerPatchSkip(Thread *thread, CORDbgSetInstruction((CORDB_ADDRESS_TYPE *)patchBypass, patch->opcode); LOG((LF_CORDB, LL_EVERYTHING, "SetInstruction was called\n")); - // // Look at instruction to get some attributes // NativeWalker::DecodeInstructionForPatchSkip(patchBypass, &(m_instrAttrib)); - + #if defined(_TARGET_AMD64_) + + // The code below handles RIP-relative addressing on AMD64. the original implementation made the assumption that // we are only using RIP-relative addressing to access read-only data (see VSW 246145 for more information). this // has since been expanded to handle RIP-relative writes as well. @@ -4392,7 +4393,7 @@ DebuggerPatchSkip::DebuggerPatchSkip(Thread *thread, // Set IP of context to point to patch bypass buffer // - CONTEXT *context = g_pEEInterface->GetThreadFilterContext(thread); + T_CONTEXT *context = g_pEEInterface->GetThreadFilterContext(thread); _ASSERTE(!ISREDIRECTEDTHREAD(thread)); CONTEXT c; if (context == NULL) @@ -4409,7 +4410,7 @@ DebuggerPatchSkip::DebuggerPatchSkip(Thread *thread, c.ContextFlags = CONTEXT_CONTROL; thread->GetThreadContext(&c); - context = &c; + context =(T_CONTEXT *) &c; ARM_ONLY(_ASSERTE(!"We should always have a filter context in DebuggerPatchSkip.")); } @@ -4436,16 +4437,21 @@ DebuggerPatchSkip::DebuggerPatchSkip(Thread *thread, thread->BypassWithSingleStep((DWORD)patch->address, patch->opcode, opcode2); m_singleStep = true; } + #else // _TARGET_ARM_ + +#ifdef _TARGET_ARM64_ + patchBypass = NativeWalker::SetupOrSimulateInstructionForPatchSkip(context, m_pSharedPatchBypassBuffer, (const BYTE *)patch->address, patch->opcode); +#endif //_TARGET_ARM64_ //set eip to point to buffer... SetIP(context, (PCODE)patchBypass); - if (context == &c) + if (context ==(T_CONTEXT*) &c) thread->SetThreadContext(&c); - LOG((LF_CORDB, LL_INFO10000, "Bypass at 0x%x\n", patchBypass)); + LOG((LF_CORDB, LL_INFO10000, "DPS::DPS Bypass at 0x%p for opcode %p \n", patchBypass, patch->opcode)); // // Turn on single step (if the platform supports it) so we can @@ -4642,7 +4648,32 @@ TP_RESULT DebuggerPatchSkip::TriggerExceptionHook(Thread *thread, CONTEXT * cont LOG((LF_CORDB,LL_INFO10000, "DPS::TEH: doing the patch-skip thing\n")); -#ifndef _TARGET_ARM_ +#if defined(_TARGET_ARM64_) + + if (!IsSingleStep(exception->ExceptionCode)) + { + LOG((LF_CORDB, LL_INFO10000, "Exception in patched Bypass instruction .\n")); + return (TPR_IGNORE_AND_STOP); + } + + _ASSERTE(m_pSharedPatchBypassBuffer); + BYTE* patchBypass = m_pSharedPatchBypassBuffer->PatchBypass; + PCODE targetIp; + if (m_pSharedPatchBypassBuffer->RipTargetFixup) + { + targetIp = m_pSharedPatchBypassBuffer->RipTargetFixup; + } + else + { + targetIp = (PCODE)((BYTE *)GetIP(context) - (patchBypass - (BYTE *)m_address)); + } + + SetIP(context, targetIp); + LOG((LF_CORDB, LL_ALWAYS, "Redirecting after Patch to 0x%p\n", GetIP(context))); + +#elif defined (_TARGET_ARM_) +//Do nothing +#else _ASSERTE(m_pSharedPatchBypassBuffer); BYTE* patchBypass = m_pSharedPatchBypassBuffer->PatchBypass; @@ -4754,7 +4785,8 @@ TP_RESULT DebuggerPatchSkip::TriggerExceptionHook(Thread *thread, CONTEXT * cont } -#endif // _TARGET_ARM_ +#endif + // Signals our thread that the debugger is done manipulating the context // during the patch skip operation. This effectively prevented other threads @@ -5906,7 +5938,7 @@ bool DebuggerStepper::TrapStep(ControllerStackInfo *info, bool in) SIZE_T offset = CodeRegionInfo::GetCodeRegionInfo(ji, info->m_activeFrame.md).AddressToOffset(ip); - LOG((LF_CORDB, LL_INFO1000, "Walking to ip 0x%x (natOff:0x%x)\n",ip,offset)); + LOG((LF_CORDB, LL_INFO1000, "Walking to ip 0x%p (natOff:0x%x)\n",ip,offset)); if (!IsInRange(offset, range, rangeCount) && !ShouldContinueStep( info, offset )) @@ -7040,7 +7072,7 @@ TP_RESULT DebuggerStepper::TriggerPatch(DebuggerControllerPatch *patch, // Grab the jit info for the method. DebuggerJitInfo *dji; dji = g_pDebugger->GetJitInfoFromAddr((TADDR) traceManagerRetAddr); - + MethodDesc * mdNative = (dji == NULL) ? g_pEEInterface->GetNativeCodeMethodDesc(dac_cast<PCODE>(traceManagerRetAddr)) : dji->m_fd; _ASSERTE(mdNative != NULL); diff --git a/src/debug/ee/controller.h b/src/debug/ee/controller.h index 0826e469cb..6611e044e5 100644 --- a/src/debug/ee/controller.h +++ b/src/debug/ee/controller.h @@ -213,6 +213,9 @@ public: *(reinterpret_cast<DWORD*>(BypassBuffer)) = SentinelValue; RipTargetFixup = 0; RipTargetFixupSize = 0; +#elif _TARGET_ARM64_ + RipTargetFixup = 0; + #endif } @@ -251,6 +254,8 @@ public: UINT_PTR RipTargetFixup; BYTE RipTargetFixupSize; +#elif defined(_TARGET_ARM64_) + UINT_PTR RipTargetFixup; #endif private: diff --git a/src/debug/ee/debugger.cpp b/src/debug/ee/debugger.cpp index 8634630ebe..a9876abc35 100644 --- a/src/debug/ee/debugger.cpp +++ b/src/debug/ee/debugger.cpp @@ -8380,7 +8380,7 @@ FramePointer GetHandlerFramePointer(BYTE *pStack) { FramePointer handlerFP; -#if !defined(_TARGET_ARM_) +#if !defined(_TARGET_ARM_) && !defined(_TARGET_ARM64_) // Refer to the comment in DispatchUnwind() to see why we have to add // sizeof(LPVOID) to the handler ebp. handlerFP = FramePointer::MakeFramePointer(LPVOID(pStack + sizeof(void*))); @@ -11888,7 +11888,7 @@ HRESULT Debugger::GetAndSendInterceptCommand(DebuggerIPCEvent *event) csi.m_activeFrame.MethodToken, csi.m_activeFrame.md, foundOffset, -#ifdef _TARGET_ARM_ +#if defined (_TARGET_ARM_ )|| defined (_TARGET_ARM64_ ) // ARM requires the caller stack pointer, not the current stack pointer CallerStackFrame::FromRegDisplay(&(csi.m_activeFrame.registers)), #else @@ -15359,6 +15359,8 @@ HRESULT Debugger::FuncEvalSetup(DebuggerIPCE_FuncEvalInfo *pEvalInfo, #endif // !UNIX_AMD64_ABI #elif defined(_TARGET_ARM_) filterContext->R0 = (DWORD)pDE; +#elif defined(_TARGET_ARM64_) + filterContext->X0 = (SIZE_T)pDE; #else PORTABILITY_ASSERT("Debugger::FuncEvalSetup is not implemented on this platform."); #endif @@ -15453,6 +15455,8 @@ HRESULT Debugger::FuncEvalSetupReAbort(Thread *pThread, Thread::ThreadAbortReque filterContext->Rcx = (SIZE_T)pDE; #elif defined(_TARGET_ARM_) filterContext->R0 = (DWORD)pDE; +#elif defined(_TARGET_ARM64_) + filterContext->X0 = (SIZE_T)pDE; #else PORTABILITY_ASSERT("FuncEvalSetupReAbort (Debugger.cpp) is not implemented on this platform."); #endif diff --git a/src/debug/ee/frameinfo.cpp b/src/debug/ee/frameinfo.cpp index 1a56a4a493..35e5bb9a09 100644 --- a/src/debug/ee/frameinfo.cpp +++ b/src/debug/ee/frameinfo.cpp @@ -1424,7 +1424,7 @@ StackWalkAction DebuggerWalkStackProc(CrawlFrame *pCF, void *data) d->info.fp = GetFramePointerForDebugger(d, pCF); -#if defined(_DEBUG) && !defined(_TARGET_ARM_) +#if defined(_DEBUG) && !defined(_TARGET_ARM_) && !defined(_TARGET_ARM64_) // Make sure the stackwalk is making progress. // On ARM this is invalid as the stack pointer does necessarily have to move when unwinding a frame. _ASSERTE(IsCloserToLeaf(d->previousFP, d->info.fp)); diff --git a/src/debug/ee/funceval.cpp b/src/debug/ee/funceval.cpp index d195fafb8b..d2e5576855 100644 --- a/src/debug/ee/funceval.cpp +++ b/src/debug/ee/funceval.cpp @@ -3962,6 +3962,12 @@ FuncEvalHijackPersonalityRoutine(IN PEXCEPTION_RECORD pExceptionRecord // in FuncEvalHijack we allocate 8 bytes of stack space and then store R0 at the current SP, so if we subtract 8 from // the establisher frame we can get the stack location where R0 was stored. pDE = *(DebuggerEval**)(pDispatcherContext->EstablisherFrame - 8); + +#elif defined(_TARGET_ARM64_) + // on ARM64 the establisher frame is the SP of the caller of FuncEvalHijack. + // in FuncEvalHijack we allocate 32 bytes of stack space and then store R0 at the current SP + 16, so if we subtract 16 from + // the establisher frame we can get the stack location where R0 was stored. + pDE = *(DebuggerEval**)(pDispatcherContext->EstablisherFrame - 16); #else _ASSERTE(!"NYI - FuncEvalHijackPersonalityRoutine()"); #endif diff --git a/src/debug/ee/walker.h b/src/debug/ee/walker.h index ee46060382..d7deb10ca4 100644 --- a/src/debug/ee/walker.h +++ b/src/debug/ee/walker.h @@ -13,6 +13,7 @@ #ifndef WALKER_H_ #define WALKER_H_ + /* ========================================================================= */ /* ------------------------------------------------------------------------- * @@ -40,6 +41,7 @@ struct InstructionAttribute bool m_fIsAbsBranch; // is this an absolute branch (either a call or a jump)? bool m_fIsRelBranch; // is this a relative branch (either a call or a jump)? bool m_fIsWrite; // does the instruction write to an address? + DWORD m_cbInstr; // the size of the instruction DWORD m_cbDisp; // the size of the displacement @@ -54,7 +56,6 @@ struct InstructionAttribute m_fIsAbsBranch = false; m_fIsRelBranch = false; m_fIsWrite = false; - m_cbInstr = 0; m_cbDisp = 0; m_dwOffsetToDisp = 0; @@ -102,7 +103,7 @@ public: // We don't currently keep the registers up to date // <TODO> Check if it really works on IA64. </TODO> virtual void Next() { m_registers = NULL; SetIP(m_nextIP); } - virtual void Skip() { m_registers = NULL; SetIP(m_skipIP); } + virtual void Skip() { m_registers = NULL; LOG((LF_CORDB, LL_INFO10000, "skipping over to %p \n", m_skipIP)); SetIP(m_skipIP); } // Decode the instruction virtual void Decode() = 0; @@ -196,7 +197,25 @@ private: DWORD m_opcode; // Current instruction or opcode }; +#elif defined (_TARGET_ARM64_) +#include "controller.h" +class NativeWalker : public Walker +{ +public: + void Init(const BYTE *ip, REGDISPLAY *pregisters) + { + Walker::Init(ip, pregisters); + } + void Decode(); + static void NativeWalker::DecodeInstructionForPatchSkip(const BYTE *address, InstructionAttribute * pInstrAttrib) + { + pInstrAttrib->Reset(); + } + static BOOL NativeWalker::DecodePCRelativeBranchInst(PT_CONTEXT context,const PRD_TYPE& opcode, PCODE& offset, WALK_TYPE& walk); + static BOOL NativeWalker::DecodeCallInst(const PRD_TYPE& opcode, int& RegNum, WALK_TYPE& walk); + static BYTE* SetupOrSimulateInstructionForPatchSkip(T_CONTEXT * context, SharedPatchBypassBuffer * m_pSharedPatchBypassBuffer, const BYTE *address, PRD_TYPE opcode); +}; #else PORTABILITY_WARNING("NativeWalker not implemented on this platform"); class NativeWalker : public Walker diff --git a/src/debug/ee/wks/CMakeLists.txt b/src/debug/ee/wks/CMakeLists.txt index 36cb25e9e6..a3cb48324b 100644 --- a/src/debug/ee/wks/CMakeLists.txt +++ b/src/debug/ee/wks/CMakeLists.txt @@ -10,19 +10,26 @@ if (CLR_CMAKE_PLATFORM_ARCH_I386) list (APPEND ASM_OPTIONS /safeseh) endif (CLR_CMAKE_PLATFORM_ARCH_I386) -# Need to compile asm file using custom command as include directories are not provided to asm compiler -add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/dbghelpers.obj - COMMAND ${CMAKE_ASM_MASM_COMPILER} ${ASM_INCLUDE_DIRECTORIES} ${ASM_DEFINITIONS} ${ASM_OPTIONS} /Fo${CMAKE_CURRENT_BINARY_DIR}/dbghelpers.obj /Ta${CORDBEE_DIR}/${ARCH_SOURCES_DIR}/dbghelpers.asm - DEPENDS ${CORDBEE_DIR}/${ARCH_SOURCES_DIR}/dbghelpers.asm - COMMENT "Compiling dbghelpers.asm") - -if(CLR_CMAKE_PLATFORM_ARCH_ARM64) - #mark obj as source that does not require compile - set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/dbghelpers.obj PROPERTIES EXTERNAL_OBJECT TRUE) - add_library_clr(cordbee_wks ${CORDBEE_SOURCES_WKS}) -else() - add_library_clr(cordbee_wks ${CORDBEE_SOURCES_WKS} ${CMAKE_CURRENT_BINARY_DIR}/dbghelpers.obj) -endif() +set(ASM_FILE ${CORDBEE_DIR}/${ARCH_SOURCES_DIR}/dbghelpers.asm) +# asm files require preprocessing using cl.exe on arm64 + if(CLR_CMAKE_PLATFORM_ARCH_ARM64) + get_filename_component(name ${ASM_FILE} NAME_WE) + set(ASM_PREPROCESSED_FILE ${CMAKE_CURRENT_BINARY_DIR}/${name}.asm) + preprocess_def_file(${ASM_FILE} ${ASM_PREPROCESSED_FILE}) + set(CORDBEE_SOURCES_WKS_PREPROCESSED_ASM ${ASM_PREPROCESSED_FILE}) + set_property(SOURCE ${CORDBEE_SOURCES_WKS_PREPROCESSED_ASM} PROPERTY COMPILE_DEFINITIONS ${ASM_DEFINITIONS}) + set_property(SOURCE ${CORDBEE_SOURCES_WKS_PREPROCESSED_ASM} PROPERTY COMPILE_DEFINITIONS ${ASM_OPTIONS}) + add_library_clr(cordbee_wks ${CORDBEE_SOURCES_WKS} ${CORDBEE_SOURCES_WKS_PREPROCESSED_ASM}) + else () + + # Need to compile asm file using custom command as include directories are not provided to asm compiler + add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/dbghelpers.obj + COMMAND ${CMAKE_ASM_MASM_COMPILER} ${ASM_INCLUDE_DIRECTORIES} ${ASM_DEFINITIONS} ${ASM_OPTIONS} /Fo${CMAKE_CURRENT_BINARY_DIR}/dbghelpers.obj /Ta${ASM_FILE} + DEPENDS ${ASM_FILE} + COMMENT "Compiling dbghelpers.asm") + + add_library_clr(cordbee_wks ${CORDBEE_SOURCES_WKS} ${CMAKE_CURRENT_BINARY_DIR}/dbghelpers.obj) + endif(CLR_CMAKE_PLATFORM_ARCH_ARM64) else () diff --git a/src/debug/ee/wks/wks.nativeproj b/src/debug/ee/wks/wks.nativeproj index 7386b5d119..8d89ac45cc 100644 --- a/src/debug/ee/wks/wks.nativeproj +++ b/src/debug/ee/wks/wks.nativeproj @@ -32,6 +32,7 @@ <CppCompile Include="@(ArmSources)" /> <CppCompile Include="@(Arm64Sources)" /> <PreprocessAssembleArm Condition="'$(BuildArchitecture)' == 'arm'" Include="..\arm\dbghelpers.asm" /> + <PreprocessAssembleArm Condition="'$(BuildArchitecture)' == 'arm64'" Include="..\arm64\dbghelpers.asm" /> <AssembleArm Condition="'$(BuildArchitecture)' == 'arm'" Include="$(IntermediateOutputDirectory)\dbghelpers.i" /> <Assemble386 Condition="'$(BuildArchitecture)' == 'i386'" Include="..\i386\dbghelpers.asm" /> <AssembleAmd64 Condition="'$(BuildArchitecture)' == 'amd64'" Include="..\amd64\dbghelpers.asm" /> diff --git a/src/debug/inc/arm64/primitives.h b/src/debug/inc/arm64/primitives.h index 69739691f7..e9e04378f7 100644 --- a/src/debug/inc/arm64/primitives.h +++ b/src/debug/inc/arm64/primitives.h @@ -13,10 +13,11 @@ #ifndef PRIMITIVES_H_ #define PRIMITIVES_H_ +typedef NEON128 FPRegister64; typedef const BYTE CORDB_ADDRESS_TYPE; typedef DPTR(CORDB_ADDRESS_TYPE) PTR_CORDB_ADDRESS_TYPE; -#define MAX_INSTRUCTION_LENGTH 8 +#define MAX_INSTRUCTION_LENGTH 4 // Given a return address retrieved during stackwalk, // this is the offset by which it should be decremented to land at the call instruction. @@ -26,6 +27,16 @@ typedef DPTR(CORDB_ADDRESS_TYPE) PTR_CORDB_ADDRESS_TYPE; #define CORDbg_BREAK_INSTRUCTION_SIZE 4 #define CORDbg_BREAK_INSTRUCTION (LONG)0xD43E0000 +#define NZCV_N 0x80000000 +#define NZCV_Z 0x40000000 +#define NZCV_C 0x20000000 +#define NZCV_V 0x10000000 + +#define NZCV_N_BIT 0x1f +#define NZCV_Z_BIT 0x1e +#define NZCV_C_BIT 0x1d +#define NZCV_V_BIT 0x1c + inline CORDB_ADDRESS GetPatchEndAddr(CORDB_ADDRESS patchAddr) { LIMITED_METHOD_DAC_CONTRACT; @@ -170,5 +181,6 @@ inline bool IsSSFlagEnabled(DT_CONTEXT * pContext) return (pContext->Cpsr & 0x00200000) != 0; } + #include "arm_primitives.h" #endif // PRIMITIVES_H_ |