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:
Andrea Fioraldi 2021-11-04 10:08:50 +01:00 committed by GitHub
parent e46bb8643a
commit eca605bf01
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 337 additions and 70 deletions

View File

@ -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::*;

View File

@ -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

View File

@ -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]

View File

@ -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>;
} }

View File

@ -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,
}; };

View File

@ -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,
}; };

View File

@ -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;
} }

View File

@ -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

View File

@ -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

View File

@ -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 {

View File

@ -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
}
}

View File

@ -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,
{ {

View File

@ -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,

View File

@ -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,
}
}
}

View File

@ -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

View File

@ -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::*;

View 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)) }
}