|
|
/*++
Copyright (c) 1991-2001 Microsoft Corporation
Module Name:
erwatch.cpp
Abstract:
This module contains the code to report pending watchdog timeout events at logon after dirty reboot.
Author:
Michael Maciesowicz (mmacie) 29-May-2001
Environment:
User mode at logon.
Revision History:
--*/
#include "savedump.h"
HANDLE CreateWatchdogEventFile( IN PWSTR FileName )
/*++
Routine Description:
This routine creates watchdog event report file.
Arguments:
FileName - Points to the watchdog event file name.
Return Value:
File handle if successful, INVALID_HANDLE_VALUE otherwise.
--*/
{ WCHAR Buffer[256]; HANDLE FileHandle; BOOL Status; SYSTEMTIME Time; TIME_ZONE_INFORMATION TimeZone;
//
// Create watchdog event file.
//
FileHandle = CreateFile(FileName, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (INVALID_HANDLE_VALUE == FileHandle) { return FileHandle; }
//
// Write header info.
//
Status = WriteWatchdogEventFile(FileHandle, L"//\r\n// Watchdog Event Log File\r\n//\r\n\r\n");
if (TRUE == Status) { Status = WriteWatchdogEventFile(FileHandle, L"LogType: Watchdog\r\n"); }
if (TRUE == Status) { GetLocalTime(&Time);
swprintf(Buffer, L"Created: %d-%2.2d-%2.2d %2.2d:%2.2d:%2.2d\r\n", Time.wYear, Time.wMonth, Time.wDay, Time.wHour, Time.wMinute, Time.wSecond);
Status = WriteWatchdogEventFile(FileHandle, Buffer); }
if (TRUE == Status) { GetTimeZoneInformation(&TimeZone);
swprintf(Buffer, L"TimeZone: %d - %s\r\n", TimeZone.Bias, TimeZone.StandardName);
Status = WriteWatchdogEventFile(FileHandle, Buffer); }
if (TRUE == Status) { swprintf(Buffer, L"WindowsVersion: XP\r\n");
Status = WriteWatchdogEventFile(FileHandle, Buffer); }
if (TRUE == Status) { Status = WriteWatchdogEventFile(FileHandle, L"EventType: 0xEA - Thread Stuck in Device Driver\r\n"); }
if (FALSE == Status) { CloseHandle(FileHandle); FileHandle = INVALID_HANDLE_VALUE; }
return FileHandle; }
BOOL CreateWatchdogEventFileName( OUT PWSTR FileName )
/*++
Routine Description:
This routine generates watchdog event report full path file name.
Arguments:
FileName - Points to the storage for generated file name (MAX_PATH size assumed).
Return Value:
TRUE if successful, FALSE otherwise.
--*/
{ INT Retry; WCHAR DirName[MAX_PATH]; DWORD Size; DWORD ReturnedSize; SYSTEMTIME Time;
ASSERT(NULL != FileName);
//
// Create %SystemRoot%\LogFiles\Watchdog directory for watchdog event files.
//
Size = MAX_PATH - sizeof (L"YYMMDD_HHMM_NN.wdl");
ReturnedSize = ExpandEnvironmentStrings(L"%SystemRoot%\\LogFiles", DirName, Size);
if ((0 == ReturnedSize) || (ReturnedSize > Size)) { return FALSE; }
CreateDirectory(DirName, NULL);
ReturnedSize = ExpandEnvironmentStrings(L"%SystemRoot%\\LogFiles\\Watchdog", DirName, Size);
if ((0 == ReturnedSize) || (ReturnedSize > Size)) { return FALSE; }
CreateDirectory(DirName, NULL);
//
// Create watchdog event file as YYMMDD_HHMM_NN.wdl.
//
GetLocalTime(&Time);
for (Retry = 1; Retry < ER_WD_MAX_RETRY; Retry++) { swprintf(FileName, L"%s\\%2.2d%2.2d%2.2d_%2.2d%2.2d_%2.2d.wdl", DirName, Time.wYear % 100, Time.wMonth, Time.wDay, Time.wHour, Time.wMinute, Retry);
if ((GetFileAttributes(FileName) == (DWORD)-1) && (GetLastError() == ERROR_FILE_NOT_FOUND)) { break; } }
//
// If we failed to create a suitable file name just fail.
//
if (Retry == ER_WD_MAX_RETRY) { return FALSE; }
return TRUE; }
USHORT GenerateSignature( OUT PER_WD_PCI_ID PciId, OUT PER_WD_DRIVER_INFO DriverInfo )
/*++
Routine Description:
This routine generates unique failure signature for given PCI ID and driver data.
Arguments:
PciId - Points to PCI ID info.
DriverInfo - Points to driver version info.
Return Value:
Failure signature.
--*/
{ USHORT Signature; PUSHORT DataPtr; LONG Count; LONG MaxCount;
Signature = 0;
if ((NULL == PciId) || (NULL == DriverInfo)) { return Signature; }
//
// Build word CRC checksum for PciId.
//
MaxCount = sizeof (ER_WD_PCI_ID) / sizeof (USHORT); DataPtr = (PUSHORT)PciId;
for (Count = 0; Count < MaxCount; Count++) { Signature ^= *DataPtr; DataPtr++; }
//
// Check for odd byte.
//
if (sizeof (ER_WD_PCI_ID) % sizeof (USHORT)) { Signature ^= *(PUCHAR)DataPtr; }
//
// Now append DriverInfo.
//
MaxCount = sizeof (ER_WD_DRIVER_INFO) / sizeof (USHORT); DataPtr = (PUSHORT)DriverInfo;
for (Count = 0; Count < MaxCount; Count++) { Signature ^= *DataPtr; DataPtr++; }
//
// Check for odd byte.
//
if (sizeof (ER_WD_DRIVER_INFO) % sizeof (USHORT)) { Signature ^= *(PUCHAR)DataPtr; }
return Signature; }
VOID GetDriverInfo( IN HKEY Key, IN OPTIONAL PWCHAR Extension, OUT PER_WD_DRIVER_INFO DriverInfo )
/*++
Routine Description:
This routine collects driver's version info.
Arguments:
Key - Watchdog open key (device specific).
Extension - Driver file name extension if one should be appended.
DriverInfo - Storage for driver version info.
Return Value:
--*/
{ PVOID VersionBuffer; PVOID VersionValue; LONG WinStatus; DWORD Type; DWORD Handle; DWORD RegLength; ULONG Index; USHORT CodePage; UINT Length;
if (NULL == DriverInfo) { return; }
ZeroMemory(DriverInfo, sizeof (ER_WD_DRIVER_INFO));
//
// Get driver file name from registry.
//
RegLength = MAX_PATH; WinStatus = RegQueryValueEx(Key, L"DriverName", NULL, &Type, (LPBYTE)DriverInfo->DriverName, &RegLength);
if (ERROR_SUCCESS != WinStatus) { swprintf(DriverInfo->DriverName, L"%s", L"Unknown"); return; }
if (Extension) { if ((wcslen(DriverInfo->DriverName) <= wcslen(Extension)) || wcscmp(DriverInfo->DriverName + wcslen(DriverInfo->DriverName) - wcslen(Extension), Extension)) { wcscat(DriverInfo->DriverName, Extension); } }
Length = GetFileVersionInfoSize(DriverInfo->DriverName, &Handle);
if (Length) { VersionBuffer = malloc(Length);
if (NULL != VersionBuffer) { if (GetFileVersionInfo(DriverInfo->DriverName, Handle, Length, VersionBuffer)) { //
// Get fixed file info.
//
if (VerQueryValue(VersionBuffer, L"\\", &VersionValue, &Length)) { CopyMemory(&(DriverInfo->FixedFileInfo), VersionValue, min(Length, sizeof (VS_FIXEDFILEINFO))); }
//
// Try to locate English code page.
//
CodePage = 0;
if (VerQueryValue(VersionBuffer, L"\\VarFileInfo\\Translation", &VersionValue, &Length)) { for (Index = 0; Index < Length / sizeof (ER_WD_LANG_AND_CODE_PAGE); Index++) { if (((PER_WD_LANG_AND_CODE_PAGE)VersionValue + Index)->Language == ER_WD_LANG_ENGLISH) { CodePage = ((PER_WD_LANG_AND_CODE_PAGE)VersionValue + Index)->CodePage; break; } } }
if (CodePage) { WCHAR ValueName[ER_WD_MAX_NAME_LENGTH + 1]; PWCHAR Destination[] = { DriverInfo->Comments, DriverInfo->CompanyName, DriverInfo->FileDescription, DriverInfo->FileVersion, DriverInfo->InternalName, DriverInfo->LegalCopyright, DriverInfo->LegalTrademarks, DriverInfo->OriginalFilename, DriverInfo->PrivateBuild, DriverInfo->ProductName, DriverInfo->ProductVersion, DriverInfo->SpecialBuild, NULL }; PWCHAR Source[] = { L"Comments", L"CompanyName", L"FileDescription", L"FileVersion", L"InternalName", L"LegalCopyright", L"LegalTrademarks", L"OriginalFilename", L"PrivateBuild", L"ProductName", L"ProductVersion", L"SpecialBuild", NULL };
//
// Read version properties.
//
for (Index = 0; Source[Index] && Destination[Index]; Index++) { swprintf(ValueName, L"\\StringFileInfo\\%04X%04X\\%s", ER_WD_LANG_ENGLISH, CodePage, Source[Index]);
if (VerQueryValue(VersionBuffer, ValueName, &VersionValue, &Length)) { CopyMemory(Destination[Index], VersionValue, min(Length * sizeof (WCHAR), ER_WD_MAX_FILE_INFO_LENGTH * sizeof (WCHAR))); } } } }
free(VersionBuffer); } } }
UCHAR GetFlags( IN HKEY Key )
/*++
Routine Description:
This routine returns error signature flags based on registry values stored by watchdog.
Arguments:
Key - Watchdog open key (device specific).
Return Value:
--*/
{ UCHAR Flags; LONG WinStatus; DWORD Type; DWORD Value; DWORD Length;
Flags = 0;
//
// Get watchdog values from registry.
//
Length = sizeof (DWORD); WinStatus = RegQueryValueEx(Key, L"DisableBugcheck", NULL, &Type, (LPBYTE)&Value, &Length);
if ((ERROR_SUCCESS == WinStatus) && Value) { Flags |= ER_WD_DISABLE_BUGCHECK_FLAG; }
Length = sizeof (DWORD); WinStatus = RegQueryValueEx(Key, L"DebuggerNotPresent", NULL, &Type, (LPBYTE)&Value, &Length);
if ((ERROR_SUCCESS == WinStatus) && Value) { Flags |= ER_WD_DEBUGGER_NOT_PRESENT_FLAG; }
Length = sizeof (DWORD); WinStatus = RegQueryValueEx(Key, L"BugcheckTriggered", NULL, &Type, (LPBYTE)&Value, &Length);
if ((ERROR_SUCCESS == WinStatus) && Value) { Flags |= ER_WD_BUGCHECK_TRIGGERED_FLAG; }
return Flags; }
VOID GetPciId( IN HKEY Key, OUT PER_WD_PCI_ID PciId )
/*++
Routine Description:
This routine collects PCI ID info.
Arguments:
Key - Watchdog open key (device specific).
PciId - Storage for PCI ID info.
Return Value:
--*/
{ PWCHAR HardwareId; PWCHAR Token; PWCHAR EndPointer; LONG WinStatus; DWORD Type; DWORD Length;
if (NULL == PciId) { return; }
ZeroMemory(PciId, sizeof (ER_WD_PCI_ID));
//
// HardwareId is a MULTI_SZ - we need a bug buffer.
//
HardwareId = (PWCHAR)malloc(ER_WD_MAX_DATA_SIZE);
if (NULL == HardwareId) { return; }
//
// Get HardwareId string from registry.
//
Length = ER_WD_MAX_DATA_SIZE; WinStatus = RegQueryValueEx(Key, L"HardwareId", NULL, &Type, (LPBYTE)HardwareId, &Length);
if (ERROR_SUCCESS != WinStatus) { free(HardwareId); return; }
//
// Make sure HardwareId is in uppercase.
//
_wcsupr(HardwareId);
//
// Get VendorId.
//
Token = wcsstr(HardwareId, L"VEN_");
if (NULL != Token) { PciId->VendorId = (USHORT)wcstoul(Token + 4, &EndPointer, 16); }
//
// Get DeviceId.
//
Token = wcsstr(HardwareId, L"DEV_");
if (NULL != Token) { PciId->DeviceId = (USHORT)wcstoul(Token + 4, &EndPointer, 16); }
//
// Get Revision.
//
Token = wcsstr(HardwareId, L"REV_");
if (NULL != Token) { PciId->Revision = (UCHAR)wcstoul(Token + 4, &EndPointer, 16); }
//
// Get SubsystemId.
//
Token = wcsstr(HardwareId, L"SUBSYS_");
if (NULL != Token) { PciId->SubsystemId = wcstoul(Token + 7, &EndPointer, 16); }
free(HardwareId); }
BOOL SaveWatchdogEventData( IN HANDLE FileHandle, IN HKEY Key, IN PER_WD_DRIVER_INFO DriverInfo )
/*++
Routine Description:
This routine transfers watchdog event data from registry to the watchdog event report file.
Arguments:
FileHandle - Handle of open watchdog event report file.
Key - Watchdog open key (device specific).
Return Value:
TRUE if successful, FALSE otherwise.
--*/
{ LONG WinStatus; DWORD Index; DWORD NameLength; DWORD DataSize; DWORD ReturnedSize; DWORD Type; WCHAR Name[ER_WD_MAX_NAME_LENGTH + 1]; WCHAR DwordBuffer[20]; PBYTE Data; BOOL Status = TRUE;
ASSERT(INVALID_HANDLE_VALUE != FileHandle);
Data = (PBYTE)malloc(ER_WD_MAX_DATA_SIZE); if (NULL == Data) { return FALSE; }
//
// Pull watchdog data from registry and write it to report.
//
for (Index = 0;; Index++) { //
// Read watchdog registry value.
//
NameLength = ER_WD_MAX_NAME_LENGTH; DataSize = ER_WD_MAX_DATA_SIZE;
WinStatus = RegEnumValue(Key, Index, Name, &NameLength, NULL, &Type, Data, &DataSize);
if (ERROR_NO_MORE_ITEMS == WinStatus) { break; }
if (ERROR_SUCCESS != WinStatus) { continue; }
//
// Pick up strings and dwords only.
//
if ((REG_EXPAND_SZ == Type) || (REG_SZ == Type) || (REG_MULTI_SZ == Type) || (REG_DWORD == Type)) { //
// Write registry entry to watchdog event file.
//
Status = WriteWatchdogEventFile(FileHandle, Name); if (TRUE != Status) { break; }
Status = WriteWatchdogEventFile(FileHandle, L": "); if (TRUE != Status) { break; }
if (REG_DWORD == Type) { swprintf(DwordBuffer, L"%u", *(PULONG)Data); Status = WriteWatchdogEventFile(FileHandle, DwordBuffer); } else { Status = WriteWatchdogEventFile(FileHandle, (PWSTR)Data); }
if (TRUE != Status) { break; }
Status = WriteWatchdogEventFile(FileHandle, L"\r\n"); if (TRUE != Status) { break; } } }
//
// Write driver info to report.
//
if (NULL != DriverInfo) { if (TRUE == Status) { swprintf((PWCHAR)Data, L"DriverFixedFileInfo: %08X %08X %08X %08X %08X %08X %08X %08X %08X %08X %08X %08X %08X\r\n", DriverInfo->FixedFileInfo.dwSignature, DriverInfo->FixedFileInfo.dwStrucVersion, DriverInfo->FixedFileInfo.dwFileVersionMS, DriverInfo->FixedFileInfo.dwFileVersionLS, DriverInfo->FixedFileInfo.dwProductVersionMS, DriverInfo->FixedFileInfo.dwProductVersionLS, DriverInfo->FixedFileInfo.dwFileFlagsMask, DriverInfo->FixedFileInfo.dwFileFlags, DriverInfo->FixedFileInfo.dwFileOS, DriverInfo->FixedFileInfo.dwFileType, DriverInfo->FixedFileInfo.dwFileSubtype, DriverInfo->FixedFileInfo.dwFileDateMS, DriverInfo->FixedFileInfo.dwFileDateLS);
Status = WriteWatchdogEventFile(FileHandle, (PWCHAR)Data); }
if ((TRUE == Status) && DriverInfo->Comments[0]) { swprintf((PWCHAR)Data, L"DriverComments: %s\r\n", DriverInfo->Comments); Status = WriteWatchdogEventFile(FileHandle, (PWCHAR)Data); }
if ((TRUE == Status) && DriverInfo->CompanyName[0]) { swprintf((PWCHAR)Data, L"DriverCompanyName: %s\r\n", DriverInfo->CompanyName); Status = WriteWatchdogEventFile(FileHandle, (PWCHAR)Data); }
if ((TRUE == Status) && DriverInfo->FileDescription[0]) { swprintf((PWCHAR)Data, L"DriverFileDescription: %s\r\n", DriverInfo->FileDescription); Status = WriteWatchdogEventFile(FileHandle, (PWCHAR)Data); }
if ((TRUE == Status) && DriverInfo->FileVersion[0]) { swprintf((PWCHAR)Data, L"DriverFileVersion: %s\r\n", DriverInfo->FileVersion); Status = WriteWatchdogEventFile(FileHandle, (PWCHAR)Data); }
if ((TRUE == Status) && DriverInfo->InternalName[0]) { swprintf((PWCHAR)Data, L"DriverInternalName: %s\r\n", DriverInfo->InternalName); Status = WriteWatchdogEventFile(FileHandle, (PWCHAR)Data); }
if ((TRUE == Status) && DriverInfo->LegalCopyright[0]) { swprintf((PWCHAR)Data, L"DriverLegalCopyright: %s\r\n", DriverInfo->LegalCopyright); Status = WriteWatchdogEventFile(FileHandle, (PWCHAR)Data); }
if ((TRUE == Status) && DriverInfo->LegalTrademarks[0]) { swprintf((PWCHAR)Data, L"DriverLegalTrademarks: %s\r\n", DriverInfo->LegalTrademarks); Status = WriteWatchdogEventFile(FileHandle, (PWCHAR)Data); }
if ((TRUE == Status) && DriverInfo->OriginalFilename[0]) { swprintf((PWCHAR)Data, L"DriverOriginalFilename: %s\r\n", DriverInfo->OriginalFilename); Status = WriteWatchdogEventFile(FileHandle, (PWCHAR)Data); }
if ((TRUE == Status) && DriverInfo->PrivateBuild[0]) { swprintf((PWCHAR)Data, L"DriverPrivateBuild: %s\r\n", DriverInfo->PrivateBuild); Status = WriteWatchdogEventFile(FileHandle, (PWCHAR)Data); }
if ((TRUE == Status) && DriverInfo->ProductName[0]) { swprintf((PWCHAR)Data, L"DriverProductName: %s\r\n", DriverInfo->ProductName); Status = WriteWatchdogEventFile(FileHandle, (PWCHAR)Data); }
if ((TRUE == Status) && DriverInfo->ProductVersion[0]) { swprintf((PWCHAR)Data, L"DriverProductVersion: %s\r\n", DriverInfo->ProductVersion); Status = WriteWatchdogEventFile(FileHandle, (PWCHAR)Data); }
if ((TRUE == Status) && DriverInfo->SpecialBuild[0]) { swprintf((PWCHAR)Data, L"DriverSpecialBuild: %s\r\n", DriverInfo->SpecialBuild); Status = WriteWatchdogEventFile(FileHandle, (PWCHAR)Data); } }
if (NULL != Data) { free(Data); Data = NULL; }
return Status; }
BOOL WatchdogEventHandler( IN BOOL NotifyPcHealth )
/*++
Routine Description:
This is the boot time routine to handle pending watchdog events.
Arguments:
NotifyPcHealth - TRUE if we should report event to PC Health, FALSE otherwise.
Return Value:
TRUE if watchdog event(s) found and reported to PC Health, FALSE otherwise.
--*/
{ HKEY Key; UCHAR Flags; ULONG WinStatus; ULONG Type; ULONG Length; ULONG Shutdown; ULONG EventFlag; ULONG Index; ULONG FileVersionMS; ULONG FileVersionLS; USHORT Signature; SEventInfoW EventInfo; HANDLE FileHandle; WCHAR WatchdogReport[MAX_PATH]; WCHAR Stage1Url[ER_WD_MAX_URL_LENGTH + 1]; WCHAR Stage2Url[ER_WD_MAX_URL_LENGTH + 1]; WCHAR CorpPath[MAX_PATH]; PWCHAR MessageBuffer; PWCHAR DescriptionBuffer; PWCHAR DeviceDescription; PWCHAR FinalReport; PWCHAR DriverName; PWCHAR String000; PWCHAR String001; PWCHAR String002; PWCHAR String003; PWCHAR String004; PWCHAR String005; BOOL LogStatus; BOOL ReturnStatus; HINSTANCE Instance; PER_WD_DRIVER_INFO DriverInfo; ER_WD_PCI_ID PciId;
MessageBuffer = NULL; DescriptionBuffer = NULL; DeviceDescription = NULL; FinalReport = NULL; String000 = NULL; String001 = NULL; String002 = NULL; String003 = NULL; String004 = NULL; String005 = NULL; ReturnStatus = FALSE; Instance = (HINSTANCE)GetModuleHandle(NULL); DriverInfo = NULL; DriverName = NULL;
//
// Check if Watchdog\Display key present.
// Note: Key not present = dirty shutdown but no watchdog event = we don't care.
//
WinStatus = RegOpenKey(HKEY_LOCAL_MACHINE, SUBKEY_WATCHDOG_DISPLAY, &Key);
if (ERROR_SUCCESS == WinStatus) { EventFlag = 0;
//
// Check for clean shutdown indicator.
//
// TODO: Use NtQueryLastShutdownType() once implemented.
//
Length = sizeof (Shutdown); WinStatus = RegQueryValueEx(Key, L"Shutdown", NULL, &Type, (LPBYTE)&Shutdown, &Length);
if (ERROR_SUCCESS != WinStatus) { //
// Value not there - assume dirty shutdown.
//
Shutdown = 0; }
//
// If dirty shutdown check if watchdog display event captured.
//
if (!Shutdown) { Length = sizeof (EventFlag); WinStatus = RegQueryValueEx(Key, L"EventFlag", NULL, &Type, (LPBYTE)&EventFlag, &Length);
if (ERROR_SUCCESS != WinStatus) { //
// Value not there - watchdog display event not captured.
//
EventFlag = 0; } }
if (EventFlag) { //
// Report watchdog event to PC Health if requested.
//
if (NotifyPcHealth) { //
// Allocate storage for localized strings.
//
String000 = (PWCHAR)malloc(ER_WD_MAX_STRING); String001 = (PWCHAR)malloc(ER_WD_MAX_STRING); String002 = (PWCHAR)malloc(ER_WD_MAX_STRING); String003 = (PWCHAR)malloc(ER_WD_MAX_STRING); String004 = (PWCHAR)malloc(ER_WD_MAX_STRING); String005 = (PWCHAR)malloc(ER_WD_MAX_STRING);
//
// Load localized strings from resources.
//
// Note: It's OK to pass NULL so we don't have to validate buffers.
//
LoadString(Instance, IDS_000, String000, ER_WD_MAX_STRING); LoadString(Instance, IDS_001, String001, ER_WD_MAX_STRING); LoadString(Instance, IDS_002, String002, ER_WD_MAX_STRING); LoadString(Instance, IDS_003, String003, ER_WD_MAX_STRING); LoadString(Instance, IDS_004, String004, ER_WD_MAX_STRING); LoadString(Instance, IDS_005, String005, ER_WD_MAX_STRING);
//
// Allocate and get DriverInfo data.
//
DriverInfo = (PER_WD_DRIVER_INFO)malloc(sizeof (ER_WD_DRIVER_INFO));
if (NULL != DriverInfo) { GetDriverInfo(Key, L".dll", DriverInfo); }
//
// Get PCI ID info.
//
GetPciId(Key, &PciId);
//
// Get watchdog event flags.
//
Flags = GetFlags(Key);
//
// Generate event signature.
//
Signature = GenerateSignature(&PciId, DriverInfo);
//
// Create watchdog report file.
//
LogStatus = CreateWatchdogEventFileName(WatchdogReport);
if (TRUE == LogStatus) { FileHandle = CreateWatchdogEventFile(WatchdogReport);
if (INVALID_HANDLE_VALUE == FileHandle) { LogStatus = FALSE; } } else { FileHandle = INVALID_HANDLE_VALUE; }
if (TRUE == LogStatus) { LogStatus = WriteWatchdogEventFile( FileHandle, L"\r\n//\r\n" L"// The driver for the display device got stuck in an infinite loop. This\r\n" L"// usually indicates a problem with the device itself or with the device\r\n" L"// driver programming the hardware incorrectly. Please check with your\r\n" L"// display device vendor for any driver updates.\r\n" L"//\r\n\r\n"); }
if (TRUE == LogStatus) { LogStatus = SaveWatchdogEventData(FileHandle, Key, DriverInfo); }
if (INVALID_HANDLE_VALUE != FileHandle) { CloseHandle(FileHandle); }
FinalReport = (TRUE == LogStatus) ? WatchdogReport : NULL;
//
// Get device description.
//
DescriptionBuffer = NULL; DeviceDescription = NULL; Length = 0;
WinStatus = RegQueryValueEx(Key, L"DeviceDescription", NULL, &Type, NULL, &Length);
if (ERROR_SUCCESS == WinStatus) { DescriptionBuffer = (PWCHAR)malloc(Length);
if (NULL != DescriptionBuffer) { WinStatus = RegQueryValueEx(Key, L"DeviceDescription", NULL, &Type, (LPBYTE)DescriptionBuffer, &Length); } else { Length = 0; } }
if ((ERROR_SUCCESS == WinStatus) && (0 != Length)) { DeviceDescription = DescriptionBuffer; } else { DeviceDescription = String004; Length = (ER_WD_MAX_STRING + 1) * sizeof (WCHAR); }
Length += 2 * ER_WD_MAX_STRING * sizeof (WCHAR);
MessageBuffer = (PWCHAR)malloc(Length);
if (NULL != MessageBuffer) { swprintf(MessageBuffer, L"%s%s%s", String003, DeviceDescription, String005); }
//
// Create URLs and corporate path.
//
if (DriverInfo) { DriverName = DriverInfo->DriverName; FileVersionMS = DriverInfo->FixedFileInfo.dwFileVersionMS; FileVersionLS = DriverInfo->FixedFileInfo.dwFileVersionLS; } else { DriverName = L"Unknown"; FileVersionMS = 0; FileVersionLS = 0; }
swprintf(Stage1Url, L"\r\nStage1URL=/StageOne/Drivers_Display/%04X%04X%02X%08X/%s/%u_%u_%u_%u/%04X%02X%02X", PciId.VendorId, PciId.DeviceId, PciId.Revision, PciId.SubsystemId, DriverName, (USHORT)(FileVersionMS >> 16), (USHORT)(FileVersionMS & 0xffff), (USHORT)(FileVersionLS >> 16), (USHORT)(FileVersionLS & 0xffff), Signature, Flags, 0xea);
swprintf(Stage2Url, L"\r\nStage2URL=/dw/StageTwo.asp?szAppName=Drivers.Display&szAppVer=%04X%04X%02X%08X&" L"szModName=%s&szModVer=%u.%u.%u.%u&Offset=%04X%02X%02X", PciId.VendorId, PciId.DeviceId, PciId.Revision, PciId.SubsystemId, DriverName, (USHORT)(FileVersionMS >> 16), (USHORT)(FileVersionMS & 0xffff), (USHORT)(FileVersionLS >> 16), (USHORT)(FileVersionLS & 0xffff), Signature, Flags, 0xea);
swprintf(CorpPath, L"\\Drivers.Display\\%04X%04X%02X%08X\\%s\\%u.%u.%u.%u\\%04X%02X%02X", PciId.VendorId, PciId.DeviceId, PciId.Revision, PciId.SubsystemId, DriverName, (USHORT)(FileVersionMS >> 16), (USHORT)(FileVersionMS & 0xffff), (USHORT)(FileVersionLS >> 16), (USHORT)(FileVersionLS & 0xffff), Signature, Flags, 0xea);
//
// Dots are not allowed in stage1 URL, replace with _ then append .htm.
//
for (Index = 0; Stage1Url[Index] != UNICODE_NULL; Index++) { if (Stage1Url[Index] == L'.') { Stage1Url[Index] = L'_'; } }
wcscat(Stage1Url, L".htm");
//
// Fill in event record.
//
// TODO: Add minidump to watchdog event reports, but only when it contains stack trace
// from the spinning thread. This is for SKUs < Server, since we're not bugchecking
// for Server and above. We should also look into snapshot report, this can be good
// piece of data to send along.
//
ZeroMemory(&EventInfo, sizeof (EventInfo));
EventInfo.cbSEI = sizeof (EventInfo); EventInfo.wszEventName = L"Thread Stuck in Device Driver"; EventInfo.wszErrMsg = String002; EventInfo.wszHdr = String001; EventInfo.wszTitle = String000; EventInfo.wszStage1 = Stage1Url; EventInfo.wszStage2 = Stage2Url; EventInfo.wszFileList = FinalReport; EventInfo.wszEventSrc = NULL; EventInfo.wszCorpPath = CorpPath; EventInfo.wszPlea = MessageBuffer; EventInfo.wszSendBtn = NULL; EventInfo.wszNoSendBtn = NULL; EventInfo.fUseLitePlea = FALSE; EventInfo.fUseIEForURLs = TRUE; EventInfo.fNoBucketLogs = FALSE; EventInfo.fNoDefCabLimit = FALSE;
//
// Notify PC Health.
//
PCHPFNotifyFault(eetUseEventInfo, NULL, &EventInfo);
//
// Clean up buffers.
//
if (NULL != DescriptionBuffer) { free(DescriptionBuffer); DescriptionBuffer = NULL; }
if (NULL != MessageBuffer) { free(MessageBuffer); MessageBuffer = NULL; }
if (NULL != String000) { free(String000); String000 = NULL; }
if (NULL != String001) { free(String001); String001 = NULL; }
if (NULL != String002) { free(String002); String002 = NULL; }
if (NULL != String003) { free(String003); String003 = NULL; }
if (NULL != String004) { free(String004); String004 = NULL; }
if (NULL != String005) { free(String005); String005 = NULL; }
if (NULL != DriverInfo) { free(DriverInfo); DriverInfo = NULL; }
//
// We trapped watchdog event and notified PC Health, set ReturnStatus to reflect this.
//
ReturnStatus = TRUE; } }
//
// Knock down watchdog's EventFlag. We do this after registering our
// event with PC Health.
//
RegDeleteValue(Key, L"EventFlag"); RegCloseKey(Key); }
//
// TODO: Handle additional device classes here when supported.
//
return ReturnStatus; }
BOOL WriteWatchdogEventFile( IN HANDLE FileHandle, IN PWSTR String )
/*++
Routine Description:
This routine writes a string to watchdog event report file.
Arguments:
FileHandle - Handle of open watchdog event report file.
String - Points to the string to write.
Return Value:
TRUE if successful, FALSE otherwise.
--*/
{ DWORD Size; DWORD ReturnedSize; PCHAR MultiByte; BOOL Status;
ASSERT(INVALID_HANDLE_VALUE != FileHandle); ASSERT(NULL != String);
//
// Get buffer size for translated string.
//
Size = WideCharToMultiByte(CP_ACP, 0, String, -1, NULL, 0, NULL, NULL);
if (Size <= 1) { return TRUE; }
MultiByte = (PCHAR)malloc(Size);
if (NULL == MultiByte) { return FALSE; }
Size = WideCharToMultiByte(CP_ACP, 0, String, -1, MultiByte, Size, NULL, NULL);
if (Size > 0) { Status = WriteFile(FileHandle, MultiByte, Size - 1, &ReturnedSize, NULL); } else { ASSERT(FALSE); Status = FALSE; }
free(MultiByte); return Status; }
|