diff options
Diffstat (limited to 'packaging/0001-Linux-ARM-Fix-managed-breakpoints-13316.patch')
-rw-r--r-- | packaging/0001-Linux-ARM-Fix-managed-breakpoints-13316.patch | 173 |
1 files changed, 173 insertions, 0 deletions
diff --git a/packaging/0001-Linux-ARM-Fix-managed-breakpoints-13316.patch b/packaging/0001-Linux-ARM-Fix-managed-breakpoints-13316.patch new file mode 100644 index 0000000000..0e5ba17ce1 --- /dev/null +++ b/packaging/0001-Linux-ARM-Fix-managed-breakpoints-13316.patch @@ -0,0 +1,173 @@ +From a181764876c53aab4e1842ad0af3a3d56d8142c7 Mon Sep 17 00:00:00 2001 +From: Igor Kulaychuk <igor.kulaychuk@gmail.com> +Date: Tue, 15 Aug 2017 00:30:56 +0300 +Subject: [PATCH 1/5] [Linux/ARM] Fix managed breakpoints (#13316) + +* [Linux/ARM] Fix managed breakpoints + +This commit introduces the following changes in order to enable +ICorDebug-based debuggers to use breakpoints on ARM Linux: + +* Use 0xde01 as breakpoint instruction on ARM Linux. + ARM reference recommends to use 0xdefe as a breakpoint instruction, + but Linux kernel generates SIGILL for this instruction. + The 0xde01 instruction causes the kernel to generate SIGTRAP. + +* Fix SIGTRAP handling on ARM Linux. + Unlike x86, when SIGTRAP happens on ARM Linux, the PC points + at the break instruction. But the rest of the code expects + that it points to an instruction after the break, + so we adjust the PC at the start of HandleHardwareException(). + +* Enable ARM single stepping for PAL. + Handle single stepping for PAL path the same way as for non-PAL path. + Also enable ArmSingleStepper executable buffer by allocating it + from system global loader executable heap. + +* Hande ARM single step only when debugger is attached, fix comments and code style + +* Pass existing Thread object to HandleArmSingleStep +--- + src/debug/inc/arm/primitives.h | 4 ++++ + src/vm/arm/armsinglestepper.cpp | 12 ++++++++++-- + src/vm/arm/cgencpu.h | 4 ++++ + src/vm/armsinglestepper.h | 4 ++++ + src/vm/exceptionhandling.cpp | 35 +++++++++++++++++++++++++++++++++++ + 5 files changed, 57 insertions(+), 2 deletions(-) + +diff --git a/src/debug/inc/arm/primitives.h b/src/debug/inc/arm/primitives.h +index 0bac542..1cceeff 100644 +--- a/src/debug/inc/arm/primitives.h ++++ b/src/debug/inc/arm/primitives.h +@@ -30,7 +30,11 @@ typedef DPTR(CORDB_ADDRESS_TYPE) PTR_CORDB_ADDRESS_TYPE; + #define STACKWALK_CONTROLPC_ADJUST_OFFSET 2 + + #define CORDbg_BREAK_INSTRUCTION_SIZE 2 ++#ifdef __linux__ ++#define CORDbg_BREAK_INSTRUCTION (USHORT)0xde01 ++#else + #define CORDbg_BREAK_INSTRUCTION (USHORT)0xdefe ++#endif + + inline CORDB_ADDRESS GetPatchEndAddr(CORDB_ADDRESS patchAddr) + { +diff --git a/src/vm/arm/armsinglestepper.cpp b/src/vm/arm/armsinglestepper.cpp +index e000959..bfe8824 100644 +--- a/src/vm/arm/armsinglestepper.cpp ++++ b/src/vm/arm/armsinglestepper.cpp +@@ -97,17 +97,25 @@ ArmSingleStepper::ArmSingleStepper() + + ArmSingleStepper::~ArmSingleStepper() + { +-#if !defined(DACCESS_COMPILE) && !defined(FEATURE_PAL) ++#if !defined(DACCESS_COMPILE) ++#ifdef FEATURE_PAL ++ SystemDomain::GetGlobalLoaderAllocator()->GetExecutableHeap()->BackoutMem(m_rgCode, kMaxCodeBuffer * sizeof(WORD)); ++#else + DeleteExecutable(m_rgCode); + #endif ++#endif + } + + void ArmSingleStepper::Init() + { +-#if !defined(DACCESS_COMPILE) && !defined(FEATURE_PAL) ++#if !defined(DACCESS_COMPILE) + if (m_rgCode == NULL) + { ++#ifdef FEATURE_PAL ++ m_rgCode = (WORD *)(void *)SystemDomain::GetGlobalLoaderAllocator()->GetExecutableHeap()->AllocMem(S_SIZE_T(kMaxCodeBuffer * sizeof(WORD))); ++#else + m_rgCode = new (executable) WORD[kMaxCodeBuffer]; ++#endif + } + #endif + } +diff --git a/src/vm/arm/cgencpu.h b/src/vm/arm/cgencpu.h +index 6f128f6..2a369d8 100644 +--- a/src/vm/arm/cgencpu.h ++++ b/src/vm/arm/cgencpu.h +@@ -566,7 +566,11 @@ public: + // a reasonable breakpoint substitute (it's what DebugBreak uses). Bkpt #0, on the other hand, always + // seems to flow directly to the kernel debugger (even if we ignore it there it doesn't seem to be + // picked up by the user mode debugger). ++#ifdef __linux__ ++ Emit16(0xde01); ++#else + Emit16(0xdefe); ++#endif + } + + void ThumbEmitMovConstant(ThumbReg dest, int constant) +diff --git a/src/vm/armsinglestepper.h b/src/vm/armsinglestepper.h +index 53a1019..8893525 100644 +--- a/src/vm/armsinglestepper.h ++++ b/src/vm/armsinglestepper.h +@@ -88,7 +88,11 @@ private: + kMaxCodeBuffer = 2 + 3 + 1, // WORD slots in our redirect buffer (2 for current instruction, 3 for + // breakpoint instructions used to pad out slots in an IT block and one + // for the final breakpoint) ++#ifdef __linux__ ++ kBreakpointOp = 0xde01, // Opcode for the breakpoint instruction used on ARM Linux ++#else + kBreakpointOp = 0xdefe, // Opcode for the breakpoint instruction used on CoreARM ++#endif + }; + + // Bit numbers of the condition flags in the CPSR. +diff --git a/src/vm/exceptionhandling.cpp b/src/vm/exceptionhandling.cpp +index 2802f73..7ed4375 100644 +--- a/src/vm/exceptionhandling.cpp ++++ b/src/vm/exceptionhandling.cpp +@@ -5176,6 +5176,38 @@ BOOL IsSafeToHandleHardwareException(PCONTEXT contextRecord, PEXCEPTION_RECORD e + IsIPInMarkedJitHelper(controlPc)); + } + ++#ifdef _TARGET_ARM_ ++static inline BOOL HandleArmSingleStep(PCONTEXT pContext, PEXCEPTION_RECORD pExceptionRecord, Thread *pThread) ++{ ++#ifdef __linux__ ++ // On ARM Linux exception point to the break instruction, ++ // but the rest of the code expects that it points to an instruction after the break ++ if (pExceptionRecord->ExceptionCode == EXCEPTION_BREAKPOINT) ++ { ++ SetIP(pContext, GetIP(pContext) + CORDbg_BREAK_INSTRUCTION_SIZE); ++ pExceptionRecord->ExceptionAddress = (void *)GetIP(pContext); ++ } ++#endif ++ // On ARM we don't have any reliable hardware support for single stepping so it is emulated in software. ++ // The implementation will end up throwing an EXCEPTION_BREAKPOINT rather than an EXCEPTION_SINGLE_STEP ++ // and leaves other aspects of the thread context in an invalid state. Therefore we use this opportunity ++ // to fixup the state before any other part of the system uses it (we do it here since only the debugger ++ // uses single step functionality). ++ ++ // First ask the emulation itself whether this exception occurred while single stepping was enabled. If so ++ // it will fix up the context to be consistent again and return true. If so and the exception was ++ // EXCEPTION_BREAKPOINT then we translate it to EXCEPTION_SINGLE_STEP (otherwise we leave it be, e.g. the ++ // instruction stepped caused an access violation). ++ if (pThread->HandleSingleStep(pContext, pExceptionRecord->ExceptionCode) && (pExceptionRecord->ExceptionCode == EXCEPTION_BREAKPOINT)) ++ { ++ pExceptionRecord->ExceptionCode = EXCEPTION_SINGLE_STEP; ++ pExceptionRecord->ExceptionAddress = (void *)GetIP(pContext); ++ return TRUE; ++ } ++ return FALSE; ++} ++#endif // _TARGET_ARM_ ++ + BOOL HandleHardwareException(PAL_SEHException* ex) + { + _ASSERTE(IsSafeToHandleHardwareException(ex->GetContextRecord(), ex->GetExceptionRecord())); +@@ -5239,6 +5271,9 @@ BOOL HandleHardwareException(PAL_SEHException* ex) + Thread *pThread = GetThread(); + if (pThread != NULL && g_pDebugInterface != NULL) + { ++#ifdef _TARGET_ARM_ ++ HandleArmSingleStep(ex->GetContextRecord(), ex->GetExceptionRecord(), pThread); ++#endif + if (ex->GetExceptionRecord()->ExceptionCode == STATUS_BREAKPOINT) + { + // If this is breakpoint context, it is set up to point to an instruction after the break instruction. +-- +2.7.4 + |