macho_assembler/formats/executable/
reader.rs1use crate::{
2 helpers::MachoReader,
3 types::{MachoProgram, MachoReadConfig},
4};
5use gaia_types::{BinaryReader, GaiaError};
6use std::{cell::RefCell, sync::OnceLock};
7use byteorder::LittleEndian;
8use std::io::{Read, Seek};
9
10#[derive(Debug, Clone, Copy)]
12pub struct ExecutableInfo {
13 pub cpu_type: u32,
15 pub file_type: u32,
17 pub ncmds: u32,
19 pub sizeofcmds: u32,
21 pub flags: u32,
23 pub entry_point: Option<u64>,
25}
26
27#[derive(Debug)]
29pub struct ExecutableReader<R: Read + Seek> {
30 reader: RefCell<BinaryReader<R, LittleEndian>>,
31 config: MachoReadConfig,
32 program: OnceLock<Result<MachoProgram, GaiaError>>,
33 info: OnceLock<Result<ExecutableInfo, GaiaError>>,
34}
35
36impl<R: Read + Seek> ExecutableReader<R> {
37 pub fn new(reader: BinaryReader<R, LittleEndian>, config: MachoReadConfig) -> Self {
39 Self {
40 reader: RefCell::new(reader),
41 config,
42 program: OnceLock::new(),
43 info: OnceLock::new(),
44 }
45 }
46
47 pub fn get_program(&self) -> Result<&MachoProgram, &GaiaError> {
49 self.program.get_or_init(|| {
50 self.read_program_internal()
51 }).as_ref()
52 }
53
54 pub fn get_info(&self) -> Result<&ExecutableInfo, &GaiaError> {
56 self.info.get_or_init(|| {
57 self.read_info()
58 }).as_ref()
59 }
60
61 fn read_program_internal(&self) -> Result<MachoProgram, GaiaError> {
63 let mut reader = self.reader.borrow_mut();
64
65 let magic = reader.read_u32()?;
67 let cpu_type = reader.read_u32()?;
68 let cpu_subtype = reader.read_u32()?;
69 let file_type = reader.read_u32()?;
70 let ncmds = reader.read_u32()?;
71 let sizeofcmds = reader.read_u32()?;
72 let flags = reader.read_u32()?;
73
74 let reserved = if magic == 0xfeedfacf {
75 Some(reader.read_u32()?)
76 } else {
77 None
78 };
79
80 let header = crate::types::MachoHeader {
81 magic,
82 cpu_type,
83 cpu_subtype,
84 file_type,
85 ncmds,
86 sizeofcmds,
87 flags,
88 reserved,
89 };
90
91 let mut load_commands = Vec::new();
93 for _ in 0..ncmds {
94 let cmd = reader.read_u32()?;
95 let cmdsize = reader.read_u32()?;
96
97 let data_size = cmdsize.saturating_sub(8) as usize;
98 let mut data = vec![0u8; data_size];
99 reader.read_exact(&mut data)?;
100
101 load_commands.push(crate::types::LoadCommand {
102 cmd,
103 cmdsize,
104 data,
105 });
106 }
107
108 Ok(MachoProgram {
109 header,
110 load_commands,
111 segments: Vec::new(),
112 sections: Vec::new(),
113 })
114 }
115
116 fn read_info(&self) -> Result<ExecutableInfo, GaiaError> {
118 let mut reader = self.reader.borrow_mut();
119
120 let _magic = reader.read_u32()?;
121 let cpu_type = reader.read_u32()?;
122 let _cpu_subtype = reader.read_u32()?;
123 let file_type = reader.read_u32()?;
124 let ncmds = reader.read_u32()?;
125 let sizeofcmds = reader.read_u32()?;
126 let flags = reader.read_u32()?;
127
128 Ok(ExecutableInfo {
129 cpu_type,
130 file_type,
131 ncmds,
132 sizeofcmds,
133 flags,
134 entry_point: None, })
136 }
137}
138
139impl<R: Read + Seek> MachoReader<R> for ExecutableReader<R> {
140 fn read_program(&mut self) -> Result<MachoProgram, GaiaError> {
141 self.read_program_internal()
142 }
143
144 fn reader(&mut self) -> &mut BinaryReader<R, LittleEndian> {
145 self.reader.get_mut()
146 }
147
148 fn config(&self) -> &MachoReadConfig {
149 &self.config
150 }
151}