[Piglit] [PATCH 03/13] util: Implement signal handler support.

Kenney Phillis kphillisjr at gmail.com
Thu Oct 31 15:47:59 CET 2013


* Non-Posix compliant platforms - Only a stub for a signal handler exists.

* Posix platforms - Add support for simple backtrace support when a crash is
detected. This support does not interfere with valgrind and gdb testing.

When running a program in the debugger ( for example, GDB ), the singal handler
is only handled after you resume the program using the the signal handler.
---
 CMakeLists.txt                                     |    9 +
 tests/util/CMakeLists.txt                          |    9 +
 tests/util/config.h.in                             |    5 +
 .../piglit-sighandler/piglit-sighandler-none.c     |   37 ++++
 .../piglit-sighandler/piglit-sighandler-posix.c    |  209 ++++++++++++++++++++
 tests/util/piglit-util.h                           |   12 ++
 6 files changed, 281 insertions(+)
 create mode 100644 tests/util/piglit-sighandler/piglit-sighandler-none.c
 create mode 100644 tests/util/piglit-sighandler/piglit-sighandler-posix.c

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 21eebc5..03e1490 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -314,12 +314,21 @@ check_function_exists(strndup   HAVE_STRNDUP)
 check_function_exists(fopen_s   HAVE_FOPEN_S)
 check_function_exists(setrlimit HAVE_SETRLIMIT)
 
+check_include_file(execinfo.h  HAVE_EXECINFO_H)
+check_include_file(signal.h    HAVE_SIGNAL_H)
+check_include_file(syscall.h   HAVE_SYSCALL_H)
 check_include_file(sys/time.h  HAVE_SYS_TIME_H)
 check_include_file(sys/types.h HAVE_SYS_TYPES_H)
 check_include_file(sys/resource.h  HAVE_SYS_RESOURCE_H)
+check_include_file(sys/siginfo.h HAVE_SYS_SIGINFO_H)
 check_include_file(sys/stat.h  HAVE_SYS_STAT_H)
+check_include_file(sys/syscall.h HAVE_SYS_SYSCALL_H)
 check_include_file(unistd.h    HAVE_UNISTD_H)
+#TODO: Implement proper libunwind support.
+#check_include_file(unwind.h    HAVE_UNWIND_H)
+#check_include_file(libunwind.h HAVE_LIBUNWIND_H)
 check_include_file(fcntl.h     HAVE_FCNTL_H)
