tools/rb/fix_stack_using_bpsyms.py

changeset 0
6474c204b198
     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),

mercurial