Updated script asan_symbolize.py.

--HG--
branch : develop
This commit is contained in:
Roman Telezhynskyi 2016-05-26 16:51:06 +03:00
parent ce720450f0
commit 2e25a12b91

View File

@ -11,11 +11,9 @@ import argparse
import bisect import bisect
import getopt import getopt
import os import os
import pty
import re import re
import subprocess import subprocess
import sys import sys
import termios
symbolizers = {} symbolizers = {}
DEBUG = False DEBUG = False
@ -25,6 +23,7 @@ sysroot_path = None
binary_name_filter = None binary_name_filter = None
fix_filename_patterns = None fix_filename_patterns = None
logfile = sys.stdin logfile = sys.stdin
allow_system_symbolizer = True
# FIXME: merge the code that calls fix_filename(). # FIXME: merge the code that calls fix_filename().
def fix_filename(file_name): def fix_filename(file_name):
@ -78,7 +77,7 @@ class LLVMSymbolizer(Symbolizer):
cmd = [self.symbolizer_path, cmd = [self.symbolizer_path,
'--use-symbol-table=true', '--use-symbol-table=true',
'--demangle=%s' % demangle, '--demangle=%s' % demangle,
'--functions=short', '--functions=linkage',
'--inlining=true', '--inlining=true',
'--default-arch=%s' % self.default_arch] '--default-arch=%s' % self.default_arch]
if self.system == 'Darwin': if self.system == 'Darwin':
@ -136,12 +135,13 @@ class Addr2LineSymbolizer(Symbolizer):
super(Addr2LineSymbolizer, self).__init__() super(Addr2LineSymbolizer, self).__init__()
self.binary = binary self.binary = binary
self.pipe = self.open_addr2line() self.pipe = self.open_addr2line()
self.output_terminator = -1
def open_addr2line(self): def open_addr2line(self):
addr2line_tool = 'addr2line' addr2line_tool = 'addr2line'
if binutils_prefix: if binutils_prefix:
addr2line_tool = binutils_prefix + addr2line_tool addr2line_tool = binutils_prefix + addr2line_tool
cmd = [addr2line_tool, '-f'] cmd = [addr2line_tool, '-fi']
if demangle: if demangle:
cmd += ['--demangle'] cmd += ['--demangle']
cmd += ['-e', self.binary] cmd += ['-e', self.binary]
@ -154,16 +154,23 @@ class Addr2LineSymbolizer(Symbolizer):
"""Overrides Symbolizer.symbolize.""" """Overrides Symbolizer.symbolize."""
if self.binary != binary: if self.binary != binary:
return None return None
lines = []
try: try:
print >> self.pipe.stdin, offset print >> self.pipe.stdin, offset
print >> self.pipe.stdin, self.output_terminator
is_first_frame = True
while True:
function_name = self.pipe.stdout.readline().rstrip() function_name = self.pipe.stdout.readline().rstrip()
file_name = self.pipe.stdout.readline().rstrip() file_name = self.pipe.stdout.readline().rstrip()
if is_first_frame:
is_first_frame = False
elif function_name in ['', '??']:
assert file_name == function_name
break
lines.append((function_name, file_name));
except Exception: except Exception:
function_name = '' lines.append(('??', '??:0'))
file_name = '' return ['%s in %s %s' % (addr, function, fix_filename(file)) for (function, file) in lines]
file_name = fix_filename(file_name)
return ['%s in %s %s' % (addr, function_name, file_name)]
class UnbufferedLineConverter(object): class UnbufferedLineConverter(object):
""" """
@ -171,6 +178,9 @@ class UnbufferedLineConverter(object):
output. Uses pty to trick the child into providing unbuffered output. output. Uses pty to trick the child into providing unbuffered output.
""" """
def __init__(self, args, close_stderr=False): def __init__(self, args, close_stderr=False):
# Local imports so that the script can start on Windows.
import pty
import termios
pid, fd = pty.fork() pid, fd = pty.fork()
if pid == 0: if pid == 0:
# We're the child. Transfer control to command. # We're the child. Transfer control to command.
@ -261,7 +271,7 @@ def BreakpadSymbolizerFactory(binary):
def SystemSymbolizerFactory(system, addr, binary): def SystemSymbolizerFactory(system, addr, binary):
if system == 'Darwin': if system == 'Darwin':
return DarwinSymbolizer(addr, binary) return DarwinSymbolizer(addr, binary)
elif system == 'Linux': elif system == 'Linux' or system == 'FreeBSD':
return Addr2LineSymbolizer(binary) return Addr2LineSymbolizer(binary)
@ -341,6 +351,11 @@ class BreakpadSymbolizer(Symbolizer):
class SymbolizationLoop(object): class SymbolizationLoop(object):
def __init__(self, binary_name_filter=None, dsym_hint_producer=None): def __init__(self, binary_name_filter=None, dsym_hint_producer=None):
if sys.platform == 'win32':
# ASan on Windows uses dbghelp.dll to symbolize in-process, which works
# even in sandboxed processes. Nothing needs to be done here.
self.process_line = self.process_line_echo
else:
# Used by clients who may want to supply a different binary name. # Used by clients who may want to supply a different binary name.
# E.g. in Chrome several binaries may share a single .dSYM. # E.g. in Chrome several binaries may share a single .dSYM.
self.binary_name_filter = binary_name_filter self.binary_name_filter = binary_name_filter
@ -352,6 +367,7 @@ class SymbolizationLoop(object):
self.last_llvm_symbolizer = None self.last_llvm_symbolizer = None
self.dsym_hints = set([]) self.dsym_hints = set([])
self.frame_no = 0 self.frame_no = 0
self.process_line = self.process_line_posix
def symbolize_address(self, addr, binary, offset): def symbolize_address(self, addr, binary, offset):
# On non-Darwin (i.e. on platforms without .dSYM debug info) always use # On non-Darwin (i.e. on platforms without .dSYM debug info) always use
@ -385,6 +401,8 @@ class SymbolizationLoop(object):
[BreakpadSymbolizerFactory(binary), self.llvm_symbolizers[binary]]) [BreakpadSymbolizerFactory(binary), self.llvm_symbolizers[binary]])
result = symbolizers[binary].symbolize(addr, binary, offset) result = symbolizers[binary].symbolize(addr, binary, offset)
if result is None: if result is None:
if not allow_system_symbolizer:
raise Exception('Failed to launch or use llvm-symbolizer.')
# Initialize system symbolizer only if other symbolizers failed. # Initialize system symbolizer only if other symbolizers failed.
symbolizers[binary].append_symbolizer( symbolizers[binary].append_symbolizer(
SystemSymbolizerFactory(self.system, addr, binary)) SystemSymbolizerFactory(self.system, addr, binary))
@ -405,14 +423,14 @@ class SymbolizationLoop(object):
def process_logfile(self): def process_logfile(self):
self.frame_no = 0 self.frame_no = 0
while True: for line in logfile:
line = logfile.readline()
if not line:
break
processed = self.process_line(line) processed = self.process_line(line)
print '\n'.join(processed) print '\n'.join(processed)
def process_line(self, line): def process_line_echo(self, line):
return [line.rstrip()]
def process_line_posix(self, line):
self.current_line = line.rstrip() self.current_line = line.rstrip()
#0 0x7f6e35cf2e45 (/blah/foo.so+0x11fe45) #0 0x7f6e35cf2e45 (/blah/foo.so+0x11fe45)
stack_trace_line_format = ( stack_trace_line_format = (
@ -437,10 +455,12 @@ class SymbolizationLoop(object):
if __name__ == '__main__': if __name__ == '__main__':
parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter, parser = argparse.ArgumentParser(
formatter_class=argparse.RawDescriptionHelpFormatter,
description='ASan symbolization script', description='ASan symbolization script',
epilog='''Example of use: epilog='Example of use:\n'
asan_symbolize.py -c "$HOME/opt/cross/bin/arm-linux-gnueabi-" -s "$HOME/SymbolFiles" < asan.log''') 'asan_symbolize.py -c "$HOME/opt/cross/bin/arm-linux-gnueabi-" '
'-s "$HOME/SymbolFiles" < asan.log')
parser.add_argument('path_to_cut', nargs='*', parser.add_argument('path_to_cut', nargs='*',
help='pattern to be cut from the result file path ') help='pattern to be cut from the result file path ')
parser.add_argument('-d','--demangle', action='store_true', parser.add_argument('-d','--demangle', action='store_true',
@ -449,7 +469,8 @@ if __name__ == '__main__':
help='set path to sysroot for sanitized binaries') help='set path to sysroot for sanitized binaries')
parser.add_argument('-c', metavar='CROSS_COMPILE', parser.add_argument('-c', metavar='CROSS_COMPILE',
help='set prefix for binutils') help='set prefix for binutils')
parser.add_argument('-l','--logfile', default=sys.stdin, type=argparse.FileType('r'), parser.add_argument('-l','--logfile', default=sys.stdin,
type=argparse.FileType('r'),
help='set log file name to parse, default is stdin') help='set log file name to parse, default is stdin')
args = parser.parse_args() args = parser.parse_args()
if args.path_to_cut: if args.path_to_cut: