git: 9ded074e875c - main - Refactor makesyscalls.lua into a library
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Wed, 30 Oct 2024 21:08:55 UTC
The branch main has been updated by brooks: URL: https://cgit.FreeBSD.org/src/commit/?id=9ded074e875c29cb92d5f643801990d7bb23cca4 commit 9ded074e875c29cb92d5f643801990d7bb23cca4 Author: agge3 <sterspark@gmail.com> AuthorDate: 2024-10-21 21:42:13 +0000 Commit: Brooks Davis <brooks@FreeBSD.org> CommitDate: 2024-10-30 21:04:30 +0000 Refactor makesyscalls.lua into a library * main.lua replicates the functionality of makesyscalls.lua * Individual files are generated by their associated module * Modules can be called as standalone scripts to generate a specific file * Data and procedures are performed by objects instead of procedual code * Bitmasks are replaced by declarative types * Temporary files are no longer produced, writing is stored in memory * Comments provide explanation to functions and semantics Google Summer of Code 2024 Final Work Product Co-authored-by: Warner Losh <imp@freebsd.org> Co-authored-by: Kyle Evans <kevans@freebsd.org> Co-authored-by: Brooks Davis <brooks@freebsd.org> Sponsored by: Google (GSoC 24) Pull Request: https://github.com/freebsd/freebsd-src/pull/1362 Signed-off-by: agge3 <sterspark@gmail.com> --- sys/tools/syscalls/README.md | 49 +++ sys/tools/syscalls/config.lua | 312 +++++++++++++++++ sys/tools/syscalls/core/freebsd-syscall.lua | 147 ++++++++ sys/tools/syscalls/core/scarg.lua | 163 +++++++++ sys/tools/syscalls/core/scret.lua | 45 +++ sys/tools/syscalls/core/syscall.lua | 497 +++++++++++++++++++++++++++ sys/tools/syscalls/main.lua | 64 ++++ sys/tools/syscalls/scripts/init_sysent.lua | 193 +++++++++++ sys/tools/syscalls/scripts/libsys_h.lua | 111 ++++++ sys/tools/syscalls/scripts/syscall_h.lua | 97 ++++++ sys/tools/syscalls/scripts/syscall_mk.lua | 90 +++++ sys/tools/syscalls/scripts/syscalls.lua | 109 ++++++ sys/tools/syscalls/scripts/syscalls_map.lua | 74 ++++ sys/tools/syscalls/scripts/sysproto_h.lua | 242 +++++++++++++ sys/tools/syscalls/scripts/systrace_args.lua | 268 +++++++++++++++ sys/tools/syscalls/tools/generator.lua | 113 ++++++ sys/tools/syscalls/tools/util.lua | 194 +++++++++++ 17 files changed, 2768 insertions(+) diff --git a/sys/tools/syscalls/README.md b/sys/tools/syscalls/README.md new file mode 100644 index 000000000000..7ae6519360ba --- /dev/null +++ b/sys/tools/syscalls/README.md @@ -0,0 +1,49 @@ +# System call creation library +Parses `syscalls.master` and packages information into objects with methods. +Modules reproduce the previous file auto-generation of `makesyscalls.lua`. + +We generally assume that this script will be run by flua, however we've +carefully crafted modules for it that mimic interfaces provided by modules +available in ports. Currently, this script is compatible with lua from +ports along with the compatible luafilesystem and lua-posix modules. + +## Usage +`main.lua` generates all files. +Files are associated with their respective modules, and modules can be run as +standalone scripts to generate specific files. + +### Examples +**All files:** +`# /usr/libexec/flua /usr/src/sys/tools/syscalls/main.lua /usr/src/sys/kern/syscalls.master` +<br> +**syscalls.h:** +`# /usr/libexec/flua /usr/src/sys/tools/syscalls/scripts/syscalls.h /usr/src/sys/kern/syscalls.master` + +## Organization +* `root` + * `main.lua` - Main entry point that calls all scripts. + * `config.lua` - Contains the global configuration table and associated + configuration functions. + + * `core` (Core Classes) + * `syscall.lua` - Packages each system call entry from `syscalls.master` + into a system call object. + * `scarg.lua` - Packages each argument for the system call into an argument + object. + * `scret.lua` - An object for the return value of the system call. + * `freebsd-syscall.lua` - Contains the master system call table after + processing. + + * `scripts` + * `init_sysent.lua` - Generates `init_sysent.c`. + * `libsys_h.lua` - Generates `lib/libsys/_libsys.h`. + * `syscall_h.lua` - Generates `syscall.h`. + * `syscall_mk.lua` - Generates `syscall.mk`. + * `syscalls.lua` - Generates `syscalls.c`. + * `syscalls_map.lua` - Generates `lib/libsys/syscalls.map`. + * `sysproto_h.lua` - Generates `sysproto.h`. + * `systrace_args.lua` - Generates `systrace_args.c`. + + * `tools` + * `util.lua` - Contains utility functions. + * `generator.lua` - Handles file generation for the library. diff --git a/sys/tools/syscalls/config.lua b/sys/tools/syscalls/config.lua new file mode 100644 index 000000000000..92098a709854 --- /dev/null +++ b/sys/tools/syscalls/config.lua @@ -0,0 +1,312 @@ +-- +-- SPDX-License-Identifier: BSD-2-Clause +-- +-- Copyright (c) 2021-2024 SRI International +-- Copyright (c) 2024 Tyler Baxter <agge@FreeBSD.org> +-- Copyright (c) 2023 Warner Losh <imp@bsdimp.com> +-- Copyright (c) 2019 Kyle Evans <kevans@FreeBSD.org> +-- + +-- +-- 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 + 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/freebsd-syscall.lua b/sys/tools/syscalls/core/freebsd-syscall.lua new file mode 100644 index 000000000000..193b1e43563c --- /dev/null +++ b/sys/tools/syscalls/core/freebsd-syscall.lua @@ -0,0 +1,147 @@ +-- +-- SPDX-License-Identifier: BSD-2-Clause +-- +-- Copyright (c) 2024 Tyler Baxter <agge@FreeBSD.org> +-- Copyright (c) 2023 Warner Losh <imp@bsdimp.com> +-- Copyright (c) 2019 Kyle Evans <kevans@FreeBSD.org> +-- + +local syscall = require("core.syscall") +local util = require("tools.util") + +local FreeBSDSyscall = {} + +FreeBSDSyscall.__index = FreeBSDSyscall + +-- For each compat option in the provided config table, process them and insert +-- them into known_flags for class syscall. +function FreeBSDSyscall:processCompat() + for _, v in pairs(self.config.compat_options) do + if v.stdcompat ~= nil then + local stdcompat = v.stdcompat + v.definition = "COMPAT_" .. stdcompat:upper() + v.compatlevel = tonumber(stdcompat:match("([0-9]+)$")) + v.flag = stdcompat:gsub("FREEBSD", "COMPAT") + v.prefix = stdcompat:lower() .. "_" + v.descr = stdcompat:lower() + end + + -- Add compat option to syscall.known_flags. + table.insert(syscall.known_flags, v.flag) + end +end + +function FreeBSDSyscall:parseSysfile() + local file = self.sysfile + local config = self.config + local commentExpr = "^%s*;.*" + + if file == nil then + return nil, "No file given" + end + + self.syscalls = {} + + local fh, msg = io.open(file) + if fh == nil then + return nil, msg + end + + local incs = "" + local defs = "" + local s + for line in fh:lines() do + line = line:gsub(commentExpr, "") -- Strip any comments. + -- NOTE: Can't use pure pattern matching here because of + -- the 's' test and this is shorter than a generic pattern + -- matching pattern. + if line == nil or line == "" then + goto skip -- Blank line, skip this line. + elseif s ~= nil then + -- If we have a partial system call object s, + -- then feed it one more line. + if s:add(line) then + -- Append to system call list. + for t in s:iter() do + if t:validate(t.num - 1) then + table.insert(self.syscalls, t) + else + util.abort(1, + "Skipped system call " .. + "at number " .. t.num) + end + end + s = nil + end + elseif line:match("^#%s*include") then + incs = incs .. line .. "\n" + elseif line:match("%%ABI_HEADERS%%") then + local h = self.config.abi_headers + if h ~= nil and h ~= "" then + incs = incs .. h .. "\n" + end + elseif line:match("^#%s*define") then + defs = defs .. line.. "\n" + elseif line:match("^#") then + util.abort(1, "Unsupported cpp op " .. line) + else + s = syscall:new() + if s:add(line) then + -- Append to system call list. + for t in s:iter() do + if t:validate(t.num - 1) then + table.insert(self.syscalls, t) + else + util.abort(1, + "Skipped system call " .. + "at number " .. t.num) + end + end + s = nil + end + end + ::skip:: + end + + -- Special handling for linux nosys. + if config.syscallprefix:find("LINUX") ~= nil then + s = nil + end + + if s ~= nil then + util.abort(1, "Dangling system call at the end") + end + + assert(fh:close()) + self.includes = incs + self.defines = defs +end + +function FreeBSDSyscall:findStructs() + self.structs = {} + + for _, s in pairs(self.syscalls) do + if s:native() and not s.type.NODEF then + for _, v in ipairs(s.args) do + local name = util.structName(v.type) + if name ~= nil then + self.structs[name] = name + end + end + end + end +end + +function FreeBSDSyscall:new(obj) + obj = obj or {} + setmetatable(obj, self) + self.__index = self + + obj:processCompat() + obj:parseSysfile() + obj:findStructs() + + return obj +end + +return FreeBSDSyscall diff --git a/sys/tools/syscalls/core/scarg.lua b/sys/tools/syscalls/core/scarg.lua new file mode 100644 index 000000000000..7ffbf15b3a80 --- /dev/null +++ b/sys/tools/syscalls/core/scarg.lua @@ -0,0 +1,163 @@ +-- +-- SPDX-License-Identifier: BSD-2-Clause +-- +-- Copyright (c) 2021-2024 SRI International +-- Copyright (c) 2024 Tyler Baxter <agge@FreeBSD.org> +-- Copyright (c) 2023 Warner Losh <imp@bsdimp.com> +-- Copyright (c) 2019 Kyle Evans <kevans@FreeBSD.org> +-- + +local config = require("config") +local util = require("tools.util") + +local scarg = {} + +scarg.__index = scarg + +-- Check this argument against config for ABI changes from native. Return TRUE +-- if there are. +local function checkAbiChanges(arg) + for k, v in pairs(config.known_abi_flags) do + if config.abiChanges(k) and v ~= nil then + for _, e in pairs(v) do + if arg:find(e) then + return true + end + end + end + end + return false +end + +-- Strips the Microsoft(R) SAL annotations from this argument. +local function stripArgAnnotations(arg) + arg = arg:gsub("_Contains_[^ ]*[_)] ?", "") + arg = arg:gsub("_In[^ ]*[_)] ?", "") + arg = arg:gsub("_Out[^ ]*[_)] ?", "") + return util.trim(arg) +end + +-- Preprocessing of this argument. +function scarg:init(line) + -- Trim whitespace and trailing comma. We don't want them here; + -- these can mess with our processing of this argument. + line = util.trim(line) -- This provides a clearer abort error. + self.scarg = util.trim(line, ',') + + self.arg_abi_change = checkAbiChanges(self.scarg) + self.changes_abi = self.arg_abi_change + self.scarg = stripArgAnnotations(self.scarg) + + self.name = self.scarg:match("([^* ]+)$") + -- Our pattern might produce a Lua pattern sequence; that's a malformed + -- declaration. + local status, type = pcall(function() + return util.trim(self.scarg:gsub(self.name .. "$", ""), nil) + end) + if not status then + util.abort(1, "Malformed argument line: " .. line) + end + self.type = type +end + +-- Processes this argument. +-- Flags if there's ABI changes from native, converts this argument to the +-- target ABI, and handles 64-bit argument pairing. +-- Returns TRUE if this argument is processed and ready to add. +-- Returns FALSE if it shouldn't be added (the argument type is void). +function scarg:process() + if self.type ~= "" and self.name ~= "void" then + -- util.is64bitType() needs a bare type so check it after + -- argname is removed. + self.changes_abi = self.changes_abi or + (config.abiChanges("pair_64bit") and + util.is64bitType(self.type)) + + self.type = self.type:gsub("intptr_t", config.abi_intptr_t) + self.type = self.type:gsub("semid_t", config.abi_semid_t) + + if util.isPtrType(self.type) then + self.type = self.type:gsub("size_t", config.abi_size_t) + self.type = self.type:gsub("^long", config.abi_long) + self.type = self.type:gsub("^u_long", config.abi_u_long) + self.type = self.type:gsub("^const u_long", "const " .. + config.abi_u_long) + elseif self.type:find("^long$") then + self.type = config.abi_long + end + + if util.isPtrArrayType(self.type) and + config.abi_ptr_array_t ~= "" then + -- `* const *` -> `**` + self.type = self.type:gsub("[*][ ]*const[ ]*[*]", "**") + -- e.g., `struct aiocb **` -> `uint32_t *` + self.type = self.type:gsub("[^*]*[*]", + config.abi_ptr_array_t .. " ", 1) + end + + if self.arg_abi_change then + self.type = self.type:gsub("(struct [^ ]*)", "%1" .. + config.abi_type_suffix) + self.type = self.type:gsub("(union [^ ]*)", "%1" .. + config.abi_type_suffix) + end + return true + end + return false +end + +-- For pairing 64-bit arguments, pad if necessary. +-- Returns TRUE if this argument was padded. +local function pad(tbl) + if #tbl % 2 == 1 then + table.insert(tbl, { + type = "int", + name = "_pad", + }) + return true + end + return false +end + +-- To append to a system call's argument table. Appends to the end. +function scarg:append(tbl) + if config.abiChanges("pair_64bit") and util.is64bitType(self.type) then + pad(tbl) -- Needs argument padding. + table.insert(tbl, { + type = "uint32_t", + name = self.name .. "1", + }) + table.insert(tbl, { + type = "uint32_t", + name = self.name .. "2", + }) + else + table.insert(tbl, { + type = self.type, + name = self.name, + }) + end +end + +-- Returns TRUE if this argument has ABI changes from native. +-- EXAMPLE: 32-bit argument for freebsd32. +function scarg:changesAbi() + return self.changes_abi +end + +function scarg:new(obj, line) + obj = obj or { } + setmetatable(obj, self) + self.__index = self + + -- ABI changes that we only want in this scope. + self.arg_abi_change = false + -- ABI changes that we want the system call object to see. + self.changes_abi = false + + obj:init(line) + + return obj +end + +return scarg diff --git a/sys/tools/syscalls/core/scret.lua b/sys/tools/syscalls/core/scret.lua new file mode 100644 index 000000000000..25522b4c830e --- /dev/null +++ b/sys/tools/syscalls/core/scret.lua @@ -0,0 +1,45 @@ +-- +-- SPDX-License-Identifier: BSD-2-Clause +-- +-- Copyright (c) 2024 Tyler Baxter <agge@FreeBSD.org> +-- Copyright (c) 2023 Warner Losh <imp@bsdimp.com> +-- Copyright (c) 2019 Kyle Evans <kevans@FreeBSD.org> +-- + +local util = require("tools.util") + +local scret = {} + +scret.__index = scret + +-- Processes this return type. +function scret:process() + local words = util.split(self.scret, "%S+") + self.scret = words[1] + -- Pointer incoming. + if words[2]:sub(1,1) == "*" then + self.scret = self.scret .. " " + end + while words[2]:sub(1,1) == "*" do + words[2] = words[2]:sub(2) + self.scret = self.scret .. "*" + end +end + +-- To add this return type to the system call. +function scret:add() + self:process() + return self.scret +end + +function scret:new(obj, line) + obj = obj or { } + setmetatable(obj, self) + self.__index = self + + self.scret = line + + return obj +end + +return scret diff --git a/sys/tools/syscalls/core/syscall.lua b/sys/tools/syscalls/core/syscall.lua new file mode 100644 index 000000000000..7e8c562dad8a --- /dev/null +++ b/sys/tools/syscalls/core/syscall.lua @@ -0,0 +1,497 @@ +-- +-- SPDX-License-Identifier: BSD-2-Clause +-- +-- Copyright (c) 2024 Tyler Baxter <agge@FreeBSD.org> +-- Copyright (c) 2023 Warner Losh <imp@bsdimp.com> +-- Copyright (c) 2019 Kyle Evans <kevans@FreeBSD.org> +-- + +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 + 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 *** 1933 LINES SKIPPED ***