Skip to content
Snippets Groups Projects
Commit 6568c3fc authored by Per's avatar Per
Browse files

examples updated

parent b196a57b
No related branches found
No related tags found
No related merge requests found
// > cargo klee --bin peripheral -r -k -g -v --release
// ...
// KLEE: done: total instructions = 33
// KLEE: done: completed paths = 1
// KLEE: done: generated tests = 1
//
// The example, has just one path, leading up to an abort.
// The reason is that the progam unconditionally will panic, as
// taking the peripheral is only only allowed once (for soundness).
// (Internally this in tracked by a state variable.)
//
// This is very good news, that KLEE will detect the error at compile time.
//
// Let's remove the error to see if the example code is correct.
// (comment out the second `take`)
//
// > cargo klee --bin peripheral -r -k -g -v --release
//
// KLEE: ERROR: src/peripheral.rs:104: divide by zero
// KLEE: NOTE: now ignoring this error at this location
//
// KLEE: done: total instructions = 85
// KLEE: done: completed paths = 2
// KLEE: done: generated tests = 2
//
//(gdb) shell ls klee-last
// assembly.ll info messages.txt run.istats run.stats test000001.div.err test000001.kquery test000001.ktest test000002.ktest warnings.txt
//
// So we see that test000001.ktest was causing a division error,
// the other test case passed
//
// (gdb) set env KTEST_FILE=klee-last/test000001.ktest
// (gdb) run
// ...
// Program received signal SIGFPE, Arithmetic exception.
// 0x00005555555551b0 in main () at src/peripheral.rs:104
// 104 let some_time_quota = unchecked_div(a, c - b);
//
// Let's look at the actual test
// (gdb) shell ktest-tool klee-last/test000001.ktest
// ktest file : 'klee-last/test000001.ktest'
// args : ['/home/pln/rust/cargo-klee/klee-examples/target/release/deps/peripheral-d1d6043ca4c81fef.ll']
// num objects: 5
// object 0: name: 'PRIMASK'
// 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: ....
// 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: ....
// object 2: name: 'vcell'
// object 2: size: 4
// object 2: data: b'\x00\x00\x00\x00'
// object 2: hex : 0x00000000
// object 2: int : 0
// object 2: uint: 0
// object 2: text: ....
// object 3: name: 'vcell'
// object 3: size: 4
// object 3: data: b'\x00\x00\x00\x00'
// object 3: hex : 0x00000000
// object 3: int : 0
// object 3: uint: 0
// object 3: text: ....
// object 4: name: 'vcell'
// object 4: size: 4
// object 4: data: b'\x00\x00\x00\x00'
// object 4: hex : 0x00000000
// object 4: int : 0
// object 4: uint: 0
// object 4: text: ....
//
// In order to analyze hardware dependent code, hardware access are treated
// as a new symbolic value. In `cortex-m` we give symbolic names to core peripherals.
// The svd2rust generated PAC is currently given the symbolic name `vcell`. This
// might in the future change to giving the address to the register instead.
//
// A breakdown of the example:
// Behind the scenes the PRIMASK register is accessed, and given concrete value.
// This access is along the happy path towards the error, so any value would
// suffice (in this case 0x00000000 was selected by KLEE).
//
// The first `vcell` access: was done when enabling the cycle counter.
// The rest of accesses stem from reading `a`, `b`, and `c`.
// Critical here is that KLEE spots that `(c - b) = 0`, leading up to a division
// by zero error (satisfied by `c` and `b` set to 0x00000000)
//
// Notice here, that this error is spotted EVEN while we are telling
// Rust to use the primitive (intrinsic) division for performance.
//
#![feature(core_intrinsics)] // we use intrinsic division
#![no_std] #![no_std]
#![no_main] #![no_main]
...@@ -8,17 +106,18 @@ extern crate cortex_m; ...@@ -8,17 +106,18 @@ extern crate cortex_m;
use cortex_m::peripheral::Peripherals; use cortex_m::peripheral::Peripherals;
use core::{intrinsics::unchecked_div, ptr::read_volatile};
#[no_mangle] #[no_mangle]
fn main() { fn main() {
let peripherals = Peripherals::take().unwrap(); let peripherals = Peripherals::take().unwrap();
let mut dwt = peripherals.DWT; let mut dwt = peripherals.DWT;
dwt.enable_cycle_counter(); dwt.enable_cycle_counter();
let a = dwt.cyccnt.read();
let b = dwt.cyccnt.read();
let c = dwt.cyccnt.read();
unsafe { unsafe {
dwt.ctrl.write(0); let some_time_quota = unchecked_div(a, c - b);
read_volatile(&some_time_quota); // prevent optization
} }
if dwt.ctrl.read() == 0 {
if dwt.ctrl.read() == 0 {
klee::kabort!();
};
};
} }
//! showcase volatile register // showcase volatile register
//! // This is the underlying abstraction to all register accesses using the
//! $ cargo klee --bin register -r -g -k // embedded Rust ecosystem.
//! ... //
//! Reading symbols from register.replay...done. // 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
//! (gdb) set env KTEST_FILE=klee-last/test000001.ktest // will still be treated as a new symbol. That might be overly pessimistic
//! (gdb) run // but is a safe approximation for the worst case behavior of the hardware.
//! Starting program: /home/pln/rust/cargo-klee/klee-examples/target/release/deps/main2.replay //
//! [Inferior 1 (process 25074) exited with code 01] // > cargo klee --bin register --release
//! // ...
//! (gdb) set env KTEST_FILE=klee-last/test000003.ktest // KLEE: ERROR: /home/pln/.cargo/registry/src/github.com-1ecc6299db9ec823/panic-abort-0.3.2/src/lib.rs:49: abort failure
//! (gdb) run // KLEE: NOTE: now ignoring this error at this location
//! Starting program: /home/pln/rust/cargo-klee/klee-examples/target/release/deps/main2.replay
//! rust_begin_unwind (_info=0x7fffffffd678) // KLEE: done: total instructions = 33
//! at /home/pln/.cargo/git/checkouts/cargo-klee-8f30fda3bd23bb30/68dc73d/src/lang_items.rs:66 // KLEE: done: completed paths = 3
//! unsafe { intrinsics::abort() } // KLEE: done: generated tests = 3
//! (gdb) backtrace //
//! #0 rust_begin_unwind (_info=0x7fffffffd678) // > ls target/release/deps/klee-last/
//! at /home/pln/.cargo/git/checkouts/cargo-klee-8f30fda3bd23bb30/68dc73d/src/lang_items.rs:6 // assembly.ll info messages.txt run.istats run.stats test000001.ktest test000002.ktest test000003.abort.err test000003.kquery test000003.ktest warnings.txt
//! #1 0x000055555555531c in core::panicking::panic_fmt () at src/libcore/panicking.rs:95 //
//! #2 0x000055555555539b in core::panicking::panic () at src/libcore/panicking.rs:59 // We see that KLEE spoted the test3 hits unreachable (and thus panics)
//! #3 0x00005555555552a6 in main () at src/main2.rs:54 //
//! (gdb) q // Let's look at the test cases separately:
//! A debugging session is active. //
//! // test1 passed:
//! Inferior 1 [process 25893] will be killed. // ktest-tool target/release/deps/klee-last/test000001.ktest
//! $ ktest-tool --write-int target/debug/deps/klee-last/test000003.ktest // ktest file : 'target/release/deps/klee-last/test000001.ktest'
//! ktest file : 'target/debug/deps/klee-last/test000003.ktest' // args : ['/home/pln/rust/cargo-klee/klee-examples/target/release/deps/register-16afa0ec4812d3e4.ll']
//! args : ['/home/pln/rust/cargo-klee/klee-examples/target/debug/deps/main2-2a0fc03ce12ab528.ll'] // num objects: 1
//! num objects: 2 // object 0: name: 'vcell'
//! object 0: name: b'register' // object 0: size: 4
//! object 0: size: 4 // object 0: data: b'\x00\x00\x00\x00'
//! object 0: data: 0 // object 0: hex : 0x00000000
//! object 1: name: b'register' // object 0: int : 0
//! object 1: size: 4 // object 0: uint: 0
//! object 1: data: 0 // object 0: text: ....
// If the first read of the register is not 1 then we are ok.
//
// The second test also passed.
// ktest-tool target/release/deps/klee-last/test000002.ktest
// ktest file : 'target/release/deps/klee-last/test000002.ktest'
// args : ['/home/pln/rust/cargo-klee/klee-examples/target/release/deps/register-16afa0ec4812d3e4.ll']
// 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/deps/klee-last/test000003.ktest
// ktest file : 'target/release/deps/klee-last/test000003.ktest'
// args : ['/home/pln/rust/cargo-klee/klee-examples/target/release/deps/register-16afa0ec4812d3e4.ll']
// 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.
#![no_std] #![no_std]
#![no_main] #![no_main]
...@@ -43,15 +88,20 @@ extern crate klee; ...@@ -43,15 +88,20 @@ extern crate klee;
extern crate panic_abort; extern crate panic_abort;
extern crate volatile_register; extern crate volatile_register;
use volatile_register::RO; use volatile_register::RW;
#[no_mangle] #[no_mangle]
fn main() { fn main() {
let rw: RO<u32> = unsafe { core::mem::uninitialized() }; // we emulate a read/write hardware register (rw)
let rw: RW<u32> = unsafe { core::mem::MaybeUninit::uninit().assume_init() };
if rw.read() == 0 { // reading will render a symbolic value of type u32
if rw.read() == 0 { if rw.read() == 1 {
klee::kabort!(); // 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
if rw.read() == 2 {
unreachable!();
} }
} }
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment