1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
use shadow_shmem::allocator::ShMemBlockSerialized;
use vasi::VirtualAddressSpaceIndependent;

use crate::syscall_types::{ForeignPtr, SyscallArgs, SyscallReg, UntypedForeignPtr};

#[derive(Copy, Clone, Debug, VirtualAddressSpaceIndependent)]
#[repr(C)]
/// Data for [`ShimEventToShim::Syscall`] and [`ShimEventToShadow::Syscall`]
pub struct ShimEventSyscall {
    pub syscall_args: SyscallArgs,
}

/// Data for [`ShimEventToShim::SyscallComplete`] and [`ShimEventToShadow::SyscallComplete`]
#[derive(Copy, Clone, Debug, VirtualAddressSpaceIndependent)]
#[repr(C)]
pub struct ShimEventSyscallComplete {
    pub retval: SyscallReg,
    /// Whether the syscall is eligible to be restarted. Only applicable
    /// when retval is -EINTR. See signal(7).
    pub restartable: bool,
}

/// Data for [`ShimEventToShim::AddThreadReq`]
#[derive(Copy, Clone, Debug, VirtualAddressSpaceIndependent)]
#[repr(C)]
pub struct ShimEventAddThreadReq {
    pub ipc_block: ShMemBlockSerialized,
    /// clone flags.
    pub flags: libc::c_ulong,
    /// clone stack. u8 pointer in shim's memory
    pub child_stack: UntypedForeignPtr,
    /// clone ptid. pid_t pointer in shim's memory
    pub ptid: UntypedForeignPtr,
    /// clone ctid. pid_t pointer in shim's memory
    pub ctid: UntypedForeignPtr,
    /// clone tls.
    pub newtls: libc::c_ulong,
}

/// Data for [`ShimEventToShadow::AddThreadRes`]
#[derive(Copy, Clone, Debug, VirtualAddressSpaceIndependent)]
#[repr(C)]
pub struct ShimEventAddThreadRes {
    pub clone_res: i64,
}

/// Data for [`ShimEventToShadow::StartReq`]
#[derive(Copy, Clone, Debug, VirtualAddressSpaceIndependent)]
#[repr(C)]
pub struct ShimEventStartReq {
    /// Shim pointer to be initd by Shadow. Required.
    pub thread_shmem_block_to_init: ForeignPtr<ShMemBlockSerialized>,
    /// Shim pointer to be initd by Shadow. Optional.
    pub process_shmem_block_to_init: ForeignPtr<ShMemBlockSerialized>,

    /// Shim pointer to be initd by Shadow. Optional.
    /// If set, shadow will write a null-terminated path.
    // TODO: Consider putting in persistent shared memory instead.
    // This has the drawback though of requiring us to statically allocate
    // the maximum path size (e.g. linux_api::limits::PATH_MAX == 4k).
    // Whether and how to do this also depends how we end up implementing
    // `chdir` https://github.com/shadow/shadow/issues/2960
    pub initial_working_dir_to_init: ForeignPtr<u8>,
    pub initial_working_dir_to_init_len: usize,
}

/// A message between Shadow and the Shim.

#[derive(Copy, Clone, Debug, VirtualAddressSpaceIndependent)]
// SAFETY: `shimevent2shadow_getId` assumes this representation.
#[repr(u32)]
// Clippy suggests boxing large enum variants. We can't do that, since
// it'd make ShimEvent unsafe for use in shared memory.
#[allow(clippy::large_enum_variant)]
pub enum ShimEventToShadow {
    /// First message from the shim, requesting that it's ready to start
    /// executing.
    StartReq(ShimEventStartReq),
    /// The whole process has died.
    /// We inject this event to trigger cleanup after we've detected that the
    /// native process has died.
    ProcessDeath,
    /// Request to emulate the given syscall.
    Syscall(ShimEventSyscall),
    /// Response to ShimEventToShim::Syscall
    SyscallComplete(ShimEventSyscallComplete),
    /// Response to `ShimEventToShim::AddThreadReq`
    AddThreadRes(ShimEventAddThreadRes),
}

#[derive(Copy, Clone, Debug, VirtualAddressSpaceIndependent)]
// SAFETY: `shimevent2shim_getId` assumes this representation.
#[repr(u32)]
// Clippy suggests boxing large enum variants. We can't do that, since
// it'd make ShimEvent unsafe for use in shared memory.
#[allow(clippy::large_enum_variant)]
pub enum ShimEventToShim {
    /// First message from shadow, indicating that it is ready for
    /// the shim to start executing.
    StartRes,
    /// Request to execute the given syscall natively.
    Syscall(ShimEventSyscall),
    /// Request from Shadow to Shim to take the included shared memory block,
    /// which holds an `IpcData`, and use it to initialize a newly spawned
    /// thread.
    AddThreadReq(ShimEventAddThreadReq),
    /// Response to ShimEventToShadow::Syscall
    SyscallComplete(ShimEventSyscallComplete),
    /// Response to ShimEventToShadow::Syscall indicating to execute it
    /// natively.
    SyscallDoNative,
}