Skip to content

Commit 6f3c41d

Browse files
committed
Add custom debug printing for your asserts
This was just a thing I wanted, wondered why nobody had written, so I tried it. Let's see how the CI likes it... Signed-off-by: Rich Ercolani <[email protected]>
1 parent a0b2a93 commit 6f3c41d

File tree

4 files changed

+324
-30
lines changed

4 files changed

+324
-30
lines changed

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

Lines changed: 122 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,22 @@
5656
/*
5757
* Common DEBUG functionality.
5858
*/
59+
#define __printflike(a, b) __printf(a, b)
60+
61+
#ifndef __maybe_unused
62+
#define __maybe_unused __attribute__((unused))
63+
#endif
64+
65+
/*
66+
* Without this, we see warnings from objtool during normal Linux builds when
67+
* the kernel is built with CONFIG_STACK_VALIDATION=y:
68+
*
69+
* warning: objtool: tsd_create() falls through to next function __list_add()
70+
* warning: objtool: .text: unexpected end of section
71+
*
72+
* Until the toolchain stops doing this, we must only define this attribute on
73+
* spl_panic() when doing static analysis.
74+
*/
5975
#if defined(__COVERITY__) || defined(__clang_analyzer__)
6076
__attribute__((__noreturn__))
6177
#endif
@@ -73,8 +89,10 @@ spl_assert(const char *buf, const char *file, const char *func, int line)
7389
#ifndef expect
7490
#define expect(expr, value) (__builtin_expect((expr), (value)))
7591
#endif
92+
#ifndef __linux__
7693
#define likely(expr) expect((expr) != 0, 1)
7794
#define unlikely(expr) expect((expr) != 0, 0)
95+
#endif
7896

7997
#define PANIC(fmt, a...) \
8098
spl_panic(__FILE__, __FUNCTION__, __LINE__, fmt, ## a)
@@ -123,7 +141,7 @@ spl_assert(const char *buf, const char *file, const char *func, int line)
123141
if (unlikely(!(_verify3_left OP _verify3_right))) \
124142
spl_panic(__FILE__, __FUNCTION__, __LINE__, \
125143
"VERIFY3(" #LEFT " " #OP " " #RIGHT ") " \
126-
"failed (%p " #OP " %p)\n", \
144+
"failed (%px " #OP " %px)\n", \
127145
(void *)_verify3_left, \
128146
(void *)_verify3_right); \
129147
} while (0)
@@ -142,10 +160,98 @@ spl_assert(const char *buf, const char *file, const char *func, int line)
142160
if (unlikely(!(0 == _verify0_right))) \
143161
spl_panic(__FILE__, __FUNCTION__, __LINE__, \
144162
"VERIFY0P(" #RIGHT ") " \
145-
"failed (NULL == %p)\n", \
163+
"failed (NULL == %px)\n", \
146164
(void *)_verify0_right); \
147165
} while (0)
148166

