/*++ Copyright (c) 1995-1997 Microsoft Corporation Module Name: dbgcc.cxx Abstract: This module contains the default ntsd debugger extensions for IIS - W3SVC Client Connection Author: Murali R. Krishnan (MuraliK) 22-Aug-1997 Revision History: --*/ #include "inetdbgp.h" # undef DBG_ASSERT /************************************************************ * Debugger Utility Functions ************************************************************/ NTSD_EXTENSION_APIS ExtensionApis; HANDLE ExtensionCurrentProcess; /************************************************************ * CLIENT_CONN related functions ************************************************************/ char * g_rgchCCState[] = { "CcsStartup", "CcsGettingClientReq", "CcsGatheringGatewayData", "CcsProcessingClientReq", "CcsDisconnecting", "CcsShutdown", "CcsMaxItems" }; #define LookupCCState( ItemState ) \ ((((ItemState) >= CCS_STARTUP) && ((ItemState) <= CCS_SHUTDOWN)) ?\ g_rgchCCState[ (ItemState)] : "") VOID PrintClientConn( CLIENT_CONN * pccOriginal, CLIENT_CONN * pcc, CHAR Verbosity); VOID PrintClientConnThunk( PVOID pccDebuggee, PVOID pccDebugger, CHAR verbosity, DWORD iCount); DECLARE_API( cc ) /*++ 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; DEFINE_CPP_VAR( CLIENT_CONN, cc); CLIENT_CONN * pcc; INIT_API(); while (*lpArgumentString == ' ') lpArgumentString++; if ( !*lpArgumentString ) { PrintUsage( "cc" ); return; } if ( *lpArgumentString == '-' ) { lpArgumentString++; if ( *lpArgumentString == 'h' ) { PrintUsage( "cc" ); return; } if ( *lpArgumentString == 'l' ) { DumpClientConnList( lpArgumentString[1], PrintClientConnThunk ); return; } } // while // // Treat the argument as the address of an AtqContext // pcc = (CLIENT_CONN * ) GetExpression( lpArgumentString ); if ( !pcc ) { dprintf( "inetdbg.cc: Unable to evaluate \"%s\"\n", lpArgumentString ); return; } move( cc, pcc ); PrintClientConn( pcc, GET_CPP_VAR_PTR( CLIENT_CONN, cc), '2' ); return; } // DECLARE_API( cc ) VOID PrintClientConn( CLIENT_CONN * pccOriginal, CLIENT_CONN * pcc, CHAR Verbosity ) /*++ Description: This function takes the client connection object and prints out the details for the same in the debugger. The granularity of the deatils are controlled by the verbosity flag Arguments: pccOriginal - pointer to the location where the original CLIENT_CONN object is located. Note: pccOriginal points to object inside debuggee process pcc - pointer to the Client Connection object that is a copy of the contents located at [pccOriginal] Note: pcc points to object inside the debugger process Verbostiy - level of details requested. Returns: None --*/ { if ( Verbosity >= '0') { // // print Brief information about the client connection // dprintf( "ClIENT_CONN:%08p Refs = %8d State = %15s\n" "\t HTTP_REQUEST = %08p AtqContext = %08p\n" , pccOriginal, pcc->_cRef, LookupCCState( pcc->_ccState), pcc->_phttpReq, pcc->_AtqContext ); } if ( Verbosity >= '1' ) { // // Print all details for the Client Connection object // dprintf( "\tSignature = %08x fSecurePort=%d fValid=%d; \n" "\tSocket = %08p Port: Local=%hd Remote=%hd\n" "\tListEntry.Flink = %08p ListEntry.Blink = %08p\n" "\tInitialBuffer = %08p InitialBytesRecvd = %d\n" "\tBuffLE.Flink = %08p BuffLE.Blink = %08p\n" "\tAddress Local = %10s Address Remote = %10s\n" "\tW3Instance = %08p Reflog = %08p\n" , pcc->_Signature, pcc->_fSecurePort, pcc->_fIsValid, pcc->_sClient, pcc->_sPort, pcc->_sRemotePort, pcc->ListEntry.Flink, pcc->ListEntry.Blink, pcc->_pvInitial, pcc->_cbInitial, pcc->_BuffListEntry.Flink, pcc->_BuffListEntry.Blink, pcc->_achLocalAddr, pcc->_achRemoteAddr, pcc->m_pInstance, #if CC_REF_TRACKING // Enabled in free builds for build 585 and later pcc->_pDbgCCRefTraceLog #else (PVOID)(-1) #endif ); } if ( Verbosity >= '2' ) { // // Print the initial request received for the client connection // dstring( " Initial Request", pcc->_pvInitial, pcc->_cbInitial); } return; } // PrintClientConn() VOID PrintClientConnThunk( PVOID pccDebuggee, PVOID pccDebugger, CHAR verbosity, DWORD iThunk) /*++ Description: This is the callback function for printing the CLIENT_CONN object. Arguments: pccDebuggee - pointer to client conn object in the debuggee process pccDebugger - pointer to client conn object in the debugger process verbosity - character indicating the verbosity level desired Returns: None --*/ { if ( ((CLIENT_CONN * )pccDebugger)->_Signature != CLIENT_CONN_SIGNATURE) { dprintf( "ClientConn(%08lp) signature %08lx doesn't" " match expected %08lx\n", pccDebuggee, ((CLIENT_CONN * )pccDebugger)->_Signature, CLIENT_CONN_SIGNATURE ); return; } PrintClientConn( (CLIENT_CONN *) pccDebuggee, (CLIENT_CONN *) pccDebugger, verbosity); } // PrintClientConnThunk() VOID DumpClientConnList( CHAR Verbosity, PFN_LIST_ENUMERATOR pfnCC ) { LIST_ENTRY * pccListHead; pccListHead = (LIST_ENTRY *) GetExpression( "&w3svc!listConnections"); if ( NULL == pccListHead) { dprintf( " Unable to get Client Connections list \n"); return; } EnumLinkedList( pccListHead, pfnCC, Verbosity, sizeof( CLIENT_CONN), FIELD_OFFSET( CLIENT_CONN, ListEntry) ); return; } // DumpClientConnList() /************************************************************ * HTTP_REQUEST related functions ************************************************************/ char * g_rgchHREQState[] = { "HtrReadingClientRequest", "HtrReadingGatewayData", "HtrParse", "HtrDoVerb", "HtrGatewayAsyncIO", "HtrSendFile", "HtrProxySendingRequest", "HtrCgi", "HtrRange", "HtrRestartRequest", "HtrWritingFile", "HtrCertRenegotiate", "HtrMaxItems" }; #define LookupHREQState( ItemState ) \ ((((ItemState) >= HTR_READING_CLIENT_REQUEST) && \ ((ItemState) <= HTR_DONE)) ?\ g_rgchHREQState[ (ItemState)] : "") const char * g_rgchHreqPutState[] = { "PSTATE_START", "PSTATE_READING", "PSTATE_DISCARD_READING", "PSTATE_DISCARD_CHUNK" }; # define LookupHreqPutState( ItemState) \ ((((ItemState) >= PSTATE_START) && \ ((ItemState) <= PSTATE_DISCARD_CHUNK)) ?\ g_rgchHreqPutState[ (ItemState)] : "") VOID PrintHttpRequest( HTTP_REQUEST * phreqOriginal, HTTP_REQUEST * phreq, CHAR Verbosity); VOID PrintHttpRequestThunk( PVOID pccDebuggee, PVOID pccDebugger, CHAR verbosity, DWORD iCount); DECLARE_API( hreq ) /*++ 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; DEFINE_CPP_VAR( HTTP_REQUEST, hreq); HTTP_REQUEST * phreq; INIT_API(); while (*lpArgumentString == ' ') lpArgumentString++; if ( !*lpArgumentString ) { PrintUsage( "hreq" ); return; } if ( *lpArgumentString == '-' ) { lpArgumentString++; if ( *lpArgumentString == 'h' ) { PrintUsage( "hreq" ); return; } if ( *lpArgumentString == 'l' ) { DumpClientConnList( lpArgumentString[1], PrintHttpRequestThunk); return; } } // if // // Treat the argument as the address of an AtqContext // phreq = (HTTP_REQUEST * ) GetExpression( lpArgumentString ); if ( !phreq ) { dprintf( "inetdbg.hreq: Unable to evaluate \"%s\"\n", lpArgumentString ); return; } move( hreq, phreq ); PrintHttpRequest( phreq, GET_CPP_VAR_PTR( HTTP_REQUEST, hreq), '2'); return; } // DECLARE_API( hreq ) VOID PrintHttpRequestThunk( PVOID pccDebuggee, PVOID pccDebugger, CHAR verbosity, DWORD iCount) /*++ Description: This is the callback function for printing the HTTP_REQUEST object. Arguments: pccDebuggee - pointer to client conn object in the debuggee process pccDebugger - pointer to client conn object in the debugger process verbosity - character indicating the verbosity level desired Returns: None --*/ { DEFINE_CPP_VAR( HTTP_REQUEST, hreq); HTTP_REQUEST * phreq; CLIENT_CONN * pcc = (CLIENT_CONN *) pccDebugger; if ( pcc->_Signature != CLIENT_CONN_SIGNATURE) { dprintf( "ClientConn(%08lp) signature %08lx doesn't" " match expected %08lx\n", pccDebuggee, pcc->_Signature, CLIENT_CONN_SIGNATURE ); return; } // // Obtain the pointer for HTTP_REQUEST object from CLIENT_CONN object // and make local copy of the HTTP_REQUEST object inside debugger process // phreq = (HTTP_REQUEST *) pcc->_phttpReq; move( hreq, phreq); // Print out the http request object PrintHttpRequest( phreq, GET_CPP_VAR_PTR( HTTP_REQUEST, hreq), verbosity); } // PrintHttpRequestThunk() VOID PrintHttpRequest( HTTP_REQUEST * phreqOriginal, HTTP_REQUEST * phreq, CHAR Verbosity ) /*++ Description: This function takes the HTTP_REQUEST object and prints out the details for the same in the debugger. The granularity of the deatils are controlled by the verbosity flag Arguments: phreqOriginal - pointer to the location where the original HTTP_REQUEST object is located. Note: phreqOriginal points to object inside debuggee process phreq - pointer to the HTTP_REQUEST object that is a copy of the contents located at [phreqOriginal] Note: phreq points to object inside the debugger process Verbostiy - level of details requested. Returns: None --*/ { if ( Verbosity >= '0') { // // print Brief information about the client connection // dprintf( "HTTP_REQUEST:%08p State = %15s\n" "\t CLIENT_CONN = %08p WamReq = %08p\n" , phreqOriginal, LookupHREQState( phreq->_htrState), phreq->_pClientConn, phreq->_pWamRequest ); } if ( Verbosity >= '1' ) { // // Print all details for the Client Connection object // dprintf( "\t _fKeepConn = %8s _fLoggedOn = %8s\n" "\t _fChunked = %8s Client Ver = %d.%d\n" "\t _tcpauth = %08p _Filter = %p \n" "\t _cbClientRequest = %8d _cbOldData = %8d\n" "\t _cbEntityBody = %8d _cbTotalEntBody = %8d\n" "\t _cbChunkHeader = %8d _cbChunkBytesRead=%8d\n" "\t _cbExtraData = %8d _pchExtraData = %08p\n" "\t _pMetaData = %08p _pURIInfo = %08p\n" "\t _pGetFile = %08p _Exec = %08p\n" "\t _pW3Stats = %08p\n" "\t _dwLogHttpResponse= %8d _dwLogWinError = %8d\n" , BoolValue(phreq->_fKeepConn), BoolValue(phreq->_fLoggedOn), BoolValue(phreq->_fChunked), (int) phreq->_VersionMajor, (int) phreq->_VersionMinor, (BYTE *) phreqOriginal + ((BYTE *) &phreq->_tcpauth - (BYTE *) phreq), (BYTE *) phreqOriginal + ((BYTE *) &phreq->_Filter - (BYTE *) phreq), phreq->_cbClientRequest, phreq->_cbOldData, phreq->_cbEntityBody, phreq->_cbTotalEntityBody, phreq->_cbChunkHeader, phreq->_cbChunkBytesRead, phreq->_cbExtraData, phreq->_pchExtraData, phreq->_pMetaData, phreq->_pURIInfo, phreq->_pGetFile, (BYTE *) phreqOriginal + ((BYTE *) &phreq->_Exec - (BYTE *) phreq), phreq->_pW3Stats, phreq->_dwLogHttpResponse, phreq->_dwLogWinError ); } if ( Verbosity >= '2' ) { // // Print state specific data // dprintf( "\t _putstate = %8s _pFileNameLock = %8p\n" , LookupHreqPutState( phreq->_putstate) , phreq->_pFileNameLock ); } return; } // PrintHttpRequest() VOID PrintW3Statistics( W3_SERVER_STATISTICS * pw3statsDebuggee ); /*++ NAME: wstats SYNOPSIS: Displays the w3svc statistics. By default print the global w3svc statistics. If given an argument treat that argument as a pointer to the W3_SERVER_STATISITCS structure and print it out --*/ DECLARE_API( wstats ) { W3_SERVER_STATISTICS * pw3stats; W3_IIS_SERVICE * pw3s; INIT_API(); while (*lpArgumentString == ' ') lpArgumentString++; // // Capture the statistics. // if ( !*lpArgumentString ) { dprintf( "OffsetOfGlobalStats from W3_IIS_SERVICE = %d (0x%x)\n", FIELD_OFFSET( W3_IIS_SERVICE, m_GlobalStats), FIELD_OFFSET( W3_IIS_SERVICE, m_GlobalStats) ); dprintf( "OffsetOfStats from W3_SERVER_INSTANCE = %d (0x%x)\n", FIELD_OFFSET( W3_SERVER_INSTANCE, m_pW3Stats), FIELD_OFFSET( W3_SERVER_INSTANCE, m_pW3Stats) ); // // In IIS 4.0, the global statistics structure is part of // the W3_IIS_SERVICE structure - obtain the address indirectly. // W3_IIS_SERVICE ** ppw3s; ppw3s = (W3_IIS_SERVICE **) GetExpression( "w3svc!g_pInetSvc"); if ( !ppw3s) { dprintf( "Unable to get w3svc!g_pInetSvc to fetch global stats\n"); return; } // // From the pointer to pointer to W3_IIS_SERVICE, // obtain the pointer to the W3_IIS_SERVICE // moveBlock( pw3s, ppw3s, sizeof(W3_IIS_SERVICE * )); pw3stats = &pw3s->m_GlobalStats; } else { // // extract the address from the argument given // pw3stats = (W3_SERVER_STATISTICS * ) GetExpression( lpArgumentString ); } PrintW3Statistics( pw3stats); return; } // stats # define P2DWORDS( a, b) \ Print2Dwords( #a, \ pw3statsDebugger->m_W3Stats. ## a, \ #b, \ pw3statsDebugger->m_W3Stats. ## b \ ) VOID PrintW3Statistics( W3_SERVER_STATISTICS * pw3statsDebuggee ) /*++ Description: This function takes the W3_SERVER_STATISTICS object and prints out the details for the same in the debugger. Arguments: pw3statsDebuggee - pointer to the location where the original structure is found inside the debuggee process. pw3statsDebugger - pointer to the copy of the data in the debugger process. Returns: None --*/ { DEFINE_CPP_VAR( W3_SERVER_STATISTICS, w3stats); W3_SERVER_STATISTICS * pw3statsDebugger = (W3_SERVER_STATISTICS *) &w3stats; CHAR szLargeInt[64]; // // copy the statistics data into the local buffer inside the debugger // process so we can play with it // move( w3stats, pw3statsDebuggee); dprintf( " %30s = 0x%08p\n", "W3_SERVER_STATISTICS", pw3statsDebuggee); PrintLargeInteger( "TotalBytesSent", &pw3statsDebugger->m_W3Stats.TotalBytesSent); PrintLargeInteger( "TotalBytesReceived", &pw3statsDebugger->m_W3Stats.TotalBytesReceived); P2DWORDS( TotalFilesSent, TotalFilesReceived); dprintf("\n"); P2DWORDS( CurrentAnonymousUsers, CurrentNonAnonymousUsers); P2DWORDS( TotalAnonymousUsers, TotalNonAnonymousUsers); P2DWORDS( MaxAnonymousUsers, MaxNonAnonymousUsers); P2DWORDS( CurrentConnections, MaxConnections); P2DWORDS( ConnectionAttempts, LogonAttempts); dprintf( "\n"); P2DWORDS( TotalGets, TotalPosts); P2DWORDS( TotalHeads, TotalPuts); P2DWORDS( TotalDeletes, TotalTraces); P2DWORDS( TotalOthers, TotalNotFoundErrors); P2DWORDS( TotalCGIRequests, TotalBGIRequests); dprintf( "\n"); P2DWORDS( CurrentCGIRequests, MaxCGIRequests); P2DWORDS( CurrentBGIRequests, MaxBGIRequests); return; } // PrintW3Statistics()