qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 0/4] trace: add Rust DTrace/SystemTap SDT support
@ 2025-11-19 20:51 Stefan Hajnoczi
  2025-11-19 20:51 ` [PATCH v2 1/4] hpet: remove unused trace events Stefan Hajnoczi
                   ` (4 more replies)
  0 siblings, 5 replies; 8+ messages in thread
From: Stefan Hajnoczi @ 2025-11-19 20:51 UTC (permalink / raw)
  To: qemu-devel
  Cc: Philippe Mathieu-Daudé, qemu-rust, Mads Ynddal, Thomas Huth,
	Manos Pitsidianakis, Alex Bennée, Paolo Bonzini, Josh Stone,
	Stefan Hajnoczi

v2:
- Re-export probe::probe!() from the trace crate to avoid the explicit probe
  crate dependency from hpet, pl011, etc. [Paolo]

This series adds SDT probe support so that SystemTap, GDB, etc can trace QEMU's
Rust code when compiled with `./configure --enable-trace-backends=dtrace`.

The dtrace(1) tool that generates the .o and C header file does not support
Rust. Use the probe crate (https://crates.io/crates/probe), which takes care of
emitting SDT probes, and extend tracetool to emit code for the trace events.

While SDT is cross-platform, the probe crate currently only supports Linux
(SystemTap). On other platforms the crate is a nop - it compiles but does
nothing. Future changes to the probe crate may add support for other operating
systems like FreeBSD, macOS, etc without much needed in the way of QEMU code
changes.

Based-on: <20251106215606.36598-1-stefanha@redhat.com>

Stefan Hajnoczi (4):
  hpet: remove unused trace events
  rust/hpet: add trace events
  subprojects: add probe crate
  tracetool: add Rust DTrace/SystemTap SDT support

 hw/timer/trace-events                         |  2 -
 rust/Cargo.lock                               |  6 ++
 rust/hw/timer/hpet/Cargo.toml                 |  1 +
 rust/hw/timer/hpet/meson.build                |  1 +
 rust/hw/timer/hpet/src/device.rs              | 45 ++++++++-----
 rust/meson.build                              |  2 +
 rust/trace/Cargo.toml                         |  1 +
 rust/trace/meson.build                        |  2 +-
 rust/trace/src/lib.rs                         |  4 ++
 scripts/archive-source.sh                     |  1 +
 scripts/make-release                          |  2 +-
 scripts/tracetool/__init__.py                 |  1 +
 scripts/tracetool/backend/dtrace.py           | 31 +++++++++
 scripts/tracetool/format/rs.py                | 27 ++++++--
 subprojects/.gitignore                        |  1 +
 .../packagefiles/probe-0.5-rs/meson.build     | 22 +++++++
 subprojects/probe-0.5-rs.wrap                 |  7 ++
 tests/tracetool/dtrace.rs                     | 65 +++++++++++++++++++
 tests/tracetool/ftrace.rs                     | 21 ++++++
 tests/tracetool/log.rs                        | 21 ++++++
 tests/tracetool/simple.rs                     | 21 ++++++
 tests/tracetool/syslog.rs                     | 21 ++++++
 tests/tracetool/tracetool-test.py             |  2 +-
 23 files changed, 280 insertions(+), 27 deletions(-)
 create mode 100644 subprojects/packagefiles/probe-0.5-rs/meson.build
 create mode 100644 subprojects/probe-0.5-rs.wrap
 create mode 100644 tests/tracetool/dtrace.rs

-- 
2.51.1



^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH v2 1/4] hpet: remove unused trace events
  2025-11-19 20:51 [PATCH v2 0/4] trace: add Rust DTrace/SystemTap SDT support Stefan Hajnoczi
@ 2025-11-19 20:51 ` Stefan Hajnoczi
  2025-11-20 14:49   ` Zhao Liu
  2025-11-19 20:51 ` [PATCH v2 2/4] rust/hpet: add " Stefan Hajnoczi
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 8+ messages in thread
From: Stefan Hajnoczi @ 2025-11-19 20:51 UTC (permalink / raw)
  To: qemu-devel
  Cc: Philippe Mathieu-Daudé, qemu-rust, Mads Ynddal, Thomas Huth,
	Manos Pitsidianakis, Alex Bennée, Paolo Bonzini, Josh Stone,
	Stefan Hajnoczi

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 hw/timer/trace-events | 2 --
 1 file changed, 2 deletions(-)

diff --git a/hw/timer/trace-events b/hw/timer/trace-events
index 2bb51f95ea..f3fca6fc9b 100644
--- a/hw/timer/trace-events
+++ b/hw/timer/trace-events
@@ -112,7 +112,6 @@ sh_timer_write(uint64_t offset, uint64_t value) "tmu012_write 0x%" PRIx64 " 0x%0
 
 # hpet.c
 hpet_timer_id_out_of_range(uint8_t timer_id) "timer id out of range: 0x%" PRIx8
-hpet_invalid_hpet_cfg(uint8_t reg_off) "invalid HPET_CFG + %u" PRIx8
 hpet_ram_read(uint64_t addr) "enter hpet_ram_readl at 0x%" PRIx64
 hpet_ram_read_reading_counter(uint8_t reg_off, uint64_t cur_tick) "reading counter + %" PRIu8 " = 0x%" PRIx64
 hpet_ram_read_invalid(void) "invalid hpet_ram_readl"
@@ -123,4 +122,3 @@ hpet_ram_write_tn_cmp(uint8_t reg_off) "hpet_ram_writel HPET_TN_CMP + %" PRIu8
 hpet_ram_write_invalid_tn_cmp(void) "invalid HPET_TN_CMP + 4 write"
 hpet_ram_write_invalid(void) "invalid hpet_ram_writel"
 hpet_ram_write_counter_write_while_enabled(void) "Writing counter while HPET enabled!"
-hpet_ram_write_counter_written(uint8_t reg_off, uint64_t value, uint64_t counter) "HPET counter + %" PRIu8 "written. crt = 0x%" PRIx64 " -> 0x%" PRIx64
-- 
2.51.1



^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v2 2/4] rust/hpet: add trace events
  2025-11-19 20:51 [PATCH v2 0/4] trace: add Rust DTrace/SystemTap SDT support Stefan Hajnoczi
  2025-11-19 20:51 ` [PATCH v2 1/4] hpet: remove unused trace events Stefan Hajnoczi
