1/*-
2 * SPDX-License-Identifier: BSD-3-Clause
3 *
4 * Copyright (c) 1999 Eivind Eklund <eivind@FreeBSD.org>
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the University nor the names of its contributors
15 * may be used to endorse or promote products derived from this software
16 * without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31#ifndef _SYS_KASSERT_H_
32#define _SYS_KASSERT_H_
33
34#include <sys/_types.h>
35#include <sys/cdefs.h>
36
37#ifdef _KERNEL
38extern const char *panicstr; /* panic message */
39#define KERNEL_PANICKED() __predict_false(panicstr != NULL)
40
41/*
42 * Trap accesses going through a pointer.
43 *
44 * Sample usage: you have a struct with numerous fields and by API contract
45 * only some of them get populated, even if the implementation temporary writes
46 * to them. You can use DEBUG_POISON_POINTER so that the consumer which should
47 * no be looking at the field gets caught.
48 *
49 * DEBUG_POISON_POINTER(obj->ptr);
50 * ....
51 * if (obj->ptr->field) // traps
52 */
53#ifdef INVARIANTS
54
55extern void *poisoned_buf;
56#define DEBUG_POISON_POINTER_VALUE poisoned_buf
57
58#define DEBUG_POISON_POINTER(x) ({ \
59 x = (DEBUG_POISON_POINTER_VALUE); \
60})
61
62#else
63#define DEBUG_POISON_POINTER(x)
64#endif
65
66#ifdef INVARIANTS /* The option is always available */
67#define VNASSERT(exp, vp, msg) do { \
68 if (__predict_false(!(exp))) { \
69 vn_printf(vp, "VNASSERT failed: %s not true at %s:%d (%s)\n",\
70 #exp, __FILE__, __LINE__, __func__); \
71 kassert_panic msg; \
72 } \
73} while (0)
74#define MPASSERT(exp, mp, msg) do { \
75 if (__predict_false(!(exp))) { \
76 printf("MPASSERT mp %p failed: %s not true at %s:%d (%s)\n",\
77 (mp), #exp, __FILE__, __LINE__, __func__); \
78 kassert_panic msg; \
79 } \
80} while (0)
81#define VNPASS(exp, vp) do { \
82 const char *_exp = #exp; \
83 VNASSERT(exp, vp, ("condition %s not met at %s:%d (%s)", \
84 _exp, __FILE__, __LINE__, __func__)); \
85} while (0)
86#define MPPASS(exp, mp) do { \
87 const char *_exp = #exp; \
88 MPASSERT(exp, mp, ("condition %s not met at %s:%d (%s)", \
89 _exp, __FILE__, __LINE__, __func__)); \
90} while (0)
91#define __assert_unreachable() \
92 panic("executing segment marked as unreachable at %s:%d (%s)\n", \
93 __FILE__, __LINE__, __func__)
94#else /* INVARIANTS */
95#define VNASSERT(exp, vp, msg) do { \
96} while (0)
97#define MPASSERT(exp, mp, msg) do { \
98} while (0)
99#define VNPASS(exp, vp) do { \
100} while (0)
101#define MPPASS(exp, mp) do { \
102} while (0)
103#define __assert_unreachable() __unreachable()
104#endif /* INVARIANTS */
105
106#ifndef CTASSERT /* Allow lint to override */
107#define CTASSERT(x) _Static_assert(x, "compile-time assertion failed")
108#endif
109
110/*
111 * These functions need to be declared before the KASSERT macro is invoked in
112 * !KASSERT_PANIC_OPTIONAL builds, so their declarations are sort of out of
113 * place compared to other function definitions in this header. On the other
114 * hand, this header is a bit disorganized anyway.
115 */
116void panic(const char *, ...) __dead2 __printflike(1, 2);
117void vpanic(const char *, __va_list) __dead2 __printflike(1, 0);
118#endif /* _KERNEL */
119
120#if defined(_STANDALONE)
121/*
122 * Until we have more experience with KASSERTS that are called
123 * from the boot loader, they are off. The bootloader does this
124 * a little differently than the kernel (we just call printf atm).
125 * we avoid most of the common functions in the boot loader, so
126 * declare printf() here too.
127 */
128int printf(const char *, ...) __printflike(1, 2);
129# define kassert_panic printf
130#else /* !_STANDALONE */
131# if defined(WITNESS) || defined(INVARIANT_SUPPORT)
132# ifdef KASSERT_PANIC_OPTIONAL
133void kassert_panic(const char *fmt, ...) __printflike(1, 2);
134# else
135# define kassert_panic panic
136# endif /* KASSERT_PANIC_OPTIONAL */
137# endif /* defined(WITNESS) || defined(INVARIANT_SUPPORT) */
138#endif /* _STANDALONE */
139
140/*
141 * Kernel assertion; see KASSERT(9) for details.
142 */
143#if (defined(_KERNEL) && defined(INVARIANTS)) || defined(_STANDALONE)
144#define KASSERT(exp,msg) do { \
145 if (__predict_false(!(exp))) \
146 kassert_panic msg; \
147} while (0)
148#else /* !(KERNEL && INVARIANTS) && !_STANDALONE */
149#define KASSERT(exp,msg) do { \
150} while (0)
151#endif /* (_KERNEL && INVARIANTS) || _STANDALONE */
152
153#ifdef _KERNEL
154/*
155 * Macros for generating panic messages based on the exact condition text.
156 *
157 * NOTE: Use these with care, as the resulting message might omit key
158 * information required to understand the assertion failure. Consult the
159 * MPASS(9) man page for guidance.
160 */
161#define MPASS(ex) MPASS4(ex, #ex, __FILE__, __LINE__)
162#define MPASS2(ex, what) MPASS4(ex, what, __FILE__, __LINE__)
163#define MPASS3(ex, file, line) MPASS4(ex, #ex, file, line)
164#define MPASS4(ex, what, file, line) \
165 KASSERT((ex), ("Assertion %s failed at %s:%d", what, file, line))
166
167/*
168 * Assert that a pointer can be loaded from memory atomically.
169 *
170 * This assertion enforces stronger alignment than necessary. For example,
171 * on some architectures, atomicity for unaligned loads will depend on
172 * whether or not the load spans multiple cache lines.
173 */
174#define ASSERT_ATOMIC_LOAD_PTR(var, msg) \
175 KASSERT(sizeof(var) == sizeof(void *) && \
176 ((uintptr_t)&(var) & (sizeof(void *) - 1)) == 0, msg)
177/*
178 * Assert that a thread is in critical(9) section.
179 */
180#define CRITICAL_ASSERT(td) \
181 KASSERT((td)->td_critnest >= 1, ("Not in critical section"))
182
183#endif /* _KERNEL */
184
185#endif /* _SYS_KASSERT_H_ */