# ----------------------------------------------------------------------------- # WAD Post-mortem debugger # # This program can be used to walk up and down the call stack of a mixed # Python-C program. The following commands are supported: # # w - A stack traceback # u - Go up the call stack # d - Go down the call stack # e - Edit a file # c - Clear the debugger. # # David Beazley # Copyright (C) 2001 # University of Chicago # All Rights Reserved # ----------------------------------------------------------------------------- import sys import os import traceback import types import linecache print "**************************************************" print "* WAD Debugger *" print "**************************************************" # Save a local copy of the last exception and value objects from sys _last_type = sys.last_type _last_value = sys.last_value _last_traceback = sys.last_traceback _last_level = 0 _cstack = None # Stack of C-only code _pystack = None # Stack of Python only code _combined_stack = None # Combined C-python stack _allmode = 0 # Show entire C stack # Generalized object for holding stack frames class wad_frame: def __init__(self,frame, n = 0): if isinstance(frame,types.TupleType): # A Python traceback object self.__FILE__ = frame[0] self.__LINE__ = frame[1] self.__NAME__ = frame[2] self.__ARGSTR__ = frame[3] self.__FRAMENO__ = n # Make the debugging string self.__DEBUGSTR__ = "#%-3d [ Python ] in %s in %s, line %d" % (self.__FRAMENO__, self.__ARGSTR__, self.__FILE__, self.__LINE__) # Try to get source data self.__SOURCE__ = "%s, Line %d\n\n" % (self.__FILE__, self.__LINE__) for i in range(self.__LINE__-2,self.__LINE__+3): l = linecache.getline(self.__FILE__,i) if not l: l = '\n' if (i == self.__LINE__): self.__SOURCE__ += " => " else: self.__SOURCE__ += " " self.__SOURCE__ += l self.__frame__ = None elif hasattr(frame,"__WAD__"): # A WAD traceback object self.__FILE__ = frame.__FILE__ self.__LINE__ = frame.__LINE__ self.__NAME__ = frame.__NAME__ self.__DEBUGSTR__ = frame.__WHERE__ self.__SOURCE__ = frame.__SOURCE__ self.__frame__ = frame def __str__(self): return self.__DEBUGSTR__.strip() def __getattr__(self,name): if self.__frame__: return getattr(self.__frame__,name) raise AttributeError def output(self): print self if self.__SOURCE__: print "\n%s" % (self.__SOURCE__) def wad_build_info(): global _last_type,_last_value, _last_traceback, _cstack, _combined_stack,_pystack _last_type = None _last_value = None _last_traceback = None _cstack = None _combined_stack = [] # Check to see if any exception is defined if not sys.last_type: print "No exception has occurred." return # Save a copy of previous exception _last_type = sys.last_type _last_value = sys.last_value _last_traceback = sys.last_traceback _last_level = 0 start_frame = 0 # Test to see what kind of object it is if issubclass(_last_type,StandardError): # Python exception print "Python exception" elif hasattr(_last_value[0],"__WAD__"): # A wad exception frame object w = sys.last_value[0] i = 0 _cstack = [] while not w[i].__LAST__: start_frame += 1 wf = wad_frame(w[i]) _cstack.append(wf) i = i + 1 # wf = wad_frame(w[i]) # _cstack.append(wf) # start_frame += 1 # Build the rest of the c stack _combined_stack = _cstack[:] while i < len(w): wf = wad_frame(w[i]) _cstack.append(wf) i = i + 1 else: print "Unknown error" # Build the Python call stack _pystack = [] t = sys.last_traceback tp = None while hasattr(t,"tb_frame"): tp = t t = t.tb_next fr = traceback.extract_stack(tp.tb_frame) for i in range(len(fr),0,-1): f = wad_frame(fr[i-1], start_frame) start_frame += 1 _pystack.append(f) _combined_stack.extend(_pystack) wad_build_info() class where_impl: def __init__(self): self.all = 0; self.cstack = 0 def __repr__(self): global _combined_stack, _cstack, _last_level if (self.cstack): stack = _cstack else: stack = _combined_stack if not stack: print "No current exception." return "" last_source = None for i in range(len(stack),0,-1): f = stack[i-1] print f if (f.__SOURCE__): last_source = f.__SOURCE__ _last_level = i-1 if last_source: print "\n%s" % last_source return "" def __getitem__(self,n): global _last_level, _cstack, _combined_stack if (self.cstack): stack = _cstack else: stack = _combined_stack _last_level = n stack[_last_level].output() return None def __len__(self): return len(frame) where = where_impl() w = where class up_impl: def __repr__(self): global _last_level, _combined_stack, _cstack if where.cstack: stack = _cstack else: stack = _combined_stack if not stack: return "" _last_level += 1 stack[_last_level].output() return "" up = up_impl() u = up class down_impl: def __repr__(self): global _last_level, _combined_stack, _cstack if where.cstack: stack = _cstack else: stack = _combined_stack if not stack: return "" _last_level -= 1 stack[_last_level].output() return "" down = down_impl() d = down class clear_impl: def __repr__(self): global _last_exc, _last_level, frame _last_exc = None frame = None clear = clear_impl() c = clear class edit_impl: def __repr__(self): global _last_level, _combined_stack, _cstack if where.cstack: stack = _cstack else: stack = _combined_stack if not stack: return "" f = stack[_last_level] e = os.getenv("EDITOR","vi") if f.__FILE__: os.system("%s +%d %s" % (e,f.__LINE__,f.__FILE__)) return "" edit = edit_impl() e = edit class var_impl: def __getattr__(self,name): if (w.cstack): stack = _cstack else: stack = _combined_stack return getattr(stack[_last_level],name) v = var_impl() repr(w)