add interesting metrics, reorganize
This commit is contained in:
parent
1d0c43081a
commit
c92cbe78d8
@ -1,8 +1,10 @@
|
|||||||
//! A singlethreaded QEMU fuzzer that can auto-restart.
|
//! A singlethreaded QEMU fuzzer that can auto-restart.
|
||||||
|
|
||||||
|
use wcet_qemu_sys::sysstate::graph::SysMapFeedback;
|
||||||
|
use wcet_qemu_sys::sysstate::graph::SysGraphFeedbackState;
|
||||||
use libafl::stats::SimpleStats;
|
use libafl::stats::SimpleStats;
|
||||||
use wcet_qemu_sys::sysstate::feedbacks::HitSysStateFeedback;
|
use wcet_qemu_sys::sysstate::feedbacks::HitSysStateFeedback;
|
||||||
use wcet_qemu_sys::sysstate::MiniFreeRTOSSystemState;
|
use wcet_qemu_sys::sysstate::RefinedFreeRTOSSystemState;
|
||||||
use libafl::corpus::QueueCorpusScheduler;
|
use libafl::corpus::QueueCorpusScheduler;
|
||||||
use libafl_qemu::QemuInstrumentationFilter;
|
use libafl_qemu::QemuInstrumentationFilter;
|
||||||
use wcet_qemu_sys::sysstate::helpers::QemuSystemStateHelper;
|
use wcet_qemu_sys::sysstate::helpers::QemuSystemStateHelper;
|
||||||
@ -330,7 +332,8 @@ fn fuzz(
|
|||||||
let feedback_state = MapFeedbackState::with_observer(&edges_observer);
|
let feedback_state = MapFeedbackState::with_observer(&edges_observer);
|
||||||
|
|
||||||
let sysstate_observer = QemuSysStateObserver::new();
|
let sysstate_observer = QemuSysStateObserver::new();
|
||||||
let sysstate_feedback_state = SysStateFeedbackState::default();
|
// let sysstate_feedback_state = SysStateFeedbackState::default();
|
||||||
|
let sysstate_feedback_state = SysGraphFeedbackState::new();
|
||||||
|
|
||||||
let target_map : HashMap<(u64,u64),u8> = match dump_edges {
|
let target_map : HashMap<(u64,u64),u8> = match dump_edges {
|
||||||
None => HashMap::new(),
|
None => HashMap::new(),
|
||||||
@ -340,11 +343,11 @@ fn fuzz(
|
|||||||
hmap
|
hmap
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
let target_trace : Option<Vec<MiniFreeRTOSSystemState>> = match dump_traces {
|
let target_trace : Option<Vec<RefinedFreeRTOSSystemState>> = match dump_traces {
|
||||||
None => None,
|
None => None,
|
||||||
Some(ref s) => {
|
Some(ref s) => {
|
||||||
let raw = fs::read(s).expect("Can not read dumped traces");
|
let raw = fs::read(s).expect("Can not read dumped traces");
|
||||||
let trace : Vec<MiniFreeRTOSSystemState> = ron::from_str(&String::from_utf8_lossy(&raw)).expect("Can not parse traces");
|
let trace : Vec<RefinedFreeRTOSSystemState> = ron::from_str(&String::from_utf8_lossy(&raw)).expect("Can not parse traces");
|
||||||
Some(trace)
|
Some(trace)
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -353,14 +356,16 @@ fn fuzz(
|
|||||||
let feedback = feedback_or!(
|
let feedback = feedback_or!(
|
||||||
// New maximization map feedback linked to the edges observer and the feedback state
|
// New maximization map feedback linked to the edges observer and the feedback state
|
||||||
MaxMapFeedback::new_tracking(&feedback_state, &edges_observer, true, false),
|
MaxMapFeedback::new_tracking(&feedback_state, &edges_observer, true, false),
|
||||||
HitImprovingFeedback::new(target_map.clone(), &edges_observer),
|
// HitImprovingFeedback::new(target_map.clone(), &edges_observer),
|
||||||
QemuClockIncreaseFeedback::default(),
|
// QemuClockIncreaseFeedback::default(),
|
||||||
ClockFeedback::new_with_observer(&clock_observer),
|
ClockFeedback::new_with_observer(&clock_observer),
|
||||||
NovelSysStateFeedback::default()
|
// NovelSysStateFeedback::default(),
|
||||||
|
SysMapFeedback::new()
|
||||||
);
|
);
|
||||||
|
|
||||||
// A feedback to choose if an input is a solution or not
|
// A feedback to choose if an input is a solution or not
|
||||||
let objective = feedback_or!(HitFeedback::new(target_map,0.0,&edges_observer),HitSysStateFeedback::new(target_trace));
|
// let objective = feedback_or!(HitFeedback::new(target_map,0.0,&edges_observer),HitSysStateFeedback::new(target_trace));
|
||||||
|
let objective = feedback_or!(HitFeedback::new(target_map,0.0,&edges_observer));
|
||||||
// let objective = SortedFeedback::new();
|
// let objective = SortedFeedback::new();
|
||||||
|
|
||||||
// create a State from scratch
|
// create a State from scratch
|
||||||
@ -392,8 +397,8 @@ fn fuzz(
|
|||||||
|
|
||||||
// A minimization+queue policy to get testcasess from the corpus
|
// A minimization+queue policy to get testcasess from the corpus
|
||||||
// let scheduler = IndexesLenTimeMinimizerCorpusScheduler::new(PowerQueueCorpusScheduler::new());
|
// let scheduler = IndexesLenTimeMinimizerCorpusScheduler::new(PowerQueueCorpusScheduler::new());
|
||||||
let scheduler = TimeStateMaximizerCorpusScheduler::new(QueueCorpusScheduler::new());
|
// let scheduler = TimeStateMaximizerCorpusScheduler::new(QueueCorpusScheduler::new());
|
||||||
// let scheduler = QueueCorpusScheduler::new();
|
let scheduler = QueueCorpusScheduler::new();
|
||||||
|
|
||||||
|
|
||||||
// A fuzzer with feedbacks and a corpus scheduler
|
// A fuzzer with feedbacks and a corpus scheduler
|
||||||
|
@ -18,7 +18,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::MiniFreeRTOSSystemState;
|
use super::RefinedFreeRTOSSystemState;
|
||||||
use super::FreeRTOSSystemStateMetadata;
|
use super::FreeRTOSSystemStateMetadata;
|
||||||
use super::observers::QemuSysStateObserver;
|
use super::observers::QemuSysStateObserver;
|
||||||
use petgraph::prelude::DiGraph;
|
use petgraph::prelude::DiGraph;
|
||||||
@ -26,170 +26,6 @@ use petgraph::graph::NodeIndex;
|
|||||||
use petgraph::Direction;
|
use petgraph::Direction;
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
|
|
||||||
//============================= Graph Feedback
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default)]
|
|
||||||
struct VariantTuple
|
|
||||||
{
|
|
||||||
start_tick: u64,
|
|
||||||
end_tick: u64,
|
|
||||||
input_counter: u32,
|
|
||||||
input: Vec<u8>, // in the end any kind of input are bytes, regardless of type and lifetime
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
|
|
||||||
struct SysGraphNode
|
|
||||||
{
|
|
||||||
base: MiniFreeRTOSSystemState,
|
|
||||||
variants: Vec<VariantTuple>,
|
|
||||||
}
|
|
||||||
impl SysGraphNode {
|
|
||||||
fn from(base: MiniFreeRTOSSystemState, input: Vec<u8>) -> Self {
|
|
||||||
SysGraphNode{variants: vec![VariantTuple{
|
|
||||||
start_tick: base.start_tick,
|
|
||||||
end_tick: base.end_tick,
|
|
||||||
input_counter: base.input_counter,
|
|
||||||
input:input}], base:base }
|
|
||||||
}
|
|
||||||
/// unites the variants of this value with another, draining the other if the bases are equal
|
|
||||||
fn unite(mut self, other: &mut SysGraphNode) -> bool {
|
|
||||||
if &self!=other {return false;}
|
|
||||||
self.variants.append(&mut other.variants);
|
|
||||||
self.variants.dedup();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl PartialEq for SysGraphNode {
|
|
||||||
fn eq(&self, other: &SysGraphNode) -> bool {
|
|
||||||
self.base==other.base
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Improved System State Graph
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
|
|
||||||
pub struct SysMapFeedbackState
|
|
||||||
{
|
|
||||||
graph: DiGraph<SysGraphNode, ()>,
|
|
||||||
entrypoint: NodeIndex,
|
|
||||||
name: String,
|
|
||||||
}
|
|
||||||
impl SysMapFeedbackState
|
|
||||||
{
|
|
||||||
pub fn new() -> Self {
|
|
||||||
let mut graph = DiGraph::<SysGraphNode, ()>::new();
|
|
||||||
let ind = graph.add_node(SysGraphNode::default());
|
|
||||||
Self {graph: graph, entrypoint: ind, name: String::from("SysMap")}
|
|
||||||
}
|
|
||||||
fn insert(&mut self, list: Vec<MiniFreeRTOSSystemState>, input: &Vec<u8>) {
|
|
||||||
let mut current_index = self.entrypoint;
|
|
||||||
for n in list {
|
|
||||||
let mut done = false;
|
|
||||||
for i in self.graph.neighbors_directed(current_index, Direction::Outgoing) {
|
|
||||||
if n == self.graph[i].base {
|
|
||||||
done = true;
|
|
||||||
current_index = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !done {
|
|
||||||
let j = self.graph.add_node(SysGraphNode::from(n,input.clone()));
|
|
||||||
self.graph.add_edge(current_index, j, ());
|
|
||||||
current_index = j;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn update(&mut self, list: &Vec<MiniFreeRTOSSystemState>, input: &Vec<u8>) -> bool {
|
|
||||||
let mut current_index = self.entrypoint;
|
|
||||||
let mut novel = false;
|
|
||||||
for n in list {
|
|
||||||
let mut matching : Option<NodeIndex> = None;
|
|
||||||
for i in self.graph.neighbors_directed(current_index, Direction::Outgoing) {
|
|
||||||
let tmp = &self.graph[i];
|
|
||||||
if n == &tmp.base {
|
|
||||||
matching = Some(i);
|
|
||||||
current_index = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
match matching {
|
|
||||||
None => {
|
|
||||||
novel = true;
|
|
||||||
let j = self.graph.add_node(SysGraphNode::from(n.clone(),input.clone()));
|
|
||||||
self.graph.add_edge(current_index, j, ());
|
|
||||||
current_index = j;
|
|
||||||
},
|
|
||||||
Some(i) => {
|
|
||||||
if n.get_time() > self.graph[i].base.get_time() {
|
|
||||||
novel = true;
|
|
||||||
self.graph[i]=SysGraphNode::from(n.clone(),input.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return novel;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Named for SysMapFeedbackState
|
|
||||||
{
|
|
||||||
#[inline]
|
|
||||||
fn name(&self) -> &str {
|
|
||||||
&self.name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl FeedbackState for SysMapFeedbackState
|
|
||||||
{
|
|
||||||
fn reset(&mut self) -> Result<(), Error> {
|
|
||||||
self.graph.clear();
|
|
||||||
self.entrypoint = self.graph.add_node(SysGraphNode::default());
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A Feedback reporting novel System-State Transitions. Depends on [`QemuSysStateObserver`]
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
|
|
||||||
pub struct SysMapFeedback
|
|
||||||
{
|
|
||||||
name: String
|
|
||||||
}
|
|
||||||
impl SysMapFeedback {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {name: String::from("SysMapFeedback") }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I, S> Feedback<I, S> for SysMapFeedback
|
|
||||||
where
|
|
||||||
I: Input,
|
|
||||||
S: HasClientPerfMonitor + HasFeedbackStates,
|
|
||||||
{
|
|
||||||
fn is_interesting<EM, OT>(
|
|
||||||
&mut self,
|
|
||||||
state: &mut S,
|
|
||||||
_manager: &mut EM,
|
|
||||||
_input: &I,
|
|
||||||
observers: &OT,
|
|
||||||
_exit_kind: &ExitKind,
|
|
||||||
) -> Result<bool, Error>
|
|
||||||
where
|
|
||||||
EM: EventFirer<I>,
|
|
||||||
OT: ObserversTuple<I, S>,
|
|
||||||
{
|
|
||||||
let observer = observers.match_name::<QemuSysStateObserver>("sysstate")
|
|
||||||
.expect("QemuSysStateObserver not found");
|
|
||||||
let feedbackstate = state
|
|
||||||
.feedback_states_mut()
|
|
||||||
.match_name_mut::<SysMapFeedbackState>("SysMap")
|
|
||||||
.unwrap();
|
|
||||||
Ok(feedbackstate.update(&observer.last_run, &observer.last_input))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Named for SysMapFeedback
|
|
||||||
{
|
|
||||||
#[inline]
|
|
||||||
fn name(&self) -> &str {
|
|
||||||
&self.name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//============================= Feedback
|
//============================= Feedback
|
||||||
|
|
||||||
/// Shared Metadata for a SysStateFeedback
|
/// Shared Metadata for a SysStateFeedback
|
||||||
@ -197,7 +33,7 @@ impl Named for SysMapFeedback
|
|||||||
pub struct SysStateFeedbackState
|
pub struct SysStateFeedbackState
|
||||||
{
|
{
|
||||||
known_traces: HashMap<u64,(u64,u64,usize)>, // encounters,ticks,length
|
known_traces: HashMap<u64,(u64,u64,usize)>, // encounters,ticks,length
|
||||||
longest: Vec<MiniFreeRTOSSystemState>,
|
longest: Vec<RefinedFreeRTOSSystemState>,
|
||||||
}
|
}
|
||||||
impl Named for SysStateFeedbackState
|
impl Named for SysStateFeedbackState
|
||||||
{
|
{
|
||||||
@ -219,7 +55,7 @@ impl FeedbackState for SysStateFeedbackState
|
|||||||
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
|
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
|
||||||
pub struct NovelSysStateFeedback
|
pub struct NovelSysStateFeedback
|
||||||
{
|
{
|
||||||
last_trace: Option<Vec<MiniFreeRTOSSystemState>>,
|
last_trace: Option<Vec<RefinedFreeRTOSSystemState>>,
|
||||||
// known_traces: HashMap<u64,(u64,usize)>,
|
// known_traces: HashMap<u64,(u64,usize)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -304,7 +140,7 @@ impl Named for NovelSysStateFeedback
|
|||||||
|
|
||||||
//=============================
|
//=============================
|
||||||
|
|
||||||
pub fn match_traces(target: &Vec<MiniFreeRTOSSystemState>, last: &Vec<MiniFreeRTOSSystemState>) -> bool {
|
pub fn match_traces(target: &Vec<RefinedFreeRTOSSystemState>, last: &Vec<RefinedFreeRTOSSystemState>) -> 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() {
|
||||||
@ -312,7 +148,7 @@ pub fn match_traces(target: &Vec<MiniFreeRTOSSystemState>, last: &Vec<MiniFreeRT
|
|||||||
}
|
}
|
||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
pub fn match_traces_name(target: &Vec<String>, last: &Vec<MiniFreeRTOSSystemState>) -> bool {
|
pub fn match_traces_name(target: &Vec<String>, last: &Vec<RefinedFreeRTOSSystemState>) -> 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() {
|
||||||
@ -367,7 +203,7 @@ impl Named for HitSysStateFeedback
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl HitSysStateFeedback {
|
impl HitSysStateFeedback {
|
||||||
pub fn new(target: Option<Vec<MiniFreeRTOSSystemState>>) -> Self {
|
pub fn new(target: Option<Vec<RefinedFreeRTOSSystemState>>) -> Self {
|
||||||
Self {target: target.map(|x| x.into_iter().map(|y| y.current_task.task_name).collect())}
|
Self {target: target.map(|x| x.into_iter().map(|y| y.current_task.task_name).collect())}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
220
fuzzers/wcet_qemu_sys/src/sysstate/graph.rs
Normal file
220
fuzzers/wcet_qemu_sys/src/sysstate/graph.rs
Normal file
@ -0,0 +1,220 @@
|
|||||||
|
|
||||||
|
/// Feedbacks organizing SystemStates as a graph
|
||||||
|
use libafl::bolts::ownedref::OwnedSlice;
|
||||||
|
use libafl::inputs::BytesInput;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use libafl_qemu::QemuClockObserver;
|
||||||
|
use libafl::feedbacks::FeedbackState;
|
||||||
|
use libafl::corpus::Testcase;
|
||||||
|
use libafl::state::HasFeedbackStates;
|
||||||
|
use libafl::bolts::tuples::MatchName;
|
||||||
|
use std::collections::hash_map::DefaultHasher;
|
||||||
|
use std::hash::Hasher;
|
||||||
|
use std::hash::Hash;
|
||||||
|
use libafl::events::EventFirer;
|
||||||
|
use libafl::state::HasClientPerfMonitor;
|
||||||
|
use libafl::feedbacks::Feedback;
|
||||||
|
use libafl::bolts::tuples::Named;
|
||||||
|
use libafl::Error;
|
||||||
|
use hashbrown::HashMap;
|
||||||
|
use libafl::{executors::ExitKind, inputs::Input, observers::ObserversTuple, state::HasMetadata};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use super::RefinedFreeRTOSSystemState;
|
||||||
|
use super::FreeRTOSSystemStateMetadata;
|
||||||
|
use super::observers::QemuSysStateObserver;
|
||||||
|
use petgraph::prelude::DiGraph;
|
||||||
|
use petgraph::graph::NodeIndex;
|
||||||
|
use petgraph::Direction;
|
||||||
|
use std::cmp::Ordering;
|
||||||
|
|
||||||
|
//============================= Data Structures
|
||||||
|
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default)]
|
||||||
|
struct VariantTuple
|
||||||
|
{
|
||||||
|
start_tick: u64,
|
||||||
|
end_tick: u64,
|
||||||
|
input_counter: u32,
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
|
||||||
|
struct SysGraphNode
|
||||||
|
{
|
||||||
|
base: RefinedFreeRTOSSystemState,
|
||||||
|
variants: Vec<VariantTuple>,
|
||||||
|
}
|
||||||
|
impl SysGraphNode {
|
||||||
|
fn from(base: RefinedFreeRTOSSystemState, 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
|
||||||
|
fn unite(&mut self, other: &mut SysGraphNode) -> bool {
|
||||||
|
if self!=other {return false;}
|
||||||
|
self.variants.append(&mut other.variants);
|
||||||
|
self.variants.dedup();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/// add a Varint from a [`RefinedFreeRTOSSystemState`]
|
||||||
|
fn unite_raw(&mut self, other: &RefinedFreeRTOSSystemState, 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl PartialEq for SysGraphNode {
|
||||||
|
fn eq(&self, other: &SysGraphNode) -> bool {
|
||||||
|
self.base==other.base
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//============================= Graph Feedback
|
||||||
|
|
||||||
|
/// Improved System State Graph
|
||||||
|
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
|
||||||
|
pub struct SysGraphFeedbackState
|
||||||
|
{
|
||||||
|
graph: DiGraph<SysGraphNode, ()>,
|
||||||
|
entrypoint: NodeIndex,
|
||||||
|
name: String,
|
||||||
|
}
|
||||||
|
impl SysGraphFeedbackState
|
||||||
|
{
|
||||||
|
pub fn new() -> Self {
|
||||||
|
let mut graph = DiGraph::<SysGraphNode, ()>::new();
|
||||||
|
let ind = graph.add_node(SysGraphNode::default());
|
||||||
|
Self {graph: graph, entrypoint: ind, name: String::from("SysMap")}
|
||||||
|
}
|
||||||
|
fn insert(&mut self, list: Vec<RefinedFreeRTOSSystemState>, input: &Vec<u8>) {
|
||||||
|
let mut current_index = self.entrypoint;
|
||||||
|
for n in list {
|
||||||
|
let mut done = false;
|
||||||
|
for i in self.graph.neighbors_directed(current_index, Direction::Outgoing) {
|
||||||
|
if n == self.graph[i].base {
|
||||||
|
done = true;
|
||||||
|
current_index = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !done {
|
||||||
|
let j = self.graph.add_node(SysGraphNode::from(n,input.clone()));
|
||||||
|
self.graph.add_edge(current_index, j, ());
|
||||||
|
current_index = j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// 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 {
|
||||||
|
let mut current_index = self.entrypoint;
|
||||||
|
let mut novel = false;
|
||||||
|
for n in list {
|
||||||
|
let mut matching : Option<NodeIndex> = None;
|
||||||
|
for i in self.graph.neighbors_directed(current_index, Direction::Outgoing) {
|
||||||
|
let tmp = &self.graph[i];
|
||||||
|
if n == &tmp.base {
|
||||||
|
matching = Some(i);
|
||||||
|
current_index = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
match matching {
|
||||||
|
None => {
|
||||||
|
novel = true;
|
||||||
|
let j = self.graph.add_node(SysGraphNode::from(n.clone(),input.clone()));
|
||||||
|
self.graph.add_edge(current_index, j, ());
|
||||||
|
current_index = j;
|
||||||
|
},
|
||||||
|
Some(i) => {
|
||||||
|
novel |= self.graph[i].unite_interesting(&n, input);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return novel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Named for SysGraphFeedbackState
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
&self.name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl FeedbackState for SysGraphFeedbackState
|
||||||
|
{
|
||||||
|
fn reset(&mut self) -> Result<(), Error> {
|
||||||
|
self.graph.clear();
|
||||||
|
self.entrypoint = self.graph.add_node(SysGraphNode::default());
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A Feedback reporting novel System-State Transitions. Depends on [`QemuSysStateObserver`]
|
||||||
|
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
|
||||||
|
pub struct SysMapFeedback
|
||||||
|
{
|
||||||
|
name: String
|
||||||
|
}
|
||||||
|
impl SysMapFeedback {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {name: String::from("SysMapFeedback") }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I, S> Feedback<I, S> for SysMapFeedback
|
||||||
|
where
|
||||||
|
I: Input,
|
||||||
|
S: HasClientPerfMonitor + HasFeedbackStates,
|
||||||
|
{
|
||||||
|
fn is_interesting<EM, OT>(
|
||||||
|
&mut self,
|
||||||
|
state: &mut S,
|
||||||
|
_manager: &mut EM,
|
||||||
|
_input: &I,
|
||||||
|
observers: &OT,
|
||||||
|
_exit_kind: &ExitKind,
|
||||||
|
) -> Result<bool, Error>
|
||||||
|
where
|
||||||
|
EM: EventFirer<I>,
|
||||||
|
OT: ObserversTuple<I, S>,
|
||||||
|
{
|
||||||
|
let observer = observers.match_name::<QemuSysStateObserver>("sysstate")
|
||||||
|
.expect("QemuSysStateObserver not found");
|
||||||
|
let feedbackstate = state
|
||||||
|
.feedback_states_mut()
|
||||||
|
.match_name_mut::<SysGraphFeedbackState>("SysMap")
|
||||||
|
.unwrap();
|
||||||
|
Ok(feedbackstate.update(&observer.last_run, &observer.last_input))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Named for SysMapFeedback
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
&self.name
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
use crate::sysstate::FreeRTOSSystemStateRaw;
|
use crate::sysstate::RawFreeRTOSSystemState;
|
||||||
use crate::sysstate::CURRENT_SYSSTATE_VEC;
|
use crate::sysstate::CURRENT_SYSSTATE_VEC;
|
||||||
use crate::sysstate::NUM_PRIOS;
|
use crate::sysstate::NUM_PRIOS;
|
||||||
use super::freertos::TCB_t;
|
use super::freertos::TCB_t;
|
||||||
@ -91,7 +91,7 @@ where
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let listbytes : u32 = u32::try_from(std::mem::size_of::<freertos::List_t>()).unwrap();
|
let listbytes : u32 = u32::try_from(std::mem::size_of::<freertos::List_t>()).unwrap();
|
||||||
let mut sysstate = FreeRTOSSystemStateRaw::default();
|
let mut sysstate = RawFreeRTOSSystemState::default();
|
||||||
sysstate.qemu_tick = emulator.get_ticks();
|
sysstate.qemu_tick = emulator.get_ticks();
|
||||||
let mut buf : [u8; 4] = [0,0,0,0];
|
let mut buf : [u8; 4] = [0,0,0,0];
|
||||||
unsafe { emulator.read_mem(h.input_counter.into(), &mut buf) };
|
unsafe { emulator.read_mem(h.input_counter.into(), &mut buf) };
|
||||||
|
@ -13,6 +13,7 @@ pub mod freertos;
|
|||||||
pub mod helpers;
|
pub mod helpers;
|
||||||
pub mod observers;
|
pub mod observers;
|
||||||
pub mod feedbacks;
|
pub mod feedbacks;
|
||||||
|
pub mod graph;
|
||||||
|
|
||||||
// Constants
|
// Constants
|
||||||
const NUM_PRIOS: usize = 5;
|
const NUM_PRIOS: usize = 5;
|
||||||
@ -20,7 +21,7 @@ const NUM_PRIOS: usize = 5;
|
|||||||
//============================= Struct definitions
|
//============================= Struct definitions
|
||||||
/// Raw info Dump from Qemu
|
/// Raw info Dump from Qemu
|
||||||
#[derive(Debug, Default, Serialize, Deserialize)]
|
#[derive(Debug, Default, Serialize, Deserialize)]
|
||||||
pub struct FreeRTOSSystemStateRaw {
|
pub struct RawFreeRTOSSystemState {
|
||||||
qemu_tick: u64,
|
qemu_tick: u64,
|
||||||
current_tcb: TCB_t,
|
current_tcb: TCB_t,
|
||||||
prio_ready_lists: [freertos::List_t; NUM_PRIOS],
|
prio_ready_lists: [freertos::List_t; NUM_PRIOS],
|
||||||
@ -28,11 +29,11 @@ pub struct FreeRTOSSystemStateRaw {
|
|||||||
input_counter: u32,
|
input_counter: u32,
|
||||||
}
|
}
|
||||||
/// List of system state dumps from QemuHelpers
|
/// List of system state dumps from QemuHelpers
|
||||||
static mut CURRENT_SYSSTATE_VEC: Vec<FreeRTOSSystemStateRaw> = vec![];
|
static mut CURRENT_SYSSTATE_VEC: Vec<RawFreeRTOSSystemState> = vec![];
|
||||||
|
|
||||||
/// A reduced version of freertos::TCB_t
|
/// A reduced version of freertos::TCB_t
|
||||||
#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
|
#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
|
||||||
pub struct MiniTCB {
|
pub struct RefinedTCB {
|
||||||
task_name: String,
|
task_name: String,
|
||||||
priority: u32,
|
priority: u32,
|
||||||
base_priority: u32,
|
base_priority: u32,
|
||||||
@ -41,7 +42,7 @@ pub struct MiniTCB {
|
|||||||
notify_state: u8,
|
notify_state: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Hash for MiniTCB {
|
impl Hash for RefinedTCB {
|
||||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||||
self.task_name.hash(state);
|
self.task_name.hash(state);
|
||||||
// self.priority.hash(state);
|
// self.priority.hash(state);
|
||||||
@ -51,7 +52,7 @@ impl Hash for MiniTCB {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MiniTCB {
|
impl RefinedTCB {
|
||||||
pub fn from_tcb(input: &TCB_t) -> Self {
|
pub fn from_tcb(input: &TCB_t) -> Self {
|
||||||
unsafe {
|
unsafe {
|
||||||
let tmp = std::mem::transmute::<[i8; 10],[u8; 10]>(input.pcTaskName);
|
let tmp = std::mem::transmute::<[i8; 10],[u8; 10]>(input.pcTaskName);
|
||||||
@ -84,40 +85,40 @@ impl MiniTCB {
|
|||||||
|
|
||||||
/// Refined information about the states an execution transitioned between
|
/// Refined information about the states an execution transitioned between
|
||||||
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
|
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
|
||||||
pub struct MiniFreeRTOSSystemState {
|
pub struct RefinedFreeRTOSSystemState {
|
||||||
start_tick: u64,
|
start_tick: u64,
|
||||||
end_tick: u64,
|
end_tick: u64,
|
||||||
input_counter: u32,
|
input_counter: u32,
|
||||||
current_task: MiniTCB,
|
current_task: RefinedTCB,
|
||||||
ready_list_after: Vec<MiniTCB>,
|
ready_list_after: Vec<RefinedTCB>,
|
||||||
}
|
}
|
||||||
impl PartialEq for MiniFreeRTOSSystemState {
|
impl PartialEq for RefinedFreeRTOSSystemState {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
self.current_task == other.current_task && self.ready_list_after == other.ready_list_after
|
self.current_task == other.current_task && self.ready_list_after == other.ready_list_after
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Hash for MiniFreeRTOSSystemState {
|
impl Hash for RefinedFreeRTOSSystemState {
|
||||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||||
self.current_task.hash(state);
|
self.current_task.hash(state);
|
||||||
// self.ready_list_after.hash(state);
|
self.ready_list_after.hash(state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl MiniFreeRTOSSystemState {
|
impl RefinedFreeRTOSSystemState {
|
||||||
fn get_time(&self) -> u64 {
|
fn get_time(&self) -> u64 {
|
||||||
self.end_tick-self.start_tick
|
self.end_tick-self.start_tick
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wrapper around Vec<MiniFreeRTOSSystemState> to attach as Metadata
|
// Wrapper around Vec<RefinedFreeRTOSSystemState> to attach as Metadata
|
||||||
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
|
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
|
||||||
pub struct FreeRTOSSystemStateMetadata {
|
pub struct FreeRTOSSystemStateMetadata {
|
||||||
inner: Vec<MiniFreeRTOSSystemState>,
|
inner: Vec<RefinedFreeRTOSSystemState>,
|
||||||
indices: Vec<usize>, // Hashed enumeration of States
|
indices: Vec<usize>, // Hashed enumeration of States
|
||||||
tcref: isize,
|
tcref: isize,
|
||||||
}
|
}
|
||||||
impl FreeRTOSSystemStateMetadata {
|
impl FreeRTOSSystemStateMetadata {
|
||||||
pub fn new(inner: Vec<MiniFreeRTOSSystemState>) -> Self{
|
pub fn new(inner: Vec<RefinedFreeRTOSSystemState>) -> Self{
|
||||||
let tmp = inner.iter().enumerate().map(|x| compute_hash(x) as usize).collect();
|
let tmp = inner.iter().enumerate().map(|x| compute_hash(x) as usize).collect();
|
||||||
Self {inner: inner, indices: tmp, tcref: 0}
|
Self {inner: inner, indices: tmp, tcref: 0}
|
||||||
}
|
}
|
||||||
|
@ -8,9 +8,9 @@ use serde::{Deserialize, Serialize};
|
|||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
CURRENT_SYSSTATE_VEC,
|
CURRENT_SYSSTATE_VEC,
|
||||||
FreeRTOSSystemStateRaw,
|
RawFreeRTOSSystemState,
|
||||||
MiniTCB,
|
RefinedTCB,
|
||||||
MiniFreeRTOSSystemState,
|
RefinedFreeRTOSSystemState,
|
||||||
freertos::{List_t, TCB_t, rtos_struct, rtos_struct::*},
|
freertos::{List_t, TCB_t, rtos_struct, rtos_struct::*},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -22,7 +22,7 @@ use super::{
|
|||||||
#[allow(clippy::unsafe_derive_deserialize)]
|
#[allow(clippy::unsafe_derive_deserialize)]
|
||||||
pub struct QemuSysStateObserver
|
pub struct QemuSysStateObserver
|
||||||
{
|
{
|
||||||
pub last_run: Vec<MiniFreeRTOSSystemState>,
|
pub last_run: Vec<RefinedFreeRTOSSystemState>,
|
||||||
pub last_input: Vec<u8>,
|
pub last_input: Vec<u8>,
|
||||||
name: String,
|
name: String,
|
||||||
}
|
}
|
||||||
@ -115,17 +115,17 @@ fn tcb_list_to_vec_cached(list: List_t, dump: &mut HashMap<u32,rtos_struct>) ->
|
|||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
/// Drains a List of raw SystemStates to produce a refined trace
|
/// Drains a List of raw SystemStates to produce a refined trace
|
||||||
fn refine_system_states(input: &mut Vec<FreeRTOSSystemStateRaw>) -> Vec<MiniFreeRTOSSystemState> {
|
fn refine_system_states(input: &mut Vec<RawFreeRTOSSystemState>) -> Vec<RefinedFreeRTOSSystemState> {
|
||||||
let mut ret = Vec::<MiniFreeRTOSSystemState>::new();
|
let mut ret = Vec::<RefinedFreeRTOSSystemState>::new();
|
||||||
let mut start_tick : u64 = 0;
|
let mut start_tick : u64 = 0;
|
||||||
for mut i in input.drain(..) {
|
for mut i in input.drain(..) {
|
||||||
let mut collector = Vec::<MiniTCB>::new();
|
let mut collector = Vec::<RefinedTCB>::new();
|
||||||
for j in i.prio_ready_lists.into_iter().rev() {
|
for j in i.prio_ready_lists.into_iter().rev() {
|
||||||
let mut tmp = tcb_list_to_vec_cached(j,&mut i.dumping_ground).iter().map(|x| MiniTCB::from_tcb(x)).collect();
|
let mut tmp = tcb_list_to_vec_cached(j,&mut i.dumping_ground).iter().map(|x| RefinedTCB::from_tcb(x)).collect();
|
||||||
collector.append(&mut tmp);
|
collector.append(&mut tmp);
|
||||||
}
|
}
|
||||||
ret.push(MiniFreeRTOSSystemState {
|
ret.push(RefinedFreeRTOSSystemState {
|
||||||
current_task: MiniTCB::from_tcb_owned(i.current_tcb),
|
current_task: RefinedTCB::from_tcb_owned(i.current_tcb),
|
||||||
start_tick: start_tick,
|
start_tick: start_tick,
|
||||||
end_tick: i.qemu_tick,
|
end_tick: i.qemu_tick,
|
||||||
ready_list_after: collector,
|
ready_list_after: collector,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user