windows-nt/Source/XPSP1/NT/sdktools/debuggers/savedump/erwatch.cpp
2020-09-26 16:20:57 +08:00

1488 lines
38 KiB
C++

/*++
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;
}