diff --git a/fuzzers/wcet_qemu_sys/Cargo.toml b/fuzzers/wcet_qemu_sys/Cargo.toml index 1fedc8942a..1f69ba6957 100644 --- a/fuzzers/wcet_qemu_sys/Cargo.toml +++ b/fuzzers/wcet_qemu_sys/Cargo.toml @@ -21,3 +21,4 @@ hashbrown = { version = "0.11", features = ["serde", "ahash-compile-time-rng"], nix = "0.23.0" goblin = "0.4.2" either = "1.6.1" +num-traits = "0.2" diff --git a/fuzzers/wcet_qemu_sys/src/bin/fuzzer.rs b/fuzzers/wcet_qemu_sys/src/bin/fuzzer.rs index af43c4bd3b..a5bf2c827c 100644 --- a/fuzzers/wcet_qemu_sys/src/bin/fuzzer.rs +++ b/fuzzers/wcet_qemu_sys/src/bin/fuzzer.rs @@ -1,5 +1,6 @@ //! A singlethreaded QEMU fuzzer that can auto-restart. +use wcet_qemu_sys::worst::QemuHashMapObserver; use hashbrown::HashMap; use clap::{App, Arg}; use core::{cell::RefCell, time::Duration}; @@ -64,7 +65,7 @@ use libafl_qemu::{ clock::ClockFeedback, clock::QemuClockIncreaseFeedback }; -use wcet_qemu_sys::worst::{SortedFeedback,HitFeedback,HitcountsMapObserver,HitImprovingFeedback,LenTimeMaximizerCorpusScheduler}; +use wcet_qemu_sys::worst::{SortedFeedback,HitFeedback,HitImprovingFeedback,LenTimeMaximizerCorpusScheduler}; /// The fuzzer main @@ -276,7 +277,7 @@ fn fuzz( let edges = unsafe { &mut edges::EDGES_MAP }; let edges_counter = unsafe { &mut edges::MAX_EDGES_NUM }; let edges_observer = - HitcountsMapObserver::new(VariableMapObserver::new("edges", edges, edges_counter)); + QemuHashMapObserver::new(VariableMapObserver::new("edges", edges, edges_counter)); // Create an observation channel to keep track of the execution time // let time_observer = TimeObserver::new("time"); @@ -301,14 +302,14 @@ fn fuzz( let feedback = feedback_or!( // New maximization map feedback linked to the edges observer and the feedback state MaxMapFeedback::new_tracking(&feedback_state, &edges_observer, true, false), - // HitImprovingFeedback::new(target_map.clone()), + HitImprovingFeedback::new(target_map.clone(), &edges_observer), QemuClockIncreaseFeedback::default(), ClockFeedback::new_with_observer(&clock_observer) ); // A feedback to choose if an input is a solution or not - // let objective = HitFeedback::new(target_map,0.0); - let objective = SortedFeedback::new(); + let objective = HitFeedback::new(target_map,0.0,&edges_observer); + // let objective = SortedFeedback::new(); // create a State from scratch let mut state = state.unwrap_or_else(||{ diff --git a/fuzzers/wcet_qemu_sys/src/bin/showmap.rs b/fuzzers/wcet_qemu_sys/src/bin/showmap.rs index 3c00a127c9..8030fa7731 100644 --- a/fuzzers/wcet_qemu_sys/src/bin/showmap.rs +++ b/fuzzers/wcet_qemu_sys/src/bin/showmap.rs @@ -1,7 +1,8 @@ //! A singlethreaded QEMU fuzzer that can auto-restart. +use wcet_qemu_sys::worst::QemuHashMapObserver; use wcet_qemu_sys::{ - worst::{DumpMapFeedback,DummyFeedback,HitcountsMapObserver}, + worst::{DumpMapFeedback,DummyFeedback}, system_trace::QemuSystemStateHelper, }; use clap::{App, Arg}; @@ -262,13 +263,13 @@ fn fuzz( let edges = unsafe { &mut edges::EDGES_MAP }; let edges_counter = unsafe { &mut edges::MAX_EDGES_NUM }; let edges_observer = - HitcountsMapObserver::new(VariableMapObserver::new("edges", edges, edges_counter)); + QemuHashMapObserver::new(VariableMapObserver::new("edges", edges, edges_counter)); //========== Observe Execution Cycles let clock_observer = QemuClockObserver::default(); //========= Feedback-Function evaluate the Maps. Need to dump it for debugging and check if it reaches targets. - let feedback = DumpMapFeedback::with_dump(dump_edges); + let feedback = DumpMapFeedback::with_dump(dump_edges, &edges_observer); // A feedback to choose if an input is a solution or not let objective = DummyFeedback::new(false); diff --git a/fuzzers/wcet_qemu_sys/src/worst.rs b/fuzzers/wcet_qemu_sys/src/worst.rs index e7ef49345b..8d9eb3024f 100644 --- a/fuzzers/wcet_qemu_sys/src/worst.rs +++ b/fuzzers/wcet_qemu_sys/src/worst.rs @@ -1,3 +1,5 @@ +use num_traits::PrimInt; +use core::fmt::Debug; use core::cmp::Ordering::{Greater,Less,Equal}; use libafl::inputs::BytesInput; use libafl::inputs::HasTargetBytes; @@ -8,7 +10,6 @@ use core::marker::PhantomData; use libafl::corpus::MinimizerCorpusScheduler; use std::path::PathBuf; use std::fs; -use libafl::observers::VariableMapObserver; use hashbrown::{HashMap}; use libafl::observers::ObserversTuple; use libafl::executors::ExitKind; @@ -30,36 +31,23 @@ use libafl::{ observers::Observer, Error, }; - -/// Map observer with hitcounts postprocessing +//=================================================================== +/// A wrapper around some other [`MapObserver`], using [`QemuEdgesMapMetadata`] to offer a convinient Hashmap. #[derive(Serialize, Deserialize, Clone, Debug)] #[serde(bound = "M: serde::de::DeserializeOwned")] -pub struct HitcountsMapObserver +pub struct QemuHashMapObserver where M: serde::Serialize + serde::de::DeserializeOwned, + T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug, { base: M, - pub edgemap: HashMap<(u64,u64),u8>, + pub edgemap: HashMap<(u64,u64),T>, } -static COUNT_CLASS_LOOKUP: [u8; 256] = [ - 0, 1, 2, 4, 8, 8, 8, 8, 16, 16, 16, 16, 16, 16, 16, 16, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, -]; - -impl Observer for HitcountsMapObserver +impl Observer for QemuHashMapObserver where - M: MapObserver + Observer, + M: MapObserver + Observer, + T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug, S: HasMetadata, // Need to grab the HashMap from a Helper { #[inline] @@ -70,25 +58,18 @@ where #[inline] fn post_exec(&mut self, state: &mut S, input: &I) -> Result<(), Error> { - //new stuff - let original_hashmap=&state.metadata().get::().unwrap().map; + let original_hashmap=&state.metadata().get::().expect("QemuEdgesMapMetadata not found").map; for (key, val) in original_hashmap.iter() { self.edgemap.insert(*key,*self.base.get(*val as usize)); } - // println!("Post-Exec Len: {} Cap: {}",self.edgemap.len(),self.edgemap.capacity()); - // println!("{:#?}",self.edgemap); - //end new stuff - let cnt = self.usable_count(); - for i in 0..cnt { - *self.get_mut(i) = COUNT_CLASS_LOOKUP[*self.get(i) as usize]; - } self.base.post_exec(state, input) } } -impl Named for HitcountsMapObserver +impl Named for QemuHashMapObserver where M: Named + serde::Serialize + serde::de::DeserializeOwned, + T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug, { #[inline] fn name(&self) -> &str { @@ -96,9 +77,10 @@ where } } -impl HasLen for HitcountsMapObserver +impl HasLen for QemuHashMapObserver where M: MapObserver, + T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug, { #[inline] fn len(&self) -> usize { @@ -106,9 +88,10 @@ where } } -impl MapObserver for HitcountsMapObserver +impl MapObserver for QemuHashMapObserver where M: MapObserver, + T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug, { #[inline] fn map(&self) -> Option<&[u8]> { @@ -141,9 +124,10 @@ where } } -impl HitcountsMapObserver +impl QemuHashMapObserver where M: serde::Serialize + serde::de::DeserializeOwned, + T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug, { /// Creates a new [`MapObserver`] pub fn new(base: M) -> Self { @@ -156,15 +140,23 @@ where /// A [`HitFeedback`] reports as interesting when all predicted worst case edges have been matched. #[derive(Serialize, Deserialize, Clone, Debug)] -pub struct HitFeedback { - target_map: HashMap<(u64,u64),u8>, +#[serde(bound = "T: serde::de::DeserializeOwned")] +pub struct HitFeedback +where + T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug, + O: MapObserver, +{ + target_map: HashMap<(u64,u64),T>, target_msd: f64, + phantom: PhantomData<(O, T)>, } -impl Feedback for HitFeedback +impl Feedback for HitFeedback where I: Input, S: HasClientPerfMonitor, + T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug, + O: MapObserver, { fn is_interesting( &mut self, @@ -178,15 +170,17 @@ where EM: EventFirer, OT: ObserversTuple, { - let observer = _observers.match_name::>>("edges") - .expect("HitcountsMapObserver not found"); + let observer = _observers.match_name::>("edges") + .expect("QemuHashMapObserver not found"); if self.target_map.len() == 0 { return Ok(false) }; let mut sum_of_square_difference : u64 = 0; // does not include found edges not in target for (edg, val) in &self.target_map { match observer.edgemap.get(&edg) { - Some(x) => sum_of_square_difference+=((cmp::max(*x,*val)-cmp::min(*x,*val)) as u64).pow(2), - None => sum_of_square_difference+=(*val as u64).pow(2), + Some(x) => { + sum_of_square_difference+=((cmp::max(*x,*val)-cmp::min(*x,*val)).to_u64().unwrap()).pow(2); + }, + None => sum_of_square_difference+=((*val).to_u64().unwrap()).pow(2), } } let mean_sum_of_squares = (sum_of_square_difference as f64) / (self.target_map.len() as f64); @@ -200,99 +194,111 @@ where } } -impl Named for HitFeedback { +impl Named for HitFeedback +where + T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug, + O: MapObserver, +{ #[inline] fn name(&self) -> &str { "HitFeedback" } } -impl HitFeedback { +impl HitFeedback +where + T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug, + O: MapObserver, +{ /// Creates a new [`HitFeedback`] #[must_use] - pub fn new(target_map: HashMap<(u64,u64),u8>, target_msd: f64) -> Self { - Self {target_map: target_map, target_msd: target_msd} - } -} - -impl Default for HitFeedback { - fn default() -> Self { - Self::new(HashMap::new(),0.0) + pub fn new(target_map: HashMap<(u64,u64),T>, target_msd: f64, _map_observer: &O) -> Self { + Self {target_map: target_map, target_msd: target_msd, phantom: PhantomData} } } //=================================================================== -/// A [`MapHitIncreaseFeedback`] reports as interesting when the total number of used edges increases. -#[derive(Serialize, Deserialize, Clone, Debug)] -pub struct MapHitIncreaseFeedback { - record_high : u64, -} +// /// A [`MapHitIncreaseFeedback`] reports as interesting when the total number of used edges increases. +// #[derive(Serialize, Deserialize, Clone, Debug)] +// pub struct MapHitIncreaseFeedback { +// record_high : u64, +// } -impl Feedback for MapHitIncreaseFeedback -where - I: Input, - S: HasClientPerfMonitor, -{ - fn is_interesting( - &mut self, - _state: &mut S, - _manager: &mut EM, - _input: &I, - _observers: &OT, - _exit_kind: &ExitKind, - ) -> Result - where - EM: EventFirer, - OT: ObserversTuple, - { - let observer = _observers.match_name::>>("edges") - .expect("HitcountsMapObserver not found"); - let cur = observer.edgemap.values().fold(0,|a,b| a+(*b as u64)); - if cur > self.record_high { - self.record_high = cur; - return Ok(true); - } - return Ok(false); - } -} +// impl Feedback for MapHitIncreaseFeedback +// where +// I: Input, +// S: HasClientPerfMonitor, +// T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug, +// O: MapObserver, +// { +// fn is_interesting( +// &mut self, +// _state: &mut S, +// _manager: &mut EM, +// _input: &I, +// _observers: &OT, +// _exit_kind: &ExitKind, +// ) -> Result +// where +// EM: EventFirer, +// OT: ObserversTuple, +// { +// let observer = _observers.match_name::>("edges") +// .expect("QemuHashMapObserver not found"); +// let cur = observer.edgemap.values().fold(0,|a,b| a+(*b as u64)); +// if cur > self.record_high { +// self.record_high = cur; +// return Ok(true); +// } +// return Ok(false); +// } +// } -impl Named for MapHitIncreaseFeedback { - #[inline] - fn name(&self) -> &str { - "HitFeedback" - } -} +// impl Named for MapHitIncreaseFeedback { +// #[inline] +// fn name(&self) -> &str { +// "HitFeedback" +// } +// } -impl MapHitIncreaseFeedback { - /// Creates a new [`HitFeedback`] - #[must_use] - pub fn new() -> Self { - Self {record_high: 0} - } -} +// impl MapHitIncreaseFeedback { +// /// Creates a new [`HitFeedback`] +// #[must_use] +// pub fn new() -> Self { +// Self {record_high: 0} +// } +// } -impl Default for MapHitIncreaseFeedback { - fn default() -> Self { - Self::new() - } -} +// impl Default for MapHitIncreaseFeedback { +// fn default() -> Self { +// Self::new() +// } +// } //=================================================================== /// A [`HitFeedback`] reports as interesting when all predicted worst case edges have been matched. #[derive(Serialize, Deserialize, Clone, Debug)] -pub struct HitImprovingFeedback { - target_map: HashMap<(u64,u64),u8>, +#[serde(bound = "T: serde::de::DeserializeOwned")] +pub struct HitImprovingFeedback +where + T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug, + O: MapObserver, +{ + target_map: HashMap<(u64,u64),T>, best_msd: f64, + phantom: PhantomData<(O, T)>, } -impl Feedback for HitImprovingFeedback +impl Feedback for HitImprovingFeedback where I: Input, S: HasClientPerfMonitor, + T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug, + O: MapObserver, { fn is_interesting( &mut self, @@ -306,15 +312,17 @@ where EM: EventFirer, OT: ObserversTuple, { - let observer = _observers.match_name::>>("edges") - .expect("HitcountsMapObserver not found"); + let observer = _observers.match_name::>("edges") + .expect("QemuHashMapObserver not found"); if self.target_map.len() == 0 { return Ok(false) }; let mut sum_of_square_difference : u64 = 0; // does not include found edges not in target for (edg, val) in &self.target_map { match observer.edgemap.get(&edg) { - Some(x) => sum_of_square_difference+=((cmp::max(*x,*val)-cmp::min(*x,*val)) as u64).pow(2), - None => sum_of_square_difference+=(*val as u64).pow(2), + Some(x) => { + sum_of_square_difference+=((cmp::max(*x,*val)-cmp::min(*x,*val)).to_u64().unwrap()).pow(2); + }, + None => sum_of_square_difference+=((*val).to_u64().unwrap()).pow(2), } } let mean_sum_of_squares = (sum_of_square_difference as f64) / (self.target_map.len() as f64); @@ -329,38 +337,47 @@ where } } -impl Named for HitImprovingFeedback { +impl Named for HitImprovingFeedback +where + T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug, + O: MapObserver, +{ #[inline] fn name(&self) -> &str { - "HitFeedback" + "HitImprovingFeedback" } } -impl HitImprovingFeedback { - /// Creates a new [`HitFeedback`] +impl HitImprovingFeedback +where + T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug, + O: MapObserver, +{ + /// Creates a new [`HitImprovingFeedback`] #[must_use] - pub fn new(target_map: HashMap<(u64,u64),u8>) -> Self { - Self {target_map: target_map, best_msd: f64::MAX} - } -} - -impl Default for HitImprovingFeedback { - fn default() -> Self { - Self::new(HashMap::new()) + pub fn new(target_map: HashMap<(u64,u64),T>, _map_observer: &O) -> Self { + Self {target_map: target_map, best_msd: f64::MAX, phantom: PhantomData} } } //=========================== Debugging Feedback /// A [`Feedback`] meant to dump the edgemap for debugging. #[derive(Debug)] -pub struct DumpMapFeedback { - dumpfile: Option +pub struct DumpMapFeedback +where + T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug, + O: MapObserver, +{ + dumpfile: Option, + phantom: PhantomData<(O, T)>, } -impl Feedback for DumpMapFeedback +impl Feedback for DumpMapFeedback where I: Input, S: HasClientPerfMonitor, + T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug, + O: MapObserver, { fn is_interesting( &mut self, @@ -374,8 +391,8 @@ where EM: EventFirer, OT: ObserversTuple, { - let observer = _observers.match_name::>>("edges") - .expect("HitcountsMapObserver not found"); + let observer = _observers.match_name::>("edges") + .expect("QemuHashMapObserver not found"); match &self.dumpfile { Some(s) => { fs::write(s,ron::to_string(&observer.edgemap).expect("Error serializing hashmap")).expect("Can not dump to file"); @@ -387,27 +404,29 @@ where } } -impl Named for DumpMapFeedback { +impl Named for DumpMapFeedback +where + T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug, + O: MapObserver, +{ #[inline] fn name(&self) -> &str { "HitFeedback" } } -impl DumpMapFeedback { +impl DumpMapFeedback +where + T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug, + O: MapObserver, +{ /// Creates a new [`HitFeedback`] #[must_use] - pub fn new() -> Self { - Self {dumpfile: None} + pub fn new(_map_observer: &O) -> Self { + Self {dumpfile: None, phantom: PhantomData} } - pub fn with_dump(dumpfile: Option) -> Self { - Self {dumpfile: dumpfile} - } -} - -impl Default for DumpMapFeedback { - fn default() -> Self { - Self::new() + pub fn with_dump(dumpfile: Option,_map_observer: &O) -> Self { + Self {dumpfile: dumpfile, phantom: PhantomData} } } @@ -511,6 +530,8 @@ where } } +//=================================================================== + /// A Feedback reporting if the Input consists of strictly decreasing bytes. #[derive(Serialize, Deserialize, Clone, Debug)] pub struct SortedFeedback {