Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

Monitoring NT Debug Services


February 2000/Monitoring NT Debug Services/Listing 2

Listing 2: debugser.cpp — Interrupt-handling code

#include "DbgTrapProcs.h"
#include "idt.h"

typedef struct DBG_PRINT_PARAMS
{
    DWORD   s;
    char*   pString;    // string to DbgPrint
    DWORD   u;
    PVOID   caller;     // Return address of who invoked DbgPrint()
} DBG_PRINT_PARAMS, *PDBG_PRINT_PARAMS;


DWORD   debugServiceVector = 0x2D;    // Interrupt vector used by NT
BOOL    bWeHooked = FALSE; // Are we hooked yet..with some soul
NT_IDT  oldIDTE; // Original IDT entry for debug service we replace
PVOID   oldISR;   // Original ISR for Debugger service
BOOL    bLogUser    = TRUE;
BOOL    bLogKernel  = TRUE;
PDBGTRAP_HEADER pHeader;    // Header for giving info to the GUI
PDBGTRAP_EVENT  peb;        // Our event buffer
DWORD   maxBufferSize = 256*1024;// Max Size of our event buffer (eb)
DWORD   bufferSize;         // Actual # of bytes allocated for eb
DWORD   numEntries;         // Max entries in the event buffer
KSPIN_LOCK      bl;         // Buffer Lock
PDWORD   pindex;            // Pointer to current index in buffer
DWORD    imgNameOfs;        // Offset in KPEB for image name

// NOTE: these must be used in the same scope
#define LOCK_BUFFER KIRQL __oldirql__ = \
    KeAcquireSpinLockRaiseToSynch( &bl );
#define UNLOCK_BUFFER   KeReleaseSpinLock( & bl, __oldirql__ );

void ResetBuffer()
{
    LOCK_BUFFER
    memset( peb, 0, bufferSize );
    *pindex = 0;
    UNLOCK_BUFFER 
}

NTSTATUS InitTrapper()
{
    // Allocate a buffer that holds exactly N events, plus the header
    numEntries = (maxBufferSize-sizeof(DBGTRAP_HEADER))
                 /sizeof(DBGTRAP_EVENT);
    bufferSize = numEntries*sizeof(DBGTRAP_EVENT)
                 +sizeof(DBGTRAP_HEADER);
    pHeader = (PDBGTRAP_HEADER)
              ExAllocatePool(NonPagedPool, bufferSize);
    if ( pHeader == FALSE)
        return STATUS_INSUFFICIENT_RESOURCES;
    // Initialize the header
    pHeader->size       = sizeof(DBGTRAP_HEADER);
    pHeader->version    = DT_VERSION;
    pHeader->sig        = 'JOSE';  // Shameless, I know...
    pHeader->numEntries = numEntries;
    pHeader->index      = 0;
    // Initialize the buffer & counter
    peb     = &pHeader->eb[0];
    pindex  = &pHeader->index;
    // Initialize the buffer lock
    KeInitializeSpinLock( &bl );
    // Set vars correctly
    DWORD mv;
    PsGetVersion( &mv, NULL, NULL, NULL );
    if ( mv == 5)
         imgNameOfs = 0x1fc;
    else
       imgNameOfs = 0x1DC;

    ResetBuffer();
    return STATUS_SUCCESS;
}

// Free up our trapper resources
void BringDownTrapper()
{
    // Since there is no safe way to syncronize freeing the buffer
    // with buffer logging, or debug service interrupt hook *must*
    // have been removed prior to calling here.
    ExFreePool( pHeader );
}

// Logs parameters specific to a DbgPrint() call
void LogDbgPrint(PDBGTRAP_EVENT pEvent, PDBG_PRINT_PARAMS param)
{
   pEvent->callingAddr  = param->caller;

   DWORD l = strlen( param->pString );
   l = (l>MAX_STRING_LENGTH) ? MAX_STRING_LENGTH-1 : l;
   
   memcpy( pEvent->string, param->pString, l );
   pEvent->string[ MAX_STRING_LENGTH-1 ] = 0;
}

// Logs parameters specific to Dbg(Un)LoadImageSymbols()
void LogLoadImageSymbols(PDBGTRAP_EVENT    pEvent,
      PANSI_STRING      name,
      PVOID*            baseAddr  )
{
   char n[256];
   char buff[sizeof(n)+10];

   pEvent->callingAddr = baseAddr[5];
   memcpy( n, name->Buffer, name->Length );
   n[name->Length] = '\0';
   DWORD l = sprintf( buff, "Driver %s @ 0x%x", n, *baseAddr );
   l = (l>MAX_STRING_LENGTH) ? MAX_STRING_LENGTH-1 : l;
   memcpy( pEvent->string, buff, l );
   pEvent->string[ MAX_STRING_LENGTH-1 ] = 0;
}

