diff options
Diffstat (limited to 'lib/asan/scripts/asan_symbolize.py')
-rwxr-xr-x | lib/asan/scripts/asan_symbolize.py | 63 |
1 files changed, 45 insertions, 18 deletions
diff --git a/lib/asan/scripts/asan_symbolize.py b/lib/asan/scripts/asan_symbolize.py index bd3bf1e9b53e..a398fcf10361 100755 --- a/lib/asan/scripts/asan_symbolize.py +++ b/lib/asan/scripts/asan_symbolize.py @@ -10,14 +10,14 @@ import bisect import getopt import os +import pty import re import subprocess import sys +import termios llvm_symbolizer = None symbolizers = {} -filetypes = {} -vmaddrs = {} DEBUG = False demangle = False; @@ -101,8 +101,10 @@ class LLVMSymbolizer(Symbolizer): def LLVMSymbolizerFactory(system): symbolizer_path = os.getenv('LLVM_SYMBOLIZER_PATH') if not symbolizer_path: - # Assume llvm-symbolizer is in PATH. - symbolizer_path = 'llvm-symbolizer' + symbolizer_path = os.getenv('ASAN_SYMBOLIZER_PATH') + if not symbolizer_path: + # Assume llvm-symbolizer is in PATH. + symbolizer_path = 'llvm-symbolizer' return LLVMSymbolizer(symbolizer_path) @@ -137,6 +139,36 @@ class Addr2LineSymbolizer(Symbolizer): return ['%s in %s %s' % (addr, function_name, file_name)] +class UnbufferedLineConverter(object): + """ + Wrap a child process that responds to each line of input with one line of + output. Uses pty to trick the child into providing unbuffered output. + """ + def __init__(self, args, close_stderr=False): + pid, fd = pty.fork() + if pid == 0: + # We're the child. Transfer control to command. + if close_stderr: + dev_null = os.open('/dev/null', 0) + os.dup2(dev_null, 2) + os.execvp(args[0], args) + else: + # Disable echoing. + attr = termios.tcgetattr(fd) + attr[3] = attr[3] & ~termios.ECHO + termios.tcsetattr(fd, termios.TCSANOW, attr) + # Set up a file()-like interface to the child process + self.r = os.fdopen(fd, "r", 1) + self.w = os.fdopen(os.dup(fd), "w", 1) + + def convert(self, line): + self.w.write(line + "\n") + return self.readline() + + def readline(self): + return self.r.readline().rstrip() + + class DarwinSymbolizer(Symbolizer): def __init__(self, addr, binary): super(DarwinSymbolizer, self).__init__() @@ -146,29 +178,21 @@ class DarwinSymbolizer(Symbolizer): self.arch = 'x86_64' else: self.arch = 'i386' - self.vmaddr = None - self.pipe = None - - def write_addr_to_pipe(self, offset): - print >> self.pipe.stdin, '0x%x' % int(offset, 16) + self.open_atos() def open_atos(self): if DEBUG: print 'atos -o %s -arch %s' % (self.binary, self.arch) cmdline = ['atos', '-o', self.binary, '-arch', self.arch] - self.pipe = subprocess.Popen(cmdline, - stdin=subprocess.PIPE, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) + self.atos = UnbufferedLineConverter(cmdline, close_stderr=True) def symbolize(self, addr, binary, offset): """Overrides Symbolizer.symbolize.""" if self.binary != binary: return None - self.open_atos() - self.write_addr_to_pipe(offset) - self.pipe.stdin.close() - atos_line = self.pipe.stdout.readline().rstrip() + atos_line = self.atos.convert('0x%x' % int(offset, 16)) + while "got symbolicator for" in atos_line: + atos_line = self.atos.readline() # A well-formed atos response looks like this: # foo(type1, type2) (in object.name) (filename.cc:80) match = re.match('^(.*) \(in (.*)\) \((.*:\d*)\)$', atos_line) @@ -331,7 +355,10 @@ class SymbolizationLoop(object): def process_stdin(self): self.frame_no = 0 - for line in sys.stdin: + while True: + line = sys.stdin.readline() + if not line: + break self.current_line = line.rstrip() #0 0x7f6e35cf2e45 (/blah/foo.so+0x11fe45) stack_trace_line_format = ( |