diff options
Diffstat (limited to 'utils/xbox/vxbdm')
| -rw-r--r-- | utils/xbox/vxbdm/console.cpp | 763 | ||||
| -rw-r--r-- | utils/xbox/vxbdm/rcommands.cpp | 320 | ||||
| -rw-r--r-- | utils/xbox/vxbdm/vxbdm.vpc | 37 | ||||
| -rw-r--r-- | utils/xbox/vxbdm/xbox/xbox.def | 3 |
4 files changed, 1123 insertions, 0 deletions
diff --git a/utils/xbox/vxbdm/console.cpp b/utils/xbox/vxbdm/console.cpp new file mode 100644 index 0000000..8ff746a --- /dev/null +++ b/utils/xbox/vxbdm/console.cpp @@ -0,0 +1,763 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Xbox console link +// +//=====================================================================================// + +#include "xbox/xbox_console.h" +#include "xbox/xbox_vxconsole.h" +#include "tier0/threadtools.h" +#include "tier0/tslist.h" +#include "tier0/ICommandLine.h" +#include "tier0/memdbgon.h" + +// all redirecting funneled here, stop redirecting in this module only +#undef OutputDebugStringA + +#pragma comment( lib, "xbdm.lib" ) + +struct DebugString_t +{ + unsigned int color; + char *pString; +}; + +#define XBX_DBGCOMMANDPREFIX "XCMD" +#define XBX_DBGRESPONSEPREFIX "XACK" +#define XBX_DBGPRINTPREFIX "XPRT" +#define XBX_DBGCOLORPREFIX "XCLR" + +#define XBX_MAX_RCMDLENGTH 256 +#define XBX_MAX_MESSAGE 2048 + +CThreadFastMutex g_xbx_dbgChannelMutex; +CThreadFastMutex g_xbx_dbgCommandHandlerMutex; +static char g_xbx_dbgRemoteBuf[XBX_MAX_RCMDLENGTH]; +static HANDLE g_xbx_dbgValidEvent; +static HANDLE g_xbx_dbgCmdCompleteEvent; +bool g_xbx_bUseVXConsoleOutput = true; +bool g_xbx_bDoSyncOutput; +static ThreadHandle_t g_xbx_hDebugThread; +CTSQueue<DebugString_t> g_xbx_DebugStringQueue; +extern CInterlockedInt g_xbx_numProfileCounters; +extern unsigned int g_xbx_profileCounters[]; +extern char g_xbx_profileName[]; +int g_xbx_freeMemory; + +_inline bool XBX_NoXBDM() { return false; } + +static CXboxConsole XboxConsole; + +DLL_EXPORT IXboxConsole *GetConsoleInterface() +{ + return &XboxConsole; +} + +//----------------------------------------------------------------------------- +// Low level string output. +// Input string should be stack based, can get clobbered. +//----------------------------------------------------------------------------- +static void OutputStringToDevice( unsigned int color, char *pString, bool bRemoteValid ) +{ + if ( !bRemoteValid ) + { + // local debug only + OutputDebugStringA( pString ); + return; + } + + // remote debug valid + // non pure colors don't translate well - find closest pure hue + unsigned int bestColor = color; + int r = ( bestColor & 0xFF ); + int g = ( bestColor >> 8 ) & 0xFF; + int b = ( bestColor >> 16 ) & 0xFF; + if ( ( r && r != 255 ) || ( g && g != 255 ) || ( b && b != 255 ) ) + { + int r0, g0, b0; + unsigned int minDist = 0xFFFFFFFF; + for ( int i=0; i<8; i++ ) + { + r0 = g0 = b0 = 0; + if ( i&4 ) + r0 = 255; + if ( i&2 ) + g0 = 255; + if ( i&1 ) + b0 = 255; + unsigned int d = ( r-r0 )*( r-r0 ) + ( g-g0 )*( g-g0 ) + ( b-b0 )*( b-b0 ); + if ( minDist > d ) + { + minDist = d; + bestColor = XMAKECOLOR( r0, g0, b0 ); + } + } + } + + // create color string + char colorString[16]; + sprintf( colorString, XBX_DBGCOLORPREFIX "[%8.8x]", bestColor ); + + // chunk line out, for each cr + char strBuffer[XBX_MAX_RCMDLENGTH]; + char *pStart = pString; + char *pEnd = pStart + strlen( pStart ); + char *pNext; + while ( pStart < pEnd ) + { + pNext = strchr( pStart, '\n' ); + if ( !pNext ) + pNext = pEnd; + else + *pNext = '\0'; + + int length = _snprintf( strBuffer, XBX_MAX_RCMDLENGTH, "%s!%s%s", XBX_DBGPRINTPREFIX, colorString, pStart ); + if ( length == -1 ) + { + strBuffer[sizeof( strBuffer )-1] = '\0'; + } + // Send the string + DmSendNotificationString( strBuffer ); + + // advance past cr + pStart = pNext+1; + } +} + +//----------------------------------------------------------------------------- +// XBX_IsConsoleConnected +// +//----------------------------------------------------------------------------- +bool CXboxConsole::IsConsoleConnected() +{ + bool bConnected; + + if ( g_xbx_dbgValidEvent == NULL ) + { + // init was never called + return false; + } + + AUTO_LOCK_FM( g_xbx_dbgChannelMutex ); + + bConnected = ( WaitForSingleObject( g_xbx_dbgValidEvent, 0 ) == WAIT_OBJECT_0 ); + + return bConnected; +} + +//----------------------------------------------------------------------------- +// Output string to listening console. Queues output for slave thread. +// Needs to be lightweight. +//----------------------------------------------------------------------------- +void CXboxConsole::DebugString( unsigned int color, const char* pFormat, ... ) +{ + if ( XBX_NoXBDM() ) + return; + + va_list args; + char szStringBuffer[XBX_MAX_MESSAGE]; + int length; + + // resolve string + va_start( args, pFormat ); + length = _vsnprintf( szStringBuffer, sizeof( szStringBuffer ), pFormat, args ); + if ( length == -1 ) + { + szStringBuffer[sizeof( szStringBuffer ) - 1] = '\0'; + } + va_end( args ); + + if ( !g_xbx_bDoSyncOutput ) + { + // queue string for delayed output + DebugString_t debugString; + debugString.color = color; + debugString.pString = strdup( szStringBuffer ); + g_xbx_DebugStringQueue.PushItem( debugString ); + } + else + { + bool bRemoteValid = g_xbx_bUseVXConsoleOutput && XBX_IsConsoleConnected(); + OutputStringToDevice( color, szStringBuffer, bRemoteValid ); + } +} + +//----------------------------------------------------------------------------- +// Waits for debug queue to drain. +//----------------------------------------------------------------------------- +void CXboxConsole::FlushDebugOutput() +{ + while ( g_xbx_DebugStringQueue.Count() != 0 ) + { + Sleep( 1 ); + } +} + +//----------------------------------------------------------------------------- +// _xdbg_strlen +// +// Critical section safe. +//----------------------------------------------------------------------------- +int _xdbg_strlen( const CHAR* str ) +{ + const CHAR* strEnd = str; + + while( *strEnd ) + strEnd++; + + return strEnd - str; +} + +//----------------------------------------------------------------------------- +// _xdbg_tolower +// +// Critical section safe. +//----------------------------------------------------------------------------- +inline CHAR _xdbg_tolower( CHAR ch ) +{ + if( ch >= 'A' && ch <= 'Z' ) + return ch - ( 'A' - 'a' ); + else + return ch; +} + +//----------------------------------------------------------------------------- +// _xdbg_strnicmp +// +// Critical section safe. +//----------------------------------------------------------------------------- +BOOL _xdbg_strnicmp( const CHAR* str1, const CHAR* str2, int n ) +{ + while ( ( _xdbg_tolower( *str1 ) == _xdbg_tolower( *str2 ) ) && *str1 && n > 0 ) + { + --n; + ++str1; + ++str2; + } + return ( !n || _xdbg_tolower( *str1 ) == _xdbg_tolower( *str2 ) ); +} + +//----------------------------------------------------------------------------- +// _xdbg_strcpy +// +// Critical section safe. +//----------------------------------------------------------------------------- +VOID _xdbg_strcpy( CHAR* strDest, const CHAR* strSrc ) +{ + while ( ( *strDest++ = *strSrc++ ) != 0 ); +} + +//----------------------------------------------------------------------------- +// _xdbg_strcpyn +// +// Critical section safe. +//----------------------------------------------------------------------------- +VOID _xdbg_strcpyn( CHAR* strDest, const CHAR* strSrc, int numChars ) +{ + while ( numChars>0 && ( *strDest++ = *strSrc++ ) != 0 ) + numChars--; +} + +//----------------------------------------------------------------------------- +// _xdbg_gettoken +// +// Critical section safe. +//----------------------------------------------------------------------------- +void _xdbg_gettoken( CHAR** tokenStream, CHAR* token, int tokenSize ) +{ + int c; + int len; + CHAR* data; + + len = 0; + + // skip prefix whitespace + data = *tokenStream; + while ( ( c = *data ) <= ' ' ) + { + if ( !c ) + goto cleanUp; + data++; + } + + // parse a token + do + { + if ( len < tokenSize ) + token[len++] = c; + + data++; + c = *data; + } while ( c > ' ' ); + + if ( len >= tokenSize ) + len = 0; + +cleanUp: + token[len] = '\0'; + *tokenStream = data; +} + +//----------------------------------------------------------------------------- +// _xdbg_tokenize +// +// Critical section safe. +//----------------------------------------------------------------------------- +int _xdbg_tokenize( CHAR* tokenStream, CHAR** tokens, int maxTokens ) +{ + char token[64]; + + // tokenize stream into seperate tokens + int numTokens = 0; + while ( 1 ) + { + tokens[numTokens++] = tokenStream; + if ( numTokens >= maxTokens ) + break; + + _xdbg_gettoken( &tokenStream, token, sizeof( token ) ); + if ( !tokenStream[0] || !token[0] ) + break; + + *tokenStream = '\0'; + tokenStream++; + } + return ( numTokens ); +} + +//----------------------------------------------------------------------------- +// _xdbg_findtoken +// +// Critical section safe. Returns -1 if not found +//----------------------------------------------------------------------------- +int _xdbg_findtoken( CHAR** tokens, int numTokens, CHAR* token ) +{ + int i; + int len; + + len = _xdbg_strlen( token ); + for ( i=0; i<numTokens; i++ ) + { + if ( _xdbg_strnicmp( tokens[i], token, len ) ) + return i; + } + + // not found + return -1; +} + +//----------------------------------------------------------------------------- +// _DebugCommandHandler +// +//----------------------------------------------------------------------------- +HRESULT __stdcall _DebugCommandHandler( const CHAR* strCommand, CHAR* strResponse, DWORD dwResponseLen, PDM_CMDCONT pdmcc ) +{ + CHAR buff[256]; + CHAR* args[8]; + int numArgs; + + AUTO_LOCK_FM( g_xbx_dbgCommandHandlerMutex ); + + // skip over the command prefix and the exclamation mark + strCommand += _xdbg_strlen( XBX_DBGCOMMANDPREFIX ) + 1; + + if ( strCommand[0] == '\0' ) + { + // just a ping + goto cleanUp; + } + + // get command and optional arguments + _xdbg_strcpyn( buff, strCommand, sizeof( buff ) ); + numArgs = _xdbg_tokenize( buff, args, sizeof( args )/sizeof( CHAR* ) ); + + if ( _xdbg_strnicmp( args[0], "__connect__", 11 ) ) + { + if ( numArgs > 1 && atoi( args[1] ) == VXCONSOLE_PROTOCOL_VERSION ) + { + // initial connect - respond that we're connected + _xdbg_strcpyn( strResponse, XBX_DBGRESPONSEPREFIX "Connected To Application.", dwResponseLen ); + SetEvent( g_xbx_dbgValidEvent ); + + // notify convar system to send its commands + // allows vxconsole to re-connect during game + _xdbg_strcpy( g_xbx_dbgRemoteBuf, "getcvars" ); + XBX_QueueEvent( XEV_REMOTECMD, ( int )g_xbx_dbgRemoteBuf, 0, 0 ); + } + else + { + _xdbg_strcpyn( strResponse, XBX_DBGRESPONSEPREFIX "Rejecting Connection: Wrong Protocol Version.", dwResponseLen ); + } + goto cleanUp; + } + + if ( _xdbg_strnicmp( args[0], "__disconnect__", 14 ) ) + { + // respond that we're disconnected + _xdbg_strcpyn( strResponse, XBX_DBGRESPONSEPREFIX "Disconnected.", dwResponseLen ); + ResetEvent( g_xbx_dbgValidEvent ); + goto cleanUp; + } + + if ( _xdbg_strnicmp( args[0], "__complete__", 12 ) ) + { + // remote server has finished command - respond to acknowledge + _xdbg_strcpyn( strResponse, XBX_DBGRESPONSEPREFIX "OK", dwResponseLen ); + + // set the complete event - allows expected synchronous calling mechanism + SetEvent( g_xbx_dbgCmdCompleteEvent ); + goto cleanUp; + } + + if ( _xdbg_strnicmp( args[0], "__memory__", 10 ) ) + { + // get a current stat of available memory + MEMORYSTATUS stat; + GlobalMemoryStatus( &stat ); + g_xbx_freeMemory = stat.dwAvailPhys; + + if ( _xdbg_findtoken( args, numArgs, "quiet" ) > 0 ) + { + _xdbg_strcpyn( strResponse, XBX_DBGRESPONSEPREFIX "OK", dwResponseLen ); + } + else + { + // 32 MB is reserved and fixed by OS, so not reporting + _snprintf( strResponse, dwResponseLen, XBX_DBGRESPONSEPREFIX "Available: %.2f MB, Used: %.2f MB, Free: %.2f MB", + stat.dwTotalPhys/( 1024.0f*1024.0f ) - 32.0f, + ( stat.dwTotalPhys - stat.dwAvailPhys )/( 1024.0f*1024.0f ) - 32.0f, + stat.dwAvailPhys/( 1024.0f*1024.0f ) ); + } + goto cleanUp; + } + + if ( g_xbx_dbgRemoteBuf[0] ) + { + // previous command still pending + _xdbg_strcpyn( strResponse, XBX_DBGRESPONSEPREFIX "Cannot execute: Previous command still pending", dwResponseLen ); + } + else + { + // add the command to the event queue to be processed by main app + _xdbg_strcpy( g_xbx_dbgRemoteBuf, strCommand ); + XBX_QueueEvent( XEV_REMOTECMD, ( int )g_xbx_dbgRemoteBuf, 0, 0 ); + _xdbg_strcpyn( strResponse, XBX_DBGRESPONSEPREFIX "OK", dwResponseLen ); + } + +cleanUp: + return XBDM_NOERR; +} + +//----------------------------------------------------------------------------- +// XBX_SendRemoteCommand +// +//----------------------------------------------------------------------------- +void CXboxConsole::SendRemoteCommand( const char *pCommand, bool async ) +{ + char cmdString[XBX_MAX_RCMDLENGTH]; + + if ( XBX_NoXBDM() || !IsConsoleConnected() ) + return; + + AUTO_LOCK_FM( g_xbx_dbgChannelMutex ); + + _snprintf( cmdString, sizeof( cmdString ), "%s!%s", XBX_DBGCOMMANDPREFIX, pCommand ); + HRESULT hr = DmSendNotificationString( cmdString ); + if ( FAILED( hr ) ) + { + XBX_Error( "XBX_SendRemoteCommand: failed on %s", cmdString ); + } + + // wait for command completion + if ( !async ) + { + DWORD timeout; + if ( !strnicmp( pCommand, "Assert()", 8 ) ) + { + // the assert is waiting for user to make selection + timeout = INFINITE; + } + else + { + // no vxconsole operation should take this long + timeout = 15000; + } + + if ( WaitForSingleObject( g_xbx_dbgCmdCompleteEvent, timeout ) == WAIT_TIMEOUT ) + { + // we have no choice but to dump core + DmCrashDump( false ); + } + } +} + +//----------------------------------------------------------------------------- +// Handle delayed VXConsole transactions +// +//----------------------------------------------------------------------------- +static unsigned _DebugThreadFunc( void *pParam ) +{ + while ( 1 ) + { + Sleep( 10 ); + + if ( !g_xbx_DebugStringQueue.Count() && !g_xbx_numProfileCounters && !g_xbx_freeMemory ) + { + continue; + } + + if ( g_xbx_numProfileCounters ) + { + // build and send asynchronously + char dbgCommand[XBX_MAX_RCMDLENGTH]; + _snprintf( dbgCommand, sizeof( dbgCommand ), "SetProfileData() %s 0x%8.8x", g_xbx_profileName, g_xbx_profileCounters ); + XBX_SendRemoteCommand( dbgCommand, true ); + + // mark as sent + g_xbx_numProfileCounters = 0; + } + + if ( g_xbx_freeMemory ) + { + // build and send asynchronously + char dbgCommand[XBX_MAX_RCMDLENGTH]; + _snprintf( dbgCommand, sizeof( dbgCommand ), "FreeMemory() 0x%8.8x", g_xbx_freeMemory ); + XBX_SendRemoteCommand( dbgCommand, true ); + + // mark as sent + g_xbx_freeMemory = 0; + } + + bool bRemoteValid = g_xbx_bUseVXConsoleOutput && XBX_IsConsoleConnected(); + while ( 1 ) + { + DebugString_t debugString; + if ( !g_xbx_DebugStringQueue.PopItem( &debugString ) ) + { + break; + } + + OutputStringToDevice( debugString.color, debugString.pString, bRemoteValid ); + free( debugString.pString ); + } + } + + return 0; +} + +//----------------------------------------------------------------------------- +// XBX_InitConsoleMonitor +// +//----------------------------------------------------------------------------- +void CXboxConsole::InitConsoleMonitor( bool bWaitForConnect ) +{ + if ( XBX_NoXBDM() ) + return; + + // create our events + g_xbx_dbgValidEvent = CreateEvent( XBOX_DONTCARE, TRUE, FALSE, NULL ); + g_xbx_dbgCmdCompleteEvent = CreateEvent( XBOX_DONTCARE, FALSE, FALSE, NULL ); + + // register our command handler with the debug monitor + HRESULT hr = DmRegisterCommandProcessor( XBX_DBGCOMMANDPREFIX, _DebugCommandHandler ); + if ( FAILED( hr ) ) + { + XBX_Error( "XBX_InitConsoleMonitor: failed to register command processor" ); + } + + // user can have output bypass slave thread + g_xbx_bDoSyncOutput = CommandLine()->FindParm( "-syncoutput" ) != 0; + + // create a slave thread to do delayed VXConsole transactions + ThreadId_t threadID; + g_xbx_hDebugThread = CreateSimpleThread( _DebugThreadFunc, NULL, &threadID, 16*1024 ); + ThreadSetDebugName( threadID, "DebugThread" ); + ThreadSetAffinity( g_xbx_hDebugThread, XBOX_PROCESSOR_5 ); + + if ( bWaitForConnect ) + { + XBX_DebugString( XBX_CLR_DEFAULT, "Waiting For VXConsole Connection...\n" ); + WaitForSingleObject( g_xbx_dbgValidEvent, INFINITE ); + } +} + +//----------------------------------------------------------------------------- +// Sends a disconnect signal to possibly attached VXConsole. +//----------------------------------------------------------------------------- +void CXboxConsole::DisconnectConsoleMonitor() +{ + if ( XBX_NoXBDM() ) + return; + + // caller is trying to safely stop vxconsole traffic, disconnect must be synchronous + XBX_SendRemoteCommand( "Disconnect()", false ); +} + +bool CXboxConsole::GetXboxName( char *pName, unsigned *pLength ) +{ + return ( DmGetXboxName( pName, (DWORD *)pLength ) == XBDM_NOERR ); +} + +void CXboxConsole::CrashDump( bool b ) +{ + DmCrashDump(b); +} + +//----------------------------------------------------------------------------- +// Walk to a specific module and dump size info +//----------------------------------------------------------------------------- +int CXboxConsole::DumpModuleSize( const char *pName ) +{ + HRESULT error; + PDM_WALK_MODULES pWalkMod = NULL; + DMN_MODLOAD modLoad; + int size = 0; + + // iterate and find match + do + { + error = DmWalkLoadedModules( &pWalkMod, &modLoad ); + if ( XBDM_NOERR == error && !stricmp( modLoad.Name, pName ) ) + { + Msg( "0x%8.8x, %5.2f MB, %s\n", modLoad.BaseAddress, modLoad.Size/( 1024.0f*1024.0f ), modLoad.Name ); + size = modLoad.Size; + error = XBDM_ENDOFLIST; + } + } + while ( XBDM_NOERR == error ); + DmCloseLoadedModules( pWalkMod ); + + if ( error != XBDM_ENDOFLIST ) + { + Warning( "DmWalkLoadedModules() failed.\n" ); + } + + return size; +} + +//----------------------------------------------------------------------------- +// 360 spew sizes of dll modules +//----------------------------------------------------------------------------- +char const* HACK_stristr( char const* pStr, char const* pSearch ) // hack because moved code from above vstdlib +{ + AssertValidStringPtr(pStr); + AssertValidStringPtr(pSearch); + + if (!pStr || !pSearch) + return 0; + + char const* pLetter = pStr; + + // Check the entire string + while (*pLetter != 0) + { + // Skip over non-matches + if (tolower((unsigned char)*pLetter) == tolower((unsigned char)*pSearch)) + { + // Check for match + char const* pMatch = pLetter + 1; + char const* pTest = pSearch + 1; + while (*pTest != 0) + { + // We've run off the end; don't bother. + if (*pMatch == 0) + return 0; + + if (tolower((unsigned char)*pMatch) != tolower((unsigned char)*pTest)) + break; + + ++pMatch; + ++pTest; + } + + // Found a match! + if (*pTest == 0) + return pLetter; + } + + ++pLetter; + } + + return 0; +} + +void CXboxConsole::DumpDllInfo( const char *pBasePath ) +{ + // Directories containing dlls + static char *dllDirs[] = + { + "bin", + "hl2\\bin", + "tf\\bin", + "portal\\bin", + "episodic\\bin" + }; + + char binPath[MAX_PATH]; + char dllPath[MAX_PATH]; + char searchPath[MAX_PATH]; + + HMODULE hModule; + WIN32_FIND_DATA wfd; + HANDLE hFind; + + Msg( "Dumping Module Sizes...\n" ); + + for ( int i = 0; i < ARRAYSIZE( dllDirs ); ++i ) + { + int totalSize = 0; + + _snprintf( binPath, sizeof( binPath ), "%s\\%s", pBasePath, dllDirs[i] ); + _snprintf( searchPath, sizeof( binPath ), "%s\\*.dll", binPath ); + + // show the directory we're searching + Msg( "\nDirectory: %s\n\n", binPath ); + + // Start the find and check for failure. + hFind = FindFirstFile( searchPath, &wfd ); + if ( INVALID_HANDLE_VALUE == hFind ) + { + Warning( "No Files Found.\n" ); + } + else + { + // Load and unload each dll individually. + do + { + if ( !HACK_stristr( wfd.cFileName, "_360.dll" ) ) + { + // exclude explicit pc dlls + // FindFirstFile does not support a spec mask of *_360.dll on the Xbox HDD + continue; + } + + _snprintf( dllPath, sizeof( dllPath ), "%s\\%s", binPath, wfd.cFileName ); + hModule = LoadLibrary( dllPath ); + if ( hModule ) + { + totalSize += DumpModuleSize( wfd.cFileName ); + FreeLibrary( hModule ); + } + else + { + Warning( "Failed to load: %s\n", dllPath ); + } + } + while( FindNextFile( hFind, &wfd ) ); + + FindClose( hFind ); + + Msg( "Total Size: %.2f MB\n", totalSize/( 1024.0f*1024.0f ) ); + } + } +} + +void CXboxConsole::OutputDebugString( const char *p ) +{ + ::OutputDebugStringA( p ); +} + +bool CXboxConsole::IsDebuggerPresent() +{ + return ( DmIsDebuggerPresent() != 0 ); +} diff --git a/utils/xbox/vxbdm/rcommands.cpp b/utils/xbox/vxbdm/rcommands.cpp new file mode 100644 index 0000000..83b9cea --- /dev/null +++ b/utils/xbox/vxbdm/rcommands.cpp @@ -0,0 +1,320 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Xbox Remote Commands +// +//=====================================================================================// + +#include "xbox/xbox_console.h" +#include "xbox/xbox_vxconsole.h" +#include "tier0/tslist.h" +#include "tier0/memdbgon.h" + +CInterlockedInt g_xbx_numProfileCounters; +unsigned int g_xbx_profileCounters[XBX_MAX_PROFILE_COUNTERS]; +char g_xbx_profileName[32]; + +//----------------------------------------------------------------------------- +// XBX_rSetProfileAttributes +// +// Expose profile counters attributes to the console. +//----------------------------------------------------------------------------- +int CXboxConsole::SetProfileAttributes( const char *pProfileName, int numCounters, const char *names[], unsigned int colors[] ) +{ + char dbgCommand[XBX_MAX_RCMDLENGTH]; + int retVal; + xrProfile_t* profileList; + + if ( numCounters > XBX_MAX_PROFILE_COUNTERS ) + { + numCounters = XBX_MAX_PROFILE_COUNTERS; + } + + profileList = new xrProfile_t[numCounters]; + memset( profileList, 0, numCounters*sizeof( xrProfile_t ) ); + + for ( int i=0; i<numCounters; i++ ) + { + strncpy( profileList[i].labelString, names[i], sizeof( profileList[i].labelString ) ); + profileList[i].labelString[sizeof( profileList[i].labelString ) - 1] = '\0'; + + profileList[i].color = colors[i]; + } + + _snprintf( dbgCommand, sizeof( dbgCommand ), "SetProfile() %s 0x%8.8x 0x%8.8x 0x%8.8x", pProfileName, numCounters, profileList, &retVal ); + XBX_SendRemoteCommand( dbgCommand, false ); + + delete[] profileList; + + return ( retVal ); +} + +//----------------------------------------------------------------------------- +// XBX_rSetProfileData +// +// Expose profile counters to the console. Expected to be called once per game frame. +//----------------------------------------------------------------------------- +void CXboxConsole::SetProfileData( const char *pProfileName, int numCounters, unsigned int *pCounters ) +{ + static unsigned int lastTime = 0; + unsigned int time; + + // not faster than 10Hz + time = GetTickCount(); + if ( time - lastTime < 100 ) + { + return; + } + + if ( g_xbx_numProfileCounters == 0 ) + { + _snprintf( g_xbx_profileName, sizeof( g_xbx_profileName ), pProfileName ); + + if ( numCounters > XBX_MAX_PROFILE_COUNTERS ) + { + numCounters = XBX_MAX_PROFILE_COUNTERS; + } + memcpy( g_xbx_profileCounters, pCounters, numCounters * sizeof( unsigned int ) ); + + // mark for sending + g_xbx_numProfileCounters = numCounters; + + lastTime = time; + } +} + +//----------------------------------------------------------------------------- +// XBX_rMemDump +// +// Send signal to remote console to read mempry dump in specified filename. +//----------------------------------------------------------------------------- +int CXboxConsole::MemDump( const char *pDumpFileName ) +{ + char dbgCommand[XBX_MAX_RCMDLENGTH]; + + _snprintf( dbgCommand, sizeof( dbgCommand ), "MemDump() %s", pDumpFileName ); + XBX_SendRemoteCommand( dbgCommand, true ); + + return 0; +} + +//----------------------------------------------------------------------------- +// XBX_rTimeStampLog +// +// Send time stamp to remote console +//----------------------------------------------------------------------------- +int CXboxConsole::TimeStampLog( float time, const char *pString ) +{ + char dbgCommand[XBX_MAX_RCMDLENGTH]; + int retVal; + xrTimeStamp_t timeStamp; + MEMORYSTATUS stat; + static int lastMemoryStamp = 0; + static float lastTimeStamp = 0; + + // get current available memory + GlobalMemoryStatus( &stat ); + + if ( !lastTimeStamp || time < lastTimeStamp ) + { + // first entry or restart, reset stamps + lastMemoryStamp = stat.dwAvailPhys; + lastTimeStamp = time; + } + + timeStamp.time = time; + timeStamp.deltaTime = time - lastTimeStamp; + timeStamp.memory = stat.dwAvailPhys; + timeStamp.deltaMemory = stat.dwAvailPhys - lastMemoryStamp; + + strncpy( timeStamp.messageString, pString, sizeof( timeStamp.messageString ) ); + timeStamp.messageString[sizeof( timeStamp.messageString ) - 1] = '\0'; + + _snprintf( dbgCommand, sizeof( dbgCommand ), "TimeStampLog() 0x%8.8x 0x%8.8x", &timeStamp, &retVal ); + XBX_SendRemoteCommand( dbgCommand, false ); + + lastTimeStamp = time; + lastMemoryStamp = stat.dwAvailPhys; + + return retVal; +} + +//----------------------------------------------------------------------------- +// XBX_rMaterialList +// +// Send material list to remote console +//----------------------------------------------------------------------------- +int CXboxConsole::MaterialList( int nMaterials, const xMaterialList_t* pXMaterialList ) +{ + char dbgCommand[XBX_MAX_RCMDLENGTH]; + int retVal; + xrMaterial_t* pRemoteList; + + pRemoteList = new xrMaterial_t[nMaterials]; + memset( pRemoteList, 0, nMaterials*sizeof( xrMaterial_t ) ); + + for ( int i=0; i<nMaterials; i++ ) + { + strncpy( pRemoteList[i].nameString, pXMaterialList[i].pName, sizeof( pRemoteList[i].nameString ) ); + pRemoteList[i].nameString[sizeof( pRemoteList[i].nameString ) - 1] = '\0'; + + strncpy( pRemoteList[i].shaderString, pXMaterialList[i].pShaderName, sizeof( pRemoteList[i].shaderString ) ); + pRemoteList[i].shaderString[sizeof( pRemoteList[i].shaderString ) - 1] = '\0'; + + pRemoteList[i].refCount = pXMaterialList[i].refCount; + } + + _snprintf( dbgCommand, sizeof( dbgCommand ), "MaterialList() 0x%8.8x 0x%8.8x 0x%8.8x", nMaterials, pRemoteList, &retVal ); + XBX_SendRemoteCommand( dbgCommand, false ); + + delete [] pRemoteList; + + return retVal; +} + +//----------------------------------------------------------------------------- +// XBX_rTextureList +// +// Send texture list to remote console +//----------------------------------------------------------------------------- +int CXboxConsole::TextureList( int nTextures, const xTextureList_t* pXTextureList ) +{ + char dbgCommand[XBX_MAX_RCMDLENGTH]; + int retVal; + xrTexture_t* pRemoteList; + + pRemoteList = new xrTexture_t[nTextures]; + memset( pRemoteList, 0, nTextures*sizeof( xrTexture_t ) ); + + for ( int i=0; i<nTextures; i++ ) + { + strncpy( pRemoteList[i].nameString, pXTextureList[i].pName, sizeof( pRemoteList[i].nameString ) ); + pRemoteList[i].nameString[sizeof( pRemoteList[i].nameString ) - 1] = '\0'; + + strncpy( pRemoteList[i].groupString, pXTextureList[i].pGroupName, sizeof( pRemoteList[i].groupString ) ); + pRemoteList[i].groupString[sizeof( pRemoteList[i].groupString ) - 1] = '\0'; + + strncpy( pRemoteList[i].formatString, pXTextureList[i].pFormatName, sizeof( pRemoteList[i].formatString ) ); + pRemoteList[i].formatString[sizeof( pRemoteList[i].formatString ) - 1] = '\0'; + + pRemoteList[i].size = pXTextureList[i].size; + pRemoteList[i].width = pXTextureList[i].width; + pRemoteList[i].height = pXTextureList[i].height; + pRemoteList[i].depth = pXTextureList[i].depth; + pRemoteList[i].numLevels = pXTextureList[i].numLevels; + pRemoteList[i].binds = pXTextureList[i].binds; + pRemoteList[i].refCount = pXTextureList[i].refCount; + pRemoteList[i].sRGB = pXTextureList[i].sRGB; + pRemoteList[i].edram = pXTextureList[i].edram; + pRemoteList[i].procedural = pXTextureList[i].procedural; + pRemoteList[i].fallback = pXTextureList[i].fallback; + pRemoteList[i].final = pXTextureList[i].final; + pRemoteList[i].failed = pXTextureList[i].failed; + } + + _snprintf( dbgCommand, sizeof( dbgCommand ), "TextureList() 0x%8.8x 0x%8.8x 0x%8.8x", nTextures, pRemoteList, &retVal ); + XBX_SendRemoteCommand( dbgCommand, false ); + + delete [] pRemoteList; + + return ( retVal ); +} + +//----------------------------------------------------------------------------- +// XBX_rSoundList +// +// Send sound list to remote console +//----------------------------------------------------------------------------- +int CXboxConsole::SoundList( int nSounds, const xSoundList_t* pXSoundList ) +{ + char dbgCommand[XBX_MAX_RCMDLENGTH]; + int retVal; + xrSound_t* pRemoteList; + + pRemoteList = new xrSound_t[nSounds]; + memset( pRemoteList, 0, nSounds*sizeof( xrSound_t ) ); + + for ( int i=0; i<nSounds; i++ ) + { + strncpy( pRemoteList[i].nameString, pXSoundList[i].name, sizeof( pRemoteList[i].nameString ) ); + pRemoteList[i].nameString[sizeof( pRemoteList[i].nameString ) - 1] = '\0'; + + strncpy( pRemoteList[i].formatString, pXSoundList[i].formatName, sizeof( pRemoteList[i].formatString ) ); + pRemoteList[i].formatString[sizeof( pRemoteList[i].formatString ) - 1] = '\0'; + + pRemoteList[i].rate = pXSoundList[i].rate; + pRemoteList[i].bits = pXSoundList[i].bits; + pRemoteList[i].channels = pXSoundList[i].channels; + pRemoteList[i].looped = pXSoundList[i].looped; + pRemoteList[i].dataSize = pXSoundList[i].dataSize; + pRemoteList[i].numSamples = pXSoundList[i].numSamples; + pRemoteList[i].streamed = pXSoundList[i].streamed; + } + + _snprintf( dbgCommand, sizeof( dbgCommand ), "SoundList() 0x%8.8x 0x%8.8x 0x%8.8x", nSounds, pRemoteList, &retVal ); + XBX_SendRemoteCommand( dbgCommand, false ); + + delete [] pRemoteList; + + return ( retVal ); +} + +//----------------------------------------------------------------------------- +// XBX_rMapInfo +// +// Send signal to remote console with various info +//----------------------------------------------------------------------------- +int CXboxConsole::MapInfo( const xMapInfo_t *pXMapInfo ) +{ + char dbgCommand[XBX_MAX_RCMDLENGTH]; + int retVal; + xrMapInfo_t xrMapInfo; + + memcpy( xrMapInfo.position, pXMapInfo->position, 3 * sizeof( float ) ); + memcpy( xrMapInfo.angle, pXMapInfo->angle, 3 * sizeof( float ) ); + + strncpy( xrMapInfo.mapPath, pXMapInfo->mapPath, sizeof( xrMapInfo.mapPath ) ); + xrMapInfo.mapPath[sizeof( xrMapInfo.mapPath ) - 1] = '\0'; + + strncpy( xrMapInfo.savePath, pXMapInfo->savePath, sizeof( xrMapInfo.savePath ) ); + xrMapInfo.savePath[sizeof( xrMapInfo.savePath ) - 1] = '\0'; + + xrMapInfo.build = pXMapInfo->build; + xrMapInfo.skill = pXMapInfo->skill; + + _snprintf( dbgCommand, sizeof( dbgCommand ), "MapInfo() 0x%8.8x 0x%8.8x", &xrMapInfo, &retVal ); + XBX_SendRemoteCommand( dbgCommand, false ); + + return retVal; +} + +//----------------------------------------------------------------------------- +// XBX_rAddCommands +// +// Expose commands to remote console +//----------------------------------------------------------------------------- +int CXboxConsole::AddCommands( int numCommands, const char* commands[], const char* help[] ) +{ + char dbgCommand[XBX_MAX_RCMDLENGTH]; + int retVal; + xrCommand_t* cmdList; + + cmdList = new xrCommand_t[numCommands]; + memset( cmdList, 0, numCommands*sizeof( xrCommand_t ) ); + + for ( int i=0; i<numCommands; i++ ) + { + strncpy( cmdList[i].nameString, commands[i], sizeof( cmdList[i].nameString ) ); + cmdList[i].nameString[sizeof( cmdList[i].nameString ) - 1] = '\0'; + + strncpy( cmdList[i].helpString, help[i], sizeof( cmdList[i].helpString ) ); + cmdList[i].helpString[sizeof( cmdList[i].helpString ) - 1] = '\0'; + } + + _snprintf( dbgCommand, sizeof( dbgCommand ), "AddCommands() 0x%8.8x 0x%8.8x 0x%8.8x", numCommands, cmdList, &retVal ); + XBX_SendRemoteCommand( dbgCommand, false ); + + delete [] cmdList; + + return ( retVal ); +} + diff --git a/utils/xbox/vxbdm/vxbdm.vpc b/utils/xbox/vxbdm/vxbdm.vpc new file mode 100644 index 0000000..65c74e7 --- /dev/null +++ b/utils/xbox/vxbdm/vxbdm.vpc @@ -0,0 +1,37 @@ +//----------------------------------------------------------------------------- +// vxbdm.VPC +// +// Project Script +//----------------------------------------------------------------------------- + +$Macro SRCDIR "..\..\.." +$Macro OUTBINDIR "$SRCDIR\..\game\bin" + +$Include "$SRCDIR\vpc_scripts\source_dll_x360_base.vpc" + +$Configuration +{ + $Xbox360ImageConversion + { + // General + $ExportByName "Yes" + } +} + +$Project +{ + $Folder "Link Libraries" + { + -$File "$SRCDIR\lib\public\tier1_360.lib" + -$File "$SRCDIR\lib\public\vstdlib_360.lib" + } +} + +$Project "vxbdm" +{ + $Folder "Source Files" + { + $file "console.cpp" + $File "rcommands.cpp" + } +} diff --git a/utils/xbox/vxbdm/xbox/xbox.def b/utils/xbox/vxbdm/xbox/xbox.def new file mode 100644 index 0000000..3c64bf8 --- /dev/null +++ b/utils/xbox/vxbdm/xbox/xbox.def @@ -0,0 +1,3 @@ +LIBRARY vxbdm_360.dll +EXPORTS + GetConsoleInterface @1
\ No newline at end of file |