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 | |
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)
-rw-r--r-- | src/debug/di/process.cpp | 50 | ||||
-rw-r--r-- | src/debug/ee/debugger.cpp | 3 | ||||
-rw-r--r-- | src/inc/msodw.h | 550 | ||||
-rw-r--r-- | src/inc/ostype.h | 77 | ||||
-rw-r--r-- | src/utilcode/util_nodependencies.cpp | 112 | ||||
-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 | ||||
-rw-r--r-- | src/zap/zapper.cpp | 4 |
17 files changed, 72 insertions, 3103 deletions
diff --git a/src/debug/di/process.cpp b/src/debug/di/process.cpp index 533a420f47..4356a8f7f4 100644 --- a/src/debug/di/process.cpp +++ b/src/debug/di/process.cpp @@ -11582,54 +11582,6 @@ void CordbProcess::HandleSyncCompleteRecieved() #ifdef FEATURE_INTEROP_DEBUGGING -// Get a Thread's _user_ starting address (the real starting address may be some -// OS shim.) -// This may return NULL for the Async-Break thread. -void* GetThreadUserStartAddr(const DEBUG_EVENT* pCreateThreadEvent) -{ - // On Win7 and above, we can trust the lpStartAddress field of the CREATE_THREAD_DEBUG_EVENT - // to be the user start address (the actual OS start address is an implementation detail that - // doesn't need to be exposed to users). Note that we are assuming that the target process - // is running on Win7 if mscordbi is. If we ever have some remoting scenario where the target - // can run on a different windows machine with a different OS version we will need a way to - // determine the target's OS version - if(RunningOnWin7()) - { - return pCreateThreadEvent->u.CreateThread.lpStartAddress; - } - - // On pre-Win7 OSes, we rely on an OS implementation detail to get the real user thread start: - // it exists in EAX at thread start time. - // Note that for a brief period of time there was a GetThreadStartInformation API in Longhorn - // we could use for this, but it was removed during the Longhorn reset. - HANDLE hThread = pCreateThreadEvent->u.CreateThread.hThread; -#if defined(DBG_TARGET_X86) - // Grab the thread's context. - DT_CONTEXT c; - c.ContextFlags = DT_CONTEXT_FULL; - BOOL succ = DbiGetThreadContext(hThread, &c); - - if (succ) - { - return (void*) c.Eax; - } -#elif defined(DBG_TARGET_AMD64) - DT_CONTEXT c; - c.ContextFlags = DT_CONTEXT_FULL; - BOOL succ = DbiGetThreadContext(hThread, &c); - - if (succ) - { - return (void*) c.Rcx; - } -#else - PORTABILITY_ASSERT("port GetThreadUserStartAddr"); -#endif - - return NULL; -} - - //--------------------------------------------------------------------------------------- // // Get (create if needed) the unmanaged thread for an unmanaged debug event. @@ -11706,7 +11658,7 @@ CordbUnmanagedThread * CordbProcess::GetUnmanagedThreadFromEvent(const DEBUG_EVE UpdateRightSideDCB(); if ((this->GetDCB()->m_helperThreadStartAddr != NULL) && (pUnmanagedThread != NULL)) { - void * pStartAddr = GetThreadUserStartAddr(pEvent); + void * pStartAddr = pEvent->u.CreateThread.lpStartAddress; if (pStartAddr == this->GetDCB()->m_helperThreadStartAddr) { diff --git a/src/debug/ee/debugger.cpp b/src/debug/ee/debugger.cpp index 8363b1f658..1e69d2b1a9 100644 --- a/src/debug/ee/debugger.cpp +++ b/src/debug/ee/debugger.cpp @@ -13525,8 +13525,7 @@ void Debugger::UnhandledHijackWorker(CONTEXT * pContext, EXCEPTION_RECORD * pRec // On Win7 WatsonLastChance returns CONTINUE_SEARCH for unhandled exceptions execpt stack overflow, and // lets OS launch debuggers for us. Before the unhandled exception reaches the OS, CLR UEF has already // processed this unhandled exception. Thus, we should not call into CLR UEF again if it is the case. - if (RunningOnWin7() && - pThread && + if (pThread && (pThread->HasThreadStateNC(Thread::TSNC_ProcessedUnhandledException) || pThread->HasThreadStateNC(Thread::TSNC_AppDomainContainUnhandled) || fSOException)) diff --git a/src/inc/msodw.h b/src/inc/msodw.h index d0745d2551..a1acc2f16f 100644 --- a/src/inc/msodw.h +++ b/src/inc/msodw.h @@ -13,455 +13,7 @@ #pragma pack(push, msodw_h) #pragma pack(4) -#define DW_TIMEOUT_VALUE 20000 -#define DW_MUTEX_TIMEOUT DW_TIMEOUT_VALUE / 2 -#define DW_NOTIFY_TIMEOUT 120000 // 2 minutes - -#define DW_CURRENT_VERSION 0x00020000 - -#define DW_MAX_ASSERT_CCH 1024 -#define DW_MAX_PATH 260 -#define DW_APPNAME_LENGTH 56 -#define DW_MAX_ERROR_CWC 260 // must be at least max_path -#define DW_MAX_REGSUBPATH 200 -#define DW_MAX_CALLSTACK 16 -#define DW_MAX_EVENTSOURCE DW_MAX_PATH -#define DW_MAX_PIDREGKEY DW_MAX_PATH #define DW_MAX_BUCKETPARAM_CWC 255 -#define DW_MAX_USERDOCS_CWC 1024 - -// return values for DW process -#define DW_RETVAL_SUCCESS 0 -#define DW_RETVAL_FAILURE 1 -#define DW_RETVAL_DEBUG 16 - -#define DW_ALLMODULES L"*\0" -#define DW_NOTAG 0 - -// this is added to the command line of the restarted app if fDweTagCommandLine is set -#define DW_CMDLINE_TAG "Watson=1" - -// The following are the fields that can be specified in a manifest file to -// launch DW in a file based reporting mode. -// The following are required UI fields. -#define DW_MANIFEST_GENERAL_APPNAME L"General_AppName=" -#define DW_MANIFEST_MAIN_INTRO_BOLD L"Main_Intro_Bold=" -#define DW_MANIFEST_QUEUED_EVENTDESCRIPTION L"Queued_EventDescription=" // this will only be shown if the report is queued - -// The following are required reporting fields. -#define DW_MANIFEST_LCID L"UI LCID=" -#define DW_MANIFEST_VERSION L"Version=" // set this to DW_CURRENT_VERSION defined in this file - -// There are two ways to specify your bucket parameters. -// The first is to fill in as many of these as you need, -// and let DW construct URLs and UNC paths for you. -#define DW_MANIFEST_EVENTTYPE L"EventType=" -#define DW_MANIFEST_P1 L"P1=" -#define DW_MANIFEST_P2 L"P2=" -#define DW_MANIFEST_P3 L"P3=" -#define DW_MANIFEST_P4 L"P4=" -#define DW_MANIFEST_P5 L"P5=" -#define DW_MANIFEST_P6 L"P6=" -#define DW_MANIFEST_P7 L"P7=" -#define DW_MANIFEST_P8 L"P8=" -#define DW_MANIFEST_P9 L"P9=" -#define DW_MANIFEST_P10 L"P10=" - -// Alternatively, you can spell it all out for us. -#define DW_MANIFEST_URL1 L"Stage1URL=" -#define DW_MANIFEST_URL2 L"Stage2URL=" -#define DW_MANIFEST_ERRORSUBPATH L"ErrorSubPath=" - -// The following are optional; DW has default behavior for all of these. -// These are UI fields (see UserInterfaceBlock for documentation if not listed below) -#define DW_MANIFEST_GENERAL_REPORTEE L"General_Reportee=" - -#define DW_MANIFEST_MAIN_CAPTION L"Main_Caption=" -#define DW_MANIFEST_MAIN_ICONFILE L"Main_IconFile=" // otherwise, no icon -#define DW_MANIFEST_MAIN_INTRO_REG L"Main_Intro_Reg=" // otherwise DAL collapses space -#define DW_MANIFEST_MAIN_CHECKBOX L"Main_CheckBox=" -#define DW_MANIFEST_MAIN_PLEA_BOLD L"Main_Plea_Bold=" -#define DW_MANIFEST_MAIN_PLEA_REG L"Main_Plea_Reg=" // otherwise DAL collapses space -#define DW_MANIFEST_MAIN_DETAILSLINK L"Main_DetailsLink=" -#define DW_MANIFEST_MAIN_REPORTBTN L"Main_ReportBtn=" -#define DW_MANIFEST_MAIN_NOREPORTBTN L"Main_NoReportBtn=" -#define DW_MANIFEST_MAIN_ALWAYSREPORTBTN L"Main_AlwaysReportBtn=" -#define DW_MANIFEST_MAIN_QUEUEBTN L"Main_QueueBtn=" -#define DW_MANIFEST_MAIN_NOQUEUEBTN L"Main_NoQueueBtn=" -#define DW_MANIFEST_MAIN_QUEUETEXT L"Main_QueueText=" -#define DW_MANIFEST_MAIN_FEEDBACKLINK L"Main_FeedbackLink=" - -#define DW_MANIFEST_DETAILS_CAPTION L"Details_Caption=" -#define DW_MANIFEST_DETAILS_PRE_HEADER L"Details_Pre_Header=" -#define DW_MANIFEST_DETAILS_PRE_BODY L"Details_Pre_Body=" -#define DW_MANIFEST_DETAILS_SIG_HEADER L"Details_Sig_Header=" -#define DW_MANIFEST_DETAILS_SIG_BODY L"Details_Sig_Body=" -#define DW_MANIFEST_DETAILS_POST_HEADER L"Details_Post_Header=" -#define DW_MANIFEST_DETAILS_POST_BODY L"Details_Post_Body=" // pretty similar to exception mode, but calls out DigPid too. -#define DW_MANIFEST_DETAILS_TECHLINK L"Details_TechLink=" -#define DW_MANIFEST_DETAILS_DCPLINK L"Details_DCPLink=" - -#define DW_MANIFEST_TECH_CAPTION L"Tech_Caption=" -#define DW_MANIFEST_TECH_FILES_HEADER L"Tech_Files_Header=" - -#define DW_MANIFEST_TRANSFER_CAPTION L"Transfer_Caption=" -#define DW_MANIFEST_TRANSFER_1CHECK L"Transfer_1check=" -#define DW_MANIFEST_TRANSFER_2CHECK L"Transfer_2check=" -#define DW_MANIFEST_TRANSFER_3CHECK L"Transfer_3check=" -#define DW_MANIFEST_TRANSFER_STATUS_INPROGRESS L"Transfer_Status_InProgress=" -#define DW_MANIFEST_TRANSFER_STATUS_DONE L"Transfer_Status_Done=" -#define DW_MANIFEST_TRANSFER_CHECKBOX L"Transfer_Checkbox=" - -#define DW_MANIFEST_SECONDLEVEL_CAPTION L"SecondLevel_Caption=" -#define DW_MANIFEST_SECONDLEVEL_PRE L"SecondLevel_Pre=" -#define DW_MANIFEST_SECONDLEVEL_POST L"SecondLevel_Post=" - -#define DW_MANIFEST_FINAL_CAPTION L"Final_Caption=" -#define DW_MANIFEST_FINAL_TEXT L"Final_Text=" -#define DW_MANIFEST_FINAL_TEXT_USERCANCEL L"Final_Text_UserCancel=" -#define DW_MANIFEST_FINAL_LINK L"Final_Link=" -#define DW_MANIFEST_FINAL_LINK_SURVEY L"Final_Link_Survey=" - -#define DW_MANIFEST_STANDBY_CAPTION L"Standby_Caption=" -#define DW_MANIFEST_STANDBY_BODY L"Standby_Body=" - -// These are reporting fields. -#define DW_MANIFEST_RFLAGS L"ReportingFlags=" -#define DW_MANIFEST_UFLAGS L"UIFlags=" -#define DW_MANIFEST_LFLAGS L"LoggingFlags=" -#define DW_MANIFEST_MFLAGS L"MiscFlags=" -#define DW_MANIFEST_BRAND L"Brand=" -#define DW_MANIFEST_EVENTSOURCE L"EventLogSource=" -#define DW_MANIFEST_EVENTID L"EventID=" -#define DW_MANIFEST_DIGPIDPATH L"DigPidRegPath=" -#define DW_MANIFEST_CHECKBOX_REGKEY L"CheckBoxRegKey=" -#define DW_MANIFEST_CUSTOM_QUERY_STRING_ELEMENTS L"CustomQueryStringElements=" - -// DW expects at least one of these to be set. -#define DW_MANIFEST_DELETABLEFILES L"FilesToDelete=" -#define DW_MANIFEST_NONDELETABLEFILES L"FilesToKeep=" - -// These may be optionally set, and will be used on second-level data requests. -#define DW_MANIFEST_USERFILES L"UserDocs=" -#define DW_MANIFEST_HEAP L"Heap=" - - -#define DW_X(X) L##X -#define DW_Y(X) DW_X(X) - -// Seperator for file lists (Manifest DataFiles and Exception Additional Files) -#define DW_FILESEPA '|' -#define DW_FILESEP DW_Y(DW_FILESEPA) - -#define DW_OMIT_SECTION L"NIL" -#define DW_APPNAME_TOKEN L"%General_AppName%" -#define DW_REPORTEE_TOKEN L"%General_Reportee%" - -// the following is required for queued information file only -#define DW_QR_VERSION L"QueueVer=" -#define DW_QR_DATE L"Date=" -#define DW_QR_TIME L"Time=" -#define DW_QR_REPORTSIZE L"ReportSize=" -#define DW_QR_BYTES L"Bytes=" -#define DW_QR_KILOBYTES L"Kilobytes=" -#define DW_QR_MEGABYTES L"Megabytes=" -#define DW_QR_MOREINFO L"MoreInfo=" -#define DW_QR_BP0 L"BP0=" -#define DW_QR_BP1 L"BP1=" -#define DW_QR_BP2 L"BP2=" -#define DW_QR_BP3 L"BP3=" -#define DW_QR_BP4 L"BP4=" -#define DW_QR_BP5 L"BP5=" -#define DW_QR_BP6 L"BP6=" -#define DW_QR_BP7 L"BP7=" -#define DW_QR_BP8 L"BP8=" -#define DW_QR_BP9 L"BP9=" -#define DW_QR_BP10 L"BP10=" -#define DW_QR_CBP L"CBP=" -#define DW_QR_DWVER0 L"DWVer0=" -#define DW_QR_DWVER1 L"DWVer1=" -#define DW_QR_DWVER2 L"DWVer2=" -#define DW_QR_DWVER3 L"DWVer3=" -#define DW_QR_MODE L"QueueMode=" - - -// shared reg values between DW and DW COM EXE -#define DEFAULT_SUBPATH L"Microsoft\\PCHealth\\ErrorReporting\\DW" -#define QUEUE_REG_SUBPATH L"Software\\" DEFAULT_SUBPATH -#define QUEUE_REG_OKTOREPORT_VALUE L"OkToReportFromTheseQueues" -#define WATSON_INSTALLED_REG_SUBPATH QUEUE_REG_SUBPATH L"\\Installed" -#define WATSON_INSTALLED_REG_SUBPATH_IA64 L"Software\\Wow6432Node\\"DEFAULT_SUBPATH L"\\Installed" -#define WATSON_INSTALLED_REG_VAL L"DW0200" // keep in sync with %MSI%\src\sdl\shared\watson.sreg -#define WATSON_INSTALLED_REG_VAL_IA64 L"DW0201" // keep in sync with %MSI%\src\sdl\shared\watson.sreg - -// names for the Watson exes -#define DW_EXEA "dw20.exe" -#define DW_EXE DW_Y(DW_EXEA) -#define DW_COM_EXEA "dwtrig20.exe" -#define DW_COM_EXE DW_Y(DW_COM_EXEA) - -// the following option is used to exec DW to set the trigger for queued reporting -// ie Run 'dw20 -k <queue number>' -#define OPTSQRTA 'k' // queued reporting trigger -#define OPTSQRT DW_Y(OPTSQRTA) - -// the following option is used to exec DW in queued reporting mode -// ie Run 'dw20 -q <queue types to report from>' -#define OPTQRMA 'q' // queued reporting mode -#define OPTQRM DW_Y(OPTQRMA) - -// the following option is used to exec the DW COM EXE to trigger queued reporting after a delay time -// ie Run 'dwtrig20 -t' -#define OPTQRTA 't' // queued reporting trigger -#define OPTQRT DW_Y(OPTQRTA) - -// the following option is used to exec the DW COM EXE to trigger queued reporting immediately -// ie Run 'dwtrig20 -f <queue types to report from>' -#define OPTQRFA 'f' // force queued reporting -#define OPTQRF DW_Y(OPTQRFA) - -#define C_QUEUE_TYPES 3 - -enum // EQueueTypes -{ - dwqueueMin = 0x00000001, - - // all the queues types - // these must be consecutive - // (valid range for queue types is 0x00000001 - 0x00008000, 16 total) - dwqueueRegular = 0x00000001, - dwqueueSignOff = 0x00000002, - dwqueueHeadless = 0x00000004, - // next valid queue type: 0x00000008 - - // the maximum dwqueueMax is 0x00008000 - dwqueueMax = 0x00000004, - - // triggering flags (valid range for triggers is 0x00010000 - 0x08000000, 12 total) - dwtriggerAtLogon = 0x00010000, - dwtriggerAtConnectionMade = 0x00020000, - - // special flags (valid range for special flags is 0x1000000 - 0x80000000, 4 total) - dwqueueAnyAdmin = 0x10000000, // Admin queue - - // flag combinations - dwqueueTypes = 0x00000007, // Regular | SignOff | Headless -}; - -enum // EQueuedReportingDialogResults -{ - qrdrCancel = 0x00000001, - qrdrLater = 0x00000002, - qrdrDone = 0x00000004, -}; - - -#ifdef DEBUG -enum // AssertActionCodes -{ - DwAssertActionFail = 0, - DwAssertActionDebug, - DwAssertActionIgnore, - DwAssertActionAlwaysIgnore, - DwAssertActionIgnoreAll, - DwAssertActionQuit, -}; -#endif - -// Caller is the app that has experienced an exception and launches DW - -enum // ECrashTimeDialogStates // msoctds -{ - msoctdsNull = 0x00000000, - msoctdsQuit = 0x00000001, - msoctdsRestart = 0x00000002, - msoctdsRecover = 0x00000004, - msoctdsUnused = 0x00000008, - msoctdsDebug = 0x00000010, -}; - -#define MSODWRECOVERQUIT (msoctdsRecover | msoctdsQuit) -#define MSODWRESTARTQUIT (msoctdsRestart | msoctdsQuit) -#define MSODWRESPONSES (msoctdsQuit | msoctdsRestart | msoctdsRecover) - -// THIS IS PHASED OUT -- DON'T USE -enum // EMsoCrashHandlerFlags // msochf -{ - msochfNull = 0x00000000, - msochfCheckboxOff = 0x00000001, - - msochfUnused = msoctdsUnused, // THESE MUST BE THE SAME 0x8 - msochfCanRecoverDocuments = msoctdsRecover, // 0x4 - - msochfObsoleteCanDebug = 0x00010001, // not used anymore - msochfCannotSneakyDebug = 0x00010002, // The "hidden" debug feature won't work - msochfDefaultDontReport = 0x00010004, - msochReportingDisabled = 0x00010008, // User cannot change default reporting choice -}; - - -// -enum // EMsoCrashHandlerResults // msochr -{ - msochrNotHandled = msoctdsNull, - msochrUnused = msoctdsUnused, - msochrDebug = msoctdsDebug, - msochrRecoverDocuments = msoctdsRecover, - msochrRestart = msoctdsRestart, - msochrQuit = msoctdsQuit, -}; - -enum // EDwReportingFlags -{ - fDwrDeleteFiles = 0x00000001, // delete "files to delete" after use (plus heap, minidump, manifest). - fDwrIgnoreHKCU = 0x00000002, // Only look at HKLM. If you do not set this, we will look at both HKCU and HKLM. - fDwrForceOfflineMode = 0x00000008, // DW will force the report to be queued - fDwrForceToAdminQueue = 0x00000004 | fDwrForceOfflineMode, // DW will force the report to be queued on the Admin queue - fDwrDenyOfflineMode = 0x00000010, // DW will not allow report to be queued - fDwrNoHeapCollection = 0x00000020, // DW will not gather the heap. - fDwrNoSecondLevelCollection = 0x00000040 | fDwrNoHeapCollection, // DW will not send any second level data, including the heap - fDwrNeverUpload = 0x00000080, // don't report - fDwrDontPromptIfCantReport = 0x00000100, // DW will not show any UI if we're not going to report. - fDwrNoDefaultCabLimit = 0x00000200, // DW under CER won't use 5 as the fallback but unlimited instead (policy still overrides) -}; - -enum // EDwUIFlags -{ - fDwuNoEventUI = 0x00000001, // DW will always try to send headless, regardless of DWAllowHeadless - // Having no UI reporting from the queue means that there is no UI at the time of the event - fDwuNoQueueUI = 0x00000002 | fDwuNoEventUI, // DW will put the report in the headless queue with no UI - fDwuShowFeedbackLink = 0x00000004, // Show the "Why should I report" link. - fDwuUseIE = 0x00000008, // always launch w/ IE - - // DO NOT use this flag. It doesn't work. Instead customize by using the UserInterfaceBlock. - fDwuUseLitePlea = 0x00000010, // DW won't suggest product change in report plea - - fDwuManifestDebug = 0x00000020, // DW will provide a debug button in manifest mode - fDwuDenySuspend = 0x00000040, // DW will keep powersave mode from suspending it, until transfer is complete. -}; - -enum // EDwLoggingFlags -{ - fDwlNoParameterLog = 0x00000001, // DW won't log the initial parameters - fDwlNoBucketLog = 0x00000002, // DW won't log the bucket ID and the bucket parameters - fDwlResponseLog = 0x00000004, // log the resolved response, including extra args, to the event log with event 1010. -}; - -enum // EDwExceptionModeFlags -{ - fDweCheckSig = 0x00000001, // checks the signatures of the App/Mod list - fDweTagCommandLine = 0x00000002, // adds DW_CMDLINE_TAG to command line when restarting apps. - fDweDefaultQuit = 0x00000004, // In exception mode, DW will default the restart/recover box to off. Doesn't affect regkey-based checkboxes. - fDweKeepMinidump = 0x00000008, // Don't delete the minidump when we're done using it. - fDweIgnoreAeDebug = 0x00000010, // Don't check AeDebug to determine whether or not to show the Debug button. - fDweGatherHeapAsMdmp = 0x00000020, // Use the minidump API to gather the heap, rather than the minimal version we build directly - fDweReleaseBeforeCabbing = 0x00000040, // Release the thread doing the dump and cab the files in the background. -}; - -enum // EDwMiscFlags -{ - fDwmOfficeDigPID = 0x00000001, // use custom internal code to figure out what SKU of Office is installed - fDwmOfficeSQMReporting = 0x00000002, // DW should collect SQM data and save it for Office to upload (if QMEnabled reg key is set). - fDwmContainsOnlyAnonymousData = 0x00000003, // DW does nothing with this flag, but the LH shim will recognize it. It should be used in rare - // circumstances when the silent report is known to contain NO PII. -}; - - -typedef struct _AssertBlock -{ - // for Assert communication - DWORD dwTag; // [in] AssertTag - char szAssert[DW_MAX_ASSERT_CCH]; // [in] Sz from the assert - int AssertActionCode; // [out] action code to take - - DWORD cdwCallstack; // The number of actual callstack entries - DWORD rgdwCallstack[DW_MAX_CALLSTACK]; // Callstack - -} AssertBlock; - -typedef struct _UserInterfaceBlock -{ - // THIS ITEM IS REQUIRED. We do not go find your executable name to use instead. - WCHAR wzGeneral_AppName[DW_APPNAME_LENGTH]; - - // everything below this point is optional - WCHAR wzGeneral_Reportee[DW_APPNAME_LENGTH]; // on whose behalf we request the report; otherwise "Microsoft" - - WCHAR wzMain_Caption[DW_MAX_ERROR_CWC]; // otherwise <General_AppName> - WCHAR wzMain_IconFile[DW_MAX_PATH]; // otherwise pulled from executable - WCHAR wzMain_Intro_Bold[DW_MAX_ERROR_CWC]; // otherwise "<General_AppName> has encountered a problem and needs to close. We are sorry for the inconvenience." - WCHAR wzMain_Intro_Reg[DW_MAX_ERROR_CWC]; // various defaults, usually "Please tell <General_Reportee> about this problem" - WCHAR wzMain_Checkbox[DW_MAX_ERROR_CWC]; // otherwise "Don't show me this again" - WCHAR wzMain_Plea_Bold[DW_MAX_ERROR_CWC]; // otherwise "Please tell <General_Reportee> about this problem" ("NIL" means skip whole string) - WCHAR wzMain_Plea_Reg[DW_MAX_ERROR_CWC]; // otherwise "We have created an error report that you can send to help us improve <General_AppName>. We will treat this report as confidential and anonymous." - WCHAR wzMain_DetailsLink[DW_MAX_ERROR_CWC]; // otherwise "See what data this error report contains." - WCHAR wzMain_ReportBtn[DW_APPNAME_LENGTH]; // otherwise "&Send Error Report" - WCHAR wzMain_NoReportBtn[DW_APPNAME_LENGTH]; // otherwise "&Don't Send" - WCHAR wzMain_AlwaysReportBtn[DW_APPNAME_LENGTH];// otherwise "&Send Error Report" - WCHAR wzMain_QueueBtn[DW_APPNAME_LENGTH]; // otherwise "&Send Report Later" - WCHAR wzMain_NoQueueBtn[DW_APPNAME_LENGTH]; // otherwise "&Don't Report" - WCHAR wzMain_QueueText[DW_MAX_ERROR_CWC]; // otherwise "You cannot send this error report now because you are not connected...." - WCHAR wzMain_FeedbackLink[DW_MAX_ERROR_CWC]; // otherwise "Why should I report to %General_Reportee%?" - - WCHAR wzDetails_Caption[DW_MAX_ERROR_CWC]; // otherwise <General_AppName> - WCHAR wzDetails_Pre_Header[DW_MAX_ERROR_CWC]; // otherwise "Error Details" - WCHAR wzDetails_Pre_Body[DW_MAX_ERROR_CWC]; // otherwise "foo" ("NIL" means delete whole Pre section) - WCHAR wzDetails_Sig_Header[DW_MAX_ERROR_CWC]; // otherwise "Error Signature" - WCHAR wzDetails_Sig_Body[DW_MAX_ERROR_CWC]; // otherwise constructed by DW from bucket params from stage 2 URL ("NIL" means delete whole Sig section) - WCHAR wzDetails_Post_Header[DW_MAX_ERROR_CWC]; // otherwise "Reporting Details" - WCHAR wzDetails_Post_Body[DW_MAX_ERROR_CWC]; // otherwise "This error report includes:..." ("NIL" means delete whole Post section) - WCHAR wzDetails_TechLink[DW_MAX_ERROR_CWC]; // otherwise "View the contents of this error report" - WCHAR wzDetails_DCPLink[DW_MAX_ERROR_CWC]; // otherwise "Read our Data Collection Policy" - - WCHAR wzTech_Caption[DW_MAX_ERROR_CWC]; // otherwise "Error Report Contents" - WCHAR wzTech_MDump_Header[DW_MAX_ERROR_CWC]; // otherwise "The following information about your process will be reported...." - WCHAR wzTech_Files_Header[DW_MAX_ERROR_CWC]; // otherwise "The following files will be included in this error report." - - WCHAR wzTransfer_Caption[DW_MAX_ERROR_CWC]; // otherwise "Error Reporting" - WCHAR wzTransfer_1Check[DW_MAX_ERROR_CWC]; // otherwise "Preparing error report" - WCHAR wzTransfer_2Check[DW_MAX_ERROR_CWC]; // otherwise "Connecting to server" - WCHAR wzTransfer_3Check[DW_MAX_ERROR_CWC]; // otherwise "Checking for the status of this problem" - WCHAR wzTransfer_Status_InProgress[DW_MAX_ERROR_CWC]; // otherwise "Transferring report..." - WCHAR wzTransfer_Status_Done[DW_MAX_ERROR_CWC]; // otherwise "Reporting Completed. Thank you!" - WCHAR wzTransfer_Checkbox[DW_MAX_ERROR_CWC]; // otherwise "Close When Done" - - WCHAR wzSecondLevel_Caption[DW_MAX_ERROR_CWC]; // otherwise "More Information" - WCHAR wzSecondLevel_Pre[DW_MAX_ERROR_CWC]; // otherwise "In order to correctly diagnose this problem the following information...." - WCHAR wzSecondLevel_Post[DW_MAX_ERROR_CWC]; // otherwise "Please click "Cancel" if you do not wish to share this information" (May also contain "Your files may contain sensitive information") - - WCHAR wzFinal_Caption[DW_MAX_ERROR_CWC]; // otherwise "Reporting" - WCHAR wzFinal_Text[DW_MAX_ERROR_CWC]; // otherwise "Thank you for taking the time to report this problem." - WCHAR wzFinal_Text_UserCancel[DW_MAX_ERROR_CWC]; // otherwise "Reporting stopped on user cancel." - WCHAR wzFinal_Link[DW_MAX_ERROR_CWC]; // otherwise "Get more information about preventing this problem in the future." - WCHAR wzFinal_Link_Survey[DW_MAX_ERROR_CWC]; // otherwise "Provide additional information about this problem via a short questionnaire." - - WCHAR wzStandby_Caption[DW_MAX_ERROR_CWC]; // otherwise "Power Management" - WCHAR wzStandby_Body[DW_MAX_ERROR_CWC]; // otherwise "Windows cannot go on standby because <General_AppName> has experienced..." - - WCHAR wzDialup_Caption[DW_MAX_ERROR_CWC]; // otherwise "Active Internet Connection Required" - WCHAR wzDialup_Body[DW_MAX_ERROR_CWC]; // otherwise "In order to report this problem, you must connect to the Internet. Please start your connection before continuing." - - WCHAR wzHangup_Caption[DW_MAX_ERROR_CWC]; // otherwise "Finished Reporting" - WCHAR wzHangup_Body[DW_MAX_ERROR_CWC]; // otherwise "Reporting has finished. You may close your Internet connection now." - WCHAR wzHangup_Body_UserCancel[DW_MAX_ERROR_CWC]; // otherwise "Reporting has been cancelled. You may close your Internet connection now." - - WCHAR wzQueued_EventDescription[DW_MAX_ERROR_CWC]; // otherwise "Application Error" - -} UserInterfaceBlock; - - -typedef struct _CustomMinidumpBlock -{ - BOOL fCustomMinidump; - DWORD dwMinidumpType; - BOOL fOnlyThisThread; - DWORD dwThisThreadFlags; - DWORD dwOtherThreadFlags; - DWORD dwThisThreadExFlags; - DWORD dwOtherThreadExFlags; - DWORD dwPreferredModuleFlags; - DWORD dwOtherModuleFlags; -} CustomMinidumpBlock; typedef struct _GenericModeBlock { @@ -479,107 +31,5 @@ typedef struct _GenericModeBlock WCHAR wzP10[DW_MAX_BUCKETPARAM_CWC]; } GenericModeBlock; - -typedef struct _DWSharedMem20 -{ - DWORD dwSize; // should be set to size of DWSharedMem - DWORD dwVersion; // callers should set this to DWCurrentVersion as in this header - - DWORD pid; // Process Id of caller - DWORD tid; // Id of excepting thread - DWORD_PTR eip; // EIP of the excepting instruction - PEXCEPTION_POINTERS pep; // Exception pointers given to the callee's - // exception handler - HANDLE hEventDone; // event DW signals when done - // caller will also signal this if it things - // DW has hung and restarts itself - HANDLE hEventNotifyDone; // App sets when it's done w/ notifcation phase - HANDLE hEventAlive; // heartbeat event DW signals per EVENT_TIMEOUT - HANDLE hMutex; // to protect the signaling of EventDone - HANDLE hProc; // handle to the calling process - - DWORD bfDWRFlags; // controls caller-specific behaviors wrt REPORTING - DWORD bfDWUFlags; // controls caller-specific behaviors wrt UI - DWORD bfDWLFlags; // controls caller-specific behaviors wrt LOGGING - DWORD bfDWEFlags; // controls caller-specific behaviors wrt EXCEPTION MODE SPECIFICS - DWORD bfDWMFlags; // controls caller-specific behaviors wrt MISCELLANEOUS THINGS - - LCID lcidUI; // will try this UI langauge if non-zero - // next DW will use the system LCID, - // and if it can't find an intl dll for that, - // will fall back on US English (1033) - - DWORD bfmsoctdsOffer; // bitfield of user choices to offer - // note that you must specify two of: - // Quit, Restart, Recover, Ignore - // The Debug choice is independent - DWORD bfmsoctdsNotify; // bitfield of user choices for which the - // app wants control back instead of simply being - // terminated by DW. The app will then be - // responsible for pinging DW (if desired) with - // hEventAlive and for notify DW it's ok to - // terminate the app w/ hEventDone - - DWORD bfmsoctdsLetRun; // bitfield of user choices for which the - // app wants control back instead of being - // terminated by DW. DW can then safely ignore - // the app and exit. - - WCHAR wzEventLogSource[DW_MAX_EVENTSOURCE]; // Set this as your source if you want to log events. - - WCHAR wzModuleFileName[DW_MAX_PATH]; // The result of GetModuleFileName(NULL) - - char szPIDRegKey[DW_MAX_PIDREGKEY]; // name of the key that holds the PID - // can be used by the Server for - // spoof-detection - char szBrand[DW_APPNAME_LENGTH]; // passed as a param to Privacy Policy link - char szCustomQueryStringElements[DW_MAX_PATH]; // passsed as param to Privacy Policy Link and Response Link - - char szCheckBoxRegKey[DW_MAX_PATH]; // If we get a key, we should show the - // "Never send reports for this type of event" checkbox. - // That string can be overridden in the UIB. - - WCHAR wzDotDataDlls[DW_MAX_PATH]; // contains the list of DLLs, terminated - // by '\0' characters, that DW will - // collect the .data sections into the - // full minidump version - // e.g. "mso9.dll\0outllib.dll\0" - - WCHAR wzFilesToDelete[1024]; // File list, seperated by DW_FILESEP - // each of these files gets added to the - // cab at upload time - // These are files that we will delete - // if fDwrDeleteFiles is sent. - - WCHAR wzFilesToKeep[1024]; // File list, seperated by DW_FILESEP - // each of these files gets added to the - // cab at upload time - // These are files that we will NOT delete - // if fDwrDeleteFiles is sent. - - WCHAR wzUserDocs[DW_MAX_USERDOCS_CWC]; // File list, seperated by DW_FILESEP - // each of these files gets added to the - // cab at upload time IFF we get a second-level request for them. - // These are files that we will NOT delete - // if fDwrDeleteFiles is sent. - - UserInterfaceBlock uib; // encapsulates UI override data. You must set the appname in here. - AssertBlock ab; // encapsulates assert-tag data - GenericModeBlock gmb; // encapsulates custom bucket parameters for generic mode - CustomMinidumpBlock cmb; // encapsulates customization info for minidump gathering - - // OUTPARAMS - DWORD msoctdsResult; // result from crash-time dialog - BOOL fReportProblem; // did user approve reporting? - WCHAR wzMinidumpLocation[DW_MAX_PATH]; // when fDweKeepMinidump is set, we write its name here. - // it is available for access once hEventDone is signaled. - - // DYNAMIC INPARAMS used during recovery conversation for DW's UI - int iPingCurrent; // current count for the recovery progress bar - int iPingEnd; // index for the end of the recovery progress bar - -} DWSharedMem20, DWSharedMem; - - #pragma pack(pop, msodw_h) #endif // MSODW_H diff --git a/src/inc/ostype.h b/src/inc/ostype.h index c18d05a5f6..f17afb1d6f 100644 --- a/src/inc/ostype.h +++ b/src/inc/ostype.h @@ -24,17 +24,11 @@ //***************************************************************************** typedef enum { RUNNING_ON_STATUS_UNINITED = 0, - RUNNING_ON_WINNT5 = 1, - RUNNING_ON_WINXP = 2, - RUNNING_ON_WIN2003 = 3, // _WIN64 can assume that all OSes that we're running on will be WIN2003+ - RUNNING_ON_VISTA = 4, - RUNNING_ON_WIN7 = 5, - RUNNING_ON_WIN8 = 6 + RUNNING_ON_WIN7 = 1, + RUNNING_ON_WIN8 = 2 } RunningOnStatusEnum; extern RunningOnStatusEnum gRunningOnStatus; -extern BOOL gExInfoAvailable; -extern BOOL gExInfoIsServer; void InitRunningOnVersionStatus(); @@ -53,43 +47,12 @@ void InitWinRTStatus(); #endif // FEATURE_COMINTEROP && !FEATURE_CORESYSTEM //***************************************************************************** -// -// List of currently supported platforms: -// -// Win2000 - not supported -// WinXP - not supported -// Win2k3 - not supported -// Vista - desktop, CoreCLR -// Win7 - desktop, CoreCLR -// Win8 - desktop, CoreCLR on CoreSystem, ARM -// -//***************************************************************************** - -//***************************************************************************** -// Returns true if you are running on Windows 7 or newer. -//***************************************************************************** -inline BOOL RunningOnWin7() -{ - WRAPPER_NO_CONTRACT; -#if defined(_ARM_) || defined(FEATURE_CORESYSTEM) - return TRUE; -#else - if (gRunningOnStatus == RUNNING_ON_STATUS_UNINITED) - { - InitRunningOnVersionStatus(); - } - - return (gRunningOnStatus >= RUNNING_ON_WIN7) ? TRUE : FALSE; -#endif -} - -//***************************************************************************** // Returns true if you are running on Windows 8 or newer. //***************************************************************************** inline BOOL RunningOnWin8() { WRAPPER_NO_CONTRACT; -#if defined(_ARM_) || defined(CROSSGEN_COMPILE) +#if (!defined(_X86_) && !defined(_AMD64_)) || defined(CROSSGEN_COMPILE) return TRUE; #else if (gRunningOnStatus == RUNNING_ON_STATUS_UNINITED) @@ -101,40 +64,6 @@ inline BOOL RunningOnWin8() #endif } -//***************************************************************************** -// Returns true if extra information is available -//***************************************************************************** -inline BOOL ExOSInfoAvailable() -{ - WRAPPER_NO_CONTRACT; - if (gRunningOnStatus == RUNNING_ON_STATUS_UNINITED) - { - InitRunningOnVersionStatus(); - } - - return gExInfoAvailable; -} - -//***************************************************************************** -// Returns true if we're running on a server OS. Requires ExOSInfoAvailable() -// to be TRUE -//***************************************************************************** -inline BOOL ExOSInfoRunningOnServer() -{ - WRAPPER_NO_CONTRACT; - /* - @TODO: _ASSERTE not available here... - _ASSERTE(ExOSInfoAvailable() && - "You should only call this after making sure ExOSInfoAvailable() returned TRUE"); - */ - if (gRunningOnStatus == RUNNING_ON_STATUS_UNINITED) - { - InitRunningOnVersionStatus(); - } - - return gExInfoIsServer; -} - #ifdef FEATURE_COMINTEROP #ifdef FEATURE_CORESYSTEM diff --git a/src/utilcode/util_nodependencies.cpp b/src/utilcode/util_nodependencies.cpp index 7ce3c83036..387ccbe071 100644 --- a/src/utilcode/util_nodependencies.cpp +++ b/src/utilcode/util_nodependencies.cpp @@ -18,11 +18,9 @@ #if !defined(FEATURE_UTILCODE_NO_DEPENDENCIES) || defined(_DEBUG) RunningOnStatusEnum gRunningOnStatus = RUNNING_ON_STATUS_UNINITED; -BOOL gExInfoAvailable = FALSE; -BOOL gExInfoIsServer = TRUE; #define NON_SUPPORTED_PLATFORM_MSGBOX_TITLE W("Platform not supported") -#define NON_SUPPORTED_PLATFORM_MSGBOX_TEXT W("The minimum supported platform is Windows 2000") +#define NON_SUPPORTED_PLATFORM_MSGBOX_TEXT W("The minimum supported platform is Windows 7") #define NON_SUPPORTED_PLATFORM_TERMINATE_ERROR_CODE 0xBAD1BAD1 //***************************************************************************** @@ -81,84 +79,6 @@ void InitRunningOnVersionStatus () goto CHECK_SUPPORTED; } - - ZeroMemory(&sVer, sizeof(OSVERSIONINFOEX)); - sVer.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); - - sVer.dwMajorVersion = 6; - sVer.dwPlatformId = VER_PLATFORM_WIN32_NT; - - - dwlConditionMask = 0; - VER_SET_CONDITION(dwlConditionMask, CLR_VER_PLATFORMID, VER_EQUAL); - VER_SET_CONDITION(dwlConditionMask, CLR_VER_MAJORVERSION, VER_GREATER_EQUAL); - - if(VerifyVersionInfo(&sVer, CLR_VER_MAJORVERSION | CLR_VER_PLATFORMID, dwlConditionMask)) - { - gRunningOnStatus = RUNNING_ON_VISTA; - fSupportedPlatform = TRUE; - goto CHECK_SUPPORTED; - } - - - ZeroMemory(&sVer, sizeof(OSVERSIONINFOEX)); - sVer.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); - - sVer.dwMajorVersion = 5; - sVer.dwMinorVersion = 2; - sVer.dwPlatformId = VER_PLATFORM_WIN32_NT; - - - dwlConditionMask = 0; - VER_SET_CONDITION(dwlConditionMask, CLR_VER_PLATFORMID, VER_EQUAL); - VER_SET_CONDITION(dwlConditionMask, CLR_VER_MAJORVERSION, VER_GREATER_EQUAL); - VER_SET_CONDITION(dwlConditionMask, CLR_VER_MINORVERSION, VER_GREATER_EQUAL); - - if(VerifyVersionInfo(&sVer, CLR_VER_MAJORVERSION | CLR_VER_PLATFORMID | CLR_VER_MINORVERSION, dwlConditionMask)) - { - gRunningOnStatus = RUNNING_ON_WIN2003; - fSupportedPlatform = TRUE; - goto CHECK_SUPPORTED; - } - - sVer.dwMajorVersion = 5; - sVer.dwMinorVersion = 1; - sVer.dwPlatformId = VER_PLATFORM_WIN32_NT; - - dwlConditionMask = 0; - VER_SET_CONDITION(dwlConditionMask, CLR_VER_PLATFORMID, VER_EQUAL); - VER_SET_CONDITION(dwlConditionMask, CLR_VER_MAJORVERSION, VER_GREATER_EQUAL); - VER_SET_CONDITION(dwlConditionMask, CLR_VER_MINORVERSION, VER_GREATER_EQUAL); - - if(VerifyVersionInfo(&sVer, CLR_VER_MAJORVERSION | CLR_VER_PLATFORMID | CLR_VER_MINORVERSION, dwlConditionMask)) - { - gRunningOnStatus = RUNNING_ON_WINXP; - fSupportedPlatform = TRUE; - goto CHECK_SUPPORTED; - } - - - - ZeroMemory(&sVer, sizeof(OSVERSIONINFOEX)); - sVer.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); - - sVer.dwMajorVersion = 5; - sVer.dwMinorVersion = 0; - sVer.dwPlatformId = VER_PLATFORM_WIN32_NT; - - - dwlConditionMask = 0; - VER_SET_CONDITION(dwlConditionMask, CLR_VER_PLATFORMID, VER_EQUAL); - VER_SET_CONDITION(dwlConditionMask, CLR_VER_MAJORVERSION, VER_GREATER_EQUAL); - VER_SET_CONDITION(dwlConditionMask, CLR_VER_MINORVERSION, VER_GREATER_EQUAL); - - if(VerifyVersionInfo(&sVer, CLR_VER_MAJORVERSION | CLR_VER_PLATFORMID | CLR_VER_MINORVERSION, dwlConditionMask)) - { - gRunningOnStatus = RUNNING_ON_WINNT5; - fSupportedPlatform = TRUE; - goto CHECK_SUPPORTED; - } - CHECK_SUPPORTED: if (!fSupportedPlatform) @@ -170,36 +90,6 @@ CHECK_SUPPORTED: TerminateProcess(GetCurrentProcess(), NON_SUPPORTED_PLATFORM_TERMINATE_ERROR_CODE); } - gExInfoAvailable = 0; - gExInfoIsServer = 0; - - OSVERSIONINFOEX sVerX; - ZeroMemory(&sVerX, sizeof(OSVERSIONINFOEX)); - sVerX.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); - sVerX.wProductType = VER_NT_DOMAIN_CONTROLLER; - - dwlConditionMask = 0; - VER_SET_CONDITION(dwlConditionMask, CLR_VER_PRODUCT_TYPE, VER_EQUAL); - - if(VerifyVersionInfo(&sVerX, CLR_VER_PRODUCT_TYPE, dwlConditionMask)) - { - gExInfoIsServer = 1; - } - - - ZeroMemory(&sVerX, sizeof(OSVERSIONINFOEX)); - sVerX.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); - sVerX.wProductType = VER_NT_SERVER; - - dwlConditionMask = 0; - VER_SET_CONDITION(dwlConditionMask, CLR_VER_PRODUCT_TYPE, VER_EQUAL); - - if(VerifyVersionInfo(&sVerX, CLR_VER_PRODUCT_TYPE, dwlConditionMask)) - { - gExInfoIsServer = 1; - } - - gExInfoAvailable = 1; #else // FEATURE_PAL // UNIXTODO: Do we need version checks for Linux? #endif // FEATURE_PAL 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 // diff --git a/src/zap/zapper.cpp b/src/zap/zapper.cpp index 59d05a08de..b7dc540e09 100644 --- a/src/zap/zapper.cpp +++ b/src/zap/zapper.cpp @@ -782,15 +782,13 @@ void Zapper::CleanupAssembly() // To be used with GetSpecificCpuInfo() #ifdef _TARGET_X86_ -BOOL Runtime_Test_For_SSE2(); - #define CPU_X86_FAMILY(cpuType) (((cpuType) & 0x0F00) >> 8) #define CPU_X86_MODEL(cpuType) (((cpuType) & 0x00F0) >> 4) // Stepping is masked out by GetSpecificCpuInfo() // #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 |