introduce JobInstance, TaskJob

This commit is contained in:
Alwin Berger 2024-10-28 08:10:37 +01:00
parent d8a15adb1d
commit d89d5e3e5e
2 changed files with 132 additions and 4 deletions

View File

@ -36,6 +36,16 @@ pub enum CaptureEvent {
Undefined, 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 // ============================= State info
/// Raw info Dump from Qemu /// Raw info Dump from Qemu
@ -356,6 +366,107 @@ fn get_task_names(trace: &Vec<ReducedFreeRTOSSystemState>) -> HashSet<String> {
libafl_bolts::impl_serdeany!(AtomicBasicBlock); 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<u64>,
pub abbs: Vec<AtomicBasicBlock>,
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<H: Hasher>(&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<u8>,
pub woet_ticks: u64,
pub woet_per_abb: Vec<u64>,
pub abbs: Vec<AtomicBasicBlock>,
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<H: Hasher>(&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 // ============================= Per testcase metadata
// Wrapper around Vec<RefinedFreeRTOSSystemState> to attach as Metadata // Wrapper around Vec<RefinedFreeRTOSSystemState> to attach as Metadata

View File

@ -17,6 +17,7 @@ use std::collections::VecDeque;
use std::borrow::Cow; use std::borrow::Cow;
use super::helpers::USR_ISR_SYMBOLS; use super::helpers::USR_ISR_SYMBOLS;
use super::JobInstance;
use super::{ AtomicBasicBlock, ExecInterval}; use super::{ AtomicBasicBlock, ExecInterval};
use super::{ use super::{
CURRENT_SYSTEMSTATE_VEC, CURRENT_SYSTEMSTATE_VEC,
@ -63,7 +64,7 @@ where
fn post_exec(&mut self, _state: &mut S, _input: &S::Input, _exit_kind: &ExitKind) -> Result<(), Error> { 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 {self.last_run = invalidate_ineffective_isr(refine_system_states(&mut CURRENT_SYSTEMSTATE_VEC));}
unsafe { 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); // fix_broken_trace(&mut temp.1);
self.last_run = temp.0.clone(); self.last_run = temp.0.clone();
// println!("{:?}",temp); // println!("{:?}",temp);
@ -78,8 +79,24 @@ where
let releases = get_releases(&self.last_trace, &self.last_states); let releases = get_releases(&self.last_trace, &self.last_states);
// println!("Releases: {:?}",&releases); // println!("Releases: {:?}",&releases);
let jobs_done = JOBS_DONE.split_off(0); let jobs_done = JOBS_DONE.split_off(0);
(self.job_instances, self.do_report) = get_release_response_pairs(&releases, &jobs_done); let (job_instances, do_report) = get_release_response_pairs(&releases, &jobs_done);
// println!("Instances: {:?}",&self.job_instances); 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::<Vec<_>>();
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::<Vec<_>>();
println!("Instances: {:?}",&job_instances);
let observer = &self; let observer = &self;
let mut worst_case_per_task = HashMap::new(); let mut worst_case_per_task = HashMap::new();
observer.job_instances.iter().for_each(|x| { observer.job_instances.iter().for_each(|x| {
@ -507,7 +524,7 @@ fn states2intervals(trace: Vec<ReducedFreeRTOSSystemState>, meta: Vec<(u64, Capt
tick_spend_preempted: 0, tick_spend_preempted: 0,
abb: None abb: None
}); });
reads.push(meta[i].4.clone()); reads.push(meta[i+1].4.clone());
last_hash = next_hash; last_hash = next_hash;
edges.push((meta[i].3.1, meta[i+1].3.0)); edges.push((meta[i].3.1, meta[i+1].3.0));
} }