1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/tools/rb/fix_stack_using_bpsyms.py Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,137 @@ 1.4 +#!/usr/bin/env python 1.5 + 1.6 +# This Source Code Form is subject to the terms of the Mozilla Public 1.7 +# License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 +# file, You can obtain one at http://mozilla.org/MPL/2.0/. 1.9 + 1.10 +from __future__ import with_statement 1.11 + 1.12 +import sys 1.13 +import os 1.14 +import re 1.15 +import bisect 1.16 + 1.17 +def prettyFileName(name): 1.18 + if name.startswith("../") or name.startswith("..\\"): 1.19 + # dom_quickstubs.cpp and many .h files show up with relative paths that are useless 1.20 + # and/or don't correspond to the layout of the source tree. 1.21 + return os.path.basename(name) + ":" 1.22 + elif name.startswith("hg:"): 1.23 + bits = name.split(":") 1.24 + if len(bits) == 4: 1.25 + (junk, repo, path, rev) = bits 1.26 + # We could construct an hgweb URL with /file/ or /annotate/, like this: 1.27 + # return "http://%s/annotate/%s/%s#l" % (repo, rev, path) 1.28 + return path + ":" 1.29 + return name + ":" 1.30 + 1.31 +class SymbolFile: 1.32 + def __init__(self, fn): 1.33 + addrs = [] # list of addresses, which will be sorted once we're done initializing 1.34 + funcs = {} # hash: address --> (function name + possible file/line) 1.35 + files = {} # hash: filenum (string) --> prettified filename ready to have a line number appended 1.36 + with open(fn) as f: 1.37 + for line in f: 1.38 + line = line.rstrip() 1.39 + # http://code.google.com/p/google-breakpad/wiki/SymbolFiles 1.40 + if line.startswith("FUNC "): 1.41 + # FUNC <address> <size> <stack_param_size> <name> 1.42 + (junk, rva, size, ss, name) = line.split(None, 4) 1.43 + rva = int(rva,16) 1.44 + funcs[rva] = name 1.45 + addrs.append(rva) 1.46 + lastFuncName = name 1.47 + elif line.startswith("PUBLIC "): 1.48 + # PUBLIC <address> <stack_param_size> <name> 1.49 + (junk, rva, ss, name) = line.split(None, 3) 1.50 + rva = int(rva,16) 1.51 + funcs[rva] = name 1.52 + addrs.append(rva) 1.53 + elif line.startswith("FILE "): 1.54 + # FILE <number> <name> 1.55 + (junk, filenum, name) = line.split(None, 2) 1.56 + files[filenum] = prettyFileName(name) 1.57 + elif line[0] in "0123456789abcdef": 1.58 + # This is one of the "line records" corresponding to the last FUNC record 1.59 + # <address> <size> <line> <filenum> 1.60 + (rva, size, line, filenum) = line.split(None) 1.61 + rva = int(rva,16) 1.62 + file = files[filenum] 1.63 + name = lastFuncName + " [" + file + line + "]" 1.64 + funcs[rva] = name 1.65 + addrs.append(rva) 1.66 + # skip everything else 1.67 + #print "Loaded %d functions from symbol file %s" % (len(funcs), os.path.basename(fn)) 1.68 + self.addrs = sorted(addrs) 1.69 + self.funcs = funcs 1.70 + 1.71 + def addrToSymbol(self, address): 1.72 + i = bisect.bisect(self.addrs, address) - 1 1.73 + if i > 0: 1.74 + #offset = address - self.addrs[i] 1.75 + return self.funcs[self.addrs[i]] 1.76 + else: 1.77 + return "" 1.78 + 1.79 +def guessSymbolFile(fn, symbolsDir): 1.80 + """Guess a symbol file based on an object file's basename, ignoring the path and UUID.""" 1.81 + fn = os.path.basename(fn) 1.82 + d1 = os.path.join(symbolsDir, fn) 1.83 + if not os.path.exists(d1): 1.84 + fn = fn + ".pdb" 1.85 + d1 = os.path.join(symbolsDir, fn) 1.86 + if not os.path.exists(d1): 1.87 + return None 1.88 + uuids = os.listdir(d1) 1.89 + if len(uuids) == 0: 1.90 + raise Exception("Missing symbol file for " + fn) 1.91 + if len(uuids) > 1: 1.92 + raise Exception("Ambiguous symbol file for " + fn) 1.93 + if fn.endswith(".pdb"): 1.94 + fn = fn[:-4] 1.95 + return os.path.join(d1, uuids[0], fn + ".sym") 1.96 + 1.97 +parsedSymbolFiles = {} 1.98 +def getSymbolFile(file, symbolsDir): 1.99 + p = None 1.100 + if not file in parsedSymbolFiles: 1.101 + symfile = guessSymbolFile(file, symbolsDir) 1.102 + if symfile: 1.103 + p = SymbolFile(symfile) 1.104 + else: 1.105 + p = None 1.106 + parsedSymbolFiles[file] = p 1.107 + else: 1.108 + p = parsedSymbolFiles[file] 1.109 + return p 1.110 + 1.111 +def addressToSymbol(file, address, symbolsDir): 1.112 + p = getSymbolFile(file, symbolsDir) 1.113 + if p: 1.114 + return p.addrToSymbol(address) 1.115 + else: 1.116 + return "" 1.117 + 1.118 +line_re = re.compile("^(.*) ?\[([^ ]*) \+(0x[0-9A-F]{1,16})\](.*)$") 1.119 +balance_tree_re = re.compile("^([ \|0-9-]*)") 1.120 + 1.121 +def fixSymbols(line, symbolsDir): 1.122 + result = line_re.match(line) 1.123 + if result is not None: 1.124 + # before allows preservation of balance trees 1.125 + # after allows preservation of counts 1.126 + (before, file, address, after) = result.groups() 1.127 + address = int(address, 16) 1.128 + # throw away the bad symbol, but keep balance tree structure 1.129 + before = balance_tree_re.match(before).groups()[0] 1.130 + symbol = addressToSymbol(file, address, symbolsDir) 1.131 + if not symbol: 1.132 + symbol = "%s + 0x%x" % (os.path.basename(file), address) 1.133 + return before + symbol + after + "\n" 1.134 + else: 1.135 + return line 1.136 + 1.137 +if __name__ == "__main__": 1.138 + symbolsDir = sys.argv[1] 1.139 + for line in iter(sys.stdin.readline, ''): 1.140 + print fixSymbols(line, symbolsDir),