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.
 
 
 
 
 
 

4293 lines
112 KiB

/*++
Copyright (c) 1993 Microsoft Corporation
Module Name:
Osdebug.c
Abstract:
This module implements the OSDebug API used by WinDBG.
Author:
Kent D. Forschmiedt (kentf) 06-Jul-1993
James L. Schaad (jimsch)
David W. Gray (davidgra) 15-Oct-1990
Environment:
Win32, User Mode
--*/
#include "windows.h"
#include "memory.h"
#include "defs.h"
#include "mm.h"
#include "ll.h"
#include "lb.h"
#include "tl.h"
#include "od.h"
#include "od2.h"
#include "osdem.h"
#include "mhhpt.h"
#include "cchpt.h"
#include "lbhpt.h"
#include "llhpt.h"
#include "osassert.h"
#include <string.h>
#include "dbgver.h"
extern AVS Avs;
static LPDBF lpdbf;
static HLLI llpid;
static HLLI llem;
static HLLI lltl = 0;
#define CEXM_MDL_native 0x20
XOSD OSDDoCallBack ( UINT, HPID, HTID, UINT, UINT, LONG );
XOSD OSDDoCallBackToEM ( EMF, HPID, HTID, UINT, LONG );
XOSD CreateProc ( LPFNSVC, HEM, HTL, LPHPID );
XOSD CreateThd ( HPID, HTID, LPHTID );
XOSD CallEM ( EMF, HPID, HTID, DWORD, LPV );
XOSD CallTL ( TLF, HPID, DWORD, LPV );
XOSD PASCAL LOADDS EMCallBackDB ( DBC, HPID, HTID, DWORD, DWORD, LPV );
XOSD PASCAL LOADDS EMCallBackTL ( TLF, HPID, DWORD, LPV );
XOSD PASCAL LOADDS EMCallBackNT ( EMF, HPID, HTID, DWORD, LPV );
XOSD PASCAL LOADDS EMCallBackEM ( EMF, HPID, HTID, DWORD, DWORD, LPV );
XOSD PASCAL LOADDS TLCallBack ( HPID, UINT, LPV );
static EMCB emcb = {
EMCallBackDB,
EMCallBackTL,
EMCallBackNT,
EMCallBackEM
};
static CRITICAL_SECTION CallbackCriticalSection;
XOSD PASCAL
OSDInit (
LPDBF lpdbfT
)
/*++
Routine Description:
Initialize the internal structures for osdebug.
Register the debugger services callback vector.
Use list manager to create the three global lists used by osdebug.
These are the list of processes ( llpid ), the list of transport
layers ( lltl ), and the list of execution models ( llem ).
Registering the debugger services with osdebug is just an
assignment of a pointer to the function structure.
If this function fails, it is catastrophic. No cleanup of
partially allocated data is attempted.
Arguments:
lpdbfT - Supplies the debugger services structure
Return Value:
xosdNone - Function succeeded
xosdOutOfMemory - List manager was unable to allocate room
for its root structures.
--*/
{
XOSD xosd = xosdNone;
assert ( lpdbfT != NULL );
InitializeCriticalSection( &CallbackCriticalSection );
lpdbf = lpdbfT;
llpid = LLInit (sizeof ( PIDS ), llfNull, ODPDKill, (LPFNFCMPNODE) NULL );
lltl = LLInit ( sizeof ( TLS ), llfNull, TLKill, (LPFNFCMPNODE) NULL );
llem = LLInit ( sizeof ( EMS ), llfNull, EMKill, (LPFNFCMPNODE) NULL );
if ( llpid == 0 || lltl == 0 || llem == 0 ) {
xosd = xosdOutOfMemory;
}
return xosd;
}
XOSD PASCAL
OSDTerm(
VOID
)
/*++
Routine Description:
Deallocate resources used by OSD. At present, this only destroys
critical sections used by osdebug.
Arguments:
None
Return Value:
xosd - always xosdNone
--*/
{
DeleteCriticalSection( &CallbackCriticalSection );
return xosdNone;
}
XOSD PASCAL
OSDCreatePID (
LPFNSVC lpfnsvc,
HEM hem,
HTL htl,
LPHPID lphpid
)
/*++
Routine Description:
Create the structures associated with a process
Create the osdebug pid structure and add it to the list of processes
( llpid ). Notify the native execution model ( hem ) and the
transport layer ( htl ) of the new process.
When connecting to a remote transport layer, check the version
signature to verify that the components are compatible.
Arguments:
lpfnsvc - Supplies a pointer to the debugger callback function.
hem - Supplies a handle to the native execution model.
htl - Supplies a handle to the transport layer.
lszEMData - Supplies a string that specifies init data for the
process required by the execution model.
lszTLData - Supplies a string that specifies init data for the
process required by the transport layer.
lphpid - Returns the handle to the pid that is generated.
Return Value:
xosdOutOfMemory - The List manager was unable to allocate
memory for the structures to be created.
Any error values that may be generated by the transport
layer or execution model initialization of a process.
--*/
{
/* *
* Use the list manager to create a process structure and add it to *
* the process list ( llpid ). *
* *
* Initialize the fields of the process structure. *
* *
* Call the execution model service function for the native execution *
* model with the emfCreatePid command and the initialization string *
* ( lszEMData ). *
* *
* Call the transport layer service function for the process's *
* transport layer with the tlfCreatePid command and the *
* initialization string ( lszTLData ). */
HEM hodem;
HPID oldhpid;
HPID hpid;
LPEM lpem;
LPTL lptl;
XOSD xosd = xosdNone;
assert ( lpfnsvc != NULL );
assert ( hem != hemNull );
assert ( htl != htlNull );
assert ( lphpid != NULL );
assert ( llpid != 0 );
// Create and initialize the process structure and add to llpid
xosd = CreateProc ( lpfnsvc, hem, htl, &hpid );
if (xosd != xosdNone) {
return xosd;
}
// Notify the transport layer of the new process
lptl = LLLock ( htl );
xosd = CallTL ( tlfConnect, hpid, 0, NULL );
LLUnlock ( htl );
if (xosd != xosdNone) {
// remove hpid from the lists of hpids in llem
for (hodem = LLNext((HLLI) llem, (HLLE)hmemNull ); hodem; hodem = LLNext( (HLLI)llem, (HLLE)hodem )) {
lpem = LLLock ( hodem );
if ( oldhpid = (HPID)LLFind ( lpem->llhpid, 0, &hpid, 0L ) ) {
LLDelete ( lpem->llhpid, (HLLE)oldhpid );
}
LLUnlock ( hodem );
}
LLUnlock ( hodem );
LLDelete ( llpid, (HLLE)hpid );
return xosd;
}
// Notify the native execution model of the new process
lpem = LLLock ( hem );
xosd = lpem->emfunc( emfConnect, hpid, htidNull, 0, 0);
if (xosd != xosdNone) {
goto err;
}
xosd = lpem->emfunc (emfCreatePid, hpid, htidNull, 0, (LONG) NULL);
err:
LLUnlock ( hem );
if (xosd != xosdNone) {
CallTL(tlfDisconnect, hpid, 0, NULL);
LLDelete ( llpid, (HLLE)hpid );
return xosd;
}
*lphpid = hpid;
return xosd;
}
XOSD PASCAL
OSDDisconnect(
HPID hpid,
HTID htid
)
{
if (!hpid) {
return xosdUnknown;
}
return CallTL( tlfDisconnect, hpid, (DWORD)htid, NULL );
}
XOSD PASCAL
OSDDestroyPID (
HPID hpid
)
/*++
Routine Description:
Destroy the structures associated with a process
Delete the osdebug pid structure from the list of processes
( llpid ). Notify the native execution model ( hem ) and the
transport layer ( htl ) that it's been deleted.
Arguments:
hpid - Supplies the process to destroy.
Return Value:
xosdInvalidProc - The hpid given was invalid.
Any error values that may be generated by the transport
layer or execution model during destruction of a process.
--*/
{
/***************************************************************************
* *
* Call the execution model service functions to let them know that *
* this hpid is being destroyed. *
* *
* Use the list manager to delete the process structure from the *
* process list ( llpid ). *
* *
***************************************************************************/
XOSD xosd;
HEM hodem;
LPEM lpem;
HPID oldhpid;
LPPID lppid;
HTL htl, htlT;
xosd = CallEM ( emfDestroyPid, hpid, htidNull, 0, 0 );
if (xosd == xosdNone) {
lppid = LLLock((HLLE)hpid);
htl = lppid->htl;
LLUnlock((HLLE)hpid);
oldhpid = NULL;
while (oldhpid = (HPID)LLNext((HLLI)llpid, (HLLE)oldhpid) ) {
if (oldhpid != hpid) {
lppid = LLLock((HLLE)oldhpid);
htlT = lppid->htl;
LLUnlock((HLLE)oldhpid);
if (htlT == htl) {
htl = 0;
break;
}
}
}
if (htl) {
// if nobody else is using it, tell TL to disconnect
xosd = CallEM ( emfDisconnect, hpid, 0, 0, 0 );
xosd = CallTL ( tlfDisconnect, hpid, 0, NULL );
}
// remove hpid from the lists of hpids in llem
for (hodem = LLNext( (HLLI)llem, (HLLE)hmemNull ); hodem; hodem = LLNext( (HLLI)llem, (HLLE)hodem )) {
lpem = LLLock ( (HLLE)hodem );
if ( oldhpid = (HPID)LLFind ( lpem->llhpid, 0, &hpid, 0L ) ) {
LLDelete ( lpem->llhpid, (HLLE)oldhpid );
}
LLUnlock ( (HLLE)hodem );
}
LLDelete ( llpid, (HLLE)hpid );
}
return xosd;
}
XOSD PASCAL
OSDDestroyTID(
HTID htid
)
/*++
Routine Description:
Companion for OSDDestroyPID(); unhooks and deletes an htid.
There is less to this than destroying a PID: the EM has to be
notified, but the TL does not.
Arguments:
htid - osdebug htid
Return Value:
xosdNone, xosdInvalidProc, xosdInvalidThread
--*/
{
LPTID lptid;
HPID hpid;
LPPID lppid;
XOSD xosd;
lptid = LLLock((HLLE) htid );
if (!lptid) {
return xosdInvalidThread;
}
hpid = lptid->hpid;
LLUnlock((HLLE) htid );
xosd = CallEM ( emfDestroyTid, hpid, htid, 0, 0 );
lppid = LLLock ( (HLLE)hpid );
if (!lppid) {
return xosdInvalidProc;
}
LLDelete ( lppid->lltid, (HLLE)htid );
LLUnlock ( (HLLE)hpid );
return xosdNone;
}
XOSD PASCAL
OSDPtrace (
OSD osd,
UINT wValue,
LPV lpData,
HPID hpid,
HTID htid
)
/*++
Routine Description:
Provide ptrace-type functionality. This just passes the parameters
to the EM service function.
Arguments:
osd - Supplies OSD index of requested service
wValue - Supplies function-dependent data
lpData - Supplies and/or Returns function dependent data
hpid - Supplies handle to process structure
htid - Supplies handle to thread structure
Return Value:
xosd value as returned by the EM service function.
--*/
{
return CallEM ( (EMF) osd, hpid, htid, wValue, lpData );
}
XOSD PASCAL
OSDIoctl (
HPID hpid,
HTID htid,
UINT wFunction,
UINT cbData,
LPV lpData
)
/*++
Routine Description:
Provide OS specific functionality. Calls the EM service function,
requesting the emfIOCTL service.
Arguments:
hpid - Supplies handle to the process to perform the operation
on. Some IOCTLs may not apply to a process, but the hpid
is required to provide the hook to the EM and TL.
htid - Supplies optional thread structure
wFunction - Supplies the IOCTL function index
cbData - Supplies the number of bytes in the data packet
lpData - Supplies and returns data. Use of this field depends on
the IOCTL.
Return Value:
xosd return value is supplied by the IOCTL function.
--*/
{
XOSD xosd = xosdNone;
LPIOL lpiol = MHAlloc ( sizeof ( IOL ) + cbData );
if ( lpiol == NULL ) return xosdOutOfMemory;
lpiol->wFunction = wFunction;
_fmemcpy ( lpiol->rgbVar, lpData, cbData );
xosd = CallEM ((EMF) emfIOCTL, hpid, htid, sizeof ( IOL ) + cbData, (LPV) lpiol );
_fmemcpy ( lpData, lpiol->rgbVar, cbData );
MHFree ( lpiol );
return xosd;
}
XOSD PASCAL
OSDProgramLoad (
HPID hpid,
LSZ lszCmdLine,
LSZ lszDebugger,
ULONG ulFlags
)
/*++
Routine Description:
Send a program load request to the EM. If the process is created,
the shell will be notified of a new process creation.
Arguments:
hpid - Supplies the process the process handle that binds to the
EM and TL. This is not neccessarily the hpid that will
correspond to the new process.
lszCmdLine - Supplies the command line that specifies the child program
and its arguments.
lszDebugger - Supplies the name of the debugger to the EM. This is
provided mainly so that the DM can print the debugger's
name in error messages.
ulFlags - Supplies flags that are passed to the EM. The following
flags are defined; any or none may be supported by any
EM/DM pair:
ulfMultiProcess - children of the new process will
be debugged.
ulfMinimizeApp - New process will be iconic
ulfNoActivate - New process will not receive focus
ulfInheritHandles - New app will inherit handles
from debugger. This is useful
when debugging an app which inherits
handles from its parent.
ulfDebugRegisters
ulfDisableNMI
ulfForceNMI
ulfDisableIBM
ulfForceIBM
Return Value:
If OSDProgramLoad cannot allocate a buffer to copy the arguements
into, it will return xosdOutOfMemory. Other xosd failure codes may be
returned from the EM, such as xosdFileNotFound, xosdAccessDenied.
--*/
{
XOSD xosd = xosdNone;
LPPRL lpprl;
UINT cchCmd;
assert ( hpid != NULL );
assert ( lszCmdLine != NULL );
(void)CallEM ( emfSetMulti,
hpid,
htidNull,
( ulFlags & ulfMultiProcess ) != 0,
NULL
);
(void)CallEM ( emfDebugger,
hpid,
htidNull,
_fstrlen ( lszDebugger ) + 1,
lszDebugger
);
cchCmd = _fstrlen( lszCmdLine ) + 1;
lpprl = (LPPRL)MHAlloc ( sizeof ( PRL ) + cchCmd );
if ( lpprl == NULL ) {
xosd = xosdOutOfMemory;
} else {
lpprl->cbCmdLine = cchCmd;
lpprl->ulChildFlags = ulFlags;
_fmemcpy( lpprl->lszCmdLine, lszCmdLine, cchCmd );
xosd = CallEM ( emfProgramLoad,
hpid,
htidNull,
sizeof( PRL ) + cchCmd,
lpprl
);
MHFree ( lpprl );
}
return xosd;
}
XOSD PASCAL
OSDAddEM (
EMFUNC emfunc,
LPDBF lpdbf,
LPHEM lphem,
EMTYPE emtype
)
/*++
Routine Description:
Create and initialize an execution model associated with the
service function EMFunc and add it to the list of osdebug's
available execution models ( llem ).
Arguments:
emfunc - Supplies a pointer to the execution model service function
to be associated with the execution model that is being
created.
lpdbf - Supplies a pointer to the debugger services structure that
will be registered with the execution model being created.
lphem - Returns the execution model handle.
emtype - Supplies the type of EM; emNative or emNonNative.
Return Value:
xosdNone - Success.
xosdOutOfMemory - List manager was unable to allocate em or
add it to the execution model list ( llem ).
Other xosd failure codes may be returned from the new EM while
it is being initialized.
--*/
{
/***************************************************************************
* IMPLEMENTATION: *
* *
* Use list manager to create an execution model handle and add it *
* to the execution model list ( llem ). *
* *
* Call the execution model service function ( lpfnsvcEM ) to *
* initialize the execution model and to register the debugger *
* service functions ( lpdbf ). *
* *
* *
***************************************************************************/
HEM hem;
HEM hemm = 0;
LPEM lpem;
LPEM lpemm;
XOSD xosd = xosdNone;
UINT wModel;
assert ( emfunc != NULL );
assert ( lpdbf != NULL );
assert ( lphem != NULL );
hem = LLCreate ( llem );
if ( hem == hemNull ) {
return xosdOutOfMemory;
}
if ( emtype == emNative ) {
// native inserted at the tail of the list
LLAdd ( llem, hem );
}
else {
// non-native inserted at head of list
LLAddHead ( llem, hem );
}
lpem = LLLock ( hem );
lpem->emfunc = emfunc;
lpem->emtype = emtype;
lpem->llhpid = LLInit ( sizeof ( HPID ), llfNull, NULL, EMHpidCmp );
if ( lpem->llhpid == 0 ) {
xosd = xosdOutOfMemory;
}
xosd = emfunc ( emfRegisterDBF, NULL, htidNull, 0, (LONG) lpdbf );
if (xosd != xosdNone) {
return xosd;
}
xosd = emfunc ( emfInit, NULL, htidNull, 0, (LONG) (LPV) &emcb );
if (xosd != xosdNone) {
return xosd;
}
xosd = emfunc ( emfGetModel, NULL, htidNull, 0, (LONG) (LPV) &wModel );
if (xosd != xosdNone) {
return xosd;
}
while ( hemm = LLNext ( llem, hemm ) ) {
lpemm = LLLock ( hemm );
if ( lpemm->model == wModel ) {
// this is an error, cannot add the same model twice
LLUnlock ( hemm );
LLUnlock ( hem );
return xosdInvalidEM;
}
LLUnlock ( hemm );
}
lpem->model = wModel;
LLUnlock ( hem );
*lphem = hem;
return xosd;
}
XOSD PASCAL
OSDDeleteEM (
HEM hem
)
/*++
Routine Description:
Remove the execution model (hem) from os debug's list of available
execution models ( llem ).
Arguments:
hem - Supplies handle to EM which is being removed
Return Value:
xosdNone - Success.
xosdInvalidEM - The execution model handle ( hem ) is invalid.
xosdEMInUse - The execution model is still being used by some pid.
OSDDiscardEM must be called on all of the pids using
this particular em before OSDDeleteEM can be called
without error.
--*/
{
/***************************************************************************
* IMPLEMENTATION: *
* *
* Check the list of pids using this execution model. If it is zero *
* indicating that no pids are using it, then call the list manager *
* to delete it from the list of available execution models ( llem ). *
* *
***************************************************************************/
XOSD xosd = xosdNone;
LPEM lpem;
assert ( hem != hemNull );
lpem = LLLock ( hem );
if ( LLSize ( lpem->llhpid ) != 0 ) {
LLUnlock ( hem );
xosd = xosdEMInUse;
} else {
// Tell the EM and DM that they're about to be discarded
(lpem->emfunc) ( emfUnInit, NULL, htidNull, 0, 0 );
LLUnlock ( hem );
if ( !LLDelete ( llem, (HLLE)hem ) ) {
xosd = xosdInvalidEM;
}
}
return xosd;
}
XOSD PASCAL
OSDDeinitTL(
TLFUNC tlfunc
)
/*++
Routine Description:
Tell the transport to clean up. This should be called if the
OSDInitTL succeeds, but the OSDAddTL fails. This sends a
tlfGlobalDestroy message to the transport layer.
Arguments:
tlfunc - Supplies the TL service function
Return Value:
xosd status returned by the TL.
--*/
{
XOSD xosd;
xosd = tlfunc(tlfGlobalDestroy, NULL, 0, (LONG)0);
return(xosd);
}
XOSD PASCAL
OSDInitTL(
TLFUNC tlfunc,
LPDBF lpdbf
)
/*++
Routine Description:
Initialize a transport layer. Send a pointer to a table of
debugger service functions to the TL, then tell it to initialize.
Arguments:
tlfunc - Supplies the address of the TL service function
lpdbf - Supplies the table of debugger service functions
Return Value:
Return status is supplied by the TL.
xosdNone if initialization succeeds, an xosd failure code if not.
--*/
{
XOSD xosd = xosdNone;
xosd = tlfunc ( tlfRegisterDBF, NULL, 0, (LONG) lpdbf );
if (xosd != xosdNone) {
return xosd;
}
xosd = tlfunc ( tlfGlobalInit, NULL, 0, (LONG) TLCallBack );
return xosd;
}
#if 0
XOSD PASCAL OSDTLGetInfo( TLFUNC tlfunc, LPGIS lpgis, UINT wLen) {
XOSD xosd = xosdNone;
xosd = tlfunc ( tlfGetInfo, NULL, wLen, (LONG) lpgis );
return xosd;
}
XOSD PASCAL OSDTLSetup( TLFUNC tlfunc, LSZ lszInit, UINT wLen, LPV lpv) {
XOSD xosd = xosdNone;
xosd = tlfunc ( tlfSetUIStruct, NULL, 0, (LONG) lpv );
if (xosd != xosdNone) {
return xosd;
}
xosd = tlfunc ( tlfSetup, NULL, wLen, (LONG) lszInit );
return xosd;
}
#endif // 0
XOSD PASCAL
OSDAddTL (
TLFUNC tlfunc,
LPHTL lphtl,
LPCH lpchInit
)
/*++
Routine Description:
Create and initialize a transport layer associated with the
service function lpfnsvcTL and add it to the list of osdebug's
available transport layers ( lltl ).
Arguments:
tlfunc - Supplies pointer to the transport layer service function
to be associated with the transport layer that is being
created.
lpdbf - Supplies pointer to the debugger services structure that
will be registered with the transport layer being created.
lphtl - Returns the transport layer handle.
Return Value:
xosdNone - Success.
xosdOutOfMemory - List manager was unable to allocate TL
or add it to the transport layer list ( lltl ).
Other xosd failure codes may be returned by the transport layer
if its initialization fails.
--*/
{
/***************************************************************************
* *
* IMPLEMENTATION: *
* *
* Use list manager to create a transport layer handle and add it *
* to the transport layer list ( lltl ). *
* *
* Call the transport layer service function ( lpfnsvcTL ) to *
* initialize the transport layer and to register the debugger *
* service functions ( lpdbf ). *
* *
***************************************************************************/
HTL htl;
LPTL lptl;
XOSD xosd = xosdNone;
AVS RemoteAvs;
assert ( tlfunc != NULL );
assert ( lpdbf != NULL );
assert ( lphtl != NULL );
htl = LLCreate ( lltl );
if ( htl == htlNull ) {
xosd = xosdOutOfMemory;
} else {
LLAdd ( lltl, htl );
lptl = LLLock ( htl );
lptl->tlfunc = tlfunc;
lptl->llpid = LLInit ( sizeof ( HPID ), llfNull, NULL, NULL );
if ( lptl->llpid == 0 ) {
xosd = xosdOutOfMemory;
}
if (xosd == xosdNone) {
xosd = tlfunc ( tlfInit, NULL, 0, (LONG) lpchInit );
}
if (xosd == xosdNone) {
xosd = tlfunc ( tlfConnect, NULL, 0, 0 );
}
if (xosd == xosdNone) {
xosd = tlfunc(tlfGetVersion, NULL, sizeof(Avs), (LONG)&RemoteAvs);
switch (xosd) {
case xosdNone:
// got version info for remote side of transport...
// verify it.
if (Avs.rlvt != RemoteAvs.rlvt ||
Avs.iApiVer != RemoteAvs.iApiVer) {
xosd = xosdBadRemoteVersion; // bogus version
}
*(MPT *)lpchInit = RemoteAvs.mpt;
break;
case xosdNotRemote:
// local transport, don't need to check ver
*(MPT *)lpchInit = RemoteAvs.mpt;
xosd = xosdNone;
break;
case xosdBadRemoteVersion:
default:
break; // pass error back after cleaning up
}
if (xosd != xosdNone) {
// version check failed, disconnect tl
// hpid cleanup is handled below
tlfunc( tlfDisconnect, NULL, 0, 0 );
}
}
LLUnlock ( htl );
if (xosd == xosdNone) {
*lphtl = htl;
} else {
LLDelete(lltl, (HLLE)htl);
}
}
return xosd;
}
XOSD PASCAL
OSDDeleteTL (
HTL htl
)
/*++
Routine Description:
Remove the transport layer (htl) from os debug's list of available
transport layers ( lltl ).
Arguments:
htl - A transport layer that has previously been returned by
OSDAddTL.
Return Value:
xosdNone - Success.
xosdTLInUse - The transport layer is still being used by
some pid. OSDDiscardTL must be called on all of the
pids using this particular em before OSDDeleteTL can
be called without error.
xosdInvalidTL - The transport layer handle ( htl ) is invalid.
--*/
{
/***************************************************************************
* *
* IMPLEMENTATION: *
* *
* Check the list of pids using this transport layer. If it is zero *
* indicating that no pids are using it, then call the list manager *
* to delete it from the list of available transport layers ( lltl ). *
* *
***************************************************************************/
XOSD xosd = xosdNone;
LPTL lptl;
assert ( htl != htlNull );
lptl = LLLock ( htl );
if ( LLSize ( lptl->llpid ) != 0 ) {
LLUnlock ( htl );
xosd = xosdTLInUse;
} else {
(*lptl->tlfunc)(tlfDestroy, NULL, 0, 0);
(*lptl->tlfunc)(tlfGlobalDestroy, NULL, 0, 0);
LLUnlock ( htl );
if ( !LLDelete ( lltl, (HLLE)htl ) ) {
xosd = xosdInvalidTL;
}
}
return xosd;
}
XOSD PASCAL
OSDGetAddr (
HPID hpid,
HTID htid,
ADR adr,
LPADDR lpaddr
)
/*++
Routine Description:
To get one of the special addresses in a process/thread which
the EM can supply.
Arguments:
hpid - The process
htid - The thread
adr - The address to get. One of the following.
adrCurrent - The the current address for the thread.
This is used to specify breakpoint
addresses, etc.
adrPC - The program counter of the thread.
adrBase - The frame base address of the thread.
adrStack - The current stack pointer of the thread.
adrData - The data area for the thread/process
adrBaseProlog - The frame base address will be fixed up as
if the prolog code of the existing function
were already executed. This requires that
the address passed in be the start of the
function.
adrTlsBase - The base of the thread local storage area.
lpaddr - Returns the requested address.
Return Value:
xosdNone - Success
Any error that may be generated by the emfGetAddr function
of the execution model associated with hpid:htid.
--*/
{
assert ( lpaddr != NULL );
if ( htid == htidNull && adr != adrCurrent ) {
_fmemset ( lpaddr, 0, sizeof ( ADDR ) );
return xosdNone;
}
else {
return CallEM ( emfGetAddr, hpid, htid, adr, lpaddr );
}
}
XOSD PASCAL
OSDIsStackSetup (
HPID hpid,
HTID htid,
LPADDR lpaddr
)
/*++
Routine Description:
Find out if the thread's stack is set up for the function
at the address supplied. Returns FALSE if the thread's PC
is in the function prolog.
The address must point to a function prolog, and the thread's
PC must be in that function, or this API's behaviour is undefined.
Arguments:
hpid - Supplies process
htid - Supplies thread
lpaddr - Supplies address of the beginning of a function.
Return Value:
xosdNone - Stack isn't setup
xosdContinue - The Stack is setup
--*/
{
assert ( lpaddr != NULL )
if ( htid == htidNull ) {
_fmemset ( lpaddr, 0, sizeof ( ADDR ) );
return xosdNone;
}
else {
return CallEM ( emfIsStackSetup, hpid, htid, 0, lpaddr );
}
}
XOSD PASCAL
OSDSetAddr (
HPID hpid,
HTID htid,
ADR adr,
LPADDR lpaddr
)
/*++
Routine Description:
Sets one of the addresses associated with a thread.
Arguments:
hpid - Supplies process
htid - Supplies thread
adr - Supplies id of the address to set, and may be
one of the following:
adrCurrent - The current address for the thread.
This is used to specify breakpoint
addresses, etc.
adrPC - The program counter of the thread.
adrBase - The frame base address of the thread.
adrStack - The current stack pointer of the thread.
adrData - The data area for the thread/process
adrBaseProlog - N/A ( can't be set )
adrTlsBase - N/A ( can't be set )
lpaddr - Supplies the address to set the hpid:htid with
Return Value:
xosdNone - Success.
Any error that may be generated by the emfSetAddr function
of the execution model associated with hpid:htid.
--*/
{
assert ( lpaddr != NULL );
if ( htid == htidNull && adr != adrCurrent ) {
return xosdInvalidThread;
}
else {
return CallEM ( emfSetAddr, hpid, htid, adr, lpaddr );
}
}
XOSD PASCAL
OSDReadReg (
HPID hpid,
HTID htid,
UINT wIndex,
LPV lpv
)
/*++
Routine Description:
Read a register in a debuggee thread
Arguments:
hpid - Supplies process
htid - Supplies thread
wIndex - Supplies register index
lpv - Returns register value
Return Value:
xosdNone - Success
The EM may return an xosd failure status if wIndex is invalid
or for other reasons.
--*/
{
assert ( lpv != NULL );
return CallEM ( emfGetReg, hpid, htid, wIndex, lpv );
}
XOSD PASCAL
OSDWriteReg (
HPID hpid,
HTID htid,
UINT wIndex,
LPV lpv
)
/*++
Routine Description:
Write a register in a debuggee thread
Arguments:
hpid - Supplies process
htid - Supplies thread
wIndex - Supplies register index
lpv - Supplies register value
Return Value:
xosdNone - Success
The EM may return an xosd failure status if wIndex is invalid
or for other reasons.
--*/
{
return CallEM ( emfSetReg, hpid, htid, wIndex, lpv );
}
XOSD PASCAL
OSDSetFrameContext (
HPID hpid,
HTID htid,
UINT wIndex,
LPV lpv
)
/*++
Routine Description:
Specify which frame to use to get context information in the EM
Arguments:
hpid - The process
htid - The thread
wIndex - The frame number; Current is 0; caller is 1, etc.
Return Value:
xosdNone - Success
Any error that may be generated by the emfSetFrameContext
of the execution model associated with hpid:htid.
--*/
{
return CallEM ( emfSetFrameContext, hpid, htid, wIndex, lpv );
}
XOSD PASCAL
OSDFrameReadReg (
HPID hpid,
HTID htid,
UINT wIndex,
LPV lpv
)
/*++
Routine Description:
Read the register specified by wIndex in the register set
specified by hpid:htid, and the frame which was set by a prior
call to OSDSetFrameContext.
Arguments:
hpid - Supplies process
htid - Supplies thread
wIndex - Supplies register index
lpv - Returns register value
Return Value:
xosdNone - Success
Any error that may be generated by the emfFrameRegValue
function of the execution model associated with hpid:htid.
--*/
{
assert ( lpv != NULL );
return CallEM ( emfFrameRegValue, hpid, htid, wIndex, lpv );
}
XOSD PASCAL
OSDFrameWriteReg (
HPID hpid,
HTID htid,
UINT wIndex,
LPV lpv
)
/*++
Routine Description:
Write the register specified by wIndex in the register set
specified by hpid:htid, and the frame which was set by a prior
call to OSDSetFrameContext.
Arguments:
hpid - Supplies process
htid - Supplies thread
wIndex - Supplies register index
lpv - Supplies register value
Return Value:
xosdNone - Success
Any error that may be generated by the emfFrameSetReg function
of the execution model associated with hpid:htid.
--*/
{
return CallEM ( emfFrameSetReg, hpid, htid, wIndex, lpv );
}
XOSD PASCAL
OSDReadFlag (
HPID hpid,
HTID htid,
UINT wIndex,
LPV lpv
)
/*++
Routine Description:
Read the flag specified by wIndex in the processor flag set
for hpid:htid pair.
Arguments:
hpid - Supplies process
htid - Supplies thread
wIndex - Supplies register index
lpv - Returns value
Return Value:
xosdNone - Success
Any error that may be generated by the emfGetFlag function
of the execution model associated with hpid:htid.
--*/
{
assert ( lpv != NULL );
return CallEM ( emfGetFlag, hpid, htid, wIndex, lpv );
}
XOSD PASCAL
OSDWriteFlag (
HPID hpid,
HTID htid,
UINT wIndex,
LPV lpv
)
/*++
Routine Description:
Write the flag specified by wIndex in the processor flag set
for hpid:htid pair.
Arguments:
hpid - Supplies process
htid - Supplies thread
wIndex - Supplies register index
lpv - Supplies new value
Return Value:
xosdNone - Success
Any error that may be generated by the emfSetFlag function
of the execution model associated with hpid:htid.
--*/
{
return CallEM ( emfSetFlag, hpid, htid, wIndex, lpv );
}
XOSD PASCAL
OSDProgramFree (
HPID hpid
)
/*++
Routine Description:
Terminate and unload the program being debugged in process hpid.
This does not guarantee termination of child processes.
Arguments:
hpid - Supplies the process to kill
Return Value:
xosdNone - Success
Any error that can be generated by emfProgramFree
--*/
{
assert ( hpid != NULL);
return CallEM ( emfProgramFree, hpid, htidNull, 0, NULL );
}
#if 0
/**** OSDGETCURRENTEM - Get the execution model for hpid:htid ****
* *
* PURPOSE: *
* *
* To get the handle for the current execution model associated *
* with hpid:htid. *
* *
* *
* INPUTS: *
* *
* hpid - The process *
* htid - The thread *
* lphem - A far pointer to the location to stuff the handle to *
* the execution model. *
* *
* OUTPUTS: *
* *
* Return Value - *
* *
* xosdNone - Success *
* xosdInvalidEM - No valid execution model for this hpid:htid *
* *
* *lphem - A handle to the current execution model for hpid:htid. *
* *
* IMPLEMENTATION: *
* *
* Look up the execution model field in the structure reference by *
* htid and stuff it into *lphem. *
* *
***************************************************************************/
XOSD PASCAL OSDGetCurrentEM ( HPID hpid, HTID htid, LPHEM lphem ) {
LPPID lppid;
HIND hodem = hmemNull;
LPEMP lpemp;
LPEM lpem;
Unreferenced( htid );
assert ( lphem != NULL );
lppid = LLLock ( hpid );
if ( lppid == NULL ) {
return xosdInvalidEM;
}
if ( lppid->lastmodel == CEXM_MDL_native ) {
lpemp = LLLock ( lppid->hempNative );
*lphem = lpemp->hem;
LLUnlock ( lppid->hempNative );
}
else {
while ( hodem = LLNext ( llem, hodem ) ) {
lpem = LLLock ( hodem );
if ( lpem->model == lppid->lastmodel ) {
*lphem = hodem;
}
LLUnlock ( hodem );
}
}
LLUnlock ( hpid );
return xosdNone;
}
/**** OSDNATIVEONLY - Force the use of only the native em for hpid:htid ****
* *
* PURPOSE: *
* *
* To allow the debugger to force the use of the native em even where *
* there is non-native code (ie pcode) *
* *
* INPUTS: *
* *
* hpid - The process *
* htid - The thread *
* fNat - true to set native only, false to return to normal mode *
* of handling multiple em's *
* *
* OUTPUTS: *
* *
* Return Value - *
* *
* xosdNone - Success *
* *
* IMPLEMENTATION: *
* *
***************************************************************************/
XOSD PASCAL OSDNativeOnly ( HPID hpid, HTID htid, BOOL fNat ) {
HEMP hemp;
HEMP hempTmp = hemNull;
XOSD xosd = xosdNone;
LPEMP lpemp;
LPPID lppid;
assert ( hpid != NULL );
lppid = LLLock ( hpid );
if ( lppid->fNative == fNat ) {
LLUnlock((HLLE)hpid);
return xosd;
}
else if ( fNat ) {
// get the native em
hemp = lppid->hempNative;
// tell all of the non-native models to disconnect, cleanup or whatever
// they need to do
while ( ( hempTmp = LLNext ( lppid->llemp, hempTmp ) ) && hempTmp != hemp ) {
lpemp = LLLock ( hempTmp );
xosd = (lpemp->emfunc) ( emfDetach, hpid, htid, 0, (LONG) 0 );
LLUnlock ( hempTmp );
}
// we then move the native em to the head of the list, forcing it to be called
// first, until fNative is reset
LLRemove ( lppid->llemp, hemp );
LLAddHead ( lppid->llemp, hemp );
// if current model used to be non-native, send notification
if ( lppid->lastmodel != CEXM_MDL_native ) {
OSDDoCallBack ( dbcEmChange, hpid, htid, lppid->lastmodel, CEXM_MDL_native, (LONG) 0 );
lppid->lastmodel = CEXM_MDL_native;
}
// finally, set our global flag to true
lppid->fNative = fNat;
}
else {
// put the native em back at the end of the list
hemp = lppid->hempNative;
LLRemove ( lppid->llemp, hemp );
LLAdd ( lppid->llemp, hemp );
// tell all of the non-native models that they can re-connect
xosd = xosdPunt;
while ( ( hempTmp = LLNext ( lppid->llemp, hempTmp ) ) && hempTmp != hemp &&
xosd == xosdPunt) {
WORD wModel;
lpemp = LLLock ( hempTmp );
xosd = (lpemp->emfunc) ( emfAttach, hpid, htid, 0, (LONG) (LPV) &wModel );
if ( xosd == xosdNone ) {
// send a dbcEmChange notification
OSDDoCallBack ( dbcEmChange, hpid, htid, lppid->lastmodel, wModel, (LONG) 0 );
lppid->lastmodel = wModel;
}
LLUnlock ( hempTmp );
}
if ( xosd == xosdPunt ) xosd = xosdNone;
// reset our global flag to false
lppid->fNative = fNat;
}
LLUnlock ( hpid );
return xosd;
}
/**** OSDUSEEM - Add the execution model to the process' list of ems ****
* *
* PURPOSE: *
* *
* To tell osdebug that it should pass commands and callbacks for the *
* process hpid through the execution model whose handle is hem. *
* *
* INPUTS: *
* *
* hpid - The process *
* hem - A handle to the execution model *
* *
* OUTPUTS: *
* *
* Return Value - *
* *
* xosdNone - Success *
* xosdOutOfMemory - Not enough memory to create the reference *
* to the execution model in the process structure. *
* xosdInvalidEM - tried to add a native em when one was already *
* present *
* *
* IMPLEMENTATION: *
* *
* *
***************************************************************************/
XOSD PASCAL OSDUseEM ( HPID hpid, HEM hem ) {
LPPID lppid;
HEMP hemp = hemNull;
LPEM lpem;
LPEMP lpemp;
HPID hpidem;
LPHPID lphpid;
assert ( hem != hemNull );
assert ( hpid != NULL );
// Add hem to pid's hem list
lppid = LLLock ( hpid );
while ( hemp = LLNext ( lppid->llemp, hemp ) ) {
lpemp = LLLock ( hemp );
if ( lpemp->hem == hem ) {
// this is an error, cannot add the same model twice
LLUnlock ( hemp );
LLUnlock ( hpid );
return xosdInvalidEM;
}
LLUnlock ( hemp );
}
hemp = LLCreate ( lppid->llemp );
if ( hemp == hmemNull ) {
LLUnlock ( hpid );
return xosdOutOfMemory;
}
lpem = LLLock ( hem );
if ( lpem->emtype ) {
LLAddHead ( lppid->llemp, hemp );
}
else {
// new native em
LLAdd ( lppid->llemp, hemp );
lppid->hempNative = hemp;
}
LLUnlock ( hpid );
// add hpid to hem in llem
hpidem = LLCreate ( lpem->llhpid );
if ( hpidem == hemNull ) {
return xosdOutOfMemory;
}
lphpid = LLLock ( hpidem );
// puts hpid in node
*lphpid = hpid;
LLUnlock ( hpidem );
LLUnlock ( hem );
LLAdd ( lpem->llhpid, hpidem );
return xosdNone;
}
/**** OSDDISCARDEM - Remove the execution model from the proc's list ****
* *
* PURPOSE: *
* *
* To remove the execution model whose handle is hem from the *
* process hpid's list of available execution models. *
* *
* INPUTS: *
* *
* hpid - A handle to the process *
* hem - A handle to the execution model. *
* *
* OUTPUTS: *
* *
* Return Value - *
* *
* xosdNone - Success *
* xosdInvalidEM - There is no execution model associated *
* with hem. *
* *
* IMPLEMENTATION: *
* *
* *
***************************************************************************/
XOSD PASCAL OSDDiscardEM ( HPID hpid, HEM hem ) {
LPPID lppid;
HEM hemdis;
LPEM lpem;
HEMP hemp = hemNull;
HEMP hempdis;
LPEMP lpemp;
HPID hpiddis;
XOSD xosd = xosdNone;
assert ( hpid != NULL );
// find the hem in the lppid's list
lppid = LLLock ( hpid );
lpemp = LLLock ( lppid->hempNative );
if ( lpemp->hem == hem ) {
// trying to remove the native em
lppid->hempNative = 0;
}
LLUnlock ( lppid->hempNative );
while (hemp = LLNext ( lppid->llemp, hemp ) ) {
lpemp = LLLock ( hemp );
if ( lpemp->hem == hem ) {
hemdis = hem;
hempdis = hemp;
}
LLUnlock ( hemp );
}
if ( ! hemdis ) {
// no em found, return error
xosd = xosdInvalidEM;
}
else {
// delete the em from the hpid, then remove hpid from em in llem
LLDelete ( lppid->llemp, (HLLE)hempdis );
lpem = LLLock ( hemdis );
if ( hpiddis = LLFind ( lpem->llhpid, 0, &hpid, 0L ) ) {
LLDelete ( lpem->llhpid, (HLLE)hpiddis );
}
else {
// hpid not found: internal cosistancy error
assert ( FALSE );
}
LLUnlock ( hemdis );
}
LLUnlock ( hpid );
return xosd;
}
#endif // 0
XOSD PASCAL
OSDUnassemble (
HPID hpid,
HTID htid,
LPSDI lpsdi
)
/*++
Routine Description:
Disassemble one machine instruction. The address of the
instruction to disassemble is in the SDI structure pointed
to by lpsdi.
Arguments:
hpid - Supplies process to get data from
htid - Supplies thread
lpsdi - Supplies and Returns disassembly info
Return Value:
xosdNone for success, other xosd codes describe the reason
for failure.
When the call succeeds, lpsdi->lsz will point to a static
string containing the disassembled instruction. The SDI
structure contains ADDR fields which will contain effective
addresses computed for the instruction, and int fields which
describe the length of each of the parts of the disassembly
text, to facilitate formatting the text for display.
The addr field will be updated to point to the next instruction
in the stream.
--*/
{
assert ( lpsdi != NULL );
return CallEM ( emfUnassemble, hpid, htid, 0, lpsdi );
}
XOSD PASCAL
OSDAssemble (
HPID hpid,
HTID htid,
LPADDR lpaddr,
LSZ lsz
)
/*++
Routine Description:
Assemble an instruction into the debuggee.
Arguments:
hpid - Supplies process
htid - Supplies thread (optional?)
lpaddr - Supplies address to assemble to
lsz - Supplies instruction text
Return Value:
xosdNone for success, other xosd codes describe cause of failure.
--*/
{
XOSD xosd = xosdNone; // [00]
// [00]
(void)CallEM ( emfSetAddr, hpid, htid, adrCurrent, lpaddr ); // [00]
// [00]
xosd = CallEM ( emfAssemble, hpid, htid, 0, lsz ); // [00]
if (xosd != xosdNone) {
return xosd;
}
// [00]
(void)CallEM ( emfGetAddr, hpid, htid, adrCurrent, lpaddr ); // [00]
// [00]
return xosd; // [00]
}
#if 0
XOSD PASCAL OSDGetPrevInst (
HPID hpid,
HTID htid,
LPADDR lpaddr
) {
return CallEM ( emfGetPrevInst, hpid, htid, 0, lpaddr );
}
#endif
XOSD PASCAL
OSDGetDebugMetric (
HPID hpid,
HTID htid,
MTRC mtrc,
LPVOID lpv
)
/*++
Routine Description:
This is a facility for getting various information about
the execution model associated with a process.
Arguments:
hpid - Supplies process
htid - Supplies thread (optional for some metrics)
mtrc - Supplies metric to query, see od.h
lpv - Returns requested info
Return Value:
xosdNone for success, other xosd codes describe the cause of failure.
lpv must point to a buffer of sufficient size to receive the info.
--*/
{
return CallEM ( emfMetric, hpid, htid, mtrc, lpv );
}
#if 0
/**** OSDGETOBJLENGTH - Get the length of the object containing *lpaddr ****
* *
* PURPOSE: Get the lenth of a given linear exe object *
* *
* INPUTS: *
* *
* hpid - A handle to the process. *
* htid - A handle to the thread. *
* lplBase - A pointer to a long in which to place the base address *
* lplLen - A pointer to a long in which to place the length *
* *lpaddr - An address within the object in question. *
* *
* OUTPUTS: *
* *
* Return Value - *
* *
* xosdNone - Success. *
* Any value that can be returned by the Get object length *
* of the execution model called. *
* *
* *
* *lplBase - The base address of the object. ( In a segmented *
* environment this will always be 0 ). *
* *lplLen - The length of the object. *
* *
* IMPLEMENTATION: *
* *
* Package the information in a gol ( Get Object Length ) package *
* and pass it to the most specific execution model associated *
* with the hpid:htid pair. *
* *
* *
***************************************************************************/
XOSD PASCAL OSDGetObjLength (
HPID hpid,
HTID htid,
LPL lplBase,
LPL lplLen,
LPADDR lpaddr ) {
GOL gol;
gol.lplBase = lplBase;
gol.lplLen = lplLen;
gol.lpaddr = lpaddr;
assert ( lpaddr != NULL );
return CallEM ( emfGetObjLength, hpid, htid, 0, &gol );
}
#endif // 0
XOSD PASCAL
OSDGetMsgMap (
HPID hpid,
HTID htid,
LPMSGMAP* MsgMap
)
/*++
Routine Description:
Get a pointer to MSGMAP structure for the EM associated with
hpid. This is a structure describing the window messages
supported by the EM. Not implemented for OS's without messages.
Arguments:
hpid - Supplies process
htid - Supplies thread (not used)
MsgMap - Returns pointer to MSGMAP structure
Return Value:
xosdNone for success, other xosd codes describe the cause of
failure. If a Win32 EM is associated with hpid, this always succeeds.
--*/
{
return CallEM ( emfGetMsgMap, hpid, htid, 0, MsgMap );
}
XOSD PASCAL
OSDGetModuleList (
HPID hpid,
HTID htid,
BOOL Flat,
LSZ ModuleName,
LPMODULE_LIST * ModuleList
)
/*++
Routine Description:
Get the list of modules loaded in a process, or look up one
module. The returned module list contains one entry per
segment per module.
N.B. The function will look up flat or segmented modules,
but not both at the same time. This is not neccessarily
desirable behaviour.
Arguments:
hpid - Supplies process
htid - Supplies thread (not used)
Flat - Supplies TRUE to get flat modues, FALSE to
get segmented ones.
ModuleName - Supplies optional name of module to look for.
If this arg is NULL, all modules will be found.
ModuleList - Returns list of modules
Return Value:
xosdNone if successful. Other xosd codes indicate the
cause of failure.
--*/
{
MODULE_LIST_REQUEST Request;
Request.Flat = Flat;
Request.Name = ModuleName;
Request.List = ModuleList;
return CallEM ( emfGetModuleList, hpid, htid, 0, &Request );
}
#if 0
/**** OSDGetError - Get the Text of an error msg for a particular hpid/htid
*
* PURPOSE: Get the OS specific error msg for a pid and tid from the em.
* The debugger is responsible for providing a 12 byte buffer
* for lszErr, and a 256 byte buffer for lszErrText
*
* INPUTS:
*
* hpid - A handle to the process.
* htid - A handle to the thread.
* lpwErrNum - the error #
* lszErr - error # text string (ex. "DMOS001" )
* lszErrText - human readable text string (ex. "Tried to load OS2 app under Windows")
*
* OUTPUTS:
*
* Return Value -
*
* xosdNone - if msg was available
* xosdSyntax - if no msg available
*
* IMPLEMENTATION:
*
***************************************************************************/
XOSD PASCAL OSDGetError ( HPID hpid,
HTID htid,
LPW lpwErrNum,
LSZ lszErr,
LSZ lszErrText ) {
GET get;
get.lpwErrNum = lpwErrNum;
get.lszErr = lszErr;
get.lszErrText = lszErrText;
return CallEM ( emfGetError, hpid, htid, 0, &get );
}
/**** OSDGETFRAME - Get the the frame previous to the frame *lpaddr ****
* *
* PURPOSE: *
* *
* Put the frame on the stack previous to the frame specified by *
* *lpaddr into *lpaddr. *
* *
* INPUTS: *
* *
* hpid - A handle to the process. *
* htid - A handle to the thread. *
* *lpaddr - The current frame. *
* lpaddr - A pointer to the return frame address. *
* *
* OUTPUTS: *
* *
* Return Value - *
* *
* xosdNone - Success. *
* Any value that can be returned by the Get Frame Function *
* of the execution model called. *
* *
* *lpaddr - The previous frame address. *
* *
* IMPLEMENTATION: *
* *
* Send the Get Frame command to the execution model. *
* *
* *
***************************************************************************/
XOSD PASCAL OSDGetFrame ( HPID hpid, HTID htid, LPADDR lpaddr ) {
return CallEM ( emfGetFrame, hpid, htid, 0, lpaddr );
}
/**** OSDGETRETURN - Get the return address for the frame *lpaddrFrame ****
* *
* PURPOSE: *
* *
* Put the return addres of the frame into *lpaddrPC. *
* *
* INPUTS: *
* *
* hpid - A handle to the process. *
* htid - A handle to the thread. *
* *lpaddrFrame - The current frame. *
* *lpaddrPC - The code addres of the current frame. *
* lpaddrPC - A pointer to the return address. *
* *
* OUTPUTS: *
* *
* Return Value - *
* *
* xosdNone - Success. *
* Any value that can be returned by the Get Return Function *
* of the execution model called. *
* *
* *lpaddr - The previous frame address. *
* *
* IMPLEMENTATION: *
* *
* Send the current addres of the htid to the frame. Send the *
* lpaddrPC into the execution model with the get return command. *
* *
* *
***************************************************************************/
XOSD PASCAL OSDGetCaller (
HPID hpid,
HTID htid,
FCT fct,
LPADDR lpaddrFrame,
LPADDR lpaddrPC ) {
(void)CallEM ( emfSetAddr, hpid, htid, adrCurrent, lpaddrFrame );
return CallEM ( emfGetCaller, hpid, htid, fct, lpaddrPC );
}
/**** OSDSAVEREGS - Save the register set of the thread ****
* *
* PURPOSE: *
* *
* Save the register set of the thread htid in an allocated handle *
* that is returned in *lphmem. *
* *
* INPUTS: *
* *
* hpid - A handle to the process. *
* htid - A handle to the thread. *
* lphmem - A pointer in which to return the register buffer. *
* *
* OUTPUTS: *
* *
* Return Value - *
* *
* xosdNone - Success. *
* Any value that can be returned by the Save Register Function *
* of the execution model called. *
* *
* *lphmem - The buffer in which the registers are saved. *
* *
* IMPLEMENTATION: *
* *
* Call the execution model to save the registers. *
* *
* *
***************************************************************************/
XOSD PASCAL OSDSaveRegs ( HPID hpid, HTID htid, LPHIND lphmem ) {
return CallEM ( emfSaveRegs, hpid, htid, 0, lphmem );
}
/**** OSDRESTORREGS - Restore the registers of the thread from hmem ****
* *
* PURPOSE: *
* *
* Restore the register set(s) of the thread htid with the values *
* save by OSDSaveRegs in hmem. *
* *
* INPUTS: *
* *
* hpid - A handle to the process. *
* htid - A handle to the thread. *
* hmem - A handle to a valid register set for the thread. *
* *
* OUTPUTS: *
* *
* Return Value - *
* *
* xosdNone - Success. *
* Any value that can be returned by the Restore Register Function*
* of the execution model called. *
* *
* IMPLEMENTATION: *
* *
* Call the execution model to restore the registers. *
* *
* *
***************************************************************************/
XOSD PASCAL OSDRestoreRegs ( HPID hpid, HTID htid, HIND hmem ) {
return CallEM ( emfRestoreRegs, hpid, htid, 0, (LPV) hmem );
}
#ifdef KBDMON
/**** OSDKBDRECORD - turn keyboard recording on or off ****
* *
* PURPOSE: *
* *
* Call the EM to set or clear the keyboard recording flag *
* *
* INPUTS: *
* *
* hpid - A handle to the process. *
* htid - A handle to the thread. *
* fOn - new value for the flag *
* *
* OUTPUTS: *
* *
* Return Value - *
* *
* xosdNone - Success. *
* *
* IMPLEMENTATION: *
* *
* Call the execution model to set or clear the flag *
* *
* *
***************************************************************************/
XOSD PASCAL OSDKbdRecord ( HPID hpid, HTID htid, BOOL fOn ) {
return CallEM ( emfKbdRecord, hpid, htid, fOn, NULL );
}
/**** OSDKBDPLAY - play back keyboard information ****
* *
* PURPOSE: *
* *
* Call the EM to play back keyboard string *
* *
* INPUTS: *
* *
* hpid - A handle to the process. *
* htid - A handle to the thread. *
* pszPlay - string to process *
* *
* OUTPUTS: *
* *
* Return Value - *
* *
* xosdNone - Success. *
* *
* IMPLEMENTATION: *
* *
* Call the execution model to play the string *
* *
* *
***************************************************************************/
XOSD PASCAL OSDKbdPlay ( HPID hpid, HTID htid, LSZ lszPlay ) {
return CallEM ( emfKbdPlay, hpid, htid, 0, (LPV)lszPlay );
}
#endif // KBDMON
#endif // 0
XOSD PASCAL
OSDGetRegDesc (
HPID hpid,
HTID htid,
UINT iReg,
RD FAR * lprd
)
/*++
Routine Description:
Get the internal description of what a specific register looks
like. This is provided for general UI interfaces. See the
RD structure for more info.
Arguments:
hpid - Supplies process
htid - Supplies thread (optional?)
iReg - Supplies index of register
lprd - Returns requested info in an RD structure
Return Value:
xosdNone. Results are undefined if iReg is out of range.
--*/
{
return CallEM ( emfGetRegStruct, hpid, htid, iReg, lprd );
}
XOSD PASCAL
OSDGetFlagDesc (
HPID hpid,
HTID htid,
UINT iFlag,
FD FAR * lpfd
)
/*++
Routine Description:
Get the internal description of what a specific flag looks
like. This is provided for general UI interfaces.
Arguments:
hpid - Supplies process
htid - Supplies thread (unused?)
iReg - Supplies index of requested flag
lprd - Returns FD structure describing flag
Return Value:
xosdNone. If iReg is out of range, behaviour is undefined.
--*/
{
return CallEM ( emfGetFlagStruct, hpid, htid, iFlag, lpfd );
}
XOSD PASCAL
OSDRegisterEmi (
HPID hpid,
HTID htid,
HEMI hemi,
LSZ lsz
)
/*++
Routine Description:
Register an EMI and filename with the EM. This hooks up the
symbol table info for a module to the EM's representation of
the module in the process.
Arguments:
hpid - Supplies process
htid - Supplies thread (unused)
hemi - Supplies handle from SH to symbolic info
lsz - Supplies the name of the module
Return Value:
xosdNone on success. Current implementation never reports failure.
--*/
{
REMI remi;
remi.hemi = hemi;
remi.lsz = lsz;
return CallEM ( emfRegisterEmi, hpid, htid, 0, &remi );
}
/***************************************************************************
* *
* Services provided for execution model and transport layer *
* *
***************************************************************************/
XOSD PASCAL LOADDS
EMCallBackDB (
DBC dbc,
HPID hpid,
HTID htid,
DWORD wModel,
DWORD cb,
LPV lpv
)
/*++
Routine Description:
Send callback messages from an execution model to the debugger.
The messages get passed through all intervening higher-level
execution models.
If dbc is a dbco value, it creates the appropriate thread or
process and returns the hpid or htid in *lpv.
Otherwise, it calls OSDCallbackToEM to query all of the higher
level EM's associated with the process. If none of them
handled the callback, it then calls the debugger's callback
function via OSDDoCallback.
Arguments:
dbc - Supplies the callback message
hpid - Supplies handle to the process
htid - Supplies handle to the thread
wModel - Supplies index of EM initiating the callback
cb - Supplies the number of bytes pointed to by lpv
lpv - Supplies data associated with the callback,
Returns data for dbco callbacks.
Return Value:
xosdNone - Success
Any value that can be returned by the debugger or higher
level execution models.
--*/
{
XOSD xosd = xosdNone;
//
// Several threads can execute this, so we protect it with a critical
// section.
//
EnterCriticalSection( &CallbackCriticalSection );
switch ( dbc ) {
case dbcoCreateThread:
xosd = CreateThd ( hpid, htid, &htid );
*( (LPHTID) lpv) = htid;
goto Return;
//return xosd;
case dbcoNewProc: {
LPPID lppid = LLLock ( (HLLE)hpid );
HPID hpidT = hpid;
LPEMP lpemp = LLLock ( (HLLE)(lppid->hempNative) );
xosd = CreateProc (
lppid->lpfnsvcCC,
lpemp->hem,
lppid->htl,
&hpid
);
*( (LPHPID) lpv) = hpid;
LLUnlock ( (HLLE)(lppid->hempNative) );
LLUnlock ( (HLLE)hpidT );
}
goto Return;
//return xosd;
}
// hit all of the EMs with the DoCallback, a la CallEM,
// hitting the debugger last
xosd = OSDDoCallBackToEM ( dbc, hpid, htid, cb, (LONG) lpv );
// if xosd is xosdPunt then all non-native EMs punted on the notification
if ( xosd == xosdPunt ) {
xosd = OSDDoCallBack ( dbc, hpid, htid, wModel, cb, (LONG) lpv );
}
Return:
LeaveCriticalSection( &CallbackCriticalSection );
return xosd;
}
XOSD PASCAL LOADDS
EMCallBackTL (
TLF wCmd,
HPID hpid,
DWORD cb,
LPV lpv
)
/*++
Routine Description:
Send messages from the execution model (native) to the transport layer.
Arguments:
wCmd - Supplies the message
hpid - Supplies process
cb - Supplies the size of the buffer at lpv, in bytes
lpv - Supplies or Returns data specific to the command
Return Value:
xosdNone for success, TL may return other xosd codes to
describe failure.
--*/
{
return CallTL ( wCmd, hpid, cb, lpv );
}
XOSD PASCAL LOADDS
EMCallBackNT (
EMF emf,
HPID hpid,
HTID htid,
DWORD cb,
LPV lpv
)
/*++
Routine Description:
Provides native em services to higher level EMs. Sends messages
from the execution model (non-native) to the native execution model
for the process hpid.
Arguments:
emf - Supplies the execution model function number
hpid - Supplies process
htid - Supplies thread
cb - Supplies size of buffer at lpv in bytes
lpv - Supplies and Returns data for EM service
Return Value:
xosdNone - Success
xosdInvalidPID - hpid is not a handle to a process.
Any value that can be returned by the native execution model.
--*/
{
XOSD xosd = xosdNone;
LPPID lppid;
HEMP hemp;
LPEMP lpemp;
lppid = LLLock ( (HLLE)hpid );
if ( lppid == NULL ) {
return xosdInvalidPID;
}
hemp = lppid->hempNative;
LLUnlock ( (HLLE)hpid );
lpemp = LLLock ( (HLLE)hemp );
xosd = (lpemp->emfunc) ( emf, hpid, htid, cb, (LONG) lpv );
LLUnlock ( (HLLE)hemp );
return xosd;
}
XOSD PASCAL LOADDS
EMCallBackEM (
EMF emf,
HPID hpid,
HTID htid,
DWORD wModel,
DWORD cb,
LPV lpv
)
/*++
Routine Description:
Provides EM services to other EMs. Sends messages from one
non-native EM to the next EM in the chain for the process hpid.
Arguments:
emf - Supplies EM function number
hpid - Supplies handle to the process
htid - Supplies handle to the thread
wModel - Supplies EM # of calling EM
cb - Supplies size in bytes of buffer at lpv.
lpv - Supplies and Returns data for EM service
Return Value:
xosd code returned by the EM that handles the service request.
--*/
{
XOSD xosd = xosdNone;
LPPID lppid;
HEMP hemp = 0;
HEMP hempnext = 0;
LPEMP lpemp;
assert ( hpid != NULL );
//native ems can never make this callback!
assert ( wModel != CEXM_MDL_native );
lppid = LLLock ( (HLLE)hpid );
if ( lppid == NULL ) {
return xosdInvalidPID;
}
while ( hemp = LLNext ( (HLLI)(lppid->llemp), (HLLE)hemp ) ) {
lpemp = LLLock ( (HLLE)hemp );
if ( lpemp->model == wModel ) {
hempnext = LLNext ( (HLLI)(lppid->llemp), (HLLE)hemp );
break;
}
LLUnlock ( (HLLE)hemp );
}
assert ( hempnext != 0 );
lpemp = LLLock ( (HLLE)hempnext );
xosd = (lpemp->emfunc) ( emf, hpid, htid, cb, (LONG) lpv );
LLUnlock ( (HLLE)hempnext );
LLUnlock ( (HLLE)hpid );
return xosd;
}
XOSD PASCAL LOADDS
TLCallBack (
HPID hpid,
UINT cb,
LPV lpv
)
/*++
Routine Description:
Call the native execution model for the process hpid with the
package sent from the transport layer. This is how the DM
sends things to its native EM.
Arguments:
hpid - Supplies handle to the process
cb - Supplies size in bytes of the packet
lpv - Supplies the packet
Return Value:
xosdNone - Success
Any return value that can be generated by a native execution model.
--*/
{
XOSD xosd = xosdNone;
LPEMP lpemp;
LPPID lppid;
EMFUNC emfunc;
assert ( hpid != NULL );
//NOTENOTE a-kentf this probably doesn't have to Unlock before calling
lppid = LLLock ( (HLLE)hpid );
lpemp = LLLock ( (HLLE)(lppid->hempNative) );
emfunc = lpemp->emfunc;
LLUnlock ( (HLLE)(lppid->hempNative) );
LLUnlock ( (HLLE)hpid );
xosd = (*emfunc)( emfDebugPacket, hpid, htidNull, cb, (LONG) lpv );
return xosd;
}
/***************************************************************************
* *
* Internal Support functions *
* *
***************************************************************************/
/**** CallEM - Call the execution model for hpid:htid ****
* *
* PURPOSE: *
* *
* This function multiplexes on the hpid and htid values to call *
* the most specific execution model possible. *
* *
* INPUTS: *
* *
* emf, wValue, lValue, lpxosd: These are all just passed through *
* to the actual execution model service function. *
* *
* hpid - This is the process that the execution model service *
* function is to handle. If it is null, the first execution *
* model that was registered with osdebug is called. *
* Hpid must not be invalid. *
* *
* htid - This is the thread that the execution model service *
* function is to handle. If it is null, the native execution *
* model for the pid is called. Htid must not be invalid. *
* *
* OUTPUTS: *
* *
* Return Value - This will return whatever the execution model *
* service function that it calls returns. *
* *
* *lpxosd - The errors returned here are those defined by the *
* execution model service function that was called. *
* *
* IMPLEMENTATION: *
* *
* Find the most specific em available. This is the current em *
* for the pid:tid if both pid & tid are non-Null, the native *
* execution model for the pid if the tid is null but the pid is *
* non-Null, or the first em installed if both pid & tid are null. *
* *
* *
***************************************************************************/
XOSD
CallEM(
EMF emf,
HPID hpid,
HTID htid,
DWORD wValue,
LPV lpv
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
XOSD xosd = xosdNone;
HEMP hemp;
LPPID lppid;
LPEMP lpemp;
HLLI llemx;
if ( hpid == NULL ) {
// get oldest native EM.
if (llem != NULL) {
hemp = (HEMP)LLLast ( llemx = llem );
} else {
return xosdUnknown;
}
if (hemp == NULL) {
return xosdUnknown;
}
} else {
lppid = LLLock ( (HLLE)hpid );
assert ( lppid != NULL );
hemp = (HEMP)LLNext ( (llemx = lppid->llemp), NULL );
LLUnlock ( (HLLE)hpid );
}
lpemp = LLLock ( (HLLE)hemp );
if (lpemp->emfunc != NULL) {
xosd = (lpemp->emfunc)( emf, hpid, htid, wValue, (LONG) lpv );
} else {
xosd = xosdUnknown;
}
LLUnlock ( (HLLE)hemp );
if (xosd == xosdPunt) {
hemp = (HEMP)LLNext ( llemx, (HLLE)hemp );
do {
lpemp = LLLock ( (HLLE)hemp );
xosd = (lpemp->emfunc) ( emf, hpid, htid, wValue, (LONG) lpv );
LLUnlock ( (HLLE)hemp );
} while (xosd == xosdPunt &&
(hemp = (HEMP)LLNext ( llemx, (HLLE)hemp )) );
if (xosd == xosdPunt) {
xosd = xosdUnsupported;
}
}
return xosd;
}
/**** CallTL - Call the transport layer for hpid ****
* *
* PURPOSE: *
* *
* *
* INPUTS: *
* *
* tlf, htid, wValue, lpv - These are all just passed *
* through to the actual transport layer service function. *
* *
* hpid - This is the process that the transport layer service *
* function is to handle. If it is null, the first transport *
* layer that was registered with osdebug is called. *
* Hpid must not be invalid. *
* *
* OUTPUTS: *
* *
* Return Value - This will return whatever the transport layer *
* service function that it calls returns. *
* *
* *lpxosd - The errors returned here are those defined by the *
* transport layer service function that was called. *
* *
* IMPLEMENTATION: *
* *
* Find the most specific tl available. This is the transport *
* layer associated with the pid if the pid is non-Null, otherwise *
* it is the first transport layer registered with osdebug. *
* *
* *
***************************************************************************/
XOSD
CallTL (
TLF tlf,
HPID hpid,
DWORD wValue,
LPV lpv
)
/*++
Routine Description:
Call the transport layer associated with hpid, and send it a
message and packet.
Arguments:
tlf - Supplies transport layer function number.
hpid - Supplies process.
wValue - Supplies function dependent data.
lpv - Supplies and Returns data depending on function.
Return Value:
xosd status code, as returned by the TL.
--*/
{
XOSD xosd = xosdNone;
HTL htl;
LPTL lptl;
if ( hpid == NULL ) {
htl = LLNext ( lltl, htlNull );
}
else {
LPPID lppid = LLLock ( (HLLE)hpid );
htl = lppid->htl;
LLUnlock ( (HLLE)hpid );
}
lptl = LLLock ( (HLLE)htl );
xosd = lptl->tlfunc ( tlf, hpid, wValue, (LONG) lpv );
LLUnlock ( (HLLE)htl );
return xosd;
}
/**** OSDDOCALLBACK - Call the debug client with a notification message ****
* *
* PURPOSE: *
* *
* INPUTS: *
* *
* OUTPUTS: *
* *
* IMPLEMENTATION: *
* *
* *
***************************************************************************/
XOSD
OSDDoCallBack (
UINT wCommand,
HPID hpid,
HTID htid,
UINT wModel,
UINT wValue,
LONG lValue
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
XOSD xosd = xosdNone;
LPPID lppid;
assert ( hpid != NULL );
lppid = LLLock ( (HLLE)hpid );
switch ( wCommand ) {
case dbcBpt:
case dbcStep:
case dbcCheckBpt:
case dbcProcTerm:
case dbcThreadTerm:
case dbcException:
case dbcWatchPoint:
case dbcEntryPoint:
if ( lppid->lastmodel != wModel ) {
// model has changed, issue dbcEmChange notification
xosd = lppid->lpfnsvcCC ( dbcEmChange, hpid, htid, wModel, (LONG) 0 );
lppid->lastmodel = wModel;
}
break;
default:
// same model as before, do nothing
break;
}
xosd = lppid->lpfnsvcCC (( USHORT ) wCommand, hpid, htid, wValue, lValue );
LLUnlock ( (HLLE)hpid );
switch ( wCommand ) {
case dbcThreadDestroy:
// The shell will call OSDDestroyTID(), instead of
// us doing it here.
break;
case dbcProcTerm:
// same here; the shell calls OSDDestroyPID() when it
// is finished using the structures.
break;
}
return xosd;
}
XOSD
OSDDoCallBackToEM (
EMF wCommand,
HPID hpid,
HTID htid,
UINT wValue,
LONG lValue
)
/*++
Routine Description:
Call all of the non-native EMs with a notification message.
Arguments:
wCommand - Supplies the message
hpid - Supplies process
htid - Supplies thread
wValue - Supplies message dependent data
lValue - Supplies message dependent data
Return Value:
An xosd status code. xosdPunt means it was not handled by any EM.
If an EM handles it, xosdNone or a failure status will be returned.
--*/
{
XOSD xosd = xosdPunt;
HEM hemp;
LPEMP lpemp;
LPPID lppid;
assert ( hpid != NULL );
// get handle to the native EM
lppid = LLLock ( (HLLE)hpid );
if ( lppid->fNative ) {
LLUnlock((HLLE) hpid );
// native only mode, return
return xosd;
}
LLUnlock ( (HLLE)hpid );
// M00BUG - this is not correct. we should be hitting the ems
// in the reverse order that they are in the list.
// This will bite us when we move to multiple nms
hemp = hemNull;
while ( xosd == xosdPunt ) {
if ( ! ( hemp = LLNext ( (HLLI)(lppid->llemp), (HLLE)hemp ) ) ) {
return xosd;
}
lpemp = LLLock ( (HLLE)hemp );
if ( lpemp->emtype == emNative ) {
LLUnlock ( (HLLE)hemp );
return xosd;
}
xosd = (lpemp->emfunc) ( wCommand, hpid, htid, wValue, lValue );
LLUnlock ( (HLLE)hemp );
}
return xosd;
}
/**** CREATEPROC - Create a process data struct and add to proc list ****
* *
* PURPOSE: *
* *
* INPUTS: *
* *
* OUTPUTS: *
* *
* IMPLEMENTATION: *
* *
* *
***************************************************************************/
XOSD
CreateProc (
LPFNSVC lpfnsvc,
HEM hem,
HTL htl,
LPHPID lphpid
)
{
XOSD xosd = xosdNone;
HPID hpid;
LPPID lppid;
HEMP hemp;
LPEMP lpemp;
HEM hodem = hmemNull;
LPEM lpem;
HPID hpidem = hmemNull;
LPHPID lphpidt;
hpid = (HPID)LLCreate ((HLLI) llpid );
if ( hpid == NULL ) {
return xosdOutOfMemory;
}
LLAdd ( (HLLI)llpid, (HLLE)hpid );
lppid = LLLock ( (HLLE)hpid );
lppid->htl = htl;
lppid->fNative = FALSE;
lppid->lastmodel = CEXM_MDL_native;
lppid->lpfnsvcCC = lpfnsvc;
lppid->lltid = LLInit ( sizeof ( TIDS ), llfNull, NULL, NULL );
lppid->llemp = LLInit ( sizeof ( EMPS ), llfNull, EMPKill, NULL );
if ( lppid->llemp == 0 || lppid->lltid == 0 ) {
xosd == xosdOutOfMemory;
}
// create llem in lppid
while ( hodem = LLNext ( (HLLI)llem, (HLLE)hodem ) ) {
hemp = LLCreate ( (HLLI)(lppid->llemp) );
if ( hemp == hemNull ) {
return xosdOutOfMemory;
}
lpem = LLLock ( (HLLE)hodem );
lpemp = LLLock ( (HLLE)hemp );
// copy relevant info to hpid's emp
lpemp->hem = hodem;
lpemp->emfunc = lpem->emfunc;
lpemp->emtype = lpem->emtype;
if ( ! lpem->emtype && hodem == hem ) {
lppid->hempNative = hemp;
}
lpemp->model = lpem->model;
LLUnlock ( (HLLE)hemp );
LLUnlock ( (HLLE)hodem );
LLAdd ( (HLLI)(lppid->llemp), (HLLE)hemp );
}
// add the hpid to all em's list of hpids
hemp = hodem = hmemNull;
while ( hodem = LLNext ( (HLLI)llem, (HLLE)hodem ) ) {
lpem = LLLock ( (HLLE)hodem );
hpidem = (HPID)LLCreate ( (HLLI)(lpem->llhpid) );
if ( hpidem == hemNull ) {
LLUnlock((HLLE)hpid);
return xosdOutOfMemory;
}
lphpidt = LLLock ( (HLLE)hpidem );
// puts hpid in node
*lphpidt = hpid;
LLUnlock ( (HLLE)hpidem );
LLUnlock ( (HLLE)hodem );
LLAdd ( (HLLI)(lpem->llhpid), (HLLE)hpidem );
}
// clean up
LLUnlock ( (HLLE)hpid );
if (xosd == xosdNone) {
*lphpid = hpid;
}
return xosd;
}
/**** CREATETHD - Create a thread data struct & add to process ****
* *
* PURPOSE: *
* *
* INPUTS: *
* *
* OUTPUTS: *
* *
* IMPLEMENTATION: *
* *
* *
***************************************************************************/
XOSD
CreateThd (
HPID hpid,
HTID htid,
LPHTID lphtid
)
{
HTID htidT;
LPTID lptidT;
LPPID lppid;
Unreferenced( htid );
lppid = LLLock ( (HLLE)hpid );
htidT = (HTID)LLCreate ( (HLLI)(lppid->lltid) );
if ( htidT == htidNull ) {
LLUnlock ( (HLLE)hpid );
return xosdOutOfMemory;
}
LLAdd((HLLI)(lppid->lltid), (HLLE)htidT);
lptidT = LLLock ( (HLLE)htidT );
lptidT->hpid = hpid;
LLUnlock ( (HLLE)htidT );
LLUnlock ( (HLLE)hpid );
*lphtid = htidT;
return xosdNone;
}
/****************************************************************************
* *
* Kill and compare functions for the various lists used by osdebug *
* *
****************************************************************************/
void PASCAL LOADDS
ODPDKill (
LPV lpv
)
{
LPPID lppid = (LPPID) lpv;
LLDestroy ( lppid->llemp );
LLDestroy ( lppid->lltid );
}
void PASCAL LOADDS
EMKill (
LPV lpv
)
{
LPEM lpem = (LPEM) lpv;
LLDestroy ( lpem->llhpid );
}
void PASCAL LOADDS
EMPKill (
LPV lpv
)
{
Unreferenced( lpv );
return;
}
void PASCAL LOADDS
TLKill (
LPV lpv
)
{
LPTL lptl = (LPTL) lpv;
LLDestroy ( lptl->llpid );
}
int FAR PASCAL LOADDS
EMHpidCmp (
LPV lpv1,
LPV lpv2,
LONG lParam
)
{
Unreferenced( lParam );
if ( *( (LPHPID) lpv1) == *( (LPHPID) lpv2 ) ) {
return fCmpEQ;
} else {
return fCmpLT;
}
}
/************************************************************************/
/* Exception Handling */
/************************************************************************/
XOSD PASCAL
OSDGetExceptionState(
HPID hpid,
HTID htid,
LPEXCEPTION_DESCRIPTION lpExd,
EXCEPTION_CONTROL exf
)
/*++
Routine Description:
Given an address of an EXCEPTION_DESC filled in with the exception
code look up the code in the table and return a pointer to the
real exception info structure for that exception.
Arguments:
hpid - Supplies process
htid - Supplies thread
lpExd - A pointer to an exception structure to be filled in.
The dwExceptionCode member of this structure must be set
in order to use the exfSpecified or exfNext parmeter
exf - one of:
exfFirst
exfNext
exfSpecified
Return Value:
xosdNone - Success
--*/
{
if (hpid || !htid) {
return CallEM ( emfGetExceptionState, hpid, htid, exf, lpExd );
} else {
return (*(EMFUNC)htid)(emfGetExceptionState, NULL, NULL, exf, lpExd);
}
}
XOSD PASCAL
OSDSetExceptionState (
HPID hpid,
HTID htid,
LPEXCEPTION_DESCRIPTION lpExd
)
/*++
Routine Description:
Set the exception state for the given hpid/htid.
First implementation of this API should ignore the HTID parameter
as it is intended that it will only be able to Get/Set thread
exception states on a per process basis rather than on a per thread
basis. Should we choose in the future that there is a need to
Get/Set exception states on a per thread basis we can make use of
the HTID parameter at that time. At that time an htid of NULL would
indicate all threads.
Parameters:
hpid - Supplies process
htid - Supplies thread
lpExd - Supplies an exception structure to be Set. Should this
exception not be found in the current list of exceptions for
the given process/thread it will be added.
Return Value:
xosdNone: Success
--*/
{
return CallEM( emfSetExceptionState, hpid, htid, 0, lpExd );
}
XOSD PASCAL
OSDSetupExecute(
HPID hpid,
HTID htid,
LPHDEP lphdep
)
/*++
Routine Description:
This routine is called to set up a thread for doing a function
evaluation. This is passed on the the EM for processing.
Arguments:
hpid - Supplies the handle to the process
htid - Supplies the handle to the thread
lphdep - Supplies a pointer to save the SAVEINFO handle at
Return Value:
XOSD error code
--*/
{
XOSD xosd;
xosd = CallEM( emfSetupExecute, hpid, htid, 0, lphdep);
return xosd;
} /* OSDSetupExecute() */
XOSD PASCAL
OSDStartExecute(
HPID hpid,
HDEP hdep,
LPADDR lpaddr,
BOOL fIgnoreEvents,
BOOL fFar
)
/*++
Routine Description:
Execute function evaluation.
Arguments:
hpid - Supplies the handle to the process
hdep - Supplies the exeute object handle
lpaddr - Supplies the address to start evaluation at
fIgnoreEvents - Supplies TRUE if sub-events are to be ignored
fFar - Supplies TRUE if this is an _far function
Return Value:
return-value - Description of conditions needed to return value. - or -
None.
--*/
{
EXECUTE_STRUCT es;
es.addr = *lpaddr;
es.fIgnoreEvents = fIgnoreEvents;
es.fFar = fFar;
return CallEM( emfStartExecute, hpid, 0, (DWORD)hdep, &es);
} /* OSDStartExecute() */
XOSD PASCAL
OSDCleanUpExecute (
HPID hpid,
HDEP hdep
)
/*++
Routine Description:
This routine is called to clean up a current pending function
evaluation.
Arguments:
hdep Supplies the handle to the execute object
Return Value:
XOSD error code
--*/
{
return CallEM( emfCleanUpExecute, hpid, htidNull, (DWORD)hdep, 0);
} /* OSDCleanUpExecute() */
XOSD PASCAL
OSDLoadDllAck(
HPID hpid
)
/*++
Routine Description:
This routine is called in response to a modLoad message to inform
the DM that processing may now continue.
Arguments:
hpid - Supplies the handle to the process for the modLoad message
Return Value:
xosd error code
--*/
{
return CallEM( emfLoadDllAck, hpid, 0, 0, 0);
} /* OSDDllLoadAck */
XOSD PASCAL
OSDUnLoadDllAck(
HPID hpid,
HEXE emi,
BOOL fTellDM
)
/*++
Routine Description:
This routine is called in response to a modLoad message to inform
the DM that processing may now continue.
Arguments:
hpid - Supplies the handle to the process for the modLoad message
emi - Supplies emi of module being unloaded.
Return Value:
xosd error code
--*/
{
return CallEM( emfUnLoadDllAck, hpid, 0, fTellDM, (LPV)emi);
}
XOSD
OSDDebugActive(
HPID hpid,
DWORD dwProcessId,
HANDLE hEventGo,
LPDWORD lpdwStatus
)
/*++
Routine Description:
Tell the EM to debug a process which is already running and not
being debugged. If this succeeds, the debugger will be notified
of a new process, very similar to the creation of a child of
a process already being debugged.
Arguments:
hpid - Supplies process to bind to the EM. If no process is
already being debugged, this will be the "root" process,
and will not yet have a real debuggee attached to it.
Otherwise, this may be any process which is bound to the
right native EM.
dwProcessId - Supplies the OS supplied process ID for the process to debug.
hEventGo - Supplies an optional event handle which the DM will signal
when the DM is ready to catch an exception in the process.
This is used when attaching to a crashed process in Win32.
lpdwStatus - Returns the error status from the DebugActiveProcess API.
Return Value:
xosdNone if the DebugActiveProcess succeeds. If it fails, the value
returned in the DWORD at lpdwStatus may be examined to learn the
cause of the failure.
--*/
{
DBG_ACTIVE_STRUCT dba;
XOSD xosd;
dba.dwProcessId = dwProcessId;
dba.hEventGo = hEventGo;
xosd = CallEM( emfDebugActive, hpid, htidNull, 0, &dba);
*lpdwStatus = dba.dwStatus;
return xosd;
}
XOSD
OSDStackWalkSetup(
HPID hpid,
HTID htid,
BOOL fInProlog,
LPSTKSTR lpstkstr
)
/*++
Routine Description:
This routine is called to setup the stkstr structure which is used
to do a stack walk operation. After this function has been called
the current Program Counter and Frame Pointer will be set in the
stkstr as well as any flags needed for it.
Arguments:
hpid - Supplies the process handle to use
htid - Supplies the thread handle to use
fInProlog- Supplies TRUE if current address is in prolog
lpstkstr - Supplies a pointer to the Stack Walk Structure to fill-in
Return Value:
XOSD error code
--*/
{
return CallEM( emfStackWalkSetup, hpid, htid, fInProlog, lpstkstr);
} /* OSDStackWalkSetup() */
XOSD
OSDStackWalkNext(
HPID hpid,
HTID htid,
LPSTKSTR lpstkstr
)
/*++
Routine Description:
Arguments:
hpid - Supplies the process handle to use
htid - Supplies the thread handle to use
lpstkstr - Supplies a pointer to the Stack Walk Structure to fill-in
Return Value:
XOSD error code
--*/
{
return CallEM( emfStackWalkNext, hpid, htid, 0, lpstkstr);
} /* OSDStackWalkNext() */
XOSD
OSDStackWalkCleanup(
HPID hpid,
HTID htid,
LPSTKSTR lpstkstr
)
/*++
Routine Description:
Tell the EM to clean up data structures used for walking stack
Arguments:
hpid - Supplies the process handle to use
htid - Supplies the thread handle to use
lpstkstr - Supplies a pointer to the Stack Walk Structure
Return Value:
XOSD error code
--*/
{
return CallEM( emfStackWalkCleanup, hpid, htid, 0, lpstkstr);
} /* OSDStackWalkCleanup() */
XOSD
OSDSetFrame(
HPID hpid,
HTID htid,
PFRAME pframe
)
/*++
Routine Description:
Get a structure describing the current stack frame for a thread.
Arguments:
hpid - Supplies the process handle to use
htid - Supplies the thread handle to use
pframe - Returns FRAME structure
Return Value:
XOSD error code
--*/
{
return CallEM( emfSetFrame, hpid, htid, 0, pframe );
} /* OSDSetFrame() */
XOSD
OSDSetPath(
HPID hpid,
BOOL Set,
LSZ Path
)
/*++
Routine Description:
Sets the search path in the DM
Arguments:
hpid - Supplies process to bind EM
Set - Supplies TRUE to set new path, FALSE to turn
off path searching.
Path - Supplies search path string
Return Value:
XOSD error code
--*/
{
return CallEM( emfSetPath, hpid, 0, Set, Path );
}
/************************************************************************/
/* Breakpoints */
/************************************************************************/
XOSD PASCAL
OSDBreakpoint (
HPID hpid,
LPBPS lpbps
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
return CallEM ( emfBreakPoint, hpid, NULL, SizeofBPS(lpbps), lpbps);
}
XOSD
OSDGetPrompt(
HPID hpid,
LPPROMPTMSG lppm
)
/*++
Routine Description:
Get a prompt string for command window. This provides a way
for the EM/DM pair to identify itself to the user.
Arguments:
hpid - Supplies process
lppm - Returns PROMPTMSG struct
Return Value:
XOSD error code
--*/
{
return CallEM( emfGetPrompt, hpid, 0, 0, lppm );
}
XOSD
OSDSendReply(
HPID hpid,
UINT cb,
LPVOID lpv
)
{
return CallEM( emfMiscReply, hpid, 0, cb, lpv );
}
XOSD PASCAL
OSDGetMemInfo(
HPID hpid,
LPMEMINFO lpMemInfo
)
{
return CallEM( emfGetMemInfo, hpid, 0, sizeof(MEMINFO), lpMemInfo );
}
XOSD
OSDGetFunctionInfo(
HPID hpid,
PADDR Addr,
PFUNCTION_INFO FunctionInfo
)
{
return CallEM( emfGetFunctionInfo, hpid, 0, (DWORD)Addr, FunctionInfo );
}
XOSD PASCAL
OSDGetProcessStatus (
HPID hpid,
LPPST lppst
)
/*++
Routine Description:
Returns a structure describing the process status for the given hpid.
uses emfProcessStatus
Arguments:
hpid - Supplies process
lppst - Returns process state structure
Return Value:
xosdNone: Success
--*/
{
return CallEM( emfProcessStatus, hpid, NULL, 0, lppst );
}
XOSD PASCAL
OSDGetThreadStatus (
HPID hpid,
HTID htid,
LPTST lptst
)
/*++
Routine Description:
Returns a structure describing the thread status for the given htid.
uses emfThreadStatus
Arguments:
hpid - Supplies process
htid - Supplies thread
lptst - Returns thread state structure
Return Value:
xosdNone: Success
--*/
{
return CallEM( emfThreadStatus, hpid, htid, 0, lptst );
}
/************************************************************************/
/* Target execution */
/************************************************************************/
XOSD PASCAL
OSDGo (
HPID hpid,
HTID htid,
LPEXOP lpExop
)
/*++
Routine Description:
Run the target program for the process hpid [thread htid].
uses emfGo.
Note: This is an asynchronous API.
Parameters:
hpid - Supplies process to run
htid - Supplies the thread to run
lpExop - Supplies options to control execution
Return Value:
xosdNone: Success
--*/
{
return CallEM( emfGo, hpid, htid, 0, lpExop );
}
XOSD PASCAL
OSDSingleStep (
HPID hpid,
HTID htid,
LPEXOP lpExop
)
/*++
Routine Description:
Execute a single processor instruction of the process hpid
and thread htid.
uses emfSingleStep
Note: This is an asynchronous API.
Parameters:
hpid - Supplies process
htid - Supplies thread
lpExop - Supplies options to control execution
Return Value:
xosdNone: Success
--*/
{
return CallEM( emfSingleStep, hpid, htid, 0, lpExop );
}
XOSD PASCAL
OSDRangeStep (
HPID hpid,
HTID htid,
LPADDR lpaddrMin,
LPADDR lpaddrMax,
LPEXOP lpExop
)
/*++
Routine Description:
Execute single processor instructions for hpid/htid while *lpaddrMin
<= adrPC <= *lpaddrMax.
Both of the boundary addresses are inclusive of the range.
uses emfRangeStep.
Note: This is an asynchronous API.
Parameters:
hpid - Supplies process
htid - Supplies thread
lpaddrMin - Supplies the lower boundary address
lpaddrMax - Supplies the upper boundary address
lpExop - Supplies options to control execution
Return Value:
xosdNone: Success
--*/
{
RSS rss;
rss.lpaddrMin = lpaddrMin;
rss.lpaddrMax = lpaddrMax;
rss.lpExop = lpExop;
return CallEM( emfRangeStep, hpid, htid, 0 , &rss );
}
XOSD PASCAL
OSDReturnStep (
HPID hpid,
HTID htid,
LPEXOP lpExop
)
/*++
Routine Description:
Execute the thread until it has returned to the caller.
uses emfReturnStep
Note: This is an asynchronous API.
Parameters:
hpid - Supplies process
htid - Supplies thread
lpExop - Supplies options to control execution
Return Value:
xosdNone: Success
--*/
{
return CallEM( emfReturnStep, hpid, htid, 0, lpExop );
}
XOSD PASCAL
OSDAsyncStop (
HPID hpid,
DWORD fSetFocus
)
/*++
Description:
Halt the execution of the target process hpid.
uses emfStop.
Note: This is an asynchronous API.
Parameters:
hpid - Supplies process
fSetFocus - Supplies option of changing focus to debuggee to avoid
user having to nudge debuggee into stop
Return Value:
--*/
{
return CallEM( emfStop, hpid, NULL, fSetFocus, 0 );
}