Print error rather than abort
[userspace-rcu.git] / urcu-checker.c
index 234bd9bc68e72ffb45ef5ef12e4ffe6723b6f3e4..cd4721d3cd95f1a1a4f2454dd5c19b99c5807ff6 100644 (file)
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
+/*
+ * NOTE: build application with -rdynamic -ldl -lurcu-common.
+ */
+
+#define _GNU_SOURCE
 #include <string.h>
 #include <assert.h>
 #include <stdlib.h>
 #include <stdio.h>
+#include <execinfo.h>
+#include <dlfcn.h>
+#include <sys/types.h>
 #include <urcu/urcu-checker.h>
 #include <urcu/tls-compat.h>
 
-#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 <syscall.h>
+#endif
+
+#if defined(_syscall0)
+_syscall0(pid_t, gettid)
+#elif defined(__NR_gettid)
+#include <unistd.h>
+static inline pid_t gettid(void)
+{
+       return syscall(__NR_gettid);
+}
+#else
+#include <sys/types.h>
+#include <unistd.h>
+
+/* 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);
        }
 }
This page took 0.023793 seconds and 4 git commands to generate.