flysand7 1 year ago
parent
commit
7faa146004
4 changed files with 1149 additions and 61 deletions
  1. 170 0
      core/sys/linux/bits.odin
  2. 83 0
      core/sys/linux/constants.odin
  3. 444 61
      core/sys/linux/sys.odin
  4. 452 0
      core/sys/linux/types.odin

+ 170 - 0
core/sys/linux/bits.odin

@@ -1398,3 +1398,173 @@ PER_OSF4        :: 0x000f
 PER_HPUX        :: 0x0010
 PER_MASK        :: 0x00ff
 
+/*
+	Bits for access modes for shared memory
+*/
+IPC_Mode_Bits :: enum {
+	WROTH  = 1,
+	RDOTH  = 2,
+	WRGRP  = 4,
+	RDGRP  = 5,
+	WRUSR  = 7,
+	RDUSR  = 8,
+	DEST   = 9,
+	LOCKED = 10,
+}
+
+/*
+	Shared memory flags bits
+*/
+IPC_Flags_Bits :: enum {
+	IPC_CREAT     = 9,
+	IPC_EXCL      = 10,
+	IPC_NOWAIT    = 11,
+	// Semaphore
+	SEM_UNDO      = 9,
+	// Shared memory
+	SHM_HUGETLB   = 11,
+	SHM_NORESERVE = 12,
+	SHM_RDONLY    = 12,
+	SHM_RND       = 13,
+	SHM_REMAP     = 14,
+	SHM_EXEC      = 15,
+	// Message queue
+	MSG_NOERROR   = 12,
+	MSG_EXCEPT    = 13,
+	MSG_COPY      = 14,
+}
+
+/*
+	IPC memory commands
+*/
+IPC_Cmd :: enum i16 {
+	// IPC common
+	IPC_RMID     = 0,
+	IPC_SET      = 1,
+	IPC_STAT     = 2,
+	// Shared memory
+	SHM_LOCK     = 11,
+	SHM_UNLOCK   = 12,
+	SHM_STAT     = 13,
+	SHM_INFO     = 14,
+	SHM_STAT_ANY = 15,
+	// Semaphore
+	GETPID       = 11,
+	GETVAL       = 12,
+	GETALL       = 13,
+	GETNCNT      = 14,
+	GETZCNT      = 15,
+	SETVAL       = 16,
+	SETALL       = 17,
+	SEM_STAT     = 18,
+	SEM_INFO     = 19,
+	SEM_STAT_ANY = 20,
+	// Message queue
+	MSG_STAT     = 11,
+	MSG_INFO     = 12,
+	MSG_STAT_ANY = 13,
+}
+
+/*
+	File locking operation bits
+*/
+FLock_Op_Bits :: enum {
+	SH = 1,
+	EX = 2,
+	NB = 4,
+	UN = 8,
+}
+
+/*
+	ptrace requests
+*/
+PTrace_Request :: enum {
+	TRACEME                = 0,
+	PEEKTEXT               = 1,
+	PEEKDATA               = 2,
+	PEEKUSER               = 3,
+	POKETEXT               = 4,
+	POKEDATA               = 5,
+	POKEUSER               = 6,
+	CONT                   = 7,
+	KILL                   = 8,
+	SINGLESTEP             = 9,
+	GETREGS                = 12,
+	SETREGS                = 13,
+	GETFPREGS              = 14,
+	SETFPREGS              = 15,
+	ATTACH                 = 16,
+	DETACH                 = 17,
+	GETFPXREGS             = 18,
+	SETFPXREGS             = 19,
+	SYSCALL                = 24,
+	GET_THREAD_AREA        = 25,
+	SET_THREAD_AREA        = 26,
+	ARCH_PRCTL             = 30,
+	SYSEMU                 = 31,
+	SYSEMU_SINGLESTEP      = 32,
+	SINGLEBLOCK            = 33,
+	SETOPTIONS             = 0x4200,
+	GETEVENTMSG            = 0x4201,
+	GETSIGINFO             = 0x4202,
+	SETSIGINFO             = 0x4203,
+	GETREGSET              = 0x4204,
+	SETREGSET              = 0x4205,
+	SEIZE                  = 0x4206,
+	INTERRUPT              = 0x4207,
+	LISTEN                 = 0x4208,
+	PEEKSIGINFO            = 0x4209,
+	GETSIGMASK             = 0x420a,
+	SETSIGMASK             = 0x420b,
+	SECCOMP_GET_FILTER     = 0x420c,
+	SECCOMP_GET_METADATA   = 0x420d,
+	GET_SYSCALL_INFO       = 0x420e,
+	GET_RSEQ_CONFIGURATION = 0x420f,
+};
+
+/*
+	ptrace options
+*/
+PTrace_Options_Bits :: enum {
+	TRACESYSGOOD    = 0,
+	TRACEFORK       = 1,
+	TRACEVFORK      = 2,
+	TRACECLONE      = 3,
+	TRACEEXEC       = 4,
+	TRACEVFORKDONE  = 5,
+	TRACEEXIT       = 6,
+	TRACESECCOMP    = 7,
+	EXITKILL        = 20,
+	SUSPEND_SECCOMP = 21,
+}
+
+/*
+	ptrace event codes.
+*/
+PTrace_Event_Code :: enum {
+	EVENT_FORK       = 1,
+	EVENT_VFORK      = 2,
+	EVENT_CLONE      = 3,
+	EVENT_EXEC       = 4,
+	EVENT_VFORK_DONE = 5,
+	EVENT_EXIT       = 6,
+	EVENT_SECCOMP    = 7,
+	EVENT_STOP       = 128,
+}
+
+/*
+	ptrace's get syscall info operation.
+*/
+PTrace_Get_Syscall_Info_Op :: enum u8 {
+	NONE    = 0,
+	ENTRY   = 1,
+	EXIT    = 2,
+	SECCOMP = 3,
+};
+
+/*
+	ptrace's PEEKSIGINFO flags bits
+*/
+PTrace_Peek_Sig_Info_Flags_Bits :: enum {
+	SHARED = 0,
+}

+ 83 - 0
core/sys/linux/constants.odin

@@ -83,6 +83,10 @@ STATX_BASIC_STATS :: Statx_Mask {
 	.BLOCKS,
 }
 
+/*
+	Tell `shmget` to create a new key
+*/
+IPC_PRIVATE :: Key(0)
 
 FCntl_Command_DUPFD            :: distinct FCntl_Command
 FCntl_Command_GETFD            :: distinct FCntl_Command
@@ -197,3 +201,82 @@ FUTEX_WAIT_REQUEUE_PI :: Futex_Wait_requeue_Pi_Type(.WAIT_REQUEUE_PI)
 FUTEX_CMP_REQUEUE_PI  :: Futex_Cmp_requeue_Pi_Type(.CMP_REQUEUE_PI)
 FUTEX_LOCK_PI2        :: Futex_Lock_Pi2_Type(.LOCK_PI2)
 
