Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

763 lines
20 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Xbox console link
  4. //
  5. //=====================================================================================//
  6. #include "xbox/xbox_console.h"
  7. #include "xbox/xbox_vxconsole.h"
  8. #include "tier0/threadtools.h"
  9. #include "tier0/tslist.h"
  10. #include "tier0/ICommandLine.h"
  11. #include "tier0/memdbgon.h"
  12. // all redirecting funneled here, stop redirecting in this module only
  13. #undef OutputDebugStringA
  14. #pragma comment( lib, "xbdm.lib" )
  15. struct DebugString_t
  16. {
  17. unsigned int color;
  18. char *pString;
  19. };
  20. #define XBX_DBGCOMMANDPREFIX "XCMD"
  21. #define XBX_DBGRESPONSEPREFIX "XACK"
  22. #define XBX_DBGPRINTPREFIX "XPRT"
  23. #define XBX_DBGCOLORPREFIX "XCLR"
  24. #define XBX_MAX_RCMDLENGTH 256
  25. #define XBX_MAX_MESSAGE 2048
  26. CThreadFastMutex g_xbx_dbgChannelMutex;
  27. CThreadFastMutex g_xbx_dbgCommandHandlerMutex;
  28. static char g_xbx_dbgRemoteBuf[XBX_MAX_RCMDLENGTH];
  29. static HANDLE g_xbx_dbgValidEvent;
  30. static HANDLE g_xbx_dbgCmdCompleteEvent;
  31. bool g_xbx_bUseVXConsoleOutput = true;
  32. bool g_xbx_bDoSyncOutput;
  33. static ThreadHandle_t g_xbx_hDebugThread;
  34. CTSQueue<DebugString_t> g_xbx_DebugStringQueue;
  35. extern CInterlockedInt g_xbx_numProfileCounters;
  36. extern unsigned int g_xbx_profileCounters[];
  37. extern char g_xbx_profileName[];
  38. int g_xbx_freeMemory;
  39. _inline bool XBX_NoXBDM() { return false; }
  40. static CXboxConsole XboxConsole;
  41. DLL_EXPORT IXboxConsole *GetConsoleInterface()
  42. {
  43. return &XboxConsole;
  44. }
  45. //-----------------------------------------------------------------------------
  46. // Low level string output.
  47. // Input string should be stack based, can get clobbered.
  48. //-----------------------------------------------------------------------------
  49. static void OutputStringToDevice( unsigned int color, char *pString, bool bRemoteValid )
  50. {
  51. if ( !bRemoteValid )
  52. {
  53. // local debug only
  54. OutputDebugStringA( pString );
  55. return;
  56. }
  57. // remote debug valid
  58. // non pure colors don't translate well - find closest pure hue
  59. unsigned int bestColor = color;
  60. int r = ( bestColor & 0xFF );
  61. int g = ( bestColor >> 8 ) & 0xFF;
  62. int b = ( bestColor >> 16 ) & 0xFF;
  63. if ( ( r && r != 255 ) || ( g && g != 255 ) || ( b && b != 255 ) )
  64. {
  65. int r0, g0, b0;
  66. unsigned int minDist = 0xFFFFFFFF;
  67. for ( int i=0; i<8; i++ )
  68. {
  69. r0 = g0 = b0 = 0;
  70. if ( i&4 )
  71. r0 = 255;
  72. if ( i&2 )
  73. g0 = 255;
  74. if ( i&1 )
  75. b0 = 255;
  76. unsigned int d = ( r-r0 )*( r-r0 ) + ( g-g0 )*( g-g0 ) + ( b-b0 )*( b-b0 );
  77. if ( minDist > d )
  78. {
  79. minDist = d;
  80. bestColor = XMAKECOLOR( r0, g0, b0 );
  81. }
  82. }
  83. }
  84. // create color string
  85. char colorString[16];
  86. sprintf( colorString, XBX_DBGCOLORPREFIX "[%8.8x]", bestColor );
  87. // chunk line out, for each cr
  88. char strBuffer[XBX_MAX_RCMDLENGTH];
  89. char *pStart = pString;
  90. char *pEnd = pStart + strlen( pStart );
  91. char *pNext;
  92. while ( pStart < pEnd )
  93. {
  94. pNext = strchr( pStart, '\n' );
  95. if ( !pNext )
  96. pNext = pEnd;
  97. else
  98. *pNext = '\0';
  99. int length = _snprintf( strBuffer, XBX_MAX_RCMDLENGTH, "%s!%s%s", XBX_DBGPRINTPREFIX, colorString, pStart );
  100. if ( length == -1 )
  101. {
  102. strBuffer[sizeof( strBuffer )-1] = '\0';
  103. }
  104. // Send the string
  105. DmSendNotificationString( strBuffer );
  106. // advance past cr
  107. pStart = pNext+1;
  108. }
  109. }
  110. //-----------------------------------------------------------------------------
  111. // XBX_IsConsoleConnected
  112. //
  113. //-----------------------------------------------------------------------------
  114. bool CXboxConsole::IsConsoleConnected()
  115. {
  116. bool bConnected;
  117. if ( g_xbx_dbgValidEvent == NULL )
  118. {
  119. // init was never called
  120. return false;
  121. }
  122. AUTO_LOCK_FM( g_xbx_dbgChannelMutex );
  123. bConnected = ( WaitForSingleObject( g_xbx_dbgValidEvent, 0 ) == WAIT_OBJECT_0 );
  124. return bConnected;
  125. }
  126. //-----------------------------------------------------------------------------
  127. // Output string to listening console. Queues output for slave thread.
  128. // Needs to be lightweight.
  129. //-----------------------------------------------------------------------------
  130. void CXboxConsole::DebugString( unsigned int color, const char* pFormat, ... )
  131. {
  132. if ( XBX_NoXBDM() )
  133. return;
  134. va_list args;
  135. char szStringBuffer[XBX_MAX_MESSAGE];
  136. int length;
  137. // resolve string
  138. va_start( args, pFormat );
  139. length = _vsnprintf( szStringBuffer, sizeof( szStringBuffer ), pFormat, args );
  140. if ( length == -1 )
  141. {
  142. szStringBuffer[sizeof( szStringBuffer ) - 1] = '\0';
  143. }
  144. va_end( args );
  145. if ( !g_xbx_bDoSyncOutput )
  146. {
  147. // queue string for delayed output
  148. DebugString_t debugString;
  149. debugString.color = color;
  150. debugString.pString = strdup( szStringBuffer );
  151. g_xbx_DebugStringQueue.PushItem( debugString );
  152. }
  153. else
  154. {
  155. bool bRemoteValid = g_xbx_bUseVXConsoleOutput && XBX_IsConsoleConnected();
  156. OutputStringToDevice( color, szStringBuffer, bRemoteValid );
  157. }
  158. }
  159. //-----------------------------------------------------------------------------
  160. // Waits for debug queue to drain.
  161. //-----------------------------------------------------------------------------
  162. void CXboxConsole::FlushDebugOutput()
  163. {
  164. while ( g_xbx_DebugStringQueue.Count() != 0 )
  165. {
  166. Sleep( 1 );
  167. }
  168. }
  169. //-----------------------------------------------------------------------------
  170. // _xdbg_strlen
  171. //
  172. // Critical section safe.
  173. //-----------------------------------------------------------------------------
  174. int _xdbg_strlen( const CHAR* str )
  175. {
  176. const CHAR* strEnd = str;
  177. while( *strEnd )
  178. strEnd++;
  179. return strEnd - str;
  180. }
  181. //-----------------------------------------------------------------------------
  182. // _xdbg_tolower
  183. //
  184. // Critical section safe.
  185. //-----------------------------------------------------------------------------
  186. inline CHAR _xdbg_tolower( CHAR ch )
  187. {
  188. if( ch >= 'A' && ch <= 'Z' )
  189. return ch - ( 'A' - 'a' );
  190. else
  191. return ch;
  192. }
  193. //-----------------------------------------------------------------------------
  194. // _xdbg_strnicmp
  195. //
  196. // Critical section safe.
  197. //-----------------------------------------------------------------------------
  198. BOOL _xdbg_strnicmp( const CHAR* str1, const CHAR* str2, int n )
  199. {
  200. while ( ( _xdbg_tolower( *str1 ) == _xdbg_tolower( *str2 ) ) && *str1 && n > 0 )
  201. {
  202. --n;
  203. ++str1;
  204. ++str2;
  205. }
  206. return ( !n || _xdbg_tolower( *str1 ) == _xdbg_tolower( *str2 ) );
  207. }
  208. //-----------------------------------------------------------------------------
  209. // _xdbg_strcpy
  210. //
  211. // Critical section safe.
  212. //-----------------------------------------------------------------------------
  213. VOID _xdbg_strcpy( CHAR* strDest, const CHAR* strSrc )
  214. {
  215. while ( ( *strDest++ = *strSrc++ ) != 0 );
  216. }
  217. //-----------------------------------------------------------------------------
  218. // _xdbg_strcpyn
  219. //
  220. // Critical section safe.
  221. //-----------------------------------------------------------------------------
  222. VOID _xdbg_strcpyn( CHAR* strDest, const CHAR* strSrc, int numChars )
  223. {
  224. while ( numChars>0 && ( *strDest++ = *strSrc++ ) != 0 )
  225. numChars--;
  226. }
  227. //-----------------------------------------------------------------------------
  228. // _xdbg_gettoken
  229. //
  230. // Critical section safe.
  231. //-----------------------------------------------------------------------------
  232. void _xdbg_gettoken( CHAR** tokenStream, CHAR* token, int tokenSize )
  233. {
  234. int c;
  235. int len;
  236. CHAR* data;
  237. len = 0;
  238. // skip prefix whitespace
  239. data = *tokenStream;
  240. while ( ( c = *data ) <= ' ' )
  241. {
  242. if ( !c )
  243. goto cleanUp;
  244. data++;
  245. }
  246. // parse a token
  247. do
  248. {
  249. if ( len < tokenSize )
  250. token[len++] = c;
  251. data++;
  252. c = *data;
  253. } while ( c > ' ' );
  254. if ( len >= tokenSize )
  255. len = 0;
  256. cleanUp:
  257. token[len] = '\0';
  258. *tokenStream = data;
  259. }
  260. //-----------------------------------------------------------------------------
  261. // _xdbg_tokenize
  262. //
  263. // Critical section safe.
  264. //-----------------------------------------------------------------------------
  265. int _xdbg_tokenize( CHAR* tokenStream, CHAR** tokens, int maxTokens )
  266. {
  267. char token[64];
  268. // tokenize stream into seperate tokens
  269. int numTokens = 0;
  270. while ( 1 )
  271. {
  272. tokens[numTokens++] = tokenStream;
  273. if ( numTokens >= maxTokens )
  274. break;
  275. _xdbg_gettoken( &tokenStream, token, sizeof( token ) );
  276. if ( !tokenStream[0] || !token[0] )
  277. break;
  278. *tokenStream = '\0';
  279. tokenStream++;
  280. }
  281. return ( numTokens );
  282. }
  283. //-----------------------------------------------------------------------------
  284. // _xdbg_findtoken
  285. //
  286. // Critical section safe. Returns -1 if not found
  287. //-----------------------------------------------------------------------------
  288. int _xdbg_findtoken( CHAR** tokens, int numTokens, CHAR* token )
  289. {
  290. int i;
  291. int len;
  292. len = _xdbg_strlen( token );
  293. for ( i=0; i<numTokens; i++ )
  294. {
  295. if ( _xdbg_strnicmp( tokens[i], token, len ) )
  296. return i;
  297. }
  298. // not found
  299. return -1;
  300. }
  301. //-----------------------------------------------------------------------------
  302. // _DebugCommandHandler
  303. //
  304. //-----------------------------------------------------------------------------
  305. HRESULT __stdcall _DebugCommandHandler( const CHAR* strCommand, CHAR* strResponse, DWORD dwResponseLen, PDM_CMDCONT pdmcc )
  306. {
  307. CHAR buff[256];
  308. CHAR* args[8];
  309. int numArgs;
  310. AUTO_LOCK_FM( g_xbx_dbgCommandHandlerMutex );
  311. // skip over the command prefix and the exclamation mark
  312. strCommand += _xdbg_strlen( XBX_DBGCOMMANDPREFIX ) + 1;
  313. if ( strCommand[0] == '\0' )
  314. {
  315. // just a ping
  316. goto cleanUp;
  317. }
  318. // get command and optional arguments
  319. _xdbg_strcpyn( buff, strCommand, sizeof( buff ) );
  320. numArgs = _xdbg_tokenize( buff, args, sizeof( args )/sizeof( CHAR* ) );
  321. if ( _xdbg_strnicmp( args[0], "__connect__", 11 ) )
  322. {
  323. if ( numArgs > 1 && atoi( args[1] ) == VXCONSOLE_PROTOCOL_VERSION )
  324. {
  325. // initial connect - respond that we're connected
  326. _xdbg_strcpyn( strResponse, XBX_DBGRESPONSEPREFIX "Connected To Application.", dwResponseLen );
  327. SetEvent( g_xbx_dbgValidEvent );
  328. // notify convar system to send its commands
  329. // allows vxconsole to re-connect during game
  330. _xdbg_strcpy( g_xbx_dbgRemoteBuf, "getcvars" );
  331. XBX_QueueEvent( XEV_REMOTECMD, ( int )g_xbx_dbgRemoteBuf, 0, 0 );
  332. }
  333. else
  334. {
  335. _xdbg_strcpyn( strResponse, XBX_DBGRESPONSEPREFIX "Rejecting Connection: Wrong Protocol Version.", dwResponseLen );
  336. }
  337. goto cleanUp;
  338. }
  339. if ( _xdbg_strnicmp( args[0], "__disconnect__", 14 ) )
  340. {
  341. // respond that we're disconnected
  342. _xdbg_strcpyn( strResponse, XBX_DBGRESPONSEPREFIX "Disconnected.", dwResponseLen );
  343. ResetEvent( g_xbx_dbgValidEvent );
  344. goto cleanUp;
  345. }
  346. if ( _xdbg_strnicmp( args[0], "__complete__", 12 ) )
  347. {
  348. // remote server has finished command - respond to acknowledge
  349. _xdbg_strcpyn( strResponse, XBX_DBGRESPONSEPREFIX "OK", dwResponseLen );
  350. // set the complete event - allows expected synchronous calling mechanism
  351. SetEvent( g_xbx_dbgCmdCompleteEvent );
  352. goto cleanUp;
  353. }
  354. if ( _xdbg_strnicmp( args[0], "__memory__", 10 ) )
  355. {
  356. // get a current stat of available memory
  357. MEMORYSTATUS stat;
  358. GlobalMemoryStatus( &stat );
  359. g_xbx_freeMemory = stat.dwAvailPhys;
  360. if ( _xdbg_findtoken( args, numArgs, "quiet" ) > 0 )
  361. {
  362. _xdbg_strcpyn( strResponse, XBX_DBGRESPONSEPREFIX "OK", dwResponseLen );
  363. }
  364. else
  365. {
  366. // 32 MB is reserved and fixed by OS, so not reporting
  367. _snprintf( strResponse, dwResponseLen, XBX_DBGRESPONSEPREFIX "Available: %.2f MB, Used: %.2f MB, Free: %.2f MB",
  368. stat.dwTotalPhys/( 1024.0f*1024.0f ) - 32.0f,
  369. ( stat.dwTotalPhys - stat.dwAvailPhys )/( 1024.0f*1024.0f ) - 32.0f,
  370. stat.dwAvailPhys/( 1024.0f*1024.0f ) );
  371. }
  372. goto cleanUp;
  373. }
  374. if ( g_xbx_dbgRemoteBuf[0] )
  375. {
  376. // previous command still pending
  377. _xdbg_strcpyn( strResponse, XBX_DBGRESPONSEPREFIX "Cannot execute: Previous command still pending", dwResponseLen );
  378. }
  379. else
  380. {
  381. // add the command to the event queue to be processed by main app
  382. _xdbg_strcpy( g_xbx_dbgRemoteBuf, strCommand );
  383. XBX_QueueEvent( XEV_REMOTECMD, ( int )g_xbx_dbgRemoteBuf, 0, 0 );
  384. _xdbg_strcpyn( strResponse, XBX_DBGRESPONSEPREFIX "OK", dwResponseLen );
  385. }
  386. cleanUp:
  387. return XBDM_NOERR;
  388. }
  389. //-----------------------------------------------------------------------------
  390. // XBX_SendRemoteCommand
  391. //
  392. //-----------------------------------------------------------------------------
  393. void CXboxConsole::SendRemoteCommand( const char *pCommand, bool async )
  394. {
  395. char cmdString[XBX_MAX_RCMDLENGTH];
  396. if ( XBX_NoXBDM() || !IsConsoleConnected() )
  397. return;
  398. AUTO_LOCK_FM( g_xbx_dbgChannelMutex );
  399. _snprintf( cmdString, sizeof( cmdString ), "%s!%s", XBX_DBGCOMMANDPREFIX, pCommand );
  400. HRESULT hr = DmSendNotificationString( cmdString );
  401. if ( FAILED( hr ) )
  402. {
  403. XBX_Error( "XBX_SendRemoteCommand: failed on %s", cmdString );
  404. }
  405. // wait for command completion
  406. if ( !async )
  407. {
  408. DWORD timeout;
  409. if ( !strnicmp( pCommand, "Assert()", 8 ) )
  410. {
  411. // the assert is waiting for user to make selection
  412. timeout = INFINITE;
  413. }
  414. else
  415. {
  416. // no vxconsole operation should take this long
  417. timeout = 15000;
  418. }
  419. if ( WaitForSingleObject( g_xbx_dbgCmdCompleteEvent, timeout ) == WAIT_TIMEOUT )
  420. {
  421. // we have no choice but to dump core
  422. DmCrashDump( false );
  423. }
  424. }
  425. }
  426. //-----------------------------------------------------------------------------
  427. // Handle delayed VXConsole transactions
  428. //
  429. //-----------------------------------------------------------------------------
  430. static unsigned _DebugThreadFunc( void *pParam )
  431. {
  432. while ( 1 )
  433. {
  434. Sleep( 10 );
  435. if ( !g_xbx_DebugStringQueue.Count() && !g_xbx_numProfileCounters && !g_xbx_freeMemory )
  436. {
  437. continue;
  438. }
  439. if ( g_xbx_numProfileCounters )
  440. {
  441. // build and send asynchronously
  442. char dbgCommand[XBX_MAX_RCMDLENGTH];
  443. _snprintf( dbgCommand, sizeof( dbgCommand ), "SetProfileData() %s 0x%8.8x", g_xbx_profileName, g_xbx_profileCounters );
  444. XBX_SendRemoteCommand( dbgCommand, true );
  445. // mark as sent
  446. g_xbx_numProfileCounters = 0;
  447. }
  448. if ( g_xbx_freeMemory )
  449. {
  450. // build and send asynchronously
  451. char dbgCommand[XBX_MAX_RCMDLENGTH];
  452. _snprintf( dbgCommand, sizeof( dbgCommand ), "FreeMemory() 0x%8.8x", g_xbx_freeMemory );
  453. XBX_SendRemoteCommand( dbgCommand, true );
  454. // mark as sent
  455. g_xbx_freeMemory = 0;
  456. }
  457. bool bRemoteValid = g_xbx_bUseVXConsoleOutput && XBX_IsConsoleConnected();
  458. while ( 1 )
  459. {
  460. DebugString_t debugString;
  461. if ( !g_xbx_DebugStringQueue.PopItem( &debugString ) )
  462. {
  463. break;
  464. }
  465. OutputStringToDevice( debugString.color, debugString.pString, bRemoteValid );
  466. free( debugString.pString );
  467. }
  468. }
  469. return 0;
  470. }
  471. //-----------------------------------------------------------------------------
  472. // XBX_InitConsoleMonitor
  473. //
  474. //-----------------------------------------------------------------------------
  475. void CXboxConsole::InitConsoleMonitor( bool bWaitForConnect )
  476. {
  477. if ( XBX_NoXBDM() )
  478. return;
  479. // create our events
  480. g_xbx_dbgValidEvent = CreateEvent( XBOX_DONTCARE, TRUE, FALSE, NULL );
  481. g_xbx_dbgCmdCompleteEvent = CreateEvent( XBOX_DONTCARE, FALSE, FALSE, NULL );
  482. // register our command handler with the debug monitor
  483. HRESULT hr = DmRegisterCommandProcessor( XBX_DBGCOMMANDPREFIX, _DebugCommandHandler );
  484. if ( FAILED( hr ) )
  485. {
  486. XBX_Error( "XBX_InitConsoleMonitor: failed to register command processor" );
  487. }
  488. // user can have output bypass slave thread
  489. g_xbx_bDoSyncOutput = CommandLine()->FindParm( "-syncoutput" ) != 0;
  490. // create a slave thread to do delayed VXConsole transactions
  491. ThreadId_t threadID;
  492. g_xbx_hDebugThread = CreateSimpleThread( _DebugThreadFunc, NULL, &threadID, 16*1024 );
  493. ThreadSetDebugName( threadID, "DebugThread" );
  494. ThreadSetAffinity( g_xbx_hDebugThread, XBOX_PROCESSOR_5 );
  495. if ( bWaitForConnect )
  496. {
  497. XBX_DebugString( XBX_CLR_DEFAULT, "Waiting For VXConsole Connection...\n" );
  498. WaitForSingleObject( g_xbx_dbgValidEvent, INFINITE );
  499. }
  500. }
  501. //-----------------------------------------------------------------------------
  502. // Sends a disconnect signal to possibly attached VXConsole.
  503. //-----------------------------------------------------------------------------
  504. void CXboxConsole::DisconnectConsoleMonitor()
  505. {
  506. if ( XBX_NoXBDM() )
  507. return;
  508. // caller is trying to safely stop vxconsole traffic, disconnect must be synchronous
  509. XBX_SendRemoteCommand( "Disconnect()", false );
  510. }
  511. bool CXboxConsole::GetXboxName( char *pName, unsigned *pLength )
  512. {
  513. return ( DmGetXboxName( pName, (DWORD *)pLength ) == XBDM_NOERR );
  514. }
  515. void CXboxConsole::CrashDump( bool b )
  516. {
  517. DmCrashDump(b);
  518. }
  519. //-----------------------------------------------------------------------------
  520. // Walk to a specific module and dump size info
  521. //-----------------------------------------------------------------------------
  522. int CXboxConsole::DumpModuleSize( const char *pName )
  523. {
  524. HRESULT error;
  525. PDM_WALK_MODULES pWalkMod = NULL;
  526. DMN_MODLOAD modLoad;
  527. int size = 0;
  528. // iterate and find match
  529. do
  530. {
  531. error = DmWalkLoadedModules( &pWalkMod, &modLoad );
  532. if ( XBDM_NOERR == error && !stricmp( modLoad.Name, pName ) )
  533. {
  534. Msg( "0x%8.8x, %5.2f MB, %s\n", modLoad.BaseAddress, modLoad.Size/( 1024.0f*1024.0f ), modLoad.Name );
  535. size = modLoad.Size;
  536. error = XBDM_ENDOFLIST;
  537. }
  538. }
  539. while ( XBDM_NOERR == error );
  540. DmCloseLoadedModules( pWalkMod );
  541. if ( error != XBDM_ENDOFLIST )
  542. {
  543. Warning( "DmWalkLoadedModules() failed.\n" );
  544. }
  545. return size;
  546. }
  547. //-----------------------------------------------------------------------------
  548. // 360 spew sizes of dll modules
  549. //-----------------------------------------------------------------------------
  550. char const* HACK_stristr( char const* pStr, char const* pSearch ) // hack because moved code from above vstdlib
  551. {
  552. AssertValidStringPtr(pStr);
  553. AssertValidStringPtr(pSearch);
  554. if (!pStr || !pSearch)
  555. return 0;
  556. char const* pLetter = pStr;
  557. // Check the entire string
  558. while (*pLetter != 0)
  559. {
  560. // Skip over non-matches
  561. if (tolower((unsigned char)*pLetter) == tolower((unsigned char)*pSearch))
  562. {
  563. // Check for match
  564. char const* pMatch = pLetter + 1;
  565. char const* pTest = pSearch + 1;
  566. while (*pTest != 0)
  567. {
  568. // We've run off the end; don't bother.
  569. if (*pMatch == 0)
  570. return 0;
  571. if (tolower((unsigned char)*pMatch) != tolower((unsigned char)*pTest))
  572. break;
  573. ++pMatch;
  574. ++pTest;
  575. }
  576. // Found a match!
  577. if (*pTest == 0)
  578. return pLetter;
  579. }
  580. ++pLetter;
  581. }
  582. return 0;
  583. }
  584. void CXboxConsole::DumpDllInfo( const char *pBasePath )
  585. {
  586. // Directories containing dlls
  587. static char *dllDirs[] =
  588. {
  589. "bin",
  590. "hl2\\bin",
  591. "tf\\bin",
  592. "portal\\bin",
  593. "episodic\\bin"
  594. };
  595. char binPath[MAX_PATH];
  596. char dllPath[MAX_PATH];
  597. char searchPath[MAX_PATH];
  598. HMODULE hModule;
  599. WIN32_FIND_DATA wfd;
  600. HANDLE hFind;
  601. Msg( "Dumping Module Sizes...\n" );
  602. for ( int i = 0; i < ARRAYSIZE( dllDirs ); ++i )
  603. {
  604. int totalSize = 0;
  605. _snprintf( binPath, sizeof( binPath ), "%s\\%s", pBasePath, dllDirs[i] );
  606. _snprintf( searchPath, sizeof( binPath ), "%s\\*.dll", binPath );
  607. // show the directory we're searching
  608. Msg( "\nDirectory: %s\n\n", binPath );
  609. // Start the find and check for failure.
  610. hFind = FindFirstFile( searchPath, &wfd );
  611. if ( INVALID_HANDLE_VALUE == hFind )
  612. {
  613. Warning( "No Files Found.\n" );
  614. }
  615. else
  616. {
  617. // Load and unload each dll individually.
  618. do
  619. {
  620. if ( !HACK_stristr( wfd.cFileName, "_360.dll" ) )
  621. {
  622. // exclude explicit pc dlls
  623. // FindFirstFile does not support a spec mask of *_360.dll on the Xbox HDD
  624. continue;
  625. }
  626. _snprintf( dllPath, sizeof( dllPath ), "%s\\%s", binPath, wfd.cFileName );
  627. hModule = LoadLibrary( dllPath );
  628. if ( hModule )
  629. {
  630. totalSize += DumpModuleSize( wfd.cFileName );
  631. FreeLibrary( hModule );
  632. }
  633. else
  634. {
  635. Warning( "Failed to load: %s\n", dllPath );
  636. }
  637. }
  638. while( FindNextFile( hFind, &wfd ) );
  639. FindClose( hFind );
  640. Msg( "Total Size: %.2f MB\n", totalSize/( 1024.0f*1024.0f ) );
  641. }
  642. }
  643. }
  644. void CXboxConsole::OutputDebugString( const char *p )
  645. {
  646. ::OutputDebugStringA( p );
  647. }
  648. bool CXboxConsole::IsDebuggerPresent()
  649. {
  650. return ( DmIsDebuggerPresent() != 0 );
  651. }