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)]
19pub struct DllReader<'config, R> {
20 options: &'config DllReadConfig,
22 reader: pe_assembler::formats::dll::reader::DllReader<R>,
23 clr_header: Option<ClrHeader>,
25 metadata_header: Option<MetadataHeader>,
27 stream_headers: Option<Vec<StreamHeader>>,
29 assembly_info: Option<DotNetAssemblyInfo>,
31 clr_program: Option<ClrProgram>,
33}
34
35impl<'config, R: Read + Seek> PeReader<R> for DllReader<'config, R> {
36 fn get_viewer(&mut self) -> &mut R {
37 self.reader.get_viewer()
38 }
39
40 fn add_diagnostics(&mut self, error: impl Into<GaiaError>) {
41 self.reader.add_diagnostics(error)
42 }
43
44 fn get_section_headers(&mut self) -> Result<&[SectionHeader], GaiaError> {
45 self.reader.get_section_headers()
46 }
47
48 fn get_pe_header(&mut self) -> Result<&PeHeader, GaiaError> {
49 self.reader.get_pe_header()
50 }
51
52 fn get_program(&mut self) -> Result<&PeProgram, GaiaError> {
53 self.reader.get_program()
54 }
55}
56
57impl<'config, R> DllReader<'config, R> {
58 pub fn new(reader: R, options: &'config DllReadConfig) -> Self {
62 Self {
63 reader: pe_assembler::formats::dll::reader::DllReader::new(reader),
64 clr_header: None,
65 metadata_header: None,
66 stream_headers: None,
67 assembly_info: None,
68 clr_program: None,
69 options,
70 }
71 }
72}
73
74impl<'config, R> DllReader<'config, R>
75where
76 R: Read + Seek,
77{
78 pub fn get_assembly_info(&mut self) -> Result<DotNetAssemblyInfo, GaiaError> {
87 if self.assembly_info.is_none() {
88 self.ensure_assembly_info_parsed()?;
89 }
90
91 self.assembly_info
92 .as_ref()
93 .cloned()
94 .ok_or_else(|| GaiaError::syntax_error("程序集信息未解析".to_string(), SourceLocation::default()))
95 }
96
97 pub fn to_clr_program(&mut self) -> Result<ClrProgram, GaiaError> {
106 if let Some(ref program) = self.clr_program {
107 return Ok(program.clone());
108 }
109
110 let program = self.parse_full_program()?;
112 self.clr_program = Some(program.clone());
113 Ok(program)
114 }
115
116 pub fn validate_assembly(&mut self) -> Result<Vec<String>, GaiaError> {
127 let mut warnings = Vec::new();
128
129 self.ensure_assembly_info_parsed()?;
131
132 if self.clr_header.is_none() {
134 warnings.push("缺少 CLR 头".to_string());
135 }
136
137 if self.metadata_header.is_none() {
139 warnings.push("缺少元数据头".to_string());
140 }
141
142 if self.stream_headers.as_ref().map_or(true, |h| h.is_empty()) {
144 warnings.push("缺少元数据流".to_string());
145 }
146
147 Ok(warnings)
148 }
149
150 pub fn get_assembly_summary(&mut self) -> String {
158 match self.get_assembly_info() {
159 Ok(info) => {
160 format!(
161 "Assembly: {}\nVersion: {}\nCulture: {}\nPublic Key Token: {}\nRuntime Version: {}",
162 info.name,
163 info.version,
164 info.culture.as_deref().unwrap_or("neutral"),
165 info.public_key_token.as_deref().unwrap_or("null"),
166 info.runtime_version.as_deref().unwrap_or("unknown")
167 )
168 }
169 Err(_) => "Unable to get assembly information".to_string(),
170 }
171 }
172
173 fn ensure_assembly_info_parsed(&mut self) -> Result<(), GaiaError> {
175 if self.assembly_info.is_some() {
176 return Ok(());
177 }
178
179 self.parse_clr_header_lazy()?;
181 self.parse_metadata_lazy()?;
182 self.extract_assembly_info()?;
183
184 Ok(())
185 }
186
187 fn parse_clr_header_lazy(&mut self) -> Result<(), GaiaError> {
189 eprintln!("Starting to parse CLR header");
190 self.clr_header = self.find_and_read_clr_header()?;
191 eprintln!("find_and_read_clr_header returned: {:?}", self.clr_header.is_some());
192 if self.clr_header.is_none() {
193 eprintln!("CLR header is empty, returning error");
194 return Err(GaiaError::syntax_error("Missing CLR header", SourceLocation::default()));
195 }
196 eprintln!("CLR header parsed successfully");
197 Ok(())
198 }
199
200 fn parse_metadata_lazy(&mut self) -> Result<(), GaiaError> {
202 if let Some(ref clr_header) = self.clr_header {
203 let pe_program = self.reader.get_program()?.clone();
205 let metadata_offset = utils::rva_to_file_offset(&pe_program, clr_header.metadata_rva)?;
206 self.metadata_header = Some(self.read_metadata_header(metadata_offset)?);
208 self.stream_headers = Some(self.read_stream_headers(metadata_offset)?);
210 }
211
212 Ok(())
213 }
214}