/*++ 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 #include #include #include #include #include #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.AllocationProtect & PAGE_GUARD) || (CrashdumpInfo->mbi.AllocationProtect & 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; }