''' Support for parsing strings containing gdb backtraces, turning them into classes ''' import re class Frame(object): ''' Class representing a stack frame of a thread within a backtrace ''' def __init__(self, index, address, function, info): self.index = index self.address = address self.function = function self.info = info class Thread(object): ''' Class representing a thread within a backtrace ''' def __init__(self, index, pid): self.index = index self.pid = pid self.frames = {} self.framelist = [] class Backtrace(object): ''' Class representing a parsed backtrace ''' def __init__(self, string): ''' Parse the given string (from gdb) ''' debug = False self._string = string if debug: print string self._crash_site = None self._thread = None self._threads = {} self._frame = None for line in string.splitlines(): if debug: print repr(line) m = re.match('^Thread ([0-9]+) \(Thread ([0-9]+)\):$', line) if m: if debug: print 'THREAD START:', m.groups() self._thread = Thread(int(m.group(1)), int(m.group(2))) self._threads[self._thread.index] = self._thread self._frame = None continue m = re.match('^#([0-9]+)\s+(?:0x([0-9a-f]+) in)? (\S+) (.*)$', line) if m: if debug: print 'STACK FRAME:', m.groups() #print m.groups() if m.group(2): address = int(m.group(2), 16) else: address = None f = Frame(int(m.group(1)), address, m.group(3), m.group(4)) if self._thread is None: self._crash_site = f self._frame = None continue else: self._thread.frames[f.index] = f self._thread.framelist.append(f) self._frame = f continue if line.startswith(' '): if self._frame: self._frame.info += '\n' + line #pprint(self._threads[5].frames[6].__dict__) def get_crash_site(self): '''Get a (Thread, Frame) pair for where the crash happened (or None)''' debug = False if debug: print self._crash_site.__dict__ for t in self._threads.values(): if debug: print t if 0 in t.frames: if debug: print t.frames[0].__dict__ if t.frames[0].address == self._crash_site.address: return (t, t.frames[0])