Skip to content

Add Wasm coredump builder #1461

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
171 changes: 171 additions & 0 deletions crates/wasmi/src/coredump.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
#[derive(Debug, Default)]
pub struct Process<'a> {
pub name: &'a str,
pub threads: &'a [Thread<'a>],
pub memories: &'a [Memory],
pub data: &'a [u8],
}

#[derive(Debug)]
pub struct Memory {
pub min: u64,
pub max: Option<u64>,
}

#[derive(Debug)]
pub struct Thread<'a> {
pub name: &'a str,
pub frames: &'a [Frame],
}

#[derive(Debug)]
pub struct Frame {
pub func_idx: u32,
pub code_offset: u32,
// TODO: locals
// TODO: stack
}

use alloc::vec::Vec;

const HEADER: [u8; 8] = [
0x00, 0x61, 0x73, 0x6D, // Magic
0x01, 0x00, 0x00, 0x00, // Version
];

/// Convert the given `proc` info into a coredump and write it into `w`.
///
/// ## Example
///
/// let frame = Frame {
/// func_idx: 6,
/// code_offset: 123,
/// };
/// let thread = Thread {
/// name: "main",
/// frames: &[frame],
/// };
/// let proc = Process {
/// name: "/usr/bin/true.exe",
/// threads: &[thread],
/// memories: &[Memory { min: 0, max: None }],
/// data: &[],
/// };
/// let mut coredump = Vec::new();
/// serialize(&mut coredump, &proc);
pub fn serialize(w: &mut Vec<u8>, proc: &Process) {
w.extend(HEADER);
write_core_section(w, proc);
write_corestack_sections(w, proc);
write_memory_section(w, proc);
write_data_section(w, proc);

Check warning on line 61 in crates/wasmi/src/coredump.rs

View check run for this annotation

Codecov / codecov/patch

crates/wasmi/src/coredump.rs#L56-L61

Added lines #L56 - L61 were not covered by tests
}

fn write_core_section(w: &mut Vec<u8>, proc: &Process) {
let mut data = Vec::new();
data.push(0x0);
write_utf8(&mut data, proc.name);
w.push(0); // custom section ID
encode_custom_section(w, "core", &data);

Check warning on line 69 in crates/wasmi/src/coredump.rs

View check run for this annotation

Codecov / codecov/patch

crates/wasmi/src/coredump.rs#L64-L69

Added lines #L64 - L69 were not covered by tests
}

fn write_corestack_sections(w: &mut Vec<u8>, proc: &Process) {
for stack in proc.threads {
let mut data = Vec::new();
encode_stack(&mut data, stack);
w.push(0); // custom section ID
encode_custom_section(w, "corestack", &data);

Check warning on line 77 in crates/wasmi/src/coredump.rs

View check run for this annotation

Codecov / codecov/patch

crates/wasmi/src/coredump.rs#L72-L77

Added lines #L72 - L77 were not covered by tests
}
}

fn write_memory_section(w: &mut Vec<u8>, proc: &Process) {
let mut section: Vec<u8> = Vec::new();
for mem in proc.memories {
let mut flags = 0;
if mem.max.is_some() {
flags |= 0b0001;

Check warning on line 86 in crates/wasmi/src/coredump.rs

View check run for this annotation

Codecov / codecov/patch

crates/wasmi/src/coredump.rs#L81-L86

Added lines #L81 - L86 were not covered by tests
}
section.push(flags);
write_u64(&mut section, mem.min);
if let Some(max) = mem.max {
write_u64(&mut section, max);

Check warning on line 91 in crates/wasmi/src/coredump.rs

View check run for this annotation

Codecov / codecov/patch

crates/wasmi/src/coredump.rs#L88-L91

Added lines #L88 - L91 were not covered by tests
}
}
w.push(5); // memory section ID
let count = proc.memories.len();
encode_section(w, count as u32, &section);

Check warning on line 96 in crates/wasmi/src/coredump.rs

View check run for this annotation

Codecov / codecov/patch

crates/wasmi/src/coredump.rs#L94-L96

Added lines #L94 - L96 were not covered by tests
}

fn write_data_section(w: &mut Vec<u8>, proc: &Process) {
let mut section = Vec::new();
section.push(0x00); // active
section.push(0x41); // "i32.const" instruction
write_u64(&mut section, 0); // i32.const value (zero)
section.push(0x0B); // "end" instruction.
write_u64(&mut section, proc.data.len() as u64);
section.extend(proc.data);

Check warning on line 106 in crates/wasmi/src/coredump.rs

View check run for this annotation

Codecov / codecov/patch

crates/wasmi/src/coredump.rs#L99-L106

Added lines #L99 - L106 were not covered by tests

w.push(11); // data section ID
encode_section(w, 1, &section);

Check warning on line 109 in crates/wasmi/src/coredump.rs

View check run for this annotation

Codecov / codecov/patch

crates/wasmi/src/coredump.rs#L108-L109

Added lines #L108 - L109 were not covered by tests
}

