macho_assembler/formats/dylib/
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 DylibInfo {
13 pub cpu_type: u32,
15 pub file_type: u32,
17 pub ncmds: u32,
19 pub sizeofcmds: u32,
21 pub flags: u32,
23}
24
25#[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 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 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 pub fn get_info(&self) -> Result<&DylibInfo, &GaiaError> {
54 self.info.get_or_init(|| {
55 self.read_info()
56 }).as_ref()
57 }
58
59 fn read_program_internal(&self) -> Result<MachoProgram, GaiaError> {
61 let mut reader = self.reader.borrow_mut();
62
63 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 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 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}