diff mbox

fwts: catch segfaults and bus errors and dump stack

Message ID 1416925140-12019-1-git-send-email-colin.king@canonical.com
State Accepted
Headers show

Commit Message

Colin Ian King Nov. 25, 2014, 2:19 p.m. UTC
From: Colin Ian King <colin.king@canonical.com>

Bugs such as LP#1376448 have been hard to track down because
the target machine is not accessible and the user is not easily
able to pass over core dump information.  In an attempt to at
least identify where a fault is occurring, this patch adds in
a SIGSEGV and SIGBUS handler that will dump to stderr a stack
trace.

This patch also re-works some of signal() handlers in fwts to
ensure we save and restore the dump stack handler in a more
generic way for fwts. This also tidies up the old fashioned
signal() handler with the more modern signal handling mechanisms.

Signed-off-by: Colin Ian King <colin.king@canonical.com>
---
 src/lib/include/fwts.h           |   1 +
 src/lib/include/fwts_backtrace.h |  29 ++++++++
 src/lib/src/Makefile.am          |   1 +
 src/lib/src/fwts_backtrace.c     | 145 +++++++++++++++++++++++++++++++++++++++
 src/lib/src/fwts_cpu.c           |   5 +-
 src/lib/src/fwts_ioport.c        |  27 ++++----
 src/lib/src/fwts_safe_mem.c      |   7 +-
 src/main.c                       |   2 +
 8 files changed, 198 insertions(+), 19 deletions(-)
 create mode 100644 src/lib/include/fwts_backtrace.h
 create mode 100644 src/lib/src/fwts_backtrace.c

Comments

Alex Hung Nov. 26, 2014, 3:13 a.m. UTC | #1
On 14-11-25 10:19 PM, Colin King wrote:
> From: Colin Ian King<colin.king@canonical.com>
>
> Bugs such as LP#1376448 have been hard to track down because
> the target machine is not accessible and the user is not easily
> able to pass over core dump information.  In an attempt to at
> least identify where a fault is occurring, this patch adds in
> a SIGSEGV and SIGBUS handler that will dump to stderr a stack
> trace.
>
> This patch also re-works some of signal() handlers in fwts to
> ensure we save and restore the dump stack handler in a more
> generic way for fwts. This also tidies up the old fashioned
> signal() handler with the more modern signal handling mechanisms.
>
> Signed-off-by: Colin Ian King<colin.king@canonical.com>

