implement STGSnippetStage, fix missing metadata

This commit is contained in:
Alwin Berger 2024-10-29 14:07:52 +01:00
parent 3d0c0247b7
commit 013f3db487
9 changed files with 185 additions and 62 deletions

View File

@ -70,3 +70,4 @@ clap = { version = "4.4.11", features = ["derive"] }
csv = "1.3.0" csv = "1.3.0"
log = "0.4" log = "0.4"
simple_moving_average = "1.0.2" simple_moving_average = "1.0.2"
itertools = "0.13.0"

View File

@ -15,7 +15,7 @@ edges::{self, edges_map_mut_ptr, QemuEdgeCoverageHelper, MAX_EDGES_FOUND}, elf::
}; };
use rand::{SeedableRng, StdRng, Rng}; use rand::{SeedableRng, StdRng, Rng};
use crate::{ use crate::{
systemstate::{self, feedbacks::{DumpSystraceFeedback, SystraceErrorFeedback}, helpers::{get_function_range, load_symbol, try_load_symbol, QemuSystemStateHelper}, mutational::{input_bytes_to_interrupt_times, InterruptShiftStage}, observers::QemuSystemStateObserver, schedulers::{GenerationScheduler, LongestTraceScheduler}, stg::{stg_map_mut_slice, GraphMaximizerCorpusScheduler, STGEdge, STGNode, StgFeedback, MAX_STG_NUM}}, time::{ systemstate::{self, feedbacks::{DumpSystraceFeedback, SystraceErrorFeedback}, helpers::{get_function_range, load_symbol, try_load_symbol, QemuSystemStateHelper}, mutational::{input_bytes_to_interrupt_times, InterruptShiftStage, STGSnippetStage}, observers::QemuSystemStateObserver, schedulers::{GenerationScheduler, LongestTraceScheduler}, stg::{stg_map_mut_slice, GraphMaximizerCorpusScheduler, STGEdge, STGNode, StgFeedback, MAX_STG_NUM}}, time::{
clock::{ClockTimeFeedback, IcHist, QemuClockIncreaseFeedback, QemuClockObserver, FUZZ_START_TIMESTAMP, QEMU_ICOUNT_SHIFT, QEMU_ISNS_PER_USEC}, qemustate::QemuStateRestoreHelper, worst::{AlwaysTrueFeedback, ExecTimeIncFeedback, TimeMaximizerCorpusScheduler, TimeProbMassScheduler, TimeStateMaximizerCorpusScheduler} clock::{ClockTimeFeedback, IcHist, QemuClockIncreaseFeedback, QemuClockObserver, FUZZ_START_TIMESTAMP, QEMU_ICOUNT_SHIFT, QEMU_ISNS_PER_USEC}, qemustate::QemuStateRestoreHelper, worst::{AlwaysTrueFeedback, ExecTimeIncFeedback, TimeMaximizerCorpusScheduler, TimeProbMassScheduler, TimeStateMaximizerCorpusScheduler}
} }
}; };
@ -478,7 +478,7 @@ let run_client = |state: Option<_>, mut mgr, _core_id| {
#[cfg(feature = "sched_afl",)] #[cfg(feature = "sched_afl",)]
let scheduler = TimeMaximizerCorpusScheduler::new(&edges_observer,TimeProbMassScheduler::new()); let scheduler = TimeMaximizerCorpusScheduler::new(&edges_observer,TimeProbMassScheduler::new());
#[cfg(feature = "sched_stg")] #[cfg(feature = "sched_stg")]
let scheduler = GraphMaximizerCorpusScheduler::new(&stg_coverage_observer,TimeProbMassScheduler::new()); let scheduler = GraphMaximizerCorpusScheduler::non_metadata_removing(&stg_coverage_observer,TimeProbMassScheduler::new());
#[cfg(feature = "sched_genetic")] #[cfg(feature = "sched_genetic")]
let scheduler = GenerationScheduler::new(); let scheduler = GenerationScheduler::new();
@ -520,7 +520,8 @@ let run_client = |state: Option<_>, mut mgr, _core_id| {
let mutator = StdScheduledMutator::new(mutations); let mutator = StdScheduledMutator::new(mutations);
let stages = (systemstate::report::SchedulerStatsStage::default(),()); let stages = (systemstate::report::SchedulerStatsStage::default(),());
let mut stages = (StdMutationalStage::new(mutator), stages); let stages = (StdMutationalStage::new(mutator), stages);
let mut stages = (STGSnippetStage::new(input_addr), stages);
#[cfg(feature = "fuzz_int")] #[cfg(feature = "fuzz_int")]
let mut stages = (InterruptShiftStage::new(&interrupt_config), stages); let mut stages = (InterruptShiftStage::new(&interrupt_config), stages);

View File

@ -192,9 +192,9 @@ where
let names : Vec<String> = observer.last_run.iter().map(|x| x.current_task.task_name.clone()).collect(); let names : Vec<String> = observer.last_run.iter().map(|x| x.current_task.task_name.clone()).collect();
match &self.dumpfile { match &self.dumpfile {
Some(s) => { Some(s) => {
let per_task_metadata = if let Some(worst_instance) = observer.job_instances.iter().filter(|x| Some(x.2.clone()) == observer.select_task).max_by(|a,b| (a.1-a.0).cmp(&(b.1-b.0))) { let per_task_metadata = if let Some(worst_instance) = observer.job_instances.iter().filter(|x| Some(&x.name) == observer.select_task.as_ref()).max_by(|a,b| (a.response-a.release).cmp(&(b.response-b.release))) {
// extract computation time spent in each task and abb // extract computation time spent in each task and abb
let t : Vec<_> = observer.last_trace.iter().filter(|x| x.start_tick < worst_instance.1 && x.end_tick > worst_instance.0 ).cloned().collect(); let t : Vec<_> = observer.last_trace.iter().filter(|x| x.start_tick < worst_instance.response && x.end_tick > worst_instance.release ).cloned().collect();
// task_name -> addr -> (count, time) // task_name -> addr -> (count, time)
let mut ret : HashMap<String, HashMap<u32, (usize, usize, u64)>> = HashMap::new(); let mut ret : HashMap<String, HashMap<u32, (usize, usize, u64)>> = HashMap::new();
let mut t2 = t.clone(); let mut t2 = t.clone();
@ -212,7 +212,7 @@ where
} }
}); });
}); });
dbg!(&ret); // dbg!(&ret);
ret ret
} else {HashMap::new()}; } else {HashMap::new()};
std::fs::write(s,ron::to_string(&(&observer.last_trace,&observer.last_states,&observer.job_instances,per_task_metadata)).expect("Error serializing hashmap")).expect("Can not dump to file"); std::fs::write(s,ron::to_string(&(&observer.last_trace,&observer.last_states,&observer.job_instances,per_task_metadata)).expect("Error serializing hashmap")).expect("Can not dump to file");

