summaryrefslogtreecommitdiff
path: root/lib/asan/scripts/asan_symbolize.py
diff options
context:
space:
mode:
Diffstat (limited to 'lib/asan/scripts/asan_symbolize.py')
-rwxr-xr-xlib/asan/scripts/asan_symbolize.py63
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 = (