OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 #===- lib/asan/scripts/asan_symbolize.py -----------------------------------===# | 2 #===- lib/asan/scripts/asan_symbolize.py -----------------------------------===# |
3 # | 3 # |
4 # The LLVM Compiler Infrastructure | 4 # The LLVM Compiler Infrastructure |
5 # | 5 # |
6 # This file is distributed under the University of Illinois Open Source | 6 # This file is distributed under the University of Illinois Open Source |
7 # License. See LICENSE.TXT for details. | 7 # License. See LICENSE.TXT for details. |
8 # | 8 # |
9 #===------------------------------------------------------------------------===# | 9 #===------------------------------------------------------------------------===# |
10 import argparse | 10 import argparse |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
59 offset: instruction offset in the @binary. | 59 offset: instruction offset in the @binary. |
60 Returns: | 60 Returns: |
61 list of strings (one string for each inlined frame) describing | 61 list of strings (one string for each inlined frame) describing |
62 the code locations for this instruction (that is, function name, file | 62 the code locations for this instruction (that is, function name, file |
63 name, line and column numbers). | 63 name, line and column numbers). |
64 """ | 64 """ |
65 return None | 65 return None |
66 | 66 |
67 | 67 |
68 class LLVMSymbolizer(Symbolizer): | 68 class LLVMSymbolizer(Symbolizer): |
69 def __init__(self, symbolizer_path, addr): | 69 def __init__(self, symbolizer_path, default_arch, system, dsym_hints=[]): |
70 super(LLVMSymbolizer, self).__init__() | 70 super(LLVMSymbolizer, self).__init__() |
71 self.symbolizer_path = symbolizer_path | 71 self.symbolizer_path = symbolizer_path |
72 self.default_arch = guess_arch(addr) | 72 self.default_arch = default_arch |
| 73 self.system = system |
| 74 self.dsym_hints = dsym_hints |
73 self.pipe = self.open_llvm_symbolizer() | 75 self.pipe = self.open_llvm_symbolizer() |
74 | 76 |
75 def open_llvm_symbolizer(self): | 77 def open_llvm_symbolizer(self): |
76 cmd = [self.symbolizer_path, | 78 cmd = [self.symbolizer_path, |
77 '--use-symbol-table=true', | 79 '--use-symbol-table=true', |
78 '--demangle=%s' % demangle, | 80 '--demangle=%s' % demangle, |
79 '--functions=short', | 81 '--functions=short', |
80 '--inlining=true', | 82 '--inlining=true', |
81 '--default-arch=%s' % self.default_arch] | 83 '--default-arch=%s' % self.default_arch] |
| 84 if self.system == 'Darwin': |
| 85 for hint in self.dsym_hints: |
| 86 cmd.append('-dsym-hint=%s' % hint) |
82 if DEBUG: | 87 if DEBUG: |
83 print ' '.join(cmd) | 88 print ' '.join(cmd) |
84 try: | 89 try: |
85 result = subprocess.Popen(cmd, stdin=subprocess.PIPE, | 90 result = subprocess.Popen(cmd, stdin=subprocess.PIPE, |
86 stdout=subprocess.PIPE) | 91 stdout=subprocess.PIPE) |
87 except OSError: | 92 except OSError: |
88 result = None | 93 result = None |
89 return result | 94 return result |
90 | 95 |
91 def symbolize(self, addr, binary, offset): | 96 def symbolize(self, addr, binary, offset): |
92 """Overrides Symbolizer.symbolize.""" | 97 """Overrides Symbolizer.symbolize.""" |
93 if not self.pipe: | 98 if not self.pipe: |
94 return None | 99 return None |
95 result = [] | 100 result = [] |
96 try: | 101 try: |
97 symbolizer_input = '%s %s' % (binary, offset) | 102 symbolizer_input = '"%s" %s' % (binary, offset) |
98 if DEBUG: | 103 if DEBUG: |
99 print symbolizer_input | 104 print symbolizer_input |
100 print >> self.pipe.stdin, symbolizer_input | 105 print >> self.pipe.stdin, symbolizer_input |
101 while True: | 106 while True: |
102 function_name = self.pipe.stdout.readline().rstrip() | 107 function_name = self.pipe.stdout.readline().rstrip() |
103 if not function_name: | 108 if not function_name: |
104 break | 109 break |
105 file_name = self.pipe.stdout.readline().rstrip() | 110 file_name = self.pipe.stdout.readline().rstrip() |
106 file_name = fix_filename(file_name) | 111 file_name = fix_filename(file_name) |
107 if (not function_name.startswith('??') or | 112 if (not function_name.startswith('??') or |
108 not file_name.startswith('??')): | 113 not file_name.startswith('??')): |
109 # Append only non-trivial frames. | 114 # Append only non-trivial frames. |
110 result.append('%s in %s %s' % (addr, function_name, | 115 result.append('%s in %s %s' % (addr, function_name, |
111 file_name)) | 116 file_name)) |
112 except Exception: | 117 except Exception: |
113 result = [] | 118 result = [] |
114 if not result: | 119 if not result: |
115 result = None | 120 result = None |
116 return result | 121 return result |
117 | 122 |
118 | 123 |
119 def LLVMSymbolizerFactory(system, addr): | 124 def LLVMSymbolizerFactory(system, default_arch, dsym_hints=[]): |
120 symbolizer_path = os.getenv('LLVM_SYMBOLIZER_PATH') | 125 symbolizer_path = os.getenv('LLVM_SYMBOLIZER_PATH') |
121 if not symbolizer_path: | 126 if not symbolizer_path: |
122 symbolizer_path = os.getenv('ASAN_SYMBOLIZER_PATH') | 127 symbolizer_path = os.getenv('ASAN_SYMBOLIZER_PATH') |
123 if not symbolizer_path: | 128 if not symbolizer_path: |
124 # Assume llvm-symbolizer is in PATH. | 129 # Assume llvm-symbolizer is in PATH. |
125 symbolizer_path = 'llvm-symbolizer' | 130 symbolizer_path = 'llvm-symbolizer' |
126 return LLVMSymbolizer(symbolizer_path, addr) | 131 return LLVMSymbolizer(symbolizer_path, default_arch, system, dsym_hints) |
127 | 132 |
128 | 133 |
129 class Addr2LineSymbolizer(Symbolizer): | 134 class Addr2LineSymbolizer(Symbolizer): |
130 def __init__(self, binary): | 135 def __init__(self, binary): |
131 super(Addr2LineSymbolizer, self).__init__() | 136 super(Addr2LineSymbolizer, self).__init__() |
132 self.binary = binary | 137 self.binary = binary |
133 self.pipe = self.open_addr2line() | 138 self.pipe = self.open_addr2line() |
134 | 139 |
135 def open_addr2line(self): | 140 def open_addr2line(self): |
136 addr2line_tool = 'addr2line' | 141 addr2line_tool = 'addr2line' |
(...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
328 function_name, file_name, line_no = res | 333 function_name, file_name, line_no = res |
329 result = ['%s in %s %s:%d' % ( | 334 result = ['%s in %s %s:%d' % ( |
330 addr, function_name, file_name, line_no)] | 335 addr, function_name, file_name, line_no)] |
331 print result | 336 print result |
332 return result | 337 return result |
333 else: | 338 else: |
334 return None | 339 return None |
335 | 340 |
336 | 341 |
337 class SymbolizationLoop(object): | 342 class SymbolizationLoop(object): |
338 def __init__(self, binary_name_filter=None): | 343 def __init__(self, binary_name_filter=None, dsym_hint_producer=None): |
339 # Used by clients who may want to supply a different binary name. | 344 # Used by clients who may want to supply a different binary name. |
340 # E.g. in Chrome several binaries may share a single .dSYM. | 345 # E.g. in Chrome several binaries may share a single .dSYM. |
341 self.binary_name_filter = binary_name_filter | 346 self.binary_name_filter = binary_name_filter |
| 347 self.dsym_hint_producer = dsym_hint_producer |
342 self.system = os.uname()[0] | 348 self.system = os.uname()[0] |
343 if self.system not in ['Linux', 'Darwin', 'FreeBSD']: | 349 if self.system not in ['Linux', 'Darwin', 'FreeBSD']: |
344 raise Exception('Unknown system') | 350 raise Exception('Unknown system') |
345 self.llvm_symbolizer = None | 351 self.llvm_symbolizers = {} |
| 352 self.last_llvm_symbolizer = None |
| 353 self.dsym_hints = set([]) |
346 self.frame_no = 0 | 354 self.frame_no = 0 |
347 | 355 |
348 def symbolize_address(self, addr, binary, offset): | 356 def symbolize_address(self, addr, binary, offset): |
349 # Initialize llvm-symbolizer lazily. | 357 # On non-Darwin (i.e. on platforms without .dSYM debug info) always use |
350 if not self.llvm_symbolizer: | 358 # a single symbolizer binary. |
351 self.llvm_symbolizer = LLVMSymbolizerFactory(self.system, addr) | 359 # On Darwin, if the dsym hint producer is present: |
| 360 # 1. check whether we've seen this binary already; if so, |
| 361 # use |llvm_symbolizers[binary]|; |
| 362 # 2. otherwise check if we've seen this hint already; if so, |
| 363 # reuse |last_llvm_symbolizer|; |
| 364 # 3. otherwise create a new symbolizer and pass all currently known |
| 365 # .dSYM hints to it. |
| 366 use_last_symbolizer = True |
| 367 if not binary in self.llvm_symbolizers: |
| 368 if self.system == 'Darwin' and self.dsym_hint_producer: |
| 369 dsym_hints = self.dsym_hint_producer(binary) |
| 370 for dsym_hint in dsym_hints: |
| 371 if not dsym_hint in self.dsym_hints: |
| 372 use_last_symbolizer = False |
| 373 self.dsym_hints.add(dsym_hint) |
| 374 if self.last_llvm_symbolizer and use_last_symbolizer: |
| 375 self.llvm_symbolizers[binary] = self.last_llvm_symbolizer |
| 376 else: |
| 377 self.last_llvm_symbolizer = LLVMSymbolizerFactory( |
| 378 self.system, guess_arch(addr), self.dsym_hints) |
| 379 self.llvm_symbolizers[binary] = self.last_llvm_symbolizer |
352 # Use the chain of symbolizers: | 380 # Use the chain of symbolizers: |
353 # Breakpad symbolizer -> LLVM symbolizer -> addr2line/atos | 381 # Breakpad symbolizer -> LLVM symbolizer -> addr2line/atos |
354 # (fall back to next symbolizer if the previous one fails). | 382 # (fall back to next symbolizer if the previous one fails). |
355 if not binary in symbolizers: | 383 if not binary in symbolizers: |
356 symbolizers[binary] = ChainSymbolizer( | 384 symbolizers[binary] = ChainSymbolizer( |
357 [BreakpadSymbolizerFactory(binary), self.llvm_symbolizer]) | 385 [BreakpadSymbolizerFactory(binary), self.llvm_symbolizers[binary]]) |
358 result = symbolizers[binary].symbolize(addr, binary, offset) | 386 result = symbolizers[binary].symbolize(addr, binary, offset) |
359 if result is None: | 387 if result is None: |
360 # Initialize system symbolizer only if other symbolizers failed. | 388 # Initialize system symbolizer only if other symbolizers failed. |
361 symbolizers[binary].append_symbolizer( | 389 symbolizers[binary].append_symbolizer( |
362 SystemSymbolizerFactory(self.system, addr, binary)) | 390 SystemSymbolizerFactory(self.system, addr, binary)) |
363 result = symbolizers[binary].symbolize(addr, binary, offset) | 391 result = symbolizers[binary].symbolize(addr, binary, offset) |
364 # The system symbolizer must produce some result. | 392 # The system symbolizer must produce some result. |
365 assert result | 393 assert result |
366 return result | 394 return result |
367 | 395 |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
432 binary_name_filter = sysroot_path_filter | 460 binary_name_filter = sysroot_path_filter |
433 sysroot_path = args.s | 461 sysroot_path = args.s |
434 if args.c: | 462 if args.c: |
435 binutils_prefix = args.c | 463 binutils_prefix = args.c |
436 if args.logfile: | 464 if args.logfile: |
437 logfile = args.logfile | 465 logfile = args.logfile |
438 else: | 466 else: |
439 logfile = sys.stdin | 467 logfile = sys.stdin |
440 loop = SymbolizationLoop(binary_name_filter) | 468 loop = SymbolizationLoop(binary_name_filter) |
441 loop.process_logfile() | 469 loop.process_logfile() |
OLD | NEW |