diff --git a/sys/tools/syscalls/config.lua b/sys/tools/syscalls/config.lua index 92098a709854..fcf4c2217959 100644 --- a/sys/tools/syscalls/config.lua +++ b/sys/tools/syscalls/config.lua @@ -1,312 +1,263 @@ -- -- SPDX-License-Identifier: BSD-2-Clause -- -- Copyright (c) 2021-2024 SRI International -- Copyright (c) 2024 Tyler Baxter -- Copyright (c) 2023 Warner Losh -- Copyright (c) 2019 Kyle Evans -- -- -- Code to read in the config file that drives this. Since we inherit from the -- FreeBSD makesyscall.sh legacy, all config is done through a config file that -- sets a number of variables (as noted below); it used to be a .sh file that -- was sourced in. This dodges the need to write a command line parser. -- local util = require("tools.util") -- -- Global config map. -- Default configuration is native. Any of these may get replaced by an -- optionally specified configuration file. -- local config = { sysnames = "syscalls.c", syshdr = "../sys/syscall.h", sysmk = "/dev/null", syssw = "init_sysent.c", systrace = "systrace_args.c", sysproto = "../sys/sysproto.h", libsysmap = "/dev/null", libsys_h = "/dev/null", sysproto_h = "_SYS_SYSPROTO_H_", syscallprefix = "SYS_", switchname = "sysent", namesname = "syscallnames", abi_flags = {}, abi_func_prefix = "", abi_type_suffix = "", abi_long = "long", abi_u_long = "u_long", abi_semid_t = "semid_t", abi_size_t = "size_t", abi_ptr_array_t = "", abi_headers = "", abi_intptr_t = "intptr_t", ptr_intptr_t_cast = "intptr_t", obsol = {}, unimpl = {}, - capabilities_conf = "capabilities.conf", compat_set = "native", mincompat = 0, - capenabled = {}, -- System calls that require ABI-specific handling. syscall_abi_change = {}, -- System calls that appear to require handling, but don't. syscall_no_abi_change = {}, -- Keep track of modifications if there are. modifications = {}, -- Stores compat_sets from syscalls.conf; config.mergeCompat() -- instantiates. compat_options = {}, } -- -- For each entry, the ABI flag is the key. One may also optionally provide an -- expr, which are contained in an array associated with each key; expr gets -- applied to each argument type to indicate whether this argument is subject to -- ABI change given the configured flags. -- config.known_abi_flags = { long_size = { "_Contains[a-z_]*_long_", "^long [a-z0-9_]+$", "long [*]", "size_t [*]", -- semid_t is not included because it is only used -- as an argument or written out individually and -- said writes are handled by the ksem framework. -- Technically a sign-extension issue exists for -- arguments, but because semid_t is actually a file -- descriptor negative 32-bit values are invalid -- regardless of sign-extension. }, time_t_size = { "_Contains[a-z_]*_timet_", }, pointer_args = { -- no expr }, pointer_size = { "_Contains[a-z_]*_ptr_", "[*][*]", }, pair_64bit = { "^dev_t[ ]*$", "^id_t[ ]*$", "^off_t[ ]*$", }, } -- All compat option entries should have five entries: -- definition: The preprocessor macro that will be set for this. -- compatlevel: The level this compatibility should be included at. This -- generally represents the version of FreeBSD that it is compatible -- with, but ultimately it's just the level of mincompat in which it's -- included. -- flag: The name of the flag in syscalls.master. -- prefix: The prefix to use for _args and syscall prototype. This will be -- used as-is, without "_" or any other character appended. -- descr: The description of this compat option in init_sysent.c comments. -- The special "stdcompat" entry will cause the other five to be autogenerated. local compat_option_sets = { native = { { definition = "COMPAT_43", compatlevel = 3, flag = "COMPAT", prefix = "o", descr = "old", }, { stdcompat = "FREEBSD4" }, { stdcompat = "FREEBSD6" }, { stdcompat = "FREEBSD7" }, { stdcompat = "FREEBSD10" }, { stdcompat = "FREEBSD11" }, { stdcompat = "FREEBSD12" }, { stdcompat = "FREEBSD13" }, { stdcompat = "FREEBSD14" }, }, } -- -- config looks like a shell script; in fact, the previous makesyscalls.sh -- script actually sourced it in. It had a pretty common format, so we should -- be fine to make various assumptions. -- -- This function processes config to be merged into our global config map with -- config.merge(). It aborts if there's malformed lines and returns NIL and a -- message if no file was provided. -- function config.process(file) local cfg = {} local comment_line_expr = "^%s*#.*" -- We capture any whitespace padding here so we can easily advance to -- the end of the line as needed to check for any trailing bogus bits. -- Alternatively, we could drop the whitespace and instead try to -- use a pattern to strip out the meaty part of the line, but then we -- would need to sanitize the line for potentially special characters. local line_expr = "^([%w%p]+%s*)=(%s*[`\"]?[^\"`]*[`\"]?)" if not file then return nil, "No file given" end local fh = assert(io.open(file)) for nextline in fh:lines() do -- Strip any whole-line comments. nextline = nextline:gsub(comment_line_expr, "") -- Parse it into key, value pairs. local key, value = nextline:match(line_expr) if key ~= nil and value ~= nil then local kvp = key .. "=" .. value key = util.trim(key) value = util.trim(value) local delim = value:sub(1,1) if delim == '"' then local trailing_context -- Strip off the key/value part. trailing_context = nextline:sub(kvp:len() + 1) -- Strip off any trailing comment. trailing_context = trailing_context:gsub("#.*$", "") -- Strip off leading/trailing whitespace. trailing_context = util.trim(trailing_context) if trailing_context ~= "" then print(trailing_context) util.abort(1, "Malformed line: " .. nextline) end value = util.trim(value, delim) else -- Strip off potential comments. value = value:gsub("#.*$", "") -- Strip off any padding whitespace. value = util.trim(value) if value:match("%s") then util.abort(1, "Malformed config line: " .. nextline) end end cfg[key] = value elseif not nextline:match("^%s*$") then -- Make sure format violations don't get overlooked -- here, but ignore blank lines. Comments are already -- stripped above. util.abort(1, "Malformed config line: " .. nextline) end end assert(fh:close()) return cfg end -- Merges processed configuration file into the global config map (see above), -- or returns NIL and a message if no file was provided. function config.merge(fh) if not fh then return nil, "No file given" end local res = assert(config.process(fh)) for k, v in pairs(res) do if v ~= config[k] then -- Handling of string lists: if k:find("abi_flags") then -- Match for pipe, that's how abi_flags -- is formatted. config[k] = util.setFromString(v, "[^|]+") - elseif k:find("capenabled") or - k:find("syscall_abi_change") or + elseif k:find("syscall_abi_change") or k:find("syscall_no_abi_change") or k:find("obsol") or k:find("unimpl") then -- Match for space, that's how these -- are formatted. config[k] = util.setFromString(v, "[^ ]+") else config[k] = v end -- Construct config modified table as config -- is processed. config.modifications[k] = true else -- config wasn't modified. config.modifications[k] = false end end end -- Returns TRUE if there are ABI changes from native for the provided ABI flag. function config.abiChanges(name) if config.known_abi_flags[name] == nil then util.abort(1, "abi_changes: unknown flag: " .. name) end return config.abi_flags[name] ~= nil end -- Instantiates config.compat_options. function config.mergeCompat() if config.compat_set ~= "" then if not compat_option_sets[config.compat_set] then util.abort(1, "Undefined compat set: " .. config.compat_set) end config.compat_options = compat_option_sets[config.compat_set] end end --- Parses the provided capabilities.conf. Returns a string (comma separated --- list) as its formatted in capabilities.conf, or NIL and a message if no file --- was provided. -local function grabCapenabled(file, open_fail_ok) - local capentries = {} - local commentExpr = "#.*" - - if file == nil then - return nil, "No file given" - end - - local fh, msg, errno = io.open(file) - if fh == nil then - if not open_fail_ok then - util.abort(errno, msg) - end - return nil, msg - end - - for nextline in fh:lines() do - -- Strip any comments. - nextline = nextline:gsub(commentExpr, "") - if nextline ~= "" then - capentries[nextline] = true - end - end - - assert(fh:close()) - return capentries -end - --- Merge capability (Capsicum) configuration into the global config. -function config.mergeCapability() - -- We ignore errors here if we're relying on the default configuration. - if not config.modifications.capenabled then - config.capenabled = grabCapenabled(config.capabilities_conf, - config.modifications.capabilities_conf == nil) - elseif config.capenabled ~= "" then - -- We have a comma separated list from the format of - -- capabilities.conf, split it into a set with boolean values - -- for each key. - config.capenabled = util.setFromString(config.capenabled, - "[^,]+") - end -end - return config diff --git a/sys/tools/syscalls/core/syscall.lua b/sys/tools/syscalls/core/syscall.lua index 7e8c562dad8a..402595b998da 100644 --- a/sys/tools/syscalls/core/syscall.lua +++ b/sys/tools/syscalls/core/syscall.lua @@ -1,497 +1,492 @@ -- -- SPDX-License-Identifier: BSD-2-Clause -- -- Copyright (c) 2024 Tyler Baxter -- Copyright (c) 2023 Warner Losh -- Copyright (c) 2019 Kyle Evans -- local config = require("config") local scarg = require("core.scarg") local scret = require("core.scret") local util = require("tools.util") local syscall = {} syscall.__index = syscall syscall.known_flags = util.set { "STD", "OBSOL", "RESERVED", "UNIMPL", "NODEF", "NOARGS", "NOPROTO", "NOSTD", "NOTSTATIC", "CAPENABLED", "SYSMUX", } -- Native is an arbitrarily large number to have a constant and not -- interfere with compat numbers. local native = 1000000 -- Processes and assigns the appropriate thread flag for this system call. function syscall:processThr() self.thr = "SY_THR_STATIC" for k, _ in pairs(self.type) do if k == "NOTSTATIC" then self.thr = "SY_THR_ABSENT" end end end -- Processes and assigns the appropriate capability flag for this system call. -- "SYF_CAPENABLED" for capability enabled; "0" for NOT capability enabled. function syscall:processCap() self.cap = "0" local stripped = util.stripAbiPrefix(self.name, self.prefix) - if config.capenabled ~= nil and (config.capenabled[self.name] ~= nil or - config.capenabled[stripped] ~= nil) then - self.cap = "SYF_CAPENABLED" - else - for k, _ in pairs(self.type) do - if k == "CAPENABLED" then - self.cap = "SYF_CAPENABLED" - end + for k, _ in pairs(self.type) do + if k == "CAPENABLED" then + self.cap = "SYF_CAPENABLED" end end end -- Check that this system call has a known type. local function checkType(type) for k, _ in pairs(type) do if not syscall.known_flags[k] and not k:match("^COMPAT") then util.abort(1, "Bad type: " .. k) end end end -- If there are ABI changes from native, process this system call to match the -- target ABI. function syscall:processChangesAbi() -- First, confirm we want to uphold our changes_abi flag. if config.syscall_no_abi_change[self.name] then self.changes_abi = false end self.noproto = not util.isEmpty(config.abi_flags) and not self.changes_abi if config.abiChanges("pointer_args") then for _, v in ipairs(self.args) do if util.isPtrType(v.type, config.abi_intptr_t) then if config.syscall_no_abi_change[self.name] then print("WARNING: " .. self.name .. " in syscall_no_abi_change, " .. "but pointers args are present") end self.changes_abi = true goto ptrfound end end ::ptrfound:: end if config.syscall_abi_change[self.name] then self.changes_abi = true end if self.changes_abi then self.noproto = false end end -- Final processing of flags. Process any flags that haven't already been -- processed (e.g., dictionaries from syscalls.conf). function syscall:processFlags() if config.obsol[self.name] or (self:compatLevel() > 0 and self:compatLevel() < tonumber(config.mincompat)) then self.args = nil self.type.OBSOL = true -- Don't apply any ABI handling, declared as obsolete. self.changes_abi = false end if config.unimpl[self.name] then self.type.UNIMPL = true end if self.noproto or self.type.SYSMUX then self.type.NOPROTO = true end if self.type.NODEF then self.audit = "AUE_NULL" end end -- Returns TRUE if prefix and arg_prefix are assigned; FALSE if they're left -- unassigned. Relies on a valid changes_abi flag, so should be called AFTER -- processChangesAbi(). function syscall:processPrefix() -- If there are ABI changes from native, assign the correct prefixes. if self.changes_abi then self.arg_prefix = config.abi_func_prefix self.prefix = config.abi_func_prefix return true end return false end -- Validate that we're not skipping system calls by comparing this system call -- number to the previous system call number. Called higher up the call stack -- by class FreeBSDSyscall. function syscall:validate(prev) return prev + 1 == self.num end -- Return the compat prefix for this system call. function syscall:compatPrefix() local c = self:compatLevel() if self.type.OBSOL then return "obs_" end if self.type.RESERVED then return "reserved #" end if self.type.UNIMPL then return "unimp_" end if c == 3 then return "o" end if c < native then return "freebsd" .. tostring(c) .. "_" end return "" end -- Return the symbol name for this system call. function syscall:symbol() return self:compatPrefix() .. self.name end -- -- Return the compatibility level for this system call. -- 0 is obsolete. -- < 0 is this isn't really a system call we care about. -- 3 is 4.3BSD in theory, but anything before FreeBSD 4. -- >= 4 is FreeBSD version, this system call was replaced with a new -- version. -- function syscall:compatLevel() if self.type.UNIMPL or self.type.RESERVED then return -1 elseif self.type.OBSOL then return 0 elseif self.type.COMPAT then return 3 end for k, _ in pairs(self.type) do local l = k:match("^COMPAT(%d+)") if l ~= nil then return tonumber(l) end end return native end -- Adds the definition for this system call. Guarded by whether we already have -- a system call number or not. function syscall:addDef(line) if self.num == nil then local words = util.split(line, "%S+") self.num = words[1] self.audit = words[2] self.type = util.setFromString(words[3], "[^|]+") checkType(self.type) self.name = words[4] -- These next three are optional, and either all present -- or all absent. self.altname = words[5] self.alttag = words[6] self.rettype = words[7] return true end return false end -- Adds the function declaration for this system call. If addDef() found an -- opening curly brace, then we're looking for a function declaration. function syscall:addFunc(line) if self.name == "{" then local words = util.split(line, "%S+") -- Expect line is `type syscall(` or `type syscall(void);`. if #words ~= 2 then util.abort(1, "Malformed line " .. line) end local ret = scret:new({}, line) self.ret = ret:add() -- Don't clobber rettype set in the alt information. if self.rettype == nil then self.rettype = "int" end self.name = words[2]:match("([%w_]+)%(") if words[2]:match("%);$") then -- Now we're looking for ending curly brace. self.expect_rbrace = true end return true end return false end -- Adds the argument(s) for this system call. Once addFunc() assigns a name -- for this system call, arguments are next in syscalls.master. function syscall:addArgs(line) if not self.expect_rbrace then if line:match("%);$") then self.expect_rbrace = true return true end local arg = scarg:new({}, line) -- We don't want to add this argument if it doesn't process. -- scarg:process() handles those conditions. if arg:process() then arg:append(self.args) end -- If this argument has ABI changes, set globally for this -- system call. self.changes_abi = self.changes_abi or arg:changesAbi() return true end return false end -- Once we have a good syscall, add some final information to it. function syscall:finalize() if self.name == nil then self.name = "" end -- Preserve the original name as the alias. self.alias = self.name self:processChangesAbi() -- process changes to the ABI self:processFlags() -- process any unprocessed flags -- If there's changes to the ABI, these prefixes will be changed by -- processPrefix(); otherwise, they'll remain empty. self.prefix = "" self.arg_prefix = "" self:processPrefix() self:processCap() -- capability flag self:processThr() -- thread flag -- Assign argument alias. if self.alttag ~= nil then self.arg_alias = self.alttag elseif self.arg_alias == nil and self.name ~= nil then -- argalias should be: -- COMPAT_PREFIX + ABI Prefix + funcname self.arg_alias = self:compatPrefix() .. self.arg_prefix .. self.name .. "_args" elseif self.arg_alias ~= nil then self.arg_alias = self.arg_prefix .. self.arg_alias end -- An empty string would not want a prefix; the entry doesn't have -- a name so we want to keep the empty string. if self.name ~= nil and self.name ~= "" then self.name = self.prefix .. self.name end self:processArgstrings() self:processArgsize() end -- Assigns the correct args_size. Defaults to "0", except if there's arguments -- or NODEF flag. function syscall:processArgsize() if self.type.SYSMUX then -- catch this first self.args_size = "0" elseif self.arg_alias ~= nil and (#self.args ~= 0 or self.type.NODEF) then self.args_size = "AS(" .. self.arg_alias .. ")" else self.args_size = "0" end end -- Constructs argstr_* strings for generated declerations/wrappers. function syscall:processArgstrings() local type = "" local type_var = "" local var = "" local comma = "" for _, v in ipairs(self.args) do local argname, argtype = v.name, v.type type = type .. comma .. argtype type_var = type_var .. comma .. argtype .. " " .. argname var = var .. comma .. argname comma = ", " end if type == "" then type = "void" type_var = "void" end self.argstr_type = type self.argstr_type_var = type_var self.argstr_var = var end -- Interface to add this system call to the master system call table. -- The system call is built up one line at a time. The states describe the -- current parsing state. -- Returns TRUE when ready to add and FALSE while still parsing. function syscall:add(line) if self:addDef(line) then return self:isAdded(line) end if self:addFunc(line) then return false -- Function added; keep going. end if self:addArgs(line) then return false -- Arguments added; keep going. end return self:isAdded(line) -- Final validation, before adding. end -- Returns TRUE if this system call was succesfully added. There's two entry -- points to this function: (1) the entry in syscalls.master is one-line, or -- (2) the entry is a full system call. This function handles those cases and -- decides whether to exit early for (1) or validate a full system call for -- (2). This function also handles cases where we don't want to add, and -- instead want to abort. function syscall:isAdded(line) -- This system call is a range - exit early. if tonumber(self.num) == nil then -- The only allowed types are RESERVED and UNIMPL. if not (self.type.RESERVED or self.type.UNIMPL) then util.abort(1, "Range only allowed with RESERVED " .. "and UNIMPL: " .. line) end self:finalize() return true -- This system call is a loadable system call - exit early. elseif self.altname ~= nil and self.alttag ~= nil and self.rettype ~= nil then self:finalize() return true -- This system call is only one line, and should only be one line -- (we didn't make it to addFunc()) - exit early. elseif self.name ~= "{" and self.ret == nil then self:finalize() return true -- This is a full system call and we've passed multiple states to -- get here - final exit. elseif self.expect_rbrace then if not line:match("}$") then util.abort(1, "Expected '}' found '" .. line .. "' instead.") end self:finalize() return true end return false end -- Return TRUE if this system call is native. function syscall:native() return self:compatLevel() == native end -- Make a shallow copy of `self` and replace the system call number with num -- (which should be a number). -- For system call ranges. function syscall:shallowCopy(num) local obj = syscall:new() -- shallow copy for k, v in pairs(self) do obj[k] = v end obj.num = num -- except override range return obj end -- Make a deep copy of the parameter object. Save copied tables in `copies`, -- indexed by original table. -- CREDIT: http://lua-users.org/wiki/CopyTable -- For a full system call (the nested arguments table should be a deep copy). local function deepCopy(orig, copies) copies = copies or {} local orig_type = type(orig) local copy if orig_type == 'table' then if copies[orig] then copy = copies[orig] else copy = {} copies[orig] = copy for orig_key, orig_value in next, orig, nil do copy[deepCopy(orig_key, copies)] = deepCopy(orig_value, copies) end setmetatable(copy, deepCopy(getmetatable(orig), copies)) end else -- number, string, boolean, etc copy = orig end return copy end -- -- In syscalls.master, system calls come in two types: (1) a fully defined -- system call with function declaration, with a distinct number for each system -- call; or (2) a one-line entry, sometimes with a distinct number and sometimes -- with a range of numbers. One-line entries can be obsolete, reserved, no -- definition, etc. Ranges are only allowed for reserved and unimplemented. -- -- This function provides the iterator to traverse system calls by number. If -- the entry is a fully defined system call with a distinct number, the iterator -- creates a deep copy and captures any nested objects; if the entry is a range -- of numbers, the iterator creates shallow copies from the start of the range -- to the end of the range. -- function syscall:iter() local s = tonumber(self.num) local e if s == nil then s, e = string.match(self.num, "(%d+)%-(%d+)") s, e = tonumber(s), tonumber(e) return function () if s <= e then s = s + 1 return self:shallowCopy(s - 1) end end else e = s self.num = s -- Replace string with number, like the clones. return function () if s == e then local deep_copy = deepCopy(self) s = e + 1 return deep_copy end end end end function syscall:new(obj) obj = obj or { } setmetatable(obj, self) self.__index = self self.expect_rbrace = false self.changes_abi = false self.args = {} self.noproto = false return obj end return syscall diff --git a/sys/tools/syscalls/main.lua b/sys/tools/syscalls/main.lua index 8f791eec0943..b15eec095f9c 100755 --- a/sys/tools/syscalls/main.lua +++ b/sys/tools/syscalls/main.lua @@ -1,64 +1,63 @@ #!/usr/libexec/flua -- -- SPDX-License-Identifier: BSD-2-Clause -- -- Copyright (c) 2024 Tyler Baxter -- Copyright (c) 2023 Warner Losh -- Copyright (c) 2019 Kyle Evans -- -- Thanks to Kyle Evans for his makesyscall.lua in FreeBSD which served as -- inspiration for this, and as a source of code at times. -- -- When we have a path, add it to the package.path (. is already in the list). if arg[0]:match("/") then local path = arg[0]:gsub("/[^/]+.lua$", "") package.path = package.path .. ";" .. path .. "/?.lua" end -- Common config file management. local config = require("config") -- FreeBSDSyscall generates a table of system calls from syscalls.master. local FreeBSDSyscall = require("core.freebsd-syscall") -- Modules for each file: local init_sysent = require("scripts.init_sysent") local libsys_h = require("scripts.libsys_h") local syscall_h = require("scripts.syscall_h") local syscall_mk = require("scripts.syscall_mk") local syscalls = require("scripts.syscalls") local syscalls_map = require("scripts.syscalls_map") local sysproto_h = require("scripts.sysproto_h") local systrace_args = require("scripts.systrace_args") -- Entry: if #arg < 1 or #arg > 2 then error("usage: " .. arg[0] .. " syscall.master") end local sysfile, configfile = arg[1], arg[2] config.merge(configfile) config.mergeCompat() -config.mergeCapability() local tbl = FreeBSDSyscall:new{sysfile = sysfile, config = config} -- Output files: init_sysent.file = config.syssw libsys_h.file = config.libsys_h syscall_h.file = config.syshdr syscall_mk.file = config.sysmk syscalls.file = config.sysnames syscalls_map.file = config.libsysmap sysproto_h.file = config.sysproto systrace_args.file = config.systrace init_sysent.generate(tbl, config, init_sysent.file) libsys_h.generate(tbl, config, libsys_h.file) syscall_h.generate(tbl, config, syscall_h.file) syscall_mk.generate(tbl, config, syscall_mk.file) syscalls.generate(tbl, config, syscalls.file) syscalls_map.generate(tbl, config, syscalls_map.file) sysproto_h.generate(tbl, config, sysproto_h.file) systrace_args.generate(tbl, config, systrace_args.file) diff --git a/sys/tools/syscalls/scripts/init_sysent.lua b/sys/tools/syscalls/scripts/init_sysent.lua index 106c51be5f8a..66683250b482 100755 --- a/sys/tools/syscalls/scripts/init_sysent.lua +++ b/sys/tools/syscalls/scripts/init_sysent.lua @@ -1,193 +1,192 @@ #!/usr/libexec/flua -- -- SPDX-License-Identifier: BSD-2-Clause -- -- Copyright (c) 2024 Tyler Baxter -- Copyright (c) 2023 Warner Losh -- Copyright (c) 2019 Kyle Evans -- -- Setup to be a module, or ran as its own script. local init_sysent = {} local script = not pcall(debug.getlocal, 4, 1) -- TRUE if script. if script then -- Add library root to the package path. local path = arg[0]:gsub("/[^/]+.lua$", "") package.path = package.path .. ";" .. path .. "/../?.lua" end local FreeBSDSyscall = require("core.freebsd-syscall") local generator = require("tools.generator") -- File has not been decided yet; config will decide file. Default defined as -- /dev/null. init_sysent.file = "/dev/null" function init_sysent.generate(tbl, config, fh) -- Grab the master system calls table. local s = tbl.syscalls -- Bind the generator to the parameter file. local gen = generator:new({}, fh) -- Write the generated preamble. gen:preamble("System call switch table.") gen:write(tbl.includes) -- Newline before and after this line. gen:write( "\n#define AS(name) (sizeof(struct name) / sizeof(syscallarg_t))\n") -- Write out all the compat directives from compat_options. for _, v in pairs(config.compat_options) do gen:write(string.format([[ #ifdef %s #define %s(n, name) .sy_narg = n, .sy_call = (sy_call_t *)__CONCAT(%s, name) #else #define %s(n, name) .sy_narg = 0, .sy_call = (sy_call_t *)nosys #endif ]], v.definition, v.flag:lower(), v.prefix, v.flag:lower())) end -- Add a newline only if there were compat_options. if config.compat_options ~= nil then gen:write("\n") end gen:write(string.format([[ /* The casts are bogus but will do for now. */ struct sysent %s[] = { ]], config.switchname)) for _, v in pairs(s) do local c = v:compatLevel() -- Comment is the function name by default, but may change -- based on the type of system call. local comment = v.name -- Handle non-compat: if v:native() then gen:write(string.format( "\t{ .sy_narg = %s, .sy_call = (sy_call_t *)", v.args_size)) -- Handle SYSMUX flag: if v.type.SYSMUX then gen:write(string.format("nosys, " .. ".sy_auevent = AUE_NULL, " .. ".sy_flags = %s, " .. ".sy_thrcnt = SY_THR_STATIC },", v.cap)) -- Handle NOSTD flag: elseif v.type.NOSTD then gen:write(string.format("lkmressys, " .. ".sy_auevent = AUE_NULL, " .. ".sy_flags = %s, " .. ".sy_thrcnt = SY_THR_ABSENT },", v.cap)) -- Handle rest of non-compat: else if v.name == "nosys" or v.name == "lkmnosys" or v.name == "sysarch" or v.name:find("^freebsd") or v.name:find("^linux") then gen:write(string.format("%s, " .. ".sy_auevent = %s, " .. ".sy_flags = %s, " .. ".sy_thrcnt = %s },", v:symbol(), v.audit, v.cap, v.thr)) else gen:write(string.format("sys_%s, " .. ".sy_auevent = %s, " .. ".sy_flags = %s, " .. ".sy_thrcnt = %s },", v:symbol(), v.audit, v.cap, v.thr)) end end -- Handle compat (everything >= FREEBSD3): elseif c >= 3 then -- Lookup the info for this specific compat option. local flag, descr for _, opt in pairs(config.compat_options) do if opt.compatlevel == c then flag = opt.flag flag = flag:lower() descr = opt.descr break end end if v.type.NOSTD then gen:write(string.format("\t{ " .. ".sy_narg = %s, " .. ".sy_call = (sy_call_t *)%s, " .. ".sy_auevent = %s, " .. ".sy_flags = 0, " .. ".sy_thrcnt = SY_THR_ABSENT },", "0", "lkmressys", "AUE_NULL")) else gen:write(string.format("\t{ %s(%s,%s), " .. ".sy_auevent = %s, " .. ".sy_flags = %s, " .. ".sy_thrcnt = %s },", flag, v.args_size, v.name, v.audit, v.cap, v.thr)) end comment = descr .. " " .. v.name -- Handle obsolete: elseif v.type.OBSOL then gen:write("\t{ " .. ".sy_narg = 0, .sy_call = (sy_call_t *)nosys, " .. ".sy_auevent = AUE_NULL, .sy_flags = 0, " .. ".sy_thrcnt = SY_THR_ABSENT },") comment = "obsolete " .. v.name -- Handle unimplemented: elseif v.type.UNIMPL then gen:write("\t{ " .. ".sy_narg = 0, .sy_call = (sy_call_t *)nosys, " .. ".sy_auevent = AUE_NULL, .sy_flags = 0, " .. ".sy_thrcnt = SY_THR_ABSENT },") -- UNIMPL comment is not different in sysent. -- Handle reserved: elseif v.type.RESERVED then gen:write("\t{ " .. ".sy_narg = 0, .sy_call = (sy_call_t *)nosys, " .. ".sy_auevent = AUE_NULL, .sy_flags = 0, " .. ".sy_thrcnt = SY_THR_ABSENT },") comment = "reserved for local use" end gen:write(string.format("\t/* %d = %s */\n", v.num, comment)) end -- End gen:write("};\n") end -- Entry of script: if script then local config = require("config") if #arg < 1 or #arg > 2 then error("usage: " .. arg[0] .. " syscall.master") end local sysfile, configfile = arg[1], arg[2] config.merge(configfile) config.mergeCompat() - config.mergeCapability() -- The parsed syscall table. local tbl = FreeBSDSyscall:new{sysfile = sysfile, config = config} init_sysent.file = config.syssw -- change file here init_sysent.generate(tbl, config, init_sysent.file) end -- Return the module. return init_sysent diff --git a/sys/tools/syscalls/scripts/libsys_h.lua b/sys/tools/syscalls/scripts/libsys_h.lua index 18ffc68fded6..75627f08750f 100755 --- a/sys/tools/syscalls/scripts/libsys_h.lua +++ b/sys/tools/syscalls/scripts/libsys_h.lua @@ -1,111 +1,110 @@ #!/usr/libexec/flua -- -- SPDX-License-Identifier: BSD-2-Clause -- -- Copyright (c) 2024 SRI International -- Copyright (c) 2024 Tyler Baxter -- Copyright (c) 2023 Warner Losh -- Copyright (c) 2019 Kyle Evans -- -- Setup to be a module, or ran as its own script. local libsys_h = {} local script = not pcall(debug.getlocal, 4, 1) -- TRUE if script. if script then -- Add library root to the package path. local path = arg[0]:gsub("/[^/]+.lua$", "") package.path = package.path .. ";" .. path .. "/../?.lua" end local FreeBSDSyscall = require("core.freebsd-syscall") local generator = require("tools.generator") local util = require("tools.util") -- File has not been decided yet; config will decide file. Default defined as -- /dev/null. libsys_h.file = "/dev/null" function libsys_h.generate(tbl, config, fh) -- Grab the master system calls table. local s = tbl.syscalls local print_decl = function (sc) return sc:native() and not sc.type.NODEF and not sc.type.SYSMUX and sc.name ~= "yield" end -- Bind the generator to the parameter file. local gen = generator:new({}, fh) -- Write the generated preamble. gen:preamble("Public system call stubs provided by libsys.\n" .. "\n" .. "Do not use directly, include instead.") gen:write(string.format([[ #ifndef __LIBSYS_H_ #define __LIBSYS_H_ #include #include #include #include #include #include /* for mcontext_t */ #include #include ]])) for name, _ in util.pairsByKeys(tbl.structs) do gen:write(string.format("struct %s;\n", name)) end gen:write("union semun;\n") gen:write("\n__BEGIN_DECLS\n") for _, v in pairs(s) do if print_decl(v) then gen:write(string.format( "typedef %s (__sys_%s_t)(%s);\n", v.ret, v.name, v.argstr_type)) end end gen:write("\n") for _, v in pairs(s) do if print_decl(v) then gen:write(string.format("%s __sys_%s(%s);\n", v.ret, v.name, v.argstr_type_var)) end end gen:write("__END_DECLS\n") -- End gen:write("\n#endif /* __LIBSYS_H_ */\n") end -- Entry of script: if script then local config = require("config") if #arg < 1 or #arg > 2 then error("usage: " .. arg[0] .. " syscall.master") end local sysfile, configfile = arg[1], arg[2] config.merge(configfile) config.mergeCompat() - config.mergeCapability() -- The parsed syscall table. local tbl = FreeBSDSyscall:new{sysfile = sysfile, config = config} libsys_h.file = config.libsys_h -- change file here libsys_h.generate(tbl, config, libsys_h.file) end -- Return the module. return libsys_h diff --git a/sys/tools/syscalls/scripts/syscall_h.lua b/sys/tools/syscalls/scripts/syscall_h.lua index ce5ffcec4b94..5f8d8fb66889 100755 --- a/sys/tools/syscalls/scripts/syscall_h.lua +++ b/sys/tools/syscalls/scripts/syscall_h.lua @@ -1,97 +1,96 @@ #!/usr/libexec/flua -- -- SPDX-License-Identifier: BSD-2-Clause -- -- Copyright (c) 2024 Tyler Baxter -- Copyright (c) 2023 Warner Losh -- Copyright (c) 2019 Kyle Evans -- -- Setup to be a module, or ran as its own script. local syscall_h = {} local script = not pcall(debug.getlocal, 4, 1) -- TRUE if script. if script then -- Add library root to the package path. local path = arg[0]:gsub("/[^/]+.lua$", "") package.path = package.path .. ";" .. path .. "/../?.lua" end local FreeBSDSyscall = require("core.freebsd-syscall") local generator = require("tools.generator") -- File has not been decided yet; config will decide file. Default defined as -- /dev/null. syscall_h.file = "/dev/null" -- Libc has all the STD, NOSTD and SYSMUX system calls in it, as well as -- replaced system calls dating back to FreeBSD 7. We are lucky that the -- system call filename is just the base symbol name for it. function syscall_h.generate(tbl, config, fh) -- Grab the master system calls table, and prepare bookkeeping for -- the max system call number. local s = tbl.syscalls local max = 0 -- Bind the generator to the parameter file. local gen = generator:new({}, fh) -- Write the generated preamble. gen:preamble("System call numbers.") for _, v in pairs(s) do local c = v:compatLevel() if v.num > max then max = v.num end if v.type.UNIMPL then goto skip elseif v.type.RESERVED then goto skip elseif v.type.NODEF then goto skip elseif v.type.STD or v.type.NOSTD or v.type.SYSMUX or c >= 7 then gen:write(string.format("#define\t%s%s%s\t%d\n", config.syscallprefix, v:compatPrefix(), v.name, v.num)) elseif c >= 0 then local comment if c == 0 then comment = "obsolete" elseif c == 3 then comment = "old" else comment = "freebsd" .. c end gen:write(string.format("\t\t\t\t/* %d is %s %s */\n", v.num, comment, v.name)) end ::skip:: end gen:write(string.format("#define\t%sMAXSYSCALL\t%d\n", config.syscallprefix, max + 1)) end -- Entry of script: if script then local config = require("config") if #arg < 1 or #arg > 2 then error("usage: " .. arg[0] .. " syscall.master") end local sysfile, configfile = arg[1], arg[2] config.merge(configfile) config.mergeCompat() - config.mergeCapability() -- The parsed system call table. local tbl = FreeBSDSyscall:new{sysfile = sysfile, config = config} syscall_h.file = config.syshdr -- change file here syscall_h.generate(tbl, config, syscall_h.file) end -- Return the module. return syscall_h diff --git a/sys/tools/syscalls/scripts/syscall_mk.lua b/sys/tools/syscalls/scripts/syscall_mk.lua index d4347a050cf1..68438ee8d90c 100755 --- a/sys/tools/syscalls/scripts/syscall_mk.lua +++ b/sys/tools/syscalls/scripts/syscall_mk.lua @@ -1,90 +1,89 @@ #!/usr/libexec/flua -- -- SPDX-License-Identifier: BSD-2-Clause -- -- Copyright (c) 2024 Tyler Baxter -- Copyright (c) 2023 Warner Losh -- Copyright (c) 2019 Kyle Evans -- -- Setup to be a module, or ran as its own script. local syscall_mk = {} local script = not pcall(debug.getlocal, 4, 1) -- TRUE if script. if script then -- Add library root to the package path. local path = arg[0]:gsub("/[^/]+.lua$", "") package.path = package.path .. ";" .. path .. "/../?.lua" end local FreeBSDSyscall = require("core.freebsd-syscall") local generator = require("tools.generator") -- File has not been decided yet; config will decide file. Default defined as -- /dev/null. syscall_mk.file = "/dev/null" -- Libc has all the STD, NOSTD and SYSMUX system calls in it, as well as -- replaced system calls dating back to FreeBSD 7. We are lucky that the -- system call filename is just the base symbol name for it. function syscall_mk.generate(tbl, config, fh) -- Grab the master system calls table. local s = tbl.syscalls -- Bookkeeping for keeping track of when we're at the last system -- call (no backslash). local size = #s local idx = 0 -- Bind the generator to the parameter file. local gen = generator:new({}, fh) -- Write the generated preamble. gen:preamble("FreeBSD system call object files.", "#") gen:write("MIASM = \\\n") -- preamble for _, v in pairs(s) do local c = v:compatLevel() idx = idx + 1 if v:native() and not v.type.NODEF then if idx >= size then -- At last system call, no backslash. gen:write(string.format("\t%s.o\n", v:symbol())) else -- Normal behavior. gen:write(string.format("\t%s.o \\\n", v:symbol())) end -- Handle compat (everything >= FREEBSD3): elseif c >= 7 and not v.type.NODEF then if idx >= size then -- At last system call, no backslash. gen:write(string.format("\t%s.o\n", v:symbol())) else -- Normal behavior. gen:write(string.format("\t%s.o \\\n", v:symbol())) end end end end -- Entry of script: if script then local config = require("config") if #arg < 1 or #arg > 2 then error("usage: " .. arg[0] .. " syscall.master") end local sysfile, configfile = arg[1], arg[2] config.merge(configfile) config.mergeCompat() - config.mergeCapability() -- The parsed syscall table. local tbl = FreeBSDSyscall:new{sysfile = sysfile, config = config} syscall_mk.file = config.sysmk -- change file here syscall_mk.generate(tbl, config, syscall_mk.file) end -- Return the module. return syscall_mk diff --git a/sys/tools/syscalls/scripts/syscalls.lua b/sys/tools/syscalls/scripts/syscalls.lua index b1a3d1020f88..38ed396a73ae 100755 --- a/sys/tools/syscalls/scripts/syscalls.lua +++ b/sys/tools/syscalls/scripts/syscalls.lua @@ -1,109 +1,108 @@ #!/usr/libexec/flua -- -- SPDX-License-Identifier: BSD-2-Clause -- -- Copyright (c) 2024 Tyler Baxter -- Copyright (c) 2023 Warner Losh -- Copyright (c) 2019 Kyle Evans -- -- Setup to be a module, or ran as its own script. local syscalls = {} local script = not pcall(debug.getlocal, 4, 1) -- TRUE if script. if script then -- Add library root to the package path. local path = arg[0]:gsub("/[^/]+.lua$", "") package.path = package.path .. ";" .. path .. "/../?.lua" end local FreeBSDSyscall = require("core.freebsd-syscall") local generator = require("tools.generator") -- File has not been decided yet; config will decide file. Default defined as -- /dev/null. syscalls.file = "/dev/null" function syscalls.generate(tbl, config, fh) -- Grab the master system calls table. local s = tbl.syscalls -- Bind the generator to the parameter file. local gen = generator:new({}, fh) -- Write the generated preamble. gen:preamble("System call names.") gen:write(string.format("const char *%s[] = {\n", config.namesname)) for _, v in pairs(s) do --print("num " .. v.num .. " name " .. v.name) local c = v:compatLevel() if v:native() then gen:write(string.format([[ "%s", /* %d = %s */ ]], v.name, v.num, v.name)) elseif c >= 3 then -- Lookup the info for this specific compat option. local flag, descr for _, opt in pairs(config.compat_options) do if opt.compatlevel == c then flag = opt.flag flag = flag:lower() descr = opt.descr break end end gen:write(string.format([[ "%s.%s", /* %d = %s %s */ ]], flag, v.name, v.num, descr, v.name)) elseif v.type.RESERVED then gen:write(string.format([[ "#%d", /* %d = reserved for local use */ ]], v.num, v.num)) elseif v.type.UNIMPL then gen:write(string.format([[ "#%d", /* %d = %s */ ]], v.num, v.num, v.alias)) elseif v.type.OBSOL then gen:write(string.format([[ "obs_%s", /* %d = obsolete %s */ ]], v.name, v.num, v.name)) end end -- End gen:write("};\n") end -- Entry of script: if script then local config = require("config") if #arg < 1 or #arg > 2 then error("usage: " .. arg[0] .. " syscall.master") end local sysfile, configfile = arg[1], arg[2] config.merge(configfile) config.mergeCompat() - config.mergeCapability() -- The parsed syscall table. local tbl = FreeBSDSyscall:new{sysfile = sysfile, config = config} syscalls.file = config.sysnames -- change file here syscalls.generate(tbl, config, syscalls.file) end -- Return the module. return syscalls diff --git a/sys/tools/syscalls/scripts/syscalls_map.lua b/sys/tools/syscalls/scripts/syscalls_map.lua index 4108d9f46fcf..57bb5e9da93b 100755 --- a/sys/tools/syscalls/scripts/syscalls_map.lua +++ b/sys/tools/syscalls/scripts/syscalls_map.lua @@ -1,74 +1,73 @@ #!/usr/libexec/flua -- -- SPDX-License-Identifier: BSD-2-Clause -- -- Copyright (c) 2024 SRI International -- Copyright (c) 2024 Tyler Baxter -- Copyright (c) 2023 Warner Losh -- Copyright (c) 2019 Kyle Evans -- -- Setup to be a module, or ran as its own script. local syscalls_map = {} local script = not pcall(debug.getlocal, 4, 1) -- TRUE if script. if script then -- Add library root to the package path. local path = arg[0]:gsub("/[^/]+.lua$", "") package.path = package.path .. ";" .. path .. "/../?.lua" end local FreeBSDSyscall = require("core.freebsd-syscall") local generator = require("tools.generator") -- File has not been decided yet; config will decide file. Default defined as -- /dev/null. syscalls_map.file = "/dev/null" function syscalls_map.generate(tbl, config, fh) -- Grab the master system calls table. local s = tbl.syscalls -- Bind the generator to the parameter file. local gen = generator:new({}, fh) -- Write the generated preamble. gen:preamble("FreeBSD system call symbols.") gen:write(string.format("FBSDprivate_1.0 {\n")) for _, v in pairs(s) do --print("num " .. v.num .. " name " .. v.name) if v:native() and not v.type.NODEF and v.name ~= "yield" then if v.name ~= "exit" and v.name ~= "vfork" then gen:write(string.format("\t_%s;\n", v.name)) end gen:write(string.format("\t__sys_%s;\n", v.name)) end end -- End gen:write("};\n") end -- Entry of script: if script then local config = require("config") if #arg < 1 or #arg > 2 then error("usage: " .. arg[0] .. " syscall.master") end local sysfile, configfile = arg[1], arg[2] config.merge(configfile) config.mergeCompat() - config.mergeCapability() -- The parsed syscall table. local tbl = FreeBSDSyscall:new{sysfile = sysfile, config = config} syscalls_map.file = config.libsysmap -- change file here syscalls_map.generate(tbl, config, syscalls_map.file) end -- Return the module. return syscalls_map diff --git a/sys/tools/syscalls/scripts/sysproto_h.lua b/sys/tools/syscalls/scripts/sysproto_h.lua index d4fc30c31292..6770e0548899 100755 --- a/sys/tools/syscalls/scripts/sysproto_h.lua +++ b/sys/tools/syscalls/scripts/sysproto_h.lua @@ -1,242 +1,241 @@ #!/usr/libexec/flua -- -- SPDX-License-Identifier: BSD-2-Clause -- -- Copyright (c) 2024 Tyler Baxter -- Copyright (c) 2019 Kyle Evans -- -- Setup to be a module, or ran as its own script. local sysproto_h = {} local script = not pcall(debug.getlocal, 4, 1) -- TRUE if script. if script then -- Add library root to the package path. local path = arg[0]:gsub("/[^/]+.lua$", "") package.path = package.path .. ";" .. path .. "/../?.lua" end local FreeBSDSyscall = require("core.freebsd-syscall") local generator = require("tools.generator") -- File has not been decided yet; config will decide file. Default defined as -- /dev/null. sysproto_h.file = "/dev/null" function sysproto_h.generate(tbl, config, fh) -- Grab the master system calls table. local s = tbl.syscalls -- Bind the generator to the parameter file. local gen = generator:new({}, fh) gen.storage_levels = {} -- make sure storage is clear -- Write the generated preamble. gen:preamble("System call prototypes.") -- Write out all the preprocessor directives. gen:write(string.format([[ #ifndef %s #define %s #include #include #include #include #include #include #include #include #include struct proc; struct thread; #define PAD_(t) (sizeof(syscallarg_t) <= sizeof(t) ? \ 0 : sizeof(syscallarg_t) - sizeof(t)) #if BYTE_ORDER == LITTLE_ENDIAN #define PADL_(t) 0 #define PADR_(t) PAD_(t) #else #define PADL_(t) PAD_(t) #define PADR_(t) 0 #endif ]], config.sysproto_h, config.sysproto_h)) -- 64-bit padding preprocessor directive. gen:pad64(config.abiChanges("pair_64bit")) -- -- Storing each compat entry requires storing multiple levels of file -- generation; compat entries are given ranges of 10 instead to cope -- with this. For example, 13 is indexed as 130; 131 is the second -- storage level of 13. -- -- Store all the compat #ifdef from compat_options at their zero index. for _, v in pairs(config.compat_options) do -- Tag an extra newline to the end, so it doesn't have to be -- worried about later. gen:store(string.format("\n#ifdef %s\n\n", v.definition), v.compatlevel * 10) end for _, v in pairs(s) do local c = v:compatLevel() -- Audit defines are stored at an arbitrarily large number so -- that they're always at the last storage level, and compat -- entries can be indexed by their compat level (more -- intuitive). local audit_idx = 10000 -- this should do -- Handle non-compat: if v:native() then -- All these negation conditions are because (in -- general) these are cases where code for sysproto.h -- is not generated. if not v.type.NOARGS and not v.type.NOPROTO and not v.type.NODEF then if #v.args > 0 then gen:write(string.format( "struct %s {\n", v.arg_alias)) for _, arg in ipairs(v.args) do if arg.type == "int" and arg.name == "_pad" and config.abiChanges( "pair_64bit") then gen:write("#ifdef PAD64_REQUIRED\n") end gen:write(string.format([[ char %s_l_[PADL_(%s)]; %s %s; char %s_r_[PADR_(%s)]; ]], arg.name, arg.type, arg.type, arg.name, arg.name, arg.type)) if arg.type == "int" and arg.name == "_pad" and config.abiChanges( "pair_64bit") then gen:write("#endif\n") end end gen:write("};\n") else gen:write(string.format( "struct %s {\n\tsyscallarg_t dummy;\n};\n", v.arg_alias)) end end if not v.type.NOPROTO and not v.type.NODEF then local sys_prefix = "sys_" if v.name == "nosys" or v.name == "lkmnosys" or v.name == "sysarch" or v.name:find("^freebsd") or v.name:find("^linux") then sys_prefix = "" end gen:store(string.format( "%s\t%s%s(struct thread *, struct %s *);\n", v.rettype, sys_prefix, v.name, v.arg_alias), 1) gen:store(string.format( "#define\t%sAUE_%s\t%s\n", config.syscallprefix, v:symbol(), v.audit), audit_idx) end -- Handle compat (everything >= FREEBSD3): elseif c >= 3 then local idx = c * 10 if not v.type.NOARGS and not v.type.NOPROTO and not v.type.NODEF then if #v.args > 0 then gen:store(string.format( "struct %s {\n", v.arg_alias), idx) for _, arg in ipairs(v.args) do gen:store(string.format([[ char %s_l_[PADL_(%s)]; %s %s; char %s_r_[PADR_(%s)]; ]], arg.name, arg.type, arg.type, arg.name, arg.name, arg.type), idx) end gen:store("};\n", idx) else -- Not stored, written on the first run. gen:write(string.format([[ struct %s { syscallarg_t dummy; }; ]], v.arg_alias)) end end if not v.type.NOPROTO and not v.type.NODEF then gen:store(string.format([[ %s %s%s(struct thread *, struct %s *); ]], v.rettype, v:compatPrefix(), v.name, v.arg_alias), idx + 1) gen:store(string.format([[ #define %sAUE_%s%s %s ]], config.syscallprefix, v:compatPrefix(), v.name, v.audit), audit_idx) end end -- Do nothing for obsolete, unimplemented, and reserved. end -- Append #endif to the end of each compat option. for _, v in pairs(config.compat_options) do -- Based on how they're indexed, 9 is the last index. local end_idx = (v.compatlevel * 10) + 9 -- Need an extra newline after #endif. gen:store(string.format("\n#endif /* %s */\n\n", v.definition), end_idx) end if gen.storage_levels ~= nil then gen:writeStorage() end -- After storage has been unrolled, tag on the ending bits. gen:write(string.format([[ #undef PAD_ #undef PADL_ #undef PADR_ #endif /* !%s */ ]], config.sysproto_h)) end -- Entry of script: if script then local config = require("config") if #arg < 1 or #arg > 2 then error("usage: " .. arg[0] .. " syscall.master") end local sysfile, configfile = arg[1], arg[2] config.merge(configfile) config.mergeCompat() - config.mergeCapability() -- The parsed system call table. local tbl = FreeBSDSyscall:new{sysfile = sysfile, config = config} sysproto_h.file = config.sysproto -- change file here sysproto_h.generate(tbl, config, sysproto_h.file) end -- Return the module. return sysproto_h diff --git a/sys/tools/syscalls/scripts/systrace_args.lua b/sys/tools/syscalls/scripts/systrace_args.lua index abd5d284d46e..88170b85e737 100755 --- a/sys/tools/syscalls/scripts/systrace_args.lua +++ b/sys/tools/syscalls/scripts/systrace_args.lua @@ -1,268 +1,267 @@ #!/usr/libexec/flua -- -- SPDX-License-Identifier: BSD-2-Clause -- -- Copyright (c) 2024 Tyler Baxter -- Copyright (c) 2023 Warner Losh -- Copyright (c) 2019 Kyle Evans -- -- Setup to be a module, or ran as its own script. local systrace_args = {} local script = not pcall(debug.getlocal, 4, 1) -- TRUE if script. if script then -- Add library root to the package path. local path = arg[0]:gsub("/[^/]+.lua$", "") package.path = package.path .. ";" .. path .. "/../?.lua" end local FreeBSDSyscall = require("core.freebsd-syscall") local util = require("tools.util") local generator = require("tools.generator") -- File has not been decided yet; config will decide file. Default defined as -- /dev/null. systrace_args.file = "/dev/null" function systrace_args.generate(tbl, config, fh) -- Grab the master system calls table. local s = tbl.syscalls -- Bind the generator to the parameter file. local gen = generator:new({}, fh) gen.storage_levels = {} -- make sure storage is clear -- 64-bit padding preprocessor directive. gen:pad64(config.abiChanges("pair_64bit")) -- Write the generated preamble. gen:preamble( "System call argument to DTrace register array conversion.\n" .. "\n" .. "This file is part of the DTrace syscall provider.") gen:write(string.format([[ static void systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) { int64_t *iarg = (int64_t *)uarg; int a = 0; switch (sysnum) { ]])) gen:store(string.format([[ static void systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) { const char *p = NULL; switch (sysnum) { ]]), 1) gen:store(string.format([[ static void systrace_return_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) { const char *p = NULL; switch (sysnum) { ]]), 2) for _, v in pairs(s) do -- Handle non compat: if v:native() then gen:write(string.format([[ /* %s */ case %d: { ]], v.name, v.num)) gen:store(string.format([[ /* %s */ case %d: ]], v.name, v.num), 1) gen:store(string.format([[ /* %s */ case %d: ]], v.name, v.num), 2) local n_args = #v.args if v.type.SYSMUX then n_args = 0 end if #v.args > 0 and not v.type.SYSMUX then local padding = "" gen:write(string.format([[ struct %s *p = params; ]], v.arg_alias)) gen:store([[ switch (ndx) { ]], 1) for idx, arg in ipairs(v.args) do local argtype = util.trim( arg.type:gsub( "__restrict$", ""), nil) if argtype == "int" and arg.name == "_pad" and config.abiChanges("pair_64bit") then gen:store( "#ifdef PAD64_REQUIRED\n", 1) end -- Pointer arg? local desc if argtype:find("*") then desc = "userland " .. argtype else desc = argtype; end gen:store(string.format([[ case %d%s: p = "%s"; break; ]], idx - 1, padding, desc), 1) if argtype == "int" and arg.name == "_pad" and config.abiChanges("pair_64bit") then padding = " - _P_" gen:store([[ #define _P_ 0 #else #define _P_ 1 #endif ]], 1) end if util.isPtrType(argtype, config.abi_intptr_t) then gen:write(string.format([[ uarg[a++] = (%s)p->%s; /* %s */ ]], config.ptr_intptr_t_cast, arg.name, argtype)) elseif argtype == "union l_semun" then gen:write(string.format([[ uarg[a++] = p->%s.buf; /* %s */ ]], arg.name, argtype)) elseif argtype:sub(1,1) == "u" or argtype == "size_t" then gen:write(string.format([[ uarg[a++] = p->%s; /* %s */ ]], arg.name, argtype)) else if argtype == "int" and arg.name == "_pad" and config.abiChanges( "pair_64bit") then gen:write([[ #ifdef PAD64_REQUIRED ]]) end gen:write(string.format([[ iarg[a++] = p->%s; /* %s */ ]], arg.name, argtype)) if argtype == "int" and arg.name == "_pad" and config.abiChanges( "pair_64bit") then gen:write("#endif\n") end end end gen:store([[ default: break; }; ]], 1) if padding ~= "" then gen:store("#undef _P_\n\n", 1) end gen:store(string.format([[ if (ndx == 0 || ndx == 1) p = "%s"; break; ]], v.ret), 2) end gen:write(string.format("\t\t*n_args = %d;\n\t\tbreak;\n\t}\n", n_args)) gen:store("\t\tbreak;\n", 1) -- Handle compat (everything >= FREEBSD3): -- Do nothing, only for native. end end gen:write([[ default: *n_args = 0; break; }; } ]]) gen:store([[ default: break; }; if (p != NULL) strlcpy(desc, p, descsz); } ]], 1) gen:store([[ default: break; }; if (p != NULL) strlcpy(desc, p, descsz); } ]], 2) -- Write all stored lines. if gen.storage_levels ~= nil then gen:writeStorage() end end -- Entry of script: if script then local config = require("config") if #arg < 1 or #arg > 2 then error("usage: " .. arg[0] .. " syscall.master") end local sysfile, configfile = arg[1], arg[2] config.merge(configfile) config.mergeCompat() - config.mergeCapability() -- The parsed system call table. local tbl = FreeBSDSyscall:new{sysfile = sysfile, config = config} systrace_args.file = config.systrace -- change file here systrace_args.generate(tbl, config, systrace_args.file) end -- Return the module. return systrace_args