246 lines
5.9 KiB
C
246 lines
5.9 KiB
C
|
/*++
|
||
|
|
||
|
Copyright (c) 1994 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
calldata.c
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
WinDbg Extension Api
|
||
|
|
||
|
Author:
|
||
|
|
||
|
David N. Cutler (davec) 22-May-1994
|
||
|
|
||
|
Environment:
|
||
|
|
||
|
User Mode.
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
--*/
|
||
|
|
||
|
#include "precomp.h"
|
||
|
#pragma hdrstop
|
||
|
|
||
|
|
||
|
typedef struct CALL_HASH_READ {
|
||
|
ULONG64 CallersAddress;
|
||
|
ULONG64 CallersCaller;
|
||
|
ULONG CallCount;
|
||
|
} CALL_HASH_READ, *PCALL_HASH_READ;
|
||
|
|
||
|
|
||
|
int __cdecl
|
||
|
HashCompare(
|
||
|
const void * Element1,
|
||
|
const void * Element2
|
||
|
);
|
||
|
|
||
|
DECLARE_API( calldata )
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Dump call data hash table
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
arg - name-of-hash-table
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
None
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
UCHAR Buffer[256];
|
||
|
ULONG64 Displacement=0;
|
||
|
ULONG64 End=0;
|
||
|
ULONG Index;
|
||
|
ULONG64 CallData;
|
||
|
ULONG64 Next;
|
||
|
ULONG Result;
|
||
|
UCHAR TableName[80];
|
||
|
PCALL_HASH_READ CallerArray;
|
||
|
ULONG NumberCallers = 0;
|
||
|
ULONG ArraySize = 1000;
|
||
|
ULONG64 HashTable_Flink;
|
||
|
|
||
|
//
|
||
|
// If a table name was not specified, then don't attempt to dump the
|
||
|
// table.
|
||
|
//
|
||
|
|
||
|
if (args[0] == '\0') {
|
||
|
dprintf("A call data table name must be specified\n");
|
||
|
return E_INVALIDARG;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Get the address of the specified call performance data and read the
|
||
|
// contents of the structure.
|
||
|
//
|
||
|
|
||
|
strcpy(&TableName[0], args);
|
||
|
dprintf("**** Dump Call Performance Data For %s ****\n\n", &TableName[0]);
|
||
|
CallData = GetExpression(&TableName[0]);
|
||
|
if ((CallData == 0) ||
|
||
|
(GetFieldValue(CallData, "_CALL_PERFORMANCE_DATA", "HashTable.Flink", HashTable_Flink)
|
||
|
!= FALSE)) {
|
||
|
|
||
|
//
|
||
|
// The target build does not support specified call performance data.
|
||
|
//
|
||
|
|
||
|
dprintf("%08p: No call performance data available\n", CallData);
|
||
|
|
||
|
} else {
|
||
|
ULONG HashTableOffset;
|
||
|
|
||
|
GetFieldOffset("_CALL_PERFORMANCE_DATA", "HashTable", &HashTableOffset);
|
||
|
|
||
|
//
|
||
|
// Dump the specified call data.
|
||
|
//
|
||
|
CallerArray = LocalAlloc(LMEM_FIXED, sizeof(CALL_HASH_READ) * ArraySize);
|
||
|
if (CallerArray==NULL) {
|
||
|
dprintf("Couldn't allocate memory for caller array\n");
|
||
|
return E_INVALIDARG;
|
||
|
}
|
||
|
|
||
|
dprintf("Loading data");
|
||
|
for (Index = 0; Index < CALL_HASH_TABLE_SIZE; Index += 1) {
|
||
|
UCHAR CallHash[] = "_CALL_HASH_ENTRY";
|
||
|
|
||
|
End = HashTableOffset + CallData + GetTypeSize("_LIST_ENTRY") * Index;
|
||
|
|
||
|
GetFieldValue(End, "_LIST_ENTRY", "Flink", Next);
|
||
|
|
||
|
while (Next != End) {
|
||
|
if (!GetFieldValue(Next, CallHash, "CallersCaller", CallerArray[NumberCallers].CallersCaller) &&
|
||
|
!GetFieldValue(Next, CallHash, "CallersAddress", CallerArray[NumberCallers].CallersAddress) &&
|
||
|
!GetFieldValue(Next, CallHash, "CallCount", CallerArray[NumberCallers].CallCount)) {
|
||
|
|
||
|
NumberCallers++;
|
||
|
|
||
|
if (NumberCallers == ArraySize) {
|
||
|
|
||
|
//
|
||
|
// Grow the caller array
|
||
|
//
|
||
|
PCALL_HASH_READ NewArray;
|
||
|
|
||
|
ArraySize = ArraySize * 2;
|
||
|
NewArray = LocalAlloc(LMEM_FIXED, sizeof(CALL_HASH_READ) * ArraySize);
|
||
|
if (NewArray == NULL) {
|
||
|
dprintf("Couldn't allocate memory to extend caller array\n");
|
||
|
LocalFree(CallerArray);
|
||
|
return E_INVALIDARG;
|
||
|
}
|
||
|
CopyMemory(NewArray, CallerArray, sizeof(CALL_HASH_READ) * NumberCallers);
|
||
|
LocalFree(CallerArray);
|
||
|
CallerArray = NewArray;
|
||
|
}
|
||
|
|
||
|
if ((NumberCallers % 10) == 0) {
|
||
|
dprintf(".");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
GetFieldValue(Next, CallHash, "ListEntry.Flink", Next);
|
||
|
if (CheckControlC()) {
|
||
|
LocalFree(CallerArray);
|
||
|
return E_INVALIDARG;
|
||
|
}
|
||
|
}
|
||
|
if (CheckControlC()) {
|
||
|
return E_INVALIDARG;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
qsort((PVOID)CallerArray,
|
||
|
NumberCallers,
|
||
|
sizeof(CALL_HASH_READ),
|
||
|
HashCompare);
|
||
|
|
||
|
dprintf("\n Number Caller/Caller's Caller\n\n");
|
||
|
|
||
|
for (Index = 0; Index < NumberCallers; Index++) {
|
||
|
GetSymbol(CallerArray[Index].CallersAddress,
|
||
|
Buffer,
|
||
|
&Displacement);
|
||
|
|
||
|
dprintf("%10d %s", CallerArray[Index].CallCount, Buffer);
|
||
|
if (Displacement != 0) {
|
||
|
dprintf("+0x%1p", Displacement);
|
||
|
}
|
||
|
|
||
|
if (CallerArray[Index].CallersCaller != 0) {
|
||
|
dprintf("\n");
|
||
|
GetSymbol(CallerArray[Index].CallersCaller,
|
||
|
Buffer,
|
||
|
&Displacement);
|
||
|
|
||
|
dprintf(" %s", Buffer);
|
||
|
if (Displacement != 0) {
|
||
|
dprintf("+0x%1p", Displacement);
|
||
|
}
|
||
|
}
|
||
|
dprintf("\n");
|
||
|
if (CheckControlC()) {
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
LocalFree(CallerArray);
|
||
|
}
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
int __cdecl
|
||
|
HashCompare(
|
||
|
const void * Element1,
|
||
|
const void * Element2
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Provides a comparison of hash elements for the qsort library function
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Element1 - Supplies pointer to the key for the search
|
||
|
|
||
|
Element2 - Supplies element to be compared to the key
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
> 0 - Element1 < Element2
|
||
|
= 0 - Element1 == Element2
|
||
|
< 0 - Element1 > Element2
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
PCALL_HASH_READ Hash1 = (PCALL_HASH_READ)Element1;
|
||
|
PCALL_HASH_READ Hash2 = (PCALL_HASH_READ)Element2;
|
||
|
|
||
|
if (Hash1->CallCount < Hash2->CallCount) {
|
||
|
return(1);
|
||
|
}
|
||
|
else if (Hash1->CallCount > Hash2->CallCount) {
|
||
|
return(-1);
|
||
|
} else {
|
||
|
return(0);
|
||
|
}
|
||
|
|
||
|
}
|