Next Generation WASM Microkernel Operating System
1// Copyright 2025 Jonas Kruckenberg
2//
3// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
4// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
5// http://opensource.org/licenses/MIT>, at your option. This file may not be
6// copied, modified, or distributed except according to those terms.
7
8use core::fmt;
9use cranelift_codegen::ir::TrapCode;
10
11const TRAP_OFFSET: u8 = 1;
12pub const TRAP_INTERNAL_ASSERT: TrapCode =
13 TrapCode::unwrap_user(TrapKind::InternalAssertionFailed as u8 + TRAP_OFFSET);
14pub const TRAP_HEAP_MISALIGNED: TrapCode =
15 TrapCode::unwrap_user(TrapKind::HeapMisaligned as u8 + TRAP_OFFSET);
16pub const TRAP_TABLE_OUT_OF_BOUNDS: TrapCode =
17 TrapCode::unwrap_user(TrapKind::TableOutOfBounds as u8 + TRAP_OFFSET);
18pub const TRAP_INDIRECT_CALL_TO_NULL: TrapCode =
19 TrapCode::unwrap_user(TrapKind::IndirectCallToNull as u8 + TRAP_OFFSET);
20pub const TRAP_BAD_SIGNATURE: TrapCode =
21 TrapCode::unwrap_user(TrapKind::BadSignature as u8 + TRAP_OFFSET);
22pub const TRAP_UNREACHABLE: TrapCode =
23 TrapCode::unwrap_user(TrapKind::UnreachableCodeReached as u8 + TRAP_OFFSET);
24pub const TRAP_NULL_REFERENCE: TrapCode =
25 TrapCode::unwrap_user(TrapKind::NullReference as u8 + TRAP_OFFSET);
26pub const TRAP_I31_NULL_REFERENCE: TrapCode =
27 TrapCode::unwrap_user(TrapKind::NullI31Ref as u8 + TRAP_OFFSET);
28pub const TRAP_ATOMIC_WAIT_NON_SHARED_MEMORY: TrapCode =
29 TrapCode::unwrap_user(TrapKind::AtomicWaitNonSharedMemory as u8 + TRAP_OFFSET);
30
31#[derive(Debug, Copy, Clone)]
32pub enum TrapKind {
33 /// Internal assertion failed
34 InternalAssertionFailed,
35 /// A wasm atomic operation was presented with a not-naturally-aligned linear-memory address.
36 HeapMisaligned,
37 /// Out-of-bounds access to a table.
38 TableOutOfBounds,
39 /// Indirect call to a null table entry.
40 IndirectCallToNull,
41 /// Signature mismatch on indirect call.
42 BadSignature,
43 /// Code that was supposed to have been unreachable was reached.
44 UnreachableCodeReached,
45 /// Call to a null reference.
46 NullReference,
47 /// Attempt to get the bits of a null `i31ref`.
48 NullI31Ref,
49
50 /// The current stack space was exhausted.
51 StackOverflow,
52 /// An out-of-bounds memory access.
53 MemoryOutOfBounds,
54 /// An integer arithmetic operation caused an overflow.
55 IntegerOverflow,
56 /// An integer division by zero.
57 IntegerDivisionByZero,
58 /// Failed float-to-int conversion.
59 BadConversionToInteger,
60
61 /// Used to indicate that a trap was raised by atomic wait operations on non shared memory.
62 AtomicWaitNonSharedMemory,
63}
64
65impl fmt::Display for TrapKind {
66 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
67 match self {
68 TrapKind::InternalAssertionFailed => f.write_str("internal assertion failed"),
69 TrapKind::HeapMisaligned => f.write_str("unaligned atomic operation"),
70 TrapKind::TableOutOfBounds => f.write_str("out of bounds table access"),
71 TrapKind::IndirectCallToNull => f.write_str("accessed uninitialized table element"),
72 TrapKind::BadSignature => f.write_str("indirect call signature mismatch"),
73 TrapKind::UnreachableCodeReached => f.write_str("unreachable code executed"),
74 TrapKind::NullReference => f.write_str("null reference called"),
75 TrapKind::NullI31Ref => f.write_str("null i32 reference called"),
76
77 TrapKind::StackOverflow => f.write_str("call stack exhausted"),
78 TrapKind::MemoryOutOfBounds => f.write_str("out of bounds memory access"),
79 TrapKind::IntegerOverflow => f.write_str("integer overflow"),
80 TrapKind::IntegerDivisionByZero => f.write_str("integer divide by zero"),
81 TrapKind::BadConversionToInteger => f.write_str("invalid conversion to integer"),
82
83 TrapKind::AtomicWaitNonSharedMemory => f.write_str("atomic wait on non-shared memory"),
84 }
85 }
86}
87
88impl core::error::Error for TrapKind {}
89
90impl TrapKind {
91 pub(crate) fn from_trap_code(code: TrapCode) -> Option<Self> {
92 match code {
93 TrapCode::STACK_OVERFLOW => Some(TrapKind::StackOverflow),
94 TrapCode::HEAP_OUT_OF_BOUNDS => Some(TrapKind::MemoryOutOfBounds),
95 TrapCode::INTEGER_OVERFLOW => Some(TrapKind::IntegerOverflow),
96 TrapCode::INTEGER_DIVISION_BY_ZERO => Some(TrapKind::IntegerDivisionByZero),
97 TrapCode::BAD_CONVERSION_TO_INTEGER => Some(TrapKind::BadConversionToInteger),
98
99 TRAP_INTERNAL_ASSERT => Some(TrapKind::InternalAssertionFailed),
100 TRAP_HEAP_MISALIGNED => Some(TrapKind::HeapMisaligned),
101 TRAP_TABLE_OUT_OF_BOUNDS => Some(TrapKind::TableOutOfBounds),
102 TRAP_INDIRECT_CALL_TO_NULL => Some(TrapKind::IndirectCallToNull),
103 TRAP_BAD_SIGNATURE => Some(TrapKind::BadSignature),
104 TRAP_UNREACHABLE => Some(TrapKind::UnreachableCodeReached),
105 TRAP_NULL_REFERENCE => Some(TrapKind::NullReference),
106 TRAP_I31_NULL_REFERENCE => Some(TrapKind::NullI31Ref),
107
108 TRAP_ATOMIC_WAIT_NON_SHARED_MEMORY => Some(TrapKind::AtomicWaitNonSharedMemory),
109
110 c => {
111 tracing::warn!("unknown trap code {c}");
112 None
113 }
114 }
115 }
116}
117
118impl From<TrapKind> for u8 {
119 fn from(value: TrapKind) -> Self {
120 match value {
121 TrapKind::InternalAssertionFailed => 0,
122 TrapKind::HeapMisaligned => 1,
123 TrapKind::TableOutOfBounds => 2,
124 TrapKind::IndirectCallToNull => 3,
125 TrapKind::BadSignature => 4,
126 TrapKind::UnreachableCodeReached => 5,
127 TrapKind::NullReference => 6,
128 TrapKind::NullI31Ref => 7,
129
130 TrapKind::StackOverflow => 8,
131 TrapKind::MemoryOutOfBounds => 9,
132 TrapKind::IntegerOverflow => 10,
133 TrapKind::IntegerDivisionByZero => 11,
134 TrapKind::BadConversionToInteger => 12,
135
136 TrapKind::AtomicWaitNonSharedMemory => 13,
137 }
138 }
139}
140
141impl TryFrom<u8> for TrapKind {
142 type Error = ();
143
144 fn try_from(value: u8) -> Result<Self, Self::Error> {
145 match value {
146 0 => Ok(Self::InternalAssertionFailed),
147 1 => Ok(Self::HeapMisaligned),
148 2 => Ok(Self::TableOutOfBounds),
149 3 => Ok(Self::IndirectCallToNull),
150 4 => Ok(Self::BadSignature),
151 5 => Ok(Self::UnreachableCodeReached),
152 6 => Ok(Self::NullReference),
153 7 => Ok(Self::NullI31Ref),
154
155 8 => Ok(Self::StackOverflow),
156 9 => Ok(Self::MemoryOutOfBounds),
157 10 => Ok(Self::IntegerOverflow),
158 11 => Ok(Self::IntegerDivisionByZero),
159 12 => Ok(Self::BadConversionToInteger),
160
161 13 => Ok(Self::AtomicWaitNonSharedMemory),
162
163 _ => Err(()),
164 }
165 }
166}