DUMP.C

/*++ 

Copyright (c) 1993 Microsoft Corporation

Module Name:

dump.c

Abstract:

This file implements the crash dump code.

Author:

Wesley Witt (wesw) 27-Jan-1995

Environment:

User Mode

--*/

#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stddef.h>
#include <crash.h>

#include "drwatson.h"
#include "proto.h"
#include "messages.h"
#include "resource.h"


#define MEM_SIZE (64*1024)


//
// these are here only so that we can link
// with crashlib. they are only referenced
// when reading a kernel mode crash dump
//
DWORD KiProcessors;
DWORD KiPcrBaseAddress;

//
// private data structure use for communcating
// crash dump data to the callback function
//
typedef struct _CRASH_DUMP_INFO {
PDEBUGPACKET dp;
EXCEPTION_DEBUG_INFO *ExceptionInfo;
DWORD MemoryCount;
DWORD Address;
PUCHAR MemoryData;
MEMORY_BASIC_INFORMATION mbi;
BOOL MbiOffset;
ULONG MbiRemaining;
PTHREADCONTEXT ptctx;
IMAGEHLP_MODULE mi;
PCRASH_MODULE CrashModule;
} CRASH_DUMP_INFO, *PCRASH_DUMP_INFO;

LPSTR
ExpandPath(
LPSTR lpPath
);

DWORD
GetTeb(
HANDLE hTread
);

BOOL
CrashDumpCallback(
DWORD DataType,
PVOID *DumpData,
LPDWORD DumpDataLength,
PCRASH_DUMP_INFO CrashdumpInfo
)

/*++

Routine Description:

This function is the callback used by crashlib.
Its purpose is to provide data to DmpCreateUserDump()
for writting to the crashdump file.

Arguments:

DataType - requested data type
DumpData - pointer to a pointer to the data
DumpDataLength - pointer to the data length
CrashdumpInfo - DrWatson private data

Return Value:

TRUE - continue calling back for the requested data type
FALSE - stop calling back and go on to the next data type

--*/

