Skip to content

Commit 1a070b6

Browse files
committed
Add custom debug printing for your asserts
I kept hackily expanding macros into if (condition) print custom info. So other people would probably find it useful too. Signed-off-by: Rich Ercolani <[email protected]>
1 parent a0d3fe7 commit 1a070b6

File tree

4 files changed

+351
-31
lines changed

4 files changed

+351
-31
lines changed

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

Lines changed: 130 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,27 @@
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
6278
extern void spl_panic(const char *file, const char *func, int line,
63-
const char *fmt, ...) __attribute__((__noreturn__));
79+
const char *fmt, ...);
6480
extern void spl_dumpstack(void);
6581

6682
static inline int
@@ -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)
@@ -84,6 +102,11 @@ spl_assert(const char *buf, const char *file, const char *func, int line)
84102
spl_assert("VERIFY(" #cond ") failed\n", \
85103
__FILE__, __FUNCTION__, __LINE__))
86104

105+
#define VERIFYF(cond, str, ...) \
106+
(void) (unlikely(!(cond)) && \
107+
spl_panic(__FILE__, __FUNCTION__, __LINE__, \
108+
"VERIFY(" #cond ") failed " str "\n", __VA_ARGS__))
109+
87110
#define VERIFY3B(LEFT, OP, RIGHT) do { \
88111
const boolean_t _verify3_left = (boolean_t)(LEFT); \
89112
const boolean_t _verify3_right = (boolean_t)(RIGHT); \
@@ -123,7 +146,7 @@ spl_assert(const char *buf, const char *file, const char *func, int line)
123146
if (unlikely(!(_verify3_left OP _verify3_right))) \
124147
spl_panic(__FILE__, __FUNCTION__, __LINE__, \
125148
"VERIFY3(" #LEFT " " #OP " " #RIGHT ") " \
126-
"failed (%p " #OP " %p)\n", \
149+
"failed (%px " #OP " %px)\n", \
127150
(void *)_verify3_left, \
128151
(void *)_verify3_right); \
129152
} while (0)
@@ -142,10 +165,98 @@ spl_assert(const char *buf, const char *file, const char *func, int line)
142165
if (unlikely(!(0 == _verify0_right))) \
143166
spl_panic(__FILE__, __FUNCTION__, __LINE__, \
144167
"VERIFY0P(" #RIGHT ") " \
145-
"failed (NULL == %p)\n", \
168+
"failed (NULL == %px)\n", \
146169
(void *)_verify0_right); \
147170
} while (0)
148171

