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 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));
|
||||||
|
|
||||||
|
@ -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>,
|
||||||
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
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