]>
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
28 if sys
.platform
.startswith("win"):
35 _DEBUG_DEBUGGER
= False
39 def __init__(self
, harness
, queue
):
40 bdb
.Bdb
.__init
__(self
)
41 self
._harness
= harness
42 self
._userBreak
= False
44 self
._knownCantExpandFiles
= {}
45 self
._knownExpandedFiles
= {}
47 def getLongName(self
, filename
):
50 if self
._knownCantExpandFiles
.get(filename
):
52 if self
._knownExpandedFiles
.get(filename
):
53 return self
._knownExpandedFiles
.get(filename
)
55 newname
= win32api
.GetLongPathName(filename
)
56 self
._knownExpandedFiles
[filename
] = newname
59 self
._knownCantExpandFiles
[filename
] = filename
62 def canonic(self
, orig_filename
):
63 if orig_filename
== "<" + orig_filename
[1:-1] + ">":
65 filename
= self
.getLongName(orig_filename
)
67 canonic
= self
.fncache
.get(filename
)
69 canonic
= os
.path
.abspath(filename
)
70 canonic
= os
.path
.normcase(canonic
)
71 self
.fncache
[filename
] = canonic
75 # Overriding this so that we continue to trace even if no breakpoints are set.
76 def set_continue(self
):
77 self
.stopframe
= self
.botframe
78 self
.returnframe
= None
81 def do_clear(self
, arg
):
82 bdb
.Breakpoint
.bpbynumber
[int(arg
)].deleteMe()
84 def user_line(self
, frame
):
85 if self
.in_debugger_code(frame
):
88 message
= self
.__frame
2message
(frame
)
89 self
._harness
.interaction(message
, frame
, "")
91 def user_call(self
, frame
, argument_list
):
92 if self
.in_debugger_code(frame
):
95 if self
.stop_here(frame
):
96 message
= self
.__frame
2message
(frame
)
97 self
._harness
.interaction(message
, frame
, "")
99 def user_return(self
, frame
, return_value
):
100 if self
.in_debugger_code(frame
):
103 message
= self
.__frame
2message
(frame
)
104 self
._harness
.interaction(message
, frame
, "")
106 def user_exception(self
, frame
, (exc_type
, exc_value
, exc_traceback
)):
107 frame
.f_locals
['__exception__'] = exc_type
, exc_value
108 if type(exc_type
) == type(''):
109 exc_type_name
= exc_type
111 exc_type_name
= exc_type
.__name
__
112 message
= "Exception occured: " + repr(exc_type_name
) + " See locals.__exception__ for details."
113 traceback
.print_exception(exc_type
, exc_value
, exc_traceback
)
114 self
._harness
.interaction(message
, frame
, message
)
116 def in_debugger_code(self
, frame
):
117 if _DEBUG_DEBUGGER
: return False
118 message
= self
.__frame
2message
(frame
)
119 return message
.count('DebuggerHarness') > 0
121 def frame2message(self
, frame
):
122 return self
.__frame
2message
(frame
)
124 def __frame2message(self
, frame
):
126 filename
= code
.co_filename
127 lineno
= frame
.f_lineno
128 basename
= os
.path
.basename(filename
)
129 message
= "%s:%s" % (basename
, lineno
)
130 if code
.co_name
!= "?":
131 message
= "%s: %s()" % (message
, code
.co_name
)
134 def runFile(self
, fileName
):
137 #global_dict['__name__'] = '__main__'
139 fileToRun
= open(fileName
, mode
='r')
140 if _VERBOSE
: print "Running file ", fileName
141 sys
.settrace(self
.trace_dispatch
)
143 exec fileToRun
in __main__
.__dict
__,__main__
.__dict
__
147 tp
, val
, tb
= sys
.exc_info()
148 traceback
.print_exception(tp
, val
, tb
)
154 def trace_dispatch(self
, frame
, event
, arg
):
157 # Check for ui events
160 return self
.dispatch_line(frame
)
162 return self
.dispatch_call(frame
, arg
)
163 if event
== 'return':
164 return self
.dispatch_return(frame
, arg
)
165 if event
== 'exception':
166 return self
.dispatch_exception(frame
, arg
)
167 print 'Adb.dispatch: unknown debugging event:', `event`
168 return self
.trace_dispatch
171 while self
._queue
.qsize():
173 item
= self
._queue
.get_nowait()
175 self
._harness
.do_exit(kill
=True)
176 elif item
.breakHere():
177 self
._userBreak
= True
178 elif item
.hasBreakpoints():
179 self
.set_all_breakpoints(item
.getBreakpoints())
183 def set_all_breakpoints(self
, dict):
184 self
.clear_all_breaks()
185 for fileName
in dict.keys():
186 lineList
= dict[fileName
]
187 for lineNumber
in lineList
:
189 if _VERBOSE
: print "Setting break at line ", str(lineNumber
), " in file ", self
.canonic(fileName
)
190 self
.set_break(fileName
, int(lineNumber
))
193 def stop_here(self
, frame
):
198 # (CT) stopframe may now also be None, see dispatch_call.
199 # (CT) the former test for None is therefore removed from here.
200 if frame
is self
.stopframe
:
202 while frame
is not None and frame
is not self
.stopframe
:
203 if frame
is self
.botframe
:
208 class BreakNotify(object):
209 def __init__(self
, bps
=None, break_here
=False, kill
=False):
211 self
._break
_here
= break_here
215 return self
._break
_here
220 def getBreakpoints(self
):
223 def hasBreakpoints(self
):
224 return (self
._bps
!= None)
226 class AGXMLRPCServer(SimpleXMLRPCServer
.SimpleXMLRPCServer
):
227 def __init__(self
, address
, logRequests
=0):
228 SimpleXMLRPCServer
.SimpleXMLRPCServer
.__init
__(self
, address
, logRequests
=logRequests
)
230 class BreakListenerThread(threading
.Thread
):
231 def __init__(self
, host
, port
, queue
):
232 threading
.Thread
.__init
__(self
)
234 self
._port
= int(port
)
235 self
._keepGoing
= True
237 self
._server
= AGXMLRPCServer((self
._host
, self
._port
), logRequests
=0)
238 self
._server
.register_function(self
.update_breakpoints
)
239 self
._server
.register_function(self
.break_requested
)
240 self
._server
.register_function(self
.die
)
242 def break_requested(self
):
243 bn
= BreakNotify(break_here
=True)
247 def update_breakpoints(self
, pickled_Binary_bpts
):
248 dict = pickle
.loads(pickled_Binary_bpts
.data
)
249 bn
= BreakNotify(bps
=dict)
254 bn
= BreakNotify(kill
=True)
259 while self
._keepGoing
:
261 self
._server
.handle_request()
264 tp
, val
, tb
= sys
.exc_info()
265 print "Exception in BreakListenerThread.run():", str(tp
), str(val
)
266 self
._keepGoing
= False
269 self
._keepGoing
= False
270 if type(self
._server
) is not types
.NoneType
:
271 if _VERBOSE
: print "Before calling server close on breakpoint server"
272 self
._server
.server_close()
273 if _VERBOSE
: print "Calling server close on breakpoint server"
277 class DebuggerHarness(object):
280 # Host and port for debugger-side RPC server
281 self
._hostname
= sys
.argv
[1]
282 self
._portNumber
= int(sys
.argv
[2])
283 # Name the gui proxy object is registered under
284 self
._breakPortNumber
= int(sys
.argv
[3])
285 # Host and port where the gui proxy can be found.
286 self
._guiHost
= sys
.argv
[4]
287 self
._guiPort
= int(sys
.argv
[5])
289 self
._command
= sys
.argv
[6]
290 # Strip out the harness' arguments so that the process we run will see argv as if
291 # it was called directly.
292 sys
.argv
= sys
.argv
[6:]
293 self
._currentFrame
= None
295 # Connect to the gui-side RPC server.
296 self
._guiServerUrl
= 'http://' + self
._guiHost
+ ':' + str(self
._guiPort
) + '/'
297 if _VERBOSE
: print "Connecting to gui server at ", self
._guiServerUrl
298 self
._guiServer
= xmlrpclib
.ServerProxy(self
._guiServerUrl
,allow_none
=1)
300 # Start the break listener
301 self
._breakQueue
= Queue
.Queue(50)
302 self
._breakListener
= BreakListenerThread(self
._hostname
, self
._breakPortNumber
, self
._breakQueue
)
303 self
._breakListener
.start()
304 # Create the debugger.
305 self
._adb
= Adb(self
, self
._breakQueue
)
307 # Create the debugger-side RPC Server and register functions for remote calls.
308 self
._server
= AGXMLRPCServer((self
._hostname
, self
._portNumber
), logRequests
=0)
309 self
._server
.register_function(self
.set_step
)
310 self
._server
.register_function(self
.set_continue
)
311 self
._server
.register_function(self
.set_next
)
312 self
._server
.register_function(self
.set_return
)
313 self
._server
.register_function(self
.set_breakpoint
)
314 self
._server
.register_function(self
.clear_breakpoint
)
315 self
._server
.register_function(self
.set_all_breakpoints
)
316 self
._server
.register_function(self
.attempt_introspection
)
317 self
._server
.register_function(self
.execute_in_frame
)
318 self
._server
.register_function(self
.add_watch
)
319 self
._server
.register_function(self
.request_frame_document
)
321 self
.frame_stack
= []
322 self
.message_frame_dict
= {}
323 self
.introspection_list
= []
324 atexit
.register(self
.do_exit
)
327 self
._adb
.runFile(self
._command
)
328 self
.do_exit(kill
=True)
331 def do_exit(self
, kill
=False):
333 self
._breakListener
.AskToStop()
334 self
._server
.server_close()
336 self
._guiServer
.quit()
345 def set_breakpoint(self
, fileName
, lineNo
):
346 self
._adb
.set_break(fileName
, lineNo
)
349 def set_all_breakpoints(self
, dict):
350 self
._adb
.clear_all_breaks()
351 for fileName
in dict.keys():
352 lineList
= dict[fileName
]
353 for lineNumber
in lineList
:
354 self
._adb
.set_break(fileName
, int(lineNumber
))
355 if _VERBOSE
: print "Setting break at ", str(lineNumber
), " in file ", fileName
358 def clear_breakpoint(self
, fileName
, lineNo
):
359 self
._adb
.clear_break(fileName
, lineNo
)
362 def add_watch(self
, name
, text
, frame_message
, run_once
):
363 if len(frame_message
) > 0:
364 frame
= self
.message_frame_dict
[frame_message
]
366 item
= eval(text
, frame
.f_globals
, frame
.f_locals
)
367 return self
.get_watch_document(item
, name
)
369 tp
, val
, tb
= sys
.exc_info()
370 return self
.get_exception_document(tp
, val
, tb
)
373 def execute_in_frame(self
, frame_message
, command
):
374 frame
= self
.message_frame_dict
[frame_message
]
375 output
= cStringIO
.StringIO()
381 exec command
in frame
.f_globals
, frame
.f_locals
382 return output
.getvalue()
389 tp
, val
, tb
= sys
.exc_info()
390 output
= cStringIO
.StringIO()
391 traceback
.print_exception(tp
, val
, tb
, file=output
)
392 return output
.getvalue()
394 def attempt_introspection(self
, frame_message
, chain
):
396 frame
= self
.message_frame_dict
[frame_message
]
399 if name
== 'globals':
400 item
= frame
.f_globals
401 elif name
== 'locals':
402 item
= frame
.f_locals
405 item
= self
.getNextItem(item
, name
)
406 return self
.get_introspection_document(item
, name
)
408 tp
, val
, tb
= sys
.exc_info()
409 traceback
.print_exception(tp
, val
, tb
)
410 return self
.get_empty_introspection_document()
412 def getNextItem(self
, link
, identifier
):
414 if self
.isTupleized(identifier
):
415 return self
.deTupleize(link
, identifier
)
417 if tp
== types
.DictType
or tp
== types
.DictProxyType
:
418 return link
[identifier
]
420 if hasattr(link
, identifier
):
421 return getattr(link
, identifier
)
422 if _VERBOSE
or True: print "Failed to find link ", identifier
, " on thing: ", self
.saferepr(link
), " of type ", repr(type(link
))
425 def isPrimitive(self
, item
):
427 return tp
is types
.IntType
or tp
is types
.LongType
or tp
is types
.FloatType \
428 or tp
is types
.BooleanType
or tp
is types
.ComplexType \
429 or tp
is types
.StringType
431 def isTupleized(self
, value
):
432 return value
.count('[')
434 def deTupleize(self
, link
, string1
):
436 start
= string1
.find('[')
437 end
= string1
.find(']')
438 num
= int(string1
[start
+1:end
])
441 tp
,val
,tb
= sys
.exc_info()
442 if _VERBOSE
: print "Got exception in deTupleize: ", val
445 def wrapAndCompress(self
, stringDoc
):
447 return xmlrpclib
.Binary(bz2
.compress(stringDoc
))
449 def get_empty_introspection_document(self
):
450 doc
= getDOMImplementation().createDocument(None, "replacement", None)
451 return self
.wrapAndCompress(doc
.toxml())
453 def get_watch_document(self
, item
, identifier
):
454 doc
= getDOMImplementation().createDocument(None, "watch", None)
455 top_element
= doc
.documentElement
456 self
.addAny(top_element
, identifier
, item
, doc
, 2)
457 return self
.wrapAndCompress(doc
.toxml())
459 def get_introspection_document(self
, item
, identifier
):
460 doc
= getDOMImplementation().createDocument(None, "replacement", None)
461 top_element
= doc
.documentElement
462 self
.addAny(top_element
, identifier
, item
, doc
, 2)
463 return self
.wrapAndCompress(doc
.toxml())
465 def get_exception_document(self
, name
, tp
, val
, tb
):
466 stack
= traceback
.format_exception(tp
, val
, tb
)
470 doc
= getDOMImplementation().createDocument(None, "watch", None)
471 top_element
= doc
.documentElement
472 item_node
= doc
.createElement("dict_nv_element")
473 item_node
.setAttribute('value', wholeStack
)
474 item_node
.setAttribute('name', str(name
))
475 top_element
.appendChild(item_node
)
477 cantIntro
= [types
.FunctionType
,
487 def addAny(self
, top_element
, name
, item
, doc
, ply
):
490 if tp
in DebuggerHarness
.cantIntro
or ply
< 1:
491 self
.addNode(top_element
,name
, item
, doc
)
492 elif tp
is types
.TupleType
or tp
is types
.ListType
:
493 self
.addTupleOrList(top_element
, name
, item
, doc
, ply
- 1)
494 elif tp
is types
.DictType
or tp
is types
.DictProxyType
:
495 self
.addDict(top_element
, name
, item
, doc
, ply
-1)
496 elif inspect
.ismodule(item
):
497 self
.addModule(top_element
, name
, item
, doc
, ply
-1)
498 elif inspect
.isclass(item
) or tp
is types
.InstanceType
:
499 self
.addClass(top_element
, name
, item
, doc
, ply
-1)
500 elif hasattr(item
, '__dict__'):
501 self
.addDictAttr(top_element
, name
, item
, doc
, ply
-1)
503 self
.addNode(top_element
,name
, item
, doc
)
506 def canIntrospect(self
, item
):
508 if tp
in DebuggerHarness
.cantIntro
:
510 elif tp
is types
.TupleType
or tp
is types
.ListType
:
512 elif tp
is types
.DictType
or tp
is types
.DictProxyType
:
514 elif inspect
.ismodule(item
):
516 elif inspect
.isclass(item
) or tp
is types
.InstanceType
:
517 if hasattr(item
, '__dict__'):
519 elif hasattr(item
, '__name__'):
521 elif hasattr(item
, '__module__'):
523 elif hasattr(item
, '__doc__'):
527 elif hasattr(item
, '__dict__'):
528 return len(item
.__dict
__) > 0
532 def addNode(self
, parent_node
, name
, item
, document
):
533 item_node
= document
.createElement("dict_nv_element")
534 item_node
.setAttribute('value', self
.saferepr(item
))
535 item_node
.setAttribute('name', str(name
))
536 introVal
= str(self
.canIntrospect(item
))
537 item_node
.setAttribute('intro', str(introVal
))
538 parent_node
.appendChild(item_node
)
541 def addTupleOrList(self
, top_node
, name
, tupple
, doc
, ply
):
542 tupleNode
= doc
.createElement('tuple')
543 tupleNode
.setAttribute('name', str(name
))
544 tupleNode
.setAttribute('value', self
.saferepr(tupple
))
545 top_node
.appendChild(tupleNode
)
548 self
.addAny(tupleNode
, name
+'[' + str(count
) + ']',item
, doc
, ply
-1)
551 def addDictAttr(self
, root_node
, name
, thing
, document
, ply
):
552 dict_node
= document
.createElement('thing')
553 dict_node
.setAttribute('name', name
)
554 dict_node
.setAttribute('value', self
.saferepr(thing
))
555 root_node
.appendChild(dict_node
)
556 self
.addDict(dict_node
, '', thing
.__dict
__, document
, ply
) # Not decreminting ply
558 def addDict(self
, root_node
, name
, dict, document
, ply
):
560 dict_node
= document
.createElement('dict')
561 dict_node
.setAttribute('name', name
)
562 dict_node
.setAttribute('value', self
.saferepr(dict))
563 root_node
.appendChild(dict_node
)
565 dict_node
= root_node
566 for key
in dict.keys():
570 self
.addAny(dict_node
, strkey
, value
, document
, ply
-1)
573 tp
,val
,tb
=sys
.exc_info()
574 print "Error recovering key: ", str(key
), " from node ", str(name
), " Val = ", str(val
)
575 traceback
.print_exception(tp
, val
, tb
)
577 def addClass(self
, root_node
, name
, class_item
, document
, ply
):
578 item_node
= document
.createElement('class')
579 item_node
.setAttribute('name', str(name
))
580 item_node
.setAttribute('value', self
.saferepr(class_item
))
581 root_node
.appendChild(item_node
)
583 if hasattr(class_item
, '__dict__'):
584 self
.addDict(item_node
, '', class_item
.__dict
__, document
, ply
-1)
586 tp
,val
,tb
=sys
.exc_info()
588 traceback
.print_exception(tp
, val
, tb
)
590 if hasattr(class_item
, '__name__'):
591 self
.addAny(item_node
,'__name__',class_item
.__name
__, document
, ply
-1)
593 tp
,val
,tb
=sys
.exc_info()
595 traceback
.print_exception(tp
, val
, tb
)
597 if hasattr(class_item
, '__module__'):
598 self
.addAny(item_node
, '__module__', class_item
.__module
__, document
, ply
-1)
600 tp
,val
,tb
=sys
.exc_info()
602 traceback
.print_exception(tp
, val
, tb
)
604 if hasattr(class_item
, '__doc__'):
605 self
.addAny(item_node
, '__doc__', class_item
.__doc
__, document
, ply
-1)
607 tp
,val
,tb
=sys
.exc_info()
609 traceback
.print_exception(tp
, val
, tb
)
611 if hasattr(class_item
, '__bases__'):
612 self
.addAny(item_node
, '__bases__', class_item
.__bases
__, document
, ply
-1)
614 tp
,val
,tb
=sys
.exc_info()
616 traceback
.print_exception(tp
, val
, tb
)
618 def addModule(self
, root_node
, name
, module_item
, document
, ply
):
619 item_node
= document
.createElement('module')
620 item_node
.setAttribute('name', str(name
))
621 item_node
.setAttribute('value', self
.saferepr(module_item
))
622 root_node
.appendChild(item_node
)
624 if hasattr(module_item
, '__file__'):
625 self
.addAny(item_node
, '__file__', module_item
.__file
__, document
, ply
-1)
629 if hasattr(module_item
, '__doc__'):
630 self
.addAny(item_node
,'__doc__', module_item
.__doc
__, document
, ply
-1)
636 def getFrameXML(self
, base_frame
):
638 self
.frame_stack
= []
640 while frame
is not None:
641 if((frame
.f_code
.co_filename
.count('DebuggerHarness.py') == 0) or _DEBUG_DEBUGGER
):
642 self
.frame_stack
.append(frame
)
644 self
.frame_stack
.reverse()
645 self
.message_frame_dict
= {}
646 doc
= getDOMImplementation().createDocument(None, "stack", None)
647 top_element
= doc
.documentElement
648 numberFrames
= len(self
.frame_stack
)
649 for index
in range(numberFrames
):
650 frame
= self
.frame_stack
[index
]
651 message
= self
._adb
.frame2message(frame
)
652 # We include globals and locals only for the last frame as an optimization for cases
653 # where there are a lot of frames.
654 self
.addFrame(frame
, top_element
, doc
, includeContent
=(index
== numberFrames
- 1))
657 def addFrame(self
, frame
, root_element
, document
, includeContent
=False):
658 frameNode
= document
.createElement('frame')
659 root_element
.appendChild(frameNode
)
662 filename
= code
.co_filename
663 frameNode
.setAttribute('file', str(filename
))
664 frameNode
.setAttribute('line', str(frame
.f_lineno
))
665 message
= self
._adb
.frame2message(frame
)
666 frameNode
.setAttribute('message', message
)
667 self
.message_frame_dict
[message
] = frame
669 self
.addDict(frameNode
, "locals", frame
.f_locals
, document
, 2)
670 self
.addNode(frameNode
, "globals", frame
.f_globals
, document
)
672 def request_frame_document(self
, message
):
673 frame
= self
.message_frame_dict
[message
]
674 doc
= getDOMImplementation().createDocument(None, "stack", None)
675 top_element
= doc
.documentElement
677 self
.addFrame(frame
, top_element
, doc
, includeContent
=True)
678 return xmlrpclib
.Binary(bz2
.compress(doc
.toxml()))
680 def getRepr(self
, varName
, globals, locals):
682 return repr(eval(varName
, globals, locals))
684 return 'Error: Could not recover value.'
687 def saferepr(self
, thing
):
692 return str(type(thing
))
694 tp
, val
, tb
= sys
.exc_info()
695 #traceback.print_exception(tp, val, tb)
698 # The debugger calls this method when it reaches a breakpoint.
699 def interaction(self
, message
, frame
, info
):
701 print 'hit debug side interaction'
702 self
._adb
._userBreak
= False
704 self
._currentFrame
= frame
708 xml
= self
.getFrameXML(frame
)
709 arg
= xmlrpclib
.Binary(bz2
.compress(xml
))
711 print '============== calling gui side interaction============'
712 self
._guiServer
.interaction(xmlrpclib
.Binary(message
), arg
, info
)
714 print 'after interaction'
717 tp
, val
, tb
= sys
.exc_info()
719 print 'Error contacting GUI server!: '
721 traceback
.print_exception(tp
, val
, tb
)
723 print "Exception printing traceback",
724 tp
, val
, tb
= sys
.exc_info()
725 traceback
.print_exception(tp
, val
, tb
)
727 # Block while waiting to be called back from the GUI. Eventually, self._wait will
728 # be set false by a function on this side. Seems pretty lame--I'm surprised it works.
732 def waitForRPC(self
):
737 print "+++ in harness wait for rpc, before handle_request"
738 self
._server
.handle_request()
740 print "+++ in harness wait for rpc, after handle_request"
743 tp
, val
, tb
= sys
.exc_info()
744 print "Got waitForRpc exception : ", repr(tp
), ": ", val
752 def set_continue(self
):
753 self
._adb
.set_continue()
758 self
._adb
.set_next(self
._currentFrame
)
762 def set_return(self
):
763 self
._adb
.set_return(self
._currentFrame
)
767 if __name__
== '__main__':
769 harness
= DebuggerHarness()
771 harness
.do_exit(kill
=True)
775 tp
, val
, tb
= sys
.exc_info()
776 traceback
.print_exception(tp
, val
, tb
)