1*b3b23f28SWarner Losh#!/usr/libexec/flua 2*b3b23f28SWarner Losh-- 3*b3b23f28SWarner Losh-- SPDX-License-Identifier: BSD-2-Clause 4*b3b23f28SWarner Losh-- 5*b3b23f28SWarner Losh-- Copyright (c) 2026 Warner Losh <imp@bsdimp.com> 6*b3b23f28SWarner Losh-- 7*b3b23f28SWarner Losh 8*b3b23f28SWarner Losh-- Setup to be a module, or ran as its own script. 9*b3b23f28SWarner Loshlocal syscall_json = {} 10*b3b23f28SWarner Loshlocal script = not pcall(debug.getlocal, 4, 1) -- TRUE if script. 11*b3b23f28SWarner Loshif script then 12*b3b23f28SWarner Losh -- Add library root to the package path. 13*b3b23f28SWarner Losh local path = arg[0]:gsub("/[^/]+.lua$", "") 14*b3b23f28SWarner Losh package.path = package.path .. ";" .. path .. "/../?.lua" 15*b3b23f28SWarner Loshend 16*b3b23f28SWarner Losh 17*b3b23f28SWarner Loshlocal FreeBSDSyscall = require("core.freebsd-syscall") 18*b3b23f28SWarner Loshlocal ucl = require("ucl") 19*b3b23f28SWarner Losh 20*b3b23f28SWarner Losh-- Convert the type flags set (table with flag=true entries) to a sorted list. 21*b3b23f28SWarner Loshlocal function flagsToList(typetbl) 22*b3b23f28SWarner Losh local flags = {} 23*b3b23f28SWarner Losh for k, _ in pairs(typetbl) do 24*b3b23f28SWarner Losh table.insert(flags, k) 25*b3b23f28SWarner Losh end 26*b3b23f28SWarner Losh table.sort(flags) 27*b3b23f28SWarner Losh return flags 28*b3b23f28SWarner Loshend 29*b3b23f28SWarner Losh 30*b3b23f28SWarner Losh-- Convert a single syscall object to a plain table suitable for JSON export. 31*b3b23f28SWarner Losh-- Much of the data is available only as a method call. 32*b3b23f28SWarner Loshlocal function syscallToTable(v) 33*b3b23f28SWarner Losh local entry = { 34*b3b23f28SWarner Losh num = v.num, 35*b3b23f28SWarner Losh name = v.name or "", 36*b3b23f28SWarner Losh alias = v.alias or "", 37*b3b23f28SWarner Losh audit = v.audit or "", 38*b3b23f28SWarner Losh flags = flagsToList(v.type), 39*b3b23f28SWarner Losh compat_level = v:compatLevel(), 40*b3b23f28SWarner Losh compat_prefix = v:compatPrefix(), 41*b3b23f28SWarner Losh symbol = v:symbol(), 42*b3b23f28SWarner Losh rettype = v.rettype or "int", 43*b3b23f28SWarner Losh cap = v.cap or "0", 44*b3b23f28SWarner Losh thr = v.thr or "SY_THR_STATIC", 45*b3b23f28SWarner Losh changes_abi = v.changes_abi or false, 46*b3b23f28SWarner Losh noproto = v.noproto or false, 47*b3b23f28SWarner Losh args_size = v.args_size or "0", 48*b3b23f28SWarner Losh arg_alias = v.arg_alias or "", 49*b3b23f28SWarner Losh } 50*b3b23f28SWarner Losh 51*b3b23f28SWarner Losh -- Export arguments with annotations. 52*b3b23f28SWarner Losh local args = {} 53*b3b23f28SWarner Losh if v.args ~= nil then 54*b3b23f28SWarner Losh for _, a in ipairs(v.args) do 55*b3b23f28SWarner Losh arg = { 56*b3b23f28SWarner Losh type = a.type, 57*b3b23f28SWarner Losh name = a.name, 58*b3b23f28SWarner Losh } 59*b3b23f28SWarner Losh if a.annotation ~= nil and a.annotation ~= "" then 60*b3b23f28SWarner Losh arg.annotation = a.annotation 61*b3b23f28SWarner Losh end 62*b3b23f28SWarner Losh table.insert(args, arg) 63*b3b23f28SWarner Losh end 64*b3b23f28SWarner Losh end 65*b3b23f28SWarner Losh entry.args = args 66*b3b23f28SWarner Losh 67*b3b23f28SWarner Losh -- Export altname/alttag/rettype if present (loadable syscalls). 68*b3b23f28SWarner Losh if v.altname ~= nil then 69*b3b23f28SWarner Losh entry.altname = v.altname 70*b3b23f28SWarner Losh end 71*b3b23f28SWarner Losh if v.alttag ~= nil then 72*b3b23f28SWarner Losh entry.alttag = v.alttag 73*b3b23f28SWarner Losh end 74*b3b23f28SWarner Losh 75*b3b23f28SWarner Losh return entry 76*b3b23f28SWarner Loshend 77*b3b23f28SWarner Losh 78*b3b23f28SWarner Loshfunction syscall_json.generate(tbl, config) 79*b3b23f28SWarner Losh -- Build the syscalls array. 80*b3b23f28SWarner Losh local syscalls = {} 81*b3b23f28SWarner Losh for _, v in pairs(tbl.syscalls) do 82*b3b23f28SWarner Losh table.insert(syscalls, syscallToTable(v)) 83*b3b23f28SWarner Losh end 84*b3b23f28SWarner Losh 85*b3b23f28SWarner Losh -- Build the structs data into a nicer structure 86*b3b23f28SWarner Losh local structs = {} 87*b3b23f28SWarner Losh if tbl.structs ~= nil then 88*b3b23f28SWarner Losh for k, _ in pairs(tbl.structs) do 89*b3b23f28SWarner Losh table.insert(structs, k) 90*b3b23f28SWarner Losh end 91*b3b23f28SWarner Losh table.sort(structs) 92*b3b23f28SWarner Losh end 93*b3b23f28SWarner Losh 94*b3b23f28SWarner Losh local root = { 95*b3b23f28SWarner Losh syscalls = syscalls, 96*b3b23f28SWarner Losh structs = structs, 97*b3b23f28SWarner Losh } 98*b3b23f28SWarner Losh 99*b3b23f28SWarner Losh local json = ucl.to_json(root) 100*b3b23f28SWarner Losh 101*b3b23f28SWarner Losh -- Write to stdout. 102*b3b23f28SWarner Losh io.write(json) 103*b3b23f28SWarner Losh io.write("\n") 104*b3b23f28SWarner Loshend 105*b3b23f28SWarner Losh 106*b3b23f28SWarner Losh-- Entry of script: 107*b3b23f28SWarner Loshif script then 108*b3b23f28SWarner Losh local config = require("config") 109*b3b23f28SWarner Losh 110*b3b23f28SWarner Losh if #arg < 1 or #arg > 2 then 111*b3b23f28SWarner Losh error("usage: " .. arg[0] .. " syscall.master [config]") 112*b3b23f28SWarner Losh end 113*b3b23f28SWarner Losh 114*b3b23f28SWarner Losh local sysfile, configfile = arg[1], arg[2] 115*b3b23f28SWarner Losh 116*b3b23f28SWarner Losh config.merge(configfile) 117*b3b23f28SWarner Losh config.mergeCompat() 118*b3b23f28SWarner Losh 119*b3b23f28SWarner Losh -- The parsed system call table. 120*b3b23f28SWarner Losh local tbl = FreeBSDSyscall:new{sysfile = sysfile, config = config} 121*b3b23f28SWarner Losh 122*b3b23f28SWarner Losh syscall_json.generate(tbl, config) 123*b3b23f28SWarner Loshend 124*b3b23f28SWarner Losh 125*b3b23f28SWarner Losh-- Return the module. 126*b3b23f28SWarner Loshreturn syscall_json 127