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}