172+
/*
173+
* Note that you should not put any operations you want to always happen
174+
* in the print section for ASSERTs unless you only want them to run on
175+
* debug builds!
176+
* e.g. ASSERT3UF(2, <, 3, "%s", foo(x)), foo(x) won't run on non-debug
177+
* builds.
178+
*/
179+
180+
#define VERIFY3BF(LEFT, OP, RIGHT, STR, ...) do { \
181+
const boolean_t _verify3_left = (boolean_t)(LEFT); \
182+
const boolean_t _verify3_right = (boolean_t)(RIGHT); \
183+
if (unlikely(!(_verify3_left OP _verify3_right))) \
184+
spl_panic(__FILE__, __FUNCTION__, __LINE__, \
185+
"VERIFY3(" #LEFT " " #OP " " #RIGHT ") " \
186+
"failed (%d " #OP " %d) " STR "\n", \
187+
(boolean_t)(_verify3_left), \
188+
(boolean_t)(_verify3_right), \
189+
__VA_ARGS__); \
190+
} while (0)
191+
192+
#define VERIFY3SF(LEFT, OP, RIGHT, STR, ...) do { \
193+
const int64_t _verify3_left = (int64_t)(LEFT); \
194+
const int64_t _verify3_right = (int64_t)(RIGHT); \
195+
if (unlikely(!(_verify3_left OP _verify3_right))) \
196+
spl_panic(__FILE__, __FUNCTION__, __LINE__, \
197+
"VERIFY3(" #LEFT " " #OP " " #RIGHT ") " \
198+
"failed (%lld " #OP " %lld) " STR "\n", \
199+
(long long)(_verify3_left), \
200+
(long long)(_verify3_right), \
201+
__VA_ARGS); \
202+
} while (0)
203+
204+
#define VERIFY3UF(LEFT, OP, RIGHT, STR, ...) do { \
205+
const uint64_t _verify3_left = (uint64_t)(LEFT); \
206+
const uint64_t _verify3_right = (uint64_t)(RIGHT); \
207+
if (unlikely(!(_verify3_left OP _verify3_right))) \
208+
spl_panic(__FILE__, __FUNCTION__, __LINE__, \
209+
"VERIFY3(" #LEFT " " #OP " " #RIGHT ") " \
210+
"failed (%llu " #OP " %llu) " STR "\n", \
211+
(unsigned long long)(_verify3_left), \
212+
(unsigned long long)(_verify3_right), \
213+
__VA_ARGS); \
214+
} while (0)
215+
216+
#define VERIFY3PF(LEFT, OP, RIGHT, STR, ...) do { \
217+
const uintptr_t _verify3_left = (uintptr_t)(LEFT); \
218+
const uintptr_t _verify3_right = (uintptr_t)(RIGHT); \
219+
if (unlikely(!(_verify3_left OP _verify3_right))) \
220+
spl_panic(__FILE__, __FUNCTION__, __LINE__, \
221+
"VERIFY3(" #LEFT " " #OP " " #RIGHT ") " \
222+
"failed (%px " #OP " %px) " STR "\n", \
223+
(void *) (_verify3_left), \
224+
(void *) (_verify3_right), \
225+
__VA_ARGS__); \
226+
} while (0)
227+
228+
#define VERIFY0PF(RIGHT, STR, ...) do { \
229+
const uintptr_t _verify3_left = (uintptr_t)(0); \
230+
const uintptr_t _verify3_right = (uintptr_t)(RIGHT); \
231+
if (unlikely(!(_verify3_left == _verify3_right))) \
232+
spl_panic(__FILE__, __FUNCTION__, __LINE__, \
233+
"VERIFY0(0 == " #RIGHT ") " \
234+
"failed (0 == %px) " STR "\n", \
235+
(long long) (_verify3_right), \
236+
__VA_ARGS__); \
237+
} while (0)
238+
239+
#define VERIFY0F(RIGHT, STR, ...) do { \
240+
const int64_t _verify3_left = (int64_t)(0); \
241+
const int64_t _verify3_right = (int64_t)(RIGHT); \
242+
if (unlikely(!(_verify3_left == _verify3_right))) \
243+
spl_panic(__FILE__, __FUNCTION__, __LINE__, \
244+
"VERIFY0(0 == " #RIGHT ") " \
245+
"failed (0 == %lld) " STR "\n", \
246+
(long long) (_verify3_right), \
247+
__VA_ARGS__); \
248+
} while (0)
249+
250+
#define VERIFY_IMPLY(A, B) \
251+
((void)(likely((!(A)) || (B)) || \
252+
spl_assert("(" #A ") implies (" #B ")", \
253+
__FILE__, __FUNCTION__, __LINE__)))
254+
255+
#define VERIFY_EQUIV(A, B) \
256+
((void)(likely(!!(A) == !!(B)) || \
257+
spl_assert("(" #A ") is equivalent to (" #B ")", \
258+
__FILE__, __FUNCTION__, __LINE__)))
259+
149260
/*
150261
* Debugging disabled (--disable-debug)
151262
*/
@@ -162,6 +273,13 @@ spl_assert(const char *buf, const char *file, const char *func, int line)
162273
((void) sizeof ((uintptr_t)(x)), (void) sizeof ((uintptr_t)(z)))
163274
#define ASSERT0(x) ((void) sizeof ((uintptr_t)(x)))
164275
#define ASSERT0P(x) ((void) sizeof ((uintptr_t)(x)))
276+
#define ASSERT3BF(x, y, z, str, ...) ASSERT3B(x,y,z)
277+
#define ASSERT3SF(x, y, z, str, ...) ASSERT3S(x,y,z)
278+
#define ASSERT3UF(x, y, z, str, ...) ASSERT3U(x,y,z)
279+
#define ASSERT3PF(x, y, z, str, ...) ASSERT3P(x,y,z)
280+
#define ASSERT0PF(x, str, ...) ASSERT0P(x)
281+
#define ASSERT0F(x, str, ...) ASSERT0(x)
282+
#define ASSERTF(x, str, ...) ASSERT(x)
165283
#define IMPLY(A, B) \
166284
((void) sizeof ((uintptr_t)(A)), (void) sizeof ((uintptr_t)(B)))
167285
#define EQUIV(A, B) \
@@ -178,16 +296,16 @@ spl_assert(const char *buf, const char *file, const char *func, int line)
178296
#define ASSERT3P VERIFY3P
179297
#define ASSERT0 VERIFY0
180298
#define ASSERT0P VERIFY0P
299+
#define ASSERT3BF VERIFY3BF
300+
#define ASSERT3SF VERIFY3SF
301+
#define ASSERT3UF VERIFY3UF
302+
#define ASSERT3PF VERIFY3PF
303+
#define ASSERT0PF VERIFY0PF
304+
#define ASSERT0F VERIFY0F
305+
#define ASSERTF VERIFYF
181306
#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-
307+
#define IMPLY VERIFY_IMPLY
308+
#define EQUIV VERIFY_EQUIV
191309

