use alloc::{
borrow::Cow,
string::{String, ToString},
};
use core::fmt::Debug;
use std::fs::create_dir_all;
use libafl_bolts::Named;
use serde::{Deserialize, Serialize};
use crate::{
Error, HasMetadata,
common::nautilus::grammartec::{chunkstore::ChunkStore, context::Context},
corpus::{Corpus, Testcase},
feedbacks::{Feedback, StateInitializer},
generators::NautilusContext,
inputs::NautilusInput,
state::HasCorpus,
};
#[derive(Serialize, Deserialize)]
pub struct NautilusChunksMetadata {
pub cks: ChunkStore,
}
impl Debug for NautilusChunksMetadata {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(
f,
"NautilusChunksMetadata {{ {} }}",
serde_json::to_string_pretty(self).unwrap(),
)
}
}
libafl_bolts::impl_serdeany!(NautilusChunksMetadata);
impl NautilusChunksMetadata {
#[must_use]
pub fn new(work_dir: String) -> Self {
create_dir_all(format!("{}/outputs/chunks", &work_dir))
.expect("Could not create folder in workdir");
Self {
cks: ChunkStore::new(work_dir),
}
}
}
#[derive(Debug)]
pub struct NautilusFeedback<'a> {
ctx: &'a Context,
}
impl<'a> NautilusFeedback<'a> {
#[must_use]
pub fn new(context: &'a NautilusContext) -> Self {
Self { ctx: &context.ctx }
}
fn append_nautilus_metadata_to_state<S>(
&mut self,
state: &mut S,
testcase: &mut Testcase<NautilusInput>,
) -> Result<(), Error>
where
S: HasCorpus<NautilusInput> + HasMetadata,
{
state.corpus().load_input_into(testcase)?;
let input = testcase.input().as_ref().unwrap().clone();
let meta = state
.metadata_map_mut()
.get_mut::<NautilusChunksMetadata>()
.expect("NautilusChunksMetadata not in the state");
meta.cks.add_tree(input.tree, self.ctx);
Ok(())
}
}
impl Named for NautilusFeedback<'_> {
fn name(&self) -> &Cow<'static, str> {
static NAME: Cow<'static, str> = Cow::Borrowed("NautilusFeedback");
&NAME
}
}
impl<S> StateInitializer<S> for NautilusFeedback<'_> {}
impl<EM, OT, S> Feedback<EM, NautilusInput, OT, S> for NautilusFeedback<'_>
where
S: HasMetadata + HasCorpus<NautilusInput>,
{
fn append_metadata(
&mut self,
state: &mut S,
_manager: &mut EM,
_observers: &OT,
testcase: &mut Testcase<NautilusInput>,
) -> Result<(), Error> {
self.append_nautilus_metadata_to_state(state, testcase)
}
#[cfg(feature = "track_hit_feedbacks")]
fn last_result(&self) -> Result<bool, Error> {
Ok(false)
}
}
#[derive(Serialize, Deserialize, Clone, Debug)]
struct NautilusUnparseMetadata {
unparsed: String,
}
libafl_bolts::impl_serdeany!(NautilusUnparseMetadata);
#[derive(Debug)]
pub struct NautilusUnparseToMetadataFeedback<'a> {
context: &'a NautilusContext,
}
impl<'a> NautilusUnparseToMetadataFeedback<'a> {
#[must_use]
pub fn new(context: &'a NautilusContext) -> Self {
Self { context }
}
}
impl<S> StateInitializer<S> for NautilusUnparseToMetadataFeedback<'_> {}
impl<EM, OT, S> Feedback<EM, NautilusInput, OT, S> for NautilusUnparseToMetadataFeedback<'_> {
fn append_metadata(
&mut self,
_state: &mut S,
_manager: &mut EM,
_observers: &OT,
testcase: &mut Testcase<NautilusInput>,
) -> Result<(), Error> {
let input = testcase.input().as_ref().unwrap().clone();
let mut unparse_target = vec![];
input.unparse(self.context, &mut unparse_target);
let unparsed = String::from_utf8_lossy(&unparse_target).to_string();
testcase.metadata_or_insert_with(|| NautilusUnparseMetadata { unparsed });
Ok(())
}
#[cfg(feature = "track_hit_feedbacks")]
fn last_result(&self) -> Result<bool, Error> {
Ok(false)
}
}
impl Named for NautilusUnparseToMetadataFeedback<'_> {
fn name(&self) -> &Cow<'static, str> {
static NAME: Cow<'static, str> = Cow::Borrowed("NautilusUnparseToMetadataFeedback");
&NAME
}
}