Kostya Serebryany | 019b76f | 2011-11-30 01:07:02 +0000 | [diff] [blame] | 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 | #===------------------------------------------------------------------------===# |
Alexander Potapenko | be84ac8 | 2012-08-02 13:59:23 +0000 | [diff] [blame] | 10 | import bisect |
Kostya Serebryany | 019b76f | 2011-11-30 01:07:02 +0000 | [diff] [blame] | 11 | import os |
| 12 | import re |
Kostya Serebryany | 019b76f | 2011-11-30 01:07:02 +0000 | [diff] [blame] | 13 | import subprocess |
Alexander Potapenko | 3f6a5c1 | 2012-09-26 13:16:42 +0000 | [diff] [blame] | 14 | import sys |
Kostya Serebryany | 019b76f | 2011-11-30 01:07:02 +0000 | [diff] [blame] | 15 | |
Alexey Samsonov | 52565d5 | 2012-09-19 08:49:53 +0000 | [diff] [blame] | 16 | llvm_symbolizer = None |
Alexander Potapenko | 879b1ff | 2012-08-02 14:58:04 +0000 | [diff] [blame] | 17 | symbolizers = {} |
Alexander Potapenko | 02a7162 | 2012-01-26 17:06:50 +0000 | [diff] [blame] | 18 | filetypes = {} |
Alexander Potapenko | be84ac8 | 2012-08-02 13:59:23 +0000 | [diff] [blame] | 19 | vmaddrs = {} |
| 20 | DEBUG = False |
Kostya Serebryany | 019b76f | 2011-11-30 01:07:02 +0000 | [diff] [blame] | 21 | |
Alexander Potapenko | 8aae955 | 2012-07-31 13:51:26 +0000 | [diff] [blame] | 22 | |
Alexander Potapenko | 59cc877 | 2012-09-26 12:12:41 +0000 | [diff] [blame] | 23 | # FIXME: merge the code that calls fix_filename(). |
Alexander Potapenko | 02a7162 | 2012-01-26 17:06:50 +0000 | [diff] [blame] | 24 | def fix_filename(file_name): |
| 25 | for path_to_cut in sys.argv[1:]: |
Alexander Potapenko | 3f6a5c1 | 2012-09-26 13:16:42 +0000 | [diff] [blame] | 26 | file_name = re.sub('.*' + path_to_cut, '', file_name) |
| 27 | file_name = re.sub('.*asan_[a-z_]*.cc:[0-9]*', '_asan_rtl_', file_name) |
| 28 | file_name = re.sub('.*crtstuff.c:0', '???:0', file_name) |
Alexander Potapenko | 02a7162 | 2012-01-26 17:06:50 +0000 | [diff] [blame] | 29 | return file_name |
| 30 | |
| 31 | |
Alexander Potapenko | 879b1ff | 2012-08-02 14:58:04 +0000 | [diff] [blame] | 32 | class Symbolizer(object): |
| 33 | def __init__(self): |
| 34 | pass |
Alexander Potapenko | 3f6a5c1 | 2012-09-26 13:16:42 +0000 | [diff] [blame] | 35 | |
Alexey Samsonov | 52565d5 | 2012-09-19 08:49:53 +0000 | [diff] [blame] | 36 | def symbolize(self, addr, binary, offset): |
Alexander Potapenko | 3f6a5c1 | 2012-09-26 13:16:42 +0000 | [diff] [blame] | 37 | """Symbolize the given address (pair of binary and offset). |
| 38 | |
| 39 | Overriden in subclasses. |
| 40 | Args: |
Alexey Samsonov | 52565d5 | 2012-09-19 08:49:53 +0000 | [diff] [blame] | 41 | addr: virtual address of an instruction. |
| 42 | binary: path to executable/shared object containing this instruction. |
| 43 | offset: instruction offset in the @binary. |
Alexander Potapenko | 3f6a5c1 | 2012-09-26 13:16:42 +0000 | [diff] [blame] | 44 | Returns: |
Alexey Samsonov | 52565d5 | 2012-09-19 08:49:53 +0000 | [diff] [blame] | 45 | list of strings (one string for each inlined frame) describing |
| 46 | the code locations for this instruction (that is, function name, file |
| 47 | name, line and column numbers). |
| 48 | """ |
| 49 | return None |
Alexander Potapenko | 879b1ff | 2012-08-02 14:58:04 +0000 | [diff] [blame] | 50 | |
| 51 | |
Alexey Samsonov | 52565d5 | 2012-09-19 08:49:53 +0000 | [diff] [blame] | 52 | class LLVMSymbolizer(Symbolizer): |
| 53 | def __init__(self, symbolizer_path): |
| 54 | super(LLVMSymbolizer, self).__init__() |
| 55 | self.symbolizer_path = symbolizer_path |
| 56 | self.pipe = self.open_llvm_symbolizer() |
Alexander Potapenko | 3f6a5c1 | 2012-09-26 13:16:42 +0000 | [diff] [blame] | 57 | |
Alexey Samsonov | 52565d5 | 2012-09-19 08:49:53 +0000 | [diff] [blame] | 58 | def open_llvm_symbolizer(self): |
Alexey Samsonov | ea2fb08 | 2012-09-19 11:43:41 +0000 | [diff] [blame] | 59 | if not os.path.exists(self.symbolizer_path): |
| 60 | return None |
Alexey Samsonov | 52565d5 | 2012-09-19 08:49:53 +0000 | [diff] [blame] | 61 | cmd = [self.symbolizer_path, |
Alexander Potapenko | 3f6a5c1 | 2012-09-26 13:16:42 +0000 | [diff] [blame] | 62 | '--use-symbol-table=true', |
| 63 | '--demangle=false', |
| 64 | '--functions=true', |
| 65 | '--inlining=true'] |
Alexey Samsonov | 52565d5 | 2012-09-19 08:49:53 +0000 | [diff] [blame] | 66 | if DEBUG: |
| 67 | print ' '.join(cmd) |
| 68 | return subprocess.Popen(cmd, stdin=subprocess.PIPE, |
| 69 | stdout=subprocess.PIPE) |
| 70 | |
| 71 | def symbolize(self, addr, binary, offset): |
Alexander Potapenko | 3f6a5c1 | 2012-09-26 13:16:42 +0000 | [diff] [blame] | 72 | """Overrides Symbolizer.symbolize.""" |
Alexey Samsonov | ea2fb08 | 2012-09-19 11:43:41 +0000 | [diff] [blame] | 73 | if not self.pipe: |
| 74 | return None |
Alexey Samsonov | 52565d5 | 2012-09-19 08:49:53 +0000 | [diff] [blame] | 75 | result = [] |
| 76 | try: |
Alexander Potapenko | 3f6a5c1 | 2012-09-26 13:16:42 +0000 | [diff] [blame] | 77 | symbolizer_input = '%s %s' % (binary, offset) |
| 78 | if DEBUG: |
| 79 | print symbolizer_input |
Alexey Samsonov | 52565d5 | 2012-09-19 08:49:53 +0000 | [diff] [blame] | 80 | print >> self.pipe.stdin, symbolizer_input |
| 81 | while True: |
| 82 | function_name = self.pipe.stdout.readline().rstrip() |
Alexander Potapenko | 3f6a5c1 | 2012-09-26 13:16:42 +0000 | [diff] [blame] | 83 | if not function_name: |
Alexey Samsonov | 52565d5 | 2012-09-19 08:49:53 +0000 | [diff] [blame] | 84 | break |
| 85 | file_name = self.pipe.stdout.readline().rstrip() |
| 86 | file_name = fix_filename(file_name) |
Alexander Potapenko | 3f6a5c1 | 2012-09-26 13:16:42 +0000 | [diff] [blame] | 87 | if (not function_name.startswith('??') and |
| 88 | not file_name.startswith('??')): |
Alexey Samsonov | 52565d5 | 2012-09-19 08:49:53 +0000 | [diff] [blame] | 89 | # Append only valid frames. |
Alexander Potapenko | 3f6a5c1 | 2012-09-26 13:16:42 +0000 | [diff] [blame] | 90 | result.append('%s in %s %s' % (addr, function_name, |
Alexey Samsonov | 52565d5 | 2012-09-19 08:49:53 +0000 | [diff] [blame] | 91 | file_name)) |
| 92 | except Exception: |
| 93 | result = [] |
Alexander Potapenko | 3f6a5c1 | 2012-09-26 13:16:42 +0000 | [diff] [blame] | 94 | if not result: |
Alexey Samsonov | 52565d5 | 2012-09-19 08:49:53 +0000 | [diff] [blame] | 95 | result = None |
| 96 | return result |
| 97 | |
| 98 | |
| 99 | def LLVMSymbolizerFactory(system): |
Alexey Samsonov | 480477c | 2012-10-08 13:11:18 +0000 | [diff] [blame] | 100 | symbolizer_path = os.getenv('LLVM_SYMBOLIZER_PATH') |
| 101 | if not symbolizer_path: |
| 102 | # Assume llvm-symbolizer is in PATH. |
| 103 | symbolizer_path = 'llvm-symbolizer' |
| 104 | return LLVMSymbolizer(symbolizer_path) |
Alexey Samsonov | 52565d5 | 2012-09-19 08:49:53 +0000 | [diff] [blame] | 105 | |
| 106 | |
| 107 | class Addr2LineSymbolizer(Symbolizer): |
Alexander Potapenko | 879b1ff | 2012-08-02 14:58:04 +0000 | [diff] [blame] | 108 | def __init__(self, binary): |
Alexey Samsonov | 52565d5 | 2012-09-19 08:49:53 +0000 | [diff] [blame] | 109 | super(Addr2LineSymbolizer, self).__init__() |
Alexander Potapenko | 879b1ff | 2012-08-02 14:58:04 +0000 | [diff] [blame] | 110 | self.binary = binary |
| 111 | self.pipe = self.open_addr2line() |
Alexander Potapenko | 3f6a5c1 | 2012-09-26 13:16:42 +0000 | [diff] [blame] | 112 | |
Alexander Potapenko | 879b1ff | 2012-08-02 14:58:04 +0000 | [diff] [blame] | 113 | def open_addr2line(self): |
Alexander Potapenko | 3f6a5c1 | 2012-09-26 13:16:42 +0000 | [diff] [blame] | 114 | cmd = ['addr2line', '-f', '-e', self.binary] |
Alexander Potapenko | 1800362 | 2012-08-15 13:58:24 +0000 | [diff] [blame] | 115 | if DEBUG: |
| 116 | print ' '.join(cmd) |
| 117 | return subprocess.Popen(cmd, |
Alexander Potapenko | 879b1ff | 2012-08-02 14:58:04 +0000 | [diff] [blame] | 118 | stdin=subprocess.PIPE, stdout=subprocess.PIPE) |
Alexander Potapenko | 3f6a5c1 | 2012-09-26 13:16:42 +0000 | [diff] [blame] | 119 | |
Alexey Samsonov | 52565d5 | 2012-09-19 08:49:53 +0000 | [diff] [blame] | 120 | def symbolize(self, addr, binary, offset): |
Alexander Potapenko | 3f6a5c1 | 2012-09-26 13:16:42 +0000 | [diff] [blame] | 121 | """Overrides Symbolizer.symbolize.""" |
Alexey Samsonov | 52565d5 | 2012-09-19 08:49:53 +0000 | [diff] [blame] | 122 | if self.binary != binary: |
| 123 | return None |
Kostya Serebryany | 019b76f | 2011-11-30 01:07:02 +0000 | [diff] [blame] | 124 | try: |
Alexander Potapenko | 1800362 | 2012-08-15 13:58:24 +0000 | [diff] [blame] | 125 | print >> self.pipe.stdin, offset |
Alexander Potapenko | 879b1ff | 2012-08-02 14:58:04 +0000 | [diff] [blame] | 126 | function_name = self.pipe.stdout.readline().rstrip() |
Alexander Potapenko | 3f6a5c1 | 2012-09-26 13:16:42 +0000 | [diff] [blame] | 127 | file_name = self.pipe.stdout.readline().rstrip() |
Alexander Potapenko | be84ac8 | 2012-08-02 13:59:23 +0000 | [diff] [blame] | 128 | except Exception: |
Alexander Potapenko | 3f6a5c1 | 2012-09-26 13:16:42 +0000 | [diff] [blame] | 129 | function_name = '' |
| 130 | file_name = '' |
Alexander Potapenko | 02a7162 | 2012-01-26 17:06:50 +0000 | [diff] [blame] | 131 | file_name = fix_filename(file_name) |
Alexander Potapenko | 3f6a5c1 | 2012-09-26 13:16:42 +0000 | [diff] [blame] | 132 | return ['%s in %s %s' % (addr, function_name, file_name)] |
Alexander Potapenko | 02a7162 | 2012-01-26 17:06:50 +0000 | [diff] [blame] | 133 | |
| 134 | |
Alexander Potapenko | be84ac8 | 2012-08-02 13:59:23 +0000 | [diff] [blame] | 135 | class DarwinSymbolizer(Symbolizer): |
| 136 | def __init__(self, addr, binary): |
| 137 | super(DarwinSymbolizer, self).__init__() |
| 138 | self.binary = binary |
Alexander Potapenko | 3f6a5c1 | 2012-09-26 13:16:42 +0000 | [diff] [blame] | 139 | # Guess which arch we're running. 10 = len('0x') + 8 hex digits. |
Alexander Potapenko | be84ac8 | 2012-08-02 13:59:23 +0000 | [diff] [blame] | 140 | if len(addr) > 10: |
Alexander Potapenko | 3f6a5c1 | 2012-09-26 13:16:42 +0000 | [diff] [blame] | 141 | self.arch = 'x86_64' |
Kostya Serebryany | 019b76f | 2011-11-30 01:07:02 +0000 | [diff] [blame] | 142 | else: |
Alexander Potapenko | 3f6a5c1 | 2012-09-26 13:16:42 +0000 | [diff] [blame] | 143 | self.arch = 'i386' |
Alexander Potapenko | be84ac8 | 2012-08-02 13:59:23 +0000 | [diff] [blame] | 144 | self.vmaddr = None |
| 145 | self.pipe = None |
Alexander Potapenko | 3f6a5c1 | 2012-09-26 13:16:42 +0000 | [diff] [blame] | 146 | |
Alexander Potapenko | be84ac8 | 2012-08-02 13:59:23 +0000 | [diff] [blame] | 147 | def write_addr_to_pipe(self, offset): |
Alexander Potapenko | 77c0ac2 | 2012-10-02 15:42:24 +0000 | [diff] [blame] | 148 | print >> self.pipe.stdin, '0x%x' % int(offset, 16) |
Alexander Potapenko | 3f6a5c1 | 2012-09-26 13:16:42 +0000 | [diff] [blame] | 149 | |
Alexander Potapenko | be84ac8 | 2012-08-02 13:59:23 +0000 | [diff] [blame] | 150 | def open_atos(self): |
| 151 | if DEBUG: |
Alexander Potapenko | 3f6a5c1 | 2012-09-26 13:16:42 +0000 | [diff] [blame] | 152 | print 'atos -o %s -arch %s' % (self.binary, self.arch) |
| 153 | cmdline = ['atos', '-o', self.binary, '-arch', self.arch] |
Alexander Potapenko | be84ac8 | 2012-08-02 13:59:23 +0000 | [diff] [blame] | 154 | self.pipe = subprocess.Popen(cmdline, |
| 155 | stdin=subprocess.PIPE, |
| 156 | stdout=subprocess.PIPE, |
| 157 | stderr=subprocess.PIPE) |
Alexander Potapenko | 3f6a5c1 | 2012-09-26 13:16:42 +0000 | [diff] [blame] | 158 | |
Alexey Samsonov | 52565d5 | 2012-09-19 08:49:53 +0000 | [diff] [blame] | 159 | def symbolize(self, addr, binary, offset): |
Alexander Potapenko | 3f6a5c1 | 2012-09-26 13:16:42 +0000 | [diff] [blame] | 160 | """Overrides Symbolizer.symbolize.""" |
Alexey Samsonov | 52565d5 | 2012-09-19 08:49:53 +0000 | [diff] [blame] | 161 | if self.binary != binary: |
| 162 | return None |
Alexander Potapenko | be84ac8 | 2012-08-02 13:59:23 +0000 | [diff] [blame] | 163 | self.open_atos() |
| 164 | self.write_addr_to_pipe(offset) |
| 165 | self.pipe.stdin.close() |
| 166 | atos_line = self.pipe.stdout.readline().rstrip() |
Alexander Potapenko | 02a7162 | 2012-01-26 17:06:50 +0000 | [diff] [blame] | 167 | # A well-formed atos response looks like this: |
| 168 | # foo(type1, type2) (in object.name) (filename.cc:80) |
| 169 | match = re.match('^(.*) \(in (.*)\) \((.*:\d*)\)$', atos_line) |
Alexander Potapenko | be84ac8 | 2012-08-02 13:59:23 +0000 | [diff] [blame] | 170 | if DEBUG: |
Alexander Potapenko | 3f6a5c1 | 2012-09-26 13:16:42 +0000 | [diff] [blame] | 171 | print 'atos_line: ', atos_line |
Alexander Potapenko | 02a7162 | 2012-01-26 17:06:50 +0000 | [diff] [blame] | 172 | if match: |
| 173 | function_name = match.group(1) |
Alexander Potapenko | 3f6a5c1 | 2012-09-26 13:16:42 +0000 | [diff] [blame] | 174 | function_name = re.sub('\(.*?\)', '', function_name) |
Alexander Potapenko | 02a7162 | 2012-01-26 17:06:50 +0000 | [diff] [blame] | 175 | file_name = fix_filename(match.group(3)) |
Alexander Potapenko | 3f6a5c1 | 2012-09-26 13:16:42 +0000 | [diff] [blame] | 176 | return ['%s in %s %s' % (addr, function_name, file_name)] |
Alexander Potapenko | 02a7162 | 2012-01-26 17:06:50 +0000 | [diff] [blame] | 177 | else: |
Alexander Potapenko | 3f6a5c1 | 2012-09-26 13:16:42 +0000 | [diff] [blame] | 178 | return ['%s in %s' % (addr, atos_line)] |
Kostya Serebryany | 019b76f | 2011-11-30 01:07:02 +0000 | [diff] [blame] | 179 | |
Alexander Potapenko | 8aae955 | 2012-07-31 13:51:26 +0000 | [diff] [blame] | 180 | |
Alexey Samsonov | 52565d5 | 2012-09-19 08:49:53 +0000 | [diff] [blame] | 181 | # Chain several symbolizers so that if one symbolizer fails, we fall back |
| 182 | # to the next symbolizer in chain. |
Alexander Potapenko | be84ac8 | 2012-08-02 13:59:23 +0000 | [diff] [blame] | 183 | class ChainSymbolizer(Symbolizer): |
Alexey Samsonov | 52565d5 | 2012-09-19 08:49:53 +0000 | [diff] [blame] | 184 | def __init__(self, symbolizer_list): |
Alexander Potapenko | be84ac8 | 2012-08-02 13:59:23 +0000 | [diff] [blame] | 185 | super(ChainSymbolizer, self).__init__() |
Alexey Samsonov | 52565d5 | 2012-09-19 08:49:53 +0000 | [diff] [blame] | 186 | self.symbolizer_list = symbolizer_list |
Alexander Potapenko | 3f6a5c1 | 2012-09-26 13:16:42 +0000 | [diff] [blame] | 187 | |
Alexey Samsonov | 52565d5 | 2012-09-19 08:49:53 +0000 | [diff] [blame] | 188 | def symbolize(self, addr, binary, offset): |
Alexander Potapenko | 3f6a5c1 | 2012-09-26 13:16:42 +0000 | [diff] [blame] | 189 | """Overrides Symbolizer.symbolize.""" |
Alexey Samsonov | 52565d5 | 2012-09-19 08:49:53 +0000 | [diff] [blame] | 190 | for symbolizer in self.symbolizer_list: |
| 191 | if symbolizer: |
| 192 | result = symbolizer.symbolize(addr, binary, offset) |
| 193 | if result: |
| 194 | return result |
| 195 | return None |
Alexander Potapenko | 3f6a5c1 | 2012-09-26 13:16:42 +0000 | [diff] [blame] | 196 | |
Alexey Samsonov | 52565d5 | 2012-09-19 08:49:53 +0000 | [diff] [blame] | 197 | def append_symbolizer(self, symbolizer): |
| 198 | self.symbolizer_list.append(symbolizer) |
Alexander Potapenko | be84ac8 | 2012-08-02 13:59:23 +0000 | [diff] [blame] | 199 | |
| 200 | |
Alexander Potapenko | 3f6a5c1 | 2012-09-26 13:16:42 +0000 | [diff] [blame] | 201 | def BreakpadSymbolizerFactory(binary): |
| 202 | suffix = os.getenv('BREAKPAD_SUFFIX') |
Alexander Potapenko | be84ac8 | 2012-08-02 13:59:23 +0000 | [diff] [blame] | 203 | if suffix: |
| 204 | filename = binary + suffix |
| 205 | if os.access(filename, os.F_OK): |
Alexander Potapenko | 1800362 | 2012-08-15 13:58:24 +0000 | [diff] [blame] | 206 | return BreakpadSymbolizer(filename) |
Alexander Potapenko | be84ac8 | 2012-08-02 13:59:23 +0000 | [diff] [blame] | 207 | return None |
| 208 | |
| 209 | |
Alexander Potapenko | 879b1ff | 2012-08-02 14:58:04 +0000 | [diff] [blame] | 210 | def SystemSymbolizerFactory(system, addr, binary): |
| 211 | if system == 'Darwin': |
| 212 | return DarwinSymbolizer(addr, binary) |
| 213 | elif system == 'Linux': |
Alexey Samsonov | 52565d5 | 2012-09-19 08:49:53 +0000 | [diff] [blame] | 214 | return Addr2LineSymbolizer(binary) |
Alexander Potapenko | 879b1ff | 2012-08-02 14:58:04 +0000 | [diff] [blame] | 215 | |
| 216 | |
Alexander Potapenko | be84ac8 | 2012-08-02 13:59:23 +0000 | [diff] [blame] | 217 | class BreakpadSymbolizer(Symbolizer): |
| 218 | def __init__(self, filename): |
| 219 | super(BreakpadSymbolizer, self).__init__() |
| 220 | self.filename = filename |
| 221 | lines = file(filename).readlines() |
| 222 | self.files = [] |
| 223 | self.symbols = {} |
| 224 | self.address_list = [] |
| 225 | self.addresses = {} |
| 226 | # MODULE mac x86_64 A7001116478B33F18FF9BEDE9F615F190 t |
| 227 | fragments = lines[0].rstrip().split() |
| 228 | self.arch = fragments[2] |
| 229 | self.debug_id = fragments[3] |
| 230 | self.binary = ' '.join(fragments[4:]) |
| 231 | self.parse_lines(lines[1:]) |
Alexander Potapenko | 3f6a5c1 | 2012-09-26 13:16:42 +0000 | [diff] [blame] | 232 | |
Alexander Potapenko | be84ac8 | 2012-08-02 13:59:23 +0000 | [diff] [blame] | 233 | def parse_lines(self, lines): |
| 234 | cur_function_addr = '' |
| 235 | for line in lines: |
| 236 | fragments = line.split() |
| 237 | if fragments[0] == 'FILE': |
| 238 | assert int(fragments[1]) == len(self.files) |
| 239 | self.files.append(' '.join(fragments[2:])) |
| 240 | elif fragments[0] == 'PUBLIC': |
| 241 | self.symbols[int(fragments[1], 16)] = ' '.join(fragments[3:]) |
Alexander Potapenko | 1800362 | 2012-08-15 13:58:24 +0000 | [diff] [blame] | 242 | elif fragments[0] in ['CFI', 'STACK']: |
Alexander Potapenko | be84ac8 | 2012-08-02 13:59:23 +0000 | [diff] [blame] | 243 | pass |
| 244 | elif fragments[0] == 'FUNC': |
| 245 | cur_function_addr = int(fragments[1], 16) |
Alexander Potapenko | 1800362 | 2012-08-15 13:58:24 +0000 | [diff] [blame] | 246 | if not cur_function_addr in self.symbols.keys(): |
| 247 | self.symbols[cur_function_addr] = ' '.join(fragments[4:]) |
Alexander Potapenko | be84ac8 | 2012-08-02 13:59:23 +0000 | [diff] [blame] | 248 | else: |
| 249 | # Line starting with an address. |
| 250 | addr = int(fragments[0], 16) |
| 251 | self.address_list.append(addr) |
| 252 | # Tuple of symbol address, size, line, file number. |
| 253 | self.addresses[addr] = (cur_function_addr, |
| 254 | int(fragments[1], 16), |
| 255 | int(fragments[2]), |
| 256 | int(fragments[3])) |
| 257 | self.address_list.sort() |
Alexander Potapenko | 3f6a5c1 | 2012-09-26 13:16:42 +0000 | [diff] [blame] | 258 | |
Alexander Potapenko | be84ac8 | 2012-08-02 13:59:23 +0000 | [diff] [blame] | 259 | def get_sym_file_line(self, addr): |
| 260 | key = None |
| 261 | if addr in self.addresses.keys(): |
| 262 | key = addr |
| 263 | else: |
| 264 | index = bisect.bisect_left(self.address_list, addr) |
| 265 | if index == 0: |
| 266 | return None |
| 267 | else: |
| 268 | key = self.address_list[index - 1] |
| 269 | sym_id, size, line_no, file_no = self.addresses[key] |
| 270 | symbol = self.symbols[sym_id] |
| 271 | filename = self.files[file_no] |
| 272 | if addr < key + size: |
| 273 | return symbol, filename, line_no |
| 274 | else: |
| 275 | return None |
Alexander Potapenko | 3f6a5c1 | 2012-09-26 13:16:42 +0000 | [diff] [blame] | 276 | |
Alexey Samsonov | 52565d5 | 2012-09-19 08:49:53 +0000 | [diff] [blame] | 277 | def symbolize(self, addr, binary, offset): |
| 278 | if self.binary != binary: |
| 279 | return None |
Alexander Potapenko | be84ac8 | 2012-08-02 13:59:23 +0000 | [diff] [blame] | 280 | res = self.get_sym_file_line(int(offset, 16)) |
| 281 | if res: |
| 282 | function_name, file_name, line_no = res |
Alexander Potapenko | 3f6a5c1 | 2012-09-26 13:16:42 +0000 | [diff] [blame] | 283 | result = ['%s in %s %s:%d' % ( |
Alexey Samsonov | 52565d5 | 2012-09-19 08:49:53 +0000 | [diff] [blame] | 284 | addr, function_name, file_name, line_no)] |
Alexander Potapenko | 1800362 | 2012-08-15 13:58:24 +0000 | [diff] [blame] | 285 | print result |
| 286 | return result |
Alexander Potapenko | be84ac8 | 2012-08-02 13:59:23 +0000 | [diff] [blame] | 287 | else: |
| 288 | return None |
| 289 | |
| 290 | |
Alexander Potapenko | 59cc877 | 2012-09-26 12:12:41 +0000 | [diff] [blame] | 291 | class SymbolizationLoop(object): |
Alexander Potapenko | 3f6a5c1 | 2012-09-26 13:16:42 +0000 | [diff] [blame] | 292 | def __init__(self, binary_name_filter=None): |
| 293 | # Used by clients who may want to supply a different binary name. |
| 294 | # E.g. in Chrome several binaries may share a single .dSYM. |
| 295 | self.binary_name_filter = binary_name_filter |
Alexander Potapenko | 59cc877 | 2012-09-26 12:12:41 +0000 | [diff] [blame] | 296 | self.system = os.uname()[0] |
| 297 | if self.system in ['Linux', 'Darwin']: |
| 298 | self.llvm_symbolizer = LLVMSymbolizerFactory(self.system) |
| 299 | else: |
Alexander Potapenko | 3f6a5c1 | 2012-09-26 13:16:42 +0000 | [diff] [blame] | 300 | raise Exception('Unknown system') |
| 301 | |
Alexander Potapenko | 59cc877 | 2012-09-26 12:12:41 +0000 | [diff] [blame] | 302 | def symbolize_address(self, addr, binary, offset): |
| 303 | # Use the chain of symbolizers: |
| 304 | # Breakpad symbolizer -> LLVM symbolizer -> addr2line/atos |
| 305 | # (fall back to next symbolizer if the previous one fails). |
Alexander Potapenko | 3f6a5c1 | 2012-09-26 13:16:42 +0000 | [diff] [blame] | 306 | if not binary in symbolizers: |
Alexander Potapenko | 59cc877 | 2012-09-26 12:12:41 +0000 | [diff] [blame] | 307 | symbolizers[binary] = ChainSymbolizer( |
Alexander Potapenko | 3f6a5c1 | 2012-09-26 13:16:42 +0000 | [diff] [blame] | 308 | [BreakpadSymbolizerFactory(binary), self.llvm_symbolizer]) |
Alexey Samsonov | 52565d5 | 2012-09-19 08:49:53 +0000 | [diff] [blame] | 309 | result = symbolizers[binary].symbolize(addr, binary, offset) |
Alexander Potapenko | 59cc877 | 2012-09-26 12:12:41 +0000 | [diff] [blame] | 310 | if result is None: |
| 311 | # Initialize system symbolizer only if other symbolizers failed. |
| 312 | symbolizers[binary].append_symbolizer( |
| 313 | SystemSymbolizerFactory(self.system, addr, binary)) |
| 314 | result = symbolizers[binary].symbolize(addr, binary, offset) |
| 315 | # The system symbolizer must produce some result. |
Alexander Potapenko | 3f6a5c1 | 2012-09-26 13:16:42 +0000 | [diff] [blame] | 316 | assert result |
Alexander Potapenko | 59cc877 | 2012-09-26 12:12:41 +0000 | [diff] [blame] | 317 | return result |
Alexander Potapenko | 3f6a5c1 | 2012-09-26 13:16:42 +0000 | [diff] [blame] | 318 | |
| 319 | def print_symbolized_lines(self, symbolized_lines): |
| 320 | if not symbolized_lines: |
| 321 | print self.current_line |
| 322 | else: |
| 323 | for symbolized_frame in symbolized_lines: |
| 324 | print ' #' + str(self.frame_no) + ' ' + symbolized_frame.rstrip() |
| 325 | self.frame_no += 1 |
| 326 | |
| 327 | def process_stdin(self): |
| 328 | self.frame_no = 0 |
Alexander Potapenko | 8aae955 | 2012-07-31 13:51:26 +0000 | [diff] [blame] | 329 | for line in sys.stdin: |
Alexander Potapenko | 3f6a5c1 | 2012-09-26 13:16:42 +0000 | [diff] [blame] | 330 | self.current_line = line.rstrip() |
Alexey Samsonov | 52565d5 | 2012-09-19 08:49:53 +0000 | [diff] [blame] | 331 | #0 0x7f6e35cf2e45 (/blah/foo.so+0x11fe45) |
| 332 | stack_trace_line_format = ( |
Alexander Potapenko | 3f6a5c1 | 2012-09-26 13:16:42 +0000 | [diff] [blame] | 333 | '^( *#([0-9]+) *)(0x[0-9a-f]+) *\((.*)\+(0x[0-9a-f]+)\)') |
Alexey Samsonov | 52565d5 | 2012-09-19 08:49:53 +0000 | [diff] [blame] | 334 | match = re.match(stack_trace_line_format, line) |
| 335 | if not match: |
Alexander Potapenko | 3f6a5c1 | 2012-09-26 13:16:42 +0000 | [diff] [blame] | 336 | print self.current_line |
Alexey Samsonov | 52565d5 | 2012-09-19 08:49:53 +0000 | [diff] [blame] | 337 | continue |
| 338 | if DEBUG: |
| 339 | print line |
Alexander Potapenko | 3f6a5c1 | 2012-09-26 13:16:42 +0000 | [diff] [blame] | 340 | _, frameno_str, addr, binary, offset = match.groups() |
| 341 | if frameno_str == '0': |
Alexey Samsonov | 52565d5 | 2012-09-19 08:49:53 +0000 | [diff] [blame] | 342 | # Assume that frame #0 is the first frame of new stack trace. |
Alexander Potapenko | 3f6a5c1 | 2012-09-26 13:16:42 +0000 | [diff] [blame] | 343 | self.frame_no = 0 |
| 344 | original_binary = binary |
| 345 | if self.binary_name_filter: |
| 346 | binary = self.binary_name_filter(binary) |
Alexander Potapenko | 59cc877 | 2012-09-26 12:12:41 +0000 | [diff] [blame] | 347 | symbolized_line = self.symbolize_address(addr, binary, offset) |
Alexey Samsonov | 52565d5 | 2012-09-19 08:49:53 +0000 | [diff] [blame] | 348 | if not symbolized_line: |
Alexander Potapenko | 3f6a5c1 | 2012-09-26 13:16:42 +0000 | [diff] [blame] | 349 | if original_binary != binary: |
| 350 | symbolized_line = self.symbolize_address(addr, binary, offset) |
| 351 | self.print_symbolized_lines(symbolized_line) |
Alexander Potapenko | 8aae955 | 2012-07-31 13:51:26 +0000 | [diff] [blame] | 352 | |
| 353 | |
| 354 | if __name__ == '__main__': |
Alexander Potapenko | 59cc877 | 2012-09-26 12:12:41 +0000 | [diff] [blame] | 355 | loop = SymbolizationLoop() |
Alexander Potapenko | 3f6a5c1 | 2012-09-26 13:16:42 +0000 | [diff] [blame] | 356 | loop.process_stdin() |