//! Runtime-facing dispatch helpers for the native kboxlike backend.
//!
//! This layer owns the small amount of state and decoding needed before the
//! tracee installer can run: map a stopped host tracee pid back to the fd model
//! process id, classify the intercepted Linux syscall as an fd operation, and
//! build the tracee install request.

use super::fd::{FdError, FdNumber, FdOperation, KboxlikeFdSystem, ModelThreadId, ProcessId};
#[cfg(all(target_os = "linux", target_arch = "x86_64"))]
use super::tracee::install_requested_operation_shadow_in_stopped_tracee;
use super::tracee::{
    install_requested_operation_shadow_if_needed, TraceeMemoryWriter,
    TraceeOperationInstallRequest, TraceeSyscallExecutor,
};
use std::collections::BTreeMap;

const LINUX_X86_64_SYS_READ: i64 = 0;
const LINUX_X86_64_SYS_WRITE: i64 = 1;
const LINUX_X86_64_SYS_PREAD64: i64 = 17;
const LINUX_X86_64_SYS_PWRITE64: i64 = 18;
const LINUX_X86_64_SYS_READV: i64 = 19;
const LINUX_X86_64_SYS_WRITEV: i64 = 20;
const LINUX_X86_64_SYS_MMAP: i64 = 9;
const LINUX_X86_64_SYS_FCNTL: i64 = 72;
const LINUX_X86_64_SYS_PREADV: i64 = 295;
const LINUX_X86_64_SYS_PWRITEV: i64 = 296;
const LINUX_X86_64_SYS_PREADV2: i64 = 327;
const LINUX_X86_64_SYS_PWRITEV2: i64 = 328;

const LINUX_F_SETLK: u64 = 6;
const LINUX_F_SETLKW: u64 = 7;
const LINUX_F_OFD_SETLK: u64 = 37;
const LINUX_F_OFD_SETLKW: u64 = 38;

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(crate) struct InterceptedSyscall {
    pub(crate) nr: i64,
    pub(crate) args: [u64; 6],
}

impl InterceptedSyscall {
    pub(crate) fn new(nr: i64, args: [u64; 6]) -> Self {
        Self { nr, args }
    }

