add wip stg tracer

This commit is contained in:
Alwin Berger 2024-04-23 16:53:55 +02:00
parent f26582ed75
commit 6774a778c3
6 changed files with 267 additions and 107 deletions

View File

@ -1,25 +0,0 @@
#!/usr/bin/env bash
parent_path=$( cd "$(dirname "${BASH_SOURCE[0]}")" ; pwd -P )
cd "$parent_path"
[ -n "$1" -a "$1" != "+" -a -z "$KERNEL" ] && export KERNEL="$1"
[ -n "$2" -a "$2" != "+" -a -z "$FUZZ_MAIN" ] && export FUZZ_MAIN="$2"
[ -n "$3" -a "$3" != "+" -a -z "$FUZZ_INPUT" ] && export FUZZ_INPUT="$3"
[ -n "$4" -a "$4" != "+" -a -z "$FUZZ_INPUT_LEN" ] && export FUZZ_INPUT_LEN="$4"
[ -n "$5" -a "$5" != "+" -a -z "$BREAKPOINT" ] && export BREAKPOINT="$5"
[ -n "$6" -a "$6" != "+" -a -z "$FUZZ_ITERS" ] && export FUZZ_ITERS="$6"
[ -n "$7" -a "$7" != "+" -a -z "$TIME_DUMP" ] && export TIME_DUMP="$7"
[ -n "$8" -a "$8" != "+" -a -z "$CASE_DUMP" ] && export CASE_DUMP="$8"
[ -n "$9" -a "$9" != "+" -a -z "$DO_SHOWMAP" ] && export DO_SHOWMAP="$9"
[ -n "${10}" -a "${10}" != "+" -a -z "$SHOWMAP_TEXTINPUT" ] && export SHOWMAP_TEXTINPUT="${10}"
[ -n "${11}" -a "${11}" != "+" -a -z "$TRACE_DUMP" ] && export TRACE_DUMP="${11}"
[ -z "$FUZZER" ] && export FUZZER=target/debug/fret
set +e
$FUZZER -icount shift=4,align=off,sleep=off -machine mps2-an385 -monitor null -kernel $KERNEL -serial null -nographic -S -semihosting --semihosting-config enable=on,target=native -snapshot -drive if=none,format=qcow2,file=dummy.qcow2
if [ "$exitcode" = "101" ]
then
exit 101
else
exit 0
fi

View File

