split system_state module, add tracedump
This commit is contained in:
parent
53bd755647
commit
f5bf5605f1
@ -1,11 +1,10 @@
|
|||||||
//! A singlethreaded QEMU fuzzer that can auto-restart.
|
//! A singlethreaded QEMU fuzzer that can auto-restart.
|
||||||
|
|
||||||
use libafl_qemu::QemuInstrumentationFilter;
|
use libafl_qemu::QemuInstrumentationFilter;
|
||||||
use wcet_qemu_sys::system_trace::QemuSystemStateHelper;
|
use wcet_qemu_sys::sysstate::helpers::QemuSystemStateHelper;
|
||||||
use wcet_qemu_sys::system_trace::QemuSysStateObserver;
|
use wcet_qemu_sys::sysstate::observers::QemuSysStateObserver;
|
||||||
use wcet_qemu_sys::system_trace::FreeRTOSSystemStateMetadata;
|
use wcet_qemu_sys::sysstate::feedbacks::SysStateFeedbackState;
|
||||||
use wcet_qemu_sys::system_trace::SysStateFeedbackState;
|
use wcet_qemu_sys::sysstate::feedbacks::NovelSysStateFeedback;
|
||||||
use wcet_qemu_sys::system_trace::NovelSysStateFeedback;
|
|
||||||
use wcet_qemu_sys::worst::QemuHashMapObserver;
|
use wcet_qemu_sys::worst::QemuHashMapObserver;
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
use clap::{App, Arg};
|
use clap::{App, Arg};
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
//! A singlethreaded QEMU fuzzer that can auto-restart.
|
//! A singlethreaded QEMU fuzzer that can auto-restart.
|
||||||
|
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
use wcet_qemu_sys::system_trace::QemuSysStateObserver;
|
use wcet_qemu_sys::sysstate::observers::QemuSysStateObserver;
|
||||||
|
use wcet_qemu_sys::sysstate::feedbacks::DumpSystraceFeedback;
|
||||||
use wcet_qemu_sys::worst::QemuHashMapObserver;
|
use wcet_qemu_sys::worst::QemuHashMapObserver;
|
||||||
use wcet_qemu_sys::{
|
use wcet_qemu_sys::{
|
||||||
worst::{DumpMapFeedback,DummyFeedback},
|
worst::{DumpMapFeedback,DummyFeedback},
|
||||||
system_trace::QemuSystemStateHelper,
|
sysstate::helpers::QemuSystemStateHelper,
|
||||||
};
|
};
|
||||||
use clap::{App, Arg};
|
use clap::{App, Arg};
|
||||||
use std::{
|
use std::{
|
||||||
@ -23,7 +24,7 @@ use libafl::{
|
|||||||
corpus::{Corpus,InMemoryCorpus,QueueCorpusScheduler},
|
corpus::{Corpus,InMemoryCorpus,QueueCorpusScheduler},
|
||||||
executors::{ExitKind},
|
executors::{ExitKind},
|
||||||
fuzzer::{StdFuzzer},
|
fuzzer::{StdFuzzer},
|
||||||
inputs::{Input,BytesInput, HasTargetBytes},
|
inputs::{BytesInput, HasTargetBytes},
|
||||||
observers::{VariableMapObserver},
|
observers::{VariableMapObserver},
|
||||||
state::{HasCorpus,StdState},
|
state::{HasCorpus,StdState},
|
||||||
Error,
|
Error,
|
||||||
@ -33,6 +34,7 @@ use libafl::{
|
|||||||
stages::StdMutationalStage,
|
stages::StdMutationalStage,
|
||||||
mutators::BitFlipMutator,
|
mutators::BitFlipMutator,
|
||||||
Fuzzer,
|
Fuzzer,
|
||||||
|
feedback_or,
|
||||||
};
|
};
|
||||||
use libafl_qemu::{
|
use libafl_qemu::{
|
||||||
edges,
|
edges,
|
||||||
@ -95,6 +97,11 @@ pub fn main() {
|
|||||||
.long("libafl-edges")
|
.long("libafl-edges")
|
||||||
.takes_value(true),
|
.takes_value(true),
|
||||||
)
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::new("traces")
|
||||||
|
.long("libafl-traces")
|
||||||
|
.takes_value(true),
|
||||||
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new("snapshot")
|
Arg::new("snapshot")
|
||||||
.help("The qcow2 file used for snapshots")
|
.help("The qcow2 file used for snapshots")
|
||||||
@ -165,9 +172,14 @@ pub fn main() {
|
|||||||
None => None
|
None => None
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let traces = match res.value_of("traces") {
|
||||||
|
Some(st) => Some(PathBuf::from(st.to_string())),
|
||||||
|
None => None
|
||||||
|
};
|
||||||
|
|
||||||
let snapshot = PathBuf::from(res.value_of("snapshot").unwrap().to_string());
|
let snapshot = PathBuf::from(res.value_of("snapshot").unwrap().to_string());
|
||||||
|
|
||||||
fuzz(seed, kernel, edges, snapshot)
|
fuzz(seed, kernel, edges, traces, snapshot)
|
||||||
.expect("An error occurred while fuzzing");
|
.expect("An error occurred while fuzzing");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -189,6 +201,7 @@ fn fuzz(
|
|||||||
seed: Either<Vec<u8>,PathBuf>,
|
seed: Either<Vec<u8>,PathBuf>,
|
||||||
kernel: PathBuf,
|
kernel: PathBuf,
|
||||||
dump_edges: Option<PathBuf>,
|
dump_edges: Option<PathBuf>,
|
||||||
|
dump_traces: Option<PathBuf>,
|
||||||
snapshot: PathBuf,
|
snapshot: PathBuf,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
//=========== Setup emulator
|
//=========== Setup emulator
|
||||||
@ -278,7 +291,7 @@ fn fuzz(
|
|||||||
let clock_observer = QemuClockObserver::default();
|
let clock_observer = QemuClockObserver::default();
|
||||||
|
|
||||||
//========= Feedback-Function evaluate the Maps. Need to dump it for debugging and check if it reaches targets.
|
//========= Feedback-Function evaluate the Maps. Need to dump it for debugging and check if it reaches targets.
|
||||||
let feedback = DumpMapFeedback::with_dump(dump_edges, &edges_observer);
|
let feedback = feedback_or!(DumpMapFeedback::with_dump(dump_edges, &edges_observer),DumpSystraceFeedback::with_dump(dump_traces));
|
||||||
|
|
||||||
// A feedback to choose if an input is a solution or not
|
// A feedback to choose if an input is a solution or not
|
||||||
let objective = DummyFeedback::new(false);
|
let objective = DummyFeedback::new(false);
|
||||||
@ -353,10 +366,9 @@ fn fuzz(
|
|||||||
});
|
});
|
||||||
println!("We imported {} inputs from disk.", state.corpus().count());
|
println!("We imported {} inputs from disk.", state.corpus().count());
|
||||||
}
|
}
|
||||||
fuzzer
|
// fuzzer
|
||||||
.fuzz_one(&mut tuple_list!(StdMutationalStage::new(BitFlipMutator::new())), &mut executor, &mut state, &mut mgr)
|
// .fuzz_one(&mut tuple_list!(StdMutationalStage::new(BitFlipMutator::new())), &mut executor, &mut state, &mut mgr)
|
||||||
.expect("Error in the fuzzing loop");
|
// .expect("Error in the fuzzing loop");
|
||||||
|
|
||||||
},
|
},
|
||||||
Left(s) => {
|
Left(s) => {
|
||||||
fuzzer.evaluate_input(&mut state, &mut executor, &mut mgr, BytesInput::new(s)).expect("Evaluation failed");
|
fuzzer.evaluate_input(&mut state, &mut executor, &mut mgr, BytesInput::new(s)).expect("Evaluation failed");
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#![feature(iter_advance_by)]
|
#![feature(iter_advance_by)]
|
||||||
#![feature(is_sorted)]
|
#![feature(is_sorted)]
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
pub mod worst;
|
pub mod sysstate;
|
||||||
pub mod freertos;
|
|
||||||
pub mod system_trace;
|
pub mod worst;
|
191
fuzzers/wcet_qemu_sys/src/sysstate/feedbacks.rs
Normal file
191
fuzzers/wcet_qemu_sys/src/sysstate/feedbacks.rs
Normal file
@ -0,0 +1,191 @@
|
|||||||
|
use std::path::PathBuf;
|
||||||
|
use libafl_qemu::QemuClockObserver;
|
||||||
|
use libafl::feedbacks::FeedbackState;
|
||||||
|
use libafl::corpus::Testcase;
|
||||||
|
use libafl::state::HasFeedbackStates;
|
||||||
|
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::HasClientPerfMonitor;
|
||||||
|
use libafl::feedbacks::Feedback;
|
||||||
|
use libafl::bolts::tuples::Named;
|
||||||
|
use libafl::Error;
|
||||||
|
use hashbrown::HashMap;
|
||||||
|
use libafl::{executors::ExitKind, inputs::Input, observers::ObserversTuple, state::HasMetadata};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use super::MiniFreeRTOSSystemState;
|
||||||
|
use super::FreeRTOSSystemStateMetadata;
|
||||||
|
use super::observers::QemuSysStateObserver;
|
||||||
|
|
||||||
|
//============================= Feedback
|
||||||
|
|
||||||
|
/// Shared Metadata for a SysStateFeedback
|
||||||
|
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
|
||||||
|
pub struct SysStateFeedbackState
|
||||||
|
{
|
||||||
|
known_traces: HashMap<u64,(u64,u64,usize)>, // encounters,ticks,length
|
||||||
|
longest: Vec<MiniFreeRTOSSystemState>,
|
||||||
|
}
|
||||||
|
impl Named for SysStateFeedbackState
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"sysstate"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl FeedbackState for SysStateFeedbackState
|
||||||
|
{
|
||||||
|
fn reset(&mut self) -> Result<(), Error> {
|
||||||
|
self.longest.clear();
|
||||||
|
self.known_traces.clear();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A Feedback reporting novel System-State Transitions. Depends on [`QemuSysStateObserver`]
|
||||||
|
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
|
||||||
|
pub struct NovelSysStateFeedback
|
||||||
|
{
|
||||||
|
last_trace: Option<Vec<MiniFreeRTOSSystemState>>,
|
||||||
|
// known_traces: HashMap<u64,(u64,usize)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I, S> Feedback<I, S> for NovelSysStateFeedback
|
||||||
|
where
|
||||||
|
I: Input,
|
||||||
|
S: HasClientPerfMonitor + HasFeedbackStates,
|
||||||
|
{
|
||||||
|
fn is_interesting<EM, OT>(
|
||||||
|
&mut self,
|
||||||
|
state: &mut S,
|
||||||
|
_manager: &mut EM,
|
||||||
|
_input: &I,
|
||||||
|
observers: &OT,
|
||||||
|
_exit_kind: &ExitKind,
|
||||||
|
) -> Result<bool, Error>
|
||||||
|
where
|
||||||
|
EM: EventFirer<I>,
|
||||||
|
OT: ObserversTuple<I, S>,
|
||||||
|
{
|
||||||
|
let observer = observers.match_name::<QemuSysStateObserver>("sysstate")
|
||||||
|
.expect("QemuSysStateObserver not found");
|
||||||
|
let clock_observer = observers.match_name::<QemuClockObserver>("clock") //TODO not fixed
|
||||||
|
.expect("QemuSysStateObserver not found");
|
||||||
|
let feedbackstate = state
|
||||||
|
.feedback_states_mut()
|
||||||
|
.match_name_mut::<SysStateFeedbackState>("sysstate")
|
||||||
|
.unwrap();
|
||||||
|
// Do Stuff
|
||||||
|
let mut hasher = DefaultHasher::new();
|
||||||
|
observer.last_run.hash(&mut hasher);
|
||||||
|
let somehash = hasher.finish();
|
||||||
|
let mut is_novel = false;
|
||||||
|
let mut takes_longer = false;
|
||||||
|
match feedbackstate.known_traces.get_mut(&somehash) {
|
||||||
|
None => {
|
||||||
|
is_novel = true;
|
||||||
|
feedbackstate.known_traces.insert(somehash,(1,clock_observer.last_runtime(),observer.last_run.len()));
|
||||||
|
}
|
||||||
|
Some(s) => {
|
||||||
|
s.0+=1;
|
||||||
|
if s.1 < clock_observer.last_runtime() {
|
||||||
|
s.1 = clock_observer.last_runtime();
|
||||||
|
takes_longer = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if observer.last_run.len() > feedbackstate.longest.len() {
|
||||||
|
feedbackstate.longest=observer.last_run.clone();
|
||||||
|
}
|
||||||
|
self.last_trace = Some(observer.last_run.clone());
|
||||||
|
// if (!is_novel) { println!("not novel") };
|
||||||
|
Ok(is_novel | takes_longer)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Append to the testcase the generated metadata in case of a new corpus item
|
||||||
|
#[inline]
|
||||||
|
fn append_metadata(&mut self, _state: &mut S, testcase: &mut Testcase<I>) -> Result<(), Error> {
|
||||||
|
let a = self.last_trace.take();
|
||||||
|
match a {
|
||||||
|
Some(s) => testcase.metadata_mut().insert(FreeRTOSSystemStateMetadata::new(s)),
|
||||||
|
None => (),
|
||||||
|
}
|
||||||
|
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: &I) -> Result<(), Error> {
|
||||||
|
self.last_trace = None;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Named for NovelSysStateFeedback
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"sysstate"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================== Debugging Feedback
|
||||||
|
/// A [`Feedback`] meant to dump the system-traces for debugging. Depends on [`QemuSysStateObserver`]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct DumpSystraceFeedback
|
||||||
|
{
|
||||||
|
dumpfile: Option<PathBuf>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I, S> Feedback<I, S> for DumpSystraceFeedback
|
||||||
|
where
|
||||||
|
I: Input,
|
||||||
|
S: HasClientPerfMonitor,
|
||||||
|
{
|
||||||
|
fn is_interesting<EM, OT>(
|
||||||
|
&mut self,
|
||||||
|
_state: &mut S,
|
||||||
|
_manager: &mut EM,
|
||||||
|
_input: &I,
|
||||||
|
observers: &OT,
|
||||||
|
_exit_kind: &ExitKind,
|
||||||
|
) -> Result<bool, Error>
|
||||||
|
where
|
||||||
|
EM: EventFirer<I>,
|
||||||
|
OT: ObserversTuple<I, S>,
|
||||||
|
{
|
||||||
|
let observer = observers.match_name::<QemuSysStateObserver>("sysstate")
|
||||||
|
.expect("QemuSysStateObserver not found");
|
||||||
|
match &self.dumpfile {
|
||||||
|
Some(s) => {
|
||||||
|
std::fs::write(s,ron::to_string(&observer.last_run).expect("Error serializing hashmap")).expect("Can not dump to file");
|
||||||
|
self.dumpfile = None
|
||||||
|
},
|
||||||
|
None => println!("{:?}",observer.last_run),
|
||||||
|
};
|
||||||
|
Ok(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Named for DumpSystraceFeedback
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"DumpSysState"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DumpSystraceFeedback
|
||||||
|
{
|
||||||
|
/// Creates a new [`DumpSystraceFeedback`]
|
||||||
|
#[must_use]
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {dumpfile: None}
|
||||||
|
}
|
||||||
|
pub fn with_dump(dumpfile: Option<PathBuf>) -> Self {
|
||||||
|
Self {dumpfile: dumpfile}
|
||||||
|
}
|
||||||
|
}
|
@ -103,7 +103,7 @@ pub enum rtos_struct {
|
|||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! impl_emu_lookup {
|
macro_rules! impl_emu_lookup {
|
||||||
($struct_name:ident) => {
|
($struct_name:ident) => {
|
||||||
impl $crate::freertos::emu_lookup for $struct_name {
|
impl $crate::sysstate::freertos::emu_lookup for $struct_name {
|
||||||
fn lookup(emu: &Emulator, addr: ::std::os::raw::c_uint) -> $struct_name {
|
fn lookup(emu: &Emulator, addr: ::std::os::raw::c_uint) -> $struct_name {
|
||||||
let mut tmp : [u8; std::mem::size_of::<$struct_name>()] = [0u8; std::mem::size_of::<$struct_name>()];
|
let mut tmp : [u8; std::mem::size_of::<$struct_name>()] = [0u8; std::mem::size_of::<$struct_name>()];
|
||||||
unsafe {
|
unsafe {
|
138
fuzzers/wcet_qemu_sys/src/sysstate/helpers.rs
Normal file
138
fuzzers/wcet_qemu_sys/src/sysstate/helpers.rs
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
use crate::sysstate::FreeRTOSSystemStateRaw;
|
||||||
|
use crate::sysstate::CURRENT_SYSSTATE_VEC;
|
||||||
|
use crate::sysstate::NUM_PRIOS;
|
||||||
|
use super::freertos::TCB_t;
|
||||||
|
use super::freertos::rtos_struct::List_Item_struct;
|
||||||
|
use super::freertos::rtos_struct::*;
|
||||||
|
use super::freertos;
|
||||||
|
use libafl::{executors::ExitKind, inputs::Input, observers::ObserversTuple, state::HasMetadata};
|
||||||
|
|
||||||
|
use libafl_qemu::{
|
||||||
|
emu::Emulator,
|
||||||
|
executor::QemuExecutor,
|
||||||
|
helper::{QemuHelper, QemuHelperTuple, QemuInstrumentationFilter},
|
||||||
|
};
|
||||||
|
|
||||||
|
//============================= Struct definitions
|
||||||
|
|
||||||
|
|
||||||
|
//============================= Qemu Helper
|
||||||
|
|
||||||
|
/// A Qemu Helper with reads FreeRTOS specific structs from Qemu whenever certain syscalls occur
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct QemuSystemStateHelper {
|
||||||
|
filter: QemuInstrumentationFilter,
|
||||||
|
tcb_addr: u32,
|
||||||
|
ready_queues: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl QemuSystemStateHelper {
|
||||||
|
#[must_use]
|
||||||
|
pub fn new(tcb_addr: u32, ready_queues: u32) -> Self {
|
||||||
|
Self {
|
||||||
|
filter: QemuInstrumentationFilter::None,
|
||||||
|
tcb_addr: tcb_addr,
|
||||||
|
ready_queues: ready_queues,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn with_instrumentation_filter(filter: QemuInstrumentationFilter, tcb_addr: u32, ready_queues: u32) -> Self {
|
||||||
|
Self { filter, tcb_addr, ready_queues}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn must_instrument(&self, addr: u64) -> bool {
|
||||||
|
self.filter.allowed(addr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I, S> QemuHelper<I, S> for QemuSystemStateHelper
|
||||||
|
where
|
||||||
|
I: Input,
|
||||||
|
S: HasMetadata,
|
||||||
|
{
|
||||||
|
fn init<'a, H, OT, QT>(&self, executor: &QemuExecutor<'a, H, I, OT, QT, S>)
|
||||||
|
where
|
||||||
|
H: FnMut(&I) -> ExitKind,
|
||||||
|
OT: ObserversTuple<I, S>,
|
||||||
|
QT: QemuHelperTuple<I, S>,
|
||||||
|
{
|
||||||
|
// emu::Emulator{_private: ()}.set_gen_block_hook(test_gen_hook);
|
||||||
|
executor.hook_block_generation(gen_not_exec_block_hook::<I, QT, S>);
|
||||||
|
executor.hook_block_execution(exec_syscall_hook::<I, QT, S>);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn exec_syscall_hook<I, QT, S>(
|
||||||
|
emulator: &Emulator,
|
||||||
|
helpers: &mut QT,
|
||||||
|
_state: &mut S,
|
||||||
|
pc: u64,
|
||||||
|
)
|
||||||
|
where
|
||||||
|
S: HasMetadata,
|
||||||
|
I: Input,
|
||||||
|
QT: QemuHelperTuple<I, S>,
|
||||||
|
{
|
||||||
|
let h = helpers.match_first_type::<QemuSystemStateHelper>().expect("QemuSystemHelper not found in helper tupel");
|
||||||
|
if !h.must_instrument(pc) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let listbytes : u32 = u32::try_from(std::mem::size_of::<freertos::List_t>()).unwrap();
|
||||||
|
let mut sysstate = FreeRTOSSystemStateRaw::default();
|
||||||
|
sysstate.qemu_tick = emulator.get_ticks();
|
||||||
|
|
||||||
|
let curr_tcb_addr : freertos::void_ptr = freertos::emu_lookup::lookup(emulator, h.tcb_addr);
|
||||||
|
sysstate.current_tcb = freertos::emu_lookup::lookup(emulator,curr_tcb_addr);
|
||||||
|
// println!("{:?}",std::str::from_utf8(¤t_tcb.pcTaskName));
|
||||||
|
|
||||||
|
for i in 0..NUM_PRIOS {
|
||||||
|
let target : u32 = listbytes*u32::try_from(i).unwrap()+h.ready_queues;
|
||||||
|
sysstate.prio_ready_lists[i] = freertos::emu_lookup::lookup(emulator, target);
|
||||||
|
// println!("List at {}: {:?}",target, sysstate.prio_ready_lists[i]);
|
||||||
|
let mut next_index = sysstate.prio_ready_lists[i].pxIndex;
|
||||||
|
for _j in 0..sysstate.prio_ready_lists[i].uxNumberOfItems {
|
||||||
|
// always jump over the xListEnd marker
|
||||||
|
if (target..target+listbytes).contains(&next_index) {
|
||||||
|
let next_item : freertos::MiniListItem_t = freertos::emu_lookup::lookup(emulator, next_index);
|
||||||
|
let new_next_index=next_item.pxNext;
|
||||||
|
sysstate.dumping_ground.insert(next_index,List_MiniItem_struct(next_item));
|
||||||
|
next_index = new_next_index;
|
||||||
|
}
|
||||||
|
let next_item : freertos::ListItem_t = freertos::emu_lookup::lookup(emulator, next_index);
|
||||||
|
// println!("Item at {}: {:?}",next_index,next_item);
|
||||||
|
assert_eq!(next_item.pvContainer,target);
|
||||||
|
let new_next_index=next_item.pxNext;
|
||||||
|
let next_tcb : TCB_t= freertos::emu_lookup::lookup(emulator,next_item.pvOwner);
|
||||||
|
// println!("TCB at {}: {:?}",next_item.pvOwner,next_tcb);
|
||||||
|
sysstate.dumping_ground.insert(next_item.pvOwner,TCB_struct(next_tcb.clone()));
|
||||||
|
sysstate.dumping_ground.insert(next_index,List_Item_struct(next_item));
|
||||||
|
next_index=new_next_index;
|
||||||
|
}
|
||||||
|
// Handle edge case where the end marker was not included yet
|
||||||
|
if (target..target+listbytes).contains(&next_index) {
|
||||||
|
let next_item : freertos::MiniListItem_t = freertos::emu_lookup::lookup(emulator, next_index);
|
||||||
|
sysstate.dumping_ground.insert(next_index,List_MiniItem_struct(next_item));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe { CURRENT_SYSSTATE_VEC.push(sysstate); }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn gen_not_exec_block_hook<I, QT, S>(
|
||||||
|
_emulator: &Emulator,
|
||||||
|
helpers: &mut QT,
|
||||||
|
_state: &mut S,
|
||||||
|
pc: u64,
|
||||||
|
)
|
||||||
|
-> Option<u64> where
|
||||||
|
S: HasMetadata,
|
||||||
|
I: Input,
|
||||||
|
QT: QemuHelperTuple<I, S>,
|
||||||
|
{
|
||||||
|
let h = helpers.match_first_type::<QemuSystemStateHelper>().expect("QemuSystemHelper not found in helper tupel");
|
||||||
|
if !h.must_instrument(pc) {
|
||||||
|
None
|
||||||
|
} else {Some(1)}
|
||||||
|
}
|
108
fuzzers/wcet_qemu_sys/src/sysstate/mod.rs
Normal file
108
fuzzers/wcet_qemu_sys/src/sysstate/mod.rs
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
//! Sysstate referes to the State of a FreeRTOS fuzzing target
|
||||||
|
use std::hash::Hasher;
|
||||||
|
use std::hash::Hash;
|
||||||
|
use hashbrown::HashMap;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use freertos::TCB_t;
|
||||||
|
|
||||||
|
pub mod freertos;
|
||||||
|
pub mod helpers;
|
||||||
|
pub mod observers;
|
||||||
|
pub mod feedbacks;
|
||||||
|
|
||||||
|
// Constants
|
||||||
|
const NUM_PRIOS: usize = 5;
|
||||||
|
|
||||||
|
//============================= Struct definitions
|
||||||
|
/// Raw info Dump from Qemu
|
||||||
|
#[derive(Debug, Default, Serialize, Deserialize)]
|
||||||
|
pub struct FreeRTOSSystemStateRaw {
|
||||||
|
qemu_tick: u64,
|
||||||
|
current_tcb: TCB_t,
|
||||||
|
prio_ready_lists: [freertos::List_t; NUM_PRIOS],
|
||||||
|
dumping_ground: HashMap<u32,freertos::rtos_struct>,
|
||||||
|
}
|
||||||
|
/// List of system state dumps from QemuHelpers
|
||||||
|
static mut CURRENT_SYSSTATE_VEC: Vec<FreeRTOSSystemStateRaw> = vec![];
|
||||||
|
|
||||||
|
/// A reduced version of freertos::TCB_t
|
||||||
|
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
|
||||||
|
pub struct MiniTCB {
|
||||||
|
task_name: String,
|
||||||
|
priority: u32,
|
||||||
|
base_priority: u32,
|
||||||
|
mutexes_held: u32,
|
||||||
|
notify_value: u32,
|
||||||
|
notify_state: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Hash for MiniTCB {
|
||||||
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||||
|
self.task_name.hash(state);
|
||||||
|
// self.priority.hash(state);
|
||||||
|
// self.mutexes_held.hash(state);
|
||||||
|
// self.notify_state.hash(state);
|
||||||
|
// self.notify_value.hash(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MiniTCB {
|
||||||
|
pub fn from_tcb(input: &TCB_t) -> Self {
|
||||||
|
unsafe {
|
||||||
|
let tmp = std::mem::transmute::<[i8; 10],[u8; 10]>(input.pcTaskName);
|
||||||
|
let name : String = std::str::from_utf8(&tmp).expect("TCB name was not utf8").chars().filter(|x| *x != '\0').collect::<String>();
|
||||||
|
Self {
|
||||||
|
task_name: name,
|
||||||
|
priority: input.uxPriority,
|
||||||
|
base_priority: input.uxBasePriority,
|
||||||
|
mutexes_held: input.uxMutexesHeld,
|
||||||
|
notify_value: input.ulNotifiedValue[0],
|
||||||
|
notify_state: input.ucNotifyState[0],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn from_tcb_owned(input: TCB_t) -> Self {
|
||||||
|
unsafe {
|
||||||
|
let tmp = std::mem::transmute::<[i8; 10],[u8; 10]>(input.pcTaskName);
|
||||||
|
let name : String = std::str::from_utf8(&tmp).expect("TCB name was not utf8").chars().filter(|x| *x != '\0').collect::<String>();
|
||||||
|
Self {
|
||||||
|
task_name: name,
|
||||||
|
priority: input.uxPriority,
|
||||||
|
base_priority: input.uxBasePriority,
|
||||||
|
mutexes_held: input.uxMutexesHeld,
|
||||||
|
notify_value: input.ulNotifiedValue[0],
|
||||||
|
notify_state: input.ucNotifyState[0],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Refined information about the states an execution transitioned between
|
||||||
|
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
|
||||||
|
pub struct MiniFreeRTOSSystemState {
|
||||||
|
start_tick: u64,
|
||||||
|
end_tick: u64,
|
||||||
|
current_task: MiniTCB,
|
||||||
|
ready_list_after: Vec<MiniTCB>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Hash for MiniFreeRTOSSystemState {
|
||||||
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||||
|
self.current_task.hash(state);
|
||||||
|
// self.ready_list_after.hash(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wrapper around Vec<MiniFreeRTOSSystemState> to attach as Metadata
|
||||||
|
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
|
||||||
|
pub struct FreeRTOSSystemStateMetadata {
|
||||||
|
inner: Vec<MiniFreeRTOSSystemState>,
|
||||||
|
}
|
||||||
|
impl FreeRTOSSystemStateMetadata {
|
||||||
|
pub fn new(inner: Vec<MiniFreeRTOSSystemState>) -> Self{
|
||||||
|
Self {inner: inner}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
libafl::impl_serdeany!(FreeRTOSSystemStateMetadata);
|
131
fuzzers/wcet_qemu_sys/src/sysstate/observers.rs
Normal file
131
fuzzers/wcet_qemu_sys/src/sysstate/observers.rs
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
use libafl::bolts::HasLen;
|
||||||
|
use libafl::bolts::tuples::Named;
|
||||||
|
use libafl::Error;
|
||||||
|
use libafl::observers::Observer;
|
||||||
|
use hashbrown::HashMap;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use super::{
|
||||||
|
CURRENT_SYSSTATE_VEC,
|
||||||
|
FreeRTOSSystemStateRaw,
|
||||||
|
MiniTCB,
|
||||||
|
MiniFreeRTOSSystemState,
|
||||||
|
freertos::{List_t, TCB_t, rtos_struct, rtos_struct::*},
|
||||||
|
};
|
||||||
|
|
||||||
|
//============================= Observer
|
||||||
|
|
||||||
|
/// The QemuSysState Observer retrieves the SysState
|
||||||
|
/// that will get updated by the target.
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Default)]
|
||||||
|
#[allow(clippy::unsafe_derive_deserialize)]
|
||||||
|
pub struct QemuSysStateObserver
|
||||||
|
{
|
||||||
|
pub last_run: Vec<MiniFreeRTOSSystemState>,
|
||||||
|
name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I, S> Observer<I, S> for QemuSysStateObserver
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
fn pre_exec(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> {
|
||||||
|
unsafe {CURRENT_SYSSTATE_VEC.clear(); }
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn post_exec(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> {
|
||||||
|
unsafe {self.last_run = refine_system_states(&mut CURRENT_SYSSTATE_VEC);}
|
||||||
|
// let mut hasher = DefaultHasher::new();
|
||||||
|
// let mut a = self.parse_last();
|
||||||
|
// a[0].start_tick=21355;
|
||||||
|
// a[0].end_tick=2131;
|
||||||
|
// a.hash(&mut hasher);
|
||||||
|
// let somehash = hasher.finish();
|
||||||
|
// println!("HashValue: {}",somehash);
|
||||||
|
// println!("{:#?}",self.parse_last());
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Named for QemuSysStateObserver
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
self.name.as_str()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HasLen for QemuSysStateObserver
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
fn len(&self) -> usize {
|
||||||
|
self.last_run.len()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl QemuSysStateObserver {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self{last_run: vec![], name: "sysstate".to_string()}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//============================= Parsing helpers
|
||||||
|
|
||||||
|
/// Parse a List_t containing TCB_t into Vec<TCB_t> from cache. Consumes the elements from cache
|
||||||
|
fn tcb_list_to_vec_cached(list: List_t, dump: &mut HashMap<u32,rtos_struct>) -> Vec<TCB_t>
|
||||||
|
{
|
||||||
|
let mut ret : Vec<TCB_t> = Vec::new();
|
||||||
|
if list.uxNumberOfItems == 0 {return ret;}
|
||||||
|
let last_list_item = match dump.remove(&list.pxIndex).expect("List_t entry was not in Hashmap") {
|
||||||
|
List_Item_struct(li) => li,
|
||||||
|
List_MiniItem_struct(mli) => match dump.remove(&mli.pxNext).expect("MiniListItem pointer invaild") {
|
||||||
|
List_Item_struct(li) => li,
|
||||||
|
_ => panic!("MiniListItem of a non empty List does not point to ListItem"),
|
||||||
|
},
|
||||||
|
_ => panic!("List_t entry was not a ListItem"),
|
||||||
|
};
|
||||||
|
let mut next_index = last_list_item.pxNext;
|
||||||
|
let last_tcb = match dump.remove(&last_list_item.pvOwner).expect("ListItem Owner not in Hashmap") {
|
||||||
|
TCB_struct(t) => t,
|
||||||
|
_ => panic!("List content does not equal type"),
|
||||||
|
};
|
||||||
|
for _ in 0..list.uxNumberOfItems-1 {
|
||||||
|
let next_list_item = match dump.remove(&next_index).expect("List_t entry was not in Hashmap") {
|
||||||
|
List_Item_struct(li) => li,
|
||||||
|
List_MiniItem_struct(mli) => match dump.remove(&mli.pxNext).expect("MiniListItem pointer invaild") {
|
||||||
|
List_Item_struct(li) => li,
|
||||||
|
_ => panic!("MiniListItem of a non empty List does not point to ListItem"),
|
||||||
|
},
|
||||||
|
_ => panic!("List_t entry was not a ListItem"),
|
||||||
|
};
|
||||||
|
match dump.remove(&next_list_item.pvOwner).expect("ListItem Owner not in Hashmap") {
|
||||||
|
TCB_struct(t) => {ret.push(t)},
|
||||||
|
_ => panic!("List content does not equal type"),
|
||||||
|
}
|
||||||
|
next_index=next_list_item.pxNext;
|
||||||
|
}
|
||||||
|
ret.push(last_tcb);
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
/// Drains a List of raw SystemStates to produce a refined trace
|
||||||
|
fn refine_system_states(input: &mut Vec<FreeRTOSSystemStateRaw>) -> Vec<MiniFreeRTOSSystemState> {
|
||||||
|
let mut ret = Vec::<MiniFreeRTOSSystemState>::new();
|
||||||
|
let mut start_tick : u64 = 0;
|
||||||
|
for i in input.into_iter() {
|
||||||
|
let mut collector = Vec::<MiniTCB>::new();
|
||||||
|
for j in i.prio_ready_lists.into_iter().rev() {
|
||||||
|
let mut tmp = tcb_list_to_vec_cached(j,&mut i.dumping_ground).iter().map(|x| MiniTCB::from_tcb(x)).collect();
|
||||||
|
collector.append(&mut tmp);
|
||||||
|
}
|
||||||
|
ret.push(MiniFreeRTOSSystemState {
|
||||||
|
current_task: MiniTCB::from_tcb_owned(i.current_tcb),
|
||||||
|
start_tick: start_tick,
|
||||||
|
end_tick: i.qemu_tick,
|
||||||
|
ready_list_after: collector,
|
||||||
|
});
|
||||||
|
start_tick=i.qemu_tick;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
@ -1,502 +0,0 @@
|
|||||||
use libafl_qemu::QemuClockObserver;
|
|
||||||
use libafl::feedbacks::FeedbackState;
|
|
||||||
use libafl::corpus::Testcase;
|
|
||||||
use libafl::state::HasFeedbackStates;
|
|
||||||
use libafl::bolts::tuples::MatchName;
|
|
||||||
use std::collections::hash_map::DefaultHasher;
|
|
||||||
use std::hash::Hasher;
|
|
||||||
use std::hash::Hash;
|
|
||||||
use crate::freertos::emu_lookup;
|
|
||||||
use crate::freertos::rtos_struct;
|
|
||||||
use crate::freertos::List_t;
|
|
||||||
use crate::freertos::TCB_t;
|
|
||||||
use crate::freertos::rtos_struct::List_Item_struct;
|
|
||||||
use libafl::events::EventFirer;
|
|
||||||
use libafl::state::HasClientPerfMonitor;
|
|
||||||
use libafl::feedbacks::Feedback;
|
|
||||||
use libafl::bolts::HasLen;
|
|
||||||
use libafl::bolts::tuples::Named;
|
|
||||||
use libafl::Error;
|
|
||||||
use libafl::observers::Observer;
|
|
||||||
use crate::freertos::rtos_struct::*;
|
|
||||||
use crate::freertos;
|
|
||||||
use hashbrown::HashMap;
|
|
||||||
use libafl::{executors::ExitKind, inputs::Input, observers::ObserversTuple, state::HasMetadata};
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
use libafl_qemu::{
|
|
||||||
emu,
|
|
||||||
emu::Emulator,
|
|
||||||
executor::QemuExecutor,
|
|
||||||
helper::{QemuHelper, QemuHelperTuple, QemuInstrumentationFilter},
|
|
||||||
};
|
|
||||||
|
|
||||||
const NUM_PRIOS: usize = 5;
|
|
||||||
|
|
||||||
//============================= Datatypes
|
|
||||||
|
|
||||||
/// Info Dump from Qemu
|
|
||||||
// pub type SysState = (u64,freertos::TCB_t,HashMap<u32,freertos::rtos_struct>);
|
|
||||||
#[derive(Debug, Default, Serialize, Deserialize)]
|
|
||||||
pub struct FreeRTOSSystemStateRaw {
|
|
||||||
qemu_tick: u64,
|
|
||||||
current_tcb: TCB_t,
|
|
||||||
prio_ready_lists: [freertos::List_t; NUM_PRIOS],
|
|
||||||
dumping_ground: HashMap<u32,freertos::rtos_struct>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
|
|
||||||
pub struct MiniTCB {
|
|
||||||
task_name: String,
|
|
||||||
priority: u32,
|
|
||||||
base_priority: u32,
|
|
||||||
mutexes_held: u32,
|
|
||||||
notify_value: u32,
|
|
||||||
notify_state: u8,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Hash for MiniTCB {
|
|
||||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
|
||||||
self.task_name.hash(state);
|
|
||||||
// self.priority.hash(state);
|
|
||||||
// self.mutexes_held.hash(state);
|
|
||||||
// self.notify_state.hash(state);
|
|
||||||
// self.notify_value.hash(state);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MiniTCB {
|
|
||||||
pub fn from_tcb(input: &TCB_t) -> Self {
|
|
||||||
unsafe {
|
|
||||||
let tmp = std::mem::transmute::<[i8; 10],[u8; 10]>(input.pcTaskName);
|
|
||||||
let name : String = std::str::from_utf8(&tmp).expect("TCB name was not utf8").chars().filter(|x| *x != '\0').collect::<String>();
|
|
||||||
Self {
|
|
||||||
task_name: name,
|
|
||||||
priority: input.uxPriority,
|
|
||||||
base_priority: input.uxBasePriority,
|
|
||||||
mutexes_held: input.uxMutexesHeld,
|
|
||||||
notify_value: input.ulNotifiedValue[0],
|
|
||||||
notify_state: input.ucNotifyState[0],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn from_tcb_owned(input: TCB_t) -> Self {
|
|
||||||
unsafe {
|
|
||||||
let tmp = std::mem::transmute::<[i8; 10],[u8; 10]>(input.pcTaskName);
|
|
||||||
let name : String = std::str::from_utf8(&tmp).expect("TCB name was not utf8").chars().filter(|x| *x != '\0').collect::<String>();
|
|
||||||
Self {
|
|
||||||
task_name: name,
|
|
||||||
priority: input.uxPriority,
|
|
||||||
base_priority: input.uxBasePriority,
|
|
||||||
mutexes_held: input.uxMutexesHeld,
|
|
||||||
notify_value: input.ulNotifiedValue[0],
|
|
||||||
notify_state: input.ucNotifyState[0],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Refined information about the states an execution transitioned between
|
|
||||||
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
|
|
||||||
pub struct MiniFreeRTOSSystemState {
|
|
||||||
start_tick: u64,
|
|
||||||
end_tick: u64,
|
|
||||||
current_task: MiniTCB,
|
|
||||||
ready_list_after: Vec<MiniTCB>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Hash for MiniFreeRTOSSystemState {
|
|
||||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
|
||||||
self.current_task.hash(state);
|
|
||||||
// self.ready_list_after.hash(state);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
|
|
||||||
pub struct FreeRTOSSystemStateMetadata {
|
|
||||||
inner: Vec<MiniFreeRTOSSystemState>,
|
|
||||||
}
|
|
||||||
impl FreeRTOSSystemStateMetadata {
|
|
||||||
pub fn new(inner: Vec<MiniFreeRTOSSystemState>) -> Self{
|
|
||||||
Self {inner: inner}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
libafl::impl_serdeany!(FreeRTOSSystemStateMetadata);
|
|
||||||
|
|
||||||
|
|
||||||
//============================= Qemu Helper
|
|
||||||
static mut CURRENT_SYSSTATE_VEC: Vec<FreeRTOSSystemStateRaw> = vec![];
|
|
||||||
|
|
||||||
/// A Qemu Helper with reads FreeRTOS specific structs from Qemu whenever certain syscalls occur
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct QemuSystemStateHelper {
|
|
||||||
filter: QemuInstrumentationFilter,
|
|
||||||
tcb_addr: u32,
|
|
||||||
ready_queues: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl QemuSystemStateHelper {
|
|
||||||
#[must_use]
|
|
||||||
pub fn new(tcb_addr: u32, ready_queues: u32) -> Self {
|
|
||||||
Self {
|
|
||||||
filter: QemuInstrumentationFilter::None,
|
|
||||||
tcb_addr: tcb_addr,
|
|
||||||
ready_queues: ready_queues,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[must_use]
|
|
||||||
pub fn with_instrumentation_filter(filter: QemuInstrumentationFilter, tcb_addr: u32, ready_queues: u32) -> Self {
|
|
||||||
Self { filter, tcb_addr, ready_queues}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[must_use]
|
|
||||||
pub fn must_instrument(&self, addr: u64) -> bool {
|
|
||||||
self.filter.allowed(addr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I, S> QemuHelper<I, S> for QemuSystemStateHelper
|
|
||||||
where
|
|
||||||
I: Input,
|
|
||||||
S: HasMetadata,
|
|
||||||
{
|
|
||||||
fn init<'a, H, OT, QT>(&self, executor: &QemuExecutor<'a, H, I, OT, QT, S>)
|
|
||||||
where
|
|
||||||
H: FnMut(&I) -> ExitKind,
|
|
||||||
OT: ObserversTuple<I, S>,
|
|
||||||
QT: QemuHelperTuple<I, S>,
|
|
||||||
{
|
|
||||||
// emu::Emulator{_private: ()}.set_gen_block_hook(test_gen_hook);
|
|
||||||
executor.hook_block_generation(gen_not_exec_block_hook::<I, QT, S>);
|
|
||||||
executor.hook_block_execution(exec_syscall_hook::<I, QT, S>);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn exec_syscall_hook<I, QT, S>(
|
|
||||||
emulator: &Emulator,
|
|
||||||
helpers: &mut QT,
|
|
||||||
state: &mut S,
|
|
||||||
pc: u64,
|
|
||||||
)
|
|
||||||
where
|
|
||||||
S: HasMetadata,
|
|
||||||
I: Input,
|
|
||||||
QT: QemuHelperTuple<I, S>,
|
|
||||||
{
|
|
||||||
let h = helpers.match_first_type::<QemuSystemStateHelper>().expect("QemuSystemHelper not found in helper tupel");
|
|
||||||
if !h.must_instrument(pc) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let LISTBYTES : u32 = u32::try_from(std::mem::size_of::<freertos::List_t>()).unwrap();
|
|
||||||
let mut sysstate = FreeRTOSSystemStateRaw::default();
|
|
||||||
sysstate.qemu_tick = emulator.get_ticks();
|
|
||||||
|
|
||||||
let curr_tcb_addr : freertos::void_ptr = freertos::emu_lookup::lookup(emulator, h.tcb_addr);
|
|
||||||
sysstate.current_tcb = freertos::emu_lookup::lookup(emulator,curr_tcb_addr);
|
|
||||||
// println!("{:?}",std::str::from_utf8(¤t_tcb.pcTaskName));
|
|
||||||
|
|
||||||
for i in 0..NUM_PRIOS {
|
|
||||||
let target : u32 = LISTBYTES*u32::try_from(i).unwrap()+h.ready_queues;
|
|
||||||
sysstate.prio_ready_lists[i] = freertos::emu_lookup::lookup(emulator, target);
|
|
||||||
// println!("List at {}: {:?}",target, sysstate.prio_ready_lists[i]);
|
|
||||||
let mut next_index = sysstate.prio_ready_lists[i].pxIndex;
|
|
||||||
for _j in 0..sysstate.prio_ready_lists[i].uxNumberOfItems {
|
|
||||||
// always jump over the xListEnd marker
|
|
||||||
if (target..target+LISTBYTES).contains(&next_index) {
|
|
||||||
let next_item : freertos::MiniListItem_t = freertos::emu_lookup::lookup(emulator, next_index);
|
|
||||||
let new_next_index=next_item.pxNext;
|
|
||||||
sysstate.dumping_ground.insert(next_index,List_MiniItem_struct(next_item));
|
|
||||||
next_index = new_next_index;
|
|
||||||
}
|
|
||||||
let next_item : freertos::ListItem_t = freertos::emu_lookup::lookup(emulator, next_index);
|
|
||||||
// println!("Item at {}: {:?}",next_index,next_item);
|
|
||||||
assert_eq!(next_item.pvContainer,target);
|
|
||||||
let new_next_index=next_item.pxNext;
|
|
||||||
let next_tcb : TCB_t= freertos::emu_lookup::lookup(emulator,next_item.pvOwner);
|
|
||||||
// println!("TCB at {}: {:?}",next_item.pvOwner,next_tcb);
|
|
||||||
sysstate.dumping_ground.insert(next_item.pvOwner,TCB_struct(next_tcb.clone()));
|
|
||||||
sysstate.dumping_ground.insert(next_index,List_Item_struct(next_item));
|
|
||||||
next_index=new_next_index;
|
|
||||||
}
|
|
||||||
// Handle edge case where the end marker was not included yet
|
|
||||||
if (target..target+LISTBYTES).contains(&next_index) {
|
|
||||||
let next_item : freertos::MiniListItem_t = freertos::emu_lookup::lookup(emulator, next_index);
|
|
||||||
sysstate.dumping_ground.insert(next_index,List_MiniItem_struct(next_item));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe { CURRENT_SYSSTATE_VEC.push(sysstate); }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn gen_not_exec_block_hook<I, QT, S>(
|
|
||||||
_emulator: &Emulator,
|
|
||||||
helpers: &mut QT,
|
|
||||||
_state: &mut S,
|
|
||||||
pc: u64,
|
|
||||||
)
|
|
||||||
-> Option<u64> where
|
|
||||||
S: HasMetadata,
|
|
||||||
I: Input,
|
|
||||||
QT: QemuHelperTuple<I, S>,
|
|
||||||
{
|
|
||||||
let h = helpers.match_first_type::<QemuSystemStateHelper>().expect("QemuSystemHelper not found in helper tupel");
|
|
||||||
if !h.must_instrument(pc) {
|
|
||||||
None
|
|
||||||
} else {Some(1)}
|
|
||||||
}
|
|
||||||
|
|
||||||
//============================= Observer
|
|
||||||
|
|
||||||
/// The QemuSysState Observer retrieves the SysState
|
|
||||||
/// that will get updated by the target.
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Default)]
|
|
||||||
#[allow(clippy::unsafe_derive_deserialize)]
|
|
||||||
pub struct QemuSysStateObserver
|
|
||||||
{
|
|
||||||
last_run: Vec<MiniFreeRTOSSystemState>,
|
|
||||||
name: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I, S> Observer<I, S> for QemuSysStateObserver
|
|
||||||
{
|
|
||||||
#[inline]
|
|
||||||
fn pre_exec(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> {
|
|
||||||
unsafe {CURRENT_SYSSTATE_VEC.clear(); }
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn post_exec(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> {
|
|
||||||
unsafe {self.last_run = parse_last(&mut CURRENT_SYSSTATE_VEC);}
|
|
||||||
// let mut hasher = DefaultHasher::new();
|
|
||||||
// let mut a = self.parse_last();
|
|
||||||
// a[0].start_tick=21355;
|
|
||||||
// a[0].end_tick=2131;
|
|
||||||
// a.hash(&mut hasher);
|
|
||||||
// let somehash = hasher.finish();
|
|
||||||
// println!("HashValue: {}",somehash);
|
|
||||||
// println!("{:#?}",self.parse_last());
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Named for QemuSysStateObserver
|
|
||||||
{
|
|
||||||
#[inline]
|
|
||||||
fn name(&self) -> &str {
|
|
||||||
self.name.as_str()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl HasLen for QemuSysStateObserver
|
|
||||||
{
|
|
||||||
#[inline]
|
|
||||||
fn len(&self) -> usize {
|
|
||||||
self.last_run.len()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn parse_last(input: &mut Vec<FreeRTOSSystemStateRaw>) -> Vec<MiniFreeRTOSSystemState> {
|
|
||||||
let mut ret = Vec::<MiniFreeRTOSSystemState>::new();
|
|
||||||
let mut start_tick : u64 = 0;
|
|
||||||
for i in input.into_iter() {
|
|
||||||
let mut collector = Vec::<MiniTCB>::new();
|
|
||||||
for j in i.prio_ready_lists.into_iter().rev() {
|
|
||||||
let mut tmp = list_to_tcb_vec_owned(j,&mut i.dumping_ground).iter().map(|x| MiniTCB::from_tcb(x)).collect();
|
|
||||||
collector.append(&mut tmp);
|
|
||||||
}
|
|
||||||
ret.push(MiniFreeRTOSSystemState {
|
|
||||||
current_task: MiniTCB::from_tcb_owned(i.current_tcb),
|
|
||||||
start_tick: start_tick,
|
|
||||||
end_tick: i.qemu_tick,
|
|
||||||
ready_list_after: collector,
|
|
||||||
});
|
|
||||||
start_tick=i.qemu_tick;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl QemuSysStateObserver {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self{last_run: vec![], name: "sysstate".to_string()}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn list_to_tcb_vec(list: &List_t, dump: &HashMap<u32,rtos_struct>) -> Vec<TCB_t>
|
|
||||||
{
|
|
||||||
let mut ret : Vec<TCB_t> = Vec::new();
|
|
||||||
if list.uxNumberOfItems == 0 {return ret;}
|
|
||||||
let first_list_index = match dump.get(&list.pxIndex).expect("List_t entry was not in Hashmap") {
|
|
||||||
List_Item_struct(li) => li.pxNext,
|
|
||||||
List_MiniItem_struct(mli) => match dump.get(&mli.pxNext).expect("MiniListItem pointer invaild") {
|
|
||||||
List_Item_struct(li) => li.pxNext,
|
|
||||||
_ => panic!("MiniListItem of a non empty List does not point to ListItem"),
|
|
||||||
},
|
|
||||||
_ => panic!("List_t entry was not a ListItem"),
|
|
||||||
};
|
|
||||||
let mut next_index = first_list_index;
|
|
||||||
for _ in 0..list.uxNumberOfItems {
|
|
||||||
let next_list_item = match dump.get(&next_index).expect("List_t entry was not in Hashmap") {
|
|
||||||
List_Item_struct(li) => li,
|
|
||||||
List_MiniItem_struct(mli) => match dump.get(&mli.pxNext).expect("MiniListItem pointer invaild") {
|
|
||||||
List_Item_struct(li) => li,
|
|
||||||
_ => panic!("MiniListItem of a non empty List does not point to ListItem"),
|
|
||||||
},
|
|
||||||
_ => panic!("List_t entry was not a ListItem"),
|
|
||||||
};
|
|
||||||
match dump.get(&next_list_item.pvOwner).expect("ListItem Owner not in Hashmap") {
|
|
||||||
TCB_struct(t) => {ret.push(*t)},
|
|
||||||
_ => panic!("List content does not equal type"),
|
|
||||||
}
|
|
||||||
next_index=next_list_item.pxNext;
|
|
||||||
}
|
|
||||||
ret
|
|
||||||
}
|
|
||||||
pub fn list_to_tcb_vec_owned(list: List_t, dump: &mut HashMap<u32,rtos_struct>) -> Vec<TCB_t>
|
|
||||||
{
|
|
||||||
let mut ret : Vec<TCB_t> = Vec::new();
|
|
||||||
if list.uxNumberOfItems == 0 {return ret;}
|
|
||||||
let last_list_item = match dump.remove(&list.pxIndex).expect("List_t entry was not in Hashmap") {
|
|
||||||
List_Item_struct(li) => li,
|
|
||||||
List_MiniItem_struct(mli) => match dump.remove(&mli.pxNext).expect("MiniListItem pointer invaild") {
|
|
||||||
List_Item_struct(li) => li,
|
|
||||||
_ => panic!("MiniListItem of a non empty List does not point to ListItem"),
|
|
||||||
},
|
|
||||||
_ => panic!("List_t entry was not a ListItem"),
|
|
||||||
};
|
|
||||||
let mut next_index = last_list_item.pxNext;
|
|
||||||
let last_tcb = match dump.remove(&last_list_item.pvOwner).expect("ListItem Owner not in Hashmap") {
|
|
||||||
TCB_struct(t) => t,
|
|
||||||
_ => panic!("List content does not equal type"),
|
|
||||||
};
|
|
||||||
for _ in 0..list.uxNumberOfItems-1 {
|
|
||||||
let next_list_item = match dump.remove(&next_index).expect("List_t entry was not in Hashmap") {
|
|
||||||
List_Item_struct(li) => li,
|
|
||||||
List_MiniItem_struct(mli) => match dump.remove(&mli.pxNext).expect("MiniListItem pointer invaild") {
|
|
||||||
List_Item_struct(li) => li,
|
|
||||||
_ => panic!("MiniListItem of a non empty List does not point to ListItem"),
|
|
||||||
},
|
|
||||||
_ => panic!("List_t entry was not a ListItem"),
|
|
||||||
};
|
|
||||||
match dump.remove(&next_list_item.pvOwner).expect("ListItem Owner not in Hashmap") {
|
|
||||||
TCB_struct(t) => {ret.push(t)},
|
|
||||||
_ => panic!("List content does not equal type"),
|
|
||||||
}
|
|
||||||
next_index=next_list_item.pxNext;
|
|
||||||
}
|
|
||||||
ret.push(last_tcb);
|
|
||||||
ret
|
|
||||||
}
|
|
||||||
//============================= Feedback
|
|
||||||
|
|
||||||
/// Shared Metadata for a SysStateFeedback
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
|
|
||||||
pub struct SysStateFeedbackState
|
|
||||||
{
|
|
||||||
known_traces: HashMap<u64,(u64,u64,usize)>, // encounters,ticks,length
|
|
||||||
longest: Vec<MiniFreeRTOSSystemState>,
|
|
||||||
}
|
|
||||||
impl Named for SysStateFeedbackState
|
|
||||||
{
|
|
||||||
#[inline]
|
|
||||||
fn name(&self) -> &str {
|
|
||||||
"sysstate"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl FeedbackState for SysStateFeedbackState
|
|
||||||
{
|
|
||||||
fn reset(&mut self) -> Result<(), Error> {
|
|
||||||
self.longest.clear();
|
|
||||||
self.known_traces.clear();
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A Feedback reporting novel System-State Transitions
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
|
|
||||||
pub struct NovelSysStateFeedback
|
|
||||||
{
|
|
||||||
last_trace: Option<Vec<MiniFreeRTOSSystemState>>,
|
|
||||||
// known_traces: HashMap<u64,(u64,usize)>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I, S> Feedback<I, S> for NovelSysStateFeedback
|
|
||||||
where
|
|
||||||
I: Input,
|
|
||||||
S: HasClientPerfMonitor + HasFeedbackStates,
|
|
||||||
{
|
|
||||||
fn is_interesting<EM, OT>(
|
|
||||||
&mut self,
|
|
||||||
state: &mut S,
|
|
||||||
_manager: &mut EM,
|
|
||||||
_input: &I,
|
|
||||||
observers: &OT,
|
|
||||||
_exit_kind: &ExitKind,
|
|
||||||
) -> Result<bool, Error>
|
|
||||||
where
|
|
||||||
EM: EventFirer<I>,
|
|
||||||
OT: ObserversTuple<I, S>,
|
|
||||||
{
|
|
||||||
let observer = observers.match_name::<QemuSysStateObserver>("sysstate")
|
|
||||||
.expect("QemuSysStateObserver not found");
|
|
||||||
let clock_observer = observers.match_name::<QemuClockObserver>("clock") //TODO not fixed
|
|
||||||
.expect("QemuSysStateObserver not found");
|
|
||||||
let feedbackstate = state
|
|
||||||
.feedback_states_mut()
|
|
||||||
.match_name_mut::<SysStateFeedbackState>("sysstate")
|
|
||||||
.unwrap();
|
|
||||||
// Do Stuff
|
|
||||||
let mut hasher = DefaultHasher::new();
|
|
||||||
observer.last_run.hash(&mut hasher);
|
|
||||||
let somehash = hasher.finish();
|
|
||||||
let mut is_novel = false;
|
|
||||||
let mut takes_longer = false;
|
|
||||||
match feedbackstate.known_traces.get_mut(&somehash) {
|
|
||||||
None => {
|
|
||||||
is_novel = true;
|
|
||||||
feedbackstate.known_traces.insert(somehash,(1,clock_observer.last_runtime(),observer.last_run.len()));
|
|
||||||
}
|
|
||||||
Some(s) => {
|
|
||||||
s.0+=1;
|
|
||||||
if s.1 < clock_observer.last_runtime() {
|
|
||||||
s.1 = clock_observer.last_runtime();
|
|
||||||
takes_longer = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if observer.last_run.len() > feedbackstate.longest.len() {
|
|
||||||
feedbackstate.longest=observer.last_run.clone();
|
|
||||||
}
|
|
||||||
self.last_trace = Some(observer.last_run.clone());
|
|
||||||
// if (!is_novel) { println!("not novel") };
|
|
||||||
Ok(is_novel | takes_longer)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Append to the testcase the generated metadata in case of a new corpus item
|
|
||||||
#[inline]
|
|
||||||
fn append_metadata(&mut self, _state: &mut S, testcase: &mut Testcase<I>) -> Result<(), Error> {
|
|
||||||
let a = self.last_trace.take();
|
|
||||||
match a {
|
|
||||||
Some(s) => testcase.metadata_mut().insert(FreeRTOSSystemStateMetadata::new(s)),
|
|
||||||
None => (),
|
|
||||||
}
|
|
||||||
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: &I) -> Result<(), Error> {
|
|
||||||
self.last_trace = None;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Named for NovelSysStateFeedback
|
|
||||||
{
|
|
||||||
#[inline]
|
|
||||||
fn name(&self) -> &str {
|
|
||||||
"sysstate"
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user