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