diff --git a/libafl/src/executors/shadow.rs b/libafl/src/executors/shadow.rs index 99441fcf59..a3cec08f43 100644 --- a/libafl/src/executors/shadow.rs +++ b/libafl/src/executors/shadow.rs @@ -1,4 +1,4 @@ -//! A `ShadowExecutor` wraps an executor to have shadow observer that will not be considered by the manager +//! A `ShadowExecutor` wraps an executor to have shadow observer that will not be considered by the feedbacks and the manager use crate::{ executors::{Executor, ExitKind, HasExecHooksTuple, HasObservers, HasObserversHooks}, @@ -27,7 +27,7 @@ pub trait HasShadowObserverHooks { ) -> Result<(), Error>; } -/// A [`ShadowExecutor`] wraps a primary executor, forwarding its methods, and a secondary one +/// A [`ShadowExecutor`] wraps an executor and a set of shadow observers pub struct ShadowExecutor { executor: E, shadow_observers: SOT, @@ -70,6 +70,14 @@ where pub fn shadow_observers_mut(&mut self) -> &mut SOT { &mut self.shadow_observers } + + pub fn shadow_hooks(&self) -> &bool { + &self.shadow_hooks + } + + pub fn shadow_hooks_mut(&mut self) -> &mut bool { + &mut self.shadow_hooks + } } impl HasShadowObserverHooks for ShadowExecutor diff --git a/libafl/src/stages/tracing.rs b/libafl/src/stages/tracing.rs index 4e37dce554..1a564c116e 100644 --- a/libafl/src/stages/tracing.rs +++ b/libafl/src/stages/tracing.rs @@ -2,7 +2,7 @@ use core::{marker::PhantomData, mem::drop}; use crate::{ corpus::Corpus, - executors::{Executor, HasExecHooksTuple, HasObservers, HasObserversHooks}, + executors::{Executor, HasExecHooksTuple, HasObservers, HasObserversHooks, ShadowExecutor}, inputs::Input, mark_feature_time, observers::ObserversTuple, @@ -15,7 +15,7 @@ use crate::{ #[cfg(feature = "introspection")] use crate::stats::PerfFeature; -/// The default mutational stage +/// A stage that runs a tracer executor #[derive(Clone, Debug)] pub struct TracingStage where @@ -87,7 +87,7 @@ where OT: ObserversTuple + HasExecHooksTuple, S: HasClientPerfStats + HasExecutions + HasCorpus, { - /// Creates a new default mutational stage + /// Creates a new default stage pub fn new(tracer_executor: TE) -> Self { Self { tracer_executor, @@ -95,3 +95,78 @@ where } } } + +/// A stage that runs the shadow executor using also the shadow observers +#[derive(Clone, Debug)] +pub struct ShadowTracingStage { + #[allow(clippy::type_complexity)] + phantom: PhantomData<(C, E, EM, I, OT, S, SOT, Z)>, +} + +impl Stage, EM, S, Z> + for ShadowTracingStage +where + I: Input, + C: Corpus, + E: Executor + HasObservers + HasObserversHooks, + OT: ObserversTuple + HasExecHooksTuple, + SOT: ObserversTuple + HasExecHooksTuple, + S: HasClientPerfStats + HasExecutions + HasCorpus, +{ + #[inline] + fn perform( + &mut self, + fuzzer: &mut Z, + executor: &mut ShadowExecutor, + state: &mut S, + manager: &mut EM, + corpus_idx: usize, + ) -> Result<(), Error> { + start_timer!(state); + let input = state + .corpus() + .get(corpus_idx)? + .borrow_mut() + .load_input()? + .clone(); + mark_feature_time!(state, PerfFeature::GetInputFromCorpus); + + let prev_shadow_hooks = *executor.shadow_hooks(); + *executor.shadow_hooks_mut() = true; + + start_timer!(state); + executor.pre_exec_observers(fuzzer, state, manager, &input)?; + mark_feature_time!(state, PerfFeature::PreExecObservers); + + start_timer!(state); + drop(executor.run_target(fuzzer, state, manager, &input)?); + mark_feature_time!(state, PerfFeature::TargetExecution); + + *state.executions_mut() += 1; + + start_timer!(state); + executor.post_exec_observers(fuzzer, state, manager, &input)?; + mark_feature_time!(state, PerfFeature::PostExecObservers); + + *executor.shadow_hooks_mut() = prev_shadow_hooks; + + Ok(()) + } +} + +impl ShadowTracingStage +where + I: Input, + C: Corpus, + E: Executor + HasObservers + HasObserversHooks, + OT: ObserversTuple + HasExecHooksTuple, + SOT: ObserversTuple + HasExecHooksTuple, + S: HasClientPerfStats + HasExecutions + HasCorpus, +{ + /// Creates a new default stage + pub fn new(_executor: &mut ShadowExecutor) -> Self { + Self { + phantom: PhantomData, + } + } +}