+PTrace_Traceme_Type                :: distinct PTrace_Request
+PTrace_Peek_Type                   :: distinct PTrace_Request
+PTrace_Poke_Type                   :: distinct PTrace_Request
+PTrace_Cont_Type                   :: distinct PTrace_Request
+PTrace_Kill_Type                   :: distinct PTrace_Request
+PTrace_Singlestep_Type             :: distinct PTrace_Request
+PTrace_Getregs_Type                :: distinct PTrace_Request
+PTrace_Setregs_Type                :: distinct PTrace_Request
+PTrace_Getfpregs_Type              :: distinct PTrace_Request
+PTrace_Setfpregs_Type              :: distinct PTrace_Request
+PTrace_Attach_Type                 :: distinct PTrace_Request
+PTrace_Detach_Type                 :: distinct PTrace_Request
+PTrace_Getfpxregs_Type             :: distinct PTrace_Request
+PTrace_Setfpxregs_Type             :: distinct PTrace_Request
+PTrace_Syscall_Type                :: distinct PTrace_Request
+PTrace_Get_Thread_Area_Type        :: distinct PTrace_Request
+PTrace_Set_Thread_Area_Type        :: distinct PTrace_Request
+PTrace_Arch_Prctl_Type             :: distinct PTrace_Request
+PTrace_Sysemu_Type                 :: distinct PTrace_Request
+PTrace_Sysemu_Singlestep_Type      :: distinct PTrace_Request
+PTrace_Singleblock_Type            :: distinct PTrace_Request
+PTrace_Setoptions_Type             :: distinct PTrace_Request
+PTrace_Geteventmsg_Type            :: distinct PTrace_Request
+PTrace_Getsiginfo_Type             :: distinct PTrace_Request
+PTrace_Setsiginfo_Type             :: distinct PTrace_Request
+PTrace_Getregset_Type              :: distinct PTrace_Request
+PTrace_Setregset_Type              :: distinct PTrace_Request
+PTrace_Seize_Type                  :: distinct PTrace_Request
+PTrace_Interrupt_Type              :: distinct PTrace_Request
+PTrace_Listen_Type                 :: distinct PTrace_Request
+PTrace_Peeksiginfo_Type            :: distinct PTrace_Request
+PTrace_Getsigmask_Type             :: distinct PTrace_Request
+PTrace_Setsigmask_Type             :: distinct PTrace_Request
+PTrace_Seccomp_Get_Filter_Type     :: distinct PTrace_Request
+PTrace_Seccomp_Get_Metadata_Type   :: distinct PTrace_Request
+PTrace_Get_Syscall_Info_Type       :: distinct PTrace_Request
+PTrace_Get_RSeq_Configuration_Type :: distinct PTrace_Request
+
+PTRACE_TRACEME                :: PTrace_Traceme_Type(.TRACEME)
+PTRACE_PEEKTEXT               :: PTrace_Peek_Type(.PEEKTEXT)
+PTRACE_PEEKDATA               :: PTrace_Peek_Type(.PEEKDATA)
+PTRACE_PEEKUSER               :: PTrace_Peek_Type(.PEEKUSER)
+PTRACE_POKETEXT               :: PTrace_Poke_Type(.POKETEXT)
+PTRACE_POKEDATA               :: PTrace_Poke_Type(.POKEDATA)
+PTRACE_POKEUSER               :: PTrace_Poke_Type(.POKEUSER)
+PTRACE_CONT                   :: PTrace_Cont_Type(.CONT)
+PTRACE_KILL                   :: PTrace_Kill_Type(.KILL)
+PTRACE_SINGLESTEP             :: PTrace_Singlestep_Type(.SINGLESTEP)
+PTRACE_GETREGS                :: PTrace_Getregs_Type(.GETREGS)
+PTRACE_SETREGS                :: PTrace_Setregs_Type(.SETREGS)
+PTRACE_GETFPREGS              :: PTrace_Getfpregs_Type(.GETFPREGS)
+PTRACE_SETFPREGS              :: PTrace_Setfpregs_Type(.SETFPREGS)
+PTRACE_ATTACH                 :: PTrace_Attach_Type(.ATTACH)
+PTRACE_DETACH                 :: PTrace_Detach_Type(.DETACH)
+PTRACE_GETFPXREGS             :: PTrace_Getfpxregs_Type(.GETFPXREGS)
+PTRACE_SETFPXREGS             :: PTrace_Setfpxregs_Type(.SETFPXREGS)
+PTRACE_SYSCALL                :: PTrace_Syscall_Type(.SYSCALL)
+PTRACE_GET_THREAD_AREA        :: PTrace_Get_Thread_Area_Type(.GET_THREAD_AREA)
+PTRACE_SET_THREAD_AREA        :: PTrace_Set_Thread_Area_Type(.SET_THREAD_AREA)
+PTRACE_ARCH_PRCTL             :: PTrace_Arch_Prctl_Type(.ARCH_PRCTL)
+PTRACE_SYSEMU                 :: PTrace_Sysemu_Type(.SYSEMU)
+PTRACE_SYSEMU_SINGLESTEP      :: PTrace_Sysemu_Singlestep_Type(.SYSEMU_SINGLESTEP)
+PTRACE_SINGLEBLOCK            :: PTrace_Singleblock_Type(.SINGLEBLOCK)
+PTRACE_SETOPTIONS             :: PTrace_Setoptions_Type(.SETOPTIONS)
+PTRACE_GETEVENTMSG            :: PTrace_Geteventmsg_Type(.GETEVENTMSG)
+PTRACE_GETSIGINFO             :: PTrace_Getsiginfo_Type(.GETSIGINFO)
+PTRACE_SETSIGINFO             :: PTrace_Setsiginfo_Type(.SETSIGINFO)
+PTRACE_GETREGSET              :: PTrace_Getregset_Type(.GETREGSET)
+PTRACE_SETREGSET              :: PTrace_Setregset_Type(.SETREGSET)
+PTRACE_SEIZE                  :: PTrace_Seize_Type(.SEIZE)
+PTRACE_INTERRUPT              :: PTrace_Interrupt_Type(.INTERRUPT)
+PTRACE_LISTEN                 :: PTrace_Listen_Type(.LISTEN)
+PTRACE_PEEKSIGINFO            :: PTrace_Peeksiginfo_Type(.PEEKSIGINFO)
+PTRACE_GETSIGMASK             :: PTrace_Getsigmask_Type(.GETSIGMASK)
+PTRACE_SETSIGMASK             :: PTrace_Setsigmask_Type(.SETSIGMASK)
+PTRACE_SECCOMP_GET_FILTER     :: PTrace_Seccomp_Get_Filter_Type(.SECCOMP_GET_FILTER)
+PTRACE_SECCOMP_GET_METADATA   :: PTrace_Seccomp_Get_Metadata_Type(.SECCOMP_GET_METADATA)
+PTRACE_GET_SYSCALL_INFO       :: PTrace_Get_Syscall_Info_Type(.GET_SYSCALL_INFO)
+PTRACE_GET_RSEQ_CONFIGURATION :: PTrace_Get_RSeq_Configuration_Type(.GET_RSEQ_CONFIGURATION)

