#!/bin/env python # vi:set tabstop=4 shiftwidth=4 expandtab: # Author: Caolan McNamara # Usage: e.g. ooomapstack backtrace # Takes a RedHat OOo backtrace and maps it back to the line numbers it came from # Checks for the current debuginfo-package you need import sys, os versionline = 'OpenOffice.org core rpm version is: openoffice.org-core-' if len(sys.argv) < 2: print 'Usage: ooomapstack BacktraceFile [/path/to/rpm/debuginfo]' sys.exit(1) dumpmaps = {} libdiffs = {} def findknownmethod(library, expectedmethod): address = '' # print 'looking for', library if dumpmaps.has_key(library): # print 'found', library map = dumpmaps[library] # print 'looking for', expectedmethod, 'in', library if map.has_key(expectedmethod): address = map[expectedmethod] # print 'excellent found', expectedmethod, 'at', address return address def resolve(library, debuglibrary, baseaddress, origaddress, origline, known): verified = False libdiff = 0 if libdiffs.has_key(library): libdiff = libdiffs[library] verified = True # print 'diff is', libdiff fixedaddress = hex(int(baseaddress, 16) + libdiff) execline = 'addr2line -C -f -e ' + debuglibrary + ' ' + fixedaddress resultfile = os.popen(execline) methodresult = resultfile.readline()[:-1] lineresult = resultfile.readline()[:-1] resultfile.close() if result == '??:0': execline = 'addr2line -C -f -e ' + debuglibrary + ' ' + origaddress resultfile = os.popen(execline) methodresult = resultfile.readline()[:-1] lineresult = resultfile.readline()[:-1] resultfile.close() if lineresult != '' or methodresult != '': answer = lineresult + '\t' + methodresult else: answer = origline if verified: if known: answer = '100%\t' + answer else: answer = ' 75%\t' + answer else: answer = ' 50%\t' + answer return answer class goodsymbol: def __init__(self, origaddress, expectedmethod, baseaddress, reladdress, library, debuglibrary, origline): self.origaddress = origaddress self.expectedmethod = expectedmethod self.baseaddress = baseaddress self.reladdress = reladdress self.library = library self.debuglibrary = debuglibrary self.origline = origline # print 'library is', library # print 'debuglibrary is', debuglibrary # print 'base address is', baseaddress # print 'expected method is', expectedmethod # print 'relative address is', reladdress def fixup(self): correctbaseaddress = findknownmethod(self.library, self.expectedmethod) if correctbaseaddress == '': return # print 'correct base is', int(correctbaseaddress, 16) # print 'given base is', int(self.baseaddress, 16) # print 'given rel is', int(self.reladdress, 16) correctbase = int(correctbaseaddress, 16) baseaddress = int(self.baseaddress, 16) - int(self.reladdress, 16) libdiff = correctbase - baseaddress if libdiffs.has_key(self.library): if libdiff != libdiffs[self.library]: print >> sys.stderr, "it's all gone horribly wrong" libdiffs[self.library] = libdiff def resolve(self): return resolve(self.library, self.debuglibrary, self.baseaddress, self.origaddress, self.origline, True) class badsymbol: def __init__(self, origaddress, baseaddress, library, debuglibrary, origline): self.origaddress = origaddress self.baseaddress = baseaddress self.library = library self.debuglibrary = debuglibrary self.origline = origline # print 'library is', library # print 'debuglibrary is', debuglibrary # print 'base address is', baseaddress def resolve(self): return resolve(self.library, self.debuglibrary, self.baseaddress, self.origaddress, self.origline, False) def fixup(self): pass class bogussymbol: def __init__(self, text): self.text = text def resolve(self): return ' 0%\t' + self.text def fixup(self): pass debuginfopath = '' backtrace = sys.argv[1] if len(sys.argv) > 2: debuginfopath = sys.argv[2] bt = open(backtrace, "r") symbols = [] while 1: line = bt.readline() if line == '': break line = line[:-1] if line == '': continue if debuginfopath == '' and line.find(versionline) != -1: version = line[len(versionline):] rpmresult = os.popen('rpm -q openoffice.org-debuginfo-' + version) result = rpmresult.readline() rpmresult.close() result = result[:-1] if result.find('is not installed') != -1: print 'You need to install openoffice.org-debuginfo-' + version print 'or set the path to the appropiate debuginfo, see Usage' sys.exit(1) if line[0:2] != '0x': continue portions = line.split(':') origaddress = portions[0] useful = portions[1] portions = useful.split(' + ') library = portions[0].strip() address = portions[1] methodresult = '' lineresult = '' result = '' if library == '': symbols.append(bogussymbol(line)) else: debuglibrary = debuginfopath + '/usr/lib/debug' + library + '.debug' library = debuginfopath + library for i in range(2,len(address)): if address[i] == ' ': address = address[0:i] break start = line.find('(') end = line.rfind(')') if start != -1 and end != -1: portions = line[start+1:end].split(' + ') expectedmethod = portions[0].strip() reladdress = portions[1] # print 'expectedmethod will be', expectedmethod symbols.append(goodsymbol(origaddress, expectedmethod, address, reladdress, library, debuglibrary, line)) else: symbols.append(badsymbol(origaddress, address, library, debuglibrary, line)) if not dumpmaps.has_key(library): map = {} execline = 'objdump -T ' + library + ' | grep \\\.text | grep Base | c++filt' resultfile = os.popen(execline) line = resultfile.readline() while line != '': line = line[:-1] result = line.split(None,6) map[result[6]] = result[0] line = resultfile.readline() resultfile.close() dumpmaps[library] = map for symbol in symbols: symbol.fixup() lineno = 1 for symbol in symbols: print lineno, '\t' + symbol.resolve() lineno = lineno + 1