167+
/*
168+
* Note that you should not put any operations you want to always happen
169+
* in the print section for ASSERTs unless you only want them to run on
170+
* debug builds!
171+
* e.g. ASSERT3Uf(2, <, 3, "%s", foo(x)), foo(x) won't run on non-debug
172+
* builds.
173+
*/
174+
175+
#define VERIFY3Bf(LEFT, OP, RIGHT, STR, ...) do { \
176+
const boolean_t _verify3_left = (boolean_t)(LEFT); \
177+
const boolean_t _verify3_right = (boolean_t)(RIGHT); \
178+
if (unlikely(!(_verify3_left OP _verify3_right))) \
179+
spl_panic(__FILE__, __FUNCTION__, __LINE__, \
180+
"VERIFY3(" #LEFT " " #OP " " #RIGHT ") " \
181+
"failed (%d " #OP " %d) " STR "\n", \
182+
(boolean_t)(_verify3_left), \
183+
(boolean_t)(_verify3_right), \
184+
__VA_ARGS__); \
185+
} while (0)
186+
187+
#define VERIFY3Sf(LEFT, OP, RIGHT, STR, ...) do { \
188+
const int64_t _verify3_left = (int64_t)(LEFT); \
189+
const int64_t _verify3_right = (int64_t)(RIGHT); \
190+
if (unlikely(!(_verify3_left OP _verify3_right))) \
191+
spl_panic(__FILE__, __FUNCTION__, __LINE__, \
192+
"VERIFY3(" #LEFT " " #OP " " #RIGHT ") " \
193+
"failed (%lld " #OP " %lld) " STR "\n", \
194+
(long long)(_verify3_left), \
195+
(long long)(_verify3_right), \
196+
__VA_ARGS); \
197+
} while (0)
198+
199+
#define VERIFY3Uf(LEFT, OP, RIGHT, STR, ...) do { \
200+
const uint64_t _verify3_left = (uint64_t)(LEFT); \
201+
const uint64_t _verify3_right = (uint64_t)(RIGHT); \
202+
if (unlikely(!(_verify3_left OP _verify3_right))) \
203+
spl_panic(__FILE__, __FUNCTION__, __LINE__, \
204+
"VERIFY3(" #LEFT " " #OP " " #RIGHT ") " \
205+
"failed (%llu " #OP " %llu) " STR "\n", \
206+
(unsigned long long)(_verify3_left), \
207+
(unsigned long long)(_verify3_right), \
208+
__VA_ARGS); \
209+
} while (0)
210+
211+
#define VERIFY3Pf(LEFT, OP, RIGHT, STR, ...) do { \
212+
const uintptr_t _verify3_left = (uintptr_t)(LEFT); \
213+
const uintptr_t _verify3_right = (uintptr_t)(RIGHT); \
214+
if (unlikely(!(_verify3_left OP _verify3_right))) \
215+
spl_panic(__FILE__, __FUNCTION__, __LINE__, \
216+
"VERIFY3(" #LEFT " " #OP " " #RIGHT ") " \
217+
"failed (%px " #OP " %px) " STR "\n", \
218+
(void *) (_verify3_left), \
219+
(void *) (_verify3_right), \
220+
__VA_ARGS__); \
221+
} while (0)
222+
223+
#define VERIFY0Pf(RIGHT, STR, ...) do { \
224+
const uintptr_t _verify3_left = (uintptr_t)(0); \
225+
const uintptr_t _verify3_right = (uintptr_t)(RIGHT); \
226+
if (unlikely(!(_verify3_left == _verify3_right))) \
227+
spl_panic(__FILE__, __FUNCTION__, __LINE__, \
228+
"VERIFY0(0 == " #RIGHT ") " \
229+
"failed (0 == %px) " STR "\n", \
230+
(long long) (_verify3_right), \
231+
__VA_ARGS__); \
232+
} while (0)
233+
234+
#define VERIFY0f(RIGHT, STR, ...) do { \
235+
const int64_t _verify3_left = (int64_t)(0); \
236+
const int64_t _verify3_right = (int64_t)(RIGHT); \
237+
if (unlikely(!(_verify3_left == _verify3_right))) \
238+
spl_panic(__FILE__, __FUNCTION__, __LINE__, \
239+
"VERIFY0(0 == " #RIGHT ") " \
240+
"failed (0 == %lld) " STR "\n", \
241+
(long long) (_verify3_right), \
242+
__VA_ARGS__); \
243+
} while (0)
244+
245+
#define VERIFY_IMPLY(A, B) \
246+
((void)(likely((!(A)) || (B)) || \
247+
spl_assert("(" #A ") implies (" #B ")", \
248+
__FILE__, __FUNCTION__, __LINE__)))
249+
250+
#define VERIFY_EQUIV(A, B) \
251+
((void)(likely(!!(A) == !!(B)) || \
252+
spl_assert("(" #A ") is equivalent to (" #B ")", \
253+
__FILE__, __FUNCTION__, __LINE__)))
254+
149255
/*
150256
* Debugging disabled (--disable-debug)
151257
*/
@@ -162,6 +268,12 @@ spl_assert(const char *buf, const char *file, const char *func, int line)
162268
((void) sizeof ((uintptr_t)(x)), (void) sizeof ((uintptr_t)(z)))
163269
#define ASSERT0(x) ((void) sizeof ((uintptr_t)(x)))
164270
#define ASSERT0P(x) ((void) sizeof ((uintptr_t)(x)))
271+
#define ASSERT3Bf(x, y, z, str, ...) ASSERT3B(x,y,z)
272+
#define ASSERT3Sf(x, y, z, str, ...) ASSERT3S(x,y,z)
273+
#define ASSERT3Uf(x, y, z, str, ...) ASSERT3U(x,y,z)
274+
#define ASSERT3Pf(x, y, z, str, ...) ASSERT3P(x,y,z)
275+
#define ASSERT0Pf(x, str, ...) ASSERT0P(x)
276+
#define ASSERT0f(x, str, ...) ASSERT0(x)
165277
#define IMPLY(A, B) \
166278
((void) sizeof ((uintptr_t)(A)), (void) sizeof ((uintptr_t)(B)))
167279
#define EQUIV(A, B) \
@@ -178,16 +290,15 @@ spl_assert(const char *buf, const char *file, const char *func, int line)
178290
#define ASSERT3P VERIFY3P
179291
#define ASSERT0 VERIFY0
180292
#define ASSERT0P VERIFY0P
293+
#define ASSERT3Bf VERIFY3Bf
294+
#define ASSERT3Sf VERIFY3Sf
295+
#define ASSERT3Uf VERIFY3Uf
296+
#define ASSERT3Pf VERIFY3Pf
297+
#define ASSERT0Pf VERIFY0Pf
298+
#define ASSERT0f VERIFY0f
181299
#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-
300+
#define IMPLY VERIFY_IMPLY
301+
#define EQUIV VERIFY_EQUIV
191302

