|
|
/*++
Copyright (c) 1995-1999 Microsoft Corporation
Module Name:
dbginet.cxx
Abstract:
This module contains the default ntsd debugger extensions for Internet Information Server
Author:
Murali R. Krishnan (MuraliK) 16-Sept-1996
Revision History:
--*/
#include "inetdbgp.h"
/************************************************************
* Scheduler Related functions ************************************************************/
// Keep this array in synch with the SCHED_ITEM_STATE enumeration
char * g_rgchSchedState[] = { "SiError", "SiIdle", "SiActive", "SiActivePeriodic", "SiCallbackPeriodic", "SiToBeDeleted", "SiMaxItems" };
#define LookupSchedState( ItemState ) \
((((ItemState) >= SI_ERROR) && ((ItemState) <= SI_MAX_ITEMS)) ? \ g_rgchSchedState[ (ItemState)] : "<Invalid>")
// Initialize class static members
CSchedData* CSchedData::sm_psd = NULL; CLockedDoubleList CSchedData::sm_lstSchedulers; LONG CSchedData::sm_nID = 0; LONG CThreadData::sm_nID = 1000; LONG SCHED_ITEM::sm_lSerialNumber = SCHED_ITEM::SERIAL_NUM_INITIAL_VALUE;
VOID PrintSchedItem( SCHED_ITEM * pschDebuggee, SCHED_ITEM * pschDebugger, CHAR Verbosity);
VOID PrintThreadDataThunk( PVOID ptdDebuggee, PVOID ptdDebugger, CHAR chVerbosity, DWORD iThunk);
VOID PrintThreadData( CThreadData* ptdDebuggee, CThreadData* ptdDebugger, CHAR chVerbosity);
VOID PrintSchedData( CSchedData* psdDebuggee, CSchedData* psdDebugger, CHAR chVerbosity);
VOID PrintSchedDataThunk( PVOID psdDebuggee, PVOID psdDebugger, CHAR chVerbosity, DWORD iThunk);
VOID DumpSchedItemList( CHAR Verbosity );
VOID DumpSchedulersList( CHAR Verbosity );
DECLARE_API( sched )
/*++
Routine Description:
This function is called as an NTSD extension to format and dump an object attributes structure.
Arguments:
hCurrentProcess - Supplies a handle to the current process (at the time the extension was called).
hCurrentThread - Supplies a handle to the current thread (at the time the extension was called).
CurrentPc - Supplies the current pc at the time the extension is called.
lpExtensionApis - Supplies the address of the functions callable by this extension.
lpArgumentString - Supplies the asciiz string that describes the ansi string to be dumped.
Return Value:
None.
--*/ { BOOL fRet; SCHED_ITEM sch( NULL, NULL, NULL); SCHED_ITEM * psch;
INIT_API();
while (*lpArgumentString == ' ') lpArgumentString++;
if ( !*lpArgumentString ) { PrintUsage( "sched" ); return; }
if ( *lpArgumentString == '-' ) { lpArgumentString++;
if ( *lpArgumentString == 'h' ) { PrintUsage( "sched" ); return; } else if ( *lpArgumentString == 'l' ) { DumpSchedItemList( lpArgumentString[1] ); return; } else if ( *lpArgumentString == 's' ) { DumpSchedulersList( lpArgumentString[1] ); return; } else if ( *lpArgumentString == 'S' ) { CSchedData* psd = (CSchedData*) GetExpression(++lpArgumentString);
if ( !psd ) { dprintf( "inetdbg.sched: Unable to evaluate \"%s\"\n", lpArgumentString );
return; }
DEFINE_CPP_VAR(CSchedData, sd); move(sd, psd);
PrintSchedData(psd, GET_CPP_VAR_PTR(CSchedData, sd), '2'); return; } else if ( *lpArgumentString == 'T' ) { CThreadData* ptd =(CThreadData*) GetExpression(++lpArgumentString);
if ( !ptd ) { dprintf( "inetdbg.sched: Unable to evaluate \"%s\"\n", lpArgumentString );
return; }
DEFINE_CPP_VAR(CThreadData, td); move(td, ptd);
PrintThreadData(ptd, GET_CPP_VAR_PTR(CThreadData, td), '2'); return; } } // while
//
// Treat the argument as the address of a SCHED_ITEM
//
psch = (SCHED_ITEM * ) GetExpression( lpArgumentString );
if ( !psch ) { dprintf( "inetdbg.sched: Unable to evaluate \"%s\"\n", lpArgumentString );
return; }
move( sch, psch ); PrintSchedItem( psch, &sch, '2' );
return; } // DECLARE_API( sched )
VOID PrintSchedItem( SCHED_ITEM * pschDebuggee, SCHED_ITEM * pschDebugger, CHAR chVerbosity) { if ( chVerbosity >= '0' ) { // Print all with one line summary info
dprintf( "%p: Serial=%-6d Flink=%p, Blink=%p, State=%s\n", pschDebuggee, pschDebugger->_dwSerialNumber, pschDebugger->_ListEntry.Flink, pschDebugger->_ListEntry.Blink, LookupSchedState( pschDebugger->_siState) ); }
if ( chVerbosity >= '1') { UCHAR szSymFnCallback[MAX_SYMBOL_LEN]; ULONG_PTR offset;
GetSymbol((ULONG_PTR) pschDebugger->_pfnCallback, szSymFnCallback, &offset);
if (!*szSymFnCallback) sprintf((char*) szSymFnCallback, "%p()", pschDebugger->_pfnCallback);
dprintf( "\tSignature = '%c%c%c%c' Context = %08p\n" "\tmsecInterval = %8d msecExpires = %I64d\n" "\tpfnCallBack = %s\n", DECODE_SIGNATURE(pschDebugger->_Signature), pschDebugger->_pContext, pschDebugger->_msecInterval, pschDebugger->_msecExpires, szSymFnCallback ); }
return; } // PrintSchedItem()
VOID PrintSchedItemThunk( PVOID pschDebuggee, PVOID pschDebugger, CHAR chVerbosity, DWORD iThunk) { if ( ((SCHED_ITEM * )pschDebugger)->_Signature != SIGNATURE_SCHED_ITEM) {
dprintf( "SCHED_ITEM(%p) signature %08lx doesn't" " match expected %08lx\n", pschDebuggee, ((SCHED_ITEM * )pschDebugger)->_Signature, SIGNATURE_SCHED_ITEM ); return; }
PrintSchedItem( (SCHED_ITEM*) pschDebuggee, (SCHED_ITEM*) pschDebugger, chVerbosity);
} // PrintSchedItemThunk()
VOID PrintThreadData( CThreadData* ptdDebuggee, CThreadData* ptdDebugger, CHAR chVerbosity) { if ( chVerbosity >= '0' ) { // Print all with one line summary info
dprintf( "CThreadData %p: ID=%-6d, Flink=%p, Blink=%p\n", ptdDebuggee, ptdDebugger->m_nID, ptdDebugger->m_leThreads.Flink, ptdDebugger->m_leThreads.Blink ); }
if ( chVerbosity >= '1') { dprintf( "\tm_dwSignature = '%c%c%c%c' m_psdOwner = %08lp\n" "\tm_hevtShutdown = %08lp m_hThreadSelf = %08lx.\n" , DECODE_SIGNATURE(ptdDebugger->m_dwSignature), ptdDebugger->m_psdOwner, ptdDebugger->m_hevtShutdown, ptdDebugger->m_hThreadSelf ); }
return; } // PrintThreadData()
VOID PrintThreadDataThunk( PVOID ptdDebuggee, PVOID ptdDebugger, CHAR chVerbosity, DWORD iThunk) { if (((CThreadData*) ptdDebugger)->m_dwSignature != SIGNATURE_THREADDATA) { dprintf( "CThreadData(%08p) signature %08lx doesn't" " match expected: %08lx\n", ptdDebuggee, ((CThreadData * )ptdDebugger)->m_dwSignature, SIGNATURE_THREADDATA ); return; }
PrintThreadData( (CThreadData *) ptdDebuggee, (CThreadData *) ptdDebugger, chVerbosity);
} // PrintThreadDataThunk()
VOID PrintSchedData( CSchedData* psdDebuggee, CSchedData* psdDebugger, CHAR chVerbosity) { if ( chVerbosity >= '0' ) { // Print all with one line summary info
dprintf( "CSchedData %p: ID=%d, Flink=%p, Blink=%p\n", psdDebuggee, psdDebugger->m_nID, psdDebugger->m_leGlobalList.Flink, psdDebugger->m_leGlobalList.Blink ); }
if ( chVerbosity >= '1') { dprintf( "\tm_dwSignature = '%c%c%c%c' m_lstItems = %08lp\n" "\tm_lstThreads = %08lp m_cRefs = %d\n" "\tm_hevtNotify = %08lp m_fShutdown = %s\n" "\tm_pachSchedItems= %08lp\n" , DECODE_SIGNATURE(psdDebugger->m_dwSignature), &psdDebuggee->m_lstItems, &psdDebuggee->m_lstThreads, psdDebugger->m_cRefs, psdDebugger->m_hevtNotify, BoolValue(psdDebugger->m_fShutdown), psdDebugger->m_pachSchedItems ); }
if ( chVerbosity >= '2') { dprintf("Threads\n");
EnumLinkedList((LIST_ENTRY*)&psdDebuggee->m_lstThreads.m_list.m_leHead, PrintThreadDataThunk, chVerbosity, sizeof(CThreadData), FIELD_OFFSET( CThreadData, m_leThreads) ); }
return; } // PrintSchedData()
VOID PrintSchedDataThunk( PVOID psdDebuggee, PVOID psdDebugger, CHAR chVerbosity, DWORD iThunk) { if (((CSchedData*) psdDebugger)->m_dwSignature != SIGNATURE_SCHEDDATA) { dprintf( "CSchedData(%08p) signature %08lx doesn't" " match expected: %08lx\n", psdDebuggee, ((CSchedData*) psdDebugger)->m_dwSignature, SIGNATURE_SCHEDDATA ); return; }
PrintSchedData( (CSchedData*) psdDebuggee, (CSchedData*) psdDebugger, chVerbosity);
} // PrintSchedDataThunk()
VOID DumpSchedItemList( CHAR Verbosity ) { CSchedData** ppsd = (CSchedData**) GetExpression( IisRtlVar("&%s!CSchedData__sm_psd")); if (NULL == ppsd) { dprintf("Unable to get %s\n", IisRtlVar("&%s!CSchedData__sm_psd")); return; }
CSchedData* psd; move(psd, ppsd);
DEFINE_CPP_VAR( CSchedData, sd); move(sd, psd);
PrintSchedData(psd, GET_CPP_VAR_PTR(CSchedData, sd), Verbosity); dprintf("\n");
EnumLinkedList( (LIST_ENTRY*) &psd->m_lstItems.m_list.m_leHead, PrintSchedItemThunk, Verbosity, sizeof( SCHED_ITEM), FIELD_OFFSET( SCHED_ITEM, _ListEntry) ); return; } // DumpSchedItemList()
VOID DumpSchedulersList( CHAR Verbosity ) { CLockedDoubleList* plstSchedulers = (CLockedDoubleList*) GetExpression( IisRtlVar("&%s!CSchedData__sm_lstSchedulers"));
if (NULL == plstSchedulers) { dprintf("Unable to get %s\n", IisRtlVar("&%s!CSchedData__sm_lstSchedulers")); return; }
EnumLinkedList( (LIST_ENTRY*) &plstSchedulers->m_list.m_leHead, PrintSchedDataThunk, Verbosity, sizeof(CSchedData), FIELD_OFFSET( CSchedData, m_leGlobalList) ); return; } // DumpSchedulersList()
/************************************************************
* Allocation cache Related functions ************************************************************/
ALLOC_CACHE_HANDLER::ALLOC_CACHE_HANDLER( IN LPCSTR pszName, IN const ALLOC_CACHE_CONFIGURATION * pacConfig) {}
ALLOC_CACHE_HANDLER::~ALLOC_CACHE_HANDLER(VOID) {}
VOID PrintAcacheHandler( IN ALLOC_CACHE_HANDLER * pachDebuggee, IN ALLOC_CACHE_HANDLER * pachDebugger, IN CHAR chVerbostity);
VOID DumpAcacheGlobals( VOID );
VOID DumpAcacheList( CHAR Verbosity );
DECLARE_API( acache )
/*++
Routine Description:
This function is called as an NTSD extension to format and dump an object attributes structure.
Arguments:
hCurrentProcess - Supplies a handle to the current process (at the time the extension was called).
hCurrentThread - Supplies a handle to the current thread (at the time the extension was called).
CurrentPc - Supplies the current pc at the time the extension is called.
lpExtensionApis - Supplies the address of the functions callable by this extension.
lpArgumentString - Supplies the asciiz string that describes the ansi string to be dumped.
Return Value:
None.
--*/ { BOOL fRet; ALLOC_CACHE_HANDLER * pach;
//
// Since ALLOC_CACHE_HANDLER is a C++ object with a non-void
// constructor, we will have to copy the contents to a temporary
// buffer and cast the value appropriately.
//
CHAR achItem[sizeof(ALLOC_CACHE_HANDLER)]; ALLOC_CACHE_HANDLER * pachCopy = (ALLOC_CACHE_HANDLER *) achItem;
INIT_API();
while (*lpArgumentString == ' ') lpArgumentString++;
if ( !*lpArgumentString ) { PrintUsage( "acache" ); return; }
if ( *lpArgumentString == '-' ) { lpArgumentString++;
if ( *lpArgumentString == 'h' ) { PrintUsage( "acache" ); return; }
if ( *lpArgumentString == 'g' ) { DumpAcacheGlobals(); return; }
if ( *lpArgumentString == 'l' ) {
DumpAcacheList( lpArgumentString[1] ); return; }
} // while
//
// Treat the argument as the address of an AtqContext
//
dprintf( "inetdbg.acache: Trying to access %s\n", lpArgumentString );
pach = (ALLOC_CACHE_HANDLER * ) GetExpression( lpArgumentString );
if ( !pach ) { dprintf( "inetdbg.acache: Unable to evaluate \"%s\"\n", lpArgumentString );
return; }
moveBlock( achItem, pach, sizeof(ALLOC_CACHE_HANDLER)); PrintAcacheHandler( pach, pachCopy, '2' );
return; } // DECLARE_API( acache )
VOID PrintAcacheHandler( ALLOC_CACHE_HANDLER * pachDebuggee, ALLOC_CACHE_HANDLER * pachDebugger, CHAR chVerbosity) { if ( chVerbosity >= '0') { dprintf( "ACACHE[%8p] " , pachDebuggee ); dstring( "Name", (PVOID) pachDebugger->m_pszName, 40); }
if ( chVerbosity >= '1') { dprintf("\t(Size=%d bytes, Concurrency=%d, Threshold=%u)" " FillPattern=%08lX\n" "\tTotal=%d." " Calls:(Alloc=%d, Free=%d)" " FreeEntries=%d. Heap=%p.\n" , pachDebugger->m_acConfig.cbSize, pachDebugger->m_acConfig.nConcurrency, pachDebugger->m_acConfig.nThreshold, pachDebugger->m_nFillPattern, pachDebugger->m_nTotal, pachDebugger->m_nAllocCalls, pachDebugger->m_nFreeCalls, pachDebugger->m_nFreeEntries, pachDebugger->m_hHeap ); }
return; } // PrintAcacheHandler()
VOID PrintAcacheHandlerThunk( PVOID pachDebuggee, PVOID pachDebugger, CHAR chVerbosity, DWORD iCount) { dprintf( "[%d] ", iCount); PrintAcacheHandler( (ALLOC_CACHE_HANDLER *) pachDebuggee, (ALLOC_CACHE_HANDLER *) pachDebugger, chVerbosity); return; } // PrintAcacheHandlerThunk()
VOID DumpAcacheGlobals( VOID ) { LIST_ENTRY * pachList; LIST_ENTRY achList;
dprintf("Allocation Cache Globals:\n");
pachList = (LIST_ENTRY *) GetExpression( IisRtlVar("&%s!ALLOC_CACHE_HANDLER__sm_lItemsHead"));
if ( NULL == pachList) {
dprintf( " Unable to get Allocation cache list object, %s\n", IisRtlVar("&%s!ALLOC_CACHE_HANDLER__sm_lItemsHead")); return; }
move( achList, pachList);
dprintf( " AllocCacheList Flink = %08p Blink = %08p\n", achList.Flink, achList.Blink );
dprintf("\tsizeof(ALLOC_CACHE_HANDLER) = %d\n", sizeof(ALLOC_CACHE_HANDLER)); return; } // DumpAcacheGlobals()
VOID DumpAcacheList( CHAR Verbosity ) { LIST_ENTRY * pachListHead;
pachListHead = (LIST_ENTRY *) GetExpression( IisRtlVar("&%s!ALLOC_CACHE_HANDLER__sm_lItemsHead"));
if ( NULL == pachListHead) {
dprintf( " Unable to get Alloc Cache List object, %s\n", IisRtlVar("&%s!ALLOC_CACHE_HANDLER__sm_lItemsHead")); return; }
EnumLinkedList( pachListHead, PrintAcacheHandlerThunk, Verbosity, sizeof( ALLOC_CACHE_HANDLER), FIELD_OFFSET( ALLOC_CACHE_HANDLER, m_lItemsEntry) ); return; } // DumpAcacheList()
/************************************************************
* Dump Symbols from stack ************************************************************/
DECLARE_API( ds )
/*++
Routine Description:
This function is called as an NTSD extension to format and dump symbols on the stack.
Arguments:
hCurrentProcess - Supplies a handle to the current process (at the time the extension was called).
hCurrentThread - Supplies a handle to the current thread (at the time the extension was called).
CurrentPc - Supplies the current pc at the time the extension is called.
lpExtensionApis - Supplies the address of the functions callable by this extension.
lpArgumentString - Supplies the asciiz string that describes the ansi string to be dumped.
Return Value:
None.
--*/
{ ULONG_PTR startingAddress; ULONG_PTR stack; DWORD i; UCHAR symbol[MAX_SYMBOL_LEN]; ULONG_PTR offset; PCHAR format; BOOL validSymbolsOnly = FALSE; MODULE_INFO moduleInfo;
INIT_API();
//
// Skip leading blanks.
//
while( *lpArgumentString == ' ' ) { lpArgumentString++; }
if( *lpArgumentString == '-' ) { lpArgumentString++; switch( *lpArgumentString ) { case 'v' : case 'V' : validSymbolsOnly = TRUE; lpArgumentString++; break;
default : PrintUsage( "ds" ); return; } }
while( *lpArgumentString == ' ' ) { lpArgumentString++; }
//
// By default, start at the current stack location. Otherwise,
// start at the given address.
//
if( !*lpArgumentString ) { #if defined(_X86_)
lpArgumentString = "esp"; #elif defined(_AMD64_)
lpArgumentString = "rsp"; #elif defined(_IA64_)
lpArgumentString = "sp"; #else
#error "unsupported CPU"
#endif
}
startingAddress = GetExpression( lpArgumentString );
if( startingAddress == 0 ) {
dprintf( "!inetdbg.ds: cannot evaluate \"%s\"\n", lpArgumentString );
return;
}
//
// Ensure startingAddress is DWORD aligned.
//
startingAddress &= ~(sizeof(ULONG_PTR)-1);
//
// Read the stack.
//
for( i = 0 ; i < NUM_STACK_SYMBOLS_TO_DUMP ; startingAddress += sizeof(ULONG_PTR) ) {
if( CheckControlC() ) { break; }
if( ReadMemory( startingAddress, &stack, sizeof(stack), NULL ) ) {
GetSymbol( stack, symbol, &offset );
if( symbol[0] == '\0' ) { if( FindModuleByAddress( stack, &moduleInfo ) ) { strcpy( (CHAR *)symbol, moduleInfo.FullName ); offset = DIFF(stack - moduleInfo.DllBase); } }
if( symbol[0] == '\0' ) { if( validSymbolsOnly ) { continue; } format = "%p : %p\n"; } else if( offset == 0 ) { format = "%p : %p : %s\n"; } else { format = "%p : %p : %s+0x%lx\n"; }
dprintf( format, startingAddress, stack, symbol, (DWORD)offset );
i++;
} else {
dprintf( "!inetdbg.ds: cannot read memory @ %p\n", startingAddress );
return;
}
}
dprintf( "!inetdbg.ds %s%lx to dump next block\n", validSymbolsOnly ? "-v " : "", startingAddress );
} // DECLARE_API( ds )
|