mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
613 lines
16 KiB
613 lines
16 KiB
/*++
|
|
|
|
Copyright (c) 1990 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
inetdbg.c
|
|
|
|
Abstract:
|
|
|
|
This function contains the default ntsd debugger extensions
|
|
|
|
Author:
|
|
|
|
Mark Lucovsky (markl) 09-Apr-1991
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
//
|
|
// Get around defn. in atqtypes.hxx
|
|
//
|
|
|
|
#define DBG_ASSERT( x )
|
|
|
|
extern "C" {
|
|
#include "inetdbgp.h"
|
|
|
|
void _cdecl main( void )
|
|
{
|
|
;
|
|
}
|
|
|
|
}
|
|
#include <atq.h>
|
|
#include <atqtypes.hxx>
|
|
|
|
NTSD_EXTENSION_APIS ExtensionApis;
|
|
HANDLE ExtensionCurrentProcess;
|
|
|
|
//
|
|
// Text names of ATQ_SOCK_STATE values
|
|
//
|
|
|
|
char * AtqSockState[] = {
|
|
"ATQ_SOCK_CLOSED",
|
|
"ATQ_SOCK_UNCONNECTED",
|
|
"ATQ_SOCK_LISTENING",
|
|
"ATQ_SOCK_CONNECTED"
|
|
};
|
|
|
|
char * AtqSyncTO[] = {
|
|
"Place holder as this enum starts from 1",
|
|
"AtqProcessingTimeout",
|
|
"AtqProcessingIo",
|
|
"AtqPendingIo",
|
|
"AtqIdle"
|
|
};
|
|
|
|
#define LookupSockState( SockState ) \
|
|
((SockState) <= ATQ_SOCK_CONNECTED ? AtqSockState[ (SockState) ] : \
|
|
"<Invalid>")
|
|
|
|
VOID
|
|
PrintUsage(
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
DumpGlobals(
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
DumpClientList(
|
|
CHAR Level,
|
|
CHAR Verbosity
|
|
);
|
|
|
|
void
|
|
DumpList(
|
|
LIST_ENTRY * pAtqClientHead,
|
|
CHAR Level,
|
|
DWORD * pcContext,
|
|
BYTE * pvStart,
|
|
BYTE * pvEnd
|
|
);
|
|
|
|
VOID
|
|
PrintAtqContext(
|
|
ATQ_CONTEXT * AtqContext
|
|
);
|
|
|
|
void
|
|
PrintListenInfo(
|
|
ACCEPTEX_LISTEN_INFO * pLI
|
|
);
|
|
|
|
VOID
|
|
DumpListenInfo(
|
|
CHAR Level
|
|
);
|
|
|
|
#define DumpDword( symbol ) \
|
|
{ \
|
|
DWORD dw = GetExpression( "&" symbol ); \
|
|
DWORD dwValue = 0; \
|
|
\
|
|
if ( dw ) \
|
|
{ \
|
|
if ( ReadMemory( (LPVOID) dw, \
|
|
&dwValue, \
|
|
sizeof(dwValue), \
|
|
NULL )) \
|
|
{ \
|
|
dprintf( "\t" symbol " = %8d (0x%8lx)\n", \
|
|
dwValue, \
|
|
dwValue ); \
|
|
} \
|
|
} \
|
|
}
|
|
|
|
|
|
|
|
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();
|
|
return;
|
|
}
|
|
|
|
if ( *lpArgumentString == '-' )
|
|
{
|
|
lpArgumentString++;
|
|
|
|
if ( *lpArgumentString == 'h' )
|
|
{
|
|
PrintUsage();
|
|
return;
|
|
}
|
|
|
|
if ( *lpArgumentString == 'g' )
|
|
{
|
|
DumpGlobals();
|
|
return;
|
|
}
|
|
|
|
if ( *lpArgumentString == 'c' )
|
|
{
|
|
DumpClientList( lpArgumentString[1], lpArgumentString[2] );
|
|
return;
|
|
}
|
|
|
|
if ( *lpArgumentString == 'l' )
|
|
{
|
|
DumpListenInfo( lpArgumentString[1] );
|
|
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( help )
|
|
{
|
|
INIT_API();
|
|
|
|
PrintUsage();
|
|
}
|
|
|
|
VOID
|
|
PrintUsage(
|
|
VOID
|
|
)
|
|
{
|
|
dprintf("\nInternet Information Server debugging extension, Version 2.0\n");
|
|
|
|
dprintf("!atq <addr> - Dump ATQ_CONTEXT at <addr>\n");
|
|
dprintf("!atq -g - Dump atq globals\n");
|
|
dprintf("!atq -c[0|1|2|3][0|1] - Dump atq client list at verbosity [n]\n");
|
|
dprintf(" 0x - Traverse list, print number on list, confirm signatures\n");
|
|
dprintf(" 1x - Active Only\n");
|
|
dprintf(" 2x - All Atq contexts\n");
|
|
dprintf(" x0 - Print one line summary of Atq Context\n");
|
|
dprintf(" x1 - Print full Atq context\n");
|
|
|
|
dprintf("!atq -l - Dump atq ListenInfo list\n");
|
|
|
|
dprintf("Bytes from Flink to beginning is 0x%lx bytes\n\n",
|
|
~(DWORD)(CONTAINING_RECORD( 0, ATQ_CONTEXT, ListEntry )));
|
|
}
|
|
|
|
VOID
|
|
DumpGlobals(
|
|
VOID
|
|
)
|
|
{
|
|
//
|
|
// Dump Atq Globals
|
|
//
|
|
|
|
dprintf("Atq Globals:\n");
|
|
|
|
DumpDword( "g_cThreads " );
|
|
DumpDword( "g_cAvailableThreads " );
|
|
DumpDword( "g_cMaxThreads " );
|
|
|
|
dprintf("\n");
|
|
DumpDword( "g_fUseAcceptEx " );
|
|
DumpDword( "g_fUseTransmitFile " );
|
|
DumpDword( "g_cbXmitBufferSize " );
|
|
DumpDword( "g_cbMinKbSec " );
|
|
DumpDword( "g_cCPU " );
|
|
DumpDword( "g_fShutdown " );
|
|
}
|
|
|
|
VOID
|
|
DumpClientList(
|
|
CHAR Level,
|
|
CHAR Verbosity
|
|
)
|
|
{
|
|
LIST_ENTRY AtqClientHead;
|
|
LIST_ENTRY * pAtqClientHead;
|
|
ATQ_CONTEXT * pAtqContext;
|
|
ATQ_CONTEXT AtqContext;
|
|
CHAR Symbol[256];
|
|
DWORD cContext = 0;
|
|
ATQ_CONTEXT_LISTHEAD * pAtqActiveContextList;
|
|
ATQ_CONTEXT_LISTHEAD AtqActiveContextList[ATQ_NUM_CONTEXT_LIST];
|
|
DWORD i;
|
|
|
|
pAtqActiveContextList = (ATQ_CONTEXT_LISTHEAD *) GetExpression( "&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" );
|
|
|
|
DumpList( &(AtqActiveContextList[i].ActiveListHead),
|
|
Verbosity,
|
|
&cContext,
|
|
(BYTE *) pAtqActiveContextList,
|
|
(BYTE *) &pAtqActiveContextList[ATQ_NUM_CONTEXT_LIST] );
|
|
|
|
if ( Level > '1' )
|
|
{
|
|
dprintf("================================================\n");
|
|
dprintf("Pending AcceptEx List\n");
|
|
|
|
DumpList( &(AtqActiveContextList[i].PendingAcceptExListHead),
|
|
Verbosity,
|
|
&cContext,
|
|
(BYTE *) pAtqActiveContextList,
|
|
(BYTE *) &pAtqActiveContextList[ATQ_NUM_CONTEXT_LIST] );
|
|
}
|
|
|
|
if ( CheckControlC() )
|
|
{
|
|
dprintf( "\n^C\n" );
|
|
return;
|
|
}
|
|
|
|
|
|
}
|
|
|
|
dprintf( "%d Atq contexts traversed\n",
|
|
cContext );
|
|
}
|
|
|
|
void
|
|
DumpList(
|
|
LIST_ENTRY * pAtqClientHead,
|
|
CHAR Verbosity,
|
|
DWORD * pcContext,
|
|
BYTE * pvStart,
|
|
BYTE * pvEnd
|
|
)
|
|
{
|
|
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,
|
|
ListEntry );
|
|
|
|
move( AtqContext, pAtqContext );
|
|
|
|
if ( AtqContext.Signature != ATQ_SIGNATURE )
|
|
{
|
|
dprintf( "Atq signature %08lx doesn't match expected %08lx at %08lx\n",
|
|
AtqContext.Signature,
|
|
ATQ_SIGNATURE,
|
|
pAtqContext );
|
|
|
|
return;
|
|
}
|
|
|
|
(*pcContext)++;
|
|
|
|
if ( Verbosity >= '1' )
|
|
{
|
|
//
|
|
// Print all
|
|
//
|
|
|
|
dprintf( "\nAtqContext at %08lx\n",
|
|
pAtqContext );
|
|
|
|
PrintAtqContext( &AtqContext );
|
|
|
|
}
|
|
else if ( Verbosity >= '0' )
|
|
{
|
|
//
|
|
// Print all with one line summary info
|
|
//
|
|
|
|
dprintf( "hAsyncIO = %4lx, Flink = %08lx, Blink = %08lx, State = %s\n",
|
|
AtqContext.hAsyncIO,
|
|
AtqContext.ListEntry.Blink,
|
|
AtqContext.ListEntry.Flink,
|
|
LookupSockState( AtqContext.SockState ) );
|
|
}
|
|
|
|
move( pEntry, &pEntry->Flink );
|
|
}
|
|
}
|
|
|
|
VOID
|
|
PrintAtqContext(
|
|
ATQ_CONTEXT * AtqContext
|
|
)
|
|
{
|
|
dprintf( "\n" );
|
|
dprintf( "\thAsyncIO = %08lx Signature = %08lx\n"
|
|
"\tOverlapped.Internal = %08lx Overlapped.Offset= %08lx\n"
|
|
"\tListEntry.Flink = %08lx ListEntry.Blink = %08lx\n"
|
|
"\tClientContext = %08lx pfnConnComp = %08lx (%s)\n"
|
|
"\tpfnCompletion = %08lx (%s)\n"
|
|
"\tpListenInfo = %08lx\n"
|
|
"\tfAcceptExContext = %s\n"
|
|
"\tContextList = %08lx\n"
|
|
"\tlSyncTimeout = %s\n"
|
|
"\tfInTimeout = %s\n"
|
|
|
|
|
|
"\tTimeOut = %08lx NextTimeout = %08lx\n"
|
|
"\tBytesSent = %d (0x%08lx)\n"
|
|
|
|
"\tpvBuff = %08lx cbBuff = %08lx\n"
|
|
"\tfConnectionIndicated= %08lx fBlocked = %8lx\n"
|
|
|
|
"\tSockState = %8lx (%s)\n",
|
|
AtqContext->hAsyncIO,
|
|
AtqContext->Signature,
|
|
AtqContext->Overlapped.Internal,
|
|
AtqContext->Overlapped.Offset,
|
|
AtqContext->ListEntry.Flink,
|
|
AtqContext->ListEntry.Blink,
|
|
AtqContext->ClientContext,
|
|
AtqContext->pfnConnComp,
|
|
"", //"pfnConnComp",
|
|
AtqContext->pfnCompletion,
|
|
"", //"pfnCompletion",
|
|
AtqContext->pListenInfo,
|
|
(AtqContext->fAcceptExContext ? "TRUE" : "FALSE"),
|
|
AtqContext->ContextList,
|
|
AtqSyncTO[AtqContext->lSyncTimeout],
|
|
(AtqContext->fInTimeout ? "TRUE" : "FALSE"),
|
|
AtqContext->TimeOut,
|
|
AtqContext->NextTimeout,
|
|
AtqContext->BytesSent,
|
|
AtqContext->BytesSent,
|
|
AtqContext->pvBuff,
|
|
AtqContext->cbBuff,
|
|
AtqContext->fConnectionIndicated,
|
|
AtqContext->fBlocked,
|
|
AtqContext->SockState,
|
|
LookupSockState( AtqContext->SockState )
|
|
);
|
|
|
|
if ( AtqContext->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];
|
|
|
|
if ( ReadMemory( (LPVOID) ((BYTE *) AtqContext->pvBuff +
|
|
AtqContext->cbBuff -
|
|
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] );
|
|
}
|
|
}
|
|
}
|
|
|
|
VOID
|
|
DumpListenInfo(
|
|
CHAR Verbosity
|
|
)
|
|
{
|
|
LIST_ENTRY AtqListenInfo;
|
|
LIST_ENTRY * pAtqListenInfo;
|
|
LIST_ENTRY * pEntry;
|
|
ATQ_CONTEXT * pAtqContext;
|
|
ATQ_CONTEXT AtqContext;
|
|
CHAR Symbol[256];
|
|
DWORD cContext = 0;
|
|
DWORD i;
|
|
ACCEPTEX_LISTEN_INFO * pListenInfo;
|
|
ACCEPTEX_LISTEN_INFO ListenInfo;
|
|
|
|
pAtqListenInfo = (LIST_ENTRY *) GetExpression( "&AtqListenInfoList" );
|
|
|
|
if ( !pAtqListenInfo )
|
|
{
|
|
dprintf("Unable to get AtqListenInfoList symbol\n" );
|
|
return;
|
|
}
|
|
|
|
move( AtqListenInfo, pAtqListenInfo );
|
|
|
|
for ( pEntry = AtqListenInfo.Flink;
|
|
pEntry != pAtqListenInfo;
|
|
)
|
|
{
|
|
if ( CheckControlC() )
|
|
{
|
|
return;
|
|
}
|
|
|
|
pListenInfo = CONTAINING_RECORD( pEntry,
|
|
ACCEPTEX_LISTEN_INFO,
|
|
ListEntry );
|
|
|
|
move( ListenInfo, pListenInfo );
|
|
|
|
if ( ListenInfo.Signature != ACCEPTEX_LISTEN_SIGN )
|
|
{
|
|
dprintf( "Listen signature %08lx doesn't match expected %08lx at %08lx\n",
|
|
ListenInfo.Signature,
|
|
ACCEPTEX_LISTEN_SIGN,
|
|
pListenInfo );
|
|
|
|
return;
|
|
}
|
|
|
|
if ( Verbosity >= '1' )
|
|
{
|
|
//
|
|
// Print all
|
|
//
|
|
|
|
dprintf( "\nListenInfo at %08lx\n",
|
|
pListenInfo );
|
|
|
|
PrintListenInfo( &ListenInfo );
|
|
|
|
}
|
|
else if ( Verbosity >= '0' )
|
|
{
|
|
//
|
|
// Print all with one line summary info
|
|
//
|
|
|
|
dprintf( "sListenSocket = %4lx, cRef = %d, cSocketsAvail = %d\n",
|
|
ListenInfo.sListenSocket,
|
|
ListenInfo.cRef,
|
|
ListenInfo.cSocketsAvail );
|
|
}
|
|
|
|
move( pEntry, &pEntry->Flink );
|
|
}
|
|
}
|
|
|
|
void
|
|
PrintListenInfo(
|
|
ACCEPTEX_LISTEN_INFO * pLI
|
|
)
|
|
{
|
|
|
|
dprintf( "\tcRef = %8d\n", pLI->cRef );
|
|
dprintf( "\tfAccepting = %s\n", (pLI->fAccepting ? " TRUE" : " FALSE"));
|
|
dprintf( "\tsListenSocket = %8lx\n", pLI->sListenSocket );
|
|
dprintf( "\tcSocketsAvail = %8d\n", pLI->cSocketsAvail );
|
|
dprintf( "\tcbInitialRecvSize = %8d\n", pLI->cbInitialRecvSize );
|
|
dprintf( "\tcsecTimeout = %8d\n", pLI->csecTimeout );
|
|
dprintf( "\tcNewIncrement = %8d\n", pLI->cNewIncrement );
|
|
dprintf( "\tcAvailDuringTimeOut = %8d\n", pLI->cAvailDuringTimeOut );
|
|
dprintf( "\tpfnOnConnect = %08lx\n", pLI->pfnOnConnect );
|
|
dprintf( "\tpfnIOCompletion = %08lx\n", pLI->pfnIOCompletion );
|
|
dprintf( "\tListEntry.Flink = %08lx\n", pLI->ListEntry.Flink );
|
|
dprintf( "\tListEntry.Blink = %08lx\n", pLI->ListEntry.Blink );
|
|
|
|
}
|