WIP: complet rework of STG
This commit is contained in:
parent
ba3850cf4d
commit
8f652f754c
@ -32,13 +32,13 @@ const NUM_PRIOS: usize = 5;
|
||||
|
||||
//============================= Struct definitions
|
||||
|
||||
#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
|
||||
#[derive(Debug, Default, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub enum CaptureEvent {
|
||||
APIStart,
|
||||
APIEnd,
|
||||
ISRStart,
|
||||
ISREnd,
|
||||
End,
|
||||
APIStart, /// src,dst
|
||||
APIEnd, /// src,dst
|
||||
ISRStart, /// _,dst
|
||||
ISREnd, /// src,_
|
||||
End, /// src,_
|
||||
#[default]
|
||||
Undefined,
|
||||
}
|
||||
@ -67,16 +67,18 @@ pub struct RefinedTCB {
|
||||
pub priority: u32,
|
||||
pub base_priority: u32,
|
||||
mutexes_held: u32,
|
||||
notify_value: u32,
|
||||
// notify_value: u32,
|
||||
notify_state: u8,
|
||||
}
|
||||
|
||||
impl PartialEq for RefinedTCB {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.task_name == other.task_name &&
|
||||
let ret = self.task_name == other.task_name &&
|
||||
self.priority == other.priority &&
|
||||
self.base_priority == other.base_priority
|
||||
// && self.notify_state == other.notify_state
|
||||
self.base_priority == other.base_priority;
|
||||
#[cfg(feature = "do_hash_notify_state")]
|
||||
let ret = ret && self.notify_state == other.notify_state;
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
@ -85,7 +87,7 @@ impl Hash for RefinedTCB {
|
||||
self.task_name.hash(state);
|
||||
self.priority.hash(state);
|
||||
self.mutexes_held.hash(state);
|
||||
#[cfg(not(feature = "no_hash_state"))]
|
||||
#[cfg(feature = "do_hash_notify_state")]
|
||||
self.notify_state.hash(state);
|
||||
// self.notify_value.hash(state);
|
||||
}
|
||||
@ -101,7 +103,7 @@ impl RefinedTCB {
|
||||
priority: input.uxPriority,
|
||||
base_priority: input.uxBasePriority,
|
||||
mutexes_held: input.uxMutexesHeld,
|
||||
notify_value: input.ulNotifiedValue[0],
|
||||
// notify_value: input.ulNotifiedValue[0],
|
||||
notify_state: input.ucNotifyState[0],
|
||||
}
|
||||
}
|
||||
@ -115,27 +117,25 @@ impl RefinedTCB {
|
||||
priority: input.uxPriority,
|
||||
base_priority: input.uxBasePriority,
|
||||
mutexes_held: input.uxMutexesHeld,
|
||||
notify_value: input.ulNotifiedValue[0],
|
||||
// notify_value: input.ulNotifiedValue[0],
|
||||
notify_state: input.ucNotifyState[0],
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Refined information about the states an execution transitioned between
|
||||
/// Reduced information about a systems state, without any execution context
|
||||
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
|
||||
pub struct RefinedFreeRTOSSystemState {
|
||||
pub start_tick: u64,
|
||||
pub end_tick: u64,
|
||||
edge: (Option<GuestAddr>,Option<GuestAddr>),
|
||||
input_counter: u32,
|
||||
pub current_task: (RefinedTCB, u32),
|
||||
ready_list_after: Vec<(RefinedTCB, u32)>,
|
||||
delay_list_after: Vec<(RefinedTCB, u32)>,
|
||||
// pub capture_point: String
|
||||
pub capture_point: (CaptureEvent,String)
|
||||
pub struct ReducedFreeRTOSSystemState {
|
||||
// pub tick: u64,
|
||||
pub current_task: RefinedTCB,
|
||||
ready_list_after: Vec<RefinedTCB>,
|
||||
delay_list_after: Vec<RefinedTCB>,
|
||||
// edge: (Option<GuestAddr>,Option<GuestAddr>),
|
||||
// pub capture_point: (CaptureEvent,String),
|
||||
// input_counter: u32
|
||||
}
|
||||
impl PartialEq for RefinedFreeRTOSSystemState {
|
||||
impl PartialEq for ReducedFreeRTOSSystemState {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.current_task == other.current_task && self.ready_list_after == other.ready_list_after &&
|
||||
self.delay_list_after == other.delay_list_after
|
||||
@ -144,42 +144,93 @@ impl PartialEq for RefinedFreeRTOSSystemState {
|
||||
}
|
||||
}
|
||||
|
||||
impl Hash for RefinedFreeRTOSSystemState {
|
||||
impl Hash for ReducedFreeRTOSSystemState {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.current_task.hash(state);
|
||||
self.ready_list_after.hash(state);
|
||||
self.delay_list_after.hash(state);
|
||||
// self.last_pc.hash(state);
|
||||
}
|
||||
}
|
||||
impl RefinedFreeRTOSSystemState {
|
||||
fn get_time(&self) -> u64 {
|
||||
self.end_tick-self.start_tick
|
||||
}
|
||||
impl ReducedFreeRTOSSystemState {
|
||||
// fn get_tick(&self) -> u64 {
|
||||
// self.tick
|
||||
// }
|
||||
|
||||
pub fn print_lists(&self) -> String {
|
||||
let mut ret = String::from("+");
|
||||
for j in self.ready_list_after.iter() {
|
||||
ret.push_str(format!(" {}#{}", j.0.task_name, j.1).as_str());
|
||||
ret.push_str(format!(" {}", j.task_name).as_str());
|
||||
}
|
||||
ret.push_str("\n-");
|
||||
for j in self.delay_list_after.iter() {
|
||||
ret.push_str(format!(" {}#{}", j.0.task_name, j.1).as_str());
|
||||
ret.push_str(format!(" {}", j.task_name).as_str());
|
||||
}
|
||||
ret
|
||||
}
|
||||
pub fn get_hash(&self) -> u64 {
|
||||
let mut h = DefaultHasher::new();
|
||||
self.hash(&mut h);
|
||||
h.finish()
|
||||
}
|
||||
}
|
||||
|
||||
// #[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq, Eq, Hash)]
|
||||
// pub enum ExecLevel {
|
||||
// APP = 0,
|
||||
// API = 1,
|
||||
// ISR = 2,
|
||||
// }
|
||||
|
||||
#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq, Eq, Hash)]
|
||||
struct ExecInterval {
|
||||
start_tick: u64,
|
||||
end_tick: u64,
|
||||
start_state: u64,
|
||||
end_state: u64,
|
||||
start_capture: (CaptureEvent, String),
|
||||
end_capture: (CaptureEvent, String),
|
||||
level: u8,
|
||||
tick_spend_preempted: u64,
|
||||
abb: Option<AtomicBasicBlock>
|
||||
}
|
||||
|
||||
impl ExecInterval {
|
||||
pub fn get_exec_time(&self) -> u64 {
|
||||
self.end_tick-self.start_tick-self.tick_spend_preempted
|
||||
}
|
||||
pub fn is_valid(&self) -> bool {
|
||||
self.start_tick != 0 || self.end_tick != 0
|
||||
}
|
||||
pub fn invaildate(&mut self) {
|
||||
self.start_tick = 0;
|
||||
self.end_tick = 0;
|
||||
}
|
||||
|
||||
/// Attach this interval to the later one, keep a record of the time spend preempted
|
||||
pub fn try_unite_with_later_interval(&mut self, later_interval : &mut Self) -> bool {
|
||||
if self.end_state!=later_interval.start_state || self.abb!=later_interval.abb || !self.is_valid() || !later_interval.is_valid() {
|
||||
return false;
|
||||
}
|
||||
// assert_eq!(self.end_state, later_interval.start_state);
|
||||
// assert_eq!(self.abb, later_interval.abb);
|
||||
later_interval.tick_spend_preempted += self.tick_spend_preempted + (later_interval.start_tick-self.end_tick);
|
||||
later_interval.start_tick = self.start_tick;
|
||||
later_interval.start_state = self.start_state;
|
||||
self.invaildate();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Wrapper around Vec<RefinedFreeRTOSSystemState> to attach as Metadata
|
||||
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
|
||||
pub struct FreeRTOSSystemStateMetadata {
|
||||
pub inner: Vec<RefinedFreeRTOSSystemState>,
|
||||
pub inner: Vec<ReducedFreeRTOSSystemState>,
|
||||
trace_length: usize,
|
||||
indices: Vec<usize>, // Hashed enumeration of States
|
||||
tcref: isize,
|
||||
}
|
||||
impl FreeRTOSSystemStateMetadata {
|
||||
pub fn new(inner: Vec<RefinedFreeRTOSSystemState>) -> Self{
|
||||
pub fn new(inner: Vec<ReducedFreeRTOSSystemState>) -> Self{
|
||||
let tmp = inner.iter().enumerate().map(|x| compute_hash(x) as usize).collect();
|
||||
Self {trace_length: inner.len(), inner: inner, indices: tmp, tcref: 0}
|
||||
}
|
||||
@ -218,6 +269,7 @@ libafl_bolts::impl_serdeany!(FreeRTOSSystemStateMetadata);
|
||||
pub struct AtomicBasicBlock {
|
||||
start: GuestAddr,
|
||||
ends: HashSet<GuestAddr>,
|
||||
level: u8,
|
||||
}
|
||||
|
||||
impl Hash for AtomicBasicBlock {
|
||||
@ -226,6 +278,7 @@ impl Hash for AtomicBasicBlock {
|
||||
self.start.hash(state);
|
||||
let mut keys : Vec<_> = self.ends.iter().collect();
|
||||
keys.sort();
|
||||
self.level.hash(state);
|
||||
keys.hash(state);
|
||||
}
|
||||
}
|
||||
@ -236,7 +289,7 @@ impl fmt::Display for AtomicBasicBlock {
|
||||
for end in &self.ends {
|
||||
ends_str.push_str(&format!("0x{:#x}, ", end));
|
||||
}
|
||||
write!(f, "ABB {{ start: 0x{:#x}, ends: [{}]}}", self.start, ends_str.trim().trim_matches(','))
|
||||
write!(f, "ABB {{ level: {}, start: 0x{:#x}, ends: [{}]}}", self.level, self.start, ends_str.trim().trim_matches(','))
|
||||
}
|
||||
}
|
||||
impl fmt::Debug for AtomicBasicBlock {
|
||||
@ -245,7 +298,7 @@ impl fmt::Debug for AtomicBasicBlock {
|
||||
for end in &self.ends {
|
||||
ends_str.push_str(&format!("{:#x}, ", end));
|
||||
}
|
||||
write!(f, "ABB {{ start: {:#x}, ends: [{}]}}", self.start, ends_str.trim().trim_matches(','))
|
||||
write!(f, "ABB {{ level: {}, start: {:#x}, ends: [{}]}}", self.level, self.start, ends_str.trim().trim_matches(','))
|
||||
}
|
||||
}
|
||||
|
||||
@ -258,6 +311,9 @@ impl PartialOrd for AtomicBasicBlock {
|
||||
impl Ord for AtomicBasicBlock {
|
||||
fn cmp(&self, other: &AtomicBasicBlock) -> std::cmp::Ordering {
|
||||
if self.start.cmp(&other.start) == std::cmp::Ordering::Equal {
|
||||
if self.level.cmp(&other.level) != std::cmp::Ordering::Equal {
|
||||
return self.level.cmp(&other.level);
|
||||
}
|
||||
// If the start addresses are equal, compare by 'ends'
|
||||
let end1 = if self.ends.len() == 1 { *self.ends.iter().next().unwrap() as u64 } else {
|
||||
let mut temp = self.ends.iter().collect::<Vec<_>>().into_iter().collect::<Vec<&GuestAddr>>();
|
||||
@ -282,202 +338,202 @@ impl Ord for AtomicBasicBlock {
|
||||
}
|
||||
|
||||
|
||||
fn get_task_names(trace: &Vec<RefinedFreeRTOSSystemState>) -> HashSet<String> {
|
||||
fn get_task_names(trace: &Vec<ReducedFreeRTOSSystemState>) -> HashSet<String> {
|
||||
let mut ret: HashSet<_, _> = HashSet::new();
|
||||
for state in trace {
|
||||
ret.insert(state.current_task.0.task_name.to_string());
|
||||
ret.insert(state.current_task.task_name.to_string());
|
||||
}
|
||||
ret
|
||||
}
|
||||
|
||||
fn extract_abbs_from_trace(trace: &Vec<RefinedFreeRTOSSystemState>) -> 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<RefinedFreeRTOSSystemState>) -> (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 {
|
||||
// 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();
|
||||
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)
|
||||
}
|
||||
// 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);
|
@ -7,14 +7,18 @@ use libafl_bolts::AsSlice;
|
||||
use libafl::Error;
|
||||
use libafl::observers::Observer;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use hashbrown::HashMap;
|
||||
use hashbrown::{HashMap, HashSet};
|
||||
use crate::systemstate::CaptureEvent;
|
||||
use std::rc::Rc;
|
||||
use std::cell::RefCell;
|
||||
use std::collections::VecDeque;
|
||||
|
||||
use super::{ AtomicBasicBlock, ExecInterval};
|
||||
use super::{
|
||||
CURRENT_SYSTEMSTATE_VEC,
|
||||
RawFreeRTOSSystemState,
|
||||
RefinedTCB,
|
||||
RefinedFreeRTOSSystemState,
|
||||
ReducedFreeRTOSSystemState,
|
||||
freertos::{List_t, TCB_t, rtos_struct, rtos_struct::*},
|
||||
};
|
||||
|
||||
@ -26,7 +30,9 @@ use super::{
|
||||
#[allow(clippy::unsafe_derive_deserialize)]
|
||||
pub struct QemuSystemStateObserver
|
||||
{
|
||||
pub last_run: Vec<RefinedFreeRTOSSystemState>,
|
||||
pub last_run: Vec<ReducedFreeRTOSSystemState>,
|
||||
pub last_states: HashMap<u64, ReducedFreeRTOSSystemState>,
|
||||
pub last_trace: Vec<ExecInterval>,
|
||||
pub last_input: Vec<u8>,
|
||||
name: String,
|
||||
}
|
||||
@ -44,7 +50,20 @@ where
|
||||
|
||||
#[inline]
|
||||
fn post_exec(&mut self, _state: &mut S, _input: &S::Input, _exit_kind: &ExitKind) -> Result<(), Error> {
|
||||
unsafe {self.last_run = remove_ineffective_isr(refine_system_states(&mut CURRENT_SYSTEMSTATE_VEC));}
|
||||
// unsafe {self.last_run = invalidate_ineffective_isr(refine_system_states(&mut CURRENT_SYSTEMSTATE_VEC));}
|
||||
unsafe {
|
||||
let mut temp = refine_system_states(&mut CURRENT_SYSTEMSTATE_VEC);
|
||||
self.last_run = temp.0.clone();
|
||||
// println!("{:?}",temp);
|
||||
let mut temp = states2intervals(temp.0, temp.1);
|
||||
self.last_trace = temp.0;
|
||||
self.last_states = temp.1;
|
||||
// println!("{:?}",temp);
|
||||
}
|
||||
// let abbs = extract_abbs_from_trace(&self.last_run);
|
||||
// println!("{:?}",abbs);
|
||||
// let abbs = trace_to_state_abb(&self.last_run);
|
||||
// println!("{:?}",abbs);
|
||||
self.last_input=_input.target_bytes().as_slice().to_owned();
|
||||
Ok(())
|
||||
}
|
||||
@ -68,7 +87,7 @@ impl HasLen for QemuSystemStateObserver
|
||||
|
||||
impl QemuSystemStateObserver {
|
||||
pub fn new() -> Self {
|
||||
Self{last_run: vec![], last_input: vec![], name: "systemstate".to_string()}
|
||||
Self{last_run: vec![], last_trace: vec![], last_input: vec![], name: "systemstate".to_string(), last_states: HashMap::new() }
|
||||
}
|
||||
|
||||
}
|
||||
@ -112,10 +131,8 @@ fn tcb_list_to_vec_cached(list: List_t, dump: &mut HashMap<u32,rtos_struct>) ->
|
||||
ret
|
||||
}
|
||||
/// Drains a List of raw SystemStates to produce a refined trace
|
||||
fn refine_system_states(input: &mut Vec<RawFreeRTOSSystemState>) -> Vec<RefinedFreeRTOSSystemState> {
|
||||
let mut iteration_counts : HashMap<String, u32>= HashMap::new();
|
||||
let mut ret = Vec::<RefinedFreeRTOSSystemState>::new();
|
||||
let mut start_tick : u64 = 0;
|
||||
fn refine_system_states(input: &mut Vec<RawFreeRTOSSystemState>) -> (Vec<ReducedFreeRTOSSystemState>, Vec<(u64, CaptureEvent, String, (Option<u32>, Option<u32>))>) {
|
||||
let mut ret = (Vec::<_>::new(), Vec::<_>::new());
|
||||
for mut i in input.drain(..) {
|
||||
let cur = RefinedTCB::from_tcb_owned(i.current_tcb);
|
||||
// collect ready list
|
||||
@ -130,66 +147,339 @@ fn refine_system_states(input: &mut Vec<RawFreeRTOSSystemState>) -> Vec<RefinedF
|
||||
delay_list.append(&mut delay_list_overflow);
|
||||
delay_list.sort_by(|a,b| a.task_name.cmp(&b.task_name));
|
||||
|
||||
// keep counts for all tasks
|
||||
let _ = iteration_counts.try_insert(cur.task_name.clone(), 1);
|
||||
for j in collector.iter() {let _ = iteration_counts.try_insert(j.task_name.clone(), 1);}
|
||||
for j in delay_list.iter() {let _ = iteration_counts.try_insert(j.task_name.clone(), 0);}
|
||||
|
||||
// Ensure that async events appear in the delay list, so we the counts in all states
|
||||
if let Some(lst) = ret.last() {
|
||||
for a in lst.delay_list_after.iter().filter(|x| x.0.task_name.contains("async")) {
|
||||
if delay_list.iter().find(|x| (*x).task_name==a.0.task_name).is_none() && cur.task_name != a.0.task_name {
|
||||
delay_list.push(a.0.clone());
|
||||
delay_list.sort_by(|a,b| a.task_name.cmp(&b.task_name));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// increase when:
|
||||
// current and delayed afterwards
|
||||
if let Some(_) = delay_list.iter().find(|x| (*x).task_name==cur.task_name) {
|
||||
*iteration_counts.get_mut(&cur.task_name).unwrap()+=1;
|
||||
}
|
||||
|
||||
let collector = collector.into_iter().map(|x| {let t = *iteration_counts.get(&x.task_name).unwrap_or(&1); (x, t)}).collect();
|
||||
// let filter_delay = delay_list.into_iter().filter(|x| !x.task_name.contains("async"));
|
||||
let delay_list : Vec<(RefinedTCB, u32)> = delay_list.into_iter().map(|x| {let t = *iteration_counts.get(&x.task_name).unwrap_or(&0); (x, t)}).collect();
|
||||
let t = *iteration_counts.get(&cur.task_name).unwrap_or(&1);
|
||||
// We don't care about the order
|
||||
ret.push(RefinedFreeRTOSSystemState {
|
||||
current_task: (cur, t),
|
||||
start_tick: start_tick,
|
||||
end_tick: i.qemu_tick,
|
||||
ret.0.push(ReducedFreeRTOSSystemState {
|
||||
current_task: cur,
|
||||
ready_list_after: collector,
|
||||
delay_list_after: delay_list,
|
||||
input_counter: i.input_counter,//+IRQ_INPUT_BYTES_NUMBER,
|
||||
edge: i.edge,
|
||||
capture_point: (i.capture_point.0,i.capture_point.1.to_string()),
|
||||
// input_counter: i.input_counter,//+IRQ_INPUT_BYTES_NUMBER,
|
||||
});
|
||||
start_tick=i.qemu_tick;
|
||||
ret.1.push((i.qemu_tick, i.capture_point.0, i.capture_point.1.to_string(), i.edge));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
fn remove_ineffective_isr(mut trace: Vec<RefinedFreeRTOSSystemState>) -> Vec<RefinedFreeRTOSSystemState> {
|
||||
// remove subsequent pairs of equal states where an ISREnd follows an ISRStart. If the interrupt had no effect on the system we, are not interested.
|
||||
let mut ret : Vec<RefinedFreeRTOSSystemState> = Vec::new();
|
||||
ret.push(trace[0].clone());
|
||||
let mut i = 1;
|
||||
while i < trace.len() - 1 {
|
||||
if trace[i] == trace[i + 1] &&
|
||||
matches!(trace[i].capture_point.0, CaptureEvent::ISRStart) &&
|
||||
matches!(trace[i + 1].capture_point.0, CaptureEvent::ISREnd) &&
|
||||
trace[i].capture_point.1 == trace[i + 1].capture_point.1
|
||||
{
|
||||
// extend the end of the last ABB until the end of the next one
|
||||
ret.last_mut().unwrap().end_tick = trace[i+1].end_tick;
|
||||
/// Transform the states and metadata into a list of ExecIntervals
|
||||
fn states2intervals(trace: Vec<ReducedFreeRTOSSystemState>, meta: Vec<(u64, CaptureEvent, String, (Option<u32>, Option<u32>))>) -> (Vec<ExecInterval>, HashMap<u64, ReducedFreeRTOSSystemState>) {
|
||||
let mut isr_stack : VecDeque<u8> = VecDeque::from([]); // 2+ = ISR, 1 = systemcall, 0 = APP. Trace starts with an ISREnd and executes the app
|
||||
|
||||
i+=2;
|
||||
|
||||
let mut level_of_task : HashMap<&str, u8> = HashMap::new();
|
||||
|
||||
let mut ret: Vec<ExecInterval> = vec![];
|
||||
let mut edges: Vec<(Option<u32>, Option<u32>)> = vec![];
|
||||
let mut last_hash : u64 = trace[0].get_hash();
|
||||
let mut table : HashMap<u64, ReducedFreeRTOSSystemState> = HashMap::new();
|
||||
table.insert(last_hash, trace[0].clone());
|
||||
for i in 0..trace.len()-1 {
|
||||
let curr_name = trace[i].current_task.task_name.as_str();
|
||||
let level = match meta[i].1 {
|
||||
CaptureEvent::APIEnd => { // API end always exits towards the app
|
||||
*level_of_task.get_mut(curr_name).unwrap()=0;
|
||||
&0
|
||||
},
|
||||
CaptureEvent::APIStart => { // API start can only be called in the app
|
||||
*level_of_task.get_mut(curr_name).unwrap()=1;
|
||||
&1
|
||||
},
|
||||
CaptureEvent::ISREnd => {
|
||||
// special case where the next block is an app start
|
||||
if !level_of_task.contains_key(curr_name) {
|
||||
level_of_task.insert(curr_name, 0);
|
||||
}
|
||||
// nested isr, TODO: Test level > 2
|
||||
if isr_stack.len() > 1 {
|
||||
isr_stack.pop_back();
|
||||
isr_stack.back().unwrap()
|
||||
} else {
|
||||
ret.push(trace[i].clone());
|
||||
i+=1;
|
||||
isr_stack.pop_back();
|
||||
// possibly go back to an api call that is still running for this task
|
||||
level_of_task.get(curr_name).unwrap()
|
||||
}
|
||||
},
|
||||
CaptureEvent::ISRStart => {
|
||||
if isr_stack.len() > 0 {
|
||||
let l = isr_stack.back().unwrap();
|
||||
isr_stack.push_back(l+1);
|
||||
isr_stack.back().unwrap()
|
||||
} else {
|
||||
isr_stack.push_back(2);
|
||||
&2
|
||||
}
|
||||
}
|
||||
ret
|
||||
_ => &100
|
||||
};
|
||||
// if trace[i].2 == CaptureEvent::End {break;}
|
||||
let next_hash=trace[i+1].get_hash();
|
||||
if !table.contains_key(&next_hash) {
|
||||
table.insert(next_hash, trace[i+1].clone());
|
||||
}
|
||||
ret.push(ExecInterval{
|
||||
start_tick: meta[i].0,
|
||||
end_tick: meta[i+1].0,
|
||||
start_state: last_hash,
|
||||
end_state: next_hash,
|
||||
start_capture: (meta[i].1, meta[i].2.clone()),
|
||||
end_capture: (meta[i+1].1, meta[i+1].2.clone()),
|
||||
level: *level,
|
||||
tick_spend_preempted: 0,
|
||||
abb: None
|
||||
});
|
||||
last_hash = next_hash;
|
||||
edges.push((meta[i].3.1, meta[i+1].3.0));
|
||||
}
|
||||
add_abb_info(&mut ret, &table, &edges);
|
||||
(ret, table)
|
||||
}
|
||||
|
||||
fn add_abb_info(trace: &mut Vec<ExecInterval>, table: &HashMap<u64, ReducedFreeRTOSSystemState>, edges: &Vec<(Option<u32>, Option<u32>)>) {
|
||||
let mut task_has_started : HashSet<String> = HashSet::new();
|
||||
let mut wip_abb_trace : Vec<Rc<RefCell<AtomicBasicBlock>>> = vec![];
|
||||
let mut open_abb_at_this_task_or_level : HashMap<(u8,&str),usize> = HashMap::new();
|
||||
|
||||
for i in 0..trace.len() {
|
||||
let curr_name = &table[&trace[i].start_state].current_task.task_name;
|
||||
// let last : Option<&usize> = last_abb_start_of_task.get(&curr_name);
|
||||
|
||||
let open_abb = open_abb_at_this_task_or_level.get(&(trace[i].level, if trace[i].level<2 {&curr_name} else {""})); // apps/apis are differentiated by task name, isrs by nested level
|
||||
|
||||
match (&trace[i].start_capture.0, &trace[i].end_capture.0) {
|
||||
// case with abb to block correspondence
|
||||
// APP ABB
|
||||
(CaptureEvent::APIEnd , CaptureEvent::APIStart ) => {assert_eq!(trace[i].level,0); assert_eq!(open_abb, None); wip_abb_trace.push(Rc::new(RefCell::new(AtomicBasicBlock{start: edges[i].0.unwrap(), ends: HashSet::from([edges[i].1.unwrap()]), level: if trace[i].level<2 {trace[i].level} else {2}})))},
|
||||
(CaptureEvent::APIEnd , CaptureEvent::End ) => {assert_eq!(trace[i].level,0); assert_eq!(open_abb, None); wip_abb_trace.push(Rc::new(RefCell::new(AtomicBasicBlock{start: edges[i].0.unwrap(), ends: HashSet::from([edges[i].1.unwrap()]), level: if trace[i].level<2 {trace[i].level} else {2}})))},
|
||||
// API ABB
|
||||
(CaptureEvent::APIStart, CaptureEvent::APIEnd ) => {assert_eq!(trace[i].level,1); assert_eq!(open_abb, None); wip_abb_trace.push(Rc::new(RefCell::new(AtomicBasicBlock{start: edges[i].0.unwrap(), ends: HashSet::from([edges[i].1.unwrap()]), level: if trace[i].level<2 {trace[i].level} else {2}})))},
|
||||
(CaptureEvent::APIStart , CaptureEvent::End ) => {assert_eq!(trace[i].level,1); assert_eq!(open_abb, None); wip_abb_trace.push(Rc::new(RefCell::new(AtomicBasicBlock{start: edges[i].0.unwrap(), ends: HashSet::from([edges[i].1.unwrap()]), level: if trace[i].level<2 {trace[i].level} else {2}})))},
|
||||
// ISR ABB
|
||||
(CaptureEvent::ISRStart, CaptureEvent::ISREnd ) => {assert_eq!(open_abb, None); wip_abb_trace.push(Rc::new(RefCell::new(AtomicBasicBlock{start: edges[i].0.unwrap(), ends: HashSet::from([edges[i].1.unwrap()]), level: if trace[i].level<2 {trace[i].level} else {2}})))},
|
||||
(CaptureEvent::ISRStart , CaptureEvent::End ) => {assert_eq!(open_abb, None); wip_abb_trace.push(Rc::new(RefCell::new(AtomicBasicBlock{start: edges[i].0.unwrap(), ends: HashSet::from([edges[i].1.unwrap()]), level: if trace[i].level<2 {trace[i].level} else {2}})))},
|
||||
//
|
||||
(_, _) => {
|
||||
match trace[i].start_capture.0 {
|
||||
// generic api abb start
|
||||
CaptureEvent::APIStart => {
|
||||
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);
|
||||
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 isr abb start
|
||||
CaptureEvent::ISRStart => {
|
||||
assert_eq!(open_abb, None);
|
||||
open_abb_at_this_task_or_level.insert((trace[i].level, if trace[i].level<2 {&curr_name} else {""}), i);
|
||||
wip_abb_trace.push(Rc::new(RefCell::new(AtomicBasicBlock{start: edges[i].0.unwrap(), ends: HashSet::new(), level: if trace[i].level<2 {trace[i].level} else {2}})));
|
||||
},
|
||||
// generic app abb start
|
||||
CaptureEvent::APIEnd => {
|
||||
assert_eq!(open_abb, None);
|
||||
open_abb_at_this_task_or_level.insert((trace[i].level, if trace[i].level<2 {&curr_name} else {""}), i);
|
||||
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
|
||||
CaptureEvent::ISREnd => {
|
||||
// special case app abb start
|
||||
if trace[i].start_capture.1=="xPortPendSVHandler" && !task_has_started.contains(curr_name) {
|
||||
assert_eq!(open_abb, None);
|
||||
wip_abb_trace.push(Rc::new(RefCell::new(AtomicBasicBlock{start: 0, ends: HashSet::new(), level: if trace[i].level<2 {trace[i].level} else {2}})));
|
||||
open_abb_at_this_task_or_level.insert((trace[i].level, if trace[i].level<2 {&curr_name} else {""}), i);
|
||||
task_has_started.insert(curr_name.clone());
|
||||
} else {
|
||||
// generic case, continue a preempted block
|
||||
let last = open_abb_at_this_task_or_level.get(&(trace[i].level, if trace[i].level<2 {&curr_name} else {""})).expect(&format!("Continued block with no start {} {} {}", trace[i].start_tick, task_has_started.contains(curr_name),trace[i].level));
|
||||
wip_abb_trace.push(wip_abb_trace[*last].clone());
|
||||
}
|
||||
},
|
||||
_ => panic!("Undefined block start")
|
||||
}
|
||||
match trace[i].end_capture.0 {
|
||||
// generic app abb end
|
||||
CaptureEvent::APIStart => {
|
||||
let _t = &wip_abb_trace[i];
|
||||
RefCell::borrow_mut(&*wip_abb_trace[i]).ends.insert(edges[i].1.unwrap());
|
||||
open_abb_at_this_task_or_level.remove(&(trace[i].level, if trace[i].level<2 {&curr_name} else {""}));
|
||||
},
|
||||
// generic api abb end
|
||||
CaptureEvent::APIEnd => {
|
||||
RefCell::borrow_mut(&*wip_abb_trace[i]).ends.insert(edges[i].1.unwrap());
|
||||
open_abb_at_this_task_or_level.remove(&(trace[i].level, if trace[i].level<2 {&curr_name} else {""}));
|
||||
},
|
||||
// generic isr abb end
|
||||
CaptureEvent::ISREnd => {
|
||||
RefCell::borrow_mut(&*wip_abb_trace[i]).ends.insert(edges[i].1.unwrap());
|
||||
open_abb_at_this_task_or_level.remove(&(trace[i].level, if trace[i].level<2 {&curr_name} else {""}));
|
||||
},
|
||||
// end anything
|
||||
CaptureEvent::End => {
|
||||
RefCell::borrow_mut(&*wip_abb_trace[i]).ends.insert(edges[i].1.unwrap());
|
||||
open_abb_at_this_task_or_level.remove(&(trace[i].level, if trace[i].level<2 {&curr_name} else {""}));
|
||||
},
|
||||
CaptureEvent::ISRStart => (),
|
||||
_ => panic!("Undefined block end")
|
||||
}
|
||||
}
|
||||
}
|
||||
// println!("{} {:x}-{:x} {:x} {} {} {:?} {:?}",curr_name, edges[i].0.unwrap_or(0xffff), edges[i].1.unwrap_or(0xffff), ((*wip_abb_trace[i])).borrow().start, &table[&trace[i].end_state].current_task.task_name, trace[i].level, trace[i].start_capture, trace[i].end_capture);
|
||||
}
|
||||
|
||||
for i in 0..trace.len() {
|
||||
trace[i].abb = Some((*wip_abb_trace[i]).borrow().clone());
|
||||
}
|
||||
// let last : Option<&usize> = last_abb_start_of_task.get(&curr_name);
|
||||
// // genric start of an ABB that gets preeempted
|
||||
// match trace[i].start_capture.0 {
|
||||
// CaptureEvent::APIEnd => {
|
||||
// if last.is_some() {
|
||||
// panic!("End an API call with open ABB");
|
||||
// }
|
||||
// last_abb_start_of_task.insert(curr_name, i);
|
||||
// }
|
||||
// CaptureEvent::ISREnd => {
|
||||
// if last.is_none() && trace[i].end_capture.1=="xPortPendSVHandler" && !task_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_start_of_task.insert(curr_name.clone(), i);
|
||||
// task_has_started.insert(curr_name);
|
||||
// }
|
||||
// },
|
||||
// _ => (),
|
||||
// }
|
||||
// // genric end of an ABB that got preeempted
|
||||
// match trace[i].end_capture.0 {
|
||||
// CaptureEvent::APIStart => {
|
||||
// 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_start_of_task.remove(&curr_name);
|
||||
// }
|
||||
// CaptureEvent::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);
|
||||
// last_abb_start_of_task.remove(&curr_name);
|
||||
// } else {
|
||||
// eprintln!("End with no ABB to terminate"); // could happen if the run ends in a kernel panic
|
||||
// }
|
||||
// }
|
||||
// _ => (),
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// for (b,e) in abb_begin_end.into_iter() {
|
||||
// let curr_name = table[&trace[i].start_state].current_task.task_name.clone();
|
||||
// let abb = Some(AtomicBasicBlock{start: edges[b].0.unwrap(), ends: HashSet::from([edges[e].1.unwrap()])});
|
||||
// for j in b..(e+1) {
|
||||
// if trace[j].current_task.0.task_name == curr_name {
|
||||
// trace[j].abb=abb.clone();
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
|
||||
/// invalidate subsequent intervals of equal states where an ISREnd follows an ISRStart. If the interrupt had no effect on the system we, are not interested.
|
||||
fn invalidate_ineffective_isr(trace: &mut Vec<ExecInterval>) {
|
||||
let mut i = 0;
|
||||
while i < trace.len() - 1 {
|
||||
if trace[i].is_valid() &&
|
||||
matches!(trace[i].start_capture.0, CaptureEvent::ISRStart) && matches!(trace[i].end_capture.0, CaptureEvent::ISREnd) &&
|
||||
trace[i].start_capture.1 == trace[i].end_capture.1 && trace[i].start_state == trace[i].end_state
|
||||
{
|
||||
trace[i].invaildate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// merge a sequence of intervals of the same state+abb. jump over all invalid blocks.
|
||||
fn merge_subsequent_abbs(trace: &mut Vec<ExecInterval>) {
|
||||
let mut i = 1;
|
||||
let mut lst_valid=0;
|
||||
while i < trace.len() - 1 {
|
||||
if trace[i].is_valid() {
|
||||
let mut temp = trace[i].clone();
|
||||
trace[lst_valid].try_unite_with_later_interval(&mut temp);
|
||||
trace[i] = temp;
|
||||
lst_valid = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//============================= ABB Observer
|
||||
|
||||
// The Qemusystemstate Observer retrieves the systemstate
|
||||
// that will get updated by the target.
|
||||
// #[derive(Serialize, Deserialize, Debug, Default)]
|
||||
// #[allow(clippy::unsafe_derive_deserialize)]
|
||||
// pub struct ABBObserver
|
||||
// {
|
||||
// pub last_run: HashMap<String,Vec<AtomicBasicBlock>>,
|
||||
// name: String,
|
||||
// }
|
||||
|
||||
// impl<S> Observer<S> for ABBObserver
|
||||
// where
|
||||
// S: UsesInput,
|
||||
// S::Input : HasTargetBytes,
|
||||
// {
|
||||
// #[inline]
|
||||
// fn pre_exec(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> {
|
||||
// self.last_run.clear();
|
||||
// Ok(())
|
||||
// }
|
||||
|
||||
// #[inline]
|
||||
// fn post_exec(&mut self, _state: &mut S, _input: &S::Input, _exit_kind: &ExitKind) -> Result<(), Error> {
|
||||
// unsafe {self.last_run=extract_abbs_from_trace(&mut CURRENT_SYSTEMSTATE_VEC);}
|
||||
// println!("{:?}", self.last_run);
|
||||
// Ok(())
|
||||
// }
|
||||
// }
|
||||
|
||||
// impl Named for ABBObserver
|
||||
// {
|
||||
// #[inline]
|
||||
// fn name(&self) -> &str {
|
||||
// self.name.as_str()
|
||||
// }
|
||||
// }
|
||||
|
||||
// impl ABBObserver {
|
||||
// pub fn new() -> Self {
|
||||
// Self{last_run: HashMap::new(), name: "abbs".to_string()}
|
||||
// }
|
||||
// }
|
@ -45,9 +45,10 @@ use libafl::{executors::ExitKind, inputs::Input, observers::ObserversTuple, stat
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use super::feedbacks::SystemStateFeedbackState;
|
||||
use super::trace_to_state_abb;
|
||||
use super::AtomicBasicBlock;
|
||||
use super::RefinedFreeRTOSSystemState;
|
||||
use super::CaptureEvent;
|
||||
use super::ExecInterval;
|
||||
use super::ReducedFreeRTOSSystemState;
|
||||
use super::FreeRTOSSystemStateMetadata;
|
||||
use super::observers::QemuSystemStateObserver;
|
||||
use petgraph::prelude::DiGraph;
|
||||
@ -62,12 +63,12 @@ use libafl_bolts::rands::Rand;
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, Default, Hash)]
|
||||
pub struct STGNode
|
||||
{
|
||||
base: RefinedFreeRTOSSystemState,
|
||||
base: ReducedFreeRTOSSystemState,
|
||||
abb: AtomicBasicBlock,
|
||||
}
|
||||
impl STGNode {
|
||||
pub fn pretty_print(&self) -> String {
|
||||
format!("{}\n{:x}-{:x}\n{}", self.base.current_task.0.task_name, self.abb.start, self.abb.ends.iter().next().unwrap_or_else(||&0), 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 {
|
||||
let mut s = DefaultHasher::new();
|
||||
@ -82,13 +83,37 @@ impl PartialEq for STGNode {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, Default, Hash, PartialEq, Eq)]
|
||||
pub struct STGEdge
|
||||
{
|
||||
// is_interrupt: bool,
|
||||
event: CaptureEvent,
|
||||
name: String
|
||||
}
|
||||
|
||||
impl STGEdge {
|
||||
pub fn pretty_print(&self) -> String {
|
||||
let mut short = match self.event {
|
||||
CaptureEvent::APIStart => "Call: ",
|
||||
CaptureEvent::APIEnd => "Ret: ",
|
||||
CaptureEvent::ISRStart => "Int: ",
|
||||
CaptureEvent::ISREnd => "IRet: ",
|
||||
CaptureEvent::End => "End: ",
|
||||
CaptureEvent::Undefined => "",
|
||||
}.to_string();
|
||||
short.push_str(&self.name);
|
||||
short
|
||||
}
|
||||
}
|
||||
|
||||
/// Shared Metadata for a systemstateFeedback
|
||||
#[derive(Debug, Serialize, Deserialize, SerdeAny, Clone)]
|
||||
pub struct STGFeedbackState
|
||||
{
|
||||
// aggregated traces as a graph
|
||||
pub graph: DiGraph<STGNode, ()>,
|
||||
index: HashMap<u64, NodeIndex>,
|
||||
pub graph: DiGraph<STGNode, STGEdge>,
|
||||
systemstate_index: HashMap<u64, ReducedFreeRTOSSystemState>,
|
||||
stgnode_index: HashMap<u64, NodeIndex>,
|
||||
entrypoint: NodeIndex,
|
||||
exit: NodeIndex,
|
||||
// Metadata about aggregated traces. aggegated meaning, order has been removed
|
||||
@ -99,9 +124,11 @@ impl Default for STGFeedbackState {
|
||||
fn default() -> STGFeedbackState {
|
||||
let mut graph = DiGraph::new();
|
||||
let mut entry = STGNode::default();
|
||||
entry.base.current_task.0.task_name="Start".to_string();
|
||||
entry.base.current_task.task_name="Start".to_string();
|
||||
let mut exit = STGNode::default();
|
||||
exit.base.current_task.0.task_name="End".to_string();
|
||||
exit.base.current_task.task_name="End".to_string();
|
||||
|
||||
let systemstate_index = HashMap::from([(entry.base.get_hash(), entry.base.clone()), (exit.base.get_hash(), exit.base.clone())]);
|
||||
|
||||
let h_entry = entry.calculate_hash();
|
||||
let h_exit = exit.calculate_hash();
|
||||
@ -113,10 +140,11 @@ impl Default for STGFeedbackState {
|
||||
|
||||
STGFeedbackState {
|
||||
graph,
|
||||
index,
|
||||
stgnode_index: index,
|
||||
entrypoint,
|
||||
exit,
|
||||
worst_observed_per_aggegated_path: HashMap::new(),
|
||||
systemstate_index,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -181,22 +209,79 @@ impl StgFeedback {
|
||||
/// newly discovered node?
|
||||
/// side effect:
|
||||
/// the graph gets new nodes
|
||||
fn update_stg(trace: &Vec<RefinedFreeRTOSSystemState>, map: Vec<(String, Rc<AtomicBasicBlock>, usize, u64)>, fbs: &mut STGFeedbackState) -> (Vec<NodeIndex>, Vec<EdgeIndex>, bool) {
|
||||
// fn update_stg(trace: &Vec<ReducedFreeRTOSSystemState>, map: Vec<(String, Rc<AtomicBasicBlock>, usize, u64)>, fbs: &mut STGFeedbackState) -> (Vec<NodeIndex>, Vec<EdgeIndex>, bool) {
|
||||
// let mut return_node_trace = vec![fbs.entrypoint];
|
||||
// let mut return_edge_trace = vec![];
|
||||
// let mut interesting = false;
|
||||
// // add all missing state+abb combinations to the graph
|
||||
// for (i,state) in trace.iter().enumerate() { // Iterate states first, keep the trace order intact
|
||||
// if let Some(marker) = map.iter().filter(|(_,_,index,_)| index==&i).next() { //
|
||||
// let node = STGNode {base: state.clone(), abb: (*marker.1).clone()};
|
||||
// let h_node = node.calculate_hash();
|
||||
// let next_idx = if let Some(idx) = fbs.index.get(&h_node) {
|
||||
// // alredy present
|
||||
// *idx
|
||||
// } else {
|
||||
// // not present
|
||||
// let idx = fbs.graph.add_node(node);
|
||||
// fbs.index.insert(h_node, idx);
|
||||
// interesting |= INTEREST_NODE;
|
||||
// idx
|
||||
// };
|
||||
// // connect in graph if edge not present
|
||||
// let e = fbs.graph.edges_directed(return_node_trace[return_node_trace.len()-1],Direction::Outgoing).find(|x| petgraph::visit::EdgeRef::target(x) == next_idx);
|
||||
// if let Some(e_) = e {
|
||||
// return_edge_trace.push(petgraph::visit::EdgeRef::id(&e_));
|
||||
// } else {
|
||||
// let e_ = fbs.graph.add_edge(return_node_trace[return_node_trace.len()-1], next_idx, ());
|
||||
// return_edge_trace.push(e_);
|
||||
// interesting |= INTEREST_EDGE;
|
||||
// }
|
||||
// return_node_trace.push(next_idx);
|
||||
// /*
|
||||
// Ideas:
|
||||
// Mark edges triggered by interrupts
|
||||
// Specify path with edges instead of nodes?
|
||||
// Form a coverage map over edges?
|
||||
// Sum up execution time per ABB
|
||||
// */
|
||||
// }
|
||||
// }
|
||||
// // every path terminates at the end
|
||||
// if !fbs.graph.neighbors_directed(return_node_trace[return_node_trace.len()-1],Direction::Outgoing).any(|x| x == fbs.exit) {
|
||||
// let e_ = fbs.graph.add_edge(return_node_trace[return_node_trace.len()-1], fbs.exit, ());
|
||||
// return_edge_trace.push(e_);
|
||||
// interesting |= INTEREST_EDGE;
|
||||
// }
|
||||
// return_node_trace.push(fbs.exit);
|
||||
// #[cfg(feature = "feed_stg")]
|
||||
// set_observer_map(&return_edge_trace);
|
||||
// (return_node_trace, return_edge_trace, interesting)
|
||||
// }
|
||||
|
||||
/// params:
|
||||
/// tarce of system states
|
||||
/// list of all atomic basic blocks with asociated state index and ticks
|
||||
/// produces:
|
||||
/// tarce of node indexes representing the path trough the graph
|
||||
/// newly discovered node?
|
||||
/// side effect:
|
||||
/// the graph gets new nodes
|
||||
fn update_stg_interval(trace: &Vec<ExecInterval>, table: &HashMap<u64, ReducedFreeRTOSSystemState>, fbs: &mut STGFeedbackState) -> (Vec<NodeIndex>, Vec<EdgeIndex>, bool) {
|
||||
let mut return_node_trace = vec![fbs.entrypoint];
|
||||
let mut return_edge_trace = vec![];
|
||||
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()};
|
||||
for (i,interval) in trace.iter().enumerate() { // Iterate intervals
|
||||
let node = STGNode {base: table[&interval.start_state].clone(), abb: interval.abb.as_ref().unwrap().clone()};
|
||||
let h_node = node.calculate_hash();
|
||||
let next_idx = if let Some(idx) = fbs.index.get(&h_node) {
|
||||
let next_idx = if let Some(idx) = fbs.stgnode_index.get(&h_node) {
|
||||
// alredy present
|
||||
*idx
|
||||
} else {
|
||||
// not present
|
||||
let idx = fbs.graph.add_node(node);
|
||||
fbs.index.insert(h_node, idx);
|
||||
fbs.stgnode_index.insert(h_node, idx);
|
||||
interesting |= INTEREST_NODE;
|
||||
idx
|
||||
};
|
||||
@ -205,7 +290,7 @@ impl StgFeedback {
|
||||
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, ());
|
||||
let e_ = fbs.graph.add_edge(return_node_trace[return_node_trace.len()-1], next_idx, STGEdge{event: interval.start_capture.0, name: interval.start_capture.1.clone()});
|
||||
return_edge_trace.push(e_);
|
||||
interesting |= INTEREST_EDGE;
|
||||
}
|
||||
@ -218,10 +303,9 @@ impl StgFeedback {
|
||||
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, ());
|
||||
let e_ = fbs.graph.add_edge(return_node_trace[return_node_trace.len()-1], fbs.exit, STGEdge { event: CaptureEvent::End, name: String::from("End") });
|
||||
return_edge_trace.push(e_);
|
||||
interesting |= INTEREST_EDGE;
|
||||
}
|
||||
@ -265,31 +349,33 @@ where
|
||||
}
|
||||
};
|
||||
|
||||
let (abbs, ordered) = trace_to_state_abb(&observer.last_run);
|
||||
// println!("{:?}",abbs);
|
||||
let (_trace, _, mut interesting) = StgFeedback::update_stg(&observer.last_run, abbs, feedbackstate);
|
||||
if INTEREST_AGGREGATE {
|
||||
let (it1, _it2) : (Vec<_>, Vec<_>) = ordered.into_iter().unzip();
|
||||
// aggegation by sorting, order of states is not relevant
|
||||
let mut tmp : Vec<_> = it1;
|
||||
tmp.sort();
|
||||
if let Some(x) = feedbackstate.worst_observed_per_aggegated_path.get_mut(&tmp) {
|
||||
let t = clock_observer.last_runtime();
|
||||
if t > *x {
|
||||
*x = t;
|
||||
interesting |= true;
|
||||
}
|
||||
} else {
|
||||
feedbackstate.worst_observed_per_aggegated_path.insert(tmp, clock_observer.last_runtime());
|
||||
interesting |= true;
|
||||
}
|
||||
}
|
||||
let (_trace, _, mut interesting) = StgFeedback::update_stg_interval(&observer.last_trace, &observer.last_states, feedbackstate);
|
||||
// let (abbs, ordered) = trace_to_state_abb(&observer.last_run);
|
||||
// // println!("{:?}",abbs);
|
||||
// let (_trace, _, mut interesting) = StgFeedback::update_stg(&observer.last_run, abbs, feedbackstate);
|
||||
// if INTEREST_AGGREGATE {
|
||||
// let (it1, _it2) : (Vec<_>, Vec<_>) = ordered.into_iter().unzip();
|
||||
// // aggegation by sorting, order of states is not relevant
|
||||
// let mut tmp : Vec<_> = it1;
|
||||
// tmp.sort();
|
||||
// if let Some(x) = feedbackstate.worst_observed_per_aggegated_path.get_mut(&tmp) {
|
||||
// let t = clock_observer.last_runtime();
|
||||
// if t > *x {
|
||||
// *x = t;
|
||||
// interesting |= INTEREST_AGGREGATE;
|
||||
// }
|
||||
// } else {
|
||||
// feedbackstate.worst_observed_per_aggegated_path.insert(tmp, clock_observer.last_runtime());
|
||||
// interesting |= INTEREST_AGGREGATE;
|
||||
// }
|
||||
// }
|
||||
|
||||
// let out = feedbackstate.graph.map(|i,x| x.pretty_print(), |_,_| "");
|
||||
// let outs = Dot::with_config(&out, &[Config::EdgeNoLabel]).to_string();
|
||||
// let outs = outs.replace(';',"\\n");
|
||||
// fs::write("./mystg.dot",outs).expect("Failed to write graph");
|
||||
|
||||
// Ok(interesting)
|
||||
Ok(interesting)
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user