Pull request
Tanish Desai and Paolo Bonzini's tracing Rust support. -----BEGIN PGP SIGNATURE----- iQEzBAABCgAdFiEEhpWov9P5fNqsNXdanKSrs4Grc8gFAmjdSSIACgkQnKSrs4Gr c8h8hwf/RXawMzImGn3I2kTOUWAQ97+yY0UgtyO010K71gypBa2EBcPIVH0ZOsy0 oT5pF2w7k0g83DXqupXiZO3yjSSmeGBXlOw8QS6D+FN0VpsdxrYJnvzVMqCckOrR 6wwM+fYYfCk/LwQFvjcMDdd6BSB/wUyMuBnh+fa8X9vxRL6CgMY7RpQd7YZ9JNtL PFQscu/K6zUARxwQ/DZTx5jYlW4rE5O4mq80CW2l1pgnyOH5vH/TySTKp0yX8eDO 5eoF7ttieOxxt6YobFak7EfWFvFuyp1j5NlWlyWKzhce1oSOAbaXnB1I61admRb3 7XrsTU0RjH6kp8ki4SZEoAh/HMw+4w== =myWt -----END PGP SIGNATURE----- Merge tag 'tracing-pull-request' of https://gitlab.com/stefanha/qemu into staging Pull request Tanish Desai and Paolo Bonzini's tracing Rust support. # -----BEGIN PGP SIGNATURE----- # # iQEzBAABCgAdFiEEhpWov9P5fNqsNXdanKSrs4Grc8gFAmjdSSIACgkQnKSrs4Gr # c8h8hwf/RXawMzImGn3I2kTOUWAQ97+yY0UgtyO010K71gypBa2EBcPIVH0ZOsy0 # oT5pF2w7k0g83DXqupXiZO3yjSSmeGBXlOw8QS6D+FN0VpsdxrYJnvzVMqCckOrR # 6wwM+fYYfCk/LwQFvjcMDdd6BSB/wUyMuBnh+fa8X9vxRL6CgMY7RpQd7YZ9JNtL # PFQscu/K6zUARxwQ/DZTx5jYlW4rE5O4mq80CW2l1pgnyOH5vH/TySTKp0yX8eDO # 5eoF7ttieOxxt6YobFak7EfWFvFuyp1j5NlWlyWKzhce1oSOAbaXnB1I61admRb3 # 7XrsTU0RjH6kp8ki4SZEoAh/HMw+4w== # =myWt # -----END PGP SIGNATURE----- # gpg: Signature made Wed 01 Oct 2025 08:30:42 AM PDT # gpg: using RSA key 8695A8BFD3F97CDAAC35775A9CA4ABB381AB73C8 # gpg: Good signature from "Stefan Hajnoczi <stefanha@redhat.com>" [unknown] # gpg: aka "Stefan Hajnoczi <stefanha@gmail.com>" [unknown] # gpg: WARNING: This key is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # Primary key fingerprint: 8695 A8BF D3F9 7CDA AC35 775A 9CA4 ABB3 81AB 73C8 * tag 'tracing-pull-request' of https://gitlab.com/stefanha/qemu: tracetool/syslog: add Rust support tracetool/ftrace: add Rust support tracetool/log: add Rust support log: change qemu_loglevel to unsigned tracetool/simple: add Rust support rust: pl011: add tracepoints rust: qdev: add minimal clock bindings rust: add trace crate tracetool: Add Rust format support tracetool/backend: remove redundant trace event checks tracetool: add CHECK_TRACE_EVENT_GET_STATE trace/ftrace: move snprintf+write from tracepoints to ftrace.c tracetool: add SPDX headers treewide: remove unnessary "coding" header tracetool: remove dead code tracetool: fix usage of try_import() Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
commit
1abdde1ad4
62 changed files with 720 additions and 223 deletions
|
|
@ -1,5 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# QEMU documentation build configuration file, created by
|
||||
# sphinx-quickstart on Thu Jan 31 16:40:14 2019.
|
||||
#
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
/* -*- coding: utf-8; mode: css -*-
|
||||
*
|
||||
/*
|
||||
* Sphinx HTML theme customization: read the doc
|
||||
* Based on Linux Documentation/sphinx-static/theme_overrides.css
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -58,15 +58,15 @@ imx_serial_write(const char *chrname, uint64_t addr, uint64_t value) "%s:[0x%03"
|
|||
imx_serial_put_data(const char *chrname, uint32_t value) "%s: 0x%" PRIx32
|
||||
|
||||
# pl011.c
|
||||
pl011_irq_state(int level) "irq state %d"
|
||||
pl011_read(uint32_t addr, uint32_t value, const char *regname) "addr 0x%03x value 0x%08x reg %s"
|
||||
pl011_read_fifo(unsigned rx_fifo_used, size_t rx_fifo_depth) "RX FIFO read, used %u/%zu"
|
||||
pl011_write(uint32_t addr, uint32_t value, const char *regname) "addr 0x%03x value 0x%08x reg %s"
|
||||
pl011_can_receive(uint32_t lcr, unsigned rx_fifo_used, size_t rx_fifo_depth, unsigned rx_fifo_available) "LCR 0x%02x, RX FIFO used %u/%zu, can_receive %u chars"
|
||||
pl011_fifo_rx_put(uint32_t c, unsigned read_count, size_t rx_fifo_depth) "RX FIFO push char [0x%02x] %d/%zu depth used"
|
||||
pl011_irq_state(bool level) "irq state %d"
|
||||
pl011_read(uint64_t addr, uint32_t value, const char *regname) "addr 0x%03" PRIx64 " value 0x%08x reg %s"
|
||||
pl011_read_fifo(unsigned rx_fifo_used, unsigned rx_fifo_depth) "RX FIFO read, used %u/%u"
|
||||
pl011_write(uint64_t addr, uint32_t value, const char *regname) "addr 0x%03" PRIx64 " value 0x%08x reg %s"
|
||||
pl011_can_receive(uint32_t lcr, unsigned rx_fifo_used, unsigned rx_fifo_depth, unsigned rx_fifo_available) "LCR 0x%02x, RX FIFO used %u/%u, can_receive %u chars"
|
||||
pl011_fifo_rx_put(uint32_t c, unsigned read_count, unsigned rx_fifo_depth) "RX FIFO push char [0x%02x] %d/%u depth used"
|
||||
pl011_fifo_rx_full(void) "RX FIFO now full, RXFF set"
|
||||
pl011_baudrate_change(unsigned int baudrate, uint64_t clock, uint32_t ibrd, uint32_t fbrd) "new baudrate %u (clk: %" PRIu64 "hz, ibrd: %" PRIu32 ", fbrd: %" PRIu32 ")"
|
||||
pl011_receive(int size) "recv %d chars"
|
||||
pl011_receive(size_t size) "recv %zd chars"
|
||||
|
||||
# cmsdk-apb-uart.c
|
||||
cmsdk_apb_uart_read(uint64_t offset, uint64_t data, unsigned size) "CMSDK APB UART read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
|
||||
|
|
|
|||
|
|
@ -19,9 +19,9 @@
|
|||
#define QEMU_LOG_FOR_TRACE_H
|
||||
|
||||
/* Private global variable, don't use */
|
||||
extern int qemu_loglevel;
|
||||
extern unsigned qemu_loglevel;
|
||||
|
||||
#define LOG_TRACE (1 << 15)
|
||||
#define LOG_TRACE (1u << 15)
|
||||
|
||||
/* Returns true if a bit is set in the current loglevel mask */
|
||||
static inline bool qemu_loglevel_mask(int mask)
|
||||
|
|
|
|||
|
|
@ -14,30 +14,30 @@ bool qemu_log_enabled(void);
|
|||
/* Returns true if qemu_log() will write somewhere other than stderr. */
|
||||
bool qemu_log_separate(void);
|
||||
|
||||
#define CPU_LOG_TB_OUT_ASM (1 << 0)
|
||||
#define CPU_LOG_TB_IN_ASM (1 << 1)
|
||||
#define CPU_LOG_TB_OP (1 << 2)
|
||||
#define CPU_LOG_TB_OP_OPT (1 << 3)
|
||||
#define CPU_LOG_INT (1 << 4)
|
||||
#define CPU_LOG_EXEC (1 << 5)
|
||||
#define CPU_LOG_PCALL (1 << 6)
|
||||
#define CPU_LOG_TB_CPU (1 << 8)
|
||||
#define CPU_LOG_RESET (1 << 9)
|
||||
#define LOG_UNIMP (1 << 10)
|
||||
#define LOG_GUEST_ERROR (1 << 11)
|
||||
#define CPU_LOG_MMU (1 << 12)
|
||||
#define CPU_LOG_TB_NOCHAIN (1 << 13)
|
||||
#define CPU_LOG_PAGE (1 << 14)
|
||||
#define CPU_LOG_TB_OUT_ASM (1u << 0)
|
||||
#define CPU_LOG_TB_IN_ASM (1u << 1)
|
||||
#define CPU_LOG_TB_OP (1u << 2)
|
||||
#define CPU_LOG_TB_OP_OPT (1u << 3)
|
||||
#define CPU_LOG_INT (1u << 4)
|
||||
#define CPU_LOG_EXEC (1u << 5)
|
||||
#define CPU_LOG_PCALL (1u << 6)
|
||||
#define CPU_LOG_TB_CPU (1u << 8)
|
||||
#define CPU_LOG_RESET (1u << 9)
|
||||
#define LOG_UNIMP (1u << 10)
|
||||
#define LOG_GUEST_ERROR (1u << 11)
|
||||
#define CPU_LOG_MMU (1u << 12)
|
||||
#define CPU_LOG_TB_NOCHAIN (1u << 13)
|
||||
#define CPU_LOG_PAGE (1u << 14)
|
||||
/* LOG_TRACE (1 << 15) is defined in log-for-trace.h */
|
||||
#define CPU_LOG_TB_OP_IND (1 << 16)
|
||||
#define CPU_LOG_TB_FPU (1 << 17)
|
||||
#define CPU_LOG_PLUGIN (1 << 18)
|
||||
#define CPU_LOG_TB_OP_IND (1u << 16)
|
||||
#define CPU_LOG_TB_FPU (1u << 17)
|
||||
#define CPU_LOG_PLUGIN (1u << 18)
|
||||
/* LOG_STRACE is used for user-mode strace logging. */
|
||||
#define LOG_STRACE (1 << 19)
|
||||
#define LOG_PER_THREAD (1 << 20)
|
||||
#define CPU_LOG_TB_VPU (1 << 21)
|
||||
#define LOG_TB_OP_PLUGIN (1 << 22)
|
||||
#define LOG_INVALID_MEM (1 << 23)
|
||||
#define LOG_STRACE (1u << 19)
|
||||
#define LOG_PER_THREAD (1u << 20)
|
||||
#define CPU_LOG_TB_VPU (1u << 21)
|
||||
#define LOG_TB_OP_PLUGIN (1u << 22)
|
||||
#define LOG_INVALID_MEM (1u << 23)
|
||||
|
||||
/* Lock/unlock output. */
|
||||
|
||||
|
|
|
|||
8
rust/Cargo.lock
generated
8
rust/Cargo.lock
generated
|
|
@ -159,6 +159,7 @@ dependencies = [
|
|||
"migration",
|
||||
"qom",
|
||||
"system",
|
||||
"trace",
|
||||
"util",
|
||||
]
|
||||
|
||||
|
|
@ -258,6 +259,13 @@ dependencies = [
|
|||
"util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "trace"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.12"
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ members = [
|
|||
"hw/core",
|
||||
"hw/char/pl011",
|
||||
"hw/timer/hpet",
|
||||
"trace",
|
||||
"util",
|
||||
"tests",
|
||||
]
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ qom = { path = "../../../qom" }
|
|||
chardev = { path = "../../../chardev" }
|
||||
system = { path = "../../../system" }
|
||||
hwcore = { path = "../../../hw/core" }
|
||||
trace = { path = "../../../trace" }
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ _libpl011_rs = static_library(
|
|||
chardev_rs,
|
||||
system_rs,
|
||||
hwcore_rs,
|
||||
trace_rs
|
||||
],
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@ use util::{log::Log, log_mask_ln};
|
|||
|
||||
use crate::registers::{self, Interrupt, RegisterOffset};
|
||||
|
||||
::trace::include_trace!("hw_char");
|
||||
|
||||
// TODO: You must disable the UART before any of the control registers are
|
||||
// reprogrammed. When the UART is disabled in the middle of transmission or
|
||||
// reception, it completes the current character before stopping
|
||||
|
|
@ -208,13 +210,7 @@ impl PL011Registers {
|
|||
(update, result)
|
||||
}
|
||||
|
||||
pub(self) fn write(
|
||||
&mut self,
|
||||
offset: RegisterOffset,
|
||||
value: u32,
|
||||
char_backend: &CharBackend,
|
||||
) -> bool {
|
||||
// eprintln!("write offset {offset} value {value}");
|
||||
pub(self) fn write(&mut self, offset: RegisterOffset, value: u32, device: &PL011State) -> bool {
|
||||
use RegisterOffset::*;
|
||||
match offset {
|
||||
DR => return self.write_data_register(value),
|
||||
|
|
@ -229,9 +225,11 @@ impl PL011Registers {
|
|||
}
|
||||
IBRD => {
|
||||
self.ibrd = value;
|
||||
device.trace_baudrate_change(self.ibrd, self.fbrd);
|
||||
}
|
||||
FBRD => {
|
||||
self.fbrd = value;
|
||||
device.trace_baudrate_change(self.ibrd, self.fbrd);
|
||||
}
|
||||
LCR_H => {
|
||||
let new_val: registers::LineControl = value.into();
|
||||
|
|
@ -242,7 +240,7 @@ impl PL011Registers {
|
|||
}
|
||||
let update = (self.line_control.send_break() != new_val.send_break()) && {
|
||||
let break_enable = new_val.send_break();
|
||||
let _ = char_backend.send_break(break_enable);
|
||||
let _ = device.char_backend.send_break(break_enable);
|
||||
self.loopback_break(break_enable)
|
||||
};
|
||||
self.line_control = new_val;
|
||||
|
|
@ -279,12 +277,13 @@ impl PL011Registers {
|
|||
}
|
||||
|
||||
fn read_data_register(&mut self, update: &mut bool) -> u32 {
|
||||
let depth = self.fifo_depth();
|
||||
self.flags.set_receive_fifo_full(false);
|
||||
let c = self.read_fifo[self.read_pos];
|
||||
|
||||
if self.read_count > 0 {
|
||||
self.read_count -= 1;
|
||||
self.read_pos = (self.read_pos + 1) & (self.fifo_depth() - 1);
|
||||
self.read_pos = (self.read_pos + 1) & (depth - 1);
|
||||
}
|
||||
if self.read_count == 0 {
|
||||
self.flags.set_receive_fifo_empty(true);
|
||||
|
|
@ -292,6 +291,7 @@ impl PL011Registers {
|
|||
if self.read_count + 1 == self.read_trigger {
|
||||
self.int_level &= !Interrupt::RX;
|
||||
}
|
||||
trace::trace_pl011_read_fifo(self.read_count, depth);
|
||||
self.receive_status_error_clear.set_from_data(c);
|
||||
*update = true;
|
||||
u32::from(c)
|
||||
|
|
@ -447,7 +447,9 @@ impl PL011Registers {
|
|||
self.read_fifo[slot] = value;
|
||||
self.read_count += 1;
|
||||
self.flags.set_receive_fifo_empty(false);
|
||||
trace::trace_pl011_fifo_rx_put(value.into(), self.read_count, depth);
|
||||
if self.read_count == depth {
|
||||
trace::trace_pl011_fifo_rx_full();
|
||||
self.flags.set_receive_fifo_full(true);
|
||||
}
|
||||
|
||||
|
|
@ -516,8 +518,21 @@ impl PL011State {
|
|||
uninit_field_mut!(*this, clock).write(clock);
|
||||
}
|
||||
|
||||
const fn clock_update(&self, _event: ClockEvent) {
|
||||
/* pl011_trace_baudrate_change(s); */
|
||||
pub fn trace_baudrate_change(&self, ibrd: u32, fbrd: u32) {
|
||||
let divider = 4.0 / f64::from(ibrd * (FBRD_MASK + 1) + fbrd);
|
||||
let hz = self.clock.hz();
|
||||
let rate = if ibrd == 0 {
|
||||
0
|
||||
} else {
|
||||
((hz as f64) * divider) as u32
|
||||
};
|
||||
trace::trace_pl011_baudrate_change(rate, hz, ibrd, fbrd);
|
||||
}
|
||||
|
||||
fn clock_update(&self, _event: ClockEvent) {
|
||||
let regs = self.regs.borrow();
|
||||
let (ibrd, fbrd) = (regs.ibrd, regs.fbrd);
|
||||
self.trace_baudrate_change(ibrd, fbrd)
|
||||
}
|
||||
|
||||
pub fn clock_needed(&self) -> bool {
|
||||
|
|
@ -543,6 +558,7 @@ impl PL011State {
|
|||
}
|
||||
Ok(field) => {
|
||||
let (update_irq, result) = self.regs.borrow_mut().read(field);
|
||||
trace::trace_pl011_read(offset, result, c"");
|
||||
if update_irq {
|
||||
self.update();
|
||||
self.char_backend.accept_input();
|
||||
|
|
@ -557,6 +573,7 @@ impl PL011State {
|
|||
if let Ok(field) = RegisterOffset::try_from(offset) {
|
||||
// qemu_chr_fe_write_all() calls into the can_receive
|
||||
// callback, so handle writes before entering PL011Registers.
|
||||
trace::trace_pl011_write(offset, value as u32, c"");
|
||||
if field == RegisterOffset::DR {
|
||||
// ??? Check if transmitter is enabled.
|
||||
let ch: [u8; 1] = [value as u8];
|
||||
|
|
@ -565,10 +582,7 @@ impl PL011State {
|
|||
let _ = self.char_backend.write_all(&ch);
|
||||
}
|
||||
|
||||
update_irq = self
|
||||
.regs
|
||||
.borrow_mut()
|
||||
.write(field, value as u32, &self.char_backend);
|
||||
update_irq = self.regs.borrow_mut().write(field, value as u32, self);
|
||||
} else {
|
||||
log_mask_ln!(
|
||||
Log::GuestError,
|
||||
|
|
@ -582,11 +596,19 @@ impl PL011State {
|
|||
|
||||
fn can_receive(&self) -> u32 {
|
||||
let regs = self.regs.borrow();
|
||||
// trace_pl011_can_receive(s->lcr, s->read_count, r);
|
||||
regs.fifo_depth() - regs.read_count
|
||||
let fifo_available = regs.fifo_depth() - regs.read_count;
|
||||
trace::trace_pl011_can_receive(
|
||||
regs.line_control.into(),
|
||||
regs.read_count,
|
||||
regs.fifo_depth(),
|
||||
fifo_available,
|
||||
);
|
||||
fifo_available
|
||||
}
|
||||
|
||||
fn receive(&self, buf: &[u8]) {
|
||||
trace::trace_pl011_receive(buf.len());
|
||||
|
||||
let mut regs = self.regs.borrow_mut();
|
||||
if regs.loopback_enabled() {
|
||||
// In loopback mode, the RX input signal is internally disconnected
|
||||
|
|
@ -635,6 +657,7 @@ impl PL011State {
|
|||
fn update(&self) {
|
||||
let regs = self.regs.borrow();
|
||||
let flags = regs.int_level & regs.int_enabled;
|
||||
trace::trace_pl011_irq_state(flags != 0);
|
||||
for (irq, i) in self.interrupts.iter().zip(IRQMASK) {
|
||||
irq.set(flags.any_set(i));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -411,6 +411,39 @@ where
|
|||
|
||||
impl<R: ObjectDeref> DeviceMethods for R where R::Target: IsA<DeviceState> {}
|
||||
|
||||
impl Clock {
|
||||
pub const PERIOD_1SEC: u64 = bindings::CLOCK_PERIOD_1SEC;
|
||||
|
||||
pub const fn period_from_ns(ns: u64) -> u64 {
|
||||
ns * Self::PERIOD_1SEC / 1_000_000_000
|
||||
}
|
||||
|
||||
pub const fn period_from_hz(hz: u64) -> u64 {
|
||||
if hz == 0 {
|
||||
0
|
||||
} else {
|
||||
Self::PERIOD_1SEC / hz
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn period_to_hz(period: u64) -> u64 {
|
||||
if period == 0 {
|
||||
0
|
||||
} else {
|
||||
Self::PERIOD_1SEC / period
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn period(&self) -> u64 {
|
||||
// SAFETY: Clock is returned by init_clock_in with zero value for period
|
||||
unsafe { &*self.0.as_ptr() }.period
|
||||
}
|
||||
|
||||
pub const fn hz(&self) -> u64 {
|
||||
Self::period_to_hz(self.period())
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl ObjectType for Clock {
|
||||
type Class = ObjectClass;
|
||||
const TYPE_NAME: &'static CStr =
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ subdir('system')
|
|||
subdir('chardev')
|
||||
subdir('hw/core')
|
||||
subdir('tests')
|
||||
|
||||
subdir('trace')
|
||||
subdir('hw')
|
||||
|
||||
cargo = find_program('cargo', required: false)
|
||||
|
|
|
|||
19
rust/trace/Cargo.toml
Normal file
19
rust/trace/Cargo.toml
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
[package]
|
||||
name = "trace"
|
||||
version = "0.1.0"
|
||||
authors = ["Tanish Desai <tanishdesai37@gmail.com>"]
|
||||
description = "QEMU tracing infrastructure support"
|
||||
resolver = "2"
|
||||
publish = false
|
||||
|
||||
edition.workspace = true
|
||||
homepage.workspace = true
|
||||
license.workspace = true
|
||||
repository.workspace = true
|
||||
rust-version.workspace = true
|
||||
|
||||
[dependencies]
|
||||
libc = { workspace = true }
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
19
rust/trace/meson.build
Normal file
19
rust/trace/meson.build
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
rust = import('rust')
|
||||
|
||||
lib_rs = configure_file(
|
||||
input: 'src/lib.rs',
|
||||
output: 'lib.rs',
|
||||
configuration: {
|
||||
'MESON_BUILD_ROOT': meson.project_build_root(),
|
||||
})
|
||||
|
||||
_trace_rs = static_library(
|
||||
'trace', # Library name,
|
||||
lib_rs,
|
||||
trace_rs_targets, # List of generated `.rs` custom targets
|
||||
override_options: ['rust_std=2021', 'build.rust_std=2021'],
|
||||
dependencies: [libc_rs],
|
||||
rust_abi: 'rust',
|
||||
)
|
||||
|
||||
trace_rs = declare_dependency(link_with: _trace_rs)
|
||||
39
rust/trace/src/lib.rs
Normal file
39
rust/trace/src/lib.rs
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
//! This crate provides macros that aid in using QEMU's tracepoint
|
||||
//! functionality.
|
||||
|
||||
#[doc(hidden)]
|
||||
/// Re-exported item to avoid adding libc as a dependency everywhere.
|
||||
pub use libc::{syslog, LOG_INFO};
|
||||
|
||||
#[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`.
|
||||
///
|
||||
/// ```ignore
|
||||
/// ::trace::include_trace!("hw_char");
|
||||
/// // ...
|
||||
/// trace::trace_pl011_read_fifo_rx_full();
|
||||
/// ```
|
||||
macro_rules! include_trace {
|
||||
($name:literal) => {
|
||||
#[allow(
|
||||
clippy::ptr_as_ptr,
|
||||
clippy::cast_lossless,
|
||||
clippy::used_underscore_binding
|
||||
)]
|
||||
mod trace {
|
||||
#[cfg(not(MESON))]
|
||||
include!(concat!(
|
||||
env!("MESON_BUILD_ROOT"),
|
||||
"/trace/trace-",
|
||||
$name,
|
||||
".rs"
|
||||
));
|
||||
|
||||
#[cfg(MESON)]
|
||||
include!(concat!("@MESON_BUILD_ROOT@/trace/trace-", $name, ".rs"));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -142,7 +142,7 @@ macro_rules! log_mask_ln {
|
|||
let _: $crate::log::Log = $mask;
|
||||
|
||||
if unsafe {
|
||||
($crate::bindings::qemu_loglevel & ($mask as std::os::raw::c_int)) != 0
|
||||
($crate::bindings::qemu_loglevel & ($mask as std::os::raw::c_uint)) != 0
|
||||
} {
|
||||
_ = $crate::log::LogGuard::log_fmt(
|
||||
format_args!("{}\n", format_args!($fmt $($args)*)));
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Analyse lock events and compute statistics
|
||||
#
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
This takes a crashing qtest trace and tries to remove superfluous operations
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
Convert plain qtest traces to C or Bash reproducers
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
Use this to convert qtest log info from a generic fuzzer input into a qtest
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
#!/usr/bin/env python3
|
||||
# coding: utf-8
|
||||
#
|
||||
# Probe gdb for supported architectures.
|
||||
#
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (c) 2017-2019 Red Hat Inc.
|
||||
#
|
||||
# Authors:
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright IBM, Corp. 2011
|
||||
# Copyright (c) 2013-2021 Red Hat Inc.
|
||||
#
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# QAPI code generation
|
||||
#
|
||||
# Copyright (c) 2015-2019 Red Hat Inc.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# QAPI schema parser
|
||||
#
|
||||
# Copyright IBM, Corp. 2011
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# QAPI schema internal representation
|
||||
#
|
||||
# Copyright (c) 2015-2019 Red Hat Inc.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Extract QEMU Plugin API symbols from a header file
|
||||
#
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# GDB debugging support, TCG status
|
||||
#
|
||||
# Copyright 2016 Linaro Ltd
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# GDB debugging support
|
||||
#
|
||||
# Copyright 2017 Linaro Ltd
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Dump the contents of a recorded execution stream
|
||||
#
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
Command-line wrapper for the tracetool machinery.
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
"""
|
||||
Machinery for generating tracing-related intermediate files.
|
||||
|
|
@ -15,7 +15,6 @@ __email__ = "stefanha@redhat.com"
|
|||
import os
|
||||
import re
|
||||
import sys
|
||||
import weakref
|
||||
from pathlib import PurePath
|
||||
|
||||
import tracetool.backend
|
||||
|
|
@ -31,6 +30,49 @@ def error(*lines):
|
|||
error_write(*lines)
|
||||
sys.exit(1)
|
||||
|
||||
FMT_TOKEN = re.compile(r'''(?:
|
||||
" ( (?: [^"\\] | \\[\\"abfnrt] | # a string literal
|
||||
\\x[0-9a-fA-F][0-9a-fA-F]) *? ) "
|
||||
| ( PRI [duixX] (?:8|16|32|64|PTR|MAX) ) # a PRIxxx macro
|
||||
| \s+ # spaces (ignored)
|
||||
)''', re.X)
|
||||
|
||||
PRI_SIZE_MAP = {
|
||||
'8': 'hh',
|
||||
'16': 'h',
|
||||
'32': '',
|
||||
'64': 'll',
|
||||
'PTR': 't',
|
||||
'MAX': 'j',
|
||||
}
|
||||
|
||||
def expand_format_string(c_fmt, prefix=""):
|
||||
def pri_macro_to_fmt(pri_macro):
|
||||
assert pri_macro.startswith("PRI")
|
||||
fmt_type = pri_macro[3] # 'd', 'i', 'u', or 'x'
|
||||
fmt_size = pri_macro[4:] # '8', '16', '32', '64', 'PTR', 'MAX'
|
||||
|
||||
size = PRI_SIZE_MAP.get(fmt_size, None)
|
||||
if size is None:
|
||||
raise Exception(f"unknown macro {pri_macro}")
|
||||
return size + fmt_type
|
||||
|
||||
result = prefix
|
||||
pos = 0
|
||||
while pos < len(c_fmt):
|
||||
m = FMT_TOKEN.match(c_fmt, pos)
|
||||
if not m:
|
||||
print("No match at position", pos, ":", repr(c_fmt[pos:]), file=sys.stderr)
|
||||
raise Exception("syntax error in trace file")
|
||||
if m[1]:
|
||||
substr = m[1]
|
||||
elif m[2]:
|
||||
substr = pri_macro_to_fmt(m[2])
|
||||
else:
|
||||
substr = ""
|
||||
result += substr
|
||||
pos = m.end()
|
||||
return result
|
||||
|
||||
out_lineno = 1
|
||||
out_filename = '<none>'
|
||||
|
|
@ -90,6 +132,49 @@ ALLOWED_TYPES = [
|
|||
"ptrdiff_t",
|
||||
]
|
||||
|
||||
C_TYPE_KEYWORDS = {"char", "int", "void", "short", "long", "signed", "unsigned"}
|
||||
|
||||
C_TO_RUST_TYPE_MAP = {
|
||||
"int": "std::ffi::c_int",
|
||||
"long": "std::ffi::c_long",
|
||||
"long long": "std::ffi::c_longlong",
|
||||
"short": "std::ffi::c_short",
|
||||
"char": "std::ffi::c_char",
|
||||
"bool": "bool",
|
||||
"unsigned": "std::ffi::c_uint",
|
||||
# multiple keywords, keep them sorted
|
||||
"long unsigned": "std::ffi::c_long",
|
||||
"long long unsigned": "std::ffi::c_ulonglong",
|
||||
"short unsigned": "std::ffi::c_ushort",
|
||||
"char unsigned": "u8",
|
||||
"int8_t": "i8",
|
||||
"uint8_t": "u8",
|
||||
"int16_t": "i16",
|
||||
"uint16_t": "u16",
|
||||
"int32_t": "i32",
|
||||
"uint32_t": "u32",
|
||||
"int64_t": "i64",
|
||||
"uint64_t": "u64",
|
||||
"void": "()",
|
||||
"size_t": "usize",
|
||||
"ssize_t": "isize",
|
||||
"uintptr_t": "usize",
|
||||
"ptrdiff_t": "isize",
|
||||
}
|
||||
|
||||
# Rust requires manual casting of <32-bit types when passing them to
|
||||
# variable-argument functions.
|
||||
RUST_VARARGS_SMALL_TYPES = {
|
||||
"std::ffi::c_short",
|
||||
"std::ffi::c_ushort",
|
||||
"std::ffi::c_char",
|
||||
"i8",
|
||||
"u8",
|
||||
"i16",
|
||||
"u16",
|
||||
"bool",
|
||||
}
|
||||
|
||||
def validate_type(name):
|
||||
bits = name.split(" ")
|
||||
for bit in bits:
|
||||
|
|
@ -105,6 +190,38 @@ def validate_type(name):
|
|||
"other complex pointer types should be "
|
||||
"declared as 'void *'" % name)
|
||||
|
||||
def c_type_to_rust(name):
|
||||
ptr = False
|
||||
const = False
|
||||
name = name.rstrip()
|
||||
if name[-1] == '*':
|
||||
name = name[:-1].rstrip()
|
||||
ptr = True
|
||||
if name[-1] == '*':
|
||||
# pointers to pointers are the same as void*
|
||||
name = "void"
|
||||
|
||||
bits = name.split()
|
||||
if "const" in bits:
|
||||
const = True
|
||||
bits.remove("const")
|
||||
if bits[0] in C_TYPE_KEYWORDS:
|
||||
if "signed" in bits:
|
||||
bits.remove("signed")
|
||||
if len(bits) > 1 and "int" in bits:
|
||||
bits.remove("int")
|
||||
bits.sort()
|
||||
name = ' '.join(bits)
|
||||
else:
|
||||
if len(bits) > 1:
|
||||
raise ValueError("Invalid type '%s'." % name)
|
||||
name = bits[0]
|
||||
|
||||
ty = C_TO_RUST_TYPE_MAP[name.strip()]
|
||||
if ptr:
|
||||
ty = f'*{"const" if const else "mut"} {ty}'
|
||||
return ty
|
||||
|
||||
class Arguments:
|
||||
"""Event arguments description."""
|
||||
|
||||
|
|
@ -122,10 +239,6 @@ class Arguments:
|
|||
else:
|
||||
self._args.append(arg)
|
||||
|
||||
def copy(self):
|
||||
"""Create a new copy."""
|
||||
return Arguments(list(self._args))
|
||||
|
||||
@staticmethod
|
||||
def build(arg_str):
|
||||
"""Build and Arguments instance from an argument string.
|
||||
|
|
@ -197,6 +310,43 @@ class Arguments:
|
|||
"""List of argument names casted to their type."""
|
||||
return ["(%s)%s" % (type_, name) for type_, name in self._args]
|
||||
|
||||
def rust_decl_extern(self):
|
||||
"""Return a Rust argument list for an extern "C" function"""
|
||||
return ", ".join((f"_{name}: {c_type_to_rust(type_)}"
|
||||
for type_, name in self._args))
|
||||
|
||||
def rust_decl(self):
|
||||
"""Return a Rust argument list for a tracepoint function"""
|
||||
def decl_type(type_):
|
||||
if type_ == "const char *":
|
||||
return "&std::ffi::CStr"
|
||||
return c_type_to_rust(type_)
|
||||
|
||||
return ", ".join((f"_{name}: {decl_type(type_)}"
|
||||
for type_, name in self._args))
|
||||
|
||||
def rust_call_extern(self):
|
||||
"""Return a Rust argument list for a call to an extern "C" function"""
|
||||
def rust_cast(name, type_):
|
||||
if type_ == "const char *":
|
||||
return f"_{name}.as_ptr()"
|
||||
return f"_{name}"
|
||||
|
||||
return ", ".join((rust_cast(name, type_) for type_, name in self._args))
|
||||
|
||||
def rust_call_varargs(self):
|
||||
"""Return a Rust argument list for a call to a C varargs function"""
|
||||
def rust_cast(name, type_):
|
||||
if type_ == "const char *":
|
||||
return f"_{name}.as_ptr()"
|
||||
|
||||
type_ = c_type_to_rust(type_)
|
||||
if type_ in RUST_VARARGS_SMALL_TYPES:
|
||||
return f"_{name} as std::ffi::c_int"
|
||||
return f"_{name} /* as {type_} */"
|
||||
|
||||
return ", ".join((rust_cast(name, type_) for type_, name in self._args))
|
||||
|
||||
|
||||
class Event(object):
|
||||
"""Event description.
|
||||
|
|
@ -222,13 +372,12 @@ class Event(object):
|
|||
r"(?P<name>\w+)"
|
||||
r"\((?P<args>[^)]*)\)"
|
||||
r"\s*"
|
||||
r"(?:(?:(?P<fmt_trans>\".+),)?\s*(?P<fmt>\".+))?"
|
||||
r"(?P<fmt>\".+)?"
|
||||
r"\s*")
|
||||
|
||||
_VALID_PROPS = set(["disable"])
|
||||
|
||||
def __init__(self, name, props, fmt, args, lineno, filename, orig=None,
|
||||
event_trans=None, event_exec=None):
|
||||
def __init__(self, name, props, fmt, args, lineno, filename):
|
||||
"""
|
||||
Parameters
|
||||
----------
|
||||
|
|
@ -236,20 +385,14 @@ class Event(object):
|
|||
Event name.
|
||||
props : list of str
|
||||
Property names.
|
||||
fmt : str, list of str
|
||||
Event printing format string(s).
|
||||
fmt : str
|
||||
Event printing format string.
|
||||
args : Arguments
|
||||
Event arguments.
|
||||
lineno : int
|
||||
The line number in the input file.
|
||||
filename : str
|
||||
The path to the input file.
|
||||
orig : Event or None
|
||||
Original Event before transformation/generation.
|
||||
event_trans : Event or None
|
||||
Generated translation-time event ("tcg" property).
|
||||
event_exec : Event or None
|
||||
Generated execution-time event ("tcg" property).
|
||||
|
||||
"""
|
||||
self.name = name
|
||||
|
|
@ -258,29 +401,16 @@ class Event(object):
|
|||
self.args = args
|
||||
self.lineno = int(lineno)
|
||||
self.filename = str(filename)
|
||||
self.event_trans = event_trans
|
||||
self.event_exec = event_exec
|
||||
|
||||
if len(args) > 10:
|
||||
raise ValueError("Event '%s' has more than maximum permitted "
|
||||
"argument count" % name)
|
||||
|
||||
if orig is None:
|
||||
self.original = weakref.ref(self)
|
||||
else:
|
||||
self.original = orig
|
||||
|
||||
unknown_props = set(self.properties) - self._VALID_PROPS
|
||||
if len(unknown_props) > 0:
|
||||
raise ValueError("Unknown properties: %s"
|
||||
% ", ".join(unknown_props))
|
||||
assert isinstance(self.fmt, str) or len(self.fmt) == 2
|
||||
|
||||
def copy(self):
|
||||
"""Create a new copy."""
|
||||
return Event(self.name, list(self.properties), self.fmt,
|
||||
self.args.copy(), self.lineno, self.filename,
|
||||
self, self.event_trans, self.event_exec)
|
||||
|
||||
@staticmethod
|
||||
def build(line_str, lineno, filename):
|
||||
|
|
@ -302,8 +432,7 @@ class Event(object):
|
|||
name = groups["name"]
|
||||
props = groups["props"].split()
|
||||
fmt = groups["fmt"]
|
||||
fmt_trans = groups["fmt_trans"]
|
||||
if fmt.find("%m") != -1 or fmt_trans.find("%m") != -1:
|
||||
if fmt.find("%m") != -1:
|
||||
raise ValueError("Event format '%m' is forbidden, pass the error "
|
||||
"as an explicit trace argument")
|
||||
if fmt.endswith(r'\n"'):
|
||||
|
|
@ -312,29 +441,22 @@ class Event(object):
|
|||
if '\\n' in fmt:
|
||||
raise ValueError("Event format must not use new line character")
|
||||
|
||||
if len(fmt_trans) > 0:
|
||||
fmt = [fmt_trans, fmt]
|
||||
args = Arguments.build(groups["args"])
|
||||
|
||||
return Event(name, props, fmt, args, lineno, posix_relpath(filename))
|
||||
|
||||
def __repr__(self):
|
||||
"""Evaluable string representation for this object."""
|
||||
if isinstance(self.fmt, str):
|
||||
fmt = self.fmt
|
||||
else:
|
||||
fmt = "%s, %s" % (self.fmt[0], self.fmt[1])
|
||||
return "Event('%s %s(%s) %s')" % (" ".join(self.properties),
|
||||
self.name,
|
||||
self.args,
|
||||
fmt)
|
||||
self.fmt)
|
||||
# Star matching on PRI is dangerous as one might have multiple
|
||||
# arguments with that format, hence the non-greedy version of it.
|
||||
_FMT = re.compile(r"(%[\d\.]*\w+|%.*?PRI\S+)")
|
||||
|
||||
def formats(self):
|
||||
"""List conversion specifiers in the argument print format string."""
|
||||
assert not isinstance(self.fmt, list)
|
||||
return self._FMT.findall(self.fmt)
|
||||
|
||||
QEMU_TRACE = "trace_%(name)s"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
"""
|
||||
Backend management.
|
||||
|
|
@ -19,11 +19,15 @@ All backends must generate their contents through the 'tracetool.out' routine.
|
|||
Backend attributes
|
||||
------------------
|
||||
|
||||
========= ====================================================================
|
||||
Attribute Description
|
||||
========= ====================================================================
|
||||
PUBLIC If exists and is set to 'True', the backend is considered "public".
|
||||
========= ====================================================================
|
||||
=========================== ====================================================
|
||||
Attribute Description
|
||||
=========================== ====================================================
|
||||
PUBLIC If exists and is set to 'True', the backend is
|
||||
considered "public".
|
||||
CHECK_TRACE_EVENT_GET_STATE If exists and is set to 'True', the backend-specific
|
||||
code inside the tracepoint is emitted within an
|
||||
``if trace_event_get_state()`` conditional.
|
||||
=========================== ====================================================
|
||||
|
||||
|
||||
Backend functions
|
||||
|
|
@ -94,29 +98,40 @@ def exists(name):
|
|||
if name == "nop":
|
||||
return True
|
||||
name = name.replace("-", "_")
|
||||
return tracetool.try_import("tracetool.backend." + name)[1]
|
||||
return tracetool.try_import("tracetool.backend." + name)[0]
|
||||
|
||||
|
||||
class Wrapper:
|
||||
def __init__(self, backends, format):
|
||||
self._backends = [backend.replace("-", "_") for backend in backends]
|
||||
self._format = format.replace("-", "_")
|
||||
self.check_trace_event_get_state = False
|
||||
for backend in self._backends:
|
||||
assert exists(backend)
|
||||
assert tracetool.format.exists(self._format)
|
||||
for backend in self.backend_modules():
|
||||
check_trace_event_get_state = getattr(backend, "CHECK_TRACE_EVENT_GET_STATE", False)
|
||||
self.check_trace_event_get_state = self.check_trace_event_get_state or check_trace_event_get_state
|
||||
|
||||
def _run_function(self, name, *args, **kwargs):
|
||||
def backend_modules(self):
|
||||
for backend in self._backends:
|
||||
func = tracetool.try_import("tracetool.backend." + backend,
|
||||
name % self._format, None)[1]
|
||||
if func is not None:
|
||||
func(*args, **kwargs)
|
||||
module = tracetool.try_import("tracetool.backend." + backend)[1]
|
||||
if module is not None:
|
||||
yield module
|
||||
|
||||
def _run_function(self, name, *args, check_trace_event_get_state=None, **kwargs):
|
||||
for backend in self.backend_modules():
|
||||
func = getattr(backend, name % self._format, None)
|
||||
if func is not None and \
|
||||
(check_trace_event_get_state is None or
|
||||
check_trace_event_get_state == getattr(backend, 'CHECK_TRACE_EVENT_GET_STATE', False)):
|
||||
func(*args, **kwargs)
|
||||
|
||||
def generate_begin(self, events, group):
|
||||
self._run_function("generate_%s_begin", events, group)
|
||||
|
||||
def generate(self, event, group):
|
||||
self._run_function("generate_%s", event, group)
|
||||
def generate(self, event, group, check_trace_event_get_state=None):
|
||||
self._run_function("generate_%s", event, group, check_trace_event_get_state=check_trace_event_get_state)
|
||||
|
||||
def generate_backend_dstate(self, event, group):
|
||||
self._run_function("generate_%s_backend_dstate", event, group)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
"""
|
||||
DTrace/SystemTAP backend.
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
"""
|
||||
Ftrace built-in backend.
|
||||
|
|
@ -12,10 +12,11 @@ __maintainer__ = "Stefan Hajnoczi"
|
|||
__email__ = "stefanha@redhat.com"
|
||||
|
||||
|
||||
from tracetool import out
|
||||
from tracetool import out, expand_format_string
|
||||
|
||||
|
||||
PUBLIC = True
|
||||
CHECK_TRACE_EVENT_GET_STATE = True
|
||||
|
||||
|
||||
def generate_h_begin(events, group):
|
||||
|
|
@ -28,22 +29,11 @@ def generate_h(event, group):
|
|||
if len(event.args) > 0:
|
||||
argnames = ", " + argnames
|
||||
|
||||
out(' {',
|
||||
' char ftrace_buf[MAX_TRACE_STRLEN];',
|
||||
' int unused __attribute__ ((unused));',
|
||||
' int trlen;',
|
||||
' if (trace_event_get_state(%(event_id)s)) {',
|
||||
'#line %(event_lineno)d "%(event_filename)s"',
|
||||
' trlen = snprintf(ftrace_buf, MAX_TRACE_STRLEN,',
|
||||
' "%(name)s " %(fmt)s "\\n" %(argnames)s);',
|
||||
out('#line %(event_lineno)d "%(event_filename)s"',
|
||||
' ftrace_write("%(name)s " %(fmt)s "\\n" %(argnames)s);',
|
||||
'#line %(out_next_lineno)d "%(out_filename)s"',
|
||||
' trlen = MIN(trlen, MAX_TRACE_STRLEN - 1);',
|
||||
' unused = write(trace_marker_fd, ftrace_buf, trlen);',
|
||||
' }',
|
||||
' }',
|
||||
name=event.name,
|
||||
args=event.args,
|
||||
event_id="TRACE_" + event.name.upper(),
|
||||
event_lineno=event.lineno,
|
||||
event_filename=event.filename,
|
||||
fmt=event.fmt.rstrip("\n"),
|
||||
|
|
@ -53,3 +43,9 @@ def generate_h(event, group):
|
|||
def generate_h_backend_dstate(event, group):
|
||||
out(' trace_event_get_state_dynamic_by_id(%(event_id)s) || \\',
|
||||
event_id="TRACE_" + event.name.upper())
|
||||
|
||||
def generate_rs(event, group):
|
||||
out(' let format_string = c"%(fmt)s";',
|
||||
' unsafe {bindings::ftrace_write(format_string.as_ptr() as *const c_char, %(args)s);}',
|
||||
fmt=expand_format_string(event.fmt),
|
||||
args=event.args.rust_call_varargs())
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
"""
|
||||
Stderr built-in backend.
|
||||
|
|
@ -12,10 +12,11 @@ __maintainer__ = "Stefan Hajnoczi"
|
|||
__email__ = "stefanha@redhat.com"
|
||||
|
||||
|
||||
from tracetool import out
|
||||
from tracetool import out, expand_format_string
|
||||
|
||||
|
||||
PUBLIC = True
|
||||
CHECK_TRACE_EVENT_GET_STATE = True
|
||||
|
||||
|
||||
def generate_h_begin(events, group):
|
||||
|
|
@ -28,14 +29,11 @@ def generate_h(event, group):
|
|||
if len(event.args) > 0:
|
||||
argnames = ", " + argnames
|
||||
|
||||
cond = "trace_event_get_state(%s)" % ("TRACE_" + event.name.upper())
|
||||
|
||||
out(' if (%(cond)s && qemu_loglevel_mask(LOG_TRACE)) {',
|
||||
out(' if (qemu_loglevel_mask(LOG_TRACE)) {',
|
||||
'#line %(event_lineno)d "%(event_filename)s"',
|
||||
' qemu_log("%(name)s " %(fmt)s "\\n"%(argnames)s);',
|
||||
' qemu_log("%(name)s " %(fmt)s "\\n"%(argnames)s);',
|
||||
'#line %(out_next_lineno)d "%(out_filename)s"',
|
||||
' }',
|
||||
cond=cond,
|
||||
' }',
|
||||
event_lineno=event.lineno,
|
||||
event_filename=event.filename,
|
||||
name=event.name,
|
||||
|
|
@ -46,3 +44,11 @@ def generate_h(event, group):
|
|||
def generate_h_backend_dstate(event, group):
|
||||
out(' trace_event_get_state_dynamic_by_id(%(event_id)s) || \\',
|
||||
event_id="TRACE_" + event.name.upper())
|
||||
|
||||
def generate_rs(event, group):
|
||||
out(' let format_string = c"%(fmt)s\\n";',
|
||||
' if (unsafe { bindings::qemu_loglevel } & bindings::LOG_TRACE) != 0 {',
|
||||
' unsafe { bindings::qemu_log(format_string.as_ptr() as *const c_char, %(args)s);}',
|
||||
' }',
|
||||
fmt=expand_format_string(event.fmt, event.name + " "),
|
||||
args=event.args.rust_call_varargs())
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
"""
|
||||
Simple built-in backend.
|
||||
|
|
@ -16,6 +16,7 @@ from tracetool import out
|
|||
|
||||
|
||||
PUBLIC = True
|
||||
CHECK_TRACE_EVENT_GET_STATE = True
|
||||
|
||||
|
||||
def is_string(arg):
|
||||
|
|
@ -36,13 +37,8 @@ def generate_h_begin(events, group):
|
|||
|
||||
|
||||
def generate_h(event, group):
|
||||
event_id = 'TRACE_' + event.name.upper()
|
||||
cond = "trace_event_get_state(%s)" % event_id
|
||||
out(' if (%(cond)s) {',
|
||||
' _simple_%(api)s(%(args)s);',
|
||||
' }',
|
||||
out(' _simple_%(api)s(%(args)s);',
|
||||
api=event.api(),
|
||||
cond=cond,
|
||||
args=", ".join(event.args.names()))
|
||||
|
||||
|
||||
|
|
@ -102,3 +98,10 @@ def generate_c(event, group):
|
|||
out(' trace_record_finish(&rec);',
|
||||
'}',
|
||||
'')
|
||||
|
||||
def generate_rs(event, group):
|
||||
out(' extern "C" { fn _simple_%(api)s(%(rust_args)s); }',
|
||||
' unsafe { _simple_%(api)s(%(args)s); }',
|
||||
api=event.api(),
|
||||
rust_args=event.args.rust_decl_extern(),
|
||||
args=event.args.rust_call_extern())
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
"""
|
||||
Syslog built-in backend.
|
||||
|
|
@ -12,10 +12,11 @@ __maintainer__ = "Stefan Hajnoczi"
|
|||
__email__ = "stefanha@redhat.com"
|
||||
|
||||
|
||||
from tracetool import out
|
||||
from tracetool import out, expand_format_string
|
||||
|
||||
|
||||
PUBLIC = True
|
||||
CHECK_TRACE_EVENT_GET_STATE = True
|
||||
|
||||
|
||||
def generate_h_begin(events, group):
|
||||
|
|
@ -28,20 +29,20 @@ def generate_h(event, group):
|
|||
if len(event.args) > 0:
|
||||
argnames = ", " + argnames
|
||||
|
||||
cond = "trace_event_get_state(%s)" % ("TRACE_" + event.name.upper())
|
||||
|
||||
out(' if (%(cond)s) {',
|
||||
'#line %(event_lineno)d "%(event_filename)s"',
|
||||
out('#line %(event_lineno)d "%(event_filename)s"',
|
||||
' syslog(LOG_INFO, "%(name)s " %(fmt)s %(argnames)s);',
|
||||
'#line %(out_next_lineno)d "%(out_filename)s"',
|
||||
' }',
|
||||
cond=cond,
|
||||
event_lineno=event.lineno,
|
||||
event_filename=event.filename,
|
||||
name=event.name,
|
||||
fmt=event.fmt.rstrip("\n"),
|
||||
argnames=argnames)
|
||||
|
||||
def generate_rs(event, group):
|
||||
out(' let format_string = c"%(fmt)s";',
|
||||
' unsafe {::trace::syslog(::trace::LOG_INFO, format_string.as_ptr() as *const c_char, %(args)s);}',
|
||||
fmt=expand_format_string(event.fmt),
|
||||
args=event.args.rust_call_varargs())
|
||||
|
||||
def generate_h_backend_dstate(event, group):
|
||||
out(' trace_event_get_state_dynamic_by_id(%(event_id)s) || \\',
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
"""
|
||||
LTTng User Space Tracing backend.
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
"""
|
||||
Format management.
|
||||
|
|
@ -70,7 +70,7 @@ def exists(name):
|
|||
if len(name) == 0:
|
||||
return False
|
||||
name = name.replace("-", "_")
|
||||
return tracetool.try_import("tracetool.format." + name)[1]
|
||||
return tracetool.try_import("tracetool.format." + name)[0]
|
||||
|
||||
|
||||
def generate(events, format, backend, group):
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
"""
|
||||
trace/generated-tracers.c
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
"""
|
||||
trace/generated-tracers.dtrace (DTrace only).
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
"""
|
||||
trace/generated-tracers.h
|
||||
|
|
@ -40,11 +40,6 @@ def generate(events, backend, group):
|
|||
enabled = 0
|
||||
else:
|
||||
enabled = 1
|
||||
if "tcg-exec" in e.properties:
|
||||
# a single define for the two "sub-events"
|
||||
out('#define TRACE_%(name)s_ENABLED %(enabled)d',
|
||||
name=e.original.name.upper(),
|
||||
enabled=enabled)
|
||||
out('#define TRACE_%s_ENABLED %d' % (e.name.upper(), enabled))
|
||||
|
||||
backend.generate_begin(events, group)
|
||||
|
|
@ -60,7 +55,6 @@ def generate(events, backend, group):
|
|||
|
||||
out(' false)')
|
||||
|
||||
# tracer without checks
|
||||
out('',
|
||||
'static inline void %(api)s(%(args)s)',
|
||||
'{',
|
||||
|
|
@ -68,11 +62,17 @@ def generate(events, backend, group):
|
|||
args=e.args)
|
||||
|
||||
if "disable" not in e.properties:
|
||||
backend.generate(e, group)
|
||||
backend.generate(e, group, check_trace_event_get_state=False)
|
||||
|
||||
if backend.check_trace_event_get_state:
|
||||
event_id = 'TRACE_' + e.name.upper()
|
||||
cond = "trace_event_get_state(%s)" % event_id
|
||||
out(' if (%(cond)s) {',
|
||||
cond=cond)
|
||||
backend.generate(e, group, check_trace_event_get_state=True)
|
||||
out(' }')
|
||||
out('}')
|
||||
|
||||
|
||||
backend.generate_end(events, group)
|
||||
|
||||
out('#endif /* TRACE_%s_GENERATED_TRACERS_H */' % group.upper())
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
"""
|
||||
Generate .stp file that printfs log messages (DTrace with SystemTAP only).
|
||||
|
|
@ -18,8 +18,6 @@ from tracetool.backend.dtrace import binary, probeprefix
|
|||
from tracetool.backend.simple import is_string
|
||||
from tracetool.format.stap import stap_escape
|
||||
|
||||
def global_var_name(name):
|
||||
return probeprefix().replace(".", "_") + "_" + name
|
||||
|
||||
STATE_SKIP = 0
|
||||
STATE_LITERAL = 1
|
||||
|
|
|
|||
64
scripts/tracetool/format/rs.py
Normal file
64
scripts/tracetool/format/rs.py
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
"""
|
||||
trace-DIR.rs
|
||||
"""
|
||||
|
||||
__author__ = "Tanish Desai <tanishdesai37@gmail.com>"
|
||||
__copyright__ = "Copyright 2025, Tanish Desai <tanishdesai37@gmail.com>"
|
||||
__license__ = "GPL version 2 or (at your option) any later version"
|
||||
|
||||
__maintainer__ = "Stefan Hajnoczi"
|
||||
__email__ = "stefanha@redhat.com"
|
||||
|
||||
|
||||
from tracetool import out
|
||||
|
||||
|
||||
def generate(events, backend, group):
|
||||
out('// 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;',
|
||||
'',
|
||||
'#[inline(always)]',
|
||||
'fn trace_event_state_is_enabled(dstate: u16) -> bool {',
|
||||
' (unsafe { trace_events_enabled_count }) != 0 && dstate != 0',
|
||||
'}',
|
||||
'',
|
||||
'extern "C" {',
|
||||
' 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('}')
|
||||
|
||||
backend.generate_begin(events, group)
|
||||
|
||||
for e in events:
|
||||
out('',
|
||||
'#[inline(always)]',
|
||||
'#[allow(dead_code)]',
|
||||
'pub fn %(api)s(%(args)s)',
|
||||
'{',
|
||||
api=e.api(e.QEMU_TRACE),
|
||||
args=e.args.rust_decl())
|
||||
|
||||
if "disable" not in e.properties:
|
||||
backend.generate(e, group, check_trace_event_get_state=False)
|
||||
if backend.check_trace_event_get_state:
|
||||
event_id = 'TRACE_' + e.name.upper()
|
||||
out(' if trace_event_state_is_enabled(unsafe { _%(event_id)s_DSTATE}) {',
|
||||
event_id = event_id,
|
||||
api=e.api())
|
||||
backend.generate(e, group, check_trace_event_get_state=True)
|
||||
out(' }')
|
||||
out('}')
|
||||
|
||||
backend.generate_end(events, group)
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
"""
|
||||
Generate .stp file that outputs simpletrace binary traces (DTrace with SystemTAP only).
|
||||
|
|
@ -17,8 +17,6 @@ from tracetool.backend.dtrace import probeprefix
|
|||
from tracetool.backend.simple import is_string
|
||||
from tracetool.format.stap import stap_escape
|
||||
|
||||
def global_var_name(name):
|
||||
return probeprefix().replace(".", "_") + "_" + name
|
||||
|
||||
def generate(events, backend, group):
|
||||
out('/* This file is autogenerated by tracetool, do not edit. */',
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
"""
|
||||
Generate .stp file (DTrace with SystemTAP only).
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
"""
|
||||
trace/generated-ust.c
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
"""
|
||||
trace/generated-ust-provider.h
|
||||
|
|
|
|||
|
|
@ -21,18 +21,10 @@ extern uint16_t _TRACE_TEST_WIBBLE_DSTATE;
|
|||
|
||||
static inline void trace_test_blah(void *context, const char *filename)
|
||||
{
|
||||
{
|
||||
char ftrace_buf[MAX_TRACE_STRLEN];
|
||||
int unused __attribute__ ((unused));
|
||||
int trlen;
|
||||
if (trace_event_get_state(TRACE_TEST_BLAH)) {
|
||||
if (trace_event_get_state(TRACE_TEST_BLAH)) {
|
||||
#line 4 "trace-events"
|
||||
trlen = snprintf(ftrace_buf, MAX_TRACE_STRLEN,
|
||||
"test_blah " "Blah context=%p filename=%s" "\n" , context, filename);
|
||||
#line 33 "ftrace.h"
|
||||
trlen = MIN(trlen, MAX_TRACE_STRLEN - 1);
|
||||
unused = write(trace_marker_fd, ftrace_buf, trlen);
|
||||
}
|
||||
ftrace_write("test_blah " "Blah context=%p filename=%s" "\n" , context, filename);
|
||||
#line 28 "ftrace.h"
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -42,18 +34,10 @@ static inline void trace_test_blah(void *context, const char *filename)
|
|||
|
||||
static inline void trace_test_wibble(void *context, int value)
|
||||
{
|
||||
{
|
||||
char ftrace_buf[MAX_TRACE_STRLEN];
|
||||
int unused __attribute__ ((unused));
|
||||
int trlen;
|
||||
if (trace_event_get_state(TRACE_TEST_WIBBLE)) {
|
||||
if (trace_event_get_state(TRACE_TEST_WIBBLE)) {
|
||||
#line 5 "trace-events"
|
||||
trlen = snprintf(ftrace_buf, MAX_TRACE_STRLEN,
|
||||
"test_wibble " "Wibble context=%p value=%d" "\n" , context, value);
|
||||
#line 54 "ftrace.h"
|
||||
trlen = MIN(trlen, MAX_TRACE_STRLEN - 1);
|
||||
unused = write(trace_marker_fd, ftrace_buf, trlen);
|
||||
}
|
||||
ftrace_write("test_wibble " "Wibble context=%p value=%d" "\n" , context, value);
|
||||
#line 41 "ftrace.h"
|
||||
}
|
||||
}
|
||||
#endif /* TRACE_TESTSUITE_GENERATED_TRACERS_H */
|
||||
|
|
|
|||
40
tests/tracetool/ftrace.rs
Normal file
40
tests/tracetool/ftrace.rs
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
// 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;
|
||||
|
||||
#[inline(always)]
|
||||
fn trace_event_state_is_enabled(dstate: u16) -> bool {
|
||||
(unsafe { trace_events_enabled_count }) != 0 && dstate != 0
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
static mut trace_events_enabled_count: u32;
|
||||
}
|
||||
extern "C" {
|
||||
static mut _TRACE_TEST_BLAH_DSTATE: u16;
|
||||
static mut _TRACE_TEST_WIBBLE_DSTATE: u16;
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
#[allow(dead_code)]
|
||||
pub fn trace_test_blah(_context: *mut (), _filename: &std::ffi::CStr)
|
||||
{
|
||||
if trace_event_state_is_enabled(unsafe { _TRACE_TEST_BLAH_DSTATE}) {
|
||||
let format_string = c"Blah context=%p filename=%s";
|
||||
unsafe {bindings::ftrace_write(format_string.as_ptr() as *const c_char, _context /* as *mut () */, _filename.as_ptr());}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
#[allow(dead_code)]
|
||||
pub fn trace_test_wibble(_context: *mut (), _value: std::ffi::c_int)
|
||||
{
|
||||
if trace_event_state_is_enabled(unsafe { _TRACE_TEST_WIBBLE_DSTATE}) {
|
||||
let format_string = c"Wibble context=%p value=%d";
|
||||
unsafe {bindings::ftrace_write(format_string.as_ptr() as *const c_char, _context /* as *mut () */, _value /* as std::ffi::c_int */);}
|
||||
}
|
||||
}
|
||||
|
|
@ -21,10 +21,12 @@ extern uint16_t _TRACE_TEST_WIBBLE_DSTATE;
|
|||
|
||||
static inline void trace_test_blah(void *context, const char *filename)
|
||||
{
|
||||
if (trace_event_get_state(TRACE_TEST_BLAH) && qemu_loglevel_mask(LOG_TRACE)) {
|
||||
if (trace_event_get_state(TRACE_TEST_BLAH)) {
|
||||
if (qemu_loglevel_mask(LOG_TRACE)) {
|
||||
#line 4 "trace-events"
|
||||
qemu_log("test_blah " "Blah context=%p filename=%s" "\n", context, filename);
|
||||
#line 28 "log.h"
|
||||
qemu_log("test_blah " "Blah context=%p filename=%s" "\n", context, filename);
|
||||
#line 29 "log.h"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -34,10 +36,12 @@ static inline void trace_test_blah(void *context, const char *filename)
|
|||
|
||||
static inline void trace_test_wibble(void *context, int value)
|
||||
{
|
||||
if (trace_event_get_state(TRACE_TEST_WIBBLE) && qemu_loglevel_mask(LOG_TRACE)) {
|
||||
if (trace_event_get_state(TRACE_TEST_WIBBLE)) {
|
||||
if (qemu_loglevel_mask(LOG_TRACE)) {
|
||||
#line 5 "trace-events"
|
||||
qemu_log("test_wibble " "Wibble context=%p value=%d" "\n", context, value);
|
||||
#line 41 "log.h"
|
||||
qemu_log("test_wibble " "Wibble context=%p value=%d" "\n", context, value);
|
||||
#line 44 "log.h"
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* TRACE_TESTSUITE_GENERATED_TRACERS_H */
|
||||
|
|
|
|||
44
tests/tracetool/log.rs
Normal file
44
tests/tracetool/log.rs
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
// 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;
|
||||
|
||||
#[inline(always)]
|
||||
fn trace_event_state_is_enabled(dstate: u16) -> bool {
|
||||
(unsafe { trace_events_enabled_count }) != 0 && dstate != 0
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
static mut trace_events_enabled_count: u32;
|
||||
}
|
||||
extern "C" {
|
||||
static mut _TRACE_TEST_BLAH_DSTATE: u16;
|
||||
static mut _TRACE_TEST_WIBBLE_DSTATE: u16;
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
#[allow(dead_code)]
|
||||
pub fn trace_test_blah(_context: *mut (), _filename: &std::ffi::CStr)
|
||||
{
|
||||
if trace_event_state_is_enabled(unsafe { _TRACE_TEST_BLAH_DSTATE}) {
|
||||
let format_string = c"test_blah Blah context=%p filename=%s\n";
|
||||
if (unsafe { bindings::qemu_loglevel } & bindings::LOG_TRACE) != 0 {
|
||||
unsafe { bindings::qemu_log(format_string.as_ptr() as *const c_char, _context /* as *mut () */, _filename.as_ptr());}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
#[allow(dead_code)]
|
||||
pub fn trace_test_wibble(_context: *mut (), _value: std::ffi::c_int)
|
||||
{
|
||||
if trace_event_state_is_enabled(unsafe { _TRACE_TEST_WIBBLE_DSTATE}) {
|
||||
let format_string = c"test_wibble Wibble context=%p value=%d\n";
|
||||
if (unsafe { bindings::qemu_loglevel } & bindings::LOG_TRACE) != 0 {
|
||||
unsafe { bindings::qemu_log(format_string.as_ptr() as *const c_char, _context /* as *mut () */, _value /* as std::ffi::c_int */);}
|
||||
}
|
||||
}
|
||||
}
|
||||
40
tests/tracetool/simple.rs
Normal file
40
tests/tracetool/simple.rs
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
// 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;
|
||||
|
||||
#[inline(always)]
|
||||
fn trace_event_state_is_enabled(dstate: u16) -> bool {
|
||||
(unsafe { trace_events_enabled_count }) != 0 && dstate != 0
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
static mut trace_events_enabled_count: u32;
|
||||
}
|
||||
extern "C" {
|
||||
static mut _TRACE_TEST_BLAH_DSTATE: u16;
|
||||
static mut _TRACE_TEST_WIBBLE_DSTATE: u16;
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
#[allow(dead_code)]
|
||||
pub fn trace_test_blah(_context: *mut (), _filename: &std::ffi::CStr)
|
||||
{
|
||||
if trace_event_state_is_enabled(unsafe { _TRACE_TEST_BLAH_DSTATE}) {
|
||||
extern "C" { fn _simple_trace_test_blah(_context: *mut (), _filename: *const std::ffi::c_char); }
|
||||
unsafe { _simple_trace_test_blah(_context, _filename.as_ptr()); }
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
#[allow(dead_code)]
|
||||
pub fn trace_test_wibble(_context: *mut (), _value: std::ffi::c_int)
|
||||
{
|
||||
if trace_event_state_is_enabled(unsafe { _TRACE_TEST_WIBBLE_DSTATE}) {
|
||||
extern "C" { fn _simple_trace_test_wibble(_context: *mut (), _value: std::ffi::c_int); }
|
||||
unsafe { _simple_trace_test_wibble(_context, _value); }
|
||||
}
|
||||
}
|
||||
40
tests/tracetool/syslog.rs
Normal file
40
tests/tracetool/syslog.rs
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
// 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;
|
||||
|
||||
#[inline(always)]
|
||||
fn trace_event_state_is_enabled(dstate: u16) -> bool {
|
||||
(unsafe { trace_events_enabled_count }) != 0 && dstate != 0
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
static mut trace_events_enabled_count: u32;
|
||||
}
|
||||
extern "C" {
|
||||
static mut _TRACE_TEST_BLAH_DSTATE: u16;
|
||||
static mut _TRACE_TEST_WIBBLE_DSTATE: u16;
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
#[allow(dead_code)]
|
||||
pub fn trace_test_blah(_context: *mut (), _filename: &std::ffi::CStr)
|
||||
{
|
||||
if trace_event_state_is_enabled(unsafe { _TRACE_TEST_BLAH_DSTATE}) {
|
||||
let format_string = c"Blah context=%p filename=%s";
|
||||
unsafe {::trace::syslog(::trace::LOG_INFO, format_string.as_ptr() as *const c_char, _context /* as *mut () */, _filename.as_ptr());}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
#[allow(dead_code)]
|
||||
pub fn trace_test_wibble(_context: *mut (), _value: std::ffi::c_int)
|
||||
{
|
||||
if trace_event_state_is_enabled(unsafe { _TRACE_TEST_WIBBLE_DSTATE}) {
|
||||
let format_string = c"Wibble context=%p value=%d";
|
||||
unsafe {::trace::syslog(::trace::LOG_INFO, format_string.as_ptr() as *const c_char, _context /* as *mut () */, _value /* as std::ffi::c_int */);}
|
||||
}
|
||||
}
|
||||
|
|
@ -14,6 +14,8 @@ def get_formats(backend):
|
|||
"c",
|
||||
"h",
|
||||
]
|
||||
if backend in {"ftrace", "log", "simple", "syslog"}:
|
||||
formats += ["rs"]
|
||||
if backend == "dtrace":
|
||||
formats += [
|
||||
"d",
|
||||
|
|
|
|||
|
|
@ -38,6 +38,21 @@ static int find_mount(char *mount_point, const char *fstype)
|
|||
return ret;
|
||||
}
|
||||
|
||||
void ftrace_write(const char *fmt, ...)
|
||||
{
|
||||
char ftrace_buf[MAX_TRACE_STRLEN];
|
||||
int unused __attribute__ ((unused));
|
||||
int trlen;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
trlen = vsnprintf(ftrace_buf, MAX_TRACE_STRLEN, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
trlen = MIN(trlen, MAX_TRACE_STRLEN - 1);
|
||||
unused = write(trace_marker_fd, ftrace_buf, trlen);
|
||||
}
|
||||
|
||||
bool ftrace_init(void)
|
||||
{
|
||||
char mount_point[PATH_MAX];
|
||||
|
|
|
|||
|
|
@ -8,5 +8,6 @@
|
|||
extern int trace_marker_fd;
|
||||
|
||||
bool ftrace_init(void);
|
||||
G_GNUC_PRINTF(1, 2) void ftrace_write(const char *fmt, ...);
|
||||
|
||||
#endif /* TRACE_FTRACE_H */
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
system_ss.add(files('control-target.c', 'trace-hmp-cmds.c'))
|
||||
|
||||
trace_rs_targets = []
|
||||
trace_events_files = []
|
||||
foreach item : [ '.' ] + trace_events_subdirs + qapi_trace_events
|
||||
if item in qapi_trace_events
|
||||
|
|
@ -24,6 +24,11 @@ foreach item : [ '.' ] + trace_events_subdirs + qapi_trace_events
|
|||
input: trace_events_file,
|
||||
command: [ tracetool, group, '--format=c', '@INPUT@', '@OUTPUT@' ],
|
||||
depend_files: tracetool_depends)
|
||||
trace_rs = custom_target(fmt.format('trace', 'rs'),
|
||||
output: fmt.format('trace', 'rs'),
|
||||
input: trace_events_file,
|
||||
command: [ tracetool, group, '--format=rs', '@INPUT@', '@OUTPUT@' ],
|
||||
depend_files: tracetool_depends)
|
||||
if 'ust' in get_option('trace_backends')
|
||||
trace_ust_h = custom_target(fmt.format('trace-ust', 'h'),
|
||||
output: fmt.format('trace-ust', 'h'),
|
||||
|
|
@ -34,6 +39,7 @@ foreach item : [ '.' ] + trace_events_subdirs + qapi_trace_events
|
|||
genh += trace_ust_h
|
||||
endif
|
||||
trace_ss.add(trace_h, trace_c)
|
||||
trace_rs_targets += trace_rs
|
||||
if 'dtrace' in get_option('trace_backends')
|
||||
trace_dtrace = custom_target(fmt.format('trace-dtrace', 'dtrace'),
|
||||
output: fmt.format('trace-dtrace', 'dtrace'),
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ static FILE *global_file;
|
|||
static __thread FILE *thread_file;
|
||||
static __thread Notifier qemu_log_thread_cleanup_notifier;
|
||||
|
||||
int qemu_loglevel;
|
||||
unsigned qemu_loglevel;
|
||||
static bool log_per_thread;
|
||||
static GArray *debug_regions;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue