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