Skip to main content

debug/
dprintf.rs

1// Copyright 2026 The Fuchsia Authors
2//
3// Use of this source code is governed by a MIT-style
4// license that can be found in the LICENSE file or at
5// https://opensource.org/licenses/MIT
6
7//! Debug logging (`dprintf`) mechanism for the Zircon kernel.
8//!
9//! # Overview
10//!
11//! This crate provides a Rust implementation of the global debug printing mechanism
12//! (`dprintf!`) used in the Zircon kernel. It is the Rust counterpart to the C++
13//! header `zircon/kernel/include/debug.h`.
14//!
15//! # Verbosity Levels
16//!
17//! The macro `dprintf!` filters messages at compile time based on the global
18//! GN build argument `kernel_debug_print_level`.
19//!
20//! This argument defaults to `2` (`SPEW`) in the kernel parameters (see
21//! `zircon/kernel/params.gni`).
22//!
23//! To override this level in your local build, add the following to your `args.gn`:
24//!
25//! ```gn
26//! kernel_debug_print_level = 1  # Restrict to INFO and CRITICAL
27//! ```
28//!
29//! The following levels are defined, matching C++:
30//! * `CRITICAL` (0) / `ALWAYS` (0): Critical errors or messages that should always be printed.
31//! * `INFO` (1): Informational messages.
32//! * `SPEW` (2): Verbose debugging messages.
33//!
34//! If a message's level is greater than the configured `kernel_debug_print_level`,
35//! the macro call compiles down to nothing, incurring zero runtime overhead.
36//!
37//! # Usage
38//!
39//! To use global debug printing in a Rust file:
40//!
41//! ```rust
42//! use debug::dprintf;
43//!
44//! fn my_function() {
45//!     dprintf!(INFO, "This is an info message: {}\n", 42);
46//!     dprintf!(SPEW, "This is verbose spew\n");
47//! }
48//! ```
49//!
50//! The macro supports literal tokens `CRITICAL`, `ALWAYS`, `INFO`, and `SPEW`
51//! without needing to import them, but you can also use arbitrary expressions
52//! that evaluate to `u32` (e.g. `debug::dprintf::INFO` or a local variable).
53
54pub const CRITICAL: u32 = 0;
55pub const ALWAYS: u32 = 0;
56pub const INFO: u32 = 1;
57pub const SPEW: u32 = 2;
58
59pub struct KernelConsoleWriter;
60
61impl core::fmt::Write for KernelConsoleWriter {
62    #[cfg(not(test))]
63    fn write_str(&mut self, s: &str) -> core::fmt::Result {
64        kprint::kprint!("{:s}", s);
65        Ok(())
66    }
67
68    #[cfg(test)]
69    fn write_str(&mut self, s: &str) -> core::fmt::Result {
70        std::print!("{}", s);
71        Ok(())
72    }
73}
74
75#[doc(hidden)]
76#[inline(always)]
77pub const fn dprintf_enabled(level: u32) -> bool {
78    let limit = if cfg!(debug_print_level = "0") {
79        CRITICAL
80    } else if cfg!(debug_print_level = "1") {
81        INFO
82    } else {
83        SPEW
84    };
85    level <= limit
86}
87
88#[doc(hidden)]
89#[inline(always)]
90pub fn print_dprintf_args(args: core::fmt::Arguments<'_>) {
91    use core::fmt::Write;
92    let mut writer = KernelConsoleWriter;
93    let _ = writer.write_fmt(args);
94}
95
96/// Formats and prints a debug message if the global debug print level is
97/// greater than or equal to the specified level.
98///
99/// Equivalent to C++ `dprintf`.
100///
101/// # Examples
102/// ```rust
103/// dprintf!(INFO, "initialized with value {}\n", val);
104/// ```
105#[macro_export]
106macro_rules! dprintf {
107    (CRITICAL, $($arg:tt)*) => { $crate::dprintf!($crate::dprintf::CRITICAL, $($arg)*) };
108    (ALWAYS, $($arg:tt)*) => { $crate::dprintf!($crate::dprintf::ALWAYS, $($arg)*) };
109    (INFO, $($arg:tt)*) => { $crate::dprintf!($crate::dprintf::INFO, $($arg)*) };
110    (SPEW, $($arg:tt)*) => { $crate::dprintf!($crate::dprintf::SPEW, $($arg)*) };
111    ($level:expr, $($arg:tt)*) => {
112        if $crate::dprintf::dprintf_enabled($level) {
113            $crate::dprintf::print_dprintf_args(core::format_args!($($arg)*));
114        }
115    };
116}
117
118#[cfg(test)]
119mod tests {
120    #[test]
121    fn test_dprintf() {
122        dprintf!(CRITICAL, "critical\n");
123        dprintf!(ALWAYS, "always\n");
124        dprintf!(INFO, "info\n");
125        dprintf!(SPEW, "spew\n");
126        dprintf!(3, "should not print\n");
127        dprintf!(INFO, "info const\n");
128    }
129}