Skip to content

Commit e5e2a5a

Browse files
authored
Add custom debug printing for your asserts
Being able to print custom debug information on assert trip seems useful. Reviewed-by: Brian Behlendorf <[email protected]> Reviewed-by: Paul Dagnelie <[email protected]> Signed-off-by: Rich Ercolani <[email protected]> Closes #15792
1 parent d98973d commit e5e2a5a

File tree

4 files changed

+372
-31
lines changed

4 files changed

+372
-31
lines changed

include/os/freebsd/spl/sys/debug.h

Lines changed: 137 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,33 @@
5656
/*
5757
* Common DEBUG functionality.
5858
*/
59+
#ifdef __FreeBSD__
60+
#include <linux/compiler.h>
61+
#endif
62+
63+
#ifndef __printflike
64+
#define __printflike(a, b) __printf(a, b)
65+
#endif
66+
67+
#ifndef __maybe_unused
68+
#define __maybe_unused __attribute__((unused))
69+
#endif
70+
71+
/*
72+
* Without this, we see warnings from objtool during normal Linux builds when
73+
* the kernel is built with CONFIG_STACK_VALIDATION=y:
74+
*
75+
* warning: objtool: tsd_create() falls through to next function __list_add()
76+
* warning: objtool: .text: unexpected end of section
77+
*
78+
* Until the toolchain stops doing this, we must only define this attribute on
79+
* spl_panic() when doing static analysis.
80+
*/
5981
#if defined(__COVERITY__) || defined(__clang_analyzer__)
6082
__attribute__((__noreturn__))
6183
#endif
6284
extern void spl_panic(const char *file, const char *func, int line,
63-
const char *fmt, ...) __attribute__((__noreturn__));
85+
const char *fmt, ...);
6486
extern void spl_dumpstack(void);
6587

6688
static inline int
@@ -73,8 +95,10 @@ spl_assert(const char *buf, const char *file, const char *func, int line)
7395
#ifndef expect
7496
#define expect(expr, value) (__builtin_expect((expr), (value)))
7597
#endif
98+
#ifndef __linux__
7699
#define likely(expr) expect((expr) != 0, 1)
77100
#define unlikely(expr) expect((expr) != 0, 0)
101+
#endif
78102

79103
#define PANIC(fmt, a...) \
80104
spl_panic(__FILE__, __FUNCTION__, __LINE__, fmt, ## a)
@@ -84,6 +108,12 @@ spl_assert(const char *buf, const char *file, const char *func, int line)
84108
spl_assert("VERIFY(" #cond ") failed\n", \
85109
__FILE__, __FUNCTION__, __LINE__))
86110

111+
#define VERIFYF(cond, str, ...) do { \
112+
if (unlikely(!cond)) \
113+
spl_panic(__FILE__, __FUNCTION__, __LINE__, \
114+
"VERIFY(" #cond ") failed " str "\n", __VA_ARGS__);\
115+
} while (0)
116+
87117
#define VERIFY3B(LEFT, OP, RIGHT) do { \
88118
const boolean_t _verify3_left = (boolean_t)(LEFT); \
89119
const boolean_t _verify3_right = (boolean_t)(RIGHT); \
@@ -123,7 +153,7 @@ spl_assert(const char *buf, const char *file, const char *func, int line)
123153
if (unlikely(!(_verify3_left OP _verify3_right))) \
124154
spl_panic(__FILE__, __FUNCTION__, __LINE__, \
125155
"VERIFY3(" #LEFT " " #OP " " #RIGHT ") " \
126-
"failed (%p " #OP " %p)\n", \
156+
"failed (%px " #OP " %px)\n", \
127157
(void *)_verify3_left, \
128158
(void *)_verify3_right); \
129159
} while (0)
@@ -142,10 +172,98 @@ spl_assert(const char *buf, const char *file, const char *func, int line)
142172
if (unlikely(!(0 == _verify0_right))) \
143173
spl_panic(__FILE__, __FUNCTION__, __LINE__, \
144174
"VERIFY0P(" #RIGHT ") " \
145-
"failed (NULL == %p)\n", \
175+
"failed (NULL == %px)\n", \
146176
(void *)_verify0_right); \
147177
} while (0)
148178

