525 lines
9.9 KiB
C
525 lines
9.9 KiB
C
|
|
|||
|
/*++
|
|||
|
|
|||
|
Copyright(c) 1999 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
triage.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
Triage dump support.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Matthew D. Hendel (math) 20-Jan-1999
|
|||
|
|
|||
|
Comments:
|
|||
|
|
|||
|
Do not merge this file with some other file. By leaving it in it's own
|
|||
|
compiland, we avoid having to link with all the other random variables
|
|||
|
in crashlib.
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "iomgr.h"
|
|||
|
#include "dumpctl.h"
|
|||
|
#include <nt.h>
|
|||
|
#include <ntrtl.h>
|
|||
|
#include <windef.h>
|
|||
|
#include <stdio.h>
|
|||
|
#include <malloc.h>
|
|||
|
#include <triage.h>
|
|||
|
#include <ntverp.h>
|
|||
|
|
|||
|
|
|||
|
#ifndef NtBuildNumber
|
|||
|
# if DBG
|
|||
|
# define NtBuildNumber (VER_PRODUCTBUILD | 0xC0000000)
|
|||
|
# else
|
|||
|
# define NtBuildNumber (VER_PRODUCTBUILD | 0xF0000000)
|
|||
|
# endif
|
|||
|
#endif
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// NOTE: Pages sizes copied from ntos\inc. These must be kept in sync with
|
|||
|
// global header files.
|
|||
|
//
|
|||
|
|
|||
|
#define PAGE_SIZE_I386 0x1000
|
|||
|
#define PAGE_SIZE_ALPHA 0x2000
|
|||
|
#define PAGE_SIZE_IA64 0x2000
|
|||
|
|
|||
|
|
|||
|
ULONG TriageImagePageSize = -1;
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
TriagepVerifyDump(
|
|||
|
IN LPVOID TriageDumpBlock
|
|||
|
);
|
|||
|
|
|||
|
ULONG
|
|||
|
TriagepGetPageSize(
|
|||
|
ULONG Architecture
|
|||
|
);
|
|||
|
|
|||
|
PTRIAGE_DUMP
|
|||
|
TriagepGetTriagePointer(
|
|||
|
IN PVOID TriageDumpBlock
|
|||
|
);
|
|||
|
|
|||
|
|
|||
|
#ifdef ALLOC_PRAGMA
|
|||
|
|
|||
|
#pragma alloc_text (INIT, TriagepVerifyDump)
|
|||
|
#pragma alloc_text (INIT, TriagepGetPageSize)
|
|||
|
#pragma alloc_text (INIT, TriagepGetTriagePointer)
|
|||
|
|
|||
|
#pragma alloc_text (INIT, TriageGetVersion)
|
|||
|
#pragma alloc_text (INIT, TriageGetDriverCount)
|
|||
|
#pragma alloc_text (INIT, TriageGetContext)
|
|||
|
#pragma alloc_text (INIT, TriageGetExceptionRecord)
|
|||
|
#pragma alloc_text (INIT, TriageGetBugcheckData)
|
|||
|
#pragma alloc_text (INIT, TriageGetDriverEntry)
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
|
|||
|
//++
|
|||
|
//
|
|||
|
// PULONG
|
|||
|
// IndexByUlong(
|
|||
|
// PVOID Pointer,
|
|||
|
// ULONG Index
|
|||
|
// )
|
|||
|
//
|
|||
|
// Routine Description:
|
|||
|
//
|
|||
|
// Return the address Index ULONGs into Pointer. That is,
|
|||
|
// Index * sizeof (ULONG) bytes into Pointer.
|
|||
|
//
|
|||
|
// Arguments:
|
|||
|
//
|
|||
|
// Pointer - Start of region.
|
|||
|
//
|
|||
|
// Index - Number of ULONGs to index into.
|
|||
|
//
|
|||
|
// Return Value:
|
|||
|
//
|
|||
|
// PULONG representing the pointer described above.
|
|||
|
//
|
|||
|
//--
|
|||
|
|
|||
|
#define IndexByUlong(Pointer,Index) (&(((ULONG*) (Pointer)) [Index]))
|
|||
|
|
|||
|
|
|||
|
//++
|
|||
|
//
|
|||
|
// PBYTE
|
|||
|
// IndexByByte(
|
|||
|
// PVOID Pointer,
|
|||
|
// ULONG Index
|
|||
|
// )
|
|||
|
//
|
|||
|
// Routine Description:
|
|||
|
//
|
|||
|
// Return the address Index BYTEs into Pointer. That is,
|
|||
|
// Index * sizeof (BYTE) bytes into Pointer.
|
|||
|
//
|
|||
|
// Arguments:
|
|||
|
//
|
|||
|
// Pointer - Start of region.
|
|||
|
//
|
|||
|
// Index - Number of BYTEs to index into.
|
|||
|
//
|
|||
|
// Return Value:
|
|||
|
//
|
|||
|
// PBYTE representing the pointer described above.
|
|||
|
//
|
|||
|
//--
|
|||
|
|
|||
|
#define IndexByByte(Pointer, Index) (&(((BYTE*) (Pointer)) [Index]))
|
|||
|
|
|||
|
|
|||
|
ULONG
|
|||
|
TriagepGetPageSize(
|
|||
|
ULONG Architecture
|
|||
|
)
|
|||
|
{
|
|||
|
switch (Architecture) {
|
|||
|
|
|||
|
case IMAGE_FILE_MACHINE_I386:
|
|||
|
return PAGE_SIZE_I386;
|
|||
|
|
|||
|
case IMAGE_FILE_MACHINE_ALPHA:
|
|||
|
return PAGE_SIZE_ALPHA;
|
|||
|
|
|||
|
case IMAGE_FILE_MACHINE_IA64:
|
|||
|
return PAGE_SIZE_IA64;
|
|||
|
|
|||
|
default:
|
|||
|
return -1;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
TriagepVerifyDump(
|
|||
|
IN LPVOID TriageDumpBlock
|
|||
|
)
|
|||
|
{
|
|||
|
BOOLEAN Succ = FALSE;
|
|||
|
PMEMORY_DUMP MemoryDump = NULL;
|
|||
|
|
|||
|
if (!TriageDumpBlock) {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
MemoryDump = (PMEMORY_DUMP) TriageDumpBlock;
|
|||
|
|
|||
|
try {
|
|||
|
|
|||
|
if (MemoryDump->Header.ValidDump != 'PMUD' ||
|
|||
|
MemoryDump->Header.Signature != 'EGAP' ||
|
|||
|
TriagepGetPageSize (MemoryDump->Header.MachineImageType) == -1) {
|
|||
|
|
|||
|
Succ = FALSE;
|
|||
|
leave;
|
|||
|
}
|
|||
|
|
|||
|
TriageImagePageSize = TriagepGetPageSize (MemoryDump->Header.MachineImageType);
|
|||
|
|
|||
|
if ( MemoryDump->Header.DumpType != DUMP_TYPE_TRIAGE ||
|
|||
|
*(ULONG*)IndexByByte (MemoryDump, MemoryDump->Triage.SizeOfDump - sizeof (DWORD)) != TRIAGE_DUMP_VALID ) {
|
|||
|
|
|||
|
Succ = FALSE;
|
|||
|
leave;
|
|||
|
}
|
|||
|
|
|||
|
// else
|
|||
|
|
|||
|
Succ = TRUE;
|
|||
|
}
|
|||
|
|
|||
|
except (EXCEPTION_EXECUTE_HANDLER) {
|
|||
|
|
|||
|
Succ = FALSE;
|
|||
|
}
|
|||
|
|
|||
|
return Succ;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
PTRIAGE_DUMP
|
|||
|
TriagepGetTriagePointer(
|
|||
|
IN PVOID TriageDumpBlock
|
|||
|
)
|
|||
|
{
|
|||
|
ASSERT (TriageImagePageSize != -1);
|
|||
|
ASSERT (TriagepVerifyDump (TriageDumpBlock));
|
|||
|
|
|||
|
return (PTRIAGE_DUMP) IndexByByte (TriageDumpBlock, TriageImagePageSize);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
TriageGetVersion(
|
|||
|
IN LPVOID TriageDumpBlock,
|
|||
|
OUT ULONG * MajorVersion,
|
|||
|
OUT ULONG * MinorVersion,
|
|||
|
OUT ULONG * ServicePackBuild
|
|||
|
)
|
|||
|
{
|
|||
|
PTRIAGE_DUMP TriageDump;
|
|||
|
PDUMP_HEADER DumpHeader;
|
|||
|
|
|||
|
if (!TriagepVerifyDump (TriageDumpBlock)) {
|
|||
|
return STATUS_INVALID_PARAMETER;
|
|||
|
}
|
|||
|
|
|||
|
TriageDump = TriagepGetTriagePointer (TriageDumpBlock);
|
|||
|
|
|||
|
if (!TriageDump) {
|
|||
|
return STATUS_INVALID_PARAMETER;
|
|||
|
}
|
|||
|
|
|||
|
DumpHeader = (PDUMP_HEADER) TriageDumpBlock;
|
|||
|
|
|||
|
if (MajorVersion) {
|
|||
|
*MajorVersion = DumpHeader->MajorVersion;
|
|||
|
}
|
|||
|
|
|||
|
if (MinorVersion) {
|
|||
|
*MinorVersion = DumpHeader->MinorVersion;
|
|||
|
}
|
|||
|
|
|||
|
if (ServicePackBuild) {
|
|||
|
*ServicePackBuild = TriageDump->ServicePackBuild;
|
|||
|
}
|
|||
|
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
TriageGetDriverCount(
|
|||
|
IN LPVOID TriageDumpBlock,
|
|||
|
OUT ULONG * DriverCount
|
|||
|
)
|
|||
|
{
|
|||
|
PTRIAGE_DUMP TriageDump;
|
|||
|
|
|||
|
if (!TriagepVerifyDump (TriageDumpBlock)) {
|
|||
|
return STATUS_INVALID_PARAMETER;
|
|||
|
}
|
|||
|
|
|||
|
TriageDump = TriagepGetTriagePointer (TriageDumpBlock);
|
|||
|
|
|||
|
if (!TriageDump) {
|
|||
|
return STATUS_INVALID_PARAMETER;
|
|||
|
}
|
|||
|
|
|||
|
*DriverCount = TriageDump->DriverCount;
|
|||
|
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
#if 0
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
TriageGetContext(
|
|||
|
IN LPVOID TriageDumpBlock,
|
|||
|
OUT LPVOID Context,
|
|||
|
IN ULONG SizeInBytes
|
|||
|
)
|
|||
|
{
|
|||
|
PTRIAGE_DUMP TriageDump;
|
|||
|
|
|||
|
if (!TriagepVerifyDump (TriageDumpBlock)) {
|
|||
|
return STATUS_INVALID_PARAMETER;
|
|||
|
}
|
|||
|
|
|||
|
TriageDump = TriagepGetTriagePointer (TriageDumpBlock);
|
|||
|
|
|||
|
if (!TriageDump) {
|
|||
|
return STATUS_INVALID_PARAMETER;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Copy the CONTEXT record.
|
|||
|
//
|
|||
|
|
|||
|
if (SizeInBytes == -1) {
|
|||
|
SizeInBytes = sizeof (CONTEXT);
|
|||
|
}
|
|||
|
|
|||
|
RtlCopyMemory (Context,
|
|||
|
IndexByUlong (TriageDumpBlock, TriageDump->ContextOffset),
|
|||
|
SizeInBytes
|
|||
|
);
|
|||
|
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
TriageGetExceptionRecord(
|
|||
|
IN LPVOID TriageDumpBlock,
|
|||
|
OUT EXCEPTION_RECORD * ExceptionRecord
|
|||
|
)
|
|||
|
{
|
|||
|
PTRIAGE_DUMP TriageDump;
|
|||
|
|
|||
|
if (!TriagepVerifyDump (TriageDumpBlock)) {
|
|||
|
return STATUS_INVALID_PARAMETER;
|
|||
|
}
|
|||
|
|
|||
|
TriageDump = TriagepGetTriagePointer (TriageDumpBlock);
|
|||
|
|
|||
|
if (!TriageDump) {
|
|||
|
return STATUS_INVALID_PARAMETER;
|
|||
|
}
|
|||
|
|
|||
|
RtlCopyMemory (ExceptionRecord,
|
|||
|
IndexByUlong (TriageDumpBlock, TriageDump->ExceptionOffset),
|
|||
|
sizeof (*ExceptionRecord)
|
|||
|
);
|
|||
|
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
|
|||
|
LOGICAL
|
|||
|
TriageActUpon(
|
|||
|
IN PVOID TriageDumpBlock
|
|||
|
)
|
|||
|
{
|
|||
|
PTRIAGE_DUMP TriageDump;
|
|||
|
|
|||
|
if (!TriagepVerifyDump (TriageDumpBlock)) {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
TriageDump = TriagepGetTriagePointer (TriageDumpBlock);
|
|||
|
|
|||
|
if (!TriageDump) {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
if ((TriageDump->TriageOptions & DCB_TRIAGE_DUMP_ACT_UPON_ENABLED) == 0) {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
TriageGetBugcheckData(
|
|||
|
IN LPVOID TriageDumpBlock,
|
|||
|
OUT ULONG * BugCheckCode,
|
|||
|
OUT UINT_PTR * BugCheckParam1,
|
|||
|
OUT UINT_PTR * BugCheckParam2,
|
|||
|
OUT UINT_PTR * BugCheckParam3,
|
|||
|
OUT UINT_PTR * BugCheckParam4
|
|||
|
)
|
|||
|
{
|
|||
|
PDUMP_HEADER DumpHeader;
|
|||
|
|
|||
|
if (!TriagepVerifyDump (TriageDumpBlock)) {
|
|||
|
return STATUS_INVALID_PARAMETER;
|
|||
|
}
|
|||
|
|
|||
|
DumpHeader = (PDUMP_HEADER) TriageDumpBlock;
|
|||
|
|
|||
|
*BugCheckCode = DumpHeader->BugCheckCode;
|
|||
|
*BugCheckParam1 = DumpHeader->BugCheckParameter1;
|
|||
|
*BugCheckParam2 = DumpHeader->BugCheckParameter2;
|
|||
|
*BugCheckParam3 = DumpHeader->BugCheckParameter3;
|
|||
|
*BugCheckParam4 = DumpHeader->BugCheckParameter4;
|
|||
|
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
PKLDR_DATA_TABLE_ENTRY
|
|||
|
TriageGetLoaderEntry(
|
|||
|
IN PVOID TriageDumpBlock,
|
|||
|
IN ULONG ModuleIndex
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function retrieves a loaded module list entry.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
TriageDumpBlock - Supplies the triage dump to reference.
|
|||
|
|
|||
|
ModuleIndex - Supplies the driver index number to locate.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
A pointer to a loader data table entry if one is available, NULL if not.
|
|||
|
|
|||
|
Environment:
|
|||
|
|
|||
|
Kernel mode, APC_LEVEL or below. Phase 0 only.
|
|||
|
|
|||
|
N.B. This function is for use by memory management ONLY.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PDUMP_STRING DriverName;
|
|||
|
PDUMP_DRIVER_ENTRY DriverList;
|
|||
|
PTRIAGE_DUMP TriageDump;
|
|||
|
PKLDR_DATA_TABLE_ENTRY DataTableEntry;
|
|||
|
|
|||
|
if (!TriagepVerifyDump (TriageDumpBlock)) {
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
|
|||
|
TriageDump = TriagepGetTriagePointer (TriageDumpBlock);
|
|||
|
|
|||
|
if (ModuleIndex >= TriageDump->DriverCount) {
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
|
|||
|
DriverList = (PDUMP_DRIVER_ENTRY)
|
|||
|
IndexByByte (TriageDumpBlock, TriageDump->DriverListOffset);
|
|||
|
|
|||
|
|
|||
|
DataTableEntry = (PKLDR_DATA_TABLE_ENTRY) (&DriverList[ModuleIndex].LdrEntry);
|
|||
|
|
|||
|
//
|
|||
|
// Repoint the module driver name into the triage buffer.
|
|||
|
//
|
|||
|
|
|||
|
DriverName = (PDUMP_STRING)
|
|||
|
IndexByByte (TriageDumpBlock,
|
|||
|
DriverList [ ModuleIndex ].DriverNameOffset);
|
|||
|
|
|||
|
DataTableEntry->BaseDllName.Length = (USHORT) (DriverName->Length * sizeof (WCHAR));
|
|||
|
DataTableEntry->BaseDllName.MaximumLength = DataTableEntry->BaseDllName.Length;
|
|||
|
DataTableEntry->BaseDllName.Buffer = DriverName->Buffer;
|
|||
|
|
|||
|
return DataTableEntry;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
PVOID
|
|||
|
TriageGetMmInformation(
|
|||
|
IN PVOID TriageDumpBlock
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function retrieves a loaded module list entry.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
TriageDumpBlock - Supplies the triage dump to reference.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
A pointer to an opaque Mm information structure.
|
|||
|
|
|||
|
Environment:
|
|||
|
|
|||
|
Kernel mode, APC_LEVEL or below. Phase 0 only.
|
|||
|
|
|||
|
N.B. This function is for use by memory management ONLY.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PTRIAGE_DUMP TriageDump;
|
|||
|
|
|||
|
if (!TriagepVerifyDump (TriageDumpBlock)) {
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
|
|||
|
TriageDump = TriagepGetTriagePointer (TriageDumpBlock);
|
|||
|
|
|||
|
if (!TriageDump) {
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
|
|||
|
return (PVOID)IndexByByte (TriageDumpBlock, TriageDump->MmOffset);
|
|||
|
}
|