1*6777b538SAndroid Build Coastguard Worker#!/usr/bin/env python3 2*6777b538SAndroid Build Coastguard Worker# 3*6777b538SAndroid Build Coastguard Worker# Copyright 2013 The Chromium Authors 4*6777b538SAndroid Build Coastguard Worker# Use of this source code is governed by a BSD-style license that can be 5*6777b538SAndroid Build Coastguard Worker# found in the LICENSE file. 6*6777b538SAndroid Build Coastguard Worker 7*6777b538SAndroid Build Coastguard Worker 8*6777b538SAndroid Build Coastguard Workerimport argparse 9*6777b538SAndroid Build Coastguard Workerimport collections 10*6777b538SAndroid Build Coastguard Workerimport os 11*6777b538SAndroid Build Coastguard Workerimport re 12*6777b538SAndroid Build Coastguard Workerimport sys 13*6777b538SAndroid Build Coastguard Worker 14*6777b538SAndroid Build Coastguard Workerfrom pylib import constants 15*6777b538SAndroid Build Coastguard Workerfrom pylib.constants import host_paths 16*6777b538SAndroid Build Coastguard Worker 17*6777b538SAndroid Build Coastguard Worker# pylint: disable=wrong-import-order 18*6777b538SAndroid Build Coastguard Worker# Uses symbol.py from third_party/android_platform, not python's. 19*6777b538SAndroid Build Coastguard Workerwith host_paths.SysPath( 20*6777b538SAndroid Build Coastguard Worker host_paths.ANDROID_PLATFORM_DEVELOPMENT_SCRIPTS_PATH, 21*6777b538SAndroid Build Coastguard Worker position=0): 22*6777b538SAndroid Build Coastguard Worker import symbol 23*6777b538SAndroid Build Coastguard Worker 24*6777b538SAndroid Build Coastguard Worker 25*6777b538SAndroid Build Coastguard Worker_RE_ASAN = re.compile( 26*6777b538SAndroid Build Coastguard Worker r""" 27*6777b538SAndroid Build Coastguard Worker (?P<prefix>.*?) 28*6777b538SAndroid Build Coastguard Worker (?P<pos>\#\S*?) # position of the call in stack. 29*6777b538SAndroid Build Coastguard Worker # escape the char "#" due to the VERBOSE flag. 30*6777b538SAndroid Build Coastguard Worker \s+(\S*?)\s+ 31*6777b538SAndroid Build Coastguard Worker \( # match the char "(". 32*6777b538SAndroid Build Coastguard Worker (?P<lib>.*?) # library path. 33*6777b538SAndroid Build Coastguard Worker \+0[xX](?P<addr>.*?) # address of the symbol in hex. 34*6777b538SAndroid Build Coastguard Worker # the prefix "0x" is skipped. 35*6777b538SAndroid Build Coastguard Worker \) # match the char ")". 36*6777b538SAndroid Build Coastguard Worker """, re.VERBOSE) 37*6777b538SAndroid Build Coastguard Worker 38*6777b538SAndroid Build Coastguard Worker# This named tuple models a parsed Asan log line. 39*6777b538SAndroid Build Coastguard WorkerAsanParsedLine = collections.namedtuple('AsanParsedLine', 40*6777b538SAndroid Build Coastguard Worker 'prefix,library,pos,rel_address') 41*6777b538SAndroid Build Coastguard Worker 42*6777b538SAndroid Build Coastguard Worker# This named tuple models an Asan log line. 'raw' is the raw content 43*6777b538SAndroid Build Coastguard Worker# while 'parsed' is None or an AsanParsedLine instance. 44*6777b538SAndroid Build Coastguard WorkerAsanLogLine = collections.namedtuple('AsanLogLine', 'raw,parsed') 45*6777b538SAndroid Build Coastguard Worker 46*6777b538SAndroid Build Coastguard Workerdef _ParseAsanLogLine(line): 47*6777b538SAndroid Build Coastguard Worker """Parse line into corresponding AsanParsedLine value, if any, or None.""" 48*6777b538SAndroid Build Coastguard Worker m = re.match(_RE_ASAN, line) 49*6777b538SAndroid Build Coastguard Worker if not m: 50*6777b538SAndroid Build Coastguard Worker return None 51*6777b538SAndroid Build Coastguard Worker return AsanParsedLine(prefix=m.group('prefix'), 52*6777b538SAndroid Build Coastguard Worker library=m.group('lib'), 53*6777b538SAndroid Build Coastguard Worker pos=m.group('pos'), 54*6777b538SAndroid Build Coastguard Worker rel_address=int(m.group('addr'), 16)) 55*6777b538SAndroid Build Coastguard Worker 56*6777b538SAndroid Build Coastguard Worker 57*6777b538SAndroid Build Coastguard Workerdef _FindASanLibraries(): 58*6777b538SAndroid Build Coastguard Worker asan_lib_dir = os.path.join(host_paths.DIR_SOURCE_ROOT, 59*6777b538SAndroid Build Coastguard Worker 'third_party', 'llvm-build', 60*6777b538SAndroid Build Coastguard Worker 'Release+Asserts', 'lib') 61*6777b538SAndroid Build Coastguard Worker asan_libs = [] 62*6777b538SAndroid Build Coastguard Worker for src_dir, _, files in os.walk(asan_lib_dir): 63*6777b538SAndroid Build Coastguard Worker asan_libs += [os.path.relpath(os.path.join(src_dir, f)) 64*6777b538SAndroid Build Coastguard Worker for f in files 65*6777b538SAndroid Build Coastguard Worker if f.endswith('.so')] 66*6777b538SAndroid Build Coastguard Worker return asan_libs 67*6777b538SAndroid Build Coastguard Worker 68*6777b538SAndroid Build Coastguard Worker 69*6777b538SAndroid Build Coastguard Workerdef _TranslateLibPath(library, asan_libs): 70*6777b538SAndroid Build Coastguard Worker for asan_lib in asan_libs: 71*6777b538SAndroid Build Coastguard Worker if os.path.basename(library) == os.path.basename(asan_lib): 72*6777b538SAndroid Build Coastguard Worker return '/' + asan_lib 73*6777b538SAndroid Build Coastguard Worker # pylint: disable=no-member 74*6777b538SAndroid Build Coastguard Worker return symbol.TranslateLibPath(library) 75*6777b538SAndroid Build Coastguard Worker 76*6777b538SAndroid Build Coastguard Worker 77*6777b538SAndroid Build Coastguard Workerdef _PrintSymbolized(asan_input, arch): 78*6777b538SAndroid Build Coastguard Worker """Print symbolized logcat output for Asan symbols. 79*6777b538SAndroid Build Coastguard Worker 80*6777b538SAndroid Build Coastguard Worker Args: 81*6777b538SAndroid Build Coastguard Worker asan_input: list of input lines. 82*6777b538SAndroid Build Coastguard Worker arch: Target CPU architecture. 83*6777b538SAndroid Build Coastguard Worker """ 84*6777b538SAndroid Build Coastguard Worker asan_libs = _FindASanLibraries() 85*6777b538SAndroid Build Coastguard Worker 86*6777b538SAndroid Build Coastguard Worker # Maps library -> [ AsanParsedLine... ] 87*6777b538SAndroid Build Coastguard Worker libraries = collections.defaultdict(list) 88*6777b538SAndroid Build Coastguard Worker 89*6777b538SAndroid Build Coastguard Worker asan_log_lines = [] 90*6777b538SAndroid Build Coastguard Worker for line in asan_input: 91*6777b538SAndroid Build Coastguard Worker line = line.rstrip() 92*6777b538SAndroid Build Coastguard Worker parsed = _ParseAsanLogLine(line) 93*6777b538SAndroid Build Coastguard Worker if parsed: 94*6777b538SAndroid Build Coastguard Worker libraries[parsed.library].append(parsed) 95*6777b538SAndroid Build Coastguard Worker asan_log_lines.append(AsanLogLine(raw=line, parsed=parsed)) 96*6777b538SAndroid Build Coastguard Worker 97*6777b538SAndroid Build Coastguard Worker # Maps library -> { address -> [(symbol, location, obj_sym_with_offset)...] } 98*6777b538SAndroid Build Coastguard Worker all_symbols = collections.defaultdict(dict) 99*6777b538SAndroid Build Coastguard Worker 100*6777b538SAndroid Build Coastguard Worker for library, items in libraries.items(): 101*6777b538SAndroid Build Coastguard Worker libname = _TranslateLibPath(library, asan_libs) 102*6777b538SAndroid Build Coastguard Worker lib_relative_addrs = set(i.rel_address for i in items) 103*6777b538SAndroid Build Coastguard Worker # pylint: disable=no-member 104*6777b538SAndroid Build Coastguard Worker symbols_by_library = symbol.SymbolInformationForSet(libname, 105*6777b538SAndroid Build Coastguard Worker lib_relative_addrs, 106*6777b538SAndroid Build Coastguard Worker True, 107*6777b538SAndroid Build Coastguard Worker cpu_arch=arch) 108*6777b538SAndroid Build Coastguard Worker if symbols_by_library: 109*6777b538SAndroid Build Coastguard Worker all_symbols[library] = symbols_by_library 110*6777b538SAndroid Build Coastguard Worker 111*6777b538SAndroid Build Coastguard Worker for log_line in asan_log_lines: 112*6777b538SAndroid Build Coastguard Worker m = log_line.parsed 113*6777b538SAndroid Build Coastguard Worker if (m and m.library in all_symbols and 114*6777b538SAndroid Build Coastguard Worker m.rel_address in all_symbols[m.library]): 115*6777b538SAndroid Build Coastguard Worker # NOTE: all_symbols[lib][address] is a never-emtpy list of tuples. 116*6777b538SAndroid Build Coastguard Worker # NOTE: The documentation for SymbolInformationForSet() indicates 117*6777b538SAndroid Build Coastguard Worker # that usually one wants to display the last list item, not the first. 118*6777b538SAndroid Build Coastguard Worker # The code below takes the first, is this the best choice here? 119*6777b538SAndroid Build Coastguard Worker s = all_symbols[m.library][m.rel_address][0] 120*6777b538SAndroid Build Coastguard Worker symbol_name = s[0] 121*6777b538SAndroid Build Coastguard Worker symbol_location = s[1] 122*6777b538SAndroid Build Coastguard Worker print('%s%s %s %s @ \'%s\'' % 123*6777b538SAndroid Build Coastguard Worker (m.prefix, m.pos, hex(m.rel_address), symbol_name, symbol_location)) 124*6777b538SAndroid Build Coastguard Worker else: 125*6777b538SAndroid Build Coastguard Worker print(log_line.raw) 126*6777b538SAndroid Build Coastguard Worker 127*6777b538SAndroid Build Coastguard Worker 128*6777b538SAndroid Build Coastguard Workerdef main(): 129*6777b538SAndroid Build Coastguard Worker parser = argparse.ArgumentParser() 130*6777b538SAndroid Build Coastguard Worker parser.add_argument('-l', 131*6777b538SAndroid Build Coastguard Worker '--logcat', 132*6777b538SAndroid Build Coastguard Worker help='File containing adb logcat output with ASan ' 133*6777b538SAndroid Build Coastguard Worker 'stacks. Use stdin if not specified.') 134*6777b538SAndroid Build Coastguard Worker parser.add_argument('--output-directory', 135*6777b538SAndroid Build Coastguard Worker help='Path to the root build directory.') 136*6777b538SAndroid Build Coastguard Worker parser.add_argument('--arch', default='arm', help='CPU architecture name') 137*6777b538SAndroid Build Coastguard Worker args = parser.parse_args() 138*6777b538SAndroid Build Coastguard Worker 139*6777b538SAndroid Build Coastguard Worker if args.output_directory: 140*6777b538SAndroid Build Coastguard Worker constants.SetOutputDirectory(args.output_directory) 141*6777b538SAndroid Build Coastguard Worker # Do an up-front test that the output directory is known. 142*6777b538SAndroid Build Coastguard Worker constants.CheckOutputDirectory() 143*6777b538SAndroid Build Coastguard Worker 144*6777b538SAndroid Build Coastguard Worker if args.logcat: 145*6777b538SAndroid Build Coastguard Worker asan_input = open(args.logcat, 'r') 146*6777b538SAndroid Build Coastguard Worker else: 147*6777b538SAndroid Build Coastguard Worker asan_input = sys.stdin 148*6777b538SAndroid Build Coastguard Worker 149*6777b538SAndroid Build Coastguard Worker _PrintSymbolized(asan_input.readlines(), args.arch) 150*6777b538SAndroid Build Coastguard Worker 151*6777b538SAndroid Build Coastguard Worker 152*6777b538SAndroid Build Coastguard Workerif __name__ == "__main__": 153*6777b538SAndroid Build Coastguard Worker sys.exit(main()) 154