746 lines
19 KiB
C
746 lines
19 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1999 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
triage.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This module contains the Phase 0 code to triage bugchecks and
|
|||
|
automatically enable various system tracing components until the
|
|||
|
guilty party is found.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Landy Wang 13-Jan-1999
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "mi.h"
|
|||
|
#include "ntiodump.h"
|
|||
|
|
|||
|
#ifdef ALLOC_PRAGMA
|
|||
|
#pragma alloc_text(INIT,MiTriageSystem)
|
|||
|
#pragma alloc_text(INIT,MiTriageAddDrivers)
|
|||
|
#endif
|
|||
|
|
|||
|
//
|
|||
|
// Always update this macro when adding triage support for additional bugchecks.
|
|||
|
//
|
|||
|
|
|||
|
#define MI_CAN_TRIAGE_BUGCHECK(BugCheckCode) \
|
|||
|
((BugCheckCode) == PROCESS_HAS_LOCKED_PAGES || \
|
|||
|
(BugCheckCode) == NO_MORE_SYSTEM_PTES || \
|
|||
|
(BugCheckCode) == BAD_POOL_HEADER || \
|
|||
|
(BugCheckCode) == DRIVER_CORRUPTED_SYSPTES || \
|
|||
|
(BugCheckCode) == DRIVER_CORRUPTED_EXPOOL || \
|
|||
|
(BugCheckCode) == DRIVER_CORRUPTED_MMPOOL)
|
|||
|
|
|||
|
//
|
|||
|
// These are bugchecks that were presumably triggered by either autotriage or
|
|||
|
// the admin's registry settings - so don't apply any new rules and in addition,
|
|||
|
// keep the old ones unaltered so it can reproduce.
|
|||
|
//
|
|||
|
|
|||
|
#define MI_HOLD_TRIAGE_BUGCHECK(BugCheckCode) \
|
|||
|
((BugCheckCode) == DRIVER_USED_EXCESSIVE_PTES || \
|
|||
|
(BugCheckCode) == DRIVER_LEFT_LOCKED_PAGES_IN_PROCESS || \
|
|||
|
(BugCheckCode) == PAGE_FAULT_IN_FREED_SPECIAL_POOL || \
|
|||
|
(BugCheckCode) == DRIVER_PAGE_FAULT_IN_FREED_SPECIAL_POOL || \
|
|||
|
(BugCheckCode) == PAGE_FAULT_BEYOND_END_OF_ALLOCATION || \
|
|||
|
(BugCheckCode) == DRIVER_PAGE_FAULT_BEYOND_END_OF_ALLOCATION || \
|
|||
|
(BugCheckCode) == DRIVER_CAUGHT_MODIFYING_FREED_POOL || \
|
|||
|
(BugCheckCode) == SYSTEM_PTE_MISUSE)
|
|||
|
|
|||
|
#define MI_TRACKING_LOCKED_PAGES 0x00000001
|
|||
|
#define MI_TRACKING_PTES 0x00000002
|
|||
|
#define MI_PROTECT_FREED_NONPAGED_POOL 0x00000004
|
|||
|
#define MI_VERIFYING_PRENT5_DRIVERS 0x00000008
|
|||
|
#define MI_KEEPING_PREVIOUS_SETTINGS 0x00000010
|
|||
|
|
|||
|
#ifdef ALLOC_DATA_PRAGMA
|
|||
|
#pragma const_seg("INITCONST")
|
|||
|
#pragma data_seg("INITDATA")
|
|||
|
#endif
|
|||
|
const PCHAR MiTriageActionStrings[] = {
|
|||
|
"Locked pages tracking",
|
|||
|
"System PTE usage tracking",
|
|||
|
"Making accesses to freed nonpaged pool cause bugchecks",
|
|||
|
"Driver Verifying Pre-Windows 2000 built drivers",
|
|||
|
"Keeping previous autotriage settings"
|
|||
|
};
|
|||
|
|
|||
|
#if DBG
|
|||
|
ULONG MiTriageDebug = 0;
|
|||
|
BOOLEAN MiTriageRegardless = FALSE;
|
|||
|
#endif
|
|||
|
|
|||
|
#ifdef ALLOC_DATA_PRAGMA
|
|||
|
#pragma const_seg()
|
|||
|
#pragma data_seg()
|
|||
|
#endif
|
|||
|
|
|||
|
//
|
|||
|
// N.B. The debugger references this.
|
|||
|
//
|
|||
|
|
|||
|
ULONG MmTriageActionTaken;
|
|||
|
|
|||
|
//
|
|||
|
// The Version number must be incremented whenever the MI_TRIAGE_STORAGE
|
|||
|
// structure is changed. This enables usermode programs to decode the Mm
|
|||
|
// portions of triage dumps regardless of which kernel revision created the
|
|||
|
// dump.
|
|||
|
//
|
|||
|
|
|||
|
typedef struct _MI_TRIAGE_STORAGE {
|
|||
|
ULONG Version;
|
|||
|
ULONG Size;
|
|||
|
ULONG MmSpecialPoolTag;
|
|||
|
ULONG MiTriageActionTaken;
|
|||
|
|
|||
|
ULONG MmVerifyDriverLevel;
|
|||
|
ULONG KernelVerifier;
|
|||
|
ULONG_PTR MmMaximumNonPagedPool;
|
|||
|
ULONG_PTR MmAllocatedNonPagedPool;
|
|||
|
|
|||
|
ULONG_PTR PagedPoolMaximum;
|
|||
|
ULONG_PTR PagedPoolAllocated;
|
|||
|
|
|||
|
ULONG_PTR CommittedPages;
|
|||
|
ULONG_PTR CommittedPagesPeak;
|
|||
|
ULONG_PTR CommitLimitMaximum;
|
|||
|
|
|||
|
} MI_TRIAGE_STORAGE, *PMI_TRIAGE_STORAGE;
|
|||
|
|
|||
|
PKLDR_DATA_TABLE_ENTRY
|
|||
|
TriageGetLoaderEntry (
|
|||
|
IN PVOID TriageDumpBlock,
|
|||
|
IN ULONG ModuleIndex
|
|||
|
);
|
|||
|
|
|||
|
LOGICAL
|
|||
|
TriageActUpon(
|
|||
|
IN PVOID TriageDumpBlock
|
|||
|
);
|
|||
|
|
|||
|
PVOID
|
|||
|
TriageGetMmInformation (
|
|||
|
IN PVOID TriageDumpBlock
|
|||
|
);
|
|||
|
|
|||
|
|
|||
|
LOGICAL
|
|||
|
MiTriageSystem (
|
|||
|
IN PLOADER_PARAMETER_BLOCK LoaderBlock
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine takes the information from the last bugcheck (if any)
|
|||
|
and triages it. Various debugging options are then automatically
|
|||
|
enabled.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
LoaderBlock - Supplies a pointer to the system loader block.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
TRUE if triaging succeeded and options were enabled. FALSE otherwise.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PVOID TriageDumpBlock;
|
|||
|
ULONG_PTR BugCheckData[5];
|
|||
|
ULONG i;
|
|||
|
ULONG ModuleCount;
|
|||
|
NTSTATUS Status;
|
|||
|
PLIST_ENTRY NextEntry;
|
|||
|
PKLDR_DATA_TABLE_ENTRY DataTableEntry;
|
|||
|
PKLDR_DATA_TABLE_ENTRY DumpTableEntry;
|
|||
|
LOGICAL Matched;
|
|||
|
ULONG OldDrivers;
|
|||
|
ULONG OldDriversNotVerifying;
|
|||
|
PMI_TRIAGE_STORAGE TriageInformation;
|
|||
|
|
|||
|
if (LoaderBlock->Extension == NULL) {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
if (LoaderBlock->Extension->Size < sizeof (LOADER_PARAMETER_EXTENSION)) {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
TriageDumpBlock = LoaderBlock->Extension->TriageDumpBlock;
|
|||
|
|
|||
|
Status = TriageGetBugcheckData (TriageDumpBlock,
|
|||
|
(PULONG)&BugCheckData[0],
|
|||
|
(PUINT_PTR) &BugCheckData[1],
|
|||
|
(PUINT_PTR) &BugCheckData[2],
|
|||
|
(PUINT_PTR) &BugCheckData[3],
|
|||
|
(PUINT_PTR) &BugCheckData[4]);
|
|||
|
|
|||
|
if (!NT_SUCCESS (Status)) {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Always display at least the bugcheck data from the previous crash.
|
|||
|
//
|
|||
|
|
|||
|
DbgPrint ("MiTriageSystem: Previous bugcheck was %x %p %p %p %p\n",
|
|||
|
BugCheckData[0],
|
|||
|
BugCheckData[1],
|
|||
|
BugCheckData[2],
|
|||
|
BugCheckData[3],
|
|||
|
BugCheckData[4]);
|
|||
|
|
|||
|
if (TriageActUpon (TriageDumpBlock) == FALSE) {
|
|||
|
DbgPrint ("MiTriageSystem: Triage disabled in registry by administrator\n");
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
DbgPrint ("MiTriageSystem: Triage ENABLED in registry by administrator\n");
|
|||
|
|
|||
|
//
|
|||
|
// See if the previous bugcheck was one where action can be taken.
|
|||
|
// If not, bail now. If so, then march on and verify all the loaded
|
|||
|
// module checksums before actually taking action on the bugcheck.
|
|||
|
//
|
|||
|
|
|||
|
if (!MI_CAN_TRIAGE_BUGCHECK(BugCheckData[0])) {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
TriageInformation = (PMI_TRIAGE_STORAGE) TriageGetMmInformation (TriageDumpBlock);
|
|||
|
|
|||
|
if (TriageInformation == NULL) {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
Status = TriageGetDriverCount (TriageDumpBlock, &ModuleCount);
|
|||
|
|
|||
|
if (!NT_SUCCESS (Status)) {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Process module information from the triage dump.
|
|||
|
//
|
|||
|
|
|||
|
#if DBG
|
|||
|
if (MiTriageDebug & 0x1) {
|
|||
|
DbgPrint ("MiTriageSystem: printing active drivers from triage crash...\n");
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
OldDrivers = 0;
|
|||
|
OldDriversNotVerifying = 0;
|
|||
|
|
|||
|
for (i = 0; i < ModuleCount; i += 1) {
|
|||
|
|
|||
|
DumpTableEntry = TriageGetLoaderEntry (TriageDumpBlock, i);
|
|||
|
|
|||
|
if (DumpTableEntry != NULL) {
|
|||
|
|
|||
|
if ((DumpTableEntry->Flags & LDRP_ENTRY_NATIVE) == 0) {
|
|||
|
OldDrivers += 1;
|
|||
|
if ((DumpTableEntry->Flags & LDRP_IMAGE_VERIFYING) == 0) {
|
|||
|
|
|||
|
//
|
|||
|
// An NT3 or NT4 driver is in the system and was not
|
|||
|
// running under the verifier.
|
|||
|
//
|
|||
|
|
|||
|
OldDriversNotVerifying += 1;
|
|||
|
}
|
|||
|
}
|
|||
|
#if DBG
|
|||
|
if (MiTriageDebug & 0x1) {
|
|||
|
|
|||
|
DbgPrint (" %wZ: base = %p, size = %lx, flags = %lx\n",
|
|||
|
&DumpTableEntry->BaseDllName,
|
|||
|
DumpTableEntry->DllBase,
|
|||
|
DumpTableEntry->SizeOfImage,
|
|||
|
DumpTableEntry->Flags);
|
|||
|
}
|
|||
|
#endif
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Ensure that every driver that is currently loaded is identical to
|
|||
|
// the one in the triage dump before proceeding.
|
|||
|
//
|
|||
|
|
|||
|
NextEntry = LoaderBlock->LoadOrderListHead.Flink;
|
|||
|
|
|||
|
while (NextEntry != &LoaderBlock->LoadOrderListHead) {
|
|||
|
|
|||
|
DataTableEntry = CONTAINING_RECORD(NextEntry,
|
|||
|
KLDR_DATA_TABLE_ENTRY,
|
|||
|
InLoadOrderLinks);
|
|||
|
|
|||
|
Matched = FALSE;
|
|||
|
|
|||
|
for (i = 0; i < ModuleCount; i += 1) {
|
|||
|
|
|||
|
DumpTableEntry = TriageGetLoaderEntry (TriageDumpBlock, i);
|
|||
|
|
|||
|
if (DumpTableEntry != NULL) {
|
|||
|
|
|||
|
if (DataTableEntry->CheckSum == DumpTableEntry->CheckSum) {
|
|||
|
Matched = TRUE;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (Matched == FALSE) {
|
|||
|
DbgPrint ("Matching checksum for module %wZ not found in triage dump\n",
|
|||
|
&DataTableEntry->BaseDllName);
|
|||
|
|
|||
|
#if DBG
|
|||
|
if (MiTriageRegardless == FALSE)
|
|||
|
#endif
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
NextEntry = NextEntry->Flink;
|
|||
|
}
|
|||
|
|
|||
|
#if DBG
|
|||
|
if (MiTriageDebug & 0x1) {
|
|||
|
DbgPrint ("MiTriageSystem: OldDrivers = %u, without verification =%u\n",
|
|||
|
OldDrivers,
|
|||
|
OldDriversNotVerifying);
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
//
|
|||
|
// All boot loaded drivers matched, take action on the triage dump now.
|
|||
|
//
|
|||
|
|
|||
|
if (MI_HOLD_TRIAGE_BUGCHECK(BugCheckData[0])) {
|
|||
|
|
|||
|
//
|
|||
|
// The last bugcheck was presumably triggered by either autotriage or
|
|||
|
// the admin's registry settings - so don't apply any new rules
|
|||
|
// and in addition, keep the old ones unaltered so it can reproduce.
|
|||
|
//
|
|||
|
|
|||
|
MmTriageActionTaken = TriageInformation->MiTriageActionTaken;
|
|||
|
MmTriageActionTaken |= MI_KEEPING_PREVIOUS_SETTINGS;
|
|||
|
}
|
|||
|
else {
|
|||
|
|
|||
|
switch (BugCheckData[0]) {
|
|||
|
|
|||
|
case PROCESS_HAS_LOCKED_PAGES:
|
|||
|
|
|||
|
//
|
|||
|
// Turn on locked pages tracking so this turns into bugcheck
|
|||
|
// DRIVER_LEFT_LOCKED_PAGES_IN_PROCESS which shows the name
|
|||
|
// of the driver.
|
|||
|
//
|
|||
|
|
|||
|
MmTriageActionTaken |= MI_TRACKING_LOCKED_PAGES;
|
|||
|
break;
|
|||
|
|
|||
|
case DRIVER_CORRUPTED_SYSPTES:
|
|||
|
|
|||
|
//
|
|||
|
// Turn on PTE tracking to trigger a SYSTEM_PTE_MISUSE bugcheck.
|
|||
|
//
|
|||
|
|
|||
|
MmTriageActionTaken |= MI_TRACKING_PTES;
|
|||
|
break;
|
|||
|
|
|||
|
case NO_MORE_SYSTEM_PTES:
|
|||
|
|
|||
|
//
|
|||
|
// Turn on PTE tracking so the driver can be identified via a
|
|||
|
// DRIVER_USED_EXCESSIVE_PTES bugcheck.
|
|||
|
//
|
|||
|
|
|||
|
if (BugCheckData[1] == SystemPteSpace) {
|
|||
|
MmTriageActionTaken |= MI_TRACKING_PTES;
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
case BAD_POOL_HEADER:
|
|||
|
case DRIVER_CORRUPTED_EXPOOL:
|
|||
|
|
|||
|
//
|
|||
|
// Turn on the driver verifier and/or special pool.
|
|||
|
// Start by enabling it for every driver that isn't built for NT5.
|
|||
|
// Override any specified driver verifier options so that only
|
|||
|
// special pool is enabled to minimize the performance hit.
|
|||
|
//
|
|||
|
|
|||
|
if (OldDrivers != 0) {
|
|||
|
if (OldDriversNotVerifying != 0) {
|
|||
|
MmTriageActionTaken |= MI_VERIFYING_PRENT5_DRIVERS;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
case DRIVER_CORRUPTED_MMPOOL:
|
|||
|
|
|||
|
//
|
|||
|
// Protect freed nonpaged pool if the system had less than 128mb
|
|||
|
// of nonpaged pool anyway. This is to trigger a
|
|||
|
// DRIVER_CAUGHT_MODIFYING_FREED_POOL bugcheck.
|
|||
|
//
|
|||
|
|
|||
|
#define MB128 ((ULONG_PTR)0x80000000 >> PAGE_SHIFT)
|
|||
|
|
|||
|
if (TriageInformation->MmMaximumNonPagedPool < MB128) {
|
|||
|
MmTriageActionTaken |= MI_PROTECT_FREED_NONPAGED_POOL;
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
case IRQL_NOT_LESS_OR_EQUAL:
|
|||
|
case DRIVER_IRQL_NOT_LESS_OR_EQUAL:
|
|||
|
default:
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// For now always show if action was taken from the bugcheck
|
|||
|
// data from the crash. This print and the space for the print strings
|
|||
|
// will be enabled for checked builds only prior to shipping.
|
|||
|
//
|
|||
|
|
|||
|
if (MmTriageActionTaken != 0) {
|
|||
|
|
|||
|
if (MmTriageActionTaken & MI_TRACKING_LOCKED_PAGES) {
|
|||
|
MmTrackLockedPages = TRUE;
|
|||
|
}
|
|||
|
|
|||
|
if (MmTriageActionTaken & MI_TRACKING_PTES) {
|
|||
|
MmTrackPtes |= 0x1;
|
|||
|
}
|
|||
|
|
|||
|
if (MmTriageActionTaken & MI_VERIFYING_PRENT5_DRIVERS) {
|
|||
|
MmVerifyDriverLevel &= ~DRIVER_VERIFIER_FORCE_IRQL_CHECKING;
|
|||
|
MmVerifyDriverLevel |= DRIVER_VERIFIER_SPECIAL_POOLING;
|
|||
|
}
|
|||
|
|
|||
|
if (MmTriageActionTaken & MI_PROTECT_FREED_NONPAGED_POOL) {
|
|||
|
MmProtectFreedNonPagedPool = TRUE;
|
|||
|
}
|
|||
|
|
|||
|
DbgPrint ("MiTriageSystem: enabling options below to find who caused the last crash\n");
|
|||
|
|
|||
|
for (i = 0; i < 32; i += 1) {
|
|||
|
if (MmTriageActionTaken & (1 << i)) {
|
|||
|
DbgPrint (" %s\n", MiTriageActionStrings[i]);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
LOGICAL
|
|||
|
MiTriageAddDrivers (
|
|||
|
IN PLOADER_PARAMETER_BLOCK LoaderBlock
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine moves the names of any drivers that autotriage has determined
|
|||
|
need verifying from the LoaderBlock into pool.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
LoaderBlock - Supplies a pointer to the system loader block.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
TRUE if any drivers were added, FALSE if not.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
ULONG i;
|
|||
|
ULONG ModuleCount;
|
|||
|
NTSTATUS Status;
|
|||
|
PKLDR_DATA_TABLE_ENTRY DumpTableEntry;
|
|||
|
PVOID TriageDumpBlock;
|
|||
|
ULONG NameLength;
|
|||
|
LOGICAL Added;
|
|||
|
PMI_VERIFIER_DRIVER_ENTRY VerifierDriverEntry;
|
|||
|
|
|||
|
if ((MmTriageActionTaken & MI_VERIFYING_PRENT5_DRIVERS) == 0) {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
TriageDumpBlock = LoaderBlock->Extension->TriageDumpBlock;
|
|||
|
|
|||
|
Status = TriageGetDriverCount (TriageDumpBlock, &ModuleCount);
|
|||
|
|
|||
|
if (!NT_SUCCESS (Status)) {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
Added = FALSE;
|
|||
|
|
|||
|
for (i = 0; i < ModuleCount; i += 1) {
|
|||
|
|
|||
|
DumpTableEntry = TriageGetLoaderEntry (TriageDumpBlock, i);
|
|||
|
|
|||
|
if (DumpTableEntry == NULL) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
if (DumpTableEntry->Flags & LDRP_ENTRY_NATIVE) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
DbgPrint ("MiTriageAddDrivers: Marking %wZ for verification when it is loaded\n", &DumpTableEntry->BaseDllName);
|
|||
|
|
|||
|
NameLength = DumpTableEntry->BaseDllName.Length;
|
|||
|
|
|||
|
VerifierDriverEntry = (PMI_VERIFIER_DRIVER_ENTRY)ExAllocatePoolWithTag (
|
|||
|
NonPagedPool,
|
|||
|
sizeof (MI_VERIFIER_DRIVER_ENTRY) +
|
|||
|
NameLength,
|
|||
|
'dLmM');
|
|||
|
|
|||
|
if (VerifierDriverEntry == NULL) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
VerifierDriverEntry->Loads = 0;
|
|||
|
VerifierDriverEntry->Unloads = 0;
|
|||
|
VerifierDriverEntry->BaseName.Buffer = (PWSTR)((PCHAR)VerifierDriverEntry +
|
|||
|
sizeof (MI_VERIFIER_DRIVER_ENTRY));
|
|||
|
|
|||
|
VerifierDriverEntry->BaseName.Length = (USHORT)NameLength;
|
|||
|
VerifierDriverEntry->BaseName.MaximumLength = (USHORT)NameLength;
|
|||
|
|
|||
|
RtlCopyMemory (VerifierDriverEntry->BaseName.Buffer,
|
|||
|
DumpTableEntry->BaseDllName.Buffer,
|
|||
|
NameLength);
|
|||
|
|
|||
|
InsertHeadList (&MiSuspectDriverList, &VerifierDriverEntry->Links);
|
|||
|
Added = TRUE;
|
|||
|
}
|
|||
|
|
|||
|
return Added;
|
|||
|
}
|
|||
|
|
|||
|
#define MAX_UNLOADED_NAME_LENGTH 24
|
|||
|
|
|||
|
typedef struct _DUMP_UNLOADED_DRIVERS {
|
|||
|
UNICODE_STRING Name;
|
|||
|
WCHAR DriverName[MAX_UNLOADED_NAME_LENGTH / sizeof (WCHAR)];
|
|||
|
PVOID StartAddress;
|
|||
|
PVOID EndAddress;
|
|||
|
} DUMP_UNLOADED_DRIVERS, *PDUMP_UNLOADED_DRIVERS;
|
|||
|
|
|||
|
|
|||
|
ULONG
|
|||
|
MmSizeOfUnloadedDriverInformation (
|
|||
|
VOID
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine returns the size of the Mm-internal unloaded driver
|
|||
|
information that is stored in the triage dump when (if?) the system crashes.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Size of the Mm-internal unloaded driver information.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
if (MmUnloadedDrivers == NULL) {
|
|||
|
return sizeof (ULONG_PTR);
|
|||
|
}
|
|||
|
|
|||
|
return sizeof(ULONG_PTR) + MI_UNLOADED_DRIVERS * sizeof(DUMP_UNLOADED_DRIVERS);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
MmWriteUnloadedDriverInformation (
|
|||
|
IN PVOID Destination
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine stores the Mm-internal unloaded driver information into
|
|||
|
the triage dump.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
ULONG i;
|
|||
|
ULONG Index;
|
|||
|
PUNLOADED_DRIVERS Unloaded;
|
|||
|
PDUMP_UNLOADED_DRIVERS DumpUnloaded;
|
|||
|
|
|||
|
if (MmUnloadedDrivers == NULL) {
|
|||
|
*(PULONG)Destination = 0;
|
|||
|
}
|
|||
|
else {
|
|||
|
|
|||
|
DumpUnloaded = (PDUMP_UNLOADED_DRIVERS)((PULONG_PTR)Destination + 1);
|
|||
|
Unloaded = MmUnloadedDrivers;
|
|||
|
|
|||
|
//
|
|||
|
// Write the list with the most recently unloaded driver first to the
|
|||
|
// least recently unloaded driver last.
|
|||
|
//
|
|||
|
|
|||
|
Index = MmLastUnloadedDriver - 1;
|
|||
|
|
|||
|
for (i = 0; i < MI_UNLOADED_DRIVERS; i += 1) {
|
|||
|
|
|||
|
if (Index >= MI_UNLOADED_DRIVERS) {
|
|||
|
Index = MI_UNLOADED_DRIVERS - 1;
|
|||
|
}
|
|||
|
|
|||
|
Unloaded = &MmUnloadedDrivers[Index];
|
|||
|
|
|||
|
DumpUnloaded->Name = Unloaded->Name;
|
|||
|
|
|||
|
if (Unloaded->Name.Buffer == NULL) {
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
DumpUnloaded->StartAddress = Unloaded->StartAddress;
|
|||
|
DumpUnloaded->EndAddress = Unloaded->EndAddress;
|
|||
|
|
|||
|
if (DumpUnloaded->Name.Length > MAX_UNLOADED_NAME_LENGTH) {
|
|||
|
DumpUnloaded->Name.Length = MAX_UNLOADED_NAME_LENGTH;
|
|||
|
}
|
|||
|
|
|||
|
if (DumpUnloaded->Name.MaximumLength > MAX_UNLOADED_NAME_LENGTH) {
|
|||
|
DumpUnloaded->Name.MaximumLength = MAX_UNLOADED_NAME_LENGTH;
|
|||
|
}
|
|||
|
|
|||
|
DumpUnloaded->Name.Buffer = DumpUnloaded->DriverName;
|
|||
|
|
|||
|
RtlCopyMemory ((PVOID)DumpUnloaded->Name.Buffer,
|
|||
|
(PVOID)Unloaded->Name.Buffer,
|
|||
|
DumpUnloaded->Name.MaximumLength);
|
|||
|
|
|||
|
DumpUnloaded += 1;
|
|||
|
Index -= 1;
|
|||
|
}
|
|||
|
|
|||
|
*(PULONG)Destination = i;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
ULONG
|
|||
|
MmSizeOfTriageInformation (
|
|||
|
VOID
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine returns the size of the Mm-internal information that is
|
|||
|
stored in the triage dump when (if?) the system crashes.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Size of the Mm-internal triage information.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
return sizeof (MI_TRIAGE_STORAGE);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
MmWriteTriageInformation (
|
|||
|
IN PVOID Destination
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine stores the Mm-internal information into the triage dump.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
MI_TRIAGE_STORAGE TriageInformation;
|
|||
|
|
|||
|
TriageInformation.Version = 1;
|
|||
|
TriageInformation.Size = sizeof (MI_TRIAGE_STORAGE);
|
|||
|
|
|||
|
TriageInformation.MmSpecialPoolTag = MmSpecialPoolTag;
|
|||
|
TriageInformation.MiTriageActionTaken = MmTriageActionTaken;
|
|||
|
|
|||
|
TriageInformation.MmVerifyDriverLevel = MmVerifierData.Level;
|
|||
|
TriageInformation.KernelVerifier = KernelVerifier;
|
|||
|
|
|||
|
TriageInformation.MmMaximumNonPagedPool = MmMaximumNonPagedPoolInBytes >> PAGE_SHIFT;
|
|||
|
TriageInformation.MmAllocatedNonPagedPool = MmAllocatedNonPagedPool;
|
|||
|
|
|||
|
TriageInformation.PagedPoolMaximum = MmSizeOfPagedPoolInBytes >> PAGE_SHIFT;
|
|||
|
TriageInformation.PagedPoolAllocated = MmPagedPoolInfo.AllocatedPagedPool;
|
|||
|
|
|||
|
TriageInformation.CommittedPages = MmTotalCommittedPages;
|
|||
|
TriageInformation.CommittedPagesPeak = MmPeakCommitment;
|
|||
|
TriageInformation.CommitLimitMaximum = MmTotalCommitLimitMaximum;
|
|||
|
|
|||
|
RtlCopyMemory (Destination,
|
|||
|
(PVOID)&TriageInformation,
|
|||
|
sizeof (MI_TRIAGE_STORAGE));
|
|||
|
}
|