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(not(testlib))] 12 #[cfg(all(CONFIG_BUG, not(CONFIG_UML), not(CONFIG_LOONGARCH), not(CONFIG_ARM)))] 13 #[cfg(CONFIG_DEBUG_BUGVERBOSE)] 14 macro_rules! warn_flags { 15 ($file:expr, $flags:expr) => { 16 const FLAGS: u32 = $crate::bindings::BUGFLAG_WARNING | $flags; 17 const _FILE: &[u8] = $file.as_bytes(); 18 // Plus one for null-terminator. 19 static FILE: [u8; _FILE.len() + 1] = { 20 let mut bytes = [0; _FILE.len() + 1]; 21 let mut i = 0; 22 while i < _FILE.len() { 23 bytes[i] = _FILE[i]; 24 i += 1; 25 } 26 bytes 27 }; 28 29 // SAFETY: 30 // - `file`, `line`, `flags`, and `size` are all compile-time constants or 31 // symbols, preventing any invalid memory access. 32 // - The asm block has no side effects and does not modify any registers 33 // or memory. It is purely for embedding metadata into the ELF section. 34 unsafe { 35 $crate::asm!( 36 concat!( 37 "/* {size} */", 38 include!(concat!(env!("OBJTREE"), "/rust/kernel/generated_arch_warn_asm.rs")), 39 include!(concat!(env!("OBJTREE"), "/rust/kernel/generated_arch_reachable_asm.rs"))); 40 file = sym FILE, 41 line = const line!(), 42 flags = const FLAGS, 43 size = const ::core::mem::size_of::<$crate::bindings::bug_entry>(), 44 ); 45 } 46 } 47 } 48 49 #[macro_export] 50 #[doc(hidden)] 51 #[cfg(not(testlib))] 52 #[cfg(all(CONFIG_BUG, not(CONFIG_UML), not(CONFIG_LOONGARCH), not(CONFIG_ARM)))] 53 #[cfg(not(CONFIG_DEBUG_BUGVERBOSE))] 54 macro_rules! warn_flags { 55 ($file:expr, $flags:expr) => { 56 const FLAGS: u32 = $crate::bindings::BUGFLAG_WARNING | $flags; 57 58 if false { 59 _ = $file; 60 } 61 62 // SAFETY: 63 // - `flags` and `size` are all compile-time constants, preventing 64 // any invalid memory access. 65 // - The asm block has no side effects and does not modify any registers 66 // or memory. It is purely for embedding metadata into the ELF section. 67 unsafe { 68 $crate::asm!( 69 concat!( 70 "/* {size} */", 71 include!(concat!(env!("OBJTREE"), "/rust/kernel/generated_arch_warn_asm.rs")), 72 include!(concat!(env!("OBJTREE"), "/rust/kernel/generated_arch_reachable_asm.rs"))); 73 flags = const FLAGS, 74 size = const ::core::mem::size_of::<$crate::bindings::bug_entry>(), 75 ); 76 } 77 } 78 } 79 80 #[macro_export] 81 #[doc(hidden)] 82 #[cfg(not(testlib))] 83 #[cfg(all(CONFIG_BUG, CONFIG_UML))] 84 macro_rules! warn_flags { 85 ($file:expr, $flags:expr) => { 86 if false { 87 _ = $file; 88 } 89 90 // SAFETY: It is always safe to call `warn_slowpath_fmt()` 91 // with a valid null-terminated string. 92 unsafe { 93 $crate::bindings::warn_slowpath_fmt( 94 $crate::str::CStrExt::as_char_ptr($crate::c_str!(::core::file!())), 95 line!() as $crate::ffi::c_int, 96 $flags as $crate::ffi::c_uint, 97 ::core::ptr::null(), 98 ); 99 } 100 }; 101 } 102 103 #[macro_export] 104 #[doc(hidden)] 105 #[cfg(not(testlib))] 106 #[cfg(all(CONFIG_BUG, any(CONFIG_LOONGARCH, CONFIG_ARM)))] 107 macro_rules! warn_flags { 108 ($file:expr, $flags:expr) => { 109 if false { 110 _ = $file; 111 _ = $flags; 112 } 113 114 // SAFETY: It is always safe to call `WARN_ON()`. 115 unsafe { $crate::bindings::WARN_ON(true) } 116 }; 117 } 118 119 #[macro_export] 120 #[doc(hidden)] 121 #[cfg(any(testlib, not(CONFIG_BUG)))] 122 macro_rules! warn_flags { 123 ($file:expr, $flags:expr) => { 124 if false { 125 _ = $file; 126 _ = $flags; 127 } 128 }; 129 } 130 131 #[doc(hidden)] 132 pub const fn bugflag_taint(value: u32) -> u32 { 133 value << 8 134 } 135 136 /// Report a warning if `cond` is true and return the condition's evaluation result. 137 #[macro_export] 138 macro_rules! warn_on { 139 ($cond:expr) => {{ 140 let cond = $cond; 141 142 #[cfg(CONFIG_DEBUG_BUGVERBOSE_DETAILED)] 143 const COND_STR: &str = concat!("[", stringify!($cond), "] ", file!()); 144 #[cfg(not(CONFIG_DEBUG_BUGVERBOSE_DETAILED))] 145 const COND_STR: &str = file!(); 146 147 if cond { 148 const WARN_ON_FLAGS: u32 = $crate::bug::bugflag_taint($crate::bindings::TAINT_WARN); 149 150 $crate::warn_flags!(COND_STR, WARN_ON_FLAGS); 151 } 152 cond 153 }}; 154 } 155