Skip to content

Instantly share code, notes, and snippets.

@nevyn
Created August 26, 2010 08:27
Show Gist options
  • Save nevyn/551067 to your computer and use it in GitHub Desktop.
Save nevyn/551067 to your computer and use it in GitHub Desktop.
LinkMap symbolicator

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.

#!/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