    #[cfg(all(target_os = "linux", target_arch = "x86_64"))]
    pub(crate) fn from_linux_x86_64_regs(regs: &libc::user_regs_struct) -> Self {
        Self {
            nr: regs.orig_rax as i64,
            args: [regs.rdi, regs.rsi, regs.rdx, regs.r10, regs.r8, regs.r9],
        }
    }
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(crate) struct ClassifiedFdOperation {
    pub(crate) fd: FdNumber,
    pub(crate) operation: FdOperation,
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(crate) enum SyscallStopOutcome {
    Unclassified,
    NoShadowNeeded,
    InstalledShadow,
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(crate) struct KboxlikeTraceeIdentity {
    pub(crate) host_pid: i32,
    pub(crate) model_pid: ProcessId,
    pub(crate) model_thread_id: ModelThreadId,
}

#[derive(Debug, Default)]
pub(crate) struct KboxlikeTraceeRegistry {
    host_to_identity: BTreeMap<i32, KboxlikeTraceeIdentity>,
    next_model_thread_id: ModelThreadId,
}

impl KboxlikeTraceeRegistry {
    pub(crate) fn new() -> Self {
        Self::default()
    }

    pub(crate) fn register_tracee(
        &mut self,
        host_pid: i32,
        model_pid: ProcessId,
    ) -> Result<(), FdError> {
        if host_pid <= 0 {
            return Err(FdError::TraceeInstallFailed("invalid tracee pid"));
        }
        if self.host_to_identity.contains_key(&host_pid) {
            return Err(FdError::TraceeInstallFailed(
                "tracee pid already registered",
            ));
        }
        self.next_model_thread_id += 1;
        self.host_to_identity.insert(
            host_pid,
            KboxlikeTraceeIdentity {
                host_pid,
                model_pid,
                model_thread_id: self.next_model_thread_id,
            },
        );
        Ok(())
    }

    pub(crate) fn unregister_tracee(&mut self, host_pid: i32) -> Option<ProcessId> {
        self.host_to_identity
            .remove(&host_pid)
            .map(|identity| identity.model_pid)
    }

    pub(crate) fn contains_model_pid(&self, model_pid: ProcessId) -> bool {
        self.host_to_identity
            .values()
            .any(|identity| identity.model_pid == model_pid)
    }

    pub(crate) fn contains_tracee(&self, host_pid: i32) -> bool {
        self.host_to_identity.contains_key(&host_pid)
    }

    pub(crate) fn tracees(&self) -> Vec<(i32, ProcessId)> {
        self.host_to_identity
            .values()
            .map(|identity| (identity.host_pid, identity.model_pid))
            .collect()
    }

    pub(crate) fn tracee_identities(&self) -> Vec<KboxlikeTraceeIdentity> {
        self.host_to_identity.values().copied().collect()
    }

    pub(crate) fn tracee_identity(&self, host_pid: i32) -> Result<KboxlikeTraceeIdentity, FdError> {
        if host_pid <= 0 {
            return Err(FdError::TraceeInstallFailed("invalid tracee pid"));
        }
        self.host_to_identity
            .get(&host_pid)
            .copied()
            .ok_or(FdError::TraceeInstallFailed("unknown tracee pid"))
    }

    pub(crate) fn model_pid(&self, host_pid: i32) -> Result<ProcessId, FdError> {
        if host_pid <= 0 {
            return Err(FdError::TraceeInstallFailed("invalid tracee pid"));
        }
        self.host_to_identity
            .get(&host_pid)
            .map(|identity| identity.model_pid)
            .ok_or(FdError::TraceeInstallFailed("unknown tracee pid"))
    }

    pub(crate) fn model_thread_id(&self, host_pid: i32) -> Result<ModelThreadId, FdError> {
        if host_pid <= 0 {
            return Err(FdError::TraceeInstallFailed("invalid tracee pid"));
        }
        self.host_to_identity
            .get(&host_pid)
            .map(|identity| identity.model_thread_id)
            .ok_or(FdError::TraceeInstallFailed("unknown tracee pid"))
    }

    pub(crate) fn install_request_for_syscall(
        &self,
        host_pid: i32,
        syscall: InterceptedSyscall,
    ) -> Result<Option<TraceeOperationInstallRequest>, FdError> {
        let Some(classified) = classify_fd_operation(syscall)? else {
            return Ok(None);
        };
        Ok(Some(TraceeOperationInstallRequest::new(
            self.model_pid(host_pid)?,
            host_pid,
            classified.fd,
            classified.operation,
        )?))
    }

    #[cfg(all(target_os = "linux", target_arch = "x86_64"))]
    pub(crate) fn install_request_for_linux_x86_64_regs(
        &self,
        host_pid: i32,
        regs: &libc::user_regs_struct,
    ) -> Result<Option<TraceeOperationInstallRequest>, FdError> {
        self.install_request_for_syscall(host_pid, InterceptedSyscall::from_linux_x86_64_regs(regs))
    }
}

pub(crate) fn classify_fd_operation(
    syscall: InterceptedSyscall,
) -> Result<Option<ClassifiedFdOperation>, FdError> {
    let classified = match syscall.nr {
        LINUX_X86_64_SYS_READ => ClassifiedFdOperation {
            fd: syscall_fd_arg(syscall.args[0])?,
            operation: FdOperation::Read,
        },
        LINUX_X86_64_SYS_WRITE | LINUX_X86_64_SYS_PWRITE64 => ClassifiedFdOperation {
            fd: syscall_fd_arg(syscall.args[0])?,
            operation: FdOperation::Write,
        },
        LINUX_X86_64_SYS_READV => ClassifiedFdOperation {
            fd: syscall_fd_arg(syscall.args[0])?,
            operation: FdOperation::Readv,
        },
        LINUX_X86_64_SYS_WRITEV => ClassifiedFdOperation {
            fd: syscall_fd_arg(syscall.args[0])?,
            operation: FdOperation::Writev,
        },
        LINUX_X86_64_SYS_PREAD64 => ClassifiedFdOperation {
            fd: syscall_fd_arg(syscall.args[0])?,
            operation: FdOperation::Read,
        },
        LINUX_X86_64_SYS_PREADV | LINUX_X86_64_SYS_PREADV2 => ClassifiedFdOperation {
            fd: syscall_fd_arg(syscall.args[0])?,
            operation: FdOperation::Preadv,
        },
        LINUX_X86_64_SYS_PWRITEV | LINUX_X86_64_SYS_PWRITEV2 => ClassifiedFdOperation {
            fd: syscall_fd_arg(syscall.args[0])?,
            operation: FdOperation::Pwritev,
        },
        LINUX_X86_64_SYS_MMAP => {
            let fd = syscall.args[4] as i32;
            if fd < 0 {
                return Ok(None);
            }
            ClassifiedFdOperation {
                fd,
                operation: FdOperation::Mmap,
            }
        }
        LINUX_X86_64_SYS_FCNTL => {
            let command = syscall.args[1];
            let operation = if is_fcntl_lock_command(command) {
                FdOperation::FcntlLock
            } else {
                FdOperation::Generic
            };
            ClassifiedFdOperation {
                fd: syscall_fd_arg(syscall.args[0])?,
                operation,
            }
        }
        _ => return Ok(None),
    };
    Ok(Some(classified))
}

fn syscall_fd_arg(raw: u64) -> Result<FdNumber, FdError> {
    let fd = raw as i32;
    if fd < 0 {
        return Err(FdError::InvalidFd(fd));
    }
    Ok(fd)
}

fn is_fcntl_lock_command(command: u64) -> bool {
    matches!(
        command,
        LINUX_F_SETLK | LINUX_F_SETLKW | LINUX_F_OFD_SETLK | LINUX_F_OFD_SETLKW
    )
}

pub(crate) fn handle_intercepted_syscall_stop(
    fd_system: &mut KboxlikeFdSystem,
    registry: &KboxlikeTraceeRegistry,
    host_pid: i32,
    syscall: InterceptedSyscall,
    supervisor_pid: i32,
    writer: &mut impl TraceeMemoryWriter,
    executor: &mut impl TraceeSyscallExecutor,
) -> Result<SyscallStopOutcome, FdError> {
    let Some(request) = registry.install_request_for_syscall(host_pid, syscall)? else {
        return Ok(SyscallStopOutcome::Unclassified);
    };
    if matches!(
        fd_system.descriptor(request.model_pid, request.fd),
        Err(FdError::BadFd(_))
    ) && request.fd <= 2
        && linux_tracee_fd_exists(host_pid, request.fd)
    {
        if std::env::var_os("SUPERMACHINE_KBOXLIVE_TRACE").is_some() {
            eprintln!(
                "KBOXLIVE_RESEED_STDIO host_pid={} model_pid={} fd={} op={:?}",
                host_pid, request.model_pid, request.fd, request.operation
            );
        }
        fd_system.insert_plain_fd(
            request.model_pid,
            request.fd,
            Some(request.fd as i64),
            false,
        )?;
    }
    let installed = match install_requested_operation_shadow_if_needed(
        fd_system,
        request,
        supervisor_pid,
        writer,
        executor,
    ) {
        Ok(installed) => installed,
        Err(FdError::BadFd(_)) if request.operation == FdOperation::Generic => {
            return Ok(SyscallStopOutcome::NoShadowNeeded);
        }
        Err(FdError::BadFd(fd)) if linux_tracee_fd_is_closed(host_pid, fd) => {
            if std::env::var_os("SUPERMACHINE_KBOXLIVE_TRACE").is_some() {
                eprintln!(
                    "KBOXLIVE_ALLOW_CLOSED_FD host_pid={} model_pid={} fd={} op={:?}",
                    host_pid, request.model_pid, fd, request.operation
                );
            }
            return Ok(SyscallStopOutcome::NoShadowNeeded);
        }
        Err(err) => {
            if std::env::var_os("SUPERMACHINE_KBOXLIVE_TRACE").is_some() {
                eprintln!(
                    "KBOXLIVE_FD_INSTALL_ERR host_pid={} model_pid={} fd={} op={:?} err={:?} proc_fd_exists={}",
                    host_pid,
                    request.model_pid,
                    request.fd,
                    request.operation,
                    err,
                    linux_tracee_fd_exists(host_pid, request.fd)
                );
            }
            return Err(err);
        }
    };
    if installed {
        Ok(SyscallStopOutcome::InstalledShadow)
    } else {
        Ok(SyscallStopOutcome::NoShadowNeeded)
    }
}

fn linux_tracee_fd_is_closed(host_pid: i32, fd: FdNumber) -> bool {
    !linux_tracee_fd_exists(host_pid, fd)
}

fn linux_tracee_fd_exists(host_pid: i32, fd: FdNumber) -> bool {
    #[cfg(all(target_os = "linux", target_arch = "x86_64"))]
    {
        if host_pid <= 0 || fd < 0 {
            return false;
        }
        return std::path::Path::new(&format!("/proc/{host_pid}/fd/{fd}")).exists();
    }
    #[cfg(not(all(target_os = "linux", target_arch = "x86_64")))]
    {
        let _ = (host_pid, fd);
        false
    }
}

#[cfg(all(target_os = "linux", target_arch = "x86_64"))]
pub(crate) fn handle_linux_x86_64_syscall_stop_in_stopped_tracee(
    fd_system: &KboxlikeFdSystem,
    registry: &KboxlikeTraceeRegistry,
    host_pid: i32,
    regs: &libc::user_regs_struct,
    supervisor_pid: i32,
) -> Result<SyscallStopOutcome, FdError> {
    let Some(request) = registry.install_request_for_linux_x86_64_regs(host_pid, regs)? else {
        return Ok(SyscallStopOutcome::Unclassified);
    };
    if install_requested_operation_shadow_in_stopped_tracee(fd_system, request, supervisor_pid)? {
        Ok(SyscallStopOutcome::InstalledShadow)
    } else {
        Ok(SyscallStopOutcome::NoShadowNeeded)
    }
}

#[cfg(test)]
mod tests {
    use super::super::fd::{ShadowKind, ShadowObject};
    use super::super::tracee::TraceeSyscall;
    use super::*;
    use std::collections::VecDeque;

    #[derive(Default)]
    struct FakeTracee {
        calls: Vec<TraceeSyscall>,
        returns: VecDeque<i64>,
    }

    #[derive(Default)]
    struct FakeMemory {
        writes: Vec<(u64, Vec<u8>)>,
    }

    impl FakeTracee {
        fn with_returns(returns: impl IntoIterator<Item = i64>) -> Self {
            Self {
                calls: Vec::new(),
                returns: returns.into_iter().collect(),
            }
        }
    }

    impl TraceeSyscallExecutor for FakeTracee {
        fn syscall(&mut self, syscall: TraceeSyscall) -> Result<i64, FdError> {
            self.calls.push(syscall);
            Ok(self.returns.pop_front().unwrap_or(0))
        }
    }

    impl TraceeMemoryWriter for FakeMemory {
        fn write_bytes(&mut self, addr: u64, bytes: &[u8]) -> Result<(), FdError> {
            self.writes.push((addr, bytes.to_vec()));
            Ok(())
        }
    }

    fn syscall(nr: i64, args: [u64; 6]) -> InterceptedSyscall {
        InterceptedSyscall::new(nr, args)
    }

    #[test]
    fn registry_maps_host_tracee_to_model_process() {
        let mut registry = KboxlikeTraceeRegistry::new();

        registry.register_tracee(4321, 7).unwrap();

        assert_eq!(registry.model_pid(4321).unwrap(), 7);
        assert_eq!(registry.model_thread_id(4321).unwrap(), 1);
        assert!(registry.contains_tracee(4321));
        assert_eq!(registry.tracees(), vec![(4321, 7)]);
        assert_eq!(
            registry.tracee_identities(),
            vec![KboxlikeTraceeIdentity {
                host_pid: 4321,
                model_pid: 7,
                model_thread_id: 1,
            }]
        );
        assert_eq!(registry.unregister_tracee(4321), Some(7));
        assert!(!registry.contains_tracee(4321));
        assert!(registry.tracees().is_empty());
        assert_eq!(
            registry.model_pid(4321).unwrap_err(),
            FdError::TraceeInstallFailed("unknown tracee pid")
        );
    }

    #[test]
    fn registry_lists_tracees_in_host_pid_order() {
        let mut registry = KboxlikeTraceeRegistry::new();

        registry.register_tracee(5000, 9).unwrap();
        registry.register_tracee(4000, 7).unwrap();
        registry.register_tracee(4500, 7).unwrap();

        assert_eq!(registry.tracees(), vec![(4000, 7), (4500, 7), (5000, 9)]);
        assert_eq!(
            registry.tracee_identities(),
            vec![
                KboxlikeTraceeIdentity {
                    host_pid: 4000,
                    model_pid: 7,
                    model_thread_id: 2,
                },
                KboxlikeTraceeIdentity {
                    host_pid: 4500,
                    model_pid: 7,
                    model_thread_id: 3,
                },
                KboxlikeTraceeIdentity {
                    host_pid: 5000,
                    model_pid: 9,
                    model_thread_id: 1,
                },
            ]
        );
    }

    #[test]
    fn registry_rejects_invalid_host_pid() {
        let mut registry = KboxlikeTraceeRegistry::new();

        assert_eq!(
            registry.register_tracee(0, 7).unwrap_err(),
            FdError::TraceeInstallFailed("invalid tracee pid")
        );
        registry.register_tracee(4321, 7).unwrap();
        assert_eq!(
            registry.register_tracee(4321, 8).unwrap_err(),
            FdError::TraceeInstallFailed("tracee pid already registered")
        );
        assert_eq!(
            registry.model_pid(-1).unwrap_err(),
            FdError::TraceeInstallFailed("invalid tracee pid")
        );
        assert_eq!(
            registry.model_thread_id(-1).unwrap_err(),
            FdError::TraceeInstallFailed("invalid tracee pid")
        );
    }

    #[test]
    fn classifier_maps_common_fd_syscalls() {
        assert_eq!(
            classify_fd_operation(syscall(LINUX_X86_64_SYS_READ, [4, 0, 0, 0, 0, 0])).unwrap(),
            Some(ClassifiedFdOperation {
                fd: 4,
                operation: FdOperation::Read,
            })
        );
        assert_eq!(
            classify_fd_operation(syscall(LINUX_X86_64_SYS_WRITEV, [5, 0, 0, 0, 0, 0])).unwrap(),
            Some(ClassifiedFdOperation {
                fd: 5,
                operation: FdOperation::Writev,
            })
        );
        assert_eq!(
            classify_fd_operation(syscall(LINUX_X86_64_SYS_PREADV2, [6, 0, 0, 0, 0, 0])).unwrap(),
            Some(ClassifiedFdOperation {
                fd: 6,
                operation: FdOperation::Preadv,
            })
        );
        assert_eq!(
            classify_fd_operation(syscall(LINUX_X86_64_SYS_PWRITEV2, [7, 0, 0, 0, 0, 0])).unwrap(),
            Some(ClassifiedFdOperation {
                fd: 7,
                operation: FdOperation::Pwritev,
            })
        );
    }

    #[test]
    fn classifier_maps_mmap_fd_from_arg_four_and_skips_anonymous_mmap() {
        assert_eq!(
            classify_fd_operation(syscall(LINUX_X86_64_SYS_MMAP, [0, 0, 0, 0, 104, 0])).unwrap(),
            Some(ClassifiedFdOperation {
                fd: 104,
                operation: FdOperation::Mmap,
            })
        );
        assert_eq!(
            classify_fd_operation(syscall(
                LINUX_X86_64_SYS_MMAP,
                [0, 0, 0, 0, (-1i64) as u64, 0],
            ))
            .unwrap(),
            None
        );
        assert_eq!(
            classify_fd_operation(syscall(
                LINUX_X86_64_SYS_MMAP,
                [0, 0, 0, 0, u32::MAX as u64, 0]
            ))
            .unwrap(),
            None
        );
    }

    #[test]
    fn classifier_maps_fcntl_lock_commands_distinct_from_generic_fcntl() {
        assert_eq!(
            classify_fd_operation(syscall(
                LINUX_X86_64_SYS_FCNTL,
                [8, LINUX_F_SETLK, 0, 0, 0, 0]
            ))
            .unwrap(),
            Some(ClassifiedFdOperation {
                fd: 8,
                operation: FdOperation::FcntlLock,
            })
        );
        assert_eq!(
            classify_fd_operation(syscall(LINUX_X86_64_SYS_FCNTL, [8, 1, 0, 0, 0, 0])).unwrap(),
            Some(ClassifiedFdOperation {
                fd: 8,
                operation: FdOperation::Generic,
            })
        );
    }

    #[test]
    fn classifier_skips_non_fd_syscalls_and_rejects_bad_fds() {
        assert_eq!(classify_fd_operation(syscall(9999, [0; 6])).unwrap(), None);
        assert_eq!(
            classify_fd_operation(syscall(
                LINUX_X86_64_SYS_READ,
                [(-1i64) as u64, 0, 0, 0, 0, 0]
            ))
            .unwrap_err(),
            FdError::InvalidFd(-1)
        );
    }

    #[test]
    fn registry_builds_tracee_install_request_from_classified_syscall() {
        let mut registry = KboxlikeTraceeRegistry::new();
        registry.register_tracee(4321, 7).unwrap();

        assert_eq!(
            registry
                .install_request_for_syscall(
                    4321,
                    syscall(LINUX_X86_64_SYS_MMAP, [0, 0, 0, 0, 104, 0]),
                )
                .unwrap(),
            Some(TraceeOperationInstallRequest {
                model_pid: 7,
                tracee_pid: 4321,
                fd: 104,
                operation: FdOperation::Mmap,
            })
        );
    }

    #[test]
    fn registry_skips_unclassified_syscall_without_requiring_registered_tracee() {
        let registry = KboxlikeTraceeRegistry::new();

        assert_eq!(
            registry
                .install_request_for_syscall(4321, syscall(9999, [0; 6]))
                .unwrap(),
            None
        );
    }

    #[test]
    fn syscall_stop_handler_skips_unclassified_syscall() {
        let mut fds = KboxlikeFdSystem::new();
        let registry = KboxlikeTraceeRegistry::new();
        let mut memory = FakeMemory::default();
        let mut tracee = FakeTracee::with_returns([0x8000]);

        assert_eq!(
            handle_intercepted_syscall_stop(
                &mut fds,
                &registry,
                4321,
                syscall(9999, [0; 6]),
                1234,
                &mut memory,
                &mut tracee,
            )
            .unwrap(),
            SyscallStopOutcome::Unclassified
        );
        assert!(memory.writes.is_empty());
        assert!(tracee.calls.is_empty());
    }

    #[test]
    fn syscall_stop_handler_reports_no_shadow_for_plain_lkl_fd() {
        let mut fds = KboxlikeFdSystem::new();
        let pid = fds.spawn_init();
        fds.insert_plain_fd(pid, 104, Some(204), false).unwrap();
        let mut registry = KboxlikeTraceeRegistry::new();
        registry.register_tracee(4321, pid).unwrap();
        let mut memory = FakeMemory::default();
        let mut tracee = FakeTracee::with_returns([0x8000]);

        assert_eq!(
            handle_intercepted_syscall_stop(
                &mut fds,
                &registry,
                4321,
                syscall(LINUX_X86_64_SYS_MMAP, [0, 0, 0, 0, 104, 0]),
                1234,
                &mut memory,
                &mut tracee,
            )
            .unwrap(),
            SyscallStopOutcome::NoShadowNeeded
        );
        assert!(memory.writes.is_empty());
        assert!(tracee.calls.is_empty());
    }

    #[test]
    fn syscall_stop_handler_allows_generic_fcntl_on_unknown_fd() {
        let mut fds = KboxlikeFdSystem::new();
        let pid = fds.spawn_init();
        let mut registry = KboxlikeTraceeRegistry::new();
        registry.register_tracee(4321, pid).unwrap();
        let mut memory = FakeMemory::default();
        let mut tracee = FakeTracee::with_returns([0x8000]);

        assert_eq!(
            handle_intercepted_syscall_stop(
                &mut fds,
                &registry,
                4321,
                syscall(LINUX_X86_64_SYS_FCNTL, [3, 2, 1, 0, 0, 0]),
                1234,
                &mut memory,
                &mut tracee,
            )
            .unwrap(),
            SyscallStopOutcome::NoShadowNeeded
        );
        assert!(memory.writes.is_empty());
        assert!(tracee.calls.is_empty());
    }

    #[test]
    fn syscall_stop_handler_installs_shadow_for_shadowed_mmap_fd() {
        let mut fds = KboxlikeFdSystem::new();
        let pid = fds.spawn_init();
        fds.insert_shadow_fd(
            pid,
            104,
            Some(204),
            ShadowObject {
                kind: ShadowKind::LocalOnly,
                supervisor_fd: 700,
            },
            false,
        )
        .unwrap();
        let mut registry = KboxlikeTraceeRegistry::new();
        registry.register_tracee(4321, pid).unwrap();
        let mut memory = FakeMemory::default();
        let mut tracee = FakeTracee::with_returns([0x8000, 901, 104, 0, 0, 0]);

        assert_eq!(
            handle_intercepted_syscall_stop(
                &mut fds,
                &registry,
                4321,
                syscall(LINUX_X86_64_SYS_MMAP, [0, 0, 0, 0, 104, 0]),
                1234,
                &mut memory,
                &mut tracee,
            )
            .unwrap(),
            SyscallStopOutcome::InstalledShadow
        );
        assert_eq!(
            memory.writes,
            vec![(0x8000, b"/proc/1234/fd/700\0".to_vec())]
        );
        assert!(!tracee.calls.is_empty());
    }

    #[test]
    fn syscall_stop_handler_errors_for_unknown_tracee_on_classified_syscall() {
        let mut fds = KboxlikeFdSystem::new();
        let registry = KboxlikeTraceeRegistry::new();
        let mut memory = FakeMemory::default();
        let mut tracee = FakeTracee::default();

        assert_eq!(
            handle_intercepted_syscall_stop(
                &mut fds,
                &registry,
                4321,
                syscall(LINUX_X86_64_SYS_MMAP, [0, 0, 0, 0, 104, 0]),
                1234,
                &mut memory,
                &mut tracee,
            )
            .unwrap_err(),
            FdError::TraceeInstallFailed("unknown tracee pid")
        );
    }

    #[cfg(all(target_os = "linux", target_arch = "x86_64"))]
    #[test]
    fn intercepted_syscall_decodes_linux_x86_64_registers() {
        let mut regs: libc::user_regs_struct = unsafe { std::mem::zeroed() };
        regs.orig_rax = LINUX_X86_64_SYS_MMAP as u64;
        regs.rdi = 1;
        regs.rsi = 2;
        regs.rdx = 3;
        regs.r10 = 4;
        regs.r8 = 104;
        regs.r9 = 6;

        assert_eq!(
            InterceptedSyscall::from_linux_x86_64_regs(&regs),
            InterceptedSyscall {
                nr: LINUX_X86_64_SYS_MMAP,
                args: [1, 2, 3, 4, 104, 6],
            }
        );
    }

    #[cfg(all(target_os = "linux", target_arch = "x86_64"))]
    #[test]
    fn registry_builds_request_from_linux_x86_64_registers() {
        let mut registry = KboxlikeTraceeRegistry::new();
        registry.register_tracee(4321, 7).unwrap();
        let mut regs: libc::user_regs_struct = unsafe { std::mem::zeroed() };
        regs.orig_rax = LINUX_X86_64_SYS_MMAP as u64;
        regs.r8 = 104;

        assert_eq!(
            registry
                .install_request_for_linux_x86_64_regs(4321, &regs)
                .unwrap(),
            Some(TraceeOperationInstallRequest {
                model_pid: 7,
                tracee_pid: 4321,
                fd: 104,
                operation: FdOperation::Mmap,
            })
        );
    }
}
