Skip to content

Add custom debug printing for your asserts #15792

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
149 changes: 137 additions & 12 deletions include/os/freebsd/spl/sys/debug.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,33 @@
/*
* Common DEBUG functionality.
*/
#ifdef __FreeBSD__
#include <linux/compiler.h>
#endif

#ifndef __printflike
#define __printflike(a, b) __printf(a, b)
#endif

#ifndef __maybe_unused
#define __maybe_unused __attribute__((unused))
#endif

/*
* Without this, we see warnings from objtool during normal Linux builds when
* the kernel is built with CONFIG_STACK_VALIDATION=y:
*
* warning: objtool: tsd_create() falls through to next function __list_add()
* warning: objtool: .text: unexpected end of section
*
* Until the toolchain stops doing this, we must only define this attribute on
* spl_panic() when doing static analysis.
*/
#if defined(__COVERITY__) || defined(__clang_analyzer__)
__attribute__((__noreturn__))
#endif
extern void spl_panic(const char *file, const char *func, int line,
const char *fmt, ...) __attribute__((__noreturn__));
const char *fmt, ...);
extern void spl_dumpstack(void);

static inline int
Expand All @@ -73,8 +95,10 @@ spl_assert(const char *buf, const char *file, const char *func, int line)
#ifndef expect
#define expect(expr, value) (__builtin_expect((expr), (value)))
#endif
#ifndef __linux__
#define likely(expr) expect((expr) != 0, 1)
#define unlikely(expr) expect((expr) != 0, 0)
#endif

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

#define VERIFYF(cond, str, ...) do { \
if (unlikely(!cond)) \
spl_panic(__FILE__, __FUNCTION__, __LINE__, \
"VERIFY(" #cond ") failed " str "\n", __VA_ARGS__);\
} while (0)

#define VERIFY3B(LEFT, OP, RIGHT) do { \
const boolean_t _verify3_left = (boolean_t)(LEFT); \
const boolean_t _verify3_right = (boolean_t)(RIGHT); \
Expand Down Expand Up @@ -123,7 +153,7 @@ spl_assert(const char *buf, const char *file, const char *func, int line)
if (unlikely(!(_verify3_left OP _verify3_right))) \
spl_panic(__FILE__, __FUNCTION__, __LINE__, \
"VERIFY3(" #LEFT " " #OP " " #RIGHT ") " \
"failed (%p " #OP " %p)\n", \
"failed (%px " #OP " %px)\n", \
(void *)_verify3_left, \
(void *)_verify3_right); \
} while (0)
Expand All @@ -142,10 +172,98 @@ spl_assert(const char *buf, const char *file, const char *func, int line)
if (unlikely(!(0 == _verify0_right))) \
spl_panic(__FILE__, __FUNCTION__, __LINE__, \
"VERIFY0P(" #RIGHT ") " \
"failed (NULL == %p)\n", \
"failed (NULL == %px)\n", \
(void *)_verify0_right); \
} while (0)

/*
* Note that you should not put any operations you want to always happen
* in the print section for ASSERTs unless you only want them to run on
* debug builds!
* e.g. ASSERT3UF(2, <, 3, "%s", foo(x)), foo(x) won't run on non-debug
* builds.
*/

#define VERIFY3BF(LEFT, OP, RIGHT, STR, ...) do { \
const boolean_t _verify3_left = (boolean_t)(LEFT); \
const boolean_t _verify3_right = (boolean_t)(RIGHT); \
if (unlikely(!(_verify3_left OP _verify3_right))) \
spl_panic(__FILE__, __FUNCTION__, __LINE__, \
"VERIFY3(" #LEFT " " #OP " " #RIGHT ") " \
"failed (%d " #OP " %d) " STR "\n", \
(boolean_t)(_verify3_left), \
(boolean_t)(_verify3_right), \
__VA_ARGS__); \
} while (0)

#define VERIFY3SF(LEFT, OP, RIGHT, STR, ...) do { \
const int64_t _verify3_left = (int64_t)(LEFT); \
const int64_t _verify3_right = (int64_t)(RIGHT); \
if (unlikely(!(_verify3_left OP _verify3_right))) \
spl_panic(__FILE__, __FUNCTION__, __LINE__, \
"VERIFY3(" #LEFT " " #OP " " #RIGHT ") " \
"failed (%lld " #OP " %lld) " STR "\n", \
(long long)(_verify3_left), \
(long long)(_verify3_right), \
__VA_ARGS); \
} while (0)

#define VERIFY3UF(LEFT, OP, RIGHT, STR, ...) do { \
const uint64_t _verify3_left = (uint64_t)(LEFT); \
const uint64_t _verify3_right = (uint64_t)(RIGHT); \
if (unlikely(!(_verify3_left OP _verify3_right))) \
spl_panic(__FILE__, __FUNCTION__, __LINE__, \
"VERIFY3(" #LEFT " " #OP " " #RIGHT ") " \
"failed (%llu " #OP " %llu) " STR "\n", \
(unsigned long long)(_verify3_left), \
(unsigned long long)(_verify3_right), \
__VA_ARGS); \
} while (0)

