A log_mask_ln!() macro is provided which expects similar arguments as the C version. However, the formatting works as one would expect from Rust.
To maximize code reuse the macro is just a thin wrapper around qemu_log(). Also, just the bare minimum of logging masks is provided which should suffice for the current use case of Rust in QEMU. Signed-off-by: Bernhard Beschow <shen...@gmail.com> --- docs/devel/rust.rst | 1 + rust/wrapper.h | 2 + rust/qemu-api/meson.build | 1 + rust/qemu-api/src/lib.rs | 1 + rust/qemu-api/src/log.rs | 78 ++++++++++++++++++++++++++++++++++++ rust/qemu-api/src/prelude.rs | 2 + 6 files changed, 85 insertions(+) create mode 100644 rust/qemu-api/src/log.rs diff --git a/docs/devel/rust.rst b/docs/devel/rust.rst index 47e9677fcb..dc8c44109e 100644 --- a/docs/devel/rust.rst +++ b/docs/devel/rust.rst @@ -162,6 +162,7 @@ module status ``errno`` complete ``error`` stable ``irq`` complete +``log`` proof of concept ``memory`` stable ``module`` complete ``qdev`` stable diff --git a/rust/wrapper.h b/rust/wrapper.h index 6060d3ba1a..15a1b19847 100644 --- a/rust/wrapper.h +++ b/rust/wrapper.h @@ -48,6 +48,8 @@ typedef enum memory_order { #endif /* __CLANG_STDATOMIC_H */ #include "qemu/osdep.h" +#include "qemu/log.h" +#include "qemu/log-for-trace.h" #include "qemu/module.h" #include "qemu-io.h" #include "system/system.h" diff --git a/rust/qemu-api/meson.build b/rust/qemu-api/meson.build index cac8595a14..33caee3c4f 100644 --- a/rust/qemu-api/meson.build +++ b/rust/qemu-api/meson.build @@ -21,6 +21,7 @@ _qemu_api_rs = static_library( 'src/errno.rs', 'src/error.rs', 'src/irq.rs', + 'src/log.rs', 'src/memory.rs', 'src/module.rs', 'src/prelude.rs', diff --git a/rust/qemu-api/src/lib.rs b/rust/qemu-api/src/lib.rs index 93902fc94b..e20be35460 100644 --- a/rust/qemu-api/src/lib.rs +++ b/rust/qemu-api/src/lib.rs @@ -21,6 +21,7 @@ pub mod errno; pub mod error; pub mod irq; +pub mod log; pub mod memory; pub mod module; pub mod qdev; diff --git a/rust/qemu-api/src/log.rs b/rust/qemu-api/src/log.rs new file mode 100644 index 0000000000..0d7f06e63c --- /dev/null +++ b/rust/qemu-api/src/log.rs @@ -0,0 +1,78 @@ +// Copyright 2025 Bernhard Beschow <shen...@gmail.com> +// SPDX-License-Identifier: GPL-2.0-or-later + +//! Bindings for QEMU's logging infrastructure + +#[repr(u32)] +/// Represents specific error categories within QEMU's logging system. +/// +/// The `Log` enum provides a Rust abstraction for logging errors, corresponding +/// to a subset of the error categories defined in the C implementation. +pub enum Log { + /// Log invalid access caused by the guest. + /// Corresponds to `LOG_GUEST_ERROR` in the C implementation. + GuestError = crate::bindings::LOG_GUEST_ERROR, + + /// Log guest access of unimplemented functionality. + /// Corresponds to `LOG_UNIMP` in the C implementation. + Unimp = crate::bindings::LOG_UNIMP, +} + +/// A macro to log messages conditionally based on a provided mask. +/// +/// The `log_mask_ln` macro checks whether the given mask matches the current +/// log level and, if so, formats and logs the message. It is the Rust +/// counterpart of the `qemu_log_mask()` macro in the C implementation. +/// +/// # Parameters +/// +/// - `$mask`: A log level mask. This should be a variant of the `Log` enum. +/// - `$fmt`: A format string following the syntax and rules of the `format!` +/// macro. It specifies the structure of the log message. +/// - `$args`: Optional arguments to be interpolated into the format string. +/// +/// # Example +/// +/// ``` +/// use qemu_api::log::Log; +/// use qemu_api::log_mask_ln; +/// +/// let error_address = 0xbad; +/// log_mask_ln!( +/// Log::GuestError, +/// "Address 0x{error_address:x} out of range" +/// ); +/// ``` +/// +/// It is also possible to use printf-style formatting, as well as having a +/// trailing `,`: +/// +/// ``` +/// use qemu_api::log::Log; +/// use qemu_api::log_mask_ln; +/// +/// let error_address = 0xbad; +/// log_mask_ln!( +/// Log::GuestError, +/// "Address 0x{:x} out of range", +/// error_address, +/// ); +/// ``` +#[macro_export] +macro_rules! log_mask_ln { + ($mask:expr, $fmt:tt $($args:tt)*) => {{ + // Type assertion to enforce type `Log` for $mask + let _: Log = $mask; + + if unsafe { + (::qemu_api::bindings::qemu_loglevel & ($mask as std::os::raw::c_int)) != 0 + } { + let formatted_string = format!("{}\n", format_args!($fmt $($args)*)); + let c_string = std::ffi::CString::new(formatted_string).unwrap(); + + unsafe { + ::qemu_api::bindings::qemu_log(c_string.as_ptr()); + } + } + }}; +} diff --git a/rust/qemu-api/src/prelude.rs b/rust/qemu-api/src/prelude.rs index 43bfcd5fca..8f9e23ee2c 100644 --- a/rust/qemu-api/src/prelude.rs +++ b/rust/qemu-api/src/prelude.rs @@ -11,6 +11,8 @@ pub use crate::errno; +pub use crate::log_mask_ln; + pub use crate::qdev::DeviceMethods; pub use crate::qom::InterfaceType; -- 2.49.0