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.
1937 lines
51 KiB
1937 lines
51 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:
|
|
|
|
--*/
|
|
|
|
#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 <tigris.hxx>
|
|
#include "smtpcli.h"
|
|
|
|
#include <ntsdexts.h>
|
|
#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 <address> - Dump nntp virtual root\n");
|
|
dprintf("!vrtable <address> - Dump nntp virtual root table\n");
|
|
dprintf("!vrootlist <address> <n> - Dump the first <n> vroots in the table\n");
|
|
dprintf("!cpool <address> - Dump CPool at <address>\n");
|
|
dprintf("!cpools - Dump nntpsvc cpools\n");
|
|
dprintf("!instance <address> - Dump instance at <address> \n");
|
|
dprintf("!newstree <address> <n>- Dump first <n> newsgroups in newstree at <address> \n");
|
|
dprintf("!newsgroup <address> - Dump newsgroup at <address> \n");
|
|
dprintf("!sockets <address> - Dump socket at <address> \n");
|
|
dprintf("!smtp - Dump smtp conx cache \n");
|
|
dprintf("!feedlist <address> - Dump active feedblock list at <address> \n");
|
|
dprintf("!feed <address> - Dump feedblock at <address> \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; i<cSlots; i++)
|
|
{
|
|
dprintf("Smtp conx object %d is 0x%p\n", i+1, rgppSCList [i]);
|
|
dprintf("Avail status is %d\n", rgAvailList [i]);
|
|
}
|
|
|
|
dprintf("\n======== End CSmtpClientPool dump =========\n");
|
|
|
|
DbgDumpPool_Exit:
|
|
|
|
DbgFreeEx( rgAvailList );
|
|
DbgFreeEx( rgppSCList );
|
|
}
|
|
|
|
VOID
|
|
DbgDumpFeedBlock(
|
|
PFEED_BLOCK feedBlock
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Dump the feedBlock passed in; validate signature
|
|
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:
|
|
|
|
--*/
|
|
{
|
|
FEED_BLOCK feed;
|
|
|
|
// read memory from debuggee's address space
|
|
move( feed, feedBlock );
|
|
|
|
// validate signature
|
|
if( FEED_BLOCK_SIGN != feed.Signature )
|
|
{
|
|
dprintf("Invalid Feed block signature Expected: 0x%08lx Got: 0x%08lx \n", FEED_BLOCK_SIGN, feed.Signature );
|
|
return;
|
|
}
|
|
|
|
// ok, dump the feed block
|
|
dprintf("============ Begin feed block dump =============== \n");
|
|
|
|
dprintf("Number of feeds done so far is %d\n", feed.NumberOfFeeds);
|
|
dprintf("Number of failed connection attempts for Push feeds is %d\n", feed.cFailedAttempts);
|
|
dprintf("The last newsgroup spec Pulled is %d\n", feed.LastNewsgroupPulled);
|
|
dprintf("Resolved IP address is %d\n", feed.IPAddress);
|
|
dprintf("feedblock ListEntry Flink is 0x%p\n", feed.ListEntry.Flink);
|
|
dprintf("feedblock ListEntry Blink is 0x%p\n", feed.ListEntry.Blink);
|
|
dprintf("feed is in progress ? %d\n", feed.FeedsInProgress);
|
|
dprintf("Count of references to this block is %d\n", feed.ReferenceCount);
|
|
dprintf("Current State of this block is %d\n", feed.State);
|
|
dprintf("Should we delete this block when the references reach 0 ? %d\n", feed.MarkedForDelete);
|
|
dprintf("Pointer to a FEED_BLOCK that we are replaced by is 0x%p\n", feed.ReplacedBy);
|
|
dprintf("Pointer to a FEED_BLOCK we replace is 0x%p\n", feed.Replaces);
|
|
dprintf("Type of this feed (push/pull/passive) is %d\n", feed.FeedType);
|
|
|
|
//dprintf("Name of reg key this feed info is stored under 0x%p\n", feed.KeyName);
|
|
|
|
dprintf("The Queue used to record outgoing articles for this ACTIVE outgoing feed is 0x%p\n", feed.pFeedQueue);
|
|
dprintf("Unique id for this feed block is %d\n", feed.FeedId);
|
|
dprintf("Should we autocreate directories? %d\n", feed.AutoCreate);
|
|
dprintf("Minutes between feeds is %d\n", feed.FeedIntervalMinutes);
|
|
|
|
dprintf("Pull Request Time is");
|
|
PrintSystemTime( &feed.PullRequestTime );
|
|
|
|
FILETIME ft;
|
|
|
|
dprintf("Start Time is");
|
|
FILETIME_FROM_LI( &ft, &feed.StartTime );
|
|
PrintSystemTime( &ft );
|
|
|
|
dprintf("Next Active Time is");
|
|
FILETIME_FROM_LI( &ft, &feed.NextActiveTime);
|
|
PrintSystemTime( &ft );
|
|
|
|
PrintString("Name of the feed server is %s\n", feed.ServerName);
|
|
dprintf("Newsgroups to pull is 0x%p\n", feed.Newsgroups);
|
|
dprintf("Distributions is 0x%p\n", feed.Distribution);
|
|
|
|
dprintf("Flag indicating whether the feed is currently 'enabled' is %d\n", feed.fEnabled);
|
|
|
|
//PrintString("The name to be used in Path processing is %s\n", feed.UucpName);
|
|
PrintString("The directory where we are to store our temp files is %s\n", feed.FeedTempDirectory);
|
|
|
|
dprintf("Maximum number of consecutive failed connect attempts before\n");
|
|
dprintf("we disable the feed is %d\n", feed.MaxConnectAttempts);
|
|
dprintf("Number of sessions to create for outbound feeds is %d\n", feed.ConcurrentSessions);
|
|
dprintf("Type of security to have is %d\n", feed.SessionSecurityType);
|
|
dprintf("Authentication security is %d\n", feed.AuthenticationSecurity);
|
|
|
|
PrintString("User Account for clear text logons is %s\n", feed.NntpAccount);
|
|
PrintString("User Password for clear text logons is %s\n", feed.NntpPassword);
|
|
|
|
dprintf("Allow control messages on this feed ? %d\n", feed.fAllowControlMessages);
|
|
|
|
dprintf("============ End feed block dump =============== \n");
|
|
}
|
|
|
|
VOID
|
|
DbgDumpFeedList(
|
|
CFeedList* pSrcFeedList,
|
|
CFeedList* pDstFeedList
|
|
)
|
|
/*--
|
|
Arguments:
|
|
|
|
pSrcFeedList - pointer in debuggee's address space
|
|
pDstFeedList - pointer in OUR address space
|
|
|
|
--*/
|
|
{
|
|
LIST_ENTRY Entry;
|
|
PLIST_ENTRY listEntry;
|
|
PLIST_ENTRY SrclistEntry = (pDstFeedList->m_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; i<MAX_CPOOL_FRAGMENTS; i++) {
|
|
dprintf(" %p%s", pPool->m_pFragments[i], ((i+1)%4)==0?"\n":"" );
|
|
}
|
|
dprintf("=========================\n");
|
|
}
|
|
DbgFree( (PVOID)pPool );
|
|
}
|
|
}
|
|
|