Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/cranelift/codegen/src/ir/trapcode.rs
1693 views
1
//! Trap codes describing the reason for a trap.
2
3
use core::fmt::{self, Display, Formatter};
4
use core::num::NonZeroU8;
5
use core::str::FromStr;
6
#[cfg(feature = "enable-serde")]
7
use serde_derive::{Deserialize, Serialize};
8
9
/// A trap code describing the reason for a trap.
10
///
11
/// All trap instructions have an explicit trap code.
12
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
13
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
14
pub struct TrapCode(NonZeroU8);
15
16
impl TrapCode {
17
/// Number of reserved opcodes for Cranelift itself. This number of traps are
18
/// defined below starting at the high end of the byte space (e.g. 255, 254,
19
/// ...)
20
const RESERVED: u8 = 5;
21
const RESERVED_START: u8 = u8::MAX - Self::RESERVED + 1;
22
23
/// Internal helper to create new reserved trap codes.
24
const fn reserved(byte: u8) -> TrapCode {
25
if let Some(code) = byte.checked_add(Self::RESERVED_START) {
26
if let Some(nz) = NonZeroU8::new(code) {
27
return TrapCode(nz);
28
}
29
}
30
panic!("invalid reserved opcode")
31
}
32
33
/// The current stack space was exhausted.
34
pub const STACK_OVERFLOW: TrapCode = TrapCode::reserved(0);
35
/// An integer arithmetic operation caused an overflow.
36
pub const INTEGER_OVERFLOW: TrapCode = TrapCode::reserved(1);
37
/// A `heap_addr` instruction detected an out-of-bounds error.
38
///
39
/// Note that not all out-of-bounds heap accesses are reported this way;
40
/// some are detected by a segmentation fault on the heap unmapped or
41
/// offset-guard pages.
42
pub const HEAP_OUT_OF_BOUNDS: TrapCode = TrapCode::reserved(2);
43
44
/// An integer division by zero.
45
pub const INTEGER_DIVISION_BY_ZERO: TrapCode = TrapCode::reserved(3);
46
47
/// Failed float-to-int conversion.
48
pub const BAD_CONVERSION_TO_INTEGER: TrapCode = TrapCode::reserved(4);
49
50
/// Create a user-defined trap code.
51
///
52
/// Returns `None` if `code` is zero or too large and is reserved by
53
/// Cranelift.
54
pub const fn user(code: u8) -> Option<TrapCode> {
55
if code >= Self::RESERVED_START {
56
return None;
57
}
58
match NonZeroU8::new(code) {
59
Some(nz) => Some(TrapCode(nz)),
60
None => None,
61
}
62
}
63
64
/// Alias for [`TrapCode::user`] with a panic built-in.
65
pub const fn unwrap_user(code: u8) -> TrapCode {
66
match TrapCode::user(code) {
67
Some(code) => code,
68
None => panic!("invalid user trap code"),
69
}
70
}
71
72
/// Returns the raw byte representing this trap.
73
pub const fn as_raw(&self) -> NonZeroU8 {
74
self.0
75
}
76
77
/// Creates a trap code from its raw byte, likely returned by
78
/// [`TrapCode::as_raw`] previously.
79
pub const fn from_raw(byte: NonZeroU8) -> TrapCode {
80
TrapCode(byte)
81
}
82
83
/// Returns a slice of all traps except `TrapCode::User` traps
84
pub const fn non_user_traps() -> &'static [TrapCode] {
85
&[
86
TrapCode::STACK_OVERFLOW,
87
TrapCode::HEAP_OUT_OF_BOUNDS,
88
TrapCode::INTEGER_OVERFLOW,
89
TrapCode::INTEGER_DIVISION_BY_ZERO,
90
TrapCode::BAD_CONVERSION_TO_INTEGER,
91
]
92
}
93
}
94
95
impl Display for TrapCode {
96
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
97
let identifier = match *self {
98
Self::STACK_OVERFLOW => "stk_ovf",
99
Self::HEAP_OUT_OF_BOUNDS => "heap_oob",
100
Self::INTEGER_OVERFLOW => "int_ovf",
101
Self::INTEGER_DIVISION_BY_ZERO => "int_divz",
102
Self::BAD_CONVERSION_TO_INTEGER => "bad_toint",
103
TrapCode(x) => return write!(f, "user{x}"),
104
};
105
f.write_str(identifier)
106
}
107
}
108
109
impl FromStr for TrapCode {
110
type Err = ();
111
112
fn from_str(s: &str) -> Result<Self, Self::Err> {
113
match s {
114
"stk_ovf" => Ok(Self::STACK_OVERFLOW),
115
"heap_oob" => Ok(Self::HEAP_OUT_OF_BOUNDS),
116
"int_ovf" => Ok(Self::INTEGER_OVERFLOW),
117
"int_divz" => Ok(Self::INTEGER_DIVISION_BY_ZERO),
118
"bad_toint" => Ok(Self::BAD_CONVERSION_TO_INTEGER),
119
_ if s.starts_with("user") => {
120
let num = s[4..].parse().map_err(|_| ())?;
121
TrapCode::user(num).ok_or(())
122
}
123
_ => Err(()),
124
}
125
}
126
}
127
128
#[cfg(test)]
129
mod tests {
130
use super::*;
131
use alloc::string::ToString;
132
133
#[test]
134
fn display() {
135
for r in TrapCode::non_user_traps() {
136
let tc = *r;
137
assert_eq!(tc.to_string().parse(), Ok(tc));
138
}
139
assert_eq!("bogus".parse::<TrapCode>(), Err(()));
140
141
assert_eq!(TrapCode::unwrap_user(17).to_string(), "user17");
142
assert_eq!("user22".parse(), Ok(TrapCode::unwrap_user(22)));
143
assert_eq!("user".parse::<TrapCode>(), Err(()));
144
assert_eq!("user-1".parse::<TrapCode>(), Err(()));
145
assert_eq!("users".parse::<TrapCode>(), Err(()));
146
}
147
}
148
149