mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1478 lines
37 KiB
1478 lines
37 KiB
/*++
|
|
|
|
Copyright (c) 1995 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
dumpexam.c
|
|
|
|
Abstract:
|
|
|
|
This module implements the NT crashdump analysis tool.
|
|
|
|
Author:
|
|
|
|
Wesley Witt (wesw) 8-Mar-1995
|
|
|
|
Environment:
|
|
|
|
NT 3.51
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
#include <ntdbg.h>
|
|
#include <ntos.h>
|
|
#include <windows.h>
|
|
#include <imagehlp.h>
|
|
#include <crash.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <disasm.h>
|
|
#include "dumpexam.h"
|
|
|
|
|
|
#define KERNEL_MODULE_NAME "nt"
|
|
#define KERNEL_IMAGE_NAME "ntoskrnl.exe"
|
|
#define KERNEL_IMAGE_NAME_MP "ntkrnlmp.exe"
|
|
#define HAL_IMAGE_NAME "hal.dll"
|
|
#define HAL_MODULE_NAME "hal"
|
|
|
|
|
|
PKPRCB KiProcessors[MAXIMUM_PROCESSORS];
|
|
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;
|
|
|
|
#include <bugcodes.dbg>
|
|
|
|
struct DIS *pdis;
|
|
CHAR CrashDumpFile[MAX_PATH];
|
|
CHAR SymbolPath[MAX_PATH];
|
|
CHAR OutputFileName[MAX_PATH];
|
|
FILE *FileOut;
|
|
ULONG PageSize;
|
|
BOOL Verbose;
|
|
BOOL PrintOnly;
|
|
BOOL QuickCheck;
|
|
DWORD ErrCnt;
|
|
PDUMP_HEADER DmpHeader;
|
|
PVOID DmpContext;
|
|
PVOID ExtContext;
|
|
PGET_REGISTER_VALUE GetRegisterValue;
|
|
PPRINT_REGISTERS PrintRegisters;
|
|
PPRINT_STACK_TRACE PrintStackTrace;
|
|
PBUG_CHECK_HEURISTICS BugCheckHeuristics;
|
|
PGET_CONTEXT GetContext;
|
|
|
|
#define MAX_SYMNAME_SIZE 1024
|
|
CHAR symBuffer[sizeof(IMAGEHLP_SYMBOL)+MAX_SYMNAME_SIZE];
|
|
PIMAGEHLP_SYMBOL sym = (PIMAGEHLP_SYMBOL) symBuffer;
|
|
|
|
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,PEXCEPTION_RECORD);
|
|
ULONG GetPfn(LPVOID);
|
|
BOOL GetProcessModules(HANDLE);
|
|
BOOL LoadKd(LPSTR);
|
|
VOID PrintModuleLoad(PDUMP_HEADER,ULONG,ULONG);
|
|
ULONG DisAddrToSymbol(struct DIS*,ULONG,char*,size_t,DWORD*);
|
|
ULONG DisFixupToSymbol(struct DIS*,ULONG,size_t,char*,size_t,DWORD*);
|
|
UINT MyGetDriveType(CHAR);
|
|
CHAR LocateCdRomDrive(VOID);
|
|
BOOL IsCdRomInDrive(CHAR,LPSTR);
|
|
BOOL DoesFileExist(LPSTR);
|
|
DWORD EstablishSymbolPath(PDUMP_HEADER,LPSTR);
|
|
BOOL GetCrashDumpName(LPSTR,DWORD);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int _cdecl
|
|
main(
|
|
int argc,
|
|
char * argv[]
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Main entry point for the dumpexam check tool.
|
|
|
|
Arguments:
|
|
|
|
Standard c args.
|
|
|
|
Return Value:
|
|
|
|
Error count.
|
|
|
|
--*/
|
|
|
|
{
|
|
PEXCEPTION_RECORD Exception;
|
|
DWORD Displacement;
|
|
LPSTR p;
|
|
LPSTR KdExt;
|
|
PVOID Context;
|
|
ULONG i;
|
|
|
|
|
|
GetCommandLineArgs();
|
|
if (!CrashDumpFile[0]) {
|
|
if (!GetCrashDumpName( CrashDumpFile, sizeof(CrashDumpFile))) {
|
|
fprintf( stderr, "missing dump file name\n" );
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
if (!OutputFileName[0]) {
|
|
GetEnvironmentVariable( "windir", OutputFileName, sizeof(OutputFileName) );
|
|
strcat( OutputFileName, "\\memory.txt" );
|
|
}
|
|
FileOut = fopen( OutputFileName, "w" );
|
|
if (!FileOut) {
|
|
return 1;
|
|
}
|
|
|
|
if (!DmpInitialize( CrashDumpFile, (PCONTEXT*)&DmpContext, &Exception, &DmpHeader )) {
|
|
fprintf( stderr, "could not initialize dump file\n" );
|
|
DmpUnInitialize();
|
|
return 1;
|
|
}
|
|
|
|
EstablishSymbolPath( DmpHeader, SymbolPath );
|
|
|
|
Context = LocalAlloc( LPTR, MAX_CONTEXT_SIZE );
|
|
|
|
switch (DmpHeader->MachineImageType) {
|
|
case IMAGE_FILE_MACHINE_I386:
|
|
PageSize = 4096;
|
|
KdExt = "kdextx86.dll";
|
|
PrintStackTrace = PrintStackTraceX86;
|
|
GetRegisterValue = GetRegisterValueX86;
|
|
PrintRegisters = PrintRegistersX86;
|
|
BugCheckHeuristics = BugCheckHeuristicsX86;
|
|
GetContext = GetContextX86;
|
|
pdis = DisNew( archtX86 );
|
|
break;
|
|
|
|
case IMAGE_FILE_MACHINE_R4000:
|
|
PageSize = 4096;
|
|
KdExt = "kdextmip.dll";
|
|
PrintStackTrace = PrintStackTraceMIPS;
|
|
GetRegisterValue = GetRegisterValueMIPS;
|
|
PrintRegisters = PrintRegistersMIPS;
|
|
BugCheckHeuristics = BugCheckHeuristicsMIPS;
|
|
GetContext = GetContextMIPS;
|
|
pdis = DisNew( archtMips );
|
|
break;
|
|
|
|
case IMAGE_FILE_MACHINE_ALPHA:
|
|
PageSize = 8192;
|
|
KdExt = "kdextalp.dll";
|
|
PrintStackTrace = PrintStackTraceALPHA;
|
|
GetRegisterValue = GetRegisterValueALPHA;
|
|
PrintRegisters = PrintRegistersALPHA;
|
|
BugCheckHeuristics = BugCheckHeuristicsALPHA;
|
|
GetContext = GetContextALPHA;
|
|
pdis = DisNew( archtAlphaAxp );
|
|
break;
|
|
|
|
case IMAGE_FILE_MACHINE_POWERPC:
|
|
PageSize = 4096;
|
|
KdExt = "kdextppc.dll";
|
|
PrintStackTrace = PrintStackTracePPC;
|
|
GetRegisterValue = GetRegisterValuePPC;
|
|
PrintRegisters = PrintRegistersPPC;
|
|
BugCheckHeuristics = BugCheckHeuristicsPPC;
|
|
GetContext = GetContextPPC;
|
|
pdis = DisNew( archtPowerPc );
|
|
break;
|
|
|
|
default:
|
|
fprintf( stderr, "unsupported processor type\n" );
|
|
ExitProcess( 0 );
|
|
break;
|
|
}
|
|
|
|
SetSymbolCallback( pdis, DisAddrToSymbol, DisFixupToSymbol );
|
|
|
|
PrintHeader( CrashDumpFile, DmpHeader, Exception );
|
|
|
|
if (PrintOnly) {
|
|
return 0;
|
|
}
|
|
|
|
sym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL);
|
|
sym->MaxNameLength = MAX_SYMNAME_SIZE;
|
|
SymSetOptions( SYMOPT_UNDNAME | SYMOPT_CASE_INSENSITIVE );
|
|
SymInitialize( DmpHeader, NULL, FALSE );
|
|
|
|
if (SymbolPath[0]) {
|
|
SymSetSearchPath( DmpHeader, SymbolPath );
|
|
}
|
|
|
|
PrintHeading( "Symbol File Load Log" );
|
|
GetProcessModules( DmpHeader );
|
|
|
|
if (SymGetSymFromName( DmpHeader, "KiProcessorBlock", sym )) {
|
|
DmpReadMemory( (PVOID)sym->Address, &KiProcessors, sizeof(KiProcessors) );
|
|
if (DmpHeader->MachineImageType == IMAGE_FILE_MACHINE_ALPHA) {
|
|
if (SymGetSymFromName( DmpHeader, "KiPcrBaseAddress", sym )) {
|
|
KiPcrBaseAddress = sym->Address;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!LoadKd( KdExt )) {
|
|
fprintf( FileOut, "**** could not load kernel debugger extenion dll [ %s ]\n", KdExt );
|
|
} else {
|
|
GetContext( (ULONG)DmpGetCurrentProcessor(), Context );
|
|
DoExtension( "drivers", "", 0, (DWORD)GetRegisterValue( Context, REG_IP ) );
|
|
DoExtension( "locks", "-p -v -d", 0, (DWORD)GetRegisterValue( Context, REG_IP ) );
|
|
DoExtension( "memusage", "", 0, (DWORD)GetRegisterValue( Context, REG_IP ) );
|
|
DoExtension( "vm", "", 0, (DWORD)GetRegisterValue( Context, REG_IP ) );
|
|
DoExtension( "errlog", "", 0, (DWORD)GetRegisterValue( Context, REG_IP ) );
|
|
DoExtension( "irpzone", "full", 0, (DWORD)GetRegisterValue( Context, REG_IP ) );
|
|
DoExtension( "process", "0 0", 0, (DWORD)GetRegisterValue( Context, REG_IP ) );
|
|
DoExtension( "process", "0 7", 0, (DWORD)GetRegisterValue( Context, REG_IP ) );
|
|
for (i=0; i<DmpHeader->NumberProcessors; i++) {
|
|
GetContext( i, Context );
|
|
DoExtension( "process", "", i, (DWORD)GetRegisterValue( Context, REG_IP ) );
|
|
DoExtension( "thread", "", i, (DWORD)GetRegisterValue( Context, REG_IP ) );
|
|
PrintRegisters( i );
|
|
PrintStackTrace( DmpHeader, i );
|
|
DoDisassemble( (DWORD)GetRegisterValue( Context, REG_IP ) );
|
|
if (i == (ULONG)DmpGetCurrentProcessor()) {
|
|
BugCheckHeuristics( DmpHeader , i );
|
|
}
|
|
}
|
|
}
|
|
|
|
fprintf( FileOut, "\n" );
|
|
|
|
LocalFree( Context );
|
|
|
|
DmpUnInitialize();
|
|
|
|
return ErrCnt;
|
|
}
|
|
|
|
|
|
BOOL
|
|
GetModnameFromImage(
|
|
DWORD lpBaseOfDll,
|
|
LPSTR lpName
|
|
)
|
|
{
|
|
#define ReadMem(b,s) DmpReadMemory( (LPVOID)(address), (b), (s) ); address += (s)
|
|
|
|
IMAGE_DEBUG_DIRECTORY DebugDir;
|
|
PIMAGE_DEBUG_MISC pMisc;
|
|
PIMAGE_DEBUG_MISC pT;
|
|
DWORD rva;
|
|
int nDebugDirs;
|
|
int i;
|
|
int j;
|
|
int l;
|
|
BOOL rVal = FALSE;
|
|
PVOID pExeName;
|
|
IMAGE_NT_HEADERS nh;
|
|
IMAGE_DOS_HEADER dh;
|
|
IMAGE_ROM_OPTIONAL_HEADER rom;
|
|
DWORD address;
|
|
DWORD sig;
|
|
PIMAGE_SECTION_HEADER pSH;
|
|
DWORD cb;
|
|
|
|
|
|
lpName[0] = 0;
|
|
|
|
address = (ULONG)lpBaseOfDll;
|
|
|
|
ReadMem( &dh, sizeof(dh) );
|
|
|
|
if (dh.e_magic == IMAGE_DOS_SIGNATURE) {
|
|
address = (ULONG)lpBaseOfDll + dh.e_lfanew;
|
|
} else {
|
|
address = (ULONG)lpBaseOfDll;
|
|
}
|
|
|
|
ReadMem( &sig, sizeof(sig) );
|
|
address -= sizeof(sig);
|
|
|
|
if (sig != IMAGE_NT_SIGNATURE) {
|
|
ReadMem( &nh.FileHeader, sizeof(IMAGE_FILE_HEADER) );
|
|
if (nh.FileHeader.SizeOfOptionalHeader == IMAGE_SIZEOF_ROM_OPTIONAL_HEADER) {
|
|
ReadMem( &rom, sizeof(rom) );
|
|
ZeroMemory( &nh.OptionalHeader, sizeof(nh.OptionalHeader) );
|
|
nh.OptionalHeader.SizeOfImage = rom.SizeOfCode;
|
|
nh.OptionalHeader.ImageBase = rom.BaseOfCode;
|
|
} else {
|
|
return FALSE;
|
|
}
|
|
} else {
|
|
ReadMem( &nh, sizeof(nh) );
|
|
}
|
|
|
|
cb = nh.FileHeader.NumberOfSections * IMAGE_SIZEOF_SECTION_HEADER;
|
|
pSH = malloc( cb );
|
|
ReadMem( pSH, cb );
|
|
|
|
nDebugDirs = nh.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size /
|
|
sizeof(IMAGE_DEBUG_DIRECTORY);
|
|
|
|
if (!nDebugDirs) {
|
|
return FALSE;
|
|
}
|
|
|
|
rva = nh.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress;
|
|
|
|
for(i = 0; i < nh.FileHeader.NumberOfSections; i++) {
|
|
if (rva >= pSH[i].VirtualAddress &&
|
|
rva < pSH[i].VirtualAddress + pSH[i].SizeOfRawData) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (i >= nh.FileHeader.NumberOfSections) {
|
|
return FALSE;
|
|
}
|
|
|
|
rva = ((rva - pSH[i].VirtualAddress) + pSH[i].VirtualAddress);
|
|
|
|
for (j = 0; j < nDebugDirs; j++) {
|
|
|
|
address = rva + (sizeof(DebugDir) * j) + (ULONG)lpBaseOfDll;
|
|
ReadMem( &DebugDir, sizeof(DebugDir) );
|
|
|
|
if (DebugDir.Type == IMAGE_DEBUG_TYPE_MISC) {
|
|
|
|
l = DebugDir.SizeOfData;
|
|
pMisc = pT = malloc(l);
|
|
|
|
if ((ULONG)DebugDir.AddressOfRawData < pSH[i].VirtualAddress ||
|
|
(ULONG)DebugDir.AddressOfRawData >=
|
|
pSH[i].VirtualAddress + pSH[i].SizeOfRawData) {
|
|
//
|
|
// the misc debug data MUST be in the .rdata section
|
|
// otherwise windbg cannot access it as it is not mapped in
|
|
//
|
|
continue;
|
|
}
|
|
|
|
address = (ULONG)DebugDir.AddressOfRawData + (ULONG)lpBaseOfDll;
|
|
ReadMem( pMisc, l );
|
|
|
|
while (l > 0) {
|
|
if (pMisc->DataType != IMAGE_DEBUG_MISC_EXENAME) {
|
|
l -= pMisc->Length;
|
|
pMisc = (PIMAGE_DEBUG_MISC)
|
|
(((LPSTR)pMisc) + pMisc->Length);
|
|
} else {
|
|
|
|
pExeName = (PVOID)&pMisc->Data[ 0 ];
|
|
|
|
if (!pMisc->Unicode) {
|
|
strcpy(lpName, (LPSTR)pExeName);
|
|
rVal = TRUE;
|
|
} else {
|
|
WideCharToMultiByte(CP_ACP,
|
|
0,
|
|
(LPWSTR)pExeName,
|
|
-1,
|
|
lpName,
|
|
MAX_PATH,
|
|
NULL,
|
|
NULL);
|
|
rVal = TRUE;
|
|
}
|
|
|
|
//
|
|
// Undo stevewo's error
|
|
//
|
|
|
|
if (_stricmp(&lpName[strlen(lpName)-4], ".DBG") == 0) {
|
|
char rgchPath[_MAX_PATH];
|
|
char rgchBase[_MAX_FNAME];
|
|
|
|
_splitpath(lpName, NULL, rgchPath, rgchBase, NULL);
|
|
if (strlen(rgchPath)==4) {
|
|
rgchPath[strlen(rgchPath)-1] = 0;
|
|
strcpy(lpName, rgchBase);
|
|
strcat(lpName, ".");
|
|
strcat(lpName, rgchPath);
|
|
} else {
|
|
strcpy(lpName, rgchBase);
|
|
strcat(lpName, ".exe");
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
free(pT);
|
|
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
return rVal;
|
|
}
|
|
|
|
|
|
LPSTR
|
|
CheckForRenamedImage(
|
|
DWORD lpBaseOfDll,
|
|
LPSTR lpOrigImageName
|
|
)
|
|
{
|
|
CHAR ImageName[MAX_PATH];
|
|
CHAR fname[_MAX_FNAME];
|
|
CHAR ext[_MAX_EXT];
|
|
|
|
|
|
if (GetModnameFromImage( lpBaseOfDll, ImageName ) && ImageName[0]) {
|
|
_splitpath( ImageName, NULL, NULL, fname, ext );
|
|
sprintf( ImageName, "%s%s", fname, ext );
|
|
if (_stricmp( ImageName, lpOrigImageName ) != 0) {
|
|
return _strdup(ImageName);
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
VOID
|
|
PrintModuleLoad(
|
|
PDUMP_HEADER DmpHeader,
|
|
ULONG ImageBase,
|
|
ULONG CheckSum
|
|
)
|
|
{
|
|
IMAGEHLP_MODULE ModuleInfo;
|
|
|
|
|
|
if (!SymGetModuleInfo( DmpHeader, ImageBase, &ModuleInfo )) {
|
|
return;
|
|
}
|
|
|
|
if (Verbose) {
|
|
fprintf(
|
|
FileOut,
|
|
"loaded %-16s 0x%08x 0x%08x %s\n",
|
|
ModuleInfo.ImageName,
|
|
ModuleInfo.BaseOfImage,
|
|
ModuleInfo.ImageSize,
|
|
ModuleInfo.LoadedImageName
|
|
);
|
|
}
|
|
|
|
if (CheckSum && CheckSum != ModuleInfo.CheckSum) {
|
|
fprintf(
|
|
FileOut,
|
|
"**** Warning: Checksum mismatch (SYMCHK=%08x, SYSCHK=%08x) for %s\n",
|
|
ModuleInfo.CheckSum,
|
|
CheckSum,
|
|
ModuleInfo.LoadedImageName
|
|
);
|
|
}
|
|
}
|
|
|
|
|
|
ULONG
|
|
DisAddrToSymbol(
|
|
struct DIS *pdis,
|
|
ULONG addr,
|
|
char *buf,
|
|
size_t bufsize,
|
|
DWORD *displacement
|
|
)
|
|
{
|
|
if (SymGetSymFromAddr( DmpHeader, addr, displacement, sym )) {
|
|
strncpy( buf, sym->Name, bufsize );
|
|
} else {
|
|
*displacement = 0;
|
|
buf[0] = 0;
|
|
}
|
|
|
|
return strlen(buf);
|
|
}
|
|
|
|
ULONG
|
|
DisFixupToSymbol(
|
|
struct DIS *pdis,
|
|
ULONG addr,
|
|
size_t fixup,
|
|
char *buf,
|
|
size_t bufsize,
|
|
DWORD *displacement
|
|
)
|
|
{
|
|
if (SymGetSymFromAddr( DmpHeader, addr, displacement, sym )) {
|
|
strncpy( buf, sym->Name, bufsize );
|
|
} else {
|
|
*displacement = 0;
|
|
buf[0] = 0;
|
|
}
|
|
|
|
return strlen(buf);
|
|
}
|
|
|
|
|
|
VOID
|
|
DoDisassemble(
|
|
ULONG Ip
|
|
)
|
|
{
|
|
#define DIS_SIZE 80
|
|
#define CODE_BUFFER_SIZE (DIS_SIZE * 2)
|
|
#define DISBUF_SIZE (100*1024)
|
|
|
|
BYTE CodeBuffer[CODE_BUFFER_SIZE];
|
|
PBYTE CodePtr;
|
|
ULONG BytesLeft;
|
|
ULONG Bytes;
|
|
ULONG Addr;
|
|
LPSTR DisBuf;
|
|
|
|
|
|
DisBuf = LocalAlloc( LPTR, DISBUF_SIZE );
|
|
BytesLeft = CODE_BUFFER_SIZE;
|
|
ZeroMemory( CodeBuffer, BytesLeft );
|
|
CodePtr = CodeBuffer;
|
|
Addr = Ip - 80;
|
|
DmpReadMemory(
|
|
(PVOID)Addr,
|
|
CodePtr,
|
|
BytesLeft
|
|
);
|
|
while( BytesLeft ) {
|
|
Bytes = Disassemble(
|
|
pdis,
|
|
Addr,
|
|
CodePtr,
|
|
BytesLeft,
|
|
" ",
|
|
DisBuf,
|
|
DISBUF_SIZE
|
|
);
|
|
if (Addr == Ip) {
|
|
DisBuf[0] = '-';
|
|
DisBuf[1] = '-';
|
|
DisBuf[2] = '-';
|
|
DisBuf[3] = '>';
|
|
}
|
|
fprintf( FileOut, "%s", DisBuf );
|
|
Addr += Bytes;
|
|
BytesLeft -= Bytes;
|
|
CodePtr += Bytes;
|
|
}
|
|
|
|
fprintf( FileOut, "\n" );
|
|
LocalFree( DisBuf );
|
|
}
|
|
|
|
|
|
BOOL
|
|
GetProcessModules(
|
|
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;
|
|
LPSTR p;
|
|
CHAR fname[_MAX_FNAME];
|
|
LPSTR ModName;
|
|
IMAGEHLP_MODULE ModuleInfo;
|
|
|
|
|
|
|
|
if (!DmpReadMemory( DmpHeader->PsLoadedModuleList, (PVOID)&List, sizeof(LIST_ENTRY))) {
|
|
fprintf( FileOut, "Error: could not read base of PsLoadedModuleList\n\n" );
|
|
return FALSE;
|
|
}
|
|
|
|
Next = List.Flink;
|
|
if (Next == NULL) {
|
|
fprintf( FileOut, "Error: PsLoadedModuleList is empty\n" );
|
|
return FALSE;
|
|
}
|
|
|
|
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))) {
|
|
fprintf( FileOut, "Error: memory read failed addr=0x%08x\n\n", (DWORD)DataTable );
|
|
return FALSE;
|
|
}
|
|
|
|
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)) {
|
|
fprintf( FileOut, "Error: unicode buffer is too small\n" );
|
|
continue;
|
|
}
|
|
|
|
cb = DmpReadMemory( (PVOID)BaseName.Buffer, (PVOID)UnicodeBuffer, BaseName.Length );
|
|
if (!cb) {
|
|
fprintf( FileOut, "Error: memory read failed addr=0x%08x\n\n", (DWORD)BaseName.Buffer );
|
|
return FALSE;
|
|
}
|
|
|
|
if (!WideCharToMultiByte(
|
|
CP_ACP,
|
|
0,
|
|
UnicodeBuffer,
|
|
cb,
|
|
AnsiBuffer,
|
|
sizeof(AnsiBuffer),
|
|
NULL,
|
|
NULL
|
|
)) {
|
|
fprintf( FileOut, "Error: could not convert module name to ansi\n\n" );
|
|
return FALSE;
|
|
}
|
|
|
|
AnsiBuffer[cb/2] = 0;
|
|
|
|
//
|
|
// change the name for mp kernels & hals
|
|
//
|
|
if (_stricmp( AnsiBuffer, HAL_IMAGE_NAME ) == 0) {
|
|
p = CheckForRenamedImage( (ULONG)DataTableBuffer.DllBase, AnsiBuffer );
|
|
ModName = HAL_MODULE_NAME;
|
|
} else if (_stricmp( AnsiBuffer, KERNEL_IMAGE_NAME ) == 0) {
|
|
p = CheckForRenamedImage( (ULONG)DataTableBuffer.DllBase, AnsiBuffer );
|
|
ModName = KERNEL_MODULE_NAME;
|
|
} else {
|
|
p = NULL;
|
|
_splitpath( AnsiBuffer, NULL, NULL, fname, NULL );
|
|
ModName = fname;
|
|
}
|
|
if (p) {
|
|
strcpy( AnsiBuffer, p );
|
|
free( p );
|
|
}
|
|
|
|
if (SymLoadModule(
|
|
DmpHeader,
|
|
NULL,
|
|
AnsiBuffer,
|
|
ModName,
|
|
(ULONG)DataTableBuffer.DllBase,
|
|
(ULONG)DataTableBuffer.SizeOfImage
|
|
)) {
|
|
PrintModuleLoad(
|
|
DmpHeader,
|
|
(ULONG)DataTableBuffer.DllBase,
|
|
DataTableBuffer.CheckSum
|
|
);
|
|
} else {
|
|
fprintf( FileOut, "**** Error: Could not load symbols for %s\n", AnsiBuffer );
|
|
}
|
|
}
|
|
|
|
cb = SymLoadModule( DmpHeader, NULL, "ntdll.dll", "ntdll", 0, 0 );
|
|
PrintModuleLoad( DmpHeader, cb, 0 );
|
|
cb = SymLoadModule( DmpHeader, NULL, "kernel32.dll", "kernel32", 0, 0 );
|
|
PrintModuleLoad( DmpHeader, cb, 0 );
|
|
|
|
fprintf( FileOut, "\n" );
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
VOID
|
|
PrintHeader(
|
|
LPSTR CrashDumpFile,
|
|
PDUMP_HEADER DmpHeader,
|
|
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;
|
|
|
|
|
|
fprintf( FileOut, "****************************************************************\n" );
|
|
fprintf( FileOut, "**\n" );
|
|
fprintf( FileOut, "** Windows NT Crash Dump Analysis\n" );
|
|
fprintf( FileOut, "**\n" );
|
|
fprintf( FileOut, "****************************************************************\n" );
|
|
fprintf( FileOut, "*\n" );
|
|
fprintf( FileOut, "Filename . . . . . . .%s\n", CrashDumpFile );
|
|
*(PULONG)buf = DmpHeader->Signature;
|
|
buf[4] = 0;
|
|
fprintf( FileOut, "Signature. . . . . . .%s\n", buf );
|
|
*(PULONG)buf = DmpHeader->ValidDump;
|
|
buf[4] = 0;
|
|
fprintf( FileOut, "ValidDump. . . . . . .%s\n", buf );
|
|
fprintf( FileOut, "MajorVersion . . . . ." );
|
|
if (DmpHeader->MajorVersion == 0xc) {
|
|
fprintf( FileOut, "checked system\n" );
|
|
} else if (DmpHeader->MajorVersion == 0xf) {
|
|
fprintf( FileOut, "free system\n" );
|
|
} else {
|
|
fprintf( FileOut, "%d\n", DmpHeader->MajorVersion );
|
|
}
|
|
fprintf( FileOut, "MinorVersion . . . . .%d\n", DmpHeader->MinorVersion );
|
|
fprintf( FileOut, "DirectoryTableBase . .0x%08x\n", DmpHeader->DirectoryTableBase );
|
|
fprintf( FileOut, "PfnDataBase. . . . . .0x%08x\n", DmpHeader->PfnDataBase );
|
|
fprintf( FileOut, "PsLoadedModuleList . .0x%08x\n", DmpHeader->PsLoadedModuleList );
|
|
fprintf( FileOut, "PsActiveProcessHead. .0x%08x\n", DmpHeader->PsActiveProcessHead );
|
|
fprintf( FileOut, "MachineImageType . . ." );
|
|
switch (DmpHeader->MachineImageType) {
|
|
case IMAGE_FILE_MACHINE_I386:
|
|
fprintf( FileOut, "i386\n" );
|
|
break;
|
|
|
|
case IMAGE_FILE_MACHINE_R4000:
|
|
fprintf( FileOut, "mips\n" );
|
|
break;
|
|
|
|
case IMAGE_FILE_MACHINE_ALPHA:
|
|
fprintf( FileOut, "alpha\n" );
|
|
break;
|
|
|
|
case IMAGE_FILE_MACHINE_POWERPC:
|
|
fprintf( FileOut, "PowerPC\n" );
|
|
break;
|
|
}
|
|
fprintf( FileOut, "NumberProcessors . . .%d\n", DmpHeader->NumberProcessors );
|
|
fprintf( FileOut, "BugCheckCode . . . . .0x%08x\n", DmpHeader->BugCheckCode );
|
|
fprintf( FileOut, "BugCheckParameter1 . .0x%08x\n", DmpHeader->BugCheckParameter1 );
|
|
fprintf( FileOut, "BugCheckParameter2 . .0x%08x\n", DmpHeader->BugCheckParameter2 );
|
|
fprintf( FileOut, "BugCheckParameter3 . .0x%08x\n", DmpHeader->BugCheckParameter3 );
|
|
fprintf( FileOut, "BugCheckParameter4 . .0x%08x\n", DmpHeader->BugCheckParameter4 );
|
|
fprintf( FileOut, "ExceptionCode. . . . .0x%08x\n", Exception->ExceptionCode );
|
|
fprintf( FileOut, "ExceptionFlags . . . .0x%08x\n", Exception->ExceptionFlags );
|
|
fprintf( FileOut, "ExceptionAddress . . .0x%08x\n", Exception->ExceptionAddress );
|
|
for (i=0; i<Exception->NumberParameters; i++) {
|
|
fprintf( FileOut, "ExceptionParam#%d . .0x%08x\n", Exception->ExceptionInformation[i] );
|
|
}
|
|
fprintf( FileOut, "\n" );
|
|
}
|
|
|
|
BOOL
|
|
SwReadMemory(
|
|
PDUMP_HEADER DmpHeader,
|
|
LPCVOID lpBaseAddress,
|
|
LPVOID lpBuffer,
|
|
DWORD nSize,
|
|
LPDWORD lpNumberOfBytesRead
|
|
)
|
|
{
|
|
DWORD cb;
|
|
if (nSize == 0) {
|
|
cb = 0;
|
|
if (lpNumberOfBytesRead) {
|
|
*lpNumberOfBytesRead = cb;
|
|
}
|
|
return TRUE;
|
|
}
|
|
cb = DmpReadMemory( (LPVOID)lpBaseAddress, lpBuffer, nSize );
|
|
if (lpNumberOfBytesRead) {
|
|
*lpNumberOfBytesRead = cb;
|
|
}
|
|
return cb > 0;
|
|
}
|
|
|
|
LPVOID
|
|
SwFunctionTableAccess(
|
|
PDUMP_HEADER DmpHeader,
|
|
DWORD AddrBase
|
|
)
|
|
{
|
|
static IMAGE_RUNTIME_FUNCTION_ENTRY rfe;
|
|
PIMAGE_FUNCTION_ENTRY rf;
|
|
|
|
rf = SymFunctionTableAccess( DmpHeader, AddrBase );
|
|
if (!rf) {
|
|
return NULL;
|
|
}
|
|
|
|
rfe.BeginAddress = rf->StartingAddress;
|
|
rfe.EndAddress = rf->EndingAddress;
|
|
rfe.ExceptionHandler = 0;
|
|
rfe.HandlerData = 0;
|
|
rfe.PrologEndAddress = rf->EndOfPrologue;
|
|
|
|
return &rfe;
|
|
}
|
|
|
|
DWORD
|
|
SwGetModuleBase(
|
|
PDUMP_HEADER DmpHeader,
|
|
DWORD ReturnAddress
|
|
)
|
|
{
|
|
IMAGEHLP_MODULE ModuleInfo;
|
|
|
|
|
|
if (!SymGetModuleInfo( DmpHeader, ReturnAddress, &ModuleInfo )) {
|
|
return 0;
|
|
}
|
|
|
|
return ModuleInfo.BaseOfImage;
|
|
}
|
|
|
|
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 'y':
|
|
do {
|
|
ch = *lpstrCmd++;
|
|
} while (ch == ' ' || ch == '\t');
|
|
i=0;
|
|
while (ch != ' ' && ch != '\0') {
|
|
SymbolPath[i++] = ch;
|
|
ch = *lpstrCmd++;
|
|
}
|
|
SymbolPath[i] = 0;
|
|
break;
|
|
|
|
case 'f':
|
|
do {
|
|
ch = *lpstrCmd++;
|
|
} while (ch == ' ' || ch == '\t');
|
|
i=0;
|
|
while (ch != ' ' && ch != '\0') {
|
|
OutputFileName[i++] = ch;
|
|
ch = *lpstrCmd++;
|
|
}
|
|
OutputFileName[i] = 0;
|
|
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 DUMPEXAM\n" );
|
|
fprintf( stderr, "Copyright (C) 1995 Microsoft Corp. All rights reserved\n\n" );
|
|
fprintf( stderr, "usage: DUMPEXAM [options] [CrashDumpFile]\n" );
|
|
fprintf( stderr, " [-?] Display this message\n" );
|
|
fprintf( stderr, " [-v] Verbose mode\n" );
|
|
fprintf( stderr, " [-p] Print header only\n" );
|
|
fprintf( stderr, " [-f File name] Specify output file name\n" );
|
|
fprintf( stderr, " [-y Path] Set the symbol search path\n" );
|
|
fprintf( stderr, "\n" );
|
|
fprintf( stderr, " If the crashdump filename is empty the name\n" );
|
|
fprintf( stderr, " specified in the registry is used.\n" );
|
|
fprintf( stderr, "\n" );
|
|
fprintf( stderr, " If the symbol search path is empty the cdrom\n" );
|
|
fprintf( stderr, " is used for symbols\n" );
|
|
ExitProcess(0);
|
|
}
|
|
|
|
VOID
|
|
PrintHeading(
|
|
char *format,
|
|
...
|
|
)
|
|
{
|
|
char buf[1024];
|
|
|
|
va_list arg_ptr;
|
|
va_start(arg_ptr, format);
|
|
_vsnprintf(buf, sizeof(buf)-1, format, arg_ptr);
|
|
va_end(arg_ptr);
|
|
fprintf( FileOut, "****************************************************************\n" );
|
|
fprintf( FileOut, "** %s\n", buf );
|
|
fprintf( FileOut, "****************************************************************\n" );
|
|
fprintf( FileOut, "*\n" );
|
|
}
|
|
|
|
LPSTR
|
|
GetBugText(
|
|
ULONG BugCode
|
|
)
|
|
{
|
|
ULONG i;
|
|
for (i=0; bugcodesSymbolicNames[i].MessageId != 0xFFFFFFFF; i++) {
|
|
if (bugcodesSymbolicNames[i].MessageId == BugCode) {
|
|
return bugcodesSymbolicNames[i].SymbolicName;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
UINT
|
|
MyGetDriveType(
|
|
IN CHAR Drive
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Determine the type of a drive (removeable, fixed, net, cd, etc).
|
|
|
|
Arguments:
|
|
|
|
Drive - supplies drive letter of drive whose type is needed.
|
|
|
|
Return Value:
|
|
|
|
Same set of values as returned by GetDriveType() API.
|
|
|
|
--*/
|
|
|
|
{
|
|
CHAR DriveName[3];
|
|
|
|
DriveName[0] = Drive;
|
|
DriveName[1] = ':';
|
|
DriveName[2] = 0;
|
|
|
|
return GetDriveType(DriveName);
|
|
}
|
|
|
|
|
|
CHAR
|
|
LocateCdRomDrive(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Determine if a CD-ROM drive is attached to the computer and
|
|
return its drive letter. If there's more than one cd-rom drive
|
|
the one with the alphabetically lower drive letter is returned.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
Drive letter of CD-ROM drive, or 0 if none could be located.
|
|
|
|
--*/
|
|
|
|
{
|
|
CHAR Drive;
|
|
UINT OldMode;
|
|
|
|
OldMode = SetErrorMode(SEM_FAILCRITICALERRORS);
|
|
|
|
for(Drive='C'; Drive<='Z'; Drive++) {
|
|
|
|
if(MyGetDriveType(Drive) == DRIVE_CDROM) {
|
|
SetErrorMode(OldMode);
|
|
return Drive;
|
|
}
|
|
}
|
|
|
|
SetErrorMode(OldMode);
|
|
return 0;
|
|
}
|
|
|
|
|
|
BOOL
|
|
IsCdRomInDrive(
|
|
IN CHAR Drive,
|
|
IN LPSTR TagFile
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Determine if a particular CD-ROM is in a drive,
|
|
based on the presence of a given tagfile.
|
|
|
|
Arguments:
|
|
|
|
Drive - supplies drive letter of drive to be checked
|
|
for presence of the tagfile.
|
|
|
|
TagFile - supplies drive-relative path (from root)
|
|
of the file whose presence validates the presence
|
|
of a volume.
|
|
|
|
Return Value:
|
|
|
|
Boolean value indicating whether the tagfile could be
|
|
accessed.
|
|
|
|
--*/
|
|
|
|
{
|
|
CHAR Path[MAX_PATH];
|
|
|
|
sprintf(Path,"%c:\\%s",Drive,TagFile);
|
|
|
|
return DoesFileExist(Path);
|
|
}
|
|
|
|
|
|
BOOL
|
|
DoesFileExist(
|
|
IN LPSTR File
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Determine if a file exists and is accessible.
|
|
|
|
Arguments:
|
|
|
|
File - supplies full path of file whose accessibility
|
|
is in question.
|
|
|
|
Return Value:
|
|
|
|
Boolean value indicating whether file is accessible.
|
|
|
|
--*/
|
|
|
|
{
|
|
UINT OldMode;
|
|
HANDLE h;
|
|
WIN32_FIND_DATA FindData;
|
|
|
|
//
|
|
// Avoid system popups.
|
|
//
|
|
OldMode = SetErrorMode(SEM_FAILCRITICALERRORS);
|
|
|
|
h = FindFirstFile(File,&FindData);
|
|
|
|
SetErrorMode(OldMode);
|
|
|
|
if(h == INVALID_HANDLE_VALUE) {
|
|
return(FALSE);
|
|
}
|
|
|
|
FindClose(h);
|
|
return(TRUE);
|
|
}
|
|
|
|
BOOL
|
|
IsThisAServer(
|
|
VOID
|
|
)
|
|
{
|
|
DWORD DataSize;
|
|
DWORD DataType;
|
|
CHAR Data[128];
|
|
LONG rc;
|
|
HKEY hKey;
|
|
|
|
|
|
if (RegOpenKeyEx(
|
|
HKEY_LOCAL_MACHINE,
|
|
"System\\CurrentControlSet\\Control\\ProductOptions",
|
|
0,
|
|
KEY_READ,
|
|
&hKey
|
|
) != NO_ERROR) {
|
|
//
|
|
// unknown so default to workstation
|
|
//
|
|
return FALSE;
|
|
}
|
|
|
|
DataSize = sizeof(Data);
|
|
|
|
rc = RegQueryValueEx(
|
|
hKey,
|
|
"ProductType",
|
|
0,
|
|
&DataType,
|
|
Data,
|
|
&DataSize
|
|
);
|
|
|
|
RegCloseKey( hKey );
|
|
|
|
if ((rc == NO_ERROR) && (DataType == REG_SZ) && _strcmpi(Data,"winnt")) {
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
DWORD
|
|
EstablishSymbolPath(
|
|
PDUMP_HEADER DmpHeader,
|
|
LPSTR SymbolPath
|
|
)
|
|
{
|
|
LPSTR TagFile;
|
|
LPSTR ProcDir;
|
|
CHAR CdDrive;
|
|
CHAR ModName[512];
|
|
CHAR Drive[_MAX_DRIVE];
|
|
CHAR Dir[_MAX_DIR];
|
|
CHAR Fname[_MAX_FNAME];
|
|
CHAR Ext[_MAX_EXT];
|
|
|
|
|
|
if (SymbolPath[0]) {
|
|
//
|
|
// the user must have specified a path
|
|
// on the command line
|
|
//
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
GetModuleFileName( NULL, ModName, sizeof(ModName) );
|
|
|
|
if (MyGetDriveType( ModName[0] ) == DRIVE_CDROM) {
|
|
//
|
|
// the user is running from the cdrom
|
|
//
|
|
_splitpath( ModName, Drive, Dir, Fname, Ext );
|
|
_makepath( SymbolPath, Drive, Dir, "symbols", NULL );
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// the user is running from a local or network drive
|
|
//
|
|
|
|
CdDrive = LocateCdRomDrive();
|
|
if (!CdDrive) {
|
|
return ERROR_WRONG_DISK;
|
|
}
|
|
|
|
TagFile = IsThisAServer() ? "cdrom.s" : "cdrom.w";
|
|
|
|
if (!IsCdRomInDrive( CdDrive, TagFile )) {
|
|
return ERROR_WRONG_DISK;
|
|
}
|
|
|
|
switch (DmpHeader->MachineImageType) {
|
|
case IMAGE_FILE_MACHINE_I386:
|
|
ProcDir = "i386";
|
|
break;
|
|
|
|
case IMAGE_FILE_MACHINE_R4000:
|
|
ProcDir = "mips";
|
|
break;
|
|
|
|
case IMAGE_FILE_MACHINE_ALPHA:
|
|
ProcDir = "alpha";
|
|
break;
|
|
|
|
case IMAGE_FILE_MACHINE_POWERPC:
|
|
ProcDir = "ppc";
|
|
break;
|
|
|
|
default:
|
|
return 0;
|
|
break;
|
|
}
|
|
|
|
sprintf( ModName, "%c:\\support\\debug\\%s\\symbols", CdDrive, ProcDir );
|
|
|
|
if (!DoesFileExist( ModName )) {
|
|
return ERROR_FILE_NOT_FOUND;
|
|
}
|
|
|
|
strcpy( SymbolPath, ModName );
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
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;
|
|
}
|