refactoring
This commit is contained in:
parent
cc2a2e6422
commit
f7e61665be
@ -1,6 +1,6 @@
|
|||||||
BDIR=remote
|
BDIR=remote
|
||||||
plot () {
|
plot () {
|
||||||
[ ! -f ~/code/FRET/LibAFL/fuzzers/FRET/benchmark/$BDIR/${1}${2}_all.png ] && Rscript plot_multi.r $BDIR/timedump ${1}${2} ~/code/FRET/LibAFL/fuzzers/FRET/benchmark/$BDIR
|
[ ! -f ../benchmark/$BDIR/${1}${2}_all.png ] && Rscript plot_multi.r $BDIR/timedump ${1}${2} ../benchmark/$BDIR
|
||||||
}
|
}
|
||||||
|
|
||||||
# Only bytes
|
# Only bytes
|
||||||
|
@ -24,5 +24,5 @@ do
|
|||||||
# fi
|
# fi
|
||||||
done < <(find ./remote/timedump -maxdepth 2 -type 'f' -iregex '.*\.case')
|
done < <(find ./remote/timedump -maxdepth 2 -type 'f' -iregex '.*\.case')
|
||||||
|
|
||||||
# echo "${PLOTS[@]}"
|
echo "${PLOTS[@]}"
|
||||||
snakemake -c 6 --keep-incomplete "${PLOTS[@]}"
|
snakemake -c 6 --rerun-incomplete --keep-incomplete "${PLOTS[@]}"
|
||||||
|
@ -16,7 +16,7 @@ if (length(args)==0) {
|
|||||||
target="waters"
|
target="waters"
|
||||||
#target="waters_int"
|
#target="waters_int"
|
||||||
#target="watersv2_int"
|
#target="watersv2_int"
|
||||||
outputpath="~/code/FRET/LibAFL/fuzzers/FRET/benchmark/"
|
outputpath="../benchmark"
|
||||||
#MY_SELECTION <- c('state', 'afl', 'graph', 'random')
|
#MY_SELECTION <- c('state', 'afl', 'graph', 'random')
|
||||||
SAVE_FILE=TRUE
|
SAVE_FILE=TRUE
|
||||||
} else {
|
} else {
|
||||||
@ -39,7 +39,7 @@ if (is.null(worst_case)) {
|
|||||||
|
|
||||||
#MY_COLORS=c("green","blue","red", "orange", "pink", "black")
|
#MY_COLORS=c("green","blue","red", "orange", "pink", "black")
|
||||||
MY_COLORS <- c("green", "blue", "red", "magenta", "orange", "cyan", "pink", "gray", "orange", "black", "yellow","brown")
|
MY_COLORS <- c("green", "blue", "red", "magenta", "orange", "cyan", "pink", "gray", "orange", "black", "yellow","brown")
|
||||||
BENCHDIR=sprintf("~/code/FRET/LibAFL/fuzzers/FRET/benchmark/%s",runtype)
|
BENCHDIR=sprintf("../benchmark/%s",runtype)
|
||||||
BASENAMES=Filter(function(x) x!="" && substr(x,1,1)!='.',list.dirs(BENCHDIR,full.names=FALSE))
|
BASENAMES=Filter(function(x) x!="" && substr(x,1,1)!='.',list.dirs(BENCHDIR,full.names=FALSE))
|
||||||
PATTERNS="%s#[0-9]*.time$"
|
PATTERNS="%s#[0-9]*.time$"
|
||||||
#RIBBON='sd'
|
#RIBBON='sd'
|
||||||
|
@ -77,7 +77,7 @@ pub fn get_target_symbols(elf: &EasyElf) -> HashMap<&'static str, GuestAddr> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_target_ranges(
|
pub fn get_target_ranges(
|
||||||
elf: &EasyElf,
|
_elf: &EasyElf,
|
||||||
symbols: &HashMap<&'static str, GuestAddr>,
|
symbols: &HashMap<&'static str, GuestAddr>,
|
||||||
) -> HashMap<&'static str, std::ops::Range<GuestAddr>> {
|
) -> HashMap<&'static str, std::ops::Range<GuestAddr>> {
|
||||||
let mut ranges = HashMap::new();
|
let mut ranges = HashMap::new();
|
||||||
@ -91,7 +91,5 @@ pub fn get_target_ranges(
|
|||||||
symbols["__API_CODE_START__"]..symbols["__API_CODE_END__"],
|
symbols["__API_CODE_START__"]..symbols["__API_CODE_END__"],
|
||||||
);
|
);
|
||||||
|
|
||||||
crate::systemstate::target_os::freertos::config::add_target_ranges(elf, symbols, &mut ranges);
|
|
||||||
|
|
||||||
ranges
|
ranges
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@ elf::EasyElf, emu::Emulator, modules::{edges::{self}, EdgeCoverageModule, Filter
|
|||||||
use libafl_targets::{edges_map_mut_ptr, EDGES_MAP_DEFAULT_SIZE, MAX_EDGES_FOUND};
|
use libafl_targets::{edges_map_mut_ptr, EDGES_MAP_DEFAULT_SIZE, MAX_EDGES_FOUND};
|
||||||
use rand::{SeedableRng, StdRng, Rng};
|
use rand::{SeedableRng, StdRng, Rng};
|
||||||
use crate::{
|
use crate::{
|
||||||
config::{get_target_ranges, get_target_symbols}, systemstate::{self, feedbacks::{DumpSystraceFeedback, SystraceErrorFeedback}, helpers::{get_function_range, load_symbol, try_load_symbol}, mutational::{input_bytes_to_interrupt_times, InterruptShiftStage, STGSnippetStage}, observers::QemuSystemStateObserver, schedulers::{GenerationScheduler, LongestTraceScheduler}, stg::{stg_map_mut_slice, GraphMaximizerCorpusScheduler, STGEdge, STGNode, StgFeedback, MAX_STG_NUM}, target_os::freertos::{config::get_range_groups, qemu_module::FreeRTOSSystemStateHelper, FreeRTOSSystem}}, time::{
|
config::{get_target_ranges, get_target_symbols}, systemstate::{self, feedbacks::{DumpSystraceFeedback, SystraceErrorFeedback}, helpers::{get_function_range, input_bytes_to_interrupt_times, load_symbol, try_load_symbol}, mutational::{InterruptShiftStage, STGSnippetStage}, schedulers::{GenerationScheduler, LongestTraceScheduler}, stg::{stg_map_mut_slice, GraphMaximizerCorpusScheduler, STGEdge, STGNode, StgFeedback, MAX_STG_NUM}, target_os::freertos::{config::get_range_groups, qemu_module::FreeRTOSSystemStateHelper, FreeRTOSSystem}}, time::{
|
||||||
clock::{ClockTimeFeedback, IcHist, QemuClockIncreaseFeedback, QemuClockObserver, FUZZ_START_TIMESTAMP, QEMU_ICOUNT_SHIFT, QEMU_ISNS_PER_USEC}, qemustate::QemuStateRestoreHelper, worst::{AlwaysTrueFeedback, ExecTimeIncFeedback, RateLimitedMonitor, TimeMaximizerCorpusScheduler, TimeProbMassScheduler, TimeStateMaximizerCorpusScheduler}
|
clock::{ClockTimeFeedback, IcHist, QemuClockIncreaseFeedback, QemuClockObserver, FUZZ_START_TIMESTAMP, QEMU_ICOUNT_SHIFT, QEMU_ISNS_PER_USEC}, qemustate::QemuStateRestoreHelper, worst::{AlwaysTrueFeedback, ExecTimeIncFeedback, RateLimitedMonitor, TimeMaximizerCorpusScheduler, TimeProbMassScheduler, TimeStateMaximizerCorpusScheduler}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -322,7 +322,7 @@ let run_client = |state: Option<_>, mut mgr, _core_id| {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Create an observation channel to keep track of the execution time
|
// Create an observation channel to keep track of the execution time
|
||||||
let clock_time_observer = QemuClockObserver::new("clocktime", if cli.dump_times {cli.dump_name.clone().map(|x| x.with_extension("time"))} else {None} );
|
let clock_time_observer = QemuClockObserver::new("clocktime"); // if cli.dump_times {cli.dump_name.clone().map(|x| x.with_extension("time"))} else {None}
|
||||||
|
|
||||||
// Create an observation channel using the coverage map
|
// Create an observation channel using the coverage map
|
||||||
#[cfg(feature = "observe_edges")]
|
#[cfg(feature = "observe_edges")]
|
||||||
@ -343,14 +343,11 @@ let run_client = |state: Option<_>, mut mgr, _core_id| {
|
|||||||
addr_of_mut!(MAX_STG_NUM)
|
addr_of_mut!(MAX_STG_NUM)
|
||||||
)}.track_indices();
|
)}.track_indices();
|
||||||
|
|
||||||
#[cfg(feature = "observe_systemstate")]
|
|
||||||
let systemstate_observer = QemuSystemStateObserver::<_,FreeRTOSSystem>::new(&cli.select_task);
|
|
||||||
|
|
||||||
// Feedback to rate the interestingness of an input
|
// Feedback to rate the interestingness of an input
|
||||||
// This one is composed by two Feedbacks in OR
|
// This one is composed by two Feedbacks in OR
|
||||||
let mut feedback = feedback_or!(
|
let mut feedback = feedback_or!(
|
||||||
// Time feedback, this one does not need a feedback state
|
// Time feedback, this one does not need a feedback state
|
||||||
ClockTimeFeedback::<FreeRTOSSystem>::new_with_observer(&clock_time_observer, &cli.select_task)
|
ClockTimeFeedback::<FreeRTOSSystem>::new_with_observer(&clock_time_observer, &cli.select_task, if cli.dump_times {cli.dump_name.clone().map(|x| x.with_extension("time"))} else {None})
|
||||||
);
|
);
|
||||||
#[cfg(feature = "feed_genetic")]
|
#[cfg(feature = "feed_genetic")]
|
||||||
let mut feedback = feedback_or!(
|
let mut feedback = feedback_or!(
|
||||||
@ -373,12 +370,12 @@ let run_client = |state: Option<_>, mut mgr, _core_id| {
|
|||||||
#[cfg(all(feature = "observe_systemstate"))]
|
#[cfg(all(feature = "observe_systemstate"))]
|
||||||
let mut feedback = feedback_or!(
|
let mut feedback = feedback_or!(
|
||||||
feedback,
|
feedback,
|
||||||
DumpSystraceFeedback::<FreeRTOSSystem>::with_dump(if cli.dump_traces {cli.dump_name.clone().map(|x| x.with_extension("trace.ron"))} else {None}, &cli.select_task)
|
DumpSystraceFeedback::<FreeRTOSSystem>::with_dump(if cli.dump_traces {cli.dump_name.clone().map(|x| x.with_extension("trace.ron"))} else {None})
|
||||||
);
|
);
|
||||||
#[cfg(feature = "trace_stg")]
|
#[cfg(feature = "trace_stg")]
|
||||||
let mut feedback = feedback_or!(
|
let mut feedback = feedback_or!(
|
||||||
feedback,
|
feedback,
|
||||||
StgFeedback::<FreeRTOSSystem>::new(if cli.dump_graph {cli.dump_name.clone()} else {None})
|
StgFeedback::<FreeRTOSSystem>::new(cli.select_task.clone(), if cli.dump_graph {cli.dump_name.clone()} else {None})
|
||||||
);
|
);
|
||||||
#[cfg(feature = "feed_stg_edge")]
|
#[cfg(feature = "feed_stg_edge")]
|
||||||
let mut feedback = feedback_or!(
|
let mut feedback = feedback_or!(
|
||||||
@ -441,7 +438,7 @@ let run_client = |state: Option<_>, mut mgr, _core_id| {
|
|||||||
|
|
||||||
let observer_list = tuple_list!();
|
let observer_list = tuple_list!();
|
||||||
#[cfg(feature = "observe_systemstate")]
|
#[cfg(feature = "observe_systemstate")]
|
||||||
let observer_list = (systemstate_observer, (stg_coverage_observer, observer_list)); // must come after clock
|
let observer_list = (stg_coverage_observer, observer_list); // must come after clock
|
||||||
#[cfg(feature = "observe_edges")]
|
#[cfg(feature = "observe_edges")]
|
||||||
let observer_list = (edges_observer, observer_list);
|
let observer_list = (edges_observer, observer_list);
|
||||||
let observer_list = (clock_time_observer, observer_list);
|
let observer_list = (clock_time_observer, observer_list);
|
||||||
|
@ -3,4 +3,10 @@
|
|||||||
- ``fuzzer.rs`` resolves symbols and creates ``api_ranges`` and ``isr_ranges``
|
- ``fuzzer.rs`` resolves symbols and creates ``api_ranges`` and ``isr_ranges``
|
||||||
- ``helpers::QemuSystemStateHelper`` captures a series of ``RawFreeRTOSSystemState``
|
- ``helpers::QemuSystemStateHelper`` captures a series of ``RawFreeRTOSSystemState``
|
||||||
- ``observers::QemuSystemStateObserver`` divides this into ``ReducedFreeRTOSSystemState`` and ``ExecInterval``, the first contains the raw states and the second contains information about the flow between states
|
- ``observers::QemuSystemStateObserver`` divides this into ``ReducedFreeRTOSSystemState`` and ``ExecInterval``, the first contains the raw states and the second contains information about the flow between states
|
||||||
- ``stg::StgFeedback`` builds an stg from the intervals
|
- ``stg::StgFeedback`` builds an stg from the intervals
|
||||||
|
## Target-specific (systemstate/target_os)
|
||||||
|
- config ``add_target_symbols`` and ``get_range_groups`` resolve important symbols
|
||||||
|
- provides a helper (e.g. ``FreeRTOSSystemStateHelper`` ) to capture the state
|
||||||
|
- collects locally into e.g. ``CURRENT_SYSTEMSTATE_VEC``
|
||||||
|
- post-processing
|
||||||
|
- replaces ``SystemTraceData`` in state metadata
|
@ -1,179 +1,23 @@
|
|||||||
use crate::time::clock::QemuClockObserver;
|
use libafl::{
|
||||||
use hashbrown::HashMap;
|
common::HasMetadata,
|
||||||
use libafl::common::HasNamedMetadata;
|
executors::ExitKind,
|
||||||
use libafl::corpus::Testcase;
|
feedbacks::Feedback,
|
||||||
|
observers::ObserversTuple,
|
||||||
|
prelude::{State, UsesInput},
|
||||||
|
state::MaybeHasClientPerfMonitor,
|
||||||
|
Error,
|
||||||
|
};
|
||||||
use libafl::events::EventFirer;
|
use libafl::events::EventFirer;
|
||||||
use libafl::feedbacks::Feedback;
|
|
||||||
use libafl::prelude::State;
|
|
||||||
use libafl::prelude::UsesInput;
|
|
||||||
use libafl::state::MaybeHasClientPerfMonitor;
|
|
||||||
use libafl::Error;
|
|
||||||
use libafl::{common::HasMetadata, executors::ExitKind, observers::ObserversTuple};
|
|
||||||
use libafl_bolts::Named;
|
use libafl_bolts::Named;
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use std::collections::hash_map::DefaultHasher;
|
|
||||||
use std::hash::Hash;
|
|
||||||
use std::hash::Hasher;
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use super::observers::QemuSystemStateObserver;
|
|
||||||
use super::target_os::TargetSystem;
|
use super::target_os::TargetSystem;
|
||||||
use super::ExecInterval;
|
|
||||||
use libafl_bolts::prelude::SerdeAny;
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
use crate::systemstate::target_os::*;
|
use crate::systemstate::target_os::*;
|
||||||
use libafl::prelude::StateInitializer;
|
use libafl::prelude::StateInitializer;
|
||||||
|
|
||||||
//============================= Feedback
|
|
||||||
|
|
||||||
/// Shared Metadata for a systemstateFeedback
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
|
||||||
pub struct SystemStateFeedbackState<SYS>
|
|
||||||
where
|
|
||||||
SYS: TargetSystem,
|
|
||||||
{
|
|
||||||
name: Cow<'static, str>,
|
|
||||||
known_traces: HashMap<u64, (u64, u64, usize)>, // encounters,ticks,length
|
|
||||||
longest: Vec<SYS::State>,
|
|
||||||
}
|
|
||||||
libafl_bolts::impl_serdeany!(SystemStateFeedbackState<SYS: SerdeAny+TargetSystem>);
|
|
||||||
|
|
||||||
impl<SYS> Named for SystemStateFeedbackState<SYS>
|
|
||||||
where
|
|
||||||
SYS: TargetSystem,
|
|
||||||
{
|
|
||||||
#[inline]
|
|
||||||
fn name(&self) -> &Cow<'static, str> {
|
|
||||||
&self.name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<SYS> Default for SystemStateFeedbackState<SYS>
|
|
||||||
where
|
|
||||||
SYS: TargetSystem,
|
|
||||||
{
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
name: Cow::from("systemstate".to_string()),
|
|
||||||
known_traces: HashMap::new(),
|
|
||||||
longest: Vec::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// /// A Feedback reporting novel System-State Transitions. Depends on [`QemuSystemStateObserver`]
|
|
||||||
// #[derive(Serialize, Deserialize, Clone, Debug)]
|
|
||||||
// pub struct NovelSystemStateFeedback
|
|
||||||
// {
|
|
||||||
// name: Cow<'static, str>,
|
|
||||||
// last_trace: Option<Vec<ReducedFreeRTOSSystemState>>,
|
|
||||||
// // known_traces: HashMap<u64,(u64,usize)>,
|
|
||||||
// }
|
|
||||||
|
|
||||||
// impl<S> StateInitializer<S> for NovelSystemStateFeedback {}
|
|
||||||
|
|
||||||
// impl<EM, I, OT, S> Feedback<EM, I, OT, S> for NovelSystemStateFeedback
|
|
||||||
// where
|
|
||||||
// S: State + UsesInput + MaybeHasClientPerfMonitor + HasNamedMetadata,
|
|
||||||
// S::Input: Default,
|
|
||||||
// EM: EventFirer<State = S>,
|
|
||||||
// OT: ObserversTuple<I, S>,
|
|
||||||
// {
|
|
||||||
// fn is_interesting(
|
|
||||||
// &mut self,
|
|
||||||
// state: &mut S,
|
|
||||||
// _manager: &mut EM,
|
|
||||||
// _input: &I,
|
|
||||||
// observers: &OT,
|
|
||||||
// _exit_kind: &ExitKind,
|
|
||||||
// ) -> Result<bool, Error>
|
|
||||||
// where
|
|
||||||
// {
|
|
||||||
// let observer : &QemuSystemStateObserver<S::Input> = observers.match_name::<QemuSystemStateObserver<S::Input>>("systemstate")
|
|
||||||
// .expect("QemuSystemStateObserver not found");
|
|
||||||
// let clock_observer = observers.match_name::<QemuClockObserver>("clocktime") //TODO not fixed
|
|
||||||
// .expect("QemuClockObserver not found");
|
|
||||||
// let feedbackstate = match state
|
|
||||||
// .named_metadata_map_mut()
|
|
||||||
// .get_mut::<SystemStateFeedbackState>("systemstate") {
|
|
||||||
// Some(s) => s,
|
|
||||||
// Option::None => {
|
|
||||||
// let n=SystemStateFeedbackState::default();
|
|
||||||
// state.named_metadata_map_mut().insert("systemstate",n);
|
|
||||||
// state.named_metadata_map_mut().get_mut::<SystemStateFeedbackState>("systemstate").unwrap()
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
// #[cfg(feature = "trace_job_response_times")]
|
|
||||||
// let last_runtime = observer.last_runtime();
|
|
||||||
// #[cfg(not(feature = "trace_job_response_times"))]
|
|
||||||
// let last_runtime = clock_observer.last_runtime();
|
|
||||||
// // let feedbackstate = state
|
|
||||||
// // .feedback_states_mut()
|
|
||||||
// // .match_name_mut::<systemstateFeedbackState>("systemstate")
|
|
||||||
// // .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) {
|
|
||||||
// Option::None => {
|
|
||||||
// is_novel = true;
|
|
||||||
// feedbackstate.known_traces.insert(somehash,(1,last_runtime,observer.last_run.len()));
|
|
||||||
// }
|
|
||||||
// Some(s) => {
|
|
||||||
// s.0+=1;
|
|
||||||
// if s.1 < last_runtime {
|
|
||||||
// s.1 = 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, _manager: &mut EM, _observers: &OT, testcase: &mut Testcase<I>) -> Result<(), Error> {
|
|
||||||
// let a = self.last_trace.take();
|
|
||||||
// match a {
|
|
||||||
// Some(s) => testcase.metadata_map_mut().insert(FreeRTOSSystemStateMetadata::new(s)),
|
|
||||||
// Option::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 NovelSystemStateFeedback
|
|
||||||
// {
|
|
||||||
// #[inline]
|
|
||||||
// fn name(&self) -> &Cow<'static, str> {
|
|
||||||
// &self.name
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// impl Default for NovelSystemStateFeedback
|
|
||||||
// {
|
|
||||||
// fn default() -> Self {
|
|
||||||
// Self {name: Cow::from("NovelSystemStateFeedback".to_string()), last_trace: None }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
//=========================== Debugging Feedback
|
//=========================== Debugging Feedback
|
||||||
/// A [`Feedback`] meant to dump the system-traces for debugging. Depends on [`QemuSystemStateObserver`]
|
/// A [`Feedback`] meant to dump the system-traces for debugging. Depends on [`QemuSystemStateObserver`]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -183,8 +27,6 @@ where
|
|||||||
{
|
{
|
||||||
name: Cow<'static, str>,
|
name: Cow<'static, str>,
|
||||||
dumpfile: Option<PathBuf>,
|
dumpfile: Option<PathBuf>,
|
||||||
dump_metadata: bool,
|
|
||||||
select_task: Option<String>, // TODO: use some global config for this
|
|
||||||
phantom: PhantomData<SYS>,
|
phantom: PhantomData<SYS>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -206,122 +48,25 @@ where
|
|||||||
_exit_kind: &ExitKind,
|
_exit_kind: &ExitKind,
|
||||||
) -> Result<bool, Error>
|
) -> Result<bool, Error>
|
||||||
where {
|
where {
|
||||||
if self.dumpfile.is_none() {
|
|
||||||
return Ok(false);
|
|
||||||
};
|
|
||||||
let trace = state
|
|
||||||
.metadata::<SYS::TraceData>()
|
|
||||||
.expect("TraceData not found");
|
|
||||||
|
|
||||||
let names: Vec<String> = trace
|
|
||||||
.states()
|
|
||||||
.iter()
|
|
||||||
.map(|x| x.current_task().task_name().clone())
|
|
||||||
.collect();
|
|
||||||
match &self.dumpfile {
|
match &self.dumpfile {
|
||||||
Some(s) => {
|
Some(s) => {
|
||||||
let per_task_metadata = if let Some(worst_instance) = trace.worst_jobs_per_task_by_time().get(self.select_task.as_ref().unwrap_or(&"".to_string()))
|
let trace = state
|
||||||
{
|
.metadata::<SYS::TraceData>()
|
||||||
// extract computation time spent in each task and abb
|
.expect("TraceData not found");
|
||||||
let t: Vec<_> = trace.intervals()
|
|
||||||
.iter()
|
|
||||||
.filter(|x| {
|
|
||||||
x.start_tick < worst_instance.response
|
|
||||||
&& x.end_tick > worst_instance.release
|
|
||||||
})
|
|
||||||
.cloned()
|
|
||||||
.collect();
|
|
||||||
// task_name -> addr -> (count, time)
|
|
||||||
let mut ret: HashMap<String, HashMap<u32, (usize, usize, u64)>> =
|
|
||||||
HashMap::new();
|
|
||||||
let mut t2 = t.clone();
|
|
||||||
t2.sort_by_key(|x| x.get_task_name_unchecked());
|
|
||||||
t2.chunk_by_mut(|x, y| {
|
|
||||||
x.get_task_name_unchecked() == y.get_task_name_unchecked()
|
|
||||||
})
|
|
||||||
.for_each(|x| {
|
|
||||||
x.sort_by_key(|y| y.abb.as_ref().unwrap().start);
|
|
||||||
x.chunk_by(|y, z| {
|
|
||||||
y.abb.as_ref().unwrap().start == z.abb.as_ref().unwrap().start
|
|
||||||
})
|
|
||||||
.for_each(|y| {
|
|
||||||
match ret.get_mut(&y[0].get_task_name_unchecked()) {
|
|
||||||
Option::None => {
|
|
||||||
ret.insert(
|
|
||||||
y[0].get_task_name_unchecked(),
|
|
||||||
HashMap::from([(
|
|
||||||
y[0].abb.as_ref().unwrap().start,
|
|
||||||
(
|
|
||||||
y.len(),
|
|
||||||
y.iter().filter(|x| x.is_abb_end()).count(),
|
|
||||||
y.iter().map(|z| z.get_exec_time()).sum::<_>(),
|
|
||||||
),
|
|
||||||
)]),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Some(x) => {
|
|
||||||
x.insert(
|
|
||||||
y[0].abb.as_ref().unwrap().start,
|
|
||||||
(
|
|
||||||
y.len(),
|
|
||||||
y.iter().filter(|x| x.is_abb_end()).count(),
|
|
||||||
y.iter().map(|z| z.get_exec_time()).sum(),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
// dbg!(&ret);
|
|
||||||
ret
|
|
||||||
} else {
|
|
||||||
HashMap::new()
|
|
||||||
};
|
|
||||||
std::fs::write(
|
std::fs::write(
|
||||||
s,
|
s,
|
||||||
ron::to_string(&(
|
ron::to_string(trace)
|
||||||
&trace,
|
.expect("Error serializing hashmap"),
|
||||||
per_task_metadata,
|
|
||||||
))
|
|
||||||
.expect("Error serializing hashmap"),
|
|
||||||
)
|
)
|
||||||
.expect("Can not dump to file");
|
.expect("Can not dump to file");
|
||||||
self.dumpfile = None
|
self.dumpfile = None
|
||||||
}
|
}
|
||||||
Option::None => {
|
Option::None => {
|
||||||
if self.dump_metadata {
|
()
|
||||||
println!("{:?}\n{:?}", trace, names);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
// if self.dump_metadata {self.last_trace=Some(observer.last_trace.clone());}
|
|
||||||
Ok(false)
|
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,
|
|
||||||
_manager: &mut EM,
|
|
||||||
_observers: &OT,
|
|
||||||
_testcase: &mut Testcase<I>,
|
|
||||||
) -> Result<(), Error> {
|
|
||||||
if !self.dump_metadata {
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
// let a = self.last_trace.take();
|
|
||||||
// match a {
|
|
||||||
// Some(s) => testcase.metadata_map_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> {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<SYS> Named for DumpSystraceFeedback<SYS>
|
impl<SYS> Named for DumpSystraceFeedback<SYS>
|
||||||
@ -344,29 +89,15 @@ where
|
|||||||
Self {
|
Self {
|
||||||
name: Cow::from("Dumpsystemstate".to_string()),
|
name: Cow::from("Dumpsystemstate".to_string()),
|
||||||
dumpfile: None,
|
dumpfile: None,
|
||||||
dump_metadata: false,
|
|
||||||
phantom: PhantomData,
|
phantom: PhantomData,
|
||||||
select_task: None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
pub fn with_dump(dumpfile: Option<PathBuf>, select_task: &Option<String>) -> Self {
|
pub fn with_dump(dumpfile: Option<PathBuf>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
name: Cow::from("Dumpsystemstate".to_string()),
|
name: Cow::from("Dumpsystemstate".to_string()),
|
||||||
dumpfile: dumpfile,
|
dumpfile: dumpfile,
|
||||||
dump_metadata: false,
|
|
||||||
phantom: PhantomData,
|
phantom: PhantomData,
|
||||||
select_task: select_task.clone(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[allow(unused)]
|
|
||||||
pub fn metadata_only() -> Self {
|
|
||||||
Self {
|
|
||||||
name: Cow::from("Dumpsystemstate".to_string()),
|
|
||||||
dumpfile: None,
|
|
||||||
dump_metadata: true,
|
|
||||||
phantom: PhantomData,
|
|
||||||
select_task: None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -386,58 +117,43 @@ impl<S, SYS> StateInitializer<S> for SystraceErrorFeedback<SYS> where SYS: Targe
|
|||||||
|
|
||||||
impl<EM, I, OT, S, SYS> Feedback<EM, I, OT, S> for SystraceErrorFeedback<SYS>
|
impl<EM, I, OT, S, SYS> Feedback<EM, I, OT, S> for SystraceErrorFeedback<SYS>
|
||||||
where
|
where
|
||||||
S: State + UsesInput + MaybeHasClientPerfMonitor,
|
S: State + UsesInput + MaybeHasClientPerfMonitor + HasMetadata,
|
||||||
EM: EventFirer<State = S>,
|
EM: EventFirer<State = S>,
|
||||||
OT: ObserversTuple<I, S>,
|
OT: ObserversTuple<I, S>,
|
||||||
SYS: TargetSystem,
|
SYS: TargetSystem,
|
||||||
{
|
{
|
||||||
fn is_interesting(
|
fn is_interesting(
|
||||||
&mut self,
|
&mut self,
|
||||||
_state: &mut S,
|
state: &mut S,
|
||||||
_manager: &mut EM,
|
_manager: &mut EM,
|
||||||
_input: &I,
|
_input: &I,
|
||||||
observers: &OT,
|
_observers: &OT,
|
||||||
_exit_kind: &ExitKind,
|
_exit_kind: &ExitKind,
|
||||||
) -> Result<bool, Error>
|
) -> Result<bool, Error>
|
||||||
where {
|
where {
|
||||||
#[cfg(feature = "trace_stg")]
|
#[cfg(feature = "trace_stg")]
|
||||||
{
|
{
|
||||||
let observer = observers
|
|
||||||
.match_name::<QemuSystemStateObserver<S::Input, SYS>>("systemstate")
|
|
||||||
.expect("QemuSystemStateObserver not found");
|
|
||||||
let is_err = (!observer.success || observer.do_report);
|
|
||||||
if let Some(m) = self.max_reports {
|
if let Some(m) = self.max_reports {
|
||||||
if m <= 0 {
|
if m <= 0 {
|
||||||
return Ok(false);
|
return Ok(false);
|
||||||
}
|
}
|
||||||
if is_err {
|
let need_to_debug = state
|
||||||
|
.metadata::<SYS::TraceData>()
|
||||||
|
.expect("TraceData not found")
|
||||||
|
.need_to_debug();
|
||||||
|
if need_to_debug {
|
||||||
self.max_reports = Some(m - 1);
|
self.max_reports = Some(m - 1);
|
||||||
}
|
}
|
||||||
|
return Ok(self.dump_case && need_to_debug);
|
||||||
|
} else {
|
||||||
|
return Ok(false);
|
||||||
}
|
}
|
||||||
return Ok(self.dump_case && is_err);
|
|
||||||
}
|
}
|
||||||
#[cfg(not(feature = "trace_stg"))]
|
#[cfg(not(feature = "trace_stg"))]
|
||||||
{
|
{
|
||||||
return Ok(false);
|
return 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,
|
|
||||||
_manager: &mut EM,
|
|
||||||
_observers: &OT,
|
|
||||||
_testcase: &mut Testcase<I>,
|
|
||||||
) -> 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: &I) -> Result<(), Error> {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<SYS> Named for SystraceErrorFeedback<SYS>
|
impl<SYS> Named for SystraceErrorFeedback<SYS>
|
||||||
|
@ -1,29 +1,18 @@
|
|||||||
use std::ops::Range;
|
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
use hashbrown::HashSet;
|
use libafl_bolts::prelude::{SerdeAny, SerdeAnyMap};
|
||||||
use libafl::prelude::ExitKind;
|
use libafl_qemu::{elf::EasyElf, read_user_reg_unchecked, GuestAddr, GuestPhysAddr};
|
||||||
use libafl::prelude::UsesInput;
|
use std::ops::Range;
|
||||||
use libafl_qemu::elf::EasyElf;
|
use std::cmp::min;
|
||||||
use libafl_qemu::modules::NopAddressFilter;
|
|
||||||
use libafl_qemu::modules::NopPageFilter;
|
|
||||||
use libafl_qemu::read_user_reg_unchecked;
|
|
||||||
use libafl_qemu::GuestAddr;
|
|
||||||
use libafl_qemu::GuestPhysAddr;
|
|
||||||
use libafl_qemu::QemuHooks;
|
|
||||||
use libafl_qemu::Hook;
|
|
||||||
use libafl_qemu::modules::{EmulatorModule, EmulatorModuleTuple};
|
|
||||||
use libafl_qemu::sys::TCGTemp;
|
|
||||||
use libafl_qemu::qemu::MemAccessInfo;
|
|
||||||
|
|
||||||
use super::CaptureEvent;
|
|
||||||
use libafl_qemu::EmulatorModules;
|
|
||||||
use libafl::prelude::ObserversTuple;
|
|
||||||
|
|
||||||
|
use crate::{fuzzer::{DO_NUM_INTERRUPT, FIRST_INT}, time::clock::QEMU_ISNS_PER_USEC};
|
||||||
|
|
||||||
|
use super::{
|
||||||
|
target_os::{SystemTraceData, TargetSystem},
|
||||||
|
ExecInterval,
|
||||||
|
};
|
||||||
|
|
||||||
//============================= API symbols
|
//============================= API symbols
|
||||||
|
|
||||||
|
|
||||||
/// Read ELF program headers to resolve physical load addresses.
|
/// Read ELF program headers to resolve physical load addresses.
|
||||||
fn virt2phys(vaddr: GuestPhysAddr, tab: &EasyElf) -> GuestPhysAddr {
|
fn virt2phys(vaddr: GuestPhysAddr, tab: &EasyElf) -> GuestPhysAddr {
|
||||||
let ret;
|
let ret;
|
||||||
@ -38,24 +27,28 @@ fn virt2phys(vaddr: GuestPhysAddr, tab: &EasyElf) -> GuestPhysAddr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Lookup a symbol in the ELF file, optionally resolve segment offsets
|
/// Lookup a symbol in the ELF file, optionally resolve segment offsets
|
||||||
pub fn load_symbol(elf : &EasyElf, symbol : &str, do_translation : bool) -> GuestAddr {
|
pub fn load_symbol(elf: &EasyElf, symbol: &str, do_translation: bool) -> GuestAddr {
|
||||||
try_load_symbol(elf, symbol, do_translation).expect(&format!("Symbol {} not found", symbol))
|
try_load_symbol(elf, symbol, do_translation).expect(&format!("Symbol {} not found", symbol))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn try_load_symbol(elf : &EasyElf, symbol : &str, do_translation : bool) -> Option<GuestAddr> {
|
/// Lookup a symbol in the ELF file, optionally resolve segment offsets
|
||||||
let ret = elf
|
pub fn try_load_symbol(elf: &EasyElf, symbol: &str, do_translation: bool) -> Option<GuestAddr> {
|
||||||
.resolve_symbol(symbol, 0);
|
let ret = elf.resolve_symbol(symbol, 0);
|
||||||
if do_translation {
|
if do_translation {
|
||||||
Option::map_or(ret, None, |x| Some(virt2phys(x as GuestPhysAddr,&elf) as GuestAddr))
|
Option::map_or(ret, None, |x| {
|
||||||
} else {ret}
|
Some(virt2phys(x as GuestPhysAddr, &elf) as GuestAddr)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
ret
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Try looking up the address range of a function in the ELF file
|
/// Try looking up the address range of a function in the ELF file
|
||||||
pub fn get_function_range(elf: &EasyElf, symbol: &str) -> Option<std::ops::Range<GuestAddr>> {
|
pub fn get_function_range(elf: &EasyElf, symbol: &str) -> Option<std::ops::Range<GuestAddr>> {
|
||||||
let gob = elf.goblin();
|
let gob = elf.goblin();
|
||||||
|
|
||||||
let mut funcs : Vec<_> = gob.syms.iter().filter(|x| x.is_function()).collect();
|
let mut funcs: Vec<_> = gob.syms.iter().filter(|x| x.is_function()).collect();
|
||||||
funcs.sort_unstable_by(|x,y| x.st_value.cmp(&y.st_value));
|
funcs.sort_unstable_by(|x, y| x.st_value.cmp(&y.st_value));
|
||||||
|
|
||||||
for sym in &gob.syms {
|
for sym in &gob.syms {
|
||||||
if let Some(sym_name) = gob.strtab.get_at(sym.st_name) {
|
if let Some(sym_name) = gob.strtab.get_at(sym.st_name) {
|
||||||
@ -82,10 +75,22 @@ pub fn get_function_range(elf: &EasyElf, symbol: &str) -> Option<std::ops::Range
|
|||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check if an address is in any of the ranges
|
||||||
|
pub fn in_any_range<'a>(
|
||||||
|
ranges: &'a Vec<(String, Range<u32>)>,
|
||||||
|
addr: GuestAddr,
|
||||||
|
) -> Option<&'a std::ops::Range<GuestAddr>> {
|
||||||
|
for (_, r) in ranges {
|
||||||
|
if r.contains(&addr) {
|
||||||
|
return Some(r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
//============================= Utility functions
|
//============================= QEMU related utility functions
|
||||||
|
|
||||||
pub fn get_icount(emulator : &libafl_qemu::Qemu) -> u64 {
|
pub fn get_icount(emulator: &libafl_qemu::Qemu) -> u64 {
|
||||||
unsafe {
|
unsafe {
|
||||||
// TODO: investigate why can_do_io is not set sometimes, as this is just a workaround
|
// TODO: investigate why can_do_io is not set sometimes, as this is just a workaround
|
||||||
let c = emulator.cpu_from_index(0);
|
let c = emulator.cpu_from_index(0);
|
||||||
@ -97,29 +102,127 @@ pub fn get_icount(emulator : &libafl_qemu::Qemu) -> u64 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_rec_return_stackframe(emu : &libafl_qemu::Qemu, lr : GuestAddr) -> GuestAddr {
|
pub fn input_bytes_to_interrupt_times(buf: &[u8], config: (usize,u32)) -> Vec<u32> {
|
||||||
let lr_ = lr & u32::MAX-1;
|
let len = buf.len();
|
||||||
|
let mut start_tick;
|
||||||
|
let mut ret = Vec::with_capacity(min(DO_NUM_INTERRUPT, len/4));
|
||||||
|
for i in 0..DO_NUM_INTERRUPT {
|
||||||
|
let mut buf4b : [u8; 4] = [0,0,0,0];
|
||||||
|
if len >= (i+1)*4 {
|
||||||
|
for j in 0usize..4usize {
|
||||||
|
buf4b[j]=buf[i*4+j];
|
||||||
|
}
|
||||||
|
start_tick = u32::from_le_bytes(buf4b);
|
||||||
|
if start_tick < FIRST_INT {start_tick=0;}
|
||||||
|
ret.push(start_tick);
|
||||||
|
} else {break;}
|
||||||
|
}
|
||||||
|
ret.sort_unstable();
|
||||||
|
// obey the minimum inter arrival time while maintaining the sort
|
||||||
|
for i in 0..ret.len() {
|
||||||
|
if ret[i]==0 {continue;}
|
||||||
|
for j in i+1..ret.len()-1 {
|
||||||
|
if ret[j]-ret[i] < config.1 * QEMU_ISNS_PER_USEC {
|
||||||
|
// ret[j] = u32::saturating_add(ret[i],config.1 * QEMU_ISNS_PER_USEC);
|
||||||
|
ret[j] = 0; // remove the interrupt
|
||||||
|
ret.sort_unstable();
|
||||||
|
} else {break;}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn interrupt_times_to_input_bytes(interrupt_times: &[u32]) -> Vec<u8> {
|
||||||
|
let mut ret = Vec::with_capacity(interrupt_times.len()*4);
|
||||||
|
for i in interrupt_times {
|
||||||
|
ret.extend(u32::to_le_bytes(*i));
|
||||||
|
}
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read_rec_return_stackframe(emu: &libafl_qemu::Qemu, lr: GuestAddr) -> GuestAddr {
|
||||||
|
let lr_ = lr & u32::MAX - 1;
|
||||||
if lr_ == 0xfffffffc || lr_ == 0xFFFFFFF8 || lr_ == 0xFFFFFFF0 {
|
if lr_ == 0xfffffffc || lr_ == 0xFFFFFFF8 || lr_ == 0xFFFFFFF0 {
|
||||||
unsafe {
|
|
||||||
// if 0xFFFFFFF0/1 0xFFFFFFF8/9 -> "main stack" MSP
|
// if 0xFFFFFFF0/1 0xFFFFFFF8/9 -> "main stack" MSP
|
||||||
let mut buf = [0u8; 4];
|
let mut buf = [0u8; 4];
|
||||||
let sp : GuestAddr = if lr_ == 0xfffffffc || lr_ == 0xFFFFFFF0 { // PSP
|
let sp: GuestAddr = if lr_ == 0xfffffffc || lr_ == 0xFFFFFFF0 {
|
||||||
|
// PSP
|
||||||
read_user_reg_unchecked(emu) as u32
|
read_user_reg_unchecked(emu) as u32
|
||||||
} else {
|
} else {
|
||||||
emu.read_reg(13).unwrap()
|
emu.read_reg(13).unwrap()
|
||||||
};
|
};
|
||||||
let ret_pc = sp+0x18; // https://developer.arm.com/documentation/dui0552/a/the-cortex-m3-processor/exception-model/exception-entry-and-return
|
let ret_pc = sp + 0x18; // https://developer.arm.com/documentation/dui0552/a/the-cortex-m3-processor/exception-model/exception-entry-and-return
|
||||||
emu.read_mem(ret_pc, buf.as_mut_slice());
|
emu.read_mem(ret_pc, buf.as_mut_slice())
|
||||||
|
.expect("Failed to read return address");
|
||||||
return u32::from_le_bytes(buf);
|
return u32::from_le_bytes(buf);
|
||||||
// elseif 0xfffffffc/d
|
// elseif 0xfffffffc/d
|
||||||
}} else {
|
} else {
|
||||||
return lr;
|
return lr;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn in_any_range<'a>(ranges: &'a Vec<(String, Range<u32>)>, addr : GuestAddr) -> Option<&'a std::ops::Range<GuestAddr>> {
|
//============================= Tracing related utility functions
|
||||||
for (_,r) in ranges {
|
|
||||||
if r.contains(&addr) {return Some(r);}
|
pub fn metadata_insert_or_update_get<T>(
|
||||||
|
metadata: &mut SerdeAnyMap,
|
||||||
|
default: impl FnOnce() -> T,
|
||||||
|
update: impl FnOnce(&mut T),
|
||||||
|
) -> &mut T
|
||||||
|
where
|
||||||
|
T: SerdeAny,
|
||||||
|
{
|
||||||
|
if metadata.contains::<T>() {
|
||||||
|
let v = metadata.get_mut::<T>().unwrap();
|
||||||
|
update(v);
|
||||||
|
return v;
|
||||||
|
} else {
|
||||||
|
return metadata.get_or_insert_with(default);
|
||||||
}
|
}
|
||||||
return None;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
/// Build an ABB-profile from a stretch of intervals
|
||||||
|
/// returns mapping: task_name -> (abb_addr -> (interval_count, exec_count, exec_time))
|
||||||
|
pub fn abb_profile(
|
||||||
|
mut intervals: Vec<ExecInterval>,
|
||||||
|
) -> HashMap<String, HashMap<u32, (usize, usize, u64)>> {
|
||||||
|
let mut ret: HashMap<String, HashMap<u32, (usize, usize, u64)>> = HashMap::new();
|
||||||
|
intervals.sort_by_key(|x| x.get_task_name_unchecked());
|
||||||
|
intervals
|
||||||
|
.chunk_by_mut(|x, y| x.get_task_name_unchecked() == y.get_task_name_unchecked())
|
||||||
|
.for_each(|x| {
|
||||||
|
x.sort_by_key(|y| y.abb.as_ref().unwrap().start);
|
||||||
|
x.chunk_by(|y, z| y.abb.as_ref().unwrap().start == z.abb.as_ref().unwrap().start)
|
||||||
|
.for_each(|y| match ret.get_mut(&y[0].get_task_name_unchecked()) {
|
||||||
|
Option::None => {
|
||||||
|
ret.insert(
|
||||||
|
y[0].get_task_name_unchecked(),
|
||||||
|
HashMap::from([(
|
||||||
|
y[0].abb.as_ref().unwrap().start,
|
||||||
|
(
|
||||||
|
y.len(),
|
||||||
|
y.iter().filter(|x| x.is_abb_end()).count(),
|
||||||
|
y.iter().map(|z| z.get_exec_time()).sum::<_>(),
|
||||||
|
),
|
||||||
|
)]),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Some(x) => {
|
||||||
|
x.insert(
|
||||||
|
y[0].abb.as_ref().unwrap().start,
|
||||||
|
(
|
||||||
|
y.len(),
|
||||||
|
y.iter().filter(|x| x.is_abb_end()).count(),
|
||||||
|
y.iter().map(|z| z.get_exec_time()).sum(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub fn unmut<T>(x: &mut T) -> &T {
|
||||||
|
&(*x)
|
||||||
|
}
|
||||||
|
@ -11,7 +11,6 @@ use serde::{Deserialize, Serialize};
|
|||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
|
||||||
pub mod helpers;
|
pub mod helpers;
|
||||||
pub mod observers;
|
|
||||||
pub mod feedbacks;
|
pub mod feedbacks;
|
||||||
pub mod schedulers;
|
pub mod schedulers;
|
||||||
pub mod stg;
|
pub mod stg;
|
||||||
@ -254,6 +253,9 @@ impl RTOSJob {
|
|||||||
self.hash_cache
|
self.hash_cache
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pub fn response_time(&self) -> u64 {
|
||||||
|
self.response-self.release
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================= Generalized job instances
|
// ============================= Generalized job instances
|
||||||
|
@ -19,7 +19,7 @@ use std::borrow::Cow;
|
|||||||
|
|
||||||
use simple_moving_average::SMA;
|
use simple_moving_average::SMA;
|
||||||
|
|
||||||
use super::{stg::{STGEdge, STGNode}, target_os::TargetSystem, RTOSJob};
|
use super::{helpers::{input_bytes_to_interrupt_times, interrupt_times_to_input_bytes}, stg::{STGEdge, STGNode}, target_os::TargetSystem, RTOSJob};
|
||||||
|
|
||||||
// pub static mut MINIMUM_INTER_ARRIVAL_TIME : u32 = 1000 /*us*/ * QEMU_ISNS_PER_USEC;
|
// pub static mut MINIMUM_INTER_ARRIVAL_TIME : u32 = 1000 /*us*/ * QEMU_ISNS_PER_USEC;
|
||||||
// one isn per 2**4 ns
|
// one isn per 2**4 ns
|
||||||
@ -27,43 +27,6 @@ use super::{stg::{STGEdge, STGNode}, target_os::TargetSystem, RTOSJob};
|
|||||||
// 1ms = 62500 insn
|
// 1ms = 62500 insn
|
||||||
// 1us = 62.5 insn
|
// 1us = 62.5 insn
|
||||||
|
|
||||||
pub fn input_bytes_to_interrupt_times(buf: &[u8], config: (usize,u32)) -> Vec<u32> {
|
|
||||||
let len = buf.len();
|
|
||||||
let mut start_tick;
|
|
||||||
let mut ret = Vec::with_capacity(min(DO_NUM_INTERRUPT, len/4));
|
|
||||||
for i in 0..DO_NUM_INTERRUPT {
|
|
||||||
let mut buf4b : [u8; 4] = [0,0,0,0];
|
|
||||||
if len >= (i+1)*4 {
|
|
||||||
for j in 0usize..4usize {
|
|
||||||
buf4b[j]=buf[i*4+j];
|
|
||||||
}
|
|
||||||
start_tick = u32::from_le_bytes(buf4b);
|
|
||||||
if start_tick < FIRST_INT {start_tick=0;}
|
|
||||||
ret.push(start_tick);
|
|
||||||
} else {break;}
|
|
||||||
}
|
|
||||||
ret.sort_unstable();
|
|
||||||
// obey the minimum inter arrival time while maintaining the sort
|
|
||||||
for i in 0..ret.len() {
|
|
||||||
if ret[i]==0 {continue;}
|
|
||||||
for j in i+1..ret.len()-1 {
|
|
||||||
if ret[j]-ret[i] < config.1 as u32 * QEMU_ISNS_PER_USEC {
|
|
||||||
// ret[j] = u32::saturating_add(ret[i],config.1 * QEMU_ISNS_PER_USEC);
|
|
||||||
ret[j] = 0; // remove the interrupt
|
|
||||||
ret.sort_unstable();
|
|
||||||
} else {break;}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ret
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn interrupt_times_to_input_bytes(interrupt_times: &[u32]) -> Vec<u8> {
|
|
||||||
let mut ret = Vec::with_capacity(interrupt_times.len()*4);
|
|
||||||
for i in interrupt_times {
|
|
||||||
ret.extend(u32::to_le_bytes(*i));
|
|
||||||
}
|
|
||||||
ret
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//======================= Custom mutator
|
//======================= Custom mutator
|
||||||
@ -249,10 +212,9 @@ where
|
|||||||
}
|
}
|
||||||
else if choice <= 75 { // 0.5 * 0.25 = 12.5% of cases
|
else if choice <= 75 { // 0.5 * 0.25 = 12.5% of cases
|
||||||
let feedbackstate = match state
|
let feedbackstate = match state
|
||||||
.named_metadata_map()
|
.metadata::<STGFeedbackState<SYS>>() {
|
||||||
.get::<STGFeedbackState<SYS>>("stgfeedbackstate") {
|
Ok(s) => s,
|
||||||
Some(s) => s,
|
Error => {
|
||||||
Option::None => {
|
|
||||||
panic!("STGfeedbackstate not visible")
|
panic!("STGfeedbackstate not visible")
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -565,10 +527,9 @@ where
|
|||||||
// eprintln!("Run mutator {}", current_case.metadata_map().get::<STGNodeMetadata>().is_some());
|
// eprintln!("Run mutator {}", current_case.metadata_map().get::<STGNodeMetadata>().is_some());
|
||||||
if let Some(meta) = current_case.metadata_map().get::<STGNodeMetadata>() {
|
if let Some(meta) = current_case.metadata_map().get::<STGNodeMetadata>() {
|
||||||
let feedbackstate = match state
|
let feedbackstate = match state
|
||||||
.named_metadata_map()
|
.metadata::<STGFeedbackState<SYS>>() {
|
||||||
.get::<STGFeedbackState<SYS>>("stgfeedbackstate") {
|
Ok(s) => s,
|
||||||
Some(s) => s,
|
Error => {
|
||||||
Option::None => {
|
|
||||||
panic!("STGfeedbackstate not visible")
|
panic!("STGfeedbackstate not visible")
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1,168 +0,0 @@
|
|||||||
use libafl::prelude::ExitKind;
|
|
||||||
use libafl::prelude::UsesInput;
|
|
||||||
use libafl::HasMetadata;
|
|
||||||
use libafl_bolts::HasLen;
|
|
||||||
use libafl_bolts::Named;
|
|
||||||
use libafl::Error;
|
|
||||||
use libafl::observers::Observer;
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use hashbrown::{HashMap, HashSet};
|
|
||||||
use crate::systemstate::CaptureEvent;
|
|
||||||
use crate::time::clock::IcHist;
|
|
||||||
use crate::time::clock::FUZZ_START_TIMESTAMP;
|
|
||||||
use std::time::SystemTime;
|
|
||||||
use std::rc::Rc;
|
|
||||||
use std::cell::RefCell;
|
|
||||||
use std::collections::VecDeque;
|
|
||||||
use std::borrow::Cow;
|
|
||||||
use itertools::Itertools;
|
|
||||||
|
|
||||||
use super::target_os::TargetSystem;
|
|
||||||
use super::RTOSJob;
|
|
||||||
use super::{ AtomicBasicBlock, ExecInterval};
|
|
||||||
use crate::systemstate::target_os::SystemState;
|
|
||||||
use crate::systemstate::target_os::*;
|
|
||||||
|
|
||||||
//============================= Observer
|
|
||||||
|
|
||||||
/// The Qemusystemstate Observer retrieves the systemstate
|
|
||||||
/// that will get updated by the target.
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
|
||||||
#[allow(clippy::unsafe_derive_deserialize)]
|
|
||||||
pub struct QemuSystemStateObserver<I, SYS>
|
|
||||||
where
|
|
||||||
SYS: TargetSystem,
|
|
||||||
for<'de2> SYS: Deserialize<'de2>,
|
|
||||||
{
|
|
||||||
last_run: Vec<SYS::State>,
|
|
||||||
last_states: HashMap<u64, SYS::State>,
|
|
||||||
last_trace: Vec<ExecInterval>,
|
|
||||||
last_reads: Vec<Vec<(u32, u8)>>,
|
|
||||||
last_input: I,
|
|
||||||
job_instances: Vec<RTOSJob>,
|
|
||||||
pub do_report: bool,
|
|
||||||
worst_job_instances: HashMap<String, RTOSJob>,
|
|
||||||
pub select_task: Option<String>,
|
|
||||||
pub success: bool,
|
|
||||||
name: Cow<'static, str>,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
impl<I, S, SYS> Observer<I, S> for QemuSystemStateObserver<I, SYS>
|
|
||||||
where
|
|
||||||
S: UsesInput<Input = I> + HasMetadata,
|
|
||||||
S::Input: Default,
|
|
||||||
I: Clone,
|
|
||||||
SYS: TargetSystem,
|
|
||||||
{
|
|
||||||
#[inline]
|
|
||||||
fn pre_exec(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn post_exec(&mut self, state: &mut S, _input: &I, _exit_kind: &ExitKind) -> Result<(), Error> {
|
|
||||||
// let trace =state.metadata::<SYS::TraceData>().expect("TraceData not found");
|
|
||||||
|
|
||||||
// copy-paste form clock observer
|
|
||||||
{
|
|
||||||
let hist = state.metadata_mut::<IcHist>();
|
|
||||||
let timestamp = SystemTime::now().duration_since(unsafe {FUZZ_START_TIMESTAMP}).unwrap().as_millis();
|
|
||||||
match hist {
|
|
||||||
Err(_) => {
|
|
||||||
state.add_metadata(IcHist(vec![(self.last_runtime(), timestamp)],
|
|
||||||
(self.last_runtime(), timestamp)));
|
|
||||||
}
|
|
||||||
Ok(v) => {
|
|
||||||
v.0.push((self.last_runtime(), timestamp));
|
|
||||||
if v.1.0 < self.last_runtime() {
|
|
||||||
v.1 = (self.last_runtime(), timestamp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I, SYS> Named for QemuSystemStateObserver<I, SYS>
|
|
||||||
where
|
|
||||||
SYS: TargetSystem,
|
|
||||||
for<'de2> SYS: Deserialize<'de2>,
|
|
||||||
{
|
|
||||||
fn name(&self) -> &Cow<'static, str> {
|
|
||||||
&self.name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I, SYS> HasLen for QemuSystemStateObserver<I, SYS>
|
|
||||||
where
|
|
||||||
SYS: TargetSystem,
|
|
||||||
for<'de2> SYS: Deserialize<'de2>,
|
|
||||||
{
|
|
||||||
#[inline]
|
|
||||||
fn len(&self) -> usize {
|
|
||||||
self.last_run.len()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I, SYS> QemuSystemStateObserver<I, SYS>
|
|
||||||
where
|
|
||||||
SYS: TargetSystem,
|
|
||||||
for<'de2> SYS: Deserialize<'de2>,
|
|
||||||
I: Default {
|
|
||||||
pub fn new(select_task: &Option<String>) -> Self {
|
|
||||||
Self{last_run: vec![], last_trace: vec![], last_reads: vec![], last_input: I::default(), worst_job_instances: HashMap::new(), do_report: false, select_task: select_task.clone(), name: Cow::from("systemstate".to_string()), last_states: HashMap::new(), success: false, job_instances: vec![]}
|
|
||||||
}
|
|
||||||
pub fn last_runtime(&self) -> u64 {
|
|
||||||
self.select_task.as_ref().map(|x| self.worst_job_instances.get(x).map(|y| y.response-y.release).unwrap_or(0).clone()).unwrap_or(unsafe{libafl_qemu::sys::icount_get_raw()})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<I, SYS> Default for QemuSystemStateObserver<I, SYS>
|
|
||||||
where
|
|
||||||
SYS: TargetSystem,
|
|
||||||
for<'de2> SYS: Deserialize<'de2>,
|
|
||||||
I: Default {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::new(&None)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// /// restore the isr/api begin/end invariant
|
|
||||||
// fn fix_broken_trace(meta: &mut Vec<(u64, CaptureEvent, String, (Option<u32>, Option<u32>))>) {
|
|
||||||
// for i in meta.iter_mut() {
|
|
||||||
// if i.1 == CaptureEvent::APIStart && i.2.ends_with("FromISR") {
|
|
||||||
// i.1 = CaptureEvent::ISREnd;
|
|
||||||
// i.2 = "ISR_0_Handler".to_string();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// /// invalidate subsequent intervals of equal states where an ISREnd follows an ISRStart. If the interrupt had no effect on the system we, are not interested.
|
|
||||||
// fn invalidate_ineffective_isr(trace: &mut Vec<ExecInterval>) {
|
|
||||||
// let mut i = 0;
|
|
||||||
// while i < trace.len() - 1 {
|
|
||||||
// if trace[i].is_valid() &&
|
|
||||||
// matches!(trace[i].start_capture.0, CaptureEvent::ISRStart) && matches!(trace[i].end_capture.0, CaptureEvent::ISREnd) &&
|
|
||||||
// trace[i].start_capture.1 == trace[i].end_capture.1 && trace[i].start_state == trace[i].end_state
|
|
||||||
// {
|
|
||||||
// trace[i].invaildate();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// /// merge a sequence of intervals of the same state+abb. jump over all invalid blocks.
|
|
||||||
// fn merge_subsequent_abbs(trace: &mut Vec<ExecInterval>) {
|
|
||||||
// let mut i = 1;
|
|
||||||
// let mut lst_valid=0;
|
|
||||||
// while i < trace.len() - 1 {
|
|
||||||
// if trace[i].is_valid() {
|
|
||||||
// let mut temp = trace[i].clone();
|
|
||||||
// trace[lst_valid].try_unite_with_later_interval(&mut temp);
|
|
||||||
// trace[i] = temp;
|
|
||||||
// lst_valid = i;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
@ -4,6 +4,7 @@ use libafl::inputs::Input;
|
|||||||
/// Feedbacks organizing SystemStates as a graph
|
/// Feedbacks organizing SystemStates as a graph
|
||||||
use libafl_bolts::prelude::SerdeAny;
|
use libafl_bolts::prelude::SerdeAny;
|
||||||
use libafl_bolts::ownedref::OwnedMutSlice;
|
use libafl_bolts::ownedref::OwnedMutSlice;
|
||||||
|
use log::Metadata;
|
||||||
use petgraph::graph::EdgeIndex;
|
use petgraph::graph::EdgeIndex;
|
||||||
use libafl::prelude::UsesInput;
|
use libafl::prelude::UsesInput;
|
||||||
use libafl::common::HasNamedMetadata;
|
use libafl::common::HasNamedMetadata;
|
||||||
@ -27,12 +28,12 @@ use libafl::{executors::ExitKind, observers::ObserversTuple, common::HasMetadata
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
|
use super::helpers::metadata_insert_or_update_get;
|
||||||
use super::target_os::SystemState;
|
use super::target_os::SystemState;
|
||||||
use super::AtomicBasicBlock;
|
use super::AtomicBasicBlock;
|
||||||
use super::CaptureEvent;
|
use super::CaptureEvent;
|
||||||
use super::ExecInterval;
|
use super::ExecInterval;
|
||||||
use super::RTOSJob;
|
use super::RTOSJob;
|
||||||
use super::observers::QemuSystemStateObserver;
|
|
||||||
use super::RTOSTask;
|
use super::RTOSTask;
|
||||||
use petgraph::prelude::DiGraph;
|
use petgraph::prelude::DiGraph;
|
||||||
use petgraph::graph::NodeIndex;
|
use petgraph::graph::NodeIndex;
|
||||||
@ -383,6 +384,7 @@ where
|
|||||||
last_top_abb_hashes: Option<Vec<u64>>, // only set, if it was interesting
|
last_top_abb_hashes: Option<Vec<u64>>, // only set, if it was interesting
|
||||||
last_job_trace: Option<Vec<RTOSJob>>, // only set, if it was interesting
|
last_job_trace: Option<Vec<RTOSJob>>, // only set, if it was interesting
|
||||||
dump_path: Option<PathBuf>,
|
dump_path: Option<PathBuf>,
|
||||||
|
select_task: Option<String>,
|
||||||
_phantom_data: PhantomData<SYS>,
|
_phantom_data: PhantomData<SYS>,
|
||||||
}
|
}
|
||||||
#[cfg(feature = "feed_stg")]
|
#[cfg(feature = "feed_stg")]
|
||||||
@ -457,10 +459,12 @@ impl<SYS> StgFeedback<SYS>
|
|||||||
where
|
where
|
||||||
SYS: TargetSystem,
|
SYS: TargetSystem,
|
||||||
{
|
{
|
||||||
pub fn new(dump_name: Option<PathBuf>) -> Self {
|
pub fn new(select_task: Option<String>, dump_name: Option<PathBuf>) -> Self {
|
||||||
// Self {name: String::from("STGFeedback"), last_node_trace: None, last_edge_trace: None, last_intervals: None }
|
// Self {name: String::from("STGFeedback"), last_node_trace: None, last_edge_trace: None, last_intervals: None }
|
||||||
let mut s = Self::default();
|
let mut s = Self::default();
|
||||||
|
unsafe{libafl_bolts::prelude::RegistryBuilder::register::<STGFeedbackState<SYS>>()};
|
||||||
s.dump_path = dump_name.map(|x| x.with_extension("stgsize"));
|
s.dump_path = dump_name.map(|x| x.with_extension("stgsize"));
|
||||||
|
s.select_task = select_task;
|
||||||
s
|
s
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -582,40 +586,31 @@ where
|
|||||||
{
|
{
|
||||||
// TODO: don't remove metadata. work around ownership issues
|
// TODO: don't remove metadata. work around ownership issues
|
||||||
let trace = state.remove_metadata::<SYS::TraceData>().expect("TraceData not found");
|
let trace = state.remove_metadata::<SYS::TraceData>().expect("TraceData not found");
|
||||||
let observer = observers.match_name::<QemuSystemStateObserver<<S as UsesInput>::Input, SYS>>("systemstate")
|
|
||||||
.expect("QemuSystemStateObserver not found");
|
|
||||||
let clock_observer = observers.match_name::<QemuClockObserver>("clocktime")
|
let clock_observer = observers.match_name::<QemuClockObserver>("clocktime")
|
||||||
.expect("QemuClockObserver not found");
|
.expect("QemuClockObserver not found");
|
||||||
#[cfg(feature = "trace_job_response_times")]
|
|
||||||
let last_runtime = observer.last_runtime();
|
|
||||||
#[cfg(not(feature = "trace_job_response_times"))]
|
|
||||||
let last_runtime = clock_observer.last_runtime();
|
let last_runtime = clock_observer.last_runtime();
|
||||||
let feedbackstate = match state
|
|
||||||
.named_metadata_map_mut()
|
#[cfg(feature = "trace_job_response_times")]
|
||||||
.get_mut::<STGFeedbackState<SYS>>("stgfeedbackstate") {
|
let worst_jobs = trace.worst_jobs_per_task_by_response_time();
|
||||||
Some(s) => s,
|
#[cfg(feature = "trace_job_response_times")]
|
||||||
Option::None => {
|
let worst_select_job = if let Some(t) = self.select_task.as_ref() {worst_jobs.get(t)} else {None};
|
||||||
let n=STGFeedbackState::<SYS>::default();
|
#[cfg(feature = "trace_job_response_times")]
|
||||||
unsafe{libafl_bolts::prelude::RegistryBuilder::register::<STGFeedbackState<SYS>>()};
|
let last_runtime = if let Some(t) = self.select_task.as_ref() {worst_select_job.map_or(0, |x| x.response_time())} else {last_runtime};
|
||||||
state.named_metadata_map_mut().insert("stgfeedbackstate",n);
|
|
||||||
state.named_metadata_map_mut().get_mut::<STGFeedbackState<SYS>>("stgfeedbackstate").unwrap()
|
let feedbackstate = state.metadata_map_mut().get_or_insert_with(||{
|
||||||
}
|
STGFeedbackState::<SYS>::default()
|
||||||
};
|
});
|
||||||
|
|
||||||
// --------------------------------- Update STG
|
// --------------------------------- Update STG
|
||||||
let (mut nodetrace, mut edgetrace, mut interesting, mut updated) = StgFeedback::update_stg_interval(trace.intervals(), &trace.mem_reads(), trace.states_map(), feedbackstate);
|
let (mut nodetrace, mut edgetrace, mut interesting, mut updated) = StgFeedback::update_stg_interval(trace.intervals(), &trace.mem_reads(), trace.states_map(), feedbackstate);
|
||||||
|
|
||||||
let worst_jobs = trace.worst_jobs_per_task_by_time();
|
|
||||||
|
|
||||||
#[cfg(feature = "trace_job_response_times")]
|
#[cfg(feature = "trace_job_response_times")]
|
||||||
let worst_target_instance = worst_jobs.get(observer.select_task.as_ref().unwrap_or(&String::new()));
|
if let Some(worst_instance) = worst_select_job {
|
||||||
|
|
||||||
#[cfg(feature = "trace_job_response_times")]
|
|
||||||
if let Some(worst_instance) = worst_target_instance {
|
|
||||||
edgetrace = edgetrace.into_iter().filter(|x| x.1 <= worst_instance.response && x.1 >= worst_instance.release ).collect();
|
edgetrace = edgetrace.into_iter().filter(|x| x.1 <= worst_instance.response && x.1 >= worst_instance.release ).collect();
|
||||||
nodetrace = nodetrace.into_iter().filter(|x| x.1 <= worst_instance.response && x.1 >= worst_instance.release ).collect();
|
nodetrace = nodetrace.into_iter().filter(|x| x.1 <= worst_instance.response && x.1 >= worst_instance.release ).collect();
|
||||||
} else {
|
} else {
|
||||||
if observer.select_task.is_none() { // if nothing was selected, just take the whole trace, otherwise there is nothing interesting here
|
if self.select_task.is_some() { // if nothing was selected, just take the whole trace, otherwise there is nothing interesting here
|
||||||
edgetrace = Vec::new();
|
edgetrace = Vec::new();
|
||||||
nodetrace = Vec::new();
|
nodetrace = Vec::new();
|
||||||
}
|
}
|
||||||
@ -625,7 +620,7 @@ where
|
|||||||
set_observer_map(&edgetrace.iter().map(|x| x.0).collect::<Vec<_>>());
|
set_observer_map(&edgetrace.iter().map(|x| x.0).collect::<Vec<_>>());
|
||||||
|
|
||||||
// --------------------------------- Update job instances
|
// --------------------------------- Update job instances
|
||||||
for i in trace.worst_jobs_per_task_by_time().iter() {
|
for i in worst_jobs.iter() {
|
||||||
interesting |= INTEREST_JOB_INSTANCE && if let Some(x) = feedbackstate.worst_task_jobs.get_mut(&i.1.get_hash_cached()) {
|
interesting |= INTEREST_JOB_INSTANCE && if let Some(x) = feedbackstate.worst_task_jobs.get_mut(&i.1.get_hash_cached()) {
|
||||||
// eprintln!("Job instance already present");
|
// eprintln!("Job instance already present");
|
||||||
x.try_update(i.1)
|
x.try_update(i.1)
|
||||||
@ -657,11 +652,11 @@ where
|
|||||||
let tmp = StgFeedback::abbs_in_exec_order(&observer.last_trace);
|
let tmp = StgFeedback::abbs_in_exec_order(&observer.last_trace);
|
||||||
#[cfg(feature = "trace_job_response_times")]
|
#[cfg(feature = "trace_job_response_times")]
|
||||||
let tmp = {
|
let tmp = {
|
||||||
if let Some(worst_instance) = worst_target_instance {
|
if let Some(worst_instance) = worst_select_job {
|
||||||
let t = trace.intervals().iter().filter(|x| x.start_tick < worst_instance.response && x.end_tick > worst_instance.release ).cloned().collect();
|
let t = trace.intervals().iter().filter(|x| x.start_tick < worst_instance.response && x.end_tick > worst_instance.release ).cloned().collect();
|
||||||
StgFeedback::<SYS>::abbs_in_exec_order(&t)
|
StgFeedback::<SYS>::abbs_in_exec_order(&t)
|
||||||
} else {
|
} else {
|
||||||
if observer.select_task.is_none() { // if nothing was selected, just take the whole trace, otherwise there is nothing interesting here
|
if self.select_task.is_none() { // if nothing was selected, just take the whole trace, otherwise there is nothing interesting here
|
||||||
StgFeedback::<SYS>::abbs_in_exec_order(trace.intervals())
|
StgFeedback::<SYS>::abbs_in_exec_order(trace.intervals())
|
||||||
} else {
|
} else {
|
||||||
Vec::new()
|
Vec::new()
|
||||||
|
@ -3,9 +3,10 @@ use libafl_qemu::{elf::EasyElf, GuestAddr};
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
fuzzer::get_all_fn_symbol_ranges,
|
fuzzer::get_all_fn_symbol_ranges,
|
||||||
systemstate::{self, helpers::{get_function_range, load_symbol}, target_os::freertos::ISR_SYMBOLS},
|
systemstate::{helpers::{get_function_range, load_symbol}, target_os::freertos::ISR_SYMBOLS},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Add os-specific symbols to the target symbol hashmap
|
||||||
pub fn add_target_symbols(elf: &EasyElf, addrs: &mut HashMap<&'static str, GuestAddr>) {
|
pub fn add_target_symbols(elf: &EasyElf, addrs: &mut HashMap<&'static str, GuestAddr>) {
|
||||||
// required for system state observation
|
// required for system state observation
|
||||||
addrs.insert("pxCurrentTCB", load_symbol(&elf, "pxCurrentTCB", false)); // loads to the address specified in elf, without respecting program headers
|
addrs.insert("pxCurrentTCB", load_symbol(&elf, "pxCurrentTCB", false)); // loads to the address specified in elf, without respecting program headers
|
||||||
@ -35,50 +36,8 @@ pub fn add_target_symbols(elf: &EasyElf, addrs: &mut HashMap<&'static str, Guest
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_target_ranges(
|
|
||||||
elf: &EasyElf,
|
|
||||||
symbols: &HashMap<&'static str, GuestAddr>,
|
|
||||||
ranges: &mut HashMap<&'static str, std::ops::Range<GuestAddr>>,
|
|
||||||
) {
|
|
||||||
let api_range = ranges.get("API_CODE").unwrap();
|
|
||||||
let app_range = ranges.get("APP_CODE").unwrap();
|
|
||||||
|
|
||||||
let mut api_fn_ranges = get_all_fn_symbol_ranges(&elf, api_range.clone());
|
|
||||||
let mut app_fn_ranges = get_all_fn_symbol_ranges(&elf, app_range.clone());
|
|
||||||
|
|
||||||
// Regular ISR functions, remove from API functions
|
|
||||||
let mut isr_fn_ranges: HashMap<String, std::ops::Range<GuestAddr>> = ISR_SYMBOLS
|
|
||||||
.iter()
|
|
||||||
.filter_map(|x| {
|
|
||||||
api_fn_ranges
|
|
||||||
.remove(&x.to_string())
|
|
||||||
.map(|y| (x.to_string(), y.clone()))
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
// User-defined ISR functions, remove from APP functions
|
|
||||||
ISR_SYMBOLS.iter().for_each(|x| {
|
|
||||||
let _ = (app_fn_ranges
|
|
||||||
.remove(&x.to_string())
|
|
||||||
.map(|y| (x.to_string(), y.clone())))
|
|
||||||
.map(|z| isr_fn_ranges.insert(z.0, z.1));
|
|
||||||
});
|
|
||||||
|
|
||||||
// Add the rest of the ISR function, if not already found
|
|
||||||
for i in ISR_SYMBOLS {
|
|
||||||
if isr_fn_ranges.get(&i.to_string()).is_none() {
|
|
||||||
if let Some(fr) = get_function_range(&elf, i) {
|
|
||||||
isr_fn_ranges.insert(i.to_string(), fr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut groups = HashMap::new();
|
|
||||||
|
|
||||||
groups.insert("API_FN", api_fn_ranges);
|
|
||||||
groups.insert("APP_FN", app_fn_ranges);
|
|
||||||
groups.insert("ISR_FN", isr_fn_ranges);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// Group functions into api, app and isr functions
|
||||||
pub fn get_range_groups(
|
pub fn get_range_groups(
|
||||||
elf: &EasyElf,
|
elf: &EasyElf,
|
||||||
_addrs: &HashMap<&'static str, GuestAddr>,
|
_addrs: &HashMap<&'static str, GuestAddr>,
|
||||||
|
@ -453,10 +453,11 @@ pub struct FreeRTOSTraceMetadata
|
|||||||
trace_length: usize,
|
trace_length: usize,
|
||||||
indices: Vec<usize>, // Hashed enumeration of States
|
indices: Vec<usize>, // Hashed enumeration of States
|
||||||
tcref: isize,
|
tcref: isize,
|
||||||
|
need_to_debug: bool,
|
||||||
}
|
}
|
||||||
impl FreeRTOSTraceMetadata
|
impl FreeRTOSTraceMetadata
|
||||||
{
|
{
|
||||||
pub fn new(trace: Vec<<FreeRTOSTraceMetadata as SystemTraceData>::State>, intervals: Vec<ExecInterval>, mem_reads: Vec<Vec<(u32, u8)>>, jobs: Vec<RTOSJob>) -> Self {
|
pub fn new(trace: Vec<<FreeRTOSTraceMetadata as SystemTraceData>::State>, intervals: Vec<ExecInterval>, mem_reads: Vec<Vec<(u32, u8)>>, jobs: Vec<RTOSJob>, need_to_debug: bool) -> Self {
|
||||||
let hashes : Vec<_> = trace
|
let hashes : Vec<_> = trace
|
||||||
.iter()
|
.iter()
|
||||||
.map(|x| compute_hash(&x) as usize)
|
.map(|x| compute_hash(&x) as usize)
|
||||||
@ -470,6 +471,7 @@ impl FreeRTOSTraceMetadata
|
|||||||
jobs: jobs,
|
jobs: jobs,
|
||||||
indices: hashes,
|
indices: hashes,
|
||||||
tcref: 0,
|
tcref: 0,
|
||||||
|
need_to_debug: need_to_debug,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -512,6 +514,10 @@ impl SystemTraceData for FreeRTOSTraceMetadata
|
|||||||
fn states_map(&self) -> &HashMap<u64, Self::State> {
|
fn states_map(&self) -> &HashMap<u64, Self::State> {
|
||||||
&self.trace_map
|
&self.trace_map
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn need_to_debug(&self) -> bool {
|
||||||
|
self.need_to_debug
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
libafl_bolts::impl_serdeany!(FreeRTOSTraceMetadata);
|
libafl_bolts::impl_serdeany!(FreeRTOSTraceMetadata);
|
||||||
|
@ -13,8 +13,6 @@ use libafl_qemu::{
|
|||||||
EmulatorModules, GuestAddr, Hook, MemAccessInfo,
|
EmulatorModules, GuestAddr, Hook, MemAccessInfo,
|
||||||
};
|
};
|
||||||
|
|
||||||
use libafl_bolts::tuples::Map;
|
|
||||||
|
|
||||||
use crate::{fuzzer::MAX_INPUT_SIZE, systemstate::{
|
use crate::{fuzzer::MAX_INPUT_SIZE, systemstate::{
|
||||||
helpers::{get_icount, in_any_range, read_rec_return_stackframe},
|
helpers::{get_icount, in_any_range, read_rec_return_stackframe},
|
||||||
target_os::{freertos::FreeRTOSStruct::*, *},
|
target_os::{freertos::FreeRTOSStruct::*, *},
|
||||||
@ -159,6 +157,7 @@ where
|
|||||||
OT: ObserversTuple<S::Input, S>,
|
OT: ObserversTuple<S::Input, S>,
|
||||||
ET: EmulatorModuleTuple<S>,
|
ET: EmulatorModuleTuple<S>,
|
||||||
{
|
{
|
||||||
|
let mut need_to_debug = false;
|
||||||
if unsafe { CURRENT_SYSTEMSTATE_VEC.len() } == 0 {
|
if unsafe { CURRENT_SYSTEMSTATE_VEC.len() } == 0 {
|
||||||
eprintln!("No system states captured, aborting");
|
eprintln!("No system states captured, aborting");
|
||||||
return;
|
return;
|
||||||
@ -194,6 +193,7 @@ where
|
|||||||
refine_system_states(unsafe { CURRENT_SYSTEMSTATE_VEC.split_off(0) });
|
refine_system_states(unsafe { CURRENT_SYSTEMSTATE_VEC.split_off(0) });
|
||||||
let (intervals, mem_reads, dumped_states, success) =
|
let (intervals, mem_reads, dumped_states, success) =
|
||||||
states2intervals(refined_states.clone(), metadata);
|
states2intervals(refined_states.clone(), metadata);
|
||||||
|
need_to_debug |= !success;
|
||||||
#[cfg(not(feature = "trace_job_response_times"))]
|
#[cfg(not(feature = "trace_job_response_times"))]
|
||||||
let jobs = Vec::new();
|
let jobs = Vec::new();
|
||||||
#[cfg(feature = "trace_job_response_times")]
|
#[cfg(feature = "trace_job_response_times")]
|
||||||
@ -201,6 +201,7 @@ where
|
|||||||
let releases = get_releases(&intervals, &dumped_states);
|
let releases = get_releases(&intervals, &dumped_states);
|
||||||
let responses = unsafe { JOBS_DONE.split_off(0) };
|
let responses = unsafe { JOBS_DONE.split_off(0) };
|
||||||
let (job_spans, do_report) = get_release_response_pairs(&releases, &responses);
|
let (job_spans, do_report) = get_release_response_pairs(&releases, &responses);
|
||||||
|
need_to_debug |= do_report;
|
||||||
|
|
||||||
let jobs : Vec<RTOSJob> = job_spans
|
let jobs : Vec<RTOSJob> = job_spans
|
||||||
.into_iter()
|
.into_iter()
|
||||||
@ -252,7 +253,7 @@ where
|
|||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
jobs
|
jobs
|
||||||
};
|
};
|
||||||
_state.add_metadata(FreeRTOSTraceMetadata::new(refined_states, intervals, mem_reads, jobs));
|
_state.add_metadata(FreeRTOSTraceMetadata::new(refined_states, intervals, mem_reads, jobs, need_to_debug));
|
||||||
}
|
}
|
||||||
|
|
||||||
type ModuleAddressFilter = NopAddressFilter;
|
type ModuleAddressFilter = NopAddressFilter;
|
||||||
|
@ -3,9 +3,7 @@ use std::fmt;
|
|||||||
use hashbrown::HashSet;
|
use hashbrown::HashSet;
|
||||||
use libafl_bolts::prelude::SerdeAny;
|
use libafl_bolts::prelude::SerdeAny;
|
||||||
use libafl_bolts::HasRefCnt;
|
use libafl_bolts::HasRefCnt;
|
||||||
use libafl_qemu::GuestAddr;
|
|
||||||
use libafl_qemu::Qemu;
|
use libafl_qemu::Qemu;
|
||||||
use serde::de::DeserializeOwned;
|
|
||||||
use std::hash::Hasher;
|
use std::hash::Hasher;
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
@ -13,15 +11,12 @@ use serde::{Deserialize, Serialize};
|
|||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
|
||||||
use super::CaptureEvent;
|
use super::helpers::abb_profile;
|
||||||
use super::ExecInterval;
|
use super::ExecInterval;
|
||||||
use super::RTOSJob;
|
use super::RTOSJob;
|
||||||
|
|
||||||
pub mod freertos;
|
pub mod freertos;
|
||||||
|
|
||||||
// Constants
|
|
||||||
const NUM_PRIOS: usize = 15;
|
|
||||||
|
|
||||||
//============================= Trait definitions
|
//============================= Trait definitions
|
||||||
|
|
||||||
pub trait TargetSystem: Serialize + Sized + for<'a> Deserialize<'a> + Default + Debug + Clone + SerdeAny {
|
pub trait TargetSystem: Serialize + Sized + for<'a> Deserialize<'a> + Default + Debug + Clone + SerdeAny {
|
||||||
@ -67,9 +62,51 @@ pub trait SystemTraceData: Serialize + Sized + for<'a> Deserialize<'a> + Default
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
fn worst_jobs_per_task_by_time(&self) -> HashMap<String, RTOSJob> {
|
fn worst_jobs_per_task_by_exec_time(&self) -> HashMap<String, RTOSJob> {
|
||||||
self.worst_jobs_per_task_by(&|old, x| x.exec_ticks > old.exec_ticks)
|
self.worst_jobs_per_task_by(&|old, x| x.exec_ticks > old.exec_ticks)
|
||||||
}
|
}
|
||||||
|
#[inline]
|
||||||
|
fn worst_jobs_per_task_by_response_time(&self) -> HashMap<String, RTOSJob> {
|
||||||
|
self.worst_jobs_per_task_by(&|old, x| x.response_time() > old.response_time())
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
/// Gives the response time of the worst job of the selected task, or 0 if the task is not found
|
||||||
|
fn wort_of_task(&self, select_task: &String) -> u64 {
|
||||||
|
self.worst_jobs_per_task_by_response_time().get(select_task).map_or(0, |job| job.response_time())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
/// extract computation time spent in each task and abb
|
||||||
|
/// task_name -> (abb_addr -> (interval_count, exec_count, exec_time))
|
||||||
|
fn select_abb_profile(
|
||||||
|
&self,
|
||||||
|
select_task: Option<String>,
|
||||||
|
) -> HashMap<String, HashMap<u32, (usize, usize, u64)>> {
|
||||||
|
if let Some(select_task) = select_task.as_ref() {
|
||||||
|
// Task selected, only profile this task
|
||||||
|
if let Some(worst_instance) = self
|
||||||
|
.worst_jobs_per_task_by_response_time()
|
||||||
|
.get(select_task)
|
||||||
|
{
|
||||||
|
let t: Vec<_> = self
|
||||||
|
.intervals()
|
||||||
|
.iter()
|
||||||
|
.filter(|x| {
|
||||||
|
x.start_tick < worst_instance.response && x.end_tick > worst_instance.release
|
||||||
|
})
|
||||||
|
.cloned()
|
||||||
|
.collect();
|
||||||
|
abb_profile(t)
|
||||||
|
} else {
|
||||||
|
HashMap::new()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Profile all tasks
|
||||||
|
abb_profile(self.intervals().clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn need_to_debug(&self) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -92,7 +129,7 @@ macro_rules! impl_emu_lookup {
|
|||||||
fn lookup(emu: &Qemu, addr: ::std::os::raw::c_uint) -> $struct_name {
|
fn lookup(emu: &Qemu, 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 {
|
||||||
emu.read_mem(addr.into(), &mut tmp);
|
emu.read_mem(addr.into(), &mut tmp).unwrap();
|
||||||
std::mem::transmute::<[u8; std::mem::size_of::<$struct_name>()], $struct_name>(tmp)
|
std::mem::transmute::<[u8; std::mem::size_of::<$struct_name>()], $struct_name>(tmp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,52 +1,51 @@
|
|||||||
use hashbrown::HashMap;
|
|
||||||
use libafl_bolts::Named;
|
|
||||||
use libafl::{
|
use libafl::{
|
||||||
executors::ExitKind,
|
common::HasNamedMetadata, executors::ExitKind, observers::Observer, observers::ObserversTuple,
|
||||||
observers::Observer,
|
prelude::UsesInput, Error,
|
||||||
Error,
|
|
||||||
common::HasNamedMetadata,
|
|
||||||
observers::ObserversTuple, prelude::UsesInput,
|
|
||||||
};
|
};
|
||||||
|
use libafl_bolts::Named;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::{fs::OpenOptions, io::Write};
|
use std::{fs::OpenOptions, io::Write};
|
||||||
|
|
||||||
use libafl::events::EventFirer;
|
use core::{fmt::Debug, time::Duration};
|
||||||
use libafl::state::MaybeHasClientPerfMonitor;
|
|
||||||
use libafl::prelude::State;
|
|
||||||
use libafl::feedbacks::Feedback;
|
|
||||||
use libafl::SerdeAny;
|
|
||||||
use libafl::common::HasMetadata;
|
use libafl::common::HasMetadata;
|
||||||
use libafl::corpus::testcase::Testcase;
|
use libafl::corpus::testcase::Testcase;
|
||||||
use core::{fmt::Debug, time::Duration};
|
use libafl::events::EventFirer;
|
||||||
use std::time::{SystemTime, UNIX_EPOCH};
|
use libafl::feedbacks::Feedback;
|
||||||
use std::path::PathBuf;
|
use libafl::prelude::State;
|
||||||
|
use libafl::state::MaybeHasClientPerfMonitor;
|
||||||
|
use libafl_bolts::tuples::MatchNameRef;
|
||||||
|
use libafl::SerdeAny;
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use std::time::{SystemTime, UNIX_EPOCH};
|
||||||
|
|
||||||
use crate::systemstate::observers::QemuSystemStateObserver;
|
use crate::systemstate::helpers::metadata_insert_or_update_get;
|
||||||
use crate::systemstate::target_os::TargetSystem;
|
use crate::systemstate::target_os::TargetSystem;
|
||||||
|
use crate::systemstate::target_os::SystemTraceData;
|
||||||
|
|
||||||
pub static mut FUZZ_START_TIMESTAMP : SystemTime = UNIX_EPOCH;
|
pub static mut FUZZ_START_TIMESTAMP: SystemTime = UNIX_EPOCH;
|
||||||
|
|
||||||
pub const QEMU_ICOUNT_SHIFT : u32 = 5;
|
pub const QEMU_ICOUNT_SHIFT: u32 = 5;
|
||||||
pub const QEMU_ISNS_PER_SEC : u32 = u32::pow(10, 9) / u32::pow(2, QEMU_ICOUNT_SHIFT);
|
pub const QEMU_ISNS_PER_SEC: u32 = u32::pow(10, 9) / u32::pow(2, QEMU_ICOUNT_SHIFT);
|
||||||
pub const QEMU_ISNS_PER_USEC : u32 = QEMU_ISNS_PER_SEC / 1000000;
|
pub const QEMU_ISNS_PER_USEC: u32 = QEMU_ISNS_PER_SEC / 1000000;
|
||||||
pub const _QEMU_NS_PER_ISN : u32 = 1 << QEMU_ICOUNT_SHIFT;
|
pub const _QEMU_NS_PER_ISN: u32 = 1 << QEMU_ICOUNT_SHIFT;
|
||||||
pub const _TARGET_SYSCLK_FREQ : u32 = 25 * 1000 * 1000;
|
pub const _TARGET_SYSCLK_FREQ: u32 = 25 * 1000 * 1000;
|
||||||
pub const _TARGET_MHZ_PER_MIPS : f32 = _TARGET_SYSCLK_FREQ as f32 / QEMU_ISNS_PER_SEC as f32;
|
pub const _TARGET_MHZ_PER_MIPS: f32 = _TARGET_SYSCLK_FREQ as f32 / QEMU_ISNS_PER_SEC as f32;
|
||||||
pub const _TARGET_MIPS_PER_MHZ : f32 = QEMU_ISNS_PER_SEC as f32 / _TARGET_SYSCLK_FREQ as f32;
|
pub const _TARGET_MIPS_PER_MHZ: f32 = QEMU_ISNS_PER_SEC as f32 / _TARGET_SYSCLK_FREQ as f32;
|
||||||
pub const _TARGET_SYSCLK_PER_QEMU_SEC : u32 = (_TARGET_SYSCLK_FREQ as f32 * _TARGET_MIPS_PER_MHZ) as u32;
|
pub const _TARGET_SYSCLK_PER_QEMU_SEC: u32 =
|
||||||
pub const _QEMU_SYSCLK_PER_TARGET_SEC : u32 = (_TARGET_SYSCLK_FREQ as f32 * _TARGET_MHZ_PER_MIPS) as u32;
|
(_TARGET_SYSCLK_FREQ as f32 * _TARGET_MIPS_PER_MHZ) as u32;
|
||||||
|
pub const _QEMU_SYSCLK_PER_TARGET_SEC: u32 =
|
||||||
|
(_TARGET_SYSCLK_FREQ as f32 * _TARGET_MHZ_PER_MIPS) as u32;
|
||||||
|
|
||||||
pub fn tick_to_time(ticks: u64) -> Duration {
|
pub fn tick_to_time(ticks: u64) -> Duration {
|
||||||
Duration::from_nanos((ticks << QEMU_ICOUNT_SHIFT) as u64)
|
Duration::from_nanos((ticks << QEMU_ICOUNT_SHIFT) as u64)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn tick_to_ms(ticks: u64) -> f32 {
|
pub fn tick_to_ms(ticks: u64) -> f32 {
|
||||||
(Duration::from_nanos(ticks << QEMU_ICOUNT_SHIFT).as_micros() as f32/10.0).round()/100.0
|
(Duration::from_nanos(ticks << QEMU_ICOUNT_SHIFT).as_micros() as f32 / 10.0).round() / 100.0
|
||||||
}
|
}
|
||||||
use libafl::prelude::StateInitializer;
|
use libafl::prelude::StateInitializer;
|
||||||
|
|
||||||
|
|
||||||
//========== Metadata
|
//========== Metadata
|
||||||
#[derive(Debug, SerdeAny, Serialize, Deserialize)]
|
#[derive(Debug, SerdeAny, Serialize, Deserialize)]
|
||||||
pub struct QemuIcountMetadata {
|
pub struct QemuIcountMetadata {
|
||||||
@ -68,16 +67,14 @@ pub struct MaxIcountMetadata {
|
|||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
impl Named for MaxIcountMetadata
|
impl Named for MaxIcountMetadata {
|
||||||
{
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn name(&self) -> &Cow<'static, str> {
|
fn name(&self) -> &Cow<'static, str> {
|
||||||
&self.name
|
&self.name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MaxIcountMetadata
|
impl MaxIcountMetadata {
|
||||||
{
|
|
||||||
/// Create new `MaxIcountMetadata`
|
/// Create new `MaxIcountMetadata`
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new(name: &'static str) -> Self {
|
pub fn new(name: &'static str) -> Self {
|
||||||
@ -95,8 +92,8 @@ impl Default for MaxIcountMetadata {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A piece of metadata tracking all icounts
|
/// A piece of metadata tracking all icounts
|
||||||
#[derive(Debug, SerdeAny, Serialize, Deserialize)]
|
#[derive(Debug, Default, SerdeAny, Serialize, Deserialize)]
|
||||||
pub struct IcHist (pub Vec<(u64, u128)>, pub (u64,u128));
|
pub struct IcHist(pub Vec<(u64, u128)>, pub (u64, u128));
|
||||||
|
|
||||||
//========== Observer
|
//========== Observer
|
||||||
|
|
||||||
@ -106,18 +103,16 @@ pub struct QemuClockObserver {
|
|||||||
name: Cow<'static, str>,
|
name: Cow<'static, str>,
|
||||||
start_tick: u64,
|
start_tick: u64,
|
||||||
end_tick: u64,
|
end_tick: u64,
|
||||||
dump_path: Option<PathBuf>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl QemuClockObserver {
|
impl QemuClockObserver {
|
||||||
/// Creates a new [`QemuClockObserver`] with the given name.
|
/// Creates a new [`QemuClockObserver`] with the given name.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new(name: &'static str, dump_path: Option<PathBuf>) -> Self {
|
pub fn new(name: &'static str) -> Self {
|
||||||
Self {
|
Self {
|
||||||
name: Cow::from(name),
|
name: Cow::from(name),
|
||||||
start_tick: 0,
|
start_tick: 0,
|
||||||
end_tick: 0,
|
end_tick: 0,
|
||||||
dump_path
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,59 +128,28 @@ where
|
|||||||
S: UsesInput + HasMetadata,
|
S: UsesInput + HasMetadata,
|
||||||
{
|
{
|
||||||
fn pre_exec(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> {
|
fn pre_exec(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> {
|
||||||
|
self.start_tick = 0;
|
||||||
// Only remember the pre-run ticks if presistent mode ist used
|
// Only remember the pre-run ticks if presistent mode ist used
|
||||||
#[cfg(not(feature = "snapshot_restore"))]
|
#[cfg(not(feature = "snapshot_restore"))]
|
||||||
unsafe {
|
unsafe {
|
||||||
self.start_tick=emu::icount_get_raw();
|
self.start_tick = emu::icount_get_raw();
|
||||||
self.end_tick=self.start_tick;
|
self.end_tick = self.start_tick;
|
||||||
}
|
}
|
||||||
// unsafe {
|
|
||||||
// println!("clock pre {}",emu::icount_get_raw());
|
|
||||||
// }
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn post_exec(&mut self, _state: &mut S, _input: &I, _exit_kind: &ExitKind) -> Result<(), Error> {
|
fn post_exec(
|
||||||
unsafe { self.end_tick = libafl_qemu::sys::icount_get_raw() };
|
&mut self,
|
||||||
if let Some(td) = &self.dump_path {
|
_state: &mut S,
|
||||||
// println!("clock post {}", self.end_tick);
|
_input: &I,
|
||||||
// println!("Number of Ticks: {} <- {} {}",self.end_tick - self.start_tick, self.end_tick, self.start_tick);
|
_exit_kind: &ExitKind,
|
||||||
let metadata =_state.metadata_map_mut();
|
) -> Result<(), Error> {
|
||||||
let hist = metadata.get_mut::<IcHist>();
|
if _exit_kind != &ExitKind::Ok {
|
||||||
let timestamp = SystemTime::now().duration_since(unsafe {FUZZ_START_TIMESTAMP}).unwrap().as_millis();
|
self.start_tick = 0;
|
||||||
match hist {
|
self.end_tick = 0;
|
||||||
Option::None => {
|
return Ok(());
|
||||||
#[cfg(not(feature="trace_job_response_times"))]
|
|
||||||
{
|
|
||||||
metadata.insert(IcHist(vec![(self.end_tick - self.start_tick, timestamp)],
|
|
||||||
(self.end_tick - self.start_tick, timestamp)));
|
|
||||||
}
|
|
||||||
#[cfg(feature="trace_job_response_times")]
|
|
||||||
metadata.insert(IcHist(vec![],(0,timestamp)));
|
|
||||||
}
|
|
||||||
Some(v) => {
|
|
||||||
#[cfg(not(feature="trace_job_response_times"))]
|
|
||||||
{
|
|
||||||
v.0.push((self.end_tick - self.start_tick, timestamp));
|
|
||||||
if v.1.0 < self.end_tick-self.start_tick {
|
|
||||||
v.1 = (self.end_tick - self.start_tick, timestamp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if v.0.len() >= 100 {
|
|
||||||
let mut file = OpenOptions::new()
|
|
||||||
.read(true)
|
|
||||||
.write(true)
|
|
||||||
.create(true)
|
|
||||||
.append(true)
|
|
||||||
.open(td).expect("Could not open timedump");
|
|
||||||
let newv : Vec<(u64, u128)> = Vec::with_capacity(110);
|
|
||||||
for i in std::mem::replace(&mut v.0, newv).into_iter() {
|
|
||||||
writeln!(file, "{},{}", i.0, i.1).expect("Write to dump failed");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
unsafe { self.end_tick = libafl_qemu::sys::icount_get_raw() };
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -203,7 +167,6 @@ impl Default for QemuClockObserver {
|
|||||||
name: Cow::from(String::from("clock")),
|
name: Cow::from(String::from("clock")),
|
||||||
start_tick: 0,
|
start_tick: 0,
|
||||||
end_tick: 0,
|
end_tick: 0,
|
||||||
dump_path: None
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -211,12 +174,12 @@ impl Default for QemuClockObserver {
|
|||||||
//========== Feedback
|
//========== Feedback
|
||||||
/// Nop feedback that annotates execution time in the new testcase, if any
|
/// Nop feedback that annotates execution time in the new testcase, if any
|
||||||
/// for this Feedback, the testcase is never interesting (use with an OR).
|
/// for this Feedback, the testcase is never interesting (use with an OR).
|
||||||
/// It decides, if the given [`QemuClockObserver`] value of a run is interesting.
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
pub struct ClockTimeFeedback<SYS> {
|
pub struct ClockTimeFeedback<SYS> {
|
||||||
exec_time: Option<Duration>,
|
exec_time: Option<Duration>,
|
||||||
select_task: Option<String>,
|
select_task: Option<String>,
|
||||||
name: Cow<'static, str>,
|
name: Cow<'static, str>,
|
||||||
|
dump_path: Option<PathBuf>,
|
||||||
phantom: std::marker::PhantomData<SYS>,
|
phantom: std::marker::PhantomData<SYS>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -233,25 +196,71 @@ where
|
|||||||
#[allow(clippy::wrong_self_convention)]
|
#[allow(clippy::wrong_self_convention)]
|
||||||
fn is_interesting(
|
fn is_interesting(
|
||||||
&mut self,
|
&mut self,
|
||||||
_state: &mut S,
|
state: &mut S,
|
||||||
_manager: &mut EM,
|
_manager: &mut EM,
|
||||||
_input: &I,
|
_input: &I,
|
||||||
observers: &OT,
|
observers: &OT,
|
||||||
_exit_kind: &ExitKind,
|
_exit_kind: &ExitKind,
|
||||||
) -> Result<bool, Error>
|
) -> Result<bool, Error>
|
||||||
where
|
where {
|
||||||
{
|
#[cfg(feature = "trace_job_response_times")]
|
||||||
#[cfg(feature="trace_job_response_times")]
|
let icount = {
|
||||||
{
|
if let Some(select) = self.select_task.as_ref() {
|
||||||
if self.select_task.is_some() {
|
let trace = state
|
||||||
let observer = observers.match_name::<QemuSystemStateObserver<S::Input, SYS>>("systemstate").unwrap();
|
.metadata::<SYS::TraceData>()
|
||||||
self.exec_time = Some(Duration::from_nanos(observer.last_runtime()));
|
.expect("TraceData not found");
|
||||||
return Ok(false)
|
trace.wort_of_task(select)
|
||||||
|
} else {
|
||||||
|
let observer = observers
|
||||||
|
.match_name::<QemuClockObserver>(self.name())
|
||||||
|
.unwrap();
|
||||||
|
observer.last_runtime()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#[cfg(not(feature = "trace_job_response_times"))]
|
||||||
|
let icount = {
|
||||||
|
let observer = observers
|
||||||
|
.match_name::<QemuClockObserver>(self.name())
|
||||||
|
.unwrap();
|
||||||
|
observer.last_runtime()
|
||||||
|
};
|
||||||
|
self.exec_time = Some(Duration::from_nanos(icount * _QEMU_NS_PER_ISN as u64));
|
||||||
|
|
||||||
|
// Dump the icounts to a file
|
||||||
|
if let Some(td) = &self.dump_path {
|
||||||
|
let metadata = state.metadata_map_mut();
|
||||||
|
let timestamp = SystemTime::now()
|
||||||
|
.duration_since(unsafe { FUZZ_START_TIMESTAMP })
|
||||||
|
.unwrap()
|
||||||
|
.as_millis();
|
||||||
|
let hist = metadata_insert_or_update_get::<IcHist>(
|
||||||
|
metadata,
|
||||||
|
|| IcHist(
|
||||||
|
vec![(icount, timestamp)],
|
||||||
|
(icount, timestamp),
|
||||||
|
),
|
||||||
|
|hist| {
|
||||||
|
hist.0.push((icount, timestamp));
|
||||||
|
if hist.1 .0 < icount {
|
||||||
|
hist.1 = (icount, timestamp);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
if hist.0.len() >= 100 {
|
||||||
|
let mut file = OpenOptions::new()
|
||||||
|
.read(true)
|
||||||
|
.write(true)
|
||||||
|
.create(true)
|
||||||
|
.append(true)
|
||||||
|
.open(td)
|
||||||
|
.expect("Could not open timedump");
|
||||||
|
let newv: Vec<(u64, u128)> = Vec::with_capacity(110);
|
||||||
|
for i in std::mem::replace(&mut hist.0, newv).into_iter() {
|
||||||
|
writeln!(file, "{},{}", i.0, i.1).expect("Write to dump failed");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// TODO Replace with match_name_type when stable
|
|
||||||
let observer = observers.match_name::<QemuClockObserver>(self.name()).unwrap();
|
|
||||||
self.exec_time = Some(Duration::from_nanos(observer.last_runtime()));
|
|
||||||
Ok(false)
|
Ok(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -287,22 +296,24 @@ impl<SYS> Named for ClockTimeFeedback<SYS> {
|
|||||||
impl<SYS> ClockTimeFeedback<SYS> {
|
impl<SYS> ClockTimeFeedback<SYS> {
|
||||||
/// Creates a new [`ClockFeedback`], deciding if the value of a [`QemuClockObserver`] with the given `name` of a run is interesting.
|
/// Creates a new [`ClockFeedback`], deciding if the value of a [`QemuClockObserver`] with the given `name` of a run is interesting.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new(name: &'static str, select_task: Option<String>) -> Self {
|
pub fn new(name: &'static str, select_task: Option<String>, dump_path: Option<PathBuf>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
exec_time: None,
|
exec_time: None,
|
||||||
select_task: select_task,
|
select_task: select_task,
|
||||||
name: Cow::from(name.to_string()),
|
name: Cow::from(name.to_string()),
|
||||||
|
dump_path: dump_path,
|
||||||
phantom: std::marker::PhantomData,
|
phantom: std::marker::PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new [`ClockFeedback`], deciding if the given [`QemuClockObserver`] value of a run is interesting.
|
/// Creates a new [`ClockFeedback`], deciding if the given [`QemuClockObserver`] value of a run is interesting.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new_with_observer(observer: &QemuClockObserver, select_task: &Option<String>) -> Self {
|
pub fn new_with_observer(observer: &QemuClockObserver, select_task: &Option<String>, dump_path: Option<PathBuf>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
exec_time: None,
|
exec_time: None,
|
||||||
select_task: select_task.clone(),
|
select_task: select_task.clone(),
|
||||||
name: observer.name().clone(),
|
name: observer.name().clone(),
|
||||||
|
dump_path: dump_path,
|
||||||
phantom: std::marker::PhantomData,
|
phantom: std::marker::PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -330,9 +341,9 @@ where
|
|||||||
_observers: &OT,
|
_observers: &OT,
|
||||||
_exit_kind: &ExitKind,
|
_exit_kind: &ExitKind,
|
||||||
) -> Result<bool, Error>
|
) -> Result<bool, Error>
|
||||||
where
|
where {
|
||||||
{
|
let observer = _observers
|
||||||
let observer = _observers.match_name::<QemuClockObserver>("clock")
|
.match_name::<QemuClockObserver>("clock")
|
||||||
.expect("QemuClockObserver not found");
|
.expect("QemuClockObserver not found");
|
||||||
let clock_state = state
|
let clock_state = state
|
||||||
.named_metadata_map_mut()
|
.named_metadata_map_mut()
|
||||||
@ -348,7 +359,13 @@ where
|
|||||||
|
|
||||||
/// Append to the testcase the generated metadata in case of a new corpus item
|
/// Append to the testcase the generated metadata in case of a new corpus item
|
||||||
#[inline]
|
#[inline]
|
||||||
fn append_metadata(&mut self, _state: &mut S, _manager: &mut EM, _observers: &OT, _testcase: &mut Testcase<I>) -> Result<(), Error> {
|
fn append_metadata(
|
||||||
|
&mut self,
|
||||||
|
_state: &mut S,
|
||||||
|
_manager: &mut EM,
|
||||||
|
_observers: &OT,
|
||||||
|
_testcase: &mut Testcase<I>,
|
||||||
|
) -> Result<(), Error> {
|
||||||
// testcase.metadata_mut().insert(QemuIcountMetadata{runtime: self.last_runtime});
|
// testcase.metadata_mut().insert(QemuIcountMetadata{runtime: self.last_runtime});
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -358,7 +375,6 @@ where
|
|||||||
fn discard_metadata(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> {
|
fn discard_metadata(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Named for QemuClockIncreaseFeedback {
|
impl Named for QemuClockIncreaseFeedback {
|
||||||
@ -372,7 +388,9 @@ impl QemuClockIncreaseFeedback {
|
|||||||
/// Creates a new [`HitFeedback`]
|
/// Creates a new [`HitFeedback`]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new(name: &'static str) -> Self {
|
pub fn new(name: &'static str) -> Self {
|
||||||
Self {name: Cow::from(String::from(name))}
|
Self {
|
||||||
|
name: Cow::from(String::from(name)),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -380,4 +398,4 @@ impl Default for QemuClockIncreaseFeedback {
|
|||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::new("MaxClock")
|
Self::new("MaxClock")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,47 +1,28 @@
|
|||||||
use core::fmt::Debug;
|
use core::{fmt::Debug, marker::PhantomData};
|
||||||
use core::cmp::Ordering::{Greater,Less,Equal};
|
|
||||||
use libafl::inputs::BytesInput;
|
|
||||||
use libafl::inputs::HasTargetBytes;
|
|
||||||
use libafl::feedbacks::MapIndexesMetadata;
|
|
||||||
use libafl::corpus::Testcase;
|
|
||||||
use libafl::prelude::{ClientStats, Monitor, SimplePrintingMonitor, UsesInput};
|
|
||||||
use core::marker::PhantomData;
|
|
||||||
use libafl::schedulers::{MinimizerScheduler, ProbabilitySamplingScheduler, TestcaseScore};
|
|
||||||
use std::path::PathBuf;
|
|
||||||
use std::fs;
|
|
||||||
use hashbrown::{HashMap};
|
|
||||||
use libafl::observers::ObserversTuple;
|
|
||||||
use libafl::executors::ExitKind;
|
|
||||||
use libafl::events::EventFirer;
|
|
||||||
use libafl::state::{MaybeHasClientPerfMonitor, HasCorpus, UsesState};
|
|
||||||
use libafl::prelude::State;
|
|
||||||
use libafl::inputs::Input;
|
|
||||||
use libafl::feedbacks::Feedback;
|
|
||||||
use libafl::common::HasMetadata;
|
|
||||||
use libafl_qemu::modules::edges::EdgeCoverageModule;
|
|
||||||
use libafl::observers::MapObserver;
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use std::cmp;
|
|
||||||
use std::time::Duration;
|
|
||||||
use std::time::Instant;
|
|
||||||
use std::ops::Sub;
|
|
||||||
|
|
||||||
use libafl::corpus::Corpus;
|
use std::{
|
||||||
|
borrow::Cow, ops::Sub, time::{Duration, Instant}
|
||||||
use libafl_bolts::{
|
|
||||||
AsSlice, ClientId, HasLen, Named
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use serde::{Serialize, Deserialize};
|
||||||
|
|
||||||
use libafl::{
|
use libafl::{
|
||||||
observers::Observer,
|
common::HasMetadata,
|
||||||
|
corpus::{Corpus, Testcase},
|
||||||
|
events::EventFirer,
|
||||||
|
executors::ExitKind,
|
||||||
|
feedbacks::{Feedback, MapIndexesMetadata},
|
||||||
|
observers::ObserversTuple,
|
||||||
|
prelude::{ClientStats, Monitor, SimplePrintingMonitor, State, StateInitializer, UsesInput},
|
||||||
|
schedulers::{MinimizerScheduler, ProbabilitySamplingScheduler, TestcaseScore},
|
||||||
|
state::{HasCorpus, MaybeHasClientPerfMonitor, UsesState},
|
||||||
Error,
|
Error,
|
||||||
};
|
};
|
||||||
|
use libafl_bolts::{ClientId, HasLen, Named};
|
||||||
|
|
||||||
use crate::systemstate::target_os::TargetSystem;
|
use crate::systemstate::target_os::TargetSystem;
|
||||||
use crate::time::clock::QemuClockObserver;
|
use crate::time::clock::QemuClockObserver;
|
||||||
|
|
||||||
use libafl::prelude::StateInitializer;
|
|
||||||
|
|
||||||
use std::borrow::Cow;
|
|
||||||
//=========================== Scheduler
|
//=========================== Scheduler
|
||||||
|
|
||||||
pub type TimeMaximizerCorpusScheduler<CS, O> =
|
pub type TimeMaximizerCorpusScheduler<CS, O> =
|
||||||
@ -50,18 +31,21 @@ pub type TimeMaximizerCorpusScheduler<CS, O> =
|
|||||||
/// Multiply the testcase size with the execution time.
|
/// Multiply the testcase size with the execution time.
|
||||||
/// This favors small and quick testcases.
|
/// This favors small and quick testcases.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct MaxTimeFavFactor
|
pub struct MaxTimeFavFactor {}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S> TestcaseScore<S> for MaxTimeFavFactor
|
impl<S> TestcaseScore<S> for MaxTimeFavFactor
|
||||||
where
|
where
|
||||||
S: HasCorpus,
|
S: HasCorpus,
|
||||||
{
|
{
|
||||||
fn compute(state: &S, entry: &mut Testcase<<S::Corpus as Corpus>::Input> ) -> Result<f64, Error> {
|
fn compute(
|
||||||
|
_state: &S,
|
||||||
|
entry: &mut Testcase<<S::Corpus as Corpus>::Input>,
|
||||||
|
) -> Result<f64, Error> {
|
||||||
// TODO maybe enforce entry.exec_time().is_some()
|
// TODO maybe enforce entry.exec_time().is_some()
|
||||||
let et = entry.exec_time().expect("testcase.exec_time is needed for scheduler");
|
let et = entry
|
||||||
let tns : i64 = et.as_nanos().try_into().expect("failed to convert time");
|
.exec_time()
|
||||||
|
.expect("testcase.exec_time is needed for scheduler");
|
||||||
|
let tns: i64 = et.as_nanos().try_into().expect("failed to convert time");
|
||||||
Ok(-tns as f64)
|
Ok(-tns as f64)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -86,223 +70,30 @@ where
|
|||||||
impl<S> TestcaseScore<S> for MaxExecsLenFavFactor<S>
|
impl<S> TestcaseScore<S> for MaxExecsLenFavFactor<S>
|
||||||
where
|
where
|
||||||
S: HasCorpus + HasMetadata,
|
S: HasCorpus + HasMetadata,
|
||||||
<<S as HasCorpus>::Corpus as libafl::corpus::Corpus>::Input: HasLen
|
<<S as HasCorpus>::Corpus as libafl::corpus::Corpus>::Input: HasLen,
|
||||||
{
|
{
|
||||||
fn compute( state: &S, entry: &mut Testcase<<S::Corpus as Corpus>::Input>) -> Result<f64, Error> {
|
fn compute(
|
||||||
let execs_per_hour = (3600.0/entry.exec_time().expect("testcase.exec_time is needed for scheduler").as_secs_f64());
|
state: &S,
|
||||||
let execs_times_length_per_hour = execs_per_hour*entry.load_len(state.corpus()).unwrap() as f64;
|
entry: &mut Testcase<<S::Corpus as Corpus>::Input>,
|
||||||
|
) -> Result<f64, Error> {
|
||||||
|
let execs_per_hour = (3600.0
|
||||||
|
/ entry
|
||||||
|
.exec_time()
|
||||||
|
.expect("testcase.exec_time is needed for scheduler")
|
||||||
|
.as_secs_f64());
|
||||||
|
let execs_times_length_per_hour =
|
||||||
|
execs_per_hour * entry.load_len(state.corpus()).unwrap() as f64;
|
||||||
Ok(execs_times_length_per_hour)
|
Ok(execs_times_length_per_hour)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//===================================================================
|
//===================================================================
|
||||||
|
/// A Feedback which rewards each increase in execution time
|
||||||
/// A Feedback reporting if the Input consists of strictly decreasing bytes.
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
pub struct SortedFeedback {
|
pub struct ExecTimeIncFeedback {
|
||||||
name: Cow<'static, str>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S> StateInitializer<S> for SortedFeedback {}
|
|
||||||
|
|
||||||
impl<EM, I, OT, S> Feedback<EM, I, OT, S> for SortedFeedback
|
|
||||||
where
|
|
||||||
S: State + UsesInput<Input = I> + MaybeHasClientPerfMonitor,
|
|
||||||
S::Input: HasTargetBytes,
|
|
||||||
EM: EventFirer<State = S>,
|
|
||||||
OT: ObserversTuple<I, S>,
|
|
||||||
{
|
|
||||||
#[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<bool, Error>
|
|
||||||
where
|
|
||||||
{
|
|
||||||
let t = _input.target_bytes();
|
|
||||||
let tmp = t.as_slice();
|
|
||||||
if tmp.len()<32 {return Ok(false);}
|
|
||||||
let tmp = Vec::<u8>::from(&tmp[0..32]);
|
|
||||||
// tmp.reverse();
|
|
||||||
// if tmp.is_sorted_by(|a,b| match a.partial_cmp(b).unwrap_or(Less) {
|
|
||||||
// Less => Some(Greater),
|
|
||||||
// Equal => Some(Greater),
|
|
||||||
// Greater => Some(Less),
|
|
||||||
// }) {return Ok(true)};
|
|
||||||
let mut is_sorted = true;
|
|
||||||
if tmp[0]<tmp[1] {
|
|
||||||
for i in 1..tmp.len() {
|
|
||||||
is_sorted &= tmp[i-1]<=tmp[i];
|
|
||||||
if !is_sorted {break;}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for i in 1..tmp.len() {
|
|
||||||
is_sorted &= tmp[i-1]>=tmp[i];
|
|
||||||
if !is_sorted {break;}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Ok(is_sorted);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Named for SortedFeedback {
|
|
||||||
#[inline]
|
|
||||||
fn name(&self) -> &Cow<'static, str> {
|
|
||||||
&self.name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SortedFeedback {
|
|
||||||
/// Creates a new [`HitFeedback`]
|
|
||||||
#[must_use]
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {name: Cow::from("Sorted".to_string()),}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for SortedFeedback {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::new()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//===================================================================
|
|
||||||
/// A Feedback which expects a certain minimum execution time
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
|
||||||
pub struct ExecTimeReachedFeedback
|
|
||||||
{
|
|
||||||
name: Cow<'static, str>,
|
|
||||||
target_time: u64,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S> StateInitializer<S> for ExecTimeReachedFeedback {}
|
|
||||||
|
|
||||||
impl<EM, I, OT, S> Feedback<EM, I, OT, S> for ExecTimeReachedFeedback
|
|
||||||
where
|
|
||||||
S: State + UsesInput + MaybeHasClientPerfMonitor,
|
|
||||||
EM: EventFirer<State = S>,
|
|
||||||
OT: ObserversTuple<I, S>,
|
|
||||||
{
|
|
||||||
#[allow(clippy::wrong_self_convention)]
|
|
||||||
fn is_interesting(
|
|
||||||
&mut self,
|
|
||||||
_state: &mut S,
|
|
||||||
_manager: &mut EM,
|
|
||||||
_input: &I,
|
|
||||||
observers: &OT,
|
|
||||||
_exit_kind: &ExitKind,
|
|
||||||
) -> Result<bool, Error>
|
|
||||||
where
|
|
||||||
{
|
|
||||||
let observer = observers.match_name::<QemuClockObserver>("clock")
|
|
||||||
.expect("QemuClockObserver not found");
|
|
||||||
Ok(observer.last_runtime() >= self.target_time)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Named for ExecTimeReachedFeedback
|
|
||||||
{
|
|
||||||
#[inline]
|
|
||||||
fn name(&self) -> &Cow<'static, str> {
|
|
||||||
&self.name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ExecTimeReachedFeedback
|
|
||||||
where
|
|
||||||
{
|
|
||||||
/// Creates a new [`ExecTimeReachedFeedback`]
|
|
||||||
#[must_use]
|
|
||||||
pub fn new(target_time : u64) -> Self {
|
|
||||||
Self {name: Cow::from("ExecTimeReachedFeedback".to_string()), target_time: target_time}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub static mut EXEC_TIME_COLLECTION : Vec<u32> = Vec::new();
|
|
||||||
|
|
||||||
/// A Noop Feedback which records a list of all execution times
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
|
||||||
pub struct ExecTimeCollectorFeedback
|
|
||||||
{
|
|
||||||
name: Cow<'static, str>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S> StateInitializer<S> for ExecTimeCollectorFeedback {}
|
|
||||||
|
|
||||||
impl<EM, I, OT, S> Feedback<EM, I, OT, S> for ExecTimeCollectorFeedback
|
|
||||||
where
|
|
||||||
S: State + UsesInput + MaybeHasClientPerfMonitor,
|
|
||||||
EM: EventFirer<State = S>,
|
|
||||||
OT: ObserversTuple<I, S>,
|
|
||||||
{
|
|
||||||
#[allow(clippy::wrong_self_convention)]
|
|
||||||
fn is_interesting(
|
|
||||||
&mut self,
|
|
||||||
_state: &mut S,
|
|
||||||
_manager: &mut EM,
|
|
||||||
_input: &I,
|
|
||||||
observers: &OT,
|
|
||||||
_exit_kind: &ExitKind,
|
|
||||||
) -> Result<bool, Error>
|
|
||||||
where
|
|
||||||
{
|
|
||||||
let observer = observers.match_name::<QemuClockObserver>("clock")
|
|
||||||
.expect("QemuClockObserver not found");
|
|
||||||
unsafe { EXEC_TIME_COLLECTION.push(observer.last_runtime().try_into().unwrap()); }
|
|
||||||
Ok(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Named for ExecTimeCollectorFeedback
|
|
||||||
{
|
|
||||||
#[inline]
|
|
||||||
fn name(&self) -> &Cow<'static, str> {
|
|
||||||
&self.name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ExecTimeCollectorFeedback
|
|
||||||
where
|
|
||||||
{
|
|
||||||
/// Creates a new [`ExecTimeCollectorFeedback`]
|
|
||||||
#[must_use]
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {name: Cow::from("ExecTimeCollectorFeedback".to_string())}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Shared Metadata for a SysStateFeedback
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
|
||||||
pub struct ExecTimeCollectorFeedbackState
|
|
||||||
{
|
|
||||||
name: Cow<'static, str>,
|
|
||||||
collection: Vec<u32>,
|
|
||||||
}
|
|
||||||
impl Named for ExecTimeCollectorFeedbackState
|
|
||||||
{
|
|
||||||
#[inline]
|
|
||||||
fn name(&self) -> &Cow<'static, str> {
|
|
||||||
&self.name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Default for ExecTimeCollectorFeedbackState {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {name: Cow::from("ExecTimeCollectorFeedbackState".to_string()), collection: Vec::new()}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//===================================================================
|
|
||||||
/// A Feedback which expects a certain minimum execution time
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
|
||||||
pub struct ExecTimeIncFeedback
|
|
||||||
{
|
|
||||||
name: Cow<'static, str>,
|
name: Cow<'static, str>,
|
||||||
longest_time: u64,
|
longest_time: u64,
|
||||||
last_is_longest: bool
|
last_is_longest: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S> StateInitializer<S> for ExecTimeIncFeedback {}
|
impl<S> StateInitializer<S> for ExecTimeIncFeedback {}
|
||||||
@ -322,9 +113,9 @@ where
|
|||||||
observers: &OT,
|
observers: &OT,
|
||||||
_exit_kind: &ExitKind,
|
_exit_kind: &ExitKind,
|
||||||
) -> Result<bool, Error>
|
) -> Result<bool, Error>
|
||||||
where
|
where {
|
||||||
{
|
let observer = observers
|
||||||
let observer = observers.match_name::<QemuClockObserver>("clocktime")
|
.match_name::<QemuClockObserver>("clocktime")
|
||||||
.expect("QemuClockObserver not found");
|
.expect("QemuClockObserver not found");
|
||||||
if observer.last_runtime() > self.longest_time {
|
if observer.last_runtime() > self.longest_time {
|
||||||
self.longest_time = observer.last_runtime();
|
self.longest_time = observer.last_runtime();
|
||||||
@ -344,7 +135,7 @@ where
|
|||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
#[cfg(feature = "feed_afl")]
|
#[cfg(feature = "feed_afl")]
|
||||||
if self.last_is_longest {
|
if self.last_is_longest {
|
||||||
let mim : Option<&mut MapIndexesMetadata>= testcase.metadata_map_mut().get_mut();
|
let mim: Option<&mut MapIndexesMetadata> = testcase.metadata_map_mut().get_mut();
|
||||||
// pretend that the longest input alone excercises some non-existing edge, to keep it relevant
|
// pretend that the longest input alone excercises some non-existing edge, to keep it relevant
|
||||||
mim.unwrap().list.push(usize::MAX);
|
mim.unwrap().list.push(usize::MAX);
|
||||||
};
|
};
|
||||||
@ -352,35 +143,34 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Named for ExecTimeIncFeedback
|
impl Named for ExecTimeIncFeedback {
|
||||||
{
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn name(&self) -> &Cow<'static, str> {
|
fn name(&self) -> &Cow<'static, str> {
|
||||||
&self.name
|
&self.name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ExecTimeIncFeedback
|
impl ExecTimeIncFeedback {
|
||||||
where
|
|
||||||
{
|
|
||||||
/// Creates a new [`ExecTimeReachedFeedback`]
|
/// Creates a new [`ExecTimeReachedFeedback`]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {name: Cow::from("ExecTimeReachedFeedback".to_string()), longest_time: 0, last_is_longest: false}
|
Self {
|
||||||
|
name: Cow::from("ExecTimeReachedFeedback".to_string()),
|
||||||
|
longest_time: 0,
|
||||||
|
last_is_longest: false,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A Noop Feedback which records a list of all execution times
|
/// A Noop Feedback which records a list of all execution times
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
pub struct AlwaysTrueFeedback
|
pub struct AlwaysTrueFeedback {
|
||||||
{
|
name: Cow<'static, str>,
|
||||||
name: Cow<'static, str>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S> StateInitializer<S> for AlwaysTrueFeedback {}
|
impl<S> StateInitializer<S> for AlwaysTrueFeedback {}
|
||||||
|
|
||||||
impl<EM, I, OT, S> Feedback<EM, I, OT, S> for AlwaysTrueFeedback
|
impl<EM, I, OT, S> Feedback<EM, I, OT, S> for AlwaysTrueFeedback
|
||||||
|
|
||||||
where
|
where
|
||||||
S: State + UsesInput + MaybeHasClientPerfMonitor,
|
S: State + UsesInput + MaybeHasClientPerfMonitor,
|
||||||
EM: EventFirer<State = S>,
|
EM: EventFirer<State = S>,
|
||||||
@ -395,37 +185,31 @@ where
|
|||||||
_observers: &OT,
|
_observers: &OT,
|
||||||
_exit_kind: &ExitKind,
|
_exit_kind: &ExitKind,
|
||||||
) -> Result<bool, Error>
|
) -> Result<bool, Error>
|
||||||
where
|
where {
|
||||||
{
|
|
||||||
Ok(true)
|
Ok(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Named for AlwaysTrueFeedback
|
impl Named for AlwaysTrueFeedback {
|
||||||
{
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn name(&self) -> &Cow<'static, str> {
|
fn name(&self) -> &Cow<'static, str> {
|
||||||
&self.name
|
&self.name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AlwaysTrueFeedback
|
impl AlwaysTrueFeedback {
|
||||||
where
|
|
||||||
{
|
|
||||||
/// Creates a new [`ExecTimeCollectorFeedback`]
|
/// Creates a new [`ExecTimeCollectorFeedback`]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
name: Cow::from("AlwaysTrueFeedback".to_string())
|
name: Cow::from("AlwaysTrueFeedback".to_string()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//=========================== Probability Mass Scheduler
|
//=========================== Probability Mass Scheduler
|
||||||
|
|
||||||
pub type TimeProbMassScheduler<S> =
|
pub type TimeProbMassScheduler<S> = ProbabilitySamplingScheduler<TimeProbFactor<S>>;
|
||||||
ProbabilitySamplingScheduler<TimeProbFactor<S>>;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct TimeProbFactor<S>
|
pub struct TimeProbFactor<S>
|
||||||
@ -443,15 +227,19 @@ impl<S> TestcaseScore<S> for TimeProbFactor<S>
|
|||||||
where
|
where
|
||||||
S: HasCorpus,
|
S: HasCorpus,
|
||||||
{
|
{
|
||||||
fn compute(_state: &S, entry: &mut Testcase<<S::Corpus as Corpus>::Input>) -> Result<f64, Error> {
|
fn compute(
|
||||||
|
_state: &S,
|
||||||
|
entry: &mut Testcase<<S::Corpus as Corpus>::Input>,
|
||||||
|
) -> Result<f64, Error> {
|
||||||
// TODO maybe enforce entry.exec_time().is_some()
|
// TODO maybe enforce entry.exec_time().is_some()
|
||||||
let et = entry.exec_time().expect("testcase.exec_time is needed for scheduler");
|
let et = entry
|
||||||
let tns : i64 = et.as_nanos().try_into().expect("failed to convert time");
|
.exec_time()
|
||||||
Ok(((tns as f64)/1000.0).powf(2.0)) //microseconds
|
.expect("testcase.exec_time is needed for scheduler");
|
||||||
|
let tns: i64 = et.as_nanos().try_into().expect("failed to convert time");
|
||||||
|
Ok(((tns as f64) / 1000.0).powf(2.0)) //microseconds
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Monitor that prints with a limited rate.
|
/// Monitor that prints with a limited rate.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct RateLimitedMonitor {
|
pub struct RateLimitedMonitor {
|
||||||
@ -483,8 +271,10 @@ impl Monitor for RateLimitedMonitor {
|
|||||||
#[inline]
|
#[inline]
|
||||||
fn display(&mut self, event_msg: &str, sender_id: ClientId) {
|
fn display(&mut self, event_msg: &str, sender_id: ClientId) {
|
||||||
let now = Instant::now();
|
let now = Instant::now();
|
||||||
const RATE : Duration = Duration::from_secs(5);
|
const RATE: Duration = Duration::from_secs(5);
|
||||||
if (event_msg!="Testcase" && event_msg!="UserStats") || now.duration_since(self.last) > RATE {
|
if (event_msg != "Testcase" && event_msg != "UserStats")
|
||||||
|
|| now.duration_since(self.last) > RATE
|
||||||
|
{
|
||||||
self.inner.display(event_msg, sender_id);
|
self.inner.display(event_msg, sender_id);
|
||||||
self.last = now;
|
self.last = now;
|
||||||
}
|
}
|
||||||
@ -506,4 +296,4 @@ impl Default for RateLimitedMonitor {
|
|||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::new()
|
Self::new()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,18 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
|
TEST_KERNEL=../benchmark/build/waters_seq_full.elf
|
||||||
|
TEST_SYMBOLS=../benchmark/target_symbols.csv
|
||||||
|
DEF_ARGS="-k $TEST_KERNEL -c $TEST_SYMBOLS -n ./dump/test"
|
||||||
|
|
||||||
# cargo build --no-default-features --features std,snapshot_restore,singlecore,feed_afl,observer_hitcounts
|
# cargo build --no-default-features --features std,snapshot_restore,singlecore,feed_afl,observer_hitcounts
|
||||||
|
|
||||||
# Test basic fuzzing loop
|
# Test basic fuzzing loop
|
||||||
../target/debug/fret -k ../benchmark/build/waters.elf -c ../benchmark/target_symbols.csv -n ./dump/waters -tar fuzz -t 10 -s 123
|
# ../target/debug/fret $DEF_ARGS -tar fuzz -t 10 -s 123
|
||||||
|
|
||||||
# Test reprodcibility
|
# Test reprodcibility
|
||||||
rm -f ./dump/demo.case.time
|
rm -f ./dump/test.time
|
||||||
../target/debug/fret -k ../benchmark/build/waters.elf -c ../benchmark/target_symbols.csv -n ./dump/demo -tr showmap -i ./demo.case
|
../target/debug/fret $DEF_ARGS -tr showmap -i ./waters.case.test
|
||||||
if [[ $(cut -d, -f1 ./dump/demo.case.time) != $(cut -d, -f1 ./demo.example.time) ]]; then echo "Not reproducible!" && exit 1; else echo "Reproducible"; fi
|
if [[ $(cut -d, -f1 ./dump/test.time) != $(cut -d, -f1 ./waters.time.test) ]]; then echo "Not reproducible!" && exit 1; else echo "Reproducible"; fi
|
||||||
|
|
||||||
# Test state dump
|
# Test state dump
|
||||||
# cargo build --no-default-features --features std,snapshot_restore,singlecore,feed_afl,observer_hitcounts,systemstate
|
# cargo build --no-default-features --features std,snapshot_restore,singlecore,feed_afl,observer_hitcounts,systemstate
|
||||||
@ -22,6 +26,6 @@ if [[ -n "$(diff -q demo.example.abb.ron dump/demo.trace.ron)" ]]; then echo "AB
|
|||||||
# ../target/debug/fret -k ../benchmark/build/minimal.elf -c ../benchmark/target_symbols.csv -n ./dump/minimal_worst -tr showmap -i ./dump/minimal.case
|
# ../target/debug/fret -k ../benchmark/build/minimal.elf -c ../benchmark/target_symbols.csv -n ./dump/minimal_worst -tr showmap -i ./dump/minimal.case
|
||||||
|
|
||||||
# Test fuzzing using systemtraces
|
# Test fuzzing using systemtraces
|
||||||
cargo build --no-default-features --features std,snapshot_restore,singlecore,feed_systemtrace
|
cargo build --no-default-features --features std,snapshot_restore,singlecore,config_stg
|
||||||
|
|
||||||
../target/debug/fret -k ../benchmark/build/waters.elf -c ../benchmark/target_symbols.csv -n ./dump/waters -tar fuzz -t 10 -s 123
|
../target/debug/fret -k ../benchmark/build/waters_seq_full.elf -c ../benchmark/target_symbols.csv -n ./dump/waters -tar fuzz -t 10 -s 123
|
||||||
|
Loading…
x
Reference in New Issue
Block a user