Skip to main content

macho_assembler/formats/dylib/
reader.rs

1use 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/// Mach-O 动态库信息
14#[derive(Debug, Clone, Copy)]
15pub struct DylibInfo {
16    /// CPU类型
17    pub cpu_type: u32,
18    /// 文件类型
19    pub file_type: u32,
20    /// 加载命令数量
21    pub ncmds: u32,
22    /// 加载命令总大小
23    pub sizeofcmds: u32,
24    /// 标志位
25    pub flags: u32,
26}
27
28/// Mach-O 动态库延迟读取器
29#[derive(Debug)]
30pub struct DylibReader<R: Read + Seek> {
31    reader: RefCell<BinaryReader<R, Fixed<LittleEndian>>>,
32    config: MachoReadConfig,
33    program: OnceLock<Result<MachoProgram, GaiaError>>,
34    info: OnceLock<Result<DylibInfo, GaiaError>>,
35}
36
37impl<R: Read + Seek> DylibReader<R> {
38    /// 创建一个新的动态库读取器
39    pub fn new(reader: BinaryReader<R, Fixed<LittleEndian>>, config: MachoReadConfig) -> Self {
40        Self { reader: RefCell::new(reader), config, program: OnceLock::new(), info: OnceLock::new() }
41    }
42
43    /// 获取程序信息(延迟加载)
44    pub fn get_program(&self) -> Result<&MachoProgram, &GaiaError> {
45        self.program.get_or_init(|| self.read_program_internal()).as_ref()
46    }
47
48    /// 获取文件信息(延迟加载)
49    pub fn get_info(&self) -> Result<&DylibInfo, &GaiaError> {
50        self.info.get_or_init(|| self.read_info()).as_ref()
51    }
52
53    /// 读取完整程序(内部方法)
54    fn read_program_internal(&self) -> Result<MachoProgram, GaiaError> {
55        let mut reader = self.reader.borrow_mut();
56
57        // 读取 Mach-O 文件头
58        let magic = reader.read_u32()?;
59        let cpu_type = reader.read_u32()?;
60        let cpu_subtype = reader.read_u32()?;
61        let file_type = reader.read_u32()?;
62        let ncmds = reader.read_u32()?;
63        let sizeofcmds = reader.read_u32()?;
64        let flags = reader.read_u32()?;
65
66        let reserved = if magic == 0xfeedfacf { Some(reader.read_u32()?) } else { None };
67
68        let header = crate::types::MachoHeader { magic, cpu_type, cpu_subtype, file_type, ncmds, sizeofcmds, flags, reserved };
69
70        // 读取加载命令
71        let mut load_commands = Vec::new();
72        for _ in 0..ncmds {
73            let cmd = reader.read_u32()?;
74            let cmdsize = reader.read_u32()?;
75
76            let data_size = cmdsize.saturating_sub(8) as usize;
77            let mut data = vec![0u8; data_size];
78            reader.read_exact(&mut data)?;
79
80            load_commands.push(crate::types::LoadCommand { cmd, cmdsize, data });
81        }
82
83        Ok(MachoProgram { header, load_commands, segments: Vec::new(), sections: Vec::new() })
84    }
85
86    /// 读取文件基本信息
87    fn read_info(&self) -> Result<DylibInfo, GaiaError> {
88        let mut reader = self.reader.borrow_mut();
89
90        let _magic = reader.read_u32()?;
91        let cpu_type = reader.read_u32()?;
92        let _cpu_subtype = reader.read_u32()?;
93        let file_type = reader.read_u32()?;
94        let ncmds = reader.read_u32()?;
95        let sizeofcmds = reader.read_u32()?;
96        let flags = reader.read_u32()?;
97
98        Ok(DylibInfo { cpu_type, file_type, ncmds, sizeofcmds, flags })
99    }
100}
101
102impl<R: Read + Seek> MachoReader<R> for DylibReader<R> {
103    fn read_program(&mut self) -> Result<MachoProgram, GaiaError> {
104        self.read_program_internal()
105    }
106
107    fn reader(&mut self) -> &mut BinaryReader<R, Fixed<LittleEndian>> {
108        self.reader.get_mut()
109    }
110
111    fn config(&self) -> &MachoReadConfig {
112        &self.config
113    }
114}