pub fn syscall_name(num: i64) -> &'static str {
lookup_syscall(num, syscall_table())
}
fn lookup_syscall(num: i64, table: &[(i64, &'static str)]) -> &'static str {
match table.binary_search_by_key(&num, |&(n, _)| n) {
Ok(idx) => table[idx].1,
Err(_) => "unknown",
}
}
#[cfg(target_arch = "x86_64")]
static SYSCALL_TABLE_X86_64: &[(i64, &str)] = &[
(0, "read"),
(1, "write"),
(2, "open"),
(3, "close"),
(4, "stat"),
(5, "fstat"),
(6, "lstat"),
(7, "poll"),
(8, "lseek"),
(9, "mmap"),
(10, "mprotect"),
(11, "munmap"),
(12, "brk"),
(13, "rt_sigaction"),
(14, "rt_sigprocmask"),
(15, "rt_sigreturn"),
(16, "ioctl"),
(17, "pread64"),
(18, "pwrite64"),
(19, "readv"),
(20, "writev"),
(21, "access"),
(22, "pipe"),
(23, "select"),
(24, "sched_yield"),
(25, "mremap"),
(26, "msync"),
(27, "mincore"),
(28, "madvise"),
(29, "shmget"),
(30, "shmat"),
(31, "shmctl"),
(32, "dup"),
(33, "dup2"),
(34, "pause"),
(35, "nanosleep"),
(36, "getitimer"),
(37, "alarm"),
(38, "setitimer"),
(39, "getpid"),
(40, "sendfile"),
(41, "socket"),
(42, "connect"),
(43, "accept"),
(44, "sendto"),
(45, "recvfrom"),
(46, "sendmsg"),
(47, "recvmsg"),
(48, "shutdown"),
(49, "bind"),
(50, "listen"),
(51, "getsockname"),
(52, "getpeername"),
(53, "socketpair"),
(54, "setsockopt"),
(55, "getsockopt"),
(56, "clone"),
(57, "fork"),
(58, "vfork"),
(59, "execve"),
(60, "exit"),
(61, "wait4"),
(62, "kill"),
(63, "uname"),
(72, "fcntl"),
(73, "flock"),
(74, "fsync"),
(75, "fdatasync"),
(76, "truncate"),
(77, "ftruncate"),
(78, "getdents"),
(79, "getcwd"),
(80, "chdir"),
(81, "fchdir"),
(82, "rename"),
(83, "mkdir"),
(84, "rmdir"),
(85, "creat"),
(86, "link"),
(87, "unlink"),
(88, "symlink"),
(89, "readlink"),
(90, "chmod"),
(91, "fchmod"),
(92, "chown"),
(93, "fchown"),
(94, "lchown"),
(95, "umask"),
(96, "gettimeofday"),
(97, "getrlimit"),
(98, "getrusage"),
(99, "sysinfo"),
(102, "getuid"),
(104, "getgid"),
(105, "setuid"),
(107, "setgid"),
(108, "geteuid"),
(109, "getegid"),
(110, "setpgid"),
(111, "getppid"),
(112, "getpgrp"),
(113, "setsid"),
(131, "sigaltstack"),
(157, "prctl"),
(158, "arch_prctl"),
(186, "gettid"),
(202, "futex"),
(217, "getdents64"),
(218, "set_tid_address"),
(228, "clock_gettime"),
(231, "exit_group"),
(257, "openat"),
(262, "newfstatat"),
(273, "set_robust_list"),
(302, "pkey_mprotect"),
(318, "getrandom"),
(329, "pkey_mprotect"),
(330, "pkey_alloc"),
(331, "pkey_free"),
(332, "statx"),
(334, "rseq"),
(435, "clone3"),
];
#[cfg(target_arch = "x86_64")]
fn syscall_table() -> &'static [(i64, &'static str)] {
SYSCALL_TABLE_X86_64
}
#[cfg(target_arch = "aarch64")]
static SYSCALL_TABLE_AARCH64: &[(i64, &str)] = &[
(17, "getcwd"),
(23, "dup"),
(24, "dup3"),
(25, "fcntl"),
(29, "ioctl"),
(33, "mknodat"),
(34, "mkdirat"),
(35, "unlinkat"),
(36, "symlinkat"),
(37, "linkat"),
(38, "renameat"),
(43, "statfs"),
(44, "fstatfs"),
(45, "truncate"),
(46, "ftruncate"),
(48, "faccessat"),
(49, "chdir"),
(50, "fchdir"),
(51, "chroot"),
(52, "fchmod"),
(53, "fchmodat"),
(54, "fchownat"),
(55, "fchown"),
(56, "openat"),
(57, "close"),
(59, "pipe2"),
(61, "getdents64"),
(62, "lseek"),
(63, "read"),
(64, "write"),
(65, "readv"),
(66, "writev"),
(67, "pread64"),
(68, "pwrite64"),
(72, "pselect6"),
(73, "ppoll"),
(78, "readlinkat"),
(79, "newfstatat"),
(80, "fstat"),
(82, "fsync"),
(83, "fdatasync"),
(88, "utimensat"),
(93, "exit"),
(94, "exit_group"),
(96, "set_tid_address"),
(98, "futex"),
(99, "set_robust_list"),
(101, "nanosleep"),
(103, "setitimer"),
(104, "getitimer"),
(113, "clock_gettime"),
(116, "sched_yield"),
(117, "sched_setscheduler"),
(118, "sched_getscheduler"),
(122, "sched_setaffinity"),
(123, "sched_getaffinity"),
(124, "sched_yield"),
(129, "kill"),
(131, "tgkill"),
(132, "sigaltstack"),
(134, "rt_sigaction"),
(135, "rt_sigprocmask"),
(139, "rt_sigreturn"),
(153, "times"),
(157, "prctl"),
(160, "uname"),
(166, "umask"),
(167, "getrusage"),
(172, "getpid"),
(173, "getppid"),
(174, "getuid"),
(175, "geteuid"),
(176, "getgid"),
(177, "getegid"),
(178, "gettid"),
(179, "sysinfo"),
(196, "shmget"),
(198, "shmdt"),
(200, "socket"),
(201, "socketpair"),
(202, "bind"),
(203, "listen"),
(204, "accept"),
(205, "connect"),
(206, "getsockname"),
(207, "getpeername"),
(208, "sendto"),
(209, "recvfrom"),
(210, "setsockopt"),
(211, "getsockopt"),
(212, "shutdown"),
(213, "sendmsg"),
(214, "recvmsg"),
(215, "readahead"),
(216, "brk"),
(217, "munmap"),
(218, "mremap"),
(220, "clone"),
(221, "execve"),
(222, "mmap"),
(226, "mprotect"),
(227, "msync"),
(228, "madvise"),
(233, "mlock"),
(234, "munlock"),
(237, "sendfile"),
(242, "accept4"),
(260, "wait4"),
(261, "prlimit64"),
(262, "fanotify_init"),
(268, "getrandom"),
(276, "renameat2"),
(278, "getrandom"),
(280, "memfd_create"),
(281, "bpf"),
(291, "statx"),
(293, "rseq"),
(435, "clone3"),
];
#[cfg(target_arch = "aarch64")]
fn syscall_table() -> &'static [(i64, &'static str)] {
SYSCALL_TABLE_AARCH64
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_common_syscalls() {
let common = ["read", "write", "close", "openat", "mmap", "brk", "clone3"];
for name in common {
let found = (-1..500).any(|n| syscall_name(n) == name);
assert!(found, "syscall '{}' should exist in the table", name);
}
}
#[test]
fn test_unknown_syscall() {
assert_eq!(syscall_name(9999), "unknown");
}
#[cfg(target_arch = "x86_64")]
#[test]
fn test_x86_64_syscalls() {
assert_eq!(syscall_name(0), "read");
assert_eq!(syscall_name(1), "write");
assert_eq!(syscall_name(2), "open");
assert_eq!(syscall_name(3), "close");
assert_eq!(syscall_name(257), "openat");
}
#[cfg(target_arch = "aarch64")]
#[test]
fn test_aarch64_syscalls() {
assert_eq!(syscall_name(63), "read");
assert_eq!(syscall_name(64), "write");
assert_eq!(syscall_name(57), "close");
assert_eq!(syscall_name(56), "openat");
assert_eq!(syscall_name(222), "mmap");
}
#[test]
fn test_syscall_name_never_panics() {
for num in [-1000, -1, 0, 1, 100, 500, 1000, 9999, i64::MAX] {
let name = syscall_name(num);
assert!(!name.is_empty(), "Syscall name should never be empty for {}", num);
}
}
#[test]
fn test_syscall_name_always_returns_str() {
for num in 0..500 {
let name = syscall_name(num);
assert!(!name.is_empty());
assert!(name.chars().all(|c| c.is_alphanumeric() || c == '_'));
}
}
use proptest::prelude::*;
proptest! {
#[test]
fn prop_syscall_name_never_panics(num in any::<i64>()) {
let name = syscall_name(num);
prop_assert!(!name.is_empty());
}
#[test]
fn prop_syscall_name_deterministic(num in 0..500i64) {
let name1 = syscall_name(num);
let name2 = syscall_name(num);
prop_assert_eq!(name1, name2);
}
#[test]
fn prop_unknown_syscalls_return_unknown(num in 500..10000i64) {
let name = syscall_name(num);
prop_assert_eq!(name, "unknown");
}
}
}