tinywasm_wasmparser/readers/core/
coredumps.rs

1use alloc::{vec, vec::Vec};
2
3use crate::{BinaryReader, FromReader, Result};
4
5/// The data portion of a custom section representing a core dump. Per the
6/// tool-conventions repo, this section just specifies the executable name that
7/// the core dump came from while the rest of the core dump information is
8/// contained in a corestack custom section
9///
10/// # Examples
11///
12/// ```
13/// use tinywasm_wasmparser::{ BinaryReader, CoreDumpSection, FromReader, Result };
14/// let data: &[u8] = &[0x00, 0x09, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x77, 0x61,
15///      0x73, 0x6d];
16/// let mut reader = BinaryReader::new(data);
17/// let core = CoreDumpSection::from_reader(&mut reader).unwrap();
18/// assert!(core.name == "test.wasm")
19/// ```
20pub struct CoreDumpSection<'a> {
21    /// The name of the process that created the core dump
22    pub name: &'a str,
23}
24
25impl<'a> FromReader<'a> for CoreDumpSection<'a> {
26    fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> {
27        let pos = reader.original_position();
28        if reader.read_u8()? != 0 {
29            bail!(pos, "invalid start byte for core dump name");
30        }
31        let name = reader.read_string()?;
32        Ok(CoreDumpSection { name })
33    }
34}
35
36/// The data portion of a "coremodules" custom section. This contains a vec of
37/// module names that will be referenced by index by other coredump sections.
38///
39/// # Example
40///
41/// ```
42/// use tinywasm_wasmparser::{ BinaryReader, CoreDumpModulesSection, FromReader, Result };
43/// let data: &[u8] = &[0x01, 0x00, 0x04, 0x74, 0x65, 0x73, 0x74];
44/// let mut reader = BinaryReader::new(data);
45/// let modules_section = CoreDumpModulesSection::from_reader(&mut reader).unwrap();
46/// assert!(modules_section.modules[0] == "test")
47/// ```
48#[derive(Debug)]
49pub struct CoreDumpModulesSection<'a> {
50    /// A list of module names, which may be URLs, file paths, or other
51    /// identifiers for the module.
52    pub modules: Vec<&'a str>,
53}
54
55impl<'a> FromReader<'a> for CoreDumpModulesSection<'a> {
56    fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> {
57        let pos = reader.original_position();
58        let mut modules = vec![];
59        for _ in 0..reader.read_var_u32()? {
60            if reader.read_u8()? != 0 {
61                bail!(pos, "invalid start byte for coremodule");
62            }
63            modules.push(reader.read_string()?);
64        }
65        Ok(CoreDumpModulesSection { modules })
66    }
67}
68/// A custom section representing the instances involved in a given coredump
69pub struct CoreDumpInstancesSection {
70    /// The instances for the coredump
71    pub instances: Vec<CoreDumpInstance>,
72}
73
74impl<'a> FromReader<'a> for CoreDumpInstancesSection {
75    fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> {
76        let mut instances = vec![];
77        for _ in 0..reader.read_var_u32()? {
78            instances.push(CoreDumpInstance::from_reader(reader)?);
79        }
80        Ok(CoreDumpInstancesSection { instances })
81    }
82}
83
84/// A single instance from a coredump instances section
85pub struct CoreDumpInstance {
86    /// The module that this is an instance of, as an index into a "coremodules"
87    /// section.
88    pub module_index: u32,
89
90    /// Which of the coredump's memories are this instance's memories, via
91    /// indexing into the memory index space.
92    pub memories: Vec<u32>,
93
94    /// Which of the coredump's globals are this instance's globals, via
95    /// indexing into the global index space.
96    pub globals: Vec<u32>,
97}
98
99impl<'a> FromReader<'a> for CoreDumpInstance {
100    fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> {
101        let pos = reader.original_position();
102        if reader.read_u8()? != 0 {
103            bail!(pos, "invalid start byte for core dump instance");
104        }
105        let module_index = reader.read_var_u32()?;
106        let mut memories = vec![];
107        for _ in 0..reader.read_var_u32()? {
108            memories.push(reader.read_var_u32()?);
109        }
110        let mut globals = vec![];
111
112        for _ in 0..reader.read_var_u32()? {
113            globals.push(reader.read_var_u32()?);
114        }
115
116        Ok(CoreDumpInstance {
117            module_index,
118            memories,
119            globals,
120        })
121    }
122}
123
124/// The data portion of a custom section representing a core dump stack. The
125/// structure of this follows the coredump spec in the tool-conventions repo
126///
127/// # Examples
128///
129/// ```
130/// let data: &[u8] = &[0x00, 0x04, 0x6d, 0x61, 0x69, 0x6e, 0x01, 0x00, 0x04,
131///     0x2a, 0x33, 0x01, 0x7f, 0x01, 0x01, 0x7f, 0x02];
132/// use tinywasm_wasmparser::{ BinaryReader, CoreDumpStackSection, FromReader };
133/// let mut reader = BinaryReader::new(data);
134/// let corestack = CoreDumpStackSection::from_reader(&mut reader).unwrap();
135/// assert!(corestack.name == "main");
136/// assert!(corestack.frames.len() == 1);
137/// let frame = &corestack.frames[0];
138/// assert!(frame.instanceidx == 4);
139/// assert!(frame.funcidx == 42);
140/// assert!(frame.codeoffset == 51);
141/// assert!(frame.locals.len() == 1);
142/// assert!(frame.stack.len() == 1);
143/// ```
144pub struct CoreDumpStackSection<'a> {
145    /// The thread name
146    pub name: &'a str,
147    /// The stack frames for the core dump
148    pub frames: Vec<CoreDumpStackFrame>,
149}
150
151impl<'a> FromReader<'a> for CoreDumpStackSection<'a> {
152    fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> {
153        let pos = reader.original_position();
154        if reader.read_u8()? != 0 {
155            bail!(pos, "invalid start byte for core dump stack name");
156        }
157        let name = reader.read_string()?;
158        let mut frames = vec![];
159        for _ in 0..reader.read_var_u32()? {
160            frames.push(CoreDumpStackFrame::from_reader(reader)?);
161        }
162        Ok(CoreDumpStackSection {
163            name: name,
164            frames: frames,
165        })
166    }
167}
168
169/// A single stack frame from a core dump
170#[derive(Debug)]
171pub struct CoreDumpStackFrame {
172    /// The instance that this stack frame belongs to.
173    pub instanceidx: u32,
174    /// The function index in the module
175    pub funcidx: u32,
176    /// The instruction's offset relative to the function's start
177    pub codeoffset: u32,
178    /// The locals for this stack frame (including function parameters)
179    pub locals: Vec<CoreDumpValue>,
180    /// The values on the stack
181    pub stack: Vec<CoreDumpValue>,
182}
183
184impl<'a> FromReader<'a> for CoreDumpStackFrame {
185    fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> {
186        let pos = reader.original_position();
187        if reader.read_u8()? != 0 {
188            bail!(pos, "invalid start byte for core dump stack frame");
189        }
190        let instanceidx = reader.read_var_u32()?;
191        let funcidx = reader.read_var_u32()?;
192        let codeoffset = reader.read_var_u32()?;
193        let mut locals = vec![];
194        for _ in 0..reader.read_var_u32()? {
195            locals.push(CoreDumpValue::from_reader(reader)?);
196        }
197        let mut stack = vec![];
198        for _ in 0..reader.read_var_u32()? {
199            stack.push(CoreDumpValue::from_reader(reader)?);
200        }
201
202        Ok(CoreDumpStackFrame {
203            instanceidx,
204            funcidx,
205            codeoffset,
206            locals,
207            stack,
208        })
209    }
210}
211
212/// Local and stack values are encoded using one byte for the type (similar to
213/// Wasm's Number Types) followed by bytes representing the actual value
214/// See the tool-conventions repo for more details.
215#[derive(Clone, Debug)]
216pub enum CoreDumpValue {
217    /// A missing value (usually missing because it was optimized out)
218    Missing,
219    /// An i32 value
220    I32(i32),
221    /// An i64 value
222    I64(i64),
223    /// An f32 value
224    F32(f32),
225    /// An f64 value
226    F64(f64),
227}
228
229impl<'a> FromReader<'a> for CoreDumpValue {
230    fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> {
231        let pos = reader.original_position();
232        match reader.read_u8()? {
233            0x01 => Ok(CoreDumpValue::Missing),
234            0x7F => Ok(CoreDumpValue::I32(reader.read_var_i32()?)),
235            0x7E => Ok(CoreDumpValue::I64(reader.read_var_i64()?)),
236            0x7D => Ok(CoreDumpValue::F32(f32::from_bits(
237                reader.read_f32()?.bits(),
238            ))),
239            0x7C => Ok(CoreDumpValue::F64(f64::from_bits(
240                reader.read_f64()?.bits(),
241            ))),
242            _ => bail!(pos, "invalid CoreDumpValue type"),
243        }
244    }
245}