# run this as: jq -r -f SELF syscalls.json # download syscalls.json from https://syscalls.mebeim.net/db/x86/64/x64/v6.6/table.json def asargs: join(", "); def csig: "\(.name)(\(.signature | asargs))"; def indent(w): w + (split("\n") | join("\n" + w)); def getargs: .signature | map(capture("(?.*[^a-zA-Z_0-9]+)(?[a-zA-Z_0-9]*)")); def strim: sub("^[[:space:]]+"; "") | sub("[[:space:]]+$"; ""); def rawtype: gsub("const"; "") | strim; # returns false if the given type may contain or be a pointer def isflat: [.] | inside([ "char", "unsigned char", "int", "struct cachestat_range", "struct stat", "struct pollfd", "sigset_t", "fd_set", "struct __kernel_old_timeval", "struct __kernel_old_itimerval", "struct __kernel_timespec", "struct sockaddr", "void", "loff_t", "struct rusage", "struct new_utsname", "struct sembuf", "struct msqid_ds", # unused pointers "struct linux_dirent", "struct timezone", "struct rlimit", "struct sysinfo", "struct tms", "gid_t", "uid_t", "siginfo_t", "struct utimbuf", "struct ustat", "struct statfs", "struct sched_param", "struct __kernel_timex", "__kernel_old_time_t", "u32", "unsigned long", "aio_context_t", "struct io_event", "struct iocb", "struct linux_dirent64", "timer_t", "struct __kernel_itimerspec", "struct epoll_event", "struct mq_attr", "unsigned int", "struct siginfo", "size_t", "struct perf_event_attr", "struct rlimit64", "struct file_handle", "struct getcpu_cache", "struct sched_attr", "union bpf_attr", "struct statx", "struct __aio_sigset", "struct rseq", "struct io_uring_params", "struct clone_args", "struct open_how", "struct mount_attr", "struct landlock_ruleset_attr", "struct futex_waitv", "" ]); # returns true if the given type definitely contains a pointer def isntflat: [.] | inside([ "struct sigaction", "struct iovec", "struct shmid_ds", "struct user_msghdr", "struct msgbuf", "stack_t", "struct sigevent", "struct kexec_segment", "struct robust_list_head", "struct mmsghdr", "" ]); def nimtype: rawtype | if . == "" then null # pointers elif endswith("*") then rtrimstr("*") | strim | if isflat then "pointer" elif isntflat then "pointer #[ TODO \(.) is not a flat type ]#" elif endswith("*") then "pointer #[ TODO \(.) is a nested pointer ]#" else error("\(.) is of dubious flatness!") end # scalar types elif startswith("enum") then "cint" elif [.] | inside(["int", "key_t", "pid_t", "clockid_t", "timer_t", "mqd_t", "__s32", "rwf_t"]) then "cint" elif [.] | inside(["size_t"]) then "csize_t" elif [.] | inside(["umode_t"]) then "cushort" elif [.] | inside(["unsigned int", "uid_t", "gid_t", "qid_t", "u32", "__u32"]) then "cuint" elif [.] | inside(["unsigned long", "off_t"]) then "clong" elif [.] | inside(["aio_context_t", "__u64"]) then "culong" elif [.] | inside(["loff_t"]) then "clonglong" elif [.] | inside(["key_serial_t"]) then "int32" elif [.] | inside(["cap_user_header_t", "cap_user_data_t"]) then "pointer" else error("\(.) is unknown as a nimtype") end; def nimstack: rawtype | if . == "" then null # pointers elif endswith("*") then rtrimstr("*") | strim | if isflat then "state.memory.raw_address(state.stack.pop.p)" elif isntflat then "nil # TODO \(.) is not a flat type" elif endswith("*") then "nil # TODO \(.) is a nested pointer" else error("\(.) is of dubious flatness!") end # scalar types elif startswith("enum") then "state.stack.pop.i.cint" elif [.] | inside(["int", "key_t", "pid_t", "clockid_t", "timer_t", "mqd_t", "__s32", "rwf_t"]) then "state.stack.pop.i.cint" elif [.] | inside(["size_t"]) then "state.stack.pop.u.csize_t" elif [.] | inside(["umode_t"]) then "state.stack.pop.i.cushort" elif [.] | inside(["unsigned int", "uid_t", "gid_t", "qid_t", "u32", "__u32"]) then "state.stack.pop.u.cuint" elif [.] | inside(["unsigned long", "off_t"]) then "state.stack.pop.i.clong" elif [.] | inside(["aio_context_t", "__u64"]) then "state.stack.pop.u.culong" elif [.] | inside(["loff_t"]) then "state.stack.pop.i.clonglong" elif [.] | inside(["key_serial_t"]) then "state.stack.pop.i.int32" elif [.] | inside(["cap_user_header_t", "cap_user_data_t"]) then "state.memory.raw_address(state.stack.pop.p)" else error("\(.) is unknown as a nimtype") end; def letstr: getargs | map("let syscall_\(.name | gsub("_"; "")): \(.type | nimtype) = \(.type | nimstack)") | join("\n"); def argcomma: if ( getargs | length ) == 0 then "" else ", " end; def argstr: getargs | map("syscall_" + (.name | gsub("_"; ""))) | join(", "); .syscalls[] | " of \(.number): # \(csig)\n" + "\(letstr | indent(" "))\n" + " let retval: clong = syscall(\(.number)\(argcomma)\(argstr))\n" + " state.stack.add ArcticType(i: retval.int64)\n"