macho_assembler/formats/dylib/
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 DylibInfo {
16 pub cpu_type: u32,
18 pub file_type: u32,
20 pub ncmds: u32,
22 pub sizeofcmds: u32,
24 pub flags: u32,
26}
27
28#[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 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 pub fn get_program(&self) -> Result<&MachoProgram, &GaiaError> {
45 self.program.get_or_init(|| self.read_program_internal()).as_ref()
46 }
47
48 pub fn get_info(&self) -> Result<&DylibInfo, &GaiaError> {
50 self.info.get_or_init(|| self.read_info()).as_ref()
51 }
52
53 fn read_program_internal(&self) -> Result<MachoProgram, GaiaError> {
55 let mut reader = self.reader.borrow_mut();
56
57 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 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 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}