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);