validation: print backtrace on segfault and other related signals

Message ID 1455711101-24345-1-git-send-email-maxim.uvarov@linaro.org
State New
Headers show

Commit Message

Maxim Uvarov Feb. 17, 2016, 12:11 p.m.
If any test got segmentation fault it's better to print something useful
for debug. That function is based on example code for TM. I hope it will
help to see fails in CI where is not clear how to get core files.

Signed-off-by: Maxim Uvarov <maxim.uvarov@linaro.org>
---
 test/validation/common/odp_cunit_common.c | 67 +++++++++++++++++++++++++++++++
 1 file changed, 67 insertions(+)

Comments

Maxim Uvarov Feb. 25, 2016, 12:26 p.m. | #1
ping. Is that reasonable patch?

Maxim.

On 02/17/16 15:11, Maxim Uvarov wrote:
> If any test got segmentation fault it's better to print something useful
> for debug. That function is based on example code for TM. I hope it will
> help to see fails in CI where is not clear how to get core files.
>
> Signed-off-by: Maxim Uvarov <maxim.uvarov@linaro.org>
> ---
>   test/validation/common/odp_cunit_common.c | 67 +++++++++++++++++++++++++++++++
>   1 file changed, 67 insertions(+)
>
> diff --git a/test/validation/common/odp_cunit_common.c b/test/validation/common/odp_cunit_common.c
> index dbd8229..602a508 100644
> --- a/test/validation/common/odp_cunit_common.c
> +++ b/test/validation/common/odp_cunit_common.c
> @@ -4,10 +4,19 @@
>    * SPDX-License-Identifier:     BSD-3-Clause
>    */
>   
> +#include <odp_posix_extensions.h>
>   #include <string.h>
> +#include <stdio.h>
> +#include <signal.h>
> +#include <execinfo.h>
> +#include <unistd.h>
> +#include <sys/time.h>
> +#include <sys/resource.h>
> +
>   #include <odp_api.h>
>   #include <odp_cunit_common.h>
>   #include <odp/helper/linux.h>
> +
>   /* Globals */
>   static odph_linux_pthread_t thread_tbl[MAX_WORKERS];
>   
> @@ -23,6 +32,7 @@ static struct {
>   } global_init_term = {tests_global_init, tests_global_term};
>   
>   static odp_suiteinfo_t *global_testsuites;
> +static odp_spinlock_t print_lock;
>   
>   /** create test thread */
>   int odp_cunit_thread_create(void *func_ptr(void *), pthrd_arg *arg)
> @@ -115,6 +125,61 @@ static odp_testinfo_t *cunit_get_test_info(odp_suiteinfo_t *sinfo,
>   	return NULL;
>   }
>   
> +static void fault_handler(int signal)
> +{
> +	size_t num_stack_frames;
> +	const char  *signal_name;
> +	void  *bt_array[128];
> +	sigset_t sigset;
> +
> +	/* disable all signals */
> +	sigfillset(&sigset);
> +	sigprocmask(SIG_BLOCK, &sigset, NULL);
> +
> +	switch (signal) {
> +	case SIGILL:
> +		signal_name = "SIGILL";   break;
> +	case SIGFPE:
> +		signal_name = "SIGFPE";   break;
> +	case SIGSEGV:
> +		signal_name = "SIGSEGV";  break;
> +	case SIGTERM:
> +		signal_name = "SIGTERM";  break;
> +	case SIGBUS:
> +		signal_name = "SIGBUS";   break;
> +	default:
> +		signal_name = "UNKNOWN";  break;
> +	}
> +
> +	odp_spinlock_lock(&print_lock);
> +	num_stack_frames = backtrace(bt_array, 100);
> +	printf("\nThread %d terminated with signal=%u (%s)\n",
> +	       odp_thread_id(), signal, signal_name);
> +	backtrace_symbols_fd(bt_array, num_stack_frames, fileno(stderr));
> +	fflush(NULL);
> +	sync();
> +	odp_spinlock_unlock(&print_lock);
> +
> +	CU_ASSERT_FATAL(0);
> +}
> +
> +static void register_fault_handler(void)
> +{
> +	struct sigaction signal_action;
> +
> +	odp_spinlock_init(&print_lock);
> +
> +	memset(&signal_action, 0, sizeof(signal_action));
> +	signal_action.sa_handler = fault_handler;
> +	sigfillset(&signal_action.sa_mask);
> +
> +	sigaction(SIGILL,  &signal_action, NULL);
> +	sigaction(SIGFPE,  &signal_action, NULL);
> +	sigaction(SIGSEGV, &signal_action, NULL);
> +	sigaction(SIGTERM, &signal_action, NULL);
> +	sigaction(SIGBUS,  &signal_action, NULL);
> +}
> +
>   /* A wrapper for the suite's init function. This is done to allow for a
>    * potential runtime check to determine whether each test in the suite
>    * is active (enabled by using ODP_TEST_INFO_CONDITIONAL()). If present,
> @@ -328,6 +393,8 @@ int odp_cunit_register(odp_suiteinfo_t testsuites[])
>   
>   	CU_set_error_action(CUEA_ABORT);
>   
> +	register_fault_handler();
> +
>   	CU_initialize_registry();
>   	global_testsuites = testsuites;
>   	cunit_register_suites(testsuites);
Mike Holmes March 2, 2016, 10:50 p.m. | #2
On 25 February 2016 at 07:26, Maxim Uvarov <maxim.uvarov@linaro.org> wrote:

> ping. Is that reasonable patch?



This makes the test framework more dependant on Linux and the validation
suite needs to be agnostic, so I have to vote no, but agree that we should
improve things.



>

>

> Maxim.

>

>

> On 02/17/16 15:11, Maxim Uvarov wrote:

>

>> If any test got segmentation fault it's better to print something useful

>> for debug. That function is based on example code for TM. I hope it will

>> help to see fails in CI where is not clear how to get core files.

>>

>> Signed-off-by: Maxim Uvarov <maxim.uvarov@linaro.org>

>> ---

>>   test/validation/common/odp_cunit_common.c | 67

>> +++++++++++++++++++++++++++++++

>>   1 file changed, 67 insertions(+)

>>

>> diff --git a/test/validation/common/odp_cunit_common.c

>> b/test/validation/common/odp_cunit_common.c

>> index dbd8229..602a508 100644

>> --- a/test/validation/common/odp_cunit_common.c

>> +++ b/test/validation/common/odp_cunit_common.c

>> @@ -4,10 +4,19 @@

>>    * SPDX-License-Identifier:     BSD-3-Clause

>>    */

