Compare commits
1 Commits
master
...
experiment
Author | SHA1 | Date | |
---|---|---|---|
2d8e696909 |
65
Cargo.lock
generated
65
Cargo.lock
generated
@ -265,26 +265,6 @@ dependencies = [
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "derive_more"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "093242cf7570c207c83073cf82f79706fe7b8317e98620a47d5be7c3d8497678"
|
||||
dependencies = [
|
||||
"derive_more-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "derive_more-impl"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.104",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "discard"
|
||||
version = "1.0.4"
|
||||
@ -442,18 +422,6 @@ version = "0.2.174"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776"
|
||||
|
||||
[[package]]
|
||||
name = "libipt"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4c3143c4dae9794d23fa2bbc6315847fdf3ef718caa09a7ba09238bce19fe9d4"
|
||||
dependencies = [
|
||||
"bitflags 2.9.1",
|
||||
"derive_more",
|
||||
"libipt-sys",
|
||||
"num_enum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libipt-sys"
|
||||
version = "0.2.4"
|
||||
@ -550,28 +518,6 @@ dependencies = [
|
||||
"minimal-lexical",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_enum"
|
||||
version = "0.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a973b4e44ce6cad84ce69d797acf9a044532e4184c4f267913d1b546a0727b7a"
|
||||
dependencies = [
|
||||
"num_enum_derive",
|
||||
"rustversion",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_enum_derive"
|
||||
version = "0.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77e878c846a8abae00dd069496dbe8751b16ac1c3d6bd2a7283a938e8228f90d"
|
||||
dependencies = [
|
||||
"proc-macro-crate",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.104",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.21.3"
|
||||
@ -609,15 +555,6 @@ dependencies = [
|
||||
"syn 2.0.104",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-crate"
|
||||
version = "3.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "edce586971a4dfaa28950c6f18ed55e0406c1ab88bbce2c6f6293a7aaba73d35"
|
||||
dependencies = [
|
||||
"toml_edit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-hack"
|
||||
version = "0.5.20+deprecated"
|
||||
@ -637,7 +574,7 @@ dependencies = [
|
||||
name = "pt-dump-decoder"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"libipt",
|
||||
"libipt-sys",
|
||||
"memmap2",
|
||||
]
|
||||
|
||||
|
3
build.rs
3
build.rs
@ -61,7 +61,8 @@ fn setup_nyx(out_dir: &str) {
|
||||
println!("cargo:warning=Cloning and building QEMU-Nyx. This may take a while...");
|
||||
shell(
|
||||
out_dir,
|
||||
"git clone https://github.com/nyx-fuzz/QEMU-Nyx --depth 1",
|
||||
// "git clone https://github.com/nyx-fuzz/QEMU-Nyx --depth 1",
|
||||
"git clone /fs/scratch/smdavenh/bachelor-project/QEMU-Nyx --depth 1",
|
||||
);
|
||||
|
||||
let is_debug_build = match env::var("DEBUG").unwrap().as_str() {
|
||||
|
@ -7,5 +7,6 @@ edition = "2024"
|
||||
|
||||
|
||||
[dependencies]
|
||||
libipt = { version = "0.4.0", features = ["libipt_master"] }
|
||||
#libipt = { version = "0.4.0", features = ["libipt_master"] }
|
||||
libipt-sys = "0.2.4"
|
||||
memmap2 = "0.9.7"
|
||||
|
@ -1,5 +1,3 @@
|
||||
use libipt::enc_dec_builder::EncoderDecoderBuilder;
|
||||
use libipt::packet::{Packet, PacketDecoder};
|
||||
use memmap2::Mmap;
|
||||
use std::error::Error;
|
||||
use std::fs::File;
|
||||
@ -8,71 +6,278 @@ use std::time::Duration;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct AnalyzeData {
|
||||
pub packets: u64,
|
||||
pub cycles: u64,
|
||||
pub time: Duration,
|
||||
pub time_outside_hypervisor: Duration,
|
||||
pub total_time: Duration,
|
||||
pub time_in_client: Duration,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum Scope {
|
||||
#[derive(Debug, Clone)]
|
||||
struct Scope {
|
||||
kind: ScopeKind,
|
||||
start_tsc: u64,
|
||||
end_tsc: u64,
|
||||
}
|
||||
|
||||
impl Scope {
|
||||
#[track_caller]
|
||||
fn new(kind: ScopeKind, start_tsc: u64, end_tsc: u64) -> Self {
|
||||
assert!(
|
||||
start_tsc <= end_tsc,
|
||||
"start_tsc {start_tsc} is greater than end_tsc {end_tsc}"
|
||||
);
|
||||
Self {
|
||||
kind,
|
||||
start_tsc,
|
||||
end_tsc,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
enum ScopeKind {
|
||||
Main,
|
||||
PreRun,
|
||||
PostRun,
|
||||
PacketGenerationDisabled,
|
||||
}
|
||||
|
||||
const PT_EVENT_ENABLED: u32 = 0;
|
||||
const PT_EVENT_DISABLED: u32 = 1;
|
||||
const PT_EVENT_ASYNC_DISABLED: u32 = 2;
|
||||
const PT_EVENT_PTWRITE: u32 = 16;
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
enum DecoderState {
|
||||
Enabled {
|
||||
kind: ScopeKind,
|
||||
start_tsc: u64,
|
||||
},
|
||||
Disabled {
|
||||
enabled_kind: ScopeKind,
|
||||
start_tsc: Option<u64>,
|
||||
},
|
||||
}
|
||||
|
||||
pub fn analyze_dump(path: impl AsRef<Path>) -> Result<AnalyzeData, Box<dyn Error>> {
|
||||
let trace_file = File::open(path)?;
|
||||
let mmap = unsafe { Mmap::map(&trace_file)? };
|
||||
|
||||
let builder = EncoderDecoderBuilder::<PacketDecoder<()>>::new();
|
||||
// I hope this is safe if the buffer is never written to
|
||||
let builder = unsafe { builder.buffer_from_raw(mmap.as_ptr() as *mut _, mmap.len()) };
|
||||
let mut events = vec![];
|
||||
let mut state = DecoderState::Disabled {
|
||||
enabled_kind: ScopeKind::PreRun,
|
||||
start_tsc: None,
|
||||
};
|
||||
|
||||
let mut decoder = builder.build()?;
|
||||
// Required before it can be used
|
||||
decoder.sync_forward()?;
|
||||
unsafe {
|
||||
let mut config: libipt_sys::pt_config = std::mem::zeroed();
|
||||
config.size = size_of::<libipt_sys::pt_config>();
|
||||
config.begin = mmap.as_ptr() as *mut _;
|
||||
config.end = config.begin.add(mmap.len());
|
||||
|
||||
let mut segments = vec![(Scope::PreRun, 0u64)];
|
||||
let mut total = 0u64;
|
||||
|
||||
for packet in decoder {
|
||||
total += 1;
|
||||
match packet {
|
||||
Ok(Packet::Cyc(cyc)) => {
|
||||
segments.last_mut().unwrap().1 += cyc.value();
|
||||
}
|
||||
Ok(Packet::Vmcs(_)) => {
|
||||
// last_packet_vmcs = true;
|
||||
}
|
||||
Ok(Packet::Ptw(ptwrite)) => {
|
||||
if ptwrite.payload() == 42 {
|
||||
// Main enter
|
||||
segments.push((Scope::Main, 0));
|
||||
} else if ptwrite.payload() == 43 {
|
||||
// Main exit
|
||||
segments.push((Scope::PostRun, 0));
|
||||
} else {
|
||||
println!("GOT PTWRITE!!!!!: {ptwrite:?}");
|
||||
}
|
||||
}
|
||||
Ok(_) => {}
|
||||
Err(error) => println!("Got error: {error:?}"),
|
||||
let decoder = libipt_sys::pt_evt_alloc_decoder(&config);
|
||||
if decoder.is_null() {
|
||||
panic!("Could not create decoder");
|
||||
}
|
||||
|
||||
let status = libipt_sys::pt_evt_sync_forward(decoder);
|
||||
if status < 0 {
|
||||
panic!("Could not sync: {status}");
|
||||
}
|
||||
|
||||
let mut last_tsc = 0;
|
||||
let mut last_event = 0;
|
||||
|
||||
loop {
|
||||
let mut event = std::mem::MaybeUninit::uninit();
|
||||
let status = libipt_sys::pt_evt_next(
|
||||
decoder,
|
||||
event.as_mut_ptr(),
|
||||
size_of::<libipt_sys::pt_event>(),
|
||||
);
|
||||
if status < 0 {
|
||||
if (-status & (1 << 2)) == 0 {
|
||||
println!("Expected EOI, got {status}");
|
||||
}
|
||||
break;
|
||||
}
|
||||
let event = event.assume_init();
|
||||
|
||||
if (event.has_tsc() > 0 && event.tsc < last_tsc && event.type_ != 20 && event.type_ != 21) {
|
||||
println!("WARN: Event {} happens before last event ({last_event})!", event.type_);
|
||||
continue;
|
||||
}
|
||||
last_tsc = event.tsc;
|
||||
last_event = event.type_;
|
||||
|
||||
// println!("Has tsc: {}, tsc: {}, {}, {}", event.has_tsc(), event.tsc, event.lost_mtc, event.lost_cyc);
|
||||
let next_state = match event.type_ {
|
||||
PT_EVENT_ENABLED | PT_EVENT_ASYNC_DISABLED => match state {
|
||||
DecoderState::Disabled { enabled_kind, .. } => {
|
||||
assert!(event.has_tsc() > 0);
|
||||
DecoderState::Enabled {
|
||||
kind: enabled_kind,
|
||||
start_tsc: event.tsc,
|
||||
}
|
||||
}
|
||||
DecoderState::Enabled { .. } => continue,
|
||||
},
|
||||
PT_EVENT_DISABLED => match state {
|
||||
DecoderState::Enabled { kind, .. } => {
|
||||
assert!(event.has_tsc() > 0);
|
||||
DecoderState::Disabled {
|
||||
enabled_kind: kind,
|
||||
start_tsc: Some(event.tsc),
|
||||
}
|
||||
}
|
||||
DecoderState::Disabled { .. } => {
|
||||
continue;
|
||||
}
|
||||
},
|
||||
PT_EVENT_PTWRITE => {
|
||||
assert!(event.has_tsc() > 0);
|
||||
let value = event.variant.ptwrite.payload;
|
||||
let new_scope = match value {
|
||||
42 => ScopeKind::Main,
|
||||
43 => ScopeKind::PostRun,
|
||||
other => panic!("Unknown ptwrite {other}"),
|
||||
};
|
||||
match state {
|
||||
DecoderState::Disabled { .. } => {
|
||||
unreachable!("Ptwrite cannot happen if the decoder is deactivate")
|
||||
}
|
||||
DecoderState::Enabled { .. } => DecoderState::Enabled {
|
||||
kind: new_scope,
|
||||
start_tsc: event.tsc,
|
||||
},
|
||||
}
|
||||
}
|
||||
_ => continue,
|
||||
};
|
||||
|
||||
println!("{state:?}, {next_state:?}, lost cyc: {}, lost mtc: {}", event.lost_cyc, event.lost_mtc);
|
||||
match (state, next_state) {
|
||||
(
|
||||
DecoderState::Enabled { kind, start_tsc },
|
||||
DecoderState::Enabled {
|
||||
start_tsc: end_tsc, ..
|
||||
}
|
||||
| DecoderState::Disabled {
|
||||
start_tsc: Some(end_tsc),
|
||||
..
|
||||
},
|
||||
) => {
|
||||
events.push(Scope::new(kind, start_tsc, end_tsc));
|
||||
}
|
||||
(
|
||||
DecoderState::Disabled {
|
||||
start_tsc: Some(start_tsc),
|
||||
..
|
||||
},
|
||||
DecoderState::Enabled {
|
||||
start_tsc: end_tsc, ..
|
||||
},
|
||||
) => events.push(Scope::new(
|
||||
ScopeKind::PacketGenerationDisabled,
|
||||
start_tsc,
|
||||
end_tsc,
|
||||
)),
|
||||
(
|
||||
DecoderState::Disabled {
|
||||
start_tsc: None, ..
|
||||
},
|
||||
DecoderState::Enabled { .. },
|
||||
) => {}
|
||||
_ => unreachable!("{state:?}, {next_state:?}"),
|
||||
}
|
||||
|
||||
state = next_state;
|
||||
}
|
||||
|
||||
// TODO: Add last event!
|
||||
|
||||
libipt_sys::pt_evt_free_decoder(decoder);
|
||||
}
|
||||
// dbg!(&segments);
|
||||
let cycles_main: u64 = segments
|
||||
.iter()
|
||||
.filter(|(scope, _)| matches!(scope, Scope::Main))
|
||||
.map(|(_, cycles)| cycles)
|
||||
.sum();
|
||||
let cycles_total = segments.iter().map(|(_, cycles)| cycles).sum();
|
||||
let total_seconds = cycles_total as f64 / 2_700_000_000.0;
|
||||
let total_seconds_no_hypervisor = cycles_main as f64 / 2_700_000_000.0;
|
||||
|
||||
let total_duration = filter_time(&events, |_| true);
|
||||
let duration_in_client = filter_time(&events, |kind| matches!(kind, ScopeKind::Main));
|
||||
|
||||
Ok(AnalyzeData {
|
||||
packets: total,
|
||||
cycles: cycles_total,
|
||||
time: Duration::from_secs_f64(total_seconds),
|
||||
time_outside_hypervisor: Duration::from_secs_f64(total_seconds_no_hypervisor),
|
||||
total_time: total_duration,
|
||||
time_in_client: duration_in_client,
|
||||
})
|
||||
}
|
||||
|
||||
fn filter_time(events: &[Scope], mut filter: impl FnMut(ScopeKind) -> bool) -> Duration {
|
||||
let iter = events.iter().filter(|scope| filter(scope.kind));
|
||||
let total_cycles = iter
|
||||
.map(|scope| scope.end_tsc - scope.start_tsc)
|
||||
.sum::<u64>() as f64;
|
||||
let cycles_per_second = 2_700_000_000.0;
|
||||
Duration::from_secs_f64(total_cycles / cycles_per_second)
|
||||
}
|
||||
|
||||
// pub fn analyze_dump(path: impl AsRef<Path>) -> Result<AnalyzeData, Box<dyn Error>> {
|
||||
// let trace_file = File::open(path)?;
|
||||
// let mmap = unsafe { Mmap::map(&trace_file)? };
|
||||
//
|
||||
// let builder = EncoderDecoderBuilder::<PacketDecoder<()>>::new();
|
||||
// // I hope this is safe if the buffer is never written to
|
||||
// let builder = unsafe { builder.buffer_from_raw(mmap.as_ptr() as *mut _, mmap.len()) };
|
||||
//
|
||||
// let mut decoder = builder.build()?;
|
||||
// // Required before it can be used
|
||||
// decoder.sync_forward()?;
|
||||
//
|
||||
// let mut segments = vec![(Scope::PreRun, 0u64)];
|
||||
// let mut total = 0u64;
|
||||
//
|
||||
// for packet in decoder {
|
||||
// total += 1;
|
||||
// match packet {
|
||||
// Ok(Packet::Cyc(cyc)) => {
|
||||
// segments.last_mut().unwrap().1 += cyc.value();
|
||||
// }
|
||||
// Ok(Packet::TipPgd(pgd)) => {
|
||||
// segments.push((Scope::PacketGenerationDisabled, 0));
|
||||
// }
|
||||
// Ok(Packet::TipPge(pge)) => {
|
||||
// match segments.as_slice() {
|
||||
// [.., (previous_segment, _), (Scope::PacketGenerationDisabled, _)] => {
|
||||
// segments.push((*previous_segment, 0));
|
||||
// }
|
||||
// [_] | [] => {}
|
||||
// [.., _, (other_scope, _)] => {
|
||||
// panic!("Invalid segments layout: {other_scope:?}");
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// Ok(Packet::Ptw(ptwrite)) => {
|
||||
// if ptwrite.payload() == 42 {
|
||||
// // Main enter
|
||||
// segments.push((Scope::Main, 0));
|
||||
// } else if ptwrite.payload() == 43 {
|
||||
// // Main exit
|
||||
// segments.push((Scope::PostRun, 0));
|
||||
// } else {
|
||||
// println!("GOT PTWRITE!!!!!: {ptwrite:?}");
|
||||
// }
|
||||
// }
|
||||
// Ok(_) => {}
|
||||
// Err(error) => println!("Got error: {error:?}"),
|
||||
// }
|
||||
// }
|
||||
// dbg!(&segments);
|
||||
// let cycles_main: u64 = segments
|
||||
// .iter()
|
||||
// .filter(|(scope, _)| matches!(scope, Scope::Main))
|
||||
// .map(|(_, cycles)| cycles)
|
||||
// .sum();
|
||||
// let cycles_total = segments.iter().map(|(_, cycles)| cycles).sum();
|
||||
// let total_seconds = cycles_total as f64 / 2_700_000_000.0;
|
||||
// let total_seconds_no_hypervisor = cycles_main as f64 / 2_700_000_000.0;
|
||||
// Ok(AnalyzeData {
|
||||
// packets: total,
|
||||
// cycles: cycles_total,
|
||||
// time: Duration::from_secs_f64(total_seconds),
|
||||
// time_outside_hypervisor: Duration::from_secs_f64(total_seconds_no_hypervisor),
|
||||
// })
|
||||
// }
|
||||
|
Loading…
x
Reference in New Issue
Block a user