192310
#endif /* NDEBUG */
193311

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

Lines changed: 128 additions & 17 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
*/
@@ -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

@@ -88,6 +102,11 @@ spl_assert(const char *buf, const char *file, const char *func, int line)
88102
spl_assert("VERIFY(" #cond ") failed\n", \
89103
__FILE__, __FUNCTION__, __LINE__))
90104

105+
#define VERIFYF(cond, str, ...) \
106+
(void) (unlikely(!(cond)) && \
107+
spl_panic(__FILE__, __FUNCTION__, __LINE__, \
108+
"VERIFY(" #cond ") failed " str "\n", __VA_ARGS__))
109+
91110
#define VERIFY3B(LEFT, OP, RIGHT) do { \
92111
const boolean_t _verify3_left = (boolean_t)(LEFT); \
93112
const boolean_t _verify3_right = (boolean_t)(RIGHT); \
@@ -150,6 +169,84 @@ spl_assert(const char *buf, const char *file, const char *func, int line)
150169
(void *)_verify0_right); \
151170
} while (0)
152171

172+
/*
173+
* Note that you should not put any operations you want to always happen
174+
* in the print section for ASSERTs unless you only want them to run on
175+
* debug builds!
176+
* e.g. ASSERT3UF(2, <, 3, "%s", foo(x)), foo(x) won't run on non-debug
177+
* builds.
178+
*/
179+
180+
#define VERIFY3BF(LEFT, OP, RIGHT, STR, ...) do { \
181+
const boolean_t _verify3_left = (boolean_t)(LEFT); \
182+
const boolean_t _verify3_right = (boolean_t)(RIGHT); \
183+
if (unlikely(!(_verify3_left OP _verify3_right))) \
184+
spl_panic(__FILE__, __FUNCTION__, __LINE__, \
185+
"VERIFY3(" #LEFT " " #OP " " #RIGHT ") " \
186+
"failed (%d " #OP " %d) " STR "\n", \
187+
(boolean_t)(_verify3_left), \
188+
(boolean_t)(_verify3_right), \
189+
__VA_ARGS__); \
190+
} while (0)
191+
192+
#define VERIFY3SF(LEFT, OP, RIGHT, STR, ...) do { \
193+
const int64_t _verify3_left = (int64_t)(LEFT); \
194+
const int64_t _verify3_right = (int64_t)(RIGHT); \
195+
if (unlikely(!(_verify3_left OP _verify3_right))) \
196+
spl_panic(__FILE__, __FUNCTION__, __LINE__, \
197+
"VERIFY3(" #LEFT " " #OP " " #RIGHT ") " \
198+
"failed (%lld " #OP " %lld) " STR "\n", \
199+
(long long)(_verify3_left), \
200+
(long long)(_verify3_right), \
201+
__VA_ARGS); \
202+
} while (0)
203+
204+
#define VERIFY3UF(LEFT, OP, RIGHT, STR, ...) do { \
205+
const uint64_t _verify3_left = (uint64_t)(LEFT); \
206+
const uint64_t _verify3_right = (uint64_t)(RIGHT); \
207+
if (unlikely(!(_verify3_left OP _verify3_right))) \
208+
spl_panic(__FILE__, __FUNCTION__, __LINE__, \
209+
"VERIFY3(" #LEFT " " #OP " " #RIGHT ") " \
210+
"failed (%llu " #OP " %llu) " STR "\n", \
211+
(unsigned long long)(_verify3_left), \
212+
(unsigned long long)(_verify3_right), \
213+
__VA_ARGS); \
214+
} while (0)
215+
216+
#define VERIFY3PF(LEFT, OP, RIGHT, STR, ...) do { \
217+
const uintptr_t _verify3_left = (uintptr_t)(LEFT); \
218+
const uintptr_t _verify3_right = (uintptr_t)(RIGHT); \
219+
if (unlikely(!(_verify3_left OP _verify3_right))) \
220+
spl_panic(__FILE__, __FUNCTION__, __LINE__, \
221+
"VERIFY3(" #LEFT " " #OP " " #RIGHT ") " \
222+
"failed (%px " #OP " %px) " STR "\n", \
223+
(void *) (_verify3_left), \
224+
(void *) (_verify3_right), \
225+
__VA_ARGS__); \
226+
} while (0)
227+
228+
#define VERIFY0PF(RIGHT, STR, ...) do { \
229+
const uintptr_t _verify3_left = (uintptr_t)(0); \
230+
const uintptr_t _verify3_right = (uintptr_t)(RIGHT); \
231+
if (unlikely(!(_verify3_left == _verify3_right))) \
232+
spl_panic(__FILE__, __FUNCTION__, __LINE__, \
233+
"VERIFY0(0 == " #RIGHT ") " \
234+
"failed (0 == %px) " STR "\n", \
235+
(long long) (_verify3_right), \
236+
__VA_ARGS__); \
237+
} while (0)
238+
239+
#define VERIFY0F(RIGHT, STR, ...) do { \
240+
const int64_t _verify3_left = (int64_t)(0); \
241+
const int64_t _verify3_right = (int64_t)(RIGHT); \
242+
if (unlikely(!(_verify3_left == _verify3_right))) \
243+
spl_panic(__FILE__, __FUNCTION__, __LINE__, \
244+
"VERIFY0(0 == " #RIGHT ") " \
245+
"failed (0 == %lld) " STR "\n", \
246+
(long long) (_verify3_right), \
247+
__VA_ARGS__); \
248+
} while (0)
249+
153250
#define VERIFY_IMPLY(A, B) \
154251
((void)(likely((!(A)) || (B)) || \
155252
spl_assert("(" #A ") implies (" #B ")", \
@@ -176,6 +273,13 @@ spl_assert(const char *buf, const char *file, const char *func, int line)
176273
((void) sizeof ((uintptr_t)(x)), (void) sizeof ((uintptr_t)(z)))
177274
#define ASSERT0(x) ((void) sizeof ((uintptr_t)(x)))
178275
#define ASSERT0P(x) ((void) sizeof ((uintptr_t)(x)))
276+
#define ASSERT3BF(x, y, z, str, ...) ASSERT3B(x,y,z)
277+
#define ASSERT3SF(x, y, z, str, ...) ASSERT3S(x,y,z)
278+
#define ASSERT3UF(x, y, z, str, ...) ASSERT3U(x,y,z)
279+
#define ASSERT3PF(x, y, z, str, ...) ASSERT3P(x,y,z)
280+
#define ASSERT0PF(x, str, ...) ASSERT0P(x)
281+
#define ASSERT0F(x, str, ...) ASSERT0(x)
282+
#define ASSERTF(x, str, ...) ASSERT(x)
179283
#define IMPLY(A, B) \
180284
((void) sizeof ((uintptr_t)(A)), (void) sizeof ((uintptr_t)(B)))
181285
#define EQUIV(A, B) \
@@ -192,6 +296,13 @@ spl_assert(const char *buf, const char *file, const char *func, int line)
192296
#define ASSERT3P VERIFY3P
193297
#define ASSERT0 VERIFY0
194298
#define ASSERT0P VERIFY0P
299+
#define ASSERT3BF VERIFY3BF
300+
#define ASSERT3SF VERIFY3SF
301+
#define ASSERT3UF VERIFY3UF
302+
#define ASSERT3PF VERIFY3PF
303+
#define ASSERT0PF VERIFY0PF
304+
#define ASSERT0F VERIFY0F
305+
#define ASSERTF VERIFYF
195306
#define ASSERT VERIFY
196307
#define IMPLY VERIFY_IMPLY
197308
#define EQUIV VERIFY_EQUIV

0 commit comments

Comments
 (0)