6 releases

9.0.0-v0 Jun 3, 2024
8.2.2-v0 Mar 11, 2024
8.2.0-v1 Jan 10, 2024
8.1.3-v4 Jan 10, 2024
8.1.3-v3 Dec 19, 2023

#118 in Emulators

GPL-2.0-only

205KB
4K SLoC

QEMU-PLUGIN

High level idiomatic Rust bindings to the QEMU Plugin API, including tools to build QEMU plugins in Rust.

Example

Below is a minimal plugin example for a plugin which prints the execution trace of the program running in QEMU. Notice that all we do is register a struct which implements Plugin in a library constructor, and the library takes care of the rest.

use anyhow::Result;
use ctor::ctor;
use qemu_plugin::{
    plugin::{HasCallbacks, Plugin, Register, PLUGIN},
    PluginId, TranslationBlock,
};
use std::sync::Mutex;

struct TinyTrace {}

impl Register for TinyTrace {}

impl HasCallbacks for TinyTrace {
    fn on_translation_block_translate(
        &mut self,
        _id: PluginId,
        tb: TranslationBlock,
    ) -> Result<()> {
        tb.instructions().enumerate().try_for_each(|(idx, insn)| {
            if idx == 0 {
                println!("====TB: {:08x}", insn.vaddr());
            }

            println!("{:08x}: {}", insn.vaddr(), insn.disas()?);
            Ok::<(), anyhow::Error>(())
        })?;

        Ok(())
    }
}

impl Plugin for TinyTrace {}

#[ctor]
fn init() {
    PLUGIN
        .set(Mutex::new(Box::new(TinyTrace {})))
        .map_err(|_| anyhow::anyhow!("Failed to set plugin"))
        .expect("Failed to set plugin");
}

The above src/lib.rs in a Cargo project with the following Cargo.toml will compile to libtiny.so, which can be loaded in QEMU by running qemu-system-ARCH -plugin ./libtiny.so.

[package]
name = "tiny"
version = "0.1.0"
edition = "2021"

[lib]
crate-type = ["cdylib"]

[dependencies]
qemu-plugin = "9.0.0-v0"
anyhow = "1.0.75"
ffi = "0.1.0"
ctor = "0.2.6"

Versioning

As of QEMU 8.2.4, the QEMU plugin API has more than a single version. This enables some great features like register inspection and conditional callbacks. Versioning is implemented in the qemu-plugin crate via compile-time features, because a dynamic library can only be compatible with one version at a time. To choose a version, set a listing like:

qemu-plugin = { version = "9.0.0-v0", features = ["plugin-api-v2"], default-features = false }

The qemu-plugin crate's default plugin version is set to the latest version that is officially released in QEMU. Currently, this is V2, released in 8.2.4 and 9.0.0. If you need a different version, you must set default-features = false.

Dependencies

~0.5–37MB
~548K SLoC