Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Start working on proof of concept for exposing Backtrace in core #77384

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions compiler/rustc_hir/src/lang_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,10 @@ language_item_table! {
// libstd panic entry point. Necessary for const eval to be able to catch it
BeginPanic, sym::begin_panic, begin_panic_fn, Target::Fn;

BacktraceEnabled, sym::backtrace_enabled, backtrace_enabled, Target::Fn;
BacktraceCreate, sym::backtrace_create, backtrace_create, Target::Fn;
BacktraceStatus, sym::backtrace_status, backtrace_status, Target::Fn;

ExchangeMalloc, sym::exchange_malloc, exchange_malloc_fn, Target::Fn;
BoxFree, sym::box_free, box_free_fn, Target::Fn;
DropInPlace, sym::drop_in_place, drop_in_place_fn, Target::Fn;
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_hir/src/weak_lang_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,7 @@ weak_lang_items! {
eh_personality, EhPersonality, rust_eh_personality;
eh_catch_typeinfo, EhCatchTypeinfo, rust_eh_catch_typeinfo;
oom, Oom, rust_oom;
backtrace_create, BacktraceCreate, rust_backtrace_create;
backtrace_enabled, BacktraceEnabled, rust_backtrace_enabled;
backtrace_status, BacktraceStatus, rust_backtrace_status;
}
6 changes: 6 additions & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,9 @@ symbols! {
automatically_derived,
avx512_target_feature,
await_macro,
backtrace_create,
backtrace_enabled,
backtrace_status,
bang,
begin_panic,
bench,
Expand Down Expand Up @@ -931,6 +934,9 @@ symbols! {
rust_2015_preview,
rust_2018_preview,
rust_2021_preview,
rust_backtrace_create,
rust_backtrace_enabled,
rust_backtrace_status,
rust_begin_unwind,
rust_eh_catch_typeinfo,
rust_eh_personality,
Expand Down
200 changes: 200 additions & 0 deletions library/core/src/backtrace.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
//! hi
#![unstable(feature = "backtrace", issue = "74465")]
use crate::{fmt, ptr};

/// The current status of a backtrace, indicating whether it was captured or
/// whether it is empty for some other reason.
#[non_exhaustive]
#[derive(Debug, PartialEq, Eq)]
pub enum BacktraceStatus {
/// Capturing a backtrace is not supported, likely because it's not
/// implemented for the current platform.
Unsupported,
/// Capturing a backtrace has been disabled through either the
/// `RUST_LIB_BACKTRACE` or `RUST_BACKTRACE` environment variables.
Disabled,
/// A backtrace has been captured and the `Backtrace` should print
/// reasonable information when rendered.
Captured,
}

// perma(?)-unstable
#[unstable(feature = "backtrace", issue = "74465")]
///
pub trait RawBacktrace: fmt::Debug + fmt::Display + 'static {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add a Send and Sync bound?

///
unsafe fn drop_and_free(self: *mut Self);
}

struct UnsupportedBacktrace;

impl UnsupportedBacktrace {
#[allow(dead_code)]
const fn create() -> Backtrace {
// don't add members to Self
let _ = Self {};

Backtrace {
inner: ptr::NonNull::<Self>::dangling().as_ptr(),
}
}
}

impl RawBacktrace for UnsupportedBacktrace {
unsafe fn drop_and_free(self: *mut Self) {}
}

impl fmt::Display for UnsupportedBacktrace {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.write_str("unsupported backtrace")
}
}

impl fmt::Debug for UnsupportedBacktrace {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.write_str("<unsupported>")
}
}
struct DisabledBacktrace;

impl DisabledBacktrace {
const fn create() -> Backtrace {
// don't add members to Self
let _ = Self {};

Backtrace {
inner: ptr::NonNull::<Self>::dangling().as_ptr(),
}
}
}

impl RawBacktrace for DisabledBacktrace {
unsafe fn drop_and_free(self: *mut Self) {}
}

impl fmt::Display for DisabledBacktrace {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.write_str("disabled backtrace")
}
}

impl fmt::Debug for DisabledBacktrace {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.write_str("<disabled>")
}
}

#[unstable(feature = "backtrace", issue = "74465")]
///
pub struct Backtrace {
///
inner: *mut dyn RawBacktrace,
}

