From 61fba15345dc006478d04190fe7c269c152943cf Mon Sep 17 00:00:00 2001 From: "Alan Ngo (from Dev Box)" Date: Tue, 10 Feb 2026 13:27:23 -0800 Subject: [PATCH 1/2] feat: add dbg! macro to wdk --- crates/wdk/src/dbg.rs | 63 +++++++++++++++++++++++++++++++++++++++++++ crates/wdk/src/lib.rs | 9 +++++++ 2 files changed, 72 insertions(+) create mode 100644 crates/wdk/src/dbg.rs diff --git a/crates/wdk/src/dbg.rs b/crates/wdk/src/dbg.rs new file mode 100644 index 000000000..c5cf02789 --- /dev/null +++ b/crates/wdk/src/dbg.rs @@ -0,0 +1,63 @@ +// Copyright (c) Microsoft Corporation +// License: MIT OR Apache-2.0 + +/// Prints and returns the value of a given expression for quick and dirty +/// debugging. +/// This is the no_std equivalent of the std library's dbg! macro. +/// Instead of writing to stderr it routes output through the debugger using +/// the println! macro in wdk. +#[cfg_attr( + any(driver_model__driver_type = "WDM", driver_model__driver_type = "KMDF"), + doc = r" +The output is routed to the debugger via [`wdk_sys::ntddk::DbgPrint`], so the `IRQL` +requirements of that function apply. In particular, this should only be called at +`IRQL` <= `DIRQL`, and calling it at `IRQL` > `DIRQL` can cause deadlocks due to +the debugger's use of IPIs (Inter-Process Interrupts). + +[`wdk_sys::ntddk::DbgPrint`]'s 512 byte limit does not apply to this macro, as it will +automatically buffer and chunk the output if it exceeds that limit. +" +)] +#[cfg_attr( + driver_model__driver_type = "UMDF", + doc = r" +The output is routed to the debugger via [`wdk_sys::windows::OutputDebugStringA`]. + +If there is no debugger attached to WUDFHost of the driver (i.e., user-mode debugging), +the output will be routed to the system debugger (i.e., kernel-mode debugging). +" +)] +#[macro_export] +macro_rules! dbg { + // NOTE: We cannot use `concat!` to make a static string as a format argument + // of `println!` because `file!` could contain a `{` or + // `$val` expression could be a block (`{ .. }`), in which case the `println!` + // will be malformed. + // TODO: Consider replacing `println!` with a no_std implementation of `eprintln!` + // to target different debug message levels. + () => { + $crate::println!("[{}:{}:{}]", core::file!(), core::line!(), core::column!()) + }; + ($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::println!( + "[{}:{}:{}] {} = {:#?}", + core::file!(), + core::line!(), + core::column!(), + core::stringify!($val), + // The `&T: Debug` check happens here (not in the format literal desugaring) + // to avoid format literal related messages and suggestions. + &&tmp as &dyn core::fmt::Debug, + ); + tmp + } + } + }; + ($($val:expr),+ $(,)?) => { + ($($crate::dbg!($val)),+,) + }; +} diff --git a/crates/wdk/src/lib.rs b/crates/wdk/src/lib.rs index 652968996..1961808d9 100644 --- a/crates/wdk/src/lib.rs +++ b/crates/wdk/src/lib.rs @@ -36,6 +36,15 @@ pub use wdk_sys::PAGED_CODE as paged_code; ))] mod print; +#[cfg(any( + all( + feature = "alloc", + any(driver_model__driver_type = "WDM", driver_model__driver_type = "KMDF") + ), + driver_model__driver_type = "UMDF", +))] +mod dbg; + #[cfg(any(driver_model__driver_type = "KMDF", driver_model__driver_type = "UMDF"))] pub mod wdf; From 8aefb3dd13e0fd3c2c05585deed6dceecb325821 Mon Sep 17 00:00:00 2001 From: "Alan Ngo (from Dev Box)" Date: Wed, 11 Feb 2026 10:11:13 -0800 Subject: [PATCH 2/2] refactor: move dbg! into print.rs --- crates/wdk/src/dbg.rs | 63 ----------------------------------------- crates/wdk/src/lib.rs | 9 ------ crates/wdk/src/print.rs | 61 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 61 insertions(+), 72 deletions(-) delete mode 100644 crates/wdk/src/dbg.rs diff --git a/crates/wdk/src/dbg.rs b/crates/wdk/src/dbg.rs deleted file mode 100644 index c5cf02789..000000000 --- a/crates/wdk/src/dbg.rs +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (c) Microsoft Corporation -// License: MIT OR Apache-2.0 - -/// Prints and returns the value of a given expression for quick and dirty -/// debugging. -/// This is the no_std equivalent of the std library's dbg! macro. -/// Instead of writing to stderr it routes output through the debugger using -/// the println! macro in wdk. -#[cfg_attr( - any(driver_model__driver_type = "WDM", driver_model__driver_type = "KMDF"), - doc = r" -The output is routed to the debugger via [`wdk_sys::ntddk::DbgPrint`], so the `IRQL` -requirements of that function apply. In particular, this should only be called at -`IRQL` <= `DIRQL`, and calling it at `IRQL` > `DIRQL` can cause deadlocks due to -the debugger's use of IPIs (Inter-Process Interrupts). - -[`wdk_sys::ntddk::DbgPrint`]'s 512 byte limit does not apply to this macro, as it will -automatically buffer and chunk the output if it exceeds that limit. -" -)] -#[cfg_attr( - driver_model__driver_type = "UMDF", - doc = r" -The output is routed to the debugger via [`wdk_sys::windows::OutputDebugStringA`]. - -If there is no debugger attached to WUDFHost of the driver (i.e., user-mode debugging), -the output will be routed to the system debugger (i.e., kernel-mode debugging). -" -)] -#[macro_export] -macro_rules! dbg { - // NOTE: We cannot use `concat!` to make a static string as a format argument - // of `println!` because `file!` could contain a `{` or - // `$val` expression could be a block (`{ .. }`), in which case the `println!` - // will be malformed. - // TODO: Consider replacing `println!` with a no_std implementation of `eprintln!` - // to target different debug message levels. - () => { - $crate::println!("[{}:{}:{}]", core::file!(), core::line!(), core::column!()) - }; - ($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::println!( - "[{}:{}:{}] {} = {:#?}", - core::file!(), - core::line!(), - core::column!(), - core::stringify!($val), - // The `&T: Debug` check happens here (not in the format literal desugaring) - // to avoid format literal related messages and suggestions. - &&tmp as &dyn core::fmt::Debug, - ); - tmp - } - } - }; - ($($val:expr),+ $(,)?) => { - ($($crate::dbg!($val)),+,) - }; -} diff --git a/crates/wdk/src/lib.rs b/crates/wdk/src/lib.rs index 1961808d9..652968996 100644 --- a/crates/wdk/src/lib.rs +++ b/crates/wdk/src/lib.rs @@ -36,15 +36,6 @@ pub use wdk_sys::PAGED_CODE as paged_code; ))] mod print; -#[cfg(any( - all( - feature = "alloc", - any(driver_model__driver_type = "WDM", driver_model__driver_type = "KMDF") - ), - driver_model__driver_type = "UMDF", -))] -mod dbg; - #[cfg(any(driver_model__driver_type = "KMDF", driver_model__driver_type = "UMDF"))] pub mod wdf; diff --git a/crates/wdk/src/print.rs b/crates/wdk/src/print.rs index 5a0d1848f..4dd4540c1 100644 --- a/crates/wdk/src/print.rs +++ b/crates/wdk/src/print.rs @@ -77,6 +77,67 @@ macro_rules! println { }; } +/// Prints and returns the value of a given expression for quick and dirty +/// debugging. +/// This is the no_std equivalent of the std library's dbg! macro. +/// Instead of writing to stderr it routes output through the debugger using +/// the println! macro in wdk. +#[cfg_attr( + any(driver_model__driver_type = "WDM", driver_model__driver_type = "KMDF"), + doc = r" +The output is routed to the debugger via [`wdk_sys::ntddk::DbgPrint`], so the `IRQL` +requirements of that function apply. In particular, this should only be called at +`IRQL` <= `DIRQL`, and calling it at `IRQL` > `DIRQL` can cause deadlocks due to +the debugger's use of IPIs (Inter-Process Interrupts). + +[`wdk_sys::ntddk::DbgPrint`]'s 512 byte limit does not apply to this macro, as it will +automatically buffer and chunk the output if it exceeds that limit. +" +)] +#[cfg_attr( + driver_model__driver_type = "UMDF", + doc = r" +The output is routed to the debugger via [`wdk_sys::windows::OutputDebugStringA`]. + +If there is no debugger attached to WUDFHost of the driver (i.e., user-mode debugging), +the output will be routed to the system debugger (i.e., kernel-mode debugging). +" +)] +#[macro_export] +macro_rules! dbg { + // NOTE: We cannot use `concat!` to make a static string as a format argument + // of `println!` because `file!` could contain a `{` or + // `$val` expression could be a block (`{ .. }`), in which case the `println!` + // will be malformed. + // TODO: Consider replacing `println!` with a no_std implementation of `eprintln!` + // to target different debug message levels. + () => { + $crate::println!("[{}:{}:{}]", core::file!(), core::line!(), core::column!()) + }; + ($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::println!( + "[{}:{}:{}] {} = {:#?}", + core::file!(), + core::line!(), + core::column!(), + core::stringify!($val), + // The `&T: Debug` check happens here (not in the format literal desugaring) + // to avoid format literal related messages and suggestions. + &&tmp as &dyn core::fmt::Debug, + ); + tmp + } + } + }; + ($($val:expr),+ $(,)?) => { + ($($crate::dbg!($val)),+,) + }; +} + /// Internal implementation of print macros. This function is an implementation /// detail and should never be called directly, but must be public to be useable /// by the print! and println! macro