|
|
/*++
* Main module of DBG DLL. * * Copyright (c) 1997, Microsoft Corporation * * This code runs in the debuggee's process. * --*/ #include <precomp.h>
#pragma hdrstop
BOOL InVdmDebugger = FALSE; BOOL bWantsNtsdPrompt = FALSE;
ULONG ulTHHOOK = 0L; // Address registered from 16-bit world
LPVOID lpRemoteAddress = NULL; // Address registered from WOW32
DWORD lpRemoteBlock = 0; // Address registered from WOW32
BOOL f386; DWORD VdmDbgEFLAGS;
WORD DbgWowhExeHead = 0; WORD DbgWowhGlobalHeap = 0; PDWORD lpVdmState = NULL; PBYTE lpNtCpuInfo = NULL;
UCHAR DbgTimerMode = VDMTI_TIMER_TICK; BOOL DbgTimerInitialized = FALSE; VOID VdmDbgAttach(VOID);
BOOLEAN DbgDllInitialize( IN PVOID DllHandle, IN ULONG Reason, IN PCONTEXT Context OPTIONAL ) /*
* DBGDllInitialize - DBG Initialiazation routine. * */
{ HANDLE MyDebugPort; DWORD st; BOOL fAlreadyDebugged;
UNREFERENCED_PARAMETER(Context);
switch ( Reason ) {
case DLL_PROCESS_ATTACH:
#ifdef i386
// X86 Only, get pointer to Register Context Block
px86 = getIntelRegistersPointer(); #endif
st = NtQueryInformationProcess( NtCurrentProcess(), ProcessDebugPort, (PVOID)&MyDebugPort, sizeof(MyDebugPort), NULL ); if ( NT_SUCCESS(st) ) { fDebugged = (MyDebugPort != NULL); } else { fDebugged = FALSE; }
if (fDebugged) { DbgAttach(); } break;
case DLL_THREAD_ATTACH: //
// See if the debugger is attaching. If it is, then turn on the
// default of breaking into the debugger.
//
fAlreadyDebugged = fDebugged;
st = NtQueryInformationProcess( NtCurrentProcess(), ProcessDebugPort, (PVOID)&MyDebugPort, sizeof(MyDebugPort), NULL ); if ( NT_SUCCESS(st) ) { fDebugged = (MyDebugPort != NULL); } else { fDebugged = FALSE; }
if (fDebugged && !fAlreadyDebugged) { DbgAttach(); } break;
case DLL_THREAD_DETACH: break;
case DLL_PROCESS_DETACH: break;
default: break; } return( TRUE ); }
void DbgAttach( void ) /*
* DbgAttach * * Called to initiate the communication with a debugger * */ { //
// Send DBG_ATTACH notification
//
DbgGetContext(); SendVDMEvent(DBG_ATTACH);
//
// This call tells ntvdm to resync with us
//
VdmDbgAttach(); }
BOOL WINAPI xxxDbgInit( PVOID pState, ULONG InitialVdmDbgFlags, PVOID pCpuInfo ) /*
* DbgInit * * Called once ntvdm has completed it's initialization. Now it * is possible to compute for example the IntelMemoryBase. * */ {
VdmDbgTraceFlags = InitialVdmDbgFlags; lpVdmState = pState; IntelMemoryBase = (ULONG)VdmMapFlat(0, 0, VDM_V86); lpNtCpuInfo = pCpuInfo;
//
// turn on default debugging bits in ntvdmstate
//
*lpVdmState |= VDM_BREAK_DEBUGGER; #if DBG
*lpVdmState |= VDM_TRACE_HISTORY; #endif
if (fDebugged) { DbgGetContext(); SendVDMEvent(DBG_INIT); } return TRUE; }
BOOL WINAPI xxxDbgIsDebuggee( void ) /*
* DbgIsDebuggee * * Determines if we are being debugged * * Entry: void * * Exit: BOOL bRet - TRUE we are being debugged * */ { return fDebugged; }
BOOL SendVDMEvent( WORD wEventType )
/* SendVDMEvent
* * Sends a VDM event notification to the debugger * * Entry: * * Exit: BOOL bRet * Returns TRUE if exception was handled, FALSE otherwise * */ { BOOL fResult;
EventParams[0] = MAKELONG( wEventType, EventFlags ); EventParams[3] = (DWORD)&viInfo;
InVdmDebugger = TRUE;
do {
bWantsNtsdPrompt = FALSE;
// Slimyness to determine whether the exception was handled or not.
try { RaiseException( STATUS_VDM_EVENT, 0, 4, EventParams ); fResult = TRUE; } except(EXCEPTION_EXECUTE_HANDLER) { fResult = FALSE; }
//
// bWantsNtsdPrompt may be changed by vdmexts
//
if (bWantsNtsdPrompt) { DbgBreakPoint(); }
} while (bWantsNtsdPrompt);
InVdmDebugger = FALSE; FlushVdmBreakPoints();
return( fResult ); }
VOID DbgGetContext( VOID )
/* DbgGetContext() - Get the VDM's current context
* * Most of the routines that send VDMEvents need to have a context record * associated with them. This routine is a quick way to get most of the * general registers. Redundant work is being done because AX for example * is often on the stack and as such must really be pulled from the frame. * Hopefully this is OK because it is fast. */
{ //
// Everything defaults to 0.
//
RtlFillMemory( &vcContext, sizeof(VDMCONTEXT), (UCHAR)0 ); RtlFillMemory( &viInfo, sizeof(VDMINTERNALINFO), (UCHAR)0 );
//
// Fill in the internal info structure
//
viInfo.dwLdtBase = (DWORD)ExpLdt; viInfo.dwIntelBase = IntelMemoryBase; viInfo.wKernelSeg = HIWORD(ulTHHOOK); viInfo.dwOffsetTHHOOK = (DWORD)(LOWORD(ulTHHOOK)); viInfo.vdmContext = &vcContext; viInfo.lpRemoteAddress = lpRemoteAddress; viInfo.lpRemoteBlock = lpRemoteBlock; viInfo.f386 = f386; viInfo.lpNtvdmState = lpVdmState; viInfo.lpVdmDbgFlags = &VdmDbgTraceFlags; viInfo.lpNtCpuInfo = lpNtCpuInfo; viInfo.lpVdmBreakPoints= &VdmBreakPoints; EventFlags = 0; if(NtCurrentTeb()->Vdm) { //
// Fill in the context structure
//
vcContext.SegEs = (ULONG)getES(); vcContext.SegDs = (ULONG)getDS(); vcContext.SegCs = (ULONG)getCS(); vcContext.SegSs = (ULONG)getSS(); vcContext.SegFs = (ULONG)getFS(); vcContext.SegGs = (ULONG)getGS(); vcContext.EFlags = getEFLAGS(); VdmDbgEFLAGS = vcContext.EFlags; // save for vdmexts
vcContext.Edi = getEDI(); vcContext.Esi = getESI(); vcContext.Ebx = getEBX(); vcContext.Edx = getEDX(); vcContext.Ecx = getECX(); vcContext.Eax = getEAX(); vcContext.Ebp = getEBP(); vcContext.Eip = getEIP(); vcContext.Esp = getESP(); //
// Put in special flags in event field
//
if (!(getMSW() & MSW_PE) || (getEFLAGS() & V86FLAGS_V86)) { EventFlags |= VDMEVENT_V86; // emulator is in real or v86 mode
} else { EventFlags |= VDMEVENT_PE; if ((getMSW() & MSW_PE) && !SEGMENT_IS_BIG(vcContext.SegCs)) { EventFlags |= VDMEVENT_PM16; // emulator is in real or v86 mode
} } } }
void WINAPI xxxDbgDispatch() { UNALIGNED WORD *stack; WORD mode; WORD selector; WORD segment; WORD new_selector; BOOL fBPRelease; BOOL fData; LPSTR lpModuleName; LPSTR lpPathName; UCHAR fPE; PFFRAME16 pFFrame; PTFRAME16 pTFrame; PNDFRAME16 pNDFrame; PSTFRAME16 pSTFrame; WORD wFrame;
fPE = ISPESET;
stack = (UNALIGNED WORD *)Sim32GetVDMPointer( ((ULONG)getSS() << 16) + (ULONG)getSP(), MAX_DBG_FRAME, fPE );
mode = *stack++;
//
// If there is no debugger, then only handle DBG_WOWINIT
//
if (!fDebugged && (mode != DBG_WOWINIT)) { return; }
switch( mode ) { case DBG_SEGLOAD: selector = *stack++; segment = *stack++; lpModuleName = (LPSTR)Sim32GetVDMPointer( (ULONG)*stack + ((ULONG)(*(stack+1)) << 16), 0, fPE ); stack += 2; lpPathName = (LPSTR)Sim32GetVDMPointer( (ULONG)*stack + ((ULONG)(*(stack+1)) << 16), 0, fPE ); if ( lpPathName == NULL ) { lpPathName = ""; }
stack += 2; fData = (BOOL)(*stack++); SegmentLoad( lpModuleName, lpPathName, selector, segment, fData ); break;
case DBG_SEGMOVE: selector = *stack++; new_selector = *stack++; SegmentMove( selector, new_selector ); break;
case DBG_SEGFREE: fBPRelease = (BOOL)*stack++; selector = *stack++; SegmentFree( selector, fBPRelease ); break;
case DBG_MODFREE: lpModuleName = (LPSTR)Sim32GetVDMPointer( (ULONG)*stack + ((ULONG)(*(stack+1)) << 16), 0, fPE ); stack += 2; lpPathName = (LPSTR)Sim32GetVDMPointer( (ULONG)*stack + ((ULONG)(*(stack+1)) << 16), 0, fPE ); if ( lpPathName == NULL ) { lpPathName = ""; } ModuleFree( lpModuleName, lpPathName ); break;
case DBG_GPFAULT2: wFrame = getBP() - (WORD)(FIELD_OFFSET(FFRAME16,wBP));
pFFrame = (PFFRAME16)Sim32GetVDMPointer( ((ULONG)getSS() << 16) + (ULONG)wFrame, MAX_DBG_FRAME, fPE );
fData = DbgGPFault2( pFFrame );
setAX((WORD)fData); break;
case DBG_DIVOVERFLOW: pTFrame = (PTFRAME16)Sim32GetVDMPointer( (ULONG)((ULONG)getSS() << 16) + (ULONG)getSP(), MAX_DBG_FRAME, fPE );
fData = DbgDivOverflow2( pTFrame );
setAX((WORD)fData); break;
case DBG_DLLSTART: pNDFrame = (PNDFRAME16)Sim32GetVDMPointer( (ULONG)((ULONG)getSS() << 16) + (ULONG)getSP(), MAX_DBG_FRAME, fPE );
fData = DbgDllStart( pNDFrame );
setAX((WORD)fData); break;
case DBG_TASKSTOP: pSTFrame = (PSTFRAME16)Sim32GetVDMPointer( (ULONG)((ULONG)getSS() << 16) + (ULONG)getSP(), MAX_DBG_FRAME, fPE );
fData = DbgTaskStop( pSTFrame ); break;
case DBG_ATTACH: break;
case DBG_TOOLHELP: ulTHHOOK = (ULONG)*stack + ((ULONG)(*(stack+1)) << 16); stack += 2; f386 = (BOOL)*stack; break;
case DBG_WOWINIT: //
// Pass in some data from KRNL386 so that VDMEXTS can get a
// hold of them.
//
DbgWowhExeHead = getDX(); DbgWowhGlobalHeap = getCX(); break;
default: setAX(0); // Event not handled
break; } }
VOID xxxDbgNotifyRemoteThreadAddress( LPVOID lpAddress, DWORD lpBlock ) { lpRemoteAddress = lpAddress; lpRemoteBlock = lpBlock; }
VOID xxxDbgNotifyDebugged( BOOL fNewDebugged ) { fDebugged = fNewDebugged; }
VOID RestoreVDMContext( VDMCONTEXT *vcContext ) {
setEAX(vcContext->Eax); setEBX(vcContext->Ebx); setECX(vcContext->Ecx); setEDX(vcContext->Edx); setEIP(vcContext->Eip); setESP(vcContext->Esp); setEBP(vcContext->Ebp); setEFLAGS(vcContext->EFlags);
}
ULONG DbgEventTime( PVDM_TRACEINFO pVdmTraceInfo ) { ULONG TickCount = 0; USHORT id; ULONG CurTick; LARGE_INTEGER CurTime; LARGE_INTEGER DiffTime; #ifdef _X86_
ULONG CurHigh, CurLow; #endif
if (!DbgTimerInitialized) {
#ifdef _X86_
ULONG CpuidHigh; _asm pushad _asm mov eax, 1 _asm _emit 0fh _asm _emit 0a2h // CPUID
_asm mov CpuidHigh, edx _asm popad if (CpuidHigh & 0x10) { // cpu has time stamp counter
DbgTimerMode = VDMTI_TIMER_PENTIUM; } #endif
switch(DbgTimerMode & VDMTI_TIMER_MODE) {
case VDMTI_TIMER_TICK: pVdmTraceInfo->TimeStamp.LowPart = GetTickCount(); DbgTimerInitialized = TRUE; break;
#ifdef _X86_
case VDMTI_TIMER_PENTIUM: _asm push eax _asm push edx _asm _emit 0fh _asm _emit 031h // RDTSC
_asm mov CurLow, eax _asm mov CurHigh, edx _asm pop edx _asm pop eax
pVdmTraceInfo->TimeStamp.LowPart = CurLow; pVdmTraceInfo->TimeStamp.HighPart = CurHigh; DbgTimerInitialized = TRUE; break; #endif
} }
if (DbgTimerInitialized) {
pVdmTraceInfo->Flags = (pVdmTraceInfo->Flags & ~VDMTI_TIMER_MODE) + (DbgTimerMode & VDMTI_TIMER_MODE);
switch(pVdmTraceInfo->Flags & VDMTI_TIMER_MODE) {
case VDMTI_TIMER_TICK: CurTick = GetTickCount();
if (CurTick > pVdmTraceInfo->TimeStamp.LowPart) { TickCount = CurTick - pVdmTraceInfo->TimeStamp.LowPart; pVdmTraceInfo->TimeStamp.LowPart = CurTick; } else { TickCount = 0; }
break;
#ifdef _X86_
case VDMTI_TIMER_PENTIUM: { _asm push eax _asm push edx _asm _emit 0fh _asm _emit 031h // RDTSC
_asm mov CurLow, eax _asm mov CurHigh, edx _asm pop edx _asm pop eax CurTime.LowPart = CurLow; CurTime.HighPart = CurHigh;
DiffTime.QuadPart = CurTime.QuadPart - pVdmTraceInfo->TimeStamp.QuadPart; pVdmTraceInfo->TimeStamp.QuadPart = CurTime.QuadPart; TickCount = DiffTime.LowPart;
//if (DiffTime.HighPart) {
// TickCount = 0xffffffff;
//}
break; } #endif
} }
return (TickCount); }
#define NUM_VDM_TRACE_PAGES 8
VOID WINAPI xxxDbgTraceEvent( PVDM_TRACEINFO pVdmTraceInfo, USHORT Type, USHORT wData, ULONG lData ) { PVDM_TRACEENTRY pEntry;
if (!(*(ULONG *)(IntelMemoryBase+FIXED_NTVDMSTATE_LINEAR) & VDM_TRACE_HISTORY)) { return; }
if (!pVdmTraceInfo->pTraceTable) { pVdmTraceInfo->pTraceTable = (PVDM_TRACEENTRY) VirtualAlloc(NULL, 4096*NUM_VDM_TRACE_PAGES, MEM_COMMIT, PAGE_READWRITE);
if (!pVdmTraceInfo->pTraceTable) { // couldn't allocate memory
return; }
pVdmTraceInfo->CurrentEntry = 0; pVdmTraceInfo->NumPages = NUM_VDM_TRACE_PAGES; pVdmTraceInfo->Flags = 0; }
pEntry = &pVdmTraceInfo->pTraceTable[pVdmTraceInfo->CurrentEntry];
pEntry->Type = Type; pEntry->wData = wData; pEntry->lData = lData; pEntry->Time = DbgEventTime(pVdmTraceInfo);
pEntry->eax = getEAX(); pEntry->ebx = getEBX(); pEntry->ecx = getECX(); pEntry->edx = getEDX(); pEntry->esi = getESI(); pEntry->edi = getEDI(); pEntry->ebp = getEBP(); pEntry->esp = getESP(); pEntry->eip = getEIP(); pEntry->eflags = getEFLAGS();
pEntry->cs = getCS(); pEntry->ds = getDS(); pEntry->es = getES(); pEntry->fs = getFS(); pEntry->gs = getGS(); pEntry->ss = getSS();
if (++pVdmTraceInfo->CurrentEntry >= (pVdmTraceInfo->NumPages*4096/sizeof(VDM_TRACEENTRY))) { pVdmTraceInfo->CurrentEntry = 0; }
}
|