xref: /freebsd/sys/tools/syscalls/core/scarg.lua (revision a3cefe7f2b4df0f70ff92d4570ce18e517af43ec)
1--
2-- SPDX-License-Identifier: BSD-2-Clause
3--
4-- Copyright (c) 2021-2024 SRI International
5-- Copyright (c) 2024 Tyler Baxter <agge@FreeBSD.org>
6-- Copyright (c) 2023 Warner Losh <imp@bsdimp.com>
7-- Copyright (c) 2019 Kyle Evans <kevans@FreeBSD.org>
8--
9
10local config = require("config")
11local util = require("tools.util")
12
13local scarg = {}
14
15scarg.__index = scarg
16
17-- Check this argument against config for ABI changes from native. Return TRUE
18-- if there are.
19local function checkAbiChanges(arg)
20	for k, v in pairs(config.known_abi_flags) do
21		if config.abiChanges(k) and v ~= nil then
22			for _, e in pairs(v) do
23				if arg:find(e) then
24					return true
25				end
26			end
27		end
28	end
29	return false
30end
31
32-- Extracts the Microsoft(R) SAL annotations from this argument.
33local function extractArgAnnotations(arg)
34	local annotations = {}
35	for ann in arg:gmatch("_Contains_[^ ]*[_)]") do
36		table.insert(annotations, ann)
37	end
38	for ann in arg:gmatch("_In[^ ]*[_)]") do
39		table.insert(annotations, ann)
40	end
41	for ann in arg:gmatch("_Out[^ ]*[_)]") do
42		table.insert(annotations, ann)
43	end
44	return table.concat(annotations, " ")
45end
46
47-- Strips the Microsoft(R) SAL annotations from this argument.
48local function stripArgAnnotations(arg)
49	arg = arg:gsub("_Contains_[^ ]*[_)] ?", "")
50	arg = arg:gsub("_In[^ ]*[_)] ?", "")
51	arg = arg:gsub("_Out[^ ]*[_)] ?", "")
52	return util.trim(arg)
53end
54
55-- Preprocessing of this argument.
56function scarg:init(line)
57	-- Trim whitespace and trailing comma. We don't want them here;
58	-- these can mess with our processing of this argument.
59	line = util.trim(line)	-- This provides a clearer abort error.
60	self.scarg = util.trim(line, ',')
61
62	self.arg_abi_change = checkAbiChanges(self.scarg)
63	self.changes_abi = self.arg_abi_change
64	self.annotation = extractArgAnnotations(self.scarg)
65	self.scarg = stripArgAnnotations(self.scarg)
66
67	self.name = self.scarg:match("([^* ]+)$")
68	-- Our pattern might produce a Lua pattern sequence; that's a malformed
69	-- declaration.
70	local status, type = pcall(function()
71		return util.trim(self.scarg:gsub(self.name .. "$", ""), nil)
72	end)
73	if not status then
74		util.abort(1, "Malformed argument line: " .. line)
75	end
76	self.type = type
77end
78
79-- Processes this argument.
80-- Flags if there's ABI changes from native, converts this argument to the
81-- target ABI, and handles 64-bit argument pairing.
82-- Returns TRUE if this argument is processed and ready to add.
83-- Returns FALSE if it shouldn't be added (the argument type is void).
84function scarg:process()
85	if self.type ~= "" and self.name ~= "void" then
86		-- util.is64bitType() needs a bare type so check it after
87		-- argname is removed.
88		self.changes_abi = self.changes_abi or
89			(config.abiChanges("pair_64bit") and
90			util.is64bitType(self.type))
91
92		self.type = self.type:gsub("intptr_t", config.abi_intptr_t)
93		self.type = self.type:gsub("semid_t", config.abi_semid_t)
94
95		if util.isPtrType(self.type) then
96			self.type = self.type:gsub("size_t", config.abi_size_t)
97			self.type = self.type:gsub("^long", config.abi_long)
98			self.type = self.type:gsub("^u_long", config.abi_u_long)
99			self.type = self.type:gsub("^const u_long", "const " ..
100			   config.abi_u_long)
101		elseif self.type:find("^long$") then
102			self.type = config.abi_long
103		end
104
105		if util.isPtrArrayType(self.type) and
106		   config.abi_ptr_array_t ~= "" then
107			-- `* const *` -> `**`
108			self.type = self.type:gsub("[*][ ]*const[ ]*[*]", "**")
109			-- e.g., `struct aiocb **` -> `uint32_t *`
110			self.type = self.type:gsub("[^*]*[*]",
111			   config.abi_ptr_array_t .. " ", 1)
112		end
113
114		if self.arg_abi_change then
115			self.type = self.type:gsub("(struct [^ ]*)", "%1" ..
116			    config.abi_type_suffix)
117			self.type = self.type:gsub("(union [^ ]*)", "%1" ..
118			    config.abi_type_suffix)
119		end
120		return true
121	end
122	return false
123end
124
125-- For pairing 64-bit arguments, pad if necessary.
126-- Returns TRUE if this argument was padded.
127local function pad(tbl)
128	if #tbl % 2 == 1 then
129		table.insert(tbl, {
130			type = "int",
131			name = "_pad",
132		})
133		return true
134	end
135	return false
136end
137
138-- To append to a system call's argument table. Appends to the end.
139function scarg:append(tbl)
140	if config.abiChanges("pair_64bit") and util.is64bitType(self.type) then
141		pad(tbl)	-- Needs argument padding.
142		table.insert(tbl, {
143			type = "uint32_t",
144			name = self.name .. "1",
145			annotation = self.annotation or "",
146		})
147		table.insert(tbl, {
148			type = "uint32_t",
149			name = self.name .. "2",
150			annotation = "",
151		})
152	else
153		table.insert(tbl, {
154			type = self.type,
155			name = self.name,
156			annotation = self.annotation or "",
157		})
158	end
159end
160
161-- Returns TRUE if this argument has ABI changes from native.
162-- EXAMPLE: 32-bit argument for freebsd32.
163function scarg:changesAbi()
164	return self.changes_abi
165end
166
167function scarg:new(obj, line)
168	obj = obj or { }
169	setmetatable(obj, self)
170	self.__index = self
171
172	-- ABI changes that we only want in this scope.
173	self.arg_abi_change = false
174	-- ABI changes that we want the system call object to see.
175	self.changes_abi = false
176
177	obj:init(line)
178
179	return obj
180end
181
182return scarg
183