fn encode_custom_section(w: &mut Vec<u8>, name: &str, data: &[u8]) {
let encoded_name_len = encoding_size(u32::try_from(name.len()).unwrap());
let total_size = encoded_name_len + name.len() + data.len();
write_u64(w, total_size as u64);
write_u64(w, name.len() as u64);
w.extend_from_slice(name.as_bytes());
w.extend(data);

Check warning on line 118 in crates/wasmi/src/coredump.rs

View check run for this annotation

Codecov / codecov/patch

crates/wasmi/src/coredump.rs#L112-L118

Added lines #L112 - L118 were not covered by tests
}

fn encode_section(w: &mut Vec<u8>, count: u32, bytes: &[u8]) {
let size = encoding_size(count) + bytes.len();
write_u64(w, size as u64);
write_u64(w, count.into());
w.extend(bytes);

Check warning on line 125 in crates/wasmi/src/coredump.rs

View check run for this annotation

Codecov / codecov/patch

crates/wasmi/src/coredump.rs#L121-L125

Added lines #L121 - L125 were not covered by tests
}

fn encoding_size(n: u32) -> usize {
let mut buf = Vec::new();
write_u64(&mut buf, n.into())

Check warning on line 130 in crates/wasmi/src/coredump.rs

View check run for this annotation

Codecov / codecov/patch

crates/wasmi/src/coredump.rs#L128-L130

Added lines #L128 - L130 were not covered by tests
}

fn encode_stack(w: &mut Vec<u8>, stack: &Thread) {
w.push(0x0); // version 0
write_utf8(w, stack.name);
write_u64(w, stack.frames.len() as u64);
for frame in stack.frames {
w.push(0x0); // version 0
write_u64(w, frame.func_idx as u64);
write_u64(w, frame.code_offset as u64);
write_u64(w, 0); // locals vec size
write_u64(w, 0); // stack vec size

Check warning on line 142 in crates/wasmi/src/coredump.rs

View check run for this annotation

Codecov / codecov/patch

crates/wasmi/src/coredump.rs#L133-L142

Added lines #L133 - L142 were not covered by tests
}
}

// Encode a UTF-8 string in wasm format.
fn write_utf8(w: &mut Vec<u8>, v: &str) {
let bytes = v.as_bytes();
write_u64(w, bytes.len() as u64);
w.extend_from_slice(bytes);

Check warning on line 150 in crates/wasmi/src/coredump.rs

View check run for this annotation

Codecov / codecov/patch

crates/wasmi/src/coredump.rs#L147-L150

Added lines #L147 - L150 were not covered by tests
}

// Encode u64 value using leb128 encoding.
fn write_u64(w: &mut Vec<u8>, mut val: u64) -> usize {

Check warning on line 154 in crates/wasmi/src/coredump.rs

View check run for this annotation

Codecov / codecov/patch

crates/wasmi/src/coredump.rs#L154

Added line #L154 was not covered by tests
const CONTINUATION_BIT: u8 = 1 << 7;
let mut bytes_written = 0;

Check warning on line 156 in crates/wasmi/src/coredump.rs

View check run for this annotation

Codecov / codecov/patch

crates/wasmi/src/coredump.rs#L156

Added line #L156 was not covered by tests
loop {
let byte = val & (u8::MAX as u64);
let mut byte = byte as u8 & !CONTINUATION_BIT;
val >>= 7;
if val != 0 {
byte |= CONTINUATION_BIT;

Check warning on line 162 in crates/wasmi/src/coredump.rs

View check run for this annotation

Codecov / codecov/patch

crates/wasmi/src/coredump.rs#L158-L162

Added lines #L158 - L162 were not covered by tests
}
let buf = [byte];
w.extend_from_slice(&buf);
bytes_written += 1;
if val == 0 {
return bytes_written;

Check warning on line 168 in crates/wasmi/src/coredump.rs

View check run for this annotation

Codecov / codecov/patch

crates/wasmi/src/coredump.rs#L164-L168

Added lines #L164 - L168 were not covered by tests
}
}
}
1 change: 1 addition & 0 deletions crates/wasmi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ mod foreach_tuple;
#[cfg(test)]
pub mod tests;

mod coredump;
mod engine;
mod error;
mod externref;
Expand Down
Loading