Skip to content

Add experimental backtrace-trace-only std feature #143910

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

Merged
merged 1 commit into from
Jul 15, 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
3 changes: 3 additions & 0 deletions library/std/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,9 @@ backtrace = [
'object/rustc-dep-of-std',
'miniz_oxide/rustc-dep-of-std',
]
# Disable symbolization in backtraces. For use with -Zbuild-std.
# FIXME: Ideally this should be an additive backtrace-symbolization feature
backtrace-trace-only = []
Copy link
Member

@bjorn3 bjorn3 Jul 14, 2025

Choose a reason for hiding this comment

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

This will still compile addr2line, gimli and object. Maybe instead have a feature to enable just backtraces and then another feature which enables this feature and in addition enables backtrace symbolication.
Edit: You already suggested that in the PR description.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, doing this fully will require making changes to backtrace-rs, which I'm trying to avoid for the initial implementation. Also, although it's unstable, I don't want to break people currently using build-std-features just yet.


panic-unwind = ["dep:panic_unwind"]
compiler-builtins-c = ["alloc/compiler-builtins-c"]
Expand Down
100 changes: 53 additions & 47 deletions library/std/src/sys/backtrace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,61 +68,67 @@ unsafe fn _print_fmt(fmt: &mut fmt::Formatter<'_>, print_fmt: PrintFmt) -> fmt::
return false;
}

let mut hit = false;
backtrace_rs::resolve_frame_unsynchronized(frame, |symbol| {
hit = true;

// `__rust_end_short_backtrace` means we are done hiding symbols
// for now. Print until we see `__rust_begin_short_backtrace`.
if print_fmt == PrintFmt::Short {
if let Some(sym) = symbol.name().and_then(|s| s.as_str()) {
if sym.contains("__rust_end_short_backtrace") {
print = true;
return;
}
if print && sym.contains("__rust_begin_short_backtrace") {
print = false;
return;
}
if !print {
omitted_count += 1;
if cfg!(feature = "backtrace-trace-only") {
const HEX_WIDTH: usize = 2 + 2 * size_of::<usize>();
let frame_ip = frame.ip();
res = writeln!(bt_fmt.formatter(), "{idx:4}: {frame_ip:HEX_WIDTH$?}");
Copy link
Member

Choose a reason for hiding this comment

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

To be able to actually symbolize the backtraces this would need to print both the path of the DSO (executable or dylib) and the offset within this DSO. It could be a dylib loaded at runtime and thanks to ASLR the exact location of DSOs can't be determined anymore after the fact unless we print it here.

Copy link
Member

Choose a reason for hiding this comment

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

This could take inspiration on what backtrace-rs does on Fuchsia which unconditionally does backtrace symbolication out of process.

Copy link
Member Author

Choose a reason for hiding this comment

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

How does this work normally when symbols aren't available? The backtrace is just unusable?

Copy link
Member

Choose a reason for hiding this comment

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

Yeah, I don't think the backtraces are all that usable without symbols when ASLR is disabled. I guess it still shows symbol names for system libraries.

Copy link
Member Author

Choose a reason for hiding this comment

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

Ok, I'm going to punt on doing the hard thing again 🙂. This is (arguably) a pre-existing issue and at least somewhat platform specific so would be much better fixed in backtrace-rs than std. This feature can then use whatever backtrace-rs has once that's written.

} else {
let mut hit = false;
backtrace_rs::resolve_frame_unsynchronized(frame, |symbol| {
hit = true;

// `__rust_end_short_backtrace` means we are done hiding symbols
// for now. Print until we see `__rust_begin_short_backtrace`.
if print_fmt == PrintFmt::Short {
if let Some(sym) = symbol.name().and_then(|s| s.as_str()) {
if sym.contains("__rust_end_short_backtrace") {
print = true;
return;
}
if print && sym.contains("__rust_begin_short_backtrace") {
print = false;
return;
}
if !print {
omitted_count += 1;
}
}
}
}

if print {
if omitted_count > 0 {
debug_assert!(print_fmt == PrintFmt::Short);
// only print the message between the middle of frames
if !first_omit {
let _ = writeln!(
bt_fmt.formatter(),
" [... omitted {} frame{} ...]",
omitted_count,
if omitted_count > 1 { "s" } else { "" }
);
if print {
if omitted_count > 0 {
debug_assert!(print_fmt == PrintFmt::Short);
// only print the message between the middle of frames
if !first_omit {
let _ = writeln!(
bt_fmt.formatter(),
" [... omitted {} frame{} ...]",
omitted_count,
if omitted_count > 1 { "s" } else { "" }
);
}
first_omit = false;
omitted_count = 0;
}
first_omit = false;
omitted_count = 0;
res = bt_fmt.frame().symbol(frame, symbol);
}
res = bt_fmt.frame().symbol(frame, symbol);
});
#[cfg(target_os = "nto")]
if libc::__my_thread_exit as *mut libc::c_void == frame.ip() {
if !hit && print {
use crate::backtrace_rs::SymbolName;
res = bt_fmt.frame().print_raw(
frame.ip(),
Some(SymbolName::new("__my_thread_exit".as_bytes())),
None,
None,
);
}
return false;
}
});
#[cfg(target_os = "nto")]
if libc::__my_thread_exit as *mut libc::c_void == frame.ip() {
if !hit && print {
use crate::backtrace_rs::SymbolName;
res = bt_fmt.frame().print_raw(
frame.ip(),
Some(SymbolName::new("__my_thread_exit".as_bytes())),
None,
None,
);
res = bt_fmt.frame().print_raw(frame.ip(), None, None, None);
}
return false;
}
if !hit && print {
res = bt_fmt.frame().print_raw(frame.ip(), None, None, None);
}

idx += 1;
Expand Down
1 change: 1 addition & 0 deletions library/sysroot/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ test = { path = "../test", public = true }
[features]
default = ["std_detect_file_io", "std_detect_dlsym_getauxval", "panic-unwind"]
backtrace = ["std/backtrace"]
backtrace-trace-only = ["std/backtrace-trace-only"]
compiler-builtins-c = ["std/compiler-builtins-c"]
compiler-builtins-mem = ["std/compiler-builtins-mem"]
compiler-builtins-no-asm = ["std/compiler-builtins-no-asm"]
Expand Down
Loading