#define VERIFY3PF(LEFT, OP, RIGHT, STR, ...) do { \
const uintptr_t _verify3_left = (uintptr_t)(LEFT); \
const uintptr_t _verify3_right = (uintptr_t)(RIGHT); \
if (unlikely(!(_verify3_left OP _verify3_right))) \
spl_panic(__FILE__, __FUNCTION__, __LINE__, \
"VERIFY3(" #LEFT " " #OP " " #RIGHT ") " \
"failed (%px " #OP " %px) " STR "\n", \
(void *) (_verify3_left), \
(void *) (_verify3_right), \
__VA_ARGS__); \
} while (0)

#define VERIFY0PF(RIGHT, STR, ...) do { \
const uintptr_t _verify3_left = (uintptr_t)(0); \
const uintptr_t _verify3_right = (uintptr_t)(RIGHT); \
if (unlikely(!(_verify3_left == _verify3_right))) \
spl_panic(__FILE__, __FUNCTION__, __LINE__, \
"VERIFY0(0 == " #RIGHT ") " \
"failed (0 == %px) " STR "\n", \
(long long) (_verify3_right), \
__VA_ARGS__); \
} while (0)

#define VERIFY0F(RIGHT, STR, ...) do { \
const int64_t _verify3_left = (int64_t)(0); \
const int64_t _verify3_right = (int64_t)(RIGHT); \
if (unlikely(!(_verify3_left == _verify3_right))) \
spl_panic(__FILE__, __FUNCTION__, __LINE__, \
"VERIFY0(0 == " #RIGHT ") " \
"failed (0 == %lld) " STR "\n", \
(long long) (_verify3_right), \
__VA_ARGS__); \
} while (0)

#define VERIFY_IMPLY(A, B) \
((void)(likely((!(A)) || (B)) || \
spl_assert("(" #A ") implies (" #B ")", \
__FILE__, __FUNCTION__, __LINE__)))

#define VERIFY_EQUIV(A, B) \
((void)(likely(!!(A) == !!(B)) || \
spl_assert("(" #A ") is equivalent to (" #B ")", \
__FILE__, __FUNCTION__, __LINE__)))

/*
* Debugging disabled (--disable-debug)
*/
Expand All @@ -162,6 +280,13 @@ spl_assert(const char *buf, const char *file, const char *func, int line)
((void) sizeof ((uintptr_t)(x)), (void) sizeof ((uintptr_t)(z)))
#define ASSERT0(x) ((void) sizeof ((uintptr_t)(x)))
#define ASSERT0P(x) ((void) sizeof ((uintptr_t)(x)))
#define ASSERT3BF(x, y, z, str, ...) ASSERT3B(x, y, z)
#define ASSERT3SF(x, y, z, str, ...) ASSERT3S(x, y, z)
#define ASSERT3UF(x, y, z, str, ...) ASSERT3U(x, y, z)
#define ASSERT3PF(x, y, z, str, ...) ASSERT3P(x, y, z)
#define ASSERT0PF(x, str, ...) ASSERT0P(x)
#define ASSERT0F(x, str, ...) ASSERT0(x)
#define ASSERTF(x, str, ...) ASSERT(x)
#define IMPLY(A, B) \
((void) sizeof ((uintptr_t)(A)), (void) sizeof ((uintptr_t)(B)))
#define EQUIV(A, B) \
Expand All @@ -178,16 +303,16 @@ spl_assert(const char *buf, const char *file, const char *func, int line)
#define ASSERT3P VERIFY3P
#define ASSERT0 VERIFY0
#define ASSERT0P VERIFY0P
#define ASSERT3BF VERIFY3BF
#define ASSERT3SF VERIFY3SF
#define ASSERT3UF VERIFY3UF
#define ASSERT3PF VERIFY3PF
#define ASSERT0PF VERIFY0PF
#define ASSERT0F VERIFY0F
#define ASSERTF VERIFYF
#define ASSERT VERIFY
#define IMPLY(A, B) \
((void)(likely((!(A)) || (B)) || \
spl_assert("(" #A ") implies (" #B ")", \
__FILE__, __FUNCTION__, __LINE__)))
#define EQUIV(A, B) \
((void)(likely(!!(A) == !!(B)) || \
spl_assert("(" #A ") is equivalent to (" #B ")", \
__FILE__, __FUNCTION__, __LINE__)))

#define IMPLY VERIFY_IMPLY
#define EQUIV VERIFY_EQUIV

#endif /* NDEBUG */

Expand Down
Loading