kernel/
bug.rs

1// SPDX-License-Identifier: GPL-2.0
2
3// Copyright (C) 2024, 2025 FUJITA Tomonori <fujita.tomonori@gmail.com>
4
5//! Support for BUG and WARN functionality.
6//!
7//! C header: [`include/asm-generic/bug.h`](srctree/include/asm-generic/bug.h)
8
9#[macro_export]
10#[doc(hidden)]
11#[cfg(all(CONFIG_BUG, not(CONFIG_UML), not(CONFIG_LOONGARCH), not(CONFIG_ARM)))]
12#[cfg(CONFIG_DEBUG_BUGVERBOSE)]
13macro_rules! warn_flags {
14    ($flags:expr) => {
15        const FLAGS: u32 = $crate::bindings::BUGFLAG_WARNING | $flags;
16        const _FILE: &[u8] = file!().as_bytes();
17        // Plus one for null-terminator.
18        static FILE: [u8; _FILE.len() + 1] = {
19            let mut bytes = [0; _FILE.len() + 1];
20            let mut i = 0;
21            while i < _FILE.len() {
22                bytes[i] = _FILE[i];
23                i += 1;
24            }
25            bytes
26        };
27
28        // SAFETY:
29        // - `file`, `line`, `flags`, and `size` are all compile-time constants or
30        // symbols, preventing any invalid memory access.
31        // - The asm block has no side effects and does not modify any registers
32        // or memory. It is purely for embedding metadata into the ELF section.
33        unsafe {
34            $crate::asm!(
35                concat!(
36                    "/* {size} */",
37                    include!(concat!(env!("OBJTREE"), "/rust/kernel/generated_arch_warn_asm.rs")),
38                    include!(concat!(env!("OBJTREE"), "/rust/kernel/generated_arch_reachable_asm.rs")));
39                file = sym FILE,
40                line = const line!(),
41                flags = const FLAGS,
42                size = const ::core::mem::size_of::<$crate::bindings::bug_entry>(),
43            );
44        }
45    }
46}
47
48#[macro_export]
49#[doc(hidden)]
50#[cfg(all(CONFIG_BUG, not(CONFIG_UML), not(CONFIG_LOONGARCH), not(CONFIG_ARM)))]
51#[cfg(not(CONFIG_DEBUG_BUGVERBOSE))]
52macro_rules! warn_flags {
53    ($flags:expr) => {
54        const FLAGS: u32 = $crate::bindings::BUGFLAG_WARNING | $flags;
55
56        // SAFETY:
57        // - `flags` and `size` are all compile-time constants, preventing
58        // any invalid memory access.
59        // - The asm block has no side effects and does not modify any registers
60        // or memory. It is purely for embedding metadata into the ELF section.
61        unsafe {
62            $crate::asm!(
63                concat!(
64                    "/* {size} */",
65                    include!(concat!(env!("OBJTREE"), "/rust/kernel/generated_arch_warn_asm.rs")),
66                    include!(concat!(env!("OBJTREE"), "/rust/kernel/generated_arch_reachable_asm.rs")));
67                flags = const FLAGS,
68                size = const ::core::mem::size_of::<$crate::bindings::bug_entry>(),
69            );
70        }
71    }
72}
73
74#[macro_export]
75#[doc(hidden)]
76#[cfg(all(CONFIG_BUG, CONFIG_UML))]
77macro_rules! warn_flags {
78    ($flags:expr) => {
79        // SAFETY: It is always safe to call `warn_slowpath_fmt()`
80        // with a valid null-terminated string.
81        unsafe {
82            $crate::bindings::warn_slowpath_fmt(
83                $crate::c_str!(::core::file!()).as_char_ptr(),
84                line!() as $crate::ffi::c_int,
85                $flags as $crate::ffi::c_uint,
86                ::core::ptr::null(),
87            );
88        }
89    };
90}
91
92#[macro_export]
93#[doc(hidden)]
94#[cfg(all(CONFIG_BUG, any(CONFIG_LOONGARCH, CONFIG_ARM)))]
95macro_rules! warn_flags {
96    ($flags:expr) => {
97        // SAFETY: It is always safe to call `WARN_ON()`.
98        unsafe { $crate::bindings::WARN_ON(true) }
99    };
100}
101
102#[macro_export]
103#[doc(hidden)]
104#[cfg(not(CONFIG_BUG))]
105macro_rules! warn_flags {
106    ($flags:expr) => {};
107}
108
109#[doc(hidden)]
110pub const fn bugflag_taint(value: u32) -> u32 {
111    value << 8
112}
113
114/// Report a warning if `cond` is true and return the condition's evaluation result.
115#[macro_export]
116macro_rules! warn_on {
117    ($cond:expr) => {{
118        let cond = $cond;
119        if cond {
120            const WARN_ON_FLAGS: u32 = $crate::bug::bugflag_taint($crate::bindings::TAINT_WARN);
121
122            $crate::warn_flags!(WARN_ON_FLAGS);
123        }
124        cond
125    }};
126}