|
|
/*++
Copyright (c) 2001-2001 Microsoft Corporation
Module Name:
ownref.c
Abstract:
Implements the ownref command.
Author:
George V. Reilly (GeorgeRe) 23-Jan-2001
Environment:
User Mode.
Revision History:
--*/
#include "precomp.h"
typedef struct _REF_OWNER_GLOBAL_CALLBACK_CONTEXT { ULONG Signature; LONG Index; BOOLEAN Verbose; PSTR Prefix; } REF_OWNER_GLOBAL_CALLBACK_CONTEXT, *PREF_OWNER_GLOBAL_CALLBACK_CONTEXT;
#define REF_OWNER_GLOBAL_CALLBACK_CONTEXT_SIGNATURE ((ULONG) 'xGOR')
BOOLEAN DumpOwnerRefTraceLog( IN PLIST_ENTRY RemoteListEntry, IN PVOID Context ) { ULONG_PTR address; ULONG result; OWNER_REF_TRACELOG logHeader; PREF_OWNER_GLOBAL_CALLBACK_CONTEXT pCtxt = (PREF_OWNER_GLOBAL_CALLBACK_CONTEXT) Context;
ASSERT(pCtxt->Signature == REF_OWNER_GLOBAL_CALLBACK_CONTEXT_SIGNATURE);
address = (ULONG_PTR) CONTAINING_RECORD( RemoteListEntry, OWNER_REF_TRACELOG, OwnerHeader.GlobalListEntry );
if (!ReadMemory( address, &logHeader, sizeof(logHeader), &result )) { return FALSE; }
dprintf("OWNER_REF_TRACELOG[%d] @ %p\n", ++pCtxt->Index, address);
return TRUE; } // DumpOwnerRefTraceLog
#if 0
VOID DumpOwnerRefTraceLogGlobalList( IN BOOLEAN Verbose ) { REF_OWNER_GLOBAL_CALLBACK_CONTEXT Context;
Context.Signature = REF_OWNER_GLOBAL_CALLBACK_CONTEXT_SIGNATURE ; Context.Verbose = Verbose; Context.Prefix = ""; Context.Index = 0; "&http!g_OwnerRefTraceLogGlobalListHead" dprintf( "\n" " OWNER_REF_TRACELOG @ %p: %d owners\n", RemoteAddress, plogHeader->OwnerHeader.OwnersCount ); EnumLinkedList( (PLIST_ENTRY)REMOTE_OFFSET( RemoteAddress, OWNER_REF_TRACELOG, OwnerHeader.ListHead ), &DumpOwnerRefTraceLogOwnerCallback, &Context ); } // DumpOwnerRefTraceLogGlobalList
#endif
typedef struct _REF_OWNER_CALLBACK_CONTEXT { ULONG Signature; LONG Index; BOOLEAN Verbose; PSTR Prefix; LONG TotalRefs; } REF_OWNER_CALLBACK_CONTEXT, *PREF_OWNER_CALLBACK_CONTEXT;
#define REF_OWNER_CALLBACK_CONTEXT_SIGNATURE ((ULONG) 'xCOR')
BOOLEAN DumpOwnerRefTraceLogOwner( IN ULONG_PTR address, IN PREF_OWNER_CALLBACK_CONTEXT pCtxt ) { ULONG result; REF_OWNER RefOwner; LONG index; ULONG index2;
ASSERT(pCtxt->Signature == REF_OWNER_CALLBACK_CONTEXT_SIGNATURE);
if (!ReadMemory( address, &RefOwner, sizeof(RefOwner), &result )) { return FALSE; }
if (RefOwner.Signature != OWNER_REF_SIGNATURE) { dprintf( "Invalid REF_OWNER @ %p: signature = '%c%c%c%c'\n", address, DECODE_SIGNATURE(RefOwner.Signature) );
return FALSE; }
pCtxt->TotalRefs += RefOwner.RelativeRefCount;
dprintf( "%s\tREF_OWNER[%3d] @ %p:" " pOwner=%p '%c%c%c%c'," " RelativeRefCount=%d," " OwnedNextEntry=%d.\n" , pCtxt->Verbose ? "\n" : "", pCtxt->Index++, address, RefOwner.pOwner, DECODE_SIGNATURE(RefOwner.OwnerSignature), RefOwner.RelativeRefCount, RefOwner.OwnedNextEntry );
if (RefOwner.OwnedNextEntry == -1 || !pCtxt->Verbose) return TRUE;
index = max( 0, (RefOwner.OwnedNextEntry + 1) - OWNED_REF_NUM_ENTRIES ); index2 = index % OWNED_REF_NUM_ENTRIES;
for ( ; index <= RefOwner.OwnedNextEntry; index++, index2++ ) { if (CheckControlC()) { break; }
if (index2 >= OWNED_REF_NUM_ENTRIES) index2 = 0;
dprintf( "\t\t%8ld: RefIndex=%6I64d, MonotonicId=%ld, Act=%s\n", index, RefOwner.RecentEntries[index2].RefIndex, RefOwner.RecentEntries[index2].MonotonicId, Action2Name(RefOwner.RecentEntries[index2].Action) ); }
return TRUE; } // DumpOwnerRefTraceLogOwner
BOOLEAN DumpOwnerRefTraceLogOwnerCallback( IN PLIST_ENTRY RemoteListEntry, IN PVOID Context ) { ULONG_PTR address = (ULONG_PTR) CONTAINING_RECORD( RemoteListEntry, REF_OWNER, ListEntry ); PREF_OWNER_CALLBACK_CONTEXT pCtxt = (PREF_OWNER_CALLBACK_CONTEXT) Context;
return DumpOwnerRefTraceLogOwner(address, pCtxt); } // DumpOwnerRefTraceLogOwnerCallback
VOID DumpOwnerRefTraceLogOwnersList( IN POWNER_REF_TRACELOG plogHeader, IN ULONG_PTR RemoteAddress, IN BOOLEAN Verbose ) { REF_OWNER_CALLBACK_CONTEXT Context;
Context.Signature = REF_OWNER_CALLBACK_CONTEXT_SIGNATURE ; Context.Verbose = Verbose; Context.Prefix = ""; Context.Index = 0; Context.TotalRefs = 0;
dprintf( "\n" " OWNER_REF_TRACELOG @ %p: %d owners\n", RemoteAddress, plogHeader->OwnerHeader.OwnersCount ); EnumLinkedList( (PLIST_ENTRY) REMOTE_OFFSET( RemoteAddress, OWNER_REF_TRACELOG, OwnerHeader.ListHead ), &DumpOwnerRefTraceLogOwnerCallback, &Context );
dprintf("\nTotal RefCount = %d\n\n", Context.TotalRefs); } // DumpOwnerRefTraceLogOwnersList
VOID DumpOwnerRefTraceLogData( IN POWNER_REF_TRACELOG plogHeader, IN ULONG_PTR RemoteAddress, IN BOOLEAN Verbose, IN ULONG_PTR context ) { OWNER_REF_TRACE_LOG_ENTRY logEntry; ULONG_PTR entryAddress; CHAR filePath[MAX_PATH]; PSTR fileName; PVOID pPrevFilePath; CHAR symbol1[MAX_SYMBOL_LENGTH]; CHAR symbol2[MAX_SYMBOL_LENGTH]; ULONG result; ULONG Dumped = 0; ULONG NonMatch = 0; ULONG NumToDump = plogHeader->TraceLog.LogSize;
LONGLONG index = max( 0, ((plogHeader->TraceLog.NextEntry + 1) - NumToDump) );
ULONGLONG index2 = index % plogHeader->TraceLog.LogSize; ULONGLONG index1000 = index % 1000;
entryAddress = (ULONG_PTR) plogHeader->TraceLog.pLogBuffer + (ULONG_PTR)( index2 * sizeof(logEntry) );
pPrevFilePath = NULL; *filePath = '\0';
//
// Dump the log.
//
dprintf( "\n" " OWNER_REF_TRACELOG @ %p: dumping entries[%I64d-%I64d]", RemoteAddress, index, plogHeader->TraceLog.NextEntry );
if (context != 0) dprintf(", filtering on owner=%p", context); dprintf("\n");
for ( ; index <= plogHeader->TraceLog.NextEntry; index++, index2++, index1000++, entryAddress += sizeof(logEntry) ) { if (CheckControlC()) { break; }
if (index2 >= (ULONG)(plogHeader->TraceLog.LogSize)) { index2 = 0; entryAddress = (ULONG_PTR) plogHeader->TraceLog.pLogBuffer; }
if (index1000 >= 1000) index1000 = 0;
if (!ReadMemory( entryAddress, &logEntry, sizeof(logEntry), NULL )) { dprintf( "ownref: cannot read memory @ %p\n", entryAddress ); return; }
if (context == 0 || context == (ULONG_PTR)logEntry.pOwner) { 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: Own=%p Act=%2lu %-30s Ref=%4d Src=%s:%lu\n", (NonMatch > 0) ? "\n" : "", index, logEntry.pOwner, (ULONG)logEntry.Action, Action2Name(logEntry.Action), logEntry.NewRefCount, fileName, (ULONG)logEntry.LineNumber );
++Dumped; NonMatch = 0; } else { if (index1000 == 0) dprintf("%d", index); if ((++NonMatch & 127) == 127) dprintf("."); } }
if (context != 0) dprintf("%d entries dumped\n\n", Dumped);
} // DumpOwnerRefTraceLogData
//
// Public functions.
//
DECLARE_API( ownref )
/*++
Routine Description:
Dumps the owner reference trace log at the specified address.
Arguments:
None.
Return Value:
None.
--*/
{ ULONG_PTR address = 0; ULONG_PTR context = 0; ULONG64 address64 = 0, context64 = 0; ULONG result; OWNER_REF_TRACELOG logHeader; CHAR strSignature[MAX_SIGNATURE_LENGTH]; BOOLEAN ListGlobal = FALSE; // CODEWORK
BOOLEAN ListAllOwners = FALSE; BOOLEAN ListOneOwner = FALSE; BOOLEAN ListRefs = FALSE; BOOLEAN Verbose = FALSE;
SNAPSHOT_EXTENSION_DATA();
// Parse any leading flags
while (*args == ' ' || *args == '\t') { args++; }
if (*args == '-') { args++;
switch (*args) { case 'g' : ListGlobal = TRUE; args++; break;
case 'O' : ListAllOwners = TRUE; args++; break;
case 'o' : ListOneOwner = TRUE; args++; break;
case 'r' : ListRefs = TRUE; args++; break;
case 'v' : Verbose = TRUE; args++; break;
default : PrintUsage( "ownref" ); return; } }
while (*args == ' ' || *args == '\t') { args++; }
//
// Snag the address and optional context from the command line.
//
if (! GetExpressionEx(args, &address64, &args)) { PrintUsage( "ownref" ); return; }
GetExpressionEx(args, &context64, &args);
address = (ULONG_PTR) address64; context = (ULONG_PTR) context64;
//
// Read the log header.
//
if (!ReadMemory( address, &logHeader, sizeof(logHeader), &result )) { dprintf( "ownref: cannot read OWNER_REF_TRACELOG @ %p\n", address ); return; }
if (ListGlobal) { dprintf("Sorry, -g option not yet implemented.\n" "Use: dl http!g_OwnerRefTraceLogGlobalListHead\n"); }
if (ListOneOwner) { REF_OWNER_CALLBACK_CONTEXT Context;
Context.Signature = REF_OWNER_CALLBACK_CONTEXT_SIGNATURE ; Context.Verbose = TRUE; Context.Prefix = ""; Context.Index = -1; Context.TotalRefs = 0;
DumpOwnerRefTraceLogOwner(address, &Context);
return; }
dprintf( "ownref: log @ %p\n" " Signature = %08lx '%c%c%c%c' (%s)\n" " TypeSignature = %08lx (%s)\n" " LogSize = %lu\n" " NextEntry = %I64d\n" " EntrySize = %lu\n" " LogBuffer = %p\n" " OwnersCount = %d\n" " MonotonicId = %d\n", address, logHeader.TraceLog.Signature, DECODE_SIGNATURE(logHeader.TraceLog.Signature), logHeader.TraceLog.Signature == TRACE_LOG_SIGNATURE ? "OK" : logHeader.TraceLog.Signature == TRACE_LOG_SIGNATURE_X ? "FREED" : "INVALID", logHeader.TraceLog.TypeSignature, SignatureToString( logHeader.TraceLog.TypeSignature, OWNER_REF_TRACELOG_SIGNATURE, 0, strSignature ), logHeader.TraceLog.LogSize, logHeader.TraceLog.NextEntry, logHeader.TraceLog.EntrySize, logHeader.TraceLog.pLogBuffer, logHeader.OwnerHeader.OwnersCount, logHeader.OwnerHeader.MonotonicId );
if (logHeader.TraceLog.pLogBuffer > ( (PUCHAR)address + sizeof(logHeader))) { dprintf( " ExtraData @ %p\n", address + sizeof(logHeader) ); }
if (logHeader.TraceLog.TypeSignature != OWNER_REF_TRACELOG_SIGNATURE) { dprintf( "ownref: log @ %p has invalid signature %08lx, '%c%c%c%c':\n", address, logHeader.TraceLog.TypeSignature, DECODE_SIGNATURE(logHeader.TraceLog.TypeSignature) ); return; }
if (logHeader.TraceLog.EntrySize != sizeof(OWNER_REF_TRACE_LOG_ENTRY) || logHeader.TraceLog.TypeSignature != OWNER_REF_TRACELOG_SIGNATURE) { dprintf( "ownref: log @ %p is not an owner ref count log\n", address ); return; }
if (logHeader.TraceLog.NextEntry == -1) { dprintf( "ownref: empty log @ %p\n", address ); return; }
if (Verbose || ListAllOwners) DumpOwnerRefTraceLogOwnersList(&logHeader, address, Verbose);
if (Verbose || ListRefs) DumpOwnerRefTraceLogData(&logHeader, address, Verbose, context);
} // ownref
|