4 * Userspace RCU library checker
6 * Copyright (c) 2014 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24 * NOTE: build application with -rdynamic -ldl -lurcu-common.
34 #include <sys/types.h>
35 #include <urcu/urcu-checker.h>
36 #include <urcu/tls-compat.h>
38 #define URCU_DEBUG_STACK_LEN 10
39 #define DEFAULT_PRINT_BACKTRACE_LEN 5
40 #define BACKTRACE_LEN 16
46 #if defined(_syscall0)
47 _syscall0(pid_t
, gettid
)
48 #elif defined(__NR_gettid)
50 static inline pid_t
gettid(void)
52 return syscall(__NR_gettid
);
55 #include <sys/types.h>
58 /* Fall-back on getpid for tid if not available. */
59 static inline pid_t
gettid(void)
65 #define err_printf(fmt, args...) \
66 fprintf(stderr, "[urcu-checker %ld/%ld] " fmt, \
67 (long) getpid(), (long) gettid(), ## args)
69 struct urcu_debug_entry
{
74 struct urcu_debug_stack
{
75 struct urcu_debug_entry stack
[URCU_DEBUG_STACK_LEN
];
80 void *ptrs
[BACKTRACE_LEN
];
84 static DEFINE_URCU_TLS(struct urcu_debug_stack
, rcu_debug_stack
);
86 static volatile int print_backtrace_len
= DEFAULT_PRINT_BACKTRACE_LEN
;
89 * Allocates a string, or NULL.
92 char *get_symbol(const void *caller
)
97 if (caller
&& dladdr(caller
, &info
) && info
.dli_sname
) {
98 caller_symbol
= strdup(info
.dli_sname
);
100 caller_symbol
= NULL
;
102 return caller_symbol
;
105 static inline __attribute__((always_inline
))
106 void save_backtrace(struct backtrace
*bt
)
108 memset(bt
, 0, sizeof(*bt
));
109 (void) backtrace(bt
->ptrs
, BACKTRACE_LEN
);
110 bt
->symbols
= backtrace_symbols(bt
->ptrs
, BACKTRACE_LEN
);
114 void free_backtrace(struct backtrace
*bt
)
120 void print_bt(struct backtrace
*bt
)
123 unsigned int empty
= 1;
125 for (j
= 0; j
< BACKTRACE_LEN
; j
++) {
134 err_printf("[backtrace]\n");
135 for (j
= 0; j
< BACKTRACE_LEN
&& j
< print_backtrace_len
; j
++) {
139 err_printf(" %p <%s>\n", bt
->ptrs
[j
], bt
->symbols
[j
]);
141 err_printf(" %p\n", bt
->ptrs
[j
]);
145 void rcu_read_lock_debug(void)
147 struct urcu_debug_stack
*r
= &URCU_TLS(rcu_debug_stack
);
149 r
->stack
[r
->stackend
++].ip
= __builtin_return_address(0);
152 void rcu_read_unlock_debug(void)
154 struct urcu_debug_stack
*r
= &URCU_TLS(rcu_debug_stack
);
156 assert(r
->stackend
!= 0);
157 r
->stack
[--r
->stackend
].ip
= NULL
;
160 void rcu_read_ongoing_check_debug(const char *func
)
162 struct urcu_debug_stack
*r
= &URCU_TLS(rcu_debug_stack
);
164 if (r
->stackend
== 0) {
167 err_printf("rcu_dereference() used outside of critical section at %p <%s>\n",
168 __builtin_return_address(0),
169 get_symbol(__builtin_return_address(0)));