diff options
Diffstat (limited to 'external/vpc/public/tier0/dbg.h')
| -rw-r--r-- | external/vpc/public/tier0/dbg.h | 716 |
1 files changed, 716 insertions, 0 deletions
diff --git a/external/vpc/public/tier0/dbg.h b/external/vpc/public/tier0/dbg.h new file mode 100644 index 0000000..2e54a47 --- /dev/null +++ b/external/vpc/public/tier0/dbg.h @@ -0,0 +1,716 @@ +//===== Copyright (c) Valve Corporation, All rights reserved. ========// +// +// Purpose: +// +// $NoKeywords: $ +// +//====================================================================// +#ifndef DBG_H +#define DBG_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "tier0/platform.h" +#include "tier0/basetypes.h" +#include "dbgflag.h" +#include "logging.h" +#include <math.h> +#include <stdio.h> +#include <stdarg.h> + +//----------------------------------------------------------------------------- +// dll export stuff +//----------------------------------------------------------------------------- + +class Color; + + +//----------------------------------------------------------------------------- +// Usage model for the Dbg library +// +// 1. Assertions. +// +// Assertions are used to detect and warn about invalid states +// +// To use an assertion, use +// +// Assert( (f == 5) ); +// AssertMsg( (f == 5), ("F needs to be %d here!\n", 5) ); +// AssertFunc( (f == 5), BadFunc() ); +// AssertEquals( f, 5 ); +// AssertFloatEquals( f, 5.0f, 1e-3 ); +// +// The first will simply report that an assertion failed on a particular +// code file and line. The second version will display a print-f formatted message +// along with the file and line, the third will display a generic message and +// will also cause the function BadFunc to be executed, and the last two +// will report an error if f is not equal to 5 (the last one asserts within +// a particular tolerance). +// +// 2. Code activation +// +// To cause code to be run only in debug builds, use DBG_CODE: +// An example is below. +// +// DBG_CODE( +// { +// int x = 5; +// ++x; +// } +// ); +// +// Code can be activated based on the dynamic spew groups also. Use +// +// DBG_DCODE( "group", level, +// { int x = 5; ++x; } +// ); +// +// 3. Breaking into the debugger. +// +// To cause an unconditional break into the debugger in debug builds only, use DBG_BREAK +// +// DBG_BREAK(); +// +// You can force a break in any build (release or debug) using +// +// DebuggerBreak(); +//----------------------------------------------------------------------------- + +PLATFORM_INTERFACE void _ExitOnFatalAssert( const tchar* pFile, int line ); + +#if defined( DBGFLAG_STRINGS_STRIP ) +#define DbgFlagMacro_ExitOnFatalAssert( pFile, line ) _ExitOnFatalAssert( "", 0 ) +#else +#define DbgFlagMacro_ExitOnFatalAssert( pFile, line ) _ExitOnFatalAssert( pFile, line ) +#endif + +PLATFORM_INTERFACE bool ShouldUseNewAssertDialog(); + +PLATFORM_INTERFACE bool SetupWin32ConsoleIO(); + +// Returns true if they want to break in the debugger. +PLATFORM_INTERFACE bool DoNewAssertDialog( const tchar *pFile, int line, const tchar *pExpression ); + +#if defined( DBGFLAG_STRINGS_STRIP ) +#define DbgFlagMacro_DoNewAssertDialog( pFile, line, pExpression ) DoNewAssertDialog( "", 0, "" ) +#else +#define DbgFlagMacro_DoNewAssertDialog( pFile, line, pExpression ) DoNewAssertDialog( pFile, line, pExpression ) +#endif + +/* Used to define macros, never use these directly. */ + +#ifdef _PREFAST_ + // When doing /analyze builds define the assert macros to be __analysis_assume. This tells + // the compiler to assume that the condition is true, which helps to suppress many + // warnings. This define is done in debug and release builds, but debug builds should be + // preferred for static analysis because some asserts are compiled out in release. + // The unfortunate !! is necessary because otherwise /analyze is incapable of evaluating + // all of the logical expressions that the regular compiler can handle. + #define _AssertMsg( _exp, _msg, _executeExp, _bFatal ) __analysis_assume( !!(_exp) ) + #define _AssertMsgOnce( _exp, _msg, _bFatal ) __analysis_assume( !!(_exp) ) + // Force asserts on for /analyze so that we get a __analysis_assume of all of the constraints. + #define DBGFLAG_ASSERT + #define DBGFLAG_ASSERTFATAL +#else + #define _AssertMsg( _exp, _msg, _executeExp, _bFatal ) \ + do { \ + if (!(_exp)) \ + { \ + LoggingResponse_t ret = Log_Assert( "%s (%d) : %s\n", __TFILE__, __LINE__, _msg ); \ + _executeExp; \ + if ( ret == LR_DEBUGGER ) \ + { \ + if ( !ShouldUseNewAssertDialog() || DbgFlagMacro_DoNewAssertDialog( __TFILE__, __LINE__, _msg ) ) \ + DebuggerBreak(); \ + if ( _bFatal ) \ + DbgFlagMacro_ExitOnFatalAssert( __TFILE__, __LINE__ ); \ + } \ + } \ + } while (0) + + #define _AssertMsgOnce( _exp, _msg, _bFatal ) \ + do { \ + static bool fAsserted; \ + if (!fAsserted ) \ + { \ + _AssertMsg( _exp, _msg, (fAsserted = true), _bFatal ); \ + } \ + } while (0) +#endif + +/* Spew macros... */ + +// AssertFatal macros +// AssertFatal is used to detect an unrecoverable error condition. +// If enabled, it may display an assert dialog (if DBGFLAG_ASSERTDLG is turned on or running under the debugger), +// and always terminates the application + +#ifdef DBGFLAG_ASSERTFATAL + +#define AssertFatal( _exp ) _AssertMsg( _exp, _T("Assertion Failed: ") _T(#_exp), ((void)0), true ) +#define AssertFatalOnce( _exp ) _AssertMsgOnce( _exp, _T("Assertion Failed: ") _T(#_exp), true ) +#define AssertFatalMsg( _exp, _msg ) _AssertMsg( _exp, _msg, ((void)0), true ) +#define AssertFatalMsgOnce( _exp, _msg ) _AssertMsgOnce( _exp, _msg, true ) +#define AssertFatalFunc( _exp, _f ) _AssertMsg( _exp, _T("Assertion Failed: " _T(#_exp), _f, true ) +#define AssertFatalEquals( _exp, _expectedValue ) AssertFatalMsg2( (_exp) == (_expectedValue), _T("Expected %d but got %d!"), (_expectedValue), (_exp) ) +#define AssertFatalFloatEquals( _exp, _expectedValue, _tol ) AssertFatalMsg2( fabs((_exp) - (_expectedValue)) <= (_tol), _T("Expected %f but got %f!"), (_expectedValue), (_exp) ) +#define VerifyFatal( _exp ) AssertFatal( _exp ) +#define VerifyEqualsFatal( _exp, _expectedValue ) AssertFatalEquals( _exp, _expectedValue ) + +#define AssertFatalMsg1( _exp, _msg, a1 ) AssertFatalMsg( _exp, (const tchar *)(CDbgFmtMsg( _msg, a1 ))) +#define AssertFatalMsg2( _exp, _msg, a1, a2 ) AssertFatalMsg( _exp, (const tchar *)(CDbgFmtMsg( _msg, a1, a2 ))) +#define AssertFatalMsg3( _exp, _msg, a1, a2, a3 ) AssertFatalMsg( _exp, (const tchar *)(CDbgFmtMsg( _msg, a1, a2, a3 ))) +#define AssertFatalMsg4( _exp, _msg, a1, a2, a3, a4 ) AssertFatalMsg( _exp, (const tchar *)(CDbgFmtMsg( _msg, a1, a2, a3, a4 ))) +#define AssertFatalMsg5( _exp, _msg, a1, a2, a3, a4, a5 ) AssertFatalMsg( _exp, (const tchar *)(CDbgFmtMsg( _msg, a1, a2, a3, a4, a5 ))) +#define AssertFatalMsg6( _exp, _msg, a1, a2, a3, a4, a5, a6 ) AssertFatalMsg( _exp, (const tchar *)(CDbgFmtMsg( _msg, a1, a2, a3, a4, a5, a6 ))) +#define AssertFatalMsg6( _exp, _msg, a1, a2, a3, a4, a5, a6 ) AssertFatalMsg( _exp, (const tchar *)(CDbgFmtMsg( _msg, a1, a2, a3, a4, a5, a6 ))) +#define AssertFatalMsg7( _exp, _msg, a1, a2, a3, a4, a5, a6, a7 ) AssertFatalMsg( _exp, (const tchar *)(CDbgFmtMsg( _msg, a1, a2, a3, a4, a5, a6, a7 ))) +#define AssertFatalMsg8( _exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8 ) AssertFatalMsg( _exp, (const tchar *)(CDbgFmtMsg( _msg, a1, a2, a3, a4, a5, a6, a7, a8 ))) +#define AssertFatalMsg9( _exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8, a9 ) AssertFatalMsg( _exp, (const tchar *)(CDbgFmtMsg( _msg, a1, a2, a3, a4, a5, a6, a7, a8, a9 ))) + +#else // DBGFLAG_ASSERTFATAL + +#define AssertFatal( _exp ) ((void)0) +#define AssertFatalOnce( _exp ) ((void)0) +#define AssertFatalMsg( _exp, _msg ) ((void)0) +#define AssertFatalMsgOnce( _exp, _msg ) ((void)0) +#define AssertFatalFunc( _exp, _f ) ((void)0) +#define AssertFatalEquals( _exp, _expectedValue ) ((void)0) +#define AssertFatalFloatEquals( _exp, _expectedValue, _tol ) ((void)0) +#define VerifyFatal( _exp ) (_exp) +#define VerifyEqualsFatal( _exp, _expectedValue ) (_exp) + +#define AssertFatalMsg1( _exp, _msg, a1 ) ((void)0) +#define AssertFatalMsg2( _exp, _msg, a1, a2 ) ((void)0) +#define AssertFatalMsg3( _exp, _msg, a1, a2, a3 ) ((void)0) +#define AssertFatalMsg4( _exp, _msg, a1, a2, a3, a4 ) ((void)0) +#define AssertFatalMsg5( _exp, _msg, a1, a2, a3, a4, a5 ) ((void)0) +#define AssertFatalMsg6( _exp, _msg, a1, a2, a3, a4, a5, a6 ) ((void)0) +#define AssertFatalMsg6( _exp, _msg, a1, a2, a3, a4, a5, a6 ) ((void)0) +#define AssertFatalMsg7( _exp, _msg, a1, a2, a3, a4, a5, a6, a7 ) ((void)0) +#define AssertFatalMsg8( _exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8 ) ((void)0) +#define AssertFatalMsg9( _exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8, a9 ) ((void)0) + +#endif // DBGFLAG_ASSERTFATAL + +// lightweight assert macros: in theory, can be run in release without slowing it down +#if defined(_CERT) || defined(_RETAIL) +#define AssertAligned(PTR) +#else +# if defined( _X360 ) +# define AssertAligned(PTR) __twnei( intp(PTR) & 0xF, 0 ) // trap if not equal to immediate value; unsigned comparison +# elif defined( DBGFLAG_ASSERT ) +# define AssertAligned( adr ) Assert( ( ( ( intp ) ( adr ) ) & 0xf ) == 0 ) +# else +# define AssertAligned(PTR) +# endif +#endif + +// Assert macros +// Assert is used to detect an important but survivable error. +// It's only turned on when DBGFLAG_ASSERT is true. + +#ifdef DBGFLAG_ASSERT + +#define Assert( _exp ) _AssertMsg( _exp, _T("Assertion Failed: ") _T(#_exp), ((void)0), false ) +#define AssertMsg_( _exp, _msg ) _AssertMsg( _exp, _msg, ((void)0), false ) +#define AssertOnce( _exp ) _AssertMsgOnce( _exp, _T("Assertion Failed: ") _T(#_exp), false ) +#define AssertMsgOnce( _exp, _msg ) _AssertMsgOnce( _exp, _msg, false ) +#define AssertFunc( _exp, _f ) _AssertMsg( _exp, _T("Assertion Failed: ") _T(#_exp), _f, false ) +#define AssertEquals( _exp, _expectedValue ) AssertMsg2( (_exp) == (_expectedValue), _T("Expected %d but got %d!"), (_expectedValue), (_exp) ) +#define AssertFloatEquals( _exp, _expectedValue, _tol ) AssertMsg2( fabs((_exp) - (_expectedValue)) <= (_tol), _T("Expected %f but got %f!"), (_expectedValue), (_exp) ) +#define Verify( _exp ) Assert( _exp ) +#define VerifyEquals( _exp, _expectedValue ) AssertEquals( _exp, _expectedValue ) + +#define AssertMsg( _exp, _msg ) AssertMsg_( _exp, _T( _msg ) ) +#define AssertMsg1( _exp, _msg, a1 ) AssertMsg_( _exp, (const tchar *)(CDbgFmtMsg( _T( _msg ), a1 )) ) +#define AssertMsg2( _exp, _msg, a1, a2 ) AssertMsg_( _exp, (const tchar *)(CDbgFmtMsg( _T( _msg ), a1, a2 )) ) +#define AssertMsg3( _exp, _msg, a1, a2, a3 ) AssertMsg_( _exp, (const tchar *)(CDbgFmtMsg( _T( _msg ), a1, a2, a3 )) ) +#define AssertMsg4( _exp, _msg, a1, a2, a3, a4 ) AssertMsg_( _exp, (const tchar *)(CDbgFmtMsg( _T( _msg ), a1, a2, a3, a4 )) ) +#define AssertMsg5( _exp, _msg, a1, a2, a3, a4, a5 ) AssertMsg_( _exp, (const tchar *)(CDbgFmtMsg( _T( _msg ), a1, a2, a3, a4, a5 )) ) +#define AssertMsg6( _exp, _msg, a1, a2, a3, a4, a5, a6 ) AssertMsg_( _exp, (const tchar *)(CDbgFmtMsg( _T( _msg ), a1, a2, a3, a4, a5, a6 )) ) +#define AssertMsg7( _exp, _msg, a1, a2, a3, a4, a5, a6, a7 ) AssertMsg_( _exp, (const tchar *)(CDbgFmtMsg( _T( _msg ), a1, a2, a3, a4, a5, a6, a7 )) ) +#define AssertMsg8( _exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8 ) AssertMsg_( _exp, (const tchar *)(CDbgFmtMsg( _T( _msg ), a1, a2, a3, a4, a5, a6, a7, a8 )) ) +#define AssertMsg9( _exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8, a9 ) AssertMsg_( _exp, (const tchar *)(CDbgFmtMsg( _T( _msg ), a1, a2, a3, a4, a5, a6, a7, a8, a9 )) ) + +#else // DBGFLAG_ASSERT + +#define Assert( _exp ) ((void)0) +#define AssertOnce( _exp ) ((void)0) +#define AssertMsg( _exp, _msg ) ((void)0) +#define AssertMsgOnce( _exp, _msg ) ((void)0) +#define AssertFunc( _exp, _f ) ((void)0) +#define AssertEquals( _exp, _expectedValue ) ((void)0) +#define AssertFloatEquals( _exp, _expectedValue, _tol ) ((void)0) +#define Verify( _exp ) (_exp) +#define VerifyEquals( _exp, _expectedValue ) (_exp) + +#define AssertMsg1( _exp, _msg, a1 ) ((void)0) +#define AssertMsg2( _exp, _msg, a1, a2 ) ((void)0) +#define AssertMsg3( _exp, _msg, a1, a2, a3 ) ((void)0) +#define AssertMsg4( _exp, _msg, a1, a2, a3, a4 ) ((void)0) +#define AssertMsg5( _exp, _msg, a1, a2, a3, a4, a5 ) ((void)0) +#define AssertMsg6( _exp, _msg, a1, a2, a3, a4, a5, a6 ) ((void)0) +#define AssertMsg6( _exp, _msg, a1, a2, a3, a4, a5, a6 ) ((void)0) +#define AssertMsg7( _exp, _msg, a1, a2, a3, a4, a5, a6, a7 ) ((void)0) +#define AssertMsg8( _exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8 ) ((void)0) +#define AssertMsg9( _exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8, a9 ) ((void)0) + +#endif // DBGFLAG_ASSERT + +#define STRINGIFY_INTERNAL(x) #x +#define STRINGIFY(x) STRINGIFY_INTERNAL(x) + +#define FILE_LINE_FUNCTION_STRING __FILE__ "(" STRINGIFY(__LINE__) "):" __FUNCTION__ ":" +#define FILE_LINE_STRING __FILE__ "(" STRINGIFY(__LINE__) "):" +#define FUNCTION_LINE_STRING __FUNCTION__ "(" STRINGIFY(__LINE__) "): " + + +////////////////////////////////////////////////////////////////////////// +// Legacy Logging System +////////////////////////////////////////////////////////////////////////// + +// Channels which map the legacy logging system to the new system. + +// Channel for all default Msg/Warning/Error commands. +DECLARE_LOGGING_CHANNEL( LOG_GENERAL ); +// Channel for all asserts. +DECLARE_LOGGING_CHANNEL( LOG_ASSERT ); +// Channel for all ConMsg and ConColorMsg commands. +DECLARE_LOGGING_CHANNEL( LOG_CONSOLE ); +// Channel for all DevMsg and DevWarning commands with level < 2. +DECLARE_LOGGING_CHANNEL( LOG_DEVELOPER ); +// Channel for ConDMsg commands. +DECLARE_LOGGING_CHANNEL( LOG_DEVELOPER_CONSOLE ); +// Channel for all DevMsg and DevWarning commands with level >= 2. +DECLARE_LOGGING_CHANNEL( LOG_DEVELOPER_VERBOSE ); + +// Legacy logging functions + +PLATFORM_INTERFACE void Error( const tchar *pMsg, ... ) FMTFUNCTION( 1, 2 ); +PLATFORM_INTERFACE void Error_SpewCallStack( int iMaxCallStackLength, const tchar *pMsg, ... ) FMTFUNCTION( 2, 3 ); + +#if defined( DBGFLAG_STRINGS_STRIP ) && !defined( TIER0_DLL_EXPORT ) + +#define Msg( ... ) ((void)0) +#define Warning( ... ) ((void)0) +#define Warning_SpewCallStack( ... ) ((void)0) +#define DevMsg( ... ) ((void)0) +#define DevWarning( ... ) ((void)0) +#define ConColorMsg( ... ) ((void)0) +#define ConMsg( ... ) ((void)0) +#define ConDMsg( ... ) ((void)0) +#define COM_TimestampedLog( ... ) ((void)0) + +#else // #if defined( DBGFLAG_STRINGS_STRIP ) && !defined( TIER0_DLL_EXPORT ) + +PLATFORM_INTERFACE void Msg( const tchar* pMsg, ... ); +PLATFORM_INTERFACE void Warning( const tchar *pMsg, ... ) FMTFUNCTION( 1, 2 ); +PLATFORM_INTERFACE void Warning_SpewCallStack( int iMaxCallStackLength, const tchar *pMsg, ... ) FMTFUNCTION( 2, 3 ); + +#ifdef _PS3 + +PLATFORM_OVERLOAD void DevMsg( int level, const tchar* pMsg, ... ) FMTFUNCTION( 2, 3 ); +PLATFORM_OVERLOAD void DevWarning( int level, const tchar *pMsg, ... ) FMTFUNCTION( 2, 3 ); + +PLATFORM_INTERFACE void DevMsg( const tchar* pMsg, ... ) FMTFUNCTION( 1, 2 ); +PLATFORM_INTERFACE void DevWarning( const tchar *pMsg, ... ) FMTFUNCTION( 1, 2 ); + +PLATFORM_INTERFACE void ConColorMsg( const Color& clr, const tchar* pMsg, ... ) FMTFUNCTION( 2, 3 ); +PLATFORM_INTERFACE void ConMsg( const tchar* pMsg, ... ) FMTFUNCTION( 1, 2 ); + +#else // !_PS3 + +PLATFORM_INTERFACE void DevMsg( int level, const tchar* pMsg, ... ) FMTFUNCTION( 2, 3 ); +PLATFORM_INTERFACE void DevWarning( int level, const tchar *pMsg, ... ) FMTFUNCTION( 2, 3 ); + +PLATFORM_OVERLOAD void DevMsg( const tchar* pMsg, ... ) FMTFUNCTION( 1, 2 ); +PLATFORM_OVERLOAD void DevWarning( const tchar *pMsg, ... ) FMTFUNCTION( 1, 2 ); + +PLATFORM_OVERLOAD void ConColorMsg( const Color& clr, const tchar* pMsg, ... ) FMTFUNCTION( 2, 3 ); +PLATFORM_OVERLOAD void ConMsg( const tchar* pMsg, ... ) FMTFUNCTION( 1, 2 ); + +#endif // _PS3 + +PLATFORM_INTERFACE void ConDMsg( const tchar* pMsg, ... ) FMTFUNCTION( 1, 2 ); + +PLATFORM_INTERFACE void COM_TimestampedLog( char const *fmt, ... ) FMTFUNCTION( 1, 2 ); + +#endif // #if defined( DBGFLAG_STRINGS_STRIP ) && !defined( TIER0_DLL_EXPORT ) + +// You can use this macro like a runtime assert macro. +// If the condition fails, then Error is called with the message. This macro is called +// like AssertMsg, where msg must be enclosed in parenthesis: +// +// ErrorIfNot( bCondition, ("a b c %d %d %d", 1, 2, 3) ); +#define ErrorIfNot( condition, msg ) \ + if ( (condition) ) \ + ; \ + else \ + { \ + Error msg; \ + } + +#ifdef _DEBUG +#define DebugMsg(...) DevMsg(__VA_ARGS__) +#else +#define DebugMsg(...) +#endif + +// @TODO: these callstack spew functions are currently disabled in the new logging system. Need to add support for these if desired. +PLATFORM_INTERFACE void _Warning_AlwaysSpewCallStack_Enable( bool bEnable ); +PLATFORM_INTERFACE void _Warning_AlwaysSpewCallStack_Length( int iMaxCallStackLength ); + +PLATFORM_INTERFACE void _Error_AlwaysSpewCallStack_Enable( bool bEnable ); +PLATFORM_INTERFACE void _Error_AlwaysSpewCallStack_Length( int iMaxCallStackLength ); + + +/* Code macros, debugger interface */ + +#ifdef _DEBUG + +#define DBG_CODE( _code ) if (0) ; else { _code } +#define DBG_CODE_NOSCOPE( _code ) _code +#define DBG_DCODE( _g, _l, _code ) if (IsSpewActive( _g, _l )) { _code } else {} +#define DBG_BREAK() DebuggerBreak() /* defined in platform.h */ + +#else /* not _DEBUG */ + +#define DBG_CODE( _code ) ((void)0) +#define DBG_CODE_NOSCOPE( _code ) +#define DBG_DCODE( _g, _l, _code ) ((void)0) +#define DBG_BREAK() ((void)0) + +#endif /* _DEBUG */ + +//----------------------------------------------------------------------------- +// Macro to assist in asserting constant invariants during compilation + +#ifdef _DEBUG +#define COMPILE_TIME_ASSERT( pred ) switch(0){case 0:case pred:;} +#define ASSERT_INVARIANT( pred ) static void UNIQUE_ID() { COMPILE_TIME_ASSERT( pred ) } +#else +#define COMPILE_TIME_ASSERT( pred ) +#define ASSERT_INVARIANT( pred ) +#endif + +#ifdef _DEBUG +template<typename DEST_POINTER_TYPE, typename SOURCE_POINTER_TYPE> +inline DEST_POINTER_TYPE assert_cast(SOURCE_POINTER_TYPE* pSource) +{ + Assert( static_cast<DEST_POINTER_TYPE>(pSource) == dynamic_cast<DEST_POINTER_TYPE>(pSource) ); + return static_cast<DEST_POINTER_TYPE>(pSource); +} +#else +#define assert_cast static_cast +#endif + +//----------------------------------------------------------------------------- +// Templates to assist in validating pointers: + +// Have to use these stubs so we don't have to include windows.h here. +PLATFORM_INTERFACE void _AssertValidReadPtr( void* ptr, int count = 1 ); +PLATFORM_INTERFACE void _AssertValidWritePtr( void* ptr, int count = 1 ); +PLATFORM_INTERFACE void _AssertValidReadWritePtr( void* ptr, int count = 1 ); +PLATFORM_INTERFACE void _AssertValidStringPtr( const tchar* ptr, int maxchar ); + +#ifdef DBGFLAG_ASSERT +inline void AssertValidStringPtr( const tchar* ptr, int maxchar = 0xFFFFFF ) { _AssertValidStringPtr( ptr, maxchar ); } +template<class T> inline void AssertValidReadPtr( T* ptr, int count = 1 ) { _AssertValidReadPtr( (void*)ptr, count ); } +template<class T> inline void AssertValidWritePtr( T* ptr, int count = 1 ) { _AssertValidWritePtr( (void*)ptr, count ); } +template<class T> inline void AssertValidReadWritePtr( T* ptr, int count = 1 ) { _AssertValidReadWritePtr( (void*)ptr, count ); } +#define AssertValidThis() AssertValidReadWritePtr(this,sizeof(*this)) + +#else + +inline void AssertValidStringPtr( const tchar* ptr, int maxchar = 0xFFFFFF ) { } +template<class T> inline void AssertValidReadPtr( T* ptr, int count = 1 ) { } +template<class T> inline void AssertValidWritePtr( T* ptr, int count = 1 ) { } +template<class T> inline void AssertValidReadWritePtr( T* ptr, int count = 1 ) { } +#define AssertValidThis() +#endif + +//----------------------------------------------------------------------------- +// Macro to protect functions that are not reentrant + +#ifdef _DEBUG +class CReentryGuard +{ +public: + CReentryGuard(int *pSemaphore) + : m_pSemaphore(pSemaphore) + { + ++(*m_pSemaphore); + } + + ~CReentryGuard() + { + --(*m_pSemaphore); + } + +private: + int *m_pSemaphore; +}; + +#define ASSERT_NO_REENTRY() \ + static int fSemaphore##__LINE__; \ + Assert( !fSemaphore##__LINE__ ); \ + CReentryGuard ReentryGuard##__LINE__( &fSemaphore##__LINE__ ) +#else +#define ASSERT_NO_REENTRY() +#endif + +// Tier0 uses these for string functions since this abstraction is normally done in tier1. +#ifdef POSIX + #define Tier0Internal_sntprintf snprintf + #define Tier0Internal_vsntprintf vsnprintf + #define Tier0Internal_vsnprintf vsnprintf +#else + #define Tier0Internal_sntprintf _sntprintf + #define Tier0Internal_vsntprintf _vsntprintf + #define Tier0Internal_vsnprintf _vsnprintf +#endif + +//----------------------------------------------------------------------------- +// +// Purpose: Inline string formatter +// + +#include "tier0/valve_off.h" +class CDbgFmtMsg +{ +public: + CDbgFmtMsg(const tchar *pszFormat, ...) + { + va_list arg_ptr; + + va_start(arg_ptr, pszFormat); + Tier0Internal_vsntprintf(m_szBuf, sizeof(m_szBuf)-1, pszFormat, arg_ptr); + va_end(arg_ptr); + + m_szBuf[sizeof(m_szBuf)-1] = 0; + } + + operator const tchar *() const + { + return m_szBuf; + } + +private: + tchar m_szBuf[256]; +}; +#include "tier0/valve_on.h" + +//----------------------------------------------------------------------------- +// +// Purpose: Embed debug info in each file. +// +#if defined( _WIN32 ) && !defined( _X360 ) + + #ifdef _DEBUG + #pragma comment(compiler) + #endif + +#endif + +//----------------------------------------------------------------------------- +// +// Purpose: Wrap around a variable to create a simple place to put a breakpoint +// + +#ifdef _DEBUG + +template< class Type > +class CDataWatcher +{ +public: + const Type& operator=( const Type &val ) + { + return Set( val ); + } + + const Type& operator=( const CDataWatcher<Type> &val ) + { + return Set( val.m_Value ); + } + + const Type& Set( const Type &val ) + { + // Put your breakpoint here + m_Value = val; + return m_Value; + } + + Type& GetForModify() + { + return m_Value; + } + + const Type& operator+=( const Type &val ) + { + return Set( m_Value + val ); + } + + const Type& operator-=( const Type &val ) + { + return Set( m_Value - val ); + } + + const Type& operator/=( const Type &val ) + { + return Set( m_Value / val ); + } + + const Type& operator*=( const Type &val ) + { + return Set( m_Value * val ); + } + + const Type& operator^=( const Type &val ) + { + return Set( m_Value ^ val ); + } + + const Type& operator|=( const Type &val ) + { + return Set( m_Value | val ); + } + + const Type& operator++() + { + return (*this += 1); + } + + Type operator--() + { + return (*this -= 1); + } + + Type operator++( int ) // postfix version.. + { + Type val = m_Value; + (*this += 1); + return val; + } + + Type operator--( int ) // postfix version.. + { + Type val = m_Value; + (*this -= 1); + return val; + } + + // For some reason the compiler only generates type conversion warnings for this operator when used like + // CNetworkVarBase<unsigned tchar> = 0x1 + // (it warns about converting from an int to an unsigned char). + template< class C > + const Type& operator&=( C val ) + { + return Set( m_Value & val ); + } + + operator const Type&() const + { + return m_Value; + } + + const Type& Get() const + { + return m_Value; + } + + const Type* operator->() const + { + return &m_Value; + } + + Type m_Value; + +}; + +#else + +template< class Type > +class CDataWatcher +{ +private: + CDataWatcher(); // refuse to compile in non-debug builds +}; + +#endif + +// Code for programmatically setting/unsetting hardware breakpoints (there's probably a 360 and +#ifdef IS_WINDOWS_PC + +typedef void * HardwareBreakpointHandle_t; + +enum EHardwareBreakpointType +{ + BREAKPOINT_EXECUTE = 0, + BREAKPOINT_WRITE, + BREAKPOINT_READWRITE, +}; + +enum EHardwareBreakpointSize +{ + BREAKPOINT_SIZE_1 = 1, + BREAKPOINT_SIZE_2 = 2, + BREAKPOINT_SIZE_4 = 4, + BREAKPOINT_SIZE_8 = 8, +}; + +PLATFORM_INTERFACE HardwareBreakpointHandle_t SetHardwareBreakpoint( EHardwareBreakpointType eType, EHardwareBreakpointSize eSize, const void *pvLocation ); +PLATFORM_INTERFACE bool ClearHardwareBreakpoint( HardwareBreakpointHandle_t handle ); + +class CHardwareBreakPointScopeGuard +{ +public: + CHardwareBreakPointScopeGuard( const void *pvLocation, size_t nLocationSize, EHardwareBreakpointType eType = BREAKPOINT_WRITE ) + { + EHardwareBreakpointSize eSize = BREAKPOINT_SIZE_4; + switch ( nLocationSize ) + { + case 1: + eSize = BREAKPOINT_SIZE_1; + break; + case 2: + eSize = BREAKPOINT_SIZE_2; + break; + case 4: + eSize = BREAKPOINT_SIZE_4; + break; + case 8: + eSize = BREAKPOINT_SIZE_8; + break; + default: + Warning( _T( "SetHardwareBreakpoint can only work with 1, 2, 4 or 8 byte data fields." ) ); + break; + } + + m_hBreakPoint = SetHardwareBreakpoint( eType, eSize, pvLocation ); + m_bActive = m_hBreakPoint != (HardwareBreakpointHandle_t)0; + } + + ~CHardwareBreakPointScopeGuard() + { + Release(); + } + + void Release() + { + if ( !m_bActive ) + return; + ClearHardwareBreakpoint( m_hBreakPoint ); + } + +private: + bool m_bActive; + HardwareBreakpointHandle_t m_hBreakPoint; +}; + +#endif // IS_WINDOWS_PC +//----------------------------------------------------------------------------- + +#endif /* DBG_H */ |