>>   +#include <odp_posix_extensions.h>

>>   #include <string.h>

>> +#include <stdio.h>

>> +#include <signal.h>

>> +#include <execinfo.h>

>> +#include <unistd.h>

>> +#include <sys/time.h>

>> +#include <sys/resource.h>

>> +

>>   #include <odp_api.h>

>>   #include <odp_cunit_common.h>

>>   #include <odp/helper/linux.h>

>> +

>>   /* Globals */

>>   static odph_linux_pthread_t thread_tbl[MAX_WORKERS];

>>   @@ -23,6 +32,7 @@ static struct {

>>   } global_init_term = {tests_global_init, tests_global_term};

>>     static odp_suiteinfo_t *global_testsuites;

>> +static odp_spinlock_t print_lock;

>>     /** create test thread */

>>   int odp_cunit_thread_create(void *func_ptr(void *), pthrd_arg *arg)

>> @@ -115,6 +125,61 @@ static odp_testinfo_t

>> *cunit_get_test_info(odp_suiteinfo_t *sinfo,

>>         return NULL;

>>   }

>>   +static void fault_handler(int signal)

>> +{

>> +       size_t num_stack_frames;

>> +       const char  *signal_name;

>> +       void  *bt_array[128];

>> +       sigset_t sigset;

>> +

>> +       /* disable all signals */

>> +       sigfillset(&sigset);

>> +       sigprocmask(SIG_BLOCK, &sigset, NULL);

>> +

>> +       switch (signal) {

>> +       case SIGILL:

>> +               signal_name = "SIGILL";   break;

>> +       case SIGFPE:

>> +               signal_name = "SIGFPE";   break;

>> +       case SIGSEGV:

>> +               signal_name = "SIGSEGV";  break;

>> +       case SIGTERM:

>> +               signal_name = "SIGTERM";  break;

>> +       case SIGBUS:

>> +               signal_name = "SIGBUS";   break;

>> +       default:

>> +               signal_name = "UNKNOWN";  break;

>> +       }

>> +

>> +       odp_spinlock_lock(&print_lock);

>> +       num_stack_frames = backtrace(bt_array, 100);

>> +       printf("\nThread %d terminated with signal=%u (%s)\n",

>> +              odp_thread_id(), signal, signal_name);

>> +       backtrace_symbols_fd(bt_array, num_stack_frames, fileno(stderr));

>> +       fflush(NULL);

>> +       sync();

>> +       odp_spinlock_unlock(&print_lock);

>> +

>> +       CU_ASSERT_FATAL(0);

>> +}

>> +

>> +static void register_fault_handler(void)

>> +{

>> +       struct sigaction signal_action;

>> +

>> +       odp_spinlock_init(&print_lock);

>> +

>> +       memset(&signal_action, 0, sizeof(signal_action));

>> +       signal_action.sa_handler = fault_handler;

>> +       sigfillset(&signal_action.sa_mask);

>> +

>> +       sigaction(SIGILL,  &signal_action, NULL);

>> +       sigaction(SIGFPE,  &signal_action, NULL);

>> +       sigaction(SIGSEGV, &signal_action, NULL);

>> +       sigaction(SIGTERM, &signal_action, NULL);

>> +       sigaction(SIGBUS,  &signal_action, NULL);

>> +}

