|
|
/*++
Copyright (c) 1993-2002 Microsoft Corporation
Module Name:
debug.cpp
Abstract:
This file implements the debug module for drwatson. This module processes all debug events and generates the postmortem dump.
Author:
Wesley Witt (wesw) 1-May-1993
Environment:
User Mode
--*/
#include "pch.cpp"
#define STATUS_POSSIBLE_DEADLOCK ((DWORD)0xC0000194L)
#define STATUS_VDM_EVENT STATUS_SEGMENT_NOTIFICATION
typedef struct tagSYSINFO { _TCHAR szUserName[MAX_PATH]; _TCHAR szMachineName[MAX_PATH]; } SYSINFO, *PSYSINFO;
//----------------------------------------------------------------------------
//
// Log output callbacks.
//
//----------------------------------------------------------------------------
class LogOutputCallbacks : public IDebugOutputCallbacks { public: // IUnknown.
STDMETHOD(QueryInterface)( THIS_ IN REFIID InterfaceId, OUT PVOID* Interface ); STDMETHOD_(ULONG, AddRef)( THIS ); STDMETHOD_(ULONG, Release)( THIS );
// IDebugOutputCallbacks.
STDMETHOD(Output)( THIS_ IN ULONG Mask, IN PCSTR Text ); };
LogOutputCallbacks g_LogOutCb;
STDMETHODIMP LogOutputCallbacks::QueryInterface( THIS_ IN REFIID InterfaceId, OUT PVOID* Interface ) { *Interface = NULL;
if (IsEqualIID(InterfaceId, __uuidof(IUnknown)) || IsEqualIID(InterfaceId, __uuidof(IDebugOutputCallbacks))) { *Interface = (IDebugOutputCallbacks *)this; AddRef(); return S_OK; } else { return E_NOINTERFACE; } }
STDMETHODIMP_(ULONG) LogOutputCallbacks::AddRef( THIS ) { // This class is designed to be static so
// there's no true refcount.
return 1; }
STDMETHODIMP_(ULONG) LogOutputCallbacks::Release( THIS ) { // This class is designed to be static so
// there's no true refcount.
return 0; }
STDMETHODIMP LogOutputCallbacks::Output( THIS_ IN ULONG Mask, IN PCSTR Text ) { PCSTR Scan;
for (;;) { Scan = strchr(Text, '\n'); if (Scan == NULL) { break; }
lprintfs(_T("%.*hs\r\n"), (int)(Scan - Text), Text); Text = Scan + 1; } lprintfs(_T("%hs"), Text); return S_OK; }
_TCHAR * GetExceptionText( DWORD dwExceptionCode ) { static _TCHAR buf[80]; DWORD dwFormatId = 0;
memset( buf, 0, sizeof(buf) );
switch (dwExceptionCode) { case STATUS_SINGLE_STEP: dwFormatId = MSG_SINGLE_STEP_EXCEPTION; break;
case DBG_CONTROL_C: dwFormatId = MSG_CONTROLC_EXCEPTION; break;
case DBG_CONTROL_BREAK: dwFormatId = MSG_CONTROL_BRK_EXCEPTION; break;
case STATUS_ACCESS_VIOLATION: dwFormatId = MSG_ACCESS_VIOLATION_EXCEPTION; break;
case STATUS_STACK_OVERFLOW: dwFormatId = MSG_STACK_OVERFLOW_EXCEPTION; break;
case STATUS_INTEGER_DIVIDE_BY_ZERO: dwFormatId = MSG_INTEGER_DIVIDE_BY_ZERO_EXCEPTION; break;
case STATUS_PRIVILEGED_INSTRUCTION: dwFormatId = MSG_PRIVILEGED_INSTRUCTION_EXCEPTION; break;
case STATUS_ILLEGAL_INSTRUCTION: dwFormatId = MSG_ILLEGAL_INSTRUCTION_EXCEPTION; break;
case STATUS_IN_PAGE_ERROR: dwFormatId = MSG_IN_PAGE_IO_EXCEPTION; break;
case STATUS_DATATYPE_MISALIGNMENT: dwFormatId = MSG_DATATYPE_EXCEPTION; break;
case STATUS_POSSIBLE_DEADLOCK: dwFormatId = MSG_DEADLOCK_EXCEPTION; break;
case STATUS_VDM_EVENT: dwFormatId = MSG_VDM_EXCEPTION; break;
case STATUS_BREAKPOINT: dwFormatId = MSG_BREAKPOINT_EXCEPTION; break;
default: lprintfs( _T("\r\n") ); break; }
FormatMessage( FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ARGUMENT_ARRAY, NULL, dwFormatId, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
buf, sizeof(buf) / sizeof(_TCHAR), NULL );
return buf; }
void CreateEngineInterfaces( PDEBUGPACKET dp ) { HRESULT Status;
if ((Status = DebugCreate(__uuidof(IDebugClient2), (void **)&dp->DbgClient)) != S_OK) { goto Error; }
if ((Status = dp->DbgClient-> QueryInterface(__uuidof(IDebugControl), (void **)&dp->DbgControl)) != S_OK || (Status = dp->DbgClient-> QueryInterface(__uuidof(IDebugDataSpaces), (void **)&dp->DbgData)) != S_OK || (Status = dp->DbgClient-> QueryInterface(__uuidof(IDebugRegisters), (void **)&dp->DbgRegisters)) != S_OK || (Status = dp->DbgClient-> QueryInterface(__uuidof(IDebugSymbols), (void **)&dp->DbgSymbols)) != S_OK || (Status = dp->DbgClient-> QueryInterface(__uuidof(IDebugSystemObjects), (void **)&dp->DbgSystem)) != S_OK) { goto Error; }
if ((Status = dp->DbgSymbols-> AddSymbolOptions(SYMOPT_FAIL_CRITICAL_ERRORS)) != S_OK || (Status = dp->DbgControl-> AddEngineOptions(DEBUG_ENGOPT_INITIAL_BREAK)) != S_OK || (Status = dp->DbgControl-> Execute(DEBUG_OUTCTL_IGNORE, "sxe et", DEBUG_EXECUTE_DEFAULT)) != S_OK) { goto Error; } return;
Error: if (dp->options.fVisual) { FatalError( Status, LoadRcString(IDS_CANT_INIT_ENGINE) ); } else { ExitProcess( 1 ); } }
void AttachToActiveProcess ( PDEBUGPACKET dp ) { HRESULT Status; if ((Status = dp->DbgClient-> AttachProcess(0, dp->dwPidToDebug, DEBUG_ATTACH_DEFAULT)) != S_OK) { if (dp->options.fVisual) { FatalError( Status, LoadRcString(IDS_ATTACHFAIL) ); } else { ExitProcess( 1 ); } }
return; }
DWORD SysInfoThread( PSYSINFO si ) { DWORD len;
len = sizeof(si->szMachineName) / sizeof(_TCHAR); GetComputerName( si->szMachineName, &len ); len = sizeof(si->szUserName) / sizeof(_TCHAR); GetUserName( si->szUserName, &len );
return 0; }
void LogSystemInformation( PDEBUGPACKET dp ) { _TCHAR buf[1024]; SYSTEM_INFO si; DWORD ver; SYSINFO mySi; SYSINFO* threadSi; DWORD dwThreadId; HANDLE hThread; DWORD TSid;
lprintf( MSG_SYSINFO_HEADER );
// Initialize default unknown values.
LoadRcStringBuf( IDS_UNKNOWN_MACHINE, mySi.szMachineName, _tsizeof(mySi.szMachineName) ); LoadRcStringBuf( IDS_UNKNOWN_USER, mySi.szUserName, _tsizeof(mySi.szUserName) );
// Attempt to get the actual values.
// The storage passed to the get thread is not taken
// from this thread's stack so that this function can exit
// without leaving the other thread with stale stack pointers.
threadSi = (SYSINFO*)malloc(sizeof(*threadSi)); if (threadSi != NULL) { hThread = CreateThread( NULL, 16000, (LPTHREAD_START_ROUTINE)SysInfoThread, threadSi, 0, &dwThreadId ); if (hThread != NULL) { // Let the thread run for a little while since
// the get calls can be slow. If the thread doesn't
// finish in the time allotted we'll just go ahead
// with the default values and forget about the get thread.
Sleep( 0 ); if (WaitForSingleObject( hThread, 30000 ) == WAIT_OBJECT_0) { // Thread finished so we have the real values.
_tcscpy(mySi.szMachineName, threadSi->szMachineName); _tcscpy(mySi.szUserName, threadSi->szUserName); free(threadSi); } CloseHandle( hThread ); } else { free(threadSi); } }
lprintf( MSG_SYSINFO_COMPUTER, mySi.szMachineName ); lprintf( MSG_SYSINFO_USER, mySi.szUserName ); ProcessIdToSessionId(dp->dwPidToDebug, &TSid); _stprintf( buf, _T("%d"), TSid ); lprintf( MSG_SYSINFO_TERMINAL_SESSION, buf ); GetSystemInfo( &si ); _stprintf( buf, _T("%d"), si.dwNumberOfProcessors ); lprintf( MSG_SYSINFO_NUM_PROC, buf ); RegLogProcessorType(); ver = GetVersion(); _stprintf( buf, _T("%d.%d"), LOBYTE(LOWORD(ver)), HIBYTE(LOWORD(ver)) ); lprintf( MSG_SYSINFO_WINVER, buf ); RegLogCurrentVersion(); lprintfs( _T("\r\n") ); }
void LogTaskList( PDEBUGPACKET dp )
/*++
Routine Description:
This function gets the current task list and logs the process id & process name to the log file.
--*/
{ HRESULT Status; #define MAX_IDS 8192
PULONG Ids = NULL; ULONG IdCount; ULONG i;
Ids = (PULONG)malloc(sizeof(*Ids) * MAX_IDS); if (Ids == NULL) { goto Error; } if ((Status = dp->DbgClient-> GetRunningProcessSystemIds(0, Ids, MAX_IDS, &IdCount)) != S_OK) { goto Error; }
if (IdCount > MAX_IDS) { // Incomplete process list is good enough.
IdCount = MAX_IDS; }
lprintf( MSG_TASK_LIST );
for (i = 0; i < IdCount; i++) { char ExeName[MAX_PATH];
if ((Status = dp->DbgClient-> GetRunningProcessDescription(0, Ids[i], DEBUG_PROC_DESC_NO_PATHS, ExeName, sizeof(ExeName), NULL, NULL, 0, NULL)) != S_OK) { lprintfs(_T("%4d Error 0x%08X\r\n"), Ids[i], Status); } else { lprintfs(_T("%4d %hs\r\n"), Ids[i], ExeName); } }
lprintfs( _T("\r\n") );
free(Ids); return;
Error: _tprintf( _T("ERROR: could not get the task list\n") ); free(Ids); }
void LogModuleList( PDEBUGPACKET dp ) { HRESULT Status; ULONG NumMod; ULONG i; char Image[MAX_PATH]; DEBUG_MODULE_PARAMETERS Params; lprintf( MSG_MODULE_LIST );
if ((Status = dp->DbgSymbols->GetNumberModules(&NumMod, &i)) != S_OK) { lprintfs(_T("Error 0x%08X\r\n"), Status); return; }
for (i = 0; i < NumMod; i++) { if ((Status = dp->DbgSymbols-> GetModuleParameters(1, NULL, i, &Params)) != S_OK || FAILED(Status = dp->DbgSymbols-> GetModuleNames(i, 0, Image, sizeof(Image), NULL, NULL, 0, NULL, NULL, 0, NULL))) { lprintfs(_T("Error 0x%08X\r\n"), Status); } else { lprintfs(_T("%016I64x - %016I64x: %hs\r\n"), Params.Base, Params.Base + Params.Size, Image); } }
lprintfs( _T("\r\n") ); }
void LogStackDump( PDEBUGPACKET dp ) { HRESULT Status; DWORD i; DWORD j; BYTE stack[1024] = {0}; ULONG64 StackOffset;
if ((Status = dp->DbgRegisters->GetStackOffset(&StackOffset)) != S_OK || (Status = dp->DbgData->ReadVirtual(StackOffset, stack, sizeof(stack), &i)) != S_OK) { lprintfs(_T("Error 0x%08X\r\n"), Status); return; }
lprintf( MSG_STACK_DUMP_HEADER );
for( i = 0; i < 20; i++ ) { j = i * 16; lprintfs( _T("%016I64x %02x %02x %02x %02x %02x %02x %02x %02x - ") _T("%02x %02x %02x %02x %02x %02x %02x %02x ") _T("%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\r\n"), j + StackOffset, stack[ j + 0 ], stack[ j + 1 ], stack[ j + 2 ], stack[ j + 3 ], stack[ j + 4 ], stack[ j + 5 ], stack[ j + 6 ], stack[ j + 7 ], stack[ j + 8 ], stack[ j + 9 ], stack[ j + 10 ], stack[ j + 11 ], stack[ j + 12 ], stack[ j + 13 ], stack[ j + 14 ], stack[ j + 15 ], isprint( stack[ j + 0 ]) ? stack[ j + 0 ] : _T('.'), isprint( stack[ j + 1 ]) ? stack[ j + 1 ] : _T('.'), isprint( stack[ j + 2 ]) ? stack[ j + 2 ] : _T('.'), isprint( stack[ j + 3 ]) ? stack[ j + 3 ] : _T('.'), isprint( stack[ j + 4 ]) ? stack[ j + 4 ] : _T('.'), isprint( stack[ j + 5 ]) ? stack[ j + 5 ] : _T('.'), isprint( stack[ j + 6 ]) ? stack[ j + 6 ] : _T('.'), isprint( stack[ j + 7 ]) ? stack[ j + 7 ] : _T('.'), isprint( stack[ j + 8 ]) ? stack[ j + 8 ] : _T('.'), isprint( stack[ j + 9 ]) ? stack[ j + 9 ] : _T('.'), isprint( stack[ j + 10 ]) ? stack[ j + 10 ] : _T('.'), isprint( stack[ j + 11 ]) ? stack[ j + 11 ] : _T('.'), isprint( stack[ j + 12 ]) ? stack[ j + 12 ] : _T('.'), isprint( stack[ j + 13 ]) ? stack[ j + 13 ] : _T('.'), isprint( stack[ j + 14 ]) ? stack[ j + 14 ] : _T('.'), isprint( stack[ j + 15 ]) ? stack[ j + 15 ] : _T('.') ); }
lprintfs( _T("\r\n") ); }
void LogCurrentThreadInformation( PDEBUGPACKET dp, PCRASHES crash ) { HRESULT Status; ULONG ThreadId; _TCHAR IdBuf[16]; ULONG64 InstrOffs; DWORD InstrWindow; // The size should match the size of pCrash->szFunction
char FuncNameA[256]; WCHAR FuncNameW[256]; ULONG64 Displ;
if ((Status = dp->DbgSystem-> GetCurrentThreadSystemId(&ThreadId)) != S_OK) { ThreadId = 0xffffffff; } _stprintf( IdBuf, _T("%x"), ThreadId ); lprintf( MSG_STATE_DUMP, IdBuf );
dp->DbgClient->SetOutputCallbacks(&g_LogOutCb); if ((Status = dp->DbgRegisters-> OutputRegisters(DEBUG_OUTCTL_THIS_CLIENT, DEBUG_REGISTERS_DEFAULT)) != S_OK) { lprintfs(_T("Error 0x%08X\r\n"), Status); } lprintfs( _T("\r\n") );
InstrWindow = dp->options.dwInstructions; if (InstrWindow > 500) { InstrWindow = 500; }
strcpy(FuncNameA, "<nosymbols>"); wcscpy(FuncNameW, L"<nosymbols>");
if ((Status = dp->DbgRegisters-> GetInstructionOffset(&InstrOffs)) != S_OK) { lprintfs(_T("Error 0x%08X\r\n"), Status); } else { if (FAILED(Status = dp->DbgSymbols-> GetNameByOffset(InstrOffs, FuncNameA, sizeof(FuncNameA), NULL, &Displ))) { strcpy(FuncNameA, "<nosymbols>"); }
#ifdef UNICODE
if (MultiByteToWideChar(CP_ACP, 0, FuncNameA, -1, FuncNameW, sizeof(FuncNameW) / sizeof(WCHAR)) == 0) { wcscpy(FuncNameW, L"<nosymbols"); } lprintf( MSG_FUNCTION, FuncNameW ); #else
lprintf( MSG_FUNCTION, FuncNameA ); #endif
dp->DbgClient->SetOutputLinePrefix(" "); if ((Status = dp->DbgControl-> OutputDisassemblyLines(DEBUG_OUTCTL_THIS_CLIENT, InstrWindow, InstrWindow, InstrOffs, DEBUG_DISASM_MATCHING_SYMBOLS, NULL, NULL, NULL, NULL)) != S_OK) { lprintfs(_T("Error 0x%08X\r\n"), Status); }
// If this is the event thread output a message
// indicating the faulting instruction.
if (crash) { dp->DbgClient->SetOutputLinePrefix(NULL); lprintf( MSG_FAULT ); } if ((Status = dp->DbgControl-> OutputDisassembly(DEBUG_OUTCTL_THIS_CLIENT, InstrOffs, DEBUG_DISASM_EFFECTIVE_ADDRESS | DEBUG_DISASM_MATCHING_SYMBOLS, &InstrOffs)) != S_OK) { lprintfs(_T("Error 0x%08X\r\n"), Status); } dp->DbgClient->SetOutputLinePrefix(" "); if ((Status = dp->DbgControl-> OutputDisassemblyLines(DEBUG_OUTCTL_THIS_CLIENT, 0, InstrWindow, InstrOffs, DEBUG_DISASM_EFFECTIVE_ADDRESS | DEBUG_DISASM_MATCHING_SYMBOLS, NULL, NULL, NULL, NULL)) != S_OK) { lprintfs(_T("Error 0x%08X\r\n"), Status); } dp->DbgClient->SetOutputLinePrefix(NULL); } lprintfs( _T("\r\n") ); if (crash) { #ifdef UNICODE
wcscpy(crash->szFunction, FuncNameW); #else
strcpy(crash->szFunction, FuncNameA); #endif
}
lprintf( MSG_STACKTRACE ); if ((Status = dp->DbgControl-> OutputStackTrace(DEBUG_OUTCTL_THIS_CLIENT, NULL, 100, DEBUG_STACK_ARGUMENTS | DEBUG_STACK_FUNCTION_INFO | DEBUG_STACK_FRAME_ADDRESSES | DEBUG_STACK_COLUMN_NAMES)) != S_OK) { lprintfs(_T("Error 0x%08X\r\n"), Status); } lprintfs( _T("\r\n") ); dp->DbgClient->SetOutputCallbacks(NULL); LogStackDump( dp ); }
void LogAllThreadInformation( PDEBUGPACKET dp, PCRASHES crash ) { HRESULT Status; ULONG NumThreads; ULONG i; ULONG ThreadId; ULONG EventTid;
if (!dp->options.fDumpAllThreads) { // Just log the current event thread's information.
LogCurrentThreadInformation(dp, crash); return; } if ((Status = dp->DbgSystem->GetNumberThreads(&NumThreads)) != S_OK || (Status = dp->DbgSystem->GetEventThread(&EventTid)) != S_OK) { lprintfs(_T("Error 0x%08X\r\n"), Status); return; } for (i = 0; i < NumThreads; i++) { if ((Status = dp->DbgSystem-> GetThreadIdsByIndex(i, 1, &ThreadId, NULL)) != S_OK || (Status = dp->DbgSystem->SetCurrentThreadId(ThreadId)) != S_OK) { lprintfs(_T("Error 0x%08X\r\n"), Status); continue; }
LogCurrentThreadInformation(dp, ThreadId == EventTid ? crash : NULL); }
dp->DbgSystem->SetCurrentThreadId(EventTid); }
void LogSymbols( PDEBUGPACKET dp ) { HRESULT Status; char ModName[64]; char Buf[MAX_PATH]; ULONG64 InstrOffs; ULONG64 ModBase; lprintf( MSG_SYMBOL_TABLE ); if ((Status = dp->DbgRegisters-> GetInstructionOffset(&InstrOffs)) != S_OK || (Status = dp->DbgSymbols-> GetModuleByOffset(InstrOffs, 0, NULL, &ModBase)) != S_OK || FAILED(Status = dp->DbgSymbols-> GetModuleNames(DEBUG_ANY_ID, ModBase, Buf, sizeof(Buf), NULL, ModName, sizeof(ModName), NULL, NULL, 0, NULL))) { lprintfs(_T("Error 0x%08X\r\n"), Status); return; } lprintfs(_T("%hs\r\n\r\n"), Buf); sprintf(Buf, "x %s!*", ModName); dp->DbgClient->SetOutputCallbacks(&g_LogOutCb); dp->DbgControl->Execute(DEBUG_OUTCTL_THIS_CLIENT, Buf, DEBUG_EXECUTE_DEFAULT); dp->DbgClient->SetOutputCallbacks(NULL); }
void PostMortemDump( PDEBUGPACKET dp, PDEBUG_LAST_EVENT_INFO_EXCEPTION Exception ) { _TCHAR dbuf[MAX_PATH]; _TCHAR szDate[20]; _TCHAR szTime[20]; CRASHES crash = {0}; char ExeName[MAX_PATH];
GetLocalTime( &crash.time ); crash.dwExceptionCode = Exception->ExceptionRecord.ExceptionCode; crash.dwAddress = (DWORD_PTR)Exception->ExceptionRecord.ExceptionAddress; if (FAILED(dp->DbgSystem-> GetCurrentProcessExecutableName(ExeName, sizeof(ExeName), NULL))) { strcpy(ExeName, "<unknown>"); } #ifdef UNICODE
if (MultiByteToWideChar(CP_ACP, 0, ExeName, -1, crash.szAppName, sizeof(crash.szAppName) / sizeof(TCHAR)) == 0) { _tcscpy(crash.szAppName, _T("<unknown>")); } #endif
lprintf( MSG_APP_EXCEPTION ); _stprintf( dbuf, _T("%d"), dp->dwPidToDebug ); lprintf( MSG_APP_EXEP_NAME, crash.szAppName, dbuf );
GetDateFormat(LOCALE_SYSTEM_DEFAULT, DATE_SHORTDATE, &crash.time, NULL, szDate, sizeof(szDate) / sizeof(_TCHAR));
_sntprintf( szTime, _tsizeof(szTime), _T("%02d:%02d:%02d.%03d"), crash.time.wHour, crash.time.wMinute, crash.time.wSecond, crash.time.wMilliseconds ); szTime[_tsizeof(szTime) - 1] = 0; lprintf( MSG_APP_EXEP_WHEN, szDate, szTime ); _stprintf( dbuf, _T("%08lx"), Exception->ExceptionRecord.ExceptionCode ); lprintf( MSG_EXCEPTION_NUMBER, dbuf );
lprintfs( _T("(%s)\r\n\r\n"), GetExceptionText(Exception->ExceptionRecord.ExceptionCode) );
LogSystemInformation( dp );
LogTaskList( dp );
LogModuleList( dp );
LogAllThreadInformation(dp, &crash);
if (dp->options.fDumpSymbols) { LogSymbols( dp ); }
ElSaveCrash( &crash, dp->options.dwMaxCrashes );
dp->ExitStatus = Exception->ExceptionRecord.ExceptionCode; return; }
// Valid range: [1-7]
#define NUM_DIGITS_FNAME 2
void CalcNextFileName( IN PTSTR pszUserName, OUT PSTR pszFileName, IN OUT PINT pnCurrentValue, IN BOOL bUseLongFileNames ) { TCHAR szDrive[_MAX_DRIVE]; TCHAR szPath[_MAX_PATH]; TCHAR szFName[_MAX_FNAME]; TCHAR szExt[_MAX_EXT]; int nLargestPossibleNum; int nCnt;
Assert(pszUserName); Assert(pnCurrentValue);
Assert(1 <= NUM_DIGITS_FNAME); Assert(NUM_DIGITS_FNAME <= 7);
// Given the number of digits, this is the largest number +1
// we can have. If we could raise int to an int, this would
// be easy.
// nLargestPossibleNum = 10^NUM_DIGITS_FNAME
// We are intentionally over by one, the actual range is
// [0, 10^NUM_DIGITS_FNAME-1]
nLargestPossibleNum = 1; for (nCnt = 0; nCnt<NUM_DIGITS_FNAME; nCnt++) { nLargestPossibleNum *= 10; }
_tsplitpath(pszUserName, szDrive, szPath, szFName, szExt);
if (!bUseLongFileNames) { // Shorten the file name len to 6, so that we can
// add the 2 digit sequence.
// MSDOS FName len == 8
szFName[8 - NUM_DIGITS_FNAME] = 0; }
sprintf(pszFileName, #ifdef UNICODE
"%ls%ls%ls%0*d%ls", #else
"%s%s%s%0*d%s", #endif
szDrive, szPath, szFName, NUM_DIGITS_FNAME, *pnCurrentValue++, szExt );
// Make sure we stay in the range [0, 10^NUM_DIGITS_FNAME]
*pnCurrentValue = ++(*pnCurrentValue) % nLargestPossibleNum; }
BOOL CreateDumpFile( PDEBUGPACKET dp )
/*++
Routine Description:
This function creates a crash dump file.
Arguments:
dp - debug packet for current process
Return Value:
TRUE - Crash dump was created FALSE - Crash dump was NOT created
--*/
{ PTSTR p; PCSTR Comment = "Dr. Watson generated MiniDump"; ULONG Qual, Format = DEBUG_FORMAT_DEFAULT; HRESULT Status; char FileName[MAX_PATH];
p = ExpandPath( dp->options.szCrashDump ); if (!p) { return FALSE; }
if (dp->options.fUseSequentialNaming) { // Figure out what the next file name should be.
CalcNextFileName(p, FileName, &dp->options.nNextDumpSequence, dp->options.fUseLongFileNames );
// Save the next value of nCurrent
RegSave(&dp->options); } else { #ifdef UNICODE
if (WideCharToMultiByte(CP_ACP, 0, p, -1, FileName, _tsizeof(FileName), NULL, NULL) == 0) { return FALSE; } #else
lstrcpyn(FileName, p, _tsizeof(FileName)); #endif
}
switch (dp->options.dwType) { case FullDump: Qual = DEBUG_USER_WINDOWS_DUMP; Comment = NULL; break; case FullMiniDump: Format = DEBUG_FORMAT_USER_SMALL_FULL_MEMORY | DEBUG_FORMAT_USER_SMALL_HANDLE_DATA; // Fall through.
case MiniDump: Qual = DEBUG_USER_WINDOWS_SMALL_DUMP; break; default: return FALSE; }
Status = dp->DbgClient->WriteDumpFile2(FileName, Qual, Format, Comment); free( p ); return Status == S_OK; }
DWORD DispatchDebugEventThread( PDEBUGPACKET dp )
/*++
Routine Description:
This is the entry point for DRWTSN32
Arguments:
None.
Return Value:
None.
--*/
{ _TCHAR szLogFileName[1024]; _TCHAR buf[1024]; PTSTR p;
if (dp->dwPidToDebug == 0) { goto exit; }
CreateEngineInterfaces(dp);
SetErrorMode( SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX );
AttachToActiveProcess( dp );
p = ExpandPath(dp->options.szLogPath);
if (p) { lstrcpyn( szLogFileName, p, _tsizeof(szLogFileName) ); free( p ); } else { _tcscpy( szLogFileName, dp->options.szLogPath ); }
MakeLogFileName( szLogFileName ); OpenLogFile( szLogFileName, dp->options.fAppendToLogFile, dp->options.fVisual );
for (;;) {
ULONG Type, Process, Thread; DEBUG_LAST_EVENT_INFO_EXCEPTION LastEx; DWORD dwThreadId; HANDLE hThread; if (dp->DbgControl-> WaitForEvent(DEBUG_WAIT_DEFAULT, 30000) != S_OK || dp->DbgControl-> GetLastEventInformation(&Type, &Process, &Thread, &LastEx, sizeof(LastEx), NULL, NULL, 0, NULL) != S_OK) { break; }
switch (Type) { case DEBUG_EVENT_EXCEPTION: if (LastEx.ExceptionRecord.ExceptionCode == STATUS_BREAKPOINT) { //
// If there is no event to signal, just use the first
// breakpoint as the stop event.
//
if (dp->hEventToSignal && LastEx.FirstChance) { //
// The aedebug event will be signalled AFTER this
// thread exits, so that it will disappear before
// the dump snapshot is taken.
//
dp->DbgControl->SetExecutionStatus(DEBUG_STATUS_GO_HANDLED); break; } } if (dp->options.fVisual) { //
// this notification is necessary because the shell must know when
// the debugee has been attached. if it doesn't know and the user is
// allowed to terminate drwatson then the system may intervene with
// a popup.
//
SendMessage( dp->hwnd, WM_ATTACHCOMPLETE, 0, 0 ); _sntprintf( buf, _tsizeof(buf), LoadRcString( IDS_AE_TEXT ), GetExceptionText(LastEx.ExceptionRecord.ExceptionCode), LastEx.ExceptionRecord.ExceptionCode, LastEx.ExceptionRecord.ExceptionAddress ); buf[_tsizeof(buf) - 1] = 0; SendMessage( dp->hwnd, WM_EXCEPTIONINFO, 0, (LPARAM) buf ); } PostMortemDump( dp, &LastEx ); if (dp->options.fCrash) { CreateDumpFile( dp ); }
//
// Attempt to terminate the debuggee. Continue
// on if this doesn't work as the debuggee should
// be killed anyway when Dr. Watson exits.
//
hThread = CreateThread( NULL, 16000, (LPTHREAD_START_ROUTINE)TerminationThread, dp, 0, &dwThreadId ); if (hThread) { WaitForSingleObject( hThread, 30000 ); CloseHandle( hThread ); }
dp->DbgControl->SetExecutionStatus(DEBUG_STATUS_GO_NOT_HANDLED); break;
case DEBUG_EVENT_EXIT_THREAD: if ( dp->hEventToSignal ) { SetEvent(dp->hEventToSignal); dp->hEventToSignal = 0L; } dp->DbgControl->SetExecutionStatus(DEBUG_STATUS_GO); break; } }
exit: CloseLogFile();
if (dp->options.fVisual) { SendMessage( dp->hwnd, WM_DUMPCOMPLETE, 0, 0 ); }
return 0; }
DWORD TerminationThread( PDEBUGPACKET dp ) { HANDLE hProcess;
hProcess = OpenProcess( PROCESS_TERMINATE, FALSE, dp->dwPidToDebug ); if (hProcess != NULL) { TerminateProcess( hProcess, dp->ExitStatus ); CloseHandle( hProcess ); }
return 0; }
|