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