summaryrefslogtreecommitdiff
path: root/external/vpc/tier0/dbg.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'external/vpc/tier0/dbg.cpp')
-rw-r--r--external/vpc/tier0/dbg.cpp627
1 files changed, 627 insertions, 0 deletions
diff --git a/external/vpc/tier0/dbg.cpp b/external/vpc/tier0/dbg.cpp
new file mode 100644
index 0000000..8effafb
--- /dev/null
+++ b/external/vpc/tier0/dbg.cpp
@@ -0,0 +1,627 @@
+//===== Copyright (c) 1996-2005, Valve Corporation, All rights reserved. ======//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//===========================================================================//
+
+#include "tier0/platform.h"
+
+#if defined( PLATFORM_WINDOWS_PC )
+#define WIN_32_LEAN_AND_MEAN
+#include <windows.h> // Currently needed for IsBadReadPtr and IsBadWritePtr
+#pragma comment(lib,"user32.lib") // For MessageBox
+#endif
+
+#include "tier0/minidump.h"
+#include "tier0/stacktools.h"
+
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include "color.h"
+#include "tier0/dbg.h"
+#include "tier0/threadtools.h"
+#include "tier0/icommandline.h"
+#include <math.h>
+
+#if defined( _X360 )
+#include "xbox/xbox_console.h"
+#endif
+
+#include "tier0/etwprof.h"
+
+#ifndef STEAM
+#define PvRealloc realloc
+#define PvAlloc malloc
+#endif
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+#if defined( ENABLE_RUNTIME_STACK_TRANSLATION )
+#pragma optimize( "g", off ) //variable argument functions seem to screw up stack walking unless this optimization is disabled
+#pragma warning( disable: 4748 ) // Turn off the warning telling us that optimizations are off if /GS is on
+#endif
+
+DEFINE_LOGGING_CHANNEL_NO_TAGS( LOG_LOADING, "LOADING" );
+
+//-----------------------------------------------------------------------------
+// Stack attachment management
+//-----------------------------------------------------------------------------
+#if defined( ENABLE_RUNTIME_STACK_TRANSLATION )
+
+static bool s_bCallStacksWithAllWarnings = false; //if true, attach a call stack to every SPEW_WARNING message. Warning()/DevWarning()/...
+static int s_iWarningMaxCallStackLength = 5;
+#define AutomaticWarningCallStackLength() (s_bCallStacksWithAllWarnings ? s_iWarningMaxCallStackLength : 0)
+
+void _Warning_AlwaysSpewCallStack_Enable( bool bEnable )
+{
+ s_bCallStacksWithAllWarnings = bEnable;
+}
+
+void _Warning_AlwaysSpewCallStack_Length( int iMaxCallStackLength )
+{
+ s_iWarningMaxCallStackLength = iMaxCallStackLength;
+}
+
+static bool s_bCallStacksWithAllErrors = false; //if true, attach a call stack to every SPEW_ERROR message. Mostly just Error()
+static int s_iErrorMaxCallStackLength = 20; //default to higher output with an error since we're quitting anyways
+#define AutomaticErrorCallStackLength() (s_bCallStacksWithAllErrors ? s_iErrorMaxCallStackLength : 0)
+
+void _Error_AlwaysSpewCallStack_Enable( bool bEnable )
+{
+ s_bCallStacksWithAllErrors = bEnable;
+}
+
+void _Error_AlwaysSpewCallStack_Length( int iMaxCallStackLength )
+{
+ s_iErrorMaxCallStackLength = iMaxCallStackLength;
+}
+
+#else //#if defined( ENABLE_RUNTIME_STACK_TRANSLATION )
+
+#define AutomaticWarningCallStackLength() 0
+#define AutomaticErrorCallStackLength() 0
+
+void _Warning_AlwaysSpewCallStack_Enable( bool bEnable )
+{
+}
+
+void _Warning_AlwaysSpewCallStack_Length( int iMaxCallStackLength )
+{
+}
+
+void _Error_AlwaysSpewCallStack_Enable( bool bEnable )
+{
+}
+
+void _Error_AlwaysSpewCallStack_Length( int iMaxCallStackLength )
+{
+}
+
+#endif //#if defined( ENABLE_RUNTIME_STACK_TRANSLATION )
+
+void _ExitOnFatalAssert( const tchar* pFile, int line )
+{
+ Log_Msg( LOG_ASSERT, _T("Fatal assert failed: %s, line %d. Application exiting.\n"), pFile, line );
+
+ // only write out minidumps if we're not in the debugger
+ if ( !Plat_IsInDebugSession() )
+ {
+ WriteMiniDump();
+ }
+
+ Log_Msg( LOG_DEVELOPER, _T("_ExitOnFatalAssert\n") );
+ Plat_ExitProcess( EXIT_FAILURE );
+}
+
+
+//-----------------------------------------------------------------------------
+// Templates to assist in validating pointers:
+//-----------------------------------------------------------------------------
+PLATFORM_INTERFACE void _AssertValidReadPtr( void* ptr, int count/* = 1*/ )
+{
+#if defined( _WIN32 ) && !defined( _X360 )
+ Assert( !IsBadReadPtr( ptr, count ) );
+#else
+ Assert( !count || ptr );
+#endif
+}
+
+PLATFORM_INTERFACE void _AssertValidWritePtr( void* ptr, int count/* = 1*/ )
+{
+#if defined( _WIN32 ) && !defined( _X360 )
+ Assert( !IsBadWritePtr( ptr, count ) );
+#else
+ Assert( !count || ptr );
+#endif
+}
+
+PLATFORM_INTERFACE void _AssertValidReadWritePtr( void* ptr, int count/* = 1*/ )
+{
+#if defined( _WIN32 ) && !defined( _X360 )
+ Assert(!( IsBadWritePtr(ptr, count) || IsBadReadPtr(ptr,count)));
+#else
+ Assert( !count || ptr );
+#endif
+}
+
+PLATFORM_INTERFACE void _AssertValidStringPtr( const tchar* ptr, int maxchar/* = 0xFFFFFF */ )
+{
+#if defined( _WIN32 ) && !defined( _X360 )
+ #ifdef TCHAR_IS_CHAR
+ Assert( !IsBadStringPtr( ptr, maxchar ) );
+ #else
+ Assert( !IsBadStringPtrW( ptr, maxchar ) );
+ #endif
+#else
+ Assert( ptr );
+#endif
+}
+
+void AppendCallStackToLogMessage( tchar *formattedMessage, int iMessageLength, int iAppendCallStackLength )
+{
+#if defined( ENABLE_RUNTIME_STACK_TRANSLATION )
+# if defined( TCHAR_IS_CHAR ) //I'm horrible with unicode and I don't plan on testing this with wide characters just yet
+ if( iAppendCallStackLength > 0 )
+ {
+ int iExistingMessageLength = (int)strlen( formattedMessage ); //no V_strlen in tier 0, plus we're only compiling this for windows and 360. Seems safe
+ formattedMessage += iExistingMessageLength;
+ iMessageLength -= iExistingMessageLength;
+
+ if( iMessageLength <= 32 )
+ return; //no room for anything useful
+
+ //append directly to the spew message
+ if( (iExistingMessageLength > 0) && (formattedMessage[-1] == '\n') )
+ {
+ --formattedMessage;
+ ++iMessageLength;
+ }
+
+ //append preface
+ int iAppendedLength = _snprintf( formattedMessage, iMessageLength, _T("\nCall Stack:\n\t") );
+
+ void **CallStackBuffer = (void **)stackalloc( iAppendCallStackLength * sizeof( void * ) );
+ int iCount = GetCallStack( CallStackBuffer, iAppendCallStackLength, 2 );
+ if( TranslateStackInfo( CallStackBuffer, iCount, formattedMessage + iAppendedLength, iMessageLength - iAppendedLength, _T("\n\t") ) == 0 )
+ {
+ //failure
+ formattedMessage[0] = '\0'; //this is pointing at where we wrote "\nCall Stack:\n\t"
+ }
+ else
+ {
+ iAppendedLength += (int)strlen( formattedMessage + iAppendedLength ); //no V_strlen in tier 0, plus we're only compiling this for windows and 360. Seems safe
+
+ if( iAppendedLength < iMessageLength )
+ {
+ formattedMessage[iAppendedLength] = '\n'; //Add another newline.
+ ++iAppendedLength;
+
+ formattedMessage[iAppendedLength] = '\0';
+ }
+ }
+ }
+# else
+ AssertMsg( false, "Fixme" );
+# endif
+#endif
+}
+
+// Forward declare for internal use only.
+CLoggingSystem *GetGlobalLoggingSystem();
+
+#define Log_LegacyHelperColor_Stack( Channel, Severity, Color, MessageFormat, AppendCallStackLength ) \
+ do \
+{ \
+ CLoggingSystem *pLoggingSystem = GetGlobalLoggingSystem(); \
+ if ( pLoggingSystem->IsChannelEnabled( Channel, Severity ) ) \
+{ \
+ tchar formattedMessage[MAX_LOGGING_MESSAGE_LENGTH]; \
+ va_list args; \
+ va_start( args, MessageFormat ); \
+ Tier0Internal_vsntprintf( formattedMessage, MAX_LOGGING_MESSAGE_LENGTH, MessageFormat, args ); \
+ va_end( args ); \
+ AppendCallStackToLogMessage( formattedMessage, MAX_LOGGING_MESSAGE_LENGTH, AppendCallStackLength ); \
+ pLoggingSystem->LogDirect( Channel, Severity, Color, formattedMessage ); \
+} \
+} while( 0 )
+
+#define Log_LegacyHelperColor( Channel, Severity, Color, MessageFormat ) Log_LegacyHelperColor_Stack( Channel, Severity, Color, MessageFormat, 0 )
+
+#define Log_LegacyHelper_Stack( Channel, Severity, MessageFormat, AppendCallStackLength ) Log_LegacyHelperColor_Stack( Channel, Severity, pLoggingSystem->GetChannelColor( Channel ), MessageFormat, AppendCallStackLength )
+#define Log_LegacyHelper( Channel, Severity, MessageFormat ) Log_LegacyHelperColor( Channel, Severity, pLoggingSystem->GetChannelColor( Channel ), MessageFormat )
+
+
+void Msg( const tchar* pMsgFormat, ... )
+{
+ Log_LegacyHelper( LOG_GENERAL, LS_MESSAGE, pMsgFormat );
+}
+
+void Warning( const tchar *pMsgFormat, ... )
+{
+ Log_LegacyHelper_Stack( LOG_GENERAL, LS_WARNING, pMsgFormat, AutomaticWarningCallStackLength() );
+}
+
+void Warning_SpewCallStack( int iMaxCallStackLength, const tchar *pMsgFormat, ... )
+{
+ Log_LegacyHelper_Stack( LOG_GENERAL, LS_WARNING, pMsgFormat, iMaxCallStackLength );
+}
+
+
+void Error( const tchar *pMsgFormat, ... )
+{
+ Log_LegacyHelper_Stack( LOG_GENERAL, LS_ERROR, pMsgFormat, AutomaticErrorCallStackLength() );
+}
+
+void Error_SpewCallStack( int iMaxCallStackLength, const tchar *pMsgFormat, ... )
+{
+ Log_LegacyHelper_Stack( LOG_GENERAL, LS_ERROR, pMsgFormat, iMaxCallStackLength );
+}
+
+
+//-----------------------------------------------------------------------------
+// A couple of super-common dynamic spew messages, here for convenience
+// These looked at the "developer" group, print if it's level 1 or higher
+//-----------------------------------------------------------------------------
+void DevMsg( int level, const tchar* pMsgFormat, ... )
+{
+ LoggingChannelID_t channel = level >= 2 ? LOG_DEVELOPER_VERBOSE : LOG_DEVELOPER;
+ Log_LegacyHelper( channel, LS_MESSAGE, pMsgFormat );
+}
+
+
+void DevWarning( int level, const tchar *pMsgFormat, ... )
+{
+ LoggingChannelID_t channel = level >= 2 ? LOG_DEVELOPER_VERBOSE : LOG_DEVELOPER;
+ Log_LegacyHelper( channel, LS_WARNING, pMsgFormat );
+}
+
+void DevMsg( const tchar *pMsgFormat, ... )
+{
+ Log_LegacyHelper( LOG_DEVELOPER, LS_MESSAGE, pMsgFormat );
+}
+
+void DevWarning( const tchar *pMsgFormat, ... )
+{
+ Log_LegacyHelper( LOG_DEVELOPER, LS_WARNING, pMsgFormat );
+}
+
+void ConColorMsg( const Color& clr, const tchar* pMsgFormat, ... )
+{
+ Log_LegacyHelperColor( LOG_CONSOLE, LS_MESSAGE, clr, pMsgFormat );
+}
+
+void ConMsg( const tchar *pMsgFormat, ... )
+{
+ Log_LegacyHelper( LOG_CONSOLE, LS_MESSAGE, pMsgFormat );
+}
+
+void ConDMsg( const tchar *pMsgFormat, ... )
+{
+ Log_LegacyHelper( LOG_DEVELOPER_CONSOLE, LS_MESSAGE, pMsgFormat );
+}
+
+// If we don't have a function from math.h, then it doesn't link certain floating-point
+// functions in and printfs with %f cause runtime errors in the C libraries.
+PLATFORM_INTERFACE float CrackSmokingCompiler( float a )
+{
+ return (float)fabs( a );
+}
+
+void* Plat_SimpleLog( const tchar* file, int line )
+{
+ FILE* f = _tfopen( _T("simple.log"), _T("at+") );
+ _ftprintf( f, _T("%s:%i\n"), file, line );
+ fclose( f );
+
+ return NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: For debugging startup times, etc.
+// Input : *fmt -
+// ... -
+//-----------------------------------------------------------------------------
+void COM_TimestampedLog( char const *fmt, ... )
+{
+ static float s_LastStamp = 0.0;
+ static bool s_bShouldLog = false;
+ static bool s_bShouldLogToConsole = false;
+ static bool s_bShouldLogToETW = false;
+ static bool s_bChecked = false;
+ static bool s_bFirstWrite = false;
+
+ if ( !s_bChecked )
+ {
+ s_bShouldLog = ( CommandLine()->CheckParm( "-profile" ) ) ? true : false;
+ s_bShouldLogToConsole = ( CommandLine()->ParmValue( "-profile", 0.0f ) != 0.0f ) ? true : false;
+
+ s_bShouldLogToETW = ( CommandLine()->CheckParm( "-etwprofile" ) ) ? true : false;
+ if ( s_bShouldLogToETW )
+ {
+ s_bShouldLog = true;
+ }
+
+ s_bChecked = true;
+ }
+ if ( !s_bShouldLog )
+ {
+ return;
+ }
+
+ char string[1024];
+ va_list argptr;
+ va_start( argptr, fmt );
+ Tier0Internal_vsnprintf( string, sizeof( string ), fmt, argptr );
+ va_end( argptr );
+
+ float curStamp = Plat_FloatTime();
+
+#if defined( _X360 )
+ XBX_rTimeStampLog( curStamp, string );
+#elif defined( _PS3 )
+ Log_Warning( LOG_LOADING, "%8.4f / %8.4f: %s\n", curStamp, curStamp - s_LastStamp, string );
+#endif
+
+ if ( IsPC() )
+ {
+ // If ETW profiling is enabled then do it only.
+ if ( s_bShouldLogToETW )
+ {
+ ETWMark( string );
+ }
+ else
+ {
+ if ( !s_bFirstWrite )
+ {
+ unlink( "timestamped.log" );
+ s_bFirstWrite = true;
+ }
+
+ FILE* fp = fopen( "timestamped.log", "at+" );
+ fprintf( fp, "%8.4f / %8.4f: %s\n", curStamp, curStamp - s_LastStamp, string );
+ fclose( fp );
+ }
+
+ if ( s_bShouldLogToConsole )
+ {
+ Msg( "%8.4f / %8.4f: %s\n", curStamp, curStamp - s_LastStamp, string );
+ }
+ }
+
+ s_LastStamp = curStamp;
+}
+
+#ifdef IS_WINDOWS_PC
+
+class CHardwareBreakPoint
+{
+public:
+
+ enum EOpCode
+ {
+ BRK_SET = 0,
+ BRK_UNSET,
+ };
+
+ CHardwareBreakPoint()
+ {
+ m_eOperation = BRK_SET;
+ m_pvAddress = 0;
+ m_hThread = 0;
+ m_hThreadEvent = 0;
+ m_nRegister = 0;
+ m_bSuccess = false;
+ }
+
+ const void *m_pvAddress;
+ HANDLE m_hThread;
+ EHardwareBreakpointType m_eType;
+ EHardwareBreakpointSize m_eSize;
+ HANDLE m_hThreadEvent;
+ int m_nRegister;
+ EOpCode m_eOperation;
+ bool m_bSuccess;
+
+ static void SetBits( DWORD_PTR& dw, int lowBit, int bits, int newValue );
+ static DWORD WINAPI ThreadProc( LPVOID lpParameter );
+};
+
+void CHardwareBreakPoint::SetBits( DWORD_PTR& dw, int lowBit, int bits, int newValue )
+{
+ DWORD_PTR mask = (1 << bits) - 1;
+ dw = (dw & ~(mask << lowBit)) | (newValue << lowBit);
+}
+
+DWORD WINAPI CHardwareBreakPoint::ThreadProc( LPVOID lpParameter )
+{
+ CHardwareBreakPoint *h = reinterpret_cast< CHardwareBreakPoint * >( lpParameter );
+ SuspendThread( h->m_hThread );
+
+ // Get current context
+ CONTEXT ct = {0};
+ ct.ContextFlags = CONTEXT_DEBUG_REGISTERS;
+ GetThreadContext(h->m_hThread,&ct);
+
+ int FlagBit = 0;
+
+ bool Dr0Busy = false;
+ bool Dr1Busy = false;
+ bool Dr2Busy = false;
+ bool Dr3Busy = false;
+ if (ct.Dr7 & 1)
+ Dr0Busy = true;
+ if (ct.Dr7 & 4)
+ Dr1Busy = true;
+ if (ct.Dr7 & 16)
+ Dr2Busy = true;
+ if (ct.Dr7 & 64)
+ Dr3Busy = true;
+
+ if ( h->m_eOperation == CHardwareBreakPoint::BRK_UNSET )
+ {
+ // Remove
+ if (h->m_nRegister == 0)
+ {
+ FlagBit = 0;
+ ct.Dr0 = 0;
+ Dr0Busy = false;
+ }
+ if (h->m_nRegister == 1)
+ {
+ FlagBit = 2;
+ ct.Dr1 = 0;
+ Dr1Busy = false;
+ }
+ if (h->m_nRegister == 2)
+ {
+ FlagBit = 4;
+ ct.Dr2 = 0;
+ Dr2Busy = false;
+ }
+ if (h->m_nRegister == 3)
+ {
+ FlagBit = 6;
+ ct.Dr3 = 0;
+ Dr3Busy = false;
+ }
+ ct.Dr7 &= ~(1 << FlagBit);
+ }
+ else
+ {
+ if (!Dr0Busy)
+ {
+ h->m_nRegister = 0;
+ ct.Dr0 = (DWORD_PTR)h->m_pvAddress;
+ Dr0Busy = true;
+ }
+ else if (!Dr1Busy)
+ {
+ h->m_nRegister = 1;
+ ct.Dr1 = (DWORD_PTR)h->m_pvAddress;
+ Dr1Busy = true;
+ }
+ else if (!Dr2Busy)
+ {
+ h->m_nRegister = 2;
+ ct.Dr2 = (DWORD_PTR)h->m_pvAddress;
+ Dr2Busy = true;
+ }
+ else if (!Dr3Busy)
+ {
+ h->m_nRegister = 3;
+ ct.Dr3 = (DWORD_PTR)h->m_pvAddress;
+ Dr3Busy = true;
+ }
+ else
+ {
+ h->m_bSuccess = false;
+ ResumeThread(h->m_hThread);
+ SetEvent(h->m_hThreadEvent);
+ return 0;
+ }
+
+ ct.Dr6 = 0;
+ int st = 0;
+ if (h->m_eType == BREAKPOINT_EXECUTE)
+ st = 0;
+ if (h->m_eType == BREAKPOINT_READWRITE)
+ st = 3;
+ if (h->m_eType == BREAKPOINT_WRITE)
+ st = 1;
+
+ int le = 0;
+ if (h->m_eSize == BREAKPOINT_SIZE_1)
+ le = 0;
+ if (h->m_eSize == BREAKPOINT_SIZE_2)
+ le = 1;
+ if (h->m_eSize == BREAKPOINT_SIZE_4)
+ le = 3;
+ if (h->m_eSize == BREAKPOINT_SIZE_8)
+ le = 2;
+
+ SetBits( ct.Dr7, 16 + h->m_nRegister*4, 2, st );
+ SetBits( ct.Dr7, 18 + h->m_nRegister*4, 2, le );
+ SetBits( ct.Dr7, h->m_nRegister*2,1,1);
+ }
+
+ ct.ContextFlags = CONTEXT_DEBUG_REGISTERS;
+ SetThreadContext(h->m_hThread,&ct);
+
+ ResumeThread( h->m_hThread );
+ h->m_bSuccess = true;
+ SetEvent( h->m_hThreadEvent );
+ return 0;
+}
+
+HardwareBreakpointHandle_t SetHardwareBreakpoint( EHardwareBreakpointType eType, EHardwareBreakpointSize eSize, const void *pvLocation )
+{
+ CHardwareBreakPoint *h = new CHardwareBreakPoint();
+ h->m_pvAddress = pvLocation;
+ h->m_eSize = eSize;
+ h->m_eType = eType;
+ HANDLE hThread = GetCurrentThread();
+ h->m_hThread = hThread;
+
+ if ( hThread == GetCurrentThread() )
+ {
+ DWORD nThreadId = GetCurrentThreadId();
+ h->m_hThread = OpenThread( THREAD_ALL_ACCESS, 0, nThreadId );
+ }
+
+ h->m_hThreadEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
+ h->m_eOperation = CHardwareBreakPoint::BRK_SET; // Set Break
+ CreateThread( 0, 0, CHardwareBreakPoint::ThreadProc, (LPVOID)h, 0, 0 );
+ WaitForSingleObject( h->m_hThreadEvent,INFINITE );
+ CloseHandle( h->m_hThreadEvent );
+ h->m_hThreadEvent = 0;
+ if ( hThread == GetCurrentThread() )
+ {
+ CloseHandle( h->m_hThread );
+ }
+ h->m_hThread = hThread;
+ if ( !h->m_bSuccess )
+ {
+ delete h;
+ return (HardwareBreakpointHandle_t)0;
+ }
+ return (HardwareBreakpointHandle_t)h;
+}
+
+bool ClearHardwareBreakpoint( HardwareBreakpointHandle_t handle )
+{
+ CHardwareBreakPoint *h = reinterpret_cast< CHardwareBreakPoint* >( handle );
+ if ( !h )
+ {
+ return false;
+ }
+
+ bool bOpened = false;
+ if ( h->m_hThread == GetCurrentThread() )
+ {
+ DWORD nThreadId = GetCurrentThreadId();
+ h->m_hThread = OpenThread( THREAD_ALL_ACCESS, 0, nThreadId );
+ bOpened = true;
+ }
+
+ h->m_hThreadEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
+ h->m_eOperation = CHardwareBreakPoint::BRK_UNSET; // Remove Break
+ CreateThread( 0,0,CHardwareBreakPoint::ThreadProc, (LPVOID)h, 0,0 );
+ WaitForSingleObject( h->m_hThreadEvent, INFINITE );
+ CloseHandle( h->m_hThreadEvent );
+ h->m_hThreadEvent = 0;
+ if ( bOpened )
+ {
+ CloseHandle( h->m_hThread );
+ }
+ delete h;
+ return true;
+}
+
+#endif // IS_WINDOWS_PC
+