blob: 14ec5bf5a709877d21a332716de0bbee1464fc7e [file] [log] [blame]
Kostya Serebryany019b76f2011-11-30 01:07:02 +00001#!/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 os
11import re
12import sys
13import string
14import subprocess
15
16pipes = {}
Alexander Potapenko02a71622012-01-26 17:06:50 +000017filetypes = {}
18DEBUG=False
Kostya Serebryany019b76f2011-11-30 01:07:02 +000019
20def patch_address(frameno, addr_s):
21 ''' Subtracts 1 or 2 from the top frame's address.
22 Top frame is normally the return address from asan_report*
23 call, which is not expected to return at all. Because of that, this
24 address often belongs to the next source code line, or even to a different
25 function. '''
26 if frameno == '0':
27 addr = int(addr_s, 16)
28 if os.uname()[4].startswith('arm'):
29 # Cancel the Thumb bit
30 addr = addr & (~1)
31 addr -= 1
32 return hex(addr)
33 return addr_s
34
Alexander Potapenko02a71622012-01-26 17:06:50 +000035
36def fix_filename(file_name):
37 for path_to_cut in sys.argv[1:]:
38 file_name = re.sub(".*" + path_to_cut, "", file_name)
39 file_name = re.sub(".*asan_[a-z_]*.cc:[0-9]*", "_asan_rtl_", file_name)
40 file_name = re.sub(".*crtstuff.c:0", "???:0", file_name)
41 return file_name
42
43
Kostya Serebryany019b76f2011-11-30 01:07:02 +000044# TODO(glider): need some refactoring here
45def symbolize_addr2line(line):
46 #0 0x7f6e35cf2e45 (/blah/foo.so+0x11fe45)
47 match = re.match('^( *#([0-9]+) *0x[0-9a-f]+) *\((.*)\+(0x[0-9a-f]+)\)', line)
48 if match:
49 frameno = match.group(2)
50 binary = match.group(3)
51 addr = match.group(4)
52 addr = patch_address(frameno, addr)
53 if not pipes.has_key(binary):
54 pipes[binary] = subprocess.Popen(["addr2line", "-f", "-e", binary],
55 stdin=subprocess.PIPE, stdout=subprocess.PIPE)
56 p = pipes[binary]
57 try:
58 print >>p.stdin, addr
59 function_name = p.stdout.readline().rstrip()
60 file_name = p.stdout.readline().rstrip()
61 except:
62 function_name = ""
63 file_name = ""
Alexander Potapenko02a71622012-01-26 17:06:50 +000064 file_name = fix_filename(file_name)
Kostya Serebryany019b76f2011-11-30 01:07:02 +000065
66 print match.group(1), "in", function_name, file_name
67 else:
68 print line.rstrip()
69
Alexander Potapenko02a71622012-01-26 17:06:50 +000070
71def get_macho_filetype(binary):
72 if not filetypes.has_key(binary):
73 otool_pipe = subprocess.Popen(["otool", "-Vh", binary],
74 stdin=subprocess.PIPE, stdout=subprocess.PIPE)
75 otool_line = "".join(otool_pipe.stdout.readlines())
76 for t in ["DYLIB", "EXECUTE"]:
77 if t in otool_line:
78 filetypes[binary] = t
79 otool_pipe.stdin.close()
80 return filetypes[binary]
81
82
Kostya Serebryany019b76f2011-11-30 01:07:02 +000083def symbolize_atos(line):
84 #0 0x7f6e35cf2e45 (/blah/foo.so+0x11fe45)
85 match = re.match('^( *#([0-9]+) *)(0x[0-9a-f]+) *\((.*)\+(0x[0-9a-f]+)\)', line)
86 if match:
87 #print line
88 prefix = match.group(1)
89 frameno = match.group(2)
Alexander Potapenko02a71622012-01-26 17:06:50 +000090 orig_addr = match.group(3)
Kostya Serebryany019b76f2011-11-30 01:07:02 +000091 binary = match.group(4)
92 offset = match.group(5)
Alexander Potapenko02a71622012-01-26 17:06:50 +000093 addr = patch_address(frameno, orig_addr)
94 load_addr = hex(int(orig_addr, 16) - int(offset, 16))
95 filetype = get_macho_filetype(binary)
96
Kostya Serebryany019b76f2011-11-30 01:07:02 +000097 if not pipes.has_key(binary):
Alexander Potapenko1f397fb2012-01-24 10:44:44 +000098 # Guess which arch we're running. 10 = len("0x") + 8 hex digits.
99 if len(addr) > 10:
100 arch = "x86_64"
101 else:
102 arch = "i386"
Alexander Potapenko02a71622012-01-26 17:06:50 +0000103
104 if filetype == "DYLIB":
105 load_addr = "0x0"
106 if DEBUG:
107 print "atos -o %s -arch %s -l %s" % (binary, arch, load_addr)
Alexander Potapenko628b3492012-07-19 12:01:07 +0000108 cmd = ["atos", "-o", binary, "-arch", arch, "-l", load_addr]
109 pipes[binary] = subprocess.Popen(cmd,
110 stdin=subprocess.PIPE,
111 stdout=subprocess.PIPE,
112 stderr=subprocess.PIPE)
Kostya Serebryany019b76f2011-11-30 01:07:02 +0000113 p = pipes[binary]
Alexander Potapenko02a71622012-01-26 17:06:50 +0000114 if filetype == "DYLIB":
115 print >>p.stdin, "%s" % offset
Kostya Serebryany019b76f2011-11-30 01:07:02 +0000116 else:
Alexander Potapenko1f397fb2012-01-24 10:44:44 +0000117 print >>p.stdin, "%s" % addr
Kostya Serebryany019b76f2011-11-30 01:07:02 +0000118 # TODO(glider): it's more efficient to make a batch atos run for each binary.
119 p.stdin.close()
120 atos_line = p.stdout.readline().rstrip()
Alexander Potapenko02a71622012-01-26 17:06:50 +0000121 # A well-formed atos response looks like this:
122 # foo(type1, type2) (in object.name) (filename.cc:80)
123 match = re.match('^(.*) \(in (.*)\) \((.*:\d*)\)$', atos_line)
124 #print "atos_line: ", atos_line
125 if match:
126 function_name = match.group(1)
127 function_name = re.sub("\(.*?\)", "", function_name)
128 file_name = fix_filename(match.group(3))
129 print "%s%s in %s %s" % (prefix, addr, function_name, file_name)
130 else:
131 print "%s%s in %s" % (prefix, addr, atos_line)
Kostya Serebryany019b76f2011-11-30 01:07:02 +0000132 del pipes[binary]
Kostya Serebryany019b76f2011-11-30 01:07:02 +0000133 else:
134 print line.rstrip()
135
136system = os.uname()[0]
137if system in ['Linux', 'Darwin']:
138 for line in sys.stdin:
139 if system == 'Linux':
140 symbolize_addr2line(line)
141 elif system == 'Darwin':
142 symbolize_atos(line)
143else:
144 print 'Unknown system: ', system