|
|
/*++
Copyright (c) 1995-1997 Microsoft Corporation
Module Name:
ref.cxx
Abstract:
This module contains the default ntsd debugger extensions for Internet Information Server.
Author:
Keith Moore (keithmo) 27-Aug-1997
Revision History:
--*/
#include "inetdbgp.h"
//
// The maximum number of contexts that may be passed to the "ref"
// extension command on the command line.
//
#define MAX_REF_CONTEXT 64
/************************************************************
* Dump Reference Traces ************************************************************/
BOOL IsContextInList( IN PVOID Context, IN PVOID * ContextList, IN LONG NumContextsInList )
/*++
Routine Description:
Scans the given context list looking for the specified context value.
Arguments:
Context - The context value to look for.
ContextList - The context list to scan.
NumContextsInList - The number of contexts in the context list.
Return Value:
BOOL - TRUE if the context value is in the list, FALSE if not.
--*/
{ while( NumContextsInList > 0 ) { if( *ContextList == Context ) { return TRUE; }
ContextList++; NumContextsInList--; }
return FALSE; }
VOID DumpReferenceLog( IN PSTR lpArgumentString, IN BOOLEAN fReverse )
/*++
Routine Description:
Dumps the specified reference log either forwards (fReverse == FALSE) or backwards (fReverse == TRUE).
Arguments:
lpArgumentString - An expression specifying the reference log to dump.
fReverse - The dump direction.
Return Value:
None.
--*/
{ ULONG_PTR refLogAddress = 0; ULONG_PTR entryAddress; LONG numEntries; TRACE_LOG logHeader; REF_TRACE_LOG_ENTRY logEntry; LONG i; DWORD_PTR offset; PCHAR format; PVOID specificContexts[MAX_REF_CONTEXT]; LONG numSpecificContexts = 0; LONG index; LONG direction; PSTR cmdName; UCHAR symbol[MAX_SYMBOL_LEN];
direction = fReverse ? -1 : 1; cmdName = fReverse ? "rref" : "ref";
//
// Skip leading blanks.
//
while( *lpArgumentString == ' ' || *lpArgumentString == '\t' ) { lpArgumentString++; }
if( *lpArgumentString == '\0' ) { PrintUsage( cmdName ); return; }
refLogAddress = (ULONG_PTR)GetExpression( lpArgumentString );
if( refLogAddress == 0 ) {
dprintf( "inetdbg.%s: cannot evaluate \"%s\"\n", cmdName, lpArgumentString );
return;
}
//
// Skip to end of expression, then skip any blanks.
//
while( *lpArgumentString != ' ' && *lpArgumentString != '\t' && *lpArgumentString != '\0' ) { lpArgumentString++; }
while( *lpArgumentString == ' ' || *lpArgumentString == '\t' ) { lpArgumentString++; }
//
// If we have context values, use them.
//
while( *lpArgumentString != '\0' && numSpecificContexts < MAX_REF_CONTEXT ) {
specificContexts[numSpecificContexts++] = (PVOID)GetExpression( lpArgumentString );
while( *lpArgumentString != ' ' && *lpArgumentString != '\t' && *lpArgumentString != '\0' ) { lpArgumentString++; }
while( *lpArgumentString == ' ' || *lpArgumentString == '\t' ) { lpArgumentString++; }
}
//
// Read the log header, perform some sanity checks.
//
if( !ReadMemory( refLogAddress, &logHeader, sizeof(logHeader), NULL ) ) {
dprintf( "inetdbg.%s: cannot read memory @ %p\n", cmdName, (PVOID)refLogAddress );
return;
}
dprintf( "inetdbg.%s: log @ %p:\n" " Signature = %08lx (%s)\n" " LogSize = %lu\n" " NextEntry = %lu\n" " EntrySize = %lu\n" " LogBuffer = %p\n", cmdName, (PVOID)refLogAddress, logHeader.Signature, logHeader.Signature == TRACE_LOG_SIGNATURE ? "OK" : logHeader.Signature == TRACE_LOG_SIGNATURE_X ? "FREED" : "INVALID", logHeader.LogSize, logHeader.NextEntry, logHeader.EntrySize, logHeader.LogBuffer );
if( logHeader.LogBuffer > ( (PUCHAR)refLogAddress + sizeof(logHeader) ) ) { dprintf( " Extra Data @ %p\n", (PVOID)( refLogAddress + sizeof(logHeader) ) ); }
if( logHeader.Signature != TRACE_LOG_SIGNATURE && logHeader.Signature != TRACE_LOG_SIGNATURE_X ) {
dprintf( "inetdbg.%s: log @ %p has invalid signature %08lx:\n", cmdName, (PVOID)refLogAddress, logHeader.Signature );
return;
}
if( logHeader.EntrySize != sizeof(logEntry) ) {
dprintf( "inetdbg.%s: log @ %p is not a ref count log\n", cmdName, (PVOID)refLogAddress );
return;
}
if( logHeader.NextEntry == -1 ) {
dprintf( "inetdbg.%s: empty log @ %p\n", cmdName, (PVOID)refLogAddress );
return;
}
//
// Calculate the starting address and number of entries.
//
if( fReverse ) { if( logHeader.NextEntry < logHeader.LogSize ) { numEntries = logHeader.NextEntry + 1; index = logHeader.NextEntry; } else { numEntries = logHeader.LogSize; index = logHeader.NextEntry % logHeader.LogSize; } } else { if( logHeader.NextEntry < logHeader.LogSize ) { numEntries = logHeader.NextEntry + 1; index = 0; } else { numEntries = logHeader.LogSize; index = ( logHeader.NextEntry + 1 ) % logHeader.LogSize; } }
entryAddress = (ULONG_PTR)logHeader.LogBuffer + (ULONG_PTR)( index * sizeof(logEntry) );
if( entryAddress >= ( (ULONG_PTR)logHeader.LogBuffer + (ULONG_PTR)( numEntries * sizeof(logEntry) ) ) ) {
dprintf( "inetdbg.%s: log @ %p has invalid data\n", cmdName, (PVOID)refLogAddress );
return;
}
//
// Dump the log.
//
for( ; numEntries > 0 ; index += direction, numEntries--, entryAddress += ( direction * sizeof(logEntry) ) ) {
if( CheckControlC() ) { break; }
if( index >= logHeader.LogSize ) { index = 0; entryAddress = (ULONG_PTR)logHeader.LogBuffer; } else if( index < 0 ) { index = logHeader.LogSize - 1; entryAddress = (ULONG_PTR)logHeader.LogBuffer + (ULONG_PTR)( index * sizeof(logEntry) ); }
if( !ReadMemory( entryAddress, &logEntry, sizeof(logEntry), NULL ) ) {
dprintf( "inetdbg.%s: cannot read memory @ %p\n", cmdName, (ULONG_PTR)entryAddress );
return;
}
if( ( numSpecificContexts == 0 ) || IsContextInList( logEntry.Context, specificContexts, numSpecificContexts ) ) {
dprintf( "\nThread = %08p, Context = %08p, NewRefCount = %-10ld : %ld\n", logEntry.Thread, logEntry.Context, logEntry.NewRefCount, index );
if ( logEntry.Context1 != REF_TRACE_EMPTY_CONTEXT || logEntry.Context2 != REF_TRACE_EMPTY_CONTEXT || logEntry.Context3 != REF_TRACE_EMPTY_CONTEXT ) {
//
// if the caller passed extended context values,
// write them to the log
//
// NOTE we use REF_TRACE_EMPTY_CONTEXT in all extended
// contexts as the signal that a caller does not use
// extended context - avoids spew for callers who don't care.
//
dprintf( "Context1 = %08p, Context2 = %08p, Context3 = %08p\n", logEntry.Context1, logEntry.Context2, logEntry.Context3 ); }
for( i = 0 ; i < REF_TRACE_LOG_STACK_DEPTH ; i++ ) {
if( logEntry.Stack[i] == NULL ) { break; }
GetSymbol( (ULONG_PTR) logEntry.Stack[i], symbol, &offset );
if( symbol[0] == '\0' ) { format = " %08p\n"; } else if( offset == 0 ) { format = " %08p : %s\n"; } else { format = " %08p : %s+0x%lx\n"; }
dprintf( format, logEntry.Stack[i], symbol, offset );
}
}
}
} // DumpReferenceLog
DECLARE_API( ref )
/*++
Routine Description:
This function is called as an NTSD extension to format and dump a reference trace log.
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(); DumpReferenceLog( lpArgumentString, FALSE );
} // DECLARE_API( ref )
DECLARE_API( rref )
/*++
Routine Description:
This function is called as an NTSD extension to format and dump a reference trace log backwards.
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(); DumpReferenceLog( lpArgumentString, TRUE );
} // DECLARE_API( rref )
DECLARE_API( resetref )
/*++
Routine Description:
This function is called as an NTSD extension to reset a reference trace log back to its initial state.
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.
--*/
{ ULONG_PTR refLogAddress = 0; TRACE_LOG logHeader;
INIT_API();
//
// Skip leading blanks.
//
while( *lpArgumentString == ' ' || *lpArgumentString == '\t' ) { lpArgumentString++; }
if( *lpArgumentString == '\0' ) { PrintUsage( "resetref" ); return; }
refLogAddress = GetExpression( lpArgumentString );
if( refLogAddress == 0 ) {
dprintf( "inetdbg.resetref: cannot evaluate \"%s\"\n", lpArgumentString );
return;
}
//
// Read the log header, perform some sanity checks.
//
if( !ReadMemory( refLogAddress, &logHeader, sizeof(logHeader), NULL ) ) {
dprintf( "inetdbg.resetref: cannot read memory @ %p\n", refLogAddress );
return;
}
dprintf( "inetdbg.resetref: log @ %p:\n" " Signature = %08lx (%s)\n" " LogSize = %lu\n" " NextEntry = %lu\n" " EntrySize = %lu\n" " LogBuffer = %08lp\n", (PVOID) refLogAddress, logHeader.Signature, logHeader.Signature == TRACE_LOG_SIGNATURE ? "OK" : logHeader.Signature == TRACE_LOG_SIGNATURE_X ? "FREED" : "INVALID", logHeader.LogSize, logHeader.NextEntry, logHeader.EntrySize, logHeader.LogBuffer );
if( logHeader.LogBuffer > ( (PUCHAR)refLogAddress + sizeof(logHeader) ) ) { dprintf( " Extra Data @ %08p\n", (PVOID) (refLogAddress + sizeof(logHeader)) ); }
if( logHeader.Signature != TRACE_LOG_SIGNATURE && logHeader.Signature != TRACE_LOG_SIGNATURE_X ) {
dprintf( "inetdbg.resetref: log @ %p has invalid signature %08lx:\n", (PVOID) refLogAddress, logHeader.Signature );
return;
}
if( logHeader.EntrySize != sizeof(REF_TRACE_LOG_ENTRY) ) {
dprintf( "inetdbg.resetref: log @ %p is not a ref count log\n", (PVOID) refLogAddress );
return;
}
//
// Reset it.
//
logHeader.NextEntry = -1;
if( !WriteMemory( refLogAddress, &logHeader, sizeof(logHeader), NULL ) ) {
dprintf( "inetdbg.resetref: cannot write memory @ %p\n", (PVOID) refLogAddress );
return;
}
dprintf( "inetdbg.resetref: log @ %p reset\n", (PVOID) refLogAddress );
} // DECLARE_API( resetref )
|