1*7c3d14c8STreehugger Robot#!/usr/bin/env python 2*7c3d14c8STreehugger Robot#===- lib/asan/scripts/asan_symbolize.py -----------------------------------===# 3*7c3d14c8STreehugger Robot# 4*7c3d14c8STreehugger Robot# The LLVM Compiler Infrastructure 5*7c3d14c8STreehugger Robot# 6*7c3d14c8STreehugger Robot# This file is distributed under the University of Illinois Open Source 7*7c3d14c8STreehugger Robot# License. See LICENSE.TXT for details. 8*7c3d14c8STreehugger Robot# 9*7c3d14c8STreehugger Robot#===------------------------------------------------------------------------===# 10*7c3d14c8STreehugger Robotimport glob 11*7c3d14c8STreehugger Robotimport os 12*7c3d14c8STreehugger Robotimport re 13*7c3d14c8STreehugger Robotimport sys 14*7c3d14c8STreehugger Robotimport string 15*7c3d14c8STreehugger Robotimport subprocess 16*7c3d14c8STreehugger Robot 17*7c3d14c8STreehugger Robotpipes = {} 18*7c3d14c8STreehugger Robotnext_inline_frameno = 0 19*7c3d14c8STreehugger Robot 20*7c3d14c8STreehugger Robotdef patch_address(frameno, addr_s): 21*7c3d14c8STreehugger Robot ''' Subtracts 1 or 2 from the top frame's address. 22*7c3d14c8STreehugger Robot Top frame is normally the return address from asan_report* 23*7c3d14c8STreehugger Robot call, which is not expected to return at all. Because of that, this 24*7c3d14c8STreehugger Robot address often belongs to the next source code line, or even to a different 25*7c3d14c8STreehugger Robot function. ''' 26*7c3d14c8STreehugger Robot if frameno == '0': 27*7c3d14c8STreehugger Robot addr = int(addr_s, 16) 28*7c3d14c8STreehugger Robot if os.uname()[4].startswith('arm'): 29*7c3d14c8STreehugger Robot # Cancel the Thumb bit 30*7c3d14c8STreehugger Robot addr = addr & (~1) 31*7c3d14c8STreehugger Robot addr -= 1 32*7c3d14c8STreehugger Robot return hex(addr) 33*7c3d14c8STreehugger Robot return addr_s 34*7c3d14c8STreehugger Robot 35*7c3d14c8STreehugger Robotdef postprocess_file_name(file_name, paths_to_cut): 36*7c3d14c8STreehugger Robot for path_to_cut in paths_to_cut: 37*7c3d14c8STreehugger Robot file_name = re.sub(".*" + path_to_cut, "", file_name) 38*7c3d14c8STreehugger Robot file_name = re.sub(".*asan_[a-z_]*.(cc|h):[0-9]*", "[asan_rtl]", file_name) 39*7c3d14c8STreehugger Robot file_name = re.sub(".*crtstuff.c:0", "???:0", file_name) 40*7c3d14c8STreehugger Robot return file_name 41*7c3d14c8STreehugger Robot 42*7c3d14c8STreehugger Robot# TODO(glider): need some refactoring here 43*7c3d14c8STreehugger Robotdef symbolize_addr2line(line, binary_prefix, paths_to_cut): 44*7c3d14c8STreehugger Robot global next_inline_frameno 45*7c3d14c8STreehugger Robot # Strip the log prefix ("I/asanwrapper( 1196): "). 46*7c3d14c8STreehugger Robot line = re.sub(r'^.*?: ', '', line) 47*7c3d14c8STreehugger Robot #0 0x7f6e35cf2e45 (/blah/foo.so+0x11fe45) 48*7c3d14c8STreehugger Robot match = re.match(r'^(\s*#)([0-9]+) *(0x[0-9a-f]+) *\((.*)\+(0x[0-9a-f]+)\)', line, re.UNICODE) 49*7c3d14c8STreehugger Robot if match: 50*7c3d14c8STreehugger Robot frameno = match.group(2) 51*7c3d14c8STreehugger Robot binary = match.group(4) 52*7c3d14c8STreehugger Robot addr = match.group(5) 53*7c3d14c8STreehugger Robot addr = patch_address(frameno, addr) 54*7c3d14c8STreehugger Robot 55*7c3d14c8STreehugger Robot if binary.startswith('/'): 56*7c3d14c8STreehugger Robot binary = binary[1:] 57*7c3d14c8STreehugger Robot binary = os.path.join(binary_prefix, binary) 58*7c3d14c8STreehugger Robot 59*7c3d14c8STreehugger Robot if not os.path.exists(binary): 60*7c3d14c8STreehugger Robot print line.rstrip().encode('utf-8') 61*7c3d14c8STreehugger Robot return 62*7c3d14c8STreehugger Robot 63*7c3d14c8STreehugger Robot addr = hex(int(addr, 16)) 64*7c3d14c8STreehugger Robot 65*7c3d14c8STreehugger Robot if not pipes.has_key(binary): 66*7c3d14c8STreehugger Robot pipes[binary] = subprocess.Popen(["addr2line", "-i", "-f", "-e", binary], 67*7c3d14c8STreehugger Robot stdin=subprocess.PIPE, stdout=subprocess.PIPE) 68*7c3d14c8STreehugger Robot p = pipes[binary] 69*7c3d14c8STreehugger Robot frames = [] 70*7c3d14c8STreehugger Robot try: 71*7c3d14c8STreehugger Robot print >>p.stdin, addr 72*7c3d14c8STreehugger Robot # This will trigger a "??" response from addr2line so we know when to stop 73*7c3d14c8STreehugger Robot print >>p.stdin 74*7c3d14c8STreehugger Robot while True: 75*7c3d14c8STreehugger Robot function_name = p.stdout.readline().rstrip() 76*7c3d14c8STreehugger Robot file_name = p.stdout.readline().rstrip() 77*7c3d14c8STreehugger Robot if function_name in ['??', '']: 78*7c3d14c8STreehugger Robot break 79*7c3d14c8STreehugger Robot file_name = postprocess_file_name(file_name, paths_to_cut) 80*7c3d14c8STreehugger Robot frames.append((function_name, file_name)) 81*7c3d14c8STreehugger Robot except: 82*7c3d14c8STreehugger Robot pass 83*7c3d14c8STreehugger Robot if not frames: 84*7c3d14c8STreehugger Robot frames.append(('', '')) 85*7c3d14c8STreehugger Robot # Consume another pair of "??" lines 86*7c3d14c8STreehugger Robot try: 87*7c3d14c8STreehugger Robot p.stdout.readline() 88*7c3d14c8STreehugger Robot p.stdout.readline() 89*7c3d14c8STreehugger Robot except: 90*7c3d14c8STreehugger Robot pass 91*7c3d14c8STreehugger Robot for frame in frames: 92*7c3d14c8STreehugger Robot inline_frameno = next_inline_frameno 93*7c3d14c8STreehugger Robot next_inline_frameno += 1 94*7c3d14c8STreehugger Robot print "%s%d" % (match.group(1).encode('utf-8'), inline_frameno), \ 95*7c3d14c8STreehugger Robot match.group(3).encode('utf-8'), "in", frame[0], frame[1] 96*7c3d14c8STreehugger Robot else: 97*7c3d14c8STreehugger Robot print line.rstrip().encode('utf-8') 98*7c3d14c8STreehugger Robot 99*7c3d14c8STreehugger Robot 100*7c3d14c8STreehugger Robotbinary_prefix = os.path.join(os.environ['ANDROID_PRODUCT_OUT'], 'symbols') 101*7c3d14c8STreehugger Robotpaths_to_cut = [os.getcwd() + '/', os.environ['ANDROID_BUILD_TOP'] + '/'] + sys.argv[1:] 102*7c3d14c8STreehugger Robot 103*7c3d14c8STreehugger Robotfor line in sys.stdin: 104*7c3d14c8STreehugger Robot line = line.decode('utf-8', 'replace') 105*7c3d14c8STreehugger Robot symbolize_addr2line(line, binary_prefix, paths_to_cut) 106