use goblin::archive::*; use scroll::Pread; use std::path::Path; use std::fs::File; #[test] fn parse_file_header() { let file_header: [u8; SIZEOF_HEADER] = [0x2f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x38, 0x32, 0x34, 0x34, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x60, 0x0a]; let buffer = &file_header[..]; match buffer.pread::(0) { Err(e) => panic!("could not read the buffer: {:?}", e), Ok(file_header2) => { let file_header = MemberHeader { identifier: [0x2f,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,], timestamp: [48, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32], owner_id: [48, 32, 32, 32, 32, 32], group_id: [48, 32, 32, 32, 32, 32], mode: [48, 32, 32, 32, 32, 32, 32, 32], file_size: [56, 50, 52, 52, 32, 32, 32, 32, 32, 32], terminator: [96, 10] }; assert_eq!(file_header, file_header2) } } } #[test] fn parse_archive() { let crt1a: Vec = include!("../etc/crt1a.rs"); const START: &str = "_start"; match Archive::parse(&crt1a) { Ok(archive) => { assert_eq!(archive.member_of_symbol(START), Some("crt1.o")); if let Some(member) = archive.get("crt1.o") { assert_eq!(member.offset, 194); assert_eq!(member.size(), 1928) } else { panic!("could not get crt1.o"); } }, Err(err) => panic!("could not parse archive: {:?}", err), }; } #[test] fn parse_self() { use std::fs; use std::io::Read; let mut path = Path::new("target").join("debug").join("libgoblin.rlib"); // https://github.com/m4b/goblin/issues/63 if fs::metadata(&path).is_err() { path = Path::new("target").join("release").join("libgoblin.rlib"); } let buffer = { let mut fd = File::open(path).expect("can open file; did you run cargo build first?"); let mut v = Vec::new(); fd.read_to_end(&mut v).expect("read file"); v }; let archive = Archive::parse(&buffer).expect("parse rlib"); // check that the archive has a useful symbol table by counting the total number of symbols let symbol_count: usize = archive.summarize().into_iter() .map(|(_member_name, _member_index, ref symbols)| symbols.len()) .sum(); assert!(symbol_count > 500); let goblin_object_name = archive.members() .into_iter() .find(|member| { println!("member: {:?}", member); member.ends_with("goblin-archive.o") // < 1.18 || (member.starts_with("goblin") && member.ends_with("0.o")) // >= 1.18 && < 1.22 || (member.starts_with("goblin") && member.ends_with("rust-cgu.o")) // = 1.22 || (member.starts_with("goblin") && member.ends_with("rcgu.o")) // >= nightly 1.23 }) .expect("goblin-.0.o not found"); let bytes = archive.extract(goblin_object_name, &buffer).expect("extract goblin object"); match goblin::Object::parse(&bytes).expect("parse object") { goblin::Object::Elf(elf) => { assert!(elf.entry == 0); } goblin::Object::Mach(goblin::mach::Mach::Binary(macho)) => { assert_eq!(macho.header.filetype, goblin::mach::header::MH_OBJECT); assert_eq!(macho.entry, 0); } other => { panic!("unexpected Object::parse result: {:?}", other); } } }