MultiMapObserver and sancov 8bit-counters instrumentation (#343)
* MultiMapObserver and 8bit instrumentation * fix test * clippy * fix * fix tutorial * sancov_8bit targets feature
This commit is contained in:
parent
e46bb8643a
commit
eca605bf01
@ -1,6 +1,6 @@
|
|||||||
use libafl::{
|
use libafl::{
|
||||||
bolts::ownedref::OwnedSlice,
|
bolts::{ownedref::OwnedSlice, HasLen},
|
||||||
inputs::{HasLen, HasTargetBytes, Input},
|
inputs::{HasTargetBytes, Input},
|
||||||
};
|
};
|
||||||
|
|
||||||
use lain::prelude::*;
|
use lain::prelude::*;
|
||||||
|
@ -68,6 +68,7 @@ ctor = "0.1.20"
|
|||||||
num_enum = { version = "0.5.1", default-features = false }
|
num_enum = { version = "0.5.1", default-features = false }
|
||||||
typed-builder = "0.9.0" # Implement the builder pattern at compiletime
|
typed-builder = "0.9.0" # Implement the builder pattern at compiletime
|
||||||
ahash = { version = "0.7", default-features=false, features=["compile-time-rng"] } # The hash function already used in hashbrown
|
ahash = { version = "0.7", default-features=false, features=["compile-time-rng"] } # The hash function already used in hashbrown
|
||||||
|
intervaltree = { git = "https://github.com/andreafioraldi/rust-intervaltree", version = "0.2.6", default-features = false, features = ["serde"] }
|
||||||
|
|
||||||
libafl_derive = { version = "0.6.1", optional = true, path = "../libafl_derive" }
|
libafl_derive = { version = "0.6.1", optional = true, path = "../libafl_derive" }
|
||||||
serde_json = { version = "1.0", optional = true, default-features = false, features = ["alloc"] } # an easy way to debug print SerdeAnyMap
|
serde_json = { version = "1.0", optional = true, default-features = false, features = ["alloc"] } # an easy way to debug print SerdeAnyMap
|
||||||
|
@ -27,6 +27,17 @@ pub trait AsSlice<T> {
|
|||||||
fn as_slice(&self) -> &[T];
|
fn as_slice(&self) -> &[T];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Has a length field
|
||||||
|
pub trait HasLen {
|
||||||
|
/// The length
|
||||||
|
fn len(&self) -> usize;
|
||||||
|
|
||||||
|
/// Returns `true` if it has no elements.
|
||||||
|
fn is_empty(&self) -> bool {
|
||||||
|
self.len() == 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Current time
|
/// Current time
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
|
@ -35,7 +35,7 @@ const fn type_eq<T: ?Sized, U: ?Sized>() -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the length of the element
|
/// Gets the length of the element
|
||||||
pub trait HasLen {
|
pub trait HasConstLen {
|
||||||
/// The length as constant `usize`
|
/// The length as constant `usize`
|
||||||
const LEN: usize;
|
const LEN: usize;
|
||||||
|
|
||||||
@ -47,7 +47,7 @@ pub trait HasLen {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HasLen for () {
|
impl HasConstLen for () {
|
||||||
const LEN: usize = 0;
|
const LEN: usize = 0;
|
||||||
|
|
||||||
fn len(&self) -> usize {
|
fn len(&self) -> usize {
|
||||||
@ -55,9 +55,9 @@ impl HasLen for () {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Head, Tail> HasLen for (Head, Tail)
|
impl<Head, Tail> HasConstLen for (Head, Tail)
|
||||||
where
|
where
|
||||||
Tail: HasLen,
|
Tail: HasConstLen,
|
||||||
{
|
{
|
||||||
const LEN: usize = 1 + Tail::LEN;
|
const LEN: usize = 1 + Tail::LEN;
|
||||||
|
|
||||||
@ -78,7 +78,7 @@ pub trait HasNameId {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the id and `const_name` for the given index in a tuple
|
/// Gets the id and `const_name` for the given index in a tuple
|
||||||
pub trait HasNameIdTuple: HasLen {
|
pub trait HasNameIdTuple: HasConstLen {
|
||||||
/// Gets the `const_name` for the entry at the given index
|
/// Gets the `const_name` for the entry at the given index
|
||||||
fn const_name_for(&self, index: usize) -> Option<&'static str>;
|
fn const_name_for(&self, index: usize) -> Option<&'static str>;
|
||||||
|
|
||||||
@ -199,7 +199,7 @@ pub trait Named {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A named tuple
|
/// A named tuple
|
||||||
pub trait NamedTuple: HasLen {
|
pub trait NamedTuple: HasConstLen {
|
||||||
/// Gets the name of this tuple
|
/// Gets the name of this tuple
|
||||||
fn name(&self, index: usize) -> Option<&str>;
|
fn name(&self, index: usize) -> Option<&str>;
|
||||||
}
|
}
|
||||||
|
@ -2,10 +2,10 @@
|
|||||||
// with testcases only from a subset of the total corpus.
|
// with testcases only from a subset of the total corpus.
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
bolts::{rands::Rand, serdeany::SerdeAny, AsSlice},
|
bolts::{rands::Rand, serdeany::SerdeAny, AsSlice, HasLen},
|
||||||
corpus::{Corpus, CorpusScheduler, Testcase},
|
corpus::{Corpus, CorpusScheduler, Testcase},
|
||||||
feedbacks::MapIndexesMetadata,
|
feedbacks::MapIndexesMetadata,
|
||||||
inputs::{HasLen, Input},
|
inputs::Input,
|
||||||
state::{HasCorpus, HasMetadata, HasRand},
|
state::{HasCorpus, HasMetadata, HasRand},
|
||||||
Error,
|
Error,
|
||||||
};
|
};
|
||||||
|
@ -6,8 +6,8 @@ use core::{convert::Into, default::Default, option::Option, time::Duration};
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
bolts::serdeany::SerdeAnyMap,
|
bolts::{serdeany::SerdeAnyMap, HasLen},
|
||||||
inputs::{HasLen, Input},
|
inputs::Input,
|
||||||
state::HasMetadata,
|
state::HasMetadata,
|
||||||
Error,
|
Error,
|
||||||
};
|
};
|
||||||
|
@ -171,7 +171,7 @@ where
|
|||||||
O: MapObserver<T>,
|
O: MapObserver<T>,
|
||||||
{
|
{
|
||||||
Self {
|
Self {
|
||||||
history_map: vec![T::default(); map_observer.map().len()],
|
history_map: vec![T::default(); map_observer.len()],
|
||||||
name: map_observer.name().to_string(),
|
name: map_observer.name().to_string(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -245,12 +245,12 @@ where
|
|||||||
if size > map_state.history_map.len() {
|
if size > map_state.history_map.len() {
|
||||||
panic!("The size of the associated map observer cannot exceed the size of the history map of the feedback. If you are running multiple instances of slightly different fuzzers (e.g. one with ASan and another without) synchronized using LLMP please check the `configuration` field of the LLMP manager.");
|
panic!("The size of the associated map observer cannot exceed the size of the history map of the feedback. If you are running multiple instances of slightly different fuzzers (e.g. one with ASan and another without) synchronized using LLMP please check the `configuration` field of the LLMP manager.");
|
||||||
}
|
}
|
||||||
assert!(size <= observer.map().len());
|
assert!(size <= observer.len());
|
||||||
|
|
||||||
if self.novelties.is_some() {
|
if self.novelties.is_some() {
|
||||||
for i in 0..size {
|
for i in 0..size {
|
||||||
let history = map_state.history_map[i];
|
let history = map_state.history_map[i];
|
||||||
let item = observer.map()[i];
|
let item = *observer.get(i);
|
||||||
|
|
||||||
let reduced = R::reduce(history, item);
|
let reduced = R::reduce(history, item);
|
||||||
if history != reduced {
|
if history != reduced {
|
||||||
@ -262,7 +262,7 @@ where
|
|||||||
} else {
|
} else {
|
||||||
for i in 0..size {
|
for i in 0..size {
|
||||||
let history = map_state.history_map[i];
|
let history = map_state.history_map[i];
|
||||||
let item = observer.map()[i];
|
let item = *observer.get(i);
|
||||||
|
|
||||||
let reduced = R::reduce(history, item);
|
let reduced = R::reduce(history, item);
|
||||||
if history != reduced {
|
if history != reduced {
|
||||||
@ -457,7 +457,7 @@ where
|
|||||||
let mut hit_target: bool = false;
|
let mut hit_target: bool = false;
|
||||||
//check if we've hit any targets.
|
//check if we've hit any targets.
|
||||||
for i in 0..size {
|
for i in 0..size {
|
||||||
if observer.map()[i] > 0 {
|
if *observer.get(i) > 0 {
|
||||||
self.target_idx.push(i);
|
self.target_idx.push(i);
|
||||||
hit_target = true;
|
hit_target = true;
|
||||||
}
|
}
|
||||||
|
@ -12,8 +12,8 @@ use std::{fs::File, io::Read, path::Path};
|
|||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
use crate::{bolts::fs::write_file_atomic, Error};
|
use crate::{bolts::fs::write_file_atomic, Error};
|
||||||
use crate::{
|
use crate::{
|
||||||
bolts::ownedref::OwnedSlice,
|
bolts::{ownedref::OwnedSlice, HasLen},
|
||||||
inputs::{HasBytesVec, HasLen, HasTargetBytes, Input},
|
inputs::{HasBytesVec, HasTargetBytes, Input},
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A bytes input is the basic input
|
/// A bytes input is the basic input
|
||||||
|
@ -13,10 +13,7 @@ use hashbrown::HashMap;
|
|||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{bolts::HasLen, inputs::Input, Error};
|
||||||
inputs::{HasLen, Input},
|
|
||||||
Error,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub trait InputEncoder<T>
|
pub trait InputEncoder<T>
|
||||||
where
|
where
|
||||||
|
@ -5,10 +5,7 @@ use alloc::{rc::Rc, string::String, vec::Vec};
|
|||||||
use core::{cell::RefCell, convert::From};
|
use core::{cell::RefCell, convert::From};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{bolts::HasLen, inputs::Input, Error};
|
||||||
inputs::{HasLen, Input},
|
|
||||||
Error,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug, Default, PartialEq, Eq)]
|
#[derive(Serialize, Deserialize, Clone, Debug, Default, PartialEq, Eq)]
|
||||||
pub struct Terminal {
|
pub struct Terminal {
|
||||||
|
@ -90,14 +90,3 @@ pub trait HasBytesVec {
|
|||||||
/// The internal bytes map (as mutable borrow)
|
/// The internal bytes map (as mutable borrow)
|
||||||
fn bytes_mut(&mut self) -> &mut Vec<u8>;
|
fn bytes_mut(&mut self) -> &mut Vec<u8>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Has a length field
|
|
||||||
pub trait HasLen {
|
|
||||||
/// The length
|
|
||||||
fn len(&self) -> usize;
|
|
||||||
|
|
||||||
/// Returns `true` if it has no elements.
|
|
||||||
fn is_empty(&self) -> bool {
|
|
||||||
self.len() == 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -14,7 +14,7 @@ pub mod gramatron;
|
|||||||
pub use gramatron::*;
|
pub use gramatron::*;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
bolts::tuples::{HasLen, Named},
|
bolts::tuples::{HasConstLen, Named},
|
||||||
inputs::Input,
|
inputs::Input,
|
||||||
Error,
|
Error,
|
||||||
};
|
};
|
||||||
@ -59,7 +59,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A `Tuple` of `Mutators` that can execute multiple `Mutators` in a row.
|
/// A `Tuple` of `Mutators` that can execute multiple `Mutators` in a row.
|
||||||
pub trait MutatorsTuple<I, S>: HasLen
|
pub trait MutatorsTuple<I, S>: HasConstLen
|
||||||
where
|
where
|
||||||
I: Input,
|
I: Input,
|
||||||
{
|
{
|
||||||
|
@ -1579,7 +1579,7 @@ mod tests {
|
|||||||
use crate::{
|
use crate::{
|
||||||
bolts::{
|
bolts::{
|
||||||
rands::StdRand,
|
rands::StdRand,
|
||||||
tuples::{tuple_list, HasLen},
|
tuples::{tuple_list, HasConstLen},
|
||||||
},
|
},
|
||||||
corpus::{Corpus, InMemoryCorpus},
|
corpus::{Corpus, InMemoryCorpus},
|
||||||
inputs::BytesInput,
|
inputs::BytesInput,
|
||||||
|
@ -9,6 +9,7 @@ use core::{
|
|||||||
hash::Hasher,
|
hash::Hasher,
|
||||||
slice::{from_raw_parts, from_raw_parts_mut},
|
slice::{from_raw_parts, from_raw_parts_mut},
|
||||||
};
|
};
|
||||||
|
use intervaltree::IntervalTree;
|
||||||
use num::Integer;
|
use num::Integer;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
@ -16,25 +17,38 @@ use crate::{
|
|||||||
bolts::{
|
bolts::{
|
||||||
ownedref::{OwnedRefMut, OwnedSliceMut},
|
ownedref::{OwnedRefMut, OwnedSliceMut},
|
||||||
tuples::Named,
|
tuples::Named,
|
||||||
|
HasLen,
|
||||||
},
|
},
|
||||||
observers::Observer,
|
observers::Observer,
|
||||||
Error,
|
Error,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A [`MapObserver`] observes the static map, as oftentimes used for afl-like coverage information
|
/// A [`MapObserver`] observes the static map, as oftentimes used for afl-like coverage information
|
||||||
pub trait MapObserver<T>: Named + serde::Serialize + serde::de::DeserializeOwned
|
pub trait MapObserver<T>: HasLen + Named + serde::Serialize + serde::de::DeserializeOwned
|
||||||
where
|
where
|
||||||
T: Integer + Default + Copy,
|
T: Integer + Default + Copy,
|
||||||
{
|
{
|
||||||
/// Get the map
|
/// Get the map if the observer can be represented with a slice
|
||||||
fn map(&self) -> &[T];
|
fn map(&self) -> Option<&[T]>;
|
||||||
|
|
||||||
/// Get the map (mutable)
|
/// Get the map (mutable) if the observer can be represented with a slice
|
||||||
fn map_mut(&mut self) -> &mut [T];
|
fn map_mut(&mut self) -> Option<&mut [T]>;
|
||||||
|
|
||||||
|
fn get(&self, idx: usize) -> &T {
|
||||||
|
&self
|
||||||
|
.map()
|
||||||
|
.expect("Cannot get a map that cannot be represented as slice")[idx]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_mut(&mut self, idx: usize) -> &mut T {
|
||||||
|
&mut self
|
||||||
|
.map_mut()
|
||||||
|
.expect("Cannot get a map that cannot be represented as slice")[idx]
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the number of usable entries in the map (all by default)
|
/// Get the number of usable entries in the map (all by default)
|
||||||
fn usable_count(&self) -> usize {
|
fn usable_count(&self) -> usize {
|
||||||
self.map().len()
|
self.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Count the set bytes in the map
|
/// Count the set bytes in the map
|
||||||
@ -42,8 +56,8 @@ where
|
|||||||
let initial = self.initial();
|
let initial = self.initial();
|
||||||
let cnt = self.usable_count();
|
let cnt = self.usable_count();
|
||||||
let mut res = 0;
|
let mut res = 0;
|
||||||
for x in self.map()[0..cnt].iter() {
|
for i in 0..cnt {
|
||||||
if *x != initial {
|
if *self.get(i) != initial {
|
||||||
res += 1;
|
res += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -53,12 +67,14 @@ where
|
|||||||
/// Compute the hash of the map
|
/// Compute the hash of the map
|
||||||
fn hash(&self) -> u64 {
|
fn hash(&self) -> u64 {
|
||||||
let mut hasher = AHasher::new_with_keys(0, 0);
|
let mut hasher = AHasher::new_with_keys(0, 0);
|
||||||
let ptr = self.map().as_ptr() as *const u8;
|
let slice = self
|
||||||
let map_size = self.map().len() / core::mem::size_of::<T>();
|
.map()
|
||||||
|
.expect("Cannot hash a map that cannot be represented as slice");
|
||||||
|
let ptr = slice.as_ptr() as *const u8;
|
||||||
|
let map_size = slice.len() / core::mem::size_of::<T>();
|
||||||
unsafe {
|
unsafe {
|
||||||
hasher.write(from_raw_parts(ptr, map_size));
|
hasher.write(from_raw_parts(ptr, map_size));
|
||||||
}
|
}
|
||||||
|
|
||||||
hasher.finish()
|
hasher.finish()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,8 +93,8 @@ where
|
|||||||
// Normal memset, see https://rust.godbolt.org/z/Trs5hv
|
// Normal memset, see https://rust.godbolt.org/z/Trs5hv
|
||||||
let initial = self.initial();
|
let initial = self.initial();
|
||||||
let cnt = self.usable_count();
|
let cnt = self.usable_count();
|
||||||
for x in self.map_mut()[0..cnt].iter_mut() {
|
for i in 0..cnt {
|
||||||
*x = initial;
|
*self.get_mut(i) = initial;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -120,18 +136,28 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a, T> HasLen for StdMapObserver<'a, T>
|
||||||
|
where
|
||||||
|
T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
fn len(&self) -> usize {
|
||||||
|
self.map.as_slice().len()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a, T> MapObserver<T> for StdMapObserver<'a, T>
|
impl<'a, T> MapObserver<T> for StdMapObserver<'a, T>
|
||||||
where
|
where
|
||||||
T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn map(&self) -> &[T] {
|
fn map(&self) -> Option<&[T]> {
|
||||||
self.map.as_slice()
|
Some(self.map.as_slice())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn map_mut(&mut self) -> &mut [T] {
|
fn map_mut(&mut self) -> Option<&mut [T]> {
|
||||||
self.map.as_mut_slice()
|
Some(self.map.as_mut_slice())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -225,6 +251,16 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a, T, const N: usize> HasLen for ConstMapObserver<'a, T, N>
|
||||||
|
where
|
||||||
|
T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
fn len(&self) -> usize {
|
||||||
|
N
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a, T, const N: usize> MapObserver<T> for ConstMapObserver<'a, T, N>
|
impl<'a, T, const N: usize> MapObserver<T> for ConstMapObserver<'a, T, N>
|
||||||
where
|
where
|
||||||
T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
||||||
@ -235,13 +271,13 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn map(&self) -> &[T] {
|
fn map(&self) -> Option<&[T]> {
|
||||||
self.map.as_slice()
|
Some(self.map.as_slice())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn map_mut(&mut self) -> &mut [T] {
|
fn map_mut(&mut self) -> Option<&mut [T]> {
|
||||||
self.map.as_mut_slice()
|
Some(self.map.as_mut_slice())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -337,18 +373,28 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a, T> HasLen for VariableMapObserver<'a, T>
|
||||||
|
where
|
||||||
|
T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
fn len(&self) -> usize {
|
||||||
|
self.map.as_slice().len()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a, T> MapObserver<T> for VariableMapObserver<'a, T>
|
impl<'a, T> MapObserver<T> for VariableMapObserver<'a, T>
|
||||||
where
|
where
|
||||||
T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn map(&self) -> &[T] {
|
fn map(&self) -> Option<&[T]> {
|
||||||
self.map.as_slice()
|
Some(self.map.as_slice())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn map_mut(&mut self) -> &mut [T] {
|
fn map_mut(&mut self) -> Option<&mut [T]> {
|
||||||
self.map.as_mut_slice()
|
Some(self.map.as_mut_slice())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -444,8 +490,8 @@ where
|
|||||||
#[inline]
|
#[inline]
|
||||||
fn post_exec(&mut self, state: &mut S, input: &I) -> Result<(), Error> {
|
fn post_exec(&mut self, state: &mut S, input: &I) -> Result<(), Error> {
|
||||||
let cnt = self.usable_count();
|
let cnt = self.usable_count();
|
||||||
for x in self.map_mut()[0..cnt].iter_mut() {
|
for i in 0..cnt {
|
||||||
*x = COUNT_CLASS_LOOKUP[*x as usize];
|
*self.get_mut(i) = COUNT_CLASS_LOOKUP[*self.get(i) as usize];
|
||||||
}
|
}
|
||||||
self.base.post_exec(state, input)
|
self.base.post_exec(state, input)
|
||||||
}
|
}
|
||||||
@ -461,17 +507,27 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<M> HasLen for HitcountsMapObserver<M>
|
||||||
|
where
|
||||||
|
M: MapObserver<u8>,
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
fn len(&self) -> usize {
|
||||||
|
self.base.len()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<M> MapObserver<u8> for HitcountsMapObserver<M>
|
impl<M> MapObserver<u8> for HitcountsMapObserver<M>
|
||||||
where
|
where
|
||||||
M: MapObserver<u8>,
|
M: MapObserver<u8>,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn map(&self) -> &[u8] {
|
fn map(&self) -> Option<&[u8]> {
|
||||||
self.base.map()
|
self.base.map()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn map_mut(&mut self) -> &mut [u8] {
|
fn map_mut(&mut self) -> Option<&mut [u8]> {
|
||||||
self.base.map_mut()
|
self.base.map_mut()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -505,3 +561,196 @@ where
|
|||||||
Self { base }
|
Self { base }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The Multi Map Observer merge different maps into one observer
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
#[serde(bound = "T: serde::de::DeserializeOwned")]
|
||||||
|
#[allow(clippy::unsafe_derive_deserialize)]
|
||||||
|
pub struct MultiMapObserver<'a, T>
|
||||||
|
where
|
||||||
|
T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
||||||
|
{
|
||||||
|
maps: Vec<OwnedSliceMut<'a, T>>,
|
||||||
|
intervals: IntervalTree<usize, usize>,
|
||||||
|
len: usize,
|
||||||
|
initial: T,
|
||||||
|
name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, I, S, T> Observer<I, S> for MultiMapObserver<'a, T>
|
||||||
|
where
|
||||||
|
T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
||||||
|
Self: MapObserver<T>,
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
fn pre_exec(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> {
|
||||||
|
self.reset_map()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T> Named for MultiMapObserver<'a, T>
|
||||||
|
where
|
||||||
|
T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
self.name.as_str()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T> HasLen for MultiMapObserver<'a, T>
|
||||||
|
where
|
||||||
|
T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
fn len(&self) -> usize {
|
||||||
|
self.len
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T> MapObserver<T> for MultiMapObserver<'a, T>
|
||||||
|
where
|
||||||
|
T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
fn map(&self) -> Option<&[T]> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn map_mut(&mut self) -> Option<&mut [T]> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn get(&self, idx: usize) -> &T {
|
||||||
|
let elem = self.intervals.query_point(idx).next().unwrap();
|
||||||
|
let i = elem.value;
|
||||||
|
let j = idx - elem.range.start;
|
||||||
|
&self.maps[i].as_slice()[j]
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn get_mut(&mut self, idx: usize) -> &mut T {
|
||||||
|
let elem = self.intervals.query_point(idx).next().unwrap();
|
||||||
|
let i = elem.value;
|
||||||
|
let j = idx - elem.range.start;
|
||||||
|
&mut self.maps[i].as_mut_slice()[j]
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn initial(&self) -> T {
|
||||||
|
self.initial
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn initial_mut(&mut self) -> &mut T {
|
||||||
|
&mut self.initial
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn set_initial(&mut self, initial: T) {
|
||||||
|
self.initial = initial;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn count_bytes(&self) -> u64 {
|
||||||
|
let initial = self.initial();
|
||||||
|
let mut res = 0;
|
||||||
|
for map in &self.maps {
|
||||||
|
for x in map.as_slice() {
|
||||||
|
if *x != initial {
|
||||||
|
res += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
fn hash(&self) -> u64 {
|
||||||
|
let mut hasher = AHasher::new_with_keys(0, 0);
|
||||||
|
for map in &self.maps {
|
||||||
|
let slice = map.as_slice();
|
||||||
|
let ptr = slice.as_ptr() as *const u8;
|
||||||
|
let map_size = slice.len() / core::mem::size_of::<T>();
|
||||||
|
unsafe {
|
||||||
|
hasher.write(from_raw_parts(ptr, map_size));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
hasher.finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reset_map(&mut self) -> Result<(), Error> {
|
||||||
|
let initial = self.initial();
|
||||||
|
for map in &mut self.maps {
|
||||||
|
for x in map.as_mut_slice() {
|
||||||
|
*x = initial;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T> MultiMapObserver<'a, T>
|
||||||
|
where
|
||||||
|
T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
|
||||||
|
{
|
||||||
|
/// Creates a new [`MultiMapObserver`]
|
||||||
|
#[must_use]
|
||||||
|
pub fn new(name: &'static str, maps: &'a mut [&'a mut [T]]) -> Self {
|
||||||
|
let mut idx = 0;
|
||||||
|
let mut v = 0;
|
||||||
|
let mut initial = T::default();
|
||||||
|
let mut builder = vec![];
|
||||||
|
let maps: Vec<_> = maps
|
||||||
|
.iter_mut()
|
||||||
|
.map(|x| {
|
||||||
|
if !x.is_empty() {
|
||||||
|
initial = x[0];
|
||||||
|
}
|
||||||
|
let l = x.len();
|
||||||
|
let r = (idx..(idx + l), v);
|
||||||
|
idx += l;
|
||||||
|
builder.push(r);
|
||||||
|
v += 1;
|
||||||
|
OwnedSliceMut::Ref(x)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
Self {
|
||||||
|
maps,
|
||||||
|
intervals: builder.into_iter().collect::<IntervalTree<usize, usize>>(),
|
||||||
|
len: idx,
|
||||||
|
name: name.to_string(),
|
||||||
|
initial,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new [`MultiMapObserver`] with an owned map
|
||||||
|
#[must_use]
|
||||||
|
pub fn new_owned(name: &'static str, maps: Vec<Vec<T>>) -> Self {
|
||||||
|
let mut idx = 0;
|
||||||
|
let mut v = 0;
|
||||||
|
let mut initial = T::default();
|
||||||
|
let mut builder = vec![];
|
||||||
|
let maps: Vec<_> = maps
|
||||||
|
.into_iter()
|
||||||
|
.map(|x| {
|
||||||
|
if !x.is_empty() {
|
||||||
|
initial = x[0];
|
||||||
|
}
|
||||||
|
let l = x.len();
|
||||||
|
let r = (idx..(idx + l), v);
|
||||||
|
idx += l;
|
||||||
|
builder.push(r);
|
||||||
|
v += 1;
|
||||||
|
OwnedSliceMut::Owned(x)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
Self {
|
||||||
|
maps,
|
||||||
|
intervals: builder.into_iter().collect::<IntervalTree<usize, usize>>(),
|
||||||
|
len: idx,
|
||||||
|
name: name.to_string(),
|
||||||
|
initial,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -18,6 +18,7 @@ sancov_pcguard_hitcounts = []
|
|||||||
sancov_pcguard_edges_ptr = []
|
sancov_pcguard_edges_ptr = []
|
||||||
sancov_pcguard_hitcounts_ptr = []
|
sancov_pcguard_hitcounts_ptr = []
|
||||||
sancov_value_profile = []
|
sancov_value_profile = []
|
||||||
|
sancov_8bit = []
|
||||||
sancov_cmplog = []
|
sancov_cmplog = []
|
||||||
sancov_pcguard = ["sancov_pcguard_hitcounts"]
|
sancov_pcguard = ["sancov_pcguard_hitcounts"]
|
||||||
clippy = [] # Ignore compiler warnings during clippy
|
clippy = [] # Ignore compiler warnings during clippy
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
//! `libafl_targets` contains runtime code, injected in the target itself during compilation.
|
//! `libafl_targets` contains runtime code, injected in the target itself during compilation.
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate alloc;
|
||||||
|
|
||||||
include!(concat!(env!("OUT_DIR"), "/constants.rs"));
|
include!(concat!(env!("OUT_DIR"), "/constants.rs"));
|
||||||
|
|
||||||
#[cfg(any(
|
#[cfg(any(
|
||||||
@ -27,6 +30,11 @@ pub mod libfuzzer;
|
|||||||
#[cfg(feature = "libfuzzer")]
|
#[cfg(feature = "libfuzzer")]
|
||||||
pub use libfuzzer::*;
|
pub use libfuzzer::*;
|
||||||
|
|
||||||
|
#[cfg(feature = "sancov_8bit")]
|
||||||
|
pub mod sancov_8bit;
|
||||||
|
#[cfg(feature = "sancov_8bit")]
|
||||||
|
pub use sancov_8bit::*;
|
||||||
|
|
||||||
pub mod coverage;
|
pub mod coverage;
|
||||||
pub use coverage::*;
|
pub use coverage::*;
|
||||||
|
|
||||||
|
14
libafl_targets/src/sancov_8bit.rs
Normal file
14
libafl_targets/src/sancov_8bit.rs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
//! [`LLVM` `8-bi-counters`](https://clang.llvm.org/docs/SanitizerCoverage.html#tracing-pcs-with-guards) runtime for `LibAFL`.
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
use core::slice::from_raw_parts_mut;
|
||||||
|
|
||||||
|
pub static mut COUNTERS_MAPS: Vec<&'static mut [u8]> = Vec::new();
|
||||||
|
|
||||||
|
/// Initialize the sancov `8-bit-counters` - usually called by `llvm`.
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
/// Set up our coverage maps.
|
||||||
|
#[no_mangle]
|
||||||
|
pub fn __sanitizer_cov_8bit_counters_init(start: *mut u8, stop: *mut u8) {
|
||||||
|
unsafe { COUNTERS_MAPS.push(from_raw_parts_mut(start, stop.offset_from(start) as usize)) }
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user