about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJosh Triplett <josh@joshtriplett.org>2024-12-01 19:07:13 -0800
committerJosh Triplett <josh@joshtriplett.org>2024-12-02 23:56:24 -0800
commita030ffbe354be8072fe2749d89c66365c192b0fe (patch)
treec78adb8413e72ffe2733e9deec90ac27c6e40402
parenta522d78598415cdd614ccc6d961160f192f64b5c (diff)
downloadrust-a030ffbe354be8072fe2749d89c66365c192b0fe.tar.gz
rust-a030ffbe354be8072fe2749d89c66365c192b0fe.zip
Add `core::arch::breakpoint` and test
Approved in [ACP 491](https://github.com/rust-lang/libs-team/issues/491).

Remove the `unsafe` on `core::intrinsics::breakpoint()`, since it's a
safe intrinsic to call and has no prerequisites.

(Thanks to @zachs18 for figuring out the `bootstrap`/`not(bootstrap)`
logic.)
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0622.md9
-rw-r--r--compiler/rustc_hir_analysis/src/check/intrinsic.rs1
-rw-r--r--library/core/src/arch.rs27
-rw-r--r--library/core/src/intrinsics/mod.rs12
-rw-r--r--tests/assembly/breakpoint.rs14
-rw-r--r--tests/ui/error-codes/E0622.rs4
-rw-r--r--tests/ui/error-codes/E0622.stderr4
7 files changed, 63 insertions, 8 deletions
diff --git a/compiler/rustc_error_codes/src/error_codes/E0622.md b/compiler/rustc_error_codes/src/error_codes/E0622.md
index 5d71ee9949d..4cb605b636d 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0622.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0622.md
@@ -7,10 +7,11 @@ Erroneous code example:
 #![allow(internal_features)]
 
 extern "rust-intrinsic" {
-    pub static breakpoint: fn(); // error: intrinsic must be a function
+    pub static atomic_singlethreadfence_seqcst: fn();
+    // error: intrinsic must be a function
 }
 
-fn main() { unsafe { breakpoint(); } }
+fn main() { unsafe { atomic_singlethreadfence_seqcst(); } }
 ```
 
 An intrinsic is a function available for use in a given programming language
@@ -22,8 +23,8 @@ error, just declare a function. Example:
 #![allow(internal_features)]
 
 extern "rust-intrinsic" {
-    pub fn breakpoint(); // ok!
+    pub fn atomic_singlethreadfence_seqcst(); // ok!
 }
 
-fn main() { unsafe { breakpoint(); } }
+fn main() { unsafe { atomic_singlethreadfence_seqcst(); } }
 ```
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
index 3e33120901f..31a9b34ee0c 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 57f456c98b3..95d88c7f679 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 46873fdc047..4c8fd922f19 100644
--- a/library/core/src/intrinsics/mod.rs
+++ b/library/core/src/intrinsics/mod.rs
@@ -1381,6 +1381,18 @@ pub unsafe fn prefetch_write_instruction<T>(_data: *const T, _locality: i32) {
 #[rustc_intrinsic]
 #[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
+#[cfg(not(bootstrap))]
+pub fn breakpoint() {
+    unreachable!()
+}
+
+/// Executes a breakpoint trap, for inspection by a debugger.
+///
+/// This intrinsic does not have a stable counterpart.
+#[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 00000000000..e0cc2d1eebb
--- /dev/null
+++ b/tests/assembly/breakpoint.rs
@@ -0,0 +1,14 @@
+//@ revisions: aarch64 x86_64
+//@ assembly-output: emit-asm
+//@[aarch64] only-aarch64
+//@[x86_64] only-x86_64
+
+#![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 ae7378a707e..08c6d171296 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 c59776b211f..739ec984fc6 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