/// Global implementation of backtrace functionality. Called to create
/// `RawBacktrace` trait objects.
extern "Rust" {
#[lang = "backtrace_create"]
fn backtrace_create(ip: usize) -> *mut dyn RawBacktrace;

#[lang = "backtrace_enabled"]
fn backtrace_enabled() -> bool;

#[lang = "backtrace_status"]
fn backtrace_status(raw: *mut dyn RawBacktrace) -> BacktraceStatus;
}

impl Backtrace {
fn create(ip: usize) -> Backtrace {
let inner = unsafe { backtrace_create(ip) };
Backtrace { inner }
}

/// Returns whether backtrace captures are enabled through environment
/// variables.
fn enabled() -> bool {
unsafe { backtrace_enabled() }
}

/// Capture a stack backtrace of the current thread.
///
/// This function will capture a stack backtrace of the current OS thread of
/// execution, returning a `Backtrace` type which can be later used to print
/// the entire stack trace or render it to a string.
///
/// This function will be a noop if the `RUST_BACKTRACE` or
/// `RUST_LIB_BACKTRACE` backtrace variables are both not set. If either
/// environment variable is set and enabled then this function will actually
/// capture a backtrace. Capturing a backtrace can be both memory intensive
/// and slow, so these environment variables allow liberally using
/// `Backtrace::capture` and only incurring a slowdown when the environment
/// variables are set.
///
/// To forcibly capture a backtrace regardless of environment variables, use
/// the `Backtrace::force_capture` function.
#[inline(never)] // want to make sure there's a frame here to remove
pub fn capture() -> Backtrace {
if !Backtrace::enabled() {
return Backtrace::disabled();
}

Self::create(Backtrace::capture as usize)
}

/// Forcibly captures a full backtrace, regardless of environment variable
/// configuration.
///
/// This function behaves the same as `capture` except that it ignores the
/// values of the `RUST_BACKTRACE` and `RUST_LIB_BACKTRACE` environment
/// variables, always capturing a backtrace.
///
/// Note that capturing a backtrace can be an expensive operation on some
/// platforms, so this should be used with caution in performance-sensitive
/// parts of code.
#[inline(never)] // want to make sure there's a frame here to remove
pub fn force_capture() -> Backtrace {
Self::create(Backtrace::force_capture as usize)
}

/// Forcibly captures a disabled backtrace, regardless of environment
/// variable configuration.
pub const fn disabled() -> Backtrace {
DisabledBacktrace::create()
}

/// Returns the status of this backtrace, indicating whether this backtrace
/// request was unsupported, disabled, or a stack trace was actually
/// captured.
pub fn status(&self) -> BacktraceStatus {
unsafe { backtrace_status(self.inner) }
}
}

#[unstable(feature = "backtrace", issue = "74465")]
unsafe impl Send for Backtrace {}

#[unstable(feature = "backtrace", issue = "74465")]
unsafe impl Sync for Backtrace {}

#[unstable(feature = "backtrace", issue = "74465")]
impl Drop for Backtrace {
fn drop(&mut self) {
unsafe { RawBacktrace::drop_and_free(self.inner) }
}
}

#[unstable(feature = "backtrace", issue = "74465")]
impl fmt::Debug for Backtrace {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
let imp: &dyn RawBacktrace = unsafe { &*self.inner };
fmt::Debug::fmt(imp, fmt)
}
}

#[unstable(feature = "backtrace", issue = "74465")]
impl fmt::Display for Backtrace {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
let imp: &dyn RawBacktrace = unsafe { &*self.inner };
fmt::Display::fmt(imp, fmt)
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: missing trailing newline

2 changes: 2 additions & 0 deletions library/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@
#![feature(fundamental)]
#![feature(intrinsics)]
#![feature(lang_items)]
#![feature(linkage)]
#![feature(link_llvm_intrinsics)]
#![feature(llvm_asm)]
#![feature(negative_impls)]
Expand Down Expand Up @@ -241,6 +242,7 @@ pub mod ops;
pub mod any;
pub mod array;
pub mod ascii;
pub mod backtrace;
pub mod cell;
pub mod char;
pub mod ffi;
Expand Down
Loading