/////////////////////////////////////////////////////////////////////////////
//
//  diagnose.h - Definitions for diag.cpp
//
//  Copyright Microsoft Corporation.  All rights reserved.
//

//  Some arbitrary constants to simplify dealing with variable size arrays.
//  Some cleanup would be necessary

#define MAX_FIELDS 32
#define MAX_TYPES 1024
#define MAX_FILTERS 8
#define MAX_SOURCES 1024
#define MAX_CONTROLLERS 1024

#define ROUND_UP_TO_POWER2( x, n ) (((x) + ((n)-1)) & ~((n)-1))
#define ROUND_DOWN_TO_POWER2( x, n ) ((x) & ~((n)-1))

extern volatile BOOL BreakOnInternalError;

void inline ERRORBREAK(char * msg)
{
    ExtVerb(msg);

#ifdef ISA_IX86
    if (BreakOnInternalError) {

        __asm int 3;
    }
#endif
}

struct FieldEntry;
struct EventTypeEntry;
struct SourceEntry;
struct FieldFilter;
struct ControllerObject;

//  Structure to cache information for entry enumeration. The values are retrieved from the
//  entry header

struct EntryHeader {
    UINT64 address;
    int size;
    int Flags;
    UINT64 timestamp;
    int TID;
    int Cpu;
    int StackSize;
    UINT64 StackAddress;
};

struct StringPattern;

#define MAX_STORAGE_FILTERS 256

class EventingEnumerator
{

public:

    FieldFilter ** Filters;
    int FiltersCount;
    StringPattern * SourcePattern;

    ULONG64 usedStorages;
    ULONG64 StorageHandles[MAX_STORAGE_FILTERS];

    EventingEnumerator();

    bool virtual ApplyFilters(FieldFilter ** filters, int Count);
    bool ApplySourceSelector(StringPattern * sourcePattern);

    void ClearStorageFilters(){usedStorages = 0;}
    bool AddStorageFilter(ULONG64 storageHandle);
    bool MatchStorageHandle(ULONG64 storageHandle);

    //  System enumeration callout. The function is called twice, one before enumeration of all
    //  controllers begin, and ones after the last controller has been parsed.

    bool virtual SystemCallout(bool finished)
    { return TRUE;}

    //  Controler enumeration callout. The function is called twice, one before enumeration of sources,
    //  storages andtypes begin. If override, by returning false, will inform the enumeration
    //  that wlaking the controller's structures must be skipped for this controller. In that case
    //  there will be no second call to notify enumeration complete

    bool virtual ControllerCallout(ControllerObject *controller, bool finished)
    {     usedStorages = 0; return TRUE;}

    //  Metadata callout. The function is called after all metadata has been loaded in controller
    //  Return TRUE if also walking entries is needed, false if no walk is further
    //  necessary on this controller.

    bool virtual MedataCallout(ControllerObject *controller);


    //  Storage enumeration callout. The function is called twice, one before enumeration zones
    //  inside the storage. If override, by returning false, will inform the enumeration that
    //  walking the storage's structures must be skipped. In that case there will be no
    //  second call to notify enumeration complete

    bool virtual StorageCallout(UINT64 storageAddress, bool finished);

    //  Zone enumeration callout. The function is called twice, one before enumeration zones
    //  inside the storage. If override, by returning false, will inform the enumeration that
    //  walking the storage's structures must be skipped. In that case there will be no
    //  second call to notify enumeration complete.

    bool virtual ZoneCallout(UINT64 zoneAddress, bool finished)
    { return TRUE;}

    //  Sources enumeration callout. There are two type of sources:
    //      a. Sources which log to regular memory storages.
    //      b. Sources which manages the updates in their's private maner (active sources)

    //  SourcesCallout is called to enumerate very source inside a controller. This is a leaf
    //  enumeration point, no other internal structures will follow this callback.

    void virtual SourcesCallout(SourceEntry * source){}

    //  Active sources will go through an enumeration also of the internal elements.
    //  They respect the same semantics as explained in controller, wrt. overriding the
    //  function. The second call when entries enumeration is completed does not occur if the
    //  override explicitely rejected the enumeration by returning false.

