implement STGSnippetStage, fix missing metadata
This commit is contained in:
parent
3d0c0247b7
commit
013f3db487
@ -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"
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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");
|
||||||
|
@ -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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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>
|
||||||
|
@ -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)
|
||||||
|
@ -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(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user