Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Xen singlestep support #150

Open
wants to merge 21 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@ hyper-v = ["winapi", "widestring", "ntapi", "vid-sys"]
log = "0.4.8"
env_logger = "0.7.1"
libc = { version = "0.2.58", optional = true }
xenctrl = { version = "0.4.2", optional = true }
xenctrl = { version = "0.4.5", optional = true }
xenstore-rs = { version = "0.3.0", optional = true }
xenforeignmemory = { version = "0.1.0", optional = true }
xenevtchn = { version = "0.1.2", optional = true }
xenevtchn = { version = "0.1.4", optional = true }
xenvmevent-sys = { version = "0.1.3", optional = true }
kvmi = { version = "0.2.1", optional = true }
fdp = { version = "0.1.0", optional = true }
Expand All @@ -49,3 +49,4 @@ clap = "2.33.0"
colored = "1.9.3"
mockall = "0.7.1"
test-case = "1.0.0"

22 changes: 11 additions & 11 deletions c_examples/regs-dump.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,17 @@ void read_registers(void* driver, const char* vm_name) {
Registers regs;
memset(&regs, 0, sizeof(regs));
if (microvmi_read_registers(driver, 0, &regs)) {
printf("rax: 0x%" PRIx64 "\n", regs.x86._0.rax);
printf("rbx: 0x%" PRIx64 "\n", regs.x86._0.rbx);
printf("rcx: 0x%" PRIx64 "\n", regs.x86._0.rcx);
printf("rdx: 0x%" PRIx64 "\n", regs.x86._0.rdx);
printf("rsi: 0x%" PRIx64 "\n", regs.x86._0.rsi);
printf("rdi: 0x%" PRIx64 "\n", regs.x86._0.rdi);
printf("rsp: 0x%" PRIx64 "\n", regs.x86._0.rsp);
printf("rbp: 0x%" PRIx64 "\n", regs.x86._0.rbp);
printf("rip: 0x%" PRIx64 "\n", regs.x86._0.rip);
printf("rflags: 0x%" PRIx64 "\n", regs.x86._0.rflags);
printf("cr3: 0x%" PRIx64 "\n", regs.x86._0.cr3);
printf("rax: 0x%" PRIx64 "\n", regs.x86.rax);
printf("rbx: 0x%" PRIx64 "\n", regs.x86.rbx);
printf("rcx: 0x%" PRIx64 "\n", regs.x86.rcx);
printf("rdx: 0x%" PRIx64 "\n", regs.x86.rdx);
printf("rsi: 0x%" PRIx64 "\n", regs.x86.rsi);
printf("rdi: 0x%" PRIx64 "\n", regs.x86.rdi);
printf("rsp: 0x%" PRIx64 "\n", regs.x86.rsp);
printf("rbp: 0x%" PRIx64 "\n", regs.x86.rbp);
printf("rip: 0x%" PRIx64 "\n", regs.x86.rip);
printf("rflags: 0x%" PRIx64 "\n", regs.x86.rflags);
printf("cr3: 0x%" PRIx64 "\n", regs.x86.cr3);
} else {
printf("Unable to read registers.\n");
}
Expand Down
120 changes: 120 additions & 0 deletions examples/singlestep-events.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::time::Instant;

use clap::{App, Arg, ArgMatches};
use colored::*;
use env_logger;

use microvmi::api::*;

fn parse_args() -> ArgMatches<'static> {
App::new(file!())
.version("0.1")
.about("Watches singlestep VMI events")
.arg(Arg::with_name("vm_name").index(1).required(true))
.arg(
Arg::with_name("count")
.help("Listen for <count> events then quit")
.takes_value(true)
.short("c"),
)
.get_matches()
}

fn toggle_singlestep_interception(drv: &mut Box<dyn Introspectable>, enabled: bool) {
drv.pause().expect("Failed to pause VM");

let intercept = InterceptType::Singlestep;
let status_str = if enabled { "Enabling" } else { "Disabling" };
println!("{} singlestep events", status_str);
for vcpu in 0..drv.get_vcpu_count().expect("Failed to get VCPU count") {
drv.toggle_intercept(vcpu, intercept, enabled)
.expect(&format!("Failed to enable singlestep"));
}

drv.resume().expect("Failed to resume VM");
}

fn main() {
env_logger::init();

let matches = parse_args();

let domain_name = matches.value_of("vm_name").unwrap();

let init_option = matches
.value_of("kvmi_socket")
.map(|socket| DriverInitParam::KVMiSocket(socket.into()));
let count_opt = matches.value_of("count").map(|counter_str| {
counter_str
.parse::<u64>()
.expect("Counter is not a valid number")
});
// set CTRL-C handler
let running = Arc::new(AtomicBool::new(true));
let r = running.clone();
ctrlc::set_handler(move || {
r.store(false, Ordering::SeqCst);
})
.expect("Error setting Ctrl-C handler");

println!("Initialize Libmicrovmi");
let mut drv: Box<dyn Introspectable> = microvmi::init(domain_name, None, init_option);

//Enable singlestep interception
toggle_singlestep_interception(&mut drv, true);

println!("Listen for singlestep events...");
// record elapsed time
let start = Instant::now();
// listen
let mut i: u64 = 0;
while running.load(Ordering::SeqCst) {
match drv.listen(1000) {
Err(error) => {
println!("Error while listening for events: {}. Exiting.", error);
break;
}
Ok(event) => match event {
Some(ev) => {
match ev.kind {
EventType::Singlestep {} => (),
_ => panic!("Not singlestep event"),
};
let ev_nb_output = format!("{}", i).cyan();
let vcpu_output = format!("VCPU {}", ev.vcpu).yellow();
let singlestep_output = format!("singlestep occurred!").color("blue");
println!(
"[{}] {} - {}: ",
ev_nb_output, vcpu_output, singlestep_output
);
drv.reply_event(ev, EventReplyType::Continue)
.expect("Failed to send event reply");
i = i + 1;
match count_opt {
None => continue,
Some(counter) => {
if i == counter {
break;
}
}
};
}
None => println!("No events yet..."),
},
}
}
let duration = start.elapsed();

//disable singlestep interception
toggle_singlestep_interception(&mut drv, false);

let ev_per_sec = i as f64 / duration.as_secs_f64();
println!(
"Caught {} events in {:.2} seconds ({:.2} events/sec)",
i,
duration.as_secs_f64(),
ev_per_sec
);
}
3 changes: 3 additions & 0 deletions src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,7 @@ pub enum InterceptType {
/// Intercept when guest requests an access to a page for which the requested type of access is not granted. For example , guest tries to write on a read only page.
Breakpoint,
Pagefault,
Singlestep,
}

/// Various types of events along with their relevant attributes being handled by this driver
Expand Down Expand Up @@ -351,6 +352,7 @@ pub enum EventType {
/// Acsess responsible for thr pagefault
access: Access,
},
Singlestep,
}

///Types of x86 control registers are listed here
Expand All @@ -367,6 +369,7 @@ pub enum CrType {

///This provides an abstraction of event which the hypervisor reports and using which we introspect the guest
#[repr(C)]
#[derive(Debug)]
pub struct Event {
///vcpu on which the event is detected
pub vcpu: u16,
Expand Down
3 changes: 3 additions & 0 deletions src/driver/kvm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,9 @@ impl<T: KVMIntrospectable> Introspectable for Kvm<T> {
.kvmi
.control_events(vcpu, KVMiInterceptType::Pagefault, enabled)?)
}
_ => {
unimplemented!()
}
}
}

Expand Down
Loading