@ 2025-11-19 20:51 ` Stefan Hajnoczi
  2025-11-20 14:49   ` Zhao Liu
  2025-11-19 20:51 ` [PATCH v2 3/4] subprojects: add probe crate Stefan Hajnoczi
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 8+ messages in thread
From: Stefan Hajnoczi @ 2025-11-19 20:51 UTC (permalink / raw)
  To: qemu-devel
  Cc: Philippe Mathieu-Daudé, qemu-rust, Mads Ynddal, Thomas Huth,
	Manos Pitsidianakis, Alex Bennée, Paolo Bonzini, Josh Stone,
	Stefan Hajnoczi

Implement the same trace events as the C implementation.

Notes:
- Keep order of hpet_ram_write_invalid_tn_cmp and hpet_ram_write_tn_cmp
  the same as the C implementation.
- Put hpet_ram_write_timer_id in HPETTimer::write() instead of
  HPETState::decode() so that reads can be excluded.

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 rust/hw/timer/hpet/Cargo.toml    |  1 +
 rust/hw/timer/hpet/meson.build   |  1 +
 rust/hw/timer/hpet/src/device.rs | 45 +++++++++++++++++++-------------
 3 files changed, 29 insertions(+), 18 deletions(-)

diff --git a/rust/hw/timer/hpet/Cargo.toml b/rust/hw/timer/hpet/Cargo.toml
index f781b28d8b..5567eefda4 100644
--- a/rust/hw/timer/hpet/Cargo.toml
+++ b/rust/hw/timer/hpet/Cargo.toml
@@ -18,6 +18,7 @@ bql = { path = "../../../bql" }
 qom = { path = "../../../qom" }
 system = { path = "../../../system" }
 hwcore = { path = "../../../hw/core" }
+trace = { path = "../../../trace" }
 
 [lints]
 workspace = true
diff --git a/rust/hw/timer/hpet/meson.build b/rust/hw/timer/hpet/meson.build
index bb64b96672..465995bb5a 100644
--- a/rust/hw/timer/hpet/meson.build
+++ b/rust/hw/timer/hpet/meson.build
@@ -11,6 +11,7 @@ _libhpet_rs = static_library(
     qom_rs,
     system_rs,
     hwcore_rs,
+    trace_rs
   ],
 )
 
diff --git a/rust/hw/timer/hpet/src/device.rs b/rust/hw/timer/hpet/src/device.rs
index 3564aa79c6..90b0ae927c 100644
--- a/rust/hw/timer/hpet/src/device.rs
+++ b/rust/hw/timer/hpet/src/device.rs
@@ -32,6 +32,8 @@
 
 use crate::fw_cfg::HPETFwConfig;
 
+::trace::include_trace!("hw_timer");
+
 /// Register space for each timer block (`HPET_BASE` is defined in hpet.h).
 const HPET_REG_SPACE_LEN: u64 = 0x400; // 1024 bytes
 
@@ -402,7 +404,8 @@ fn del_timer(&mut self) {
 
     /// Configuration and Capability Register
     fn set_tn_cfg_reg(&mut self, shift: u32, len: u32, val: u64) {
-        // TODO: Add trace point - trace_hpet_ram_write_tn_cfg(addr & 4)
+        trace::trace_hpet_ram_write_tn_cfg((shift / 8).try_into().unwrap());
+
         let old_val: u64 = self.config;
         let mut new_val: u64 = old_val.deposit(shift, len, val);
         new_val = hpet_fixup_reg(new_val, old_val, HPET_TN_CFG_WRITE_MASK);
@@ -435,17 +438,18 @@ fn set_tn_cmp_reg(&mut self, shift: u32, len: u32, val: u64) {
         let mut length = len;
         let mut value = val;
 
-        // TODO: Add trace point - trace_hpet_ram_write_tn_cmp(addr & 4)
         if self.is_32bit_mod() {
             // High 32-bits are zero, leave them untouched.
             if shift != 0 {
-                // TODO: Add trace point - trace_hpet_ram_write_invalid_tn_cmp()
+                trace::trace_hpet_ram_write_invalid_tn_cmp();
                 return;
             }
             length = 64;
             value = u64::from(value as u32); // truncate!
         }
 
+        trace::trace_hpet_ram_write_tn_cmp((shift / 8).try_into().unwrap());
+
         if !self.is_periodic() || self.is_valset_enabled() {
             self.cmp = self.cmp.deposit(shift, length, value);
         }
@@ -512,6 +516,9 @@ const fn read(&self, reg: TimerRegister) -> u64 {
 
     fn write(&mut self, reg: TimerRegister, value: u64, shift: u32, len: u32) {
         use TimerRegister::*;
+
+        trace::trace_hpet_ram_write_timer_id(self.index as u64);
+
         match reg {
             CFG => self.set_tn_cfg_reg(shift, len, value),
             CMP => self.set_tn_cmp_reg(shift, len, value),
@@ -689,15 +696,13 @@ fn set_int_status_reg(&self, shift: u32, _len: u32, val: u64) {
     /// Main Counter Value Register
     fn set_counter_reg(&self, shift: u32, len: u32, val: u64) {
         if self.is_hpet_enabled() {
-            // TODO: Add trace point -
-            // trace_hpet_ram_write_counter_write_while_enabled()
-            //
             // HPET spec says that writes to this register should only be
             // done while the counter is halted. So this is an undefined
             // behavior. There's no need to forbid it, but when HPET is
             // enabled, the changed counter value will not affect the
             // tick count (i.e., the previously calculated offset will
             // not be changed as well).
+            trace::trace_hpet_ram_write_counter_write_while_enabled();
         }
         self.counter
             .set(self.counter.get().deposit(shift, len, val));
@@ -787,11 +792,10 @@ fn decode(&self, mut addr: hwaddr, size: u32) -> HPETAddrDecode<'_> {
         } else {
             let timer_id: usize = ((addr - 0x100) / 0x20) as usize;
             if timer_id < self.num_timers {
-                // TODO: Add trace point - trace_hpet_ram_[read|write]_timer_id(timer_id)
                 TimerRegister::try_from(addr & 0x18)
                     .map(|reg| HPETRegister::Timer(&self.timers[timer_id], reg))
             } else {
-                // TODO: Add trace point -  trace_hpet_timer_id_out_of_range(timer_id)
+                trace::trace_hpet_timer_id_out_of_range(timer_id.try_into().unwrap());
                 Err(addr)
             }
         };
@@ -803,7 +807,8 @@ fn decode(&self, mut addr: hwaddr, size: u32) -> HPETAddrDecode<'_> {
     }
 
     fn read(&self, addr: hwaddr, size: u32) -> u64 {
-        // TODO: Add trace point - trace_hpet_ram_read(addr)
+        trace::trace_hpet_ram_read(addr);
+
         let HPETAddrDecode { shift, reg, .. } = self.decode(addr, size);
 
         use GlobalRegister::*;
@@ -814,16 +819,21 @@ fn read(&self, addr: hwaddr, size: u32) -> u64 {
             Global(CFG) => self.config.get(),
             Global(INT_STATUS) => self.int_status.get(),
             Global(COUNTER) => {
-                // TODO: Add trace point
-                // trace_hpet_ram_read_reading_counter(addr & 4, cur_tick)
-                if self.is_hpet_enabled() {
+                let cur_tick = if self.is_hpet_enabled() {
                     self.get_ticks()
                 } else {
                     self.counter.get()
-                }
+                };
+
+                trace::trace_hpet_ram_read_reading_counter(
+                    (addr & 4) as u8,
+                    cur_tick
+                );
+
+                cur_tick
             }
             Unknown(_) => {
-                // TODO: Add trace point- trace_hpet_ram_read_invalid()
+                trace::trace_hpet_ram_read_invalid();
                 0
             }
         }) >> shift
@@ -832,7 +842,8 @@ fn read(&self, addr: hwaddr, size: u32) -> u64 {
     fn write(&self, addr: hwaddr, value: u64, size: u32) {
         let HPETAddrDecode { shift, len, reg } = self.decode(addr, size);
 
-        // TODO: Add trace point - trace_hpet_ram_write(addr, value)
+        trace::trace_hpet_ram_write(addr, value);
+
         use GlobalRegister::*;
         use HPETRegister::*;
         match reg {
@@ -841,9 +852,7 @@ fn write(&self, addr: hwaddr, value: u64, size: u32) {
             Global(CFG) => self.set_cfg_reg(shift, len, value),
             Global(INT_STATUS) => self.set_int_status_reg(shift, len, value),
             Global(COUNTER) => self.set_counter_reg(shift, len, value),
-            Unknown(_) => {
-                // TODO: Add trace point - trace_hpet_ram_write_invalid()
-            }
+            Unknown(_) => trace::trace_hpet_ram_write_invalid(),
         }
     }
 
-- 
2.51.1



^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v2 3/4] subprojects: add probe crate
  2025-11-19 20:51 [PATCH v2 0/4] trace: add Rust DTrace/SystemTap SDT support Stefan Hajnoczi
  2025-11-19 20:51 ` [PATCH v2 1/4] hpet: remove unused trace events Stefan Hajnoczi
  2025-11-19 20:51 ` [PATCH v2 2/4] rust/hpet: add " Stefan Hajnoczi
@ 2025-11-19 20:51 ` Stefan Hajnoczi
  2025-11-19 20:52 ` [PATCH v2 4/4] tracetool: add Rust DTrace/SystemTap SDT support Stefan Hajnoczi
  2025-11-21 10:02 ` [PATCH v2 0/4] trace: " Paolo Bonzini
  4 siblings, 0 replies; 8+ messages in thread
