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)] 110 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