qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
To: qemu-devel@nongnu.org
Cc: "Paolo Bonzini" <pbonzini@redhat.com>,
	"Peter Maydell" <peter.maydell@linaro.org>,
	"Marc-André Lureau" <marcandre.lureau@redhat.com>,
	"Daniel P. Berrangé" <berrange@redhat.com>,
	"Philippe Mathieu-Daudé" <philmd@linaro.org>,
	"Alex Bennée" <alex.bennee@linaro.org>,
	"Thomas Huth" <thuth@redhat.com>,
	"Junjie Mao" <junjie.mao@hotmail.com>,
	"Junjie Mao" <junjie.mao@intel.com>,
	"Zhao Liu" <zhao1.liu@intel.com>, "Kevin Wolf" <kwolf@redhat.com>,
	"Philippe Mathieu-Daudé" <philmd@linaro.org>,
	"Richard Henderson" <richard.henderson@linaro.org>,
	"Gustavo Romero" <gustavo.romero@linaro.org>,
	"Pierrick Bouvier" <pierrick.bouvier@linaro.org>
Subject: [PATCH 10/11] rust/qemu-api: add log module
Date: Thu, 24 Oct 2024 17:03:08 +0300	[thread overview]
Message-ID: <20241024-rust-round-2-v1-10-051e7a25b978@linaro.org> (raw)
In-Reply-To: <20241024-rust-round-2-v1-0-051e7a25b978@linaro.org>

Logging in QEMU is done by function-like C macros, which we cannot use
directly from Rust with bindgen.

This commit adds a new qemu_api module, `log`, that provides the
following interfaces:

- a `LogMask` enum type that uses the mask values from the generated
  bindings, and makes sure the rust enum variant names and values will
  match.
- `LogMask` aliases `LogMask::GUEST_ERROR` and `LogMask::UNIMPLEMENTED`
  for convenience.
- a private qemu_loglevel_mask() function, counterpart of
  `qemu_loglevel_mask` in `include/qemu/log-for-trace.h`, which we
  cannot use from bindgen since it's a static inline item.
- public qemu_log(), qemu_log_mask() and qemu_log_mask_and_addr()
  functions that should act like the C equivalent:

  pub fn qemu_log_mask_and_addr(log_mask: LogMask, address: u64, str: &str);
  pub fn qemu_log_mask(log_mask: LogMask, str: &str);
  pub fn qemu_log(str: &str);

  It takes a 'static or allocated string slice as argument, but in the
  feature we will introduce better log macros in Rust that make use of
  Rust's format arguments. This is not really a bad compromise since
  generating a log item is not a hot path so allocating here is fine.

Example usage will be:

```rust
qemu_log_mask(LogMask::GUEST_ERROR, "device XYZ failed spectacularly");

qemu_log_mask(
 LogMask::UNIMPLEMENTED,
 &format!(
   "We haven't implemented this feature in {file}:{line} out of pure laziness.",
   file = file!(),
   line = line!()
 )
);
```

Signed-off-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
---
 rust/wrapper.h            |   1 +
 rust/qemu-api/meson.build |   1 +
 rust/qemu-api/src/lib.rs  |   1 +
 rust/qemu-api/src/log.rs  | 140 ++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 143 insertions(+)

diff --git a/rust/wrapper.h b/rust/wrapper.h
index 77e40213efb686d23f6b768b78602e4337623280..8f76ef26f111d5e1f308268f445696acc7ddbfef 100644
--- a/rust/wrapper.h
+++ b/rust/wrapper.h
@@ -32,6 +32,7 @@
 
 #include "qemu/osdep.h"
 #include "qemu/module.h"
+#include "qemu/log.h"
 #include "qemu-io.h"
 #include "sysemu/sysemu.h"
 #include "hw/sysbus.h"
