]>
git.saurik.com Git - wxWidgets.git/blob - wxPython/samples/ide/activegrid/tool/DebuggerHarness.py
1 #----------------------------------------------------------------------------
2 # Name: DebuggerHarness.py
9 # Copyright: (c) 2005 ActiveGrid, Inc.
10 # License: wxWindows License
11 #----------------------------------------------------------------------------
14 import SimpleXMLRPCServer
22 from xml
.dom
.minidom
import getDOMImplementation
26 if sys
.platform
.startswith("win"):
33 _DEBUG_DEBUGGER
= False
37 def __init__(self
, harness
, queue
):
38 bdb
.Bdb
.__init
__(self
)
39 self
._harness
= harness
40 self
._userBreak
= False
42 self
._knownCantExpandFiles
= {}
43 self
._knownExpandedFiles
= {}
45 def getLongName(self
, filename
):
48 if self
._knownCantExpandFiles
.get(filename
):
50 if self
._knownExpandedFiles
.get(filename
):
51 return self
._knownExpandedFiles
.get(filename
)
53 newname
= win32api
.GetLongPathName(filename
)
54 self
._knownExpandedFiles
[filename
] = newname
57 self
._knownCantExpandFiles
[filename
] = filename
60 def canonic(self
, orig_filename
):
61 if orig_filename
== "<" + orig_filename
[1:-1] + ">":
63 filename
= self
.getLongName(orig_filename
)
65 canonic
= self
.fncache
.get(filename
)
67 canonic
= os
.path
.abspath(filename
)
68 canonic
= os
.path
.normcase(canonic
)
69 self
.fncache
[filename
] = canonic
73 # Overriding this so that we continue to trace even if no breakpoints are set.
74 def set_continue(self
):
75 self
.stopframe
= self
.botframe
76 self
.returnframe
= None
79 def do_clear(self
, arg
):
80 bdb
.Breakpoint
.bpbynumber
[int(arg
)].deleteMe()
82 def user_line(self
, frame
):
83 if self
.in_debugger_code(frame
):
86 message
= self
.__frame
2message
(frame
)
87 self
._harness
.interaction(message
, frame
, "")
89 def user_call(self
, frame
, argument_list
):
90 if self
.in_debugger_code(frame
):
93 if self
.stop_here(frame
):
94 message
= self
.__frame
2message
(frame
)
95 self
._harness
.interaction(message
, frame
, "")
97 def user_return(self
, frame
, return_value
):
98 if self
.in_debugger_code(frame
):
101 message
= self
.__frame
2message
(frame
)
102 self
._harness
.interaction(message
, frame
, "")
104 def user_exception(self
, frame
, (exc_type
, exc_value
, exc_traceback
)):
105 frame
.f_locals
['__exception__'] = exc_type
, exc_value
106 if type(exc_type
) == type(''):
107 exc_type_name
= exc_type
109 exc_type_name
= exc_type
.__name
__
110 message
= "Exception occured: " + repr(exc_type_name
) + " See locals.__exception__ for details."
111 traceback
.print_exception(exc_type
, exc_value
, exc_traceback
)
112 self
._harness
.interaction(message
, frame
, message
)
114 def in_debugger_code(self
, frame
):
115 if _DEBUG_DEBUGGER
: return False
116 message
= self
.__frame
2message
(frame
)
117 return message
.count('DebuggerHarness') > 0
119 def frame2message(self
, frame
):
120 return self
.__frame
2message
(frame
)
122 def __frame2message(self
, frame
):
124 filename
= code
.co_filename
125 lineno
= frame
.f_lineno
126 basename
= os
.path
.basename(filename
)
127 message
= "%s:%s" % (basename
, lineno
)
128 if code
.co_name
!= "?":
129 message
= "%s: %s()" % (message
, code
.co_name
)
132 def runFile(self
, fileName
):
135 #global_dict['__name__'] = '__main__'
137 fileToRun
= open(fileName
, mode
='r')
138 if _VERBOSE
: print "Running file ", fileName
139 sys
.settrace(self
.trace_dispatch
)
141 exec fileToRun
in __main__
.__dict
__,__main__
.__dict
__
145 tp
, val
, tb
= sys
.exc_info()
146 traceback
.print_exception(tp
, val
, tb
)
152 def trace_dispatch(self
, frame
, event
, arg
):
155 # Check for ui events
158 return self
.dispatch_line(frame
)
160 return self
.dispatch_call(frame
, arg
)
161 if event
== 'return':
162 return self
.dispatch_return(frame
, arg
)
163 if event
== 'exception':
164 return self
.dispatch_exception(frame
, arg
)
165 print 'Adb.dispatch: unknown debugging event:', `event`
166 return self
.trace_dispatch
169 while self
._queue
.qsize():
171 item
= self
._queue
.get_nowait()
173 self
._harness
.do_exit(kill
=True)
174 elif item
.breakHere():
175 self
._userBreak
= True
176 elif item
.hasBreakpoints():
177 self
.set_all_breakpoints(item
.getBreakpoints())
181 def set_all_breakpoints(self
, dict):
182 self
.clear_all_breaks()
183 for fileName
in dict.keys():
184 lineList
= dict[fileName
]
185 for lineNumber
in lineList
:
187 if _VERBOSE
: print "Setting break at line ", str(lineNumber
), " in file ", self
.canonic(fileName
)
188 self
.set_break(fileName
, int(lineNumber
))
191 def stop_here(self
, frame
):
192 if( self
._userBreak
):
196 # (CT) stopframe may now also be None, see dispatch_call.
197 # (CT) the former test for None is therefore removed from here.
198 if frame
is self
.stopframe
:
200 while frame
is not None and frame
is not self
.stopframe
:
201 if frame
is self
.botframe
:
206 class BreakNotify(object):
207 def __init__(self
, bps
=None, break_here
=False, kill
=False):
209 self
._break
_here
= break_here
213 return self
._break
_here
218 def getBreakpoints(self
):
221 def hasBreakpoints(self
):
222 return (self
._bps
!= None)
224 class AGXMLRPCServer(SimpleXMLRPCServer
.SimpleXMLRPCServer
):
225 def __init__(self
, address
, logRequests
=0):
226 SimpleXMLRPCServer
.SimpleXMLRPCServer
.__init
__(self
, address
, logRequests
=logRequests
)
228 class BreakListenerThread(threading
.Thread
):
229 def __init__(self
, host
, port
, queue
):
230 threading
.Thread
.__init
__(self
)
232 self
._port
= int(port
)
233 self
._keepGoing
= True
235 self
._server
= AGXMLRPCServer((self
._host
, self
._port
), logRequests
=0)
236 self
._server
.register_function(self
.update_breakpoints
)
237 self
._server
.register_function(self
.break_requested
)
238 self
._server
.register_function(self
.die
)
240 def break_requested(self
):
241 bn
= BreakNotify(break_here
=True)
245 def update_breakpoints(self
, pickled_Binary_bpts
):
246 dict = pickle
.loads(pickled_Binary_bpts
.data
)
247 bn
= BreakNotify(bps
=dict)
252 bn
= BreakNotify(kill
=True)
257 while self
._keepGoing
:
259 self
._server
.handle_request()
262 tp
, val
, tb
= sys
.exc_info()
263 print "Exception in BreakListenerThread.run():", str(tp
), str(val
)
264 self
._keepGoing
= False
267 self
._keepGoing
= False
268 if type(self
._server
) is not types
.NoneType
:
269 if _VERBOSE
: print "Before calling server close on breakpoint server"
270 self
._server
.server_close()
271 if _VERBOSE
: print "Calling server close on breakpoint server"
274 class DebuggerHarness(object):
277 # Host and port for debugger-side RPC server
278 self
._hostname
= sys
.argv
[1]
279 self
._portNumber
= int(sys
.argv
[2])
280 # Name the gui proxy object is registered under
281 self
._breakPortNumber
= int(sys
.argv
[3])
282 # Host and port where the gui proxy can be found.
283 self
._guiHost
= sys
.argv
[4]
284 self
._guiPort
= int(sys
.argv
[5])
286 self
._command
= sys
.argv
[6]
287 # Strip out the harness' arguments so that the process we run will see argv as if
288 # it was called directly.
289 sys
.argv
= sys
.argv
[6:]
290 self
._currentFrame
= None
292 # Connect to the gui-side RPC server.
293 self
._guiServerUrl
= 'http://' + self
._guiHost
+ ':' + str(self
._guiPort
) + '/'
294 if _VERBOSE
: print "Connecting to gui server at ", self
._guiServerUrl
295 self
._guiServer
= xmlrpclib
.ServerProxy(self
._guiServerUrl
,allow_none
=1)
297 # Start the break listener
298 self
._breakQueue
= Queue
.Queue(50)
299 self
._breakListener
= BreakListenerThread(self
._hostname
, self
._breakPortNumber
, self
._breakQueue
)
300 self
._breakListener
.start()
301 # Create the debugger.
302 self
._adb
= Adb(self
, self
._breakQueue
)
304 # Create the debugger-side RPC Server and register functions for remote calls.
305 self
._server
= AGXMLRPCServer((self
._hostname
, self
._portNumber
), logRequests
=0)
306 self
._server
.register_function(self
.set_step
)
307 self
._server
.register_function(self
.set_continue
)
308 self
._server
.register_function(self
.set_next
)
309 self
._server
.register_function(self
.set_return
)
310 self
._server
.register_function(self
.set_breakpoint
)
311 self
._server
.register_function(self
.clear_breakpoint
)
312 self
._server
.register_function(self
.set_all_breakpoints
)
313 self
._server
.register_function(self
.attempt_introspection
)
314 self
._server
.register_function(self
.add_watch
)
316 self
.message_frame_dict
= {}
317 self
.introspection_list
= []
318 atexit
.register(self
.do_exit
)
321 self
._adb
.runFile(self
._command
)
322 self
.do_exit(kill
=True)
325 def do_exit(self
, kill
=False):
327 self
._breakListener
.AskToStop()
328 self
._server
.server_close()
330 self
._guiServer
.quit()
339 def set_breakpoint(self
, fileName
, lineNo
):
340 self
._adb
.set_break(fileName
, lineNo
)
343 def set_all_breakpoints(self
, dict):
344 self
._adb
.clear_all_breaks()
345 for fileName
in dict.keys():
346 lineList
= dict[fileName
]
347 for lineNumber
in lineList
:
348 self
._adb
.set_break(fileName
, int(lineNumber
))
349 if _VERBOSE
: print "Setting break at ", str(lineNumber
), " in file ", fileName
352 def clear_breakpoint(self
, fileName
, lineNo
):
353 self
._adb
.clear_break(fileName
, lineNo
)
356 def add_watch(self
, name
, text
, frame_message
, run_once
):
357 if len(frame_message
) > 0:
358 frame
= self
.message_frame_dict
[frame_message
]
360 item
= eval(text
, frame
.f_globals
, frame
.f_locals
)
361 return self
.get_watch_document(item
, name
)
363 tp
, val
, tb
= sys
.exc_info()
364 return self
.get_exception_document(tp
, val
, tb
)
367 def attempt_introspection(self
, frame_message
, chain
):
369 frame
= self
.message_frame_dict
[frame_message
]
372 if name
== 'globals':
373 item
= frame
.f_globals
374 elif name
== 'locals':
375 item
= frame
.f_locals
378 item
= self
.getNextItem(item
, name
)
379 return self
.get_introspection_document(item
, name
)
381 tp
, val
, tb
= sys
.exc_info()
382 traceback
.print_exception(tp
, val
, tb
)
383 return self
.get_empty_introspection_document()
385 def getNextItem(self
, link
, identifier
):
387 if self
.isTupleized(identifier
):
388 return self
.deTupleize(link
, identifier
)
390 if tp
== types
.DictType
or tp
== types
.DictProxyType
:
391 return link
[identifier
]
393 if hasattr(link
, identifier
):
394 return getattr(link
, identifier
)
395 if _VERBOSE
or True: print "Failed to find link ", identifier
, " on thing: ", self
.saferepr(link
), " of type ", repr(type(link
))
398 def isPrimitive(self
, item
):
400 return tp
is types
.IntType
or tp
is types
.LongType
or tp
is types
.FloatType \
401 or tp
is types
.BooleanType
or tp
is types
.ComplexType \
402 or tp
is types
.StringType
404 def isTupleized(self
, value
):
405 return value
.count('[')
407 def deTupleize(self
, link
, string1
):
409 start
= string1
.find('[')
410 end
= string1
.find(']')
411 num
= int(string1
[start
+1:end
])
414 tp
,val
,tb
= sys
.exc_info()
415 if _VERBOSE
: print "Got exception in deTupleize: ", val
418 def wrapAndCompress(self
, stringDoc
):
420 return xmlrpclib
.Binary(bz2
.compress(stringDoc
))
422 def get_empty_introspection_document(self
):
423 doc
= getDOMImplementation().createDocument(None, "replacement", None)
424 return self
.wrapAndCompress(doc
.toxml())
426 def get_watch_document(self
, item
, identifier
):
427 doc
= getDOMImplementation().createDocument(None, "watch", None)
428 top_element
= doc
.documentElement
429 self
.addAny(top_element
, identifier
, item
, doc
, 2)
430 return self
.wrapAndCompress(doc
.toxml())
432 def get_introspection_document(self
, item
, identifier
):
433 doc
= getDOMImplementation().createDocument(None, "replacement", None)
434 top_element
= doc
.documentElement
435 self
.addAny(top_element
, identifier
, item
, doc
, 2)
436 return self
.wrapAndCompress(doc
.toxml())
438 def get_exception_document(self
, name
, tp
, val
, tb
):
439 stack
= traceback
.format_exception(tp
, val
, tb
)
443 doc
= getDOMImplementation().createDocument(None, "watch", None)
444 top_element
= doc
.documentElement
445 item_node
= doc
.createElement("dict_nv_element")
446 item_node
.setAttribute('value', wholeStack
)
447 item_node
.setAttribute('name', str(name
))
448 top_element
.appendChild(item_node
)
450 def addAny(self
, top_element
, name
, item
, doc
, ply
):
453 self
.addNode(top_element
,name
, self
.saferepr(item
), doc
)
454 elif tp
is types
.TupleType
or tp
is types
.ListType
:
455 self
.addTupleOrList(top_element
, name
, item
, doc
, ply
- 1)
456 elif tp
is types
.DictType
or tp
is types
.DictProxyType
:
457 self
.addDict(top_element
, name
, item
, doc
, ply
-1)
458 elif inspect
.ismodule(item
):
459 self
.addModule(top_element
, name
, item
, doc
, ply
-1)
460 elif inspect
.isclass(item
) or tp
is types
.InstanceType
:
461 self
.addClass(top_element
, name
, item
, doc
, ply
-1)
462 #elif hasattr(item, '__dict__'):
463 # self.addDictAttr(top_element, name, item, doc, ply -1)
464 elif hasattr(item
, '__dict__'):
465 self
.addDict(top_element
, name
, item
.__dict
__, doc
, ply
-1)
467 self
.addNode(top_element
,name
, self
.saferepr(item
), doc
)
469 def addTupleOrList(self
, top_node
, name
, tupple
, doc
, ply
):
470 tupleNode
= doc
.createElement('tuple')
471 tupleNode
.setAttribute('name', str(name
))
472 tupleNode
.setAttribute('value', str(type(tupple
)))
473 top_node
.appendChild(tupleNode
)
476 self
.addAny(tupleNode
, name
+'[' + str(count
) + ']',item
, doc
, ply
-1)
480 def getFrameXML(self
, base_frame
):
481 doc
= getDOMImplementation().createDocument(None, "stack", None)
482 top_element
= doc
.documentElement
486 while frame
is not None:
487 if((frame
.f_code
.co_filename
.count('DebuggerHarness.py') == 0) or _DEBUG_DEBUGGER
):
491 self
.message_frame_dict
= {}
493 self
.addFrame(f
,top_element
, doc
)
496 def addFrame(self
, frame
, root_element
, document
):
497 frameNode
= document
.createElement('frame')
498 root_element
.appendChild(frameNode
)
501 filename
= code
.co_filename
502 frameNode
.setAttribute('file', str(filename
))
503 frameNode
.setAttribute('line', str(frame
.f_lineno
))
504 message
= self
._adb
.frame2message(frame
)
505 frameNode
.setAttribute('message', message
)
506 #print "Frame: %s %s %s" %(message, frame.f_lineno, filename)
507 self
.message_frame_dict
[message
] = frame
508 self
.addDict(frameNode
, "locals", frame
.f_locals
, document
, 2)
509 self
.addNode(frameNode
, "globals", "", document
)
511 def getRepr(self
, varName
, globals, locals):
513 return repr(eval(varName
, globals, locals))
515 return 'Error: Could not recover value.'
517 def addNode(self
, parent_node
, name
, value
, document
):
518 item_node
= document
.createElement("dict_nv_element")
519 item_node
.setAttribute('value', self
.saferepr(value
))
520 item_node
.setAttribute('name', str(name
))
521 parent_node
.appendChild(item_node
)
523 def addDictAttr(self
, root_node
, name
, thing
, document
, ply
):
524 dict_node
= document
.createElement('thing')
525 root_node
.setAttribute('name', name
)
526 root_node
.setAttribute('value', str(type(dict)) + " add attr")
527 self
.addDict(root_node
, name
, thing
.__dict
__, document
, ply
) # Not decreminting ply
529 def saferepr(self
, thing
):
533 tp
, val
, tb
= sys
.exc_info()
536 def addDict(self
, root_node
, name
, dict, document
, ply
):
537 dict_node
= document
.createElement('dict')
538 dict_node
.setAttribute('name', name
)
539 dict_node
.setAttribute('value', str(type(dict)) + " add dict")
540 root_node
.appendChild(dict_node
)
541 for key
in dict.keys():
544 self
.addAny(dict_node
, strkey
, dict[key
], document
, ply
-1)
546 tp
,val
,tb
=sys
.exc_info()
548 print "Error recovering key: ", str(key
), " from node ", str(name
), " Val = ", str(val
)
549 traceback
.print_exception(tp
, val
, tb
)
550 self
.addAny(dict_node
, strkey
, "Exception getting " + str(name
) + "[" + strkey
+ "]: " + str(val
), document
, ply
-1)
552 def addClass(self
, root_node
, name
, class_item
, document
, ply
):
553 item_node
= document
.createElement('class')
554 item_node
.setAttribute('name', str(name
))
555 root_node
.appendChild(item_node
)
557 if hasattr(class_item
, '__dict__'):
558 self
.addAny(item_node
, '__dict__', class_item
.__dict
__, document
, ply
-1)
560 tp
,val
,tb
=sys
.exc_info()
562 traceback
.print_exception(tp
, val
, tb
)
563 self
.addAny(item_node
, '__dict__', "Exception getting __dict__: " + str(val
), document
, ply
-1)
565 if hasattr(class_item
, '__name__'):
566 self
.addAny(item_node
,'__name__',class_item
.__name
__, document
, ply
-1)
568 tp
,val
,tb
=sys
.exc_info()
570 traceback
.print_exception(tp
, val
, tb
)
571 self
.addAny(item_node
,'__name__',"Exception getting class.__name__: " + val
, document
, ply
-1)
573 if hasattr(class_item
, '__module__'):
574 self
.addAny(item_node
, '__module__', class_item
.__module
__, document
, ply
-1)
576 tp
,val
,tb
=sys
.exc_info()
578 traceback
.print_exception(tp
, val
, tb
)
579 self
.addAny(item_node
, '__module__', "Exception getting class.__module__: " + val
, document
, ply
-1)
581 if hasattr(class_item
, '__doc__'):
582 self
.addAny(item_node
, '__doc__', class_item
.__doc
__, document
, ply
-1)
584 tp
,val
,tb
=sys
.exc_info()
586 traceback
.print_exception(tp
, val
, tb
)
587 self
.addAny(item_node
, '__doc__', "Exception getting class.__doc__: " + val
, document
, ply
-1)
589 if hasattr(class_item
, '__bases__'):
590 self
.addAny(item_node
, '__bases__', class_item
.__bases
__, document
, ply
-1)
592 tp
,val
,tb
=sys
.exc_info()
594 traceback
.print_exception(tp
, val
, tb
)
595 self
.addAny(item_node
, '__bases__', "Exception getting class.__bases__: " + val
, document
, ply
-1)
597 def addModule(self
, root_node
, name
, module_item
, document
, ply
):
598 item_node
= document
.createElement('module')
599 item_node
.setAttribute('name', str(name
))
600 root_node
.appendChild(item_node
)
602 if hasattr(module_item
, '__file__'):
603 self
.addAny(item_node
, '__file__', module_item
.__file
__, document
, ply
-1)
607 if hasattr(module_item
, '__doc__'):
608 self
.addAny(item_node
,'__doc__', module_item
.__doc
__, document
, ply
-1)
612 # The debugger calls this method when it reaches a breakpoint.
613 def interaction(self
, message
, frame
, info
):
615 print 'hit debug side interaction'
616 self
._userBreak
= False
618 self
._currentFrame
= frame
623 xml
= self
.getFrameXML(frame
)
624 arg
= xmlrpclib
.Binary(bz2
.compress(xml
))
626 print '============== calling gui side interaction============'
627 self
._guiServer
.interaction(xmlrpclib
.Binary(message
), arg
, info
)
629 print 'after interaction'
632 tp
, val
, tb
= sys
.exc_info()
634 print 'Error contacting GUI server!: '
636 traceback
.print_exception(tp
, val
, tb
)
638 print "Exception printing traceback",
639 tp
, val
, tb
= sys
.exc_info()
640 traceback
.print_exception(tp
, val
, tb
)
642 # Block while waiting to be called back from the GUI. Eventually, self._wait will
643 # be set false by a function on this side. Seems pretty lame--I'm surprised it works.
647 def waitForRPC(self
):
652 print "+++ in harness wait for rpc, before handle_request"
653 self
._server
.handle_request()
655 print "+++ in harness wait for rpc, after handle_request"
658 tp
, val
, tb
= sys
.exc_info()
659 print "Got waitForRpc exception : ", repr(tp
), ": ", val
667 def set_continue(self
):
668 self
._adb
.set_continue()
673 self
._adb
.set_next(self
._currentFrame
)
677 def set_return(self
):
678 self
._adb
.set_return(self
._currentFrame
)
682 if __name__
== '__main__':
684 harness
= DebuggerHarness()
689 tp
, val
, tb
= sys
.exc_info()
690 traceback
.print_exception(tp
, val
, tb
)