tools/rb/fix_stack_using_bpsyms.py

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rwxr-xr-x

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

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

mercurial