diff --git a/rust/qemu-api/meson.build b/rust/qemu-api/meson.build
index 11984abb878bef18be3c819f61da24ce1405ea59..a82ff0d39a2263d15bda312aa0a2d46c77b2501f 100644
--- a/rust/qemu-api/meson.build
+++ b/rust/qemu-api/meson.build
@@ -3,6 +3,7 @@ _qemu_api_rs = static_library(
   structured_sources(
     [
       'src/lib.rs',
+      'src/log.rs',
       'src/objects.rs',
       'src/vmstate.rs',
     ],
diff --git a/rust/qemu-api/src/lib.rs b/rust/qemu-api/src/lib.rs
index d276adfb6622eee6e42494e089e1f20b0b5cdf08..c3eb464f66361ee2349e636c49e38d3a6b57ad97 100644
--- a/rust/qemu-api/src/lib.rs
+++ b/rust/qemu-api/src/lib.rs
@@ -29,6 +29,7 @@ unsafe impl Sync for bindings::VMStateDescription {}
 unsafe impl Sync for bindings::VMStateField {}
 unsafe impl Sync for bindings::VMStateInfo {}
 
+pub mod log;
 pub mod objects;
 pub mod vmstate;
 
diff --git a/rust/qemu-api/src/log.rs b/rust/qemu-api/src/log.rs
new file mode 100644
index 0000000000000000000000000000000000000000..50525ac6b7f49786c2975843b7dc70b91c18d5a0
--- /dev/null
+++ b/rust/qemu-api/src/log.rs
@@ -0,0 +1,140 @@
+// Copyright 2024, Linaro Limited
+// Author(s): Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+//! Logging functionality.
+//!
+//! This module provides:
+//!
+//! - a [`LogMask`] enum type that uses the mask values from the generated
+//!   bindings, and makes sures the rust enum variant names and values will
+//!   match.
+//! - [`LogMask`] aliases [`LogMask::GUEST_ERROR`] and [`LogMask::UNIMPLEMENTED`]
+//!   for convenience.
+//! - a private `qemu_loglevel_mask()` function, counterpart of
+//!   `qemu_loglevel_mask` in `include/qemu/log-for-trace.h`, which we
+//!   cannot use from bindgen since it's a `static inline` item.
+//! - public [`qemu_log`], [`qemu_log_mask`] and [`qemu_log_mask_and_addr`] functions that act like
+//!   the C equivalents.
+//!
+//! # Examples
+//!
+//! ```rust
+//! # use qemu_api::log::*;
+//! # fn main() {
+//! qemu_log_mask(LogMask::GUEST_ERROR, "device XYZ failed spectacularly");
+//!
+//! qemu_log_mask(
+//!  LogMask::UNIMPLEMENTED,
+//!  &format!(
+//!    "We haven't implemented this feature in {file}:{line} out of pure laziness.",
+//!    file = file!(),
+//!    line = line!()
+//!  )
+//! );
+//! # }
+//! ```
+
+use crate::bindings;
+
+macro_rules! mask_variants {
+    ($(#[$outer:meta])*
+     pub enum $name:ident {
+         $(
+             $(#[$attrs:meta])*
+             $symbol:ident
+         ),*$(,)*
+     }) => {
+        $(#[$outer])*
+            pub enum $name {
+                $(
+                    $(#[$attrs])*
+                    $symbol = bindings::$symbol
+                ),*
+            }
+    };
+}
+
+mask_variants! {
+    /// A wrapper type for the various log mask `#defines` in the C code base.
+    #[allow(non_camel_case_types)]
+    #[derive(Copy, Clone, Eq, PartialEq, Debug)]
+    #[repr(u32)]
+    pub enum LogMask {
+        CPU_LOG_TB_OUT_ASM,
+        CPU_LOG_TB_IN_ASM,
+        CPU_LOG_TB_OP,
+        CPU_LOG_TB_OP_OPT,
+        CPU_LOG_INT,
+        CPU_LOG_EXEC,
+        CPU_LOG_PCALL,
+        CPU_LOG_TB_CPU,
+        CPU_LOG_RESET,
+        LOG_UNIMP,
+        LOG_GUEST_ERROR,
+        CPU_LOG_MMU,
+        CPU_LOG_TB_NOCHAIN,
+        CPU_LOG_PAGE,
+        LOG_TRACE,
+        CPU_LOG_TB_OP_IND,
+        CPU_LOG_TB_FPU,
+        CPU_LOG_PLUGIN,
+        /// For user-mode strace logging.
+        LOG_STRACE,
+        LOG_PER_THREAD,
+        CPU_LOG_TB_VPU,
+        LOG_TB_OP_PLUGIN,
+    }
+}
+
+impl LogMask {
+    /// Alias.
+    pub const GUEST_ERROR: Self = LogMask::LOG_GUEST_ERROR;
+    /// Alias.
+    pub const UNIMPLEMENTED: Self = LogMask::LOG_UNIMP;
+}
+
+/// Returns `true` if a bit is set in the current loglevel mask.
+///
+/// Counterpart of `qemu_loglevel_mask` in `include/qemu/log-for-trace.h`.
+fn qemu_loglevel_mask(mask: LogMask) -> bool {
+    // SAFETY: This is an internal global variable. We only read from it and reading invalid values
+    // is not a concern here.
+    let current_level = unsafe { bindings::qemu_loglevel };
+    let mask = mask as ::core::ffi::c_int;
+
+    (current_level & mask) != 0
+}
+
+/// Log a message in QEMU's log, given a specific log mask.
+pub fn qemu_log_mask(log_mask: LogMask, str: &str) {
+    if qemu_loglevel_mask(log_mask) {
+        qemu_log(str);
+    }
+}
+
+/// Log a message in QEMU's log only if a bit is set on the current loglevel mask and we are in the
+/// address range we care about.
+pub fn qemu_log_mask_and_addr(log_mask: LogMask, address: u64, str: &str) {
+    if qemu_loglevel_mask(log_mask) && {
+        // SAFETY: This function reads global variables/system state but an error here is not a
+        // concern.
+        unsafe { bindings::qemu_log_in_addr_range(address) }
+    } {
+        qemu_log(str);
+    }
+}
+
+/// Log a message in QEMU's log, without a log mask.
+pub fn qemu_log(str: &str) {
+    let Ok(cstr) = ::std::ffi::CString::new(str) else {
+        panic!(
+            "qemu_log_mask: Converting passed string {:?} to CString failed.",
+            str
+        );
+    };
+    // SAFETY: We're passing two valid CStr pointers. The second argument for the variadic
+    // `qemu_log` function must be a `*const c_char` since the format specifier is `%s`.
+    // Therefore this is a safe call.
+    unsafe { bindings::qemu_log(c"%s\n".as_ptr(), cstr.as_ptr()) };
+}

-- 
2.45.2



  parent reply	other threads:[~2024-10-24 14:05 UTC|newest]

Thread overview: 25+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-10-24 14:02 [PATCH 00/11] Rust device model patches and misc cleanups Manos Pitsidianakis
2024-10-24 14:02 ` [PATCH 01/11] Revert "rust: add PL011 device model" Manos Pitsidianakis
2024-10-24 14:03 ` [PATCH 02/11] rust: add PL011 device model Manos Pitsidianakis
2024-10-24 14:03 ` [PATCH 03/11] rust/qemu-api-macros: introduce Device proc macro Manos Pitsidianakis
2024-10-24 15:13   ` Alex Bennée
2024-10-24 17:06     ` Manos Pitsidianakis
2024-10-25 12:01   ` Paolo Bonzini
2024-10-25 14:04     ` Manos Pitsidianakis
2024-10-25 15:22       ` Paolo Bonzini
2024-10-25 16:22         ` Manos Pitsidianakis
2024-10-27 20:58   ` Paolo Bonzini
2024-10-27 22:39     ` Manos Pitsidianakis
2024-10-28  7:07       ` Paolo Bonzini
2024-10-24 14:03 ` [PATCH 04/11] rust: add support for migration in device models Manos Pitsidianakis
2024-10-24 14:03 ` [PATCH 05/11] rust/pl011: move CLK_NAME static to function scope Manos Pitsidianakis
2024-10-24 14:03 ` [PATCH 06/11] rust/pl011: add TYPE_PL011_LUMINARY device Manos Pitsidianakis
2024-10-24 17:27   ` Zhao Liu
2024-10-24 14:03 ` [PATCH 07/11] rust/pl011: move pub callback decl to local scope Manos Pitsidianakis
2024-10-24 14:03 ` [PATCH 08/11] rust/pl011: remove commented out C code Manos Pitsidianakis
2024-10-24 14:03 ` [PATCH 09/11] rust/pl011: Use correct masks for IBRD and FBRD Manos Pitsidianakis
2024-10-24 14:03 ` Manos Pitsidianakis [this message]
2024-10-24 14:03 ` [PATCH 11/11] rust/pl011: log guest/unimp errors Manos Pitsidianakis
2024-10-25  9:33 ` [PATCH 00/11] Rust device model patches and misc cleanups Paolo Bonzini
2024-10-26 10:06   ` Manos Pitsidianakis
2024-10-27  8:13     ` Paolo Bonzini

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=20241024-rust-round-2-v1-10-051e7a25b978@linaro.org \
    --to=manos.pitsidianakis@linaro.org \
    --cc=alex.bennee@linaro.org \
    --cc=berrange@redhat.com \
    --cc=gustavo.romero@linaro.org \
    --cc=junjie.mao@hotmail.com \
    --cc=junjie.mao@intel.com \
    --cc=kwolf@redhat.com \
    --cc=marcandre.lureau@redhat.com \
    --cc=pbonzini@redhat.com \
    --cc=peter.maydell@linaro.org \
    --cc=philmd@linaro.org \
    --cc=pierrick.bouvier@linaro.org \
    --cc=qemu-devel@nongnu.org \
    --cc=richard.henderson@linaro.org \
    --cc=thuth@redhat.com \
    --cc=zhao1.liu@intel.com \
    /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;
as well as URLs for NNTP newsgroup(s).