xref: /linux/rust/kernel/bug.rs (revision 352af6a011d586ff042db4b2d1f7421875eb8a14)
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)]
13 macro_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))]
52 macro_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))]
77 macro_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)))]
95 macro_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))]
105 macro_rules! warn_flags {
106     ($flags:expr) => {};
107 }
108 
109 #[doc(hidden)]
bugflag_taint(value: u32) -> u32110 pub 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]
116 macro_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 }
127