Enable bpmd command even unjitted functions work.
authorMike McLaughlin <mikem@microsoft.com>
Wed, 17 Jun 2015 00:43:04 +0000 (17:43 -0700)
committerMike McLaughlin <mikem@microsoft.com>
Fri, 19 Jun 2015 21:36:20 +0000 (14:36 -0700)
Preallocate JIT notification table on VM side (since ICLRDataTarget2->AllocVirtual isn't implemented under lldb) and implement WriteVirtual on debugger side to allow DAC to write entries.

Used the special set breakpoint on exception throw lldb command to catch the special exception the VM throws when some
thing is jitted. The debugger side finds the exception record by searching for the RtlpRaiseException function on the stack
when the bp is hit. It also assumes that the local variable is called ExceptionRecord.

Fix all the file path separators to use the platform independent defines.

Ifdef all the "/d" options in the supported commands because the / char isn't supported as a command line option and /d is always the DML option that isn't supported either.

Fix problem Prem run into running sos after the process stops.

15 files changed:
src/ToolBox/SOS/Strike/datatarget.cpp
src/ToolBox/SOS/Strike/strike.cpp
src/ToolBox/SOS/Strike/util.cpp
src/ToolBox/SOS/Strike/util.h
src/ToolBox/SOS/lldbplugin/debugclient.cpp
src/ToolBox/SOS/lldbplugin/debugclient.h
src/ToolBox/SOS/lldbplugin/inc/dbgeng.h
src/ToolBox/SOS/lldbplugin/soscommand.cpp
src/ToolBox/SOS/lldbplugin/sosplugin.h
src/dlls/mscoree/mscorwks_unixexports.src
src/inc/palclr.h
src/pal/inc/rt/palrt.h
src/pal/src/exception/seh-unwind.cpp
src/vm/ceemain.cpp
src/vm/util.hpp

index 227f7c3..15d61d4 100644 (file)
@@ -119,7 +119,11 @@ DataTarget::WriteVirtual(
     /* [in] */ ULONG32 request,
     /* [optional][out] */ ULONG32 *done)
 {
-    return E_NOTIMPL;
+    if (g_ExtData == NULL)
+    {
+        return E_UNEXPECTED;
+    }
+    return g_ExtData->WriteVirtual(address, (PVOID)buffer, request, done);
 }
 
 HRESULT STDMETHODCALLTYPE
index 1d27c71..d9b96bf 100644 (file)
@@ -271,7 +271,9 @@ DECLARE_API(IP2MD)
     TADDR IP = 0;
     CMDOption option[] = 
     {   // name, vptr, type, hasValue
+#ifndef FEATURE_PAL
         {"/d", &dml, COBOOL, FALSE},
+#endif
     };
     CMDValue arg[] = 
     {   // vptr, type
@@ -655,7 +657,9 @@ DECLARE_API(DumpStackObjects)
     CMDOption option[] = 
     {   // name, vptr, type, hasValue
         {"-verify", &bVerify, COBOOL, FALSE},
+#ifndef FEATURE_PAL
         {"/d", &dml, COBOOL, FALSE}
+#endif
     };    
     CMDValue arg[] = 
     {   // vptr, type
@@ -691,7 +695,9 @@ DECLARE_API(DumpMD)
 
     CMDOption option[] = 
     {   // name, vptr, type, hasValue
+#ifndef FEATURE_PAL
         {"/d", &dml, COBOOL, FALSE},
+#endif
     };
     CMDValue arg[] = 
     {   // vptr, type
@@ -1129,7 +1135,9 @@ DECLARE_API(DumpClass)
 
     CMDOption option[] = 
     {   // name, vptr, type, hasValue
+#ifndef FEATURE_PAL
         {"/d", &dml, COBOOL, FALSE},
+#endif
     };
     CMDValue arg[] = 
     {   // vptr, type
@@ -1257,7 +1265,9 @@ DECLARE_API(DumpMT)
     CMDOption option[] = 
     {   // name, vptr, type, hasValue
         {"-MD", &bDumpMDTable, COBOOL, FALSE},
+#ifndef FEATURE_PAL
         {"/d", &dml, COBOOL, FALSE}
+#endif
     };
     CMDValue arg[] = 
     {   // vptr, type
@@ -1757,7 +1767,9 @@ DECLARE_API(DumpArray)
         {"-length", &flags.Length, COSIZE_T, TRUE},
         {"-details", &flags.bDetail, COBOOL, FALSE},
         {"-nofields", &flags.bNoFieldsForElement, COBOOL, FALSE},
+#ifndef FEATURE_PAL
         {"/d", &dml, COBOOL, FALSE},
+#endif
     };
     CMDValue arg[] = 
     {   // vptr, type
@@ -1973,7 +1985,9 @@ DECLARE_API(DumpObj)
     {   // name, vptr, type, hasValue
         {"-nofields", &bNoFields, COBOOL, FALSE},
         {"-refs", &bRefs, COBOOL, FALSE},
+#ifndef FEATURE_PAL
         {"/d", &dml, COBOOL, FALSE},
+#endif
     };
     CMDValue arg[] = 
     {   // vptr, type
@@ -2589,7 +2603,9 @@ DECLARE_API(PrintException)
         {"-lines", &bLineNumbers, COBOOL, FALSE},
         {"-l", &bLineNumbers, COBOOL, FALSE},
         {"-ccw", &bCCW, COBOOL, FALSE},
+#ifndef FEATURE_PAL
         {"/d", &dml, COBOOL, FALSE}
+#endif
     };
     CMDValue arg[] = 
     {   // vptr, type
@@ -2733,8 +2749,6 @@ DECLARE_API(PrintException)
     return Status;
 }
 
-#ifndef FEATURE_PAL
-
 /**********************************************************************\
 * Routine Description:                                                 *
 *                                                                      *
@@ -2753,7 +2767,9 @@ DECLARE_API(DumpVC)
 
     CMDOption option[] = 
     {   // name, vptr, type, hasValue
+#ifndef FEATURE_PAL
         {"/d", &dml, COBOOL, FALSE}
+#endif
     };
     CMDValue arg[] = 
     {   // vptr, type
@@ -2782,6 +2798,8 @@ DECLARE_API(DumpVC)
     return PrintVC(p_MT, p_Object);
 }
 
+#ifndef FEATURE_PAL
+
 #ifdef FEATURE_COMINTEROP
 
 DECLARE_API(DumpRCW)
@@ -3610,7 +3628,9 @@ public:
             {"-max", &mMaxSize, COHEX, TRUE},        // max size of objects to display
             {"-live", &mLive, COHEX, FALSE},         // only print live objects
             {"-dead", &mDead, COHEX, FALSE},         // only print dead objects
+#ifndef FEATURE_PAL
             {"/d", &mDML, COBOOL, FALSE},            // Debugger Markup Language
+#endif
         };
 
         CMDValue arg[] = 
@@ -5208,7 +5228,9 @@ DECLARE_API(DumpModule)
     CMDOption option[] = 
     {   // name, vptr, type, hasValue
         {"-mt", &bMethodTables, COBOOL, FALSE},
+#ifndef FEATURE_PAL
         {"/d", &dml, COBOOL, FALSE}
+#endif
     };
     CMDValue arg[] = 
     {   // vptr, type
@@ -5296,7 +5318,9 @@ DECLARE_API(DumpDomain)
 
     CMDOption option[] = 
     {   // name, vptr, type, hasValue
+#ifndef FEATURE_PAL
         {"/d", &dml, COBOOL, FALSE},
+#endif
     };
     CMDValue arg[] = 
     {   // vptr, type
@@ -5414,7 +5438,9 @@ DECLARE_API(DumpAssembly)
 
     CMDOption option[] = 
     {   // name, vptr, type, hasValue
+#ifndef FEATURE_PAL
         {"/d", &dml, COBOOL, FALSE},
+#endif
     };
     CMDValue arg[] = 
     {   // vptr, type
@@ -5952,7 +5978,9 @@ DECLARE_API(Threads)
     {   // name, vptr, type, hasValue
         {"-special", &bPrintSpecialThreads, COBOOL, FALSE},
         {"-live", &bPrintLiveThreadsOnly, COBOOL, FALSE},
+#ifndef FEATURE_PAL
         {"/d", &dml, COBOOL, FALSE},
+#endif
     };
     if (!GetCMDOption(args, option, _countof(option), NULL, 0, NULL)) 
     {
@@ -6041,6 +6069,7 @@ DECLARE_API(WatsonBuckets)
         
     return Status;
 } // WatsonBuckets()
+#endif // FEATURE_PAL
 
 struct PendingBreakpoint
 {
@@ -6062,7 +6091,7 @@ struct PendingBreakpoint
     }
 
     PendingBreakpoint *pNext;
-    PendingBreakpoint() : pNext(NULL), ilOffset(0), lineNumber(0), methodToken(0)
+    PendingBreakpoint() : lineNumber(0), ilOffset(0), methodToken(0), pNext(NULL) 
     {
         szModuleName[0] = L'\0';
         szFunctionName[0] = L'\0';
@@ -6106,9 +6135,13 @@ void IssueDebuggerBPCommand ( CLRDATA_ADDRESS addr )
             wcscpy_s(wszNameBuffer, _countof(wszNameBuffer), W("UNKNOWN"));        
         }
 
+#ifndef FEATURE_PAL
         sprintf_s(buffer, _countof(buffer), "bp %p", (void*) (size_t) addr);
+#else
+        sprintf_s(buffer, _countof(buffer), "breakpoint set --address 0x%p", (void*) (size_t) addr);
+#endif
         ExtOut("Setting breakpoint: %s [%S]\n", buffer, wszNameBuffer);
-        g_ExtControl->Execute(DEBUG_EXECUTE_NOT_LOGGED, buffer ,0);
+        g_ExtControl->Execute(DEBUG_EXECUTE_NOT_LOGGED, buffer0);
 
         if ( curLimit < MaxBPsCached )
             alreadyPlacedBPs[curLimit++] = addr;
@@ -6264,6 +6297,7 @@ public:
         }
     }
 
+#ifndef FEATURE_PAL
     void SaveBreakpoints(FILE* pFile)
     {
         PendingBreakpoint *pCur = m_breakpoints;
@@ -6276,6 +6310,7 @@ public:
             pCur = pCur->pNext;
         }
     }
+#endif
 
     void ClearBreakpoint(size_t breakPointToClear)
     {
@@ -6332,11 +6367,11 @@ public:
 
         //get a pointer to just the filename (the portion after the last backslash)
         WCHAR* pModuleFilename = wszNameBuffer;
-        WCHAR* pSlash = wcschr(pModuleFilename, L'\\');
+        WCHAR* pSlash = wcschr(pModuleFilename, DIRECTORY_SEPARATOR_CHAR_W);
         while(pSlash != NULL)
         {
             pModuleFilename = pSlash+1;
-            pSlash = wcschr(pModuleFilename, L'\\');
+            pSlash = wcschr(pModuleFilename, DIRECTORY_SEPARATOR_CHAR_W);
         }
 
         ImageInfo ii;
@@ -6687,9 +6722,7 @@ public:
                     DacpGetModuleAddress dgma;
                     if (SUCCEEDED(dgma.Request(pMod)))
                     {
-#ifndef FEATURE_PAL
                         g_bpoints.Update(TO_TADDR(dgma.ModulePtr), FALSE);
-#endif
                     }
                     else
                     {
@@ -6723,9 +6756,7 @@ public:
         DacpGetModuleAddress dgma;
         if (SUCCEEDED(dgma.Request(mod)))
         {
-#ifndef FEATURE_PAL
             g_bpoints.Update(TO_TADDR(dgma.ModulePtr), TRUE);
-#endif
         }
 
         if(!g_fAllowJitOptimization)
@@ -6754,9 +6785,7 @@ public:
         DacpGetModuleAddress dgma;
         if (SUCCEEDED(dgma.Request(mod)))
         {
-#ifndef FEATURE_PAL
             g_bpoints.RemovePendingForModule(TO_TADDR(dgma.ModulePtr));
-#endif
         }
 
         m_dbgStatus = DEBUG_STATUS_GO_HANDLED;
@@ -6838,15 +6867,16 @@ BOOL CheckCLRNotificationEvent(DEBUG_LAST_EVENT_INFO_EXCEPTION* pdle)
 {
     ULONG Type, ProcessId, ThreadId;
     ULONG ExtraInformationUsed;
-    HRESULT Status = g_ExtControl->GetLastEventInformation( &Type,
-                                                    &ProcessId,
-                                                    &ThreadId,
-                                                    pdle,
-                                                    sizeof(DEBUG_LAST_EVENT_INFO_EXCEPTION),
-                                                    &ExtraInformationUsed,
-                                                    NULL,
-                                                    0,
-                                                    NULL);
+    HRESULT Status = g_ExtControl->GetLastEventInformation(
+        &Type,
+        &ProcessId,
+        &ThreadId,
+        pdle,
+        sizeof(DEBUG_LAST_EVENT_INFO_EXCEPTION),
+        &ExtraInformationUsed,
+        NULL,
+        0,
+        NULL);
 
     if (Status != S_OK || Type != DEBUG_EVENT_EXCEPTION)
     {
@@ -6859,11 +6889,10 @@ BOOL CheckCLRNotificationEvent(DEBUG_LAST_EVENT_INFO_EXCEPTION* pdle)
     }
 
     return TRUE;
-    }
+}
 
 HRESULT HandleCLRNotificationEvent()
 {
-    HRESULT Status = E_FAIL;
     /*
      * Did we get module load notification? If so, check if any in our pending list
      * need to be registered for jit notification.
@@ -6877,12 +6906,13 @@ HRESULT HandleCLRNotificationEvent()
     if (!CheckCLRNotificationEvent(&dle))
     {
         ExtOut("Expecting first chance CLRN exception\n");
-        return Status;
+        return E_FAIL;
     }
 
     // Notification only needs to live for the lifetime of the call below, so it's a non-static
     // local.
-    if (g_clrData->TranslateExceptionRecordToNotification(&dle.ExceptionRecord, &Notification) != S_OK)
+    HRESULT Status = g_clrData->TranslateExceptionRecordToNotification(&dle.ExceptionRecord, &Notification);
+    if (Status != S_OK)
     {
         ExtOut("Error processing exception notification\n");
         return Status;
@@ -6894,17 +6924,20 @@ HRESULT HandleCLRNotificationEvent()
             case DEBUG_STATUS_GO:
             case DEBUG_STATUS_GO_HANDLED:
             case DEBUG_STATUS_GO_NOT_HANDLED:
+#ifndef FEATURE_PAL
                 g_ExtControl->Execute(DEBUG_EXECUTE_NOT_LOGGED, "g", 0);
+#else
+                g_ExtControl->Execute(DEBUG_EXECUTE_NOT_LOGGED, "process continue", 0);
+#endif
                 break;
             default:
                 break;
         }
     }
 
-    return Status;
+    return S_OK;
 }
 
-
 DECLARE_API(HandleCLRN)
 {
     INIT_API();    
@@ -6913,7 +6946,6 @@ DECLARE_API(HandleCLRN)
     return HandleCLRNotificationEvent();
 }
 
-#ifndef FEATURE_PAL
 DECLARE_API(bpmd)
 {
     INIT_API_NOEE();    
@@ -7222,6 +7254,7 @@ DECLARE_API(bpmd)
         }
         else if (MethodDescData.bIsDynamic)
         {
+#ifndef FEATURE_PAL
             // Dynamic methods don't have JIT notifications. This is something we must
             // fix in the next release. Until then, you have a cumbersome user experience.
             ExtOut("This DynamicMethodDesc is not yet JITTED. Placing memory breakpoint at %p\n",
@@ -7238,12 +7271,15 @@ DECLARE_API(bpmd)
                 (void*) (size_t) MethodDescData.AddressOfNativeCodeSlot,
                 (void*) (size_t) MethodDescData.AddressOfNativeCodeSlot);
 
-            Status = g_ExtControl->Execute(DEBUG_EXECUTE_NOT_LOGGED, buffer ,0);
+            Status = g_ExtControl->Execute(DEBUG_EXECUTE_NOT_LOGGED, buffer0);
             if (FAILED(Status))
             {
                 ExtOut("Unable to set breakpoint with IDebugControl::Execute: %x\n",Status);
                 ExtOut("Attempted to run: %s\n", buffer);                
             }            
+#else
+            ExtErr("This DynamicMethodDesc is not yet JITTED %p\n", MethodDescData.AddressOfNativeCodeSlot);
+#endif // FEATURE_PAL
         }
         else
         {
@@ -7267,13 +7303,24 @@ DECLARE_API(bpmd)
     if (bNeedNotificationExceptions)
     {
         ExtOut("Adding pending breakpoints...\n");
+#ifndef FEATURE_PAL
         sprintf_s(buffer, _countof(buffer), "sxe -c \"!HandleCLRN\" clrn");
-        Status = g_ExtControl->Execute(DEBUG_EXECUTE_NOT_LOGGED, buffer ,0);        
+        Status = g_ExtControl->Execute(DEBUG_EXECUTE_NOT_LOGGED, buffer, 0);        
+#else
+        sprintf_s(buffer, _countof(buffer), "breakpoint set -E c++ -h false -w true");
+        Status = g_ExtControl->Execute(DEBUG_EXECUTE_NOT_LOGGED, buffer, 0);        
+        if (Status == S_OK)
+        {
+            sprintf_s(buffer, _countof(buffer), "breakpoint command add -o \"sos HandleCLRN\"");
+            Status = g_ExtControl->Execute(DEBUG_EXECUTE_NOT_LOGGED, buffer, 0);
+        }
+#endif // FEATURE_PAL
     }
 
     return Status;
 }
-#endif
+
+#ifndef FEATURE_PAL
 
 /**********************************************************************\
 * Routine Description:                                                 *
@@ -7430,7 +7477,9 @@ DECLARE_API(FindAppDomain)
 
     CMDOption option[] = 
     {   // name, vptr, type, hasValue
+#ifndef FEATURE_PAL
         {"/d", &dml, COBOOL, FALSE},
+#endif
     };
     CMDValue arg[] = 
     {   // vptr, type
@@ -8877,7 +8926,9 @@ DECLARE_API(Token2EE)
 
     CMDOption option[] = 
     {   // name, vptr, type, hasValue
+#ifndef FEATURE_PAL
         {"/d", &dml, COBOOL, FALSE},
+#endif
     };
 
     CMDValue arg[] = 
@@ -8932,7 +8983,7 @@ DECLARE_API(Token2EE)
             FileNameForModule(dwAddr, FileName);
 
             // We'd like a short form for this output
-            LPWSTR pszFilename = wcsrchr (FileName, L'\\');
+            LPWSTR pszFilename = wcsrchr (FileName, DIRECTORY_SEPARATOR_CHAR_W);
             if (pszFilename == NULL)
             {
                 pszFilename = FileName;
@@ -8969,7 +9020,9 @@ DECLARE_API(Name2EE)
 
     CMDOption option[] = 
     {   // name, vptr, type, hasValue
+#ifndef FEATURE_PAL
         {"/d", &dml, COBOOL, FALSE},
+#endif
     };
     
     CMDValue arg[] = 
@@ -9060,7 +9113,7 @@ DECLARE_API(Name2EE)
             FileNameForModule (dwAddr, FileName);
 
             // We'd like a short form for this output
-            LPWSTR pszFilename = wcsrchr (FileName, L'\\');
+            LPWSTR pszFilename = wcsrchr (FileName, DIRECTORY_SEPARATOR_CHAR_W);
             if (pszFilename == NULL)
             {
                 pszFilename = FileName;
@@ -10012,7 +10065,7 @@ DECLARE_API(GetCodeTypeFlags)
     sprintf_s(buffer,_countof (buffer),
         "r$t%d=%x",
         preg, codeType);
-    Status = g_ExtControl->Execute(DEBUG_EXECUTE_NOT_LOGGED, buffer ,0);
+    Status = g_ExtControl->Execute(DEBUG_EXECUTE_NOT_LOGGED, buffer0);
     if (FAILED(Status))
     {
         ExtOut("Error setting register $t%d\n", preg);
@@ -10081,7 +10134,7 @@ DECLARE_API(StopOnException)
     sprintf_s(buffer,_countof (buffer),
         "r$t%d=0",
         preg);
-    Status = g_ExtControl->Execute(DEBUG_EXECUTE_NOT_LOGGED, buffer ,0);
+    Status = g_ExtControl->Execute(DEBUG_EXECUTE_NOT_LOGGED, buffer0);
     if (FAILED(Status))
     {
         ExtOut("Error initialized register $t%d to zero\n", preg);
@@ -10101,7 +10154,7 @@ DECLARE_API(StopOnException)
             EXCEPTION_COMPLUS
             );
             
-        Status = g_ExtControl->Execute(DEBUG_EXECUTE_NOT_LOGGED, buffer ,0);        
+        Status = g_ExtControl->Execute(DEBUG_EXECUTE_NOT_LOGGED, buffer0);        
         if (FAILED(Status))
         {
             ExtOut("Error setting breakpoint: %s\n", buffer);
@@ -10147,7 +10200,7 @@ DECLARE_API(StopOnException)
                 sprintf_s(buffer,_countof (buffer),
                     "r$t%d=1",
                     preg);
-                Status = g_ExtControl->Execute(DEBUG_EXECUTE_NOT_LOGGED, buffer ,0);
+                Status = g_ExtControl->Execute(DEBUG_EXECUTE_NOT_LOGGED, buffer0);
                 if (FAILED(Status))
                 {
                     ExtOut("Failed to execute the following command: %s\n", buffer);
@@ -12120,7 +12173,9 @@ DECLARE_API(ClrStack)
         {"-n", &bSuppressLines, COBOOL, FALSE},
         {"-i", &bICorDebug, COBOOL, FALSE},
         {"-gc", &bGC, COBOOL, FALSE},
+#ifndef FEATURE_PAL
         {"/d", &dml, COBOOL, FALSE},
+#endif
     };
     CMDValue arg[] = 
     {   // vptr, type
index 361ab45..275113a 100644 (file)
@@ -596,7 +596,7 @@ BOOL GetPathFromModule(
     if (len == 0 || len == cFqPath)
         return FALSE;
 
-    WCHAR *pLastSep = wcsrchr(fqPath, L'\\');
+    WCHAR *pLastSep = wcsrchr(fqPath, DIRECTORY_SEPARATOR_CHAR_W);
     if (pLastSep == NULL || pLastSep+1 >= fqPath+cFqPath)
         return FALSE;
 
@@ -2353,13 +2353,21 @@ BOOL IsSameModuleName (const char *str1, const char *str2)
     const char *ptr2 = str2 + strlen(str2)-1;
     while (ptr2 >= str2)
     {
+#ifndef FEATURE_PAL
         if (tolower(*ptr1) != tolower(*ptr2))
+#else
+        if (*ptr1 != *ptr2)
+#endif
+        {
             return FALSE;
-        ptr2 --;
-        ptr1 --;
+        }
+        ptr2--;
+        ptr1--;
     }
-    if (ptr1 >= str1 && *ptr1 != '\\' && *ptr1 != ':')
+    if (ptr1 >= str1 && *ptr1 != DIRECTORY_SEPARATOR_CHAR_A && *ptr1 != ':')
+    {
         return FALSE;
+    }
     return TRUE;
 }
 
@@ -2602,7 +2610,11 @@ BOOL IsFusionLoadedModule (LPCSTR fusionName, LPCSTR mName)
                 return FALSE;
             }
             
+#ifndef FEATURE_PAL
             if (tolower(*fusionName) != tolower(*mName))
+#else
+            if (*fusionName != *mName)
+#endif
             {
                 return FALSE;
             }
@@ -2635,12 +2647,14 @@ BOOL DebuggerModuleNamesMatch (CLRDATA_ADDRESS PEFileAddr, __in __in_z LPSTR mNa
                 {                                    
                     CHAR ModuleName[MAX_PATH+1];
 
-                    if (g_ExtSymbols->GetModuleNames (Index, base,
-                        NULL, 0, NULL,
-                        ModuleName, MAX_PATH, NULL,
-                        NULL, 0, NULL) == S_OK)
+                    if (g_ExtSymbols->GetModuleNames(Index, base, NULL, 0, NULL, ModuleName, 
+                        MAX_PATH, NULL, NULL, 0, NULL) == S_OK)
                     {
+#ifndef FEATURE_PAL
                         if (_stricmp (ModuleName, mName) == 0)
+#else
+                        if (strcmp (ModuleName, mName) == 0)
+#endif
                         {
                             return TRUE;
                         }
@@ -2792,9 +2806,9 @@ DWORD_PTR *ModuleFromName(__in __in_z __in_opt LPSTR mName, int *numModule)
                     fileName[m] = '\0';
                     
                     if ((mName == NULL) || 
-                        IsSameModuleName (fileName, mName) ||
+                        IsSameModuleName(fileName, mName) ||
                         DebuggerModuleNamesMatch(ModuleData.File, mName) ||
-                        IsFusionLoadedModule (fileName, mName))
+                        IsFusionLoadedModule(fileName, mName))
                     {
                         AddToModuleList(moduleList, *numModule, maxList,
                                          (DWORD_PTR)ModuleAddr);
@@ -3155,11 +3169,15 @@ void GetInfoFromModule (DWORD_PTR ModuleAddr, ULONG token, DWORD_PTR *ret)
                     }
                     else
                     {
+#ifndef FEATURE_PAL
                         if (IsDMLEnabled())
                             DMLOut("Not JITTED yet. Use <exec cmd=\"!bpmd -md %p\">!bpmd -md %p</exec> to break on run.\n",
-                                    SOS_PTR(md), SOS_PTR(md));
+                                SOS_PTR(md), SOS_PTR(md));
                         else
                             ExtOut("Not JITTED yet. Use !bpmd -md %p to break on run.\n", SOS_PTR(md));
+#else
+                        ExtOut("Not JITTED yet. Use 'sos bpmd -md %p' to break on run.\n", SOS_PTR(md));
+#endif
                     }
                 }
                 else
@@ -3992,7 +4010,11 @@ BOOL GetCMDOption(const char *string, CMDOption *option, size_t nOption,
             }
         }
 
+#ifndef FEATURE_PAL
         if (ptr[0] != '-' && ptr[0] != '/') {
+#else
+        if (ptr[0] != '-') {
+#endif
             if (maxArg == 0) {
                 ExtOut ("Incorrect argument: %s\n", ptr);
                 return FALSE;
@@ -5531,9 +5553,6 @@ NoOutputHolder::~NoOutputHolder()
         Output::g_bSuppressOutput--;
 }
 
-// Do not support source line numbers on PAL platforms
-#ifndef FEATURE_PAL
-
 //
 // Code to support mapping RVAs to managed code line numbers.
 //
@@ -5806,9 +5825,6 @@ ConvertNativeToIlOffset(
 }
 
 
-#endif
-
-
 // Based on a native offset, passed in the first argument this function
 // identifies the corresponding source file name and line number.
 HRESULT
@@ -6138,10 +6154,11 @@ HRESULT __stdcall PERvaMemoryReader::ReadExecutableAtRVA(DWORD relativeVirtualAd
     return SafeReadMemory(m_moduleBaseAddress + relativeVirtualAddress, data, cbData, pcbData) ? S_OK : E_FAIL;
 }
 
-
+#endif // FEATURE_PAL
 
 HRESULT SymbolReader::LoadSymbols(IMetaDataImport * pMD, ICorDebugModule * pModule)
 {
+#ifndef FEATURE_PAL
     HRESULT Status = S_OK;
     if(m_pSymReader != NULL) return S_OK;
     
@@ -6167,10 +6184,14 @@ HRESULT SymbolReader::LoadSymbols(IMetaDataImport * pMD, ICorDebugModule * pModu
     IfFailRet(pModule->GetName(_countof(moduleName), &len, moduleName));
 
     return LoadSymbols(pMD, baseAddress, moduleName, isInMemory);
+#else
+    return E_FAIL;
+#endif // FEATURE_PAL
 }
 
 HRESULT SymbolReader::LoadSymbols(IMetaDataImport * pMD, ULONG64 baseAddress, __in_z WCHAR* pModuleName, BOOL isInMemory)
 {
+#ifndef FEATURE_PAL
     HRESULT Status = S_OK;
 
     if(m_pSymReader != NULL) return S_OK;
@@ -6236,6 +6257,9 @@ HRESULT SymbolReader::LoadSymbols(IMetaDataImport * pMD, ULONG64 baseAddress, __
         m_pSymReader = NULL;
     }
     return Status;
+#else
+    return E_FAIL;
+#endif // FEATURE_PAL
 }
 
 HRESULT SymbolReader::GetNamedLocalVariable(ISymUnmanagedScope * pScope, ICorDebugILFrame * pILFrame, mdMethodDef methodToken, ULONG localIndex, __inout_ecount(paramNameLen) WCHAR* paramName, ULONG paramNameLen, ICorDebugValue** ppValue)
@@ -6244,6 +6268,7 @@ HRESULT SymbolReader::GetNamedLocalVariable(ISymUnmanagedScope * pScope, ICorDeb
 
     if(pScope == NULL)
     {
+#ifndef FEATURE_PAL
         ToRelease<ISymUnmanagedMethod> pSymMethod;
         IfFailRet(m_pSymReader->GetMethod(methodToken, &pSymMethod));
 
@@ -6251,6 +6276,9 @@ HRESULT SymbolReader::GetNamedLocalVariable(ISymUnmanagedScope * pScope, ICorDeb
         IfFailRet(pSymMethod->GetRootScope(&pScope));
 
         return GetNamedLocalVariable(pScope, pILFrame, methodToken, localIndex, paramName, paramNameLen, ppValue);
+#else
+        return E_FAIL;
+#endif // FEATURE_PAL
     }
     else
     {
@@ -6306,6 +6334,7 @@ HRESULT SymbolReader::GetNamedLocalVariable(ISymUnmanagedScope * pScope, ICorDeb
     }
     return E_FAIL;
 }
+
 HRESULT SymbolReader::GetNamedLocalVariable(ICorDebugFrame * pFrame, ULONG localIndex, __inout_ecount(paramNameLen) WCHAR* paramName, ULONG paramNameLen, ICorDebugValue** ppValue)
 {
     HRESULT Status = S_OK;
@@ -6328,8 +6357,10 @@ HRESULT SymbolReader::GetNamedLocalVariable(ICorDebugFrame * pFrame, ULONG local
 
     return GetNamedLocalVariable(NULL, pILFrame, methodDef, localIndex, paramName, paramNameLen, ppValue);
 }
+
 HRESULT SymbolReader::ResolveSequencePoint(__in_z WCHAR* pFilename, ULONG32 lineNumber, mdMethodDef* pToken, ULONG32* pIlOffset)
 {
+#ifndef FEATURE_PAL
     HRESULT Status = S_OK;
     ULONG32 cDocs = 0;
     ULONG32 cDocsNeeded = 0;
@@ -6387,12 +6418,10 @@ HRESULT SymbolReader::ResolveSequencePoint(__in_z WCHAR* pFilename, ULONG32 line
         }
         return S_OK;
     }
+#endif // FEATURE_PAL
     return E_FAIL;
 }
 
-
-#endif
-
 WString GetFrameFromAddress(TADDR frameAddr, IXCLRDataStackWalk *pStackWalk)
 {
     TADDR vtAddr;
index 9e32e9d..5b0c40f 100644 (file)
@@ -2368,15 +2368,20 @@ private:
     volatile ULONG m_refCount;
 };
 
+#endif // !FEATURE_PAL
+
 class SymbolReader
 {
 private:
+#ifndef FEATURE_PAL
     ISymUnmanagedReader* m_pSymReader;
+#endif
 
 private:
     HRESULT GetNamedLocalVariable(ISymUnmanagedScope * pScope, ICorDebugILFrame * pILFrame, mdMethodDef methodToken, ULONG localIndex, __inout_ecount(paramNameLen) WCHAR* paramName, ULONG paramNameLen, ICorDebugValue** ppValue);
 
 public:
+#ifndef FEATURE_PAL
     SymbolReader() : m_pSymReader (NULL) {}
     ~SymbolReader()
     {
@@ -2386,6 +2391,10 @@ public:
             m_pSymReader = NULL;
         }
     }
+#else
+    SymbolReader() {}
+    ~SymbolReader() {}
+#endif
 
     HRESULT LoadSymbols(IMetaDataImport * pMD, ICorDebugModule * pModule);
     HRESULT LoadSymbols(IMetaDataImport * pMD, ULONG64 baseAddress, __in_z WCHAR* pModuleName, BOOL isInMemory);
@@ -2393,8 +2402,6 @@ public:
     HRESULT SymbolReader::ResolveSequencePoint(__in_z WCHAR* pFilename, ULONG32 lineNumber, mdMethodDef* pToken, ULONG32* pIlOffset);
 };
 
-#endif // !FEATURE_PAL
-
 HRESULT
 GetLineByOffset(
         __in  ULONG64 IP,
index 8b2f9c7..75d5cee 100644 (file)
@@ -15,6 +15,7 @@ DebugClient::DebugClient(lldb::SBDebugger &debugger, lldb::SBCommandReturnObject
     m_returnObject(returnObject),
     m_coreclrDirectory(coreclrDirectory)
 {
+    returnObject.SetStatus(lldb::eReturnStatusSuccessFinishResult);
 }
 
 DebugClient::~DebugClient()
@@ -153,12 +154,115 @@ DebugClient::GetExecutingProcessorType(
     return S_OK;
 }
 
+HRESULT 
+DebugClient::Execute(
+    ULONG outputControl,
+    PCSTR command,
+    ULONG flags)
+{
+    lldb::SBCommandInterpreter interpreter = m_debugger.GetCommandInterpreter();
+
+    lldb::SBCommandReturnObject result;
+    lldb::ReturnStatus status = interpreter.HandleCommand(command, result);
+
+    return status <= lldb::eReturnStatusSuccessContinuingResult ? S_OK : E_FAIL;
+}
+
+// PAL raise exception function and exception record pointer variable name
+// See coreclr\src\pal\src\exception\seh-unwind.cpp for the details.
+#define FUNCTION_NAME "RtlpRaiseException"
+#define VARIABLE_NAME "ExceptionRecord"
+
+HRESULT 
+DebugClient::GetLastEventInformation(
+    PULONG type,
+    PULONG processId,
+    PULONG threadId,
+    PVOID extraInformation,
+    ULONG extraInformationSize,
+    PULONG extraInformationUsed,
+    PSTR description,
+    ULONG descriptionSize,
+    PULONG descriptionUsed)
+{
+    if (extraInformationSize < sizeof(DEBUG_LAST_EVENT_INFO_EXCEPTION) || 
+        type == NULL || processId == NULL || threadId == NULL || extraInformationUsed == NULL) 
+    {
+        return E_FAIL;
+    }
+
+    *type = DEBUG_EVENT_EXCEPTION;
+    *processId = 0;
+    *threadId = 0;
+    *extraInformationUsed = sizeof(DEBUG_LAST_EVENT_INFO_EXCEPTION);
+
+    DEBUG_LAST_EVENT_INFO_EXCEPTION *pdle = (DEBUG_LAST_EVENT_INFO_EXCEPTION *)extraInformation;
+    pdle->FirstChance = 1; 
+
+    lldb::SBProcess process = GetCurrentProcess();
+    if (!process.IsValid())
+    {
+        return E_FAIL;
+    }
+    lldb::SBThread thread = process.GetSelectedThread();
+    if (!thread.IsValid())
+    {
+        return E_FAIL;
+    }
+
+    // Enumerate each stack frame at the special "throw"
+    // breakpoint and find the raise exception function 
+    // with the exception record parameter.
+    int numFrames = thread.GetNumFrames();
+    for (int i = 0; i < numFrames; i++)
+    {
+        lldb::SBFrame frame = thread.GetFrameAtIndex(i);
+        if (!frame.IsValid())
+        {
+            break;
+        }
+
+        const char *functionName = frame.GetFunctionName();
+        if (functionName == NULL || strncmp(functionName, FUNCTION_NAME, sizeof(FUNCTION_NAME) - 1) != 0)
+        {
+            continue;
+        }
+
+        lldb::SBValue exValue = frame.FindVariable(VARIABLE_NAME);
+        if (!exValue.IsValid())
+        {
+            break;
+        }
+
+        lldb::SBError error;
+        ULONG64 pExceptionRecord = exValue.GetValueAsUnsigned(error);
+        if (error.Fail())
+        {
+            break;
+        }
+
+        process.ReadMemory(pExceptionRecord, &pdle->ExceptionRecord, sizeof(pdle->ExceptionRecord), error);
+        if (error.Fail())
+        {
+            break;
+        }
+
+        return S_OK;
+    }
+
+    return E_FAIL;
+}
+
 // Internal output string function
 void
 DebugClient::OutputString(
     ULONG mask,
     PCSTR str)
 {
+    if (mask == DEBUG_OUTPUT_ERROR)
+    {
+        m_returnObject.SetStatus(lldb::eReturnStatusFailed);
+    }
     // Can not use AppendMessage or AppendWarning because they add a newline. SetError
     // can not be used for DEBUG_OUTPUT_ERROR mask because it caches the error strings
     // seperately from the normal output so error/normal texts are not intermixed 
@@ -203,11 +307,23 @@ DebugClient::WriteVirtual(
     ULONG bufferSize,
     PULONG bytesWritten)
 {
+    lldb::SBError error;
+    size_t written = 0;
+
+    lldb::SBProcess process = GetCurrentProcess();
+    if (!process.IsValid())
+    {
+        goto exit;
+    }
+
+    written = process.WriteMemory(offset, buffer, bufferSize, error);
+
+exit:
     if (bytesWritten)
     {
-        *bytesWritten = 0;
+        *bytesWritten = written;
     }
-    return E_NOTIMPL;
+    return error.Success() ? S_OK : E_FAIL;
 }
 
 //----------------------------------------------------------------------------
index d2a2201..3081189 100644 (file)
@@ -58,7 +58,23 @@ public:
         PULONG size);
 
     HRESULT GetExecutingProcessorType(
-        PULONG Type);
+        PULONG type);
+
+    HRESULT Execute(
+        ULONG outputControl,
+        PCSTR command,
+        ULONG flags);
+
+    HRESULT GetLastEventInformation(
+        PULONG type,
+        PULONG processId,
+        PULONG threadId,
+        PVOID extraInformation,
+        ULONG extraInformationSize,
+        PULONG extraInformationUsed,
+        PSTR description,
+        ULONG descriptionSize,
+        PULONG descriptionUsed);
 
     //----------------------------------------------------------------------------
     // IDebugDataSpaces
index 9871a3e..9890e13 100644 (file)
@@ -78,9 +78,38 @@ public:
     // current processor context.
     virtual HRESULT GetExecutingProcessorType(
         PULONG type) = 0;
+
+    // Executes the given command string.
+    // If the string has multiple commands
+    // Execute will not return until all
+    // of them have been executed.  If this
+    // requires waiting for the debuggee to
+    // execute an internal wait will be done
+    // so Execute can take an arbitrary amount
+    // of time.
+    virtual HRESULT Execute(
+        ULONG outputControl,
+        PCSTR command,
+        ULONG flags) = 0;
+
+    // Retrieves information about the last event that occurred.
+    // EventType is one of the event callback mask bits.
+    // ExtraInformation contains additional event-specific
+    // information.  Not all events have additional information.
+    virtual HRESULT GetLastEventInformation(
+        PULONG type,
+        PULONG processId,
+        PULONG threadId,
+        PVOID extraInformation,
+        ULONG extraInformationSize,
+        PULONG extraInformationUsed,
+        PSTR description,
+        ULONG descriptionSize,
+        PULONG descriptionUsed) = 0;
 };
 
 typedef class IDebugControl2* PDEBUG_CONTROL2;
+
 // Output mask bits.
 // Normal output.
 #define DEBUG_OUTPUT_NORMAL            0x00000001
@@ -103,6 +132,26 @@ typedef class IDebugControl2* PDEBUG_CONTROL2;
 // Symbol messages, such as for !sym noisy.
 #define DEBUG_OUTPUT_SYMBOLS           0x00000200
 
+// Execute and ExecuteCommandFile flags.
+// These flags only apply to the command
+// text itself; output from the executed
+// command is controlled by the output
+// control parameter.
+// Default execution.  Command is logged
+// but not output.
+#define DEBUG_EXECUTE_DEFAULT    0x00000000
+// Echo commands during execution.  In
+// ExecuteCommandFile also echoes the prompt
+// for each line of the file.
+#define DEBUG_EXECUTE_ECHO       0x00000001
+// Do not log or output commands during execution.
+// Overridden by DEBUG_EXECUTE_ECHO.
+#define DEBUG_EXECUTE_NOT_LOGGED 0x00000002
+// If this flag is not set an empty string
+// to Execute will repeat the last Execute
+// string.
+#define DEBUG_EXECUTE_NO_REPEAT  0x00000004
+
 // Classes of debuggee.  Each class
 // has different qualifiers for specific
 // kinds of debuggees.
@@ -114,6 +163,57 @@ typedef class IDebugControl2* PDEBUG_CONTROL2;
 #define IMAGE_FILE_MACHINE_I386              0x014c  // Intel 386.
 #define IMAGE_FILE_MACHINE_AMD64             0x8664  // AMD64 (K8)
 
+// Execution status codes used for waiting,
+// for returning current status and for
+// event method return values.
+#define DEBUG_STATUS_NO_CHANGE           0
+#define DEBUG_STATUS_GO                  1
+#define DEBUG_STATUS_GO_HANDLED          2
+#define DEBUG_STATUS_GO_NOT_HANDLED      3
+#define DEBUG_STATUS_STEP_OVER           4
+#define DEBUG_STATUS_STEP_INTO           5
+#define DEBUG_STATUS_BREAK               6
+#define DEBUG_STATUS_NO_DEBUGGEE         7
+#define DEBUG_STATUS_STEP_BRANCH         8
+#define DEBUG_STATUS_IGNORE_EVENT        9
+#define DEBUG_STATUS_RESTART_REQUESTED   10
+#define DEBUG_STATUS_REVERSE_GO          11
+#define DEBUG_STATUS_REVERSE_STEP_BRANCH 12
+#define DEBUG_STATUS_REVERSE_STEP_OVER   13
+#define DEBUG_STATUS_REVERSE_STEP_INTO   14
+#define DEBUG_STATUS_OUT_OF_SYNC         15
+#define DEBUG_STATUS_WAIT_INPUT          16
+#define DEBUG_STATUS_TIMEOUT             17
+
+#define DEBUG_STATUS_MASK                0x1f
+
+#define DEBUG_EVENT_EXCEPTION            0x00000002
+
+#ifdef DEFINE_EXCEPTION_RECORD
+
+#define EXCEPTION_MAXIMUM_PARAMETERS     15
+
+// This copy of the "64" bit record has been modified
+// by removing the alignment field to make it the same
+// as the _EXCEPTION_RECORD used in the pal defined in 
+// pal.h.
+typedef struct _EXCEPTION_RECORD64 {
+    DWORD ExceptionCode;
+    DWORD ExceptionFlags;
+    DWORD64 ExceptionRecord;
+    DWORD64 ExceptionAddress;
+    DWORD NumberParameters;
+    DWORD64 ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS];
+} EXCEPTION_RECORD64, *PEXCEPTION_RECORD64;
+
+#endif // DEFINE_EXCEPTION_RECORD
+
+typedef struct _DEBUG_LAST_EVENT_INFO_EXCEPTION
+{
+    EXCEPTION_RECORD64 ExceptionRecord;
+    ULONG FirstChance;
+} DEBUG_LAST_EVENT_INFO_EXCEPTION, *PDEBUG_LAST_EVENT_INFO_EXCEPTION;
+
 //----------------------------------------------------------------------------
 // IDebugDataSpaces
 //----------------------------------------------------------------------------
index b321321..be0ef9b 100644 (file)
@@ -5,6 +5,7 @@
 
 #include "sosplugin.h"
 #include <dlfcn.h>
+#include <string.h>
 #include <string>
 
 class sosCommand : public lldb::SBCommandPluginInterface
@@ -72,10 +73,8 @@ public:
             }
             else 
             {
-                std::string directoryString;
-                directoryString.append(directory);
-                directoryString.append("/");
-                directoryString.copy(m_coreclrDirectory, MAX_PATH, 0);
+                strcpy(m_coreclrDirectory, directory);
+                strcat(m_coreclrDirectory, "/");
 
                 // Load the DAC module first explicitly because SOS and DBI
                 // have implicit references to the DAC's PAL.
index e031660..412955c 100644 (file)
@@ -5,6 +5,7 @@
 
 #include <lldb/API/LLDB.h>
 #include "mstypes.h"
+#define DEFINE_EXCEPTION_RECORD
 #include <dbgeng.h>
 #include "debugclient.h"
 
index be6018f..81a99d6 100644 (file)
@@ -22,6 +22,7 @@ ForkAndExecProcess
 FormatMessageW
 FreeEnvironmentStringsW
 GetACP
+GetCLRRuntimeHost
 GetConsoleCP
 GetConsoleOutputCP
 GetCurrentDirectoryW
@@ -52,6 +53,7 @@ MultiByteToWideChar
 OpenEventW
 OpenMutexW
 OpenSemaphoreW
+PAL_InitializeCoreCLR 
 PAL_Random
 PAL_RegisterModule
 PAL_UnregisterModule
index 808b3bb..9af7814 100644 (file)
@@ -86,7 +86,7 @@
 #define PORTABILITY_ASSERT(message)     _ASSERTE(false && message)
 #endif
 
-
+#define DIRECTORY_SEPARATOR_CHAR_A '\\'
 #define DIRECTORY_SEPARATOR_CHAR_W W('\\')
 #define DIRECTORY_SEPARATOR_STR_W W("\\")
 
index 731c9a9..0468d17 100644 (file)
@@ -1354,10 +1354,12 @@ typedef VOID (__stdcall *WAITORTIMERCALLBACK)(PVOID, BOOLEAN);
 #define _ReturnAddress() __builtin_return_address(0)
 
 #ifdef PLATFORM_UNIX
+#define DIRECTORY_SEPARATOR_CHAR_A '/'
 #define DIRECTORY_SEPARATOR_CHAR_W W('/')
 #define DIRECTORY_SEPARATOR_STR_W W("/")
 #define PATH_SEPARATOR_CHAR_W W(':')
 #else // PLATFORM_UNIX
+#define DIRECTORY_SEPARATOR_CHAR_A '\\'
 #define DIRECTORY_SEPARATOR_CHAR_W W('\\')
 #define DIRECTORY_SEPARATOR_STR_W W("\\")
 #define PATH_SEPARATOR_CHAR_W W(';')
index a6435a4..2e77814 100644 (file)
@@ -195,6 +195,18 @@ BOOL PAL_VirtualUnwind(CONTEXT *context, KNONVOLATILE_CONTEXT_POINTERS *contextP
 #error don't know how to unwind on this platform
 #endif
 
+/*++
+Function:
+    RtlpRaiseException
+
+Parameters:
+    ExceptionRecord - the Windows exception record to throw
+
+Note:
+    The name of this function and the name of the ExceptionRecord 
+    parameter is used in the sos lldb plugin code to read the exception
+    record. See coreclr\src\ToolBox\SOS\lldbplugin\debugclient.cpp.
+--*/
 PAL_NORETURN
 static void RtlpRaiseException(EXCEPTION_RECORD *ExceptionRecord)
 {
index e6eff9b..4055635 100644 (file)
@@ -1423,6 +1423,7 @@ HRESULT EEStartup(COINITIEE fFlags)
 
 #if defined(FEATURE_PAL) && !defined(CROSSGEN_COMPILE)
     DacGlobals::Initialize();
+    InitializeJITNotificationTable();
 #endif
 
     PAL_TRY(COINITIEE *, pfFlags, &fFlags)
index b6f3adb..0b4fb0a 100644 (file)
@@ -1081,6 +1081,16 @@ struct JITNotification
 GPTR_DECL(JITNotification,g_pNotificationTable);
 GVAL_DECL(ULONG32, g_dacNotificationFlags);
 
+#if defined(FEATURE_PAL) && !defined(DACCESS_COMPILE)
+
+inline void
+InitializeJITNotificationTable()
+{
+    g_pNotificationTable = new (nothrow) JITNotification[1001];
+}
+
+#endif // FEATURE_PAL && !DACCESS_COMPILE
+
 class JITNotifications
 {
 public: