macho_assembler/formats/executable/
reader.rs

1use 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/// Mach-O 可执行文件信息
11#[derive(Debug, Clone, Copy)]
12pub struct ExecutableInfo {
13    /// CPU类型
14    pub cpu_type: u32,
15    /// 文件类型
16    pub file_type: u32,
17    /// 加载命令数量
18    pub ncmds: u32,
19    /// 加载命令总大小
20    pub sizeofcmds: u32,
21    /// 标志位
22    pub flags: u32,
23    /// 程序入口点地址(可选)
24    pub entry_point: Option<u64>,
25}
26
27/// Mach-O 可执行文件延迟读取器
28#[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    /// 创建一个新的可执行文件读取器
38    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    /// 获取程序信息(延迟加载)
48    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    /// 获取文件信息(延迟加载)
55    pub fn get_info(&self) -> Result<&ExecutableInfo, &GaiaError> {
56        self.info.get_or_init(|| {
57            self.read_info()
58        }).as_ref()
59    }
60
61    /// 读取完整程序(内部方法)
62    fn read_program_internal(&self) -> Result<MachoProgram, GaiaError> {
63        let mut reader = self.reader.borrow_mut();
64        
65        // 读取 Mach-O 文件头
66        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        // 读取加载命令
92        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    /// 读取文件基本信息
117    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, // TODO: 从 LC_MAIN 或 LC_UNIXTHREAD 中提取
135        })
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}