xref: /freebsd/sys/tools/syscalls/scripts/syscall_json.lua (revision b3b23f284a67317309af7c30bb70d5f461f3f02f)
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