summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--functions.cmake6
-rw-r--r--src/debug/daccess/dacdbiimpl.cpp5
-rw-r--r--src/debug/di/CMakeLists.txt22
-rw-r--r--src/debug/di/DI.props6
-rw-r--r--src/debug/di/arm64/cordbregisterset.cpp4
-rw-r--r--src/debug/di/arm64/floatconversion.asm22
-rw-r--r--src/debug/di/module.cpp4
-rw-r--r--src/debug/di/rspriv.h2
-rw-r--r--src/debug/di/rsthread.cpp34
-rw-r--r--src/debug/di/shimstackwalk.cpp2
-rw-r--r--src/debug/ee/arm64/arm64walker.cpp461
-rw-r--r--src/debug/ee/arm64/dbghelpers.asm54
-rw-r--r--src/debug/ee/controller.cpp60
-rw-r--r--src/debug/ee/controller.h5
-rw-r--r--src/debug/ee/debugger.cpp8
-rw-r--r--src/debug/ee/frameinfo.cpp2
-rw-r--r--src/debug/ee/funceval.cpp6
-rw-r--r--src/debug/ee/walker.h23
-rw-r--r--src/debug/ee/wks/CMakeLists.txt33
-rw-r--r--src/debug/ee/wks/wks.nativeproj1
-rw-r--r--src/debug/inc/arm64/primitives.h14
-rw-r--r--src/inc/cordebug.idl33
-rw-r--r--src/pal/prebuilt/inc/cordebug.h44
-rw-r--r--src/vm/arm64/cgencpu.h63
-rw-r--r--src/vm/arm64/stubs.cpp17
-rw-r--r--src/vm/exceptionhandling.cpp3
-rw-r--r--src/vm/stubmgr.cpp12
-rw-r--r--src/vm/stubmgr.h2
-rw-r--r--src/vm/util.cpp40
29 files changed, 909 insertions, 79 deletions
diff --git a/functions.cmake b/functions.cmake
index a61687e7a6..bbc571b46d 100644
--- a/functions.cmake
+++ b/functions.cmake
@@ -47,10 +47,10 @@ endfunction(convert_to_absolute_path)
#Preprocess exports definition file
function(preprocess_def_file inputFilename outputFilename)
get_compile_definitions(PREPROCESS_DEFINITIONS)
-
+ get_include_directories(ASM_INCLUDE_DIRECTORIES)
add_custom_command(
OUTPUT ${outputFilename}
- COMMAND ${CMAKE_CXX_COMPILER} /P /EP /TC ${PREPROCESS_DEFINITIONS} /Fi${outputFilename} ${inputFilename}
+ COMMAND ${CMAKE_CXX_COMPILER} ${ASM_INCLUDE_DIRECTORIES} /P /EP /TC ${PREPROCESS_DEFINITIONS} /Fi${outputFilename} ${inputFilename}
DEPENDS ${inputFilename}
COMMENT "Preprocessing ${inputFilename}"
)
@@ -185,4 +185,4 @@ function(_install)
if(NOT DEFINED CLR_CROSS_COMPONENTS_BUILD)
install(${ARGV})
endif()
-endfunction() \ No newline at end of file
+endfunction()
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_
diff --git a/src/inc/cordebug.idl b/src/inc/cordebug.idl
index 72549aefe5..49b8acc923 100644
--- a/src/inc/cordebug.idl
+++ b/src/inc/cordebug.idl
@@ -3737,6 +3737,39 @@ interface ICorDebugRegisterSet : IUnknown
REGISTER_ARM64_X28,
REGISTER_ARM64_LR,
+ REGISTER_ARM64_V0,
+ REGISTER_ARM64_V1,
+ REGISTER_ARM64_V2,
+ REGISTER_ARM64_V3,
+ REGISTER_ARM64_V4,
+ REGISTER_ARM64_V5,
+ REGISTER_ARM64_V6,
+ REGISTER_ARM64_V7,
+ REGISTER_ARM64_V8,
+ REGISTER_ARM64_V9,
+ REGISTER_ARM64_V10,
+ REGISTER_ARM64_V11,
+ REGISTER_ARM64_V12,
+ REGISTER_ARM64_V13,
+ REGISTER_ARM64_V14,
+ REGISTER_ARM64_V15,
+ REGISTER_ARM64_V16,
+ REGISTER_ARM64_V17,
+ REGISTER_ARM64_V18,
+ REGISTER_ARM64_V19,
+ REGISTER_ARM64_V20,
+ REGISTER_ARM64_V21,
+ REGISTER_ARM64_V22,
+ REGISTER_ARM64_V23,
+ REGISTER_ARM64_V24,
+ REGISTER_ARM64_V25,
+ REGISTER_ARM64_V26,
+ REGISTER_ARM64_V27,
+ REGISTER_ARM64_V28,
+ REGISTER_ARM64_V29,
+ REGISTER_ARM64_V30,
+ REGISTER_ARM64_V31,
+
// other architectures here
} CorDebugRegister;
diff --git a/src/pal/prebuilt/inc/cordebug.h b/src/pal/prebuilt/inc/cordebug.h
index 46f6929778..a5a5cf2e8a 100644
--- a/src/pal/prebuilt/inc/cordebug.h
+++ b/src/pal/prebuilt/inc/cordebug.h
@@ -3,11 +3,11 @@
/* this ALWAYS GENERATED file contains the definitions for the interfaces */
- /* File created by MIDL compiler version 8.00.0613 */
-/* at Mon Jan 18 19:14:07 2038
+ /* File created by MIDL compiler version 8.00.0603 */
+/* at Fri Jul 15 18:01:08 2016
*/
-/* Compiler settings for C:/ssd/coreclr/src/inc/cordebug.idl:
- Oicf, W1, Zp8, env=Win32 (32b run), target_arch=X86 8.00.0613
+/* Compiler settings for E:/git/coreclr/src/inc/cordebug.idl:
+ Oicf, W1, Zp8, env=Win32 (32b run), target_arch=X86 8.00.0603
protocol : dce , ms_ext, c_ext, robust
error checks: allocation ref bounds_check enum stub_data
VC __declspec() decoration level:
@@ -29,7 +29,7 @@
#ifndef __RPCNDR_H_VERSION__
#error this stub requires an updated version of <rpcndr.h>
-#endif /* __RPCNDR_H_VERSION__ */
+#endif // __RPCNDR_H_VERSION__
#ifndef COM_NO_WINDOWS_H
#include "windows.h"
@@ -8639,7 +8639,39 @@ enum CorDebugRegister
REGISTER_ARM64_X26 = ( REGISTER_ARM64_X25 + 1 ) ,
REGISTER_ARM64_X27 = ( REGISTER_ARM64_X26 + 1 ) ,
REGISTER_ARM64_X28 = ( REGISTER_ARM64_X27 + 1 ) ,
- REGISTER_ARM64_LR = ( REGISTER_ARM64_X28 + 1 )
+ REGISTER_ARM64_LR = ( REGISTER_ARM64_X28 + 1 ) ,
+ REGISTER_ARM64_V0 = ( REGISTER_ARM64_LR + 1 ) ,
+ REGISTER_ARM64_V1 = ( REGISTER_ARM64_V0 + 1 ) ,
+ REGISTER_ARM64_V2 = ( REGISTER_ARM64_V1 + 1 ) ,
+ REGISTER_ARM64_V3 = ( REGISTER_ARM64_V2 + 1 ) ,
+ REGISTER_ARM64_V4 = ( REGISTER_ARM64_V3 + 1 ) ,
+ REGISTER_ARM64_V5 = ( REGISTER_ARM64_V4 + 1 ) ,
+ REGISTER_ARM64_V6 = ( REGISTER_ARM64_V5 + 1 ) ,
+ REGISTER_ARM64_V7 = ( REGISTER_ARM64_V6 + 1 ) ,
+ REGISTER_ARM64_V8 = ( REGISTER_ARM64_V7 + 1 ) ,
+ REGISTER_ARM64_V9 = ( REGISTER_ARM64_V8 + 1 ) ,
+ REGISTER_ARM64_V10 = ( REGISTER_ARM64_V9 + 1 ) ,
+ REGISTER_ARM64_V11 = ( REGISTER_ARM64_V10 + 1 ) ,
+ REGISTER_ARM64_V12 = ( REGISTER_ARM64_V11 + 1 ) ,
+ REGISTER_ARM64_V13 = ( REGISTER_ARM64_V12 + 1 ) ,
+ REGISTER_ARM64_V14 = ( REGISTER_ARM64_V13 + 1 ) ,
+ REGISTER_ARM64_V15 = ( REGISTER_ARM64_V14 + 1 ) ,
+ REGISTER_ARM64_V16 = ( REGISTER_ARM64_V15 + 1 ) ,
+ REGISTER_ARM64_V17 = ( REGISTER_ARM64_V16 + 1 ) ,
+ REGISTER_ARM64_V18 = ( REGISTER_ARM64_V17 + 1 ) ,
+ REGISTER_ARM64_V19 = ( REGISTER_ARM64_V18 + 1 ) ,
+ REGISTER_ARM64_V20 = ( REGISTER_ARM64_V19 + 1 ) ,
+ REGISTER_ARM64_V21 = ( REGISTER_ARM64_V20 + 1 ) ,
+ REGISTER_ARM64_V22 = ( REGISTER_ARM64_V21 + 1 ) ,
+ REGISTER_ARM64_V23 = ( REGISTER_ARM64_V22 + 1 ) ,
+ REGISTER_ARM64_V24 = ( REGISTER_ARM64_V23 + 1 ) ,
+ REGISTER_ARM64_V25 = ( REGISTER_ARM64_V24 + 1 ) ,
+ REGISTER_ARM64_V26 = ( REGISTER_ARM64_V25 + 1 ) ,
+ REGISTER_ARM64_V27 = ( REGISTER_ARM64_V26 + 1 ) ,
+ REGISTER_ARM64_V28 = ( REGISTER_ARM64_V27 + 1 ) ,
+ REGISTER_ARM64_V29 = ( REGISTER_ARM64_V28 + 1 ) ,
+ REGISTER_ARM64_V30 = ( REGISTER_ARM64_V29 + 1 ) ,
+ REGISTER_ARM64_V31 = ( REGISTER_ARM64_V30 + 1 )
} CorDebugRegister;
diff --git a/src/vm/arm64/cgencpu.h b/src/vm/arm64/cgencpu.h
index 4929cd1dc9..53079352cb 100644
--- a/src/vm/arm64/cgencpu.h
+++ b/src/vm/arm64/cgencpu.h
@@ -153,9 +153,34 @@ inline TADDR GetSP(const T_CONTEXT * context) {
return TADDR(context->Sp);
}
-inline PCODE GetLR(const T_CONTEXT * context) {
+inline TADDR GetLR(const T_CONTEXT * context) {
LIMITED_METHOD_DAC_CONTRACT;
- return PCODE(context->Lr);
+ return context->Lr;
+}
+
+inline void SetLR( T_CONTEXT * context, TADDR eip) {
+ LIMITED_METHOD_DAC_CONTRACT;
+ context->Lr = eip;
+}
+
+inline TADDR GetReg(T_CONTEXT * context, int Regnum)
+{
+ LIMITED_METHOD_DAC_CONTRACT;
+ _ASSERTE(Regnum >= 0 && Regnum < 32 );
+ return context->X[Regnum];
+}
+
+inline void SetReg(T_CONTEXT * context, int Regnum, PCODE RegContent)
+{
+ LIMITED_METHOD_DAC_CONTRACT;
+ _ASSERTE(Regnum >= 0 && Regnum <=28 );
+ context->X[Regnum] = RegContent;
+}
+inline void SetSimdReg(T_CONTEXT * context, int Regnum, NEON128 RegContent)
+{
+ LIMITED_METHOD_DAC_CONTRACT;
+ _ASSERTE(Regnum >= 0 && Regnum <= 28);
+ context->V[Regnum] = RegContent;
}
extern "C" LPVOID __stdcall GetCurrentSP();
@@ -176,6 +201,40 @@ inline TADDR GetFP(const T_CONTEXT * context)
return (TADDR)(context->Fp);
}
+inline NEON128 GetSimdMem(PCODE ip)
+{
+ NEON128 mem;
+ LIMITED_METHOD_DAC_CONTRACT;
+ EX_TRY
+ {
+ mem.Low = dac_cast<PCODE>(ip);
+ mem.High = dac_cast<PCODE>(ip + sizeof(PCODE));
+ }
+ EX_CATCH
+ {
+ _ASSERTE(!"Memory read within jitted Code Failed, this should not happen!!!!");
+ }
+ EX_END_CATCH(SwallowAllExceptions);
+
+ return mem;
+}
+inline TADDR GetMem(PCODE ip)
+{
+ TADDR mem;
+ LIMITED_METHOD_DAC_CONTRACT;
+ EX_TRY
+ {
+ mem = dac_cast<TADDR>(ip);
+ }
+ EX_CATCH
+ {
+ _ASSERTE(!"Memory read within jitted Code Failed, this should not happen!!!!");
+ }
+ EX_END_CATCH(SwallowAllExceptions);
+ return mem;
+}
+
+
#ifdef FEATURE_COMINTEROP
void emitCOMStubCall (ComCallMethodDesc *pCOMMethod, PCODE target);
#endif // FEATURE_COMINTEROP
diff --git a/src/vm/arm64/stubs.cpp b/src/vm/arm64/stubs.cpp
index bb2a6cf256..7db8a31f20 100644
--- a/src/vm/arm64/stubs.cpp
+++ b/src/vm/arm64/stubs.cpp
@@ -1051,23 +1051,6 @@ AdjustContextForVirtualStub(
}
#endif // !(DACCESS_COMPILE && CROSSGEN_COMPILE)
-extern "C" {
-
-void FuncEvalHijack(void)
-{
- _ASSERTE(!"ARM64:NYI");
-}
-
-void ExceptionHijack(void)
-{
- _ASSERTE(!"ARM64:NYI");
-}
-void ExceptionHijackEnd(void)
-{
- _ASSERTE(!"ARM64:NYI");
-}
-};
-
#ifdef FEATURE_COMINTEROP
extern "C" void GenericComPlusCallStub(void)
{
diff --git a/src/vm/exceptionhandling.cpp b/src/vm/exceptionhandling.cpp
index a99a20b312..e59f10e070 100644
--- a/src/vm/exceptionhandling.cpp
+++ b/src/vm/exceptionhandling.cpp
@@ -2457,7 +2457,7 @@ CLRUnwindStatus ExceptionTracker::ProcessManagedCallFrame(
PTR_EXCEPTION_CLAUSE_TOKEN pLimitClauseToken = NULL;
if (!fIgnoreThisFrame && !fIsFirstPass && !m_sfResumeStackFrame.IsNull() && (sf >= m_sfResumeStackFrame))
{
- CONSISTENCY_CHECK_MSG(sf == m_sfResumeStackFrame, "Passed initial resume frame and fIgnoreThisFrame wasn't set!");
+ EH_LOG((LL_INFO100, " RESUMEFRAME: sf is %p and m_sfResumeStackFrame: %p\n", sf.SP, m_sfResumeStackFrame.SP));
EH_LOG((LL_INFO100, " RESUMEFRAME: %s initial resume frame: %p\n", (sf == m_sfResumeStackFrame) ? "REACHED" : "PASSED" , m_sfResumeStackFrame.SP));
// process this frame to call handlers
@@ -2469,6 +2469,7 @@ CLRUnwindStatus ExceptionTracker::ProcessManagedCallFrame(
// as the last clause we process in the "inital resume frame". Anything further
// down the list of clauses is skipped along with all call frames up to the actual
// resume frame.
+ CONSISTENCY_CHECK_MSG(sf == m_sfResumeStackFrame, "Passed initial resume frame and fIgnoreThisFrame wasn't set!");
}
//
// END resume frame code
diff --git a/src/vm/stubmgr.cpp b/src/vm/stubmgr.cpp
index d648262078..39f4c25a7d 100644
--- a/src/vm/stubmgr.cpp
+++ b/src/vm/stubmgr.cpp
@@ -2313,6 +2313,18 @@ BOOL DelegateInvokeStubManager::TraceManager(Thread *thread, TraceDestination *t
else
offsetOfNextDest = DelegateObject::GetOffsetOfMethodPtrAux();
destAddr = *(PCODE*)(pThis + offsetOfNextDest);
+#elif defined(_TARGET_ARM64_)
+ (*pRetAddr) = (BYTE *)(size_t)(pContext->Lr);
+ pThis = (BYTE*)(size_t)(pContext->X0);
+
+ // Could be in the singlecast invoke stub (in which case the next destination is in _methodPtr) or a
+ // shuffle thunk (destination in _methodPtrAux).
+ int offsetOfNextDest;
+ if (pc == GetEEFuncEntryPoint(SinglecastDelegateInvokeStub))
+ offsetOfNextDest = DelegateObject::GetOffsetOfMethodPtr();
+ else
+ offsetOfNextDest = DelegateObject::GetOffsetOfMethodPtrAux();
+ destAddr = *(PCODE*)(pThis + offsetOfNextDest);
#else
PORTABILITY_ASSERT("DelegateInvokeStubManager::TraceManager");
destAddr = NULL;
diff --git a/src/vm/stubmgr.h b/src/vm/stubmgr.h
index eecd616b7a..f0098c9d55 100644
--- a/src/vm/stubmgr.h
+++ b/src/vm/stubmgr.h
@@ -933,7 +933,7 @@ public:
#elif defined(_TARGET_ARM_)
return pContext->R12;
#elif defined(_TARGET_ARM64_)
- return pContext->X15;
+ return pContext->X12;
#else
PORTABILITY_ASSERT("StubManagerHelpers::GetHiddenArg");
return NULL;
diff --git a/src/vm/util.cpp b/src/vm/util.cpp
index 7a05624113..f7185c744f 100644
--- a/src/vm/util.cpp
+++ b/src/vm/util.cpp
@@ -739,6 +739,46 @@ SIZE_T GetRegOffsInCONTEXT(ICorDebugInfo::RegNum regNum)
case ICorDebugInfo::REGNUM_AMBIENT_SP: return offsetof(T_CONTEXT, Sp);
default: _ASSERTE(!"Bad regNum"); return (SIZE_T)(-1);
}
+#elif defined(_TARGET_ARM64_)
+
+ switch(regNum)
+ {
+ case ICorDebugInfo::REGNUM_X0: return offsetof(T_CONTEXT, X0);
+ case ICorDebugInfo::REGNUM_X1: return offsetof(T_CONTEXT, X1);
+ case ICorDebugInfo::REGNUM_X2: return offsetof(T_CONTEXT, X2);
+ case ICorDebugInfo::REGNUM_X3: return offsetof(T_CONTEXT, X3);
+ case ICorDebugInfo::REGNUM_X4: return offsetof(T_CONTEXT, X4);
+ case ICorDebugInfo::REGNUM_X5: return offsetof(T_CONTEXT, X5);
+ case ICorDebugInfo::REGNUM_X6: return offsetof(T_CONTEXT, X6);
+ case ICorDebugInfo::REGNUM_X7: return offsetof(T_CONTEXT, X7);
+ case ICorDebugInfo::REGNUM_X8: return offsetof(T_CONTEXT, X8);
+ case ICorDebugInfo::REGNUM_X9: return offsetof(T_CONTEXT, X9);
+ case ICorDebugInfo::REGNUM_X10: return offsetof(T_CONTEXT, X10);
+ case ICorDebugInfo::REGNUM_X11: return offsetof(T_CONTEXT, X11);
+ case ICorDebugInfo::REGNUM_X12: return offsetof(T_CONTEXT, X12);
+ case ICorDebugInfo::REGNUM_X13: return offsetof(T_CONTEXT, X13);
+ case ICorDebugInfo::REGNUM_X14: return offsetof(T_CONTEXT, X14);
+ case ICorDebugInfo::REGNUM_X15: return offsetof(T_CONTEXT, X15);
+ case ICorDebugInfo::REGNUM_X16: return offsetof(T_CONTEXT, X16);
+ case ICorDebugInfo::REGNUM_X17: return offsetof(T_CONTEXT, X17);
+ case ICorDebugInfo::REGNUM_X18: return offsetof(T_CONTEXT, X18);
+ case ICorDebugInfo::REGNUM_X19: return offsetof(T_CONTEXT, X19);
+ case ICorDebugInfo::REGNUM_X20: return offsetof(T_CONTEXT, X20);
+ case ICorDebugInfo::REGNUM_X21: return offsetof(T_CONTEXT, X21);
+ case ICorDebugInfo::REGNUM_X22: return offsetof(T_CONTEXT, X22);
+ case ICorDebugInfo::REGNUM_X23: return offsetof(T_CONTEXT, X23);
+ case ICorDebugInfo::REGNUM_X24: return offsetof(T_CONTEXT, X24);
+ case ICorDebugInfo::REGNUM_X25: return offsetof(T_CONTEXT, X25);
+ case ICorDebugInfo::REGNUM_X26: return offsetof(T_CONTEXT, X26);
+ case ICorDebugInfo::REGNUM_X27: return offsetof(T_CONTEXT, X27);
+ case ICorDebugInfo::REGNUM_X28: return offsetof(T_CONTEXT, X28);
+ case ICorDebugInfo::REGNUM_FP: return offsetof(T_CONTEXT, Fp);
+ case ICorDebugInfo::REGNUM_LR: return offsetof(T_CONTEXT, Lr);
+ case ICorDebugInfo::REGNUM_SP: return offsetof(T_CONTEXT, Sp);
+ case ICorDebugInfo::REGNUM_PC: return offsetof(T_CONTEXT, Pc);
+ case ICorDebugInfo::REGNUM_AMBIENT_SP: return offsetof(T_CONTEXT, Sp);
+ default: _ASSERTE(!"Bad regNum"); return (SIZE_T)(-1);
+ }
#else
PORTABILITY_ASSERT("GetRegOffsInCONTEXT is not implemented on this platform.");
return (SIZE_T) -1;