Create a version resilient interface between sos (libsos.so) and the lldb plugin
authorMike McLaughlin <mikem@microsoft.com>
Sat, 20 Feb 2016 08:27:33 +0000 (00:27 -0800)
committerMike McLaughlin <mikem@microsoft.com>
Thu, 25 Feb 2016 23:54:25 +0000 (15:54 -0800)
(libsosplugin.so). There is a ILLDBServices interface between the two with a proper
QI/Addref/Release interface so we can add new interfaces later and still be backwards
and forward compatible. Internally in sos there is a DebugClient wrapper around this
interface that makes it look like all the individual dbgeng interfaces (IDebugControl4,
IDebugSymbols, IDebugDataSpaces, etc) even with QI, etc.

Enable the sos the u (clru), DumpStack (dumpstack), EEStack (eestack), DumpIL (dumpil), DumpSig and
DumpSigElem commands (aliases in parans).

Add the clrstack -f option that displays the intermixed native and managed frames
when managed assembly and offsets.

Implement GetContextFromFrame. Enable the _EFN_* exported functions.

Add source file/line number support (native only) via GetLineByOffset.

Fix bug when executed just "sos". Displays help now.

Disable the U -gcinfo option since it isn't implemented on xplat because it uses Windows fibers.

Fixed a problem where some HelperMethodFrames were not unwinding; clrstack would stop without displaying
managed functions on the stack. The HelperMethodFrames were not sometimes unwinding because the lldb
VirtualUnwind used by the DAC was using (via the data target) to do the out of context unwind has some
limitations.  lldb doesn't have a way to unwind an arbitrary register context so the VirtualUnwind
implementation searches through the thread's frames until it finds a match and returns the next one. The
match was an exact match and in some cases it didn't find a frame. Changed it to check if the incoming
context's SP is in between frames and return the next one if so.

Only add the special internal "corerun" lldb plugin command in debug builds.

Commit migrated from https://github.com/dotnet/coreclr/commit/266ee6dc6d688ec973acfee2e30d61877cd288be

25 files changed:
src/coreclr/src/ToolBox/SOS/Strike/CMakeLists.txt
src/coreclr/src/ToolBox/SOS/Strike/datatarget.cpp
src/coreclr/src/ToolBox/SOS/Strike/disasm.cpp
src/coreclr/src/ToolBox/SOS/Strike/disasm.h
src/coreclr/src/ToolBox/SOS/Strike/disasmX86.cpp
src/coreclr/src/ToolBox/SOS/Strike/exts.cpp
src/coreclr/src/ToolBox/SOS/Strike/exts.h
src/coreclr/src/ToolBox/SOS/Strike/inc/dbgeng.h [new file with mode: 0644]
src/coreclr/src/ToolBox/SOS/Strike/inc/dbghelp.h [moved from src/coreclr/src/ToolBox/SOS/lldbplugin/inc/dbghelp.h with 54% similarity]
src/coreclr/src/ToolBox/SOS/Strike/inc/wdbgexts.h [moved from src/coreclr/src/ToolBox/SOS/lldbplugin/inc/wdbgexts.h with 100% similarity]
src/coreclr/src/ToolBox/SOS/Strike/platformspecific.h
src/coreclr/src/ToolBox/SOS/Strike/sos_stacktrace.h
src/coreclr/src/ToolBox/SOS/Strike/sosdocs.txt
src/coreclr/src/ToolBox/SOS/Strike/sosdocsunix.txt
src/coreclr/src/ToolBox/SOS/Strike/strike.cpp
src/coreclr/src/ToolBox/SOS/Strike/util.cpp
src/coreclr/src/ToolBox/SOS/Strike/util.h
src/coreclr/src/ToolBox/SOS/lldbplugin/CMakeLists.txt
src/coreclr/src/ToolBox/SOS/lldbplugin/inc/lldbservices.h [moved from src/coreclr/src/ToolBox/SOS/lldbplugin/inc/dbgeng.h with 70% similarity]
src/coreclr/src/ToolBox/SOS/lldbplugin/mstypes.h
src/coreclr/src/ToolBox/SOS/lldbplugin/services.cpp [moved from src/coreclr/src/ToolBox/SOS/lldbplugin/debugclient.cpp with 73% similarity]
src/coreclr/src/ToolBox/SOS/lldbplugin/services.h [moved from src/coreclr/src/ToolBox/SOS/lldbplugin/debugclient.h with 73% similarity]
src/coreclr/src/ToolBox/SOS/lldbplugin/soscommand.cpp
src/coreclr/src/ToolBox/SOS/lldbplugin/sosplugin.cpp
src/coreclr/src/ToolBox/SOS/lldbplugin/sosplugin.h

index 76c47e4..d151a83 100644 (file)
@@ -32,7 +32,6 @@ include_directories(${CLR_DIR}/src/gcdump)
 include_directories(${CLR_DIR}/src/debug/shim)
 
 if(WIN32)
-  include_directories("inc")
   include_directories("$ENV{VSInstallDir}/DIA SDK/include")
 
   add_definitions(-DUSE_STL)
@@ -89,6 +88,7 @@ else(WIN32)
   add_compile_options(-Wno-null-arithmetic)
   add_compile_options(-Wno-format)
 
+  include_directories(BEFORE inc)
   include_directories(BEFORE ../lldbplugin/inc)
 
   add_compile_options(-fPIC)
index d7b036d..869ae67 100644 (file)
@@ -200,9 +200,9 @@ DataTarget::VirtualUnwind(
     /* [in] */ ULONG32 contextSize,
     /* [in, out, size_is(contextSize)] */ PBYTE context)
 {
-    if (g_ExtClient == NULL)
+    if (g_ExtServices == NULL)
     {
         return E_UNEXPECTED;
     }
-    return g_ExtClient->VirtualUnwind(threadId, contextSize, context);
+    return g_ExtServices->VirtualUnwind(threadId, contextSize, context);
 }
index c74391e..701c6be 100644 (file)
@@ -69,19 +69,17 @@ namespace X86GCDump
 #define ERANGE 34
 #endif
 
