1#![doc = include_str!("../README.md")]
2#![deny(missing_docs)]
3#![cfg_attr(docsrs, feature(doc_cfg))]
4
5mod control_flow_cache;
6pub mod control_flow_handler;
7mod diagnose;
8pub mod error;
9pub mod memory_reader;
10mod static_analyzer;
11mod tnt_buffer;
12
13use std::num::NonZero;
14
15use iptr_decoder::{DecoderContext, HandlePacket, IpReconstructionPattern};
16
17#[cfg(feature = "cache")]
18use crate::control_flow_cache::ControlFlowCacheManager;
19pub use crate::{
20 control_flow_handler::{ControlFlowTransitionKind, HandleControlFlow},
21 diagnose::DiagnosticInformation,
22 memory_reader::ReadMemory,
23};
24use crate::{
25 error::{AnalyzerError, AnalyzerResult},
26 static_analyzer::StaticControlFlowAnalyzer,
27 tnt_buffer::TntBufferManager,
28};
29
30#[derive(Clone, Copy, Debug)]
32enum TntProceed {
33 Continue,
36 Break {
39 processed_bit_count: u32,
42 },
43}
44
45#[derive(Clone, Copy, Debug)]
47enum PreTipStatus {
48 Normal,
55 PendingIndirect,
57 PendingFup,
60 PendingOvf,
63}
64
65pub struct EdgeAnalyzer<H: HandleControlFlow, R: ReadMemory> {
71 last_ip: u64,
77 last_bb: Option<NonZero<u64>>,
88 pre_tip_status: PreTipStatus,
90 tnt_buffer_manager: TntBufferManager,
92 #[cfg(feature = "cache")]
94 cache_manager: ControlFlowCacheManager<Option<H::CachedKey>>,
95 static_analyzer: StaticControlFlowAnalyzer,
97 #[cfg(all(feature = "cache", feature = "more_diagnose"))]
99 cache_trailing_bits_hit_count: usize,
100 #[cfg(all(feature = "cache", feature = "more_diagnose"))]
102 cache_8bit_hit_count: usize,
103 #[cfg(all(feature = "cache", feature = "more_diagnose"))]
105 cache_32bit_hit_count: usize,
106 #[cfg(all(feature = "cache", feature = "more_diagnose"))]
108 cache_missed_bit_count: usize,
109 handler: H,
111 reader: R,
113}
114
115impl<H: HandleControlFlow, R: ReadMemory> EdgeAnalyzer<H, R> {
116 #[must_use]
118 pub fn new(handler: H, reader: R) -> Self {
119 Self {
120 last_ip: 0,
121 last_bb: None,
122 pre_tip_status: PreTipStatus::Normal,
123 tnt_buffer_manager: TntBufferManager::new(),
124 #[cfg(feature = "cache")]
125 cache_manager: ControlFlowCacheManager::new(),
126 static_analyzer: StaticControlFlowAnalyzer::new(),
127 #[cfg(all(feature = "cache", feature = "more_diagnose"))]
128 cache_32bit_hit_count: 0,
129 #[cfg(all(feature = "cache", feature = "more_diagnose"))]
130 cache_8bit_hit_count: 0,
131 #[cfg(all(feature = "cache", feature = "more_diagnose"))]
132 cache_trailing_bits_hit_count: 0,
133 #[cfg(all(feature = "cache", feature = "more_diagnose"))]
134 cache_missed_bit_count: 0,
135 handler,
136 reader,
137 }
138 }
139
140 pub fn into_handler_and_reader(self) -> (H, R) {
142 (self.handler, self.reader)
143 }
144
145 pub fn handler(&self) -> &H {
147 &self.handler
148 }
149
150 pub fn reader(&self) -> &R {
152 &self.reader
153 }
154
155 fn reconstruct_ip_and_update_last(
158 &mut self,
159 ip_reconstruction_pattern: IpReconstructionPattern,
160 ) -> Option<u64> {
161 if !iptr_decoder::utils::reconstruct_ip_and_update_last(
162 &mut self.last_ip,
163 ip_reconstruction_pattern,
164 ) {
165 return None;
166 }
167
168 Some(self.last_ip)
169 }
170
171 #[expect(
179 clippy::enum_glob_use,
180 clippy::items_after_statements,
181 clippy::needless_continue
182 )]
183 fn process_tnt_bit_without_querying_cache(
184 &mut self,
185 context: &DecoderContext,
186 last_bb_ref: &mut u64,
187 is_taken: bool,
188 ) -> AnalyzerResult<TntProceed, H, R> {
189 #[cfg(all(feature = "cache", feature = "more_diagnose"))]
190 {
191 self.cache_missed_bit_count += 1;
192 }
193 let mut last_bb = *last_bb_ref;
194 let mut tnt_bit_processed = false;
195 let tnt_proceed;
196 'cfg_traverse: loop {
197 let cfg_node =
198 self.static_analyzer
199 .resolve(&mut self.reader, context.tracee_mode(), last_bb)?;
200 let terminator = cfg_node.terminator;
201 use static_analyzer::CfgTerminator::*;
202 match terminator {
203 Branch { r#true, r#false } => {
204 if tnt_bit_processed {
205 tnt_proceed = TntProceed::Continue;
206 break 'cfg_traverse;
207 }
208 let r#false = r#false as u64 | (r#true & 0xFFFF_FFFF_0000_0000);
209 last_bb = if is_taken { r#true } else { r#false };
210 self.handler
211 .on_new_block(last_bb, ControlFlowTransitionKind::ConditionalBranch, true)
212 .map_err(AnalyzerError::ControlFlowHandler)?;
213 tnt_bit_processed = true;
214 continue 'cfg_traverse;
216 }
217 DirectGoto { target } => {
218 last_bb = target;
219 self.handler
220 .on_new_block(last_bb, ControlFlowTransitionKind::DirectJump, true)
221 .map_err(AnalyzerError::ControlFlowHandler)?;
222 continue 'cfg_traverse;
223 }
224 DirectCall { target } => {
225 last_bb = target;
226 self.handler
227 .on_new_block(last_bb, ControlFlowTransitionKind::DirectCall, true)
228 .map_err(AnalyzerError::ControlFlowHandler)?;
229 continue 'cfg_traverse;
230 }
231 IndirectGoto
232 | IndirectCall
233 | FarTransfers {
234 next_instruction: _,
235 } => {
236 if tnt_bit_processed {
237 tnt_proceed = TntProceed::Continue;
238 break 'cfg_traverse;
239 }
240 tnt_proceed = TntProceed::Break {
242 processed_bit_count: 0,
243 };
244 break 'cfg_traverse;
245 }
246 NearRet => {
247 if tnt_bit_processed {
248 tnt_proceed = TntProceed::Continue;
249 break 'cfg_traverse;
250 }
251 if !is_taken {
252 return Err(AnalyzerError::InvalidPacket);
255 }
256 return Err(AnalyzerError::UnsupportedReturnCompression);
257 }
258 }
259 }
260 *last_bb_ref = last_bb;
261
262 Ok(tnt_proceed)
263 }
264
265 fn process_all_pending_tnts(&mut self, context: &DecoderContext) -> AnalyzerResult<(), H, R> {
267 let Some(last_bb) = self.last_bb else {
268 return Ok(());
269 };
270 let mut last_bb = last_bb.get();
273 let tnt_buffer = self.tnt_buffer_manager.take();
275 let res = self.handle_maybe_full_tnt_buffer(context, &mut last_bb, tnt_buffer);
276 self.last_bb = NonZero::new(last_bb);
277 res
278 }
279
280 #[expect(clippy::redundant_else)]
283 fn handle_tip_or_tip_pgd_packet(
284 &mut self,
285 context: &DecoderContext,
286 ip_reconstruction_pattern: IpReconstructionPattern,
287 is_pgd: bool,
288 ) -> AnalyzerResult<(), H, R> {
289 let Some(new_last_bb) = self.reconstruct_ip_and_update_last(ip_reconstruction_pattern)
290 else {
291 if is_pgd {
293 self.pre_tip_status = PreTipStatus::Normal;
295 return Ok(());
296 } else {
297 return Err(AnalyzerError::InvalidPacket);
299 }
300 };
301 self.process_all_pending_tnts(context)?;
307 self.last_bb = NonZero::new(new_last_bb);
308 match self.pre_tip_status {
309 PreTipStatus::Normal | PreTipStatus::PendingIndirect => {
310 self.handler
311 .on_new_block(new_last_bb, ControlFlowTransitionKind::Indirect, false)
312 .map_err(AnalyzerError::ControlFlowHandler)?;
313 self.pre_tip_status = PreTipStatus::Normal;
314 }
315 PreTipStatus::PendingFup => {
316 self.handler
317 .on_new_block(new_last_bb, ControlFlowTransitionKind::NewBlock, false)
318 .map_err(AnalyzerError::ControlFlowHandler)?;
319 self.pre_tip_status = PreTipStatus::Normal;
320 self.tnt_buffer_manager.clear();
321 return Ok(());
322 }
323 PreTipStatus::PendingOvf => {
324 return Err(AnalyzerError::InvalidPacket);
326 }
327 }
328
329 Ok(())
330 }
331}
332
333impl<H, R> HandlePacket for EdgeAnalyzer<H, R>
334where
335 H: HandleControlFlow,
336 R: ReadMemory,
337 AnalyzerError<H, R>: std::error::Error,
338{
339 type Error = AnalyzerError<H, R>;
340
341 fn at_decode_begin(&mut self) -> Result<(), Self::Error> {
342 self.last_ip = 0;
343 self.last_bb = None;
344 self.pre_tip_status = PreTipStatus::Normal;
345 self.tnt_buffer_manager.clear();
346 self.handler
347 .at_decode_begin()
348 .map_err(AnalyzerError::ControlFlowHandler)?;
349 self.reader
350 .at_decode_begin()
351 .map_err(AnalyzerError::MemoryReader)?;
352 #[cfg(all(feature = "cache", feature = "more_diagnose"))]
353 {
354 self.cache_32bit_hit_count = 0;
355 self.cache_8bit_hit_count = 0;
356 self.cache_trailing_bits_hit_count = 0;
357 self.cache_missed_bit_count = 0;
358 }
359
360 Ok(())
361 }
362
363 fn on_short_tnt_packet(
364 &mut self,
365 context: &DecoderContext,
366 packet_byte: NonZero<u8>,
367 highest_bit: u32,
368 ) -> Result<(), Self::Error> {
369 if highest_bit == 0 {
370 return Ok(());
372 }
373 let Some(last_bb) = self.last_bb else {
374 return Ok(());
376 };
377 let mut last_bb = last_bb.get();
378 if let Some(full_tnt_buffer) = self.tnt_buffer_manager.extend_with_short_tnt(packet_byte) {
379 let res = self.handle_full_tnt_buffer(context, &mut last_bb, full_tnt_buffer);
380 self.last_bb = NonZero::new(last_bb);
381 res?;
382 }
383
384 Ok(())
385 }
386
387 fn on_long_tnt_packet(
388 &mut self,
389 context: &DecoderContext,
390 packet_bytes: NonZero<u64>,
391 highest_bit: u32,
392 ) -> Result<(), Self::Error> {
393 if highest_bit == u32::MAX {
394 return Ok(());
396 }
397 let Some(last_bb) = self.last_bb else {
398 return Ok(());
400 };
401 let mut last_bb = last_bb.get();
402 if let Some(full_tnt_buffer) = self.tnt_buffer_manager.extend_with_long_tnt(packet_bytes) {
403 let res = self.handle_full_tnt_buffer(context, &mut last_bb, full_tnt_buffer);
404 self.last_bb = NonZero::new(last_bb);
405 res?;
406 }
407
408 Ok(())
409 }
410
411 fn on_tip_packet(
412 &mut self,
413 context: &DecoderContext,
414 ip_reconstruction_pattern: IpReconstructionPattern,
415 ) -> Result<(), Self::Error> {
416 self.handle_tip_or_tip_pgd_packet(context, ip_reconstruction_pattern, false)?;
417 Ok(())
418 }
419
420 fn on_tip_pgd_packet(
421 &mut self,
422 context: &DecoderContext,
423 ip_reconstruction_pattern: IpReconstructionPattern,
424 ) -> Result<(), Self::Error> {
425 self.handle_tip_or_tip_pgd_packet(context, ip_reconstruction_pattern, true)?;
426
427 self.last_bb = None;
428 self.tnt_buffer_manager.clear();
429 Ok(())
430 }
431
432 fn on_tip_pge_packet(
433 &mut self,
434 _context: &DecoderContext,
435 ip_reconstruction_pattern: IpReconstructionPattern,
436 ) -> Result<(), Self::Error> {
437 if matches!(self.pre_tip_status, PreTipStatus::PendingOvf) {
438 let Some(last_bb) = self.reconstruct_ip_and_update_last(ip_reconstruction_pattern)
439 else {
440 return Err(AnalyzerError::InvalidPacket);
443 };
444 self.last_bb = NonZero::new(last_bb);
445 self.pre_tip_status = PreTipStatus::Normal;
446 self.tnt_buffer_manager.clear();
447 self.handler
448 .on_new_block(last_bb, ControlFlowTransitionKind::NewBlock, false)
449 .map_err(AnalyzerError::ControlFlowHandler)?;
450 return Ok(());
451 }
452 if let Some(last_bb) = self.reconstruct_ip_and_update_last(ip_reconstruction_pattern) {
453 self.last_bb = NonZero::new(last_bb);
454 self.handler
455 .on_new_block(last_bb, ControlFlowTransitionKind::NewBlock, false)
456 .map_err(AnalyzerError::ControlFlowHandler)?;
457 }
458 self.pre_tip_status = PreTipStatus::Normal;
459 self.tnt_buffer_manager.clear();
460
461 Ok(())
462 }
463
464 fn on_fup_packet(
465 &mut self,
466 _context: &DecoderContext,
467 ip_reconstruction_pattern: IpReconstructionPattern,
468 ) -> Result<(), Self::Error> {
469 if matches!(self.pre_tip_status, PreTipStatus::PendingOvf) {
470 self.pre_tip_status = PreTipStatus::Normal;
471 let Some(last_bb) = self.reconstruct_ip_and_update_last(ip_reconstruction_pattern)
472 else {
473 return Err(AnalyzerError::InvalidPacket);
476 };
477 self.last_bb = NonZero::new(last_bb);
478 self.tnt_buffer_manager.clear();
479
480 return Ok(());
481 }
482 self.reconstruct_ip_and_update_last(ip_reconstruction_pattern);
483 self.pre_tip_status = PreTipStatus::PendingFup;
484
485 Ok(())
486 }
487
488 fn on_ovf_packet(&mut self, _context: &DecoderContext) -> Result<(), Self::Error> {
489 self.pre_tip_status = PreTipStatus::PendingOvf;
490 Ok(())
491 }
492
493 fn on_psb_packet(&mut self, _context: &DecoderContext) -> Result<(), Self::Error> {
494 self.last_bb = None;
495 self.last_ip = 0;
496 self.pre_tip_status = PreTipStatus::Normal;
497 self.tnt_buffer_manager.clear();
498
499 Ok(())
500 }
501}