xref: /freebsd/sys/tools/syscalls/scripts/sysproto_h.lua (revision 42d075f4b7b74eb3c4f943d6bdcc2aeb56be6388)
19ded074eSagge3#!/usr/libexec/flua
29ded074eSagge3--
39ded074eSagge3-- SPDX-License-Identifier: BSD-2-Clause
49ded074eSagge3--
59ded074eSagge3-- Copyright (c) 2024 Tyler Baxter <agge@FreeBSD.org>
69ded074eSagge3-- Copyright (c) 2019 Kyle Evans <kevans@FreeBSD.org>
79ded074eSagge3--
89ded074eSagge3
99ded074eSagge3-- Setup to be a module, or ran as its own script.
109ded074eSagge3local sysproto_h = {}
119ded074eSagge3local script = not pcall(debug.getlocal, 4, 1)	-- TRUE if script.
129ded074eSagge3if script then
139ded074eSagge3	-- Add library root to the package path.
149ded074eSagge3	local path = arg[0]:gsub("/[^/]+.lua$", "")
159ded074eSagge3	package.path = package.path .. ";" .. path .. "/../?.lua"
169ded074eSagge3end
179ded074eSagge3
189ded074eSagge3local FreeBSDSyscall = require("core.freebsd-syscall")
199ded074eSagge3local generator = require("tools.generator")
209ded074eSagge3
219ded074eSagge3-- File has not been decided yet; config will decide file.  Default defined as
229ded074eSagge3-- /dev/null.
239ded074eSagge3sysproto_h.file = "/dev/null"
249ded074eSagge3
259ded074eSagge3function sysproto_h.generate(tbl, config, fh)
269ded074eSagge3	-- Grab the master system calls table.
279ded074eSagge3	local s = tbl.syscalls
289ded074eSagge3
299ded074eSagge3	-- Bind the generator to the parameter file.
309ded074eSagge3	local gen = generator:new({}, fh)
319ded074eSagge3	gen.storage_levels = {}	-- make sure storage is clear
329ded074eSagge3
339ded074eSagge3	-- Write the generated preamble.
349ded074eSagge3	gen:preamble("System call prototypes.")
359ded074eSagge3
369ded074eSagge3	-- Write out all the preprocessor directives.
379ded074eSagge3	gen:write(string.format([[
389ded074eSagge3#ifndef %s
399ded074eSagge3#define	%s
409ded074eSagge3
419ded074eSagge3#include <sys/types.h>
429ded074eSagge3#include <sys/signal.h>
439ded074eSagge3#include <sys/cpuset.h>
449ded074eSagge3#include <sys/domainset.h>
459ded074eSagge3#include <sys/_ffcounter.h>
469ded074eSagge3#include <sys/_semaphore.h>
479ded074eSagge3#include <sys/ucontext.h>
489ded074eSagge3#include <sys/wait.h>
499ded074eSagge3
509ded074eSagge3#include <bsm/audit_kevents.h>
519ded074eSagge3
529ded074eSagge3struct proc;
539ded074eSagge3
549ded074eSagge3struct thread;
559ded074eSagge3
569ded074eSagge3#define	PAD_(t)	(sizeof(syscallarg_t) <= sizeof(t) ? \
579ded074eSagge3		0 : sizeof(syscallarg_t) - sizeof(t))
589ded074eSagge3
599ded074eSagge3#if BYTE_ORDER == LITTLE_ENDIAN
609ded074eSagge3#define	PADL_(t)	0
619ded074eSagge3#define	PADR_(t)	PAD_(t)
629ded074eSagge3#else
639ded074eSagge3#define	PADL_(t)	PAD_(t)
649ded074eSagge3#define	PADR_(t)	0
659ded074eSagge3#endif
669ded074eSagge3
679ded074eSagge3]], config.sysproto_h, config.sysproto_h))
689ded074eSagge3
699ded074eSagge3	-- 64-bit padding preprocessor directive.
709ded074eSagge3	gen:pad64(config.abiChanges("pair_64bit"))
719ded074eSagge3
729ded074eSagge3	--
739ded074eSagge3	-- Storing each compat entry requires storing multiple levels of file
749ded074eSagge3	-- generation; compat entries are given ranges of 10 instead to cope
759ded074eSagge3	-- with this.  For example, 13 is indexed as 130; 131 is the second
769ded074eSagge3	-- storage level of 13.
779ded074eSagge3	--
789ded074eSagge3
799ded074eSagge3	-- Store all the compat #ifdef from compat_options at their zero index.
809ded074eSagge3	for _, v in pairs(config.compat_options) do
819ded074eSagge3		-- Tag an extra newline to the end, so it doesn't have to be
829ded074eSagge3		-- worried about later.
839ded074eSagge3		gen:store(string.format("\n#ifdef %s\n\n", v.definition),
849ded074eSagge3				  v.compatlevel * 10)
859ded074eSagge3	end
869ded074eSagge3
879ded074eSagge3	for _, v in pairs(s) do
889ded074eSagge3		local c = v:compatLevel()
899ded074eSagge3
909ded074eSagge3		-- Audit defines are stored at an arbitrarily large number so
919ded074eSagge3		-- that they're always at the last storage level, and compat
929ded074eSagge3		-- entries can be indexed by their compat level (more
939ded074eSagge3		-- intuitive).
949ded074eSagge3		local audit_idx = 10000 -- this should do
959ded074eSagge3
96*42d075f4SBrooks Davis		gen:write(v.prolog)
97*42d075f4SBrooks Davis		gen:store(v.prolog, 1)
98*42d075f4SBrooks Davis		for _, w in pairs(config.compat_options) do
99*42d075f4SBrooks Davis			gen:store(v.prolog, w.compatlevel * 10)
100*42d075f4SBrooks Davis		end
101*42d075f4SBrooks Davis
1029ded074eSagge3		-- Handle non-compat:
1039ded074eSagge3		if v:native() then
1049ded074eSagge3			-- All these negation conditions are because (in
1059ded074eSagge3			-- general) these are cases where code for sysproto.h
1069ded074eSagge3			-- is not generated.
1079ded074eSagge3			if not v.type.NOARGS and not v.type.NOPROTO and
1089ded074eSagge3			    not v.type.NODEF then
1099ded074eSagge3				if #v.args > 0 then
1109ded074eSagge3					gen:write(string.format(
1119ded074eSagge3					    "struct %s {\n", v.arg_alias))
1129ded074eSagge3					for _, arg in ipairs(v.args) do
1139ded074eSagge3						if arg.type == "int" and
1149ded074eSagge3						   arg.name == "_pad" and
1159ded074eSagge3						   config.abiChanges(
1169ded074eSagge3						       "pair_64bit") then
1179ded074eSagge3							gen:write("#ifdef PAD64_REQUIRED\n")
1189ded074eSagge3						end
1199ded074eSagge3
1209ded074eSagge3						gen:write(string.format([[
1219ded074eSagge3	char %s_l_[PADL_(%s)]; %s %s; char %s_r_[PADR_(%s)];
1229ded074eSagge3]],
1239ded074eSagge3						    arg.name, arg.type,
1249ded074eSagge3						    arg.type, arg.name,
1259ded074eSagge3						    arg.name, arg.type))
1269ded074eSagge3
1279ded074eSagge3						if arg.type == "int" and
1289ded074eSagge3						    arg.name == "_pad" and
1299ded074eSagge3						    config.abiChanges(
1309ded074eSagge3							"pair_64bit") then
1319ded074eSagge3							gen:write("#endif\n")
1329ded074eSagge3						end
1339ded074eSagge3					end
1349ded074eSagge3					gen:write("};\n")
1359ded074eSagge3				else
1369ded074eSagge3					gen:write(string.format(
1379ded074eSagge3					    "struct %s {\n\tsyscallarg_t dummy;\n};\n",
1389ded074eSagge3					    v.arg_alias))
1399ded074eSagge3				end
1409ded074eSagge3			end
1419ded074eSagge3			if not v.type.NOPROTO and not v.type.NODEF then
1429ded074eSagge3				local sys_prefix = "sys_"
1439ded074eSagge3				if v.name == "nosys" or v.name == "lkmnosys" or
1449ded074eSagge3				    v.name == "sysarch" or
1459ded074eSagge3				    v.name:find("^freebsd") or
1469ded074eSagge3				    v.name:find("^linux") then
1479ded074eSagge3					sys_prefix = ""
1489ded074eSagge3				end
1499ded074eSagge3				gen:store(string.format(
1509ded074eSagge3				    "%s\t%s%s(struct thread *, struct %s *);\n",
1519ded074eSagge3				    v.rettype, sys_prefix, v.name, v.arg_alias),
1529ded074eSagge3				    1)
1539ded074eSagge3				gen:store(string.format(
1549ded074eSagge3				    "#define\t%sAUE_%s\t%s\n",
1559ded074eSagge3				    config.syscallprefix, v:symbol(), v.audit),
1569ded074eSagge3				    audit_idx)
1579ded074eSagge3			end
1589ded074eSagge3
1599ded074eSagge3		-- Handle compat (everything >= FREEBSD3):
1609ded074eSagge3		elseif c >= 3 then
1619ded074eSagge3			local idx = c * 10
1629ded074eSagge3			if not v.type.NOARGS and not v.type.NOPROTO and
1639ded074eSagge3				not v.type.NODEF then
1649ded074eSagge3				if #v.args > 0 then
1659ded074eSagge3					gen:store(string.format(
1669ded074eSagge3					    "struct %s {\n", v.arg_alias), idx)
1679ded074eSagge3					for _, arg in ipairs(v.args) do
1689ded074eSagge3						gen:store(string.format([[
1699ded074eSagge3	char %s_l_[PADL_(%s)]; %s %s; char %s_r_[PADR_(%s)];
1709ded074eSagge3]],
1719ded074eSagge3						    arg.name, arg.type,
1729ded074eSagge3						    arg.type, arg.name,
1739ded074eSagge3						    arg.name, arg.type), idx)
1749ded074eSagge3					end
1759ded074eSagge3					gen:store("};\n", idx)
1769ded074eSagge3				else
1779ded074eSagge3					-- Not stored, written on the first run.
1789ded074eSagge3					gen:write(string.format([[
1799ded074eSagge3struct %s {
1809ded074eSagge3	syscallarg_t dummy;
1819ded074eSagge3};
1829ded074eSagge3]],
1839ded074eSagge3					    v.arg_alias))
1849ded074eSagge3				end
1859ded074eSagge3			end
1869ded074eSagge3			if not v.type.NOPROTO and not v.type.NODEF then
1879ded074eSagge3				gen:store(string.format([[
1889ded074eSagge3%s	%s%s(struct thread *, struct %s *);
1899ded074eSagge3]],
1909ded074eSagge3				    v.rettype, v:compatPrefix(), v.name,
1919ded074eSagge3				    v.arg_alias), idx + 1)
1929ded074eSagge3				gen:store(string.format([[
1939ded074eSagge3#define	%sAUE_%s%s	%s
1949ded074eSagge3]],
1959ded074eSagge3				    config.syscallprefix, v:compatPrefix(),
1969ded074eSagge3				    v.name, v.audit), audit_idx)
1979ded074eSagge3			end
1989ded074eSagge3		end
1999ded074eSagge3		-- Do nothing for obsolete, unimplemented, and reserved.
2009ded074eSagge3	end
2019ded074eSagge3
2029ded074eSagge3	-- Append #endif to the end of each compat option.
2039ded074eSagge3	for _, v in pairs(config.compat_options) do
2049ded074eSagge3		-- Based on how they're indexed, 9 is the last index.
2059ded074eSagge3		local end_idx = (v.compatlevel * 10) + 9
2069ded074eSagge3		-- Need an extra newline after #endif.
2079ded074eSagge3		gen:store(string.format("\n#endif /* %s */\n\n", v.definition),
2089ded074eSagge3		    end_idx)
2099ded074eSagge3	end
2109ded074eSagge3
211*42d075f4SBrooks Davis	gen:write(tbl.epilog)
212*42d075f4SBrooks Davis	gen:store(tbl.epilog, 1)
213*42d075f4SBrooks Davis	for _, w in pairs(config.compat_options) do
214*42d075f4SBrooks Davis		gen:store(tbl.epilog, w.compatlevel * 10)
215*42d075f4SBrooks Davis	end
216*42d075f4SBrooks Davis
2179ded074eSagge3	if gen.storage_levels ~= nil then
2189ded074eSagge3		gen:writeStorage()
2199ded074eSagge3	end
2209ded074eSagge3
2219ded074eSagge3	-- After storage has been unrolled, tag on the ending bits.
2229ded074eSagge3	gen:write(string.format([[
2239ded074eSagge3
2249ded074eSagge3#undef PAD_
2259ded074eSagge3#undef PADL_
2269ded074eSagge3#undef PADR_
2279ded074eSagge3
2289ded074eSagge3#endif /* !%s */
2299ded074eSagge3]], config.sysproto_h))
2309ded074eSagge3end
2319ded074eSagge3
2329ded074eSagge3-- Entry of script:
2339ded074eSagge3if script then
2349ded074eSagge3	local config = require("config")
2359ded074eSagge3
2369ded074eSagge3	if #arg < 1 or #arg > 2 then
2379ded074eSagge3		error("usage: " .. arg[0] .. " syscall.master")
2389ded074eSagge3	end
2399ded074eSagge3
2409ded074eSagge3	local sysfile, configfile = arg[1], arg[2]
2419ded074eSagge3
2429ded074eSagge3	config.merge(configfile)
2439ded074eSagge3	config.mergeCompat()
2449ded074eSagge3
2459ded074eSagge3	-- The parsed system call table.
2469ded074eSagge3	local tbl = FreeBSDSyscall:new{sysfile = sysfile, config = config}
2479ded074eSagge3
2489ded074eSagge3	sysproto_h.file = config.sysproto	-- change file here
2499ded074eSagge3	sysproto_h.generate(tbl, config, sysproto_h.file)
2509ded074eSagge3end
2519ded074eSagge3
2529ded074eSagge3-- Return the module.
2539ded074eSagge3return sysproto_h
254