summaryrefslogtreecommitdiff
path: root/src/vm/exceptionhandling.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/vm/exceptionhandling.cpp')
-rw-r--r--src/vm/exceptionhandling.cpp35
1 files changed, 35 insertions, 0 deletions
diff --git a/src/vm/exceptionhandling.cpp b/src/vm/exceptionhandling.cpp
index c6d42eddd7..a52ccd7c2a 100644
--- a/src/vm/exceptionhandling.cpp
+++ b/src/vm/exceptionhandling.cpp
@@ -5186,6 +5186,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()));
@@ -5249,6 +5281,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.