rust/tests/ui/debuginfo/backtrace-dylib-dep.rs

116 lines
3.5 KiB
Rust

// Check that backtrace info is correctly generated for dynamic libraries and is usable by a
// rust binary.
// Part of porting some backtrace tests to rustc: <https://github.com/rust-lang/rust/issues/122899>.
// Original test:
// <https://github.com/rust-lang/backtrace-rs/tree/6fa4b85b9962c3e1be8c2e5cc605cd078134152b/crates/dylib-dep>
// ignore-tidy-linelength
//@ ignore-android FIXME #17520
//@ ignore-fuchsia Backtraces not symbolized
//@ ignore-musl musl doesn't support dynamic libraries (at least when the original test was written).
//@ needs-unwind
//@ compile-flags: -g -Copt-level=0 -Cstrip=none -Cforce-frame-pointers=yes
//@ aux-crate: dylib_dep_helper=dylib-dep-helper.rs
//@ aux-crate: auxiliary=dylib-dep-helper-aux.rs
//@ run-pass
#![allow(improper_ctypes)]
#![allow(improper_ctypes_definitions)]
extern crate dylib_dep_helper;
extern crate auxiliary;
use std::backtrace::Backtrace;
macro_rules! pos {
() => {
(file!(), line!())
};
}
#[collapse_debuginfo(yes)]
macro_rules! check {
($($pos:expr),*) => ({
verify(&[$($pos,)* pos!()]);
})
}
fn verify(filelines: &[Pos]) {
let trace = Backtrace::capture();
eprintln!("-----------------------------------");
eprintln!("looking for:");
for (file, line) in filelines.iter().rev() {
eprintln!("\t{file}:{line}");
}
eprintln!("found:\n{trace:#?}");
let mut iter = filelines.iter().rev();
// FIXME(jieyouxu): use proper `BacktraceFrame` accessors when it becomes available. Right now,
// this depends on the debug format of `Backtrace` which is of course fragile.
let backtrace = format!("{:#?}", trace);
while let Some((file, line)) = iter.next() {
// FIXME(jieyouxu): make this test use proper accessors on `BacktraceFrames` once it has
// them.
assert!(backtrace.contains(file), "expected backtrace to contain {}", file);
assert!(backtrace.contains(&line.to_string()), "expected backtrace to contain {}", line);
}
}
type Pos = (&'static str, u32);
extern "C" {
#[link_name = "foo"]
fn foo(p: Pos, cb: fn(Pos, Pos));
}
fn main() {
std::env::set_var("RUST_BACKTRACE", "1");
unsafe {
foo(pos!(), |a, b| {
check!(a, b)
})
}
outer(pos!());
}
#[inline(never)]
fn outer(main_pos: Pos) {
inner(main_pos, pos!());
inner_inlined(main_pos, pos!());
}
#[inline(never)]
fn inner(main_pos: Pos, outer_pos: Pos) {
check!(main_pos, outer_pos);
check!(main_pos, outer_pos);
let inner_pos = pos!(); auxiliary::callback(|aux_pos| {
check!(main_pos, outer_pos, inner_pos, aux_pos);
});
let inner_pos = pos!(); auxiliary::callback_inlined(|aux_pos| {
check!(main_pos, outer_pos, inner_pos, aux_pos);
});
}
#[inline(always)]
fn inner_inlined(main_pos: Pos, outer_pos: Pos) {
check!(main_pos, outer_pos);
check!(main_pos, outer_pos);
#[inline(always)]
fn inner_further_inlined(main_pos: Pos, outer_pos: Pos, inner_pos: Pos) {
check!(main_pos, outer_pos, inner_pos);
}
inner_further_inlined(main_pos, outer_pos, pos!());
let inner_pos = pos!(); auxiliary::callback(|aux_pos| {
check!(main_pos, outer_pos, inner_pos, aux_pos);
});
let inner_pos = pos!(); auxiliary::callback_inlined(|aux_pos| {
check!(main_pos, outer_pos, inner_pos, aux_pos);
});
// this tests a distinction between two independent calls to the inlined function.
// (un)fortunately, LLVM somehow merges two consecutive such calls into one node.
inner_further_inlined(main_pos, outer_pos, pos!());
}