@ -37,7 +37,7 @@ use libafl_qemu::{
}; };
use rand::{SeedableRng, StdRng, Rng}; use rand::{SeedableRng, StdRng, Rng};
use crate::{ use crate::{
clock::{ClockTimeFeedback, IcHist, QemuClockIncreaseFeedback, QemuClockObserver, FUZZ_START_TIMESTAMP}, mutational::{MyStateStage, MINIMUM_INTER_ARRIVAL_TIME}, qemustate::QemuStateRestoreHelper, systemstate::{self, feedbacks::{DumpSystraceFeedback, NovelSystemStateFeedback}, graph::{GraphMaximizerCorpusScheduler, SysGraphFeedbackState, SysMapFeedback}, helpers::QemuSystemStateHelper, observers::QemuSystemStateObserver, schedulers::{GenerationScheduler, LongestTraceScheduler}}, worst::{AlwaysTrueFeedback, ExecTimeIncFeedback, TimeMaximizerCorpusScheduler, TimeStateMaximizerCorpusScheduler} clock::{ClockTimeFeedback, IcHist, QemuClockIncreaseFeedback, QemuClockObserver, FUZZ_START_TIMESTAMP}, mutational::{InterruptShiftStage, MINIMUM_INTER_ARRIVAL_TIME}, qemustate::QemuStateRestoreHelper, systemstate::{self, feedbacks::{DumpSystraceFeedback, NovelSystemStateFeedback}, graph::{GraphMaximizerCorpusScheduler, SysGraphFeedbackState, SysMapFeedback}, helpers::QemuSystemStateHelper, observers::QemuSystemStateObserver, schedulers::{GenerationScheduler, LongestTraceScheduler}, stg::StgFeedback}, worst::{AlwaysTrueFeedback, ExecTimeIncFeedback, TimeMaximizerCorpusScheduler, TimeStateMaximizerCorpusScheduler}
}; };
use std::time::{SystemTime, UNIX_EPOCH}; use std::time::{SystemTime, UNIX_EPOCH};
use clap::{Parser, Subcommand}; use clap::{Parser, Subcommand};
@ -423,30 +423,6 @@ pub fn fuzz() {
let api_ranges : Vec<_> = api_ranges.into_iter().collect(); let api_ranges : Vec<_> = api_ranges.into_iter().collect();
let isr_ranges : Vec<_> = isr_ranges.into_iter().collect(); let isr_ranges : Vec<_> = isr_ranges.into_iter().collect();
// println!("all: {}, api: {}, isr: {}", api_ranges.len(), systemstate::helpers::API_SYMBOLS.len(), systemstate::helpers::ISR_SYMBOLS.len());
// #[cfg(feature = "systemstate")]
// let mut api_addreses : HashMap<GuestAddr,&'static str> = HashMap::new();
// #[cfg(feature = "systemstate")]
// for s in systemstate::helpers::API_SYMBOLS {
// if let Some(sb) = try_load_symbol(&elf, &s, false) {
// api_addreses.insert(sb,s);
// }
// }
// #[cfg(feature = "systemstate")]
// let mut isr_addreses : HashMap<GuestAddr,&'static str> = HashMap::new();
// #[cfg(feature = "systemstate")]
// for s in systemstate::helpers::ISR_SYMBOLS {
// if let Some(sb) = try_load_symbol(&elf, &s, false) {
// isr_addreses.insert(sb & !1,s);
// }
// }
// #[cfg(feature = "systemstate")]
// let mut api_ranges : Vec<(&'static str,std::ops::Range<GuestAddr>)> = systemstate::helpers::API_SYMBOLS.iter().filter_map(|x| get_function_range(&elf, x).map(|y| (*x,y))).collect();
// #[cfg(feature = "systemstate")]
// let mut isr_ranges : Vec<(&'static str,std::ops::Range<GuestAddr>)> = systemstate::helpers::ISR_SYMBOLS.iter().filter_map(|x| get_function_range(&elf, x).map(|y| (*x,y))).collect();
// Client setup ================================================================================ // Client setup ================================================================================
let mut run_client = |state: Option<_>, mut mgr, _core_id| { let mut run_client = |state: Option<_>, mut mgr, _core_id| {
@ -584,6 +560,11 @@ pub fn fuzz() {
feedback, feedback,
DumpSystraceFeedback::with_dump(if cli.dump_traces {cli.dump_name.clone().map(|x| x.with_extension("trace.ron"))} else {None}) DumpSystraceFeedback::with_dump(if cli.dump_traces {cli.dump_name.clone().map(|x| x.with_extension("trace.ron"))} else {None})
); );
#[cfg(feature = "systemstate")]
let mut feedback = feedback_or!(
feedback,
StgFeedback::default()
);
#[cfg(feature = "feed_systemtrace")] #[cfg(feature = "feed_systemtrace")]
let mut feedback = feedback_or!( let mut feedback = feedback_or!(
feedback, feedback,
@ -671,7 +652,7 @@ pub fn fuzz() {
// let mut stages = tuple_list!(StdMutationalStage::new(mutator)); // let mut stages = tuple_list!(StdMutationalStage::new(mutator));
// #[cfg(all(feature = "feed_systemtrace", feature = "fuzz_int"))] // #[cfg(all(feature = "feed_systemtrace", feature = "fuzz_int"))]
#[cfg(feature = "fuzz_int")] #[cfg(feature = "fuzz_int")]
let mut stages = tuple_list!(StdMutationalStage::new(mutator),MyStateStage::new()); let mut stages = tuple_list!(StdMutationalStage::new(mutator),InterruptShiftStage::new());
#[cfg(not(feature = "fuzz_int"))] #[cfg(not(feature = "fuzz_int"))]
let mut stages = tuple_list!(StdMutationalStage::new(mutator)); let mut stages = tuple_list!(StdMutationalStage::new(mutator));

View File

@ -26,12 +26,12 @@ pub const MINIMUM_INTER_ARRIVAL_TIME : u32 = 700 * 1000 * (1 << 4);
/// The default mutational stage /// The default mutational stage
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default)]
pub struct MyStateStage<E, EM, Z> { pub struct InterruptShiftStage<E, EM, Z> {
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
phantom: PhantomData<(E, EM, Z)>, phantom: PhantomData<(E, EM, Z)>,
} }
impl<E, EM, Z> MyStateStage<E, EM, Z> impl<E, EM, Z> InterruptShiftStage<E, EM, Z>
where where
E: UsesState<State = Z::State>, E: UsesState<State = Z::State>,
EM: UsesState<State = Z::State>, EM: UsesState<State = Z::State>,
@ -43,7 +43,7 @@ where
} }
} }
impl<E, EM, Z> Stage<E, EM, Z> for MyStateStage<E, EM, Z> impl<E, EM, Z> Stage<E, EM, Z> for InterruptShiftStage<E, EM, Z>
where where
E: UsesState<State = Z::State>, E: UsesState<State = Z::State>,
EM: UsesState<State = Z::State>, EM: UsesState<State = Z::State>,
@ -233,7 +233,7 @@ where
} }
} }
impl<E, EM, Z> UsesState for MyStateStage<E, EM, Z> impl<E, EM, Z> UsesState for InterruptShiftStage<E, EM, Z>
where where
E: UsesState<State = Z::State>, E: UsesState<State = Z::State>,
EM: UsesState<State = Z::State>, EM: UsesState<State = Z::State>,

