Skip to content
This repository was archived by the owner on Nov 8, 2023. It is now read-only.

Commit bee1688

Browse files
niklasmohrinojeda
authored andcommitted
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 <[email protected]> [Reworded, adapted for upstream and applied latest changes] Signed-off-by: Miguel Ojeda <[email protected]>
1 parent ef32054 commit bee1688

File tree

3 files changed

+166
-1
lines changed

3 files changed

+166
-1
lines changed

rust/kernel/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ mod allocator;
2626
pub mod error;
2727
pub mod prelude;
2828
pub mod print;
29+
#[doc(hidden)]
30+
pub mod std_vendor;
2931
pub mod str;
3032

3133
#[doc(hidden)]

rust/kernel/prelude.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ pub use alloc::{boxed::Box, vec::Vec};
1717

1818
pub use macros::{module, vtable};
1919

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};
2121

2222
pub use super::error::{code::*, Error, Result};
2323

rust/kernel/std_vendor.rs

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
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+
}

0 commit comments

Comments
 (0)