1#!/usr/bin/python 2# vim:sw=4:ts=4:et: 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/. 6 7# This script uses `fix-stacks` to post-process the entries produced by 8# MozFormatCodeAddress(). 9 10from __future__ import absolute_import, print_function 11from subprocess import Popen, PIPE 12import atexit 13import os 14import platform 15import re 16import sys 17 18# Matches lines produced by MozFormatCodeAddress(), e.g. 19# `#01: ???[tests/example +0x43a0]`. 20line_re = re.compile("#\d+: .+\[.+ \+0x[0-9A-Fa-f]+\]") 21 22fix_stacks = None 23 24 25def fixSymbols(line, jsonMode=False, slowWarning=False, breakpadSymsDir=None, hide_errors=False): 26 global fix_stacks 27 28 result = line_re.search(line) 29 if result is None: 30 return line 31 32 if not fix_stacks: 33 # Look in MOZ_FETCHES_DIR (for automation), then in MOZBUILD_STATE_PATH 34 # (for a local build where the user has that set), then in ~/.mozbuild 35 # (for a local build with default settings). 36 base = os.environ.get( 37 'MOZ_FETCHES_DIR', 38 os.environ.get( 39 'MOZBUILD_STATE_PATH', 40 os.path.expanduser('~/.mozbuild') 41 ) 42 ) 43 fix_stacks_exe = base + '/fix-stacks/fix-stacks' 44 if platform.system() == 'Windows': 45 fix_stacks_exe = fix_stacks_exe + '.exe' 46 47 if not (os.path.isfile(fix_stacks_exe) and os.access(fix_stacks_exe, os.X_OK)): 48 raise Exception('cannot find `fix-stacks`; please run `./mach bootstrap`') 49 50 args = [fix_stacks_exe] 51 if jsonMode: 52 args.append('-j') 53 if breakpadSymsDir: 54 # `fileid` should be packaged next to `fix_stacks.py`. 55 here = os.path.dirname(__file__) 56 fileid_exe = os.path.join(here, 'fileid') 57 if platform.system() == 'Windows': 58 fileid_exe = fileid_exe + '.exe' 59 60 args.append('-b') 61 args.append(breakpadSymsDir + "," + fileid_exe) 62 63 # Sometimes we need to prevent errors from going to stderr. 64 stderr = open(os.devnull) if hide_errors else None 65 66 fix_stacks = Popen(args, stdin=PIPE, stdout=PIPE, stderr=stderr) 67 68 # Shut down the fix_stacks process on exit. We use `terminate()` 69 # because it is more forceful than `wait()`, and the Python docs warn 70 # about possible deadlocks with `wait()`. 71 def cleanup(fix_stacks): 72 fix_stacks.stdin.close() 73 fix_stacks.terminate() 74 atexit.register(cleanup, fix_stacks) 75 76 if slowWarning: 77 print("Initializing stack-fixing for the first stack frame, this may take a while...") 78 79 # Sometimes `line` is lacking a trailing newline. If we pass such a `line` 80 # to `fix-stacks` it will wait until it receives a newline, causing this 81 # script to hang. So we add a newline if one is missing and then remove it 82 # from the output. 83 is_missing_newline = not line.endswith('\n') 84 if is_missing_newline: 85 line = line + "\n" 86 fix_stacks.stdin.write(line) 87 fix_stacks.stdin.flush() 88 out = fix_stacks.stdout.readline() 89 if is_missing_newline: 90 out = out[:-1] 91 return out 92 93 94if __name__ == "__main__": 95 for line in sys.stdin: 96 sys.stdout.write(fixSymbols(line)) 97