Diff
Modified: trunk/Tools/ChangeLog (232785 => 232786)
--- trunk/Tools/ChangeLog 2018-06-13 01:09:28 UTC (rev 232785)
+++ trunk/Tools/ChangeLog 2018-06-13 01:55:20 UTC (rev 232786)
@@ -1,3 +1,20 @@
+2018-06-12 Thibault Saunier <tsaun...@igalia.com>
+
+ webkitpy: Implement coredumpctl support on linux
+ https://bugs.webkit.org/show_bug.cgi?id=184039
+
+ Reviewed by Daniel Bates.
+
+ And start using an Executive to run subprocesses
+ in GDBCrashLogGenerator.
+
+ Unit tests adapted to the new API and still passing.
+
+ * Scripts/webkitpy/port/linux_get_crash_log.py:
+ (GDBCrashLogGenerator):
+ (GDBCrashLogGenerator._get_trace_from_systemd):
+ (GDBCrashLogGenerator.generate_crash_log):
+
2018-06-12 Valerie R Young <vale...@bocoup.com>
test262/Runner.pm: fix one test (can't find jsc)
Modified: trunk/Tools/Scripts/webkitpy/port/gtk.py (232785 => 232786)
--- trunk/Tools/Scripts/webkitpy/port/gtk.py 2018-06-13 01:09:28 UTC (rev 232785)
+++ trunk/Tools/Scripts/webkitpy/port/gtk.py 2018-06-13 01:55:20 UTC (rev 232786)
@@ -227,7 +227,8 @@
return super(GtkPort, self).check_sys_deps(needs_http) and self._driver_class().check_driver(self)
def _get_crash_log(self, name, pid, stdout, stderr, newer_than, target_host=None):
- return GDBCrashLogGenerator(name, pid, newer_than, self._filesystem, self._path_to_driver).generate_crash_log(stdout, stderr)
+ return GDBCrashLogGenerator(self._executive, name, pid, newer_than,
+ self._filesystem, self._path_to_driver).generate_crash_log(stdout, stderr)
def test_expectations_file_position(self):
# GTK port baseline search path is gtk -> wk2 -> generic (as gtk-wk2 and gtk baselines are merged), so port test expectations file is at third to last position.
Modified: trunk/Tools/Scripts/webkitpy/port/linux_get_crash_log.py (232785 => 232786)
--- trunk/Tools/Scripts/webkitpy/port/linux_get_crash_log.py 2018-06-13 01:09:28 UTC (rev 232785)
+++ trunk/Tools/Scripts/webkitpy/port/linux_get_crash_log.py 2018-06-13 01:55:20 UTC (rev 232786)
@@ -27,22 +27,31 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+import datetime
+import os
+import re
+import shutil
import subprocess
-import os
+import tempfile
+import time
+from webkitpy.common.system.executive import ScriptError
+
class GDBCrashLogGenerator(object):
- def __init__(self, name, pid, newer_than, filesystem, path_to_driver):
+
+ def __init__(self, executive, name, pid, newer_than, filesystem, path_to_driver):
self.name = name
self.pid = pid
self.newer_than = newer_than
self._filesystem = filesystem
self._path_to_driver = path_to_driver
+ self._executive = executive
def _get_gdb_output(self, coredump_path):
process_name = self._filesystem.join(os.path.dirname(str(self._path_to_driver())), self.name)
cmd = ['gdb', '-ex', 'thread apply all bt 1024', '--batch', process_name, coredump_path]
- proc = subprocess.Popen(cmd, stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ proc = self._executive.popen(cmd, stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout, stderr = proc.communicate()
errors = [stderr_line.strip().decode('utf8', 'ignore') for stderr_line in stderr.splitlines()]
if proc.returncode != 0:
@@ -49,6 +58,39 @@
stdout = ('ERROR: The gdb process exited with non-zero return code %s\n\n' % proc.returncode) + stdout
return (stdout.decode('utf8', 'ignore'), errors)
+ def _get_trace_from_systemd(self, pid):
+ # Letting up to 5 seconds for the backtrace to be generated on the systemd side
+ for try_number in range(5):
+ if try_number != 0:
+ # Looping, it means we consider the logs might not be ready yet.
+ time.sleep(1)
+
+ try:
+ info = self._executive.run_command(['coredumpctl', 'info', str(pid)], return_stderr=True)
+ except ScriptError, OSError:
+ continue
+
+ if self.newer_than:
+ found_newer = False
+ # Coredumpctl will use the latest core dump with the specified PID
+ # assume it is the right one.
+ for timestamp in re.findall(r'Timestamp:.*(\d{4}-\d+-\d+ \d+:\d+:\d+)', info):
+ date = time.mktime(datetime.datetime.strptime(timestamp, "%Y-%m-%d %H:%M:%S").timetuple())
+ if date > self.newer_than:
+ found_newer = True
+ break
+
+ if not found_newer:
+ continue
+
+ temp_file = tempfile.NamedTemporaryFile()
+ if self._executive.run_command(['coredumpctl', 'dump', pid, '--output', temp_file.name], return_exit_code=True):
+ continue
+
+ return self._get_gdb_output(temp_file.name)
+
+ return '', []
+
def generate_crash_log(self, stdout, stderr):
pid_representation = str(self.pid or '<unknown>')
log_directory = os.environ.get("WEBKIT_CORE_DUMPS_DIRECTORY")
@@ -62,17 +104,27 @@
return filename == expected_crash_dump_filename
return filename.find(self.name) > -1
+ # Poor man which, ignore any failure.
+ try:
+ coredumpctl = not self._executive.run_command(['coredumpctl', '--version'], return_exit_code=True)
+ except:
+ coredumpctl = False
+
if log_directory:
- dumps = self._filesystem.files_under(log_directory, file_filter=match_filename)
+ dumps = self._filesystem.files_under(
+ log_directory, file_filter=match_filename)
if dumps:
# Get the most recent coredump matching the pid and/or process name.
coredump_path = list(reversed(sorted(dumps)))[0]
if not self.newer_than or self._filesystem.mtime(coredump_path) > self.newer_than:
crash_log, errors = self._get_gdb_output(coredump_path)
+ elif coredumpctl:
+ crash_log, errors = self._get_trace_from_systemd(pid_representation)
stderr_lines = errors + str(stderr or '<empty>').decode('utf8', 'ignore').splitlines()
errors_str = '\n'.join(('STDERR: ' + stderr_line) for stderr_line in stderr_lines)
- cppfilt_proc = subprocess.Popen(['c++filt', ], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ cppfilt_proc = self._executive.popen(
+ ['c++filt'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
errors_str = cppfilt_proc.communicate(errors_str)[0]
if not crash_log:
Modified: trunk/Tools/Scripts/webkitpy/port/linux_get_crash_log_unittest.py (232785 => 232786)
--- trunk/Tools/Scripts/webkitpy/port/linux_get_crash_log_unittest.py 2018-06-13 01:09:28 UTC (rev 232785)
+++ trunk/Tools/Scripts/webkitpy/port/linux_get_crash_log_unittest.py 2018-06-13 01:55:20 UTC (rev 232786)
@@ -31,8 +31,10 @@
import sys
import unittest
+from webkitpy.common.system.executive_mock import MockExecutive
+from webkitpy.common.system.executive_mock import MockProcess
+from webkitpy.common.system.filesystem_mock import MockFileSystem
from webkitpy.port.linux_get_crash_log import GDBCrashLogGenerator
-from webkitpy.common.system.filesystem_mock import MockFileSystem
class GDBCrashLogGeneratorTest(unittest.TestCase):
@@ -41,7 +43,10 @@
if sys.platform.startswith('win'):
return
- generator = GDBCrashLogGenerator('DumpRenderTree', 28529, newer_than=None, filesystem=MockFileSystem({'/path/to/coredumps': ''}), path_to_driver=None)
+ executive = MockExecutive()
+ executive._proc = MockProcess()
+ executive._proc.stdout = 'STDERR: <empty>'
+ generator = GDBCrashLogGenerator(executive, 'DumpRenderTree', 28529, newer_than=None, filesystem=MockFileSystem({'/path/to/coredumps': ''}), path_to_driver=None)
core_directory = os.environ.get('WEBKIT_CORE_DUMPS_DIRECTORY', '/path/to/coredumps')
core_pattern = generator._filesystem.join(core_directory, "core-pid_%p.dump")
Modified: trunk/Tools/Scripts/webkitpy/port/wpe.py (232785 => 232786)
--- trunk/Tools/Scripts/webkitpy/port/wpe.py 2018-06-13 01:09:28 UTC (rev 232785)
+++ trunk/Tools/Scripts/webkitpy/port/wpe.py 2018-06-13 01:55:20 UTC (rev 232786)
@@ -107,4 +107,4 @@
return 2
def _get_crash_log(self, name, pid, stdout, stderr, newer_than, target_host=None):
- return GDBCrashLogGenerator(name, pid, newer_than, self._filesystem, self._path_to_driver).generate_crash_log(stdout, stderr)
+ return GDBCrashLogGenerator(self._executive, name, pid, newer_than, self._filesystem, self._path_to_driver).generate_crash_log(stdout, stderr)