From 8a325ad789d5a2c5e079dd210c2c6c40a1703195 Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Thu, 13 Nov 2014 14:58:22 -0500 Subject: [PATCH] Print error rather than abort Signed-off-by: Mathieu Desnoyers --- Makefile.am | 1 + tests/benchmark/Makefile.am | 2 +- tests/regression/Makefile.am | 2 +- tests/unit/Makefile.am | 2 +- urcu-checker.c | 114 +++++++++++++++++++++++++++++++++-- 5 files changed, 114 insertions(+), 7 deletions(-) diff --git a/Makefile.am b/Makefile.am index 7ead5f0..8fbf11d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -59,6 +59,7 @@ lib_LTLIBRARIES = liburcu-common.la \ # liburcu_common_la_SOURCES = wfqueue.c wfcqueue.c wfstack.c $(COMPAT) \ urcu-checker.c +liburcu_common_la_LDFLAGS = -ldl liburcu_la_SOURCES = urcu.c urcu-pointer.c $(COMPAT) liburcu_la_LIBADD = liburcu-common.la diff --git a/tests/benchmark/Makefile.am b/tests/benchmark/Makefile.am index b8cf35d..17c1fe0 100644 --- a/tests/benchmark/Makefile.am +++ b/tests/benchmark/Makefile.am @@ -1,7 +1,7 @@ if !LIBC_INCLUDES_PTHREAD AM_LDFLAGS=-lpthread endif -AM_CFLAGS=-I$(top_srcdir) -I$(top_builddir) -I$(top_srcdir)/tests/common -g +AM_CFLAGS=-I$(top_srcdir) -I$(top_builddir) -I$(top_srcdir)/tests/common -g -ldl noinst_PROGRAMS = test_urcu test_urcu_dynamic_link test_urcu_timing \ test_urcu_signal test_urcu_signal_dynamic_link test_urcu_signal_timing \ diff --git a/tests/regression/Makefile.am b/tests/regression/Makefile.am index 354ad1a..8701e9b 100644 --- a/tests/regression/Makefile.am +++ b/tests/regression/Makefile.am @@ -1,7 +1,7 @@ if !LIBC_INCLUDES_PTHREAD AM_LDFLAGS=-lpthread endif -AM_CFLAGS=-I$(top_srcdir) -I$(top_builddir) -I$(top_srcdir)/tests/common -g +AM_CFLAGS=-I$(top_srcdir) -I$(top_builddir) -I$(top_srcdir)/tests/common -g -ldl noinst_PROGRAMS = test_urcu_fork \ rcutorture_urcu \ diff --git a/tests/unit/Makefile.am b/tests/unit/Makefile.am index cd40b39..97275a6 100644 --- a/tests/unit/Makefile.am +++ b/tests/unit/Makefile.am @@ -1,7 +1,7 @@ if !LIBC_INCLUDES_PTHREAD AM_LDFLAGS=-lpthread endif -AM_CFLAGS=-I$(top_srcdir) -I$(top_builddir) -I$(top_srcdir)/tests/common -g +AM_CFLAGS=-I$(top_srcdir) -I$(top_builddir) -I$(top_srcdir)/tests/common -g -ldl noinst_PROGRAMS = test_uatomic \ test_urcu_multiflavor \ diff --git a/urcu-checker.c b/urcu-checker.c index 234bd9b..cd4721d 100644 --- a/urcu-checker.c +++ b/urcu-checker.c @@ -20,14 +20,51 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +/* + * NOTE: build application with -rdynamic -ldl -lurcu-common. + */ + +#define _GNU_SOURCE #include #include #include #include +#include +#include +#include #include #include -#define URCU_DEBUG_STACK_LEN 10 +#define URCU_DEBUG_STACK_LEN 10 +#define DEFAULT_PRINT_BACKTRACE_LEN 5 +#define BACKTRACE_LEN 16 + +#ifdef __linux__ +#include +#endif + +#if defined(_syscall0) +_syscall0(pid_t, gettid) +#elif defined(__NR_gettid) +#include +static inline pid_t gettid(void) +{ + return syscall(__NR_gettid); +} +#else +#include +#include + +/* Fall-back on getpid for tid if not available. */ +static inline pid_t gettid(void) +{ + return getpid(); +} +#endif + +#define err_printf(fmt, args...) \ + fprintf(stderr, "[urcu-checker %ld/%ld] " fmt, \ + (long) getpid(), (long) gettid(), ## args) struct urcu_debug_entry { void *ip; @@ -39,8 +76,72 @@ struct urcu_debug_stack { int stackend; }; +struct backtrace { + void *ptrs[BACKTRACE_LEN]; + char **symbols; +}; + static DEFINE_URCU_TLS(struct urcu_debug_stack, rcu_debug_stack); +static volatile int print_backtrace_len = DEFAULT_PRINT_BACKTRACE_LEN; + +/* + * Allocates a string, or NULL. + */ +static +char *get_symbol(const void *caller) +{ + Dl_info info; + char *caller_symbol; + + if (caller && dladdr(caller, &info) && info.dli_sname) { + caller_symbol = strdup(info.dli_sname); + } else { + caller_symbol = NULL; + } + return caller_symbol; +} + +static inline __attribute__((always_inline)) +void save_backtrace(struct backtrace *bt) +{ + memset(bt, 0, sizeof(*bt)); + (void) backtrace(bt->ptrs, BACKTRACE_LEN); + bt->symbols = backtrace_symbols(bt->ptrs, BACKTRACE_LEN); +} + +static +void free_backtrace(struct backtrace *bt) +{ + free(bt->symbols); +} + +static +void print_bt(struct backtrace *bt) +{ + int j; + unsigned int empty = 1; + + for (j = 0; j < BACKTRACE_LEN; j++) { + if (bt->ptrs[j]) { + empty = 0; + break; + } + } + if (empty) + return; + + err_printf("[backtrace]\n"); + for (j = 0; j < BACKTRACE_LEN && j < print_backtrace_len; j++) { + if (!bt->ptrs[j]) + continue; + if (bt->symbols) + err_printf(" %p <%s>\n", bt->ptrs[j], bt->symbols[j]); + else + err_printf(" %p\n", bt->ptrs[j]); + } +} + void rcu_read_lock_debug(void) { struct urcu_debug_stack *r = &URCU_TLS(rcu_debug_stack); @@ -61,8 +162,13 @@ void rcu_read_ongoing_check_debug(const char *func) struct urcu_debug_stack *r = &URCU_TLS(rcu_debug_stack); if (r->stackend == 0) { - fprintf(stderr, "URCU LOCKED CHECK failure: %p\n", - __builtin_return_address(0)); - abort(); + struct backtrace bt; + + err_printf("rcu_dereference() used outside of critical section at %p <%s>\n", + __builtin_return_address(0), + get_symbol(__builtin_return_address(0))); + save_backtrace(&bt); + print_bt(&bt); + free_backtrace(&bt); } } -- 2.34.1