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

763 lines
20 KiB
C++
Raw 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-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 ***********************/