xref: /freebsd/sys/tools/syscalls/core/freebsd-syscall.lua (revision 8d6feaaaa26f444abb209360e52b993e39cb81bb)
1--
2-- SPDX-License-Identifier: BSD-2-Clause
3--
4-- Copyright (c) 2024 Tyler Baxter <agge@FreeBSD.org>
5-- Copyright (c) 2023 Warner Losh <imp@bsdimp.com>
6-- Copyright (c) 2019 Kyle Evans <kevans@FreeBSD.org>
7--
8
9local syscall = require("core.syscall")
10local util = require("tools.util")
11
12local FreeBSDSyscall = {}
13
14FreeBSDSyscall.__index = FreeBSDSyscall
15
16-- For each compat option in the provided config table, process them and insert
17-- them into known_flags for class syscall.
18function FreeBSDSyscall:processCompat()
19	for _, v in pairs(self.config.compat_options) do
20		if v.stdcompat ~= nil then
21			local stdcompat = v.stdcompat
22			v.definition = "COMPAT_" .. stdcompat:upper()
23			v.compatlevel = tonumber(stdcompat:match("([0-9]+)$"))
24			v.flag = stdcompat:gsub("FREEBSD", "COMPAT")
25			v.prefix = stdcompat:lower() .. "_"
26			v.descr = stdcompat:lower()
27		end
28
29		-- Add compat option to syscall.known_flags.
30		table.insert(syscall.known_flags, v.flag)
31	end
32end
33
34function FreeBSDSyscall:parseSysfile()
35	local file = self.sysfile
36	local config = self.config
37	local commentExpr = "^%s*;.*"
38
39	if file == nil then
40		return nil, "No file given"
41	end
42
43	self.syscalls = {}
44
45	local fh, msg = io.open(file)
46	if fh == nil then
47		return nil, msg
48	end
49
50	local incs = ""
51	local defs = ""
52	local s
53	for line in fh:lines() do
54		line = line:gsub(commentExpr, "") -- Strip any comments.
55		-- NOTE: Can't use pure pattern matching here because of
56		-- the 's' test and this is shorter than a generic pattern
57		-- matching pattern.
58		if line == nil or line == "" then
59			goto skip	-- Blank line, skip this line.
60		elseif s ~= nil then
61			-- If we have a partial system call object s,
62			-- then feed it one more line.
63			if s:add(line) then
64				-- Append to system call list.
65				for t in s:iter() do
66					if t:validate(t.num - 1) then
67						table.insert(self.syscalls, t)
68					else
69						util.abort(1,
70						    "Skipped system call " ..
71						    "at number " .. t.num)
72					end
73				end
74				s = nil
75			end
76		elseif line:match("^#%s*include") then
77			incs = incs .. line .. "\n"
78		elseif line:match("%%ABI_HEADERS%%") then
79			local h = self.config.abi_headers
80			if h ~= nil and h ~= "" then
81				incs = incs .. h .. "\n"
82			end
83		elseif line:match("^#%s*define") then
84			defs = defs .. line.. "\n"
85		elseif line:match("^#") then
86			util.abort(1, "Unsupported cpp op " .. line)
87		else
88			s = syscall:new()
89			if s:add(line) then
90				-- Append to system call list.
91				for t in s:iter() do
92					if t:validate(t.num - 1) then
93						table.insert(self.syscalls, t)
94					else
95						util.abort(1,
96						    "Skipped system call " ..
97						    "at number " .. t.num)
98					end
99				end
100				s = nil
101			end
102		end
103		::skip::
104	end
105
106	-- Special handling for linux nosys.
107	if config.syscallprefix:find("LINUX") ~= nil then
108		s = nil
109	end
110
111	if s ~= nil then
112		util.abort(1, "Dangling system call at the end")
113	end
114
115	assert(fh:close())
116	self.includes = incs
117	self.defines = defs
118end
119
120function FreeBSDSyscall:findStructs()
121	self.structs = {}
122
123	for _, s in pairs(self.syscalls) do
124		if s:native() and not s.type.NODEF then
125			for _, v in ipairs(s.args) do
126				local name = util.structName(v.type)
127				if name ~= nil then
128					self.structs[name] = name
129				end
130			end
131		end
132	end
133end
134
135function FreeBSDSyscall:new(obj)
136	obj = obj or {}
137	setmetatable(obj, self)
138	self.__index = self
139
140	obj:processCompat()
141	obj:parseSysfile()
142	obj:findStructs()
143
144	return obj
145end
146
147return FreeBSDSyscall
148