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"
|
edition = "2021"
|
||||||
|
|
||||||
[features]
|
[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 = []
|
std = []
|
||||||
snapshot_restore = []
|
snapshot_restore = []
|
||||||
snapshot_fast = [ "snapshot_restore" ]
|
snapshot_fast = [ "snapshot_restore" ]
|
||||||
@ -24,7 +24,7 @@ gensize_1 = [ ]
|
|||||||
gensize_10 = [ ]
|
gensize_10 = [ ]
|
||||||
gensize_100 = [ ]
|
gensize_100 = [ ]
|
||||||
observer_hitcounts = []
|
observer_hitcounts = []
|
||||||
no_hash_state = []
|
do_hash_notify_state = []
|
||||||
count_iterations = []
|
count_iterations = []
|
||||||
run_until_saturation = []
|
run_until_saturation = []
|
||||||
|
|
||||||
|
@ -36,6 +36,7 @@ use core::{fmt::Debug, time::Duration};
|
|||||||
// use libafl::feedbacks::FeedbackState;
|
// use libafl::feedbacks::FeedbackState;
|
||||||
// use libafl::state::HasFeedbackStates;
|
// use libafl::state::HasFeedbackStates;
|
||||||
use std::time::{SystemTime, UNIX_EPOCH};
|
use std::time::{SystemTime, UNIX_EPOCH};
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
pub static mut FUZZ_START_TIMESTAMP : SystemTime = UNIX_EPOCH;
|
pub static mut FUZZ_START_TIMESTAMP : SystemTime = UNIX_EPOCH;
|
||||||
|
|
||||||
@ -98,16 +99,18 @@ pub struct QemuClockObserver {
|
|||||||
name: String,
|
name: String,
|
||||||
start_tick: u64,
|
start_tick: u64,
|
||||||
end_tick: u64,
|
end_tick: u64,
|
||||||
|
dump_path: Option<PathBuf>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl QemuClockObserver {
|
impl QemuClockObserver {
|
||||||
/// Creates a new [`QemuClockObserver`] with the given name.
|
/// Creates a new [`QemuClockObserver`] with the given name.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new(name: &'static str) -> Self {
|
pub fn new(name: &'static str, dump_path: Option<PathBuf>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
name: name.to_string(),
|
name: name.to_string(),
|
||||||
start_tick: 0,
|
start_tick: 0,
|
||||||
end_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> {
|
fn post_exec(&mut self, _state: &mut S, _input: &S::Input, _exit_kind: &ExitKind) -> Result<(), Error> {
|
||||||
unsafe { self.end_tick = emu::icount_get_raw() };
|
unsafe { self.end_tick = emu::icount_get_raw() };
|
||||||
// println!("clock post {}", self.end_tick);
|
if let Some(td) = &self.dump_path {
|
||||||
// println!("Number of Ticks: {} <- {} {}",self.end_tick - self.start_tick, self.end_tick, self.start_tick);
|
// println!("clock post {}", self.end_tick);
|
||||||
let metadata =_state.metadata_map_mut();
|
// println!("Number of Ticks: {} <- {} {}",self.end_tick - self.start_tick, self.end_tick, self.start_tick);
|
||||||
let hist = metadata.get_mut::<IcHist>();
|
let metadata =_state.metadata_map_mut();
|
||||||
let timestamp = SystemTime::now().duration_since(unsafe {FUZZ_START_TIMESTAMP}).unwrap().as_millis();
|
let hist = metadata.get_mut::<IcHist>();
|
||||||
match hist {
|
let timestamp = SystemTime::now().duration_since(unsafe {FUZZ_START_TIMESTAMP}).unwrap().as_millis();
|
||||||
None => {
|
match hist {
|
||||||
metadata.insert(IcHist(vec![(self.end_tick - self.start_tick, timestamp)],
|
None => {
|
||||||
(self.end_tick - self.start_tick, timestamp)));
|
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 v.0.len() >= 100 {
|
Some(v) => {
|
||||||
if let Ok(td) = env::var("DUMP_TIMES") {
|
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()
|
let mut file = OpenOptions::new()
|
||||||
.read(true)
|
.read(true)
|
||||||
.write(true)
|
.write(true)
|
||||||
.create(true)
|
.create(true)
|
||||||
.append(true)
|
.append(true)
|
||||||
.open(td).expect("Could not open timedump");
|
.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() {
|
for i in std::mem::replace(&mut v.0, newv).into_iter() {
|
||||||
writeln!(file, "{},{}", i.0, i.1).expect("Write to dump failed");
|
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"),
|
name: String::from("clock"),
|
||||||
start_tick: 0,
|
start_tick: 0,
|
||||||
end_tick: 0,
|
end_tick: 0,
|
||||||
|
dump_path: None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,19 +14,23 @@ use libafl_qemu::{
|
|||||||
};
|
};
|
||||||
use rand::{SeedableRng, StdRng, Rng};
|
use rand::{SeedableRng, StdRng, Rng};
|
||||||
use crate::{
|
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 std::time::{SystemTime, UNIX_EPOCH};
|
||||||
use clap::{Parser, Subcommand};
|
use clap::{Parser, Subcommand};
|
||||||
use csv::Reader;
|
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;
|
use crate::systemstate::stg::STGFeedbackState;
|
||||||
|
|
||||||
// Constants ================================================================================
|
// Constants ================================================================================
|
||||||
|
|
||||||
pub static mut RNG_SEED: u64 = 1;
|
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 MAX_NUM_INTERRUPT: usize = 32;
|
||||||
pub const DO_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 {
|
for sym in &funcs {
|
||||||
let sym_name = gob.strtab.get_at(sym.st_name);
|
let sym_name = gob.strtab.get_at(sym.st_name);
|
||||||
if let Some(sym_name) = sym_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) {
|
if let Some(r) = get_function_range(elf, sym_name) {
|
||||||
api_addreses.insert(sym_name.to_string(), r);
|
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});
|
let dump_path = $cli.dump_name.clone().unwrap().with_extension(if $c=="" {"stg"} else {$c});
|
||||||
println!("Dumping graph to {:?}", &dump_path);
|
println!("Dumping graph to {:?}", &dump_path);
|
||||||
if let Some(md) = $state.named_metadata_map_mut().get_mut::<STGFeedbackState>("stgfeedbackstate") {
|
if let Some(md) = $state.named_metadata_map_mut().get_mut::<STGFeedbackState>("stgfeedbackstate") {
|
||||||
let out = md.graph.map(|i,x| x.pretty_print(), |_,_| "");
|
let out = md.graph.map(|i,x| x.color_print(), |i,x| x.color_print());
|
||||||
let outs = Dot::with_config(&out, &[Config::EdgeNoLabel]).to_string();
|
let outs = Dot::with_config(&out, &[]).to_string();
|
||||||
|
let outs = outs.replace("\\\"","\"");
|
||||||
let outs = outs.replace(';',"\\n");
|
let outs = outs.replace(';',"\\n");
|
||||||
fs::write(dump_path,outs).expect("Failed to write graph");
|
fs::write(dump_path,outs).expect("Failed to write graph");
|
||||||
}
|
}
|
||||||
@ -302,17 +308,10 @@ pub fn fuzz() {
|
|||||||
let cli = Cli::parse();
|
let cli = Cli::parse();
|
||||||
env_from_config(&cli.kernel, &cli.config);
|
env_from_config(&cli.kernel, &cli.config);
|
||||||
unsafe {FUZZ_START_TIMESTAMP = SystemTime::now();}
|
unsafe {FUZZ_START_TIMESTAMP = SystemTime::now();}
|
||||||
if let Some(n) = &cli.dump_name {
|
if cli.dump_name.is_none() && (cli.dump_times || cli.dump_cases || cli.dump_traces || cli.dump_graph) {
|
||||||
if cli.dump_times {
|
panic!("Dump name not give but dump is requested");
|
||||||
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");
|
|
||||||
}
|
}
|
||||||
let mut starttime = std::time::Instant::now();
|
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
|
// Hardcoded parameters
|
||||||
let timeout = Duration::from_secs(10);
|
let timeout = Duration::from_secs(10);
|
||||||
let broker_port = 1337;
|
let broker_port = 1337;
|
||||||
@ -354,6 +353,7 @@ pub fn fuzz() {
|
|||||||
let task_delay_addr = load_symbol(&elf, "pxDelayedTaskList", false);
|
let task_delay_addr = load_symbol(&elf, "pxDelayedTaskList", false);
|
||||||
let task_delay_overflow_addr = load_symbol(&elf, "pxOverflowDelayedTaskList", false);
|
let task_delay_overflow_addr = load_symbol(&elf, "pxOverflowDelayedTaskList", false);
|
||||||
let scheduler_lock = load_symbol(&elf, "uxSchedulerSuspended", 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 critical_section = load_symbol(&elf, "uxCriticalNesting", false);
|
||||||
// let task_queue_addr = virt2phys(task_queue_addr,&elf.goblin());
|
// let task_queue_addr = virt2phys(task_queue_addr,&elf.goblin());
|
||||||
#[cfg(feature = "systemstate")]
|
#[cfg(feature = "systemstate")]
|
||||||
@ -472,7 +472,7 @@ pub fn fuzz() {
|
|||||||
t[j]=buf[i*4+j];
|
t[j]=buf[i*4+j];
|
||||||
}
|
}
|
||||||
if i == 0 || true {
|
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 {
|
} else {
|
||||||
start_tick = u32::saturating_add(start_tick,max(MINIMUM_INTER_ARRIVAL_TIME,u32::from_le_bytes(t)));
|
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
|
// 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();
|
let systemstate_observer = QemuSystemStateObserver::new();
|
||||||
|
|
||||||
@ -629,7 +629,7 @@ pub fn fuzz() {
|
|||||||
let qhelpers = tuple_list!(
|
let qhelpers = tuple_list!(
|
||||||
QemuEdgeCoverageHelper::default(),
|
QemuEdgeCoverageHelper::default(),
|
||||||
QemuStateRestoreHelper::new(),
|
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);
|
let mut hooks = QemuHooks::new(emu.clone(),qhelpers);
|
||||||
|
|
||||||
|
@ -9,16 +9,10 @@ use libafl_bolts::rands::{
|
|||||||
Rand
|
Rand
|
||||||
};
|
};
|
||||||
use libafl::{
|
use libafl::{
|
||||||
corpus::{Corpus, self},
|
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
|
||||||
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},
|
|
||||||
};
|
};
|
||||||
use libafl::prelude::State;
|
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);
|
pub const MINIMUM_INTER_ARRIVAL_TIME : u32 = 700 * 1000 * (1 << 4);
|
||||||
|
|
||||||
@ -48,7 +42,7 @@ where
|
|||||||
E: UsesState<State = Z::State>,
|
E: UsesState<State = Z::State>,
|
||||||
EM: UsesState<State = Z::State>,
|
EM: UsesState<State = Z::State>,
|
||||||
Z: Evaluator<E, EM>,
|
Z: Evaluator<E, EM>,
|
||||||
Z::State: MaybeHasClientPerfMonitor + HasCorpus + HasRand + HasMetadata,
|
Z::State: MaybeHasClientPerfMonitor + HasCorpus + HasRand + HasMetadata + HasNamedMetadata,
|
||||||
<Z::State as UsesInput>::Input: HasBytesVec
|
<Z::State as UsesInput>::Input: HasBytesVec
|
||||||
{
|
{
|
||||||
fn perform(
|
fn perform(
|
||||||
@ -89,7 +83,7 @@ where
|
|||||||
t[j]=target_bytes[i*4+j];
|
t[j]=target_bytes[i*4+j];
|
||||||
}
|
}
|
||||||
if i == 0 || true {
|
if i == 0 || true {
|
||||||
start_tick = u32::from_le_bytes(t);
|
start_tick = u32::from_le_bytes(t)+FIRST_INT;
|
||||||
} else {
|
} else {
|
||||||
start_tick = u32::saturating_add(start_tick,max(MINIMUM_INTER_ARRIVAL_TIME,u32::from_le_bytes(t)));
|
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 suffix = target_bytes.split_off(4 * num_interrupts);
|
||||||
let mut prefix : Vec<[u8; 4]> = vec![];
|
let mut prefix : Vec<[u8; 4]> = vec![];
|
||||||
// let mut suffix : Vec<u8> = 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() {
|
if tmp.is_some() {
|
||||||
let trace = tmp.expect("FreeRTOSSystemStateMetadata not found");
|
let trace = tmp.expect("STGNodeMetadata not found");
|
||||||
|
|
||||||
// calculate hits and identify snippets
|
// calculate hits and identify snippets
|
||||||
let mut last_m = false;
|
let mut last_m = false;
|
||||||
let mut marks : Vec<(&RefinedFreeRTOSSystemState, 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.inner.len() {
|
for i in 0..trace.intervals.len() {
|
||||||
let curr = &trace.inner[i];
|
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)));
|
let m = interrupt_offsets[0..num_interrupts].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));
|
||||||
@ -197,7 +200,7 @@ where
|
|||||||
let mut numbers : Vec<u32> = interrupt_offsets[0..num_interrupts].to_vec();
|
let mut numbers : Vec<u32> = interrupt_offsets[0..num_interrupts].to_vec();
|
||||||
numbers.sort();
|
numbers.sort();
|
||||||
// println!("Mutator: {:?}", numbers);
|
// println!("Mutator: {:?}", numbers);
|
||||||
let mut start : u32 = 0;
|
// let mut start : u32 = 0;
|
||||||
// for i in 0..numbers.len() {
|
// for i in 0..numbers.len() {
|
||||||
// let tmp = numbers[i];
|
// let tmp = numbers[i];
|
||||||
// numbers[i] = numbers[i]-start;
|
// numbers[i] = numbers[i]-start;
|
||||||
|
@ -20,7 +20,7 @@ use hashbrown::HashMap;
|
|||||||
use libafl::{executors::ExitKind, inputs::Input, observers::ObserversTuple, state::HasMetadata};
|
use libafl::{executors::ExitKind, inputs::Input, observers::ObserversTuple, state::HasMetadata};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use super::RefinedFreeRTOSSystemState;
|
use super::ReducedFreeRTOSSystemState;
|
||||||
use super::FreeRTOSSystemStateMetadata;
|
use super::FreeRTOSSystemStateMetadata;
|
||||||
use super::observers::QemuSystemStateObserver;
|
use super::observers::QemuSystemStateObserver;
|
||||||
use petgraph::prelude::DiGraph;
|
use petgraph::prelude::DiGraph;
|
||||||
@ -35,7 +35,7 @@ use std::cmp::Ordering;
|
|||||||
pub struct SystemStateFeedbackState
|
pub struct SystemStateFeedbackState
|
||||||
{
|
{
|
||||||
known_traces: HashMap<u64,(u64,u64,usize)>, // encounters,ticks,length
|
known_traces: HashMap<u64,(u64,u64,usize)>, // encounters,ticks,length
|
||||||
longest: Vec<RefinedFreeRTOSSystemState>,
|
longest: Vec<ReducedFreeRTOSSystemState>,
|
||||||
}
|
}
|
||||||
impl Named for SystemStateFeedbackState
|
impl Named for SystemStateFeedbackState
|
||||||
{
|
{
|
||||||
@ -57,7 +57,7 @@ impl Named for SystemStateFeedbackState
|
|||||||
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
|
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
|
||||||
pub struct NovelSystemStateFeedback
|
pub struct NovelSystemStateFeedback
|
||||||
{
|
{
|
||||||
last_trace: Option<Vec<RefinedFreeRTOSSystemState>>,
|
last_trace: Option<Vec<ReducedFreeRTOSSystemState>>,
|
||||||
// known_traces: HashMap<u64,(u64,usize)>,
|
// 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;
|
let mut ret = true;
|
||||||
if target.len() > last.len() {return false;}
|
if target.len() > last.len() {return false;}
|
||||||
for i in 0..target.len() {
|
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
|
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;
|
let mut ret = true;
|
||||||
if target.len() > last.len() {return false;}
|
if target.len() > last.len() {return false;}
|
||||||
for i in 0..target.len() {
|
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
|
ret
|
||||||
}
|
}
|
||||||
@ -213,8 +213,8 @@ impl Named for HitSystemStateFeedback
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl HitSystemStateFeedback {
|
impl HitSystemStateFeedback {
|
||||||
pub fn new(target: Option<Vec<RefinedFreeRTOSSystemState>>) -> Self {
|
pub fn new(target: Option<Vec<ReducedFreeRTOSSystemState>>) -> Self {
|
||||||
Self {target: target.map(|x| x.into_iter().map(|y| y.current_task.0.task_name).collect())}
|
Self {target: target.map(|x| x.into_iter().map(|y| y.current_task.task_name).collect())}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//=========================== Debugging Feedback
|
//=========================== Debugging Feedback
|
||||||
@ -224,7 +224,7 @@ pub struct DumpSystraceFeedback
|
|||||||
{
|
{
|
||||||
dumpfile: Option<PathBuf>,
|
dumpfile: Option<PathBuf>,
|
||||||
dump_metadata: bool,
|
dump_metadata: bool,
|
||||||
last_trace: Option<Vec<RefinedFreeRTOSSystemState>>,
|
last_trace: Option<Vec<ReducedFreeRTOSSystemState>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S> Feedback<S> for DumpSystraceFeedback
|
impl<S> Feedback<S> for DumpSystraceFeedback
|
||||||
@ -245,7 +245,7 @@ where
|
|||||||
{
|
{
|
||||||
let observer = observers.match_name::<QemuSystemStateObserver>("systemstate")
|
let observer = observers.match_name::<QemuSystemStateObserver>("systemstate")
|
||||||
.expect("QemuSystemStateObserver not found");
|
.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 {
|
match &self.dumpfile {
|
||||||
Some(s) => {
|
Some(s) => {
|
||||||
std::fs::write(s,ron::to_string(&observer.last_run).expect("Error serializing hashmap")).expect("Can not dump to file");
|
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 libafl::{executors::ExitKind, inputs::Input, observers::ObserversTuple, state::HasMetadata};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use super::RefinedFreeRTOSSystemState;
|
use super::ExecInterval;
|
||||||
|
use super::ReducedFreeRTOSSystemState;
|
||||||
use super::FreeRTOSSystemStateMetadata;
|
use super::FreeRTOSSystemStateMetadata;
|
||||||
use super::observers::QemuSystemStateObserver;
|
use super::observers::QemuSystemStateObserver;
|
||||||
use petgraph::prelude::DiGraph;
|
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
|
pub input: Vec<u8>, // in the end any kind of input are bytes, regardless of type and lifetime
|
||||||
}
|
}
|
||||||
impl VariantTuple {
|
impl VariantTuple {
|
||||||
fn from(other: &RefinedFreeRTOSSystemState,input: Vec<u8>) -> Self {
|
fn from(other: &ReducedFreeRTOSSystemState,input: Vec<u8>) -> Self {
|
||||||
VariantTuple{
|
// VariantTuple{
|
||||||
start_tick: other.start_tick,
|
// start_tick: other.tick,
|
||||||
end_tick: other.end_tick,
|
// end_tick: other.end_tick,
|
||||||
input_counter: other.input_counter,
|
// input_counter: other.input_counter,
|
||||||
input: input,
|
// input: input,
|
||||||
}
|
// }
|
||||||
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
|
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
|
||||||
pub struct SysGraphNode
|
pub struct SysGraphNode
|
||||||
{
|
{
|
||||||
base: RefinedFreeRTOSSystemState,
|
base: ReducedFreeRTOSSystemState,
|
||||||
pub variants: Vec<VariantTuple>,
|
pub variants: Vec<VariantTuple>,
|
||||||
}
|
}
|
||||||
impl SysGraphNode {
|
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 }
|
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
|
/// unites the variants of this value with another, draining the other if the bases are equal
|
||||||
@ -86,42 +88,43 @@ impl SysGraphNode {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
/// add a Varint from a [`RefinedFreeRTOSSystemState`]
|
/// 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;}
|
if &self.base!=other {return false;}
|
||||||
self.variants.push(VariantTuple::from(other, input.clone()));
|
self.variants.push(VariantTuple::from(other, input.clone()));
|
||||||
self.variants.dedup();
|
self.variants.dedup();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
/// add a Varint from a [`RefinedFreeRTOSSystemState`], if it's interesting
|
/// add a Varint from a [`RefinedFreeRTOSSystemState`], if it's interesting
|
||||||
fn unite_interesting(&mut self, other: &RefinedFreeRTOSSystemState, input: &Vec<u8>) -> bool {
|
fn unite_interesting(&mut self, other: &ReducedFreeRTOSSystemState, input: &Vec<u8>) -> bool {
|
||||||
if &self.base!=other {return false;}
|
// if &self.base!=other {return false;}
|
||||||
let interesting =
|
// 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.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.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) || // longest input
|
||||||
self.variants.iter().all(|x| x.input_counter<other.input_counter); // shortest input
|
// self.variants.iter().all(|x| x.input_counter<other.input_counter); // shortest input
|
||||||
if interesting {
|
// if interesting {
|
||||||
let var = VariantTuple::from(other, input.clone());
|
// let var = VariantTuple::from(other, input.clone());
|
||||||
self.variants.push(var);
|
// self.variants.push(var);
|
||||||
}
|
// }
|
||||||
return interesting;
|
// return interesting;
|
||||||
|
todo!()
|
||||||
}
|
}
|
||||||
pub fn get_taskname(&self) -> &str {
|
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> {
|
pub fn get_input_counts(&self) -> Vec<u32> {
|
||||||
self.variants.iter().map(|x| x.input_counter).collect()
|
self.variants.iter().map(|x| x.input_counter).collect()
|
||||||
}
|
}
|
||||||
pub fn pretty_print(&self) -> String {
|
pub fn pretty_print(&self) -> String {
|
||||||
let mut ret = String::new();
|
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:");
|
ret.push_str(";Rl:");
|
||||||
for i in &self.base.ready_list_after {
|
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:");
|
ret.push_str(";Dl:");
|
||||||
for i in &self.base.delay_list_after {
|
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);
|
// println!("{}",ret);
|
||||||
ret
|
ret
|
||||||
@ -185,14 +188,14 @@ impl SysGraphFeedbackState
|
|||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let mut graph = DiGraph::<SysGraphNode, ()>::new();
|
let mut graph = DiGraph::<SysGraphNode, ()>::new();
|
||||||
let mut entry = SysGraphNode::default();
|
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();
|
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 entry = graph.add_node(entry);
|
||||||
let exit = graph.add_node(exit);
|
let exit = graph.add_node(exit);
|
||||||
Self {graph: graph, entrypoint: entry, exit: exit, name: String::from("SysMap")}
|
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;
|
let mut current_index = self.entrypoint;
|
||||||
for n in list {
|
for n in list {
|
||||||
let mut done = false;
|
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
|
/// 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 current_index = self.entrypoint;
|
||||||
let mut novel = false;
|
let mut novel = false;
|
||||||
let mut trace : Vec<NodeIndex> = vec![current_index];
|
let mut trace : Vec<NodeIndex> = vec![current_index];
|
||||||
@ -262,9 +265,9 @@ impl SysGraphFeedbackState
|
|||||||
fn reset(&mut self) -> Result<(), Error> {
|
fn reset(&mut self) -> Result<(), Error> {
|
||||||
self.graph.clear();
|
self.graph.clear();
|
||||||
let mut entry = SysGraphNode::default();
|
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();
|
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.entrypoint = self.graph.add_node(entry);
|
||||||
self.exit = self.graph.add_node(exit);
|
self.exit = self.graph.add_node(exit);
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -13,7 +13,7 @@ use libafl_qemu::edges::QemuEdgesMapMetadata;
|
|||||||
use libafl_qemu::emu;
|
use libafl_qemu::emu;
|
||||||
use libafl_qemu::hooks;
|
use libafl_qemu::hooks;
|
||||||
use libafl_qemu::Hook;
|
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::RawFreeRTOSSystemState;
|
||||||
use crate::systemstate::CURRENT_SYSTEMSTATE_VEC;
|
use crate::systemstate::CURRENT_SYSTEMSTATE_VEC;
|
||||||
use crate::systemstate::NUM_PRIOS;
|
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] = &[
|
pub const ISR_SYMBOLS : &'static [&'static str] = &[
|
||||||
// ISRs
|
// 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
|
//============================= Qemu Helper
|
||||||
@ -60,6 +60,7 @@ pub struct QemuSystemStateHelper {
|
|||||||
delay_queue: GuestAddr,
|
delay_queue: GuestAddr,
|
||||||
delay_queue_overflow: GuestAddr,
|
delay_queue_overflow: GuestAddr,
|
||||||
scheduler_lock_addr: GuestAddr,
|
scheduler_lock_addr: GuestAddr,
|
||||||
|
scheduler_running_addr: GuestAddr,
|
||||||
critical_addr: GuestAddr,
|
critical_addr: GuestAddr,
|
||||||
input_counter: Option<GuestAddr>,
|
input_counter: Option<GuestAddr>,
|
||||||
app_range: Range<GuestAddr>,
|
app_range: Range<GuestAddr>,
|
||||||
@ -77,6 +78,7 @@ impl QemuSystemStateHelper {
|
|||||||
delay_queue: GuestAddr,
|
delay_queue: GuestAddr,
|
||||||
delay_queue_overflow: GuestAddr,
|
delay_queue_overflow: GuestAddr,
|
||||||
scheduler_lock_addr: GuestAddr,
|
scheduler_lock_addr: GuestAddr,
|
||||||
|
scheduler_running_addr: GuestAddr,
|
||||||
critical_addr: GuestAddr,
|
critical_addr: GuestAddr,
|
||||||
input_counter: Option<GuestAddr>,
|
input_counter: Option<GuestAddr>,
|
||||||
app_range: Range<GuestAddr>,
|
app_range: Range<GuestAddr>,
|
||||||
@ -91,6 +93,7 @@ impl QemuSystemStateHelper {
|
|||||||
delay_queue,
|
delay_queue,
|
||||||
delay_queue_overflow,
|
delay_queue_overflow,
|
||||||
scheduler_lock_addr,
|
scheduler_lock_addr,
|
||||||
|
scheduler_running_addr,
|
||||||
critical_addr,
|
critical_addr,
|
||||||
input_counter: input_counter,
|
input_counter: input_counter,
|
||||||
app_range,
|
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);
|
let next_item : freertos::ListItem_t = freertos::emu_lookup::lookup(emulator, next_index);
|
||||||
// println!("Item at {}: {:?}",next_index,next_item);
|
// 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 new_next_index=next_item.pxNext;
|
||||||
let next_tcb : TCB_t= freertos::emu_lookup::lookup(emulator,next_item.pvOwner);
|
let next_tcb : TCB_t= freertos::emu_lookup::lookup(emulator,next_item.pvOwner);
|
||||||
// println!("TCB at {}: {:?}",next_item.pvOwner,next_tcb);
|
// 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));
|
// println!("{:?}",std::str::from_utf8(¤t_tcb.pcTaskName));
|
||||||
let critical : void_ptr = freertos::emu_lookup::lookup(emulator, h.critical_addr);
|
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 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);
|
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
|
// 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
|
// Extract delay list
|
||||||
let mut target : GuestAddr = h.delay_queue;
|
let mut target : GuestAddr = h.delay_queue;
|
||||||
target = freertos::emu_lookup::lookup(emulator, target);
|
target = freertos::emu_lookup::lookup(emulator, target);
|
||||||
@ -339,7 +350,7 @@ where
|
|||||||
// println!("API Call Edge {:x} {:x}", src, dest);
|
// println!("API Call Edge {:x} {:x}", src, dest);
|
||||||
return Some(1);
|
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) {
|
if let Some(_) = in_any_range(&h.api_fn_ranges, src) {
|
||||||
// println!("API Return Edge {:#x}", src);
|
// println!("API Return Edge {:#x}", src);
|
||||||
return Some(2);
|
return Some(2);
|
||||||
|
@ -182,16 +182,16 @@ impl ReducedFreeRTOSSystemState {
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq, Eq, Hash)]
|
||||||
struct ExecInterval {
|
pub struct ExecInterval {
|
||||||
start_tick: u64,
|
pub start_tick: u64,
|
||||||
end_tick: u64,
|
pub end_tick: u64,
|
||||||
start_state: u64,
|
pub start_state: u64,
|
||||||
end_state: u64,
|
pub end_state: u64,
|
||||||
start_capture: (CaptureEvent, String),
|
pub start_capture: (CaptureEvent, String),
|
||||||
end_capture: (CaptureEvent, String),
|
pub end_capture: (CaptureEvent, String),
|
||||||
level: u8,
|
pub level: u8,
|
||||||
tick_spend_preempted: u64,
|
tick_spend_preempted: u64,
|
||||||
abb: Option<AtomicBasicBlock>
|
pub abb: Option<AtomicBasicBlock>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ExecInterval {
|
impl ExecInterval {
|
||||||
@ -219,6 +219,10 @@ impl ExecInterval {
|
|||||||
self.invaildate();
|
self.invaildate();
|
||||||
return true;
|
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
|
// 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> {
|
fn get_task_names(trace: &Vec<ReducedFreeRTOSSystemState>) -> HashSet<String> {
|
||||||
let mut ret: HashSet<_, _> = HashSet::new();
|
let mut ret: HashSet<_, _> = HashSet::new();
|
||||||
@ -346,194 +358,4 @@ fn get_task_names(trace: &Vec<ReducedFreeRTOSSystemState>) -> HashSet<String> {
|
|||||||
ret
|
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);
|
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 {self.last_run = invalidate_ineffective_isr(refine_system_states(&mut CURRENT_SYSTEMSTATE_VEC));}
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut temp = refine_system_states(&mut CURRENT_SYSTEMSTATE_VEC);
|
let mut temp = refine_system_states(&mut CURRENT_SYSTEMSTATE_VEC);
|
||||||
|
fix_broken_trace(&mut temp.1);
|
||||||
self.last_run = temp.0.clone();
|
self.last_run = temp.0.clone();
|
||||||
// println!("{:?}",temp);
|
// println!("{:?}",temp);
|
||||||
let mut temp = states2intervals(temp.0, temp.1);
|
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 curr_name = trace[i].current_task.task_name.as_str();
|
||||||
let level = match meta[i].1 {
|
let level = match meta[i].1 {
|
||||||
CaptureEvent::APIEnd => { // API end always exits towards the app
|
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;
|
*level_of_task.get_mut(curr_name).unwrap()=0;
|
||||||
&0
|
&0
|
||||||
},
|
},
|
||||||
@ -197,14 +201,19 @@ fn states2intervals(trace: Vec<ReducedFreeRTOSSystemState>, meta: Vec<(u64, Capt
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
CaptureEvent::ISRStart => {
|
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 {
|
if isr_stack.len() > 0 {
|
||||||
let l = isr_stack.back().unwrap();
|
let l = isr_stack.back().unwrap();
|
||||||
isr_stack.push_back(l+1);
|
isr_stack.push_back(*l);
|
||||||
isr_stack.back().unwrap()
|
isr_stack.back().unwrap()
|
||||||
} else {
|
} else {
|
||||||
isr_stack.push_back(2);
|
isr_stack.push_back(2);
|
||||||
&2
|
&2
|
||||||
}
|
}}
|
||||||
}
|
}
|
||||||
_ => &100
|
_ => &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 curr_name = &table[&trace[i].start_state].current_task.task_name;
|
||||||
// let last : Option<&usize> = last_abb_start_of_task.get(&curr_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) {
|
match (&trace[i].start_capture.0, &trace[i].end_capture.0) {
|
||||||
// case with abb to block correspondence
|
// 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
|
// generic isr abb start
|
||||||
CaptureEvent::ISRStart => {
|
CaptureEvent::ISRStart => {
|
||||||
assert_eq!(open_abb, None);
|
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}})));
|
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
|
// generic app abb start
|
||||||
CaptureEvent::APIEnd => {
|
CaptureEvent::APIEnd => {
|
||||||
assert_eq!(open_abb, None);
|
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}})));
|
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
|
// 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) {
|
if trace[i].start_capture.1=="xPortPendSVHandler" && !task_has_started.contains(curr_name) {
|
||||||
assert_eq!(open_abb, None);
|
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}})));
|
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());
|
task_has_started.insert(curr_name.clone());
|
||||||
} else {
|
} else {
|
||||||
// generic case, continue a preempted block
|
// 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());
|
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 => {
|
CaptureEvent::APIStart => {
|
||||||
let _t = &wip_abb_trace[i];
|
let _t = &wip_abb_trace[i];
|
||||||
RefCell::borrow_mut(&*wip_abb_trace[i]).ends.insert(edges[i].1.unwrap());
|
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
|
// generic api abb end
|
||||||
CaptureEvent::APIEnd => {
|
CaptureEvent::APIEnd => {
|
||||||
RefCell::borrow_mut(&*wip_abb_trace[i]).ends.insert(edges[i].1.unwrap());
|
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
|
// generic isr abb end
|
||||||
CaptureEvent::ISREnd => {
|
CaptureEvent::ISREnd => {
|
||||||
RefCell::borrow_mut(&*wip_abb_trace[i]).ends.insert(edges[i].1.unwrap());
|
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
|
// end anything
|
||||||
CaptureEvent::End => {
|
CaptureEvent::End => {
|
||||||
RefCell::borrow_mut(&*wip_abb_trace[i]).ends.insert(edges[i].1.unwrap());
|
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 => (),
|
CaptureEvent::ISRStart => (),
|
||||||
_ => panic!("Undefined block end")
|
_ => 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() {
|
for i in 0..trace.len() {
|
||||||
trace[i].abb = Some((*wip_abb_trace[i]).borrow().clone());
|
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.
|
/// 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>) {
|
fn invalidate_ineffective_isr(trace: &mut Vec<ExecInterval>) {
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
|
@ -70,7 +70,24 @@ impl STGNode {
|
|||||||
pub fn pretty_print(&self) -> String {
|
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())
|
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();
|
let mut s = DefaultHasher::new();
|
||||||
self.base.hash(&mut s);
|
self.base.hash(&mut s);
|
||||||
self.abb.hash(&mut s);
|
self.abb.hash(&mut s);
|
||||||
@ -104,6 +121,18 @@ impl STGEdge {
|
|||||||
short.push_str(&self.name);
|
short.push_str(&self.name);
|
||||||
short
|
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
|
/// Shared Metadata for a systemstateFeedback
|
||||||
@ -113,9 +142,10 @@ pub struct STGFeedbackState
|
|||||||
// aggregated traces as a graph
|
// aggregated traces as a graph
|
||||||
pub graph: DiGraph<STGNode, STGEdge>,
|
pub graph: DiGraph<STGNode, STGEdge>,
|
||||||
systemstate_index: HashMap<u64, ReducedFreeRTOSSystemState>,
|
systemstate_index: HashMap<u64, ReducedFreeRTOSSystemState>,
|
||||||
|
state_abb_hash_index: HashMap<(u64, u64), NodeIndex>,
|
||||||
stgnode_index: HashMap<u64, NodeIndex>,
|
stgnode_index: HashMap<u64, NodeIndex>,
|
||||||
entrypoint: NodeIndex,
|
entrypoint: NodeIndex,
|
||||||
exit: NodeIndex,
|
exitpoint: NodeIndex,
|
||||||
// Metadata about aggregated traces. aggegated meaning, order has been removed
|
// Metadata about aggregated traces. aggegated meaning, order has been removed
|
||||||
worst_observed_per_aggegated_path: HashMap<Vec<AtomicBasicBlock>,u64>
|
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 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_entry = entry.get_hash();
|
||||||
let h_exit = exit.calculate_hash();
|
let h_exit = exit.get_hash();
|
||||||
|
|
||||||
let entrypoint = graph.add_node(entry);
|
let entrypoint = graph.add_node(entry.clone());
|
||||||
let exit = graph.add_node(exit);
|
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 {
|
STGFeedbackState {
|
||||||
graph,
|
graph,
|
||||||
stgnode_index: index,
|
stgnode_index: index,
|
||||||
entrypoint,
|
entrypoint,
|
||||||
exit,
|
exitpoint,
|
||||||
worst_observed_per_aggegated_path: HashMap::new(),
|
worst_observed_per_aggegated_path: HashMap::new(),
|
||||||
systemstate_index,
|
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
|
//============================= Graph Feedback
|
||||||
|
|
||||||
pub static mut STG_MAP: [u8; EDGES_MAP_SIZE] = [0; EDGES_MAP_SIZE];
|
pub static mut STG_MAP: [u8; EDGES_MAP_SIZE] = [0; EDGES_MAP_SIZE];
|
||||||
@ -171,19 +241,20 @@ pub struct StgFeedback
|
|||||||
{
|
{
|
||||||
name: String,
|
name: String,
|
||||||
last_trace: Option<Vec<NodeIndex>>,
|
last_trace: Option<Vec<NodeIndex>>,
|
||||||
|
last_intervals: Option<Vec<ExecInterval>>,
|
||||||
}
|
}
|
||||||
#[cfg(feature = "feed_stg")]
|
#[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;
|
const INTEREST_EDGE : bool = true;
|
||||||
#[cfg(not(feature = "feed_stg"))]
|
#[cfg(feature = "feed_stg")]
|
||||||
const INTEREST_NODE : bool = true;
|
const INTEREST_NODE : bool = true;
|
||||||
#[cfg(not(feature = "feed_stg"))]
|
#[cfg(feature = "feed_stg")]
|
||||||
const INTEREST_AGGREGATE : bool = true;
|
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>) {
|
fn set_observer_map(trace : &Vec<EdgeIndex>) {
|
||||||
unsafe {
|
unsafe {
|
||||||
for i in 0..MAX_STG_NUM {
|
for i in 0..MAX_STG_NUM {
|
||||||
@ -199,74 +270,18 @@ fn set_observer_map(trace : &Vec<EdgeIndex>) {
|
|||||||
}
|
}
|
||||||
impl StgFeedback {
|
impl StgFeedback {
|
||||||
pub fn new() -> Self {
|
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:
|
/// params:
|
||||||
/// tarce of system states
|
/// tarce of intervals
|
||||||
/// list of all atomic basic blocks with asociated state index and ticks
|
/// hashtable of states
|
||||||
|
/// feedbackstate
|
||||||
/// produces:
|
/// produces:
|
||||||
/// tarce of node indexes representing the path trough the graph
|
/// tarce of node indexes representing the path trough the graph
|
||||||
/// newly discovered node?
|
/// newly discovered node?
|
||||||
/// side effect:
|
/// 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) {
|
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_node_trace = vec![fbs.entrypoint];
|
||||||
let mut return_edge_trace = vec![];
|
let mut return_edge_trace = vec![];
|
||||||
@ -274,14 +289,16 @@ impl StgFeedback {
|
|||||||
// add all missing state+abb combinations to the graph
|
// add all missing state+abb combinations to the graph
|
||||||
for (i,interval) in trace.iter().enumerate() { // Iterate intervals
|
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 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) {
|
let next_idx = if let Some(idx) = fbs.stgnode_index.get(&h_node) {
|
||||||
// alredy present
|
// alredy present
|
||||||
*idx
|
*idx
|
||||||
} else {
|
} else {
|
||||||
// not present
|
// not present
|
||||||
|
let h = (node.base.get_hash(), node.abb.get_hash());
|
||||||
let idx = fbs.graph.add_node(node);
|
let idx = fbs.graph.add_node(node);
|
||||||
fbs.stgnode_index.insert(h_node, idx);
|
fbs.stgnode_index.insert(h_node, idx);
|
||||||
|
fbs.state_abb_hash_index.insert(h, idx);
|
||||||
interesting |= INTEREST_NODE;
|
interesting |= INTEREST_NODE;
|
||||||
idx
|
idx
|
||||||
};
|
};
|
||||||
@ -304,16 +321,27 @@ impl StgFeedback {
|
|||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
// every path terminates at the end
|
// 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) {
|
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.exit, STGEdge { event: CaptureEvent::End, name: String::from("End") });
|
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_);
|
return_edge_trace.push(e_);
|
||||||
interesting |= INTEREST_EDGE;
|
interesting |= INTEREST_EDGE;
|
||||||
}
|
}
|
||||||
return_node_trace.push(fbs.exit);
|
return_node_trace.push(fbs.exitpoint);
|
||||||
#[cfg(feature = "feed_stg")]
|
#[cfg(feature = "feed_stg")]
|
||||||
set_observer_map(&return_edge_trace);
|
set_observer_map(&return_edge_trace);
|
||||||
(return_node_trace, return_edge_trace, interesting)
|
(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
|
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 (nodetrace, _edgetrace, 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);
|
if INTEREST_AGGREGATE {
|
||||||
// let (_trace, _, mut interesting) = StgFeedback::update_stg(&observer.last_run, abbs, feedbackstate);
|
let mut tmp = StgFeedback::abbs_in_exec_order(&observer.last_trace);
|
||||||
// if INTEREST_AGGREGATE {
|
// aggegation by sorting, order of states is not relevant
|
||||||
// let (it1, _it2) : (Vec<_>, Vec<_>) = ordered.into_iter().unzip();
|
tmp.sort();
|
||||||
// // aggegation by sorting, order of states is not relevant
|
if let Some(x) = feedbackstate.worst_observed_per_aggegated_path.get_mut(&tmp) {
|
||||||
// let mut tmp : Vec<_> = it1;
|
let t = clock_observer.last_runtime();
|
||||||
// tmp.sort();
|
if t > *x {
|
||||||
// if let Some(x) = feedbackstate.worst_observed_per_aggegated_path.get_mut(&tmp) {
|
*x = t;
|
||||||
// let t = clock_observer.last_runtime();
|
interesting |= INTEREST_AGGREGATE;
|
||||||
// if t > *x {
|
}
|
||||||
// *x = t;
|
} else {
|
||||||
// interesting |= INTEREST_AGGREGATE;
|
feedbackstate.worst_observed_per_aggegated_path.insert(tmp, clock_observer.last_runtime());
|
||||||
// }
|
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 out = feedbackstate.graph.map(|i,x| x.pretty_print(), |_,_| "");
|
||||||
// let outs = Dot::with_config(&out, &[Config::EdgeNoLabel]).to_string();
|
// let outs = Dot::with_config(&out, &[Config::EdgeNoLabel]).to_string();
|
||||||
// let outs = outs.replace(';',"\\n");
|
// let outs = outs.replace(';',"\\n");
|
||||||
// fs::write("./mystg.dot",outs).expect("Failed to write graph");
|
// 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)
|
Ok(interesting)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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<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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user