View File

@ -39,40 +39,6 @@ pub static mut NEXT_INPUT : Vec<u8> = Vec::new();
//============================= API symbols //============================= API symbols
pub const API_SYMBOLS : &'static [&'static str] = &[
// Task Creation
"xTaskCreate", "xTaskCreateStatic", "vTaskDelete", "xTaskGetStaticBuffers",
// Task Control
"vTaskDelay","vTaskDelayUntil","xTaskDelayUntil", "uxTaskPriorityGet", "uxTaskPriorityGetFromISR", "uxTaskBasePriorityGet","uxTaskBasePriorityGetFromISR", "vTaskPrioritySet","vTaskSuspend","vTaskResume","xTaskResumeFromISR","xTaskAbortDelay",
// Task Utilities
"uxTaskGetSystemState","vTaskGetInfo","xTaskGetCurrentTaskHandle","xTaskGetIdleTaskHandle","uxTaskGetStackHighWaterMark","eTaskGetState","pcTaskGetName","xTaskGetHandle","xTaskGetTickCount","xTaskGetTickCountFromISR","xTaskGetSchedulerState","uxTaskGetNumberOfTasks","vTaskList","vTaskListTasks","vTaskStartTrace","ulTaskEndTrace","vTaskGetRunTimeStats","vTaskGetRunTimeStatistics","vTaskGetIdleRunTimeCounter","ulTaskGetRunTimeCounter","ulTaskGetRunTimePercent","ulTaskGetIdleRunTimeCounter","ulTaskGetIdleRunTimePercent","vTaskSetApplicationTaskTag","xTaskGetApplicationTaskTag","xTaskCallApplicationTaskHook","pvTaskGetThreadLocalStoragePointer","vTaskSetThreadLocalStoragePointer","vTaskSetTimeOutState","xTaskCheckForTimeOut",
// RTOS Kernel Control
"taskYIELD","taskENTER_CRITICAL","taskEXIT_CRITICAL","taskENTER_CRITICAL_FROM_ISR","taskEXIT_CRITICAL_FROM_ISR","taskDISABLE_INTERRUPTS","taskENABLE_INTERRUPTS","vTaskStartScheduler","vTaskEndScheduler","vTaskSuspendAll","xTaskResumeAll","vTaskStepTick",
// Direct To Task Notifications
"xTaskNotifyGive","xTaskNotifyGiveIndexed","vTaskNotifyGiveFromISR","vTaskNotifyGiveIndexedFromISR","ulTaskNotifyTake","ulTaskNotifyTakeIndexed","xTaskNotify","xTaskNotifyIndexed","xTaskNotifyAndQuery","xTaskNotifyAndQueryIndexed","xTaskNotifyAndQueryFromISR","xTaskNotifyAndQueryFromISRIndexed","xTaskNotifyFromISR","xTaskNotifyFromISRIndexed","xTaskNotifyWait","xTaskNotifyWaitIndexed","xTaskNotifyStateClear","xTaskNotifyStateClearIndexed","ulTasknotifyValueClear","ulTasknotifyValueClearIndexed",
// Queues
"xQueueCreate","xQueueCreateStatic","vQueueDelete","xQueueSend","xQueueSendFromISR","xQueueSendToBack","xQueueSendToBackFromISR","xQueueSendToFront","xQueueSendToFrontFromISR","xQueueReceive","xQueueReceiveFromISR","uxQueueMessagesWaiting","uxQueueMessagesWaitingFromISR","uxQueueSpacesAvailable","xQueueReset","xQueuePeek","xQueuePeekFromISR","vQueueAddToRegistry","pcQueueGetName","vQueueUnregisterQueue","xQueueIsQueueEmptyFromISR","xQueueIsQueueFullFromISR","xQueueOverwrite","xQueueOverwriteFromISR","xQueueGetStaticBuffers",
// Queue Sets
"xQueueCreateSet","xQueueAddToSet","xQueueRemoveFromSet","xQueueSelectFromSet","xQueueSelectFromSetFromISR",
// Stream Buffers
"xStreamBufferCreate","xStreamBufferCreateStatic","xStreamBufferSend","xStreamBufferSendFromISR","xStreamBufferReceive","xStreamBufferReceiveFromISR","vStreamBufferDelete","xStreamBufferBytesAvailable","xStreamBufferSpacesAvailable","xStreamBufferSetTriggerLevel","xStreamBufferReset","xStreamBufferIsEmpty","xStreamBufferIsFull","xStreamBufferGetStaticBuffers",
// Message Buffers
"xMessageBufferCreate","xMessageBufferCreateStatic","xMessageBufferSend","xMessageBufferSendFromISR","xMessageBufferReceive","xMessageBufferReceiveFromISR","vMessageBufferDelete","xMessageBufferSpacesAvailable","xMessageBufferReset","xMessageBufferIsEmpty","xMessageBufferIsFull","xMessageBufferGetStaticBuffers",
// Semaphores
"xSemaphoreCreateBinary","xSemaphoreCreateBinaryStatic","vSemaphoreCreateBinary","xSemaphoreCreateCounting","xSemaphoreCreateCountingStatic","xSemaphoreCreateMutex","xSemaphoreCreateMutexStatic","xSemaphoreCreateRecursiveMutex","xSemaphoreCreateRecursiveMutexStatic","vSemaphoreDelete","xSemaphoreGetMutexHolder","xSemaphoreTake","xSemaphoreTakeFromISR","xSemaphoreTakeRecursive","xSemaphoreGive","xSemaphoreGiveRecursive","xSemaphoreGiveFromISR","uxSemaphoreGetCount","xSemaphoreGetStaticBuffer",
// Software Timers
"xTimerCreate","xTimerCreateStatic","xTimerIsTimerActive","pvTimerGetTimerID","pcTimerGetName","vTimerSetReloadMode","xTimerStart","xTimerStop","xTimerChangePeriod","xTimerDelete","xTimerReset","xTimerStartFromISR","xTimerStopFromISR","xTimerChangePeriodFromISR","xTimerResetFromISR","pvTimerGetTimerID","vTimerSetTimerID","xTimerGetTimerDaemonTaskHandle","xTimerPendFunctionCall","xTimerPendFunctionCallFromISR","pcTimerGetName","xTimerGetPeriod","xTimerGetExpiryTime","xTimerGetReloadMode",
// Event Groups
"vEventGroupDelete","xEventGroupClearBits","xEventGroupClearBitsFromISR","xEventGroupCreate","xEventGroupCreateStatic","xEventGroupGetBits","xEventGroupGetBitsFromISR","xEventGroupGetStaticBuffer","xEventGroupSetBits","xEventGroupSetBitsFromISR","xEventGroupSync","xEventGroupWaitBits",
// MPU Specific functions
"xTaskCreateRestricted","xTaskCreateRestrictedStatic","vTaskAllocateMPURegions","portSWITCH_TO_USER_MODE",
// Co-routines
"xCoRoutineCreate","crDELAY","crQUEUE_SEND","crQUEUE_RECEIVE","crQUEUE_SEND_FROM_ISR","crQUEUE_RECEIVE_FROM_ISR","vCoRoutineSchedule",
// Custom resolved macros
"vPortEnterCritical","vPortExitCritical","xTaskGenericNotify","xTaskGenericNotifyFromISR","xQueueGenericSend","xQueueGenericReset","ulTaskGenericNotifyTake","xTimerCreateTimerTask",
"pvPortMalloc","prvAddNewTaskToReadyList","prvUnlockQueue","prvCheckForValidListAndQueue","prvProcessTimerOrBlockTask","prvInitialiseNewQueue","prvSampleTimeNow"
];
pub const ISR_SYMBOLS : &'static [&'static str] = &[ pub const ISR_SYMBOLS : &'static [&'static str] = &[
// ISRs // ISRs
"Reset_Handler","Default_Handler","Default_Handler2","Default_Handler3","Default_Handler4","Default_Handler5","Default_Handler6","vPortSVCHandler","xPortPendSVHandler","xPortSysTickHandler","isr_starter" "Reset_Handler","Default_Handler","Default_Handler2","Default_Handler3","Default_Handler4","Default_Handler5","Default_Handler6","vPortSVCHandler","xPortPendSVHandler","xPortSysTickHandler","isr_starter"
@ -178,10 +144,6 @@ where
} }
CURRENT_SYSTEMSTATE_VEC.drain(..index); CURRENT_SYSTEMSTATE_VEC.drain(..index);
} }
unsafe {
let abbs = extract_abbs_from_trace(&CURRENT_SYSTEMSTATE_VEC);
//println!("{:?}", abbs);
}
} }
} }

