]>
git.proxmox.com Git - rustc.git/blob - tests/ui/runtime/backtrace-debuginfo.rs
2 // We disable tail merging here because it can't preserve debuginfo and thus
3 // potentially breaks the backtraces. Also, subtle changes can decide whether
4 // tail merging succeeds, so the test might work today but fail tomorrow due to a
5 // seemingly completely unrelated change.
6 // Unfortunately, LLVM has no "disable" option for this, so we have to set
7 // "enable" to 0 instead.
9 // compile-flags:-g -Copt-level=0 -Cllvm-args=-enable-tail-merge=0
10 // compile-flags:-Cforce-frame-pointers=yes
11 // compile-flags:-Cstrip=none
12 // ignore-pretty issue #37195
13 // ignore-emscripten spawning processes is not supported
14 // ignore-sgx no processes
15 // ignore-fuchsia Backtrace not symbolized, trace different line alignment
19 #[path = "backtrace-debuginfo-aux.rs"] mod aux;
22 () => ((file
!(), line
!()))
25 macro_rules
! dump_and_die
{
26 ($
($pos
:expr
),*) => ({
27 // FIXME(#18285): we cannot include the current position because
28 // the macro span takes over the last frame's file/line.
30 // You might also be wondering why a major platform,
31 // i686-pc-windows-msvc, is located in here. Some of the saga can be
32 // found on #62897, but the tl;dr; is that it appears that if the
33 // standard library doesn't have debug information or frame pointers,
34 // which it doesn't by default on the test builders, then the stack
35 // walking routines in dbghelp will randomly terminate the stack trace
36 // in libstd without going further. Presumably the addition of frame
37 // pointers and/or debuginfo fixes this since tests always work with
38 // nightly compilers (which have debuginfo). In general though this test
39 // is replicated in rust-lang/backtrace-rs and has extensive coverage
40 // there, even on i686-pc-windows-msvc. We do the best we can in
41 // rust-lang/rust to test it as well, but sometimes we just gotta keep
43 if cfg
!(any(target_os
= "android",
44 all(target_os
= "linux", target_arch
= "arm"),
45 all(target_env
= "msvc", target_arch
= "x86"),
46 target_os
= "freebsd",
47 target_os
= "dragonfly",
48 target_os
= "openbsd")) {
49 // skip these platforms as this support isn't implemented yet.
51 dump_filelines(&[$
($pos
),*]);
57 // we can't use a function as it will alter the backtrace
59 ($counter
:expr
; $
($pos
:expr
),*) => ({
61 dump_and_die
!($
($pos
),*)
68 type Pos
= (&'
static str, u32);
70 // this goes to stdout and each line has to be occurred
71 // in the following backtrace to stderr with a correct order.
72 fn dump_filelines(filelines
: &[Pos
]) {
73 for &(file
, line
) in filelines
.iter().rev() {
75 let basename
= file
.split(&['
/'
, '
\\'
][..]).last().unwrap();
76 println
!("{}:{}", basename
, line
);
81 fn inner(counter
: &mut i32, main_pos
: Pos
, outer_pos
: Pos
) {
82 check
!(counter
; main_pos
, outer_pos
);
83 check
!(counter
; main_pos
, outer_pos
);
84 let inner_pos
= pos
!(); aux
::callback(|aux_pos
| {
85 check
!(counter
; main_pos
, outer_pos
, inner_pos
, aux_pos
);
87 let inner_pos
= pos
!(); aux
::callback_inlined(|aux_pos
| {
88 check
!(counter
; main_pos
, outer_pos
, inner_pos
, aux_pos
);
92 // We emit the wrong location for the caller here when inlined on MSVC
93 #[cfg_attr(not(target_env = "msvc"), inline(always))]
94 #[cfg_attr(target_env = "msvc", inline(never))]
95 fn inner_inlined(counter
: &mut i32, main_pos
: Pos
, outer_pos
: Pos
) {
96 check
!(counter
; main_pos
, outer_pos
);
97 check
!(counter
; main_pos
, outer_pos
);
99 // Again, disable inlining for MSVC.
100 #[cfg_attr(not(target_env = "msvc"), inline(always))]
101 #[cfg_attr(target_env = "msvc", inline(never))]
102 fn inner_further_inlined(counter
: &mut i32, main_pos
: Pos
, outer_pos
: Pos
, inner_pos
: Pos
) {
103 check
!(counter
; main_pos
, outer_pos
, inner_pos
);
105 inner_further_inlined(counter
, main_pos
, outer_pos
, pos
!());
107 let inner_pos
= pos
!(); aux
::callback(|aux_pos
| {
108 check
!(counter
; main_pos
, outer_pos
, inner_pos
, aux_pos
);
110 let inner_pos
= pos
!(); aux
::callback_inlined(|aux_pos
| {
111 check
!(counter
; main_pos
, outer_pos
, inner_pos
, aux_pos
);
114 // this tests a distinction between two independent calls to the inlined function.
115 // (un)fortunately, LLVM somehow merges two consecutive such calls into one node.
116 inner_further_inlined(counter
, main_pos
, outer_pos
, pos
!());
120 fn outer(mut counter
: i32, main_pos
: Pos
) {
121 inner(&mut counter
, main_pos
, pos
!());
122 inner_inlined(&mut counter
, main_pos
, pos
!());
125 fn check_trace(output
: &str, error
: &str) -> Result
<(), String
> {
126 // reverse the position list so we can start with the last item (which was the first line)
127 let mut remaining
: Vec
<&str> = output
.lines().map(|s
| s
.trim()).rev().collect();
129 if !error
.contains("stack backtrace") {
130 return Err(format
!("no backtrace found in stderr:\n{}", error
))
132 for line
in error
.lines() {
133 if !remaining
.is_empty() && line
.contains(remaining
.last().unwrap()) {
137 if !remaining
.is_empty() {
138 return Err(format
!("trace does not match position list\n\
139 still need to find {:?}\n\n\
142 remaining
, output
, error
))
147 fn run_test(me
: &str) {
149 use std
::process
::Command
;
152 let mut errors
= Vec
::new();
154 let out
= Command
::new(me
)
155 .env("RUST_BACKTRACE", "full")
156 .arg(i
.to_string()).output().unwrap();
157 let output
= str::from_utf8(&out
.stdout
).unwrap();
158 let error
= str::from_utf8(&out
.stderr
).unwrap();
159 if out
.status
.success() {
160 assert
!(output
.contains("done."), "bad output for successful run: {}", output
);
163 if let Err(e
) = check_trace(output
, error
) {
169 if errors
.len() > 0 {
170 for error
in errors
{
171 println
!("---------------------------------------");
172 println
!("{}", error
);
175 panic
!("found some errors");
181 let args
: Vec
<String
> = env
::args().collect();
183 let case
= args
[1].parse().unwrap();
184 eprintln
!("test case {}", case
);