summaryrefslogtreecommitdiffstats
path: root/backtrace.py
diff options
context:
space:
mode:
Diffstat (limited to 'backtrace.py')
-rw-r--r--backtrace.py72
1 files changed, 59 insertions, 13 deletions
diff --git a/backtrace.py b/backtrace.py
index 57e907e..cebba2f 100644
--- a/backtrace.py
+++ b/backtrace.py
@@ -13,6 +13,26 @@ class Frame(object):
self.function = function
self.info = info
+ def as_python_frame(self):
+ '''For relevant frames, return (file, line, funcname, args) tuple; otherwise None'''
+ if self.function != 'PyEval_EvalFrameEx':
+ return None
+ return PythonFrame(self)
+ #result += '#%i %s\n' % (frame.index, frame.info)
+
+class PythonFrame(object):
+ '''
+ Class representating an interpretation of a C stack frame as a Python stack frame
+ '''
+ def __init__(self, c_frame):
+ self.c_frame = c_frame
+ m = re.match('\(f=Frame 0x[0-9a-f]+, for file (\S+), line ([0-9]+), in (\S+) \((.*), throwflag=0\) at (\S+)',
+ c_frame.info)
+ self.file = m.group(1)
+ self.linenum = m.group(2)
+ self.funcname = m.group(3)
+ self.vars = m.group(4)
+
class Thread(object):
'''
Class representing a thread within a backtrace
@@ -23,10 +43,30 @@ class Thread(object):
self.frames = {}
self.framelist = []
+ def as_python_backtrace(self, with_vars):
+ '''Generate a textual guess at a python-level backtrace'''
+ result = ''
+ for frame in self.framelist:
+ pyframe = frame.as_python_frame()
+ if pyframe:
+ result += '#%i %s:%s %s\n' % (frame.index,
+ pyframe.file,
+ pyframe.linenum,
+ pyframe.funcname)
+ if with_vars:
+ result += ' %s\n' % (pyframe.vars, )
+ return result
+
class Backtrace(object):
'''
Class representing a parsed backtrace
'''
+ @classmethod
+ def from_text_file(cls, filename, debug=False):
+ with open(filename, 'r') as f:
+ text = f.read()
+ return Backtrace(text, debug)
+
def __init__(self, string, debug=False):
'''
Parse the given string (from gdb)
@@ -51,7 +91,7 @@ class Backtrace(object):
self._frame = None
continue
- m = re.match('^#([0-9]+)\s+(?:0x([0-9a-f]+) in)? (\S+) (.*)$', line)
+ m = re.match('^#([0-9]+)\s+(?:0x([0-9a-f]+) in )?(\S+) (.*)$', line)
if m:
if debug:
print 'STACK FRAME:', m.groups()
@@ -64,18 +104,8 @@ class Backtrace(object):
address,
m.group(3),
m.group(4))
-
- if self._thread is None:
- if debug:
- print 'GOT CRASH SITE'
- self._crash_site = f
- self._frame = None
- continue
- else:
- self._thread.frames[f.index] = f
- self._thread.framelist.append(f)
- self._frame = f
- continue
+ self.__on_new_frame(f, debug)
+ continue
if line.startswith(' '):
if self._frame:
@@ -83,6 +113,17 @@ class Backtrace(object):
#pprint(self._threads[5].frames[6].__dict__)
+ def __on_new_frame(self, f, debug):
+ if self._thread is None:
+ if debug:
+ print 'GOT CRASH SITE'
+ self._crash_site = f
+ self._frame = None
+ else:
+ self._thread.frames[f.index] = f
+ self._thread.framelist.append(f)
+ self._frame = f
+
def get_crash_site(self):
'''Get a (Thread, Frame) pair for where the crash happened (or None)'''
debug = False
@@ -96,3 +137,8 @@ class Backtrace(object):
print t.frames[0].__dict__
if t.frames[0].address == self._crash_site.address:
return (t, t.frames[0])
+
+ def as_python_backtrace(self, with_vars):
+ '''Generate a textual guess at a python-level backtrace'''
+ thread, frame = self.get_crash_site()
+ return thread.as_python_backtrace(with_vars)