776 lines
20 KiB
C++
776 lines
20 KiB
C++
|
|
||
|
#include "precomp.h"
|
||
|
|
||
|
|
||
|
#include <memory.h>
|
||
|
#include <stdlib.h>
|
||
|
#include "wdbgexts.h"
|
||
|
|
||
|
#include "Debugger.h"
|
||
|
#include "UserDump.h"
|
||
|
#include "DbgHelp.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);
|
||
|
|
||
|
|
||
|
TCHAR g_szCrashDumpFile[MAX_PATH];
|
||
|
|
||
|
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
|
||
|
DebugApp(
|
||
|
LPTSTR pszAppName
|
||
|
)
|
||
|
/*++
|
||
|
Return: TRUE if successful, FALSE otherwise.
|
||
|
|
||
|
Desc: Launch the debuggee.
|
||
|
--*/
|
||
|
{
|
||
|
BOOL bRet;
|
||
|
STARTUPINFO StartupInfo;
|
||
|
|
||
|
wcscpy(g_szCrashDumpFile, L"d:\\temp\\crash.dmp");
|
||
|
|
||
|
ZeroMemory(&StartupInfo, sizeof(StartupInfo));
|
||
|
StartupInfo.cb = sizeof(StartupInfo);
|
||
|
|
||
|
bRet = CreateProcess(NULL,
|
||
|
pszAppName,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
FALSE,
|
||
|
CREATE_SEPARATE_WOW_VDM | DEBUG_ONLY_THIS_PROCESS,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
&StartupInfo,
|
||
|
&g_ProcessInformation);
|
||
|
|
||
|
if (!bRet) {
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
if (g_ProcessInformation.hProcess != NULL) {
|
||
|
|
||
|
InitVerifierLogSupport(pszAppName, g_ProcessInformation.dwProcessId);
|
||
|
|
||
|
//
|
||
|
// 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;
|
||
|
|
||
|
CloseHandle(g_ProcessInformation.hProcess);
|
||
|
CloseHandle(g_ProcessInformation.hThread);
|
||
|
|
||
|
ZeroMemory(&g_ProcessInformation, sizeof(PROCESS_INFORMATION));
|
||
|
}
|
||
|
|
||
|
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) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
pDll->pszName = (LPTSTR)HeapAlloc(GetProcessHeap(), 0, (lstrlen(pszDllName) + 1) * sizeof(TCHAR));
|
||
|
|
||
|
if (pDll->pszName == NULL) {
|
||
|
HeapFree(GetProcessHeap(), 0, pDll);
|
||
|
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) {
|
||
|
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) {
|
||
|
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.
|
||
|
//
|
||
|
DPF("[DebuggerLoop] Hit initial breakpoint.");
|
||
|
|
||
|
//
|
||
|
// Now it would be a good time to initialize the debugger extensions.
|
||
|
//
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
DPF("[DebuggerLoop] Hit breakpoint.");
|
||
|
|
||
|
VLog("Hard coded Breakpoint");
|
||
|
|
||
|
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:
|
||
|
DPF("[DebuggerLoop] Hit single step breakpoint.");
|
||
|
break;
|
||
|
|
||
|
case EXCEPTION_ACCESS_VIOLATION:
|
||
|
DPF("[DebuggerLoop] AV. Addr: 0x%08X, firstChance %d",
|
||
|
DebugEv.u.Exception.ExceptionRecord.ExceptionAddress,
|
||
|
DebugEv.u.Exception.dwFirstChance);
|
||
|
|
||
|
if (DebugEv.u.Exception.dwFirstChance == 0) {
|
||
|
VLog("Access Violation");
|
||
|
|
||
|
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:
|
||
|
DPF("[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;
|
||
|
|
||
|
DPF("[DebuggerLoop] new thread. StartAddress: 0x%x",
|
||
|
DebugEv.u.CreateThread.lpStartAddress);
|
||
|
break;
|
||
|
|
||
|
case EXIT_THREAD_DEBUG_EVENT:
|
||
|
DPF("[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);
|
||
|
|
||
|
DPF("[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) {
|
||
|
DPF("[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);
|
||
|
|
||
|
DPF("[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) {
|
||
|
DPF("[DebuggerLoop] DLL UNLOADED. BaseDll: 0x%X unknown.",
|
||
|
DebugEv.u.UnloadDll.lpBaseOfDll);
|
||
|
} else {
|
||
|
DPF("[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
|
||
|
DPF("DPF - %s", g_szDbgString);
|
||
|
#else
|
||
|
DPF("DPF - %S", g_szDbgString);
|
||
|
#endif // UNICODE
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
DPF("[DebuggerLoop] Unknown event 0x%X",
|
||
|
DebugEv.dwDebugEventCode);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Resume executing the thread that reported the debugging event.
|
||
|
//
|
||
|
ContinueDebugEvent(DebugEv.dwProcessId,
|
||
|
DebugEv.dwThreadId,
|
||
|
dwContinueStatus);
|
||
|
}
|
||
|
|
||
|
EndProcess:
|
||
|
DPF("[DebuggerLoop] The debugged process has exited.");
|
||
|
}
|
||
|
|
||
|
|