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

Prepare backtrace for Rust 2024 #700

Merged
merged 5 commits into from
Feb 13, 2025
Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ jobs:
with:
submodules: true
- name: Install Rust
run: rustup update 1.79.0 --no-self-update && rustup default 1.79.0
run: rustup update 1.82.0 --no-self-update && rustup default 1.82.0
- run: cargo build

miri:
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ autoexamples = true
autotests = true
edition = "2021"
exclude = ["/ci/"]
rust-version = "1.79.0"
rust-version = "1.82.0"

[workspace]
members = ['crates/cpp_smoke_test', 'crates/as-if-std']
Expand Down
46 changes: 26 additions & 20 deletions src/backtrace/libunwind.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,9 @@ impl Drop for Bomb {

#[inline(always)]
pub unsafe fn trace(mut cb: &mut dyn FnMut(&super::Frame) -> bool) {
uw::_Unwind_Backtrace(trace_fn, addr_of_mut!(cb).cast());
unsafe {
uw::_Unwind_Backtrace(trace_fn, addr_of_mut!(cb).cast());
}

extern "C" fn trace_fn(
ctx: *mut uw::_Unwind_Context,
Expand Down Expand Up @@ -168,7 +170,7 @@ mod uw {
pub type _Unwind_Trace_Fn =
extern "C" fn(ctx: *mut _Unwind_Context, arg: *mut c_void) -> _Unwind_Reason_Code;

extern "C" {
unsafe extern "C" {
pub fn _Unwind_Backtrace(
trace: _Unwind_Trace_Fn,
trace_argument: *mut c_void,
Expand All @@ -186,7 +188,7 @@ mod uw {
not(all(target_os = "vita", target_arch = "arm")),
not(all(target_os = "nuttx", target_arch = "arm")),
))] {
extern "C" {
unsafe extern "C" {
pub fn _Unwind_GetIP(ctx: *mut _Unwind_Context) -> libc::uintptr_t;
pub fn _Unwind_FindEnclosingFunction(pc: *mut c_void) -> *mut c_void;

Expand All @@ -206,10 +208,10 @@ mod uw {
// instead of relying on _Unwind_GetCFA.
#[cfg(all(target_os = "linux", target_arch = "s390x"))]
pub unsafe fn get_sp(ctx: *mut _Unwind_Context) -> libc::uintptr_t {
extern "C" {
unsafe extern "C" {
pub fn _Unwind_GetGR(ctx: *mut _Unwind_Context, index: libc::c_int) -> libc::uintptr_t;
}
_Unwind_GetGR(ctx, 15)
unsafe { _Unwind_GetGR(ctx, 15) }
}
} else {
use core::ptr::addr_of_mut;
Expand Down Expand Up @@ -246,7 +248,7 @@ mod uw {
}

type _Unwind_Word = libc::c_uint;
extern "C" {
unsafe extern "C" {
fn _Unwind_VRS_Get(
ctx: *mut _Unwind_Context,
klass: _Unwind_VRS_RegClass,
Expand All @@ -259,13 +261,15 @@ mod uw {
pub unsafe fn _Unwind_GetIP(ctx: *mut _Unwind_Context) -> libc::uintptr_t {
let mut val: _Unwind_Word = 0;
let ptr = addr_of_mut!(val);
let _ = _Unwind_VRS_Get(
ctx,
_Unwind_VRS_RegClass::_UVRSC_CORE,
15,
_Unwind_VRS_DataRepresentation::_UVRSD_UINT32,
ptr.cast::<c_void>(),
);
unsafe {
let _ = _Unwind_VRS_Get(
ctx,
_Unwind_VRS_RegClass::_UVRSC_CORE,
15,
_Unwind_VRS_DataRepresentation::_UVRSD_UINT32,
ptr.cast::<c_void>(),
);
}
(val & !1) as libc::uintptr_t
}

Expand All @@ -275,13 +279,15 @@ mod uw {
pub unsafe fn get_sp(ctx: *mut _Unwind_Context) -> libc::uintptr_t {
let mut val: _Unwind_Word = 0;
let ptr = addr_of_mut!(val);
let _ = _Unwind_VRS_Get(
ctx,
_Unwind_VRS_RegClass::_UVRSC_CORE,
SP,
_Unwind_VRS_DataRepresentation::_UVRSD_UINT32,
ptr.cast::<c_void>(),
);
unsafe {
let _ = _Unwind_VRS_Get(
ctx,
_Unwind_VRS_RegClass::_UVRSC_CORE,
SP,
_Unwind_VRS_DataRepresentation::_UVRSD_UINT32,
ptr.cast::<c_void>(),
);
}
val as libc::uintptr_t
}

Expand Down
15 changes: 10 additions & 5 deletions src/backtrace/miri.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use alloc::boxed::Box;
use alloc::vec::Vec;
use core::ffi::c_void;

extern "Rust" {
unsafe extern "Rust" {
fn miri_backtrace_size(flags: u64) -> usize;
fn miri_get_backtrace(flags: u64, buf: *mut *mut ());
fn miri_resolve_frame(ptr: *mut (), flags: u64) -> MiriFrame;
Expand Down Expand Up @@ -56,7 +56,10 @@ impl Frame {
}
}

pub fn trace<F: FnMut(&super::Frame) -> bool>(cb: F) {
// SAFETY: This function is safe to call. It is only marked as `unsafe` to
// avoid having to allow `unused_unsafe` since other implementations are
// unsafe.
pub unsafe fn trace<F: FnMut(&super::Frame) -> bool>(cb: F) {
// SAFETY: Miri guarantees that the backtrace API functions
// can be called from any thread.
unsafe { trace_unsynchronized(cb) };
Expand Down Expand Up @@ -97,13 +100,15 @@ pub fn resolve_addr(ptr: *mut c_void) -> Frame {
}

unsafe fn trace_unsynchronized<F: FnMut(&super::Frame) -> bool>(mut cb: F) {
let len = miri_backtrace_size(0);
let len = unsafe { miri_backtrace_size(0) };

let mut frames = Vec::with_capacity(len);

miri_get_backtrace(1, frames.as_mut_ptr());
unsafe {
miri_get_backtrace(1, frames.as_mut_ptr());

frames.set_len(len);
frames.set_len(len);
}

for ptr in frames.iter() {
let frame = resolve_addr((*ptr).cast::<c_void>());
Expand Down
2 changes: 1 addition & 1 deletion src/backtrace/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ pub fn trace<F: FnMut(&Frame) -> bool>(cb: F) {
///
/// See information on `trace` for caveats on `cb` panicking.
pub unsafe fn trace_unsynchronized<F: FnMut(&Frame) -> bool>(mut cb: F) {
trace_imp(&mut cb)
unsafe { trace_imp(&mut cb) }
}

/// A trait representing one frame of a backtrace, yielded to the `trace`
Expand Down
5 changes: 4 additions & 1 deletion src/backtrace/noop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@
use core::ffi::c_void;
use core::ptr::null_mut;

// SAFETY: This function is safe to call. It is only marked as `unsafe` to
// avoid having to allow `unused_unsafe` since other implementations are
// unsafe.
#[inline(always)]
pub fn trace(_cb: &mut dyn FnMut(&super::Frame) -> bool) {}
pub unsafe fn trace(_cb: &mut dyn FnMut(&super::Frame) -> bool) {}

#[derive(Clone)]
pub struct Frame;
Expand Down
29 changes: 16 additions & 13 deletions src/backtrace/win64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,9 @@ pub unsafe fn trace(cb: &mut dyn FnMut(&super::Frame) -> bool) {
use core::ptr;

// Capture the initial context to start walking from.
let mut context = core::mem::zeroed::<MyContext>();
RtlCaptureContext(&mut context.0);
// FIXME: shouldn't this have a Default impl?
let mut context = unsafe { core::mem::zeroed::<MyContext>() };
unsafe { RtlCaptureContext(&mut context.0) };

loop {
let ip = context.ip();
Expand All @@ -93,7 +94,7 @@ pub unsafe fn trace(cb: &mut dyn FnMut(&super::Frame) -> bool) {
// us to backtrace through JIT frames.
// Note that `RtlLookupFunctionEntry` only works for in-process backtraces,
// but that's all we support anyway, so it all lines up well.
let fn_entry = RtlLookupFunctionEntry(ip, &mut base, ptr::null_mut());
let fn_entry = unsafe { RtlLookupFunctionEntry(ip, &mut base, ptr::null_mut()) };
if fn_entry.is_null() {
// No function entry could be found - this may indicate a corrupt
// stack or that a binary was unloaded (amongst other issues). Stop
Expand Down Expand Up @@ -124,16 +125,18 @@ pub unsafe fn trace(cb: &mut dyn FnMut(&super::Frame) -> bool) {
let previous_sp = context.sp();
let mut handler_data = 0usize;
let mut establisher_frame = 0;
RtlVirtualUnwind(
0,
base,
ip,
fn_entry,
&mut context.0,
ptr::addr_of_mut!(handler_data).cast::<*mut c_void>(),
&mut establisher_frame,
ptr::null_mut(),
);
unsafe {
RtlVirtualUnwind(
0,
base,
ip,
fn_entry,
&mut context.0,
ptr::addr_of_mut!(handler_data).cast::<*mut c_void>(),
&mut establisher_frame,
ptr::null_mut(),
);
}

// RtlVirtualUnwind indicates the end of the stack in two different ways:
// * On x64, it sets the instruction pointer to 0.
Expand Down
4 changes: 2 additions & 2 deletions src/print/fuchsia.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use core::mem::{size_of, transmute};
use core::slice::from_raw_parts;
use libc::c_char;

extern "C" {
unsafe extern "C" {
// dl_iterate_phdr takes a callback that will receive a dl_phdr_info pointer
// for every DSO that has been linked into the process. dl_iterate_phdr also
// ensures that the dynamic linker is locked from start to finish of the
Expand Down Expand Up @@ -148,7 +148,7 @@ impl<'a> NoteIter<'a> {
// can be anything but the range must be valid for this to be safe.
unsafe fn new(base: *const u8, size: usize) -> Self {
NoteIter {
base: from_raw_parts(base, size),
base: unsafe { from_raw_parts(base, size) },
error: false,
}
}
Expand Down
Loading