1dc3865b01cd56b703b77f58d5acff6529491eaf3Evgeniy Stepanov#!/usr/bin/env python 2dc3865b01cd56b703b77f58d5acff6529491eaf3Evgeniy Stepanov#===- lib/asan/scripts/asan_symbolize.py -----------------------------------===# 3dc3865b01cd56b703b77f58d5acff6529491eaf3Evgeniy Stepanov# 4dc3865b01cd56b703b77f58d5acff6529491eaf3Evgeniy Stepanov# The LLVM Compiler Infrastructure 5dc3865b01cd56b703b77f58d5acff6529491eaf3Evgeniy Stepanov# 6dc3865b01cd56b703b77f58d5acff6529491eaf3Evgeniy Stepanov# This file is distributed under the University of Illinois Open Source 7dc3865b01cd56b703b77f58d5acff6529491eaf3Evgeniy Stepanov# License. See LICENSE.TXT for details. 8dc3865b01cd56b703b77f58d5acff6529491eaf3Evgeniy Stepanov# 9dc3865b01cd56b703b77f58d5acff6529491eaf3Evgeniy Stepanov#===------------------------------------------------------------------------===# 10dc3865b01cd56b703b77f58d5acff6529491eaf3Evgeniy Stepanovimport os 11dc3865b01cd56b703b77f58d5acff6529491eaf3Evgeniy Stepanovimport re 12dc3865b01cd56b703b77f58d5acff6529491eaf3Evgeniy Stepanovimport sys 13dc3865b01cd56b703b77f58d5acff6529491eaf3Evgeniy Stepanovimport string 14dc3865b01cd56b703b77f58d5acff6529491eaf3Evgeniy Stepanovimport subprocess 15dc3865b01cd56b703b77f58d5acff6529491eaf3Evgeniy Stepanov 16dc3865b01cd56b703b77f58d5acff6529491eaf3Evgeniy Stepanovpipes = {} 17dc3865b01cd56b703b77f58d5acff6529491eaf3Evgeniy Stepanovload_addresses = {} 1846d7b0bd647fa4844f9fe4ca9be31b8341ad12f5Evgeniy Stepanovnext_inline_frameno = 0 19dc3865b01cd56b703b77f58d5acff6529491eaf3Evgeniy Stepanov 20dc3865b01cd56b703b77f58d5acff6529491eaf3Evgeniy Stepanovdef patch_address(frameno, addr_s): 21dc3865b01cd56b703b77f58d5acff6529491eaf3Evgeniy Stepanov ''' Subtracts 1 or 2 from the top frame's address. 22dc3865b01cd56b703b77f58d5acff6529491eaf3Evgeniy Stepanov Top frame is normally the return address from asan_report* 23dc3865b01cd56b703b77f58d5acff6529491eaf3Evgeniy Stepanov call, which is not expected to return at all. Because of that, this 24dc3865b01cd56b703b77f58d5acff6529491eaf3Evgeniy Stepanov address often belongs to the next source code line, or even to a different 25dc3865b01cd56b703b77f58d5acff6529491eaf3Evgeniy Stepanov function. ''' 26dc3865b01cd56b703b77f58d5acff6529491eaf3Evgeniy Stepanov if frameno == '0': 27dc3865b01cd56b703b77f58d5acff6529491eaf3Evgeniy Stepanov addr = int(addr_s, 16) 28dc3865b01cd56b703b77f58d5acff6529491eaf3Evgeniy Stepanov if os.uname()[4].startswith('arm'): 29dc3865b01cd56b703b77f58d5acff6529491eaf3Evgeniy Stepanov # Cancel the Thumb bit 30dc3865b01cd56b703b77f58d5acff6529491eaf3Evgeniy Stepanov addr = addr & (~1) 31dc3865b01cd56b703b77f58d5acff6529491eaf3Evgeniy Stepanov addr -= 1 32dc3865b01cd56b703b77f58d5acff6529491eaf3Evgeniy Stepanov return hex(addr) 33dc3865b01cd56b703b77f58d5acff6529491eaf3Evgeniy Stepanov return addr_s 34dc3865b01cd56b703b77f58d5acff6529491eaf3Evgeniy Stepanov 35dc3865b01cd56b703b77f58d5acff6529491eaf3Evgeniy Stepanovdef android_get_load_address(path): 36dc3865b01cd56b703b77f58d5acff6529491eaf3Evgeniy Stepanov if load_addresses.has_key(path): 37dc3865b01cd56b703b77f58d5acff6529491eaf3Evgeniy Stepanov return load_addresses[path] 38dc3865b01cd56b703b77f58d5acff6529491eaf3Evgeniy Stepanov readelf = os.path.join(os.environ['ANDROID_EABI_TOOLCHAIN'], 'arm-linux-androideabi-readelf') 39dc3865b01cd56b703b77f58d5acff6529491eaf3Evgeniy Stepanov readelf_pipe = subprocess.Popen([readelf, "-l", path], stdin=subprocess.PIPE, stdout=subprocess.PIPE) 40dc3865b01cd56b703b77f58d5acff6529491eaf3Evgeniy Stepanov for line in readelf_pipe.stdout: 41dc3865b01cd56b703b77f58d5acff6529491eaf3Evgeniy Stepanov if ('LOAD' in line) and (' E ' in line): 42dc3865b01cd56b703b77f58d5acff6529491eaf3Evgeniy Stepanov match = re.match(r'\s*LOAD\s+0x[01-9a-zA-Z]+\s+(0x[01-9a-zA-Z]+)', line, re.UNICODE) 43dc3865b01cd56b703b77f58d5acff6529491eaf3Evgeniy Stepanov if match: 44dc3865b01cd56b703b77f58d5acff6529491eaf3Evgeniy Stepanov load_addr = int(match.group(1), 16) 45dc3865b01cd56b703b77f58d5acff6529491eaf3Evgeniy Stepanov load_addresses[path] = load_addr 46dc3865b01cd56b703b77f58d5acff6529491eaf3Evgeniy Stepanov return load_addr 47dc3865b01cd56b703b77f58d5acff6529491eaf3Evgeniy Stepanov else: break 48dc3865b01cd56b703b77f58d5acff6529491eaf3Evgeniy Stepanov print 'Could not make sense of readelf output!' 49dc3865b01cd56b703b77f58d5acff6529491eaf3Evgeniy Stepanov sys.exit(1) 50dc3865b01cd56b703b77f58d5acff6529491eaf3Evgeniy Stepanov 5146d7b0bd647fa4844f9fe4ca9be31b8341ad12f5Evgeniy Stepanovdef postprocess_file_name(file_name, paths_to_cut): 5246d7b0bd647fa4844f9fe4ca9be31b8341ad12f5Evgeniy Stepanov for path_to_cut in paths_to_cut: 5346d7b0bd647fa4844f9fe4ca9be31b8341ad12f5Evgeniy Stepanov file_name = re.sub(".*" + path_to_cut, "", file_name) 5446d7b0bd647fa4844f9fe4ca9be31b8341ad12f5Evgeniy Stepanov file_name = re.sub(".*asan_[a-z_]*.(cc|h):[0-9]*", "[asan_rtl]", file_name) 5546d7b0bd647fa4844f9fe4ca9be31b8341ad12f5Evgeniy Stepanov file_name = re.sub(".*crtstuff.c:0", "???:0", file_name) 5646d7b0bd647fa4844f9fe4ca9be31b8341ad12f5Evgeniy Stepanov return file_name 5746d7b0bd647fa4844f9fe4ca9be31b8341ad12f5Evgeniy Stepanov 58dc3865b01cd56b703b77f58d5acff6529491eaf3Evgeniy Stepanov# TODO(glider): need some refactoring here 59dc3865b01cd56b703b77f58d5acff6529491eaf3Evgeniy Stepanovdef symbolize_addr2line(line, binary_prefix, paths_to_cut): 6046d7b0bd647fa4844f9fe4ca9be31b8341ad12f5Evgeniy Stepanov global next_inline_frameno 61dc3865b01cd56b703b77f58d5acff6529491eaf3Evgeniy Stepanov # Strip the log prefix ("I/asanwrapper( 1196): "). 62dc3865b01cd56b703b77f58d5acff6529491eaf3Evgeniy Stepanov line = re.sub(r'^[A-Z]/[^\s]*\(\s*\d+\): ', '', line) 63dc3865b01cd56b703b77f58d5acff6529491eaf3Evgeniy Stepanov #0 0x7f6e35cf2e45 (/blah/foo.so+0x11fe45) 6446d7b0bd647fa4844f9fe4ca9be31b8341ad12f5Evgeniy Stepanov match = re.match(r'^(\s*#)([0-9]+) *(0x[0-9a-f]+) *\((.*)\+(0x[0-9a-f]+)\)', line, re.UNICODE) 65dc3865b01cd56b703b77f58d5acff6529491eaf3Evgeniy Stepanov if match: 66dc3865b01cd56b703b77f58d5acff6529491eaf3Evgeniy Stepanov frameno = match.group(2) 6746d7b0bd647fa4844f9fe4ca9be31b8341ad12f5Evgeniy Stepanov binary = match.group(4) 6846d7b0bd647fa4844f9fe4ca9be31b8341ad12f5Evgeniy Stepanov addr = match.group(5) 69dc3865b01cd56b703b77f58d5acff6529491eaf3Evgeniy Stepanov addr = patch_address(frameno, addr) 70dc3865b01cd56b703b77f58d5acff6529491eaf3Evgeniy Stepanov 71dc3865b01cd56b703b77f58d5acff6529491eaf3Evgeniy Stepanov if binary.startswith('/'): 72dc3865b01cd56b703b77f58d5acff6529491eaf3Evgeniy Stepanov binary = binary[1:] 73dc3865b01cd56b703b77f58d5acff6529491eaf3Evgeniy Stepanov binary = os.path.join(binary_prefix, binary) 74dc3865b01cd56b703b77f58d5acff6529491eaf3Evgeniy Stepanov 75dc3865b01cd56b703b77f58d5acff6529491eaf3Evgeniy Stepanov load_addr = android_get_load_address(binary) 76dc3865b01cd56b703b77f58d5acff6529491eaf3Evgeniy Stepanov addr = hex(int(addr, 16) + load_addr) 77dc3865b01cd56b703b77f58d5acff6529491eaf3Evgeniy Stepanov 78dc3865b01cd56b703b77f58d5acff6529491eaf3Evgeniy Stepanov if not pipes.has_key(binary): 7946d7b0bd647fa4844f9fe4ca9be31b8341ad12f5Evgeniy Stepanov pipes[binary] = subprocess.Popen(["addr2line", "-i", "-f", "-e", binary], 80dc3865b01cd56b703b77f58d5acff6529491eaf3Evgeniy Stepanov stdin=subprocess.PIPE, stdout=subprocess.PIPE) 81dc3865b01cd56b703b77f58d5acff6529491eaf3Evgeniy Stepanov p = pipes[binary] 8246d7b0bd647fa4844f9fe4ca9be31b8341ad12f5Evgeniy Stepanov frames = [] 83dc3865b01cd56b703b77f58d5acff6529491eaf3Evgeniy Stepanov try: 84dc3865b01cd56b703b77f58d5acff6529491eaf3Evgeniy Stepanov print >>p.stdin, addr 8546d7b0bd647fa4844f9fe4ca9be31b8341ad12f5Evgeniy Stepanov # This will trigger a "??" response from addr2line so we know when to stop 8646d7b0bd647fa4844f9fe4ca9be31b8341ad12f5Evgeniy Stepanov print >>p.stdin 8746d7b0bd647fa4844f9fe4ca9be31b8341ad12f5Evgeniy Stepanov while True: 8846d7b0bd647fa4844f9fe4ca9be31b8341ad12f5Evgeniy Stepanov function_name = p.stdout.readline().rstrip() 8946d7b0bd647fa4844f9fe4ca9be31b8341ad12f5Evgeniy Stepanov file_name = p.stdout.readline().rstrip() 9046d7b0bd647fa4844f9fe4ca9be31b8341ad12f5Evgeniy Stepanov if function_name in ['??', '']: 9146d7b0bd647fa4844f9fe4ca9be31b8341ad12f5Evgeniy Stepanov break 9246d7b0bd647fa4844f9fe4ca9be31b8341ad12f5Evgeniy Stepanov file_name = postprocess_file_name(file_name, paths_to_cut) 9346d7b0bd647fa4844f9fe4ca9be31b8341ad12f5Evgeniy Stepanov frames.append((function_name, file_name)) 94dc3865b01cd56b703b77f58d5acff6529491eaf3Evgeniy Stepanov except: 9546d7b0bd647fa4844f9fe4ca9be31b8341ad12f5Evgeniy Stepanov pass 9646d7b0bd647fa4844f9fe4ca9be31b8341ad12f5Evgeniy Stepanov if not frames: 9746d7b0bd647fa4844f9fe4ca9be31b8341ad12f5Evgeniy Stepanov frames.append(('', '')) 9846d7b0bd647fa4844f9fe4ca9be31b8341ad12f5Evgeniy Stepanov # Consume another pair of "??" lines 9946d7b0bd647fa4844f9fe4ca9be31b8341ad12f5Evgeniy Stepanov try: 10046d7b0bd647fa4844f9fe4ca9be31b8341ad12f5Evgeniy Stepanov p.stdout.readline() 10146d7b0bd647fa4844f9fe4ca9be31b8341ad12f5Evgeniy Stepanov p.stdout.readline() 10246d7b0bd647fa4844f9fe4ca9be31b8341ad12f5Evgeniy Stepanov except: 10346d7b0bd647fa4844f9fe4ca9be31b8341ad12f5Evgeniy Stepanov pass 10446d7b0bd647fa4844f9fe4ca9be31b8341ad12f5Evgeniy Stepanov for frame in frames: 10546d7b0bd647fa4844f9fe4ca9be31b8341ad12f5Evgeniy Stepanov inline_frameno = next_inline_frameno 10646d7b0bd647fa4844f9fe4ca9be31b8341ad12f5Evgeniy Stepanov next_inline_frameno += 1 10746d7b0bd647fa4844f9fe4ca9be31b8341ad12f5Evgeniy Stepanov print "%s%d" % (match.group(1).encode('utf-8'), inline_frameno), \ 10846d7b0bd647fa4844f9fe4ca9be31b8341ad12f5Evgeniy Stepanov match.group(3).encode('utf-8'), "in", frame[0], frame[1] 109dc3865b01cd56b703b77f58d5acff6529491eaf3Evgeniy Stepanov else: 110dc3865b01cd56b703b77f58d5acff6529491eaf3Evgeniy Stepanov print line.rstrip().encode('utf-8') 111dc3865b01cd56b703b77f58d5acff6529491eaf3Evgeniy Stepanov 112dc3865b01cd56b703b77f58d5acff6529491eaf3Evgeniy Stepanov 113dc3865b01cd56b703b77f58d5acff6529491eaf3Evgeniy Stepanovbinary_prefix = os.path.join(os.environ['ANDROID_PRODUCT_OUT'], 'symbols') 114dc3865b01cd56b703b77f58d5acff6529491eaf3Evgeniy Stepanovpaths_to_cut = [os.getcwd() + '/', os.environ['ANDROID_BUILD_TOP'] + '/'] + sys.argv[1:] 115dc3865b01cd56b703b77f58d5acff6529491eaf3Evgeniy Stepanov 116dc3865b01cd56b703b77f58d5acff6529491eaf3Evgeniy Stepanovfor line in sys.stdin: 117dc3865b01cd56b703b77f58d5acff6529491eaf3Evgeniy Stepanov line = line.decode('utf-8') 118dc3865b01cd56b703b77f58d5acff6529491eaf3Evgeniy Stepanov symbolize_addr2line(line, binary_prefix, paths_to_cut) 119