    bool virtual ActiveSourceCallout(SourceEntry * source, bool finished, ControllerObject *controller)
    { return TRUE;}

    //  Leaf enumeration point to notify about the presence of a new type that has been read
    //  from the corrent controller's repository

    bool virtual TypeCallout(EventTypeEntry * entryDescriptor);

    //  Callout for every entry in the storage, as they are parsed. Internally the override
    //  may also choose to walk the fields inside with a call to the method:
    //            entryDescriptor->WalkFields(this);
    //  Otherwise this is also a leaf call, the value of the entry is already loaded
    //  in the buffer so querying values, properties will assume the right context

    bool virtual EntryCallout(EntryHeader *header, EventTypeEntry * entryDescriptor)
    { return TRUE;}

    //  Callout for active entries. The active entries to not have a the usual ENTRY_HEADER
    //  that everything else has, because the storage of such events are really the responsibility
    //  of the source. To also force the enumeration of fields for each entry the following call
    //  must be made in the override:
    //            entryDescriptor->WalkFields(this);

    bool virtual ActiveEntryCallout(EventTypeEntry * entryDescriptor, BOOL finished)
    { return TRUE;}

    //  The following callout is to notify about every field in a type / entry that gets enumerated.
    //  for regular entries these will not be invoked, unless in the EntryCallout or in
    //  ActiveEntryCallout the entryDescriptor->WalkFields(this) call is done.

    bool virtual FieldCallout(EventTypeEntry * entryDescriptor, FieldEntry * fieldDescriptor)
    { return TRUE;}
};


// TODO: redefinition of constants. Must be moved to a common place

#define RECORD_STACK_TRACES 0x0001

#define RECORD_LAYOUT_FLAGS (RECORD_STACK_TRACES)

#define FIELD_TYPE__int8 0x1    // 1
#define FIELD_TYPE__uint8 0x2    // 2
#define FIELD_TYPE__byte 0x2    // 2
#define FIELD_TYPE__int16 0x3    // 3
#define FIELD_TYPE__uint16 0x4    // 4
#define FIELD_TYPE__int32 0x5    // 5
#define FIELD_TYPE__int 0x5    // 5
#define FIELD_TYPE__uint32 0x6    // 6
#define FIELD_TYPE__int64 0x7    // 7
#define FIELD_TYPE__uint64 0x8    // 8
#define FIELD_TYPE__IntPtr 0x9    // 9
#define FIELD_TYPE__UIntPtr 0xa    // 10
#define FIELD_TYPE_GENERIC_TYPE 0xff

#define FIELD_TYPE__arrayType 0x8000
#define FIELD_TYPE__string 0x4000
#define FIELD_TYPE__szChar 0x2000

#define FIELD_TYPE_VARIABLE_SIZE (FIELD_TYPE__arrayType | FIELD_TYPE__string | FIELD_TYPE__szChar)
#define FIELD_TYPE_VARIABLE_ANY_STRING (FIELD_TYPE__string | FIELD_TYPE__szChar)

struct ArrayType
{
    USHORT Length;
    USHORT ItemSize;
    UINT Type;
    PVOID Buffer;
};


//
//  Filtering operations
//

enum PatternMatch{
    anywhere = 1,
    exact = 2,
    begin = 3
};

enum FilterOperation{
    all = 0,  // no test on value
    equal = 1,
    less = 2,
    greater = 3,
    different = 4,

    contains = 5 // for strings only
};

struct ControllerObject;

// Utility class for simple string pattern matching

struct StringPattern
{
    char * Pattern;
    PatternMatch MatchMode;

    StringPattern();
    ~StringPattern();

    void Cleanup();
    bool IsMatch(char * p);
    char * ParseInput(char * arg);
};

struct SymbolicValue {
    struct SymbolicValue * Next;
    PCHAR Name;
    ULONG64 Value;
    UCHAR FlagChar;
    ULONG64 ParentKey;

    SymbolicValue() {
        Name = NULL;
        Value = 0;
        FlagChar = 0;
        Next = NULL;
    }
    ~SymbolicValue(){ if (Name) free (Name);}
};

struct EnumType {

