xref: /freebsd-src/sys/tools/syscalls/config.lua (revision ec86d763d1c94648419aeb931683dcb37bf72656)
19ded074eSagge3--
29ded074eSagge3-- SPDX-License-Identifier: BSD-2-Clause
39ded074eSagge3--
49ded074eSagge3-- Copyright (c) 2021-2024 SRI International
59ded074eSagge3-- Copyright (c) 2024 Tyler Baxter <agge@FreeBSD.org>
69ded074eSagge3-- Copyright (c) 2023 Warner Losh <imp@bsdimp.com>
79ded074eSagge3-- Copyright (c) 2019 Kyle Evans <kevans@FreeBSD.org>
89ded074eSagge3--
99ded074eSagge3
109ded074eSagge3--
119ded074eSagge3-- Code to read in the config file that drives this. Since we inherit from the
129ded074eSagge3-- FreeBSD makesyscall.sh legacy, all config is done through a config file that
139ded074eSagge3-- sets a number of variables (as noted below); it used to be a .sh file that
149ded074eSagge3-- was sourced in. This dodges the need to write a command line parser.
159ded074eSagge3--
169ded074eSagge3
179ded074eSagge3local util = require("tools.util")
189ded074eSagge3
199ded074eSagge3--
209ded074eSagge3-- Global config map.
219ded074eSagge3-- Default configuration is native. Any of these may get replaced by an
229ded074eSagge3-- optionally specified configuration file.
239ded074eSagge3--
249ded074eSagge3local config = {
259ded074eSagge3	sysnames = "syscalls.c",
269ded074eSagge3	syshdr = "../sys/syscall.h",
279ded074eSagge3	sysmk = "/dev/null",
289ded074eSagge3	syssw = "init_sysent.c",
299ded074eSagge3	systrace = "systrace_args.c",
309ded074eSagge3	sysproto = "../sys/sysproto.h",
319ded074eSagge3	libsysmap = "/dev/null",
329ded074eSagge3	libsys_h = "/dev/null",
339ded074eSagge3	sysproto_h = "_SYS_SYSPROTO_H_",
349ded074eSagge3	syscallprefix = "SYS_",
359ded074eSagge3	switchname = "sysent",
369ded074eSagge3	namesname = "syscallnames",
379ded074eSagge3	abi_flags = {},
389ded074eSagge3	abi_func_prefix = "",
399ded074eSagge3	abi_type_suffix = "",
409ded074eSagge3	abi_long = "long",
419ded074eSagge3	abi_u_long = "u_long",
429ded074eSagge3	abi_semid_t = "semid_t",
439ded074eSagge3	abi_size_t = "size_t",
449ded074eSagge3	abi_ptr_array_t = "",
459ded074eSagge3	abi_headers = "",
469ded074eSagge3	abi_intptr_t = "intptr_t",
479ded074eSagge3	ptr_intptr_t_cast = "intptr_t",
489ded074eSagge3	obsol = {},
499ded074eSagge3	unimpl = {},
509ded074eSagge3	compat_set = "native",
519ded074eSagge3	mincompat = 0,
529ded074eSagge3	-- System calls that require ABI-specific handling.
539ded074eSagge3	syscall_abi_change = {},
549ded074eSagge3	-- System calls that appear to require handling, but don't.
559ded074eSagge3	syscall_no_abi_change = {},
569ded074eSagge3	-- Keep track of modifications if there are.
579ded074eSagge3	modifications = {},
589ded074eSagge3	-- Stores compat_sets from syscalls.conf; config.mergeCompat()
599ded074eSagge3	-- instantiates.
609ded074eSagge3	compat_options = {},
619ded074eSagge3}
629ded074eSagge3
639ded074eSagge3--
649ded074eSagge3-- For each entry, the ABI flag is the key. One may also optionally provide an
659ded074eSagge3-- expr, which are contained in an array associated with each key; expr gets
669ded074eSagge3-- applied to each argument type to indicate whether this argument is subject to
679ded074eSagge3-- ABI change given the configured flags.
689ded074eSagge3--
699ded074eSagge3config.known_abi_flags = {
709ded074eSagge3	long_size = {
719ded074eSagge3		"_Contains[a-z_]*_long_",
729ded074eSagge3		"^long [a-z0-9_]+$",
739ded074eSagge3		"long [*]",
749ded074eSagge3		"size_t [*]",
759ded074eSagge3		-- semid_t is not included because it is only used
769ded074eSagge3		-- as an argument or written out individually and
779ded074eSagge3		-- said writes are handled by the ksem framework.
789ded074eSagge3		-- Technically a sign-extension issue exists for
799ded074eSagge3		-- arguments, but because semid_t is actually a file
809ded074eSagge3		-- descriptor negative 32-bit values are invalid
819ded074eSagge3		-- regardless of sign-extension.
829ded074eSagge3	},
839ded074eSagge3	time_t_size = {
849ded074eSagge3		"_Contains[a-z_]*_timet_",
859ded074eSagge3	},
869ded074eSagge3	pointer_args = {
879ded074eSagge3		-- no expr
889ded074eSagge3	},
899ded074eSagge3	pointer_size = {
909ded074eSagge3		"_Contains[a-z_]*_ptr_",
919ded074eSagge3		"[*][*]",
929ded074eSagge3	},
939ded074eSagge3	pair_64bit = {
949ded074eSagge3		"^dev_t[ ]*$",
959ded074eSagge3		"^id_t[ ]*$",
969ded074eSagge3		"^off_t[ ]*$",
979ded074eSagge3	},
989ded074eSagge3}
999ded074eSagge3
1009ded074eSagge3-- All compat option entries should have five entries:
1019ded074eSagge3--	definition: The preprocessor macro that will be set for this.
1029ded074eSagge3--	compatlevel: The level this compatibility should be included at. This
1039ded074eSagge3--	    generally represents the version of FreeBSD that it is compatible
1049ded074eSagge3--	    with, but ultimately it's just the level of mincompat in which it's
1059ded074eSagge3--	    included.
1069ded074eSagge3--	flag: The name of the flag in syscalls.master.
1079ded074eSagge3--	prefix: The prefix to use for _args and syscall prototype.  This will be
1089ded074eSagge3--	    used as-is, without "_" or any other character appended.
1099ded074eSagge3--	descr: The description of this compat option in init_sysent.c comments.
1109ded074eSagge3-- The special "stdcompat" entry will cause the other five to be autogenerated.
1119ded074eSagge3local compat_option_sets = {
1129ded074eSagge3	native = {
1139ded074eSagge3		{
1149ded074eSagge3			definition = "COMPAT_43",
1159ded074eSagge3			compatlevel = 3,
1169ded074eSagge3			flag = "COMPAT",
1179ded074eSagge3			prefix = "o",
1189ded074eSagge3			descr = "old",
1199ded074eSagge3		},
1209ded074eSagge3		{ stdcompat = "FREEBSD4" },
1219ded074eSagge3		{ stdcompat = "FREEBSD6" },
1229ded074eSagge3		{ stdcompat = "FREEBSD7" },
1239ded074eSagge3		{ stdcompat = "FREEBSD10" },
1249ded074eSagge3		{ stdcompat = "FREEBSD11" },
1259ded074eSagge3		{ stdcompat = "FREEBSD12" },
1269ded074eSagge3		{ stdcompat = "FREEBSD13" },
1279ded074eSagge3		{ stdcompat = "FREEBSD14" },
1289ded074eSagge3	},
1299ded074eSagge3}
1309ded074eSagge3
1319ded074eSagge3--
1329ded074eSagge3-- config looks like a shell script; in fact, the previous makesyscalls.sh
1339ded074eSagge3-- script actually sourced it in.  It had a pretty common format, so we should
1349ded074eSagge3-- be fine to make various assumptions.
1359ded074eSagge3--
1369ded074eSagge3-- This function processes config to be merged into our global config map with
1379ded074eSagge3-- config.merge(). It aborts if there's malformed lines and returns NIL and a
1389ded074eSagge3-- message if no file was provided.
1399ded074eSagge3--
1409ded074eSagge3function config.process(file)
1419ded074eSagge3	local cfg = {}
1429ded074eSagge3	local comment_line_expr = "^%s*#.*"
1439ded074eSagge3	-- We capture any whitespace padding here so we can easily advance to
1449ded074eSagge3	-- the end of the line as needed to check for any trailing bogus bits.
1459ded074eSagge3	-- Alternatively, we could drop the whitespace and instead try to
1469ded074eSagge3	-- use a pattern to strip out the meaty part of the line, but then we
1479ded074eSagge3	-- would need to sanitize the line for potentially special characters.
1489ded074eSagge3	local line_expr = "^([%w%p]+%s*)=(%s*[`\"]?[^\"`]*[`\"]?)"
1499ded074eSagge3
1509ded074eSagge3	if not file then
1519ded074eSagge3		return nil, "No file given"
1529ded074eSagge3	end
1539ded074eSagge3
1549ded074eSagge3	local fh = assert(io.open(file))
1559ded074eSagge3
1569ded074eSagge3	for nextline in fh:lines() do
1579ded074eSagge3		-- Strip any whole-line comments.
1589ded074eSagge3		nextline = nextline:gsub(comment_line_expr, "")
1599ded074eSagge3		-- Parse it into key, value pairs.
1609ded074eSagge3		local key, value = nextline:match(line_expr)
1619ded074eSagge3		if key ~= nil and value ~= nil then
1629ded074eSagge3			local kvp = key .. "=" .. value
1639ded074eSagge3			key = util.trim(key)
1649ded074eSagge3			value = util.trim(value)
1659ded074eSagge3			local delim = value:sub(1,1)
1669ded074eSagge3			if delim == '"' then
1679ded074eSagge3				local trailing_context
1689ded074eSagge3
1699ded074eSagge3				-- Strip off the key/value part.
1709ded074eSagge3				trailing_context = nextline:sub(kvp:len() + 1)
1719ded074eSagge3				-- Strip off any trailing comment.
1729ded074eSagge3				trailing_context = trailing_context:gsub("#.*$",
1739ded074eSagge3				    "")
1749ded074eSagge3				-- Strip off leading/trailing whitespace.
1759ded074eSagge3				trailing_context = util.trim(trailing_context)
1769ded074eSagge3				if trailing_context ~= "" then
1779ded074eSagge3					print(trailing_context)
1789ded074eSagge3					util.abort(1,
1799ded074eSagge3					    "Malformed line: " .. nextline)
1809ded074eSagge3				end
1819ded074eSagge3
1829ded074eSagge3				value = util.trim(value, delim)
1839ded074eSagge3			else
1849ded074eSagge3				-- Strip off potential comments.
1859ded074eSagge3				value = value:gsub("#.*$", "")
1869ded074eSagge3				-- Strip off any padding whitespace.
1879ded074eSagge3				value = util.trim(value)
1889ded074eSagge3				if value:match("%s") then
1899ded074eSagge3					util.abort(1,
1909ded074eSagge3					    "Malformed config line: " ..
1919ded074eSagge3					    nextline)
1929ded074eSagge3				end
1939ded074eSagge3			end
1949ded074eSagge3			cfg[key] = value
1959ded074eSagge3		elseif not nextline:match("^%s*$") then
1969ded074eSagge3			-- Make sure format violations don't get overlooked
1979ded074eSagge3			-- here, but ignore blank lines.  Comments are already
1989ded074eSagge3			-- stripped above.
1999ded074eSagge3			util.abort(1, "Malformed config line: " .. nextline)
2009ded074eSagge3		end
2019ded074eSagge3	end
2029ded074eSagge3
2039ded074eSagge3	assert(fh:close())
2049ded074eSagge3	return cfg
2059ded074eSagge3end
2069ded074eSagge3
2079ded074eSagge3-- Merges processed configuration file into the global config map (see above),
2089ded074eSagge3-- or returns NIL and a message if no file was provided.
2099ded074eSagge3function config.merge(fh)
2109ded074eSagge3	if not fh then
2119ded074eSagge3		return nil, "No file given"
2129ded074eSagge3	end
2139ded074eSagge3
2149ded074eSagge3	local res = assert(config.process(fh))
2159ded074eSagge3
2169ded074eSagge3	for k, v in pairs(res) do
2179ded074eSagge3		if v ~= config[k] then
2189ded074eSagge3			-- Handling of string lists:
2199ded074eSagge3			if k:find("abi_flags") then
2209ded074eSagge3				-- Match for pipe, that's how abi_flags
2219ded074eSagge3				-- is formatted.
2229ded074eSagge3				config[k] = util.setFromString(v, "[^|]+")
223*ec86d763SBrooks Davis			elseif k:find("syscall_abi_change") or
2249ded074eSagge3			    k:find("syscall_no_abi_change") or
2259ded074eSagge3			    k:find("obsol") or
2269ded074eSagge3			    k:find("unimpl") then
2279ded074eSagge3				-- Match for space, that's how these
2289ded074eSagge3				-- are formatted.
2299ded074eSagge3				config[k] = util.setFromString(v, "[^ ]+")
2309ded074eSagge3			else
2319ded074eSagge3				config[k] = v
2329ded074eSagge3			end
2339ded074eSagge3			-- Construct config modified table as config
2349ded074eSagge3			-- is processed.
2359ded074eSagge3			config.modifications[k] = true
2369ded074eSagge3		else
2379ded074eSagge3			-- config wasn't modified.
2389ded074eSagge3			config.modifications[k] = false
2399ded074eSagge3		end
2409ded074eSagge3	end
2419ded074eSagge3end
2429ded074eSagge3
2439ded074eSagge3-- Returns TRUE if there are ABI changes from native for the provided ABI flag.
2449ded074eSagge3function config.abiChanges(name)
2459ded074eSagge3	if config.known_abi_flags[name] == nil then
2469ded074eSagge3		util.abort(1, "abi_changes: unknown flag: " .. name)
2479ded074eSagge3	end
2489ded074eSagge3	return config.abi_flags[name] ~= nil
2499ded074eSagge3end
2509ded074eSagge3
2519ded074eSagge3-- Instantiates config.compat_options.
2529ded074eSagge3function config.mergeCompat()
2539ded074eSagge3	if config.compat_set ~= "" then
2549ded074eSagge3		if not compat_option_sets[config.compat_set] then
2559ded074eSagge3			util.abort(1, "Undefined compat set: " ..
2569ded074eSagge3			    config.compat_set)
2579ded074eSagge3		end
2589ded074eSagge3
2599ded074eSagge3		config.compat_options = compat_option_sets[config.compat_set]
2609ded074eSagge3	end
2619ded074eSagge3end
2629ded074eSagge3
2639ded074eSagge3return config
264