diff options
Diffstat (limited to 'ripple/minitrace/src/syscall_abi/macros.rs')
-rw-r--r-- | ripple/minitrace/src/syscall_abi/macros.rs | 161 |
1 files changed, 161 insertions, 0 deletions
diff --git a/ripple/minitrace/src/syscall_abi/macros.rs b/ripple/minitrace/src/syscall_abi/macros.rs new file mode 100644 index 0000000..07e6099 --- /dev/null +++ b/ripple/minitrace/src/syscall_abi/macros.rs @@ -0,0 +1,161 @@ +// SPDX-FileCopyrightText: edef <edef@unfathomable.blue> +// SPDX-License-Identifier: OSL-3.0 + +#[cfg(test)] +use std::fmt::{self, Debug}; + +#[cfg(test)] +pub(crate) fn libc_check<T: Debug + Eq + fmt::LowerHex>( + item: &'static str, + (our_name, our_value): (&'static str, T), + (libc_name, libc_value): (&'static str, T), +) { + match () { + _ if libc_name.ends_with(our_name) => {} + _ if libc_name.starts_with(&format!("{our_name}_")) => {} + () => panic!("{libc_name} doesn't match {our_name}"), + } + + assert!( + our_value == libc_value, + "{item}::{our_name} ({our_value:#x}) != libc::{libc_name} ({libc_value:#x})", + ); +} + +#[macro_export] +macro_rules! syscall_bitflags { + ( + $( + struct $BitFlags:ident: $T:ty { + $( + const $FLAG:ident = $value:expr => $LIBC_FLAG:ident; + )* + } + )* + ) => { + #[test] + fn verify_syscall_bitflags() { + $( + $BitFlags::verify(); + )* + } + + $( + $crate::bitflags! { + pub(crate) struct $BitFlags: $T { + $( + const $FLAG = $value; + )* + } + } + + impl $BitFlags { + #[cfg(test)] + fn verify() { + $( + $crate::syscall_abi::macros::libc_check( + stringify!($BitFlags), + (stringify!($FLAG), Self::$FLAG.bits()), + (stringify!($LIBC_FLAG), $crate::libc::$LIBC_FLAG) + ); + )* + } + } + + impl $crate::syscall_abi::SyscallArg for $BitFlags { + fn try_from_reg(reg: u64) -> Option<Self> { + $crate::syscall_abi::SyscallArg::try_from_reg(reg).and_then(Self::from_bits) + } + } + )* + }; +} + +#[macro_export] +macro_rules! syscall_enums { + ( + $( + enum $Enum:ident: $T:ty { + $( + $VARIANT:ident = $value:literal $(=> $LIBC_VALUE:ident)?, + )* + } + )* + ) => { + #[test] + fn verify_syscall_enums() { + $( + $Enum::verify(); + )* + } + + $( + #[derive(Debug, Copy, Clone, Eq, PartialEq)] + #[allow(non_camel_case_types)] + pub(crate) enum $Enum { + $($VARIANT = $value),* + } + + impl $crate::syscall_abi::SyscallArg for $Enum { + fn try_from_reg(reg: u64) -> Option<Self> { + let reg = <$T as $crate::syscall_abi::SyscallArg>::try_from_reg(reg)?; + Some(match reg { + $( + $value => $Enum::$VARIANT, + )* + _ => return None + }) + } + } + + impl $Enum { + #[cfg(test)] + fn verify() { + $( + $( + $crate::syscall_abi::macros::libc_check( + stringify!($Enum), + (stringify!($VARIANT), Self::$VARIANT as $T), + (stringify!($LIBC_VALUE), $crate::libc::$LIBC_VALUE) + ); + )? + )* + } + } + )* + }; +} + +#[macro_export] +macro_rules! define_syscalls { + (enum $SyscallEntry:ident { + $(fn $syscall:ident ( $($arg:ident : $Arg:ty),* ) -> $Ret:ty = $nr:literal ;)* + }) => { + #[derive(Debug, Clone)] + #[allow(non_camel_case_types)] + // TODO(edef): re-enable dead_code lint when we start fully interpreting syscall args + #[allow(dead_code)] + pub(crate) enum $SyscallEntry { + $($syscall { + $($arg : $Arg),* + }),* + } + + impl $SyscallEntry { + pub(crate) fn from_regs(process: &Process, regs: $crate::libc::user_regs_struct) -> anyhow::Result<$SyscallEntry> { + use anyhow::bail; + Ok(match (regs.orig_rax, [regs.rdi, regs.rsi, regs.rdx, regs.r10, regs.r8, regs.r9]) { + $( + ($nr, [$($arg,)* ..]) => $SyscallEntry::$syscall { + $($arg: match ProcessSyscallArg::try_from_process_reg(process, $arg) { + Some(x) => x, + None => bail!("couldn't parse {}(2) {}: {:#08x}", stringify!($syscall), stringify!($arg), $arg) + }),* + }, + )* + (n, _) => bail!("unknown syscall number {n}") + }) + } + } + } +} |