1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
// SPDX-License-Identifier: BSD-2-Clauses

use std::os::raw::c_char;

// TODO replace with the variadic when it is stable
// TODO make it return a different value depending on what is the error
#[no_mangle]
extern "C" fn checkasm_fail_func(_fmt: *const c_char) -> i32 {
    eprintln!("checkasm failed");
    1
}

/// declare a function checker with the correct arguments
///
/// pass the function to check as first argument followed by the function arguments.
#[macro_export]
macro_rules! declare_fn {
    ($fun:ident ($($name:ident : $ty:ty),+)) => {
        cfg_if::cfg_if! {
            if #[cfg(target_arch="x86_64")] {
                fn $fun(func: *mut std::ffi::c_void, $($name: $ty),+) {
                    const CLOB: u64 = 0xdeadbeefdeadbeef;

                    extern "C" {
                        fn checkasm_checked_call(func: *mut c_void, ...) -> i32;
                        fn checkasm_stack_clobber(clobber: u64, ...);
                    }

                    unsafe {
                        checkasm_stack_clobber(CLOB, CLOB, CLOB, CLOB, CLOB, CLOB, CLOB,
                                               CLOB, CLOB, CLOB, CLOB, CLOB, CLOB, CLOB,
                                               CLOB, CLOB, CLOB, CLOB, CLOB, CLOB, CLOB);
                        #[cfg(target_os="windows")] {
                            let r = checkasm_checked_call(func, 0, 0, 0, 0, 0, $($name),+,
                                                          11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0, 0, 0);
                            assert_eq!(r, 0);
                        }
                        #[cfg(not(target_os="windows"))] {
                            let r = checkasm_checked_call(func, 0, 0, 0, 0, 0, $($name),+,
                                                          9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0);
                            assert_eq!(r, 0);
                        }
                    }
                }
            } else if #[cfg(target_arch="aarch64")] {
                fn $fun(func: *mut std::ffi::c_void, $($name: $ty),+) {
                    const CLOB: u64 = 0xdeadbeefdeadbeef;

                    extern "C" {
                        fn checkasm_checked_call(func: *mut c_void, ...) -> i32;
                        fn checkasm_stack_clobber(clobber: u64, ...);
                    }

                    unsafe {
                        checkasm_stack_clobber(CLOB, CLOB, CLOB, CLOB, CLOB, CLOB,
                                               CLOB, CLOB, CLOB, CLOB, CLOB, CLOB,
                                               CLOB, CLOB, CLOB, CLOB, CLOB, CLOB,
                                               CLOB, CLOB, CLOB, CLOB, CLOB);
                        let r = checkasm_checked_call(func, 0, 0, 0, 0, 0, 0, 0, $($name),+,
                                                      7, 6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0);
                        assert_eq!(r, 0);
                    }
                }
            } else {
                fn $fun(func: *mut c_void, $($name: $ty),+) {
                    unsafe {
                        let f: fn($($ty),+) = std::mem::transmute(func);
                        f($($name),+);
                    }
                }
            }
        }
    }
}