View File

@ -9,6 +9,7 @@ use std::hash::Hasher;
use std::hash::Hash; use std::hash::Hash;
use hashbrown::HashMap; use hashbrown::HashMap;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::rc::Rc;
use freertos::TCB_t; use freertos::TCB_t;
@ -18,6 +19,7 @@ pub mod observers;
pub mod feedbacks; pub mod feedbacks;
pub mod graph; pub mod graph;
pub mod schedulers; pub mod schedulers;
pub mod stg;
// #[cfg(feature = "fuzz_interrupt")] // #[cfg(feature = "fuzz_interrupt")]
// pub const IRQ_INPUT_BYTES_NUMBER : u32 = 2; // Offset for interrupt bytes // pub const IRQ_INPUT_BYTES_NUMBER : u32 = 2; // Offset for interrupt bytes
@ -210,7 +212,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, "AtomicBasicBlock {{ start: 0x{:#x}, ends: [{}]}}", self.start, ends_str.trim().trim_matches(',')) write!(f, "ABB {{ start: 0x{:#x}, ends: [{}]}}", self.start, ends_str.trim().trim_matches(','))
} }
} }
impl fmt::Debug for AtomicBasicBlock { impl fmt::Debug for AtomicBasicBlock {
@ -219,7 +221,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, "AtomicBasicBlock {{ start: {:#x}, ends: [{}]}}", self.start, ends_str.trim().trim_matches(',')) write!(f, "ABB {{ start: {:#x}, ends: [{}]}}", self.start, ends_str.trim().trim_matches(','))
} }
} }
@ -233,8 +235,8 @@ fn get_task_names(trace: &Vec<RefinedFreeRTOSSystemState>) -> HashSet<String> {
ret ret
} }
fn extract_abbs_from_trace(trace: &Vec<RawFreeRTOSSystemState>) -> HashMap<String,Vec<AtomicBasicBlock>> { fn extract_abbs_from_trace(trace: &Vec<RefinedFreeRTOSSystemState>) -> HashMap<String,Vec<Rc<AtomicBasicBlock>>> {
let mut abbs_of_task : HashMap<String, Vec<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
@ -242,8 +244,7 @@ fn extract_abbs_from_trace(trace: &Vec<RawFreeRTOSSystemState>) -> HashMap<Strin
// 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 tmp = unsafe { std::mem::transmute::<[i8; 10],[u8; 10]>(trace[i].current_tcb.pcTaskName) }; let curr_name = trace[i].current_task.0.task_name.clone();
let curr_name : String = std::str::from_utf8(&tmp).expect("TCB name was not utf8").chars().filter(|x| *x != '\0').collect::<String>();
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 => {
@ -255,12 +256,12 @@ fn extract_abbs_from_trace(trace: &Vec<RawFreeRTOSSystemState>) -> HashMap<Strin
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) => {
abb.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(AtomicBasicBlock {start, ends: t}); v.push(Rc::new(AtomicBasicBlock {start, ends: t}));
} }
}; };
}, },
@ -268,7 +269,7 @@ fn extract_abbs_from_trace(trace: &Vec<RawFreeRTOSSystemState>) -> HashMap<Strin
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(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);
} }
} }
@ -278,7 +279,7 @@ fn extract_abbs_from_trace(trace: &Vec<RawFreeRTOSSystemState>) -> HashMap<Strin
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(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);
} }
}, },
@ -304,12 +305,12 @@ fn extract_abbs_from_trace(trace: &Vec<RawFreeRTOSSystemState>) -> HashMap<Strin
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) => {
abb.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(AtomicBasicBlock {start, ends: t}); v.push(Rc::new(AtomicBasicBlock {start, ends: t}));
} }
}; };
}, },
@ -317,7 +318,7 @@ fn extract_abbs_from_trace(trace: &Vec<RawFreeRTOSSystemState>) -> HashMap<Strin
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(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);
} }
} }
@ -327,7 +328,7 @@ fn extract_abbs_from_trace(trace: &Vec<RawFreeRTOSSystemState>) -> HashMap<Strin
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(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);
} }
}, },
@ -338,4 +339,85 @@ fn extract_abbs_from_trace(trace: &Vec<RawFreeRTOSSystemState>) -> HashMap<Strin
abbs_of_task abbs_of_task
} }
/// returns (name, abb, index, ticks)
fn trace_to_state_abb(trace: &Vec<RefinedFreeRTOSSystemState>) -> Vec<(String, Rc<AtomicBasicBlock>, usize, u64)> {
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
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));},
CaptureEvent::ISRStart => (),
CaptureEvent::ISREnd => {chunks.push((curr_name.clone(), abb.clone(), i, trace[i+1].end_tick-trace[i].end_tick));},
_ => panic!(),
}
}
}
}
chunks.sort_by_key(|x| x.2);
chunks
}
libafl_bolts::impl_serdeany!(AtomicBasicBlock); libafl_bolts::impl_serdeany!(AtomicBasicBlock);

