| 
 | 1 | +// Check that backtrace info is correctly generated for dynamic libraries and is usable by a  | 
 | 2 | +// rust binary.  | 
 | 3 | +// Part of porting some backtrace tests to rustc: <https://github.com/rust-lang/rust/issues/122899>.  | 
 | 4 | +// Original test:  | 
 | 5 | +// <https://github.com/rust-lang/backtrace-rs/tree/6fa4b85b9962c3e1be8c2e5cc605cd078134152b/crates/dylib-dep>  | 
 | 6 | +// ignore-tidy-linelength  | 
 | 7 | +//@ ignore-android FIXME #17520  | 
 | 8 | +//@ ignore-fuchsia Backtraces not symbolized  | 
 | 9 | +//@ ignore-musl musl doesn't support dynamic libraries (at least when the original test was written).  | 
 | 10 | +//@ needs-unwind  | 
 | 11 | +//@ compile-flags: -g -Copt-level=0 -Cstrip=none -Cforce-frame-pointers=yes  | 
 | 12 | +//@ aux-crate: dylib_dep_helper=dylib-dep-helper.rs  | 
 | 13 | +//@ aux-crate: auxiliary=dylib-dep-helper-aux.rs  | 
 | 14 | +//@ run-pass  | 
 | 15 | + | 
 | 16 | +#![allow(improper_ctypes)]  | 
 | 17 | +#![allow(improper_ctypes_definitions)]  | 
 | 18 | + | 
 | 19 | +extern crate dylib_dep_helper;  | 
 | 20 | +extern crate auxiliary;  | 
 | 21 | + | 
 | 22 | +use std::backtrace::Backtrace;  | 
 | 23 | + | 
 | 24 | +macro_rules! pos {  | 
 | 25 | +    () => {  | 
 | 26 | +        (file!(), line!())  | 
 | 27 | +    };  | 
 | 28 | +}  | 
 | 29 | + | 
 | 30 | +macro_rules! check {  | 
 | 31 | +    ($($pos:expr),*) => ({  | 
 | 32 | +        verify(&[$($pos,)* pos!()]);  | 
 | 33 | +    })  | 
 | 34 | +}  | 
 | 35 | + | 
 | 36 | +fn verify(filelines: &[Pos]) {  | 
 | 37 | +    let trace = Backtrace::capture();  | 
 | 38 | +    eprintln!("-----------------------------------");  | 
 | 39 | +    eprintln!("looking for:");  | 
 | 40 | +    for (file, line) in filelines.iter().rev() {  | 
 | 41 | +        eprintln!("\t{file}:{line}");  | 
 | 42 | +    }  | 
 | 43 | +    eprintln!("found:\n{trace:#?}");  | 
 | 44 | +    let mut iter = filelines.iter().rev();  | 
 | 45 | +    // FIXME(jieyouxu): use proper `BacktraceFrame` accessors when it becomes available. Right now,  | 
 | 46 | +    // this depends on the debug format of `Backtrace` which is of course fragile.  | 
 | 47 | +    let backtrace = format!("{:#?}", trace);  | 
 | 48 | +    while let Some((file, line)) = iter.next() {  | 
 | 49 | +        // FIXME(jieyouxu): make this test use proper accessors on `BacktraceFrames` once it has  | 
 | 50 | +        // them.  | 
 | 51 | +        assert!(backtrace.contains(file), "expected backtrace to contain {}", file);  | 
 | 52 | +        assert!(backtrace.contains(&line.to_string()), "expected backtrace to contain {}", line);  | 
 | 53 | +    }  | 
 | 54 | +}  | 
 | 55 | + | 
 | 56 | +type Pos = (&'static str, u32);  | 
 | 57 | + | 
 | 58 | +extern "C" {  | 
 | 59 | +    #[link_name = "foo"]  | 
 | 60 | +    fn foo(p: Pos, cb: fn(Pos, Pos));  | 
 | 61 | +}  | 
 | 62 | + | 
 | 63 | +fn main() {  | 
 | 64 | +    std::env::set_var("RUST_BACKTRACE", "1");  | 
 | 65 | + | 
 | 66 | +    unsafe {  | 
 | 67 | +        foo(pos!(), |a, b| {  | 
 | 68 | +            check!(a, b)  | 
 | 69 | +        })  | 
 | 70 | +    }  | 
 | 71 | + | 
 | 72 | +    outer(pos!());  | 
 | 73 | +}  | 
 | 74 | + | 
 | 75 | +#[inline(never)]  | 
 | 76 | +fn outer(main_pos: Pos) {  | 
 | 77 | +    inner(main_pos, pos!());  | 
 | 78 | +    inner_inlined(main_pos, pos!());  | 
 | 79 | +}  | 
 | 80 | + | 
 | 81 | +#[inline(never)]  | 
 | 82 | +fn inner(main_pos: Pos, outer_pos: Pos) {  | 
 | 83 | +    check!(main_pos, outer_pos);  | 
 | 84 | +    check!(main_pos, outer_pos);  | 
 | 85 | +    let inner_pos = pos!(); auxiliary::callback(|aux_pos| {  | 
 | 86 | +        check!(main_pos, outer_pos, inner_pos, aux_pos);  | 
 | 87 | +    });  | 
 | 88 | +    let inner_pos = pos!(); auxiliary::callback_inlined(|aux_pos| {  | 
 | 89 | +        check!(main_pos, outer_pos, inner_pos, aux_pos);  | 
 | 90 | +    });  | 
 | 91 | +}  | 
 | 92 | + | 
 | 93 | +#[inline(always)]  | 
 | 94 | +fn inner_inlined(main_pos: Pos, outer_pos: Pos) {  | 
 | 95 | +    check!(main_pos, outer_pos);  | 
 | 96 | +    check!(main_pos, outer_pos);  | 
 | 97 | + | 
 | 98 | +    #[inline(always)]  | 
 | 99 | +    fn inner_further_inlined(main_pos: Pos, outer_pos: Pos, inner_pos: Pos) {  | 
 | 100 | +        check!(main_pos, outer_pos, inner_pos);  | 
 | 101 | +    }  | 
 | 102 | +    inner_further_inlined(main_pos, outer_pos, pos!());  | 
 | 103 | + | 
 | 104 | +    let inner_pos = pos!(); auxiliary::callback(|aux_pos| {  | 
 | 105 | +        check!(main_pos, outer_pos, inner_pos, aux_pos);  | 
 | 106 | +    });  | 
 | 107 | +    let inner_pos = pos!(); auxiliary::callback_inlined(|aux_pos| {  | 
 | 108 | +        check!(main_pos, outer_pos, inner_pos, aux_pos);  | 
 | 109 | +    });  | 
 | 110 | + | 
 | 111 | +    // this tests a distinction between two independent calls to the inlined function.  | 
 | 112 | +    // (un)fortunately, LLVM somehow merges two consecutive such calls into one node.  | 
 | 113 | +    inner_further_inlined(main_pos, outer_pos, pos!());  | 
 | 114 | +}  | 
0 commit comments