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",
|
"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]]
|
[[package]]
|
||||||
name = "discard"
|
name = "discard"
|
||||||
version = "1.0.4"
|
version = "1.0.4"
|
||||||
@ -442,18 +422,6 @@ version = "0.2.174"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776"
|
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]]
|
[[package]]
|
||||||
name = "libipt-sys"
|
name = "libipt-sys"
|
||||||
version = "0.2.4"
|
version = "0.2.4"
|
||||||
@ -550,28 +518,6 @@ dependencies = [
|
|||||||
"minimal-lexical",
|
"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]]
|
[[package]]
|
||||||
name = "once_cell"
|
name = "once_cell"
|
||||||
version = "1.21.3"
|
version = "1.21.3"
|
||||||
@ -609,15 +555,6 @@ dependencies = [
|
|||||||
"syn 2.0.104",
|
"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]]
|
[[package]]
|
||||||
name = "proc-macro-hack"
|
name = "proc-macro-hack"
|
||||||
version = "0.5.20+deprecated"
|
version = "0.5.20+deprecated"
|
||||||
@ -637,7 +574,7 @@ dependencies = [
|
|||||||
name = "pt-dump-decoder"
|
name = "pt-dump-decoder"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libipt",
|
"libipt-sys",
|
||||||
"memmap2",
|
"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...");
|
println!("cargo:warning=Cloning and building QEMU-Nyx. This may take a while...");
|
||||||
shell(
|
shell(
|
||||||
out_dir,
|
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() {
|
let is_debug_build = match env::var("DEBUG").unwrap().as_str() {
|
||||||
|
@ -7,5 +7,6 @@ edition = "2024"
|
|||||||
|
|
||||||
|
|
||||||
[dependencies]
|
[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"
|
memmap2 = "0.9.7"
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
use libipt::enc_dec_builder::EncoderDecoderBuilder;
|
|
||||||
use libipt::packet::{Packet, PacketDecoder};
|
|
||||||
use memmap2::Mmap;
|
use memmap2::Mmap;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
@ -8,71 +6,278 @@ use std::time::Duration;
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct AnalyzeData {
|
pub struct AnalyzeData {
|
||||||
pub packets: u64,
|
pub total_time: Duration,
|
||||||
pub cycles: u64,
|
pub time_in_client: Duration,
|
||||||
pub time: Duration,
|
|
||||||
pub time_outside_hypervisor: Duration,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
enum Scope {
|
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,
|
Main,
|
||||||
PreRun,
|
PreRun,
|
||||||
PostRun,
|
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>> {
|
pub fn analyze_dump(path: impl AsRef<Path>) -> Result<AnalyzeData, Box<dyn Error>> {
|
||||||
let trace_file = File::open(path)?;
|
let trace_file = File::open(path)?;
|
||||||
let mmap = unsafe { Mmap::map(&trace_file)? };
|
let mmap = unsafe { Mmap::map(&trace_file)? };
|
||||||
|
|
||||||
let builder = EncoderDecoderBuilder::<PacketDecoder<()>>::new();
|
let mut events = vec![];
|
||||||
// I hope this is safe if the buffer is never written to
|
let mut state = DecoderState::Disabled {
|
||||||
let builder = unsafe { builder.buffer_from_raw(mmap.as_ptr() as *mut _, mmap.len()) };
|
enabled_kind: ScopeKind::PreRun,
|
||||||
|
start_tsc: None,
|
||||||
|
};
|
||||||
|
|
||||||
let mut decoder = builder.build()?;
|
unsafe {
|
||||||
// Required before it can be used
|
let mut config: libipt_sys::pt_config = std::mem::zeroed();
|
||||||
decoder.sync_forward()?;
|
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 decoder = libipt_sys::pt_evt_alloc_decoder(&config);
|
||||||
let mut total = 0u64;
|
if decoder.is_null() {
|
||||||
|
panic!("Could not create decoder");
|
||||||
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 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
|
let total_duration = filter_time(&events, |_| true);
|
||||||
.iter()
|
let duration_in_client = filter_time(&events, |kind| matches!(kind, ScopeKind::Main));
|
||||||
.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 {
|
Ok(AnalyzeData {
|
||||||
packets: total,
|
total_time: total_duration,
|
||||||
cycles: cycles_total,
|
time_in_client: duration_in_client,
|
||||||
time: Duration::from_secs_f64(total_seconds),
|
|
||||||
time_outside_hypervisor: Duration::from_secs_f64(total_seconds_no_hypervisor),
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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