summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMike McLaughlin <mikem@microsoft.com>2015-06-16 17:43:04 -0700
committerMike McLaughlin <mikem@microsoft.com>2015-06-19 14:36:20 -0700
commited78e1f8d1de2c3cf94c1e54e3e4ec17258eac2f (patch)
tree19e8424152fe387e193dd610a1304449ffbfbb5e /src
parent646bcd7b284bf1b3f5659cb3392316154c084b68 (diff)
downloadcoreclr-ed78e1f8d1de2c3cf94c1e54e3e4ec17258eac2f.tar.gz
coreclr-ed78e1f8d1de2c3cf94c1e54e3e4ec17258eac2f.tar.bz2
coreclr-ed78e1f8d1de2c3cf94c1e54e3e4ec17258eac2f.zip
Enable bpmd command even unjitted functions work.
Preallocate JIT notification table on VM side (since ICLRDataTarget2->AllocVirtual isn't implemented under lldb) and implement WriteVirtual on debugger side to allow DAC to write entries. Used the special set breakpoint on exception throw lldb command to catch the special exception the VM throws when some thing is jitted. The debugger side finds the exception record by searching for the RtlpRaiseException function on the stack when the bp is hit. It also assumes that the local variable is called ExceptionRecord. Fix all the file path separators to use the platform independent defines. Ifdef all the "/d" options in the supported commands because the / char isn't supported as a command line option and /d is always the DML option that isn't supported either. Fix problem Prem run into running sos after the process stops.
Diffstat (limited to 'src')
-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
-rw-r--r--src/dlls/mscoree/mscorwks_unixexports.src2
-rw-r--r--src/inc/palclr.h2
-rw-r--r--src/pal/inc/rt/palrt.h2
-rw-r--r--src/pal/src/exception/seh-unwind.cpp12
-rw-r--r--src/vm/ceemain.cpp1
-rw-r--r--src/vm/util.hpp10
15 files changed, 423 insertions, 69 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"
diff --git a/src/dlls/mscoree/mscorwks_unixexports.src b/src/dlls/mscoree/mscorwks_unixexports.src
index be6018f94c..81a99d6a7e 100644
--- a/src/dlls/mscoree/mscorwks_unixexports.src
+++ b/src/dlls/mscoree/mscorwks_unixexports.src
@@ -22,6 +22,7 @@ ForkAndExecProcess
FormatMessageW
FreeEnvironmentStringsW
GetACP
+GetCLRRuntimeHost
GetConsoleCP
GetConsoleOutputCP
GetCurrentDirectoryW
@@ -52,6 +53,7 @@ MultiByteToWideChar
OpenEventW
OpenMutexW
OpenSemaphoreW
+PAL_InitializeCoreCLR
PAL_Random
PAL_RegisterModule
PAL_UnregisterModule
diff --git a/src/inc/palclr.h b/src/inc/palclr.h
index 808b3bb961..9af7814ee6 100644
--- a/src/inc/palclr.h
+++ b/src/inc/palclr.h
@@ -86,7 +86,7 @@
#define PORTABILITY_ASSERT(message) _ASSERTE(false && message)
#endif
-
+#define DIRECTORY_SEPARATOR_CHAR_A '\\'
#define DIRECTORY_SEPARATOR_CHAR_W W('\\')
#define DIRECTORY_SEPARATOR_STR_W W("\\")
diff --git a/src/pal/inc/rt/palrt.h b/src/pal/inc/rt/palrt.h
index 731c9a9743..0468d17b08 100644
--- a/src/pal/inc/rt/palrt.h
+++ b/src/pal/inc/rt/palrt.h
@@ -1354,10 +1354,12 @@ typedef VOID (__stdcall *WAITORTIMERCALLBACK)(PVOID, BOOLEAN);
#define _ReturnAddress() __builtin_return_address(0)
#ifdef PLATFORM_UNIX
+#define DIRECTORY_SEPARATOR_CHAR_A '/'
#define DIRECTORY_SEPARATOR_CHAR_W W('/')
#define DIRECTORY_SEPARATOR_STR_W W("/")
#define PATH_SEPARATOR_CHAR_W W(':')
#else // PLATFORM_UNIX
+#define DIRECTORY_SEPARATOR_CHAR_A '\\'
#define DIRECTORY_SEPARATOR_CHAR_W W('\\')
#define DIRECTORY_SEPARATOR_STR_W W("\\")
#define PATH_SEPARATOR_CHAR_W W(';')
diff --git a/src/pal/src/exception/seh-unwind.cpp b/src/pal/src/exception/seh-unwind.cpp
index a6435a42f4..2e77814b9b 100644
--- a/src/pal/src/exception/seh-unwind.cpp
+++ b/src/pal/src/exception/seh-unwind.cpp
@@ -195,6 +195,18 @@ BOOL PAL_VirtualUnwind(CONTEXT *context, KNONVOLATILE_CONTEXT_POINTERS *contextP
#error don't know how to unwind on this platform
#endif
+/*++
+Function:
+ RtlpRaiseException
+
+Parameters:
+ ExceptionRecord - the Windows exception record to throw
+
+Note:
+ The name of this function and the name of the ExceptionRecord
+ parameter is used in the sos lldb plugin code to read the exception
+ record. See coreclr\src\ToolBox\SOS\lldbplugin\debugclient.cpp.
+--*/
PAL_NORETURN
static void RtlpRaiseException(EXCEPTION_RECORD *ExceptionRecord)
{
diff --git a/src/vm/ceemain.cpp b/src/vm/ceemain.cpp
index e6eff9bf14..4055635e65 100644
--- a/src/vm/ceemain.cpp
+++ b/src/vm/ceemain.cpp
@@ -1423,6 +1423,7 @@ HRESULT EEStartup(COINITIEE fFlags)
#if defined(FEATURE_PAL) && !defined(CROSSGEN_COMPILE)
DacGlobals::Initialize();
+ InitializeJITNotificationTable();
#endif
PAL_TRY(COINITIEE *, pfFlags, &fFlags)
diff --git a/src/vm/util.hpp b/src/vm/util.hpp
index b6f3adb131..0b4fb0a46b 100644
--- a/src/vm/util.hpp
+++ b/src/vm/util.hpp
@@ -1081,6 +1081,16 @@ struct JITNotification
GPTR_DECL(JITNotification,g_pNotificationTable);
GVAL_DECL(ULONG32, g_dacNotificationFlags);
+#if defined(FEATURE_PAL) && !defined(DACCESS_COMPILE)
+
+inline void
+InitializeJITNotificationTable()
+{
+ g_pNotificationTable = new (nothrow) JITNotification[1001];
+}
+
+#endif // FEATURE_PAL && !DACCESS_COMPILE
+
class JITNotifications
{
public: