use crate::capture::types::ImplementationDifficulty;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UnknownMemoryRegionAnalysis {
pub total_unknown_bytes: usize,
pub unknown_percentage: f64,
pub unknown_categories: Vec<UnknownMemoryCategory>,
pub potential_causes: Vec<UnknownMemoryCause>,
pub reduction_strategies: Vec<UnknownRegionReductionStrategy>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UnknownMemoryCategory {
pub category_type: UnknownRegionType,
pub description: String,
pub estimated_size: usize,
pub confidence_level: f64,
pub examples: Vec<UnknownMemoryExample>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum UnknownRegionType {
MemoryMappedRegions,
ThreadLocalStorage,
DynamicLibraryRegions,
SystemReservedRegions,
JitCodeRegions,
ExternalLibraryAllocations,
GuardPages,
VdsoRegions,
AnonymousMappings,
SharedMemorySegments,
PreTrackingAllocations,
CorruptedMetadata,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UnknownMemoryExample {
pub address_range: (usize, usize),
pub size: usize,
pub suspected_origin: String,
pub access_pattern: MemoryAccessPattern,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum UnknownMemoryCause {
ForeignFunctionInterface {
library_name: String,
function_name: Option<String>,
},
MemoryMapping {
mapping_type: MappingType,
file_path: Option<String>,
},
SystemAllocations {
allocation_type: SystemAllocationType,
},
ThreadingMemory {
thread_id: Option<u64>,
memory_type: ThreadMemoryType,
},
DynamicLoading {
library_path: String,
load_time: u64,
},
InstrumentationGaps {
gap_type: InstrumentationGapType,
description: String,
},
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum MappingType {
FileMapping,
AnonymousMapping,
SharedMapping,
DeviceMapping,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum SystemAllocationType {
KernelBuffers,
DriverMemory,
SystemCaches,
HardwareReserved,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum ThreadMemoryType {
ThreadStack,
ThreadLocalStorage,
ThreadControlBlock,
ThreadSynchronization,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum InstrumentationGapType {
EarlyBootstrap,
SignalHandlers,
InterruptHandlers,
AtomicOperations,
CompilerOptimizations,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UnknownRegionReductionStrategy {
pub strategy_type: ReductionStrategyType,
pub description: String,
pub implementation_steps: Vec<String>,
pub expected_improvement: f64,
pub implementation_difficulty: ImplementationDifficulty,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum ReductionStrategyType {
EnhancedInstrumentation,
BetterSymbolResolution,
MemoryMappingTracking,
FfiCallInterception,
SystemCallMonitoring,
ThreadAwareTracking,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SystemRegionInfo {
pub region_type: String,
pub description: String,
pub read_only: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LibraryMappingInfo {
pub start_address: usize,
pub end_address: usize,
pub permissions: String,
pub file_path: String,
}
impl LibraryMappingInfo {
pub fn contains_address(&self, addr: usize) -> bool {
addr >= self.start_address && addr < self.end_address
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum MemoryAccessPattern {
Sequential,
Random,
Sparse,
Unknown,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_analysis_creation() {
let analysis = UnknownMemoryRegionAnalysis {
total_unknown_bytes: 1024,
unknown_percentage: 25.5,
unknown_categories: vec![],
potential_causes: vec![],
reduction_strategies: vec![],
};
assert_eq!(
analysis.total_unknown_bytes, 1024,
"Total bytes should match"
);
assert_eq!(analysis.unknown_percentage, 25.5, "Percentage should match");
}
#[test]
fn test_category_creation() {
let category = UnknownMemoryCategory {
category_type: UnknownRegionType::MemoryMappedRegions,
description: "Test category".to_string(),
estimated_size: 4096,
confidence_level: 0.85,
examples: vec![],
};
assert_eq!(category.estimated_size, 4096, "Size should match");
assert_eq!(category.confidence_level, 0.85, "Confidence should match");
}
#[test]
fn test_region_type_variants() {
let variants = [
UnknownRegionType::MemoryMappedRegions,
UnknownRegionType::ThreadLocalStorage,
UnknownRegionType::DynamicLibraryRegions,
UnknownRegionType::SystemReservedRegions,
UnknownRegionType::JitCodeRegions,
UnknownRegionType::ExternalLibraryAllocations,
UnknownRegionType::GuardPages,
UnknownRegionType::VdsoRegions,
UnknownRegionType::AnonymousMappings,
UnknownRegionType::SharedMemorySegments,
UnknownRegionType::PreTrackingAllocations,
UnknownRegionType::CorruptedMetadata,
];
for variant in &variants {
let debug_str = format!("{variant:?}");
assert!(
!debug_str.is_empty(),
"Variant should have debug representation"
);
}
}
#[test]
fn test_example_creation() {
let example = UnknownMemoryExample {
address_range: (0x1000, 0x2000),
size: 4096,
suspected_origin: "mmap".to_string(),
access_pattern: MemoryAccessPattern::Sequential,
};
assert_eq!(
example.address_range.0, 0x1000,
"Start address should match"
);
assert_eq!(example.size, 4096, "Size should match");
}
#[test]
fn test_cause_variants() {
let ffi_cause = UnknownMemoryCause::ForeignFunctionInterface {
library_name: "libc".to_string(),
function_name: Some("malloc".to_string()),
};
let mmap_cause = UnknownMemoryCause::MemoryMapping {
mapping_type: MappingType::AnonymousMapping,
file_path: None,
};
let system_cause = UnknownMemoryCause::SystemAllocations {
allocation_type: SystemAllocationType::KernelBuffers,
};
let thread_cause = UnknownMemoryCause::ThreadingMemory {
thread_id: Some(1),
memory_type: ThreadMemoryType::ThreadStack,
};
let dynamic_cause = UnknownMemoryCause::DynamicLoading {
library_path: "/lib/test.so".to_string(),
load_time: 1000,
};
let gap_cause = UnknownMemoryCause::InstrumentationGaps {
gap_type: InstrumentationGapType::EarlyBootstrap,
description: "Early initialization".to_string(),
};
assert!(matches!(
ffi_cause,
UnknownMemoryCause::ForeignFunctionInterface { .. }
));
assert!(matches!(
mmap_cause,
UnknownMemoryCause::MemoryMapping { .. }
));
assert!(matches!(
system_cause,
UnknownMemoryCause::SystemAllocations { .. }
));
assert!(matches!(
thread_cause,
UnknownMemoryCause::ThreadingMemory { .. }
));
assert!(matches!(
dynamic_cause,
UnknownMemoryCause::DynamicLoading { .. }
));
assert!(matches!(
gap_cause,
UnknownMemoryCause::InstrumentationGaps { .. }
));
}
#[test]
fn test_mapping_type_variants() {
assert!(matches!(MappingType::FileMapping, MappingType::FileMapping));
assert!(matches!(
MappingType::AnonymousMapping,
MappingType::AnonymousMapping
));
assert!(matches!(
MappingType::SharedMapping,
MappingType::SharedMapping
));
assert!(matches!(
MappingType::DeviceMapping,
MappingType::DeviceMapping
));
}
#[test]
fn test_system_allocation_type_variants() {
let variants = [
SystemAllocationType::KernelBuffers,
SystemAllocationType::DriverMemory,
SystemAllocationType::SystemCaches,
SystemAllocationType::HardwareReserved,
];
for variant in &variants {
let debug_str = format!("{variant:?}");
assert!(
!debug_str.is_empty(),
"Variant should have debug representation"
);
}
}
#[test]
fn test_thread_memory_type_variants() {
let variants = [
ThreadMemoryType::ThreadStack,
ThreadMemoryType::ThreadLocalStorage,
ThreadMemoryType::ThreadControlBlock,
ThreadMemoryType::ThreadSynchronization,
];
for variant in &variants {
let debug_str = format!("{variant:?}");
assert!(
!debug_str.is_empty(),
"Variant should have debug representation"
);
}
}
#[test]
fn test_instrumentation_gap_type_variants() {
let variants = [
InstrumentationGapType::EarlyBootstrap,
InstrumentationGapType::SignalHandlers,
InstrumentationGapType::InterruptHandlers,
InstrumentationGapType::AtomicOperations,
InstrumentationGapType::CompilerOptimizations,
];
for variant in &variants {
let debug_str = format!("{variant:?}");
assert!(
!debug_str.is_empty(),
"Variant should have debug representation"
);
}
}
#[test]
fn test_reduction_strategy_creation() {
let strategy = UnknownRegionReductionStrategy {
strategy_type: ReductionStrategyType::EnhancedInstrumentation,
description: "Test strategy".to_string(),
implementation_steps: vec!["Step 1".to_string(), "Step 2".to_string()],
expected_improvement: 50.0,
implementation_difficulty: ImplementationDifficulty::Medium,
};
assert_eq!(
strategy.implementation_steps.len(),
2,
"Should have two steps"
);
assert_eq!(
strategy.expected_improvement, 50.0,
"Improvement should match"
);
}
#[test]
fn test_reduction_strategy_type_variants() {
let variants = [
ReductionStrategyType::EnhancedInstrumentation,
ReductionStrategyType::BetterSymbolResolution,
ReductionStrategyType::MemoryMappingTracking,
ReductionStrategyType::FfiCallInterception,
ReductionStrategyType::SystemCallMonitoring,
ReductionStrategyType::ThreadAwareTracking,
];
for variant in &variants {
let debug_str = format!("{variant:?}");
assert!(
!debug_str.is_empty(),
"Variant should have debug representation"
);
}
}
#[test]
fn test_system_region_info_creation() {
let info = SystemRegionInfo {
region_type: "kernel".to_string(),
description: "Kernel region".to_string(),
read_only: true,
};
assert_eq!(info.region_type, "kernel", "Region type should match");
assert!(info.read_only, "Should be read-only");
}
#[test]
fn test_library_mapping_info() {
let info = LibraryMappingInfo {
start_address: 0x1000,
end_address: 0x2000,
permissions: "r-x".to_string(),
file_path: "/lib/test.so".to_string(),
};
assert!(info.contains_address(0x1000), "Start should be contained");
assert!(info.contains_address(0x1500), "Middle should be contained");
assert!(
!info.contains_address(0x2000),
"End should not be contained"
);
assert!(
!info.contains_address(0x500),
"Before should not be contained"
);
}
#[test]
fn test_memory_access_pattern_variants() {
assert!(matches!(
MemoryAccessPattern::Sequential,
MemoryAccessPattern::Sequential
));
assert!(matches!(
MemoryAccessPattern::Random,
MemoryAccessPattern::Random
));
assert!(matches!(
MemoryAccessPattern::Sparse,
MemoryAccessPattern::Sparse
));
assert!(matches!(
MemoryAccessPattern::Unknown,
MemoryAccessPattern::Unknown
));
}
#[test]
fn test_serialization() {
let analysis = UnknownMemoryRegionAnalysis {
total_unknown_bytes: 1024,
unknown_percentage: 25.5,
unknown_categories: vec![],
potential_causes: vec![],
reduction_strategies: vec![],
};
let json = serde_json::to_string(&analysis);
assert!(json.is_ok(), "Should serialize to JSON");
let deserialized: Result<UnknownMemoryRegionAnalysis, _> =
serde_json::from_str(&json.unwrap());
assert!(deserialized.is_ok(), "Should deserialize from JSON");
}
#[test]
fn test_zero_values() {
let analysis = UnknownMemoryRegionAnalysis {
total_unknown_bytes: 0,
unknown_percentage: 0.0,
unknown_categories: vec![],
potential_causes: vec![],
reduction_strategies: vec![],
};
assert_eq!(
analysis.total_unknown_bytes, 0,
"Zero bytes should be valid"
);
assert_eq!(
analysis.unknown_percentage, 0.0,
"Zero percentage should be valid"
);
}
}