|
|
/*++
Copyright (c) 1995-1997 Microsoft Corporation
Module Name :
dbgatq.cxx
Abstract:
This module contains the NTSD Debugger extensions for the Asynchronous Thread Queue DLL
Author:
Murali R. Krishnan ( MuraliK ) 12-May-1997
Environment: Debugger Mode - inside NT command line debuggers
Project:
Internet Server Debugging DLL
Functions Exported:
Revision History:
--*/
/************************************************************
* Include Headers ************************************************************/
#include "inetdbgp.h"
/************************************************************
* Definitions of Variables & Macros ************************************************************/
//
// Text names of ATQ_SOCK_STATE values
//
char * AtqSockState[] = { "ATQ_SOCK_CLOSED", "ATQ_SOCK_UNCONNECTED", "ATQ_SOCK_LISTENING", "ATQ_SOCK_CONNECTED" };
char * AtqEndpointState[] = { "AtqStateInit", "AtqStateActive", "AtqStateClosed", "AtqStateMax", };
#define LookupSockState( SockState ) \
((SockState) <= ATQ_SOCK_CONNECTED ? AtqSockState[ (SockState) ] :\ "<Invalid>")
/************************************************************
* Functions ************************************************************/
VOID DumpAtqGlobals( VOID );
VOID DumpAtqContextList( CHAR Level, CHAR Verbosity, ATQ_ENDPOINT * pEndpointIn );
void DumpEndpointList( LIST_ENTRY * pAtqClientHead, CHAR Level, DWORD * pcContext, BYTE * pvStart, BYTE * pvEnd, ATQ_ENDPOINT * pEndpointIn );
VOID PrintAtqContext( ATQ_CONTEXT * AtqContext );
void PrintEndpoint( ATQ_ENDPOINT * pEp );
VOID DumpEndpoint( CHAR Level );
DECLARE_API( atq )
/*++
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; ATQ_CONTEXT AtqContext; ATQ_CONTEXT * pAtqContext;
INIT_API();
while (*lpArgumentString == ' ') lpArgumentString++;
if ( !*lpArgumentString ) { PrintUsage( "atq" ); return; }
if ( *lpArgumentString == '-' ) { lpArgumentString++;
switch ( *lpArgumentString ) {
case 'g': { DumpAtqGlobals(); break; }
case 'c': { DumpAtqContextList( lpArgumentString[1], lpArgumentString[2], NULL ); break; }
case 'e': {
ATQ_ENDPOINT * pEndpoint;
// Arguments: -e<Level><Verbosity> <EndpointAddr>
pEndpoint = ((ATQ_ENDPOINT * ) GetExpression( lpArgumentString + 4)); if ( !pEndpoint ) {
dprintf( "inetdbg: Unable to evaluate " "EndpointAddr \"%s\"\n", lpArgumentString );
break; }
DumpAtqContextList( lpArgumentString[1], lpArgumentString[2], pEndpoint ); break; }
case 'l': { DumpEndpoint( lpArgumentString[1] ); break; }
case 'p': { //
// Treat the argument as the address of an AtqEndpoint
//
ATQ_ENDPOINT * pEndpoint;
// Arguments: -p <EndpointAddr>
pEndpoint = ((ATQ_ENDPOINT *) GetExpression( lpArgumentString + 2 ) );
if ( !pEndpoint ) { dprintf( "inetdbg: Unable to evaluate \"%s\"\n", lpArgumentString );
break; } else { ATQ_ENDPOINT Endpoint; move( Endpoint, pEndpoint ); PrintEndpoint( &Endpoint ); } break; }
default: case 'h': { PrintUsage( "atq" ); break; }
} // switch
return; }
//
// Treat the argument as the address of an AtqContext
//
pAtqContext = (PATQ_CONT)GetExpression( lpArgumentString );
if ( !pAtqContext ) { dprintf( "inetdbg: Unable to evaluate \"%s\"\n", lpArgumentString );
return; }
move( AtqContext, pAtqContext ); PrintAtqContext( &AtqContext ); } // DECLARE_API( atq )
/************************************************************
* ATQ related functions ************************************************************/
VOID DumpAtqGlobals( VOID ) { //
// Dump Atq Globals
//
dprintf("Atq Globals:\n");
DumpDword( "isatq!g_cConcurrency " ); DumpDword( "isatq!g_cThreads " ); DumpDword( "isatq!g_cAvailableThreads " ); DumpDword( "isatq!g_cMaxThreads " );
dprintf("\n"); DumpDword( "isatq!g_fUseAcceptEx " ); DumpDword( "isatq!g_fUseTransmitFile " ); DumpDword( "isatq!g_cbXmitBufferSize " ); DumpDword( "isatq!g_cbMinKbSec " ); DumpDword( "isatq!g_cCPU " ); DumpDword( "isatq!g_fShutdown " ); dprintf("\n");
DumpDword( "isatq!g_msThreadTimeout " ); DumpDword( "isatq!g_dwTimeoutCookie " ); DumpDword( "isatq!g_cListenBacklog " ); DumpDword( "isatq!AtqCurrentTick " ); DumpDword( "isatq!AtqGlobalContextCount" ); dprintf("\tsizeof(ATQ_CONTEXT) = %d\n", sizeof(ATQ_CONTEXT));
return; } // DumpAtqGlobals()
VOID DumpAtqContextList( CHAR Level, CHAR Verbosity, ATQ_ENDPOINT * pEndpointIn ) { LIST_ENTRY AtqClientHead; LIST_ENTRY * pAtqClientHead; ATQ_CONTEXT * pAtqContext; ATQ_CONTEXT AtqContext; CHAR Symbol[256]; DWORD cContext = 0; DWORD cc1; ATQ_CONTEXT_LISTHEAD * pAtqActiveContextList; ATQ_CONTEXT_LISTHEAD AtqActiveContextList[ATQ_NUM_CONTEXT_LIST]; DWORD i;
pAtqActiveContextList = (ATQ_CONTEXT_LISTHEAD *) GetExpression( "&isatq!AtqActiveContextList" );
if ( !pAtqActiveContextList ) { dprintf("Unable to get AtqActiveContextList symbol\n" ); return; }
if ( !ReadMemory( (LPVOID) pAtqActiveContextList, AtqActiveContextList, sizeof(AtqActiveContextList), NULL )) { dprintf("Unable to read AtqActiveContextList memory\n" ); return; }
for ( i = 0; i < ATQ_NUM_CONTEXT_LIST; i++ ) { dprintf("================================================\n"); dprintf("== Context List %d ==\n", i ); dprintf("================================================\n");
dprintf(" Active List ==>\n" );
cc1 = 0; DumpEndpointList( &(AtqActiveContextList[i].ActiveListHead), Verbosity, &cc1, (BYTE *) pAtqActiveContextList, (BYTE *) &pAtqActiveContextList[ATQ_NUM_CONTEXT_LIST], pEndpointIn );
if ( 0 != cc1) { dprintf( "\n\t%d Atq contexts traversed\n", cc1 ); cContext += cc1; }
if ( Level >= '1' ) { dprintf("================================================\n"); dprintf("Pending AcceptEx List\n");
cc1 = 0; DumpEndpointList( &(AtqActiveContextList[i].PendingAcceptExListHead), Verbosity, &cc1, (BYTE *) pAtqActiveContextList, (BYTE *) &pAtqActiveContextList[ATQ_NUM_CONTEXT_LIST], pEndpointIn ); if ( 0 != cc1) { dprintf( "\n\t%d Atq contexts traversed\n", cc1 ); cContext += cc1; } }
if ( CheckControlC() ) { dprintf( "\n^C\n" ); return; }
}
dprintf( "%d Atq contexts traversed\n", cContext );
return; } // DumpAtqContextList()
void DumpEndpointList( LIST_ENTRY * pAtqClientHead, CHAR Verbosity, DWORD * pcContext, BYTE * pvStart, BYTE * pvEnd, ATQ_ENDPOINT * pEndpointIn ) { LIST_ENTRY * pEntry; ATQ_CONTEXT * pAtqContext; ATQ_CONTEXT AtqContext;
//
// the list head is embedded in a structure so the exit condition of the
// loop is when the remote memory address ends up in the array memory
//
for ( pEntry = pAtqClientHead->Flink; !((BYTE *)pEntry >= pvStart && (BYTE *)pEntry <= pvEnd); ) { if ( CheckControlC() ) { return; }
pAtqContext = CONTAINING_RECORD( pEntry, ATQ_CONTEXT, m_leTimeout );
move( AtqContext, pAtqContext );
// selectively print only the contexts that have a matching Endpoint
if ( (pEndpointIn != NULL) && (AtqContext.pEndpoint != pEndpointIn) ) {
move( pEntry, &pEntry->Flink ); continue; }
(*pcContext)++;
if ( AtqContext.Signature != ATQ_CONTEXT_SIGNATURE ) { dprintf( "AtqContext(%08lp) signature %08lx doesn't" " match expected %08lx\n", pAtqContext, AtqContext.Signature, ATQ_CONTEXT_SIGNATURE );
return; }
if ( Verbosity >= '1' ) { //
// Print all
//
dprintf( "\nAtqContext at %08lp\n", pAtqContext );
PrintAtqContext( &AtqContext );
} else if ( Verbosity >= '0' ) { //
// Print all with one line summary info
//
dprintf( "hAsyncIO = %4lp, Flink = %08lp, Blink = %08lp," " State = %8lx, Flags =%8lx\n", AtqContext.hAsyncIO, AtqContext.m_leTimeout.Blink, AtqContext.m_leTimeout.Flink, AtqContext.m_acState, AtqContext.m_acFlags ); }
move( pEntry, &pEntry->Flink ); } } // DumpEndpointList()
VOID PrintAtqContext( ATQ_CONTEXT * pContext ) { UCHAR szSymFnCallback[MAX_SYMBOL_LEN]; ULONG_PTR offset;
GetSymbol((ULONG_PTR) pContext->pfnCompletion, szSymFnCallback, &offset);
if (!*szSymFnCallback) sprintf((char*) szSymFnCallback, "%p()", pContext->pfnCompletion);
dprintf( "\n" ); dprintf( "\thAsyncIO = %08lp Signature = %08lx\n" "\tOverlapped.Internal = %08lp Overlapped.Offset= %08lx\n" "\tLE-Timeout.Flink = %08lp LE-Timeout.Blink = %p\n" "\tClientContext = %08lp ContextList = %p\n" "\tpfnIOCompletion = %s\n" "\tlSyncTimeout = %8d m_nIO = %8d\n" "\tTimeOut = %08lx NextTimeout = %08lx\n" "\tBytesSent = %d (0x%08lx)\n" "\tpvBuff = %08lp pEndPoint = %08lp\n" "\tState = %8lx Flags = %08lx\n", pContext->hAsyncIO, pContext->Signature, pContext->Overlapped.Internal,pContext->Overlapped.Offset, pContext->m_leTimeout.Flink, pContext->m_leTimeout.Blink, pContext->ClientContext, pContext->ContextList, szSymFnCallback, pContext->lSyncTimeout, pContext->m_nIO, pContext->TimeOut, pContext->NextTimeout, pContext->BytesSent, pContext->BytesSent, pContext->pvBuff, pContext->pEndpoint, pContext->m_acState, pContext->m_acFlags );
// identify and print the various properties
dprintf( "\t"); // First print the state bits
if ( pContext->m_acState & ACS_SOCK_CLOSED) { dprintf( " ACS_SOCK_CLOSED"); } if ( pContext->m_acState & ACS_SOCK_UNCONNECTED) { dprintf( " ACS_SOCK_UNCONNECTED"); } if ( pContext->m_acState & ACS_SOCK_LISTENING) { dprintf( " ACS_SOCK_LISTENING"); } if ( pContext->m_acState & ACS_SOCK_CONNECTED) { dprintf( " ACS_SOCK_CONNECTED"); } if ( pContext->m_acState & ACS_SOCK_TOBE_FREED) { dprintf( " ACS_SOCK_TOBE_FREED"); }
// now print the flags associated with this context
if ( pContext->m_acFlags & ACF_ACCEPTEX_ROOT_CONTEXT) { dprintf( " ACCEPTEX_CONTEXT"); } if ( pContext->m_acFlags & ACF_CONN_INDICATED) { dprintf( " CONNECTION_INDICATED"); } if ( pContext->m_acFlags & ACF_IN_TIMEOUT) { dprintf( " IN_TIMEOUT"); } if ( pContext->m_acFlags & ACF_BLOCKED) { dprintf( " BLOCKED_BY_BWT"); } if ( pContext->m_acFlags & ACF_REUSE_CONTEXT) { dprintf( " REUSE_CONTEXT"); } if ( pContext->m_acFlags & ACF_RECV_ISSUED) { dprintf( " RECV_ISSUED"); } if ( pContext->m_acFlags & ACF_ABORTIVE_CLOSE) { dprintf( " ABORTIVE_CLOSE"); } dprintf( "\n");
if ( pContext->IsFlag( ACF_ACCEPTEX_ROOT_CONTEXT) && pContext->pvBuff ) { //
// This size should correspond to the MIN_SOCKADDR_SIZE field in
// atqnew.c. We assume it's two thirty two byte values currently.
//
DWORD AddrInfo[16]; ATQ_ENDPOINT * pEndpoint = pContext->pEndpoint; ATQ_ENDPOINT Endpoint;
move( Endpoint, pEndpoint );
if ( ReadMemory( (LPVOID) ((BYTE *) pContext->pvBuff + Endpoint.InitialRecvSize + 2 * MIN_SOCKADDR_SIZE - sizeof( AddrInfo )), AddrInfo, sizeof(AddrInfo), NULL )) {
dprintf( "\tLocal/Remote Addr = %08x %08x %08x %08x\n" "\t %08x %08x %08x %08x\n" "\t %08x %08x %08x %08x\n" "\t %08x %08x %08x %08x\n", AddrInfo[0], AddrInfo[1], AddrInfo[2], AddrInfo[3], AddrInfo[4], AddrInfo[5], AddrInfo[6], AddrInfo[7], AddrInfo[8], AddrInfo[9], AddrInfo[10], AddrInfo[11], AddrInfo[12], AddrInfo[13], AddrInfo[14], AddrInfo[15] ); } } } // PrintAtqContext()
VOID DumpEndpoint( CHAR Verbosity ) { LIST_ENTRY AtqEndpointList; LIST_ENTRY * pAtqEndpointList; LIST_ENTRY * pEntry; ATQ_CONTEXT * pAtqContext; ATQ_CONTEXT AtqContext; CHAR Symbol[256]; DWORD cEndp = 0; DWORD i; ATQ_ENDPOINT * pEndpoint; ATQ_ENDPOINT Endpoint;
pAtqEndpointList = (LIST_ENTRY *) GetExpression( "&isatq!AtqEndpointList" );
if ( !pAtqEndpointList ) { dprintf("Unable to get AtqEndpointList symbol\n" ); return; }
move( AtqEndpointList, pAtqEndpointList );
for ( pEntry = AtqEndpointList.Flink; pEntry != pAtqEndpointList; cEndp++ ) { if ( CheckControlC() ) { return; }
pEndpoint = CONTAINING_RECORD( pEntry, ATQ_ENDPOINT, ListEntry );
move( Endpoint, pEndpoint );
if ( Endpoint.Signature != ATQ_ENDPOINT_SIGNATURE ) { dprintf( "Endpoint(%08p) signature %08lx doesn't match expected %08lx\n", pEndpoint, Endpoint.Signature, ATQ_ENDPOINT_SIGNATURE );
break; }
if ( Verbosity >= '1' ) { //
// Print all
//
dprintf( "\nEndpoint at %08lp\n", pEndpoint );
PrintEndpoint( &Endpoint );
} else if ( Verbosity >= '0' ) { //
// Print all with one line summary info
//
dprintf( "sListenSocket = %4lp, cRef = %d, cSocketsAvail = %d\n", Endpoint.ListenSocket, Endpoint.m_refCount, Endpoint.nSocketsAvail ); }
move( pEntry, &pEntry->Flink ); }
dprintf( "%d Atq Endpoints traversed\n", cEndp );
return; } // DumpEndpoint()
void PrintEndpoint( ATQ_ENDPOINT * pEp ) {
dprintf( "\tcRef = %8d State = %s\n" "\tIP Address = %s Port = %04x\n" "\tsListenSocket = %8p InitRecvSize = %04x\n" "\tnSocketsAvail = %8d nAvailAtTimeout = %d\n" "\tnAcceptExOutstdg =%8d\n" "\tUseAcceptEx = %8s AcceptExTimeout = %8d\n" "\tEnableBw Throttle= %s\n" "\tListEntry.Flink = %08lp ListEntry.Blink = %08lp\n" "\tClient Context = %08lp pfnCompletion = %08lp()\n" "\tpfnConnComp = %08lp() pfnConnExComp = %08lp()\n" "\tShutDownCallback = %08lp() ShutDown Context = %08lp\n" , pEp->m_refCount, AtqEndpointState[pEp->State], pEp->IpAddress, pEp->Port, pEp->ListenSocket, pEp->InitialRecvSize, pEp->nSocketsAvail, pEp->nAvailDuringTimeOut, pEp->nAcceptExOutstanding, BoolValue( pEp->UseAcceptEx), pEp->AcceptExTimeout, BoolValue( pEp->EnableBw), pEp->ListEntry.Flink, pEp->ListEntry.Blink, pEp->Context, pEp->IoCompletion, pEp->ConnectCompletion, pEp->ConnectExCompletion, pEp->ShutdownCallback, pEp->ShutdownCallbackContext );
return; } // PrintEndpoint()
/************************ End of File ***********************/
|