Acked-by: Alex Hung <alex.hung@canonical.com>
Ivan Hu Dec. 5, 2014, 8:47 a.m. UTC | #2
On 2014年11月25日 22:19, Colin King wrote:
> From: Colin Ian King <colin.king@canonical.com>
>
> Bugs such as LP#1376448 have been hard to track down because
> the target machine is not accessible and the user is not easily
> able to pass over core dump information.  In an attempt to at
> least identify where a fault is occurring, this patch adds in
> a SIGSEGV and SIGBUS handler that will dump to stderr a stack
> trace.
>
> This patch also re-works some of signal() handlers in fwts to
> ensure we save and restore the dump stack handler in a more
> generic way for fwts. This also tidies up the old fashioned
> signal() handler with the more modern signal handling mechanisms.
>
> Signed-off-by: Colin Ian King <colin.king@canonical.com>
> ---
>   src/lib/include/fwts.h           |   1 +
>   src/lib/include/fwts_backtrace.h |  29 ++++++++
>   src/lib/src/Makefile.am          |   1 +
>   src/lib/src/fwts_backtrace.c     | 145 +++++++++++++++++++++++++++++++++++++++
>   src/lib/src/fwts_cpu.c           |   5 +-
>   src/lib/src/fwts_ioport.c        |  27 ++++----
>   src/lib/src/fwts_safe_mem.c      |   7 +-
>   src/main.c                       |   2 +
>   8 files changed, 198 insertions(+), 19 deletions(-)
>   create mode 100644 src/lib/include/fwts_backtrace.h
>   create mode 100644 src/lib/src/fwts_backtrace.c
>
> diff --git a/src/lib/include/fwts.h b/src/lib/include/fwts.h
> index d98932b..d5fc231 100644
> --- a/src/lib/include/fwts.h
> +++ b/src/lib/include/fwts.h
> @@ -35,6 +35,7 @@
>   #define FWTS_JSON_DATA_PATH	DATAROOTDIR "/fwts"
>   
>   #include "fwts_version.h"
> +#include "fwts_backtrace.h"
>   #include "fwts_types.h"
>   #include "fwts_binpaths.h"
>   #include "fwts_framework.h"
> diff --git a/src/lib/include/fwts_backtrace.h b/src/lib/include/fwts_backtrace.h
> new file mode 100644
> index 0000000..e0b0dde
> --- /dev/null
> +++ b/src/lib/include/fwts_backtrace.h
> @@ -0,0 +1,29 @@
> +/*
> + * Copyright (C) 2010-2014 Canonical
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * as published by the Free Software Foundation; either version 2
> + * of the License, or (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
> + *
> + */
> +#ifndef __FWTS_BACKTRACE__
> +#define __FWTS_BACKTRACE__
> +
> +#include <signal.h>
> +
> +void fwts_print_backtrace(void);
> +int fwts_fault_catch(void);
> +void fwts_sig_handler_set(int signum, void (*handler)(int), struct sigaction *old_action);
> +void fwts_sig_handler_restore(int signum, struct sigaction *old_action);
> +
> +#endif
> diff --git a/src/lib/src/Makefile.am b/src/lib/src/Makefile.am
> index 33f81f4..2f0bbcc 100644
> --- a/src/lib/src/Makefile.am
> +++ b/src/lib/src/Makefile.am
> @@ -29,6 +29,7 @@ libfwts_la_SOURCES = 		\
>   	fwts_acpid.c 		\
>   	fwts_alloc.c 		\
>   	fwts_args.c 		\
> +	fwts_backtrace.c	\
>   	fwts_battery.c 		\
>   	fwts_binpaths.c 	\
>   	fwts_button.c 		\
> diff --git a/src/lib/src/fwts_backtrace.c b/src/lib/src/fwts_backtrace.c
> new file mode 100644
> index 0000000..eb84b48
> --- /dev/null
> +++ b/src/lib/src/fwts_backtrace.c
> @@ -0,0 +1,145 @@
> +/*
> + * Copyright (C) 2010-2014 Canonical
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * as published by the Free Software Foundation; either version 2
> + * of the License, or (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
> + *
> + */
> +#include <execinfo.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <stdint.h>
> +#include <stdbool.h>
> +#include <inttypes.h>
> +#include <string.h>
> +#include <signal.h>
> +#include <setjmp.h>
> +
> +#include "fwts.h"
> +
> +#define BACK_TRACE_SIZE		(512)
> +
> +static sigjmp_buf jmp_env;
> +static void *bt_buff[BACK_TRACE_SIZE];
> +static size_t bt_size = 0;
> +
> +/*
> + *  fwts_print_backtrace()
> + *	parse symbol backtrace and dump it in a easy
> + *	to read format.
> + */
> +void fwts_print_backtrace(void)
> +{
> +	char **bt_strings;
> +	size_t i;
> +
> +	fprintf(stderr, "Backtrace:\n");
> +	if (bt_size) {
> +		bt_strings = backtrace_symbols(bt_buff, bt_size);
> +
> +		for (i = 0; i < bt_size; i++) {
> +			/*
> +			 *  convert trace into output in form:
> +			 *   0x00007fb04a493ec5 /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf5)
> +			 */
> +			char *addrstr = strstr(bt_strings[i], " [0x");
> +			if (addrstr) {
> +				uint64_t addr;
> +
> +				*addrstr = '\0';
> +				addr = (uint64_t)strtoull(addrstr + 2, NULL, 16);
> +				fprintf(stderr, "0x%16.16" PRIx64 " %s\n", addr, bt_strings[i]);
> +			}
> +		}
> +		free(bt_strings);
> +	} else {
> +		fprintf(stderr, "  No data\n");
> +	}
> +	fprintf(stderr, "\n");
> +	fflush(stdout);
> +}
> +
> +/*
> + *  fwts_fault_handler()
> + *	catch a signal, save stack dump, jmp back or abort
> + */
> +static void fwts_fault_handler(int signum)
> +{
> +	static bool already_handled = false;
> +
> +	/* Capture backtrace and jmp back */
> +
> +	if (!already_handled) {
> +		already_handled = true;
> +		/* Capture backtrace from this stack context */
> +		bt_size = backtrace(bt_buff, BACK_TRACE_SIZE);
> +		/* Jmp back to the sigsetjmp context */
> +		siglongjmp(jmp_env, signum);
> +	}
> +	/* We've hit a fault before, so abort */
> +	_exit(EXIT_FAILURE);
> +}
> +
> +/*
> + *  fwts_sig_handler_set()
> + *	helper to set signal handler
> + */
> +void fwts_sig_handler_set(int signum, void (*handler)(int), struct sigaction *old_action)
> +{
> +	struct sigaction new_action;
> +
> +	memset(&new_action, 0, sizeof new_action);
> +	new_action.sa_handler = handler;
> +	sigemptyset(&new_action.sa_mask);
> +
> +        (void)sigaction(signum, &new_action, old_action);
> +}
> +
> +/*
> + *  fwts_sig_handler_restore()
> + *	helper to restore signal handler
> + */
> +void fwts_sig_handler_restore(int signum, struct sigaction *old_action)
> +{
> +        (void)sigaction(signum, old_action, NULL);
> +}
> +
> +/*
> + *  fwts_fault_catch()
> + *	catch segfaults and bus errors, dump stack
> + *	trace so we can see what's causing them
> + */
> +int fwts_fault_catch(void)
> +{
> +	int ret;
> +
> +	/* Trap segfaults and bus errors */
> +	fwts_sig_handler_set(SIGSEGV, fwts_fault_handler, NULL);
> +	fwts_sig_handler_set(SIGBUS, fwts_fault_handler, NULL);
> +
> +	ret = sigsetjmp(jmp_env, 1);
> +	/*
> +	 *  We reach here with ret == SIGNUM if the fault handler
> +	 *  longjmps back to here.  Or we reach here with
> +	 *  ret == 0 if sigsetjmp has set the jmp_env up
> +	 *  correctly.
> +	 */
> +	if (ret) {
> +		fprintf(stderr, "\nCaught SIGNAL %d (%s), aborting.\n",
> +			ret, strsignal(ret));
> +		fwts_print_backtrace();
> +		exit(EXIT_FAILURE);
> +	}
> +	return FWTS_OK;
> +}
> diff --git a/src/lib/src/fwts_cpu.c b/src/lib/src/fwts_cpu.c
> index 9cbbdef..fe78ee5 100644
> --- a/src/lib/src/fwts_cpu.c
> +++ b/src/lib/src/fwts_cpu.c
> @@ -377,7 +377,7 @@ int fwts_cpu_performance(
>    */
>   static void fwts_cpu_consume_cycles(void)
>   {
> -	signal(SIGUSR1, fwts_cpu_consume_sighandler);
> +	fwts_sig_handler_set(SIGUSR1, fwts_cpu_consume_sighandler, NULL);
>   	uint64_t i = 0;
>   
>   	for (;;) {
> @@ -410,8 +410,7 @@ int fwts_cpu_consume_start(void)
>   	if ((fwts_cpu_pids = (pid_t*)calloc(fwts_cpu_num, sizeof(pid_t))) == NULL)
>   		return FWTS_ERROR;
>   
> -	signal(SIGINT, fwts_cpu_sigint_handler);
> -
> +	fwts_sig_handler_set(SIGINT, fwts_cpu_sigint_handler, NULL);
>   	for (i=0;i<fwts_cpu_num;i++) {
>   		pid_t pid;
>   
> diff --git a/src/lib/src/fwts_ioport.c b/src/lib/src/fwts_ioport.c
> index e433995..d0d661a 100644
> --- a/src/lib/src/fwts_ioport.c
> +++ b/src/lib/src/fwts_ioport.c
> @@ -27,6 +27,7 @@
>   #include <setjmp.h>
>   
>   static sigjmp_buf jmpbuf;
> +static struct sigaction old_action;
>   
>   /*
>    *  If we hit a SIGSEGV then the port read
> @@ -37,7 +38,7 @@ static void segv_handler(int dummy)
>   {
>   	FWTS_UNUSED(dummy);
>   
> -	signal(SIGSEGV, SIG_DFL);
> +	fwts_sig_handler_restore(SIGSEGV, &old_action);
>   	siglongjmp(jmpbuf, 1);
>   }
>   
> @@ -50,9 +51,9 @@ int fwts_inb(uint32_t port, uint8_t *value)
>   	if (sigsetjmp(jmpbuf, 1) != 0)
>   		return FWTS_ERROR;
>   
> -	signal(SIGSEGV, segv_handler);
> +	fwts_sig_handler_set(SIGSEGV, segv_handler, &old_action);
>   	*value = inb(port);
> -	signal(SIGSEGV, SIG_DFL);
> +	fwts_sig_handler_restore(SIGSEGV, &old_action);
>   
>   	return FWTS_OK;
>   }
> @@ -66,9 +67,9 @@ int fwts_inw(uint32_t port, uint16_t *value)
>   	if (sigsetjmp(jmpbuf, 1) != 0)
>   		return FWTS_ERROR;
>   
> -	signal(SIGSEGV, segv_handler);
> +	fwts_sig_handler_set(SIGSEGV, segv_handler, &old_action);
>   	*value = inw(port);
> -	signal(SIGSEGV, SIG_DFL);
> +	fwts_sig_handler_restore(SIGSEGV, &old_action);
>   
>   	return FWTS_OK;
>   }
> @@ -82,9 +83,9 @@ int fwts_inl(uint32_t port, uint32_t *value)
>   	if (sigsetjmp(jmpbuf, 1) != 0)
>   		return FWTS_ERROR;
>   
> -	signal(SIGSEGV, segv_handler);
> +	fwts_sig_handler_set(SIGSEGV, segv_handler, &old_action);
>   	*value = inl(port);
> -	signal(SIGSEGV, SIG_DFL);
> +	fwts_sig_handler_restore(SIGSEGV, &old_action);
>   
>   	return FWTS_OK;
>   }
> @@ -98,9 +99,9 @@ int fwts_outb(uint32_t port, uint8_t value)
>   	if (sigsetjmp(jmpbuf, 1) != 0)
>   		return FWTS_ERROR;
>   
> -	signal(SIGSEGV, segv_handler);
> +	fwts_sig_handler_set(SIGSEGV, segv_handler, &old_action);
>   	outb(port, value);
> -	signal(SIGSEGV, SIG_DFL);
> +	fwts_sig_handler_restore(SIGSEGV, &old_action);
>   
>   	return FWTS_OK;
>   }
> @@ -114,9 +115,9 @@ int fwts_outw(uint32_t port, uint16_t value)
>   	if (sigsetjmp(jmpbuf, 1) != 0)
>   		return FWTS_ERROR;
>   
> -	signal(SIGSEGV, segv_handler);
> +	fwts_sig_handler_set(SIGSEGV, segv_handler, &old_action);
>   	outw(port, value);
> -	signal(SIGSEGV, SIG_DFL);
> +	fwts_sig_handler_restore(SIGSEGV, &old_action);
>   
>   	return FWTS_OK;
>   }
> @@ -130,9 +131,9 @@ int fwts_outl(uint32_t port, uint32_t value)
>   	if (sigsetjmp(jmpbuf, 1) != 0)
>   		return FWTS_ERROR;
>   
> -	signal(SIGSEGV, segv_handler);
> +	fwts_sig_handler_set(SIGSEGV, segv_handler, &old_action);
>   	outl(port, value);
> -	signal(SIGSEGV, SIG_DFL);
> +	fwts_sig_handler_restore(SIGSEGV, &old_action);
>   
>   	return FWTS_OK;
>   }
> diff --git a/src/lib/src/fwts_safe_mem.c b/src/lib/src/fwts_safe_mem.c
> index 6fcfe1f..4d75ab3 100644
> --- a/src/lib/src/fwts_safe_mem.c
> +++ b/src/lib/src/fwts_safe_mem.c
> @@ -23,6 +23,7 @@
>   #include "fwts.h"
>   
>   static sigjmp_buf jmpbuf;
> +static struct sigaction old_action;
>   
>   /*
>    *  If we hit a SIGSEGV then the port read
> @@ -33,7 +34,7 @@ static void segv_handler(int dummy)
>   {
>   	FWTS_UNUSED(dummy);
>   
> -	signal(SIGSEGV, SIG_DFL);
> +	fwts_sig_handler_restore(SIGSEGV, &old_action);
>   	siglongjmp(jmpbuf, 1);
>   }
>   
> @@ -48,9 +49,9 @@ int fwts_safe_memcpy(void *dst, const void *src, const size_t n)
>   	if (sigsetjmp(jmpbuf, 1) != 0)
>   		return FWTS_ERROR;
>   	
> -	signal(SIGSEGV, segv_handler);
> +	fwts_sig_handler_set(SIGSEGV, segv_handler, &old_action);
>   	memcpy(dst, src, n);
> -	signal(SIGSEGV, SIG_DFL);
> +	fwts_sig_handler_restore(SIGSEGV, &old_action);
>   
>   	return FWTS_OK;
>   }
> diff --git a/src/main.c b/src/main.c
> index 56981d5..ef67b4c 100644
> --- a/src/main.c
> +++ b/src/main.c
> @@ -24,6 +24,8 @@
>   
>   int main(int argc, char **argv)
>   {
> +	(void)fwts_fault_catch();
> +
>   	if (fwts_framework_args(argc, argv) == FWTS_OK)
>   		exit(EXIT_SUCCESS);
>   	else

Acked-by: Ivan Hu <ivan.hu@canonical.com>
diff mbox

Patch

diff --git a/src/lib/include/fwts.h b/src/lib/include/fwts.h
index d98932b..d5fc231 100644
--- a/src/lib/include/fwts.h
+++ b/src/lib/include/fwts.h
@@ -35,6 +35,7 @@ 
 #define FWTS_JSON_DATA_PATH	DATAROOTDIR "/fwts"
 
 #include "fwts_version.h"
+#include "fwts_backtrace.h"
 #include "fwts_types.h"
 #include "fwts_binpaths.h"
 #include "fwts_framework.h"
diff --git a/src/lib/include/fwts_backtrace.h b/src/lib/include/fwts_backtrace.h
new file mode 100644
index 0000000..e0b0dde
--- /dev/null
+++ b/src/lib/include/fwts_backtrace.h
@@ -0,0 +1,29 @@ 
+/*
+ * Copyright (C) 2010-2014 Canonical
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+#ifndef __FWTS_BACKTRACE__
+#define __FWTS_BACKTRACE__
+
+#include <signal.h>
+
+void fwts_print_backtrace(void);
+int fwts_fault_catch(void);
+void fwts_sig_handler_set(int signum, void (*handler)(int), struct sigaction *old_action);
+void fwts_sig_handler_restore(int signum, struct sigaction *old_action);
+
+#endif
diff --git a/src/lib/src/Makefile.am b/src/lib/src/Makefile.am
index 33f81f4..2f0bbcc 100644
--- a/src/lib/src/Makefile.am
+++ b/src/lib/src/Makefile.am
@@ -29,6 +29,7 @@  libfwts_la_SOURCES = 		\
 	fwts_acpid.c 		\
 	fwts_alloc.c 		\
 	fwts_args.c 		\
+	fwts_backtrace.c	\
 	fwts_battery.c 		\
 	fwts_binpaths.c 	\
 	fwts_button.c 		\
diff --git a/src/lib/src/fwts_backtrace.c b/src/lib/src/fwts_backtrace.c
new file mode 100644
index 0000000..eb84b48
--- /dev/null
+++ b/src/lib/src/fwts_backtrace.c
@@ -0,0 +1,145 @@ 
+/*
+ * Copyright (C) 2010-2014 Canonical
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+#include <execinfo.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <inttypes.h>
+#include <string.h>
+#include <signal.h>
+#include <setjmp.h>
+
+#include "fwts.h"
+
+#define BACK_TRACE_SIZE		(512)
+
+static sigjmp_buf jmp_env;
+static void *bt_buff[BACK_TRACE_SIZE];
+static size_t bt_size = 0;
+
+/*
+ *  fwts_print_backtrace()
+ *	parse symbol backtrace and dump it in a easy
+ *	to read format.
+ */
+void fwts_print_backtrace(void)
+{
+	char **bt_strings;
+	size_t i;
+
+	fprintf(stderr, "Backtrace:\n");
+	if (bt_size) {
+		bt_strings = backtrace_symbols(bt_buff, bt_size);
+
+		for (i = 0; i < bt_size; i++) {
+			/*
+			 *  convert trace into output in form:
+			 *   0x00007fb04a493ec5 /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf5)
+			 */
+			char *addrstr = strstr(bt_strings[i], " [0x");
+			if (addrstr) {
+				uint64_t addr;
+
+				*addrstr = '\0';
+				addr = (uint64_t)strtoull(addrstr + 2, NULL, 16);
+				fprintf(stderr, "0x%16.16" PRIx64 " %s\n", addr, bt_strings[i]);
+			}
+		}
+		free(bt_strings);
+	} else {
+		fprintf(stderr, "  No data\n");
+	}
+	fprintf(stderr, "\n");
+	fflush(stdout);
+}
+
+/*
+ *  fwts_fault_handler()
+ *	catch a signal, save stack dump, jmp back or abort
+ */
+static void fwts_fault_handler(int signum)
+{
+	static bool already_handled = false;
+
+	/* Capture backtrace and jmp back */
+
+	if (!already_handled) {
+		already_handled = true;
+		/* Capture backtrace from this stack context */
+		bt_size = backtrace(bt_buff, BACK_TRACE_SIZE);
+		/* Jmp back to the sigsetjmp context */
+		siglongjmp(jmp_env, signum);
+	}
+	/* We've hit a fault before, so abort */
+	_exit(EXIT_FAILURE);
+}
+
+/*
+ *  fwts_sig_handler_set()
+ *	helper to set signal handler
+ */
+void fwts_sig_handler_set(int signum, void (*handler)(int), struct sigaction *old_action)
+{
+	struct sigaction new_action;
+
+	memset(&new_action, 0, sizeof new_action);
+	new_action.sa_handler = handler;
+	sigemptyset(&new_action.sa_mask);
+
+        (void)sigaction(signum, &new_action, old_action);
+}
+
+/*
+ *  fwts_sig_handler_restore()
+ *	helper to restore signal handler
+ */
+void fwts_sig_handler_restore(int signum, struct sigaction *old_action)
+{
+        (void)sigaction(signum, old_action, NULL);
+}
+
+/*
+ *  fwts_fault_catch()
+ *	catch segfaults and bus errors, dump stack
+ *	trace so we can see what's causing them
+ */
+int fwts_fault_catch(void)
+{
+	int ret;
+
+	/* Trap segfaults and bus errors */
+	fwts_sig_handler_set(SIGSEGV, fwts_fault_handler, NULL);
+	fwts_sig_handler_set(SIGBUS, fwts_fault_handler, NULL);
+
+	ret = sigsetjmp(jmp_env, 1);
+	/*
+	 *  We reach here with ret == SIGNUM if the fault handler
+	 *  longjmps back to here.  Or we reach here with
+	 *  ret == 0 if sigsetjmp has set the jmp_env up
+	 *  correctly.
+	 */
+	if (ret) {
+		fprintf(stderr, "\nCaught SIGNAL %d (%s), aborting.\n",
+			ret, strsignal(ret));
+		fwts_print_backtrace();
+		exit(EXIT_FAILURE);
+	}
+	return FWTS_OK;
+}
diff --git a/src/lib/src/fwts_cpu.c b/src/lib/src/fwts_cpu.c
index 9cbbdef..fe78ee5 100644
--- a/src/lib/src/fwts_cpu.c
+++ b/src/lib/src/fwts_cpu.c
@@ -377,7 +377,7 @@  int fwts_cpu_performance(
  */
 static void fwts_cpu_consume_cycles(void)
 {
-	signal(SIGUSR1, fwts_cpu_consume_sighandler);
+	fwts_sig_handler_set(SIGUSR1, fwts_cpu_consume_sighandler, NULL);
 	uint64_t i = 0;
 
 	for (;;) {
@@ -410,8 +410,7 @@  int fwts_cpu_consume_start(void)
 	if ((fwts_cpu_pids = (pid_t*)calloc(fwts_cpu_num, sizeof(pid_t))) == NULL)
 		return FWTS_ERROR;
 
-	signal(SIGINT, fwts_cpu_sigint_handler);
-
+	fwts_sig_handler_set(SIGINT, fwts_cpu_sigint_handler, NULL);
 	for (i=0;i<fwts_cpu_num;i++) {
 		pid_t pid;
 
diff --git a/src/lib/src/fwts_ioport.c b/src/lib/src/fwts_ioport.c
index e433995..d0d661a 100644
--- a/src/lib/src/fwts_ioport.c
+++ b/src/lib/src/fwts_ioport.c
@@ -27,6 +27,7 @@ 
 #include <setjmp.h>
 
 static sigjmp_buf jmpbuf;
+static struct sigaction old_action;
 
 /*
  *  If we hit a SIGSEGV then the port read
@@ -37,7 +38,7 @@  static void segv_handler(int dummy)
 {
 	FWTS_UNUSED(dummy);
 
-	signal(SIGSEGV, SIG_DFL);
+	fwts_sig_handler_restore(SIGSEGV, &old_action);
 	siglongjmp(jmpbuf, 1);
 }
 
@@ -50,9 +51,9 @@  int fwts_inb(uint32_t port, uint8_t *value)
 	if (sigsetjmp(jmpbuf, 1) != 0)
 		return FWTS_ERROR;
 
-	signal(SIGSEGV, segv_handler);
+	fwts_sig_handler_set(SIGSEGV, segv_handler, &old_action);
 	*value = inb(port);
-	signal(SIGSEGV, SIG_DFL);
+	fwts_sig_handler_restore(SIGSEGV, &old_action);
 
 	return FWTS_OK;
 }
@@ -66,9 +67,9 @@  int fwts_inw(uint32_t port, uint16_t *value)
 	if (sigsetjmp(jmpbuf, 1) != 0)
 		return FWTS_ERROR;
 
-	signal(SIGSEGV, segv_handler);
+	fwts_sig_handler_set(SIGSEGV, segv_handler, &old_action);
 	*value = inw(port);
-	signal(SIGSEGV, SIG_DFL);
+	fwts_sig_handler_restore(SIGSEGV, &old_action);
 
 	return FWTS_OK;
 }
@@ -82,9 +83,9 @@  int fwts_inl(uint32_t port, uint32_t *value)
 	if (sigsetjmp(jmpbuf, 1) != 0)
 		return FWTS_ERROR;
 
-	signal(SIGSEGV, segv_handler);
+	fwts_sig_handler_set(SIGSEGV, segv_handler, &old_action);
 	*value = inl(port);
-	signal(SIGSEGV, SIG_DFL);
+	fwts_sig_handler_restore(SIGSEGV, &old_action);
 
 	return FWTS_OK;
 }
@@ -98,9 +99,9 @@  int fwts_outb(uint32_t port, uint8_t value)
 	if (sigsetjmp(jmpbuf, 1) != 0)
 		return FWTS_ERROR;
 
-	signal(SIGSEGV, segv_handler);
+	fwts_sig_handler_set(SIGSEGV, segv_handler, &old_action);
 	outb(port, value);
-	signal(SIGSEGV, SIG_DFL);
+	fwts_sig_handler_restore(SIGSEGV, &old_action);
 
 	return FWTS_OK;
 }
@@ -114,9 +115,9 @@  int fwts_outw(uint32_t port, uint16_t value)
 	if (sigsetjmp(jmpbuf, 1) != 0)
 		return FWTS_ERROR;
 
-	signal(SIGSEGV, segv_handler);
+	fwts_sig_handler_set(SIGSEGV, segv_handler, &old_action);
 	outw(port, value);
-	signal(SIGSEGV, SIG_DFL);
+	fwts_sig_handler_restore(SIGSEGV, &old_action);
 
 	return FWTS_OK;
 }
@@ -130,9 +131,9 @@  int fwts_outl(uint32_t port, uint32_t value)
 	if (sigsetjmp(jmpbuf, 1) != 0)
 		return FWTS_ERROR;
 
-	signal(SIGSEGV, segv_handler);
+	fwts_sig_handler_set(SIGSEGV, segv_handler, &old_action);
 	outl(port, value);
-	signal(SIGSEGV, SIG_DFL);
+	fwts_sig_handler_restore(SIGSEGV, &old_action);
 
 	return FWTS_OK;
 }
diff --git a/src/lib/src/fwts_safe_mem.c b/src/lib/src/fwts_safe_mem.c
index 6fcfe1f..4d75ab3 100644
--- a/src/lib/src/fwts_safe_mem.c
+++ b/src/lib/src/fwts_safe_mem.c
@@ -23,6 +23,7 @@ 
 #include "fwts.h"
 
 static sigjmp_buf jmpbuf;
+static struct sigaction old_action;
 
 /*
  *  If we hit a SIGSEGV then the port read
@@ -33,7 +34,7 @@  static void segv_handler(int dummy)
 {
 	FWTS_UNUSED(dummy);
 
-	signal(SIGSEGV, SIG_DFL);
+	fwts_sig_handler_restore(SIGSEGV, &old_action);
 	siglongjmp(jmpbuf, 1);
 }
 
@@ -48,9 +49,9 @@  int fwts_safe_memcpy(void *dst, const void *src, const size_t n)
 	if (sigsetjmp(jmpbuf, 1) != 0)
 		return FWTS_ERROR;
 	
-	signal(SIGSEGV, segv_handler);
+	fwts_sig_handler_set(SIGSEGV, segv_handler, &old_action);
 	memcpy(dst, src, n);
-	signal(SIGSEGV, SIG_DFL);
+	fwts_sig_handler_restore(SIGSEGV, &old_action);
 
 	return FWTS_OK;
 }
diff --git a/src/main.c b/src/main.c
index 56981d5..ef67b4c 100644
--- a/src/main.c
+++ b/src/main.c
@@ -24,6 +24,8 @@ 
 
 int main(int argc, char **argv)
 {
+	(void)fwts_fault_catch();
+
 	if (fwts_framework_args(argc, argv) == FWTS_OK)
 		exit(EXIT_SUCCESS);
 	else