Fix managed breakpoints on OSx.
authorMike McLaughlin <mikem@microsoft.com>
Tue, 8 Sep 2015 23:26:28 +0000 (16:26 -0700)
committerMike McLaughlin <mikem@microsoft.com>
Tue, 6 Oct 2015 23:51:56 +0000 (16:51 -0700)
Changed the OSx exception initialization to enable breakpoints/stepping.

Fix problem with faults and breakpoints in coreclr code not being forwarded to
native debugger (if being debugged).

Fix debugger shutdown where we release the transport too many times and assert in debug.

When building the register context for an exception don't save/restore the debug
registers because they cause an priviledged instruction fault.

Fixed the PAL's TRACE formatting by merging the printfcpp.cpp formatting into
silent_printf.cpp. "%p" wasn't being formatted correctly in a PAL TRACE statement.

The executable heap zone wasn't being set because the process heap
is used instead of creating a new heap.

Commit migrated from https://github.com/dotnet/coreclr/commit/08f67f0acdb3935acc30b0a0f0ebee21513f2668

src/coreclr/src/debug/di/shimremotedatatarget.cpp
src/coreclr/src/debug/ee/debugger.cpp
src/coreclr/src/pal/src/cruntime/silent_printf.cpp
src/coreclr/src/pal/src/exception/machexception.cpp
src/coreclr/src/pal/src/exception/seh.cpp
src/coreclr/src/pal/src/memory/heap.cpp
src/coreclr/src/pal/src/thread/context.cpp

index 4983d74..fd34d33 100644 (file)
@@ -130,6 +130,7 @@ void ShimRemoteDataTarget::Dispose()
         m_pProxy->ReleaseTransport(m_pTransport);
     }
 
+    m_pTransport = NULL;
     m_hr = CORDBG_E_OBJECT_NEUTERED;
 }
 
index 270615b..eb649a5 100644 (file)
@@ -2054,6 +2054,9 @@ HRESULT Debugger::Startup(void)
     }
 #endif
 
+#ifdef FEATURE_PAL
+    PAL_InitializeDebug();
+#endif // FEATURE_PAL
 
     // Lazily initialize the interop-safe heap
 
