Skip to content
Snippets Groups Projects
Commit 9fd1a194 authored by Jorge Aparicio's avatar Jorge Aparicio
Browse files

initial commit

parents
No related branches found
No related tags found
No related merge requests found
**/*.rs.bk
.#*
target
\ No newline at end of file
# 1 minute introduction
``` console
$ cargo install --path cargo-klee # add -f, if already installed
$ cd klee-examples
$ cargo klee --example foo --release
```
[[package]]
name = "cargo-klee"
version = "0.1.0"
dependencies = [
"libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "libc"
version = "0.2.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
[metadata]
"checksum libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "5ba3df4dcb460b9dfbd070d41c94c19209620c191b0340b929ce748a2bcd42d2"
[package]
authors = ["Jorge Aparicio <jorge@japaric.io>"]
name = "cargo-klee"
version = "0.1.0"
[dependencies]
libc = "0.2.33"
extern crate libc;
use std::io::{self, Read, Write};
use std::process::{Command, Stdio};
use std::{env, str};
fn main() {
// first argument is the path to this binary; the second argument is always "klee" -- both can
// be ignored
let args = env::args().skip(2).collect::<Vec<_>>();
// turn `cargo klee --example foo` into `xargo rustc --example foo -- (..)`
let mut c = Command::new("xargo");
c.arg("rustc")
.args(&args)
// verbose output for debugging purposes
.arg("-v")
.arg("--color=always")
.arg("--")
// ignore linking
.args(&["-C", "linker=true"])
// force LTO
.args(&["-C", "lto"])
// also output the LLVM-IR (.ll file) for debugging purposes
.arg("--emit=llvm-bc,llvm-ir")
// force panic=abort in all crates
.env("RUSTFLAGS", "-C panic=abort")
// collect stderr
.stderr(Stdio::piped());
// print full command for debugging purposes
eprintln!("{:?}", c);
// spawn process and drive it completion while replicating its stderr in ours
let mut p = c.spawn().unwrap();
let mut pstderr = p.stderr.take().unwrap();
let mut buf = [0; 1024];
let mut output = vec![];
let stderr = io::stderr();
let mut stderr = stderr.lock();
loop {
if let Ok(n) = pstderr.read(&mut buf) {
stderr.write(&buf[..n]).unwrap();
output.extend_from_slice(&buf[..n]);
}
if let Some(status) = p.try_wait().unwrap() {
assert!(status.success());
break;
}
}
// next we are going to try to run the .bc file using klee inside a docker container
// FIXME the way we find out which .bc file we have to use is pretty hacky; using Cargo as a
// library would be cleaner, I suppose
// find out the argument passed to `--example`, if used at all
let mut example = None;
let mut iargs = args.iter();
while let Some(arg) = iargs.next() {
if arg == "--example" {
example = iargs.next();
break;
}
}
// get the suffix of the example
let (example, suffix) = if let Some(example) = example {
let mut suffix = None;
let output = str::from_utf8(&output).unwrap();
for line in output.lines() {
if line.contains(&format!("examples/{}.rs", example)) {
for part in line.split(' ') {
if part.starts_with("extra-filename=") {
suffix = part.split('=').nth(1);
}
}
}
}
(example, suffix.unwrap())
} else {
// nothing to do if the user didn't use `--example`
return;
};
let profile = if args.iter().any(|a| a == "--release") {
"release"
} else {
"debug"
};
let mut docker = Command::new("docker");
docker
.arg("run")
.arg("--rm")
.args(&["--user", &format!("{}:{}", uid(), gid())])
.args(&[
"-v",
&format!("{}:/mnt", env::current_dir().unwrap().display()),
])
.args(&["-w", "/mnt"])
.arg("-it")
.arg("afoht/llvm-klee-4")
.args(&[
"/usr/bin/klee",
&format!("target/{}/examples/{}{}.bc", profile, example, suffix),
]);
// print full command for debugging purposes
eprintln!("{:?}", docker);
assert!(docker.status().unwrap().success());
}
// NOTE from cross
fn gid() -> u32 {
unsafe { libc::getgid() }
}
// NOTE from cross
fn uid() -> u32 {
unsafe { libc::getuid() }
}
[[package]]
name = "cstr_core"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cty 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "cty"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "klee"
version = "0.1.0"
dependencies = [
"cstr_core 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"cty 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "klee-examples"
version = "0.1.0"
dependencies = [
"klee 0.1.0",
]
[[package]]
name = "memchr"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[metadata]
"checksum cstr_core 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7829882406e7b36cff95319f674b72fc51dd3b0e6968f33db8f6a26903c1e128"
"checksum cty 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c4e1d41c471573612df00397113557693b5bf5909666a8acb253930612b93312"
"checksum memchr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "148fab2e51b4f1cfc66da2a7c32981d1d3c083a803978268bb11fe4b86925e7a"
[package]
name = "klee-examples"
version = "0.1.0"
authors = ["Jorge Aparicio <jorge@japaric.io>"]
[dependencies]
klee = {path="../klee"}
[profile.release]
debug = true
\ No newline at end of file
#![no_std]
#[macro_use]
extern crate klee;
use core::ptr;
fn main() {
let u = symbol!("u");
unsafe {
ptr::read_volatile(&f2(f1(u)));
}
}
// add 1 and saturate
fn f1(u: u8) -> u8 {
u.wrapping_add(1)
}
fn f2(u: u8) -> u8 {
100 / u
}
Cargo.lock
\ No newline at end of file
[package]
authors = ["Jorge Aparicio <jorge@japaric.io>"]
name = "klee"
version = "0.1.0"
[dependencies]
cstr_core = "0.1.0"
cty = "0.1.5"
#[lang = "panic_fmt"]
unsafe extern "C" fn panic_fmt(_: ::core::fmt::Arguments, _: &'static str, _: u32, _: u32) -> ! {
::abort()
}
#[lang = "start"]
extern "C" fn start(main: fn(), _argc: isize, _argv: *const *const u8) -> isize {
main();
0
}
#![no_std]
#![feature(lang_items)]
extern crate cstr_core;
extern crate cty;
mod lang_items;
mod ll;
use core::mem;
use cty::c_void;
#[doc(hidden)]
pub use cstr_core::CStr;
pub fn abort() -> ! {
unsafe { ll::abort() }
}
pub fn assume(cond: bool) {
unsafe {
ll::klee_assume(cond);
}
}
#[doc(hidden)]
#[inline]
pub fn symbol<T>(name: &CStr) -> T {
let mut t: T = unsafe { mem::uninitialized() };
unsafe {
ll::klee_make_symbolic(
&mut t as *mut T as *mut c_void,
mem::size_of::<T>(),
name.as_ptr(),
)
}
t
}
#[macro_export]
macro_rules! symbol {
($name:expr) => {
$crate::symbol(unsafe {
$crate::CStr::from_bytes_with_nul_unchecked(concat!($name, "\0").as_bytes())
})
}
}
#[macro_export]
macro_rules! kassert {
($e:expr) => {
if !$e {
$crate::abort();
}
}
}
use cty::{c_char, c_void};
extern "C" {
pub fn abort() -> !;
pub fn klee_assume(cond: bool);
pub fn klee_make_symbolic(ptr: *mut c_void, size: usize, name: *const c_char);
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment