X-Git-Url: http://git.liburcu.org/?p=userspace-rcu.git;a=blobdiff_plain;f=urcu-checker.c;fp=urcu-checker.c;h=cd4721d3cd95f1a1a4f2454dd5c19b99c5807ff6;hp=234bd9bc68e72ffb45ef5ef12e4ffe6723b6f3e4;hb=8a325ad789d5a2c5e079dd210c2c6c40a1703195;hpb=791151d0b8f0314496cf18c822c071b1dd5791ea 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); } }