From: Stefan Hajnoczi @ 2025-11-19 20:51 UTC (permalink / raw)
  To: qemu-devel
  Cc: Philippe Mathieu-Daudé, qemu-rust, Mads Ynddal, Thomas Huth,
	Manos Pitsidianakis, Alex Bennée, Paolo Bonzini, Josh Stone,
	Stefan Hajnoczi

The probe crate (https://crates.io/crates/probe) provides a probe!()
macro that defines SystemTap SDT probes on Linux hosts or does nothing
on other host OSes.

This crate will be used to implement DTrace support for Rust.

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 rust/meson.build                              |  2 ++
 scripts/archive-source.sh                     |  1 +
 scripts/make-release                          |  2 +-
 subprojects/.gitignore                        |  1 +
 .../packagefiles/probe-0.5-rs/meson.build     | 22 +++++++++++++++++++
 subprojects/probe-0.5-rs.wrap                 |  7 ++++++
 6 files changed, 34 insertions(+), 1 deletion(-)
 create mode 100644 subprojects/packagefiles/probe-0.5-rs/meson.build
 create mode 100644 subprojects/probe-0.5-rs.wrap

diff --git a/rust/meson.build b/rust/meson.build
index 76e10699b3..afbeeeb47a 100644
--- a/rust/meson.build
+++ b/rust/meson.build
@@ -4,6 +4,7 @@ subproject('bilge-impl-0.2-rs', required: true)
 subproject('foreign-0.3-rs', required: true)
 subproject('glib-sys-0.21-rs', required: true)
 subproject('libc-0.2-rs', required: true)
+subproject('probe-0.5-rs', required: true)
 
 anyhow_rs = dependency('anyhow-1-rs')
 bilge_rs = dependency('bilge-0.2-rs')
@@ -11,6 +12,7 @@ bilge_impl_rs = dependency('bilge-impl-0.2-rs')
 foreign_rs = dependency('foreign-0.3-rs')
 glib_sys_rs = dependency('glib-sys-0.21-rs')
 libc_rs = dependency('libc-0.2-rs')
+probe_rs = dependency('probe-0.5-rs')
 
 subproject('proc-macro2-1-rs', required: true)
 subproject('quote-1-rs', required: true)
diff --git a/scripts/archive-source.sh b/scripts/archive-source.sh
index 8f97b19a08..a37acab524 100755
--- a/scripts/archive-source.sh
+++ b/scripts/archive-source.sh
@@ -41,6 +41,7 @@ subprojects=(
   keycodemapdb
   libc-0.2-rs
   libvfio-user
+  probe-0.5-rs
   proc-macro-error-1-rs
   proc-macro-error-attr-1-rs
   proc-macro2-1-rs
diff --git a/scripts/make-release b/scripts/make-release
index bc1b43caa2..5f54b0e793 100755
--- a/scripts/make-release
+++ b/scripts/make-release
@@ -42,7 +42,7 @@ fi
 SUBPROJECTS="libvfio-user keycodemapdb berkeley-softfloat-3
   berkeley-testfloat-3 anyhow-1-rs arbitrary-int-1-rs attrs-0.2-rs bilge-0.2-rs
   bilge-impl-0.2-rs either-1-rs foreign-0.3-rs itertools-0.11-rs
-  libc-0.2-rs proc-macro2-1-rs
+  libc-0.2-rs probe-0.5-rs proc-macro2-1-rs
   proc-macro-error-1-rs proc-macro-error-attr-1-rs quote-1-rs
   syn-2-rs unicode-ident-1-rs"
 
diff --git a/subprojects/.gitignore b/subprojects/.gitignore
index c00c847837..011ce4dc3b 100644
--- a/subprojects/.gitignore
+++ b/subprojects/.gitignore
@@ -16,6 +16,7 @@
 /glib-sys-*
 /itertools-*
 /libc-*
+/probe-*
 /proc-macro-error-*
 /proc-macro-error-attr-*
 /proc-macro*
diff --git a/subprojects/packagefiles/probe-0.5-rs/meson.build b/subprojects/packagefiles/probe-0.5-rs/meson.build
new file mode 100644
index 0000000000..e6ea69533b
--- /dev/null
+++ b/subprojects/packagefiles/probe-0.5-rs/meson.build
@@ -0,0 +1,22 @@
+project('probe-0.5-rs', 'rust',
+  meson_version: '>=1.5.0',
+  version: '0.5.2',
+  license: 'Apache-2.0 OR MIT',
+  default_options: [])
+
+_probe_rs = static_library(
+  'probe',
+  files('src/lib.rs'),
+  gnu_symbol_visibility: 'hidden',
+  override_options: ['rust_std=2021', 'build.rust_std=2021'],
+  rust_abi: 'rust',
+  rust_args: [
+    '--cap-lints', 'allow',
+  ],
+)
+
+probe_deps = declare_dependency(
+  link_with: _probe_rs,
+)
+
+meson.override_dependency('probe-0.5-rs', probe_deps)
diff --git a/subprojects/probe-0.5-rs.wrap b/subprojects/probe-0.5-rs.wrap
new file mode 100644
index 0000000000..73229ee1c2
--- /dev/null
+++ b/subprojects/probe-0.5-rs.wrap
@@ -0,0 +1,7 @@
+[wrap-file]
+directory = probe-0.5.2
+source_url = https://crates.io/api/v1/crates/probe/0.5.2/download
+source_filename = probe-0.5.2.tar.gz
+source_hash = 136558b6e1ebaecc92755d0ffaf9421f519531bed30cc2ad23b22cb00965cc5e
+#method = cargo
+patch_directory = probe-0.5-rs
-- 
2.51.1



^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v2 4/4] tracetool: add Rust DTrace/SystemTap SDT support
  2025-11-19 20:51 [PATCH v2 0/4] trace: add Rust DTrace/SystemTap SDT support Stefan Hajnoczi
                   ` (2 preceding siblings ...)
  2025-11-19 20:51 ` [PATCH v2 3/4] subprojects: add probe crate Stefan Hajnoczi
@ 2025-11-19 20:52 ` Stefan Hajnoczi
  2025-11-21 10:02 ` [PATCH v2 0/4] trace: " Paolo Bonzini
  4 siblings, 0 replies; 8+ messages in thread
From: Stefan Hajnoczi @ 2025-11-19 20:52 UTC (permalink / raw)
  To: qemu-devel
  Cc: Philippe Mathieu-Daudé, qemu-rust, Mads Ynddal, Thomas Huth,
	Manos Pitsidianakis, Alex Bennée, Paolo Bonzini, Josh Stone,
	Stefan Hajnoczi

Implement DTrace/SystemTap SDT by emitting the following:
- The probe crate's probe!() macro is used to emit a DTrace/SystemTap
  SDT probe.
- Every trace event gets a corresponding trace_<name>_enabled() -> bool
  generated function that Rust code can use to avoid expensive
  computation when a trace event is disabled. This API works for other
  trace backends too.

`#[allow(dead_code)]` additions are necessary for QEMU's dstate in
generated trace-<dir>.rs files since they are unused by the dtrace
backend. `./configure --enable-trace-backends=` can enable multiple
backends, so keep it simple and just silence the warning instead of
trying to detect the condition when generating the dstate code can be
skipped.

The tracetool tests are updated. Take a look at
tests/tracetool/dtrace.rs to see what the new generated code looks like.

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 rust/Cargo.lock                     |  6 +++
 rust/trace/Cargo.toml               |  1 +
 rust/trace/meson.build              |  2 +-
 rust/trace/src/lib.rs               |  4 ++
 scripts/tracetool/__init__.py       |  1 +
 scripts/tracetool/backend/dtrace.py | 31 ++++++++++++++
 scripts/tracetool/format/rs.py      | 27 ++++++++++--
 tests/tracetool/dtrace.rs           | 65 +++++++++++++++++++++++++++++
 tests/tracetool/ftrace.rs           | 21 ++++++++++
 tests/tracetool/log.rs              | 21 ++++++++++
 tests/tracetool/simple.rs           | 21 ++++++++++
 tests/tracetool/syslog.rs           | 21 ++++++++++
 tests/tracetool/tracetool-test.py   |  2 +-
 13 files changed, 217 insertions(+), 6 deletions(-)
 create mode 100644 tests/tracetool/dtrace.rs

diff --git a/rust/Cargo.lock b/rust/Cargo.lock
index 0c1df625df..5bd768cb0d 100644
--- a/rust/Cargo.lock
+++ b/rust/Cargo.lock
@@ -144,6 +144,7 @@ dependencies = [
  "migration",
  "qom",
  "system",
+ "trace",
  "util",
 ]
 
@@ -229,6 +230,10 @@ dependencies = [
  "util",
 ]
 
+[[package]]
+name = "probe"
+version = "0.5.2"
+
 [[package]]
 name = "proc-macro-error"
 version = "1.0.4"
@@ -429,6 +434,7 @@ name = "trace"
 version = "0.1.0"
 dependencies = [
  "libc",
+ "probe",
 ]
 
 [[package]]
diff --git a/rust/trace/Cargo.toml b/rust/trace/Cargo.toml
index fc81bce580..11e27f8d28 100644
--- a/rust/trace/Cargo.toml
+++ b/rust/trace/Cargo.toml
@@ -14,6 +14,7 @@ rust-version.workspace = true
 
 [dependencies]
 libc = { workspace = true }
+probe = "0.5"
 
 [lints]
 workspace = true
diff --git a/rust/trace/meson.build b/rust/trace/meson.build
index adca57e550..cf6b0355a8 100644
--- a/rust/trace/meson.build
+++ b/rust/trace/meson.build
@@ -12,7 +12,7 @@ _trace_rs = static_library(
   lib_rs,
   trace_rs_targets,         # List of generated `.rs` custom targets
   override_options: ['rust_std=2021', 'build.rust_std=2021'],
-  dependencies: [libc_rs],
+  dependencies: [libc_rs, probe_rs],
   rust_abi: 'rust',
 )
 
diff --git a/rust/trace/src/lib.rs b/rust/trace/src/lib.rs
index e03bce43c4..49331f07c6 100644
--- a/rust/trace/src/lib.rs
+++ b/rust/trace/src/lib.rs
@@ -7,6 +7,10 @@
 /// Re-exported item to avoid adding libc as a dependency everywhere.
 pub use libc::{syslog, LOG_INFO};
 
+#[doc(hidden)]
+/// Re-exported item to avoid adding probe as a dependency everywhere.
+pub use probe::probe;
+
 #[macro_export]
 /// Define the trace-points from the named directory (which should have slashes
 /// replaced by underscore characters) as functions in a module called `trace`.
diff --git a/scripts/tracetool/__init__.py b/scripts/tracetool/__init__.py
index 74062d21a7..61ba6f1ba8 100644
--- a/scripts/tracetool/__init__.py
+++ b/scripts/tracetool/__init__.py
@@ -461,6 +461,7 @@ def formats(self):
 
     QEMU_TRACE               = "trace_%(name)s"
     QEMU_TRACE_TCG           = QEMU_TRACE + "_tcg"
+    QEMU_RUST_DSTATE         = "trace_%(name)s_enabled"
     QEMU_DSTATE              = "_TRACE_%(NAME)s_DSTATE"
     QEMU_BACKEND_DSTATE      = "TRACE_%(NAME)s_BACKEND_DSTATE"
     QEMU_EVENT               = "_TRACE_%(NAME)s_EVENT"
diff --git a/scripts/tracetool/backend/dtrace.py b/scripts/tracetool/backend/dtrace.py
index b4af403025..f0b58cc158 100644
--- a/scripts/tracetool/backend/dtrace.py
+++ b/scripts/tracetool/backend/dtrace.py
@@ -70,3 +70,34 @@ def generate_h(event, group):
 def generate_h_backend_dstate(event, group):
     out('    QEMU_%(uppername)s_ENABLED() || \\',
         uppername=event.name.upper())
+
+
+def generate_rs_begin(events, group):
+    out('use std::cell::UnsafeCell;',
+        '',
+        'extern "C" {')
+    # These are the Rust declarations of the .probes section semaphores
+    # generated by dtrace(1) in its .o file output.
+    for e in events:
+        if 'disable' in e.properties:
+            continue
+        out('    #[allow(dead_code)]',
+            f'    static qemu_{e.name}_semaphore: UnsafeCell<u16>;')
+    out('}',
+        '')
+
+
+def generate_rs(event, group):
+    args = event.args.rust_call_extern()
+    if args:
+        args = ', ' + args
+
+    out(f'    ::trace::probe!(qemu, {event.name}{args});')
+
+
+def generate_rs_backend_dstate(event, group):
+    # Rust does not have access to the <provider>_<name>_ENABLED() macro from
+    # the dtrace(1) generated .h file. Use the matching semaphore declarations
+    # generated by generate_rs_begin() instead.
+    out('    (unsafe {qemu_%(n)s_semaphore.get().read_volatile()}) != 0 ||',
+        n=event.name)
diff --git a/scripts/tracetool/format/rs.py b/scripts/tracetool/format/rs.py
index 32ac4e5977..7d9af7edfe 100644
--- a/scripts/tracetool/format/rs.py
+++ b/scripts/tracetool/format/rs.py
@@ -24,25 +24,43 @@ def generate(events, backend, group):
         '#[allow(unused_imports)]',
         'use util::bindings;',
         '',
+        '#[allow(dead_code)]',
         '#[inline(always)]',
         'fn trace_event_state_is_enabled(dstate: u16) -> bool {',
         '    (unsafe { trace_events_enabled_count }) != 0 && dstate != 0',
         '}',
         '',
         'extern "C" {',
+        '    #[allow(dead_code)]',
         '    static mut trace_events_enabled_count: u32;',
         '}',)
 
     out('extern "C" {')
 
     for e in events:
