mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1175 lines
29 KiB
1175 lines
29 KiB
/*++
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|
/************************* GLOBAL VARIABLES ******************************/
|
|
|
|
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_EVENT DeWow;
|
|
|
|
|
|
/************************** FUNCTIONS ************************************/
|
|
|
|
|
|
void
|
|
ProcessEntryPointEvent(
|
|
DEBUG_EVENT * 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,
|
|
lpb,
|
|
&in,
|
|
sizeof(in),
|
|
&cbRead);
|
|
|
|
if ((b == 0) || (cbRead != sizeof(in))) {
|
|
b = GetLastError();
|
|
} else {
|
|
_splitpath(in.FileName, NULL, NULL, szName0, szExt);
|
|
strcat(szName0, szExt);
|
|
_splitpath(nameBuffer, NULL, NULL, szName1, szExt);
|
|
strcat(szName1, szExt);
|
|
|
|
if (_strcmpi(szName0, szName1) == 0) {
|
|
*nameBuffer = 0;
|
|
hthdx->hprc->pstate &= ~ps_preEntry;
|
|
hthdx->tstate |= ts_stopped;
|
|
NotifyEM(pde, hthdx, 0, (LPVOID)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_EVENT * 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)
|
|
|
|
LPDWORD lpdw = &pde->u.Exception.ExceptionRecord.ExceptionInformation[0];
|
|
int mode = LOWORD( lpdw[0] );
|
|
int cb;
|
|
int cbRead;
|
|
int b;
|
|
char rgch[512];
|
|
char * lpb;
|
|
LPMODULELOAD lpmdl;
|
|
RTP rtp;
|
|
LPRTP lprtp;
|
|
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;
|
|
|
|
|
|
#ifdef i386
|
|
DeWow = *pde;
|
|
|
|
rtp.hpid = hprcx->hpid;
|
|
rtp.htid = hthdx->htid;
|
|
|
|
hthdx->fWowEvent = TRUE;
|
|
|
|
VDMProcessException(pde);
|
|
|
|
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, 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 = strlen(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.
|
|
//
|
|
lprtp = (LPRTP) rgch;
|
|
*lprtp = rtp;
|
|
lprtp->dbc = dbceModFree16;
|
|
lprtp->cb = sizeof(WORD);
|
|
*((WORD *)(&lprtp->rgbVar[0])) = idx;
|
|
|
|
DmTlFunc(tlfDebugPacket, rtp.hpid, lprtp->cb + sizeof(RTP),
|
|
(LONG)(LPV) lprtp);
|
|
|
|
RemoveDllName( hprcx, idx );
|
|
idx = -1;
|
|
}
|
|
}
|
|
|
|
if (idx == -1) {
|
|
|
|
cb = cb + sizeof(MODULELOAD) + (sn.Segment+1)*sizeof(OBJD);
|
|
lprtp = (LPRTP) malloc(cb + sizeof(RTP));
|
|
memset(lprtp, 0, cb + sizeof(RTP));
|
|
|
|
*lprtp = rtp;
|
|
lprtp->dbc = dbcModLoad;
|
|
lprtp->cb = cb;
|
|
|
|
lpmdl = (LPMODULELOAD) &(lprtp->rgbVar[0]);
|
|
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);
|
|
strcpy((char *) &lpmdl->rgobjd[lpmdl->cobj], sn.FileName);
|
|
|
|
lpmdl->fRealMode = FALSE;
|
|
lpmdl->fFlatMode = FALSE;
|
|
lpmdl->fOffset32 = FALSE;
|
|
|
|
DmTlFunc(tlfRequest, rtp.hpid, lprtp->cb + sizeof(RTP),
|
|
(LONG)(LPV) lprtp);
|
|
|
|
hemi = *((HEMI *) abEMReplyBuf);
|
|
|
|
free(lprtp);
|
|
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 {
|
|
LPSLI lpsli;
|
|
|
|
lprtp = (LPRTP) malloc( sizeof(RTP) + sizeof(SLI));
|
|
*lprtp = rtp;
|
|
lprtp->dbc = dbceSegLoad;
|
|
lprtp->cb = sizeof(SLI);
|
|
lpsli = (LPSLI) &lprtp->rgbVar[0];
|
|
lpsli->wSelector = sn.Selector1;
|
|
lpsli->wSegNo = sn.Segment;
|
|
lpsli->mte = idx;
|
|
|
|
DmTlFunc(tlfDebugPacket, rtp.hpid, lprtp->cb + sizeof(RTP),
|
|
(LONG)(LPV) lprtp);
|
|
|
|
free( lprtp );
|
|
}
|
|
|
|
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, 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 = strlen(sn.FileName)+1;
|
|
|
|
idx = LookupDllName(hprcx, sn.FileName);
|
|
|
|
if ( idx != -1 ) {
|
|
LPSLI lpsli;
|
|
|
|
lprtp = (LPRTP) malloc( sizeof(RTP) + sizeof(SLI));
|
|
*lprtp = rtp;
|
|
lprtp->dbc = dbceSegMove;
|
|
lprtp->cb = sizeof(SLI);
|
|
lpsli = (LPSLI) &lprtp->rgbVar[0];
|
|
assert( sn.Selector1 == 0 );
|
|
lpsli->wSelector = sn.Selector2;
|
|
lpsli->wSegNo = sn.Segment;
|
|
lpsli->mte = idx;
|
|
|
|
DmTlFunc(tlfDebugPacket, rtp.hpid, lprtp->cb + sizeof(RTP),
|
|
(LONG)(LPV) lprtp);
|
|
|
|
free( lprtp );
|
|
}
|
|
|
|
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, 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 = strlen(sn.FileName)+1;
|
|
idx = LookupDllName(hprcx, sn.FileName);
|
|
|
|
if (idx == -1) {
|
|
cb = cb + sizeof(MODULELOAD);
|
|
lprtp = (LPRTP) malloc(cb + sizeof(RTP));
|
|
memset(lprtp, 0, cb + sizeof(RTP));
|
|
|
|
*lprtp = rtp;
|
|
lprtp->dbc = dbcModLoad;
|
|
lprtp->cb = cb;
|
|
|
|
lpmdl = (LPMODULELOAD) &(lprtp->rgbVar[0]);
|
|
lpmdl->cobj = 0;
|
|
|
|
lpmdl->mte = InsertDllName(hprcx, sn.FileName);
|
|
|
|
idx = LookupDllName(hprcx, sn.FileName);
|
|
|
|
if ( idx != -1 ) {
|
|
hprcx->rgDllList[idx].fReal = TRUE;
|
|
}
|
|
|
|
strcpy((char *) &lpmdl->rgobjd[lpmdl->cobj], sn.FileName);
|
|
|
|
lpmdl->StartingSegment = sn.Segment;
|
|
|
|
lpmdl->fRealMode = TRUE;
|
|
lpmdl->fFlatMode = FALSE;
|
|
lpmdl->fOffset32 = FALSE;
|
|
|
|
DmTlFunc(tlfRequest, rtp.hpid, lprtp->cb + sizeof(RTP),
|
|
(LONG)(LPV) lprtp);
|
|
|
|
hemi = *((HEMI *) abEMReplyBuf);
|
|
|
|
free(lprtp);
|
|
}
|
|
|
|
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, 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 = strlen(sn.FileName)+1;
|
|
|
|
idx = LookupDllName(hprcx, sn.FileName);
|
|
|
|
if (idx != -1) {
|
|
lprtp = (LPRTP) rgch;
|
|
*lprtp = rtp;
|
|
lprtp->dbc = dbceModFree16;
|
|
lprtp->cb = sizeof(WORD);
|
|
*((WORD *)(&lprtp->rgbVar[0])) = idx;
|
|
|
|
DmTlFunc(tlfDebugPacket, rtp.hpid, lprtp->cb + sizeof(RTP),
|
|
(LONG)(LPV) lprtp);
|
|
|
|
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;
|
|
VDMGetThreadContext(pde, &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, 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;
|
|
VDMGetThreadContext(pde, &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;
|
|
VDMGetThreadContext(pde, &hthdx->context);
|
|
|
|
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, 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 = (LPVOID) PC(hthdx);
|
|
|
|
dispatch:
|
|
hthdx->fAddrIsReal = FALSE;
|
|
hthdx->fAddrIsFlat = FALSE;
|
|
|
|
if (VDMGetThreadSelectorEntry(pde,
|
|
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);
|
|
|
|
/*
|
|
* 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;
|
|
VDMGetThreadContext(pde, &hthdx->context);
|
|
pde->u.Exception.ExceptionRecord.ExceptionCode = 13;
|
|
|
|
hthdx->fAddrIsReal = FALSE;
|
|
hthdx->fAddrIsFlat = FALSE;
|
|
|
|
if (VDMGetThreadSelectorEntry(pde, 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
|
|
#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) &&
|
|
(strcmp(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)) {
|
|
hprcx->rgDllList[i].szDllName = _strdup(sz);
|
|
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));
|
|
}
|
|
|
|
|
|
hprcx->rgDllList[i].szDllName = _strdup(sz);
|
|
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 VDMEnumProcessWOW( (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->next) {
|
|
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 + 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 = VDMGetPointer(hprc->rwHand, hthd->rwHand,
|
|
GetAddrSeg(*lpaddr),
|
|
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 g 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 VDMGetThreadContext(&DeWow, 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 VDMSetThreadContext(&DeWow, lpcxt);
|
|
#else
|
|
return FALSE;
|
|
#endif
|
|
} /* WOWSetThreadContext() */
|