/*++ 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 its own compiland, we avoid having to link with all the other random variables in crashlib. --*/ #include "iomgr.h" #include "dumpctl.h" #include #include #include #include #include #include #include #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_AMD64 0x1000 #define PAGE_SIZE_IA64 0x2000 ULONG TriageImagePageSize = (ULONG) -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_AMD64: return PAGE_SIZE_AMD64; case IMAGE_FILE_MACHINE_IA64: return PAGE_SIZE_IA64; default: return (ULONG) -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); }