Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

rust: std_vendor: add `dbg!` macro based on `std`'s one

The Rust standard library has a really handy macro, `dbg!` [1,2].
It prints the source location (filename and line) along with the raw
source code that is invoked with and the `Debug` representation
of the given expression, e.g.:

let a = 2;
let b = dbg!(a * 2) + 1;
// ^-- prints: [src/main.rs:2] a * 2 = 4
assert_eq!(b, 5);

Port the macro over to the `kernel` crate inside a new module
called `std_vendor`, using `pr_info!` instead of `eprintln!` and
make the rules about committing uses of `dbg!` into version control
more concrete (i.e. tailored for the kernel).

Since the source code for the macro is taken from the standard
library source (with only minor adjustments), the new file is
licensed under `Apache 2.0 OR MIT`, just like the original [3,4].

Link: https://doc.rust-lang.org/std/macro.dbg.html [1]
Link: https://github.com/rust-lang/rust/blob/master/library/std/src/macros.rs#L212 [2]
Link: https://github.com/rust-lang/rust/blob/master/library/std/Cargo.toml [3]
Link: https://github.com/rust-lang/rust/blob/master/COPYRIGHT [4]
Signed-off-by: Niklas Mohrin <dev@niklasmohrin.de>
[Reworded, adapted for upstream and applied latest changes]
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>

authored by

Niklas Mohrin and committed by
Miguel Ojeda
bee16889 ef320549

