-
Notifications
You must be signed in to change notification settings - Fork 13.9k
Filter backtrace #48702
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
Filter backtrace #48702
Changes from 1 commit
6d49756
6ccf28a
199b485
8e4a951
a9c5a95
2a74f37
1edc781
7663b93
0c4e2d2
d87fd39
313dfd5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -69,16 +69,18 @@ fn _print(w: &mut Write, format: PrintFormat) -> io::Result<()> { | |
| inline_context: 0, | ||
| }; MAX_NB_FRAMES]; | ||
| let (nb_frames, context) = unwind_backtrace(&mut frames)?; | ||
| let (skipped_before, skipped_after) = | ||
| filter_frames(&frames[..nb_frames], format, &context); | ||
| if skipped_before + skipped_after > 0 { | ||
| let filtered_frames = filter_frames(&frames[..nb_frames], &context, format); | ||
| if filtered_frames.len() != nb_frames { | ||
| writeln!(w, "note: Some details are omitted, \ | ||
| run with `RUST_BACKTRACE=full` for a verbose backtrace.")?; | ||
| } | ||
| writeln!(w, "stack backtrace:")?; | ||
|
|
||
| let filtered_frames = &frames[..nb_frames - skipped_after]; | ||
| for (index, frame) in filtered_frames.iter().skip(skipped_before).enumerate() { | ||
| for (index, frame, is_on_filter_edge) in filtered_frames { | ||
| // Don't use ANSI escape codes on windows, because most terminals on it don't support them | ||
| if is_on_filter_edge && cfg!(not(windows)) { | ||
| write!(w, "\x1B[2m")?; | ||
|
||
| } | ||
| resolve_symname(*frame, |symname| { | ||
| output(w, index, *frame, symname, format) | ||
| }, &context)?; | ||
|
|
@@ -88,43 +90,84 @@ fn _print(w: &mut Write, format: PrintFormat) -> io::Result<()> { | |
| if has_more_filenames { | ||
| w.write_all(b" <... and possibly more>")?; | ||
| } | ||
| if cfg!(not(windows)) { | ||
| write!(w, "\x1B[0m")?; | ||
| } | ||
| } | ||
|
|
||
| Ok(()) | ||
| } | ||
|
|
||
| /// Returns a number of frames to remove at the beginning and at the end of the | ||
| /// backtrace, according to the backtrace format. | ||
| fn filter_frames(frames: &[Frame], | ||
| format: PrintFormat, | ||
| context: &BacktraceContext) -> (usize, usize) | ||
| { | ||
| if format == PrintFormat::Full { | ||
| return (0, 0); | ||
| } | ||
| fn should_show_frame(frame: &Frame, context: &BacktraceContext) -> bool { | ||
| const FILTERED_SYMBOLS: &[&str] = &[ | ||
| "main", | ||
| "rust_begin_unwind", | ||
| ]; | ||
| const FILTERED_SYMBOL_PARTS: &[&str] = &[ | ||
| "panic", | ||
| "sys", | ||
| "lang_start", | ||
| ]; | ||
| let mut should_show = true; | ||
| let _ = resolve_symname(*frame, |symname| { | ||
| if let Some(mangled_symbol_name) = symname { | ||
| for filtered_symbol in FILTERED_SYMBOLS { | ||
| if mangled_symbol_name == *filtered_symbol { | ||
| should_show = false; | ||
| return Ok(()); | ||
| } | ||
| } | ||
| for filtered_symbol_part in FILTERED_SYMBOL_PARTS { | ||
| if mangled_symbol_name.contains(filtered_symbol_part) { | ||
| should_show = false; | ||
| return Ok(()); | ||
| } | ||
| } | ||
| } | ||
| Ok(()) | ||
| }, context); | ||
| should_show | ||
| } | ||
|
|
||
| let skipped_before = 0; | ||
| /// Returns the frames to show as a Vec. | ||
| /// If the bool is true the frame is on the edge between showing and not showing. | ||
| fn filter_frames<'a>(frames: &'a [Frame], | ||
| context: &BacktraceContext, | ||
| format: PrintFormat) -> Vec<(usize, &'a Frame, bool)> | ||
|
||
| { | ||
| let mut frames_iter = frames.iter().enumerate().peekable(); | ||
| let mut filtered_frames = Vec::new(); | ||
| let mut show_prev_frame = false; | ||
|
|
||
| let skipped_after = frames.len() - frames.iter().position(|frame| { | ||
| let mut is_marker = false; | ||
| while let Some((i, frame)) = frames_iter.next() { | ||
| let mut is_after_begin_short_backtrace = false; | ||
| let _ = resolve_symname(*frame, |symname| { | ||
| if let Some(mangled_symbol_name) = symname { | ||
| // Use grep to find the concerned functions | ||
| if mangled_symbol_name.contains("__rust_begin_short_backtrace") { | ||
| is_marker = true; | ||
| is_after_begin_short_backtrace = true; | ||
| } | ||
| } | ||
| Ok(()) | ||
| }, context); | ||
| is_marker | ||
| }).unwrap_or(frames.len()); | ||
| if is_after_begin_short_backtrace && format != PrintFormat::Full { | ||
| break; | ||
| } | ||
|
|
||
| if skipped_before + skipped_after >= frames.len() { | ||
| // Avoid showing completely empty backtraces | ||
| return (0, 0); | ||
| let show_cur_frame = should_show_frame(frame, context); | ||
| let show_next_frame = frames_iter | ||
| .peek() | ||
| .map(|&(_, frame)| should_show_frame(frame, context)) | ||
| .unwrap_or(false); | ||
| if show_cur_frame { | ||
| filtered_frames.push((i, frame, false)); | ||
| } else if show_prev_frame || show_next_frame || format == PrintFormat::Full { | ||
| filtered_frames.push((i, frame, true)); | ||
| } | ||
| show_prev_frame = show_cur_frame; | ||
| } | ||
|
|
||
| (skipped_before, skipped_after) | ||
| filtered_frames | ||
| } | ||
|
|
||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| -include ../tools.mk | ||
|
|
||
| # Test that short backtraces don't include several internal symbols | ||
|
|
||
| all: | ||
| $(RUSTC) main.rs -o $(TMPDIR)/main | ||
| # with short backtrace | ||
| RUST_BACKTRACE=1 $(TMPDIR)/main 2> $(TMPDIR)/short_bt.stderr || exit 0 && exit 1 | ||
| $(CGREP) "panicked at" < $(TMPDIR)/short_bt.stderr | ||
| $(CGREP) -v "std::panicking" < $(TMPDIR)/short_bt.stderr | ||
| $(CGREP) -v "std::sys" < $(TMPDIR)/short_bt.stderr | ||
| $(CGREP) -v "__rust_maybe_catch_panic" < $(TMPDIR)/short_bt.stderr | ||
| $(CGREP) -v "__rust_begin_short_backtrace" < $(TMPDIR)/short_bt.stderr | ||
| # with long backtrace | ||
| RUST_BACKTRACE=full $(TMPDIR)/main 2> $(TMPDIR)/long_bt.stderr || exit 0 && exit 1 | ||
| $(CGREP) "panicked at" < $(TMPDIR)/long_bt.stderr | ||
| $(CGREP) "std::panicking" < $(TMPDIR)/long_bt.stderr | ||
| $(CGREP) "std::sys" < $(TMPDIR)/long_bt.stderr | ||
| $(CGREP) "__rust_maybe_catch_panic" < $(TMPDIR)/long_bt.stderr | ||
| # FIXME: prevent tail call optimization for this | ||
| $(CGREP) -v "__rust_begin_short_backtrace" < $(TMPDIR)/long_bt.stderr |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| fn main() { | ||
| (None as Option<()>).unwrap(); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah unfortunately this has the unintended side effect of ignoring
src/librustc_back/target, so perhaps these changes could be left out for now?