macho_assembler/formats/executable/
reader.rs1use crate::{
2 helpers::MachoReader,
3 types::{MachoProgram, MachoReadConfig},
4};
5use gaia_binary::{BinaryReader, Fixed, LittleEndian};
6use gaia_types::GaiaError;
7use std::{
8 cell::RefCell,
9 io::{Read, Seek},
10 sync::OnceLock,
11};
12
13#[derive(Debug, Clone, Copy)]
15pub struct ExecutableInfo {
16 pub cpu_type: u32,
18 pub file_type: u32,
20 pub ncmds: u32,
22 pub sizeofcmds: u32,
24 pub flags: u32,
26 pub entry_point: Option<u64>,
28}
29
30#[derive(Debug)]
32pub struct ExecutableReader<R: Read + Seek> {
33 reader: RefCell<BinaryReader<R, Fixed<LittleEndian>>>,
34 config: MachoReadConfig,
35 program: OnceLock<Result<MachoProgram, GaiaError>>,
36 info: OnceLock<Result<ExecutableInfo, GaiaError>>,
37}
38
39impl<R: Read + Seek> ExecutableReader<R> {
40 pub fn new(reader: BinaryReader<R, Fixed<LittleEndian>>, config: MachoReadConfig) -> Self {
42 Self { reader: RefCell::new(reader), config, program: OnceLock::new(), info: OnceLock::new() }
43 }
44
45 pub fn get_program(&self) -> Result<&MachoProgram, &GaiaError> {
47 self.program.get_or_init(|| self.read_program_internal()).as_ref()
48 }
49
50 pub fn get_info(&self) -> Result<&ExecutableInfo, &GaiaError> {
52 self.info.get_or_init(|| self.read_info()).as_ref()
53 }
54
55 fn read_program_internal(&self) -> Result<MachoProgram, GaiaError> {
57 let mut reader = self.reader.borrow_mut();
58
59 let magic = reader.read_u32()?;
61 let cpu_type = reader.read_u32()?;
62 let cpu_subtype = reader.read_u32()?;
63 let file_type = reader.read_u32()?;
64 let ncmds = reader.read_u32()?;
65 let sizeofcmds = reader.read_u32()?;
66 let flags = reader.read_u32()?;
67
68 let reserved = if magic == 0xfeedfacf { Some(reader.read_u32()?) } else { None };
69
70 let header = crate::types::MachoHeader { magic, cpu_type, cpu_subtype, file_type, ncmds, sizeofcmds, flags, reserved };
71
72 let mut load_commands = Vec::new();
74 for _ in 0..ncmds {
75 let cmd = reader.read_u32()?;
76 let cmdsize = reader.read_u32()?;
77
78 let data_size = cmdsize.saturating_sub(8) as usize;
79 let mut data = vec![0u8; data_size];
80 reader.read_exact(&mut data)?;
81
82 load_commands.push(crate::types::LoadCommand { cmd, cmdsize, data });
83 }
84
85 Ok(MachoProgram { header, load_commands, segments: Vec::new(), sections: Vec::new() })
86 }
87
88 fn read_info(&self) -> Result<ExecutableInfo, GaiaError> {
90 let mut reader = self.reader.borrow_mut();
91
92 let _magic = reader.read_u32()?;
93 let cpu_type = reader.read_u32()?;
94 let _cpu_subtype = reader.read_u32()?;
95 let file_type = reader.read_u32()?;
96 let ncmds = reader.read_u32()?;
97 let sizeofcmds = reader.read_u32()?;
98 let flags = reader.read_u32()?;
99
100 Ok(ExecutableInfo {
101 cpu_type,
102 file_type,
103 ncmds,
104 sizeofcmds,
105 flags,
106 entry_point: None, })
108 }
109}
110
111impl<R: Read + Seek> MachoReader<R> for ExecutableReader<R> {
112 fn read_program(&mut self) -> Result<MachoProgram, GaiaError> {
113 self.read_program_internal()
114 }
115
116 fn reader(&mut self) -> &mut BinaryReader<R, Fixed<LittleEndian>> {
117 self.reader.get_mut()
118 }
119
120 fn config(&self) -> &MachoReadConfig {
121 &self.config
122 }
123}