Skip to main content

memscope_rs/analysis/unknown/
types.rs

1use crate::capture::types::ImplementationDifficulty;
2use serde::{Deserialize, Serialize};
3
4#[derive(Debug, Clone, Serialize, Deserialize)]
5pub struct UnknownMemoryRegionAnalysis {
6    pub total_unknown_bytes: usize,
7    pub unknown_percentage: f64,
8    pub unknown_categories: Vec<UnknownMemoryCategory>,
9    pub potential_causes: Vec<UnknownMemoryCause>,
10    pub reduction_strategies: Vec<UnknownRegionReductionStrategy>,
11}
12
13#[derive(Debug, Clone, Serialize, Deserialize)]
14pub struct UnknownMemoryCategory {
15    pub category_type: UnknownRegionType,
16    pub description: String,
17    pub estimated_size: usize,
18    pub confidence_level: f64,
19    pub examples: Vec<UnknownMemoryExample>,
20}
21
22#[derive(Debug, Clone, Serialize, Deserialize)]
23pub enum UnknownRegionType {
24    MemoryMappedRegions,
25    ThreadLocalStorage,
26    DynamicLibraryRegions,
27    SystemReservedRegions,
28    JitCodeRegions,
29    ExternalLibraryAllocations,
30    GuardPages,
31    VdsoRegions,
32    AnonymousMappings,
33    SharedMemorySegments,
34    PreTrackingAllocations,
35    CorruptedMetadata,
36}
37
38#[derive(Debug, Clone, Serialize, Deserialize)]
39pub struct UnknownMemoryExample {
40    pub address_range: (usize, usize),
41    pub size: usize,
42    pub suspected_origin: String,
43    pub access_pattern: MemoryAccessPattern,
44}
45
46#[derive(Debug, Clone, Serialize, Deserialize)]
47pub enum UnknownMemoryCause {
48    ForeignFunctionInterface {
49        library_name: String,
50        function_name: Option<String>,
51    },
52    MemoryMapping {
53        mapping_type: MappingType,
54        file_path: Option<String>,
55    },
56    SystemAllocations {
57        allocation_type: SystemAllocationType,
58    },
59    ThreadingMemory {
60        thread_id: Option<u64>,
61        memory_type: ThreadMemoryType,
62    },
63    DynamicLoading {
64        library_path: String,
65        load_time: u64,
66    },
67    InstrumentationGaps {
68        gap_type: InstrumentationGapType,
69        description: String,
70    },
71}
72
73#[derive(Debug, Clone, Serialize, Deserialize)]
74pub enum MappingType {
75    FileMapping,
76    AnonymousMapping,
77    SharedMapping,
78    DeviceMapping,
79}
80
81#[derive(Debug, Clone, Serialize, Deserialize)]
82pub enum SystemAllocationType {
83    KernelBuffers,
84    DriverMemory,
85    SystemCaches,
86    HardwareReserved,
87}
88
89#[derive(Debug, Clone, Serialize, Deserialize)]
90pub enum ThreadMemoryType {
91    ThreadStack,
92    ThreadLocalStorage,
93    ThreadControlBlock,
94    ThreadSynchronization,
95}
96
97#[derive(Debug, Clone, Serialize, Deserialize)]
98pub enum InstrumentationGapType {
99    EarlyBootstrap,
100    SignalHandlers,
101    InterruptHandlers,
102    AtomicOperations,
103    CompilerOptimizations,
104}
105
106#[derive(Debug, Clone, Serialize, Deserialize)]
107pub struct UnknownRegionReductionStrategy {
108    pub strategy_type: ReductionStrategyType,
109    pub description: String,
110    pub implementation_steps: Vec<String>,
111    pub expected_improvement: f64,
112    pub implementation_difficulty: ImplementationDifficulty,
113}
114
115#[derive(Debug, Clone, Serialize, Deserialize)]
116pub enum ReductionStrategyType {
117    EnhancedInstrumentation,
118    BetterSymbolResolution,
119    MemoryMappingTracking,
120    FfiCallInterception,
121    SystemCallMonitoring,
122    ThreadAwareTracking,
123}
124
125#[derive(Debug, Clone, Serialize, Deserialize)]
126pub struct SystemRegionInfo {
127    pub region_type: String,
128    pub description: String,
129    pub read_only: bool,
130}
131
132#[derive(Debug, Clone, Serialize, Deserialize)]
133pub struct LibraryMappingInfo {
134    pub start_address: usize,
135    pub end_address: usize,
136    pub permissions: String,
137    pub file_path: String,
138}
139
140impl LibraryMappingInfo {
141    pub fn contains_address(&self, addr: usize) -> bool {
142        addr >= self.start_address && addr < self.end_address
143    }
144}
145
146#[derive(Debug, Clone, Serialize, Deserialize)]
147pub enum MemoryAccessPattern {
148    Sequential,
149    Random,
150    Sparse,
151    Unknown,
152}
153
154#[cfg(test)]
155mod tests {
156    use super::*;
157
158    /// Objective: Verify UnknownMemoryRegionAnalysis creation
159    /// Invariants: All fields should be properly initialized
160    #[test]
161    fn test_analysis_creation() {
162        let analysis = UnknownMemoryRegionAnalysis {
163            total_unknown_bytes: 1024,
164            unknown_percentage: 25.5,
165            unknown_categories: vec![],
166            potential_causes: vec![],
167            reduction_strategies: vec![],
168        };
169
170        assert_eq!(
171            analysis.total_unknown_bytes, 1024,
172            "Total bytes should match"
173        );
174        assert_eq!(analysis.unknown_percentage, 25.5, "Percentage should match");
175    }
176
177    /// Objective: Verify UnknownMemoryCategory creation
178    /// Invariants: All fields should be accessible
179    #[test]
180    fn test_category_creation() {
181        let category = UnknownMemoryCategory {
182            category_type: UnknownRegionType::MemoryMappedRegions,
183            description: "Test category".to_string(),
184            estimated_size: 4096,
185            confidence_level: 0.85,
186            examples: vec![],
187        };
188
189        assert_eq!(category.estimated_size, 4096, "Size should match");
190        assert_eq!(category.confidence_level, 0.85, "Confidence should match");
191    }
192
193    /// Objective: Verify UnknownRegionType variants
194    /// Invariants: All variants should be distinct
195    #[test]
196    fn test_region_type_variants() {
197        let variants = [
198            UnknownRegionType::MemoryMappedRegions,
199            UnknownRegionType::ThreadLocalStorage,
200            UnknownRegionType::DynamicLibraryRegions,
201            UnknownRegionType::SystemReservedRegions,
202            UnknownRegionType::JitCodeRegions,
203            UnknownRegionType::ExternalLibraryAllocations,
204            UnknownRegionType::GuardPages,
205            UnknownRegionType::VdsoRegions,
206            UnknownRegionType::AnonymousMappings,
207            UnknownRegionType::SharedMemorySegments,
208            UnknownRegionType::PreTrackingAllocations,
209            UnknownRegionType::CorruptedMetadata,
210        ];
211
212        for variant in &variants {
213            let debug_str = format!("{variant:?}");
214            assert!(
215                !debug_str.is_empty(),
216                "Variant should have debug representation"
217            );
218        }
219    }
220
221    /// Objective: Verify UnknownMemoryExample creation
222    /// Invariants: All fields should be properly initialized
223    #[test]
224    fn test_example_creation() {
225        let example = UnknownMemoryExample {
226            address_range: (0x1000, 0x2000),
227            size: 4096,
228            suspected_origin: "mmap".to_string(),
229            access_pattern: MemoryAccessPattern::Sequential,
230        };
231
232        assert_eq!(
233            example.address_range.0, 0x1000,
234            "Start address should match"
235        );
236        assert_eq!(example.size, 4096, "Size should match");
237    }
238
239    /// Objective: Verify UnknownMemoryCause variants
240    /// Invariants: All variants should be constructible
241    #[test]
242    fn test_cause_variants() {
243        let ffi_cause = UnknownMemoryCause::ForeignFunctionInterface {
244            library_name: "libc".to_string(),
245            function_name: Some("malloc".to_string()),
246        };
247
248        let mmap_cause = UnknownMemoryCause::MemoryMapping {
249            mapping_type: MappingType::AnonymousMapping,
250            file_path: None,
251        };
252
253        let system_cause = UnknownMemoryCause::SystemAllocations {
254            allocation_type: SystemAllocationType::KernelBuffers,
255        };
256
257        let thread_cause = UnknownMemoryCause::ThreadingMemory {
258            thread_id: Some(1),
259            memory_type: ThreadMemoryType::ThreadStack,
260        };
261
262        let dynamic_cause = UnknownMemoryCause::DynamicLoading {
263            library_path: "/lib/test.so".to_string(),
264            load_time: 1000,
265        };
266
267        let gap_cause = UnknownMemoryCause::InstrumentationGaps {
268            gap_type: InstrumentationGapType::EarlyBootstrap,
269            description: "Early initialization".to_string(),
270        };
271
272        assert!(matches!(
273            ffi_cause,
274            UnknownMemoryCause::ForeignFunctionInterface { .. }
275        ));
276        assert!(matches!(
277            mmap_cause,
278            UnknownMemoryCause::MemoryMapping { .. }
279        ));
280        assert!(matches!(
281            system_cause,
282            UnknownMemoryCause::SystemAllocations { .. }
283        ));
284        assert!(matches!(
285            thread_cause,
286            UnknownMemoryCause::ThreadingMemory { .. }
287        ));
288        assert!(matches!(
289            dynamic_cause,
290            UnknownMemoryCause::DynamicLoading { .. }
291        ));
292        assert!(matches!(
293            gap_cause,
294            UnknownMemoryCause::InstrumentationGaps { .. }
295        ));
296    }
297
298    /// Objective: Verify MappingType variants
299    /// Invariants: All variants should be distinct
300    #[test]
301    fn test_mapping_type_variants() {
302        assert!(matches!(MappingType::FileMapping, MappingType::FileMapping));
303        assert!(matches!(
304            MappingType::AnonymousMapping,
305            MappingType::AnonymousMapping
306        ));
307        assert!(matches!(
308            MappingType::SharedMapping,
309            MappingType::SharedMapping
310        ));
311        assert!(matches!(
312            MappingType::DeviceMapping,
313            MappingType::DeviceMapping
314        ));
315    }
316
317    /// Objective: Verify SystemAllocationType variants
318    /// Invariants: All variants should be distinct
319    #[test]
320    fn test_system_allocation_type_variants() {
321        let variants = [
322            SystemAllocationType::KernelBuffers,
323            SystemAllocationType::DriverMemory,
324            SystemAllocationType::SystemCaches,
325            SystemAllocationType::HardwareReserved,
326        ];
327
328        for variant in &variants {
329            let debug_str = format!("{variant:?}");
330            assert!(
331                !debug_str.is_empty(),
332                "Variant should have debug representation"
333            );
334        }
335    }
336
337    /// Objective: Verify ThreadMemoryType variants
338    /// Invariants: All variants should be distinct
339    #[test]
340    fn test_thread_memory_type_variants() {
341        let variants = [
342            ThreadMemoryType::ThreadStack,
343            ThreadMemoryType::ThreadLocalStorage,
344            ThreadMemoryType::ThreadControlBlock,
345            ThreadMemoryType::ThreadSynchronization,
346        ];
347
348        for variant in &variants {
349            let debug_str = format!("{variant:?}");
350            assert!(
351                !debug_str.is_empty(),
352                "Variant should have debug representation"
353            );
354        }
355    }
356
357    /// Objective: Verify InstrumentationGapType variants
358    /// Invariants: All variants should be distinct
359    #[test]
360    fn test_instrumentation_gap_type_variants() {
361        let variants = [
362            InstrumentationGapType::EarlyBootstrap,
363            InstrumentationGapType::SignalHandlers,
364            InstrumentationGapType::InterruptHandlers,
365            InstrumentationGapType::AtomicOperations,
366            InstrumentationGapType::CompilerOptimizations,
367        ];
368
369        for variant in &variants {
370            let debug_str = format!("{variant:?}");
371            assert!(
372                !debug_str.is_empty(),
373                "Variant should have debug representation"
374            );
375        }
376    }
377
378    /// Objective: Verify UnknownRegionReductionStrategy creation
379    /// Invariants: All fields should be accessible
380    #[test]
381    fn test_reduction_strategy_creation() {
382        let strategy = UnknownRegionReductionStrategy {
383            strategy_type: ReductionStrategyType::EnhancedInstrumentation,
384            description: "Test strategy".to_string(),
385            implementation_steps: vec!["Step 1".to_string(), "Step 2".to_string()],
386            expected_improvement: 50.0,
387            implementation_difficulty: ImplementationDifficulty::Medium,
388        };
389
390        assert_eq!(
391            strategy.implementation_steps.len(),
392            2,
393            "Should have two steps"
394        );
395        assert_eq!(
396            strategy.expected_improvement, 50.0,
397            "Improvement should match"
398        );
399    }
400
401    /// Objective: Verify ReductionStrategyType variants
402    /// Invariants: All variants should be distinct
403    #[test]
404    fn test_reduction_strategy_type_variants() {
405        let variants = [
406            ReductionStrategyType::EnhancedInstrumentation,
407            ReductionStrategyType::BetterSymbolResolution,
408            ReductionStrategyType::MemoryMappingTracking,
409            ReductionStrategyType::FfiCallInterception,
410            ReductionStrategyType::SystemCallMonitoring,
411            ReductionStrategyType::ThreadAwareTracking,
412        ];
413
414        for variant in &variants {
415            let debug_str = format!("{variant:?}");
416            assert!(
417                !debug_str.is_empty(),
418                "Variant should have debug representation"
419            );
420        }
421    }
422
423    /// Objective: Verify SystemRegionInfo creation
424    /// Invariants: All fields should be accessible
425    #[test]
426    fn test_system_region_info_creation() {
427        let info = SystemRegionInfo {
428            region_type: "kernel".to_string(),
429            description: "Kernel region".to_string(),
430            read_only: true,
431        };
432
433        assert_eq!(info.region_type, "kernel", "Region type should match");
434        assert!(info.read_only, "Should be read-only");
435    }
436
437    /// Objective: Verify LibraryMappingInfo creation and contains_address
438    /// Invariants: Address bounds should be correctly checked
439    #[test]
440    fn test_library_mapping_info() {
441        let info = LibraryMappingInfo {
442            start_address: 0x1000,
443            end_address: 0x2000,
444            permissions: "r-x".to_string(),
445            file_path: "/lib/test.so".to_string(),
446        };
447
448        assert!(info.contains_address(0x1000), "Start should be contained");
449        assert!(info.contains_address(0x1500), "Middle should be contained");
450        assert!(
451            !info.contains_address(0x2000),
452            "End should not be contained"
453        );
454        assert!(
455            !info.contains_address(0x500),
456            "Before should not be contained"
457        );
458    }
459
460    /// Objective: Verify MemoryAccessPattern variants
461    /// Invariants: All variants should be distinct
462    #[test]
463    fn test_memory_access_pattern_variants() {
464        assert!(matches!(
465            MemoryAccessPattern::Sequential,
466            MemoryAccessPattern::Sequential
467        ));
468        assert!(matches!(
469            MemoryAccessPattern::Random,
470            MemoryAccessPattern::Random
471        ));
472        assert!(matches!(
473            MemoryAccessPattern::Sparse,
474            MemoryAccessPattern::Sparse
475        ));
476        assert!(matches!(
477            MemoryAccessPattern::Unknown,
478            MemoryAccessPattern::Unknown
479        ));
480    }
481
482    /// Objective: Verify serialization of types
483    /// Invariants: Types should serialize and deserialize correctly
484    #[test]
485    fn test_serialization() {
486        let analysis = UnknownMemoryRegionAnalysis {
487            total_unknown_bytes: 1024,
488            unknown_percentage: 25.5,
489            unknown_categories: vec![],
490            potential_causes: vec![],
491            reduction_strategies: vec![],
492        };
493
494        let json = serde_json::to_string(&analysis);
495        assert!(json.is_ok(), "Should serialize to JSON");
496
497        let deserialized: Result<UnknownMemoryRegionAnalysis, _> =
498            serde_json::from_str(&json.unwrap());
499        assert!(deserialized.is_ok(), "Should deserialize from JSON");
500    }
501
502    /// Objective: Verify edge case with zero values
503    /// Invariants: Should handle zero values correctly
504    #[test]
505    fn test_zero_values() {
506        let analysis = UnknownMemoryRegionAnalysis {
507            total_unknown_bytes: 0,
508            unknown_percentage: 0.0,
509            unknown_categories: vec![],
510            potential_causes: vec![],
511            reduction_strategies: vec![],
512        };
513
514        assert_eq!(
515            analysis.total_unknown_bytes, 0,
516            "Zero bytes should be valid"
517        );
518        assert_eq!(
519            analysis.unknown_percentage, 0.0,
520            "Zero percentage should be valid"
521        );
522    }
523}