Index: tools/valgrind/asan/third_party/asan_symbolize.py |
diff --git a/tools/valgrind/asan/third_party/asan_symbolize.py b/tools/valgrind/asan/third_party/asan_symbolize.py |
index 59fceaaed814c031fc08ea301f146cfe862a3e8a..1a56e44127c1e507eb31f6cd1df573183adf14e0 100755 |
--- a/tools/valgrind/asan/third_party/asan_symbolize.py |
+++ b/tools/valgrind/asan/third_party/asan_symbolize.py |
@@ -23,6 +23,8 @@ sysroot_path = None |
binary_name_filter = None |
fix_filename_patterns = None |
logfile = sys.stdin |
+allow_system_symbolizer = True |
+force_system_symbolizer = False |
# FIXME: merge the code that calls fix_filename(). |
def fix_filename(file_name): |
@@ -36,6 +38,10 @@ def fix_filename(file_name): |
def sysroot_path_filter(binary_name): |
return sysroot_path + binary_name |
+def is_valid_arch(s): |
+ return s in ["i386", "x86_64", "x86_64h", "arm", "armv6", "armv7", "armv7s", |
+ "armv7k", "arm64", "powerpc64", "powerpc64le", "s390x", "s390"] |
+ |
def guess_arch(addr): |
# Guess which arch we're running. 10 = len('0x') + 8 hex digits. |
if len(addr) > 10: |
@@ -76,17 +82,19 @@ class LLVMSymbolizer(Symbolizer): |
cmd = [self.symbolizer_path, |
'--use-symbol-table=true', |
'--demangle=%s' % demangle, |
- '--functions=short', |
+ '--functions=linkage', |
'--inlining=true', |
'--default-arch=%s' % self.default_arch] |
if self.system == 'Darwin': |
for hint in self.dsym_hints: |
cmd.append('--dsym-hint=%s' % hint) |
if DEBUG: |
- print ' '.join(cmd) |
+ print(' '.join(cmd)) |
try: |
result = subprocess.Popen(cmd, stdin=subprocess.PIPE, |
- stdout=subprocess.PIPE) |
+ stdout=subprocess.PIPE, |
+ bufsize=0, |
+ universal_newlines=True) |
except OSError: |
result = None |
return result |
@@ -99,8 +107,8 @@ class LLVMSymbolizer(Symbolizer): |
try: |
symbolizer_input = '"%s" %s' % (binary, offset) |
if DEBUG: |
- print symbolizer_input |
- print >> self.pipe.stdin, symbolizer_input |
+ print(symbolizer_input) |
+ self.pipe.stdin.write("%s\n" % symbolizer_input) |
while True: |
function_name = self.pipe.stdout.readline().rstrip() |
if not function_name: |
@@ -134,34 +142,44 @@ class Addr2LineSymbolizer(Symbolizer): |
super(Addr2LineSymbolizer, self).__init__() |
self.binary = binary |
self.pipe = self.open_addr2line() |
+ self.output_terminator = -1 |
def open_addr2line(self): |
addr2line_tool = 'addr2line' |
if binutils_prefix: |
addr2line_tool = binutils_prefix + addr2line_tool |
- cmd = [addr2line_tool, '-f'] |
+ cmd = [addr2line_tool, '-fi'] |
if demangle: |
cmd += ['--demangle'] |
cmd += ['-e', self.binary] |
if DEBUG: |
- print ' '.join(cmd) |
+ print(' '.join(cmd)) |
return subprocess.Popen(cmd, |
- stdin=subprocess.PIPE, stdout=subprocess.PIPE) |
+ stdin=subprocess.PIPE, stdout=subprocess.PIPE, |
+ bufsize=0, |
+ universal_newlines=True) |
def symbolize(self, addr, binary, offset): |
"""Overrides Symbolizer.symbolize.""" |
if self.binary != binary: |
return None |
+ lines = [] |
try: |
- print >> self.pipe.stdin, offset |
- function_name = self.pipe.stdout.readline().rstrip() |
- file_name = self.pipe.stdout.readline().rstrip() |
+ self.pipe.stdin.write("%s\n" % offset) |
+ self.pipe.stdin.write("%s\n" % self.output_terminator) |
+ is_first_frame = True |
+ while True: |
+ function_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: |
- function_name = '' |
- file_name = '' |
- file_name = fix_filename(file_name) |
- return ['%s in %s %s' % (addr, function_name, file_name)] |
- |
+ lines.append(('??', '??:0')) |
+ return ['%s in %s %s' % (addr, function, fix_filename(file)) for (function, file) in lines] |
class UnbufferedLineConverter(object): |
""" |
@@ -197,15 +215,15 @@ class UnbufferedLineConverter(object): |
class DarwinSymbolizer(Symbolizer): |
- def __init__(self, addr, binary): |
+ def __init__(self, addr, binary, arch): |
super(DarwinSymbolizer, self).__init__() |
self.binary = binary |
- self.arch = guess_arch(addr) |
+ self.arch = arch |
self.open_atos() |
def open_atos(self): |
if DEBUG: |
- print 'atos -o %s -arch %s' % (self.binary, self.arch) |
+ print('atos -o %s -arch %s' % (self.binary, self.arch)) |
cmdline = ['atos', '-o', self.binary, '-arch', self.arch] |
self.atos = UnbufferedLineConverter(cmdline, close_stderr=True) |
@@ -220,7 +238,7 @@ class DarwinSymbolizer(Symbolizer): |
# foo(type1, type2) (in object.name) (filename.cc:80) |
match = re.match('^(.*) \(in (.*)\) \((.*:\d*)\)$', atos_line) |
if DEBUG: |
- print 'atos_line: ', atos_line |
+ print('atos_line: ', atos_line) |
if match: |
function_name = match.group(1) |
function_name = re.sub('\(.*?\)', '', function_name) |
@@ -259,10 +277,10 @@ def BreakpadSymbolizerFactory(binary): |
return None |
-def SystemSymbolizerFactory(system, addr, binary): |
+def SystemSymbolizerFactory(system, addr, binary, arch): |
if system == 'Darwin': |
- return DarwinSymbolizer(addr, binary) |
- elif system == 'Linux': |
+ return DarwinSymbolizer(addr, binary, arch) |
+ elif system == 'Linux' or system == 'FreeBSD': |
return Addr2LineSymbolizer(binary) |
@@ -334,7 +352,7 @@ class BreakpadSymbolizer(Symbolizer): |
function_name, file_name, line_no = res |
result = ['%s in %s %s:%d' % ( |
addr, function_name, file_name, line_no)] |
- print result |
+ print(result) |
return result |
else: |
return None |
@@ -360,7 +378,7 @@ class SymbolizationLoop(object): |
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, arch): |
# On non-Darwin (i.e. on platforms without .dSYM debug info) always use |
# a single symbolizer binary. |
# On Darwin, if the dsym hint producer is present: |
@@ -372,29 +390,35 @@ class SymbolizationLoop(object): |
# if so, reuse |last_llvm_symbolizer| which has the full set of hints; |
# 3. otherwise create a new symbolizer and pass all currently known |
# .dSYM hints to it. |
- if not binary in self.llvm_symbolizers: |
- use_new_symbolizer = True |
- if self.system == 'Darwin' and self.dsym_hint_producer: |
- dsym_hints_for_binary = set(self.dsym_hint_producer(binary)) |
- use_new_symbolizer = bool(dsym_hints_for_binary - self.dsym_hints) |
- self.dsym_hints |= dsym_hints_for_binary |
- if self.last_llvm_symbolizer and not use_new_symbolizer: |
+ result = None |
+ if not force_system_symbolizer: |
+ if not binary in self.llvm_symbolizers: |
+ use_new_symbolizer = True |
+ if self.system == 'Darwin' and self.dsym_hint_producer: |
+ dsym_hints_for_binary = set(self.dsym_hint_producer(binary)) |
+ use_new_symbolizer = bool(dsym_hints_for_binary - self.dsym_hints) |
+ self.dsym_hints |= dsym_hints_for_binary |
+ if self.last_llvm_symbolizer and not use_new_symbolizer: |
+ self.llvm_symbolizers[binary] = self.last_llvm_symbolizer |
+ else: |
+ self.last_llvm_symbolizer = LLVMSymbolizerFactory( |
+ self.system, arch, self.dsym_hints) |
self.llvm_symbolizers[binary] = self.last_llvm_symbolizer |
- else: |
- self.last_llvm_symbolizer = LLVMSymbolizerFactory( |
- self.system, guess_arch(addr), self.dsym_hints) |
- self.llvm_symbolizers[binary] = self.last_llvm_symbolizer |
- # Use the chain of symbolizers: |
- # Breakpad symbolizer -> LLVM symbolizer -> addr2line/atos |
- # (fall back to next symbolizer if the previous one fails). |
- if not binary in symbolizers: |
- symbolizers[binary] = ChainSymbolizer( |
- [BreakpadSymbolizerFactory(binary), self.llvm_symbolizers[binary]]) |
- result = symbolizers[binary].symbolize(addr, binary, offset) |
+ # Use the chain of symbolizers: |
+ # Breakpad symbolizer -> LLVM symbolizer -> addr2line/atos |
+ # (fall back to next symbolizer if the previous one fails). |
+ if not binary in symbolizers: |
+ symbolizers[binary] = ChainSymbolizer( |
+ [BreakpadSymbolizerFactory(binary), self.llvm_symbolizers[binary]]) |
+ result = symbolizers[binary].symbolize(addr, binary, offset) |
+ else: |
+ symbolizers[binary] = ChainSymbolizer([]) |
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. |
symbolizers[binary].append_symbolizer( |
- SystemSymbolizerFactory(self.system, addr, binary)) |
+ SystemSymbolizerFactory(self.system, addr, binary, arch)) |
result = symbolizers[binary].symbolize(addr, binary, offset) |
# The system symbolizer must produce some result. |
assert result |
@@ -414,7 +438,7 @@ class SymbolizationLoop(object): |
self.frame_no = 0 |
for line in logfile: |
processed = self.process_line(line) |
- print '\n'.join(processed) |
+ print('\n'.join(processed)) |
def process_line_echo(self, line): |
return [line.rstrip()] |
@@ -428,18 +452,28 @@ class SymbolizationLoop(object): |
if not match: |
return [self.current_line] |
if DEBUG: |
- print line |
+ print(line) |
_, frameno_str, addr, binary, offset = match.groups() |
+ arch = "" |
+ # Arch can be embedded in the filename, e.g.: "libabc.dylib:x86_64h" |
+ colon_pos = binary.rfind(":") |
+ if colon_pos != -1: |
+ maybe_arch = binary[colon_pos+1:] |
+ if is_valid_arch(maybe_arch): |
+ arch = maybe_arch |
+ binary = binary[0:colon_pos] |
+ if arch == "": |
+ arch = guess_arch(addr) |
if frameno_str == '0': |
# Assume that frame #0 is the first frame of new stack trace. |
self.frame_no = 0 |
original_binary = binary |
if self.binary_name_filter: |
binary = self.binary_name_filter(binary) |
- symbolized_line = self.symbolize_address(addr, binary, offset) |
+ symbolized_line = self.symbolize_address(addr, binary, offset, arch) |
if not symbolized_line: |
if original_binary != binary: |
- symbolized_line = self.symbolize_address(addr, binary, offset) |
+ symbolized_line = self.symbolize_address(addr, binary, offset, arch) |
return self.get_symbolized_lines(symbolized_line) |
@@ -461,6 +495,8 @@ if __name__ == '__main__': |
parser.add_argument('-l','--logfile', default=sys.stdin, |
type=argparse.FileType('r'), |
help='set log file name to parse, default is stdin') |
+ parser.add_argument('--force-system-symbolizer', action='store_true', |
+ help='don\'t use llvm-symbolizer') |
args = parser.parse_args() |
if args.path_to_cut: |
fix_filename_patterns = args.path_to_cut |
@@ -475,5 +511,9 @@ if __name__ == '__main__': |
logfile = args.logfile |
else: |
logfile = sys.stdin |
+ if args.force_system_symbolizer: |
+ force_system_symbolizer = True |
+ if force_system_symbolizer: |
+ assert(allow_system_symbolizer) |
loop = SymbolizationLoop(binary_name_filter) |
loop.process_logfile() |