// Logs general parameters common to all debug services
void LogEvent(PDBGTRAP_EVENT pEvent, NtDebuggerService service)
{
    PEPROCESS pep = 0;
    pEvent->count = *pindex;
    KeQuerySystemTime( &pEvent->time );
    pEvent->pid = PsGetCurrentProcessId();
    pep = PsGetCurrentProcess();
    strcpy( pEvent->procName, &((CHAR*)pep)[imgNameOfs] );
    pEvent->action = service;
}

void LoggerDispatch(NtDebuggerService service, PVOID paramsCX,
      PVOID paramsDX)
{
   LOCK_BUFFER
   // see if we're going to overrun  the buffer
   if ( *pindex >= numEntries )
      *pindex = 0;
   PDBGTRAP_EVENT pCurrentEvent = &peb[*pindex];
   switch (service)
   {
      case DS_PRINT:
         LogDbgPrint( pCurrentEvent, (PDBG_PRINT_PARAMS)paramsCX );
           break;
      case DS_PROMPT:
           break;
      case DS_LOADSYMBOLS:
      case DS_UNLOADSYMBOLS:
         LogLoadImageSymbols( pCurrentEvent, 
                (PANSI_STRING)paramsCX, (PVOID*)paramsDX);
           break;
   }
   LogEvent( pCurrentEvent, service );
   ++*pindex;
   UNLOCK_BUFFER
}

void _declspec(naked) DTDebuggerTrap()
{
    static NtDebuggerService   service;    // Which debugger service
                                           // is requested
    static DWORD               paramsCX;   // Parameters passed to
                                           // the service
    static DWORD               paramsDX;
    _asm
    {  
        // Check & see if there's anything to do
        test  [esp+8], X86_VM // VDM  doesn't have Dbg services
        jnz   DT_CHAIN
        test [esp+4], X86_USER
        jz  DT_CAMEFROMKERNEL
        cmp [esp+4], NT_UCS   // Don't log if user selector != 1b
        jnz DT_CHAIN
        cmp BYTE PTR ss:[bLogUser], 0 // Don't log of GUI says not to
        jz  DT_CHAIN
        jmp DT_LOG           // Passed all tests, log user event
DT_CAMEFROMKERNEL:
        cmp ss:[bLogKernel], 0
        jz  DT_CHAIN
        // First rule of tinkering: 
        //      "Save all the pieces"
        // So let's Set up a semi-standard environment
DT_LOG:
        pushad
        push    ds
        push    es
        push    gs
        push    fs
        mov     bx, NT_DS
        mov     ds, bx
        mov     es, bx
        mov     gs, bx
        mov     bx, NT_FS
        mov     fs, bx
        push   edx
        push   ecx
        push   eax
        call   LoggerDispatch
        // Restore everything
        pop     fs
        pop     gs
        pop     es
        pop     ds
        popad
        // Chain to original ISR
DT_CHAIN:
        jmp     cs:[oldISR]
    }
}

// This guy actually installs the hook on the debug service vector.
// Returns TRUE if we actually did anything, FALSE if not. 
// NOTE: This routine (like others in this driver) is NOT thread 
// safe. Our whole subsystem currently expects a single
// controler-single reader (but can have mutliple writers(cpus)). 
// This routine should therefore only be called inside a dispatch 
// routine from the GUI, or in the context of the system's worker 
// thred via DriverEntry, or Unload.
BOOL InstallDebugServiceHook(BOOL bHook)
{
    PNT_IDT pidtBase = NULL;

    // Anything to do?
    if ( bWeHooked == bHook )
        return FALSE;        
    // Loop  over all processors & hook the debug service vector
    for ( char cpu=0; cpu<*KeNumberProcessors; ++cpu )
    {
       PKTHREAD pThread = KeGetCurrentThread();
       KeSetAffinityThread( pThread, 1<<cpu );
       // Get this processor's IDT base address
       pidtBase = GetIDTBase();
       if ( bHook )
           pidtBase[ debugServiceVector ].Hook( DTDebuggerTrap, &oldISR );
       else
           pidtBase[ debugServiceVector ].Hook( oldISR );   
    }

    // Set the thread's affinity back to run on all processors
    PKTHREAD pThread = KeGetCurrentThread();
    KeSetAffinityThread( pThread, (1<<*KeNumberProcessors)-1 );
    // No turning back now...all or nothing
    bWeHooked = !bWeHooked;  

    return TRUE;
}
//End of File

Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.