]>
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 code
= compile(command
, '<string>', 'single')
382 exec code
in frame
.f_globals
, frame
.f_locals
383 return output
.getvalue()
390 tp
, val
, tb
= sys
.exc_info()
391 output
= cStringIO
.StringIO()
392 traceback
.print_exception(tp
, val
, tb
, file=output
)
393 return output
.getvalue()
395 def attempt_introspection(self
, frame_message
, chain
):
397 frame
= self
.message_frame_dict
[frame_message
]
400 if name
== 'globals':
401 item
= frame
.f_globals
402 elif name
== 'locals':
403 item
= frame
.f_locals
406 item
= self
.getNextItem(item
, name
)
407 return self
.get_introspection_document(item
, name
)
409 tp
, val
, tb
= sys
.exc_info()
410 traceback
.print_exception(tp
, val
, tb
)
411 return self
.get_empty_introspection_document()
413 def getNextItem(self
, link
, identifier
):
415 if self
.isTupleized(identifier
):
416 return self
.deTupleize(link
, identifier
)
418 if tp
== types
.DictType
or tp
== types
.DictProxyType
:
419 return link
[identifier
]
421 if hasattr(link
, identifier
):
422 return getattr(link
, identifier
)
423 if _VERBOSE
or True: print "Failed to find link ", identifier
, " on thing: ", self
.saferepr(link
), " of type ", repr(type(link
))
426 def isPrimitive(self
, item
):
428 return tp
is types
.IntType
or tp
is types
.LongType
or tp
is types
.FloatType \
429 or tp
is types
.BooleanType
or tp
is types
.ComplexType \
430 or tp
is types
.StringType
432 def isTupleized(self
, value
):
433 return value
.count('[')
435 def deTupleize(self
, link
, string1
):
437 start
= string1
.find('[')
438 end
= string1
.find(']')
439 num
= int(string1
[start
+1:end
])
442 tp
,val
,tb
= sys
.exc_info()
443 if _VERBOSE
: print "Got exception in deTupleize: ", val
446 def wrapAndCompress(self
, stringDoc
):
448 return xmlrpclib
.Binary(bz2
.compress(stringDoc
))
450 def get_empty_introspection_document(self
):
451 doc
= getDOMImplementation().createDocument(None, "replacement", None)
452 return self
.wrapAndCompress(doc
.toxml())
454 def get_watch_document(self
, item
, identifier
):
455 doc
= getDOMImplementation().createDocument(None, "watch", None)
456 top_element
= doc
.documentElement
457 self
.addAny(top_element
, identifier
, item
, doc
, 2)
458 return self
.wrapAndCompress(doc
.toxml())
460 def get_introspection_document(self
, item
, identifier
):
461 doc
= getDOMImplementation().createDocument(None, "replacement", None)
462 top_element
= doc
.documentElement
463 self
.addAny(top_element
, identifier
, item
, doc
, 2)
464 return self
.wrapAndCompress(doc
.toxml())
466 def get_exception_document(self
, name
, tp
, val
, tb
):
467 stack
= traceback
.format_exception(tp
, val
, tb
)
471 doc
= getDOMImplementation().createDocument(None, "watch", None)
472 top_element
= doc
.documentElement
473 item_node
= doc
.createElement("dict_nv_element")
474 item_node
.setAttribute('value', wholeStack
)
475 item_node
.setAttribute('name', str(name
))
476 top_element
.appendChild(item_node
)
478 cantIntro
= [types
.FunctionType
,
488 def addAny(self
, top_element
, name
, item
, doc
, ply
):
491 if tp
in DebuggerHarness
.cantIntro
or ply
< 1:
492 self
.addNode(top_element
,name
, item
, doc
)
493 elif tp
is types
.TupleType
or tp
is types
.ListType
:
494 self
.addTupleOrList(top_element
, name
, item
, doc
, ply
- 1)
495 elif tp
is types
.DictType
or tp
is types
.DictProxyType
:
496 self
.addDict(top_element
, name
, item
, doc
, ply
-1)
497 elif inspect
.ismodule(item
):
498 self
.addModule(top_element
, name
, item
, doc
, ply
-1)
499 elif inspect
.isclass(item
) or tp
is types
.InstanceType
:
500 self
.addClass(top_element
, name
, item
, doc
, ply
-1)
501 elif hasattr(item
, '__dict__'):
502 self
.addDictAttr(top_element
, name
, item
, doc
, ply
-1)
504 self
.addNode(top_element
,name
, item
, doc
)
507 def canIntrospect(self
, item
):
509 if tp
in DebuggerHarness
.cantIntro
:
511 elif tp
is types
.TupleType
or tp
is types
.ListType
:
513 elif tp
is types
.DictType
or tp
is types
.DictProxyType
:
515 elif inspect
.ismodule(item
):
517 elif inspect
.isclass(item
) or tp
is types
.InstanceType
:
518 if hasattr(item
, '__dict__'):
520 elif hasattr(item
, '__name__'):
522 elif hasattr(item
, '__module__'):
524 elif hasattr(item
, '__doc__'):
528 elif hasattr(item
, '__dict__'):
529 return len(item
.__dict
__) > 0
533 def addNode(self
, parent_node
, name
, item
, document
):
534 item_node
= document
.createElement("dict_nv_element")
535 item_node
.setAttribute('value', self
.saferepr(item
))
536 item_node
.setAttribute('name', str(name
))
537 introVal
= str(self
.canIntrospect(item
))
538 item_node
.setAttribute('intro', str(introVal
))
539 parent_node
.appendChild(item_node
)
542 def addTupleOrList(self
, top_node
, name
, tupple
, doc
, ply
):
543 tupleNode
= doc
.createElement('tuple')
544 tupleNode
.setAttribute('name', str(name
))
545 tupleNode
.setAttribute('value', self
.saferepr(tupple
))
546 top_node
.appendChild(tupleNode
)
549 self
.addAny(tupleNode
, name
+'[' + str(count
) + ']',item
, doc
, ply
-1)
552 def addDictAttr(self
, root_node
, name
, thing
, document
, ply
):
553 dict_node
= document
.createElement('thing')
554 dict_node
.setAttribute('name', name
)
555 dict_node
.setAttribute('value', self
.saferepr(thing
))
556 root_node
.appendChild(dict_node
)
557 self
.addDict(dict_node
, '', thing
.__dict
__, document
, ply
) # Not decreminting ply
559 def addDict(self
, root_node
, name
, dict, document
, ply
):
561 dict_node
= document
.createElement('dict')
562 dict_node
.setAttribute('name', name
)
563 dict_node
.setAttribute('value', self
.saferepr(dict))
564 root_node
.appendChild(dict_node
)
566 dict_node
= root_node
567 for key
in dict.keys():
571 self
.addAny(dict_node
, strkey
, value
, document
, ply
-1)
574 tp
,val
,tb
=sys
.exc_info()
575 print "Error recovering key: ", str(key
), " from node ", str(name
), " Val = ", str(val
)
576 traceback
.print_exception(tp
, val
, tb
)
578 def addClass(self
, root_node
, name
, class_item
, document
, ply
):
579 item_node
= document
.createElement('class')
580 item_node
.setAttribute('name', str(name
))
581 item_node
.setAttribute('value', self
.saferepr(class_item
))
582 root_node
.appendChild(item_node
)
584 if hasattr(class_item
, '__dict__'):
585 self
.addDict(item_node
, '', class_item
.__dict
__, document
, ply
-1)
587 tp
,val
,tb
=sys
.exc_info()
589 traceback
.print_exception(tp
, val
, tb
)
591 if hasattr(class_item
, '__name__'):
592 self
.addAny(item_node
,'__name__',class_item
.__name
__, document
, ply
-1)
594 tp
,val
,tb
=sys
.exc_info()
596 traceback
.print_exception(tp
, val
, tb
)
598 if hasattr(class_item
, '__module__'):
599 self
.addAny(item_node
, '__module__', class_item
.__module
__, document
, ply
-1)
601 tp
,val
,tb
=sys
.exc_info()
603 traceback
.print_exception(tp
, val
, tb
)
605 if hasattr(class_item
, '__doc__'):
606 self
.addAny(item_node
, '__doc__', class_item
.__doc
__, document
, ply
-1)
608 tp
,val
,tb
=sys
.exc_info()
610 traceback
.print_exception(tp
, val
, tb
)
612 if hasattr(class_item
, '__bases__'):
613 self
.addAny(item_node
, '__bases__', class_item
.__bases
__, document
, ply
-1)
615 tp
,val
,tb
=sys
.exc_info()
617 traceback
.print_exception(tp
, val
, tb
)
619 def addModule(self
, root_node
, name
, module_item
, document
, ply
):
620 item_node
= document
.createElement('module')
621 item_node
.setAttribute('name', str(name
))
622 item_node
.setAttribute('value', self
.saferepr(module_item
))
623 root_node
.appendChild(item_node
)
625 if hasattr(module_item
, '__file__'):
626 self
.addAny(item_node
, '__file__', module_item
.__file
__, document
, ply
-1)
630 if hasattr(module_item
, '__doc__'):
631 self
.addAny(item_node
,'__doc__', module_item
.__doc
__, document
, ply
-1)
637 def getFrameXML(self
, base_frame
):
639 self
.frame_stack
= []
641 while frame
is not None:
642 if((frame
.f_code
.co_filename
.count('DebuggerHarness.py') == 0) or _DEBUG_DEBUGGER
):
643 self
.frame_stack
.append(frame
)
645 self
.frame_stack
.reverse()
646 self
.message_frame_dict
= {}
647 doc
= getDOMImplementation().createDocument(None, "stack", None)
648 top_element
= doc
.documentElement
649 numberFrames
= len(self
.frame_stack
)
650 for index
in range(numberFrames
):
651 frame
= self
.frame_stack
[index
]
652 message
= self
._adb
.frame2message(frame
)
653 # We include globals and locals only for the last frame as an optimization for cases
654 # where there are a lot of frames.
655 self
.addFrame(frame
, top_element
, doc
, includeContent
=(index
== numberFrames
- 1))
658 def addFrame(self
, frame
, root_element
, document
, includeContent
=False):
659 frameNode
= document
.createElement('frame')
660 root_element
.appendChild(frameNode
)
663 filename
= code
.co_filename
664 frameNode
.setAttribute('file', str(filename
))
665 frameNode
.setAttribute('line', str(frame
.f_lineno
))
666 message
= self
._adb
.frame2message(frame
)
667 frameNode
.setAttribute('message', message
)
668 self
.message_frame_dict
[message
] = frame
670 self
.addDict(frameNode
, "locals", frame
.f_locals
, document
, 2)
671 self
.addNode(frameNode
, "globals", frame
.f_globals
, document
)
673 def request_frame_document(self
, message
):
674 frame
= self
.message_frame_dict
[message
]
675 doc
= getDOMImplementation().createDocument(None, "stack", None)
676 top_element
= doc
.documentElement
678 self
.addFrame(frame
, top_element
, doc
, includeContent
=True)
679 return xmlrpclib
.Binary(bz2
.compress(doc
.toxml()))
681 def getRepr(self
, varName
, globals, locals):
683 return repr(eval(varName
, globals, locals))
685 return 'Error: Could not recover value.'
688 def saferepr(self
, thing
):
693 return str(type(thing
))
695 tp
, val
, tb
= sys
.exc_info()
696 #traceback.print_exception(tp, val, tb)
699 # The debugger calls this method when it reaches a breakpoint.
700 def interaction(self
, message
, frame
, info
):
702 print 'hit debug side interaction'
703 self
._adb
._userBreak
= False
705 self
._currentFrame
= frame
709 xml
= self
.getFrameXML(frame
)
710 arg
= xmlrpclib
.Binary(bz2
.compress(xml
))
712 print '============== calling gui side interaction============'
713 self
._guiServer
.interaction(xmlrpclib
.Binary(message
), arg
, info
)
715 print 'after interaction'
718 tp
, val
, tb
= sys
.exc_info()
720 print 'Error contacting GUI server!: '
722 traceback
.print_exception(tp
, val
, tb
)
724 print "Exception printing traceback",
725 tp
, val
, tb
= sys
.exc_info()
726 traceback
.print_exception(tp
, val
, tb
)
728 # Block while waiting to be called back from the GUI. Eventually, self._wait will
729 # be set false by a function on this side. Seems pretty lame--I'm surprised it works.
733 def waitForRPC(self
):
738 print "+++ in harness wait for rpc, before handle_request"
739 self
._server
.handle_request()
741 print "+++ in harness wait for rpc, after handle_request"
744 tp
, val
, tb
= sys
.exc_info()
745 print "Got waitForRpc exception : ", repr(tp
), ": ", val
753 def set_continue(self
):
754 self
._adb
.set_continue()
759 self
._adb
.set_next(self
._currentFrame
)
763 def set_return(self
):
764 self
._adb
.set_return(self
._currentFrame
)
768 if __name__
== '__main__':
770 harness
= DebuggerHarness()
772 harness
.do_exit(kill
=True)
776 tp
, val
, tb
= sys
.exc_info()
777 traceback
.print_exception(tp
, val
, tb
)