    UINT64 Key;
    int BasicType;
    ULONG64 FlagsMask;
    struct SymbolicValue * ValuesLists;
    int NumFlags;
    int PrintWidth;
    PCHAR Name;

    EnumType()
    {
        Key = 0;
        FlagsMask = 0;
        ValuesLists = NULL;
        NumFlags = 0;
        PrintWidth = 0;
        Name = NULL;
    }

    ~EnumType();

    void AddSymbolicValue(SymbolicValue * symValue);
    int GetFieldPrintWidth();
    int PrintValue(int printWidth, int offset);
    ULONG64 GetFieldNumericValue(int offset);
    PCHAR GetStringSymbol(int offset);

};

struct FieldEntry {

    int Offset;
    int Type;
    int Size;
    PCHAR Name;
    UINT64 ParentKey;
    int ExtendedFieldIndex;
    unsigned int PrintWidth;
    UINT64 TypeKey;
    EnumType * SymType;
    ControllerObject * Controller;

    FieldEntry();
    ~FieldEntry();

    ULONG64 GetFieldNumericValue();
    ULONG64 PrintValue(EventTypeEntry * type);
    int GetFieldPrintWidth();

    int GetArraySize(void * buffer);
    ULONG64 GetFieldNumericValue(void * buffer, int index);

};

//
//  Utility class used in searching and filtering of entries in
//  either regular or active sources.
//
struct FieldFilter
{
    char * FieldNamePattern;
    char * StringValuePattern;
    INT64 NumericValuePattern;

    PatternMatch FieldMatchMode;
    FilterOperation Operation;

    FieldFilter();
    ~FieldFilter();

    void Cleanup();

    FieldFilter(PatternMatch matchMode,
                char * fieldPattern,
                FilterOperation op,
                UINT64 value,
                char * strValue);

    bool MatchFieldName(char * p);

    bool MatchFieldValue(INT64 value);
    bool MatchFieldValue(char * value);

    char * ParseInput(char * arg);
};

//  Simple variable size array implementation

struct VariableArray
{

    UINT64 *Array;
    int InUse;
    int Size;

    VariableArray();
    ~VariableArray();
    bool Add(UINT64 value);

private:
    bool Extend();
};



struct EventTypeEntry {

    UINT64 Key;
    int NumFields;
    FieldEntry * Fields[MAX_FIELDS];
    PCHAR Name;
    PCHAR Descriptor;

    int size;
    int ExtendedFieldsCount;

    FieldFilter * filterList[MAX_FILTERS];
    FieldEntry * fieldsFilterList[MAX_FILTERS];
    int filterCount;
    bool FilterApplied;

    EventTypeEntry();
    ~EventTypeEntry();

    void AddNewField(FieldEntry * field);
    bool TestFilter(FieldFilter * newFilter);
    bool ApplyFilter(FieldFilter * newFilter);
    void ClearFilters();
    bool FilterMatch();

    void UpdateFieldsOffsets();
    void WalkFields(EventingEnumerator * enumerator);
    char * GetExtendedString(int index);
    void * GetFieldArray(int index);
    void Format(int formatStringIndex, int argIndex);
    void PrintDescription();

    FieldEntry * GetField(PCHAR name);
    int GetFieldIndex(PCHAR name);
    void EnumerateEntries(EventingEnumerator * enumerator, UINT64 address, ULONG count);
};

struct SourceEntry {

    UINT64 Key;
    PCHAR Name;
    UINT64 StorageHandle;
    ULONG ControlFlags;

    //
    //  For active sources
    //

    UINT64 EventTypeHandle;
    UINT64 DebuggerBufferAddress;
    UINT64 Count;
    UINT64 EntrySize;

    SourceEntry();
    ~SourceEntry();

    void EnumerateEntries(EventingEnumerator * enumerator, ControllerObject *controller);

};


struct ControllerObject {

    //  Enumeration support local variables and definitions

    EventTypeEntry * RegisteredTypes[MAX_TYPES];
    int TypesCount;

    FieldEntry * RegisteredFieldsTypes[MAX_FIELDS];

    SourceEntry * RegisteredSources[MAX_SOURCES];
    int SourcesCount;

