1747ad3c4Slazypassion //! Trap codes describing the reason for a trap. 2747ad3c4Slazypassion 3747ad3c4Slazypassion use core::fmt::{self, Display, Formatter}; 4*9fc41baeSAlex Crichton use core::num::NonZeroU8; 5747ad3c4Slazypassion use core::str::FromStr; 61431ab52SArtur Jamro #[cfg(feature = "enable-serde")] 79ec02f9dSChristopher Serr use serde_derive::{Deserialize, Serialize}; 8747ad3c4Slazypassion 9747ad3c4Slazypassion /// A trap code describing the reason for a trap. 10747ad3c4Slazypassion /// 11747ad3c4Slazypassion /// All trap instructions have an explicit trap code. 12747ad3c4Slazypassion #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] 131431ab52SArtur Jamro #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] 14*9fc41baeSAlex Crichton pub struct TrapCode(NonZeroU8); 15747ad3c4Slazypassion 16*9fc41baeSAlex Crichton impl TrapCode { 17*9fc41baeSAlex Crichton /// Number of reserved opcodes for Cranelift itself. This number of traps are 18*9fc41baeSAlex Crichton /// defined below starting at the high end of the byte space (e.g. 255, 254, 19*9fc41baeSAlex Crichton /// ...) 20*9fc41baeSAlex Crichton const RESERVED: u8 = 5; 21*9fc41baeSAlex Crichton const RESERVED_START: u8 = u8::MAX - Self::RESERVED + 1; 22*9fc41baeSAlex Crichton 23*9fc41baeSAlex Crichton /// Internal helper to create new reserved trap codes. reserved(byte: u8) -> TrapCode24*9fc41baeSAlex Crichton const fn reserved(byte: u8) -> TrapCode { 25*9fc41baeSAlex Crichton if let Some(code) = byte.checked_add(Self::RESERVED_START) { 26*9fc41baeSAlex Crichton if let Some(nz) = NonZeroU8::new(code) { 27*9fc41baeSAlex Crichton return TrapCode(nz); 28*9fc41baeSAlex Crichton } 29*9fc41baeSAlex Crichton } 30*9fc41baeSAlex Crichton panic!("invalid reserved opcode") 31*9fc41baeSAlex Crichton } 32*9fc41baeSAlex Crichton 33*9fc41baeSAlex Crichton /// The current stack space was exhausted. 34*9fc41baeSAlex Crichton pub const STACK_OVERFLOW: TrapCode = TrapCode::reserved(0); 35*9fc41baeSAlex Crichton /// An integer arithmetic operation caused an overflow. 36*9fc41baeSAlex Crichton pub const INTEGER_OVERFLOW: TrapCode = TrapCode::reserved(1); 37747ad3c4Slazypassion /// A `heap_addr` instruction detected an out-of-bounds error. 38747ad3c4Slazypassion /// 39747ad3c4Slazypassion /// Note that not all out-of-bounds heap accesses are reported this way; 40747ad3c4Slazypassion /// some are detected by a segmentation fault on the heap unmapped or 41747ad3c4Slazypassion /// offset-guard pages. 42*9fc41baeSAlex Crichton pub const HEAP_OUT_OF_BOUNDS: TrapCode = TrapCode::reserved(2); 43747ad3c4Slazypassion 44747ad3c4Slazypassion /// An integer division by zero. 45*9fc41baeSAlex Crichton pub const INTEGER_DIVISION_BY_ZERO: TrapCode = TrapCode::reserved(3); 46747ad3c4Slazypassion 47747ad3c4Slazypassion /// Failed float-to-int conversion. 48*9fc41baeSAlex Crichton pub const BAD_CONVERSION_TO_INTEGER: TrapCode = TrapCode::reserved(4); 49747ad3c4Slazypassion 50*9fc41baeSAlex Crichton /// Create a user-defined trap code. 51*9fc41baeSAlex Crichton /// 52*9fc41baeSAlex Crichton /// Returns `None` if `code` is zero or too large and is reserved by 53*9fc41baeSAlex Crichton /// Cranelift. user(code: u8) -> Option<TrapCode>54*9fc41baeSAlex Crichton pub const fn user(code: u8) -> Option<TrapCode> { 55*9fc41baeSAlex Crichton if code >= Self::RESERVED_START { 56*9fc41baeSAlex Crichton return None; 57*9fc41baeSAlex Crichton } 58*9fc41baeSAlex Crichton match NonZeroU8::new(code) { 59*9fc41baeSAlex Crichton Some(nz) => Some(TrapCode(nz)), 60*9fc41baeSAlex Crichton None => None, 61*9fc41baeSAlex Crichton } 62747ad3c4Slazypassion } 63747ad3c4Slazypassion 64*9fc41baeSAlex Crichton /// Alias for [`TrapCode::user`] with a panic built-in. unwrap_user(code: u8) -> TrapCode65*9fc41baeSAlex Crichton pub const fn unwrap_user(code: u8) -> TrapCode { 66*9fc41baeSAlex Crichton match TrapCode::user(code) { 67*9fc41baeSAlex Crichton Some(code) => code, 68*9fc41baeSAlex Crichton None => panic!("invalid user trap code"), 69*9fc41baeSAlex Crichton } 70*9fc41baeSAlex Crichton } 71*9fc41baeSAlex Crichton 72*9fc41baeSAlex Crichton /// Returns the raw byte representing this trap. as_raw(&self) -> NonZeroU873*9fc41baeSAlex Crichton pub const fn as_raw(&self) -> NonZeroU8 { 74*9fc41baeSAlex Crichton self.0 75*9fc41baeSAlex Crichton } 76*9fc41baeSAlex Crichton 77*9fc41baeSAlex Crichton /// Creates a trap code from its raw byte, likely returned by 78*9fc41baeSAlex Crichton /// [`TrapCode::as_raw`] previously. from_raw(byte: NonZeroU8) -> TrapCode79*9fc41baeSAlex Crichton pub const fn from_raw(byte: NonZeroU8) -> TrapCode { 80*9fc41baeSAlex Crichton TrapCode(byte) 81*9fc41baeSAlex Crichton } 82*9fc41baeSAlex Crichton 8365a3af72SAfonso Bordado /// Returns a slice of all traps except `TrapCode::User` traps non_user_traps() -> &'static [TrapCode]8465a3af72SAfonso Bordado pub const fn non_user_traps() -> &'static [TrapCode] { 8565a3af72SAfonso Bordado &[ 86*9fc41baeSAlex Crichton TrapCode::STACK_OVERFLOW, 87*9fc41baeSAlex Crichton TrapCode::HEAP_OUT_OF_BOUNDS, 88*9fc41baeSAlex Crichton TrapCode::INTEGER_OVERFLOW, 89*9fc41baeSAlex Crichton TrapCode::INTEGER_DIVISION_BY_ZERO, 90*9fc41baeSAlex Crichton TrapCode::BAD_CONVERSION_TO_INTEGER, 9165a3af72SAfonso Bordado ] 9265a3af72SAfonso Bordado } 9365a3af72SAfonso Bordado } 9465a3af72SAfonso Bordado 95747ad3c4Slazypassion impl Display for TrapCode { fmt(&self, f: &mut Formatter) -> fmt::Result96747ad3c4Slazypassion fn fmt(&self, f: &mut Formatter) -> fmt::Result { 97747ad3c4Slazypassion let identifier = match *self { 98*9fc41baeSAlex Crichton Self::STACK_OVERFLOW => "stk_ovf", 99*9fc41baeSAlex Crichton Self::HEAP_OUT_OF_BOUNDS => "heap_oob", 100*9fc41baeSAlex Crichton Self::INTEGER_OVERFLOW => "int_ovf", 101*9fc41baeSAlex Crichton Self::INTEGER_DIVISION_BY_ZERO => "int_divz", 102*9fc41baeSAlex Crichton Self::BAD_CONVERSION_TO_INTEGER => "bad_toint", 103*9fc41baeSAlex Crichton TrapCode(x) => return write!(f, "user{x}"), 104747ad3c4Slazypassion }; 105747ad3c4Slazypassion f.write_str(identifier) 106747ad3c4Slazypassion } 107747ad3c4Slazypassion } 108747ad3c4Slazypassion 109747ad3c4Slazypassion impl FromStr for TrapCode { 110747ad3c4Slazypassion type Err = (); 111747ad3c4Slazypassion from_str(s: &str) -> Result<Self, Self::Err>112747ad3c4Slazypassion fn from_str(s: &str) -> Result<Self, Self::Err> { 113747ad3c4Slazypassion match s { 114*9fc41baeSAlex Crichton "stk_ovf" => Ok(Self::STACK_OVERFLOW), 115*9fc41baeSAlex Crichton "heap_oob" => Ok(Self::HEAP_OUT_OF_BOUNDS), 116*9fc41baeSAlex Crichton "int_ovf" => Ok(Self::INTEGER_OVERFLOW), 117*9fc41baeSAlex Crichton "int_divz" => Ok(Self::INTEGER_DIVISION_BY_ZERO), 118*9fc41baeSAlex Crichton "bad_toint" => Ok(Self::BAD_CONVERSION_TO_INTEGER), 119*9fc41baeSAlex Crichton _ if s.starts_with("user") => { 120*9fc41baeSAlex Crichton let num = s[4..].parse().map_err(|_| ())?; 121*9fc41baeSAlex Crichton TrapCode::user(num).ok_or(()) 122*9fc41baeSAlex Crichton } 123747ad3c4Slazypassion _ => Err(()), 124747ad3c4Slazypassion } 125747ad3c4Slazypassion } 126747ad3c4Slazypassion } 127747ad3c4Slazypassion 128747ad3c4Slazypassion #[cfg(test)] 129747ad3c4Slazypassion mod tests { 130747ad3c4Slazypassion use super::*; 13110e226f9Sbjorn3 use alloc::string::ToString; 132747ad3c4Slazypassion 133747ad3c4Slazypassion #[test] display()134747ad3c4Slazypassion fn display() { 13565a3af72SAfonso Bordado for r in TrapCode::non_user_traps() { 136747ad3c4Slazypassion let tc = *r; 137747ad3c4Slazypassion assert_eq!(tc.to_string().parse(), Ok(tc)); 138747ad3c4Slazypassion } 139747ad3c4Slazypassion assert_eq!("bogus".parse::<TrapCode>(), Err(())); 140747ad3c4Slazypassion 141*9fc41baeSAlex Crichton assert_eq!(TrapCode::unwrap_user(17).to_string(), "user17"); 142*9fc41baeSAlex Crichton assert_eq!("user22".parse(), Ok(TrapCode::unwrap_user(22))); 143747ad3c4Slazypassion assert_eq!("user".parse::<TrapCode>(), Err(())); 144747ad3c4Slazypassion assert_eq!("user-1".parse::<TrapCode>(), Err(())); 145747ad3c4Slazypassion assert_eq!("users".parse::<TrapCode>(), Err(())); 146747ad3c4Slazypassion } 147747ad3c4Slazypassion } 148