-        out('    static mut %s: u16;' % e.api(e.QEMU_DSTATE))
-    out('}')
+        out('    #[allow(dead_code)]',
+            '    static mut %s: u16;' % e.api(e.QEMU_DSTATE))
+    out('}',
+        '')
 
     backend.generate_begin(events, group)
 
     for e in events:
-        out('',
+        out('#[inline(always)]',
+            '#[allow(dead_code)]',
+            'pub fn %(api)s() -> bool',
+            '{',
+            api=e.api(e.QEMU_RUST_DSTATE))
+
+        if "disable" not in e.properties:
+            backend.generate_backend_dstate(e, group)
+            if backend.check_trace_event_get_state:
+                out('    trace_event_state_is_enabled(unsafe { _%(event_id)s_DSTATE}) ||',
+                    event_id = 'TRACE_' + e.name.upper())
+
+        out('    false',
+            '}',
+            '',
             '#[inline(always)]',
             '#[allow(dead_code)]',
             'pub fn %(api)s(%(args)s)',
@@ -59,6 +77,7 @@ def generate(events, backend, group):
                     api=e.api())
                 backend.generate(e, group, check_trace_event_get_state=True)
                 out('    }')
-        out('}')
+        out('}',
+            '')
 
     backend.generate_end(events, group)
diff --git a/tests/tracetool/dtrace.rs b/tests/tracetool/dtrace.rs
new file mode 100644
index 0000000000..233c2ef159
--- /dev/null
+++ b/tests/tracetool/dtrace.rs
@@ -0,0 +1,65 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+// This file is @generated by tracetool, do not edit.
+
+#[allow(unused_imports)]
+use std::ffi::c_char;
+#[allow(unused_imports)]
+use util::bindings;
+
+#[allow(dead_code)]
+#[inline(always)]
+fn trace_event_state_is_enabled(dstate: u16) -> bool {
+    (unsafe { trace_events_enabled_count }) != 0 && dstate != 0
+}
+
+extern "C" {
+    #[allow(dead_code)]
+    static mut trace_events_enabled_count: u32;
+}
+extern "C" {
+    #[allow(dead_code)]
+    static mut _TRACE_TEST_BLAH_DSTATE: u16;
+    #[allow(dead_code)]
+    static mut _TRACE_TEST_WIBBLE_DSTATE: u16;
+}
+
+use probe::probe;
+use std::cell::UnsafeCell;
+
+extern "C" {
+    #[allow(dead_code)]
+    static qemu_test_blah_semaphore: UnsafeCell<u16>;
+    #[allow(dead_code)]
+    static qemu_test_wibble_semaphore: UnsafeCell<u16>;
+}
+
+#[inline(always)]
+#[allow(dead_code)]
+pub fn trace_test_blah_enabled() -> bool
+{
+    (unsafe {qemu_test_blah_semaphore.get().read_volatile()}) != 0 ||
+    false
+}
+
+#[inline(always)]
+#[allow(dead_code)]
+pub fn trace_test_blah(_context: *mut (), _filename: &std::ffi::CStr)
+{
+    probe!(qemu, test_blah, _context, _filename.as_ptr());
+}
+
+#[inline(always)]
+#[allow(dead_code)]
+pub fn trace_test_wibble_enabled() -> bool
+{
+    (unsafe {qemu_test_wibble_semaphore.get().read_volatile()}) != 0 ||
+    false
+}
+
+#[inline(always)]
+#[allow(dead_code)]
+pub fn trace_test_wibble(_context: *mut (), _value: std::ffi::c_int)
+{
+    probe!(qemu, test_wibble, _context, _value);
+}
+
diff --git a/tests/tracetool/ftrace.rs b/tests/tracetool/ftrace.rs
index 07b9259cf2..34f6600490 100644
--- a/tests/tracetool/ftrace.rs
+++ b/tests/tracetool/ftrace.rs
@@ -6,19 +6,31 @@
 #[allow(unused_imports)]
 use util::bindings;
 
+#[allow(dead_code)]
 #[inline(always)]
 fn trace_event_state_is_enabled(dstate: u16) -> bool {
     (unsafe { trace_events_enabled_count }) != 0 && dstate != 0
 }
 
 extern "C" {
+    #[allow(dead_code)]
     static mut trace_events_enabled_count: u32;
 }
 extern "C" {
+    #[allow(dead_code)]
     static mut _TRACE_TEST_BLAH_DSTATE: u16;
+    #[allow(dead_code)]
     static mut _TRACE_TEST_WIBBLE_DSTATE: u16;
 }
 
+#[inline(always)]
+#[allow(dead_code)]
+pub fn trace_test_blah_enabled() -> bool
+{
+    trace_event_state_is_enabled(unsafe { _TRACE_TEST_BLAH_DSTATE}) ||
+    false
+}
+
 #[inline(always)]
 #[allow(dead_code)]
 pub fn trace_test_blah(_context: *mut (), _filename: &std::ffi::CStr)
@@ -29,6 +41,14 @@ pub fn trace_test_blah(_context: *mut (), _filename: &std::ffi::CStr)
     }
 }
 