View File

@ -8,6 +8,7 @@ use std::hash::Hasher;
use std::hash::Hash; use std::hash::Hash;
use hashbrown::HashMap; use hashbrown::HashMap;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use itertools::Itertools;
use freertos::TCB_t; use freertos::TCB_t;
@ -452,18 +453,34 @@ impl TaskJob {
self.hash_cache self.hash_cache
} }
} }
pub fn try_update(&mut self, other: &mut JobInstance) -> bool { pub fn try_update(&mut self, other: &JobInstance) -> bool {
assert_eq!(self.get_hash(), other.get_hash()); assert_eq!(self.get_hash(), other.get_hash_cached());
let mut ret = false; let mut ret = false;
if other.exec_ticks > self.woet_ticks { if other.exec_ticks > self.woet_ticks {
self.woet_ticks = other.exec_ticks; self.woet_ticks = other.exec_ticks;
self.woet_per_abb = other.ticks_per_abb.clone(); 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().sorted_by(|a,b| a.0.cmp(&b.0)).map(|x| x.1).collect();
self.worst_bytes = other.mem_reads.iter().map(|x| x.1).collect();
ret = true; ret = true;
} }
ret ret
} }
pub fn from_instance(input: &JobInstance) -> Self {
let c = input.get_hash_cached();
Self {
name: input.name.clone(),
worst_bytes: input.mem_reads.iter().map(|x| x.1.clone()).collect(),
woet_ticks: input.exec_ticks,
woet_per_abb: input.ticks_per_abb.clone(),
abbs: input.abbs.clone(),
hash_cache: c
}
}
pub fn map_bytes_onto(&self, input: &JobInstance, offset: Option<u32>) -> Vec<(u32,u8)> {
if input.mem_reads.len() == 0 {return vec![];}
let ret = input.mem_reads.iter().take(self.worst_bytes.len()).enumerate().filter_map(|(idx,(addr,oldbyte))| if self.worst_bytes[idx]!=*oldbyte {Some((*addr-offset.unwrap_or_default(), self.worst_bytes[idx]))} else {None}).collect();
// eprintln!("Mapped: {:?}", ret);
ret
}
} }