index 09de2a6..d01070c 100644 (file)
@@ -80,6 +80,16 @@ INT Silent_PAL_vsnprintf(LPSTR Buffer, INT Count, LPCSTR Format, va_list aparg)
         {
             if (Prefix == PFF_PREFIX_LONG && Type == PFF_TYPE_STRING)
             {
+                if (WIDTH_STAR == Width)
+                {
+                    Width = va_arg(ap, INT);
+                }
+                else if (WIDTH_INVALID == Width)
+                {
+                    /* both a '*' and a number, ignore, but remove arg */
+                    TempInt = va_arg(ap, INT); /* value not used */
+                }
+
                 if (PRECISION_STAR == Precision)
                 {
                     Precision = va_arg(ap, INT);
@@ -89,6 +99,7 @@ INT Silent_PAL_vsnprintf(LPSTR Buffer, INT Count, LPCSTR Format, va_list aparg)
                     /* both a '*' and a number, ignore, but remove arg */
                     TempInt = va_arg(ap, INT); /* value not used */
                 }
+
                 TempWStr = va_arg(ap, LPWSTR);
                 Length = Silent_WideCharToMultiByte(TempWStr, -1, 0, 0);
                 if (!Length)
@@ -98,7 +109,7 @@ INT Silent_PAL_vsnprintf(LPSTR Buffer, INT Count, LPCSTR Format, va_list aparg)
                 }
 
                 /* clip string output to MAX_STR_LEN characters */
-                if(-1 == Precision)
+                if (PRECISION_DOT == Precision)
                 {
                     Precision = MAX_STR_LEN;
                 }
@@ -145,6 +156,13 @@ INT Silent_PAL_vsnprintf(LPSTR Buffer, INT Count, LPCSTR Format, va_list aparg)
             else if (Prefix == PFF_PREFIX_LONG && Type == PFF_TYPE_CHAR)
             {
                 CHAR TempBuffer[4];
+
+                if (WIDTH_STAR == Width ||
+                    WIDTH_INVALID == Width)
+                {
+                    /* ignore (because it's a char), and remove arg */
+                    TempInt = va_arg(ap, INT); /* value not used */
+                }
                 if (PRECISION_STAR == Precision ||
                     PRECISION_INVALID == Precision)
                 {
@@ -173,6 +191,10 @@ INT Silent_PAL_vsnprintf(LPSTR Buffer, INT Count, LPCSTR Format, va_list aparg)
                next arg */
             else if (Type == PFF_TYPE_N)
             {
+                if (WIDTH_STAR == Width)
+                {
+                    Width = va_arg(ap, INT);
+                }
                 if (PRECISION_STAR == Precision)
                 {
                     Precision = va_arg(ap, INT);
@@ -186,6 +208,35 @@ INT Silent_PAL_vsnprintf(LPSTR Buffer, INT Count, LPCSTR Format, va_list aparg)
                     *(va_arg(ap, LPLONG)) = BufferPtr - Buffer;
                 }
             }
+            else if (Type == PFF_TYPE_CHAR && (Flags & PFF_ZERO) != 0)
+            {
+                // Some versions of sprintf don't support 0-padded chars,
+                // so we handle them here.
+                char ch[2];
+
+                ch[0] = (char) va_arg(ap, int);
+                ch[1] = '\0';
+                Length = 1;
+                BufferRanOut = !Internal_AddPaddingA(&BufferPtr,
+                                           Count - (BufferPtr - Buffer),
+                                           ch,
+                                           Width - Length,
+                                           Flags);
+            }
+            else if (Type == PFF_TYPE_STRING && (Flags & PFF_ZERO) != 0)
+            {
+                // Some versions of sprintf don't support 0-padded strings,
+                // so we handle them here.
+                char *tempStr;
+
+                tempStr = va_arg(ap, char *);
+                Length = strlen(tempStr);
+                BufferRanOut = !Internal_AddPaddingA(&BufferPtr,
+                                           Count - (BufferPtr - Buffer),
+                                           tempStr,
+                                           Width - Length,
+                                           Flags);
+            }
             /* types that sprintf can handle */
             else
             {
@@ -205,10 +256,22 @@ INT Silent_PAL_vsnprintf(LPSTR Buffer, INT Count, LPCSTR Format, va_list aparg)
 
                     TempInt = snprintf(BufferPtr, TempCount, TempBuff, trunc2);
                 }
+                else if (Type == PFF_TYPE_INT && Prefix == PFF_PREFIX_SHORT)
+                {
+                    // Convert explicitly from int to short to get
+                    // correct sign extension for shorts on all systems.
+                    int n;
+                    short s;
+
+                    n = va_arg(ap, int);
+                    s = (short) n;
+
+                    TempInt = snprintf(BufferPtr, TempCount, TempBuff, s);
+                }
                 else
                 {
                     /* limit string output (%s) to 300 characters */
-                    if(TempBuff[0]=='%' && TempBuff[1]=='s')
+                    if(TempBuff[0] == '%' && TempBuff[1] == 's')
                     {
                         if (strcpy_s(TempBuff, sizeof(TempBuff), "%.300s") != SAFECRT_SUCCESS)
                         {
@@ -253,7 +316,6 @@ INT Silent_PAL_vsnprintf(LPSTR Buffer, INT Count, LPCSTR Format, va_list aparg)
     }
     else
     {
-
         return BufferPtr - Buffer;
     }
 }
@@ -293,6 +355,16 @@ int Silent_PAL_vfprintf(PAL_FILE *stream, const char *format, va_list aparg)
         {
             if (Prefix == PFF_PREFIX_LONG && Type == PFF_TYPE_STRING)
             {
+                if (WIDTH_STAR == Width)
+                {
+                    Width = va_arg(ap, INT);
+                }
+                else if (WIDTH_INVALID == Width)
+                {
+                    /* both a '*' and a number, ignore, but remove arg */
+                    TempInt = va_arg(ap, INT); /* value not used */
+                }
+
                 if (PRECISION_STAR == Precision)
                 {
                     Precision = va_arg(ap, INT);
@@ -302,6 +374,7 @@ int Silent_PAL_vfprintf(PAL_FILE *stream, const char *format, va_list aparg)
                     /* both a '*' and a number, ignore, but remove arg */
                     TempInt = va_arg(ap, INT); /* value not used */
                 }
+
                 TempWStr = va_arg(ap, LPWSTR);
                 Length = Silent_WideCharToMultiByte(TempWStr, -1, 0, 0);
                 if (!Length)
@@ -364,6 +437,12 @@ int Silent_PAL_vfprintf(PAL_FILE *stream, const char *format, va_list aparg)
             else if (Prefix == PFF_PREFIX_LONG && Type == PFF_TYPE_CHAR)
             {
                 CHAR TempBuffer[4];
+                if (WIDTH_STAR == Width ||
+                    WIDTH_INVALID == Width)
+                {
+                    /* ignore (because it's a char), and remove arg */
+                    TempInt = va_arg(ap, INT); /* value not used */
+                }
                 if (PRECISION_STAR == Precision ||
                     PRECISION_INVALID == Precision)
                 {
@@ -396,10 +475,15 @@ int Silent_PAL_vfprintf(PAL_FILE *stream, const char *format, va_list aparg)
                next arg */
             else if (Type == PFF_TYPE_N)
             {
+                if (WIDTH_STAR == Width)
+                {
+                    Width = va_arg(ap, INT);
+                }
                 if (PRECISION_STAR == Precision)
                 {
                     Precision = va_arg(ap, INT);
                 }
+
                 if (Prefix == PFF_PREFIX_SHORT)
                 {
                     *(va_arg(ap, short *)) = written;
@@ -427,6 +511,18 @@ int Silent_PAL_vfprintf(PAL_FILE *stream, const char *format, va_list aparg)
 
                     TempInt = fprintf((FILE*)stream, TempBuff, trunc2);
                 }
+                else if (Type == PFF_TYPE_INT && Prefix == PFF_PREFIX_SHORT)
+                {
+                    // Convert explicitly from int to short to get
+                    // correct sign extension for shorts on all systems.
+                    int n;
+                    short s;
+
+                    n = va_arg(ap, int);
+                    s = (short)n;
+
+                    TempInt = fprintf((FILE*)stream, TempBuff, s);
+                }
                 else
                 {
                     va_list apcopy;
@@ -521,19 +617,17 @@ Function:
   
   see Internal_ExtractFormatA function in printf.c
 *******************************************************************************/
-BOOL Silent_ExtractFormatA(LPCSTR *Fmt, LPSTR Out, LPINT Flags,
-                                    LPINT Width, LPINT Precision,
-                                    LPINT Prefix, LPINT Type)
+BOOL Silent_ExtractFormatA(LPCSTR *Fmt, LPSTR Out, LPINT Flags, LPINT Width, LPINT Precision, LPINT Prefix, LPINT Type)
 {
     BOOL Result = FALSE;
     LPSTR TempStr;
     LPSTR TempStrPtr;
 
-    *Width = -1;
-    *Precision = -1;
-    *Flags = 0;
-    *Prefix = -1;
-    *Type = -1;
+    *Width = WIDTH_DEFAULT;
+    *Precision = PRECISION_DEFAULT;
+    *Flags = PFF_NONE;
+    *Prefix = PFF_PREFIX_DEFAULT;
+    *Type = PFF_TYPE_DEFAULT;
 
     if (*Fmt && **Fmt == '%')
     {
@@ -593,6 +687,22 @@ BOOL Silent_ExtractFormatA(LPCSTR *Fmt, LPSTR Out, LPINT Flags,
             return Result;
         }
     }
+    else if (**Fmt == '*')
+    {
+        *Width = WIDTH_STAR;
+        *Out++ = *(*Fmt)++;
+        if (isdigit((unsigned char) **Fmt))
+        {
+            /* this is an invalid width because we have a * then a number */
+            /* printf handles this by just printing the whole string */
+            *Width = WIDTH_INVALID;
+            while (isdigit((unsigned char) **Fmt))
+            {
+               *Out++ = *(*Fmt)++;
+            }
+        }
+    }
+
 
     /* grab precision specifier */
     if (**Fmt == '.')
@@ -629,10 +739,6 @@ BOOL Silent_ExtractFormatA(LPCSTR *Fmt, LPSTR Out, LPINT Flags,
                     *Out++ = *(*Fmt)++;
                 }
             }
-            else
-            {
-                *Precision = PRECISION_STAR;
-            }
         }
         else
         {
@@ -640,6 +746,12 @@ BOOL Silent_ExtractFormatA(LPCSTR *Fmt, LPSTR Out, LPINT Flags,
         }
     }
 
+#ifdef BIT64
+    if (**Fmt == 'p')
+    {
+        *Prefix = PFF_PREFIX_LONGLONG;
+    }
+#endif
     /* grab prefix of 'I64' for __int64 */
     if ((*Fmt)[0] == 'I' && (*Fmt)[1] == '6' && (*Fmt)[2] == '4')
     {
@@ -656,8 +768,14 @@ BOOL Silent_ExtractFormatA(LPCSTR *Fmt, LPSTR Out, LPINT Flags,
     /* grab prefix of 'l' or the undocumented 'w' (at least in MSDN) */
     else if (**Fmt == 'l' || **Fmt == 'w')
     {
-        *Prefix = PFF_PREFIX_LONG;
         ++(*Fmt);
+#ifdef BIT64
+        // Only want to change the prefix on 64 bit when printing characters.
+        if (**Fmt == 'c' || **Fmt == 's')
+#endif       
+        {
+            *Prefix = PFF_PREFIX_LONG;
+        }
     }
     else if (**Fmt == 'L')
     {
@@ -739,25 +857,22 @@ BOOL Silent_ExtractFormatA(LPCSTR *Fmt, LPSTR Out, LPINT Flags,
     else if (**Fmt == 'p')
     {
         *Type = PFF_TYPE_P;
-        if (*Prefix == PFF_PREFIX_SHORT)
-        {
-            *Out++ = 'h';
-        }
-        else if (*Prefix == PFF_PREFIX_LONG)
+        *Out++ = *(*Fmt)++;
+
+        if (*Prefix == PFF_PREFIX_LONGLONG)
         {
-            *Out++ = 'l';
+            if (*Precision == PRECISION_DEFAULT)
+            {
+                *Precision = 16;
+            }
         }
-        else if (*Prefix == PFF_PREFIX_LONGLONG)
+        else
         {
-            /* native *printf does not support %I64p
-               (actually %llp), so we need to cheat a little bit */
-            *Out++ = 'l';
-            *Out++ = 'l';
+            if (*Precision == PRECISION_DEFAULT)
+            {
+                *Precision = 8;
+            }
         }
-        (*Fmt)++;
-        *Out++ = '.';
-        *Out++ = '8';
-        *Out++ = 'X';
         Result = TRUE;
     }
 
index 201aa80..d51c692 100644 (file)
@@ -93,6 +93,7 @@ struct ForwardedNotification
 #endif // !DISABLE_EXCEPTIONS
 
 static const char * PAL_MACH_EXCEPTION_MODE = "PAL_MachExceptionMode";
+
 enum MachExceptionMode
 {
     // special value to indicate we've not initialized yet
@@ -123,7 +124,7 @@ enum MachExceptionMode
     MachException_SuppressManaged   = 4,
 
     // Default value to use if environment variable not set.
-    MachException_Default           = 2,
+    MachException_Default           = 0,
 };
 
 static exception_mask_t GetExceptionMask()
@@ -536,6 +537,7 @@ void PAL_DispatchException(DWORD64 dwRDI, DWORD64 dwRSI, DWORD64 dwRDX, DWORD64
     pointers.ExceptionRecord = pExRecord;
     pointers.ContextRecord = pContext;
 
+    NONPAL_TRACE("PAL_DispatchException(EC %08x EA %p)\n", pExRecord->ExceptionCode, pExRecord->ExceptionAddress);
     SEHProcessException(&pointers);
 }
 
@@ -717,7 +719,13 @@ catch_exception_raise(
 #endif // _AMD64_
         );
     
-    ThreadContext.ContextFlags = CONTEXT_ALL;
+    // Don't save/restore the debug registers because loading them on OSx causes a 
+    // priviledged instruction fault. The "DE" in CR4 is set.
+#ifdef _X86_
+    ThreadContext.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS | CONTEXT_FLOATING_POINT | CONTEXT_EXTENDED_REGISTERS
+#else
+    ThreadContext.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS | CONTEXT_FLOATING_POINT;
+#endif
 
     MachRet = CONTEXT_GetThreadContextFromPort(thread, &ThreadContext);
     CHECK_MACH("CONTEXT_GetThreadContextFromPort", MachRet);
@@ -1178,12 +1186,11 @@ bool IsHandledException(MachMessage *pNotification)
     if (IsWithinCoreCLR(ip))
     {
         NONPAL_TRACE("    IP (%p) is in CoreCLR.\n", ip);
-        return true;
+        return CatchHardwareExceptionHolder::IsEnabled();
     }
 
     // Check inside our executable heap.
-    bool fExecutableHeap = s_pExecutableHeap != NULL &&
-        malloc_zone_owns_addr(s_pExecutableHeap, ip);
+    bool fExecutableHeap = s_pExecutableHeap != NULL && malloc_zone_owns_addr(s_pExecutableHeap, ip);
     if (fExecutableHeap)
     {
         NONPAL_TRACE("    IP (%p) is in the executable heap (%p).\n", ip, s_pExecutableHeap);
@@ -1219,7 +1226,7 @@ bool IsHandledException(MachMessage *pNotification)
     void *pCallerIP = (void *)*((PULONG64)(rbpFaultingFunc+1));
     if (IsWithinCoreCLR(pCallerIP))
     {
-        NONPAL_TRACE("    CallerIP (%p) is in CoreCLR.\n", pCallerIP);
+        NONPAL_TRACE("    CallerIP (%p) is in CoreCLR (IP %p).\n", pCallerIP, ip);
         return true;
     }
 #endif // defined(_AMD64_)
index 3080814..846da29 100644 (file)
@@ -164,6 +164,7 @@ PAL_SetHardwareExceptionHandler(
     IN PHARDWARE_EXCEPTION_HANDLER exceptionHandler)
 
 {
+    //TRACE("Hardware exception installed: %p\n", exceptionHandler);
     g_hardwareExceptionHandler = exceptionHandler;
 }
 
@@ -194,7 +195,8 @@ SEHProcessException(PEXCEPTION_POINTERS pointers)
         throw exception;
     }
 
-    TRACE("Unhandled hardware exception %08x\n", pointers->ExceptionRecord->ExceptionCode);
+    TRACE("Unhandled hardware exception %08x at %p\n", 
+        pointers->ExceptionRecord->ExceptionCode, pointers->ExceptionRecord->ExceptionAddress);
 }
 
 /*++
index 5cc59d0..c2f316d 100644 (file)
@@ -137,13 +137,7 @@ HeapCreate(
     }
     else
     {
-        malloc_zone_t *pZone = malloc_create_zone(dwInitialSize, 0 /* flags */);
-        ret = (HANDLE)pZone;
-#ifdef CACHE_HEAP_ZONE
-        _ASSERT_MSG(s_pExecutableHeap == NULL, "PAL currently only handles the creation of one executable heap.");
-        s_pExecutableHeap = pZone;
-        TRACE("s_pExecutableHeap is %p.\n", s_pExecutableHeap);
-#endif // CACHE_HEAP_ZONE
+        ret = (HANDLE)malloc_create_zone(dwInitialSize, 0 /* flags */);
     }
     
 #else // __APPLE__
@@ -176,7 +170,15 @@ GetProcessHeap(
 #if HEAP_HANDLES_ARE_REAL_HANDLES
 #error
 #else
-    ret = (HANDLE) malloc_default_zone();
+    malloc_zone_t *pZone = malloc_default_zone();
+    ret = (HANDLE)pZone;
+#ifdef CACHE_HEAP_ZONE
+    if (s_pExecutableHeap == NULL)
+    {
+        s_pExecutableHeap = pZone;
+        TRACE("s_pExecutableHeap is %p (process heap).\n", s_pExecutableHeap);
+    }
+#endif // CACHE_HEAP_ZONE
 #endif // HEAP_HANDLES_ARE_REAL_HANDLES
 #else
     ret = (HANDLE) DUMMY_HEAP;
index 6006aad..fdeeda3 100644 (file)
@@ -894,12 +894,14 @@ CONTEXT_GetThreadContextFromPort(
         lpContext->R13 = State.__r13;
         lpContext->R14 = State.__r14;
         lpContext->R15 = State.__r15;
-//        lpContext->SegSs = State.ss; // no such state?
         lpContext->EFlags = State.__rflags;
         lpContext->Rip = State.__rip;
         lpContext->SegCs = State.__cs;
-//        lpContext->SegDs_PAL_Undefined = State.ds; // no such state?
-//        lpContext->SegEs_PAL_Undefined = State.es; // no such state?
+        // RtlRestoreContext uses the actual ss instead of this one
+        // to build the iret frame so just set it zero.
+        lpContext->SegSs = 0;
+        lpContext->SegDs = 0;
+        lpContext->SegEs = 0;
         lpContext->SegFs = State.__fs;
         lpContext->SegGs = State.__gs;
 #else