    EnumType * RegisteredEnums[MAX_TYPES];
    int EnumCount;
    SymbolicValue * RegisteredSymbolicValues[MAX_FIELDS];

    UINT64 ControllerHandle;
    UINT64 ContextHandle;
    UINT64 RepositoryAddress;
    UINT64 StorageListHead;

    ControllerObject(UINT64 handle,
                     UINT64 contextHandle,
                     UINT64 storageAddress,
                     UINT64 storageListHead);
    ~ControllerObject();


    void FetchMetadata(EventingEnumerator * enumerator);
    void WalkEntries(EventingEnumerator * enumerator);
    EventTypeEntry * FindType(ULONG64 Key);
    UINT64 ReadMemoryHeader(EventingEnumerator * enumerator, UINT64 entryAddress);
    char * GetControllerName();
    EnumType * FindEnum(ULONG64 Key);

private:

    void AddTempField(FieldEntry * field);
    void PopulateFields(EventTypeEntry * type);
    void AddewType(EventTypeEntry * newType);
    SourceEntry * FindSource(ULONG64 Key);
    void AddNewSource(SourceEntry * newSource);
    void WalkTypes(EventingEnumerator * enumerator);
    void WalkSources(EventingEnumerator * enumerator);
    void WalkActiveSourcesEntries(EventingEnumerator * enumerator);
    void ReadSource(UINT64 entryAddress);
    void ReadEventDescriptor(UINT64 entryAddress);
    void ReadFieldDescriptor(UINT64 entryAddress, UINT64 parent);
    void ReadGenericFieldDescriptor(UINT64 entryAddress, UINT64 parent);
    UINT64 ReadMetadataMemoryHeader(EventingEnumerator * enumerator, UINT64 entryAddress);
    UINT64 ReadMemoryZone(EventingEnumerator * enumerator, UINT64 zoneAddress);
    UINT64 ReadStorage(EventingEnumerator * enumerator, UINT64 storageAddress, bool isRepository);

    void AddNewEnum(EnumType * newEnum);
    void PopulateFields(EnumType * type);
    void AddTempField(SymbolicValue * field);
    void ReadEnumDescriptor(UINT64 entryAddress);
    void ReadValueDescriptor(UINT64 entryAddress, UINT64 parent);

    void FlushTypeArray();
    void FlushSourceArray();

};




//
//  Generic utility prototypes
//

extern EventTypeEntry * SystemHeaderType;

int GetFieldSize(int type);
char * GetFieldTypeName(int type);
bool MatchPatternString(PatternMatch matchMode, char * p, char* pattern);
char * ReadToken(PCSTR& args);

void FlushTransforms();
void ParseStringFormatTransform(PCSTR & args);
void ParseVisibleFields(PCSTR & args);
void ParseSymbolLookupTransform(PCSTR & args);

#define SKIP_WHITESPACES(arg)                                  \
    while (*(arg) == ' ' || *(arg) == '\t') (arg)++;

extern ULONG64 GetValue(PCSTR& args, bool fHex);
HRESULT FindBound(const char *symbol, ULONG64 *ptrval);
HRESULT SetBound(const char *symbol, ULONG64 ptrval);

//
//  Classes support for filtering, sorting and content dump
//


class DumpTracing : public EventingEnumerator
{
    //  High level diagnosis enumeration. Each override will skip walking through actuall entries

public:
    bool DumpSummary;

    DumpTracing() {CrtEntryIndex = 0; DumpSummary = false;}

    //  Override callouts

    bool virtual TypeCallout(EventTypeEntry * entryDescriptor);
    void virtual SourcesCallout(SourceEntry * source);
    bool virtual ActiveSourceCallout(SourceEntry * source, bool finished, ControllerObject *controller);
    bool virtual ControllerCallout(ControllerObject *controller, bool finished);
    bool virtual FieldCallout(EventTypeEntry * entryDescriptor, FieldEntry * fieldDescriptor);
    bool virtual EntryCallout(EntryHeader *header, EventTypeEntry * entryDescriptor);

private:
    enum Lastprinted {
        controller,
        type,
        source,
        activesource
    };

    int CrtEntryIndex;
    Lastprinted LastItem;
    int PrintPhase;
    int FieldIndex;

};

