From nobody Sun Nov 16 04:03:35 2025 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1743468215; cv=none; d=zohomail.com; s=zohoarc; b=XH7qBxgHARkhBiVkL6l2FSVNv17vam95a2PkEgLnU4ZesjVUmjxkBN/RaOowaOq5NaQcp55lY3k5K3DEDocfSXpB1c1T/olIr1y8fRadVsC5QCbqlT1ywC17k+IfnzWhNgWGJTBTgJ264xgonGTaEjx7TF6lOtbZskvOw4ziOJU= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1743468215; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=YmtoUUxxAeMNlj2iWxoiI13JEEUgLwhrrIjeipFbtJs=; b=hNBAcqgGAtxpq1Dhf8iLGOOacF4IBvP9k/0Pk65plrR0+KwxmyXZzFqGy6Ka97o56elXHQstXI4ZkAxdKxAr+nB9peUwhauYXEPbHGToWiEeA6yob8OafBTwTmELrvhQsAGyRWawNrLDPfAOt7y3gTRZaNH74pHAY9dZZvHlMXg= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 17434682153161003.4756910601068; Mon, 31 Mar 2025 17:43:35 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1tzPi3-0004sg-TL; Mon, 31 Mar 2025 20:42:32 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1tzPSr-0003Md-AV; Mon, 31 Mar 2025 20:26:51 -0400 Received: from out-02.smtp.spacemail.com ([63.250.43.87]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1tzPSo-0000gN-R9; Mon, 31 Mar 2025 20:26:49 -0400 Received: from prod-lbout-phx.jellyfish.systems (unknown [198.177.122.3]) by smtp.spacemail.com (Postfix) with ESMTPA id 4ZRTMH360czGpBH; Tue, 01 Apr 2025 00:26:35 +0000 (UTC) Received: from enumclass.. (unknown [206.221.150.91]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mail.spacemail.com (Postfix) with ESMTPSA id 4ZRTMG4cZgz8sWP; Tue, 1 Apr 2025 00:26:34 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=enumclass.cc; s=spacemail; t=1743467195; bh=S/g2k8i0K/bwT8fXEnWu/VvIS/hn/3hFxwV7PpWvqjc=; h=From:To:Cc:Subject:Date:From; b=z9mvb0+ggACBJEYkURbhqnDKCOojKoaHVM+eH4t1GmIXLObZKTpWEuLzeFmzh65xC DzSgCTqDZ/w8930k2omIZHzLPVjivobr1fwcp5uJ8XlT5/rg+klkMqsKRfg/Exewc4 AZpl6qrfUJpjxWT3G8wyXChBHzHLWdxUDHTmSI7tTAUjfJQ0oL4RPnf4JdQPX50FAK UEb7NsKja4Y8ua0eivwqlIJW1VZoYpIb/FBkU9ElqbsvFieKzmuhM1g4vGvk8k2w3w EgQT0uzvjRN8/R3ckkatKyr82QE8iw+uy0/Ucxdkpttiq4B6i8UMGX8ezXgwMh/NDB 9XPLuBK7UoUng== From: saman To: qemu-devel@nongnu.org Cc: Stefan Hajnoczi , qemu-rust@nongnu.org, Mads Ynddal , Manos Pitsidianakis , saman Subject: [PATCH] Rust: Add tracing and logging support for Rust code Date: Mon, 31 Mar 2025 19:26:33 -0500 Message-ID: <20250401002633.738345-1-saman@enumclass.cc> X-Mailer: git-send-email 2.43.0 MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=63.250.43.87; envelope-from=saman@enumclass.cc; helo=out-02.smtp.spacemail.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_VALIDITY_CERTIFIED_BLOCKED=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-Mailman-Approved-At: Mon, 31 Mar 2025 20:42:30 -0400 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @enumclass.cc) X-ZM-MESSAGEID: 1743468220266019100 Content-Type: text/plain; charset="utf-8" This change introduces initial support for tracing and logging in Rust-based QEMU code. As an example, tracing and logging have been implemented in the pl011 device, which is written in Rust. - Updated `rust/wrapper.h` to include the `qemu/log.h` and `hw/char/trace.h= ` header. - Added log.rs to wrap `qemu_log_mask` and `qemu_log_mask_and_addr` - Modified `tracetool` scripts to move C function implementation from header to .c - Added log and trace in rust version of PL011 device Future enhancements could include generating idiomatic Rust APIs for tracing using the tracetool scripts Signed-off-by: saman --- include/qemu/log-for-trace.h | 5 +-- rust/hw/char/pl011/src/device.rs | 34 +++++++++++++++--- rust/hw/char/pl011/src/registers.rs | 20 +++++++++++ rust/qemu-api/meson.build | 1 + rust/qemu-api/src/lib.rs | 1 + rust/qemu-api/src/log.rs | 54 +++++++++++++++++++++++++++++ rust/wrapper.h | 2 ++ scripts/tracetool/format/c.py | 16 +++++++++ scripts/tracetool/format/h.py | 11 ++---- util/log.c | 5 +++ 10 files changed, 131 insertions(+), 18 deletions(-) create mode 100644 rust/qemu-api/src/log.rs diff --git a/include/qemu/log-for-trace.h b/include/qemu/log-for-trace.h index d47c9cd446..ad5cd0dd24 100644 --- a/include/qemu/log-for-trace.h +++ b/include/qemu/log-for-trace.h @@ -24,10 +24,7 @@ extern int qemu_loglevel; #define LOG_TRACE (1 << 15) =20 /* Returns true if a bit is set in the current loglevel mask */ -static inline bool qemu_loglevel_mask(int mask) -{ - return (qemu_loglevel & mask) !=3D 0; -} +bool qemu_loglevel_mask(int mask); =20 /* main logging function */ void G_GNUC_PRINTF(1, 2) qemu_log(const char *fmt, ...); diff --git a/rust/hw/char/pl011/src/device.rs b/rust/hw/char/pl011/src/devi= ce.rs index bf88e0b00a..42385a7bf6 100644 --- a/rust/hw/char/pl011/src/device.rs +++ b/rust/hw/char/pl011/src/device.rs @@ -2,15 +2,21 @@ // Author(s): Manos Pitsidianakis // SPDX-License-Identifier: GPL-2.0-or-later =20 -use std::{ffi::CStr, mem::size_of, ptr::addr_of_mut}; +use std::{ + ffi::{CStr, CString}, + mem::size_of, + ptr::addr_of_mut, +}; =20 use qemu_api::{ chardev::{CharBackend, Chardev, Event}, impl_vmstate_forward, irq::{IRQState, InterruptSource}, + log::Mask, memory::{hwaddr, MemoryRegion, MemoryRegionOps, MemoryRegionOpsBuilder= }, prelude::*, qdev::{Clock, ClockEvent, DeviceImpl, DeviceState, Property, ResetType= , ResettablePhasesImpl}, + qemu_log_mask, qom::{ObjectImpl, Owned, ParentField}, static_assert, sysbus::{SysBusDevice, SysBusDeviceImpl}, @@ -298,7 +304,7 @@ pub(self) fn write( DMACR =3D> { self.dmacr =3D value; if value & 3 > 0 { - // qemu_log_mask(LOG_UNIMP, "pl011: DMA not implemente= d\n"); + qemu_log_mask!(Mask::log_unimp, "pl011: DMA not implem= ented\n"); eprintln!("pl011: DMA not implemented"); } } @@ -535,11 +541,21 @@ fn read(&self, offset: hwaddr, _size: u32) -> u64 { u64::from(device_id[(offset - 0xfe0) >> 2]) } Err(_) =3D> { - // qemu_log_mask(LOG_GUEST_ERROR, "pl011_read: Bad offset = 0x%x\n", (int)offset); + qemu_log_mask!( + Mask::log_guest_error, + "pl011_read: Bad offset 0x%x\n", + offset as i32 + ); 0 } Ok(field) =3D> { + let regname =3D field.as_str(); let (update_irq, result) =3D self.regs.borrow_mut().read(f= ield); + let c_string =3D CString::new(regname).expect("CString::ne= w failed"); + let name_ptr =3D c_string.as_ptr(); + unsafe { + qemu_api::bindings::trace_pl011_read(offset as u32, re= sult, name_ptr); + } if update_irq { self.update(); self.char_backend.accept_input(); @@ -576,8 +592,16 @@ fn write(&self, offset: hwaddr, value: u64, _size: u32= ) { =20 fn can_receive(&self) -> u32 { let regs =3D self.regs.borrow(); - // trace_pl011_can_receive(s->lcr, s->read_count, r); - u32::from(regs.read_count < regs.fifo_depth()) + let fifo_available =3D u32::from(regs.read_count < regs.fifo_depth= ()); + unsafe { + qemu_api::bindings::trace_pl011_can_receive( + u32::from(regs.line_control), + regs.read_count, + regs.fifo_depth().try_into().unwrap(), + fifo_available, + ); + } + fifo_available } =20 fn receive(&self, buf: &[u8]) { diff --git a/rust/hw/char/pl011/src/registers.rs b/rust/hw/char/pl011/src/r= egisters.rs index cd92fa2c30..11c085030d 100644 --- a/rust/hw/char/pl011/src/registers.rs +++ b/rust/hw/char/pl011/src/registers.rs @@ -72,6 +72,26 @@ pub enum RegisterOffset { //Reserved =3D 0x04C, } =20 +impl RegisterOffset { + pub fn as_str(&self) -> &'static str { + match self { + RegisterOffset::DR =3D> "DR", + RegisterOffset::RSR =3D> "RSR", + RegisterOffset::FR =3D> "FR", + RegisterOffset::FBRD =3D> "FBRD", + RegisterOffset::ILPR =3D> "ILPR", + RegisterOffset::IBRD =3D> "IBRD", + RegisterOffset::LCR_H =3D> "LCR_H", + RegisterOffset::CR =3D> "CR", + RegisterOffset::FLS =3D> "FLS", + RegisterOffset::IMSC =3D> "IMSC", + RegisterOffset::RIS =3D> "RIS", + RegisterOffset::MIS =3D> "MIS", + RegisterOffset::ICR =3D> "ICR", + RegisterOffset::DMACR =3D> "DMACR", + } + } +} /// Receive Status Register / Data Register common error bits /// /// The `UARTRSR` register is updated only when a read occurs diff --git a/rust/qemu-api/meson.build b/rust/qemu-api/meson.build index 858685ddd4..f8eddf7887 100644 --- a/rust/qemu-api/meson.build +++ b/rust/qemu-api/meson.build @@ -34,6 +34,7 @@ _qemu_api_rs =3D static_library( 'src/qom.rs', 'src/sysbus.rs', 'src/timer.rs', + 'src/log.rs', 'src/vmstate.rs', 'src/zeroable.rs', ], diff --git a/rust/qemu-api/src/lib.rs b/rust/qemu-api/src/lib.rs index 05f38b51d3..b54989a243 100644 --- a/rust/qemu-api/src/lib.rs +++ b/rust/qemu-api/src/lib.rs @@ -21,6 +21,7 @@ pub mod chardev; pub mod errno; pub mod irq; +pub mod log; pub mod memory; pub mod module; pub mod offset_of; diff --git a/rust/qemu-api/src/log.rs b/rust/qemu-api/src/log.rs new file mode 100644 index 0000000000..07e8bceb34 --- /dev/null +++ b/rust/qemu-api/src/log.rs @@ -0,0 +1,54 @@ +#[allow(non_camel_case_types)] +#[repr(u32)] +pub enum Mask { + cpu_log_tb_out_asm =3D crate::bindings::CPU_LOG_TB_OUT_ASM, + cpu_log_tb_in_asm =3D crate::bindings::CPU_LOG_TB_IN_ASM, + cpu_log_tb_op =3D crate::bindings::CPU_LOG_TB_OP, + cpu_log_tb_op_opt =3D crate::bindings::CPU_LOG_TB_OP_OPT, + cpu_log_int =3D crate::bindings::CPU_LOG_INT, + cpu_log_exec =3D crate::bindings::CPU_LOG_EXEC, + cpu_log_pcall =3D crate::bindings::CPU_LOG_PCALL, + cpu_log_tb_cpu =3D crate::bindings::CPU_LOG_TB_CPU, + cpu_log_reset =3D crate::bindings::CPU_LOG_RESET, + log_unimp =3D crate::bindings::LOG_UNIMP, + log_guest_error =3D crate::bindings::LOG_GUEST_ERROR, + cpu_log_mmu =3D crate::bindings::CPU_LOG_MMU, + cpu_log_tb_nochain =3D crate::bindings::CPU_LOG_TB_NOCHAIN, + cpu_log_page =3D crate::bindings::CPU_LOG_PAGE, + cpu_log_tb_op_ind =3D crate::bindings::CPU_LOG_TB_OP_IND, + cpu_log_tb_fpu =3D crate::bindings::CPU_LOG_TB_FPU, + cpu_log_plugin =3D crate::bindings::CPU_LOG_PLUGIN, + log_strace =3D crate::bindings::LOG_STRACE, + log_per_thread =3D crate::bindings::LOG_PER_THREAD, + cpu_log_tb_vpu =3D crate::bindings::CPU_LOG_TB_VPU, + log_tb_op_plugin =3D crate::bindings::LOG_TB_OP_PLUGIN, + log_invalid_mem =3D crate::bindings::LOG_INVALID_MEM, +} + +#[macro_export] +macro_rules! qemu_log_mask { + ($mask:expr, $fmt:expr $(, $arg:expr)*) =3D> {{ + let mask: Mask =3D $mask; + unsafe { + if $crate::bindings::qemu_loglevel_mask(mask as std::os::raw::= c_int) { + let format_str =3D std::ffi::CString::new($fmt).expect("CS= tring::new failed"); + $crate::bindings::qemu_log(format_str.as_ptr() $(, $arg)*); + } + } + }}; +} + +#[macro_export] +macro_rules! qemu_log_mask_and_addr { + ($mask:expr, $addr:expr, $fmt:expr $(, $arg:expr)*) =3D> {{ + let mask: Mask =3D $mask; + let addr: $crate::bindings::hwaddr =3D $addr; + unsafe { + if $crate::bindings::qemu_loglevel_mask(mask as std::os::raw::= c_int) && + $crate::bindings::qemu_log_in_addr_range(addr) { + let format_str =3D std::ffi::CString::new($fmt).expect("CS= tring::new failed"); + $crate::bindings::qemu_log(format_str.as_ptr() $(, $arg)*); + } + } + }}; +} diff --git a/rust/wrapper.h b/rust/wrapper.h index d4fec54657..cd2f311d71 100644 --- a/rust/wrapper.h +++ b/rust/wrapper.h @@ -64,5 +64,7 @@ typedef enum memory_order { #include "chardev/char-serial.h" #include "exec/memattrs.h" #include "qemu/timer.h" +#include "qemu/log.h" #include "exec/address-spaces.h" #include "hw/char/pl011.h" +#include "hw/char/trace.h" diff --git a/scripts/tracetool/format/c.py b/scripts/tracetool/format/c.py index 69edf0d588..f2d383f89c 100644 --- a/scripts/tracetool/format/c.py +++ b/scripts/tracetool/format/c.py @@ -43,6 +43,22 @@ def generate(events, backend, group): sstate =3D "TRACE_%s_ENABLED" % e.name.upper(), dstate =3D e.api(e.QEMU_DSTATE)) =20 + cond =3D "true" + + out('', + 'void %(api)s(%(args)s)', + '{', + ' if (%(cond)s) {', + ' %(api_nocheck)s(%(names)s);', + ' }', + '}', + api=3De.api(), + api_nocheck=3De.api(e.QEMU_TRACE_NOCHECK), + args=3De.args, + names=3D", ".join(e.args.names()), + cond=3Dcond + ) + out('TraceEvent *%(group)s_trace_events[] =3D {', group =3D group.lower()) =20 diff --git a/scripts/tracetool/format/h.py b/scripts/tracetool/format/h.py index ea126b07ea..16b360ae49 100644 --- a/scripts/tracetool/format/h.py +++ b/scripts/tracetool/format/h.py @@ -74,17 +74,10 @@ def generate(events, backend, group): cond =3D "true" =20 out('', - 'static inline void %(api)s(%(args)s)', - '{', - ' if (%(cond)s) {', - ' %(api_nocheck)s(%(names)s);', - ' }', - '}', + 'void %(api)s(%(args)s);', api=3De.api(), - api_nocheck=3De.api(e.QEMU_TRACE_NOCHECK), args=3De.args, - names=3D", ".join(e.args.names()), - cond=3Dcond) + ) =20 backend.generate_end(events, group) =20 diff --git a/util/log.c b/util/log.c index b87d399e4c..51f659be0a 100644 --- a/util/log.c +++ b/util/log.c @@ -143,6 +143,11 @@ void qemu_log_unlock(FILE *logfile) } } =20 +bool qemu_loglevel_mask(int mask) +{ + return (qemu_loglevel & mask) !=3D 0; +} + void qemu_log(const char *fmt, ...) { FILE *f =3D qemu_log_trylock(); --=20 2.43.0