bee1688940
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>
164 lines
5.0 KiB
Rust
164 lines
5.0 KiB
Rust
// SPDX-License-Identifier: Apache-2.0 OR MIT
|
|
|
|
//! The contents of this file come from the Rust standard library, hosted in
|
|
//! the <https://github.com/rust-lang/rust> repository, licensed under
|
|
//! "Apache-2.0 OR MIT" and adapted for kernel use. For copyright details,
|
|
//! see <https://github.com/rust-lang/rust/blob/master/COPYRIGHT>.
|
|
|
|
/// [`std::dbg`], but using [`pr_info`] instead of [`eprintln`].
|
|
///
|
|
/// Prints and returns the value of a given expression for quick and dirty
|
|
/// debugging.
|
|
///
|
|
/// An example:
|
|
///
|
|
/// ```rust
|
|
/// let a = 2;
|
|
/// # #[allow(clippy::dbg_macro)]
|
|
/// let b = dbg!(a * 2) + 1;
|
|
/// // ^-- prints: [src/main.rs:2] a * 2 = 4
|
|
/// assert_eq!(b, 5);
|
|
/// ```
|
|
///
|
|
/// The macro works by using the `Debug` implementation of the type of
|
|
/// the given expression to print the value with [`printk`] along with the
|
|
/// source location of the macro invocation as well as the source code
|
|
/// of the expression.
|
|
///
|
|
/// Invoking the macro on an expression moves and takes ownership of it
|
|
/// before returning the evaluated expression unchanged. If the type
|
|
/// of the expression does not implement `Copy` and you don't want
|
|
/// to give up ownership, you can instead borrow with `dbg!(&expr)`
|
|
/// for some expression `expr`.
|
|
///
|
|
/// The `dbg!` macro works exactly the same in release builds.
|
|
/// This is useful when debugging issues that only occur in release
|
|
/// builds or when debugging in release mode is significantly faster.
|
|
///
|
|
/// Note that the macro is intended as a temporary debugging tool to be
|
|
/// used during development. Therefore, avoid committing `dbg!` macro
|
|
/// invocations into the kernel tree.
|
|
///
|
|
/// For debug output that is intended to be kept in the kernel tree,
|
|
/// use [`pr_debug`] and similar facilities instead.
|
|
///
|
|
/// # Stability
|
|
///
|
|
/// The exact output printed by this macro should not be relied upon
|
|
/// and is subject to future changes.
|
|
///
|
|
/// # Further examples
|
|
///
|
|
/// With a method call:
|
|
///
|
|
/// ```rust
|
|
/// # #[allow(clippy::dbg_macro)]
|
|
/// fn foo(n: usize) {
|
|
/// if dbg!(n.checked_sub(4)).is_some() {
|
|
/// // ...
|
|
/// }
|
|
/// }
|
|
///
|
|
/// foo(3)
|
|
/// ```
|
|
///
|
|
/// This prints to the kernel log:
|
|
///
|
|
/// ```text,ignore
|
|
/// [src/main.rs:4] n.checked_sub(4) = None
|
|
/// ```
|
|
///
|
|
/// Naive factorial implementation:
|
|
///
|
|
/// ```rust
|
|
/// # #[allow(clippy::dbg_macro)]
|
|
/// # {
|
|
/// fn factorial(n: u32) -> u32 {
|
|
/// if dbg!(n <= 1) {
|
|
/// dbg!(1)
|
|
/// } else {
|
|
/// dbg!(n * factorial(n - 1))
|
|
/// }
|
|
/// }
|
|
///
|
|
/// dbg!(factorial(4));
|
|
/// # }
|
|
/// ```
|
|
///
|
|
/// This prints to the kernel log:
|
|
///
|
|
/// ```text,ignore
|
|
/// [src/main.rs:3] n <= 1 = false
|
|
/// [src/main.rs:3] n <= 1 = false
|
|
/// [src/main.rs:3] n <= 1 = false
|
|
/// [src/main.rs:3] n <= 1 = true
|
|
/// [src/main.rs:4] 1 = 1
|
|
/// [src/main.rs:5] n * factorial(n - 1) = 2
|
|
/// [src/main.rs:5] n * factorial(n - 1) = 6
|
|
/// [src/main.rs:5] n * factorial(n - 1) = 24
|
|
/// [src/main.rs:11] factorial(4) = 24
|
|
/// ```
|
|
///
|
|
/// The `dbg!(..)` macro moves the input:
|
|
///
|
|
/// ```ignore
|
|
/// /// A wrapper around `usize` which importantly is not Copyable.
|
|
/// #[derive(Debug)]
|
|
/// struct NoCopy(usize);
|
|
///
|
|
/// let a = NoCopy(42);
|
|
/// let _ = dbg!(a); // <-- `a` is moved here.
|
|
/// let _ = dbg!(a); // <-- `a` is moved again; error!
|
|
/// ```
|
|
///
|
|
/// You can also use `dbg!()` without a value to just print the
|
|
/// file and line whenever it's reached.
|
|
///
|
|
/// Finally, if you want to `dbg!(..)` multiple values, it will treat them as
|
|
/// a tuple (and return it, too):
|
|
///
|
|
/// ```
|
|
/// # #[allow(clippy::dbg_macro)]
|
|
/// assert_eq!(dbg!(1usize, 2u32), (1, 2));
|
|
/// ```
|
|
///
|
|
/// However, a single argument with a trailing comma will still not be treated
|
|
/// as a tuple, following the convention of ignoring trailing commas in macro
|
|
/// invocations. You can use a 1-tuple directly if you need one:
|
|
///
|
|
/// ```
|
|
/// # #[allow(clippy::dbg_macro)]
|
|
/// # {
|
|
/// assert_eq!(1, dbg!(1u32,)); // trailing comma ignored
|
|
/// assert_eq!((1,), dbg!((1u32,))); // 1-tuple
|
|
/// # }
|
|
/// ```
|
|
///
|
|
/// [`std::dbg`]: https://doc.rust-lang.org/std/macro.dbg.html
|
|
/// [`eprintln`]: https://doc.rust-lang.org/std/macro.eprintln.html
|
|
/// [`printk`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html
|
|
#[macro_export]
|
|
macro_rules! dbg {
|
|
// NOTE: We cannot use `concat!` to make a static string as a format argument
|
|
// of `pr_info!` because `file!` could contain a `{` or
|
|
// `$val` expression could be a block (`{ .. }`), in which case the `pr_info!`
|
|
// will be malformed.
|
|
() => {
|
|
$crate::pr_info!("[{}:{}]\n", ::core::file!(), ::core::line!())
|
|
};
|
|
($val:expr $(,)?) => {
|
|
// Use of `match` here is intentional because it affects the lifetimes
|
|
// of temporaries - https://stackoverflow.com/a/48732525/1063961
|
|
match $val {
|
|
tmp => {
|
|
$crate::pr_info!("[{}:{}] {} = {:#?}\n",
|
|
::core::file!(), ::core::line!(), ::core::stringify!($val), &tmp);
|
|
tmp
|
|
}
|
|
}
|
|
};
|
|
($($val:expr),+ $(,)?) => {
|
|
($($crate::dbg!($val)),+,)
|
|
};
|
|
}
|