On Tue, Jun 10, 2025 at 11:21 PM Bernhard Beschow <shen...@gmail.com> wrote: > > A log_mask!() 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 | 76 +++++++++++++++++++++++++++++++++++++++ > 5 files changed, 81 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..9e3c61b8b7 > --- /dev/null > +++ b/rust/qemu-api/src/log.rs > @@ -0,0 +1,76 @@ > +// Copyright 2025 Bernhard Beschow <shen...@gmail.com> > +// SPDX-License-Identifier: GPL-2.0-or-later > + > +#[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 an 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` 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; > +/// > +/// let error_address = 0xbad; > +/// log_mask!( > +/// Log::GuestError, > +/// "Address 0x{error_address:x} out of range\n" > +/// ); > +/// ``` > +/// > +/// 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; > +/// > +/// let error_address = 0xbad; > +/// log_mask!( > +/// Log::GuestError, > +/// "Address 0x{:x} out of range\n", > +/// error_address, > +/// ); > +/// ``` > +#[macro_export] > +macro_rules! log_mask { > + ($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!($fmt $($args)*); > + let c_string = std::ffi::CString::new(formatted_string).unwrap(); > + > + unsafe { > + ::qemu_api::bindings::qemu_log(c_string.as_ptr()); > + } > + } > + }}; > +} > -- > 2.49.0 >
Maybe we could take this chance to remove the requirement for trailing newline? Not urgent, and also something we could change afterwards anyway. We could also introduce log_mask_ln! macro but now I'm just bikeshedding. Besides that, I think it'd be useful to have the macro re-exported in rust/qemu-api/src/prelude.rs as well. Please add it for the next version. -- Manos Pitsidianakis Emulation and Virtualization Engineer at Linaro Ltd