pe_assembler/helpers/coff_reader/
mod.rs1use crate::types::{
2 coff::{CoffFileType, CoffHeader, CoffInfo, CoffObject, CoffRelocation, CoffSymbol, SectionHeader},
3 CoffSection,
4};
5use byteorder::{LittleEndian, ReadBytesExt};
6use gaia_types::{helpers::Architecture, GaiaError};
7use std::io::{Read, Seek, SeekFrom};
8
9pub trait CoffReader<R: Read + Seek> {
11 fn get_viewer(&mut self) -> &mut R;
13
14 fn add_diagnostics(&mut self, error: impl Into<GaiaError>);
16
17 fn get_position(&mut self) -> Result<u64, GaiaError>
18 where
19 R: Seek,
20 {
21 Ok(self.get_viewer().stream_position()?)
22 }
23
24 fn set_position(&mut self, offset: u64) -> Result<u64, GaiaError>
25 where
26 R: Seek,
27 {
28 Ok(self.get_viewer().seek(SeekFrom::Start(offset))?)
29 }
30
31 fn get_coff_header(&mut self) -> Result<&CoffHeader, GaiaError>;
33
34 fn set_coff_header(&mut self, head: CoffHeader) -> Option<CoffHeader>;
36
37 fn get_section_headers(&mut self) -> Result<&[SectionHeader], GaiaError>;
39
40 fn set_section_headers(&mut self, headers: Vec<SectionHeader>) -> Vec<SectionHeader>;
42
43 fn get_coff_object(&mut self) -> Result<&CoffObject, GaiaError>;
45
46 fn set_coff_object(&mut self, object: CoffObject) -> Option<CoffObject>;
48
49 fn get_coff_info(&mut self) -> Result<&CoffInfo, GaiaError>;
51
52 fn set_coff_info(&mut self, info: CoffInfo) -> Option<CoffInfo>;
54
55 fn create_coff_info(&mut self) -> Result<CoffInfo, GaiaError> {
57 let header = self.get_coff_header()?.clone();
58
59 let target_arch = match header.machine {
61 0x014c => Architecture::X86,
62 0x8664 => Architecture::X86_64,
63 0x01c0 => Architecture::ARM32,
64 0xaa64 => Architecture::ARM64,
65 _ => Architecture::Unknown,
66 };
67
68 let current_pos = self.get_position()?;
70 self.get_viewer().seek(SeekFrom::End(0))?;
71 let file_size = self.get_position()?;
72 self.set_position(current_pos)?;
73
74 Ok(CoffInfo {
75 file_type: CoffFileType::Object,
76 target_arch,
77 section_count: header.number_of_sections,
78 symbol_count: header.number_of_symbols,
79 file_size,
80 timestamp: header.time_date_stamp,
81 })
82 }
83}
84
85impl CoffRelocation {
86 pub fn read<R: Read>(mut reader: R) -> Result<Self, GaiaError> {
88 Ok(CoffRelocation {
89 virtual_address: reader.read_u32::<LittleEndian>()?,
90 symbol_table_index: reader.read_u32::<LittleEndian>()?,
91 relocation_type: reader.read_u16::<LittleEndian>()?,
92 })
93 }
94}
95
96impl CoffSymbol {
97 pub fn read<R: Read>(mut reader: R) -> Result<Self, GaiaError> {
99 let mut name_bytes = [0u8; 8];
100 reader.read_exact(&mut name_bytes)?;
101
102 let name = if name_bytes[0..4] == [0, 0, 0, 0] {
103 format!("symbol_{}", u32::from_le_bytes([name_bytes[4], name_bytes[5], name_bytes[6], name_bytes[7]]))
105 }
106 else {
107 String::from_utf8_lossy(&name_bytes).trim_end_matches('\0').to_string()
108 };
109
110 Ok(CoffSymbol {
111 name,
112 value: reader.read_u32::<LittleEndian>()?,
113 section_number: reader.read_i16::<LittleEndian>()?,
114 symbol_type: reader.read_u16::<LittleEndian>()?,
115 storage_class: reader.read_u8()?,
116 number_of_aux_symbols: reader.read_u8()?,
117 })
118 }
119}
120
121impl SectionHeader {
122 pub fn read<R: Read>(mut reader: R) -> Result<Self, GaiaError> {
124 let mut name = [0u8; 8];
125 reader.read_exact(&mut name)?;
126
127 Ok(SectionHeader {
128 name,
129 virtual_size: reader.read_u32::<LittleEndian>()?,
130 virtual_address: reader.read_u32::<LittleEndian>()?,
131 size_of_raw_data: reader.read_u32::<LittleEndian>()?,
132 pointer_to_raw_data: reader.read_u32::<LittleEndian>()?,
133 pointer_to_relocations: reader.read_u32::<LittleEndian>()?,
134 pointer_to_line_numbers: reader.read_u32::<LittleEndian>()?,
135 number_of_relocations: reader.read_u16::<LittleEndian>()?,
136 number_of_line_numbers: reader.read_u16::<LittleEndian>()?,
137 characteristics: reader.read_u32::<LittleEndian>()?,
138 })
139 }
140}
141
142pub(crate) fn read_coff_header<R: Read + Seek>(reader: &mut impl CoffReader<R>) -> Result<CoffHeader, GaiaError> {
144 let original_pos = reader.get_position()?;
146
147 reader.set_position(0)?;
149
150 let coff_header = CoffHeader::read(reader.get_viewer())?;
152
153 match coff_header.machine {
155 0x014c | 0x8664 | 0x01c0 | 0xaa64 => {} unknown => {
157 let error = GaiaError::invalid_data(&format!("不支持的机器类型: 0x{:04x}", unknown));
158 reader.add_diagnostics(error);
159 }
160 }
161
162 if coff_header.number_of_sections == 0 {
164 let error = GaiaError::invalid_data("COFF 文件必须至少有一个节");
165 reader.add_diagnostics(error);
166 }
167
168 reader.set_position(original_pos)?;
170
171 Ok(coff_header)
172}
173
174pub(crate) fn read_section_headers<R: Read + Seek>(reader: &mut impl CoffReader<R>) -> Result<Vec<SectionHeader>, GaiaError> {
176 let header = reader.get_coff_header()?.clone();
178 let original_pos = reader.get_position()?;
179
180 let mut section_headers = Vec::with_capacity(header.number_of_sections as usize);
182
183 let section_header_offset = std::mem::size_of::<CoffHeader>() as u64 + header.size_of_optional_header as u64;
185
186 reader.set_position(section_header_offset)?;
187
188 for _ in 0..header.number_of_sections {
189 let section_header = SectionHeader::read(reader.get_viewer())?;
190 section_headers.push(section_header);
191 }
192
193 reader.set_position(original_pos)?;
195
196 Ok(section_headers)
197}
198
199pub(crate) fn read_section_from_header<R: Read + Seek>(
201 reader: &mut impl CoffReader<R>,
202 header: &SectionHeader,
203) -> Result<CoffSection, GaiaError> {
204 let mut data = Vec::new();
205 let mut relocations = Vec::new();
206
207 if header.size_of_raw_data > 0 && header.pointer_to_raw_data > 0 {
209 let original_pos = reader.get_position()?;
210 reader.set_position(header.pointer_to_raw_data as u64)?;
211 data.resize(header.size_of_raw_data as usize, 0);
212 reader.get_viewer().read_exact(&mut data)?;
213 reader.set_position(original_pos)?;
214 }
215
216 if header.number_of_relocations > 0 && header.pointer_to_relocations > 0 {
218 let original_pos = reader.get_position()?;
219 reader.set_position(header.pointer_to_relocations as u64)?;
220
221 for _ in 0..header.number_of_relocations {
222 let relocation = CoffRelocation::read(reader.get_viewer())?;
223 relocations.push(relocation);
224 }
225
226 reader.set_position(original_pos)?;
227 }
228
229 Ok(CoffSection { header: *header, data, relocations })
230}
231
232pub(crate) fn read_symbols<R: Read + Seek>(reader: &mut impl CoffReader<R>) -> Result<Vec<CoffSymbol>, GaiaError> {
234 let header = reader.get_coff_header()?.clone();
235 let original_pos = reader.get_position()?;
236
237 let symbol_table_offset = header.pointer_to_symbol_table as u64;
239 reader.set_position(symbol_table_offset)?;
240
241 let mut symbols = Vec::new();
242 for _ in 0..header.number_of_symbols {
243 let symbol = CoffSymbol::read(reader.get_viewer())?;
244 symbols.push(symbol);
245 }
246
247 reader.set_position(original_pos)?;
248 Ok(symbols)
249}
250
251pub(crate) fn read_coff_object<R: Read + Seek>(reader: &mut impl CoffReader<R>) -> Result<CoffObject, GaiaError> {
253 let header = reader.get_coff_header()?.clone();
254 let section_headers = read_section_headers(reader)?;
255
256 let mut sections = Vec::new();
258 for section_header in §ion_headers {
259 let section = read_section_from_header(reader, section_header)?;
260 sections.push(section);
261 }
262
263 let symbols = read_symbols(reader)?;
265
266 let string_table = Vec::new();
268
269 Ok(CoffObject { header, sections, symbols, string_table })
270}