+#[inline(always)]
+#[allow(dead_code)]
+pub fn trace_test_wibble_enabled() -> bool
+{
+    trace_event_state_is_enabled(unsafe { _TRACE_TEST_WIBBLE_DSTATE}) ||
+    false
+}
+
 #[inline(always)]
 #[allow(dead_code)]
 pub fn trace_test_wibble(_context: *mut (), _value: std::ffi::c_int)
@@ -38,3 +58,4 @@ pub fn trace_test_wibble(_context: *mut (), _value: std::ffi::c_int)
         unsafe {bindings::ftrace_write(format_string.as_ptr() as *const c_char, _context /* as *mut () */, _value /* as std::ffi::c_int */);}
     }
 }
+
diff --git a/tests/tracetool/log.rs b/tests/tracetool/log.rs
index c191895c8f..770758611d 100644
--- a/tests/tracetool/log.rs
+++ b/tests/tracetool/log.rs
@@ -6,19 +6,31 @@
 #[allow(unused_imports)]
 use util::bindings;
 
+#[allow(dead_code)]
 #[inline(always)]
 fn trace_event_state_is_enabled(dstate: u16) -> bool {
     (unsafe { trace_events_enabled_count }) != 0 && dstate != 0
 }
 
 extern "C" {
+    #[allow(dead_code)]
     static mut trace_events_enabled_count: u32;
 }
 extern "C" {
+    #[allow(dead_code)]
     static mut _TRACE_TEST_BLAH_DSTATE: u16;
+    #[allow(dead_code)]
     static mut _TRACE_TEST_WIBBLE_DSTATE: u16;
 }
 
