macho_assembler/formats/dylib/
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 DylibInfo {
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
25/// Mach-O 动态库延迟读取器
26#[derive(Debug)]
27pub struct DylibReader<R: Read + Seek> {
28    reader: RefCell<BinaryReader<R, LittleEndian>>,
29    config: MachoReadConfig,
30    program: OnceLock<Result<MachoProgram, GaiaError>>,
31    info: OnceLock<Result<DylibInfo, GaiaError>>,
32}
33
34impl<R: Read + Seek> DylibReader<R> {
35    /// 创建一个新的动态库读取器
36    pub fn new(reader: BinaryReader<R, LittleEndian>, config: MachoReadConfig) -> Self {
37        Self {
38            reader: RefCell::new(reader),
39            config,
40            program: OnceLock::new(),
41            info: OnceLock::new(),
42        }
43    }
44
45    /// 获取程序信息(延迟加载)
46    pub fn get_program(&self) -> Result<&MachoProgram, &GaiaError> {
47        self.program.get_or_init(|| {
48            self.read_program_internal()
49        }).as_ref()
50    }
51
52    /// 获取文件信息(延迟加载)
53    pub fn get_info(&self) -> Result<&DylibInfo, &GaiaError> {
54        self.info.get_or_init(|| {
55            self.read_info()
56        }).as_ref()
57    }
58
59    /// 读取完整程序(内部方法)
60    fn read_program_internal(&self) -> Result<MachoProgram, GaiaError> {
61        let mut reader = self.reader.borrow_mut();
62        
63        // 读取 Mach-O 文件头
64        let magic = reader.read_u32()?;
65        let cpu_type = reader.read_u32()?;
66        let cpu_subtype = reader.read_u32()?;
67        let file_type = reader.read_u32()?;
68        let ncmds = reader.read_u32()?;
69        let sizeofcmds = reader.read_u32()?;
70        let flags = reader.read_u32()?;
71        
72        let reserved = if magic == 0xfeedfacf {
73            Some(reader.read_u32()?)
74        } else {
75            None
76        };
77
78        let header = crate::types::MachoHeader {
79            magic,
80            cpu_type,
81            cpu_subtype,
82            file_type,
83            ncmds,
84            sizeofcmds,
85            flags,
86            reserved,
87        };
88
89        // 读取加载命令
90        let mut load_commands = Vec::new();
91        for _ in 0..ncmds {
92            let cmd = reader.read_u32()?;
93            let cmdsize = reader.read_u32()?;
94            
95            let data_size = cmdsize.saturating_sub(8) as usize;
96            let mut data = vec![0u8; data_size];
97            reader.read_exact(&mut data)?;
98            
99            load_commands.push(crate::types::LoadCommand {
100                cmd,
101                cmdsize,
102                data,
103            });
104        }
105
106        Ok(MachoProgram {
107            header,
108            load_commands,
109            segments: Vec::new(),
110            sections: Vec::new(),
111        })
112    }
113
114    /// 读取文件基本信息
115    fn read_info(&self) -> Result<DylibInfo, GaiaError> {
116        let mut reader = self.reader.borrow_mut();
117        
118        let _magic = reader.read_u32()?;
119        let cpu_type = reader.read_u32()?;
120        let _cpu_subtype = reader.read_u32()?;
121        let file_type = reader.read_u32()?;
122        let ncmds = reader.read_u32()?;
123        let sizeofcmds = reader.read_u32()?;
124        let flags = reader.read_u32()?;
125        
126        Ok(DylibInfo {
127            cpu_type,
128            file_type,
129            ncmds,
130            sizeofcmds,
131            flags,
132        })
133    }
134}
135
136impl<R: Read + Seek> MachoReader<R> for DylibReader<R> {
137    fn read_program(&mut self) -> Result<MachoProgram, GaiaError> {
138        self.read_program_internal()
139    }
140
141    fn reader(&mut self) -> &mut BinaryReader<R, LittleEndian> {
142        self.reader.get_mut()
143    }
144
145    fn config(&self) -> &MachoReadConfig {
146        &self.config
147    }
148}