View File

@ -9,7 +9,7 @@ use libafl_bolts::{rands::{
random_seed, Rand, StdRand random_seed, Rand, StdRand
}, Named}; }, Named};
use libafl::{ use libafl::{
common::{HasMetadata, HasNamedMetadata}, corpus::{self, Corpus}, events::{Event, EventFirer, LogSeverity}, fuzzer::Evaluator, inputs::{HasMutatorBytes, HasTargetBytes, Input, MultipartInput}, mark_feature_time, prelude::{new_hash_feedback, AggregatorOps, CorpusId, MutationResult, Mutator, UserStats, UserStatsValue, UsesInput}, stages::Stage, start_timer, state::{HasCorpus, HasRand, MaybeHasClientPerfMonitor, UsesState}, Error common::{HasMetadata, HasNamedMetadata}, corpus::{self, Corpus}, events::{Event, EventFirer, EventProcessor, LogSeverity}, fuzzer::Evaluator, inputs::{HasMutatorBytes, HasTargetBytes, Input, MultipartInput}, mark_feature_time, prelude::{new_hash_feedback, AggregatorOps, CorpusId, MutationResult, Mutator, UserStats, UserStatsValue, UsesInput}, stages::Stage, start_timer, state::{HasCorpus, HasRand, MaybeHasClientPerfMonitor, UsesState}, Error
}; };
use libafl::prelude::State; use libafl::prelude::State;
use petgraph::{graph::NodeIndex, graph::{self, DiGraph}}; use petgraph::{graph::NodeIndex, graph::{self, DiGraph}};
@ -19,7 +19,7 @@ use std::borrow::Cow;
use simple_moving_average::SMA; use simple_moving_average::SMA;
use super::stg::{STGEdge, STGNode}; use super::{stg::{STGEdge, STGNode}, JobInstance};
// pub static mut MINIMUM_INTER_ARRIVAL_TIME : u32 = 1000 /*us*/ * QEMU_ISNS_PER_USEC; // pub static mut MINIMUM_INTER_ARRIVAL_TIME : u32 = 1000 /*us*/ * QEMU_ISNS_PER_USEC;
// one isn per 2**4 ns // one isn per 2**4 ns
@ -88,7 +88,7 @@ pub fn try_force_new_branches(interrupt_ticks : &[u32], fbs: &STGFeedbackState,
for (num,&interrupt_time) in interrupt_ticks.iter().enumerate() { for (num,&interrupt_time) in interrupt_ticks.iter().enumerate() {
let lower_bound = if num==0 {FIRST_INT} else {interrupt_ticks[num-1].saturating_add(config.1 * QEMU_ISNS_PER_USEC)}; let lower_bound = if num==0 {FIRST_INT} else {interrupt_ticks[num-1].saturating_add(config.1 * QEMU_ISNS_PER_USEC)};
let next = if interrupt_ticks.len()>num+1 {interrupt_ticks[num+1]} else {u32::MAX}; let next = if interrupt_ticks.len()>num+1 {interrupt_ticks[num+1]} else {u32::MAX};
for exec_interval in meta.intervals.iter().filter(|x| x.start_tick >= lower_bound as u64 && x.start_tick < next as u64) { for exec_interval in meta.intervals().iter().filter(|x| x.start_tick >= lower_bound as u64 && x.start_tick < next as u64) {
if !(exec_interval.start_capture.0==CaptureEvent::ISRStart) { // shortcut to skip interrupt handers without node lookup if !(exec_interval.start_capture.0==CaptureEvent::ISRStart) { // shortcut to skip interrupt handers without node lookup
let node_index = fbs.state_abb_hash_index.get(&exec_interval.get_hash_index()).unwrap(); let node_index = fbs.state_abb_hash_index.get(&exec_interval.get_hash_index()).unwrap();
if !has_interrupt_handler_non_systick(&fbs.graph, node_index.clone()) { if !has_interrupt_handler_non_systick(&fbs.graph, node_index.clone()) {
@ -306,8 +306,8 @@ where
// calculate hits and identify snippets // calculate hits and identify snippets
let mut last_m = false; let mut last_m = false;
let mut marks : Vec<(&ExecInterval, usize, usize)>= vec![]; // 1: got interrupted, 2: interrupt handler let mut marks : Vec<(&ExecInterval, usize, usize)>= vec![]; // 1: got interrupted, 2: interrupt handler
for i in 0..trace.intervals.len() { for i in 0..trace.intervals().len() {
let curr = &trace.intervals[i]; let curr = &trace.intervals()[i];
let m = old_interrupt_times.iter().any(|x| (curr.start_tick..curr.end_tick).contains(&(*x as u64))); let m = old_interrupt_times.iter().any(|x| (curr.start_tick..curr.end_tick).contains(&(*x as u64)));
if m { if m {
marks.push((curr, i, 1)); marks.push((curr, i, 1));
@ -323,7 +323,7 @@ where
for i in 0..old_interrupt_times.len() { for i in 0..old_interrupt_times.len() {
// bounds based on minimum inter-arrival time // bounds based on minimum inter-arrival time
let mut lb = FIRST_INT; let mut lb = FIRST_INT;
let mut ub : u32 = trace.intervals[trace.intervals.len()-1].end_tick.try_into().expect("ticks > u32"); let mut ub : u32 = trace.intervals()[trace.intervals().len()-1].end_tick.try_into().expect("ticks > u32");
if i > 0 { if i > 0 {
// use the new times, because changes to preceding timings are not accounted for yet // use the new times, because changes to preceding timings are not accounted for yet
lb = u32::saturating_add(new_interrupt_times[i-1], interrup_config.1 * QEMU_ISNS_PER_USEC); lb = u32::saturating_add(new_interrupt_times[i-1], interrup_config.1 * QEMU_ISNS_PER_USEC);
@ -453,18 +453,23 @@ where
pub fn try_worst_snippets(bytes : &[u8], fbs: &STGFeedbackState, meta: &STGNodeMetadata) -> Option<Vec<u8>> { pub fn try_worst_snippets(bytes : &[u8], fbs: &STGFeedbackState, meta: &STGNodeMetadata) -> Option<Vec<u8>> {
let mut new = false; let mut new = false;
let mut ret = Vec::new(); let mut ret = Vec::new();
for (num,interval) in meta.intervals.iter().enumerate() { for (num,interval) in meta.intervals().iter().enumerate() {
todo!(); todo!();
} }
if new {Some(ret)} else {None} if new {Some(ret)} else {None}
} }
static mut num_snippet_stage_execs : u64 = 0;
static mut num_snippet_rerun : u64 = 0;
static mut num_snippet_success : u64 = 0;
/// The default mutational stage /// The default mutational stage
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default)]
pub struct STGSnippetStage<E, EM, Z> { pub struct STGSnippetStage<E, EM, Z> {
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
phantom: PhantomData<(E, EM, Z)>, phantom: PhantomData<(E, EM, Z)>,
input_addr: u32
} }
impl<E, EM, Z> STGSnippetStage<E, EM, Z> impl<E, EM, Z> STGSnippetStage<E, EM, Z>
@ -474,8 +479,36 @@ where
Z: Evaluator<E, EM>, Z: Evaluator<E, EM>,
Z::State: MaybeHasClientPerfMonitor + HasCorpus + HasRand, Z::State: MaybeHasClientPerfMonitor + HasCorpus + HasRand,
{ {
pub fn new() -> Self { pub fn new(input_addr: u32) -> Self {
Self { phantom: PhantomData } Self { phantom: PhantomData, input_addr }
}
}
impl<E, EM, Z, I> STGSnippetStage<E, EM, Z>
where
E: UsesState<State = Z::State>,
EM: UsesState<State = Z::State>,
EM: EventFirer,
Z: Evaluator<E, EM>,
Z::State: MaybeHasClientPerfMonitor + HasCorpus + HasRand + HasMetadata + HasNamedMetadata,
<Z::State as UsesInput>::Input: Input,
Z::State: UsesInput<Input = MultipartInput<I>>,
I: HasMutatorBytes + Default
{
fn report_stats(&self, state: &mut <STGSnippetStage<E, EM, Z> as UsesState>::State, manager: &mut EM) {
unsafe {
let _ = manager.fire(
state,
Event::UpdateUserStats {
name: Cow::from("STGSnippetStage"),
value: UserStats::new(
UserStatsValue::String(Cow::from(format!("{} -> {}/{} {:.1}% ", num_snippet_stage_execs, num_snippet_success, num_snippet_rerun, num_snippet_success as f32 * 100.0 / num_snippet_rerun as f32))),
AggregatorOps::None,
),
phantom: PhantomData,
},
);
}
} }
} }
@ -500,24 +533,46 @@ where
let mut myrand = StdRand::new(); let mut myrand = StdRand::new();
myrand.set_seed(state.rand_mut().next()); myrand.set_seed(state.rand_mut().next());
let mut do_rerun = false;
let current_case = state.current_testcase()?; let current_case = state.current_testcase()?;
let old_input = current_case.input().as_ref().unwrap(); let old_input = current_case.input().as_ref().unwrap();
let mut new_input = old_input.clone(); let mut new_input = old_input.clone();
if let Some(bytes) = old_input.parts_by_name("bytes").next() { let new_bytes = new_input.parts_by_name_mut("bytes").next().expect("bytes not found in multipart input").1.bytes_mut();
let new_bytes = new_input.parts_by_name("bytes").next(); // dbg!(current_case.metadata_map());
if let Some(meta) = current_case.metadata_map().get::<STGNodeMetadata>() { // eprintln!("Run mutator {}", current_case.metadata_map().get::<STGNodeMetadata>().is_some());
let feedbackstate = match state if let Some(meta) = current_case.metadata_map().get::<STGNodeMetadata>() {
.named_metadata_map() let feedbackstate = match state
.get::<STGFeedbackState>("stgfeedbackstate") { .named_metadata_map()
Some(s) => s, .get::<STGFeedbackState>("stgfeedbackstate") {
Option::None => { Some(s) => s,
panic!("STGfeedbackstate not visible") Option::None => {
panic!("STGfeedbackstate not visible")
}
};
// Maximize all snippets
// dbg!(meta.jobs().len());
for jobinst in meta.jobs().iter() {
match feedbackstate.worst_task_jobs.get(&jobinst.get_hash_cached()) {
Some(worst) => {
let new = worst.map_bytes_onto(jobinst, Some(self.input_addr));
do_rerun |= new.len() > 0;
for (addr, byte) in new {
new_bytes[addr as usize] = byte;
} }
}; },
todo!(); Option::None => {}
}
} }
} }
drop(current_case);
unsafe {num_snippet_stage_execs+=1;}
if do_rerun {
unsafe {num_snippet_rerun+=1;}
let (_, corpus_idx) = fuzzer.evaluate_input(state, executor, manager, new_input)?;
if corpus_idx.is_some() { unsafe{num_snippet_success+=1; self.report_stats(state, manager);}}
} else if {unsafe{num_snippet_stage_execs}} % 5 == 0 {self.report_stats(state, manager);}
Ok(()) Ok(())
} }

View File

@ -41,9 +41,9 @@ pub struct QemuSystemStateObserver<I>
pub last_trace: Vec<ExecInterval>, pub last_trace: Vec<ExecInterval>,
pub last_reads: Vec<Vec<(u32, u8)>>, pub last_reads: Vec<Vec<(u32, u8)>>,
pub last_input: I, pub last_input: I,
pub job_instances: Vec<(u64, u64, String)>, pub job_instances: Vec<JobInstance>,
pub do_report: bool, pub do_report: bool,
pub worst_job_instances: HashMap<String, u64>, pub worst_job_instances: HashMap<String, JobInstance>,
pub select_task: Option<String>, pub select_task: Option<String>,
pub success: bool, pub success: bool,
name: Cow<'static, str>, name: Cow<'static, str>,
@ -96,18 +96,18 @@ where
hash_cache: 0 hash_cache: 0
} }
}).collect::<Vec<_>>(); }).collect::<Vec<_>>();
println!("Instances: {:?}",&job_instances); // println!("Instances: {:?}",&job_instances);
self.job_instances = job_instances;
let observer = &self; let observer = &self;
let mut worst_case_per_task = HashMap::new(); let mut worst_case_per_task : HashMap<String, JobInstance> = HashMap::new();
observer.job_instances.iter().for_each(|x| { observer.job_instances.iter().for_each(|x| {
let time = x.1-x.0; if worst_case_per_task.get(&x.name).is_some() {
if worst_case_per_task.get(&x.2).is_some() { let old = worst_case_per_task.get_mut(&x.name).unwrap();
let old = worst_case_per_task.get_mut(&x.2).unwrap(); if x.exec_ticks > old.exec_ticks {
if time > *old { old.exec_ticks=x.exec_ticks;
*old=time;
} }
} else { } else {
worst_case_per_task.insert(x.2.clone(), time); worst_case_per_task.insert(x.name.clone(), x.clone());
} }
}); });
self.worst_job_instances = worst_case_per_task; self.worst_job_instances = worst_case_per_task;
@ -160,7 +160,7 @@ where I: Default {
Self{last_run: vec![], last_trace: vec![], last_reads: vec![], last_input: I::default(), worst_job_instances: HashMap::new(), do_report: false, select_task: select_task.clone(), name: Cow::from("systemstate".to_string()), last_states: HashMap::new(), success: false, job_instances: vec![]} Self{last_run: vec![], last_trace: vec![], last_reads: vec![], last_input: I::default(), worst_job_instances: HashMap::new(), do_report: false, select_task: select_task.clone(), name: Cow::from("systemstate".to_string()), last_states: HashMap::new(), success: false, job_instances: vec![]}
} }
pub fn last_runtime(&self) -> u64 { pub fn last_runtime(&self) -> u64 {
self.select_task.as_ref().map(|x| self.worst_job_instances.get(x).unwrap_or(&0).clone()).unwrap_or(unsafe{libafl_qemu::sys::icount_get_raw()}) self.select_task.as_ref().map(|x| self.worst_job_instances.get(x).map(|y| y.response-y.release).unwrap_or(0).clone()).unwrap_or(unsafe{libafl_qemu::sys::icount_get_raw()})
} }
} }
impl<I> Default for QemuSystemStateObserver<I> impl<I> Default for QemuSystemStateObserver<I>

View File

@ -101,7 +101,7 @@ where
.get(idx)? .get(idx)?
.borrow() .borrow()
.metadata_map() .metadata_map()
.get::<STGNodeMetadata>().map_or(0, |x| x.nodes.len()); .get::<STGNodeMetadata>().map_or(0, |x| x.nodes().len());
let m = self.get_update_trace_length(state,l); let m = self.get_update_trace_length(state,l);
state.rand_mut().below(m as usize) > l state.rand_mut().below(m as usize) > l
} && state.rand_mut().coinflip(self.skip_non_favored_prob) } && state.rand_mut().coinflip(self.skip_non_favored_prob)

View File

@ -29,8 +29,10 @@ use serde::{Deserialize, Serialize};
use super::AtomicBasicBlock; use super::AtomicBasicBlock;
use super::CaptureEvent; use super::CaptureEvent;
use super::ExecInterval; use super::ExecInterval;
use super::JobInstance;
use super::ReducedFreeRTOSSystemState; use super::ReducedFreeRTOSSystemState;
use super::observers::QemuSystemStateObserver; use super::observers::QemuSystemStateObserver;
use super::TaskJob;
use petgraph::prelude::DiGraph; use petgraph::prelude::DiGraph;
use petgraph::graph::NodeIndex; use petgraph::graph::NodeIndex;
use petgraph::Direction; use petgraph::Direction;
@ -151,7 +153,9 @@ pub struct STGFeedbackState
worst_observed_per_aggegated_path: HashMap<Vec<AtomicBasicBlock>,u64>, worst_observed_per_aggegated_path: HashMap<Vec<AtomicBasicBlock>,u64>,
worst_observed_per_abb_path: HashMap<u64,u64>, worst_observed_per_abb_path: HashMap<u64,u64>,
worst_observed_per_stg_path: HashMap<u64,u64>, worst_observed_per_stg_path: HashMap<u64,u64>,
worst_abb_exec_count: HashMap<AtomicBasicBlock, usize> worst_abb_exec_count: HashMap<AtomicBasicBlock, usize>,
// Metadata about job instances
pub worst_task_jobs: HashMap<u64, TaskJob>,
} }
impl Default for STGFeedbackState { impl Default for STGFeedbackState {
@ -185,7 +189,8 @@ impl Default for STGFeedbackState {
worst_observed_per_stg_path: HashMap::new(), worst_observed_per_stg_path: HashMap::new(),
worst_abb_exec_count: HashMap::new(), worst_abb_exec_count: HashMap::new(),
systemstate_index, systemstate_index,
state_abb_hash_index state_abb_hash_index,
worst_task_jobs: HashMap::new(),
} }
} }
} }
@ -201,17 +206,18 @@ impl Named for STGFeedbackState
// Wrapper around Vec<RefinedFreeRTOSSystemState> to attach as Metadata // Wrapper around Vec<RefinedFreeRTOSSystemState> to attach as Metadata
#[derive(Debug, Default, Serialize, Deserialize, Clone)] #[derive(Debug, Default, Serialize, Deserialize, Clone)]
pub struct STGNodeMetadata { pub struct STGNodeMetadata {
pub nodes: Vec<NodeIndex>, nodes: Vec<NodeIndex>,
pub edges: Vec<EdgeIndex>, edges: Vec<EdgeIndex>,
pub abbs: u64, abbs: u64,
pub aggregate: u64, aggregate: u64,
pub top_abb_counts: Vec<u64>, top_abb_counts: Vec<u64>,
pub intervals: Vec<ExecInterval>, intervals: Vec<ExecInterval>,
jobs: Vec<JobInstance>,
indices: Vec<usize>, indices: Vec<usize>,
tcref: isize, tcref: isize,
} }
impl STGNodeMetadata { impl STGNodeMetadata {
pub fn new(nodes: Vec<NodeIndex>, edges: Vec<EdgeIndex>, abbs: u64, aggregate: u64, top_abb_counts: Vec<u64>, intervals: Vec<ExecInterval>) -> Self{ pub fn new(nodes: Vec<NodeIndex>, edges: Vec<EdgeIndex>, abbs: u64, aggregate: u64, top_abb_counts: Vec<u64>, intervals: Vec<ExecInterval>, jobs: Vec<JobInstance>) -> Self {
#[allow(unused)] #[allow(unused)]
let mut indices : Vec<_> = vec![]; let mut indices : Vec<_> = vec![];
#[cfg(all(feature = "sched_stg",not(any(feature = "sched_stg_pathhash",feature = "sched_stg_abbhash",feature = "sched_stg_aggregatehash"))))] #[cfg(all(feature = "sched_stg",not(any(feature = "sched_stg_pathhash",feature = "sched_stg_abbhash",feature = "sched_stg_aggregatehash"))))]
@ -233,7 +239,35 @@ impl STGNodeMetadata {
// indices.push(aggregate as usize); // indices.push(aggregate as usize);
indices = top_abb_counts.iter().map(|x| (*x) as usize).collect(); indices = top_abb_counts.iter().map(|x| (*x) as usize).collect();
} }
Self {indices, intervals, nodes, abbs, aggregate, top_abb_counts, edges, tcref: 0} Self {indices, intervals, jobs, nodes, abbs, aggregate, top_abb_counts, edges, tcref: 0}
}
pub fn nodes(&self) -> &Vec<NodeIndex> {
&self.nodes
}
pub fn edges(&self) -> &Vec<EdgeIndex> {
&self.edges
}
pub fn abbs(&self) -> u64 {
self.abbs
}
pub fn aggregate(&self) -> u64 {
self.aggregate
}
pub fn top_abb_counts(&self) -> &Vec<u64> {
&self.top_abb_counts
}
pub fn intervals(&self) -> &Vec<ExecInterval> {
&self.intervals
}
pub fn jobs(&self) -> &Vec<JobInstance> {
&self.jobs
} }
} }
@ -317,6 +351,7 @@ pub struct StgFeedback
last_abbs_hash: Option<u64>, // only set, if it was interesting last_abbs_hash: Option<u64>, // only set, if it was interesting
last_aggregate_hash: Option<u64>, // only set, if it was interesting last_aggregate_hash: Option<u64>, // only set, if it was interesting
last_top_abb_hashes: Option<Vec<u64>>, // only set, if it was interesting last_top_abb_hashes: Option<Vec<u64>>, // only set, if it was interesting
last_job_trace: Option<Vec<JobInstance>>, // only set, if it was interesting
dump_path: Option<PathBuf> dump_path: Option<PathBuf>
} }
#[cfg(feature = "feed_stg")] #[cfg(feature = "feed_stg")]
@ -340,6 +375,9 @@ const INTEREST_PATH : bool = false;
const INTEREST_ABBPATH : bool = false; const INTEREST_ABBPATH : bool = false;
#[cfg(not(feature = "feed_stg_aggregatehash"))] #[cfg(not(feature = "feed_stg_aggregatehash"))]
const INTEREST_AGGREGATE : bool = false; const INTEREST_AGGREGATE : bool = false;
const INTEREST_JOB_INSTANCE : bool = true;
fn set_observer_map(trace : &Vec<EdgeIndex>) { fn set_observer_map(trace : &Vec<EdgeIndex>) {
unsafe { unsafe {
for i in 0..MAX_STG_NUM { for i in 0..MAX_STG_NUM {
@ -526,8 +564,23 @@ where
} }
}; };
// --------------------------------- Update STG
let (nodetrace, edgetrace, mut interesting, mut updated) = StgFeedback::update_stg_interval(&observer.last_trace, &observer.last_reads, &observer.last_states, feedbackstate); let (nodetrace, edgetrace, mut interesting, mut updated) = StgFeedback::update_stg_interval(&observer.last_trace, &observer.last_reads, &observer.last_states, feedbackstate);
// --------------------------------- Update job instances
for i in observer.worst_job_instances.iter() {
interesting |= INTEREST_JOB_INSTANCE && if let Some(x) = feedbackstate.worst_task_jobs.get_mut(&i.1.get_hash_cached()) {
// eprintln!("Job instance already present");
x.try_update(i.1)
} else {
// eprintln!("New Job instance");
feedbackstate.worst_task_jobs.insert(i.1.get_hash_cached(), TaskJob::from_instance(&i.1));
true
}
};
self.last_job_trace = Some(observer.job_instances.clone());
// dbg!(&observer.job_instances);
{ {
let h = get_generic_hash(&edgetrace); let h = get_generic_hash(&edgetrace);
if let Some(x) = feedbackstate.worst_observed_per_stg_path.get_mut(&h) { if let Some(x) = feedbackstate.worst_observed_per_stg_path.get_mut(&h) {
@ -547,8 +600,8 @@ where
let tmp = StgFeedback::abbs_in_exec_order(&observer.last_trace); let tmp = StgFeedback::abbs_in_exec_order(&observer.last_trace);
#[cfg(feature = "trace_job_response_times")] #[cfg(feature = "trace_job_response_times")]
let tmp = { let tmp = {
if let Some(worst_instance) = observer.job_instances.iter().filter(|x| Some(x.2.clone()) == observer.select_task).max_by(|a,b| (a.1-a.0).cmp(&(b.1-b.0))) { if let Some(worst_instance) = observer.job_instances.iter().filter(|x| Some(x.name.clone()) == observer.select_task).max_by(|a,b| (a.response-a.release).cmp(&(b.response-b.release))) {
let t = observer.last_trace.iter().filter(|x| x.start_tick < worst_instance.1 && x.end_tick > worst_instance.0 ).cloned().collect(); let t = observer.last_trace.iter().filter(|x| x.start_tick < worst_instance.response && x.end_tick > worst_instance.release ).cloned().collect();
StgFeedback::abbs_in_exec_order(&t) StgFeedback::abbs_in_exec_order(&t)
} else { } else {
if observer.select_task.is_none() { // if nothing was selected, just take the whole trace, otherwise there is nothing interesting here if observer.select_task.is_none() { // if nothing was selected, just take the whole trace, otherwise there is nothing interesting here
@ -633,12 +686,8 @@ where
/// Append to the testcase the generated metadata in case of a new corpus item /// Append to the testcase the generated metadata in case of a new corpus item
#[inline] #[inline]
fn append_metadata<EM, OT>(&mut self, _state: &mut S, _manager: &mut EM, _observers: &OT, testcase: &mut Testcase<S::Input>) -> Result<(), Error> { fn append_metadata<EM, OT>(&mut self, _state: &mut S, _manager: &mut EM, _observers: &OT, testcase: &mut Testcase<S::Input>) -> Result<(), Error> {
let nodes = self.last_node_trace.take(); let meta = STGNodeMetadata::new(self.last_node_trace.take().unwrap_or_default(), self.last_edge_trace.take().unwrap_or_default(), self.last_abbs_hash.take().unwrap_or_default(), self.last_aggregate_hash.take().unwrap_or_default(), self.last_top_abb_hashes.take().unwrap_or_default(), self.last_intervals.take().unwrap_or_default(), self.last_job_trace.take().unwrap_or_default());
let edges = self.last_edge_trace.take(); testcase.metadata_map_mut().insert(meta);
match nodes {
Some(s) => testcase.metadata_map_mut().insert(STGNodeMetadata::new(s, edges.unwrap(), self.last_abbs_hash.take().unwrap_or_default(), self.last_aggregate_hash.take().unwrap_or_default(), self.last_top_abb_hashes.take().unwrap_or_default(), self.last_intervals.take().unwrap())),
Option::None => (),
}
Ok(()) Ok(())
} }

View File

@ -342,7 +342,7 @@ where
.map .map
.insert(elem, idx); .insert(elem, idx);
} }
println!("Number of interesting corpus elements: {}", state.metadata_map_mut().get::<TopRatedsMetadata>().unwrap().get_number()); // println!("Number of interesting corpus elements: {}", state.metadata_map_mut().get::<TopRatedsMetadata>().unwrap().get_number());
Ok(()) Ok(())
} }