summary refs log tree commit diff
path: root/ripple/minitrace/src/syscall_abi/macros.rs
diff options
context:
space:
mode:
Diffstat (limited to 'ripple/minitrace/src/syscall_abi/macros.rs')
-rw-r--r--ripple/minitrace/src/syscall_abi/macros.rs161
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}")
+				})
+			}
+		}
+	}
+}