If you have an ldmap/LinkMap file and a crash report, you can use this utility to symbolicate the crash report. It's not at all optimized... You need to replace INSERT_BUNDLE_IDENTIFIER_HERE with the identifier of your app (com.yourcompany.yourapp); it's what it uses to determine what symbols might be missing and should be looked up.
Created
August 26, 2010 08:27
-
-
Save nevyn/551067 to your computer and use it in GitHub Desktop.
LinkMap symbolicator
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
import sys, subprocess | |
import re | |
class Symbol(object): | |
def __init__(self, name, start, size, filename): | |
self.name = name | |
self.start = start | |
self.size = size | |
self.filename = filename | |
self.end = start + size | |
def __str__(self): | |
#return "%s [0x%x to 0x%x] in %s" % (self.name, self.start, self.end, self.filename) | |
return "%s in %s" % (self.name, self.filename) | |
class LinkMap(object): | |
def __init__(self, linkmappath): | |
self._object_files = {} | |
self._symbols = {} | |
self._section_re = re.compile("^# (.*):$") | |
self._obj_re = re.compile("^\[\s?(.+)\] .*/(.*)$") | |
self._symbol_re = re.compile("^(0x[\dABCDEF]*)\t(0x[\dABCDEF]*)\t\[(.+)\] (.*)$") | |
p = subprocess.Popen("cat %s | c++filt" % (linkmappath,), shell=True, stdout=subprocess.PIPE) | |
self._linkmaptxt, _ = p.communicate() | |
self.parse() | |
def parse(self): | |
section = "unknown" | |
for line in self._linkmaptxt.split("\n"): | |
m = self._section_re.search(line) | |
if m: | |
section = m.group(1).replace(" ", "_").lower() | |
continue | |
if len(line)>0 and line[0] == "#": | |
continue | |
getattr(self, "parse_"+section)(line) | |
def parse_unknown(self, line): | |
pass | |
def parse_sections(self, line): | |
pass | |
def parse_object_files(self, line): | |
m = self._obj_re.search(line) | |
if not m: | |
return; | |
self._object_files[int(m.group(1))] = m.group(2) | |
def parse_symbols(self, line): | |
m = self._symbol_re.search(line) | |
if not m: | |
return; | |
start = int(m.group(1),0) | |
size = int(m.group(2),0) | |
fileno = int(m.group(3)) | |
filename = (fileno in self._object_files) and self._object_files[fileno] or "Unknown" | |
name = m.group(4) | |
self._symbols[start] = Symbol(name, start, size, filename) | |
def lookup(self, addr): | |
for sym in self._symbols.values(): | |
if addr > sym.start and addr < sym.end: | |
offset = addr - sym.start | |
return (sym, offset) | |
return (Symbol("Unknown", 0, 0, "Unknown"), 0) | |
def main(): | |
if len(sys.argv) < 3: | |
print "usage: " + sys.argv[0] + " <linkmap.txt> <crashlog.log>" | |
return | |
linkmap = LinkMap(sys.argv[1]) | |
crashlog = file(sys.argv[2], "r").read() | |
line_re = re.compile("^(\d+\s+INSERT_BUNDLE_IDENTIFIER_HERE\s+)(0x[\dabcdef]+) (.*)$") | |
for line in crashlog.split("\n"): | |
m = line_re.search(line) | |
if not m: | |
print line | |
continue | |
addr = int(m.group(2), 0) | |
symbol, offset = linkmap.lookup(addr) | |
print line_re.sub(r"\1\2 "+str(symbol)+" + "+str(offset), line) | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment