1422 lines
33 KiB
C
1422 lines
33 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1993 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
crash.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This module implements support for handling crash dump files.
|
|||
|
This consists of opening the file and returning the context
|
|||
|
and processor type, reading and writing virtual addresses and
|
|||
|
reading and writing physical addresses.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Lou Perazzoli (Loup) 10-Nov-1993
|
|||
|
Wesley Witt (wesw) 1-Dec-1993 (additional work)
|
|||
|
|
|||
|
Environment:
|
|||
|
|
|||
|
NT 3.1
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
Lou Perazzoli (Loup) 23-Jan-1996 - add large page support for x86.
|
|||
|
|
|||
|
--*/
|
|||
|
#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 <string.h>
|
|||
|
|
|||
|
|
|||
|
BOOL
|
|||
|
DmpReadControlSpaceX86(
|
|||
|
USHORT Processor,
|
|||
|
PVOID TargetBaseAddress,
|
|||
|
PVOID UserInterfaceBuffer,
|
|||
|
ULONG TransferCount,
|
|||
|
PULONG ActualBytesRead
|
|||
|
);
|
|||
|
|
|||
|
BOOL
|
|||
|
DmpReadControlSpaceMip(
|
|||
|
USHORT Processor,
|
|||
|
PVOID TargetBaseAddress,
|
|||
|
PVOID UserInterfaceBuffer,
|
|||
|
ULONG TransferCount,
|
|||
|
PULONG ActualBytesRead
|
|||
|
);
|
|||
|
|
|||
|
BOOL
|
|||
|
DmpReadControlSpaceAlp(
|
|||
|
USHORT Processor,
|
|||
|
PVOID TargetBaseAddress,
|
|||
|
PVOID UserInterfaceBuffer,
|
|||
|
ULONG TransferCount,
|
|||
|
PULONG ActualBytesRead
|
|||
|
);
|
|||
|
|
|||
|
BOOL
|
|||
|
DmpReadControlSpacePPC(
|
|||
|
USHORT Processor,
|
|||
|
PVOID TargetBaseAddress,
|
|||
|
PVOID UserInterfaceBuffer,
|
|||
|
ULONG TransferCount,
|
|||
|
PULONG ActualBytesRead
|
|||
|
);
|
|||
|
|
|||
|
BOOL
|
|||
|
DmpGetContextX86(
|
|||
|
IN ULONG Processor,
|
|||
|
OUT PVOID Context
|
|||
|
);
|
|||
|
|
|||
|
BOOL
|
|||
|
DmpGetContextMip(
|
|||
|
IN ULONG Processor,
|
|||
|
OUT PVOID Context
|
|||
|
);
|
|||
|
|
|||
|
BOOL
|
|||
|
DmpGetContextAlp(
|
|||
|
IN ULONG Processor,
|
|||
|
OUT PVOID Context
|
|||
|
);
|
|||
|
|
|||
|
BOOL
|
|||
|
DmpGetContextPPC(
|
|||
|
IN ULONG Processor,
|
|||
|
OUT PVOID Context
|
|||
|
);
|
|||
|
|
|||
|
INT
|
|||
|
DmpGetCurrentProcessorX86(
|
|||
|
VOID
|
|||
|
);
|
|||
|
|
|||
|
INT
|
|||
|
DmpGetCurrentProcessorMip(
|
|||
|
VOID
|
|||
|
);
|
|||
|
|
|||
|
INT
|
|||
|
DmpGetCurrentProcessorAlp(
|
|||
|
VOID
|
|||
|
);
|
|||
|
|
|||
|
INT
|
|||
|
DmpGetCurrentProcessorPPC(
|
|||
|
VOID
|
|||
|
);
|
|||
|
|
|||
|
|
|||
|
|
|||
|
#define X86_VALID 0x1
|
|||
|
#define X86_TRANSITION_MASK 0xC00
|
|||
|
#define X86_TRANSITION_CHECK 0x800
|
|||
|
#define X86_VALID_PFN_MASK 0xFFFFF000
|
|||
|
#define X86_VALID_PFN_SHIFT 12
|
|||
|
#define X86_TRANS_PFN_MASK 0xFFFFF000
|
|||
|
#define X86_TRANS_PFN_SHIFT 12
|
|||
|
#define X86_PDE_SHIFT 22
|
|||
|
#define X86_PTE_SHIFT 12
|
|||
|
#define X86_PTE_MASK 0x3ff
|
|||
|
#define X86_PHYSICAL_MASK 0x0
|
|||
|
#define X86_PHYSICAL_START 0x1
|
|||
|
#define X86_PHYSICAL_END 0x0
|
|||
|
#define X86_PAGESIZE 4096
|
|||
|
#define X86_PAGESHIFT 12
|
|||
|
#define X86_LARGE_PAGE_MASK 0x80
|
|||
|
#define X86_LARGE_PAGE_SIZE (4*1024*1024)
|
|||
|
|
|||
|
#define MIPS_VALID 0x2
|
|||
|
#define MIPS_TRANSITION_MASK 0x104
|
|||
|
#define MIPS_TRANSITION_CHECK 0x100
|
|||
|
#define MIPS_VALID_PFN_MASK 0x3FFFFFC0
|
|||
|
#define MIPS_VALID_PFN_SHIFT 6
|
|||
|
#define MIPS_TRANS_PFN_MASK 0xFFFFFE00
|
|||
|
#define MIPS_TRANS_PFN_SHIFT 9
|
|||
|
#define MIPS_PDE_SHIFT 22
|
|||
|
#define MIPS_PTE_SHIFT 12
|
|||
|
#define MIPS_PTE_MASK 0x3ff
|
|||
|
#define MIPS_PHYSICAL_MASK 0x1FFFFFFF
|
|||
|
#define MIPS_PHYSICAL_START 0x80000000
|
|||
|
#define MIPS_PHYSICAL_END 0xBFFFFFFF
|
|||
|
#define MIPS_PAGESIZE 4096
|
|||
|
#define MIPS_PAGESHIFT 12
|
|||
|
|
|||
|
#define PPC_VALID 0x4
|
|||
|
#define PPC_TRANSITION_MASK 0x3
|
|||
|
#define PPC_TRANSITION_CHECK 0x2
|
|||
|
#define PPC_VALID_PFN_MASK 0xFFFFF000
|
|||
|
#define PPC_VALID_PFN_SHIFT 12
|
|||
|
#define PPC_TRANS_PFN_MASK 0xFFFFF000
|
|||
|
#define PPC_TRANS_PFN_SHIFT 12
|
|||
|
#define PPC_PDE_SHIFT 22
|
|||
|
#define PPC_PTE_SHIFT 12
|
|||
|
#define PPC_PTE_MASK 0x3ff
|
|||
|
#define PPC_PHYSICAL_MASK 0x1FFFFFFF
|
|||
|
#define PPC_PHYSICAL_START 0x80000000
|
|||
|
#define PPC_PHYSICAL_END 0x807FFFFF
|
|||
|
#define PPC_PAGESIZE 4096
|
|||
|
#define PPC_PAGESHIFT 12
|
|||
|
|
|||
|
#define ALPHA_VALID 0x1
|
|||
|
#define ALPHA_TRANSITION_MASK 0x6
|
|||
|
#define ALPHA_TRANSITION_CHECK 0x4
|
|||
|
#define ALPHA_VALID_PFN_MASK 0xFFFFFE00
|
|||
|
#define ALPHA_VALID_PFN_SHIFT 9
|
|||
|
#define ALPHA_TRANS_PFN_MASK 0xFFFFFE00
|
|||
|
#define ALPHA_TRANS_PFN_SHIFT 9
|
|||
|
#define ALPHA_PDE_SHIFT 24
|
|||
|
#define ALPHA_PTE_SHIFT 13
|
|||
|
#define ALPHA_PTE_MASK 0x7ff
|
|||
|
#define ALPHA_PHYSICAL_MASK 0x3FFFFFFF
|
|||
|
#define ALPHA_PHYSICAL_START 0x80000000
|
|||
|
#define ALPHA_PHYSICAL_END 0xBFFFFFFF
|
|||
|
#define ALPHA_PAGESIZE 8192
|
|||
|
#define ALPHA_PAGESHIFT 13
|
|||
|
|
|||
|
#define MM_MAXIMUM_IMAGE_SECTIONS \
|
|||
|
((MM_MAXIMUM_IMAGE_HEADER - (PageSize + sizeof(IMAGE_NT_HEADERS))) / \
|
|||
|
sizeof(IMAGE_SECTION_HEADER))
|
|||
|
|
|||
|
#define MI_ROUND_TO_SIZE(LENGTH,ALIGNMENT) \
|
|||
|
(((ULONG)LENGTH + ALIGNMENT - 1) & ~(ALIGNMENT - 1))
|
|||
|
|
|||
|
#define MAX_PHYSICAL_MEMORY_FRAGMENTS 20
|
|||
|
|
|||
|
//
|
|||
|
// globals
|
|||
|
//
|
|||
|
PPHYSICAL_MEMORY_DESCRIPTOR DmpPhysicalMemoryBlock;
|
|||
|
HANDLE File;
|
|||
|
HANDLE MemMap;
|
|||
|
PCHAR DmpDumpBase;
|
|||
|
PULONG DmpDumpBaseUlong;
|
|||
|
PULONG DmpPdePage;
|
|||
|
PDUMP_HEADER DumpHeader;
|
|||
|
PUSERMODE_CRASHDUMP_HEADER DumpHeaderUser;
|
|||
|
PVOID DumpContext;
|
|||
|
PVOID DumpThread;
|
|||
|
BOOL UserModeDump;
|
|||
|
PMEMORY_BASIC_INFORMATION MemoryInfo;
|
|||
|
PVOID MemoryData;
|
|||
|
|
|||
|
ULONG ValidPteMask = X86_VALID;
|
|||
|
ULONG TransitionMask = X86_TRANSITION_MASK;
|
|||
|
ULONG TransitionCheck = X86_TRANSITION_CHECK;
|
|||
|
ULONG ValidPfnMask = X86_VALID_PFN_MASK;
|
|||
|
ULONG ValidPfnShift = X86_VALID_PFN_SHIFT;
|
|||
|
ULONG TransitionPfnMask = X86_TRANS_PFN_MASK;
|
|||
|
ULONG TransitionPfnShift = X86_TRANS_PFN_SHIFT;
|
|||
|
ULONG PdeShift = X86_PDE_SHIFT;
|
|||
|
ULONG PteShift = X86_PTE_SHIFT;
|
|||
|
ULONG PteMask = X86_PTE_MASK;
|
|||
|
ULONG PhysicalAddressMask = X86_PHYSICAL_MASK;
|
|||
|
ULONG PhysicalAddressStart = X86_PHYSICAL_START;
|
|||
|
ULONG PhysicalAddressEnd = X86_PHYSICAL_END;
|
|||
|
ULONG PageSize = X86_PAGESIZE;
|
|||
|
ULONG PageShift = X86_PAGESHIFT;
|
|||
|
ULONG LargePageMask = X86_LARGE_PAGE_MASK;
|
|||
|
ULONG LargePageSize = X86_LARGE_PAGE_SIZE;
|
|||
|
SYSTEM_INFO SystemInfo;
|
|||
|
|
|||
|
|
|||
|
|
|||
|
BOOL
|
|||
|
MapDumpFile(
|
|||
|
IN LPSTR FileName
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine maps the crash dump file.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
FileName - Supplies the file name to open.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Status of the operation. 0 is success.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
File = CreateFile(
|
|||
|
FileName,
|
|||
|
GENERIC_READ,
|
|||
|
FILE_SHARE_READ,
|
|||
|
NULL,
|
|||
|
OPEN_ALWAYS,
|
|||
|
FILE_ATTRIBUTE_NORMAL,
|
|||
|
NULL
|
|||
|
);
|
|||
|
|
|||
|
if (File == INVALID_HANDLE_VALUE) {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
MemMap = CreateFileMapping(
|
|||
|
File,
|
|||
|
NULL,
|
|||
|
PAGE_READONLY,
|
|||
|
0,
|
|||
|
0,
|
|||
|
NULL
|
|||
|
);
|
|||
|
|
|||
|
if (MemMap == 0) {
|
|||
|
CloseHandle( File );
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
DmpDumpBase = MapViewOfFile(
|
|||
|
MemMap,
|
|||
|
FILE_MAP_READ,
|
|||
|
0,
|
|||
|
0,
|
|||
|
0
|
|||
|
);
|
|||
|
|
|||
|
if (DmpDumpBase == NULL) {
|
|||
|
CloseHandle( MemMap );
|
|||
|
CloseHandle( File );
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
DmpDumpBaseUlong = (PULONG)DmpDumpBase;
|
|||
|
DumpHeader = (PDUMP_HEADER)DmpDumpBase;
|
|||
|
|
|||
|
if ((DumpHeader->Signature == 'RESU') &&
|
|||
|
(DumpHeader->ValidDump == 'PMUD')) {
|
|||
|
//
|
|||
|
// user mode crash dump file
|
|||
|
//
|
|||
|
DumpHeaderUser = (PUSERMODE_CRASHDUMP_HEADER)DmpDumpBase;
|
|||
|
UserModeDump = TRUE;
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
if ((DumpHeader->Signature == 'EGAP') &&
|
|||
|
(DumpHeader->ValidDump == 'PMUD')) {
|
|||
|
//
|
|||
|
// kernel mode crash dump file
|
|||
|
//
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
UnmapViewOfFile( DmpDumpBase );
|
|||
|
CloseHandle( MemMap );
|
|||
|
CloseHandle( File );
|
|||
|
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
BOOL
|
|||
|
DmpInitialize (
|
|||
|
IN LPSTR FileName,
|
|||
|
OUT PCONTEXT *Context,
|
|||
|
OUT PEXCEPTION_RECORD *Exception,
|
|||
|
OUT PVOID *DmpHeader
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine opens the crash dump file and returns the processor
|
|||
|
type and context record.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
FileName - Supplies the file name to open.
|
|||
|
|
|||
|
ProcessorType - Returns the processor type for the crash dump.
|
|||
|
|
|||
|
Context - Returns a pointer to the context record.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Status of the operation. 0 is success.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
DWORD fsize;
|
|||
|
PCRASH_MODULE CrashModule;
|
|||
|
ULONG i;
|
|||
|
|
|||
|
|
|||
|
GetSystemInfo( &SystemInfo );
|
|||
|
|
|||
|
if (!MapDumpFile( FileName )) {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
if (UserModeDump) {
|
|||
|
if (DumpHeaderUser->MajorVersion >= 4) {
|
|||
|
*Exception = (PEXCEPTION_RECORD) ( DmpDumpBase +
|
|||
|
DumpHeaderUser->DebugEventOffset +
|
|||
|
FIELD_OFFSET(DEBUG_EVENT, u.Exception.ExceptionRecord) );
|
|||
|
DumpThread = (PCRASH_THREAD) ( DmpDumpBase + DumpHeaderUser->ThreadStateOffset );
|
|||
|
|
|||
|
} else {
|
|||
|
*Exception = (PEXCEPTION_RECORD) ( DmpDumpBase + DumpHeaderUser->DebugEventOffset );
|
|||
|
DumpThread = NULL;
|
|||
|
}
|
|||
|
*Context = (PCONTEXT) ( DmpDumpBase + DumpHeaderUser->ThreadOffset );
|
|||
|
*DmpHeader = DumpHeaderUser;
|
|||
|
MemoryInfo = (PMEMORY_BASIC_INFORMATION) ( DmpDumpBase + DumpHeaderUser->MemoryRegionOffset );
|
|||
|
MemoryData = (PMEMORY_BASIC_INFORMATION) ( DmpDumpBase + DumpHeaderUser->DataOffset );
|
|||
|
DumpContext = *Context;
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
fsize = GetFileSize(File,NULL);
|
|||
|
if (strcmp( DmpDumpBase+fsize-8, "DUMPREF" ) == 0) {
|
|||
|
char *fname = malloc( fsize-sizeof(DUMP_HEADER) );
|
|||
|
//
|
|||
|
// point to the share name
|
|||
|
//
|
|||
|
char *p = DmpDumpBase + sizeof(DUMP_HEADER);
|
|||
|
|
|||
|
// copy the share name
|
|||
|
//
|
|||
|
strcpy( fname, p );
|
|||
|
p += strlen(p) + 1;
|
|||
|
|
|||
|
//
|
|||
|
// copy the file name
|
|||
|
//
|
|||
|
strcat( fname, p );
|
|||
|
p += strlen(p) + 1;
|
|||
|
|
|||
|
//
|
|||
|
// give it back to the caller
|
|||
|
//
|
|||
|
strcpy( FileName, fname );
|
|||
|
free( fname );
|
|||
|
|
|||
|
//
|
|||
|
// try to map it again
|
|||
|
//
|
|||
|
DmpUnInitialize();
|
|||
|
if (!MapDumpFile( FileName )) {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
DmpPhysicalMemoryBlock = (PPHYSICAL_MEMORY_DESCRIPTOR)&DmpDumpBaseUlong[DH_PHYSICAL_MEMORY_BLOCK];
|
|||
|
|
|||
|
DumpContext = (PCONTEXT)&DmpDumpBaseUlong[DH_CONTEXT_RECORD];
|
|||
|
*Context = DumpContext;
|
|||
|
*Exception = (PEXCEPTION_RECORD)&DmpDumpBaseUlong[DH_EXCEPTION_RECORD];
|
|||
|
*DmpHeader = DumpHeader;
|
|||
|
|
|||
|
switch (DumpHeader->MachineImageType) {
|
|||
|
case IMAGE_FILE_MACHINE_I386:
|
|||
|
ValidPteMask = X86_VALID;
|
|||
|
TransitionMask = X86_TRANSITION_MASK;
|
|||
|
TransitionCheck = X86_TRANSITION_CHECK;
|
|||
|
ValidPfnMask = X86_VALID_PFN_MASK;
|
|||
|
ValidPfnShift = X86_VALID_PFN_SHIFT;
|
|||
|
TransitionPfnMask = X86_TRANS_PFN_MASK;
|
|||
|
TransitionPfnShift = X86_TRANS_PFN_SHIFT;
|
|||
|
PdeShift = X86_PDE_SHIFT;
|
|||
|
PteShift = X86_PTE_SHIFT;
|
|||
|
PteMask = X86_PTE_MASK;
|
|||
|
PageSize = X86_PAGESIZE;
|
|||
|
PageShift = X86_PAGESHIFT;
|
|||
|
PhysicalAddressMask = X86_PHYSICAL_MASK;
|
|||
|
PhysicalAddressStart = X86_PHYSICAL_START;
|
|||
|
PhysicalAddressEnd = X86_PHYSICAL_END;
|
|||
|
LargePageMask = X86_LARGE_PAGE_MASK;
|
|||
|
LargePageSize = X86_LARGE_PAGE_SIZE;
|
|||
|
break;
|
|||
|
|
|||
|
case IMAGE_FILE_MACHINE_R4000:
|
|||
|
ValidPteMask = MIPS_VALID;
|
|||
|
TransitionMask = MIPS_TRANSITION_MASK;
|
|||
|
TransitionCheck = MIPS_TRANSITION_CHECK;
|
|||
|
ValidPfnMask = MIPS_VALID_PFN_MASK;
|
|||
|
ValidPfnShift = MIPS_VALID_PFN_SHIFT;
|
|||
|
TransitionPfnMask = MIPS_TRANS_PFN_MASK;
|
|||
|
TransitionPfnShift = MIPS_TRANS_PFN_SHIFT;
|
|||
|
PdeShift = MIPS_PDE_SHIFT;
|
|||
|
PteShift = MIPS_PTE_SHIFT;
|
|||
|
PteMask = MIPS_PTE_MASK;
|
|||
|
PageSize = MIPS_PAGESIZE;
|
|||
|
PageShift = MIPS_PAGESHIFT;
|
|||
|
PhysicalAddressMask = MIPS_PHYSICAL_MASK;
|
|||
|
PhysicalAddressStart = MIPS_PHYSICAL_START;
|
|||
|
PhysicalAddressEnd = MIPS_PHYSICAL_END;
|
|||
|
LargePageMask = 0;
|
|||
|
LargePageSize = 0;
|
|||
|
break;
|
|||
|
|
|||
|
case IMAGE_FILE_MACHINE_POWERPC:
|
|||
|
ValidPteMask = PPC_VALID;
|
|||
|
TransitionMask = PPC_TRANSITION_MASK;
|
|||
|
TransitionCheck = PPC_TRANSITION_CHECK;
|
|||
|
ValidPfnMask = PPC_VALID_PFN_MASK;
|
|||
|
ValidPfnShift = PPC_VALID_PFN_SHIFT;
|
|||
|
TransitionPfnMask = PPC_TRANS_PFN_MASK;
|
|||
|
TransitionPfnShift = PPC_TRANS_PFN_SHIFT;
|
|||
|
PdeShift = PPC_PDE_SHIFT;
|
|||
|
PteShift = PPC_PTE_SHIFT;
|
|||
|
PteMask = PPC_PTE_MASK;
|
|||
|
PageSize = PPC_PAGESIZE;
|
|||
|
PageShift = PPC_PAGESHIFT;
|
|||
|
PhysicalAddressMask = PPC_PHYSICAL_MASK;
|
|||
|
PhysicalAddressStart = PPC_PHYSICAL_START;
|
|||
|
PhysicalAddressEnd = PPC_PHYSICAL_END;
|
|||
|
LargePageMask = 0;
|
|||
|
LargePageSize = 0;
|
|||
|
break;
|
|||
|
|
|||
|
case IMAGE_FILE_MACHINE_ALPHA:
|
|||
|
ValidPteMask = ALPHA_VALID;
|
|||
|
TransitionMask = ALPHA_TRANSITION_MASK;
|
|||
|
TransitionCheck = ALPHA_TRANSITION_CHECK;
|
|||
|
ValidPfnMask = ALPHA_VALID_PFN_MASK;
|
|||
|
ValidPfnShift = ALPHA_VALID_PFN_SHIFT;
|
|||
|
TransitionPfnMask = ALPHA_TRANS_PFN_MASK;
|
|||
|
TransitionPfnShift = ALPHA_TRANS_PFN_SHIFT;
|
|||
|
PdeShift = ALPHA_PDE_SHIFT;
|
|||
|
PteShift = ALPHA_PTE_SHIFT;
|
|||
|
PteMask = ALPHA_PTE_MASK;
|
|||
|
PageSize = ALPHA_PAGESIZE;
|
|||
|
PageShift = ALPHA_PAGESHIFT;
|
|||
|
PhysicalAddressMask = ALPHA_PHYSICAL_MASK;
|
|||
|
PhysicalAddressStart = ALPHA_PHYSICAL_START;
|
|||
|
PhysicalAddressEnd = ALPHA_PHYSICAL_END;
|
|||
|
LargePageMask = 0;
|
|||
|
LargePageSize = 0;
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
|
|||
|
//
|
|||
|
// Unknown machine type.
|
|||
|
//
|
|||
|
UnmapViewOfFile( DmpDumpBase );
|
|||
|
CloseHandle( MemMap );
|
|||
|
CloseHandle( File );
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
DmpPdePage = PageToLocation ((DumpHeader->DirectoryTableBase & ValidPfnMask) >> ValidPfnShift);
|
|||
|
|
|||
|
if (DmpPdePage == NULL) {
|
|||
|
UnmapViewOfFile( DmpDumpBase );
|
|||
|
CloseHandle( MemMap );
|
|||
|
CloseHandle( File );
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
DmpUnInitialize (
|
|||
|
VOID
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine cleans up from DmpInitialize.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
UnmapViewOfFile( DmpDumpBase );
|
|||
|
CloseHandle( MemMap );
|
|||
|
CloseHandle( File );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
ULONG
|
|||
|
PteToPfn (
|
|||
|
IN ULONG Pte
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine returns the PFN for the specified PTE.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Pte - Supplies the PTE to examine.
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
PFN for the PTE.
|
|||
|
|
|||
|
0xFFFFFFFF is returned if the specified PTE is not valid.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
if (Pte & ValidPteMask) {
|
|||
|
return ((Pte & ValidPfnMask) >> ValidPfnShift);
|
|||
|
}
|
|||
|
if ((Pte & TransitionMask) == TransitionCheck) {
|
|||
|
return ((Pte & TransitionPfnMask) >> TransitionPfnShift);
|
|||
|
}
|
|||
|
|
|||
|
return 0xFFFFFFFF;
|
|||
|
}
|
|||
|
|
|||
|
PVOID
|
|||
|
PageToLocation (
|
|||
|
IN ULONG Page
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine returns the address of the physical page within the dump.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Page - Supplies the phyiscal page number to locate.
|
|||
|
|
|||
|
Globals:
|
|||
|
|
|||
|
DmpPhysicalMemoryBlock - Supplies a pointer to the physical memory block.
|
|||
|
|
|||
|
DmpDumpBase - Supplies the base of the mapped dump file.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Address of the specified physical page within the dump.
|
|||
|
|
|||
|
NULL is returned if the specified page cannot be located.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
ULONG frags;
|
|||
|
ULONG j;
|
|||
|
ULONG offset;
|
|||
|
|
|||
|
frags = DmpPhysicalMemoryBlock->NumberOfRuns;
|
|||
|
j = 0;
|
|||
|
offset = 1;
|
|||
|
while (j < frags) {
|
|||
|
if ((Page >= DmpPhysicalMemoryBlock->Run[j].BasePage) &&
|
|||
|
(Page < (DmpPhysicalMemoryBlock->Run[j].BasePage +
|
|||
|
DmpPhysicalMemoryBlock->Run[j].PageCount))) {
|
|||
|
offset += Page - DmpPhysicalMemoryBlock->Run[j].BasePage;
|
|||
|
return (PVOID)((PCHAR)DmpDumpBase + (offset * PageSize));
|
|||
|
}
|
|||
|
offset += DmpPhysicalMemoryBlock->Run[j].PageCount;
|
|||
|
j += 1;
|
|||
|
}
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
|
|||
|
ULONG
|
|||
|
GetPhysicalPage (
|
|||
|
IN PVOID PhysicalAddress
|
|||
|
)
|
|||
|
{
|
|||
|
return (((ULONG)PhysicalAddress & PhysicalAddressMask) >> PageShift);
|
|||
|
}
|
|||
|
|
|||
|
PVOID
|
|||
|
VaToLocation (
|
|||
|
IN PVOID VirtualAddress
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine returns the address of the specified virtual address
|
|||
|
within the dump.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
VirtualAddress - Supplies the virtual address to locate.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Address of the specified virtual address within the dump.
|
|||
|
|
|||
|
NULL is returned if the address cannot be located.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
ULONG PdeOffset;
|
|||
|
ULONG PteOffset;
|
|||
|
PULONG PtePage;
|
|||
|
PVOID VaPage;
|
|||
|
ULONG Pfn;
|
|||
|
ULONG i;
|
|||
|
ULONG Offset;
|
|||
|
|
|||
|
|
|||
|
if (UserModeDump) {
|
|||
|
Offset = 0;
|
|||
|
for (i=0; i<DumpHeaderUser->MemoryRegionCount; i++) {
|
|||
|
if ((ULONG)VirtualAddress >= (ULONG)MemoryInfo[i].BaseAddress &&
|
|||
|
(ULONG)VirtualAddress < (ULONG)MemoryInfo[i].BaseAddress+MemoryInfo[i].RegionSize) {
|
|||
|
return (PVOID)((ULONG)MemoryData+Offset+((ULONG)VirtualAddress-(ULONG)MemoryInfo[i].BaseAddress));
|
|||
|
}
|
|||
|
Offset += MemoryInfo[i].RegionSize;
|
|||
|
}
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
|
|||
|
if (((ULONG)VirtualAddress >= PhysicalAddressStart) &&
|
|||
|
((ULONG)VirtualAddress < PhysicalAddressEnd)) {
|
|||
|
|
|||
|
VaPage = PageToLocation (GetPhysicalPage (VirtualAddress));
|
|||
|
|
|||
|
return (PVOID)((PCHAR)VaPage + ((ULONG)VirtualAddress & (PageSize - 1)));
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
PdeOffset = (ULONG)VirtualAddress >> PdeShift;
|
|||
|
PteOffset = ((ULONG)VirtualAddress >> PteShift) & PteMask;
|
|||
|
|
|||
|
if (DmpPdePage[PdeOffset] & ValidPteMask) {
|
|||
|
|
|||
|
//
|
|||
|
// PDE is valid. Check for Large Pages.
|
|||
|
//
|
|||
|
|
|||
|
if (DmpPdePage[PdeOffset] & LargePageMask) {
|
|||
|
|
|||
|
Pfn = ((DmpPdePage[PdeOffset] & ~(LargePageSize - 1)) |
|
|||
|
((ULONG)VirtualAddress & (LargePageSize - 1))) >> PageShift;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// Lookup page via PTE.
|
|||
|
//
|
|||
|
|
|||
|
PtePage = PageToLocation(PteToPfn(DmpPdePage[PdeOffset]));
|
|||
|
if (PtePage == NULL) {
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
|
|||
|
Pfn = PteToPfn( PtePage[PteOffset] );
|
|||
|
if (Pfn == 0xFFFFFFFF) {
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
VaPage = PageToLocation( Pfn );
|
|||
|
|
|||
|
if (VaPage == NULL) {
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
return (PVOID)((PCHAR)VaPage + ((ULONG)VirtualAddress &
|
|||
|
(PageSize - 1)));
|
|||
|
}
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
PVOID
|
|||
|
PhysicalToLocation (
|
|||
|
IN PVOID PhysicalAddress
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine returns the address of the specified virtual address
|
|||
|
within the dump.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
PhysicalAddress - Supplies the virtual address to locate.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Address of the specified virtual address within the dump.
|
|||
|
|
|||
|
NULL is returned if the address cannot be located.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
ULONG Page;
|
|||
|
PVOID Base;
|
|||
|
|
|||
|
Page = (ULONG)PhysicalAddress >> PageShift;
|
|||
|
|
|||
|
Base = PageToLocation (Page);
|
|||
|
|
|||
|
if (!Base) {
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
|
|||
|
return ((PVOID)((PCHAR)Base + ((ULONG)PhysicalAddress & (PageSize - 1))));
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
DmpReadMemory (
|
|||
|
IN PVOID BaseAddress,
|
|||
|
IN PVOID Buffer,
|
|||
|
IN ULONG Size
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
BaseAddress - Supplies the virtual address to read memory from.
|
|||
|
|
|||
|
Buffer - Supplies a pointer to the buffer to put the results from the read.
|
|||
|
|
|||
|
Size - Supplies the size in bytes to copy to the buffer.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Returns number of bytes copied to the buffer.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PCHAR Location;
|
|||
|
PCHAR OutBuffer;
|
|||
|
ULONG BytesCopied = 0;
|
|||
|
PCHAR VirtualAddress;
|
|||
|
|
|||
|
|
|||
|
__try {
|
|||
|
VirtualAddress = (PCHAR)BaseAddress;
|
|||
|
OutBuffer = (PCHAR)Buffer;
|
|||
|
|
|||
|
while ((Location = VaToLocation(VirtualAddress)) && (Size > 0)) {
|
|||
|
if (OutBuffer) {
|
|||
|
*OutBuffer++ = *Location;
|
|||
|
}
|
|||
|
Size -= 1;
|
|||
|
BytesCopied += 1;
|
|||
|
VirtualAddress += 1;
|
|||
|
}
|
|||
|
} __except(EXCEPTION_EXECUTE_HANDLER) {
|
|||
|
BytesCopied = 0;
|
|||
|
}
|
|||
|
|
|||
|
return BytesCopied;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
DmpWriteMemory (
|
|||
|
IN PVOID BaseAddress,
|
|||
|
IN PVOID Buffer,
|
|||
|
IN ULONG Size
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
BaseAddress - Supplies the virtual address to write memory to.
|
|||
|
|
|||
|
Buffer - Supplies a pointer to the buffer to copy to the base address.
|
|||
|
|
|||
|
Size - Supplies the size in bytes to copy to the buffer.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Returns number of bytes copied to the buffer.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PCHAR Location;
|
|||
|
PCHAR OutBuffer;
|
|||
|
ULONG BytesCopied = 0;
|
|||
|
PCHAR VirtualAddress;
|
|||
|
ULONG Protect;
|
|||
|
|
|||
|
|
|||
|
__try {
|
|||
|
VirtualAddress = (PCHAR)BaseAddress;
|
|||
|
OutBuffer = (PCHAR)Buffer;
|
|||
|
|
|||
|
while (Size) {
|
|||
|
Location = VaToLocation( VirtualAddress );
|
|||
|
if (!Location) {
|
|||
|
break;
|
|||
|
}
|
|||
|
VirtualProtect( Location, SystemInfo.dwPageSize, PAGE_WRITECOPY, &Protect );
|
|||
|
*Location = *OutBuffer++;
|
|||
|
Size -= 1;
|
|||
|
BytesCopied += 1;
|
|||
|
VirtualAddress += 1;
|
|||
|
}
|
|||
|
} __except(EXCEPTION_EXECUTE_HANDLER) {
|
|||
|
BytesCopied = 0;
|
|||
|
}
|
|||
|
|
|||
|
return BytesCopied;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
DmpReadPhysicalMemory (
|
|||
|
IN PVOID BaseAddress,
|
|||
|
IN PVOID Buffer,
|
|||
|
IN ULONG Size
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
BaseAddress - Supplies the physical address to read memory from.
|
|||
|
|
|||
|
Buffer - Supplies a pointer to the buffer to put the results from the read.
|
|||
|
|
|||
|
Size - Supplies the size in bytes to copy to the buffer.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Returns number of bytes copied to the buffer.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PCHAR Location;
|
|||
|
PCHAR OutBuffer;
|
|||
|
ULONG BytesCopied = 0;
|
|||
|
PCHAR PhysicalAddress;
|
|||
|
|
|||
|
|
|||
|
if (UserModeDump) {
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
__try {
|
|||
|
PhysicalAddress = (PCHAR)BaseAddress;
|
|||
|
OutBuffer = (PCHAR)Buffer;
|
|||
|
|
|||
|
while ((Location = PhysicalToLocation(PhysicalAddress)) && (Size > 0)) {
|
|||
|
*OutBuffer++ = *Location;
|
|||
|
Size -= 1;
|
|||
|
BytesCopied += 1;
|
|||
|
PhysicalAddress += 1;
|
|||
|
}
|
|||
|
} __except(EXCEPTION_EXECUTE_HANDLER) {
|
|||
|
BytesCopied = 0;
|
|||
|
}
|
|||
|
|
|||
|
return BytesCopied;
|
|||
|
}
|
|||
|
|
|||
|
DWORD
|
|||
|
DmpWritePhysicalMemory (
|
|||
|
IN PVOID BaseAddress,
|
|||
|
IN PVOID Buffer,
|
|||
|
IN ULONG Size
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
BaseAddress - Supplies the physical address to write memory to.
|
|||
|
|
|||
|
Buffer - Supplies a pointer to the buffer to copy to the base address.
|
|||
|
|
|||
|
Size - Supplies the size in bytes to copy to the buffer.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Returns number of bytes copied from the buffer.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PCHAR Location;
|
|||
|
PCHAR OutBuffer;
|
|||
|
ULONG BytesCopied = 0;
|
|||
|
PCHAR PhysicalAddress;
|
|||
|
ULONG Protect;
|
|||
|
|
|||
|
|
|||
|
if (UserModeDump) {
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
__try {
|
|||
|
PhysicalAddress = (PCHAR)BaseAddress;
|
|||
|
OutBuffer = (PCHAR)Buffer;
|
|||
|
|
|||
|
while (Size) {
|
|||
|
Location = PhysicalToLocation( PhysicalAddress );
|
|||
|
if (!Location) {
|
|||
|
break;
|
|||
|
}
|
|||
|
VirtualProtect( Location, SystemInfo.dwPageSize, PAGE_WRITECOPY, &Protect );
|
|||
|
*Location = *OutBuffer++;
|
|||
|
Size -= 1;
|
|||
|
BytesCopied += 1;
|
|||
|
PhysicalAddress += 1;
|
|||
|
}
|
|||
|
} __except(EXCEPTION_EXECUTE_HANDLER) {
|
|||
|
BytesCopied = 0;
|
|||
|
}
|
|||
|
|
|||
|
return BytesCopied;
|
|||
|
}
|
|||
|
|
|||
|
BOOL
|
|||
|
DmpReadControlSpace(
|
|||
|
USHORT Processor,
|
|||
|
PVOID TargetBaseAddress,
|
|||
|
PVOID UserInterfaceBuffer,
|
|||
|
ULONG TransferCount,
|
|||
|
PULONG ActualBytesRead
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine accesses control space out of the dump file.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Status of the operation. 1 is success.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
BOOL rval;
|
|||
|
|
|||
|
if (UserModeDump) {
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
switch (DumpHeader->MachineImageType) {
|
|||
|
case IMAGE_FILE_MACHINE_I386:
|
|||
|
rval = DmpReadControlSpaceX86(
|
|||
|
Processor,
|
|||
|
TargetBaseAddress,
|
|||
|
UserInterfaceBuffer,
|
|||
|
TransferCount,
|
|||
|
ActualBytesRead
|
|||
|
);
|
|||
|
break;
|
|||
|
|
|||
|
case IMAGE_FILE_MACHINE_R4000:
|
|||
|
rval = DmpReadControlSpaceMip(
|
|||
|
Processor,
|
|||
|
TargetBaseAddress,
|
|||
|
UserInterfaceBuffer,
|
|||
|
TransferCount,
|
|||
|
ActualBytesRead
|
|||
|
);
|
|||
|
break;
|
|||
|
|
|||
|
case IMAGE_FILE_MACHINE_ALPHA:
|
|||
|
rval = DmpReadControlSpaceAlp(
|
|||
|
Processor,
|
|||
|
TargetBaseAddress,
|
|||
|
UserInterfaceBuffer,
|
|||
|
TransferCount,
|
|||
|
ActualBytesRead
|
|||
|
);
|
|||
|
break;
|
|||
|
|
|||
|
case IMAGE_FILE_MACHINE_POWERPC:
|
|||
|
rval = DmpReadControlSpacePPC(
|
|||
|
Processor,
|
|||
|
TargetBaseAddress,
|
|||
|
UserInterfaceBuffer,
|
|||
|
TransferCount,
|
|||
|
ActualBytesRead
|
|||
|
);
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
rval = FALSE;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
return rval;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
BOOL
|
|||
|
DmpGetContext(
|
|||
|
IN ULONG Processor, // for user mode dumps this is a thread index
|
|||
|
OUT PVOID Context
|
|||
|
)
|
|||
|
{
|
|||
|
BOOL rval;
|
|||
|
ULONG MachineImageType;
|
|||
|
|
|||
|
|
|||
|
if (UserModeDump) {
|
|||
|
MachineImageType = DumpHeaderUser->MachineImageType;
|
|||
|
} else {
|
|||
|
MachineImageType = DumpHeader->MachineImageType;
|
|||
|
}
|
|||
|
|
|||
|
switch (MachineImageType) {
|
|||
|
case IMAGE_FILE_MACHINE_I386:
|
|||
|
rval = DmpGetContextX86( Processor, Context );
|
|||
|
break;
|
|||
|
|
|||
|
case IMAGE_FILE_MACHINE_R4000:
|
|||
|
rval = DmpGetContextMip( Processor, Context );
|
|||
|
break;
|
|||
|
|
|||
|
case IMAGE_FILE_MACHINE_ALPHA:
|
|||
|
rval = DmpGetContextAlp( Processor, Context );
|
|||
|
break;
|
|||
|
|
|||
|
case IMAGE_FILE_MACHINE_POWERPC:
|
|||
|
rval = DmpGetContextPPC( Processor, Context );
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
rval = FALSE;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
return rval;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
INT
|
|||
|
DmpGetCurrentProcessor(
|
|||
|
VOID
|
|||
|
)
|
|||
|
{
|
|||
|
INT Processor;
|
|||
|
|
|||
|
|
|||
|
if (UserModeDump) {
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
switch (DumpHeader->MachineImageType) {
|
|||
|
case IMAGE_FILE_MACHINE_I386:
|
|||
|
Processor = DmpGetCurrentProcessorX86();
|
|||
|
break;
|
|||
|
|
|||
|
case IMAGE_FILE_MACHINE_R4000:
|
|||
|
Processor = DmpGetCurrentProcessorMip();
|
|||
|
break;
|
|||
|
|
|||
|
case IMAGE_FILE_MACHINE_ALPHA:
|
|||
|
Processor = DmpGetCurrentProcessorAlp();
|
|||
|
break;
|
|||
|
|
|||
|
case IMAGE_FILE_MACHINE_POWERPC:
|
|||
|
Processor = DmpGetCurrentProcessorPPC();
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
Processor = -1;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
return Processor;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
BOOL
|
|||
|
DmpCreateUserDump(
|
|||
|
LPSTR CrashDumpName,
|
|||
|
PDMP_CREATE_DUMP_CALLBACK DmpCallback,
|
|||
|
PVOID lpv
|
|||
|
)
|
|||
|
{
|
|||
|
OSVERSIONINFO OsVersion;
|
|||
|
USERMODE_CRASHDUMP_HEADER DumpHeader;
|
|||
|
DWORD cb;
|
|||
|
HANDLE hFile;
|
|||
|
BOOL rval;
|
|||
|
PVOID DumpData;
|
|||
|
DWORD DumpDataLength;
|
|||
|
ULONG Biggest = 0;
|
|||
|
|
|||
|
|
|||
|
hFile = CreateFile(
|
|||
|
CrashDumpName,
|
|||
|
GENERIC_READ | GENERIC_WRITE,
|
|||
|
0,
|
|||
|
NULL,
|
|||
|
CREATE_ALWAYS,
|
|||
|
0,
|
|||
|
NULL
|
|||
|
);
|
|||
|
|
|||
|
if (hFile == INVALID_HANDLE_VALUE) {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
OsVersion.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
|||
|
GetVersionEx( &OsVersion );
|
|||
|
ZeroMemory( &DumpHeader, sizeof(USERMODE_CRASHDUMP_HEADER) );
|
|||
|
DumpHeader.Signature = 'RESU';
|
|||
|
DumpHeader.ValidDump = 'PMUD';
|
|||
|
DumpHeader.MajorVersion = OsVersion.dwMajorVersion;
|
|||
|
DumpHeader.MinorVersion = OsVersion.dwMinorVersion;
|
|||
|
#if defined(_M_IX86)
|
|||
|
DumpHeader.MachineImageType = IMAGE_FILE_MACHINE_I386;
|
|||
|
#elif defined(_M_MRX000)
|
|||
|
DumpHeader.MachineImageType = IMAGE_FILE_MACHINE_R4000;
|
|||
|
#elif defined(_M_ALPHA)
|
|||
|
DumpHeader.MachineImageType = IMAGE_FILE_MACHINE_ALPHA;
|
|||
|
#elif defined(_M_PPC)
|
|||
|
DumpHeader.MachineImageType = IMAGE_FILE_MACHINE_POWERPC;
|
|||
|
#else
|
|||
|
#error( "unknown target machine" );
|
|||
|
#endif
|
|||
|
|
|||
|
if (!WriteFile( hFile, &DumpHeader, sizeof(DumpHeader), &cb, NULL )) {
|
|||
|
goto bad_file;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// write the debug event
|
|||
|
//
|
|||
|
DumpHeader.DebugEventOffset = SetFilePointer( hFile, 0, 0, FILE_CURRENT );
|
|||
|
DmpCallback( DMP_DEBUG_EVENT, &DumpData, &DumpDataLength, lpv );
|
|||
|
if (!WriteFile( hFile, DumpData, sizeof(DEBUG_EVENT), &cb, NULL )) {
|
|||
|
goto bad_file;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// write the memory map
|
|||
|
//
|
|||
|
DumpHeader.MemoryRegionOffset = SetFilePointer( hFile, 0, 0, FILE_CURRENT );
|
|||
|
do {
|
|||
|
__try {
|
|||
|
rval = DmpCallback(
|
|||
|
DMP_MEMORY_BASIC_INFORMATION,
|
|||
|
&DumpData,
|
|||
|
&DumpDataLength,
|
|||
|
lpv
|
|||
|
);
|
|||
|
} __except (EXCEPTION_EXECUTE_HANDLER) {
|
|||
|
rval = FALSE;
|
|||
|
}
|
|||
|
if (rval) {
|
|||
|
DumpHeader.MemoryRegionCount += 1;
|
|||
|
if (!WriteFile( hFile, DumpData, sizeof(MEMORY_BASIC_INFORMATION), &cb, NULL )) {
|
|||
|
goto bad_file;
|
|||
|
}
|
|||
|
Biggest = max( Biggest, ((PMEMORY_BASIC_INFORMATION)DumpData)->RegionSize );
|
|||
|
}
|
|||
|
} while( rval );
|
|||
|
|
|||
|
//
|
|||
|
// write the thread contexts
|
|||
|
//
|
|||
|
DumpHeader.ThreadOffset = SetFilePointer( hFile, 0, 0, FILE_CURRENT );
|
|||
|
do {
|
|||
|
__try {
|
|||
|
rval = DmpCallback(
|
|||
|
DMP_THREAD_CONTEXT,
|
|||
|
&DumpData,
|
|||
|
&DumpDataLength,
|
|||
|
lpv
|
|||
|
);
|
|||
|
} __except (EXCEPTION_EXECUTE_HANDLER) {
|
|||
|
rval = FALSE;
|
|||
|
}
|
|||
|
if (rval) {
|
|||
|
if (!WriteFile( hFile, DumpData, sizeof(CONTEXT), &cb, NULL )) {
|
|||
|
goto bad_file;
|
|||
|
}
|
|||
|
DumpHeader.ThreadCount += 1;
|
|||
|
}
|
|||
|
} while( rval );
|
|||
|
|
|||
|
//
|
|||
|
// write the thread states
|
|||
|
//
|
|||
|
DumpHeader.ThreadStateOffset = SetFilePointer( hFile, 0, 0, FILE_CURRENT );
|
|||
|
do {
|
|||
|
__try {
|
|||
|
rval = DmpCallback(
|
|||
|
DMP_THREAD_STATE,
|
|||
|
&DumpData,
|
|||
|
&DumpDataLength,
|
|||
|
lpv
|
|||
|
);
|
|||
|
} __except (EXCEPTION_EXECUTE_HANDLER) {
|
|||
|
rval = FALSE;
|
|||
|
}
|
|||
|
if (rval) {
|
|||
|
if (!WriteFile( hFile, DumpData, sizeof(CRASH_THREAD), &cb, NULL )) {
|
|||
|
goto bad_file;
|
|||
|
}
|
|||
|
}
|
|||
|
} while( rval );
|
|||
|
|
|||
|
//
|
|||
|
// write the module table
|
|||
|
//
|
|||
|
DumpHeader.ModuleOffset = SetFilePointer( hFile, 0, 0, FILE_CURRENT );
|
|||
|
do {
|
|||
|
__try {
|
|||
|
rval = DmpCallback(
|
|||
|
DMP_MODULE,
|
|||
|
&DumpData,
|
|||
|
&DumpDataLength,
|
|||
|
lpv
|
|||
|
);
|
|||
|
} __except (EXCEPTION_EXECUTE_HANDLER) {
|
|||
|
rval = FALSE;
|
|||
|
}
|
|||
|
if (rval) {
|
|||
|
if (!WriteFile(
|
|||
|
hFile,
|
|||
|
DumpData,
|
|||
|
sizeof(CRASH_MODULE) + ((PCRASH_MODULE)DumpData)->ImageNameLength,
|
|||
|
&cb,
|
|||
|
NULL
|
|||
|
)) {
|
|||
|
goto bad_file;
|
|||
|
}
|
|||
|
DumpHeader.ModuleCount += 1;
|
|||
|
}
|
|||
|
} while( rval );
|
|||
|
|
|||
|
//
|
|||
|
// write the virtual memory
|
|||
|
//
|
|||
|
DumpHeader.DataOffset = SetFilePointer( hFile, 0, 0, FILE_CURRENT );
|
|||
|
do {
|
|||
|
__try {
|
|||
|
rval = DmpCallback(
|
|||
|
DMP_MEMORY_DATA,
|
|||
|
&DumpData,
|
|||
|
&DumpDataLength,
|
|||
|
lpv
|
|||
|
);
|
|||
|
} __except (EXCEPTION_EXECUTE_HANDLER) {
|
|||
|
rval = FALSE;
|
|||
|
}
|
|||
|
if (rval) {
|
|||
|
if (!WriteFile(
|
|||
|
hFile,
|
|||
|
DumpData,
|
|||
|
DumpDataLength,
|
|||
|
&cb,
|
|||
|
NULL
|
|||
|
)) {
|
|||
|
goto bad_file;
|
|||
|
}
|
|||
|
}
|
|||
|
} while( rval );
|
|||
|
|
|||
|
//
|
|||
|
// re-write the dump header
|
|||
|
//
|
|||
|
SetFilePointer( hFile, 0, 0, FILE_BEGIN );
|
|||
|
if (!WriteFile( hFile, &DumpHeader, sizeof(DumpHeader), &cb, NULL )) {
|
|||
|
goto bad_file;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// close the file
|
|||
|
//
|
|||
|
CloseHandle( hFile );
|
|||
|
|
|||
|
return TRUE;
|
|||
|
|
|||
|
bad_file:
|
|||
|
|
|||
|
CloseHandle( hFile );
|
|||
|
DeleteFile( CrashDumpName );
|
|||
|
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
BOOL
|
|||
|
DmpGetThread(
|
|||
|
IN ULONG Processor,
|
|||
|
OUT PCRASH_THREAD Thread
|
|||
|
)
|
|||
|
{
|
|||
|
DWORD StartAddr;
|
|||
|
|
|||
|
if (!UserModeDump) {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
if (Processor > DumpHeaderUser->ThreadCount-1) {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
if (!DumpThread) {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
CopyMemory( Thread, &((PCRASH_THREAD)DumpThread)[Processor], sizeof(CRASH_THREAD) );
|
|||
|
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|