1#![allow(clippy::unwrap_used, clippy::expect_used)]
10
11#[derive(Default)]
21pub struct LimeBuilder {
22 ranges: Vec<(u64, Vec<u8>)>,
23}
24
25impl LimeBuilder {
26 pub fn new() -> Self {
28 Self { ranges: Vec::new() }
29 }
30
31 pub fn add_range(mut self, start: u64, data: &[u8]) -> Self {
33 self.ranges.push((start, data.to_vec()));
34 self
35 }
36
37 pub fn build(self) -> Vec<u8> {
39 const MAGIC: u32 = 0x4C694D45;
40 const VERSION: u32 = 1;
41
42 let mut out = Vec::new();
43 for (start, data) in &self.ranges {
44 let e_addr = start + data.len() as u64 - 1; out.extend_from_slice(&MAGIC.to_le_bytes());
46 out.extend_from_slice(&VERSION.to_le_bytes());
47 out.extend_from_slice(&start.to_le_bytes());
48 out.extend_from_slice(&e_addr.to_le_bytes());
49 out.extend_from_slice(&0u64.to_le_bytes()); out.extend_from_slice(data);
51 }
52 out
53 }
54}
55
56#[derive(Default)]
67pub struct AvmlBuilder {
68 ranges: Vec<(u64, Vec<u8>)>,
69}
70
71impl AvmlBuilder {
72 pub fn new() -> Self {
74 Self { ranges: Vec::new() }
75 }
76
77 pub fn add_range(mut self, start: u64, data: &[u8]) -> Self {
79 self.ranges.push((start, data.to_vec()));
80 self
81 }
82
83 pub fn build(self) -> Vec<u8> {
85 const MAGIC: u32 = 0x4C4D5641;
86 const VERSION: u32 = 2;
87
88 let mut out = Vec::new();
89 for (start, data) in &self.ranges {
90 let e_addr = start + data.len() as u64; let uncompressed_size = data.len() as u64;
92
93 let mut encoder = snap::raw::Encoder::new();
94 let compressed = encoder.compress_vec(data).expect("snappy compress");
95
96 out.extend_from_slice(&MAGIC.to_le_bytes());
97 out.extend_from_slice(&VERSION.to_le_bytes());
98 out.extend_from_slice(&start.to_le_bytes());
99 out.extend_from_slice(&e_addr.to_le_bytes());
100 out.extend_from_slice(&0u64.to_le_bytes()); out.extend_from_slice(&compressed);
102 out.extend_from_slice(&uncompressed_size.to_le_bytes()); }
104 out
105 }
106}
107
108pub struct CrashDumpBuilder {
126 runs: Vec<(u64, Vec<u8>)>,
127 cr3: u64,
128 ps_active_process_head: u64,
129 ps_loaded_module_list: u64,
130 kd_debugger_data_block: u64,
131 machine_type: u32,
132 num_processors: u32,
133 dump_type: u32,
134 system_time: u64,
135}
136
137impl Default for CrashDumpBuilder {
138 fn default() -> Self {
139 Self {
140 runs: Vec::new(),
141 cr3: 0x0018_7000,
142 ps_active_process_head: 0xFFFFF802_1A2B3C40,
143 ps_loaded_module_list: 0xFFFFF802_1A2B3D60,
144 kd_debugger_data_block: 0xFFFFF802_1A000000,
145 machine_type: 0x8664, num_processors: 4,
147 dump_type: 0x01, system_time: 0x01DA_5678_9ABC_DEF0,
149 }
150 }
151}
152
153impl CrashDumpBuilder {
154 pub fn new() -> Self {
156 Self::default()
157 }
158
159 pub fn add_run(mut self, base_page: u64, data: &[u8]) -> Self {
162 assert!(
163 data.len() % 4096 == 0,
164 "run data length must be a multiple of 4096"
165 );
166 self.runs.push((base_page, data.to_vec()));
167 self
168 }
169
170 pub fn cr3(mut self, val: u64) -> Self {
172 self.cr3 = val;
173 self
174 }
175
176 pub fn ps_active_process_head(mut self, val: u64) -> Self {
178 self.ps_active_process_head = val;
179 self
180 }
181
182 pub fn ps_loaded_module_list(mut self, val: u64) -> Self {
184 self.ps_loaded_module_list = val;
185 self
186 }
187
188 pub fn kd_debugger_data_block(mut self, val: u64) -> Self {
190 self.kd_debugger_data_block = val;
191 self
192 }
193
194 pub fn machine_type(mut self, val: u32) -> Self {
196 self.machine_type = val;
197 self
198 }
199
200 pub fn num_processors(mut self, val: u32) -> Self {
202 self.num_processors = val;
203 self
204 }
205
206 pub fn dump_type(mut self, val: u32) -> Self {
208 self.dump_type = val;
209 self
210 }
211
212 pub fn system_time(mut self, val: u64) -> Self {
214 self.system_time = val;
215 self
216 }
217
218 pub fn build(self) -> Vec<u8> {
220 const PAGE_MAGIC: u32 = 0x4547_4150; const DU64_SIG: u32 = 0x3436_5544; const HEADER_SIZE: usize = 0x2000; const PAGE_SIZE: usize = 4096;
224
225 let mut header = vec![0u8; HEADER_SIZE];
226
227 header[0x000..0x004].copy_from_slice(&PAGE_MAGIC.to_le_bytes());
229 header[0x004..0x008].copy_from_slice(&DU64_SIG.to_le_bytes());
231 header[0x010..0x018].copy_from_slice(&self.cr3.to_le_bytes());
233 header[0x020..0x028].copy_from_slice(&self.ps_loaded_module_list.to_le_bytes());
235 header[0x028..0x030].copy_from_slice(&self.ps_active_process_head.to_le_bytes());
237 header[0x030..0x034].copy_from_slice(&self.machine_type.to_le_bytes());
239 header[0x034..0x038].copy_from_slice(&self.num_processors.to_le_bytes());
241 header[0x080..0x088].copy_from_slice(&self.kd_debugger_data_block.to_le_bytes());
243
244 let num_runs = self.runs.len() as u32;
246 let total_pages: u64 = self
247 .runs
248 .iter()
249 .map(|(_, d)| (d.len() / PAGE_SIZE) as u64)
250 .sum();
251 header[0x088..0x08C].copy_from_slice(&num_runs.to_le_bytes());
253 header[0x08C..0x090].copy_from_slice(&0u32.to_le_bytes());
255 header[0x090..0x098].copy_from_slice(&total_pages.to_le_bytes());
257 for (i, (base_page, data)) in self.runs.iter().enumerate() {
259 let page_count = (data.len() / PAGE_SIZE) as u64;
260 let off = 0x098 + i * 16;
261 header[off..off + 8].copy_from_slice(&base_page.to_le_bytes());
262 header[off + 8..off + 16].copy_from_slice(&page_count.to_le_bytes());
263 }
264
265 header[0xF98..0xF9C].copy_from_slice(&self.dump_type.to_le_bytes());
267 header[0xFA8..0xFB0].copy_from_slice(&self.system_time.to_le_bytes());
269
270 let is_bitmap = self.dump_type == 0x02 || self.dump_type == 0x05;
271
272 if is_bitmap {
273 self.build_bitmap(header)
274 } else {
275 self.build_run_based(header)
276 }
277 }
278
279 fn build_run_based(self, mut out: Vec<u8>) -> Vec<u8> {
281 for (_, data) in &self.runs {
282 out.extend_from_slice(data);
283 }
284 out
285 }
286
287 fn build_bitmap(self, mut out: Vec<u8>) -> Vec<u8> {
289 const DUMP_VALID: u32 = 0x504D_5544; const PAGE_SIZE: usize = 4096;
291
292 let max_pfn: u64 = self
294 .runs
295 .iter()
296 .map(|(base, data)| base + (data.len() / PAGE_SIZE) as u64)
297 .max()
298 .unwrap_or(0);
299
300 let bitmap_bits = max_pfn as usize;
302 let bitmap_bytes = bitmap_bits.div_ceil(8);
303 let bitmap_bytes_aligned = (bitmap_bytes + 7) & !7;
305
306 let mut bitmap = vec![0u8; bitmap_bytes_aligned];
307 for (base_page, data) in &self.runs {
308 let page_count = data.len() / PAGE_SIZE;
309 for p in 0..page_count {
310 let pfn = *base_page as usize + p;
311 bitmap[pfn / 8] |= 1 << (pfn % 8);
312 }
313 }
314
315 let total_set_pages: u32 = self
321 .runs
322 .iter()
323 .map(|(_, d)| (d.len() / PAGE_SIZE) as u32)
324 .sum();
325 let summary_header_size: u32 = 16; let data_offset = summary_header_size as usize + bitmap_bytes_aligned;
327
328 out.extend_from_slice(&DUMP_VALID.to_le_bytes());
329 out.extend_from_slice(&(data_offset as u32).to_le_bytes());
330 out.extend_from_slice(&(bitmap_bytes_aligned as u32).to_le_bytes());
331 out.extend_from_slice(&total_set_pages.to_le_bytes());
332 out.extend_from_slice(&bitmap);
333
334 let mut pfn_data: Vec<(u64, &[u8])> = Vec::new();
337 for (base_page, data) in &self.runs {
338 let page_count = data.len() / PAGE_SIZE;
339 for p in 0..page_count {
340 let pfn = base_page + p as u64;
341 let start = p * PAGE_SIZE;
342 pfn_data.push((pfn, &data[start..start + PAGE_SIZE]));
343 }
344 }
345 pfn_data.sort_by_key(|(pfn, _)| *pfn);
346 for (_, page) in &pfn_data {
347 out.extend_from_slice(page);
348 }
349
350 out
351 }
352}
353
354#[derive(Default)]
356pub struct ElfCoreBuilder {
357 segments: Vec<(u64, Vec<u8>)>,
358}
359
360impl ElfCoreBuilder {
361 pub fn new() -> Self {
363 Self {
364 segments: Vec::new(),
365 }
366 }
367
368 pub fn add_segment(mut self, paddr: u64, data: &[u8]) -> Self {
370 self.segments.push((paddr, data.to_vec()));
371 self
372 }
373
374 pub fn build(self) -> Vec<u8> {
376 let ehdr_size: usize = 64;
377 let phdr_size: usize = 56;
378 let phdr_count = self.segments.len();
379 let phdr_total = phdr_count * phdr_size;
380 let data_start = (ehdr_size + phdr_total).div_ceil(0x1000) * 0x1000;
381 let mut out = vec![0u8; data_start];
382
383 out[0..4].copy_from_slice(&[0x7F, b'E', b'L', b'F']);
385 out[4] = 2; out[5] = 1; out[6] = 1; out[16..18].copy_from_slice(&4u16.to_le_bytes()); out[18..20].copy_from_slice(&62u16.to_le_bytes()); out[20..24].copy_from_slice(&1u32.to_le_bytes()); out[32..40].copy_from_slice(&(ehdr_size as u64).to_le_bytes()); out[52..54].copy_from_slice(&(ehdr_size as u16).to_le_bytes()); out[54..56].copy_from_slice(&(phdr_size as u16).to_le_bytes()); out[56..58].copy_from_slice(&(phdr_count as u16).to_le_bytes()); let mut current_offset = data_start;
397 for (i, (paddr, data)) in self.segments.iter().enumerate() {
398 let phdr_off = ehdr_size + i * phdr_size;
399 out[phdr_off..phdr_off + 4].copy_from_slice(&1u32.to_le_bytes()); out[phdr_off + 4..phdr_off + 8].copy_from_slice(&6u32.to_le_bytes()); out[phdr_off + 8..phdr_off + 16]
402 .copy_from_slice(&(current_offset as u64).to_le_bytes());
403 out[phdr_off + 24..phdr_off + 32].copy_from_slice(&paddr.to_le_bytes());
404 out[phdr_off + 32..phdr_off + 40].copy_from_slice(&(data.len() as u64).to_le_bytes());
405 out[phdr_off + 40..phdr_off + 48].copy_from_slice(&(data.len() as u64).to_le_bytes());
406 out[phdr_off + 48..phdr_off + 56].copy_from_slice(&0x1000u64.to_le_bytes());
407 out.resize(current_offset + data.len(), 0);
408 out[current_offset..current_offset + data.len()].copy_from_slice(data);
409 current_offset += data.len();
410 }
411 out
412 }
413}
414
415#[derive(Default)]
440pub struct VmwareStateBuilder {
441 memory_regions: Vec<(u64, Vec<u8>)>,
442 cr3: Option<u64>,
443}
444
445impl VmwareStateBuilder {
446 pub fn new() -> Self {
448 Self {
449 memory_regions: Vec::new(),
450 cr3: None,
451 }
452 }
453
454 pub fn add_region(mut self, paddr: u64, data: &[u8]) -> Self {
456 self.memory_regions.push((paddr, data.to_vec()));
457 self
458 }
459
460 pub fn cr3(mut self, cr3: u64) -> Self {
462 self.cr3 = Some(cr3);
463 self
464 }
465
466 pub fn build(self) -> Vec<u8> {
468 let group_count: u32 = if self.cr3.is_some() { 2 } else { 1 };
469
470 let header_size = 12usize;
472 let group_entry_size = 80usize;
473 let groups_size = group_count as usize * group_entry_size;
474
475 let mut out = Vec::new();
476
477 out.extend_from_slice(&0xBED2BED0u32.to_le_bytes()); out.extend_from_slice(&0u32.to_le_bytes()); out.extend_from_slice(&group_count.to_le_bytes()); let groups_start = out.len();
484 out.resize(header_size + groups_size, 0);
485
486 let memory_tags_offset = out.len() as u64;
488
489 for (paddr, data) in &self.memory_regions {
491 let name = b"regionPPN";
493 out.push(0x06); out.push(name.len() as u8);
495 out.extend_from_slice(name);
496 out.extend_from_slice(&8u32.to_le_bytes()); out.extend_from_slice(&paddr.to_le_bytes());
498
499 let name = b"regionBytes";
501 out.push(0x06); out.push(name.len() as u8);
503 out.extend_from_slice(name);
504 let data_len = data.len() as u32;
505 out.extend_from_slice(&data_len.to_le_bytes()); out.extend_from_slice(data);
507 }
508
509 out.push(0x00);
511
512 {
514 let entry_offset = groups_start;
515 let name = b"memory";
516 out[entry_offset..entry_offset + name.len()].copy_from_slice(name);
517 let tags_off_pos = entry_offset + 64;
519 out[tags_off_pos..tags_off_pos + 8].copy_from_slice(&memory_tags_offset.to_le_bytes());
520 }
522
523 if let Some(cr3_val) = self.cr3 {
525 let cpu_tags_offset = out.len() as u64;
526
527 let name = b"CR3";
529 out.push(0x46); out.push(name.len() as u8);
531 out.extend_from_slice(name);
532 out.push(0x00); out.push(0x03); out.extend_from_slice(&cr3_val.to_le_bytes());
535
536 out.push(0x00);
538
539 let entry_offset = groups_start + group_entry_size;
541 let name = b"cpu";
542 out[entry_offset..entry_offset + name.len()].copy_from_slice(name);
543 let tags_off_pos = entry_offset + 64;
544 out[tags_off_pos..tags_off_pos + 8].copy_from_slice(&cpu_tags_offset.to_le_bytes());
545 }
546
547 out
548 }
549}
550
551fn xpress_compress_safe(data: &[u8]) -> Vec<u8> {
558 if let Ok(compressed) = lzxpress::data::compress(data) {
560 if let Ok(decompressed) = lzxpress::data::decompress(&compressed) {
562 if decompressed == data {
563 return compressed;
564 }
565 }
566 }
567
568 let mut out = Vec::with_capacity(data.len() + data.len() / 32 * 4 + 8);
572 let mut pos = 0;
573 while pos < data.len() {
574 let chunk_len = (data.len() - pos).min(32);
575 out.extend_from_slice(&0u32.to_le_bytes());
577 out.extend_from_slice(&data[pos..pos + chunk_len]);
578 pos += chunk_len;
579 }
580 out
581}
582
583pub struct HiberfilBuilder {
599 pages: Vec<(u64, [u8; 4096])>,
600 cr3: u64,
601}
602
603impl Default for HiberfilBuilder {
604 fn default() -> Self {
605 Self {
606 pages: Vec::new(),
607 cr3: 0x1ab000,
608 }
609 }
610}
611
612impl HiberfilBuilder {
613 pub fn new() -> Self {
615 Self::default()
616 }
617
618 pub fn cr3(mut self, cr3: u64) -> Self {
620 self.cr3 = cr3;
621 self
622 }
623
624 pub fn add_page(mut self, pfn: u64, data: &[u8; 4096]) -> Self {
626 self.pages.push((pfn, *data));
627 self
628 }
629
630 pub fn build(self) -> Vec<u8> {
632 const PAGE_SIZE: usize = 4096;
633 const HIBR_MAGIC: u32 = 0x7262_6968; const LENGTH_SELF_64: u32 = 256;
635 const XPRESS_SIG: [u8; 8] = [0x81, 0x81, b'x', b'p', b'r', b'e', b's', b's'];
636 const BLOCK_HEADER_SIZE: usize = 0x20;
637
638 let mut out = vec![0u8; 3 * PAGE_SIZE]; out[0x00..0x04].copy_from_slice(&HIBR_MAGIC.to_le_bytes());
643 out[0x0C..0x10].copy_from_slice(&LENGTH_SELF_64.to_le_bytes());
645 out[0x68..0x70].copy_from_slice(&2u64.to_le_bytes());
647
648 let cr3_offset = PAGE_SIZE + 0x28;
651 out[cr3_offset..cr3_offset + 8].copy_from_slice(&self.cr3.to_le_bytes());
652
653 let table_base = 2 * PAGE_SIZE;
656 let mut table_offset = 0usize;
657 for (pfn, _) in &self.pages {
658 out[table_base + table_offset..table_base + table_offset + 8]
659 .copy_from_slice(&pfn.to_le_bytes());
660 table_offset += 8;
661 }
662 out[table_base + table_offset..table_base + table_offset + 8]
664 .copy_from_slice(&u64::MAX.to_le_bytes());
665
666 for (_, page_data) in &self.pages {
669 let compressed = xpress_compress_safe(page_data);
670
671 let compressed_size_field = (compressed.len() * 4 - 1) as u32;
673 let num_pages_minus_1: u8 = 0; let mut block = Vec::new();
676 block.extend_from_slice(&XPRESS_SIG);
678 block.push(num_pages_minus_1);
680 block.push(compressed_size_field as u8);
682 block.push((compressed_size_field >> 8) as u8);
683 block.push((compressed_size_field >> 16) as u8);
684 block.resize(BLOCK_HEADER_SIZE, 0);
686 block.extend_from_slice(&compressed);
688
689 out.extend_from_slice(&block);
690 }
691
692 out
693 }
694}
695
696pub struct KdumpBuilder {
723 pages: Vec<(u64, Vec<u8>)>,
724 compression: u32,
725 block_size: u32,
726}
727
728impl Default for KdumpBuilder {
729 fn default() -> Self {
730 Self {
731 pages: Vec::new(),
732 compression: 0x04, block_size: 4096,
734 }
735 }
736}
737
738impl KdumpBuilder {
739 pub fn new() -> Self {
741 Self::default()
742 }
743
744 pub fn block_size(mut self, bs: u32) -> Self {
746 self.block_size = bs;
747 self
748 }
749
750 pub fn compression(mut self, flags: u32) -> Self {
756 self.compression = flags;
757 self
758 }
759
760 pub fn add_page(mut self, pfn: u64, data: &[u8]) -> Self {
762 self.pages.push((pfn, data.to_vec()));
763 self
764 }
765
766 pub fn build(self) -> Vec<u8> {
768 let bs = self.block_size as usize;
769
770 let max_pfn = self
772 .pages
773 .iter()
774 .map(|(pfn, _)| *pfn)
775 .max()
776 .map_or(0, |p| p + 1);
777
778 let bitmap_bits = max_pfn as usize;
780 let bitmap_bytes_raw = bitmap_bits.div_ceil(8);
781 let bitmap_blocks = bitmap_bytes_raw.div_ceil(bs);
782 let bitmap_bytes = bitmap_blocks * bs;
783
784 let mut bitmap = vec![0u8; bitmap_bytes];
786 for (pfn, _) in &self.pages {
787 let pfn = *pfn as usize;
788 if pfn / 8 < bitmap.len() {
789 bitmap[pfn / 8] |= 1 << (pfn % 8);
790 }
791 }
792
793 let mut compressed_pages: Vec<(u32, Vec<u8>)> = Vec::new(); for (_, page_data) in &self.pages {
796 let (flags, compressed) = self.compress_page(page_data);
797 compressed_pages.push((flags, compressed));
798 }
799
800 let desc_start_block = 2 + 2 * bitmap_blocks;
806 let desc_start = desc_start_block * bs;
807
808 let mut indexed_pages: Vec<(usize, u64)> = self
810 .pages
811 .iter()
812 .enumerate()
813 .map(|(i, (pfn, _))| (i, *pfn))
814 .collect();
815 indexed_pages.sort_by_key(|(_, pfn)| *pfn);
816
817 let num_descs = indexed_pages.len();
819 let descs_raw_size = num_descs * 24;
820 let descs_padded = descs_raw_size.div_ceil(bs) * bs;
821 let data_start = desc_start + descs_padded;
822
823 let mut data_offsets: Vec<usize> = Vec::new();
825 let mut cur_offset = data_start;
826 for (orig_idx, _) in &indexed_pages {
827 data_offsets.push(cur_offset);
828 cur_offset += compressed_pages[*orig_idx].1.len();
829 }
830
831 let total_size = cur_offset;
833 let mut out = vec![0u8; total_size];
834
835 out[0x00..0x08].copy_from_slice(b"KDUMP ");
838 out[0x08..0x0C].copy_from_slice(&6i32.to_le_bytes());
840 let fields_off = (0x0C + 390 + 3) & !3; #[allow(clippy::cast_possible_wrap)]
845 let block_size_i32 = self.block_size as i32;
846 out[fields_off..fields_off + 4].copy_from_slice(&block_size_i32.to_le_bytes());
847 out[fields_off + 4..fields_off + 8].copy_from_slice(&1i32.to_le_bytes());
849 out[fields_off + 8..fields_off + 12].copy_from_slice(&(bitmap_blocks as u32).to_le_bytes());
851 out[fields_off + 12..fields_off + 16].copy_from_slice(&(max_pfn as u32).to_le_bytes());
853
854 let bm1_start = 2 * bs;
858 out[bm1_start..bm1_start + bitmap.len()].copy_from_slice(&bitmap);
859
860 let bm2_start = (2 + bitmap_blocks) * bs;
862 out[bm2_start..bm2_start + bitmap.len()].copy_from_slice(&bitmap);
863
864 for (desc_idx, (orig_idx, _)) in indexed_pages.iter().enumerate() {
866 let d_off = desc_start + desc_idx * 24;
867 let (flags, ref compressed) = compressed_pages[*orig_idx];
868 out[d_off..d_off + 8].copy_from_slice(
870 &{
871 #[allow(clippy::cast_possible_wrap)]
872 let offset_i64 = data_offsets[desc_idx] as i64;
873 offset_i64
874 }
875 .to_le_bytes(),
876 );
877 out[d_off + 8..d_off + 12].copy_from_slice(&(compressed.len() as u32).to_le_bytes());
879 out[d_off + 12..d_off + 16].copy_from_slice(&flags.to_le_bytes());
881 }
883
884 for (desc_idx, (orig_idx, _)) in indexed_pages.iter().enumerate() {
886 let offset = data_offsets[desc_idx];
887 let data = &compressed_pages[*orig_idx].1;
888 out[offset..offset + data.len()].copy_from_slice(data);
889 }
890
891 out
892 }
893
894 fn compress_page(&self, data: &[u8]) -> (u32, Vec<u8>) {
897 match self.compression {
898 0x00 => {
899 (0x00, data.to_vec())
901 }
902 0x01 => {
903 use std::io::Write;
905 let mut encoder =
906 flate2::write::ZlibEncoder::new(Vec::new(), flate2::Compression::default());
907 encoder.write_all(data).expect("zlib compress write");
908 let compressed = encoder.finish().expect("zlib compress finish");
909 (0x01, compressed)
910 }
911 0x04 => {
912 let mut encoder = snap::raw::Encoder::new();
914 let compressed = encoder.compress_vec(data).expect("snappy compress");
915 (0x04, compressed)
916 }
917 0x20 => {
918 let compressed = Self::zstd_compress_minimal(data);
920 (0x20, compressed)
921 }
922 _ => (0x00, data.to_vec()),
923 }
924 }
925
926 fn zstd_compress_minimal(data: &[u8]) -> Vec<u8> {
935 let mut out = Vec::new();
936 out.extend_from_slice(&0xFD2FB528u32.to_le_bytes());
938 out.push(0x00);
942 out.push(0x00);
944 let block_header: u32 = 1 | ((data.len() as u32) << 3);
949 let bh_bytes = block_header.to_le_bytes();
950 out.extend_from_slice(&bh_bytes[..3]);
951 out.extend_from_slice(data);
953 out
954 }
955}
956
957#[cfg(test)]
963mod tests {
964 use super::*;
965 use crate::avml::AvmlProvider;
966 use crate::elf_core::ElfCoreProvider;
967 use crate::lime::LimeProvider;
968 use crate::PhysicalMemoryProvider;
969
970 #[test]
973 fn lime_builder_roundtrip() {
974 let data = vec![0xAB; 64];
975 let bytes = LimeBuilder::new().add_range(0x1000, &data).build();
976 let provider = LimeProvider::from_bytes(&bytes).unwrap();
977 assert_eq!(provider.ranges().len(), 1);
978 assert_eq!(provider.ranges()[0].start, 0x1000);
979 assert_eq!(provider.ranges()[0].end, 0x1000 + 64);
980
981 let mut buf = vec![0u8; 64];
982 let n = provider.read_phys(0x1000, &mut buf).unwrap();
983 assert_eq!(n, 64);
984 assert!(buf.iter().all(|&b| b == 0xAB));
985 }
986
987 #[test]
988 fn lime_builder_two_ranges() {
989 let bytes = LimeBuilder::new()
990 .add_range(0x0000, &[0x11; 32])
991 .add_range(0x8000, &[0x22; 48])
992 .build();
993 let provider = LimeProvider::from_bytes(&bytes).unwrap();
994 assert_eq!(provider.ranges().len(), 2);
995 assert_eq!(provider.total_size(), 32 + 48);
996
997 let mut buf = [0u8; 4];
998 let n = provider.read_phys(0x0000, &mut buf).unwrap();
999 assert_eq!(n, 4);
1000 assert_eq!(buf, [0x11; 4]);
1001
1002 let n = provider.read_phys(0x8000, &mut buf).unwrap();
1003 assert_eq!(n, 4);
1004 assert_eq!(buf, [0x22; 4]);
1005 }
1006
1007 #[test]
1008 fn lime_builder_empty_produces_parseable_bytes() {
1009 let bytes = LimeBuilder::new().build();
1011 let provider = LimeProvider::from_bytes(&bytes).unwrap();
1013 assert_eq!(provider.ranges().len(), 0);
1014 assert_eq!(provider.total_size(), 0);
1015 }
1016
1017 #[test]
1020 fn avml_builder_roundtrip() {
1021 let data = vec![0xCD; 128];
1022 let bytes = AvmlBuilder::new().add_range(0x2000, &data).build();
1023 let provider = AvmlProvider::from_bytes(&bytes).unwrap();
1024 assert_eq!(provider.ranges().len(), 1);
1025 assert_eq!(provider.ranges()[0].start, 0x2000);
1026 assert_eq!(provider.ranges()[0].end, 0x2000 + 128);
1027
1028 let mut buf = vec![0u8; 128];
1029 let n = provider.read_phys(0x2000, &mut buf).unwrap();
1030 assert_eq!(n, 128);
1031 assert!(buf.iter().all(|&b| b == 0xCD));
1032 }
1033
1034 #[test]
1035 fn avml_builder_two_ranges() {
1036 let bytes = AvmlBuilder::new()
1037 .add_range(0x0000, &[0xAA; 64])
1038 .add_range(0x4000, &[0xBB; 96])
1039 .build();
1040 let provider = AvmlProvider::from_bytes(&bytes).unwrap();
1041 assert_eq!(provider.ranges().len(), 2);
1042 assert_eq!(provider.total_size(), 64 + 96);
1043
1044 let mut buf = [0u8; 4];
1045 let n = provider.read_phys(0x0000, &mut buf).unwrap();
1046 assert_eq!(n, 4);
1047 assert_eq!(buf, [0xAA; 4]);
1048
1049 let n = provider.read_phys(0x4000, &mut buf).unwrap();
1050 assert_eq!(n, 4);
1051 assert_eq!(buf, [0xBB; 4]);
1052 }
1053
1054 #[test]
1057 fn elf_builder_roundtrip() {
1058 let data = vec![0xEF; 256];
1059 let bytes = ElfCoreBuilder::new().add_segment(0x3000, &data).build();
1060 let provider = ElfCoreProvider::from_bytes(bytes).unwrap();
1061 assert_eq!(provider.ranges().len(), 1);
1062 assert_eq!(provider.ranges()[0].start, 0x3000);
1063 assert_eq!(provider.ranges()[0].end, 0x3000 + 256);
1064
1065 let mut buf = vec![0u8; 256];
1066 let n = provider.read_phys(0x3000, &mut buf).unwrap();
1067 assert_eq!(n, 256);
1068 assert!(buf.iter().all(|&b| b == 0xEF));
1069 }
1070
1071 #[test]
1072 fn elf_builder_two_segments() {
1073 let bytes = ElfCoreBuilder::new()
1074 .add_segment(0x0000, &[0x55; 512])
1075 .add_segment(0x1000_0000, &[0x66; 128])
1076 .build();
1077 let provider = ElfCoreProvider::from_bytes(bytes).unwrap();
1078 assert_eq!(provider.ranges().len(), 2);
1079 assert_eq!(provider.total_size(), 512 + 128);
1080
1081 let mut buf = [0u8; 4];
1082 let n = provider.read_phys(0x0000, &mut buf).unwrap();
1083 assert_eq!(n, 4);
1084 assert_eq!(buf, [0x55; 4]);
1085
1086 let n = provider.read_phys(0x1000_0000, &mut buf).unwrap();
1087 assert_eq!(n, 4);
1088 assert_eq!(buf, [0x66; 4]);
1089 }
1090}