diff options
author | Jan Kotas <jkotas@microsoft.com> | 2018-03-31 00:29:33 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-03-31 00:29:33 -0700 |
commit | c05eeefbb63cf7f9a466a7371bd44d3254806f03 (patch) | |
tree | b0f688af865656fba94f5a59a0dd6b3f2dba9663 /src/vm | |
parent | 42ae2c03de22d32f96890077e109e1f9e57451d1 (diff) | |
download | coreclr-c05eeefbb63cf7f9a466a7371bd44d3254806f03.tar.gz coreclr-c05eeefbb63cf7f9a466a7371bd44d3254806f03.tar.bz2 coreclr-c05eeefbb63cf7f9a466a7371bd44d3254806f03.zip |
Delete dead code to support OSes prior to Windows 7 (#17367)
Diffstat (limited to 'src/vm')
-rw-r--r-- | src/vm/ceemain.cpp | 15 | ||||
-rw-r--r-- | src/vm/crossgencompile.cpp | 7 | ||||
-rw-r--r-- | src/vm/dwreport.cpp | 2055 | ||||
-rw-r--r-- | src/vm/dwreport.h | 4 | ||||
-rw-r--r-- | src/vm/eepolicy.cpp | 2 | ||||
-rw-r--r-- | src/vm/excep.cpp | 212 | ||||
-rw-r--r-- | src/vm/i386/cgencpu.h | 4 | ||||
-rw-r--r-- | src/vm/i386/cgenx86.cpp | 67 | ||||
-rw-r--r-- | src/vm/threads.cpp | 2 | ||||
-rw-r--r-- | src/vm/vars.cpp | 7 | ||||
-rw-r--r-- | src/vm/vars.hpp | 4 |
11 files changed, 65 insertions, 2314 deletions
diff --git a/src/vm/ceemain.cpp b/src/vm/ceemain.cpp index 20b579af9a..0f2efd64c0 100644 --- a/src/vm/ceemain.cpp +++ b/src/vm/ceemain.cpp @@ -910,19 +910,8 @@ void EEStartupHelper(COINITIEE fFlags) #ifndef CROSSGEN_COMPILE -#ifndef FEATURE_PAL - // Watson initialization must precede InitializeDebugger() and InstallUnhandledExceptionFilter() - // because on CoreCLR when Waston is enabled, debugging service needs to be enabled and UEF will be used. - if (!InitializeWatson(fFlags)) - { - IfFailGo(E_FAIL); - } - - // Note: In Windows 7, the OS will take over the job of error reporting, and so most - // of our watson code should not be used. In such cases, we will however still need - // to provide some services to windows error reporting, such as computing bucket - // parameters for a managed unhandled exception. - if (RunningOnWin7() && IsWatsonEnabled() && !RegisterOutOfProcessWatsonCallbacks()) +#ifndef FEATURE_PAL + if (!RegisterOutOfProcessWatsonCallbacks()) { IfFailGo(E_FAIL); } diff --git a/src/vm/crossgencompile.cpp b/src/vm/crossgencompile.cpp index f608afcad4..47894bfbdd 100644 --- a/src/vm/crossgencompile.cpp +++ b/src/vm/crossgencompile.cpp @@ -255,13 +255,6 @@ PCODE MethodDesc::TryGetMultiCallableAddrOfCode(CORINFO_ACCESS_FLAGS accessFlags return 0x321; } -#ifdef _TARGET_X86_ -BOOL Runtime_Test_For_SSE2() -{ - return TRUE; -} -#endif - #ifdef _TARGET_AMD64_ INT32 rel32UsingJumpStub(INT32 UNALIGNED * pRel32, PCODE target, MethodDesc *pMethod, LoaderAllocator *pLoaderAllocator /* = NULL */, bool throwOnOutOfMemoryWithinRange /*= true*/) diff --git a/src/vm/dwreport.cpp b/src/vm/dwreport.cpp index 57d67e7c22..0890f3f334 100644 --- a/src/vm/dwreport.cpp +++ b/src/vm/dwreport.cpp @@ -27,75 +27,13 @@ #include "utilcode.h" #include "../dlls/mscorrc/resource.h" // for resource ids -#include "imagehlp.h" - EFaultRepRetVal DoReportFault(EXCEPTION_POINTERS * pExceptionInfo); -// Should the CLR use Watson to report fatal errors and unhandled exceptions? -static BOOL g_watsonErrorReportingEnabled = FALSE; // Variables to control launching Watson only once, but making all threads wait for that single launch to finish. LONG g_watsonAlreadyLaunched = 0; // Used to note that another thread has done Watson. -HandleHolder g_hWatsonCompletionEvent = NULL; // Used to signal that Watson has finished. - -const WCHAR kErrorReportingPoliciesKey[] = W("SOFTWARE\\Policies\\Microsoft\\PCHealth\\ErrorReporting"); -const WCHAR kErrorReportingKey[] = W("SOFTWARE\\Microsoft\\PCHealth\\ErrorReporting"); - -const WCHAR kShowUIValue[] = W("ShowUI"); -const WCHAR kForceQueueModeValue[] = W("ForceQueueMode"); -const WCHAR kDoReportValue[] = W("DoReport"); -const WCHAR kAllOrNoneValue[] = W("AllOrNone"); -const WCHAR kIncludeMSAppsValue[] = W("IncludeMicrosoftApps"); -const WCHAR kIncludeWindowsAppsValue[] = W("IncludeWindowsApps"); -const WCHAR kExclusionListKey[] = W("SOFTWARE\\Microsoft\\PCHealth\\ErrorReporting\\ExclusionList"); -const WCHAR kInclusionListKey[] = W("SOFTWARE\\Microsoft\\PCHealth\\ErrorReporting\\InclusionList"); -const WCHAR kExclusionListSubKey[] = W("\\ExclusionList"); -const WCHAR kInclusionListSubKey[] = W("\\InclusionList"); - - -// Default values for various registry keys -const DWORD kDefaultShowUIValue = 1; -const DWORD kDefaultForceQueueModeValue = 0; -const DWORD kDefaultDoReportValue = 1; -const DWORD kDefaultAllOrNoneValue = 1; -const DWORD kDefaultExclusionValue = 0; -const DWORD kDefaultInclusionValue = 0; -const DWORD kDefaultIncludeMSAppsValue = 1; -const DWORD kDefaultIncludeWindowsAppsValue = 1; - -// Default value for the default debugger and auto debugger attach settings. -const BOOL kDefaultDebuggerIsWatson = FALSE; -const BOOL kDefaultAutoValue = FALSE; - -// When debugging the watson process itself, the faulting process will spin -// waiting for Watson to signal various events. If these waits time out, the -// faulting process will go ahead and exit, which is sub-optimal if you need to -// inspect the faulting process with the debugger at the same time. In debug -// builds, use a longer wait time, since watson may be stopped under the -// debugger for a while. - -#ifdef _DEBUG -const DWORD kDwWaitTime = DW_TIMEOUT_VALUE * 1000; -#else -const DWORD kDwWaitTime = DW_TIMEOUT_VALUE; -#endif - -#ifdef _TARGET_X86_ - const DWORD kWatsonRegKeyOptions = 0; -#else - const DWORD kWatsonRegKeyOptions = KEY_WOW64_32KEY; -#endif - -const WCHAR kWatsonPath[] = WATSON_INSTALLED_REG_SUBPATH; -#if defined(_TARGET_X86_) -const WCHAR kWatsonValue[] = WATSON_INSTALLED_REG_VAL; -#else -const WCHAR kWatsonValue[] = WATSON_INSTALLED_REG_VAL_IA64; -#endif -const WCHAR* kWatsonImageNameOnLonghorn = W("\\dw20.exe"); - typedef HMODULE (*AcquireLibraryHandleFn)(LPCWSTR); template <AcquireLibraryHandleFn AcquireLibraryHandleFnPtr, bool RequiresFree> @@ -143,43 +81,11 @@ typedef SimpleModuleHolder<CLRLoadLibrary, true> WerModuleHolder; BOOL IsWatsonEnabled() { LIMITED_METHOD_CONTRACT; - return g_watsonErrorReportingEnabled; + return TRUE; } //------------------------------------------------------------------------------ // Description -// Initializes watson global critsec and event. Records whether run via -// managed .exe. -// -// Parameters -// fFlags -- the COINITIEE flags used to start the runtime. -// -// Returns -// TRUE -- always -//------------------------------------------------------------------------------ -BOOL InitializeWatson(COINITIEE fFlags) -{ - LIMITED_METHOD_CONTRACT; - - // Watson is enabled for all SKUs - g_watsonErrorReportingEnabled = TRUE; - - LOG((LF_EH, LL_INFO10, "InitializeWatson: %s\n", g_watsonErrorReportingEnabled ? "enabled" : "disabled")); - - if (!IsWatsonEnabled()) - { - return TRUE; - } - - // Create the event that all-but-the-first threads will wait on (the first thread - // will set the event when Watson is done.) - g_hWatsonCompletionEvent = WszCreateEvent(NULL, TRUE /*manual reset*/, FALSE /*initial state*/, NULL); - return (g_hWatsonCompletionEvent != NULL); - -} // BOOL InitializeWatson() - -//------------------------------------------------------------------------------ -// Description // Register out-of-process Watson callbacks provided in DAC dll for WIN7 or later // // Parameters @@ -199,7 +105,6 @@ BOOL RegisterOutOfProcessWatsonCallbacks() { NOTHROW; GC_NOTRIGGER; - PRECONDITION(RunningOnWin7()); } CONTRACTL_END; @@ -272,85 +177,9 @@ BOOL RegisterOutOfProcessWatsonCallbacks() } //------------------------------------------------------------------------------ -// CreateWatsonSharedMemory -// // Description -// -// Creates a shared memory block for communication with Watson -// -// Parameters -// hWatsonSharedMemory -- [out] The handle to the watson shared memory. -// ppWatsonSharedMemory -- [out] A pointer to the Watson shared memory. -// Returns -// S_OK -- if the function complete normally. -// FALSE -- otherwise -// Exceptions -// None -//------------------------------------------------------------------------------ -HRESULT CreateWatsonSharedMemory(HANDLE* hWatsonSharedMemory, - DWSharedMem** ppWatsonSharedMemory); - //------------------------------------------------------------------------------ // Description -// Alerts the host that the thread is leaving the runtime, and sleeps -// waiting for an object to be signalled -// -// Parameters -// handle -- the handle to wait on -// timeout -- the length of time to wait -// -// Returns -// DWORD -- The return value from WaitForSingleObject -// -// Exceptions -// None -// -// Notes -// winwrap.h prevents us from using SetEvent by including -// #define SetEvent Dont_Use_SetEvent -// This is because using SetEvent within the runtime will result in poor -// interaction with any sort of host process (e.g. SQL). We can use the -// SetEvent/WaitForSingleObject primitives as long as we do some other work to -// make sure the host understands. -//------------------------------------------------------------------------------ -#undef SetEvent -DWORD ClrWaitForSingleObject(HANDLE handle, DWORD timeout) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - SO_TOLERANT; - MODE_ANY; - } - CONTRACTL_END; - - CONTRACT_VIOLATION(ThrowsViolation); - - return WaitForSingleObject(handle, timeout); -} // DWORD ClrWaitForSingleObject() - -//------------------------------------------------------------------------------ -// Helper class to set an event in destructor -- allows setting an event on the -// way out of a function. -// -// Used to synchronize multiple threads with unhandled exceptions -- only the -// first will run Watson, and all the rest will wait on the first one to be -// done. -//------------------------------------------------------------------------------ -class SettingEventHolder -{ -public: - SettingEventHolder(HANDLE &event) : m_event(event), m_bSetIt(FALSE) { LIMITED_METHOD_CONTRACT; } - ~SettingEventHolder() { LIMITED_METHOD_CONTRACT; if (m_bSetIt && m_event) SetEvent(m_event); } - void EnableSetting() { LIMITED_METHOD_CONTRACT; m_bSetIt = TRUE; } - DWORD DoWait(DWORD timeout=INFINITE_TIMEOUT) { WRAPPER_NO_CONTRACT; return m_event ? ClrWaitForSingleObject(m_event, timeout) : 0; } - -private: - HANDLE m_event; // The event to set - BOOL m_bSetIt; // If true, set event in destructor. -}; - HRESULT DwGetFileVersionInfo( __in_z LPCWSTR wszFilePath, USHORT& major, @@ -381,168 +210,6 @@ HRESULT DwGetFileVersionInfo( return result; } -enum MicrosoftAppTypes -{ - MicrosoftAppTypesNone = 0, - MicrosoftAppTypesWindows = 0x1, - MicrosoftAppTypesOther = 0x2 -}; - -inline void SetMSFTApp(DWORD &AppType) { LIMITED_METHOD_CONTRACT; AppType |= MicrosoftAppTypesOther; } -inline void SetMSFTWindowsApp(DWORD &AppType) { LIMITED_METHOD_CONTRACT; AppType |= MicrosoftAppTypesWindows; } - -inline BOOL IsMSFTApp(DWORD AppType) { LIMITED_METHOD_CONTRACT; return (AppType & MicrosoftAppTypesOther) ? TRUE : FALSE; } -inline BOOL IsMSFTWindowsApp(DWORD AppType) { LIMITED_METHOD_CONTRACT; return (AppType & MicrosoftAppTypesWindows) ? TRUE : FALSE; } - - -//------------------------------------------------------------------------------ -// Description -// Determine if the application is a Microsoft application. -// -// Parameters -// wszFilePath Path to a file to exctract the information from -// pAppTypes [out] Put MicrosoftAppTypes here. -// -// Returns -// S_OK If the function succeede -// E_XXXX Failure result. -// -// Exceptions -// None -//------------------------------------------------------------------------------ -HRESULT DwCheckCompany( // S_OK or error. - __in_z LPWSTR wszFilePath, // Path to the executable. - DWORD* pAppTypes) // Non-microsoft, microsoft, microsoft windows. -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - // - // Note that this code is equivalent to FusionGetFileVersionInfo, found in fusion\asmcache\asmcache.cpp - // - - HRESULT hr = S_OK; // result of some operation - DWORD dwHandle = 0; - DWORD bufSize = 0; // Size of allocation for VersionInfo. - DWORD ret; - - // Avoid confusion - *pAppTypes = MicrosoftAppTypesNone; - - // Find the buffer size for the version info structure we need to create - EX_TRY - { - bufSize = GetFileVersionInfoSizeW(wszFilePath, &dwHandle); - if (!bufSize) - { - hr = HRESULT_FROM_GetLastErrorNA(); - } - } - EX_CATCH - { - hr = E_OUTOFMEMORY; - } - EX_END_CATCH(SwallowAllExceptions); - if (!bufSize) - { - return hr; - } - - // Allocate the buffer for the version info structure - // _alloca() can't return NULL -- raises STATUS_STACK_OVERFLOW. - BYTE* pVersionInfoBuffer = reinterpret_cast< BYTE* >(_alloca(bufSize)); - - // Extract the version information blob. The version information - // contains much more than the actual item of interest. - { - // If the previoud GetFileVersionInfoSizeW succeeds, version.dll has been loaded - // in the process, and delay load of GetFileVersionInfoW will not throw. - CONTRACT_VIOLATION(ThrowsViolation); - ret = GetFileVersionInfoW(wszFilePath, dwHandle, bufSize, pVersionInfoBuffer); - - if (!ret) - { - return HRESULT_FROM_GetLastErrorNA(); - } - } - - // Extract the actual CompanyName and compare it to "Microsoft" and - // "MicrosoftWindows" - - // Get the language and codepage for the version info. - UINT size = 0; - struct - { - WORD language; - WORD codePage; - }* translation; - - { - // If the previoud GetFileVersionInfoSizeW succeeds, version.dll has been loaded - // in the process, and delay load of GetFileVersionInfoW will not throw. - CONTRACT_VIOLATION(ThrowsViolation); - ret = VerQueryValueW(pVersionInfoBuffer, W("\\VarFileInfo\\Translation"), - reinterpret_cast< void **>(&translation), &size); - - if (!ret || size == 0) - { - return HRESULT_FROM_GetLastErrorNA(); - } - } - - // Build the query key for the language-specific company name resource. - WCHAR buf[64]; //----+----1----+----2----+----3----+----4 - _snwprintf_s(buf, NumItems(buf), _TRUNCATE, W("\\StringFileInfo\\%04x%04x\\CompanyName"), - translation->language, translation->codePage); - - // Get the company name. - WCHAR *name; - { - // If the previoud GetFileVersionInfoSizeW succeeds, version.dll has been loaded - // in the process, and delay load of GetFileVersionInfoW will not throw. - CONTRACT_VIOLATION(ThrowsViolation); - ret = VerQueryValueW(pVersionInfoBuffer, buf, - reinterpret_cast< void** >(&name), &size); - } - - // If there is company name info, check it. - if (ret != 0 && size != 0 && wcsstr(name, W("Microsoft"))) - { - SetMSFTApp(*pAppTypes); - } - - - // Now build the query key for the language-specific product name resource. - _snwprintf_s(buf, NumItems(buf), _TRUNCATE, W("\\StringFileInfo\\%04x%04x\\ProductName"), - translation->language, translation->codePage); - - // Get the product name. - { - // If the previoud GetFileVersionInfoSizeW succeeds, version.dll has been loaded - // in the process, and delay load of GetFileVersionInfoW will not throw. - CONTRACT_VIOLATION(ThrowsViolation); - ret = VerQueryValueW(pVersionInfoBuffer, buf, - reinterpret_cast< void** >(&name), &size); - } - - // If there is product name info, check it. - if (ret != 0 && size != 0 && wcsstr(name, W("Microsoft\x0ae Windows\x0ae"))) - { - SetMSFTWindowsApp(*pAppTypes); - } - - return S_OK; - -} // HRESULT DwCheckCompany() - - -//------------------------------------------------------------------------------ -// Description // Read the description from the resource section. // // Parameters @@ -797,914 +464,6 @@ int DwGetAssemblyVersion( // Number of characters written. } // int DwGetAssemblyVersion() - -//------------------------------------------------------------------------------ -// CLRWatsonHelper class -// -// Certain registry keys affect the behavior of watson. In particulary, they -// control -// o whether or not a Watson report should result in UI popups -// o which debugger should be used to JIT attach to the faulting process -// o whether error reports should be sent at all. -// This class is a holder for static functions that access these registry keys -// to determine the proper settings. -// -//------------------------------------------------------------------------------ -class CLRWatsonHelper -{ -public: - enum WHDebugAction - { - WHDebug_InvalidValue, - WHDebug_AutoLaunch, - WHDebug_AskToLaunch, - WHDebug_DontLaunch - } m_debugAction; - - enum WHReportAction - { - WHReport_InvalidValue, - WHReport_AutoQueue, - WHReport_AskToSend, - WHReport_DontSend - } m_reportAction; - - enum WHDialogAction - { - WHDialog_InvalidValue, - WHDialog_OkToPopup, - WHDialog_DontPopup - } m_dialogAction; - - CLRWatsonHelper() - : m_debugAction(WHDebug_InvalidValue), - m_reportAction(WHReport_InvalidValue), - m_dialogAction(WHDialog_InvalidValue) - { LIMITED_METHOD_CONTRACT; } - - void Init(BOOL bIsManagedFault, TypeOfReportedError tore); - - // Does the current interactive USER have sufficient permissions to - // launch Watson or a debugger against this PROCESS? - BOOL CurrentUserHasSufficientPermissions(); - - // Should a debugger automatically, or should the user be queried for a debugger? - BOOL ShouldDebug(); - - // Should a managed debugger be launched, without even asking? - BOOL ShouldAutoAttach(); - - // Should Watson include a "Debug" button? - BOOL ShouldOfferDebug(); - - // Should a Watson report be generated? - BOOL ShouldReport(); - - // Should there be a popup? Possibly with only "quit"? - BOOL ShouldShowUI(); - - // If a Watson report is generated, should it be auto-queued? - // (vs asking the user what to do about it) - BOOL ShouldQueueReport(); - -private: - // Looks in HKCU/Software/Policies/Microsoft/PCHealth/ErrorReporting - // then in HKLM/ " " " " " - // then in HKCU/SOftware/Microsoft/PCHealth/ErrorReporting - // then in HKLM/ " " " " - static int GetPCHealthConfigLong( // Return value from registry or default. - LPCWSTR szName, // Name of value to get. - int iDefault); // Default value to return if not found. - - // Like above, but searches for a subkey with the given value. - static BOOL GetPCHealthConfigSubKeyLong(// Return value from registry or default. - LPCWSTR szSubKey, // Name of the subkey. - LPCWSTR szName, // Name of value to get. - int iDefault, // Default value to return if not found. - DWORD *pValue); // Put value here. - - void AssertValid() - { - LIMITED_METHOD_CONTRACT; - _ASSERTE(m_debugAction != WHDebug_InvalidValue); - _ASSERTE(m_reportAction != WHReport_InvalidValue); - _ASSERTE(m_dialogAction != WHDialog_InvalidValue); - } - -}; // class CLRWatsonHelper - -//------------------------------------------------------------------------------ -// Description -// Initialization for watson helper class. -// -// Parameters -// bIsManagedFault - true if EXCEPTION_COMPLUS or fault from jitted code. -// - false otherwise -// -// -// Notes: -// - Launches and Pops always happen to the same session in which the -// process is running. -// - This function computes what actions should happen, but doesn't do any. -// -// This routine returns which actions should be taken given the current registry -// settings and environment. It implements the following matrix: -// -// <<-- AutoLaunch -->> -// TRUE FALSE -// Interactive process A3 B2 -// Non-interactive process A3 C1 -// -// Action codes: -// A - Auto attach debugger -// B - Ask to attach debugger -// C - Don't attach debugger -// -// 1 - Auto Queue Watson report -// 2 - Ask to Send Watson report -// 3 - Don't send Watson report -// -// -// CLRWatsonHelper::Init -//------------------------------------------------------------------------------ -void CLRWatsonHelper::Init( - BOOL bIsManagedFault, // Is the fault in question from managed code? - TypeOfReportedError tore) // What sort of error is this? -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - // Initialize returned values - WHDebugAction tmpDebugAction = WHDebug_InvalidValue; - WHReportAction tmpReportAction = WHReport_InvalidValue; - WHDialogAction tmpDialogAction = WHDialog_InvalidValue; - - // First run the matrix, then later provide the over-rides - BOOL fRunningInteractive = RunningInteractive(); - - if (fRunningInteractive) - { - // Interactive services and interactive apps running as LocalSystem are considered non-interactive - // so that we don't display any UI for them. Note that we should check the process token (and not the - // thread token if the thread is impersonating a user) to determine if the app is running as LocalSystem. - // This is because Watson displays UI for us and Watson is run by calling CreateProcess. CreateProcess - // always creates child processes using the process token. - - BOOL fLocalSystemOrService; - if (RunningAsLocalSystemOrService(fLocalSystemOrService) != ERROR_SUCCESS) - { - // Err on the side of caution; treat the app as non-interactive - fRunningInteractive = FALSE; - } - else if (fLocalSystemOrService) - { - fRunningInteractive = FALSE; - } - } - - BOOL bAutoLaunch = FALSE; - SString ssDummy; - - GetDebuggerSettingInfo(ssDummy, &bAutoLaunch); - - if (bAutoLaunch) - { - tmpDebugAction = WHDebug_AutoLaunch; - tmpReportAction = WHReport_DontSend; - tmpDialogAction = WHDialog_DontPopup; - } - else - { - if (fRunningInteractive) - { - tmpDebugAction = WHDebug_AskToLaunch; - tmpReportAction = WHReport_AskToSend; - tmpDialogAction = WHDialog_OkToPopup; - } - else - { - // Non-interactive process - tmpDebugAction = WHDebug_DontLaunch; - tmpReportAction = WHReport_AutoQueue; - tmpDialogAction = WHDialog_DontPopup; - } - } - - // If this is a breakpoint, never send a report. - if (tore.IsBreakpoint()) - tmpReportAction = WHReport_DontSend; - - // Store off the results. - m_debugAction = tmpDebugAction; - m_reportAction = tmpReportAction; - m_dialogAction = tmpDialogAction; - - // Done. Log some stuff in debug mode. - #if defined(_DEBUG) - { - char *(rda[]) = {"InvalidValue", "AutoDebug", "AskToDebug", "DontDebug"}; - char *(rwa[]) = {"InvalidValue", "AutoQueue", "AskToSend", "DontSend"}; - char *(rdlga[]) = {"InvalidValue", "OkToPopup", "DontPopup"}; - LOG((LF_EH, LL_INFO100, "CLR Watson: debug action: %s\n", rda[m_debugAction])); - LOG((LF_EH, LL_INFO100, "CLR Watson: report action: %s\n", rwa[m_reportAction])); - LOG((LF_EH, LL_INFO100, "CLR Watson: dialog action: %s\n", rdlga[m_dialogAction])); - #define LB(expr) LOG((LF_EH, LL_INFO100, "CLR Watson: " #expr ": %s\n", ((expr) ? "true" : "false") )) - LB(CurrentUserHasSufficientPermissions()); - LB(ShouldDebug()); - LB(ShouldAutoAttach()); - LB(ShouldOfferDebug()); - LB(ShouldReport()); - LB(ShouldQueueReport()); - #undef LB - } - #endif - -} // void CLRWatsonHelper::Init() - - -//------------------------------------------------------------------------------ -// CurrentUserHasSufficientPermissions -// -// Determines if the user logged in has the correct permissions to launch Watson. -// -// Parameters: -// None. -// -// Returns: -// TRUE if the user has sufficient permissions, else FALSE -//------------------------------------------------------------------------------ -BOOL CLRWatsonHelper::CurrentUserHasSufficientPermissions() -{ - // TODO! Implement! - return TRUE; -} // BOOL CLRWatsonHelper::CurrentUserHasSufficientPermissions() - - - -//------------------------------------------------------------------------------ -// Description -// Determines whether we will show Watson at all. -// -// Parameters -// none -// -// Returns -// TRUE -- If Watson should show UI. -// FALSE -- Otherwise -//------------------------------------------------------------------------------ -BOOL CLRWatsonHelper::ShouldShowUI() -{ - WRAPPER_NO_CONTRACT; - - AssertValid(); - - return (m_dialogAction == WHDialog_OkToPopup); -} // BOOL CLRWatsonHelper::ShouldShowUI() - -//------------------------------------------------------------------------------ -// Description -// Determines whether a debugger will (or may be) launched. True if there -// is an auto-launch debugger, or if we will ask the user. -// -// Parameters -// none -// -// Returns -// TRUE -- If a debugger might be attached. -// FALSE -- Otherwise -//------------------------------------------------------------------------------ -BOOL CLRWatsonHelper::ShouldDebug() -{ - LIMITED_METHOD_CONTRACT; - - return ShouldOfferDebug() || ShouldAutoAttach(); -} // BOOL CLRWatsonHelper::ShouldDebug() - -//------------------------------------------------------------------------------ -// Description -// Determines whether or not the Debug button should be present in the -// Watson dialog -// -// Parameters -// none -// -// Returns -// TRUE -- if the Debug button should be displayed -// FALSE -- otherwise -// -// Notes -// This means "is there an appropriate debugger registered for auto attach?" -//------------------------------------------------------------------------------ -BOOL CLRWatsonHelper::ShouldOfferDebug() -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - AssertValid(); - - // Permission check. - if (!CurrentUserHasSufficientPermissions()) - { - return FALSE; - } - - // Check based on DbgJitDebugLaunchSetting & interactivity. - if (m_debugAction != WHDebug_AskToLaunch) - { - // Don't ask the user about debugging. Do or don't debug; but don't ask. - return FALSE; - } - - SString ssDebuggerString; - GetDebuggerSettingInfo(ssDebuggerString, NULL); - - // If there is no debugger installed, don't offer to debug, since we can't. - if (ssDebuggerString.IsEmpty()) - { - return FALSE; - } - - return TRUE; - -} // BOOL CLRWatsonHelper::ShouldOfferDebug() - -//------------------------------------------------------------------------------ -// -// ShouldAutoAttach -// -// Description -// Determines whether or not a debugger should be launched -// automatically, without prompting the user. -// -// Parameters -// None. -// -// Returns -// TRUE -- If a debugger should be auto-attached. -// FALSE -- Otherwise -// -//------------------------------------------------------------------------------ -BOOL CLRWatsonHelper::ShouldAutoAttach() -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - AssertValid(); - - // Permissions check. - if (!CurrentUserHasSufficientPermissions()) - { - return FALSE; - } - - return (m_debugAction == WHDebug_AutoLaunch); -} // BOOL CLRWatsonHelper::ShouldAutoAttach() - - -//------------------------------------------------------------------------------ -// Description -// Returns whether a Watson report should be generated. -// -// Parameters -// none -// -// Returns -// TRUE - a Watson report should be generated (with a minidump). -// FALSE - don't generate a report. -// -//------------------------------------------------------------------------------ -BOOL CLRWatsonHelper::ShouldReport() -{ - WRAPPER_NO_CONTRACT; - - AssertValid(); - - // If we queue or ask, we should generate. - return (m_reportAction == WHReport_AutoQueue) || (m_reportAction == WHReport_AskToSend); - -} // BOOL CLRWatsonHelper::ShouldReport() - - -//------------------------------------------------------------------------------ -// Description -// If a Watson report is generated, returns whether it should be auto-queued. -// (vs asking the user what to do about it) -// -// Parameters -// none -// -// Returns -// TRUE - any Watson report should be be queued. -// FALSE - any Watson report is posed to the user for "send" or "don't send". -// -//------------------------------------------------------------------------------ -BOOL CLRWatsonHelper::ShouldQueueReport() -{ - WRAPPER_NO_CONTRACT; - - AssertValid(); - - // If we queue a report. - return (m_reportAction == WHReport_AutoQueue); - -} // BOOL CLRWatsonHelper::ShouldQueueReport() - -//------------------------------------------------------------------------------ -// Description -// Reads a PCHealth configuration LONG value from the registry. -// -// Parameters -// szName -- name of the value -// iDefault -- default value, if not found -// -// Returns -// The value read, or default if no value found. -// -// Exceptions -// None -// -// NOtes: -// Looks in HKCU/Software/Policies/Microsoft/PCHealth/ErrorReporting -// then in HKLM/ " " " " " -// then in HKCU/SOftware/Microsoft/PCHealth/ErrorReporting -// then in HKLM/ " " " " -//------------------------------------------------------------------------------ -int CLRWatsonHelper::GetPCHealthConfigLong( // Return value from registry or default. - LPCTSTR szName, // Name of value to get. - int iDefault) // Default value to return if not found. -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - long iValue; // Actual value from registry. - - // Try HKCR policy key - if (GetRegistryLongValue(HKEY_CURRENT_USER, kErrorReportingPoliciesKey, szName, &iValue, FALSE)) - return iValue; - - // Try HKLM policy key - if (GetRegistryLongValue(HKEY_LOCAL_MACHINE, kErrorReportingPoliciesKey, szName, &iValue, FALSE)) - return iValue; - - // Try HKCR key - if (GetRegistryLongValue(HKEY_CURRENT_USER, kErrorReportingKey, szName, &iValue, FALSE)) - return iValue; - - // Try HKLM key - if (GetRegistryLongValue(HKEY_LOCAL_MACHINE, kErrorReportingKey, szName, &iValue, FALSE)) - return iValue; - - // None of them had value -- return default. - return iDefault; -} // long CLRWatsonHelper::GetPCHealthConfigLong() - -//------------------------------------------------------------------------------ -// Description -// Reads a PCHealth configuration LONG value from the registry, from a -// given subkey. -// -// Parameters -// szSubKey -- name of the subkey. -// szName -- name of the value -// iDefault -- default value, if not found -// pValue -- put value here. -// -// Returns -// TRUE - a value was found in the registry -// FALSE - no value found. -// -// Exceptions -// None -// -// NOtes: -// Looks in HKCU/Software/Policies/Microsoft/PCHealth/ErrorReporting -// then in HKLM/ " " " " " -// then in HKCU/SOftware/Microsoft/PCHealth/ErrorReporting -// then in HKLM/ " " " " -//------------------------------------------------------------------------------ -BOOL CLRWatsonHelper::GetPCHealthConfigSubKeyLong( // Return value from registry or default. - LPCWSTR szSubKey, // Name of the subkey. - LPCWSTR szName, // Name of value to get. - int iDefault, // Default value to return if not found. - DWORD *pValue) // Put the value (registry or default) here. -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - long iValue; // Actual value from registry. - - // Only one thread will *ever* enter this function, so it is safe to use a static - // buffer. We know the the longest strings we will want to catenate. Size - // the buffer appropriately, and we're set. - static WCHAR rcBuf[lengthof(kErrorReportingPoliciesKey) + lengthof(kInclusionListSubKey) + 3]; - - _ASSERT( (wcslen(kErrorReportingPoliciesKey) + wcslen(szSubKey) + 1) < lengthof(rcBuf)); - - // Try HKCR policy key - wcscpy_s(rcBuf, COUNTOF(rcBuf), kErrorReportingPoliciesKey); - wcsncat_s(rcBuf, COUNTOF(rcBuf), szSubKey, lengthof(rcBuf)-wcslen(rcBuf)-1); - - if (GetRegistryLongValue(HKEY_CURRENT_USER, rcBuf, szName, &iValue, FALSE)) - { - *pValue = iValue; - return TRUE; - } - - // Try the HKLM policy key - if (GetRegistryLongValue(HKEY_LOCAL_MACHINE, rcBuf, szName, &iValue, FALSE)) - { - *pValue = iValue; - return TRUE; - } - - // Try HKCR key - wcscpy_s(rcBuf, COUNTOF(rcBuf), kErrorReportingKey); - wcsncat_s(rcBuf, COUNTOF(rcBuf), szSubKey, lengthof(rcBuf)-wcslen(rcBuf)-1); - - if (GetRegistryLongValue(HKEY_CURRENT_USER, rcBuf, szName, &iValue, FALSE)) - { - *pValue = iValue; - return TRUE; - } - - // Try HKLM key - if (GetRegistryLongValue(HKEY_LOCAL_MACHINE, rcBuf, szName, &iValue, FALSE)) - { - *pValue = iValue; - return TRUE; - } - - // None of them had value -- return default. - *pValue = iDefault; - return FALSE; -} // long CLRWatsonHelper::GetPCHealthConfigLong() - - -//------------------------------------------------------------------------------ -//------------------------------------------------------------------------------ -HRESULT CreateWatsonSharedMemory( - HANDLE *hWatsonSharedMemory, - DWSharedMem **ppWatsonSharedMemory) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - // Watson needs to inherit the shared memory block, so we have to set up - // security attributes to make that happens. - SECURITY_ATTRIBUTES securityAttributes; - memset(&securityAttributes, 0, sizeof(securityAttributes)); - securityAttributes.nLength = sizeof(securityAttributes); - securityAttributes.bInheritHandle = TRUE; - - _ASSERTE(NULL != hWatsonSharedMemory); - _ASSERTE(NULL != ppWatsonSharedMemory); - - *hWatsonSharedMemory = NULL; - *ppWatsonSharedMemory = NULL; - - // In cases where we have to return form this function with a failure, we - // need to clean up the handle. Use a holder to take care of that for us. - HandleHolder hTemp = - WszCreateFileMapping(INVALID_HANDLE_VALUE, - &securityAttributes, - PAGE_READWRITE, - 0, - sizeof(DWSharedMem), - NULL); - - if (hTemp == NULL) - { - return HRESULT_FROM_GetLastErrorNA(); - } - - DWSharedMem* pTemp = - static_cast< DWSharedMem* >(CLRMapViewOfFile(hTemp, - FILE_MAP_ALL_ACCESS, - 0, - 0, - sizeof(DWSharedMem))); - - if (NULL == pTemp) - { - return HRESULT_FROM_GetLastErrorNA(); - } - - memset(pTemp, 0, sizeof(DWSharedMem)); - *hWatsonSharedMemory = hTemp; - *ppWatsonSharedMemory = pTemp; - - // We're ready to exit normally and pass the IPC block's handle back to our - // caller, so we don't want to close it. - hTemp.SuppressRelease(); - - return S_OK; -} // HRESULT CreateWatsonSharedMemory() - - - -const WCHAR* kWatsonImageNameOnVista = W("\\dw20.exe"); - -//------------------------------------------------------------------------------ -// Description -// A helper function to launch the Watson process and wait for it to -// complete -// Parameters -// hWatsonSharedMemory -// Handle to the shared memory block to pass to Watson. This handle -// must be inheritable. -// hEventAlive -// hEventDone -// hMutex -// Returns -// true - If watson executed normally -// false - if watson was unable to launch, reported an error, or -// appeared to hang/crash -//------------------------------------------------------------------------------ -BOOL RunWatson( - HANDLE hWatsonSharedMemory, - HANDLE hEventAlive, - HANDLE hEventDone, - HANDLE hMutex) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - PRECONDITION(!RunningOnWin7()); - } - CONTRACTL_END; - - // Since we're doing our own error reporting, we don't want to pop up the - // OS Watson dialog/GPF Dialog. Supress it now. - - PROCESS_INFORMATION processInformation; - STARTUPINFOW startupInfo; - memset(&startupInfo, 0, sizeof(STARTUPINFOW)); - startupInfo.cb = sizeof(STARTUPINFOW); - - HRESULT hr = S_OK; - PathString watsonAppName; - PathString watsonCommandLine; - EX_TRY - { - do - { - - - - - { - HKEYHolder hKey; - // Look for key \\HKLM\Software\Microsoft\PCHealth\ErrorReporting\DW\Installed" - DWORD ret = WszRegOpenKeyEx(HKEY_LOCAL_MACHINE, - kWatsonPath, - 0, - KEY_READ | kWatsonRegKeyOptions, - &hKey); - - if (ERROR_SUCCESS != ret) - { - hr = E_FAIL; - break; - } - - - // Look in ...\DW\Installed for dw0200 (dw0201 on ia64). This will be - // the full path to the executable. - - ClrRegReadString(hKey, kWatsonValue, watsonAppName); - - - COUNT_T len = watsonCommandLine.GetCount(); - WCHAR* buffer = watsonCommandLine.OpenUnicodeBuffer(len); - _snwprintf_s(buffer, - len, - _TRUNCATE, - W("dw20.exe -x -s %lu"), - PtrToUlong(hWatsonSharedMemory)); - watsonCommandLine.CloseBuffer(); - - } - } while (false); - } - EX_CATCH_HRESULT(hr); - - - if (hr != S_OK) - { - return false; - } - - { - BOOL ret = WszCreateProcess(watsonAppName, - watsonCommandLine, - NULL, - NULL, - TRUE, - NULL, - NULL, - NULL, - &startupInfo, - &processInformation); - - if (FALSE == ret) - { - // - // Watson failed to start up. - // - // This can happen if e.g. Watson wasn't installed on the machine. - // - return FALSE; - } - } - - - - // Wait for watson to finish. - // - // This code was more-or-less pasted directly out of the test app for - // watson, found at - // - // \\redist\redist\Watson\dw20_latest\neutral\retail\0\testcrash.cpp - - // These handles need to live until we're done waiting for the watson - // process to finish execution. - HandleHolder hProcess(processInformation.hProcess); - HandleHolder hThread(processInformation.hThread); - - - BOOL watsonSignalledCompletion = FALSE, bDWRunning = TRUE; - - while (bDWRunning) - { - if (WAIT_OBJECT_0 == ClrWaitForSingleObject(hEventAlive, - kDwWaitTime)) - { - // Okay, Watson's still pinging us; see if it's finished. - if (WAIT_OBJECT_0 == ClrWaitForSingleObject(hEventDone, 1)) - { - bDWRunning = FALSE; - watsonSignalledCompletion = TRUE; - } - - // If watson is finished (i.e. has signaled hEventDone), - // bDWRunning is false and we'll fall out of the loop. If - // watson isn't finished, we'll go back to waiting for the - // next ping on hEventAlive - continue; - } - - // we timed-out waiting for DW to respond. - DWORD dw = WaitForSingleObject(hMutex, DW_TIMEOUT_VALUE); - - if (WAIT_TIMEOUT == dw) - { - // either DW's hung or crashed, we must carry on. Let watson - // no that we're giving up on watson, in case it comes back - // from the hang. - SetEvent(hEventDone); - bDWRunning = FALSE; - } - else if (WAIT_ABANDONED == dw) - { - // The mutex was abandoned, which means Watson crashed on - // us. - bDWRunning = FALSE; - - ReleaseMutex(hMutex); - } - else - { - // Check one last time to see if Watson has woken up. - if (WAIT_OBJECT_0 != ClrWaitForSingleObject(hEventAlive, 1)) - { - // Nope. hasn't woken up. Give up on Watson - SetEvent(hEventDone); - bDWRunning = FALSE; - } - else - { - // Oh, it HAS woken up! See if it's finished as well. - if (WAIT_OBJECT_0 == ClrWaitForSingleObject(hEventDone, 1)) - { - bDWRunning = FALSE; - watsonSignalledCompletion = TRUE; - } - } - - ReleaseMutex(hMutex); - } - } - - // Go ahead and bail if Watson didn't exit for some reason. - if (!watsonSignalledCompletion) - { - return FALSE; - } - - // We're now done with hProcess and hThread, it's safe to let the - // HandleHolders destroy them now. - // - // We don't need to wait for the Watson process to exit; once it's signalled - // "hEventDone" it's safe to assume that Watson will not try communicating - // with us anymore and we have succeeded. - return true; -} // BOOL RunWatson() - - -// -// Constants used to control various aspects of Watson's behavior. -// - - -// Flags controlling the minidump Watson creates. -const DWORD kMiniDumpType = MiniDumpNormal; -const DWORD kThreadWriteFlags = ThreadWriteThread | ThreadWriteContext | ThreadWriteStack; -const DWORD kModuleWriteFlags = ModuleWriteModule; // | ModuleWriteDataSeg ? - - - -// Reporting. The defaults are fine here -const DWORD kReportingFlags = 0; - -// -// Enable these flags if the report should be queued (i.e., if no UI should be -// shown, but a report should still be sent). -// - -// Enable these flags are for bfDWRFlags -const DWORD kQueuingReportingFlags = fDwrForceToAdminQueue | fDwrIgnoreHKCU; - -// Enable these flags in the bfDWUFlags field -const DWORD kQueuingUIFlags = fDwuNoEventUI; - -// -// No reporting flags. Enable these flags if an error report should not be sent. -// - -// Enable these flags in bfDWRFlags if a report is not to be sent. -const DWORD kNoReportFlags = fDwrNeverUpload; - - -// UI Flags -// -// We need to use the light plea, since we may be reporting faults for -// Non-Microsoft software (if some random 3rd party app throws an exception, we -// can't really promise that their error report will be used to fix the -// problem). -// -const DWORD kUIFlags = fDwuDenySuspend | fDwuShowFeedbackLink; - -// Exception mode flags. By default, the "restart" and "recover" buttons are -// checked. We need to turn that behavior off. We also need to use the -// minidump API to gather the heap dump, in order to get a managed-aware -// minidump. Finally, release the dumping thread before doing the cabbing -// for performance reasons. -const DWORD kExceptionModeFlags = fDweDefaultQuit | fDweGatherHeapAsMdmp | fDweReleaseBeforeCabbing; - -// "Miscellaneous" flags. These flags are only used by Office. -const DWORD kMiscFlags = 0; - -// Flags to control which buttons are available on the Watson dialog. -// -// We will only display the "Send Error Report" and "Don't Send" buttons -// available -- we're not going to make the "restart" or "recover" checkboxes -// available by default. -const DWORD kOfferFlags = msoctdsQuit; - -//------------------------------------------------------------------------------ -// Description // Returns the IP of the instruction that caused the exception to occur. // For managed exceptions this may not match the Exceptions contained in // the exception record. @@ -2160,477 +919,6 @@ HRESULT GetBucketParametersForCurrentException( } // HRESULT GetBucketParametersForCurrentException() -//------------------------------------------------------------------------------ -// Description -// -// Parameters -// pExceptionInfo -- information about the exception that caused the error. -// If the error is not the result of an exception, pass NULL for this -// parameter -// tore -- Information about the fault -// pThread -- Thread object for faulting thread, could be NULL -// dwThreadID -- OS Thread ID for faulting thread -// -// Returns -// FaultReportResult -- enumeration indicating the -// FaultReportResultAbort -- if Watson could not execute normally -// FaultReportResultDebug -- if Watson executed normally, and the user -// chose to debug the process -// FaultReportResultQuit -- if Watson executed normally, and the user -// chose to end the process (e.g. pressed "Send Error Report" or -// "Don't Send"). -// -// Exceptions -// None. -//------------------------------------------------------------------------------ -#ifdef _PREFAST_ -#pragma warning(push) -#pragma warning(disable:21000) // Suppress PREFast warning about overly large function -#endif -FaultReportResult DoFaultReportWorker( // Was Watson attempted, successful? Run debugger? - EXCEPTION_POINTERS *pExceptionInfo, // Information about the fault. - TypeOfReportedError tore, // What sort of error is this? - Thread *pThread, // Thread object for faulting thread, could be NULL - DWORD dwThreadID) // OS Thread ID for faulting thread -{ - WRAPPER_NO_CONTRACT; - - _ASSERTE(!RunningOnWin7()); - - LOG((LF_EH, LL_INFO100, "DoFaultReportWorker: at sp %p ...\n", GetCurrentSP())); - - if (!IsWatsonEnabled()) - { - return FaultReportResultQuit; - } - - // If we've already tried to report a Watson crash once, we don't really - // want to pester the user about this exception. This can occur in certain - // pathological programs. - // For events other than user breakpoint, we only want to report once. - // For user breakpoints, report whenever the thread wants to. - if (!tore.IsUserBreakpoint()) - { - // If Watson already launched (say, on another thread)... - if (FastInterlockCompareExchange(&g_watsonAlreadyLaunched, 1, 0) != 0) - { - // wait until Watson process is completed - ClrWaitForSingleObject(g_hWatsonCompletionEvent, INFINITE_TIMEOUT); - return FaultReportResultQuit; - } - } - - // Assume an unmanaged fault until we determine otherwise. - BOOL bIsManagedFault = FALSE; - - // IF we don't have an ExceptionInfo, what does that mean? - if (pExceptionInfo) - { - if (IsExceptionFromManagedCode(pExceptionInfo->ExceptionRecord)) - { - // This is a managed fault. - bIsManagedFault = TRUE; - } - } - - // Figure out what we should do. - CLRWatsonHelper policy; - policy.Init(bIsManagedFault, tore); - - if (policy.ShouldAutoAttach()) - { - return FaultReportResultDebug; - } - - // Is there anything for Watson to do? (Either report, or ask about debugging?) - if ((!policy.ShouldReport()) && (!policy.ShouldOfferDebug()) && (!policy.ShouldShowUI())) - { - // Hmm ... we're not supposed to report anything or pop up a dialog. In - // this case, we can stop right now. - return FaultReportResultQuit; - } - - HANDLE hWatsonSharedMemory; - DWSharedMem *pWatsonSharedMemory; - { - HRESULT hr = CreateWatsonSharedMemory(&hWatsonSharedMemory, - &pWatsonSharedMemory); - if (FAILED(hr)) - { - return FaultReportResultAbort; - } - } - - // Some basic bookkeeping for Watson - pWatsonSharedMemory->dwSize = sizeof(DWSharedMem); - pWatsonSharedMemory->dwVersion = DW_CURRENT_VERSION; - pWatsonSharedMemory->pid = GetCurrentProcessId(); - pWatsonSharedMemory->tid = dwThreadID; - _snwprintf_s(pWatsonSharedMemory->wzEventLogSource, - NumItems(pWatsonSharedMemory->wzEventLogSource), - _TRUNCATE, - W(".NET Runtime %0d.%0d Error Reporting"), - VER_MAJORVERSION, - VER_MINORVERSION); - pWatsonSharedMemory->eip = (pExceptionInfo) ? reinterpret_cast< DWORD_PTR >(pExceptionInfo->ExceptionRecord->ExceptionAddress) : NULL; - - // If we set exception pointers, the debugger will automatically do a .ecxr on them. SO, - // don't set the pointers unless it really is an exception and we have a - // a good context record - if (tore.IsException() || - (tore.IsFatalError() && pExceptionInfo && pExceptionInfo->ContextRecord && - (pExceptionInfo->ContextRecord->ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL) - ) - { - pWatsonSharedMemory->pep = pExceptionInfo; - } - else - { - pWatsonSharedMemory->pep = NULL; - } - - // Handles to kernel objects that Watson uses. - // - // We're expecting these handles to be valid until the Watson child process - // has run to completion. Make sure these holders stay in scope until after - // the call to RunWatson - - HandleHolder hEventDone(NULL), - hEventNotifyDone(NULL), - hEventAlive(NULL), - hMutex(NULL), - hProc(NULL), - sharedMemoryHolder(hWatsonSharedMemory); - { - // SECURITY_ATTRIBUTES so the handles can be inherited (by Watson). - SECURITY_ATTRIBUTES securityAttributes = - { sizeof(SECURITY_ATTRIBUTES), NULL, true }; - - hEventDone = WszCreateEvent(&securityAttributes, FALSE, FALSE, NULL); - if (hEventDone == NULL) - { - LOG((LF_EH, LL_INFO100, "CLR Watson: WszCreateEvent returned error, GetLastError(): %#x\n", GetLastError())); - return FaultReportResultAbort; - } - pWatsonSharedMemory->hEventDone = hEventDone; - - - hEventNotifyDone = WszCreateEvent(&securityAttributes, FALSE, FALSE, NULL); - if (hEventNotifyDone == NULL) - { - LOG((LF_EH, LL_INFO100, "CLR Watson: WszCreateEvent returned error, GetLastError(): %#x\n", GetLastError())); - return FaultReportResultAbort; - } - pWatsonSharedMemory->hEventNotifyDone = hEventNotifyDone; - - - hEventAlive = WszCreateEvent(&securityAttributes, FALSE, FALSE, NULL); - if (hEventAlive == NULL) - { - LOG((LF_EH, LL_INFO100, "CLR Watson: WszCreateEvent returned error, GetLastError(): %#x\n", GetLastError())); - return FaultReportResultAbort; - } - pWatsonSharedMemory->hEventAlive = hEventAlive; - - - hMutex = WszCreateMutex(&securityAttributes, FALSE, NULL); - if (hMutex == NULL) - { - LOG((LF_EH, LL_INFO100, "CLR Watson: WszCreateEvent returned error, GetLastError(): %#x\n", GetLastError())); - return FaultReportResultAbort; - } - pWatsonSharedMemory->hMutex = hMutex; - } - - // During error reporting we need to do dump collection, freeze threads inside the process, read memory blocks - // (if you register memory), read stuff from the PEB, create remote threads for recovery. So it needs quite a - // lot of permissions; we end up with PROCESS_ALL_ACCESS to satisfy all required permissions. - hProc = OpenProcess(PROCESS_ALL_ACCESS, - TRUE, - pWatsonSharedMemory->pid); - if (hProc == NULL) - { - LOG((LF_EH, LL_INFO100, "CLR Watson: OpenProcess returned error, GetLastError(): %#x\n", GetLastError())); - return FaultReportResultAbort; - } - - pWatsonSharedMemory->hProc = hProc; - - - // Flags to control reporting, queuing, etc. - DWORD reportingFlags = kReportingFlags; // 0 - DWORD uiFlags = kUIFlags; // fDwuDenySuspend | fDwuShowFeedbackLink - DWORD dwEflags = kExceptionModeFlags; // fDweDefaultQuit | fDweGatherHeapAsMdmp - - // Reporting flags... - if (policy.ShouldQueueReport()) - { // If we should queue a report, - // turn on kQueueingReportingFlags, which is fDwrForceToAdminQueue | fDwrIgnoreHKCU - reportingFlags |= kQueuingReportingFlags; - } - else - if (!policy.ShouldReport()) - { // We shouldn't report at all, - // turn on kNoReportFlags, which is fDwrNeverUpload, which means "don't report" - reportingFlags |= kNoReportFlags; - } - else - { - // Ask to report. - } - - // Offer flags... - DWORD offerFlags = kOfferFlags; // msoctdsQuit - if (policy.ShouldOfferDebug()) - { // Turn on msoctdsDebug, which adds "Debug" button. - offerFlags |= msoctdsDebug; - } - else - { // No debug, so ignore aeDebug - dwEflags |= fDweIgnoreAeDebug; - } - - // UI flags... - if (policy.ShouldQueueReport() && !policy.ShouldOfferDebug()) - { // Queue report headlessly. Turn on kQueueingUIFlags, which is fDwuNoEventUI. - uiFlags |= kQueuingUIFlags; - } - - pWatsonSharedMemory->bfmsoctdsOffer = offerFlags; // From above - pWatsonSharedMemory->bfDWRFlags = reportingFlags; // From above - pWatsonSharedMemory->bfDWUFlags = uiFlags; // From above - pWatsonSharedMemory->bfDWEFlags = dwEflags; // From above - pWatsonSharedMemory->bfDWMFlags = kMiscFlags; // 0 - - // We're going to rely on Watson's default localization behavior. - pWatsonSharedMemory->lcidUI = 0; - - // By default, Watson will terminate the process after snapping a - // minidump. Notify & LetRun flags disable that. - pWatsonSharedMemory->bfmsoctdsNotify = msoctdsNull; - pWatsonSharedMemory->bfmsoctdsLetRun = offerFlags; - - { - PathString wzModuleFileName; - DWORD dwRet = WszGetModuleFileName(NULL, - wzModuleFileName); - BaseBucketParamsManager::CopyStringToBucket(pWatsonSharedMemory->wzModuleFileName, NumItems(pWatsonSharedMemory->wzModuleFileName), wzModuleFileName); - - _ASSERTE(0 != dwRet); - if (0 == dwRet) - { - LOG((LF_EH, LL_INFO100, "CLR Watson: WszGetModuleFileName returned error, GetLastError(): %#x\n", GetLastError())); - return FaultReportResultAbort; - } - } - - // We're going capture the same minidump information for all modules, so set wzDotDataDlls to "*" - if (sizeof(DW_ALLMODULES) <= sizeof(pWatsonSharedMemory->wzDotDataDlls)) - { - memcpy(pWatsonSharedMemory->wzDotDataDlls, DW_ALLMODULES, sizeof(DW_ALLMODULES)); - } - else - { - // Assert, but go on - _ASSERTE(sizeof(DW_ALLMODULES) <= sizeof(pWatsonSharedMemory->wzDotDataDlls)); - pWatsonSharedMemory->wzDotDataDlls[0] = 0; - } - - // UI Customization - // - // The only UI customization we perform is to set the App Name. Currently we - // do this just by using the executable name. - // - { - PathString buf; // Buffer for path for description. - LPCWSTR pName ; // Pointer to filename or description. - int size; // Size of description. - HMODULE hModule; // Handle to module. - DWORD result; // Return code - - // Get module name. - hModule = WszGetModuleHandle(NULL); - result = WszGetModuleFileName(hModule, buf); - - if (result == 0) - { // Couldn't get module name. This should never happen. - pName = W("<<unknown>>"); - } - else - { // re-use the buf for pathname and description. - size = DwGetAppDescription(buf, buf); - pName = buf.GetUnicode(); - // If the returned size was zero, buf wasn't changed, and still contains the path. - // find just the filename part. - if (size == 0) - { // Look for final '\' - pName = wcsrchr(buf, W('\\')); - // If found, skip it; if not, point to full name. - pName = pName ? pName+1 : (LPCWSTR)buf; - } - } - - wcsncpy_s(pWatsonSharedMemory->uib.wzGeneral_AppName, - COUNTOF(pWatsonSharedMemory->uib.wzGeneral_AppName), - pName, - _TRUNCATE); - - // For breakpoint, need to customize the "We're sorry..." message - if (tore.IsBreakpoint()) - { - LCID lcid = 0; - // Get the message. - StackSString sszMain_Intro_Bold; - StackSString sszMain_Intro_Reg; - EX_TRY - { - sszMain_Intro_Bold.LoadResource(CCompRC::Debugging, IDS_WATSON_DEBUG_BREAK_INTRO_BOLD); - sszMain_Intro_Reg.LoadResource(CCompRC::Debugging, IDS_WATSON_DEBUG_BREAK_INTRO_REG); - // Try to determine the language used for the above resources - // At the moment this OS call is a heuristic which should match most of the time. But the - // CLR is starting to support languages that don't even have LCIDs, so this may not always - // be correct (and there may be NO LCID we can pass to watson). Long term, the correct fix - // here is to get out of the game of making watson policy / UI decisions. This is happening - // for Windows 7. - lcid = GetThreadLocale(); - } - EX_CATCH - { - // Just don't customize. - } - EX_END_CATCH(SwallowAllExceptions) - - // If we were able to get a string, set it. - if (sszMain_Intro_Reg.GetCount() > 0) - { - // Instead of "<app.exe> has encountered an error and nees to close...", say - // "<app.exe> has encountered a user-defined breakpoint." - wcsncpy_s(pWatsonSharedMemory->uib.wzMain_Intro_Bold, COUNTOF(pWatsonSharedMemory->uib.wzMain_Intro_Bold), sszMain_Intro_Bold, _TRUNCATE); - // Instead of "If you were in the middle of something...", say - // "A breakpoint in an application indicates a program error..." - wcsncpy_s(pWatsonSharedMemory->uib.wzMain_Intro_Reg, COUNTOF(pWatsonSharedMemory->uib.wzMain_Intro_Reg), sszMain_Intro_Reg, _TRUNCATE); - - pWatsonSharedMemory->bfDWUFlags = fDwuDenySuspend; - - pWatsonSharedMemory->lcidUI = lcid; - } - } - - } - - // Get the bucket parameters. - switch (tore.GetType()) - { - case TypeOfReportedError::NativeThreadUnhandledException: - // Let Watson provide the buckets for a native thread. - break; - case TypeOfReportedError::UnhandledException: - case TypeOfReportedError::FatalError: - case TypeOfReportedError::UserBreakpoint: - case TypeOfReportedError::NativeBreakpoint: - // For managed exception or exceptions that come from managed code, we get the managed bucket parameters, - // which will be displayed in the "details" section on any UI. - // - // Otherwise, use the unmanaged IP to bucket. - if (bIsManagedFault) - { - RetrieveManagedBucketParameters(pExceptionInfo?pExceptionInfo->ExceptionRecord:NULL, &pWatsonSharedMemory->gmb, tore, pThread); - } - break; - default: - _ASSERTE(!"Unexpected TypeOfReportedException"); - break; - } - - // dwThisThreadExFlags and dwOtherThreadExFlags are only used on IA64. - CustomMinidumpBlock cmb = - { - TRUE, // fCustomMinidump - kMiniDumpType, // dwMinidumpType : MiniDumpNormal - FALSE, // fOnlyThisThread - kThreadWriteFlags, // dwThisThreadFlags : ThreadWriteThread | ThreadWriteContext | ThreadWriteStack - kThreadWriteFlags, // dwOtherThreadFlags - 0, // dwThisThreadExFlags - 0, // dwOtherThreadExFlags - kModuleWriteFlags, // dwPreferredModuleFlags - kModuleWriteFlags // dwOtherModuleFlags. - }; - - pWatsonSharedMemory->cmb = cmb; - - // At this point, the IPC block is all ready to go - BOOL result = false; - // There are two calls to RunWatson below. We want the second call to execute iff - // secondInvocation is true. - BOOL secondInvocation = true; - - - EX_TRY - { - bool fRunWatson = false; -#if defined(_TARGET_X86_) - bool fGuardPagePresent = false; - - // There is an unfortunate side effect of calling ReadProcessMemory() out-of-process on IA64 WOW. - // On all platforms (IA64 native & WOW64, AMD64 native & WOW64, and x86 native), if we call - // ReadProcessMemory() out-of-process on a page with PAGE_GUARD protection, the read operation - // fails as expected. However, on IA64 WOW64 only, the PAGE_GUARD protection is removed after - // the read operation. Even IA64 native preserves the PAGE_GUARD protection. - // See VSW 451447 for more information. - if ((pThread != NULL) && pThread->DetermineIfGuardPagePresent()) - { - fGuardPagePresent = true; - } -#endif // _TARGET_X86_ - - if (secondInvocation) - { - fRunWatson = true; - result = RunWatson(hWatsonSharedMemory, - pWatsonSharedMemory->hEventAlive, - pWatsonSharedMemory->hEventDone, - pWatsonSharedMemory->hMutex); - } - -#if defined(_TARGET_X86_) - if (fRunWatson && fGuardPagePresent) - { - // This shouldn't cause a problem because guard pages are present in the first place. - _ASSERTE(pThread != NULL); - pThread->RestoreGuardPage(); - } -#endif // _TARGET_X86_ - } - EX_CATCH - { - // We couldn't wait around for watson to execute for some reason. - result = false; - } - EX_END_CATCH(SwallowAllExceptions) - - // It's now safe to close all the synchronization and process handles. - - if (!result) - { - // Hmmm ... watson couldn't execute correctly. - return FaultReportResultAbort; - } - - LOG((LF_EH, LL_INFO100, "CLR Watson: returned 0x%x\n", pWatsonSharedMemory->msoctdsResult)); - - // If user clicked "Debug" - if (msoctdsDebug == pWatsonSharedMemory->msoctdsResult) - { - return FaultReportResultDebug; - } - - // No debugging, successful completion. - return FaultReportResultQuit; -} // FaultReportResult DoFaultReportWorker() -#ifdef _PREFAST_ -#pragma warning(pop) -#endif - class WatsonThreadData { public: @@ -2650,188 +938,7 @@ class WatsonThreadData { FaultReportResult result; // Result of invoking Watson }; -class WatsonSOExceptionAddress { - public: - - WatsonSOExceptionAddress() - { - m_SystemMethod = NULL; - m_UserMethod = NULL; - } - - SLOT m_SystemMethod; // IP in the first method on the stack which is in a system module - SLOT m_UserMethod; // IP in the first method on the stack which is in a non-system module -}; - -//------------------------------------------------------------------------------ -// Description -// This function is the stack walk callback for a thread that hit a soft SO (i.e., a SO caused by a -// failed stack probe). -// -// Parameters -// pCf -- A pointer to the current CrawlFrame -// data - A pointer to WatsonSOExceptionAddress instance -// -// Returns: -// SWA_ABORT to stop the stack crawl -// SWA_CONTINUE to continue crawling the stack -// -// Exceptions -// None. -//------------------------------------------------------------------------------ -StackWalkAction WatsonSOStackCrawlCallback(CrawlFrame* pCf, void* pParam) -{ - WRAPPER_NO_CONTRACT; - - _ASSERTE(pParam != NULL); - WatsonSOExceptionAddress *pData = (WatsonSOExceptionAddress *) pParam; - - SLOT ip; - - if (pCf->IsFrameless()) - { - ip = (PBYTE)GetControlPC(pCf->GetRegisterSet()); - } - else - { - ip = (SLOT) pCf->GetFrame()->GetIP(); - } - - MethodDesc *pMD = pCf->GetFunction(); - - if (pMD != NULL) - { - if (pMD->GetModule()->IsSystem()) - { - if (pData->m_SystemMethod == NULL) - { - pData->m_SystemMethod = ip; - } - return SWA_CONTINUE; - } - else - { - _ASSERTE(pData->m_UserMethod == NULL); - pData->m_UserMethod = ip; - return SWA_ABORT; - } - } - else - { - return SWA_CONTINUE; - } - -}// WatsonSOCrawlCallBack - -//------------------------------------------------------------------------------ -// Description -// Wrapper function for DoFaultReport. This function is called for SOs. -// It sets up the ExceptionInfo appropriately for soft SOs (caused by -// failed stack probes) before callign DoFaultReport. -// -// Parameters -// pParam -- A pointer to a WatsonThreadData instance -// -// Exceptions -// None. -//------------------------------------------------------------------------------ -DWORD WINAPI DoFaultReportWorkerCallback(LPVOID pParam) -{ - WRAPPER_NO_CONTRACT; - - _ASSERTE(pParam != NULL); - - WatsonThreadData* pData = (WatsonThreadData*) pParam; - - EXCEPTION_POINTERS ExceptionInfo; - EXCEPTION_RECORD ExceptionRecord; - PEXCEPTION_POINTERS pExceptionInfo = pData->pExceptionInfo; - - if (IsSOExceptionCode(pExceptionInfo->ExceptionRecord->ExceptionCode)) - { - EX_TRY - { - if (ShouldLogInEventLog()) - { - EventReporter reporter(EventReporter::ERT_StackOverflow); - reporter.Report(); - } - } - EX_CATCH - { - } - EX_END_CATCH(SwallowAllExceptions); - } - - // The purpose of the loop below is to avoid deadlocks during the abnormal process termination. - // We will try to acquire the lock for 100 times to see whether we can successfully grap it. If we - // can, then we can setup the thread and report the fault without worrying about the deadlock. - // Otherwise we won't report the fault. It's still possible that we can enter the critical section - // and report the fault without having deadlocks after this spin, but compared to the risky of - // having deadlock, we still prefer not to report the fault if we can't get the lock after spin. - BOOL isThreadSetup = false; - for (int i = 0; i < 100; i++) - { - if (ThreadStore::CanAcquireLock()) - { - SetupThread(); - isThreadSetup = true; - break; - } - __SwitchToThread(30, CALLER_LIMITS_SPINNING); - } - - if (isThreadSetup) - { - GCX_COOP(); - - if (pData->pThread != NULL && pExceptionInfo != NULL && - pExceptionInfo->ContextRecord == NULL && - pExceptionInfo->ExceptionRecord->ExceptionCode == STATUS_STACK_OVERFLOW && - pExceptionInfo->ExceptionRecord->ExceptionAddress == 0) - { - // In the case of a soft SO on a managed thread, we set the ExceptionAddress to one of the following - // - // 1. The first method on the stack that is in a non-system module. - // 2. Failing that, the first method on the stack that is in a system module - - CONTEXT ContextRecord; - memset(&ContextRecord, 0, sizeof(CONTEXT)); - - ExceptionInfo.ContextRecord = &ContextRecord; // To display the "Send" button, dw20 wants a non-NULL pointer - ExceptionRecord = *(pExceptionInfo->ExceptionRecord); - ExceptionInfo.ExceptionRecord = &ExceptionRecord; - pExceptionInfo = &ExceptionInfo; - - WatsonSOExceptionAddress WatsonExceptionAddresses; - - pData->pThread->StackWalkFrames( - WatsonSOStackCrawlCallback, - &WatsonExceptionAddresses, - FUNCTIONSONLY|ALLOW_ASYNC_STACK_WALK); - - if (WatsonExceptionAddresses.m_UserMethod != NULL) - { - pExceptionInfo->ExceptionRecord->ExceptionAddress = WatsonExceptionAddresses.m_UserMethod; - } - else if (WatsonExceptionAddresses.m_SystemMethod != NULL) - { - pExceptionInfo->ExceptionRecord->ExceptionAddress = WatsonExceptionAddresses.m_SystemMethod; - } - - } - pData->result = DoFaultReportWorker( - pExceptionInfo, - pData->tore, - pData->pThread, - pData->dwThreadID); - } - - - return 0; - -} // void DoFaultReportFavorWorker() DWORD WINAPI ResetWatsonBucketsCallbackForStackOverflow(LPVOID pParam) { @@ -2840,7 +947,6 @@ DWORD WINAPI ResetWatsonBucketsCallbackForStackOverflow(LPVOID pParam) THROWS; GC_TRIGGERS; PRECONDITION(IsWatsonEnabled()); - PRECONDITION(RunningOnWin7()); PRECONDITION(pParam != NULL); } CONTRACTL_END; @@ -2886,7 +992,6 @@ void ResetWatsonBucketsFavorWorker(void * pParam) NOTHROW; GC_NOTRIGGER; PRECONDITION(IsWatsonEnabled()); - PRECONDITION(RunningOnWin7()); PRECONDITION(pParam != NULL); } CONTRACTL_END; @@ -2905,41 +1010,6 @@ void ResetWatsonBucketsFavorWorker(void * pParam) } -//------------------------------------------------------------------------------ -// Description -// This function is called by the Debugger thread in response to a favor -// posted to it by the faulting thread. The faulting thread uses the -// Debugger thread to invoke Watson in the case of stack overflows. -// Since the debugger thread doesn't have a managed Thread object, -// it cannot be directly used to call DoFaultReport. Instead, this function -// spawns a worker thread and waits for it to complete. -// -// Parameters -// pParam -- A pointer to a WatsonThreadData instance -// -// Exceptions -// None. -//------------------------------------------------------------------------------ -void DoFaultReportFavorWorker(void* pParam) -{ - WRAPPER_NO_CONTRACT; - - _ASSERTE(pParam != NULL); - - HANDLE hThread = NULL; - DWORD dwThreadId; - - hThread = ::CreateThread(NULL, 0, DoFaultReportWorkerCallback, pParam, 0, &dwThreadId); - if (hThread != NULL) - { - WaitForSingleObject(hThread, INFINITE); - CloseHandle(hThread); - } - - return; - -} // void DoFaultReportFavorWorker() - //---------------------------------------------------------------------------- // CreateThread() callback to invoke native Watson or put up our fake Watson // dialog depending on m_fDoReportFault value. @@ -3019,129 +1089,6 @@ VOID WINAPI DoFaultReportDoFavorCallback(LPVOID pFaultReportInfoAsVoid) } } - - -//------------------------------------------------------------------------------ -// Description -// -// Parameters -// pExceptionInfo -- information about the exception that caused the error. -// If the error is not the result of an exception, pass NULL for this -// parameter -// tore -- Information about the fault -// Returns -// FaultReportResult -- enumeration indicating the -// FaultReportResultAbort -- if Watson could not execute normally -// FaultReportResultDebug -- if Watson executed normally, and the user -// chose to debug the process -// FaultReportResultQuit -- if Watson executed normally, and the user -// chose to end the process (e.g. pressed "Send Error Report" or -// "Don't Send"). -// -// Exceptions -// None. -//------------------------------------------------------------------------------ -FaultReportResult DoFaultReport( // Was Watson attempted, successful? Run debugger? - EXCEPTION_POINTERS *pExceptionInfo, // Information about the fault. - TypeOfReportedError tore) // What sort of error is this? -{ - WRAPPER_NO_CONTRACT; - - _ASSERTE(!RunningOnWin7()); - - LOG((LF_EH, LL_INFO100, "DoFaultReport: at sp %p ...\n", GetCurrentSP())); - - Thread *pThread = GetThread(); - - // If watson isn't available (eg. in Silverlight), then use a simple dialog box instead - if (!IsWatsonEnabled()) - { - if (!pThread) - { - return FaultReportResultAbort; - } - - // Since the StackOverflow handler also calls us, we must keep our stack budget - // to a minimum. Thus, we will launch a thread to do the actual work. - FaultReportInfo fri; - fri.m_fDoReportFault = FALSE; - fri.m_pExceptionInfo = pExceptionInfo; - fri.m_threadid = GetCurrentThreadId(); - // DoFaultCreateThreadReportCallback will overwrite this - if it doesn't, we'll assume it failed. - fri.m_faultReportResult = FaultReportResultAbort; - - GCX_PREEMP(); - - - if (pExceptionInfo->ExceptionRecord->ExceptionCode != STATUS_STACK_OVERFLOW) - { - DoFaultReportCreateThreadCallback(&fri); - } - else - { - // Stack overflow case - we don't have enough stack on our own thread so let the debugger - // helper thread do the work. - if (!g_pDebugInterface || FAILED(g_pDebugInterface->RequestFavor(DoFaultReportDoFavorCallback, &fri))) - { - // If we can't initialize the debugger helper thread or we are running on the debugger helper - // thread, give it up. We don't have enough stack space. - - } - } - - return fri.m_faultReportResult; - } - - - // Check if the current thread has the permission to open a process handle of the current process. - // If not, the current thread may have been impersonated, we have to launch Watson from a new thread as in SO case. - BOOL fOpenProcessFailed = FALSE; - if (pExceptionInfo->ExceptionRecord->ExceptionCode != STATUS_STACK_OVERFLOW) - { - HandleHolder hProcess = OpenProcess(PROCESS_ALL_ACCESS, TRUE, GetCurrentProcessId()); - fOpenProcessFailed = hProcess == NULL; - } - - if ((pExceptionInfo->ExceptionRecord->ExceptionCode == STATUS_STACK_OVERFLOW) || fOpenProcessFailed) - { - - WatsonThreadData* pData = new(nothrow) WatsonThreadData( - pExceptionInfo, - tore, - pThread, - GetCurrentThreadId(), - FaultReportResultAbort); // default result - - if (pData == NULL) - { - return FaultReportResultAbort; - } - - GCX_PREEMP(); - - if (!g_pDebugInterface || - // When GC is in progress and current thread is either a GC thread or a managed - // thread under Coop mode, this will let the new generated DoFaultReportCallBack - // thread trigger a deadlock. So in this case, we should directly abort the fault - // report to avoid the deadlock. - ((IsGCThread() || pThread->PreemptiveGCDisabled()) && GCHeapUtilities::IsGCInProgress()) || - FAILED(g_pDebugInterface->RequestFavor(DoFaultReportFavorWorker, pData))) - { - // If we can't initialize the debugger helper thread or we are running on the debugger helper - // thread, return without invoking Watson. We don't have enough stack space. - - delete pData; - return FaultReportResultAbort; - } - - FaultReportResult ret = pData->result; - delete pData; - return ret; - } - - return DoFaultReportWorker(pExceptionInfo, tore, GetThread(), GetCurrentThreadId()); -} // FaultReportResult DoFaultReport() - // look at the type of the contract failure. if it's a precondition then we want to blame the caller // of the method that originated the ContractException not just the first non-contract runtime frame. // if this isn't a ContractException then we default to Invariant which won't skip the extra frame. diff --git a/src/vm/dwreport.h b/src/vm/dwreport.h index 77ed0fd35a..a9d804631d 100644 --- a/src/vm/dwreport.h +++ b/src/vm/dwreport.h @@ -52,8 +52,6 @@ FaultReportResult DoFaultReport( // Was Watson attempted, successful? EXCEPTION_POINTERS *pExceptionInfo, // Information about the fault. TypeOfReportedError tore); // What sort of error is reported. -BOOL InitializeWatson(COINITIEE fFlags); -BOOL InitializeWatsonVersionInfo(LPCSTR pVer); BOOL IsWatsonEnabled(); BOOL RegisterOutOfProcessWatsonCallbacks(); @@ -81,8 +79,6 @@ void ResetWatsonBucketsFavorWorker(void * pParam); extern LONG g_watsonAlreadyLaunched; -extern HandleHolder g_hWatsonCompletionEvent; - //---------------------------------------------------------------------------- // Passes data between DoFaultReport and DoFaultReportCallback //---------------------------------------------------------------------------- diff --git a/src/vm/eepolicy.cpp b/src/vm/eepolicy.cpp index e15af92bfc..574943a40e 100644 --- a/src/vm/eepolicy.cpp +++ b/src/vm/eepolicy.cpp @@ -1472,7 +1472,7 @@ void DECLSPEC_NORETURN EEPolicy::HandleFatalStackOverflow(EXCEPTION_POINTERS *pE } #ifndef FEATURE_PAL - if (RunningOnWin7() && IsWatsonEnabled() && (g_pDebugInterface != NULL)) + if (IsWatsonEnabled() && (g_pDebugInterface != NULL)) { _ASSERTE(pExceptionInfo != NULL); diff --git a/src/vm/excep.cpp b/src/vm/excep.cpp index 3ba3d05a82..9cb1296204 100644 --- a/src/vm/excep.cpp +++ b/src/vm/excep.cpp @@ -126,7 +126,6 @@ BOOL __stdcall IsExceptionFromManagedCodeCallback(EXCEPTION_RECORD * pExceptionR SO_TOLERANT; SUPPORTS_DAC; PRECONDITION(CheckPointer(pExceptionRecord)); - PRECONDITION(!RunningOnWin7()); } CONTRACTL_END; // If we can't enter the EE, done. @@ -4083,49 +4082,6 @@ void DisableOSWatson(void) LOG((LF_EH, LL_INFO100, "DisableOSWatson: SetErrorMode = 0x%x\n", lastErrorMode | SEM_NOGPFAULTERRORBOX)); } - - -//---------------------------------------------------------------------------- -// -// RaiseFailFastExceptionOnWin7 - invoke RaiseFailFastException on Win7 -// -// Arguments: -// pExceptionRecord - pointer to exception record -// pContext - pointer to exception context -// -// Return Value: -// None -// -// Note: -// RaiseFailFastException will not return unless a debugger is attached -// and the user chooses to keep going. -// -//---------------------------------------------------------------------------- -void RaiseFailFastExceptionOnWin7(PEXCEPTION_RECORD pExceptionRecord, PCONTEXT pContext) -{ - LIMITED_METHOD_CONTRACT; - _ASSERTE(RunningOnWin7()); - -#ifndef FEATURE_CORESYSTEM - typedef void (WINAPI * RaiseFailFastExceptionFnPtr)(PEXCEPTION_RECORD, PCONTEXT, DWORD); - RaiseFailFastExceptionFnPtr RaiseFailFastException; - - HINSTANCE hKernel32 = WszGetModuleHandle(WINDOWS_KERNEL32_DLLNAME_W); - if (hKernel32 == NULL) - return; - - RaiseFailFastException = (RaiseFailFastExceptionFnPtr)GetProcAddress(hKernel32, "RaiseFailFastException"); - if (RaiseFailFastException == NULL) - return; -#endif - - // enable preemptive mode before call into OS to allow runtime suspend to finish - GCX_PREEMP(); - - STRESS_LOG0(LF_CORDB,LL_INFO10, "D::RFFE: About to call RaiseFailFastException\n"); - RaiseFailFastException(pExceptionRecord, pContext, 0); - STRESS_LOG0(LF_CORDB,LL_INFO10, "D::RFFE: Return from RaiseFailFastException\n"); -} #endif // !FEATURE_PAL //------------------------------------------------------------------------------ @@ -4196,133 +4152,83 @@ LONG WatsonLastChance( // EXCEPTION_CONTINUE_SEARCH, _CONTINUE_ LOG((LF_EH, LL_INFO10, "WatsonLastChance: Debugger not attached at sp %p ...\n", GetCurrentSP())); #ifndef FEATURE_PAL - BOOL bRunDoFaultReport = TRUE; FaultReportResult result = FaultReportResultQuit; - if (RunningOnWin7()) + BOOL fSOException = FALSE; + + if ((pExceptionInfo != NULL) && + (pExceptionInfo->ExceptionRecord != NULL) && + (pExceptionInfo->ExceptionRecord->ExceptionCode == STATUS_STACK_OVERFLOW)) { - BOOL fSOException = FALSE; + fSOException = TRUE; + } - if ((pExceptionInfo != NULL) && - (pExceptionInfo->ExceptionRecord != NULL) && - (pExceptionInfo->ExceptionRecord->ExceptionCode == STATUS_STACK_OVERFLOW)) - { - fSOException = TRUE; - } + if (g_pDebugInterface) + { + // we are about to let the OS trigger jit attach, however we need to synchronize with our + // own jit attach that we might be doing on another thread + // PreJitAttach races this thread against any others which might be attaching and if some other + // thread is doing it then we wait for its attach to complete first + g_pDebugInterface->PreJitAttach(TRUE, FALSE, FALSE); + } - if (g_pDebugInterface) + // Let unhandled excpetions except stack overflow go to the OS + if (tore.IsUnhandledException() && !fSOException) + { + return EXCEPTION_CONTINUE_SEARCH; + } + else if (tore.IsUserBreakpoint()) + { + DoReportFault(pExceptionInfo); + } + else + { + BOOL fWatsonAlreadyLaunched = FALSE; + if (FastInterlockCompareExchange(&g_watsonAlreadyLaunched, 1, 0) != 0) { - // we are about to let the OS trigger jit attach, however we need to synchronize with our - // own jit attach that we might be doing on another thread - // PreJitAttach races this thread against any others which might be attaching and if some other - // thread is doing it then we wait for its attach to complete first - g_pDebugInterface->PreJitAttach(TRUE, FALSE, FALSE); + fWatsonAlreadyLaunched = TRUE; } - // Let unhandled excpetions except stack overflow go to the OS - if (tore.IsUnhandledException() && !fSOException) - { - return EXCEPTION_CONTINUE_SEARCH; - } - else if (tore.IsUserBreakpoint()) - { - DoReportFault(pExceptionInfo); - } - else + // Logic to avoid double prompt if more than one threads calling into WatsonLastChance + if (!fWatsonAlreadyLaunched) { - BOOL fWatsonAlreadyLaunched = FALSE; - if (FastInterlockCompareExchange(&g_watsonAlreadyLaunched, 1, 0) != 0) + // EEPolicy::HandleFatalStackOverflow pushes a FaultingExceptionFrame on the stack after SO + // exception. Our hijack code runs in the exception context, and overwrites the stack space + // after SO excpetion, so we need to pop up this frame before invoking RaiseFailFast. + // This cumbersome code should be removed once SO synchronization is moved to be completely + // out-of-process. + if (fSOException && pThread && pThread->GetFrame() != FRAME_TOP) { - fWatsonAlreadyLaunched = TRUE; + GCX_COOP(); // Must be cooperative to modify frame chain. + pThread->GetFrame()->Pop(pThread); } - // Logic to avoid double prompt if more than one threads calling into WatsonLastChance - if (!fWatsonAlreadyLaunched) - { - // EEPolicy::HandleFatalStackOverflow pushes a FaultingExceptionFrame on the stack after SO - // exception. Our hijack code runs in the exception context, and overwrites the stack space - // after SO excpetion, so we need to pop up this frame before invoking RaiseFailFast. - // This cumbersome code should be removed once SO synchronization is moved to be completely - // out-of-process. - if (fSOException && pThread && pThread->GetFrame() != FRAME_TOP) - { - GCX_COOP(); // Must be cooperative to modify frame chain. - pThread->GetFrame()->Pop(pThread); - } - - LOG((LF_EH, LL_INFO10, "D::WLC: Call RaiseFailFastExceptionOnWin7\n")); - RaiseFailFastExceptionOnWin7(pExceptionInfo == NULL ? NULL : pExceptionInfo->ExceptionRecord, - pExceptionInfo == NULL ? NULL : pExceptionInfo->ContextRecord); - STRESS_LOG0(LF_CORDB,LL_INFO10, "D::WLC: Return from RaiseFailFastExceptionOnWin7\n"); - } - } - - if (g_pDebugInterface) - { - // if execution resumed here then we may or may not be attached - // either way we need to end the attach process and unblock any other - // threads which were waiting for the attach here to complete - g_pDebugInterface->PostJitAttach(); - } + LOG((LF_EH, LL_INFO10, "D::WLC: Call RaiseFailFastExceptionOnWin7\n")); + // enable preemptive mode before call into OS to allow runtime suspend to finish + GCX_PREEMP(); - if (IsDebuggerPresent()) - { - result = FaultReportResultDebug; - jitAttachRequested = FALSE; + STRESS_LOG0(LF_CORDB, LL_INFO10, "D::RFFE: About to call RaiseFailFastException\n"); + RaiseFailFastException(pExceptionInfo == NULL ? NULL : pExceptionInfo->ExceptionRecord, + pExceptionInfo == NULL ? NULL : pExceptionInfo->ContextRecord, + 0); + STRESS_LOG0(LF_CORDB, LL_INFO10, "D::RFFE: Return from RaiseFailFastException\n"); } } - else + + if (g_pDebugInterface) { - // If we've got a fatal error but Watson isn't enabled, then fall back to old-style non-managed-aware - // error reporting using faultrep to try and ensure we get an error report about this fatal error. - if (!IsWatsonEnabled() && tore.IsFatalError() && (pExceptionInfo != NULL)) - { - EFaultRepRetVal r = DoReportFault(pExceptionInfo); - if (r != frrvErr && r != frrvErrNoDW && r != frrvErrTimeout) - { - // Once native Watson is sucessfully launched, we should not try to launch - // our fake Watson dailog box. - bRunDoFaultReport = FALSE; - } - } + // if execution resumed here then we may or may not be attached + // either way we need to end the attach process and unblock any other + // threads which were waiting for the attach here to complete + g_pDebugInterface->PostJitAttach(); + } - if (bRunDoFaultReport) - { - // http://devdiv/sites/docs/NetFX4/CLR/Specs/Developer%20Services/Error%20Reporting/WER%20SxS%20DCR.doc - // - // Watson SxS support for Desktop CLR - // - // For an unhandled exception thrown from native code, the first runtime that encounters the - // unhandled native exception will report Watson if it is allowed by Watson SxS manager to do - // Watson. If more than one runtimes attempt to report Watson concurrently, only one runtims - // will be bestowed to report Watson. The result is that at most one Watson report will be - // submitted for a process. - // - // To coordinate Watson reporting among runtimes in a process, Watson SxS manager, which is part - // of the shim, will provide a new set of APIs, and keeps a status of whether a Watson report - // has been submitted for a process. - // - // Each runtime registers an exception claiming callack with Watson SxS manager at startup. - // Watson SxS manager provide an exception claiming API, which iterators through registerd - // exception claiming callbacks to determine if an exception is thrown by one of registered - // runtimes. - // - // Before a runtime goes to process Watson for an unhandled exception, it first asks Waston SxS - // manager if a Watson report has already been submitted for the current process. If so, it - // will not try to do Watson. If not, it checks if the unhandled exception is thrown by itself. - // If true, it will report Watson only when Watson SxS manager allows it to do Watson. - // - // If the unhandled exception is not thrown by itself, it will invoke Watson SxS manager's exception - // claiming API to determine if the unhandled exception was thrown by another runtime which is - // responsible for reporting Watson. If true, it will not try to do Watson. If none of runtimes - // in the process claims the ownership of the unhandled exception, it will report Watson only when - // Watson SxS manager allows it to do Watson. - result = DoFaultReport(pExceptionInfo, tore); - - // Set the event to indicate that Watson processing is completed. Other threads can continue. - UnsafeSetEvent(g_hWatsonCompletionEvent); - } + + if (IsDebuggerPresent()) + { + result = FaultReportResultDebug; + jitAttachRequested = FALSE; } switch(result) diff --git a/src/vm/i386/cgencpu.h b/src/vm/i386/cgencpu.h index ffdfb82b14..f1bdd0f73f 100644 --- a/src/vm/i386/cgencpu.h +++ b/src/vm/i386/cgencpu.h @@ -44,8 +44,6 @@ EXTERN_C void STDCALL PInvokeStackImbalanceHelper(void); EXTERN_C void SinglecastDelegateInvokeStub(); #endif // FEATURE_STUBS_AS_IL -BOOL Runtime_Test_For_SSE2(); - #ifdef CROSSGEN_COMPILE #define GetEEFuncEntryPoint(pfn) 0x1001 #else @@ -61,7 +59,7 @@ BOOL Runtime_Test_For_SSE2(); // #define CPU_X86_STEPPING(cpuType) (((cpuType) & 0x000F) ) #define CPU_X86_USE_CMOV(cpuFeat) ((cpuFeat & 0x00008001) == 0x00008001) -#define CPU_X86_USE_SSE2(cpuFeat) (((cpuFeat & 0x04000000) == 0x04000000) && Runtime_Test_For_SSE2()) +#define CPU_X86_USE_SSE2(cpuFeat) ((cpuFeat & 0x04000000) == 0x04000000) // Values for CPU_X86_FAMILY(cpuType) #define CPU_X86_486 4 diff --git a/src/vm/i386/cgenx86.cpp b/src/vm/i386/cgenx86.cpp index 492cec4668..e222607a60 100644 --- a/src/vm/i386/cgenx86.cpp +++ b/src/vm/i386/cgenx86.cpp @@ -84,73 +84,6 @@ void ClearRegDisplayArgumentAndScratchRegisters(REGDISPLAY * pRD) #ifndef DACCESS_COMPILE -//============================================================================= -// Runtime test to see if the OS has enabled support for the SSE2 instructions -// -// -BOOL Runtime_Test_For_SSE2() -{ -#ifdef FEATURE_CORESYSTEM - return TRUE; -#else - - BOOL result = IsProcessorFeaturePresent(PF_XMMI64_INSTRUCTIONS_AVAILABLE); - - if (result == FALSE) - return FALSE; - - // ********************************************************************** - // *** *** - // *** IMPORTANT NOTE: *** - // *** *** - // *** All of these RunningOnXXX APIs return true when *** - // *** the OS that you are running on is that OS or later. *** - // *** For example RunningOnWin2003() will return true *** - // *** when you are running on Win2k3, Vista, Win7 or later. *** - // *** *** - // ********************************************************************** - - - // Windows 7 and later should alwys be using SSE2 instructions - // this is true for both for native and Wow64 - // - if (RunningOnWin7()) - return TRUE; - - if (RunningInWow64()) - { - // There is an issue with saving/restoring the SSE2 registers under wow64 - // So we figure out if we are running on an impacted OS and Service Pack level - // See DevDiv Bugs 89587 for the wow64 bug. - // - - _ASSERTE(ExOSInfoAvailable()); // This is always available on Vista and later - - // - // The issue is fixed in Windows Server 2008 or Vista/SP1 - // - // It is not fixed in Vista/RTM, so check for that case - // - if ((ExOSInfoRunningOnServer() == FALSE)) - { - OSVERSIONINFOEX osvi; - - ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX)); - osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); - osvi.wServicePackMajor = 0; - - DWORDLONG dwlConditionMask = 0; - VER_SET_CONDITION( dwlConditionMask, CLR_VER_SERVICEPACKMAJOR, VER_EQUAL); - - if (VerifyVersionInfo(&osvi, CLR_VER_SERVICEPACKMAJOR, dwlConditionMask)) - result = FALSE; - } - } - - return result; -#endif -} - //--------------------------------------------------------------- // Returns the type of CPU (the value of x of x86) // (Please note, that it returns 6 for P5-II) diff --git a/src/vm/threads.cpp b/src/vm/threads.cpp index 928f20a095..283c6299ca 100644 --- a/src/vm/threads.cpp +++ b/src/vm/threads.cpp @@ -8828,7 +8828,7 @@ static void ManagedThreadBase_DispatchInner(ManagedThreadCallState *pCallState) // This also implies that there will be no exception object marshalling (and it may not be required after all) // as well and once the holder reverts the AD context, the LastThrownObject in Thread will be set to NULL. #ifndef FEATURE_PAL - BOOL fSetupEHAtTransition = !(RunningOnWin7()); + BOOL fSetupEHAtTransition = FALSE; #else // !FEATURE_PAL BOOL fSetupEHAtTransition = TRUE; #endif // !FEATURE_PAL diff --git a/src/vm/vars.cpp b/src/vm/vars.cpp index 92eff4217f..04437f9964 100644 --- a/src/vm/vars.cpp +++ b/src/vm/vars.cpp @@ -28,11 +28,6 @@ const char g_psBaseLibrary[] = CoreLibName_IL_A; const char g_psBaseLibraryName[] = CoreLibName_A; const char g_psBaseLibrarySatelliteAssemblyName[] = CoreLibSatelliteName_A; -#ifdef FEATURE_COMINTEROP -const WCHAR g_pwBaseLibraryTLB[] = CoreLibName_TLB_W; -const char g_psBaseLibraryTLB[] = CoreLibName_TLB_A; -#endif // FEATURE_COMINTEROP - Volatile<LONG> g_TrapReturningThreads; HINSTANCE g_pMSCorEE; @@ -249,8 +244,6 @@ LPWSTR g_pCachedModuleFileName = 0; // HINSTANCE g_hInstShim = NULL; -char g_Version[] = VER_PRODUCTVERSION_STR; - #endif // #ifndef DACCESS_COMPILE #ifdef DACCESS_COMPILE diff --git a/src/vm/vars.hpp b/src/vm/vars.hpp index 58dbe0e86a..69540c7f39 100644 --- a/src/vm/vars.hpp +++ b/src/vm/vars.hpp @@ -579,10 +579,6 @@ EXTERN const char g_psBaseLibrary[]; EXTERN const char g_psBaseLibraryName[]; EXTERN const char g_psBaseLibrarySatelliteAssemblyName[]; -#ifdef FEATURE_COMINTEROP -EXTERN const WCHAR g_pwBaseLibraryTLB[]; -EXTERN const char g_psBaseLibraryTLB[]; -#endif // FEATURE_COMINTEROP #endif // DACCESS_COMPILE // |