+#[inline(always)]
+#[allow(dead_code)]
+pub fn trace_test_blah_enabled() -> bool
+{
+    trace_event_state_is_enabled(unsafe { _TRACE_TEST_BLAH_DSTATE}) ||
+    false
+}
+
 #[inline(always)]
 #[allow(dead_code)]
 pub fn trace_test_blah(_context: *mut (), _filename: &std::ffi::CStr)
@@ -31,6 +43,14 @@ pub fn trace_test_blah(_context: *mut (), _filename: &std::ffi::CStr)
     }
 }
 
+#[inline(always)]
+#[allow(dead_code)]
+pub fn trace_test_wibble_enabled() -> bool
+{
+    trace_event_state_is_enabled(unsafe { _TRACE_TEST_WIBBLE_DSTATE}) ||
+    false
+}
+
 #[inline(always)]
 #[allow(dead_code)]
 pub fn trace_test_wibble(_context: *mut (), _value: std::ffi::c_int)
@@ -42,3 +62,4 @@ pub fn trace_test_wibble(_context: *mut (), _value: std::ffi::c_int)
         }
     }
 }
+
diff --git a/tests/tracetool/simple.rs b/tests/tracetool/simple.rs
index 9ee39495e3..92f896ef17 100644
--- a/tests/tracetool/simple.rs
+++ b/tests/tracetool/simple.rs
@@ -6,19 +6,31 @@
 #[allow(unused_imports)]
 use util::bindings;
 
