doom3-gpl
Doom 3 GPL source release
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
DebuggerClient.cpp
Go to the documentation of this file.
1 /*
2 ===========================================================================
3 
4 Doom 3 GPL Source Code
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
6 
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
8 
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13 
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
21 
22 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.
23 
24 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.
25 
26 ===========================================================================
27 */
28 
29 #include "../../idlib/precompiled.h"
30 #pragma hdrstop
31 
32 #include "DebuggerApp.h"
33 
34 /*
35 ================
36 rvDebuggerClient::rvDebuggerClient
37 ================
38 */
40 {
41  mConnected = false;
43 }
44 
45 /*
46 ================
47 rvDebuggerClient::~rvDebuggerClient
48 ================
49 */
51 {
52  ClearBreakpoints ( );
53  ClearCallstack ( );
54  ClearThreads ( );
55 }
56 
57 /*
58 ================
59 rvDebuggerClient::Initialize
60 
61 Initialize the debugger client
62 ================
63 */
65 {
66  // Nothing else can run with the debugger
68 
69  // Initialize the network connection
70  if ( !mPort.InitForPort ( 27981 ) )
71  {
72  return false;
73  }
74 
75  // Server must be running on the local host on port 28980
76  Sys_StringToNetAdr ( "localhost", &mServerAdrt, true );
77  mServerAdr.port = 27980;
78 
79  // Attempt to let the server know we are here. The server may not be running so this
80  // message will just get ignored.
82 
83  return true;
84 }
85 
86 /*
87 ================
88 rvDebuggerClient::Shutdown
89 
90 Shutdown the debugger client and let the debugger server
91 know we are shutting down
92 ================
93 */
95 {
96  if ( mConnected )
97  {
99  mConnected = false;
100  }
101 }
102 
103 /*
104 ================
105 rvDebuggerClient::ProcessMessages
106 
107 Process all incomding messages from the debugger server
108 ================
109 */
111 {
112  netadr_t adrFrom;
113  msg_t msg;
115 
116  MSG_Init( &msg, buffer, sizeof( buffer ) );
117 
118  // Check for pending udp packets on the debugger port
119  while ( mPort.GetPacket ( adrFrom, msg.data, msg.cursize, msg.maxsize ) )
120  {
121  unsigned short command;
122 
123  // Only accept packets from the debugger server for security reasons
124  if ( !Sys_CompareNetAdrBase ( adrFrom, mServerAdr ) )
125  {
126  continue;
127  }
128 
129  command = (unsigned short) MSG_ReadShort ( &msg );
130 
131  // Is this what we are waiting for?
132  if ( command == mWaitFor )
133  {
135  }
136 
137  switch ( command )
138  {
139  case DBMSG_CONNECT:
140  mConnected = true;
142  SendBreakpoints ( );
143  break;
144 
145  case DBMSG_CONNECTED:
146  mConnected = true;
147  SendBreakpoints ( );
148  break;
149 
150  case DBMSG_DISCONNECT:
151  mConnected = false;
152  break;
153 
154  case DBMSG_BREAK:
155  HandleBreak ( &msg );
156  break;
157 
158  // Callstack being send to the client
160  HandleInspectCallstack ( &msg );
161  break;
162 
163  // Thread list is being sent to the client
165  HandleInspectThreads ( &msg );
166  break;
167 
169  HandleInspectVariable ( &msg );
170  break;
171  }
172 
173  // Give the window a chance to process the message
174  msg.readcount = 0;
175  msg.bit = 0;
177  }
178 
179  return true;
180 }
181 
182 /*
183 ================
184 rvDebuggerClient::HandleBreak
185 
186 Handle the DBMSG_BREAK message send from the server. This message is handled
187 by caching the file and linenumber where the break occured.
188 ================
189 */
190 void rvDebuggerClient::HandleBreak ( msg_t* msg )
191 {
192  char filename[MAX_PATH];
193 
194  mBreak = true;
195 
196  // Line number
197  mBreakLineNumber = MSG_ReadLong ( msg );
198 
199  // Filename
200  MSG_ReadString ( msg, filename, MAX_PATH );
201  mBreakFilename = filename;
202 
203  // Clear the variables
204  mVariables.Clear ( );
205 
206  // Request the callstack and threads
209 
211  WaitFor ( DBMSG_INSPECTTHREADS, 2000 );
212 }
213 
214 /*
215 ================
216 rvDebuggerClient::InspectVariable
217 
218 Instructs the client to inspect the given variable at the given callstack depth. The
219 variable is inspected by sending a DBMSG_INSPECTVARIABLE message to the server which
220 will in turn respond back to the client with the variable value
221 ================
222 */
223 void rvDebuggerClient::InspectVariable ( const char* name, int callstackDepth )
224 {
225  msg_t msg;
227 
228  MSG_Init( &msg, buffer, sizeof( buffer ) );
229  MSG_WriteShort ( &msg, (int)DBMSG_INSPECTVARIABLE );
230  MSG_WriteShort ( &msg, (short)(mCallstack.Num()-callstackDepth) );
231  MSG_WriteString ( &msg, name );
232 
233  SendPacket ( msg.data, msg.cursize );
234 }
235 
236 /*
237 ================
238 rvDebuggerClient::HandleInspectCallstack
239 
240 Handle the message DBMSG_INSPECTCALLSTACK being sent from the server. This message
241 is handled by adding the callstack entries to a list for later lookup.
242 ================
243 */
245 {
246  int depth;
247 
248  ClearCallstack ( );
249 
250  // Read all of the callstack entries specfied in the message
251  for ( depth = (short)MSG_ReadShort ( msg ) ; depth > 0; depth -- )
252  {
254 
255  char temp[1024];
256 
257  // Function name
258  MSG_ReadString ( msg, temp, 1024 );
259  entry->mFunction = temp;
260 
261  // Filename
262  MSG_ReadString ( msg, temp, 1024 );
263  entry->mFilename = temp;
264 
265  // Line Number
266  entry->mLineNumber = MSG_ReadLong ( msg );
267 
268  // Add to list
269  mCallstack.Append ( entry );
270  }
271 }
272 
273 /*
274 ================
275 rvDebuggerClient::HandleInspectThreads
276 
277 Handle the message DBMSG_INSPECTTHREADS being sent from the server. This message
278 is handled by adding the list of threads to a list for later lookup.
279 ================
280 */
282 {
283  int count;
284 
285  ClearThreads ( );
286 
287  // Loop over the number of threads in the message
288  for ( count = (short)MSG_ReadShort ( msg ) ; count > 0; count -- )
289  {
290  rvDebuggerThread* entry = new rvDebuggerThread;
291 
292  char temp[1024];
293 
294  // Thread name
295  MSG_ReadString ( msg, temp, 1024 );
296  entry->mName = temp;
297 
298  // Thread ID
299  entry->mID = MSG_ReadLong ( msg );
300 
301  // Thread state
302  entry->mCurrent = MSG_ReadBits ( msg, 1 ) ? true : false;
303  entry->mDoneProcessing = MSG_ReadBits ( msg, 1 ) ? true : false;
304  entry->mWaiting = MSG_ReadBits ( msg, 1 ) ? true : false;
305  entry->mDying = MSG_ReadBits ( msg, 1 ) ? true : false;
306 
307  // Add thread to list
308  mThreads.Append ( entry );
309  }
310 }
311 
312 /*
313 ================
314 rvDebuggerClient::HandleInspectVariable
315 
316 Handle the message DBMSG_INSPECTVARIABLE being sent from the server. This message
317 is handled by adding the inspected variable to a dictionary for later lookup
318 ================
319 */
321 {
322  char var[1024];
323  char value[1024];
324  int callDepth;
325 
326  callDepth = (short)MSG_ReadShort ( msg );
327  MSG_ReadString ( msg, var, 1024 );
328  MSG_ReadString ( msg, value, 1024 );
329 
330  mVariables.Set ( va("%d:%s", mCallstack.Num()-callDepth, var), value );
331 }
332 
333 /*
334 ================
335 rvDebuggerClient::WaitFor
336 
337 Waits the given amount of time for the specified message to be received by the
338 debugger client.
339 ================
340 */
342 {
343  int start;
344 
345  // Cant wait if not connected
346  if ( !mConnected )
347  {
348  return false;
349  }
350 
351  start = Sys_Milliseconds ( );
352  mWaitFor = msg;
353 
354  while ( mWaitFor != DBMSG_UNKNOWN && Sys_Milliseconds()-start < time )
355  {
356  ProcessMessages ( );
357  Sleep ( 0 );
358  }
359 
360  if ( mWaitFor != DBMSG_UNKNOWN )
361  {
363  return false;
364  }
365 
366  return true;
367 }
368 
369 /*
370 ================
371 rvDebuggerClient::FindBreakpoint
372 
373 Searches for a breakpoint that maches the given filename and linenumber
374 ================
375 */
376 rvDebuggerBreakpoint* rvDebuggerClient::FindBreakpoint ( const char* filename, int linenumber )
377 {
378  int i;
379 
380  for ( i = 0; i < mBreakpoints.Num(); i ++ )
381  {
383 
384  if ( linenumber == bp->GetLineNumber ( ) && !idStr::Icmp ( bp->GetFilename ( ), filename ) )
385  {
386  return bp;
387  }
388  }
389 
390  return NULL;
391 }
392 
393 /*
394 ================
395 rvDebuggerClient::ClearBreakpoints
396 
397 Removes all breakpoints from the client and server
398 ================
399 */
401 {
402  int i;
403 
404  for ( i = 0; i < GetBreakpointCount(); i ++ )
405  {
407  assert ( bp );
408 
409  SendRemoveBreakpoint ( *bp );
410  delete bp;
411  }
412 
413  mBreakpoints.Clear ( );
414 }
415 
416 /*
417 ================
418 rvDebuggerClient::AddBreakpoint
419 
420 Adds a breakpoint to the client and server with the give nfilename and linenumber
421 ================
422 */
423 int rvDebuggerClient::AddBreakpoint ( const char* filename, int lineNumber, bool onceOnly )
424 {
425  int index = mBreakpoints.Append ( new rvDebuggerBreakpoint ( filename, lineNumber ) );
426 
427  SendAddBreakpoint ( *mBreakpoints[index] );
428 
429  return index;
430 }
431 
432 /*
433 ================
434 rvDebuggerClient::RemoveBreakpoint
435 
436 Removes the breakpoint with the given ID from the client and server
437 ================
438 */
440 {
441  int index;
442 
443  for ( index = 0; index < GetBreakpointCount(); index ++ )
444  {
445  if ( mBreakpoints[index]->GetID ( ) == bpID )
446  {
448  delete mBreakpoints[index];
449  mBreakpoints.RemoveIndex ( index );
450  return true;
451  }
452  }
453 
454  return false;
455 }
456 
457 /*
458 ================
459 rvDebuggerClient::SendMessage
460 
461 Send a message with no data to the debugger server
462 ================
463 */
465 {
466  msg_t msg;
468 
469  MSG_Init( &msg, buffer, sizeof( buffer ) );
470  MSG_WriteShort ( &msg, (int)dbmsg );
471 
472  SendPacket ( msg.data, msg.cursize );
473 }
474 
475 /*
476 ================
477 rvDebuggerClient::SendBreakpoints
478 
479 Send all breakpoints to the debugger server
480 ================
481 */
483 {
484  int i;
485 
486  if ( !mConnected )
487  {
488  return;
489  }
490 
491  // Send all the breakpoints to the server
492  for ( i = 0; i < mBreakpoints.Num(); i ++ )
493  {
495  }
496 }
497 
498 /*
499 ================
500 rvDebuggerClient::SendAddBreakpoint
501 
502 Send an individual breakpoint over to the debugger server
503 ================
504 */
506 {
507  msg_t msg;
509 
510  if ( !mConnected )
511  {
512  return;
513  }
514 
515  MSG_Init( &msg, buffer, sizeof( buffer ) );
516  MSG_WriteShort ( &msg, (int)DBMSG_ADDBREAKPOINT );
517  MSG_WriteBits ( &msg, onceOnly?1:0, 1 );
518  MSG_WriteLong ( &msg, (unsigned long) bp.GetLineNumber ( ) );
519  MSG_WriteLong ( &msg, bp.GetID ( ) );
520  MSG_WriteString ( &msg, bp.GetFilename() );
521 
522  SendPacket ( msg.data, msg.cursize );
523 }
524 
525 /*
526 ================
527 rvDebuggerClient::SendRemoveBreakpoint
528 
529 Sends a remove breakpoint message to the debugger server
530 ================
531 */
533 {
534  msg_t msg;
536 
537  if ( !mConnected )
538  {
539  return;
540  }
541 
542  MSG_Init( &msg, buffer, sizeof( buffer ) );
543  MSG_WriteShort ( &msg, (int)DBMSG_REMOVEBREAKPOINT );
544  MSG_WriteLong ( &msg, bp.GetID() );
545 
546  SendPacket ( msg.data, msg.cursize );
547 }
548 
549 /*
550 ================
551 rvDebuggerClient::ClearCallstack
552 
553 Clear all callstack entries
554 ================
555 */
557 {
558  int depth;
559 
560  for ( depth = 0; depth < mCallstack.Num(); depth ++ )
561  {
562  delete mCallstack[depth];
563  }
564 
565  mCallstack.Clear ( );
566 }
567 
568 /*
569 ================
570 rvDebuggerClient::ClearThreads
571 
572 Clear all thread entries
573 ================
574 */
576 {
577  int i;
578 
579  for ( i = 0; i < mThreads.Num(); i ++ )
580  {
581  delete mThreads[i];
582  }
583 
584  mThreads.Clear ( );
585 }
586 
GLsizei const GLfloat * value
Definition: glext.h:3614
bool WaitFor(EDebuggerMessage msg, int time)
assert(prefInfo.fullscreenBtn)
EDebuggerMessage mWaitFor
rvDebuggerThreadList mThreads
rvDebuggerWindow & GetWindow(void)
Definition: DebuggerApp.h:100
void InspectVariable(const char *name, int callstackDepth)
bool Sys_CompareNetAdrBase(const netadr_t a, const netadr_t b)
Definition: posix_net.cpp:248
int Sys_Milliseconds(void)
unsigned short port
Definition: sys_public.h:407
bool Sys_StringToNetAdr(const char *s, netadr_t *a, bool doDNSResolve)
Definition: posix_net.cpp:171
GLint GLint GLsizei GLsizei GLsizei depth
Definition: glext.h:2878
rvDebuggerBreakpoint * FindBreakpoint(const char *filename, int linenumber)
void Set(const char *key, const char *value)
Definition: Dict.cpp:275
void SendBreakpoints(void)
void Sleep(const int time)
int i
Definition: process.py:33
void ClearThreads(void)
void HandleInspectVariable(msg_t *msg)
int Icmp(const char *text) const
Definition: Str.h:667
bool GetPacket(netadr_t &from, void *data, int &size, int maxSize)
Definition: posix_net.cpp:487
int com_editors
Definition: Common.cpp:97
void SendMessage(EDebuggerMessage dbmsg)
GLuint GLuint GLsizei count
Definition: glext.h:2845
GLuint index
Definition: glext.h:3476
void SendRemoveBreakpoint(rvDebuggerBreakpoint &bp)
rvDebuggerCallstackList mCallstack
#define NULL
Definition: Lib.h:88
void Clear(void)
Definition: Dict.cpp:201
void SendPacket(void *data, int datasize)
GLuint buffer
Definition: glext.h:3108
bool ProcessMessages(void)
void SendAddBreakpoint(rvDebuggerBreakpoint &bp, bool onceOnly=false)
bool InitForPort(int portNumber)
Definition: posix_net.cpp:598
const int MAX_MSGLEN
Definition: DebuggerApp.h:52
void ClearBreakpoints(void)
void HandleInspectCallstack(msg_t *msg)
const char * GetFilename(void)
bool Initialize(void)
void HandleBreak(msg_t *msg)
int Append(const type &obj)
Definition: List.h:646
int Num(void) const
Definition: List.h:265
bool RemoveIndex(int index)
Definition: List.h:849
unsigned char byte
Definition: Lib.h:75
const GLcharARB * name
Definition: glext.h:3629
bool RemoveBreakpoint(int bpID)
int GetBreakpointCount(void)
int AddBreakpoint(const char *filename, int lineNumber, bool onceOnly=false)
char * va(const char *fmt,...)
Definition: Str.cpp:1568
rvDebuggerApp gDebuggerApp
Definition: debugger.cpp:38
void ProcessNetMessage(msg_t *msg)
rvDebuggerBreakpointList mBreakpoints
GLuint start
Definition: glext.h:2845
void ClearCallstack(void)
void HandleInspectThreads(msg_t *msg)
EDebuggerMessage
void Clear(void)
Definition: List.h:184