From: Alice Ryhl <aliceryhl@google.com>
To: Zhi Wang <zhiw@nvidia.com>
Cc: Alice Ryhl <aliceryhl@google.com>,
rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org,
andrewjballance@gmail.com, daniel.almeida@collabora.com,
dakr@kernel.org, ojeda@kernel.org, boqun@kernel.org,
gary@garyguo.net, bjorn3_gh@protonmail.com, lossin@kernel.org,
a.hindborg@kernel.org, tmgross@umich.edu, cjia@nvidia.com,
smitra@nvidia.com, ankita@nvidia.com, aniketa@nvidia.com,
kwankhede@nvidia.com, targupta@nvidia.com, kjaju@nvidia.com,
alkumar@nvidia.com, acourbot@nvidia.com, jhubbard@nvidia.com,
zhiwang@kernel.org
Subject: Re: [PATCH v3 4/5] rust: print: add dynamic debug support to pr_debug!
Date: Fri, 16 Oct 2026 08:50:44 +0000 [thread overview]
Message-ID: <20261016085045.3517539-1-aliceryhl@google.com> (raw)
In-Reply-To: <20261001145940.1077801-5-zhiw@nvidia.com>
On Thu, Oct 01, 2026 at 05:59:39PM +0300, Zhi Wang wrote:
> +/// 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,
> +}
Should this be #[repr(C, align(8))] to match how C adds __aligned(8) in
DEFINE_DYNAMIC_DEBUG_METADATA_CLS?
> +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 }
> + }
Two comments here:
1. Instead of hardcoding `c"<unknown>"` for `descriptor.function`, how
about passing `$crate::c_str!(module_path!())` from `dynamic_debug!`
(an idea from Thomas Weißschuh's RFC series [1])? Even though Rust
doesn't have a `function_name!()` macro, recording `module_path!()`
makes the `+f` prefix flag useful and allows `func` queries in
`/proc/dynamic_debug/control` to filter by Rust module path within a
multi-file crate.
[1] https://lore.kernel.org/rust-for-linux/20261011-rust-dyndbg-v1-8-832e4039b71f@weissschuh.net/
2. The inline bitfield manipulation and `unsafe { core::mem::zeroed() }`
is pretty ugly. Please use the same strategy as `FamilyFlags` in
`rust/kernel/net/netlink.rs` to handle bitfields in `const` context:
- Move the bitfield construction into a dedicated helper struct with a
`const fn into_bitfield(self) -> bindings::__BindgenBitfieldUnit<[u8; 4]>`
method.
- Construct `bindings::_ddebug` directly using struct literal syntax
with `..pin_init::zeroed()`, avoiding `unsafe { core::mem::zeroed() }`
and field-by-field mutation.
- Add a kunit test (like `test_family_flags_bitfield`) that verifies
`into_bitfield()` against bindgen's generated `set_lineno`,
`set_class_id`, and `set_flags` (or `bindings::_ddebug::new_bitfield_1`).
> + /// 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(),
> + )
> + };
> + }
`Descriptor::print` (and `Descriptor::dev_print` in patch 5/5) should be
marked `#[inline]`, just like `Descriptor::enabled`.
> +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!(),
> + );
Is `#[used(compiler)]` needed here at all?
When the `pr_debug!` / `dev_dbg!` statement is reachable, `DESCRIPTOR`
is already referenced by `static_branch_unlikely!(DESCRIPTOR, ...)` and
by `&raw mut DESCRIPTOR` passed to `Descriptor::print`. And if the
callsite is optimized out (for example, inside an unused function or
dead branch), we *want* the static `DESCRIPTOR` to be deleted as well
rather than leaving an orphan entry in `__dyndbg`. This would match C's
`DEFINE_DYNAMIC_DEBUG_METADATA_CLS`, which does not use `__used`.
For instance, with `#[used(compiler)]` present, the uncalled `fn example`
in the `dev_dbg!` doctest still emits a dead `DESCRIPTOR` into `vmlinux`'s
`__dyndbg` section.
> +/// Stub for host doctests, matching [`crate::print_macro!`].
> +#[cfg(testlib)]
> +#[macro_export]
> +macro_rules! dynamic_debug {
> + ($descriptor:ident, ($($arg:tt)*), $body:block) => {
> + ()
> + };
> +}
If `dynamic_debug!` drops `$body` under `#[cfg(testlib)]`, any variables
used only inside `pr_debug!` or `dev_dbg!` will trigger `unused_variables`
warnings under `testlib`, and `$body` won't be type-checked. How about:
if false {
let $descriptor: *mut $crate::print::dynamic_debug::Descriptor =
::core::ptr::null_mut();
$body
}
Alice
next prev parent reply other threads:[~2026-10-16 8:50 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
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-16 8:50 ` Alice Ryhl [this message]
2026-10-01 14:59 ` [PATCH v3 5/5] rust: device: add dynamic debug support to dev_dbg! Zhi Wang
2026-10-16 8:41 ` Alice Ryhl
2026-10-15 19:29 ` [PATCH v3 0/5] Rust dynamic debug support for pr_debug! and dev_dbg! Zhi Wang
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261016085045.3517539-1-aliceryhl@google.com \
--to=aliceryhl@google.com \
--cc=a.hindborg@kernel.org \
--cc=acourbot@nvidia.com \
--cc=alkumar@nvidia.com \
--cc=andrewjballance@gmail.com \
--cc=aniketa@nvidia.com \
--cc=ankita@nvidia.com \
--cc=bjorn3_gh@protonmail.com \
--cc=boqun@kernel.org \
--cc=cjia@nvidia.com \
--cc=dakr@kernel.org \
--cc=daniel.almeida@collabora.com \
--cc=gary@garyguo.net \
--cc=jhubbard@nvidia.com \
--cc=kjaju@nvidia.com \
--cc=kwankhede@nvidia.com \
--cc=linux-kernel@vger.kernel.org \
--cc=lossin@kernel.org \
--cc=ojeda@kernel.org \
--cc=rust-for-linux@vger.kernel.org \
--cc=smitra@nvidia.com \
--cc=targupta@nvidia.com \
--cc=tmgross@umich.edu \
--cc=zhiw@nvidia.com \
--cc=zhiwang@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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®