Skip to content

Commit

Permalink
Update to 9.0.0, add plugin version 2 and 3, update tracer and tiny e…
Browse files Browse the repository at this point in the history
…xamples with register output
  • Loading branch information
novafacing committed Jun 2, 2024
1 parent 7b6088c commit d2b4766
Show file tree
Hide file tree
Showing 28 changed files with 2,301 additions and 531 deletions.
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
"rust-analyzer.cargo.buildScripts.enable": false
"rust-analyzer.cargo.buildScripts.enable": false,
}
8 changes: 4 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ license = "GPL-2.0-only"
publish = true
readme = "README.md"
repository = "https://github.com/novafacing/qemu-rs"
version = "8.2.2-v0"
version = "9.0.0-v0"

[workspace]
resolver = "2"
Expand All @@ -23,6 +23,6 @@ members = [
default-members = ["qemu-plugin", "qemu-plugin-sys"]

[workspace.dependencies]
qemu-plugin-sys = { version = "8.2.2-v0", path = "qemu-plugin-sys" }
qemu-plugin = { version = "8.2.2-v0", path = "qemu-plugin" }
qemu = { version = "8.2.2-v0", path = "qemu" }
qemu-plugin-sys = { version = "9.0.0-v0", path = "qemu-plugin-sys", default-features = false }
qemu-plugin = { version = "9.0.0-v0", path = "qemu-plugin", default-features = false }
qemu = { version = "9.0.0-v0", path = "qemu" }
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ installs Rust wrappers for QEMU as binaries.
You can install QEMU with (add any additional features you need, e.g. `plugins`):

```sh
cargo install qemu@8.2.2-v0 --features=binaries
cargo install qemu@9.0.0-v0 --features=binaries
```

On some systems, particularly BTRFS systems, `/tmp` may not be large enough for the
Expand Down
20 changes: 17 additions & 3 deletions plugins/tiny/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,37 @@ use anyhow::{anyhow, Result};
use ctor::ctor;
use qemu_plugin::{
plugin::{HasCallbacks, Plugin, Register, PLUGIN},
PluginId, TranslationBlock,
PluginId, TranslationBlock, VCPUIndex, qemu_plugin_get_registers,
RegisterDescriptor,
};
use std::sync::Mutex;

struct TinyTrace {}
#[derive(Default)]
struct TinyTrace {
registers: Vec<RegisterDescriptor<'static>>,
}

impl Plugin for TinyTrace {}
impl Register for TinyTrace {}

impl HasCallbacks for TinyTrace {
fn on_vcpu_init(&mut self, _id: PluginId, _vcpu_id: VCPUIndex) -> Result<()> {
self.registers = qemu_plugin_get_registers()?;
Ok(())
}
fn on_translation_block_translate(
&mut self,
_id: PluginId,
tb: TranslationBlock,
) -> Result<()> {
let registers = self.registers.clone();
tb.instructions().try_for_each(|insn| {
println!("{:08x}: {}", insn.vaddr(), insn.disas()?);
for register in &registers {
let value = register.read()?;
println!(" {}: {:?}", register.name, value);
}

Ok(())
})
}
Expand All @@ -28,7 +42,7 @@ impl HasCallbacks for TinyTrace {
#[ctor]
fn init() {
PLUGIN
.set(Mutex::new(Box::new(TinyTrace {})))
.set(Mutex::new(Box::new(TinyTrace::default())))
.map_err(|_| anyhow!("Failed to set plugin"))
.expect("Failed to set plugin");
}
13 changes: 8 additions & 5 deletions plugins/tracer/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ crate-type = ["cdylib", "lib"]
[dependencies]
anyhow = "1.0.75"
ctor = "0.2.6"
qemu-plugin = { workspace = true, features = ["unix-weak-link"] }
qemu-plugin = { workspace = true, features = [
"unix-weak-link",
], default-features = false }
serde = { version = "1.0.193", features = ["derive"] }
serde_cbor = "0.11.2"
tokio = { version = "1.35.0", features = ["full"] }
Expand All @@ -22,13 +24,14 @@ yaxpeax-x86 = "1.2.2"
clap = { version = "4.4.11", features = ["derive", "string"] }
# Enable the `qemu` feature to build and install QEMU with the `qemu` crate instead
# of trying to use the system QEMU.
qemu = { workspace = true, features = [
"plugins",
], optional = true }
qemu = { workspace = true, features = ["plugins"], optional = true }
memfd-exec = { version = "0.2.1", optional = true }
rand = "0.8.5"
serde_json = "1.0.108"

[features]
qemu = ["dep:memfd-exec", "dep:qemu"]
default = []
default = ["plugin-api-v2"]
plugin-api-v1 = ["qemu-plugin/plugin-api-v1"]
plugin-api-v2 = ["qemu-plugin/plugin-api-v2"]
plugin-api-v3 = ["qemu-plugin/plugin-api-v3"]
69 changes: 57 additions & 12 deletions plugins/tracer/src/bin/tracer.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use anyhow::{anyhow, Error, Result};
use clap::Parser;
#[cfg(feature = "memfd-exec")]
#[cfg(feature = "qemu")]
use memfd_exec::{MemFdExecutable, Stdio};
#[cfg(feature = "qemu")]
use qemu::QEMU_X86_64_LINUX_USER;
Expand Down Expand Up @@ -47,6 +47,38 @@ fn tmp(prefix: &str, suffix: &str) -> PathBuf {
))
}

#[cfg(feature = "plugin-api-v1")]
#[derive(Parser, Debug, Clone)]
/// Run QEMU with a plugin that logs events. To pass arguments to QEMU, use the QEMU environment
/// variables.
struct Args {
#[clap(short = 'i', long)]
/// Whether instructions should be logged
pub log_insns: bool,
#[clap(short = 'm', long)]
/// Whether memory accesses should be logged
pub log_mem: bool,
#[clap(short = 's', long)]
/// Whether syscalls should be logged
pub log_syscalls: bool,
#[clap(short = 'a', long)]
/// Whether all events should be logged
pub log_all: bool,
#[clap(short = 'I', long)]
/// An input file to use as the program's stdin, otherwise the driver's stdin is used
pub input_file: Option<PathBuf>,
#[clap(short = 'O', long)]
/// An output file to write the trace to, otherwise stdout is used
pub output_file: Option<PathBuf>,
/// The program to run
#[clap()]
pub program: PathBuf,
/// The arguments to the program
#[clap(num_args = 1.., last = true)]
pub args: Vec<String>,
}

#[cfg(any(feature = "plugin-api-v2", feature = "plugin-api-v3"))]
#[derive(Parser, Debug, Clone)]
/// Run QEMU with a plugin that logs events. To pass arguments to QEMU, use the QEMU environment
/// variables.
Expand All @@ -60,6 +92,9 @@ struct Args {
#[clap(short = 's', long)]
/// Whether syscalls should be logged
pub log_syscalls: bool,
#[clap(short = 'r', long)]
/// Whether registers should be logged
pub log_registers: bool,
#[clap(short = 'a', long)]
/// Whether all events should be logged
pub log_all: bool,
Expand All @@ -79,12 +114,25 @@ struct Args {

impl Args {
fn to_plugin_args(&self) -> String {
format!(
"log_insns={},log_mem={},log_syscalls={}",
self.log_insns | self.log_all,
self.log_mem | self.log_all,
self.log_syscalls | self.log_all
)
#[cfg(feature = "plugin-api-v1")]
{
format!(
"log_insns={},log_mem={},log_syscalls={}",
self.log_insns | self.log_all,
self.log_mem | self.log_all,
self.log_syscalls | self.log_all,
)
}
#[cfg(any(feature = "plugin-api-v2", feature = "plugin-api-v3"))]
{
format!(
"log_insns={},log_mem={},log_syscalls={},log_registers={}",
self.log_insns | self.log_all,
self.log_mem | self.log_all,
self.log_syscalls | self.log_all,
self.log_registers | self.log_all,
)
}
}

fn to_qemu_args(&self, socket_path: &Path, plugin_path: &Path) -> Result<Vec<String>> {
Expand Down Expand Up @@ -302,17 +350,14 @@ async fn main() -> Result<()> {
let listen_sock = UnixListener::bind(&socket_path)?;

let qemu_args = args.to_qemu_args(&socket_path, &plugin_path)?;
let qemu_task = spawn(async move { run(input, qemu_args).await });

let socket_task = spawn_blocking(move || listen(listen_sock, args.output_file.as_ref()));

let (qemu_res, socket_res) = join!(qemu_task, socket_task);
let qemu_task = spawn(async move { run(input, qemu_args).await });
let (qemu_res, socket_res) = join!(socket_task, qemu_task);

remove_file(&plugin_path).await?;
remove_file(&socket_path).await?;

qemu_res??;

socket_res??;

Ok(())
Expand Down
Loading

0 comments on commit d2b4766

Please sign in to comment.