+166 -1
+2
rust/kernel/lib.rs
··· 26 26 pub mod error; 27 27 pub mod prelude; 28 28 pub mod print; 29 + #[doc(hidden)] 30 + pub mod std_vendor; 29 31 pub mod str; 30 32 31 33 #[doc(hidden)]
+1 -1
rust/kernel/prelude.rs
··· 17 17 18 18 pub use macros::{module, vtable}; 19 19 20 - pub use super::{pr_alert, pr_crit, pr_debug, pr_emerg, pr_err, pr_info, pr_notice, pr_warn}; 20 + pub use super::{dbg, pr_alert, pr_crit, pr_debug, pr_emerg, pr_err, pr_info, pr_notice, pr_warn}; 21 21 22 22 pub use super::error::{code::*, Error, Result}; 23 23
+163
rust/kernel/std_vendor.rs
··· 1 + // SPDX-License-Identifier: Apache-2.0 OR MIT 2 + 3 + //! The contents of this file come from the Rust standard library, hosted in 4 + //! the <https://github.com/rust-lang/rust> repository, licensed under 5 + //! "Apache-2.0 OR MIT" and adapted for kernel use. For copyright details, 6 + //! see <https://github.com/rust-lang/rust/blob/master/COPYRIGHT>. 7 + 8 + /// [`std::dbg`], but using [`pr_info`] instead of [`eprintln`]. 9 + /// 10 + /// Prints and returns the value of a given expression for quick and dirty 11 + /// debugging. 12 + /// 13 + /// An example: 14 + /// 15 + /// ```rust 16 + /// let a = 2; 17 + /// # #[allow(clippy::dbg_macro)] 18 + /// let b = dbg!(a * 2) + 1; 19 + /// // ^-- prints: [src/main.rs:2] a * 2 = 4 20 + /// assert_eq!(b, 5); 21 + /// ``` 22 + /// 23 + /// The macro works by using the `Debug` implementation of the type of 24 + /// the given expression to print the value with [`printk`] along with the 25 + /// source location of the macro invocation as well as the source code 26 + /// of the expression. 27 + /// 28 + /// Invoking the macro on an expression moves and takes ownership of it 29 + /// before returning the evaluated expression unchanged. If the type 30 + /// of the expression does not implement `Copy` and you don't want 31 + /// to give up ownership, you can instead borrow with `dbg!(&expr)` 32 + /// for some expression `expr`. 33 + /// 34 + /// The `dbg!` macro works exactly the same in release builds. 35 + /// This is useful when debugging issues that only occur in release 36 + /// builds or when debugging in release mode is significantly faster. 37 + /// 38 + /// Note that the macro is intended as a temporary debugging tool to be 39 + /// used during development. Therefore, avoid committing `dbg!` macro 40 + /// invocations into the kernel tree. 41 + /// 42 + /// For debug output that is intended to be kept in the kernel tree, 43 + /// use [`pr_debug`] and similar facilities instead. 44 + /// 45 + /// # Stability 46 + /// 47 + /// The exact output printed by this macro should not be relied upon 48 + /// and is subject to future changes. 49 + /// 50 + /// # Further examples 51 + /// 52 + /// With a method call: 53 + /// 54 + /// ```rust 55 + /// # #[allow(clippy::dbg_macro)] 56 + /// fn foo(n: usize) { 57 + /// if dbg!(n.checked_sub(4)).is_some() { 58 + /// // ... 59 + /// } 60 + /// } 61 + /// 62 + /// foo(3) 63 + /// ``` 64 + /// 65 + /// This prints to the kernel log: 66 + /// 67 + /// ```text,ignore 68 + /// [src/main.rs:4] n.checked_sub(4) = None 69 + /// ``` 70 + /// 71 + /// Naive factorial implementation: 72 + /// 73 + /// ```rust 74 + /// # #[allow(clippy::dbg_macro)] 75 + /// # { 76 + /// fn factorial(n: u32) -> u32 { 77 + /// if dbg!(n <= 1) { 78 + /// dbg!(1) 79 + /// } else { 80 + /// dbg!(n * factorial(n - 1)) 81 + /// } 82 + /// } 83 + /// 84 + /// dbg!(factorial(4)); 85 + /// # } 86 + /// ``` 87 + /// 88 + /// This prints to the kernel log: 89 + /// 90 + /// ```text,ignore 91 + /// [src/main.rs:3] n <= 1 = false 92 + /// [src/main.rs:3] n <= 1 = false 93 + /// [src/main.rs:3] n <= 1 = false 94 + /// [src/main.rs:3] n <= 1 = true 95 + /// [src/main.rs:4] 1 = 1 96 + /// [src/main.rs:5] n * factorial(n - 1) = 2 97 + /// [src/main.rs:5] n * factorial(n - 1) = 6 98 + /// [src/main.rs:5] n * factorial(n - 1) = 24 99 + /// [src/main.rs:11] factorial(4) = 24 100 + /// ``` 101 + /// 102 + /// The `dbg!(..)` macro moves the input: 103 + /// 104 + /// ```ignore 105 + /// /// A wrapper around `usize` which importantly is not Copyable. 106 + /// #[derive(Debug)] 107 + /// struct NoCopy(usize); 108 + /// 109 + /// let a = NoCopy(42); 110 + /// let _ = dbg!(a); // <-- `a` is moved here. 111 + /// let _ = dbg!(a); // <-- `a` is moved again; error! 112 + /// ``` 113 + /// 114 + /// You can also use `dbg!()` without a value to just print the 115 + /// file and line whenever it's reached. 116 + /// 117 + /// Finally, if you want to `dbg!(..)` multiple values, it will treat them as 118 + /// a tuple (and return it, too): 119 + /// 120 + /// ``` 121 + /// # #[allow(clippy::dbg_macro)] 122 + /// assert_eq!(dbg!(1usize, 2u32), (1, 2)); 123 + /// ``` 124 + /// 125 + /// However, a single argument with a trailing comma will still not be treated 126 + /// as a tuple, following the convention of ignoring trailing commas in macro 127 + /// invocations. You can use a 1-tuple directly if you need one: 128 + /// 129 + /// ``` 130 + /// # #[allow(clippy::dbg_macro)] 131 + /// # { 132 + /// assert_eq!(1, dbg!(1u32,)); // trailing comma ignored 133 + /// assert_eq!((1,), dbg!((1u32,))); // 1-tuple 134 + /// # } 135 + /// ``` 136 + /// 137 + /// [`std::dbg`]: https://doc.rust-lang.org/std/macro.dbg.html 138 + /// [`eprintln`]: https://doc.rust-lang.org/std/macro.eprintln.html 139 + /// [`printk`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html 140 + #[macro_export] 141 + macro_rules! dbg { 142 + // NOTE: We cannot use `concat!` to make a static string as a format argument 143 + // of `pr_info!` because `file!` could contain a `{` or 144 + // `$val` expression could be a block (`{ .. }`), in which case the `pr_info!` 145 + // will be malformed. 146 + () => { 147 + $crate::pr_info!("[{}:{}]\n", ::core::file!(), ::core::line!()) 148 + }; 149 + ($val:expr $(,)?) => { 150 + // Use of `match` here is intentional because it affects the lifetimes 151 + // of temporaries - https://stackoverflow.com/a/48732525/1063961 152 + match $val { 153 + tmp => { 154 + $crate::pr_info!("[{}:{}] {} = {:#?}\n", 155 + ::core::file!(), ::core::line!(), ::core::stringify!($val), &tmp); 156 + tmp 157 + } 158 + } 159 + }; 160 + ($($val:expr),+ $(,)?) => { 161 + ($($crate::dbg!($val)),+,) 162 + }; 163 + }