* 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

_______________________________________________
Piglit mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/piglit

Reply via email to