+check_include_file(wait.h	   HAVE_WAIT_H)
 
 configure_file(
 	"${piglit_SOURCE_DIR}/tests/util/config.h.in"
diff --git a/tests/util/CMakeLists.txt b/tests/util/CMakeLists.txt
index dcc5634..5c184ea 100644
--- a/tests/util/CMakeLists.txt
+++ b/tests/util/CMakeLists.txt
@@ -9,6 +9,15 @@ set(UTIL_SOURCES
 	piglit-util.c
 	)
 
+
+# Auto-detect Correct Signal Handler.
+if(UNIX)
+	list(APPEND UTIL_SOURCES piglit-sighandler/piglit-sighandler-posix.c)
+else()
+	# No Signal Handler found.
+	list(APPEND UTIL_SOURCES piglit-sighandler/piglit-sighandler-none.c)
+endif()
+
 set(UTIL_GL_INCLUDES
 	${UTIL_INCLUDES}
 	${GLEXT_INCLUDE_DIR}
diff --git a/tests/util/config.h.in b/tests/util/config.h.in
index 2e8262a..b75e1f7 100644
--- a/tests/util/config.h.in
+++ b/tests/util/config.h.in
@@ -3,9 +3,14 @@
 #cmakedefine HAVE_SETRLIMIT
 #cmakedefine HAVE_STRNDUP
 
+#cmakedefine HAVE_EXECINFO_H
 #cmakedefine HAVE_FCNTL_H
+#cmakedefine HAVE_LIBUNWIND_H
+#cmakedefine HAVE_SIGNAL_H
 #cmakedefine HAVE_SYS_STAT_H
 #cmakedefine HAVE_SYS_TYPES_H
 #cmakedefine HAVE_SYS_TIME_H
 #cmakedefine HAVE_SYS_RESOURCE_H
+#cmakedefine HAVE_SYS_SIGINFO_H
 #cmakedefine HAVE_UNISTD_H
+#cmakedefine HAVE_UNWIND_H
diff --git a/tests/util/piglit-sighandler/piglit-sighandler-none.c b/tests/util/piglit-sighandler/piglit-sighandler-none.c
new file mode 100644
index 0000000..9b98976
--- /dev/null
+++ b/tests/util/piglit-sighandler/piglit-sighandler-none.c
@@ -0,0 +1,37 @@
+/*
+ * Copyright © 2013 Kenney Phillis
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "piglit-util.h"
+
+/** @file piglit-sighandler-none.c
+ *
+ * A stub to fill in the piglit_register_signal_handler function.
+ *
+ */
+
+#warning "Piglit Segmentation Handler Not Implemented for Your Platform."
+bool piglit_register_signal_handler()
+{
+	/* Nothing to Do */
+	return false;
+}
diff --git a/tests/util/piglit-sighandler/piglit-sighandler-posix.c b/tests/util/piglit-sighandler/piglit-sighandler-posix.c
new file mode 100644
index 0000000..63b31c9
--- /dev/null
+++ b/tests/util/piglit-sighandler/piglit-sighandler-posix.c
@@ -0,0 +1,209 @@
+/*
+ * Copyright © 2013 Kenney Phillis
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+/** @file piglit-sighandler-posix.c
+ *
+ * Implements posix compatible signal handler.
+ *
+ */
+#include "config.h"
+#include "piglit-util.h"
+
+#include <assert.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#if defined(HAVE_SYS_TYPES_H)
+# include <sys/types.h>
+#endif
+
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+
+#ifdef HAVE_FCNTL_H
+# include <fcntl.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#ifdef HAVE_SIGNAL_H
+#include <signal.h>
+#endif
+
+#ifdef HAVE_SYS_SIGINFO_H
+#include <sys/siginfo.h>
+#endif
+
+#ifdef HAVE_SYSCALL_H
+#include <syscall.h>
+#elif defined( HAVE_SYS_SYSCALL_H )
+#include <sys/syscall.h>
+#endif
+
+// for Backtrace Support
+#if defined(HAVE_LIBUNWIND_H)
+#include <libunwind.h>
+#elif defined(HAVE_EXECINFO_H)
+#include <execinfo.h>
+#endif
+
+#ifdef HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#elif defined( HAVE_WAIT_H)
+#include <wait.h>
+#endif
+
+void piglit_sighandler(int sig, siginfo_t *info, void *secret);
+bool piglit_sighandler_gdb_report( char*name_buf,  char* pid_buf);
+void piglit_sighandler_backtrace(int sig, siginfo_t *info, void *secret);
+
+bool piglit_register_signal_handler()
+{
+	/* Register the Piglit signal action handler. */
+	struct sigaction sa;
+	sigset_t block_mask;
+	sigemptyset (&block_mask);
+	/**
+	 * Most signals are already set to need a block. However, this is the
+	 * only signal that you absolutely haft to block to be able to capture
+	 * output
+	 */
+	sigaddset (&block_mask, SIGABRT);
+	sigaddset (&block_mask, SIGINT);
+	sigaddset (&block_mask, SIGQUIT);
+	sa.sa_handler = (void *)piglit_sighandler;
+	sa.sa_mask = block_mask;
+	sa.sa_flags = 0;
+#ifdef SA_SIGINFO
+	sa.sa_flags |= SA_SIGINFO;
+	sa.sa_sigaction  = (void *)piglit_sighandler;
+#endif
+#ifdef SA_RESTART
+	sa.sa_flags |= SA_RESTART;
+#endif
+	/* Actually Register the Signal Actions */
+	sigaction( SIGTRAP, &sa, NULL); /*  5 - Trace trap (POSIX) */
+	sigaction( SIGABRT, &sa, NULL); /*  6 - Abort ( ANSI )*/
+	sigaction( SIGFPE,  &sa, NULL); /*  8 - FPE ( Floating Point Exception) */
+	sigaction( SIGUSR1, &sa, NULL); /* 10 - User Defined Signal*/
+	sigaction( SIGSEGV, &sa, NULL); /* 11 - Segmentation Fault */
+
+	return true;
+}
+
+
+
+void piglit_sighandler(int sig, siginfo_t *info, void *secret) {
+	char proc_pid_buf[30];
+	char proc_name_buf[512];
+	// Get executable name.
+	proc_name_buf[readlink("/proc/self/exe", proc_name_buf, 511)]='\0';
+	sprintf(proc_pid_buf, "%d", getpid());
+	fprintf(stdout,"\nPiglit: Crash Detected on %s ( PID: %s ).\n"
+		"\tGenerating Debug information\n", proc_name_buf, proc_pid_buf);
+	fprintf(stdout,"info.si_signo = %d\n", sig);
+	fprintf(stdout,"info.si_code  = %d\n", info->si_code);
+	fprintf(stdout,"info.si_addr  = %p\n", info->si_addr);
+	fprintf(stdout,"info.si_errno = %d\n", info->si_errno);
+	piglit_sighandler_backtrace(sig, info, secret);
+
+	fprintf(stdout,"PIGLIT: {'result': 'crash' }\n");
+	fflush(stdout);
+
+	/* Maintain the Signal, and use that as the return code. */
+	exit(sig);
+}
+
+void piglit_sighandler_backtrace(int sig, siginfo_t *info, void *secret)
+{
+#if defined( HAVE_UNWIND_H)
+	/* Unwind Capable */
+	unw_context_t uc;
+	unw_cursor_t cursor;
+	unw_word_t ip, sp, offp;
+	char functionName[256];
+	int res;
+	/* Initialize the Context */
+	unw_getcontext(&uc);
+	unw_init_local(&cursor, &uc);
+	while (unw_step(&cursor) !=0)
+	{
+
+		functionName[0] = '\0';
+		res = unw_get_proc_name(&cursor, functionName, 256, &offp);
+		if(res == UNW_EUNSPEC) {
+			printf ("ERROR: unwind: Unspecified Error.");
+			continue;
+		}
+		if(res == UNW_ENOINFO){
+			printf ("ERROR: unwind: Unspecified to determine Name of Procedure.\n");
+			continue;
+		}
+		unw_get_reg(&cursor, UNW_REG_IP, &ip); /* Instruction Pointer*/
+		unw_get_reg(&cursor, UNW_REG_SP, &sp); /* Stack Pointer*/
+#ifdef UNW_ENOMME
+		if(res== UNW_ENOMME) {
+			printf ("Warning: unwind: Procedure Name to Long... Name is Truncated.\n");
+		}
+#endif
+#if __WORDSIZE == 64
+		/* Print Stack Pointer and Instruction Pointer */
+		printf ("SP=0x%016lx IP=0x%016lx" ,sp, ip);
+		/* Print Symbol name and Instruction Offset */
+		printf (": (%s+0x%016lx)  [%016lx]\n", functionName, offp, ip);
+#elif __WORDSIZE == 32
+		/* Print Stack Pointer and Instruction Pointer */
+		printf ("SP=0x%08x IP=0x%08x" ,sp, ip);
+		/* Print Symbol name and Instruction Offset */
+		printf (": (%s+0x%08x)  [%08x]\n", functionName, offp, ip);
+#else
+		/* Print Stack Pointer and Instruction Pointer */
+		printf ("SP=0x%04x IP=0x%04x" ,sp, ip);
+		/* Print Symbol name and Instruction Offset */
+		printf (": (%s+0x%04x)  [%04x]\n", functionName, offp, ip);
+#endif
+	}
+#elif defined(HAVE_EXECINFO_H)
+	void *trace[16];
+	char **messages = (char **)NULL;
+	int i, trace_size = 0;
+	trace_size = backtrace(trace, 16);
+	/* overwrite sigaction with caller's address */
+	//trace[1] = (void *) uc->uc_mcontext.gregs[REG_EIP];
+
+	messages = backtrace_symbols(trace, trace_size);
+	/* skip first stack frame (points here) */
+	printf("[backtrace] Execution path\n");
+	for (i=0; i<trace_size; ++i) {
+		fprintf(stderr,"%d - %s\n",i, messages[i]);
+	}
+#else
+	fprintf(stdout,"Piglit: Warning, Unable to generate Backtraces.\n");
+#endif
+}
diff --git a/tests/util/piglit-util.h b/tests/util/piglit-util.h
index f9f70f3..088ef9a 100644
--- a/tests/util/piglit-util.h
+++ b/tests/util/piglit-util.h
@@ -111,6 +111,18 @@ enum piglit_result {
 #define MAX2(a, b) ((a) > (b) ? (a) : (b))
 
 /**
+ * Register platform specific signal handler.
+
+ * This Signal handler is used to automatically generate call stacks
+ * when a test crashes.
+ *
+ * \precondition \c Some call stacks will not completely register.
+ *    For example, SIGABRT on linux is already after test terminates.
+ *
+ */
+bool piglit_register_signal_handler();
+
+/**
  * Determine if an extension is listed in an extension string
  *
  * \param haystack   List of all extensions to be searched
-- 
1.7.9.5



More information about the Piglit mailing list