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