-
Notifications
You must be signed in to change notification settings - Fork 69
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
Use debuginfo for short backtrace printing #818
Comments
This issue is not meant to be used for technical discussion. There is a Zulip stream for that. Use this issue to leave procedural comments, such as volunteering to review, indicating that you second the proposal (or third, etc), or raising a concern that you would like to be addressed. Concerns or objections to the proposal should be discussed on Zulip and formally registered here by adding a comment with the following syntax:
Concerns can be lifted with:
See documentation at https://forge.rust-lang.org cc @rust-lang/compiler |
@rustbot second |
[experimental] shorten backtraces using debuginfo cc rust-lang/compiler-team#818 r? `@ghost` `@rustbot` label S-experimental try-job: aarch64-apple
[experimental] shorten backtraces using debuginfo cc rust-lang/compiler-team#818 r? `@ghost` `@rustbot` label S-experimental try-job: aarch64-apple
[experimental] shorten backtraces using debuginfo cc rust-lang/compiler-team#818 r? `@ghost` `@rustbot` label S-experimental try-job: aarch64-apple
@rustbot label -final-comment-period +major-change-accepted |
…odes The Rust standard library has two [styles](https://doc.rust-lang.org/stable/std/panic/enum.BacktraceStyle.html) for printing backtraces at runtime: 1. Full backtraces. These work in the obvious way. 2. Short backtraces. These filter out "unimportant" frames that are likely not related to the developer's bug. For example, frames like `__libc_start_main`, `_Unwind_Resume`, and rust runtime internals like `std::rt::lang_start` are filtered out. Currently, the Rust runtime determines "unimportant" frames by looking directly at un-mangled symbol names of generated functions. This is not extensible, and involves a state machine that requires the frames to be present at runtime; in particular the frames must be marked `noinline`, impeding optimizations. This extends LLVM to encode short backtrace metadata in DWARF debuginfo. It currently does not attempt to add debuginfo to PDB, which was not designed to be extensible. See rust-lang/compiler-team#818 for more background. - Add a new category for Rust DWARF vendor extensions - Add a new `enum ShortBacktraceAttr { SkipFrame, StartFrame, EndFrame }`. StartFrame and EndFrame correspond to the existing `__rust_start_short_backtrace` and `__rust_end_short_backtrace` symbols. SkipFrame currently has no analogue. Each of these values is mutually exclusive with the others, and generating multiple for the same function is a logical error. - Update all callsites of `DISubprogram::getImpl` to pass in a `std::optional<ShortBacktraceAttr>` - Emit `ShortBacktraceAttr` when creating DWARF debuginfo. Note that this also generates debuginfo in more cases than before: When using line-tables-only debuginfo, LLVM attempts to skip functions with 0 lexical scopes. But some shims in the Rust standard library, such as `std::ops::Fn::call`, are shims that never appear in Rust source code but still appear in the backtrace. Generate info for these functions if they have a short backtrace attribute, so that they are correctly skipped in backtraces. - Parse and serialize the new attribute in .ll files - Add a regression test
…odes The Rust standard library has two [styles](https://doc.rust-lang.org/stable/std/panic/enum.BacktraceStyle.html) for printing backtraces at runtime: 1. Full backtraces. These work in the obvious way. 2. Short backtraces. These filter out "unimportant" frames that are likely not related to the developer's bug. For example, frames like `__libc_start_main`, `_Unwind_Resume`, and rust runtime internals like `std::rt::lang_start` are filtered out. Currently, the Rust runtime determines "unimportant" frames by looking directly at un-mangled symbol names of generated functions. This is not extensible, and involves a state machine that requires the frames to be present at runtime; in particular the frames must be marked `noinline`, impeding optimizations. This extends LLVM to encode short backtrace metadata in DWARF debuginfo. It currently does not attempt to add debuginfo to PDB, which was not designed to be extensible. See rust-lang/compiler-team#818 for more background. - Add a new category for Rust DWARF vendor extensions - Add a new `enum ShortBacktraceAttr { SkipFrame, StartFrame, EndFrame }`. StartFrame and EndFrame correspond to the existing `__rust_start_short_backtrace` and `__rust_end_short_backtrace` symbols. SkipFrame currently has no analogue. Each of these values is mutually exclusive with the others, and generating multiple for the same function is a logical error. - Update all callsites of `DISubprogram::getImpl` to pass in a `std::optional<ShortBacktraceAttr>` - Emit `ShortBacktraceAttr` when creating DWARF debuginfo. Note that this also generates debuginfo in more cases than before: When using line-tables-only debuginfo, LLVM attempts to skip functions with 0 lexical scopes. But some shims in the Rust standard library, such as `std::ops::Fn::call`, are shims that never appear in Rust source code but still appear in the backtrace. Generate info for these functions if they have a short backtrace attribute, so that they are correctly skipped in backtraces. - Parse and serialize the new attribute in .ll files - Add a regression test
…odes The Rust standard library has two [styles](https://doc.rust-lang.org/stable/std/panic/enum.BacktraceStyle.html) for printing backtraces at runtime: 1. Full backtraces. These work in the obvious way. 2. Short backtraces. These filter out "unimportant" frames that are likely not related to the developer's bug. For example, frames like `__libc_start_main`, `_Unwind_Resume`, and rust runtime internals like `std::rt::lang_start` are filtered out. Currently, the Rust runtime determines "unimportant" frames by looking directly at un-mangled symbol names of generated functions. This is not extensible, and involves a state machine that requires the frames to be present at runtime; in particular the frames must be marked `noinline`, impeding optimizations. This extends LLVM to encode short backtrace metadata in DWARF debuginfo. It currently does not attempt to add debuginfo to PDB, which was not designed to be extensible. See rust-lang/compiler-team#818 for more background. - Add a new category for Rust DWARF vendor extensions - Add a new `enum ShortBacktraceAttr { SkipFrame, StartFrame, EndFrame }`. StartFrame and EndFrame correspond to the existing `__rust_start_short_backtrace` and `__rust_end_short_backtrace` symbols. SkipFrame currently has no analogue. Each of these values is mutually exclusive with the others, and generating multiple for the same function is a logical error. - Update all callsites of `DISubprogram::getImpl` to pass in a `std::optional<ShortBacktraceAttr>` - Emit `ShortBacktraceAttr` when creating DWARF debuginfo. Note that this also generates debuginfo in more cases than before: When using line-tables-only debuginfo, LLVM attempts to skip functions with 0 lexical scopes. But some shims in the Rust standard library, such as `std::ops::Fn::call`, are shims that never appear in Rust source code but still appear in the backtrace. Generate info for these functions if they have a short backtrace attribute, so that they are correctly skipped in backtraces. - Parse and serialize the new attribute in .ll files - Add a regression test
…odes The Rust standard library has two [styles](https://doc.rust-lang.org/stable/std/panic/enum.BacktraceStyle.html) for printing backtraces at runtime: 1. Full backtraces. These work in the obvious way. 2. Short backtraces. These filter out "unimportant" frames that are likely not related to the developer's bug. For example, frames like `__libc_start_main`, `_Unwind_Resume`, and rust runtime internals like `std::rt::lang_start` are filtered out. Currently, the Rust runtime determines "unimportant" frames by looking directly at un-mangled symbol names of generated functions. This is not extensible, and involves a state machine that requires the frames to be present at runtime; in particular the frames must be marked `noinline`, impeding optimizations. This extends LLVM to encode short backtrace metadata in DWARF debuginfo. It currently does not attempt to add debuginfo to PDB, which was not designed to be extensible. See rust-lang/compiler-team#818 for more background. - Add a new category for Rust DWARF vendor extensions - Add a new `enum ShortBacktraceAttr { SkipFrame, StartFrame, EndFrame }`. StartFrame and EndFrame correspond to the existing `__rust_start_short_backtrace` and `__rust_end_short_backtrace` symbols. SkipFrame currently has no analogue. Each of these values is mutually exclusive with the others, and generating multiple for the same function is a logical error. - Update all callsites of `DISubprogram::getImpl` to pass in a `std::optional<ShortBacktraceAttr>` - Emit `ShortBacktraceAttr` when creating DWARF debuginfo. Note that this also generates debuginfo in more cases than before: When using line-tables-only debuginfo, LLVM attempts to skip functions with 0 lexical scopes. But some shims in the Rust standard library, such as `std::ops::Fn::call`, are shims that never appear in Rust source code but still appear in the backtrace. Generate info for these functions if they have a short backtrace attribute, so that they are correctly skipped in backtraces. - Parse and serialize the new attribute in .ll files - Add a regression test
This implements the runtime side of rust-lang/compiler-team#818. - Extract a helper out of `find_frames` for iterating over a `LookupContinuation` - Make the type signature for `search_object_map` consistent across all platforms. Backtraces are inherently platform specific, but let's not make it any harder on ourselves than we have to. - Add a new `pub fn short_backtraces() -> enum { ThisFrameOnly, Start, End }` API - Use the new [`gimli::UnitRef::shared_attrs`](gimli-rs/gimli#756) API to determine whether a given frame has a short backtrace. This, for now, requires a git dependency on gimli.
This implements the runtime side of rust-lang/compiler-team#818. - Extract a helper out of `find_frames` for iterating over a `LookupContinuation` - Make the type signature for `search_object_map` consistent across all platforms. Backtraces are inherently platform specific, but let's not make it any harder on ourselves than we have to. - Add a new `pub fn short_backtraces() -> enum { ThisFrameOnly, Start, End }` API - Use the new [`gimli::UnitRef::shared_attrs`](gimli-rs/gimli#756) API to determine whether a given frame has a short backtrace. This, for now, requires a git dependency on gimli. Note that this currently does not work on MacOS. I do not have a Mac to test this; someone lent me theirs and I tracked it down to `cx.find_dwarf_and_unit` returning `None`, but I have not had the time or resources to narrow it down further than that.
This implements the runtime side of rust-lang/compiler-team#818. - Extract a helper out of `find_frames` for iterating over a `LookupContinuation` - Make the type signature for `search_object_map` consistent across all platforms. Backtraces are inherently platform specific, but let's not make it any harder on ourselves than we have to. - Add a new `pub fn short_backtraces() -> enum { ThisFrameOnly, Start, End }` API - Use the new [`gimli::UnitRef::shared_attrs`](gimli-rs/gimli#756) API to determine whether a given frame has a short backtrace. This, for now, requires a git dependency on gimli. Note that this currently does not work on MacOS. I do not have a Mac to test this; someone lent me theirs and I tracked it down to `cx.find_dwarf_and_unit` returning `None`, but I have not had the time or resources to narrow it down further than that.
…odes The Rust standard library has two [styles](https://doc.rust-lang.org/stable/std/panic/enum.BacktraceStyle.html) for printing backtraces at runtime: 1. Full backtraces. These work in the obvious way. 2. Short backtraces. These filter out "unimportant" frames that are likely not related to the developer's bug. For example, frames like `__libc_start_main`, `_Unwind_Resume`, and rust runtime internals like `std::rt::lang_start` are filtered out. Currently, the Rust runtime determines "unimportant" frames by looking directly at un-mangled symbol names of generated functions. This is not extensible, and involves a state machine that requires the frames to be present at runtime; in particular the frames must be marked `noinline`, impeding optimizations. This extends LLVM to encode short backtrace metadata in DWARF debuginfo. It currently does not attempt to add debuginfo to PDB, which was not designed to be extensible. See rust-lang/compiler-team#818 for more background. - Add a new category for Rust DWARF vendor extensions - Add a new `enum ShortBacktraceAttr { SkipFrame, StartFrame, EndFrame }`. StartFrame and EndFrame correspond to the existing `__rust_start_short_backtrace` and `__rust_end_short_backtrace` symbols. SkipFrame currently has no analogue. Each of these values is mutually exclusive with the others, and generating multiple for the same function is a logical error. - Update all callsites of `DISubprogram::getImpl` to pass in a `std::optional<ShortBacktraceAttr>` - Emit `ShortBacktraceAttr` when creating DWARF debuginfo. Note that this also generates debuginfo in more cases than before: When using line-tables-only debuginfo, LLVM attempts to skip functions with 0 lexical scopes. But some shims in the Rust standard library, such as `std::ops::Fn::call`, are shims that never appear in Rust source code but still appear in the backtrace. Generate info for these functions if they have a short backtrace attribute, so that they are correctly skipped in backtraces. - Parse and serialize the new attribute in .ll files - Add a regression test
…odes The Rust standard library has two [styles](https://doc.rust-lang.org/stable/std/panic/enum.BacktraceStyle.html) for printing backtraces at runtime: 1. Full backtraces. These work in the obvious way. 2. Short backtraces. These filter out "unimportant" frames that are likely not related to the developer's bug. For example, frames like `__libc_start_main`, `_Unwind_Resume`, and rust runtime internals like `std::rt::lang_start` are filtered out. Currently, the Rust runtime determines "unimportant" frames by looking directly at un-mangled symbol names of generated functions. This is not extensible, and involves a state machine that requires the frames to be present at runtime; in particular the frames must be marked `noinline`, impeding optimizations. This extends LLVM to encode short backtrace metadata in DWARF debuginfo. It currently does not attempt to add debuginfo to PDB, which was not designed to be extensible. See rust-lang/compiler-team#818 for more background. - Add a new category for Rust DWARF vendor extensions - Add a new `enum ShortBacktraceAttr { SkipFrame, StartFrame, EndFrame }`. StartFrame and EndFrame correspond to the existing `__rust_start_short_backtrace` and `__rust_end_short_backtrace` symbols. SkipFrame currently has no analogue. Each of these values is mutually exclusive with the others, and generating multiple for the same function is a logical error. - Update all callsites of `DISubprogram::getImpl` to pass in a `std::optional<ShortBacktraceAttr>` - Emit `ShortBacktraceAttr` when creating DWARF debuginfo. Note that this also generates debuginfo in more cases than before: When using line-tables-only debuginfo, LLVM attempts to skip functions with 0 lexical scopes. But some shims in the Rust standard library, such as `std::ops::Fn::call`, are shims that never appear in Rust source code but still appear in the backtrace. Generate info for these functions if they have a short backtrace attribute, so that they are correctly skipped in backtraces. - Parse and serialize the new attribute in .ll files - Add a regression test
…odes The Rust standard library has two [styles](https://doc.rust-lang.org/stable/std/panic/enum.BacktraceStyle.html) for printing backtraces at runtime: 1. Full backtraces. These work in the obvious way. 2. Short backtraces. These filter out "unimportant" frames that are likely not related to the developer's bug. For example, frames like `__libc_start_main`, `_Unwind_Resume`, and rust runtime internals like `std::rt::lang_start` are filtered out. Currently, the Rust runtime determines "unimportant" frames by looking directly at un-mangled symbol names of generated functions. This is not extensible, and involves a state machine that requires the frames to be present at runtime; in particular the frames must be marked `noinline`, impeding optimizations. This extends LLVM to encode short backtrace metadata in DWARF debuginfo. It currently does not attempt to add debuginfo to PDB, which was not designed to be extensible. Other languages are allowed and encouraged to use this new debuginfo for their backtraces. The Rust runtime does not distinguish between producers of the debuginfo; any function with this debuginfo will be respected when printing backtraces. I hope in the future to extend `llvm-symbolizer` to have a short backtrace printing mode. See rust-lang/compiler-team#818 for more background. - Add a new `enum ShortBacktraceAttr { SkipFrame, StartFrame, EndFrame }`. StartFrame and EndFrame correspond to the existing `__rust_start_short_backtrace` and `__rust_end_short_backtrace` symbols. SkipFrame currently has no analogue. Each of these values is mutually exclusive with the others, and generating multiple for the same function is a logical error. - Update all callsites of `DISubprogram::getImpl` to pass in a `std::optional<ShortBacktraceAttr>` - Emit `ShortBacktraceAttr` when creating DWARF debuginfo. Note that this also generates debuginfo in more cases than before: When using line-tables-only debuginfo, LLVM attempts to skip functions with 0 lexical scopes. But some shims in the Rust standard library, such as `std::ops::Fn::call`, are shims that never appear in Rust source code but still appear in the backtrace. Generate info for these functions if they have a short backtrace attribute, so that they are correctly skipped in backtraces. - Parse and serialize the new attribute in .ll files - Add a regression test
Proposal
The problem
This MCP is intended to solve rust-lang/rust#124586 in an extensible way.
Currently, short backtrace printing (the part of the default panic handler in std that hides frames like
lang_start
andstd::panicking
) works like this:__rust_{start,end}_short_backtrace
which are marked withinline(never)
.start
frame is encountered.This has two drawbacks:
inline(never)
, they form an optimization barrier, because most of LLVM's optimizations are hamstrung when they can't do inlining.both of these make me reluctant to add more start/end function pairs, because it will hurt performance for everyone using rust and also it's hard to be sure that the panic state machine is working as expected.
Note these drawbacks only to new
__rust_{start,end}
frames. in std itself we only call these functions once, so we don't care about performance, and we are reasonably confident the existing state machine is correct for those two frames.My proposed solution
#[rustc_{start,end}_short_backtrace]
attributes. Use them everywhere except the two existing functions.rustc_{start,end}_backtrace
pairs with debuginfo instead of frames. In other words, any callgraph that goes A -> start_short_backtrace -> B will now go directly A -> B, and B will be annotated with debuginfo marking it appropriately.Additionally, expose a new
#[rustc_skip_short_backtrace]
attribute. When applied to a function, this generates debuginfo that says to skip that frame only, but not to change the state of the panic handler state machine. When applied to a module, this generates debuginfo that says to skip any function defined in that module (e.g. DWARF will useDW_TAG_namespace
).Note that this allows other languages besides Rust to read and write functions marked as skippable, as long as their compiler understands the format we use for the debuginfo.
Drawbacks
Alternatives
__rust_start_short_backtrace
altogether and only use the new attributes. This will regress anyone who was using those frames outside std. It also will break if debuginfo is disabled.#[rustc_skip_short_backtrace]
attribute is represented with debuginfo; start/end attributes are still represented asinline(never)
frames. This avoids missing start/end frames when debuginfo is disabled, but has a slight performance hit anywhere a start/end pair appears.#[rustc_skip_short_backtrace]
to a static injected intostd
that contains a slice of function names (or addresses). Continue using frames for start/end pairs. This is platform independent, but prevents the new attribute from being used anywhere outside std(/alloc/core). Has a small performance hit for start/end pairs. Does not allow other languages to mark frames as skippable, or to read the list of skippable frames.#[global_allocator]
works today.Future work
Mentors or Reviewers
@bjorn3, @saethlin
cc @rust-lang/libs
Process
The main points of the Major Change Process are as follows:
@rustbot second
.-C flag
, then full team check-off is required.@rfcbot fcp merge
on either the MCP or the PR.You can read more about Major Change Proposals on forge.
Comments
This issue is not meant to be used for technical discussion. There is a Zulip stream for that. Use this issue to leave procedural comments, such as volunteering to review, indicating that you second the proposal (or third, etc), or raising a concern that you would like to be addressed.
The text was updated successfully, but these errors were encountered: