Windows-Server-2003/sdktools/dbwin32/dbdbg32.cpp

473 lines
15 KiB
C++

#include <windows.h>
#include <malloc.h>
#include <stddef.h>
#include <process.h>
#define _DBDBG32_
#include "dbwin32.h"
ProcessList::ProcessList() : GrowableList(sizeof(ProcessInfo))
{
}
ProcessList::~ProcessList()
{
}
BOOL ProcessList::IsEqual(void *pv1, void *pv2)
{
return(!memcmp(pv1, pv2, sizeof(DWORD)));
}
ThreadList::ThreadList() : GrowableList(sizeof(ThreadInfo))
{
}
ThreadList::~ThreadList()
{
}
BOOL ThreadList::IsEqual(void *pv1, void *pv2)
{
return(!memcmp(pv1, pv2, sizeof(ThreadInfo)));
}
DllList::DllList() : GrowableList(sizeof(DllInfo))
{
}
DllList::~DllList()
{
}
BOOL DllList::IsEqual(void *pv1, void *pv2)
{
return(!memcmp(pv1, pv2, (sizeof(DWORD) + sizeof(LPVOID))));
}
void __cdecl AttachThread(void *pv)
{
AttachInfo *pai = (AttachInfo *)pv;
if (DebugActiveProcess(pai->dwProcess))
DebugThread(pai->hwndFrame, pai->dwProcess);
else
{
MessageBeep(MB_ICONEXCLAMATION);
MessageBox(pai->hwndFrame, "Unable to attach to process.", "DbWin32",
MB_ICONEXCLAMATION | MB_OK);
}
delete pai;
}
void __cdecl ExecThread(void *pv)
{
ExecInfo *pei = (ExecInfo *)pv;
STARTUPINFO si;
PROCESS_INFORMATION pi;
memset(&si, 0, sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
si.wShowWindow = SW_SHOWDEFAULT;
pi.hProcess = NULL;
if (CreateProcess(NULL, pei->lpszCommandLine, NULL, NULL, TRUE,
DEBUG_PROCESS | CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi))
{
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
DebugThread(pei->hwndFrame, pi.dwProcessId);
}
else
{
MessageBeep(MB_ICONEXCLAMATION);
MessageBox(pei->hwndFrame, "Unable to execute process.", "DbWin32",
MB_ICONEXCLAMATION | MB_OK);
}
free((void *)(pei->lpszCommandLine));
delete pei;
}
void __cdecl SystemThread(void *pv)
{
BOOL fFailed = TRUE;
DWORD dwRet;
HANDLE hevtBuffer = NULL, hevtData = NULL;
HANDLE hfileShared = NULL;
HWND hwndFrame = (HWND)pv;
LPVOID lpvBuffer = NULL;
LPSTR lpszText = NULL;
DEBUG_EVENT DebugEvent;
hevtBuffer = CreateEvent(NULL, FALSE, FALSE, "DBWIN_BUFFER_READY");
if (hevtBuffer)
hevtData = CreateEvent(NULL, FALSE, FALSE, "DBWIN_DATA_READY");
if (hevtBuffer && hevtData)
hfileShared = CreateFileMapping((HANDLE)-1, NULL, PAGE_READWRITE, 0,
4096, "DBWIN_BUFFER");
if (hevtBuffer && hevtData && hfileShared)
lpvBuffer = MapViewOfFile(hfileShared, FILE_MAP_READ, 0, 0, 512);
if (hevtBuffer && hevtData && hfileShared && lpvBuffer)
{
fFailed = FALSE;
lpszText = (LPSTR)lpvBuffer + sizeof(DWORD);
DebugEvent.dwDebugEventCode = OUTPUT_DEBUG_STRING_EVENT;
DebugEvent.dwProcessId = DebugEvent.dwThreadId = 0;
SetEvent(hevtBuffer);
}
else
{
MessageBeep(MB_ICONEXCLAMATION);
MessageBox(hwndFrame, "Unable to open System Window.", "DbWin32",
MB_ICONEXCLAMATION | MB_OK);
}
while (!fFailed)
{
dwRet = WaitForSingleObject(hevtData, INFINITE);
if (dwRet != WAIT_OBJECT_0)
{
SendText(hwndFrame, &DebugEvent, 0,
"-------- DbWin32 ERROR! --------\r\n",
DBO_OUTPUTDEBUGSTRING);
SendText(hwndFrame, &DebugEvent, 0,
"-------- Shutting down System Window --------\r\n",
DBO_OUTPUTDEBUGSTRING);
fFailed = TRUE;
}
else
{
SendText(hwndFrame, &DebugEvent, 0, lpszText,
DBO_OUTPUTDEBUGSTRING);
SetEvent(hevtBuffer);
}
}
if (hfileShared)
CloseHandle(hfileShared);
if (hevtData)
CloseHandle(hevtData);
if (hevtBuffer)
CloseHandle(hevtBuffer);
}
void __cdecl DebugThread(HWND hwndFrame, DWORD dwProcess)
{
char DisplayBuffer[BUF_SIZE];
WORD wEvent;
DWORD dwContinue;
SIZE_T dwRead;
ProcessList pl;
ProcessInfo pi;
ThreadList tl;
ThreadInfo ti;
DllList dl;
DllInfo di;
int iItem;
BOOL fDone = FALSE;
DEBUG_EVENT DebugEvent;
EXCEPTION_DEBUG_INFO *pException = &DebugEvent.u.Exception;
CREATE_THREAD_DEBUG_INFO *pCreateThread = &DebugEvent.u.CreateThread;
CREATE_PROCESS_DEBUG_INFO *pCreateProcessInfo = &DebugEvent.u.CreateProcessInfo;
EXIT_THREAD_DEBUG_INFO *pExitThread = &DebugEvent.u.ExitThread;
EXIT_PROCESS_DEBUG_INFO *pExitProcess = &DebugEvent.u.ExitProcess;
LOAD_DLL_DEBUG_INFO *pLoadDll = &DebugEvent.u.LoadDll;
UNLOAD_DLL_DEBUG_INFO *pUnloadDll = &DebugEvent.u.UnloadDll;
OUTPUT_DEBUG_STRING_INFO *pDebugString = &DebugEvent.u.DebugString;
RIP_INFO *pRipInfo = &DebugEvent.u.RipInfo;
while (!fDone && WaitForDebugEvent(&DebugEvent, INFINITE))
{
*DisplayBuffer = '\0';
dwContinue = DBG_CONTINUE;
switch (DebugEvent.dwDebugEventCode)
{
case EXCEPTION_DEBUG_EVENT:
ProcessExceptionEvent(pException, DisplayBuffer);
if (pException->ExceptionRecord.ExceptionCode !=
EXCEPTION_BREAKPOINT)
{
dwContinue = DBG_EXCEPTION_NOT_HANDLED;
}
wEvent = DBO_EXCEPTIONS;
break;
case CREATE_THREAD_DEBUG_EVENT:
ti.dwProcess = DebugEvent.dwProcessId;
ti.dwThread = DebugEvent.dwThreadId;
tl.InsertItem(&ti);
wsprintf(DisplayBuffer, "Create Thread: PID 0x%X - TID 0x%X\r\n",
ti.dwProcess, ti.dwThread);
wEvent = DBO_THREADCREATE;
break;
case CREATE_PROCESS_DEBUG_EVENT:
ti.dwProcess = pi.dwProcess = DebugEvent.dwProcessId;
ti.dwThread = DebugEvent.dwThreadId;
tl.InsertItem(&ti);
pi.hProcess = pCreateProcessInfo->hProcess;
GetModuleName(pCreateProcessInfo->hFile, pi.hProcess,
(DWORD_PTR)pCreateProcessInfo->lpBaseOfImage, pi.rgchModule);
pl.InsertItem(&pi);
wsprintf(DisplayBuffer, "Create Process: PID 0x%X - %s\r\n",
pi.dwProcess, pi.rgchModule);
wEvent = DBO_PROCESSCREATE;
break;
case EXIT_THREAD_DEBUG_EVENT:
ti.dwProcess = DebugEvent.dwProcessId;
ti.dwThread = DebugEvent.dwThreadId;
tl.RemoveItem(&ti);
wsprintf(DisplayBuffer, "Exit Thread: PID 0x%X - TID 0x%X - dwReturnCode %d\r\n",
ti.dwProcess, ti.dwThread, pExitThread->dwExitCode);
wEvent = DBO_THREADEXIT;
break;
case EXIT_PROCESS_DEBUG_EVENT:
pi.dwProcess = DebugEvent.dwProcessId;
if (pl.FindItem(&pi, &iItem))
{
pl.RemoveItem(iItem);
}
wsprintf(DisplayBuffer, "Exit Process: PID 0x%X - %s - dwReturnCode %d\r\n",
pi.dwProcess, pi.rgchModule, pExitProcess->dwExitCode);
if (pi.dwProcess == dwProcess)
{
fDone = TRUE;
}
wEvent = DBO_PROCESSEXIT;
break;
case LOAD_DLL_DEBUG_EVENT:
di.dwProcess = pi.dwProcess = DebugEvent.dwProcessId;
if (pl.FindItem(&pi))
{
di.lpBaseOfDll = pLoadDll->lpBaseOfDll;
GetModuleName(pLoadDll->hFile, pi.hProcess, (DWORD_PTR)di.lpBaseOfDll,
di.rgchModule);
dl.InsertItem(&di);
wsprintf(DisplayBuffer, "DLL Load: %s\r\n", di.rgchModule);
wEvent = DBO_DLLLOAD;
}
break;
case UNLOAD_DLL_DEBUG_EVENT:
di.dwProcess = DebugEvent.dwProcessId;
di.lpBaseOfDll = pUnloadDll->lpBaseOfDll;
if (dl.FindItem(&di, &iItem))
{
dl.RemoveItem(iItem);
}
wsprintf(DisplayBuffer, "Dll Unload: %s\r\n", di.rgchModule);
wEvent = DBO_DLLUNLOAD;
break;
case OUTPUT_DEBUG_STRING_EVENT:
pi.dwProcess = DebugEvent.dwProcessId;
if (!pl.FindItem(&pi) ||
(!ReadProcessMemory(pi.hProcess,
pDebugString->lpDebugStringData, DisplayBuffer,
pDebugString->nDebugStringLength, &dwRead)))
{
dwRead = 0;
}
DisplayBuffer[dwRead] = '\0';
wEvent = DBO_OUTPUTDEBUGSTRING;
break;
case RIP_EVENT:
wsprintf(DisplayBuffer, "RIP: dwError %d - dwType %d\r\n",
pRipInfo->dwError, pRipInfo->dwType);
wEvent = DBO_RIP;
break;
// No events should reach here.
default:
wsprintf(DisplayBuffer, "Unknown Event: 0x%X\r\n",
DebugEvent.dwDebugEventCode);
wEvent = DBO_ALL;
break;
}
if (*DisplayBuffer)
SendText(hwndFrame, &DebugEvent, dwProcess, DisplayBuffer, wEvent);
if (DebugEvent.dwDebugEventCode == EXIT_THREAD_DEBUG_EVENT)
PostMessage(hwndFrame, WM_ENDTHREAD, (WPARAM)ti.dwThread,
ti.dwProcess);
if (DebugEvent.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT)
{
if (fDone)
{
for (iItem = tl.Count(); iItem > 0; iItem--)
{
tl.GetItem(iItem - 1, &ti);
PostMessage(hwndFrame, WM_ENDTHREAD, (WPARAM)ti.dwThread, ti.dwProcess);
}
for (iItem = pl.Count(); iItem > 0; iItem--)
{
pl.GetItem(iItem - 1, &pi);
PostMessage(hwndFrame, WM_ENDTHREAD, 0, pi.dwProcess);
}
}
PostMessage(hwndFrame, WM_ENDTHREAD, 0, DebugEvent.dwProcessId);
}
ContinueDebugEvent(DebugEvent.dwProcessId, DebugEvent.dwThreadId, dwContinue);
}
}
void SendText(HWND hwndFrame, DEBUG_EVENT *pDebugEvent, DWORD dwParentProcess,
LPCSTR lpszText, WORD wEvent)
{
char rgchText[BUF_SIZE], *pch = rgchText;
StringInfo *psi;
psi = new StringInfo;
// Niceify the text
if (pDebugEvent->dwDebugEventCode == OUTPUT_DEBUG_STRING_EVENT)
{
psi->cLines = 0;
while (*lpszText != '\0')
{
if ((*lpszText == 0x0d) || (*lpszText == 0x0a))
{
*pch++ = 0x0d;
*pch++ = 0x0a;
while ((*lpszText == 0x0d) || (*lpszText == 0x0a))
lpszText++;
psi->cLines++;
}
else
{
*pch++ = *lpszText++;
}
}
*pch = '\0';
psi->lpszText = _strdup(rgchText);
}
else
{
psi->cLines = 1;
psi->lpszText = _strdup(lpszText);
}
psi->dwProcess = pDebugEvent->dwProcessId;
psi->dwThread = pDebugEvent->dwThreadId;
psi->dwParentProcess = dwParentProcess;
PostMessage(hwndFrame, WM_SENDTEXT, wEvent, (LPARAM)psi);
}
void ProcessExceptionEvent(EXCEPTION_DEBUG_INFO *pException, LPSTR lpszBuf)
{
if (pException->dwFirstChance)
strcpy(lpszBuf, "First");
else
strcpy(lpszBuf, "Second");
strcat(lpszBuf, " chance exception: ");
switch (pException->ExceptionRecord.ExceptionCode)
{
//--standard exceptions
case EXCEPTION_ACCESS_VIOLATION:
strcat(lpszBuf, "Access Violation");
break;
case EXCEPTION_DATATYPE_MISALIGNMENT:
strcat(lpszBuf, "Datatype Misalignment");
break;
case EXCEPTION_BREAKPOINT:
strcat(lpszBuf, "Breakpoint");
break;
case EXCEPTION_SINGLE_STEP:
strcat(lpszBuf, "Single Step");
break;
case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
strcat(lpszBuf, "Array Bound Exceeded");
break;
case EXCEPTION_FLT_DENORMAL_OPERAND:
strcat(lpszBuf, "FP-Denormal Operand");
break;
case EXCEPTION_FLT_DIVIDE_BY_ZERO:
strcat(lpszBuf, "FP-Divide By Zero");
break;
case EXCEPTION_FLT_INEXACT_RESULT:
strcat(lpszBuf, "FP-Inexact Result");
break;
case EXCEPTION_FLT_INVALID_OPERATION:
strcat(lpszBuf, "FP-Invalid Operation");
break;
case EXCEPTION_FLT_OVERFLOW:
strcat(lpszBuf, "FP-Overflow");
break;
case EXCEPTION_FLT_STACK_CHECK:
strcat(lpszBuf, "FP-Stack Check");
break;
case EXCEPTION_FLT_UNDERFLOW:
strcat(lpszBuf, "FP-Underflow");
break;
case EXCEPTION_INT_DIVIDE_BY_ZERO:
strcat(lpszBuf, "INT-Divide By Zero");
break;
case EXCEPTION_INT_OVERFLOW:
strcat(lpszBuf, "INT-Overflow");
break;
case EXCEPTION_PRIV_INSTRUCTION:
strcat(lpszBuf, "Privileged Instruction");
break;
case EXCEPTION_IN_PAGE_ERROR:
strcat(lpszBuf, "In Page Error");
break;
//-- Debug exceptions
case DBG_TERMINATE_THREAD:
strcat(lpszBuf, "DBG-Terminate Thread");
break;
case DBG_TERMINATE_PROCESS:
strcat(lpszBuf, "DBG-Terminate Process");
break;
case DBG_CONTROL_C:
strcat(lpszBuf, "DBG-Control+C");
break;
case DBG_CONTROL_BREAK:
strcat(lpszBuf, "DBG-Control+Break");
break;
//-- RPC exceptions (some)
case RPC_S_UNKNOWN_IF:
strcat(lpszBuf, "RPC-Unknown Interface");
break;
case RPC_S_SERVER_UNAVAILABLE:
strcat(lpszBuf, "RPC-Server Unavailable");
break;
//-- VDM exceptions (minimal information)
case EXCEPTION_VDM_EVENT: // see dbwin32.h for definition
strcat(lpszBuf, "VDM");
break;
default:
char rgchTmp[25];
wsprintf(rgchTmp, "Unknown-[0x%X]", pException->ExceptionRecord.ExceptionCode);
strcat(lpszBuf, rgchTmp);
break;
}
strcat(lpszBuf, "\r\n");
}
#define IMAGE_SECOND_HEADER_OFFSET (15 * sizeof(ULONG))
#define IMAGE_EXPORT_TABLE_RVA_OFFSET (30 * sizeof(DWORD))
#define IMAGE_NAME_RVA_OFFSET offsetof(IMAGE_EXPORT_DIRECTORY, Name)
void GetModuleName(HANDLE hFile, HANDLE hProcess, DWORD_PTR BaseOfImage, LPSTR lpszBuf)
{
DWORD dwRead = 0;
WORD DosSignature;
DWORD NtSignature, PeHeader, ExportTableRVA, NameRVA;
strcpy(lpszBuf, "<unknown>");
if (!hFile)
return;
if (GetFileType(hFile) != FILE_TYPE_DISK)
return;
SetFilePointer(hFile, 0L, NULL, FILE_BEGIN);
if (!ReadFile(hFile, &DosSignature, sizeof(DosSignature), &dwRead, NULL))
return;
if (DosSignature != IMAGE_DOS_SIGNATURE)
return;
SetFilePointer(hFile, IMAGE_SECOND_HEADER_OFFSET, NULL, FILE_BEGIN);
if (!ReadFile(hFile, &PeHeader, sizeof(PeHeader), &dwRead, NULL))
return;
SetFilePointer(hFile, PeHeader, NULL, FILE_BEGIN);
if (!ReadFile(hFile, &NtSignature, sizeof(NtSignature), &dwRead, NULL))
return;
if (NtSignature != IMAGE_NT_SIGNATURE)
return;
SetFilePointer(hFile, PeHeader + IMAGE_EXPORT_TABLE_RVA_OFFSET, NULL, FILE_BEGIN);
if (!ReadFile(hFile, &ExportTableRVA, sizeof(ExportTableRVA), &dwRead, NULL))
return;
if (!ExportTableRVA)
return;
ReadProcessMemory(hProcess, (LPVOID)(BaseOfImage + ExportTableRVA +
IMAGE_NAME_RVA_OFFSET), &NameRVA, sizeof(NameRVA), NULL);
ReadProcessMemory(hProcess, (LPVOID)(BaseOfImage + NameRVA), lpszBuf, MODULE_SIZE, NULL);
}