2020-09-30 17:12:29 +02:00

1422 lines
33 KiB
C
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
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;
}