shithub: mc

Download patch

ref: 820585fb7338092fa5b5001b81ad45b06376939d
parent: 77246bfe1b9f147b1b255e811fb8b2032c49dc9e
author: Ori Bernstein <ori@eigenstate.org>
date: Sat Jul 13 18:46:57 EDT 2019

Oops, mangled something with git9.

--- /dev/null
+++ b/lib/json/test/inputs/n_structure_whitespace_U+2060_word_joiner.json
@@ -1,0 +1,1 @@
+[⁠]
\ No newline at end of file
--- /dev/null
+++ b/lib/json/test/inputs/y_number_negative_zero.json
@@ -1,0 +1,1 @@
+[-0]
\ No newline at end of file
--- /dev/null
+++ b/lib/std/dir+openbsd.myr
@@ -1,0 +1,65 @@
+use sys
+
+use "alloc"
+use "die"
+use "memops"
+use "option"
+use "result"
+use "slcp"
+use "sldup"
+use "types"
+
+pkg std =
+	type dir = struct
+		fd	: sys.fd
+		buf	: byte[16384]
+		len	: int64
+		off	: int64
+	;;
+
+	const diropen	: (p : byte[:] -> std.result(dir#, byte[:]))
+	const dirread	: (d : dir# -> std.option(byte[:]))
+	const dirclose	: (d : dir# -> void)
+;;
+
+const diropen = {p
+	var fd
+	var dir
+
+	fd = sys.open(p, sys.Ordonly | sys.Odir)
+	if fd < 0
+		-> `Err "couldn't open directory"
+	;;
+	dir = zalloc()
+	dir.fd = fd
+	-> `Ok dir
+}
+
+const dirread = {d
+	var len
+	var dent
+	var namelen
+
+	if d.off >= d.len
+		len = sys.getdents(d.fd, d.buf[:])
+		if len <= 0
+			-> `None
+		;;
+		d.len = len
+		d.off = 0
+	;;
+
+	dent = (&d.buf[d.off] : sys.dirent#)
+	namelen = 0
+	d.off += (dent.reclen : int64)
+	while dent.name[namelen] != 0
+		namelen++
+	;;
+	-> `Some sldup(dent.name[:namelen])
+}
+
+const dirclose = {d
+	sys.close(d.fd)
+	free(d)
+}
+
--- /dev/null
+++ b/lib/std/syswrap-ss+openbsd.myr
@@ -1,0 +1,31 @@
+use sys
+use "types"
+use "errno"
+use "cstrconv"
+use "slcp"
+use "die"
+
+pkg std =
+	const nanosleep	: (nsecs : uint64 -> errno)
+	$noret const exit	: (status:int -> void)
+
+	pkglocal const bgetcwd	: (buf : byte[:] -> errno)
+;;
+
+const exit	= {status;	sys.exit(status)}
+
+const bgetcwd	= {buf
+	-> (sys.__getcwd(buf) - 1 : errno)
+}
+
+const nanosleep	= {nsecs
+	var req, rem
+	var s, ns
+
+	s = (nsecs / 1_000_000_000 : int64)
+	ns = (nsecs % 1_000_000_000 : int64)
+	req = [.sec = s, .nsec = ns]
+
+	-> (sys.nanosleep(&req, &rem) : errno)
+}
+
--- a/lib/std/test/bigint.myr
+++ b/lib/std/test/bigint.myr
@@ -21,7 +21,6 @@
 		[.name = "format-zero", .fn = fmtzero],
 		[.name = "division", .fn = smokediv],
 		[.name = "modulo", .fn = smokemod],
-		[.name = "shift", .fn = shiftoff],
 		[.name = "add-negatives", .fn = addneg],
 		[.name = "sub-negatives", .fn = subneg],
 	][:])
@@ -262,13 +261,6 @@
 	run(c, std.mk(`Sub (\
 		std.mk(`Val "-8"), \
 		std.mk(`Val "-8"))), \
-		"0")
-}
-
-const shiftoff = {c
-	run(c, std.mk(`Shr ( \
-		std.mk(`Val "1"), \
-		std.mk(`Val "65"))), \
 		"0")
 }
 
--- /dev/null
+++ b/lib/sys/ifreq+netbsd.myr
@@ -1,0 +1,2 @@
+pkg sys =
+;;
--- /dev/null
+++ b/lib/sys/ifreq+openbsd.myr
@@ -1,0 +1,2 @@
+pkg sys =
+;;
--- /dev/null
+++ b/lib/sys/ifreq+plan9.myr
@@ -1,0 +1,2 @@
+pkg sys =
+;;
--- /dev/null
+++ b/lib/sys/syserrno+openbsd.myr
@@ -1,0 +1,123 @@
+pkg sys =
+	type errno = int
+
+	const Eperm	: errno = -1		/* Operation not permitted */
+	const Enoent	: errno = -2		/* No such file or directory */
+	const Esrch	: errno = -3		/* No such process */
+	const Eintr	: errno = -4		/* Interrupted system call */
+	const Eio	: errno = -5		/* Input/output error */
+	const Enxio	: errno = -6		/* Device not configured */
+	const E2big	: errno = -7		/* Argument list too long */
+	const Enoexec	: errno = -8		/* Exec format error */
+	const Ebadf	: errno = -9		/* Bad file descriptor */
+	const Echild	: errno = -10		/* No child processes */
+	const Edeadlk	: errno = -11		/* Resource deadlock avoided */
+	/* 11 was EAGAIN */
+	const Enomem	: errno = -12		/* Cannot allocate memory */
+	const Eacces	: errno = -13		/* Permission denied */
+	const Efault	: errno = -14		/* Bad address */
+	const Enotblk	: errno = -15		/* Block device required */
+	const Ebusy	: errno = -16		/* Device busy */
+	const Eexist	: errno = -17		/* File exists */
+	const Exdev	: errno = -18		/* Cross-device link */
+	const Enodev	: errno = -19		/* Operation not supported by device */
+	const Enotdir	: errno = -20		/* Not a directory */
+	const Eisdir	: errno = -21		/* Is a directory */
+	const Einval	: errno = -22		/* Invalid argument */
+	const Enfile	: errno = -23		/* Too many open files in system */
+	const Emfile	: errno = -24		/* Too many open files */
+	const Enotty	: errno = -25		/* Inappropriate ioctl for device */
+	const Etxtbsy	: errno = -26		/* Text file busy */
+	const Efbig	: errno = -27		/* File too large */
+	const Enospc	: errno = -28		/* No space left on device */
+	const Espipe	: errno = -29		/* Illegal seek */
+	const Erofs	: errno = -30		/* Read-only filesystem */
+	const Emlink	: errno = -31		/* Too many links */
+	const Epipe	: errno = -32		/* Broken pipe */
+
+	/* math software */
+	const Edom	: errno = -33		/* Numerical argument out of domain */
+	const Erange	: errno = -34		/* Result too large */
+
+	/* non-blocking and interrupt i/o */
+	const Eagain	: errno = -35		/* Resource temporarily unavailable */
+	const Einprogress	: errno = -36		/* Operation now in progress */
+	const Ealready	: errno = -37		/* Operation already in progress */
+
+	/* ipc/network software -- argument errors */
+	const Enotsock		: errno = -38		/* Socket operation on non-socket */
+	const Edestaddrreq	: errno = -39		/* Destination address required */
+	const Emsgsize		: errno = -40		/* Message too long */
+	const Eprototype	: errno = -41		/* Protocol wrong type for socket */
+	const Enoprotoopt	: errno = -42		/* Protocol not available */
+	const Eprotonosupport	: errno = -43		/* Protocol not supported */
+	const Esocktnosupport	: errno = -44		/* Socket type not supported */
+	const Eopnotsupp	: errno = -45		/* Operation not supported */
+	const Epfnosupport	: errno = -46		/* Protocol family not supported */
+	const Eafnosupport	: errno = -47		/* Address family not supported by protocol family */
+	const Eaddrinuse	: errno = -48		/* Address already in use */
+	const Eaddrnotavail	: errno = -49		/* Can't assign requested address */
+
+	/* ipc/network software -- operational errors */
+	const Enetdown	: errno = -50		/* Network is down */
+	const Enetunreach	: errno = -51		/* Network is unreachable */
+	const Enetreset	: errno = -52		/* Network dropped connection on reset */
+	const Econnaborted	: errno = -53		/* Software caused connection abort */
+	const Econnreset	: errno = -54		/* Connection reset by peer */
+	const Enobufs	: errno = -55		/* No buffer space available */
+	const Eisconn	: errno = -56		/* Socket is already connected */
+	const Enotconn	: errno = -57		/* Socket is not connected */
+	const Eshutdown	: errno = -58		/* Can't send after socket shutdown */
+	const Etoomanyrefs	: errno = -59		/* Too many references: can't splice */
+	const Etimedout	: errno = -60		/* Operation timed out */
+	const Econnrefused	: errno = -61		/* Connection refused */
+
+	const Eloop	: errno = -62		/* Too many levels of symbolic links */
+	const Enametoolong	: errno = -63		/* File name too long */
+
+	/* should be rearranged */
+	const Ehostdown		: errno = -64		/* Host is down */
+	const Ehostunreach	: errno = -65		/* No route to host */
+	const Enotempty	: errno = -66		/* Directory not empty */
+
+	/* quotas & mush */
+	const Eproclim	: errno = -67		/* Too many processes */
+	const Eusers	: errno = -68		/* Too many users */
+	const Edquot	: errno = -69		/* Disc quota exceeded */
+
+	/* Network File System */
+	const Estale	: errno = -70		/* Stale NFS file handle */
+	const Eremote	: errno = -71		/* Too many levels of remote in path */
+	const Ebadrpc	: errno = -72		/* RPC struct is bad */
+	const Erpcmismatch	: errno = -73		/* RPC version wrong */
+	const Eprogunavail	: errno = -74		/* RPC prog. not avail */
+	const Eprogmismatch	: errno = -75		/* Program version wrong */
+	const Eprocunavail	: errno = -76		/* Bad procedure for program */
+
+	const Enolck	: errno = -77		/* No locks available */
+	const Enosys	: errno = -78		/* Function not implemented */
+
+	const Eftype	: errno = -79		/* Inappropriate file type or format */
+	const Eauth	: errno = -80		/* Authentication error */
+	const Eneedauth	: errno = -81		/* Need authenticator */
+	const Eidrm	: errno = -82		/* Identifier removed */
+	const Enomsg	: errno = -83		/* No message of desired type */
+	const Eoverflow	: errno = -84		/* Value too large to be stored in data type */
+	const Ecanceled	: errno = -85		/* Operation canceled */
+	const Eilseq	: errno = -86		/* Illegal byte sequence */
+	const Enoattr	: errno = -87		/* Attribute not found */
+
+	const Edoofus	: errno = -88		/* Programming error */
+
+	const Ebadmsg	: errno = -89		/* Bad message */
+	const Emultihop	: errno = -90		/* Multihop attempted */
+	const Enolink	: errno = -91		/* Link has been severed */
+	const Eproto	: errno = -92		/* Protocol error */
+
+	const Enotcapable	: errno = -93		/* Capabilities insufficient */
+	const Ecapmode	: errno = -94		/* Not permitted in capability mode */
+	const Enotrecoverable	: errno = -95		/* State not recoverable */
+	const Eownerdead	: errno = -96		/* Previous owner died */
+
+	const Elast	: errno = -96		/* Must be equal largest errno */
+;;
--- /dev/null
+++ b/lib/thread/ncpu+openbsd.myr
@@ -1,0 +1,23 @@
+use std
+use sys
+
+pkg thread =
+	const ncpu	: (-> int)
+;;
+
+const ncpu = {
+	var mib	: int[2]
+	var ncpu : int
+	var ncpusz
+	var res
+
+	mib[0] = 6 /* CTL_HW */
+	mib[1] = 3 /* HW_NCPU */
+	ncpusz = sizeof(int)
+
+	res = sys.sysctl(mib[:], (&ncpu : void#), &ncpusz, (0 : void#), (0 : sys.size#))
+	if res < 0 || ncpu <= 0
+		-> 1
+	;;
+	-> ncpu
+}
--- /dev/null
+++ b/rt/abort-netbsd.s
@@ -1,0 +1,42 @@
+.text
+
+.globl _rt$abort_oob
+.globl __rt$abort_oob
+_rt$abort_oob:
+__rt$abort_oob:
+	/* format pc */
+	movq	(%rsp),%rax
+	movq	$15,%rdx
+	leaq	.digitchars(%rip),%r8
+	leaq    .pcstr(%rip),%r9
+.loop:
+	movq	%rax, %rcx
+	andq	$0xf, %rcx
+	movb    (%r8,%rcx),%r10b
+	movb	%r10b,(%r9,%rdx)
+	subq	$1, %rdx
+	shrq	$4, %rax
+	jnz .loop
+	/* write abort message */
+	movq	$4, %rax 	/* write(fd=%rdi, msg=%rsi, len=%rdx) */
+	movq	$2, %rdi		/* fd */
+	leaq	.msg(%rip), %rsi	/* msg */
+	movq	$(.msgend-.msg), %rdx	/* length */
+	syscall
+	/* kill self */
+	movq	$20,%rax 	/* getpid */
+	syscall	
+	movq	%rax, %rdi	/* save pid */
+	movq	$37, %rax	/* kill(pid=%rdi, sig=%rsi) */
+	movq	$6, %rsi
+	syscall
+.data
+.msg: 	/* pc name:  */
+	.ascii "0x"
+.pcstr:
+	.ascii "0000000000000000"
+	.ascii ": out of bounds access\n"
+.msgend:
+
+.digitchars:
+	.ascii "0123456789abcdef"
--- /dev/null
+++ b/support/syscall-gen/specials+openbsd:6.2-x64.frag
@@ -1,0 +1,286 @@
+/* process control */
+const exit	: (status:int -> void)
+const getpid	: ( -> pid)
+const kill	: (pid:pid, sig:int64 -> int64)
+const fork	: (-> pid)
+const wait4	: (pid:pid, loc:int32#, opt : int64, usage:rusage#	-> int64)
+const waitpid	: (pid:pid, loc:int32#, opt : int64	-> int64)
+const execv	: (cmd : byte[:], args : byte[:][:] -> int64)
+const execve	: (cmd : byte[:], args : byte[:][:], env : byte[:][:] -> int64)
+/* wrappers to extract wait status */
+const waitstatus	: (st : int32 -> waitstatus)
+extern const __tfork_thread	: (tfp : tforkparams#, sz : size, fn : void#, arg : void# -> pid)
+
+/* fd manipulation */
+const open	: (path:byte[:], opts:fdopt -> fd)
+const openmode	: (path:byte[:], opts:fdopt, mode:int64 -> fd)
+const close	: (fd:fd -> int64)
+const creat	: (path:byte[:], mode:int64 -> fd)
+const unlink	: (path:byte[:] -> int)
+const read	: (fd:fd, buf:byte[:] -> size)
+const pread	: (fd:fd, buf:byte[:], off : off -> size)
+const readv	: (fd:fd, iov:iovec[:] -> size)
+const write	: (fd:fd, buf:byte[:] -> size)
+const pwrite	: (fd:fd, buf:byte[:], off : off -> size)
+const writev	: (fd:fd, iov:iovec[:] -> size)
+const lseek	: (fd:fd, off : off, whence : whence -> int64)
+const stat	: (path:byte[:], sb:statbuf# -> int64)
+const lstat	: (path:byte[:], sb:statbuf# -> int64)
+const fstat	: (fd:fd, sb:statbuf# -> int64)
+const mkdir	: (path : byte[:], mode : int64	-> int64)
+generic ioctl	: (fd:fd, req : int64, arg:@a# -> int64)
+const getdents	: (fd : fd, buf : byte[:] -> int64)
+const chdir	: (p : byte[:] -> int64)
+const __getcwd	: (buf : byte[:] -> int64)
+const poll	: (pfd : pollfd[:], tm : int -> int)
+
+/* signals */
+const sigaction	: (sig : signo, act : sigaction#, oact : sigaction# -> int)
+const sigprocmask	: (how : int32, set : sigset#, oset : sigset# -> int)
+
+/* fd stuff */
+const pipe	: (fds : fd[2]# -> int64)
+const dup	: (fd : fd -> fd)
+const dup2	: (src : fd, dst : fd -> fd)
+/* NB: the C ABI uses '...' for the args. */
+const fcntl	: (fd : fd, cmd : fcntlcmd, args : byte# -> int64)
+
+/* networking */
+const socket	: (dom : sockfam, stype : socktype, proto : sockproto	-> fd)
+const connect	: (sock	: fd, addr : sockaddr#, len : size -> int)
+const accept	: (sock : fd, addr : sockaddr#, len : size# -> fd)
+const listen	: (sock : fd, backlog : int	-> int)
+const bind	: (sock : fd, addr : sockaddr#, len : size -> int)
+const setsockopt	: (sock : fd, lev : sockproto, opt : sockopt, val : void#, len : size -> int)
+const getsockopt	: (sock : fd, lev : sockproto, opt : sockopt, val : void#, len : size# -> int)
+
+/* memory mapping */
+const munmap	: (addr:byte#, len:size -> int64)
+const mmap	: (addr:byte#, len:size, prot:mprot, flags:mopt, fd:fd, off:off -> byte#)
+
+/* time - doublecheck if this is right */
+const clock_getres	: (clk : clock, ts : timespec# -> int32)
+const clock_gettime	: (clk : clock, ts : timespec# -> int32)
+const clock_settime	: (clk : clock, ts : timespec# -> int32)
+const sleep	: (time : uint64 -> int32)
+const nanosleep	: (req : timespec#, rem : timespec# -> int32)
+
+/* system information */
+const uname 	: (buf : utsname# -> int)
+const sysctl	: (mib : int[:], \
+		old : void#, oldsz : size#, \
+		new : void#, newsz : size# \
+		-> int)
+
+/* 
+wraps a syscall argument, converting it to 64 bits for the syscall function. This is
+the same as casting, but more concise than writing a cast to uint64
+*/
+generic a = {x : @t; -> (x : uint64)}
+
+extern const cstring	: (str : byte[:] -> byte#)
+extern const alloca	: (sz : size	-> byte#)
+
+extern const __freebsd_pipe	: (fds : fd[2]# -> int64)
+
+/* process management */
+const exit	= {status;		syscall(Sysexit, a(status))}
+const getpid	= {;			-> (syscall(Sysgetpid, 1) : pid)}
+const kill	= {pid, sig;		-> syscall(Syskill, pid, sig)}
+const fork	= {;			-> (syscall(Sysfork) : pid)}
+const wait4	= {pid, loc, opt, usage;	-> syscall(Syswait4, pid, loc, opt, usage)}
+const waitpid	= {pid, loc, opt;
+	-> wait4(pid, loc, opt, (0 : rusage#)) 
+}
+
+const execv	= {cmd, args
+	var p, cargs, i
+
+	/* of course we fucking have to duplicate this code everywhere,
+	* since we want to stack allocate... */
+	p = alloca((args.len + 1)*sizeof(byte#))
+	cargs = (p : byte##)[:args.len + 1]
+	for i = 0; i < args.len; i++
+		cargs[i] = cstring(args[i])
+	;;
+	cargs[args.len] = (0 : byte#)
+	-> syscall(Sysexecve, cstring(cmd), a(p), a(__cenvp))
+}
+
+const execve	= {cmd, args, env
+	var cargs, cenv, i
+	var p
+
+	/* copy the args */
+	p = alloca((args.len + 1)*sizeof(byte#))
+	cargs = (p : byte##)[:args.len]
+	for i = 0; i < args.len; i++
+		cargs[i] = cstring(args[i])
+	;;
+	cargs[args.len] = (0 : byte#)
+
+	/*
+	 copy the env.
+	 of course we fucking have to duplicate this code everywhere,
+	 since we want to stack allocate... 
+	*/
+	p = alloca((env.len + 1)*sizeof(byte#))
+	cenv = (p : byte##)[:env.len]
+	for i = 0; i < env.len; i++
+		cenv[i] = cstring(env[i])
+	;;
+	cenv[env.len] = (0 : byte#)
+
+	-> syscall(Sysexecve, cstring(cmd), a(p), a(cenv))
+}
+
+/* fd manipulation */
+const open	= {path, opts;		-> (syscall(Sysopen, cstring(path), a(opts), a(0o777)) : fd)}
+const openmode	= {path, opts, mode;	-> (syscall(Sysopen, cstring(path), a(opts), a(mode)) : fd)}
+const close	= {fd;			-> syscall(Sysclose, a(fd))}
+const creat	= {path, mode;		-> (openmode(path, Ocreat | Otrunc | Owronly, mode) : fd)}
+const unlink	= {path;		-> (syscall(Sysunlink, cstring(path)) : int)}
+const read	= {fd, buf;		-> (syscall(Sysread, a(fd), (buf : byte#), a(buf.len)) : size)}
+const pread	= {fd, buf, off;	-> (syscall(Syspread, a(fd), (buf : byte#), a(buf.len), a(off)) : size)}
+const readv	= {fd, vec;		-> (syscall(Sysreadv, a(fd), (vec : iovec#), a(vec.len)) : size)}
+const write	= {fd, buf;		-> (syscall(Syswrite, a(fd), (buf : byte#), a(buf.len)) : size)}
+const pwrite	= {fd, buf, off;	-> (syscall(Syspwrite, a(fd), (buf : byte#), a(buf.len), a(off)) : size)}
+const writev	= {fd, vec;		-> (syscall(Syswritev, a(fd), (vec : iovec#), a(vec.len)) : size)}
+const lseek	= {fd, off, whence;	-> syscall(Syslseek, a(fd), a(off), a(whence))}
+const stat	= {path, sb;		-> syscall(Sysstat, cstring(path), a(sb))}
+const lstat	= {path, sb;		-> syscall(Syslstat, cstring(path), a(sb))}
+const fstat	= {fd, sb;		-> syscall(Sysfstat, a(fd), a(sb))}
+const mkdir	= {path, mode;		-> (syscall(Sysmkdir, cstring(path), a(mode)) : int64)}
+generic ioctl	= {fd, req, arg;	-> (syscall(Sysioctl, a(fd), a(req), a(arg)) : int64)}
+const chdir	= {dir;	-> syscall(Syschdir, cstring(dir))}
+const __getcwd	= {buf;	-> syscall(Sys__getcwd, a(buf), a(buf.len))}
+const getdents	= {fd, buf;		-> (syscall(Sysgetdents, a(fd), a(buf), a(buf.len)) : int64)}
+
+/* signals */
+const sigaction	= {sig, act, oact;	-> (syscall(Syssigaction, a(sig), a(act), a(oact)) : int)}
+const sigprocmask	= {sig, act, oact;	-> (syscall(Syssigprocmask, a(sig), a(act), a(oact)) : int)}
+
+/* file stuff */
+const pipe	= {fds;	-> syscall(Syspipe, fds)}
+const dup 	= {fd;	-> (syscall(Sysdup, a(fd)) : fd)}
+const dup2 	= {src, dst;	-> (syscall(Sysdup2, a(src), a(dst)) : fd)}
+const fcntl	= {fd, cmd, args; 	-> syscall(Sysfcntl, a(fd), a(cmd), a(args))}
+const poll      = {pfd, tm;     -> (syscall(Syspoll, (pfd : byte#), a(pfd.len), a(tm)) : int)}
+
+/* networking */
+const socket	= {dom, stype, proto;	-> (syscall(Syssocket, a(dom), a(stype), a(proto)) : fd)}
+const connect	= {sock, addr, len;	-> (syscall(Sysconnect, a(sock), a(addr), a(len)) : int)}
+const accept	= {sock, addr, len;	-> (syscall(Sysaccept, a(sock), a(addr), a(len)) : fd)}
+const listen	= {sock, backlog;	-> (syscall(Syslisten, a(sock), a(backlog)) : int)}
+const bind	= {sock, addr, len;	-> (syscall(Sysbind, a(sock), a(addr), a(len)) : int)}
+const setsockopt	= {sock, lev, opt, val, len;	-> (syscall(Syssetsockopt, a(sock), a(lev), a(opt), a(val), a(len)) : int)}
+const getsockopt	= {sock, lev, opt, val, len;	-> (syscall(Syssetsockopt, a(sock), a(lev), a(opt), a(val), a(len)) : int)}
+
+/* memory management */
+const munmap	= {addr, len;		-> syscall(Sysmunmap, a(addr), a(len))}
+const mmap	= {addr, len, prot, flags, fd, off;
+	/* the actual syscall has padding on the offset arg */
+	-> (syscall(Sysmmap, a(addr), a(len), a(prot), a(flags), a(fd), a(0), a(off)) : byte#)
+}
+
+/* time */
+const clock_getres = {clk, ts;	-> (syscall(Sysclock_getres, clockid(clk), a(ts)) : int32)}
+const clock_gettime = {clk, ts;	-> (syscall(Sysclock_gettime, clockid(clk), a(ts)) : int32)}
+const clock_settime = {clk, ts;	-> (syscall(Sysclock_settime, clockid(clk), a(ts)) : int32)}
+
+const sleep = {time
+	var req, rem
+	req = [.sec = (time : int64), .nsec = 0]
+	-> nanosleep(&req, &rem)
+}
+
+const nanosleep	= {req, rem;	-> (syscall(Sysnanosleep, a(req), a(rem)) : int32)}
+
+
+/* system information */
+const uname	= {buf
+	var mib : int[2]
+	var ret
+	var sys, syssz
+	var nod, nodsz
+	var rel, relsz
+	var ver, versz
+	var mach, machsz
+
+	ret = 0
+	mib[0] = 1 /* CTL_KERN */
+	mib[1] = 1 /* KERN_OSTYPE */
+	sys = (buf.system[:] : void#)
+	syssz = buf.system.len
+	ret = sysctl(mib[:], sys, &syssz, (0 : void#), (0 : size#))
+	if ret < 0
+		-> ret
+	;;
+
+	mib[0] = 1 /* CTL_KERN */
+	mib[1] = 10 /* KERN_HOSTNAME */
+	nod = (buf.node[:] : void#)
+	nodsz = buf.node.len
+	ret = sysctl(mib[:], nod, &nodsz, (0 : void#), (0 : size#))
+	if ret < 0
+		-> ret
+	;;
+
+	mib[0] = 1 /* CTL_KERN */
+	mib[1] = 2 /* KERN_OSRELEASE */
+	rel = (buf.release[:] : void#)
+	relsz = buf.release.len
+	ret = sysctl(mib[:], rel, &relsz, (0 : void#), (0 : size#))
+	if ret < 0
+		-> ret
+	;;
+
+	mib[0] = 1 /* CTL_KERN */
+	mib[1] = 27 /* KERN_OSVERSION */
+	ver = (buf.version[:] : void#)
+	versz = buf.version.len
+	ret = sysctl(mib[:], ver, &versz, (0 : void#), (0 : size#))
+	if ret < 0
+		-> ret
+	;;
+
+	mib[0] = 6 /* CTL_HW */
+	mib[1] = 1 /* HW_MACHINE */
+	mach = (buf.machine[:] : void#)
+	machsz = buf.machine.len
+	ret = sysctl(mib[:], mach, &machsz, (0 : void#), (0 : size#))
+	if ret < 0
+		-> ret
+	;;
+
+	-> 0
+}
+
+const sysctl = {mib, old, oldsz, new, newsz
+	/* all args already passed through a() or ar  ptrs */
+	-> (syscall(Syssysctl, \
+		(mib : int#), a(mib.len), old, oldsz, new, newsz) : int)
+}
+
+const clockid = {clk
+	match clk
+	| `Clockrealtime:	-> 0
+	| `Clockproccputime:	-> 2
+	| `Clockmonotonic:	-> 3
+	| `Clockthreadcputime:	-> 4
+	| `Clockuptime:	-> 5
+	;;
+	-> -1
+}
+
+const waitstatus = {st
+	if st < 0
+		-> `Waitfail st
+	;;
+	match st & 0o177
+	| 0:    -> `Waitexit (st >> 8)
+	| 0x7f:-> `Waitstop (st >> 8)
+	| sig:  -> `Waitsig sig
+	;;
+}
+
--- /dev/null
+++ b/support/syscall-gen/specials+openbsd:6.3-x64.frag
@@ -1,0 +1,286 @@
+/* process control */
+const exit	: (status:int -> void)
+const getpid	: ( -> pid)
+const kill	: (pid:pid, sig:int64 -> int64)
+const fork	: (-> pid)
+const wait4	: (pid:pid, loc:int32#, opt : int64, usage:rusage#	-> int64)
+const waitpid	: (pid:pid, loc:int32#, opt : int64	-> int64)
+const execv	: (cmd : byte[:], args : byte[:][:] -> int64)
+const execve	: (cmd : byte[:], args : byte[:][:], env : byte[:][:] -> int64)
+/* wrappers to extract wait status */
+const waitstatus	: (st : int32 -> waitstatus)
+extern const __tfork_thread	: (tfp : tforkparams#, sz : size, fn : void#, arg : void# -> pid)
+
+/* fd manipulation */
+const open	: (path:byte[:], opts:fdopt -> fd)
+const openmode	: (path:byte[:], opts:fdopt, mode:int64 -> fd)
+const close	: (fd:fd -> int64)
+const creat	: (path:byte[:], mode:int64 -> fd)
+const unlink	: (path:byte[:] -> int)
+const read	: (fd:fd, buf:byte[:] -> size)
+const pread	: (fd:fd, buf:byte[:], off : off -> size)
+const readv	: (fd:fd, iov:iovec[:] -> size)
+const write	: (fd:fd, buf:byte[:] -> size)
+const pwrite	: (fd:fd, buf:byte[:], off : off -> size)
+const writev	: (fd:fd, iov:iovec[:] -> size)
+const lseek	: (fd:fd, off : off, whence : whence -> int64)
+const stat	: (path:byte[:], sb:statbuf# -> int64)
+const lstat	: (path:byte[:], sb:statbuf# -> int64)
+const fstat	: (fd:fd, sb:statbuf# -> int64)
+const mkdir	: (path : byte[:], mode : int64	-> int64)
+generic ioctl	: (fd:fd, req : int64, arg:@a# -> int64)
+const getdents	: (fd : fd, buf : byte[:] -> int64)
+const chdir	: (p : byte[:] -> int64)
+const __getcwd	: (buf : byte[:] -> int64)
+const poll	: (pfd : pollfd[:], tm : int -> int)
+
+/* signals */
+const sigaction	: (sig : signo, act : sigaction#, oact : sigaction# -> int)
+const sigprocmask	: (how : int32, set : sigset#, oset : sigset# -> int)
+
+/* fd stuff */
+const pipe	: (fds : fd[2]# -> int64)
+const dup	: (fd : fd -> fd)
+const dup2	: (src : fd, dst : fd -> fd)
+/* NB: the C ABI uses '...' for the args. */
+const fcntl	: (fd : fd, cmd : fcntlcmd, args : byte# -> int64)
+
+/* networking */
+const socket	: (dom : sockfam, stype : socktype, proto : sockproto	-> fd)
+const connect	: (sock	: fd, addr : sockaddr#, len : size -> int)
+const accept	: (sock : fd, addr : sockaddr#, len : size# -> fd)
+const listen	: (sock : fd, backlog : int	-> int)
+const bind	: (sock : fd, addr : sockaddr#, len : size -> int)
+const setsockopt	: (sock : fd, lev : sockproto, opt : sockopt, val : void#, len : size -> int)
+const getsockopt	: (sock : fd, lev : sockproto, opt : sockopt, val : void#, len : size# -> int)
+
+/* memory mapping */
+const munmap	: (addr:byte#, len:size -> int64)
+const mmap	: (addr:byte#, len:size, prot:mprot, flags:mopt, fd:fd, off:off -> byte#)
+
+/* time - doublecheck if this is right */
+const clock_getres	: (clk : clock, ts : timespec# -> int32)
+const clock_gettime	: (clk : clock, ts : timespec# -> int32)
+const clock_settime	: (clk : clock, ts : timespec# -> int32)
+const sleep	: (time : uint64 -> int32)
+const nanosleep	: (req : timespec#, rem : timespec# -> int32)
+
+/* system information */
+const uname 	: (buf : utsname# -> int)
+const sysctl	: (mib : int[:], \
+		old : void#, oldsz : size#, \
+		new : void#, newsz : size# \
+		-> int)
+
+/* 
+wraps a syscall argument, converting it to 64 bits for the syscall function. This is
+the same as casting, but more concise than writing a cast to uint64
+*/
+generic a = {x : @t; -> (x : uint64)}
+
+extern const cstring	: (str : byte[:] -> byte#)
+extern const alloca	: (sz : size	-> byte#)
+
+extern const __freebsd_pipe	: (fds : fd[2]# -> int64)
+
+/* process management */
+const exit	= {status;		syscall(Sysexit, a(status))}
+const getpid	= {;			-> (syscall(Sysgetpid, 1) : pid)}
+const kill	= {pid, sig;		-> syscall(Syskill, pid, sig)}
+const fork	= {;			-> (syscall(Sysfork) : pid)}
+const wait4	= {pid, loc, opt, usage;	-> syscall(Syswait4, pid, loc, opt, usage)}
+const waitpid	= {pid, loc, opt;
+	-> wait4(pid, loc, opt, (0 : rusage#)) 
+}
+
+const execv	= {cmd, args
+	var p, cargs, i
+
+	/* of course we fucking have to duplicate this code everywhere,
+	* since we want to stack allocate... */
+	p = alloca((args.len + 1)*sizeof(byte#))
+	cargs = (p : byte##)[:args.len + 1]
+	for i = 0; i < args.len; i++
+		cargs[i] = cstring(args[i])
+	;;
+	cargs[args.len] = (0 : byte#)
+	-> syscall(Sysexecve, cstring(cmd), a(p), a(__cenvp))
+}
+
+const execve	= {cmd, args, env
+	var cargs, cenv, i
+	var p
+
+	/* copy the args */
+	p = alloca((args.len + 1)*sizeof(byte#))
+	cargs = (p : byte##)[:args.len]
+	for i = 0; i < args.len; i++
+		cargs[i] = cstring(args[i])
+	;;
+	cargs[args.len] = (0 : byte#)
+
+	/*
+	 copy the env.
+	 of course we fucking have to duplicate this code everywhere,
+	 since we want to stack allocate... 
+	*/
+	p = alloca((env.len + 1)*sizeof(byte#))
+	cenv = (p : byte##)[:env.len]
+	for i = 0; i < env.len; i++
+		cenv[i] = cstring(env[i])
+	;;
+	cenv[env.len] = (0 : byte#)
+
+	-> syscall(Sysexecve, cstring(cmd), a(p), a(cenv))
+}
+
+/* fd manipulation */
+const open	= {path, opts;		-> (syscall(Sysopen, cstring(path), a(opts), a(0o777)) : fd)}
+const openmode	= {path, opts, mode;	-> (syscall(Sysopen, cstring(path), a(opts), a(mode)) : fd)}
+const close	= {fd;			-> syscall(Sysclose, a(fd))}
+const creat	= {path, mode;		-> (openmode(path, Ocreat | Otrunc | Owronly, mode) : fd)}
+const unlink	= {path;		-> (syscall(Sysunlink, cstring(path)) : int)}
+const read	= {fd, buf;		-> (syscall(Sysread, a(fd), (buf : byte#), a(buf.len)) : size)}
+const pread	= {fd, buf, off;	-> (syscall(Syspread, a(fd), (buf : byte#), a(buf.len), a(off)) : size)}
+const readv	= {fd, vec;		-> (syscall(Sysreadv, a(fd), (vec : iovec#), a(vec.len)) : size)}
+const write	= {fd, buf;		-> (syscall(Syswrite, a(fd), (buf : byte#), a(buf.len)) : size)}
+const pwrite	= {fd, buf, off;	-> (syscall(Syspwrite, a(fd), (buf : byte#), a(buf.len), a(off)) : size)}
+const writev	= {fd, vec;		-> (syscall(Syswritev, a(fd), (vec : iovec#), a(vec.len)) : size)}
+const lseek	= {fd, off, whence;	-> syscall(Syslseek, a(fd), a(off), a(whence))}
+const stat	= {path, sb;		-> syscall(Sysstat, cstring(path), a(sb))}
+const lstat	= {path, sb;		-> syscall(Syslstat, cstring(path), a(sb))}
+const fstat	= {fd, sb;		-> syscall(Sysfstat, a(fd), a(sb))}
+const mkdir	= {path, mode;		-> (syscall(Sysmkdir, cstring(path), a(mode)) : int64)}
+generic ioctl	= {fd, req, arg;	-> (syscall(Sysioctl, a(fd), a(req), a(arg)) : int64)}
+const chdir	= {dir;	-> syscall(Syschdir, cstring(dir))}
+const __getcwd	= {buf;	-> syscall(Sys__getcwd, a(buf), a(buf.len))}
+const getdents	= {fd, buf;		-> (syscall(Sysgetdents, a(fd), a(buf), a(buf.len)) : int64)}
+
+/* signals */
+const sigaction	= {sig, act, oact;	-> (syscall(Syssigaction, a(sig), a(act), a(oact)) : int)}
+const sigprocmask	= {sig, act, oact;	-> (syscall(Syssigprocmask, a(sig), a(act), a(oact)) : int)}
+
+/* file stuff */
+const pipe	= {fds;	-> syscall(Syspipe, fds)}
+const dup 	= {fd;	-> (syscall(Sysdup, a(fd)) : fd)}
+const dup2 	= {src, dst;	-> (syscall(Sysdup2, a(src), a(dst)) : fd)}
+const fcntl	= {fd, cmd, args; 	-> syscall(Sysfcntl, a(fd), a(cmd), a(args))}
+const poll      = {pfd, tm;     -> (syscall(Syspoll, (pfd : byte#), a(pfd.len), a(tm)) : int)}
+
+/* networking */
+const socket	= {dom, stype, proto;	-> (syscall(Syssocket, a(dom), a(stype), a(proto)) : fd)}
+const connect	= {sock, addr, len;	-> (syscall(Sysconnect, a(sock), a(addr), a(len)) : int)}
+const accept	= {sock, addr, len;	-> (syscall(Sysaccept, a(sock), a(addr), a(len)) : fd)}
+const listen	= {sock, backlog;	-> (syscall(Syslisten, a(sock), a(backlog)) : int)}
+const bind	= {sock, addr, len;	-> (syscall(Sysbind, a(sock), a(addr), a(len)) : int)}
+const setsockopt	= {sock, lev, opt, val, len;	-> (syscall(Syssetsockopt, a(sock), a(lev), a(opt), a(val), a(len)) : int)}
+const getsockopt	= {sock, lev, opt, val, len;	-> (syscall(Syssetsockopt, a(sock), a(lev), a(opt), a(val), a(len)) : int)}
+
+/* memory management */
+const munmap	= {addr, len;		-> syscall(Sysmunmap, a(addr), a(len))}
+const mmap	= {addr, len, prot, flags, fd, off;
+	/* the actual syscall has padding on the offset arg */
+	-> (syscall(Sysmmap, a(addr), a(len), a(prot), a(flags), a(fd), a(0), a(off)) : byte#)
+}
+
+/* time */
+const clock_getres = {clk, ts;	-> (syscall(Sysclock_getres, clockid(clk), a(ts)) : int32)}
+const clock_gettime = {clk, ts;	-> (syscall(Sysclock_gettime, clockid(clk), a(ts)) : int32)}
+const clock_settime = {clk, ts;	-> (syscall(Sysclock_settime, clockid(clk), a(ts)) : int32)}
+
+const sleep = {time
+	var req, rem
+	req = [.sec = (time : int64), .nsec = 0]
+	-> nanosleep(&req, &rem)
+}
+
+const nanosleep	= {req, rem;	-> (syscall(Sysnanosleep, a(req), a(rem)) : int32)}
+
+
+/* system information */
+const uname	= {buf
+	var mib : int[2]
+	var ret
+	var sys, syssz
+	var nod, nodsz
+	var rel, relsz
+	var ver, versz
+	var mach, machsz
+
+	ret = 0
+	mib[0] = 1 /* CTL_KERN */
+	mib[1] = 1 /* KERN_OSTYPE */
+	sys = (buf.system[:] : void#)
+	syssz = buf.system.len
+	ret = sysctl(mib[:], sys, &syssz, (0 : void#), (0 : size#))
+	if ret < 0
+		-> ret
+	;;
+
+	mib[0] = 1 /* CTL_KERN */
+	mib[1] = 10 /* KERN_HOSTNAME */
+	nod = (buf.node[:] : void#)
+	nodsz = buf.node.len
+	ret = sysctl(mib[:], nod, &nodsz, (0 : void#), (0 : size#))
+	if ret < 0
+		-> ret
+	;;
+
+	mib[0] = 1 /* CTL_KERN */
+	mib[1] = 2 /* KERN_OSRELEASE */
+	rel = (buf.release[:] : void#)
+	relsz = buf.release.len
+	ret = sysctl(mib[:], rel, &relsz, (0 : void#), (0 : size#))
+	if ret < 0
+		-> ret
+	;;
+
+	mib[0] = 1 /* CTL_KERN */
+	mib[1] = 27 /* KERN_OSVERSION */
+	ver = (buf.version[:] : void#)
+	versz = buf.version.len
+	ret = sysctl(mib[:], ver, &versz, (0 : void#), (0 : size#))
+	if ret < 0
+		-> ret
+	;;
+
+	mib[0] = 6 /* CTL_HW */
+	mib[1] = 1 /* HW_MACHINE */
+	mach = (buf.machine[:] : void#)
+	machsz = buf.machine.len
+	ret = sysctl(mib[:], mach, &machsz, (0 : void#), (0 : size#))
+	if ret < 0
+		-> ret
+	;;
+
+	-> 0
+}
+
+const sysctl = {mib, old, oldsz, new, newsz
+	/* all args already passed through a() or ar  ptrs */
+	-> (syscall(Syssysctl, \
+		(mib : int#), a(mib.len), old, oldsz, new, newsz) : int)
+}
+
+const clockid = {clk
+	match clk
+	| `Clockrealtime:	-> 0
+	| `Clockproccputime:	-> 2
+	| `Clockmonotonic:	-> 3
+	| `Clockthreadcputime:	-> 4
+	| `Clockuptime:	-> 5
+	;;
+	-> -1
+}
+
+const waitstatus = {st
+	if st < 0
+		-> `Waitfail st
+	;;
+	match st & 0o177
+	| 0:    -> `Waitexit (st >> 8)
+	| 0x7f:-> `Waitstop (st >> 8)
+	| sig:  -> `Waitsig sig
+	;;
+}
+
--- /dev/null
+++ b/test/data/catfile-in
@@ -1,0 +1,1 @@
+Hello-世界