windows-nt/Source/XPSP1/NT/inetsrv/iis/svcs/dbgext/ref.cxx

669 lines
14 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
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 )