862 lines
22 KiB
C++
862 lines
22 KiB
C++
|
/*++
|
||
|
|
||
|
Copyright (c) 1989-2000 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
Debugger.cpp
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
This module implements the AppVerifier.exe debugger.
|
||
|
|
||
|
Author:
|
||
|
|
||
|
clupu created 01/25/2001
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
--*/
|
||
|
|
||
|
#include "stdafx.h"
|
||
|
#include "appverif.h"
|
||
|
|
||
|
#include "Log.h"
|
||
|
|
||
|
#include <memory.h>
|
||
|
#include <stdlib.h>
|
||
|
#include "wdbgexts.h"
|
||
|
|
||
|
#include "Debugger.h"
|
||
|
#include "Setting.h"
|
||
|
#include "UserDump.h"
|
||
|
#include "DbgHelp.h"
|
||
|
#include "ChooseExe.h"
|
||
|
|
||
|
#ifdef BP_SIZE
|
||
|
ULONG g_BpSize = BP_SIZE;
|
||
|
#endif
|
||
|
#ifdef BP_INSTR
|
||
|
ULONG g_BpInstr = BP_INSTR;
|
||
|
#endif
|
||
|
|
||
|
typedef void (*PFNDBGEXT)(HANDLE hCurrentProcess,
|
||
|
HANDLE hCurrentThread,
|
||
|
DWORD dwUnused,
|
||
|
PWINDBG_EXTENSION_APIS lpExtensionApis,
|
||
|
LPSTR lpArgumentString);
|
||
|
|
||
|
|
||
|
|
||
|
PFNDBGEXT g_pfnPhextsInit;
|
||
|
|
||
|
BOOL g_bInitialBreakpoint = TRUE;
|
||
|
|
||
|
PROCESS_INFORMATION g_ProcessInformation;
|
||
|
|
||
|
WINDBG_EXTENSION_APIS ExtensionAPIs;
|
||
|
|
||
|
|
||
|
typedef struct tagLOADEDDLL
|
||
|
{
|
||
|
struct tagLOADEDDLL* pNext;
|
||
|
LPTSTR pszName;
|
||
|
LPVOID lpBaseOfDll;
|
||
|
} LOADEDDLL, *PLOADEDDLL;
|
||
|
|
||
|
PLOADEDDLL g_pFirstDll;
|
||
|
|
||
|
|
||
|
PPROCESS_INFO g_pProcessHead = NULL;
|
||
|
PPROCESS_INFO g_pFirstProcess = NULL;
|
||
|
|
||
|
|
||
|
//
|
||
|
// BUGBUG: what's this for ?
|
||
|
//
|
||
|
TCHAR g_szDbgString[1024];
|
||
|
|
||
|
|
||
|
//
|
||
|
// Local function prototypes
|
||
|
//
|
||
|
|
||
|
void DebuggerLoop(void);
|
||
|
|
||
|
|
||
|
|
||
|
DWORD WINAPI ExecuteAppThread( LPVOID lParam )
|
||
|
/*++
|
||
|
Return: TRUE if successful, FALSE otherwise.
|
||
|
|
||
|
Desc: Launch the debuggee.
|
||
|
--*/
|
||
|
{
|
||
|
BOOL bRet;
|
||
|
STARTUPINFO StartupInfo;
|
||
|
|
||
|
ZeroMemory(&StartupInfo, sizeof(StartupInfo));
|
||
|
StartupInfo.cb = sizeof(StartupInfo);
|
||
|
|
||
|
//
|
||
|
// Set some pageheap flags
|
||
|
//
|
||
|
AVSetVerifierFlagsForExe(g_szAppShortName, (DWORD)(LPARAM)lParam);
|
||
|
|
||
|
bRet = CreateProcess(NULL,
|
||
|
g_szAppFullPath,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
FALSE,
|
||
|
CREATE_SEPARATE_WOW_VDM | DEBUG_ONLY_THIS_PROCESS,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
&StartupInfo,
|
||
|
&g_ProcessInformation);
|
||
|
|
||
|
if ( !bRet )
|
||
|
{
|
||
|
LogMessage(LOG_ERROR, _T("[ExecuteApp] Couldn't start \"%s\""), g_szAppFullPath);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
LogMessage(LOG_INFO,
|
||
|
_T("[ExecuteApp] CreateProcess hProcess 0x%X. \"%s\""),
|
||
|
g_ProcessInformation.hProcess,
|
||
|
g_szAppFullPath);
|
||
|
|
||
|
if ( g_ProcessInformation.hProcess != NULL )
|
||
|
{
|
||
|
|
||
|
//
|
||
|
// Start the debugger loop.
|
||
|
//
|
||
|
DebuggerLoop();
|
||
|
|
||
|
//
|
||
|
// Free the memory.
|
||
|
//
|
||
|
PPROCESS_INFO pProcess = g_pProcessHead;
|
||
|
PPROCESS_INFO pProcessNext;
|
||
|
|
||
|
while ( pProcess != NULL )
|
||
|
{
|
||
|
pProcessNext = pProcess->pNext;
|
||
|
|
||
|
PTHREAD_INFO pThread = pProcess->pFirstThreadInfo;
|
||
|
PTHREAD_INFO pThreadNext;
|
||
|
|
||
|
while ( pThread != NULL )
|
||
|
{
|
||
|
pThreadNext = pThread->pNext;
|
||
|
|
||
|
HeapFree(GetProcessHeap(), 0, pThread);
|
||
|
|
||
|
pThread = pThreadNext;
|
||
|
}
|
||
|
|
||
|
HeapFree(GetProcessHeap(), 0, pProcess);
|
||
|
|
||
|
pProcess = pProcessNext;
|
||
|
}
|
||
|
|
||
|
g_pProcessHead = NULL;
|
||
|
|
||
|
PLOADEDDLL pDll = g_pFirstDll;
|
||
|
PLOADEDDLL pDllNext;
|
||
|
|
||
|
while ( pDll != NULL )
|
||
|
{
|
||
|
pDllNext = pDll->pNext;
|
||
|
|
||
|
HeapFree(GetProcessHeap(), 0, pDll->pszName);
|
||
|
HeapFree(GetProcessHeap(), 0, pDll);
|
||
|
|
||
|
pDll = pDllNext;
|
||
|
}
|
||
|
|
||
|
g_pFirstDll = NULL;
|
||
|
|
||
|
g_bDebuggeeExited = TRUE;
|
||
|
|
||
|
CloseHandle(g_ProcessInformation.hProcess);
|
||
|
CloseHandle(g_ProcessInformation.hThread);
|
||
|
|
||
|
ZeroMemory(&g_ProcessInformation, sizeof(PROCESS_INFORMATION));
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Delete the pageheap flags
|
||
|
//
|
||
|
AVSetVerifierFlagsForExe(g_szAppShortName, 0);
|
||
|
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
|
||
|
PPROCESS_INFO GetProcessInfo( HANDLE hProcess )
|
||
|
{
|
||
|
PPROCESS_INFO pProcess = g_pProcessHead;
|
||
|
|
||
|
while ( pProcess != NULL )
|
||
|
{
|
||
|
if ( pProcess->hProcess == hProcess )
|
||
|
{
|
||
|
return pProcess;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
SIZE_T
|
||
|
ReadMemoryDbg(
|
||
|
HANDLE hProcess,
|
||
|
LPVOID Address,
|
||
|
LPVOID Buffer,
|
||
|
SIZE_T Length
|
||
|
)
|
||
|
{
|
||
|
SIZE_T cbRead;
|
||
|
LPVOID AddressBp;
|
||
|
PPROCESS_INFO pProcess;
|
||
|
|
||
|
if ( !ReadProcessMemory(hProcess,
|
||
|
Address,
|
||
|
Buffer,
|
||
|
Length,
|
||
|
&cbRead) )
|
||
|
{
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
pProcess = GetProcessInfo(hProcess);
|
||
|
|
||
|
if ( pProcess == NULL )
|
||
|
{
|
||
|
return 0;
|
||
|
}
|
||
|
#if defined(BP_INSTR) && defined(BP_SIZE)
|
||
|
for ( int i = 0; i < MAX_BREAKPOINTS; i++ )
|
||
|
{
|
||
|
|
||
|
AddressBp = pProcess->bp[i].Address;
|
||
|
|
||
|
if ( (ULONG_PTR)AddressBp >= (ULONG_PTR)Address &&
|
||
|
(ULONG_PTR)AddressBp < (ULONG_PTR)Address + Length )
|
||
|
{
|
||
|
|
||
|
CopyMemory((LPVOID)((ULONG_PTR)Buffer + (ULONG_PTR)AddressBp - (ULONG_PTR)Address),
|
||
|
&pProcess->bp[i].OriginalInstr,
|
||
|
g_BpSize);
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
return cbRead;
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
WriteMemoryDbg(
|
||
|
HANDLE hProcess,
|
||
|
PVOID Address,
|
||
|
PVOID Buffer,
|
||
|
SIZE_T Length
|
||
|
)
|
||
|
{
|
||
|
SIZE_T cb = 0;
|
||
|
BOOL bSuccess;
|
||
|
|
||
|
bSuccess = WriteProcessMemory(hProcess, Address, Buffer, Length, &cb);
|
||
|
|
||
|
if ( !bSuccess || cb != Length )
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
GetImageName(
|
||
|
HANDLE hProcess,
|
||
|
ULONG_PTR ImageBase,
|
||
|
PVOID ImageNamePtr,
|
||
|
LPTSTR ImageName,
|
||
|
DWORD ImageNameLength
|
||
|
)
|
||
|
/*++
|
||
|
Return: TRUE if successful, FALSE otherwise.
|
||
|
|
||
|
Desc: BUGBUG: give details here
|
||
|
--*/
|
||
|
{
|
||
|
DWORD_PTR i;
|
||
|
BYTE UnicodeBuf[256 * 2];
|
||
|
IMAGE_DOS_HEADER dh;
|
||
|
IMAGE_NT_HEADERS nh;
|
||
|
IMAGE_EXPORT_DIRECTORY expdir;
|
||
|
|
||
|
if ( !ReadMemoryDbg(hProcess,
|
||
|
(ULONG*)ImageNamePtr,
|
||
|
&i,
|
||
|
sizeof(i)) )
|
||
|
{
|
||
|
|
||
|
goto GetFromExports;
|
||
|
}
|
||
|
|
||
|
if ( !ReadMemoryDbg(hProcess,
|
||
|
(ULONG*)i,
|
||
|
(ULONG*)UnicodeBuf,
|
||
|
sizeof(UnicodeBuf)) )
|
||
|
{
|
||
|
|
||
|
goto GetFromExports;
|
||
|
}
|
||
|
|
||
|
ZeroMemory(ImageName, ImageNameLength);
|
||
|
|
||
|
#ifdef UNICODE
|
||
|
lstrcpyW(ImageName, (LPCWSTR)UnicodeBuf);
|
||
|
#else
|
||
|
WideCharToMultiByte(CP_ACP,
|
||
|
0,
|
||
|
(LPWSTR)UnicodeBuf,
|
||
|
wcslen((LPWSTR)UnicodeBuf),
|
||
|
ImageName,
|
||
|
ImageNameLength,
|
||
|
NULL,
|
||
|
NULL);
|
||
|
#endif // UNICODE
|
||
|
|
||
|
if ( lstrlen(ImageName) == 0 )
|
||
|
{
|
||
|
goto GetFromExports;
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
|
||
|
GetFromExports:
|
||
|
|
||
|
if ( !ReadMemoryDbg(hProcess,
|
||
|
(ULONG*)ImageBase,
|
||
|
(ULONG*)&dh,
|
||
|
sizeof(IMAGE_DOS_HEADER)) )
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
if ( dh.e_magic != IMAGE_DOS_SIGNATURE )
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
if ( !ReadMemoryDbg(hProcess,
|
||
|
(ULONG*)(ImageBase + dh.e_lfanew),
|
||
|
(ULONG*)&nh,
|
||
|
sizeof(IMAGE_NT_HEADERS)) )
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
if ( nh.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress == 0 )
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
if ( !ReadMemoryDbg(hProcess,
|
||
|
(ULONG*)(ImageBase +
|
||
|
nh.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress),
|
||
|
(ULONG*)&expdir,
|
||
|
sizeof(IMAGE_EXPORT_DIRECTORY)) )
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
if ( !ReadMemoryDbg(hProcess,
|
||
|
(ULONG*)(ImageBase + expdir.Name),
|
||
|
#ifdef UNICODE
|
||
|
(ULONG*)UnicodeBuf,
|
||
|
#else
|
||
|
(ULONG*)ImageName,
|
||
|
#endif // UNICODE
|
||
|
ImageNameLength) )
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
#ifdef UNICODE
|
||
|
MultiByteToWideChar(CP_ACP,
|
||
|
0,
|
||
|
(LPCSTR)UnicodeBuf,
|
||
|
-1,
|
||
|
ImageName,
|
||
|
ImageNameLength);
|
||
|
#endif // UNICODE
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
AddDll(
|
||
|
LPVOID lpBaseOfDll,
|
||
|
LPCTSTR pszDllName
|
||
|
)
|
||
|
/*++
|
||
|
Return: void.
|
||
|
|
||
|
Desc: BUGBUG: give details here
|
||
|
--*/
|
||
|
{
|
||
|
PLOADEDDLL pDll;
|
||
|
|
||
|
pDll = (PLOADEDDLL)HeapAlloc(GetProcessHeap(), 0, sizeof(LOADEDDLL));
|
||
|
|
||
|
if ( pDll == NULL )
|
||
|
{
|
||
|
LogMessage(LOG_ERROR, _T("[AddDll] Failed to allocate %d bytes"), sizeof(LOADEDDLL));
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
pDll->pszName = (LPTSTR)HeapAlloc(GetProcessHeap(), 0, (lstrlen(pszDllName) + 1) * sizeof(TCHAR));
|
||
|
|
||
|
if ( pDll->pszName == NULL )
|
||
|
{
|
||
|
HeapFree(GetProcessHeap(), 0, pDll);
|
||
|
LogMessage(LOG_ERROR,
|
||
|
_T("[AddDll] Failed to allocate %d bytes"),
|
||
|
(lstrlen(pszDllName) + 1) * sizeof(TCHAR));
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
lstrcpy(pDll->pszName, pszDllName);
|
||
|
|
||
|
pDll->lpBaseOfDll = lpBaseOfDll;
|
||
|
|
||
|
pDll->pNext = g_pFirstDll;
|
||
|
g_pFirstDll = pDll;
|
||
|
}
|
||
|
|
||
|
LPTSTR GetDll( LPVOID lpBaseOfDll )
|
||
|
/*++
|
||
|
Return: The name of the DLL with the specified base address.
|
||
|
|
||
|
Desc: BUGBUG
|
||
|
--*/
|
||
|
{
|
||
|
PLOADEDDLL pDll = g_pFirstDll;
|
||
|
|
||
|
while ( pDll != NULL )
|
||
|
{
|
||
|
if ( pDll->lpBaseOfDll == lpBaseOfDll )
|
||
|
{
|
||
|
return pDll->pszName;
|
||
|
}
|
||
|
pDll = pDll->pNext;
|
||
|
}
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
void RemoveDll( LPVOID lpBaseOfDll )
|
||
|
/*++
|
||
|
Return: void.
|
||
|
|
||
|
Desc: BUGBUG: give details here
|
||
|
--*/
|
||
|
{
|
||
|
PLOADEDDLL* ppDll = &g_pFirstDll;
|
||
|
PLOADEDDLL pDllFree;
|
||
|
|
||
|
while ( *ppDll != NULL )
|
||
|
{
|
||
|
|
||
|
if ( (*ppDll)->lpBaseOfDll == lpBaseOfDll )
|
||
|
{
|
||
|
|
||
|
HeapFree(GetProcessHeap(), 0, (*ppDll)->pszName);
|
||
|
pDllFree = *ppDll;
|
||
|
|
||
|
*ppDll = (*ppDll)->pNext;
|
||
|
|
||
|
HeapFree(GetProcessHeap(), 0, pDllFree);
|
||
|
break;
|
||
|
}
|
||
|
ppDll = &((*ppDll)->pNext);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL ProcessModuleLoad( PPROCESS_INFO pProcess, DEBUG_EVENT* pde )
|
||
|
|
||
|
/*++
|
||
|
Return: TRUE on success, FALSE otherwise
|
||
|
|
||
|
Desc: Process all module load debug events, create process & dll load.
|
||
|
The purpose is to allocate a MODULEINFO structure, fill in the
|
||
|
necessary values, and load the symbol table.
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
HANDLE hFile=NULL;
|
||
|
DWORD_PTR dwBaseOfImage;
|
||
|
|
||
|
if ( pde->dwDebugEventCode == CREATE_PROCESS_DEBUG_EVENT )
|
||
|
{
|
||
|
|
||
|
hFile = pde->u.CreateProcessInfo.hFile;
|
||
|
dwBaseOfImage = (DWORD_PTR)pde->u.CreateProcessInfo.lpBaseOfImage;
|
||
|
|
||
|
SymInitialize(pProcess->hProcess, NULL, FALSE);
|
||
|
|
||
|
}
|
||
|
else if ( pde->dwDebugEventCode == LOAD_DLL_DEBUG_EVENT )
|
||
|
{
|
||
|
hFile = pde->u.LoadDll.hFile;
|
||
|
dwBaseOfImage = (DWORD_PTR)pde->u.LoadDll.lpBaseOfDll;
|
||
|
}
|
||
|
|
||
|
if ( hFile == NULL || hFile == INVALID_HANDLE_VALUE )
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
if ( dwBaseOfImage==(DWORD_PTR)NULL )
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
if ( !SymLoadModule(pProcess->hProcess, hFile, NULL, NULL, dwBaseOfImage, 0) )
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
void DebuggerLoop( void )
|
||
|
/*++
|
||
|
Return: void.
|
||
|
|
||
|
Desc: BUGBUG: give details here
|
||
|
--*/
|
||
|
{
|
||
|
DEBUG_EVENT DebugEv; // debugging event information
|
||
|
DWORD dwContinueStatus = DBG_CONTINUE; // exception continuation
|
||
|
PPROCESS_INFO pProcess = NULL;
|
||
|
PTHREAD_INFO pThread = NULL;
|
||
|
|
||
|
while ( TRUE )
|
||
|
{
|
||
|
|
||
|
//
|
||
|
// Wait for a debugging event to occur. The second parameter indicates
|
||
|
// that the function does not return until a debugging event occurs.
|
||
|
//
|
||
|
WaitForDebugEvent(&DebugEv, INFINITE);
|
||
|
|
||
|
//
|
||
|
// Update the processes and threads lists.
|
||
|
//
|
||
|
pProcess = g_pProcessHead;
|
||
|
while ( pProcess != NULL )
|
||
|
{
|
||
|
if ( pProcess->dwProcessId == DebugEv.dwProcessId )
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
pProcess = pProcess->pNext;
|
||
|
}
|
||
|
|
||
|
if ( pProcess == NULL )
|
||
|
{
|
||
|
//
|
||
|
// New process.
|
||
|
//
|
||
|
pProcess = (PPROCESS_INFO)HeapAlloc(GetProcessHeap(),
|
||
|
HEAP_ZERO_MEMORY,
|
||
|
sizeof(PROCESS_INFO));
|
||
|
if ( pProcess == NULL )
|
||
|
{
|
||
|
LogMessage(LOG_ERROR,
|
||
|
_T("[DebuggerLoop] Failed to allocate memory for the new process. Fatal !"));
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
pProcess->dwProcessId = DebugEv.dwProcessId;
|
||
|
pProcess->pNext = g_pProcessHead;
|
||
|
g_pProcessHead = pProcess;
|
||
|
}
|
||
|
|
||
|
pThread = pProcess->pFirstThreadInfo;
|
||
|
|
||
|
while ( pThread != NULL )
|
||
|
{
|
||
|
if ( pThread->dwThreadId == DebugEv.dwThreadId )
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
pThread = pThread->pNext;
|
||
|
}
|
||
|
|
||
|
if ( pThread == NULL )
|
||
|
{
|
||
|
//
|
||
|
// New thread.
|
||
|
//
|
||
|
pThread = (PTHREAD_INFO)HeapAlloc(GetProcessHeap(),
|
||
|
HEAP_ZERO_MEMORY,
|
||
|
sizeof(THREAD_INFO));
|
||
|
if ( pThread == NULL )
|
||
|
{
|
||
|
LogMessage(LOG_ERROR,
|
||
|
_T("[DebuggerLoop] Failed to allocate memory for the new thread. Fatal !"));
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
pThread->dwThreadId = DebugEv.dwThreadId;
|
||
|
pThread->pNext = pProcess->pFirstThreadInfo;
|
||
|
pProcess->pFirstThreadInfo = pThread;
|
||
|
}
|
||
|
|
||
|
dwContinueStatus = DBG_CONTINUE;
|
||
|
|
||
|
if ( DebugEv.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT )
|
||
|
{
|
||
|
goto EndProcess;
|
||
|
}
|
||
|
|
||
|
switch ( DebugEv.dwDebugEventCode )
|
||
|
{
|
||
|
|
||
|
case EXCEPTION_DEBUG_EVENT:
|
||
|
|
||
|
switch ( DebugEv.u.Exception.ExceptionRecord.ExceptionCode )
|
||
|
{
|
||
|
case EXCEPTION_BREAKPOINT:
|
||
|
|
||
|
//
|
||
|
// Hit a breakpoint.
|
||
|
//
|
||
|
if ( !pProcess->bSeenLdrBp )
|
||
|
{
|
||
|
|
||
|
pProcess->bSeenLdrBp = TRUE;
|
||
|
|
||
|
//
|
||
|
// When the initial breakpoint is hit all the
|
||
|
// staticly linked DLLs are already loaded so
|
||
|
// we can go ahead and set breakpoints.
|
||
|
//
|
||
|
LogMessage(LOG_INFO, _T("[DebuggerLoop] Hit initial breakpoint."));
|
||
|
|
||
|
//
|
||
|
// Now it would be a good time to initialize the debugger extensions.
|
||
|
//
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
LogMessage(LOG_INFO, _T("[DebuggerLoop] Hit breakpoint."));
|
||
|
|
||
|
LogAVStatus(AVS_PAGEHEAP_DOUBLEFREE);
|
||
|
|
||
|
if ( MessageBox(NULL,
|
||
|
_T("An Access Violation occured. Do you want to create")
|
||
|
_T(" a crash dump file so you can later debug this problem ?"),
|
||
|
_T("Error"),
|
||
|
MB_ICONEXCLAMATION | MB_YESNO | MB_DEFBUTTON1) == IDYES )
|
||
|
{
|
||
|
|
||
|
pProcess->DebugEvent = DebugEv;
|
||
|
GenerateUserModeDump(g_szCrashDumpFile,
|
||
|
pProcess,
|
||
|
&DebugEv.u.Exception);
|
||
|
}
|
||
|
|
||
|
if ( MessageBox(NULL,
|
||
|
_T("Do you want to continue running the program ?"),
|
||
|
_T("Error"),
|
||
|
MB_ICONEXCLAMATION | MB_YESNO | MB_DEFBUTTON1) != IDYES )
|
||
|
{
|
||
|
goto EndProcess;
|
||
|
}
|
||
|
|
||
|
dwContinueStatus = DBG_EXCEPTION_NOT_HANDLED;
|
||
|
break;
|
||
|
|
||
|
case STATUS_SINGLE_STEP:
|
||
|
LogMessage(LOG_INFO, _T("[DebuggerLoop] Hit single step breakpoint."));
|
||
|
break;
|
||
|
|
||
|
case EXCEPTION_ACCESS_VIOLATION:
|
||
|
LogMessage(LOG_INFO,
|
||
|
_T("[DebuggerLoop] AV. Addr: 0x%08X, firstChance %d"),
|
||
|
DebugEv.u.Exception.ExceptionRecord.ExceptionAddress,
|
||
|
DebugEv.u.Exception.dwFirstChance);
|
||
|
|
||
|
LogAVStatus(AVS_PAGEHEAP_DOUBLEFREE);
|
||
|
|
||
|
if ( MessageBox(NULL,
|
||
|
_T("An Access Violation occured. Do you want to create")
|
||
|
_T(" a crash dump file so you can later debug this problem ?"),
|
||
|
_T("Error"),
|
||
|
MB_ICONEXCLAMATION | MB_YESNO | MB_DEFBUTTON1) == IDYES )
|
||
|
{
|
||
|
|
||
|
pProcess->DebugEvent = DebugEv;
|
||
|
GenerateUserModeDump(g_szCrashDumpFile,
|
||
|
pProcess,
|
||
|
&DebugEv.u.Exception);
|
||
|
}
|
||
|
|
||
|
if ( MessageBox(NULL,
|
||
|
_T("Do you want to continue running the program ?"),
|
||
|
_T("Error"),
|
||
|
MB_ICONEXCLAMATION | MB_YESNO | MB_DEFBUTTON1) != IDYES )
|
||
|
{
|
||
|
goto EndProcess;
|
||
|
}
|
||
|
|
||
|
dwContinueStatus = DBG_EXCEPTION_NOT_HANDLED;
|
||
|
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
LogMessage(LOG_INFO, _T("[DebuggerLoop] Unknown debugger exception."));
|
||
|
|
||
|
dwContinueStatus = DBG_EXCEPTION_NOT_HANDLED;
|
||
|
break;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case CREATE_THREAD_DEBUG_EVENT:
|
||
|
pThread->hProcess = pProcess->hProcess;
|
||
|
pThread->hThread = DebugEv.u.CreateThread.hThread;
|
||
|
|
||
|
LogMessage(LOG_INFO,
|
||
|
_T("[DebuggerLoop] new thread. StartAddress: 0x%x"),
|
||
|
DebugEv.u.CreateThread.lpStartAddress);
|
||
|
break;
|
||
|
|
||
|
case EXIT_THREAD_DEBUG_EVENT:
|
||
|
LogMessage(LOG_INFO,
|
||
|
_T("[DebuggerLoop] exiting thread with code: 0x%x"),
|
||
|
DebugEv.u.ExitThread.dwExitCode);
|
||
|
break;
|
||
|
|
||
|
case CREATE_PROCESS_DEBUG_EVENT:
|
||
|
|
||
|
pProcess->hProcess = DebugEv.u.CreateProcessInfo.hProcess;
|
||
|
pThread->hProcess = pProcess->hProcess;
|
||
|
pThread->hThread = DebugEv.u.CreateProcessInfo.hThread;
|
||
|
|
||
|
if ( g_pFirstProcess == NULL )
|
||
|
{
|
||
|
g_pFirstProcess = pProcess;
|
||
|
}
|
||
|
|
||
|
pProcess->EntryPoint = DebugEv.u.CreateProcessInfo.lpStartAddress;
|
||
|
|
||
|
ProcessModuleLoad(pProcess, &DebugEv);
|
||
|
|
||
|
LogMessage(LOG_INFO,
|
||
|
_T("[DebuggerLoop] new process. BaseImage: 0x%x StartAddress: 0x%x"),
|
||
|
DebugEv.u.CreateProcessInfo.lpBaseOfImage,
|
||
|
DebugEv.u.CreateProcessInfo.lpStartAddress);
|
||
|
break;
|
||
|
|
||
|
case LOAD_DLL_DEBUG_EVENT:
|
||
|
{
|
||
|
TCHAR szAsciiBuf[256];
|
||
|
TCHAR szDllName[128];
|
||
|
TCHAR szExt[16];
|
||
|
BOOL bRet;
|
||
|
|
||
|
bRet = GetImageName(pProcess->hProcess,
|
||
|
(ULONG_PTR)DebugEv.u.LoadDll.lpBaseOfDll,
|
||
|
DebugEv.u.LoadDll.lpImageName,
|
||
|
szAsciiBuf,
|
||
|
sizeof(szAsciiBuf));
|
||
|
if (!bRet) {
|
||
|
LogMessage(LOG_INFO,
|
||
|
_T("[DebuggerLoop] DLL LOADED. BaseDll: 0x%X cannot get the name."),
|
||
|
DebugEv.u.LoadDll.lpBaseOfDll);
|
||
|
AddDll(DebugEv.u.LoadDll.lpBaseOfDll, NULL);
|
||
|
} else {
|
||
|
_tsplitpath(szAsciiBuf, NULL, NULL, szDllName, szExt);
|
||
|
lstrcat(szDllName, szExt);
|
||
|
|
||
|
AddDll(DebugEv.u.LoadDll.lpBaseOfDll, szDllName);
|
||
|
|
||
|
LogMessage(LOG_INFO,
|
||
|
_T("[DebuggerLoop] DLL LOADED. BaseDll: 0x%X \"%s\"."),
|
||
|
DebugEv.u.LoadDll.lpBaseOfDll,
|
||
|
szDllName);
|
||
|
}
|
||
|
|
||
|
ProcessModuleLoad(pProcess, &DebugEv);
|
||
|
|
||
|
CloseHandle(DebugEv.u.LoadDll.hFile);
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case UNLOAD_DLL_DEBUG_EVENT:
|
||
|
{
|
||
|
LPTSTR pszName = GetDll(DebugEv.u.UnloadDll.lpBaseOfDll);
|
||
|
|
||
|
if ( pszName == NULL )
|
||
|
{
|
||
|
LogMessage(LOG_INFO,
|
||
|
_T("[DebuggerLoop] DLL UNLOADED. BaseDll: 0x%X unknown."),
|
||
|
DebugEv.u.UnloadDll.lpBaseOfDll);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
LogMessage(LOG_INFO,
|
||
|
_T("[DebuggerLoop] DLL UNLOADED. BaseDll: 0x%X \"%s\"."),
|
||
|
DebugEv.u.UnloadDll.lpBaseOfDll, pszName);
|
||
|
}
|
||
|
|
||
|
RemoveDll(DebugEv.u.UnloadDll.lpBaseOfDll);
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case OUTPUT_DEBUG_STRING_EVENT:
|
||
|
ReadMemoryDbg(pThread->hProcess,
|
||
|
DebugEv.u.DebugString.lpDebugStringData,
|
||
|
g_szDbgString,
|
||
|
DebugEv.u.DebugString.nDebugStringLength);
|
||
|
|
||
|
#ifdef UNICODE
|
||
|
LogMessage(LOG_INFO, _T("DPF - %S"), g_szDbgString);
|
||
|
#else
|
||
|
LogMessage(LOG_INFO, _T("DPF - %s"), g_szDbgString);
|
||
|
#endif // UNICODE
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
LogMessage(LOG_ERROR,
|
||
|
_T("[DebuggerLoop] Unknown event 0x%X"),
|
||
|
DebugEv.dwDebugEventCode);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Resume executing the thread that reported the debugging event.
|
||
|
//
|
||
|
ContinueDebugEvent(DebugEv.dwProcessId,
|
||
|
DebugEv.dwThreadId,
|
||
|
dwContinueStatus);
|
||
|
}
|
||
|
|
||
|
EndProcess:
|
||
|
LogMessage(LOG_INFO, _T("[DebuggerLoop] The debugged process has exited."));
|
||
|
|
||
|
LogAVStatus(AVS_APP_TERMINATED);
|
||
|
}
|
||
|
|
||
|
|