{
DWORD cb;

switch( DataType ) {
case DMP_DEBUG_EVENT:
*DumpData = &CrashdumpInfo->dp->DebugEvent;
*DumpDataLength = sizeof(DEBUG_EVENT);
break;

case DMP_THREAD_STATE:
{
static CRASH_THREAD CrashThread;
PTHREADCONTEXT ptctx;
PLIST_ENTRY ListEntry;

*DumpData = &CrashThread;

if (CrashdumpInfo->ptctx == NULL) {
ListEntry = CrashdumpInfo->dp->ThreadList.Flink;
} else {
ListEntry = CrashdumpInfo->ptctx->ThreadList.Flink;
}

if (ListEntry == &CrashdumpInfo->dp->ThreadList) {
CrashdumpInfo->ptctx = NULL;
return FALSE;
}

ptctx =
CrashdumpInfo->ptctx = CONTAINING_RECORD(ListEntry, THREADCONTEXT, ThreadList);

ZeroMemory(&CrashThread, sizeof(CrashThread));

CrashThread.ThreadId = ptctx->dwThreadId;
CrashThread.SuspendCount = SuspendThread(ptctx->hThread);
if (CrashThread.SuspendCount != (DWORD)-1) {
ResumeThread(ptctx->hThread);
}
CrashThread.PriorityClass = GetPriorityClass(CrashdumpInfo->dp->hProcess);
CrashThread.Priority = GetThreadPriority(ptctx->hThread);
CrashThread.Teb = GetTeb(ptctx->hThread);

*DumpDataLength = sizeof(CRASH_THREAD);
}
break;

case DMP_MEMORY_BASIC_INFORMATION:
while( TRUE ) {
CrashdumpInfo->Address += CrashdumpInfo->mbi.RegionSize;
if (!VirtualQueryEx(
CrashdumpInfo->dp->hProcess,
(LPVOID)CrashdumpInfo->Address,
&CrashdumpInfo->mbi,
sizeof(MEMORY_BASIC_INFORMATION) )) {
return FALSE;
}
if ((CrashdumpInfo->mbi.AllocationProtect & PAGE_GUARD) ||
(CrashdumpInfo->mbi.AllocationProtect & PAGE_NOACCESS)) {
continue;
}
if ((CrashdumpInfo->mbi.State & MEM_FREE) ||
(CrashdumpInfo->mbi.State & MEM_RESERVE)) {
continue;
}
break;
}
*DumpData = &CrashdumpInfo->mbi;
*DumpDataLength = sizeof(MEMORY_BASIC_INFORMATION);
break;

case DMP_THREAD_CONTEXT:
{
PLIST_ENTRY ListEntry;

if (CrashdumpInfo->ptctx == NULL) {
ListEntry = CrashdumpInfo->dp->ThreadList.Flink;
} else {
ListEntry = CrashdumpInfo->ptctx->ThreadList.Flink;
}

if (ListEntry == &CrashdumpInfo->dp->ThreadList) {
CrashdumpInfo->ptctx = NULL;
return FALSE;
}

CrashdumpInfo->ptctx = CONTAINING_RECORD(ListEntry, THREADCONTEXT, ThreadList);

*DumpData = &CrashdumpInfo->ptctx->context;
*DumpDataLength = sizeof(CONTEXT);
}
break;

case DMP_MODULE:
if (CrashdumpInfo->mi.BaseOfImage == 0) {
return FALSE;
}
CrashdumpInfo->CrashModule->BaseOfImage = CrashdumpInfo->mi.BaseOfImage;
CrashdumpInfo->CrashModule->SizeOfImage = CrashdumpInfo->mi.ImageSize;
CrashdumpInfo->CrashModule->ImageNameLength = strlen(CrashdumpInfo->mi.ImageName) + 1;
strcpy( CrashdumpInfo->CrashModule->ImageName, CrashdumpInfo->mi.ImageName );
*DumpData = CrashdumpInfo->CrashModule;
*DumpDataLength = sizeof(CRASH_MODULE) + CrashdumpInfo->CrashModule->ImageNameLength;
if (!SymGetModuleInfo( CrashdumpInfo->dp->hProcess, (DWORD)-1, &CrashdumpInfo->mi )) {
CrashdumpInfo->mi.BaseOfImage = 0;
}
break;

case DMP_MEMORY_DATA:
if (!CrashdumpInfo->MemoryCount) {
CrashdumpInfo->Address = 0;
CrashdumpInfo->MbiOffset = 0;
CrashdumpInfo->MbiRemaining = 0;
ZeroMemory( &CrashdumpInfo->mbi, sizeof(MEMORY_BASIC_INFORMATION) );
CrashdumpInfo->MemoryData = VirtualAlloc(
NULL,
MEM_SIZE,
MEM_COMMIT,
PAGE_READWRITE
);
}
if (!CrashdumpInfo->MbiRemaining) {
while( TRUE ) {
CrashdumpInfo->Address += CrashdumpInfo->mbi.RegionSize;
if (!VirtualQueryEx(
CrashdumpInfo->dp->hProcess,
(LPVOID)CrashdumpInfo->Address,
&CrashdumpInfo->mbi,
sizeof(MEMORY_BASIC_INFORMATION) )) {
if (CrashdumpInfo->MemoryData) {
VirtualFree( CrashdumpInfo->MemoryData, MEM_SIZE, MEM_RELEASE );
}
return FALSE;
}
if ((CrashdumpInfo->mbi.Protect & PAGE_GUARD) ||
(CrashdumpInfo->mbi.Protect & PAGE_NOACCESS)) {
continue;
}
if ((CrashdumpInfo->mbi.State & MEM_FREE) ||
(CrashdumpInfo->mbi.State & MEM_RESERVE)) {
continue;
}
CrashdumpInfo->MbiOffset = 0;
CrashdumpInfo->MbiRemaining = CrashdumpInfo->mbi.RegionSize;
CrashdumpInfo->MemoryCount += 1;
break;
}
}
*DumpDataLength = min( CrashdumpInfo->MbiRemaining, MEM_SIZE );
CrashdumpInfo->MbiRemaining -= *DumpDataLength;
ReadProcessMemory(
CrashdumpInfo->dp->hProcess,
(PUCHAR)((ULONG)CrashdumpInfo->mbi.BaseAddress + (ULONG)CrashdumpInfo->MbiOffset),
CrashdumpInfo->MemoryData,
*DumpDataLength,
&cb
);
*DumpData = CrashdumpInfo->MemoryData;
CrashdumpInfo->MbiOffset += *DumpDataLength;
break;
}

return TRUE;
}


BOOL
CreateDumpFile(
PDEBUGPACKET dp,
LPEXCEPTION_DEBUG_INFO ed
)

/*++

Routine Description:

This function creates a crash dump file.

Arguments:

dp - debug packet for current process

ed - exception data

Return Value:

TRUE - Crash dump was created
FALSE - Crash dump was NOT created

--*/

{
CRASH_DUMP_INFO CrashdumpInfo;
LPSTR p;


ZeroMemory( &CrashdumpInfo, sizeof(CRASH_DUMP_INFO) );

CrashdumpInfo.dp = dp;
CrashdumpInfo.ExceptionInfo = ed;
CrashdumpInfo.ptctx = NULL;
//
// Get first entry in module list
//
SymGetModuleInfo( dp->hProcess, (DWORD)0, &CrashdumpInfo.mi );
CrashdumpInfo.CrashModule = LocalAlloc( LPTR, 4096 );

p = ExpandPath( dp->options.szCrashDump );
if (!p) {
return FALSE;
}

DmpCreateUserDump( p, CrashDumpCallback, &CrashdumpInfo );

free( p );

LocalFree( CrashdumpInfo.CrashModule );

return TRUE;
}