From d89d5e3e5ef3ed2b7645ef4eac78bb02080dfd14 Mon Sep 17 00:00:00 2001 From: Alwin Berger Date: Mon, 28 Oct 2024 08:10:37 +0100 Subject: [PATCH] introduce JobInstance, TaskJob --- fuzzers/FRET/src/systemstate/mod.rs | 111 ++++++++++++++++++++++ fuzzers/FRET/src/systemstate/observers.rs | 25 ++++- 2 files changed, 132 insertions(+), 4 deletions(-) diff --git a/fuzzers/FRET/src/systemstate/mod.rs b/fuzzers/FRET/src/systemstate/mod.rs index ce308f361a..c76bd4b0c4 100644 --- a/fuzzers/FRET/src/systemstate/mod.rs +++ b/fuzzers/FRET/src/systemstate/mod.rs @@ -36,6 +36,16 @@ pub enum CaptureEvent { Undefined, } +/* + Hierarchy of tracing data: + - RawFreeRTOSSystemState: Raw data from Qemu, represents a particular instant + - ReducedFreeRTOSSystemState: Generalized state of the system, without execution context + - ExecInterval: Some interval of execution between instants + - AtomicBasicBlock: A single-entry multiple-exit region between api calls. May be used referenced in multiple intervals. + - JobInstance: A single execution of a task, records the place and input read + - TaskJob: Generalized Job instance, records the worst inputs seen so far +*/ + // ============================= State info /// Raw info Dump from Qemu @@ -356,6 +366,107 @@ fn get_task_names(trace: &Vec) -> HashSet { libafl_bolts::impl_serdeany!(AtomicBasicBlock); +// ============================= Job instances + +#[derive(Debug, Default, Serialize, Deserialize, Clone)] +pub struct JobInstance { + pub name: String, + pub mem_reads: Vec<(u32, u8)>, + pub release: u64, + pub response: u64, + pub exec_ticks: u64, + pub ticks_per_abb: Vec, + pub abbs: Vec, + hash_cache: u64 +} + +impl PartialEq for JobInstance { + fn eq(&self, other: &Self) -> bool { + self.abbs == other.abbs + } +} +impl Eq for JobInstance {} +impl Hash for JobInstance { + fn hash(&self, state: &mut H) { + self.abbs.hash(state); + } +} +impl JobInstance { + pub fn get_hash(&mut self) -> u64 { + if self.hash_cache == 0 { + let mut s = DefaultHasher::new(); + self.hash(&mut s); + self.hash_cache = s.finish(); + } + self.hash_cache + } + pub fn get_hash_cached(&self) -> u64 { + if self.hash_cache == 0 { + let mut s = DefaultHasher::new(); + self.hash(&mut s); + s.finish() + } else { + self.hash_cache + } + } +} + +// ============================= Generalized job instances + +#[derive(Debug, Default, Serialize, Deserialize, Clone)] +pub struct TaskJob { + pub name: String, + pub worst_bytes: Vec, + pub woet_ticks: u64, + pub woet_per_abb: Vec, + pub abbs: Vec, + hash_cache: u64 +} + +impl PartialEq for TaskJob { + fn eq(&self, other: &Self) -> bool { + self.abbs == other.abbs + } +} +impl Eq for TaskJob {} +impl Hash for TaskJob { + fn hash(&self, state: &mut H) { + self.abbs.hash(state); + } +} +impl TaskJob { + pub fn get_hash(&mut self) -> u64 { + if self.hash_cache == 0 { + let mut s = DefaultHasher::new(); + self.hash(&mut s); + self.hash_cache = s.finish(); + } + self.hash_cache + } + pub fn get_hash_cached(&self) -> u64 { + if self.hash_cache == 0 { + let mut s = DefaultHasher::new(); + self.hash(&mut s); + s.finish() + } else { + self.hash_cache + } + } + pub fn try_update(&mut self, other: &mut JobInstance) -> bool { + assert_eq!(self.get_hash(), other.get_hash()); + let mut ret = false; + if other.exec_ticks > self.woet_ticks { + self.woet_ticks = other.exec_ticks; + self.woet_per_abb = other.ticks_per_abb.clone(); + other.mem_reads.sort_by(|a,b| a.0.cmp(&b.0)); + self.worst_bytes = other.mem_reads.iter().map(|x| x.1).collect(); + ret = true; + } + ret + } +} + + // ============================= Per testcase metadata // Wrapper around Vec to attach as Metadata diff --git a/fuzzers/FRET/src/systemstate/observers.rs b/fuzzers/FRET/src/systemstate/observers.rs index fe1208cd6f..7561339d53 100644 --- a/fuzzers/FRET/src/systemstate/observers.rs +++ b/fuzzers/FRET/src/systemstate/observers.rs @@ -17,6 +17,7 @@ use std::collections::VecDeque; use std::borrow::Cow; use super::helpers::USR_ISR_SYMBOLS; +use super::JobInstance; use super::{ AtomicBasicBlock, ExecInterval}; use super::{ CURRENT_SYSTEMSTATE_VEC, @@ -63,7 +64,7 @@ where fn post_exec(&mut self, _state: &mut S, _input: &S::Input, _exit_kind: &ExitKind) -> Result<(), Error> { // unsafe {self.last_run = invalidate_ineffective_isr(refine_system_states(&mut CURRENT_SYSTEMSTATE_VEC));} unsafe { - let temp = refine_system_states(CURRENT_SYSTEMSTATE_VEC.drain(..).collect()); + let temp = refine_system_states(CURRENT_SYSTEMSTATE_VEC.split_off(0)); // fix_broken_trace(&mut temp.1); self.last_run = temp.0.clone(); // println!("{:?}",temp); @@ -78,8 +79,24 @@ where let releases = get_releases(&self.last_trace, &self.last_states); // println!("Releases: {:?}",&releases); let jobs_done = JOBS_DONE.split_off(0); - (self.job_instances, self.do_report) = get_release_response_pairs(&releases, &jobs_done); - // println!("Instances: {:?}",&self.job_instances); + let (job_instances, do_report) = get_release_response_pairs(&releases, &jobs_done); + self.do_report = do_report; + let job_instances = job_instances.into_iter().map(|x| { + let intervals = self.last_trace.iter().enumerate().filter(|y| y.1.start_tick <= x.1 && y.1.end_tick >= x.0 && x.2 == y.1.get_task_name_unchecked()).map(|(idx,x)| (x, &self.last_reads[idx])).collect::>(); + let (abbs, rest) : (Vec<_>, Vec<_>) = intervals.chunk_by(|a,b| a.0.abb.as_ref().unwrap().instance_eq(b.0.abb.as_ref().unwrap())).into_iter().map(|intervals| (intervals[0].0.abb.as_ref().unwrap().clone(), (intervals.iter().fold(0, |sum, x| sum+x.0.get_exec_time()), intervals.iter().fold(HashSet::new(), |mut sum, x| {sum.extend(x.1.iter()); sum})))).unzip(); + let (ticks_per_abb, mem_reads) : (Vec<_>, Vec<_>) = rest.into_iter().unzip(); + JobInstance { + name: x.2.clone(), + mem_reads: mem_reads.into_iter().flatten().map(|x| (x,0)).collect(), // TODO: add read values + release: x.0, + response: x.1, + exec_ticks: ticks_per_abb.iter().sum(), + ticks_per_abb: ticks_per_abb, + abbs: abbs, + hash_cache: 0 + } + }).collect::>(); + println!("Instances: {:?}",&job_instances); let observer = &self; let mut worst_case_per_task = HashMap::new(); observer.job_instances.iter().for_each(|x| { @@ -507,7 +524,7 @@ fn states2intervals(trace: Vec, meta: Vec<(u64, Capt tick_spend_preempted: 0, abb: None }); - reads.push(meta[i].4.clone()); + reads.push(meta[i+1].4.clone()); last_hash = next_hash; edges.push((meta[i].3.1, meta[i+1].3.0)); }