pub mod map;
pub use map::*;
pub mod cmp;
pub use cmp::*;
#[cfg(feature = "std")]
pub mod stdio;
#[cfg(feature = "std")]
pub use stdio::{StdErrObserver, StdOutObserver};
#[cfg(feature = "regex")]
pub mod stacktrace;
#[cfg(feature = "regex")]
pub use stacktrace::*;
pub mod concolic;
pub mod value;
pub mod list;
use alloc::string::{String, ToString};
use core::{fmt::Debug, time::Duration};
#[cfg(feature = "std")]
use std::time::Instant;
#[cfg(feature = "no_std")]
use libafl_bolts::current_time;
use libafl_bolts::{tuples::MatchName, Named};
pub use list::*;
use serde::{Deserialize, Serialize};
pub use value::*;
use crate::{executors::ExitKind, inputs::UsesInput, state::UsesState, Error};
pub trait UsesObserver<S>
where
S: UsesInput,
{
type Observer: Observer<S>;
}
pub trait Observer<S>: Named
where
S: UsesInput,
{
#[inline]
fn flush(&mut self) -> Result<(), Error> {
Ok(())
}
#[inline]
fn pre_exec(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> {
Ok(())
}
#[inline]
fn post_exec(
&mut self,
_state: &mut S,
_input: &S::Input,
_exit_kind: &ExitKind,
) -> Result<(), Error> {
Ok(())
}
#[inline]
fn pre_exec_child(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> {
Ok(())
}
#[inline]
fn post_exec_child(
&mut self,
_state: &mut S,
_input: &S::Input,
_exit_kind: &ExitKind,
) -> Result<(), Error> {
Ok(())
}
#[inline]
fn observes_stdout(&self) -> bool {
false
}
#[inline]
fn observes_stderr(&self) -> bool {
false
}
#[inline]
#[allow(unused_variables)]
fn observe_stdout(&mut self, stdout: &[u8]) {}
#[inline]
#[allow(unused_variables)]
fn observe_stderr(&mut self, stderr: &[u8]) {}
}
pub trait UsesObservers: UsesState {
type Observers: ObserversTuple<Self::State>;
}
pub trait ObserversTuple<S>: MatchName
where
S: UsesInput,
{
fn pre_exec_all(&mut self, state: &mut S, input: &S::Input) -> Result<(), Error>;
fn post_exec_all(
&mut self,
state: &mut S,
input: &S::Input,
exit_kind: &ExitKind,
) -> Result<(), Error>;
fn pre_exec_child_all(&mut self, state: &mut S, input: &S::Input) -> Result<(), Error>;
fn post_exec_child_all(
&mut self,
state: &mut S,
input: &S::Input,
exit_kind: &ExitKind,
) -> Result<(), Error>;
fn observes_stdout(&self) -> bool;
fn observes_stderr(&self) -> bool;
fn observe_stdout(&mut self, stdout: &[u8]);
fn observe_stderr(&mut self, stderr: &[u8]);
}
impl<S> ObserversTuple<S> for ()
where
S: UsesInput,
{
fn pre_exec_all(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> {
Ok(())
}
fn post_exec_all(
&mut self,
_state: &mut S,
_input: &S::Input,
_exit_kind: &ExitKind,
) -> Result<(), Error> {
Ok(())
}
fn pre_exec_child_all(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> {
Ok(())
}
fn post_exec_child_all(
&mut self,
_state: &mut S,
_input: &S::Input,
_exit_kind: &ExitKind,
) -> Result<(), Error> {
Ok(())
}
#[inline]
fn observes_stdout(&self) -> bool {
false
}
#[inline]
fn observes_stderr(&self) -> bool {
false
}
#[inline]
#[allow(unused_variables)]
fn observe_stdout(&mut self, stdout: &[u8]) {}
#[inline]
#[allow(unused_variables)]
fn observe_stderr(&mut self, stderr: &[u8]) {}
}
impl<Head, Tail, S> ObserversTuple<S> for (Head, Tail)
where
Head: Observer<S>,
Tail: ObserversTuple<S>,
S: UsesInput,
{
fn pre_exec_all(&mut self, state: &mut S, input: &S::Input) -> Result<(), Error> {
self.0.pre_exec(state, input)?;
self.1.pre_exec_all(state, input)
}
fn post_exec_all(
&mut self,
state: &mut S,
input: &S::Input,
exit_kind: &ExitKind,
) -> Result<(), Error> {
self.0.post_exec(state, input, exit_kind)?;
self.1.post_exec_all(state, input, exit_kind)
}
fn pre_exec_child_all(&mut self, state: &mut S, input: &S::Input) -> Result<(), Error> {
self.0.pre_exec_child(state, input)?;
self.1.pre_exec_child_all(state, input)
}
fn post_exec_child_all(
&mut self,
state: &mut S,
input: &S::Input,
exit_kind: &ExitKind,
) -> Result<(), Error> {
self.0.post_exec_child(state, input, exit_kind)?;
self.1.post_exec_child_all(state, input, exit_kind)
}
#[inline]
fn observes_stdout(&self) -> bool {
self.0.observes_stdout() || self.1.observes_stdout()
}
#[inline]
fn observes_stderr(&self) -> bool {
self.0.observes_stderr() || self.1.observes_stderr()
}
#[inline]
fn observe_stdout(&mut self, stdout: &[u8]) {
self.0.observe_stdout(stdout);
self.1.observe_stdout(stdout);
}
#[inline]
fn observe_stderr(&mut self, stderr: &[u8]) {
self.0.observe_stderr(stderr);
self.1.observe_stderr(stderr);
}
}
pub trait ObserverWithHashField {
fn hash(&self) -> Option<u64>;
}
#[allow(unused_variables)]
pub trait DifferentialObserver<OTA, OTB, S>: Observer<S>
where
OTA: ObserversTuple<S>,
OTB: ObserversTuple<S>,
S: UsesInput,
{
fn pre_observe_first(&mut self, observers: &mut OTA) -> Result<(), Error> {
Ok(())
}
fn post_observe_first(&mut self, observers: &mut OTA) -> Result<(), Error> {
Ok(())
}
fn pre_observe_second(&mut self, observers: &mut OTB) -> Result<(), Error> {
Ok(())
}
fn post_observe_second(&mut self, observers: &mut OTB) -> Result<(), Error> {
Ok(())
}
}
pub trait DifferentialObserversTuple<OTA, OTB, S>: ObserversTuple<S>
where
OTA: ObserversTuple<S>,
OTB: ObserversTuple<S>,
S: UsesInput,
{
fn pre_observe_first_all(&mut self, observers: &mut OTA) -> Result<(), Error>;
fn post_observe_first_all(&mut self, observers: &mut OTA) -> Result<(), Error>;
fn pre_observe_second_all(&mut self, observers: &mut OTB) -> Result<(), Error>;
fn post_observe_second_all(&mut self, observers: &mut OTB) -> Result<(), Error>;
}
impl<OTA, OTB, S> DifferentialObserversTuple<OTA, OTB, S> for ()
where
OTA: ObserversTuple<S>,
OTB: ObserversTuple<S>,
S: UsesInput,
{
fn pre_observe_first_all(&mut self, _: &mut OTA) -> Result<(), Error> {
Ok(())
}
fn post_observe_first_all(&mut self, _: &mut OTA) -> Result<(), Error> {
Ok(())
}
fn pre_observe_second_all(&mut self, _: &mut OTB) -> Result<(), Error> {
Ok(())
}
fn post_observe_second_all(&mut self, _: &mut OTB) -> Result<(), Error> {
Ok(())
}
}
impl<Head, Tail, OTA, OTB, S> DifferentialObserversTuple<OTA, OTB, S> for (Head, Tail)
where
Head: DifferentialObserver<OTA, OTB, S>,
Tail: DifferentialObserversTuple<OTA, OTB, S>,
OTA: ObserversTuple<S>,
OTB: ObserversTuple<S>,
S: UsesInput,
{
fn pre_observe_first_all(&mut self, observers: &mut OTA) -> Result<(), Error> {
self.0.pre_observe_first(observers)?;
self.1.pre_observe_first_all(observers)
}
fn post_observe_first_all(&mut self, observers: &mut OTA) -> Result<(), Error> {
self.0.post_observe_first(observers)?;
self.1.post_observe_first_all(observers)
}
fn pre_observe_second_all(&mut self, observers: &mut OTB) -> Result<(), Error> {
self.0.pre_observe_second(observers)?;
self.1.pre_observe_second_all(observers)
}
fn post_observe_second_all(&mut self, observers: &mut OTB) -> Result<(), Error> {
self.0.post_observe_second(observers)?;
self.1.post_observe_second_all(observers)
}
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct TimeObserver {
name: String,
#[cfg(feature = "std")]
#[serde(with = "instant_serializer")]
start_time: Instant,
#[cfg(feature = "no_std")]
start_time: Duration,
last_runtime: Option<Duration>,
}
#[cfg(feature = "std")]
mod instant_serializer {
use core::time::Duration;
use std::time::Instant;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
#[allow(clippy::trivially_copy_pass_by_ref)]
pub fn serialize<S>(instant: &Instant, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let duration = instant.elapsed();
duration.serialize(serializer)
}
pub fn deserialize<'de, D>(deserializer: D) -> Result<Instant, D::Error>
where
D: Deserializer<'de>,
{
let duration = Duration::deserialize(deserializer)?;
let instant = Instant::now().checked_sub(duration).unwrap();
Ok(instant)
}
}
impl TimeObserver {
#[must_use]
pub fn new(name: &'static str) -> Self {
Self {
name: name.to_string(),
#[cfg(feature = "std")]
start_time: Instant::now(),
#[cfg(feature = "no_std")]
start_time: Duration::from_secs(0),
last_runtime: None,
}
}
#[must_use]
pub fn last_runtime(&self) -> &Option<Duration> {
&self.last_runtime
}
}
impl<S> Observer<S> for TimeObserver
where
S: UsesInput,
{
#[cfg(feature = "std")]
fn pre_exec(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> {
self.last_runtime = None;
self.start_time = Instant::now();
Ok(())
}
#[cfg(feature = "no_std")]
fn pre_exec(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> {
self.last_runtime = None;
self.start_time = current_time();
Ok(())
}
#[cfg(feature = "std")]
fn post_exec(
&mut self,
_state: &mut S,
_input: &S::Input,
_exit_kind: &ExitKind,
) -> Result<(), Error> {
self.last_runtime = Some(self.start_time.elapsed());
Ok(())
}
#[cfg(feature = "no_std")]
fn post_exec(
&mut self,
_state: &mut S,
_input: &S::Input,
_exit_kind: &ExitKind,
) -> Result<(), Error> {
self.last_runtime = current_time().checked_sub(self.start_time);
}
}
impl Named for TimeObserver {
fn name(&self) -> &str {
&self.name
}
}
impl<OTA, OTB, S> DifferentialObserver<OTA, OTB, S> for TimeObserver
where
OTA: ObserversTuple<S>,
OTB: ObserversTuple<S>,
S: UsesInput,
{
}
#[cfg(feature = "std")]
#[cfg(test)]
mod tests {
use core::ptr::addr_of_mut;
use libafl_bolts::{
ownedref::OwnedMutSlice,
tuples::{tuple_list, tuple_list_type},
Named,
};
use crate::observers::{StdMapObserver, TimeObserver};
static mut MAP: [u32; 4] = [0; 4];
#[test]
fn test_observer_serde() {
let obv = tuple_list!(TimeObserver::new("time"), unsafe {
StdMapObserver::from_ownedref(
"map",
OwnedMutSlice::from_raw_parts_mut(addr_of_mut!(MAP) as *mut u32, MAP.len()),
)
});
let vec = postcard::to_allocvec(&obv).unwrap();
log::info!("{vec:?}");
let obv2: tuple_list_type!(TimeObserver, StdMapObserver<u32, false>) =
postcard::from_bytes(&vec).unwrap();
assert_eq!(obv.0.name(), obv2.0.name());
}
}