Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

2490 lines
60 KiB

/*++
Copyright (c) 1990 Microsoft Corporation
Module Name:
procem.c
Abstract:
Author:
Environment:
NT 3.1
Revision History:
--*/
#include "precomp.h"
#pragma hdrstop
#ifndef KERNEL
#include <crash.h>
extern BOOL CrashDump;
#endif
SetFile()
#ifdef WIN32S
// set true while in exception dbg evt
extern BOOL fCanGetThreadContext;
#endif
#ifndef WIN32S
extern DEBUG_ACTIVE_STRUCT DebugActiveStruct;
extern PKILLSTRUCT KillQueue;
extern CRITICAL_SECTION csKillQueue;
#endif
extern WT_STRUCT WtStruct;
extern EXPECTED_EVENT masterEE, *eeList;
extern HTHDX thdList;
extern HPRCX prcList;
extern CRITICAL_SECTION csThreadProcList;
extern DEBUG_EVENT falseSSEvent;
extern METHOD EMNotifyMethod;
extern CRITICAL_SECTION csProcessDebugEvent;
extern HANDLE hEventCreateProcess;
extern HANDLE hEventNoDebuggee;
extern HANDLE hDmPollThread;
extern HANDLE hEventRemoteQuit;
extern HANDLE hEventContinue;
extern LPDM_MSG LpDmMsg;
extern HPID hpidRoot;
extern BOOL fUseRoot;
extern BOOL fDisconnected;
extern DMTLFUNCTYPE DmTlFunc;
extern char nameBuffer[];
VOID
MethodContinueSS(
DEBUG_EVENT*,
HTHDX,
DWORD,
METHOD*
);
BOOL
MakeThreadSuspendItself(
HTHDX
);
VOID
ProcessIoctlGenericCmd(
HPRCX hprc,
HTHDX hthd,
LPDBB lpdbb
);
VOID
ProcessIoctlCustomCmd(
HPRCX hprc,
HTHDX hthd,
LPDBB lpdbb
);
#ifdef KERNEL
extern BOOL DmKdBreakIn;
#endif
#if defined(KERNEL)
BOOL fSmartRangeStep = TRUE;
#else
BOOL fSmartRangeStep = FALSE;
#endif
void
ActionRemoveBP(
DEBUG_EVENT* de,
HTHDX hthd,
DWORD unused,
BREAKPOINT* bp
)
{
Unreferenced( de );
Unreferenced( hthd );
RemoveBP(bp);
}
VOID
ProcessCreateProcessCmd(
HPRCX hprc,
HTHDX hthd,
LPDBB lpdbb
)
/*++
Routine Description:
Create a process requested by the EM.
Arguments:
hprc -
hthd -
lpdbb -
Return Value:
None.
--*/
{
XOSD xosd = xosdNone;
Unreferenced( hprc );
Unreferenced( hthd );
DEBUG_PRINT_2(
"ProcessCreateProcessCmd called with HPID=%d, (sizeof(HPID)=%d)",
lpdbb->hpid, sizeof(HPID));
hpidRoot = lpdbb->hpid;
fUseRoot = TRUE;
Reply(0, &xosd, lpdbb->hpid);
return;
} /* ProcessCreateProcessCmd() */
DWORD
ProcessProcStatCmd(
HPRCX hprc,
HTHDX hthd,
LPDBB lpdbb
)
{
LPPST lppst = (LPPST)LpDmMsg->rgb;
Unreferenced( lpdbb );
DEBUG_PRINT("ProcessProcStatCmd\n");
lppst->dwProcessID = hprc->pid;
sprintf(lppst->rgchProcessID, "%5d", hprc->pid);
/*
* Check if any of this process's threads are running
*/
if (hprc->pstate & ps_exited) {
lppst->dwProcessState = pstExited;
strcpy(lppst->rgchProcessState, "Exited");
} else if (hprc->pstate & ps_dead) {
lppst->dwProcessState = pstDead;
strcpy(lppst->rgchProcessState, "Dead");
} else {
lppst->dwProcessState = pstRunning;
strcpy(lppst->rgchProcessState, "Running");
EnterCriticalSection(&csThreadProcList);
for (hthd = (HTHDX)hprc->hthdChild;hthd;hthd=hthd->nextSibling) {
if (hthd->tstate & ts_stopped) {
lppst->dwProcessState = pstStopped;
strcpy(lppst->rgchProcessState, "Stopped");
break;
}
}
LeaveCriticalSection(&csThreadProcList);
}
return sizeof(PST);
}
DWORD
ProcessThreadStatCmd(
HPRCX hprc,
HTHDX hthd,
LPDBB lpdbb
)
{
LPTST lptst = (LPTST) LpDmMsg->rgb;
XOSD xosd = xosdNone;
#ifndef KERNEL
typedef NTSTATUS (* QTHREAD)(HANDLE,THREADINFOCLASS,PVOID,ULONG,PULONG);
NTSTATUS Status;
THREAD_BASIC_INFORMATION ThreadBasicInfo;
QTHREAD Qthread;
DWORD dw;
#endif // KERNEL
Unreferenced( hprc );
DEBUG_PRINT("ProcessThreadStatCmd : ");
#ifdef KERNEL
assert(hthd != 0);
#else // KERNEL
if (!hthd) {
WaitForSingleObject(hprc->hEventCreateThread, INFINITE);
hthd = HTHDXFromHPIDHTID(lpdbb->hpid, lpdbb->htid);
assert(hthd != 0);
if (!hthd) {
LpDmMsg->xosdRet = xosdInvalidThread;
return sizeof(TST);
}
}
#endif // KERNEL
ZeroMemory(lptst, sizeof(TST));
#ifdef KERNEL
lptst->dwThreadID = hthd->tid;
sprintf(lptst->rgchThreadID, "%5d", lptst->dwThreadID);
lptst->dwSuspendCount = 0;
lptst->dwSuspendCountMax = 0;
lptst->dwPriority = 1;
lptst->dwPriorityMax = 1;
sprintf(lptst->rgchPriority, "%2d", lptst->dwPriority);
#else // !KERNEL
if (CrashDump) {
lptst->dwThreadID = hthd->CrashThread.ThreadId;
} else {
lptst->dwThreadID = hthd->tid;
}
sprintf(lptst->rgchThreadID, "%5d", lptst->dwThreadID);
if (CrashDump) {
lptst->dwSuspendCount = hthd->CrashThread.SuspendCount;
} else {
dw = SuspendThread(hthd->rwHand);
if (dw != 0xffffffff) {
lptst->dwSuspendCount = dw;
ResumeThread(hthd->rwHand);
} else {
switch (GetLastError()) {
case (DWORD)STATUS_SUSPEND_COUNT_EXCEEDED:
lptst->dwSuspendCount = MAXIMUM_SUSPEND_COUNT;
break;
case (DWORD)STATUS_THREAD_IS_TERMINATING:
lptst->dwSuspendCount = 0;
break;
default:
lptst->dwSuspendCount = 0;
xosd = xosdInvalidThread;
}
}
}
lptst->dwSuspendCountMax = MAXIMUM_SUSPEND_COUNT;
if (CrashDump) {
dw = hthd->CrashThread.PriorityClass;
} else {
dw = GetPriorityClass(hprc->rwHand);
}
if (!dw) {
xosd = xosdInvalidThread;
} else {
switch (dw) {
case IDLE_PRIORITY_CLASS:
lptst->dwPriority = 4;
lptst->dwPriorityMax = 15;
break;
case NORMAL_PRIORITY_CLASS:
lptst->dwPriority = 9;
lptst->dwPriorityMax = 15;
break;
case HIGH_PRIORITY_CLASS:
lptst->dwPriority = 13;
lptst->dwPriorityMax = 15;
break;
case REALTIME_PRIORITY_CLASS:
lptst->dwPriority = 4;
lptst->dwPriorityMax = 31;
break;
}
if (CrashDump) {
dw = hthd->CrashThread.Priority;
} else {
dw = GetThreadPriority(hthd->rwHand);
}
if (dw == THREAD_PRIORITY_ERROR_RETURN) {
xosd = xosdInvalidThread;
} else {
lptst->dwPriority += dw;
if ((long)lptst->dwPriority > (long)lptst->dwPriorityMax) {
lptst->dwPriority = lptst->dwPriorityMax;
} else if ((long)lptst->dwPriority < (long)(lptst->dwPriorityMax - 15)) {
lptst->dwPriority = lptst->dwPriorityMax - 15;
}
sprintf(lptst->rgchPriority, "%2d", lptst->dwPriority);
}
}
#endif // !KERNEL
if (hthd->tstate & ts_running) {
lptst->dwState = tstRunning;
strcpy(lptst->rgchState, "Running");
} else if (hthd->tstate & ts_stopped) {
lptst->dwState = tstStopped;
if (hthd->tstate & ts_frozen) {
lptst->dwSuspendCount = 1;
}
strcpy(lptst->rgchState, "Stopped");
} else if (hthd->tstate & ts_dead) {
lptst->dwState = tstExiting;
strcpy(lptst->rgchState, "Exiting");
} else if (hthd->tstate & ts_destroyed) {
lptst->dwState = tstDead;
strcpy(lptst->rgchState, "Dead");
} else {
lptst->dwState = tstRunnable;
strcpy(lptst->rgchState, "Pre-run");
}
if (hthd->tstate & ts_rip ) {
lptst->dwState |= tstRip;
strcat(lptst->rgchState, ", RIPped");
} else if (hthd->tstate & ts_first) {
lptst->dwState |= tstExcept1st;
strcat(lptst->rgchState, ", 1st chance");
} else if (hthd->tstate & ts_second) {
lptst->dwState |= tstExcept2nd;
strcat(lptst->rgchState, ", 2nd chance");
}
if (hthd->tstate & ts_frozen) {
lptst->dwState |= tstFrozen;
strcat(lptst->rgchState, ", suspended");
}
lptst->dwTeb = 0;
#ifndef KERNEL
if (CrashDump) {
lptst->dwTeb = hthd->CrashThread.Teb;
} else {
Qthread = (QTHREAD)GetProcAddress( GetModuleHandle( "ntdll.dll" ),
"NtQueryInformationThread" );
if (Qthread) {
Status = Qthread( hthd->rwHand,
ThreadBasicInformation,
&ThreadBasicInfo,
sizeof(ThreadBasicInfo),
NULL
);
if (NT_SUCCESS(Status)) {
lptst->dwTeb = (DWORD)ThreadBasicInfo.TebBaseAddress;
}
}
}
#endif // !KERNEL
LpDmMsg->xosdRet = xosd;
return sizeof(TST);
}
/*** ProcessLoadCmd
**
** Synopsis:
**
** Entry:
**
** Returns:
**
** Description:
** Process a load command from the debugger
*/
void
ProcessLoadCmd(
HPRCX hprc,
HTHDX hthd,
LPDBB lpdbb
)
{
#ifdef KERNEL
LPPRL lpprl = (LPPRL)(lpdbb->rgbVar);
LPSTR p;
char progname[MAX_PATH];
char fname[_MAX_FNAME];
char ext[_MAX_EXT];
ValidateHeap();
if (fDisconnected) {
DmKdBreakIn = TRUE;
SetEvent( hEventRemoteQuit );
LpDmMsg->xosdRet = xosdNone;
Reply(0, LpDmMsg, lpdbb->hpid);
return;
}
// The debugger will pass us a quoted string version of the name. Parse out the quotes.
for (p=lpprl->lszCmdLine+1; p && *p && *p !='"'; p++) ;
if (*p=='"') {
*p = '\0';
}
_splitpath( lpprl->lszCmdLine+1, NULL, NULL, fname, ext );
if (_stricmp(ext,"exe") != 0) {
strcpy(ext, "exe" );
}
_makepath( progname, NULL, NULL, fname, ext );
if ((_stricmp(progname,KERNEL_IMAGE_NAME)==0) ||
(_stricmp(progname,OSLOADER_IMAGE_NAME)==0)) {
ValidateHeap();
if (!DmKdConnectAndInitialize( progname )) {
LpDmMsg->xosdRet = xosdFileNotFound;
} else {
LpDmMsg->xosdRet = xosdNone;
}
} else {
LpDmMsg->xosdRet = xosdFileNotFound;
}
ValidateHeap();
Reply(0, LpDmMsg, lpdbb->hpid);
ValidateHeap();
return;
#else // !KERNEL
char * szApplicationName;
char * szCommandLine=NULL;
char ** szEnvironment=NULL;
char * szCurrentDirectory=NULL;
DWORD creationFlags;
STARTUPINFO si;
XOSD xosd;
LPPRL lpprl = (LPPRL)(lpdbb->rgbVar);
HPRCX hprc1;
HPRCX hprcT;
fDisconnected = FALSE;
/*
* For various strange reasons the list of processes may not have
* been completely cleared. If not do so now
*/
for (hprc1 = prcList; hprc1 != hprcxNull; hprc1 = hprcT) {
hprcT = hprc1->next;
if (hprc1->pstate & ps_dead) {
FreeProcess( hprc1, FALSE );
}
}
memset(&si, 0, sizeof(si));
si.cb = sizeof(si);
si.dwFlags = STARTF_USESHOWWINDOW;
#ifdef OSDEBUG4
switch ( lpprl->dwChildFlags & (ulfMinimizeApp | ulfNoActivate) )
#else
switch ( lpprl->ulChildFlags & (ulfMinimizeApp | ulfNoActivate) )
#endif
{
case 0:
si.wShowWindow = SW_SHOWNORMAL;
break;
case ulfMinimizeApp:
si.wShowWindow = SW_SHOWMINIMIZED;
break;
case ulfNoActivate:
si.wShowWindow = SW_SHOWNOACTIVATE;
break;
case (ulfMinimizeApp | ulfNoActivate):
si.wShowWindow = SW_SHOWMINNOACTIVE;
break;
}
#ifdef OSDEBUG4
creationFlags = (lpprl->dwChildFlags & ulfMultiProcess)?
#else
creationFlags = (lpprl->ulChildFlags & ulfMultiProcess)?
#endif
DEBUG_PROCESS :
DEBUG_ONLY_THIS_PROCESS;
#ifdef OSDEBUG4
if (lpprl->dwChildFlags & ulfWowVdm) {
#else
if (lpprl->ulChildFlags & ulfWowVdm) {
#endif
creationFlags |= CREATE_SEPARATE_WOW_VDM;
}
szApplicationName = lpprl->lszCmdLine;
DEBUG_PRINT_2("Load Program: \"%s\" HPRC=0x%x\n",
szApplicationName, (DWORD) hprc);
// M00BUG -- Reply on load failure needs to be done here
xosd = Load(hprc,
szApplicationName,
szCommandLine,
(LPVOID)0, // &lc->processAttributes,
(LPVOID)0, // &lc->threadAttributes,
creationFlags,
#ifdef OSDEBUG4
(lpprl->dwChildFlags & ulfInheritHandles) != 0,
#else
(lpprl->ulChildFlags & ulfInheritHandles) != 0,
#endif
szEnvironment,
szCurrentDirectory,
&si );
/*
** If the load failed then we need to reply right now. Otherwise
** we will delay the reply until we get the All Dlls loaded exception.
*/
if (!fUseRoot || xosd != xosdNone) {
Reply(0, &xosd, lpdbb->hpid);
}
return;
#endif // !KERNEL
}
DWORD
ProcessUnloadCmd(
HPRCX hprc,
HTHDX hthd,
LPDBB lpdbb
)
{
DEBUG_EVENT devent, *pde=&devent;
HTHDXSTRUCT tHthdS;
HTHDX hthdT;
Unreferenced( lpdbb );
DEBUG_PRINT("ProcessUnloadCmd called.\n");
/*
* Verify we got a valid HPRCX
*/
if (!hprc) {
return FALSE;
}
if (hprc->pstate != (ps_root | ps_destroyed)) {
if (hprc->hthdChild != 0) {
tHthdS = *((HTHDX)(hprc->hthdChild));
} else {
memset( &tHthdS, 0, sizeof( HTHDXSTRUCT ) );
tHthdS.hprc = hprc;
tHthdS.rwHand = (HANDLE)-1;
}
/*
* Pump back destruction notifications
*/
pde->dwDebugEventCode = DESTROY_THREAD_DEBUG_EVENT;
pde->dwProcessId = hprc->pid;
for(hthd=hprc->hthdChild; hthd; hthd = hthdT){
hthdT = hthd->nextSibling;
if (hthd->rwHand != (HANDLE)INVALID) {
pde->dwThreadId = hthd->tid;
NotifyEM(pde, hthd, 0, hprc);
//
// The session manager "owns" this handle...
//
//CloseHandle(hthd->rwHand);
}
FreeHthdx(hthd);
}
hprc->hthdChild = NULL;
#ifndef KERNEL
if (hprc->rwHand != (HANDLE)INVALID && hprc->CloseProcessHandle) {
CloseHandle(hprc->rwHand);
hprc->rwHand = (HANDLE)INVALID;
}
#endif // KERNEL
pde->dwDebugEventCode = EXIT_PROCESS_DEBUG_EVENT;
pde->u.ExitProcess.dwExitCode = hprc->dwExitCode;
NotifyEM(pde, &tHthdS, 0, hprc);
pde->dwDebugEventCode = DESTROY_PROCESS_DEBUG_EVENT;
NotifyEM(pde, &tHthdS, 0, hprc);
}
return (DWORD) TRUE;
} /* ProcessUnloadCmd() */
XOSD
FreeProcess(
HPRCX hprc,
BOOL fKillRoot
)
{
HPRCX chp;
HPRCX * pphp;
PBREAKPOINT pbp;
PBREAKPOINT pbpT;
int iDll;
EnterCriticalSection(&csThreadProcList);
pphp = &prcList->next;
chp = *pphp;
while (chp) {
if (chp != hprc) {
pphp = &chp->next;
} else {
#ifndef KERNEL
if (chp->rwHand != (HANDLE)INVALID && chp->CloseProcessHandle) {
CloseHandle(chp->rwHand);
chp->rwHand = (HANDLE)INVALID;
}
#endif
RemoveExceptionList(chp);
for (pbp = BPNextHprcPbp(hprc, NULL); pbp; pbp = pbpT) {
pbpT = BPNextHprcPbp(hprc, pbp);
RemoveBP(pbp);
}
for (iDll = 0; iDll < chp->cDllList; iDll++) {
DestroyDllLoadItem(&chp->rgDllList[iDll]);
}
free(chp->rgDllList);
if (!fKillRoot && (chp->pstate & ps_root)) {
chp->pid = (PID)-1;
chp->pstate = ps_root | ps_destroyed;
ResetEvent(chp->hExitEvent);
pphp = &chp->next;
} else {
CloseHandle(chp->hExitEvent);
*pphp = chp->next;
free(chp);
}
}
chp = *pphp;
}
/*
* special case:
* if everything has been deleted except for the "sticky"
* root process, delete it now, and set fUseRoot.
* The hpid remains the same. If that changes, the EM needs
* to send a DestroyPid/CreatePid to change it here.
*/
if (prcList->next
&& prcList->next->next == NULL
&& prcList->next->pstate == (ps_root | ps_destroyed)) {
CloseHandle(prcList->next->hExitEvent);
free(prcList->next);
prcList->next = NULL;
fUseRoot = TRUE;
}
LeaveCriticalSection(&csThreadProcList);
return xosdNone;
} /* FreeProcess() */
XOSD
HandleWatchpoints(
HPRCX hprcx,
BOOL fSet,
LPBPIS lpbpis,
LPDWORD lpdwNotification
)
{
BOOL fRet;
ADDR addr = {0};
HTHDX hthdx;
XOSD xosd = xosdNone;
PBREAKPOINT pbp;
HANDLE hWalk;
hthdx = !lpbpis->fOneThd ? 0:
HTHDXFromHPIDHTID(hprcx->hpid, lpbpis->htid);
switch ( lpbpis->bptp ) {
case bptpDataR:
case bptpDataW:
case bptpDataC:
case bptpDataExec:
if (lpbpis->data.cb != 0) {
addr = lpbpis->data.addr;
fRet = ADDR_IS_FLAT(addr) ||
TranslateAddress(hprcx, hthdx, &addr, TRUE);
assert(fRet);
if (!fRet) {
xosd = xosdBadAddress;
break;
}
}
if (fSet) {
hWalk = SetWalk(hprcx,
hthdx,
GetAddrOff(addr),
lpbpis->data.cb,
lpbpis->bptp );
if (!hWalk) {
xosd = xosdUnknown;
} else {
pbp = GetNewBp(hprcx,
hthdx,
lpbpis->bptp,
lpbpis->bpns,
NULL,
NULL,
NULL);
assert(pbp);
pbp->hWalk = hWalk;
AddBpToList(pbp);
*lpdwNotification = (DWORD)pbp;
}
} else {
assert((LPVOID)*lpdwNotification);
pbp = (PBREAKPOINT)(*lpdwNotification);
assert(pbp->hWalk);
if (RemoveWalk(pbp->hWalk)) {
RemoveBP((PBREAKPOINT)*lpdwNotification);
} else {
xosd = xosdUnknown;
}
}
break;
case bptpRange:
#if 0
addr = lpbpis->rng.addr;
fRet = ADDR_IS_FLAT(addr) ||
TranslateAddress(hprcx, hthdx, &addr, TRUE);
assert(fRet);
if (!fRet) {
xosd = xosdBadAddress;
} else {
if (fSet) {
if (!SetWalkRange( hprcx, hthdx, GetAddrOff(addr),
GetAddrOff(addr)+lpbpis->rng.cb)) {
xosd = xosdUnknown;
}
} else {
if ( !RemoveWalkRange( hprcx, hthdx, GetAddrOff(addr),
GetAddrOff(addr)+lpbpis->rng.cb)) {
xosd = xosdUnknown;
}
}
}
break;
#endif
case bptpRegC:
case bptpRegR:
case bptpRegW:
default:
xosd = xosdUnsupported;
break;
}
return xosd;
}
XOSD
HandleBreakpoints(
HPRCX hprcx,
BOOL fSet,
LPBPIS lpbpis,
LPDWORD lpdwNotification
)
{
LPADDR lpaddr;
HTHDX hthdx;
BREAKPOINT *bp;
XOSD xosd = xosdNone;
switch (lpbpis->bptp) {
case bptpExec:
lpaddr = &lpbpis->exec.addr;
break;
case bptpMessage:
lpaddr = &lpbpis->msg.addr;
break;
case bptpMClass:
lpaddr = &lpbpis->mcls.addr;
break;
}
if (fSet) {
DPRINT(5, ("Set a breakpoint: %d @%08x:%04x:%08x",
ADDR_IS_FLAT(*lpaddr), lpaddr->emi,
lpaddr->addr.seg, lpaddr->addr.off));
hthdx = lpbpis->fOneThd? 0 :
HTHDXFromHPIDHTID(hprcx->hpid, lpbpis->htid);
bp = SetBP(hprcx, hthdx, lpbpis->bptp, lpbpis->bpns, lpaddr, 0);
if (bp == NULL) {
xosd = xosdUnknown;
} else {
*lpdwNotification = (DWORD)bp;
}
} else {
DEBUG_PRINT("Clear a breakpoint");
hthdx = lpbpis->fOneThd? 0 :
HTHDXFromHPIDHTID(hprcx->hpid, lpbpis->htid);
bp = FindBP(hprcx, hthdx, lpbpis->bptp, lpbpis->bpns, lpaddr, TRUE);
if (bp != NULL) {
assert((DWORD)bp == *lpdwNotification);
RemoveBP(bp);
} else if ( (hprcx->pstate & (ps_destroyed | ps_killed)) == 0) {
// Don't fail if this process is already trashed.
xosd = xosdUnknown;
}
}
return xosd;
}
VOID
ProcessBreakpointCmd(
HPRCX hprcx,
HTHDX hthdx,
LPDBB lpdbb
)
{
XOSD xosd;
XOSD * lpxosd;
LPDWORD lpdwMessage;
LPDWORD lpdwNotification;
LPBPS lpbps = (LPBPS)lpdbb->rgbVar;
LPBPIS lpbpis;
UINT i;
DWORD SizeofBps = SizeofBPS(lpbps);
if (!lpbps->cbpis) {
// enable or disable all extant bps.
// is this used?
assert(0 && "clear/set all BPs not implemented in DM");
xosd = xosdUnsupported;
Reply(0, &xosd, lpdbb->hpid);
return;
}
#ifdef KERNEL
if (!ApiIsAllowed) {
xosd = xosdUnknown;
Reply(0, &xosd, lpdbb->hpid);
return;
}
#endif
lpdwMessage = DwMessage(lpbps);
lpxosd = RgXosd(lpbps);
lpdwNotification = DwNotification(lpbps);
lpbpis = RgBpis(lpbps);
// walk the list of breakpoint commands
for (i = 0; i < lpbps->cbpis; i++) {
switch( lpbpis[i].bptp ) {
case bptpDataC:
case bptpDataR:
case bptpDataW:
case bptpDataExec:
case bptpRegC:
case bptpRegR:
case bptpRegW:
//
// dispatch to watchpoint handler
//
lpxosd[i] = HandleWatchpoints(hprcx, lpbps->fSet, &lpbpis[i],
&lpdwNotification[i]);
break;
case bptpMessage:
case bptpMClass:
//
// handle as address BP - let debugger handle the details
//
case bptpExec:
lpxosd[i] = HandleBreakpoints(hprcx, lpbps->fSet, &lpbpis[i],
&lpdwNotification[i]);
break;
case bptpInt:
case bptpRange:
// ???
assert(0 && "don't know what these are supposed to do");
break;
}
}
// send whole structure back to EM
LpDmMsg->xosdRet = xosdNone;
memcpy(LpDmMsg->rgb, lpbps, SizeofBps);
Reply(SizeofBps, LpDmMsg, lpdbb->hpid);
}
VOID
ProcessReadMemoryCmd(
HPRCX hprc,
HTHDX hthd,
LPDBB lpdbb
)
/*++
Routine Description:
This function is called in response to a request from the EM to read
the debuggees memory. It will take care of any address translations
which need to be done and request the read operation from the OS.
Arguments:
hprc - Supplies the handle to the process descriptor
hthd - Supplies the handle to the thread descriptor
lpdbb - Supplies the request packet.
Return Value:
None.
--*/
{
LPRWP lprwp = (LPRWP) lpdbb->rgbVar;
DWORD cb = (DWORD) lprwp->cb;
LPDM_MSG lpm = (LPDM_MSG)malloc( cb + sizeof(DWORD) + FIELD_OFFSET(DM_MSG, rgb));
char * buffer = lpm->rgb + sizeof(DWORD);
DWORD length;
DPRINT(5, ("ProcessReadMemoryCmd : %x %d:%04x:%08x %d\n", hprc,
lprwp->addr.emi, lprwp->addr.addr.seg,
lprwp->addr.addr.off, cb));
if (AddrReadMemory(hprc, hthd, &(lprwp->addr), buffer, cb, &length) == 0) {
lpm->xosdRet = xosdUnknown;
Reply(0, lpm, lpdbb->hpid);
} else {
lpm->xosdRet = xosdNone;
*((DWORD *) (lpm->rgb)) = length;
Reply( length + sizeof(DWORD), lpm, lpdbb->hpid);
}
free(lpm);
return;
} /* ProcessReadMemoryCmd() */
VOID
ProcessWriteMemoryCmd(
HPRCX hprc,
HTHDX hthd,
LPDBB lpdbb
)
/*++
Routine Description:
this routine is called to case a write into a debuggess memory.
Arguments:
hprc - Supplies a handle to the process to write memory in
hthd - Supplies a handle to a thread
lpdbb - points to data for the command
Return Value:
XOSD error code
--*/
{
LPRWP lprwp = (LPRWP)lpdbb->rgbVar;
DWORD cb = lprwp->cb;
char * buffer = lprwp->rgb;
HANDLE rwHand;
DWORD length;
DWORD offset;
XOSD xosd = xosdUnknown;
BP_UNIT instr;
BREAKPOINT *bp;
DEBUG_PRINT("ProcessWriteMemoryCmd called\n");
/*
* Sanitize the memory block before writing it into memory :
* ie: replace any breakpoints that might be in the block
*/
for(bp=bpList->next; bp; bp=bp->next) {
if (BPInRange(hprc, hthd, bp, &lprwp->addr, cb, &offset, &instr)) {
bp->instr1 = *((BP_UNIT *) (buffer + offset));
*((BP_UNIT *) (buffer + offset)) = BP_OPCODE;
}
}
rwHand = hprc->rwHand;
if (AddrWriteMemory(hprc, hthd, &lprwp->addr, buffer, cb, &length)) {
xosd = xosdNone;
}
Reply(0, &xosd, lpdbb->hpid);
return;
} /* ProcessWriteMemoryCmd() */
#ifndef OSDEBUG4
VOID
ProcessGetFrameContextCmd(
HPRCX hprc,
HTHDX hthd,
LPDBB lpdbb
)
/*++
Routine Description:
This routine is called in response to a request to get the full
context of a thread.
Arguments:
hprc - Supplies the handle of process for the thread
hthd - Supplies the handle of the thread
lpdbb - Supplies pointer to argument area for request
Return Value:
None.
--*/
{
PKNONVOLATILE_CONTEXT_POINTERS lpctxptrs;
LPCONTEXT lpregs;
UINT frame = *(UINT *)lpdbb->rgbVar;
Unreferenced(hprc);
DEBUG_PRINT( "ProcessGetFrameContextCmd :\n");
//
// zero out the context pointers
//
lpregs = &( (PFRAME_INFO)LpDmMsg->rgb )->frameRegs;
lpctxptrs = &( (PFRAME_INFO)LpDmMsg->rgb )->frameRegPtrs;
ClearContextPointers(lpctxptrs);
if (hthd == 0
#ifdef WIN32S
// Can't yet get thread context within
// a non-exception event.
|| ! fCanGetThreadContext
#endif
)
{
LpDmMsg->xosdRet = xosdUnknown;
Reply( 0, LpDmMsg, lpdbb->hpid );
return;
}
lpregs->ContextFlags = CONTEXT_FULL | CONTEXT_FLOATING_POINT;
if (!DbgGetThreadContext(hthd,lpregs)) {
LpDmMsg->xosdRet = xosdUnknown;
Reply( 0, LpDmMsg, lpdbb->hpid);
return;
}
//
// For each frame before the target, we do a walk-back
//
//
// ----> this MUST be fixed for user mode... for now it is broken
// ----> when i get time i'll fix it
// ----> this needs to call imagehlp just like the em, but it can't
// ----> so it has to call the em or this whole thing needs to be
// ----> moved to the em
//
#ifdef KERNEL
while (frame != 0) {
frame--;
if (!ProcessFrameStackWalkNextCmd(hprc,
hthd,
lpregs,
lpctxptrs)) {
LpDmMsg->xosdRet = xosdEndOfStack;
Reply( 0, LpDmMsg, lpdbb->hpid);
}
}
#endif
LpDmMsg->xosdRet = xosdNone;
Reply( sizeof(FRAME_INFO), LpDmMsg, lpdbb->hpid );
return;
} /* ProcessGetFrameContextCmd() */
#endif
VOID
ProcessGetContextCmd(
HPRCX hprc,
HTHDX hthd,
LPDBB lpdbb
)
/*++
Routine Description:
This routine is called in response to a request to get the full
context of a thread for a particular frame.
The current frame is 0. They count back positively; caller is 1.
Arguments:
hprc - Supplies the handle of process for the thread
hthd - Supplies the handle of the thread
lpdbb - Supplies pointer to argument area for request
Return Value:
None.
--*/
{
LPCONTEXT lpreg = (LPCONTEXT)LpDmMsg->rgb;
BOOL rval;
Unreferenced(hprc);
DEBUG_PRINT( "ProcessGetContextCmd\n");
if (hthd == 0
#ifdef WIN32S
// Can't yet get thread context within
// a non-exception event.
|| ! fCanGetThreadContext
#endif
)
{
LpDmMsg->xosdRet = xosdUnknown;
Reply( 0, LpDmMsg, lpdbb->hpid );
return;
}
lpreg->ContextFlags = CONTEXT_FULL | CONTEXT_FLOATING_POINT;
if ((hthd->tstate & ts_frozen) && hthd->pss) {
memcpy(lpreg, &hthd->pss->context, sizeof(CONTEXT));
LpDmMsg->xosdRet = xosdNone;
Reply( sizeof(CONTEXT), LpDmMsg, lpdbb->hpid );
} else if ((hthd->tstate & ts_stopped)
#ifdef KERNEL
&&(!hthd->fContextStale)
#endif
) {
memcpy(lpreg, &hthd->context, sizeof(CONTEXT));
LpDmMsg->xosdRet = xosdNone;
Reply( sizeof(CONTEXT), LpDmMsg, lpdbb->hpid );
} else if (DbgGetThreadContext(hthd,lpreg)) {
LpDmMsg->xosdRet = xosdNone;
Reply( sizeof(CONTEXT), LpDmMsg, lpdbb->hpid );
} else {
LpDmMsg->xosdRet = xosdUnknown;
Reply( 0, LpDmMsg, lpdbb->hpid );
}
return;
} /* ProcessGetContextCmd() */
VOID
ProcessSetContextCmd(
HPRCX hprc,
HTHDX hthd,
LPDBB lpdbb
)
/*++
Routine Description:
This function is used to update the register set for a thread
Arguments:
hprc - Supplies a handle to a process
hthd - Supplies the handle to the thread to be updated
lpdbb - Supplies the set of context information
Return Value:
None.
--*/
{
LPCONTEXT lpcxt = (LPCONTEXT)(lpdbb->rgbVar);
XOSD xosd = xosdNone;
ADDR addr;
Unreferenced(hprc);
DPRINT(5, ("ProcessSetContextCmd : "));
lpcxt->ContextFlags = CONTEXT_FULL | CONTEXT_FLOATING_POINT;
if ((hthd->tstate & ts_frozen) && hthd->pss) {
memcpy(&hthd->pss->context, lpcxt, sizeof(CONTEXT));
} else {
memcpy(&hthd->context, lpcxt, sizeof(CONTEXT));
if (hthd->tstate & ts_stopped) {
hthd->fContextDirty = TRUE;
/*
* If we change the program counter then we may be pointing
* at a different breakpoint. If so then setup to point
* to the new breakpoint
*/
AddrFromHthdx(&addr, hthd);
SetBPFlag(hthd, FindBP(hthd->hprc, hthd, bptpExec, (BPNS)-1, &addr, FALSE));
#ifndef KERNEL
} else if (hthd->fWowEvent) {
WOWSetThreadContext(hthd, lpcxt);
#endif
} else {
DbgSetThreadContext(hthd, lpcxt);
}
}
Reply(0, &xosd, lpdbb->hpid);
return;
} /* ProcessSetContextCmd() */
#if defined(DOLPHIN)
void
PushRunningThread(
HTHDX hthd,
HTHDX hthdFocus
)
/*++
Routine Description:
Someone's trying to step a thread that didn't stop. We must push
the stopped thread otherwise it will hit the same BP it's currently at.
Arguments:
hthd - the stopped thread
hthdFocus - the thread we want to step/go
Return Value:
none
--*/
{
BREAKPOINT* bp;
if (bp = AtBP(hthd)) {
if (bp != EMBEDDED_BP && bp->isStep) {
// Hit SS again
} else {
/*
* We are recovering from a breakpoint, so restore the
* original instruction, single step and then finally go.
*/
METHOD *ContinueSSMethod;
DEBUG_PRINT("***Recovering from a breakpoint");
ClearBPFlag(hthd);
if (bp == EMBEDDED_BP) {
IncrementIP(hthd);
} else {
ContinueSSMethod = (METHOD*)malloc(sizeof(METHOD));
ContinueSSMethod->notifyFunction = (ACVECTOR)MethodContinueSS;
ContinueSSMethod->lparam = ContinueSSMethod;
ContinueSSMethod->lparam2 = bp;
RestoreInstrBP(hthd, bp);
SingleStepEx(hthd, ContinueSSMethod, FALSE, FALSE, FALSE);
}
}
}
/* Also ensure that the focus thread has accurate context */
if (hthdFocus != NULL) {
hthdFocus->context.ContextFlags = CONTEXT_FULL | CONTEXT_FLOATING_POINT;
DmpGetThreadContext( hthdFocus, &hthdFocus->context );
}
}
#endif // DOLPHIN
VOID
ProcessSingleStepCmd(
HPRCX hprc,
HTHDX hthd,
LPDBB lpdbb
)
/*++
Routine Description:
This command is called to do a single step of the processor. If
calls are made then it will step into the command.
Arguments:
hprc - Supplies process handle
hthd - Supplies thread handle
lpdbb - Supplies information on command
Return Value:
None.
--*/
{
LPEXOP lpexop = (LPEXOP)lpdbb->rgbVar;
XOSD xosd = xosdNone;
Unreferenced( hprc );
DEBUG_PRINT("ProcessSingleStepCmd called\n");
if (hprc->pstate & ps_dead) {
hprc->pstate |= ps_dead;
/*
* The process has exited, and we have
* announced the death of all its threads (but one).
* All that remains is to clean up the remains.
*/
ProcessUnloadCmd(hprc, hthd, lpdbb);
Reply(0, &xosd, lpdbb->hpid);
AddQueue( QT_CONTINUE_DEBUG_EVENT,
hprc->pid,
hthd->tid,
DBG_CONTINUE,
0);
return;
}
#ifndef KERNEL
if (lpexop->fSetFocus) {
DmSetFocus(hprc);
}
#if defined(DOLPHIN)
if (!(hthd->tstate & ts_stopped)) {
HTHDX lastHthd = HTHDXFromPIDTID(hprc->pid, hprc->lastTidDebugEvent);
PushRunningThread(lastHthd, hthd);
}
/* Catch any exception that changes flow of control */
RegisterExpectedEvent(hthd->hprc, (HTHDX)0,
EXCEPTION_DEBUG_EVENT,
(DWORD)NO_SUBCLASS,
DONT_NOTIFY,
ActionExceptionDuringStep,
FALSE,
NULL);
#endif // DOLPHIN
#endif // !KERNEL
if (hthd->tstate & ts_stepping) {
xosd = xosdUnknown;
} else if (lpexop->fStepOver) {
StepOver(hthd, &EMNotifyMethod, FALSE, FALSE);
} else {
SingleStep(hthd, &EMNotifyMethod, FALSE, FALSE);
}
Reply(0, &xosd, lpdbb->hpid);
return;
} /* ProcessSingleStepCmd() */
VOID
ProcessRangeStepCmd(
HPRCX hprc,
HTHDX hthd,
LPDBB lpdbb
)
/*++
Routine Description:
This routine is called to start a range step. This will continue
to do steps as long as the current PC is between the starting
and ending addresses
Arguments:
hprc - Supplies the process handle to be stepped
hthd - Supples the thread handle to be stepped
lpdbb - Supples the information about the command
Return Value:
None.
--*/
{
LPRST lprst = (LPRST)lpdbb->rgbVar;
XOSD xosd = xosdNone;
DEBUG_PRINT_2("RangeStep [%08x - %08x]\n", lprst->offStart, lprst->offEnd);
if (hprc->pstate & ps_dead) {
hprc->pstate |= ps_dead;
/*
* The process has exited, and we have
* announced the death of all its threads (but one).
* All that remains is to clean up the remains.
*/
ProcessUnloadCmd(hprc, hthd, lpdbb);
Reply(0, &xosd, lpdbb->hpid);
AddQueue( QT_CONTINUE_DEBUG_EVENT,
hprc->pid,
hthd->tid,
DBG_CONTINUE,
0);
return;
}
assert(hthd);
#if !defined(KERNEL)
#if defined(DOLPHIN)
if (!(hthd->tstate & ts_stopped)) {
HTHDX lastHthd = HTHDXFromPIDTID(hprc->pid, hprc->lastTidDebugEvent);
PushRunningThread(lastHthd, hthd);
}
/* Catch any exception that changes flow of control */
RegisterExpectedEvent(hthd->hprc, (HTHDX)0,
EXCEPTION_DEBUG_EVENT,
(DWORD)NO_SUBCLASS,
DONT_NOTIFY,
ActionExceptionDuringStep,
FALSE,
NULL);
#endif // DOLPHIN
#endif // !KERNEL
RangeStep(hthd,
lprst->offStart,
lprst->offEnd,
!lprst->fInitialBP,
lprst->fStepOver
);
Reply(0, &xosd, lpdbb->hpid);
return;
} /* ProcessRangeStepCmd() */
#if 0
VOID
ProcessReturnStepCmd(
HPRCX hprc,
HTHDX hthd,
LPDBB lpdbb
)
/*++
Routine Description:
Arguments:
hprc - Supplies the process handle to be stepped
hthd - Supples the thread handle to be stepped
lpdbb - Supples the information about the command
Return Value:
None.
--*/
{
LPRTRNSTP lprtrnstp = (LPRTRNSTP)lpdbb->rgbVar;
XOSD xosd = xosdNone;
Unreferenced( hprc );
if (hprc->pstate & ps_dead) {
hprc->pstate |= ps_dead;
/*
* The process has exited, and we have
* announced the death of all its threads (but one).
* All that remains is to clean up the remains.
*/
ProcessUnloadCmd(hprc, hthd, lpdbb);
Reply(0, &xosd, lpdbb->hpid);
AddQueue( QT_CONTINUE_DEBUG_EVENT,
hprc->pid,
hthd->tid,
DBG_CONTINUE,
0);
return;
}
if (lprtrnstp->exop.fSetFocus) {
DmSetFocus(hprc);
}
#if defined(DOLPHIN)
if (!(hthd->tstate & ts_stopped)) {
HTHDX lastHthd = HTHDXFromPIDTID(hprc->pid, hprc->lastTidDebugEvent);
PushRunningThread(lastHthd, hthd);
}
/* Catch any exception that changes flow of control */
RegisterExpectedEvent(hthd->hprc, (HTHDX)0,
EXCEPTION_DEBUG_EVENT,
(DWORD)NO_SUBCLASS,
DONT_NOTIFY,
ActionExceptionDuringStep,
FALSE,
NULL);
#endif // DOLPHIN
ReturnStep(hthd, &EMNotifyMethod, FALSE, FALSE, &(lprtrnstp->addrRA), &(lprtrnstp->addrBase));
Reply(0, &xosd, lpdbb->hpid);
return;
} /* ProcessReturnStepCmd() */
#endif
VOID
ProcessContinueCmd(
HPRCX hprc,
HTHDX hthd,
LPDBB lpdbb
)
/*++
Routine Description:
This function is used to cause a process to be executed.
It is called in response to a GO command.
Arguments:
hprc - Supplies handle to process to execute
hthdd - Supplies handle to thread
lpdbb - Command buffer
Return Value:
xosd Error code
TODO:
Are there any times where we do not want to allow a GO command
to be executed.
Two other possible problems here that need to be deal with are:
1. Single thread go commands
2. The current thread not being the thread where the last debug
event occured. In this case the DoContinueDebugEvent
command SHOULD NOT WORK.
--*/
{
LPEXOP lpexop = (LPEXOP)lpdbb->rgbVar;
BREAKPOINT *bp;
XOSD xosd = xosdNone;
DEBUG_EVENT de;
HTHDXSTRUCT hthdS;
DWORD cs;
DPRINT(5, ("ProcessContinueCmd : pid=%08lx, tid=%08lx, hthd=%08lx",
hprc->pid, hthd ? hthd->tid : -1, hthd));
#ifndef KERNEL
if (lpexop->fSetFocus) {
DmSetFocus(hprc);
}
#endif
if (hprc->pstate & ps_connect) {
Reply(0, &xosd, lpdbb->hpid);
SetEvent( hEventContinue );
return;
}
//
// Don't enter during event processing, because we
// might be here before the DM has finished with the
// event we are responding to.
//
// Don't worry about new events during our processing,
// since they won't apply to this process.
//
EnterCriticalSection(&csProcessDebugEvent);
LeaveCriticalSection(&csProcessDebugEvent);
if (!hthd) {
WaitForSingleObject(hprc->hEventCreateThread, INFINITE);
hthd = HTHDXFromHPIDHTID(lpdbb->hpid, lpdbb->htid);
assert(hthd != 0);
if (!hthd) {
#ifdef OSDEBUG4
xosd = xosdBadThread;
#else
xosd = xosdInvalidThread;
#endif
Reply(0, &xosd, lpdbb->hpid);
return;
}
}
if (hprc->pstate & ps_dead) {
hprc->pstate |= ps_dead;
//
// The process has exited, and we have announced
// the death of all its threads (but one).
// All that remains is to clean up the remains.
//
AddQueue( QT_CONTINUE_DEBUG_EVENT,
hthd->hprc->pid,
hthd->tid,
DBG_CONTINUE,
0);
ProcessUnloadCmd(hprc, hthd, lpdbb);
Reply(0, &xosd, lpdbb->hpid);
return;
}
if (hthd->tstate & ts_dead) {
//
// Note that if a terminated thread is frozen
// then we do not send a destroy on it yet:
// ProcessAsyncGoCmd() deals with those cases.
//
hthdS = *hthd; // keep some info
//
// If it isn't frozen, destroy it.
//
if ( !(hthd->tstate & ts_frozen)) {
de.dwDebugEventCode = DESTROY_THREAD_DEBUG_EVENT;
NotifyEM(&de, hthd, 0, NULL);
FreeHthdx(hthd);
hprc->pstate &= ~ps_deadThread;
}
//
// if there are other dead threads (how??)
// put the deadThread bit back.
//
for (hthd = hprc->hthdChild; hthd; hthd = hthd->nextSibling) {
if (hthd->tstate & ts_dead) {
hprc->pstate |= ps_deadThread;
}
}
AddQueue( QT_CONTINUE_DEBUG_EVENT,
hthdS.hprc->pid,
hthdS.tid,
DBG_CONTINUE,
0);
Reply(0, &xosd, lpdbb->hpid);
return;
}
#if !defined(KERNEL) && !defined(WIN32S)
if (hthd->tstate & ts_frozen) {
//
// this thread is not really suspended. We need to
// continue it and cause it to be suspended before
// allowing it to actually execute the user's code.
//
if (!MakeThreadSuspendItself(hthd)) {
hthd->tstate &= ~ts_frozen;
}
}
#endif
//
// If the current thread is sitting a breakpoint then it is necessary
// to do a step over it and then try and do a go. Steps are necessary
// to ensure that the breakpoint will be restored.
//
// If the breakpoint is embedded in the code path and not one we
// set then just advance the IP past the breakpoint.
//
// NOTENOTE - jimsch - it is necessary to do a single thread step
// to insure that no other threads of execution would have
// hit the breakpoint we are disabling while the step on
// the current thead is being executed.
//
// NOTENOTE - jimsch - INTEL - two byte int 3 is not deal with
// correctly if it is embedded.
//
if (bp = AtBP(hthd)) {
//
// We are recovering from a breakpoint, so restore the
// original instruction, single step and then finally go.
//
METHOD *ContinueSSMethod;
DEBUG_PRINT("Recovering from a breakpoint\n");
if (bp == EMBEDDED_BP) {
//
// "step" past the bp and continue.
//
if (!hthd->fDontStepOff) {
ClearBPFlag(hthd);
hthd->fIsCallDone = FALSE;
IncrementIP(hthd);
}
} else {
ContinueSSMethod = (METHOD*)malloc(sizeof(METHOD));
ContinueSSMethod->notifyFunction = (ACVECTOR)MethodContinueSS;
ContinueSSMethod->lparam = ContinueSSMethod;
ContinueSSMethod->lparam2 = bp;
SingleStep(hthd, ContinueSSMethod, FALSE, FALSE);
Reply(0, &xosd, lpdbb->hpid);
return;
}
}
//
// Have the Expression BP manager know that we are continuing
//
ExprBPContinue( hprc, hthd );
//
// Do a continue debug event and continue execution
//
assert ( (hprc->pstate & ps_destroyed) == 0 );
//
// fExceptionHandled may also have been set by function eval code.
//
hthd->fExceptionHandled = hthd->fExceptionHandled ||
!lpexop->fPassException;
if ((hthd->tstate & (ts_first | ts_second)) && !hthd->fExceptionHandled) {
cs = (DWORD)DBG_EXCEPTION_NOT_HANDLED;
} else {
cs = (DWORD)DBG_CONTINUE;
}
hthd->tstate &= ~(ts_stopped|ts_first|ts_second);
hthd->tstate |= ts_running;
hthd->fExceptionHandled = FALSE;
Reply(0, &xosd, lpdbb->hpid);
#ifndef KERNEL
//
// In user mode crashdumps, this is how we emulate the
// continuation of the loader breakpoint.
//
if (CrashDump) {
SetEvent( hEventContinue );
} else
#endif
{
AddQueue( QT_CONTINUE_DEBUG_EVENT,
hthd->hprc->pid,
hthd->tid,
(DWORD)cs,
0);
}
return;
} /* ProcessContinueCmd() */
void
MethodContinueSS(
DEBUG_EVENT *pde,
HTHDX hthd,
DWORD unused,
METHOD *method
)
{
PBREAKPOINT bp = (BREAKPOINT*) method->lparam2;
Unreferenced( pde );
if (bp != EMBEDDED_BP && !bp->hWalk) {
WriteBreakPoint( bp );
}
free(method->lparam);
//
// Have the Expression BP manager know that we are continuing
//
ExprBPContinue( hthd->hprc, hthd );
AddQueue( QT_CONTINUE_DEBUG_EVENT,
hthd->hprc->pid,
hthd->tid,
DBG_CONTINUE,
0);
hthd->tstate &= ~(ts_stopped|ts_first|ts_second);
hthd->tstate |= ts_running;
return;
}
DWORD
ProcessFreezeThreadCmd(
HPRCX hprc,
HTHDX hthd,
LPDBB lpdbb
)
{
#ifdef KERNEL
XOSD xosd = xosdNone;
hthd->tstate |= ts_frozen;
Reply(0, &xosd, lpdbb->hpid);
return( xosd );
#else // KERNEL
XOSD xosd = xosdNone;
Unreferenced( hprc );
DEBUG_PRINT("ProcessFreezeThreadCmd called.\n\r");
#ifdef WIN32S
xosd = xosdUnsupported; // can't freeze thread in win32s
#else // !WIN32S
if (!(hthd->tstate & ts_frozen)) {
if (hthd->tstate & ts_stopped) {
//
// If the thread is at a debug event, don't suspend it -
// let it suspend itself later when we continue it.
//
hthd->tstate |= ts_frozen;
} else if (SuspendThread(hthd->rwHand) != -1L) {
hthd->tstate |= ts_frozen;
} else {
#ifdef OSDEBUG4
xosd = xosdBadThread;
#else
xosd = xosdInvalidThread;
#endif // OSDEBUG4
}
}
#endif // WIN32S
Reply(0, &xosd, lpdbb->hpid);
return( xosd );
#endif // KERNEL
}
#ifdef WIN32S // {
#define EXCEPTION_ACCESS_VIOLATION STATUS_ACCESS_VIOLATION
#define EXCEPTION_DATATYPE_MISALIGNMENT STATUS_DATATYPE_MISALIGNMENT
#define EXCEPTION_BREAKPOINT STATUS_BREAKPOINT
#define EXCEPTION_SINGLE_STEP STATUS_SINGLE_STEP
#define EXCEPTION_ARRAY_BOUNDS_EXCEEDED STATUS_ARRAY_BOUNDS_EXCEEDED
#define EXCEPTION_FLT_DENORMAL_OPERAND STATUS_FLOAT_DENORMAL_OPERAND
#define EXCEPTION_FLT_DIVIDE_BY_ZERO STATUS_FLOAT_DIVIDE_BY_ZERO
#define EXCEPTION_FLT_INEXACT_RESULT STATUS_FLOAT_INEXACT_RESULT
#define EXCEPTION_FLT_INVALID_OPERATION STATUS_FLOAT_INVALID_OPERATION
#define EXCEPTION_FLT_OVERFLOW STATUS_FLOAT_OVERFLOW
#define EXCEPTION_FLT_STACK_CHECK STATUS_FLOAT_STACK_CHECK
#define EXCEPTION_FLT_UNDERFLOW STATUS_FLOAT_UNDERFLOW
#define EXCEPTION_INT_DIVIDE_BY_ZERO STATUS_INTEGER_DIVIDE_BY_ZERO
#define EXCEPTION_INT_OVERFLOW STATUS_INTEGER_OVERFLOW
#define EXCEPTION_PRIV_INSTRUCTION STATUS_PRIVILEGED_INSTRUCTION
#define EXCEPTION_IN_PAGE_ERROR STATUS_IN_PAGE_ERROR
#endif // }
#define efdDefault efdStop
EXCEPTION_DESCRIPTION ExceptionList[] = {
#ifndef WIN32S // WIN32S can't get these
// DBG_CONTROL_C and DBG_CONTROL_BREAK are *only*
// raised if the app is being debugged. The system
// remotely creates a thread in the debuggee and then
// raises one of these exceptions; the debugger must
// respond to the first-chance exception if it wants
// to trap it at all, because it will never see a
// last-chance notification.
{(DWORD)DBG_CONTROL_C, efdStop, "Control-C"},
{(DWORD)DBG_CONTROL_BREAK, efdStop, "Control-Break"},
#endif
{(DWORD)EXCEPTION_DATATYPE_MISALIGNMENT, efdDefault, "Datatype Misalignment"},
{(DWORD)EXCEPTION_ACCESS_VIOLATION, efdDefault, "Access Violation"},
{(DWORD)EXCEPTION_IN_PAGE_ERROR, efdDefault, "In Page Error"},
{(DWORD)STATUS_ILLEGAL_INSTRUCTION, efdDefault, "Illegal Instruction"},
{(DWORD)EXCEPTION_ARRAY_BOUNDS_EXCEEDED, efdDefault, "Array Bounds Exceeded"},
// Floating point exceptions will only be raised if
// the user calls _controlfp() to turn them on.
{(DWORD)EXCEPTION_FLT_DENORMAL_OPERAND, efdDefault, "Float Denormal Operand"},
{(DWORD)EXCEPTION_FLT_DIVIDE_BY_ZERO, efdDefault, "Float Divide by Zero"},
{(DWORD)EXCEPTION_FLT_INEXACT_RESULT, efdDefault, "Float Inexact Result"},
{(DWORD)EXCEPTION_FLT_INVALID_OPERATION, efdDefault, "Float Invalid Operation"},
{(DWORD)EXCEPTION_FLT_OVERFLOW, efdDefault, "Float Overflow"},
{(DWORD)EXCEPTION_FLT_STACK_CHECK, efdDefault, "Float Stack Check"},
{(DWORD)EXCEPTION_FLT_UNDERFLOW, efdDefault, "Float Underflow"},
// STATUS_NO_MEMORY can be raised by HeapAlloc and
// HeapRealloc.
{(DWORD)STATUS_NO_MEMORY, efdDefault, "No Memory"},
// STATUS_NONCONTINUABLE_EXCEPTION is raised if a
// noncontinuable exception happens and an exception
// filter return -1, meaning to resume execution.
{(DWORD)STATUS_NONCONTINUABLE_EXCEPTION, efdDefault, "Noncontinuable Exception"},
// STATUS_INVALID_DISPOSITION means an NT exception
// filter (which is slightly different from an MS C
// exception filter) returned some value other than
// 0 or 1 to the system.
{(DWORD)STATUS_INVALID_DISPOSITION, efdDefault, "Invalid Disposition"},
{(DWORD)EXCEPTION_INT_DIVIDE_BY_ZERO, efdDefault, "Integer Divide by Zero"},
{(DWORD)EXCEPTION_INT_OVERFLOW, efdDefault, "Integer Overflow"},
{(DWORD)EXCEPTION_PRIV_INSTRUCTION, efdDefault, "Privileged Instruction"},
{(DWORD)STATUS_STACK_OVERFLOW, efdDefault, "Stack Overflow"},
{(DWORD)STATUS_DLL_NOT_FOUND, efdDefault, "DLL Not Found"},
{(DWORD)STATUS_DLL_INIT_FAILED, efdDefault, "DLL Initialization Failed"},
{(DWORD)(0xE0000000 | 'msc'), efdNotify, "Microsoft C++ Exception"},
{(DWORD)RPC_S_SERVER_UNAVAILABLE, efdNotify, "RPC Server Unavailable"},
{(DWORD)RPC_S_SERVER_TOO_BUSY, efdNotify, "RPC Server Busy"},
{(DWORD)RPC_S_OUT_OF_RESOURCES, efdNotify, "RPC Out Of Resources"},
};
#define SIZEOFELIST ( sizeof(ExceptionList) / sizeof(ExceptionList[0]) )
void
ProcessGetExceptionState(
HPRCX hprc,
HTHDX hthd,
LPDBB lpdbb
)
/*++
Routine Description:
This function is used to query the dm about exception handling.
Arguments:
hprc - Supplies process handle
hthd - Supplies thread handle
lpdbb - Supplies info about the command
Return Value:
None.
--*/
{
LPEXCMD lpexcmd = (LPEXCMD)lpdbb->rgbVar;
LPEXCEPTION_DESCRIPTION lpexdesc = (LPEXCEPTION_DESCRIPTION)LpDmMsg->rgb;
EXCEPTION_LIST *eList;
XOSD xosd = xosdNone;
int i = 0;
DWORD val = 1;
Unreferenced (hthd);
DEBUG_PRINT("ProcessGetExceptionStateCmd");
if (!hprc) {
xosd = xosdUnknown;
Reply(0, &xosd, lpdbb->hpid);
return;
}
switch( lpexcmd->exc ) {
case exfFirst:
if (!hprc || !hprc->exceptionList) {
*lpexdesc = ExceptionList[0];
} else {
*lpexdesc = hprc->exceptionList->excp;
}
break;
case exfNext:
xosd = xosdEndOfStack;
if (hprc && hprc->exceptionList) {
for (eList=hprc->exceptionList; eList; eList=eList->next) {
if (eList->excp.dwExceptionCode ==
lpexdesc->dwExceptionCode) {
eList = eList->next;
if (eList) {
*lpexdesc = eList->excp;
xosd = xosdNone;
} else {
lpexdesc->dwExceptionCode = 0;
}
break;
}
}
} else {
for (i = 0; i < SIZEOFELIST; i++) {
if (ExceptionList[i].dwExceptionCode ==
lpexdesc->dwExceptionCode) {
if (i+1 < SIZEOFELIST) {
*lpexdesc = ExceptionList[i+1];
xosd = xosdNone;
} else {
lpexdesc->dwExceptionCode = 0;
}
break;
}
}
}
break;
case exfSpecified:
xosd = xosdEndOfStack;
if (hprc && hprc->exceptionList) {
for (eList = hprc->exceptionList; eList; eList = eList->next) {
if (eList->excp.dwExceptionCode ==
lpexdesc->dwExceptionCode) {
*lpexdesc = eList->excp;
xosd = xosdNone;
break;
}
}
} else {
for (i = 0; i < SIZEOFELIST; i++) {
if (ExceptionList[i].dwExceptionCode ==
lpexdesc->dwExceptionCode) {
*lpexdesc = ExceptionList[i+1];
xosd = xosdNone;
break;
}
}
}
break;
default:
assert(!"Invalid exf to ProcessGetExceptionState");
xosd = xosdUnknown;
break;
}
LpDmMsg->xosdRet = xosd;
Reply(sizeof(EXCEPTION_DESCRIPTION), LpDmMsg, lpdbb->hpid);
return;
}
VOID
ProcessSetExceptionState(
HPRCX hprc,
HTHDX hthd,
LPDBB lpdbb
)
/*++
Routine Description:
This function is used to change how the debugger will handle exceptions.
Arguments:
hprc - Supplies process handle
hthd - Supplies thread handle
lpdbb - Supplies info about the command
Return Value:
None.
--*/
{
LPEXCEPTION_DESCRIPTION lpexdesc = (LPEXCEPTION_DESCRIPTION)lpdbb->rgbVar;
EXCEPTION_LIST *eList;
XOSD xosd = xosdNone;
Unreferenced (hthd);
DEBUG_PRINT("ProcessSetExceptionStateCmd");
if (!hprc) {
WaitForSingleObject(hEventCreateProcess, INFINITE);
hprc = HPRCFromHPID(lpdbb->hpid);
if (!hprc) {
xosd = xosdUnknown;
Reply(0, &xosd, lpdbb->hpid);
return;
}
}
for (eList=hprc->exceptionList; eList; eList=eList->next) {
if (eList->excp.dwExceptionCode==lpexdesc->dwExceptionCode) {
break;
}
}
if (eList) {
// update it:
eList->excp = *lpexdesc;
} else {
// add it:
InsertException(&(hprc->exceptionList), lpexdesc);
}
Reply(0, &xosd, lpdbb->hpid);
return;
}
EXCEPTION_FILTER_DEFAULT
ExceptionAction(
HPRCX hprc,
DWORD dwExceptionCode
)
{
EXCEPTION_LIST *eList;
for (eList=hprc->exceptionList; eList; eList=eList->next) {
if (eList->excp.dwExceptionCode==dwExceptionCode ) {
break;
}
}
if (eList != NULL) {
return eList->excp.efd;
} else {
return efdDefault;
}
}
void
RemoveExceptionList(
HPRCX hprc
)
{
EXCEPTION_LIST *el, *elt;
for(el = hprc->exceptionList; el; el = elt) {
elt = el->next;
free(el);
}
hprc->exceptionList = NULL;
}
EXCEPTION_LIST *
InsertException(
EXCEPTION_LIST ** ppeList,
LPEXCEPTION_DESCRIPTION lpexc
)
{
LPEXCEPTION_LIST pnew;
while ((*ppeList) &&
(*ppeList)->excp.dwExceptionCode < lpexc->dwExceptionCode) {
ppeList = &((*ppeList)->next);
}
pnew = (LPEXCEPTION_LIST)malloc(sizeof(EXCEPTION_LIST));
pnew->next = *ppeList;
*ppeList = pnew;
pnew->excp = *lpexc;
return pnew;
}
void
InitExceptionList(
HPRCX hprc
)
{
int i;
for (i = 0; i < SIZEOFELIST; i++) {
InsertException(&(hprc->exceptionList), ExceptionList + i);
}
}
VOID
ProcessIoctlCmd(
HPRCX hprc,
HTHDX hthd,
LPDBB lpdbb
)
/*++
Routine Description:
This function is called in response to an ioctl command from the
shell. It is used as a catch all to get and set strange information
which is not covered else where. The set of ioctls is OS and
implemenation dependent.
Arguments:
hprc - Supplies a process handle
hthd - Supplies a thread handle
lpdbb - Supplies the command information packet
Return Value:
None.
--*/
{
LPIOL lpiol = (LPIOL)lpdbb->rgbVar;
switch( lpiol->wFunction ) {
case ioctlGetProcessHandle:
LpDmMsg->xosdRet = xosdNone;
*((HANDLE *)LpDmMsg->rgb) = hprc->rwHand;
Reply( sizeof(HANDLE), LpDmMsg, lpdbb->hpid );
return;
case ioctlGetThreadHandle:
LpDmMsg->xosdRet = xosdNone;
*((HANDLE *)LpDmMsg->rgb) = hthd->rwHand;
Reply( sizeof(HANDLE), LpDmMsg, lpdbb->hpid );
return;
case ioctlGeneric:
ProcessIoctlGenericCmd( hprc, hthd, lpdbb );
return;
case ioctlCustomCommand:
ProcessIoctlCustomCmd( hprc, hthd, lpdbb );
return;
default:
LpDmMsg->xosdRet = xosdUnsupported;
Reply(0, LpDmMsg, lpdbb->hpid);
return;
}
return;
} /* ProcessIoctlCmd() */
VOID
ProcessSetPathCmd(
HPRCX hprc,
HTHDX hthd,
LPDBB lpdbb
)
/*++
Routine Description:
Sets the search path;
Arguments:
hprc -
hthd -
lpdbb -
Return Value:
None.
--*/
{
SETPTH *SetPath = (SETPTH *)lpdbb->rgbVar;
if ( SetPath->Set ) {
SearchPathSet = TRUE;
if ( SetPath->Path[0] ) {
strcpy(SearchPathString, SetPath->Path );
} else {
SearchPathString[0] = '\0';
}
} else {
SearchPathSet = FALSE;
SearchPathString[0] = '\0';
}
LpDmMsg->xosdRet = xosdNone;
Reply(0, LpDmMsg, lpdbb->hpid);
}