From: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
To: qemu-devel@nongnu.org
Cc: qemu-rust@nongnu.org,
"Philippe Mathieu-Daudé" <philmd@linaro.org>,
alex.bennee@linaro.org,
"Manos Pitsidianakis" <manos.pitsidianakis@linaro.org>
Subject: [PATCH RFC 3/5] rust/qemu-api-macros: Add #[trace_events] macro
Date: Mon, 04 Aug 2025 16:47:16 +0300 [thread overview]
Message-ID: <20250804-rust_trace-v1-3-b20cc16b0c51@linaro.org> (raw)
In-Reply-To: <20250804-rust_trace-v1-0-b20cc16b0c51@linaro.org>
WIP
Add attribute macro that converts a module definition into trace events.
Currently it allocates a string to pass to
::qemu_api::log::LogGuard::log_fmt. If you pass format_args! directly
the arguments are not properly written, might be a bug in the
qemu_api::log implementation.
Signed-off-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
---
rust/qemu-api-macros/src/lib.rs | 140 +++++++++++++++++++++++++++++++++++++++-
1 file changed, 137 insertions(+), 3 deletions(-)
diff --git a/rust/qemu-api-macros/src/lib.rs b/rust/qemu-api-macros/src/lib.rs
index b525d89c09e496a1f7f5582dc6d994e318f62bca..7d13b1c195085f1d153514cc01ec5c389160916a 100644
--- a/rust/qemu-api-macros/src/lib.rs
+++ b/rust/qemu-api-macros/src/lib.rs
@@ -3,10 +3,15 @@
// SPDX-License-Identifier: GPL-2.0-or-later
use proc_macro::TokenStream;
-use quote::quote;
+use quote::{format_ident, quote};
use syn::{
- parse_macro_input, parse_quote, punctuated::Punctuated, spanned::Spanned, token::Comma, Data,
- DeriveInput, Error, Field, Fields, FieldsUnnamed, Ident, Meta, Path, Token, Variant,
+ parse::{Parse, ParseStream},
+ parse_macro_input, parse_quote,
+ punctuated::Punctuated,
+ spanned::Spanned,
+ token::Comma,
+ Data, DeriveInput, Error, Field, Fields, FieldsUnnamed, FnArg, Ident, LitCStr, LitStr, Meta,
+ Path, Token, Variant,
};
mod bits;
use bits::BitsConstInternal;
@@ -263,3 +268,132 @@ pub fn bits_const_internal(ts: TokenStream) -> TokenStream {
.unwrap_or_else(syn::Error::into_compile_error)
.into()
}
+
+#[derive(Debug)]
+struct TraceModule {
+ module_name: syn::Ident,
+ trace_events: Vec<(proc_macro2::TokenStream, syn::Ident)>,
+}
+
+impl Parse for TraceModule {
+ fn parse(input: ParseStream) -> syn::Result<Self> {
+ if input.peek(Token![pub]) {
+ input.parse::<Token![pub]>()?;
+ }
+ input.parse::<Token![mod]>()?;
+ let module_name: Ident = input.parse()?;
+ let braced;
+ _ = syn::braced!(braced in input);
+ let mut trace_events = vec![];
+ while !braced.is_empty() {
+ braced.parse::<Token![fn]>()?;
+ let name = braced.parse::<Ident>()?;
+ let name_cstr = LitCStr::new(
+ &std::ffi::CString::new(name.to_string()).unwrap(),
+ name.span(),
+ );
+ let name_cstr_ident = format_ident!("trace_{name}_name");
+ let arguments_inner;
+ _ = syn::parenthesized!(arguments_inner in braced);
+ let fn_arguments: Punctuated<FnArg, Token![,]> =
+ Punctuated::parse_terminated(&arguments_inner)?;
+ let body;
+ _ = syn::braced!(body in braced);
+ let trace_event_format_str: LitStr = body.parse()?;
+ assert!(body.is_empty(), "{body:?}");
+
+ let trace_macro_ident = format_ident!("trace_{name}");
+ let name_ident = format_ident!("trace_{name}_EVENT");
+ let dstate = format_ident!("TRACE_{name}_DSTATE");
+ let enabled = format_ident!("TRACE_{name}_ENABLED");
+ trace_events.push(
+ (
+ quote! {
+ static mut #dstate: u16 = 0;
+ const #enabled: bool = true;
+ const #name_cstr_ident: &::std::ffi::CStr = #name_cstr;
+
+ static mut #name_ident: ::qemu_api::bindings::TraceEvent = ::qemu_api::bindings::TraceEvent {
+ id: 0,
+ name: #name_cstr_ident.as_ptr(),
+ sstate: #enabled,
+ dstate: &raw mut #dstate,
+ };
+
+ macro_rules! #trace_macro_ident {
+ ($($args:tt)*) => {{
+ crate::#module_name::#name($($args)*);
+ }};
+ }
+ pub(crate) use #trace_macro_ident;
+
+ pub fn #name(#fn_arguments) {
+ if #enabled
+ && unsafe { ::qemu_api::bindings::trace_events_enabled_count > 0 }
+ && unsafe { #dstate > 0 }
+ && unsafe {
+ (::qemu_api::bindings::qemu_loglevel & (::qemu_api::log::Log::Trace as std::os::raw::c_int)) != 0
+ } {
+ _ = ::qemu_api::log::LogGuard::log_fmt(
+ format_args!("{}", format!("{} {}\n", stringify!(#name), format_args!(#trace_event_format_str)))
+ );
+ }
+ }
+ },
+ name_ident,
+ )
+ );
+ }
+
+ Ok(Self {
+ module_name,
+ trace_events,
+ })
+ }
+}
+
+#[proc_macro_attribute]
+pub fn trace_events(_attr: TokenStream, item: TokenStream) -> TokenStream {
+ let input = parse_macro_input!(item as TraceModule);
+ let TraceModule {
+ module_name,
+ trace_events,
+ } = input;
+ let mut event_names = quote! {};
+ let mut trace_event_impl = quote! {};
+ let tracevents_len = trace_events.len() + 1;
+ for (body, event_name) in trace_events {
+ event_names = quote! {
+ #event_names
+ &raw mut #event_name,
+ };
+ trace_event_impl = quote! {
+ #trace_event_impl
+ #body
+ };
+ }
+
+ quote! {
+ #[macro_use]
+ mod #module_name {
+ #![allow(static_mut_refs)]
+ #![allow(non_upper_case_globals)]
+
+ #trace_event_impl
+
+ #[used]
+ static mut TRACE_EVENTS: [*mut ::qemu_api::bindings::TraceEvent; #tracevents_len] = unsafe {
+ [
+ #event_names
+ ::core::ptr::null_mut(),
+ ]
+ };
+
+ ::qemu_api::module_init!(
+ MODULE_INIT_TRACE => unsafe {
+ ::qemu_api::bindings::trace_event_register_group(TRACE_EVENTS.as_mut_ptr())
+ }
+ );
+ }
+ }.into()
+}
--
2.47.2
next prev parent reply other threads:[~2025-08-04 15:17 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-08-04 13:47 [PATCH RFC 0/5] rust: implement tracing Manos Pitsidianakis
2025-08-04 13:47 ` [PATCH RFC 1/5] rust/bindings: add trace headers Manos Pitsidianakis
2025-08-04 13:47 ` [PATCH RFC 2/5] rust/qemu-api/log: add Log::Trace variant Manos Pitsidianakis
2025-08-04 13:47 ` Manos Pitsidianakis [this message]
2025-08-04 13:47 ` [PATCH RFC 4/5] rust/pl011: impl Copy, Clone for RegisterOffset Manos Pitsidianakis
2025-08-04 13:47 ` [PATCH RFC 5/5] rust/pl011: add trace events Manos Pitsidianakis
2025-08-05 16:04 ` [PATCH RFC 0/5] rust: implement tracing Daniel P. Berrangé
2025-08-05 16:25 ` Manos Pitsidianakis
2025-08-05 16:43 ` Daniel P. Berrangé
2025-08-05 16:47 ` Manos Pitsidianakis
2025-08-05 17:54 ` Daniel P. Berrangé
2025-08-05 20:06 ` Manos Pitsidianakis
2025-08-06 9:02 ` Paolo Bonzini
2025-08-06 9:21 ` Daniel P. Berrangé
2025-08-06 9:34 ` Manos Pitsidianakis
2025-08-06 9:36 ` Manos Pitsidianakis
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=20250804-rust_trace-v1-3-b20cc16b0c51@linaro.org \
--to=manos.pitsidianakis@linaro.org \
--cc=alex.bennee@linaro.org \
--cc=philmd@linaro.org \
--cc=qemu-devel@nongnu.org \
--cc=qemu-rust@nongnu.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;
as well as URLs for NNTP newsgroup(s).