forked from mozilla/gecko-dev
-
Notifications
You must be signed in to change notification settings - Fork 2
/
fix_stack_using_bpsyms.py
executable file
·137 lines (124 loc) · 4.6 KB
/
fix_stack_using_bpsyms.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#!/usr/bin/env python
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
# This script uses breakpad symbols to post-process the entries produced by
# NS_FormatCodeAddress(), which on TBPL builds often lack a file name and a
# line number (and on Linux even the symbol is often bad).
from __future__ import with_statement
import sys
import os
import re
import bisect
def prettyFileName(name):
if name.startswith("../") or name.startswith("..\\"):
# dom_quickstubs.cpp and many .h files show up with relative paths that are useless
# and/or don't correspond to the layout of the source tree.
return os.path.basename(name) + ":"
elif name.startswith("hg:"):
bits = name.split(":")
if len(bits) == 4:
(junk, repo, path, rev) = bits
# We could construct an hgweb URL with /file/ or /annotate/, like this:
# return "http://%s/annotate/%s/%s#l" % (repo, rev, path)
return path + ":"
return name + ":"
class SymbolFile:
def __init__(self, fn):
addrs = [] # list of addresses, which will be sorted once we're done initializing
funcs = {} # hash: address --> (function name + possible file/line)
files = {} # hash: filenum (string) --> prettified filename ready to have a line number appended
with open(fn) as f:
for line in f:
line = line.rstrip()
# http://code.google.com/p/google-breakpad/wiki/SymbolFiles
if line.startswith("FUNC "):
# FUNC <address> <size> <stack_param_size> <name>
(junk, rva, size, ss, name) = line.split(None, 4)
rva = int(rva,16)
funcs[rva] = name
addrs.append(rva)
lastFuncName = name
elif line.startswith("PUBLIC "):
# PUBLIC <address> <stack_param_size> <name>
(junk, rva, ss, name) = line.split(None, 3)
rva = int(rva,16)
funcs[rva] = name
addrs.append(rva)
elif line.startswith("FILE "):
# FILE <number> <name>
(junk, filenum, name) = line.split(None, 2)
files[filenum] = prettyFileName(name)
elif line[0] in "0123456789abcdef":
# This is one of the "line records" corresponding to the last FUNC record
# <address> <size> <line> <filenum>
(rva, size, line, filenum) = line.split(None)
rva = int(rva,16)
file = files[filenum]
name = lastFuncName + " [" + file + line + "]"
funcs[rva] = name
addrs.append(rva)
# skip everything else
#print "Loaded %d functions from symbol file %s" % (len(funcs), os.path.basename(fn))
self.addrs = sorted(addrs)
self.funcs = funcs
def addrToSymbol(self, address):
i = bisect.bisect(self.addrs, address) - 1
if i > 0:
#offset = address - self.addrs[i]
return self.funcs[self.addrs[i]]
else:
return ""
def guessSymbolFile(fn, symbolsDir):
"""Guess a symbol file based on an object file's basename, ignoring the path and UUID."""
fn = os.path.basename(fn)
d1 = os.path.join(symbolsDir, fn)
if not os.path.exists(d1):
fn = fn + ".pdb"
d1 = os.path.join(symbolsDir, fn)
if not os.path.exists(d1):
return None
uuids = os.listdir(d1)
if len(uuids) == 0:
raise Exception("Missing symbol file for " + fn)
if len(uuids) > 1:
raise Exception("Ambiguous symbol file for " + fn)
if fn.endswith(".pdb"):
fn = fn[:-4]
return os.path.join(d1, uuids[0], fn + ".sym")
parsedSymbolFiles = {}
def getSymbolFile(file, symbolsDir):
p = None
if not file in parsedSymbolFiles:
symfile = guessSymbolFile(file, symbolsDir)
if symfile:
p = SymbolFile(symfile)
else:
p = None
parsedSymbolFiles[file] = p
else:
p = parsedSymbolFiles[file]
return p
def addressToSymbol(file, address, symbolsDir):
p = getSymbolFile(file, symbolsDir)
if p:
return p.addrToSymbol(address)
else:
return ""
# Matches lines produced by NS_FormatCodeAddress().
line_re = re.compile("^(.*#\d+: )(.+)\[(.+) \+(0x[0-9A-Fa-f]+)\](.*)$")
def fixSymbols(line, symbolsDir):
result = line_re.match(line)
if result is not None:
(before, fn, file, address, after) = result.groups()
address = int(address, 16)
symbol = addressToSymbol(file, address, symbolsDir)
if not symbol:
symbol = "%s + 0x%x" % (os.path.basename(file), address)
return before + symbol + after + "\n"
else:
return line
if __name__ == "__main__":
symbolsDir = sys.argv[1]
for line in iter(sys.stdin.readline, ''):
print fixSymbols(line, symbolsDir),