wasm/core/structure/modules/
data_segments.rs

1use alloc::{format, vec::Vec};
2use core::fmt;
3
4use crate::core::{decoding::reader::span::Span, structure::modules::indices::MemIdx};
5
6#[derive(Clone)]
7pub struct DataSegment {
8    pub init: Vec<u8>,
9    pub mode: DataMode,
10}
11
12#[derive(Clone)]
13pub enum DataMode {
14    Passive,
15    Active(DataModeActive),
16}
17
18#[derive(Clone)]
19pub struct DataModeActive {
20    pub memory_idx: MemIdx,
21    pub offset: Span,
22}
23
24impl fmt::Debug for DataSegment {
25    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
26        let mut init_str = alloc::string::String::new();
27
28        let iter = self.init.iter().peekable();
29        // only if it's valid do we print is as a normal utf-8 char, otherwise, hex
30        for &byte in iter {
31            if let Ok(valid_char) = alloc::string::String::from_utf8(Vec::from(&[byte])) {
32                init_str.push_str(valid_char.as_str());
33            } else {
34                init_str.push_str(&format!("\\x{byte:02x}"));
35            }
36        }
37
38        f.debug_struct("DataSegment")
39            .field("init", &init_str)
40            .field("mode", &self.mode)
41            .finish()
42    }
43}
44
45///
46///  Usually, we'd have something like this:
47/// ```wasm
48/// (module
49///  (memory 1) ;; memory starting with 1 page
50///  (data (i32.const 0) "abc")  ;; writing the array of byte "abc" in the first memory (0) at offset 0
51///                             ;; for hardcoded offsets, we'll usually use i32.const because of wasm being x86 arch
52/// )
53/// ```
54///
55/// Since the span has only the start and length and acts a reference, we print the start and end (both inclusive, notice the '..=')
56/// We print it in both decimal and hexadecimal so it's easy to trace in something like <https://webassembly.github.io/wabt/demo/wat2wasm/>
57impl fmt::Debug for DataMode {
58    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
59        match self {
60            DataMode::Passive => f.debug_struct("Passive").finish(),
61            DataMode::Active(active_data_mode) => {
62                let from = active_data_mode.offset.from;
63                let to = active_data_mode.offset.from + active_data_mode.offset.len() - 1;
64                f.debug_struct("Active")
65                    // .field("offset", format_args!("[{}..={}]", from, to))
66                    .field(
67                        "offset",
68                        &format_args!("[{from}..={to}] (hex = [{from:X}..={to:X}])"),
69                    )
70                    .finish()
71                // f.
72            }
73        }
74    }
75}
76
77pub struct _PassiveData {
78    pub init: Vec<u8>,
79}
80
81impl fmt::Debug for _PassiveData {
82    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> core::fmt::Result {
83        let mut init_str = alloc::string::String::new();
84
85        let iter = self.init.iter().peekable();
86        for &byte in iter {
87            if let Ok(valid_char) = alloc::string::String::from_utf8(Vec::from(&[byte])) {
88                init_str.push_str(valid_char.as_str());
89            } else {
90                // If it's not valid UTF-8, print it as hex
91                init_str.push_str(&format!("\\x{byte:02x}"));
92            }
93        }
94        f.debug_struct("PassiveData")
95            .field("init", &init_str)
96            .finish()
97    }
98}