Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/tools/syscalls/core/syscall.lua
39530 views
1
--
2
-- SPDX-License-Identifier: BSD-2-Clause
3
--
4
-- Copyright (c) 2024 Tyler Baxter <[email protected]>
5
-- Copyright (c) 2023 Warner Losh <[email protected]>
6
-- Copyright (c) 2019 Kyle Evans <[email protected]>
7
--
8
9
local config = require("config")
10
local scarg = require("core.scarg")
11
local scret = require("core.scret")
12
local util = require("tools.util")
13
14
local syscall = {}
15
16
syscall.__index = syscall
17
18
syscall.known_flags = util.set {
19
"STD",
20
"OBSOL",
21
"RESERVED",
22
"UNIMPL",
23
"NODEF",
24
"NOARGS",
25
"NOPROTO",
26
"NOSTD",
27
28
-- flags beyond this point are modifiers
29
"CAPENABLED",
30
"NOLIB",
31
"NORETURN",
32
"NOTSTATIC",
33
"SYSMUX",
34
}
35
36
-- Native is an arbitrarily large number to have a constant and not
37
-- interfere with compat numbers.
38
local native = 1000000
39
40
-- Processes and assigns the appropriate thread flag for this system call.
41
function syscall:processThr()
42
self.thr = "SY_THR_STATIC"
43
for k, _ in pairs(self.type) do
44
if k == "NOTSTATIC" then
45
self.thr = "SY_THR_ABSENT"
46
end
47
end
48
end
49
50
-- Processes and assigns the appropriate capability flag for this system call.
51
-- "SYF_CAPENABLED" for capability enabled; "0" for NOT capability enabled.
52
function syscall:processCap()
53
self.cap = "0"
54
local stripped = util.stripAbiPrefix(self.name, self.prefix)
55
for k, _ in pairs(self.type) do
56
if k == "CAPENABLED" then
57
self.cap = "SYF_CAPENABLED"
58
end
59
end
60
end
61
62
-- Check that this system call has a known type.
63
local function checkType(type)
64
for k, _ in pairs(type) do
65
if not syscall.known_flags[k] and not
66
k:match("^COMPAT") then
67
util.abort(1, "Bad type: " .. k)
68
end
69
end
70
end
71
72
-- If there are ABI changes from native, process this system call to match the
73
-- target ABI.
74
function syscall:processChangesAbi()
75
-- First, confirm we want to uphold our changes_abi flag.
76
if config.syscall_no_abi_change[self.name] then
77
self.changes_abi = false
78
end
79
self.noproto = not util.isEmpty(config.abi_flags) and
80
not self.changes_abi
81
if config.abiChanges("pointer_args") then
82
for _, v in ipairs(self.args) do
83
if util.isPtrType(v.type, config.abi_intptr_t) then
84
if config.syscall_no_abi_change[self.name] then
85
print("WARNING: " .. self.name ..
86
" in syscall_no_abi_change, " ..
87
"but pointers args are present")
88
end
89
self.changes_abi = true
90
goto ptrfound
91
end
92
end
93
::ptrfound::
94
end
95
if config.syscall_abi_change[self.name] then
96
self.changes_abi = true
97
end
98
if self.changes_abi then
99
self.noproto = false
100
end
101
end
102
103
-- Final processing of flags. Process any flags that haven't already been
104
-- processed (e.g., dictionaries from syscalls.conf).
105
function syscall:processFlags()
106
if config.obsol[self.name] or (self:compatLevel() > 0 and
107
self:compatLevel() < tonumber(config.mincompat)) then
108
self.args = nil
109
self.type.OBSOL = true
110
-- Don't apply any ABI handling, declared as obsolete.
111
self.changes_abi = false
112
end
113
if config.unimpl[self.name] then
114
self.type.UNIMPL = true
115
end
116
if self.noproto or self.type.SYSMUX then
117
self.type.NOPROTO = true
118
end
119
if self.type.NODEF then
120
self.audit = "AUE_NULL"
121
end
122
end
123
124
-- Returns TRUE if prefix and arg_prefix are assigned; FALSE if they're left
125
-- unassigned. Relies on a valid changes_abi flag, so should be called AFTER
126
-- processChangesAbi().
127
function syscall:processPrefix()
128
-- If there are ABI changes from native, assign the correct prefixes.
129
if self.changes_abi then
130
self.arg_prefix = config.abi_func_prefix
131
self.prefix = config.abi_func_prefix
132
return true
133
end
134
return false
135
end
136
137
-- Validate that we're not skipping system calls by comparing this system call
138
-- number to the previous system call number. Called higher up the call stack
139
-- by class FreeBSDSyscall.
140
function syscall:validate(prev)
141
return prev + 1 == self.num
142
end
143
144
-- Return the compat prefix for this system call.
145
function syscall:compatPrefix()
146
local c = self:compatLevel()
147
if self.type.OBSOL then
148
return "obs_"
149
end
150
if self.type.RESERVED then
151
return "reserved #"
152
end
153
if self.type.UNIMPL then
154
return "unimp_"
155
end
156
if c == 3 then
157
return "o"
158
end
159
if c < native then
160
return "freebsd" .. tostring(c) .. "_"
161
end
162
return ""
163
end
164
165
-- Return the symbol name for this system call.
166
function syscall:symbol()
167
return self:compatPrefix() .. self.name
168
end
169
170
--
171
-- Return the compatibility level for this system call.
172
-- 0 is obsolete.
173
-- < 0 is this isn't really a system call we care about.
174
-- 3 is 4.3BSD in theory, but anything before FreeBSD 4.
175
-- >= 4 is FreeBSD version, this system call was replaced with a new
176
-- version.
177
--
178
function syscall:compatLevel()
179
if self.type.UNIMPL or self.type.RESERVED then
180
return -1
181
elseif self.type.OBSOL then
182
return 0
183
elseif self.type.COMPAT then
184
return 3
185
end
186
for k, _ in pairs(self.type) do
187
local l = k:match("^COMPAT(%d+)")
188
if l ~= nil then
189
return tonumber(l)
190
end
191
end
192
return native
193
end
194
195
-- Adds the definition for this system call. Guarded by whether we already have
196
-- a system call number or not.
197
function syscall:addDef(line)
198
if self.num == nil then
199
local words = util.split(line, "%S+")
200
self.num = words[1]
201
self.audit = words[2]
202
self.type = util.setFromString(words[3], "[^|]+")
203
checkType(self.type)
204
self.name = words[4]
205
-- These next three are optional, and either all present
206
-- or all absent.
207
self.altname = words[5]
208
self.alttag = words[6]
209
self.rettype = words[7]
210
return true
211
end
212
return false
213
end
214
215
-- Adds the function declaration for this system call. If addDef() found an
216
-- opening curly brace, then we're looking for a function declaration.
217
function syscall:addFunc(line)
218
if self.name == "{" then
219
local words = util.split(line, "%S+")
220
-- Expect line is `type syscall(` or `type syscall(void);`.
221
if #words ~= 2 then
222
util.abort(1, "Malformed line " .. line)
223
end
224
225
local ret = scret:new({}, line)
226
self.ret = ret:add()
227
-- Don't clobber rettype set in the alt information.
228
if self.rettype == nil then
229
self.rettype = "int"
230
end
231
232
self.name = words[2]:match("([%w_]+)%(")
233
if words[2]:match("%);$") then
234
-- Now we're looking for ending curly brace.
235
self.expect_rbrace = true
236
end
237
return true
238
end
239
return false
240
end
241
242
-- Adds the argument(s) for this system call. Once addFunc() assigns a name
243
-- for this system call, arguments are next in syscalls.master.
244
function syscall:addArgs(line)
245
if not self.expect_rbrace then
246
if line:match("%);$") then
247
self.expect_rbrace = true
248
return true
249
end
250
local arg = scarg:new({}, line)
251
-- We don't want to add this argument if it doesn't process.
252
-- scarg:process() handles those conditions.
253
if arg:process() then
254
arg:append(self.args)
255
end
256
-- If this argument has ABI changes, set globally for this
257
-- system call.
258
self.changes_abi = self.changes_abi or arg:changesAbi()
259
return true
260
end
261
return false
262
end
263
264
-- Once we have a good syscall, add some final information to it.
265
function syscall:finalize()
266
if self.name == nil then
267
self.name = ""
268
end
269
270
-- Preserve the original name as the alias.
271
self.alias = self.name
272
273
self:processChangesAbi() -- process changes to the ABI
274
self:processFlags() -- process any unprocessed flags
275
276
-- If there's changes to the ABI, these prefixes will be changed by
277
-- processPrefix(); otherwise, they'll remain empty.
278
self.prefix = ""
279
self.arg_prefix = ""
280
self:processPrefix()
281
282
self:processCap() -- capability flag
283
self:processThr() -- thread flag
284
285
-- Assign argument alias.
286
if self.alttag ~= nil then
287
self.arg_alias = self.alttag
288
elseif self.arg_alias == nil and self.name ~= nil then
289
-- argalias should be:
290
-- COMPAT_PREFIX + ABI Prefix + funcname
291
self.arg_alias = self:compatPrefix() .. self.arg_prefix ..
292
self.name .. "_args"
293
elseif self.arg_alias ~= nil then
294
self.arg_alias = self.arg_prefix .. self.arg_alias
295
end
296
297
-- An empty string would not want a prefix; the entry doesn't have
298
-- a name so we want to keep the empty string.
299
if self.name ~= nil and self.name ~= "" then
300
self.name = self.prefix .. self.name
301
end
302
303
self:processArgstrings()
304
self:processArgsize()
305
end
306
307
-- Assigns the correct args_size. Defaults to "0", except if there's arguments
308
-- or NODEF flag.
309
function syscall:processArgsize()
310
if self.type.SYSMUX then -- catch this first
311
self.args_size = "0"
312
elseif self.arg_alias ~= nil and
313
(#self.args ~= 0 or self.type.NODEF) then
314
self.args_size = "AS(" .. self.arg_alias .. ")"
315
else
316
self.args_size = "0"
317
end
318
end
319
320
-- Constructs argstr_* strings for generated declerations/wrappers.
321
function syscall:processArgstrings()
322
local type = ""
323
local type_var = ""
324
local var = ""
325
local comma = ""
326
327
for _, v in ipairs(self.args) do
328
local argname, argtype = v.name, v.type
329
type = type .. comma .. argtype
330
type_var = type_var .. comma .. argtype .. " " .. argname
331
var = var .. comma .. argname
332
comma = ", "
333
end
334
if type == "" then
335
type = "void"
336
type_var = "void"
337
end
338
339
self.argstr_type = type
340
self.argstr_type_var = type_var
341
self.argstr_var = var
342
end
343
344
-- Interface to add this system call to the master system call table.
345
-- The system call is built up one line at a time. The states describe the
346
-- current parsing state.
347
-- Returns TRUE when ready to add and FALSE while still parsing.
348
function syscall:add(line)
349
if self:addDef(line) then
350
return self:isAdded(line)
351
end
352
if self:addFunc(line) then
353
return false -- Function added; keep going.
354
end
355
if self:addArgs(line) then
356
return false -- Arguments added; keep going.
357
end
358
return self:isAdded(line) -- Final validation, before adding.
359
end
360
361
-- Returns TRUE if this system call was succesfully added. There's two entry
362
-- points to this function: (1) the entry in syscalls.master is one-line, or
363
-- (2) the entry is a full system call. This function handles those cases and
364
-- decides whether to exit early for (1) or validate a full system call for
365
-- (2). This function also handles cases where we don't want to add, and
366
-- instead want to abort.
367
function syscall:isAdded(line)
368
-- This system call is a range - exit early.
369
if tonumber(self.num) == nil then
370
-- The only allowed types are RESERVED and UNIMPL.
371
if not (self.type.RESERVED or self.type.UNIMPL) then
372
util.abort(1, "Range only allowed with RESERVED " ..
373
"and UNIMPL: " .. line)
374
end
375
self:finalize()
376
return true
377
-- This system call is a loadable system call - exit early.
378
elseif self.altname ~= nil and self.alttag ~= nil and
379
self.rettype ~= nil then
380
self:finalize()
381
return true
382
-- This system call is only one line, and should only be one line
383
-- (we didn't make it to addFunc()) - exit early.
384
elseif self.name ~= "{" and self.ret == nil then
385
self:finalize()
386
return true
387
-- This is a full system call and we've passed multiple states to
388
-- get here - final exit.
389
elseif self.expect_rbrace then
390
if not line:match("}$") then
391
util.abort(1, "Expected '}' found '" .. line ..
392
"' instead.")
393
end
394
self:finalize()
395
return true
396
end
397
return false
398
end
399
400
-- Return TRUE if this system call is native.
401
function syscall:native()
402
return self:compatLevel() == native
403
end
404
405
-- Make a shallow copy of `self` and replace the system call number with num
406
-- (which should be a number).
407
-- For system call ranges.
408
function syscall:shallowCopy(num)
409
local obj = syscall:new()
410
411
-- shallow copy
412
for k, v in pairs(self) do
413
obj[k] = v
414
end
415
obj.num = num -- except override range
416
return obj
417
end
418
419
-- Make a deep copy of the parameter object. Save copied tables in `copies`,
420
-- indexed by original table.
421
-- CREDIT: http://lua-users.org/wiki/CopyTable
422
-- For a full system call (the nested arguments table should be a deep copy).
423
local function deepCopy(orig, copies)
424
copies = copies or {}
425
local orig_type = type(orig)
426
local copy
427
if orig_type == 'table' then
428
if copies[orig] then
429
copy = copies[orig]
430
else
431
copy = {}
432
copies[orig] = copy
433
for orig_key, orig_value in next, orig, nil do
434
copy[deepCopy(orig_key, copies)] =
435
deepCopy(orig_value, copies)
436
end
437
setmetatable(copy, deepCopy(getmetatable(orig), copies))
438
end
439
else -- number, string, boolean, etc
440
copy = orig
441
end
442
return copy
443
end
444
445
--
446
-- In syscalls.master, system calls come in two types: (1) a fully defined
447
-- system call with function declaration, with a distinct number for each system
448
-- call; or (2) a one-line entry, sometimes with a distinct number and sometimes
449
-- with a range of numbers. One-line entries can be obsolete, reserved, no
450
-- definition, etc. Ranges are only allowed for reserved and unimplemented.
451
--
452
-- This function provides the iterator to traverse system calls by number. If
453
-- the entry is a fully defined system call with a distinct number, the iterator
454
-- creates a deep copy and captures any nested objects; if the entry is a range
455
-- of numbers, the iterator creates shallow copies from the start of the range
456
-- to the end of the range.
457
--
458
function syscall:iter()
459
local s = tonumber(self.num)
460
local e
461
if s == nil then
462
s, e = string.match(self.num, "(%d+)%-(%d+)")
463
s, e = tonumber(s), tonumber(e)
464
return function ()
465
if s <= e then
466
s = s + 1
467
return self:shallowCopy(s - 1)
468
end
469
end
470
else
471
e = s
472
self.num = s -- Replace string with number, like the clones.
473
return function ()
474
if s == e then
475
local deep_copy = deepCopy(self)
476
s = e + 1
477
return deep_copy
478
end
479
end
480
end
481
end
482
483
function syscall:new(obj)
484
obj = obj or { }
485
setmetatable(obj, self)
486
self.__index = self
487
488
self.expect_rbrace = false
489
self.changes_abi = false
490
self.args = {}
491
self.noproto = false
492
493
return obj
494
end
495
496
return syscall
497
498