1 //! Trap codes describing the reason for a trap.
2 
3 use core::fmt::{self, Display, Formatter};
4 use core::str::FromStr;
5 #[cfg(feature = "enable-serde")]
6 use serde::{Deserialize, Serialize};
7 
8 /// A trap code describing the reason for a trap.
9 ///
10 /// All trap instructions have an explicit trap code.
11 #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
12 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
13 pub enum TrapCode {
14     /// The current stack space was exhausted.
15     ///
16     /// On some platforms, a stack overflow may also be indicated by a segmentation fault from the
17     /// stack guard page.
18     StackOverflow,
19 
20     /// A `heap_addr` instruction detected an out-of-bounds error.
21     ///
22     /// Note that not all out-of-bounds heap accesses are reported this way;
23     /// some are detected by a segmentation fault on the heap unmapped or
24     /// offset-guard pages.
25     HeapOutOfBounds,
26 
27     /// A `table_addr` instruction detected an out-of-bounds error.
28     TableOutOfBounds,
29 
30     /// Other bounds checking error.
31     OutOfBounds,
32 
33     /// Indirect call to a null table entry.
34     IndirectCallToNull,
35 
36     /// Signature mismatch on indirect call.
37     BadSignature,
38 
39     /// An integer arithmetic operation caused an overflow.
40     IntegerOverflow,
41 
42     /// An integer division by zero.
43     IntegerDivisionByZero,
44 
45     /// Failed float-to-int conversion.
46     BadConversionToInteger,
47 
48     /// Code that was supposed to have been unreachable was reached.
49     UnreachableCodeReached,
50 
51     /// Execution has potentially run too long and may be interrupted.
52     /// This trap is resumable.
53     Interrupt,
54 
55     /// A user-defined trap code.
56     User(u16),
57 }
58 
59 impl Display for TrapCode {
60     fn fmt(&self, f: &mut Formatter) -> fmt::Result {
61         use self::TrapCode::*;
62         let identifier = match *self {
63             StackOverflow => "stk_ovf",
64             HeapOutOfBounds => "heap_oob",
65             TableOutOfBounds => "table_oob",
66             OutOfBounds => "oob",
67             IndirectCallToNull => "icall_null",
68             BadSignature => "bad_sig",
69             IntegerOverflow => "int_ovf",
70             IntegerDivisionByZero => "int_divz",
71             BadConversionToInteger => "bad_toint",
72             UnreachableCodeReached => "unreachable",
73             Interrupt => "interrupt",
74             User(x) => return write!(f, "user{}", x),
75         };
76         f.write_str(identifier)
77     }
78 }
79 
80 impl FromStr for TrapCode {
81     type Err = ();
82 
83     fn from_str(s: &str) -> Result<Self, Self::Err> {
84         use self::TrapCode::*;
85         match s {
86             "stk_ovf" => Ok(StackOverflow),
87             "heap_oob" => Ok(HeapOutOfBounds),
88             "table_oob" => Ok(TableOutOfBounds),
89             "oob" => Ok(OutOfBounds),
90             "icall_null" => Ok(IndirectCallToNull),
91             "bad_sig" => Ok(BadSignature),
92             "int_ovf" => Ok(IntegerOverflow),
93             "int_divz" => Ok(IntegerDivisionByZero),
94             "bad_toint" => Ok(BadConversionToInteger),
95             "unreachable" => Ok(UnreachableCodeReached),
96             "interrupt" => Ok(Interrupt),
97             _ if s.starts_with("user") => s[4..].parse().map(User).map_err(|_| ()),
98             _ => Err(()),
99         }
100     }
101 }
102 
103 #[cfg(test)]
104 mod tests {
105     use super::*;
106     use alloc::string::ToString;
107 
108     // Everything but user-defined codes.
109     const CODES: [TrapCode; 11] = [
110         TrapCode::StackOverflow,
111         TrapCode::HeapOutOfBounds,
112         TrapCode::TableOutOfBounds,
113         TrapCode::OutOfBounds,
114         TrapCode::IndirectCallToNull,
115         TrapCode::BadSignature,
116         TrapCode::IntegerOverflow,
117         TrapCode::IntegerDivisionByZero,
118         TrapCode::BadConversionToInteger,
119         TrapCode::UnreachableCodeReached,
120         TrapCode::Interrupt,
121     ];
122 
123     #[test]
124     fn display() {
125         for r in &CODES {
126             let tc = *r;
127             assert_eq!(tc.to_string().parse(), Ok(tc));
128         }
129         assert_eq!("bogus".parse::<TrapCode>(), Err(()));
130 
131         assert_eq!(TrapCode::User(17).to_string(), "user17");
132         assert_eq!("user22".parse(), Ok(TrapCode::User(22)));
133         assert_eq!("user".parse::<TrapCode>(), Err(()));
134         assert_eq!("user-1".parse::<TrapCode>(), Err(()));
135         assert_eq!("users".parse::<TrapCode>(), Err(()));
136     }
137 }
138