[Fuchsia] Symbolize stderr in blink web tests
Previously call stacks from crashed web tests wasn't symbolized properly.
Updated the scripts to run the symbolizer as a stderr filter, which
makes it easier to debug layout test crashes.
Also fixed file descriptor leak in run_package.py
Change-Id: I2622865ab930535567b16e70ca9e50610a93761f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1584779
Commit-Queue: Sergey Ulanov <sergeyu@chromium.org>
Reviewed-by: Kevin Marshall <kmarshall@chromium.org>
Reviewed-by: Dirk Pranke <dpranke@chromium.org>
Cr-Commit-Position: refs/heads/master@{#654220}
diff --git a/build/fuchsia/run_package.py b/build/fuchsia/run_package.py
index e8ea07d..638d3b7 100644
--- a/build/fuchsia/run_package.py
+++ b/build/fuchsia/run_package.py
@@ -42,16 +42,20 @@
def __init__(self, streams):
assert len(streams) > 0
self._streams = streams
- self._read_pipe, write_pipe = os.pipe()
+ self._output_stream = None
+ self._thread = None
+
+ def Start(self):
+ """Returns a pipe to the merged output stream."""
+
+ read_pipe, write_pipe = os.pipe()
+
# Disable buffering for the stream to make sure there is no delay in logs.
self._output_stream = os.fdopen(write_pipe, 'w', 0)
self._thread = threading.Thread(target=self._Run)
-
- def Start(self):
- """Returns a file descriptor to the merged output stream."""
-
self._thread.start();
- return self._read_pipe
+
+ return os.fdopen(read_pipe, 'r')
def _Run(self):
streams_by_fd = {}
@@ -190,17 +194,17 @@
stderr=subprocess.STDOUT)
if system_logger:
- output_fd = MergedInputStream([process.stdout,
- system_logger.stdout]).Start()
+ output_stream = MergedInputStream([process.stdout,
+ system_logger.stdout]).Start()
else:
- output_fd = process.stdout.fileno()
+ output_stream = process.stdout
# Run the log data through the symbolizer process.
build_ids_paths = map(
lambda package_path: os.path.join(
os.path.dirname(package_path), 'ids.txt'),
[package_path] + package_deps)
- output_stream = SymbolizerFilter(output_fd, build_ids_paths)
+ output_stream = SymbolizerFilter(output_stream, build_ids_paths)
for next_line in output_stream:
print next_line.rstrip()
diff --git a/build/fuchsia/symbolizer.py b/build/fuchsia/symbolizer.py
index 0b7c39e..18f583f 100644
--- a/build/fuchsia/symbolizer.py
+++ b/build/fuchsia/symbolizer.py
@@ -9,13 +9,13 @@
from common import SDK_ROOT
-def SymbolizerFilter(input_fd, build_ids_files):
- """Symbolizes an output stream from a process.
+def RunSymbolizer(input_pipe, build_ids_files):
+ """Starts a symbolizer process.
- input_fd: A file descriptor of the stream to be symbolized.
+ input_pipe: Input pipe to be symbolized.
build_ids_file: Path to the ids.txt file which maps build IDs to
unstripped binaries on the filesystem.
- Returns a generator that yields symbolized process output."""
+ Returns a Popen object for the started process."""
llvm_symbolizer_path = os.path.join(SDK_ROOT, os.pardir, os.pardir,
'llvm-build', 'Release+Asserts', 'bin',
@@ -28,11 +28,19 @@
symbolizer_cmd.extend(['-ids', build_ids_file])
logging.info('Running "%s".' % ' '.join(symbolizer_cmd))
- symbolizer_proc = subprocess.Popen(
- symbolizer_cmd,
- stdout=subprocess.PIPE,
- stdin=input_fd,
- close_fds=True)
+ return subprocess.Popen(symbolizer_cmd, stdout=subprocess.PIPE,
+ stdin=input_pipe, close_fds=True)
+
+
+def SymbolizerFilter(input_pipe, build_ids_files):
+ """Symbolizes an output stream from a process.
+
+ input_pipe: Input pipe to be symbolized.
+ build_ids_file: Path to the ids.txt file which maps build IDs to
+ unstripped binaries on the filesystem.
+ Returns a generator that yields symbolized process output."""
+
+ symbolizer_proc = RunSymbolizer(input_pipe, build_ids_files)
while True:
line = symbolizer_proc.stdout.readline()
diff --git a/third_party/blink/tools/blinkpy/web_tests/port/fuchsia.py b/third_party/blink/tools/blinkpy/web_tests/port/fuchsia.py
index dd5b0539..978db91 100644
--- a/third_party/blink/tools/blinkpy/web_tests/port/fuchsia.py
+++ b/third_party/blink/tools/blinkpy/web_tests/port/fuchsia.py
@@ -48,6 +48,7 @@
# pylint: disable=invalid-name
fuchsia_target = None
qemu_target = None
+symbolizer = None
# pylint: enable=invalid-name
@@ -62,7 +63,9 @@
global fuchsia_target
import target as fuchsia_target
global qemu_target
- import qemu_target as qemu_target
+ import qemu_target
+ global symbolizer
+ import symbolizer
# pylint: enable=import-error
# pylint: enable=invalid-name
# pylint: disable=redefined-outer-name
@@ -266,6 +269,10 @@
def get_target_host(self):
return self._target_host
+ def get_build_ids_path(self):
+ package_path = self._path_to_driver()
+ return os.path.join(os.path.dirname(package_path), 'ids.txt')
+
class ChromiumFuchsiaDriver(driver.Driver):
def __init__(self, port, worker_number, no_timeout=False):
@@ -294,6 +301,7 @@
treat_no_data_as_crash=False, more_logging=False):
super(FuchsiaServerProcess, self).__init__(
port_obj, name, cmd, env, treat_no_data_as_crash, more_logging)
+ self._symbolizer_proc = None
def _start(self):
if self._proc:
@@ -335,4 +343,15 @@
proc.stdin.close()
proc.stdin = stdin_pipe
+ # Run symbolizer to filter the stderr stream.
+ self._symbolizer_proc = symbolizer.RunSymbolizer(
+ proc.stderr, [self._port.get_build_ids_path()]);
+ proc.stderr = self._symbolizer_proc.stdout
+
self._set_proc(proc)
+
+ def stop(self, timeout_secs=0.0):
+ result = super(FuchsiaServerProcess, self).stop(timeout_secs)
+ if self._symbolizer_proc:
+ self._symbolizer_proc.kill()
+ return result