include_directories(${CLR_DIR}/src/debug/shim)
if(WIN32)
- include_directories("inc")
include_directories("$ENV{VSInstallDir}/DIA SDK/include")
add_definitions(-DUSE_STL)
add_compile_options(-Wno-null-arithmetic)
add_compile_options(-Wno-format)
+ include_directories(BEFORE inc)
include_directories(BEFORE ../lldbplugin/inc)
add_compile_options(-fPIC)
/* [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);
}
#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,
*Size = GetFileSize(hFile, NULL);
if (*Size == ULONG_MAX) {
CloseHandle( hFile );
- return FALSE;
+ return NULL;
}
hMappedFile = CreateFileMapping (
if ( !hMappedFile ) {
CloseHandle ( hFile );
- return FALSE;
+ return NULL;
}
MappedFile = MapViewOfFile (
CloseHandle (hFile);
return MappedFile;
+#else // FEATURE_PAL
+ return NULL;
+#endif // FEATURE_PAL
}
char* PrintOneLine (__in_z char *begin, __in_z char *limit)
{
char filename[MAX_PATH_FNAME+1];
char line[256];
- int lcount = 10;
+ int lcount = 10;
ULONG linenum = 0;
ULONG64 Displacement = 0;
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;
}
return;
}
- g_ExtSymbols->GetSourceFileLineOffsets (filename, Buffer, FileLines, NULL);
+ g_ExtSymbols->GetSourceFileLineOffsets(filename, Buffer, FileLines, NULL);
int beginLine = 0;
int endLine = 0;
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;
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;
#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;
}
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) {
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;
}
}
}
}
-
}
void DisasmAndClean (DWORD_PTR &IP, __out_ecount_opt(length) char *line, ULONG length)
ptr[0] = '\0';
}
-#endif // FEATURE_PAL
-
-
// If byref, move to pass the byref prefix
BOOL IsByRef (__deref_inout_z char *& ptr)
{
// 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];
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))
{
}
}
#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)
{
}
}
-#endif // FEATURE_PAL
-
#ifdef SOS_TARGET_X86
///
/// X86Machine implementation
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);
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)
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,
SOSEHInfo *pEHInfo,
BOOL bSuppressLines,
BOOL bDisplayOffsets) const;
-#endif
+
virtual void IsReturnAddress(
TADDR retAddr,
TADDR* whereCalled) const;
+
virtual BOOL GetExceptionContext (
TADDR stack,
TADDR PC,
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; }
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)
{
return bValid;
}
-
enum ADDRESSMODE {REG, DATA, INDIRECT, NODATA, BAD};
struct RegState
}
}
-#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)
}
}
-#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)
return ettNative;
}
+#ifndef FEATURE_PAL
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 *
* *
#endif
return TRUE;
#else
- ExtErr("AMD64Machine::GetExceptionContext not implemented\n");
return FALSE;
#endif // FEATURE_PAL
}
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:
return Status;
}
-#endif // FEATURE_PAL
-
extern "C" HRESULT
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;
#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
};
#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;
#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);
#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
{
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
#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;
// 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,
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
//
//-----------------------------------------------------------------------------------------
-#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)
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
--- /dev/null
+// 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__
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
#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
Notes:
HRESULT CALLBACK _EFN_StackTrace(
- PDEBUG_CLIENT Client,
+ PDEBUG_CLIENT client,
WCHAR wszTextOut[],
UINT *puiTextLength,
LPVOID pTransitionContexts,
#endif // __cplusplus
HRESULT CALLBACK _EFN_StackTrace(
- PDEBUG_CLIENT Client,
+ PDEBUG_CLIENT client,
__out_ecount(*puiTextLength) WCHAR wszTextOut[],
size_t *puiTextLength,
LPVOID pTransitionContexts,
//
// 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
// _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
// 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
//
// 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"
\\
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
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
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
----------------------------- -----------------------------
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
-----------------------------
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.
\\
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
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
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
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>)
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.
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.
this problem, and running with Managed Debugging Assistants is advised. If that
possibility is eliminated, consider contacting Microsoft Product Support for
help.
-
\\
COMMAND: dumplog.
#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
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
{
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
// (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: *
DumpStackFlag DSFlag;
DSFlag.fEEonly = FALSE;
+ DSFlag.fSuppressSrcInfo = FALSE;
DSFlag.top = 0;
DSFlag.end = 0;
// 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
DumpStackFlag DSFlag;
DSFlag.fEEonly = FALSE;
+ DSFlag.fSuppressSrcInfo = FALSE;
DSFlag.top = 0;
DSFlag.end = 0;
{ // 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))
return Status;
}
-#endif // FEATURE_PAL
-
HRESULT DumpStackObjectsRaw(size_t nArg, __in_z LPSTR exprBottom, __in_z LPSTR exprTop, BOOL bVerify)
{
size_t StackTop = 0;
return Status;
}
-#ifndef FEATURE_PAL
-
BOOL GatherDynamicInfo(TADDR DynamicMethodObj, DacpObjectData *codeArray,
DacpObjectData *tokenArray, TADDR *ptokenArrayAddr)
{
return bRet;
}
-
DECLARE_API(DumpIL)
{
INIT_API();
ExtOut("%S\n", (PCWSTR)sigString.Ptr());
}
-
/**********************************************************************\
* Routine Description: *
* *
return Status;
}
-
-
/**********************************************************************\
* Routine Description: *
* *
return Status;
}
-#endif // FEATURE_PAL
-
-
/**********************************************************************\
* Routine Description: *
* *
return Status;
}
-
/**********************************************************************\
* Routine Description: *
* *
// 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
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);
flags &= ~(CLRDATA_NOTIFY_ON_MODULE_LOAD | CLRDATA_NOTIFY_ON_MODULE_UNLOAD);
g_clrData->SetOtherNotificationFlags(flags);
- g_ExtClient->ClearExceptionCallback();
+ g_ExtServices->ClearExceptionCallback();
}
#endif
}
return S_OK;
}
-#ifdef FEATURE_PAL
-HRESULT HandleExceptionNotification(PDEBUG_CLIENT Client)
-{
- INIT_API();
- return HandleCLRNotificationEvent();
-}
-#endif
+#ifndef FEATURE_PAL
DECLARE_API(HandleCLRN)
{
return HandleCLRNotificationEvent();
}
+#else // FEATURE_PAL
+
+HRESULT HandleExceptionNotification(ILLDBServices *client)
+{
+ INIT_API();
+ return HandleCLRNotificationEvent();
+}
+
+#endif // FEATURE_PAL
+
DECLARE_API(bpmd)
{
INIT_API();
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
}
return TRUE;
}
-#ifndef FEATURE_PAL
/**********************************************************************\
* Routine Description: *
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
return Status;
}
-#endif // FEATURE_PAL
-
/**********************************************************************\
* Routine Description: *
* *
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
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;
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)
}
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).
}
} 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;
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;
g_ExtSystem->GetCurrentThreadId(&id);
ExtOut("(%d)\n", id);
- PrintThread(osid, bParams, bLocals, bSuppressLines, bGC);
+ PrintThread(osid, bParams, bLocals, bSuppressLines, bGC, bNative);
}
private:
BOOL bICorDebug = FALSE;
BOOL bGC = FALSE;
BOOL dml = FALSE;
+ BOOL bFull = FALSE;
DWORD frameToDumpVariablesFor = -1;
StringHolder cvariableName;
ArrayHolder<WCHAR> wvariableName = new NOTHROW WCHAR[mdNameLen];
{"-n", &bSuppressLines, COBOOL, FALSE},
{"-i", &bICorDebug, COBOOL, FALSE},
{"-gc", &bGC, COBOOL, FALSE},
+ {"-f", &bFull, COBOOL, FALSE},
#ifndef FEATURE_PAL
{"/d", &dml, COBOOL, FALSE},
#endif
return ClrStackImplWithICorDebug::ClrStackFromPublicInterface(bParams, bLocals, FALSE, wvariableName, frameToDumpVariablesFor);
}
- ClrStackImpl::PrintCurrentThread(bParams, bLocals, bSuppressLines, bGC);
+ ClrStackImpl::PrintCurrentThread(bParams, bLocals, bSuppressLines, bGC, bFull);
return S_OK;
}
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);
}
}
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);
}
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
{
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);
}
#undef DOAPPEND
}
-#ifndef FEATURE_PAL
-
BOOL AppendContext(LPVOID pTransitionContexts, size_t maxCount, size_t *pcurCount, size_t uiSizeOfContext,
CROSS_PLATFORM_CONTEXT *context)
{
}
HRESULT CALLBACK ImplementEFNStackTrace(
- PDEBUG_CLIENT Client,
+ PDEBUG_CLIENT client,
__out_ecount_opt(*puiTextLength) WCHAR wszTextOut[],
size_t *puiTextLength,
LPVOID pTransitionContexts,
}
#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;
}
Exit:
- if (g_ExtControl4)
- {
- g_ExtControl4->Release();
- g_ExtControl4 = NULL;
- }
#else // _TARGET_WIN64_
#ifdef _DEBUG
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,
PAL_TRY_NAKED
{
- Status = ImplementEFNStackTrace(Client, wszTextOut, puiTextLength,
+ Status = ImplementEFNStackTrace(client, wszTextOut, puiTextLength,
pTransitionContexts, puiTransitionContextCount,
uiSizeOfContext, Flags);
}
// 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,
{
INIT_API();
- Status = ImplementEFNStackTraceTry(Client, wszTextOut, puiTextLength,
+ Status = ImplementEFNStackTraceTry(client, wszTextOut, puiTextLength,
pTransitionContexts, puiTransitionContextCount,
uiSizeOfContext, Flags);
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.
{
size_t textLength = 0;
size_t contextLength = 0;
- Status = ImplementEFNStackTraceTry(Client,
+ Status = ImplementEFNStackTraceTry(client,
NULL,
&textLength,
NULL,
return Status;
}
- Status = ImplementEFNStackTrace(Client,
+ Status = ImplementEFNStackTrace(client,
wszBuffer,
&textLength,
pContexts,
return Status;
}
- Status = ImplementEFNStackTrace(Client,
+ Status = ImplementEFNStackTrace(client,
wszBuffer,
&textLength,
pSimple,
return Status;
}
-#endif // !FEATURE_PAL
-
+#ifndef FEATURE_PAL
// This is an internal-only Apollo extension to de-optimize the code
DECLARE_API(SuppressJitOptimization)
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
// 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
// conforms to CLRDATA_ADDRESS contract.
HRESULT CALLBACK
_EFN_GetManagedObjectName(
- PDEBUG_CLIENT Client,
+ PDEBUG_CLIENT client,
ULONG64 objAddr,
__out_ecount (cbName) PSTR szName,
ULONG cbName
// conforms to CLRDATA_ADDRESS contract.
HRESULT CALLBACK
_EFN_GetManagedObjectFieldInfo(
- PDEBUG_CLIENT Client,
+ PDEBUG_CLIENT client,
ULONG64 objAddr,
__out_ecount (mdNameLen) PSTR szFieldName,
PULONG64 pValue,
return S_OK;
}
-#endif // FEATURE_PAL
-
void PrintHelp (__in_z LPCSTR pszCmdName)
{
static LPSTR pText = NULL;
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);
* 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;
{&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;
}
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
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);
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());
//
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
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
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};
}
fallback:
- //
+#endif // FEATURE_PAL
return g_ExtSymbols->GetLineByOffset(
Offset,
pLinenum,
&displacement);
}
-#endif // FEATURE_PAL
void TableOutput::ReInit(int numColumns, int defaultColumnWidth, Alignment alignmentDefault, int indent, int padding)
{
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);
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)
{
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;
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)
{
}
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("!");
}
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;
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
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.
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)
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
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.
//
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
// 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.
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;
/* [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(
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__
// 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__
#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
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),
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
//----------------------------------------------------------------------------
// or stop button.
// This method is reentrant.
HRESULT
-DebugClient::GetInterrupt()
+LLDBServices::GetInterrupt()
{
return E_FAIL;
}
// according to the output distribution
// settings.
HRESULT
-DebugClient::Output(
+LLDBServices::Output(
ULONG mask,
PCSTR format,
...)
}
HRESULT
-DebugClient::OutputVaList(
+LLDBServices::OutputVaList(
ULONG mask,
PCSTR format,
va_list args)
// extra work in the engine so they should
// only be used when necessary.
HRESULT
-DebugClient::ControlledOutput(
+LLDBServices::ControlledOutput(
ULONG outputControl,
ULONG mask,
PCSTR format,
}
HRESULT
-DebugClient::ControlledOutputVaList(
+LLDBServices::ControlledOutputVaList(
ULONG outputControl,
ULONG mask,
PCSTR format,
// Returns information about the debuggee such
// as user vs. kernel, dump vs. live, etc.
HRESULT
-DebugClient::GetDebuggeeType(
+LLDBServices::GetDebuggeeType(
PULONG debugClass,
PULONG qualifier)
{
// processor context. The page size may vary between
// processor types.
HRESULT
-DebugClient::GetPageSize(
+LLDBServices::GetPageSize(
PULONG size)
{
*size = 4096;
}
HRESULT
-DebugClient::GetExecutingProcessorType(
+LLDBServices::GetExecutingProcessorType(
PULONG type)
{
*type = IMAGE_FILE_MACHINE_AMD64;
}
HRESULT
-DebugClient::Execute(
+LLDBServices::Execute(
ULONG outputControl,
PCSTR command,
ULONG flags)
#define VARIABLE_NAME "ExceptionRecord"
HRESULT
-DebugClient::GetLastEventInformation(
+LLDBServices::GetLastEventInformation(
PULONG type,
PULONG processId,
PULONG threadId,
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;
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)
{
// 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,
}
HRESULT
-DebugClient::WriteVirtual(
+LLDBServices::WriteVirtual(
ULONG64 offset,
PVOID buffer,
ULONG bufferSize,
//----------------------------------------------------------------------------
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;
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;
}
}
str.append(1, '\0');
- hr = S_OK;
exit:
if (nameSize)
}
HRESULT
-DebugClient::GetNumberModules(
+LLDBServices::GetNumberModules(
PULONG loaded,
PULONG unloaded)
{
return hr;
}
-HRESULT DebugClient::GetModuleByIndex(
+HRESULT LLDBServices::GetModuleByIndex(
ULONG index,
PULONG64 base)
{
}
HRESULT
-DebugClient::GetModuleByModuleName(
+LLDBServices::GetModuleByModuleName(
PCSTR name,
ULONG startIndex,
PULONG index,
}
HRESULT
-DebugClient::GetModuleByOffset(
+LLDBServices::GetModuleByOffset(
ULONG64 offset,
ULONG startIndex,
PULONG index,
}
HRESULT
-DebugClient::GetModuleNames(
+LLDBServices::GetModuleNames(
ULONG index,
ULONG64 base,
PSTR imageNameBuffer,
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())
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();
return module.GetFileSpec().GetDirectory();
}
-// Internal function
ULONG64
-DebugClient::GetModuleBase(
+LLDBServices::GetModuleBase(
/* const */ lldb::SBTarget& target,
/* const */ lldb::SBModule& module)
{
//----------------------------------------------------------------------------
HRESULT
-DebugClient::GetCurrentProcessId(
+LLDBServices::GetCurrentProcessId(
PULONG id)
{
if (id == NULL)
}
HRESULT
-DebugClient::GetCurrentThreadId(
+LLDBServices::GetCurrentThreadId(
PULONG id)
{
if (id == NULL)
}
HRESULT
-DebugClient::SetCurrentThreadId(
+LLDBServices::SetCurrentThreadId(
ULONG id)
{
lldb::SBProcess process = GetCurrentProcess();
}
HRESULT
-DebugClient::GetCurrentThreadSystemId(
+LLDBServices::GetCurrentThreadSystemId(
PULONG sysId)
{
if (sysId == NULL)
}
HRESULT
-DebugClient::GetThreadIdBySystemId(
+LLDBServices::GetThreadIdBySystemId(
ULONG sysId,
PULONG threadId)
{
}
HRESULT
-DebugClient::GetThreadContextById(
+LLDBServices::GetThreadContextById(
/* in */ ULONG32 threadID,
/* in */ ULONG32 contextFlags,
/* in */ ULONG32 contextSize,
// Internal function
void
-DebugClient::GetContextFromFrame(
+LLDBServices::GetContextFromFrame(
/* const */ lldb::SBFrame& frame,
DT_CONTEXT *dtcontext)
{
// Internal function
DWORD_PTR
-DebugClient::GetRegister(
+LLDBServices::GetRegister(
/* const */ lldb::SBFrame& frame,
const char *name)
{
//----------------------------------------------------------------------------
HRESULT
-DebugClient::GetValueByName(
+LLDBServices::GetValueByName(
PCSTR name,
PDWORD_PTR debugValue)
{
}
HRESULT
-DebugClient::GetInstructionOffset(
+LLDBServices::GetInstructionOffset(
PULONG64 offset)
{
lldb::SBFrame frame = GetCurrentFrame();
}
HRESULT
-DebugClient::GetStackOffset(
+LLDBServices::GetStackOffset(
PULONG64 offset)
{
lldb::SBFrame frame = GetCurrentFrame();
}
HRESULT
-DebugClient::GetFrameOffset(
+LLDBServices::GetFrameOffset(
PULONG64 offset)
{
lldb::SBFrame frame = GetCurrentFrame();
}
//----------------------------------------------------------------------------
-// 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;
}
lldb::SBThread
-DebugClient::GetCurrentThread()
+LLDBServices::GetCurrentThread()
{
lldb::SBThread thread;
}
lldb::SBFrame
-DebugClient::GetCurrentFrame()
+LLDBServices::GetCurrentFrame()
{
lldb::SBFrame frame;
#include <cstdarg>
-class DebugClient : public IDebugClient
+class LLDBServices : public ILLDBServices
{
private:
+ LONG m_ref;
lldb::SBDebugger &m_debugger;
lldb::SBCommandReturnObject &m_returnObject;
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
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
//----------------------------------------------------------------------------
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
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);
};
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)
}
}
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);
}
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);
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;
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.");
bool
lldb::PluginInitialize (lldb::SBDebugger debugger)
{
+#ifdef _DEBUG
corerunCommandInitialize(debugger);
+#endif
sosCommandInitialize(debugger);
setclrpathCommandInitialize(debugger);
setsostidCommandInitialize(debugger);
#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;