448 lines
9.5 KiB
C
448 lines
9.5 KiB
C
/*++
|
|
|
|
Copyright (c) 1998-2001 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
ref.c
|
|
|
|
Abstract:
|
|
|
|
Implements the ref command.
|
|
|
|
Author:
|
|
|
|
Keith Moore (keithmo) 17-Jun-1998
|
|
|
|
Environment:
|
|
|
|
User Mode.
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
|
|
#include "precomp.h"
|
|
|
|
#undef BEGIN_REF_ACTION
|
|
#undef END_REF_ACTION
|
|
#undef REF_ACTION
|
|
|
|
#define BEGIN_REF_ACTION() NAMED_REFTRACE_ACTION g_RefTraceActions[] = {
|
|
#define END_REF_ACTION() };
|
|
#define REF_ACTION(x) { REF_ACTION_##x, #x },
|
|
|
|
#include "..\drv\refaction.h"
|
|
|
|
#define NUM_REFTRACE_ACTIONS \
|
|
(sizeof(g_RefTraceActions) / sizeof(g_RefTraceActions[0]))
|
|
|
|
|
|
const CHAR*
|
|
Action2Name(
|
|
ULONG Action)
|
|
{
|
|
if (Action < NUM_REFTRACE_ACTIONS)
|
|
{
|
|
ASSERT(g_RefTraceActions[Action].Action == Action);
|
|
return g_RefTraceActions[Action].Name;
|
|
}
|
|
else
|
|
return "????";
|
|
}
|
|
|
|
typedef
|
|
BOOLEAN
|
|
(*FN_MATCH_CONTEXT)(
|
|
IN ULONG_PTR context,
|
|
IN PREF_TRACE_LOG_ENTRY plogEntry
|
|
);
|
|
|
|
BOOLEAN
|
|
RefMatchContext(
|
|
IN ULONG_PTR context,
|
|
IN PREF_TRACE_LOG_ENTRY plogEntry)
|
|
{
|
|
return (context == 0 || context == (ULONG_PTR) plogEntry->pContext);
|
|
}
|
|
|
|
BOOLEAN
|
|
ThreadMatchContext(
|
|
IN ULONG_PTR context,
|
|
IN PREF_TRACE_LOG_ENTRY plogEntry)
|
|
{
|
|
return (context == 0 || context == (ULONG_PTR) plogEntry->pThread);
|
|
}
|
|
|
|
|
|
// Do all the real
|
|
VOID
|
|
DumpRefTrace(
|
|
PCSTR args,
|
|
FN_MATCH_CONTEXT pfnMatchContext,
|
|
PCSTR cmd)
|
|
{
|
|
ULONG_PTR address = 0;
|
|
ULONG_PTR context = 0;
|
|
ULONG_PTR flags = 0;
|
|
ULONG_PTR entryAddress;
|
|
ULONG result;
|
|
TRACE_LOG logHeader;
|
|
REF_TRACE_LOG_ENTRY logEntry;
|
|
PSTR fileName;
|
|
LONGLONG index;
|
|
ULONGLONG index2;
|
|
ULONGLONG index1000;
|
|
ULONG_PTR offset1;
|
|
ULONG_PTR offset2;
|
|
CHAR filePath[MAX_PATH];
|
|
PVOID pPrevFilePath;
|
|
CHAR symbol1[MAX_SYMBOL_LENGTH];
|
|
CHAR symbol2[MAX_SYMBOL_LENGTH];
|
|
ULONG Dumped = 0;
|
|
ULONG NonMatch = 0;
|
|
ULONG64 address64 = 0;
|
|
ULONG64 context64 = 0;
|
|
ULONG64 flags64 = 0;
|
|
ULONG NumToDump = 0;
|
|
|
|
while (*args == ' ' || *args == '\t')
|
|
{
|
|
args++;
|
|
}
|
|
|
|
if (*args == '-')
|
|
{
|
|
args++;
|
|
|
|
switch (*args)
|
|
{
|
|
case 'l' :
|
|
for (index = 0; index < NUM_REFTRACE_ACTIONS; ++index)
|
|
{
|
|
dprintf(
|
|
"%4u: REF_ACTION_%s\n",
|
|
g_RefTraceActions[index].Action,
|
|
g_RefTraceActions[index].Name);
|
|
}
|
|
return;
|
|
|
|
default :
|
|
PrintUsage( cmd );
|
|
return;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Snag the address and optional context and flags from the command line.
|
|
//
|
|
|
|
if (! GetExpressionEx(args, &address64, &args))
|
|
{
|
|
PrintUsage( cmd );
|
|
return;
|
|
}
|
|
|
|
if (GetExpressionEx(args, &context64, &args))
|
|
GetExpressionEx(args, &flags64, &args);
|
|
|
|
address = (ULONG_PTR) address64;
|
|
context = (ULONG_PTR) context64;
|
|
flags = (ULONG_PTR) flags64;
|
|
|
|
//
|
|
// Read the log header.
|
|
//
|
|
|
|
if (!ReadMemory(
|
|
address,
|
|
&logHeader,
|
|
sizeof(logHeader),
|
|
&result
|
|
))
|
|
{
|
|
dprintf(
|
|
"%s: cannot read TRACE_LOG @ %p\n",
|
|
cmd,
|
|
address
|
|
);
|
|
return;
|
|
}
|
|
|
|
dprintf(
|
|
"%s: log @ %p\n"
|
|
" Signature = %08lx '%c%c%c%c' (%s)\n"
|
|
" TypeSignature = %08lx '%c%c%c%c'\n"
|
|
" LogSize = %lu\n"
|
|
" NextEntry = %I64d\n"
|
|
" EntrySize = %lu\n"
|
|
" LogBuffer = %p\n",
|
|
cmd,
|
|
address,
|
|
logHeader.Signature,
|
|
DECODE_SIGNATURE(logHeader.Signature),
|
|
logHeader.Signature == TRACE_LOG_SIGNATURE
|
|
? "OK"
|
|
: logHeader.Signature == TRACE_LOG_SIGNATURE_X
|
|
? "FREED"
|
|
: "INVALID",
|
|
logHeader.TypeSignature,
|
|
DECODE_SIGNATURE(logHeader.TypeSignature),
|
|
logHeader.LogSize,
|
|
logHeader.NextEntry,
|
|
logHeader.EntrySize,
|
|
logHeader.pLogBuffer
|
|
);
|
|
|
|
if (logHeader.pLogBuffer > ( (PUCHAR)address + sizeof(logHeader) ))
|
|
{
|
|
dprintf(
|
|
" ExtraData @ %p\n",
|
|
address + sizeof(logHeader)
|
|
);
|
|
}
|
|
|
|
if (logHeader.Signature != TRACE_LOG_SIGNATURE &&
|
|
logHeader.Signature != TRACE_LOG_SIGNATURE_X)
|
|
{
|
|
dprintf(
|
|
"%s: log @ %p has invalid signature %08lx:\n",
|
|
cmd,
|
|
address,
|
|
logHeader.Signature
|
|
);
|
|
return;
|
|
}
|
|
|
|
if (logHeader.EntrySize != sizeof(logEntry)
|
|
|| logHeader.TypeSignature != REF_TRACELOG_SIGNATURE
|
|
)
|
|
{
|
|
dprintf(
|
|
"%s: log @ %p is not a ref count log\n",
|
|
cmd,
|
|
address
|
|
);
|
|
return;
|
|
}
|
|
|
|
if (logHeader.NextEntry == -1)
|
|
{
|
|
dprintf(
|
|
"%s: empty log @ %p\n",
|
|
cmd,
|
|
address
|
|
);
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Calculate the log size to dump.
|
|
//
|
|
|
|
NumToDump = logHeader.LogSize;
|
|
|
|
index = max( 0, (logHeader.NextEntry + 1) - NumToDump );
|
|
index2 = index % logHeader.LogSize;
|
|
index1000 = index % 1000;
|
|
|
|
pPrevFilePath = NULL;
|
|
*filePath = '\0';
|
|
|
|
entryAddress = (ULONG_PTR) logHeader.pLogBuffer +
|
|
(ULONG_PTR)( index2 * sizeof(logEntry) );
|
|
|
|
//
|
|
// Dump the log.
|
|
//
|
|
|
|
for ( ;
|
|
index <= logHeader.NextEntry;
|
|
index++,
|
|
index2++,
|
|
index1000++,
|
|
entryAddress += sizeof(logEntry)
|
|
)
|
|
{
|
|
if (CheckControlC())
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (index2 >= (ULONG)(logHeader.LogSize))
|
|
{
|
|
index2 = 0;
|
|
entryAddress = (ULONG_PTR) logHeader.pLogBuffer;
|
|
}
|
|
|
|
if (index1000 >= 1000)
|
|
index1000 = 0;
|
|
|
|
if (!ReadMemory(
|
|
entryAddress,
|
|
&logEntry,
|
|
sizeof(logEntry),
|
|
NULL
|
|
))
|
|
{
|
|
dprintf(
|
|
"%s: cannot read memory @ %p\n",
|
|
cmd,
|
|
entryAddress
|
|
);
|
|
return;
|
|
}
|
|
|
|
if ((*pfnMatchContext)(context, &logEntry))
|
|
{
|
|
if (logEntry.pFileName != pPrevFilePath)
|
|
{
|
|
if (ReadMemory(
|
|
(ULONG_PTR)logEntry.pFileName,
|
|
filePath,
|
|
sizeof(filePath),
|
|
&result
|
|
))
|
|
{
|
|
fileName = strrchr( filePath, '\\' );
|
|
|
|
if (fileName != NULL)
|
|
{
|
|
fileName++;
|
|
}
|
|
else
|
|
{
|
|
fileName = filePath;
|
|
}
|
|
|
|
pPrevFilePath = logEntry.pFileName;
|
|
}
|
|
else
|
|
{
|
|
sprintf(
|
|
filePath,
|
|
"%p",
|
|
logEntry.pFileName
|
|
);
|
|
|
|
fileName = filePath;
|
|
}
|
|
}
|
|
|
|
dprintf(
|
|
"%s%4I64d: CPU=%lu Ctx=%p Act=%2lu %-30s Ref=%4d Src=%s:%lu\n",
|
|
(NonMatch > 0) ? "\n" : "",
|
|
index,
|
|
(ULONG)logEntry.Processor,
|
|
logEntry.pContext,
|
|
(ULONG)logEntry.Action,
|
|
Action2Name(logEntry.Action),
|
|
logEntry.NewRefCount,
|
|
fileName,
|
|
(ULONG)logEntry.LineNumber
|
|
);
|
|
|
|
if (flags & 1)
|
|
{
|
|
GetSymbol(
|
|
logEntry.pCaller,
|
|
symbol1,
|
|
&offset1
|
|
);
|
|
|
|
GetSymbol(
|
|
logEntry.pCallersCaller,
|
|
symbol2,
|
|
&offset2
|
|
);
|
|
|
|
dprintf(
|
|
" Process=%p Thread=%p\n"
|
|
" Caller1=%p (%s+0x%p)\n"
|
|
" Caller2=%p (%s+0x%p)\n",
|
|
logEntry.pProcess,
|
|
logEntry.pThread,
|
|
logEntry.pCaller,
|
|
symbol1,
|
|
offset1,
|
|
logEntry.pCallersCaller,
|
|
symbol2,
|
|
offset2
|
|
);
|
|
}
|
|
|
|
++Dumped;
|
|
NonMatch = 0;
|
|
}
|
|
else
|
|
{
|
|
if (index1000 == 0)
|
|
dprintf("%I64d", index);
|
|
|
|
if ((++NonMatch & 127) == 127)
|
|
dprintf(".");
|
|
}
|
|
}
|
|
|
|
if (context != 0)
|
|
dprintf("%d entries dumped\n\n", Dumped);
|
|
|
|
} // DumpRefTrace
|
|
|
|
|
|
|
|
//
|
|
// Public functions.
|
|
//
|
|
|
|
DECLARE_API( ref )
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Dumps the reference trace log at the specified address.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
SNAPSHOT_EXTENSION_DATA();
|
|
|
|
DumpRefTrace(args, RefMatchContext, "ref");
|
|
} // ref
|
|
|
|
|
|
DECLARE_API( tref )
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Dumps the trace log at the specified address.
|
|
Filtering done by thread instead of context.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
SNAPSHOT_EXTENSION_DATA();
|
|
|
|
DumpRefTrace(args, ThreadMatchContext, "tref");
|
|
} // ref
|
|
|