//! Internal a.out File abstraction. use core::fmt; use std::{ ffi::{c_uchar, c_ushort}, fs::File, io::Read, }; use crate::{Args, disasm::DisasmError, operands::Byte}; #[allow(non_camel_case_types)] pub type c_long = i32; // we use a a.out with 32 byte #[derive(Debug, Clone)] /// Internal representation of the a.out binary format. pub struct Aout { pub header: Header, pub text: Vec, pub data: Vec, } impl fmt::Display for Aout { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "Header: {:#?}\n", self.header).unwrap(); write!(f, "Text: {:#?}\n", self.text).unwrap(); write!(f, "Data: {:#?}\n", self.data) } } impl Aout { pub fn new_from_args(args: &Args) -> Self { let path = args .path .clone() .ok_or(DisasmError::NoFile(args.path.clone())) .unwrap(); let mut file = File::open(path).unwrap(); let mut buf = Vec::new(); file.read_to_end(&mut buf).unwrap(); let aout = Aout::new(buf); log::debug!("{:?}", aout); aout } pub fn new(buf: Vec) -> Self { let hdr = Header { magic: [buf[0], buf[1]], flags: buf[2], cpu: buf[3], hdrlen: buf[4], unused: buf[5], version: c_ushort::from_be_bytes([buf[6], buf[7]]), text: c_long::from_le_bytes([buf[8], buf[9], buf[10], buf[11]]), data: c_long::from_le_bytes([buf[12], buf[13], buf[14], buf[15]]), bss: c_long::from_le_bytes([buf[16], buf[17], buf[18], buf[19]]), entry: c_long::from_le_bytes([buf[20], buf[21], buf[22], buf[23]]), total: c_long::from_le_bytes([buf[24], buf[25], buf[26], buf[27]]), syms: c_long::from_le_bytes([buf[28], buf[29], buf[30], buf[31]]), }; let text_start = hdr.hdrlen as usize; let text_end = text_start + hdr.text as usize; let data_start = text_end; let data_end = data_start + hdr.data as usize; let text_section = &buf[text_start..text_end]; let data_section = &buf[data_start..data_end]; Aout { header: hdr, text: Vec::from(text_section), data: Vec::from(data_section), } } } #[derive(Debug, Clone)] pub struct Header { pub magic: [c_uchar; 2], // magic number pub flags: c_uchar, // flags, see below pub cpu: c_uchar, // cpu id pub hdrlen: c_uchar, // length of header pub unused: c_uchar, // reserved for future use pub version: c_ushort, // version stamp pub text: c_long, // size of text segment in bytes pub data: c_long, // size of data segment in bytes pub bss: c_long, // size of bss segment in bytes pub entry: c_long, // entry point pub total: c_long, // total memory allocated pub syms: c_long, // size of symbol table } impl fmt::Display for Header { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!( f, "Header: Magic: {:02X?} Flags: {:#04X} CPU: {} Header Length: {} Unused: {} Version: {:#06X} Text Size: {} Data Size: {} BSS Size: {} Entry Point: {:#X} Total Allocated: {} Symbol Table Size: {} ", self.magic, self.flags, self.cpu, self.hdrlen, self.unused, self.version, self.text, self.data, self.bss, self.entry, self.total, self.syms ) } }