class DumpType : public EventingEnumerator
{

public:

    UINT64 typeHandle;
    int printHeader;
    UINT64 lastTimeStamp;
    int CrtEntryIndex;

    DumpType(UINT64 handle);

    bool virtual FieldCallout(EventTypeEntry * entryDescriptor, FieldEntry * fieldDescriptor);

    bool virtual EntryCallout(EntryHeader *header, EventTypeEntry * entryDescriptor);
    bool virtual PrintHeader(EventTypeEntry * entryDescriptor);
    bool virtual TypeCallout(EventTypeEntry * entryDescriptor);
    bool virtual ActiveEntryCallout(EventTypeEntry * entryDescriptor, BOOL finished);
    bool virtual ActiveSourceCallout(SourceEntry * source, bool finished, ControllerObject *controller);
};

class TypeFilterEnumerator : public EventingEnumerator
{

public:

    VariableArray * Array;
    StringPattern * Pattern;

    TypeFilterEnumerator();
    ~TypeFilterEnumerator();
    void SetPattern(StringPattern * pattern);
    bool virtual TypeCallout(EventTypeEntry * entryDescriptor);
};

class TypeEntryCollector : public TypeFilterEnumerator
{

public:

    char * sortField;
    UINT64 crtHandle;
    UINT64 TypeHandle;
    BOOL GroupByController;
    EventingEnumerator *cascadeEnumerator;
    ControllerObject * currentController;
    static const int FieldsWidth = 3;

    TypeEntryCollector(UINT64 typeHandle, char * field);
    ~TypeEntryCollector();

    bool virtual FieldCallout(EventTypeEntry * entryDescriptor, FieldEntry * fieldDescriptor);
    bool virtual EntryCallout(EntryHeader *header, EventTypeEntry * entryDescriptor);
    bool virtual TypeCallout(EventTypeEntry * entryDescriptor);
    bool virtual ControllerCallout(ControllerObject *controller, bool finished);
    bool virtual SystemCallout(bool finished);
    bool virtual MedataCallout(ControllerObject *controller);
    void virtual SourcesCallout(SourceEntry * source);
    bool virtual StorageCallout(UINT64 storageAddress, bool finished);

private:
    void SortItems();
    void WalkItems(EventingEnumerator * enumerator);
};

class SourceCollector : public TypeEntryCollector
{

public:
    StringPattern *SourcePattern;
    UINT64 storageHandle;

    SourceCollector(char * sourceName, char * field);
    void virtual SourcesCallout(SourceEntry * source);
    bool virtual StorageCallout(UINT64 storageAddress, bool finished);

};

//
//  Function support for GC profiling
//


void DumpMemory(PCSTR fname);
void WriteFileRange (int Base, int Size, PCSTR fname);
void WriteCLRProfileFile(PCSTR fname, bool Kernel);
void EnableKernelGCProfiler(ULONG64 MemorySize, bool breakOnRecycle);
void DisableKernelGCProfiler();
void EnableSIPGCProfiler(ULONG64 MemorySize, bool breakOnRecycle);
extern ULONG_PTR MetadataSize;
extern char * MetadataInfo;



class MemoryRagesCollection : public VariableArray {
    int DiscardedRanges;
    UINT64 PreviousAddress;
    UINT64 PreviousSize;

public:

    MemoryRagesCollection() : VariableArray(){DiscardedRanges=0; PreviousAddress = 0; PreviousSize = 0;};
    void AddRange(UINT64 startRVA, UINT64 rangeSize);

    int GetEffectiveRanges(){return GetRangesCount() - DiscardedRanges;}
    UINT64 GetStartAddress(int i){return Array[i * 2];}
    UINT64 GetRangeSize(int i){return Array[i * 2 + 1];}
    int GetRangesCount(){return InUse / 2;}
    void CompactItems();
    UINT64 GetRVA(UINT64 address);
};

extern ULONG pointerSize;

ULONG_PTR SWITCH_TO_METADATA_CURSOR();
void RESTORE_CURSOR(ULONG_PTR savedCursor);

void WalkTracingDatabase(EventingEnumerator * enumerator, bool typesOnly);
UINT64 GetStackTrace(int index) ;

