Skip to content

Commit

Permalink
add more documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
sonodima committed Oct 3, 2024
1 parent bcac53b commit b61cde1
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 2 deletions.
16 changes: 15 additions & 1 deletion src/code.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
/// Represents a system-specific exception code.
///
/// This enum encapsulates the various exception codes that can be returned by the
/// `GetExceptionCode` Windows API function.
///
/// See: <https://learn.microsoft.com/en-us/windows/win32/debug/getexceptioncode>
#[repr(u32)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
Expand Down Expand Up @@ -29,6 +34,15 @@ pub enum ExceptionCode {
}

impl core::fmt::Display for ExceptionCode {
/// Formats the exception code into a human-readable string.
///
/// # Arguments
///
/// * `f` - The formatter to write to.
///
/// # Returns
///
/// Whether the formatting operation succeeded.
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
ExceptionCode::Invalid => write!(f, "invalid exception"),
Expand All @@ -54,7 +68,7 @@ impl core::fmt::Display for ExceptionCode {
ExceptionCode::PrivilegedInstruction => write!(f, "the thread attempts to execute an instruction with an operation that is not allowed in the current computer mode"),
ExceptionCode::SingleStep => write!(f, "a trace trap or other single instruction mechanism signals that one instruction is executed"),
ExceptionCode::StackOverflow => write!(f, "the thread used up its stack"),
ExceptionCode::UnwindConsolidate =>write!(f, "a frame consolidation has been executed")
ExceptionCode::UnwindConsolidate => write!(f, "a frame consolidation has been executed")
}
}
}
27 changes: 27 additions & 0 deletions src/exception.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ use core::ffi::c_void;

use crate::{code::ExceptionCode, registers::Registers};

/// Represents an exception that occurs during program execution, along with additional
/// context information.
#[repr(C)]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Exception {
Expand All @@ -12,33 +14,58 @@ pub struct Exception {
}

impl Exception {
/// Creates a new exception with default values.
///
/// Exceptions created with this function are to be considered invalid, and should
/// only be used as a placeholder.
pub(crate) fn empty() -> Self {
Self {
code: ExceptionCode::Invalid,
address: core::ptr::null_mut(),
#[cfg(any(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64"))]
registers: Registers::empty(),
}
}

/// # Returns
///
/// The system-specific code of the exception.
pub fn code(&self) -> ExceptionCode {
self.code
}

/// # Returns
///
/// A pointer to the memory address where the exception occurred.
pub fn address(&self) -> *mut c_void {
self.address
}

/// # Returns
///
/// The dump of the CPU registers at the time of the exception.
#[cfg(any(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64"))]
pub fn registers(&self) -> &Registers {
&self.registers
}
}

impl core::fmt::Display for Exception {
/// Formats the exception into a human-readable string.
///
/// # Arguments
///
/// * `f` - The formatter to write to.
///
/// # Returns
///
/// Whether the formatting operation succeeded.
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{}", self.code)
}
}

/// In case the `std` feature is enabled, this implementation allows the exception to be
/// treated as a standard error.
#[cfg(feature = "std")]
impl std::error::Error for Exception {}
40 changes: 39 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,21 @@ mod registers;

pub use code::ExceptionCode;
pub use exception::Exception;
pub use registers::Registers;

type HandledProc = unsafe extern "system" fn(*mut c_void);

const MS_SUCCEEDED: u32 = 0x0;
const MS_CATCHED: u32 = 0x1;

/// Type alias for a function that converts a pointer to a function and executes it.
type HandledProc = unsafe extern "system" fn(*mut c_void);


/// Internal function that converts a pointer to a function and executes it.
///
/// # Arguments
///
/// * `closure` - A pointer to the closure or function to execute.
#[inline(always)]
unsafe extern "system" fn handled_proc<F>(closure: *mut c_void)
where
Expand All @@ -30,10 +39,33 @@ where

#[cfg(all(windows, not(docsrs)))]
extern "C" {
/// External function that is responsible for handling exceptions.
///
/// # Arguments
///
/// * `proc` - The wrapper function that will execute the closure.
/// * `closure` - A pointer to the closure or function to be executed within the
/// handled context.
/// * `exception` - Where the exception information will be stored if one occurs.
///
/// # Returns
///
/// * `0x0` - If the closure executed without throwing any exceptions.
/// * `0x1` - If an exception occurred during the execution of the closure.
#[link_name = "HandlerStub"]
fn handler_stub(proc: HandledProc, closure: *mut c_void, exception: *mut Exception) -> u32;
}

/// Primary execution orchestrator that calls the exception handling stub.
///
/// # Arguments
///
/// * `closure` - The closure or function to be executed within the handled context.
///
/// # Returns
///
/// * `Ok(())` - If the closure executed without throwing any exceptions.
/// * `Err(Exception)` - If an exception occurred during the execution of the closure.
#[cfg(all(windows, not(docsrs)))]
fn do_execute_proc<F>(mut closure: F) -> Result<(), Exception>
where
Expand All @@ -49,6 +81,12 @@ where
}
}

/// Fallback execution orchestrator to be used when exception handling is disabled.
///
/// # Panics
///
/// This function will always panic, notifying the user that exception handling is not
/// available in the current build.
#[cfg(any(not(windows), docsrs))]
fn do_execute_proc<F>(_closure: F) -> Result<(), Exception>
where
Expand Down
6 changes: 6 additions & 0 deletions src/registers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const NUM_REGISTERS: usize = 17;
#[cfg(target_arch = "aarch64")]
const NUM_REGISTERS: usize = 33;

/// Represents a saved state of the CPU registers.
#[cfg(any(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64"))]
#[repr(C)]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
Expand All @@ -14,12 +15,16 @@ pub struct Registers {

#[cfg(any(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64"))]
impl Registers {
/// Creates an instance of `Registers` with all registers initialized to zero.
pub fn empty() -> Self {
Self {
list: [0; NUM_REGISTERS],
}
}

/// # Returns
///
/// All the registers in the CPU state, in the order they were saved.
pub fn list(&self) -> &[usize] {
&self.list
}
Expand All @@ -28,6 +33,7 @@ impl Registers {
macro_rules! get_reg {
($reg:ident, $index:expr) => {
#[inline]
#[doc = concat!("# Returns\n\nThe value of the `", stringify!($reg), "` register.")]
pub fn $reg(&self) -> usize {
self.list[$index]
}
Expand Down

0 comments on commit b61cde1

Please sign in to comment.