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