1 #!/usr/bin/env python 2 # 3 # Copyright 2013 The Chromium Authors. All rights reserved. 4 # Use of this source code is governed by a BSD-style license that can be 5 # found in the LICENSE file. 6 7 8 import collections 9 import optparse 10 import os 11 import re 12 import sys 13 14 from pylib import constants 15 16 # Uses symbol.py from third_party/android_platform, not python's. 17 sys.path.insert(0, 18 os.path.join(constants.DIR_SOURCE_ROOT, 19 'third_party/android_platform/development/scripts')) 20 import symbol 21 22 23 _RE_ASAN = re.compile(r'(.*?)(#\S*?) (\S*?) \((.*?)\+(.*?)\)') 24 25 def _ParseAsanLogLine(line): 26 m = re.match(_RE_ASAN, line) 27 if not m: 28 return None 29 return { 30 'prefix': m.group(1), 31 'library': m.group(4), 32 'pos': m.group(2), 33 'rel_address': '%08x' % int(m.group(5), 16), 34 } 35 36 37 def _FindASanLibraries(): 38 asan_lib_dir = os.path.join(constants.DIR_SOURCE_ROOT, 39 'third_party', 'llvm-build', 40 'Release+Asserts', 'lib') 41 asan_libs = [] 42 for src_dir, _, files in os.walk(asan_lib_dir): 43 asan_libs += [os.path.relpath(os.path.join(src_dir, f)) 44 for f in files 45 if f.endswith('.so')] 46 return asan_libs 47 48 49 def _TranslateLibPath(library, asan_libs): 50 for asan_lib in asan_libs: 51 if os.path.basename(library) == os.path.basename(asan_lib): 52 return '/' + asan_lib 53 return symbol.TranslateLibPath(library) 54 55 56 def _Symbolize(asan_input): 57 asan_libs = _FindASanLibraries() 58 libraries = collections.defaultdict(list) 59 asan_lines = [] 60 for asan_log_line in [a.rstrip() for a in asan_input]: 61 m = _ParseAsanLogLine(asan_log_line) 62 if m: 63 libraries[m['library']].append(m) 64 asan_lines.append({'raw_log': asan_log_line, 'parsed': m}) 65 66 all_symbols = collections.defaultdict(dict) 67 for library, items in libraries.iteritems(): 68 libname = _TranslateLibPath(library, asan_libs) 69 lib_relative_addrs = set([i['rel_address'] for i in items]) 70 info_dict = symbol.SymbolInformationForSet(libname, 71 lib_relative_addrs, 72 True) 73 if info_dict: 74 all_symbols[library]['symbols'] = info_dict 75 76 for asan_log_line in asan_lines: 77 m = asan_log_line['parsed'] 78 if not m: 79 print asan_log_line['raw_log'] 80 continue 81 if (m['library'] in all_symbols and 82 m['rel_address'] in all_symbols[m['library']]['symbols']): 83 s = all_symbols[m['library']]['symbols'][m['rel_address']][0] 84 print '%s%s %s %s' % (m['prefix'], m['pos'], s[0], s[1]) 85 else: 86 print asan_log_line['raw_log'] 87 88 89 def main(): 90 parser = optparse.OptionParser() 91 parser.add_option('-l', '--logcat', 92 help='File containing adb logcat output with ASan stacks. ' 93 'Use stdin if not specified.') 94 options, _ = parser.parse_args() 95 if options.logcat: 96 asan_input = file(options.logcat, 'r') 97 else: 98 asan_input = sys.stdin 99 _Symbolize(asan_input.readlines()) 100 101 102 if __name__ == "__main__": 103 sys.exit(main()) 104