mirror of https://github.com/dotnet/runtime
Merge 0bc660ee66
into 02596ba8d9
This commit is contained in:
commit
d2c3d400aa
|
@ -21,6 +21,10 @@
|
|||
#include "../../vm/methoditer.h"
|
||||
#include "../../vm/tailcallhelp.h"
|
||||
|
||||
#if defined(TARGET_ARM64)
|
||||
extern "C" void* PacStripPtr(void* ptr);
|
||||
#endif // TARGET_ARM64
|
||||
|
||||
const char *GetTType( TraceType tt);
|
||||
|
||||
#define IsSingleStep(exception) ((exception) == EXCEPTION_SINGLE_STEP)
|
||||
|
@ -5821,6 +5825,11 @@ static bool IsTailCall(const BYTE * ip, ControllerStackInfo* info, TailCallFunct
|
|||
TailCallTls* tls = GetThread()->GetTailCallTls();
|
||||
LPVOID tailCallAwareRetAddr = tls->GetFrame()->TailCallAwareReturnAddress;
|
||||
|
||||
#if defined(TARGET_ARM64)
|
||||
retAddr = PacStripPtr(retAddr);
|
||||
tailCallAwareRetAddr = PacStripPtr(tailCallAwareRetAddr);
|
||||
#endif // TARGET_ARM64
|
||||
|
||||
LOG((LF_CORDB,LL_INFO1000, "ITCTR: ret addr is %p, tailcall aware ret addr is %p\n",
|
||||
retAddr, tailCallAwareRetAddr));
|
||||
|
||||
|
|
|
@ -9,7 +9,9 @@ enum CFI_OPCODE
|
|||
{
|
||||
CFI_ADJUST_CFA_OFFSET, // Offset is adjusted relative to the current one.
|
||||
CFI_DEF_CFA_REGISTER, // New register is used to compute CFA
|
||||
CFI_REL_OFFSET // Register is saved at offset from the current CFA
|
||||
CFI_REL_OFFSET, // Register is saved at offset from the current CFA
|
||||
CFI_DEF_CFA, // Take address from register and add offset to it
|
||||
CFI_NEGATE_RA_STATE, // Sign the return address in lr with paciaz
|
||||
};
|
||||
|
||||
struct CFI_CODE
|
||||
|
|
|
@ -703,6 +703,7 @@ RETAIL_CONFIG_DWORD_INFO(EXTERNAL_EnableArm64Rcpc, W("EnableArm64Rc
|
|||
RETAIL_CONFIG_DWORD_INFO(EXTERNAL_EnableArm64Rcpc2, W("EnableArm64Rcpc2"), 1, "Allows Arm64 Rcpc2+ hardware intrinsics to be disabled")
|
||||
RETAIL_CONFIG_DWORD_INFO(EXTERNAL_EnableArm64Sve, W("EnableArm64Sve"), 1, "Allows Arm64 SVE hardware intrinsics to be disabled")
|
||||
RETAIL_CONFIG_DWORD_INFO(EXTERNAL_EnableArm64Sve2, W("EnableArm64Sve2"), 1, "Allows Arm64 SVE2 hardware intrinsics to be disabled")
|
||||
RETAIL_CONFIG_DWORD_INFO(EXTERNAL_JitPacEnabled, W("JitPacEnabled"), 1, "Allows Arm64 Pointer Authentication (PAC) to be disabled")
|
||||
#elif defined(TARGET_RISCV64)
|
||||
RETAIL_CONFIG_DWORD_INFO(EXTERNAL_EnableRiscV64Zba, W("EnableRiscV64Zba"), 1, "Allows RiscV64 Zba hardware intrinsics to be disabled")
|
||||
RETAIL_CONFIG_DWORD_INFO(EXTERNAL_EnableRiscV64Zbb, W("EnableRiscV64Zbb"), 1, "Allows RiscV64 Zbb hardware intrinsics to be disabled")
|
||||
|
|
|
@ -76,6 +76,10 @@ typedef void * OBJECTREF;
|
|||
|
||||
#ifndef __cgencpu_h__
|
||||
|
||||
#if defined(TARGET_ARM64)
|
||||
extern "C" void* PacStripPtr(void* ptr);
|
||||
#endif // TARGET_ARM64
|
||||
|
||||
inline void SetIP(T_CONTEXT* context, PCODE rip)
|
||||
{
|
||||
_ASSERTE(!"don't call this");
|
||||
|
@ -105,7 +109,7 @@ inline PCODE GetIP(T_CONTEXT* context)
|
|||
#elif defined(TARGET_ARM)
|
||||
return (PCODE)context->Pc;
|
||||
#elif defined(TARGET_ARM64)
|
||||
return (PCODE)context->Pc;
|
||||
return (PCODE) PacStripPtr((void *)context->Pc);
|
||||
#elif defined(TARGET_LOONGARCH64)
|
||||
return (PCODE)context->Pc;
|
||||
#elif defined(TARGET_RISCV64)
|
||||
|
|
|
@ -271,6 +271,8 @@ void CodeGen::genPopCalleeSavedRegistersAndFreeLclFrame(bool jmpEpilog)
|
|||
GetEmitter()->emitIns_R_R_I(INS_add, EA_PTRSIZE, REG_SPBASE, REG_SPBASE, spAdjust);
|
||||
compiler->unwindAllocStack(spAdjust);
|
||||
}
|
||||
|
||||
GetEmitter()->emitPacInEpilog();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
|
@ -1342,6 +1344,7 @@ void CodeGen::genFuncletProlog(BasicBlock* block)
|
|||
gcInfo.gcResetForBB();
|
||||
|
||||
compiler->unwindBegProlog();
|
||||
GetEmitter()->emitPacInProlog();
|
||||
|
||||
regMaskTP maskSaveRegsFloat = genFuncletInfo.fiSaveRegs & RBM_ALLFLOAT;
|
||||
regMaskTP maskSaveRegsInt = genFuncletInfo.fiSaveRegs & ~maskSaveRegsFloat;
|
||||
|
@ -1628,6 +1631,8 @@ void CodeGen::genFuncletEpilog()
|
|||
}
|
||||
}
|
||||
|
||||
GetEmitter()->emitPacInEpilog();
|
||||
|
||||
inst_RV(INS_ret, REG_LR, TYP_I_IMPL);
|
||||
compiler->unwindReturn(REG_LR);
|
||||
|
||||
|
|
|
@ -4464,6 +4464,9 @@ void CodeGen::genPushCalleeSavedRegisters()
|
|||
}
|
||||
#endif // DEBUG
|
||||
|
||||
// Sign LR as part of Pointer Authentication (PAC) support
|
||||
GetEmitter()->emitPacInProlog();
|
||||
|
||||
// The frameType number is arbitrary, is defined below, and corresponds to one of the frame styles we
|
||||
// generate based on various sizes.
|
||||
int frameType = 0;
|
||||
|
|
|
@ -8766,6 +8766,7 @@ public:
|
|||
void unwindSaveRegPair(regNumber reg1, regNumber reg2, int offset); // stp reg1, reg2, [sp, #offset]
|
||||
void unwindSaveRegPairPreindexed(regNumber reg1, regNumber reg2, int offset); // stp reg1, reg2, [sp, #offset]!
|
||||
void unwindSaveNext(); // unwind code: save_next
|
||||
void unwindPacSignLR(); // unwind code: pac_sign_lr
|
||||
void unwindReturn(regNumber reg); // ret lr
|
||||
#endif // defined(TARGET_ARM64)
|
||||
|
||||
|
|
|
@ -3252,6 +3252,11 @@ private:
|
|||
instrDescAlign* emitNewInstrAlign();
|
||||
#endif
|
||||
|
||||
#if defined(TARGET_ARM64)
|
||||
void emitPacInProlog();
|
||||
void emitPacInEpilog();
|
||||
#endif
|
||||
|
||||
instrDesc* emitNewInstrSmall(emitAttr attr);
|
||||
instrDesc* emitNewInstr(emitAttr attr = EA_4BYTE);
|
||||
instrDesc* emitNewInstrSC(emitAttr attr, cnsval_ssize_t cns);
|
||||
|
|
|
@ -1397,6 +1397,32 @@ static const char * const bRegNames[] =
|
|||
|
||||
// clang-format on
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// emitPacInProlog: Sign LR as part of Pointer Authentication (PAC) support
|
||||
//
|
||||
void emitter::emitPacInProlog()
|
||||
{
|
||||
if (JitConfig.JitPacEnabled() == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
emitIns(INS_paciaz);
|
||||
emitComp->unwindPacSignLR();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// emitPacInEpilog: unsign LR as part of Pointer Authentication (PAC) support
|
||||
//
|
||||
void emitter::emitPacInEpilog()
|
||||
{
|
||||
if (JitConfig.JitPacEnabled() == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
emitIns(INS_autiaz);
|
||||
emitComp->unwindPacSignLR();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// emitRegName: Returns a general-purpose register name or SIMD and floating-point scalar register name.
|
||||
//
|
||||
|
|
|
@ -125,6 +125,7 @@ CONFIG_STRING(JitInlineMethodsWithEHRange, "JitInlineMethodsWithEHRange")
|
|||
|
||||
CONFIG_INTEGER(JitLongAddress, "JitLongAddress", 0) // Force using the large pseudo instruction form for long address
|
||||
CONFIG_INTEGER(JitMaxUncheckedOffset, "JitMaxUncheckedOffset", 8)
|
||||
RELEASE_CONFIG_INTEGER(JitPacEnabled, "JitPacEnabled", 1)
|
||||
|
||||
//
|
||||
// MinOpts
|
||||
|
|
|
@ -413,6 +413,11 @@ void Compiler::DumpCfiInfo(bool isHotCode,
|
|||
assert(dwarfReg == DWARF_REG_ILLEGAL);
|
||||
printf(" CodeOffset: 0x%02X Op: AdjustCfaOffset Offset:0x%X\n", codeOffset, offset);
|
||||
break;
|
||||
case CFI_NEGATE_RA_STATE:
|
||||
assert(dwarfReg == DWARF_REG_ILLEGAL);
|
||||
assert(offset == 0);
|
||||
printf(" CodeOffset: 0x%02X Op: NegateRAState\n", codeOffset);
|
||||
break;
|
||||
default:
|
||||
printf(" Unrecognized CFI_CODE: 0x%llX\n", *(UINT64*)pCode);
|
||||
break;
|
||||
|
|
|
@ -635,6 +635,33 @@ void Compiler::unwindSaveNext()
|
|||
pu->AddCode(0xE6);
|
||||
}
|
||||
|
||||
void Compiler::unwindPacSignLR()
|
||||
{
|
||||
if (JitConfig.JitPacEnabled() == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#if defined(FEATURE_CFI_SUPPORT)
|
||||
if (generateCFIUnwindCodes())
|
||||
{
|
||||
FuncInfoDsc* func = funCurrentFunc();
|
||||
UNATIVE_OFFSET cbProlog = 0;
|
||||
if (compGeneratingProlog)
|
||||
{
|
||||
cbProlog = unwindGetCurrentOffset(func);
|
||||
}
|
||||
|
||||
// Maps to DW_CFA_AARCH64_negate_ra_state
|
||||
createCfiCode(func, cbProlog, CFI_NEGATE_RA_STATE, DWARF_REG_ILLEGAL);
|
||||
|
||||
return;
|
||||
}
|
||||
#endif // FEATURE_CFI_SUPPORT
|
||||
|
||||
// pac_sign_lr: 11111100: sign the return address in lr with paciaz
|
||||
funCurrentFunc()->uwi.AddCode(0xFC);
|
||||
}
|
||||
|
||||
void Compiler::unwindReturn(regNumber reg)
|
||||
{
|
||||
// Nothing to do; we will always have at least one trailing "end" opcode in our padding.
|
||||
|
@ -1081,6 +1108,12 @@ void DumpUnwindInfo(Compiler* comp,
|
|||
|
||||
printf(" %02X save_next\n", b1);
|
||||
}
|
||||
else if (b1 == 0xFC)
|
||||
{
|
||||
// pac_sign_lr: 11111100 : sign the return address in lr with paciaz.
|
||||
|
||||
printf(" %02X pac_sign_lr\n", b1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Unknown / reserved unwind code
|
||||
|
|
|
@ -161,6 +161,11 @@ public:
|
|||
|
||||
virtual bool IsUnwindable(PTR_VOID pvAddress) PURE_VIRTUAL
|
||||
|
||||
#ifdef TARGET_ARM64
|
||||
virtual bool IsPacPresent(MethodInfo * pMethodInfo,
|
||||
REGDISPLAY * pRegisterSet ) PURE_VIRTUAL
|
||||
#endif
|
||||
|
||||
virtual bool GetReturnAddressHijackInfo(MethodInfo * pMethodInfo,
|
||||
REGDISPLAY * pRegisterSet, // in
|
||||
PTR_PTR_VOID * ppvRetAddrLocation // out
|
||||
|
|
|
@ -65,6 +65,10 @@ EXTERN_C CODE_LOCATION RhpRethrow2;
|
|||
#define FAILFAST_OR_DAC_FAIL_UNCONDITIONALLY(msg) { ASSERT_UNCONDITIONALLY(msg); RhFailFast(); }
|
||||
#endif
|
||||
|
||||
#if defined(TARGET_ARM64)
|
||||
extern "C" void* PacStripPtr(void* ptr);
|
||||
#endif // TARGET_ARM64
|
||||
|
||||
StackFrameIterator::StackFrameIterator(Thread * pThreadToWalk, PInvokeTransitionFrame* pInitialTransitionFrame)
|
||||
{
|
||||
STRESS_LOG0(LF_STACKWALK, LL_INFO10000, "----Init---- [ GC ]\n");
|
||||
|
@ -1786,7 +1790,11 @@ UnwindOutOfCurrentManagedFrame:
|
|||
// if the thread is safe to walk, it better not have a hijack in place.
|
||||
ASSERT(!m_pThread->IsHijacked());
|
||||
|
||||
#if defined(TARGET_ARM64)
|
||||
SetControlPC(PacStripPtr(dac_cast<PTR_VOID>(PCODEToPINSTR(m_RegDisplay.GetIP()))));
|
||||
#else
|
||||
SetControlPC(dac_cast<PTR_VOID>(PCODEToPINSTR(m_RegDisplay.GetIP())));
|
||||
#endif // TARGET_ARM64
|
||||
|
||||
PTR_VOID collapsingTargetFrame = NULL;
|
||||
|
||||
|
@ -2117,6 +2125,10 @@ void StackFrameIterator::CalculateCurrentMethodState()
|
|||
return;
|
||||
}
|
||||
|
||||
#if defined(TARGET_ARM64)
|
||||
m_ControlPC = PacStripPtr(m_ControlPC);
|
||||
#endif // TARGET_ARM64
|
||||
|
||||
// Assume that the caller is likely to be in the same module
|
||||
if (m_pCodeManager == NULL || !m_pCodeManager->FindMethodInfo(m_ControlPC, &m_methodInfo))
|
||||
{
|
||||
|
|
|
@ -107,6 +107,7 @@
|
|||
// Fix the stack by restoring the original return address
|
||||
//
|
||||
ldr lr, [x2, #OFFSETOF__Thread__m_pvHijackedReturnAddress]
|
||||
xpaclri
|
||||
|
||||
//
|
||||
// Clear hijack state
|
||||
|
|
|
@ -116,6 +116,7 @@ PROBE_FRAME_SIZE field 0
|
|||
;; Fix the stack by restoring the original return address
|
||||
;;
|
||||
ldr lr, [x2, #OFFSETOF__Thread__m_pvHijackedReturnAddress]
|
||||
DCD 0xD50320FF ;; xpaclri instruction in binary to avoid error while compiling with non-PAC enabled compilers
|
||||
|
||||
;;
|
||||
;; Clear hijack state
|
||||
|
|
|
@ -3,3 +3,29 @@
|
|||
|
||||
#include <unixasmmacros.inc>
|
||||
#include "AsmOffsets.inc"
|
||||
|
||||
// void* PacStripPtr(void *);
|
||||
// This function strips the pointer of PAC info that is passed as an agrument.
|
||||
// To avoid failing on non-PAC enabled machines, we use xpaclri (instead of xpaci) which strips lr explicitly.
|
||||
// Thus we move need to move input in lr, strip it and copy it back to the result register.
|
||||
.arch_extension pauth
|
||||
LEAF_ENTRY PacStripPtr, _TEXT
|
||||
mov x9, lr
|
||||
mov lr, x0
|
||||
xpaclri
|
||||
mov x0, lr
|
||||
ret x9
|
||||
LEAF_END PacStripPtr, _TEXT
|
||||
|
||||
// void* PacSignPtr(void *);
|
||||
// This function sign the input pointer using zero as salt.
|
||||
// To avoid failing on non-PAC enabled machines, we use paciaz (instead of paciza) which signs lr explicitly.
|
||||
// Thus we need to move input in lr, sign it and then copy it back to the result register.
|
||||
.arch_extension pauth
|
||||
LEAF_ENTRY PacSignPtr, _TEXT
|
||||
mov x9, lr
|
||||
mov lr, x0
|
||||
paciaz
|
||||
mov x0, lr
|
||||
ret x9
|
||||
LEAF_END PacSignPtr, _TEXT
|
|
@ -5,4 +5,28 @@
|
|||
|
||||
TEXTAREA
|
||||
|
||||
; void* PacStripPtr(void *);
|
||||
; This function strips the pointer of PAC info that is passed as an agrument.
|
||||
; To avoid failing on non-PAC enabled machines, we use xpaclri (instead of xpaci) which strips lr explicitly.
|
||||
; Thus we move need to move input in lr, strip it and copy it back to the result register.
|
||||
LEAF_ENTRY PacStripPtr
|
||||
mov x9, lr
|
||||
mov lr, x0
|
||||
DCD 0xD50320FF ; xpaclri instruction in binary to avoid error while compiling with non-PAC enabled compilers
|
||||
mov x0, lr
|
||||
ret x9
|
||||
LEAF_END PacStripPtr
|
||||
|
||||
; void* PacSignPtr(void *);
|
||||
; This function sign the input pointer using zero as salt.
|
||||
; To avoid failing on non-PAC enabled machines, we use paciaz (instead of paciza) which signs lr explicitly.
|
||||
; Thus we need to move input in lr, sign it and then copy it back to the result register.
|
||||
LEAF_ENTRY PacSignPtr
|
||||
mov x9, lr
|
||||
mov lr, x0
|
||||
DCD 0xD503231F ; paciaz instruction in binary to avoid error while compiling with non-PAC enabled compilers
|
||||
mov x0, lr
|
||||
ret x9
|
||||
LEAF_END PacSignPtr
|
||||
|
||||
end
|
||||
|
|
|
@ -36,6 +36,11 @@ static Thread* g_RuntimeInitializingThread;
|
|||
|
||||
#endif //!DACCESS_COMPILE
|
||||
|
||||
#if defined(TARGET_ARM64)
|
||||
extern "C" void* PacSignPtr(void* ptr);
|
||||
extern "C" void* PacStripPtr(void* ptr);
|
||||
#endif // TARGET_ARM64
|
||||
|
||||
ee_alloc_context::PerThreadRandom::PerThreadRandom()
|
||||
{
|
||||
minipal_xoshiro128pp_init(&random_state, (uint32_t)minipal_lowres_ticks());
|
||||
|
@ -809,8 +814,14 @@ void Thread::HijackReturnAddressWorker(StackFrameIterator* frameIterator, Hijack
|
|||
CrossThreadUnhijack();
|
||||
|
||||
void* pvRetAddr = *ppvRetAddrLocation;
|
||||
|
||||
ASSERT(pvRetAddr != NULL);
|
||||
|
||||
#if defined(TARGET_ARM64)
|
||||
ASSERT(StackFrameIterator::IsValidReturnAddress(PacStripPtr(pvRetAddr)));
|
||||
#else
|
||||
ASSERT(StackFrameIterator::IsValidReturnAddress(pvRetAddr));
|
||||
#endif // TARGET_ARM64
|
||||
|
||||
m_ppvHijackedReturnAddressLocation = ppvRetAddrLocation;
|
||||
m_pvHijackedReturnAddress = pvRetAddr;
|
||||
|
@ -820,7 +831,14 @@ void Thread::HijackReturnAddressWorker(StackFrameIterator* frameIterator, Hijack
|
|||
frameIterator->GetRegisterSet()));
|
||||
#endif
|
||||
|
||||
*ppvRetAddrLocation = (void*)pfnHijackFunction;
|
||||
void* pvHijackedAddr = (void*)pfnHijackFunction;
|
||||
#if defined(TARGET_ARM64)
|
||||
if (frameIterator->GetCodeManager()->IsPacPresent(frameIterator->GetMethodInfo(), frameIterator->GetRegisterSet()))
|
||||
{
|
||||
pvHijackedAddr = PacSignPtr(pvHijackedAddr);
|
||||
}
|
||||
#endif // TARGET_ARM64
|
||||
*ppvRetAddrLocation = pvHijackedAddr;
|
||||
|
||||
STRESS_LOG2(LF_STACKWALK, LL_INFO10000, "InternalHijack: TgtThread = %llx, IP = %p\n",
|
||||
GetPalThreadIdForLogging(), frameIterator->GetRegisterSet()->GetIP());
|
||||
|
@ -948,6 +966,7 @@ void Thread::UnhijackWorker()
|
|||
|
||||
// Restore the original return address.
|
||||
ASSERT(m_ppvHijackedReturnAddressLocation != NULL);
|
||||
|
||||
*m_ppvHijackedReturnAddressLocation = m_pvHijackedReturnAddress;
|
||||
|
||||
// Clear the hijack state.
|
||||
|
|
|
@ -64,6 +64,84 @@ UnixNativeCodeManager::~UnixNativeCodeManager()
|
|||
{
|
||||
}
|
||||
|
||||
#if defined(TARGET_ARM64)
|
||||
static size_t readULEB(const uint8_t *&p, const uint8_t *end)
|
||||
{
|
||||
size_t result = 0;
|
||||
unsigned shift = 0;
|
||||
while (p < end) {
|
||||
uint8_t byte = *p++;
|
||||
result |= size_t(byte & 0x7F) << shift;
|
||||
if ((byte & 0x80) == 0) // clear top bit indicates the last by of the value
|
||||
break;
|
||||
shift += 7;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool UnixNativeCodeManager::IsPacPresent(MethodInfo * pMethodInfo,
|
||||
REGDISPLAY * pRegisterSet)
|
||||
{
|
||||
UnixNativeMethodInfo* pNativeMethodInfo = (UnixNativeMethodInfo*)pMethodInfo;
|
||||
const uint8_t *p = (uint8_t *) pNativeMethodInfo->unwind_info;
|
||||
const uint8_t *end = p + *((uint32_t *)p);
|
||||
p += 4; // Skip length
|
||||
assert(*((uint32_t *)p) != 0); // Ensure it's FDE entry
|
||||
p += 4; // Skip offset to CIE
|
||||
p += 4; // Skip PC start
|
||||
p += 4; // Skip function length
|
||||
size_t augmentationLength = readULEB(p, end);
|
||||
p += augmentationLength; // skip augmentation data
|
||||
|
||||
while (p < end) {
|
||||
uint8_t op = *p++;
|
||||
|
||||
if (op == DW_CFA_AARCH64_negate_ra_state)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((op & 0xC0) == DW_CFA_advance_loc)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if ((op & ~(0x3F)) == DW_CFA_offset)
|
||||
{
|
||||
readULEB(p, end); // offset
|
||||
continue;
|
||||
}
|
||||
|
||||
// Extended, single‐byte opcodes:
|
||||
switch (op) {
|
||||
case DW_CFA_advance_loc1:
|
||||
case DW_CFA_def_cfa_register:
|
||||
p++; // offset
|
||||
break;
|
||||
|
||||
case DW_CFA_offset_extended_sf:
|
||||
case DW_CFA_offset_extended:
|
||||
readULEB(p, end); // register
|
||||
readULEB(p, end); // offset
|
||||
break;
|
||||
|
||||
case DW_CFA_def_cfa_offset: // DW_CFA_def_cfa_offset
|
||||
readULEB(p, end); // offset
|
||||
break;
|
||||
|
||||
case DW_CFA_def_cfa: // DW_CFA_def_cfa
|
||||
p++; // register
|
||||
readULEB(p, end); // offset
|
||||
break;
|
||||
|
||||
default: // Unknown unwind op code
|
||||
//TODO-PAC: Handle unknown op codes correctly. return false/assert false?
|
||||
p++;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#endif // TARGET_ARM64
|
||||
|
||||
// Virtually unwind stack to the caller of the context specified by the REGDISPLAY
|
||||
bool UnixNativeCodeManager::VirtualUnwind(MethodInfo* pMethodInfo, REGDISPLAY* pRegisterSet)
|
||||
{
|
||||
|
|
|
@ -73,6 +73,10 @@ public:
|
|||
REGDISPLAY * pRegisterSet, // in
|
||||
PTR_PTR_VOID * ppvRetAddrLocation); // out
|
||||
|
||||
#if defined(TARGET_ARM64)
|
||||
bool IsPacPresent(MethodInfo * pMethodInfo, REGDISPLAY * pRegisterSet);
|
||||
#endif // TARGET_ARM64
|
||||
|
||||
PTR_VOID RemapHardwareFaultToGCSafePoint(MethodInfo * pMethodInfo, PTR_VOID controlPC);
|
||||
|
||||
bool EHEnumInit(MethodInfo * pMethodInfo, PTR_VOID * pMethodStartAddress, EHEnumState * pEHEnumState);
|
||||
|
|
|
@ -831,6 +831,55 @@ bool CoffNativeCodeManager::IsUnwindable(PTR_VOID pvAddress)
|
|||
return true;
|
||||
}
|
||||
|
||||
#if defined(TARGET_ARM64)
|
||||
bool CoffNativeCodeManager::IsPacPresent(MethodInfo * pMethodInfo,
|
||||
REGDISPLAY * pRegisterSet)
|
||||
{
|
||||
CoffNativeMethodInfo * pNativeMethodInfo = (CoffNativeMethodInfo *)pMethodInfo;
|
||||
|
||||
size_t unwindDataBlobSize;
|
||||
|
||||
PTR_VOID pUnwindDataBlob = GetUnwindDataBlob(m_moduleBase, pNativeMethodInfo->runtimeFunction, &unwindDataBlobSize);
|
||||
|
||||
PTR_uint8_t UnwindCodePtr = dac_cast<PTR_uint8_t>(pUnwindDataBlob);
|
||||
PTR_uint8_t UnwindCodesEndPtr = dac_cast<PTR_uint8_t>(pUnwindDataBlob) + unwindDataBlobSize;
|
||||
|
||||
while (UnwindCodePtr < UnwindCodesEndPtr)
|
||||
{
|
||||
uint8_t CurCode = * UnwindCodePtr;
|
||||
if ((CurCode & 0xfe) == 0xe4) // The last unwind code
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (CurCode == 0xFC) // Unwind code for PAC (pac_sign_lr)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (CurCode < 0xC0)
|
||||
{
|
||||
UnwindCodePtr += 1;
|
||||
}
|
||||
else if (CurCode < 0xE0)
|
||||
{
|
||||
UnwindCodePtr += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
static const BYTE UnwindCodeSizeTable[32] =
|
||||
{
|
||||
4,1,2,1,1,1,1,3, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 2,3,4,5,1,1,1,1
|
||||
};
|
||||
|
||||
UnwindCodePtr += UnwindCodeSizeTable[CurCode - 0xE0];
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
#endif //TARGET_ARM64
|
||||
|
||||
bool CoffNativeCodeManager::GetReturnAddressHijackInfo(MethodInfo * pMethodInfo,
|
||||
REGDISPLAY * pRegisterSet, // in
|
||||
PTR_PTR_VOID * ppvRetAddrLocation) // out
|
||||
|
|
|
@ -90,6 +90,8 @@ public:
|
|||
|
||||
bool IsUnwindable(PTR_VOID pvAddress);
|
||||
|
||||
bool IsPacPresent(MethodInfo * pMethodInfo, REGDISPLAY * pRegisterSet);
|
||||
|
||||
bool GetReturnAddressHijackInfo(MethodInfo * pMethodInfo,
|
||||
REGDISPLAY * pRegisterSet, // in
|
||||
PTR_PTR_VOID * ppvRetAddrLocation); // out
|
||||
|
|
|
@ -11,6 +11,7 @@ namespace ILCompiler.ObjectWriter
|
|||
CFI_ADJUST_CFA_OFFSET, // Offset is adjusted relative to the current one.
|
||||
CFI_DEF_CFA_REGISTER, // New register is used to compute CFA
|
||||
CFI_REL_OFFSET, // Register is saved at offset from the current CFA
|
||||
CFI_DEF_CFA // Take address from register and add offset to it.
|
||||
CFI_DEF_CFA, // Take address from register and add offset to it.
|
||||
CFI_NEGATE_RA_STATE, // Sign the return address in lr with paciaz
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,6 +51,7 @@ namespace ILCompiler.ObjectWriter
|
|||
{
|
||||
codeOffset = Math.Max(codeOffset, blobData[offset++]);
|
||||
CFI_OPCODE opcode = (CFI_OPCODE)blobData[offset++];
|
||||
|
||||
short dwarfReg = BitConverter.ToInt16(blobData, offset);
|
||||
offset += sizeof(short);
|
||||
int cfiOffset = BitConverter.ToInt32(blobData, offset);
|
||||
|
@ -113,6 +114,10 @@ namespace ILCompiler.ObjectWriter
|
|||
cfaOffset = cfiOffset;
|
||||
cfiCodeOffset += DwarfHelper.WriteULEB128(cfiCode.AsSpan(cfiCodeOffset), (uint)cfaOffset);
|
||||
break;
|
||||
|
||||
case CFI_OPCODE.CFI_NEGATE_RA_STATE:
|
||||
cfiCode[cfiCodeOffset++] = DW_CFA_AARCH64_negate_ra_state;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -121,6 +121,10 @@ namespace ILCompiler.ObjectWriter
|
|||
EmitSpAdjustment(cfiOffset);
|
||||
}
|
||||
break;
|
||||
|
||||
case CFI_OPCODE.CFI_NEGATE_RA_STATE:
|
||||
// Do nothing here.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -790,6 +790,13 @@ namespace ILCompiler.ObjectWriter
|
|||
{
|
||||
codeOffset = Math.Max(codeOffset, blobData[offset++]);
|
||||
CFI_OPCODE opcode = (CFI_OPCODE)blobData[offset++];
|
||||
|
||||
if (opcode == CFI_OPCODE.CFI_NEGATE_RA_STATE)
|
||||
{
|
||||
// Falling back to DWARF
|
||||
return UNWIND_ARM64_MODE_DWARF;
|
||||
}
|
||||
|
||||
short dwarfReg = BinaryPrimitives.ReadInt16LittleEndian(blobData.AsSpan(offset));
|
||||
offset += sizeof(short);
|
||||
int cfiOffset = BinaryPrimitives.ReadInt32LittleEndian(blobData.AsSpan(offset));
|
||||
|
|
|
@ -89,7 +89,8 @@ namespace Internal.JitInterface
|
|||
CFI_ADJUST_CFA_OFFSET, // Offset is adjusted relative to the current one.
|
||||
CFI_DEF_CFA_REGISTER, // New register is used to compute CFA
|
||||
CFI_REL_OFFSET, // Register is saved at offset from the current CFA
|
||||
CFI_DEF_CFA // Take address from register and add offset to it.
|
||||
CFI_DEF_CFA, // Take address from register and add offset to it.
|
||||
CFI_NEGATE_RA_STATE, // Sign the return address in lr with paciaz
|
||||
}
|
||||
|
||||
// Get the CFI data in the same shape as clang/LLVM generated one. This improves the compatibility with libunwind and other unwind solutions
|
||||
|
@ -120,6 +121,7 @@ namespace Internal.JitInterface
|
|||
}
|
||||
|
||||
int offset = 0;
|
||||
bool shouldAddPACOpCode = false;
|
||||
while (offset < blobData.Length)
|
||||
{
|
||||
codeOffset = Math.Max(codeOffset, blobData[offset++]);
|
||||
|
@ -173,6 +175,10 @@ namespace Internal.JitInterface
|
|||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case CFI_OPCODE.CFI_NEGATE_RA_STATE:
|
||||
shouldAddPACOpCode = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -182,6 +188,14 @@ namespace Internal.JitInterface
|
|||
|
||||
using (BinaryWriter cfiWriter = new BinaryWriter(cfiStream))
|
||||
{
|
||||
if (shouldAddPACOpCode)
|
||||
{
|
||||
cfiWriter.Write((byte)codeOffset);
|
||||
cfiWriter.Write((byte)CFI_OPCODE.CFI_NEGATE_RA_STATE);
|
||||
cfiWriter.Write((short)-1);
|
||||
cfiWriter.Write(cfaOffset);
|
||||
}
|
||||
|
||||
if (cfaRegister != -1)
|
||||
{
|
||||
cfiWriter.Write((byte)codeOffset);
|
||||
|
|
|
@ -31,6 +31,10 @@
|
|||
#define FIELD_OFFSET(type, field) ((LONG)__builtin_offsetof(type, field))
|
||||
#endif
|
||||
|
||||
#if !defined(DACCESS_COMPILE) && !defined(FEATURE_CDAC_UNWINDER)
|
||||
extern "C" void* PacStripPtr(void* ptr);
|
||||
#endif // !defined(DACCESS_COMPILE) && !defined(FEATURE_CDAC_UNWINDER)
|
||||
|
||||
#ifdef HOST_UNIX
|
||||
#define RtlZeroMemory ZeroMemory
|
||||
|
||||
|
@ -251,16 +255,71 @@ do {
|
|||
|
||||
#endif // !defined(DEBUGGER_UNWIND)
|
||||
|
||||
//
|
||||
// Macros for stripping pointer authentication (PAC) bits.
|
||||
//
|
||||
#if !defined(DACCESS_COMPILE) && !defined(FEATURE_CDAC_UNWINDER)
|
||||
|
||||
#if !defined(DEBUGGER_STRIP_PAC)
|
||||
#define STRIP_PAC(pointer) RtlStripPacOnline(pointer)
|
||||
|
||||
// NOTE: Pointer authentication is not used by .NET, so the implementation does nothing
|
||||
#define STRIP_PAC(Params, pointer)
|
||||
FORCEINLINE
|
||||
VOID RtlStripPacOnline(_Inout_ PULONG64 Pointer)
|
||||
|
||||
#endif
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This routine strips the ARM64 Pointer Authentication Code (PAC) from a
|
||||
pointer using the ARM64-native xpaci intrinsic directly. Hence this should
|
||||
only be called when stripping a pointer at runtime (not debugger)
|
||||
|
||||
Arguments:
|
||||
|
||||
Pointer - Supplies a pointer to the pointer whose PAC will be stripped.
|
||||
|
||||
Return Value:
|
||||
|
||||
None.
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
*Pointer = (ULONG64)PacStripPtr((void *) (*Pointer));
|
||||
}
|
||||
#else
|
||||
|
||||
#define STRIP_PAC(pointer) RtlStripPacManual(pointer)
|
||||
|
||||
FORCEINLINE
|
||||
VOID
|
||||
RtlStripPacManual(
|
||||
_Inout_ PULONG64 Pointer
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This routine manually strips the ARM64 Pointer Authentication Code (PAC)
|
||||
from a pointer. This is functionally similar to the XPAC family of
|
||||
instructions.
|
||||
|
||||
N.B. Even though PAC is only supported on ARM64, this routine is available
|
||||
on all architectures to conveniently enable scenarios such as the
|
||||
Debugger.
|
||||
|
||||
Arguments:
|
||||
|
||||
Pointer - Supplies a pointer to the pointer whose PAC will be stripped.
|
||||
|
||||
Return Value:
|
||||
|
||||
None.
|
||||
|
||||
--*/
|
||||
{
|
||||
*Pointer &= 0x0000FFFFFFFFFFFF;
|
||||
return;
|
||||
}
|
||||
|
||||
#endif // !defined(DACCESS_COMPILE) && !defined(FEATURE_CDAC_UNWINDER)
|
||||
|
||||
//
|
||||
// Macros to clarify opcode parsing
|
||||
|
@ -2343,7 +2402,7 @@ ExecuteCodes:
|
|||
return STATUS_UNWIND_INVALID_SEQUENCE;
|
||||
}
|
||||
|
||||
STRIP_PAC(UnwindParams, &ContextRecord->Lr);
|
||||
STRIP_PAC(&ContextRecord->Lr);
|
||||
|
||||
//
|
||||
// TODO: Implement support for UnwindFlags RTL_VIRTUAL_UNWIND2_VALIDATE_PAC.
|
||||
|
|
|
@ -161,11 +161,38 @@ NESTED_ENTRY OnHijackTripThread, _TEXT, NoHandler
|
|||
EPILOG_RESTORE_REG_PAIR x25, x26, 64
|
||||
EPILOG_RESTORE_REG_PAIR x27, x28, 80
|
||||
EPILOG_RESTORE_REG_PAIR_INDEXED fp, lr, 192
|
||||
xpaclri
|
||||
EPILOG_RETURN
|
||||
NESTED_END OnHijackTripThread, _TEXT
|
||||
|
||||
#endif // FEATURE_HIJACK
|
||||
|
||||
// void* PacStripPtr(void *);
|
||||
// This function strips the pointer of PAC info that is passed as an agrument.
|
||||
// To avoid failing on non-PAC enabled machines, we use xpaclri (instead of xpaci) which strips lr explicitly.
|
||||
// Thus we move need to move input in lr, strip it and copy it back to the result register.
|
||||
.arch_extension pauth
|
||||
LEAF_ENTRY PacStripPtr, _TEXT
|
||||
mov x9, lr
|
||||
mov lr, x0
|
||||
xpaclri
|
||||
mov x0, lr
|
||||
ret x9
|
||||
LEAF_END PacStripPtr, _TEXT
|
||||
|
||||
// void* PacSignPtr(void *);
|
||||
// This function sign the input pointer using zero as salt.
|
||||
// To avoid failing on non-PAC enabled machines, we use paciaz (instead of paciza) which signs lr explicitly.
|
||||
// Thus we need to move input in lr, sign it and then copy it back to the result register.
|
||||
.arch_extension pauth
|
||||
LEAF_ENTRY PacSignPtr, _TEXT
|
||||
mov x9, lr
|
||||
mov lr, x0
|
||||
paciaz
|
||||
mov x0, lr
|
||||
ret x9
|
||||
LEAF_END PacSignPtr, _TEXT
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// Redirection Stub for GC in fully interruptible method
|
||||
//GenerateRedirectedHandledJITCaseStub GCThreadControl
|
||||
|
|
|
@ -497,11 +497,36 @@ COMToCLRDispatchHelper_RegSetup
|
|||
EPILOG_RESTORE_REG_PAIR x25, x26, #64
|
||||
EPILOG_RESTORE_REG_PAIR x27, x28, #80
|
||||
EPILOG_RESTORE_REG_PAIR fp, lr, #192!
|
||||
DCD 0xD50320FF ; xpaclri instruction in binary to avoid error while compiling with non-PAC enabled compilers
|
||||
EPILOG_RETURN
|
||||
NESTED_END
|
||||
|
||||
#endif ; FEATURE_HIJACK
|
||||
|
||||
; void* PacStripPtr(void *);
|
||||
; This function strips the pointer of PAC info that is passed as an agrument.
|
||||
; To avoid failing on non-PAC enabled machines, we use xpaclri (instead of xpaci) which strips lr explicitly.
|
||||
; Thus we move need to move input in lr, strip it and copy it back to the result register.
|
||||
LEAF_ENTRY PacStripPtr
|
||||
mov x9, lr
|
||||
mov lr, x0
|
||||
DCD 0xD50320FF ; xpaclri instruction in binary to avoid error while compiling with non-PAC enabled compilers
|
||||
mov x0, lr
|
||||
ret x9
|
||||
LEAF_END PacStripPtr
|
||||
|
||||
; void* PacSignPtr(void *);
|
||||
; This function sign the input pointer using zero as salt.
|
||||
; To avoid failing on non-PAC enabled machines, we use paciaz (instead of paciza) which signs lr explicitly.
|
||||
; Thus we need to move input in lr, sign it and then copy it back to the result register.
|
||||
LEAF_ENTRY PacSignPtr
|
||||
mov x9, lr
|
||||
mov lr, x0
|
||||
DCD 0xD503231F ; paciaz instruction in binary to avoid error while compiling with non-PAC enabled compilers
|
||||
mov x0, lr
|
||||
ret x9
|
||||
LEAF_END PacSignPtr
|
||||
|
||||
;; ------------------------------------------------------------------
|
||||
;; Redirection Stub for GC in fully interruptible method
|
||||
GenerateRedirectedHandledJITCaseStub GCThreadControl
|
||||
|
|
|
@ -44,7 +44,6 @@
|
|||
EXTERN_C void getFPReturn(int fpSize, INT64 *pRetVal);
|
||||
EXTERN_C void setFPReturn(int fpSize, INT64 retVal);
|
||||
|
||||
|
||||
class ComCallMethodDesc;
|
||||
|
||||
extern PCODE GetPreStubEntryPoint();
|
||||
|
@ -218,7 +217,8 @@ typedef struct _PROFILE_PLATFORM_SPECIFIC_DATA
|
|||
|
||||
inline PCODE GetIP(const T_CONTEXT * context) {
|
||||
LIMITED_METHOD_DAC_CONTRACT;
|
||||
return context->Pc;
|
||||
//TODO-PAC: Strip/Authenticate while populating the context.
|
||||
return (PCODE) context->Pc;
|
||||
}
|
||||
|
||||
inline void SetIP(T_CONTEXT *context, PCODE eip) {
|
||||
|
|
|
@ -6915,6 +6915,82 @@ bool IsIPInEpilog(PTR_CONTEXT pContextToCheck, EECodeInfo *pCodeInfo, BOOL *pSaf
|
|||
return fIsInEpilog;
|
||||
}
|
||||
|
||||
#if defined(TARGET_ARM64)
|
||||
// This function is used to check if Pointer Authentication (PAC) is enabled for this stack frame or not.
|
||||
bool IsPacPresent(EECodeInfo *pCodeInfo)
|
||||
{
|
||||
_ASSERTE(pCodeInfo->IsValid());
|
||||
|
||||
// Lookup the function entry for the IP
|
||||
PTR_RUNTIME_FUNCTION FunctionEntry = pCodeInfo->GetFunctionEntry();
|
||||
|
||||
// We should always get a function entry for a managed method
|
||||
_ASSERTE(FunctionEntry != NULL);
|
||||
DWORD_PTR ImageBase = pCodeInfo->GetModuleBase();
|
||||
|
||||
_ASSERTE((FunctionEntry->UnwindData & 3) == 0); // Packed unwind data are not used with managed code
|
||||
ULONG_PTR UnwindDataPtr = (ULONG_PTR)(ImageBase + FunctionEntry->UnwindData);
|
||||
|
||||
// Read the header word. For unwind info layout details refer https://learn.microsoft.com/en-us/cpp/build/arm64-exception-handling?view=msvc-170#arm64-exception-handling-information
|
||||
DWORD HeaderWord = *(DWORD*)UnwindDataPtr;
|
||||
UnwindDataPtr += 4;
|
||||
|
||||
_ASSERTE(((HeaderWord >> 18) & 3) == 0); // Version 0 is the only supported version.
|
||||
|
||||
ULONG UnwindWords = (HeaderWord >> 27) & 31;
|
||||
ULONG EpilogScopeCount = (HeaderWord >> 22) & 31;
|
||||
if (EpilogScopeCount == 0 && UnwindWords == 0)
|
||||
{
|
||||
EpilogScopeCount = *(DWORD*)UnwindDataPtr;
|
||||
UnwindDataPtr += 4;
|
||||
UnwindWords = (EpilogScopeCount >> 16) & 0xff;
|
||||
EpilogScopeCount &= 0xffff;
|
||||
}
|
||||
|
||||
if ((HeaderWord & (1 << 21)) != 0)
|
||||
{
|
||||
EpilogScopeCount = 0;
|
||||
}
|
||||
|
||||
ULONG_PTR UnwindCodePtr = UnwindDataPtr + 4 * EpilogScopeCount;
|
||||
ULONG_PTR UnwindCodesEndPtr = UnwindCodePtr + 4 * UnwindWords;
|
||||
|
||||
while (UnwindCodePtr < UnwindCodesEndPtr)
|
||||
{
|
||||
ULONG CurCode = *(BYTE*)UnwindCodePtr;
|
||||
if ((CurCode & 0xfe) == 0xe4) // The last unwind code
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (CurCode == 0xFC) // Unwind code for PAC (pac_sign_lr)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (CurCode < 0xC0)
|
||||
{
|
||||
UnwindCodePtr += 1;
|
||||
}
|
||||
else if (CurCode < 0xE0)
|
||||
{
|
||||
UnwindCodePtr += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
static const BYTE UnwindCodeSizeTable[32] =
|
||||
{
|
||||
4,1,2,1,1,1,1,3, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 2,3,4,5,1,1,1,1
|
||||
};
|
||||
|
||||
UnwindCodePtr += UnwindCodeSizeTable[CurCode - 0xE0];
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
#endif // TARGET_ARM64
|
||||
|
||||
#endif // FEATURE_HIJACK && (!TARGET_X86 || TARGET_UNIX)
|
||||
|
||||
#define EXCEPTION_VISUALCPP_DEBUGGER ((DWORD) (1<<30 | 0x6D<<16 | 5000))
|
||||
|
|
|
@ -34,7 +34,9 @@ BOOL AdjustContextForJITHelpers(EXCEPTION_RECORD *pExceptionRecord, CONTEXT *pCo
|
|||
// General purpose functions for use on an IP in jitted code.
|
||||
bool IsIPInProlog(EECodeInfo *pCodeInfo);
|
||||
bool IsIPInEpilog(PTR_CONTEXT pContextToCheck, EECodeInfo *pCodeInfo, BOOL *pSafeToInjectThreadAbort);
|
||||
|
||||
#if defined(TARGET_ARM64)
|
||||
bool IsPacPresent(EECodeInfo *pCodeInfo);
|
||||
#endif // TARGET_ARM64
|
||||
#endif // FEATURE_HIJACK && (!TARGET_X86 || TARGET_UNIX)
|
||||
|
||||
// Enums
|
||||
|
|
|
@ -10,6 +10,9 @@
|
|||
#include "gcrefmap.h"
|
||||
#include "threads.h"
|
||||
|
||||
#if defined(TARGET_ARM64)
|
||||
extern "C" void* PacStripPtr(void* ptr);
|
||||
#endif // TARGET_ARM64
|
||||
|
||||
FCIMPL2(void*, TailCallHelp::AllocTailCallArgBufferWorker, INT32 size, void* gcDesc)
|
||||
{
|
||||
|
@ -25,7 +28,13 @@ FCIMPL2(void*, TailCallHelp::GetTailCallInfo, void** retAddrSlot, void** retAddr
|
|||
|
||||
Thread* thread = GetThread();
|
||||
|
||||
*retAddr = thread->GetReturnAddress(retAddrSlot);
|
||||
void* retAddrFromSlot = thread->GetReturnAddress(retAddrSlot);
|
||||
|
||||
#if defined(TARGET_ARM64)
|
||||
retAddrFromSlot = PacStripPtr(retAddrFromSlot);
|
||||
#endif // TARGET_ARM64
|
||||
*retAddr = retAddrFromSlot;
|
||||
|
||||
return thread->GetTailCallTls();
|
||||
}
|
||||
FCIMPLEND
|
||||
|
|
|
@ -2621,7 +2621,7 @@ public:
|
|||
|
||||
private:
|
||||
#ifdef FEATURE_HIJACK
|
||||
void HijackThread(ExecutionState *esb X86_ARG(ReturnKind returnKind) X86_ARG(bool hasAsyncRet));
|
||||
void HijackThread(ExecutionState *esb X86_ARG(ReturnKind returnKind) X86_ARG(bool hasAsyncRet) ARM64_ARG(bool isPacEnabledFrame));
|
||||
|
||||
VOID *m_pvHJRetAddr; // original return address (before hijack)
|
||||
VOID **m_ppvHJRetAddrPtr; // place we bashed a new return address
|
||||
|
|
|
@ -22,6 +22,10 @@
|
|||
|
||||
#define HIJACK_NONINTERRUPTIBLE_THREADS
|
||||
|
||||
#if defined(TARGET_ARM64)
|
||||
extern "C" void* PacSignPtr(void* ptr);
|
||||
#endif // TARGET_ARM64
|
||||
|
||||
bool ThreadSuspend::s_fSuspendRuntimeInProgress = false;
|
||||
|
||||
bool ThreadSuspend::s_fSuspended = false;
|
||||
|
@ -4532,7 +4536,7 @@ struct ExecutionState
|
|||
};
|
||||
|
||||
// Client is responsible for suspending the thread before calling
|
||||
void Thread::HijackThread(ExecutionState *esb X86_ARG(ReturnKind returnKind) X86_ARG(bool hasAsyncRet))
|
||||
void Thread::HijackThread(ExecutionState *esb X86_ARG(ReturnKind returnKind) X86_ARG(bool hasAsyncRet) ARM64_ARG(bool isPacEnabledFrame))
|
||||
{
|
||||
CONTRACTL {
|
||||
NOTHROW;
|
||||
|
@ -4600,6 +4604,13 @@ void Thread::HijackThread(ExecutionState *esb X86_ARG(ReturnKind returnKind) X86
|
|||
m_HijackedFunction = esb->m_pFD;
|
||||
|
||||
// Bash the stack to return to one of our stubs
|
||||
#if defined(TARGET_ARM64)
|
||||
if (isPacEnabledFrame)
|
||||
{
|
||||
pvHijackAddr = PacSignPtr(pvHijackAddr);
|
||||
}
|
||||
#endif // TARGET_ARM64
|
||||
|
||||
*esb->m_ppvRetAddrPtr = pvHijackAddr;
|
||||
SetThreadState(TS_Hijacked);
|
||||
}
|
||||
|
@ -5309,9 +5320,13 @@ BOOL Thread::HandledJITCase()
|
|||
|
||||
X86_ONLY(ReturnKind returnKind;)
|
||||
X86_ONLY(bool hasAsyncRet;)
|
||||
ARM64_ONLY(bool isPacEnabledFrame;)
|
||||
if (GetReturnAddressHijackInfo(&codeInfo X86_ARG(&returnKind) X86_ARG(&hasAsyncRet)))
|
||||
{
|
||||
HijackThread(&esb X86_ARG(returnKind) X86_ARG(hasAsyncRet));
|
||||
#ifdef TARGET_ARM64
|
||||
isPacEnabledFrame = IsPacPresent(&codeInfo);
|
||||
#endif
|
||||
HijackThread(&esb X86_ARG(returnKind) X86_ARG(hasAsyncRet) ARM64_ARG(isPacEnabledFrame));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5863,7 +5878,11 @@ void HandleSuspensionForInterruptedThread(CONTEXT *interruptedContext)
|
|||
StackWalkerWalkingThreadHolder threadStackWalking(pThread);
|
||||
|
||||
// Hijack the return address to point to the appropriate routine based on the method's return type.
|
||||
pThread->HijackThread(&executionState X86_ARG(returnKind) X86_ARG(hasAsyncRet));
|
||||
ARM64_ONLY(bool isPacEnabledFrame);
|
||||
#ifdef TARGET_ARM64
|
||||
isPacEnabledFrame = IsPacPresent(&codeInfo);
|
||||
#endif
|
||||
pThread->HijackThread(&executionState X86_ARG(returnKind) X86_ARG(hasAsyncRet) ARM64_ARG(isPacEnabledFrame));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -354,7 +354,18 @@ int DwarfInstructions<A, R>::stepWithDwarf(A &addressSpace, pint_t pc,
|
|||
if (cieInfo.addressesSignedWithBKey)
|
||||
asm("hint 0xe" : "+r"(x17) : "r"(x16)); // autib1716
|
||||
else
|
||||
asm("hint 0xc" : "+r"(x17) : "r"(x16)); // autia1716
|
||||
{
|
||||
//TODO-PAC: Restore the authenticating with A key when signing with SP is in place.
|
||||
//asm("hint 0xc" : "+r"(x17) : "r"(x16)); // autia1716
|
||||
__asm__ __volatile__ ("mov x9, lr\n\t"
|
||||
"mov lr, %0\n\t"
|
||||
"xpaclri\n\t"
|
||||
"mov %0, lr\n\t"
|
||||
"mov lr, x9"
|
||||
: "+r"(x17)
|
||||
:
|
||||
: "x9", "lr"); // strip PAC
|
||||
}
|
||||
}
|
||||
returnAddress = x17;
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue