/*++ 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_