use super::{
CpuExceptionContext, X64_EXCP_AC, X64_EXCP_BP, X64_EXCP_BR, X64_EXCP_DB, X64_EXCP_DE,
X64_EXCP_DF, X64_EXCP_GP, X64_EXCP_MC, X64_EXCP_MF, X64_EXCP_NM, X64_EXCP_NMI, X64_EXCP_NP,
X64_EXCP_OF, X64_EXCP_PF, X64_EXCP_SS, X64_EXCP_TS, X64_EXCP_UD, X64_EXCP_XF,
X64_PF_ERR_INSN_FETCH, X64_PF_ERR_PRESENT, X64_PF_ERR_RESERVED, X64_PF_ERR_USER,
X64_PF_ERR_WRITE,
};
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum AccessType {
Read,
Write,
Execute,
}
impl AccessType {
pub fn mnemonic(self) -> char {
match self {
Self::Read => 'R',
Self::Write => 'W',
Self::Execute => 'X',
}
}
}
impl CpuExceptionContext {
pub fn is_page_fault(&self) -> bool {
self.vector == X64_EXCP_PF
}
pub fn is_general_protection(&self) -> bool {
self.vector == X64_EXCP_GP
}
pub fn is_invalid_opcode(&self) -> bool {
self.vector == X64_EXCP_UD
}
pub fn is_double_fault(&self) -> bool {
self.vector == X64_EXCP_DF
}
pub fn is_breakpoint(&self) -> bool {
self.vector == X64_EXCP_BP
}
pub fn name(&self) -> &'static str {
match self.vector {
X64_EXCP_DE => "#DE",
X64_EXCP_DB => "#DB",
X64_EXCP_NMI => "NMI",
X64_EXCP_BP => "#BP",
X64_EXCP_OF => "#OF",
X64_EXCP_BR => "#BR",
X64_EXCP_UD => "#UD",
X64_EXCP_NM => "#NM",
X64_EXCP_DF => "#DF",
X64_EXCP_TS => "#TS",
X64_EXCP_NP => "#NP",
X64_EXCP_SS => "#SS",
X64_EXCP_GP => "#GP",
X64_EXCP_PF => "#PF",
X64_EXCP_MF => "#MF",
X64_EXCP_AC => "#AC",
X64_EXCP_MC => "#MC",
X64_EXCP_XF => "#XF",
_ => "?",
}
}
pub fn has_error_code(&self) -> bool {
matches!(
self.vector,
X64_EXCP_DF
| X64_EXCP_TS
| X64_EXCP_NP
| X64_EXCP_SS
| X64_EXCP_GP
| X64_EXCP_PF
| X64_EXCP_AC
)
}
pub fn pf_access_type(&self) -> Option<AccessType> {
if !self.is_page_fault() {
return None;
}
if self.error & X64_PF_ERR_INSN_FETCH != 0 {
Some(AccessType::Execute)
} else if self.error & X64_PF_ERR_WRITE != 0 {
Some(AccessType::Write)
} else {
Some(AccessType::Read)
}
}
pub fn pf_was_user(&self) -> Option<bool> {
self.is_page_fault()
.then_some(self.error & X64_PF_ERR_USER != 0)
}
pub fn pf_was_protection_violation(&self) -> Option<bool> {
self.is_page_fault()
.then_some(self.error & X64_PF_ERR_PRESENT != 0)
}
pub fn pf_reserved_bit_set(&self) -> Option<bool> {
self.is_page_fault()
.then_some(self.error & X64_PF_ERR_RESERVED != 0)
}
}