wasmparser/readers/core/
coredumps.rs

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