1 extern crate addr2line;
2 extern crate fallible_iterator;
3 extern crate findshlibs;
4 extern crate gimli;
5 extern crate memmap;
6 extern crate object;
7 
8 use addr2line::Context;
9 use fallible_iterator::FallibleIterator;
10 use findshlibs::{IterationControl, SharedLibrary, TargetSharedLibrary};
11 use object::Object;
12 use std::fs::File;
13 
find_debuginfo() -> memmap::Mmap14 fn find_debuginfo() -> memmap::Mmap {
15     let path = std::env::current_exe().unwrap();
16     let file = File::open(&path).unwrap();
17     let map = unsafe { memmap::Mmap::map(&file).unwrap() };
18     let file = &object::File::parse(&*map).unwrap();
19     if let Ok(uuid) = file.mach_uuid() {
20         for candidate in path.parent().unwrap().read_dir().unwrap() {
21             let path = candidate.unwrap().path();
22             if !path.to_str().unwrap().ends_with(".dSYM") {
23                 continue;
24             }
25             for candidate in path.join("Contents/Resources/DWARF").read_dir().unwrap() {
26                 let path = candidate.unwrap().path();
27                 let file = File::open(&path).unwrap();
28                 let map = unsafe { memmap::Mmap::map(&file).unwrap() };
29                 let file = &object::File::parse(&*map).unwrap();
30                 if file.mach_uuid().unwrap() == uuid {
31                     return map;
32                 }
33             }
34         }
35     }
36 
37     return map;
38 }
39 
40 #[test]
correctness()41 fn correctness() {
42     let map = find_debuginfo();
43     let file = &object::File::parse(&*map).unwrap();
44     let ctx = Context::new(file).unwrap();
45 
46     let mut bias = None;
47     TargetSharedLibrary::each(|lib| {
48         bias = Some(lib.virtual_memory_bias().0 as u64);
49         IterationControl::Break
50     });
51 
52     let test = |sym: u64, expected_prefix: &str| {
53         let ip = sym.wrapping_sub(bias.unwrap());
54 
55         let frames = ctx.find_frames(ip).unwrap();
56         let frame = frames.last().unwrap().unwrap();
57         let name = frame.function.as_ref().unwrap().demangle().unwrap();
58         // Old rust versions generate DWARF with wrong linkage name,
59         // so only check the start.
60         if !name.starts_with(expected_prefix) {
61             panic!("incorrect name '{}', expected {:?}", name, expected_prefix);
62         }
63     };
64 
65     test(test_function as u64, "correctness::test_function");
66     test(
67         small::test_function as u64,
68         "correctness::small::test_function",
69     );
70     test(auxiliary::foo as u64, "auxiliary::foo");
71 }
72 
73 mod small {
test_function()74     pub fn test_function() {
75         println!("y");
76     }
77 }
78 
test_function()79 fn test_function() {
80     println!("x");
81 }
82 
83 #[test]
zero_function()84 fn zero_function() {
85     let map = find_debuginfo();
86     let file = &object::File::parse(&*map).unwrap();
87     let ctx = Context::new(file).unwrap();
88     for probe in 0..10 {
89         assert!(ctx.find_frames(probe).unwrap().count().unwrap() < 10);
90     }
91 }
92