     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

    //! ARM compiler specific intrinsics
    //!
    //! # References
    //!
    //! - [ARM Compiler v 6.10 - armclang Reference Guide][arm_comp_ref]
    //!
    //! [arm_comp_ref]: https://developer.arm.com/docs/100067/0610

    #[cfg(test)]
    use stdarch_test::assert_instr;

    /// Inserts a breakpoint instruction.
    ///
    /// `val` is a compile-time constant integer in range `[0, 255]`.
    ///
    /// The breakpoint instruction inserted is:
    ///
    /// * `BKPT` when compiling as T32,
    /// * `BRK` when compiling as A32 or A64.
    ///
    /// # Safety
    ///
    /// If `val` is out-of-range the behavior is **undefined**.
    ///
    /// # Note
    ///
    /// [ARM's documentation][arm_docs] defines that `__breakpoint` accepts the
    /// following values for `val`:
    ///
    /// - `0...65535` when compiling as A32 or A64,
    /// - `0...255` when compiling as T32.
    ///
    /// The current implementation only accepts values in range `[0, 255]` - if the
    /// value is out-of-range the behavior is **undefined**.
    ///
    /// [arm_docs]: https://developer.arm.com/docs/100067/latest/compiler-specific-intrinsics/__breakpoint-intrinsic
    #[cfg_attr(all(test, target_arch = "arm"), assert_instr(bkpt, val = 0))]
    #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(brk, val = 0))]
    #[inline(always)]
    #[rustc_args_required_const(0)]
    pub unsafe fn __breakpoint(val: i32) {
        // Ensure that this compiles correctly on non-arm architectures, so libstd
        // doc builds work. The proper macro will shadow this definition below.
        #[allow(unused_macros)]
        macro_rules! call {
            ($e:expr) => {
                ()
            };
        }

        #[cfg(target_arch = "arm")]
        macro_rules! call {
            ($imm8:expr) => {
                asm!(concat!("BKPT ", stringify!($imm8)) : : : : "volatile")
            }
        }

        #[cfg(target_arch = "aarch64")]
        macro_rules! call {
            ($imm8:expr) => {
                asm!(concat!("BRK ", stringify!($imm8)) : : : : "volatile")
            }
        }

        // We can't `panic!` inside this intrinsic, so we can't really validate the
        // arguments here. If `val` is out-of-range this macro uses `val == 255`:
        constify_imm8!(val, call);
    }