windows-nt/Source/XPSP1/NT/inetsrv/iis/svcs/dbgext/dbginet.cxx
2020-09-26 16:20:57 +08:00

903 lines
21 KiB
C++
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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