windows-nt/Source/XPSP1/NT/inetsrv/iis/iisrearc/ul/ulkd/ownref.c
2020-09-26 16:20:57 +08:00

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