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