192303
#endif /* NDEBUG */
193304

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

Lines changed: 122 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,29 @@
11
/*
2-
* Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
3-
* Copyright (C) 2007 The Regents of the University of California.
4-
* Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
5-
* Written by Brian Behlendorf <[email protected]>.
6-
* UCRL-CODE-235197
2+
* Copyright (c) 2020 iXsystems, Inc.
3+
* All rights reserved.
74
*
8-
* This file is part of the SPL, Solaris Porting Layer.
5+
* Redistribution and use in source and binary forms, with or without
6+
* modification, are permitted provided that the following conditions
7+
* are met:
8+
* 1. Redistributions of source code must retain the above copyright
9+
* notice, this list of conditions and the following disclaimer.
10+
* 2. Redistributions in binary form must reproduce the above copyright
11+
* notice, this list of conditions and the following disclaimer in the
12+
* documentation and/or other materials provided with the distribution.
913
*
10-
* The SPL is free software; you can redistribute it and/or modify it
11-
* under the terms of the GNU General Public License as published by the
12-
* Free Software Foundation; either version 2 of the License, or (at your
13-
* option) any later version.
14+
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
15+
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17+
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
18+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20+
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21+
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22+
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23+
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24+
* SUCH DAMAGE.
1425
*
15-
* The SPL is distributed in the hope that it will be useful, but WITHOUT
16-
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17-
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
18-
* for more details.
19-
*
20-
* You should have received a copy of the GNU General Public License along
21-
* with the SPL. If not, see <http://www.gnu.org/licenses/>.
26+
* $FreeBSD$
2227
*/
2328