View File

@ -0,0 +1,160 @@
use libafl::SerdeAny;
/// Feedbacks organizing SystemStates as a graph
use libafl::inputs::HasBytesVec;
use std::fs;
use libafl_bolts::rands::RandomSeed;
use libafl_bolts::rands::StdRand;
use libafl::mutators::Mutator;
use libafl::mutators::MutationResult;
use libafl::prelude::HasTargetBytes;
use libafl::prelude::UsesInput;
use libafl::state::HasNamedMetadata;
use libafl::state::UsesState;
use libafl::prelude::State;
use petgraph::dot::Config;
use petgraph::dot::Dot;
use core::marker::PhantomData;
use libafl::state::HasCorpus;
use libafl::state::HasSolutions;
use libafl::state::HasRand;
use crate::worst::MaxExecsLenFavFactor;
use crate::worst::MaxTimeFavFactor;
use libafl::schedulers::MinimizerScheduler;
use libafl_bolts::HasRefCnt;
use libafl_bolts::AsSlice;
use libafl_bolts::ownedref::OwnedSlice;
use libafl::inputs::BytesInput;
use std::path::PathBuf;
use crate::clock::QemuClockObserver;
use libafl::corpus::Testcase;
use libafl_bolts::tuples::MatchName;
use std::collections::hash_map::DefaultHasher;
use std::hash::Hasher;
use std::hash::Hash;
use libafl::events::EventFirer;
use libafl::state::MaybeHasClientPerfMonitor;
use libafl::feedbacks::Feedback;
use libafl_bolts::Named;
use libafl::Error;
use hashbrown::HashMap;
use libafl::{executors::ExitKind, inputs::Input, observers::ObserversTuple, state::HasMetadata};
use serde::{Deserialize, Serialize};
use super::feedbacks::SystemStateFeedbackState;
use super::trace_to_state_abb;
use super::AtomicBasicBlock;
use super::RefinedFreeRTOSSystemState;
use super::FreeRTOSSystemStateMetadata;
use super::observers::QemuSystemStateObserver;
use petgraph::prelude::DiGraph;
use petgraph::graph::NodeIndex;
use petgraph::Direction;
use std::cmp::Ordering;
use std::rc::Rc;
use libafl_bolts::rands::Rand;
//============================= Data Structures
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
pub struct STGNode
{
base: RefinedFreeRTOSSystemState,
abb: AtomicBasicBlock,
}
impl STGNode {
fn pretty_print(&self) -> String {
format!("{}\n{:x}-{:x}", self.base.current_task.0.task_name, self.abb.start, self.abb.ends.iter().next().unwrap_or_else(||&0))
}
}
impl PartialEq for STGNode {
fn eq(&self, other: &STGNode) -> bool {
self.base==other.base
}
}
//============================= Graph Feedback
/// A Feedback reporting novel System-State Transitions. Depends on [`QemuSystemStateObserver`]
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
pub struct StgFeedback
{
name: String,
last_trace: Option<Vec<NodeIndex>>,
}
impl StgFeedback {
pub fn new() -> Self {
Self {name: String::from("SysMapFeedback"), last_trace: None }
}
fn trace_to_stg(trace: &Vec<RefinedFreeRTOSSystemState>, map: Vec<(String, Rc<AtomicBasicBlock>, usize, u64)>) -> DiGraph<STGNode,()>{
let mut graph = DiGraph::new();
let mut entry = STGNode::default();
entry.base.current_task.0.task_name="Start".to_string();
let mut exit = STGNode::default();
exit.base.current_task.0.task_name="End".to_string();
let entry = graph.add_node(entry);
let exit = graph.add_node(exit);
let mut last = entry;
for (i,state) in trace.iter().enumerate() {
if let Some(marker) = map.iter().filter(|(_,_,index,_)| index==&i).next() {
graph.add_node(STGNode {base: state.clone(), abb: (*marker.1).clone()});
}
}
graph
}
}
impl<S> Feedback<S> for StgFeedback
where
S: State + UsesInput + MaybeHasClientPerfMonitor + HasNamedMetadata,
S::Input: HasTargetBytes,
{
#[allow(clippy::wrong_self_convention)]
fn is_interesting<EM, OT>(
&mut self,
state: &mut S,
_manager: &mut EM,
_input: &S::Input,
observers: &OT,
_exit_kind: &ExitKind,
) -> Result<bool, Error>
where
EM: EventFirer<State = S>,
OT: ObserversTuple<S>,
{
let observer = observers.match_name::<QemuSystemStateObserver>("systemstate")
.expect("QemuSystemStateObserver not found");
let abbs = trace_to_state_abb(&observer.last_run);
println!("{:?}",abbs);
let res =StgFeedback::trace_to_stg(&observer.last_run, abbs);
let out = res.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(false)
}
/// Append to the testcase the generated metadata in case of a new corpus item
#[inline]
fn append_metadata<OT>(&mut self, _state: &mut S, _observers: &OT, testcase: &mut Testcase<S::Input>) -> Result<(), Error> {
Ok(())
}
/// Discard the stored metadata in case that the testcase is not added to the corpus
#[inline]
fn discard_metadata(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> {
Ok(())
}
}
impl Named for StgFeedback
{
#[inline]
fn name(&self) -> &str {
&self.name
}
}