Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 | 2 |
| 3 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 3 # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 4 # Use of this source code is governed by a BSD-style license that can be | 4 # Use of this source code is governed by a BSD-style license that can be |
| 5 # found in the LICENSE file. | 5 # found in the LICENSE file. |
| 6 | 6 |
| 7 import os | 7 from asan_symbolize_trunk import SymbolizationLoop |
| 8 | |
| 8 import re | 9 import re |
| 9 import sys | 10 import sys |
| 10 import string | |
| 11 import subprocess | |
| 12 | |
| 13 pipes = {} | |
| 14 filetypes = {} | |
| 15 vmaddrs = {} | |
| 16 DEBUG=False | |
| 17 | 11 |
| 18 def fix_filename(file_name): | 12 def fix_filename(file_name): |
| 19 for path_to_cut in sys.argv[1:]: | 13 for path_to_cut in sys.argv[1:]: |
| 20 file_name = re.sub(".*" + path_to_cut, "", file_name) | 14 file_name = re.sub(".*" + path_to_cut, "", file_name) |
| 21 file_name = re.sub(".*asan_[a-z_]*.cc:[0-9]*", "_asan_rtl_", file_name) | 15 file_name = re.sub(".*asan_[a-z_]*.cc:[0-9]*", "_asan_rtl_", file_name) |
| 22 file_name = re.sub(".*crtstuff.c:0", "???:0", file_name) | 16 file_name = re.sub(".*crtstuff.c:0", "???:0", file_name) |
| 23 return file_name | 17 return file_name |
| 24 | 18 |
| 25 # TODO(glider): need some refactoring here | |
| 26 def symbolize_addr2line(line): | |
| 27 #0 0x7f6e35cf2e45 (/blah/foo.so+0x11fe45) | |
| 28 match = re.match('^( *#([0-9]+) *0x[0-9a-f]+) *\((.*)\+(0x[0-9a-f]+)\)', line) | |
| 29 if match: | |
| 30 frameno = match.group(2) | |
| 31 binary = match.group(3) | |
| 32 addr = match.group(4) | |
| 33 if not pipes.has_key(binary): | |
| 34 pipes[binary] = subprocess.Popen(["addr2line", "-f", "-e", binary], | |
| 35 stdin=subprocess.PIPE, stdout=subprocess.PIPE, | |
| 36 stderr=open(os.devnull, 'w')) | |
| 37 p = pipes[binary] | |
| 38 try: | |
| 39 print >>p.stdin, addr | |
| 40 function_name = p.stdout.readline().rstrip() | |
| 41 file_name = p.stdout.readline().rstrip() | |
| 42 except: | |
| 43 function_name = "" | |
| 44 file_name = "" | |
| 45 file_name = fix_filename(file_name) | |
| 46 | |
| 47 print match.group(1), "in", function_name, file_name | |
| 48 else: | |
| 49 print line.rstrip() | |
| 50 | |
| 51 def fix_binary_for_chromium(binary): | |
| 52 BUILDTYPE = 'Release' | |
| 53 # Chromium Helper EH is the same binary as Chromium Helper, but there's no | |
| 54 # .dSYM directory for it. | |
| 55 binary = binary.replace('Chromium Helper EH', 'Chromium Helper') | |
| 56 pieces = binary.split(BUILDTYPE) | |
| 57 if len(pieces) != 2: | |
| 58 return binary | |
| 59 prefix, suffix = pieces | |
| 60 to_fix = { 'Chromium Framework': 'framework', | |
| 61 'Chromium Helper': 'app' } | |
| 62 for filename in to_fix: | |
| 63 ext = to_fix[filename] | |
| 64 if suffix.endswith(filename): | |
| 65 binary = (prefix + BUILDTYPE + '/' + filename + '.' + | |
| 66 ext + '.dSYM/Contents/Resources/DWARF/' + filename) | |
| 67 return binary | |
| 68 filename = suffix.split('/')[-1] | |
| 69 binary = (prefix + BUILDTYPE + '/' + filename + | |
| 70 '.dSYM/Contents/Resources/DWARF/' + filename) | |
| 71 return binary | |
| 72 | |
| 73 | |
| 74 # Get the skew value to be added to the address. | |
| 75 # We're ooking for the following piece in otool -l output: | |
| 76 # Load command 0 | |
| 77 # cmd LC_SEGMENT | |
| 78 # cmdsize 736 | |
| 79 # segname __TEXT | |
| 80 # vmaddr 0x00000000 | |
| 81 def get_binary_vmaddr(binary): | |
| 82 if binary in vmaddrs: | |
| 83 return vmaddrs[binary] | |
| 84 cmdline = ["otool", "-l", binary] | |
| 85 pipe = subprocess.Popen(cmdline, | |
| 86 stdin=subprocess.PIPE, | |
| 87 stdout=subprocess.PIPE) | |
| 88 is_text = False | |
| 89 vmaddr = 0 | |
| 90 for line in pipe.stdout.readlines(): | |
| 91 line = line.strip() | |
| 92 if line.startswith('segname'): | |
| 93 is_text = (line == 'segname __TEXT') | |
| 94 continue | |
| 95 if line.startswith('vmaddr') and is_text: | |
| 96 sv = line.split(' ') | |
| 97 vmaddr = int(sv[-1], 16) | |
| 98 break | |
| 99 vmaddrs[binary] = vmaddr | |
| 100 return vmaddr | |
| 101 | |
| 102 | |
| 103 def write_addr_to_pipe(pipe, addr, offset, binary): | |
| 104 skew = get_binary_vmaddr(binary) | |
| 105 print >>pipe, "0x%x" % (int(offset, 16) + skew) | |
| 106 | |
| 107 def open_atos(binary): | |
| 108 #print "atos -o %s -l %s" % (binary, hex(load_addr)) | |
| 109 cmdline = ["atos", "-o", binary] | |
| 110 return subprocess.Popen(cmdline, | |
| 111 stdin=subprocess.PIPE, | |
| 112 stdout=subprocess.PIPE) | |
| 113 | |
| 114 def symbolize_atos(line): | |
| 115 #0 0x7f6e35cf2e45 (/blah/foo.so+0x11fe45) | |
| 116 match = re.match('^( *#[0-9]+ *)(0x[0-9a-f]+) *\((.*)\+(0x[0-9a-f]+)\)', line) | |
| 117 if match: | |
| 118 #print line | |
| 119 prefix = match.group(1) | |
| 120 addr = match.group(2) | |
| 121 binary = match.group(3) | |
| 122 offset = match.group(4) | |
| 123 load_addr = int(addr, 16) - int(offset, 16) | |
| 124 original_binary = binary | |
| 125 binary = fix_binary_for_chromium(binary) | |
| 126 if not pipes.has_key(binary): | |
| 127 pipes[binary] = open_atos(binary) | |
| 128 p = pipes[binary] | |
| 129 try: | |
| 130 write_addr_to_pipe(p.stdin, addr, offset, binary) | |
| 131 except: | |
| 132 # Oops, atos failed. Trying to use the original binary. | |
| 133 binary = original_binary | |
| 134 pipes[binary] = open_atos(binary) | |
| 135 p = pipes[binary] | |
| 136 write_addr_to_pipe(p.stdin, addr, offset, binary) | |
| 137 | |
| 138 # TODO(glider): it's more efficient to make a batch atos run for each | |
| 139 # binary. | |
| 140 p.stdin.close() | |
| 141 atos_line = p.stdout.readline().rstrip() | |
| 142 del pipes[binary] | |
| 143 | |
| 144 print "%s%s in %s" % (prefix, addr, atos_line) | |
| 145 else: | |
| 146 print line.rstrip() | |
| 147 | |
| 148 def main(): | |
| 149 system = os.uname()[0] | |
| 150 if system in ['Linux', 'Darwin']: | |
| 151 for line in sys.stdin: | |
| 152 if system == 'Linux': | |
| 153 symbolize_addr2line(line) | |
| 154 elif system == 'Darwin': | |
| 155 symbolize_atos(line) | |
| 156 else: | |
| 157 print 'Unknown system: ', system | |
| 158 | |
| 159 if __name__ == '__main__': | 19 if __name__ == '__main__': |
| 160 main() | 20 loop = SymbolizationLoop(binary_name_filter=fix_filename) |
|
M-A Ruel
2012/09/26 16:58:30
still prefer a main() function.
| |
| 21 loop.process_stdin() | |
| OLD | NEW |