+ 444 - 61
core/sys/linux/sys.odin

@@ -165,7 +165,16 @@ munmap :: proc "contextless" (addr: rawptr, size: uint) -> (Errno) {
 	return Errno(-ret)
 }
 
-// TODO(flysand): brk
+/*
+	Extend the data segment size until the address `addr`. Note: you may be
+	familiar with sbrk(), which is not actually a syscall, so is not
+	implemented here.
+	Available since Linux 1.0.
+*/
+brk :: proc "contextless" (addr: uintptr) -> (Errno) {
+	ret := syscall(SYS_brk, addr)
+	return Errno(-ret)
+}
 
 /// Alter an action taken by a process
 rt_sigaction :: proc "contextless" (sig: Signal, sigaction: ^Sig_Action, old_sigaction: ^Sig_Action) -> Errno {
@@ -180,8 +189,6 @@ rt_sigprocmask :: proc "contextless" (mask_kind: Sig_Mask_Kind, new_set: ^Sig_Se
 	return Errno(-ret)
 }
 
-// TODO(flysand): rt_sigreturn
-
 // TODO(flysand): ioctl
 
 /// Read the file at a specified offset
@@ -200,9 +207,23 @@ pwrite :: proc "contextless" (fd: Fd, buf: []$T, offset: i64) -> (int, Errno) {
 	return errno_unwrap(ret, int)
 }
 
-// TODO(flysand): readv
+/*
+	Read the data from file into multiple buffers.
+	Available since Linux 2.0.
+*/
+readv :: proc "contextless" (fd: Fd, iov: []IO_Vec) -> (int, Errno) {
+	ret := syscall(SYS_readv, fd, raw_data(iov), len(iov))
+	return errno_unwrap(ret, int)
+}
 
-// TODO(flysand): writev
+/*
+	Write the data from multiple buffers into a file.
+	Available since Linux 2.0.
+*/
+writev :: proc "contextless" (fd: Fd, iov: []IO_Vec) -> (int, Errno) {
+	ret := syscall(SYS_writev, fd, raw_data(iov), len(iov))
+	return errno_unwrap(ret, int)
+}
 
 /// Check user permissions for a file
 /// If Mode is F_OK, checks whether the file exists
@@ -226,11 +247,18 @@ pipe2 :: proc "contextless" (pipes: ^[2]Fd, flags: Open_Flags) -> (Errno) {
 	return Errno(-ret)
 }
 
-// TODO(flysand): select
-
-// TODO(flysand): sched_yield
+/*
+	Yield the processor.
+	Available since Linux 2.0.
+*/
+sched_yield :: proc "contextless" () {
+	syscall(SYS_sched_yield)
+}
 
-// TODO(flysand): add docs here
+/*
+	Remap a virtual memory address.
+	Available since Linux 2.0.
+*/
 mremap :: proc "contextless" (old_addr: rawptr, old_size: uint, new_size: uint, flags: MRemap_Flags, new_addr: uintptr = 0) -> (rawptr, Errno) {
 	if .FIXED in flags {
 		ret := syscall(SYS_mremap, old_addr, old_size, new_size, transmute(i32) flags, new_addr)
@@ -248,7 +276,14 @@ msync :: proc "contextless" (addr: rawptr, size: uint, flags: MSync_Flags) -> (E
 	return Errno(-ret)
 }
 
-// TODO(flysand): mincore
+/*
+	Determine if pages are resident in memory.
+	Available since Linux 2.4.
+*/
+mincore :: proc "contextless" (addr: rawptr, size: uint, vec: []b8) -> (Errno) {
+	ret := syscall(SYS_mincore, addr, size, raw_data(vec))
+	return Errno(-ret)
+}
 
 /// Give advice about use of memory
 /// Available since Linux 2.4
@@ -257,11 +292,44 @@ madvise :: proc "contextless" (addr: rawptr, size: uint, advice: MAdvice) -> (Er
 	return Errno(-ret)
 }
 
-// TODO(flysand): shmget
+/*
+	Allocate a SystemV shared memory segment.
+	Available since Linux 2.0.
+*/
+shmget :: proc "contextless" (key: Key, size: uint, flags: IPC_Flags) -> (Key, Errno) {
+	ret := syscall(SYS_shmget, key, size, transmute(i16) flags)
+	return errno_unwrap(ret, Key)
+}
 
-// TODO(flysand): shmat
+/*
+	SystemV shared memory segment operations.
+	Available since Linux 2.0.
+*/
+shmat :: proc "contextless" (key: Key, addr: rawptr, flags: IPC_Flags) -> (rawptr, Errno) {
+	ret := syscall(SYS_shmat, key, addr, transmute(i16) flags)
+	return errno_unwrap(ret, Key)
+}
 
-// TODO(flysand): shmctl
+shmctl_ds :: proc "contextless" (key: Key, cmd: IPC_Cmd, buf: ^Shmid_DS) -> (Errno) {
+	ret := syscall(SYS_shmctl, key, cmd, buf)
+	return Errno(-ret)
+}
+
+shmctl_info :: proc "contextless" (key: Key, cmd: IPC_Cmd, buf: ^Shmid_Info) -> (int, Errno) {
+	ret := syscall(SYS_shmctl, key, cmd, buf)
+	return errno_unwrap(ret, int)
+}
+
+shmctl_stat :: proc "contextless" (index: int, cmd: IPC_Cmd, buf: ^Shmid_DS) -> (Key, Errno) {
+	ret := syscall(SYS_shmctl, key, cmd, buf)
+	return errno_unwrap(ret, Key)
+}
+
+/*
+	SystemV shared memory control.
+	Available since Linux 2.0.
+*/
+shmctl :: proc {shmctl_ds, shmctl_info, shmctl_stat}
 
 /// Allocate a new file descriptor that refers to the same file as the one provided
 /// Available since Linux 1.0
@@ -283,15 +351,48 @@ dup2 :: proc "contextless" (old: Fd, new: Fd) -> (Fd, Errno) {
 	}
 }
 
-// TODO(flysand): pause
+/*
+	Wait until the next signal is delivered.
+	Available since Linux 1.0.
+*/
+pause :: proc "contextless" () {
+	syscall(SYS_pause)
+}
 
-// TODO(flysand): nanosleep
+/*
+	High-resolution sleep.
+	Available since Linux 2.0.
+*/
+nanosleep :: proc "contextless" (req: ^Time_Spec, rem: ^Time_Spec) -> (Errno) {
+	ret := syscall(SYS_nanosleep, req, rem)
+	return Errno(-ret)
+}
 
-// TODO(flysand): getitimer
+/*
+	Get the value of an internal timer.
+	Available since Linux 1.0.
+*/
+getitimer :: proc "contextless" (which: ITimer_Which, cur: ^ITimer_Val) -> (Errno) {
+	ret := syscall(SYS_getitimer, cur)
+	return Errno(-ret)
+}
 
-// TODO(flysand): alarm
+/*
+	Set an alarm clock for delivery of a signal.
+	Available since Linux 1.0.
+*/
+alarm :: proc "contextless" (seconds: u32) -> u32 {
+	return cast(u32) syscall(SYS_alarm, seconds)
+}
 
-// TODO(flysand): setitimer
+/*
+	Set the value of an internal timer.
+	Available since Linux 1.0.
+*/
+getitimer :: proc "contextless" (which: ITimer_Which, new: ^ITimer_Val, old: ^ITimer_Val) -> (Errno) {
+	ret := syscall(SYS_getitimer, new, old)
+	return Errno(-ret)
+}
 
 /// Returns the thread group ID of the current process
 /// Note that it doesn't return the pid, despite it's name.
@@ -300,7 +401,20 @@ getpid :: proc "contextless" () -> Pid {
 	return cast(Pid) syscall(SYS_getpid)
 }
 
-// TODO(flysand): sendfile
+/*
+	Transfer the data between file descriptors.
+	Available since Linux 2.2.
+	On 32-bit platforms available since Linux 2.6.
+*/
+sendfile :: proc "contextless" (out: Fd, in: Fd, offset: ^i64, count: uint) -> (int, Errno) {
+	when size_of(int) == 8 {
+		ret := syscall(SYS_sendfile, out, in, offset, count)
+		return errno_unwrap(ret, Errno)
+	} else {
+		ret := syscall(SYS_sendfile64, out, in, offset, count)
+		return errno_unwrap(ret, Errno)
+	}
+}
 
 /// Create a socket file descriptor
 /// Available since Linux 2.0
@@ -377,10 +491,28 @@ recv :: proc {recvfrom, recv_noaddr}
 /// Available since Linux 2.0
 send :: proc {sendto, send_noaddr}
 
-// TODO(flysand): sendmsg
+/*
+	Send a message on a socket.
+	Available since Linux 2.0.
+*/
+sendmsg :: proc "contextless" (sock: Fd, msghdr: ^Msg_Hdr, flags: Socket_Msg) -> (int, Errno) {
+	ret := syscall(SYS_sendmsg, sock, msghdr, transmute(i32) flags)
+	return errno_unwrap(ret, int)
+}
 
-// TODO(flysand): recvmsg
+/*
+	Receive a message on a socket.
+	Available since Linux 2.0.
+*/
+recvmsg :: proc "contextless" (sock: Fd, msghdr: ^Msg_Hdr, flags: Socket_Msg) -> (int, Errno) {
+	ret := syscall(SYS_recvmsg, sock, msghdr, transmute(i32) flags)
+	return errno_unwrap(ret, int)
+}
 
+/*
+	Shutdown a socket.
+	Available since Linux 2.0.
+*/
 shutdown :: proc "contextless" (sock: Fd, how: Shutdown_How) -> (Errno) {
 	ret := syscall(SYS_shutdown, sock, how)
 	return Errno(-ret)
@@ -405,11 +537,34 @@ listen :: proc "contextless" (sock: Fd, queue_len: i32) -> (Errno) {
 	return Errno(-ret)
 }
 
-// TODO(flysand): getsockname
+/*
+	Get socket name (aka it's bound address).
+	Available since Linux 2.0.
+*/
+getsockname :: proc "contextless" (sock: Fd, addr: ^Sock_Addr_Any) -> (Errno) {
+	addr_len := size_of(Sock_Addr_Any)
+	ret := syscall(SYS_getsockname, sock, addr, &addr_len)
+	return Errno(-ret)
+}
 
-// TODO(flysand): getpeername
+/*
+	Get the name of the connected peer socket.
+	Available since Linux 2.0.
+*/
+getpeername :: proc "contextless" (sock: Fd, addr: ^Sock_Addr_Any) -> (Errno) {
+	addr_len := size_of(Sock_Addr_Any)
+	ret := syscall(SYS_getpeername, sock, addr, &addr_len)
+	return Errno(-ret)
+}
 
-// TODO(flysand): socketpair
+/*
+	Create a pair of connected sockets.
+	Available since Linux 2.0.
+*/
+socketpair :: proc "contextless" (domain: Protocol_Family, type: Socket_Type, proto: Protocol, pair: ^[2]Fd) -> (Errno) {
+	ret := syscall(SYS_socketpair, domain, type, proto, pair)
+	return Errno(-ret)
+}
 
 // TODO(flysand): the parameters are the same, maybe there's a way to make it into a single proc, sacrificing type
 // safety slightly
@@ -518,9 +673,32 @@ fork :: proc "contextless" () -> (Pid, Errno) {
 	}
 }
 
-// TODO(flysand): vfork
+/*
+	Create a child process and block parent.
+	Available since Linux 2.2.
+*/
+vfork :: proc "contextless" () -> Pid {
+	when ODIN_ARCH != .arm64 {
+		return Pid(syscall(SYS_vfork))
+	} else {
+		return Pid(syscall(SYS_fork))
+	}
+}
 
-// TODO(flysand): execve
+/*
+	Replace the current process with another program.
+	Available since Linux 1.0.
+	On ARM64 available since Linux 3.19.
+*/
+execve :: proc "contextless" (name: cstring, argv: [^]cstring, envp: [^]cstring) -> (Errno) {
+	when ODIN_ARCH != .arm64 {
+		ret := syscall(SYS_execve, cast(rawptr) name, cast(rawptr) argv, cast(rawptr) envp)
+		return Errno(-ret)
+	} else {
+		ret := syscall(SYS_execveat, AT_FDCWD, cast(rawptr) name, cast(rawptr) argv, cast(rawptr) envp)
+		return Errno(-ret)
+	}
+}
 
 /// Exit the thread with a given exit code
 /// Available since Linux 1.0
@@ -539,7 +717,14 @@ wait4 :: proc "contextless" (pid: Pid, status: ^u32, options: Wait_Options) -> (
 /// See wait4
 waitpid :: wait4
 
-// TODO(flysand): kill
+/*
+	Send signal to a process.
+	Available since Linux 1.0.
+*/
+kill :: proc "contextless" (pid: Pid, signal: Signal) -> (Errno) {
+	ret := syscall(SYS_kill, pid, signal)
+	return Errno(-ret)
+}
 
 /// Get system information
 /// Available since Linux 1.0
@@ -548,21 +733,84 @@ uname :: proc "contextless" (uts_name: ^UTS_Name) -> (Errno) {
 	return Errno(-ret)
 }
 
-// TODO(flysand): semget
+/*
+	Get a SystemV semaphore set identifier.
+	Available since Linux 2.0.
+*/
+semget :: proc "contextless" (key: Key, n: i32, flags: IPC_Flags) -> (Key, Errno) {
+	ret := syscall(SYS_semget, key, n, transmute(i16) flags)
+	return errno_unwrap(ret, Key)
+}
 
-// TODO(flysand): semop
+/*
+	SystemV semaphore operations.
+	Available since Linux 2.0.
+*/
+semop :: proc "contextless" (key: Key, ops: []Sem_Buf) -> (Errno) {
+	ret := syscall(SYS_semop, key, raw_data(ops), len(ops))
+	return Errno(-ret)
+}
 
-// TODO(flysand): semctl
+semctl3 :: proc "contextless" (key: Key, semnum: i32, cmd: IPC_Cmd) -> (int, Errno) {
+	ret := syscall(SYS_semctl, key, semnum, cmd)
+	return errno_unwrap(ret, int)
+}
 
-// TODO(flysand): shmdt
+semctl4 :: proc "contextless" (key: Key, semnum: i32, cmd: IPC_Cmd, semun: Sem_Un) -> (int, Errno) {
+	ret := syscall(SYS_semctl, key, semnum, cmd, semun)
+	return errno_unwrap(ret, int)
+}
 
-// TODO(flysand): msgget
+/*
+	SystemV semaphore control operations.
+	Available since Linux 2.0.
+*/
+semctl :: proc {semctl3, semctl4}
 
-// TODO(flysand): msgsnd
+/*
+	SystemV shared memory operations.
+	Available since Linux 2.0.
+*/
+shmdt :: proc "contextless" (shmaddr: rawptr) -> (Errno) {
+	ret := syscall(SYS_shmdt, shmaddr)
+	return Errno(-ret)
+}
 
-// TODO(flysand): msgrcv
+/*
+	Get SystemV message queue identifier.
+	Available since Linux 2.0.
+*/
+msgget :: proc "contextless" (key: Key, flags: IPC_Flags) -> (Key, Errno) {
+	ret := syscall(SYS_msgget, key, transmute(i16) flags)
+	return errno_unwrap(ret, Key)
+}
 
-// TODO(flysand): msgctl
+/*
+	Send message to a SystemV message queue.
+	Available since Linux 2.0.
+*/
+msgsnd :: proc "contextless" (key: Key, buf: rawptr, size: int, flags: IPC_Flags) -> (Errno) {
+	ret := syscall(SYS_msgsnd, key, buf, size, transmute(i16) flags)
+	return Errno(-ret)
+}
+
+/*
+	Receive a message from a SystemV message queue.
+	Available since Linux 2.0.
+*/
+msgrcv :: proc "contextless" (key: Key, buf: rawptr, size: int, type: uint, flags: IPC_Flags) -> (int, Errno) {
+	ret := syscall(SYS_msgrcv, key, buf, size, type, transmute(i16) flags)
+	return errno_unwrap(ret, int)
+}
+
+/*
+	SystemV message control operations.
+	Available since Linux 2.0.
+*/
+msgctl :: proc "contextless" (key: Key, cmd: IPC_Cmd, buf: ^Msqid_DS) -> (int, Errno) {
+	ret := syscall(SYS_msgctl, key, cmd, buf)
+	return errno_unwrap(ret, int)
+}
 
 fcntl_dupfd :: proc "contextless" (fd: Fd, cmd: FCntl_Command_DUPFD, newfd: Fd) -> (Fd, Errno) {
 	ret := syscall(SYS_fcntl, fd, cmd, newfd)
@@ -726,7 +974,14 @@ fcntl :: proc {
 	fcntl_set_file_rw_hint,
 }
 
-// TODO(flysand): flock
+/*
+	Apply or remove advisory lock on an open file.
+	Available since Linux 2.0.
+*/
+flock :: proc "contextless" (fd: Fd, operation: FLock_Op) -> (Errno) {
+	ret := syscall(SYS_flock, fd, transmute(i32) operation)
+	return Errno(-ret)
+}
 
 /// Sync state of the file with the storage device
 fsync :: proc "contextless" (fd: Fd) -> (Errno) {
@@ -734,7 +989,15 @@ fsync :: proc "contextless" (fd: Fd) -> (Errno) {
 	return Errno(-ret)
 }
 
-// TODO(flysand): fdatasync
+/*
+	Synchronize the state of the file with the storage device. Similar to `fsync`,
+	except does not flush the metadata.
+	Available since Linux 2.0.
+*/
+fdatasync :: proc "contextless" (fd: Fd) -> (Errno) {
+	ret := syscall(SYS_fdatasync, fd)
+	return Errno(-ret)
+}
 
 /// Truncate a file to specified length
 /// On 32-bit architectures available since Linux 2.4
@@ -828,7 +1091,19 @@ rmdir :: proc "contextless" (name: cstring) -> (Errno) {
 	}
 }
 
-// TODO(flysand): creat
+/*
+	Create a file.
+	Available since Linux 1.0.
+	On ARM64 available since Linux 2.6.16.
+*/
+creat :: proc "contextless" (name: cstring, mode: Mode) -> (Errno) {
+	when ODIN_ARCH == .arm64 {
+		return openat(AT_FDCWD, name, {.CREAT, .WRONLY,.TRUNC}, mode)
+	} else {
+		ret := syscall(SYS_creat, cast(rawptr) name, transmute(u32) mode)
+		return Errno(-ret)
+	}
+}
 
 /// Create a hard link on a file
 /// Available since Linux 1.0
@@ -949,9 +1224,23 @@ lchown :: proc "contextless" (name: cstring, uid: Uid, gid: Gid) -> (Errno) {
 	}
 }
 
-// TODO(flysand): umask
+/*
+	Set file mode creation mask.
+	Available since Linux 1.0.
+*/
+umask :: proc "contextless" (mask: Mask) -> Mask {
+	ret := syscall(SYS_umask, transmute(u32) mask)
+	return transmute(u32) cast(u32) ret
+}
 
-// TODO(flysand): gettimeofday
+/*
+	Get current time.
+	Available since Linux 1.0.
+*/
+gettimeofday :: proc "contextless" (tv: ^Time_Val) -> (Errno) {
+	ret := syscall(SYS_gettimeofday, tv)
+	return Errno(-ret)
+}
 
 /// Get limits on resources
 /// Available since Linux 1.0
@@ -980,7 +1269,97 @@ times :: proc "contextless" (tms: ^Tms) -> (Errno) {
 	return Errno(-ret)
 }
 
-// TODO(flysand): ptrace
+ptrace_traceme :: proc "contextless" (rq: PTrace_Traceme_Type) -> (Errno) {
+	ret := syscall(SYS_ptrace, rq)
+	return Errno(-ret)
+}
+
+ptrace_peek :: proc "contextless" (rq: PTrace_Peek_Type, addr: uintptr) -> (uint, Errno) {
+	ret := syscall(SYS_ptrace, rq, addr)
+	return errno_unwrap(rq, uint)
+}
+
+ptrace_poke :: proc "contextless" (rq: PTrace_Poke_Type, addr: uintptr, data: uint) -> (Errno) {
+	ret := syscall(SYS_ptrace, rq, addr, data)
+	return Errno(-ret)
+}
+
+ptrace_getregs :: proc "contextless" (rq: PTrace_Getregs_Type, buf: ^User_Regs) -> (Errno) {
+	ret := syscall(SYS_ptrace, rq, 0, buf)
+	return Errno(-ret)
+}
+
+ptrace_getfpregs :: proc "contextless" (rq: PTrace_Getfpregs_Type, buf: ^User_FP_Regs) -> (Errno) {
+	ret := syscall(SYS_ptrace, rq, 0, buf)
+	return Errno(-ret)
+}
+
+ptrace_getfpxregs :: proc "contextless" (rq: PTrace_Getfpxregs_Type, buf: ^User_FPX_Regs) -> (Errno) {
+	ret := syscall(SYS_ptrace, rq, 0, buf)
+	return Errno(-ret)
+}
+
+ptrace_setregs :: proc "contextless" (rq: PTrace_Setregs_Type, buf: ^User_Regs) -> (Errno) {
+	ret := syscall(SYS_ptrace, rq, 0, buf)
+	return Errno(-ret)
+}
+
+ptrace_setfpregs :: proc "contextless" (rq: PTrace_Setfpregs_Type, buf: ^User_FP_Regs) -> (Errno) {
+	ret := syscall(SYS_ptrace, rq, 0, buf)
+	return Errno(-ret)
+}
+
+ptrace_setfpxregs :: proc "contextless" (rq: PTrace_Setfpxregs_Type, buf: ^User_FPX_Regs) -> (Errno) {
+	ret := syscall(SYS_ptrace, rq, 0, buf)
+	return Errno(-ret)
+}
+
+// TODO(flysand): ptrace_getregset
+// TODO(flysand): ptrace_setregset
+// TODO(flysand): ptrace_setsiginfo
+// TODO(flysand): ptrace_peeksiginfo
+// TODO(flysand): ptrace_getsigmask
+// TODO(flysand): ptrace_setsigmask
+
+ptrace_setoptions :: proc "contextless" (rq: PTrace_Setoptions_Type, options: PTrace_Options) -> (Errno) {
+	ret := syscall(SYS_ptrace, rq, 0, transmute(u32) options)
+	return Errno(-ret)
+}
+
+// TODO(flysand): ptrace_geteventmsg
+// TODO(flysand): ptrace_cont
+// TODO(flysand): ptrace_syscall
+// TODO(flysand): ptrace_singlestep
+// TODO(flysand): ptrace_set_syscall
+// TODO(flysand): ptrace_sysemu
+// TODO(flysand): ptrace_sysemu_singlestep
+// TODO(flysand): ptrace_listen
+// TODO(flysand): ptrace_kill
+// TODO(flysand): ptrace_interrupt
+// TODO(flysand): ptrace_attach
+// TODO(flysand): ptrace_seize
+// TODO(flysand): ptrace_seccomp_get_filter
+// TODO(flysand): ptrace_detach
+// TODO(flysand): ptrace_get_thread_area
+// TODO(flysand): ptrace_set_thread_area
+// TODO(flysand): ptrace_get_syscall_info
+// TODO(flysand): ptrace_setsigmask
+
+/*
+	Trace process
+*/
+ptrace :: proc {
+	ptrace_traceme,
+	peek,
+	ptrace_poke,
+	ptrace_getregs,
+	ptrace_getfpregs,
+	ptrace_getfpxregs,
+	ptrace_setregs,
+	ptrace_setfpregs,
+	ptrace_setfpxregs,
+	ptrace_setoptions,
+}
 
 /// Get real user ID
 /// Available since Linux 1.0
@@ -1186,8 +1565,6 @@ getpgid :: proc "contextless" (pid: Pid) -> (Pid, Errno) {
 	return errno_unwrap(ret, Pid)
 }
 
-// NOTE(flysand): setfsuid and setfsgid are deprecated
-
 /// Get session ID of the calling process
 /// Available since Linux 2.0
 getsid :: proc "contextless" (pid: Pid) -> (Pid, Errno) {
@@ -1234,8 +1611,6 @@ sigaltstack :: proc "contextless" (stack: ^Sig_Stack, old_stack: ^Sig_Stack) ->
 	return Errno(-ret)
 }
 
-// TODO(flysand): utime
-
 /// Create a special or ordinary file
 /// `mode` parameter contains both the the file mode and the type of the node to create
 ///  ->  Add one of S_IFSOCK, S_IFBLK, S_IFFIFO, S_IFCHR to mode
@@ -1251,8 +1626,6 @@ mknod :: proc "contextless" (name: cstring, mode: Mode, dev: Dev) -> (Errno) {
 	}
 }
 
-// TODO(flysand): uselib
-
 /// Set the process execution domain
 /// Available since Linux 1.2
 personality :: proc "contextless" (personality: uint) -> (uint, Errno) {
@@ -1414,16 +1787,10 @@ setdomainname :: proc "contextless" (name: string) -> (Errno) {
 
 // TODO(flysand): ioperm
 
-// TODO(flysand): create_module
-
 // TODO(flysand): init_module
 
 // TODO(flysand): delete_module
 
-// TODO(flysand): get_kernel_syms
-
-// TODO(flysand): query_module
-
 // TODO(flysand): quotactl
 
 // TODO(flysand): nfsservctl
@@ -1474,9 +1841,14 @@ gettid :: proc "contextless" () -> Pid {
 
 // TODO(flysand): fremovexattr
 
-// TODO(flysand): tkill
-
-// TODO(flysand): time
+/*
+	Get current time in seconds.
+	Available since Linux 1.0.
+*/
+time :: proc "contextless" (tloc: ^uint) -> (Errno) {
+	ret := syscall(SYS_time, tloc)
+	return Errno(-ret)
+}
 
 /// Wait on a futex until it's signaled
 futex_wait :: proc "contextless" (futex: ^Futex, op: Futex_Wait_Type, flags: Futex_Flags, val: u32, timeout: ^Time_Spec = nil) -> (Errno) {
@@ -1593,8 +1965,6 @@ set_tid_address :: proc "contextless" (tidptr: ^u32) {
 	syscall(SYS_set_tid_address, tidptr)
 }
 
-// TODO(flysand): restart_syscall
-
 // TODO(flysand): semtimedop
 
 // TODO(flysand): fadvise64
@@ -1847,7 +2217,6 @@ dup3 :: proc "contextless" (old: Fd, new: Fd, flags: Open_Flags) -> (Fd, Errno)
 
 // TODO(flysand): pwritev
 
-
 /// Send signal information to a thread
 /// Available since Linux 2.2
 rt_tgsigqueueinfo :: proc "contextless" (tgid: Pid, pid: Pid, sig: Signal, si: ^Sig_Info) -> (Errno) {
@@ -1862,7 +2231,14 @@ perf_event_open :: proc "contextless" (attr: ^Perf_Event_Attr, pid: Pid, cpu: in
 	return errno_unwrap(ret, Fd)
 }
 
-// TODO(flysand): recvmmsg
+/*
+	Receive multiple messages from a socket.
+	Available since Linux 2.6.33.
+*/
+recvmmsg :: proc "contextless" (sock: Fd, msg_vec: []MMsg_Hdr, flags: Socket_Msg) -> (int, Errno) {
+	ret := syscall(SYS_recvmmsg, sock, raw_data(msg_vec), len(msg_vec), transmute(i32) flags)
+	return errno_unwrap(ret, int)
+}
 
 // TODO(flysand): fanotify_init
 
@@ -1878,7 +2254,14 @@ perf_event_open :: proc "contextless" (attr: ^Perf_Event_Attr, pid: Pid, cpu: in
 
 // TODO(flysand): syncfs
 
-// TODO(flysand): sendmmsg
+/*
+	Send multiple messages on a socket.
+	Available since Linux 3.0.
+*/
+sendmmsg :: proc "contextless" (sock: Fd, msg_vec: []MMsg_Hdr, flags: Socket_Msg) -> (int, Errno) {
+	ret := syscall(SYS_sendmmsg, sock, raw_data(msg_vec), len(msg_vec), transmute(i32) flags)
+	return errno_unwrap(ret, int)
+}
 
 // TODO(flysand): setns
 

+ 452 - 0
core/sys/linux/types.odin

@@ -26,6 +26,9 @@ Pid_FD :: distinct i32
 /// Used pretty much only in struct Stat64 for 32-bit platforms
 Inode :: distinct u64
 
+/// Shared memory identifiers used by `shm*` calls
+Key :: distinct i32
+
 /// Represents time with nanosecond precision
 Time_Spec :: struct {
 	time_sec:  uint,
@@ -38,6 +41,15 @@ Time_Val :: struct {
 	microseconds: int,
 }
 
+/*
+	Access and modification times for files
+*/
+UTim_Buf :: struct {
+	actime:  uint,
+	modtime: uint,
+};
+
+
 /// open.2 flags
 Open_Flags :: bit_set[Open_Flags_Bits; u32]
 
@@ -235,6 +247,13 @@ FLock :: struct {
 	pid:    Pid,
 }
 
+/*
+	File locking operations.
+	Use one of `EX`, `RW` or `UN` to specify the operation, and add `UN` if
+	you need a non-blocking operation.
+*/
+FLock_Op :: bit_set[FLock_Op_Bits; i32]
+
 /// Flags for fcntl_notify
 FD_Notifications :: bit_set[FD_Notifications_Bits; i32]
 
@@ -496,6 +515,25 @@ Sock_Addr_Any :: struct #raw_union {
 	using ipv6: Sock_Addr_In6,
 }
 
+/*
+	Message header for sendmsg/recvmsg
+*/
+Msg_Hdr :: struct {
+	name:       rawptr,
+	namelen:    i32,
+	iov:        []IO_Vec, // ptr followed by length, abi matches
+	control:    []u8,
+	flags:      Socket_Msg,
+};
+
+/*
+	Multiple message header for sendmmsg/recvmmsg
+*/
+MMsg_Hdr :: struct {
+	hdr: Msg_Hdr,
+	len: u32,
+}
+
 /// Just an alias to make futex-values more visible
 Futex :: u32
 
@@ -564,3 +602,417 @@ RUsage :: struct {
 	nvcsw_word:    int,
 	nivcsw_word:   int,
 }
+
+/*
+	Struct used for IO operations
+*/
+IO_Vec :: struct {
+	base: rawptr,
+	len:  uint,
+}
+
+/*
+	Access mode for shared memory
+*/
+IPC_Mode :: bit_set[IPC_Mode; u32]
+
+/*
+	Flags used by IPC objects
+*/
+IPC_Flags :: bit_set[IPC_Flags_Bits; i16]
+
+/*
+	Permissions for IPC objects
+*/
+IPC_Perm :: struct {
+	key:  Key,
+	uid:  u32,
+	gid:  u32,
+	cuid: u32,
+	cgid: u32,
+	mode: IPC_Mode,
+	seq:  u16,
+	_:    [2 + 2*size_of(int)],
+}
+
+when size_of(int) == 8 || ODIN_ARCH == .i386 {
+	// 32-bit and 64-bit x86, 64-bit arm
+	_Arch_Shmid_DS :: struct {
+		perm:   IPC_Perm,
+		segsz:  uint,
+		atime:  int,
+		dtime:  int,
+		ctime:  int,
+		cpid:   Pid,
+		lpid:   Pid,
+		nattch: uint,
+		_:      [2]uint,
+	}
+} else {
+	// Other 32-bit platforms
+	// NOTE(flysand): I'm not risking assuming it's little endian...
+	_Arch_Shmid_DS :: struct {
+		perm:       IPC_Perm,
+		segsz:      uint,
+		atime:      uint,
+		atime_high: uint,
+		dtime:      uint,
+		dtime_high: uint,
+		ctime:      uint,
+		ctime_high: uint,
+		cpid:       Pid,
+		lpid:       Pid,
+		nattach:    uint,
+		_:          [2]uint,        
+	}
+}
+
+/*
+	SystemV shared memory data.
+*/
+Shmid_DS :: _Arch_Shmid_DS
+
+/*
+	SystemV shared memory info.
+*/
+Shm_Info :: struct {
+	used_ids:       i32
+	shm_tot:        uint,
+	shm_rss:        uint,
+	shm_swp:        uint,
+	swap_attempts:  uint,
+	swap_successes: uint,
+}
+
+/*
+	SystemV semaphore operation.
+*/
+Sem_Buf :: struct {
+	num: u16,
+	op:  IPC_Cmd,
+	flg: IPC_Flags,
+}
+
+when ODIN_ARCH == .i386 {
+	_Arch_Semid_DS :: struct {
+		perm:       IPC_Perm,
+		otime:      uint,
+		otime_high: uint,
+		ctime:      uint,
+		ctime_high: uint,
+		nsems:      uint,
+		_:          [2]uint,
+	}
+else when ODIN_ARCH == .amd64 {
+	_Arch_Semid_DS :: struct {
+		perm:       IPC_Perm,
+		otime:      int,
+		ctime:      int,
+		nsems:      uint,
+		_:          [2]uint,
+	}
+} else when ODIN_ARCH == .amd32 {
+	_Arch_Semid_DS :: struct {
+		perm:       IPC_Perm,
+		otime:      uint,
+		otime_high: uint,
+		ctime:      uint,
+		ctime_high: uint,
+		nsems:      uint,
+		_:          [2]uint,
+	}
+} else when ODIN_ARCH == .amd64 {
+	_Arch_Semid_DS :: struct {
+		perm:       IPC_Perm,
+		otime:      int,
+		ctime:      int,
+		sem_nsems:  uint,
+		__unused3:  uint,
+		__unused4:  uint,
+	}
+}
+
+/*
+	Architecture-specific semaphore data.
+*/
+Semid_DS :: _Arch_Semid_DS
+
+/*
+	Argument for semctl functions
+*/
+Sem_Un :: struct #raw_union {
+	val:   i32,
+	buf:   rawptr,
+	array: u16,
+	__buf: Sem_Info,
+	_:     uintptr,
+}
+
+/*
+	SystenV semaphore info.
+*/
+Sem_Info {
+	map: i32,
+	mni: i32,
+	mns: i32,
+	mnu: i32,
+	msl: i32,
+	opm: i32,
+	ume: i32,
+	usz: i32,
+	vmx: i32,
+	aem: i32,
+}
+
+/*
+	Template for the struct used for sending and receiving messages
+*/
+Msg_Buf :: struct {
+	type: int,
+	text: [0]u8,
+}
+
+/*
+	SystemV message queue data.
+*/
+struct Msqid_DS {
+	perm:   IPC_Perm,
+	stime:  uint,
+	rtime:  uint,
+	ctime:  uint,
+	cbytes: uint,
+	qnum:   uint,
+	qbytes: uint,
+	lspid:  Pid,
+	lrpid:  Pid,
+	_:      [2]uint
+};
+
+/*
+	Interval timer types
+*/
+ITimer_Which :: enum {
+	REAL    = 0,
+	VIRTUAL = 1,
+	PROF    = 2,
+}
+
+/*
+	Interval timer value
+*/
+ITimer_Val :: struct {
+	interval: Time_Val,
+	value:    Time_Val,
+}
+
+when ODIN_ARCH == .arm32 {
+	_Arch_User_Regs :: struct {
+		cpsr:             uint,
+		pc:               uint,
+		lr:               uint,
+		sp:               uint,
+		ip:               uint,
+		fp:               uint,
+		r10:              uint,
+		r9:               uint,
+		r8:               uint,
+		r7:               uint,
+		r6:               uint,
+		r5:               uint,
+		r4:               uint,
+		r3:               uint,
+		r2:               uint,
+		r1:               uint,
+		r0:               uint,
+		ORIG_r0:          uint,
+	}
+	// TODO(flysand): Idk what to do about these, couldn't find their
+	// definitions
+	_Arch_User_FP_Regs :: struct {}
+	_Arch_User_FPX_Regs :: struct {}
+} else when ODIN_ARCH == .arm64 {
+	_Arch_User_Regs :: struct {
+		regs:             [31]uint,
+		sp:               uint,
+		pc:               uint,
+		pstate:           uint,
+	}
+	_Arch_User_FP_Regs :: struct {
+		vregs:            [32]u128,
+		fpsr:             u32,
+		fpcr:             u32,
+		_:                [2]u32
+	}
+	_Arch_User_FPX_Regs :: struct {}
+} else when ODIN_ARCH == .i386 {
+	_Arch_User_Regs :: struct {
+		ebx:              uint,
+		ecx:              uint,
+		edx:              uint,
+		esi:              uint,
+		edi:              uint,
+		ebp:              uint,
+		eax:              uint,
+		xds:              uint,
+		xes:              uint,
+		xfs:              uint,
+		xgs:              uint,
+		orig_eax:         uint,
+		eip:              uint,
+		xcs:              uint,
+		eflags:           uint,
+		esp:              uint,
+		xss:              uint,
+	}
+	// x87 FPU state
+	_Arch_User_FP_Regs :: struct {
+		cwd:              uint,
+		swd:              uint,
+		twd:              uint,
+		fip:              uint,
+		fcs:              uint,
+		foo:              uint,
+		fos:              uint,
+		st_space:         [20]uint,
+	}
+	// FXSR instruction set state
+	_Arch_User_FPX_Regs :: struct {
+		cwd:              u16,
+		swd:              u16,
+		twd:              u16,
+		fop:              u16,
+		fip:              uint,
+		fcs:              uint,
+		foo:              uint,
+		fos:              uint,
+		mxcsr:            uint,
+		_:                uint,
+		st_space:         [32]uint,
+		xmm_space:        [32]uint,
+		padding:          [56]uint,
+	}
+} else when ODIN_ARCH == .amd64 {
+	_Arch_User_Regs {
+		// Callee-preserved, may not be correct if the syscall doesn't need
+		// these registers
+		r15:              uint,
+		r14:              uint,
+		r13:              uint,
+		r12:              uint,
+		rbp:              uint,
+		rbx:              uint,
+		// Always saved
+		r11:              uint,
+		r10:              uint,
+		r9:               uint,
+		r8:               uint,
+		rax:              uint,
+		rcx:              uint,
+		rdx:              uint,
+		rsi:              uint,
+		rdi:              uint,
+		// On syscall entry this is the syscall number, on CPU exception this
+		// is the error code, on hardware interrupt this is its IRQ number
+		orig_rax:         uint,
+		// Return frame for iretq
+		rip:              uint,
+		cs:               uint,
+		eflags:           uint,
+		rsp:              uint,
+		ss:               uint,
+	}
+	// All floating point state
+	_Arch_User_FP_Regs :: struct {
+		cwd:              u16,
+		swd:              u16,
+		twd:              u16,
+		fop:              u16,
+		rip:              uint,
+		rdp:              uint,
+		mxcsr:            u32,
+		mxcsr_mask:       u32,
+		st_space:         [32]u32,
+		xmm_space:        [64]u32,
+		_:                [24]u32;
+	}
+}
+
+/*
+	Architecture-specific registers struct.
+*/
+User_Regs :: _Arch_User_Regs
+
+/*
+	Architecture-specific floating-point registers
+*/
+User_FP_Regs :: _Arch_User_FP_Regs
+
+/*
+	Architecture-specific extended floating-point registers.
+	Currently only used for x86 CPU's.
+*/
+User_FPX_Regs :: _Arch_User_FPX_Regs
+
+/*
+	ptrace options.
+*/
+PTrace_Options :: bit_set[PTrace_Options_Bits; u32]
+
+/*
+	ptrace's PEEKSIGINFO argument.
+*/
+PTrace_Peek_Sig_Info_Args :: struct {
+	off:   u64,
+	flags: PTrace_Peek_Sig_Info_Flags,
+	nr:    i32,
+}
+
+/*
+	ptrace's PEEKSIGINFO flags.
+*/
+PTrace_Peek_Sig_Info_Flags :: bit_set[PTrace_Peek_Sig_Info_Flags_Bits, u32]
+
+/*
+	ptrace's SECCOMP metadata.
+*/
+PTrace_Seccomp_Metadata
+{
+	filter_off: u64,
+	flags:      u64,
+}
+
+/*
+	ptrace's results of GET_SYSCALL_INFO.
+*/
+PTrace_Syscall_Info :: struct {
+	op:                  PTrace_Get_Syscall_Info_Op,
+	arch:                u32, // TODO: AUDIT_ARCH*
+	instruction_pointer: u64,
+	stack_pointer:       u64,
+	using _: struct #raw_union {
+		entry: struct {
+			nr:       u64,
+			args:     [6]u64,
+		},
+		exit: struct {
+			rval:     i64,
+			is_error: b8,
+		},
+		seccomp: struct {
+			nr:       u64,
+			args:     [6]u64,
+			ret_data: u32,
+		},
+	};
+};
+
+/*
+	ptrace's results of GET_RSEQ_CONFIGURATION.
+*/
+PTrace_RSeq_Configuration {
+	rseq_abi_pointer: u64,
+	rseq_abi_size:    u32,
+	signature:        u32,
+	flags:            u32,
+	_:                u32,
+};