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.

1307 lines
33 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // LOCAL_CMDS.CPP
  4. //
  5. // Local commands ( *xxxx ) executed by this application.
  6. //=====================================================================================//
  7. #include "vxconsole.h"
  8. localCommand_t g_localCommands[] =
  9. {
  10. // Command name, Flags Handler Help string
  11. // console commands
  12. { "*cls", FN_CONSOLE, lc_cls, ": Clear the screen" },
  13. { "*connect", FN_CONSOLE, lc_autoConnect, ": Connect and listen until successful" },
  14. { "*disconnect", FN_CONSOLE, lc_disconnect, ": Terminate Debug Console session" },
  15. { "*help", FN_CONSOLE, lc_help, "[command] : List commands/usage" },
  16. { "*quit", FN_CONSOLE, lc_quit, ": Terminate console" },
  17. { "*run", FN_XBOX, lc_run, "[app.xex] : Run application or Reboot" },
  18. { "*reset", FN_XBOX, lc_reset, "Reboot" },
  19. { "*screenshot", FN_XBOX, lc_screenshot, "<file.bmp> : Copy the screen to file.bmp" },
  20. { "*memory", FN_APP, lc_memory, ": Dump Memory Stats" },
  21. { "*dir", FN_XBOX, lc_dir, "<filepath> [/s]: Directory listing" },
  22. { "*del", FN_XBOX, lc_del, "<filepath> [/s] [/q]: Delete file" },
  23. { "*modules", FN_XBOX, lc_modules, ": Lists currently loaded modules" },
  24. { "*sections", FN_XBOX, lc_sections, "<module> : Lists the sections in the module" },
  25. { "*bug", FN_CONSOLE, lc_bug, ": Open bug submission form" },
  26. { "*clearconfigs", FN_XBOX, lc_ClearConfigs, ": Erase all game configs" },
  27. // xcommands
  28. { "*break", FN_XBOX, NULL, " addr=<address> | 'Write'/'Read'/'Execute'=<address> size=<DataSize> ['clear']: Sets/Clears a breakpoint" },
  29. // { "*bye", FN_XBOX, NULL, ": Closes connection" },
  30. { "*continue", FN_XBOX, NULL, " thread=<threadid>: Resumes execution of a thread which has been stopped" },
  31. // { "*delete", FN_XBOX, NULL, " name=<remotefile>: Deletes a file on the Xbox" },
  32. // { "*dirlist", FN_XBOX, NULL, " name=<remotedir>: Lists the items in the directory" },
  33. { "*getcontext", FN_XBOX, NULL, " thread=<threadid> 'Control' | 'Int' | 'FP' | 'Full': Gets the context of the thread" },
  34. { "*getfileattributes", FN_XBOX, NULL, " name=<remotefile>: Gets attributes of a file" },
  35. { "*getmem", FN_XBOX, NULL, " addr=<address> length=<len>: Reads memory from the Xbox" },
  36. { "*go", FN_XBOX, NULL, ": Resumes suspended title threads" },
  37. { "*halt", FN_XBOX, NULL, " thread=<threadid> Breaks a thread" },
  38. { "*isstopped", FN_XBOX, NULL, " thread=<threadid>: Determines if a thread is stopped and why" },
  39. { "*mkdir", FN_XBOX, NULL, " name=<remotedir>: Creates a new directory on the Xbox" },
  40. { "*modlong", FN_XBOX, NULL, " name=<module>: Lists the long name of the module" },
  41. // { "*reboot", FN_XBOX, NULL, " [warm] [wait]: Reboots the xbox" },
  42. { "*rename", FN_XBOX, NULL, " name=<remotefile> newname=<newname>: Renames a file on the Xbox" },
  43. { "*resume", FN_XBOX, NULL, " thread=<threadid>: Resumes thread execution" },
  44. { "*setcontext", FN_XBOX, NULL, " thread=<threadid>: Sets the context of the thread." },
  45. { "*setfileattributes", FN_XBOX, NULL, " <remotefile> <attrs>: Sets attributes of a file" },
  46. { "*setmem", FN_XBOX, NULL, " addr=<address> data=<rawdata>: Sets memory on the Xbox" },
  47. { "*stop", FN_XBOX, NULL, ": Stops the process" },
  48. { "*suspend", FN_XBOX, NULL, " thread=<threadid>: Suspends the thread" },
  49. { "*systime", FN_XBOX, NULL, ": Gets the system time of the xbox" },
  50. { "*threadinfo", FN_XBOX, NULL, " thread=<threadid>: Gets thread info" },
  51. { "*threads", FN_XBOX, lc_threads, ": Gets the thread list" },
  52. // { "*title", FN_XBOX, NULL, " dir=<remotedir> name=<remotexex> [cmdline=<cmdline>]: Sets title to run" },
  53. { "*xexinfo", FN_XBOX, NULL, " name=<remotexex | 'running'>: Gets info on an xex" },
  54. { "*crash", FN_XBOX, lc_crashdump, " crash the console, emitting a dump" },
  55. };
  56. const int g_numLocalCommands = sizeof( g_localCommands )/sizeof( g_localCommands[0] );
  57. static BOOL g_bAutoConnectQuiet;
  58. static int g_bAutoConnectWait;
  59. //-----------------------------------------------------------------------------
  60. // MatchCommands
  61. //
  62. //-----------------------------------------------------------------------------
  63. int MatchLocalCommands( char* cmdStr, const char* cmdList[], int maxCmds )
  64. {
  65. int numCommands = 0;
  66. // look in local
  67. int matchLen = strlen( cmdStr );
  68. for ( int i=0; i<g_numLocalCommands; i++ )
  69. {
  70. if ( !strnicmp( cmdStr, g_localCommands[i].strCommand, matchLen ) )
  71. {
  72. cmdList[numCommands++] = g_localCommands[i].strCommand;
  73. if ( numCommands >= maxCmds )
  74. break;
  75. }
  76. }
  77. return ( numCommands );
  78. }
  79. //-----------------------------------------------------------------------------
  80. // DecodeRebootArgs
  81. //
  82. //-----------------------------------------------------------------------------
  83. void DecodeRebootArgs( int argc, char** argv, char* xexPath, char* xexName, char* xexArgs )
  84. {
  85. char drive[MAX_PATH];
  86. char dir[MAX_PATH];
  87. char filename[MAX_PATH];
  88. char extension[MAX_PATH];
  89. xexPath[0] = '\0';
  90. xexName[0] = '\0';
  91. xexArgs[0] = '\0';
  92. if ( !argc )
  93. return;
  94. _splitpath( argv[0], drive, dir, filename, extension );
  95. sprintf( xexPath, "%s%s", drive, dir );
  96. sprintf( xexName, "%s%s", filename, extension );
  97. for ( int i=1; i<argc; i++ )
  98. {
  99. strcat( xexArgs, argv[i] );
  100. if ( i < argc-1 )
  101. strcat( xexArgs, " " );
  102. }
  103. }
  104. //-----------------------------------------------------------------------------
  105. // Helper function. Causes a disconnect, has optional re-connect time.
  106. // A non-zero wait will delay before attempting re-connect.
  107. //-----------------------------------------------------------------------------
  108. void DoDisconnect( BOOL bKeepConnection, int waitTime )
  109. {
  110. // save state, user gates auto-connect ability
  111. int autoConnect = g_autoConnect;
  112. // full disconnect, disables autoconnect
  113. lc_disconnect( 0, NULL );
  114. if ( autoConnect && bKeepConnection && waitTime > 0 )
  115. {
  116. // restore autoconnect status
  117. lc_autoConnect( 0, NULL );
  118. // lets the system settle a little between contexts
  119. g_bAutoConnectWait = waitTime;
  120. g_bAutoConnectQuiet = FALSE;
  121. }
  122. }
  123. //-----------------------------------------------------------------------------
  124. // lc_bug
  125. //
  126. //-----------------------------------------------------------------------------
  127. BOOL lc_bug( int argc, char* argv[] )
  128. {
  129. if ( argc != 1 )
  130. {
  131. char* args[2] = {"*help", argv[0]};
  132. lc_help( 1, args );
  133. goto cleanUp;
  134. }
  135. BugDlg_Open();
  136. return TRUE;
  137. cleanUp:
  138. return FALSE;
  139. }
  140. //-----------------------------------------------------------------------------
  141. // lc_dir
  142. //
  143. //-----------------------------------------------------------------------------
  144. BOOL lc_dir( int argc, char* argv[] )
  145. {
  146. fileNode_t *nodePtr;
  147. fileNode_t *pFileList;
  148. int numFiles;
  149. int numDirs;
  150. __int64 totalBytes;
  151. bool recurse;
  152. char dateTimeString[256];
  153. char sizeString[64];
  154. char filePath[MAX_PATH];
  155. char fileName[MAX_PATH];
  156. char targetName[MAX_PATH];
  157. char newPath[MAX_PATH];
  158. SYSTEMTIME systemTime;
  159. SYSTEMTIME localTime;
  160. const char *dirString;
  161. BOOL errCode;
  162. int nPass;
  163. TIME_ZONE_INFORMATION tzInfo;
  164. pFileList = NULL;
  165. errCode = FALSE;
  166. if ( argc < 2 )
  167. {
  168. char* args[2] = {"*dir", argv[0]};
  169. lc_help( 2, args );
  170. goto cleanUp;
  171. }
  172. strcpy( newPath, argv[1] );
  173. // seperate components
  174. Sys_StripFilename( newPath, filePath, sizeof( filePath ) );
  175. Sys_StripPath( newPath, fileName, sizeof( fileName ) );
  176. if ( fileName[0] )
  177. {
  178. if ( !strstr( fileName,"*" ) && !strstr( fileName,"?" ) )
  179. {
  180. // assume filename was a directory name
  181. strcat( newPath, "\\" );
  182. Sys_StripFilename( newPath, filePath, sizeof( filePath ) );
  183. Sys_StripPath( newPath, fileName, sizeof( fileName ) );
  184. }
  185. }
  186. recurse = false;
  187. if ( argc >= 3 )
  188. {
  189. if ( !stricmp( argv[2], "/s" ) )
  190. recurse = true;
  191. }
  192. if ( !GetTargetFileList_r( filePath, recurse, FA_NORMAL|FA_DIRECTORY|FA_READONLY, 0, &pFileList ) )
  193. {
  194. ConsoleWindowPrintf( RGB( 255,0,0 ), "Bad Target Path '%s'\n", filePath );
  195. goto cleanUp;
  196. }
  197. ConsoleWindowPrintf( XBX_CLR_DEFAULT, "\nDirectory of %s\n\n", argv[1] );
  198. GetTimeZoneInformation( &tzInfo );
  199. numFiles = 0;
  200. numDirs = 0;
  201. totalBytes = 0;
  202. for ( nPass=0; nPass<2; nPass++ )
  203. {
  204. for ( nodePtr=pFileList; nodePtr; nodePtr=nodePtr->nextPtr )
  205. {
  206. if ( !nPass && !( nodePtr->attributes & FA_DIRECTORY ) )
  207. {
  208. // first pass, dirs only
  209. continue;
  210. }
  211. else if ( nPass && ( nodePtr->attributes & FA_DIRECTORY ) )
  212. {
  213. // second pass, files only
  214. continue;
  215. }
  216. Sys_StripPath( nodePtr->filename, targetName, sizeof( targetName ) );
  217. if ( fileName[0] && !Sys_IsWildcardMatch( fileName, targetName, false ) )
  218. continue;
  219. FileTimeToSystemTime( &nodePtr->changeTime, &systemTime );
  220. SystemTimeToTzSpecificLocalTime( &tzInfo, &systemTime, &localTime );
  221. SystemTimeToString( &localTime, dateTimeString, sizeof( dateTimeString ) );
  222. __int64 fullSize = MAKEINT64( nodePtr->sizeHigh, nodePtr->sizeLow );
  223. if ( nodePtr->attributes & FA_DIRECTORY )
  224. {
  225. numDirs++;
  226. dirString = "<DIR>";
  227. sprintf( sizeString, "%s", " " );
  228. }
  229. else
  230. {
  231. numFiles++;
  232. dirString = " ";
  233. Sys_NumberToCommaString( fullSize, sizeString, sizeof( sizeString ) );
  234. totalBytes += fullSize;
  235. }
  236. ConsoleWindowPrintf( XBX_CLR_DEFAULT, "%s %s %12s %s\n", dateTimeString, dirString, sizeString, targetName );
  237. }
  238. }
  239. Sys_NumberToCommaString( totalBytes, sizeString, sizeof( sizeString ) );
  240. ConsoleWindowPrintf( XBX_CLR_DEFAULT, "%9s %d File(s) %s bytes\n", " ", numFiles, sizeString );
  241. ConsoleWindowPrintf( XBX_CLR_DEFAULT, "%9s %d Dir(s)\n", " ", numDirs );
  242. // success
  243. errCode = TRUE;
  244. cleanUp:
  245. if ( pFileList )
  246. FreeTargetFileList( pFileList );
  247. return errCode;
  248. }
  249. //-----------------------------------------------------------------------------
  250. // lc_del
  251. //
  252. //-----------------------------------------------------------------------------
  253. BOOL lc_del( int argc, char* argv[] )
  254. {
  255. HRESULT hr;
  256. fileNode_t *nodePtr;
  257. fileNode_t *pFileList;
  258. int numDeleted;
  259. int numErrors;
  260. bool recurse;
  261. char filePath[MAX_PATH];
  262. char fileName[MAX_PATH];
  263. char targetName[MAX_PATH];
  264. BOOL errCode;
  265. pFileList = NULL;
  266. errCode = FALSE;
  267. if ( argc < 2 )
  268. {
  269. char* args[2] = {"*del", argv[0]};
  270. lc_help( 2, args );
  271. goto cleanUp;
  272. }
  273. // seperate components
  274. Sys_StripFilename( argv[1], filePath, sizeof( filePath ) );
  275. Sys_StripPath( argv[1], fileName, sizeof( fileName ) );
  276. bool bQuiet = false;
  277. recurse = false;
  278. if ( argc >= 3 )
  279. {
  280. for ( int i = 2; i < argc; i++ )
  281. {
  282. if ( !V_stricmp( argv[i], "/s" ) )
  283. {
  284. recurse = true;
  285. }
  286. else if ( !V_stricmp( argv[i], "/q" ) )
  287. {
  288. // silence errors
  289. bQuiet = true;
  290. }
  291. }
  292. }
  293. if ( !GetTargetFileList_r( filePath, recurse, FA_NORMAL|FA_READONLY|FA_DIRECTORY, 0, &pFileList ) )
  294. {
  295. ConsoleWindowPrintf( XBX_CLR_RED, "Bad Target Path '%s'\n", filePath );
  296. goto cleanUp;
  297. }
  298. numErrors = 0;
  299. numDeleted = 0;
  300. for ( nodePtr=pFileList; nodePtr; nodePtr=nodePtr->nextPtr )
  301. {
  302. Sys_StripPath( nodePtr->filename, targetName, sizeof( targetName ) );
  303. if ( fileName[0] && !Sys_IsWildcardMatch( fileName, targetName, false ) )
  304. continue;
  305. hr = DmDeleteFile( nodePtr->filename, ( nodePtr->attributes & FA_DIRECTORY ) != 0 );
  306. if ( hr != XBDM_NOERR )
  307. {
  308. if ( !bQuiet )
  309. {
  310. ConsoleWindowPrintf( XBX_CLR_RED, "Error Deleting '%s'\n", nodePtr->filename );
  311. }
  312. numErrors++;
  313. }
  314. else
  315. {
  316. ConsoleWindowPrintf( XBX_CLR_DEFAULT, "Deleted '%s'\n", nodePtr->filename );
  317. numDeleted++;
  318. }
  319. }
  320. if ( !numDeleted && !numErrors )
  321. {
  322. ConsoleWindowPrintf( XBX_CLR_RED, "No Files found for '%s'\n", argv[1] );
  323. }
  324. else
  325. {
  326. ConsoleWindowPrintf( XBX_CLR_DEFAULT, "%d files deleted.\n", numDeleted );
  327. }
  328. // success
  329. errCode = TRUE;
  330. cleanUp:
  331. if ( pFileList )
  332. FreeTargetFileList( pFileList );
  333. return errCode;
  334. }
  335. //-----------------------------------------------------------------------------
  336. // lc_memory
  337. //
  338. //-----------------------------------------------------------------------------
  339. BOOL lc_memory( int argc, char* argv[] )
  340. {
  341. HRESULT hr;
  342. hr = DmAPI_SendCommand( VXCONSOLE_COMMAND_PREFIX "!" "__memory__", true );
  343. if ( FAILED( hr ) )
  344. return FALSE;
  345. // success
  346. return TRUE;
  347. }
  348. //-----------------------------------------------------------------------------
  349. // lc_screenshot
  350. //
  351. //-----------------------------------------------------------------------------
  352. BOOL lc_screenshot( int argc, char* argv[] )
  353. {
  354. char filename[MAX_PATH];
  355. char filepath[MAX_PATH];
  356. static int shot = 0;
  357. struct _stat dummyStat;
  358. if ( argc <= 1 )
  359. {
  360. strcpy( filepath, g_localPath );
  361. Sys_AddFileSeperator( filepath, sizeof( filepath ) );
  362. // spin up to available file
  363. while ( 1 )
  364. {
  365. sprintf( filename, "%sscreenshot_%4.4d.bmp", filepath, shot );
  366. if ( _stat( filename, &dummyStat ) == -1 )
  367. {
  368. // filename not in use
  369. break;
  370. }
  371. shot++;
  372. }
  373. }
  374. else if ( argc == 2 )
  375. {
  376. strcpy( filename, argv[1] );
  377. Sys_AddExtension( ".bmp", filename, sizeof( filename ) );
  378. }
  379. else if ( argc > 2 )
  380. {
  381. char* args[2] = {"*help", argv[0]};
  382. lc_help( 2, args );
  383. goto cleanUp;
  384. }
  385. HRESULT hr = DmScreenShot( filename );
  386. if ( FAILED( hr ) )
  387. {
  388. DmAPI_DisplayError( "lc_screenshot(): DmScreenShot() failure", hr );
  389. goto cleanUp;
  390. }
  391. ConsoleWindowPrintf( XBX_CLR_DEFAULT, "Screenshot saved to %s\n", filename );
  392. // advance the shot
  393. shot++;
  394. // success
  395. return TRUE;
  396. cleanUp:
  397. return FALSE;
  398. }
  399. //-----------------------------------------------------------------------------
  400. // lc_modules
  401. //
  402. //-----------------------------------------------------------------------------
  403. BOOL lc_modules( int argc, char* argv[] )
  404. {
  405. HRESULT hr;
  406. PDM_WALK_MODULES pWalkMod = NULL;
  407. CUtlVector< DMN_MODLOAD > list;
  408. // add a fake module at 0xFFFFFFFF to make sorting simple
  409. DMN_MODLOAD modLoad = { 0 };
  410. modLoad.BaseAddress = (VOID*)0xFFFFFFFF;
  411. list.AddToTail( modLoad );
  412. ConsoleWindowPrintf( XBX_CLR_DEFAULT, "Modules:\n" );
  413. while ( 1 )
  414. {
  415. hr = DmWalkLoadedModules( &pWalkMod, &modLoad );
  416. if ( hr == XBDM_ENDOFLIST )
  417. {
  418. hr = XBDM_NOERR;
  419. break;
  420. }
  421. else if ( FAILED( hr ) )
  422. {
  423. DmAPI_DisplayError( "lc_modules(): DmWalkLoadedModules() failure", hr );
  424. break;
  425. }
  426. // add in ascending address order
  427. for ( int i = 0; i < list.Count(); i++ )
  428. {
  429. if ( modLoad.BaseAddress <= list[i].BaseAddress )
  430. {
  431. list.InsertBefore( i, modLoad );
  432. break;
  433. }
  434. }
  435. }
  436. unsigned int total = 0;
  437. for ( int i = 0; i < list.Count()-1; i++ )
  438. {
  439. DMN_MODLOAD *pModule = &list[i];
  440. ConsoleWindowPrintf( XBX_CLR_DEFAULT, "Base: 0x%8.8x, Size: %5.2f MB, [%s]\n", pModule->BaseAddress, pModule->Size/( 1024.0f*1024.0f ), pModule->Name );
  441. total += pModule->Size;
  442. }
  443. ConsoleWindowPrintf( XBX_CLR_DEFAULT, "Total: %.2f MB\n\n", total/( 1024.0f*1024.0f ) );
  444. if ( pWalkMod )
  445. {
  446. DmCloseLoadedModules( pWalkMod );
  447. }
  448. if ( !FAILED( hr ) )
  449. {
  450. // success
  451. return TRUE;
  452. }
  453. return FALSE;
  454. }
  455. //-----------------------------------------------------------------------------
  456. // lc_sections
  457. //
  458. //-----------------------------------------------------------------------------
  459. BOOL lc_sections( int argc, char* argv[] )
  460. {
  461. char moduleName[MAX_PATH];
  462. HRESULT hr;
  463. PDM_WALK_MODSECT pWalkModSect = NULL;
  464. DMN_SECTIONLOAD sectLoad;
  465. if ( argc != 2 )
  466. {
  467. char* args[2] = {"*help", argv[0]};
  468. lc_help( 2, args );
  469. goto cleanUp;
  470. }
  471. strcpy( moduleName, argv[1] );
  472. ConsoleWindowPrintf( XBX_CLR_DEFAULT, "Sections:\n" );
  473. while ( 1 )
  474. {
  475. hr = DmWalkModuleSections( &pWalkModSect, moduleName, &sectLoad );
  476. if ( hr == XBDM_ENDOFLIST )
  477. {
  478. hr = XBDM_NOERR;
  479. break;
  480. }
  481. else if ( FAILED( hr ) )
  482. {
  483. DmAPI_DisplayError( "lc_sections(): DmWalkModuleSections() failure", hr );
  484. break;
  485. }
  486. ConsoleWindowPrintf( XBX_CLR_DEFAULT, "[%s]:\n", sectLoad.Name );
  487. ConsoleWindowPrintf( XBX_CLR_DEFAULT, " Base: 0x%8.8x\n", sectLoad.BaseAddress );
  488. ConsoleWindowPrintf( XBX_CLR_DEFAULT, " Size: %.2f MB ( %d bytes )\n", sectLoad.Size/( 1024.0f*1024.0f ), sectLoad.Size );
  489. ConsoleWindowPrintf( XBX_CLR_DEFAULT, " Index: %d\n", sectLoad.Index );
  490. }
  491. ConsoleWindowPrintf( XBX_CLR_DEFAULT, "End.\n\n" );
  492. if ( pWalkModSect )
  493. DmCloseModuleSections( pWalkModSect );
  494. if ( !FAILED( hr ) )
  495. {
  496. // success
  497. return TRUE;
  498. }
  499. cleanUp:
  500. return FALSE;
  501. }
  502. //-----------------------------------------------------------------------------
  503. // lc_threads
  504. //
  505. //-----------------------------------------------------------------------------
  506. BOOL lc_threads( int argc, char* argv[] )
  507. {
  508. char nameBuff[256];
  509. char suspendBuff[32];
  510. DWORD threadList[256];
  511. DWORD numThreads = 256;
  512. memset( &threadList, 0, sizeof( threadList ) );
  513. HRESULT hr = DmGetThreadList( threadList, &numThreads );
  514. if ( FAILED( hr ) )
  515. return FALSE;
  516. // enumerate threads and display sorted by processor
  517. DM_THREADINFOEX threadInfoEx;
  518. for ( int core = 0; core < 3; core++ )
  519. {
  520. ConsoleWindowPrintf( XBX_CLR_DEFAULT, "\n--- CORE %d ---\n", core );
  521. for ( int unit = 0; unit < 2; unit++ )
  522. {
  523. for ( int i = 0; i < (int)numThreads; i++ )
  524. {
  525. threadInfoEx.Size = sizeof( DM_THREADINFOEX );
  526. hr = DmGetThreadInfoEx( threadList[i], &threadInfoEx );
  527. if ( FAILED( hr ) )
  528. return FALSE;
  529. if ( threadInfoEx.CurrentProcessor != core*2 + unit )
  530. {
  531. continue;
  532. }
  533. nameBuff[0] = '\0';
  534. DmGetMemory( threadInfoEx.ThreadNameAddress, threadInfoEx.ThreadNameLength, nameBuff, NULL );
  535. if ( !nameBuff[0] )
  536. {
  537. strcpy( nameBuff, "???" );
  538. }
  539. suspendBuff[0] = '\0';
  540. if ( threadInfoEx.SuspendCount )
  541. {
  542. sprintf( suspendBuff, "(Suspend: %d)", threadInfoEx.SuspendCount );
  543. }
  544. ConsoleWindowPrintf( XBX_CLR_DEFAULT, " Id: 0x%8.8x Pri: %2d Proc: %1d Stack: %7.2f KB [%s] %s\n",
  545. threadList[i],
  546. threadInfoEx.Priority,
  547. threadInfoEx.CurrentProcessor,
  548. (float)( (unsigned int)threadInfoEx.StackBase - (unsigned int)threadInfoEx.StackLimit )/1024.0f,
  549. nameBuff,
  550. suspendBuff );
  551. }
  552. }
  553. }
  554. return TRUE;
  555. }
  556. //-----------------------------------------------------------------------------
  557. // lc_run
  558. //
  559. //-----------------------------------------------------------------------------
  560. BOOL lc_run( int argc, char* argv[] )
  561. {
  562. HRESULT hr;
  563. char xexDrive[MAX_PATH];
  564. char xexPath[MAX_PATH];
  565. char xexName[MAX_PATH];
  566. char xexArgs[MAX_PATH];
  567. if ( !argc )
  568. {
  569. char* args[2] = {"*help", argv[0]};
  570. lc_help( 2, args );
  571. goto cleanUp;
  572. }
  573. // copy args
  574. g_rebootArgc = argc-1;
  575. for ( int i=1; i<argc; i++ )
  576. {
  577. if ( i==1 )
  578. {
  579. strcpy( xexPath, argv[i] );
  580. Sys_AddExtension( ".xex", xexPath, sizeof( xexPath ) );
  581. _splitpath( xexPath, xexDrive, NULL, NULL, NULL );
  582. if ( !xexDrive[0] )
  583. {
  584. char szTempPath[MAX_PATH];
  585. V_strncpy( szTempPath, "e:\\", sizeof( szTempPath ) );
  586. V_strncat( szTempPath, xexPath, sizeof( szTempPath ) );
  587. V_strncpy( xexPath, szTempPath, sizeof( xexPath ) );
  588. }
  589. g_rebootArgv[i-1] = Sys_CopyString( xexPath );
  590. }
  591. else
  592. {
  593. g_rebootArgv[i-1] = Sys_CopyString( argv[i] );
  594. }
  595. }
  596. if ( !g_rebootArgc )
  597. {
  598. // reboot
  599. hr = DmReboot( DMBOOT_COLD );
  600. }
  601. else
  602. {
  603. DecodeRebootArgs( g_rebootArgc, g_rebootArgv, xexPath, xexName, xexArgs );
  604. // trial set title - ensure title is present
  605. hr = DmSetTitle( xexPath, xexName, xexArgs );
  606. if ( FAILED( hr ) )
  607. {
  608. DmAPI_DisplayError( "lc_Run(): DmSetTitle() failure", hr );
  609. goto cleanUp;
  610. }
  611. // reboot - wait for 15s to connect and run title
  612. hr = DmReboot( DMBOOT_WAIT );
  613. }
  614. if ( FAILED( hr ) )
  615. {
  616. DmAPI_DisplayError( "lc_Run(): DmReboot() failure", hr );
  617. goto cleanUp;
  618. }
  619. // set reboot state
  620. g_reboot = true;
  621. return TRUE;
  622. cleanUp:
  623. // free args
  624. for ( int i=0; i<g_rebootArgc; i++ )
  625. Sys_Free( g_rebootArgv[i] );
  626. g_rebootArgc = 0;
  627. return FALSE;
  628. }
  629. //-----------------------------------------------------------------------------
  630. // lc_reset
  631. //
  632. //-----------------------------------------------------------------------------
  633. BOOL lc_reset( int argc, char* argv[] )
  634. {
  635. if ( !argc )
  636. {
  637. char* args[2] = {"*help", argv[0]};
  638. lc_help( 2, args );
  639. return FALSE;
  640. }
  641. HRESULT hr = DmReboot( DMBOOT_COLD );
  642. if ( FAILED( hr ) )
  643. {
  644. DmAPI_DisplayError( "lc_Run(): DmReboot() failure", hr );
  645. return FALSE;
  646. }
  647. // set reboot state
  648. g_reboot = true;
  649. return TRUE;
  650. }
  651. //-----------------------------------------------------------------------------
  652. // lc_help
  653. //
  654. // Handles the "help" command. If no args, prints a list of built-in
  655. // and remote commands ( remote only if connected ). If a command
  656. // is specified, prints detailed help for that command
  657. //-----------------------------------------------------------------------------
  658. BOOL lc_help( int argc, char* argv[] )
  659. {
  660. if ( argc <= 1 )
  661. {
  662. // no arguments - print out our list of commands
  663. ConsoleWindowPrintf( XBX_CLR_DEFAULT, "\n" );
  664. ConsoleWindowPrintf( XBX_CLR_DEFAULT, "Console Commands:\n" );
  665. ConsoleWindowPrintf( XBX_CLR_DEFAULT, "---------------\n" );
  666. for ( int i = 0; i < g_numLocalCommands; i++ )
  667. {
  668. ConsoleWindowPrintf( XBX_CLR_DEFAULT, "%s\n", g_localCommands[i].strCommand );
  669. }
  670. if ( g_connectedToApp )
  671. {
  672. ConsoleWindowPrintf( XBX_CLR_DEFAULT, "Remote Commands: ( %d )\n", g_numRemoteCommands );
  673. ConsoleWindowPrintf( XBX_CLR_DEFAULT, "----------------\n" );
  674. if ( !g_numRemoteCommands )
  675. {
  676. ConsoleWindowPrintf( XBX_CLR_DEFAULT, "( None )\n" );
  677. }
  678. else
  679. {
  680. for ( int i=0; i<g_numRemoteCommands; i++ )
  681. ConsoleWindowPrintf( XBX_CLR_DEFAULT, "%s\n", g_remoteCommands[i]->strCommand );
  682. }
  683. ConsoleWindowPrintf( XBX_CLR_DEFAULT, "\n" );
  684. }
  685. }
  686. else
  687. {
  688. // match as many as possible
  689. int cch = lstrlenA( argv[1] );
  690. // print help description for all local matches
  691. for ( int i=0; i<g_numLocalCommands; i++ )
  692. {
  693. if ( !_strnicmp( g_localCommands[i].strCommand, argv[1], cch ) && g_localCommands[i].strHelp )
  694. {
  695. ConsoleWindowPrintf( XBX_CLR_DEFAULT, "%s %s\n", g_localCommands[i].strCommand, g_localCommands[i].strHelp );
  696. }
  697. }
  698. // print help description for all remote matches
  699. if ( g_connectedToApp )
  700. {
  701. for ( int i=0; i<g_numRemoteCommands; i++ )
  702. {
  703. if ( !_strnicmp( g_remoteCommands[i]->strCommand, argv[1], cch ) && g_remoteCommands[i]->strHelp )
  704. {
  705. ConsoleWindowPrintf( XBX_CLR_DEFAULT, "%s %s\n", g_remoteCommands[i]->strCommand, g_remoteCommands[i]->strHelp );
  706. }
  707. }
  708. }
  709. ConsoleWindowPrintf( XBX_CLR_DEFAULT, "\n" );
  710. }
  711. return TRUE;
  712. }
  713. //-----------------------------------------------------------------------------
  714. // lc_cls
  715. //-----------------------------------------------------------------------------
  716. BOOL lc_cls( int argc, char* argv[] )
  717. {
  718. SetWindowText( g_hwndOutputWindow, "" );
  719. // non't let the compiler complain about unused parameters
  720. ( VOID )argc;
  721. ( VOID )argv;
  722. return TRUE;
  723. }
  724. //-----------------------------------------------------------------------------
  725. // lc_connect
  726. //
  727. // Connect to XBox
  728. //-----------------------------------------------------------------------------
  729. BOOL lc_connect( int argc, char* argv[] )
  730. {
  731. HRESULT hr;
  732. BOOL connected = FALSE;
  733. if ( g_connectedToXBox )
  734. {
  735. if ( !lc_disconnect( 0, NULL ) )
  736. return FALSE;
  737. }
  738. if ( argc >= 1 && argv[0][0] )
  739. {
  740. hr = DmSetXboxName( argv[0] );
  741. if ( FAILED( hr ) )
  742. {
  743. char message[255];
  744. sprintf( message, "ConnectToXBox(): DmSetXboxName( %s ) failure", argv[0] );
  745. DmAPI_DisplayError( message, hr );
  746. goto cleanUp;
  747. }
  748. }
  749. // open connection
  750. hr = DmOpenConnection( &g_pdmConnection );
  751. if ( FAILED( hr ) )
  752. {
  753. DmAPI_DisplayError( "ConnectToXBox(): DmOpenConnection() failure", hr );
  754. goto cleanUp;
  755. }
  756. connected = TRUE;
  757. DWORD namelen = MAX_XBOXNAMELEN;
  758. hr = DmGetXboxName( g_xboxName, &namelen );
  759. if ( FAILED( hr ) )
  760. {
  761. DmAPI_DisplayError( "ConnectToXBox(): DmGetXboxName() failure", hr );
  762. goto cleanUp;
  763. }
  764. hr = DmResolveXboxName( &g_xboxAddress );
  765. if ( FAILED( hr ) )
  766. {
  767. DmAPI_DisplayError( "ConnectToXBox(): DmResolveXboxName() failure", hr );
  768. goto cleanUp;
  769. }
  770. // success
  771. g_connectedToXBox = TRUE;
  772. g_connectFailure = 0;
  773. if ( !g_connectCount )
  774. ConsoleWindowPrintf( XBX_CLR_DEFAULT, "Connected To: '%s'(%d.%d.%d.%d)\n", g_xboxName, ( ( byte* )&g_xboxAddress )[3], ( ( byte* )&g_xboxAddress )[2], ( ( byte* )&g_xboxAddress )[1], ( ( byte* )&g_xboxAddress )[0] );
  775. g_connectCount++;
  776. SetConnectionIcon( ICON_CONNECTED_XBOX );
  777. if ( g_connectCount == 1 )
  778. {
  779. // inital connect
  780. }
  781. return TRUE;
  782. cleanUp:
  783. if ( connected )
  784. DmCloseConnection( g_pdmConnection );
  785. return FALSE;
  786. }
  787. //-----------------------------------------------------------------------------
  788. // lc_listen
  789. //
  790. // Open listen session with App
  791. //-----------------------------------------------------------------------------
  792. BOOL lc_listen( int argc, char* argv[] )
  793. {
  794. HRESULT hr;
  795. BOOL success;
  796. BOOL sessionStarted;
  797. BOOL sessionValid;
  798. char *args[1];
  799. char cmdStr[256];
  800. if ( g_connectedToXBox || g_connectedToApp )
  801. {
  802. if ( !lc_disconnect( 0, NULL ) )
  803. return ( FALSE );
  804. }
  805. if ( !g_connectedToXBox )
  806. {
  807. // connect to xbox
  808. args[0] = g_xboxTargetName;
  809. if ( !lc_connect( 1, args ) )
  810. return FALSE;
  811. }
  812. // until otherwise
  813. success = FALSE;
  814. sessionStarted = FALSE;
  815. sessionValid = FALSE;
  816. // init session
  817. hr = DmOpenNotificationSession( 0, &g_pdmnSession );
  818. if ( FAILED( hr ) )
  819. {
  820. DmAPI_DisplayError( "lc_session(): DmOpenNotificationSession() failure", hr );
  821. goto cleanUp;
  822. }
  823. sessionStarted = TRUE;
  824. // get notifications of app debugging output
  825. hr = DmNotify( g_pdmnSession, DM_DEBUGSTR, Remote_NotifyDebugString );
  826. if ( FAILED( hr ) )
  827. {
  828. DmAPI_DisplayError( "lc_session(): DmNotify() failure", hr );
  829. goto cleanUp;
  830. }
  831. // get command notifications
  832. hr = DmRegisterNotificationProcessor( g_pdmnSession, VXCONSOLE_COMMAND_PREFIX, Remote_NotifyCommandFunc );
  833. if ( FAILED( hr ) )
  834. {
  835. DmAPI_DisplayError( "lc_session(): DmRegisterNotificationProcessor() failure", hr );
  836. goto cleanUp;
  837. }
  838. // get print notifications
  839. hr = DmRegisterNotificationProcessor( g_pdmnSession, VXCONSOLE_PRINT_PREFIX, Remote_NotifyPrintFunc );
  840. if ( FAILED( hr ) )
  841. {
  842. DmAPI_DisplayError( "lc_session(): DmRegisterNotificationProcessor() failure", hr );
  843. goto cleanUp;
  844. }
  845. sessionValid = TRUE;
  846. // Send initial connect command to the External Command Processor so it knows we're here
  847. sprintf( cmdStr, "%s %d", VXCONSOLE_COMMAND_PREFIX "!" "__connect__", VXCONSOLE_PROTOCOL_VERSION );
  848. hr = DmAPI_SendCommand( cmdStr, true );
  849. if ( FAILED( hr ) )
  850. {
  851. if ( !g_autoConnect )
  852. ConsoleWindowPrintf( RGB( 255,0,0 ), "Couldn't Find Application\n" );
  853. goto cleanUp;
  854. }
  855. else
  856. {
  857. // connected
  858. success = TRUE;
  859. g_connectedToApp = TRUE;
  860. g_connectedTime = Sys_GetSystemTime();
  861. SetConnectionIcon( ICON_CONNECTED_APP1 );
  862. if ( g_clsOnConnect )
  863. {
  864. if ( g_bPlayTestMode )
  865. {
  866. // demarcate the log
  867. ConsoleWindowPrintf( CLR_DEFAULT, "\n******** CONNECTION ********\n" );
  868. }
  869. lc_cls( 0, NULL );
  870. CpuProfile_Clear();
  871. TimeStampLog_Clear();
  872. }
  873. goto cleanUp;
  874. }
  875. cleanUp:
  876. if ( !success )
  877. {
  878. if ( sessionValid )
  879. DmNotify( g_pdmnSession, DM_NONE, NULL );
  880. if ( sessionStarted )
  881. DmCloseNotificationSession( g_pdmnSession );
  882. }
  883. return ( success );
  884. }
  885. //-----------------------------------------------------------------------------
  886. // AutoConnectTimerProc
  887. //
  888. //-----------------------------------------------------------------------------
  889. void AutoConnectTimerProc( HWND hwnd, UINT_PTR idEvent )
  890. {
  891. static BOOL busy;
  892. int icon;
  893. char* cmdStr;
  894. BOOL bKeepConnection = TRUE;
  895. // blink the connection icon
  896. if ( g_connectedToApp && (! g_bSuppressBlink ) )
  897. {
  898. if ( g_currentIcon == ICON_CONNECTED_APP0 )
  899. icon = ICON_CONNECTED_APP1;
  900. else
  901. icon = ICON_CONNECTED_APP0;
  902. SetConnectionIcon( icon );
  903. }
  904. if ( busy )
  905. {
  906. // not ready for new tick
  907. return;
  908. }
  909. if ( g_bAutoConnectWait > 0 )
  910. {
  911. if ( g_bAutoConnectWait && !g_bAutoConnectQuiet )
  912. ConsoleWindowPrintf( XBX_CLR_DEFAULT, "Waiting... %d seconds remaining\n", g_bAutoConnectWait );
  913. g_bAutoConnectWait--;
  914. return;
  915. }
  916. // no more ticks until ready
  917. busy = TRUE;
  918. if ( !g_connectedToApp )
  919. {
  920. // looking for application - must force re-connect every time
  921. if ( g_connectedToXBox )
  922. {
  923. // temporary "partial" disconnect
  924. DmCloseConnection( g_pdmConnection );
  925. g_connectedToXBox = FALSE;
  926. }
  927. // attempt to start or re-establish connection and session
  928. lc_listen( 0, NULL );
  929. if ( !g_connectedToXBox )
  930. {
  931. SetConnectionIcon( ICON_DISCONNECTED );
  932. g_connectFailure++;
  933. }
  934. if ( g_reboot && g_connectedToXBox )
  935. {
  936. char xexPath[MAX_PATH];
  937. char xexName[MAX_PATH];
  938. char xexArgs[MAX_PATH];
  939. DecodeRebootArgs( g_rebootArgc, g_rebootArgv, xexPath, xexName, xexArgs );
  940. if ( g_rebootArgc )
  941. {
  942. // free args
  943. for ( int i=0; i<g_rebootArgc; i++ )
  944. Sys_Free( g_rebootArgv[i] );
  945. g_rebootArgc = 0;
  946. HRESULT hr = DmSetTitle( xexPath, xexName, xexArgs );
  947. if ( FAILED( hr ) )
  948. DmAPI_DisplayError( "Reboot: DmSetTitle() failure", hr );
  949. else
  950. {
  951. hr = DmGo();
  952. if ( FAILED( hr ) )
  953. DmAPI_DisplayError( "Reboot: DmGo() failure", hr );
  954. }
  955. }
  956. g_reboot = false;
  957. }
  958. if ( !g_connectFailure )
  959. {
  960. // quietly attempt re-connection or ping every 3 seconds
  961. g_bAutoConnectWait = 3;
  962. g_bAutoConnectQuiet = TRUE;
  963. busy = FALSE;
  964. }
  965. else
  966. {
  967. if ( g_connectFailure == 1 )
  968. {
  969. // console may be rebooting, allow sufficient dvd boot up delay, then attempt re-connection
  970. // 5 seconds barely covers the xbox splash
  971. g_bAutoConnectWait = 15;
  972. g_bAutoConnectQuiet = FALSE;
  973. busy = FALSE;
  974. }
  975. else
  976. {
  977. // a sustained connection failure means the xbox is just not there
  978. // re-trying is too cpu intensive and causes pc to appear locked
  979. // warn and stop auto connecting, user must fix
  980. bKeepConnection = FALSE;
  981. goto disconnect;
  982. }
  983. }
  984. return;
  985. }
  986. else
  987. {
  988. // try to send ping across open connection at an idle interval
  989. cmdStr = VXCONSOLE_COMMAND_PREFIX "!";
  990. HRESULT hr = DmAPI_SendCommand( cmdStr, false );
  991. if ( FAILED( hr ) && hr != XBDM_UNDEFINED )
  992. goto disconnect;
  993. // quietly ping
  994. g_bAutoConnectWait = 3;
  995. g_bAutoConnectQuiet = TRUE;
  996. busy = FALSE;
  997. return;
  998. }
  999. disconnect:
  1000. ConsoleWindowPrintf( XBX_CLR_DEFAULT, "Connection To Xbox Lost.\n" );
  1001. DoDisconnect( bKeepConnection, 3 );
  1002. busy = FALSE;
  1003. }
  1004. //-----------------------------------------------------------------------------
  1005. // lc_autoConnect
  1006. //-----------------------------------------------------------------------------
  1007. BOOL lc_autoConnect( int argc, char* argv[] )
  1008. {
  1009. if ( !g_autoConnect )
  1010. {
  1011. ConsoleWindowPrintf( XBX_CLR_DEFAULT, "Enabling Auto Connect.\n" );
  1012. ConsoleWindowPrintf( XBX_CLR_DEFAULT, "Looking for Connection...\n" );
  1013. g_autoConnect = TRUE;
  1014. }
  1015. else
  1016. {
  1017. // already enabled
  1018. return ( TRUE );
  1019. }
  1020. if ( !g_autoConnectTimer )
  1021. {
  1022. UINT_PTR timer = TIMERID_AUTOCONNECT;
  1023. g_autoConnectTimer = SetTimer( g_hDlgMain, timer, 1000, NULL );
  1024. }
  1025. return ( TRUE );
  1026. }
  1027. //-----------------------------------------------------------------------------
  1028. // lc_disconnect
  1029. //-----------------------------------------------------------------------------
  1030. BOOL lc_disconnect( int argc, char* argv[] )
  1031. {
  1032. if ( g_autoConnect )
  1033. {
  1034. ConsoleWindowPrintf( XBX_CLR_DEFAULT, "Disabling Auto Connect.\n" );
  1035. if ( g_autoConnectTimer )
  1036. {
  1037. UINT_PTR timer = TIMERID_AUTOCONNECT;
  1038. KillTimer( g_hDlgMain, timer );
  1039. }
  1040. g_autoConnectTimer = 0;
  1041. g_autoConnect = FALSE;
  1042. }
  1043. if ( g_connectedToApp )
  1044. {
  1045. ConsoleWindowPrintf( XBX_CLR_DEFAULT, "Closing Session.\n" );
  1046. DmAPI_SendCommand( VXCONSOLE_COMMAND_PREFIX "!" "__disconnect__", false );
  1047. // close session
  1048. DmNotify( g_pdmnSession, DM_NONE, NULL );
  1049. DmCloseNotificationSession( g_pdmnSession );
  1050. g_connectedToApp = FALSE;
  1051. }
  1052. if ( g_connectedToXBox )
  1053. {
  1054. ConsoleWindowPrintf( XBX_CLR_DEFAULT, "Closing Connection.\n" );
  1055. // close connection
  1056. DmCloseConnection( g_pdmConnection );
  1057. // set the command ready mutex
  1058. SetEvent( g_hCommandReadyEvent );
  1059. g_connectedToXBox = FALSE;
  1060. g_xboxName[0] = '\0';
  1061. g_xboxAddress = 0;
  1062. }
  1063. SetConnectionIcon( ICON_DISCONNECTED );
  1064. g_connectCount = 0;
  1065. // free remote commands
  1066. Remote_DeleteCommands();
  1067. // Don't let the compiler complain about unused parameters
  1068. ( VOID )argc;
  1069. ( VOID )argv;
  1070. return TRUE;
  1071. }
  1072. //-----------------------------------------------------------------------------
  1073. // lc_crashdump
  1074. //-----------------------------------------------------------------------------
  1075. BOOL lc_crashdump( int argc, char* argv[] )
  1076. {
  1077. DmCrashDump();
  1078. // Don't let the compiler complain about unused parameters
  1079. ( VOID )argc;
  1080. ( VOID )argv;
  1081. return TRUE;
  1082. }
  1083. //-----------------------------------------------------------------------------
  1084. // lc_quit
  1085. //-----------------------------------------------------------------------------
  1086. BOOL lc_quit( int argc, char* argv[] )
  1087. {
  1088. PostMessage( g_hDlgMain, WM_CLOSE, 0, 0 );
  1089. // don't let the compiler complain about unused parameters
  1090. ( VOID )argc;
  1091. ( VOID )argv;
  1092. return TRUE;
  1093. }
  1094. //-----------------------------------------------------------------------------
  1095. // lc_ClearConfigs
  1096. //
  1097. //-----------------------------------------------------------------------------
  1098. BOOL lc_ClearConfigs( int argc, char* argv[] )
  1099. {
  1100. if ( argc != 1 )
  1101. {
  1102. char* args[2] = {"*help", argv[0]};
  1103. lc_help( 1, args );
  1104. goto cleanUp;
  1105. }
  1106. // delete any configurations (ignore errors)
  1107. char szTempFilename[MAX_PATH];
  1108. V_ComposeFileName( "HDD:\\Content", "*.*", szTempFilename, sizeof( szTempFilename ) );
  1109. char *pArgs[4];
  1110. pArgs[0] = "*del";
  1111. pArgs[1] = szTempFilename;
  1112. pArgs[2] = "/s";
  1113. pArgs[3] = "/q";
  1114. lc_del( 4, pArgs );
  1115. return TRUE;
  1116. cleanUp:
  1117. return FALSE;
  1118. }