clr_assembler/formats/dll/reader/
mod.rs1mod headers;
2mod metadata;
3mod program;
4mod utils;
5
6use crate::{
7 formats::dll::DllReadConfig,
8 program::{ClrHeader, ClrProgram, ClrVersion, DotNetAssemblyInfo, MetadataHeader, StreamHeader},
9};
10use gaia_types::{GaiaError, SourceLocation};
11use pe_assembler::{
12 helpers::PeReader,
13 types::{PeHeader, PeProgram, SectionHeader},
14};
15use std::io::{Read, Seek};
16
17#[derive(Debug)]
18pub struct DllReader<'config, R> {
19 options: &'config DllReadConfig,
21 reader: pe_assembler::formats::dll::reader::DllReader<R>,
22 clr_header: Option<ClrHeader>,
24 metadata_header: Option<MetadataHeader>,
26 stream_headers: Option<Vec<StreamHeader>>,
28 assembly_info: Option<DotNetAssemblyInfo>,
30 clr_program: Option<ClrProgram>,
32}
33
34impl<'config, R: Read + Seek> PeReader<R> for DllReader<'config, R> {
35 fn get_viewer(&mut self) -> &mut R {
36 self.reader.get_viewer()
37 }
38
39 fn add_diagnostics(&mut self, error: impl Into<GaiaError>) {
40 self.reader.add_diagnostics(error)
41 }
42
43 fn get_section_headers(&mut self) -> Result<&[SectionHeader], GaiaError> {
44 self.reader.get_section_headers()
45 }
46
47 fn get_pe_header(&mut self) -> Result<&PeHeader, GaiaError> {
48 self.reader.get_pe_header()
49 }
50
51 fn get_program(&mut self) -> Result<&PeProgram, GaiaError> {
52 self.reader.get_program()
53 }
54}
55
56impl<'config, R> DllReader<'config, R> {
57 pub fn new(reader: R, options: &'config DllReadConfig) -> Self {
61 Self {
62 reader: pe_assembler::formats::dll::reader::DllReader::new(reader),
63 clr_header: None,
64 metadata_header: None,
65 stream_headers: None,
66 assembly_info: None,
67 clr_program: None,
68 options,
69 }
70 }
71}
72
73impl<'config, R> DllReader<'config, R>
74where
75 R: Read + Seek,
76{
77 pub fn get_assembly_info(&mut self) -> Result<DotNetAssemblyInfo, GaiaError> {
86 if self.assembly_info.is_none() {
87 self.ensure_assembly_info_parsed()?;
88 }
89
90 self.assembly_info
91 .as_ref()
92 .cloned()
93 .ok_or_else(|| GaiaError::syntax_error("程序集信息未解析".to_string(), SourceLocation::default()))
94 }
95
96 pub fn to_clr_program(&mut self) -> Result<ClrProgram, GaiaError> {
105 if let Some(ref program) = self.clr_program {
106 return Ok(program.clone());
107 }
108
109 let program = self.parse_full_program()?;
111 self.clr_program = Some(program.clone());
112 Ok(program)
113 }
114
115 pub fn validate_assembly(&mut self) -> Result<Vec<String>, GaiaError> {
126 let mut warnings = Vec::new();
127
128 self.ensure_assembly_info_parsed()?;
130
131 if self.clr_header.is_none() {
133 warnings.push("缺少 CLR 头".to_string());
134 }
135
136 if self.metadata_header.is_none() {
138 warnings.push("缺少元数据头".to_string());
139 }
140
141 if self.stream_headers.as_ref().map_or(true, |h| h.is_empty()) {
143 warnings.push("缺少元数据流".to_string());
144 }
145
146 Ok(warnings)
147 }
148
149 pub fn get_assembly_summary(&mut self) -> String {
157 match self.get_assembly_info() {
158 Ok(info) => {
159 format!(
160 "Assembly: {}\nVersion: {}\nCulture: {}\nPublic Key Token: {}\nRuntime Version: {}",
161 info.name,
162 info.version,
163 info.culture.as_deref().unwrap_or("neutral"),
164 info.public_key_token.as_deref().unwrap_or("null"),
165 info.runtime_version.as_deref().unwrap_or("unknown")
166 )
167 }
168 Err(_) => "Unable to get assembly information".to_string(),
169 }
170 }
171
172 fn ensure_assembly_info_parsed(&mut self) -> Result<(), GaiaError> {
174 if self.assembly_info.is_some() {
175 return Ok(());
176 }
177
178 self.parse_clr_header_lazy()?;
180 self.parse_metadata_lazy()?;
181 self.extract_assembly_info()?;
182
183 Ok(())
184 }
185
186 fn parse_clr_header_lazy(&mut self) -> Result<(), GaiaError> {
188 eprintln!("Starting to parse CLR header");
189 self.clr_header = self.find_and_read_clr_header()?;
190 eprintln!("find_and_read_clr_header returned: {:?}", self.clr_header.is_some());
191 if self.clr_header.is_none() {
192 eprintln!("CLR header is empty, returning error");
193 return Err(GaiaError::syntax_error("Missing CLR header", SourceLocation::default()));
194 }
195 eprintln!("CLR header parsed successfully");
196 Ok(())
197 }
198
199 fn parse_metadata_lazy(&mut self) -> Result<(), GaiaError> {
201 if let Some(ref clr_header) = self.clr_header {
202 let pe_program = self.reader.get_program()?.clone();
204 let metadata_offset = utils::rva_to_file_offset(&pe_program, clr_header.metadata_rva)?;
205 self.metadata_header = Some(self.read_metadata_header(metadata_offset)?);
207 self.stream_headers = Some(self.read_stream_headers(metadata_offset)?);
209 }
210
211 Ok(())
212 }
213}