2429
/*
@@ -47,6 +52,7 @@
4752
#ifndef _SPL_DEBUG_H
4853
#define _SPL_DEBUG_H
4954

55+
5056
/*
5157
* Common DEBUG functionality.
5258
*/
@@ -70,7 +76,7 @@
7076
__attribute__((__noreturn__))
7177
#endif
7278
extern void spl_panic(const char *file, const char *func, int line,
73-
const char *fmt, ...);
79+
const char *fmt, ...) __attribute__((__noreturn__));
7480
extern void spl_dumpstack(void);
7581

7682
static inline int
@@ -80,6 +86,14 @@ spl_assert(const char *buf, const char *file, const char *func, int line)
8086
return (0);
8187
}
8288

89+
#ifndef expect
90+
#define expect(expr, value) (__builtin_expect((expr), (value)))
91+
#endif
92+
#ifndef __linux__
93+
#define likely(expr) expect((expr) != 0, 1)
94+
#define unlikely(expr) expect((expr) != 0, 0)
95+
#endif
96+
8397
#define PANIC(fmt, a...) \
8498
spl_panic(__FILE__, __FUNCTION__, __LINE__, fmt, ## a)
8599

@@ -150,6 +164,84 @@ spl_assert(const char *buf, const char *file, const char *func, int line)
150164
(void *)_verify0_right); \
151165
} while (0)
152166

