You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
651 lines
17 KiB
651 lines
17 KiB
/*++
|
|
|
|
Copyright (c) 2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
output.hxx
|
|
|
|
Abstract:
|
|
|
|
This header file declares output classes for callbacks,
|
|
control, parsing, and filtering.
|
|
|
|
Author:
|
|
|
|
JasonHa
|
|
|
|
--*/
|
|
|
|
|
|
#ifndef _OUTPUT_HXX_
|
|
#define _OUTPUT_HXX_
|
|
|
|
|
|
class OutputControl
|
|
{
|
|
public:
|
|
// IUnknown
|
|
virtual ULONG STDMETHODCALLTYPE AddRef(THIS) {
|
|
return ++RefCount;
|
|
}
|
|
|
|
virtual ULONG STDMETHODCALLTYPE Release(void) {
|
|
ULONG NewCount = RefCount-1;
|
|
if (NewCount == 0)
|
|
{
|
|
delete this;
|
|
}
|
|
else
|
|
{
|
|
RefCount = NewCount;
|
|
}
|
|
return NewCount;
|
|
}
|
|
|
|
OutputControl()
|
|
{
|
|
RefCount = 1;
|
|
OutCtl = DEBUG_OUTCTL_AMBIENT;
|
|
Control = NULL;
|
|
}
|
|
|
|
OutputControl(ULONG OutputControl,
|
|
PDEBUG_CLIENT Client = NULL)
|
|
{
|
|
RefCount = 1;
|
|
OutCtl = DEBUG_OUTCTL_AMBIENT;
|
|
Control = NULL;
|
|
SetControl(OutputControl, Client);
|
|
}
|
|
|
|
OutputControl(PDEBUG_CLIENT Client)
|
|
{
|
|
RefCount = 1;
|
|
OutCtl = DEBUG_OUTCTL_AMBIENT;
|
|
Control = NULL;
|
|
SetControl(DEBUG_OUTCTL_AMBIENT, Client);
|
|
}
|
|
|
|
~OutputControl()
|
|
{
|
|
if (RefCount != 1)
|
|
{
|
|
DbgPrint("OutputControl::RefCount != 1.\n");
|
|
DbgBreakPoint();
|
|
}
|
|
|
|
if (Control != NULL) Control->Release();
|
|
}
|
|
|
|
ULONG GetControl() { return OutCtl; }
|
|
HRESULT SetControl(ULONG OutputControl, PDEBUG_CLIENT Client = NULL);
|
|
|
|
HRESULT Output(ULONG Mask, PCSTR Format, ...);
|
|
HRESULT OutputVaList(ULONG Mask, PCSTR Format, va_list Args);
|
|
|
|
HRESULT Output(PCSTR Format, ...);
|
|
HRESULT OutErr(PCSTR Format, ...);
|
|
HRESULT OutWarn(PCSTR Format, ...);
|
|
HRESULT OutVerb(PCSTR Format, ...);
|
|
|
|
HRESULT GetInterrupt();
|
|
HRESULT SetInterrupt(ULONG Flags);
|
|
HRESULT Evaluate(IN PCSTR Expression, IN ULONG DesiredType, OUT PDEBUG_VALUE Value, OUT OPTIONAL PULONG RemainderIndex);
|
|
HRESULT CoerceValue(IN PDEBUG_VALUE In, IN ULONG OutType, OUT PDEBUG_VALUE Out);
|
|
HRESULT IsPointer64Bit();
|
|
|
|
private:
|
|
ULONG RefCount;
|
|
PDEBUG_CONTROL Control;
|
|
ULONG OutCtl;
|
|
};
|
|
|
|
|
|
class OutputState
|
|
{
|
|
public:
|
|
OutputState(PDEBUG_CLIENT OrgClient, BOOL SameClient=FALSE);
|
|
~OutputState();
|
|
|
|
HRESULT Setup(ULONG OutMask, PDEBUG_OUTPUT_CALLBACKS OutCallbacks);
|
|
|
|
HRESULT Execute(IN PCSTR pszCommand);
|
|
|
|
HRESULT OutputType(
|
|
IN BOOL Physical,
|
|
IN ULONG64 Offset,
|
|
IN ULONG64 Module,
|
|
IN ULONG TypeId,
|
|
IN ULONG Flags
|
|
);
|
|
|
|
HRESULT OutputType(
|
|
IN BOOL Physical,
|
|
IN ULONG64 Offset,
|
|
IN PCSTR Type,
|
|
IN ULONG Flags
|
|
);
|
|
|
|
HRESULT OutputTypePhysical(
|
|
IN ULONG64 Offset,
|
|
IN ULONG64 Module,
|
|
IN ULONG TypeId,
|
|
IN ULONG Flags
|
|
)
|
|
{
|
|
return OutputType(TRUE, Offset, Module, TypeId, Flags);
|
|
}
|
|
|
|
HRESULT OutputTypePhysical(
|
|
IN ULONG64 Offset,
|
|
IN PCSTR Type,
|
|
IN ULONG Flags
|
|
)
|
|
{
|
|
return OutputType(TRUE, Offset, Type, Flags);
|
|
}
|
|
|
|
HRESULT OutputTypeVirtual(
|
|
IN ULONG64 Offset,
|
|
IN ULONG64 Module,
|
|
IN ULONG TypeId,
|
|
IN ULONG Flags
|
|
)
|
|
{
|
|
return OutputType(FALSE, Offset, Module, TypeId, Flags);
|
|
}
|
|
|
|
HRESULT OutputTypeVirtual(
|
|
IN ULONG64 Offset,
|
|
IN PCSTR Type,
|
|
IN ULONG Flags
|
|
)
|
|
{
|
|
return OutputType(FALSE, Offset, Type, Flags);
|
|
}
|
|
|
|
void Restore();
|
|
|
|
public:
|
|
PDEBUG_CLIENT Client;
|
|
|
|
private:
|
|
HRESULT hrInit;
|
|
PDEBUG_CONTROL Control;
|
|
PDEBUG_SYMBOLS Symbols;
|
|
BOOL CreatedClient;
|
|
BOOL SetCallbacks;
|
|
BOOL Saved;
|
|
ULONG OrgOutMask;
|
|
PDEBUG_OUTPUT_CALLBACKS OrgOutCallbacks;
|
|
};
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// Default output callbacks implementation, provides IUnknown for
|
|
// static classes.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
class DefOutputCallbacks :
|
|
public IDebugOutputCallbacks
|
|
{
|
|
public:
|
|
DefOutputCallbacks() { RefCount = 1; }
|
|
~DefOutputCallbacks()
|
|
{
|
|
if (RefCount != 1)
|
|
{
|
|
DbgPrint("DefOutputCallbacks@0x%p::RefCount(%lu) != 1.\n", this, RefCount);
|
|
DbgBreakPoint();
|
|
}
|
|
#if DBG
|
|
RefCount--;
|
|
#endif
|
|
}
|
|
|
|
// IUnknown.
|
|
STDMETHOD(QueryInterface)(
|
|
THIS_
|
|
IN REFIID InterfaceId,
|
|
OUT PVOID* Interface
|
|
);
|
|
STDMETHOD_(ULONG, AddRef)(
|
|
THIS
|
|
);
|
|
STDMETHOD_(ULONG, Release)(
|
|
THIS
|
|
);
|
|
|
|
// IDebugOutputCallbacks.
|
|
STDMETHOD(Output)(
|
|
THIS_
|
|
IN ULONG Mask,
|
|
IN PCSTR Text
|
|
);
|
|
|
|
protected:
|
|
ULONG RefCount;
|
|
};
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// DebugOutputCallbacks.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
class DebugOutputCallbacks : public DefOutputCallbacks
|
|
{
|
|
public:
|
|
// IDebugOutputCallbacks.
|
|
STDMETHOD(Output)(
|
|
THIS_
|
|
IN ULONG Mask,
|
|
IN PCSTR Text
|
|
);
|
|
};
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// OutputReader
|
|
//
|
|
// General DebugOutputCallback class to read output.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
class OutputReader : public DefOutputCallbacks
|
|
{
|
|
public:
|
|
OutputReader()
|
|
{
|
|
hHeap = NULL;
|
|
Buffer = NULL;
|
|
BufferSize = 0;
|
|
BufferLeft = 0;
|
|
}
|
|
|
|
~OutputReader()
|
|
{
|
|
if (Buffer) HeapFree(hHeap, 0, Buffer);
|
|
}
|
|
|
|
// IDebugOutputCallbacks.
|
|
STDMETHOD(Output)(
|
|
THIS_
|
|
IN ULONG Mask,
|
|
IN PCSTR Text
|
|
);
|
|
|
|
// Discard any text left unused by Parse
|
|
virtual void DiscardOutput();
|
|
|
|
// Get a copy of the output buffer
|
|
HRESULT GetOutputCopy(PSTR *Copy);
|
|
|
|
// Free the copy
|
|
void FreeOutputCopy(PSTR Copy)
|
|
{
|
|
if (hHeap != NULL) { HeapFree(hHeap, 0, Copy); }
|
|
}
|
|
|
|
protected:
|
|
HANDLE hHeap;
|
|
PSTR Buffer;
|
|
SIZE_T BufferSize;
|
|
SIZE_T BufferLeft;
|
|
};
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// OutputParser
|
|
//
|
|
// General DebugOutputCallback class to parse output.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
#define PARSE_OUTPUT_DISCARD 0x00000000
|
|
#define PARSE_OUTPUT_NO_DISCARD 0x00000001
|
|
|
|
#define PARSE_OUTPUT_UNPARSED 0x00000000
|
|
#define PARSE_OUTPUT_ALL 0x00000002
|
|
|
|
#define PARSE_OUTPUT_DEFAULT (PARSE_OUTPUT_DISCARD | PARSE_OUTPUT_UNPARSED)
|
|
|
|
class OutputParser : public OutputReader
|
|
{
|
|
public:
|
|
OutputParser() : OutputReader()
|
|
{
|
|
UnparsedIndex = 0;
|
|
}
|
|
|
|
// Send all read text through Parse method
|
|
// Flags:
|
|
// PARSE_OUTPUT_DISCARD or PARSE_OUTPUT_NO_DISCARD
|
|
// PARSE_OUTPUT_UNPARSED or PARSE_OUTPUT_ALL
|
|
// PARSE_OUTPUT_DEFAULT = PARSE_OUTPUT_DISCARD + PARSE_OUTPUT_UNPARSED
|
|
HRESULT ParseOutput(FLONG Flags = PARSE_OUTPUT_DEFAULT);
|
|
|
|
// Discard any text left unused by Parse
|
|
void DiscardOutput();
|
|
|
|
// Check if ready to look for keys/values
|
|
virtual HRESULT Ready() PURE;
|
|
|
|
// Reset progress counter so we may parse more output
|
|
virtual void Relook() PURE;
|
|
|
|
// Parse line of text and optionally return index to unused portion of text
|
|
virtual HRESULT Parse(IN PCSTR Text, OUT OPTIONAL PULONG RemainderIndex) PURE;
|
|
|
|
// Check if all keys/values were found during past reads
|
|
virtual HRESULT Complete() PURE;
|
|
|
|
private:
|
|
DWORD UnparsedIndex;
|
|
};
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// BasicOutputParser
|
|
//
|
|
// Basic DebugOutputCallback class to parse output looking for
|
|
// string keys and subsequent values.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
#define PARSER_UNSPECIFIED_RADIX -1
|
|
#define PARSER_DEFAULT_RADIX 0
|
|
|
|
class BasicOutputParser : public OutputParser
|
|
{
|
|
typedef struct {
|
|
PDEBUG_VALUE Value;
|
|
ULONG Type;
|
|
ULONG Radix;
|
|
CHAR Key[80];
|
|
} LookupEntry;
|
|
|
|
public:
|
|
BasicOutputParser(PDEBUG_CLIENT OutputClient, ULONG TotalEntries = 4)
|
|
{
|
|
Client = OutputClient;
|
|
|
|
Entries = new LookupEntry[TotalEntries];
|
|
if (!Entries) TotalEntries = 0;
|
|
|
|
MaxEntries = TotalEntries;
|
|
NumEntries = 0;
|
|
CurEntry = 0;
|
|
}
|
|
|
|
~BasicOutputParser()
|
|
{
|
|
if (Entries) delete[] Entries;
|
|
}
|
|
|
|
HRESULT LookFor(OUT PDEBUG_VALUE Value,
|
|
IN PCSTR Key,
|
|
IN ULONG Type = DEBUG_VALUE_INVALID,
|
|
IN ULONG Radix = PARSER_UNSPECIFIED_RADIX);
|
|
|
|
// Check if ready to look for keys/values
|
|
HRESULT Ready() { return (CurEntry != NumEntries) ? S_OK : S_FALSE; }
|
|
|
|
// Reset progress counter so we may parse more output
|
|
void Relook() { CurEntry = 0; }
|
|
|
|
// Parse line of text and optionally return index to unused portion of text
|
|
HRESULT Parse(IN PCSTR Text, OUT OPTIONAL PULONG RemainderIndex);
|
|
|
|
// Check if all keys/values were found during past reads
|
|
HRESULT Complete()
|
|
{
|
|
return (Client != NULL &&
|
|
CurEntry == NumEntries) ?
|
|
S_OK :
|
|
S_FALSE;
|
|
}
|
|
|
|
private:
|
|
PDEBUG_CLIENT Client;
|
|
ULONG MaxEntries;
|
|
ULONG NumEntries;
|
|
|
|
ULONG CurEntry;
|
|
|
|
LookupEntry *Entries;
|
|
};
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// BitFieldParser
|
|
//
|
|
// DebugOutputCallback class to parse bitfield type output
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
class BitFieldInfo {
|
|
public:
|
|
BitFieldInfo() { Valid = FALSE; };
|
|
BitFieldInfo(ULONG InitBitPos, ULONG InitBits) {
|
|
Valid = Compose(InitBitPos, InitBits);
|
|
}
|
|
|
|
BOOL Compose(ULONG CBitPos, ULONG CBits)
|
|
{
|
|
BitPos = CBitPos;
|
|
Bits = CBits;
|
|
Mask = (((((ULONG64) 1) << Bits) - 1) << BitPos);
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL Valid;
|
|
ULONG BitPos;
|
|
ULONG Bits;
|
|
ULONG64 Mask;
|
|
};
|
|
|
|
class BitFieldParser : public OutputParser
|
|
{
|
|
public:
|
|
BitFieldParser(PDEBUG_CLIENT Client, BitFieldInfo *BFI);
|
|
|
|
// Reset progress counter so we may parse more output
|
|
void Relook()
|
|
{
|
|
if (BitField != NULL)
|
|
{
|
|
BitField->Valid = FALSE;
|
|
BitField->BitPos = 0;
|
|
BitField->Bits = 0;
|
|
BitField->Mask = 0;
|
|
}
|
|
BitFieldReader.Relook();
|
|
}
|
|
|
|
// Check if ready to look for bit fields
|
|
HRESULT Ready()
|
|
{
|
|
return (BitField != NULL) ?
|
|
BitFieldReader.Ready() :
|
|
S_FALSE;
|
|
}
|
|
|
|
// Parse line of text and optionally return index to unused portion of text
|
|
HRESULT Parse(IN PCSTR Text, OUT OPTIONAL PULONG RemainderIndex);
|
|
|
|
// Check if bit fields were found during past reads
|
|
HRESULT Complete()
|
|
{
|
|
return (BitField != NULL && BitField->Valid) ?
|
|
BitFieldReader.Complete() :
|
|
S_FALSE;
|
|
}
|
|
|
|
private:
|
|
BitFieldInfo *BitField;
|
|
DEBUG_VALUE BitPos;
|
|
DEBUG_VALUE Bits;
|
|
BasicOutputParser BitFieldReader;
|
|
};
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// OutputFilter
|
|
//
|
|
// DebugOutputCallback class to filter output
|
|
// by skipping/replacing lines.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
// Query Flags
|
|
#define OUTFILTER_QUERY_EVERY_LINE 0x00000000
|
|
#define OUTFILTER_QUERY_ONE_LINE 0x00000001
|
|
|
|
#define OUTFILTER_QUERY_WHOLE_WORD 0x00000002 // Characters before and after
|
|
// query must not be C symbols
|
|
// [a-z,A-A,0-9,_]
|
|
|
|
#define OUTFILTER_QUERY_ENABLED 0x00000004
|
|
#define OUTFILTER_QUERY_HIT 0x00000008
|
|
|
|
// Replace Flags
|
|
#define OUTFILTER_REPLACE_EVERY 0x00000000
|
|
#define OUTFILTER_REPLACE_ONCE 0x00010000
|
|
|
|
#define OUTFILTER_REPLACE_ALL_INSTANCES (OUTFILTER_REPLACE_EVERY | OUTFILTER_QUERY_EVERY_LINE)
|
|
#define OUTFILTER_REPLACE_ONCE_PER_LINE (OUTFILTER_REPLACE_ONCE | OUTFILTER_QUERY_EVERY_LINE)
|
|
#define OUTFILTER_REPLACE_EXACTLY_ONCE (OUTFILTER_REPLACE_ONCE | OUTFILTER_QUERY_ONE_LINE)
|
|
|
|
#define OUTFILTER_REPLACE_CONTINUE 0x00000000
|
|
#define OUTFILTER_REPLACE_NEXT_LINE 0x00020000 // Stop replacement checks
|
|
// for current line after
|
|
// this replacement
|
|
|
|
#define OUTFILTER_REPLACE_BEFORE 0x04000000 // Replace text in line prior to query match
|
|
#define OUTFILTER_REPLACE_THIS 0x02000000 // Replace query text
|
|
#define OUTFILTER_REPLACE_AFTER 0x01000000 // Replace text following query match
|
|
|
|
#define OUTFILTER_REPLACE_FROM_START (OUTFILTER_REPLACE_BEFORE | OUTFILTER_REPLACE_THIS)
|
|
#define OUTFILTER_REPLACE_TO_END (OUTFILTER_REPLACE_THIS | OUTFILTER_REPLACE_AFTER)
|
|
#define OUTFILTER_REPLACE_LINE (OUTFILTER_REPLACE_BEFORE | \
|
|
OUTFILTER_REPLACE_THIS | \
|
|
OUTFILTER_REPLACE_AFTER)
|
|
|
|
#define OUTFILTER_REPLACE_PRIORITY(x) (((x+8) & 0xF) << 28) // Higher priority replacement queries
|
|
// are tested before lower. Priority
|
|
// range: 7 (high) to -7 (low)
|
|
|
|
#define OUTFILTER_REPLACE_DEFAULT (OUTFILTER_REPLACE_ALL_INSTANCES | \
|
|
OUTFILTER_REPLACE_CONTINUE | \
|
|
OUTFILTER_REPLACE_THIS | \
|
|
OUTFILTER_REPLACE_PRIORITY(0))
|
|
|
|
// Skip Flags
|
|
#define OUTFILTER_SKIP_DEFAULT OUTFILTER_QUERY_EVERY_LINE
|
|
|
|
// FindMatch Flags
|
|
#define OUTFILTER_FINDMATCH_ANYWHERE 0
|
|
#define OUTFILTER_FINDMATCH_AT_START 1
|
|
#define OUTFILTER_FINDMATCH_MARK 0
|
|
#define OUTFILTER_FINDMATCH_NO_MARK 2
|
|
|
|
#define OUTFILTER_FINDMATCH_DEFAULT (OUTFILTER_FINDMATCH_ANYWHERE | OUTFILTER_FINDMATCH_MARK)
|
|
|
|
class OutputFilter : public OutputReader
|
|
{
|
|
public:
|
|
OutputFilter(PDEBUG_CLIENT DbgClient) : OutputReader()
|
|
{
|
|
Client = DbgClient;
|
|
if (Client != NULL) Client->AddRef();
|
|
SkipList = NULL;
|
|
ReplaceList = NULL;
|
|
Outputing = FALSE;
|
|
}
|
|
~OutputFilter()
|
|
{
|
|
if (Client != NULL) Client->Release();
|
|
}
|
|
|
|
// IDebugOutputCallbacks.
|
|
STDMETHOD(Output)(
|
|
THIS_
|
|
IN ULONG Mask,
|
|
IN PCSTR Text
|
|
);
|
|
|
|
HRESULT Query(PCSTR Query,
|
|
PDEBUG_VALUE Value = NULL,
|
|
ULONG Type = DEBUG_VALUE_INVALID,
|
|
ULONG Radix = PARSER_UNSPECIFIED_RADIX);
|
|
|
|
HRESULT Replace(ULONG Flags, PCSTR Query, PCSTR Replacement);
|
|
HRESULT Skip(ULONG Flags, PCSTR Query);
|
|
|
|
HRESULT OutputText(OutputControl *OutCtl = NULL, ULONG Mask = DEBUG_OUTPUT_NORMAL);
|
|
|
|
protected:
|
|
class QuerySpec
|
|
{
|
|
public:
|
|
QuerySpec(ULONG Flags, PCSTR Query);
|
|
~QuerySpec()
|
|
{
|
|
if (Query != NULL)
|
|
{
|
|
delete[] Query;
|
|
}
|
|
}
|
|
|
|
QuerySpec *Next;
|
|
ULONG Flags;
|
|
ULONG QueryLen;
|
|
PSTR Query;
|
|
};
|
|
|
|
class ReplacementSpec : public QuerySpec
|
|
{
|
|
public:
|
|
ReplacementSpec(ULONG Flags, PCSTR QueryText, PCSTR ReplacementText);
|
|
~ReplacementSpec()
|
|
{
|
|
if (Replacement != NULL)
|
|
{
|
|
delete[] Replacement;
|
|
}
|
|
}
|
|
|
|
// ReplacementSpec *Next;
|
|
ULONG ReplacementLen;
|
|
PSTR Replacement;
|
|
};
|
|
|
|
QuerySpec **FindPrior(ULONG Flags, PCSTR Query, QuerySpec **List);
|
|
QuerySpec *FindMatch(PCSTR Text,
|
|
QuerySpec *List,
|
|
ULONG Start = 0,
|
|
ULONG Flags = OUTFILTER_FINDMATCH_DEFAULT,
|
|
PULONG MatchPos = NULL);
|
|
|
|
PDEBUG_CLIENT Client;
|
|
|
|
ReplacementSpec *ReplaceList;
|
|
QuerySpec *SkipList;
|
|
|
|
private:
|
|
BOOL Outputing;
|
|
};
|
|
|
|
|
|
#endif _OUTPUT_HXX_
|
|
|