179+
/*
180+
* Note that you should not put any operations you want to always happen
181+
* in the print section for ASSERTs unless you only want them to run on
182+
* debug builds!
183+
* e.g. ASSERT3UF(2, <, 3, "%s", foo(x)), foo(x) won't run on non-debug
184+
* builds.
185+
*/
186+
187+
#define VERIFY3BF(LEFT, OP, RIGHT, STR, ...) do { \
188+
const boolean_t _verify3_left = (boolean_t)(LEFT); \
189+
const boolean_t _verify3_right = (boolean_t)(RIGHT); \
190+
if (unlikely(!(_verify3_left OP _verify3_right))) \
191+
spl_panic(__FILE__, __FUNCTION__, __LINE__, \
192+
"VERIFY3(" #LEFT " " #OP " " #RIGHT ") " \
193+
"failed (%d " #OP " %d) " STR "\n", \
194+
(boolean_t)(_verify3_left), \
195+
(boolean_t)(_verify3_right), \
196+
__VA_ARGS__); \
197+
} while (0)
198+
199+
#define VERIFY3SF(LEFT, OP, RIGHT, STR, ...) do { \
200+
const int64_t _verify3_left = (int64_t)(LEFT); \
201+
const int64_t _verify3_right = (int64_t)(RIGHT); \
202+
if (unlikely(!(_verify3_left OP _verify3_right))) \
203+
spl_panic(__FILE__, __FUNCTION__, __LINE__, \
204+
"VERIFY3(" #LEFT " " #OP " " #RIGHT ") " \
205+
"failed (%lld " #OP " %lld) " STR "\n", \
206+
(long long)(_verify3_left), \
207+
(long long)(_verify3_right), \
208+
__VA_ARGS); \
209+
} while (0)
210+
211+
#define VERIFY3UF(LEFT, OP, RIGHT, STR, ...) do { \
212+
const uint64_t _verify3_left = (uint64_t)(LEFT); \
213+
const uint64_t _verify3_right = (uint64_t)(RIGHT); \
214+
if (unlikely(!(_verify3_left OP _verify3_right))) \
215+
spl_panic(__FILE__, __FUNCTION__, __LINE__, \
216+
"VERIFY3(" #LEFT " " #OP " " #RIGHT ") " \
217+
"failed (%llu " #OP " %llu) " STR "\n", \
218+
(unsigned long long)(_verify3_left), \
219+
(unsigned long long)(_verify3_right), \
220+
__VA_ARGS); \
221+
} while (0)
222+
223+
#define VERIFY3PF(LEFT, OP, RIGHT, STR, ...) do { \
224+
const uintptr_t _verify3_left = (uintptr_t)(LEFT); \
225+
const uintptr_t _verify3_right = (uintptr_t)(RIGHT); \
226+
if (unlikely(!(_verify3_left OP _verify3_right))) \
227+
spl_panic(__FILE__, __FUNCTION__, __LINE__, \
228+
"VERIFY3(" #LEFT " " #OP " " #RIGHT ") " \
229+
"failed (%px " #OP " %px) " STR "\n", \
230+
(void *) (_verify3_left), \
231+
(void *) (_verify3_right), \
232+
__VA_ARGS__); \
233+
} while (0)
234+
235+
#define VERIFY0PF(RIGHT, STR, ...) do { \
236+
const uintptr_t _verify3_left = (uintptr_t)(0); \
237+
const uintptr_t _verify3_right = (uintptr_t)(RIGHT); \
238+
if (unlikely(!(_verify3_left == _verify3_right))) \
239+
spl_panic(__FILE__, __FUNCTION__, __LINE__, \
240+
"VERIFY0(0 == " #RIGHT ") " \
241+
"failed (0 == %px) " STR "\n", \
242+
(long long) (_verify3_right), \
243+
__VA_ARGS__); \
244+
} while (0)
245+
246+
#define VERIFY0F(RIGHT, STR, ...) do { \
247+
const int64_t _verify3_left = (int64_t)(0); \
248+
const int64_t _verify3_right = (int64_t)(RIGHT); \
249+
if (unlikely(!(_verify3_left == _verify3_right))) \
250+
spl_panic(__FILE__, __FUNCTION__, __LINE__, \
251+
"VERIFY0(0 == " #RIGHT ") " \
252+
"failed (0 == %lld) " STR "\n", \
253+
(long long) (_verify3_right), \
254+
__VA_ARGS__); \
255+
} while (0)
256+
257+
#define VERIFY_IMPLY(A, B) \
258+
((void)(likely((!(A)) || (B)) || \
259+
spl_assert("(" #A ") implies (" #B ")", \
260+
__FILE__, __FUNCTION__, __LINE__)))
261+
262+
#define VERIFY_EQUIV(A, B) \
263+
((void)(likely(!!(A) == !!(B)) || \
264+
spl_assert("(" #A ") is equivalent to (" #B ")", \
265+
__FILE__, __FUNCTION__, __LINE__)))
266+
149267
/*
150268
* Debugging disabled (--disable-debug)
151269
*/
@@ -162,6 +280,13 @@ spl_assert(const char *buf, const char *file, const char *func, int line)
162280
((void) sizeof ((uintptr_t)(x)), (void) sizeof ((uintptr_t)(z)))
163281
#define ASSERT0(x) ((void) sizeof ((uintptr_t)(x)))
164282
#define ASSERT0P(x) ((void) sizeof ((uintptr_t)(x)))
283+
#define ASSERT3BF(x, y, z, str, ...) ASSERT3B(x, y, z)
284+
#define ASSERT3SF(x, y, z, str, ...) ASSERT3S(x, y, z)
285+
#define ASSERT3UF(x, y, z, str, ...) ASSERT3U(x, y, z)
286+
#define ASSERT3PF(x, y, z, str, ...) ASSERT3P(x, y, z)
287+
#define ASSERT0PF(x, str, ...) ASSERT0P(x)
288+
#define ASSERT0F(x, str, ...) ASSERT0(x)
289+
#define ASSERTF(x, str, ...) ASSERT(x)
165290
#define IMPLY(A, B) \
166291
((void) sizeof ((uintptr_t)(A)), (void) sizeof ((uintptr_t)(B)))
167292
#define EQUIV(A, B) \
@@ -178,16 +303,16 @@ spl_assert(const char *buf, const char *file, const char *func, int line)
178303
#define ASSERT3P VERIFY3P
179304
#define ASSERT0 VERIFY0
180305
#define ASSERT0P VERIFY0P
306+
#define ASSERT3BF VERIFY3BF
307+
#define ASSERT3SF VERIFY3SF
308+
#define ASSERT3UF VERIFY3UF
309+
#define ASSERT3PF VERIFY3PF
310+
#define ASSERT0PF VERIFY0PF
311+
#define ASSERT0F VERIFY0F
312+
#define ASSERTF VERIFYF
181313
#define ASSERT VERIFY
182-
#define IMPLY(A, B) \
183-
((void)(likely((!(A)) || (B)) || \
184-
spl_assert("(" #A ") implies (" #B ")", \
185-
__FILE__, __FUNCTION__, __LINE__)))
186-
#define EQUIV(A, B) \
187-
((void)(likely(!!(A) == !!(B)) || \
188-
spl_assert("(" #A ") is equivalent to (" #B ")", \
189-
__FILE__, __FUNCTION__, __LINE__)))
190-
314+
#define IMPLY VERIFY_IMPLY
315+
#define EQUIV VERIFY_EQUIV
191316

192317
#endif /* NDEBUG */
193318

0 commit comments

Comments
 (0)