summaryrefslogtreecommitdiff
path: root/src/vm/eventreporter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/vm/eventreporter.cpp')
-rw-r--r--src/vm/eventreporter.cpp837
1 files changed, 837 insertions, 0 deletions
diff --git a/src/vm/eventreporter.cpp b/src/vm/eventreporter.cpp
new file mode 100644
index 0000000000..567f4f5d51
--- /dev/null
+++ b/src/vm/eventreporter.cpp
@@ -0,0 +1,837 @@
+// 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.
+//
+
+//
+//*****************************************************************************
+// EventReporter.cpp
+//
+// A utility to log an entry in event log.
+//
+//*****************************************************************************
+
+
+#include "common.h"
+#include "utilcode.h"
+#include "eventreporter.h"
+#include "typestring.h"
+#include "debugdebugger.h"
+
+#include "../dlls/mscorrc/resource.h"
+
+#if defined(FEATURE_CORECLR)
+#include "getproductversionnumber.h"
+#endif // FEATURE_CORECLR
+
+//---------------------------------------------------------------------------------------
+//
+// A constructor for EventReporter. The header of the log is generated here.
+//
+// Arguments:
+// type - Event report type
+//
+// Assumptions:
+// The argument type must be valid.
+//
+EventReporter::EventReporter(EventReporterType type)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ m_eventType = type;
+
+ HMODULE hModule = WszGetModuleHandle(NULL);
+ PathString appPath;
+ DWORD ret = WszGetModuleFileName(hModule, appPath);
+
+ fBufferFull = FALSE;
+
+ InlineSString<256> ssMessage;
+
+ if(!ssMessage.LoadResource(CCompRC::Optional, IDS_ER_APPLICATION))
+ m_Description.Append(W("Application: "));
+ else
+ {
+ m_Description.Append(ssMessage);
+ }
+
+ // If we were able to get an app name.
+ if (ret != 0)
+ {
+ // If app name has a '\', consider the part after that; otherwise consider whole name.
+ LPCWSTR appName = wcsrchr(appPath, W('\\'));
+ appName = appName ? appName+1 : appPath;
+ m_Description.Append(appName);
+ m_Description.Append(W("\n"));
+ }
+ else
+ {
+ ssMessage.Clear();
+ if(!ssMessage.LoadResource(CCompRC::Optional, IDS_ER_UNKNOWN))
+ m_Description.Append(W("unknown\n"));
+ else
+ {
+ m_Description.Append(ssMessage);
+ m_Description.Append(W("\n"));
+ }
+ }
+
+ ssMessage.Clear();
+ if(!ssMessage.LoadResource(CCompRC::Optional, IDS_ER_FRAMEWORK_VERSION))
+#ifndef FEATURE_CORECLR
+ m_Description.Append(W("Framework Version: "));
+#else // FEATURE_CORECLR
+ m_Description.Append(W("CoreCLR Version: "));
+#endif // !FEATURE_CORECLR
+ else
+ {
+ m_Description.Append(ssMessage);
+ }
+
+ BOOL fHasVersion = FALSE;
+#ifndef FEATURE_CORECLR
+ if (GetCLRModule() != NULL)
+ {
+ WCHAR buffer[80];
+ DWORD length;
+ if (SUCCEEDED(GetCORVersionInternal(buffer, 80, &length)))
+ {
+ m_Description.Append(buffer);
+ m_Description.Append(W("\n"));
+ fHasVersion = TRUE;
+ }
+ }
+#else // FEATURE_CORECLR
+ DWORD dwMajorVersion = 0;
+ DWORD dwMinorVersion = 0;
+ DWORD dwBuild = 0;
+ DWORD dwRevision = 0;
+ EventReporter::GetCoreCLRInstanceProductVersion(&dwMajorVersion, &dwMinorVersion, &dwBuild, &dwRevision);
+ m_Description.AppendPrintf(W("%lu.%lu.%lu.%lu\n"),dwMajorVersion, dwMinorVersion, dwBuild, dwRevision);
+ fHasVersion = TRUE;
+#endif // !FEATURE_CORECLR
+
+ if (!fHasVersion)
+ {
+ ssMessage.Clear();
+ if(!ssMessage.LoadResource(CCompRC::Optional, IDS_ER_UNKNOWN))
+ m_Description.Append(W("unknown\n"));
+ else
+ {
+ m_Description.Append(ssMessage);
+ m_Description.Append(W("\n"));
+ }
+ }
+
+ ssMessage.Clear();
+
+ switch(m_eventType) {
+ case ERT_UnhandledException:
+ if(!ssMessage.LoadResource(CCompRC::Optional, IDS_ER_UNHANDLEDEXCEPTION))
+ m_Description.Append(W("Description: The process was terminated due to an unhandled exception."));
+ else
+ {
+ m_Description.Append(ssMessage);
+ }
+ m_Description.Append(W("\n"));
+ break;
+
+ case ERT_ManagedFailFast:
+ if(!ssMessage.LoadResource(CCompRC::Optional, IDS_ER_MANAGEDFAILFAST))
+ m_Description.Append(W("Description: The application requested process termination through System.Environment.FailFast(string message)."));
+ else
+ {
+ m_Description.Append(ssMessage);
+ }
+ m_Description.Append(W("\n"));
+ break;
+
+ case ERT_UnmanagedFailFast:
+ if(!ssMessage.LoadResource(CCompRC::Optional, IDS_ER_UNMANAGEDFAILFAST))
+ m_Description.Append(W("Description: The process was terminated due to an internal error in the .NET Runtime "));
+ else
+ {
+ m_Description.Append(ssMessage);
+ }
+ break;
+
+ case ERT_StackOverflow:
+ // Fetch the localized Stack Overflow Error text or fall back on a hardcoded variant if things get dire.
+ if(!ssMessage.LoadResource(CCompRC::Optional, IDS_ER_STACK_OVERFLOW))
+ m_Description.Append(W("Description: The process was terminated due to stack overflow."));
+ else
+ {
+ m_Description.Append(ssMessage);
+ }
+ m_Description.Append(W("\n"));
+ break;
+
+ case ERT_CodeContractFailed:
+ if(!ssMessage.LoadResource(CCompRC::Optional, IDS_ER_CODECONTRACT_FAILED))
+ m_Description.Append(W("Description: The application encountered a bug. A managed code contract (precondition, postcondition, object invariant, or assert) failed."));
+ else
+ {
+ m_Description.Append(ssMessage);
+ }
+ m_Description.Append(W("\n"));
+ break;
+
+ default:
+ _ASSERTE(!"Unknown EventReporterType.");
+ break;
+ }
+}
+
+
+//---------------------------------------------------------------------------------------
+//
+// Add extra description to the EventLog report.
+//
+// Arguments:
+// pString - The extra description to append to log
+//
+// Return Value:
+// None.
+//
+void EventReporter::AddDescription(__in WCHAR *pString)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_NOTRIGGER;
+ SO_INTOLERANT;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+ StackSString s(pString);
+ AddDescription(s);
+}
+
+//---------------------------------------------------------------------------------------
+//
+// Add extra description to the EventLog report.
+//
+// Arguments:
+// pString - The extra description to append to log
+//
+// Return Value:
+// None.
+//
+void EventReporter::AddDescription(SString& s)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_NOTRIGGER;
+ SO_INTOLERANT;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+ _ASSERTE (m_eventType == ERT_UnhandledException || m_eventType == ERT_ManagedFailFast ||
+ m_eventType == ERT_UnmanagedFailFast || m_eventType == ERT_CodeContractFailed);
+ if (m_eventType == ERT_ManagedFailFast)
+ {
+ SmallStackSString ssMessage;
+ if(!ssMessage.LoadResource(CCompRC::Optional, IDS_ER_MANAGEDFAILFASTMSG))
+ m_Description.Append(W("Message: "));
+ else
+ {
+ m_Description.Append(ssMessage);
+ }
+ }
+ else if (m_eventType == ERT_UnhandledException)
+ {
+ SmallStackSString ssMessage;
+ if (!ssMessage.LoadResource(CCompRC::Optional, IDS_ER_UNHANDLEDEXCEPTIONMSG))
+ {
+ m_Description.Append(W("Exception Info: "));
+ }
+ else
+ {
+ m_Description.Append(ssMessage);
+ }
+ }
+ else if (m_eventType == ERT_CodeContractFailed)
+ {
+ SmallStackSString ssMessage;
+ if (!ssMessage.LoadResource(CCompRC::Optional, IDS_ER_CODECONTRACT_DETAILMSG))
+ m_Description.Append(W("Contract details: "));
+ else
+ m_Description.Append(ssMessage);
+ }
+ m_Description.Append(s);
+ m_Description.Append(W("\n"));
+}
+
+//---------------------------------------------------------------------------------------
+//
+// Add a marker for stack trace section in the EventLog entry
+//
+// Arguments:
+// None.
+//
+// Return Value:
+// None.
+//
+void EventReporter::BeginStackTrace()
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_NOTRIGGER;
+ SO_INTOLERANT;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+ _ASSERTE (m_eventType == ERT_UnhandledException || m_eventType == ERT_ManagedFailFast || m_eventType == ERT_CodeContractFailed);
+ InlineSString<80> ssMessage;
+ if(!ssMessage.LoadResource(CCompRC::Optional, IDS_ER_STACK))
+ m_Description.Append(W("Stack:\n"));
+ else
+ {
+ m_Description.Append(ssMessage);
+ m_Description.Append(W("\n"));
+ }
+}
+
+//---------------------------------------------------------------------------------------
+//
+// Add the signature of one managed stack frame into EventLog entry.
+//
+// Arguments:
+// s - The signature of managed function, including argument type
+//
+// Return Value:
+// None.
+//
+void EventReporter::AddStackTrace(SString& s)
+{
+ WRAPPER_NO_CONTRACT;
+ _ASSERTE (m_eventType == ERT_UnhandledException || m_eventType == ERT_ManagedFailFast || m_eventType == ERT_CodeContractFailed);
+
+ // Continue to append to the buffer until we are full
+ if (fBufferFull == FALSE)
+ {
+ m_Description.Append(s);
+ m_Description.Append(W("\n"));
+
+ COUNT_T curSize = m_Description.GetCount();
+
+ // Truncate the buffer if we have exceeded the limit based upon the OS we are on
+ DWORD dwMaxSizeLimit = MAX_SIZE_EVENTLOG_ENTRY_STRING_WINVISTA;
+ if (curSize >= dwMaxSizeLimit)
+ {
+ // Load the truncation message
+ StackSString truncate;
+ if (!truncate.LoadResource(CCompRC::Optional, IDS_ER_MESSAGE_TRUNCATE))
+ {
+ truncate.Set(W("The remainder of the message was truncated."));
+ }
+ truncate.Insert(truncate.Begin(), W("\n"));
+ truncate.Insert(truncate.End(), W("\n"));
+
+ SString::Iterator ext;
+ COUNT_T truncCount = truncate.GetCount();
+
+ // Go back "truncCount" characters from the end of the string.
+ // The "-1" in end is to accomodate null termination.
+ ext = m_Description.Begin() + dwMaxSizeLimit - truncCount - 1;
+
+ // Now look for a "\n" from the last position we got
+ BOOL fFoundMarker = m_Description.FindBack(ext, W("\n"));
+ if (ext != m_Description.Begin())
+ {
+ // Move to the next character if we found the "\n"
+ if (fFoundMarker)
+ ext++;
+ }
+
+ // Truncate the string till our current position and append
+ // the truncation message
+ m_Description.Truncate(ext);
+ m_Description.Append(truncate);
+
+ // Set the flag that we are full - no point appending more stack details
+ fBufferFull = TRUE;
+ }
+ }
+}
+
+//---------------------------------------------------------------------------------------
+//
+// Generate an entry in EventLog.
+//
+// Arguments:
+// None.
+//
+// Return Value:
+// None.
+//
+void EventReporter::Report()
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ }
+ CONTRACTL_END;
+
+ DWORD eventID;
+ switch (m_eventType)
+ {
+ case ERT_UnhandledException:
+ eventID = 1026;
+ break;
+ case ERT_ManagedFailFast:
+ eventID = 1025;
+ break;
+ case ERT_UnmanagedFailFast:
+ eventID = 1023;
+ break;
+ case ERT_StackOverflow:
+ eventID = 1027;
+ break;
+ case ERT_CodeContractFailed:
+ eventID = 1028;
+ break;
+ default:
+ _ASSERTE(!"Invalid event type");
+ eventID = 1023;
+ break;
+ }
+
+ CONTRACT_VIOLATION(ThrowsViolation);
+
+ COUNT_T ctSize = m_Description.GetCount();
+ LOG((LF_EH, LL_INFO100, "EventReporter::Report - Writing %d bytes to event log.\n", ctSize));
+
+ if (ctSize > 0)
+ {
+ DWORD dwRetVal = ClrReportEvent(W(".NET Runtime"),
+ EVENTLOG_ERROR_TYPE,
+ 0,
+ eventID,
+ NULL,
+ m_Description.GetUnicode()
+ );
+
+ if (dwRetVal != ERROR_SUCCESS)
+ {
+ LOG((LF_EH, LL_INFO100, "EventReporter::Report - Error (win32 code %d) while writing to event log.\n", dwRetVal));
+
+ // We were unable to log the error to event log - now check why.
+ if ((dwRetVal != ERROR_EVENTLOG_FILE_CORRUPT) && (dwRetVal != ERROR_LOG_FILE_FULL) &&
+ (dwRetVal != ERROR_NOT_ENOUGH_MEMORY)) // Writing to the log can fail under OOM (observed on Vista)
+ {
+ // If the event log file was neither corrupt nor full, then assert,
+ // since something is wrong!
+#ifndef _TARGET_ARM_
+ //ARMTODO: Event reporting is currently non-functional on winpe.
+ _ASSERTE(!"EventReporter::Report - Unable to log details to event log!");
+#endif
+ }
+ else
+ {
+ // Since the event log file was either corrupt or full, simply
+ // write this status to our log. We cannot fix a corrupt file
+ // and we cannot clear the log since we dont administer the machine.
+ STRESS_LOG0(LF_CORDB, LL_INFO10000, "EventReporter::Report: Event log is full, corrupt or not enough memory to process.\n");
+ }
+ }
+ }
+}
+
+
+//---------------------------------------------------------------------------------------
+//
+// Check if we should generate an EventLog entry.
+//
+// Arguments:
+// None
+//
+// Return Value:
+// TRUE - We should generate one entry
+// FALSE - We should not generate one entry
+//
+BOOL ShouldLogInEventLog()
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ }
+ CONTRACTL_END;
+
+#ifndef FEATURE_CORESYSTEM
+ // If the process is being debugged, don't log
+ if ((CORDebuggerAttached() || IsDebuggerPresent())
+#ifdef _DEBUG
+ // Allow debug to be able to break in
+ &&
+ CLRConfig::GetConfigValue(CLRConfig::INTERNAL_BreakOnUncaughtException) == 0
+#endif
+ )
+ {
+ return FALSE;
+ }
+
+ static LONG fOnce = 0;
+ if (fOnce == 1 || FastInterlockExchange(&fOnce, 1) == 1)
+ {
+ return FALSE;
+ }
+
+ if (CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_logFatalError) == 0)
+ return FALSE;
+ else
+ return TRUE;
+#else
+ // no event log on Apollo
+ return FALSE;
+#endif //!FEATURE_CORESYSTEM
+}
+
+//---------------------------------------------------------------------------------------
+//
+// A callback function for stack walker to save signature of one managed frame.
+//
+// Arguments:
+// pCF - The frame info passed by stack walker.
+// pData - The data to pass info between stack walker and its caller
+//
+// Return Value:
+// SWA_CONTINUE - Continue search for the next frame.
+//
+struct LogCallstackData
+{
+ EventReporter *pReporter;
+ SmallStackSString *pWordAt;
+};
+
+StackWalkAction LogCallstackForEventReporterCallback(
+ CrawlFrame *pCF, //
+ VOID* pData // Caller's private data
+)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ SO_INTOLERANT;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ EventReporter* pReporter = ((LogCallstackData*)pData)->pReporter;
+ SmallStackSString *pWordAt = ((LogCallstackData*)pData)->pWordAt;
+
+ MethodDesc *pMD = pCF->GetFunction();
+ _ASSERTE(pMD != NULL);
+
+ StackSString str;
+ str = *pWordAt;
+
+ TypeString::AppendMethodInternal(str, pMD, TypeString::FormatNamespace|TypeString::FormatFullInst|TypeString::FormatSignature);
+ pReporter->AddStackTrace(str);
+
+ return SWA_CONTINUE;
+}
+
+//---------------------------------------------------------------------------------------
+//
+// A woker to save managed stack trace.
+//
+// Arguments:
+// reporter - EventReporter object for EventLog
+//
+// Return Value:
+// None
+//
+void LogCallstackForEventReporterWorker(EventReporter& reporter)
+{
+ Thread* pThread = GetThread();
+ _ASSERTE (pThread);
+
+ SmallStackSString WordAt;
+
+ if (!WordAt.LoadResource(CCompRC::Optional, IDS_ER_WORDAT))
+ {
+ WordAt.Set(W(" at"));
+ }
+ else
+ {
+ WordAt.Insert(WordAt.Begin(), W(" "));
+ }
+ WordAt += W(" ");
+
+ LogCallstackData data = {
+ &reporter, &WordAt
+ };
+
+ pThread->StackWalkFrames(&LogCallstackForEventReporterCallback, &data, QUICKUNWIND | FUNCTIONSONLY);
+}
+
+//---------------------------------------------------------------------------------------
+//
+// Generate stack trace info for those managed frames on the stack currently.
+//
+// Arguments:
+// reporter - EventReporter object for EventLog
+//
+// Return Value:
+// None
+//
+void LogCallstackForEventReporter(EventReporter& reporter)
+{
+ WRAPPER_NO_CONTRACT;
+
+ reporter.BeginStackTrace();
+
+ LogCallstackForEventReporterWorker(reporter);
+}
+
+void ReportExceptionStackHelper(OBJECTREF exObj, EventReporter& reporter, SmallStackSString& wordAt, int recursionLimit)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ }
+ CONTRACTL_END;
+
+ if (exObj == NULL || recursionLimit == 0)
+ {
+ return;
+ }
+
+ struct
+ {
+ OBJECTREF exObj;
+ EXCEPTIONREF ex;
+ STRINGREF remoteStackTraceString;
+ } gc;
+ ZeroMemory(&gc, sizeof(gc));
+ gc.exObj = exObj;
+ gc.ex = (EXCEPTIONREF)exObj;
+
+ GCPROTECT_BEGIN(gc);
+
+ ReportExceptionStackHelper((gc.ex)->GetInnerException(), reporter, wordAt, recursionLimit - 1);
+
+ StackSString exTypeStr;
+ TypeString::AppendType(exTypeStr, TypeHandle((gc.ex)->GetMethodTable()), TypeString::FormatNamespace | TypeString::FormatFullInst);
+ reporter.AddDescription(exTypeStr);
+
+ gc.remoteStackTraceString = (gc.ex)->GetRemoteStackTraceString();
+ if (gc.remoteStackTraceString != NULL && gc.remoteStackTraceString->GetStringLength())
+ {
+ SString remoteStackTrace;
+ gc.remoteStackTraceString->GetSString(remoteStackTrace);
+
+ // If source info is contained, trim it
+ StripFileInfoFromStackTrace(remoteStackTrace);
+
+ reporter.AddStackTrace(remoteStackTrace);
+ }
+
+ DebugStackTrace::GetStackFramesData stackFramesData;
+ stackFramesData.pDomain = NULL;
+ stackFramesData.skip = 0;
+ stackFramesData.NumFramesRequested = 0;
+
+ DebugStackTrace::GetStackFramesFromException(&(gc.exObj), &stackFramesData);
+
+ for (int j = 0; j < stackFramesData.cElements; j++)
+ {
+ StackSString str;
+ str = wordAt;
+ TypeString::AppendMethodInternal(str, stackFramesData.pElements[j].pFunc, TypeString::FormatNamespace | TypeString::FormatFullInst | TypeString::FormatSignature);
+ reporter.AddStackTrace(str);
+ }
+
+ StackSString separator(L""); // This will result in blank line
+ reporter.AddStackTrace(separator);
+
+ GCPROTECT_END();
+}
+
+
+//---------------------------------------------------------------------------------------
+//
+// Generate an EventLog entry for unhandled exception.
+//
+// Arguments:
+// pExceptionInfo - Exception information
+//
+// Return Value:
+// None
+//
+void DoReportForUnhandledException(PEXCEPTION_POINTERS pExceptionInfo)
+{
+ WRAPPER_NO_CONTRACT;
+
+ if (ShouldLogInEventLog())
+ {
+ Thread *pThread = GetThread();
+ EventReporter reporter(EventReporter::ERT_UnhandledException);
+ EX_TRY
+ {
+ StackSString s;
+ if (pThread && pThread->HasException() != NULL)
+ {
+ GCX_COOP();
+ struct
+ {
+ OBJECTREF throwable;
+ STRINGREF originalExceptionMessage;
+ } gc;
+ ZeroMemory(&gc, sizeof(gc));
+
+ GCPROTECT_BEGIN(gc);
+
+ gc.throwable = pThread->GetThrowable();
+ _ASSERTE(gc.throwable != NULL);
+
+#ifdef FEATURE_CORECLR
+ // On CoreCLR, managed code execution happens in non-default AppDomains and all threads have an AD transition
+ // at their base from DefaultDomain to the target Domain before they start executing managed code. Thus, when
+ // an exception goes unhandled in a non-default AppDomain on a reverse pinvoke thread, the original exception details are copied
+ // to the Message property of System.CrossAppDomainMarshaledException instance at the AD transition boundary,
+ // and the exception is then thrown in the calling AppDomain. This is done since CoreCLR does not support marshaling of
+ // objects across AppDomains.
+ //
+ // On SL, exceptions dont go unhandled to the OS. But in WLC, they can. Thus, when the scenario above happens for WLC,
+ // the OS will invoke CoreCLR's registered UEF and reach here to write the stacktrace from the
+ // exception object (which will be a CrossAppDomainMarshaledException instance) to the event log. At this point,
+ // we shall be in DefaultDomain.
+ //
+ // However, the original exception details are in the Message property of CrossAppDomainMarshaledException. So, we should
+ // look that up and if it is not empty, add those details to the EventReporter so that they get written to the
+ // event log as well.
+ //
+ // We can also be here when in non-DefaultDomain an exception goes unhandled on a pure managed thread. In such a case,
+ // we wont have CrossAppDomainMarshaledException instance but the original exception object that will be used to extract
+ // the stack trace from.
+ if (pThread->GetDomain()->IsDefaultDomain())
+ {
+ if (IsExceptionOfType(kCrossAppDomainMarshaledException, &(gc.throwable)))
+ {
+ // This is a CrossAppDomainMarshaledException instance - check if it has
+ // something for us in the Message property.
+ gc.originalExceptionMessage = ((EXCEPTIONREF)gc.throwable)->GetMessage();
+ if (gc.originalExceptionMessage != NULL)
+ {
+ // Ok - so, we have details about the original exception. Add them to the
+ // EventReporter object so that they get written to the event log.
+ reporter.AddDescription(gc.originalExceptionMessage->GetBuffer());
+
+ LOG((LF_EH, LL_INFO100, "DoReportForUnhandledException - Added original exception details to EventReporter from CrossAppDomainMarshaledException object.\n"));
+ }
+ else
+ {
+ LOG((LF_EH, LL_INFO100, "DoReportForUnhandledException - Original exception details not present in CrossAppDomainMarshaledException object.\n"));
+ }
+ }
+ }
+ else
+#endif // FEATURE_CORECLR
+ {
+ if (IsException(gc.throwable->GetMethodTable()))
+ {
+ SmallStackSString wordAt;
+ if (!wordAt.LoadResource(CCompRC::Optional, IDS_ER_WORDAT))
+ {
+ wordAt.Set(W(" at"));
+ }
+ else
+ {
+ wordAt.Insert(wordAt.Begin(), W(" "));
+ }
+ wordAt += W(" ");
+
+ ReportExceptionStackHelper(gc.throwable, reporter, wordAt, /* recursionLimit = */10);
+ }
+ else
+ {
+ TypeString::AppendType(s, TypeHandle(gc.throwable->GetMethodTable()), TypeString::FormatNamespace | TypeString::FormatFullInst);
+ reporter.AddDescription(s);
+ reporter.BeginStackTrace();
+ LogCallstackForEventReporterWorker(reporter);
+ }
+ }
+
+ GCPROTECT_END();
+ }
+ else
+ {
+ InlineSString<80> ssErrorFormat;
+ if(!ssErrorFormat.LoadResource(CCompRC::Optional, IDS_ER_UNHANDLEDEXCEPTIONINFO))
+ ssErrorFormat.Set(W("exception code %1, exception address %2"));
+ SmallStackSString exceptionCodeString;
+ exceptionCodeString.Printf(W("%x"), pExceptionInfo->ExceptionRecord->ExceptionCode);
+ SmallStackSString addressString;
+ addressString.Printf(W("%p"), (UINT_PTR)pExceptionInfo->ExceptionRecord->ExceptionAddress);
+ s.FormatMessage(FORMAT_MESSAGE_FROM_STRING, (LPCWSTR)ssErrorFormat, 0, 0, exceptionCodeString, addressString);
+ reporter.AddDescription(s);
+ if (pThread)
+ {
+ LogCallstackForEventReporter(reporter);
+ }
+ }
+ }
+ EX_CATCH
+ {
+ // We are reporting an exception. If we throw while working on this, it is not fatal.
+ }
+ EX_END_CATCH(SwallowAllExceptions);
+
+ reporter.Report();
+ }
+}
+
+#if defined(FEATURE_CORECLR)
+// This function will return the product version of CoreCLR
+// instance we are executing in.
+void EventReporter::GetCoreCLRInstanceProductVersion(DWORD * pdwMajor, DWORD * pdwMinor, DWORD * pdwBuild, DWORD * pdwRevision)
+{
+ STATIC_CONTRACT_THROWS;
+
+ // Get the instance of the runtime
+ HMODULE hModRuntime = GetCLRModule();
+ _ASSERTE(hModRuntime != NULL);
+
+ // Get the path to the runtime
+ PathString runtimePath;
+ DWORD ret = WszGetModuleFileName(hModRuntime, runtimePath);
+ if (ret != 0)
+ {
+ // Got the path - get the file version from the path
+ SString path;
+ path.Clear();
+ path.Append(runtimePath);
+ DWORD dwVersionMS = 0;
+ DWORD dwVersionLS = 0;
+ GetProductVersionNumber(path, &dwVersionMS, &dwVersionLS);
+
+ // Get the Major.Minor.Build.Revision details from the returned values
+ *pdwMajor = HIWORD(dwVersionMS);
+ *pdwMinor = LOWORD(dwVersionMS);
+ *pdwBuild = HIWORD(dwVersionLS);
+ *pdwRevision = LOWORD(dwVersionLS);
+ LOG((LF_CORDB, LL_INFO100, "GetCoreCLRInstanceVersion: Got CoreCLR version: %lu.%lu.%lu.%lu\n",
+ *pdwMajor, *pdwMinor, *pdwBuild, *pdwRevision));
+ }
+ else
+ {
+ // Failed to get the path
+ LOG((LF_CORDB, LL_INFO100, "GetCoreCLRInstanceVersion: Unable to get CoreCLR version.\n"));
+ }
+}
+#endif // FEATURE_CORECLR