/*++ 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) ] :\ "") /************************************************************ * 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 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 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 ***********************/