669 lines
14 KiB
C++
669 lines
14 KiB
C++
|
/*++
|
|||
|
|
|||
|
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 )
|