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