aboutsummaryrefslogtreecommitdiff
path: root/vendor/backtrace-ext/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/backtrace-ext/src/lib.rs')
-rw-r--r--vendor/backtrace-ext/src/lib.rs277
1 files changed, 0 insertions, 277 deletions
diff --git a/vendor/backtrace-ext/src/lib.rs b/vendor/backtrace-ext/src/lib.rs
deleted file mode 100644
index b04c59d..0000000
--- a/vendor/backtrace-ext/src/lib.rs
+++ /dev/null
@@ -1,277 +0,0 @@
-//! Minor conveniences on top of the backtrace crate
-//!
-//! See [`short_frames_strict`][] for details.
-use backtrace::*;
-use std::ops::Range;
-
-#[cfg(test)]
-mod test;
-
-/// Gets an iterator over the frames that are part of Rust's "short backtrace" range.
-/// If no such range is found, the full stack is yielded.
-///
-/// Rust generally tries to include special frames on the stack called `rust_end_short_backtrace`
-/// and `rust_begin_short_backtrace` which delimit the "real" stackframes from "gunk" stackframes
-/// like setting up main and invoking the panic runtime. This yields all the "real" frames between
-/// those two (which theoretically can be nothing with enough optimization, although that's unlikely
-/// for any non-trivial program).
-///
-/// If only one of the special frames is present we will only clamp one side of the stack
-/// (similar to `a..` or `..a`). If the special frames are in the wrong order we will discard
-/// them and produce the full stack. If multiple versions of a special frame are found
-/// (I've seen it in the wild), we will pick the "innermost" ones, producing the smallest
-/// possible backtrace (and excluding all special frames from the output).
-///
-/// Each element of the iterator includes a Range which you should use to slice
-/// the frame's `symbols()` array. This handles the theoretical situation where "real" frames
-/// got inlined together with the special marker frames. I want to believe this can't happen
-/// but you can never trust backtraces to be reasonable! We will never yield a Frame to you
-/// with an empty Range.
-///
-/// Note that some "gunk" frames may still be found within the short backtrace, as there is still some
-/// platform-specific and optimization-specific glue around the edges because compilers are
-/// complicated and nothing's perfect. This can include:
-///
-/// * `core::ops::function::FnOnce::call_once`
-/// * `std::panicking::begin_panic_handler`
-/// * `core::panicking::panic_fmt`
-/// * `rust_begin_unwind`
-///
-/// In the future we may introduce a non-strict short_frames which heuristically filters
-/// those frames out too. Until then, the strict approach is safe.
-///
-/// # Example
-///
-/// Here's an example simple "short backtrace" implementation.
-/// Note the use of `sub_frames` for the inner loop to restrict `symbols`!
-///
-/// This example is based off of code found in `miette` (Apache-2.0), which itself
-/// copied the logic from `human-panic` (MIT/Apache-2.0).
-///
-/// FIXME: it would be nice if this example consulted `RUST_BACKTRACE=full`,
-/// and maybe other vars used by rust's builtin panic handler..?
-///
-/// ```
-/// fn backtrace() -> String {
-/// use std::fmt::Write;
-/// if let Ok(var) = std::env::var("RUST_BACKTRACE") {
-/// if !var.is_empty() && var != "0" {
-/// const HEX_WIDTH: usize = std::mem::size_of::<usize>() + 2;
-/// // Padding for next lines after frame's address
-/// const NEXT_SYMBOL_PADDING: usize = HEX_WIDTH + 6;
-/// let mut backtrace = String::new();
-/// let trace = backtrace::Backtrace::new();
-/// let frames = backtrace_ext::short_frames_strict(&trace).enumerate();
-/// for (idx, (frame, subframes)) in frames {
-/// let ip = frame.ip();
-/// let _ = write!(backtrace, "\n{:4}: {:2$?}", idx, ip, HEX_WIDTH);
-///
-/// let symbols = frame.symbols();
-/// if symbols.is_empty() {
-/// let _ = write!(backtrace, " - <unresolved>");
-/// continue;
-/// }
-///
-/// for (idx, symbol) in symbols[subframes].iter().enumerate() {
-/// // Print symbols from this address,
-/// // if there are several addresses
-/// // we need to put it on next line
-/// if idx != 0 {
-/// let _ = write!(backtrace, "\n{:1$}", "", NEXT_SYMBOL_PADDING);
-/// }
-///
-/// if let Some(name) = symbol.name() {
-/// let _ = write!(backtrace, " - {}", name);
-/// } else {
-/// let _ = write!(backtrace, " - <unknown>");
-/// }
-///
-/// // See if there is debug information with file name and line
-/// if let (Some(file), Some(line)) = (symbol.filename(), symbol.lineno()) {
-/// let _ = write!(
-/// backtrace,
-/// "\n{:3$}at {}:{}",
-/// "",
-/// file.display(),
-/// line,
-/// NEXT_SYMBOL_PADDING
-/// );
-/// }
-/// }
-/// }
-/// return backtrace;
-/// }
-/// }
-/// "".into()
-/// }
-/// ```
-pub fn short_frames_strict(
- backtrace: &Backtrace,
-) -> impl Iterator<Item = (&BacktraceFrame, Range<usize>)> {
- short_frames_strict_impl(backtrace)
-}
-
-pub(crate) fn short_frames_strict_impl<B: Backtraceish>(
- backtrace: &B,
-) -> impl Iterator<Item = (&B::Frame, Range<usize>)> {
- // Search for the special frames
- let mut short_start = None;
- let mut short_end = None;
- let frames = backtrace.frames();
- for (frame_idx, frame) in frames.iter().enumerate() {
- let symbols = frame.symbols();
- for (subframe_idx, frame) in symbols.iter().enumerate() {
- if let Some(name) = frame.name_str() {
- // Yes these ARE backwards, and that's intentional! We want to print the frames from
- // "newest to oldest" (show what panicked first), and that's the order that Backtrace
- // gives us, but these magic labels view the stack in the opposite order. So we just
- // swap it once here and forget about that weirdness.
- //
- // Note that due to platform/optimization wobblyness you can end up with multiple frames
- // that contain these names in sequence. If that happens we just want to pick the two
- // that are closest together. For the start that means just using the last one we found,
- // and for the end that means taking the first one we find.
- if name.contains("rust_end_short_backtrace") {
- short_start = Some((frame_idx, subframe_idx));
- }
- if name.contains("rust_begin_short_backtrace") && short_end.is_none() {
- short_end = Some((frame_idx, subframe_idx));
- }
- }
- }
- }
-
- // Check if these are in the right order, if they aren't, discard them
- // This also handles the mega-cursed case of "someone made a symbol with both names
- // so actually they're the exact same subframe".
- if let (Some(start), Some(end)) = (short_start, short_end) {
- if start >= end {
- short_start = None;
- short_end = None;
- }
- }
-
- // By default we want to produce a full stack trace and now we'll try to clamp it.
- let mut first_frame = 0usize;
- let mut first_subframe = 0usize;
- // NOTE: this is INCLUSIVE
- let mut last_frame = frames.len().saturating_sub(1);
- // NOTE: this is EXCLUSIVE
- let mut last_subframe_excl = backtrace
- .frames()
- .last()
- .map(|frame| frame.symbols().len())
- .unwrap_or(0);
-
- // This code tries to be really paranoid about boundary conditions although in practice
- // most of them are impossible because there's always going to be gunk on either side
- // of the short backtrace to smooth out the boundaries, and panic_fmt is basically
- // impossible to optimize out. Still, don't trust backtracers!!!
- //
- // This library has a fuckton of tests to try to catch all the little corner cases here.
-
- // If we found the start bound...
- if let Some((idx, sub_idx)) = short_start {
- if frames[idx].symbols().len() == sub_idx + 1 {
- // If it was the last subframe of this frame, we want to just
- // use the whole next frame! It's ok if this takes us to `first_frame = len`,
- // that will be properly handled as an empty output
- first_frame = idx + 1;
- first_subframe = 0;
- } else {
- // Otherwise use this frame, and all the subframes after it
- first_frame = idx;
- first_subframe = sub_idx + 1;
- }
- }
-
- // If we found the end bound...
- if let Some((idx, sub_idx)) = short_end {
- if sub_idx == 0 {
- // If it was the first subframe of this frame, we want to just
- // use the whole previous frame!
- if idx == 0 {
- // If we were *also* on the first frame, set subframe_excl
- // to 0, indicating an empty output
- last_frame = 0;
- last_subframe_excl = 0;
- } else {
- last_frame = idx - 1;
- last_subframe_excl = frames[last_frame].symbols().len();
- }
- } else {
- // Otherwise use this frame (no need subframe math, exclusive bound!)
- last_frame = idx;
- last_subframe_excl = sub_idx;
- }
- }
-
- // If the two subframes managed to perfectly line up with eachother, just
- // throw everything out and yield an empty range. We don't need to fix any
- // other values at this point as they won't be used for anything with an
- // empty iterator
- let final_frames = {
- let start = (first_frame, first_subframe);
- let end = (last_frame, last_subframe_excl);
- if start == end {
- &frames[0..0]
- } else {
- &frames[first_frame..=last_frame]
- }
- };
-
- // Get the index of the last frame when starting from the first frame
- let adjusted_last_frame = last_frame.saturating_sub(first_frame);
-
- // finally do the iteration
- final_frames.iter().enumerate().map(move |(idx, frame)| {
- // Default to all subframes being yielded
- let mut sub_start = 0;
- let mut sub_end_excl = frame.symbols().len();
- // If we're on first frame, apply its subframe clamp
- if idx == 0 {
- sub_start = first_subframe;
- }
- // If we're on the last frame, apply its subframe clamp
- if idx == adjusted_last_frame {
- sub_end_excl = last_subframe_excl;
- }
- (frame, sub_start..sub_end_excl)
- })
-}
-
-pub(crate) trait Backtraceish {
- type Frame: Frameish;
- fn frames(&self) -> &[Self::Frame];
-}
-
-pub(crate) trait Frameish {
- type Symbol: Symbolish;
- fn symbols(&self) -> &[Self::Symbol];
-}
-
-pub(crate) trait Symbolish {
- fn name_str(&self) -> Option<&str>;
-}
-
-impl Backtraceish for Backtrace {
- type Frame = BacktraceFrame;
- fn frames(&self) -> &[Self::Frame] {
- self.frames()
- }
-}
-
-impl Frameish for BacktraceFrame {
- type Symbol = BacktraceSymbol;
- fn symbols(&self) -> &[Self::Symbol] {
- self.symbols()
- }
-}
-
-impl Symbolish for BacktraceSymbol {
- // We need to shortcut SymbolName here because
- // HRTB isn't in our msrv
- fn name_str(&self) -> Option<&str> {
- self.name().and_then(|n| n.as_str())
- }
-}