+#[allow(dead_code)]
 #[inline(always)]
 fn trace_event_state_is_enabled(dstate: u16) -> bool {
     (unsafe { trace_events_enabled_count }) != 0 && dstate != 0
 }
 
 extern "C" {
+    #[allow(dead_code)]
     static mut trace_events_enabled_count: u32;
 }
 extern "C" {
+    #[allow(dead_code)]
     static mut _TRACE_TEST_BLAH_DSTATE: u16;
+    #[allow(dead_code)]
     static mut _TRACE_TEST_WIBBLE_DSTATE: u16;
 }
 
+#[inline(always)]
+#[allow(dead_code)]
+pub fn trace_test_blah_enabled() -> bool
+{
+    trace_event_state_is_enabled(unsafe { _TRACE_TEST_BLAH_DSTATE}) ||
+    false
+}
+
 #[inline(always)]
 #[allow(dead_code)]
 pub fn trace_test_blah(_context: *mut (), _filename: &std::ffi::CStr)
@@ -29,6 +41,14 @@ pub fn trace_test_blah(_context: *mut (), _filename: &std::ffi::CStr)
     }
 }
 
+#[inline(always)]
+#[allow(dead_code)]
+pub fn trace_test_wibble_enabled() -> bool
+{
+    trace_event_state_is_enabled(unsafe { _TRACE_TEST_WIBBLE_DSTATE}) ||
+    false
+}
+
 #[inline(always)]
 #[allow(dead_code)]
 pub fn trace_test_wibble(_context: *mut (), _value: std::ffi::c_int)
@@ -38,3 +58,4 @@ pub fn trace_test_wibble(_context: *mut (), _value: std::ffi::c_int)
         unsafe { _simple_trace_test_wibble(_context, _value); }
     }
 }
+
diff --git a/tests/tracetool/syslog.rs b/tests/tracetool/syslog.rs
index 9d3675a0b5..378d03d34b 100644
--- a/tests/tracetool/syslog.rs
+++ b/tests/tracetool/syslog.rs
@@ -6,19 +6,31 @@
 #[allow(unused_imports)]
 use util::bindings;
 
+#[allow(dead_code)]
 #[inline(always)]
 fn trace_event_state_is_enabled(dstate: u16) -> bool {
     (unsafe { trace_events_enabled_count }) != 0 && dstate != 0
 }
 
 extern "C" {
+    #[allow(dead_code)]
     static mut trace_events_enabled_count: u32;
 }
 extern "C" {
+    #[allow(dead_code)]
     static mut _TRACE_TEST_BLAH_DSTATE: u16;
+    #[allow(dead_code)]
     static mut _TRACE_TEST_WIBBLE_DSTATE: u16;
 }
 
+#[inline(always)]
+#[allow(dead_code)]
+pub fn trace_test_blah_enabled() -> bool
+{
+    trace_event_state_is_enabled(unsafe { _TRACE_TEST_BLAH_DSTATE}) ||
+    false
+}
+
 #[inline(always)]
 #[allow(dead_code)]
 pub fn trace_test_blah(_context: *mut (), _filename: &std::ffi::CStr)
@@ -29,6 +41,14 @@ pub fn trace_test_blah(_context: *mut (), _filename: &std::ffi::CStr)
     }
 }
 
+#[inline(always)]
+#[allow(dead_code)]
+pub fn trace_test_wibble_enabled() -> bool
+{
+    trace_event_state_is_enabled(unsafe { _TRACE_TEST_WIBBLE_DSTATE}) ||
+    false
+}
+
 #[inline(always)]
 #[allow(dead_code)]
 pub fn trace_test_wibble(_context: *mut (), _value: std::ffi::c_int)
