add wip stg tracer
This commit is contained in:
parent
f26582ed75
commit
6774a778c3
@ -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
|
@ -37,7 +37,7 @@ use libafl_qemu::{
|
||||
};
|
||||
use rand::{SeedableRng, StdRng, Rng};
|
||||
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 clap::{Parser, Subcommand};
|
||||
@ -423,30 +423,6 @@ pub fn fuzz() {
|
||||
let api_ranges : Vec<_> = api_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 ================================================================================
|
||||
|
||||
let mut run_client = |state: Option<_>, mut mgr, _core_id| {
|
||||
@ -584,6 +560,11 @@ pub fn fuzz() {
|
||||
feedback,
|
||||
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")]
|
||||
let mut feedback = feedback_or!(
|
||||
feedback,
|
||||
@ -671,7 +652,7 @@ pub fn fuzz() {
|
||||
// let mut stages = tuple_list!(StdMutationalStage::new(mutator));
|
||||
// #[cfg(all(feature = "feed_systemtrace", 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"))]
|
||||
let mut stages = tuple_list!(StdMutationalStage::new(mutator));
|
||||
|
||||
|
@ -26,12 +26,12 @@ pub const MINIMUM_INTER_ARRIVAL_TIME : u32 = 700 * 1000 * (1 << 4);
|
||||
|
||||
/// The default mutational stage
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct MyStateStage<E, EM, Z> {
|
||||
pub struct InterruptShiftStage<E, EM, Z> {
|
||||
#[allow(clippy::type_complexity)]
|
||||
phantom: PhantomData<(E, EM, Z)>,
|
||||
}
|
||||
|
||||
impl<E, EM, Z> MyStateStage<E, EM, Z>
|
||||
impl<E, EM, Z> InterruptShiftStage<E, EM, Z>
|
||||
where
|
||||
E: 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
|
||||
E: 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
|
||||
E: UsesState<State = Z::State>,
|
||||
EM: UsesState<State = Z::State>,
|
||||
|
@ -39,40 +39,6 @@ pub static mut NEXT_INPUT : Vec<u8> = Vec::new();
|
||||
|
||||
//============================= 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] = &[
|
||||
// ISRs
|
||||
"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);
|
||||
}
|
||||
unsafe {
|
||||
let abbs = extract_abbs_from_trace(&CURRENT_SYSTEMSTATE_VEC);
|
||||
//println!("{:?}", abbs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9,6 +9,7 @@ use std::hash::Hasher;
|
||||
use std::hash::Hash;
|
||||
use hashbrown::HashMap;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::rc::Rc;
|
||||
|
||||
use freertos::TCB_t;
|
||||
|
||||
@ -18,6 +19,7 @@ pub mod observers;
|
||||
pub mod feedbacks;
|
||||
pub mod graph;
|
||||
pub mod schedulers;
|
||||
pub mod stg;
|
||||
|
||||
// #[cfg(feature = "fuzz_interrupt")]
|
||||
// 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 {
|
||||
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 {
|
||||
@ -219,7 +221,7 @@ impl fmt::Debug for AtomicBasicBlock {
|
||||
for end in &self.ends {
|
||||
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
|
||||
}
|
||||
|
||||
fn extract_abbs_from_trace(trace: &Vec<RawFreeRTOSSystemState>) -> HashMap<String,Vec<AtomicBasicBlock>> {
|
||||
let mut abbs_of_task : HashMap<String, Vec<AtomicBasicBlock>> = HashMap::new();
|
||||
fn extract_abbs_from_trace(trace: &Vec<RefinedFreeRTOSSystemState>) -> HashMap<String,Vec<Rc<AtomicBasicBlock>>> {
|
||||
let mut abbs_of_task : HashMap<String, Vec<Rc<AtomicBasicBlock>>> = HashMap::new();
|
||||
let mut last_abb_of_task : HashMap<String, usize> = HashMap::new();
|
||||
// iterate over all states and extract atomic basic blocks
|
||||
// an atomic base block has a single entry and multiple exits
|
||||
@ -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
|
||||
// so the next APIStart with the same current_tcb.pcTaskName is the end of the atomic block
|
||||
for i in 0..trace.len() {
|
||||
let tmp = unsafe { std::mem::transmute::<[i8; 10],[u8; 10]>(trace[i].current_tcb.pcTaskName) };
|
||||
let curr_name : String = std::str::from_utf8(&tmp).expect("TCB name was not utf8").chars().filter(|x| *x != '\0').collect::<String>();
|
||||
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 => {
|
||||
@ -255,12 +256,12 @@ fn extract_abbs_from_trace(trace: &Vec<RawFreeRTOSSystemState>) -> HashMap<Strin
|
||||
Some(v) => {
|
||||
match v.iter_mut().find(|x| x.start==start) {
|
||||
Some(abb) => {
|
||||
abb.ends.insert(end);
|
||||
Rc::get_mut(abb).unwrap().ends.insert(end);
|
||||
}
|
||||
None => {
|
||||
let mut t = HashSet::new();
|
||||
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 t = HashSet::new();
|
||||
t.insert(end);
|
||||
v.push(AtomicBasicBlock {start, ends: t});
|
||||
v.push(Rc::new(AtomicBasicBlock {start, ends: t}));
|
||||
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 end = trace[i].edge.0.unwrap();
|
||||
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);
|
||||
}
|
||||
},
|
||||
@ -304,12 +305,12 @@ fn extract_abbs_from_trace(trace: &Vec<RawFreeRTOSSystemState>) -> HashMap<Strin
|
||||
Some(v) => {
|
||||
match v.iter_mut().find(|x| x.start==start) {
|
||||
Some(abb) => {
|
||||
abb.ends.insert(end);
|
||||
Rc::get_mut(abb).unwrap().ends.insert(end);
|
||||
}
|
||||
None => {
|
||||
let mut t = HashSet::new();
|
||||
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 t = HashSet::new();
|
||||
t.insert(end);
|
||||
v.push(AtomicBasicBlock {start, ends: t});
|
||||
v.push(Rc::new(AtomicBasicBlock {start, ends: t}));
|
||||
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 end = trace[i].edge.0.unwrap();
|
||||
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);
|
||||
}
|
||||
},
|
||||
@ -338,4 +339,85 @@ fn extract_abbs_from_trace(trace: &Vec<RawFreeRTOSSystemState>) -> HashMap<Strin
|
||||
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);
|
160
fuzzers/FRET/src/systemstate/stg.rs
Normal file
160
fuzzers/FRET/src/systemstate/stg.rs
Normal 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
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user