975 lines
22 KiB
C++
975 lines
22 KiB
C++
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// diagdump.cpp - Extension using the enumeration support for diagnosis
|
||
|
// to dump the content of the tracing
|
||
|
//
|
||
|
// Copyright Microsoft Corporation. All rights reserved.
|
||
|
//
|
||
|
|
||
|
#include "singx86.h"
|
||
|
#include "diagnose.h"
|
||
|
|
||
|
bool DumpAllEvents = FALSE;
|
||
|
bool DumpStackTraces = FALSE;
|
||
|
bool DumpDescriptions = FALSE;
|
||
|
|
||
|
//
|
||
|
// Simple transforms on fields
|
||
|
//
|
||
|
|
||
|
//
|
||
|
// Empty base class for common transform manipulation
|
||
|
//
|
||
|
|
||
|
class EntryTransform {
|
||
|
|
||
|
public:
|
||
|
virtual bool IsFieldHidden(EventTypeEntry * entryDescriptor, FieldEntry * fieldDescriptor)
|
||
|
{
|
||
|
|
||
|
// all fields are visilbe by default
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
virtual bool DoTransform(EventTypeEntry * entryDescriptor, FieldEntry * fieldDescriptor)
|
||
|
{
|
||
|
// no transform is applied on fields by default
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
virtual int GetFieldWidth(EventTypeEntry * entryDescriptor, FieldEntry * fieldDescriptor)
|
||
|
{
|
||
|
// no transform is applied on fields by default
|
||
|
return 0;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
class StringFormatTransform : public EntryTransform {
|
||
|
|
||
|
// Name of the field the transform will perform on
|
||
|
char * FieldName;
|
||
|
|
||
|
// the index of the first argument that will be used in string formatting
|
||
|
int ArgumentBaseIndex;
|
||
|
|
||
|
public:
|
||
|
|
||
|
StringFormatTransform(char * fieldName, int argumentBase)
|
||
|
{
|
||
|
FieldName = _strdup(fieldName);
|
||
|
ArgumentBaseIndex = argumentBase;
|
||
|
}
|
||
|
|
||
|
~StringFormatTransform()
|
||
|
{
|
||
|
if (FieldName != NULL) free(FieldName);
|
||
|
|
||
|
}
|
||
|
|
||
|
virtual int GetFieldWidth(EventTypeEntry * entryDescriptor, FieldEntry * fieldDescriptor)
|
||
|
{
|
||
|
if (_stricmp(FieldName, fieldDescriptor->Name) == 0) {
|
||
|
|
||
|
return 30; // this is dependent of format and arguments. Just pick a value common
|
||
|
// for current usages
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
virtual bool DoTransform(EventTypeEntry * entryDescriptor, FieldEntry * fieldDescriptor)
|
||
|
{
|
||
|
|
||
|
if (_stricmp(FieldName, fieldDescriptor->Name) == 0) {
|
||
|
|
||
|
ExtOut(" ");
|
||
|
entryDescriptor->Format(fieldDescriptor->ExtendedFieldIndex + 1, ArgumentBaseIndex);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
class SymbolLookupTransform : public EntryTransform {
|
||
|
|
||
|
// Name of the field the transform will perform on
|
||
|
char * FieldName;
|
||
|
|
||
|
public:
|
||
|
|
||
|
SymbolLookupTransform(char * fieldName)
|
||
|
{
|
||
|
FieldName = _strdup(fieldName);
|
||
|
}
|
||
|
|
||
|
~SymbolLookupTransform()
|
||
|
{
|
||
|
if (FieldName != NULL) free(FieldName);
|
||
|
}
|
||
|
|
||
|
virtual int GetFieldWidth(EventTypeEntry * entryDescriptor, FieldEntry * fieldDescriptor)
|
||
|
{
|
||
|
if (_stricmp(FieldName, fieldDescriptor->Name) == 0) {
|
||
|
|
||
|
return 70;
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
virtual bool DoTransform(EventTypeEntry * entryDescriptor, FieldEntry * fieldDescriptor)
|
||
|
{
|
||
|
|
||
|
if (_stricmp(FieldName, fieldDescriptor->Name) == 0) {
|
||
|
|
||
|
char symbol[512];
|
||
|
ULONG64 displacement = 0;
|
||
|
ULONG64 fieldValue = fieldDescriptor->GetFieldNumericValue();
|
||
|
|
||
|
HRESULT status = g_ExtSymbols->GetNameByOffset(fieldValue,
|
||
|
symbol,
|
||
|
arrayof(symbol),
|
||
|
NULL,
|
||
|
&displacement);
|
||
|
if (status == S_OK) {
|
||
|
|
||
|
ExtOut(" %-68s", symbol);
|
||
|
|
||
|
} else {
|
||
|
|
||
|
ExtOut(" %-68s", "");
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
class RestrictToFieldsTransform : public EntryTransform {
|
||
|
|
||
|
// The pattern containing the fields available for display
|
||
|
// in the format "F1|F2|F3"
|
||
|
|
||
|
char * AvailableFields;
|
||
|
|
||
|
public:
|
||
|
|
||
|
RestrictToFieldsTransform(char * fieldList)
|
||
|
{
|
||
|
AvailableFields = _strdup(fieldList);
|
||
|
}
|
||
|
|
||
|
~RestrictToFieldsTransform()
|
||
|
{
|
||
|
if (AvailableFields != NULL) free(AvailableFields);
|
||
|
|
||
|
}
|
||
|
|
||
|
virtual bool IsFieldHidden(EventTypeEntry * entryDescriptor, FieldEntry * fieldDescriptor)
|
||
|
{
|
||
|
if ((AvailableFields != NULL) && (strstr(AvailableFields, fieldDescriptor->Name) != NULL)) {
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
};
|
||
|
|
||
|
const int MaxTransformAllowed = 16;
|
||
|
|
||
|
EntryTransform * Transforms[MaxTransformAllowed];
|
||
|
int InUseTransforms = 0;
|
||
|
|
||
|
void FlushTransforms()
|
||
|
{
|
||
|
for (int i = 0; i < InUseTransforms; i++) {
|
||
|
|
||
|
delete Transforms[i];
|
||
|
Transforms[i] = NULL;
|
||
|
}
|
||
|
InUseTransforms = 0;
|
||
|
}
|
||
|
|
||
|
bool AddTransform(EntryTransform * transform)
|
||
|
{
|
||
|
if (InUseTransforms < MaxTransformAllowed) {
|
||
|
|
||
|
Transforms[InUseTransforms++] = transform;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
bool ApplyTransforms(EventTypeEntry * entryDescriptor, FieldEntry * fieldDescriptor)
|
||
|
{
|
||
|
for (int i = 0; i < InUseTransforms; i++) {
|
||
|
|
||
|
if (Transforms[i]->DoTransform(entryDescriptor, fieldDescriptor)) {
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
int GetTransformFieldWidth(EventTypeEntry * entryDescriptor, FieldEntry * fieldDescriptor)
|
||
|
{
|
||
|
int width = 0;
|
||
|
|
||
|
for (int i = 0; i < InUseTransforms; i++) {
|
||
|
|
||
|
int crtWidth = Transforms[i]->GetFieldWidth(entryDescriptor, fieldDescriptor);
|
||
|
|
||
|
if (width < crtWidth) {
|
||
|
|
||
|
width = crtWidth;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return width;
|
||
|
}
|
||
|
|
||
|
|
||
|
bool TestVisibility(EventTypeEntry * entryDescriptor, FieldEntry * fieldDescriptor)
|
||
|
{
|
||
|
for (int i = 0; i < InUseTransforms; i++) {
|
||
|
|
||
|
if (Transforms[i]->IsFieldHidden(entryDescriptor, fieldDescriptor)) {
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
void ParseStringFormatTransform(PCSTR & args)
|
||
|
{
|
||
|
char * str = ReadToken(args);
|
||
|
|
||
|
if (str != NULL) {
|
||
|
|
||
|
StringFormatTransform * tr = new StringFormatTransform(str, 3/*FIXME*/);
|
||
|
if (!AddTransform(tr)) delete tr;
|
||
|
free(str);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void ParseVisibleFields(PCSTR & args)
|
||
|
{
|
||
|
char * str = ReadToken(args);
|
||
|
|
||
|
if (str != NULL) {
|
||
|
|
||
|
RestrictToFieldsTransform * tr = new RestrictToFieldsTransform (str);
|
||
|
|
||
|
if (!AddTransform(tr)) delete tr;
|
||
|
free(str);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void ParseSymbolLookupTransform(PCSTR & args)
|
||
|
{
|
||
|
char * str = ReadToken(args);
|
||
|
|
||
|
if (str != NULL) {
|
||
|
|
||
|
SymbolLookupTransform * tr = new SymbolLookupTransform(str);
|
||
|
if (!AddTransform(tr)) delete tr;
|
||
|
free(str);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void WriteLine(int length)
|
||
|
{
|
||
|
while (length--) ExtOut("-");
|
||
|
}
|
||
|
|
||
|
|
||
|
void DumpStackTrace()
|
||
|
{
|
||
|
for (int i = 1; ; i++) {
|
||
|
|
||
|
UINT64 ipValue = GetStackTrace(i);
|
||
|
|
||
|
if (ipValue == 0) {
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
CHAR name[512];
|
||
|
|
||
|
if (g_ExtSymbols->GetNameByOffset(ipValue,
|
||
|
(PSTR)&name,
|
||
|
sizeof(name),
|
||
|
NULL, NULL) == S_OK) {
|
||
|
ExtOut(" %p %s\n", ipValue, name);
|
||
|
|
||
|
} else {
|
||
|
|
||
|
ExtOut(" %p {invalid symbol}\n", ipValue);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Implementation of DumpTracing methods
|
||
|
//
|
||
|
|
||
|
|
||
|
bool DumpTracing::TypeCallout(EventTypeEntry * entryDescriptor)
|
||
|
{
|
||
|
if (!EventingEnumerator::TypeCallout(entryDescriptor)) {
|
||
|
|
||
|
if (!EventingEnumerator::TypeCallout(SystemHeaderType)) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (LastItem != type) {
|
||
|
|
||
|
if (DumpSummary) ExtOut("Registered event types:\n");
|
||
|
LastItem = type;
|
||
|
}
|
||
|
|
||
|
if (DumpSummary) ExtOut(" %s: (Key=%p, FieldsCount=%ld) - %s\n",
|
||
|
entryDescriptor->Name,
|
||
|
(UINT64)entryDescriptor->Key,
|
||
|
entryDescriptor->NumFields,
|
||
|
entryDescriptor->Descriptor);
|
||
|
|
||
|
return FALSE;
|
||
|
|
||
|
}
|
||
|
|
||
|
void DumpTracing::SourcesCallout(SourceEntry * source)
|
||
|
{
|
||
|
if (LastItem != DumpTracing::source) {
|
||
|
|
||
|
if (DumpSummary) ExtOut("Registered sources:\n");
|
||
|
LastItem = DumpTracing::source;
|
||
|
}
|
||
|
|
||
|
if (DumpSummary) ExtOut(" %s: (Key=%p, Storage=%p, ControlFlags=%lx)\n",
|
||
|
source->Name,
|
||
|
(UINT64)source->Key,
|
||
|
source->StorageHandle,
|
||
|
source->ControlFlags);
|
||
|
}
|
||
|
|
||
|
bool DumpTracing::ActiveSourceCallout(SourceEntry * source, bool finished, ControllerObject *controller)
|
||
|
{
|
||
|
if (LastItem != DumpTracing::activesource) {
|
||
|
|
||
|
if (DumpSummary) ExtOut("Registered active sources:\n");
|
||
|
LastItem = DumpTracing::activesource;
|
||
|
}
|
||
|
|
||
|
if (!finished) {
|
||
|
|
||
|
EventTypeEntry * typeEntry = controller->FindType(source->EventTypeHandle);
|
||
|
|
||
|
if (typeEntry != NULL) {
|
||
|
|
||
|
if (DumpSummary) ExtOut(" %s: (Key=%p, Type=%p, Buffer=%p, %ld %s items)\n",
|
||
|
source->Name,
|
||
|
source->Key,
|
||
|
source->EventTypeHandle,
|
||
|
source->DebuggerBufferAddress,
|
||
|
(int)source->Count,
|
||
|
typeEntry->Name);
|
||
|
|
||
|
} else {
|
||
|
|
||
|
if (DumpSummary) ExtOut(" %s: (Key=%p, Type=%p, Buffer=%p, %ld unknown type items)\n",
|
||
|
source->Name,
|
||
|
source->Key,
|
||
|
source->EventTypeHandle,
|
||
|
source->DebuggerBufferAddress,
|
||
|
(int)source->Count);
|
||
|
}
|
||
|
|
||
|
|
||
|
}
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
bool DumpTracing::ControllerCallout( ControllerObject *ctrl, bool finished)
|
||
|
{
|
||
|
if (!EventingEnumerator::ControllerCallout(ctrl, finished)) {
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
if (DumpSummary) {
|
||
|
|
||
|
if (!finished) {
|
||
|
ExtOut("********************************************\n");
|
||
|
ExtOut("*\n");
|
||
|
ExtOut("* Controller %p (context %p)\n",
|
||
|
ctrl->ControllerHandle,
|
||
|
ctrl->ContextHandle);
|
||
|
ExtOut("*\n");
|
||
|
ExtOut("********************************************\n");
|
||
|
} else {
|
||
|
ExtOut("\n\n");
|
||
|
}
|
||
|
}
|
||
|
LastItem = controller;
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
bool DumpTracing::FieldCallout(EventTypeEntry * entryDescriptor, FieldEntry * fieldDescriptor)
|
||
|
{
|
||
|
if (!TestVisibility(entryDescriptor, fieldDescriptor)) {
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
if (PrintPhase == 0) {
|
||
|
|
||
|
if (!DumpDescriptions || (MetadataSize == 0)) {
|
||
|
|
||
|
fieldDescriptor->PrintValue(entryDescriptor);
|
||
|
}
|
||
|
|
||
|
} else if (MetadataSize != 0){
|
||
|
|
||
|
if (FieldIndex != 0) ExtOut(",");
|
||
|
ExtOut("%s", fieldDescriptor->Name);
|
||
|
FieldIndex += 1;
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
bool DumpTracing::EntryCallout(EntryHeader *header, EventTypeEntry * entryDescriptor)
|
||
|
{
|
||
|
if (entryDescriptor == NULL) {
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
if (!entryDescriptor->FilterMatch()) {
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
if (DumpAllEvents) {
|
||
|
|
||
|
PrintPhase = 0;
|
||
|
|
||
|
ExtOut("%6ld %p", CrtEntryIndex++, header->StackAddress);
|
||
|
entryDescriptor->WalkFields(this);
|
||
|
|
||
|
if (DumpDescriptions) {
|
||
|
|
||
|
ExtOut(" ");
|
||
|
entryDescriptor->PrintDescription();
|
||
|
ExtOut("\n");
|
||
|
|
||
|
} else {
|
||
|
|
||
|
PrintPhase = 1;
|
||
|
FieldIndex = 0;
|
||
|
ExtOut(" : %s(", entryDescriptor->Name);
|
||
|
entryDescriptor->WalkFields(this);
|
||
|
ExtOut(")\n");
|
||
|
}
|
||
|
|
||
|
if (header->StackSize && DumpStackTraces) {
|
||
|
|
||
|
DumpStackTrace();
|
||
|
ExtOut("\n");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
//
|
||
|
// Implementation of DumpType class
|
||
|
//
|
||
|
|
||
|
DumpType::DumpType(UINT64 handle)
|
||
|
{
|
||
|
typeHandle = handle;
|
||
|
printHeader = 1;
|
||
|
}
|
||
|
|
||
|
|
||
|
bool DumpType::FieldCallout(EventTypeEntry * entryDescriptor, FieldEntry * fieldDescriptor)
|
||
|
{
|
||
|
if (!TestVisibility(entryDescriptor, fieldDescriptor)) {
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
if (printHeader < 3) {
|
||
|
|
||
|
int width = fieldDescriptor->GetFieldPrintWidth();
|
||
|
int transformWidth = GetTransformFieldWidth(entryDescriptor, fieldDescriptor);
|
||
|
|
||
|
if (transformWidth > width) {
|
||
|
|
||
|
width = transformWidth;
|
||
|
}
|
||
|
|
||
|
if (printHeader == 1) {
|
||
|
|
||
|
char buff[100];
|
||
|
|
||
|
_snprintf(buff, sizeof(buff), "%%%lds", width);
|
||
|
ExtOut(buff, fieldDescriptor->Name);
|
||
|
|
||
|
} else if (printHeader == 2) {
|
||
|
|
||
|
WriteLine(width);
|
||
|
}
|
||
|
} else {
|
||
|
|
||
|
if (!ApplyTransforms(entryDescriptor, fieldDescriptor)) {
|
||
|
|
||
|
fieldDescriptor->PrintValue(entryDescriptor);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
bool DumpType::EntryCallout(EntryHeader *header, EventTypeEntry * entryDescriptor)
|
||
|
{
|
||
|
if ((entryDescriptor == NULL) || (entryDescriptor->Key != typeHandle)) {
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
if (!entryDescriptor->FilterMatch()) {
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
if (DumpAllEvents) {
|
||
|
|
||
|
if (printHeader == 1) {
|
||
|
|
||
|
PrintHeader(entryDescriptor);
|
||
|
|
||
|
} else if ((CrtEntryIndex % 50) == 0){
|
||
|
|
||
|
printHeader = 1;
|
||
|
ExtOut(" Index Stacks");
|
||
|
entryDescriptor->WalkFields(this);
|
||
|
ExtOut("\n");
|
||
|
printHeader += 1;
|
||
|
WriteLine(6);
|
||
|
entryDescriptor->WalkFields(this);
|
||
|
ExtOut("\n");
|
||
|
printHeader += 1;
|
||
|
}
|
||
|
|
||
|
INT64 delta;
|
||
|
|
||
|
if (lastTimeStamp == 0) {
|
||
|
|
||
|
delta = 0;
|
||
|
} else {
|
||
|
|
||
|
delta = header->timestamp - lastTimeStamp;
|
||
|
}
|
||
|
|
||
|
ExtOut("%6ld %p", CrtEntryIndex++, header->StackAddress);
|
||
|
lastTimeStamp = header->timestamp;
|
||
|
entryDescriptor->WalkFields(this);
|
||
|
ExtOut("\n");
|
||
|
|
||
|
if (header->StackSize && DumpStackTraces) {
|
||
|
|
||
|
DumpStackTrace();
|
||
|
ExtOut("\n");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
|
||
|
}
|
||
|
|
||
|
bool DumpType::PrintHeader(EventTypeEntry * entryDescriptor)
|
||
|
{
|
||
|
ExtOut("TYPE: %p Key=%p FieldsCount=%ld (%s-%s)\n",
|
||
|
(UINT64)entryDescriptor,
|
||
|
(UINT64)entryDescriptor->Key,
|
||
|
entryDescriptor->NumFields,
|
||
|
entryDescriptor->Name,
|
||
|
entryDescriptor->Descriptor);
|
||
|
|
||
|
ExtOut(" Index Stacks");
|
||
|
entryDescriptor->WalkFields(this);
|
||
|
ExtOut("\n");
|
||
|
|
||
|
printHeader += 1;
|
||
|
WriteLine(16);
|
||
|
entryDescriptor->WalkFields(this);
|
||
|
ExtOut("\n");
|
||
|
printHeader += 1;
|
||
|
CrtEntryIndex = 0;
|
||
|
return TRUE;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
bool DumpType::TypeCallout(EventTypeEntry * entryDescriptor)
|
||
|
{
|
||
|
|
||
|
if (!EventingEnumerator::TypeCallout(entryDescriptor)) {
|
||
|
|
||
|
if (!EventingEnumerator::TypeCallout(SystemHeaderType)) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (entryDescriptor->Key != typeHandle) {
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
lastTimeStamp = 0;
|
||
|
return TRUE;
|
||
|
|
||
|
}
|
||
|
|
||
|
bool DumpType::ActiveEntryCallout(EventTypeEntry * entryDescriptor, BOOL finished)
|
||
|
{
|
||
|
if (finished) {
|
||
|
ExtOut("\n");
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
if (entryDescriptor->Key != typeHandle) {
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
if (!entryDescriptor->FilterMatch()) {
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
if (printHeader == 1) {
|
||
|
|
||
|
PrintHeader(entryDescriptor);
|
||
|
}
|
||
|
|
||
|
ExtOut("%6ld", CrtEntryIndex++);
|
||
|
|
||
|
return TRUE;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
bool DumpType::ActiveSourceCallout(SourceEntry * source, bool finished, ControllerObject *controller)
|
||
|
{
|
||
|
if (!finished) {
|
||
|
|
||
|
CrtEntryIndex = 0;
|
||
|
printHeader = 1;
|
||
|
|
||
|
if ((source->EventTypeHandle == typeHandle)) {
|
||
|
|
||
|
ExtOut("ACTIVE SOURCE: %p Key=%p Type=%p Buffer=%p (%ld items)(%s)\n",
|
||
|
(UINT64)source,
|
||
|
source->Key,
|
||
|
source->EventTypeHandle,
|
||
|
source->DebuggerBufferAddress,
|
||
|
(int)source->Count,
|
||
|
source->Name);
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
|
||
|
} else {
|
||
|
ExtOut("\n");
|
||
|
}
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Implementation of the TypeFilterEnumerator methods
|
||
|
//
|
||
|
|
||
|
TypeFilterEnumerator::TypeFilterEnumerator()
|
||
|
{
|
||
|
Array = new VariableArray();
|
||
|
Pattern = NULL;
|
||
|
}
|
||
|
|
||
|
TypeFilterEnumerator::~TypeFilterEnumerator()
|
||
|
{
|
||
|
if (Array != NULL) delete (Array);
|
||
|
if (Pattern != NULL) delete (Pattern);
|
||
|
|
||
|
}
|
||
|
|
||
|
void TypeFilterEnumerator::SetPattern(StringPattern * pattern) {
|
||
|
|
||
|
Pattern = pattern;
|
||
|
}
|
||
|
|
||
|
|
||
|
bool TypeFilterEnumerator::TypeCallout(EventTypeEntry * entryDescriptor)
|
||
|
{
|
||
|
if (Pattern->IsMatch(entryDescriptor->Name)) {
|
||
|
|
||
|
Array->Add(entryDescriptor->Key);
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Implementation of the TypeEntryCollector methods
|
||
|
//
|
||
|
|
||
|
TypeEntryCollector::TypeEntryCollector(UINT64 typeHandle, char * field)
|
||
|
: TypeFilterEnumerator()
|
||
|
{
|
||
|
TypeHandle = typeHandle;
|
||
|
sortField = field;
|
||
|
cascadeEnumerator = NULL;
|
||
|
GroupByController = FALSE;
|
||
|
}
|
||
|
|
||
|
TypeEntryCollector::~TypeEntryCollector() {
|
||
|
|
||
|
}
|
||
|
|
||
|
bool TypeEntryCollector::MedataCallout(ControllerObject *controller)
|
||
|
{
|
||
|
if (cascadeEnumerator) {
|
||
|
|
||
|
return cascadeEnumerator->MedataCallout(controller);
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
void TypeEntryCollector::SourcesCallout(SourceEntry * source)
|
||
|
{
|
||
|
if (cascadeEnumerator) {
|
||
|
|
||
|
return cascadeEnumerator->SourcesCallout(source);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool TypeEntryCollector::StorageCallout(UINT64 storageAddress, bool finished)
|
||
|
{
|
||
|
if (cascadeEnumerator) {
|
||
|
|
||
|
return cascadeEnumerator->StorageCallout(storageAddress, finished);
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
bool TypeEntryCollector::FieldCallout(EventTypeEntry * entryDescriptor,
|
||
|
FieldEntry * fieldDescriptor)
|
||
|
{
|
||
|
// NOTE this assumes inserting FieldsWidth elements to the array
|
||
|
|
||
|
if (_stricmp(sortField, fieldDescriptor->Name) == 0) {
|
||
|
|
||
|
Array->Add(crtHandle);
|
||
|
Array->Add(fieldDescriptor->GetFieldNumericValue());
|
||
|
Array->Add((UINT64)currentController);
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
bool TypeEntryCollector::EntryCallout(EntryHeader *header,
|
||
|
EventTypeEntry * entryDescriptor)
|
||
|
{
|
||
|
if ((entryDescriptor == NULL) ||
|
||
|
((TypeHandle != 0) && (entryDescriptor->Key != TypeHandle))) {
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
if (!entryDescriptor->FilterMatch()) {
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
crtHandle = header->address;
|
||
|
entryDescriptor->WalkFields(this);
|
||
|
|
||
|
return TRUE;
|
||
|
|
||
|
}
|
||
|
|
||
|
bool TypeEntryCollector::TypeCallout(EventTypeEntry * entryDescriptor)
|
||
|
{
|
||
|
|
||
|
if (!EventingEnumerator::TypeCallout(entryDescriptor)) {
|
||
|
|
||
|
if (!EventingEnumerator::TypeCallout(SystemHeaderType)) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (cascadeEnumerator) {
|
||
|
|
||
|
cascadeEnumerator->TypeCallout(entryDescriptor);
|
||
|
}
|
||
|
|
||
|
if ((TypeHandle != 0) && (entryDescriptor->Key != TypeHandle)) {
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
return TRUE;
|
||
|
|
||
|
}
|
||
|
|
||
|
static int ItemCompare(const void * e1, const void * e2)
|
||
|
{
|
||
|
UINT64 *ptr1 = (UINT64 *) e1;
|
||
|
UINT64 *ptr2 = (UINT64 *) e2;
|
||
|
|
||
|
if (ptr1[1] < ptr2[1]) {
|
||
|
return -1;
|
||
|
} else if (ptr1[1] == ptr2[1]) {
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
void TypeEntryCollector::SortItems()
|
||
|
{
|
||
|
qsort(Array->Array, Array->InUse / FieldsWidth, FieldsWidth*sizeof(UINT64), ItemCompare);
|
||
|
}
|
||
|
|
||
|
void TypeEntryCollector::WalkItems(EventingEnumerator * enumerator)
|
||
|
{
|
||
|
|
||
|
for (int i = 0; i < Array->InUse; i+= FieldsWidth) {
|
||
|
|
||
|
ControllerObject * ctrl = (ControllerObject *)Array->Array[i+2];
|
||
|
|
||
|
if (ctrl != NULL) {
|
||
|
|
||
|
ctrl->ReadMemoryHeader(enumerator, Array->Array[i]);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool TypeEntryCollector::ControllerCallout(ControllerObject *controller, bool finished)
|
||
|
{
|
||
|
if (!EventingEnumerator::ControllerCallout(controller, finished)) {
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
if (finished) {
|
||
|
|
||
|
if (GroupByController) {
|
||
|
|
||
|
SortItems();
|
||
|
|
||
|
if (cascadeEnumerator) {
|
||
|
|
||
|
WalkItems(cascadeEnumerator);
|
||
|
cascadeEnumerator->ControllerCallout(controller, finished);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Recycle the elements captured so far since the cascade enumerator processed them
|
||
|
// already
|
||
|
//
|
||
|
|
||
|
if (Array != NULL) delete (Array);
|
||
|
Array = new VariableArray();
|
||
|
}
|
||
|
currentController = 0;
|
||
|
|
||
|
} else {
|
||
|
|
||
|
currentController = controller;
|
||
|
if (GroupByController) {
|
||
|
if (cascadeEnumerator) {
|
||
|
|
||
|
cascadeEnumerator->ControllerCallout(controller, finished);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
bool TypeEntryCollector::SystemCallout(bool finished)
|
||
|
{
|
||
|
|
||
|
if (finished) {
|
||
|
|
||
|
SortItems();
|
||
|
|
||
|
if (cascadeEnumerator) {
|
||
|
|
||
|
WalkItems(cascadeEnumerator);
|
||
|
}
|
||
|
}
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Source collector methods.
|
||
|
//
|
||
|
|
||
|
SourceCollector::SourceCollector(char * sourceName, char * field)
|
||
|
: TypeEntryCollector(0, field)
|
||
|
{
|
||
|
SourcePattern = NULL;
|
||
|
storageHandle = 0;
|
||
|
|
||
|
if (sourceName != NULL) {
|
||
|
SourcePattern = new StringPattern();
|
||
|
|
||
|
if (SourcePattern) {
|
||
|
|
||
|
SourcePattern->ParseInput(sourceName);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void SourceCollector::SourcesCallout(SourceEntry * source)
|
||
|
{
|
||
|
if (SourcePattern) {
|
||
|
|
||
|
if (SourcePattern->IsMatch(source->Name)) {
|
||
|
|
||
|
storageHandle = source->StorageHandle;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
bool SourceCollector::StorageCallout(UINT64 storageAddress, bool finished)
|
||
|
{
|
||
|
if ((storageHandle == 0) || (storageAddress == storageHandle)) {
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
|