/*++ 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: --*/ #ifdef DBG #undef DBG #endif #define dllexp #define CALL_STACK_BUF_SIZE 1024 // // To obtain the private & protected members of C++ class, // let me fake the "private" keyword // # define private public # define protected public #define INCL_INETSRV_INCS #include #include "smtpcli.h" #include #include "nntpdbgp.h" extern "C" { #if 0 void __cdecl main( void ) { ; } #endif } // // Globals that we have to have because we included others' headers // CShareLockNH CNewsGroupCore::m_rglock[GROUP_LOCK_ARRAY_SIZE]; //DECLARE_DEBUG_PRINTS_OBJECT( ); NTSD_EXTENSION_APIS ExtensionApis; HANDLE ExtensionCurrentProcess; // globals char g_szBuffer [1024]; // temp buffer for misc stuff VOID PrintUsage( VOID ); VOID PrintSystemTime( FILETIME* pftTime ); VOID PrintString( LPSTR lp1, LPSTR lp2 ); VOID DbgPrintInstance( NNTP_SERVER_INSTANCE* pInstance ); VOID DbgPrintNewstree( CNewsTree* ptree, DWORD nGroups ); CNewsGroup* DbgPrintNewsgroup( CNewsGroup * pSrcGroup ); CNNTPVRoot* DbgPrintVRoot( CNNTPVRoot *pDestGroup ); VOID DbgPrintVRootList( CNNTPVRoot* pFirstVRoot, DWORD nVRoots ); VOID DbgPrintDebugVRootList( CNNTPVRoot* pFirstVRoot, DWORD nVRoots ); void DbgPrintVRootTable( CNNTPVRootTable * pVRTable ); VOID DbgDumpPool( CSmtpClientPool* pSCPool ); VOID DbgDumpFeedBlock( PFEED_BLOCK feedBlock ); VOID DbgDumpFeedList( CFeedList* pSrcFeedList, CFeedList* pDstFeedList ); VOID DbgDumpCPool(CPool* pCPool, DWORD dwSignature, LPCSTR symbol); VOID SkipArgument( LPSTR* ppArg ) { // skip the arg and the spaces after while( *(*ppArg) != ' ' ) (*ppArg)++; while( *(*ppArg) == ' ' ) (*ppArg)++; } // // Here and elsewhere we use "nntpsvc" prefix in GetExpression() calls. // #define DEBUG_PREFIX "&nntpsvc!" #define DumpDword( symbol ) \ { \ DWORD dw = GetExpression( DEBUG_PREFIX symbol ); \ DWORD dwValue = 0; \ \ if ( dw ) \ { \ if ( ReadMemory( (LPVOID) dw, \ &dwValue, \ sizeof(dwValue), \ NULL )) \ { \ dprintf( "\t" symbol " = %8d (0x%8lx)\n", \ dwValue, \ dwValue ); \ } \ } \ } #define DumpCPool( symbol, signature ) \ { \ DbgDumpCPool((CPool*)GetExpression(DEBUG_PREFIX symbol), signature, symbol ); \ } // // util functions // VOID CopyUnicodeStringIntoAscii( IN LPSTR AsciiString, IN LPWSTR UnicodeString ) { while ( (*AsciiString++ = (CHAR)*UnicodeString++) != '\0'); } // CopyUnicodeStringIntoAscii DECLARE_API( help ) { INIT_API(); PrintUsage(); } DECLARE_API( cpool ) { CPool* pCPool; INIT_API(); while (*lpArgumentString == ' ') lpArgumentString++; if ( !*lpArgumentString ) { PrintUsage(); return; } // // Get the address of the instance // pCPool = (CPool*)GetExpression( lpArgumentString ); if ( !pCPool ) { dprintf( "nntpdbg: Unable to evaluate \"%s\"\n", lpArgumentString ); return; } DbgDumpCPool(pCPool, 0, NULL); } DECLARE_API( cpools ) { INIT_API(); // // Dump Nntpsvc cpools // dprintf("Nntpsvc Cpools:\n"); DumpCPool("CArticle__gArticlePool",ARTICLE_SIGNATURE); DumpCPool("CCIOAllocator__IOPool",CIO_SIGNATURE) ; DumpCPool("CFeed__gFeedPool",FEED_SIGNATURE) ; DumpCPool("CChannel__gChannelPool",CHANNEL_SIGNATURE) ; DumpCPool("CSessionSocket__gSocketAllocator",SESSION_SOCKET_SIGNATURE) ; DumpCPool("CSessionState__gStatePool",SESSION_STATE_SIGNATURE) ; DumpCPool("CXoverIndex__gCacheAllocator",1) ; DumpCPool("CXoverIndex__gXoverIndexAllocator",1) ; } DECLARE_API( instance ) /*++ 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. --*/ { NNTP_SERVER_INSTANCE *pSrcInst, *pDstInst; DWORD cbInst = sizeof(NNTP_SERVER_INSTANCE); INIT_API(); while (*lpArgumentString == ' ') lpArgumentString++; if ( !*lpArgumentString ) { PrintUsage(); return; } // // Get the address of the instance // pSrcInst = (NNTP_SERVER_INSTANCE*)GetExpression( lpArgumentString ); if ( !pSrcInst ) { dprintf( "nntpdbg: Unable to evaluate \"%s\"\n", lpArgumentString ); return; } dprintf("Instance object is 0x%p\n", pSrcInst); // // Allocate memory in our address space so we can read data from the debuggee's address space // pDstInst = (NNTP_SERVER_INSTANCE*) DbgAlloc( cbInst ); if( !pDstInst ) { dprintf( "nntpdbg: Unable to allocate memory \n"); return; } if( !ReadMemory( pSrcInst, pDstInst, cbInst, NULL ) ) { dprintf("Could not get data at 0x%x\n", pSrcInst); DbgFree( pDstInst ); return; } // // Dump the the server instance // DbgPrintInstance( pDstInst ); DbgFree( pDstInst ); } DECLARE_API( newstree ) /*++ 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. --*/ { CNewsTree *pSrcTree, *pDstTree; DWORD cbTree = sizeof(CNewsTree); DWORD nGroups = 0; INIT_API(); while (*lpArgumentString == ' ') lpArgumentString++; if ( !*lpArgumentString ) { PrintUsage(); return; } // // Get the address of the global newstree pointer // pSrcTree = (CNewsTree*)GetExpression( lpArgumentString ); if ( !pSrcTree ) { dprintf( "nntpdbg: Unable to evaluate \"%s\"\n", lpArgumentString ); return; } // same as doing pSrcTree = *ppSrcTree !! dprintf("Newstree object is 0x%p\n", pSrcTree); SkipArgument( &lpArgumentString ); nGroups = atoi( lpArgumentString ); // // Allocate memory in our address space so we can read data from the debuggee's address space // pDstTree = (CNewsTree*) DbgAlloc( cbTree ); if( !pDstTree ) { dprintf( "nntpdbg: Unable to allocate memory \n"); return; } if( !ReadMemory( pSrcTree, pDstTree, cbTree, NULL ) ) { dprintf("Could not get data at 0x%x\n", pSrcTree); DbgFree( pDstTree ); return; } // // Dump the newstree // DbgPrintNewstree( pDstTree, nGroups ); DbgFree( pDstTree ); } DECLARE_API( vrootlist ) /*++ 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. --*/ { CNNTPVRoot *pFirstVRoot; DWORD nVRoots = 0; INIT_API(); while (*lpArgumentString == ' ') lpArgumentString++; if ( !*lpArgumentString ) { PrintUsage(); return; } // // Get the address of the first vroot // pFirstVRoot = (CNNTPVRoot*)GetExpression( lpArgumentString ); if ( !pFirstVRoot ) { dprintf( "nntpdbg: Unable to evaluate \"%s\"\n", lpArgumentString ); return; } SkipArgument( &lpArgumentString ); nVRoots = atoi( lpArgumentString ); // // Dump the list // DbgPrintVRootList( pFirstVRoot, nVRoots ); } DECLARE_API( newsgroup ) /*++ 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. --*/ { CNewsGroup* pSrcGroup; INIT_API(); while (*lpArgumentString == ' ') lpArgumentString++; if ( !*lpArgumentString ) { PrintUsage(); return; } // // Treat the argument as the address of a CNewsGroup struct // NOTE: pSrcGroup is an address in the debuggee's address space ! // pSrcGroup = (CNewsGroup*)GetExpression( lpArgumentString ); if ( !pSrcGroup ) { dprintf( "nntpdbg: Unable to evaluate \"%s\"\n", lpArgumentString ); return; } // // Dump the CNewsGroup object // DbgPrintNewsgroup( pSrcGroup ); } DECLARE_API( vroot ) /*++ 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. --*/ { CNNTPVRoot* pVroot = NULL; INIT_API(); while (*lpArgumentString == ' ') lpArgumentString++; if ( !*lpArgumentString ) { PrintUsage(); return; } // // Treat the argument as the address of a CNNTPVRoot struct // NOTE: pVroot is an address in the debuggee's address space ! // pVroot = (CNNTPVRoot*)GetExpression( lpArgumentString ); if ( !pVroot ) { dprintf( "nntpdbg: Unable to evaluate \"%s\"\n", lpArgumentString ); return; } // // Dump the CNNTPVRoot object // DbgPrintVRoot( pVroot ); } DECLARE_API( vrtable ) /*++ 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. --*/ { CNNTPVRootTable* pVRTable = NULL; INIT_API(); while (*lpArgumentString == ' ') lpArgumentString++; if ( !*lpArgumentString ) { PrintUsage(); return; } // // Treat the argument as the address of a CNNTPVRootTable struct // NOTE: pVRTable is an address in the debuggee's address space ! // pVRTable = (CNNTPVRootTable*)GetExpression( lpArgumentString ); if ( !pVRTable ) { dprintf( "nntpdbg: Unable to evaluate \"%s\"\n", lpArgumentString ); return; } // // Dump the CNNTPVRootTable object // DbgPrintVRootTable( pVRTable ); } DECLARE_API( sockets ) /*++ 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. --*/ { CSessionSocket *pSrcSocket, *pDstSocket; DWORD cbSocket = sizeof(CSessionSocket); INIT_API(); while (*lpArgumentString == ' ') lpArgumentString++; if ( !*lpArgumentString ) { PrintUsage(); return; } // // Get the address of the socket obj // pSrcSocket = (CSessionSocket*)GetExpression( lpArgumentString ); if ( !pSrcSocket ) { dprintf( "nntpdbg: Unable to evaluate \"%s\"\n", lpArgumentString ); return; } dprintf("Socket object is 0x%p\n", pSrcSocket); // // Allocate memory in our address space so we can read data from the debuggee's address space // pDstSocket = (CSessionSocket*) DbgAlloc( cbSocket ); if( !pDstSocket ) { dprintf( "nntpdbg: Unable to allocate memory \n"); return; } if( !ReadMemory( pSrcSocket, pDstSocket, cbSocket, NULL ) ) { dprintf("Could not get data at 0x%x\n", pSrcSocket); DbgFree( pDstSocket ); return; } // // Dump the socket obj // dprintf(" ========== socket object =========== \n"); dprintf(" Prev = 0x%p Next = 0x%p \n", pDstSocket->m_pPrev, pDstSocket->m_pPrev); dprintf(" Sink = 0x%p \n", pDstSocket->m_pSink ); dprintf(" Port = 0x%08lx \n", pDstSocket->m_nntpPort ); dprintf(" ClientContext = 0x%p \n", pDstSocket->m_context ); dprintf(" ========== socket object =========== \n"); DbgFree( pDstSocket ); } DECLARE_API( smtp ) /*++ 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. --*/ { CSmtpClientPool *pSrcSCPool, *pDstSCPool; DWORD cbSCPool = sizeof(CSmtpClientPool); INIT_API(); // // Get the address of the global newstree pointer // pSrcSCPool = (CSmtpClientPool*)GetExpression( DEBUG_PREFIX "g_SCPool" ); if ( !pSrcSCPool ) { dprintf( "nntpdbg: Unable to evaluate \"%s\"\n", DEBUG_PREFIX "g_SCPool" ); return; } // // Allocate memory in our address space so we can read data from the debuggee's address space // pDstSCPool = (CSmtpClientPool*) DbgAlloc( cbSCPool ); if( !pDstSCPool ) { dprintf( "nntpdbg: Unable to allocate memory \n"); return; } if( !ReadMemory( pSrcSCPool, pDstSCPool, cbSCPool, NULL ) ) { dprintf("Could not get data at 0x%x\n", pSrcSCPool); DbgFree( pDstSCPool ); return; } // // Dump the smtp conx cache // DbgDumpPool( pDstSCPool ); DbgFree( pDstSCPool ); } DECLARE_API( feedlist ) /*++ 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. --*/ { CFeedList* pSrcFeedList; CFeedList* pDstFeedList; DWORD cbFeedList = sizeof(CFeedList); INIT_API(); while (*lpArgumentString == ' ') lpArgumentString++; if ( !*lpArgumentString ) { PrintUsage(); return; } // // Get the ActiveFeeds global // pSrcFeedList = (CFeedList*)GetExpression( lpArgumentString ); if ( !pSrcFeedList ) { dprintf( "nntpdbg: Unable to evaluate \"%s\"\n", lpArgumentString ); return; } pDstFeedList = (CFeedList*)DbgAlloc( cbFeedList ); if( !pDstFeedList ) { dprintf("nntpdbg: Unable to allocate memory\n"); return; } // // Dump the feedblock list // if( !ReadMemory( pSrcFeedList, pDstFeedList, cbFeedList, NULL ) ) { dprintf("nntpdbg: Unable to read memory at 0x%p\n", pSrcFeedList ); DbgFree( pDstFeedList ); return; } DbgDumpFeedList( pSrcFeedList, pDstFeedList ); DbgFree( pDstFeedList ); } DECLARE_API( feed ) /*++ 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. --*/ { PFEED_BLOCK feedBlock; INIT_API(); while (*lpArgumentString == ' ') lpArgumentString++; if ( !*lpArgumentString ) { PrintUsage(); return; } // // Treat the argument as the address of a FEED_BLOCK // feedBlock = (PFEED_BLOCK)GetExpression( lpArgumentString ); if ( !feedBlock ) { dprintf( "nntpdbg: Unable to evaluate \"%s\"\n", lpArgumentString ); return; } DbgDumpFeedBlock( feedBlock ); } DECLARE_API( rf ) /*++ 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. --*/ { INIT_API(); PLONG pcCallStack = NULL; LONG cCallStack = 0; PVOID pvCallStack = NULL; CHAR** ppchCallStack = NULL; CHAR** ppchReal = NULL; LPVOID lpvCallStack = NULL; LPVOID lpvBuffer = NULL; // // Get the number of buffers // pcCallStack = (PLONG)GetExpression( "exstrace!g_iCallStack" ); if ( !pcCallStack ) { dprintf( "nntpdbg: Unable to evaluate \"exstrace!g_cCallStack\"\n" ); return; } if ( !ReadMemory( pcCallStack, &cCallStack, sizeof(LONG), NULL ) ) { dprintf( "nntpdbg: Could not read g_cCallStack\n" ); return; } // // Get pointer to buffer // pvCallStack = (CHAR**)GetExpression( "exstrace!g_ppchCallStack" ); if ( !pvCallStack ) { dprintf( "nntpdbg: Unable to evaluate \"exstrace!g_ppchCallStack\"\n" ); return; } if ( !ReadMemory( pvCallStack, &ppchCallStack, sizeof(CHAR**), NULL ) ) { dprintf( "nntpdbg: Could not read g_ppchCallStack\n" ); return; } lpvCallStack = DbgAlloc( sizeof(CHAR*) * cCallStack ); if ( !lpvCallStack ) { dprintf( "nntpdbg: Unable to allocate memory\n" ); return; } if ( !ReadMemory( ppchCallStack, lpvCallStack, sizeof(CHAR*)*cCallStack, NULL ) ) { dprintf( "nntpdbg: Could not get data at 0x%x\n", ppchCallStack ); DbgFree( lpvCallStack ); return; } else ppchReal = (CHAR**)lpvCallStack; lpvBuffer = DbgAlloc( CALL_STACK_BUF_SIZE ); if ( !lpvBuffer ) { DbgFree( lpvCallStack ); dprintf( "nntpdbg: Unable to allocate memory\n" ); return; } for ( LONG i = 0; i < cCallStack; i++ ) { if( ppchReal[i] ) { if ( !ReadMemory( ppchReal[i], lpvBuffer, CALL_STACK_BUF_SIZE, NULL ) ) { dprintf( "nntpdbg: Could not get data at 0x%x\n", ppchReal[i] ); DbgFree( lpvCallStack ); DbgFree( lpvBuffer ); return; } *(PBYTE(lpvBuffer)+CALL_STACK_BUF_SIZE-1) = 0; dprintf("%s\n", (PCHAR)lpvBuffer ); } } DbgFree( lpvBuffer ); DbgFree( lpvCallStack ); } VOID PrintUsage( VOID ) { dprintf("\n\nMicrosoft Internet News Server debugging extension, Version 2.0\n\n"); dprintf("!vroot
- Dump nntp virtual root\n"); dprintf("!vrtable
- Dump nntp virtual root table\n"); dprintf("!vrootlist
- Dump the first vroots in the table\n"); dprintf("!cpool
- Dump CPool at
\n"); dprintf("!cpools - Dump nntpsvc cpools\n"); dprintf("!instance
- Dump instance at
\n"); dprintf("!newstree
- Dump first newsgroups in newstree at
\n"); dprintf("!newsgroup
- Dump newsgroup at
\n"); dprintf("!sockets
- Dump socket at
\n"); dprintf("!smtp - Dump smtp conx cache \n"); dprintf("!feedlist
- Dump active feedblock list at
\n"); dprintf("!feed
- Dump feedblock at
\n"); dprintf("!rf - Dump all randfail call stacks \n" ); dprintf("!help - Usage \n\n"); } VOID DbgPrintInstance( NNTP_SERVER_INSTANCE* pInst ) /*++ Routine Description: Dump the first n newsgroup objects in the newstree. NOTE: Assumed that the pointer passed is in OUR address space --*/ { dprintf("\n\n======== Begin Instance dump =========\n"); if ( NNTP_SERVER_INSTANCE_SIGNATURE == pInst->m_signature ) { switch( pInst->m_dwServerState ) { case MD_SERVER_STATE_STARTED: dprintf("Server state is started\n"); break; case MD_SERVER_STATE_STARTING: dprintf("Server state is starting\n"); break; case MD_SERVER_STATE_STOPPING: dprintf("Server state is stopping\n" ); break; case MD_SERVER_STATE_STOPPED: dprintf("Server state is stopped\n" ); break; case MD_SERVER_STATE_PAUSING: dprintf("Server state is pausing\n" ); break; case MD_SERVER_STATE_PAUSED: dprintf("Server state is paused\n" ); break; case MD_SERVER_STATE_CONTINUING: dprintf("Server state is continuing\n" ); break; } dprintf("Server has %d references\n", pInst->m_reference ); dprintf("Instance id is %d\n", pInst->QueryInstanceId() ); dprintf("Default port is %d\n", pInst->m_sDefaultPort ); pInst->m_fAddedToServerInstanceList ? dprintf("Added to server instance list\n" ) : dprintf("NOT added to server instance list\n" ); dprintf("It has %d connections now\n", pInst->m_dwCurrentConnections ); dprintf("Owning service is 0x%p\n", pInst->m_Service ); dprintf("Previous instance 0x%p\n", CONTAINING_RECORD( pInst->m_InstanceListEntry.Flink, IIS_SERVER_INSTANCE, m_InstanceListEntry ) ); dprintf("Next instance 0x%p\n", CONTAINING_RECORD( pInst->m_InstanceListEntry.Blink, IIS_SERVER_INSTANCE, m_InstanceListEntry ) ); pInst->m_ServiceStartCalled ? dprintf("Start method called\n") : dprintf("Start method NOT called\n" ); dprintf("Article table pointer 0x%p\n", pInst->m_pArticleTable ); dprintf("History table pointer 0x%p\n", pInst->m_pHistoryTable ); dprintf("Xover table pointer 0x%p\n", pInst->m_pXoverTable ); dprintf("Xover cache is 0x%p\n", pInst->m_pXCache ); dprintf("Expire object is 0x%p\n", pInst->m_pExpireObject ); dprintf("VRoot table is 0x%p\n", pInst->m_pVRootTable ); dprintf("Dirnot object is 0x%p\n", pInst->m_pDirNot ); dprintf("Server object is 0x%p\n", pInst->m_pNntpServerObject ); dprintf("Wrapper( for posting lib) is 0x%p\n", pInst->m_pInstanceWrapper ); dprintf("Wrapper( for newstree lib) is 0x%p\n", pInst->m_pInstanceWrapperEx ); dprintf("SEO router 0x%p\n", pInst->m_pSEORouter ); dprintf("Newstree is 0x%p\n", pInst->m_pTree ); pInst->m_fAllowClientPosts ? dprintf("Server allows client posts\n") : dprintf("Server doesn't allow client posts\n" ); pInst->m_fAllowFeedPosts ? dprintf("Server allows feed posts\n" ) : dprintf("Server doesn't allow feed posts\n" ); pInst->m_fAllowControlMessages ? dprintf("Server allows control messages\n" ) : dprintf("Server doesn't allow control messages\n" ); pInst->m_fNewnewsAllowed ? dprintf("Newnews allowed\n" ) : dprintf("Newnews not allowed\n" ); dprintf("Client post hard limit %d\n", pInst->m_cbHardLimit ); dprintf("Client post soft limit %d\n", pInst->m_cbSoftLimit ); dprintf("Feed hard limit %d\n", pInst->m_cbFeedHardLimit ); dprintf("Feed soft limit %d\n", pInst->m_cbFeedSoftLimit ); dprintf("SSL access params 0x%08lx\n", pInst->m_dwSslAccessPerms ); dprintf("SSLInfo object 0x%p\n", pInst->m_pSSLInfo ); dprintf("Rebuild object 0x%p\n", pInst->m_pRebuild ); dprintf("Last rebuild error %d\n", pInst->m_dwLastRebuildError ); dprintf("Socket list 0x%p\n", pInst->m_pInUseList ); dprintf("Active feed list 0x%p\n", pInst->m_pActiveFeeds ); dprintf("Passive feed list 0x%p\n", pInst->m_pPassiveFeeds ); } else { dprintf("Instance signature bad\n" ); } dprintf("\n\n======== End Instance dump =========\n\n"); } VOID DbgPrintNewstree( CNewsTree* ptree, DWORD nGroups ) /*++ Routine Description: Dump the first n newsgroup objects in the newstree. NOTE: Assumed that the pointer passed is in OUR address space --*/ { CNewsGroup* pGroup; dprintf("\n\n======== Newstree members =========\n"); dprintf(" Owning instance is 0x%p\n", ptree->m_pInstance ); dprintf(" StartSpecial is %d\n", ptree->m_idStartSpecial ); dprintf(" LastSpecial is %d\n", ptree->m_idLastSpecial ); dprintf(" idSlaveGroup is %d\n", ptree->m_idSlaveGroup ); dprintf(" idSpecialHigh is %d\n", ptree->m_idSpecialHigh ); dprintf(" idStart is %d\n", ptree->m_idStart ); dprintf(" idHigh is %d\n", ptree->m_idHigh ); dprintf(" First group is 0x%p\n", ptree->m_pFirst ); dprintf(" Last group is 0x%p\n", ptree->m_pLast ); dprintf(" Num groups is %d\n", ptree->m_cGroups ); dprintf(" VRoot table is 0x%p\n", ptree->m_pVRTable ); ptree->m_fStoppingTree ? dprintf( " Tree is being stopped\n" ) : dprintf( " Tree is not being stopped\n" ); dprintf(" Group.lst object is 0x%p\n", ptree->m_pFixedPropsFile ); dprintf(" Groupvar.lst object is 0x%p\n", ptree->m_pVarPropsFile ); dprintf(" Server object is 0x%p\n", ptree->m_pServerObject ); ptree->m_fVRTableInit ? dprintf(" Vroot table initialized\n" ) : dprintf(" Vroot table NOT initialized\n" ); if( nGroups ) { dprintf("\n\n======== Begin Newstree dump =========\n"); for( pGroup = (CNewsGroup*)ptree->m_pFirst; pGroup && nGroups--; ) { pGroup = DbgPrintNewsgroup( pGroup ); } dprintf("\n\n======== End Newstree dump =========\n\n"); } } VOID DbgPrintVRootList( CNNTPVRoot* pFirstVRoot, DWORD nVRoots ) /*++ Routine Description: Dump the first n newsgroup objects in the newstree. NOTE: Assumed that the pointer passed is in OUR address space --*/ { CNNTPVRoot* pVRoot; if( nVRoots ) { dprintf("\n\n======== Begin virtual root list dump =========\n"); for( pVRoot = pFirstVRoot; pVRoot && nVRoots--; ) { pVRoot = DbgPrintVRoot( pVRoot ); } dprintf("\n\n======== End virtual root list dump =========\n\n"); } } VOID PrintSystemTime( FILETIME* pftTime ) { SYSTEMTIME st; FileTimeToSystemTime( pftTime, &st ); dprintf(" %04d::%02d::%02d::::%02d::%02d::%02d\n", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond); } VOID PrintString( LPSTR lp1, LPSTR lp2 ) { move( g_szBuffer, lp2 ); dprintf( lp1, g_szBuffer ); } CNewsGroup* DbgPrintNewsgroup( CNewsGroup * pSrcGroup ) /*++ Routine Description: Dump the newsgroup object at pGroup. NOTE: Assumed that the pointer passed in is in the debuggee's address space ie. we need to allocate memory and copy the data over into our address space ! Arguments: Returns: The next newsgroup pointer --*/ { CNewsGroup *pGroup, *pDstGroup; char szNewsGroup [MAX_NEWSGROUP_NAME]; DWORD cbGroupName; LPCSTR lpstrGroup; DWORD cbPath, cbNewsGroup; CNewsGroup* pGroupRet = NULL; BOOL fActive = TRUE; SYSTEMTIME sysTime; // // Allocate memory in our address space so we can read data from the debuggee's address space // cbNewsGroup = sizeof(CNewsGroup); pDstGroup = (CNewsGroup*) DbgAlloc( cbNewsGroup ); if( !pDstGroup ) { dprintf( "nntpdbg: Unable to allocate memory \n"); return NULL; } if( !ReadMemory( pSrcGroup, pDstGroup, cbNewsGroup, NULL ) ) { dprintf("Could not get data at 0x%x\n", pSrcGroup); goto DbgPrintNewsgroup_Exit; } // Now, we can use pGroup to access the members of the CNewsGroup object pGroup = pDstGroup; // // Dump the newsgroup object // dprintf("\n\n======== Begin Newsgroup object =========\n\n"); // // Check to see if group object is deallocated // fActive = ( pGroup->m_dwSignature == CNEWSGROUPCORE_SIGNATURE ); if ( fActive ) { // // dump newsgroup name // lpstrGroup = pGroup->m_pszGroupName; cbGroupName = pGroup->m_cchGroupName; // it should have already included '\0' if( ReadMemory( lpstrGroup, szNewsGroup, cbGroupName, NULL) ) { dprintf("Newsgroup name is %s\n", szNewsGroup ); } // // Dump native name // lpstrGroup = pGroup->m_pszNativeName; if ( lpstrGroup && ReadMemory( lpstrGroup, szNewsGroup, cbGroupName, NULL ) ) { dprintf("Pretty name is %s\n", szNewsGroup ); } else { dprintf("No native name\n" ); } // // Dump pretty name // lpstrGroup = pGroup->m_pszPrettyName; cbGroupName = pGroup->m_cchPrettyName; if ( lpstrGroup && ReadMemory( lpstrGroup, szNewsGroup, cbGroupName, NULL ) ) { dprintf("Pretty name is %s\n", szNewsGroup ); } else { dprintf("No pretty name\n" ); } // // Dump help text // lpstrGroup = pGroup->m_pszHelpText; cbGroupName = pGroup->m_cchHelpText; if ( lpstrGroup && ReadMemory( lpstrGroup, szNewsGroup, cbGroupName, NULL ) ) { dprintf("Help text is %s\n", szNewsGroup ); } else { dprintf("No help text\n" ); } // // Dump moderator // lpstrGroup = pGroup->m_pszModerator; cbGroupName = pGroup->m_cchModerator; if ( lpstrGroup && ReadMemory( lpstrGroup, szNewsGroup, cbGroupName, NULL ) ) { dprintf("Moderator is %s\n", szNewsGroup ); } else { dprintf("No moderator\n" ); } // // dump group privates // dprintf("Ref count is %d\n", pGroup->m_cRefs ); dprintf("Parent tree is 0x%p\n", pGroup->m_pNewsTree ); dprintf("Parent vroot is 0x%p\n", pGroup->m_pVRoot ); dprintf("Low watermark is %d\n", pGroup->m_iLowWatermark); dprintf("High watermark is %d\n", pGroup->m_iHighWatermark); dprintf("Article estimate is %d\n", pGroup->m_cMessages ); dprintf("Group id is %d\n", pGroup->m_dwGroupId ); pGroup->m_fReadOnly ? dprintf("Group is read only\n" ) : dprintf("Group is not read only\n" ); pGroup->m_fDeleted ? dprintf("Group is marked deleted\n") : dprintf("Group is NOT marked deleted\n"); FileTimeToSystemTime( &(pGroup->m_ftCreateDate), &sysTime ); dprintf("Group create time: %d/%d/%d - %d:%d:%d\n", sysTime.wMonth, sysTime.wDay, sysTime.wYear, sysTime.wHour, sysTime.wMinute, sysTime.wSecond ); dprintf("Cache hit is %d\n", pGroup->m_dwCacheHit ); pGroup->m_fAllowExpire ? dprintf( "Expire allowed\n" ) : dprintf( "Expire not allowed\n" ); pGroup->m_fAllowPost ? dprintf( "Post allowed\n" ) : dprintf( "Expire not allowed\n" ); pGroup->m_fDecorateVisited ? dprintf( "Decorate visited\n" ) : dprintf( "Decorate non-visited\n" ); dprintf("m_artXoverExpireLow is %d\n", pGroup->m_artXoverExpireLow); dprintf("Prev group is 0x%p\n", pGroup->m_pPrev); dprintf("Next group is 0x%p\n", pGroup->m_pNext); pGroupRet = (CNewsGroup*)pGroup->m_pNext; } else { dprintf( "Newsgroup signature is bad\n" ); } dprintf("\n======== End Newsgroup object =========\n"); DbgPrintNewsgroup_Exit: DbgFreeEx( pDstGroup ); return pGroupRet; } CNNTPVRoot* DbgPrintVRoot( CNNTPVRoot * pVRoot ) /*++ Routine Description: Dump the vroot object at pVRoot NOTE: Assumed that the pointer passed in is in the debuggee's address space ie. we need to allocate memory and copy the data over into our address space ! Arguments: Returns: The next newsgroup pointer --*/ { CNNTPVRoot *pDestVRoot, *pMyVRoot; DWORD cbVRoot; CNNTPVRoot* pVRootRet = NULL; BOOL fActive = FALSE; // // Allocate memory in our address space so we can read data from the debuggee's address space // cbVRoot = sizeof(CNNTPVRoot); pDestVRoot = (CNNTPVRoot*) DbgAlloc( cbVRoot ); if( !pDestVRoot ) { dprintf( "nntpdbg: Unable to allocate memory \n"); return NULL; } if( !ReadMemory( pVRoot, pDestVRoot, cbVRoot, NULL ) ) { dprintf("Could not get data at 0x%x\n", pVRoot ); goto DbgPrintVRoot_Exit; } // Now, we can use pMyVRoot to access the members of the CNNTPVRoot object pMyVRoot = pDestVRoot; // // Dump the vroot object // dprintf("\n\n======== Begin virtual root object =========\n\n"); // // Check to see if group object is deallocated // fActive = ( pMyVRoot->m_dwSig == VROOT_GOOD_SIG ); if ( fActive ) { // // Dump reference // dprintf("Reference count is %d\n", pMyVRoot->m_cRefs ); dprintf("Next vroot is 0x%p\n", pMyVRoot->m_pNext ); pVRootRet = (CNNTPVRoot*)pMyVRoot->m_pNext; dprintf("Prev vroot is 0x%p\n", pMyVRoot->m_pPrev ); pMyVRoot->m_fInit ? dprintf("Vroot is initialized\n") : dprintf("Vroot is NOT initialized\n" ); dprintf("Vroot name is %s\n", pMyVRoot->m_szVRootName ); dprintf("Owning vroot table is 0x%p\n", pMyVRoot->m_pVRootTable ); pMyVRoot->m_fUpgrade ? dprintf("This is an upgraded vroot\n" ) : dprintf("This is not an upgraded vroot\n" ); pMyVRoot->m_fIsIndexed ? dprintf("Content indexed\n" ) : dprintf("Not content indexed\n" ); dprintf("Access bitmask is 0x%08lx\n", pMyVRoot->m_dwAccess ); dprintf("SSL access bitmask 0x%08lx\n", pMyVRoot->m_dwSSL ); dprintf("Metabase object 0x%p\n", pMyVRoot->m_pMB ); dprintf("Directory path %s\n", pMyVRoot->m_szDirectory ); dprintf("Prepare driver 0x%p\n", pMyVRoot->m_pDriverPrepare ); dprintf("Good driver 0x%p\n", pMyVRoot->m_pDriver ); switch( pMyVRoot->m_eLogonInfo ) { case CNNTPVRoot::VROOT_LOGON_DEFAULT: dprintf("This is a file system vroot\n"); break; case CNNTPVRoot::VROOT_LOGON_UNC: dprintf("This is a UNC vroot\n" ); break; case CNNTPVRoot::VROOT_LOGON_EX: dprintf("This is an exchange vroot\n" ); break; } switch( pMyVRoot->m_eState ) { case CNNTPVRoot::VROOT_STATE_UNINIT: dprintf("Vroot not inited\n" ); break; case CNNTPVRoot::VROOT_STATE_CONNECTING: dprintf("Vroot is connecting\n" ); break; case CNNTPVRoot::VROOT_STATE_CONNECTED: dprintf("Vroot is connected\n" ); break; } dprintf("VRoot Win32 Error %d\n", pMyVRoot->m_dwWin32Error ); dprintf("Impersonation token ( for UNC ): %d\n", pMyVRoot->m_hImpersonation ); pMyVRoot->m_bExpire ? dprintf("Vroot handles expire himself\n") : dprintf("Protocol should help him expire\n" ); pMyVRoot->m_lDecCompleted == 0 ? dprintf("Decorate newstree in progress\n") : dprintf("Decorate newstree completed\n" ); #ifdef DEBUG dprintf("Next vroot in debug list 0x%p\n", CONTAINING_RECORD( pMyVRoot->m_DebugList.Flink, CVRoot, m_DebugList ) ); #endif } else { dprintf("Vroot signature bad\n" ); } dprintf("\n======== End virtual root object =========\n"); DbgPrintVRoot_Exit: DbgFreeEx( pDestVRoot ); return pVRootRet; } void DbgPrintVRootTable( CNNTPVRootTable * pVRTable ) /*++ Routine Description: Dump the vroot table object at pVRTable NOTE: Assumed that the pointer passed in is in the debuggee's address space ie. we need to allocate memory and copy the data over into our address space ! Arguments: Returns: The next newsgroup pointer --*/ { CNNTPVRootTable *pDestVRTable, *pMyVRTable; DWORD cbVRTable; CHAR szVRootPath[MAX_VROOT_PATH]; // // Allocate memory in our address space so we can read data from the debuggee's address space // cbVRTable = sizeof(CNNTPVRootTable); pDestVRTable = (CNNTPVRootTable*) DbgAlloc( cbVRTable ); if( !pDestVRTable ) { dprintf( "nntpdbg: Unable to allocate memory \n"); return ; } if( !ReadMemory( pVRTable, pDestVRTable, cbVRTable, NULL ) ) { dprintf("Could not get data at 0x%x\n", pVRTable ); goto DbgPrintVRootTable_Exit; } // Now, we can use pMyVRTable to access the members of the CNNTPVRoot object pMyVRTable = pDestVRTable; // // Dump the vroot object // dprintf("\n\n======== Begin virtual root table object =========\n\n"); #ifdef DEBUG if ( IsListEmpty( &pMyVRTable->impl.m_DebugListHead ) ) { dprintf("Debug list is empty\n"); } else { dprintf("First vroot in debug list 0x%p\n", CONTAINING_RECORD( pMyVRTable->impl.m_DebugListHead.Flink, CVRoot, m_DebugList ) ); } #endif CopyUnicodeStringIntoAscii( szVRootPath, pMyVRTable->impl.m_wszRootPath ); dprintf("VRoot path is %s\n", szVRootPath ); pMyVRTable->impl.m_fInit ? dprintf("We have been initialized\n") : dprintf("We are not initialized\n" ); pMyVRTable->impl.m_fShuttingDown ? dprintf("We are shutting down\n") : dprintf("We are not shutting down\n" ); if ( pMyVRTable->impl.m_listVRoots.IsEmpty() ) { dprintf("Table is empty\n" ); } else { dprintf("The first vroot on table is 0x%p\n", pMyVRTable->impl.m_listVRoots.m_pHead ); } dprintf("Owning instance wrapper 0x%p\n", pMyVRTable->m_pInstWrapper ); dprintf("\n======== End virtual root table object =========\n"); DbgPrintVRootTable_Exit: DbgFreeEx( pDestVRTable ); } VOID DbgDumpPool( CSmtpClientPool* pSCPool ) /*++ Routine Description: Dump the smtp cached conx NOTE: Assumed that the pointer passed is in OUR address space --*/ { DWORD cSlots = pSCPool->m_cSlots; DWORD i; BOOL* rgAvailList = NULL; CSmtpClient** rgppSCList = NULL; dprintf("\n======== Begin CSmtpClientPool dump =========\n\n"); dprintf("Number of slots is %d\n", cSlots); DWORD cbAvailList = sizeof(BOOL)*cSlots; DWORD cbSCList = sizeof(CSmtpClient*)*cSlots; rgAvailList = (BOOL*)DbgAlloc( cbAvailList ); if( !rgAvailList || !ReadMemory( pSCPool->m_rgAvailList, rgAvailList, cbAvailList, NULL) ) { dprintf("Failed to allocate or read memory\n"); goto DbgDumpPool_Exit; } rgppSCList = (CSmtpClient**)DbgAlloc( cbSCList ); if( !rgppSCList || !ReadMemory( pSCPool->m_rgpSCList, rgppSCList, cbSCList, NULL) ) { dprintf("Failed to allocate or read memory\n"); goto DbgDumpPool_Exit; } // Dump the conx object pointers and avail status for(i=0; im_ListHead).Flink ; listEntry = SrclistEntry; DWORD offset = (DWORD)((DWORD_PTR)&((CFeedList*)0)->m_ListHead); PLIST_ENTRY listEnd = (PLIST_ENTRY)((LPBYTE)pSrcFeedList+offset); //dprintf("offset is %d listEnd is 0x%p\n", offset, listEnd); while( listEntry != listEnd ) { PFEED_BLOCK feedBlock = CONTAINING_RECORD( listEntry, FEED_BLOCK, ListEntry ); DbgDumpFeedBlock( feedBlock ); SrclistEntry = listEntry; move( Entry, SrclistEntry ); listEntry = Entry.Flink ; } } VOID DbgDumpCPool(CPool* pCPool, DWORD dwSignature, LPCSTR szSymbol) { CPool* pPool = (CPool*)DbgAlloc( sizeof(CPool)); if ( pCPool && pPool ) { if ( ReadMemory( (LPVOID) pCPool, pPool, sizeof(CPool), NULL )) { dprintf( "%s at 0x%8lx, signature is 0x%.8x\n", (szSymbol?szSymbol:"CPool"), pCPool, pPool->m_dwSignature); if( dwSignature != 0 && dwSignature != pPool->m_dwSignature ) { dprintf(" *** signature mismatch\n" ); } dprintf(" m_cMaxInstances = %d\n", pPool->m_cMaxInstances ); dprintf(" m_cInstanceSize = %d\n", pPool->m_cInstanceSize ); dprintf(" m_cNumberCommitted = %d\n", pPool->m_cNumberCommitted ); dprintf(" m_cNumberInUse = %d\n", pPool->m_cNumberInUse ); dprintf(" m_cNumberAvail = %d\n", pPool->m_cNumberAvail ); dprintf(" m_cFragmentInstances = %d\n", pPool->m_cFragmentInstances ); dprintf(" m_cFragments = %d\n", pPool->m_cFragments ); dprintf(" Fragments:\n"); for(int i=0; im_pFragments[i], ((i+1)%4)==0?"\n":"" ); } dprintf("=========================\n"); } DbgFree( (PVOID)pPool ); } }