| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236 |
- /*
- ** Command & Conquer Generals Zero Hour(tm)
- ** Copyright 2025 Electronic Arts Inc.
- **
- ** This program is free software: you can redistribute it and/or modify
- ** it under the terms of the GNU General Public License as published by
- ** the Free Software Foundation, either version 3 of the License, or
- ** (at your option) any later version.
- **
- ** This program is distributed in the hope that it will be useful,
- ** but WITHOUT ANY WARRANTY; without even the implied warranty of
- ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- ** GNU General Public License for more details.
- **
- ** You should have received a copy of the GNU General Public License
- ** along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- /////////////////////////////////////////////////////////////////////////EA-V1
- // $File: //depot/GeneralsMD/Staging/code/Libraries/Source/debug/debug_debug.h $
- // $Author: mhoffe $
- // $Revision: #1 $
- // $DateTime: 2003/07/03 11:55:26 $
- //
- // ©2003 Electronic Arts
- //
- // main Debug object (singleton)
- //////////////////////////////////////////////////////////////////////////////
- #ifdef _MSC_VER
- # pragma once
- #endif
- #ifndef DEBUG_DEBUG_H // Include guard
- #define DEBUG_DEBUG_H
- // this makes sure that whenever this header is included
- // the accompanying OBJ file is linked in as well
- #pragma comment(linker,"/include:___DebugIncludeInLink1")
- /**
- \class Debug debug.h <rts/debug.h>
-
- \brief Debug module main class (singleton).
- */
- class Debug
- {
- // necessary because all debug commands operate directly on this class
- friend class DebugCmdInterfaceDebug;
- // necessary because exception handler needs direct access
- friend class DebugExceptionhandler;
- public:
- enum
- {
- /// maximum number of times a check can be hit before it is turned off
- MAX_CHECK_HITS = 20
- };
- /**
- \brief HRESULT translator callback function type.
-
- See \ref Debug::AddHResultTranslator for more information.
- \param debug Debug instance where info can be written to
- \param hresult current HRESULT value
- \param user user value passed into AddHResultTranslator
- \return true if value translated and no more translators should be called,
- false if next translator should be tried
- */
- typedef bool (*HResultTranslator)(Debug &debug, long hresult, void *user);
- /**
- \class MemDump debug.h <rts/debug.h>
- \brief Helper class for performing a raw memory dump.
- Can be used directly in the output stream, e.g.
- \code
- DLOG( "This is 16 bytes of memory:\n" << Debug::MemDump::Raw(&somePointer,16) );
- \endcode
- */
- class MemDump
- {
- // necessary because Debug needs access to the following private members
- friend Debug;
-
- const unsigned char *m_startPtr; ///< start dumping with this address
- unsigned m_numItems; ///< dump the given number of items
- unsigned m_bytePerItem; ///< determines the number of bytes per item (1. 2 or 4)
- bool m_absAddr; ///< show absolute addresses (true) or relative addresses (false)
- bool m_withChars; ///< show printable characters on right side of dump (true) or not (false)
-
- // constructor is private on purpose so that nobody can
- // create instances of this class except the static functions
- // provided herein
- MemDump(const void *ptr, unsigned num, unsigned bpi, bool absAddr, bool withChars):
- m_startPtr((const unsigned char *)ptr), m_numItems(num),
- m_bytePerItem(bpi), m_absAddr(absAddr), m_withChars(withChars) {}
- public:
- /**
- Creates a memory dump descriptor.
- \param startPtr address to start dump from
- \param numItems number of items (usually bytes) to dump
- \param bytePerItem number of bytes per item (usually 1)
- */
- static MemDump Raw(const void *startPtr, unsigned numItems, unsigned bytePerItem=1)
- {
- return MemDump(startPtr,numItems,bytePerItem,true,false);
- }
- /**
- Creates a memory dump descriptor with relative addresses.
- \param startPtr address to start dump from
- \param numItems number of items (usually bytes) to dump
- \param bytePerItem number of bytes per item (usually 1)
- */
- static MemDump RawRel(const void *startPtr, unsigned numItems, unsigned bytePerItem=1)
- {
- return MemDump(startPtr,numItems,bytePerItem,false,false);
- }
- /**
- Creates a memory dump descriptor that dumps out ASCII chars as well.
- \param startPtr address to start dump from
- \param numItems number of items (usually bytes) to dump
- \param bytePerItem number of bytes per item (usually 1)
- */
- static MemDump Char(const void *startPtr, unsigned numItems, unsigned bytePerItem=1)
- {
- return MemDump(startPtr,numItems,bytePerItem,true,true);
- }
- /**
- Creates a memory dump descriptor with relative addresses that dumps out ASCII chars as well.
- \param startPtr address to start dump from
- \param numItems number of items (usually bytes) to dump
- \param bytePerItem number of bytes per item (usually 1)
- */
- static MemDump CharRel(const void *startPtr, unsigned numItems, unsigned bytePerItem=1)
- {
- return MemDump(startPtr,numItems,bytePerItem,false,true);
- }
- };
- /**
- \class HResult debug.h <rts/debug.h>
- \brief Helper class for writing HRESULTs to the debug stream.
- Can be used directly in the output stream, e.g.
- \code
- DLOG( "My HResult is: " << Debug::HResult(SomeHRESULTValue) << "\n" );
- \endcode
- The most interesting thing about HRESULTs is that custom HRESULT translators
- can be added or removed during runtime, see \ref Debug::AddHResultTranslator for more
- information.
- */
- class HResult
- {
- // necessary because Debug needs access to the following private members
- friend Debug;
-
- long m_hresult; ///< HRESULT value
-
- public:
- /**
- Creates a HRESULT descriptor.
- \param hresult HRESULT value (checked, Windows declares HRESULT as typedef long)
- */
- explicit HResult(long hresult): m_hresult(hresult) {}
- };
- /** \internal
-
- \brief Helper class for adding log group descriptions.
- */
- class LogDescription
- {
- // sorry, no copies or assignments
- LogDescription(const LogDescription&);
- LogDescription& operator=(const LogDescription&);
- public:
- /** \internal
- Adds a description for a logging file/group.
- \param fileOrGroup filename or logging group (see \ref Debug::LogBegin)
- \param description descriptive text for logging file/group
- */
- LogDescription(const char *fileOrGroup, const char *description);
- };
- /**
- \brief Switches integer output to hexadecimal format.
- */
- class Hex {};
-
- /// \internal Performs actual switch to hexadecimal format.
- Debug& operator<<(Hex &)
- {
- SetPrefixAndRadix("0x",16);
- return *this;
- }
- /**
- \brief Switches integer output to decimal format.
- */
- class Dec {};
- /// \internal Performs actuals switch to decimal format
- Debug& operator<<(Dec &)
- {
- SetPrefixAndRadix("",10);
- return *this;
- }
- /**
- \brief Switches integer output to binary format.
- */
- class Bin {};
- /// \internal Performs actuals switch to binary format
- Debug& operator<<(Bin &)
- {
- SetPrefixAndRadix("%",2);
- return *this;
- }
- /**
- \brief Sets output width for the next insertion.
- */
- class Width
- {
- // necessary because Debug needs access to the following private members
- friend Debug;
- int m_width; ///< output width
- public:
- /// \brief Sets new output width (next insertion only).
- explicit Width(int width): m_width(width) {}
- };
- /// \internal Performs actuals width switch
- Debug& operator<<(Width &w)
- {
- m_width=w.m_width;
- return *this;
- }
- /**
- \brief Sets new fill character.
- */
- class FillChar
- {
- // necessary because Debug needs access to the following private members
- friend Debug;
- char m_fill; ///< fill character
- public:
- /// \brief Sets new fill character.
- explicit FillChar(char ch=' '): m_fill(ch) {}
- };
- /// \internal Performs actuals setting of fill char
- Debug& operator<<(FillChar &c)
- {
- m_fillChar=c.m_fill;
- return *this;
- }
- /**
- \brief Repeats a given character N times.
- */
- class RepeatChar
- {
- // necessary because Debug needs access to the following private members
- friend Debug;
- char m_char; ///< character
- int m_count; ///< repeat count
- public:
- /// \brief Repeats a given character N times
- explicit RepeatChar(char ch, int count): m_char(ch), m_count(count) {}
- };
- /// \internal Performs actuals repeating of char
- Debug& operator<<(RepeatChar &c);
- /**
- \brief Old printf style formatting.
- \note Do not use this helper class for new code. It is mainly here
- to get the old code base adapted to the new debug module more quickly.
- */
- class Format
- {
- // necessary because Debug needs access to the following private members
- friend Debug;
- // no CC, AOp
- Format(const Format &);
- Format& operator=(const Format&);
- char m_buffer[512]; ///< this contains the string to write \note Fixed size buffer!
- public:
- /// \brief Old printf style formatting.
- explicit Format(const char *format, ...);
- };
- /// \internal Writes printf style formatted string to debug log.
- Debug& operator<<(const Format &f)
- {
- operator<<(f.m_buffer);
- return *this;
- }
-
- // this is necessary because LogDescription needs to call AddLogGroup
- friend class LogDescription;
-
- /** \internal
-
- \brief Performs logical cleanup.
- */
- ~Debug();
- /**
- \brief Installs exception handler for current thread.
- For the main thread this is already done, but for any additional
- threads being created this function must be called.
- */
- static void InstallExceptionHandler(void);
- /** \internal
-
- \brief Helper function for skipping over disabled asserts and logs.
- This function simply records the address it has been called from. If
- an assert or other function is disabled this function returns true,
- false otherwise.
-
- @todo_opt Change so that instead of returning true the call to this
- function is directly removed from the calling code
- \return true if next assert/log should be skipped, false otherwise
- */
- static bool SkipNext(void);
- /** \internal
-
- \brief Helper function which gets called if an assertion fails.
-
- Starts building the assert string which will then be send to the active
- output destinations. SkipNext must be called before calling this function
- since this function also associates the most recent SkipNext call with
- the current assertion.
- \param file file that contains DASSERT or DASSERT_MSG macro
- \param line line where assert macro can be found
- \param expr expression that triggered the assertion, NULL for 'general failure' (\ref DFAIL)
- \return reference to Debug instance
- */
- static Debug &AssertBegin(const char *file, int line, const char *expr);
- /** \internal
- \brief Displays assertion window.
- Depending on the user feedback (abort, retry, ignore) the program then
- either aborts or continues. This function is to be used as the final
- call in a debug message stream.
- \return false (always)
- */
- bool AssertDone(void);
- /** \internal
-
- \brief Helper function which gets called if a check fails.
-
- Starts building the assert string which will then be send to the active
- output destinations. SkipNext must be called before calling this function
- since this function also associates the most recent SkipNext call with
- the current check.
- \param file file that contains DCHECK or DCHECK_MSG macro
- \param line line where check macro can be found
- \param expr expression that triggered the assertion
- \return reference to Debug instance
- */
- static Debug &CheckBegin(const char *file, int line, const char *expr);
- /** \internal
- \brief Flushes current 'check' message.
- This function is to be used as the final call in a debug message stream.
- \return false (always)
- */
- bool CheckDone(void);
- /** \internal
-
- \brief Helper function which gets when writing data to the output log.
-
- Starts building the log string which will then be send to the active
- output destinations. SkipNext must be called before calling this function
- since this function also associates the most recent SkipNext call with
- the current log group.
- \param fileOrGroup current file or group the following log data is for
- \return reference to Debug instance
- */
- static Debug &LogBegin(const char *fileOrGroup);
- /** \internal
- \brief Flushes current 'log' message.
- This function is to be used as the final call in a debug message stream.
- \return false (always)
- */
- bool LogDone(void);
- /** \internal
-
- \brief Helper function which gets called on crash.
-
- Starts building the crash string which will then be send to the active
- output destinations.
- \param file file that contains DCRASH or DCRASH_RELEASE macro, if NULL
- then no file info is given (used by DCRASH_RELEASE in release
- builds)
- \param line line where crash macro can be found, 0 if no line info should
- be given
- \return reference to Debug instance
- */
- static Debug &CrashBegin(const char *file, int line);
- /** \internal
- \brief Exits program with a 'crash' message.
- This function is to be used as the final call in a debug message stream.
- \param die true if module should exit after displaying message, false if
- the user should have the choice
- \return false (always)
- */
- bool CrashDone(bool die);
- /** \internal
- \brief Write string to output log.
- \param str string to write
- \return *this
- */
- Debug& operator<<(const char *str);
- /** \internal
- \brief Define prefix and radix for integer output.
- \param prefix prefix to use (typically "" or "0x")
- \param radix radix to use (typically 10 or 16)
- */
- void SetPrefixAndRadix(const char *prefix, int radix);
- /** \internal
- \brief Write signed integer to output log.
- \param val signed integer
- \return *this
- */
- Debug& operator<<(int val);
- /** \internal
- \brief Write unsigned integer to output log.
- \param val unsigned integer
- \return *this
- */
- Debug& operator<<(unsigned val);
- /** \internal
- \brief Write signed long to output log.
- \param val signed long
- \return *this
- */
- Debug& operator<<(long val);
- /** \internal
- \brief Write unsigned long to output log.
- \param val unsigned long
- \return *this
- */
- Debug& operator<<(unsigned long val);
- /** \internal
- \brief Write boolean value to output log.
- \param val bool
- \return *this
- */
- Debug& operator<<(bool val);
- /** \internal
- \brief Write float value to output log.
- \param val float
- \return *this
- */
- Debug& operator<<(float val);
- /** \internal
- \brief Write double precision float to output log.
- \param val double
- \return *this
- */
- Debug& operator<<(double val);
- /** \internal
- \brief Write signed short integer to output log.
- \param val signed short integer
- \return *this
- */
- Debug& operator<<(short val);
- /** \internal
- \brief Write unsigned short integer to output log.
- \param val unsigned short integer
- \return *this
- */
- Debug& operator<<(unsigned short val);
- /** \internal
- \brief Write signed 64 bit integer to output log.
- \param val signed 64 bit integer
- \return *this
- */
- Debug& operator<<(__int64 val);
- /** \internal
- \brief Write unsigned 64 bit integer to output log.
- \param val unsigned 64 bit integer
- \return *this
- */
- Debug& operator<<(unsigned __int64 val);
- /** \internal
- \brief Write pointer address to output log.
- \param ptr pointer address
- \return *this
- */
- Debug& operator<<(const void *ptr);
- /** \internal
- \brief Write memory dump to output log.
- \param dump MemDump descriptor, defines what range of memory to dump
- \return *this
- */
- Debug& operator<<(const MemDump &dump);
- /** \internal
- \brief Write HRESULT value to output log.
- \param hres HResult descriptor
- \return *this
- */
- Debug& operator<<(HResult hres);
- /** \internal
- \brief Determines if a log file/group is active or not.
- \param fileOrGroup Name of source file or group to check for. If the
- string contains any forward or backslashes then anything
- before them is ignored. If the then remaining string
- contains any dots anything beyond the first dot is ignored
- as well.
- \return true if logging is enabled, false if not
- */
- static bool IsLogEnabled(const char *fileOrGroup);
- /**
- \brief Adds a HRESULT translator.
- A HRESULT translator is called whenever a HResult descriptor is passed into
- the Debug log stream. Such a translator can translate the numeric value
- into something more meaningful.
- Translators are differentiated by both function address and user pointer. There
- is however no harm in adding the same translator/user pointer pair twice.
- \param prio priority, translators with a higher priority get called first
- \param func translator address
- \param user optional user pointer which will be passed to the given translator
- \see RemoveHResultTranslator
- */
- static void AddHResultTranslator(unsigned prio, HResultTranslator func, void *user=0);
- /**
- \brief Removes a HRESULT translator.
- If the translator/user pointer pair does not exist nothing is done.
- \param func translator address
- \param user optional user pointer
- \see AddHResultTranslator
- */
- static void RemoveHResultTranslator(HResultTranslator func, void *user=0);
- /**
- \brief Registers a new I/O class factory function.
- This is typically used internally by the DEBUG_IMPLEMENT_IO_INTERFACE
- macro. If there is already an I/O class with the same name registered
- the new one overwrites the old.
- \param io_id name of I/O class as it should be registered with Debug module
- \param descr short class description
- \param func factory function
- \return true (so function can be used in static initializers)
- */
- static bool AddIOFactory(const char *io_id, const char *descr,
- DebugIOInterface* (*func)(void));
- /**
- \brief Adds a new command group.
- If the command group already exists the new command interface is added at
- the end of the list. A command issued for that group is first passed
- to the 'old' command interface. If that DebugCmdInterface::Execute call
- fails the command is passed on to the next interface within the same
- command group.
- The only exception is the 'help' command. Here all Execute functions are
- always called.
- Ownership of the interface pointer is passed to the Debug module i.e. the
- interface is destroyed when the Debug module shuts down (unless the
- interface is removed using RemoveCommands).
- \param cmdgroup command group this interface implements
- \param cmdif command group interface instance
- \return true (so function can be used in static initializers)
- */
- static bool AddCommands(const char *cmdgroup, DebugCmdInterface *cmdif);
- /**
- \brief Removes a command group.
- \param cmdif command group interface that will be removed
- */
- static void RemoveCommands(DebugCmdInterface *cmdif);
- /**
- \brief Issues a debug command.
- \param cmd command to execute
- */
- static void Command(const char *cmd);
- /**
- \brief Update method, must be called on a regular basis.
-
- Scans I/O classes for new command input and processes it.
- */
- static void Update(void);
- /** \internal
- \brief Simple recursive pattern matcher.
- \param str string to match
- \param pattern pattern, only wildcard valid is '*'
- \return true if string matches pattern, false if not
- */
- static bool SimpleMatch(const char *str, const char *pattern);
- /**
- \brief Tell debug module about build info.
- All these strings are free form and can be up to 63 chars long.
- \param version official version
- \param internalVersion internal version
- \param buildDate build date & time
- */
- static void SetBuildInfo(const char *version,
- const char *internalVersion,
- const char *buildDate);
- /**
- \brief Write build information into log.
- */
- void WriteBuildInfo(void);
- private:
- // no assignment, no copy constructor
- Debug(const Debug&);
- Debug& operator=(const Debug&);
- /** \internal
-
- Undocumented default constructor. Initializes debugging library.
- We can make this private as well so nobody accidently tries to create
- a Debug instance. Actually this function does not do anything -
- initialization is rather performed by PreStaticInit() and
- PostStaticInit().
- */
- Debug(void);
- /** \internal
-
- This function gets called before any static C++ symbols are
- initialized. Code herein must be extremely careful because all
- global C++ instances are not initialized yet.
- */
- static void PreStaticInit(void);
- /** \internal
-
- This function gets called after all static C++ symbols have
- been initialized.
- */
- static void PostStaticInit(void);
- /** \internal
- This function gets called if the program exists. Use this
- function for any cleanup purposes (not the destructor, it
- might get called too early).
- */
- static void StaticExit(void);
- /** \internal
-
- The only debug instance. Actually not used for anything
- except as magic first parameter for overloaded stream operators.
- */
- static Debug Instance;
- /** \internal
-
- Helper variable for putting PreStaticInit() into the MSVC
- startup list.
- */
- static void *PreStatic;
- /** \internal
-
- Helper variable for putting PostStaticInit() into the MSVC
- startup list.
- */
- static void *PostStatic;
- /// \internal HResult translator vector entry
- struct HResultTranslatorEntry
- {
- /// priority
- unsigned prio;
- /// translator function
- HResultTranslator func;
- /// user pointer
- void *user;
- };
- /// \internal HResult translator vector
- HResultTranslatorEntry *hrTranslators;
- /// \internal number of HResult translators
- unsigned numHrTranslators;
- /// \internal I/O class/factory list entry
- struct IOFactoryListEntry
- {
- /// pointer to next entry in list
- IOFactoryListEntry *next;
- /// I/O ID
- const char *ioID;
- /// I/O description
- const char *descr;
- /// factory function
- DebugIOInterface* (*factory)(void);
- /// I/O interface (may be NULL)
- DebugIOInterface *io;
- /// input buffer
- char *input;
- /// used size of input buffer
- unsigned inputUsed;
- /// allocated size of input buffer
- unsigned inputAlloc;
- };
- /** \internal
-
- First I/O factory list entry. A singly linked list is
- okay for this because looking up I/O IDs is not
- time critical.
- */
- IOFactoryListEntry *firstIOFactory;
- /// \internal command interface list entry
- struct CmdInterfaceListEntry
- {
- /// pointer to next entry in list
- CmdInterfaceListEntry *next;
- /// command group
- const char *group;
- /// interface pointer
- DebugCmdInterface *cmdif;
- };
- /** \internal
-
- First command interface list entry. A singly linked list is
- okay for this because looking up command groups is not
- time critical.
- */
- CmdInterfaceListEntry *firstCmdGroup;
- /// \internal current stack frame (used by SkipNext)
- static unsigned curStackFrame;
- /** \internal
-
- Bit mask for frame entry types. Implemented as a bit
- mask since it is also used for the inclusion/exclusion
- list where a single pattern can apply to more than
- one type.
- */
- enum
- {
- /// assert
- FrameTypeAssert = 0x00000001,
- /// check
- FrameTypeCheck = 0x00000002,
- /// log
- FrameTypeLog = 0x00000004
- };
- /** \internal
- List of possible statuses for a frame hash entry.
- */
- enum FrameStatus
- {
- /// unknown, must check
- Unknown = 0,
- /// skip this frame
- Skip,
- /// do not skip this frame
- NoSkip
- };
- /** \internal
- \brief Hash table entry for mapping stack frame addresses to
- asserts/checks/logs.
- */
- struct FrameHashEntry
- {
- /// pointer to next entry with same hash
- FrameHashEntry *next;
- /// frame address
- unsigned frameAddr;
- /// frame type (FrameTypeAssert, FrameTypeCheck, or FrameTypeLog)
- unsigned frameType;
- /// file (or group if log)
- const char *fileOrGroup;
- /// line number (undefined for logs)
- int line;
- /// number of times this frame has been hit
- int hits;
- /// frame status
- FrameStatus status;
- };
- /// \internal initial frame hash size (prime number)
- enum { FRAME_HASH_SIZE = 10007 };
- /// \internal frame hash pointers
- FrameHashEntry *frameHash[FRAME_HASH_SIZE];
- /// \internal number of FrameHashEntry structures to allocate at one time
- enum { FRAME_HASH_ALLOC_COUNT = 100 };
- /// \internal next unused FrameHashEntry structure
- FrameHashEntry *nextUnusedFrameHash;
- /// \internal number of available FrameHashEntry structures
- unsigned numAvailableFrameHash;
- /** \internal
- Look up given frame address.
- \param addr frame address
- \return FrameHashEntry found or 0 if nothing found
- */
- __forceinline FrameHashEntry *LookupFrame(unsigned addr)
- {
- for (FrameHashEntry *e=frameHash[addr%FRAME_HASH_SIZE];e;e=e->next)
- if (e->frameAddr==addr)
- return e;
- return 0;
- }
- /** \internal
-
- Add frame address entry (entry must not exist yet). If
- a log frame is added then a corresponding entry is added
- to the list of known log groups as well.
- \param addr frame address
- \param type frame type
- \param fileOrGroup file (or group name)
- \param line line number
- \return the entry just added
- */
- FrameHashEntry *AddFrameEntry(unsigned addr, unsigned type,
- const char *fileOrGroup, int line);
- /** \internal
- Updates the frames status variable depending on the current
- pattern list.
- \param entry entry that needs to be updated
- */
- void UpdateFrameStatus(FrameHashEntry &entry);
- /** \internal
- Combines LookupFrame, AddFrameEntry and UpdateFrameStatus.
- \param addr frame address
- \param type frame type
- \param fileOrGroup file (or group name)
- \param line line number
- \return the entry just added (or the already existing entry)
- */
- FrameHashEntry *GetFrameEntry(unsigned addr, unsigned type,
- const char *fileOrGroup, int line)
- {
- FrameHashEntry *e=LookupFrame(addr);
- if (!e)
- e=AddFrameEntry(addr,type,fileOrGroup,line);
- if (e->status==Unknown)
- UpdateFrameStatus(*e);
- return e;
- }
- /** \internal
- \brief List of known logs.
-
- A singly linked list is
- okay for this because looking up log groups happens only
- if a new stack frame entry is added (which happens only
- once for each log command).
- */
- struct KnownLogGroupList
- {
- /// next entry
- KnownLogGroupList *next;
- /// name of log group (dynamically allocated memory)
- char *nameGroup;
- /// log description (if any)
- const char *descr;
- };
- /// \internal first log group list entry
- KnownLogGroupList *firstLogGroup;
- /** \internal
- Adds a log group (and optionally description) to the list
- of known groups. If a group with that name already exists
- nothing is done. Takes care of stripping path and extension
- of the passed in group name (if it's a file name).
- Returns translated group name.
- \param fileOrGroup file or log group
- \param descr description, may be NULL
- \return translated log group name
- */
- const char *AddLogGroup(const char *fileOrGroup, const char *descr);
- /// \internal I/O buffers for all I/O string types
- struct
- {
- /// buffer
- char *buffer;
- /// used buffer size
- unsigned used;
- /// allocated buffer size
- unsigned alloc;
- /// has last character been CR?
- bool lastWasCR;
- } ioBuffer[DebugIOInterface::StringType::MAX];
- /// \internal current I/O string type we're writing
- DebugIOInterface::StringType curType;
- /// \internal current I/O string source (fixed size, careful!)
- char curSource[256];
- /// \internal used to enable/disable all asserts/checks/logs
- int disableAssertsEtc;
- /** \internal
-
- Starts new output stream with the given type and source.
- \param type string type
- \param fmt wsprintf format string
- */
- void StartOutput(DebugIOInterface::StringType type, const char *fmt, ...);
- /** \internal
- Adds the given string to the currently active output buffer.
- \param str string
- \param len string length
- */
- void AddOutput(const char *str, unsigned len);
- /** \internal
-
- Flushes current I/O buffer to all output handlers.
- \param defaultLog if true and no I/O class is active then data
- is written to default.log
- */
- void FlushOutput(bool defaultLog=true);
- /// \internal pointer to currently active frame
- FrameHashEntry *curFrameEntry;
- /// \internal pattern list entry
- struct PatternListEntry
- {
- /// next entry
- PatternListEntry *next;
- /// frame type(s)
- unsigned frameTypes;
- /// active (true) or inactive (false)?
- bool isActive;
- /// pattern itself (dynamic allocated memory)
- char *pattern;
- };
- /** \internal
- First pattern list list entry. A singly linked list is
- okay for this because checking patterns is a costly
- operation anyway and is therefore cached.
- */
- PatternListEntry *firstPatternEntry;
- /// \internal last pattern list entry for fast additions to list at end
- PatternListEntry *lastPatternEntry;
- /** \internal
- Adds a new pattern list entry. This function does not check if
- a matching pattern entry exists already.
- \param types frame type(s)
- \param isActive active (true) or inactive (false)?
- \param pattern pattern itself
- */
- void AddPatternEntry(unsigned types, bool isActive, const char *pattern);
- /** \internal
- Executes the given command.
- \param cmdstart start of command
- \param cmdend end of command (not including this character)
- */
- void ExecCommand(const char *cmdstart, const char *cmdend);
- /** \internal
- \brief Checks if main program is running windowed or not.
-
- If the decisison can not be made an windowed program is assumed.
- \return true if windowed, false if full screen
- */
- bool IsWindowed(void);
- /// \internal name of current command group
- char curCommandGroup[100];
- /// \internal if true then always flush after each line written
- bool alwaysFlush;
- /// \internal if true then put timestamps before each new line
- bool timeStamp;
- /// \internal the one and only stack walker
- DebugStackwalk m_stackWalk;
- /// \internal current integer prefix to use
- char m_prefix[16];
- /// \internal current integer radix to use
- int m_radix;
- /// \internal official version
- char m_version[64];
- /// \internal internal version
- char m_intVersion[64];
- /// \internal build date/time
- char m_buildDate[64];
- /// \internal output width
- int m_width;
- /// \internal fill char
- char m_fillChar;
-
- /// \internal <0 if fullscreen, >0 if windowed, ==0 if not checked yet
- char m_isWindowed;
- };
- /// \addtogroup debug_fn Debugging functions
- ///@{
- /**
- \brief Determines default commands to be executed at startup.
- This function returns a list of default commands which are executed on
- startup if no .dbgcmd file is read.
- Currently this function returns:
- \code
- "debug.io flat add"
- \endcode
- In order to provide a different set of commands simply put another
- version of DebugGetDefaultCommands in a CPP file. This is basically
- identical to having a .dbgcmd file in the current directory. For some
- situations (e.g. passing EXEs off to QA) it is however safer to have
- these startup commands build into the EXE itself rather than relying
- on QA having the right .dbgcmd file in place.
- As an example a new version of this function might return:
- \code
- "debug.io flat add\nio flat copy q:\logfiles\n"
- \endcode
- \return list of commands, separated by \\n
- \note This function is executed after all static variables have been initialized.
- */
- const char *DebugGetDefaultCommands(void);
- ///@} end of debug_fn group
- #endif // DEBUG_DEBUG_H
|