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

5293 lines
107 KiB
C

/*++
Copyright (c) 1993 Microsoft Corporation
Module Name:
Osdebug.c
Abstract:
OSDebug version 4 API
Author:
Kent D. Forschmiedt (kentf)
Environment:
Win32, User Mode
--*/
#include <windows.h>
#include <stdlib.h>
#include <tchar.h>
#include "cvinfo.h"
#include "odtypes.h"
#include "od.h"
#include "dbgver.h"
#include "odp.h"
#include "odassert.h"
#define WINDBG_POINTERS_MACROS_ONLY
#include "sundown.h"
#undef WINDBG_POINTERS_MACROS_ONLY
#define CEXM_MDL_native 0x20
// debugger services vector
static LPDBF lpdbf;
// List roots
// Processes
static HLLI llpid;
// EMs
static HLLI llem;
// TLs
static HLLI lltl;
#ifdef __cplusplus
extern "C" {
#endif
extern AVS Avs;
XOSD
OSDDoCallBack (
DBC dbc,
HPID hpid,
HTID htid,
DWORD dwModel,
DWORD64 lParam1,
DWORD64 lParam2
);
XOSD
OSDDoCallBackToEM (
DBC emf,
HPID hpid,
HTID htid,
DWORD64 lParam1,
DWORD64 lParam2
);
XOSD
CallEM (
EMF emf,
HPID hpid,
HTID htid,
DWORD64 lParam,
DWORD64 lpv
);
XOSD
CallTL (
TLF tlf,
HPID hpid,
DWORD64 lParam,
DWORD64 lpv
);
XOSD
EMCallBackDB (
DBC dbc,
HPID hpid,
HTID htid,
DWORD dwModel,
DWORD64 cb,
DWORD64 lpv
);
XOSD
EMCallBackTL (
TLF tlf,
HPID hpid,
DWORD64 cb,
DWORD64 lpv
);
XOSD
EMCallBackNT (
EMF emf,
HPID hpid,
HTID htid,
DWORD64 cb,
DWORD64 lpv
);
XOSD
EMCallBackEM (
EMF emf,
HPID hpid,
HTID htid,
DWORD dwModel,
DWORD64 cb,
DWORD64 lpv
);
XOSD
TLCallBack (
HPID hpid,
DWORD64 lParam,
DWORD64 lpv
);
XOSD
CreateProc (
LPFNSVC lpfnsvc,
HEM hem,
HTL htl,
LPHPID lphpid
);
XOSD
CreateThd (
HPID hpid,
HTID htid,
LPHTID lphtid
);
static EMCB emcb = {
EMCallBackDB,
EMCallBackTL,
EMCallBackNT,
EMCallBackEM
};
static CRITICAL_SECTION CallbackCriticalSection;
#define CheckErr(xosd) if ( xosd != xosdNone ) return xosd
/* OSDebug Controller Initialization / Termination */
XOSD
OSDAPI
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 ( PROCESSINFO ), 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
OSDAPI
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;
}
/* Execution Model loading, unloading and configuration */
XOSD
OSDAPI
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 ).
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 ).
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.
--*/
{
HEM hem;
HEM hemm = 0;
LPEMS lpem;
LPEMS lpemm;
XOSD xosd = xosdNone;
DWORD dwModel;
assert ( emfunc != NULL );
assert ( lpdbf != NULL );
assert ( lphem != NULL );
hem = (HEM)LLCreate ( llem );
if ( !hem ) {
return xosdOutOfMemory;
}
if ( emtype == emNative ) {
// native inserted at the tail of the list
LLAdd ( llem, (HLLE)hem );
}
else {
// non-native inserted at head of list
LLAddHead ( llem, (HLLE)hem );
}
lpem = (LPEMS) LLLock ( (HLLE)hem );
lpem->emfunc = (EMFUNC_ODP) emfunc;
lpem->emtype = emtype;
lpem->llhpid = LLInit ( sizeof ( HPID ), llfNull, NULL, EMHpidCmp );
if ( lpem->llhpid == 0 ) {
xosd = xosdOutOfMemory;
}
xosd = (*lpem->emfunc) ( emfRegisterDBF, NULL, NULL, 0, (DWORD64) lpdbf );
CheckErr ( xosd );
xosd = (*lpem->emfunc) ( emfInit, NULL, NULL, 0, (DWORD64)&emcb );
CheckErr ( xosd );
xosd = (*lpem->emfunc) ( emfGetModel, NULL, NULL, 0, (DWORD64)&dwModel );
CheckErr ( xosd );
while ( hemm = (HEM)LLNext ( llem, (HLLE)hemm ) ) {
lpemm = (LPEMS) LLLock ( (HLLE)hemm );
if ( lpemm->model == dwModel ) {
// this is an error, cannot add the same model twice
LLUnlock ( (HLLE)hemm );
LLUnlock ( (HLLE)hem );
return xosdDuplicate;
}
LLUnlock ( (HLLE)hemm );
}
lpem->model = dwModel;
LLUnlock ( (HLLE)hem );
*lphem = hem;
return xosd;
}
XOSD
OSDAPI
OSDDeleteEM (
HEM hem
)
/*++
Routine Description:
Remove the execution model (hem) from os debug's list of available
execution models ( llem ).
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 ).
Arguments:
hem - Supplies handle to EM which is being removed
Return Value:
xosdNone - Success.
xosdInvalidEM - The execution model handle ( hem ) is invalid.
xosdInUse - 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.
--*/
{
XOSD xosd = xosdNone;
LPEMS lpem;
assert ( hem != NULL );
lpem = (LPEMS) LLLock ( (HLLE)hem );
if ( LLSize ( lpem->llhpid ) != 0 ) {
LLUnlock ( (HLLE)hem );
xosd = xosdInUse;
} else {
// Tell the EM and DM that they're about to be discarded
(lpem->emfunc) ( emfUnInit, NULL, NULL, 0, 0 );
LLUnlock ( (HLLE)hem );
if ( !LLDelete ( llem, (HLLE)hem ) ) {
xosd = xosdInvalidParameter;
}
}
return xosd;
}
XOSD
OSDAPI
OSDEMGetInfo(
HEM hem,
LPEMIS lpemis
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
XOSD xosd = xosdNone;
LPEMS lpem;
assert ( hem != NULL );
lpem = (LPEMS) LLLock ( (HLLE)hem );
xosd = (lpem->emfunc) ( emfGetInfo, NULL, NULL, 0, (DWORD64)lpemis );
LLUnlock( (HLLE)hem );
return xosd;
}
XOSD
OSDAPI
OSDEMSetup(
HEM hem,
LPEMSS lpemss
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
XOSD xosd = xosdNone;
LPEMS lpem;
assert ( hem != NULL );
lpem = (LPEMS) LLLock ( (HLLE)hem );
xosd = (lpem->emfunc) ( emfSetup, NULL, NULL, 0, (DWORD64)lpemss );
LLUnlock( (HLLE)hem );
return xosd;
}
/* EM Manipulation */
XOSD
OSDAPI
OSDGetCurrentEM (
HPID hpid,
HTID htid,
LPHEM lphem
)
/*++
Routine Description:
Get the handle for the current execution model associated
with hpid:htid.
Arguments:
hpid - Supplies process
htid - Supplies thread
lphem - Returns the handle to the execution model.
Return Value:
xosdNone - Success
xosdInvalidEM - No valid execution model for this hpid:htid
--*/
{
LPPROCESSINFO lppid;
HEM hodem;
LPEMP lpemp;
LPEMS lpem;
Unreferenced( htid );
assert ( lphem != NULL );
lppid = (LPPROCESSINFO) LLLock ( (HLLE)hpid );
if ( lppid == NULL ) {
return xosdInvalidParameter;
}
if ( lppid->lastmodel == CEXM_MDL_native ) {
lpemp = (LPEMP) LLLock ( (HLLE)lppid->hempNative );
*lphem = lpemp->hem;
LLUnlock ( (HLLE)lppid->hempNative );
}
else {
hodem = NULL;
while ( hodem = (HEM)LLNext ( llem, (HLLE)hodem ) ) {
lpem = (LPEMS) LLLock ( (HLLE)hodem );
if ( lpem->model == lppid->lastmodel ) {
*lphem = hodem;
}
LLUnlock ( (HLLE)hodem );
}
}
LLUnlock ( (HLLE)hpid );
return xosdNone;
}
XOSD
OSDAPI
OSDNativeOnly (
HPID hpid,
HTID htid,
DWORD fNat
)
/*++
Routine Description:
Force the use of the native em even where there is
non-native code (ie pcode or emulator).
Arguments:
hpid - Supplies process
htid - Supplies thread
fNat - Supplies to set native only, false to return to normal
mode of handling multiple em's
Return Value:
xosdNone - Success
--*/
{
HEMP hemp;
HEMP hempTmp = NULL;
XOSD xosd = xosdNone;
LPEMP lpemp;
LPPROCESSINFO lppid;
assert ( hpid != NULL );
lppid = (LPPROCESSINFO) LLLock ( (HLLE)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 = (HEMP)LLNext ( lppid->llemp, (HLLE)hempTmp ) ) &&
hempTmp != hemp ) {
lpemp = (LPEMP) LLLock ( (HLLE)hempTmp );
xosd = (lpemp->emfunc) ( emfDetach, hpid, htid, 0, 0 );
LLUnlock ( (HLLE)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, (HLLE)hemp );
LLAddHead ( lppid->llemp, (HLLE)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,
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, (HLLE)hemp );
LLAdd ( lppid->llemp, (HLLE)hemp );
// tell all of the non-native models that they can re-connect
xosd = xosdPunt;
while ( ( hempTmp = (HEMP)LLNext ( lppid->llemp, (HLLE)hempTmp ) ) &&
hempTmp != hemp && xosd == xosdPunt) {
DWORD dwModel;
lpemp = (LPEMP) LLLock ( (HLLE)hempTmp );
xosd = (lpemp->emfunc) ( emfAttach,
hpid,
htid,
0,
(DWORD64) &dwModel );
if ( xosd == xosdNone ) {
// send a dbcEmChange notification
OSDDoCallBack ( dbcEmChange,
hpid,
htid,
lppid->lastmodel,
dwModel,
0 );
lppid->lastmodel = dwModel;
}
LLUnlock ( (HLLE)hempTmp );
}
if ( xosd == xosdPunt ) {
xosd = xosdNone;
}
// reset our global flag to false
lppid->fNative = fNat;
}
LLUnlock ( (HLLE)hpid );
return xosd;
}
XOSD
OSDAPI
OSDUseEM (
HPID hpid,
HEM hem
)
/*++
Routine Description:
To tell osdebug that it should pass commands and callbacks for the
process hpid through the execution model whose handle is hem.
Arguments:
hpid - Supplies process
hem - Supplies handle to the execution model
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
--*/
{
LPPROCESSINFO lppid;
HEMP hemp = NULL;
LPEMS lpem;
LPEMP lpemp;
HPID hpidem;
LPHPID lphpid;
assert ( hem != NULL );
assert ( hpid != NULL );
// Add hem to pid's hem list
lppid = (LPPROCESSINFO) LLLock ( (HLLE)hpid );
while ( hemp = (HEMP)LLNext ( lppid->llemp, (HLLE)hemp ) ) {
lpemp = (LPEMP) LLLock ( (HLLE)hemp );
if ( lpemp->hem == hem ) {
// this is an error, cannot add the same model twice
LLUnlock ( (HLLE)hemp );
LLUnlock ( (HLLE)hpid );
return xosdDuplicate;
}
LLUnlock ( (HLLE)hemp );
}
hemp = (HEMP)LLCreate ( lppid->llemp );
if ( hemp == NULL ) {
LLUnlock ( (HLLE)hpid );
return xosdOutOfMemory;
}
lpem = (LPEMS) LLLock ( (HLLE)hem );
if ( lpem->emtype ) {
LLAddHead ( lppid->llemp, (HLLE)hemp );
}
else {
// new native em
LLAdd ( lppid->llemp, (HLLE)hemp );
lppid->hempNative = hemp;
}
LLUnlock ( (HLLE)hpid );
// add hpid to hem in llem
hpidem = (HPID)LLCreate ( lpem->llhpid );
if ( hpidem == NULL ) {
return xosdOutOfMemory;
}
lphpid = (LPHPID) LLLock ( (HLLE)hpidem );
// puts hpid in node
*lphpid = hpid;
LLUnlock ( (HLLE)hpidem );
LLUnlock ( (HLLE)hem );
LLAdd ( lpem->llhpid, (HLLE)hpidem );
return xosdNone;
}
XOSD
OSDAPI
OSDDiscardEM (
HPID hpid,
HTID htid,
HEM hem
)
/*++
Routine Description:
Remove an execution model from a process' list of available
execution models.
Arguments:
hpid - Supplies process
hem - Supplies handle to the execution model
Return Value:
xosdNone - Success
xosdInvalidParameter - There is no execution model associated with hem.
--*/
{
LPPROCESSINFO lppid;
HEM hemdis;
LPEMS lpem;
HEMP hemp = NULL;
HEMP hempdis;
LPEMP lpemp;
HPID hpiddis;
XOSD xosd = xosdNone;
assert ( hpid != NULL );
// find the hem in the lppid's list
lppid = (LPPROCESSINFO) LLLock ( (HLLE)hpid );
lpemp = (LPEMP) LLLock ( (HLLE)lppid->hempNative );
if ( lpemp->hem == hem ) {
// trying to remove the native em
lppid->hempNative = 0;
}
LLUnlock ( (HLLE)lppid->hempNative );
while (hemp = (HEMP)LLNext ( lppid->llemp, (HLLE)hemp ) ) {
lpemp = (LPEMP) LLLock ( (HLLE)hemp );
if ( lpemp->hem == hem ) {
hemdis = hem;
hempdis = hemp;
}
LLUnlock ( (HLLE)hemp );
}
if ( ! hemdis ) {
// no em found, return error
xosd = xosdInvalidParameter;
}
else {
// delete the em from the hpid, then remove hpid from em in llem
LLDelete ( lppid->llemp, (HLLE)hempdis );
lpem = (LPEMS) LLLock ( (HLLE)hemdis );
if ( hpiddis = (HPID)LLFind ( lpem->llhpid, 0, &hpid, 0 ) ) {
LLDelete ( lpem->llhpid, (HLLE)hpiddis );
}
else {
// hpid not found: internal cosistancy error
assert ( FALSE );
}
LLUnlock ( (HLLE)hemdis );
}
LLUnlock ( (HLLE)hpid );
return xosd;
}
/* Transport layer loading, unloading and configuration */
XOSD
OSDAPI
OSDAddTL (
TLFUNC tlfunc,
LPDBF lpbdf,
LPHTL lphtl
)
/*++
Routine Description:
Create and initialize a transport layer associated with the
service function tlfunc and add it to the list of osdebug's
available transport layers ( lltl ).
Use list manager to create a transport layer handle and add it
to the transport layer list ( lltl ).
Call the transport layer service function ( tlfunc ) to initialize
the transport layer and to register the debugger service functions
( lpdbf ) and OSDebug TL callback function ( TLCallBack ).
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.
--*/
{
HTL htl;
LPTL lptl;
XOSD xosd = xosdNone;
assert ( tlfunc != NULL );
assert ( lpdbf != NULL );
assert ( lphtl != NULL );
htl = (HTL)LLCreate ( lltl );
if ( htl == NULL ) {
xosd = xosdOutOfMemory;
} else {
LLAdd ( lltl, (HLLE)htl );
lptl = (LPTL) LLLock ( (HLLE)htl );
lptl->tlfunc = (TLFUNC_ODP) tlfunc;
if (xosd == xosdNone) {
xosd = lptl->tlfunc ( tlfInit, NULL, (UINT_PTR)lpdbf, (UINT_PTR)TLCallBack);
}
LLUnlock ( (HLLE)htl );
if (xosd != xosdNone) {
LLDelete(lltl, (HLLE)htl);
} else {
*lphtl = htl;
}
}
return xosd;
}
XOSD
OSDAPI
OSDStartTL(
HTL htl
)
{
LPTL lptl;
XOSD xosd;
lptl = (LPTL) LLLock ( (HLLE)htl );
xosd = lptl->tlfunc ( tlfConnect, NULL, 0, 0 );
LLUnlock( (HLLE)htl );
return xosd;
}
UINT
CountProcessesUsingTl(
HTL htl
)
/*++
Routine Description:
This function counts the number of hpid's currently using the given TL.
Arguments:
htl - The TL to to count Hpids for.
Return Value:
The number of Hpids using the given TL.
--*/
{
HPID hPid = NULL;
LPPROCESSINFO lppid;
UINT nUsers = 0;
HTL htlT;
while (hPid = (HPID) LLNext (llpid, (HLLE) hPid)) {
lppid = (LPPROCESSINFO) LLLock ((HLLE) hPid);
htlT = lppid->htl;
LLUnlock ((HLLE)hPid);
if (htlT == htl) {
nUsers++;
}
}
return nUsers;
}
XOSD
OSDAPI
OSDDeleteTL (
HTL htl
)
/*++
Routine Description:
Remove the transport layer (htl) from OSDebug's list of available
transport layers ( lltl ).
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 ).
Arguments:
htl - A transport layer that has previously been returned by
OSDAddTL.
Return Value:
xosdNone - Success.
xosdInUse - 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.
xosdInvalidParameter - The transport layer handle ( htl ) is invalid.
--*/
{
XOSD xosd = xosdNone;
LPTL lptl;
assert ( htl != NULL );
lptl = (LPTL) LLLock ( (HLLE)htl );
if ( CountProcessesUsingTl (htl) != 0 ) {
LLUnlock ( (HLLE)htl );
xosd = xosdInUse;
} else {
(*lptl->tlfunc)(tlfDestroy, NULL, 0, 0);
LLUnlock ( (HLLE)htl );
if ( !LLDelete ( lltl, (HLLE)htl ) ) {
xosd = xosdInvalidParameter;
}
}
return xosd;
}
XOSD
OSDAPI
OSDDiscardTL(
HPID hpid,
HTL htl
)
/*++
Routine Description:
Remove a reference to a tl by a pid. In particular, this allows us to
remove a TL before we destroy the PID. This is sometimes necessary in
error conditions.
--*/
{
HPID hpidT = NULL;
LPPROCESSINFO lppid;
lppid = (LPPROCESSINFO) LLLock ((HLLE) hpid);
if (lppid->htl == htl) {
lppid->htl = NULL;
}
LLUnlock ((HLLE) hpid);
return xosdNone;
}
XOSD
OSDAPI
OSDTLGetInfo(
HTL htl,
LPTLIS lptlis
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
XOSD xosd;
LPTL lptl;
assert ( htl != NULL );
lptl = (LPTL) LLLock ( (HLLE)htl );
xosd = (*lptl->tlfunc) ( tlfGetInfo, NULL, 0, (UINT_PTR) lptlis );
LLUnlock ( (HLLE)htl );
return xosd;
}
XOSD
OSDAPI
OSDTLSetup(
HTL htl,
LPTLSS lptlss
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
XOSD xosd;
LPTL lptl;
assert ( htl != NULL );
lptl = (LPTL) LLLock ( (HLLE)htl );
xosd = (*lptl->tlfunc) ( tlfSetup, NULL, 0, (UINT_PTR) lptlss );
LLUnlock ( (HLLE)htl );
return xosd;
}
XOSD
OSDAPI
OSDDisconnect(
HPID hpid,
HTID htid
)
/*++
Routine Description:
Performs a brute force disconnect of the TL. This effectively simulates
hanging up the phone or unplugging the network on a remote TL.
Arguments:
hpid - Supplies process to bind the TL
htid - Supplies thread, ignored
Return Value:
xosdNone, usually.
--*/
{
if (!hpid) {
return xosdUnknown;
}
return CallTL( tlfDisconnect, hpid, (UINT_PTR)htid, 0 );
}
/* Target process initialization / deletion */
XOSD
OSDAPI
OSDCreateHpid (
LPFNSVC lpfnsvcCallBack,
HEM hemNative,
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:
lpfnsvcCallBack - Supplies a pointer to the debugger callback function.
hemNative - Supplies a handle to the native execution model.
htl - Supplies a handle to the transport layer. This
may be NULL, in which case the new hpid can ONLY
be used for operations which don't need to go to
the remote side, such as querying (most) metrics.
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;
AVS RemoteAvs;
HPID hpid;
LPEMS lpem;
XOSD xosd = xosdNone;
XOSD xosdSave = xosdNone;
assert ( lpfnsvcCallBack != NULL );
assert ( hemNative != NULL );
assert ( lphpid != NULL );
assert ( llpid != 0 );
// Create and initialize the process structure and add to llpid
xosd = CreateProc ( lpfnsvcCallBack, hemNative, htl, &hpid );
if (xosd != xosdNone) {
return xosd;
}
// Notify the transport layer of the new process
if (htl) {
xosd = CallTL ( tlfConnect, hpid, 0, 0 );
switch(xosd = CallTL (tlfGetVersion, hpid, sizeof(Avs), (DWORD64)&RemoteAvs)) {
case xosdNone:
// got version info for remote side of transport...
// verify it.
if (Avs.rlvt != RemoteAvs.rlvt || Avs.iRmj != RemoteAvs.iRmj) {
xosd = xosdBadVersion; // bogus version
}
break;
case xosdNotRemote:
xosd = xosdNone;
break;
case xosdBadVersion:
default:
break;
}
}
if (xosd == xosdNone) {
// Notify the native execution model of the new process
lpem = (LPEMS) LLLock ( (HLLE)hemNative );
if (htl) {
xosd = lpem->emfunc (emfConnect, hpid, NULL, 0, 0);
}
// BUGBUG: Need to verify that we have the right DM when
// BUGBUG: xosd == xosdInUse.
if (xosd == xosdInUse) {
xosdSave = xosdInUse;
xosd = xosdNone;
}
if (xosd == xosdNone) {
xosd = lpem->emfunc (emfCreateHpid, hpid, NULL, 0, 0);
}
LLUnlock ( (HLLE)hemNative );
}
if (xosd == xosdNone) {
*lphpid = hpid;
} else {
if (htl) {
CallTL(tlfDisconnect, hpid, 0, 0);
}
// remove hpid from the lists of hpids in llem
for (hodem = (HEM)LLNext((HLLI) llem, NULL );
hodem;
hodem = (HEM)LLNext( (HLLI)llem, (HLLE)hodem )) {
lpem = (LPEMS) LLLock ( (HLLE)hodem );
if ( oldhpid = (HPID)LLFind ( lpem->llhpid, 0, &hpid, 0L ) ) {
LLDelete ( lpem->llhpid, (HLLE)oldhpid );
}
LLUnlock ( (HLLE)hodem );
}
LLUnlock ( (HLLE)hodem );
LLDelete ( llpid, (HLLE)hpid );
}
return xosd == xosdNone? xosdSave : xosd;
}
XOSD
OSDAPI
OSDDestroyHpid (
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;
LPEMS lpem;
HPID oldhpid;
LPPROCESSINFO lppid;
HTL htl, htlT;
xosd = CallEM ( emfDestroyHpid, hpid, NULL, 0, 0 );
if (xosd == xosdNone) {
lppid = (LPPROCESSINFO) LLLock((HLLE)hpid);
htl = lppid->htl;
LLUnlock((HLLE)hpid);
// if this is the last Process using this TL, disconnect
if (htl && CountProcessesUsingTl (htl) == 1) {
xosd = CallEM ( emfDisconnect, hpid, 0, 0, 0 );
xosd = CallTL ( tlfDisconnect, hpid, 0, 0 );
}
// remove hpid from the lists of hpids in llem
for (hodem = (HEM)LLNext( (HLLI)llem, NULL );
hodem;
hodem = (HEM)LLNext( (HLLI)llem, (HLLE)hodem )) {
lpem = (LPEMS) 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
OSDAPI
OSDDestroyHtid(
HPID hpid,
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
--*/
{
LPTHREADINFO lptid;
LPPROCESSINFO lppid;
XOSD xosd;
assert( htid != NULL );
lptid = (LPTHREADINFO) LLLock((HLLE) htid );
if (!lptid) {
return xosdInvalidHandle;
}
LLUnlock((HLLE) htid );
xosd = CallEM ( emfDestroyHtid, hpid, htid, 0, 0 );
lppid = (LPPROCESSINFO) LLLock ( (HLLE)hpid );
if (!lppid) {
return xosdBadProcess;
}
LLDelete ( lppid->lltid, (HLLE)htid );
LLUnlock ( (HLLE)hpid );
return xosdNone;
}
/* Address manipulation */
XOSD
OSDAPI
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.
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 == NULL && adr != adrData ) {
_fmemset ( lpaddr, 0, sizeof ( ADDR ) );
return xosdNone;
}
else {
XOSD xosd = CallEM ( emfGetAddr, hpid, htid, adr, (DWORD64)lpaddr );
assert(Is64PtrSE(lpaddr->addr.off));
return xosd;
}
}
XOSD
OSDAPI
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:
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 );
assert(Is64PtrSE(lpaddr->addr.off));
if ( htid == NULL && adr != adrData ) {
return xosdInvalidParameter;
}
else {
return CallEM ( emfSetAddr, hpid, htid, adr, (DWORD64)lpaddr );
}
}
XOSD
OSDAPI
OSDFixupAddr (
HPID hpid,
HTID htid,
LPADDR lpaddr
)
/*++
Routine Description:
Take an unfixed-up (logical) address and transform it into the
equivalent fixed up (physical) address.
Uses emfFixupAddr.
Arguments:
hpid - Supplies the process to which the address is associated.
htid - Supplies the thread to which the address is associated.
lpaddr - Supplies the address which is to be fixed up.
Return Value:
xosdNone - Success
xosdInvalidMTE - The logical address could not be found in any of the
modules in the given process.
--*/
{
ADDR addrTmp = {0};
XOSD xosd = xosdNone;
assert(Is64PtrSE(lpaddr->addr.off));
addrTmp = *lpaddr;
xosd = CallEM( emfFixupAddr, hpid, htid, 0, (DWORD64)&addrTmp );
if (xosdNone == xosd) {
*lpaddr = addrTmp;
}
return xosd;
}
XOSD
OSDAPI
OSDUnFixupAddr (
HPID hpid,
HTID htid,
LPADDR lpaddr
)
/*++
Routine Description:
Take a fixed up (physical) address and transform it into the
equivalent unfixed up (logical) address.
Note: It is essential that there be complete mapping (determined by
the em) between logical and physical addresses associated with a
process. Since it is often the case that part of the address space is
not mapped via symbol information to any exe/dll, in order to work
with the symbol handler, when these addresses are unfixed up, the hpid
should be entered in the emi field.
Uses emfUnfixupAddr.
Arguments:
hpid - Supplies the process of address to be unfixed up.
htid - Supplies the thread
lpaddr - Supplies the address to be unfixed up.
Return Value:
xosdNone - Success
--*/
{
ADDR addrTmp = *lpaddr;
XOSD xosd = CallEM( emfUnFixupAddr, hpid, htid, 0, (DWORD64)&addrTmp );
if (xosdNone == xosd) {
assert(Is64PtrSE(addrTmp.addr.off));
*lpaddr = addrTmp;
}
return xosd;
}
XOSD
OSDAPI
OSDCompareAddrs (
HPID hpid,
LPADDR lpaddr1,
LPADDR lpaddr2,
LPDWORD lpResult
)
/*++
Routine Description:
Compare address *lpaddr1 to address *lpaddr2.
Note: It is the case in some (DOS) supported operating systems
address comparison may not be a simple matter of comparing segments
and offsets. Therefore address comparison should be done through
this function.
Uses emfCompareAddrs.
Arguments:
hpid - Supplies the process with which the addresses are associated.
lpaddr1 - Supplies the first address to compare.
lpaddr2 - A pointer to the second address to compare.
lpResult - Returns result of comparison
Return Value:
xosdNone: Success
*lpResult < 0: *lpaddr1 < *lpaddr2
*lpResult == 0: *lpaddr1 == *lpaddr2
*lpResult >0: *lpaddr1 > *lpaddr2
--*/
{
CAS cas;
cas.lpaddr1 = lpaddr1;
cas.lpaddr2 = lpaddr2;
cas.lpResult = lpResult;
assert(Is64PtrSE(lpaddr1->addr.off));
assert(Is64PtrSE(lpaddr2->addr.off));
return CallEM( emfCompareAddrs, hpid, NULL, 0, (DWORD64)&cas );
}
XOSD
OSDAPI
OSDRegisterEmi (
HPID hpid,
HEMI hemi,
LPTSTR 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
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, NULL, 0, (DWORD64)&remi );
}
XOSD
OSDAPI
OSDUnRegisterEmi (
HPID hpid,
HEMI hemi
)
/*++
Routine Description:
As modules are loaded, address mapping and stack walking info are
stored in the EM. This tells the EM to discard that info.
Arguments:
hpid - Supplies handle to the process
hemi - Supplies emi for module being unloaded
Return Value:
xosdNone - Success
--*/
{
return CallEM ( emfUnRegisterEmi, hpid, NULL, 0, (DWORD64)hemi );
}
XOSD
OSDAPI
OSDSetEmi (
HPID hpid,
HTID htid,
LPADDR lpaddr
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
return CallEM ( emfSetEmi, hpid, htid, 0, (DWORD64)lpaddr );
}
XOSD
OSDAPI
OSDGetMemoryInformation(
HPID hpid,
HTID htid,
LPMEMINFO lpMemInfo
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
return CallEM( emfGetMemoryInfo, hpid, htid, sizeof(MEMINFO), (DWORD64)lpMemInfo );
}
/* Modules and Segments */
XOSD
OSDAPI
OSDGetModuleNameFromAddress (
IN HPID hpid,
IN DWORD64 Address,
OUT LPTSTR pszModuleName,
IN size_t SizeOf
)
/*++
Routine Description:
Get a module name via the PID and address. This is done by using the EMs module
list, and bypasses SAPI.
Arguments:
hpid - Supplies process
Address - Address used to find the module.
pszModuleName - If successful will contain the module name. Recommendation: it be at
least MAX_PATH in length.
SizeOf - Size of pszModuleName in characters.
Return Value:
xosdNone if successful. Other xosd codes indicate the
cause of failure.
--*/
{
XOSD xosd;
TCHAR szModName[_MAX_PATH];
assert(pszModuleName);
*szModName = 0;
xosd = CallEM ( emfGetModuleNameFromAddress,
hpid,
NULL,
Address,
(DWORD64)szModName
);
if (xosdNone == xosd) {
_tcsncpy(pszModuleName, szModName, SizeOf-1);
pszModuleName[SizeOf-1] = 0;
}
return xosd;
}
XOSD
OSDAPI
OSDGetModuleList (
HPID hpid,
HTID htid,
LPTSTR lpModuleName,
LPMODULE_LIST * lplpModuleList
)
/*++
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.
Arguments:
hpid - Supplies process
htid - Supplies thread. NULL is valid.
lpModuleName - Supplies optional name of module to look for.
If this arg is NULL, all modules will be found.
lplpModuleList - Returns list of modules in provided pointer.
This will be memory allocated with MHAlloc.
Return Value:
xosdNone if successful. Other xosd codes indicate the
cause of failure.
--*/
{
return CallEM ( emfGetModuleList,
hpid,
htid,
(DWORD64)lpModuleName,
(DWORD64)lplpModuleList
);
}
XOSD
OSDAPI
OSDSpawnOrphan (
HPID hpid,
LPCTSTR lszRemoteExe,
LPCTSTR lszCmdLine,
LPCTSTR lszRemoteDir,
LPSPAWNORPHAN FAR lpso,
DWORD dwFlags
)
/*++
Routine Description:
Create a process which is not a debuggee.
This is used for VC++'s Project.Execute.
Arguments:
hpid - Supplies TL binding to target machine. Only used for determining which
EM, TL, etc. to use; will NOT attach the new process to this HPID. You
can think of this as sort of like OSDReadFile: it just does something
useful on the target machine, without actually affecting the debuggee.
lszRemoteExe - Supplies name of remote exe. *
lszCmdLine - Supplies command line. *
lszRemoteDir - OPTIONAL Supplies the initial directory of the program. This
argument may be NULL or "", in which case the DM must choose a sensible
default, such as the directory of the EXE.
lpso - Returns a SPAWNORPHAN structure, in which data about the newly created
process is returned. lpso->dwPid is set to the PID of the new process, and
lpso->rgchErr[] is set to either "" for a successful spawn, or an error
string which should be displayed to the user if the spawn failed. *
dwFlags - Supplies flags that are passed to the EM. The following
flags are defined; any or none may be supported by any EM/DM pair:
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.
Return Value:
Any xosd other than xosdNone indicates failure, and the
debugger should display an appropriate error message
(preferably depending on the XOSD returned). If xosdNone
is returned, the caller must check lpso->rgchErr[0]; if
this byte is '\0', then the spawn was successful, otherwise
rgchErr contains an error message which should be displayed
to the user.
--*/
{
SOS sos;
XOSD xosd;
#ifdef DEBUG
// As long as we're un-consting the strings, we should verify that they're not changed
unsigned cb = _ftcslen (lszRemoteExe) + _ftcslen (lszRemoteExe) +_ftcslen (lszRemoteExe);
#endif
assert (!(dwFlags & ulfMultiProcess));
assert (hpid);
assert (lszRemoteExe);
assert (lpso);
memset (&sos, 0, sizeof(sos));
sos.dwChildFlags = dwFlags;
sos.lszRemoteExe = (LPTSTR) lszRemoteExe;
sos.lszCmdLine = (LPTSTR) lszCmdLine;
sos.lszRemoteDir = (LPTSTR) lszRemoteDir;
sos.lpso = lpso;
xosd = CallEM ( emfSpawnOrphan, hpid, NULL, sizeof (sos), (DWORD64)&sos );
#ifdef DEBUG
assert (cb == _ftcslen (lszRemoteExe) + _ftcslen (lszRemoteExe) +_ftcslen (lszRemoteExe));
#endif
return xosd;
}
/* Target Application loading / unloading */
XOSD
OSDAPI
OSDProgramLoad (
HPID hpid,
LPTSTR lszRemoteExe,
LPTSTR lszCmdLine,
LPTSTR lszRemoteDir,
LPTSTR lszDebugger,
DWORD dwFlags
)
/*++
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.
lszRemoteExe -
lszCmdLine - Supplies the command line that specifies the child program
and its arguments.
lszRemoteDir -
lszDebugger - Supplies the name of the debugger to the EM. This is
provided so that the DM can print the debugger's name
in error messages, and so the DM can put it in the
debuggee's window title.
dwFlags - 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.
Return Value:
xosdOutOfMemory - could not allocate a buffer to copy the arguments into
xosdFileNotFound
xosdAccessDenied
xosdLoadChild
--*/
{
XOSD xosd = xosdNone;
PRL prl;
assert ( hpid != NULL );
assert ( lszRemoteExe != NULL );
memset (&prl, 0, sizeof(prl));
xosd = CallEM (
emfSetMulti,
hpid,
NULL,
( dwFlags & ulfMultiProcess ) != 0,
0
);
CheckErr(xosd);
xosd = CallEM (
emfDebugger,
hpid,
NULL,
(_ftcslen ( lszDebugger ) + 1) * sizeof(TCHAR),
(DWORD64)lszDebugger
);
CheckErr(xosd);
prl.lszRemoteExe = lszRemoteExe;
prl.lszCmdLine = lszCmdLine;
prl.lszRemoteDir = lszRemoteDir;
prl.dwChildFlags = dwFlags;
prl.lpso = NULL;
xosd = CallEM ( emfProgramLoad,
hpid,
NULL,
sizeof( prl ),
(DWORD64)&prl
);
return xosd;
}
XOSD
OSDAPI
OSDDebugActive(
HPID hpid,
LPVOID lpvPrivate,
DWORD cbData
)
/*++
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.
cbData - Supplies size of data passed in lpvPrivate
lpvPrivate - Supplies pointer to a private data structure recognized
by the EM.
Return Value:
xosdNone
--*/
{
return CallEM( emfDebugActive, hpid, NULL, cbData, (DWORD64)lpvPrivate);
}
XOSD
OSDAPI
OSDSetPath(
HPID hpid,
DWORD fSet,
LPTSTR lszPath
)
/*++
Routine Description:
Sets the search path in the DM
Arguments:
hpid - Supplies process to bind EM
fSet - Supplies TRUE to set new path, FALSE to turn
off path searching.
lszPath - Supplies search path string
Return Value:
XOSD error code
--*/
{
return CallEM( emfSetPath, hpid, 0, fSet, (DWORD64)lszPath );
}
XOSD
OSDAPI
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, NULL, 0, 0 );
}
XOSD
OSDAPI
OSDNewSymbolsLoaded (
HPID hpid
)
/*++
Routine Description:
Notify the DM that new symbols have been loaded via a !reload.
Arguments:
hpid - Supplies the process whose EM function we should use.
Return Value:
xosdNone - Success
Any xosd error
--*/
{
assert ( hpid != NULL);
return CallEM ( emfNewSymbolsLoaded, hpid, NULL, 0, 0 );
}
XOSD
OSDAPI
OSDSignalKernelLoadCompleted (
HPID hpid
)
/*++
Routine Description:
Notify the DM that the synchronous module load of the kernel is
complete.
Arguments:
hpid - Supplies the process whose EM function we should use.
Return Value:
xosdNone - Success
Any xosd error
--*/
{
assert ( hpid != NULL);
return CallEM ( emfKernelLoaded, hpid, NULL, 0, 0 );
}
/* Target execution */
XOSD
OSDAPI
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, (DWORD64)lpExop );
}
XOSD
OSDAPI
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, (DWORD64)lpExop );
}
XOSD
OSDAPI
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;
assert(Is64PtrSE(lpaddrMin->addr.off));
assert(Is64PtrSE(lpaddrMax->addr.off));
return CallEM( emfRangeStep, hpid, htid, 0 , (DWORD64)&rss );
}
XOSD
OSDAPI
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, (DWORD64)lpExop );
}
XOSD
OSDAPI
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 );
}
/* Calling functions in the target */
XOSD
OSDAPI
OSDSetupExecute(
HPID hpid,
HTID htid,
LPHIND lphind
)
/*++
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
lphind - Supplies a pointer to save the SAVEINFO handle at
Return Value:
XOSD error code
--*/
{
XOSD xosd;
xosd = CallEM( emfSetupExecute, hpid, htid, 0, (DWORD64)lphind);
return xosd;
} /* OSDSetupExecute() */
XOSD
OSDAPI
OSDStartExecute(
HPID hpid,
HIND hind,
LPADDR lpaddr,
DWORD fIgnoreEvents,
DWORD fFar
)
/*++
Routine Description:
Execute function evaluation.
Arguments:
hpid - Supplies the handle to the process
hind - 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;
assert(Is64PtrSE(lpaddr->addr.off));
es.addr = *lpaddr;
es.fIgnoreEvents = fIgnoreEvents;
es.fFar = fFar;
return CallEM( emfStartExecute, hpid, 0, (DWORD64)hind, (DWORD64)&es);
} /* OSDStartExecute() */
XOSD
OSDAPI
OSDCleanUpExecute (
HPID hpid,
HIND hind
)
/*++
Routine Description:
This routine is called to clean up a current pending function
evaluation.
Arguments:
hind Supplies the handle to the execute object
Return Value:
XOSD error code
--*/
{
return CallEM( emfCleanUpExecute, hpid, NULL, (DWORD64)hind, 0);
} /* OSDCleanUpExecute() */
/* General target information */
XOSD
OSDAPI
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:
mtrc - Supplies metric to query, one of:
mtrcAsync whether debuggee runs asynchronously from debugger
mtrcWatchPoints whether watchpoints are supported on target
mtrcPidSize size in bytes of an OS PID
mtrcTidSize size in bytes of an OS TID
mtrcPidValue get OS PID for the specified HPID
mtrcTidValue get OS TID for the specified HPID/HTID pair
mtrcProcessorType debuggee's processor (return value from enum MPT)
mtrcProcessorLevel debuggee's processor level
mtrcThreads whether target OS supports multiple threads
mtrcEndian big Endian or little Endian
mtrcCRegs Number of Registers
mtrcCFlags Number of Flags
mtrcAssembler Assembler exists for the Execution model
hpid - Supplies process
htid - Supplies thread (optional for some metrics)
lpv - Returns requested info
Return Value:
xosdNone for success, other xosd codes describe the cause of failure.
lpl must point to a LONG which will receive the info.
--*/
{
return CallEM ( emfMetric, hpid, htid, mtrc, (DWORD64)lpv );
}
/* Target memory */
XOSD
OSDAPI
OSDReadMemory (
HPID hpid,
HTID htid,
LPADDR lpaddr,
LPVOID lpbBuffer,
DWORD cbBuffer,
LPDWORD lpcbRead
)
/*++
Routine Description:
Read a stream of cbBuffer bytes from the target process hpid at the
address *lpaddr into the buffer *lpbBuffer. A negative return value
is an error, positive return values represent the number of bytes
actually read. The return value will never be greater than the number
of bytes requested.
uses emfReadMemory
Arguments:
hpid - Supplies process
htid - Supplies thread
lpaddr - Supplies address to read from
lpbBuffer - Returns the results
cbBuffer - Supplies the number of bytes to read
lpcbRead - Returns the nuber of bytes actually read
Return Value:
xosdNone: Success
--*/
{
RWMS rwms;
assert(Is64PtrSE(lpaddr->addr.off));
rwms.lpaddr = lpaddr;
rwms.lpbBuffer = (LPBYTE) lpbBuffer;
rwms.cbBuffer = cbBuffer;
rwms.lpcb = lpcbRead;
return CallEM( emfReadMemory, hpid, htid, 0, (DWORD64)&rwms );
}
XOSD
OSDAPI
OSDWriteMemory (
HPID hpid,
HTID htid,
LPADDR lpaddr,
LPVOID lpbBuffer,
DWORD cbBuffer,
LPDWORD lpcbWritten
)
/*++
Routine Description:
Write a stream of cbBuffer bytes from the buffer *lpbBuffer to the
target process specified by hpid at the address *lpaddr.
uses emfWriteMemory
Arguments:
hpid - Supplies process
htid - Supplies thread
lpaddr - Supplies address to write data to
lpbBuffer - Supplies data to write
cbBuffer - Supplies the number of bytes to write
lpcbWritten - Returns the number of bytes actually written
Return Value
xosdNone: Success
--*/
{
RWMS rwms;
assert(Is64PtrSE(lpaddr->addr.off));
rwms.lpaddr = lpaddr;
rwms.lpbBuffer = (LPBYTE) lpbBuffer;
rwms.cbBuffer = cbBuffer;
rwms.lpcb = lpcbWritten;
return CallEM( emfWriteMemory, hpid, htid, 0, (DWORD64)&rwms );
}
XOSD
OSDAPI
OSDGetObjectLength (
HPID hpid,
HTID htid,
LPADDR lpaddr,
LPUOFFSET lpuoffStart,
LPUOFFSET lpuoffLength
)
/*++
Routine Description:
Get the length of a given linear exe object
Arguments:
hpid - Supplies process
htid - Supplies thread
lpaddr - Supplies address within the object in question
lpuoffStart - Returns linear address of beginning of object
lpuoffLength - Returns the length, in bytes, of the object
Return Value:
xosdNone - Success
Any value that can be returned by the emfGetObjLength of the
execution model called.
--*/
{
GOL gol;
assert ( lpaddr != NULL );
assert(Is64PtrSE(lpaddr->addr.off));
gol.lplBase = lpuoffStart;
gol.lplLen = lpuoffLength;
gol.lpaddr = lpaddr;
return CallEM ( emfGetObjLength, hpid, htid, 0, (DWORD64)&gol );
}
XOSD
OSDAPI
OSDGetFunctionInformation(
HPID hpid,
HTID htid,
LPADDR lpaddr,
LPFUNCTION_INFORMATION lpFunctionInformation
)
/*++
Routine Description:
Get information describing the layout of a function. The data available
are platform dependent, but the FUNCTION_INFORMATION structure is
portable.
Arguments:
hpid - Supplies process
htid - Supplies thread
lpaddr - Supplies address within the object in question
lpFunctionInformation - Returns a packet describing the function
Return Value:
xosdNone - Success
Any value that can be returned by the emfGetFunctionInfo of the
execution model called.
--*/
{
GFI gfi;
assert ( lpaddr != NULL );
assert(Is64PtrSE(lpaddr->addr.off));
gfi.lpaddr = lpaddr;
gfi.lpFunctionInformation = lpFunctionInformation;
return CallEM ( emfGetFunctionInfo, hpid, htid, 0, (DWORD64)&gfi );
}
/* Register management */
XOSD
OSDAPI
OSDGetRegDesc (
HPID hpid,
HTID htid,
DWORD iReg,
LPRD 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, (DWORD64)lprd );
}
XOSD
OSDAPI
OSDGetFlagDesc (
HPID hpid,
HTID htid,
DWORD iFlag,
LPFD 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, (DWORD64)lpfd );
}
XOSD
OSDAPI
OSDReadRegister (
HPID hpid,
HTID htid,
DWORD dwIndex,
LPVOID lpv
)
/*++
Routine Description:
Read a register in a debuggee thread
Arguments:
hpid - Supplies process
htid - Supplies thread
dwIndex - 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.
--*/
{
return CallEM ( emfGetReg, hpid, htid, dwIndex, (DWORD64)lpv );
}
XOSD
OSDAPI
OSDWriteRegister (
HPID hpid,
HTID htid,
DWORD dwIndex,
LPVOID lpv
)
/*++
Routine Description:
Write a register in a debuggee thread
Arguments:
hpid - Supplies process
htid - Supplies thread
dwIndex - 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, dwIndex, (DWORD64)lpv );
}
XOSD
OSDAPI
OSDReadFlag (
HPID hpid,
HTID htid,
DWORD dwIndex,
LPVOID 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
dwIndex - 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, dwIndex, (DWORD64)lpv );
}
XOSD
OSDAPI
OSDWriteFlag (
HPID hpid,
HTID htid,
DWORD dwIndex,
LPVOID 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
dwIndex - 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, dwIndex, (DWORD64)lpv );
}
XOSD
OSDAPI
OSDSaveRegs (
HPID hpid,
HTID htid,
LPHIND lphmem
)
/*++
Routine Description:
Save the register set of a thread so that it may be restored later.
Arguments:
hpid - Supplies process
htid - Supplies thread
lphmem - Returns a handle to the stored context
Return Value:
xosdNone - Success
Any value that can be returned by the emfSaveRegs of the execution
model called.
--*/
{
return CallEM ( emfSaveRegs, hpid, htid, 0, (DWORD64)lphmem );
}
XOSD
OSDAPI
OSDRestoreRegs (
HPID hpid,
HTID htid,
HIND hmem
)
/*++
Routine Description:
Restore a thread context stored by OSDSaveRegs.
Arguments:
hpid - Supplies process
htid - Supplies thread
hmem - Supplies saved context
Return Value:
xosdNone - Success
Any value that can be returned by the emfRestoreRegs of the
execution model called.
--*/
{
return CallEM ( emfRestoreRegs, hpid, htid, 0, (DWORD64)hmem );
}
/* Breakpoints */
XOSD
OSDAPI
OSDBreakpoint (
HPID hpid,
LPBPS lpbps
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
return CallEM ( emfBreakPoint,
hpid,
NULL,
SizeofBPS(lpbps),
(DWORD64)lpbps
);
}
/* Assembly and Disassembly */
XOSD
OSDAPI
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, (DWORD64)lpsdi );
}
XOSD
OSDAPI
OSDAssemble (
HPID hpid,
HTID htid,
LPADDR lpaddr,
LPTSTR 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.
--*/
{
assert(Is64PtrSE(lpaddr->addr.off));
return CallEM ( emfAssemble, hpid, htid, (DWORD64)lpaddr, (DWORD64)lsz );
}
#define doffMax 120 // Double the Max number of instructions guaranteed
// to get you back in sync. We use the second half
// of the buffer for cache'n.
static HPID hpidGPI = NULL;
static BYTE rgbGPI [ doffMax ];
static ADDR addrGPI;
XOSD
GPIBuildCache (
HPID hpid,
HTID htid,
LPADDR lpaddr
)
{
XOSD xosd = xosdBadAddress;
int fFound = FALSE;
ADDR addr = *lpaddr;
ADDR addrT;
int ib = 0;
_fmemset ( rgbGPI, 0, doffMax );
addrGPI = *lpaddr;
hpidGPI = hpid;
GetAddrOff ( addr ) -= min ( (UOFFSET) doffMax, GetAddrOff ( *lpaddr ) );
while ( !fFound && GetAddrOff ( addr ) < GetAddrOff ( *lpaddr ) ) {
SDI sdi;
sdi.dop = dopNone;
sdi.addr = addr;
addrT = addr;
CallEM ( emfUnassemble, hpid, htid, sizeof( sdi ), (DWORD64)&sdi );
/*
** If we wrapped, because of disasm on the offset boundary
*/
if ( GetAddrOff ( sdi.addr ) < GetAddrOff ( addr ) ) {
break;
}
addr = sdi.addr;
rgbGPI [ ib ] = (BYTE) ( GetAddrOff ( addrGPI ) - GetAddrOff ( addr ) );
if ( GetAddrOff ( addr ) == GetAddrOff ( *lpaddr ) ) {
xosd = xosdNone;
*lpaddr= addrT;
fFound = TRUE;
}
ib += 1;
}
// We haven't synced yet, so *lpaddr is probably pointing
// to something that isn't really synchronous
if ( !fFound ) {
xosd = (XOSD) ( GetAddrOff ( *lpaddr ) - GetAddrOff ( addrT ) );
GetAddrOff ( *lpaddr ) -= xosd;
if ( GetAddrOff ( *lpaddr ) != 0 ) {
UOFFSET uoff;
OSDGetPrevInst ( hpid, htid, lpaddr, &uoff );
}
}
return xosd;
}
void
GPIShiftCache (
LPADDR lpaddr,
int *pib
)
{
int doff = (int) ( GetAddrOff ( addrGPI ) - GetAddrOff ( *lpaddr ) );
int ib = 0;
int ibRet = -1;
for( ib = 0, ibRet = -1; ibRet == -1 && ib < doffMax; ++ib ) {
rgbGPI [ ib ] = (BYTE) max ( (int) rgbGPI [ ib ] - doff, 0 );
if ( rgbGPI[ ib ] == 0 ) {
ibRet = ib;
}
}
if ( ib == doffMax ) {
ibRet = doffMax - 1;
}
*pib = ibRet;
addrGPI = *lpaddr;
}
XOSD
GPIUseCache (
HPID hpid,
HTID htid,
LPADDR lpaddr
)
{
XOSD xosd = xosdBadAddress;
int fFound = FALSE;
ADDR addr = *lpaddr;
int ib = 0;
int ibCache= 0;
int ibMax = 0;
BYTE rgb [ doffMax ];
GPIShiftCache ( lpaddr, &ibMax );
_fmemset ( rgb, 0, doffMax );
GetAddrOff ( addr ) -= min ( (UOFFSET) doffMax, GetAddrOff ( *lpaddr ) );
while ( !fFound && GetAddrOff ( addr ) < GetAddrOff ( *lpaddr ) ) {
ADDR addrT;
BYTE doff = (BYTE) ( GetAddrOff ( *lpaddr ) - GetAddrOff ( addr ) );
// Attempt to align with the cache
while ( doff < rgbGPI [ ibCache ] ) {
ibCache += 1;
}
if ( doff == rgbGPI [ ibCache ] ) {
// We have alignment with the cache
addr = *lpaddr;
addrT = addr;
GetAddrOff ( addrT ) -= rgbGPI [ ibMax - 1 ];
}
else {
SDI sdi;
sdi.dop = dopNone;
sdi.addr = addr;
addrT = addr;
CallEM ( emfUnassemble, hpid, htid, sizeof( sdi ), (DWORD64)&sdi );
addr = sdi.addr;
rgb [ ib ] = (BYTE) ( GetAddrOff ( addrGPI ) - GetAddrOff ( addr ) );
ib += 1;
}
if ( GetAddrOff ( addr ) == GetAddrOff ( *lpaddr ) ) {
xosd = xosdNone;
*lpaddr= addrT;
fFound = TRUE;
}
}
// Rebuild the cache
_fmemmove ( &rgbGPI [ ib - 1 ], &rgbGPI [ ibCache ], ibMax - ibCache );
_fmemcpy ( rgbGPI, rgb, ib - 1 );
return xosd;
}
XOSD
OSDAPI
OSDGetPrevInst (
HPID hpid,
HTID htid,
LPADDR lpaddr,
LPUOFFSET lpuoffset
)
{
if ( GetAddrOff ( *lpaddr ) == 0 ) {
return xosdBadAddress;
}
else if (
hpid == hpidGPI &&
GetAddrSeg ( *lpaddr ) == GetAddrSeg ( addrGPI ) &&
GetAddrOff ( *lpaddr ) < GetAddrOff ( addrGPI ) &&
GetAddrOff ( *lpaddr ) > GetAddrOff ( addrGPI ) - doffMax / 2
) {
return GPIUseCache ( hpid, htid, lpaddr );
}
else {
return GPIBuildCache ( hpid, htid, lpaddr );
}
}
/* Stack Tracing */
XOSD
OSDAPI
OSDGetFrame (
HPID hpid,
HTID htid,
DWORD cFrame,
LPHTID lphtid
)
/*++
Routine Description:
Put the frame on the stack previous to the frame specified by
*lphtid into *lphtid.
Arguments:
hpid - Supplies process
htid - Supplies thread
cFrame - Used to tell the EM how many frames total the caller will
be requesting. a value of zero indicates all frames.
phTid - Pointer to real HTID, or last virtual HTID. If the HTID
is real the routine will return a virtualized version of
the HTID in the lphTid paramater. If the HTID is virtual
then the routine will return the next virtualized HTID for
the next frame.
Return Value:
xosdNone - Success.
xosdEndOfStack - No more frames.
Any value that can be returned by the Get Frame Function
of the execution model called.
--*/
{
return CallEM ( emfGetFrame, hpid, htid, cFrame, (DWORD64)lphtid );
}
/* Process and Thread manipulation */
XOSD
OSDAPI
OSGetThreadStatus (
HPID hpid,
HTID htid,
LPTST lptst
)
/*++
Routine Description:
Gets a thread state structure for the given hpid/htid. This routine
can fail if an operation is invalid for the target architetecture.
uses emfThreadStatus
Arguments:
hpid - Supplies process
htid - Supplies thread
lptst - Returns a thread state structure.
Return Value:
xosdNone: Success
--*/
{
return CallEM( emfThreadStatus, hpid, htid, 0, (DWORD64)lptst );
}
XOSD
OSDAPI
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, (DWORD64)lppst );
}
XOSD
OSDAPI
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, (DWORD64)lptst );
}
XOSD
OSDAPI
OSDFreezeThread (
HPID hpid,
HTID htid,
DWORD fFreeze
)
/*++
Routine Description:
Freezes or thaws the thread specified by hpid/htid.
uses emfFreezeThread
Arguments:
hpid - Supplies process
htid - Supplies thread
fFreeze - Supplies TRUE to freeze, FALSE to thaw.
Return Value:
xosdNone: Success
--*/
{
return CallEM( emfFreezeThread, hpid, htid, fFreeze, 0 );
}
XOSD
OSDAPI
OSDSetThreadPriority (
HPID hpid,
HTID htid,
DWORD dwPriority
)
/*++
Routine Description:
Sets the priority of the thread specified by hpid/htid to the given
meta priority level.
uses emfSetThreadPriority
Arguments:
hpid - Supplies process
htid - Supplies thread
dwPriority - Supplies the meta priority level to assign to the thread.
Return Value:
xosdNone: Success
--*/
{
return CallEM( emfSetThreadPriority, hpid, htid, dwPriority, 0 );
}
/* File manipulation */
/* Exception Handling */
XOSD
OSDAPI
OSDGetExceptionState(
HPID hpid,
HTID htid,
LPEXCEPTION_DESCRIPTION lpExd
)
/*++
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
Return Value:
xosdNone - Success
--*/
{
if (hpid == 0) {
// an annoying little hack, forcing htid to be pointer sized:
// if hpid is 0, there is no OSDebug bining yet, so htid is really
// a pointer to an EMFunc.
return ((XOSD (OSDAPI *)(EMF, HPID, HTID, DWORD64, DWORD64))htid) (
emfGetExceptionState, 0, 0, 0, SEPtrTo64(lpExd) );
} else {
return CallEM ( emfGetExceptionState, hpid, htid, 0, (DWORD64)lpExd );
}
}
XOSD
OSDAPI
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, (DWORD64)lpExd );
}
/* Message handling */
XOSD
OSDAPI
OSDGetMessageMap (
HPID hpid,
HTID htid,
LPMESSAGEMAP* lplpMessageMap
)
/*++
Routine Description:
Retrieves a table from the EM of the messages that may be used
in the process represented by hpid. In the WIN32 implementation,
this is a pointer to a static structure, and does not need to be
freed or otherwise messed with.
Arguments:
hpid - Supplies process
htid - Supplies thread
lplpMessageMap - 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 ( emfGetMessageMap, hpid, htid, 0, (DWORD64)lplpMessageMap );
}
/**** OSDGetMessageMaskMap ****/
XOSD
OSDAPI
OSDGetMessageMaskMap (
HPID hpid,
HTID htid,
LPMASKMAP * lplpMaskMap
)
/*++
Routine Description:
Retrieves a table of message mask descriptions from the EM. The
first element in the table represents the least significant bit in
the mask. The second element represents the the next bit and so on.
uses emfGetMessageMaskMap
Arguments:
hpid - Supplies process
htid - Supplies thread
lplpMaskMap - Returns a pointer to MSKMAP
Return Value:
xosdNone: Sucess
--*/
{
return CallEM ( emfGetMessageMaskMap, hpid, htid, 0, (DWORD64)lplpMaskMap );
}
/* Screen manipulation */
XOSD
OSDAPI
OSDShowDebuggee (
HPID hpid,
DWORD fShow
)
/*++
Routine Description:
Direct the debug monitor to set or not focus to the debuggee when
executing. This should be called if the debug monitor is responsible
for setting focus. See mtrcShowDebuggee in the General Target
Information section. If the debugger host is responsible for
setting focus then the DM will be calling back with a dbcShowDebuggee
( Formerly dbcFlipScreen ) to set focus when executing.
uses emfShowDebuggee
Arguments:
hpid - Supplies process to bring to the foreground
fShow - Supplies TRUE if the debug monitor should force the debuggee
to have focus when executing, FALSE if not.
Return Value:
xosdNone: Success
--*/
{
return CallEM( emfShowDebuggee, hpid, NULL, fShow, 0 );
}
/* I/O requests */
XOSD
OSDAPI
OSDInfoReply (
HPID hpid,
HTID htid,
LPVOID lpvData,
DWORD cbData
)
/*++
Routine Description:
This routine is to allow the DM to request information from the host.
The DM will callback with a dbcInfoRequest with one of the paramaters
being a pointer to a string indiciating the request. This routine is
use to convey the requested information to the DM. This routine is
intended solely for RIP's on Windows/Window NT but can be used for
other things.
Need to examine subcatagories for types of requests that will be coming
from dbcInfoRequest so the host can display and query for information
in a non-console fashion.
uses emfInfoReply
Arguments:
hpid - Supplies process
htid - Supplies thread
lpvData - Supplies pointer to data which is being sent back to the DM
cbData - Supplies count in bytes of data being sent.
Return Value:
xosdNone: Success
--*/
{
return CallEM( emfInfoReply, hpid, htid, cbData, (DWORD64)lpvData );
}
/* OS Specific services */
XOSD
OSDAPI
OSDGetTaskList (
HPID hpid,
LPTASKLIST * lplpTaskList
)
/*++
Routine Description:
Get a list of processes from the target system. This is intended to
give the debugger the ability to browse for a process to debug.
uses emfGetTaskList
Arguments:
hpid - Supplies process. The process is not relevant, only the
EM which it is bound to. Hpid may be NULL, and the EM
selected will be the oldest native EM loaded.
lplpTaskList - Returns the list of items. This will be allocated
so that it can be freed with MHFree.
Return Value:
xosdNone
xosdInvalidProc
xosdOutOfMemory
--*/
{
return CallEM ( emfGetTaskList, hpid, NULL, 0, (DWORD64)lplpTaskList );
}
XOSD
OSDAPI
OSDSetDebugMode (
HPID hpid,
DBM dbmService,
LPVOID lpvData,
DWORD cbData
)
/*++
Routine Description:
If the target supports hard mode/ soft mode switching ( See
mtrcHardSoftMode in the General Target Information Section ) then this
routine can be called to set the target into hard or soft mode. The
data provided is specific to the target machine and the host must be
aware of the format of the data.
uses emfSetDebugMode
Parameters:
hpid - Supplies process
dbmService - Supplies new mode, either dmbSoftMode or dbmHardMode
lpvData - Supplies a pointer to a DBMI
cbData - Supplies size of a DBMI structure
Return Value:
xosdNone: Success
--*/
{
SDMS sdms;
sdms.dbmService = dbmService;
sdms.lpvData = lpvData;
sdms.cbData = cbData;
return CallEM( emfSetDebugMode, hpid, NULL, 0, (DWORD64)&sdms );
}
XOSD
OSDAPI
OSDSystemService (
HPID hpid,
HTID htid,
SSVC ssvc,
LPVOID lpvData,
DWORD cbData,
LPDWORD lpcbReturn
)
/*++
Routine Description:
Provide OS specific functionality. Calls the EM service function,
requesting emfSystemService.
Arguments:
hpid - Supplies handle to the process to perform the operation
on. Some SSVCs 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 SSVC function index
lpvData - Supplies and returns data. Use of this field depends on
the SSVC.
cbData - Supplies the number of bytes in the data packet
lpcbReturn - Returns the number of bytes written to lpvData
Return Value:
xosd return value is supplied by the service function.
--*/
{
XOSD xosd = xosdNone;
LPSSS lpsss = (LPSSS) malloc( sizeof( SSS ) + cbData );
DWORD cbr;
if ( lpsss == NULL ) {
return xosdOutOfMemory;
}
lpsss->ssvc = ssvc;
lpsss->cbSend = cbData;
if (cbData) {
_fmemcpy ( lpsss->rgbData, lpvData, cbData );
}
xosd = CallEM ((EMF) emfSystemService,
hpid,
htid,
sizeof ( SSS ) + cbData,
(DWORD64) lpsss );
if (xosd == xosdNone) {
cbr = lpsss->cbReturned;
if (cbr > cbData) {
cbr = cbData;
}
if (cbr) {
_fmemcpy ( lpvData, lpsss->rgbData, cbr);
}
if (lpcbReturn) {
*lpcbReturn = cbr;
}
}
_ffree ( lpsss );
return xosd;
}
/*
* *
* Services provided for execution model and transport layer *
* *
*/
XOSD
EMCallBackDB (
DBC dbc,
HPID hpid,
HTID htid,
DWORD dwModel,
DWORD64 cb,
DWORD64 lparam
)
/*++
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
dwModel - Supplies index of EM initiating the callback
cb - Supplies the number of bytes pointed to by lpv
lparam - 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) lparam) = htid;
goto Return;
//return xosd;
case dbcoNewProc: {
LPPROCESSINFO lppid = (LPPROCESSINFO) LLLock ( (HLLE)hpid );
HPID hpidT = hpid;
LPEMP lpemp = (LPEMP) LLLock ( (HLLE)(lppid->hempNative) );
xosd = CreateProc (
lppid->lpfnsvcCC,
lpemp->hem,
lppid->htl,
&hpid
);
*( (LPHPID) lparam) = 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, lparam );
// if xosd is xosdPunt then all non-native EMs punted on the notification
if ( xosd == xosdPunt ) {
xosd = OSDDoCallBack ( dbc, hpid, htid, dwModel, cb, lparam );
}
Return:
LeaveCriticalSection( &CallbackCriticalSection );
return xosd;
}
XOSD
EMCallBackTL (
TLF wCmd,
HPID hpid,
DWORD64 cb,
DWORD64 lparam
)
/*++
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, lparam );
}
XOSD
EMCallBackNT (
EMF emf,
HPID hpid,
HTID htid,
DWORD64 cb,
DWORD64 lparam
)
/*++
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
lparam - 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;
LPPROCESSINFO lppid;
HEMP hemp;
LPEMP lpemp;
lppid = (LPPROCESSINFO) LLLock ( (HLLE)hpid );
if ( lppid == NULL ) {
return xosdInvalidParameter;
}
hemp = lppid->hempNative;
LLUnlock ( (HLLE)hpid );
lpemp = (LPEMP) LLLock ( (HLLE)hemp );
xosd = (lpemp->emfunc) ( emf, hpid, htid, cb, lparam );
LLUnlock ( (HLLE)hemp );
return xosd;
}
XOSD
EMCallBackEM (
EMF emf,
HPID hpid,
HTID htid,
DWORD dwModel,
DWORD64 cb,
DWORD64 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
dwModel - 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;
LPPROCESSINFO lppid;
HEMP hemp = 0;
HEMP hempnext = 0;
LPEMP lpemp;
assert ( hpid != NULL );
//native ems can never make this callback!
assert ( dwModel != CEXM_MDL_native );
lppid = (LPPROCESSINFO) LLLock ( (HLLE)hpid );
if ( lppid == NULL ) {
return xosdInvalidParameter;
}
while ( hemp = (HEMP)LLNext ( (HLLI)(lppid->llemp), (HLLE)hemp ) ) {
lpemp = (LPEMP) LLLock ( (HLLE)hemp );
if ( lpemp->model == dwModel ) {
hempnext = (HEMP)LLNext ( (HLLI)(lppid->llemp), (HLLE)hemp );
break;
}
LLUnlock ( (HLLE)hemp );
}
assert ( hempnext != 0 );
lpemp = (LPEMP) LLLock ( (HLLE)hempnext );
xosd = (lpemp->emfunc) ( emf, hpid, htid, cb, (DWORD64) lpv );
LLUnlock ( (HLLE)hempnext );
LLUnlock ( (HLLE)hpid );
return xosd;
}
XOSD
TLCallBack (
HPID hpid,
DWORD64 cb,
DWORD64 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;
LPPROCESSINFO lppid;
EMFUNC_ODP emfunc;
assert ( hpid != NULL );
lppid = (LPPROCESSINFO) LLLock ( (HLLE)hpid );
lpemp = (LPEMP) LLLock ( (HLLE)(lppid->hempNative) );
emfunc = lpemp->emfunc;
LLUnlock ( (HLLE)(lppid->hempNative) );
LLUnlock ( (HLLE)hpid );
xosd = (*emfunc)( emfDebugPacket, hpid, NULL, cb, (DWORD64)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,
DWORD64 wValue,
DWORD64 lpv
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
XOSD xosd = xosdNone;
HEMP hemp;
LPPROCESSINFO lppid;
LPEMP lpemp;
HLLI llemx;
if ( hpid == NULL ) {
// get oldest native EM.
if (llem != NULL) {
hemp = (HEMP)LLLast ( llemx = llem );
} else {
return(xosdInvalidParameter);
}
if (hemp == NULL) {
return(xosdInvalidParameter);
}
} else {
lppid = (LPPROCESSINFO) LLLock ( (HLLE)hpid );
assert ( lppid != NULL );
hemp = (HEMP)LLNext ( (llemx = lppid->llemp), NULL );
LLUnlock ( (HLLE)hpid );
}
lpemp = (LPEMP) LLLock ( (HLLE)hemp );
if (lpemp->emfunc != NULL) {
xosd = (lpemp->emfunc)( emf, hpid, htid, wValue, (DWORD64) lpv );
} else {
xosd = xosdInvalidParameter;
}
LLUnlock ( (HLLE)hemp );
if (xosd == xosdPunt) {
hemp = (HEMP)LLNext ( llemx, (HLLE)hemp );
do {
lpemp = (LPEMP) LLLock ( (HLLE)hemp );
xosd = (lpemp->emfunc) ( emf, hpid, htid, wValue, (DWORD64) 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,
DWORD64 wValue,
DWORD64 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 = (HTL)LLNext ( lltl, NULL );
}
else {
LPPROCESSINFO lppid = (LPPROCESSINFO) LLLock ( (HLLE)hpid );
htl = lppid->htl;
LLUnlock ( (HLLE)hpid );
}
if (!htl) {
// Do NOT assert here! The debugger is allowed to call any
// OSDebug function with an HPID which was created with (HTL)0;
// if the debugger then calls some OSDebug function which
// requires remote communication, the function will not assert,
// but will return xosdInvalidParameter. The caller may check the
// return code of the OSDebug call with an assertion if he so chooses.
xosd = xosdInvalidParameter;
}
else {
lptl = (LPTL) LLLock ( (HLLE)htl );
xosd = lptl->tlfunc ( tlf, hpid, wValue, (DWORD64)lpv );
LLUnlock ( (HLLE)htl );
}
return xosd;
}
/**** OSDDOCALLBACK - Call the debug client with a notification message ****
* *
* PURPOSE: *
* *
* INPUTS: *
* *
* OUTPUTS: *
* *
* IMPLEMENTATION: *
* *
* *
*/
XOSD
OSDDoCallBack (
DWORD wCommand,
HPID hpid,
HTID htid,
DWORD dwModel,
DWORD64 wValue,
DWORD64 lValue
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
XOSD xosd = xosdNone;
LPPROCESSINFO lppid;
assert ( hpid != NULL );
lppid = (LPPROCESSINFO) LLLock ( (HLLE)hpid );
switch ( wCommand ) {
case dbcBpt:
case dbcProcTerm:
case dbcThreadTerm:
case dbcException:
case dbcWatchPoint:
case dbcStep:
case dbcEntryPoint:
if ( lppid->lastmodel != dwModel ) {
// model has changed, issue dbcEmChange notification
xosd = lppid->lpfnsvcCC ( dbcEmChange, hpid, htid, dwModel, 0 );
lppid->lastmodel = dwModel;
}
break;
default:
// same model as before, do nothing
break;
}
xosd = lppid->lpfnsvcCC (( USHORT ) wCommand, hpid, htid, wValue, lValue );
LLUnlock ( (HLLE)hpid );
switch ( wCommand ) {
case dbcDeleteThread:
// 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 (
DBC wCommand,
HPID hpid,
HTID htid,
DWORD64 wValue,
DWORD64 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;
HEMP hemp;
LPEMP lpemp;
LPPROCESSINFO lppid;
DBCPK dbcpk;
assert ( hpid != NULL );
// get handle to the native EM
lppid = (LPPROCESSINFO) LLLock ( (HLLE)hpid );
if ( lppid->fNative ) {
LLUnlock((HLLE) hpid );
// native only mode, return
return xosd;
}
LLUnlock ( (HLLE)hpid );
dbcpk.dbc = wCommand;
dbcpk.hpid = hpid;
dbcpk.htid = htid;
dbcpk.wValue = wValue;
dbcpk.lValue = lValue;
// 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 = NULL;
while ( xosd == xosdPunt ) {
if ( ! ( hemp = (HEMP)LLNext ( lppid->llemp, (HLLE)hemp ) ) ) {
return xosd;
}
lpemp = (LPEMP) LLLock ( (HLLE)hemp );
if ( lpemp->emtype == emNative ) {
LLUnlock ( (HLLE)hemp );
return xosd;
}
xosd = (lpemp->emfunc) ( emfDbc, hpid, htid, sizeof(DBCPK), (DWORD64)&dbcpk );
LLUnlock ( (HLLE)hemp );
}
return xosd;
}
XOSD
OSDGetLastTLError(
HTL htl,
HPID hpid,
LPSTR Buffer,
ULONG Length
)
/*++
Routine Description:
Get the last error from the TL.
--*/
{
LPTL lptl;
XOSD xosd;
assert (htl);
lptl = (LPTL) LLLock ((HLLE)htl);
xosd = lptl->tlfunc (tlfGetLastError, hpid, Length, (DWORD64)Buffer);
LLUnlock ((HLLE) htl);
return xosd;
}
XOSD
OSDGetTimeStamp(
HPID hpid,
HTID htid,
LPTSTR ImageName,
PULONG TimeStamp,
PULONG CheckSum
)
{
XOSD xosd;
TCS tcs = {0};
tcs.ImageName = ImageName;
xosd = CallEM (emfGetTimeStamp, hpid, htid, sizeof (tcs), (DWORD64)&tcs);
if (TimeStamp) {
*TimeStamp = tcs.TimeStamp;
}
if (CheckSum) {
*CheckSum = tcs.CheckSum;
}
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;
LPPROCESSINFO lppid;
HEMP hemp;
LPEMP lpemp;
HEM hodem = NULL;
LPEMS lpem;
HPID hpidem = NULL;
LPHPID lphpidt;
hpid = (HPID)LLCreate ((HLLI) llpid );
if ( hpid == NULL ) {
return xosdOutOfMemory;
}
LLAdd ( (HLLI)llpid, (HLLE)hpid );
lppid = (LPPROCESSINFO) LLLock ( (HLLE)hpid );
lppid->htl = htl;
lppid->fNative = FALSE;
lppid->lastmodel = CEXM_MDL_native;
lppid->lpfnsvcCC = lpfnsvc;
lppid->lltid = LLInit ( sizeof ( THREADINFO ), llfNull, NULL, NULL );
lppid->llemp = LLInit ( sizeof ( EMP ), llfNull, EMPKill, NULL );
if ( lppid->llemp == 0 || lppid->lltid == 0 ) {
xosd = xosdOutOfMemory;
}
// create llem in lppid
while ( hodem = (HEM)LLNext ( (HLLI)llem, (HLLE)hodem ) ) {
hemp = (HEMP)LLCreate ( (HLLI)(lppid->llemp) );
if ( hemp == NULL ) {
return xosdOutOfMemory;
}
lpem = (LPEMS) LLLock ( (HLLE)hodem );
lpemp = (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 = NULL;
hodem = NULL;
while ( hodem = (HEM)LLNext ( (HLLI)llem, (HLLE)hodem ) ) {
lpem = (LPEMS) LLLock ( (HLLE)hodem );
hpidem = (HPID)LLCreate ( (HLLI)(lpem->llhpid) );
if ( hpidem == NULL ) {
LLUnlock((HLLE)hpid);
return xosdOutOfMemory;
}
lphpidt = (LPHPID) 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 );
CheckErr ( xosd );
*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;
LPTHREADINFO lptidT;
LPPROCESSINFO lppid;
Unreferenced( htid );
lppid = (LPPROCESSINFO) LLLock ( (HLLE)hpid );
htidT = (HTID)LLCreate ( (HLLI)(lppid->lltid) );
if ( htidT == NULL ) {
LLUnlock ( (HLLE)hpid );
return xosdOutOfMemory;
}
LLAdd((HLLI)(lppid->lltid), (HLLE)htidT);
lptidT = (LPTHREADINFO) 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
ODPDKill (
LPVOID lpv
)
{
LPPROCESSINFO lppid = (LPPROCESSINFO) lpv;
LLDestroy ( lppid->llemp );
LLDestroy ( lppid->lltid );
}
void
EMKill (
LPVOID lpv
)
{
LPEMS lpem = (LPEMS) lpv;
LLDestroy ( lpem->llhpid );
}
void
EMPKill (
LPVOID lpv
)
{
Unreferenced( lpv );
return;
}
void
TLKill (
LPVOID lpv
)
{
// nothing to destroy in the current implementation
}
int
EMHpidCmp (
LPVOID lpv1,
LPVOID lpv2,
LONG lParam
)
{
Unreferenced( lParam );
if ( *( (LPHPID) lpv1) == *( (LPHPID) lpv2 ) ) {
return fCmpEQ;
} else {
return fCmpLT;
}
}
#ifdef __cplusplus
} // cplusplus
#endif