blob: f849e316736b28d7b443ddf954c3ec4fe78b7f1f [file] [log] [blame]
# -----------------------------------------------------------------------------
# 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)