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
|
//============================= Struct definitions
|
||||||
|
|
||||||
#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
|
#[derive(Debug, Default, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
pub enum CaptureEvent {
|
pub enum CaptureEvent {
|
||||||
APIStart,
|
APIStart, /// src,dst
|
||||||
APIEnd,
|
APIEnd, /// src,dst
|
||||||
ISRStart,
|
ISRStart, /// _,dst
|
||||||
ISREnd,
|
ISREnd, /// src,_
|
||||||
End,
|
End, /// src,_
|
||||||
#[default]
|
#[default]
|
||||||
Undefined,
|
Undefined,
|
||||||
}
|
}
|
||||||
@ -67,16 +67,18 @@ pub struct RefinedTCB {
|
|||||||
pub priority: u32,
|
pub priority: u32,
|
||||||
pub base_priority: u32,
|
pub base_priority: u32,
|
||||||
mutexes_held: u32,
|
mutexes_held: u32,
|
||||||
notify_value: u32,
|
// notify_value: u32,
|
||||||
notify_state: u8,
|
notify_state: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for RefinedTCB {
|
impl PartialEq for RefinedTCB {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
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.priority == other.priority &&
|
||||||
self.base_priority == other.base_priority
|
self.base_priority == other.base_priority;
|
||||||
// && self.notify_state == other.notify_state
|
#[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.task_name.hash(state);
|
||||||
self.priority.hash(state);
|
self.priority.hash(state);
|
||||||
self.mutexes_held.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_state.hash(state);
|
||||||
// self.notify_value.hash(state);
|
// self.notify_value.hash(state);
|
||||||
}
|
}
|
||||||
@ -101,7 +103,7 @@ impl RefinedTCB {
|
|||||||
priority: input.uxPriority,
|
priority: input.uxPriority,
|
||||||
base_priority: input.uxBasePriority,
|
base_priority: input.uxBasePriority,
|
||||||
mutexes_held: input.uxMutexesHeld,
|
mutexes_held: input.uxMutexesHeld,
|
||||||
notify_value: input.ulNotifiedValue[0],
|
// notify_value: input.ulNotifiedValue[0],
|
||||||
notify_state: input.ucNotifyState[0],
|
notify_state: input.ucNotifyState[0],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -115,27 +117,25 @@ impl RefinedTCB {
|
|||||||
priority: input.uxPriority,
|
priority: input.uxPriority,
|
||||||
base_priority: input.uxBasePriority,
|
base_priority: input.uxBasePriority,
|
||||||
mutexes_held: input.uxMutexesHeld,
|
mutexes_held: input.uxMutexesHeld,
|
||||||
notify_value: input.ulNotifiedValue[0],
|
// notify_value: input.ulNotifiedValue[0],
|
||||||
notify_state: input.ucNotifyState[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)]
|
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
|
||||||
pub struct RefinedFreeRTOSSystemState {
|
pub struct ReducedFreeRTOSSystemState {
|
||||||
pub start_tick: u64,
|
// pub tick: u64,
|
||||||
pub end_tick: u64,
|
pub current_task: RefinedTCB,
|
||||||
edge: (Option<GuestAddr>,Option<GuestAddr>),
|
ready_list_after: Vec<RefinedTCB>,
|
||||||
input_counter: u32,
|
delay_list_after: Vec<RefinedTCB>,
|
||||||
pub current_task: (RefinedTCB, u32),
|
// edge: (Option<GuestAddr>,Option<GuestAddr>),
|
||||||
ready_list_after: Vec<(RefinedTCB, u32)>,
|
// pub capture_point: (CaptureEvent,String),
|
||||||
delay_list_after: Vec<(RefinedTCB, u32)>,
|
// input_counter: u32
|
||||||
// pub capture_point: String
|
|
||||||
pub capture_point: (CaptureEvent,String)
|
|
||||||
}
|
}
|
||||||
impl PartialEq for RefinedFreeRTOSSystemState {
|
impl PartialEq for ReducedFreeRTOSSystemState {
|
||||||
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 &&
|
||||||
self.delay_list_after == other.delay_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) {
|
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);
|
||||||
self.delay_list_after.hash(state);
|
self.delay_list_after.hash(state);
|
||||||
// self.last_pc.hash(state);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl RefinedFreeRTOSSystemState {
|
impl ReducedFreeRTOSSystemState {
|
||||||
fn get_time(&self) -> u64 {
|
// fn get_tick(&self) -> u64 {
|
||||||
self.end_tick-self.start_tick
|
// self.tick
|
||||||
}
|
// }
|
||||||
|
|
||||||
pub fn print_lists(&self) -> String {
|
pub fn print_lists(&self) -> String {
|
||||||
let mut ret = String::from("+");
|
let mut ret = String::from("+");
|
||||||
for j in self.ready_list_after.iter() {
|
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-");
|
ret.push_str("\n-");
|
||||||
for j in self.delay_list_after.iter() {
|
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
|
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
|
// 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 {
|
||||||
pub inner: Vec<RefinedFreeRTOSSystemState>,
|
pub inner: Vec<ReducedFreeRTOSSystemState>,
|
||||||
trace_length: usize,
|
trace_length: usize,
|
||||||
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<RefinedFreeRTOSSystemState>) -> Self{
|
pub fn new(inner: Vec<ReducedFreeRTOSSystemState>) -> 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 {trace_length: inner.len(), inner: inner, indices: tmp, tcref: 0}
|
Self {trace_length: inner.len(), inner: inner, indices: tmp, tcref: 0}
|
||||||
}
|
}
|
||||||
@ -218,6 +269,7 @@ libafl_bolts::impl_serdeany!(FreeRTOSSystemStateMetadata);
|
|||||||
pub struct AtomicBasicBlock {
|
pub struct AtomicBasicBlock {
|
||||||
start: GuestAddr,
|
start: GuestAddr,
|
||||||
ends: HashSet<GuestAddr>,
|
ends: HashSet<GuestAddr>,
|
||||||
|
level: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Hash for AtomicBasicBlock {
|
impl Hash for AtomicBasicBlock {
|
||||||
@ -226,6 +278,7 @@ impl Hash for AtomicBasicBlock {
|
|||||||
self.start.hash(state);
|
self.start.hash(state);
|
||||||
let mut keys : Vec<_> = self.ends.iter().collect();
|
let mut keys : Vec<_> = self.ends.iter().collect();
|
||||||
keys.sort();
|
keys.sort();
|
||||||
|
self.level.hash(state);
|
||||||
keys.hash(state);
|
keys.hash(state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -236,7 +289,7 @@ impl fmt::Display for AtomicBasicBlock {
|
|||||||
for end in &self.ends {
|
for end in &self.ends {
|
||||||
ends_str.push_str(&format!("0x{:#x}, ", end));
|
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 {
|
impl fmt::Debug for AtomicBasicBlock {
|
||||||
@ -245,7 +298,7 @@ impl fmt::Debug for AtomicBasicBlock {
|
|||||||
for end in &self.ends {
|
for end in &self.ends {
|
||||||
ends_str.push_str(&format!("{:#x}, ", end));
|
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 {
|
impl Ord for AtomicBasicBlock {
|
||||||
fn cmp(&self, other: &AtomicBasicBlock) -> std::cmp::Ordering {
|
fn cmp(&self, other: &AtomicBasicBlock) -> std::cmp::Ordering {
|
||||||
if self.start.cmp(&other.start) == std::cmp::Ordering::Equal {
|
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'
|
// 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 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>>();
|
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();
|
let mut ret: HashSet<_, _> = HashSet::new();
|
||||||
for state in trace {
|
for state in trace {
|
||||||
ret.insert(state.current_task.0.task_name.to_string());
|
ret.insert(state.current_task.task_name.to_string());
|
||||||
}
|
}
|
||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extract_abbs_from_trace(trace: &Vec<RefinedFreeRTOSSystemState>) -> HashMap<String,Vec<Rc<AtomicBasicBlock>>> {
|
// 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 abbs_of_task : HashMap<String, Vec<Rc<AtomicBasicBlock>>> = HashMap::new();
|
||||||
let mut last_abb_of_task : HashMap<String, usize> = HashMap::new();
|
// let mut last_abb_of_task : HashMap<String, usize> = HashMap::new();
|
||||||
// iterate over all states and extract atomic basic blocks
|
// // iterate over all states and extract atomic basic blocks
|
||||||
// an atomic base block has a single entry and multiple exits
|
// // an atomic base block has a single entry and multiple exits
|
||||||
// the cuts between blocks are api calls
|
// // the cuts between blocks are api calls
|
||||||
// when capture_point is APIEnd, the destination of the edge is the start of an atomic block
|
// // 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
|
// // so the next APIStart with the same current_tcb.pcTaskName is the end of the atomic block
|
||||||
for i in 0..trace.len() {
|
// for i in 0..trace.len() {
|
||||||
let curr_name = trace[i].current_task.0.task_name.clone();
|
// let curr_name = trace[i].current_task.0.task_name.clone();
|
||||||
let last : Option<&usize> = last_abb_of_task.get(&curr_name);
|
// let last : Option<&usize> = last_abb_of_task.get(&curr_name);
|
||||||
match trace[i].capture_point.0 {
|
// match trace[i].capture_point.0 {
|
||||||
CaptureEvent::APIStart => {
|
// CaptureEvent::APIStart => {
|
||||||
// end the last atomic block
|
// // end the last atomic block
|
||||||
if let Some(&l) = last {
|
// if let Some(&l) = last {
|
||||||
let start = trace[l].edge.1.unwrap();
|
// let start = trace[l].edge.1.unwrap();
|
||||||
let end = trace[i].edge.0.unwrap();
|
// let end = trace[i].edge.0.unwrap();
|
||||||
match abbs_of_task.get_mut(&curr_name) {
|
// match abbs_of_task.get_mut(&curr_name) {
|
||||||
Some(v) => {
|
// Some(v) => {
|
||||||
match v.iter_mut().find(|x| x.start==start) {
|
// match v.iter_mut().find(|x| x.start==start) {
|
||||||
Some(abb) => {
|
// Some(abb) => {
|
||||||
Rc::get_mut(abb).unwrap().ends.insert(end);
|
// Rc::get_mut(abb).unwrap().ends.insert(end);
|
||||||
}
|
// }
|
||||||
None => {
|
// None => {
|
||||||
let mut t = HashSet::new();
|
// let mut t = HashSet::new();
|
||||||
t.insert(end);
|
// t.insert(end);
|
||||||
v.push(Rc::new(AtomicBasicBlock {start, ends: t}));
|
// v.push(Rc::new(AtomicBasicBlock {start, ends: t}));
|
||||||
}
|
// }
|
||||||
};
|
// };
|
||||||
},
|
// },
|
||||||
None => {
|
// None => {
|
||||||
let mut v = Vec::new();
|
// let mut v = Vec::new();
|
||||||
let mut t = HashSet::new();
|
// let mut t = HashSet::new();
|
||||||
t.insert(end);
|
// t.insert(end);
|
||||||
v.push(Rc::new(AtomicBasicBlock {start, ends: t}));
|
// v.push(Rc::new(AtomicBasicBlock {start, ends: t}));
|
||||||
abbs_of_task.insert(curr_name, v);
|
// abbs_of_task.insert(curr_name, v);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
} else {
|
// } else {
|
||||||
// first API call of this task
|
// // first API call of this task
|
||||||
let mut v = Vec::new();
|
// let mut v = Vec::new();
|
||||||
let mut t = HashSet::new();
|
// let mut t = HashSet::new();
|
||||||
let end = trace[i].edge.0.unwrap();
|
// let end = trace[i].edge.0.unwrap();
|
||||||
t.insert(end);
|
// t.insert(end);
|
||||||
v.push(Rc::new(AtomicBasicBlock {start: 0, ends: t}));
|
// v.push(Rc::new(AtomicBasicBlock {start: 0, ends: t}));
|
||||||
abbs_of_task.insert(curr_name, v);
|
// abbs_of_task.insert(curr_name, v);
|
||||||
}
|
// }
|
||||||
},
|
// },
|
||||||
CaptureEvent::APIEnd => {
|
// CaptureEvent::APIEnd => {
|
||||||
match last {
|
// match last {
|
||||||
Some(&l) => {
|
// Some(&l) => {
|
||||||
//assert!(trace[l].capture_point.0 == CaptureEvent::APIStart);
|
// //assert!(trace[l].capture_point.0 == CaptureEvent::APIStart);
|
||||||
},
|
// },
|
||||||
None => (),
|
// None => (),
|
||||||
}
|
// }
|
||||||
last_abb_of_task.insert(curr_name, i);
|
// last_abb_of_task.insert(curr_name, i);
|
||||||
},
|
// },
|
||||||
CaptureEvent::ISRStart => {
|
// CaptureEvent::ISRStart => {
|
||||||
},
|
// },
|
||||||
CaptureEvent::ISREnd => {
|
// CaptureEvent::ISREnd => {
|
||||||
},
|
// },
|
||||||
CaptureEvent::End => {
|
// CaptureEvent::End => {
|
||||||
// end the last atomic block
|
// // end the last atomic block
|
||||||
if let Some(&l) = last {
|
// if let Some(&l) = last {
|
||||||
let start = trace[l].edge.1.unwrap();
|
// let start = trace[l].edge.1.unwrap();
|
||||||
let end = trace[i].edge.0.unwrap();
|
// let end = trace[i].edge.0.unwrap();
|
||||||
match abbs_of_task.get_mut(&curr_name) {
|
// match abbs_of_task.get_mut(&curr_name) {
|
||||||
Some(v) => {
|
// Some(v) => {
|
||||||
match v.iter_mut().find(|x| x.start==start) {
|
// match v.iter_mut().find(|x| x.start==start) {
|
||||||
Some(abb) => {
|
// Some(abb) => {
|
||||||
Rc::get_mut(abb).unwrap().ends.insert(end);
|
// Rc::get_mut(abb).unwrap().ends.insert(end);
|
||||||
}
|
// }
|
||||||
None => {
|
// None => {
|
||||||
let mut t = HashSet::new();
|
// let mut t = HashSet::new();
|
||||||
t.insert(end);
|
// t.insert(end);
|
||||||
v.push(Rc::new(AtomicBasicBlock {start, ends: t}));
|
// v.push(Rc::new(AtomicBasicBlock {start, ends: t}));
|
||||||
}
|
// }
|
||||||
};
|
// };
|
||||||
},
|
// },
|
||||||
None => {
|
// None => {
|
||||||
let mut v = Vec::new();
|
// let mut v = Vec::new();
|
||||||
let mut t = HashSet::new();
|
// let mut t = HashSet::new();
|
||||||
t.insert(end);
|
// t.insert(end);
|
||||||
v.push(Rc::new(AtomicBasicBlock {start, ends: t}));
|
// v.push(Rc::new(AtomicBasicBlock {start, ends: t}));
|
||||||
abbs_of_task.insert(curr_name, v);
|
// abbs_of_task.insert(curr_name, v);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
} else {
|
// } else {
|
||||||
// first API call of this task
|
// // first API call of this task
|
||||||
let mut v = Vec::new();
|
// let mut v = Vec::new();
|
||||||
let mut t = HashSet::new();
|
// let mut t = HashSet::new();
|
||||||
let end = trace[i].edge.0.unwrap();
|
// let end = trace[i].edge.0.unwrap();
|
||||||
t.insert(end);
|
// t.insert(end);
|
||||||
v.push(Rc::new(AtomicBasicBlock {start: 0, ends: t}));
|
// v.push(Rc::new(AtomicBasicBlock {start: 0, ends: t}));
|
||||||
abbs_of_task.insert(curr_name, v);
|
// abbs_of_task.insert(curr_name, v);
|
||||||
}
|
// }
|
||||||
},
|
// },
|
||||||
CaptureEvent::Undefined => {
|
// CaptureEvent::Undefined => {
|
||||||
},
|
// },
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
abbs_of_task
|
// abbs_of_task
|
||||||
}
|
// }
|
||||||
|
|
||||||
/// returns (name, abb, index, ticks, Option<total abb ticks iff abb termiates here>)
|
/// 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)>) {
|
// 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 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 has_started : HashSet<String> = HashSet::new();
|
||||||
let mut abb_begin_end : HashMap<usize,usize> = HashMap::new();
|
// let mut abb_begin_end : HashMap<usize,usize> = HashMap::new();
|
||||||
let mut last_abb_of_task : HashMap<String, usize> = HashMap::new();
|
// let mut last_abb_of_task : HashMap<String, usize> = HashMap::new();
|
||||||
for i in 0..trace.len() {
|
// for i in 0..trace.len() {
|
||||||
let curr_name = trace[i].current_task.0.task_name.clone();
|
// let curr_name = trace[i].current_task.0.task_name.clone();
|
||||||
let last : Option<&usize> = last_abb_of_task.get(&curr_name);
|
// let last : Option<&usize> = last_abb_of_task.get(&curr_name);
|
||||||
match trace[i].capture_point.0 {
|
// match trace[i].capture_point.0 {
|
||||||
CaptureEvent::APIStart => {
|
// CaptureEvent::APIStart => {
|
||||||
// end the last atomic block, which began with APIEnd or initial PendSV End
|
// // end the last atomic block, which began with APIEnd or initial PendSV End
|
||||||
if let Some(&l) = last {
|
// if let Some(&l) = last {
|
||||||
// let start = trace[l].edge.1.unwrap();
|
// // let start = trace[l].edge.1.unwrap();
|
||||||
// let end = trace[i].edge.0.unwrap();
|
// // let end = trace[i].edge.0.unwrap();
|
||||||
abb_begin_end.insert(l, i);
|
// abb_begin_end.insert(l, i);
|
||||||
} else {
|
// } else {
|
||||||
panic!("Start an API call with no ABB to terminate");
|
// panic!("Start an API call with no ABB to terminate");
|
||||||
}
|
// }
|
||||||
last_abb_of_task.remove(&curr_name);
|
// last_abb_of_task.remove(&curr_name);
|
||||||
},
|
// },
|
||||||
CaptureEvent::APIEnd => {
|
// CaptureEvent::APIEnd => {
|
||||||
// APIEnd means a new ABB begins
|
// // APIEnd means a new ABB begins
|
||||||
match last {
|
// match last {
|
||||||
Some(&l) => {
|
// Some(&l) => {
|
||||||
panic!("End an API call with open ABB");
|
// panic!("End an API call with open ABB");
|
||||||
},
|
// },
|
||||||
None => (),
|
// None => (),
|
||||||
}
|
// }
|
||||||
last_abb_of_task.insert(curr_name, i);
|
// last_abb_of_task.insert(curr_name, i);
|
||||||
},
|
// },
|
||||||
CaptureEvent::ISRStart => {
|
// CaptureEvent::ISRStart => {
|
||||||
},
|
// },
|
||||||
CaptureEvent::ISREnd => {
|
// CaptureEvent::ISREnd => {
|
||||||
if last.is_none() && trace[i].capture_point.1=="xPortPendSVHandler" && !has_started.contains(&curr_name) {
|
// 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
|
// // 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);
|
// last_abb_of_task.insert(curr_name.clone(), i);
|
||||||
has_started.insert(curr_name);
|
// has_started.insert(curr_name);
|
||||||
}
|
// }
|
||||||
},
|
// },
|
||||||
CaptureEvent::End => {
|
// CaptureEvent::End => {
|
||||||
// end the last atomic block
|
// // end the last atomic block
|
||||||
if let Some(&l) = last {
|
// if let Some(&l) = last {
|
||||||
abb_begin_end.insert(l, i);
|
// abb_begin_end.insert(l, i);
|
||||||
} else {
|
// } else {
|
||||||
panic!("End without running ABB");
|
// panic!("End without running ABB");
|
||||||
}
|
// }
|
||||||
last_abb_of_task.remove(&curr_name);
|
// last_abb_of_task.remove(&curr_name);
|
||||||
},
|
// },
|
||||||
CaptureEvent::Undefined => {
|
// CaptureEvent::Undefined => {
|
||||||
},
|
// },
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
let mut abb_intervals : Vec<_> = abb_begin_end.into_iter().collect();
|
// let mut abb_intervals : Vec<_> = abb_begin_end.into_iter().collect();
|
||||||
abb_intervals.sort_by_key(|(x,_)| *x);
|
// abb_intervals.sort_by_key(|(x,_)| *x);
|
||||||
let mut chunks = Vec::new(); // (name, abb, index, ticks)
|
// let mut chunks = Vec::new(); // (name, abb, index, ticks)
|
||||||
for &(s,e) in abb_intervals.iter() {
|
// for &(s,e) in abb_intervals.iter() {
|
||||||
let curr_name = trace[s].current_task.0.task_name.clone();
|
// let curr_name = trace[s].current_task.0.task_name.clone();
|
||||||
let start = match trace[s].capture_point.0 {
|
// let start = match trace[s].capture_point.0 {
|
||||||
CaptureEvent::ISREnd => 0,
|
// CaptureEvent::ISREnd => 0,
|
||||||
CaptureEvent::APIEnd => trace[s].edge.1.unwrap(),
|
// CaptureEvent::APIEnd => trace[s].edge.1.unwrap(),
|
||||||
_ => panic!(),
|
// _ => panic!(),
|
||||||
};
|
// };
|
||||||
let end = trace[e].edge.0.unwrap();
|
// let end = trace[e].edge.0.unwrap();
|
||||||
let abb = Rc::new(AtomicBasicBlock {start, ends: HashSet::from([end])});
|
// let abb = Rc::new(AtomicBasicBlock {start, ends: HashSet::from([end])});
|
||||||
// find intervalls where the abb is actually running, not preempted
|
// // find intervalls where the abb is actually running, not preempted
|
||||||
// count up exec time
|
// // count up exec time
|
||||||
let mut sum_of_pieces = 0;
|
// let mut sum_of_pieces = 0;
|
||||||
for i in s..e {
|
// for i in s..e {
|
||||||
if trace[i].current_task.0.task_name == curr_name {
|
// if trace[i].current_task.0.task_name == curr_name {
|
||||||
match trace[i].capture_point.0 {
|
// 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::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::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;},
|
// 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!(),
|
// _ => panic!(),
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
abbs_in_exec_order.push((e,(*abb).clone(), sum_of_pieces));
|
// abbs_in_exec_order.push((e,(*abb).clone(), sum_of_pieces));
|
||||||
}
|
// }
|
||||||
abbs_in_exec_order.sort_by_key(|x| x.0);
|
// 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();
|
// 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.sort_by_key(|x| x.2);
|
||||||
(chunks, abbs_in_exec_order)
|
// (chunks, abbs_in_exec_order)
|
||||||
}
|
// }
|
||||||
|
|
||||||
libafl_bolts::impl_serdeany!(AtomicBasicBlock);
|
libafl_bolts::impl_serdeany!(AtomicBasicBlock);
|
@ -7,14 +7,18 @@ use libafl_bolts::AsSlice;
|
|||||||
use libafl::Error;
|
use libafl::Error;
|
||||||
use libafl::observers::Observer;
|
use libafl::observers::Observer;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use hashbrown::HashMap;
|
use hashbrown::{HashMap, HashSet};
|
||||||
use crate::systemstate::CaptureEvent;
|
use crate::systemstate::CaptureEvent;
|
||||||
|
use std::rc::Rc;
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
|
use super::{ AtomicBasicBlock, ExecInterval};
|
||||||
use super::{
|
use super::{
|
||||||
CURRENT_SYSTEMSTATE_VEC,
|
CURRENT_SYSTEMSTATE_VEC,
|
||||||
RawFreeRTOSSystemState,
|
RawFreeRTOSSystemState,
|
||||||
RefinedTCB,
|
RefinedTCB,
|
||||||
RefinedFreeRTOSSystemState,
|
ReducedFreeRTOSSystemState,
|
||||||
freertos::{List_t, TCB_t, rtos_struct, rtos_struct::*},
|
freertos::{List_t, TCB_t, rtos_struct, rtos_struct::*},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -26,7 +30,9 @@ use super::{
|
|||||||
#[allow(clippy::unsafe_derive_deserialize)]
|
#[allow(clippy::unsafe_derive_deserialize)]
|
||||||
pub struct QemuSystemStateObserver
|
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>,
|
pub last_input: Vec<u8>,
|
||||||
name: String,
|
name: String,
|
||||||
}
|
}
|
||||||
@ -44,7 +50,20 @@ where
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
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.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();
|
self.last_input=_input.target_bytes().as_slice().to_owned();
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -68,7 +87,7 @@ impl HasLen for QemuSystemStateObserver
|
|||||||
|
|
||||||
impl QemuSystemStateObserver {
|
impl QemuSystemStateObserver {
|
||||||
pub fn new() -> Self {
|
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
|
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<RawFreeRTOSSystemState>) -> Vec<RefinedFreeRTOSSystemState> {
|
fn refine_system_states(input: &mut Vec<RawFreeRTOSSystemState>) -> (Vec<ReducedFreeRTOSSystemState>, Vec<(u64, CaptureEvent, String, (Option<u32>, Option<u32>))>) {
|
||||||
let mut iteration_counts : HashMap<String, u32>= HashMap::new();
|
let mut ret = (Vec::<_>::new(), Vec::<_>::new());
|
||||||
let mut ret = Vec::<RefinedFreeRTOSSystemState>::new();
|
|
||||||
let mut start_tick : u64 = 0;
|
|
||||||
for mut i in input.drain(..) {
|
for mut i in input.drain(..) {
|
||||||
let cur = RefinedTCB::from_tcb_owned(i.current_tcb);
|
let cur = RefinedTCB::from_tcb_owned(i.current_tcb);
|
||||||
// collect ready list
|
// 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.append(&mut delay_list_overflow);
|
||||||
delay_list.sort_by(|a,b| a.task_name.cmp(&b.task_name));
|
delay_list.sort_by(|a,b| a.task_name.cmp(&b.task_name));
|
||||||
|
|
||||||
// keep counts for all tasks
|
ret.0.push(ReducedFreeRTOSSystemState {
|
||||||
let _ = iteration_counts.try_insert(cur.task_name.clone(), 1);
|
current_task: cur,
|
||||||
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,
|
|
||||||
ready_list_after: collector,
|
ready_list_after: collector,
|
||||||
delay_list_after: delay_list,
|
delay_list_after: delay_list,
|
||||||
input_counter: i.input_counter,//+IRQ_INPUT_BYTES_NUMBER,
|
// input_counter: i.input_counter,//+IRQ_INPUT_BYTES_NUMBER,
|
||||||
edge: i.edge,
|
|
||||||
capture_point: (i.capture_point.0,i.capture_point.1.to_string()),
|
|
||||||
});
|
});
|
||||||
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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_ineffective_isr(mut trace: Vec<RefinedFreeRTOSSystemState>) -> Vec<RefinedFreeRTOSSystemState> {
|
/// Transform the states and metadata into a list of ExecIntervals
|
||||||
// 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.
|
fn states2intervals(trace: Vec<ReducedFreeRTOSSystemState>, meta: Vec<(u64, CaptureEvent, String, (Option<u32>, Option<u32>))>) -> (Vec<ExecInterval>, HashMap<u64, ReducedFreeRTOSSystemState>) {
|
||||||
let mut ret : Vec<RefinedFreeRTOSSystemState> = Vec::new();
|
let mut isr_stack : VecDeque<u8> = VecDeque::from([]); // 2+ = ISR, 1 = systemcall, 0 = APP. Trace starts with an ISREnd and executes the app
|
||||||
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;
|
|
||||||
|
|
||||||
i+=2;
|
|
||||||
} else {
|
let mut level_of_task : HashMap<&str, u8> = HashMap::new();
|
||||||
ret.push(trace[i].clone());
|
|
||||||
i+=1;
|
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 {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => &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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ret
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 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 serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use super::feedbacks::SystemStateFeedbackState;
|
use super::feedbacks::SystemStateFeedbackState;
|
||||||
use super::trace_to_state_abb;
|
|
||||||
use super::AtomicBasicBlock;
|
use super::AtomicBasicBlock;
|
||||||
use super::RefinedFreeRTOSSystemState;
|
use super::CaptureEvent;
|
||||||
|
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;
|
||||||
@ -62,12 +63,12 @@ use libafl_bolts::rands::Rand;
|
|||||||
#[derive(Serialize, Deserialize, Clone, Debug, Default, Hash)]
|
#[derive(Serialize, Deserialize, Clone, Debug, Default, Hash)]
|
||||||
pub struct STGNode
|
pub struct STGNode
|
||||||
{
|
{
|
||||||
base: RefinedFreeRTOSSystemState,
|
base: ReducedFreeRTOSSystemState,
|
||||||
abb: AtomicBasicBlock,
|
abb: AtomicBasicBlock,
|
||||||
}
|
}
|
||||||
impl STGNode {
|
impl STGNode {
|
||||||
pub fn pretty_print(&self) -> String {
|
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 {
|
fn calculate_hash(&self) -> u64 {
|
||||||
let mut s = DefaultHasher::new();
|
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
|
/// Shared Metadata for a systemstateFeedback
|
||||||
#[derive(Debug, Serialize, Deserialize, SerdeAny, Clone)]
|
#[derive(Debug, Serialize, Deserialize, SerdeAny, Clone)]
|
||||||
pub struct STGFeedbackState
|
pub struct STGFeedbackState
|
||||||
{
|
{
|
||||||
// aggregated traces as a graph
|
// aggregated traces as a graph
|
||||||
pub graph: DiGraph<STGNode, ()>,
|
pub graph: DiGraph<STGNode, STGEdge>,
|
||||||
index: HashMap<u64, NodeIndex>,
|
systemstate_index: HashMap<u64, ReducedFreeRTOSSystemState>,
|
||||||
|
stgnode_index: HashMap<u64, NodeIndex>,
|
||||||
entrypoint: NodeIndex,
|
entrypoint: NodeIndex,
|
||||||
exit: NodeIndex,
|
exit: NodeIndex,
|
||||||
// Metadata about aggregated traces. aggegated meaning, order has been removed
|
// Metadata about aggregated traces. aggegated meaning, order has been removed
|
||||||
@ -99,9 +124,11 @@ impl Default for STGFeedbackState {
|
|||||||
fn default() -> STGFeedbackState {
|
fn default() -> STGFeedbackState {
|
||||||
let mut graph = DiGraph::new();
|
let mut graph = DiGraph::new();
|
||||||
let mut entry = STGNode::default();
|
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();
|
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_entry = entry.calculate_hash();
|
||||||
let h_exit = exit.calculate_hash();
|
let h_exit = exit.calculate_hash();
|
||||||
@ -113,10 +140,11 @@ impl Default for STGFeedbackState {
|
|||||||
|
|
||||||
STGFeedbackState {
|
STGFeedbackState {
|
||||||
graph,
|
graph,
|
||||||
index,
|
stgnode_index: index,
|
||||||
entrypoint,
|
entrypoint,
|
||||||
exit,
|
exit,
|
||||||
worst_observed_per_aggegated_path: HashMap::new(),
|
worst_observed_per_aggegated_path: HashMap::new(),
|
||||||
|
systemstate_index,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -181,47 +209,103 @@ impl StgFeedback {
|
|||||||
/// newly discovered node?
|
/// newly discovered node?
|
||||||
/// side effect:
|
/// side effect:
|
||||||
/// the graph gets new nodes
|
/// 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_node_trace = vec![fbs.entrypoint];
|
||||||
let mut return_edge_trace = vec![];
|
let mut return_edge_trace = vec![];
|
||||||
let mut interesting = false;
|
let mut interesting = false;
|
||||||
// add all missing state+abb combinations to the graph
|
// add all missing state+abb combinations to the graph
|
||||||
for (i,state) in trace.iter().enumerate() { // Iterate states first, keep the trace order intact
|
for (i,interval) in trace.iter().enumerate() { // Iterate intervals
|
||||||
if let Some(marker) = map.iter().filter(|(_,_,index,_)| index==&i).next() { //
|
let node = STGNode {base: table[&interval.start_state].clone(), abb: interval.abb.as_ref().unwrap().clone()};
|
||||||
let node = STGNode {base: state.clone(), abb: (*marker.1).clone()};
|
let h_node = node.calculate_hash();
|
||||||
let h_node = node.calculate_hash();
|
let next_idx = if let Some(idx) = fbs.stgnode_index.get(&h_node) {
|
||||||
let next_idx = if let Some(idx) = fbs.index.get(&h_node) {
|
// alredy present
|
||||||
// alredy present
|
*idx
|
||||||
*idx
|
} else {
|
||||||
} else {
|
// not present
|
||||||
// not present
|
let idx = fbs.graph.add_node(node);
|
||||||
let idx = fbs.graph.add_node(node);
|
fbs.stgnode_index.insert(h_node, idx);
|
||||||
fbs.index.insert(h_node, idx);
|
interesting |= INTEREST_NODE;
|
||||||
interesting |= INTEREST_NODE;
|
idx
|
||||||
idx
|
};
|
||||||
};
|
// connect in graph if edge not present
|
||||||
// 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);
|
||||||
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 {
|
||||||
if let Some(e_) = e {
|
return_edge_trace.push(petgraph::visit::EdgeRef::id(&e_));
|
||||||
return_edge_trace.push(petgraph::visit::EdgeRef::id(&e_));
|
} else {
|
||||||
} else {
|
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()});
|
||||||
let e_ = fbs.graph.add_edge(return_node_trace[return_node_trace.len()-1], next_idx, ());
|
return_edge_trace.push(e_);
|
||||||
return_edge_trace.push(e_);
|
interesting |= INTEREST_EDGE;
|
||||||
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
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
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
|
// 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.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_);
|
return_edge_trace.push(e_);
|
||||||
interesting |= INTEREST_EDGE;
|
interesting |= INTEREST_EDGE;
|
||||||
}
|
}
|
||||||
@ -265,31 +349,33 @@ where
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let (abbs, ordered) = trace_to_state_abb(&observer.last_run);
|
let (_trace, _, mut interesting) = StgFeedback::update_stg_interval(&observer.last_trace, &observer.last_states, feedbackstate);
|
||||||
// println!("{:?}",abbs);
|
// let (abbs, ordered) = trace_to_state_abb(&observer.last_run);
|
||||||
let (_trace, _, mut interesting) = StgFeedback::update_stg(&observer.last_run, abbs, feedbackstate);
|
// // println!("{:?}",abbs);
|
||||||
if INTEREST_AGGREGATE {
|
// let (_trace, _, mut interesting) = StgFeedback::update_stg(&observer.last_run, abbs, feedbackstate);
|
||||||
let (it1, _it2) : (Vec<_>, Vec<_>) = ordered.into_iter().unzip();
|
// if INTEREST_AGGREGATE {
|
||||||
// aggegation by sorting, order of states is not relevant
|
// let (it1, _it2) : (Vec<_>, Vec<_>) = ordered.into_iter().unzip();
|
||||||
let mut tmp : Vec<_> = it1;
|
// // aggegation by sorting, order of states is not relevant
|
||||||
tmp.sort();
|
// let mut tmp : Vec<_> = it1;
|
||||||
if let Some(x) = feedbackstate.worst_observed_per_aggegated_path.get_mut(&tmp) {
|
// tmp.sort();
|
||||||
let t = clock_observer.last_runtime();
|
// if let Some(x) = feedbackstate.worst_observed_per_aggegated_path.get_mut(&tmp) {
|
||||||
if t > *x {
|
// let t = clock_observer.last_runtime();
|
||||||
*x = t;
|
// if t > *x {
|
||||||
interesting |= true;
|
// *x = t;
|
||||||
}
|
// interesting |= INTEREST_AGGREGATE;
|
||||||
} else {
|
// }
|
||||||
feedbackstate.worst_observed_per_aggegated_path.insert(tmp, clock_observer.last_runtime());
|
// } else {
|
||||||
interesting |= true;
|
// 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");
|
||||||
|
|
||||||
|
// Ok(interesting)
|
||||||
Ok(interesting)
|
Ok(interesting)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user