diff --git a/Cargo.toml b/Cargo.toml index 2cc9906b3b0adfc4d1573bd3e666844631fbcb92..087dec5234898c30d46b45ea60204d0fbeff3a19 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,3 +6,8 @@ edition = "2018" [dependencies] cstr_core = "0.1.2" + +[features] +inline-asm = [] +klee-analysis = [] +klee-replay = [] diff --git a/src/lib.rs b/src/lib.rs index 9be2219b5ff0bcc3a3b375787030358a840680dc..e1c30328bb8063da484ef85a279897eb3bf440d9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,70 +1,31 @@ -#![no_std] - -use core::ffi::c_void; -use cstr_core::c_char; - -#[doc(hidden)] -pub use cstr_core::CStr; - -pub mod ll; - -#[inline(always)] -fn klee_abort() -> ! { - unsafe { ll::abort() }; -} - -#[inline(always)] -pub fn klee_assume(cond: bool) { - unsafe { - ll::klee_assume(cond); - } -} +//! Documentation: +//! +//! ``` +//! cargo doc --features klee-analysis --open +//! +//! cargo doc --features klee-replay --features inline-asm --open +//! ``` +//! +//! Notice that replay requires the `inline asm` feature. +//! +//! TODO: unfortunately it seems that attributes only can apply to a single item +//! so the conditionals have to be repeated +//! +//! TODO: better documentation (as always) -#[inline(always)] -pub fn klee_make_symbolic<T>(t: &mut T, name: &'static CStr) { - unsafe { - ll::klee_make_symbolic( - t as *mut T as *mut c_void, - core::mem::size_of::<T>(), - name.as_ptr() as *const c_char, - ) - } -} - -/// terminates path (and generates unique test) -#[macro_export] -macro_rules! klee_abort { - () => { - unsafe { $crate::ll::abort() }; - }; -} - -/// conditionally terminates path (and generates unique test) -#[macro_export] -macro_rules! klee_assert { - ($e:expr) => {{ - if !$e { - unsafe { $crate::ll::abort() }; - } - }}; -} - -/// condititonally terminates path (and generates unique test) -#[macro_export] -macro_rules! klee_assert_eq { - ($e1:expr, $e2:expr ) => {{ - if !($e1 == $e2) { - unsafe { $crate::ll::abort() }; - } - }}; -} - -/// makes mutable reference symbolic associated to static string -#[macro_export] -macro_rules! klee_make_symbolic { - (&mut $id:expr, $name:expr) => { - $crate::klee_make_symbolic(unsafe { &mut $id }, unsafe { - $crate::CStr::from_bytes_with_nul_unchecked(concat!($name, "\0").as_bytes()) - }) - }; -} +#![no_std] +#![cfg_attr(feature = "inline-asm", feature(asm))] + +// re-exports for klee-analysis +#[cfg(feature = "klee-analysis")] +mod lib_klee_analysis; +#[cfg(feature = "klee-analysis")] +pub mod ll; // low level bindings +#[cfg(feature = "klee-analysis")] +pub use lib_klee_analysis::*; // functions and macros + +// re-exports for klee-replay +#[cfg(feature = "klee-replay")] +mod lib_klee_replay; +#[cfg(feature = "klee-replay")] +pub use lib_klee_replay::*; // functions and macros diff --git a/src/lib_klee_analysis.rs b/src/lib_klee_analysis.rs new file mode 100644 index 0000000000000000000000000000000000000000..d8a30c2c25ccbe2c5c5b80d8d55cf5e6f2678982 --- /dev/null +++ b/src/lib_klee_analysis.rs @@ -0,0 +1,68 @@ +use core::ffi::c_void; +use cstr_core::c_char; + +#[doc(hidden)] +pub use cstr_core::CStr; + +#[inline(always)] +fn klee_abort() -> ! { + unsafe { crate::ll::abort() }; +} + +/// introduces assumption +#[inline(always)] +pub fn klee_assume(cond: bool) { + unsafe { + crate::ll::klee_assume(cond); + } +} + +/// makes refence symbolic +#[inline(always)] +pub fn klee_make_symbolic<T>(t: &mut T, name: &'static CStr) { + unsafe { + crate::ll::klee_make_symbolic( + t as *mut T as *mut c_void, + core::mem::size_of::<T>(), + name.as_ptr() as *const c_char, + ) + } +} + +/// terminates path (and generates unique test) +#[macro_export] +macro_rules! klee_abort { + () => { + unsafe { $crate::ll::abort() }; + }; +} + +/// conditionally terminates path (and generates unique test) +#[macro_export] +macro_rules! klee_assert { + ($e:expr) => {{ + if !$e { + unsafe { $crate::ll::abort() }; + } + }}; +} + +/// condititonally terminates path (and generates unique test) +#[macro_export] +macro_rules! klee_assert_eq { + ($e1:expr, $e2:expr ) => {{ + if !($e1 == $e2) { + unsafe { $crate::ll::abort() }; + } + }}; +} + +/// makes mutable reference symbolic associated to static string +#[macro_export] +macro_rules! klee_make_symbolic { + (&mut $id:expr, $name:expr) => { + $crate::klee_make_symbolic(unsafe { &mut $id }, unsafe { + $crate::CStr::from_bytes_with_nul_unchecked(concat!($name, "\0").as_bytes()) + }) + }; +} diff --git a/src/lib_klee_replay.rs b/src/lib_klee_replay.rs new file mode 100644 index 0000000000000000000000000000000000000000..2f40b0faa6ca51b72d69f894b53aaa3abb60e6c1 --- /dev/null +++ b/src/lib_klee_replay.rs @@ -0,0 +1,54 @@ +use core::ffi::c_void; +use cstr_core::c_char; + +#[doc(hidden)] +pub use cstr_core::CStr; + +#[inline(always)] +fn klee_abort() -> ! { + panic!(); +} + +/// suppress assumption +#[inline(always)] +pub fn klee_assume(_cond: bool) {} + +#[inline(always)] +pub fn klee_make_symbolic<T>(t: &mut T) { + // force llvm to consider data to be mutaded + unsafe { + asm!("bkpt #0" : /* output */: /* input */ "r"(t): /* clobber */ : "volatile") + } +} + +/// terminates path +#[macro_export] +macro_rules! klee_abort { + () => { + panic!() + }; +} + +/// condititonally terminates path +#[macro_export] +macro_rules! klee_assert { + ($e:expr) => { + assert!($e) + }; +} + +/// condititonally terminates path +#[macro_export] +macro_rules! klee_assert_eq { + ($e1:expr, $e2:expr ) => { + assert_eq!($e1, $e2) + }; +} + +/// makes mutable reference symbolic associated to static string +#[macro_export] +macro_rules! klee_make_symbolic { + (&mut $id:expr, $name:expr) => { + $crate::klee_make_symbolic(unsafe { &mut $id }) + }; +} diff --git a/src/ll.rs b/src/ll.rs index 2010aebf357997496f0e6202ebbcc84a109b0331..ee2565a9ab12aad6768d35e5956a5604776b9e88 100644 --- a/src/ll.rs +++ b/src/ll.rs @@ -1,3 +1,4 @@ +//! Low level bindings extern "C" { pub fn abort() -> !; pub fn klee_assume(cond: bool);