Title: [232786] trunk/Tools
Revision
232786
Author
commit-qu...@webkit.org
Date
2018-06-12 18:55:20 -0700 (Tue, 12 Jun 2018)

Log Message

webkitpy: Implement coredumpctl support on linux
https://bugs.webkit.org/show_bug.cgi?id=184039

Patch by Thibault Saunier <tsaun...@igalia.com> on 2018-06-12
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):

Modified Paths

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)
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to