Skip to content

Commit

Permalink
Update for plugin v4
Browse files Browse the repository at this point in the history
  • Loading branch information
novafacing committed Dec 5, 2024
1 parent f0ff0fc commit 9594f58
Show file tree
Hide file tree
Showing 20 changed files with 302 additions and 332 deletions.
8 changes: 3 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,11 @@ license = "GPL-2.0-only"
publish = true
readme = "README.md"
repository = "https://github.com/novafacing/qemu-rs"
version = "9.0.0-v0"
version = "9.1.0-v0"

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

[workspace.dependencies]
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" }
qemu-plugin-sys = { version = "9.1.0-v0", path = "qemu-plugin-sys", default-features = false }
qemu-plugin = { version = "9.1.0-v0", path = "qemu-plugin", default-features = false }
18 changes: 1 addition & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,4 @@ and instructions) of a program like:

```sh
cargo run -r --bin tracer -- -a /bin/ls -- -lah
```

## Installing QEMU

This repository also provides a crate (`qemu`) which builds QEMU from source and
installs Rust wrappers for QEMU as binaries.

You can install QEMU with (add any additional features you need, e.g. `plugins`):

```sh
cargo install [email protected] --features=binaries
```

On some systems, particularly BTRFS systems, `/tmp` may not be large enough for the
temporary build directory (QEMU is quite large to build). In this case, create a
directory on your root filesystem (e.g. `$HOME/.cargo/tmp`) and set
`CARGO_TARGET_DIR=$HOME/.cargo/tmp` when running the install command.
```
9 changes: 5 additions & 4 deletions plugins/tiny-system/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,13 @@ crate-type = ["cdylib"]
qemu-plugin = { workspace = true, features = [
"unix-weak-link",
], default-features = false }
anyhow = "1.0.75"
ffi = "0.1.0"
ctor = "0.2.6"
anyhow = "1.0.94"
ffi = "0.1.1"
ctor = "0.2.9"

[features]
default = ["plugin-api-v2"]
default = ["plugin-api-v4"]
plugin-api-v1 = ["qemu-plugin/plugin-api-v1"]
plugin-api-v2 = ["qemu-plugin/plugin-api-v2"]
plugin-api-v3 = ["qemu-plugin/plugin-api-v3"]
plugin-api-v4 = ["qemu-plugin/plugin-api-v4"]
9 changes: 5 additions & 4 deletions plugins/tiny/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,13 @@ crate-type = ["cdylib"]
qemu-plugin = { workspace = true, features = [
"unix-weak-link",
], default-features = false }
anyhow = "1.0.75"
ffi = "0.1.0"
ctor = "0.2.6"
anyhow = "1.0.94"
ffi = "0.1.1"
ctor = "0.2.9"

[features]
default = ["plugin-api-v2"]
default = ["plugin-api-v4"]
plugin-api-v1 = ["qemu-plugin/plugin-api-v1"]
plugin-api-v2 = ["qemu-plugin/plugin-api-v2"]
plugin-api-v3 = ["qemu-plugin/plugin-api-v3"]
plugin-api-v4 = ["qemu-plugin/plugin-api-v4"]
6 changes: 3 additions & 3 deletions plugins/tiny/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,21 @@ use qemu_plugin::{
plugin::{HasCallbacks, Plugin, Register, PLUGIN},
PluginId, TranslationBlock,
};
#[cfg(any(feature = "plugin-api-v2", feature = "plugin-api-v3"))]
#[cfg(not(feature = "plugin-api-v1"))]
use qemu_plugin::{qemu_plugin_get_registers, RegisterDescriptor, VCPUIndex};
use std::sync::Mutex;

#[derive(Default)]
struct TinyTrace {
#[cfg(any(feature = "plugin-api-v2", feature = "plugin-api-v3"))]
#[cfg(not(feature = "plugin-api-v1"))]
registers: Vec<RegisterDescriptor<'static>>,
}

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

impl HasCallbacks for TinyTrace {
#[cfg(any(feature = "plugin-api-v2", feature = "plugin-api-v3"))]
#[cfg(not(feature = "plugin-api-v1"))]
fn on_vcpu_init(&mut self, _id: PluginId, _vcpu_id: VCPUIndex) -> Result<()> {
self.registers = qemu_plugin_get_registers()?;
Ok(())
Expand Down
23 changes: 10 additions & 13 deletions plugins/tracer/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,30 +8,27 @@ name = "tracer"
crate-type = ["cdylib", "lib"]

[dependencies]
anyhow = "1.0.75"
ctor = "0.2.6"
anyhow = "1.0.94"
ctor = "0.2.9"
qemu-plugin = { workspace = true, features = [
"unix-weak-link",
], default-features = false }
serde = { version = "1.0.193", features = ["derive"] }
serde = { version = "1.0.215", features = ["derive"] }
serde_cbor = "0.11.2"
tokio = { version = "1.35.0", features = ["full"] }
typed-builder = "0.18.0"
yaxpeax-x86 = "1.2.2"
tokio = { version = "1.42.0", features = ["full"] }
typed-builder = "0.20.0"
yaxpeax-x86 = "2.0.0"

# Dependencies only used by this crate's `tracer` binary. We do not use dev-dependencies
# because they cannot be optional.
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 }
clap = { version = "4.5.22", features = ["derive", "string"] }
memfd-exec = { version = "0.2.1", optional = true }
rand = "0.8.5"
serde_json = "1.0.108"
serde_json = "1.0.133"

[features]
qemu = ["dep:memfd-exec", "dep:qemu"]
default = ["plugin-api-v2"]
default = ["plugin-api-v4"]
plugin-api-v1 = ["qemu-plugin/plugin-api-v1"]
plugin-api-v2 = ["qemu-plugin/plugin-api-v2"]
plugin-api-v3 = ["qemu-plugin/plugin-api-v3"]
plugin-api-v4 = ["qemu-plugin/plugin-api-v4"]
85 changes: 2 additions & 83 deletions plugins/tracer/src/bin/tracer.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,8 @@
use anyhow::{anyhow, Error, Result};
use clap::Parser;
#[cfg(feature = "qemu")]
use memfd_exec::{MemFdExecutable, Stdio};
#[cfg(feature = "qemu")]
use qemu::QEMU_X86_64_LINUX_USER;
use rand::{distributions::Alphanumeric, thread_rng, Rng};
use serde_cbor::Deserializer;
use serde_json::to_string;
#[cfg(not(feature = "qemu"))]
use std::process::{Command, Stdio};
use std::{
fs::OpenOptions,
Expand Down Expand Up @@ -78,7 +73,7 @@ struct Args {
pub args: Vec<String>,
}

#[cfg(any(feature = "plugin-api-v2", feature = "plugin-api-v3"))]
#[cfg(not(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.
Expand Down Expand Up @@ -123,7 +118,7 @@ impl Args {
self.log_syscalls | self.log_all,
)
}
#[cfg(any(feature = "plugin-api-v2", feature = "plugin-api-v3"))]
#[cfg(not(feature = "plugin-api-v1"))]
{
format!(
"log_insns={},log_mem={},log_syscalls={},log_registers={}",
Expand Down Expand Up @@ -157,82 +152,6 @@ impl Args {
}
}

#[cfg(feature = "qemu")]
async fn run(input: Option<Vec<u8>>, args: Vec<String>) -> Result<()> {
let mut exe = MemFdExecutable::new("qemu", QEMU_X86_64_LINUX_USER)
.args(args)
.stdin(if input.is_some() {
Stdio::piped()
} else {
Stdio::inherit()
})
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()?;

if let Some(input) = input {
let mut stdin = exe.stdin.take().ok_or_else(|| anyhow!("No stdin"))?;
spawn_blocking(move || stdin.write_all(&input));
}

let stdout = exe.stdout.take().ok_or_else(|| anyhow!("No stdout"))?;

let out_reader = spawn_blocking(move || {
let mut line = String::new();
let mut out_reader = BufReader::new(stdout);

loop {
line.clear();

if let 0 = out_reader.read_line(&mut line)? {
break;
}

let line = line.trim();

if !line.is_empty() {
println!("{line}");
}
}

Ok::<(), Error>(())
});

let stderr = exe.stderr.take().ok_or_else(|| anyhow!("No stderr"))?;

let err_reader = spawn_blocking(move || {
let mut line = String::new();
let mut err_reader = BufReader::new(stderr);

loop {
line.clear();

if let 0 = err_reader.read_line(&mut line)? {
break;
}

let line = line.trim();

if !line.is_empty() {
eprintln!("{line}");
}
}

Ok::<(), Error>(())
});

let waiter = spawn_blocking(move || exe.wait());

let (out_res, err_res, waiter_res) = join!(out_reader, err_reader, waiter);

out_res??;
err_res??;
waiter_res??;

Ok(())
}

#[cfg(not(feature = "qemu"))]
async fn run(input: Option<Vec<u8>>, args: Vec<String>) -> Result<()> {
let mut exe = Command::new("qemu-x86_64")
.args(args)
Expand Down
Loading

0 comments on commit 9594f58

Please sign in to comment.