>> +

>>   /* A wrapper for the suite's init function. This is done to allow for a

>>    * potential runtime check to determine whether each test in the suite

>>    * is active (enabled by using ODP_TEST_INFO_CONDITIONAL()). If present,

>> @@ -328,6 +393,8 @@ int odp_cunit_register(odp_suiteinfo_t testsuites[])

>>         CU_set_error_action(CUEA_ABORT);

>>   +     register_fault_handler();

>> +

>>         CU_initialize_registry();

>>         global_testsuites = testsuites;

>>         cunit_register_suites(testsuites);

>>

>

> _______________________________________________

> lng-odp mailing list

> lng-odp@lists.linaro.org

> https://lists.linaro.org/mailman/listinfo/lng-odp

>




-- 
Mike Holmes
Technical Manager - Linaro Networking Group
Linaro.org <http://www.linaro.org/> *│ *Open source software for ARM SoCs
"Work should be fun and collborative, the rest follows"

Patch

diff --git a/test/validation/common/odp_cunit_common.c b/test/validation/common/odp_cunit_common.c
index dbd8229..602a508 100644
--- a/test/validation/common/odp_cunit_common.c
+++ b/test/validation/common/odp_cunit_common.c
@@ -4,10 +4,19 @@ 
  * SPDX-License-Identifier:     BSD-3-Clause
  */
 
+#include <odp_posix_extensions.h>
 #include <string.h>
+#include <stdio.h>
+#include <signal.h>
+#include <execinfo.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
 #include <odp_api.h>
 #include <odp_cunit_common.h>
 #include <odp/helper/linux.h>
+
 /* Globals */
 static odph_linux_pthread_t thread_tbl[MAX_WORKERS];
 
@@ -23,6 +32,7 @@  static struct {
 } global_init_term = {tests_global_init, tests_global_term};
 
 static odp_suiteinfo_t *global_testsuites;
+static odp_spinlock_t print_lock;
 
 /** create test thread */
 int odp_cunit_thread_create(void *func_ptr(void *), pthrd_arg *arg)
@@ -115,6 +125,61 @@  static odp_testinfo_t *cunit_get_test_info(odp_suiteinfo_t *sinfo,
 	return NULL;
 }
 
+static void fault_handler(int signal)
+{
+	size_t num_stack_frames;
+	const char  *signal_name;
+	void  *bt_array[128];
+	sigset_t sigset;
+
+	/* disable all signals */
+	sigfillset(&sigset);
+	sigprocmask(SIG_BLOCK, &sigset, NULL);
+
+	switch (signal) {
+	case SIGILL:
+		signal_name = "SIGILL";   break;
+	case SIGFPE:
+		signal_name = "SIGFPE";   break;
+	case SIGSEGV:
+		signal_name = "SIGSEGV";  break;
+	case SIGTERM:
+		signal_name = "SIGTERM";  break;
+	case SIGBUS:
+		signal_name = "SIGBUS";   break;
+	default:
+		signal_name = "UNKNOWN";  break;
+	}
+
+	odp_spinlock_lock(&print_lock);
+	num_stack_frames = backtrace(bt_array, 100);
+	printf("\nThread %d terminated with signal=%u (%s)\n",
+	       odp_thread_id(), signal, signal_name);
+	backtrace_symbols_fd(bt_array, num_stack_frames, fileno(stderr));
+	fflush(NULL);
+	sync();
+	odp_spinlock_unlock(&print_lock);
+
+	CU_ASSERT_FATAL(0);
+}
+
+static void register_fault_handler(void)
+{
+	struct sigaction signal_action;
+
+	odp_spinlock_init(&print_lock);
+
+	memset(&signal_action, 0, sizeof(signal_action));
+	signal_action.sa_handler = fault_handler;
+	sigfillset(&signal_action.sa_mask);
+
+	sigaction(SIGILL,  &signal_action, NULL);
+	sigaction(SIGFPE,  &signal_action, NULL);
+	sigaction(SIGSEGV, &signal_action, NULL);
+	sigaction(SIGTERM, &signal_action, NULL);
+	sigaction(SIGBUS,  &signal_action, NULL);
+}
+
 /* A wrapper for the suite's init function. This is done to allow for a
  * potential runtime check to determine whether each test in the suite
  * is active (enabled by using ODP_TEST_INFO_CONDITIONAL()). If present,
@@ -328,6 +393,8 @@  int odp_cunit_register(odp_suiteinfo_t testsuites[])
 
 	CU_set_error_action(CUEA_ABORT);
 
+	register_fault_handler();
+
 	CU_initialize_registry();
 	global_testsuites = testsuites;
 	cunit_register_suites(testsuites);