diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 3e33120901f69..31a9b34ee0c77 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -87,6 +87,7 @@ pub fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) - | sym::assert_inhabited | sym::assert_zero_valid | sym::assert_mem_uninitialized_valid + | sym::breakpoint | sym::size_of | sym::min_align_of | sym::needs_drop diff --git a/library/core/src/arch.rs b/library/core/src/arch.rs index 57f456c98b3c6..95d88c7f67991 100644 --- a/library/core/src/arch.rs +++ b/library/core/src/arch.rs @@ -42,3 +42,30 @@ pub macro naked_asm("assembly template", $(operands,)* $(options($(option),*))?) pub macro global_asm("assembly template", $(operands,)* $(options($(option),*))?) { /* compiler built-in */ } + +/// Compiles to a target-specific software breakpoint instruction or equivalent. +/// +/// This will typically abort the program. It may result in a core dump, and/or the system logging +/// debug information. Additional target-specific capabilities may be possible depending on +/// debuggers or other tooling; in particular, a debugger may be able to resume execution. +/// +/// If possible, this will produce an instruction sequence that allows a debugger to resume *after* +/// the breakpoint, rather than resuming *at* the breakpoint; however, the exact behavior is +/// target-specific and debugger-specific, and not guaranteed. +/// +/// If the target platform does not have any kind of debug breakpoint instruction, this may compile +/// to a trapping instruction (e.g. an undefined instruction) instead, or to some other form of +/// target-specific abort that may or may not support convenient resumption. +/// +/// The precise behavior and the precise instruction generated are not guaranteed, except that in +/// normal execution with no debug tooling involved this will not continue executing. +/// +/// - On x86 targets, this produces an `int3` instruction. +/// - On aarch64 targets, this produces a `brk #0xf000` instruction. +// When stabilizing this, update the comment on `core::intrinsics::breakpoint`. +#[unstable(feature = "breakpoint", issue = "133724")] +#[inline(always)] +#[cfg(not(bootstrap))] +pub fn breakpoint() { + core::intrinsics::breakpoint(); +} diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index 46873fdc0479f..14e59f29d026a 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -1375,12 +1375,24 @@ pub unsafe fn prefetch_write_instruction(_data: *const T, _locality: i32) { unreachable!() } -/// Executes a breakpoint trap, for inspection by a debugger. +/// Compiles to a target-specific software breakpoint instruction or equivalent. /// -/// This intrinsic does not have a stable counterpart. +/// The (future) stabilized version of this intrinsic is [`core::arch::breakpoint`]. +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[rustc_nounwind] +#[cfg(not(bootstrap))] +pub fn breakpoint() { + unreachable!() +} + +/// Compiles to a target-specific software breakpoint instruction or equivalent. +/// +/// The (future) stabilized version of this intrinsic is [`core::arch::breakpoint`]. #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] +#[cfg(bootstrap)] pub unsafe fn breakpoint() { unreachable!() } diff --git a/tests/assembly/breakpoint.rs b/tests/assembly/breakpoint.rs new file mode 100644 index 0000000000000..93f1c1083c87c --- /dev/null +++ b/tests/assembly/breakpoint.rs @@ -0,0 +1,16 @@ +//@ revisions: aarch64 x86_64 +//@ assembly-output: emit-asm +//@[aarch64] compile-flags: --target aarch64-unknown-linux-gnu +//@[aarch64] needs-llvm-components: aarch64 +//@[x86_64] compile-flags: --target x86_64-unknown-linux-gnu -C llvm-args=-x86-asm-syntax=intel +//@[x86_64] needs-llvm-components: x86 + +#![feature(breakpoint)] +#![crate_type = "lib"] + +// CHECK-LABEL: use_bp +// aarch64: brk #0xf000 +// x86_64: int3 +pub fn use_bp() { + core::arch::breakpoint(); +} diff --git a/tests/ui/error-codes/E0622.rs b/tests/ui/error-codes/E0622.rs index ae7378a707e5c..08c6d17129604 100644 --- a/tests/ui/error-codes/E0622.rs +++ b/tests/ui/error-codes/E0622.rs @@ -1,6 +1,6 @@ #![feature(intrinsics)] extern "rust-intrinsic" { - pub static breakpoint : unsafe extern "rust-intrinsic" fn(); + pub static atomic_singlethreadfence_seqcst : unsafe extern "rust-intrinsic" fn(); //~^ ERROR intrinsic must be a function [E0622] } -fn main() { unsafe { breakpoint(); } } +fn main() { unsafe { atomic_singlethreadfence_seqcst(); } } diff --git a/tests/ui/error-codes/E0622.stderr b/tests/ui/error-codes/E0622.stderr index c59776b211fd6..739ec984fc606 100644 --- a/tests/ui/error-codes/E0622.stderr +++ b/tests/ui/error-codes/E0622.stderr @@ -1,8 +1,8 @@ error[E0622]: intrinsic must be a function --> $DIR/E0622.rs:3:5 | -LL | pub static breakpoint : unsafe extern "rust-intrinsic" fn(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected a function +LL | pub static atomic_singlethreadfence_seqcst : unsafe extern "rust-intrinsic" fn(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected a function error: aborting due to 1 previous error