summaryrefslogtreecommitdiffstats
path: root/private/sdktools/dumpchk
diff options
context:
space:
mode:
authorAdam <you@example.com>2020-05-17 05:51:50 +0200
committerAdam <you@example.com>2020-05-17 05:51:50 +0200
commite611b132f9b8abe35b362e5870b74bce94a1e58e (patch)
treea5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/sdktools/dumpchk
downloadNT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip
Diffstat (limited to 'private/sdktools/dumpchk')
-rw-r--r--private/sdktools/dumpchk/dumpchk.c977
-rw-r--r--private/sdktools/dumpchk/dumpchk.rc11
-rw-r--r--private/sdktools/dumpchk/makefile1
-rw-r--r--private/sdktools/dumpchk/sources9
4 files changed, 998 insertions, 0 deletions
diff --git a/private/sdktools/dumpchk/dumpchk.c b/private/sdktools/dumpchk/dumpchk.c
new file mode 100644
index 000000000..ffcdf3f11
--- /dev/null
+++ b/private/sdktools/dumpchk/dumpchk.c
@@ -0,0 +1,977 @@
+/*++
+
+Copyright (c) 1994 Microsoft Corporation
+
+Module Name:
+
+ dumpchk.c
+
+Abstract:
+
+ This module implements the NT crashdump validation tool.
+
+Author:
+
+ Wesley Witt (wesw) 6-June-1994
+
+Environment:
+
+ NT 3.5
+
+Revision History:
+
+--*/
+
+#include <nt.h>
+#include <ntrtl.h>
+#include <nturtl.h>
+#include <ntdbg.h>
+#include <ntos.h>
+#include <windows.h>
+#include <crash.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+ULONG KiProcessors[1];
+ULONG KiPcrBaseAddress;
+
+//
+// mips
+//
+typedef struct _HARDWARE_PTE_MIPS {
+ ULONG Global : 1;
+ ULONG Valid : 1;
+ ULONG Dirty : 1;
+ ULONG CachePolicy : 3;
+ ULONG PageFrameNumber : 24;
+ ULONG Write : 1;
+ ULONG CopyOnWrite : 1;
+} HARDWARE_PTE_MIPS, *PHARDWARE_PTE_MIPS;
+
+//
+// i386
+//
+typedef struct _HARDWARE_PTE_I386 {
+ ULONG Valid : 1;
+ ULONG Write : 1;
+ ULONG Owner : 1;
+ ULONG WriteThrough : 1;
+ ULONG CacheDisable : 1;
+ ULONG Accessed : 1;
+ ULONG Dirty : 1;
+ ULONG Rsvd : 2;
+ ULONG CopyOnWrite : 1;
+ ULONG Prototype : 1;
+ ULONG Transition : 1;
+ ULONG PageFrameNumber : 20;
+} HARDWARE_PTE_I386, *PHARDWARE_PTE_I386;
+
+//
+// alpha
+//
+typedef struct _HARDWARE_PTE_ALPHA {
+ ULONG Valid: 1;
+ ULONG Owner: 1;
+ ULONG Dirty: 1;
+ ULONG reserved: 1;
+ ULONG Global: 1;
+ ULONG filler2: 2;
+ ULONG Write: 1;
+ ULONG CopyOnWrite: 1;
+ ULONG PageFrameNumber: 23;
+} HARDWARE_PTE_ALPHA, *PHARDWARE_PTE_ALPHA;
+
+//
+// ppc
+//
+typedef struct _HARDWARE_PTE_PPC {
+ ULONG Dirty : 2;
+ ULONG Valid : 1; // software
+ ULONG GuardedStorage : 1; // software? see 6-39 of PPC 601 UserManual
+ ULONG MemoryCoherence : 1;
+ ULONG CacheDisable : 1;
+ ULONG WriteThrough : 1;
+ ULONG Change : 1;
+ ULONG Reference : 1;
+ ULONG Write : 1; // software
+ ULONG CopyOnWrite : 1; // software
+ ULONG rsvd1 : 1;
+ ULONG PageFrameNumber : 20;
+} HARDWARE_PTE_PPC, *PHARDWARE_PTE_PPC;
+
+
+CHAR CrashDumpFile[MAX_PATH];
+ULONG PageSize;
+BOOL Verbose;
+BOOL PrintOnly;
+BOOL QuickCheck;
+DWORD ErrCnt;
+
+extern PPHYSICAL_MEMORY_DESCRIPTOR DmpPhysicalMemoryBlock;
+extern PCHAR DmpDumpBase;
+extern PULONG DmpDumpBaseUlong;
+extern PULONG DmpPdePage;
+extern PDUMP_HEADER DumpHeader;
+extern ULONG ValidPteMask;
+extern ULONG TransitionMask;
+extern ULONG TransitionCheck;
+extern ULONG ValidPfnMask;
+extern ULONG ValidPfnShift;
+extern ULONG TransitionPfnMask;
+extern ULONG TransitionPfnShift;
+extern ULONG PdeShift;
+extern ULONG PteShift;
+extern ULONG PteMask;
+extern ULONG PhysicalAddressMask;
+extern ULONG PhysicalAddressStart;
+extern ULONG PhysicalAddressEnd;
+extern ULONG PageSize;
+extern ULONG PageShift;
+
+
+//
+// prototypes
+//
+VOID GetCommandLineArgs(VOID);
+VOID Usage(VOID);
+VOID PrintHeader(LPSTR,PDUMP_HEADER,PCONTEXT,PEXCEPTION_RECORD);
+DWORD ValidateDumpFile(PDUMP_HEADER);
+ULONG GetPfn(LPVOID);
+DWORD ValidateModuleList(PDUMP_HEADER);
+BOOL ControlCHandler(DWORD);
+BOOL GetCrashDumpName(LPSTR,DWORD);
+
+
+int _cdecl
+main(
+ int argc,
+ char * argv[]
+ )
+
+/*++
+
+Routine Description:
+
+ Main entry point for the crasgdump check tool.
+
+Arguments:
+
+ Standard c args.
+
+Return Value:
+
+ Error count.
+
+--*/
+
+{
+ PCONTEXT Context;
+ PEXCEPTION_RECORD Exception;
+ PDUMP_HEADER DmpHeader;
+
+
+ GetCommandLineArgs();
+ if (!CrashDumpFile[0]) {
+ if (!GetCrashDumpName( CrashDumpFile, sizeof(CrashDumpFile))) {
+ fprintf( stderr, "missing dump file name\n" );
+ return 1;
+ }
+ }
+
+ if (!DmpInitialize( CrashDumpFile, &Context, &Exception, &DmpHeader )) {
+ printf( "could not initialize dump file - %s\n", CrashDumpFile );
+ DmpUnInitialize();
+ return 1;
+ }
+
+ switch (DmpHeader->MachineImageType) {
+ case IMAGE_FILE_MACHINE_I386:
+ PageSize = 4096;
+ break;
+
+ case IMAGE_FILE_MACHINE_R4000:
+ PageSize = 4096;
+ break;
+
+ case IMAGE_FILE_MACHINE_ALPHA:
+ PageSize = 8192;
+ break;
+ }
+
+ PrintHeader( CrashDumpFile, DmpHeader, Context, Exception );
+
+ if (!PrintOnly) {
+ SetConsoleCtrlHandler( ControlCHandler, TRUE );
+
+ ValidateModuleList( DmpHeader );
+
+ ValidateDumpFile( DmpHeader );
+
+ if (ErrCnt) {
+ printf( "\n\nTotal errors = %d\n", ErrCnt );
+ } else {
+ printf( "**************\n" );
+ printf( "**************--> This dump file is good!\n" );
+ printf( "**************\n" );
+ }
+ }
+
+ DmpUnInitialize();
+
+ return ErrCnt;
+}
+
+
+ULONG
+GetPfn(
+ LPVOID PdePage
+ )
+
+/*++
+
+Routine Description:
+
+ This routine extracts a pfn from a hardware pte.
+ This routine handles the machine dependencies associated
+ with hardware ptes.
+
+Arguments:
+
+ PdePage - Pointer to a hardware pte
+
+Return Value:
+
+ Page frame number.
+
+--*/
+
+{
+ ULONG pfn = 0;
+
+ switch (DumpHeader->MachineImageType) {
+ case IMAGE_FILE_MACHINE_I386:
+ pfn = ((PHARDWARE_PTE_I386)PdePage)->PageFrameNumber;
+ break;
+
+ case IMAGE_FILE_MACHINE_R4000:
+ pfn = ((PHARDWARE_PTE_MIPS)PdePage)->PageFrameNumber;
+ break;
+
+ case IMAGE_FILE_MACHINE_ALPHA:
+ pfn = ((PHARDWARE_PTE_ALPHA)PdePage)->PageFrameNumber;
+ break;
+
+ case IMAGE_FILE_MACHINE_POWERPC:
+ pfn = ((PHARDWARE_PTE_PPC)PdePage)->PageFrameNumber;
+ break;
+ }
+
+ return pfn;
+}
+
+
+DWORD
+PrintError(
+ ULONG va,
+ ULONG pfn
+ )
+
+/*++
+
+Routine Description:
+
+ This routine discovers what type of error exists with the supplied
+ virtual address and print the error text.
+
+Arguments:
+
+ va - Virtual address
+ pfn - pfn for the virtual address
+
+Return Value:
+
+ 1 - An error was printed.
+ 0 - An error was NOT printed.
+
+--*/
+
+{
+ CHAR errbuf[256];
+ LPSTR p;
+ BOOL verr;
+ ULONG loc;
+ PVOID VaPage;
+ ULONG PhyPage;
+ ULONG PdeOffset;
+ ULONG PteOffset;
+ PULONG PtePage;
+ DWORD rval = 0;
+
+ p = errbuf;
+ verr = FALSE;
+
+ p += sprintf( p, "Error: memory read failed 0x%08x ", va );
+ if (pfn) {
+ p += sprintf( p, "pfn=%x ", pfn );
+ }
+
+ loc = (ULONG)VaToLocation( (LPVOID)va );
+
+ if ((va >= PhysicalAddressStart) && (va < PhysicalAddressEnd)) {
+
+ PhyPage = GetPhysicalPage( (LPVOID)va );
+ VaPage = PageToLocation( PhyPage );
+ loc = (ULONG)((PCHAR)VaPage + (va & (PageSize - 1))) - (ULONG)DmpDumpBase;
+
+ p += sprintf( p, "phypage=%x vapage=%x, loc=%x\n", PhyPage, VaPage, loc );
+
+ } else {
+
+ PdeOffset = va >> PdeShift;
+ PteOffset = (va >> PteShift) & PteMask;
+
+ p += sprintf( p, "pde=%x, pte=%x ", PdeOffset, PteOffset );
+
+ if (DmpPdePage[PdeOffset] & ValidPteMask) {
+ PtePage = PageToLocation(PteToPfn(DmpPdePage[PdeOffset]));
+ p += sprintf( p, "ptepage=%x ", PtePage );
+ if (PtePage == NULL) {
+ p += sprintf( p, "*** invalid ptepage\n" );
+ } else {
+ VaPage = PageToLocation(PteToPfn (PtePage[PteOffset]));
+ p += sprintf( p, "vapage=%x ", VaPage );
+ if (VaPage == NULL) {
+ p += sprintf( p, "*** invalid vapage\n" );
+ verr = TRUE;
+ } else {
+ loc = (ULONG)((PCHAR)VaPage + ((ULONG)va & (PageSize - 1))) - (ULONG)DmpDumpBase;
+ p += sprintf( p, "loc=%x\n", loc );
+ }
+ }
+ } else {
+ p += sprintf( p, "*** invalid pde\n" );
+ }
+ }
+
+ if (verr) {
+ if (Verbose) {
+ printf( errbuf );
+ rval = 1;
+ }
+ } else {
+ printf( errbuf );
+ rval = 1;
+ }
+
+ return rval;
+}
+
+
+DWORD
+ValidateDumpFile(
+ PDUMP_HEADER DmpHeader
+ )
+
+/*++
+
+Routine Description:
+
+ This routine attempts to validate a crashdump file by enumerating
+ all possible virtual addresses one page at a time and then reading
+ memory at the virtual address. There are 2 classes of errors that
+ are detected: swapped out memory and all others. If the error is
+ dues to the memory being swapped out then the user can suppress the
+ reporting of these errors thru the verbose flag.
+
+Arguments:
+
+ DmpHeader - Supplies the crashdump header structure
+
+Return Value:
+
+ Count of errors detected.
+
+--*/
+
+{
+ ULONG i;
+ ULONG j;
+ ULONG k;
+ ULONG va1;
+ ULONG va2;
+ ULONG page;
+ LPBYTE PageBuf;
+ PULONG PtePage;
+ ULONG addr;
+ ULONG endaddr;
+ ULONG len;
+
+
+ //
+ // allocate a buffer big enough to read one page
+ //
+ if (QuickCheck) {
+ PageBuf = NULL;
+ } else {
+ PageBuf = malloc( PageSize );
+ }
+
+ if (!PageBuf) {
+ printf( "**************\n" );
+ printf( "**************--> Performing a quick check (^C to end)\n" );
+ printf( "**************\n" );
+ } else {
+ printf( "**************\n" );
+ printf( "**************--> Performing a complete check (^C to end)\n" );
+ printf( "**************\n" );
+ }
+
+ //
+ // first enumerate all physical addresses
+ //
+
+ printf( "**************\n" );
+ printf( "**************--> Validating all physical addresses\n" );
+ printf( "**************\n" );
+
+ addr = PhysicalAddressStart;
+ endaddr = PhysicalAddressEnd;
+
+ while (addr < endaddr ) {
+ len = min( PageSize, endaddr - addr );
+
+ page = GetPhysicalPage( (LPVOID)addr );
+
+ //
+ // verify that there is a physical page in the
+ // dump file fpr this address
+ //
+ for (k=0; k<DmpPhysicalMemoryBlock->NumberOfRuns; k++) {
+ if ((page >= DmpPhysicalMemoryBlock->Run[k].BasePage) &&
+ (page < (DmpPhysicalMemoryBlock->Run[k].BasePage +
+ DmpPhysicalMemoryBlock->Run[k].PageCount))) {
+ //
+ // found it
+ //
+ break;
+ }
+ }
+
+ if (k == DmpPhysicalMemoryBlock->NumberOfRuns) {
+ //
+ // there is not a physical page present so loop
+ // back and process the next pte. this will happen
+ // for memory that is mapped (like video) but is
+ // not written to the crash dump
+ //
+ addr += len;
+ continue;
+ }
+
+ if (!DmpReadMemory( (LPVOID)addr, PageBuf, len )) {
+ ErrCnt += PrintError( addr, 0 );
+ }
+ addr += len;
+ }
+
+ printf( "**************\n" );
+ printf( "**************--> Validating all virtual addresses\n" );
+ printf( "**************\n" );
+
+ //
+ // enumerate all of the system pdes
+ //
+ for (i=0; i<PageSize/sizeof(ULONG); i++) {
+
+ //
+ // check to see if it is a valid pde
+ //
+ if (DmpPdePage[i] & ValidPteMask) {
+
+ //
+ // begin to form a virtual address
+ // by shifting the pde index into place
+ //
+ va1 = i << PdeShift;
+
+ //
+ // now enumerate all of the ptes for this pde
+ //
+ for (j=0; j<PteMask; j++) {
+ //
+ // or in the pte into the virtual address
+ //
+ va2 = va1 | ( j << PteShift );
+
+ //
+ // get the page number
+ //
+ PtePage = PageToLocation(PteToPfn(DmpPdePage[i]));
+ if (!PtePage) {
+ continue;
+ }
+
+ page = PteToPfn( PtePage[j] );
+
+ //
+ // verify that there is a physical page in the
+ // dump file fpr this pde
+ //
+ for (k=0; k<DmpPhysicalMemoryBlock->NumberOfRuns; k++) {
+ if ((page >= DmpPhysicalMemoryBlock->Run[k].BasePage) &&
+ (page < (DmpPhysicalMemoryBlock->Run[k].BasePage +
+ DmpPhysicalMemoryBlock->Run[k].PageCount))) {
+ //
+ // found it
+ //
+ break;
+ }
+ }
+
+ if (k == DmpPhysicalMemoryBlock->NumberOfRuns) {
+ //
+ // there is not a physical page present so loop
+ // back and process the next pte. this will happen
+ // for memory that is mapped (like video) but is
+ // not written to the crash dump
+ //
+ continue;
+ }
+
+ //
+ // now we try to read a page of memory at this
+ // newly formed virtual address
+ //
+ if (!DmpReadMemory( (LPVOID)va2, PageBuf, PageSize )) {
+ //
+ // failure, the crashdump file is either bad
+ // or the memory is simply swapped out
+ //
+ ErrCnt += PrintError( va2, GetPfn( &DmpPdePage[i] ) );
+ }
+ }
+ }
+ }
+
+ //
+ // free the page buffer
+ //
+ if (PageBuf) {
+ free( PageBuf );
+ }
+
+ return ErrCnt;
+}
+
+
+DWORD
+ValidateModuleList(
+ PDUMP_HEADER DmpHeader
+ )
+{
+ LIST_ENTRY List;
+ PLIST_ENTRY Next;
+ ULONG len = 0;
+ ULONG cb;
+ PLDR_DATA_TABLE_ENTRY DataTable;
+ LDR_DATA_TABLE_ENTRY DataTableBuffer;
+ CHAR AnsiBuffer[512];
+ WCHAR UnicodeBuffer[512];
+ UNICODE_STRING BaseName;
+
+
+ printf( "**************\n" );
+ printf( "**************--> Validating the integrity of the PsLoadedModuleList\n" );
+ printf( "**************\n" );
+
+ if (!DmpReadMemory( DmpHeader->PsLoadedModuleList, (PVOID)&List, sizeof(LIST_ENTRY))) {
+ printf( "Error: could not read base of PsLoadedModuleList\n\n" );
+ return ++ErrCnt;
+ }
+
+ Next = List.Flink;
+ if (Next == NULL) {
+ printf( "Error: PsLoadedModuleList is empty\n" );
+ ErrCnt += PrintError( (ULONG)DmpHeader->PsLoadedModuleList, 0 );
+ printf( "\n" );
+ return ErrCnt;
+ }
+
+ while ((ULONG)Next != (ULONG)DmpHeader->PsLoadedModuleList) {
+ DataTable = CONTAINING_RECORD( Next,
+ LDR_DATA_TABLE_ENTRY,
+ InLoadOrderLinks
+ );
+ if (!DmpReadMemory( (PVOID)DataTable, (PVOID)&DataTableBuffer, sizeof(LDR_DATA_TABLE_ENTRY))) {
+ printf( "Error: memory read failed addr=0x%08x\n\n", (DWORD)DataTable );
+ return ++ErrCnt;
+ }
+
+ Next = DataTableBuffer.InLoadOrderLinks.Flink;
+
+ //
+ // Get the base DLL name.
+ //
+ if (DataTableBuffer.BaseDllName.Length != 0 &&
+ DataTableBuffer.BaseDllName.Buffer != NULL
+ ) {
+ BaseName = DataTableBuffer.BaseDllName;
+ }
+ else
+ if (DataTableBuffer.FullDllName.Length != 0 &&
+ DataTableBuffer.FullDllName.Buffer != NULL
+ ) {
+ BaseName = DataTableBuffer.FullDllName;
+ }
+ else {
+ continue;
+ }
+
+ if (BaseName.Length > sizeof(UnicodeBuffer)) {
+ printf( "Error: unicode buffer is too small\n" );
+ ErrCnt++;
+ continue;
+ }
+
+ cb = DmpReadMemory( (PVOID)BaseName.Buffer, (PVOID)UnicodeBuffer, BaseName.Length );
+ if (!cb) {
+ printf( "Error: memory read failed addr=0x%08x\n\n", (DWORD)BaseName.Buffer );
+ return ++ErrCnt;
+ }
+
+ RtlZeroMemory(&((PUCHAR)&UnicodeBuffer[0])[cb],(sizeof(WCHAR)*512)-cb);
+ RtlZeroMemory(&AnsiBuffer[0],512);
+
+ if (!WideCharToMultiByte(
+ CP_ACP,
+ 0,
+ UnicodeBuffer,
+ cb,
+ AnsiBuffer,
+ sizeof(AnsiBuffer),
+ NULL,
+ NULL
+ )) {
+ printf( "Error: could not convert module name to ansi\n\n" );
+ return ++ErrCnt;
+ }
+
+ if (Verbose) {
+ printf( "validating %-16s 0x%08x 0x%08x\n",
+ AnsiBuffer,
+ DataTableBuffer.DllBase,
+ DataTableBuffer.SizeOfImage );
+ }
+ }
+
+ printf( "\n" );
+
+ return ErrCnt;
+}
+
+
+
+VOID
+PrintHeader(
+ LPSTR CrashDumpFile,
+ PDUMP_HEADER DmpHeader,
+ PCONTEXT Context,
+ PEXCEPTION_RECORD Exception
+ )
+
+/*++
+
+Routine Description:
+
+ This routine prints each field in the crashdump header.
+
+Arguments:
+
+ DmpHeader - Supplies the crashdump header structure
+
+Return Value:
+
+ Nothing.
+
+--*/
+
+{
+ CHAR buf[16];
+ DWORD i;
+
+
+ printf( "\n" );
+ printf( "Filename . . . . . . .%s\n", CrashDumpFile );
+ *(PULONG)buf = DmpHeader->Signature;
+ buf[4] = 0;
+ printf( "Signature. . . . . . .%s\n", buf );
+ *(PULONG)buf = DmpHeader->ValidDump;
+ buf[4] = 0;
+ printf( "ValidDump. . . . . . .%s\n", buf );
+ printf( "MajorVersion . . . . ." );
+ if (DmpHeader->MajorVersion == 0xc) {
+ printf( "checked system\n" );
+ } else if (DmpHeader->MajorVersion == 0xf) {
+ printf( "free system\n" );
+ } else {
+ printf( "%d\n", DmpHeader->MajorVersion );
+ }
+ printf( "MinorVersion . . . . .%d\n", DmpHeader->MinorVersion );
+ printf( "DirectoryTableBase . .0x%08x\n", DmpHeader->DirectoryTableBase );
+ printf( "PfnDataBase. . . . . .0x%08x\n", DmpHeader->PfnDataBase );
+ printf( "PsLoadedModuleList . .0x%08x\n", DmpHeader->PsLoadedModuleList );
+ printf( "PsActiveProcessHead. .0x%08x\n", DmpHeader->PsActiveProcessHead );
+ printf( "MachineImageType . . ." );
+ switch (DmpHeader->MachineImageType) {
+ case IMAGE_FILE_MACHINE_I386:
+ printf( "i386\n" );
+ break;
+
+ case IMAGE_FILE_MACHINE_R4000:
+ printf( "mips\n" );
+ break;
+
+ case IMAGE_FILE_MACHINE_ALPHA:
+ printf( "alpha\n" );
+ break;
+
+ case IMAGE_FILE_MACHINE_POWERPC:
+ printf( "PowerPC\n" );
+ break;
+ }
+ printf( "NumberProcessors . . .%d\n", DmpHeader->NumberProcessors );
+ printf( "BugCheckCode . . . . .0x%08x\n", DmpHeader->BugCheckCode );
+ printf( "BugCheckParameter1 . .0x%08x\n", DmpHeader->BugCheckParameter1 );
+ printf( "BugCheckParameter2 . .0x%08x\n", DmpHeader->BugCheckParameter2 );
+ printf( "BugCheckParameter3 . .0x%08x\n", DmpHeader->BugCheckParameter3 );
+ printf( "BugCheckParameter4 . .0x%08x\n", DmpHeader->BugCheckParameter4 );
+ printf( "\n" );
+ printf( "ExceptionCode. . . . .0x%08x\n", Exception->ExceptionCode );
+ printf( "ExceptionFlags . . . .0x%08x\n", Exception->ExceptionFlags );
+ printf( "ExceptionAddress . . .0x%08x\n", Exception->ExceptionAddress );
+ for (i=0; i<Exception->NumberParameters; i++) {
+ printf( "ExceptionParam#%d . .0x%08x\n", Exception->ExceptionInformation[i] );
+ }
+ printf( "\n" );
+ printf( "NumberOfRuns . . . . .0x%x\n", DmpPhysicalMemoryBlock->NumberOfRuns );
+ printf( "NumberOfPages. . . . .0x%x\n", DmpPhysicalMemoryBlock->NumberOfPages );
+ for (i=0; i<DmpPhysicalMemoryBlock->NumberOfRuns; i++) {
+ printf( "Run #%d\n", i+1 );
+ printf( " BasePage . . . . . .0x%x\n", DmpPhysicalMemoryBlock->Run[i].BasePage );
+ printf( " PageCount. . . . . .0x%x\n", DmpPhysicalMemoryBlock->Run[i].PageCount );
+ }
+ printf( "\n\n" );
+}
+
+VOID
+GetCommandLineArgs(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Obtains the command line options for this tool.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ char *lpstrCmd = GetCommandLine();
+ UCHAR ch;
+ DWORD i = 0;
+
+ // skip over program name
+ do {
+ ch = *lpstrCmd++;
+ }
+ while (ch != ' ' && ch != '\t' && ch != '\0');
+
+ // skip over any following white space
+ while (ch == ' ' || ch == '\t') {
+ ch = *lpstrCmd++;
+ }
+
+ if (!*lpstrCmd) {
+ //
+ // no args so we default the dump file
+ // to what's in the registry
+ //
+ Verbose = TRUE;
+ return;
+ }
+
+ // process each switch character '-' as encountered
+
+ while (ch == '-' || ch == '/') {
+ ch = tolower(*lpstrCmd++);
+ // process multiple switch characters as needed
+ do {
+ switch (ch) {
+ case 'v':
+ Verbose = TRUE;
+ ch = *lpstrCmd++;
+ break;
+
+ case 'p':
+ PrintOnly = TRUE;
+ ch = *lpstrCmd++;
+ break;
+
+ case 'q':
+ QuickCheck = TRUE;
+ ch = *lpstrCmd++;
+ break;
+
+ case '?':
+ Usage();
+ ch = *lpstrCmd++;
+ break;
+
+ default:
+ return;
+ }
+ } while (ch != ' ' && ch != '\t' && ch != '\0');
+
+ while (ch == ' ' || ch == '\t') {
+ ch = *lpstrCmd++;
+ }
+ }
+ //
+ // get the crashdump file name
+ //
+ i=0;
+ while (ch != ' ' && ch != '\0') {
+ CrashDumpFile[i++] = ch;
+ ch = *lpstrCmd++;
+ }
+ CrashDumpFile[i] = 0;
+
+ return;
+}
+
+
+VOID
+Usage(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Prints usage text for this tool.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ fprintf( stderr, "Microsoft (R) Windows NT (TM) Version 3.51 DUMPCHK\n" );
+ fprintf( stderr, "Copyright (C) 1995 Microsoft Corp. All rights reserved\n\n" );
+ fprintf( stderr, "usage: DUMPCHK [options] CrashDumpFile\n" );
+ fprintf( stderr, " [-?] Display this message\n" );
+ fprintf( stderr, " [-v] Verbose mode\n" );
+ fprintf( stderr, " [-p] Print header only, NO validation\n" );
+ fprintf( stderr, " [-q] Perform a quick test\n" );
+ ExitProcess(0);
+}
+
+BOOL
+ControlCHandler(
+ DWORD dwCtrlType
+ )
+
+/*++
+
+Routine Description:
+
+ Handles Control-C events so that we can
+ print an error summary before ending.
+
+Arguments:
+
+ dwCtrlType - Event type
+
+Return Value:
+
+ FALSE
+
+--*/
+
+{
+ if (dwCtrlType == CTRL_C_EVENT) {
+ if (ErrCnt) {
+ printf( "\n\nTotal errors = %d\n", ErrCnt );
+ } else {
+ printf( "**************\n" );
+ printf( "**************--> This dump file is good (so far)!\n" );
+ printf( "**************\n" );
+ }
+ }
+
+ return FALSE;
+}
+
+BOOL
+GetCrashDumpName(
+ LPSTR DumpName,
+ DWORD Length
+ )
+{
+ DWORD DataSize;
+ DWORD DataType;
+ CHAR Data[128];
+ LONG rc;
+ HKEY hKey;
+
+
+ if (RegOpenKeyEx(
+ HKEY_LOCAL_MACHINE,
+ "System\\CurrentControlSet\\Control\\CrashControl",
+ 0,
+ KEY_READ,
+ &hKey
+ ) != NO_ERROR) {
+ //
+ // unknown, possibly crashdumps not enabled
+ //
+ return FALSE;
+ }
+
+ DataSize = sizeof(Data);
+
+ rc = RegQueryValueEx(
+ hKey,
+ "DumpFile",
+ 0,
+ &DataType,
+ Data,
+ &DataSize
+ );
+
+ RegCloseKey( hKey );
+
+ if ((rc == NO_ERROR) && (DataType == REG_EXPAND_SZ)) {
+ if (ExpandEnvironmentStrings( Data, DumpName, Length )) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
diff --git a/private/sdktools/dumpchk/dumpchk.rc b/private/sdktools/dumpchk/dumpchk.rc
new file mode 100644
index 000000000..bbbe71d13
--- /dev/null
+++ b/private/sdktools/dumpchk/dumpchk.rc
@@ -0,0 +1,11 @@
+#include <windows.h>
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_APP
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "Microsoft\256 Crash Dump Checker"
+
+#define VER_INTERNALNAME_STR "dumpchk.exe"
+#define VER_ORIGINALFILENAME_STR "dumpchk.exe"
+
+#include <common.ver>
diff --git a/private/sdktools/dumpchk/makefile b/private/sdktools/dumpchk/makefile
new file mode 100644
index 000000000..5acbbd24c
--- /dev/null
+++ b/private/sdktools/dumpchk/makefile
@@ -0,0 +1 @@
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/sdktools/dumpchk/sources b/private/sdktools/dumpchk/sources
new file mode 100644
index 000000000..8444a0b65
--- /dev/null
+++ b/private/sdktools/dumpchk/sources
@@ -0,0 +1,9 @@
+MAJORCOMP=sdktools
+MINORCOMP=dumpchk
+TARGETNAME=dumpchk
+TARGETPATH=obj
+TARGETTYPE=PROGRAM
+UMTYPE=console
+SOURCES=dumpchk.c dumpchk.rc
+INCLUDES=$(BASEDIR)\private\ntos\inc
+LINKLIBS=$(BASEDIR)\public\sdk\lib\*\crashlib.lib