WIP: deprecate graph and use STG
This commit is contained in:
parent
8f652f754c
commit
b9d6f41ac6
@ -5,7 +5,7 @@ authors = ["Andrea Fioraldi <andreafioraldi@gmail.com>", "Dominik Maier <domenuk
|
||||
edition = "2021"
|
||||
|
||||
[features]
|
||||
default = ["std", "snapshot_restore", "singlecore", "restarting", "feed_systemtrace", "fuzz_int", "no_hash_state" ]
|
||||
default = ["std", "snapshot_restore", "singlecore", "restarting", "feed_systemtrace", "fuzz_int", "do_hash_notify_state" ]
|
||||
std = []
|
||||
snapshot_restore = []
|
||||
snapshot_fast = [ "snapshot_restore" ]
|
||||
@ -24,7 +24,7 @@ gensize_1 = [ ]
|
||||
gensize_10 = [ ]
|
||||
gensize_100 = [ ]
|
||||
observer_hitcounts = []
|
||||
no_hash_state = []
|
||||
do_hash_notify_state = []
|
||||
count_iterations = []
|
||||
run_until_saturation = []
|
||||
|
||||
|
@ -36,6 +36,7 @@ use core::{fmt::Debug, time::Duration};
|
||||
// use libafl::feedbacks::FeedbackState;
|
||||
// use libafl::state::HasFeedbackStates;
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
use std::path::PathBuf;
|
||||
|
||||
pub static mut FUZZ_START_TIMESTAMP : SystemTime = UNIX_EPOCH;
|
||||
|
||||
@ -98,16 +99,18 @@ pub struct QemuClockObserver {
|
||||
name: String,
|
||||
start_tick: u64,
|
||||
end_tick: u64,
|
||||
dump_path: Option<PathBuf>
|
||||
}
|
||||
|
||||
impl QemuClockObserver {
|
||||
/// Creates a new [`QemuClockObserver`] with the given name.
|
||||
#[must_use]
|
||||
pub fn new(name: &'static str) -> Self {
|
||||
pub fn new(name: &'static str, dump_path: Option<PathBuf>) -> Self {
|
||||
Self {
|
||||
name: name.to_string(),
|
||||
start_tick: 0,
|
||||
end_tick: 0,
|
||||
dump_path
|
||||
}
|
||||
}
|
||||
|
||||
@ -137,36 +140,33 @@ where
|
||||
|
||||
fn post_exec(&mut self, _state: &mut S, _input: &S::Input, _exit_kind: &ExitKind) -> Result<(), Error> {
|
||||
unsafe { self.end_tick = emu::icount_get_raw() };
|
||||
// println!("clock post {}", self.end_tick);
|
||||
// println!("Number of Ticks: {} <- {} {}",self.end_tick - self.start_tick, self.end_tick, self.start_tick);
|
||||
let metadata =_state.metadata_map_mut();
|
||||
let hist = metadata.get_mut::<IcHist>();
|
||||
let timestamp = SystemTime::now().duration_since(unsafe {FUZZ_START_TIMESTAMP}).unwrap().as_millis();
|
||||
match hist {
|
||||
None => {
|
||||
metadata.insert(IcHist(vec![(self.end_tick - self.start_tick, timestamp)],
|
||||
(self.end_tick - self.start_tick, timestamp)));
|
||||
}
|
||||
Some(v) => {
|
||||
v.0.push((self.end_tick - self.start_tick, timestamp));
|
||||
if (v.1.0 < self.end_tick-self.start_tick) {
|
||||
v.1 = (self.end_tick - self.start_tick, timestamp);
|
||||
if let Some(td) = &self.dump_path {
|
||||
// println!("clock post {}", self.end_tick);
|
||||
// println!("Number of Ticks: {} <- {} {}",self.end_tick - self.start_tick, self.end_tick, self.start_tick);
|
||||
let metadata =_state.metadata_map_mut();
|
||||
let hist = metadata.get_mut::<IcHist>();
|
||||
let timestamp = SystemTime::now().duration_since(unsafe {FUZZ_START_TIMESTAMP}).unwrap().as_millis();
|
||||
match hist {
|
||||
None => {
|
||||
metadata.insert(IcHist(vec![(self.end_tick - self.start_tick, timestamp)],
|
||||
(self.end_tick - self.start_tick, timestamp)));
|
||||
}
|
||||
if v.0.len() >= 100 {
|
||||
if let Ok(td) = env::var("DUMP_TIMES") {
|
||||
Some(v) => {
|
||||
v.0.push((self.end_tick - self.start_tick, timestamp));
|
||||
if v.1.0 < self.end_tick-self.start_tick {
|
||||
v.1 = (self.end_tick - self.start_tick, timestamp);
|
||||
}
|
||||
if v.0.len() >= 100 {
|
||||
let mut file = OpenOptions::new()
|
||||
.read(true)
|
||||
.write(true)
|
||||
.create(true)
|
||||
.append(true)
|
||||
.open(td).expect("Could not open timedump");
|
||||
let newv : Vec<(u64, u128)> = Vec::with_capacity(100);
|
||||
let newv : Vec<(u64, u128)> = Vec::with_capacity(110);
|
||||
for i in std::mem::replace(&mut v.0, newv).into_iter() {
|
||||
writeln!(file, "{},{}", i.0, i.1).expect("Write to dump failed");
|
||||
}
|
||||
} else {
|
||||
// If we don't write out values we don't need to remember them at all
|
||||
v.0.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -188,6 +188,7 @@ impl Default for QemuClockObserver {
|
||||
name: String::from("clock"),
|
||||
start_tick: 0,
|
||||
end_tick: 0,
|
||||
dump_path: None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,19 +14,23 @@ use libafl_qemu::{
|
||||
};
|
||||
use rand::{SeedableRng, StdRng, Rng};
|
||||
use crate::{
|
||||
clock::{ClockTimeFeedback, IcHist, QemuClockIncreaseFeedback, QemuClockObserver, FUZZ_START_TIMESTAMP}, mutational::{InterruptShiftStage, MINIMUM_INTER_ARRIVAL_TIME}, qemustate::QemuStateRestoreHelper, systemstate::{self, feedbacks::{DumpSystraceFeedback, NovelSystemStateFeedback}, graph::{GraphMaximizerCorpusScheduler, SysGraphFeedbackState, SysMapFeedback}, helpers::QemuSystemStateHelper, observers::QemuSystemStateObserver, schedulers::{GenerationScheduler, LongestTraceScheduler}, stg::{stg_map_mut_slice, StgFeedback, MAX_STG_NUM}}, worst::{AlwaysTrueFeedback, ExecTimeIncFeedback, TimeMaximizerCorpusScheduler, TimeStateMaximizerCorpusScheduler}
|
||||
clock::{ClockTimeFeedback, IcHist, QemuClockIncreaseFeedback, QemuClockObserver, FUZZ_START_TIMESTAMP}, mutational::{InterruptShiftStage, MINIMUM_INTER_ARRIVAL_TIME}, qemustate::QemuStateRestoreHelper, systemstate::{self, feedbacks::{DumpSystraceFeedback, NovelSystemStateFeedback}, graph::{GraphMaximizerCorpusScheduler, SysGraphFeedbackState, SysMapFeedback}, helpers::{QemuSystemStateHelper, ISR_SYMBOLS}, observers::QemuSystemStateObserver, schedulers::{GenerationScheduler, LongestTraceScheduler}, stg::{stg_map_mut_slice, STGEdge, STGNode, StgFeedback, MAX_STG_NUM}}, worst::{AlwaysTrueFeedback, ExecTimeIncFeedback, TimeMaximizerCorpusScheduler, TimeStateMaximizerCorpusScheduler}
|
||||
};
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
use clap::{Parser, Subcommand};
|
||||
use csv::Reader;
|
||||
use petgraph::dot::{Dot, Config};
|
||||
use petgraph::{dot::{Config, Dot}, Graph};
|
||||
use petgraph::graph::EdgeIndex;
|
||||
use petgraph::graph::NodeIndex;
|
||||
use petgraph::prelude::DiGraph;
|
||||
use crate::systemstate::stg::STGFeedbackState;
|
||||
|
||||
// Constants ================================================================================
|
||||
|
||||
pub static mut RNG_SEED: u64 = 1;
|
||||
|
||||
pub static mut LIMIT : u32 = u32::MAX;
|
||||
pub static mut LIMIT : u32 = u32::MAX>>1;
|
||||
pub const FIRST_INT : u32 = 500000;
|
||||
|
||||
pub const MAX_NUM_INTERRUPT: usize = 32;
|
||||
pub const DO_NUM_INTERRUPT: usize = 32;
|
||||
@ -98,6 +102,7 @@ pub fn get_all_fn_symbol_ranges(elf: &EasyElf, api_range: std::ops::Range<GuestA
|
||||
for sym in &funcs {
|
||||
let sym_name = gob.strtab.get_at(sym.st_name);
|
||||
if let Some(sym_name) = sym_name {
|
||||
// if ISR_SYMBOLS.contains(&sym_name) {continue;}; // skip select symbols, which correspond to ISR-safe system calls
|
||||
if let Some(r) = get_function_range(elf, sym_name) {
|
||||
api_addreses.insert(sym_name.to_string(), r);
|
||||
}
|
||||
@ -241,8 +246,9 @@ macro_rules! do_dump_stg {
|
||||
let dump_path = $cli.dump_name.clone().unwrap().with_extension(if $c=="" {"stg"} else {$c});
|
||||
println!("Dumping graph to {:?}", &dump_path);
|
||||
if let Some(md) = $state.named_metadata_map_mut().get_mut::<STGFeedbackState>("stgfeedbackstate") {
|
||||
let out = md.graph.map(|i,x| x.pretty_print(), |_,_| "");
|
||||
let outs = Dot::with_config(&out, &[Config::EdgeNoLabel]).to_string();
|
||||
let out = md.graph.map(|i,x| x.color_print(), |i,x| x.color_print());
|
||||
let outs = Dot::with_config(&out, &[]).to_string();
|
||||
let outs = outs.replace("\\\"","\"");
|
||||
let outs = outs.replace(';',"\\n");
|
||||
fs::write(dump_path,outs).expect("Failed to write graph");
|
||||
}
|
||||
@ -302,17 +308,10 @@ pub fn fuzz() {
|
||||
let cli = Cli::parse();
|
||||
env_from_config(&cli.kernel, &cli.config);
|
||||
unsafe {FUZZ_START_TIMESTAMP = SystemTime::now();}
|
||||
if let Some(n) = &cli.dump_name {
|
||||
if cli.dump_times {
|
||||
env::set_var("DUMP_TIMES", n.with_extension("time"));
|
||||
}
|
||||
} else if cli.dump_times || cli.dump_cases || cli.dump_traces || cli.dump_graph {
|
||||
cli.dump_name.clone().expect("Dump name not give but dump is requested");
|
||||
if cli.dump_name.is_none() && (cli.dump_times || cli.dump_cases || cli.dump_traces || cli.dump_graph) {
|
||||
panic!("Dump name not give but dump is requested");
|
||||
}
|
||||
let mut starttime = std::time::Instant::now();
|
||||
if let Ok(s) = env::var("FUZZ_SIZE") {
|
||||
str::parse::<usize>(&s).expect("FUZZ_SIZE was not a number");
|
||||
};
|
||||
// Hardcoded parameters
|
||||
let timeout = Duration::from_secs(10);
|
||||
let broker_port = 1337;
|
||||
@ -354,6 +353,7 @@ pub fn fuzz() {
|
||||
let task_delay_addr = load_symbol(&elf, "pxDelayedTaskList", false);
|
||||
let task_delay_overflow_addr = load_symbol(&elf, "pxOverflowDelayedTaskList", false);
|
||||
let scheduler_lock = load_symbol(&elf, "uxSchedulerSuspended", false);
|
||||
let scheduler_running = load_symbol(&elf, "xSchedulerRunning", false);
|
||||
let critical_section = load_symbol(&elf, "uxCriticalNesting", false);
|
||||
// let task_queue_addr = virt2phys(task_queue_addr,&elf.goblin());
|
||||
#[cfg(feature = "systemstate")]
|
||||
@ -472,7 +472,7 @@ pub fn fuzz() {
|
||||
t[j]=buf[i*4+j];
|
||||
}
|
||||
if i == 0 || true {
|
||||
unsafe {start_tick = u32::from_le_bytes(t) % LIMIT;}
|
||||
unsafe {start_tick = u32::from_le_bytes(t) % LIMIT + FIRST_INT;}
|
||||
} else {
|
||||
start_tick = u32::saturating_add(start_tick,max(MINIMUM_INTER_ARRIVAL_TIME,u32::from_le_bytes(t)));
|
||||
}
|
||||
@ -529,7 +529,7 @@ pub fn fuzz() {
|
||||
)};
|
||||
|
||||
// Create an observation channel to keep track of the execution time
|
||||
let clock_time_observer = QemuClockObserver::new("clocktime");
|
||||
let clock_time_observer = QemuClockObserver::new("clocktime", if cli.dump_times {cli.dump_name.clone().map(|x| x.with_extension("time"))} else {None} );
|
||||
|
||||
let systemstate_observer = QemuSystemStateObserver::new();
|
||||
|
||||
@ -629,7 +629,7 @@ pub fn fuzz() {
|
||||
let qhelpers = tuple_list!(
|
||||
QemuEdgeCoverageHelper::default(),
|
||||
QemuStateRestoreHelper::new(),
|
||||
QemuSystemStateHelper::new(api_addreses,api_ranges,isr_addreses,isr_ranges,curr_tcb_pointer,task_queue_addr,task_delay_addr,task_delay_overflow_addr,scheduler_lock, critical_section,input_counter_ptr,app_range.clone())
|
||||
QemuSystemStateHelper::new(api_addreses,api_ranges,isr_addreses,isr_ranges,curr_tcb_pointer,task_queue_addr,task_delay_addr,task_delay_overflow_addr,scheduler_lock,scheduler_running, critical_section,input_counter_ptr,app_range.clone())
|
||||
);
|
||||
let mut hooks = QemuHooks::new(emu.clone(),qhelpers);
|
||||
|
||||
|
@ -9,16 +9,10 @@ use libafl_bolts::rands::{
|
||||
Rand
|
||||
};
|
||||
use libafl::{
|
||||
corpus::{Corpus, self},
|
||||
fuzzer::Evaluator,
|
||||
mark_feature_time,
|
||||
stages::{Stage},
|
||||
start_timer,
|
||||
state::{MaybeHasClientPerfMonitor, HasCorpus, HasRand, UsesState, HasMetadata},
|
||||
Error, prelude::{HasBytesVec, UsesInput, new_hash_feedback, MutationResult, Mutator, CorpusId},
|
||||
corpus::{self, Corpus}, fuzzer::Evaluator, mark_feature_time, prelude::{new_hash_feedback, CorpusId, HasBytesVec, MutationResult, Mutator, UsesInput}, stages::Stage, start_timer, state::{HasCorpus, HasMetadata, HasNamedMetadata, HasRand, MaybeHasClientPerfMonitor, UsesState}, Error
|
||||
};
|
||||
use libafl::prelude::State;
|
||||
use crate::{systemstate::{FreeRTOSSystemStateMetadata, RefinedFreeRTOSSystemState}, fuzzer::DO_NUM_INTERRUPT, clock::IcHist};
|
||||
use crate::{clock::IcHist, fuzzer::{DO_NUM_INTERRUPT, FIRST_INT}, systemstate::{stg::{STGFeedbackState, STGNodeMetadata}, ExecInterval, FreeRTOSSystemStateMetadata, ReducedFreeRTOSSystemState}};
|
||||
|
||||
pub const MINIMUM_INTER_ARRIVAL_TIME : u32 = 700 * 1000 * (1 << 4);
|
||||
|
||||
@ -48,7 +42,7 @@ where
|
||||
E: UsesState<State = Z::State>,
|
||||
EM: UsesState<State = Z::State>,
|
||||
Z: Evaluator<E, EM>,
|
||||
Z::State: MaybeHasClientPerfMonitor + HasCorpus + HasRand + HasMetadata,
|
||||
Z::State: MaybeHasClientPerfMonitor + HasCorpus + HasRand + HasMetadata + HasNamedMetadata,
|
||||
<Z::State as UsesInput>::Input: HasBytesVec
|
||||
{
|
||||
fn perform(
|
||||
@ -89,7 +83,7 @@ where
|
||||
t[j]=target_bytes[i*4+j];
|
||||
}
|
||||
if i == 0 || true {
|
||||
start_tick = u32::from_le_bytes(t);
|
||||
start_tick = u32::from_le_bytes(t)+FIRST_INT;
|
||||
} else {
|
||||
start_tick = u32::saturating_add(start_tick,max(MINIMUM_INTER_ARRIVAL_TIME,u32::from_le_bytes(t)));
|
||||
}
|
||||
@ -105,17 +99,26 @@ where
|
||||
let mut suffix = target_bytes.split_off(4 * num_interrupts);
|
||||
let mut prefix : Vec<[u8; 4]> = vec![];
|
||||
// let mut suffix : Vec<u8> = vec![];
|
||||
#[cfg(feature = "feed_systemtrace")]
|
||||
// #[cfg(feature = "feed_stg")]
|
||||
{
|
||||
let tmp = _input.metadata_map().get::<FreeRTOSSystemStateMetadata>();
|
||||
let feedbackstate = match state
|
||||
.named_metadata_map_mut()
|
||||
.get_mut::<STGFeedbackState>("stgfeedbackstate") {
|
||||
Some(s) => s,
|
||||
None => {
|
||||
panic!("STGfeedbackstate not visible")
|
||||
}
|
||||
};
|
||||
|
||||
let tmp = _input.metadata_map().get::<STGNodeMetadata>();
|
||||
if tmp.is_some() {
|
||||
let trace = tmp.expect("FreeRTOSSystemStateMetadata not found");
|
||||
let trace = tmp.expect("STGNodeMetadata not found");
|
||||
|
||||
// calculate hits and identify snippets
|
||||
let mut last_m = false;
|
||||
let mut marks : Vec<(&RefinedFreeRTOSSystemState, usize, usize)>= vec![]; // 1: got interrupted, 2: interrupt handler
|
||||
for i in 0..trace.inner.len() {
|
||||
let curr = &trace.inner[i];
|
||||
let mut marks : Vec<(&ExecInterval, usize, usize)>= vec![]; // 1: got interrupted, 2: interrupt handler
|
||||
for i in 0..trace.intervals.len() {
|
||||
let curr = &trace.intervals[i];
|
||||
let m = interrupt_offsets[0..num_interrupts].iter().any(|x| (curr.start_tick..curr.end_tick).contains(&(*x as u64)));
|
||||
if m {
|
||||
marks.push((curr, i, 1));
|
||||
@ -197,7 +200,7 @@ where
|
||||
let mut numbers : Vec<u32> = interrupt_offsets[0..num_interrupts].to_vec();
|
||||
numbers.sort();
|
||||
// println!("Mutator: {:?}", numbers);
|
||||
let mut start : u32 = 0;
|
||||
// let mut start : u32 = 0;
|
||||
// for i in 0..numbers.len() {
|
||||
// let tmp = numbers[i];
|
||||
// numbers[i] = numbers[i]-start;
|
||||
|
@ -20,7 +20,7 @@ use hashbrown::HashMap;
|
||||
use libafl::{executors::ExitKind, inputs::Input, observers::ObserversTuple, state::HasMetadata};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use super::RefinedFreeRTOSSystemState;
|
||||
use super::ReducedFreeRTOSSystemState;
|
||||
use super::FreeRTOSSystemStateMetadata;
|
||||
use super::observers::QemuSystemStateObserver;
|
||||
use petgraph::prelude::DiGraph;
|
||||
@ -35,7 +35,7 @@ use std::cmp::Ordering;
|
||||
pub struct SystemStateFeedbackState
|
||||
{
|
||||
known_traces: HashMap<u64,(u64,u64,usize)>, // encounters,ticks,length
|
||||
longest: Vec<RefinedFreeRTOSSystemState>,
|
||||
longest: Vec<ReducedFreeRTOSSystemState>,
|
||||
}
|
||||
impl Named for SystemStateFeedbackState
|
||||
{
|
||||
@ -57,7 +57,7 @@ impl Named for SystemStateFeedbackState
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
|
||||
pub struct NovelSystemStateFeedback
|
||||
{
|
||||
last_trace: Option<Vec<RefinedFreeRTOSSystemState>>,
|
||||
last_trace: Option<Vec<ReducedFreeRTOSSystemState>>,
|
||||
// known_traces: HashMap<u64,(u64,usize)>,
|
||||
}
|
||||
|
||||
@ -151,19 +151,19 @@ impl Named for NovelSystemStateFeedback
|
||||
|
||||
//=============================
|
||||
|
||||
pub fn match_traces(target: &Vec<RefinedFreeRTOSSystemState>, last: &Vec<RefinedFreeRTOSSystemState>) -> bool {
|
||||
pub fn match_traces(target: &Vec<ReducedFreeRTOSSystemState>, last: &Vec<ReducedFreeRTOSSystemState>) -> bool {
|
||||
let mut ret = true;
|
||||
if target.len() > last.len() {return false;}
|
||||
for i in 0..target.len() {
|
||||
ret &= target[i].current_task.0.task_name==last[i].current_task.0.task_name;
|
||||
ret &= target[i].current_task.task_name==last[i].current_task.task_name;
|
||||
}
|
||||
ret
|
||||
}
|
||||
pub fn match_traces_name(target: &Vec<String>, last: &Vec<RefinedFreeRTOSSystemState>) -> bool {
|
||||
pub fn match_traces_name(target: &Vec<String>, last: &Vec<ReducedFreeRTOSSystemState>) -> bool {
|
||||
let mut ret = true;
|
||||
if target.len() > last.len() {return false;}
|
||||
for i in 0..target.len() {
|
||||
ret &= target[i]==last[i].current_task.0.task_name;
|
||||
ret &= target[i]==last[i].current_task.task_name;
|
||||
}
|
||||
ret
|
||||
}
|
||||
@ -213,8 +213,8 @@ impl Named for HitSystemStateFeedback
|
||||
}
|
||||
|
||||
impl HitSystemStateFeedback {
|
||||
pub fn new(target: Option<Vec<RefinedFreeRTOSSystemState>>) -> Self {
|
||||
Self {target: target.map(|x| x.into_iter().map(|y| y.current_task.0.task_name).collect())}
|
||||
pub fn new(target: Option<Vec<ReducedFreeRTOSSystemState>>) -> Self {
|
||||
Self {target: target.map(|x| x.into_iter().map(|y| y.current_task.task_name).collect())}
|
||||
}
|
||||
}
|
||||
//=========================== Debugging Feedback
|
||||
@ -224,7 +224,7 @@ pub struct DumpSystraceFeedback
|
||||
{
|
||||
dumpfile: Option<PathBuf>,
|
||||
dump_metadata: bool,
|
||||
last_trace: Option<Vec<RefinedFreeRTOSSystemState>>,
|
||||
last_trace: Option<Vec<ReducedFreeRTOSSystemState>>,
|
||||
}
|
||||
|
||||
impl<S> Feedback<S> for DumpSystraceFeedback
|
||||
@ -245,7 +245,7 @@ where
|
||||
{
|
||||
let observer = observers.match_name::<QemuSystemStateObserver>("systemstate")
|
||||
.expect("QemuSystemStateObserver not found");
|
||||
let names : Vec<String> = observer.last_run.iter().map(|x| x.current_task.0.task_name.clone()).collect();
|
||||
let names : Vec<String> = observer.last_run.iter().map(|x| x.current_task.task_name.clone()).collect();
|
||||
match &self.dumpfile {
|
||||
Some(s) => {
|
||||
std::fs::write(s,ron::to_string(&observer.last_run).expect("Error serializing hashmap")).expect("Can not dump to file");
|
||||
|
@ -38,7 +38,8 @@ use hashbrown::HashMap;
|
||||
use libafl::{executors::ExitKind, inputs::Input, observers::ObserversTuple, state::HasMetadata};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use super::RefinedFreeRTOSSystemState;
|
||||
use super::ExecInterval;
|
||||
use super::ReducedFreeRTOSSystemState;
|
||||
use super::FreeRTOSSystemStateMetadata;
|
||||
use super::observers::QemuSystemStateObserver;
|
||||
use petgraph::prelude::DiGraph;
|
||||
@ -58,24 +59,25 @@ pub struct VariantTuple
|
||||
pub input: Vec<u8>, // in the end any kind of input are bytes, regardless of type and lifetime
|
||||
}
|
||||
impl VariantTuple {
|
||||
fn from(other: &RefinedFreeRTOSSystemState,input: Vec<u8>) -> Self {
|
||||
VariantTuple{
|
||||
start_tick: other.start_tick,
|
||||
end_tick: other.end_tick,
|
||||
input_counter: other.input_counter,
|
||||
input: input,
|
||||
}
|
||||
fn from(other: &ReducedFreeRTOSSystemState,input: Vec<u8>) -> Self {
|
||||
// VariantTuple{
|
||||
// start_tick: other.tick,
|
||||
// end_tick: other.end_tick,
|
||||
// input_counter: other.input_counter,
|
||||
// input: input,
|
||||
// }
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
|
||||
pub struct SysGraphNode
|
||||
{
|
||||
base: RefinedFreeRTOSSystemState,
|
||||
base: ReducedFreeRTOSSystemState,
|
||||
pub variants: Vec<VariantTuple>,
|
||||
}
|
||||
impl SysGraphNode {
|
||||
fn from(base: RefinedFreeRTOSSystemState, input: Vec<u8>) -> Self {
|
||||
fn from(base: ReducedFreeRTOSSystemState, input: Vec<u8>) -> Self {
|
||||
SysGraphNode{variants: vec![VariantTuple::from(&base, input)], base:base }
|
||||
}
|
||||
/// unites the variants of this value with another, draining the other if the bases are equal
|
||||
@ -86,42 +88,43 @@ impl SysGraphNode {
|
||||
return true;
|
||||
}
|
||||
/// add a Varint from a [`RefinedFreeRTOSSystemState`]
|
||||
fn unite_raw(&mut self, other: &RefinedFreeRTOSSystemState, input: &Vec<u8>) -> bool {
|
||||
fn unite_raw(&mut self, other: &ReducedFreeRTOSSystemState, input: &Vec<u8>) -> bool {
|
||||
if &self.base!=other {return false;}
|
||||
self.variants.push(VariantTuple::from(other, input.clone()));
|
||||
self.variants.dedup();
|
||||
return true;
|
||||
}
|
||||
/// add a Varint from a [`RefinedFreeRTOSSystemState`], if it's interesting
|
||||
fn unite_interesting(&mut self, other: &RefinedFreeRTOSSystemState, input: &Vec<u8>) -> bool {
|
||||
if &self.base!=other {return false;}
|
||||
let interesting =
|
||||
self.variants.iter().all(|x| x.end_tick-x.start_tick<other.end_tick-other.start_tick) || // longest variant
|
||||
self.variants.iter().all(|x| x.end_tick-x.start_tick>other.end_tick-other.start_tick) || // shortest variant
|
||||
self.variants.iter().all(|x| x.input_counter>other.input_counter) || // longest input
|
||||
self.variants.iter().all(|x| x.input_counter<other.input_counter); // shortest input
|
||||
if interesting {
|
||||
let var = VariantTuple::from(other, input.clone());
|
||||
self.variants.push(var);
|
||||
}
|
||||
return interesting;
|
||||
fn unite_interesting(&mut self, other: &ReducedFreeRTOSSystemState, input: &Vec<u8>) -> bool {
|
||||
// if &self.base!=other {return false;}
|
||||
// let interesting =
|
||||
// self.variants.iter().all(|x| x.end_tick-x.start_tick<other.end_tick-other.tick) || // longest variant
|
||||
// self.variants.iter().all(|x| x.end_tick-x.start_tick>other.end_tick-other.tick) || // shortest variant
|
||||
// self.variants.iter().all(|x| x.input_counter>other.input_counter) || // longest input
|
||||
// self.variants.iter().all(|x| x.input_counter<other.input_counter); // shortest input
|
||||
// if interesting {
|
||||
// let var = VariantTuple::from(other, input.clone());
|
||||
// self.variants.push(var);
|
||||
// }
|
||||
// return interesting;
|
||||
todo!()
|
||||
}
|
||||
pub fn get_taskname(&self) -> &str {
|
||||
&self.base.current_task.0.task_name
|
||||
&self.base.current_task.task_name
|
||||
}
|
||||
pub fn get_input_counts(&self) -> Vec<u32> {
|
||||
self.variants.iter().map(|x| x.input_counter).collect()
|
||||
}
|
||||
pub fn pretty_print(&self) -> String {
|
||||
let mut ret = String::new();
|
||||
ret.push_str(&format!("{}#{}",&self.base.current_task.0.task_name,&self.base.current_task.1));
|
||||
ret.push_str(&format!("{}",&self.base.current_task.task_name));
|
||||
ret.push_str(";Rl:");
|
||||
for i in &self.base.ready_list_after {
|
||||
ret.push_str(&format!(";{}#{}",i.0.task_name,i.1));
|
||||
ret.push_str(&format!(";{}",i.task_name));
|
||||
}
|
||||
ret.push_str(";Dl:");
|
||||
for i in &self.base.delay_list_after {
|
||||
ret.push_str(&format!(";{}#{}",i.0.task_name,i.1));
|
||||
ret.push_str(&format!(";{}",i.task_name));
|
||||
}
|
||||
// println!("{}",ret);
|
||||
ret
|
||||
@ -185,14 +188,14 @@ impl SysGraphFeedbackState
|
||||
pub fn new() -> Self {
|
||||
let mut graph = DiGraph::<SysGraphNode, ()>::new();
|
||||
let mut entry = SysGraphNode::default();
|
||||
entry.base.current_task.0.task_name="Start".to_string();
|
||||
entry.base.current_task.task_name="Start".to_string();
|
||||
let mut exit = SysGraphNode::default();
|
||||
exit.base.current_task.0.task_name="End".to_string();
|
||||
exit.base.current_task.task_name="End".to_string();
|
||||
let entry = graph.add_node(entry);
|
||||
let exit = graph.add_node(exit);
|
||||
Self {graph: graph, entrypoint: entry, exit: exit, name: String::from("SysMap")}
|
||||
}
|
||||
fn insert(&mut self, list: Vec<RefinedFreeRTOSSystemState>, input: &Vec<u8>) {
|
||||
fn insert(&mut self, list: Vec<ReducedFreeRTOSSystemState>, input: &Vec<u8>) {
|
||||
let mut current_index = self.entrypoint;
|
||||
for n in list {
|
||||
let mut done = false;
|
||||
@ -211,7 +214,7 @@ impl SysGraphFeedbackState
|
||||
}
|
||||
}
|
||||
/// Try adding a system state path from a [Vec<RefinedFreeRTOSSystemState>], return true if the path was interesting
|
||||
fn update(&mut self, list: &Vec<RefinedFreeRTOSSystemState>, input: &Vec<u8>) -> (bool, Vec<NodeIndex>) {
|
||||
fn update(&mut self, list: &Vec<ReducedFreeRTOSSystemState>, input: &Vec<u8>) -> (bool, Vec<NodeIndex>) {
|
||||
let mut current_index = self.entrypoint;
|
||||
let mut novel = false;
|
||||
let mut trace : Vec<NodeIndex> = vec![current_index];
|
||||
@ -262,9 +265,9 @@ impl SysGraphFeedbackState
|
||||
fn reset(&mut self) -> Result<(), Error> {
|
||||
self.graph.clear();
|
||||
let mut entry = SysGraphNode::default();
|
||||
entry.base.current_task.0.task_name="Start".to_string();
|
||||
entry.base.current_task.task_name="Start".to_string();
|
||||
let mut exit = SysGraphNode::default();
|
||||
exit.base.current_task.0.task_name="End".to_string();
|
||||
exit.base.current_task.task_name="End".to_string();
|
||||
self.entrypoint = self.graph.add_node(entry);
|
||||
self.exit = self.graph.add_node(exit);
|
||||
Ok(())
|
||||
|
@ -13,7 +13,7 @@ use libafl_qemu::edges::QemuEdgesMapMetadata;
|
||||
use libafl_qemu::emu;
|
||||
use libafl_qemu::hooks;
|
||||
use libafl_qemu::Hook;
|
||||
use crate::systemstate::extract_abbs_from_trace;
|
||||
// use crate::systemstate::extract_abbs_from_trace;
|
||||
use crate::systemstate::RawFreeRTOSSystemState;
|
||||
use crate::systemstate::CURRENT_SYSTEMSTATE_VEC;
|
||||
use crate::systemstate::NUM_PRIOS;
|
||||
@ -41,7 +41,7 @@ pub static mut NEXT_INPUT : Vec<u8> = Vec::new();
|
||||
|
||||
pub const ISR_SYMBOLS : &'static [&'static str] = &[
|
||||
// ISRs
|
||||
"Reset_Handler","Default_Handler","Default_Handler2","Default_Handler3","Default_Handler4","Default_Handler5","Default_Handler6","vPortSVCHandler","xPortPendSVHandler","xPortSysTickHandler","isr_starter"
|
||||
"Reset_Handler","Default_Handler","Default_Handler2","Default_Handler3","Default_Handler4","Default_Handler5","Default_Handler6","vPortSVCHandler","xPortPendSVHandler","xPortSysTickHandler","isr_starter"//,"vTaskGenericNotifyGiveFromISR"
|
||||
];
|
||||
|
||||
//============================= Qemu Helper
|
||||
@ -60,6 +60,7 @@ pub struct QemuSystemStateHelper {
|
||||
delay_queue: GuestAddr,
|
||||
delay_queue_overflow: GuestAddr,
|
||||
scheduler_lock_addr: GuestAddr,
|
||||
scheduler_running_addr: GuestAddr,
|
||||
critical_addr: GuestAddr,
|
||||
input_counter: Option<GuestAddr>,
|
||||
app_range: Range<GuestAddr>,
|
||||
@ -77,6 +78,7 @@ impl QemuSystemStateHelper {
|
||||
delay_queue: GuestAddr,
|
||||
delay_queue_overflow: GuestAddr,
|
||||
scheduler_lock_addr: GuestAddr,
|
||||
scheduler_running_addr: GuestAddr,
|
||||
critical_addr: GuestAddr,
|
||||
input_counter: Option<GuestAddr>,
|
||||
app_range: Range<GuestAddr>,
|
||||
@ -91,6 +93,7 @@ impl QemuSystemStateHelper {
|
||||
delay_queue,
|
||||
delay_queue_overflow,
|
||||
scheduler_lock_addr,
|
||||
scheduler_running_addr,
|
||||
critical_addr,
|
||||
input_counter: input_counter,
|
||||
app_range,
|
||||
@ -162,7 +165,14 @@ fn read_freertos_list(systemstate : &mut RawFreeRTOSSystemState, emulator: &Emul
|
||||
}
|
||||
let next_item : freertos::ListItem_t = freertos::emu_lookup::lookup(emulator, next_index);
|
||||
// println!("Item at {}: {:?}",next_index,next_item);
|
||||
assert_eq!(next_item.pvContainer,target);
|
||||
if next_item.pvContainer != target {
|
||||
// the list is being modified, abort by setting the list empty
|
||||
eprintln!("Warning: attempted to read a list that is being modified");
|
||||
let mut read=read;
|
||||
read.uxNumberOfItems = 0;
|
||||
return read;
|
||||
}
|
||||
// assert_eq!(next_item.pvContainer,target);
|
||||
let new_next_index=next_item.pxNext;
|
||||
let next_tcb : TCB_t= freertos::emu_lookup::lookup(emulator,next_item.pvOwner);
|
||||
// println!("TCB at {}: {:?}",next_item.pvOwner,next_tcb);
|
||||
@ -246,10 +256,11 @@ fn trigger_collection(emulator: &Emulator, edge: (Option<GuestAddr>,Option<Guest
|
||||
// println!("{:?}",std::str::from_utf8(¤t_tcb.pcTaskName));
|
||||
let critical : void_ptr = freertos::emu_lookup::lookup(emulator, h.critical_addr);
|
||||
let suspended : void_ptr = freertos::emu_lookup::lookup(emulator, h.scheduler_lock_addr);
|
||||
let running : void_ptr = freertos::emu_lookup::lookup(emulator, h.scheduler_running_addr);
|
||||
|
||||
systemstate.current_tcb = freertos::emu_lookup::lookup(emulator,curr_tcb_addr);
|
||||
// During ISRs it is only safe to extract structs if they are not currently being modified
|
||||
if (systemstate.capture_point.0==CaptureEvent::APIStart || systemstate.capture_point.0==CaptureEvent::APIEnd) || (critical == 0 && suspended == 0) {
|
||||
if systemstate.capture_point.0==CaptureEvent::APIStart || systemstate.capture_point.0==CaptureEvent::APIEnd || (critical == 0 && suspended == 0 ) {
|
||||
// Extract delay list
|
||||
let mut target : GuestAddr = h.delay_queue;
|
||||
target = freertos::emu_lookup::lookup(emulator, target);
|
||||
@ -339,7 +350,7 @@ where
|
||||
// println!("API Call Edge {:x} {:x}", src, dest);
|
||||
return Some(1);
|
||||
}
|
||||
} else if !h.app_range.contains(&src) && dest == 0 {
|
||||
} else if dest == 0 { // !h.app_range.contains(&src) &&
|
||||
if let Some(_) = in_any_range(&h.api_fn_ranges, src) {
|
||||
// println!("API Return Edge {:#x}", src);
|
||||
return Some(2);
|
||||
|
@ -182,16 +182,16 @@ impl ReducedFreeRTOSSystemState {
|
||||
// }
|
||||
|
||||
#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq, Eq, Hash)]
|
||||
struct ExecInterval {
|
||||
start_tick: u64,
|
||||
end_tick: u64,
|
||||
start_state: u64,
|
||||
end_state: u64,
|
||||
start_capture: (CaptureEvent, String),
|
||||
end_capture: (CaptureEvent, String),
|
||||
level: u8,
|
||||
pub struct ExecInterval {
|
||||
pub start_tick: u64,
|
||||
pub end_tick: u64,
|
||||
pub start_state: u64,
|
||||
pub end_state: u64,
|
||||
pub start_capture: (CaptureEvent, String),
|
||||
pub end_capture: (CaptureEvent, String),
|
||||
pub level: u8,
|
||||
tick_spend_preempted: u64,
|
||||
abb: Option<AtomicBasicBlock>
|
||||
pub abb: Option<AtomicBasicBlock>
|
||||
}
|
||||
|
||||
impl ExecInterval {
|
||||
@ -219,6 +219,10 @@ impl ExecInterval {
|
||||
self.invaildate();
|
||||
return true;
|
||||
}
|
||||
|
||||
pub fn get_hash_index(&self) -> (u64, u64) {
|
||||
return (self.start_state, self.abb.as_ref().expect("ABB not set").get_hash())
|
||||
}
|
||||
}
|
||||
|
||||
// Wrapper around Vec<RefinedFreeRTOSSystemState> to attach as Metadata
|
||||
@ -337,6 +341,14 @@ impl Ord for AtomicBasicBlock {
|
||||
}
|
||||
}
|
||||
|
||||
impl AtomicBasicBlock {
|
||||
fn get_hash(&self) -> u64 {
|
||||
let mut s = DefaultHasher::new();
|
||||
self.hash(&mut s);
|
||||
s.finish()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn get_task_names(trace: &Vec<ReducedFreeRTOSSystemState>) -> HashSet<String> {
|
||||
let mut ret: HashSet<_, _> = HashSet::new();
|
||||
@ -346,194 +358,4 @@ fn get_task_names(trace: &Vec<ReducedFreeRTOSSystemState>) -> HashSet<String> {
|
||||
ret
|
||||
}
|
||||
|
||||
// fn extract_abbs_from_trace(trace: &Vec<ReducedFreeRTOSSystemState>) -> HashMap<String,Vec<Rc<AtomicBasicBlock>>> {
|
||||
// let mut abbs_of_task : HashMap<String, Vec<Rc<AtomicBasicBlock>>> = HashMap::new();
|
||||
// let mut last_abb_of_task : HashMap<String, usize> = HashMap::new();
|
||||
// // iterate over all states and extract atomic basic blocks
|
||||
// // an atomic base block has a single entry and multiple exits
|
||||
// // the cuts between blocks are api calls
|
||||
// // when capture_point is APIEnd, the destination of the edge is the start of an atomic block
|
||||
// // so the next APIStart with the same current_tcb.pcTaskName is the end of the atomic block
|
||||
// for i in 0..trace.len() {
|
||||
// let curr_name = trace[i].current_task.0.task_name.clone();
|
||||
// let last : Option<&usize> = last_abb_of_task.get(&curr_name);
|
||||
// match trace[i].capture_point.0 {
|
||||
// CaptureEvent::APIStart => {
|
||||
// // end the last atomic block
|
||||
// if let Some(&l) = last {
|
||||
// let start = trace[l].edge.1.unwrap();
|
||||
// let end = trace[i].edge.0.unwrap();
|
||||
// match abbs_of_task.get_mut(&curr_name) {
|
||||
// Some(v) => {
|
||||
// match v.iter_mut().find(|x| x.start==start) {
|
||||
// Some(abb) => {
|
||||
// Rc::get_mut(abb).unwrap().ends.insert(end);
|
||||
// }
|
||||
// None => {
|
||||
// let mut t = HashSet::new();
|
||||
// t.insert(end);
|
||||
// v.push(Rc::new(AtomicBasicBlock {start, ends: t}));
|
||||
// }
|
||||
// };
|
||||
// },
|
||||
// None => {
|
||||
// let mut v = Vec::new();
|
||||
// let mut t = HashSet::new();
|
||||
// t.insert(end);
|
||||
// v.push(Rc::new(AtomicBasicBlock {start, ends: t}));
|
||||
// abbs_of_task.insert(curr_name, v);
|
||||
// }
|
||||
// }
|
||||
// } else {
|
||||
// // first API call of this task
|
||||
// let mut v = Vec::new();
|
||||
// let mut t = HashSet::new();
|
||||
// let end = trace[i].edge.0.unwrap();
|
||||
// t.insert(end);
|
||||
// v.push(Rc::new(AtomicBasicBlock {start: 0, ends: t}));
|
||||
// abbs_of_task.insert(curr_name, v);
|
||||
// }
|
||||
// },
|
||||
// CaptureEvent::APIEnd => {
|
||||
// match last {
|
||||
// Some(&l) => {
|
||||
// //assert!(trace[l].capture_point.0 == CaptureEvent::APIStart);
|
||||
// },
|
||||
// None => (),
|
||||
// }
|
||||
// last_abb_of_task.insert(curr_name, i);
|
||||
// },
|
||||
// CaptureEvent::ISRStart => {
|
||||
// },
|
||||
// CaptureEvent::ISREnd => {
|
||||
// },
|
||||
// CaptureEvent::End => {
|
||||
// // end the last atomic block
|
||||
// if let Some(&l) = last {
|
||||
// let start = trace[l].edge.1.unwrap();
|
||||
// let end = trace[i].edge.0.unwrap();
|
||||
// match abbs_of_task.get_mut(&curr_name) {
|
||||
// Some(v) => {
|
||||
// match v.iter_mut().find(|x| x.start==start) {
|
||||
// Some(abb) => {
|
||||
// Rc::get_mut(abb).unwrap().ends.insert(end);
|
||||
// }
|
||||
// None => {
|
||||
// let mut t = HashSet::new();
|
||||
// t.insert(end);
|
||||
// v.push(Rc::new(AtomicBasicBlock {start, ends: t}));
|
||||
// }
|
||||
// };
|
||||
// },
|
||||
// None => {
|
||||
// let mut v = Vec::new();
|
||||
// let mut t = HashSet::new();
|
||||
// t.insert(end);
|
||||
// v.push(Rc::new(AtomicBasicBlock {start, ends: t}));
|
||||
// abbs_of_task.insert(curr_name, v);
|
||||
// }
|
||||
// }
|
||||
// } else {
|
||||
// // first API call of this task
|
||||
// let mut v = Vec::new();
|
||||
// let mut t = HashSet::new();
|
||||
// let end = trace[i].edge.0.unwrap();
|
||||
// t.insert(end);
|
||||
// v.push(Rc::new(AtomicBasicBlock {start: 0, ends: t}));
|
||||
// abbs_of_task.insert(curr_name, v);
|
||||
// }
|
||||
// },
|
||||
// CaptureEvent::Undefined => {
|
||||
// },
|
||||
// }
|
||||
// }
|
||||
// abbs_of_task
|
||||
// }
|
||||
|
||||
/// returns (name, abb, index, ticks, Option<total abb ticks iff abb termiates here>)
|
||||
// fn trace_to_state_abb(trace: &Vec<ReducedFreeRTOSSystemState>) -> (Vec<(String, Rc<AtomicBasicBlock>, usize, u64)>, Vec<(AtomicBasicBlock, u64)>) {
|
||||
// let mut abbs_in_exec_order : Vec<(usize,AtomicBasicBlock,u64)> = vec![]; // indices in trace where an abb ends, along with it's time
|
||||
// let mut has_started : HashSet<String> = HashSet::new();
|
||||
// let mut abb_begin_end : HashMap<usize,usize> = HashMap::new();
|
||||
// let mut last_abb_of_task : HashMap<String, usize> = HashMap::new();
|
||||
// for i in 0..trace.len() {
|
||||
// let curr_name = trace[i].current_task.0.task_name.clone();
|
||||
// let last : Option<&usize> = last_abb_of_task.get(&curr_name);
|
||||
// match trace[i].capture_point.0 {
|
||||
// CaptureEvent::APIStart => {
|
||||
// // end the last atomic block, which began with APIEnd or initial PendSV End
|
||||
// if let Some(&l) = last {
|
||||
// // let start = trace[l].edge.1.unwrap();
|
||||
// // let end = trace[i].edge.0.unwrap();
|
||||
// abb_begin_end.insert(l, i);
|
||||
// } else {
|
||||
// panic!("Start an API call with no ABB to terminate");
|
||||
// }
|
||||
// last_abb_of_task.remove(&curr_name);
|
||||
// },
|
||||
// CaptureEvent::APIEnd => {
|
||||
// // APIEnd means a new ABB begins
|
||||
// match last {
|
||||
// Some(&l) => {
|
||||
// panic!("End an API call with open ABB");
|
||||
// },
|
||||
// None => (),
|
||||
// }
|
||||
// last_abb_of_task.insert(curr_name, i);
|
||||
// },
|
||||
// CaptureEvent::ISRStart => {
|
||||
// },
|
||||
// CaptureEvent::ISREnd => {
|
||||
// if last.is_none() && trace[i].capture_point.1=="xPortPendSVHandler" && !has_started.contains(&curr_name) {
|
||||
// // The initial ABB of a tasks starts not when an api call ends, but when it is fist scheduled
|
||||
// last_abb_of_task.insert(curr_name.clone(), i);
|
||||
// has_started.insert(curr_name);
|
||||
// }
|
||||
// },
|
||||
// CaptureEvent::End => {
|
||||
// // end the last atomic block
|
||||
// if let Some(&l) = last {
|
||||
// abb_begin_end.insert(l, i);
|
||||
// } else {
|
||||
// panic!("End without running ABB");
|
||||
// }
|
||||
// last_abb_of_task.remove(&curr_name);
|
||||
// },
|
||||
// CaptureEvent::Undefined => {
|
||||
// },
|
||||
// }
|
||||
// }
|
||||
// let mut abb_intervals : Vec<_> = abb_begin_end.into_iter().collect();
|
||||
// abb_intervals.sort_by_key(|(x,_)| *x);
|
||||
// let mut chunks = Vec::new(); // (name, abb, index, ticks)
|
||||
// for &(s,e) in abb_intervals.iter() {
|
||||
// let curr_name = trace[s].current_task.0.task_name.clone();
|
||||
// let start = match trace[s].capture_point.0 {
|
||||
// CaptureEvent::ISREnd => 0,
|
||||
// CaptureEvent::APIEnd => trace[s].edge.1.unwrap(),
|
||||
// _ => panic!(),
|
||||
// };
|
||||
// let end = trace[e].edge.0.unwrap();
|
||||
// let abb = Rc::new(AtomicBasicBlock {start, ends: HashSet::from([end])});
|
||||
// // find intervalls where the abb is actually running, not preempted
|
||||
// // count up exec time
|
||||
// let mut sum_of_pieces = 0;
|
||||
// for i in s..e {
|
||||
// if trace[i].current_task.0.task_name == curr_name {
|
||||
// match trace[i].capture_point.0 {
|
||||
// CaptureEvent::APIEnd => {chunks.push((curr_name.clone(), abb.clone(), i, trace[i+1].end_tick-trace[i].end_tick)); sum_of_pieces+=trace[i+1].end_tick-trace[i].end_tick;},
|
||||
// CaptureEvent::ISRStart => (),
|
||||
// CaptureEvent::ISREnd => {chunks.push((curr_name.clone(), abb.clone(), i, trace[i+1].end_tick-trace[i].end_tick)); sum_of_pieces+=trace[i+1].end_tick-trace[i].end_tick;},
|
||||
// _ => panic!(),
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// abbs_in_exec_order.push((e,(*abb).clone(), sum_of_pieces));
|
||||
// }
|
||||
// abbs_in_exec_order.sort_by_key(|x| x.0);
|
||||
// let abbs_in_exec_order : Vec<_> = abbs_in_exec_order.into_iter().map(|(_x,y,z)| (y,z)).collect();
|
||||
// chunks.sort_by_key(|x| x.2);
|
||||
// (chunks, abbs_in_exec_order)
|
||||
// }
|
||||
|
||||
libafl_bolts::impl_serdeany!(AtomicBasicBlock);
|
@ -53,6 +53,7 @@ where
|
||||
// unsafe {self.last_run = invalidate_ineffective_isr(refine_system_states(&mut CURRENT_SYSTEMSTATE_VEC));}
|
||||
unsafe {
|
||||
let mut temp = refine_system_states(&mut CURRENT_SYSTEMSTATE_VEC);
|
||||
fix_broken_trace(&mut temp.1);
|
||||
self.last_run = temp.0.clone();
|
||||
// println!("{:?}",temp);
|
||||
let mut temp = states2intervals(temp.0, temp.1);
|
||||
@ -174,6 +175,9 @@ fn states2intervals(trace: Vec<ReducedFreeRTOSSystemState>, meta: Vec<(u64, Capt
|
||||
let curr_name = trace[i].current_task.task_name.as_str();
|
||||
let level = match meta[i].1 {
|
||||
CaptureEvent::APIEnd => { // API end always exits towards the app
|
||||
if !level_of_task.contains_key(curr_name) {
|
||||
level_of_task.insert(curr_name, 0);
|
||||
}
|
||||
*level_of_task.get_mut(curr_name).unwrap()=0;
|
||||
&0
|
||||
},
|
||||
@ -197,14 +201,19 @@ fn states2intervals(trace: Vec<ReducedFreeRTOSSystemState>, meta: Vec<(u64, Capt
|
||||
}
|
||||
},
|
||||
CaptureEvent::ISRStart => {
|
||||
// special case for isrs which do not capture their end
|
||||
if meta[i].2 == "isr_starter" {
|
||||
&2
|
||||
} else {
|
||||
// regular case
|
||||
if isr_stack.len() > 0 {
|
||||
let l = isr_stack.back().unwrap();
|
||||
isr_stack.push_back(l+1);
|
||||
isr_stack.push_back(*l);
|
||||
isr_stack.back().unwrap()
|
||||
} else {
|
||||
isr_stack.push_back(2);
|
||||
&2
|
||||
}
|
||||
}}
|
||||
}
|
||||
_ => &100
|
||||
};
|
||||
@ -240,7 +249,8 @@ fn add_abb_info(trace: &mut Vec<ExecInterval>, table: &HashMap<u64, ReducedFreeR
|
||||
let curr_name = &table[&trace[i].start_state].current_task.task_name;
|
||||
// let last : Option<&usize> = last_abb_start_of_task.get(&curr_name);
|
||||
|
||||
let open_abb = open_abb_at_this_task_or_level.get(&(trace[i].level, if trace[i].level<2 {&curr_name} else {""})); // apps/apis are differentiated by task name, isrs by nested level
|
||||
let open_abb = open_abb_at_this_task_or_level.get(&(trace[i].level, if trace[i].level<2 {&curr_name} else {trace[i].start_capture.1.as_str()})).to_owned(); // apps/apis are differentiated by task name, isrs by nested level
|
||||
|
||||
|
||||
match (&trace[i].start_capture.0, &trace[i].end_capture.0) {
|
||||
// case with abb to block correspondence
|
||||
@ -265,13 +275,13 @@ fn add_abb_info(trace: &mut Vec<ExecInterval>, table: &HashMap<u64, ReducedFreeR
|
||||
// generic isr abb start
|
||||
CaptureEvent::ISRStart => {
|
||||
assert_eq!(open_abb, None);
|
||||
open_abb_at_this_task_or_level.insert((trace[i].level, if trace[i].level<2 {&curr_name} else {""}), i);
|
||||
open_abb_at_this_task_or_level.insert( (trace[i].level, if trace[i].level<2 {&curr_name} else {trace[i].start_capture.1.as_str()}) , i);
|
||||
wip_abb_trace.push(Rc::new(RefCell::new(AtomicBasicBlock{start: edges[i].0.unwrap(), ends: HashSet::new(), level: if trace[i].level<2 {trace[i].level} else {2}})));
|
||||
},
|
||||
// generic app abb start
|
||||
CaptureEvent::APIEnd => {
|
||||
assert_eq!(open_abb, None);
|
||||
open_abb_at_this_task_or_level.insert((trace[i].level, if trace[i].level<2 {&curr_name} else {""}), i);
|
||||
open_abb_at_this_task_or_level.insert( (trace[i].level, if trace[i].level<2 {&curr_name} else {trace[i].start_capture.1.as_str()}) , i);
|
||||
wip_abb_trace.push(Rc::new(RefCell::new(AtomicBasicBlock{start: edges[i].0.unwrap(), ends: HashSet::new(), level: if trace[i].level<2 {trace[i].level} else {2}})));
|
||||
},
|
||||
// generic continued blocks
|
||||
@ -280,11 +290,11 @@ fn add_abb_info(trace: &mut Vec<ExecInterval>, table: &HashMap<u64, ReducedFreeR
|
||||
if trace[i].start_capture.1=="xPortPendSVHandler" && !task_has_started.contains(curr_name) {
|
||||
assert_eq!(open_abb, None);
|
||||
wip_abb_trace.push(Rc::new(RefCell::new(AtomicBasicBlock{start: 0, ends: HashSet::new(), level: if trace[i].level<2 {trace[i].level} else {2}})));
|
||||
open_abb_at_this_task_or_level.insert((trace[i].level, if trace[i].level<2 {&curr_name} else {""}), i);
|
||||
open_abb_at_this_task_or_level.insert( (trace[i].level, if trace[i].level<2 {&curr_name} else {trace[i].start_capture.1.as_str()}) , i);
|
||||
task_has_started.insert(curr_name.clone());
|
||||
} else {
|
||||
// generic case, continue a preempted block
|
||||
let last = open_abb_at_this_task_or_level.get(&(trace[i].level, if trace[i].level<2 {&curr_name} else {""})).expect(&format!("Continued block with no start {} {} {}", trace[i].start_tick, task_has_started.contains(curr_name),trace[i].level));
|
||||
let last = open_abb_at_this_task_or_level.get(&(trace[i].level, if trace[i].level<2 {&curr_name} else {trace[i].start_capture.1.as_str()})).expect(&format!("Continued block with no start {} {} {}", trace[i].start_tick, task_has_started.contains(curr_name),trace[i].level));
|
||||
wip_abb_trace.push(wip_abb_trace[*last].clone());
|
||||
}
|
||||
},
|
||||
@ -295,30 +305,31 @@ fn add_abb_info(trace: &mut Vec<ExecInterval>, table: &HashMap<u64, ReducedFreeR
|
||||
CaptureEvent::APIStart => {
|
||||
let _t = &wip_abb_trace[i];
|
||||
RefCell::borrow_mut(&*wip_abb_trace[i]).ends.insert(edges[i].1.unwrap());
|
||||
open_abb_at_this_task_or_level.remove(&(trace[i].level, if trace[i].level<2 {&curr_name} else {""}));
|
||||
open_abb_at_this_task_or_level.remove(&(trace[i].level, if trace[i].level<2 {&curr_name} else {trace[i].start_capture.1.as_str()}));
|
||||
},
|
||||
// generic api abb end
|
||||
CaptureEvent::APIEnd => {
|
||||
RefCell::borrow_mut(&*wip_abb_trace[i]).ends.insert(edges[i].1.unwrap());
|
||||
open_abb_at_this_task_or_level.remove(&(trace[i].level, if trace[i].level<2 {&curr_name} else {""}));
|
||||
open_abb_at_this_task_or_level.remove(&(trace[i].level, if trace[i].level<2 {&curr_name} else {trace[i].start_capture.1.as_str()}));
|
||||
},
|
||||
// generic isr abb end
|
||||
CaptureEvent::ISREnd => {
|
||||
RefCell::borrow_mut(&*wip_abb_trace[i]).ends.insert(edges[i].1.unwrap());
|
||||
open_abb_at_this_task_or_level.remove(&(trace[i].level, if trace[i].level<2 {&curr_name} else {""}));
|
||||
open_abb_at_this_task_or_level.remove(&(trace[i].level, if trace[i].level<2 {&curr_name} else {trace[i].start_capture.1.as_str()}));
|
||||
},
|
||||
// end anything
|
||||
CaptureEvent::End => {
|
||||
RefCell::borrow_mut(&*wip_abb_trace[i]).ends.insert(edges[i].1.unwrap());
|
||||
open_abb_at_this_task_or_level.remove(&(trace[i].level, if trace[i].level<2 {&curr_name} else {""}));
|
||||
open_abb_at_this_task_or_level.remove(&(trace[i].level, if trace[i].level<2 {&curr_name} else {trace[i].start_capture.1.as_str()}));
|
||||
},
|
||||
CaptureEvent::ISRStart => (),
|
||||
_ => panic!("Undefined block end")
|
||||
}
|
||||
}
|
||||
}
|
||||
// println!("{} {:x}-{:x} {:x} {} {} {:?} {:?}",curr_name, edges[i].0.unwrap_or(0xffff), edges[i].1.unwrap_or(0xffff), ((*wip_abb_trace[i])).borrow().start, &table[&trace[i].end_state].current_task.task_name, trace[i].level, trace[i].start_capture, trace[i].end_capture);
|
||||
// println!("{} {} {:x}-{:x} {:x}-{:X} {:?} {:?} {}",curr_name, trace[i].level, edges[i].0.unwrap_or(0xffff), edges[i].1.unwrap_or(0xffff), ((*wip_abb_trace[i])).borrow().start, ((*wip_abb_trace[i])).borrow().ends.iter().next().unwrap_or(&0xffff), trace[i].start_capture, trace[i].end_capture, trace[i].start_tick);
|
||||
}
|
||||
drop(open_abb_at_this_task_or_level);
|
||||
|
||||
for i in 0..trace.len() {
|
||||
trace[i].abb = Some((*wip_abb_trace[i]).borrow().clone());
|
||||
@ -412,6 +423,16 @@ fn add_abb_info(trace: &mut Vec<ExecInterval>, table: &HashMap<u64, ReducedFreeR
|
||||
}
|
||||
|
||||
|
||||
/// restore the isr/api begin/end invariant
|
||||
fn fix_broken_trace(meta: &mut Vec<(u64, CaptureEvent, String, (Option<u32>, Option<u32>))>) {
|
||||
for i in meta.iter_mut() {
|
||||
if i.1 == CaptureEvent::APIStart && i.2 == "vTaskGenericNotifyGiveFromISR" {
|
||||
i.1 = CaptureEvent::ISREnd;
|
||||
i.2 = "isr_starter".to_string();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// invalidate subsequent intervals of equal states where an ISREnd follows an ISRStart. If the interrupt had no effect on the system we, are not interested.
|
||||
fn invalidate_ineffective_isr(trace: &mut Vec<ExecInterval>) {
|
||||
let mut i = 0;
|
||||
|
@ -70,7 +70,24 @@ impl STGNode {
|
||||
pub fn pretty_print(&self) -> String {
|
||||
format!("{}\nl{} {:x}-{:x}\n{}", self.base.current_task.task_name, self.abb.level, self.abb.start, self.abb.ends.iter().next().unwrap_or_else(||&0xFFFF), self.base.print_lists())
|
||||
}
|
||||
fn calculate_hash(&self) -> u64 {
|
||||
pub fn color_print(&self) -> String {
|
||||
let color = match self.abb.level {
|
||||
1 => "\", shape=box, style=filled, fillcolor=\"lightblue",
|
||||
2 => "\", shape=box, style=filled, fillcolor=\"yellow",
|
||||
0 => "\", shape=box, style=filled, fillcolor=\"white",
|
||||
_ => "\", style=filled, fillcolor=\"lightgray",
|
||||
};
|
||||
let message = match self.abb.level {
|
||||
1 => format!("API Call"),
|
||||
2 => format!("ISR"),
|
||||
0 => format!("Task: {}",self.base.current_task.task_name),
|
||||
_ => format!(""),
|
||||
};
|
||||
let mut label = format!("{}\nABB: {:x}-{:x}\n{}", message, self.abb.start, self.abb.ends.iter().next().unwrap_or_else(||&0xFFFF), self.base.print_lists());
|
||||
label.push_str(color);
|
||||
label
|
||||
}
|
||||
fn get_hash(&self) -> u64 {
|
||||
let mut s = DefaultHasher::new();
|
||||
self.base.hash(&mut s);
|
||||
self.abb.hash(&mut s);
|
||||
@ -104,6 +121,18 @@ impl STGEdge {
|
||||
short.push_str(&self.name);
|
||||
short
|
||||
}
|
||||
pub fn color_print(&self) -> String {
|
||||
let mut short = self.name.clone();
|
||||
short.push_str(match self.event {
|
||||
CaptureEvent::APIStart => "\", color=\"blue",
|
||||
CaptureEvent::APIEnd => "\", color=\"black",
|
||||
CaptureEvent::ISRStart => "\", color=red, style=\"dashed",
|
||||
CaptureEvent::ISREnd => "\", color=red, style=\"solid",
|
||||
CaptureEvent::End => "",
|
||||
CaptureEvent::Undefined => "",
|
||||
});
|
||||
short
|
||||
}
|
||||
}
|
||||
|
||||
/// Shared Metadata for a systemstateFeedback
|
||||
@ -113,9 +142,10 @@ pub struct STGFeedbackState
|
||||
// aggregated traces as a graph
|
||||
pub graph: DiGraph<STGNode, STGEdge>,
|
||||
systemstate_index: HashMap<u64, ReducedFreeRTOSSystemState>,
|
||||
state_abb_hash_index: HashMap<(u64, u64), NodeIndex>,
|
||||
stgnode_index: HashMap<u64, NodeIndex>,
|
||||
entrypoint: NodeIndex,
|
||||
exit: NodeIndex,
|
||||
exitpoint: NodeIndex,
|
||||
// Metadata about aggregated traces. aggegated meaning, order has been removed
|
||||
worst_observed_per_aggegated_path: HashMap<Vec<AtomicBasicBlock>,u64>
|
||||
}
|
||||
@ -130,21 +160,24 @@ impl Default for STGFeedbackState {
|
||||
|
||||
let systemstate_index = HashMap::from([(entry.base.get_hash(), entry.base.clone()), (exit.base.get_hash(), exit.base.clone())]);
|
||||
|
||||
let h_entry = entry.calculate_hash();
|
||||
let h_exit = exit.calculate_hash();
|
||||
let h_entry = entry.get_hash();
|
||||
let h_exit = exit.get_hash();
|
||||
|
||||
let entrypoint = graph.add_node(entry);
|
||||
let exit = graph.add_node(exit);
|
||||
let entrypoint = graph.add_node(entry.clone());
|
||||
let exitpoint = graph.add_node(exit.clone());
|
||||
|
||||
let index = HashMap::from([(h_entry, entrypoint), (h_exit, exit)]);
|
||||
let state_abb_hash_index = HashMap::from([((entry.base.get_hash(), entry.abb.get_hash()), entrypoint), ((exit.base.get_hash(), exit.abb.get_hash()), exitpoint)]);
|
||||
|
||||
let index = HashMap::from([(h_entry, entrypoint), (h_exit, exitpoint)]);
|
||||
|
||||
STGFeedbackState {
|
||||
graph,
|
||||
stgnode_index: index,
|
||||
entrypoint,
|
||||
exit,
|
||||
exitpoint,
|
||||
worst_observed_per_aggegated_path: HashMap::new(),
|
||||
systemstate_index,
|
||||
state_abb_hash_index
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -157,6 +190,43 @@ impl Named for STGFeedbackState
|
||||
}
|
||||
}
|
||||
|
||||
// Wrapper around Vec<RefinedFreeRTOSSystemState> to attach as Metadata
|
||||
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
|
||||
pub struct STGNodeMetadata {
|
||||
pub inner: Vec<NodeIndex>,
|
||||
pub intervals: Vec<ExecInterval>,
|
||||
indices: Vec<usize>,
|
||||
tcref: isize,
|
||||
}
|
||||
impl STGNodeMetadata {
|
||||
pub fn new(inner: Vec<NodeIndex>, intervals: Vec<ExecInterval>) -> Self{
|
||||
Self {indices: inner.iter().map(|x| x.index()).collect(), intervals, inner: inner, tcref: 0}
|
||||
}
|
||||
}
|
||||
impl AsSlice for STGNodeMetadata {
|
||||
/// Convert the slice of system-states to a slice of hashes over enumerated states
|
||||
fn as_slice(&self) -> &[usize] {
|
||||
self.indices.as_slice()
|
||||
}
|
||||
|
||||
type Entry = usize;
|
||||
}
|
||||
|
||||
impl HasRefCnt for STGNodeMetadata {
|
||||
fn refcnt(&self) -> isize {
|
||||
self.tcref
|
||||
}
|
||||
|
||||
fn refcnt_mut(&mut self) -> &mut isize {
|
||||
&mut self.tcref
|
||||
}
|
||||
}
|
||||
|
||||
libafl_bolts::impl_serdeany!(STGNodeMetadata);
|
||||
|
||||
pub type GraphMaximizerCorpusScheduler<CS> =
|
||||
MinimizerScheduler<CS, MaxTimeFavFactor<<CS as UsesState>::State>,STGNodeMetadata>;
|
||||
|
||||
//============================= Graph Feedback
|
||||
|
||||
pub static mut STG_MAP: [u8; EDGES_MAP_SIZE] = [0; EDGES_MAP_SIZE];
|
||||
@ -171,19 +241,20 @@ pub struct StgFeedback
|
||||
{
|
||||
name: String,
|
||||
last_trace: Option<Vec<NodeIndex>>,
|
||||
last_intervals: Option<Vec<ExecInterval>>,
|
||||
}
|
||||
#[cfg(feature = "feed_stg")]
|
||||
const INTEREST_EDGE : bool = false;
|
||||
#[cfg(feature = "feed_stg")]
|
||||
const INTEREST_NODE : bool = false;
|
||||
#[cfg(feature = "feed_stg")]
|
||||
const INTEREST_AGGREGATE : bool = false;
|
||||
#[cfg(not(feature = "feed_stg"))]
|
||||
const INTEREST_EDGE : bool = true;
|
||||
#[cfg(not(feature = "feed_stg"))]
|
||||
#[cfg(feature = "feed_stg")]
|
||||
const INTEREST_NODE : bool = true;
|
||||
#[cfg(not(feature = "feed_stg"))]
|
||||
#[cfg(feature = "feed_stg")]
|
||||
const INTEREST_AGGREGATE : bool = true;
|
||||
#[cfg(not(feature = "feed_stg"))]
|
||||
const INTEREST_EDGE : bool = false;
|
||||
#[cfg(not(feature = "feed_stg"))]
|
||||
const INTEREST_NODE : bool = false;
|
||||
#[cfg(not(feature = "feed_stg"))]
|
||||
const INTEREST_AGGREGATE : bool = false;
|
||||
fn set_observer_map(trace : &Vec<EdgeIndex>) {
|
||||
unsafe {
|
||||
for i in 0..MAX_STG_NUM {
|
||||
@ -199,74 +270,18 @@ fn set_observer_map(trace : &Vec<EdgeIndex>) {
|
||||
}
|
||||
impl StgFeedback {
|
||||
pub fn new() -> Self {
|
||||
Self {name: String::from("SysMapFeedback"), last_trace: None }
|
||||
Self {name: String::from("STGFeedback"), last_trace: None, last_intervals: None }
|
||||
}
|
||||
/// params:
|
||||
/// tarce of system states
|
||||
/// list of all atomic basic blocks with asociated state index and ticks
|
||||
/// produces:
|
||||
/// tarce of node indexes representing the path trough the graph
|
||||
/// newly discovered node?
|
||||
/// side effect:
|
||||
/// the graph gets new nodes
|
||||
// fn update_stg(trace: &Vec<ReducedFreeRTOSSystemState>, map: Vec<(String, Rc<AtomicBasicBlock>, usize, u64)>, fbs: &mut STGFeedbackState) -> (Vec<NodeIndex>, Vec<EdgeIndex>, bool) {
|
||||
// let mut return_node_trace = vec![fbs.entrypoint];
|
||||
// let mut return_edge_trace = vec![];
|
||||
// let mut interesting = false;
|
||||
// // add all missing state+abb combinations to the graph
|
||||
// for (i,state) in trace.iter().enumerate() { // Iterate states first, keep the trace order intact
|
||||
// if let Some(marker) = map.iter().filter(|(_,_,index,_)| index==&i).next() { //
|
||||
// let node = STGNode {base: state.clone(), abb: (*marker.1).clone()};
|
||||
// let h_node = node.calculate_hash();
|
||||
// let next_idx = if let Some(idx) = fbs.index.get(&h_node) {
|
||||
// // alredy present
|
||||
// *idx
|
||||
// } else {
|
||||
// // not present
|
||||
// let idx = fbs.graph.add_node(node);
|
||||
// fbs.index.insert(h_node, idx);
|
||||
// interesting |= INTEREST_NODE;
|
||||
// idx
|
||||
// };
|
||||
// // connect in graph if edge not present
|
||||
// let e = fbs.graph.edges_directed(return_node_trace[return_node_trace.len()-1],Direction::Outgoing).find(|x| petgraph::visit::EdgeRef::target(x) == next_idx);
|
||||
// if let Some(e_) = e {
|
||||
// return_edge_trace.push(petgraph::visit::EdgeRef::id(&e_));
|
||||
// } else {
|
||||
// let e_ = fbs.graph.add_edge(return_node_trace[return_node_trace.len()-1], next_idx, ());
|
||||
// return_edge_trace.push(e_);
|
||||
// interesting |= INTEREST_EDGE;
|
||||
// }
|
||||
// return_node_trace.push(next_idx);
|
||||
// /*
|
||||
// Ideas:
|
||||
// Mark edges triggered by interrupts
|
||||
// Specify path with edges instead of nodes?
|
||||
// Form a coverage map over edges?
|
||||
// Sum up execution time per ABB
|
||||
// */
|
||||
// }
|
||||
// }
|
||||
// // every path terminates at the end
|
||||
// if !fbs.graph.neighbors_directed(return_node_trace[return_node_trace.len()-1],Direction::Outgoing).any(|x| x == fbs.exit) {
|
||||
// let e_ = fbs.graph.add_edge(return_node_trace[return_node_trace.len()-1], fbs.exit, ());
|
||||
// return_edge_trace.push(e_);
|
||||
// interesting |= INTEREST_EDGE;
|
||||
// }
|
||||
// return_node_trace.push(fbs.exit);
|
||||
// #[cfg(feature = "feed_stg")]
|
||||
// set_observer_map(&return_edge_trace);
|
||||
// (return_node_trace, return_edge_trace, interesting)
|
||||
// }
|
||||
|
||||
/// params:
|
||||
/// tarce of system states
|
||||
/// list of all atomic basic blocks with asociated state index and ticks
|
||||
/// tarce of intervals
|
||||
/// hashtable of states
|
||||
/// feedbackstate
|
||||
/// produces:
|
||||
/// tarce of node indexes representing the path trough the graph
|
||||
/// newly discovered node?
|
||||
/// side effect:
|
||||
/// the graph gets new nodes
|
||||
/// the graph gets new nodes and edge
|
||||
fn update_stg_interval(trace: &Vec<ExecInterval>, table: &HashMap<u64, ReducedFreeRTOSSystemState>, fbs: &mut STGFeedbackState) -> (Vec<NodeIndex>, Vec<EdgeIndex>, bool) {
|
||||
let mut return_node_trace = vec![fbs.entrypoint];
|
||||
let mut return_edge_trace = vec![];
|
||||
@ -274,14 +289,16 @@ impl StgFeedback {
|
||||
// add all missing state+abb combinations to the graph
|
||||
for (i,interval) in trace.iter().enumerate() { // Iterate intervals
|
||||
let node = STGNode {base: table[&interval.start_state].clone(), abb: interval.abb.as_ref().unwrap().clone()};
|
||||
let h_node = node.calculate_hash();
|
||||
let h_node = node.get_hash();
|
||||
let next_idx = if let Some(idx) = fbs.stgnode_index.get(&h_node) {
|
||||
// alredy present
|
||||
*idx
|
||||
} else {
|
||||
// not present
|
||||
let h = (node.base.get_hash(), node.abb.get_hash());
|
||||
let idx = fbs.graph.add_node(node);
|
||||
fbs.stgnode_index.insert(h_node, idx);
|
||||
fbs.state_abb_hash_index.insert(h, idx);
|
||||
interesting |= INTEREST_NODE;
|
||||
idx
|
||||
};
|
||||
@ -304,16 +321,27 @@ impl StgFeedback {
|
||||
*/
|
||||
}
|
||||
// every path terminates at the end
|
||||
if !fbs.graph.neighbors_directed(return_node_trace[return_node_trace.len()-1],Direction::Outgoing).any(|x| x == fbs.exit) {
|
||||
let e_ = fbs.graph.add_edge(return_node_trace[return_node_trace.len()-1], fbs.exit, STGEdge { event: CaptureEvent::End, name: String::from("End") });
|
||||
if !fbs.graph.neighbors_directed(return_node_trace[return_node_trace.len()-1],Direction::Outgoing).any(|x| x == fbs.exitpoint) {
|
||||
let e_ = fbs.graph.add_edge(return_node_trace[return_node_trace.len()-1], fbs.exitpoint, STGEdge { event: CaptureEvent::End, name: String::from("End") });
|
||||
return_edge_trace.push(e_);
|
||||
interesting |= INTEREST_EDGE;
|
||||
}
|
||||
return_node_trace.push(fbs.exit);
|
||||
return_node_trace.push(fbs.exitpoint);
|
||||
#[cfg(feature = "feed_stg")]
|
||||
set_observer_map(&return_edge_trace);
|
||||
(return_node_trace, return_edge_trace, interesting)
|
||||
}
|
||||
|
||||
fn abbs_in_exec_order(trace: &Vec<ExecInterval>) -> Vec<AtomicBasicBlock> {
|
||||
let mut ret = Vec::new();
|
||||
for i in 0..trace.len() {
|
||||
if trace[i].abb != None &&
|
||||
(trace[i].end_capture.0 == CaptureEvent::APIStart || trace[i].end_capture.0 == CaptureEvent::APIEnd || trace[i].end_capture.0 == CaptureEvent::End || trace[i].end_capture.0 == CaptureEvent::ISREnd) {
|
||||
ret.push(trace[i].abb.as_ref().unwrap().clone());
|
||||
}
|
||||
}
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> Feedback<S> for StgFeedback
|
||||
@ -349,39 +377,42 @@ where
|
||||
}
|
||||
};
|
||||
|
||||
let (_trace, _, mut interesting) = StgFeedback::update_stg_interval(&observer.last_trace, &observer.last_states, feedbackstate);
|
||||
// let (abbs, ordered) = trace_to_state_abb(&observer.last_run);
|
||||
// // println!("{:?}",abbs);
|
||||
// let (_trace, _, mut interesting) = StgFeedback::update_stg(&observer.last_run, abbs, feedbackstate);
|
||||
// if INTEREST_AGGREGATE {
|
||||
// let (it1, _it2) : (Vec<_>, Vec<_>) = ordered.into_iter().unzip();
|
||||
// // aggegation by sorting, order of states is not relevant
|
||||
// let mut tmp : Vec<_> = it1;
|
||||
// tmp.sort();
|
||||
// if let Some(x) = feedbackstate.worst_observed_per_aggegated_path.get_mut(&tmp) {
|
||||
// let t = clock_observer.last_runtime();
|
||||
// if t > *x {
|
||||
// *x = t;
|
||||
// interesting |= INTEREST_AGGREGATE;
|
||||
// }
|
||||
// } else {
|
||||
// feedbackstate.worst_observed_per_aggegated_path.insert(tmp, clock_observer.last_runtime());
|
||||
// interesting |= INTEREST_AGGREGATE;
|
||||
// }
|
||||
// }
|
||||
let (nodetrace, _edgetrace, mut interesting) = StgFeedback::update_stg_interval(&observer.last_trace, &observer.last_states, feedbackstate);
|
||||
|
||||
if INTEREST_AGGREGATE {
|
||||
let mut tmp = StgFeedback::abbs_in_exec_order(&observer.last_trace);
|
||||
// aggegation by sorting, order of states is not relevant
|
||||
tmp.sort();
|
||||
if let Some(x) = feedbackstate.worst_observed_per_aggegated_path.get_mut(&tmp) {
|
||||
let t = clock_observer.last_runtime();
|
||||
if t > *x {
|
||||
*x = t;
|
||||
interesting |= INTEREST_AGGREGATE;
|
||||
}
|
||||
} else {
|
||||
feedbackstate.worst_observed_per_aggegated_path.insert(tmp, clock_observer.last_runtime());
|
||||
interesting |= INTEREST_AGGREGATE;
|
||||
}
|
||||
}
|
||||
|
||||
// let out = feedbackstate.graph.map(|i,x| x.pretty_print(), |_,_| "");
|
||||
// let outs = Dot::with_config(&out, &[Config::EdgeNoLabel]).to_string();
|
||||
// let outs = outs.replace(';',"\\n");
|
||||
// fs::write("./mystg.dot",outs).expect("Failed to write graph");
|
||||
self.last_trace = Some(nodetrace);
|
||||
self.last_intervals = Some(observer.last_trace.clone());
|
||||
|
||||
// Ok(interesting)
|
||||
Ok(interesting)
|
||||
}
|
||||
|
||||
/// Append to the testcase the generated metadata in case of a new corpus item
|
||||
#[inline]
|
||||
fn append_metadata<OT>(&mut self, _state: &mut S, _observers: &OT, testcase: &mut Testcase<S::Input>) -> Result<(), Error> {
|
||||
fn append_metadata<OT>(&mut self, _state: &mut S, observers: &OT, testcase: &mut Testcase<S::Input>) -> Result<(), Error> {
|
||||
let a = self.last_trace.take();
|
||||
match a {
|
||||
Some(s) => testcase.metadata_map_mut().insert(STGNodeMetadata::new(s, self.last_intervals.take().unwrap())),
|
||||
None => (),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user