extern crate addr2line; extern crate fallible_iterator; extern crate findshlibs; extern crate gimli; extern crate memmap; extern crate object; use addr2line::Context; use fallible_iterator::FallibleIterator; use findshlibs::{IterationControl, SharedLibrary, TargetSharedLibrary}; use object::Object; use std::fs::File; fn find_debuginfo() -> memmap::Mmap { let path = std::env::current_exe().unwrap(); let file = File::open(&path).unwrap(); let map = unsafe { memmap::Mmap::map(&file).unwrap() }; let file = &object::File::parse(&*map).unwrap(); if let Ok(uuid) = file.mach_uuid() { for candidate in path.parent().unwrap().read_dir().unwrap() { let path = candidate.unwrap().path(); if !path.to_str().unwrap().ends_with(".dSYM") { continue; } for candidate in path.join("Contents/Resources/DWARF").read_dir().unwrap() { let path = candidate.unwrap().path(); let file = File::open(&path).unwrap(); let map = unsafe { memmap::Mmap::map(&file).unwrap() }; let file = &object::File::parse(&*map).unwrap(); if file.mach_uuid().unwrap() == uuid { return map; } } } } return map; } #[test] fn correctness() { let map = find_debuginfo(); let file = &object::File::parse(&*map).unwrap(); let ctx = Context::new(file).unwrap(); let mut bias = None; TargetSharedLibrary::each(|lib| { bias = Some(lib.virtual_memory_bias().0 as u64); IterationControl::Break }); let test = |sym: u64, expected_prefix: &str| { let ip = sym.wrapping_sub(bias.unwrap()); let frames = ctx.find_frames(ip).unwrap(); let frame = frames.last().unwrap().unwrap(); let name = frame.function.as_ref().unwrap().demangle().unwrap(); // Old rust versions generate DWARF with wrong linkage name, // so only check the start. if !name.starts_with(expected_prefix) { panic!("incorrect name '{}', expected {:?}", name, expected_prefix); } }; test(test_function as u64, "correctness::test_function"); test( small::test_function as u64, "correctness::small::test_function", ); test(auxiliary::foo as u64, "auxiliary::foo"); } mod small { pub fn test_function() { println!("y"); } } fn test_function() { println!("x"); } #[test] fn zero_function() { let map = find_debuginfo(); let file = &object::File::parse(&*map).unwrap(); let ctx = Context::new(file).unwrap(); for probe in 0..10 { assert!(ctx.find_frames(probe).unwrap().count().unwrap() < 10); } }