* [PATCH v3 0/5] Rust dynamic debug support for pr_debug! and dev_dbg!
@ 2026-10-01 14:59 Zhi Wang
2026-10-01 14:59 ` [PATCH v3 1/5] gpu: nova-core: validate firmware versions before debug logging Zhi Wang
` (4 more replies)
0 siblings, 5 replies; 6+ messages in thread
From: Zhi Wang @ 2026-10-01 14:59 UTC (permalink / raw)
To: rust-for-linux, linux-kernel
Cc: andrewjballance, daniel.almeida, dakr, aliceryhl, ojeda, boqun,
gary, bjorn3_gh, lossin, a.hindborg, tmgross, cjia, smitra,
ankita, aniketa, kwankhede, targupta, kjaju, alkumar, acourbot,
jhubbard, zhiwang, Zhi Wang
Add runtime dynamic debug control to Rust pr_debug! and dev_dbg!, using
the existing C control file, boot/module parameters, prefixes and jump
labels. Callsite flags and static keys always start disabled. Users enable
messages with dyndbg queries; Rust debug assertions do not affect whether
a debug message is printed.
This continues Andrew Ballance's RFC v2:
https://lore.kernel.org/rust-for-linux/20250620210533.400889-1-andrewjballance@gmail.com/
This revision retains RFC v2's nested-field static-branch macros and
static mut descriptors addressed through raw pointers.
Changes since RFC v2:
- Make debug logging independent of Rust's debug_assertions setting.
Both pr_debug! and dev_dbg! start disabled and are enabled through
dyndbg; without dynamic debug support, both remain disabled.
- Keep caller expressions outside unsafe blocks and avoid implicit Rust
references when reading descriptor flags without jump labels.
- Correct big-endian bitfield layout and keep module descriptors writable
with #[used(compiler)]. This fixes the kernel write fault when
static_key_enable_cpuslocked() tries to write the static key.
- Use Kbuild module names and actual format strings for filtering, preserve
the crate log prefix, and support +d stack output.
- Complete DYNAMIC_DEBUG_CORE-only support with per-crate opt-in.
- Port to driver-core-testing and preserve Nova's firmware validation when
debug logging is disabled.
Limitations:
- Function metadata deliberately remains <unknown>;
Andrew Ballance (3):
rust: jump label: add support for nested arguments
rust: print: add dynamic debug support to pr_debug!
rust: device: add dynamic debug support to dev_dbg!
Zhi Wang (2):
gpu: nova-core: validate firmware versions before debug logging
dynamic_debug: expose printing declarations with the core enabled
.../admin-guide/dynamic-debug-howto.rst | 41 ++++
MAINTAINERS | 2 +
drivers/gpu/nova-core/firmware/booter.rs | 8 +-
drivers/gpu/nova-core/firmware/fsp.rs | 3 +-
.../nova-core/firmware/fwsec/bootloader.rs | 7 +-
drivers/gpu/nova-core/firmware/gsp.rs | 3 +-
drivers/gpu/nova-core/firmware/riscv.rs | 7 +-
include/linux/dynamic_debug.h | 16 +-
rust/Makefile | 3 +
rust/bindings/bindings_helper.h | 1 +
rust/helpers/dynamic_debug.c | 33 +++
rust/helpers/helpers.c | 1 +
rust/kernel/device.rs | 42 +++-
rust/kernel/jump_label.rs | 17 +-
rust/kernel/print.rs | 53 ++++-
rust/kernel/print/dynamic_debug.rs | 192 ++++++++++++++++++
scripts/Makefile.build | 1 +
scripts/generate_rust_analyzer.py | 1 +
18 files changed, 386 insertions(+), 45 deletions(-)
create mode 100644 rust/helpers/dynamic_debug.c
create mode 100644 rust/kernel/print/dynamic_debug.rs
base-commit: f1850e443b0e4f2429ddf42a8d5033ea54ae8a90
--
2.53.0
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v3 1/5] gpu: nova-core: validate firmware versions before debug logging
2026-10-01 14:59 [PATCH v3 0/5] Rust dynamic debug support for pr_debug! and dev_dbg! Zhi Wang
@ 2026-10-01 14:59 ` Zhi Wang
2026-10-01 14:59 ` [PATCH v3 2/5] rust: jump label: add support for nested arguments Zhi Wang
` (3 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Zhi Wang @ 2026-10-01 14:59 UTC (permalink / raw)
To: rust-for-linux, linux-kernel
Cc: andrewjballance, daniel.almeida, dakr, aliceryhl, ojeda, boqun,
gary, bjorn3_gh, lossin, a.hindborg, tmgross, cjia, smitra,
ankita, aniketa, kwankhede, targupta, kjaju, alkumar, acourbot,
jhubbard, zhiwang, Zhi Wang
Firmware loaders currently use tlv.get_string(b"VERS")? inside dev_dbg!
arguments. The string conversion rejects non-printable ASCII, and its
error currently propagates even with debug assertions disabled.
Move those conversions before the logging calls so that making dev_dbg!
arguments conditional does not change firmware validation. Keep the
message text and the order of the remaining initialization unchanged.
Signed-off-by: Zhi Wang <zhiw@nvidia.com>
---
drivers/gpu/nova-core/firmware/booter.rs | 8 ++------
drivers/gpu/nova-core/firmware/fsp.rs | 3 ++-
drivers/gpu/nova-core/firmware/fwsec/bootloader.rs | 7 ++-----
drivers/gpu/nova-core/firmware/gsp.rs | 3 ++-
drivers/gpu/nova-core/firmware/riscv.rs | 7 ++-----
5 files changed, 10 insertions(+), 18 deletions(-)
diff --git a/drivers/gpu/nova-core/firmware/booter.rs b/drivers/gpu/nova-core/firmware/booter.rs
index aa4458bb3312..6b5384e75c5c 100644
--- a/drivers/gpu/nova-core/firmware/booter.rs
+++ b/drivers/gpu/nova-core/firmware/booter.rs
@@ -93,12 +93,8 @@ pub(crate) fn new(
};
let fw = request_tlv(dev, chipset, fw_name)?;
let tlv = Tlv::new(fw.data())?;
- dev_dbg!(
- dev,
- "loaded {} firmware v{}\n",
- fw_name,
- tlv.get_string(b"VERS")?
- );
+ let version = tlv.get_string(b"VERS")?;
+ dev_dbg!(dev, "loaded {} firmware v{}\n", fw_name, version);
let os_data_offset = tlv.get_u32(b"DAOF")?;
let os_data_size = tlv.get_u32(b"DASZ")?;
diff --git a/drivers/gpu/nova-core/firmware/fsp.rs b/drivers/gpu/nova-core/firmware/fsp.rs
index d47b1d2a1030..308ce7889ced 100644
--- a/drivers/gpu/nova-core/firmware/fsp.rs
+++ b/drivers/gpu/nova-core/firmware/fsp.rs
@@ -50,7 +50,8 @@ impl<'a> FspFirmware<'a> {
pub(crate) fn new(dev: &'a device::Device<device::Bound>, chipset: Chipset) -> Result<Self> {
let fw = request_tlv(dev, chipset, "fmc")?;
let tlv = Tlv::new(fw.data())?;
- dev_dbg!(dev, "loaded fsp firmware v{}\n", tlv.get_string(b"VERS")?);
+ let version = tlv.get_string(b"VERS")?;
+ dev_dbg!(dev, "loaded fsp firmware v{}\n", version);
let fmc_image_data = tlv.get_bytes(b"BLOB")?;
let fmc_image = Coherent::from_slice(dev, fmc_image_data, GFP_KERNEL)?;
diff --git a/drivers/gpu/nova-core/firmware/fwsec/bootloader.rs b/drivers/gpu/nova-core/firmware/fwsec/bootloader.rs
index a87878fe2aec..406995a24e7b 100644
--- a/drivers/gpu/nova-core/firmware/fwsec/bootloader.rs
+++ b/drivers/gpu/nova-core/firmware/fwsec/bootloader.rs
@@ -125,11 +125,8 @@ pub(crate) fn new(
) -> Result<Self> {
let fw = request_tlv(dev, chipset, "gen_bootloader")?;
let tlv = Tlv::new(fw.data())?;
- dev_dbg!(
- dev,
- "loaded generic bootloader firmware v{}\n",
- tlv.get_string(b"VERS")?
- );
+ let version = tlv.get_string(b"VERS")?;
+ dev_dbg!(dev, "loaded generic bootloader firmware v{}\n", version);
let ucode = {
let blob = tlv.get_bytes(b"BLOB")?;
diff --git a/drivers/gpu/nova-core/firmware/gsp.rs b/drivers/gpu/nova-core/firmware/gsp.rs
index 22d1f9329c9f..ac741a97e759 100644
--- a/drivers/gpu/nova-core/firmware/gsp.rs
+++ b/drivers/gpu/nova-core/firmware/gsp.rs
@@ -74,7 +74,8 @@ pub(crate) fn new(
pin_init::pin_init_scope(move || {
let firmware = request_tlv(dev, chipset, "gsp")?;
let tlv = Tlv::new(firmware.data())?;
- dev_dbg!(dev, "loaded gsp firmware v{}\n", tlv.get_string(b"VERS")?);
+ let version = tlv.get_string(b"VERS")?;
+ dev_dbg!(dev, "loaded gsp firmware v{}\n", version);
let size = usize::from_safe_cast(tlv.get_u32(b"SIZE")?);
let mut fw_vvec = VVec::zeroed(size, GFP_KERNEL).map_err(|_| ENOMEM)?;
diff --git a/drivers/gpu/nova-core/firmware/riscv.rs b/drivers/gpu/nova-core/firmware/riscv.rs
index f05cfb1c65da..918908ebcac8 100644
--- a/drivers/gpu/nova-core/firmware/riscv.rs
+++ b/drivers/gpu/nova-core/firmware/riscv.rs
@@ -30,11 +30,8 @@ impl<'a> RiscvFirmware<'a> {
/// Parses the RISC-V firmware image contained in `fw`.
pub(crate) fn new(dev: &'a device::Device<device::Bound>, fw: &Firmware) -> Result<Self> {
let tlv = Tlv::new(fw.data())?;
- dev_dbg!(
- dev,
- "loaded gsp bootloader firmware v{}\n",
- tlv.get_string(b"VERS")?
- );
+ let version = tlv.get_string(b"VERS")?;
+ dev_dbg!(dev, "loaded gsp bootloader firmware v{}\n", version);
let code_offset = tlv.get_u32(b"CDOF")?;
let data_offset = tlv.get_u32(b"DAOF")?;
--
2.53.0
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v3 2/5] rust: jump label: add support for nested arguments
2026-10-01 14:59 [PATCH v3 0/5] Rust dynamic debug support for pr_debug! and dev_dbg! Zhi Wang
2026-10-01 14:59 ` [PATCH v3 1/5] gpu: nova-core: validate firmware versions before debug logging Zhi Wang
@ 2026-10-01 14:59 ` Zhi Wang
2026-10-01 14:59 ` [PATCH v3 3/5] dynamic_debug: expose printing declarations with the core enabled Zhi Wang
` (2 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Zhi Wang @ 2026-10-01 14:59 UTC (permalink / raw)
To: rust-for-linux, linux-kernel
Cc: andrewjballance, daniel.almeida, dakr, aliceryhl, ojeda, boqun,
gary, bjorn3_gh, lossin, a.hindborg, tmgross, cjia, smitra,
ankita, aniketa, kwankhede, targupta, kjaju, alkumar, acourbot,
jhubbard, zhiwang, Zhi Wang
From: Andrew Ballance <andrewjballance@gmail.com>
allows for nested arguments to be used with the static_branch macro.
e.g. `outer.inner.key` can now be accessed by the macro
Link: https://lore.kernel.org/rust-for-linux/20250620210533.400889-2-andrewjballance@gmail.com/
Signed-off-by: Andrew Ballance <andrewjballance@gmail.com>
[Zhi: Rebase; extend the host-test stub in the same way and document
the initialized-key and storage requirements for Rust-defined callsites.]
Signed-off-by: Zhi Wang <zhiw@nvidia.com>
---
rust/kernel/jump_label.rs | 17 ++++++++++-------
1 file changed, 10 insertions(+), 7 deletions(-)
diff --git a/rust/kernel/jump_label.rs b/rust/kernel/jump_label.rs
index f54cedcb6fd5..9bda169e82cd 100644
--- a/rust/kernel/jump_label.rs
+++ b/rust/kernel/jump_label.rs
@@ -16,12 +16,15 @@
///
/// # Safety
///
-/// The macro must be used with a real static key defined by C.
+/// The static variable must contain an initialized `static_key_false` at the specified field.
+/// Its storage must remain valid while the key is registered with the jump label code. Updates
+/// to the key must use the C static-key APIs.
#[macro_export]
macro_rules! static_branch_unlikely {
- ($key:path, $keytyp:ty, $field:ident) => {{
+ ($key:path, $keytyp:ty, $($field:ident).+) => {{
let _key: *const $keytyp = ::core::ptr::addr_of!($key);
- let _key: *const $crate::bindings::static_key_false = ::core::ptr::addr_of!((*_key).$field);
+ let _key: *const $crate::bindings::static_key_false =
+ ::core::ptr::addr_of!((*_key)$(.$field)+);
let _key: *const $crate::bindings::static_key = _key.cast();
#[cfg(not(CONFIG_JUMP_LABEL))]
@@ -30,7 +33,7 @@ macro_rules! static_branch_unlikely {
}
#[cfg(CONFIG_JUMP_LABEL)]
- $crate::jump_label::arch_static_branch! { $key, $keytyp, $field, false }
+ $crate::jump_label::arch_static_branch! { $key, $keytyp, $($field).+, false }
}};
}
pub use static_branch_unlikely;
@@ -47,14 +50,14 @@ macro_rules! static_branch_unlikely {
#[cfg(not(testlib))]
#[cfg(CONFIG_JUMP_LABEL)]
macro_rules! arch_static_branch {
- ($key:path, $keytyp:ty, $field:ident, $branch:expr) => {'my_label: {
+ ($key:path, $keytyp:ty, $($field:ident).+, $branch:expr) => {'my_label: {
$crate::asm!(
include!(concat!(env!("OBJTREE"), "/rust/kernel/generated_arch_static_branch_asm.rs"));
l_yes = label {
break 'my_label true;
},
symb = sym $key,
- off = const ::core::mem::offset_of!($keytyp, $field),
+ off = const ::core::mem::offset_of!($keytyp, $($field).+),
branch = const $crate::jump_label::bool_to_int($branch),
);
@@ -67,7 +70,7 @@ macro_rules! arch_static_branch {
#[cfg(testlib)]
#[cfg(CONFIG_JUMP_LABEL)]
macro_rules! arch_static_branch {
- ($key:path, $keytyp:ty, $field:ident, $branch:expr) => {
+ ($key:path, $keytyp:ty, $($field:ident).+, $branch:expr) => {
// The asm falls through until patched, which never happens on the host.
false
};
--
2.53.0
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v3 3/5] dynamic_debug: expose printing declarations with the core enabled
2026-10-01 14:59 [PATCH v3 0/5] Rust dynamic debug support for pr_debug! and dev_dbg! Zhi Wang
2026-10-01 14:59 ` [PATCH v3 1/5] gpu: nova-core: validate firmware versions before debug logging Zhi Wang
2026-10-01 14:59 ` [PATCH v3 2/5] rust: jump label: add support for nested arguments Zhi Wang
@ 2026-10-01 14:59 ` Zhi Wang
2026-10-01 14:59 ` [PATCH v3 4/5] rust: print: add dynamic debug support to pr_debug! Zhi Wang
2026-10-01 14:59 ` [PATCH v3 5/5] rust: device: add dynamic debug support to dev_dbg! Zhi Wang
4 siblings, 0 replies; 6+ messages in thread
From: Zhi Wang @ 2026-10-01 14:59 UTC (permalink / raw)
To: rust-for-linux, linux-kernel
Cc: andrewjballance, daniel.almeida, dakr, aliceryhl, ojeda, boqun,
gary, bjorn3_gh, lossin, a.hindborg, tmgross, cjia, smitra,
ankita, aniketa, kwankhede, targupta, kjaju, alkumar, acourbot,
jhubbard, zhiwang, Zhi Wang
The dynamic debug printing functions exist whenever DYNAMIC_DEBUG_CORE is
enabled, even if the current translation unit has not opted in to debug
callsites. Expose their declarations under that same condition.
Rust bindings and helpers are compiled independently of the driver crates
that opt in with DYNAMIC_DEBUG_MODULE. They need the declarations in a
CORE-only configuration without enabling callsites globally. Leave the
existing conditions around the callsite macros unchanged.
Signed-off-by: Zhi Wang <zhiw@nvidia.com>
---
include/linux/dynamic_debug.h | 16 ++++++++++------
1 file changed, 10 insertions(+), 6 deletions(-)
diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
index 05743900a116..04df97596a41 100644
--- a/include/linux/dynamic_debug.h
+++ b/include/linux/dynamic_debug.h
@@ -131,12 +131,7 @@ struct ddebug_class_param {
const struct ddebug_class_map *map;
};
-/*
- * pr_debug() and friends are globally enabled or modules have selectively
- * enabled them.
- */
-#if defined(CONFIG_DYNAMIC_DEBUG) || \
- (defined(CONFIG_DYNAMIC_DEBUG_CORE) && defined(DYNAMIC_DEBUG_MODULE))
+#ifdef CONFIG_DYNAMIC_DEBUG_CORE
extern __printf(2, 3)
void __dynamic_pr_debug(struct _ddebug *descriptor, const char *fmt, ...);
@@ -161,6 +156,15 @@ void __dynamic_ibdev_dbg(struct _ddebug *descriptor,
const struct ib_device *ibdev,
const char *fmt, ...);
+#endif /* CONFIG_DYNAMIC_DEBUG_CORE */
+
+/*
+ * pr_debug() and friends are globally enabled or modules have selectively
+ * enabled them.
+ */
+#if defined(CONFIG_DYNAMIC_DEBUG) || \
+ (defined(CONFIG_DYNAMIC_DEBUG_CORE) && defined(DYNAMIC_DEBUG_MODULE))
+
#define __dynamic_dump_stack(desc) \
{ \
if (desc.flags & _DPRINTK_FLAGS_INCL_STACK) \
--
2.53.0
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v3 4/5] rust: print: add dynamic debug support to pr_debug!
2026-10-01 14:59 [PATCH v3 0/5] Rust dynamic debug support for pr_debug! and dev_dbg! Zhi Wang
` (2 preceding siblings ...)
2026-10-01 14:59 ` [PATCH v3 3/5] dynamic_debug: expose printing declarations with the core enabled Zhi Wang
@ 2026-10-01 14:59 ` Zhi Wang
2026-10-01 14:59 ` [PATCH v3 5/5] rust: device: add dynamic debug support to dev_dbg! Zhi Wang
4 siblings, 0 replies; 6+ messages in thread
From: Zhi Wang @ 2026-10-01 14:59 UTC (permalink / raw)
To: rust-for-linux, linux-kernel
Cc: andrewjballance, daniel.almeida, dakr, aliceryhl, ojeda, boqun,
gary, bjorn3_gh, lossin, a.hindborg, tmgross, cjia, smitra,
ankita, aniketa, kwankhede, targupta, kjaju, alkumar, acourbot,
jhubbard, zhiwang, Zhi Wang
From: Andrew Ballance <andrewjballance@gmail.com>
Register Rust callsites in __dyndbg and use the existing C dynamic debug
core for selection, prefixes, stack output and module lifetime handling.
Keep the original Rust format string in the catalogue and format actual
arguments through %pA, preserving the module prefix.
Keep the descriptor in static mut storage and access it through raw
pointers, following the RFC v2 design. Use the nested-field static
branch when jump labels are enabled; otherwise read the print flag via a
C helper. Initialize every callsite as disabled, independently of Rust
debug assertions, and let dynamic debug control its print state. Without
dynamic debug for the crate, keep messages disabled while type-checking
their arguments. Evaluate arguments only when enabled, and keep user
expressions outside the macro's unsafe block. Use match scrutinees to
keep formatting temporaries alive through the synchronous printing call.
Use used(compiler) for the descriptor: the GNU retain flag emitted by
plain used collides with the module loader's SHF_RO_AFTER_INIT flag.
Provide a host-test stub matching the existing printing macros.
Pass Kbuild's normalized module name through RUST_MODNAME for callsite
identity, independently of the existing module! log prefix. Keep metadata
items in a separate scope so implicit argument captures cannot be
shadowed by macro-internal names.
Function names are deliberately recorded as <unknown>; module, file,
line and original-format selection remain available without inferred
function names or compiler-specific name extraction.
Link: https://lore.kernel.org/rust-for-linux/20250620210533.400889-4-andrewjballance@gmail.com/
Signed-off-by: Andrew Ballance <andrewjballance@gmail.com>
[Zhi: Rebase onto driver-core-testing; retain raw-pointer descriptor access;
revise bitfield initialization, configuration gates, Kbuild
module identity, macro hygiene and synchronous printing; retain
<unknown> function metadata and add maintainer routing.]
Signed-off-by: Zhi Wang <zhiw@nvidia.com>
---
MAINTAINERS | 2 +
rust/Makefile | 3 +
rust/bindings/bindings_helper.h | 1 +
rust/helpers/dynamic_debug.c | 25 +++++
rust/helpers/helpers.c | 1 +
rust/kernel/print.rs | 53 +++++++--
rust/kernel/print/dynamic_debug.rs | 165 +++++++++++++++++++++++++++++
scripts/Makefile.build | 1 +
scripts/generate_rust_analyzer.py | 1 +
9 files changed, 246 insertions(+), 6 deletions(-)
create mode 100644 rust/helpers/dynamic_debug.c
create mode 100644 rust/kernel/print/dynamic_debug.rs
diff --git a/MAINTAINERS b/MAINTAINERS
index aec32deef0a1..ecd1312ab35a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -9262,6 +9262,8 @@ S: Maintained
F: include/linux/dynamic_debug.h
F: lib/dynamic_debug.c
F: lib/test_dynamic_debug.c
+F: rust/helpers/dynamic_debug.c
+F: rust/kernel/print/dynamic_debug.rs
DYNAMIC INTERRUPT MODERATION
M: Tal Gilboa <talgi@nvidia.com>
diff --git a/rust/Makefile b/rust/Makefile
index da1a7409d984..b8be882be0e0 100644
--- a/rust/Makefile
+++ b/rust/Makefile
@@ -173,6 +173,7 @@ quiet_cmd_rustdoc = RUSTDOC $(if $(rustdoc_host),H, ) $<
cmd_rustdoc = \
$(rustc_target_envs) \
OBJTREE=$(abspath $(objtree)) \
+ RUST_MODNAME=$(call name-fix-token,$(subst rustdoc-,,$@)) \
$(RUSTDOC) $(filter-out $(skip_flags) --remap-path-scope=%,$(if $(rustdoc_host),$(rust_common_flags),$(rust_flags))) \
$(rustc_target_flags) -L$(objtree)/$(obj)$(if $(rustdoc_host),/host) \
-Zunstable-options --generate-link-to-definition \
@@ -388,6 +389,7 @@ quiet_cmd_rustdoc_test_kernel = RUSTDOC TK $<
mkdir -p $(objtree)/$(obj)/test/doctests/kernel; \
$(rustc_target_envs) \
OBJTREE=$(abspath $(objtree)) \
+ RUST_MODNAME=kernel \
$(RUSTDOC) --test $(filter-out --remap-path-scope=%,$(rust_flags)) \
-L$(objtree)/$(obj) --extern ffi --extern pin_init \
--extern kernel --extern build_error --extern macros \
@@ -647,6 +649,7 @@ quiet_cmd_rustc_library = $(if $(skip_clippy),RUSTC,$(RUSTC_OR_CLIPPY_QUIET)) L
cmd_rustc_library = \
$(rustc_target_envs) \
OBJTREE=$(abspath $(objtree)) \
+ RUST_MODNAME=$(call name-fix-token,$(modname)) \
$(if $(skip_clippy),$(RUSTC),$(RUSTC_OR_CLIPPY)) \
$(filter-out $(skip_flags),$(rust_flags)) $(rustc_target_flags) \
--emit=dep-info=$(depfile) --emit=$(if $(link_helper),llvm-bc=$(patsubst %.o,%.bc,$@),obj=$@) \
diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h
index 4b31aa7f432f..385d04090628 100644
--- a/rust/bindings/bindings_helper.h
+++ b/rust/bindings/bindings_helper.h
@@ -54,6 +54,7 @@
#include <linux/device/faux.h>
#include <linux/dma-direction.h>
#include <linux/dma-mapping.h>
+#include <linux/dynamic_debug.h>
#include <linux/dma-resv.h>
#include <linux/errname.h>
#include <linux/ethtool.h>
diff --git a/rust/helpers/dynamic_debug.c b/rust/helpers/dynamic_debug.c
new file mode 100644
index 000000000000..0ede4ee2eb79
--- /dev/null
+++ b/rust/helpers/dynamic_debug.c
@@ -0,0 +1,25 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/dynamic_debug.h>
+#include <linux/printk.h>
+
+#ifdef CONFIG_DYNAMIC_DEBUG_CORE
+#ifndef CONFIG_JUMP_LABEL
+__rust_helper bool rust_helper_ddebug_enabled(struct _ddebug *descriptor)
+{
+ /* Match the C dynamic debug branch without creating a Rust reference. */
+ return descriptor->flags & _DPRINTK_FLAGS_PRINT;
+}
+#endif
+
+/* The printing helpers receive Rust fmt::Arguments for the %pA bridge. */
+__rust_helper void rust_helper_ddebug_print(struct _ddebug *descriptor,
+ const char *prefix,
+ const void *args)
+{
+ __dynamic_pr_debug(descriptor, "%s: %pA", prefix, args);
+ if (descriptor->flags & _DPRINTK_FLAGS_INCL_STACK)
+ dump_stack();
+}
+
+#endif
diff --git a/rust/helpers/helpers.c b/rust/helpers/helpers.c
index 440fb7638e3c..9730ab7fa143 100644
--- a/rust/helpers/helpers.c
+++ b/rust/helpers/helpers.c
@@ -62,6 +62,7 @@
#endif
#include "drm.c"
#include "drm_gpuvm.c"
+#include "dynamic_debug.c"
#include "err.c"
#include "fs.c"
#include "fwctl.c"
diff --git a/rust/kernel/print.rs b/rust/kernel/print.rs
index 0d62beeedca5..60502f2e614e 100644
--- a/rust/kernel/print.rs
+++ b/rust/kernel/print.rs
@@ -18,6 +18,10 @@
},
};
+#[cfg(CONFIG_DYNAMIC_DEBUG_CORE)]
+#[doc(hidden)]
+pub mod dynamic_debug;
+
// Called from `vsprintf` with format specifier `%pA`.
#[expect(clippy::missing_safety_doc)]
#[export]
@@ -376,13 +380,24 @@ macro_rules! pr_info (
///
/// Use this level for debug messages.
///
-/// Equivalent to the kernel's [`pr_debug`] macro, except that it doesn't support dynamic debug
-/// yet.
+/// Equivalent to the kernel's [`pr_debug`] macro.
+///
+/// Supports [dynamic debug] when `CONFIG_DYNAMIC_DEBUG` is enabled, or when
+/// `CONFIG_DYNAMIC_DEBUG_CORE` is enabled and the crate is built with
+/// `--cfg DYNAMIC_DEBUG_MODULE`. Messages can then be enabled and disabled at runtime,
+/// starting disabled. Rust's `debug_assertions` setting does not affect debug logging.
+/// Without dynamic debug for the crate, messages stay disabled. Disabled messages do not
+/// evaluate their formatting arguments, but the arguments are still checked at compile time.
+///
+/// Dynamic debug callsites can be selected by module, file, line, or format. Their function name
+/// is recorded as `<unknown>`, so selecting a Rust function by its name is not supported.
+/// The module selector uses Kbuild's module name, independently of the crate's log prefix.
///
/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
/// [`std::format!`] for information about the formatting syntax.
///
/// [`pr_debug`]: https://docs.kernel.org/core-api/printk-basics.html#c.pr_debug
+/// [dynamic debug]: https://docs.kernel.org/admin-guide/dynamic-debug-howto.html
/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
/// [`std::format!`]: https://doc.rust-lang.org/std/macro.format.html
///
@@ -393,12 +408,38 @@ macro_rules! pr_info (
/// ```
#[macro_export]
#[doc(alias = "print")]
+#[expect(clippy::crate_in_macro_def)]
macro_rules! pr_debug (
- ($($arg:tt)*) => (
- if cfg!(debug_assertions) {
- $crate::print_macro!($crate::print::format_strings::DEBUG, false, $($arg)*)
+ ($($arg:tt)*) => ({
+ #[cfg(any(CONFIG_DYNAMIC_DEBUG, all(CONFIG_DYNAMIC_DEBUG_CORE, DYNAMIC_DEBUG_MODULE)))]
+ {
+ $crate::dynamic_debug!(__descriptor, ($($arg)*), {
+ match (
+ const {
+ match $crate::str::CStr::from_bytes_with_nul(crate::__LOG_PREFIX) {
+ Ok(prefix) => prefix,
+ Err(_) => panic!("the module log prefix must be a C string"),
+ }
+ },
+ $crate::prelude::fmt!($($arg)*),
+ ) {
+ // SAFETY: `dynamic_debug!` supplies a live, initialized static descriptor.
+ // Its mutable fields are accessed only by the C dynamic debug code.
+ (prefix, args) => unsafe {
+ $crate::print::dynamic_debug::Descriptor::print(__descriptor, prefix, args)
+ },
+ }
+ });
}
- )
+
+ #[cfg(not(any(CONFIG_DYNAMIC_DEBUG, all(CONFIG_DYNAMIC_DEBUG_CORE, DYNAMIC_DEBUG_MODULE))))]
+ {
+ // Keep checking arguments even when dynamic debug is unavailable.
+ if false {
+ $crate::print_macro!($crate::print::format_strings::DEBUG, false, $($arg)*)
+ }
+ }
+ })
);
/// Continues a previous log message in the same line.
diff --git a/rust/kernel/print/dynamic_debug.rs b/rust/kernel/print/dynamic_debug.rs
new file mode 100644
index 000000000000..da4c40ed8fcc
--- /dev/null
+++ b/rust/kernel/print/dynamic_debug.rs
@@ -0,0 +1,165 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Callsite metadata and printing for dynamic debug.
+//!
+//! C header: [`include/linux/dynamic_debug.h`](srctree/include/linux/dynamic_debug.h).
+//!
+//! The printing macros place descriptors in `__dyndbg`. The existing C dynamic debug core
+//! discovers them at boot or module load and removes them before the module is freed.
+
+use crate::{
+ fmt,
+ prelude::*,
+ str::as_char_ptr_in_const_context, //
+};
+
+/// A dynamic debug callsite descriptor.
+///
+/// The [`crate::dynamic_debug!`] macro places descriptors at stable addresses in `__dyndbg`.
+#[repr(transparent)]
+pub struct Descriptor {
+ /// The C descriptor, exposed for static-branch field addressing.
+ pub inner: bindings::_ddebug,
+}
+
+impl Descriptor {
+ /// Creates an initially disabled descriptor.
+ pub const fn new(
+ module: &'static CStr,
+ file: &'static CStr,
+ format: &'static CStr,
+ line: u32,
+ ) -> Self {
+ // SAFETY: `_ddebug` contains raw pointers, integers and, with jump labels, a static key.
+ // All accept zero; the pointers and bitfields are filled in before publication.
+ let mut descriptor: bindings::_ddebug = unsafe { core::mem::zeroed() };
+ descriptor.modname = as_char_ptr_in_const_context(module);
+ descriptor.function = as_char_ptr_in_const_context(c"<unknown>");
+ descriptor.filename = as_char_ptr_in_const_context(file);
+ descriptor.format = as_char_ptr_in_const_context(format);
+
+ // C packs `lineno:18`, `class_id:6` and `flags:8` into an unsigned int. Bindgen's setters
+ // are not const, so encode the target's bitfield ordering explicitly. Truncate line numbers
+ // as the C bitfield assignment does.
+ let line = line & ((1 << 18) - 1);
+ let class = bindings::_DPRINTK_CLASS_DFLT;
+ let flags = bindings::_DPRINTK_FLAGS_NONE;
+ #[cfg(target_endian = "little")]
+ let bits = (line | (class << 18) | (flags << 24)).to_le_bytes();
+ #[cfg(target_endian = "big")]
+ let bits = ((line << 14) | (class << 8) | flags).to_be_bytes();
+ descriptor._bitfield_1 = bindings::__BindgenBitfieldUnit::new(bits);
+
+ #[cfg(CONFIG_JUMP_LABEL)]
+ // An all-zero key is `STATIC_KEY_INIT_FALSE`.
+ static_assert!(bindings::JUMP_TYPE_FALSE == 0);
+
+ Self { inner: descriptor }
+ }
+
+ /// Checks the print flag when jump labels are unavailable.
+ ///
+ /// # Safety
+ ///
+ /// `descriptor` must point to an initialized descriptor valid for this call. Concurrent access
+ /// to its fields must follow the C dynamic debug and jump label synchronization rules, without
+ /// conflicting Rust accesses.
+ #[cfg(not(CONFIG_JUMP_LABEL))]
+ #[inline]
+ pub unsafe fn enabled(descriptor: *mut Self) -> bool {
+ // SAFETY: The pointer is valid by the caller's guarantee. The helper uses the same flag
+ // access as the C dynamic debug branch, without forming a Rust reference to it.
+ unsafe { bindings::ddebug_enabled(&raw mut (*descriptor).inner) }
+ }
+
+ /// Prints arguments with the crate's log prefix and the dynamic debug prefixes.
+ ///
+ /// # Safety
+ ///
+ /// `descriptor` must point to an initialized descriptor valid for this call, whose string
+ /// pointers refer to valid NUL-terminated C strings. Concurrent access must follow the C
+ /// dynamic debug and jump label synchronization rules, without conflicting Rust accesses.
+ pub unsafe fn print(descriptor: *mut Self, prefix: &CStr, args: fmt::Arguments<'_>) {
+ // SAFETY: The descriptor is valid by the caller's guarantee. The helper uses the C string
+ // `prefix` and consumes `args` through `%pA` synchronously, so their borrows remain valid.
+ unsafe {
+ bindings::ddebug_print(
+ &raw mut (*descriptor).inner,
+ prefix.as_char_ptr(),
+ core::ptr::from_ref(&args).cast(),
+ )
+ };
+ }
+}
+
+/// Extracts only the format string for the callsite catalogue.
+///
+/// The original tokens are separately passed to `fmt!`, preserving implicit argument capture.
+#[doc(hidden)]
+#[macro_export]
+macro_rules! dynamic_debug_format {
+ ($format:expr $(, $($rest:tt)*)?) => {
+ // The C catalogue ends at the first NUL; Rust formatting still uses the full string.
+ match $crate::str::CStr::from_bytes_until_nul(concat!($format, "\0").as_bytes()) {
+ Ok(format) => format,
+ Err(_) => panic!("the format string must be NUL-terminated"),
+ }
+ };
+}
+
+/// Defines a callsite and evaluates a printing expression only when it is enabled.
+#[doc(hidden)]
+#[macro_export]
+#[cfg(not(testlib))]
+macro_rules! dynamic_debug {
+ ($descriptor:ident, ($($arg:tt)*), $body:block) => {{
+ // Keep item names out of the user's scope, including implicit format captures.
+ let (descriptor, enabled) = {
+ // `used(compiler)` avoids `SHF_GNU_RETAIN`, which the module loader interprets as
+ // `SHF_RO_AFTER_INIT`.
+ #[used(compiler)]
+ #[unsafe(link_section = "__dyndbg")]
+ static mut DESCRIPTOR: $crate::print::dynamic_debug::Descriptor =
+ $crate::print::dynamic_debug::Descriptor::new(
+ $crate::c_str!(env!("RUST_MODNAME")),
+ $crate::c_str!(file!()),
+ $crate::dynamic_debug_format!($($arg)*),
+ line!(),
+ );
+
+ #[cfg(CONFIG_JUMP_LABEL)]
+ // SAFETY: `DESCRIPTOR` contains an initialized false key at the specified field and
+ // remains valid until the C core unregisters the module's jump label entries.
+ let enabled = unsafe {
+ $crate::jump_label::static_branch_unlikely!(
+ DESCRIPTOR,
+ $crate::print::dynamic_debug::Descriptor,
+ inner.key.dd_key_false
+ )
+ };
+
+ #[cfg(not(CONFIG_JUMP_LABEL))]
+ // SAFETY: The static descriptor is initialized and accessed only by the C helpers
+ // and dynamic debug core, which use the C synchronization rules.
+ let enabled = unsafe {
+ $crate::print::dynamic_debug::Descriptor::enabled(&raw mut DESCRIPTOR)
+ };
+
+ (&raw mut DESCRIPTOR, enabled)
+ };
+
+ if enabled {
+ let $descriptor = descriptor;
+ $body
+ }
+ }};
+}
+
+/// Stub for host doctests, matching [`crate::print_macro!`].
+#[cfg(testlib)]
+#[macro_export]
+macro_rules! dynamic_debug {
+ ($descriptor:ident, ($($arg:tt)*), $body:block) => {
+ ()
+ };
+}
diff --git a/scripts/Makefile.build b/scripts/Makefile.build
index 4349108e75e1..19ed7f2a2d49 100644
--- a/scripts/Makefile.build
+++ b/scripts/Makefile.build
@@ -325,6 +325,7 @@ rust_allowed_features := arbitrary_self_types,asm_goto,generic_arg_infer,used_wi
# modules case.
rust_common_cmd = \
OBJTREE=$(abspath $(objtree)) \
+ RUST_MODNAME=$(call name-fix-token,$(modname)) \
RUST_MODFILE=$(modfile) $(RUSTC_OR_CLIPPY) $(rust_flags) \
-Zallow-features=$(rust_allowed_features) \
-Zcrate-attr=no_std \
diff --git a/scripts/generate_rust_analyzer.py b/scripts/generate_rust_analyzer.py
index dc1219736f77..5c9cb4df6e48 100755
--- a/scripts/generate_rust_analyzer.py
+++ b/scripts/generate_rust_analyzer.py
@@ -104,6 +104,7 @@ def generate_crates(
edition = edition if edition is not None else "2021"
crate_env = {
"RUST_MODFILE": "This is only for rust-analyzer",
+ "RUST_MODNAME": display_name.replace("-", "_"),
**crates_envs.get(display_name, {}),
}
return {
--
2.53.0
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v3 5/5] rust: device: add dynamic debug support to dev_dbg!
2026-10-01 14:59 [PATCH v3 0/5] Rust dynamic debug support for pr_debug! and dev_dbg! Zhi Wang
` (3 preceding siblings ...)
2026-10-01 14:59 ` [PATCH v3 4/5] rust: print: add dynamic debug support to pr_debug! Zhi Wang
@ 2026-10-01 14:59 ` Zhi Wang
4 siblings, 0 replies; 6+ messages in thread
From: Zhi Wang @ 2026-10-01 14:59 UTC (permalink / raw)
To: rust-for-linux, linux-kernel
Cc: andrewjballance, daniel.almeida, dakr, aliceryhl, ojeda, boqun,
gary, bjorn3_gh, lossin, a.hindborg, tmgross, cjia, smitra,
ankita, aniketa, kwankhede, targupta, kjaju, alkumar, acourbot,
jhubbard, zhiwang, Zhi Wang
From: Andrew Ballance <andrewjballance@gmail.com>
Use Rust dynamic debug descriptors for dev_dbg! under DYNAMIC_DEBUG, or
DYNAMIC_DEBUG_CORE with a per-crate DYNAMIC_DEBUG_MODULE opt-in. Route
output through __dynamic_dev_dbg to retain device information and the
standard dynamic debug prefix controls.
Evaluate both the device expression and formatting arguments only when
the callsite is enabled. Calls start disabled and are controlled only by
dynamic debug. Without dynamic debug for the crate, type-check the
arguments without evaluating or printing them. Debug assertions no longer
control either path.
Make direct Device::pr_dbg() calls unconditional, like the other level
methods; callers needing callsite control and lazy evaluation use dev_dbg!.
No in-tree direct callers need conversion.
Document configuration, module selection and the explicit function-name
and embedded-NUL limitations.
Link: https://lore.kernel.org/rust-for-linux/20250620210533.400889-5-andrewjballance@gmail.com/
Signed-off-by: Andrew Ballance <andrewjballance@gmail.com>
[Zhi: Rebase onto driver-core-testing; use the revised descriptor and
printing bridge; keep device and argument evaluation conditional in
both dynamic and fallback paths; keep caller expressions outside unsafe
blocks while retaining their temporaries through each printing call.]
Signed-off-by: Zhi Wang <zhiw@nvidia.com>
---
.../admin-guide/dynamic-debug-howto.rst | 41 ++++++++++++++++++
rust/helpers/dynamic_debug.c | 8 ++++
rust/kernel/device.rs | 42 +++++++++++++++----
rust/kernel/print/dynamic_debug.rs | 27 ++++++++++++
4 files changed, 110 insertions(+), 8 deletions(-)
diff --git a/Documentation/admin-guide/dynamic-debug-howto.rst b/Documentation/admin-guide/dynamic-debug-howto.rst
index 9c2f096ed1d8..004312c0e9bc 100644
--- a/Documentation/admin-guide/dynamic-debug-howto.rst
+++ b/Documentation/admin-guide/dynamic-debug-howto.rst
@@ -390,3 +390,44 @@ just a shortcut for ``print_hex_dump(KERN_DEBUG)``.
For ``print_hex_dump_debug()``/``print_hex_dump_bytes()``, format string is
its ``prefix_str`` argument, if it is constant string; or ``hexdump``
in case ``prefix_str`` is built dynamically.
+
+Rust printing macros
+====================
+
+Rust ``pr_debug!`` and ``dev_dbg!`` use the same control file and boot or
+module parameters as their C counterparts. With ``CONFIG_DYNAMIC_DEBUG=y``,
+their callsites are initially disabled and can be enabled at runtime or
+through boot and module parameters. Rust's ``debug_assertions`` setting
+does not affect debug logging.
+
+With only ``CONFIG_DYNAMIC_DEBUG_CORE=y``, select the Rust crates to include
+in the catalogue using their Kbuild Rust flags, for example::
+
+ RUSTFLAGS_my_driver.o += --cfg DYNAMIC_DEBUG_MODULE
+
+Without dynamic debug for a crate, its ``pr_debug!`` and ``dev_dbg!`` calls
+stay disabled. Disabled calls do not evaluate their formatting arguments
+or device expressions, but their arguments are still checked at compile
+time. Keep required work and error handling outside those expressions.
+
+Rust callsites support the ``module``, ``file``, ``line`` and ``format``
+selectors. The module is the name supplied by Kbuild, including for callsites
+in nested Rust modules. Hyphens in this name become underscores, just as for C
+callsites. This name is independent of the prefix printed by ``pr_debug!``,
+which continues to use the name declared in ``module!``. The format is the
+original Rust format string, with ``{}`` placeholders, rather than the C
+``%pA`` formatting bridge.
+An embedded NUL ends the catalogue's copy of the format string; Rust
+formatting still uses the full string.
+
+Automatic Rust function names are not provided. The function field contains
+``<unknown>``, which is also what the ``f`` prefix flag displays. Use the
+other selectors to select Rust callsites; ``func`` cannot distinguish Rust
+functions. Rust callsites use the default, unclassified debug class.
+
+For example, to control a module named ``my_driver`` at load time or while
+it is running::
+
+ modprobe my_driver dyndbg=+p
+ echo 'module my_driver -p' > /proc/dynamic_debug/control
+ echo 'module my_driver +p' > /proc/dynamic_debug/control
diff --git a/rust/helpers/dynamic_debug.c b/rust/helpers/dynamic_debug.c
index 0ede4ee2eb79..fd2cfc57a3e6 100644
--- a/rust/helpers/dynamic_debug.c
+++ b/rust/helpers/dynamic_debug.c
@@ -22,4 +22,12 @@ __rust_helper void rust_helper_ddebug_print(struct _ddebug *descriptor,
dump_stack();
}
+__rust_helper void rust_helper_ddebug_dev_print(struct _ddebug *descriptor,
+ const struct device *dev,
+ const void *args)
+{
+ __dynamic_dev_dbg(descriptor, dev, "%pA", args);
+ if (descriptor->flags & _DPRINTK_FLAGS_INCL_STACK)
+ dump_stack();
+}
#endif
diff --git a/rust/kernel/device.rs b/rust/kernel/device.rs
index 2291d85b6849..968ac16ebb91 100644
--- a/rust/kernel/device.rs
+++ b/rust/kernel/device.rs
@@ -370,14 +370,13 @@ pub fn pr_info(&self, args: fmt::Arguments<'_>) {
/// Prints a debug-level message (level 7) prefixed with device information.
///
- /// More details are available from [`dev_dbg`].
+ /// This method prints unconditionally. Use [`dev_dbg!`] for dynamic debug callsites and lazy
+ /// evaluation of the device and formatting arguments.
///
- /// [`dev_dbg`]: crate::dev_dbg
+ /// [`dev_dbg!`]: crate::dev_dbg
pub fn pr_dbg(&self, args: fmt::Arguments<'_>) {
- if cfg!(debug_assertions) {
- // SAFETY: `klevel` is null-terminated, uses one of the kernel constants.
- unsafe { self.printk(bindings::KERN_DEBUG, args) };
- }
+ // SAFETY: `KERN_DEBUG` is a null-terminated kernel log-level constant.
+ unsafe { self.printk(bindings::KERN_DEBUG, args) };
}
/// Prints the provided message to the console.
@@ -929,13 +928,19 @@ macro_rules! dev_info {
///
/// This level should be used for debug messages.
///
-/// Equivalent to the kernel's `dev_dbg` macro, except that it doesn't support dynamic debug yet.
+/// Equivalent to the kernel's `dev_dbg` macro.
+///
+/// Supports [dynamic debug] with the same configuration and callsite selection as [`pr_debug!`].
+/// The function name is recorded as `<unknown>`. When a message is disabled, neither the device
+/// expression nor the formatting arguments are evaluated.
///
/// Mimics the interface of [`std::print!`]. More information about the syntax is available from
/// [`core::fmt`] and [`std::format!`].
///
/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
/// [`std::format!`]: https://doc.rust-lang.org/std/macro.format.html
+/// [dynamic debug]: https://docs.kernel.org/admin-guide/dynamic-debug-howto.html
+/// [`pr_debug!`]: crate::pr_debug!
///
/// # Examples
///
@@ -948,5 +953,26 @@ macro_rules! dev_info {
/// ```
#[macro_export]
macro_rules! dev_dbg {
- ($($f:tt)*) => { $crate::dev_printk!(pr_dbg, $($f)*) }
+ ($dev:expr, $($f:tt)*) => {{
+ #[cfg(any(CONFIG_DYNAMIC_DEBUG, all(CONFIG_DYNAMIC_DEBUG_CORE, DYNAMIC_DEBUG_MODULE)))]
+ {
+ $crate::dynamic_debug!(__descriptor, ($($f)*), {
+ match ($dev.as_ref(), $crate::prelude::fmt!($($f)*)) {
+ // SAFETY: `dynamic_debug!` supplies a live, initialized static descriptor.
+ // Its mutable fields are accessed only by the C dynamic debug code.
+ (dev, args) => unsafe {
+ $crate::print::dynamic_debug::Descriptor::dev_print(__descriptor, dev, args)
+ },
+ }
+ });
+ }
+
+ #[cfg(not(any(CONFIG_DYNAMIC_DEBUG, all(CONFIG_DYNAMIC_DEBUG_CORE, DYNAMIC_DEBUG_MODULE))))]
+ {
+ // Keep checking arguments even when dynamic debug is unavailable.
+ if false {
+ $crate::dev_printk!(pr_dbg, $dev, $($f)*);
+ }
+ }
+ }};
}
diff --git a/rust/kernel/print/dynamic_debug.rs b/rust/kernel/print/dynamic_debug.rs
index da4c40ed8fcc..e7250013998f 100644
--- a/rust/kernel/print/dynamic_debug.rs
+++ b/rust/kernel/print/dynamic_debug.rs
@@ -8,6 +8,10 @@
//! discovers them at boot or module load and removes them before the module is freed.
use crate::{
+ device::{
+ Device,
+ DeviceContext, //
+ },
fmt,
prelude::*,
str::as_char_ptr_in_const_context, //
@@ -90,6 +94,29 @@ pub unsafe fn print(descriptor: *mut Self, prefix: &CStr, args: fmt::Arguments<'
)
};
}
+
+ /// Prints arguments with device information and the dynamic debug prefixes.
+ ///
+ /// # Safety
+ ///
+ /// `descriptor` must point to an initialized descriptor valid for this call, whose string
+ /// pointers refer to valid NUL-terminated C strings. Concurrent access must follow the C
+ /// dynamic debug and jump label synchronization rules, without conflicting Rust accesses.
+ pub unsafe fn dev_print<Ctx: DeviceContext>(
+ descriptor: *mut Self,
+ dev: &Device<Ctx>,
+ args: fmt::Arguments<'_>,
+ ) {
+ // SAFETY: The descriptor is valid by the caller's guarantee and `dev` is alive for this
+ // call. The helper consumes the `%pA` arguments synchronously without retaining them.
+ unsafe {
+ bindings::ddebug_dev_print(
+ &raw mut (*descriptor).inner,
+ dev.as_raw(),
+ core::ptr::from_ref(&args).cast(),
+ )
+ };
+ }
}
/// Extracts only the format string for the callsite catalogue.
--
2.53.0
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-10-01 15:00 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-01 14:59 [PATCH v3 0/5] Rust dynamic debug support for pr_debug! and dev_dbg! Zhi Wang
2026-10-01 14:59 ` [PATCH v3 1/5] gpu: nova-core: validate firmware versions before debug logging Zhi Wang
2026-10-01 14:59 ` [PATCH v3 2/5] rust: jump label: add support for nested arguments Zhi Wang
2026-10-01 14:59 ` [PATCH v3 3/5] dynamic_debug: expose printing declarations with the core enabled Zhi Wang
2026-10-01 14:59 ` [PATCH v3 4/5] rust: print: add dynamic debug support to pr_debug! Zhi Wang
2026-10-01 14:59 ` [PATCH v3 5/5] rust: device: add dynamic debug support to dev_dbg! Zhi Wang
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®