Windows2000/private/windbg64/debugger/dm/user/wow.c
2020-09-30 17:12:32 +02:00

1249 lines
30 KiB
C

/*++
Copyright (c) 1992 Microsoft Corporation
Module Name:
WOW.C
Abstract:
This file contains the code which is responsable for dealing with
the WOW debug structures and debug events.
Author:
James L Schaad (jimsch) 05-11-92
Environment:
User Mode WIN32
--*/
#include "precomp.h"
#pragma hdrstop
#if defined(i386) && !defined(WIN32S)
VDMPROCESSEXCEPTIONPROC pfnVDMProcessException;
VDMGETTHREADSELECTORENTRYPROC pfnVDMGetThreadSelectorEntry;
VDMGETPOINTERPROC pfnVDMGetPointer;
VDMGETCONTEXTPROC pfnVDMGetThreadContext;
VDMSETCONTEXTPROC pfnVDMSetThreadContext;
VDMGETSELECTORMODULEPROC pfnVDMGetSelectorModule;
VDMENUMPROCESSWOWPROC pfnVDMEnumProcessWOW;
#endif
/** GLOBAL VARIABLES **/
#if defined(i386) && !defined(WIN32S)
BOOL FVDMInitDone;
BOOL FVDMActive;
#endif
extern char abEMReplyBuf[];
extern DDVECTOR RgfnFuncEventDispatch[];
extern DDVECTOR DebugDispatchTable[];
extern char nameBuffer[];
/** Local Prototypes **/
int LookupDllName(HPRCX hprcx, char * sz);
int InsertDllName(HPRCX hprcx, char * sz);
void RemoveDllName(HPRCX hprcx, int idx);
static DEBUG_EVENT64 DeWow;
DEBUG_EVENT32 DeWow32;
/** FUNCTIONS **/
void
ProcessEntryPointEvent(
DEBUG_EVENT64 * pde,
HTHDX hthdx
)
/*++
Routine Description:
This handles task start events after the first one.
Arguments:
Return Value:
--*/
{
#if defined(i386) && !defined(WIN32S)
IMAGE_NOTE in;
LPBYTE lpb;
DWORD cbRead;
int b;
char szName0[_MAX_FNAME + _MAX_EXT];
char szName1[_MAX_FNAME + _MAX_EXT];
char szExt [_MAX_EXT];
lpb = (LPBYTE)pde->
u.Exception.ExceptionRecord.ExceptionInformation[2];
b = DbgReadMemory(hthdx->hprc,
(UINT_PTR)lpb,
&in,
sizeof(in),
&cbRead);
if ((b == 0) || (cbRead != sizeof(in))) {
b = GetLastError();
} else {
_splitpath(in.FileName, NULL, NULL, szName0, szExt);
_tcscat(szName0, szExt);
_splitpath(nameBuffer, NULL, NULL, szName1, szExt);
_tcscat(szName1, szExt);
if (_strcmpi(szName0, szName1) == 0) {
*nameBuffer = 0;
hthdx->hprc->pstate &= ~ps_preEntry;
hthdx->tstate |= ts_stopped;
NotifyEM(pde, hthdx, 0, ENTRY_BP);
return;
}
}
AddQueue( QT_CONTINUE_DEBUG_EVENT,
hthdx->hprc->pid,
hthdx->tid,
DBG_CONTINUE,
0);
hthdx->tstate &= ~(ts_stopped|ts_first|ts_second);
hthdx->tstate |= ts_running;
return;
#endif
}
void
ProcessSegmentLoadEvent(
DEBUG_EVENT64 * pde,
HTHDX hthdx
)
/*++
Routine Description:
This function takes care of dealing with segment load events from
the wow system. These come in as exceptions and are translated
to segment load events in ProcessDebugEvent.
Arguments:
pde - Supplies a pointer to the modified debug event
hthdx - Supplies the handle to the thread of the debug event
Return Value:
None.
--*/
{
#if defined(i386) && !defined(WIN32S)
PDWORDLONG lpdw = &pde->u.Exception.ExceptionRecord.ExceptionInformation[0];
int mode = LOWORD( (DWORD)lpdw[0] );
int cb;
int cbRead;
int b;
char * lpb;
WORD packetType = tlfDebugPacket;
HEMI hemi;
HPRCX hprcx = hthdx->hprc;
int idx;
SEGMENT_NOTE sn;
ADDR addr;
EXPECTED_EVENT * pee;
DWORD eventCode;
DWORD subClass;
LDT_ENTRY ldt;
BREAKPOINT *bp;
DeWow = *pde;
if ( !FVDMInitDone ) {
HANDLE hmodVDM;
hmodVDM = LoadLibrary("VDMDBG.DLL");
if ( hmodVDM != (HANDLE)NULL ) {
FVDMActive = TRUE;
pfnVDMProcessException = (VDMPROCESSEXCEPTIONPROC)
GetProcAddress( hmodVDM, "VDMProcessException" );
pfnVDMGetPointer = (VDMGETPOINTERPROC)
GetProcAddress( hmodVDM, "VDMGetPointer" );
pfnVDMGetThreadSelectorEntry = (VDMGETTHREADSELECTORENTRYPROC)
GetProcAddress( hmodVDM, "VDMGetThreadSelectorEntry" );
pfnVDMGetThreadContext = (VDMGETCONTEXTPROC)
GetProcAddress( hmodVDM, "VDMGetContext" );
pfnVDMSetThreadContext = (VDMSETCONTEXTPROC)
GetProcAddress( hmodVDM, "VDMSetContext" );
pfnVDMGetSelectorModule = (VDMGETSELECTORMODULEPROC)
GetProcAddress( hmodVDM, "VDMGetSelectorModule" );
pfnVDMEnumProcessWOW = (VDMENUMPROCESSWOWPROC)
GetProcAddress( hmodVDM, "VDMEnumProcessWOW" );
} else {
DMPrintShellMsg( _T("LoadLibrary(VDMDBG.DLL) failed\n"));
}
FVDMInitDone = TRUE;
}
if ( !FVDMActive ) {
return;
} else {
DebugEvent64To32(pde, &DeWow32);
(*pfnVDMProcessException)((LPDEBUG_EVENT)&DeWow32);
DebugEvent32To64(&DeWow32, pde);
}
hthdx->fWowEvent = TRUE;
switch ( mode ) {
/*
* SEG LOAD:
* LOWORD(lpdw[0]) DBG_SEGLOAD
* HIWORD(lpdw[0]) Unused
* LOWORD(lpdw[1]) Unused
* HIWORD(lpdw[1]) Unused
* lpdw[2] pointer to SEGMENT_NOTE structure
* lpdw[3] Reserved
*/
case DBG_SEGLOAD:
lpb = (char *) lpdw[2];
b = DbgReadMemory(hprcx, (UINT_PTR)lpb, &sn, sizeof(sn), &cbRead);
if ((b == 0) || (cbRead != sizeof(sn))) {
b = GetLastError();
AddQueue( QT_CONTINUE_DEBUG_EVENT,
hthdx->hprc->pid,
hthdx->tid,
DBG_CONTINUE,
0);
hthdx->tstate &= ~(ts_stopped|ts_first|ts_second);
hthdx->tstate |= ts_running;
return;
}
if (sn.FileName[0] == 0) {
AddQueue( QT_CONTINUE_DEBUG_EVENT,
hthdx->hprc->pid,
hthdx->tid,
DBG_CONTINUE,
0);
hthdx->tstate &= ~(ts_stopped|ts_first|ts_second);
hthdx->tstate |= ts_running;
return;
}
cb = _tcslen(sn.FileName)+1;
idx = LookupDllName(hprcx, sn.FileName);
if ( idx != -1 ) {
if (hprcx->rgDllList[idx].fReal) {
// Changing from real to protected mode. We don't
// support this, so we'll throw away what we have
// and start from scratch.
WORD w = (WORD)idx;
DMSendDebugPacket(dbceModFree16,
hprcx->hpid,
hthdx->htid,
sizeof(WORD),
&w
);
RemoveDllName( hprcx, idx );
idx = -1;
}
}
if (idx == -1) {
LPMODULELOAD lpmdl;
cb = cb + sizeof(MODULELOAD) + (sn.Segment+1)*sizeof(OBJD);
lpmdl = (LPMODULELOAD) MHAlloc(cb);
lpmdl->cobj = sn.Segment+1;
lpmdl->rgobjd[sn.Segment].wSel = sn.Selector1;
lpmdl->rgobjd[sn.Segment].cb = (DWORD) -1;
lpmdl->rgobjd[sn.Segment].wPad = 1;
lpmdl->mte = InsertDllName(hprcx, sn.FileName);
_tcscpy((char *) &lpmdl->rgobjd[lpmdl->cobj], sn.FileName);
lpmdl->fRealMode = FALSE;
lpmdl->fFlatMode = FALSE;
lpmdl->fOffset32 = FALSE;
DMSendRequestReply(dbcModLoad,
hprcx->hpid,
hthdx->htid,
cb,
lpmdl,
sizeof(HEMI),
&hemi
);
hemi = *((HEMI *) abEMReplyBuf);
MHFree(lpmdl);
AddQueue( QT_CONTINUE_DEBUG_EVENT,
hthdx->hprc->pid,
hthdx->tid,
DBG_CONTINUE,
0);
hthdx->tstate &= ~(ts_stopped|ts_first|ts_second);
hthdx->tstate |= ts_running;
} else {
SLI sli;
sli.wSelector = sn.Selector1;
sli.wSegNo = sn.Segment;
sli.mte = idx;
DMSendDebugPacket(dbceSegLoad,
hprcx->hpid,
hthdx->htid,
sizeof(SLI),
&sli
);
}
break;
/*
* SEGMOVE:
* This event will be triggered if a selector number
* is to be changed.
* LOWORD( lpdw[0] ) - SEGMOVE
* LOWORD( lpdw[1] ) - old selector number
* HIWORD( lpdw[1] ) - new selector number
*/
case DBG_SEGMOVE:
lpb = (char *) lpdw[2];
b = DbgReadMemory(hprcx, (UINT_PTR)lpb, &sn, sizeof(sn), &cbRead);
if ((b == 0) || (cbRead != sizeof(sn))) {
b = GetLastError();
AddQueue( QT_CONTINUE_DEBUG_EVENT,
hthdx->hprc->pid,
hthdx->tid,
DBG_CONTINUE,
0);
hthdx->tstate &= ~(ts_stopped|ts_first|ts_second);
hthdx->tstate |= ts_running;
return;
}
if (sn.FileName[0] == 0) {
AddQueue( QT_CONTINUE_DEBUG_EVENT,
hthdx->hprc->pid,
hthdx->tid,
DBG_CONTINUE,
0);
hthdx->tstate &= ~(ts_stopped|ts_first|ts_second);
hthdx->tstate |= ts_running;
return;
}
cb = _tcslen(sn.FileName)+1;
idx = LookupDllName(hprcx, sn.FileName);
if ( idx != -1 ) {
SLI sli;
assert( sn.Selector1 == 0 );
sli.wSelector = sn.Selector2;
sli.wSegNo = sn.Segment;
sli.mte = idx;
DMSendDebugPacket(dbceSegMove,
hprcx->hpid,
hthdx->htid,
sizeof(SLI),
&sli
);
}
AddQueue( QT_CONTINUE_DEBUG_EVENT,
hthdx->hprc->pid,
hthdx->tid,
DBG_CONTINUE,
0);
hthdx->tstate &= ~(ts_stopped|ts_first|ts_second);
hthdx->tstate |= ts_running;
break;
/*
* SEGFREE:
* This event is triggered if a selector is freed
* LOWORD( lpdw[0] ) - SEGFREE
* HIWORD( lpdw[0] ) - fBPRelease
* LOWORD( lpdw[1] ) - selector to be freed
*/
case DBG_SEGFREE:
AddQueue( QT_CONTINUE_DEBUG_EVENT,
hthdx->hprc->pid,
hthdx->tid,
DBG_CONTINUE,
0);
hthdx->tstate &= ~(ts_stopped|ts_first|ts_second);
hthdx->tstate |= ts_running;
break;
/*
* MODLOAD:
* This event is triggered when a new DLL is loaded
* LOWORD( lpdw[0] ) - MODLOAD
* HIWORD( lpdw[0] ) - length of module name
* HIWORD( lpdw[1] ) - selector
* lpdw[2] - address of module name
* lpdw[3] - image length
*/
case DBG_MODLOAD:
lpb = (char *) lpdw[2];
b = DbgReadMemory(hprcx, (UINT_PTR)lpb, &sn, sizeof(sn), &cbRead);
if ((b == 0) || (cbRead != sizeof(sn))) {
b = GetLastError();
AddQueue( QT_CONTINUE_DEBUG_EVENT,
hthdx->hprc->pid,
hthdx->tid,
DBG_CONTINUE,
0);
hthdx->tstate &= ~(ts_stopped|ts_first|ts_second);
hthdx->tstate |= ts_running;
return;
}
if (sn.FileName[0] == 0) {
AddQueue( QT_CONTINUE_DEBUG_EVENT,
hthdx->hprc->pid,
hthdx->tid,
DBG_CONTINUE,
0);
hthdx->tstate &= ~(ts_stopped|ts_first|ts_second);
hthdx->tstate |= ts_running;
return;
}
cb = _tcslen(sn.FileName)+1;
idx = LookupDllName(hprcx, sn.FileName);
if (idx == -1) {
LPMODULELOAD lpmdl;
cb = cb + sizeof(MODULELOAD);
lpmdl = (LPMODULELOAD) MHAlloc(cb);
lpmdl->cobj = 0;
lpmdl->mte = InsertDllName(hprcx, sn.FileName);
idx = LookupDllName(hprcx, sn.FileName);
if ( idx != -1 ) {
hprcx->rgDllList[idx].fReal = TRUE;
}
_tcscpy((char *) &lpmdl->rgobjd[lpmdl->cobj], sn.FileName);
lpmdl->StartingSegment = sn.Segment;
lpmdl->fRealMode = TRUE;
lpmdl->fFlatMode = FALSE;
lpmdl->fOffset32 = FALSE;
DMSendRequestReply(dbcModLoad,
hprcx->hpid,
hthdx->htid,
cb,
lpmdl,
sizeof(HEMI),
&hemi
);
MHFree(lpmdl);
}
AddQueue( QT_CONTINUE_DEBUG_EVENT,
hthdx->hprc->pid,
hthdx->tid,
DBG_CONTINUE,
0);
hthdx->tstate &= ~(ts_stopped|ts_first|ts_second);
hthdx->tstate |= ts_running;
break;
/*
* MODFREE:
* This event is triggered when a DLL is unloaded
* LOWORD( lpdw[0] ) - MODFREE
*/
case DBG_MODFREE:
lpb = (char *) lpdw[2];
b = DbgReadMemory(hprcx, (UINT_PTR)lpb, &sn, sizeof(sn), &cbRead);
if ((b == 0) || (cbRead != sizeof(sn))) {
b = GetLastError();
AddQueue( QT_CONTINUE_DEBUG_EVENT,
hthdx->hprc->pid,
hthdx->tid,
DBG_CONTINUE,
0);
hthdx->tstate &= ~(ts_stopped|ts_first|ts_second);
hthdx->tstate |= ts_running;
return;
}
if (sn.FileName[0] == 0) {
AddQueue( QT_CONTINUE_DEBUG_EVENT,
hthdx->hprc->pid,
hthdx->tid,
DBG_CONTINUE,
0);
hthdx->tstate &= ~(ts_stopped|ts_first|ts_second);
hthdx->tstate |= ts_running;
return;
}
cb = _tcslen(sn.FileName)+1;
idx = LookupDllName(hprcx, sn.FileName);
if (idx != -1) {
WORD w = (WORD)idx;
DMSendDebugPacket(dbceModFree16,
hprcx->hpid,
hthdx->htid,
sizeof(WORD),
&w
);
RemoveDllName( hprcx, idx );
}
AddQueue( QT_CONTINUE_DEBUG_EVENT,
hthdx->hprc->pid,
hthdx->tid,
DBG_CONTINUE,
0);
hthdx->tstate &= ~(ts_stopped|ts_first|ts_second);
hthdx->tstate |= ts_running;
break;
/*
* Int 01h break;
*/
case DBG_SINGLESTEP:
hthdx->context.ContextFlags = VDMCONTEXT_FULL;
(*pfnVDMGetThreadContext)(hthdx->hprc->rwHand, hthdx->rwHand, &hthdx->context);
eventCode = EXCEPTION_DEBUG_EVENT;
pde->dwDebugEventCode = EXCEPTION_DEBUG_EVENT;
pde->u.Exception.ExceptionRecord.ExceptionCode = subClass =
(DWORD)EXCEPTION_SINGLE_STEP;
/*
* They are not clearing the trace bit
*/
hthdx->context.EFlags &= ~TF_BIT_MASK;
hthdx->fContextDirty = TRUE;
AddrInit(&addr,
0,
(SEGMENT) hthdx->context.SegCs,
SE32To64( hthdx->context.Eip ),
FALSE,
FALSE,
FALSE,
FALSE
);
bp = FindBP(hthdx->hprc, hthdx, bptpExec, (BPNS)-1, &addr, FALSE);
if ( bp ) {
SetBPFlag( hthdx, bp );
}
goto dispatch;
case DBG_TASKSTART:
hthdx->context.ContextFlags = VDMCONTEXT_FULL;
(*pfnVDMGetThreadContext)(hthdx->hprc->rwHand, hthdx->rwHand, &hthdx->context);
eventCode =
pde->dwDebugEventCode = ENTRYPOINT_DEBUG_EVENT;
goto dispatch;
case DBG_TASKSTOP:
case DBG_DLLSTART:
case DBG_DLLSTOP:
case DBG_ATTACH:
AddQueue( QT_CONTINUE_DEBUG_EVENT,
hthdx->hprc->pid,
hthdx->tid,
DBG_CONTINUE,
0);
hthdx->tstate &= ~(ts_stopped|ts_first|ts_second);
hthdx->tstate |= ts_running;
break;
/*
* Int 03h break
* LOWORD(lpdw[0]) BREAKPOINT
* HIWORD(lpdw[0]) Protect Mode
*/
case DBG_BREAK:
hthdx->context.ContextFlags = VDMCONTEXT_FULL;
(*pfnVDMGetThreadContext)(hthdx->hprc->rwHand, hthdx->rwHand, &hthdx->context);
Set_PC(hthdx, PC(hthdx) - 1);
hthdx->fContextDirty = TRUE;
eventCode = pde->dwDebugEventCode = BREAKPOINT_DEBUG_EVENT;
// NOTENOTE jimsch -- assuming only 0xcc not 0xcd 0x3 breakpoints
AddrInit(&addr,
0,
(SEGMENT) hthdx->context.SegCs,
SE32To64( hthdx->context.Eip ),
FALSE,
FALSE,
FALSE,
FALSE
);
bp = FindBP(hthdx->hprc, hthdx, bptpExec, (BPNS)-1, &addr, FALSE);
if ( bp && bp->isStep ) {
eventCode = EXCEPTION_DEBUG_EVENT;
pde->dwDebugEventCode = EXCEPTION_DEBUG_EVENT;
pde->u.Exception.ExceptionRecord.ExceptionCode =
subClass = (DWORD)EXCEPTION_SINGLE_STEP;
RemoveBP(bp);
} else {
if ( bp ) {
SetBPFlag( hthdx, bp );
}
pde->u.Exception.ExceptionRecord.ExceptionCode =
subClass = (DWORD)bp;
}
pde->u.Exception.ExceptionRecord.ExceptionAddress = PC(hthdx);
dispatch:
hthdx->fAddrIsReal = FALSE;
hthdx->fAddrIsFlat = FALSE;
DebugEvent64To32(pde, &DeWow32);
if ((*pfnVDMGetThreadSelectorEntry)(&DeWow32,
hthdx->rwHand,
(WORD) hthdx->context.SegCs,
&ldt)) {
if (ldt.HighWord.Bits.Default_Big) {
hthdx->fAddrOff32 = TRUE;
} else {
hthdx->fAddrOff32 = FALSE;
}
} else {
hthdx->fAddrOff32 = FALSE;
}
/*
* Check if this debug event was expected
*/
pee = PeeIsEventExpected(hthdx, eventCode, subClass, TRUE);
/*
* If it wasn't, run the standard handler with
* notifications going to the execution model
*/
assert((0 < eventCode) && (eventCode < MAX_EVENT_CODE));
if (pee == NULL) {
if ((hthdx != NULL) && (hthdx->tstate & ts_funceval)) {
RgfnFuncEventDispatch[eventCode-EXCEPTION_DEBUG_EVENT](pde, hthdx);
} else {
DebugDispatchTable[eventCode-EXCEPTION_DEBUG_EVENT](pde,hthdx);
}
return;
}
/*
* If it was expected then call the action
* function if one was specified
*/
if (pee->action) {
(pee->action)(pde, hthdx, 0, pee->lparam);
}
/*
* And call the notifier if one was specified
*/
if (pee->notifier) {
METHOD *nm = pee->notifier;
(nm->notifyFunction)(pde, hthdx, 0, nm->lparam);
}
free(pee);
break;
#if 0 // why is this here??
case DBG_DIVOVERFLOW:
pde->dwDebugEventCode = 3;
goto fault_occured;
case DBG_INSTRFAULT:
pde->dwDebugEventCode = 1;
goto fault_occured;
#endif
case DBG_DIVOVERFLOW:
case DBG_INSTRFAULT:
case DBG_GPFAULT:
pde->dwDebugEventCode = EXCEPTION_DEBUG_EVENT;
#if 0 // why is this here??
fault_occured:
#endif
hthdx->context.ContextFlags = VDMCONTEXT_FULL;
(*pfnVDMGetThreadContext)(hthdx->hprc->rwHand, hthdx->rwHand, &hthdx->context);
pde->u.Exception.ExceptionRecord.ExceptionCode = 13;
hthdx->fAddrIsReal = FALSE;
hthdx->fAddrIsFlat = FALSE;
DebugEvent64To32(pde, &DeWow32);
if ((*pfnVDMGetThreadSelectorEntry)(&DeWow32, hthdx->rwHand,
(WORD) hthdx->context.SegCs, &ldt)) {
if (ldt.HighWord.Bits.Default_Big) {
hthdx->fAddrOff32 = TRUE;
} else {
hthdx->fAddrOff32 = FALSE;
}
} else {
hthdx->fAddrOff32 = FALSE;
}
ProcessExceptionEvent(pde, hthdx);
break;
default:
AddQueue( QT_CONTINUE_DEBUG_EVENT,
hthdx->hprc->pid,
hthdx->tid,
DBG_CONTINUE,
0);
hthdx->tstate &= ~(ts_stopped|ts_first|ts_second);
hthdx->tstate |= ts_running;
break;
}
#endif // i386 && !Win32S
return;
} /* ProcessSegmentLoadEvent() */
#if defined(i386) && !defined(WIN32S)
int
LookupDllName(
HPRCX hprcx,
char * sz
)
/*++
Routine Description:
This routine will snoop through the structures of an exe and determine
if we have previously seen this dll name for this process.
Arguments:
hprcx - Supplies a handle to a process
sz - Supplies a pointer to a DLL file name
Return Value:
The index in the array if present. Else -1
--*/
{
int i;
/*
* If there is no list then the item is not on the list
*/
if (hprcx->rgDllList == NULL) {
return -1;
}
/*
* Check each item in the list
*/
for (i=0; i<hprcx->cDllList; i++) {
if ((hprcx->rgDllList[i].fValidDll) &&
(hprcx->rgDllList[i].szDllName != NULL) &&
(_tcscmp(hprcx->rgDllList[i].szDllName, sz) == 0)) {
return i;
}
}
return -1;
} /* LookupDllName() */
int
InsertDllName(
HPRCX hprcx,
char * sz
)
/*++
Routine Description:
This routine will take a dll name and an mte and put then into the
list of dlls for the current process.
Arguments:
hprcx - Supplies a handle to a process
sz - Supplies a pointer to a DLL file name
Return Value:
The index in the array where it was placed.
--*/
{
int i;
int cb;
int cItem;
/*
* If there is no list then make a list
*/
if (hprcx->rgDllList == NULL) {
hprcx->rgDllList = (PDLLLOAD_ITEM) malloc(sizeof(DLLLOAD_ITEM) * 10);
memset(hprcx->rgDllList, 0, sizeof(DLLLOAD_ITEM)*10);
}
/*
* Check each item in the list
*/
for (i=0; i<hprcx->cDllList; i++) {
if ((hprcx->rgDllList[i].fValidDll == FALSE) &&
(hprcx->rgDllList[i].szDllName == NULL)) {
if ((hprcx->rgDllList[i].szDllName = MHAlloc(_tcslen(sz) + 1)) != NULL) {
_tcscpy(hprcx->rgDllList[i].szDllName, sz);
} else {
assert(FALSE); // Need to deal with this case correctly.
}
hprcx->rgDllList[i].fValidDll = TRUE;
hprcx->rgDllList[i].fWow = TRUE;
return i;
}
}
cItem = hprcx->cDllList;
if (i == cItem) {
cb = i * sizeof(DLLLOAD_ITEM);
cItem += 10;
hprcx->rgDllList = (PDLLLOAD_ITEM) realloc(hprcx->rgDllList, cItem*sizeof(DLLLOAD_ITEM));
memset(cb + (char *) hprcx->rgDllList, 0, 10*sizeof(DLLLOAD_ITEM));
}
if ((hprcx->rgDllList[i].szDllName = MHAlloc(_tcslen(sz) + 1)) != NULL) {
_tcscpy(hprcx->rgDllList[i].szDllName, sz);
} else {
assert(FALSE); // Need to deal with this case correctly.
}
hprcx->rgDllList[i].fValidDll = TRUE;
hprcx->rgDllList[i].fWow = TRUE;
hprcx->cDllList += 10;
return i;
} /* InsertDllName() */
void
RemoveDllName(
HPRCX hprcx,
int idx
)
/*++
Routine Description:
This routine will remove a dll from the internal list of known dlls.
Arguments:
hprcx - Supplies the handle to the current process
idx - supplies the index of the dll to be removed
Return Value:
None.
--*/
{
assert( hprcx->rgDllList != NULL );
free(hprcx->rgDllList[idx].szDllName);
hprcx->rgDllList[idx].szDllName = NULL;
hprcx->rgDllList[idx].fValidDll = FALSE;
hprcx->rgDllList[idx].fReal = FALSE;
hprcx->rgDllList[idx].fWow = FALSE;
return;
} /* RemoveDllName() */
#endif // i386 && !WIN32S
/*++
Routine Description:
Callback for VDMEnumProcessWOW
Arguments:
See PROCESSENUMPROC in vdmdbg.h
Return Value:
TRUE
--*/
BOOL WINAPI EnumCallBack(
DWORD dwProcessId,
DWORD dwAttributes,
LPARAM lpUserDefined
)
{
UNREFERENCED_PARAMETER( dwProcessId );
UNREFERENCED_PARAMETER( dwAttributes );
UNREFERENCED_PARAMETER( lpUserDefined );
return TRUE;
}
BOOL
IsWOWPresent(
VOID
)
/*++
Routine Description:
Determines if WOW is running
Arguments:
None
Return Value:
TRUE if WOW is running, FALSE otherwise
--*/
{
#if defined(i386) && !defined(WIN32S)
return (*pfnVDMEnumProcessWOW)( (PROCESSENUMPROC)EnumCallBack, 0 );
#else
return FALSE;
#endif
}
BOOL
TranslateAddress(
HPRCX hprc,
HTHDX hthd,
LPADDR lpaddr,
BOOL f16ToFlat
)
/*++
Routine Description:
This function is used to preform address translations from the segmented
to the flat world and back again.
Arguments:
hprc - Supplies the handle to the current process
hthd - Supplies the handle to the thread for the address
lpaddr - Supplies the address to be translated
f16ToFlat - Supplies the direction the translation is to be made
Return Value:
TRUE on success and FALSE on failure
--*/
{
#if defined(i386)
LDT_ENTRY ldt;
ULONG ul;
#ifdef WIN32S
ADDR_IS_FLAT(*lpaddr) = TRUE;
ADDR_IS_REAL(*lpaddr) = FALSE;
return TRUE;
#endif
/*
* Step 0. If the address has already been mapped flat then return
*/
if (ADDR_IS_FLAT(*lpaddr)) {
return TRUE;
}
/*
* Step 1. Is to find a stopped thread. This is mainly for WOW support
* where the lack of a stopped thread is a serious thing,
* we can not do anything smartly with wow if this is the
* case. We will currently only search for a single
* stopped thread cause the blasted operating system won't
* let us have more than one.
*/
if (hthd == 0) {
for (hthd = hprc->hthdChild; hthd != hthdxNull; hthd = hthd->nextSibling) {
if (hthd->tstate & ts_stopped) {
break;
}
}
if (hthd == 0) {
hthd = hprc->hthdChild;
}
}
/*
* Must have a thread
*/
if (hthd == NULL) {
return FALSE;
}
/*
* Step 2. Depending on if the last event was WOW we need to
* either go in with a WOW remap or do the standard
* non-wow remap
*/
if (hthd->fAddrIsFlat) {
if (ADDR_IS_REAL( *lpaddr )) {
ul = GetAddrSeg(*lpaddr) * 16 + (DWORD)GetAddrOff(*lpaddr);
lpaddr->addr.off = ul;
} else if (GetThreadSelectorEntry(hthd->rwHand, GetAddrSeg(*lpaddr),
&ldt)) {
ul = (ldt.HighWord.Bytes.BaseHi << 24) |
(ldt.HighWord.Bytes.BaseMid << 16) |
(ldt.BaseLow);
lpaddr->addr.off += ul;
} else {
/*
* Unrecognized selector
*/
return FALSE;
}
} else {
#if defined(i386) && !defined(WIN32S)
lpaddr->addr.off = (*pfnVDMGetPointer)(hprc->rwHand, hthd->rwHand,
(WORD)GetAddrSeg(*lpaddr),
(DWORD)GetAddrOff(*lpaddr),
!lpaddr->mode.fReal);
#else // defined(i386) && !defined(WIN32S)
assert(FALSE);
return FALSE;
#endif // defined(i386) && !defined(WIN32S)
}
#endif
ADDR_IS_FLAT(*lpaddr) = TRUE;
ADDR_IS_REAL(*lpaddr) = FALSE;
return TRUE;
} /* TranslateAddress() */
BOOL
WOWGetThreadContext(
HTHDX hthdx,
LPCONTEXT lpcxt
)
/*++
Routine Description:
This routine is called to get the context of a WOW thread. We have
a current assumption that we will only have one WOW event at a time.
Arguments:
hthdx - supplies the handle to the thread to change the context of
lpcxt - supplies the new context.
Return Value:
TRUE on success and FALSE on failure
--*/
{
#if defined(i386) && !defined(WIN32S)
assert(hthdx->fWowEvent);
if (hthdx->tid != DeWow.dwThreadId) {
assert(FALSE);
return FALSE;
}
return (*pfnVDMGetThreadContext)(hthdx->hprc->rwHand, hthdx->rwHand, lpcxt);
#else
return FALSE;
#endif
} /* WOWGetThreadContext() */
BOOL
WOWSetThreadContext(
HTHDX hthdx,
LPCONTEXT lpcxt
)
/*++
Routine Description:
This routine is called to set the context of a WOW thread. We have
a current assumption that we will only have one WOW event at a time.
Arguments:
hthdx - supplies the handle to the thread to change the context of
lpcxt - supplies the new context.
Return Value:
TRUE on success and FALSE on failure
--*/
{
#if defined(i386) && !defined(WIN32S)
assert(hthdx->fWowEvent);
if (hthdx->tid != DeWow.dwThreadId) {
assert(FALSE);
return FALSE;
}
return (*pfnVDMSetThreadContext)(hthdx->hprc->rwHand, hthdx->rwHand, lpcxt);
#else
return FALSE;
#endif
} /* WOWSetThreadContext() */