@@ -38,3 +58,4 @@ pub fn trace_test_wibble(_context: *mut (), _value: std::ffi::c_int)
         unsafe {::trace::syslog(::trace::LOG_INFO, format_string.as_ptr() as *const c_char, _context /* as *mut () */, _value /* as std::ffi::c_int */);}
     }
 }
+
diff --git a/tests/tracetool/tracetool-test.py b/tests/tracetool/tracetool-test.py
index 786083ad7f..30006a9919 100755
--- a/tests/tracetool/tracetool-test.py
+++ b/tests/tracetool/tracetool-test.py
@@ -14,7 +14,7 @@ def get_formats(backend):
         "c",
         "h",
     ]
-    if backend in {"ftrace", "log", "simple", "syslog"}:
+    if backend in {"dtrace", "ftrace", "log", "simple", "syslog"}:
         formats += ["rs"]
     if backend == "dtrace":
         formats += [
-- 
2.51.1



^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH v2 2/4] rust/hpet: add trace events
  2025-11-19 20:51 ` [PATCH v2 2/4] rust/hpet: add " Stefan Hajnoczi
@ 2025-11-20 14:49   ` Zhao Liu
  0 siblings, 0 replies; 8+ messages in thread
From: Zhao Liu @ 2025-11-20 14:49 UTC (permalink / raw)
  To: Stefan Hajnoczi
  Cc: qemu-devel, Philippe Mathieu-Daudé, qemu-rust, Mads Ynddal,
	Thomas Huth, Manos Pitsidianakis, Alex Bennée, Paolo Bonzini,
	Josh Stone

On Wed, Nov 19, 2025 at 03:51:58PM -0500, Stefan Hajnoczi wrote:
> Date: Wed, 19 Nov 2025 15:51:58 -0500
> From: Stefan Hajnoczi <stefanha@redhat.com>
> Subject: [PATCH v2 2/4] rust/hpet: add trace events
> 
> Implement the same trace events as the C implementation.
> 
> Notes:
> - Keep order of hpet_ram_write_invalid_tn_cmp and hpet_ram_write_tn_cmp
>   the same as the C implementation.
> - Put hpet_ram_write_timer_id in HPETTimer::write() instead of
>   HPETState::decode() so that reads can be excluded.

Yes, these changes are accurate and clear.

> Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
> ---
>  rust/hw/timer/hpet/Cargo.toml    |  1 +
>  rust/hw/timer/hpet/meson.build   |  1 +
>  rust/hw/timer/hpet/src/device.rs | 45 +++++++++++++++++++-------------
>  3 files changed, 29 insertions(+), 18 deletions(-)

Reviewed-by: Zhao Liu <zhao1.liu@intel.com>



^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v2 1/4] hpet: remove unused trace events
  2025-11-19 20:51 ` [PATCH v2 1/4] hpet: remove unused trace events Stefan Hajnoczi
@ 2025-11-20 14:49   ` Zhao Liu
  0 siblings, 0 replies; 8+ messages in thread
From: Zhao Liu @ 2025-11-20 14:49 UTC (permalink / raw)
  To: Stefan Hajnoczi
  Cc: qemu-devel, Philippe Mathieu-Daudé, qemu-rust, Mads Ynddal,
	Thomas Huth, Manos Pitsidianakis, Alex Bennée, Paolo Bonzini,
	Josh Stone

On Wed, Nov 19, 2025 at 03:51:57PM -0500, Stefan Hajnoczi wrote:
> Date: Wed, 19 Nov 2025 15:51:57 -0500
> From: Stefan Hajnoczi <stefanha@redhat.com>
> Subject: [PATCH v2 1/4] hpet: remove unused trace events
> 
> Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
> ---
>  hw/timer/trace-events | 2 --
>  1 file changed, 2 deletions(-)

Reviewed-by: Zhao Liu <zhao1.liu@intel.com>



^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v2 0/4] trace: add Rust DTrace/SystemTap SDT support
  2025-11-19 20:51 [PATCH v2 0/4] trace: add Rust DTrace/SystemTap SDT support Stefan Hajnoczi
                   ` (3 preceding siblings ...)
  2025-11-19 20:52 ` [PATCH v2 4/4] tracetool: add Rust DTrace/SystemTap SDT support Stefan Hajnoczi
@ 2025-11-21 10:02 ` Paolo Bonzini
  4 siblings, 0 replies; 8+ messages in thread
From: Paolo Bonzini @ 2025-11-21 10:02 UTC (permalink / raw)
  To: Stefan Hajnoczi
  Cc: qemu-devel, Philippe Mathieu-Daudé, qemu-rust, Mads Ynddal,
	Thomas Huth, Manos Pitsidianakis, Alex Bennée, Josh Stone

> v2:
> - Re-export probe::probe!() from the trace crate to avoid the explicit probe
>   crate dependency from hpet, pl011, etc. [Paolo]

Queued to rust-next, thanks.

Paolo



^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2025-11-21 10:05 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-11-19 20:51 [PATCH v2 0/4] trace: add Rust DTrace/SystemTap SDT support Stefan Hajnoczi
2025-11-19 20:51 ` [PATCH v2 1/4] hpet: remove unused trace events Stefan Hajnoczi
2025-11-20 14:49   ` Zhao Liu
2025-11-19 20:51 ` [PATCH v2 2/4] rust/hpet: add " Stefan Hajnoczi
2025-11-20 14:49   ` Zhao Liu
2025-11-19 20:51 ` [PATCH v2 3/4] subprojects: add probe crate Stefan Hajnoczi
2025-11-19 20:52 ` [PATCH v2 4/4] tracetool: add Rust DTrace/SystemTap SDT support Stefan Hajnoczi
2025-11-21 10:02 ` [PATCH v2 0/4] trace: " Paolo Bonzini

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).