Forked from
Per Lindgren / klee-examples
21 commits behind the upstream repository.
-
Per Lindgren authoredPer Lindgren authored
register_test.rs 5.10 KiB
#![no_std]
#![no_main]
use panic_klee as _;
use volatile_register::RW;
#[no_mangle]
fn main() {
// we emulate a read/write hardware register (rw)
let rw: RW<u32> = unsafe { core::mem::MaybeUninit::uninit().assume_init() };
// reading will render a symbolic value of type u32
let read_1 = rw.read();
if read_1 == 1 {
// we emulate a write to the hardware register
unsafe { rw.write(0) };
// this read is still treated as a new symbolic value of type u32
let read_2 = rw.read();
if read_2 == 2 {
// will generate a panic!() if reached.
unreachable!();
}
}
}
// showcase volatile register
// This is the underlying abstraction to all register accesses using the
// embedded Rust ecosystem.
//
// When analyzed by KLEE, we make the return value symbolic, thus each access
// givs a new unique symbol. Even if we write a value to it, the next read
// will still be treated as a new symbol. That might be overly pessimistic
// but is a safe approximation for the worst case behavior of the hardware.
//
// > cargo klee --example register_test --release
// ...
// KLEE: ERROR: /home/pln/.cargo/registry/src/github.com-1ecc6299db9ec823/panic-abort-0.3.2/src/lib.rs:49: abort failure
// KLEE: NOTE: now ignoring this error at this location
// KLEE: done: total instructions = 33
// KLEE: done: completed paths = 3
// KLEE: done: generated tests = 3
//
// > ls target/release/examples/klee-last/
// assembly.ll info messages.txt run.istats run.stats test000001.ktest test000002.ktest test000003.abort.err test000003.kquery test000003.ktest warnings.txt
//
// We see that KLEE spotted the test000003 hits unreachable (and thus panics)
//
// Let's look at the test cases separately:
//
// test1 passed:
// > ktest-tool target/release/examples/klee-last/test000001.ktest
// ktest file : 'target/release/examples/klee-last/test000001.ktest'
// args : ['...']
// num objects: 1
// object 0: name: 'vcell'
// object 0: size: 4
// object 0: data: b'\x00\x00\x00\x00'
// object 0: hex : 0x00000000
// object 0: int : 0
// object 0: uint: 0
// object 0: text: ....
//
// If the first read of the register is not 1 then we are ok (program ends).
//
// The second test also passed.
// ktest-tool target/release/examples/klee-last/test000002.ktest
// ktest file : 'target/release/examples/klee-last/test000002.ktest'
// args : ['...']
// num objects: 2
// object 0: name: 'vcell'
// object 0: size: 4
// object 0: data: b'\x01\x00\x00\x00'
// object 0: hex : 0x01000000
// object 0: int : 1
// object 0: uint: 1
// object 0: text: ....
// object 1: name: 'vcell'
// object 1: size: 4
// object 1: data: b'\x00\x00\x00\x00'
// object 1: hex : 0x00000000
// object 1: int : 0
// object 1: uint: 0
// object 1: text: ....
// Here we are saved by the second reading of the register NOT giving
// returning 2.
//
// The third test gives the error.
// ktest-tool target/release/examples/klee-last/test000003.ktest
// ktest file : 'target/release/examples/klee-last/test000003.ktest'
// args : ['...']
// num objects: 2
// object 0: name: 'vcell'
// object 0: size: 4
// object 0: data: b'\x01\x00\x00\x00'
// object 0: hex : 0x01000000
// object 0: int : 1
// object 0: uint: 1
// object 0: text: ....
// object 1: name: 'vcell'
// object 1: size: 4
// object 1: data: b'\x02\x00\x00\x00'
// object 1: hex : 0x02000000
// object 1: int : 2
// object 1: uint: 2
// object 1: text: ....
//
// The first read gives 1, the second 2, and we hit unreacable.
//
// We can replay the last test to gather more information:
// $ cargo klee --example register_test -r -k -g -v
// ...
// Reading symbols from register.replay...done.
//
// (gdb) set env KTEST_FILE=klee-last/test000001.ktest
// (gdb) run # for the generated test the program will run to end
// Starting program: /home/pln/rust/trustit/klee-examples/target/debug/examples/register_test.replay
// [Inferior 1 (process 25074) exited with code ...]
//
// (gdb) set env KTEST_FILE=klee-last/test000003.ktest
// (gdb) run # for the generated test the program will panic due to unreachable.
// // Starting program: /home/pln/rust/trustit/klee-examples/target/debug/examples/register_test.replay
// Program received signal SIGABRT, Aborted.
// 0x00007ffff7dd3f25 in raise () from /usr/lib/libc.so.6
// (gdb) backtrace
// #0 0x00007ffff7dd3f25 in raise () from /usr/lib/libc.so.6
// #1 0x00007ffff7dbd897 in abort () from /usr/lib/libc.so.6
// #2 0x00005555555553db in rust_begin_unwind (_info=0x7fffffffd268) at /home/pln/.cargo/git/checkouts/panic-klee-aa8d015442188497/3b0c897/src/lib.rs:8
// #3 0x000055555555533d in core::panicking::panic_fmt () at src/libcore/panicking.rs:139
// #4 0x00005555555553a9 in core::panicking::panic () at src/libcore/panicking.rs:70
// #5 0x0000555555555303 in main () at examples/register_test.rs:104
// (gdb) frame 5
// #5 0x0000555555555303 in main () at examples/register_test.rs:104
// 104 unreachable!();
// (gdb) print read_1
// $1 = 1
// (gdb) print read_2
// $2 = 2
//
// If this does not work its a gdb problem, try lldb the LLVM debugger
// (debug info may not be completely compatible)
//
// This is the way!