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'I/asanwrapper\.sh.*?(#\S*?) (\S*?) \((.*?)\+(.*?)\)') 24 25 def _ParseAsanLogLine(line): 26 m = re.match(_RE_ASAN, line) 27 if not m: 28 return None 29 return { 30 'library': m.group(3), 31 'pos': m.group(1), 32 'rel_address': '%08x' % int(m.group(4), 16), 33 } 34 35 36 def _FindASanLibraries(): 37 asan_lib_dir = os.path.join(constants.DIR_SOURCE_ROOT, 38 'third_party', 'llvm-build', 39 'Release+Asserts', 'lib') 40 asan_libs = [] 41 for src_dir, _, files in os.walk(asan_lib_dir): 42 asan_libs += [os.path.relpath(os.path.join(src_dir, f)) 43 for f in files 44 if f.endswith('.so')] 45 return asan_libs 46 47 48 def _TranslateLibPath(library, asan_libs): 49 for asan_lib in asan_libs: 50 if os.path.basename(library) == os.path.basename(asan_lib): 51 return '/' + asan_lib 52 return symbol.TranslateLibPath(library) 53 54 55 def _Symbolize(input): 56 asan_libs = _FindASanLibraries() 57 libraries = collections.defaultdict(list) 58 asan_lines = [] 59 for asan_log_line in [a.strip() for a in input]: 60 m = _ParseAsanLogLine(asan_log_line) 61 if m: 62 libraries[m['library']].append(m) 63 asan_lines.append({'raw_log': asan_log_line, 'parsed': m}) 64 65 all_symbols = collections.defaultdict(dict) 66 original_symbols_dir = symbol.SYMBOLS_DIR 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[0], s[1], s[2] 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, args = parser.parse_args() 95 if options.logcat: 96 input = file(options.logcat, 'r') 97 else: 98 input = sys.stdin 99 _Symbolize(input.readlines()) 100 101 102 if __name__ == "__main__": 103 sys.exit(main()) 104