/*++ 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 #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 ); }