]> git.proxmox.com Git - rustc.git/blame - vendor/addr2line/tests/output_equivalence.rs
New upstream version 1.69.0+dfsg1
[rustc.git] / vendor / addr2line / tests / output_equivalence.rs
CommitLineData
064997fb
FG
1extern crate backtrace;
2extern crate findshlibs;
3extern crate rustc_test as test;
4
5use std::env;
6use std::ffi::OsStr;
7use std::path::Path;
8use std::process::Command;
9
10use backtrace::Backtrace;
11use findshlibs::{IterationControl, SharedLibrary, TargetSharedLibrary};
12use test::{ShouldPanic, TestDesc, TestDescAndFn, TestFn, TestName};
13
9ffffee4 14#[inline(never)]
064997fb
FG
15fn make_trace() -> Vec<String> {
16 fn foo() -> Backtrace {
17 bar()
18 }
19 #[inline(never)]
20 fn bar() -> Backtrace {
21 baz()
22 }
23 #[inline(always)]
24 fn baz() -> Backtrace {
25 Backtrace::new_unresolved()
26 }
27
28 let mut base_addr = None;
29 TargetSharedLibrary::each(|lib| {
30 base_addr = Some(lib.virtual_memory_bias().0 as isize);
31 IterationControl::Break
32 });
33 let addrfix = -base_addr.unwrap();
34
35 let trace = foo();
36 trace
37 .frames()
38 .iter()
39 .take(5)
40 .map(|x| format!("{:p}", (x.ip() as *const u8).wrapping_offset(addrfix)))
41 .collect()
42}
43
44fn run_cmd<P: AsRef<OsStr>>(exe: P, me: &Path, flags: Option<&str>, trace: &str) -> String {
45 let mut cmd = Command::new(exe);
46 cmd.env("LC_ALL", "C"); // GNU addr2line is localized, we aren't
47 cmd.env("RUST_BACKTRACE", "1"); // if a child crashes, we want to know why
48
49 if let Some(flags) = flags {
50 cmd.arg(flags);
51 }
52 cmd.arg("--exe").arg(me).arg(trace);
53
54 let output = cmd.output().unwrap();
55
56 assert!(output.status.success());
57 String::from_utf8(output.stdout).unwrap()
58}
59
60fn run_test(flags: Option<&str>) {
61 let me = env::current_exe().unwrap();
62 let mut exe = me.clone();
63 assert!(exe.pop());
64 if exe.file_name().unwrap().to_str().unwrap() == "deps" {
65 assert!(exe.pop());
66 }
67 exe.push("examples");
68 exe.push("addr2line");
69
70 assert!(exe.is_file());
71
72 let trace = make_trace();
73
74 // HACK: GNU addr2line has a bug where looking up multiple addresses can cause the second
75 // lookup to fail. Workaround by doing one address at a time.
76 for addr in &trace {
77 let theirs = run_cmd("addr2line", &me, flags, addr);
78 let ours = run_cmd(&exe, &me, flags, addr);
79
80 // HACK: GNU addr2line does not tidy up paths properly, causing double slashes to be printed.
81 // We consider our behavior to be correct, so we fix their output to match ours.
82 let theirs = theirs.replace("//", "/");
83
84 assert!(
85 theirs == ours,
86 "Output not equivalent:
87
88$ addr2line {0} --exe {1} {2}
89{4}
90$ {3} {0} --exe {1} {2}
91{5}
92
93
94",
95 flags.unwrap_or(""),
96 me.display(),
97 trace.join(" "),
98 exe.display(),
99 theirs,
100 ours
101 );
102 }
103}
104
105static FLAGS: &'static str = "aipsf";
106
107fn make_tests() -> Vec<TestDescAndFn> {
108 (0..(1 << FLAGS.len()))
109 .map(|bits| {
110 if bits == 0 {
111 None
112 } else {
113 let mut param = String::new();
114 param.push('-');
115 for (i, flag) in FLAGS.chars().enumerate() {
116 if (bits & (1 << i)) != 0 {
117 param.push(flag);
118 }
119 }
120 Some(param)
121 }
122 })
123 .map(|param| TestDescAndFn {
124 desc: TestDesc {
125 name: TestName::DynTestName(format!(
126 "addr2line {}",
127 param.as_ref().map_or("", String::as_str)
128 )),
129 ignore: false,
130 should_panic: ShouldPanic::No,
131 allow_fail: false,
132 },
133 testfn: TestFn::DynTestFn(Box::new(move || {
134 run_test(param.as_ref().map(String::as_str))
135 })),
136 })
137 .collect()
138}
139
140fn main() {
141 if !cfg!(target_os = "linux") {
142 return;
143 }
144 let args: Vec<_> = env::args().collect();
145 test::test_main(&args, make_tests());
146}