167+
/*
168+
* Note that you should not put any operations you want to always happen
169+
* in the print section for ASSERTs unless you only want them to run on
170+
* debug builds!
171+
* e.g. ASSERT3Uf(2, <, 3, "%s", foo(x)), foo(x) won't run on non-debug
172+
* builds.
173+
*/
174+
175+
#define VERIFY3Bf(LEFT, OP, RIGHT, STR, ...) do { \
176+
const boolean_t _verify3_left = (boolean_t)(LEFT); \
177+
const boolean_t _verify3_right = (boolean_t)(RIGHT); \
178+
if (unlikely(!(_verify3_left OP _verify3_right))) \
179+
spl_panic(__FILE__, __FUNCTION__, __LINE__, \
180+
"VERIFY3(" #LEFT " " #OP " " #RIGHT ") " \
181+
"failed (%d " #OP " %d) " STR "\n", \
182+
(boolean_t)(_verify3_left), \
183+
(boolean_t)(_verify3_right), \
184+
__VA_ARGS__); \
185+
} while (0)
186+
187+
#define VERIFY3Sf(LEFT, OP, RIGHT, STR, ...) do { \
188+
const int64_t _verify3_left = (int64_t)(LEFT); \
189+
const int64_t _verify3_right = (int64_t)(RIGHT); \
190+
if (unlikely(!(_verify3_left OP _verify3_right))) \
191+
spl_panic(__FILE__, __FUNCTION__, __LINE__, \
192+
"VERIFY3(" #LEFT " " #OP " " #RIGHT ") " \
193+
"failed (%lld " #OP " %lld) " STR "\n", \
194+
(long long)(_verify3_left), \
195+
(long long)(_verify3_right), \
196+
__VA_ARGS); \
197+
} while (0)
198+
199+
#define VERIFY3Uf(LEFT, OP, RIGHT, STR, ...) do { \
200+
const uint64_t _verify3_left = (uint64_t)(LEFT); \
201+
const uint64_t _verify3_right = (uint64_t)(RIGHT); \
202+
if (unlikely(!(_verify3_left OP _verify3_right))) \
203+
spl_panic(__FILE__, __FUNCTION__, __LINE__, \
204+
"VERIFY3(" #LEFT " " #OP " " #RIGHT ") " \
205+
"failed (%llu " #OP " %llu) " STR "\n", \
206+
(unsigned long long)(_verify3_left), \
207+
(unsigned long long)(_verify3_right), \
208+
__VA_ARGS); \
209+
} while (0)
210+
211+
#define VERIFY3Pf(LEFT, OP, RIGHT, STR, ...) do { \
212+
const uintptr_t _verify3_left = (uintptr_t)(LEFT); \
213+
const uintptr_t _verify3_right = (uintptr_t)(RIGHT); \
214+
if (unlikely(!(_verify3_left OP _verify3_right))) \
215+
spl_panic(__FILE__, __FUNCTION__, __LINE__, \
216+
"VERIFY3(" #LEFT " " #OP " " #RIGHT ") " \
217+
"failed (%px " #OP " %px) " STR "\n", \
218+
(void *) (_verify3_left), \
219+
(void *) (_verify3_right), \
220+
__VA_ARGS__); \
221+
} while (0)
222+
223+
#define VERIFY0Pf(RIGHT, STR, ...) do { \
224+
const uintptr_t _verify3_left = (uintptr_t)(0); \
225+
const uintptr_t _verify3_right = (uintptr_t)(RIGHT); \
226+
if (unlikely(!(_verify3_left == _verify3_right))) \
227+
spl_panic(__FILE__, __FUNCTION__, __LINE__, \
228+
"VERIFY0(0 == " #RIGHT ") " \
229+
"failed (0 == %px) " STR "\n", \
230+
(long long) (_verify3_right), \
231+
__VA_ARGS__); \
232+
} while (0)
233+
234+
#define VERIFY0f(RIGHT, STR, ...) do { \
235+
const int64_t _verify3_left = (int64_t)(0); \
236+
const int64_t _verify3_right = (int64_t)(RIGHT); \
237+
if (unlikely(!(_verify3_left == _verify3_right))) \
238+
spl_panic(__FILE__, __FUNCTION__, __LINE__, \
239+
"VERIFY0(0 == " #RIGHT ") " \
240+
"failed (0 == %lld) " STR "\n", \
241+
(long long) (_verify3_right), \
242+
__VA_ARGS__); \
243+
} while (0)
244+
153245
#define VERIFY_IMPLY(A, B) \
154246
((void)(likely((!(A)) || (B)) || \
155247
spl_assert("(" #A ") implies (" #B ")", \
@@ -176,6 +268,12 @@ spl_assert(const char *buf, const char *file, const char *func, int line)
176268
((void) sizeof ((uintptr_t)(x)), (void) sizeof ((uintptr_t)(z)))
177269
#define ASSERT0(x) ((void) sizeof ((uintptr_t)(x)))
178270
#define ASSERT0P(x) ((void) sizeof ((uintptr_t)(x)))
271+
#define ASSERT3Bf(x, y, z, str, ...) ASSERT3B(x,y,z)
272+
#define ASSERT3Sf(x, y, z, str, ...) ASSERT3S(x,y,z)
273+
#define ASSERT3Uf(x, y, z, str, ...) ASSERT3U(x,y,z)
274+
#define ASSERT3Pf(x, y, z, str, ...) ASSERT3P(x,y,z)
275+
#define ASSERT0Pf(x, str, ...) ASSERT0P(x)
276+
#define ASSERT0f(x, str, ...) ASSERT0(x)
179277
#define IMPLY(A, B) \
180278
((void) sizeof ((uintptr_t)(A)), (void) sizeof ((uintptr_t)(B)))
181279
#define EQUIV(A, B) \
@@ -192,6 +290,12 @@ spl_assert(const char *buf, const char *file, const char *func, int line)
192290
#define ASSERT3P VERIFY3P
193291
#define ASSERT0 VERIFY0
194292
#define ASSERT0P VERIFY0P
293+
#define ASSERT3Bf VERIFY3Bf
294+
#define ASSERT3Sf VERIFY3Sf
295+
#define ASSERT3Uf VERIFY3Uf
296+
#define ASSERT3Pf VERIFY3Pf
297+
#define ASSERT0Pf VERIFY0Pf
298+
#define ASSERT0f VERIFY0f
195299
#define ASSERT VERIFY
196300
#define IMPLY VERIFY_IMPLY
197301
#define EQUIV VERIFY_EQUIV

0 commit comments

Comments
 (0)