From 6774a778c3ab6875181815d3a7560f4243fc1533 Mon Sep 17 00:00:00 2001 From: Alwin Berger Date: Tue, 23 Apr 2024 16:53:55 +0200 Subject: [PATCH] add wip stg tracer --- fuzzers/FRET/fuzzer.sh | 25 ---- fuzzers/FRET/src/fuzzer.rs | 33 ++--- fuzzers/FRET/src/mutational.rs | 8 +- fuzzers/FRET/src/systemstate/helpers.rs | 38 ------ fuzzers/FRET/src/systemstate/mod.rs | 110 +++++++++++++--- fuzzers/FRET/src/systemstate/stg.rs | 160 ++++++++++++++++++++++++ 6 files changed, 267 insertions(+), 107 deletions(-) delete mode 100755 fuzzers/FRET/fuzzer.sh create mode 100644 fuzzers/FRET/src/systemstate/stg.rs diff --git a/fuzzers/FRET/fuzzer.sh b/fuzzers/FRET/fuzzer.sh deleted file mode 100755 index 968a149f13..0000000000 --- a/fuzzers/FRET/fuzzer.sh +++ /dev/null @@ -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 \ No newline at end of file diff --git a/fuzzers/FRET/src/fuzzer.rs b/fuzzers/FRET/src/fuzzer.rs index d665a3afa0..6a2802e10f 100644 --- a/fuzzers/FRET/src/fuzzer.rs +++ b/fuzzers/FRET/src/fuzzer.rs @@ -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 = 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 = 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)> = 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)> = 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)); diff --git a/fuzzers/FRET/src/mutational.rs b/fuzzers/FRET/src/mutational.rs index 1be5f1019a..79910106da 100644 --- a/fuzzers/FRET/src/mutational.rs +++ b/fuzzers/FRET/src/mutational.rs @@ -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 { +pub struct InterruptShiftStage { #[allow(clippy::type_complexity)] phantom: PhantomData<(E, EM, Z)>, } -impl MyStateStage +impl InterruptShiftStage where E: UsesState, EM: UsesState, @@ -43,7 +43,7 @@ where } } -impl Stage for MyStateStage +impl Stage for InterruptShiftStage where E: UsesState, EM: UsesState, @@ -233,7 +233,7 @@ where } } -impl UsesState for MyStateStage +impl UsesState for InterruptShiftStage where E: UsesState, EM: UsesState, diff --git a/fuzzers/FRET/src/systemstate/helpers.rs b/fuzzers/FRET/src/systemstate/helpers.rs index 123643a075..4d440fee87 100644 --- a/fuzzers/FRET/src/systemstate/helpers.rs +++ b/fuzzers/FRET/src/systemstate/helpers.rs @@ -39,40 +39,6 @@ pub static mut NEXT_INPUT : Vec = 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); - } } } diff --git a/fuzzers/FRET/src/systemstate/mod.rs b/fuzzers/FRET/src/systemstate/mod.rs index 509a3258f2..d08f6ded2c 100644 --- a/fuzzers/FRET/src/systemstate/mod.rs +++ b/fuzzers/FRET/src/systemstate/mod.rs @@ -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) -> HashSet { ret } -fn extract_abbs_from_trace(trace: &Vec) -> HashMap> { - let mut abbs_of_task : HashMap> = HashMap::new(); +fn extract_abbs_from_trace(trace: &Vec) -> HashMap>> { + let mut abbs_of_task : HashMap>> = HashMap::new(); let mut last_abb_of_task : HashMap = 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) -> HashMap(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::(); + 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) -> HashMap { 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) -> HashMap) -> HashMap) -> HashMap { 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) -> HashMap) -> HashMap) -> HashMap) -> Vec<(String, Rc, usize, u64)> { + let mut has_started : HashSet = HashSet::new(); + let mut abb_begin_end : HashMap = HashMap::new(); + let mut last_abb_of_task : HashMap = 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); \ No newline at end of file diff --git a/fuzzers/FRET/src/systemstate/stg.rs b/fuzzers/FRET/src/systemstate/stg.rs new file mode 100644 index 0000000000..8ee07679e4 --- /dev/null +++ b/fuzzers/FRET/src/systemstate/stg.rs @@ -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>, +} +impl StgFeedback { + pub fn new() -> Self { + Self {name: String::from("SysMapFeedback"), last_trace: None } + } + fn trace_to_stg(trace: &Vec, map: Vec<(String, Rc, usize, u64)>) -> DiGraph{ + 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 Feedback for StgFeedback +where + S: State + UsesInput + MaybeHasClientPerfMonitor + HasNamedMetadata, + S::Input: HasTargetBytes, +{ + #[allow(clippy::wrong_self_convention)] + fn is_interesting( + &mut self, + state: &mut S, + _manager: &mut EM, + _input: &S::Input, + observers: &OT, + _exit_kind: &ExitKind, + ) -> Result + where + EM: EventFirer, + OT: ObserversTuple, + { + let observer = observers.match_name::("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(&mut self, _state: &mut S, _observers: &OT, testcase: &mut Testcase) -> 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 + } +} \ No newline at end of file