summaryrefslogtreecommitdiffstats
path: root/private/windbg/newdm/user
diff options
context:
space:
mode:
authorAdam <you@example.com>2020-05-17 05:51:50 +0200
committerAdam <you@example.com>2020-05-17 05:51:50 +0200
commite611b132f9b8abe35b362e5870b74bce94a1e58e (patch)
treea5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/windbg/newdm/user
downloadNT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip
Diffstat (limited to 'private/windbg/newdm/user')
-rw-r--r--private/windbg/newdm/user/dm.def7
-rw-r--r--private/windbg/newdm/user/dm.rc14
-rw-r--r--private/windbg/newdm/user/makefile6
-rw-r--r--private/windbg/newdm/user/makefile.inc23
-rw-r--r--private/windbg/newdm/user/precomp.h81
-rw-r--r--private/windbg/newdm/user/process.c335
-rw-r--r--private/windbg/newdm/user/sources89
-rw-r--r--private/windbg/newdm/user/userapi.c2041
-rw-r--r--private/windbg/newdm/user/wow.c1175
9 files changed, 3771 insertions, 0 deletions
diff --git a/private/windbg/newdm/user/dm.def b/private/windbg/newdm/user/dm.def
new file mode 100644
index 000000000..a46fad329
--- /dev/null
+++ b/private/windbg/newdm/user/dm.def
@@ -0,0 +1,7 @@
+LIBRARY dm
+
+EXPORTS
+ DmDllInit PRIVATE
+ DMInit PRIVATE
+ DMFunc PRIVATE
+ DBGVersionCheck PRIVATE
diff --git a/private/windbg/newdm/user/dm.rc b/private/windbg/newdm/user/dm.rc
new file mode 100644
index 000000000..8e2f96f6a
--- /dev/null
+++ b/private/windbg/newdm/user/dm.rc
@@ -0,0 +1,14 @@
+//
+// Adapted from OAK\BIN\VERRC.TPL
+//
+#include <windows.h>
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DLL
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "Debuggee Module for WinDbg"
+#define VER_INTERNALNAME_STR "dm.dll\0"
+#define VER_ORIGINALFILENAME_STR "dm.dll\0"
+
+#include <common.ver>
+ \ No newline at end of file
diff --git a/private/windbg/newdm/user/makefile b/private/windbg/newdm/user/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/windbg/newdm/user/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/windbg/newdm/user/makefile.inc b/private/windbg/newdm/user/makefile.inc
new file mode 100644
index 000000000..e2cfd4e35
--- /dev/null
+++ b/private/windbg/newdm/user/makefile.inc
@@ -0,0 +1,23 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ makefile.inc
+
+Abstract:
+
+ This file tells nmake the correct dependency relationships
+ for objects created from c files in this directory which are
+ wrappers for c files in another directory.
+
+
+Author:
+
+ Kent Forschmiedt
+
+
+!ENDIF
+
+obj\i386\d3dm.obj: ..\..\em\p_i386\d3.c
diff --git a/private/windbg/newdm/user/precomp.h b/private/windbg/newdm/user/precomp.h
new file mode 100644
index 000000000..7fc930840
--- /dev/null
+++ b/private/windbg/newdm/user/precomp.h
@@ -0,0 +1,81 @@
+/*--
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ precomp.h
+
+Abstract:
+
+ Header file that is pre-compiled into a .pch file
+
+Author:
+
+ Wesley Witt (wesw) 21-Sep-1993
+
+Environment:
+
+ Win32, User Mode
+
+--*/
+
+#include <nt.h>
+#include <ntrtl.h>
+#include <nturtl.h>
+#include <ntdbg.h>
+#include <windows.h>
+#include <stdlib.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <memory.h>
+#include <process.h>
+#include <string.h>
+#include <malloc.h>
+
+#if defined(TARGET_i386) && !defined(WIN32S)
+#include <vdmdbg.h>
+#endif
+
+#if defined(TARGET_ALPHA)
+#include <alphaops.h>
+#include "ctxptrs.h"
+#endif
+
+#if defined(TARGET_MIPS)
+#include <mipsinst.h>
+#endif
+
+#if defined(TARGET_PPC)
+#include <ppcinst.h>
+#endif
+
+#ifdef OSDEBUG4
+
+#include "od.h"
+#include "odp.h"
+#include "emdm.h"
+#include "win32dm.h"
+
+#else // OSDEBUG4
+
+#include "defs.h"
+#include "types.h"
+#include "cvtypes.hxx"
+#include "od.h"
+#include "emdm.h"
+#include "ll.h"
+#include "tl.h"
+#include "shapi.hxx"
+
+#endif // OSDEBUG4
+
+#include "heap.h"
+
+#include "dm.h"
+#include "list.h"
+#include "bp.h"
+#include "funccall.h"
+#include "debug.h"
+#include "dbgver.h"
+
diff --git a/private/windbg/newdm/user/process.c b/private/windbg/newdm/user/process.c
new file mode 100644
index 000000000..9c010eee9
--- /dev/null
+++ b/private/windbg/newdm/user/process.c
@@ -0,0 +1,335 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ process.c
+
+Abstract:
+
+ This code provides access to the task list.
+
+Author:
+
+ Wesley Witt (wesw) 16-June-1993
+
+Environment:
+
+ User Mode
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+#ifndef WIN32S
+
+#include <winperf.h>
+
+
+
+//
+// defines
+//
+#define INITIAL_SIZE 51200
+#define EXTEND_SIZE 25600
+#define REGKEY_PERF "software\\microsoft\\windows nt\\currentversion\\perflib"
+#define REGSUBKEY_COUNTERS "Counters"
+#define PROCESS_COUNTER "process"
+#define PROCESSID_COUNTER "id process"
+#define UNKNOWN_TASK "unknown"
+
+
+
+VOID
+GetTaskList(
+ PTASK_LIST pTask,
+ DWORD dwNumTasks
+ )
+
+/*++
+
+Routine Description:
+
+ Provides an API for getting a list of tasks running at the time of the
+ API call. This function uses the registry performance data to get the
+ task list and is therefor straight WIN32 calls that anyone can call.
+
+Arguments:
+
+ ldwNumTasks - pointer to a dword that will be set to the
+ number of tasks returned.
+
+Return Value:
+
+ PTASK_LIST - pointer to an array of TASK_LIST records.
+
+--*/
+
+{
+ DWORD rc;
+ HKEY hKeyNames = NULL;
+ DWORD dwType;
+ DWORD dwSize;
+ LPBYTE buf = NULL;
+ CHAR szSubKey[1024];
+ LANGID lid;
+ LPSTR p;
+ LPSTR p2;
+ PPERF_DATA_BLOCK pPerf;
+ PPERF_OBJECT_TYPE pObj;
+ PPERF_INSTANCE_DEFINITION pInst;
+ PPERF_COUNTER_BLOCK pCounter;
+ PPERF_COUNTER_DEFINITION pCounterDef;
+ DWORD i;
+ DWORD dwProcessIdTitle;
+ DWORD dwProcessIdCounter;
+ CHAR szProcessName[MAX_PATH];
+ DWORD dwLimit = dwNumTasks - 1;
+ DWORD ThisPid = GetCurrentProcessId();
+
+
+
+ //
+ // Look for the list of counters. Always use the neutral
+ // English version, regardless of the local language. We
+ // are looking for some particular keys, and we are always
+ // going to do our looking in English. We are not going
+ // to show the user the counter names, so there is no need
+ // to go find the corresponding name in the local language.
+ //
+ lid = MAKELANGID( LANG_ENGLISH, SUBLANG_NEUTRAL );
+ sprintf( szSubKey, "%s\\%03x", REGKEY_PERF, lid );
+ rc = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
+ szSubKey,
+ 0,
+ KEY_READ,
+ &hKeyNames
+ );
+ if (rc != ERROR_SUCCESS) {
+ goto exit;
+ }
+
+ //
+ // get the buffer size for the counter names
+ //
+ rc = RegQueryValueEx( hKeyNames,
+ REGSUBKEY_COUNTERS,
+ NULL,
+ &dwType,
+ NULL,
+ &dwSize
+ );
+
+ if (rc != ERROR_SUCCESS) {
+ goto exit;
+ }
+
+ //
+ // allocate the counter names buffer
+ //
+ buf = (LPBYTE) malloc( dwSize );
+ if (buf == NULL) {
+ goto exit;
+ }
+ memset( buf, 0, dwSize );
+
+ //
+ // read the counter names from the registry
+ //
+ rc = RegQueryValueEx( hKeyNames,
+ REGSUBKEY_COUNTERS,
+ NULL,
+ &dwType,
+ buf,
+ &dwSize
+ );
+
+ if (rc != ERROR_SUCCESS) {
+ goto exit;
+ }
+
+ //
+ // now loop thru the counter names looking for the following counters:
+ //
+ // 1. "Process" process name
+ // 2. "ID Process" process id
+ //
+ // the buffer contains multiple null terminated strings and then
+ // finally null terminated at the end. the strings are in pairs of
+ // counter number and counter name.
+ //
+
+ p = buf;
+ while (*p) {
+ if (_stricmp(p, PROCESS_COUNTER) == 0) {
+ //
+ // look backwards for the counter number
+ //
+ for( p2=p-2; isdigit(*p2); p2--) ;
+ strcpy( szSubKey, p2+1 );
+ }
+ else
+ if (_stricmp(p, PROCESSID_COUNTER) == 0) {
+ //
+ // look backwards for the counter number
+ //
+ for( p2=p-2; isdigit(*p2); p2--) ;
+ dwProcessIdTitle = atol( p2+1 );
+ }
+ //
+ // next string
+ //
+ p += (strlen(p) + 1);
+ }
+
+ //
+ // free the counter names buffer
+ //
+ free( buf );
+
+
+ //
+ // allocate the initial buffer for the performance data
+ //
+ dwSize = INITIAL_SIZE;
+ buf = malloc( dwSize );
+ if (buf == NULL) {
+ goto exit;
+ }
+ memset( buf, 0, dwSize );
+
+
+ while (TRUE) {
+
+ rc = RegQueryValueEx( HKEY_PERFORMANCE_DATA,
+ szSubKey,
+ NULL,
+ &dwType,
+ buf,
+ &dwSize
+ );
+
+ pPerf = (PPERF_DATA_BLOCK) buf;
+
+ //
+ // check for success and valid perf data block signature
+ //
+ if ((rc == ERROR_SUCCESS) &&
+ (dwSize > 0) &&
+ (pPerf)->Signature[0] == (WCHAR)'P' &&
+ (pPerf)->Signature[1] == (WCHAR)'E' &&
+ (pPerf)->Signature[2] == (WCHAR)'R' &&
+ (pPerf)->Signature[3] == (WCHAR)'F' ) {
+ break;
+ }
+
+ //
+ // if buffer is not big enough, reallocate and try again
+ //
+ if (rc == ERROR_MORE_DATA) {
+ dwSize += EXTEND_SIZE;
+ buf = realloc( buf, dwSize );
+ memset( buf, 0, dwSize );
+ }
+ else {
+ goto exit;
+ }
+ }
+
+ //
+ // set the perf_object_type pointer
+ //
+ pObj = (PPERF_OBJECT_TYPE) ((DWORD)pPerf + pPerf->HeaderLength);
+
+ //
+ // loop thru the performance counter definition records looking
+ // for the process id counter and then save its offset
+ //
+ pCounterDef = (PPERF_COUNTER_DEFINITION) ((DWORD)pObj + pObj->HeaderLength);
+ for (i=0; i<(DWORD)pObj->NumCounters; i++) {
+ if (pCounterDef->CounterNameTitleIndex == dwProcessIdTitle) {
+ dwProcessIdCounter = pCounterDef->CounterOffset;
+ break;
+ }
+ pCounterDef++;
+ }
+
+ dwNumTasks = min( dwLimit, (DWORD)pObj->NumInstances );
+
+ pInst = (PPERF_INSTANCE_DEFINITION) ((DWORD)pObj + pObj->DefinitionLength);
+
+ //
+ // loop thru the performance instance data extracting each process name
+ // and process id
+ //
+ for (i=0; i<dwNumTasks; i++) {
+ //
+ // pointer to the process name
+ //
+ p = (LPSTR) ((DWORD)pInst + pInst->NameOffset);
+
+ //
+ // convert it to ascii
+ //
+ rc = WideCharToMultiByte( CP_ACP,
+ 0,
+ (LPCWSTR)p,
+ -1,
+ szProcessName,
+ sizeof(szProcessName),
+ NULL,
+ NULL
+ );
+
+ if (!rc) {
+ //
+ // if we cant convert the string then use a bogus value
+ //
+ strcpy( pTask->ProcessName, UNKNOWN_TASK );
+ }
+
+ if (strlen(szProcessName)+4 <= sizeof(pTask->ProcessName)) {
+ strcpy( pTask->ProcessName, szProcessName );
+ strcat( pTask->ProcessName, ".exe" );
+ }
+
+ //
+ // get the process id
+ //
+ pCounter = (PPERF_COUNTER_BLOCK) ((DWORD)pInst + pInst->ByteLength);
+ pTask->dwProcessId = *((LPDWORD) ((DWORD)pCounter + dwProcessIdCounter));
+ if (pTask->dwProcessId == 0) {
+ pTask->dwProcessId = (DWORD)-2;
+ }
+ if (_stricmp(szProcessName,"csrss")==0) {
+ pTask->dwProcessId = (DWORD)-1;
+ }
+
+ //
+ // next process
+ //
+ if (pTask->dwProcessId == ThisPid) {
+ ZeroMemory( pTask, sizeof(*pTask) );
+ } else {
+ pTask++;
+ }
+ pInst = (PPERF_INSTANCE_DEFINITION) ((DWORD)pCounter + pCounter->ByteLength);
+ }
+
+exit:
+ if (buf) {
+ free( buf );
+ }
+
+ if (hKeyNames) {
+ RegCloseKey( hKeyNames );
+ RegCloseKey( HKEY_PERFORMANCE_DATA );
+ }
+
+ return;
+}
+
+#endif
diff --git a/private/windbg/newdm/user/sources b/private/windbg/newdm/user/sources
new file mode 100644
index 000000000..d3634544f
--- /dev/null
+++ b/private/windbg/newdm/user/sources
@@ -0,0 +1,89 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Jim Schaad (jimsch)
+
+!ENDIF
+
+MAJORCOMP=windbg
+MINORCOMP=dm
+
+TARGETNAME=dm
+TARGETPATH=obj
+TARGETTYPE=DYNLINK
+
+DLLENTRY=DllInit
+
+SOURCES= \
+ ..\bp.c \
+ ..\dmx32.c \
+ ..\event.c \
+ ..\funccall.c \
+ ..\procem.c \
+ ..\step.c \
+ ..\util.c \
+ ..\walk.c \
+ process.c \
+ userapi.c \
+ wow.c \
+ dm.rc
+
+i386_SOURCES= \
+ ..\i386mach.c \
+ ..\i386d3dm.c
+
+mips_SOURCES= \
+ ..\mipsmach.c
+
+ppc_SOURCES= \
+ ..\ppcmach.c
+
+alpha_SOURCES= \
+ ..\alpmach.c
+
+UMTYPE=windows
+
+!include ..\..\common.src
+
+MIPS_FLAGS=-DNO_TRACE_BIT -DTARGET_MIPS
+386_FLAGS=-DWOW -DTARGET_i386
+ALPHA_FLAGS=-DNO_TRACE_BIT -DTARGET_ALPHA
+PPC_FLAGS=-DNO_TRACE_BIT -DTARGET_PPC
+
+C_DEFINES = $(C_DEFINES) -DDWORDLONG=ULONGLONG
+
+INCLUDES=..;..\..\osdebug\include;..\..\osdebug
+
+CONDITIONAL_INCLUDES=odp.h win32dm.h
+
+TARGETLIBS= \
+ $(BASEDIR)\public\sdk\lib\*\kernel32.lib \
+ $(BASEDIR)\public\sdk\lib\*\user32.lib \
+ $(BASEDIR)\public\sdk\lib\*\vdmdbg.lib \
+ $(BASEDIR)\public\sdk\lib\*\advapi32.lib \
+ $(BASEDIR)\public\sdk\lib\*\crashlib.lib \
+!IF $(ALPHA)
+ ..\..\em\p_alpha\obj\*\emalp.lib \
+!ENDIF
+ $(MORE_LIBS)
+
+NTTARGETFILES=
+
+PRECOMPILED_INCLUDE=precomp.h
+PRECOMPILED_PCH=precomp.pch
+PRECOMPILED_OBJ=precomp.obj
diff --git a/private/windbg/newdm/user/userapi.c b/private/windbg/newdm/user/userapi.c
new file mode 100644
index 000000000..da84896e6
--- /dev/null
+++ b/private/windbg/newdm/user/userapi.c
@@ -0,0 +1,2041 @@
+#include "precomp.h"
+#pragma hdrstop
+
+#ifdef WIN32S
+extern BOOL fProcessingDebugEvent;
+extern BOOL fWaitForDebugEvent;
+extern DWORD tidExit;
+extern BOOL fExitProcessDebugEvent; // set true when the last debug event
+#endif
+
+HANDLE hEventContinue;
+extern LPDM_MSG LpDmMsg;
+extern SYSTEM_INFO SystemInfo;
+extern WT_STRUCT WtStruct; // .. for wt
+extern DEBUG_ACTIVE_STRUCT DebugActiveStruct; // ... for DebugActiveProcess()
+
+extern PKILLSTRUCT KillQueue;
+extern CRITICAL_SECTION csKillQueue;
+
+extern HTHDX thdList;
+extern HPRCX prcList;
+extern CRITICAL_SECTION csThreadProcList;
+
+extern BOOL fSmartRangeStep;
+extern HANDLE hEventNoDebuggee;
+extern HANDLE hEventRemoteQuit;
+extern BOOL fDisconnected;
+extern BOOL fUseRoot;
+extern char nameBuffer[];
+
+#if defined(TARGET_MIPS)
+MIPSCONTEXTSIZE MipsContextSize;
+#endif
+
+
+
+BOOL
+DbgWriteMemory(
+ HPRCX hprc,
+ LPVOID lpOffset,
+ LPBYTE lpb,
+ DWORD cb,
+ LPDWORD pcbWritten
+ )
+/*++
+
+Routine Description:
+
+ Write to a flat address in a process.
+
+Arguments:
+
+ hprc - Supplies the handle to the process
+
+ lpOffset - Supplies address of data in process
+
+ lpb - Supplies a pointer to the bytes to be written
+
+ cb - Supplies the count of bytes to be written
+
+ pcbWritten - Returns the number of bytes actually written
+
+Return Value:
+
+ TRUE if successful and FALSE otherwise
+
+--*/
+
+{
+ BOOL fRet;
+
+ assert(hprc->rwHand != (HANDLE)-1);
+
+ if (hprc->rwHand == (HANDLE)-1) {
+ return FALSE;
+ }
+
+ fRet = WriteProcessMemory(hprc->rwHand, lpOffset, lpb, cb, pcbWritten);
+
+#if defined(JLS_RWBP) && DBG
+ {
+ DWORD cbT;
+ LPBYTE lpbT = malloc(cb);
+
+ assert( fRet );
+ assert( *pcbWritten == cb );
+ fRet = ReadProcessMemory(hprc->rwHand, lpOffset, lpbT, cb, &cbT);
+ assert(fRet);
+ assert( cb == cbT);
+ assert(memcmp(lpbT, lpb) == 0);
+ free lpbT;
+ }
+#endif
+
+ return fRet;
+}
+
+
+BOOL
+DbgReadMemory(
+ HPRCX hprc,
+ LPVOID lpOffset,
+ LPVOID lpb,
+ DWORD cb,
+ LPDWORD lpRead
+ )
+/*++
+
+Routine Description:
+
+ Read from a flat address in a process.
+
+Arguments:
+
+ hprc - Supplies the handle to the process
+
+ lpOffset - Supplies address of data in process
+
+ lpb - Supplies a pointer to the local buffer
+
+ cb - Supplies the count of bytes to read
+
+ lpRead - Returns the number of bytes actually read
+
+Return Value:
+
+ TRUE if successful and FALSE otherwise
+
+--*/
+
+{
+#ifndef WIN32S
+ DWORD cbr;
+ if (CrashDump) {
+ cbr = DmpReadMemory( (PVOID)lpOffset, lpb, cb );
+ if (lpRead) {
+ *lpRead = cbr;
+ }
+ return (cbr > 0) || (cbr == cb);
+ }
+#endif
+
+ assert(hprc->rwHand != (HANDLE)-1);
+
+ if (hprc->rwHand == (HANDLE)-1) {
+ return FALSE;
+ }
+
+ if (ReadProcessMemory(hprc->rwHand, lpOffset, lpb, cb, lpRead)) {
+
+ return TRUE;
+
+ } else {
+
+#if DBG
+ int e = GetLastError();
+#endif
+ //
+ // Reads across page boundaries will not work if the
+ // second page is not accessible.
+ //
+#define PAGE_SIZE (SystemInfo.dwPageSize)
+#define PAGE_MASK (~(PAGE_SIZE-1))
+
+ DWORD firstsize;
+ DWORD dwRead;
+
+ firstsize = (((DWORD)lpOffset + PAGE_SIZE) & PAGE_MASK) - (DWORD)lpOffset;
+ if (cb < firstsize) {
+ firstsize = cb;
+ }
+
+ //
+ // read from the first page. If the first read fails,
+ // fail the whole thing.
+ //
+
+ if (!ReadProcessMemory(hprc->rwHand, lpOffset, lpb, firstsize,
+ lpRead)) {
+ return FALSE;
+ }
+
+ //
+ // read intermediate complete pages.
+ // if any of these reads fail, succeed with a short read.
+ //
+
+ assert(*lpRead == firstsize);
+ cb -= firstsize;
+ lpb = (LPVOID)((LPBYTE)lpb + firstsize);
+ lpOffset = (LPVOID)((LPBYTE)lpOffset + firstsize);
+
+ while (cb >= PAGE_SIZE) {
+
+ if (!ReadProcessMemory(hprc->rwHand, lpOffset, lpb, PAGE_SIZE,
+ &dwRead)) {
+ return TRUE;
+ } else {
+ assert(dwRead == PAGE_SIZE);
+ lpb = (LPVOID)((LPBYTE)lpb + PAGE_SIZE);
+ lpOffset = (LPVOID)((LPBYTE)lpOffset + PAGE_SIZE);
+ *lpRead += dwRead;
+ cb -= PAGE_SIZE;
+ }
+ }
+
+ if (cb > 0) {
+ if (ReadProcessMemory(hprc->rwHand, lpOffset, lpb, cb, &dwRead)) {
+ assert(dwRead == cb);
+ *lpRead += dwRead;
+ }
+ }
+
+ return TRUE;
+ }
+
+}
+
+BOOL
+DbgGetThreadContext(
+ HTHDX hthd,
+ PCONTEXT lpcontext
+ )
+{
+#ifndef WIN32S
+ if (CrashDump) {
+ return DmpGetContext(hthd->tid-1, lpcontext);
+ } else if (hthd->fWowEvent) {
+ return WOWGetThreadContext(hthd, lpcontext);
+ } else
+#endif
+ {
+#ifndef TARGET_MIPS
+ return GetThreadContext(hthd->rwHand, lpcontext);
+#else
+ BOOL rc;
+ DWORD Flags = lpcontext->ContextFlags;
+
+ if (MipsContextSize == Ctx32Bit) {
+ lpcontext->ContextFlags = ((lpcontext->ContextFlags & ~CONTEXT_EXTENDED_INTEGER) | CONTEXT_INTEGER);
+ }
+ rc = GetThreadContext(hthd->rwHand, lpcontext);
+ if (rc) {
+ if ((Flags & CONTEXT_EXTENDED_INTEGER) == CONTEXT_EXTENDED_INTEGER) {
+ CoerceContext32To64(lpcontext);
+ } else if ((Flags & CONTEXT_INTEGER) == CONTEXT_INTEGER) {
+ CoerceContext64To32(lpcontext);
+ }
+ }
+ return rc;
+#endif
+ }
+}
+
+BOOL
+DbgSetThreadContext(
+ HTHDX hthd,
+ PCONTEXT lpcontext
+ )
+{
+ assert(!CrashDump);
+
+#ifndef WIN32S
+ if (CrashDump) {
+ return FALSE;
+ } else if (hthd->fWowEvent) {
+ return WOWSetThreadContext(hthd, lpcontext);
+ } else
+#endif
+ {
+#ifdef TARGET_MIPS
+ CONTEXT ctx = *lpcontext;
+ lpcontext = &ctx;
+ if (MipsContextSize == Ctx32Bit) {
+ CoerceContext64To32(lpcontext);
+ } else {
+ CoerceContext32To64(lpcontext);
+ }
+#endif
+ return SetThreadContext(hthd->rwHand, lpcontext);
+ }
+}
+
+BOOL
+WriteBreakPoint(
+ IN PBREAKPOINT Breakpoint
+ )
+{
+ DWORD cb;
+ BP_UNIT opcode = BP_OPCODE;
+ BOOL r = AddrWriteMemory(Breakpoint->hprc,
+ Breakpoint->hthd,
+ &Breakpoint->addr,
+ &opcode,
+ BP_SIZE,
+ &cb);
+ return (r && (cb == BP_SIZE));
+}
+
+BOOL
+RestoreBreakPoint(
+ IN PBREAKPOINT Breakpoint
+ )
+{
+ DWORD cb;
+ BOOL r;
+
+ assert(Breakpoint->bpType == bptpExec);
+
+ r = AddrWriteMemory(Breakpoint->hprc,
+ Breakpoint->hthd,
+ &Breakpoint->addr,
+ &Breakpoint->instr1,
+ BP_SIZE,
+ &cb);
+ return (r && (cb == BP_SIZE));
+}
+
+
+
+/****************************************************************************/
+/****************************************************************************/
+#ifndef PROCESSOR_MIPS_R10000
+#define PROCESSOR_MIPS_R10000 10000
+#endif
+
+
+VOID
+GetMachineType(
+ LPPROCESSOR p
+ )
+{
+ // Look Ma, no ifdefs!!
+
+ SYSTEM_INFO SystemInfo;
+
+ GetSystemInfo(&SystemInfo);
+ switch (SystemInfo.wProcessorArchitecture) {
+
+ case PROCESSOR_ARCHITECTURE_INTEL:
+ p->Level = SystemInfo.wProcessorLevel;
+ p->Type = mptix86;
+ p->Endian = endLittle;
+ break;
+
+ case PROCESSOR_ARCHITECTURE_MIPS:
+ p->Level = SystemInfo.wProcessorLevel * 1000;
+ p->Type = mptmips;
+ p->Endian = endLittle;
+ break;
+
+ case PROCESSOR_ARCHITECTURE_ALPHA:
+ p->Level = SystemInfo.wProcessorLevel;
+ p->Type = mptdaxp;
+ p->Endian = endLittle;
+ p->Level = 21064; // BUGBUG - why?
+ break;
+
+ case PROCESSOR_ARCHITECTURE_PPC:
+ p->Level = SystemInfo.wProcessorLevel + 600; // BUGBUG - 603+
+ p->Type = mptmppc;
+ p->Endian = endLittle;
+ break;
+
+ default:
+ assert(!"Unknown target machine");
+ break;
+ }
+}
+
+
+
+HWND
+HwndFromPid (
+ PID pid
+ )
+{
+
+ HWND hwnd = GetForegroundWindow();
+ HWND hwndNext;
+
+ DPRINT(4, ( "*HwndFromPid, pid = 0x%lx\n", pid ) );
+
+ for (hwndNext = GetWindow ( hwnd, GW_HWNDFIRST );
+ hwndNext;
+ hwndNext = GetWindow ( hwndNext, GW_HWNDNEXT )) {
+
+ // what we want is windows *without* an owner, hence !GetWindow...
+ if ( !GetWindow ( hwndNext, GW_OWNER ) &&
+ IsWindowVisible ( hwndNext ) ) {
+ PID pidT;
+
+ GetWindowThreadProcessId ( hwndNext, &pidT );
+ DPRINT(4, ("\thwnd 0x%08lx owned by process 0x%lx, ",
+ hwndNext, pidT ) );
+#if DBG
+ {
+ char szWindowText[256];
+ if ( GetWindowText(hwndNext, szWindowText,
+ sizeof(szWindowText)) ) {
+ DPRINT(4, ("title = \"%s\"\n", szWindowText) );
+ } else {
+ DPRINT(4, ("title = \"<none>\"\n") );
+ }
+ }
+#endif
+ if ( pid == pidT ) {
+ // found a match, return the hwnd
+ break;
+ }
+ } // if ( !GetWindow...
+ hwndNext = GetWindow ( hwndNext, GW_HWNDNEXT );
+ } // while ( hwndNext )
+
+ return hwndNext;
+}
+
+VOID
+DmSetFocus (
+ HPRCX phprc
+ )
+{
+ PID pidGer; // debugger pid
+ PID pidCurFore; // owner of foreground window
+ HWND hwndCurFore; // current foreground window
+ HWND phprc_hwndProcess;
+ HWND hwndT;
+
+
+ // decide if we are the foreground app currently
+ pidGer = GetCurrentProcessId(); // debugger pid
+ hwndCurFore = GetForegroundWindow();
+ if ( hwndCurFore &&
+ GetWindowThreadProcessId ( hwndCurFore, &pidCurFore ) ) {
+ if ( pidCurFore != pidGer ) {
+ // foreground is not debugger, bail out
+ return;
+ }
+ }
+
+ phprc_hwndProcess = HwndFromPid ( phprc->pid );
+ if ( !phprc_hwndProcess ) {
+ // no window attached to pid; bail out
+ return;
+ }
+
+ // continuing with valid hwnd's and we have foreground window
+ assert ( phprc_hwndProcess );
+
+ // now, get the last active window in that group!
+ hwndT = GetLastActivePopup ( phprc_hwndProcess );
+
+ // NOTE: taskman has a check at this point for state disabled...
+ // don't know if I should do it either...
+ SetForegroundWindow ( hwndT );
+}
+
+
+
+/****************************************************************************/
+//
+// ContinueDebugEvent() queue.
+// We can only have one debug event pending per process, but there may be
+// one event pending for each process we are debugging.
+//
+// There are 200 entries in a static sized queue. If there are ever more
+// than 200 debug events pending, AND windbg actually handles them all in
+// less than 1/5 second, we will be in trouble. Until then, sleep soundly.
+//
+/****************************************************************************/
+typedef struct tagCQUEUE {
+ struct tagCQUEUE *next;
+ DWORD pid;
+ DWORD tid;
+ DWORD dwContinueStatus;
+} CQUEUE, *LPCQUEUE;
+
+static LPCQUEUE lpcqFirst;
+static LPCQUEUE lpcqLast;
+static LPCQUEUE lpcqFree;
+static CQUEUE cqueue[200];
+static CRITICAL_SECTION csContinueQueue;
+
+static BOOL DequeueContinueDebugEvents( void );
+
+
+/***************************************************************************/
+/***************************************************************************/
+
+
+
+VOID
+QueueContinueDebugEvent(
+ DWORD dwProcessId,
+ DWORD dwThreadId,
+ DWORD dwContinueStatus
+ )
+
+/*++
+
+Routine Description:
+
+ Queue a debug event continue for later execution.
+
+Arguments:
+
+ dwProcessId = pid to continue
+
+ dwThreadId = tid to continue
+
+ dwContinueStatus - Supplies the continue status code
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+#ifdef WIN32S
+
+ HTHDX hthd;
+
+ if (dwContinueStatus != DBG_TERMINATE_PROCESS) {
+ hthd = HTHDXFromPIDTID(dwProcessId, dwThreadId);
+ if (hthd) {
+ if (hthd->fContextDirty) {
+ /*
+ * Set the child's context
+ */
+ DPRINT(1, ("Context is dirty\n"));
+
+ DbgSetThreadContext(hthd, &hthd->context);
+
+ hthd->fContextDirty = FALSE;
+ }
+ }
+ }
+
+ DPRINT(1, ("ContinueDebugEvent(PID:%x, TID:%x, Stat:%u)\r\n",
+ dwProcessId, dwThreadId, dwContinueStatus));
+
+ ContinueDebugEvent(dwProcessId, dwThreadId, dwContinueStatus);
+ fProcessingDebugEvent = FALSE;
+ fWaitForDebugEvent = FALSE;
+
+#else
+
+ LPCQUEUE lpcq;
+
+ EnterCriticalSection(&csContinueQueue);
+
+ lpcq = lpcqFree;
+ assert(lpcq);
+
+ lpcqFree = lpcq->next;
+
+ lpcq->next = NULL;
+ if (lpcqLast) {
+ lpcqLast->next = lpcq;
+ }
+ lpcqLast = lpcq;
+
+ if (!lpcqFirst) {
+ lpcqFirst = lpcq;
+ }
+
+ lpcq->pid = dwProcessId;
+ lpcq->tid = dwThreadId;
+ lpcq->dwContinueStatus = dwContinueStatus;
+
+ LeaveCriticalSection(&csContinueQueue);
+
+#endif
+
+ return;
+} /* QueueContinueDebugEvent() */
+
+
+#ifndef WIN32S
+BOOL
+DequeueContinueDebugEvents(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Remove any pending continues from the queue and execute them.
+
+Arguments:
+
+ none
+
+Return Value:
+
+ TRUE if one or more events were continued.
+ FALSE if none were continued.
+
+--*/
+{
+ LPCQUEUE lpcq;
+ BOOL fDid = FALSE;
+ HTHDX hthd;
+
+ EnterCriticalSection(&csContinueQueue);
+
+ while ( lpcq=lpcqFirst ) {
+
+ hthd = HTHDXFromPIDTID(lpcq->pid, lpcq->tid);
+ if (hthd) {
+ if (hthd->fContextDirty) {
+ /*
+ * Set the child's context
+ */
+
+ DbgSetThreadContext(hthd, &hthd->context);
+
+ hthd->fContextDirty = FALSE;
+ }
+ hthd->fWowEvent = FALSE;
+ }
+
+ ContinueDebugEvent(lpcq->pid, lpcq->tid, lpcq->dwContinueStatus);
+
+ lpcqFirst = lpcq->next;
+ if (lpcqFirst == NULL) {
+ lpcqLast = NULL;
+ }
+
+ lpcq->next = lpcqFree;
+ lpcqFree = lpcq;
+
+ fDid = TRUE;
+ }
+
+ LeaveCriticalSection(&csContinueQueue);
+ return fDid;
+} /* DequeueContinueDebugEvents() */
+#endif // !WIN32S
+
+
+VOID
+AddQueue(
+ DWORD dwType,
+ DWORD dwProcessId,
+ DWORD dwThreadId,
+ DWORD dwData,
+ DWORD dwLen
+ )
+
+/*++
+
+Routine Description:
+
+
+
+Arguments:
+
+ dwType
+
+ dwProcessId
+
+ dwThreadId
+
+ dwData
+
+ dwLen
+
+Return Value:
+
+ none
+
+--*/
+
+{
+ switch (dwType) {
+ case QT_CONTINUE_DEBUG_EVENT:
+ case QT_TRACE_DEBUG_EVENT:
+ if (CrashDump) {
+ break;
+ }
+
+ QueueContinueDebugEvent(dwProcessId, dwThreadId, dwData);
+ break;
+
+
+ case QT_RELOAD_MODULES:
+ case QT_REBOOT:
+ case QT_CRASH:
+ case QT_RESYNC:
+ assert(!"Unsupported usermode QType in AddQueue.");
+ break;
+
+ case QT_DEBUGSTRING:
+ assert(!"Is this a bad idea?");
+ DMPrintShellMsg( "%s", (LPSTR)dwData );
+ free((LPSTR)dwData);
+ break;
+
+ }
+
+ if (dwType == QT_CONTINUE_DEBUG_EVENT) {
+ SetEvent( hEventContinue );
+ }
+
+ return;
+}
+
+BOOL
+DequeueAllEvents(
+ BOOL fForce, // force a dequeue even if the dm isn't initialized
+ BOOL fConsume // delete all events from the queue with no action
+ )
+{
+#ifdef WIN32S
+ return TRUE;
+#else
+ return DequeueContinueDebugEvents();
+#endif
+}
+
+VOID
+InitEventQueue(
+ VOID
+ )
+{
+ int n;
+ int i;
+
+ InitializeCriticalSection(&csContinueQueue);
+
+ n = sizeof(cqueue) / sizeof(CQUEUE);
+ for (i = 0; i < n-1; i++) {
+ cqueue[i].next = &cqueue[i+1];
+ }
+ cqueue[n-1].next = NULL;
+ lpcqFree = &cqueue[0];
+ lpcqFirst = NULL;
+ lpcqLast = NULL;
+}
+
+
+VOID
+ProcessQueryTlsBaseCmd(
+ HPRCX hprcx,
+ HTHDX hthdx,
+ LPDBB lpdbb
+ )
+
+/*++
+
+Routine Description:
+
+ This function is called in response to an EM request to get the base
+ of the thread local storage for a given thread and DLL.
+
+Arguments:
+
+ hprcx - Supplies a process handle
+ hthdx - Supplies a thread handle
+ lpdbb - Supplies the command information packet
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ XOSD xosd;
+ OFFSET offRgTls;
+ DWORD iTls;
+ LPADDR lpaddr = (LPADDR) LpDmMsg->rgb;
+ OFFSET offResult;
+ DWORD cb;
+ int iDll;
+ OFFSET offDll = * (OFFSET *) lpdbb->rgbVar;
+
+ /*
+ * Read number 1. Get the pointer to the Thread Local Storage array.
+ */
+
+
+ if ((DbgReadMemory(hprcx, (char *) hthdx->offTeb+0x2c,
+ &offRgTls, sizeof(OFFSET), &cb) == 0) ||
+ (cb != sizeof(OFFSET))) {
+ err:
+ xosd = xosdUnknown;
+ Reply(0, &xosd, lpdbb->hpid);
+ return;
+ }
+
+ /*
+ * Read number 2. Get the TLS index for this dll
+ */
+
+ for (iDll=0; iDll<hprcx->cDllList; iDll+=1 ) {
+ if (hprcx->rgDllList[iDll].fValidDll &&
+ (hprcx->rgDllList[iDll].offBaseOfImage == offDll)) {
+ break;
+ }
+ }
+
+ if (iDll == hprcx->cDllList) {
+ goto err;
+ }
+
+ if (!DbgReadMemory(hprcx,
+ (char *) hprcx->rgDllList[iDll].offTlsIndex,
+ &iTls,
+ sizeof(iTls),
+ &cb) ||
+ (cb != sizeof(iTls))) {
+ goto err;
+ }
+
+
+ /*
+ * Read number 3. Get the actual TLS base pointer
+ */
+
+ if ((DbgReadMemory(hprcx, (char *)offRgTls+iTls*sizeof(OFFSET),
+ &offResult, sizeof(OFFSET), &cb) == 0) ||
+ (cb != sizeof(OFFSET))) {
+ goto err;
+ }
+
+ memset(lpaddr, 0, sizeof(ADDR));
+
+ lpaddr->addr.off = offResult;
+#ifdef TARGET_i386
+ lpaddr->addr.seg = (SEGMENT) hthdx->context.SegDs;
+#else
+ lpaddr->addr.seg = 0;
+#endif
+ ADDR_IS_FLAT(*lpaddr) = TRUE;
+
+ LpDmMsg->xosdRet = xosdNone;
+ Reply( sizeof(ADDR), LpDmMsg, lpdbb->hpid );
+ return;
+} /* ProcessQueryTlsBaseCmd() */
+
+
+VOID
+ProcessQuerySelectorCmd(
+ HPRCX hprcx,
+ HTHDX hthdx,
+ LPDBB lpdbb
+ )
+/*++
+
+Routine Description:
+
+ This command is sent from the EM to fill in an LDT_ENTRY structure
+ for a given selector.
+
+Arguments:
+
+ hprcx - Supplies the handle to the process
+
+ hthdx - Supplies the handle to the thread and is optional
+
+ lpdbb - Supplies the pointer to the full query packet
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ XOSD xosd;
+
+#if defined( TARGET_i386 )
+ SEGMENT seg;
+
+ seg = *((SEGMENT *) lpdbb->rgbVar);
+
+ if (hthdx == hthdxNull) {
+ hthdx = hprcx->hthdChild;
+ }
+
+ if ((hthdx != NULL) &&
+ (GetThreadSelectorEntry(hthdx->rwHand, seg, (LDT_ENTRY *) LpDmMsg->rgb))) {
+ LpDmMsg->xosdRet = xosdNone;
+ Reply( sizeof(LDT_ENTRY), LpDmMsg, lpdbb->hpid);
+ return;
+ }
+#endif
+
+#ifdef OSDEBUG4
+ xosd = xosdInvalidParameter;
+#else
+ xosd = xosdInvalidSelector;
+#endif
+
+ Reply( sizeof(xosd), &xosd, lpdbb->hpid);
+
+ return;
+} /* ProcessQuerySelectorCmd */
+
+
+VOID
+ProcessVirtualQueryCmd(
+ HPRCX hprc,
+ LPDBB lpdbb
+ )
+{
+ XOSD xosd = xosdNone;
+ ADDR addr;
+ BOOL fRet;
+ DWORD dwSize;
+
+ if (!hprc->rwHand || hprc->rwHand == (HANDLE)(-1)) {
+#ifdef OSDEBUG4
+ xosd = xosdBadProcess;
+#else
+ xosd = xosdInvalidProc;
+#endif
+ }
+
+ addr = *(LPADDR)(lpdbb->rgbVar);
+
+ if (!ADDR_IS_FLAT(addr)) {
+ fRet = TranslateAddress(hprc, 0, &addr, TRUE);
+ assert(fRet);
+ if (!fRet) {
+ xosd = xosdBadAddress;
+ goto reply;
+ }
+ }
+
+ dwSize = VirtualQueryEx(hprc->rwHand,
+ (LPCVOID)addr.addr.off,
+ (PMEMORY_BASIC_INFORMATION)LpDmMsg->rgb,
+ sizeof(MEMORY_BASIC_INFORMATION));
+
+ if (dwSize != sizeof(MEMORY_BASIC_INFORMATION)) {
+ xosd = xosdUnknown;
+ goto reply;
+ }
+
+ reply:
+
+ LpDmMsg->xosdRet = xosd;
+ Reply( sizeof(MEMORY_BASIC_INFORMATION), LpDmMsg, lpdbb->hpid );
+
+ return;
+} /* ProcessVirtualQueryCmd */
+
+VOID
+ProcessGetDmInfoCmd(
+ HPRCX hprc,
+ LPDBB lpdbb,
+ DWORD cb
+ )
+{
+ LPDMINFO lpi = (LPDMINFO)LpDmMsg->rgb;
+
+ LpDmMsg->xosdRet = xosdNone;
+
+ lpi->fAsync = 1;
+#ifdef WIN32S
+ lpi->fHasThreads = 0;
+#else
+ lpi->fHasThreads = 1;
+#endif
+ lpi->fReturnStep = 0;
+ //lpi->fRemote = ???
+ lpi->fAsyncStop = 1;
+ lpi->fAlwaysFlat = 0;
+ lpi->fHasReload = 0;
+
+ lpi->cbSpecialRegs = 0;
+ lpi->MajorVersion = 0;
+ lpi->MinorVersion = 0;
+
+ lpi->Breakpoints = bptsExec |
+ bptsDataC |
+ bptsDataW |
+ bptsDataR |
+ bptsDataExec;
+
+ GetMachineType(&lpi->Processor);
+
+ //
+ // hack so that TL can call tlfGetVersion before
+ // reply buffer is initialized.
+ //
+ if ( cb >= (sizeof(DBB) + sizeof(DMINFO)) ) {
+ memcpy(lpdbb->rgbVar, lpi, sizeof(DMINFO));
+ }
+
+ Reply( sizeof(DMINFO), LpDmMsg, lpdbb->hpid );
+} /* ProcessGetDMInfoCmd */
+
+
+
+ActionResumeThread(
+ DEBUG_EVENT * pde,
+ HTHDX hthd,
+ DWORD unused,
+ PSUSPENDSTRUCT pss
+ )
+{
+ //
+ // This thread just hit a breakpoint after falling out of
+ // SuspendThread. Clear the BP, put the original context
+ // back and continue.
+ //
+
+ RemoveBP( pss->pbp );
+
+ hthd->context = pss->context;
+ hthd->fContextDirty = TRUE;
+ hthd->pss = NULL;
+
+ free(pss);
+
+ AddQueue( QT_CONTINUE_DEBUG_EVENT,
+ hthd->hprc->pid,
+ hthd->tid,
+ DBG_CONTINUE,
+ 0);
+ return 0;
+}
+
+
+BOOL
+MakeThreadSuspendItself(
+ HTHDX hthd
+ )
+/*++
+
+Routine Description:
+
+ Set up the thread to call SuspendThread. This relies on kernel32
+ being present in the debuggee, and the current implementation gives
+ up if the thread is in a 16 bit context.
+
+ The cpu dependent part of this is MakeThreadSuspendItselfHelper,
+ in mach.c.
+
+Arguments:
+
+ hthd - Supplies thread
+
+Return Value:
+
+ TRUE if the thread will be suspended, FALSE if not.
+
+--*/
+{
+ PSUSPENDSTRUCT pss;
+ ADDR addr;
+ HANDLE hdll;
+ FARPROC lpSuspendThread;
+
+ //
+ // the only time this should fail is when the debuggee
+ // does not use kernel32, which is rare.
+ //
+
+ if (!hthd->hprc->dwKernel32Base) {
+ DPRINT(1, ("can't suspend thread %x: Kernel32 not loaded\n",
+ (DWORD)hthd));
+ DMPrintShellMsg("*** Unable to suspend thread.\n");
+ return 0;
+ }
+
+ //
+ // Oh, yeah... don't try to do this with a 16 bit thread, either.
+ // maybe someday...
+ //
+
+ if (hthd->fWowEvent) {
+ DMPrintShellMsg("*** Can't leave 16 bit thread suspended.\n");
+ return 0;
+ }
+
+ //
+ // find the address of SuspendThread
+ //
+
+ hdll = GetModuleHandle("KERNEL32");
+ assert(hdll || !"kernel32 not found in DM!!!");
+ if (!hdll) {
+ return 0;
+ }
+
+ lpSuspendThread = GetProcAddress(hdll, "SuspendThread");
+ assert(lpSuspendThread || !"SuspendThread not found in kernel32!!!");
+ if (!lpSuspendThread) {
+ return 0;
+ }
+
+ //
+ // this is probably unneccessary, because I think kernel32
+ // may not be relocated.
+ //
+ lpSuspendThread = (FARPROC)((DWORD)lpSuspendThread - (DWORD)hdll
+ + hthd->hprc->dwKernel32Base);
+
+ pss = malloc(sizeof(*pss));
+ assert(pss || !"malloc failed in MakeThreadSuspendItself");
+ if (!pss) {
+ return 0;
+ }
+
+ //
+ // Remember the current context
+ //
+ hthd->pss = pss;
+ pss->context = hthd->context;
+
+ //
+ // set a BP on the current PC, and register a persistent
+ // expected event to catch it later.
+ //
+
+ AddrInit(&addr, 0, 0, (DWORD) PC(hthd), TRUE, TRUE, FALSE, FALSE);
+ pss->pbp = SetBP( hthd->hprc, hthd, bptpExec, bpnsStop, &addr, (HPID) INVALID);
+
+ //
+ // don't try to step off of BP.
+ //
+ pss->atBP = hthd->atBP;
+ hthd->atBP = NULL;
+
+ RegisterExpectedEvent(
+ hthd->hprc,
+ hthd,
+ BREAKPOINT_DEBUG_EVENT,
+ (DWORD)pss->pbp,
+ NULL,
+ (ACVECTOR)ActionResumeThread,
+ TRUE,
+ pss);
+
+ //
+ // do machine dependent part
+ //
+ MakeThreadSuspendItselfHelper(hthd, lpSuspendThread);
+
+ return TRUE;
+}
+
+
+
+VOID
+ProcessIoctlGenericCmd(
+ HPRCX hprc,
+ HTHDX hthd,
+ LPDBB lpdbb
+ )
+{
+ LPIOL lpiol = (LPIOL)lpdbb->rgbVar;
+ PIOCTLGENERIC pig = (PIOCTLGENERIC)lpiol->rgbVar;
+ DWORD len;
+ ADDR addr;
+
+
+ switch( pig->ioctlSubType ) {
+ case IG_TRANSLATE_ADDRESS:
+ memcpy( &addr, pig->data, sizeof(addr) );
+ if (TranslateAddress( hprc, hthd, &addr, TRUE )) {
+ memcpy( pig->data, &addr, sizeof(addr) );
+ len = sizeof(IOCTLGENERIC) + pig->length;
+ memcpy( LpDmMsg->rgb, pig, len );
+ LpDmMsg->xosdRet = xosdNone;
+ Reply( sizeof(IOCTLGENERIC)+pig->length, LpDmMsg, lpdbb->hpid );
+ } else {
+ LpDmMsg->xosdRet = xosdUnknown;
+ Reply( 0, LpDmMsg, lpdbb->hpid );
+ }
+ break;
+
+ case IG_WATCH_TIME:
+ WtRangeStep( hthd );
+ LpDmMsg->xosdRet = xosdNone;
+ Reply( 0, LpDmMsg, lpdbb->hpid );
+ break;
+
+ case IG_WATCH_TIME_STOP:
+ WtStruct.fWt = TRUE;
+ WtStruct.dwType = pig->ioctlSubType;
+ WtStruct.hthd = hthd;
+ LpDmMsg->xosdRet = xosdNone;
+ Reply( 0, LpDmMsg, lpdbb->hpid );
+ break;
+
+ case IG_WATCH_TIME_RECALL:
+ WtStruct.fWt = TRUE;
+ WtStruct.dwType = pig->ioctlSubType;
+ WtStruct.hthd = hthd;
+ LpDmMsg->xosdRet = xosdNone;
+ Reply( 0, LpDmMsg, lpdbb->hpid );
+ break;
+
+ case IG_WATCH_TIME_PROCS:
+ WtStruct.fWt = TRUE;
+ WtStruct.dwType = pig->ioctlSubType;
+ WtStruct.hthd = hthd;
+ LpDmMsg->xosdRet = xosdNone;
+ Reply( 0, LpDmMsg, lpdbb->hpid );
+ break;
+
+ case IG_THREAD_INFO:
+#ifdef WIN32S
+ LpDmMsg->xosdRet = xosdUnknown;
+ Reply( 0, LpDmMsg, lpdbb->hpid );
+#else
+ {
+ typedef NTSTATUS (* QTHREAD)(HANDLE,THREADINFOCLASS,PVOID,ULONG,PULONG);
+
+ NTSTATUS Status;
+ THREAD_BASIC_INFORMATION ThreadBasicInfo;
+ QTHREAD Qthread;
+
+ Qthread = (QTHREAD)GetProcAddress( GetModuleHandle( "ntdll.dll" ), "NtQueryInformationThread" );
+ if (!Qthread) {
+ LpDmMsg->xosdRet = xosdUnknown;
+ Reply( 0, LpDmMsg, lpdbb->hpid );
+ break;
+ }
+
+ Status = Qthread( hthd->rwHand,
+ ThreadBasicInformation,
+ &ThreadBasicInfo,
+ sizeof(ThreadBasicInfo),
+ NULL
+ );
+ if (!NT_SUCCESS(Status)) {
+ LpDmMsg->xosdRet = xosdUnknown;
+ Reply( 0, LpDmMsg, lpdbb->hpid );
+ }
+
+ *(LPDWORD)pig->data = (DWORD)ThreadBasicInfo.TebBaseAddress;
+
+ len = sizeof(IOCTLGENERIC) + pig->length;
+ memcpy( LpDmMsg->rgb, pig, len );
+
+ LpDmMsg->xosdRet = xosdNone;
+ Reply( len, LpDmMsg, lpdbb->hpid );
+ }
+#endif // WIN32S
+ break;
+
+ case IG_TASK_LIST:
+#ifdef WIN32S
+ LpDmMsg->xosdRet = xosdUnknown;
+ Reply( 0, LpDmMsg, lpdbb->hpid );
+#else
+ {
+ PTASK_LIST pTaskList = (PTASK_LIST)pig->data;
+ GetTaskList( pTaskList, pTaskList->dwProcessId );
+ len = sizeof(IOCTLGENERIC) + pig->length;
+ memcpy( LpDmMsg->rgb, pig, len );
+ LpDmMsg->xosdRet = xosdNone;
+ Reply( sizeof(IOCTLGENERIC)+pig->length, LpDmMsg, lpdbb->hpid );
+ }
+#endif
+ break;
+
+ default:
+ LpDmMsg->xosdRet = xosdUnknown;
+ Reply( 0, LpDmMsg, lpdbb->hpid );
+ break;
+ }
+
+ return;
+}
+
+
+VOID
+ProcessIoctlCustomCmd(
+ HPRCX hprc,
+ HTHDX hthd,
+ LPDBB lpdbb
+ )
+{
+ LPIOL lpiol = (LPIOL)lpdbb->rgbVar;
+ LPSTR p = lpiol->rgbVar;
+
+
+ LpDmMsg->xosdRet = xosdUnsupported;
+
+ //
+ // parse the command
+ //
+ while (*p && !isspace(*p++));
+ if (*p) {
+ *(p-1) = '\0';
+ }
+
+ //
+ // we don't have any custom dot command here yet
+ // when we do this is what the code should look like:
+ //
+ // at this point the 'p' variable points to any arguments
+ // to the dot command
+ //
+ // if (_stricmp( lpiol->rgbVar, "dot-command" ) == 0) {
+ // -----> do your thing <------
+ // LpDmMsg->xosdRet = xosdNone;
+ // }
+ //
+#if 0
+ if ( !_stricmp(lpiol->rgbVar, "FastStep") ) {
+ fSmartRangeStep = TRUE;
+ LpDmMsg->xosdRet = xosdNone;
+ } else if ( !_stricmp(lpiol->rgbVar, "SlowStep") ) {
+ fSmartRangeStep = FALSE;
+ LpDmMsg->xosdRet = xosdNone;
+ }
+#else
+ LpDmMsg->xosdRet = xosdNone;
+#endif
+
+ //
+ // send back our response
+ //
+ Reply(0, LpDmMsg, lpdbb->hpid);
+} /* ProcessIoctlCustomCmd() */
+
+
+#ifndef WIN32S
+
+DWORD WINAPI
+DoTerminate(
+ LPVOID lpv
+ )
+{
+ HPRCX hprcx = (HPRCX)lpv;
+
+ if (CrashDump) {
+ ProcessUnloadCmd(hprcx, NULL, NULL);
+ return 0;
+ }
+ TerminateProcess(hprcx->rwHand, 1);
+
+ //
+ // now that TerminateThread has completed, put priority
+ // back before calling out of DM
+ //
+
+ SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
+
+ WaitForSingleObject(hprcx->hExitEvent, INFINITE);
+
+ ProcessUnloadCmd(hprcx, NULL, NULL);
+
+ return 0;
+}
+
+VOID
+CompleteTerminateProcessCmd(
+ VOID
+ )
+{
+ DEBUG_EVENT devent, *de=&devent;
+ HANDLE hThread;
+ DWORD dwTid;
+ BREAKPOINT *pbpT;
+ BREAKPOINT *pbp;
+ PKILLSTRUCT pk;
+ HPRCX hprc;
+ HTHDX hthd;
+
+ DEBUG_PRINT("CompleteTerminateProcessCmd");
+
+ EnterCriticalSection(&csKillQueue);
+
+ pk = KillQueue;
+ if (pk) {
+ KillQueue = pk->next;
+ }
+
+ LeaveCriticalSection(&csKillQueue);
+
+ assert(pk);
+ if (!pk) {
+ return;
+ }
+
+ hprc = pk->hprc;
+ free(pk);
+
+ ConsumeAllProcessEvents(hprc, TRUE);
+
+ /*
+ * see if process is already dead
+ */
+
+ if ((hprc->pstate & ps_dead) || (hprc->rwHand == (HANDLE)INVALID)) {
+
+ //
+ // Queue a continue if any thread is stopped
+ //
+
+ for (hthd = hprc->hthdChild; hthd; hthd = hthd->nextSibling) {
+ if (hthd->tstate & ts_stopped) {
+ AddQueue( QT_CONTINUE_DEBUG_EVENT,
+ hthd->hprc->pid,
+ hthd->tid,
+ DBG_CONTINUE,
+ 0);
+ hthd->tstate &= ~ts_stopped;
+ hthd->tstate |= ts_running;
+ }
+ }
+
+ ProcessUnloadCmd(hprc, NULL, NULL);
+
+ } else {
+
+ for (pbp = BPNextHprcPbp(hprc, NULL); pbp; pbp = pbpT) {
+ pbpT = BPNextHprcPbp(hprc, pbp);
+ RemoveBP(pbp);
+ }
+
+ //
+ // Start another thread to kill the thing. This thread needs to
+ // continue any threads which are stopped. The new thread will then
+ // wait until this one (the poll thread) has handled all of the
+ // events, and then send destruction notifications to the shell.
+ //
+
+ hThread = CreateThread(NULL,
+ 4096,
+ DoTerminate,
+ (LPVOID)hprc,
+ 0,
+ &dwTid);
+ assert(hThread);
+ if ( !hThread ) {
+ return;
+ }
+
+ //
+ // Yield so DoTerminate can do its thing before we start posting
+ // ContinueDebugEvents, so we minimize the time that the app
+ // runs before it is terminated.
+ //
+
+ hprc->pstate |= ps_killed;
+ SetThreadPriority(hThread, THREAD_PRIORITY_TIME_CRITICAL);
+ Sleep(0);
+
+ CloseHandle(hThread);
+
+ //
+ // Queue a continue if any thread is stopped
+ //
+
+ for (hthd = hprc->hthdChild; hthd; hthd = hthd->nextSibling) {
+ if (hthd->tstate & ts_stopped) {
+ AddQueue( QT_CONTINUE_DEBUG_EVENT,
+ hthd->hprc->pid,
+ hthd->tid,
+ DBG_CONTINUE,
+ 0);
+ hthd->tstate &= ~ts_stopped;
+ hthd->tstate |= ts_running;
+ }
+ }
+
+ }
+
+}
+
+
+DWORD
+ProcessTerminateProcessCmd(
+ HPRCX hprc,
+ HTHDX hthd,
+ LPDBB lpdbb
+ )
+{
+ PKILLSTRUCT pk;
+
+ if (!hprc) {
+ return FALSE;
+ }
+
+ Unreferenced( lpdbb );
+
+ pk = (PKILLSTRUCT)malloc(sizeof(KILLSTRUCT));
+ pk->hprc = hprc;
+
+ EnterCriticalSection(&csKillQueue);
+
+ pk->next = KillQueue;
+ KillQueue = pk;
+
+ LeaveCriticalSection(&csKillQueue);
+
+ return TRUE;
+}
+#endif
+
+#ifdef WIN32S
+
+DWORD
+ProcessTerminateProcessCmd(
+ HPRCX hprc,
+ HTHDX hthd,
+ LPDBB lpdbb
+ )
+{
+ DWORD rval;
+
+ if (!hprc) {
+ return FALSE;
+ }
+
+ Unreferenced( lpdbb );
+
+ DEBUG_PRINT_2("ProcessTerminateProcessCmd called hprc=0x%x, hthd=0x%x.\n\r",
+ hprc, hthd);
+
+ // Win32s doesn't support TerminateProcess(), but does give us a special
+ // ContinueDebugEvent flag. If we are stopped at a debug event, we can
+ // Continue with this flag to terminate the child app.
+
+ DEBUG_PRINT("ConsumeAllProcessEvents\r\n");
+
+ ConsumeAllProcessEvents(hprc, TRUE);
+
+ DEBUG_PRINT("Check process state\r\n");
+
+ if ((hprc->pstate & ps_dead) || hprc->rwHand == (HANDLE)INVALID) {
+ DEBUG_PRINT("Process already dead\r\n");
+ if (fExitProcessDebugEvent) {
+ // we saved tidExit when we got the EXIT_PROCESS_DEBUG_EVENT
+ AddQueue( QT_CONTINUE_DEBUG_EVENT,
+ hprc->pid,
+ tidExit,
+ DBG_CONTINUE,
+ 0);
+ }
+ rval = FALSE; // already dead
+ }
+
+ if (fProcessingDebugEvent) {
+ DEBUG_PRINT_1("Continue with %s\r\n",
+ (fExitProcessDebugEvent ? "DBG_CONTINUE" : "DBG_TERMINATE_PROCESS"));
+
+ for (hthd = hprc->hthdChild; hthd; hthd = hthd->nextSibling) {
+ if (hthd->tstate & ts_stopped) {
+ AddQueue( QT_CONTINUE_DEBUG_EVENT,
+ hthd->hprc->pid,
+ hthd->tid,
+ fExitProcessDebugEvent?
+ DBG_CONTINUE : DBG_TERMINATE_PROCESS,
+ 0);
+ hthd->tstate &= ~ts_stopped;
+ hthd->tstate |= ts_running;
+ }
+ }
+
+ // mark this process as killed
+ DEBUG_PRINT("Mark process as killed\r\n");
+ hprc->pstate |= ps_killed;
+ rval = TRUE; // killed it.
+ } else {
+ DEBUG_PRINT("Can't terminate process right now\r\n");
+ // can't continue debug event right now, so can't terminate.
+ rval = FALSE;
+ }
+
+ return rval;
+}
+#endif
+
+
+VOID
+ProcessAllProgFreeCmd(
+ HPRCX hprcXX,
+ HTHDX hthd,
+ LPDBB lpdbb
+ )
+{
+ HPRCX hprc;
+
+ Unreferenced(hprcXX);
+ Unreferenced(hthd);
+
+ for (;;) {
+
+ EnterCriticalSection(&csThreadProcList);
+ for (hprc = prcList; hprc; hprc = hprc->next) {
+ if (hprc->pstate != (ps_root | ps_destroyed)) {
+ break;
+ }
+ }
+ LeaveCriticalSection(&csThreadProcList);
+
+ if (hprc) {
+ ProcessTerminateProcessCmd(hprc, hthd, lpdbb);
+ ProcessUnloadCmd(hprc, hthd, lpdbb);
+ } else {
+ break;
+ }
+
+ }
+
+ WaitForSingleObject(hEventNoDebuggee, INFINITE);
+}
+
+
+DWORD
+ProcessAsyncGoCmd(
+ HPRCX hprc,
+ HTHDX hthd,
+ LPDBB lpdbb
+ )
+{
+ XOSD xosd = xosdNone;
+#ifndef WIN32S
+ DEBUG_EVENT de;
+#endif
+
+ DEBUG_PRINT("ProcessAsyncGoCmd called.\n\r");
+
+#ifdef WIN32S
+ xosd = xosdUnsupported; // can't resume thread in win32s
+#else
+
+#ifdef WIN32
+ if ((hthd->tstate & ts_frozen)) {
+ if (hthd->tstate & ts_stopped) {
+ //
+ // if at a debug event, it won't really be suspended,
+ // so just clear the flag.
+ //
+ hthd->tstate &= ~ts_frozen;
+
+ } else if (ResumeThread(hthd->rwHand) == -1L ) {
+
+#ifdef OSDEBUG4
+ xosd = xosdBadThread;
+#else
+ xosd = xosdInvalidThread;
+#endif
+
+ } else {
+
+ hthd->tstate &= ~ts_frozen;
+
+ /*
+ * deal with dead, frozen, continued thread:
+ */
+ if ((hthd->tstate & ts_dead) && !(hthd->tstate & ts_stopped)) {
+
+ de.dwDebugEventCode = DESTROY_THREAD_DEBUG_EVENT;
+ de.dwProcessId = hprc->pid;
+ de.dwThreadId = hthd->tid;
+ NotifyEM(&de, hthd, 0, NULL);
+ FreeHthdx(hthd);
+
+ hprc->pstate &= ~ps_deadThread;
+ for (hthd = hprc->hthdChild; hthd; hthd = hthd->nextSibling) {
+ if (hthd->tstate & ts_dead) {
+ hprc->pstate |= ps_deadThread;
+ }
+ }
+
+ }
+ }
+ }
+#endif // WIN32
+#endif // !WIN32S
+
+ Reply(0, &xosd, lpdbb->hpid);
+ return(xosd);
+}
+
+
+void
+ActionAsyncStop(
+ DEBUG_EVENT * pde,
+ HTHDX hthd,
+ DWORD unused,
+ BREAKPOINT * pbp
+ )
+/*++
+
+Routine Description:
+
+ This routine is called if a breakpoint is hit which is part of a
+ Async Stop request. When hit is needs to do the following: clean
+ out any expected events on the current thread, clean out all breakpoints
+ which are setup for doing the current async stop.
+
+Arguments:
+
+ pde - Supplies a pointer to the debug event which just occured
+
+ hthd - Supplies a pointer to the thread for the debug event
+
+ pbp - Supplies a pointer to the breakpoint for the ASYNC stop
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ union {
+ RTP rtp;
+ char rgb[sizeof(RTP) + sizeof(BPR)];
+ } rtpbuf;
+ RTP * prtp = &rtpbuf.rtp;
+ BPR * pbpr = (BPR *) prtp->rgbVar;
+ HPRCX hprc = hthd->hprc;
+ BREAKPOINT * pbpT;
+
+ /*
+ * We no longer need to have this breakpoint set.
+ */
+
+ RemoveBP( pbp );
+
+ /*
+ * Remove any other breakpoints in this process which are for
+ * async stop commands
+ */
+
+ for (pbp = BPNextHprcPbp(hprc, NULL); pbp != NULL; pbp = pbpT) {
+
+ pbpT = BPNextHprcPbp(hprc, pbp);
+
+ if (pbp->id == (HPID)ASYNC_STOP_BP) {
+ RemoveBP( pbp );
+ }
+ }
+
+ /*
+ * Setup a return packet which says we hit an async stop breakpoint
+ */
+
+ prtp->hpid = hprc->hpid;
+ prtp->htid = hthd->htid;
+ prtp->dbc = dbcAsyncStop;
+ prtp->cb = sizeof(BPR);
+
+#ifdef TARGET_i386
+ pbpr->segCS = (SEGMENT) hthd->context.SegCs;
+ pbpr->segSS = (SEGMENT) hthd->context.SegSs;
+ pbpr->offEBP = (UOFFSET) hthd->context.Ebp;
+#endif
+
+ pbpr->offEIP = (DWORD) PC(hthd);
+
+ DmTlFunc(tlfDebugPacket, prtp->hpid, sizeof(rtpbuf), (LONG)&rtpbuf);
+
+ return;
+} /* ActionAsyncStop() */
+
+
+
+VOID
+ProcessAsyncStopCmd(
+ HPRCX hprc,
+ HTHDX hthd,
+ LPDBB lpdbb
+ )
+
+/*++
+
+Routine Description:
+
+ This function is called in response to a asynchronous stop request.
+ In order to do this we will set breakpoints the current PC for
+ every thread in the system and wait for the fireworks to start.
+
+Arguments:
+
+ hprc - Supplies a process handle
+
+ hthd - Supplies a thread handle
+
+ lpdbb - Supplies the command information packet
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+#ifdef WIN32S
+
+ /*
+ * Win32s doesn't support async stop this way. The user should
+ * press the debugger hot key at the debuggee console to generate
+ * an async stop. This may change if BoazF gives us a private API
+ * to generate the async stop exception.
+ */
+ DEBUG_PRINT("\r\nProcessAsyncStopCmd\r\n");
+
+ LpDmMsg->xosdRet = xosdUnsupported;
+ Reply(0, LpDmMsg, lpdbb->hpid);
+ return;
+
+#else
+ CONTEXT regs;
+ BREAKPOINT * pbp;
+ ADDR addr;
+ BOOL fSetFocus = * ( BOOL *) lpdbb->rgbVar;
+
+ regs.ContextFlags = CONTEXT_CONTROL;
+
+
+ /*
+ * Step 1. Enumerate through the threads and freeze them all.
+ */
+
+ for (hthd = hprc->hthdChild; hthd != NULL; hthd = hthd->nextSibling) {
+ if (SuspendThread(hthd->rwHand) == -1L) {
+ ; // Internal error;
+ }
+ }
+
+ /*
+ * Step 2. Place a breakpoint on every PC address
+ */
+
+ for (hthd = hprc->hthdChild; hthd != NULL; hthd = hthd->nextSibling) {
+#ifndef WIN32S
+ if (CrashDump) {
+ DmpGetContext( hthd->tid-1, &regs );
+ } else
+#endif
+ {
+ GetThreadContext( hthd->rwHand, &regs );
+ }
+
+ AddrInit(&addr, 0, 0, (DWORD)cPC(&regs), TRUE, TRUE, FALSE, FALSE);
+ pbp = SetBP(hprc, hthd, bptpExec, bpnsStop, &addr, (HPID) ASYNC_STOP_BP);
+
+ RegisterExpectedEvent(hthd->hprc,
+ hthd,
+ BREAKPOINT_DEBUG_EVENT,
+ (DWORD)pbp,
+ DONT_NOTIFY,
+ (ACVECTOR)ActionAsyncStop,
+ FALSE,
+ pbp);
+ }
+
+ /*
+ * Step 3. Unfreeze all threads
+ */
+
+ if (fSetFocus) {
+ DmSetFocus(hprc);
+ }
+ for (hthd = hprc->hthdChild; hthd != NULL; hthd = hthd->nextSibling) {
+ if (ResumeThread(hthd->rwHand) == -1) {
+ ; // Internal error
+ }
+ }
+
+ LpDmMsg->xosdRet = xosdNone;
+ Reply(0, LpDmMsg, lpdbb->hpid);
+ return;
+#endif
+} /* ProcessAsyncStopCmd() */
+
+
+VOID
+ProcessDebugActiveCmd(
+ HPRCX hprc,
+ HTHDX hthd,
+ LPDBB lpdbb
+ )
+{
+#ifdef WIN32S
+
+ Unreferenced(hprc);
+ Unreferenced(hthd);
+
+ LpDmMsg->xosdRet = xosdUnsupported; // can't attatch in win32s
+ *((DWORD *)LpDmMsg->rgb) = ERROR_NOT_SUPPORTED;
+ Reply(sizeof(DWORD), LpDmMsg, lpdbb->hpid);
+
+#else
+
+#ifdef OSDEBUG4
+
+ LPDAP lpdap = ((LPDAP)(lpdbb->rgbVar));
+
+ Unreferenced(hprc);
+ Unreferenced(hthd);
+
+ if (fDisconnected) {
+
+ SetEvent( hEventRemoteQuit );
+
+ } else if (!StartDmPollThread()) {
+
+ //
+ // CreateThread() failed; fail and send a dbcError.
+ //
+ LpDmMsg->xosdRet = xosdUnknown;
+ Reply(0, LpDmMsg, lpdbb->hpid);
+
+ } else if (WaitForSingleObject(DebugActiveStruct.hEventReady, INFINITE)
+ != 0) {
+ //
+ // the wait failed. why? are there cases where we
+ // should restart the wait?
+ //
+ LpDmMsg->xosdRet = xosdUnknown;
+ Reply(0, LpDmMsg, lpdbb->hpid);
+
+ } else {
+
+ ResetEvent(DebugActiveStruct.hEventReady);
+ ResetEvent(DebugActiveStruct.hEventApiDone);
+
+ DebugActiveStruct.dwProcessId = lpdap->dwProcessId;
+ DebugActiveStruct.hEventGo = lpdap->hEventGo;
+ DebugActiveStruct.fAttach = TRUE;
+
+ *nameBuffer = 0;
+
+ // wait for it...
+
+ if (WaitForSingleObject(DebugActiveStruct.hEventApiDone, INFINITE) == 0
+ && DebugActiveStruct.fReturn != 0) {
+
+ LpDmMsg->xosdRet = xosdNone;
+ //
+ // the poll thread will reply when creating the "root" process.
+ //
+ if (!fUseRoot) {
+ Reply(0, LpDmMsg, lpdbb->hpid);
+ }
+
+ } else {
+ LpDmMsg->xosdRet = xosdUnknown;
+ Reply(0, LpDmMsg, lpdbb->hpid);
+ }
+
+ }
+
+
+#else // OSDEBUG4
+
+ LPDBG_ACTIVE_STRUCT lpdba = ((LPDBG_ACTIVE_STRUCT)(lpdbb->rgbVar));
+
+ Unreferenced(hprc);
+ Unreferenced(hthd);
+
+ if (fDisconnected) {
+ SetEvent( hEventRemoteQuit );
+ } else if (!StartDmPollThread()) {
+
+ LpDmMsg->xosdRet = xosdUnknown;
+ // Last error is from CreateThread();
+ *((DWORD *)LpDmMsg->rgb) = GetLastError();
+ Reply(0, LpDmMsg, lpdbb->hpid);
+
+ // wait for attach struct to be available
+ } else if (WaitForSingleObject(DebugActiveStruct.hEventReady, INFINITE)
+ != 0) {
+ LpDmMsg->xosdRet = xosdUnknown;
+ *((DWORD *)LpDmMsg->rgb) = GetLastError();
+ Reply(0, LpDmMsg, lpdbb->hpid);
+
+ } else {
+
+ ResetEvent(DebugActiveStruct.hEventReady);
+ ResetEvent(DebugActiveStruct.hEventApiDone);
+
+ DebugActiveStruct.dwProcessId = lpdba->dwProcessId;
+ DebugActiveStruct.hEventGo = lpdba->hEventGo;
+ DebugActiveStruct.fAttach = TRUE;
+
+ *nameBuffer = 0;
+
+ // wait for it...
+
+ if (WaitForSingleObject(DebugActiveStruct.hEventApiDone, INFINITE) == 0
+ && DebugActiveStruct.fReturn != 0) {
+
+ LpDmMsg->xosdRet = xosdNone;
+ //
+ // the poll thread will reply when creating the "root" process.
+ //
+ if (!fUseRoot) {
+ Reply(0, LpDmMsg, lpdbb->hpid);
+ }
+
+ } else {
+
+ DebugActiveStruct.dwProcessId = 0;
+ DebugActiveStruct.hEventGo = NULL;
+ LpDmMsg->xosdRet = xosdUnknown;
+ *((DWORD *)LpDmMsg->rgb) = DebugActiveStruct.dwError;
+ Reply(0, LpDmMsg, lpdbb->hpid);
+ }
+ }
+
+#endif // OSDEBUG4
+
+ SetEvent(DebugActiveStruct.hEventReady);
+
+#endif // WIN32S
+}
+
+
+VOID
+ProcessRemoteQuit(
+ VOID
+ )
+{
+ HPRCX hprc;
+ BREAKPOINT *pbp;
+ BREAKPOINT *pbpT;
+
+
+ EnterCriticalSection(&csThreadProcList);
+
+ for(hprc=prcList->next; hprc; hprc=hprc->next) {
+ for (pbp = BPNextHprcPbp(hprc, NULL); pbp; pbp = pbpT) {
+ pbpT = BPNextHprcPbp(hprc, pbp);
+ RemoveBP(pbp);
+ }
+ }
+
+ LeaveCriticalSection(&csThreadProcList);
+
+ fDisconnected = TRUE;
+ ResetEvent( hEventRemoteQuit );
+}
diff --git a/private/windbg/newdm/user/wow.c b/private/windbg/newdm/user/wow.c
new file mode 100644
index 000000000..e536bc792
--- /dev/null
+++ b/private/windbg/newdm/user/wow.c
@@ -0,0 +1,1175 @@
+/*++
+
+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() */