Path: blob/main/crates/environ/src/fact/traps.rs
1692 views
//! Module used to encode failure messages associated with traps in an adapter1//! module.2//!3//! This module is a bit forward-looking in an attempt to help assist with4//! debugging issues with adapter modules and their implementation. This isn't5//! actually wired up to any decoder at this time and may end up getting deleted6//! entirely depending on how things go.7//!8//! Currently in core wasm the `unreachable` instruction and other traps have no9//! ability to assign failure messages with traps. This means that if an adapter10//! fails all you have is the program counter into the wasm function, but11//! there's not actually any source corresponding to wasm adapters either. This12//! module is an attempt to assign optional string messages to `unreachable`13//! trap instructions so, when sufficient debugging options are enabled, these14//! trap messages could be displayed instead of a bland "unreachable" trap15//! message.16//!17//! This information is currently encoded as a custom section in the wasm18//! module.1920use crate::prelude::*;21use std::collections::HashMap;22use std::fmt;23use wasm_encoder::Encode;2425#[derive(Hash, PartialEq, Eq, Copy, Clone)]26pub enum Trap {27CannotLeave,28CannotEnter,29UnalignedPointer,30InvalidDiscriminant,31InvalidChar,32ListByteLengthOverflow,33StringLengthTooBig,34StringLengthOverflow,35AssertFailed(&'static str),36}3738#[derive(Default)]39pub struct TrapSection {40trap_to_index: HashMap<Trap, usize>,41trap_list: Vec<Trap>,42function_traps: Vec<(u32, Vec<(usize, usize)>)>,43}4445impl TrapSection {46/// Appends a list of traps found within a function.47///48/// The `func` is the core wasm function index that is being described. The49/// `traps` is a list of `(offset, trap)` where `offset` is the offset50/// within the function body itself and `trap` is the description of the51/// trap of the opcode at that offset.52pub fn append(&mut self, func: u32, traps: Vec<(usize, Trap)>) {53if traps.is_empty() {54return;55}5657// Deduplicate `Trap` annotations to avoid repeating the trap string58// internally within the custom section.59let traps = traps60.into_iter()61.map(|(offset, trap)| {62let trap = *self.trap_to_index.entry(trap).or_insert_with(|| {63let idx = self.trap_list.len();64self.trap_list.push(trap);65idx66});67(offset, trap)68})69.collect();70self.function_traps.push((func, traps));71}7273/// Creates the custom section payload of this section to be encoded into a74/// core wasm module.75pub fn finish(self) -> Vec<u8> {76let mut data = Vec::new();7778// First append all trap messages which will be indexed below.79self.trap_list.len().encode(&mut data);80for trap in self.trap_list.iter() {81trap.to_string().encode(&mut data);82}8384// Afterwards encode trap information for all known functions where85// offsets are relative to the body of the function index specified and86// the trap message is a pointer into the table built above this.87self.function_traps.len().encode(&mut data);88for (func, traps) in self.function_traps.iter() {89func.encode(&mut data);90traps.len().encode(&mut data);91for (func_offset, trap_message) in traps {92func_offset.encode(&mut data);93trap_message.encode(&mut data);94}95}9697data98}99}100101impl fmt::Display for Trap {102fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {103match self {104Trap::CannotLeave => "cannot leave instance".fmt(f),105Trap::CannotEnter => "cannot enter instance".fmt(f),106Trap::UnalignedPointer => "pointer not aligned correctly".fmt(f),107Trap::InvalidDiscriminant => "invalid variant discriminant".fmt(f),108Trap::InvalidChar => "invalid char value specified".fmt(f),109Trap::ListByteLengthOverflow => "byte size of list too large for i32".fmt(f),110Trap::StringLengthTooBig => "string byte size exceeds maximum".fmt(f),111Trap::StringLengthOverflow => "string byte size overflows i32".fmt(f),112Trap::AssertFailed(s) => write!(f, "assertion failure: {s}"),113}114}115}116117118