From e7f5f28e8722a7bffb2bf0bc0976b28055d4a301 Mon Sep 17 00:00:00 2001 From: Marcondiro Date: Mon, 8 Jul 2024 11:59:07 +0000 Subject: [PATCH] Improve docs --- libafl_derive/src/lib.rs | 36 +++++++++++++++++++++++++---- libafl_qemu/src/qemu/mod.rs | 5 ++-- libafl_qemu/src/qemu/qemu_config.rs | 18 ++++++++++++++- 3 files changed, 51 insertions(+), 8 deletions(-) diff --git a/libafl_derive/src/lib.rs b/libafl_derive/src/lib.rs index 361405bf401..a803ebd3977 100644 --- a/libafl_derive/src/lib.rs +++ b/libafl_derive/src/lib.rs @@ -77,16 +77,44 @@ pub fn libafl_serdeany_derive(input: TokenStream) -> TokenStream { /// Options: Some => inner type display None => "". /// Vec: inner type display space separated concatenation. /// Generics and other more or less exotic stuff are not supported. +/// +/// # Examples +/// +/// ```rust +/// use libafl_derive; +/// +/// #[derive(libafl_derive::Display)] +/// struct MyStruct { +/// foo: String, +/// bar: Option, +/// } +/// ``` +/// +/// The above code will expand to: +/// +/// ```rust +/// struct MyStruct { +/// foo: String, +/// bar: Option, +/// } +/// +/// impl core::fmt::Display for MyStruct { +/// fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { +/// f.write_fmt(format_args!(" {0}", self.foo))?; +/// if let Some(opt) = &self.bar { +/// f.write_fmt(format_args!(" {0}", opt))?; +/// } +/// Ok(()) +/// } +/// } +/// ``` #[proc_macro_derive(Display)] pub fn libafl_display(input: TokenStream) -> TokenStream { let DeriveInput { ident, data, .. } = parse_macro_input!(input as DeriveInput); if let Struct(s) = data { if let Named(fields) = s.fields { - let fields_fmt = fields - .named - .iter() - .map(libafl_display_field_by_type); + let fields_fmt = fields.named.iter().map(libafl_display_field_by_type); return quote! { impl core::fmt::Display for #ident { diff --git a/libafl_qemu/src/qemu/mod.rs b/libafl_qemu/src/qemu/mod.rs index 07320d682c7..a0337eb9e47 100644 --- a/libafl_qemu/src/qemu/mod.rs +++ b/libafl_qemu/src/qemu/mod.rs @@ -572,10 +572,9 @@ impl From for HookData { #[allow(clippy::unused_self)] impl Qemu { + /// For more details about the parameters check + /// [the QEMU documentation](https://www.qemu.org/docs/master/about/). pub fn builder() -> QemuConfigBuilder { - // Since Qemu is a zero sized struct, this is not a completely standard builder pattern. - // The Qemu configuration is not stored in the Qemu struct after build(). - // Therefore, to use the derived builder and avoid boilerplate a builder for QemuConfig is derived. QemuConfig::builder() } diff --git a/libafl_qemu/src/qemu/qemu_config.rs b/libafl_qemu/src/qemu/qemu_config.rs index f688693a071..e85b2f84d13 100644 --- a/libafl_qemu/src/qemu/qemu_config.rs +++ b/libafl_qemu/src/qemu/qemu_config.rs @@ -103,6 +103,7 @@ pub enum Monitor { } /// Set the directory for the BIOS, VGA BIOS and keymaps. +/// Corresponds to the `-L` option of QEMU. #[derive(Debug, Clone)] pub struct Bios { path: PathBuf, @@ -197,6 +198,7 @@ impl From for Snapshot { } } +/// When set to DISABLE, corresponds to the `-S` option of QEMU. #[derive(Debug, Clone, strum_macros::Display)] pub enum StartCPU { #[strum(serialize = "")] @@ -300,7 +302,11 @@ impl> From for Program { } #[derive(Debug, Clone, libafl_derive::Display, TypedBuilder)] -#[builder(build_method(into = Result), builder_method(vis = "pub(crate)"))] +#[builder(build_method(into = Result), builder_method(vis = "pub(crate)", + doc = "Since Qemu is a zero sized struct, this is not a completely standard builder pattern. \ + The Qemu configuration is not stored in the Qemu struct after build() but in QEMU_CONFIG \ + Therefore, to use the derived builder and avoid boilerplate a builder for QemuConfig is \ + derived."))] pub struct QemuConfig { #[cfg(emulation_mode = "systemmode")] #[builder(default, setter(strip_option))] @@ -337,6 +343,16 @@ pub struct QemuConfig { } // Adding something here? Please leave Program as the last field impl From for Result { + /// This method is necessary to make the API resemble a typical builder pattern, i.e. + /// `Qemu::builder().foo(bar).build()`, while still leveraging TypedBuilder for this + /// non-standard use case where `Qemu` doesn't store the configuration. + /// Internally, TypedBuilder is used to generate a builder for `QemuConfig`. + /// This `QemuConfig.into()` method is used by the derived `QemuConfigBuilder.build()` + /// to go from `QemuConfigBuilder` to `QemuConfig`, and finally to `Qemu` in one fn. + /// + /// # Errors + /// returns `QemuInitError` if the Qemu initialization fails, including if Qemu has been + /// initialized already. fn from(config: QemuConfig) -> Self { let args = config .to_string()