validate: launcher: Add a way to retrieve trace without coredumpctl

Simply spnning on segfaults (like gst-launch) and catch that in
the launcher to transform the timeout into a segfault and grab a gdb
backtrace
This commit is contained in:
Thibault Saunier 2018-12-07 09:03:24 -03:00
parent 21e23c72fc
commit 72995d5bbe
6 changed files with 119 additions and 19 deletions

View file

@ -20,11 +20,23 @@
* Boston, MA 02111-1307, USA.
*/
#include<math.h>
#include<ctype.h>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include "config.h"
#include <math.h>
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <glib.h>
#ifdef G_OS_UNIX
#include <glib-unix.h>
#include <sys/wait.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include "gst-validate-utils.h"
#include <gst/gst.h>
@ -821,3 +833,76 @@ gst_validate_object_set_property (GstValidateReporter * reporter,
g_value_reset (&nvalue);
return res;
}
#ifdef G_OS_UNIX
static void
fault_restore (void)
{
struct sigaction action;
memset (&action, 0, sizeof (action));
action.sa_handler = SIG_DFL;
sigaction (SIGSEGV, &action, NULL);
sigaction (SIGQUIT, &action, NULL);
}
static void
fault_spin (void)
{
int spinning = TRUE;
g_on_error_stack_trace ("GstValidate");
wait (NULL);
g_printerr ("Please run 'gdb <process-name> %d' to "
"continue debugging, Ctrl-C to quit, or Ctrl-\\ to dump core.\n",
(gint) getpid ());
while (spinning)
g_usleep (1000000);
}
static void
fault_handler_sighandler (int signum)
{
fault_restore ();
/* printf is used instead of g_print(), since it's less likely to
* deadlock */
switch (signum) {
case SIGSEGV:
g_printerr ("<Caught SIGNAL: SIGSEGV>\n");
break;
case SIGQUIT:
g_print ("<Caught SIGNAL: SIGQUIT>\n");
break;
default:
g_printerr ("<Caught SIGNAL: %d>\n", signum);
break;
}
fault_spin ();
}
static void
fault_setup (void)
{
struct sigaction action;
memset (&action, 0, sizeof (action));
action.sa_handler = fault_handler_sighandler;
sigaction (SIGSEGV, &action, NULL);
sigaction (SIGQUIT, &action, NULL);
}
#endif /* G_OS_UNIX */
void
gst_validate_spin_on_fault_signals (void)
{
#ifdef G_OS_UNIX
fault_setup ();
#endif
}

View file

@ -64,4 +64,7 @@ GstValidateActionReturn gst_validate_object_set_property (GstValidateReporter *
const GValue * value,
gboolean optional);
GST_VALIDATE_API
void gst_validate_spin_on_fault_signals (void);
#endif

View file

@ -232,6 +232,7 @@ class Test(Loggable):
self.add_env_variable("DISPLAY")
def add_stack_trace_to_logfile(self):
self.debug("Adding stack trace")
trace_gatherer = BackTraceGenerator.get_default()
stack_trace = trace_gatherer.get_trace(self)
@ -241,11 +242,13 @@ class Test(Loggable):
info = "\n\n== Stack trace: == \n%s" % stack_trace
if self.options.redirect_logs:
print(info)
elif self.options.xunit_file:
return
if self.options.xunit_file:
self.stack_trace = stack_trace
else:
with open(self.logfile, 'a') as f:
f.write(info)
with open(self.logfile, 'a') as f:
f.write(info)
def set_result(self, result, message="", error=""):
self.debug("Setting result: %s (message: %s, error: %s)" % (result,
@ -638,12 +641,8 @@ class GstValidateListener(socketserver.BaseRequestHandler):
class GstValidateTest(Test):
""" A class representing a particular test. """
findpos_regex = re.compile(
'.*position.*(\d+):(\d+):(\d+).(\d+).*duration.*(\d+):(\d+):(\d+).(\d+)')
findlastseek_regex = re.compile(
'seeking to.*(\d+):(\d+):(\d+).(\d+).*stop.*(\d+):(\d+):(\d+).(\d+).*rate.*(\d+)\.(\d+)')
HARD_TIMEOUT_FACTOR = 5
fault_sig_regex = re.compile("<Caught SIGNAL: .*>")
def __init__(self, application_name, classname,
options, reporter, duration=0,
@ -908,11 +907,16 @@ class GstValidateTest(Test):
msg = ""
result = Result.PASSED
if self.result == Result.TIMEOUT:
if expected_timeout:
not_found_expected_failures.remove(expected_timeout)
result, msg = self.check_expected_timeout(expected_timeout)
else:
return
with open(self.logfile) as f:
signal_fault_info = self.fault_sig_regex.findall(f.read())
if signal_fault_info:
result = Result.FAILED
msg = signal_fault_info[0]
elif expected_timeout:
not_found_expected_failures.remove(expected_timeout)
result, msg = self.check_expected_timeout(expected_timeout)
else:
return
elif self.process.returncode in COREDUMP_SIGNALS:
result = Result.FAILED
msg = "Application segfaulted "

View file

@ -33,6 +33,7 @@
#include <gst/validate/media-descriptor-writer.h>
#include <gst/validate/media-descriptor-parser.h>
#include <gst/validate/media-descriptor.h>
#include <gst/validate/gst-validate-utils.h>
#include <gst/pbutils/encoding-profile.h>
#include <locale.h> /* for LC_ALL */
@ -102,6 +103,8 @@ main (int argc, gchar ** argv)
}
g_option_context_free (ctx);
gst_validate_spin_on_fault_signals ();
runner = gst_validate_runner_new ();
if (expected_file) {

View file

@ -31,6 +31,7 @@
#include <gst/gst.h>
#include <gst/video/video.h>
#include <gst/validate/gst-validate-utils.h>
#include <gst/validate/validate.h>
#include <gst/pbutils/encoding-profile.h>
@ -836,6 +837,8 @@ main (int argc, gchar ** argv)
g_unix_signal_add (SIGINT, (GSourceFunc) intr_handler, pipeline);
#endif
gst_validate_spin_on_fault_signals ();
monitor =
gst_validate_monitor_factory_create (GST_OBJECT_CAST (pipeline), runner,
NULL);

View file

@ -457,6 +457,8 @@ main (int argc, gchar ** argv)
g_unix_signal_add (SIGINT, (GSourceFunc) intr_handler, pipeline);
#endif
gst_validate_spin_on_fault_signals ();
if (_is_playbin_pipeline (argc - 1, argv + 1)) {
_register_playbin_actions ();
}