-#ifndef FEATURE_PAL
-
 PVOID
 GenOpenMapping(
     PCSTR FilePath,
     PULONG Size
     )
 {
+#ifndef FEATURE_PAL
     HANDLE hFile;
     HANDLE hMappedFile;
     PVOID MappedFile;
 
-
     hFile = CreateFileA(
                 FilePath,
                 GENERIC_READ,
@@ -132,7 +130,7 @@ GenOpenMapping(
     *Size = GetFileSize(hFile, NULL);
     if (*Size == ULONG_MAX) {
         CloseHandle( hFile );
-        return FALSE;
+        return NULL;
     }
     
     hMappedFile = CreateFileMapping (
@@ -146,7 +144,7 @@ GenOpenMapping(
 
     if ( !hMappedFile ) {
         CloseHandle ( hFile );
-        return FALSE;
+        return NULL;
     }
 
     MappedFile = MapViewOfFile (
@@ -161,6 +159,9 @@ GenOpenMapping(
     CloseHandle (hFile);
 
     return MappedFile;
+#else // FEATURE_PAL
+    return NULL;
+#endif // FEATURE_PAL
 }
 
 char* PrintOneLine (__in_z char *begin, __in_z char *limit)
@@ -208,7 +209,7 @@ void UnassemblyUnmanaged(DWORD_PTR IP, BOOL bSuppressLines)
 {
     char            filename[MAX_PATH_FNAME+1];
     char            line[256];
-    int             lcount          = 10;
+    int             lcount = 10;
 
     ULONG linenum = 0;
     ULONG64 Displacement = 0;
@@ -218,18 +219,19 @@ void UnassemblyUnmanaged(DWORD_PTR IP, BOOL bSuppressLines)
     if (!bSuppressLines)
     {
         ReloadSymbolWithLineInfo();
-        fLineAvailable = SUCCEEDED (g_ExtSymbols->GetLineByOffset (TO_CDADDR(IP), &linenum,
-                                                                    filename,
-                                                                    MAX_PATH_FNAME+1,
-                                                                    NULL,
-                                                                    &Displacement));
+        fLineAvailable = SUCCEEDED (g_ExtSymbols->GetLineByOffset(TO_CDADDR(IP), 
+                                                                  &linenum,
+                                                                  filename,
+                                                                  MAX_PATH_FNAME+1,
+                                                                  NULL,
+                                                                  &Displacement));
     }
     ULONG FileLines = 0;
     ArrayHolder<ULONG64> Buffer = NULL;
 
     if (fLineAvailable)
     {
-        g_ExtSymbols->GetSourceFileLineOffsets (filename, NULL, 0, &FileLines);
+        g_ExtSymbols->GetSourceFileLineOffsets(filename, NULL, 0, &FileLines);
         if (FileLines == 0xFFFFFFFF || FileLines == 0)
             fLineAvailable = FALSE;
     }
@@ -255,7 +257,7 @@ void UnassemblyUnmanaged(DWORD_PTR IP, BOOL bSuppressLines)
         return;
     }
 
-    g_ExtSymbols->GetSourceFileLineOffsets (filename, Buffer, FileLines, NULL);
+    g_ExtSymbols->GetSourceFileLineOffsets(filename, Buffer, FileLines, NULL);
     
     int beginLine = 0;
     int endLine = 0;
@@ -265,7 +267,7 @@ void UnassemblyUnmanaged(DWORD_PTR IP, BOOL bSuppressLines)
         if (IsInterrupt())
             return;
         if (Buffer[lastLine] != DEBUG_INVALID_OFFSET) {
-            g_ExtSymbols->GetNameByOffset(Buffer[lastLine],NULL,0,NULL,&Displacement);
+            g_ExtSymbols->GetNameByOffset(Buffer[lastLine], NULL, 0, NULL, &Displacement);
             if (Displacement == 0) {
                 beginLine = lastLine;
                 break;
@@ -299,7 +301,7 @@ void UnassemblyUnmanaged(DWORD_PTR IP, BOOL bSuppressLines)
         if (IsInterrupt())
             return;
         if (Buffer[lastLine] != DEBUG_INVALID_OFFSET) {
-            g_ExtSymbols->GetNameByOffset(Buffer[lastLine],NULL,0,NULL,&Displacement);
+            g_ExtSymbols->GetNameByOffset(Buffer[lastLine], NULL, 0, NULL, &Displacement);
             if (Displacement == 0) {
                 endLine = lastLine;
                 break;
@@ -348,16 +350,19 @@ void UnassemblyUnmanaged(DWORD_PTR IP, BOOL bSuppressLines)
 #define MAX_SOURCE_PATH 1024
     char Found[MAX_SOURCE_PATH];
     char *pFile;
-    if (g_ExtSymbols->FindSourceFile(0, filename,
-                       DEBUG_FIND_SOURCE_BEST_MATCH |
-                       DEBUG_FIND_SOURCE_FULL_PATH,
-                       NULL, Found, sizeof(Found), NULL) != S_OK)
+    if (g_ExtSymbols->FindSourceFile(0,
+                                     filename, 
+                                     DEBUG_FIND_SOURCE_BEST_MATCH | DEBUG_FIND_SOURCE_FULL_PATH, 
+                                     NULL,
+                                     Found, 
+                                     sizeof(Found), 
+                                     NULL) != S_OK)
     {
         pFile = filename;
     }
     else
     {
-        MappedBase = GenOpenMapping ( Found, &MappedSize );
+        MappedBase = GenOpenMapping(Found, &MappedSize);
         pFile = Found;
     }
     
@@ -382,8 +387,8 @@ void UnassemblyUnmanaged(DWORD_PTR IP, BOOL bSuppressLines)
         if (IsInterrupt())
             return;
         if (MappedBase) {
-            ExtOut ("%4d ", lastLine+1);
-            pFileCh = PrintOneLine (pFileCh, (char*)MappedBase+MappedSize);
+            ExtOut("%4d ", lastLine+1);
+            pFileCh = PrintOneLine(pFileCh, (char*)MappedBase+MappedSize);
         }
         if (Buffer[lastLine] != DEBUG_INVALID_OFFSET) {
             if (MappedBase == 0) {
@@ -404,14 +409,14 @@ void UnassemblyUnmanaged(DWORD_PTR IP, BOOL bSuppressLines)
             while (1) {
                 if (IsInterrupt())
                     return;
-                g_ExtControl->Disassemble (vIP, 0, line, 256, NULL, &vIP);
+                g_ExtControl->Disassemble(vIP, 0, line, 256, NULL, &vIP);
                 ExtOut (line);
                 if (vIP > vNextLineIP || vNextLineIP - vIP > 40) {
-                    if (FAILED (g_ExtSymbols->GetLineByOffset (vIP, &linenum,
-                                                               filename1,
-                                                               MAX_PATH_FNAME+1,
-                                                               NULL,
-                                                               &Displacement))) {
+                    if (FAILED (g_ExtSymbols->GetLineByOffset(vIP, &linenum,
+                                                              filename1,
+                                                              MAX_PATH_FNAME+1,
+                                                              NULL,
+                                                              &Displacement))) {
                         if (lastLine != endOfFunc) {
                             break;
                         }
@@ -430,7 +435,6 @@ void UnassemblyUnmanaged(DWORD_PTR IP, BOOL bSuppressLines)
             }
         }
     }
-        
 }
 
 void DisasmAndClean (DWORD_PTR &IP, __out_ecount_opt(length) char *line, ULONG length)
@@ -444,9 +448,6 @@ void DisasmAndClean (DWORD_PTR &IP, __out_ecount_opt(length) char *line, ULONG l
         ptr[0] = '\0';
 }
 
-#endif // FEATURE_PAL
-
-
 // If byref, move to pass the byref prefix
 BOOL IsByRef (__deref_inout_z char *& ptr)
 {
@@ -838,12 +839,40 @@ void SOSEHInfo::FormatForDisassembly(CLRDATA_ADDRESS offSet)
 // use the IS_DBG_TARGET_XYZ macro.
 //
 
-#ifndef FEATURE_PAL
+void PrintNativeStack(DWORD_PTR ip, BOOL bSuppressLines)
+{
+    char filename[MAX_PATH_FNAME + 1];
+    char symbol[1024];
+    ULONG64 displacement;
+
+    HRESULT hr = g_ExtSymbols->GetNameByOffset(TO_CDADDR(ip), symbol, _countof(symbol), NULL, &displacement);
+    if (SUCCEEDED(hr) && symbol[0] != '\0')
+    {
+        ExtOut("%s", symbol);
+
+        if (displacement)
+        {
+            ExtOut(" + %#x", displacement);
+        }
+
+        if (!bSuppressLines)
+        {
+            ULONG line;
+            hr = g_ExtSymbols->GetLineByOffset(TO_CDADDR(ip), &line, filename, _countof(filename), NULL, NULL);
+            if (SUCCEEDED(hr))
+            {
+                ExtOut(" [%s:%d]", filename, line);
+            }
+        }
+    }
+    else
+    {
+        DMLOut(DMLIP(ip));
+    }
+}
 
 // Return TRUE if we have printed something.
-BOOL PrintCallInfo (DWORD_PTR vEBP, DWORD_PTR IP,
-                    DumpStackFlag& DSFlag,
-                    BOOL bSymbolOnly)
+BOOL PrintCallInfo(DWORD_PTR vEBP, DWORD_PTR IP, DumpStackFlag& DSFlag, BOOL bSymbolOnly)
 {
     char Symbol[1024];
     char filename[MAX_PATH_FNAME+1];
@@ -873,7 +902,7 @@ BOOL PrintCallInfo (DWORD_PTR vEBP, DWORD_PTR IP,
             methodDesc = (DWORD_PTR) codeHeaderData.MethodDescPtr;
             Displacement = IP - IPBegin;        
             if (IP >= IPBegin && Displacement <= codeHeaderData.MethodSize)
-                ExtOut ("+%#x ", Displacement);    
+                ExtOut ("+ %#x ", Displacement);    
         }            
         if (NameForMD_s(methodDesc, g_mdName, mdNameLen))
         {
@@ -913,29 +942,9 @@ BOOL PrintCallInfo (DWORD_PTR vEBP, DWORD_PTR IP,
                 }
             }
 #endif // _TARGET_AMD64_
-            if (methodDesc == 0) {
-                HRESULT hr;
-                hr = g_ExtSymbols->GetNameByOffset(TO_CDADDR(IP), Symbol, 1024, NULL, &Displacement);
-                if (SUCCEEDED(hr) && Symbol[0] != '\0')
-                {
-                    ExtOut ("%s", Symbol);
-                    if (Displacement)
-                        ExtOut ("+%#x", Displacement);
-#ifndef FEATURE_PAL
-                    if (!DSFlag.fSuppressSrcInfo)
-                    {
-                        ULONG line;
-                        hr = g_ExtSymbols->GetLineByOffset (TO_CDADDR(IP), &line, filename,
-                            MAX_PATH_FNAME+1, NULL, NULL);
-                        if (SUCCEEDED (hr))
-                            ExtOut (" [%s:%d]", filename, line);
-                    }
-#endif
-                }
-                else
-                {
-                    DMLOut(DMLIP(IP));
-                }
+            if (methodDesc == 0) 
+            {
+                PrintNativeStack(IP, DSFlag.fSuppressSrcInfo);
             }
             else if (g_bDacBroken)
             {
@@ -1034,8 +1043,6 @@ void DumpStackWorker (DumpStackFlag &DSFlag)
     }
 }
 
-#endif // FEATURE_PAL
-
 #ifdef SOS_TARGET_X86
 ///
 /// X86Machine implementation
index 7d4745c..d3c13fe 100644 (file)
@@ -69,16 +69,14 @@ struct SOSEHInfo
 
 BOOL IsClonedFinally(DACEHInfo *pEHInfo);
 
-#ifndef FEATURE_PAL
-
 void DumpStackWorker (DumpStackFlag &DSFlag);
 
 void UnassemblyUnmanaged (DWORD_PTR IP, BOOL bSuppressLines);
 
-BOOL GetCalleeSite (DWORD_PTR IP, DWORD_PTR &IPCallee);
-
 HRESULT CheckEEDll ();
 
+BOOL GetCalleeSite (DWORD_PTR IP, DWORD_PTR &IPCallee);
+
 void DisasmAndClean (DWORD_PTR &IP, __out_ecount_opt(length) char *line, ULONG length);
 
 INT_PTR GetValueFromExpr(___in __in_z char *ptr, INT_PTR &value);
@@ -92,12 +90,11 @@ BOOL IsTermSep (char ch);
 const char * HelperFuncName (size_t IP);
 
 enum eTargetType { ettUnk = 0, ettNative = 1, ettJitHelp = 2, ettStub = 3, ettMD = 4 };
+
 // GetFinalTarget is based on HandleCall, but avoids printing anything to the output.
 // This is currently only called on x64
 eTargetType GetFinalTarget(DWORD_PTR callee, DWORD_PTR* finalMDorIP);
 
-#endif // FEATURE_PAL
-
 #ifdef _MSC_VER
 // SOS is essentially single-threaded. ignore "construction of local static object is not thread-safe"
 #pragma warning(push)
@@ -258,7 +255,7 @@ public:
 
     ULONG GetPlatform()             const { return IMAGE_FILE_MACHINE_AMD64; }
     ULONG GetContextSize()          const { return sizeof(AMD64_CONTEXT); }
-#ifndef FEATURE_PAL
+
     virtual void Unassembly(
                 TADDR IPBegin, 
                 TADDR IPEnd, 
@@ -268,10 +265,11 @@ public:
                 SOSEHInfo *pEHInfo,
                 BOOL bSuppressLines,
                 BOOL bDisplayOffsets) const;
-#endif
+
     virtual void IsReturnAddress(
                 TADDR retAddr, 
                 TADDR* whereCalled) const;
+
     virtual BOOL GetExceptionContext (
                 TADDR stack, 
                 TADDR PC, 
@@ -279,6 +277,7 @@ public:
                 CROSS_PLATFORM_CONTEXT * cxr,
                 TADDR *exrAddr, 
                 PEXCEPTION_RECORD exr) const;
+
     // retrieve stack pointer, frame pointer, and instruction pointer from the target context
     virtual TADDR GetSP(const CROSS_PLATFORM_CONTEXT & ctx) const  { return ctx.Amd64Context.Rsp; }
     virtual TADDR GetBP(const CROSS_PLATFORM_CONTEXT & ctx) const  { return ctx.Amd64Context.Rbp; }
index 0c263f6..4dd18aa 100644 (file)
@@ -167,8 +167,6 @@ inline RegIndex FindReg (___in __in_z char *ptr, __out_opt int *plen = NULL, __o
     return NONE;
 }
 
-#ifndef FEATURE_PAL
-
 // Find the value of an expression.
 inline BOOL FindSrc (__in_z char *ptr, ___in Register *reg, INT_PTR &value, BOOL &bDigit)
 {
@@ -203,7 +201,6 @@ inline BOOL FindSrc (__in_z char *ptr, ___in Register *reg, INT_PTR &value, BOOL
     return bValid;
 }
 
-
 enum ADDRESSMODE {REG, DATA, INDIRECT, NODATA, BAD};
 
 struct RegState
@@ -754,9 +751,6 @@ void
     }
 }
 
-#endif // FEATURE_PAL
-
-
 // Find the real callee site.  Handle JMP instruction.
 // Return TRUE if we get the address, FALSE if not.
 BOOL GetCalleeSite (TADDR IP, TADDR &IPCallee)
@@ -809,8 +803,6 @@ BOOL GetCalleeSite (TADDR IP, TADDR &IPCallee)
     }
 }
 
-#ifndef FEATURE_PAL
-
 // GetFinalTarget is based on HandleCall, but avoids printing anything to the output.
 // This is currently only called on x64
 eTargetType GetFinalTarget(TADDR callee, TADDR* finalMDorIP)
@@ -866,6 +858,7 @@ eTargetType GetFinalTarget(TADDR callee, TADDR* finalMDorIP)
     return ettNative;
 }
 
+#ifndef FEATURE_PAL
 
 void ExpFuncStateInit (TADDR *IPRetAddr)
 {
@@ -909,10 +902,11 @@ void ExpFuncStateInit (TADDR *IPRetAddr)
 
 #endif // FEATURE_PAL
 
+
 /**********************************************************************\
 * Routine Description:                                                 *
 *                                                                      *
-*    This function is called to fill in a crsoo platform context       *
+*    This function is called to fill in a cross platform context       *
 *    struct by looking on the stack for return addresses into          *
 *    KiUserExceptionDispatcher                                         *
 *                                                                      *
@@ -1014,7 +1008,6 @@ BOOL
 #endif
     return TRUE;
 #else
-    ExtErr("AMD64Machine::GetExceptionContext not implemented\n");
     return FALSE;
 #endif // FEATURE_PAL
 }
index 029ed0a..5084d0a 100644 (file)
@@ -32,47 +32,62 @@ ULONG   TargetMachine;
 BOOL    Connected;
 ULONG   g_TargetClass;
 DWORD_PTR g_filterHint = 0;
-IMachine* g_targetMachine = NULL;
-BOOL    g_bDacBroken = FALSE;
 
 PDEBUG_CLIENT         g_ExtClient;    
+PDEBUG_DATA_SPACES2   g_ExtData2;
+PDEBUG_SYMBOLS2       g_ExtSymbols2;
+PDEBUG_ADVANCED3      g_ExtAdvanced3;
+PDEBUG_CLIENT         g_pCallbacksClient;
+
+#else
+
+DebugClient*          g_DebugClient;
+ILLDBServices*        g_ExtServices;    
+
+#endif // FEATURE_PAL
+
+IMachine* g_targetMachine = NULL;
+BOOL      g_bDacBroken = FALSE;
+
 PDEBUG_CONTROL2       g_ExtControl;
 PDEBUG_DATA_SPACES    g_ExtData;
-PDEBUG_DATA_SPACES2   g_ExtData2;
 PDEBUG_REGISTERS      g_ExtRegisters;
 PDEBUG_SYMBOLS        g_ExtSymbols;
-PDEBUG_SYMBOLS2       g_ExtSymbols2;
 PDEBUG_SYSTEM_OBJECTS g_ExtSystem;
-PDEBUG_ADVANCED3      g_ExtAdvanced3;
-
-PDEBUG_CLIENT         g_pCallbacksClient;
 
 #define SOS_ExtQueryFailGo(var, riid)                       \
     var = NULL;                                             \
-    if ((Status = Client->QueryInterface(__uuidof(riid),    \
+    if ((Status = client->QueryInterface(__uuidof(riid),    \
                                  (void **)&var)) != S_OK)   \
     {                                                       \
         goto Fail;                                          \
     }
 
 // Queries for all debugger interfaces.
+#ifndef FEATURE_PAL    
 extern "C" HRESULT
-ExtQuery(PDEBUG_CLIENT Client)
+ExtQuery(PDEBUG_CLIENT client)
 {
+    g_ExtClient = client;
+#else
+extern "C" HRESULT
+ExtQuery(ILLDBServices* services)
+{
+    g_ExtServices = services;
+    DebugClient* client = new DebugClient(services);
+    g_DebugClient = client;
+#endif
     HRESULT Status;
-    
     SOS_ExtQueryFailGo(g_ExtControl, IDebugControl2);
     SOS_ExtQueryFailGo(g_ExtData, IDebugDataSpaces);
-    SOS_ExtQueryFailGo(g_ExtData2, IDebugDataSpaces2);
     SOS_ExtQueryFailGo(g_ExtRegisters, IDebugRegisters);
     SOS_ExtQueryFailGo(g_ExtSymbols, IDebugSymbols);
-    SOS_ExtQueryFailGo(g_ExtSymbols2, IDebugSymbols2);
     SOS_ExtQueryFailGo(g_ExtSystem, IDebugSystemObjects);
+#ifndef FEATURE_PAL
+    SOS_ExtQueryFailGo(g_ExtData2, IDebugDataSpaces2);
+    SOS_ExtQueryFailGo(g_ExtSymbols2, IDebugSymbols2);
     SOS_ExtQueryFailGo(g_ExtAdvanced3, IDebugAdvanced3);
-    g_ExtClient = Client;
-
-    
-
+#endif // FEATURE_PAL
     return S_OK;
 
  Fail:
@@ -83,8 +98,6 @@ ExtQuery(PDEBUG_CLIENT Client)
     return Status;
 }
 
-#endif // FEATURE_PAL
-
 extern "C" HRESULT
 ArchQuery(void)
 {
@@ -129,23 +142,28 @@ ArchQuery(void)
     return S_OK;
 }
 
-#ifndef FEATURE_PAL
-
 // Cleans up all debugger interfaces.
 void
 ExtRelease(void)
 {
-    g_ExtClient = NULL;
     EXT_RELEASE(g_ExtControl);
     EXT_RELEASE(g_ExtData);
-    EXT_RELEASE(g_ExtData2);
     EXT_RELEASE(g_ExtRegisters);
     EXT_RELEASE(g_ExtSymbols);
-    EXT_RELEASE(g_ExtSymbols2);
     EXT_RELEASE(g_ExtSystem);
+#ifndef FEATURE_PAL
+    EXT_RELEASE(g_ExtData2);
+    EXT_RELEASE(g_ExtSymbols2);
     EXT_RELEASE(g_ExtAdvanced3);
+    g_ExtClient = NULL;
+#else 
+    EXT_RELEASE(g_DebugClient);
+    g_ExtServices = NULL;
+#endif // FEATURE_PAL
 }
 
+#ifndef FEATURE_PAL
+
 BOOL IsMiniDumpFileNODAC();
 extern HMODULE g_hInstance;
 
@@ -358,37 +376,48 @@ BOOL WINAPI DllMain(HANDLE hInstance, DWORD dwReason, LPVOID lpReserved)
 
 #else // FEATURE_PAL
 
-BOOL g_bDacBroken = FALSE;
-IMachine* g_targetMachine = NULL;
-
-PDEBUG_CLIENT         g_ExtClient;    
-PDEBUG_DATA_SPACES    g_ExtData;
-PDEBUG_CONTROL2       g_ExtControl;
-PDEBUG_SYMBOLS        g_ExtSymbols;
-PDEBUG_SYSTEM_OBJECTS g_ExtSystem;
-PDEBUG_REGISTERS      g_ExtRegisters;
+HRESULT
+DebugClient::QueryInterface(
+    REFIID InterfaceId,
+    PVOID* Interface
+    )
+{
+    if (InterfaceId == __uuidof(IUnknown) ||
+        InterfaceId == __uuidof(IDebugControl2) ||
+        InterfaceId == __uuidof(IDebugControl4) ||
+        InterfaceId == __uuidof(IDebugDataSpaces) ||
+        InterfaceId == __uuidof(IDebugSymbols) ||
+        InterfaceId == __uuidof(IDebugSystemObjects) ||
+        InterfaceId == __uuidof(IDebugRegisters))
+    {
+        *Interface = this;
+        AddRef();
+        return S_OK;
+    }
+    else
+    {
+        *Interface = NULL;
+        return E_NOINTERFACE;
+    }
+}
 
-extern "C" HRESULT
-ExtQuery(PDEBUG_CLIENT Client)
+ULONG
+DebugClient::AddRef()
 {
-    g_ExtClient = Client;
-    g_ExtControl = (PDEBUG_CONTROL2)Client;
-    g_ExtData = (PDEBUG_DATA_SPACES)Client;
-    g_ExtSymbols = (PDEBUG_SYMBOLS)Client;
-    g_ExtSystem = (PDEBUG_SYSTEM_OBJECTS)Client;
-    g_ExtRegisters = (PDEBUG_REGISTERS)Client;
-    return S_OK;
+    LONG ref = InterlockedIncrement(&m_ref);    
+    return ref;
 }
 
-void
-ExtRelease(void)
+ULONG
+DebugClient::Release()
 {
-    g_ExtClient = NULL;
-    g_ExtControl = NULL;
-    g_ExtData = NULL;
-    g_ExtSymbols = NULL;
-    g_ExtSystem = NULL;
-    g_ExtRegisters = NULL;
+    LONG ref = InterlockedDecrement(&m_ref);
+    if (ref == 0)
+    {
+        m_lldbservices->Release();
+        delete this;
+    }
+    return ref;
 }
 
 #endif // FEATURE_PAL
index b405f17..8cdba9f 100644 (file)
@@ -123,15 +123,13 @@ private:
 };
 
 #ifndef MINIDUMP
-
 #define EXIT_API     ExtRelease
 
-
 // Safe release and NULL.
 #define EXT_RELEASE(Unk) \
     ((Unk) != NULL ? ((Unk)->Release(), (Unk) = NULL) : NULL)
 
-extern PDEBUG_CLIENT         g_ExtClient;
 extern PDEBUG_CONTROL2       g_ExtControl;
 extern PDEBUG_DATA_SPACES    g_ExtData;
 extern PDEBUG_SYMBOLS        g_ExtSymbols;
@@ -141,14 +139,19 @@ extern PDEBUG_REGISTERS      g_ExtRegisters;
 #ifndef FEATURE_PAL
 
 // Global variables initialized by query.
+extern PDEBUG_CLIENT         g_ExtClient;
 extern PDEBUG_DATA_SPACES2   g_ExtData2;
 extern PDEBUG_SYMBOLS2       g_ExtSymbols2;
 extern PDEBUG_ADVANCED3      g_ExtAdvanced3;
 
-#endif // !FEATURE_PAL
+#else // FEATURE_PAL
+
+extern ILLDBServices*        g_ExtServices;    
+
+#endif // FEATURE_PAL
 
 HRESULT
-ExtQuery(PDEBUG_CLIENT Client);
+ExtQuery(PDEBUG_CLIENT client);
 
 HRESULT 
 ArchQuery(void);
@@ -179,7 +182,7 @@ inline BOOL IsInterrupt()
 #undef DECLARE_API
 
 #define DECLARE_API(extension)     \
-CPPMOD HRESULT CALLBACK extension(PDEBUG_CLIENT Client, PCSTR args)
+CPPMOD HRESULT CALLBACK extension(PDEBUG_CLIENT client, PCSTR args)
 
 class __ExtensionCleanUp
 {
@@ -214,7 +217,7 @@ inline void DACMessage(HRESULT Status)
     ExtOut("\n");
     ExtOut("If you are debugging a minidump, you need to make sure that your executable\n");
     ExtOut("path is pointing to coreclr.dll as well.\n");
-#else
+#else // FEATURE_PAL
     ExtOut("You can run the debugger command 'setclrpath' to control the load of %s.\n", MAKEDLLNAME_A("mscordaccore"));
     ExtOut("If that succeeds, the SOS command should work on retry.\n");
 #endif // FEATURE_PAL
@@ -225,7 +228,7 @@ HRESULT CheckEEDll();
 #define INIT_API_NOEE()                                         \
     HRESULT Status;                                             \
     __ExtensionCleanUp __extensionCleanUp;                      \
-    if ((Status = ExtQuery(Client)) != S_OK) return Status;     \
+    if ((Status = ExtQuery(client)) != S_OK) return Status;     \
     if ((Status = ArchQuery()) != S_OK)      return Status;     \
     ControlC = FALSE;                                           \
     g_bDacBroken = TRUE;
@@ -319,7 +322,6 @@ public:
     // Returns the size of the CONTEXT for the target machine
     virtual ULONG GetContextSize() const = 0;
 
-#ifndef FEATURE_PAL
     // Disassembles a managed method specified by the IPBegin-IPEnd range
     virtual void Unassembly(
                 TADDR IPBegin, 
@@ -330,7 +332,6 @@ public:
                 SOSEHInfo *pEHInfo,
                 BOOL bSuppressLines,
                 BOOL bDisplayOffsets) const = 0;
-#endif
 
     // Validates whether retAddr represents a return address by unassembling backwards.
     // If the instruction before retAddr represents a target-specific call instruction
@@ -421,11 +422,7 @@ inline CLRDATA_ADDRESS GetBP(const CROSS_PLATFORM_CONTEXT& context)
 //
 //-----------------------------------------------------------------------------------------
 
-#ifdef FEATURE_PAL
-
-#define GetExpression(exp) g_ExtClient->GetExpression(exp)
-
-#else // FEATURE_PAL
+#ifndef FEATURE_PAL
 
 extern WINDBG_EXTENSION_APIS ExtensionApis;
 #define GetExpression (ExtensionApis.lpGetExpressionRoutine)
@@ -434,6 +431,10 @@ extern ULONG TargetMachine;
 extern ULONG g_TargetClass;
 extern ULONG g_VDbgEng;
 
+#else // FEATURE_PAL
+
+#define GetExpression(exp) g_ExtServices->GetExpression(exp)
+
 #endif // FEATURE_PAL
 
 #define CACHE_SIZE  DT_OS_PAGE_SIZE
diff --git a/src/coreclr/src/ToolBox/SOS/Strike/inc/dbgeng.h b/src/coreclr/src/ToolBox/SOS/Strike/inc/dbgeng.h
new file mode 100644 (file)
index 0000000..fb84881
--- /dev/null
@@ -0,0 +1,479 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+//----------------------------------------------------------------------------
+//
+// Debugger engine interface subset implemented with ILLDBServices
+//
+//----------------------------------------------------------------------------
+
+#ifndef __DBGENG_H__
+#define __DBGENG_H__
+
+#include <unknwn.h>
+#include <rpc.h>
+#include <lldbservices.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+class DebugClient
+{
+private:
+    LONG m_ref;
+    ILLDBServices *m_lldbservices;
+
+public:
+    DebugClient(ILLDBServices *lldbservices) : 
+        m_ref(1),
+        m_lldbservices(lldbservices)
+    {
+        m_lldbservices->AddRef();
+    }
+
+    //----------------------------------------------------------------------------
+    // IUnknown
+    //----------------------------------------------------------------------------
+
+    HRESULT 
+    QueryInterface(
+        REFIID InterfaceId,
+        PVOID* Interface);
+
+    ULONG AddRef();
+
+    ULONG Release();
+
+    //----------------------------------------------------------------------------
+    // IDebugControl2
+    //----------------------------------------------------------------------------
+
+    // Checks for a user interrupt, such a Ctrl-C
+    // or stop button.
+    // This method is reentrant.
+    HRESULT 
+    GetInterrupt()
+    {
+        return m_lldbservices->GetInterrupt();
+    }
+
+    // Sends output through clients
+    // output callbacks if the mask is allowed
+    // by the current output control mask and
+    // according to the output distribution
+    // settings.
+    HRESULT 
+    Output(
+        ULONG mask,
+        PCSTR format,
+        ...)
+    {
+        va_list args;
+        va_start (args, format);
+        HRESULT result = OutputVaList(mask, format, args);
+        va_end (args);
+        return result;
+    }
+
+    HRESULT 
+    OutputVaList(
+        ULONG mask,
+        PCSTR format,
+        va_list args)
+    {
+        return m_lldbservices->OutputVaList(mask, format, args);
+    }
+
+    // The following methods allow direct control
+    // over the distribution of the given output
+    // for situations where something other than
+    // the default is desired.  These methods require
+    // extra work in the engine so they should
+    // only be used when necessary.
+    HRESULT 
+    ControlledOutput(
+        ULONG outputControl,
+        ULONG mask,
+        PCSTR format,
+        ...)
+    {
+        va_list args;
+        va_start (args, format);
+        HRESULT result = ControlledOutputVaList(outputControl, mask, format, args);
+        va_end (args);
+        return result;
+    }
+
+    HRESULT 
+    ControlledOutputVaList(
+        ULONG outputControl,
+        ULONG mask,
+        PCSTR format,
+        va_list args)
+    {
+        return OutputVaList(mask, format, args);
+    }
+
+    // Returns information about the debuggee such
+    // as user vs. kernel, dump vs. live, etc.
+    HRESULT 
+    GetDebuggeeType(
+        PULONG debugClass,
+        PULONG qualifier)
+    {
+        return m_lldbservices->GetDebuggeeType(debugClass, qualifier);
+    }
+
+    // Returns the page size for the currently executing
+    // processor context.  The page size may vary between
+    // processor types.
+    HRESULT 
+    GetPageSize(
+        PULONG size)
+    {
+        return m_lldbservices->GetPageSize(size);
+    }
+
+    HRESULT 
+    GetExecutingProcessorType(
+        PULONG type)
+    {
+        return m_lldbservices->GetExecutingProcessorType(type);
+    }
+
+    HRESULT 
+    Execute(
+        ULONG outputControl,
+        PCSTR command,
+        ULONG flags)
+    {
+        return m_lldbservices->Execute(outputControl, command, flags);
+    }
+
+    HRESULT 
+    GetLastEventInformation(
+        PULONG type,
+        PULONG processId,
+        PULONG threadId,
+        PVOID extraInformation,
+        ULONG extraInformationSize,
+        PULONG extraInformationUsed,
+        PSTR description,
+        ULONG descriptionSize,
+        PULONG descriptionUsed)
+    {
+        return m_lldbservices->GetLastEventInformation(type, processId, threadId, extraInformation, 
+            extraInformationSize, extraInformationUsed, description, descriptionSize, descriptionUsed);
+    }
+
+    HRESULT 
+    Disassemble(
+        ULONG64 offset,
+        ULONG flags,
+        PSTR buffer,
+        ULONG bufferSize,
+        PULONG disassemblySize,
+        PULONG64 endOffset)
+    {
+        return m_lldbservices->Disassemble(offset, flags, buffer, bufferSize, disassemblySize, endOffset);
+    }
+
+    //----------------------------------------------------------------------------
+    // IDebugControl4
+    //----------------------------------------------------------------------------
+
+    // Stack tracing with a full initial context
+    // and full context return for each frame.
+    // The FrameContextsSize parameter is the total
+    // byte size of FrameContexts.  FrameContextsEntrySize
+    // gives the byte size of each entry in
+    // FrameContexts.
+    HRESULT
+    GetContextStackTrace(
+        PVOID startContext,
+        ULONG startContextSize,
+        PDEBUG_STACK_FRAME frames,
+        ULONG framesSize,
+        PVOID frameContexts,
+        ULONG frameContextsSize,
+        ULONG frameContextsEntrySize,
+        PULONG framesFilled)
+    {
+        return m_lldbservices->GetContextStackTrace(startContext, startContextSize, frames, 
+            framesSize, frameContexts, frameContextsSize, frameContextsEntrySize, framesFilled);
+    }
+
+    //----------------------------------------------------------------------------
+    // IDebugDataSpaces
+    //----------------------------------------------------------------------------
+
+    HRESULT 
+    ReadVirtual(
+        ULONG64 offset,
+        PVOID buffer,
+        ULONG bufferSize,
+        PULONG bytesRead)
+    {
+        return m_lldbservices->ReadVirtual(offset, buffer, bufferSize, bytesRead);
+    }
+
+    HRESULT 
+    WriteVirtual(
+        ULONG64 offset,
+        PVOID buffer,
+        ULONG bufferSize,
+        PULONG bytesWritten)
+    {
+        return m_lldbservices->WriteVirtual(offset, buffer, bufferSize, bytesWritten);
+    }
+
+    //----------------------------------------------------------------------------
+    // IDebugSymbols
+    //----------------------------------------------------------------------------
+
+    HRESULT 
+    GetSymbolOptions(
+        PULONG options)
+    {
+        return m_lldbservices->GetSymbolOptions(options);
+    }
+
+    HRESULT 
+    GetNameByOffset(
+        ULONG64 offset,
+        PSTR nameBuffer,
+        ULONG nameBufferSize,
+        PULONG nameSize,
+        PULONG64 displacement)
+    {
+        return m_lldbservices->GetNameByOffset(offset, nameBuffer, nameBufferSize, nameSize, displacement);
+    }
+
+    HRESULT 
+    GetNumberModules(
+        PULONG loaded,
+        PULONG unloaded)
+    {
+        return m_lldbservices->GetNumberModules(loaded, unloaded);
+    }
+
+    HRESULT GetModuleByIndex(
+        ULONG index,
+        PULONG64 base)
+    {
+        return m_lldbservices->GetModuleByIndex(index, base);
+    }
+
+    HRESULT 
+    GetModuleByModuleName(
+        PCSTR name,
+        ULONG startIndex,
+        PULONG index,
+        PULONG64 base)
+    {
+        return m_lldbservices->GetModuleByModuleName(name, startIndex, index, base);
+    }
+
+    HRESULT 
+    GetModuleByOffset(
+        ULONG64 offset,
+        ULONG startIndex,
+        PULONG index,
+        PULONG64 base)
+    {
+        return m_lldbservices->GetModuleByOffset(offset, startIndex, index, base);
+    }
+
+    HRESULT 
+    GetModuleNames(
+        ULONG index,
+        ULONG64 base,
+        PSTR imageNameBuffer,
+        ULONG imageNameBufferSize,
+        PULONG imageNameSize,
+        PSTR moduleNameBuffer,
+        ULONG moduleNameBufferSize,
+        PULONG moduleNameSize,
+        PSTR loadedImageNameBuffer,
+        ULONG loadedImageNameBufferSize,
+        PULONG loadedImageNameSize)
+    {
+        return m_lldbservices->GetModuleNames(index, base, imageNameBuffer, imageNameBufferSize, imageNameSize, moduleNameBuffer,
+            moduleNameBufferSize, moduleNameSize, loadedImageNameBuffer, loadedImageNameBufferSize, loadedImageNameSize);
+    }
+
+    HRESULT 
+    GetLineByOffset(
+        ULONG64 offset,
+        PULONG line,
+        PSTR fileBuffer,
+        ULONG fileBufferSize,
+        PULONG fileSize,
+        PULONG64 displacement)
+    {
+        return m_lldbservices->GetLineByOffset(offset, line, fileBuffer, fileBufferSize, fileSize, displacement);
+    }
+     
+    HRESULT 
+    GetSourceFileLineOffsets(
+        PCSTR file,
+        PULONG64 buffer,
+        ULONG bufferLines,
+        PULONG fileLines)
+    {
+        return m_lldbservices->GetSourceFileLineOffsets(file, buffer, bufferLines, fileLines);
+    }
+
+    // Uses the given file path and the source path
+    // information to try and locate an existing file.
+    // The given file path is merged with elements
+    // of the source path and checked for existence.
+    // If a match is found the element used is returned.
+    // A starting element can be specified to restrict
+    // the search to a subset of the path elements;
+    // this can be useful when checking for multiple
+    // matches along the source path.
+    // The returned element can be 1, indicating
+    // the file was found directly and not on the path.
+    HRESULT 
+    FindSourceFile(
+        ULONG startElement,
+        PCSTR file,
+        ULONG flags,
+        PULONG foundElement,
+        PSTR buffer,
+        ULONG bufferSize,
+        PULONG foundSize)
+    {
+        return m_lldbservices->FindSourceFile(startElement, file, flags, foundElement, buffer, bufferSize, foundSize);
+    }
+
+    //----------------------------------------------------------------------------
+    // IDebugSystemObjects
+    //----------------------------------------------------------------------------
+
+    HRESULT 
+    GetCurrentProcessId(
+        PULONG id)
+    {
+        return m_lldbservices->GetCurrentProcessId(id);
+    }
+
+    HRESULT 
+    GetCurrentThreadId(
+        PULONG id)
+    {
+        return m_lldbservices->GetCurrentThreadId(id);
+    }
+
+    HRESULT 
+    SetCurrentThreadId(
+        ULONG id)
+    {
+        return m_lldbservices->SetCurrentThreadId(id);
+    }
+
+    HRESULT 
+    GetCurrentThreadSystemId(
+        PULONG sysId)
+    {
+        return m_lldbservices->GetCurrentThreadSystemId(sysId);
+    }
+
+    HRESULT 
+    GetThreadIdBySystemId(
+        ULONG sysId,
+        PULONG threadId)
+    {
+        return m_lldbservices->GetThreadIdBySystemId(sysId, threadId);
+    }
+
+    HRESULT 
+    GetThreadContextById(
+        /* in */ ULONG32 threadID,
+        /* in */ ULONG32 contextFlags,
+        /* in */ ULONG32 contextSize,
+        /* out */ PBYTE context)
+    {
+        return m_lldbservices->GetThreadContextById(threadID, contextFlags, contextSize, context);
+    }
+
+    //----------------------------------------------------------------------------
+    // IDebugRegisters
+    //----------------------------------------------------------------------------
+
+    HRESULT
+    GetValueByName(
+        PCSTR name,
+        PDWORD_PTR debugValue)
+    {
+        return m_lldbservices->GetValueByName(name, debugValue);
+    }
+
+    HRESULT 
+    GetInstructionOffset(
+        PULONG64 offset)
+    {
+        return m_lldbservices->GetInstructionOffset(offset);
+    }
+
+    HRESULT 
+    GetStackOffset(
+        PULONG64 offset)
+    {
+        return m_lldbservices->GetStackOffset(offset);
+    }
+
+    HRESULT 
+    GetFrameOffset(
+        PULONG64 offset)
+    {
+        return m_lldbservices->GetFrameOffset(offset);
+    }
+};
+MIDL_INTERFACE("d4366723-44df-4bed-8c7e-4c05424f4588")
+IDebugControl2 : DebugClient
+{
+};
+
+MIDL_INTERFACE("94e60ce9-9b41-4b19-9fc0-6d9eb35272b3")
+IDebugControl4 : DebugClient
+{
+};
+
+MIDL_INTERFACE("88f7dfab-3ea7-4c3a-aefb-c4e8106173aa")
+IDebugDataSpaces : DebugClient
+{
+};
+
+MIDL_INTERFACE("8c31e98c-983a-48a5-9016-6fe5d667a950")
+IDebugSymbols : DebugClient
+{
+};
+
+MIDL_INTERFACE("6b86fe2c-2c4f-4f0c-9da2-174311acc327")
+IDebugSystemObjects : DebugClient
+{
+};
+
+MIDL_INTERFACE("ce289126-9e84-45a7-937e-67bb18691493")
+IDebugRegisters : DebugClient
+{
+};
+
+typedef interface ILLDBServices* PDEBUG_CLIENT;
+typedef interface IDebugControl2* PDEBUG_CONTROL2;
+typedef interface IDebugControl4* PDEBUG_CONTROL4;
+typedef interface IDebugDataSpaces* PDEBUG_DATA_SPACES;
+typedef interface IDebugSymbols* PDEBUG_SYMBOLS;
+typedef interface IDebugSystemObjects* PDEBUG_SYSTEM_OBJECTS;
+typedef interface IDebugRegisters* PDEBUG_REGISTERS;
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif // #ifndef __DBGENG_H__
@@ -14,19 +14,4 @@ Abstract:
 
 Revision History:
 
---*/
-
-#ifndef _DBGHELP_
-#define _DBGHELP_
-
-#if _MSC_VER > 1020
-#pragma once
-#endif
-//
-// options that are set/returned by SymSetOptions() & SymGetOptions()
-// these are used as a mask
-//
-#define SYMOPT_LOAD_LINES                0x00000010
-
-#endif // _DBGHELP_
+--*/
\ No newline at end of file
index 12f8f5e..d79a460 100644 (file)
@@ -14,7 +14,7 @@
 #define __PLATFORM_SPECIFIC_INCLUDED
 
 // The main debugger code already has target platform definitions for CONTEXT.
-#include "../../../../debug/inc/dbgtargetcontext.h"
+#include "../../../debug/inc/dbgtargetcontext.h"
 
 #ifndef FEATURE_PAL
 
index e0a22c6..4aba4ea 100644 (file)
@@ -20,7 +20,7 @@
 Notes:
 
 HRESULT CALLBACK _EFN_StackTrace(
-    PDEBUG_CLIENT Client,
+    PDEBUG_CLIENT client,
     WCHAR wszTextOut[],
     UINT *puiTextLength,
     LPVOID pTransitionContexts,
@@ -96,7 +96,7 @@ extern "C" {
 #endif // __cplusplus
 
 HRESULT CALLBACK _EFN_StackTrace(
-    PDEBUG_CLIENT Client,
+    PDEBUG_CLIENT client,
     __out_ecount(*puiTextLength) WCHAR wszTextOut[],
     size_t *puiTextLength,
     LPVOID pTransitionContexts,
@@ -120,7 +120,7 @@ HRESULT CALLBACK _EFN_StackTrace(
 // 
 // The output will be truncated of cbString is not long enough for the full stack trace.
 HRESULT _EFN_GetManagedExcepStack(
-    PDEBUG_CLIENT Client,
+    PDEBUG_CLIENT client,
     ULONG64 StackObjAddr,
     __out_ecount(cbString) PSTR szStackString,
     ULONG cbString
@@ -129,7 +129,7 @@ HRESULT _EFN_GetManagedExcepStack(
 // _EFN_GetManagedExcepStackW - same as _EFN_GetManagedExcepStack, but returns 
 //                              the stack as a wide string.
 HRESULT _EFN_GetManagedExcepStackW(
-    PDEBUG_CLIENT Client,
+    PDEBUG_CLIENT client,
     ULONG64 StackObjAddr,
     __out_ecount(cchString) PWSTR wszStackString,
     ULONG cchString
@@ -142,7 +142,7 @@ HRESULT _EFN_GetManagedExcepStackW(
 // cbName - the number of characters available in the buffer
 //
 HRESULT _EFN_GetManagedObjectName(
-    PDEBUG_CLIENT Client,
+    PDEBUG_CLIENT client,
     ULONG64 objAddr,
     __out_ecount(cbName) PSTR szName,
     ULONG cbName
@@ -159,12 +159,13 @@ HRESULT _EFN_GetManagedObjectName(
 //
 // At least one of pValue and pOffset must be non-NULL.
 HRESULT _EFN_GetManagedObjectFieldInfo(
-    PDEBUG_CLIENT Client,
+    PDEBUG_CLIENT client,
     ULONG64 objAddr,
     __out_ecount (mdNameLen) PSTR szFieldName,
     PULONG64 pValue,
     PULONG pOffset
     );
+
 #ifdef __cplusplus
 }
 #endif // __cplusplus : extern "C"
index e7dc3a4..594fca1 100644 (file)
@@ -835,7 +835,7 @@ exceptions by switching to the thread in question, and running
 \\
 
 COMMAND: clrstack.
-!CLRStack [-a] [-l] [-p] [-n]
+!CLRStack [-a] [-l] [-p] [-n] [-f]
 !CLRStack [-a] [-l] [-p] [-i] [variable name] [frame]
 
 CLRStack attempts to provide a true stack trace for managed code only. It is
@@ -846,6 +846,10 @@ SOS can't retrieve local names at this time, so the output for locals is in
 the format <local address> = <value>. The -a (all) parameter is a short-cut
 for -l and -p combined. 
 
+The -f option (full mode) displays the native frames intermixing them with
+the managed frames and the assembly name and function offset for the managed
+frames.
+
 If the debugger has the option SYMOPT_LOAD_LINES specified (either by the
 .lines or .symopt commands), SOS will look up the symbols for every managed 
 frame and if successful will display the corresponding source file name and 
index 8a6218a..4a2417b 100644 (file)
@@ -26,10 +26,13 @@ Object Inspection                  Examining code and stacks
 DumpObj (dumpobj)                  Threads (clrthreads)
 DumpArray                          ThreadState
 DumpStackObjects (dso)             IP2MD (ip2md)
-DumpHeap (dumpheap)                CLRStack (clrstack) 
-DumpVC                             GCInfo
-GCRoot (gcroot)                    EHInfo
-PrintException (pe)                bpmd (bpmd)
+DumpHeap (dumpheap)                u (clru)
+DumpVC                             DumpStack (dumpstack)
+GCRoot (gcroot)                    EEStack (eestack)
+PrintException (pe)                CLRStack (clrstack) 
+                                   GCInfo
+                                   EHInfo
+                                   bpmd (bpmd)
 
 Examining CLR data structures      Diagnostic Utilities
 -----------------------------      -----------------------------
@@ -37,12 +40,15 @@ DumpDomain                         VerifyHeap
 EEHeap (eeheap)                    FindAppDomain          
 Name2EE (name2ee)                  DumpLog (dumplog)
 DumpMT (dumpmt)
-DumpClass                                             
+DumpClass (dumpclass)
 DumpMD (dumpmd)                    
 Token2EE                           
-DumpModule                         
-DumpAssembly                       
-DumpRuntimeTypes                   
+DumpModule (dumpmodule)
+DumpAssembly
+DumpRuntimeTypes
+DumpIL (dumpil)
+DumpSig
+DumpSigElem
 
 Other
 -----------------------------
@@ -407,7 +413,9 @@ places:
 First, all stacks will be searched for roots, then handle tables, and finally
 the freachable queue of the finalizer. Some caution about the stack roots: 
 GCRoot doesn't attempt to determine if a stack root it encountered is valid 
-or is old (discarded) data. 
+or is old (discarded) data. You would have to use CLRStack and U to 
+disassemble the frame that the local or argument value belongs to in order to 
+determine if it is still in use.
 
 Because people often want to restrict the search to gc handles and freachable
 objects, there is a -nostacks option.
@@ -548,7 +556,7 @@ exceptions by switching to the thread in question, and running
 \\
 
 COMMAND: clrstack.
-CLRStack [-a] [-l] [-p] [-n]
+CLRStack [-a] [-l] [-p] [-n] [-f]
 CLRStack [-a] [-l] [-p] [-i] [variable name] [frame]
 
 CLRStack attempts to provide a true stack trace for managed code only. It is
@@ -559,6 +567,10 @@ SOS can't retrieve local names at this time, so the output for locals is in
 the format <local address> = <value>. The -a (all) parameter is a short-cut
 for -l and -p combined. 
 
+The -f option (full mode) displays the native frames intermixing them with
+the managed frames and the assembly name and function offset for the managed
+frames.
+
 If the debugger has the option SYMOPT_LOAD_LINES specified (either by the
 .lines or .symopt commands), SOS will look up the symbols for every managed 
 frame and if successful will display the corresponding source file name and 
@@ -634,7 +646,7 @@ associated with it. For example, this output from K:
         Transparency: Critical
 
 We have taken a return address into Mainy.Main, and discovered information 
-about that method. You could run DumpMT, DumpClass, DumpMD, or 
+about that method. You could run U, DumpMT, DumpClass, DumpMD, or 
 DumpModule on the fields listed to learn more.
 
 The "Source line" output will only be present if the debugger can find the 
@@ -642,6 +654,88 @@ symbols for the managed module containing the given <code address>, and if the
 debugger is configured to load line number information.
 \\
 
+COMMAND: clru.
+COMMAND: u.
+U [-gcinfo] [-ehinfo] [-n] [-o] <MethodDesc address> | <Code address>
+
+Presents an annotated disassembly of a managed method when given a MethodDesc
+pointer for the method, or a code address within the method body. Unlike the
+debugger "U" function, the entire method from start to finish is printed,
+with annotations that convert metadata tokens to names.
+
+       <example output>
+       ...
+       03ef015d b901000000       mov     ecx,0x1
+       03ef0162 ff156477a25b     call   dword ptr [mscorlib_dll+0x3c7764 (5ba27764)] (System.Console.InitializeStdOutError(Boolean), mdToken: 06000713)
+       03ef0168 a17c20a701       mov     eax,[01a7207c] (Object: SyncTextWriter)
+       03ef016d 89442414         mov     [esp+0x14],eax
+
+If you pass the -gcinfo flag, you'll get inline display of the GCInfo for
+the method. You can also obtain this information with the GCInfo command.
+
+If you pass the -ehinfo flag, you'll get inline display of exception info
+for the method. (Beginning and end of try/finally/catch handlers, etc.).
+You can also obtain this information with the EHInfo command.
+
+If you pass the -o flag, the byte offset of each instruction from the
+beginning of the method will be printed in addition to the absolute address of
+the instruction.
+
+If the debugger has the option SYMOPT_LOAD_LINES specified (either by the
+.lines or .symopt commands), and if symbols are available for the managed
+module containing the method being examined, the output of the command will
+include the source file name and line number corresponding to the 
+disassembly. The -n (No line numbers) flag can be specified to disable this
+behavior.
+
+       <example output>
+       ...
+       c:\Code\prj.mini\exc.cs @ 38:
+       001b00b0 8b0d3020ab03    mov     ecx,dword ptr ds:[3AB2030h] ("Break in debugger. When done type <Enter> to continue: ")
+       001b00b6 e8d5355951      call    mscorlib_ni+0x8b3690 (51743690) (System.Console.Write(System.String), mdToken: 0600091b)
+       001b00bb 90              nop
+
+       c:\Code\prj.mini\exc.cs @ 39:
+       001b00bc e863cdc651      call    mscorlib_ni+0xf8ce24 (51e1ce24) (System.Console.ReadLine(), mdToken: 060008f6)
+       >>> 001b00c1 90              nop
+       ...
+\\
+
+COMMAND: dumpstack.
+DumpStack [-EE] [-n] [top stack [bottom stack]]
+
+[x86 and x64 documentation]
+
+This command provides a verbose stack trace obtained by "scraping." Therefore
+the output is very noisy and potentially confusing. The command is good for
+viewing the complete call stack when "kb" gets confused. For best results,
+make sure you have valid symbols.
+
+-EE will only show managed functions.
+
+If the debugger has the option SYMOPT_LOAD_LINES specified (either by the
+.lines or .symopt commands), SOS will look up the symbols for every managed 
+frame and if successful will display the corresponding source file name and 
+line number. The -n (No line numbers) parameter can be specified to disable 
+this behavior.
+
+You can also pass a stack range to limit the output.
+\\
+
+COMMAND: eestack.
+EEStack [-short] [-EE]
+
+This command runs DumpStack on all threads in the process. The -EE option is 
+passed directly to DumpStack. The -short option tries to narrow down the 
+output to "interesting" threads only, which is defined by
+
+1) The thread has taken a lock.
+2) The thread has been "hijacked" in order to allow a garbage collection.
+3) The thread is currently in managed code.
+
+See the documentation for DumpStack for more info.
+\\
+
 COMMAND: ehinfo.
 EHInfo (<MethodDesc address> | <Code address>)
 
@@ -1061,8 +1155,9 @@ a code address in a managed function into a MethodDesc:
        IsJitted: yes
        CodeAddr: 03ef00b8
 
-You can call DumpClass, DumpMT, DumpModule on the Class, MethodTable and Module
-fields above.
+If IsJitted is "yes," you can run U on the CodeAddr pointer to see a 
+disassembly of the JITTED code.  You can call also DumpClass, DumpMT, 
+DumpModule on the Class, MethodTable and Module fields above.
 \\
 
 COMMAND: token2ee.
@@ -1205,7 +1300,126 @@ AppDomains.  For example:
      2843684        ?   23a544c System.IEquatable`1[[System.IntPtr, mscorlib]]
      2843784        ?   3c999c System.Int32
      2843798        ?   3caa04 System.IEquatable`1[[System.Int32, mscorlib]]
+\\
+
+COMMAND: dumpsig.
+DumpSig <sigaddr> <moduleaddr>
 
+This command dumps the signature of a method or field given by <sigaddr>.  This is
+useful when you are debugging parts of the runtime which returns a raw PCCOR_SIGNATURE
+structure and need to know what its contents are.
+
+Sample output for a method:
+    0:000> sos DumpSig 0x000007fe`ec20879d 0x000007fe`eabd1000
+    [DEFAULT] [hasThis] Void (Boolean,String,String)
+
+The first section of the output is the calling convention.  This includes, but is not
+limited to, "[DEFAULT]", "[C]", "[STDCALL]", "[THISCALL]", and so on.  The second
+portion of the output is either "[hasThis]" or "[explicit]" for whether the method
+is an instance method or a static method respectively.  The third portion of the 
+output is the return value (in this case a "void").  Finally, the method's arguments
+are printed as the final portion of the output.
+
+Sample output for a field:
+    0:000> sos DumpSig 0x000007fe`eb7fd8cd 0x000007fe`eabd1000
+    [FIELD] ValueClass System.RuntimeTypeHandle 
+
+DumpSig will also work with generics.  Here is the output for the following
+function:
+    public A Test(IEnumerable<B> n)
+
+    0:000> sos DumpSig 00000000`00bc2437 000007ff00043178 
+    [DEFAULT] [hasThis] __Canon (Class System.Collections.Generic.IEnumerable`1<__Canon>)
+\\
+
+COMMAND: dumpsigelem.
+DumpSigElem <sigaddr> <moduleaddr>
+
+This command dumps a single element of a signature object.  For most circumstances,
+you should use DumpSig to look at individual signature objects, but if you find a 
+signature that has been corrupted in some manner you can use DumpSigElem to read out 
+the valid portions of it.
+
+If we look at a valid signature object for a method we see the following:
+    0:000> dumpsig 0x000007fe`ec20879d 0x000007fe`eabd1000
+    [DEFAULT] [hasThis] Void (Boolean,String,String)
+
+We can look at the individual elements of this object by adding the offsets into the 
+object which correspond to the return value and parameters:
+    0:000> sos DumpSigElem 0x000007fe`ec20879d+2 0x000007fe`eabd1000
+    Void
+    0:000> sos DumpSigElem 0x000007fe`ec20879d+3 0x000007fe`eabd1000
+    Boolean
+    0:000> sos DumpSigElem 0x000007fe`ec20879d+4 0x000007fe`eabd1000
+    String
+    0:000> sos DumpSigElem 0x000007fe`ec20879d+5 0x000007fe`eabd1000
+    String
+
+We can do something similar for fields.  Here is the full signature of a field:
+    0:000> dumpsig 0x000007fe`eb7fd8cd 0x000007fe`eabd1000
+    [FIELD] ValueClass System.RuntimeTypeHandle 
+
+Using DumpSigElem we can find the type of the field by adding the offset of it (1) to 
+the address of the signature:
+    0:000> sos DumpSigElem 0x000007fe`eb7fd8cd+1 0x000007fe`eabd1000
+    ValueClass System.RuntimeTypeHandle
+
+DumpSigElem will also work with generics.  Let a function be defined as follows:
+    public A Test(IEnumerable<B> n)
+
+The elements of this signature can be obtained by adding offsets into the signature
+when calling DumpSigElem:
+
+    0:000> sos DumpSigElem 00000000`00bc2437+2 000007ff00043178 
+    __Canon
+    0:000> sos DumpSigElem 00000000`00bc2437+4 000007ff00043178 
+    Class System.Collections.Generic.IEnumerable`1<__Canon>
+
+The actual offsets that you should add are determined by the contents of the
+signature itself.  By trial and error you should be able to find various elements
+of the signature.
+\\
+
+COMMAND: dumpil.
+DumpIL <Managed DynamicMethod object> | 
+       <DynamicMethodDesc pointer> |
+       <MethodDesc pointer> |
+        /i <IL pointer>
+
+DumpIL prints the IL code associated with a managed method. We added this
+function specifically to debug DynamicMethod code which was constructed on
+the fly. Happily it works for non-dynamic code as well.
+
+You can use it in four ways: 
+
+  1) If you have a System.Reflection.Emit.DynamicMethod object, just pass
+     the pointer as the first argument. 
+  2) If you have a DynamicMethodDesc pointer you can use that to print the
+     IL associated with the dynamic method.
+  3) If you have an ordinary MethodDesc, you can see the IL for that as well,
+     just pass it as the first argument.
+  4) If you have a pointer directly to the IL, specify /i followed by the
+     the IL address.  This is useful for writers of profilers that instrument
+     IL.
+     
+
+Note that dynamic IL is constructed a bit differently. Rather than referring
+to metadata tokens, the IL points to objects in a managed object array. Here
+is a simple example of the output for a dynamic method:
+
+  0:000> sos DumpIL b741dc
+  This is dynamic IL. Exception info is not reported at this time.
+  If a token is unresolved, run "sos DumpObj <addr>" on the addr given
+  in parenthesis. You can also look at the token table yourself, by
+  running "DumpArray 00b77388".
+
+  IL_0000: ldstr 70000002 "Inside invoked method "
+  IL_0005: call 6000003 System.Console.WriteLine(System.String)
+  IL_000a: ldc.i4.1
+  IL_000b: newarr 2000004 "System.Int32"
+  IL_0010: stloc.0
+  IL_0011: ldloc.0
+  IL_0012: ret
 \\
 
 COMMAND: verifyheap.
@@ -1246,7 +1460,6 @@ in the CLR. In user code, an error in constructing PInvoke calls can cause
 this problem, and running with Managed Debugging Assistants is advised. If that
 possibility is eliminated, consider contacting Microsoft Product Support for
 help.
-
 \\
 
 COMMAND: dumplog.
index c78cec5..b7875d0 100644 (file)
@@ -184,12 +184,6 @@ HMODULE g_hInstance = NULL;
 #include "ntinfo.h"
 #endif // FEATURE_PAL
 
-// Size of a fixed array:
-#ifndef ARRAYSIZE
-#define ARRAYSIZE(a) (sizeof(a)/sizeof((a)[0]))
-#endif // !ARRAYSIZE
-
-
 #ifndef IfFailRet
 #define IfFailRet(EXPR) do { Status = (EXPR); if(FAILED(Status)) { return (Status); } } while (0)
 #endif
@@ -303,7 +297,6 @@ DECLARE_API(IP2MD)
     DMLOut("MethodDesc:   %s\n", DMLMethodDesc(pMD));
     DumpMDInfo(TO_TADDR(pMD), cdaStart, FALSE /* fStackTraceFormat */);
 
-#ifndef FEATURE_PAL
     char  filename[MAX_PATH_FNAME+1];
     ULONG linenum;
     // symlines will be non-zero only if SYMOPT_LOAD_LINES was set in the symbol options
@@ -321,18 +314,15 @@ DECLARE_API(IP2MD)
     {
         ExtOut("Source file:  %s @ %d\n", filename, linenum);
     }
-#endif
 
     return Status;
 }
 
-#ifndef FEATURE_PAL
-
 // (MAX_STACK_FRAMES is also used by x86 to prevent infinite loops in _EFN_StackTrace)
 #define MAX_STACK_FRAMES 1000
 
-
 #ifdef _TARGET_WIN64_
+
 // I use a global set of frames for stack walking on win64 because the debugger's
 // GetStackTrace function doesn't provide a way to find out the total size of a stackwalk,
 // and I'd like to have a reasonably big maximum without overflowing the stack by declaring
@@ -340,8 +330,36 @@ DECLARE_API(IP2MD)
 // (so no dynamic allocation if possible).
 DEBUG_STACK_FRAME g_Frames[MAX_STACK_FRAMES];
 AMD64_CONTEXT g_X64FrameContexts[MAX_STACK_FRAMES];
-#endif
 
+static HRESULT
+GetContextStackTrace(PULONG pnumFrames)
+{
+    PDEBUG_CONTROL4 debugControl4;
+    HRESULT hr;
+
+    // Do we have advanced capability?
+    if ((hr = g_ExtControl->QueryInterface(__uuidof(IDebugControl4), (void **)&debugControl4)) == S_OK)
+    {
+        // GetContextStackTrace fills g_X64FrameContexts as an array of 
+        // contexts packed as target architecture contexts. We cannot 
+        // safely cast this as an array of CROSS_PLATFORM_CONTEXT, since 
+        // sizeof(CROSS_PLATFORM_CONTEXT) != sizeof(TGT_CONTEXT)
+        hr = debugControl4->GetContextStackTrace(
+            NULL,
+            0,
+            g_Frames,
+            MAX_STACK_FRAMES,
+            g_X64FrameContexts,
+            MAX_STACK_FRAMES*g_targetMachine->GetContextSize(),
+            g_targetMachine->GetContextSize(),
+            pnumFrames);
+
+        debugControl4->Release();
+    }
+    return hr;
+}
+
+#endif // _TARGET_WIN64_
 
 /**********************************************************************\
 * Routine Description:                                                 *
@@ -410,6 +428,7 @@ DECLARE_API(DumpStack)
 
     DumpStackFlag DSFlag;
     DSFlag.fEEonly = FALSE;
+    DSFlag.fSuppressSrcInfo = FALSE;
     DSFlag.top = 0;
     DSFlag.end = 0;
 
@@ -418,7 +437,9 @@ DECLARE_API(DumpStack)
         // name, vptr, type, hasValue
         {"-EE", &DSFlag.fEEonly, COBOOL, FALSE},
         {"-n",  &DSFlag.fSuppressSrcInfo, COBOOL, FALSE},
+#ifndef FEATURE_PAL
         {"/d", &dml, COBOOL, FALSE}
+#endif
     };
     CMDValue arg[] = {
         // vptr, type
@@ -465,6 +486,7 @@ DECLARE_API (EEStack)
 
     DumpStackFlag DSFlag;
     DSFlag.fEEonly = FALSE;
+    DSFlag.fSuppressSrcInfo = FALSE;
     DSFlag.top = 0;
     DSFlag.end = 0;
 
@@ -474,7 +496,9 @@ DECLARE_API (EEStack)
     {   // name, vptr, type, hasValue
         {"-EE", &DSFlag.fEEonly, COBOOL, FALSE},
         {"-short", &bShortList, COBOOL, FALSE},
+#ifndef FEATURE_PAL
         {"/d", &dml, COBOOL, FALSE}
+#endif
     };    
 
     if (!GetCMDOption(args, option, _countof(option), NULL, 0, NULL)) 
@@ -559,8 +583,6 @@ DECLARE_API (EEStack)
     return Status;
 }
 
-#endif // FEATURE_PAL
-
 HRESULT DumpStackObjectsRaw(size_t nArg, __in_z LPSTR exprBottom, __in_z LPSTR exprTop, BOOL bVerify)
 {
     size_t StackTop = 0;
@@ -712,8 +734,6 @@ DECLARE_API(DumpMD)
     return Status;
 }
 
-#ifndef FEATURE_PAL
-
 BOOL GatherDynamicInfo(TADDR DynamicMethodObj, DacpObjectData *codeArray, 
                        DacpObjectData *tokenArray, TADDR *ptokenArrayAddr)
 {
@@ -791,7 +811,6 @@ BOOL GatherDynamicInfo(TADDR DynamicMethodObj, DacpObjectData *codeArray,
     return bRet;
 }
 
-
 DECLARE_API(DumpIL)
 {
     INIT_API();
@@ -1011,7 +1030,6 @@ void DumpSigWorker (
     ExtOut("%S\n", (PCWSTR)sigString.Ptr());
 }
 
-
 /**********************************************************************\
 * Routine Description:                                                 *
 *                                                                      *
@@ -1059,8 +1077,6 @@ DECLARE_API(DumpSig)
     return Status;
 }
 
-
-
 /**********************************************************************\
 * Routine Description:                                                 *
 *                                                                      *
@@ -1110,9 +1126,6 @@ DECLARE_API(DumpSigElem)
     return Status;
 }
 
-#endif // FEATURE_PAL
-
-
 /**********************************************************************\
 * Routine Description:                                                 *
 *                                                                      *
@@ -1237,7 +1250,6 @@ DECLARE_API(DumpClass)
     return Status;
 }
 
-
 /**********************************************************************\
 * Routine Description:                                                 *
 *                                                                      *
@@ -2293,7 +2305,6 @@ size_t FormatGeneratedException (DWORD_PTR dataPtr,
         // or did not update so (when ste is an explicit frames), do not update wszBuffer
         if (Status == S_OK)
         {
-#ifndef FEATURE_PAL
             char filename[MAX_LONGPATH+1] = "";
             ULONG linenum = 0;
             if (bLineNumbers
@@ -2307,15 +2318,12 @@ size_t FormatGeneratedException (DWORD_PTR dataPtr,
 
             if (!bLineNumbers)
             {
-#endif // FEATURE_PAL
                 swprintf_s(wszLineBuffer, _countof(wszLineBuffer), W("    %s\n"), so.String());
-#ifndef FEATURE_PAL
             }
             else
             {
                 swprintf_s(wszLineBuffer, _countof(wszLineBuffer), W("    %s [%S @ %d]\n"), so.String(), filename, linenum);
             }
-#endif // FEATURE_PAL
 
             Length += _wcslen(wszLineBuffer);
 
@@ -6316,7 +6324,7 @@ public:
             flags &= ~(CLRDATA_NOTIFY_ON_MODULE_LOAD | CLRDATA_NOTIFY_ON_MODULE_UNLOAD);
             g_clrData->SetOtherNotificationFlags(flags);
 
-            g_ExtClient->ClearExceptionCallback();
+            g_ExtServices->ClearExceptionCallback();
         }
 #endif
     }
@@ -6990,13 +6998,7 @@ HRESULT HandleCLRNotificationEvent()
     return S_OK;
 }
 
-#ifdef FEATURE_PAL
-HRESULT HandleExceptionNotification(PDEBUG_CLIENT Client)
-{
-    INIT_API();
-    return HandleCLRNotificationEvent();
-}
-#endif
+#ifndef FEATURE_PAL
 
 DECLARE_API(HandleCLRN)
 {
@@ -7006,6 +7008,16 @@ DECLARE_API(HandleCLRN)
     return HandleCLRNotificationEvent();
 }
 
+#else // FEATURE_PAL
+
+HRESULT HandleExceptionNotification(ILLDBServices *client)
+{
+    INIT_API();
+    return HandleCLRNotificationEvent();
+}
+
+#endif // FEATURE_PAL
+
 DECLARE_API(bpmd)
 {
     INIT_API();    
@@ -7389,7 +7401,7 @@ DECLARE_API(bpmd)
             flags |= (CLRDATA_NOTIFY_ON_MODULE_LOAD | CLRDATA_NOTIFY_ON_MODULE_UNLOAD);
             g_clrData->SetOtherNotificationFlags(flags);
         }
-        Status = g_ExtClient->SetExceptionCallback(HandleExceptionNotification);
+        Status = g_ExtServices->SetExceptionCallback(HandleExceptionNotification);
 #endif // FEATURE_PAL
     }
 
@@ -8130,7 +8142,6 @@ BOOL gatherEh(UINT clauseIndex,UINT totalClauses,DACEHInfo *pEHInfo,LPVOID token
     return TRUE;
 }
 
-#ifndef FEATURE_PAL
 
 /**********************************************************************\
 * Routine Description:                                                 *
@@ -8155,11 +8166,15 @@ DECLARE_API(u)
 
     CMDOption option[] = 
     {   // name, vptr, type, hasValue
+#ifndef FEATURE_PAL
         {"-gcinfo", &fWithGCInfo, COBOOL, FALSE},
+#endif
         {"-ehinfo", &fWithEHInfo, COBOOL, FALSE},
         {"-n", &bSuppressLines, COBOOL, FALSE},
         {"-o", &bDisplayOffsets, COBOOL, FALSE},
+#ifndef FEATURE_PAL
         {"/d", &dml, COBOOL, FALSE},
+#endif
     };
     CMDValue arg[] = 
     {   // vptr, type
@@ -8421,8 +8436,6 @@ DECLARE_API(u)
     return Status;
 }
 
-#endif // FEATURE_PAL
-
 /**********************************************************************\
 * Routine Description:                                                 *
 *                                                                      *
@@ -11994,7 +12007,7 @@ void PrintRef(const SOSStackRefData &ref, TableOutput &out)
 class ClrStackImpl
 {
 public:
-    static void PrintThread(ULONG osID, BOOL bParams, BOOL bLocals, BOOL bSuppressLines, BOOL bGC)
+    static void PrintThread(ULONG osID, BOOL bParams, BOOL bLocals, BOOL bSuppressLines, BOOL bGC, BOOL bFull)
     {
         // Symbols variables
         ULONG symlines = 0; // symlines will be non-zero only if SYMOPT_LOAD_LINES was set in the symbol options
@@ -12014,6 +12027,21 @@ public:
             ExtOut("Failed to start stack walk: %lx\n", hr);
             return;
         }
+
+#ifdef _TARGET_WIN64_
+        PDEBUG_STACK_FRAME currentNativeFrame = NULL;
+        ULONG numNativeFrames = 0;
+        if (bFull)
+        {
+            hr = GetContextStackTrace(&numNativeFrames);
+            if (FAILED(hr))
+            {
+                ExtOut("Failed to get native stack frames: %lx\n", hr);
+                return;
+            }
+            currentNativeFrame = &g_Frames[0];
+        }
+#endif // _TARGET_WIN64_
         
         unsigned int refCount = 0, errCount = 0;
         ArrayHolder<SOSStackRefData> pRefs = NULL;
@@ -12039,15 +12067,29 @@ public:
             if (SUCCEEDED(frameDataResult) && FrameData.frameAddr)
                 sp = FrameData.frameAddr;
 
-            // Print the stack and instruction pointers.
+#ifdef _TARGET_WIN64_
+            while ((numNativeFrames > 0) && (currentNativeFrame->StackOffset <= sp))
+            {
+                if (currentNativeFrame->StackOffset != sp)
+                {
+                    PrintNativeStackFrame(out, currentNativeFrame, bSuppressLines);
+                }
+                currentNativeFrame++;
+                numNativeFrames--;
+            }
+#endif // _TARGET_WIN64_
+
+            // Print the stack pointer.
             out.WriteColumn(0, sp);
-            out.WriteColumn(1, InstructionPtr(ip));
 
             // Print the method/Frame info
             if (SUCCEEDED(frameDataResult) && FrameData.frameAddr)
             {
+                // Skip the instruction pointer because it doesn't really mean anything for method frames
+                out.WriteColumn(1, bFull ? String("") : InstructionPtr(ip));
+                
                 // This is a clr!Frame.
-                out.WriteColumn(2, GetFrameFromAddress(TO_TADDR(FrameData.frameAddr), pStackWalk));
+                out.WriteColumn(2, GetFrameFromAddress(TO_TADDR(FrameData.frameAddr), pStackWalk, bFull));
             
                 // Print out gc references for the Frame.  
                 for (unsigned int i = 0; i < refCount; ++i)
@@ -12061,7 +12103,8 @@ public:
             }
             else
             {
-                out.WriteColumn(2, MethodNameFromIP(ip, bSuppressLines));
+                out.WriteColumn(1, InstructionPtr(ip));
+                out.WriteColumn(2, MethodNameFromIP(ip, bSuppressLines, bFull, bFull));
                     
                 // Print out gc references.  refCount will be zero if bGC is false (or if we
                 // failed to fetch gc reference information).
@@ -12079,8 +12122,17 @@ public:
             }
 
         } while (pStackWalk->Next() == S_OK);
+
+#ifdef _TARGET_WIN64_
+        while (numNativeFrames > 0)
+        {
+            PrintNativeStackFrame(out, currentNativeFrame, bSuppressLines);
+            currentNativeFrame++;
+            numNativeFrames--;
+        }
+#endif // _TARGET_WIN64_
     }
-    
+
     static HRESULT GetFrameLocation(IXCLRDataStackWalk *pStackWalk, CLRDATA_ADDRESS *ip, CLRDATA_ADDRESS *sp)
     {
         CROSS_PLATFORM_CONTEXT context;
@@ -12102,7 +12154,51 @@ public:
         return S_OK;
     }
     
-    static void PrintCurrentThread(BOOL bParams, BOOL bLocals, BOOL bSuppressLines, BOOL bGC)
+    static void PrintNativeStackFrame(TableOutput out, PDEBUG_STACK_FRAME frame, BOOL bSuppressLines)
+    {
+        char filename[MAX_PATH_FNAME + 1];
+        char symbol[1024];
+        ULONG64 displacement;
+
+        ULONG64 ip = frame->InstructionOffset;
+
+        out.WriteColumn(0, frame->StackOffset);
+        out.WriteColumn(1, InstructionPtr(ip));
+
+        HRESULT hr = g_ExtSymbols->GetNameByOffset(TO_CDADDR(ip), symbol, _countof(symbol), NULL, &displacement);
+        if (SUCCEEDED(hr) && symbol[0] != '\0')
+        {
+            String frameOutput;
+            frameOutput += symbol;
+
+            if (displacement)
+            {
+                frameOutput += " + ";
+                frameOutput += Decimal(displacement);
+            }
+
+            if (!bSuppressLines)
+            {
+                ULONG line;
+                hr = g_ExtSymbols->GetLineByOffset(TO_CDADDR(ip), &line, filename, _countof(filename), NULL, NULL);
+                if (SUCCEEDED(hr))
+                {
+                    frameOutput += " at ";
+                    frameOutput += filename;
+                    frameOutput += ":";
+                    frameOutput += Decimal(line);
+                }
+            }
+
+            out.WriteColumn(2, frameOutput);
+        }
+        else
+        {
+            out.WriteColumn(2, "");
+        }
+    }
+
+    static void PrintCurrentThread(BOOL bParams, BOOL bLocals, BOOL bSuppressLines, BOOL bGC, BOOL bNative)
     {
         ULONG id = 0;
         ULONG osid = 0;
@@ -12112,7 +12208,7 @@ public:
         g_ExtSystem->GetCurrentThreadId(&id);
         ExtOut("(%d)\n", id);
         
-        PrintThread(osid, bParams, bLocals, bSuppressLines, bGC);
+        PrintThread(osid, bParams, bLocals, bSuppressLines, bGC, bNative);
     }
 private: 
 
@@ -12523,6 +12619,7 @@ DECLARE_API(ClrStack)
     BOOL bICorDebug = FALSE;
     BOOL bGC = FALSE;
     BOOL dml = FALSE;
+    BOOL bFull = FALSE;
     DWORD frameToDumpVariablesFor = -1;
     StringHolder cvariableName;
     ArrayHolder<WCHAR> wvariableName = new NOTHROW WCHAR[mdNameLen];
@@ -12543,6 +12640,7 @@ DECLARE_API(ClrStack)
         {"-n", &bSuppressLines, COBOOL, FALSE},
         {"-i", &bICorDebug, COBOOL, FALSE},
         {"-gc", &bGC, COBOOL, FALSE},
+        {"-f", &bFull, COBOOL, FALSE},
 #ifndef FEATURE_PAL
         {"/d", &dml, COBOOL, FALSE},
 #endif
@@ -12593,7 +12691,7 @@ DECLARE_API(ClrStack)
         return ClrStackImplWithICorDebug::ClrStackFromPublicInterface(bParams, bLocals, FALSE, wvariableName, frameToDumpVariablesFor);
     }
     
-    ClrStackImpl::PrintCurrentThread(bParams, bLocals, bSuppressLines, bGC);
+    ClrStackImpl::PrintCurrentThread(bParams, bLocals, bSuppressLines, bGC, bFull);
     
     return S_OK;
 }
@@ -12934,14 +13032,11 @@ static HRESULT DumpMDInfoBuffer(DWORD_PTR dwStartAddr, DWORD Flags, ULONG64 Esp,
         return E_FAIL;
     }
 
-    static WCHAR wszNameBuffer[1024]; // should be large enough
+    ArrayHolder<WCHAR> wszNameBuffer = new WCHAR[MAX_LONGPATH+1];
 
     if (Flags & SOS_STACKTRACE_SHOWADDRESSES)
     {
-        _snwprintf_s(wszNameBuffer, _countof(wszNameBuffer), _countof(wszNameBuffer)-1, W("%p %p "), 
-                    (void*)(size_t) Esp, 
-                    (void*)(size_t) IPAddr); // _TRUNCATE
-
+        _snwprintf_s(wszNameBuffer, MAX_LONGPATH, MAX_LONGPATH, W("%p %p "), (void*)(size_t) Esp, (void*)(size_t) IPAddr); // _TRUNCATE
         DOAPPEND(wszNameBuffer);
     }
 
@@ -12961,35 +13056,42 @@ static HRESULT DumpMDInfoBuffer(DWORD_PTR dwStartAddr, DWORD Flags, ULONG64 Esp,
     }
     ULONG Index;
     ULONG64 base;
-    if (g_ExtSymbols->GetModuleByOffset(UL64_TO_CDA(addrInModule), 0, &Index, 
-        &base) == S_OK)
+    if (g_ExtSymbols->GetModuleByOffset(UL64_TO_CDA(addrInModule), 0, &Index, &base) == S_OK)
     {                                    
-        CHAR ModuleName[MAX_LONGPATH+1];
-
-        if (g_ExtSymbols->GetModuleNames (Index, base,
-            NULL, 0, NULL,
-            ModuleName, MAX_LONGPATH, NULL,
-            NULL, 0, NULL) == S_OK)
-        {
-            MultiByteToWideChar (CP_ACP, 
-                    0, 
-                    ModuleName, 
-                    -1, 
-                    wszNameBuffer, 
-                    ARRAYSIZE(wszNameBuffer));
+        ArrayHolder<char> szModuleName = new char[MAX_LONGPATH+1];
+        if (g_ExtSymbols->GetModuleNames(Index, base, NULL, 0, NULL, szModuleName, MAX_LONGPATH, NULL, NULL, 0, NULL) == S_OK)
+        {
+            MultiByteToWideChar (CP_ACP, 0, szModuleName, MAX_LONGPATH, wszNameBuffer, MAX_LONGPATH);
             DOAPPEND (wszNameBuffer);
             bModuleNameWorked = TRUE;
         }
     }
+#ifdef FEATURE_PAL
+    else
+    {
+        if (g_sos->GetPEFileName(dmd.File, MAX_LONGPATH, wszNameBuffer, NULL) == S_OK)
+        {
+            if (wszNameBuffer[0] != W('\0'))
+            {
+                WCHAR *pJustName = _wcsrchr(wszNameBuffer, DIRECTORY_SEPARATOR_CHAR_W);
+                if (pJustName == NULL)
+                    pJustName = wszNameBuffer - 1;
 
-    // Under certain circumstances DacpMethodDescData::GetMethodName() 
+                DOAPPEND(pJustName + 1);
+                bModuleNameWorked = TRUE;
+            }
+        }
+    }
+#endif // FEATURE_PAL
+
+    // Under certain circumstances DacpMethodDescData::GetMethodDescName() 
     //   returns a module qualified method name
-    HRESULT hr = g_sos->GetMethodDescName(dwStartAddr, 1024, wszNameBuffer, NULL);
+    HRESULT hr = g_sos->GetMethodDescName(dwStartAddr, MAX_LONGPATH, wszNameBuffer, NULL);
 
     WCHAR* pwszMethNameBegin = (hr != S_OK ? NULL : _wcschr(wszNameBuffer, L'!'));
     if (!bModuleNameWorked && hr == S_OK && pwszMethNameBegin != NULL)
     {
-        // if we weren't able to get the module name, but GetMethodName returned
+        // if we weren't able to get the module name, but GetMethodDescName returned
         // the module as part of the returned method name, use this data
         DOAPPEND(wszNameBuffer);
     }
@@ -13003,8 +13105,8 @@ static HRESULT DumpMDInfoBuffer(DWORD_PTR dwStartAddr, DWORD Flags, ULONG64 Esp,
         if (hr == S_OK)
         {
             // the module name we retrieved above from debugger will take 
-            // precedence over the name possibly returned by GetMethodName()
-            DOAPPEND(pwszMethNameBegin != NULL ? (pwszMethNameBegin+1) : wszNameBuffer);
+            // precedence over the name possibly returned by GetMethodDescName()
+            DOAPPEND(pwszMethNameBegin != NULL ? (pwszMethNameBegin+1) : (WCHAR *)wszNameBuffer);
         }
         else
         {
@@ -13015,7 +13117,7 @@ static HRESULT DumpMDInfoBuffer(DWORD_PTR dwStartAddr, DWORD Flags, ULONG64 Esp,
     ULONG64 Displacement = (IPAddr - MethodDescData.NativeCodeAddr);
     if (Displacement)
     {
-        _snwprintf_s(wszNameBuffer,_countof (wszNameBuffer),  _countof (wszNameBuffer)-1, W("+%#x"), Displacement); // _TRUNCATE
+        _snwprintf_s(wszNameBuffer, MAX_LONGPATH, MAX_LONGPATH, W("+%#x"), Displacement); // _TRUNCATE
         DOAPPEND (wszNameBuffer);
     }
 
@@ -13023,8 +13125,6 @@ static HRESULT DumpMDInfoBuffer(DWORD_PTR dwStartAddr, DWORD Flags, ULONG64 Esp,
 #undef DOAPPEND
 }
 
-#ifndef FEATURE_PAL
-
 BOOL AppendContext(LPVOID pTransitionContexts, size_t maxCount, size_t *pcurCount, size_t uiSizeOfContext,
     CROSS_PLATFORM_CONTEXT *context)
 {
@@ -13053,7 +13153,7 @@ BOOL AppendContext(LPVOID pTransitionContexts, size_t maxCount, size_t *pcurCoun
 }
 
 HRESULT CALLBACK ImplementEFNStackTrace(
-    PDEBUG_CLIENT Client,
+    PDEBUG_CLIENT client,
     __out_ecount_opt(*puiTextLength) WCHAR wszTextOut[],
     size_t *puiTextLength,
     LPVOID pTransitionContexts,
@@ -13120,41 +13220,16 @@ HRESULT CALLBACK ImplementEFNStackTrace(
     }
 
 #ifdef _TARGET_WIN64_
-
     ULONG numFrames = 0;
-    PDEBUG_CONTROL4 g_ExtControl4 = NULL;
-    // Do we have advanced capability?
-    if ((Status = g_ExtControl->QueryInterface(__uuidof(IDebugControl4),
-                                 (void **)&g_ExtControl4)) == S_OK)
-    {
-        // GetContextStackTrace fills g_X64FrameContexts as an array of 
-        // contexts packed as target architecture contexts. We cannot 
-        // safely cast this as an array of CROSS_PLATFORM_CONTEXT, since 
-        // sizeof(CROSS_PLATFORM_CONTEXT) != sizeof(TGT_CONTEXT)
-        Status = g_ExtControl4->GetContextStackTrace(
-            NULL,
-            0,
-            g_Frames,
-            MAX_STACK_FRAMES,
-            g_X64FrameContexts,
-            MAX_STACK_FRAMES*g_targetMachine->GetContextSize(),
-            g_targetMachine->GetContextSize(),
-            &numFrames
-            );
-    }
-    else
-    {
-        // The new interface is required for context information
-        goto Exit;
-    }
+    BOOL bInNative = TRUE;
 
+    Status = GetContextStackTrace(&numFrames);
     if (FAILED(Status))
     {
         goto Exit;
     }
 
-    BOOL bInNative = TRUE;
-    for (ULONG i=0; i < numFrames; i++)
+    for (ULONG i = 0; i < numFrames; i++)
     {
         PDEBUG_STACK_FRAME pCur = g_Frames + i;                
 
@@ -13216,11 +13291,6 @@ HRESULT CALLBACK ImplementEFNStackTrace(
     }
 
 Exit:
-    if (g_ExtControl4)
-    {
-        g_ExtControl4->Release();
-        g_ExtControl4 = NULL;
-    }
 #else // _TARGET_WIN64_
 
 #ifdef _DEBUG
@@ -13364,9 +13434,15 @@ Exit:
     return Status;
 }
 
+#ifdef FEATURE_PAL
+#define PAL_TRY_NAKED PAL_CPP_TRY
+#define PAL_EXCEPT_NAKED(disp) PAL_CPP_CATCH_ALL
+#define PAL_ENDTRY_NAKED PAL_CPP_ENDTRY
+#endif
+
 // TODO: Convert PAL_TRY_NAKED to something that works on the Mac.
 HRESULT CALLBACK ImplementEFNStackTraceTry(
-    PDEBUG_CLIENT Client,
+    PDEBUG_CLIENT client,
     __out_ecount_opt(*puiTextLength) WCHAR wszTextOut[],
     size_t *puiTextLength,
     LPVOID pTransitionContexts,
@@ -13378,7 +13454,7 @@ HRESULT CALLBACK ImplementEFNStackTraceTry(
 
     PAL_TRY_NAKED
     {
-        Status = ImplementEFNStackTrace(Client, wszTextOut, puiTextLength, 
+        Status = ImplementEFNStackTrace(client, wszTextOut, puiTextLength, 
             pTransitionContexts, puiTransitionContextCount,
             uiSizeOfContext, Flags);
     }
@@ -13392,7 +13468,7 @@ HRESULT CALLBACK ImplementEFNStackTraceTry(
 
 // See sos_stacktrace.h for the contract with the callers regarding the LPVOID arguments.
 HRESULT CALLBACK _EFN_StackTrace(
-    PDEBUG_CLIENT Client,
+    PDEBUG_CLIENT client,
     __out_ecount_opt(*puiTextLength) WCHAR wszTextOut[],
     size_t *puiTextLength,
     __out_bcount_opt(uiSizeOfContext*(*puiTransitionContextCount)) LPVOID pTransitionContexts,
@@ -13402,7 +13478,7 @@ HRESULT CALLBACK _EFN_StackTrace(
 {
     INIT_API();    
 
-    Status = ImplementEFNStackTraceTry(Client, wszTextOut, puiTextLength, 
+    Status = ImplementEFNStackTraceTry(client, wszTextOut, puiTextLength, 
         pTransitionContexts, puiTransitionContextCount,
         uiSizeOfContext, Flags);
 
@@ -13680,7 +13756,6 @@ HRESULT ImplementEFNGetManagedExcepStack(
     return Status;
 }
 
-#ifndef FEATURE_PAL
 // TODO: Enable this when ImplementEFNStackTraceTry is fixed.
 // This function, like VerifyDAC, exists for the purpose of testing
 // hard-to-get-to SOS APIs.
@@ -13748,7 +13823,7 @@ DECLARE_API(VerifyStackTrace)
     {
         size_t textLength = 0;
         size_t contextLength = 0;
-        Status = ImplementEFNStackTraceTry(Client,
+        Status = ImplementEFNStackTraceTry(client,
                                  NULL,
                                  &textLength,
                                  NULL,
@@ -13783,7 +13858,7 @@ DECLARE_API(VerifyStackTrace)
             return Status;
         }
 
-        Status = ImplementEFNStackTrace(Client,
+        Status = ImplementEFNStackTrace(client,
                                  wszBuffer,
                                  &textLength,
                                  pContexts,
@@ -13841,7 +13916,7 @@ DECLARE_API(VerifyStackTrace)
             return Status;
         }
 
-        Status = ImplementEFNStackTrace(Client,
+        Status = ImplementEFNStackTrace(client,
                                  wszBuffer,
                                  &textLength,
                                  pSimple,
@@ -13886,9 +13961,8 @@ DECLARE_API(VerifyStackTrace)
 
     return Status;
 }
-#endif // !FEATURE_PAL
-
 
+#ifndef FEATURE_PAL
 
 // This is an internal-only Apollo extension to de-optimize the code
 DECLARE_API(SuppressJitOptimization)
@@ -14093,12 +14167,14 @@ DECLARE_API(ExposeDML)
     return S_OK;
 }
 
+#endif // FEATURE_PAL
+
 // According to kksharma the Windows debuggers always sign-extend
 // arguments when calling externally, therefore StackObjAddr 
 // conforms to CLRDATA_ADDRESS contract.
 HRESULT CALLBACK 
 _EFN_GetManagedExcepStack(
-    PDEBUG_CLIENT Client,
+    PDEBUG_CLIENT client,
     ULONG64 StackObjAddr,
    __out_ecount (cbString) PSTR szStackString,
     ULONG cbString
@@ -14129,7 +14205,7 @@ _EFN_GetManagedExcepStack(
 // same as _EFN_GetManagedExcepStack, but returns the stack as a wide string.
 HRESULT CALLBACK
 _EFN_GetManagedExcepStackW(
-    PDEBUG_CLIENT Client,
+    PDEBUG_CLIENT client,
     ULONG64 StackObjAddr,
     __out_ecount(cchString) PWSTR wszStackString,
     ULONG cchString
@@ -14145,7 +14221,7 @@ _EFN_GetManagedExcepStackW(
 // conforms to CLRDATA_ADDRESS contract.
 HRESULT CALLBACK 
 _EFN_GetManagedObjectName(
-    PDEBUG_CLIENT Client,
+    PDEBUG_CLIENT client,
     ULONG64 objAddr,
     __out_ecount (cbName) PSTR szName,
     ULONG cbName
@@ -14173,7 +14249,7 @@ _EFN_GetManagedObjectName(
 // conforms to CLRDATA_ADDRESS contract.
 HRESULT CALLBACK 
 _EFN_GetManagedObjectFieldInfo(
-    PDEBUG_CLIENT Client,
+    PDEBUG_CLIENT client,
     ULONG64 objAddr,
     __out_ecount (mdNameLen) PSTR szFieldName,
     PULONG64 pValue,
@@ -14225,8 +14301,6 @@ _EFN_GetManagedObjectFieldInfo(
     return S_OK;
 }
 
-#endif // FEATURE_PAL
-
 void PrintHelp (__in_z LPCSTR pszCmdName)
 {
     static LPSTR pText = NULL;
@@ -14250,7 +14324,7 @@ void PrintHelp (__in_z LPCSTR pszCmdName)
             return;
         }
         char lpFilename[MAX_LONGPATH + 12]; // + 12 to make enough room for strcat function.
-        strcpy_s(lpFilename, _countof(lpFilename), g_ExtClient->GetCoreClrDirectory());
+        strcpy_s(lpFilename, _countof(lpFilename), g_ExtServices->GetCoreClrDirectory());
         strcat_s(lpFilename, _countof(lpFilename), "sosdocsunix.txt");
         
         HANDLE hSosDocFile = CreateFileA(lpFilename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
@@ -14328,13 +14402,12 @@ void PrintHelp (__in_z LPCSTR pszCmdName)
 *    arguments passed into each.
 *                                                                      *
 \**********************************************************************/
-extern "C" HRESULT CALLBACK
-Help(PDEBUG_CLIENT Client, PCSTR Args)
+DECLARE_API(Help)
 {
     // Call extension initialization functions directly, because we don't need the DAC dll to be initialized to get help.
     HRESULT Status;
     __ExtensionCleanUp __extensionCleanUp;
-    if ((Status = ExtQuery(Client)) != S_OK) return Status;
+    if ((Status = ExtQuery(client)) != S_OK) return Status;
     ControlC = FALSE;
 
     StringHolder commandName;
@@ -14343,7 +14416,7 @@ Help(PDEBUG_CLIENT Client, PCSTR Args)
         {&commandName.data, COSTRING}
     };
     size_t nArg;
-    if (!GetCMDOption(Args, NULL, 0, arg, _countof(arg), &nArg))
+    if (!GetCMDOption(args, NULL, 0, arg, _countof(arg), &nArg))
     {
         return Status;
     }
index 1763646..59ede3e 100644 (file)
@@ -2099,7 +2099,7 @@ HRESULT FileNameForModule (DacpModuleData *pModule, __out_ecount (MAX_LONGPATH)
         hr = g_sos->GetPEFileName(dwAddr, MAX_LONGPATH, fileName, NULL);
         if (SUCCEEDED(hr))
         {
-            if (fileName[0] != L'\0')
+            if (fileName[0] != W('\0'))
                 return hr; // done
         }
 #ifndef FEATURE_PAL
@@ -4165,7 +4165,7 @@ HRESULT LoadClrDebugDll(void)
             return E_FAIL;
         }
         char dacModulePath[MAX_LONGPATH];
-        strcpy_s(dacModulePath, _countof(dacModulePath), g_ExtClient->GetCoreClrDirectory());
+        strcpy_s(dacModulePath, _countof(dacModulePath), g_ExtServices->GetCoreClrDirectory());
         strcat_s(dacModulePath, _countof(dacModulePath), MAKEDLLNAME_A("mscordaccore"));
 
         HMODULE hdac = LoadLibraryA(dacModulePath);
@@ -4446,7 +4446,7 @@ public:
         return hr;
 #else
         WCHAR modulePath[MAX_LONGPATH];
-        int length = MultiByteToWideChar(CP_ACP, 0, g_ExtClient->GetCoreClrDirectory(), -1, modulePath, _countof(modulePath));
+        int length = MultiByteToWideChar(CP_ACP, 0, g_ExtServices->GetCoreClrDirectory(), -1, modulePath, _countof(modulePath));
         if (0 >= length)
         {
             ExtOut("MultiByteToWideChar(coreclrDirectory) failed. Last error = 0x%x\n", GetLastError());
@@ -4657,11 +4657,11 @@ public:
     //
     virtual HRESULT STDMETHODCALLTYPE VirtualUnwind(DWORD threadId, ULONG32 contextSize, PBYTE context)
     {
-        if (g_ExtClient == NULL)
+        if (g_ExtServices == NULL)
         {
             return E_UNEXPECTED;
         }
-        return g_ExtClient->VirtualUnwind(threadId, contextSize, context);
+        return g_ExtServices->VirtualUnwind(threadId, contextSize, context);
 
     }
 #endif // FEATURE_PAL
@@ -5866,6 +5866,8 @@ ConvertNativeToIlOffset(
     return Status;
 }
 
+#endif // FEATURE_PAL
+
 // Based on a native offset, passed in the first argument this function
 // identifies the corresponding source file name and line number.
 HRESULT
@@ -5878,6 +5880,7 @@ GetLineByOffset(
     HRESULT hr = S_OK;
     ULONG64 displacement = 0;
 
+#ifndef FEATURE_PAL
     // first let's try it the hard way, this will work with the public debuggers
     {
         ImageInfo Image = {0};
@@ -5947,7 +5950,7 @@ GetLineByOffset(
     }
 
 fallback:
-    // 
+#endif // FEATURE_PAL
     return g_ExtSymbols->GetLineByOffset(
                     Offset, 
                     pLinenum,
@@ -5957,7 +5960,6 @@ fallback:
                     &displacement);
 }
 
-#endif // FEATURE_PAL
 
 void TableOutput::ReInit(int numColumns, int defaultColumnWidth, Alignment alignmentDefault, int indent, int padding)
 {
@@ -6457,7 +6459,32 @@ HRESULT SymbolReader::ResolveSequencePoint(__in_z WCHAR* pFilename, ULONG32 line
     return E_FAIL;
 }
 
-WString GetFrameFromAddress(TADDR frameAddr, IXCLRDataStackWalk *pStackWalk)
+static void AddAssemblyName(WString& methodOutput, CLRDATA_ADDRESS mdesc)
+{
+    DacpMethodDescData mdescData;
+    if (SUCCEEDED(mdescData.Request(g_sos, mdesc)))
+    {
+        DacpModuleData dmd;
+        if (SUCCEEDED(dmd.Request(g_sos, mdescData.ModulePtr)))
+        {
+            ArrayHolder<WCHAR> wszFileName = new WCHAR[MAX_LONGPATH+1];
+            if (SUCCEEDED(g_sos->GetPEFileName(dmd.File, MAX_LONGPATH, wszFileName, NULL)))
+            {
+                if (wszFileName[0] != W('\0'))
+                {
+                    WCHAR *pJustName = _wcsrchr(wszFileName, DIRECTORY_SEPARATOR_CHAR_W);
+                    if (pJustName == NULL)
+                        pJustName = wszFileName - 1;
+
+                    methodOutput += (pJustName + 1);
+                    methodOutput += W("!");
+                }
+            }
+        }
+    }
+}
+
+WString GetFrameFromAddress(TADDR frameAddr, IXCLRDataStackWalk *pStackWalk, BOOL bAssemblyName)
 {
     TADDR vtAddr;
     MOVE(vtAddr, frameAddr);
@@ -6477,9 +6504,17 @@ WString GetFrameFromAddress(TADDR frameAddr, IXCLRDataStackWalk *pStackWalk)
     if (SUCCEEDED(g_sos->GetMethodDescPtrFromFrame(frameAddr, &mdesc)))
     {
         if (SUCCEEDED(g_sos->GetMethodDescName(mdesc, mdNameLen, g_mdName, NULL)))
+        {
+            if (bAssemblyName)
+            {
+                AddAssemblyName(frameOutput, mdesc);
+            }
             frameOutput += g_mdName;
+        }
         else
+        {
             frameOutput += W("<unknown method>");
+        }
     }
     else if (pStackWalk)
     {
@@ -6503,9 +6538,8 @@ WString GetFrameFromAddress(TADDR frameAddr, IXCLRDataStackWalk *pStackWalk)
     return frameOutput;
 }
 
-WString MethodNameFromIP(CLRDATA_ADDRESS ip, BOOL bSuppressLines)
+WString MethodNameFromIP(CLRDATA_ADDRESS ip, BOOL bSuppressLines, BOOL bAssemblyName, BOOL bDisplacement)
 {
-    ArrayHolder<char> filename = new char[MAX_LONGPATH+1];
     ULONG linenum;
     WString methodOutput;
     CLRDATA_ADDRESS mdesc = 0;
@@ -6519,17 +6553,35 @@ WString MethodNameFromIP(CLRDATA_ADDRESS ip, BOOL bSuppressLines)
         DacpMethodDescData mdescData;
         if (SUCCEEDED(g_sos->GetMethodDescName(mdesc, mdNameLen, g_mdName, NULL)))
         {
+            if (bAssemblyName)
+            {
+                AddAssemblyName(methodOutput, mdesc);
+            }
+
             methodOutput += g_mdName;
+
+            if (bDisplacement)
+            {
+                if (SUCCEEDED(mdescData.Request(g_sos, mdesc)))
+                {
+                    ULONG64 disp = (ip - mdescData.NativeCodeAddr);
+                    if (disp)
+                    {
+                        methodOutput += W(" + ");
+                        methodOutput += Decimal(disp);
+                    }
+                }
+            }
         }
         else if (SUCCEEDED(mdescData.Request(g_sos, mdesc)))
         {
             DacpModuleData dmd;
             BOOL bModuleNameWorked = FALSE;
             ULONG64 addrInModule = ip;
-            if (dmd.Request(g_sos, mdescData.ModulePtr) == S_OK)
+            if (SUCCEEDED(dmd.Request(g_sos, mdescData.ModulePtr)))
             {
                 CLRDATA_ADDRESS peFileBase = 0;
-                if (g_sos->GetPEFileBase(dmd.File, &peFileBase) == S_OK)
+                if (SUCCEEDED(g_sos->GetPEFileBase(dmd.File, &peFileBase)))
                 {
                     if (peFileBase)
                     {
@@ -6539,22 +6591,13 @@ WString MethodNameFromIP(CLRDATA_ADDRESS ip, BOOL bSuppressLines)
             }
             ULONG Index;
             ULONG64 moduleBase;
-            if (g_ExtSymbols->GetModuleByOffset(UL64_TO_CDA(addrInModule), 0, &Index, 
-                &moduleBase) == S_OK)
+            if (SUCCEEDED(g_ExtSymbols->GetModuleByOffset(UL64_TO_CDA(addrInModule), 0, &Index, &moduleBase)))
             {                                    
-                CHAR ModuleName[MAX_LONGPATH+1];
+                ArrayHolder<char> szModuleName = new char[MAX_LONGPATH+1];
 
-                if (g_ExtSymbols->GetModuleNames (Index, moduleBase,
-                    NULL, 0, NULL,
-                    ModuleName, MAX_LONGPATH, NULL,
-                    NULL, 0, NULL) == S_OK)
+                if (SUCCEEDED(g_ExtSymbols->GetModuleNames(Index, moduleBase, NULL, 0, NULL, szModuleName, MAX_LONGPATH, NULL, NULL, 0, NULL)))
                 {
-                    MultiByteToWideChar (CP_ACP, 
-                            0, 
-                            ModuleName, 
-                            -1, 
-                            g_mdName, 
-                            _countof(g_mdName));
+                    MultiByteToWideChar (CP_ACP, 0, szModuleName, MAX_LONGPATH, g_mdName, _countof(g_mdName));
                     methodOutput += g_mdName;
                     methodOutput += W("!");
                 }
@@ -6566,17 +6609,17 @@ WString MethodNameFromIP(CLRDATA_ADDRESS ip, BOOL bSuppressLines)
             methodOutput = W("<unknown>");
         }
 
-#ifndef FEATURE_PAL
+        ArrayHolder<char> szFileName = new char[MAX_LONGPATH+1];
+
         if (!bSuppressLines &&
-            SUCCEEDED(GetLineByOffset(TO_CDADDR(ip), &linenum, filename, MAX_LONGPATH+1)))
+            SUCCEEDED(GetLineByOffset(TO_CDADDR(ip), &linenum, szFileName, MAX_LONGPATH)))
         {
-            int len = MultiByteToWideChar(CP_ACP, 0, filename, -1, NULL, 0);
-            ArrayHolder<WCHAR> wfilename = new WCHAR[len];
-            MultiByteToWideChar(CP_ACP, 0, filename, -1, wfilename, len);
+            int len = MultiByteToWideChar(CP_ACP, 0, szFileName, MAX_LONGPATH, NULL, 0);
+            ArrayHolder<WCHAR> wszFileName = new WCHAR[len];
+            MultiByteToWideChar(CP_ACP, 0, szFileName, MAX_LONGPATH, wszFileName, len);
             
-            methodOutput += WString(W(" [")) + wfilename + W(" @ ") + Decimal(linenum) + W("]");
+            methodOutput += WString(W(" [")) + wszFileName + W(" @ ") + Decimal(linenum) + W("]");
         }
-#endif // FEATURE_PAL
     }
     
     return methodOutput;
index 68a7232..47025ab 100644 (file)
@@ -2386,14 +2386,12 @@ public:
     HRESULT SymbolReader::ResolveSequencePoint(__in_z WCHAR* pFilename, ULONG32 lineNumber, mdMethodDef* pToken, ULONG32* pIlOffset);
 };
 
-#ifndef FEATURE_PAL
 HRESULT
 GetLineByOffset(
         ___in ULONG64 IP,
         ___out ULONG *pLinenum,
         __out_ecount(cbFileName) LPSTR lpszFileName,
         ___in ULONG cbFileName);
-#endif // FEATURE_PAL
 
 /// X86 Context
 #define X86_SIZE_OF_80387_REGISTERS      80
@@ -2690,9 +2688,9 @@ typedef struct _CROSS_PLATFORM_CONTEXT {
 
 
 WString BuildRegisterOutput(const SOSStackRefData &ref, bool printObj = true);
-WString MethodNameFromIP(CLRDATA_ADDRESS methodDesc, BOOL bSuppressLines=FALSE);
+WString MethodNameFromIP(CLRDATA_ADDRESS methodDesc, BOOL bSuppressLines = FALSE, BOOL bAssemblyName = FALSE, BOOL bDisplacement = FALSE);
 HRESULT GetGCRefs(ULONG osID, SOSStackRefData **ppRefs, unsigned int *pRefCnt, SOSStackRefError **ppErrors, unsigned int *pErrCount);
-WString GetFrameFromAddress(TADDR frameAddr, IXCLRDataStackWalk *pStackwalk=0);
+WString GetFrameFromAddress(TADDR frameAddr, IXCLRDataStackWalk *pStackwalk = NULL, BOOL bAssemblyName = FALSE);
 
 /* This cache is used to read data from the target process if the reads are known
  * to be sequential.
index 1ea53c1..28bd3d1 100644 (file)
@@ -2,6 +2,8 @@ project(sosplugin)
 
 set(CMAKE_INCLUDE_CURRENT_DIR ON)
 
+add_definitions(-DPAL_STDCPP_COMPAT -DBIT64)
+
 if(CLR_CMAKE_PLATFORM_ARCH_AMD64)
     add_definitions(-D_TARGET_AMD64_=1)
     add_definitions(-DDBG_TARGET_64BIT=1)
@@ -71,12 +73,17 @@ set(SOURCES
     soscommand.cpp
     setclrpathcommand.cpp
     setsostidcommand.cpp
-    coreruncommand.cpp
-    debugclient.cpp
-    ${CLR_DIR}/src/coreclr/hosts/unixcorerun/corerun.cpp
-    ${CLR_DIR}/src/coreclr/hosts/unixcoreruncommon/coreruncommon.cpp
+    services.cpp
 )
 
+if(UPPERCASE_CMAKE_BUILD_TYPE STREQUAL DEBUG)
+    list(APPEND SOURCES
+        coreruncommand.cpp
+        ${CLR_DIR}/src/coreclr/hosts/unixcorerun/corerun.cpp
+        ${CLR_DIR}/src/coreclr/hosts/unixcoreruncommon/coreruncommon.cpp
+    )
+endif(UPPERCASE_CMAKE_BUILD_TYPE STREQUAL DEBUG)
+
 add_library(sosplugin SHARED ${SOURCES})
 add_dependencies(sosplugin sos)
 
 
 //----------------------------------------------------------------------------
 //
-// Debugger engine interface subset implemented with LLDB APIs.
+// LLDB debugger services for sos
 //
 //----------------------------------------------------------------------------
 
-#ifndef __DBGENG_H__
-#define __DBGENG_H__
-
-#include <cstdarg>
+#ifndef __LLDBSERVICES_H__
+#define __LLDBSERVICES_H__
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-//----------------------------------------------------------------------------
-// IDebugControl2
-//----------------------------------------------------------------------------
-
-class IDebugControl2
-{
-public:
-    // Checks for a user interrupt, such a Ctrl-C
-    // or stop button.
-    // This method is reentrant.
-    virtual HRESULT GetInterrupt(
-        void) = 0;
-
-    // Sends output through clients
-    // output callbacks if the mask is allowed
-    // by the current output control mask and
-    // according to the output distribution
-    // settings.
-    virtual HRESULT Output(
-        ULONG mask,
-        PCSTR format, 
-        ...) = 0;
-
-    virtual HRESULT OutputVaList(
-        ULONG mask,
-        PCSTR format,
-        va_list args) = 0;
-
-    // The following methods allow direct control
-    // over the distribution of the given output
-    // for situations where something other than
-    // the default is desired.  These methods require
-    // extra work in the engine so they should
-    // only be used when necessary.
-    virtual HRESULT ControlledOutput(
-        ULONG outputControl,
-        ULONG mask,
-        PCSTR format,
-        ...) = 0;
-
-    virtual HRESULT ControlledOutputVaList(
-        ULONG outputControl,
-        ULONG mask,
-        PCSTR format,
-        va_list args) = 0;
-
-    // Returns information about the debuggee such
-    // as user vs. kernel, dump vs. live, etc.
-    virtual HRESULT GetDebuggeeType(
-        PULONG debugClass,
-        PULONG qualifier) = 0;
-
-    // Returns the page size for the currently executing
-    // processor context.  The page size may vary between
-    // processor types.
-    virtual HRESULT GetPageSize(
-        PULONG size) = 0;
-
-    // Returns the type of processor used in the
-    // 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
@@ -215,32 +119,6 @@ typedef struct _DEBUG_LAST_EVENT_INFO_EXCEPTION
     ULONG FirstChance;
 } DEBUG_LAST_EVENT_INFO_EXCEPTION, *PDEBUG_LAST_EVENT_INFO_EXCEPTION;
 
-//----------------------------------------------------------------------------
-// IDebugDataSpaces
-//----------------------------------------------------------------------------
-
-struct IDebugDataSpaces
-{
-public:
-    virtual HRESULT ReadVirtual(
-        ULONG64 offset,
-        PVOID buffer,
-        ULONG bufferSize,
-        PULONG bytesRead) = 0;
-
-    virtual HRESULT WriteVirtual(
-        ULONG64 offset,
-        PVOID buffer,
-        ULONG bufferSize,
-        PULONG bytesWritten) = 0;
-};
-
-typedef IDebugDataSpaces* PDEBUG_DATA_SPACES;
-
-//----------------------------------------------------------------------------
-// IDebugSymbols
-//----------------------------------------------------------------------------
-
 //
 // Information about a module.
 //
@@ -280,6 +158,20 @@ typedef struct _DEBUG_MODULE_PARAMETERS
     ULONG64 Reserved[2];
 } DEBUG_MODULE_PARAMETERS, *PDEBUG_MODULE_PARAMETERS;
 
+// FindSourceFile flags.
+#define DEBUG_FIND_SOURCE_DEFAULT      0x00000000
+// Returns fully-qualified paths only.  If this
+// is not set the path returned may be relative.
+#define DEBUG_FIND_SOURCE_FULL_PATH    0x00000001
+// Scans all the path elements for a match and
+// returns the one that has the most similarity
+// between the given file and the matching element.
+#define DEBUG_FIND_SOURCE_BEST_MATCH   0x00000002
+// Do not search source server paths.
+#define DEBUG_FIND_SOURCE_NO_SRCSRV    0x00000004
+// Restrict FindSourceFileAndToken to token lookup only.
+#define DEBUG_FIND_SOURCE_TOKEN_LOOKUP 0x00000008
+
 // A special value marking an offset that should not
 // be treated as a valid offset.  This is only used
 // in special situations where it is unlikely that
@@ -289,9 +181,197 @@ typedef struct _DEBUG_MODULE_PARAMETERS
 // General unspecified ID constant.
 #define DEBUG_ANY_ID 0xffffffff
 
-class IDebugSymbols
+typedef struct _DEBUG_STACK_FRAME
+{
+    ULONG64 InstructionOffset;
+    ULONG64 ReturnOffset;
+    ULONG64 FrameOffset;
+    ULONG64 StackOffset;
+    ULONG64 FuncTableEntry;
+    ULONG64 Params[4];
+    ULONG64 Reserved[6];
+    BOOL    Virtual;
+    ULONG   FrameNumber;
+} DEBUG_STACK_FRAME, *PDEBUG_STACK_FRAME;
+
+#define DBG_FRAME_DEFAULT                0 // the same as INLINE_FRAME_CONTEXT_INIT in dbghelp.h
+#define DBG_FRAME_IGNORE_INLINE 0xFFFFFFFF // the same as INLINE_FRAME_CONTEXT_IGNORE in dbghelp.h
+
+typedef struct _DEBUG_STACK_FRAME_EX
+{
+    // First DEBUG_STACK_FRAME structure
+    ULONG64 InstructionOffset;
+    ULONG64 ReturnOffset;
+    ULONG64 FrameOffset;
+    ULONG64 StackOffset;
+    ULONG64 FuncTableEntry;
+    ULONG64 Params[4];
+    ULONG64 Reserved[6];
+    BOOL    Virtual;
+    ULONG   FrameNumber;
+
+    // Extended DEBUG_STACK_FRAME fields.
+    ULONG InlineFrameContext;
+    ULONG Reserved1; // For alignment purpose.
+} DEBUG_STACK_FRAME_EX, *PDEBUG_STACK_FRAME_EX;
+
+// The types of inline frame context.
+#define STACK_FRAME_TYPE_INIT   0x00
+#define STACK_FRAME_TYPE_STACK  0x01
+#define STACK_FRAME_TYPE_INLINE 0x02
+#define STACK_FRAME_TYPE_RA     0x80 // Whether the instruction pointer is the current IP or a RA from callee frame.
+#define STACK_FRAME_TYPE_IGNORE 0xFF
+
+//
+// options that are set/returned by SymSetOptions() & SymGetOptions()
+// these are used as a mask
+//
+#define SYMOPT_LOAD_LINES                0x00000010
+
+interface ILLDBServices;
+typedef HRESULT (*PFN_EXCEPTION_CALLBACK)(ILLDBServices *services);
+
+//----------------------------------------------------------------------------
+// ILLDBServices
+//----------------------------------------------------------------------------
+
+MIDL_INTERFACE("2E6C569A-9E14-4DA4-9DFC-CDB73A532566")
+ILLDBServices : public IUnknown
 {
 public:
+    //----------------------------------------------------------------------------
+    // ILLDBServices
+    //----------------------------------------------------------------------------
+
+    // Returns the coreclr module directory found by lldb plugin 
+    // in the target process.
+    virtual PCSTR GetCoreClrDirectory() = 0;
+
+    // Evaluates a lldb expression into a value.
+    virtual DWORD_PTR GetExpression(
+        /* [in] */ PCSTR exp) = 0;
+
+    // Unwind one native stack frame given a thread and register context
+    virtual HRESULT VirtualUnwind(
+        /* [in] */ DWORD threadID,
+        /* [in] */ ULONG32 contextSize,
+        /* [in, out, size_is(contextSize)] */ PBYTE context) = 0;
+
+    // Set an exception throw callback
+    virtual HRESULT SetExceptionCallback(
+        /* [in] */ PFN_EXCEPTION_CALLBACK callback) = 0;
+
+    // Clear the exception throw callback
+    virtual HRESULT ClearExceptionCallback() = 0;
+
+    //------------------------------------------------
+    // IDebugControl2
+    //------------------------------------------------
+
+    // Checks for a user interrupt, such a Ctrl-C
+    // or stop button.
+    // This method is reentrant.
+    virtual HRESULT GetInterrupt(
+        void) = 0;
+
+    virtual HRESULT OutputVaList(
+        ULONG mask,
+        PCSTR format,
+        va_list args) = 0;
+
+    // Returns information about the debuggee such
+    // as user vs. kernel, dump vs. live, etc.
+    virtual HRESULT GetDebuggeeType(
+        PULONG debugClass,
+        PULONG qualifier) = 0;
+
+    // Returns the page size for the currently executing
+    // processor context.  The page size may vary between
+    // processor types.
+    virtual HRESULT GetPageSize(
+        PULONG size) = 0;
+
+    // Returns the type of processor used in the
+    // 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;
+
+    virtual HRESULT Disassemble(
+        ULONG64 offset,
+        ULONG flags,
+        PSTR buffer,
+        ULONG bufferSize,
+        PULONG disassemblySize,
+        PULONG64 endOffset) = 0;
+
+    //----------------------------------------------------------------------------
+    // IDebugControl4
+    //----------------------------------------------------------------------------
+
+    // Stack tracing with a full initial context
+    // and full context return for each frame.
+    // The FrameContextsSize parameter is the total
+    // byte size of FrameContexts.  FrameContextsEntrySize
+    // gives the byte size of each entry in
+    // FrameContexts.
+    virtual HRESULT GetContextStackTrace(
+        PVOID startContext,
+        ULONG startContextSize,
+        PDEBUG_STACK_FRAME frames,
+        ULONG framesSize,
+        PVOID frameContexts,
+        ULONG frameContextsSize,
+        ULONG frameContextsEntrySize,
+        PULONG framesFilled) = 0;
+    
+    //------------------------------------------------
+    // IDebugDataSpaces
+    //------------------------------------------------
+
+    virtual HRESULT ReadVirtual(
+        ULONG64 offset,
+        PVOID buffer,
+        ULONG bufferSize,
+        PULONG bytesRead) = 0;
+
+    virtual HRESULT WriteVirtual(
+        ULONG64 offset,
+        PVOID buffer,
+        ULONG bufferSize,
+        PULONG bytesWritten) = 0;
+
+    //------------------------------------------------
+    // IDebugSymbols
+    //------------------------------------------------
+
     // Controls the symbol options used during
     // symbol operations.
     // Uses the same flags as dbghelps SymSetOptions.
@@ -357,17 +437,45 @@ public:
         PSTR loadedImageNameBuffer,
         ULONG loadedImageNameBufferSize,
         PULONG loadedImageNameSize) = 0;
-};
 
-typedef class IDebugSymbols* PDEBUG_SYMBOLS;
-
-//----------------------------------------------------------------------------
-// IDebugSystemObjects
-//----------------------------------------------------------------------------
+    HRESULT virtual GetLineByOffset(
+        ULONG64 offset,
+        PULONG line,
+        PSTR fileBuffer,
+        ULONG fileBufferSize,
+        PULONG fileSize,
+        PULONG64 displacement) = 0;
+     
+    HRESULT virtual GetSourceFileLineOffsets(
+        PCSTR file,
+        PULONG64 buffer,
+        ULONG bufferLines,
+        PULONG fileLines) = 0;
+
+    // Uses the given file path and the source path
+    // information to try and locate an existing file.
+    // The given file path is merged with elements
+    // of the source path and checked for existence.
+    // If a match is found the element used is returned.
+    // A starting element can be specified to restrict
+    // the search to a subset of the path elements;
+    // this can be useful when checking for multiple
+    // matches along the source path.
+    // The returned element can be 1, indicating
+    // the file was found directly and not on the path.
+    HRESULT virtual FindSourceFile(
+        ULONG startElement,
+        PCSTR file,
+        ULONG flags,
+        PULONG foundElement,
+        PSTR buffer,
+        ULONG bufferSize,
+        PULONG foundSize) = 0;
+    
+    //------------------------------------------------
+    // IDebugSystemObjects
+    //------------------------------------------------
 
-class IDebugSystemObjects 
-{
-public:
     virtual HRESULT GetCurrentProcessId(
         PULONG id) = 0;
 
@@ -408,17 +516,11 @@ public:
         /* [in] */ ULONG32 contextFlags,
         /* [in] */ ULONG32 contextSize,
         /* [out, size_is(contextSize)] */ PBYTE context) = 0;
-};
 
-typedef class IDebugSystemObjects* PDEBUG_SYSTEM_OBJECTS;
+    //------------------------------------------------
+    // IDebugRegister
+    //------------------------------------------------
 
-//----------------------------------------------------------------------------
-// IDebugRegister
-//----------------------------------------------------------------------------
-
-class IDebugRegister
-{
-public:
     // This is the combination of dbgeng's GetIndexByName and GetValue and not
     // actually part of the dbgeng's IDebugRegister interface.
     virtual HRESULT GetValueByName(
@@ -442,44 +544,8 @@ public:
         PULONG64 offset) = 0;
 };
 
-typedef class IDebugRegister* PDEBUG_REGISTERS;
-
-//----------------------------------------------------------------------------
-// IDebugClient
-//----------------------------------------------------------------------------
-
-class IDebugClient;
-typedef HRESULT (*PFN_EXCEPTION_CALLBACK)(IDebugClient* client);
-
-class IDebugClient : IDebugControl2, IDebugDataSpaces, IDebugSymbols, IDebugSystemObjects, IDebugRegister
-{
-public:
-    // Returns the coreclr module directory found by lldb plugin 
-    // in the target process.
-    virtual PCSTR GetCoreClrDirectory() = 0;
-
-    // Evaluates a lldb expression into a value.
-    virtual DWORD_PTR GetExpression(
-        /* [in] */ PCSTR exp) = 0;
-
-    // Unwind one native stack frame given a thread and register context
-    virtual HRESULT VirtualUnwind(
-        /* [in] */ DWORD threadID,
-        /* [in] */ ULONG32 contextSize,
-        /* [in, out, size_is(contextSize)] */ PBYTE context) = 0;
-
-    // Set an exception throw callback
-    virtual HRESULT SetExceptionCallback(
-        /* [in] */ PFN_EXCEPTION_CALLBACK callback) = 0;
-
-    // Clear the exception throw callback
-    virtual HRESULT ClearExceptionCallback() = 0;
-};
-
-typedef class IDebugClient* PDEBUG_CLIENT;
-
 #ifdef __cplusplus
 };
 #endif
 
-#endif // #ifndef __DBGENG_H__
+#endif // #ifndef __LLDBSERVICES_H__
index 6339019..b5eee92 100644 (file)
@@ -2,63 +2,21 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 // See the LICENSE file in the project root for more information.
 
-// Contains some definitions duplicated from pal.h, etc. because pal.h
-// has various conflicits with the linux standard runtime h files.
-//
-typedef void VOID;
-typedef VOID *PVOID;
+// Contains some definitions duplicated from pal.h, palrt.h, rpc.h, 
+// etc. because they have various conflicits with the linux standard
+// runtime h files like wchar_t, memcpy, etc.
 
-typedef int BOOL;
-typedef int LONG;   
-typedef unsigned int ULONG;
-typedef ULONG ULONG32;
-typedef ULONG *PULONG;
-typedef unsigned char BYTE;
-typedef unsigned char UCHAR;
-typedef BYTE *PBYTE;
-typedef unsigned short WORD;
-typedef unsigned short USHORT;
-typedef unsigned int DWORD;
-
-typedef long long LONG64;
-typedef unsigned long long ULONG64;
-typedef ULONG64 *PULONG64;
-
-typedef long long LONGLONG;
-typedef unsigned long long ULONGLONG;
-typedef ULONGLONG DWORD64;
-
-#ifdef DBG_TARGET_64BIT
-typedef ULONG64 ULONG_PTR, *PULONG_PTR;
-typedef ULONG64 DWORD_PTR, *PDWORD_PTR;
-#else
-typedef ULONG32 ULONG_PTR, *PULONG_PTR;
-typedef ULONG32 DWORD_PTR, *PDWORD_PTR;
-#endif
-
-typedef wchar_t WCHAR;
-typedef WCHAR *PWCHAR;
-typedef const WCHAR *PCWSTR;
-
-typedef const char *PCSTR;
-typedef char *PSTR;
-
-typedef int HRESULT;
+#include <../../../pal/inc/pal_mstypes.h>
 
 #define S_OK                             (HRESULT)0x00000000
 #define S_FALSE                          (HRESULT)0x00000001
 #define E_NOTIMPL                        (HRESULT)0x80004001
 #define E_FAIL                           (HRESULT)0x80004005
 #define E_INVALIDARG                     (HRESULT)0x80070057
+#define E_NOINTERFACE                    (HRESULT)0x80004002
 
 #define MAX_PATH                         260 
 
-#if defined(_MSC_VER) || defined(__llvm__)
-#define DECLSPEC_ALIGN(x)   __declspec(align(x))
-#else
-#define DECLSPEC_ALIGN(x) 
-#endif
-
 // Platform-specific library naming
 // 
 #ifdef __APPLE__
@@ -74,3 +32,75 @@ typedef int HRESULT;
 #define MAKEDLLNAME_W(name) u"lib" name u".so"
 #define MAKEDLLNAME_A(name)  "lib" name  ".so"
 #endif
+
+#if defined(_MSC_VER) || defined(__llvm__)
+#define DECLSPEC_ALIGN(x)   __declspec(align(x))
+#else
+#define DECLSPEC_ALIGN(x) 
+#endif
+
+#define interface struct
+#define DECLSPEC_UUID(x)    __declspec(uuid(x))
+#define DECLSPEC_NOVTABLE
+#define MIDL_INTERFACE(x)   struct DECLSPEC_UUID(x) DECLSPEC_NOVTABLE
+
+#ifdef __cplusplus
+#define REFGUID const GUID &
+#else
+#define REFGUID const GUID *
+#endif
+
+#ifdef __cplusplus
+extern "C++" {
+#include "string.h"
+#if !defined _SYS_GUID_OPERATOR_EQ_ && !defined _NO_SYS_GUID_OPERATOR_EQ_
+#define _SYS_GUID_OPERATOR_EQ_
+inline int IsEqualGUID(REFGUID rguid1, REFGUID rguid2)
+    { return !memcmp(&rguid1, &rguid2, sizeof(GUID)); }
+inline int operator==(REFGUID guidOne, REFGUID guidOther)
+    { return IsEqualGUID(guidOne,guidOther); }
+inline int operator!=(REFGUID guidOne, REFGUID guidOther)
+    { return !IsEqualGUID(guidOne,guidOther); }
+#endif
+};
+#endif // __cplusplus
+
+typedef GUID IID;
+#ifdef __cplusplus
+#define REFIID const IID &
+#else
+#define REFIID const IID *
+#endif
+#define IID_NULL GUID_NULL
+#define IsEqualIID(riid1, riid2) IsEqualGUID(riid1, riid2)
+
+MIDL_INTERFACE("00000000-0000-0000-C000-000000000046")
+IUnknown
+{
+public:
+    virtual HRESULT QueryInterface( 
+        REFIID riid,
+        void **ppvObject) = 0;
+        
+    virtual ULONG AddRef( void) = 0;
+        
+    virtual ULONG Release( void) = 0;
+};
+
+EXTERN_C
+inline
+LONG
+InterlockedIncrement(
+    LONG volatile *lpAddend)
+{
+    return __sync_add_and_fetch(lpAddend, (LONG)1);
+}
+
+EXTERN_C
+inline
+LONG
+InterlockedDecrement(
+    LONG volatile *lpAddend)
+{
+    return __sync_sub_and_fetch(lpAddend, (LONG)1);
+}
\ No newline at end of file
@@ -12,7 +12,8 @@ ULONG g_currentThreadIndex = -1;
 ULONG g_currentThreadSystemId = -1;
 char *g_coreclrDirectory;
 
-DebugClient::DebugClient(lldb::SBDebugger &debugger, lldb::SBCommandReturnObject &returnObject, lldb::SBProcess *process, lldb::SBThread *thread) : 
+LLDBServices::LLDBServices(lldb::SBDebugger &debugger, lldb::SBCommandReturnObject &returnObject, lldb::SBProcess *process, lldb::SBThread *thread) : 
+    m_ref(1),
     m_debugger(debugger),
     m_returnObject(returnObject),
     m_currentProcess(process),
@@ -21,11 +22,258 @@ DebugClient::DebugClient(lldb::SBDebugger &debugger, lldb::SBCommandReturnObject
     returnObject.SetStatus(lldb::eReturnStatusSuccessFinishResult);
 }
 
-DebugClient::~DebugClient()
+LLDBServices::~LLDBServices()
 {
 }
 
 //----------------------------------------------------------------------------
+// IUnknown
+//----------------------------------------------------------------------------
+
+HRESULT
+LLDBServices::QueryInterface(
+    REFIID InterfaceId,
+    PVOID* Interface
+    )
+{
+    if (InterfaceId == __uuidof(IUnknown) ||
+        InterfaceId == __uuidof(ILLDBServices))
+    {
+        *Interface = (ILLDBServices*)this;
+        AddRef();
+        return S_OK;
+    }
+    else
+    {
+        *Interface = NULL;
+        return E_NOINTERFACE;
+    }
+}
+
+ULONG
+LLDBServices::AddRef()
+{
+    LONG ref = InterlockedIncrement(&m_ref);    
+    return ref;
+}
+
+ULONG
+LLDBServices::Release()
+{
+    LONG ref = InterlockedDecrement(&m_ref);
+    if (ref == 0)
+    {
+        delete this;
+    }
+    return ref;
+}
+
+//----------------------------------------------------------------------------
+// ILLDBServices
+//----------------------------------------------------------------------------
+
+PCSTR
+LLDBServices::GetCoreClrDirectory()
+{
+    return g_coreclrDirectory;
+}
+
+DWORD_PTR
+LLDBServices::GetExpression(
+    PCSTR exp)
+{
+    if (exp == nullptr)
+    {
+        return 0;
+    }
+
+    lldb::SBFrame frame = GetCurrentFrame();
+    if (!frame.IsValid())
+    {
+        return 0;
+    }
+
+    DWORD_PTR result = 0;
+    lldb::SBError error;
+    std::string str;
+
+    // To be compatible with windbg/dbgeng, we need to emulate the default
+    // hex radix (because sos prints addresses and other hex values without
+    // the 0x) by first prepending 0x and if that fails use the actual
+    // undecorated expression.
+    str.append("0x");
+    str.append(exp);
+
+    result = GetExpression(frame, error, str.c_str());
+    if (error.Fail())
+    {
+        result = GetExpression(frame, error, exp);
+    }
+
+    return result;
+}
+
+// Internal function
+DWORD_PTR 
+LLDBServices::GetExpression(
+    /* const */ lldb::SBFrame& frame,
+    lldb::SBError& error,
+    PCSTR exp)
+{
+    DWORD_PTR result = 0;
+
+    lldb::SBValue value = frame.EvaluateExpression(exp, lldb::eNoDynamicValues);
+    if (value.IsValid())
+    {
+        result = value.GetValueAsUnsigned(error);
+    }
+
+    return result;
+}
+
+//
+// lldb doesn't have a way or API to unwind an arbitary context (IP, SP)
+// and return the next frame so we have to stick with the native frames
+// lldb has found and find the closest frame to the incoming context SP.
+//
+HRESULT 
+LLDBServices::VirtualUnwind(
+    DWORD threadID,
+    ULONG32 contextSize,
+    PBYTE context)
+{
+    lldb::SBProcess process;
+    lldb::SBThread thread;
+
+    if (context == NULL || contextSize < sizeof(DT_CONTEXT))
+    {
+        return E_INVALIDARG;
+    }
+
+    process = GetCurrentProcess();
+    if (!process.IsValid())
+    {
+        return E_FAIL;
+    }
+
+    thread = process.GetThreadByID(threadID);
+    if (!thread.IsValid())
+    {
+        return E_FAIL;
+    }
+
+    DT_CONTEXT *dtcontext = (DT_CONTEXT*)context;
+    lldb::SBFrame frameFound;
+
+#ifdef DBG_TARGET_AMD64
+    DWORD64 spToFind = dtcontext->Rsp;
+#elif DBG_TARGET_ARM
+    DWORD spToFind = dtcontext->Sp;
+#endif
+    
+    int numFrames = thread.GetNumFrames();
+    for (int i = 0; i < numFrames; i++)
+    {
+        lldb::SBFrame frame = thread.GetFrameAtIndex(i);
+        if (!frame.IsValid())
+        {
+            break;
+        }
+        lldb::addr_t sp = frame.GetSP();
+
+        if ((i + 1) < numFrames)
+        {
+            lldb::SBFrame frameNext = thread.GetFrameAtIndex(i + 1);
+            if (frameNext.IsValid())
+            {
+                lldb::addr_t spNext = frameNext.GetSP();
+
+                // An exact match of the current frame's SP would be nice
+                // but sometimes the incoming context is between lldb frames
+                if (spToFind >= sp && spToFind < spNext)
+                {
+                    frameFound = frameNext;
+                    break;
+                }
+            }
+        }
+    }
+
+    if (!frameFound.IsValid())
+    {
+        return E_FAIL;
+    }
+
+    GetContextFromFrame(frameFound, dtcontext);
+
+    return S_OK;
+}
+
+bool 
+ExceptionBreakpointCallback(
+    void *baton, 
+    lldb::SBProcess &process,
+    lldb::SBThread &thread, 
+    lldb::SBBreakpointLocation &location)
+{
+    lldb::SBDebugger debugger = process.GetTarget().GetDebugger();
+
+    // Send the normal and error output to stdout/stderr since we
+    // don't have a return object from the command interpreter.
+    lldb::SBCommandReturnObject result;
+    result.SetImmediateOutputFile(stdout);
+    result.SetImmediateErrorFile(stderr);
+
+    // Save the process and thread to be used by the current process/thread 
+    // helper functions.
+    LLDBServices* client = new LLDBServices(debugger, result, &process, &thread);
+    return ((PFN_EXCEPTION_CALLBACK)baton)(client) == S_OK;
+}
+
+lldb::SBBreakpoint g_exceptionbp;
+
+HRESULT 
+LLDBServices::SetExceptionCallback(
+    PFN_EXCEPTION_CALLBACK callback)
+{
+    if (!g_exceptionbp.IsValid())
+    {
+        lldb::SBTarget target = m_debugger.GetSelectedTarget();
+        if (!target.IsValid())
+        {
+            return E_FAIL;
+        }
+        lldb::SBBreakpoint exceptionbp = target.BreakpointCreateForException(lldb::LanguageType::eLanguageTypeC_plus_plus, false, true);
+        if (!exceptionbp.IsValid())
+        {
+            return E_FAIL;
+        }
+#ifdef FLAGS_ANONYMOUS_ENUM
+        exceptionbp.AddName("DoNotDeleteOrDisable");
+#endif
+        exceptionbp.SetCallback(ExceptionBreakpointCallback, (void *)callback);
+        g_exceptionbp = exceptionbp;
+    }
+    return S_OK;
+}
+
+HRESULT 
+LLDBServices::ClearExceptionCallback()
+{
+    if (g_exceptionbp.IsValid())
+    {
+        lldb::SBTarget target = m_debugger.GetSelectedTarget();
+        if (!target.IsValid())
+        {
+            return E_FAIL;
+        }
+        target.BreakpointDelete(g_exceptionbp.GetID());
+        g_exceptionbp = lldb::SBBreakpoint();
+    }
+    return S_OK;
+}
+
+//----------------------------------------------------------------------------
 // IDebugControl2
 //----------------------------------------------------------------------------
 
@@ -33,7 +281,7 @@ DebugClient::~DebugClient()
 // or stop button.
 // This method is reentrant.
 HRESULT 
-DebugClient::GetInterrupt()
+LLDBServices::GetInterrupt()
 {
     return E_FAIL;
 }
@@ -44,7 +292,7 @@ DebugClient::GetInterrupt()
 // according to the output distribution
 // settings.
 HRESULT 
-DebugClient::Output(
+LLDBServices::Output(
     ULONG mask,
     PCSTR format,
     ...)
@@ -57,7 +305,7 @@ DebugClient::Output(
 }
 
 HRESULT 
-DebugClient::OutputVaList(
+LLDBServices::OutputVaList(
     ULONG mask,
     PCSTR format,
     va_list args)
@@ -103,7 +351,7 @@ DebugClient::OutputVaList(
 // extra work in the engine so they should
 // only be used when necessary.
 HRESULT 
-DebugClient::ControlledOutput(
+LLDBServices::ControlledOutput(
     ULONG outputControl,
     ULONG mask,
     PCSTR format,
@@ -117,7 +365,7 @@ DebugClient::ControlledOutput(
 }
 
 HRESULT 
-DebugClient::ControlledOutputVaList(
+LLDBServices::ControlledOutputVaList(
     ULONG outputControl,
     ULONG mask,
     PCSTR format,
@@ -129,7 +377,7 @@ DebugClient::ControlledOutputVaList(
 // Returns information about the debuggee such
 // as user vs. kernel, dump vs. live, etc.
 HRESULT 
-DebugClient::GetDebuggeeType(
+LLDBServices::GetDebuggeeType(
     PULONG debugClass,
     PULONG qualifier)
 {
@@ -142,7 +390,7 @@ DebugClient::GetDebuggeeType(
 // processor context.  The page size may vary between
 // processor types.
 HRESULT 
-DebugClient::GetPageSize(
+LLDBServices::GetPageSize(
     PULONG size)
 {
     *size = 4096;
@@ -150,7 +398,7 @@ DebugClient::GetPageSize(
 }
 
 HRESULT 
-DebugClient::GetExecutingProcessorType(
+LLDBServices::GetExecutingProcessorType(
     PULONG type)
 {
     *type = IMAGE_FILE_MACHINE_AMD64;
@@ -158,7 +406,7 @@ DebugClient::GetExecutingProcessorType(
 }
 
 HRESULT 
-DebugClient::Execute(
+LLDBServices::Execute(
     ULONG outputControl,
     PCSTR command,
     ULONG flags)
@@ -178,7 +426,7 @@ DebugClient::Execute(
 #define VARIABLE_NAME "ExceptionRecord"
 
 HRESULT 
-DebugClient::GetLastEventInformation(
+LLDBServices::GetLastEventInformation(
     PULONG type,
     PULONG processId,
     PULONG threadId,
@@ -192,7 +440,7 @@ DebugClient::GetLastEventInformation(
     if (extraInformationSize < sizeof(DEBUG_LAST_EVENT_INFO_EXCEPTION) || 
         type == NULL || processId == NULL || threadId == NULL || extraInformationUsed == NULL) 
     {
-        return E_FAIL;
+        return E_INVALIDARG;
     }
 
     *type = DEBUG_EVENT_EXCEPTION;
@@ -260,9 +508,115 @@ DebugClient::GetLastEventInformation(
     return E_FAIL;
 }
 
+HRESULT 
+LLDBServices::Disassemble(
+    ULONG64 offset,
+    ULONG flags,
+    PSTR buffer,
+    ULONG bufferSize,
+    PULONG disassemblySize,
+    PULONG64 endOffset)
+{
+    lldb::SBInstruction instruction;
+    lldb::SBInstructionList list;
+    lldb::SBTarget target;
+    lldb::SBAddress address;
+    lldb::SBError error;
+    lldb::SBData data;
+    std::string str;
+    HRESULT hr = S_OK;
+    ULONG size = 0;
+    uint8_t byte;
+    int cch;
+
+    if (buffer == NULL)
+    {
+        hr = E_INVALIDARG;
+        goto exit;
+    }
+    *buffer = 0;
+
+    target = m_debugger.GetSelectedTarget();
+    if (!target.IsValid())
+    {
+        hr = E_INVALIDARG;
+        goto exit;
+    }
+    address = target.ResolveLoadAddress(offset);
+    if (!address.IsValid())
+    {
+        hr = E_INVALIDARG;
+        goto exit;
+    }
+    list = target.ReadInstructions(address, 1, "intel");
+    if (!list.IsValid())
+    {
+        hr = E_FAIL;
+        goto exit;
+    }
+    instruction = list.GetInstructionAtIndex(0);
+    if (!instruction.IsValid())
+    {
+        hr = E_FAIL;
+        goto exit;
+    }
+    cch = snprintf(buffer, bufferSize, "%016lx ", offset);
+    buffer += cch;
+    bufferSize -= cch;
+
+    size = instruction.GetByteSize();
+    data = instruction.GetData(target);
+    for (int i = 0; i < size && bufferSize > 0; i++)
+    {
+        byte = data.GetUnsignedInt8(error, i);
+        if (error.Fail())
+        {
+            hr = E_FAIL;
+            goto exit;
+        }
+        cch = snprintf(buffer, bufferSize, "%02x", byte);
+        buffer += cch;
+        bufferSize -= cch;
+    }
+    // Pad the data bytes to 16 chars
+    cch = size * 2;
+    while (bufferSize > 0)
+    {
+        *buffer++ = ' ';
+        bufferSize--;
+        if (++cch >= 21)
+            break;
+    } 
+
+    cch = snprintf(buffer, bufferSize, "%s", instruction.GetMnemonic(target));
+    buffer += cch;
+    bufferSize -= cch;
+
+    // Pad the mnemonic to 8 chars
+    while (bufferSize > 0)
+    {
+        *buffer++ = ' ';
+        bufferSize--;
+        if (++cch >= 8)
+            break;
+    } 
+    snprintf(buffer, bufferSize, "%s\n", instruction.GetOperands(target));
+
+exit:
+    if (disassemblySize != NULL)
+    {
+        *disassemblySize = size;
+    }
+    if (endOffset != NULL)
+    {
+        *endOffset = offset + size;
+    }
+    return hr;
+}
+
 // Internal output string function
 void
-DebugClient::OutputString(
+LLDBServices::OutputString(
     ULONG mask,
     PCSTR str)
 {
@@ -276,13 +630,102 @@ DebugClient::OutputString(
     // correctly.
     m_returnObject.Printf("%s", str);
 }
-
+
+//----------------------------------------------------------------------------
+// IDebugControl4
+//----------------------------------------------------------------------------
+
+HRESULT
+LLDBServices::GetContextStackTrace(
+    PVOID startContext,
+    ULONG startContextSize,
+    PDEBUG_STACK_FRAME frames,
+    ULONG framesSize,
+    PVOID frameContexts,
+    ULONG frameContextsSize,
+    ULONG frameContextsEntrySize,
+    PULONG framesFilled)
+{
+    DT_CONTEXT *currentContext = (DT_CONTEXT*)frameContexts;
+    PDEBUG_STACK_FRAME currentFrame = frames;
+    lldb::SBThread thread;
+    lldb::SBFrame frame;
+    ULONG cFrames = 0;
+    HRESULT hr = S_OK;
+
+    // Doesn't support a starting context
+    if (startContext != NULL || frames == NULL || frameContexts == NULL || frameContextsEntrySize != sizeof(DT_CONTEXT))
+    {
+        hr = E_INVALIDARG;
+        goto exit;
+    }
+
+    thread = GetCurrentThread();
+    if (!thread.IsValid())
+    {
+        hr = E_FAIL;
+        goto exit;
+    }
+
+    frame = thread.GetFrameAtIndex(0);
+    for (int i = 0; i < thread.GetNumFrames(); i++)
+    {
+        if (!frame.IsValid() || (cFrames > framesSize) || ((char *)currentContext > ((char *)frameContexts + frameContextsSize)))
+        {
+            break;
+        }
+        lldb::SBFrame framePrevious;
+        lldb::SBFrame frameNext;
+
+        currentFrame->InstructionOffset = frame.GetPC();
+        currentFrame->StackOffset = frame.GetSP();
+
+        currentFrame->FuncTableEntry = 0;
+        currentFrame->Params[0] = 0;
+        currentFrame->Params[1] = 0;
+        currentFrame->Params[2] = 0;
+        currentFrame->Params[3] = 0;
+        currentFrame->Virtual = i == 0 ? TRUE : FALSE;
+        currentFrame->FrameNumber = frame.GetFrameID();
+
+        frameNext = thread.GetFrameAtIndex(i + 1);
+        if (frameNext.IsValid())
+        {
+            currentFrame->ReturnOffset = frameNext.GetPC();
+        }
+
+        if (framePrevious.IsValid())
+        {
+            currentFrame->FrameOffset = framePrevious.GetSP();
+        }
+        else
+        {
+            currentFrame->FrameOffset = frame.GetSP();
+        }
+
+        GetContextFromFrame(frame, currentContext);
+
+        framePrevious = frame;
+        frame = frameNext;
+        currentContext++;
+        currentFrame++;
+        cFrames++;
+    }
+
+exit:
+    if (framesFilled != NULL)
+    {
+        *framesFilled = cFrames;
+    }
+    return hr;
+}
+    
 //----------------------------------------------------------------------------
 // IDebugDataSpaces
 //----------------------------------------------------------------------------
 
 HRESULT 
-DebugClient::ReadVirtual(
+LLDBServices::ReadVirtual(
     ULONG64 offset,
     PVOID buffer,
     ULONG bufferSize,
@@ -308,7 +751,7 @@ exit:
 }
 
 HRESULT 
-DebugClient::WriteVirtual(
+LLDBServices::WriteVirtual(
     ULONG64 offset,
     PVOID buffer,
     ULONG bufferSize,
@@ -338,23 +781,23 @@ exit:
 //----------------------------------------------------------------------------
 
 HRESULT 
-DebugClient::GetSymbolOptions(
+LLDBServices::GetSymbolOptions(
     PULONG options)
 {
-    *options = 0;
+    *options = SYMOPT_LOAD_LINES;
     return S_OK;
 }
 
 HRESULT 
-DebugClient::GetNameByOffset(
+LLDBServices::GetNameByOffset(
     ULONG64 offset,
     PSTR nameBuffer,
     ULONG nameBufferSize,
     PULONG nameSize,
     PULONG64 displacement)
 {
-    HRESULT hr = E_FAIL;
-    ULONG64 disp = 0;
+    ULONG64 disp = DEBUG_INVALID_OFFSET;
+    HRESULT hr = S_OK;
 
     lldb::SBTarget target;
     lldb::SBAddress address;
@@ -366,18 +809,21 @@ DebugClient::GetNameByOffset(
     target = m_debugger.GetSelectedTarget();
     if (!target.IsValid())
     {
+        hr = E_FAIL;
         goto exit;
     }
 
     address = target.ResolveLoadAddress(offset);
     if (!address.IsValid())
     {
+        hr = E_INVALIDARG;
         goto exit;
     }
 
     module = address.GetModule();
     if (!module.IsValid())
     {
+        hr = E_FAIL;
         goto exit;
     }
 
@@ -405,7 +851,6 @@ DebugClient::GetNameByOffset(
     }
 
     str.append(1, '\0');
-    hr = S_OK;
 
 exit:
     if (nameSize)
@@ -424,7 +869,7 @@ exit:
 }
 
 HRESULT 
-DebugClient::GetNumberModules(
+LLDBServices::GetNumberModules(
     PULONG loaded,
     PULONG unloaded)
 {
@@ -452,7 +897,7 @@ exit:
     return hr;
 }
 
-HRESULT DebugClient::GetModuleByIndex(
+HRESULT LLDBServices::GetModuleByIndex(
     ULONG index,
     PULONG64 base)
 {
@@ -484,7 +929,7 @@ exit:
 }
 
 HRESULT 
-DebugClient::GetModuleByModuleName(
+LLDBServices::GetModuleByModuleName(
     PCSTR name,
     ULONG startIndex,
     PULONG index,
@@ -539,7 +984,7 @@ exit:
 }
 
 HRESULT 
-DebugClient::GetModuleByOffset(
+LLDBServices::GetModuleByOffset(
     ULONG64 offset,
     ULONG startIndex,
     PULONG index,
@@ -598,7 +1043,7 @@ exit:
 }
 
 HRESULT 
-DebugClient::GetModuleNames(
+LLDBServices::GetModuleNames(
     ULONG index,
     ULONG64 base,
     PSTR imageNameBuffer,
@@ -611,9 +1056,9 @@ DebugClient::GetModuleNames(
     ULONG loadedImageNameBufferSize,
     PULONG loadedImageNameSize)
 {
-    HRESULT hr = S_OK;
     lldb::SBTarget target;
     lldb::SBFileSpec fileSpec;
+    HRESULT hr = S_OK;
 
     target = m_debugger.GetSelectedTarget();
     if (!target.IsValid())
@@ -687,8 +1132,117 @@ exit:
     return hr;
 }
 
+HRESULT 
+LLDBServices::GetLineByOffset(
+    ULONG64 offset,
+    PULONG fileLine,
+    PSTR fileBuffer,
+    ULONG fileBufferSize,
+    PULONG fileSize,
+    PULONG64 displacement)
+{
+    ULONG64 disp = DEBUG_INVALID_OFFSET;
+    HRESULT hr = S_OK;
+    ULONG line = 0;
+
+    lldb::SBTarget target;
+    lldb::SBAddress address;
+    lldb::SBFileSpec file;
+    lldb::SBLineEntry lineEntry;
+    std::string str;
+
+    target = m_debugger.GetSelectedTarget();
+    if (!target.IsValid())
+    {
+        hr = E_FAIL;
+        goto exit;
+    }
+
+    address = target.ResolveLoadAddress(offset);
+    if (!address.IsValid())
+    {
+        hr = E_INVALIDARG;
+        goto exit;
+    }
+
+    if (displacement)
+    {
+        lldb::SBSymbol symbol = address.GetSymbol();
+        if (symbol.IsValid())
+        {
+            lldb::SBAddress startAddress = symbol.GetStartAddress();
+            disp = address.GetOffset() - startAddress.GetOffset();
+        }
+    }
+
+    lineEntry = address.GetLineEntry();
+    if (!lineEntry.IsValid())
+    {
+        hr = E_FAIL;
+        goto exit;
+    }
+
+    line = lineEntry.GetLine();
+    file = lineEntry.GetFileSpec();
+    if (file.IsValid())
+    {
+        str.append(file.GetDirectory());
+        str.append(1, '/');
+        str.append(file.GetFilename());
+    }
+
+    str.append(1, '\0');
+
+exit:
+    if (fileLine)
+    {
+        *fileLine = line;
+    }
+    if (fileSize)
+    {
+        *fileSize = str.length();
+    }
+    if (fileBuffer)
+    {
+        str.copy(fileBuffer, fileBufferSize);
+    }
+    if (displacement)
+    {
+        *displacement = disp;
+    }
+    return hr;
+}
+HRESULT 
+LLDBServices::GetSourceFileLineOffsets(
+    PCSTR file,
+    PULONG64 buffer,
+    ULONG bufferLines,
+    PULONG fileLines)
+{
+    if (fileLines != NULL)
+    {
+        *fileLines = (ULONG)-1;
+    }
+    return E_NOTIMPL;
+}
+
+HRESULT 
+LLDBServices::FindSourceFile(
+    ULONG startElement,
+    PCSTR file,
+    ULONG flags,
+    PULONG foundElement,
+    PSTR buffer,
+    ULONG bufferSize,
+    PULONG foundSize)
+{
+    return E_NOTIMPL;
+}
+
+// Internal functions
 PCSTR
-DebugClient::GetModuleDirectory(
+LLDBServices::GetModuleDirectory(
     PCSTR name)
 {
     lldb::SBTarget target = m_debugger.GetSelectedTarget();
@@ -709,9 +1263,8 @@ DebugClient::GetModuleDirectory(
     return module.GetFileSpec().GetDirectory();
 }
 
-// Internal function
 ULONG64
-DebugClient::GetModuleBase(
+LLDBServices::GetModuleBase(
     /* const */ lldb::SBTarget& target,
     /* const */ lldb::SBModule& module)
 {
@@ -738,7 +1291,7 @@ DebugClient::GetModuleBase(
 //----------------------------------------------------------------------------
 
 HRESULT 
-DebugClient::GetCurrentProcessId(
+LLDBServices::GetCurrentProcessId(
     PULONG id)
 {
     if (id == NULL)  
@@ -758,7 +1311,7 @@ DebugClient::GetCurrentProcessId(
 }
 
 HRESULT 
-DebugClient::GetCurrentThreadId(
+LLDBServices::GetCurrentThreadId(
     PULONG id)
 {
     if (id == NULL)  
@@ -786,7 +1339,7 @@ DebugClient::GetCurrentThreadId(
 }
 
 HRESULT 
-DebugClient::SetCurrentThreadId(
+LLDBServices::SetCurrentThreadId(
     ULONG id)
 {
     lldb::SBProcess process = GetCurrentProcess();
@@ -804,7 +1357,7 @@ DebugClient::SetCurrentThreadId(
 }
 
 HRESULT 
-DebugClient::GetCurrentThreadSystemId(
+LLDBServices::GetCurrentThreadSystemId(
     PULONG sysId)
 {
     if (sysId == NULL)  
@@ -832,7 +1385,7 @@ DebugClient::GetCurrentThreadSystemId(
 }
 
 HRESULT 
-DebugClient::GetThreadIdBySystemId(
+LLDBServices::GetThreadIdBySystemId(
     ULONG sysId,
     PULONG threadId)
 {
@@ -877,7 +1430,7 @@ exit:
 }
 
 HRESULT 
-DebugClient::GetThreadContextById(
+LLDBServices::GetThreadContextById(
     /* in */ ULONG32 threadID,
     /* in */ ULONG32 contextFlags,
     /* in */ ULONG32 contextSize,
@@ -935,7 +1488,7 @@ exit:
 
 // Internal function
 void
-DebugClient::GetContextFromFrame(
+LLDBServices::GetContextFromFrame(
     /* const */ lldb::SBFrame& frame,
     DT_CONTEXT *dtcontext)
 {
@@ -990,7 +1543,7 @@ DebugClient::GetContextFromFrame(
 
 // Internal function
 DWORD_PTR 
-DebugClient::GetRegister(
+LLDBServices::GetRegister(
     /* const */ lldb::SBFrame& frame,
     const char *name)
 {
@@ -1007,7 +1560,7 @@ DebugClient::GetRegister(
 //----------------------------------------------------------------------------
 
 HRESULT
-DebugClient::GetValueByName(
+LLDBServices::GetValueByName(
     PCSTR name,
     PDWORD_PTR debugValue)
 {
@@ -1030,7 +1583,7 @@ DebugClient::GetValueByName(
 }
 
 HRESULT 
-DebugClient::GetInstructionOffset(
+LLDBServices::GetInstructionOffset(
     PULONG64 offset)
 {
     lldb::SBFrame frame = GetCurrentFrame();
@@ -1045,7 +1598,7 @@ DebugClient::GetInstructionOffset(
 }
 
 HRESULT 
-DebugClient::GetStackOffset(
+LLDBServices::GetStackOffset(
     PULONG64 offset)
 {
     lldb::SBFrame frame = GetCurrentFrame();
@@ -1060,7 +1613,7 @@ DebugClient::GetStackOffset(
 }
 
 HRESULT 
-DebugClient::GetFrameOffset(
+LLDBServices::GetFrameOffset(
     PULONG64 offset)
 {
     lldb::SBFrame frame = GetCurrentFrame();
@@ -1075,202 +1628,11 @@ DebugClient::GetFrameOffset(
 }
 
 //----------------------------------------------------------------------------
-// IDebugClient
-//----------------------------------------------------------------------------
-
-PCSTR
-DebugClient::GetCoreClrDirectory()
-{
-    return g_coreclrDirectory;
-}
-
-DWORD_PTR
-DebugClient::GetExpression(
-    PCSTR exp)
-{
-    if (exp == nullptr)
-    {
-        return 0;
-    }
-
-    lldb::SBFrame frame = GetCurrentFrame();
-    if (!frame.IsValid())
-    {
-        return 0;
-    }
-
-    DWORD_PTR result = 0;
-    lldb::SBError error;
-    std::string str;
-
-    // To be compatible with windbg/dbgeng, we need to emulate the default
-    // hex radix (because sos prints addresses and other hex values without
-    // the 0x) by first prepending 0x and if that fails use the actual
-    // undecorated expression.
-    str.append("0x");
-    str.append(exp);
-
-    result = GetExpression(frame, error, str.c_str());
-    if (error.Fail())
-    {
-        result = GetExpression(frame, error, exp);
-    }
-
-    return result;
-}
-
-// Internal function
-DWORD_PTR 
-DebugClient::GetExpression(
-    /* const */ lldb::SBFrame& frame,
-    lldb::SBError& error,
-    PCSTR exp)
-{
-    DWORD_PTR result = 0;
-
-    lldb::SBValue value = frame.EvaluateExpression(exp, lldb::eNoDynamicValues);
-    if (value.IsValid())
-    {
-        result = value.GetValueAsUnsigned(error);
-    }
-
-    return result;
-}
-
-HRESULT 
-DebugClient::VirtualUnwind(
-    DWORD threadID,
-    ULONG32 contextSize,
-    PBYTE context)
-{
-    lldb::SBProcess process;
-    lldb::SBThread thread;
-
-    if (context == NULL || contextSize < sizeof(DT_CONTEXT))
-    {
-        return E_FAIL;
-    }
-
-    process = GetCurrentProcess();
-    if (!process.IsValid())
-    {
-        return E_FAIL;
-    }
-
-    thread = process.GetThreadByID(threadID);
-    if (!thread.IsValid())
-    {
-        return E_FAIL;
-    }
-
-    DT_CONTEXT *dtcontext = (DT_CONTEXT*)context;
-    lldb::SBFrame frameFound;
-
-#ifdef DBG_TARGET_AMD64
-    DWORD64 spToFind = dtcontext->Rsp;
-#elif DBG_TARGET_ARM
-    DWORD spToFind = dtcontext->Sp;
-#endif
-    
-    int numFrames = thread.GetNumFrames();
-    for (int i = 0; i < numFrames; i++)
-    {
-        lldb::SBFrame frame = thread.GetFrameAtIndex(i);
-        if (!frame.IsValid())
-        {
-            break;
-        }
-
-        lldb::addr_t sp = frame.GetSP();
-
-        if (sp == spToFind && (i + 1) < numFrames)
-        {
-            // Get next frame after finding the match
-            frameFound = thread.GetFrameAtIndex(i + 1);
-            break;
-        }
-    }
-
-    if (!frameFound.IsValid())
-    {
-        return E_FAIL;
-    }
-
-    GetContextFromFrame(frameFound, dtcontext);
-
-    return S_OK;
-}
-
-bool 
-ExceptionBreakpointCallback(
-    void *baton, 
-    lldb::SBProcess &process,
-    lldb::SBThread &thread, 
-    lldb::SBBreakpointLocation &location)
-{
-    lldb::SBDebugger debugger = process.GetTarget().GetDebugger();
-
-    // Send the normal and error output to stdout/stderr since we
-    // don't have a return object from the command interpreter.
-    lldb::SBCommandReturnObject result;
-    result.SetImmediateOutputFile(stdout);
-    result.SetImmediateErrorFile(stderr);
-
-    // Save the process and thread to be used by the current process/thread 
-    // helper functions.
-    DebugClient* client = new DebugClient(debugger, result, &process, &thread);
-    return ((PFN_EXCEPTION_CALLBACK)baton)(client) == S_OK;
-}
-
-lldb::SBBreakpoint g_exceptionbp;
-
-HRESULT 
-DebugClient::SetExceptionCallback(
-    PFN_EXCEPTION_CALLBACK callback)
-{
-    if (!g_exceptionbp.IsValid())
-    {
-        lldb::SBTarget target = m_debugger.GetSelectedTarget();
-        if (!target.IsValid())
-        {
-            return E_FAIL;
-        }
-        lldb::SBBreakpoint exceptionbp = target.BreakpointCreateForException(lldb::LanguageType::eLanguageTypeC_plus_plus, false, true);
-        if (!exceptionbp.IsValid())
-        {
-            return E_FAIL;
-        }
-#ifdef FLAGS_ANONYMOUS_ENUM
-        exceptionbp.AddName("DoNotDeleteOrDisable");
-#endif
-        exceptionbp.SetCallback(ExceptionBreakpointCallback, (void *)callback);
-        g_exceptionbp = exceptionbp;
-    }
-    return S_OK;
-}
-
-HRESULT 
-DebugClient::ClearExceptionCallback()
-{
-    if (g_exceptionbp.IsValid())
-    {
-        lldb::SBTarget target = m_debugger.GetSelectedTarget();
-        if (!target.IsValid())
-        {
-            return E_FAIL;
-        }
-        target.BreakpointDelete(g_exceptionbp.GetID());
-        g_exceptionbp = lldb::SBBreakpoint();
-    }
-    return S_OK;
-}
-
-//----------------------------------------------------------------------------
 // Helper functions
 //----------------------------------------------------------------------------
 
 lldb::SBProcess
-DebugClient::GetCurrentProcess()
+LLDBServices::GetCurrentProcess()
 {
     lldb::SBProcess process;
 
@@ -1291,7 +1653,7 @@ DebugClient::GetCurrentProcess()
 }
 
 lldb::SBThread 
-DebugClient::GetCurrentThread()
+LLDBServices::GetCurrentThread()
 {
     lldb::SBThread thread;
 
@@ -1312,7 +1674,7 @@ DebugClient::GetCurrentThread()
 }
 
 lldb::SBFrame 
-DebugClient::GetCurrentFrame()
+LLDBServices::GetCurrentFrame()
 {
     lldb::SBFrame frame;
 
@@ -4,9 +4,10 @@
 
 #include <cstdarg>
 
-class DebugClient : public IDebugClient
+class LLDBServices : public ILLDBServices
 {
 private:
+    LONG m_ref;
     lldb::SBDebugger &m_debugger;
     lldb::SBCommandReturnObject &m_returnObject;
 
@@ -24,8 +25,39 @@ private:
     lldb::SBFrame GetCurrentFrame();
 
 public:
-    DebugClient(lldb::SBDebugger &debugger, lldb::SBCommandReturnObject &returnObject, lldb::SBProcess *process = nullptr, lldb::SBThread *thread = nullptr);
-    ~DebugClient();
+    LLDBServices(lldb::SBDebugger &debugger, lldb::SBCommandReturnObject &returnObject, lldb::SBProcess *process = nullptr, lldb::SBThread *thread = nullptr);
+    ~LLDBServices();
+    //----------------------------------------------------------------------------
+    // IUnknown
+    //----------------------------------------------------------------------------
+
+    HRESULT QueryInterface(
+        REFIID InterfaceId,
+        PVOID* Interface);
+
+    ULONG AddRef();
+
+    ULONG Release();
+
+    //----------------------------------------------------------------------------
+    // ILLDBServices
+    //----------------------------------------------------------------------------
+
+    PCSTR GetCoreClrDirectory();
+
+    DWORD_PTR GetExpression(
+        PCSTR exp);
+
+    HRESULT VirtualUnwind(
+        DWORD threadID,
+        ULONG32 contextSize,
+        PBYTE context);
+
+    HRESULT SetExceptionCallback(
+        PFN_EXCEPTION_CALLBACK callback);
+
+    HRESULT ClearExceptionCallback();
 
     //----------------------------------------------------------------------------
     // IDebugControl2
@@ -81,6 +113,29 @@ public:
         ULONG descriptionSize,
         PULONG descriptionUsed);
 
+    HRESULT Disassemble(
+        ULONG64 offset,
+        ULONG flags,
+        PSTR buffer,
+        ULONG bufferSize,
+        PULONG disassemblySize,
+        PULONG64 endOffset);
+
+    //----------------------------------------------------------------------------
+    // IDebugControl4
+    //----------------------------------------------------------------------------
+
+    HRESULT
+    GetContextStackTrace(
+        PVOID startContext,
+        ULONG startContextSize,
+        PDEBUG_STACK_FRAME frames,
+        ULONG framesSize,
+        PVOID frameContexts,
+        ULONG frameContextsSize,
+        ULONG frameContextsEntrySize,
+        PULONG framesFilled);
+    
     //----------------------------------------------------------------------------
     // IDebugDataSpaces
     //----------------------------------------------------------------------------
@@ -144,8 +199,28 @@ public:
         ULONG loadedImageNameBufferSize,
         PULONG loadedImageNameSize);
 
-    PCSTR GetModuleDirectory(
-        PCSTR name);
+    HRESULT GetLineByOffset(
+        ULONG64 offset,
+        PULONG line,
+        PSTR fileBuffer,
+        ULONG fileBufferSize,
+        PULONG fileSize,
+        PULONG64 displacement);
+     
+    HRESULT GetSourceFileLineOffsets(
+        PCSTR file,
+        PULONG64 buffer,
+        ULONG bufferLines,
+        PULONG fileLines);
+
+    HRESULT FindSourceFile(
+        ULONG startElement,
+        PCSTR file,
+        ULONG flags,
+        PULONG foundElement,
+        PSTR buffer,
+        ULONG bufferSize,
+        PULONG foundSize);
 
     //----------------------------------------------------------------------------
     // IDebugSystemObjects
@@ -191,21 +266,9 @@ public:
         PULONG64 offset);
 
     //----------------------------------------------------------------------------
-    // IDebugClient
+    // LLDBServices (internal)
     //----------------------------------------------------------------------------
 
-    PCSTR GetCoreClrDirectory();
-
-    DWORD_PTR GetExpression(
-        PCSTR exp);
-
-    HRESULT VirtualUnwind(
-        DWORD threadID,
-        ULONG32 contextSize,
-        PBYTE context);
-
-    HRESULT SetExceptionCallback(
-        PFN_EXCEPTION_CALLBACK callback);
-
-    HRESULT ClearExceptionCallback();
+    PCSTR GetModuleDirectory(
+        PCSTR name);
 };
index 93c17b9..5d47808 100644 (file)
@@ -24,18 +24,21 @@ public:
                char** arguments,
                lldb::SBCommandReturnObject &result)
     {
-        DebugClient* client = new DebugClient(debugger, result);
-        LoadSos(client);
+        LLDBServices* services = new LLDBServices(debugger, result);
+        LoadSos(services);
 
         if (m_sosHandle)
         {
             const char* sosCommand = m_command;
             if (sosCommand == NULL) 
             {
-                if (arguments == NULL) {
-                    goto exit;
+                if (arguments == NULL || *arguments == NULL) {
+                    sosCommand = "Help";
+                }
+                else
+                {
+                    sosCommand = *arguments++;
                 }
-                sosCommand = *arguments++;
             }
             CommandFunc commandFunc = (CommandFunc)dlsym(m_sosHandle, sosCommand);
             if (commandFunc)
@@ -50,31 +53,31 @@ public:
                     }
                 }
                 const char* sosArgs = str.c_str();
-                HRESULT hr = commandFunc(client, sosArgs);
+                HRESULT hr = commandFunc(services, sosArgs);
                 if (hr != S_OK)
                 {
-                    client->Output(DEBUG_OUTPUT_ERROR, "%s %s failed\n", sosCommand, sosArgs);
+                    services->Output(DEBUG_OUTPUT_ERROR, "%s %s failed\n", sosCommand, sosArgs);
                 }
             }
             else
             {
-                client->Output(DEBUG_OUTPUT_ERROR, "SOS command '%s' not found %s\n", sosCommand, dlerror());
+                services->Output(DEBUG_OUTPUT_ERROR, "SOS command '%s' not found %s\n", sosCommand, dlerror());
             }
         }
-exit:
-        delete client;
+
+        services->Release();
         return result.Succeeded();
     }
 
     void
-    LoadSos(DebugClient *client)
+    LoadSos(LLDBServices *services)
     {
         if (m_sosHandle == NULL)
         {
             if (g_coreclrDirectory == NULL)
             {
                 const char *coreclrModule = MAKEDLLNAME_A("coreclr");
-                const char *directory = client->GetModuleDirectory(coreclrModule);
+                const char *directory = services->GetModuleDirectory(coreclrModule);
                 if (directory != NULL)
                 {
                     std::string path(directory);
@@ -83,19 +86,19 @@ exit:
                 }
                 else
                 {
-                    client->Output(DEBUG_OUTPUT_WARNING, "The %s module is not loaded yet in the target process\n", coreclrModule);
+                    services->Output(DEBUG_OUTPUT_WARNING, "The %s module is not loaded yet in the target process\n", coreclrModule);
                 }
             }
 
             if (g_coreclrDirectory != NULL)
             {
-                m_sosHandle = LoadModule(client, MAKEDLLNAME_A("sos"));
+                m_sosHandle = LoadModule(services, MAKEDLLNAME_A("sos"));
             }
         }
     }
 
     void *
-    LoadModule(DebugClient *client, const char *moduleName)
+    LoadModule(LLDBServices *services, const char *moduleName)
     {
         std::string modulePath(g_coreclrDirectory);
         modulePath.append(moduleName);
@@ -103,7 +106,7 @@ exit:
         void *moduleHandle = dlopen(modulePath.c_str(), RTLD_NOW);
         if (moduleHandle == NULL)
         {
-            client->Output(DEBUG_OUTPUT_ERROR, "dlopen(%s) failed %s\n", modulePath.c_str(), dlerror());
+            services->Output(DEBUG_OUTPUT_ERROR, "dlopen(%s) failed %s\n", modulePath.c_str(), dlerror());
         }
 
         return moduleHandle;
@@ -118,13 +121,19 @@ sosCommandInitialize(lldb::SBDebugger debugger)
     interpreter.AddCommand("bpmd", new sosCommand("bpmd"), "Creates a breakpoint at the specified managed method in the specified module.");
     interpreter.AddCommand("clrstack", new sosCommand("ClrStack"), "Provides a stack trace of managed code only.");
     interpreter.AddCommand("clrthreads", new sosCommand("Threads"), "List the managed threads running.");
+    interpreter.AddCommand("clru", new sosCommand("u"), "Displays an annotated disassembly of a managed method.");
+    interpreter.AddCommand("dumpclass", new sosCommand("DumpClass"), "Displays information about a EE class structure at the specified address.");
     interpreter.AddCommand("dumpheap", new sosCommand("DumpHeap"), "Displays info about the garbage-collected heap and collection statistics about objects.");
+    interpreter.AddCommand("dumpil", new sosCommand("DumpIL"), "Displays the Microsoft intermediate language (MSIL) that is associated with a managed method.");
     interpreter.AddCommand("dumplog", new sosCommand("DumpLog"), "Writes the contents of an in-memory stress log to the specified file.");
     interpreter.AddCommand("dumpmd", new sosCommand("DumpMD"), "Displays information about a MethodDesc structure at the specified address.");
+    interpreter.AddCommand("dumpmodule", new sosCommand("DumpModule"), "Displays information about a EE module structure at the specified address.");
     interpreter.AddCommand("dumpmt", new sosCommand("DumpMT"), "Displays information about a method table at the specified address.");
     interpreter.AddCommand("dumpobj", new sosCommand("DumpObj"), "Displays info about an object at the specified address.");
+    interpreter.AddCommand("dumpstack", new sosCommand("DumpStack"), "Displays a native and managed stack trace.");
     interpreter.AddCommand("dso", new sosCommand("DumpStackObjects"), "Displays all managed objects found within the bounds of the current stack.");
     interpreter.AddCommand("eeheap", new sosCommand("EEHeap"), "Displays info about process memory consumed by internal runtime data structures.");
+    interpreter.AddCommand("eestack", new sosCommand("EEStack"), "Runs dumpstack on all threads in the process.");
     interpreter.AddCommand("gcroot", new sosCommand("GCRoot"), "Displays info about references (or roots) to an object at the specified address.");
     interpreter.AddCommand("ip2md", new sosCommand("IP2MD"), "Displays the MethodDesc structure at the specified address in code that has been JIT-compiled.");
     interpreter.AddCommand("name2ee", new sosCommand("Name2EE"), "Displays the MethodTable structure and EEClass structure for the specified type or method in the specified module.");
index 3fecae0..6d43d90 100644 (file)
@@ -11,7 +11,9 @@ namespace lldb {
 bool
 lldb::PluginInitialize (lldb::SBDebugger debugger)
 {
+#ifdef _DEBUG
     corerunCommandInitialize(debugger);
+#endif
     sosCommandInitialize(debugger);
     setclrpathCommandInitialize(debugger);
     setsostidCommandInitialize(debugger);
index 1d897c0..4d38589 100644 (file)
@@ -5,11 +5,11 @@
 #include <lldb/API/LLDB.h>
 #include "mstypes.h"
 #define DEFINE_EXCEPTION_RECORD
-#include <dbgeng.h>
+#include <lldbservices.h>
 #include <dbgtargetcontext.h>
-#include "debugclient.h"
+#include "services.h"
 
-typedef HRESULT (*CommandFunc)(PDEBUG_CLIENT client, const char *args);
+typedef HRESULT (*CommandFunc)(ILLDBServices* services, const char *args);
 
 extern char *g_coreclrDirectory;
 extern ULONG g_currentThreadIndex;