Add bolts::math, make functions const, cleanup (#1444)
* Make some functions const * fix isprint * more const * move integer_sqrt to bolts, use binary search, use u128 to handle extreme values * Technically correct * clippy * u64 algo * More test * cumulative_distribution to in_place * move calculate_cumulative_distribution_in_place to bolts * clippy * Move math stuff to bolts::math * actually add math * math? * For some reason this fixes things, dunno * fix builds? * does that help? * clippy ignores * more clean clippy * more cfg_attr
This commit is contained in:
parent
d338b30c08
commit
454142c29e
@ -326,6 +326,10 @@ where
|
|||||||
|
|
||||||
/// The Metadata for each testcase used in power schedules.
|
/// The Metadata for each testcase used in power schedules.
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
|
#[cfg_attr(
|
||||||
|
any(not(feature = "serdeany_autoreg"), miri),
|
||||||
|
allow(clippy::unsafe_derive_deserialize)
|
||||||
|
)] // for SerdeAny
|
||||||
pub struct SchedulerTestcaseMetadata {
|
pub struct SchedulerTestcaseMetadata {
|
||||||
/// Number of bits set in bitmap, updated in calibrate_case
|
/// Number of bits set in bitmap, updated in calibrate_case
|
||||||
bitmap_size: u64,
|
bitmap_size: u64,
|
||||||
|
@ -47,6 +47,10 @@ use crate::{
|
|||||||
|
|
||||||
/// How an execution finished.
|
/// How an execution finished.
|
||||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
|
||||||
|
#[cfg_attr(
|
||||||
|
any(not(feature = "serdeany_autoreg"), miri),
|
||||||
|
allow(clippy::unsafe_derive_deserialize)
|
||||||
|
)] // for SerdeAny
|
||||||
pub enum ExitKind {
|
pub enum ExitKind {
|
||||||
/// The run exited normally.
|
/// The run exited normally.
|
||||||
Ok,
|
Ok,
|
||||||
@ -69,6 +73,10 @@ pub enum ExitKind {
|
|||||||
|
|
||||||
/// How one of the diffing executions finished.
|
/// How one of the diffing executions finished.
|
||||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
|
||||||
|
#[cfg_attr(
|
||||||
|
any(not(feature = "serdeany_autoreg"), miri),
|
||||||
|
allow(clippy::unsafe_derive_deserialize)
|
||||||
|
)] // for SerdeAny
|
||||||
pub enum DiffExitKind {
|
pub enum DiffExitKind {
|
||||||
/// The run exited normally.
|
/// The run exited normally.
|
||||||
Ok,
|
Ok,
|
||||||
|
@ -222,6 +222,10 @@ where
|
|||||||
|
|
||||||
/// A testcase metadata holding a list of indexes of a map
|
/// A testcase metadata holding a list of indexes of a map
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
#[cfg_attr(
|
||||||
|
any(not(feature = "serdeany_autoreg"), miri),
|
||||||
|
allow(clippy::unsafe_derive_deserialize)
|
||||||
|
)] // for SerdeAny
|
||||||
pub struct MapIndexesMetadata {
|
pub struct MapIndexesMetadata {
|
||||||
/// The list of indexes.
|
/// The list of indexes.
|
||||||
pub list: Vec<usize>,
|
pub list: Vec<usize>,
|
||||||
@ -266,6 +270,10 @@ impl MapIndexesMetadata {
|
|||||||
|
|
||||||
/// A testcase metadata holding a list of indexes of a map
|
/// A testcase metadata holding a list of indexes of a map
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
#[cfg_attr(
|
||||||
|
any(not(feature = "serdeany_autoreg"), miri),
|
||||||
|
allow(clippy::unsafe_derive_deserialize)
|
||||||
|
)] // for SerdeAny
|
||||||
pub struct MapNoveltiesMetadata {
|
pub struct MapNoveltiesMetadata {
|
||||||
/// A `list` of novelties.
|
/// A `list` of novelties.
|
||||||
pub list: Vec<usize>,
|
pub list: Vec<usize>,
|
||||||
@ -300,6 +308,10 @@ impl MapNoveltiesMetadata {
|
|||||||
/// The state of [`MapFeedback`]
|
/// The state of [`MapFeedback`]
|
||||||
#[derive(Default, Serialize, Deserialize, Clone, Debug)]
|
#[derive(Default, Serialize, Deserialize, Clone, Debug)]
|
||||||
#[serde(bound = "T: DeserializeOwned")]
|
#[serde(bound = "T: DeserializeOwned")]
|
||||||
|
#[cfg_attr(
|
||||||
|
any(not(feature = "serdeany_autoreg"), miri),
|
||||||
|
allow(clippy::unsafe_derive_deserialize)
|
||||||
|
)] // for SerdeAny
|
||||||
pub struct MapFeedbackMetadata<T>
|
pub struct MapFeedbackMetadata<T>
|
||||||
where
|
where
|
||||||
T: Default + Copy + 'static + Serialize,
|
T: Default + Copy + 'static + Serialize,
|
||||||
|
@ -109,7 +109,7 @@ impl From<BytesInput> for Vec<u8> {
|
|||||||
impl BytesInput {
|
impl BytesInput {
|
||||||
/// Creates a new bytes input using the given bytes
|
/// Creates a new bytes input using the given bytes
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new(bytes: Vec<u8>) -> Self {
|
pub const fn new(bytes: Vec<u8>) -> Self {
|
||||||
Self { bytes }
|
Self { bytes }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,10 @@ pub enum GeneralizedItem {
|
|||||||
|
|
||||||
/// Metadata regarding the generalised content of an input
|
/// Metadata regarding the generalised content of an input
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
|
#[cfg_attr(
|
||||||
|
any(not(feature = "serdeany_autoreg"), miri),
|
||||||
|
allow(clippy::unsafe_derive_deserialize)
|
||||||
|
)] // for SerdeAny
|
||||||
pub struct GeneralizedInputMetadata {
|
pub struct GeneralizedInputMetadata {
|
||||||
generalized: Vec<GeneralizedItem>,
|
generalized: Vec<GeneralizedItem>,
|
||||||
}
|
}
|
||||||
|
@ -72,6 +72,10 @@ where
|
|||||||
|
|
||||||
/// The metadata used for `gramatron`
|
/// The metadata used for `gramatron`
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
#[cfg_attr(
|
||||||
|
any(not(feature = "serdeany_autoreg"), miri),
|
||||||
|
allow(clippy::unsafe_derive_deserialize)
|
||||||
|
)] // for SerdeAny
|
||||||
pub struct GramatronIdxMapMetadata {
|
pub struct GramatronIdxMapMetadata {
|
||||||
/// The map containing a vec for each terminal
|
/// The map containing a vec for each terminal
|
||||||
pub map: HashMap<usize, Vec<usize>>,
|
pub map: HashMap<usize, Vec<usize>>,
|
||||||
|
@ -28,6 +28,10 @@ use crate::{
|
|||||||
/// On the other hand, in the core fuzzing mode, the fuzzer chooses the best `swarms`, which was determined during the pilot fuzzing mode, to compute the probability to choose the operation operator.
|
/// On the other hand, in the core fuzzing mode, the fuzzer chooses the best `swarms`, which was determined during the pilot fuzzing mode, to compute the probability to choose the operation operator.
|
||||||
/// With the current implementation we are always in the pacemaker fuzzing mode.
|
/// With the current implementation we are always in the pacemaker fuzzing mode.
|
||||||
#[derive(Serialize, Deserialize, Clone)]
|
#[derive(Serialize, Deserialize, Clone)]
|
||||||
|
#[cfg_attr(
|
||||||
|
any(not(feature = "serdeany_autoreg"), miri),
|
||||||
|
allow(clippy::unsafe_derive_deserialize)
|
||||||
|
)] // for SerdeAny
|
||||||
pub struct MOpt {
|
pub struct MOpt {
|
||||||
/// Random number generator
|
/// Random number generator
|
||||||
pub rand: StdRand,
|
pub rand: StdRand,
|
||||||
|
@ -24,6 +24,10 @@ use crate::{
|
|||||||
|
|
||||||
/// The metadata placed in a [`crate::corpus::Testcase`] by a [`LoggerScheduledMutator`].
|
/// The metadata placed in a [`crate::corpus::Testcase`] by a [`LoggerScheduledMutator`].
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
#[cfg_attr(
|
||||||
|
any(not(feature = "serdeany_autoreg"), miri),
|
||||||
|
allow(clippy::unsafe_derive_deserialize)
|
||||||
|
)] // for SerdeAny
|
||||||
pub struct LogMutationMetadata {
|
pub struct LogMutationMetadata {
|
||||||
/// A list of logs
|
/// A list of logs
|
||||||
pub list: Vec<String>,
|
pub list: Vec<String>,
|
||||||
|
@ -34,8 +34,8 @@ use crate::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
/// A state metadata holding a list of tokens
|
/// A state metadata holding a list of tokens
|
||||||
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
|
|
||||||
#[allow(clippy::unsafe_derive_deserialize)]
|
#[allow(clippy::unsafe_derive_deserialize)]
|
||||||
|
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
|
||||||
pub struct Tokens {
|
pub struct Tokens {
|
||||||
// We keep a vec and a set, set for faster deduplication, vec for access
|
// We keep a vec and a set, set for faster deduplication, vec for access
|
||||||
tokens_vec: Vec<Vec<u8>>,
|
tokens_vec: Vec<Vec<u8>>,
|
||||||
@ -1759,18 +1759,22 @@ impl TextType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns `true` if the given `u8` char is
|
||||||
|
/// in the valid ascii range (`<= 0x7F`)
|
||||||
#[inline]
|
#[inline]
|
||||||
fn isascii(c: u8) -> bool {
|
const fn isascii(c: u8) -> bool {
|
||||||
c <= 0x7F
|
c <= 0x7F
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns `true` if the given `u8` char is
|
||||||
|
/// a valid printable character (between `0x20` and `0x7E`)
|
||||||
#[inline]
|
#[inline]
|
||||||
fn isprint(c: u8) -> bool {
|
const fn isprint(c: u8) -> bool {
|
||||||
(0x20..=0x7e).contains(&c)
|
c >= 0x20 && c <= 0x7E
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn strlen(buf: &[u8]) -> usize {
|
const fn strlen(buf: &[u8]) -> usize {
|
||||||
let mut count = 0;
|
let mut count = 0;
|
||||||
while count < buf.len() {
|
while count < buf.len() {
|
||||||
if buf[count] == 0x0 {
|
if buf[count] == 0x0 {
|
||||||
|
@ -8,7 +8,9 @@ use core::{
|
|||||||
marker::PhantomData,
|
marker::PhantomData,
|
||||||
};
|
};
|
||||||
|
|
||||||
use libafl_bolts::{calculate_cumulative_sum_in_place, impl_serdeany, rands::Rand, Named};
|
use libafl_bolts::{
|
||||||
|
impl_serdeany, math::calculate_cumulative_distribution_in_place, rands::Rand, Named,
|
||||||
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
pub use crate::mutators::{mutations::*, token_mutations::*};
|
pub use crate::mutators::{mutations::*, token_mutations::*};
|
||||||
@ -22,6 +24,10 @@ use crate::{
|
|||||||
|
|
||||||
/// Metadata in the state, that controls the behavior of the [`TuneableScheduledMutator`] at runtime
|
/// Metadata in the state, that controls the behavior of the [`TuneableScheduledMutator`] at runtime
|
||||||
#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
|
#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
|
||||||
|
#[cfg_attr(
|
||||||
|
any(not(feature = "serdeany_autoreg"), miri),
|
||||||
|
allow(clippy::unsafe_derive_deserialize)
|
||||||
|
)] // for SerdeAny
|
||||||
pub struct TuneableScheduledMutatorMetadata {
|
pub struct TuneableScheduledMutatorMetadata {
|
||||||
/// The offsets of mutators to run, in order. Clear to fall back to random,
|
/// The offsets of mutators to run, in order. Clear to fall back to random,
|
||||||
/// or use `mutation_probabilities`
|
/// or use `mutation_probabilities`
|
||||||
@ -40,6 +46,8 @@ pub struct TuneableScheduledMutatorMetadata {
|
|||||||
pub iter_probabilities_pow_cumulative: Vec<f32>,
|
pub iter_probabilities_pow_cumulative: Vec<f32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl_serdeany!(TuneableScheduledMutatorMetadata);
|
||||||
|
|
||||||
impl Default for TuneableScheduledMutatorMetadata {
|
impl Default for TuneableScheduledMutatorMetadata {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
@ -70,8 +78,6 @@ impl TuneableScheduledMutatorMetadata {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_serdeany!(TuneableScheduledMutatorMetadata);
|
|
||||||
|
|
||||||
/// A [`Mutator`] that schedules one of the embedded mutations on each call.
|
/// A [`Mutator`] that schedules one of the embedded mutations on each call.
|
||||||
/// The index of the next mutation can be set.
|
/// The index of the next mutation can be set.
|
||||||
pub struct TuneableScheduledMutator<I, MT, S>
|
pub struct TuneableScheduledMutator<I, MT, S>
|
||||||
@ -247,36 +253,6 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the cumulative distribution function for a discrete distribution.
|
|
||||||
fn calculate_cumulative_distribution(probabilities: Vec<f32>) -> Result<Vec<f32>, Error> {
|
|
||||||
if probabilities.is_empty() {
|
|
||||||
return Err(Error::illegal_argument("empty list of probabilities"));
|
|
||||||
}
|
|
||||||
|
|
||||||
if !probabilities.iter().all(|&p| (0.0..=1.0).contains(&p)) {
|
|
||||||
return Err(Error::illegal_argument(format!(
|
|
||||||
"invalid probability distribution: {probabilities:?}"
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut cumulative = probabilities;
|
|
||||||
calculate_cumulative_sum_in_place(&mut cumulative);
|
|
||||||
|
|
||||||
// The cumulative sum should be roughly equal to 1.
|
|
||||||
let last = cumulative.last_mut().unwrap();
|
|
||||||
if num_traits::abs(*last - 1.0_f32) > 1.0e-4 {
|
|
||||||
return Err(Error::illegal_argument(format!(
|
|
||||||
"sum of probabilities ({}) is not 1",
|
|
||||||
*last
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clamp the end of the vector to account for floating point errors.
|
|
||||||
*last = 1.0_f32;
|
|
||||||
|
|
||||||
Ok(cumulative)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S> TuneableScheduledMutator<(), (), S>
|
impl<S> TuneableScheduledMutator<(), (), S>
|
||||||
where
|
where
|
||||||
S: HasRand + HasMetadata,
|
S: HasRand + HasMetadata,
|
||||||
@ -317,7 +293,7 @@ where
|
|||||||
/// Setting this function will unset everything previously set in `set_iters`.
|
/// Setting this function will unset everything previously set in `set_iters`.
|
||||||
pub fn set_iter_probabilities_pow(
|
pub fn set_iter_probabilities_pow(
|
||||||
state: &mut S,
|
state: &mut S,
|
||||||
iter_probabilities_pow: Vec<f32>,
|
mut iter_probabilities_pow: Vec<f32>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
if iter_probabilities_pow.len() >= 32 {
|
if iter_probabilities_pow.len() >= 32 {
|
||||||
return Err(Error::illegal_argument(
|
return Err(Error::illegal_argument(
|
||||||
@ -328,8 +304,8 @@ where
|
|||||||
metadata.iters = None;
|
metadata.iters = None;
|
||||||
|
|
||||||
// we precalculate the cumulative probability to be faster when sampling later.
|
// we precalculate the cumulative probability to be faster when sampling later.
|
||||||
metadata.iter_probabilities_pow_cumulative =
|
calculate_cumulative_distribution_in_place(&mut iter_probabilities_pow)?;
|
||||||
calculate_cumulative_distribution(iter_probabilities_pow)?;
|
metadata.iter_probabilities_pow_cumulative = iter_probabilities_pow;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -353,15 +329,15 @@ where
|
|||||||
/// Setting the probabilities will remove the value set through `set_mutation_ids`.
|
/// Setting the probabilities will remove the value set through `set_mutation_ids`.
|
||||||
pub fn set_mutation_probabilities(
|
pub fn set_mutation_probabilities(
|
||||||
state: &mut S,
|
state: &mut S,
|
||||||
mutation_probabilities: Vec<f32>,
|
mut mutation_probabilities: Vec<f32>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let metadata = TuneableScheduledMutatorMetadata::get_mut(state).unwrap();
|
let metadata = TuneableScheduledMutatorMetadata::get_mut(state).unwrap();
|
||||||
metadata.mutation_ids.clear();
|
metadata.mutation_ids.clear();
|
||||||
metadata.next_id = 0.into();
|
metadata.next_id = 0.into();
|
||||||
|
|
||||||
// we precalculate the cumulative probability to be faster when sampling later.
|
// we precalculate the cumulative probability to be faster when sampling later.
|
||||||
metadata.mutation_probabilities_cumulative =
|
calculate_cumulative_distribution_in_place(&mut mutation_probabilities)?;
|
||||||
calculate_cumulative_distribution(mutation_probabilities)?;
|
metadata.mutation_probabilities_cumulative = mutation_probabilities;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -395,8 +371,7 @@ mod test {
|
|||||||
use libafl_bolts::tuples::tuple_list;
|
use libafl_bolts::tuples::tuple_list;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
calculate_cumulative_distribution, BitFlipMutator, ByteDecMutator,
|
BitFlipMutator, ByteDecMutator, TuneableScheduledMutator, TuneableScheduledMutatorMetadata,
|
||||||
TuneableScheduledMutator, TuneableScheduledMutatorMetadata,
|
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
inputs::BytesInput,
|
inputs::BytesInput,
|
||||||
@ -406,6 +381,11 @@ mod test {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_tuning() {
|
fn test_tuning() {
|
||||||
|
#[cfg(any(not(feature = "serdeany_autoreg"), miri))]
|
||||||
|
unsafe {
|
||||||
|
TuneableScheduledMutatorMetadata::register();
|
||||||
|
}
|
||||||
|
|
||||||
let mut state: NopState<BytesInput> = NopState::new();
|
let mut state: NopState<BytesInput> = NopState::new();
|
||||||
let mutators = tuple_list!(
|
let mutators = tuple_list!(
|
||||||
BitFlipMutator::new(),
|
BitFlipMutator::new(),
|
||||||
@ -423,28 +403,12 @@ mod test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn get_cdf_fails_with_invalid_probs() {
|
fn test_mutation_distribution() {
|
||||||
// Distribution has to sum up to 1.
|
#[cfg(any(not(feature = "serdeany_autoreg"), miri))]
|
||||||
assert!(calculate_cumulative_distribution(vec![]).is_err());
|
unsafe {
|
||||||
assert!(calculate_cumulative_distribution(vec![0.0]).is_err());
|
TuneableScheduledMutatorMetadata::register();
|
||||||
assert!(calculate_cumulative_distribution(vec![0.9]).is_err());
|
|
||||||
assert!(calculate_cumulative_distribution(vec![0.9, 0.9]).is_err());
|
|
||||||
assert!(calculate_cumulative_distribution(vec![f32::NAN]).is_err());
|
|
||||||
assert!(calculate_cumulative_distribution(vec![f32::INFINITY]).is_err());
|
|
||||||
assert!(calculate_cumulative_distribution(vec![f32::NEG_INFINITY]).is_err());
|
|
||||||
|
|
||||||
// Elements have to be between 0 and 1
|
|
||||||
assert!(calculate_cumulative_distribution(vec![-0.5, 0.5, 0.5]).is_err());
|
|
||||||
|
|
||||||
assert!(calculate_cumulative_distribution(vec![1.0]).is_ok());
|
|
||||||
assert!(calculate_cumulative_distribution(vec![0.0, 1.0]).is_ok());
|
|
||||||
assert!(calculate_cumulative_distribution(vec![0.0, 1.0, 0.0]).is_ok());
|
|
||||||
assert!(calculate_cumulative_distribution(vec![0.5, 0.5]).is_ok());
|
|
||||||
assert!(calculate_cumulative_distribution(vec![0.2; 5]).is_ok());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_mutation_distribution() {
|
|
||||||
let mut state: NopState<BytesInput> = NopState::new();
|
let mut state: NopState<BytesInput> = NopState::new();
|
||||||
let mutators = tuple_list!(
|
let mutators = tuple_list!(
|
||||||
BitFlipMutator::new(),
|
BitFlipMutator::new(),
|
||||||
|
@ -55,6 +55,10 @@ impl CmpValues {
|
|||||||
|
|
||||||
/// A state metadata holding a list of values logged from comparisons
|
/// A state metadata holding a list of values logged from comparisons
|
||||||
#[derive(Debug, Default, Serialize, Deserialize)]
|
#[derive(Debug, Default, Serialize, Deserialize)]
|
||||||
|
#[cfg_attr(
|
||||||
|
any(not(feature = "serdeany_autoreg"), miri),
|
||||||
|
allow(clippy::unsafe_derive_deserialize)
|
||||||
|
)] // for SerdeAny
|
||||||
pub struct CmpValuesMetadata {
|
pub struct CmpValuesMetadata {
|
||||||
/// A `list` of values.
|
/// A `list` of values.
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
@ -562,6 +566,10 @@ where
|
|||||||
|
|
||||||
/// A state metadata holding a list of values logged from comparisons. AFL++ RQ version.
|
/// A state metadata holding a list of values logged from comparisons. AFL++ RQ version.
|
||||||
#[derive(Debug, Default, Serialize, Deserialize)]
|
#[derive(Debug, Default, Serialize, Deserialize)]
|
||||||
|
#[cfg_attr(
|
||||||
|
any(not(feature = "serdeany_autoreg"), miri),
|
||||||
|
allow(clippy::unsafe_derive_deserialize)
|
||||||
|
)] // for SerdeAny
|
||||||
pub struct AFLppCmpValuesMetadata {
|
pub struct AFLppCmpValuesMetadata {
|
||||||
/// The first map of AFLppCmpVals retrieved by running the un-mutated input
|
/// The first map of AFLppCmpVals retrieved by running the un-mutated input
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
|
@ -22,6 +22,10 @@ use crate::{
|
|||||||
|
|
||||||
/// A testcase metadata holding a list of indexes of a map
|
/// A testcase metadata holding a list of indexes of a map
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
#[cfg_attr(
|
||||||
|
any(not(feature = "serdeany_autoreg"), miri),
|
||||||
|
allow(clippy::unsafe_derive_deserialize)
|
||||||
|
)] // for SerdeAny
|
||||||
pub struct AccountingIndexesMetadata {
|
pub struct AccountingIndexesMetadata {
|
||||||
/// The list of indexes.
|
/// The list of indexes.
|
||||||
pub list: Vec<usize>,
|
pub list: Vec<usize>,
|
||||||
@ -73,6 +77,10 @@ impl AccountingIndexesMetadata {
|
|||||||
|
|
||||||
/// A state metadata holding a map of favoreds testcases for each map entry
|
/// A state metadata holding a map of favoreds testcases for each map entry
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
#[cfg_attr(
|
||||||
|
any(not(feature = "serdeany_autoreg"), miri),
|
||||||
|
allow(clippy::unsafe_derive_deserialize)
|
||||||
|
)] // for SerdeAny
|
||||||
pub struct TopAccountingMetadata {
|
pub struct TopAccountingMetadata {
|
||||||
/// map index -> corpus index
|
/// map index -> corpus index
|
||||||
pub map: HashMap<usize, CorpusId>,
|
pub map: HashMap<usize, CorpusId>,
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
use alloc::string::{String, ToString};
|
use alloc::string::{String, ToString};
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
|
use libafl_bolts::math::integer_sqrt;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -14,16 +15,6 @@ use crate::{
|
|||||||
Error,
|
Error,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn integer_sqrt(val: u64) -> u64 {
|
|
||||||
let mut i = 0;
|
|
||||||
let mut r = 0;
|
|
||||||
while r <= val {
|
|
||||||
r = i * i;
|
|
||||||
i += 1;
|
|
||||||
}
|
|
||||||
i - 1
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Copy, Default)]
|
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Copy, Default)]
|
||||||
/// The state of the `EcoFuzz` scheduling algorithm
|
/// The state of the `EcoFuzz` scheduling algorithm
|
||||||
pub enum EcoState {
|
pub enum EcoState {
|
||||||
@ -38,6 +29,10 @@ pub enum EcoState {
|
|||||||
|
|
||||||
/// The testcase Metadata for `EcoScheduler`
|
/// The testcase Metadata for `EcoScheduler`
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
|
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
|
||||||
|
#[cfg_attr(
|
||||||
|
any(not(feature = "serdeany_autoreg"), miri),
|
||||||
|
allow(clippy::unsafe_derive_deserialize)
|
||||||
|
)] // for SerdeAny
|
||||||
pub struct EcoTestcaseMetadata {
|
pub struct EcoTestcaseMetadata {
|
||||||
mutation_num: u64,
|
mutation_num: u64,
|
||||||
exec_num: u64,
|
exec_num: u64,
|
||||||
@ -53,6 +48,10 @@ libafl_bolts::impl_serdeany!(EcoTestcaseMetadata);
|
|||||||
|
|
||||||
/// The state Metadata for `EcoScheduler`
|
/// The state Metadata for `EcoScheduler`
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
|
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
|
||||||
|
#[cfg_attr(
|
||||||
|
any(not(feature = "serdeany_autoreg"), miri),
|
||||||
|
allow(clippy::unsafe_derive_deserialize)
|
||||||
|
)] // for SerdeAny
|
||||||
pub struct EcoMetadata {
|
pub struct EcoMetadata {
|
||||||
state: EcoState,
|
state: EcoState,
|
||||||
initial_corpus_count: Option<usize>,
|
initial_corpus_count: Option<usize>,
|
||||||
@ -283,7 +282,7 @@ where
|
|||||||
let tcmeta = tc.metadata_mut::<EcoTestcaseMetadata>()?;
|
let tcmeta = tc.metadata_mut::<EcoTestcaseMetadata>()?;
|
||||||
|
|
||||||
tcmeta.exec_num = exec_num;
|
tcmeta.exec_num = exec_num;
|
||||||
tcmeta.serial = state.corpus().count() as u64 + 1;
|
tcmeta.serial = (state.corpus().count() as u64).saturating_add(1);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,12 +23,20 @@ pub const DEFAULT_SKIP_NON_FAVORED_PROB: u64 = 95;
|
|||||||
|
|
||||||
/// A testcase metadata saying if a testcase is favored
|
/// A testcase metadata saying if a testcase is favored
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
#[cfg_attr(
|
||||||
|
any(not(feature = "serdeany_autoreg"), miri),
|
||||||
|
allow(clippy::unsafe_derive_deserialize)
|
||||||
|
)] // for SerdeAny
|
||||||
pub struct IsFavoredMetadata {}
|
pub struct IsFavoredMetadata {}
|
||||||
|
|
||||||
libafl_bolts::impl_serdeany!(IsFavoredMetadata);
|
libafl_bolts::impl_serdeany!(IsFavoredMetadata);
|
||||||
|
|
||||||
/// A state metadata holding a map of favoreds testcases for each map entry
|
/// A state metadata holding a map of favoreds testcases for each map entry
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
#[cfg_attr(
|
||||||
|
any(not(feature = "serdeany_autoreg"), miri),
|
||||||
|
allow(clippy::unsafe_derive_deserialize)
|
||||||
|
)] // for SerdeAny
|
||||||
pub struct TopRatedsMetadata {
|
pub struct TopRatedsMetadata {
|
||||||
/// map index -> corpus index
|
/// map index -> corpus index
|
||||||
pub map: HashMap<usize, CorpusId>,
|
pub map: HashMap<usize, CorpusId>,
|
||||||
|
@ -24,6 +24,10 @@ libafl_bolts::impl_serdeany!(SchedulerMetadata);
|
|||||||
|
|
||||||
/// The metadata used for power schedules
|
/// The metadata used for power schedules
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
|
#[cfg_attr(
|
||||||
|
any(not(feature = "serdeany_autoreg"), miri),
|
||||||
|
allow(clippy::unsafe_derive_deserialize)
|
||||||
|
)] // for SerdeAny
|
||||||
pub struct SchedulerMetadata {
|
pub struct SchedulerMetadata {
|
||||||
/// Powerschedule strategy
|
/// Powerschedule strategy
|
||||||
strat: Option<PowerSchedule>,
|
strat: Option<PowerSchedule>,
|
||||||
|
@ -27,6 +27,10 @@ where
|
|||||||
|
|
||||||
/// A state metadata holding a map of probability of corpus elements.
|
/// A state metadata holding a map of probability of corpus elements.
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
#[cfg_attr(
|
||||||
|
any(not(feature = "serdeany_autoreg"), miri),
|
||||||
|
allow(clippy::unsafe_derive_deserialize)
|
||||||
|
)] // for SerdeAny
|
||||||
pub struct ProbabilityMetadata {
|
pub struct ProbabilityMetadata {
|
||||||
/// corpus index -> probability
|
/// corpus index -> probability
|
||||||
pub map: HashMap<CorpusId, f64>,
|
pub map: HashMap<CorpusId, f64>,
|
||||||
|
@ -18,6 +18,10 @@ use crate::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Default, Clone, Copy, Eq, PartialEq, Debug, Serialize, Deserialize)]
|
#[derive(Default, Clone, Copy, Eq, PartialEq, Debug, Serialize, Deserialize)]
|
||||||
|
#[cfg_attr(
|
||||||
|
any(not(feature = "serdeany_autoreg"), miri),
|
||||||
|
allow(clippy::unsafe_derive_deserialize)
|
||||||
|
)] // for SerdeAny
|
||||||
struct TuneableSchedulerMetadata {
|
struct TuneableSchedulerMetadata {
|
||||||
next: Option<CorpusId>,
|
next: Option<CorpusId>,
|
||||||
}
|
}
|
||||||
|
@ -24,9 +24,12 @@ use crate::{
|
|||||||
Error,
|
Error,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
|
||||||
|
|
||||||
/// The Metadata for `WeightedScheduler`
|
/// The Metadata for `WeightedScheduler`
|
||||||
|
#[cfg_attr(
|
||||||
|
any(not(feature = "serdeany_autoreg"), miri),
|
||||||
|
allow(clippy::unsafe_derive_deserialize)
|
||||||
|
)] // for SerdeAny
|
||||||
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
pub struct WeightedScheduleMetadata {
|
pub struct WeightedScheduleMetadata {
|
||||||
/// The fuzzer execution spent in the current cycles
|
/// The fuzzer execution spent in the current cycles
|
||||||
runs_in_current_cycle: usize,
|
runs_in_current_cycle: usize,
|
||||||
|
@ -7,7 +7,7 @@ use alloc::{
|
|||||||
use core::{fmt::Debug, marker::PhantomData, time::Duration};
|
use core::{fmt::Debug, marker::PhantomData, time::Duration};
|
||||||
|
|
||||||
use hashbrown::HashSet;
|
use hashbrown::HashSet;
|
||||||
use libafl_bolts::{current_time, AsIter, Named};
|
use libafl_bolts::{current_time, impl_serdeany, AsIter, Named};
|
||||||
use num_traits::Bounded;
|
use num_traits::Bounded;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
@ -26,15 +26,19 @@ use crate::{
|
|||||||
Error,
|
Error,
|
||||||
};
|
};
|
||||||
|
|
||||||
libafl_bolts::impl_serdeany!(UnstableEntriesMetadata);
|
|
||||||
/// The metadata to keep unstable entries
|
/// The metadata to keep unstable entries
|
||||||
/// In libafl, the stability is the number of the unstable entries divided by the size of the map
|
/// In libafl, the stability is the number of the unstable entries divided by the size of the map
|
||||||
/// This is different from AFL++, which shows the number of the unstable entries divided by the number of filled entries.
|
/// This is different from AFL++, which shows the number of the unstable entries divided by the number of filled entries.
|
||||||
|
#[cfg_attr(
|
||||||
|
any(not(feature = "serdeany_autoreg"), miri),
|
||||||
|
allow(clippy::unsafe_derive_deserialize)
|
||||||
|
)] // for SerdeAny
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
pub struct UnstableEntriesMetadata {
|
pub struct UnstableEntriesMetadata {
|
||||||
unstable_entries: HashSet<usize>,
|
unstable_entries: HashSet<usize>,
|
||||||
map_len: usize,
|
map_len: usize,
|
||||||
}
|
}
|
||||||
|
impl_serdeany!(UnstableEntriesMetadata);
|
||||||
|
|
||||||
impl UnstableEntriesMetadata {
|
impl UnstableEntriesMetadata {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
|
@ -101,8 +101,12 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
|
||||||
/// Store the taint and the input
|
/// Store the taint and the input
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
#[cfg_attr(
|
||||||
|
any(not(feature = "serdeany_autoreg"), miri),
|
||||||
|
allow(clippy::unsafe_derive_deserialize)
|
||||||
|
)] // for SerdeAny
|
||||||
pub struct TaintMetadata {
|
pub struct TaintMetadata {
|
||||||
input_vec: Vec<u8>,
|
input_vec: Vec<u8>,
|
||||||
ranges: Vec<Range<usize>>,
|
ranges: Vec<Range<usize>>,
|
||||||
|
@ -16,6 +16,10 @@ use crate::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
/// Metadata used to store information about disk dump indexes for names
|
/// Metadata used to store information about disk dump indexes for names
|
||||||
|
#[cfg_attr(
|
||||||
|
any(not(feature = "serdeany_autoreg"), miri),
|
||||||
|
allow(clippy::unsafe_derive_deserialize)
|
||||||
|
)] // for SerdeAny
|
||||||
#[derive(Default, Serialize, Deserialize, Clone, Debug)]
|
#[derive(Default, Serialize, Deserialize, Clone, Debug)]
|
||||||
pub struct DumpToDiskMetadata {
|
pub struct DumpToDiskMetadata {
|
||||||
last_corpus: Option<CorpusId>,
|
last_corpus: Option<CorpusId>,
|
||||||
|
@ -25,7 +25,7 @@ use crate::{
|
|||||||
|
|
||||||
const MAX_GENERALIZED_LEN: usize = 8192;
|
const MAX_GENERALIZED_LEN: usize = 8192;
|
||||||
|
|
||||||
fn increment_by_offset(_list: &[Option<u8>], idx: usize, off: u8) -> usize {
|
const fn increment_by_offset(_list: &[Option<u8>], idx: usize, off: u8) -> usize {
|
||||||
idx + 1 + off as usize
|
idx + 1 + off as usize
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,6 +22,10 @@ use crate::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
/// Metadata used to store information about disk sync time
|
/// Metadata used to store information about disk sync time
|
||||||
|
#[cfg_attr(
|
||||||
|
any(not(feature = "serdeany_autoreg"), miri),
|
||||||
|
allow(clippy::unsafe_derive_deserialize)
|
||||||
|
)] // for SerdeAny
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
pub struct SyncFromDiskMetadata {
|
pub struct SyncFromDiskMetadata {
|
||||||
/// The last time the sync was done
|
/// The last time the sync was done
|
||||||
@ -191,6 +195,10 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Metadata used to store information about the last sent testcase with `SyncFromBrokerStage`
|
/// Metadata used to store information about the last sent testcase with `SyncFromBrokerStage`
|
||||||
|
#[cfg_attr(
|
||||||
|
any(not(feature = "serdeany_autoreg"), miri),
|
||||||
|
allow(clippy::unsafe_derive_deserialize)
|
||||||
|
)] // for SerdeAny
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
pub struct SyncFromBrokerMetadata {
|
pub struct SyncFromBrokerMetadata {
|
||||||
/// The `CorpusId` of the last sent testcase
|
/// The `CorpusId` of the last sent testcase
|
||||||
|
@ -20,6 +20,10 @@ use crate::{
|
|||||||
Error, Evaluator,
|
Error, Evaluator,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[cfg_attr(
|
||||||
|
any(not(feature = "serdeany_autoreg"), miri),
|
||||||
|
allow(clippy::unsafe_derive_deserialize)
|
||||||
|
)] // for SerdeAny
|
||||||
#[derive(Default, Clone, Copy, Eq, PartialEq, Debug, Serialize, Deserialize)]
|
#[derive(Default, Clone, Copy, Eq, PartialEq, Debug, Serialize, Deserialize)]
|
||||||
struct TuneableMutationalStageMetadata {
|
struct TuneableMutationalStageMetadata {
|
||||||
iters: Option<u64>,
|
iters: Option<u64>,
|
||||||
|
@ -75,6 +75,21 @@ Welcome to `LibAFL`
|
|||||||
#![allow(clippy::borrow_as_ptr)]
|
#![allow(clippy::borrow_as_ptr)]
|
||||||
#![allow(clippy::borrow_deref_ref)]
|
#![allow(clippy::borrow_deref_ref)]
|
||||||
|
|
||||||
|
/// We need some sort of "[`String`]" for errors in `no_alloc`...
|
||||||
|
/// We can only support `'static` without allocator, so let's do that.
|
||||||
|
#[cfg(not(feature = "alloc"))]
|
||||||
|
type String = &'static str;
|
||||||
|
|
||||||
|
/// We also need a non-allocating format...
|
||||||
|
/// This one simply returns the `fmt` string.
|
||||||
|
/// Good enough for simple errors, for anything else, use the `alloc` feature.
|
||||||
|
#[cfg(not(feature = "alloc"))]
|
||||||
|
macro_rules! format {
|
||||||
|
($fmt:literal) => {{
|
||||||
|
$fmt
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate std;
|
extern crate std;
|
||||||
@ -85,6 +100,55 @@ pub extern crate alloc;
|
|||||||
#[cfg(feature = "ctor")]
|
#[cfg(feature = "ctor")]
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub use ctor::ctor;
|
pub use ctor::ctor;
|
||||||
|
#[cfg(feature = "alloc")]
|
||||||
|
pub mod anymap;
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
pub mod build_id;
|
||||||
|
#[cfg(all(
|
||||||
|
any(feature = "cli", feature = "frida_cli", feature = "qemu_cli"),
|
||||||
|
feature = "std"
|
||||||
|
))]
|
||||||
|
pub mod cli;
|
||||||
|
#[cfg(feature = "gzip")]
|
||||||
|
pub mod compress;
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
pub mod core_affinity;
|
||||||
|
pub mod cpu;
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
pub mod fs;
|
||||||
|
#[cfg(feature = "alloc")]
|
||||||
|
pub mod llmp;
|
||||||
|
pub mod math;
|
||||||
|
#[cfg(all(feature = "std", unix))]
|
||||||
|
pub mod minibsod;
|
||||||
|
pub mod os;
|
||||||
|
#[cfg(feature = "alloc")]
|
||||||
|
pub mod ownedref;
|
||||||
|
pub mod rands;
|
||||||
|
#[cfg(feature = "alloc")]
|
||||||
|
pub mod serdeany;
|
||||||
|
pub mod shmem;
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
pub mod staterestore;
|
||||||
|
pub mod tuples;
|
||||||
|
|
||||||
|
#[cfg(feature = "alloc")]
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
use core::{iter::Iterator, time};
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
use std::time::{SystemTime, UNIX_EPOCH};
|
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
/// The client ID == the sender id.
|
||||||
|
#[repr(transparent)]
|
||||||
|
#[derive(
|
||||||
|
Debug, Default, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize,
|
||||||
|
)]
|
||||||
|
pub struct ClientId(pub u32);
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
use log::{Metadata, Record};
|
||||||
|
|
||||||
#[deprecated(
|
#[deprecated(
|
||||||
since = "0.11.0",
|
since = "0.11.0",
|
||||||
@ -112,21 +176,6 @@ use std::{env::VarError, io};
|
|||||||
#[cfg(feature = "libafl_derive")]
|
#[cfg(feature = "libafl_derive")]
|
||||||
pub use libafl_derive::SerdeAny;
|
pub use libafl_derive::SerdeAny;
|
||||||
|
|
||||||
/// We need some sort of "[`String`]" for errors in `no_alloc`...
|
|
||||||
/// We can only support `'static` without allocator, so let's do that.
|
|
||||||
#[cfg(not(feature = "alloc"))]
|
|
||||||
type String = &'static str;
|
|
||||||
|
|
||||||
/// We also need a non-allocating format...
|
|
||||||
/// This one simply returns the `fmt` string.
|
|
||||||
/// Good enough for simple errors, for anything else, use the `alloc` feature.
|
|
||||||
#[cfg(not(feature = "alloc"))]
|
|
||||||
macro_rules! format {
|
|
||||||
($fmt:literal) => {{
|
|
||||||
$fmt
|
|
||||||
}};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// We need fixed names for many parts of this lib.
|
/// We need fixed names for many parts of this lib.
|
||||||
pub trait Named {
|
pub trait Named {
|
||||||
/// Provide the name of this element.
|
/// Provide the name of this element.
|
||||||
@ -467,55 +516,6 @@ pub unsafe extern "C" fn external_current_millis() -> u64 {
|
|||||||
1000
|
1000
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "alloc")]
|
|
||||||
pub mod anymap;
|
|
||||||
#[cfg(feature = "std")]
|
|
||||||
pub mod build_id;
|
|
||||||
#[cfg(all(
|
|
||||||
any(feature = "cli", feature = "frida_cli", feature = "qemu_cli"),
|
|
||||||
feature = "std"
|
|
||||||
))]
|
|
||||||
pub mod cli;
|
|
||||||
#[cfg(feature = "gzip")]
|
|
||||||
pub mod compress;
|
|
||||||
#[cfg(feature = "std")]
|
|
||||||
pub mod core_affinity;
|
|
||||||
pub mod cpu;
|
|
||||||
#[cfg(feature = "std")]
|
|
||||||
pub mod fs;
|
|
||||||
#[cfg(feature = "alloc")]
|
|
||||||
pub mod llmp;
|
|
||||||
#[cfg(all(feature = "std", unix))]
|
|
||||||
pub mod minibsod;
|
|
||||||
pub mod os;
|
|
||||||
#[cfg(feature = "alloc")]
|
|
||||||
pub mod ownedref;
|
|
||||||
pub mod rands;
|
|
||||||
#[cfg(feature = "alloc")]
|
|
||||||
pub mod serdeany;
|
|
||||||
pub mod shmem;
|
|
||||||
#[cfg(feature = "std")]
|
|
||||||
pub mod staterestore;
|
|
||||||
pub mod tuples;
|
|
||||||
|
|
||||||
#[cfg(feature = "alloc")]
|
|
||||||
use alloc::vec::Vec;
|
|
||||||
use core::{iter::Iterator, ops::AddAssign, time};
|
|
||||||
#[cfg(feature = "std")]
|
|
||||||
use std::time::{SystemTime, UNIX_EPOCH};
|
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
/// The client ID == the sender id.
|
|
||||||
#[repr(transparent)]
|
|
||||||
#[derive(
|
|
||||||
Debug, Default, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize,
|
|
||||||
)]
|
|
||||||
pub struct ClientId(pub u32);
|
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
|
||||||
use log::{Metadata, Record};
|
|
||||||
|
|
||||||
/// Can be converted to a slice
|
/// Can be converted to a slice
|
||||||
pub trait AsSlice {
|
pub trait AsSlice {
|
||||||
/// Type of the entries in this slice
|
/// Type of the entries in this slice
|
||||||
@ -656,23 +656,6 @@ pub fn current_time() -> time::Duration {
|
|||||||
time::Duration::from_millis(millis)
|
time::Duration::from_millis(millis)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Given a u64 number, return a hashed number using this mixing function
|
|
||||||
/// This function is used to hash an address into a more random number (used in `libafl_frida`).
|
|
||||||
/// Mixing function: <http://mostlymangling.blogspot.com/2018/07/on-mixing-functions-in-fast-splittable.html>
|
|
||||||
#[inline]
|
|
||||||
#[must_use]
|
|
||||||
pub fn xxh3_rrmxmx_mixer(v: u64) -> u64 {
|
|
||||||
let tmp = (v >> 32) + ((v & 0xffffffff) << 32);
|
|
||||||
let bitflip = 0x1cad21f72c81017c ^ 0xdb979082e96dd4de;
|
|
||||||
let mut h64 = tmp ^ bitflip;
|
|
||||||
h64 = h64.rotate_left(49) & h64.rotate_left(24);
|
|
||||||
h64 = h64.wrapping_mul(0x9FB21C651E98DF25);
|
|
||||||
h64 ^= (h64 >> 35) + 8;
|
|
||||||
h64 = h64.wrapping_mul(0x9FB21C651E98DF25);
|
|
||||||
h64 ^= h64 >> 28;
|
|
||||||
h64
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Gets current nanoseconds since [`UNIX_EPOCH`]
|
/// Gets current nanoseconds since [`UNIX_EPOCH`]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -695,30 +678,6 @@ pub fn format_duration_hms(duration: &time::Duration) -> String {
|
|||||||
format!("{}h-{}m-{}s", (secs / 60) / 60, (secs / 60) % 60, secs % 60)
|
format!("{}h-{}m-{}s", (secs / 60) / 60, (secs / 60) % 60, secs % 60)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Calculates the cumulative sum for a slice, in-place.
|
|
||||||
/// The values are useful for example for cumulative probabilities.
|
|
||||||
///
|
|
||||||
/// So, to give an example:
|
|
||||||
/// ```rust
|
|
||||||
/// # extern crate libafl_bolts;
|
|
||||||
/// use libafl_bolts::calculate_cumulative_sum_in_place;
|
|
||||||
///
|
|
||||||
/// let mut value = [2, 4, 1, 3];
|
|
||||||
/// calculate_cumulative_sum_in_place(&mut value);
|
|
||||||
/// assert_eq!(&[2, 6, 7, 10], &value);
|
|
||||||
/// ```
|
|
||||||
pub fn calculate_cumulative_sum_in_place<T>(mut_slice: &mut [T])
|
|
||||||
where
|
|
||||||
T: Default + AddAssign<T> + Copy,
|
|
||||||
{
|
|
||||||
let mut acc = T::default();
|
|
||||||
|
|
||||||
for val in mut_slice {
|
|
||||||
acc += *val;
|
|
||||||
*val = acc;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Stderr logger
|
/// Stderr logger
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
pub static LIBAFL_STDERR_LOGGER: SimpleStderrLogger = SimpleStderrLogger::new();
|
pub static LIBAFL_STDERR_LOGGER: SimpleStderrLogger = SimpleStderrLogger::new();
|
||||||
|
@ -521,6 +521,9 @@ fn next_shmem_size(max_alloc: usize) -> usize {
|
|||||||
|
|
||||||
/// Initialize a new `llmp_page`. The size should be relative to
|
/// Initialize a new `llmp_page`. The size should be relative to
|
||||||
/// `llmp_page->messages`
|
/// `llmp_page->messages`
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
/// Will write to the raw SHM page header, should be safe for correct [`ShMem`] implementations
|
||||||
unsafe fn llmp_page_init<SHM: ShMem>(shmem: &mut SHM, sender_id: ClientId, allow_reinit: bool) {
|
unsafe fn llmp_page_init<SHM: ShMem>(shmem: &mut SHM, sender_id: ClientId, allow_reinit: bool) {
|
||||||
#[cfg(feature = "llmp_debug")]
|
#[cfg(feature = "llmp_debug")]
|
||||||
log::trace!("llmp_page_init: shmem {:?}", &shmem);
|
log::trace!("llmp_page_init: shmem {:?}", &shmem);
|
||||||
@ -551,6 +554,9 @@ unsafe fn llmp_page_init<SHM: ShMem>(shmem: &mut SHM, sender_id: ClientId, allow
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get the next pointer and make sure it's in the current page, and has enough space.
|
/// Get the next pointer and make sure it's in the current page, and has enough space.
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
/// Will dereference `last_msg`
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn llmp_next_msg_ptr_checked<SHM: ShMem>(
|
unsafe fn llmp_next_msg_ptr_checked<SHM: ShMem>(
|
||||||
map: &mut LlmpSharedMap<SHM>,
|
map: &mut LlmpSharedMap<SHM>,
|
||||||
@ -576,6 +582,9 @@ unsafe fn llmp_next_msg_ptr_checked<SHM: ShMem>(
|
|||||||
|
|
||||||
/// Pointer to the message behind the last message
|
/// Pointer to the message behind the last message
|
||||||
/// The messages are padded, so accesses will be aligned properly.
|
/// The messages are padded, so accesses will be aligned properly.
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
/// Will dereference the `last_msg` ptr
|
||||||
#[inline]
|
#[inline]
|
||||||
#[allow(clippy::cast_ptr_alignment)]
|
#[allow(clippy::cast_ptr_alignment)]
|
||||||
unsafe fn _llmp_next_msg_ptr(last_msg: *const LlmpMsg) -> *mut LlmpMsg {
|
unsafe fn _llmp_next_msg_ptr(last_msg: *const LlmpMsg) -> *mut LlmpMsg {
|
||||||
|
145
libafl_bolts/src/math.rs
Normal file
145
libafl_bolts/src/math.rs
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
//! Math-related functions that we commonly (or at least sometimes) need
|
||||||
|
|
||||||
|
use core::ops::AddAssign;
|
||||||
|
|
||||||
|
use crate::Error;
|
||||||
|
|
||||||
|
/// Returns the cumulative distribution function for a discrete distribution.
|
||||||
|
pub fn calculate_cumulative_distribution_in_place(probabilities: &mut [f32]) -> Result<(), Error> {
|
||||||
|
if probabilities.is_empty() {
|
||||||
|
return Err(Error::illegal_argument("empty list of probabilities"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if !probabilities.iter().all(|&p| (0.0..=1.0).contains(&p)) {
|
||||||
|
return Err(Error::illegal_argument(format!(
|
||||||
|
"invalid probability distribution: {probabilities:?}"
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
let cumulative = probabilities;
|
||||||
|
calculate_cumulative_sum_in_place(cumulative);
|
||||||
|
|
||||||
|
// The cumulative sum should be roughly equal to 1.
|
||||||
|
let last = cumulative.last_mut().unwrap();
|
||||||
|
let offset_to_1 = *last - 1.0_f32;
|
||||||
|
if offset_to_1.is_nan() || offset_to_1 > 1.0e-4 || -offset_to_1 > 1.0e-4 {
|
||||||
|
return Err(Error::illegal_argument(format!(
|
||||||
|
"sum of probabilities ({last}) is not 1"
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clamp the end of the vector to account for floating point errors.
|
||||||
|
*last = 1.0_f32;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Calculates the integer square root using binary search
|
||||||
|
/// Algorithm from
|
||||||
|
/// <https://en.wikipedia.org/wiki/Integer_square_root#Algorithm_using_binary_search>.
|
||||||
|
#[must_use]
|
||||||
|
pub const fn integer_sqrt(val: u64) -> u64 {
|
||||||
|
if val == u64::MAX {
|
||||||
|
return 2_u64.pow(32) - 1;
|
||||||
|
}
|
||||||
|
let mut ret = 0;
|
||||||
|
let mut i = val + 1;
|
||||||
|
let mut m;
|
||||||
|
|
||||||
|
while ret != i - 1 {
|
||||||
|
m = (ret + i) / 2;
|
||||||
|
|
||||||
|
if m.saturating_mul(m) <= val {
|
||||||
|
ret = m;
|
||||||
|
} else {
|
||||||
|
i = m;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Given a u64 number, return a hashed number using this mixing function
|
||||||
|
/// This function is used to hash an address into a more random number (used in `libafl_frida`).
|
||||||
|
/// Mixing function: <http://mostlymangling.blogspot.com/2018/07/on-mixing-functions-in-fast-splittable.html>
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn xxh3_rrmxmx_mixer(v: u64) -> u64 {
|
||||||
|
let tmp = (v >> 32) + ((v & 0xffffffff) << 32);
|
||||||
|
let bitflip = 0x1cad21f72c81017c ^ 0xdb979082e96dd4de;
|
||||||
|
let mut h64 = tmp ^ bitflip;
|
||||||
|
h64 = h64.rotate_left(49) & h64.rotate_left(24);
|
||||||
|
h64 = h64.wrapping_mul(0x9FB21C651E98DF25);
|
||||||
|
h64 ^= (h64 >> 35) + 8;
|
||||||
|
h64 = h64.wrapping_mul(0x9FB21C651E98DF25);
|
||||||
|
h64 ^= h64 >> 28;
|
||||||
|
h64
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Calculates the cumulative sum for a slice, in-place.
|
||||||
|
/// The values are useful for example for cumulative probabilities.
|
||||||
|
///
|
||||||
|
/// So, to give an example:
|
||||||
|
/// ```rust
|
||||||
|
/// # extern crate libafl_bolts;
|
||||||
|
/// use libafl_bolts::math::calculate_cumulative_sum_in_place;
|
||||||
|
///
|
||||||
|
/// let mut value = [2, 4, 1, 3];
|
||||||
|
/// calculate_cumulative_sum_in_place(&mut value);
|
||||||
|
/// assert_eq!(&[2, 6, 7, 10], &value);
|
||||||
|
/// ```
|
||||||
|
pub fn calculate_cumulative_sum_in_place<T>(mut_slice: &mut [T])
|
||||||
|
where
|
||||||
|
T: Default + AddAssign<T> + Copy,
|
||||||
|
{
|
||||||
|
let mut acc = T::default();
|
||||||
|
|
||||||
|
for val in mut_slice {
|
||||||
|
acc += *val;
|
||||||
|
*val = acc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::{calculate_cumulative_distribution_in_place, integer_sqrt};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_integer_sqrt() {
|
||||||
|
assert_eq!(0, integer_sqrt(0));
|
||||||
|
assert_eq!(1, integer_sqrt(1));
|
||||||
|
assert_eq!(2, integer_sqrt(4));
|
||||||
|
assert_eq!(10, integer_sqrt(120));
|
||||||
|
assert_eq!(11, integer_sqrt(121));
|
||||||
|
assert_eq!(11, integer_sqrt(128));
|
||||||
|
assert_eq!(2_u64.pow(16) - 1, integer_sqrt(u64::from(u32::MAX)));
|
||||||
|
assert_eq!(2_u64.pow(32) - 1, integer_sqrt(u64::MAX));
|
||||||
|
assert_eq!(2_u64.pow(32) - 1, integer_sqrt(u64::MAX - 1));
|
||||||
|
assert_eq!(128, integer_sqrt(128 * 128));
|
||||||
|
assert_eq!(128, integer_sqrt((128 * 128) + 1));
|
||||||
|
assert_eq!(128, integer_sqrt((128 * 128) + 127));
|
||||||
|
assert_eq!(128, integer_sqrt((128 * 128) + 127));
|
||||||
|
assert_eq!(999999, integer_sqrt((999999 * 999999) + 9));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn get_cdf_fails_with_invalid_probs() {
|
||||||
|
// Distribution has to sum up to 1.
|
||||||
|
assert!(calculate_cumulative_distribution_in_place(&mut []).is_err());
|
||||||
|
assert!(calculate_cumulative_distribution_in_place(&mut [0.0]).is_err());
|
||||||
|
assert!(calculate_cumulative_distribution_in_place(&mut [0.9]).is_err());
|
||||||
|
assert!(calculate_cumulative_distribution_in_place(&mut [0.9, 0.9]).is_err());
|
||||||
|
assert!(calculate_cumulative_distribution_in_place(&mut [f32::NAN]).is_err());
|
||||||
|
assert!(calculate_cumulative_distribution_in_place(&mut [f32::INFINITY]).is_err());
|
||||||
|
assert!(calculate_cumulative_distribution_in_place(&mut [f32::NEG_INFINITY]).is_err());
|
||||||
|
|
||||||
|
// Elements have to be between 0 and 1
|
||||||
|
assert!(calculate_cumulative_distribution_in_place(&mut [-0.5, 0.5, 0.5]).is_err());
|
||||||
|
|
||||||
|
assert!(calculate_cumulative_distribution_in_place(&mut [1.0]).is_ok());
|
||||||
|
assert!(calculate_cumulative_distribution_in_place(&mut [0.0, 1.0]).is_ok());
|
||||||
|
assert!(calculate_cumulative_distribution_in_place(&mut [0.0, 1.0, 0.0]).is_ok());
|
||||||
|
assert!(calculate_cumulative_distribution_in_place(&mut [0.5, 0.5]).is_ok());
|
||||||
|
assert!(calculate_cumulative_distribution_in_place(&mut [0.2; 5]).is_ok());
|
||||||
|
}
|
||||||
|
}
|
@ -618,15 +618,6 @@ pub use serdeany_registry::*;
|
|||||||
macro_rules! create_register {
|
macro_rules! create_register {
|
||||||
($struct_type:ty) => {
|
($struct_type:ty) => {
|
||||||
const _: () = {
|
const _: () = {
|
||||||
/// Manually register this type at a later point in time
|
|
||||||
///
|
|
||||||
/// # Safety
|
|
||||||
/// This may never be called concurrently as it dereferences the `RegistryBuilder` without acquiring a lock.
|
|
||||||
#[cfg(not(feature = "serdeany_autoreg"))]
|
|
||||||
pub unsafe fn register() {
|
|
||||||
$crate::serdeany::RegistryBuilder::register::<$struct_type>();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Automatically register this type
|
/// Automatically register this type
|
||||||
#[cfg(feature = "serdeany_autoreg")]
|
#[cfg(feature = "serdeany_autoreg")]
|
||||||
#[$crate::ctor]
|
#[$crate::ctor]
|
||||||
@ -665,6 +656,18 @@ macro_rules! impl_serdeany {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(any(not(feature = "serdeany_autoreg"), miri))]
|
||||||
|
impl< $( $lt $( : $clt $(+ $dlt )* )? ),+ > $struct_name < $( $lt ),+ > {
|
||||||
|
|
||||||
|
/// Manually register this type at a later point in time
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
/// This may never be called concurrently as it dereferences the `RegistryBuilder` without acquiring a lock.
|
||||||
|
pub unsafe fn register() {
|
||||||
|
$crate::serdeany::RegistryBuilder::register::<$struct_name < $( $lt ),+ >>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$(
|
$(
|
||||||
$crate::create_register!($struct_name < $( $opt ),+ >);
|
$crate::create_register!($struct_name < $( $opt ),+ >);
|
||||||
)*
|
)*
|
||||||
@ -690,6 +693,17 @@ macro_rules! impl_serdeany {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(any(not(feature = "serdeany_autoreg"), miri))]
|
||||||
|
impl $struct_name {
|
||||||
|
/// Manually register this type at a later point in time
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
/// This may never be called concurrently as it dereferences the `RegistryBuilder` without acquiring a lock.
|
||||||
|
pub unsafe fn register() {
|
||||||
|
$crate::serdeany::RegistryBuilder::register::<$struct_name>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$crate::create_register!($struct_name);
|
$crate::create_register!($struct_name);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -141,13 +141,13 @@ impl ShMemId {
|
|||||||
/// Returns `true` if this `ShMemId` has an empty backing slice.
|
/// Returns `true` if this `ShMemId` has an empty backing slice.
|
||||||
/// If this is the case something went wrong, and this `ShMemId` may not be read from.
|
/// If this is the case something went wrong, and this `ShMemId` may not be read from.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn is_empty(&self) -> bool {
|
pub const fn is_empty(&self) -> bool {
|
||||||
self.id[0] == 0
|
self.id[0] == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the id as a fixed-length slice
|
/// Get the id as a fixed-length slice
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn as_array(&self) -> &[u8; 20] {
|
pub const fn as_array(&self) -> &[u8; 20] {
|
||||||
&self.id
|
&self.id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@ use std::{cell::RefCell, marker::PhantomPinned, pin::Pin, rc::Rc};
|
|||||||
use dynasmrt::DynasmLabelApi;
|
use dynasmrt::DynasmLabelApi;
|
||||||
use dynasmrt::{dynasm, DynasmApi};
|
use dynasmrt::{dynasm, DynasmApi};
|
||||||
use frida_gum::{instruction_writer::InstructionWriter, stalker::StalkerOutput};
|
use frida_gum::{instruction_writer::InstructionWriter, stalker::StalkerOutput};
|
||||||
use libafl_bolts::xxh3_rrmxmx_mixer;
|
use libafl_bolts::math::xxh3_rrmxmx_mixer;
|
||||||
use rangemap::RangeMap;
|
use rangemap::RangeMap;
|
||||||
|
|
||||||
use crate::helper::FridaRuntime;
|
use crate::helper::FridaRuntime;
|
||||||
|
@ -12,6 +12,10 @@ use crate::{
|
|||||||
GuestAddr,
|
GuestAddr,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[cfg_attr(
|
||||||
|
any(not(feature = "serdeany_autoreg"), miri),
|
||||||
|
allow(clippy::unsafe_derive_deserialize)
|
||||||
|
)] // for SerdeAny
|
||||||
#[derive(Debug, Default, Serialize, Deserialize)]
|
#[derive(Debug, Default, Serialize, Deserialize)]
|
||||||
pub struct QemuCmpsMapMetadata {
|
pub struct QemuCmpsMapMetadata {
|
||||||
pub map: HashMap<u64, u64>,
|
pub map: HashMap<u64, u64>,
|
||||||
|
@ -19,6 +19,10 @@ static DRCOV_IDS: Mutex<Option<Vec<u64>>> = Mutex::new(None);
|
|||||||
static DRCOV_MAP: Mutex<Option<HashMap<GuestAddr, u64>>> = Mutex::new(None);
|
static DRCOV_MAP: Mutex<Option<HashMap<GuestAddr, u64>>> = Mutex::new(None);
|
||||||
static DRCOV_LENGTHS: Mutex<Option<HashMap<GuestAddr, GuestUsize>>> = Mutex::new(None);
|
static DRCOV_LENGTHS: Mutex<Option<HashMap<GuestAddr, GuestUsize>>> = Mutex::new(None);
|
||||||
|
|
||||||
|
#[cfg_attr(
|
||||||
|
any(not(feature = "serdeany_autoreg"), miri),
|
||||||
|
allow(clippy::unsafe_derive_deserialize)
|
||||||
|
)] // for SerdeAny
|
||||||
#[derive(Debug, Default, Serialize, Deserialize)]
|
#[derive(Debug, Default, Serialize, Deserialize)]
|
||||||
pub struct QemuDrCovMetadata {
|
pub struct QemuDrCovMetadata {
|
||||||
pub current_id: u64,
|
pub current_id: u64,
|
||||||
|
@ -14,6 +14,10 @@ use crate::{
|
|||||||
hooks::QemuHooks,
|
hooks::QemuHooks,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[cfg_attr(
|
||||||
|
any(not(feature = "serdeany_autoreg"), miri),
|
||||||
|
allow(clippy::unsafe_derive_deserialize)
|
||||||
|
)] // for SerdeAny
|
||||||
#[derive(Debug, Default, Serialize, Deserialize)]
|
#[derive(Debug, Default, Serialize, Deserialize)]
|
||||||
pub struct QemuEdgesMapMetadata {
|
pub struct QemuEdgesMapMetadata {
|
||||||
pub map: HashMap<(GuestAddr, GuestAddr), u64>,
|
pub map: HashMap<(GuestAddr, GuestAddr), u64>,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user