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