]> git.proxmox.com Git - rustc.git/blame - src/test/ui/runtime/backtrace-debuginfo.rs
New upstream version 1.66.0+dfsg1
[rustc.git] / src / test / ui / runtime / backtrace-debuginfo.rs
CommitLineData
416331ca 1// run-pass
e9174d1e
SL
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
3b2f2976 4// tail merging succeeds, so the test might work today but fail tomorrow due to a
e9174d1e
SL
5// seemingly completely unrelated change.
6// Unfortunately, LLVM has no "disable" option for this, so we have to set
7// "enable" to 0 instead.
7453a54e 8
17df50a5 9// compile-flags:-g -Copt-level=0 -Cllvm-args=-enable-tail-merge=0
83c7162d 10// compile-flags:-Cforce-frame-pointers=yes
064997fb 11// compile-flags:-Cstrip=none
c30ab7b3 12// ignore-pretty issue #37195
5bcae85e 13// ignore-emscripten spawning processes is not supported
48663c56 14// ignore-sgx no processes
2b03887a 15// ignore-fuchsia Backtrace not symbolized, trace different line alignment
2c00a5a8 16
c34b1796
AL
17use std::env;
18
19#[path = "backtrace-debuginfo-aux.rs"] mod aux;
20
21macro_rules! pos {
22 () => ((file!(), line!()))
23}
24
c34b1796
AL
25macro_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.
416331ca
XL
29 //
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
42 // landing PRs.
ea8adc8c 43 if cfg!(any(target_os = "android",
54a0048b 44 all(target_os = "linux", target_arch = "arm"),
416331ca 45 all(target_env = "msvc", target_arch = "x86"),
54a0048b
SL
46 target_os = "freebsd",
47 target_os = "dragonfly",
54a0048b 48 target_os = "openbsd")) {
7453a54e
SL
49 // skip these platforms as this support isn't implemented yet.
50 } else {
51 dump_filelines(&[$($pos),*]);
52 panic!();
53 }
c34b1796
AL
54 })
55}
56
c34b1796
AL
57// we can't use a function as it will alter the backtrace
58macro_rules! check {
59 ($counter:expr; $($pos:expr),*) => ({
60 if *$counter == 0 {
61 dump_and_die!($($pos),*)
62 } else {
63 *$counter -= 1;
64 }
65 })
66}
67
68type Pos = (&'static str, u32);
69
70// this goes to stdout and each line has to be occurred
71// in the following backtrace to stderr with a correct order.
72fn dump_filelines(filelines: &[Pos]) {
2c00a5a8 73 for &(file, line) in filelines.iter().rev() {
c34b1796
AL
74 // extract a basename
75 let basename = file.split(&['/', '\\'][..]).last().unwrap();
76 println!("{}:{}", basename, line);
77 }
78}
79
80#[inline(never)]
81fn 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);
86 });
87 let inner_pos = pos!(); aux::callback_inlined(|aux_pos| {
88 check!(counter; main_pos, outer_pos, inner_pos, aux_pos);
89 });
90}
91
2c00a5a8 92// We emit the wrong location for the caller here when inlined on MSVC
e9174d1e
SL
93#[cfg_attr(not(target_env = "msvc"), inline(always))]
94#[cfg_attr(target_env = "msvc", inline(never))]
c34b1796
AL
95fn 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);
98
e9174d1e
SL
99 // Again, disable inlining for MSVC.
100 #[cfg_attr(not(target_env = "msvc"), inline(always))]
101 #[cfg_attr(target_env = "msvc", inline(never))]
c34b1796
AL
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);
104 }
105 inner_further_inlined(counter, main_pos, outer_pos, pos!());
106
107 let inner_pos = pos!(); aux::callback(|aux_pos| {
108 check!(counter; main_pos, outer_pos, inner_pos, aux_pos);
109 });
110 let inner_pos = pos!(); aux::callback_inlined(|aux_pos| {
111 check!(counter; main_pos, outer_pos, inner_pos, aux_pos);
112 });
e9174d1e
SL
113
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!());
c34b1796
AL
117}
118
119#[inline(never)]
120fn outer(mut counter: i32, main_pos: Pos) {
121 inner(&mut counter, main_pos, pos!());
122 inner_inlined(&mut counter, main_pos, pos!());
123}
124
2c00a5a8 125fn check_trace(output: &str, error: &str) -> Result<(), String> {
c34b1796
AL
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();
128
2c00a5a8
XL
129 if !error.contains("stack backtrace") {
130 return Err(format!("no backtrace found in stderr:\n{}", error))
131 }
c34b1796
AL
132 for line in error.lines() {
133 if !remaining.is_empty() && line.contains(remaining.last().unwrap()) {
134 remaining.pop();
135 }
136 }
2c00a5a8
XL
137 if !remaining.is_empty() {
138 return Err(format!("trace does not match position list\n\
139 still need to find {:?}\n\n\
140 --- stdout\n{}\n\
141 --- stderr\n{}",
142 remaining, output, error))
143 }
144 Ok(())
c34b1796
AL
145}
146
147fn run_test(me: &str) {
148 use std::str;
149 use std::process::Command;
150
c34b1796 151 let mut i = 0;
2c00a5a8 152 let mut errors = Vec::new();
c34b1796
AL
153 loop {
154 let out = Command::new(me)
8bb4bdeb 155 .env("RUST_BACKTRACE", "full")
c34b1796
AL
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);
161 break;
162 } else {
2c00a5a8
XL
163 if let Err(e) = check_trace(output, error) {
164 errors.push(e);
165 }
c34b1796
AL
166 }
167 i += 1;
168 }
2c00a5a8
XL
169 if errors.len() > 0 {
170 for error in errors {
171 println!("---------------------------------------");
172 println!("{}", error);
173 }
174
175 panic!("found some errors");
176 }
c34b1796
AL
177}
178
179#[inline(never)]
180fn main() {
181 let args: Vec<String> = env::args().collect();
182 if args.len() >= 2 {
183 let case = args[1].parse().unwrap();
abe05a73 184 eprintln!("test case {}", case);
c34b1796
AL
185 outer(case, pos!());
186 println!("done.");
187 } else {
188 run_test(&args[0]);
189 }
190}