xref: /freebsd/sys/tools/syscalls/core/scarg.lua (revision 9ded074e875c29cb92d5f643801990d7bb23cca4)
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-- Strips the Microsoft(R) SAL annotations from this argument.
33local function stripArgAnnotations(arg)
34	arg = arg:gsub("_Contains_[^ ]*[_)] ?", "")
35	arg = arg:gsub("_In[^ ]*[_)] ?", "")
36	arg = arg:gsub("_Out[^ ]*[_)] ?", "")
37	return util.trim(arg)
38end
39
40-- Preprocessing of this argument.
41function scarg:init(line)
42	-- Trim whitespace and trailing comma. We don't want them here;
43	-- these can mess with our processing of this argument.
44	line = util.trim(line)	-- This provides a clearer abort error.
45	self.scarg = util.trim(line, ',')
46
47	self.arg_abi_change = checkAbiChanges(self.scarg)
48	self.changes_abi = self.arg_abi_change
49	self.scarg = stripArgAnnotations(self.scarg)
50
51	self.name = self.scarg:match("([^* ]+)$")
52	-- Our pattern might produce a Lua pattern sequence; that's a malformed
53	-- declaration.
54	local status, type = pcall(function()
55		return util.trim(self.scarg:gsub(self.name .. "$", ""), nil)
56	end)
57	if not status then
58		util.abort(1, "Malformed argument line: " .. line)
59	end
60	self.type = type
61end
62
63-- Processes this argument.
64-- Flags if there's ABI changes from native, converts this argument to the
65-- target ABI, and handles 64-bit argument pairing.
66-- Returns TRUE if this argument is processed and ready to add.
67-- Returns FALSE if it shouldn't be added (the argument type is void).
68function scarg:process()
69	if self.type ~= "" and self.name ~= "void" then
70		-- util.is64bitType() needs a bare type so check it after
71		-- argname is removed.
72		self.changes_abi = self.changes_abi or
73			(config.abiChanges("pair_64bit") and
74			util.is64bitType(self.type))
75
76		self.type = self.type:gsub("intptr_t", config.abi_intptr_t)
77		self.type = self.type:gsub("semid_t", config.abi_semid_t)
78
79		if util.isPtrType(self.type) then
80			self.type = self.type:gsub("size_t", config.abi_size_t)
81			self.type = self.type:gsub("^long", config.abi_long)
82			self.type = self.type:gsub("^u_long", config.abi_u_long)
83			self.type = self.type:gsub("^const u_long", "const " ..
84			   config.abi_u_long)
85		elseif self.type:find("^long$") then
86			self.type = config.abi_long
87		end
88
89		if util.isPtrArrayType(self.type) and
90		   config.abi_ptr_array_t ~= "" then
91			-- `* const *` -> `**`
92			self.type = self.type:gsub("[*][ ]*const[ ]*[*]", "**")
93			-- e.g., `struct aiocb **` -> `uint32_t *`
94			self.type = self.type:gsub("[^*]*[*]",
95			   config.abi_ptr_array_t .. " ", 1)
96		end
97
98		if self.arg_abi_change then
99			self.type = self.type:gsub("(struct [^ ]*)", "%1" ..
100			    config.abi_type_suffix)
101			self.type = self.type:gsub("(union [^ ]*)", "%1" ..
102			    config.abi_type_suffix)
103		end
104		return true
105	end
106	return false
107end
108
109-- For pairing 64-bit arguments, pad if necessary.
110-- Returns TRUE if this argument was padded.
111local function pad(tbl)
112	if #tbl % 2 == 1 then
113		table.insert(tbl, {
114			type = "int",
115			name = "_pad",
116		})
117		return true
118	end
119	return false
120end
121
122-- To append to a system call's argument table. Appends to the end.
123function scarg:append(tbl)
124	if config.abiChanges("pair_64bit") and util.is64bitType(self.type) then
125		pad(tbl)	-- Needs argument padding.
126		table.insert(tbl, {
127			type = "uint32_t",
128			name = self.name .. "1",
129		})
130		table.insert(tbl, {
131			type = "uint32_t",
132			name = self.name .. "2",
133		})
134	else
135		table.insert(tbl, {
136			type = self.type,
137			name = self.name,
138		})
139	end
140end
141
142-- Returns TRUE if this argument has ABI changes from native.
143-- EXAMPLE: 32-bit argument for freebsd32.
144function scarg:changesAbi()
145	return self.changes_abi
146end
147
148function scarg:new(obj, line)
149	obj = obj or { }
150	setmetatable(obj, self)
151	self.__index = self
152
153	-- ABI changes that we only want in this scope.
154	self.arg_abi_change = false
155	-- ABI changes that we want the system call object to see.
156	self.changes_abi = false
157
158	obj:init(line)
159
160	return obj
161end
162
163return scarg
164