Fix debuggertests failures OSX. (dotnet/coreclr#5267)
authorMike McLaughlin <mikem@microsoft.com>
Fri, 27 May 2016 08:48:12 +0000 (01:48 -0700)
committerJan Vorlicek <janvorli@microsoft.com>
Fri, 27 May 2016 08:48:12 +0000 (10:48 +0200)
The change that triggered the failures was going to a separate JIT module with its own PAL. The reason is a problem in the OSX exception forwarding a single-step exception: to forward/chain an exception to the next PAL the exception we restore the registers at the point of the exception and retry the it. For all the hardware exceptions this is fine, but for single-step the register state is after the instruction has been stepped so when it is retried and chained to the next PAL another instruction is stepped so the debugger gets notified an instruction after where it wanted. Chaining the single-step exception on Linux doesn’t have this problem because we just basically “jump” to the next PAL/signal handler.

The fix is too only “hook” single-step/breakpoint exceptions in the coreclr module/PAL (yet another PAL_INITIALIZE flag) and not in the JIT module (or any other non-coreclr PALs).

Commit migrated from https://github.com/dotnet/coreclr/commit/200ab604ac909928e96de6af7525cee231a370c3

src/coreclr/src/pal/inc/pal.h
src/coreclr/src/pal/src/exception/machexception.cpp
src/coreclr/src/pal/src/exception/machexception.h
src/coreclr/src/pal/src/init/pal.cpp

index 310323e..08f051a 100644 (file)
@@ -481,6 +481,7 @@ typedef long time_t;
 #define PAL_INITIALIZE_EXEC_ALLOCATOR               0x02
 #define PAL_INITIALIZE_STD_HANDLES                  0x04
 #define PAL_INITIALIZE_REGISTER_SIGTERM_HANDLER     0x08
+#define PAL_INITIALIZE_DEBUGGER_EXCEPTIONS          0x10
 
 // PAL_Initialize() flags
 #define PAL_INITIALIZE                 (PAL_INITIALIZE_SYNC_THREAD | PAL_INITIALIZE_STD_HANDLES)
@@ -489,7 +490,7 @@ typedef long time_t;
 #define PAL_INITIALIZE_DLL             PAL_INITIALIZE_NONE       
 
 // PAL_InitializeCoreCLR() flags
-#define PAL_INITIALIZE_CORECLR         (PAL_INITIALIZE | PAL_INITIALIZE_EXEC_ALLOCATOR | PAL_INITIALIZE_REGISTER_SIGTERM_HANDLER)
+#define PAL_INITIALIZE_CORECLR         (PAL_INITIALIZE | PAL_INITIALIZE_EXEC_ALLOCATOR | PAL_INITIALIZE_REGISTER_SIGTERM_HANDLER | PAL_INITIALIZE_DEBUGGER_EXCEPTIONS)
 
 typedef DWORD (PALAPI *PTHREAD_START_ROUTINE)(LPVOID lpThreadParameter);
 typedef PTHREAD_START_ROUTINE LPTHREAD_START_ROUTINE;
index 18eb8c4..508a967 100644 (file)
@@ -49,6 +49,8 @@ mach_port_t s_ExceptionPort;
 
 static BOOL s_DebugInitialized = FALSE;
 
+static DWORD s_PalInitializeFlags = 0;
+
 static const char * PAL_MACH_EXCEPTION_MODE = "PAL_MachExceptionMode";
 
 // This struct is used to track the threads that need to have an exception forwarded
@@ -191,7 +193,7 @@ GetExceptionMask()
     {
         machExceptionMask |= PAL_EXC_ILLEGAL_MASK;
     }
-    if (!(exMode & MachException_SuppressDebugging))
+    if (!(exMode & MachException_SuppressDebugging) && (s_PalInitializeFlags & PAL_INITIALIZE_DEBUGGER_EXCEPTIONS))
     {
 #ifdef FEATURE_PAL_SXS
         // Always hook exception ports for breakpoint exceptions.
@@ -1325,24 +1327,27 @@ MachSetThreadContext(CONTEXT *lpContext)
     }
 }
 
+
 /*++
 Function :
     SEHInitializeMachExceptions 
 
     Initialize all SEH-related stuff related to mach exceptions
 
-    (no parameters)
+    flags - PAL_INITIALIZE flags
 
 Return value :
     TRUE  if SEH support initialization succeeded
     FALSE otherwise
 --*/
 BOOL 
-SEHInitializeMachExceptions(void)
+SEHInitializeMachExceptions(DWORD flags)
 {
     pthread_t exception_thread;
     kern_return_t machret;
 
+    s_PalInitializeFlags = flags;
+
     // Allocate a mach port that will listen in on exceptions
     machret = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &s_ExceptionPort);
     if (machret != KERN_SUCCESS)
index c9f0276..18e3150 100644 (file)
@@ -35,7 +35,7 @@ extern "C"
 #define PAL_EXC_ALL_MASK       (PAL_EXC_ILLEGAL_MASK | PAL_EXC_DEBUGGING_MASK | PAL_EXC_MANAGED_MASK)
 
 // Process and thread initialization/cleanup/context routines
-BOOL SEHInitializeMachExceptions(void);
+BOOL SEHInitializeMachExceptions(DWORD flags);
 void SEHCleanupExceptionPort (void);
 void MachExceptionInitializeDebug(void);
 PAL_NORETURN void MachSetThreadContext(CONTEXT *lpContext);
index 416916b..ccd2298 100644 (file)
@@ -305,7 +305,7 @@ Initialize(
 #if HAVE_MACH_EXCEPTIONS
         // Mach exception port needs to be set up before the thread
         // data or threads are set up.
-        if (!SEHInitializeMachExceptions())
+        if (!SEHInitializeMachExceptions(flags))
         {
             ERROR("SEHInitializeMachExceptions failed!\n");
             palError = ERROR_GEN_FAILURE;