DebuggerClient.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587
  1. /*
  2. ===========================================================================
  3. Doom 3 GPL Source Code
  4. Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
  6. Doom 3 Source Code is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation, either version 3 of the License, or
  9. (at your option) any later version.
  10. Doom 3 Source Code is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
  17. If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
  18. ===========================================================================
  19. */
  20. #include "../../idlib/precompiled.h"
  21. #pragma hdrstop
  22. #include "DebuggerApp.h"
  23. /*
  24. ================
  25. rvDebuggerClient::rvDebuggerClient
  26. ================
  27. */
  28. rvDebuggerClient::rvDebuggerClient ( )
  29. {
  30. mConnected = false;
  31. mWaitFor = DBMSG_UNKNOWN;
  32. }
  33. /*
  34. ================
  35. rvDebuggerClient::~rvDebuggerClient
  36. ================
  37. */
  38. rvDebuggerClient::~rvDebuggerClient ( )
  39. {
  40. ClearBreakpoints ( );
  41. ClearCallstack ( );
  42. ClearThreads ( );
  43. }
  44. /*
  45. ================
  46. rvDebuggerClient::Initialize
  47. Initialize the debugger client
  48. ================
  49. */
  50. bool rvDebuggerClient::Initialize ( void )
  51. {
  52. // Nothing else can run with the debugger
  53. com_editors = EDITOR_DEBUGGER;
  54. // Initialize the network connection
  55. if ( !mPort.InitForPort ( 27981 ) )
  56. {
  57. return false;
  58. }
  59. // Server must be running on the local host on port 28980
  60. Sys_StringToNetAdr ( "localhost", &mServerAdrt, true );
  61. mServerAdr.port = 27980;
  62. // Attempt to let the server know we are here. The server may not be running so this
  63. // message will just get ignored.
  64. SendMessage ( DBMSG_CONNECT );
  65. return true;
  66. }
  67. /*
  68. ================
  69. rvDebuggerClient::Shutdown
  70. Shutdown the debugger client and let the debugger server
  71. know we are shutting down
  72. ================
  73. */
  74. void rvDebuggerClient::Shutdown ( void )
  75. {
  76. if ( mConnected )
  77. {
  78. SendMessage ( DBMSG_DISCONNECT );
  79. mConnected = false;
  80. }
  81. }
  82. /*
  83. ================
  84. rvDebuggerClient::ProcessMessages
  85. Process all incomding messages from the debugger server
  86. ================
  87. */
  88. bool rvDebuggerClient::ProcessMessages ( void )
  89. {
  90. netadr_t adrFrom;
  91. msg_t msg;
  92. byte buffer[MAX_MSGLEN];
  93. MSG_Init( &msg, buffer, sizeof( buffer ) );
  94. // Check for pending udp packets on the debugger port
  95. while ( mPort.GetPacket ( adrFrom, msg.data, msg.cursize, msg.maxsize ) )
  96. {
  97. unsigned short command;
  98. // Only accept packets from the debugger server for security reasons
  99. if ( !Sys_CompareNetAdrBase ( adrFrom, mServerAdr ) )
  100. {
  101. continue;
  102. }
  103. command = (unsigned short) MSG_ReadShort ( &msg );
  104. // Is this what we are waiting for?
  105. if ( command == mWaitFor )
  106. {
  107. mWaitFor = DBMSG_UNKNOWN;
  108. }
  109. switch ( command )
  110. {
  111. case DBMSG_CONNECT:
  112. mConnected = true;
  113. SendMessage ( DBMSG_CONNECTED );
  114. SendBreakpoints ( );
  115. break;
  116. case DBMSG_CONNECTED:
  117. mConnected = true;
  118. SendBreakpoints ( );
  119. break;
  120. case DBMSG_DISCONNECT:
  121. mConnected = false;
  122. break;
  123. case DBMSG_BREAK:
  124. HandleBreak ( &msg );
  125. break;
  126. // Callstack being send to the client
  127. case DBMSG_INSPECTCALLSTACK:
  128. HandleInspectCallstack ( &msg );
  129. break;
  130. // Thread list is being sent to the client
  131. case DBMSG_INSPECTTHREADS:
  132. HandleInspectThreads ( &msg );
  133. break;
  134. case DBMSG_INSPECTVARIABLE:
  135. HandleInspectVariable ( &msg );
  136. break;
  137. }
  138. // Give the window a chance to process the message
  139. msg.readcount = 0;
  140. msg.bit = 0;
  141. gDebuggerApp.GetWindow().ProcessNetMessage ( &msg );
  142. }
  143. return true;
  144. }
  145. /*
  146. ================
  147. rvDebuggerClient::HandleBreak
  148. Handle the DBMSG_BREAK message send from the server. This message is handled
  149. by caching the file and linenumber where the break occured.
  150. ================
  151. */
  152. void rvDebuggerClient::HandleBreak ( msg_t* msg )
  153. {
  154. char filename[MAX_PATH];
  155. mBreak = true;
  156. // Line number
  157. mBreakLineNumber = MSG_ReadLong ( msg );
  158. // Filename
  159. MSG_ReadString ( msg, filename, MAX_PATH );
  160. mBreakFilename = filename;
  161. // Clear the variables
  162. mVariables.Clear ( );
  163. // Request the callstack and threads
  164. SendMessage ( DBMSG_INSPECTCALLSTACK );
  165. WaitFor ( DBMSG_INSPECTCALLSTACK, 2000 );
  166. SendMessage ( DBMSG_INSPECTTHREADS );
  167. WaitFor ( DBMSG_INSPECTTHREADS, 2000 );
  168. }
  169. /*
  170. ================
  171. rvDebuggerClient::InspectVariable
  172. Instructs the client to inspect the given variable at the given callstack depth. The
  173. variable is inspected by sending a DBMSG_INSPECTVARIABLE message to the server which
  174. will in turn respond back to the client with the variable value
  175. ================
  176. */
  177. void rvDebuggerClient::InspectVariable ( const char* name, int callstackDepth )
  178. {
  179. msg_t msg;
  180. byte buffer[MAX_MSGLEN];
  181. MSG_Init( &msg, buffer, sizeof( buffer ) );
  182. MSG_WriteShort ( &msg, (int)DBMSG_INSPECTVARIABLE );
  183. MSG_WriteShort ( &msg, (short)(mCallstack.Num()-callstackDepth) );
  184. MSG_WriteString ( &msg, name );
  185. SendPacket ( msg.data, msg.cursize );
  186. }
  187. /*
  188. ================
  189. rvDebuggerClient::HandleInspectCallstack
  190. Handle the message DBMSG_INSPECTCALLSTACK being sent from the server. This message
  191. is handled by adding the callstack entries to a list for later lookup.
  192. ================
  193. */
  194. void rvDebuggerClient::HandleInspectCallstack ( msg_t* msg )
  195. {
  196. int depth;
  197. ClearCallstack ( );
  198. // Read all of the callstack entries specfied in the message
  199. for ( depth = (short)MSG_ReadShort ( msg ) ; depth > 0; depth -- )
  200. {
  201. rvDebuggerCallstack* entry = new rvDebuggerCallstack;
  202. char temp[1024];
  203. // Function name
  204. MSG_ReadString ( msg, temp, 1024 );
  205. entry->mFunction = temp;
  206. // Filename
  207. MSG_ReadString ( msg, temp, 1024 );
  208. entry->mFilename = temp;
  209. // Line Number
  210. entry->mLineNumber = MSG_ReadLong ( msg );
  211. // Add to list
  212. mCallstack.Append ( entry );
  213. }
  214. }
  215. /*
  216. ================
  217. rvDebuggerClient::HandleInspectThreads
  218. Handle the message DBMSG_INSPECTTHREADS being sent from the server. This message
  219. is handled by adding the list of threads to a list for later lookup.
  220. ================
  221. */
  222. void rvDebuggerClient::HandleInspectThreads ( msg_t* msg )
  223. {
  224. int count;
  225. ClearThreads ( );
  226. // Loop over the number of threads in the message
  227. for ( count = (short)MSG_ReadShort ( msg ) ; count > 0; count -- )
  228. {
  229. rvDebuggerThread* entry = new rvDebuggerThread;
  230. char temp[1024];
  231. // Thread name
  232. MSG_ReadString ( msg, temp, 1024 );
  233. entry->mName = temp;
  234. // Thread ID
  235. entry->mID = MSG_ReadLong ( msg );
  236. // Thread state
  237. entry->mCurrent = MSG_ReadBits ( msg, 1 ) ? true : false;
  238. entry->mDoneProcessing = MSG_ReadBits ( msg, 1 ) ? true : false;
  239. entry->mWaiting = MSG_ReadBits ( msg, 1 ) ? true : false;
  240. entry->mDying = MSG_ReadBits ( msg, 1 ) ? true : false;
  241. // Add thread to list
  242. mThreads.Append ( entry );
  243. }
  244. }
  245. /*
  246. ================
  247. rvDebuggerClient::HandleInspectVariable
  248. Handle the message DBMSG_INSPECTVARIABLE being sent from the server. This message
  249. is handled by adding the inspected variable to a dictionary for later lookup
  250. ================
  251. */
  252. void rvDebuggerClient::HandleInspectVariable ( msg_t* msg )
  253. {
  254. char var[1024];
  255. char value[1024];
  256. int callDepth;
  257. callDepth = (short)MSG_ReadShort ( msg );
  258. MSG_ReadString ( msg, var, 1024 );
  259. MSG_ReadString ( msg, value, 1024 );
  260. mVariables.Set ( va("%d:%s", mCallstack.Num()-callDepth, var), value );
  261. }
  262. /*
  263. ================
  264. rvDebuggerClient::WaitFor
  265. Waits the given amount of time for the specified message to be received by the
  266. debugger client.
  267. ================
  268. */
  269. bool rvDebuggerClient::WaitFor ( EDebuggerMessage msg, int time )
  270. {
  271. int start;
  272. // Cant wait if not connected
  273. if ( !mConnected )
  274. {
  275. return false;
  276. }
  277. start = Sys_Milliseconds ( );
  278. mWaitFor = msg;
  279. while ( mWaitFor != DBMSG_UNKNOWN && Sys_Milliseconds()-start < time )
  280. {
  281. ProcessMessages ( );
  282. Sleep ( 0 );
  283. }
  284. if ( mWaitFor != DBMSG_UNKNOWN )
  285. {
  286. mWaitFor = DBMSG_UNKNOWN;
  287. return false;
  288. }
  289. return true;
  290. }
  291. /*
  292. ================
  293. rvDebuggerClient::FindBreakpoint
  294. Searches for a breakpoint that maches the given filename and linenumber
  295. ================
  296. */
  297. rvDebuggerBreakpoint* rvDebuggerClient::FindBreakpoint ( const char* filename, int linenumber )
  298. {
  299. int i;
  300. for ( i = 0; i < mBreakpoints.Num(); i ++ )
  301. {
  302. rvDebuggerBreakpoint* bp = mBreakpoints[i];
  303. if ( linenumber == bp->GetLineNumber ( ) && !idStr::Icmp ( bp->GetFilename ( ), filename ) )
  304. {
  305. return bp;
  306. }
  307. }
  308. return NULL;
  309. }
  310. /*
  311. ================
  312. rvDebuggerClient::ClearBreakpoints
  313. Removes all breakpoints from the client and server
  314. ================
  315. */
  316. void rvDebuggerClient::ClearBreakpoints ( void )
  317. {
  318. int i;
  319. for ( i = 0; i < GetBreakpointCount(); i ++ )
  320. {
  321. rvDebuggerBreakpoint* bp = mBreakpoints[i];
  322. assert ( bp );
  323. SendRemoveBreakpoint ( *bp );
  324. delete bp;
  325. }
  326. mBreakpoints.Clear ( );
  327. }
  328. /*
  329. ================
  330. rvDebuggerClient::AddBreakpoint
  331. Adds a breakpoint to the client and server with the give nfilename and linenumber
  332. ================
  333. */
  334. int rvDebuggerClient::AddBreakpoint ( const char* filename, int lineNumber, bool onceOnly )
  335. {
  336. int index = mBreakpoints.Append ( new rvDebuggerBreakpoint ( filename, lineNumber ) );
  337. SendAddBreakpoint ( *mBreakpoints[index] );
  338. return index;
  339. }
  340. /*
  341. ================
  342. rvDebuggerClient::RemoveBreakpoint
  343. Removes the breakpoint with the given ID from the client and server
  344. ================
  345. */
  346. bool rvDebuggerClient::RemoveBreakpoint ( int bpID )
  347. {
  348. int index;
  349. for ( index = 0; index < GetBreakpointCount(); index ++ )
  350. {
  351. if ( mBreakpoints[index]->GetID ( ) == bpID )
  352. {
  353. SendRemoveBreakpoint ( *mBreakpoints[index] );
  354. delete mBreakpoints[index];
  355. mBreakpoints.RemoveIndex ( index );
  356. return true;
  357. }
  358. }
  359. return false;
  360. }
  361. /*
  362. ================
  363. rvDebuggerClient::SendMessage
  364. Send a message with no data to the debugger server
  365. ================
  366. */
  367. void rvDebuggerClient::SendMessage ( EDebuggerMessage dbmsg )
  368. {
  369. msg_t msg;
  370. byte buffer[MAX_MSGLEN];
  371. MSG_Init( &msg, buffer, sizeof( buffer ) );
  372. MSG_WriteShort ( &msg, (int)dbmsg );
  373. SendPacket ( msg.data, msg.cursize );
  374. }
  375. /*
  376. ================
  377. rvDebuggerClient::SendBreakpoints
  378. Send all breakpoints to the debugger server
  379. ================
  380. */
  381. void rvDebuggerClient::SendBreakpoints ( void )
  382. {
  383. int i;
  384. if ( !mConnected )
  385. {
  386. return;
  387. }
  388. // Send all the breakpoints to the server
  389. for ( i = 0; i < mBreakpoints.Num(); i ++ )
  390. {
  391. SendAddBreakpoint ( *mBreakpoints[i] );
  392. }
  393. }
  394. /*
  395. ================
  396. rvDebuggerClient::SendAddBreakpoint
  397. Send an individual breakpoint over to the debugger server
  398. ================
  399. */
  400. void rvDebuggerClient::SendAddBreakpoint ( rvDebuggerBreakpoint& bp, bool onceOnly )
  401. {
  402. msg_t msg;
  403. byte buffer[MAX_MSGLEN];
  404. if ( !mConnected )
  405. {
  406. return;
  407. }
  408. MSG_Init( &msg, buffer, sizeof( buffer ) );
  409. MSG_WriteShort ( &msg, (int)DBMSG_ADDBREAKPOINT );
  410. MSG_WriteBits ( &msg, onceOnly?1:0, 1 );
  411. MSG_WriteLong ( &msg, (unsigned long) bp.GetLineNumber ( ) );
  412. MSG_WriteLong ( &msg, bp.GetID ( ) );
  413. MSG_WriteString ( &msg, bp.GetFilename() );
  414. SendPacket ( msg.data, msg.cursize );
  415. }
  416. /*
  417. ================
  418. rvDebuggerClient::SendRemoveBreakpoint
  419. Sends a remove breakpoint message to the debugger server
  420. ================
  421. */
  422. void rvDebuggerClient::SendRemoveBreakpoint ( rvDebuggerBreakpoint& bp )
  423. {
  424. msg_t msg;
  425. byte buffer[MAX_MSGLEN];
  426. if ( !mConnected )
  427. {
  428. return;
  429. }
  430. MSG_Init( &msg, buffer, sizeof( buffer ) );
  431. MSG_WriteShort ( &msg, (int)DBMSG_REMOVEBREAKPOINT );
  432. MSG_WriteLong ( &msg, bp.GetID() );
  433. SendPacket ( msg.data, msg.cursize );
  434. }
  435. /*
  436. ================
  437. rvDebuggerClient::ClearCallstack
  438. Clear all callstack entries
  439. ================
  440. */
  441. void rvDebuggerClient::ClearCallstack ( void )
  442. {
  443. int depth;
  444. for ( depth = 0; depth < mCallstack.Num(); depth ++ )
  445. {
  446. delete mCallstack[depth];
  447. }
  448. mCallstack.Clear ( );
  449. }
  450. /*
  451. ================
  452. rvDebuggerClient::ClearThreads
  453. Clear all thread entries
  454. ================
  455. */
  456. void rvDebuggerClient::ClearThreads ( void )
  457. {
  458. int i;
  459. for ( i = 0; i < mThreads.Num(); i ++ )
  460. {
  461. delete mThreads[i];
  462. }
  463. mThreads.Clear ( );
  464. }